diff --git a/.gitmodules b/.gitmodules index 4612b3d0c9..e69de29bb2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +0,0 @@ -[submodule "framework"] - path = framework - url = https://github.com/Mbed-TLS/mbedtls-framework -[submodule "tf-psa-crypto"] - path = tf-psa-crypto - url = https://github.com/Mbed-TLS/TF-PSA-Crypto.git diff --git a/framework b/framework deleted file mode 160000 index dff9da0443..0000000000 --- a/framework +++ /dev/null @@ -1 +0,0 @@ -Subproject commit dff9da04438d712f7647fd995bc90fadd0c0e2ce diff --git a/tf-psa-crypto b/tf-psa-crypto deleted file mode 160000 index 29160dd877..0000000000 --- a/tf-psa-crypto +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 29160dd877d29658279fd683b2ae57b320ddcf09 diff --git a/tf-psa-crypto/BRANCHES.md b/tf-psa-crypto/BRANCHES.md new file mode 100644 index 0000000000..32966dc12f --- /dev/null +++ b/tf-psa-crypto/BRANCHES.md @@ -0,0 +1,109 @@ +# Maintained branches + +At any point in time, we have a number of maintained branches, currently consisting of: + +- The [`main`](https://github.com/Mbed-TLS/TF-PSA-Crypto/tree/main) branch: + this always contains the latest release, including all publicly available + security fixes. +- The [`development`](https://github.com/Mbed-TLS/TF-PSA-Crypto/tree/development) branch: + This branch was used to prepare version 1.0.0 of TF-PSA-Crypto and continues to host + development for future versions. +- [`tf-psa-crypto-1.1`](https://github.com/Mbed-TLS/TF-PSA-Crypto/tree/tf-psa-crypto-1.1) + maintained until March 2029, see + . + +We use [Semantic Versioning](https://semver.org/). In particular, we maintain +API compatibility in the `main` branch across minor version changes (e.g. +the API of 1.(x+1) is backward compatible with 1.x). We only break API +compatibility on major version changes (e.g. from 1.x to 2.0). We also maintain +ABI compatibility within LTS branches; see the next section for details. + +We will make regular LTS releases on an 18-month cycle, each of which will have +a 3 year support lifetime. The release date of the first 1.x LTS is yet to be +determined. + +Mbed TLS currently maintains the LTS branch [`mbedtls-3.6`](https://github.com/Mbed-TLS/mbedtls/tree/mbedtls-3.6). +This branch contains the implementation of the PSA Cryptography API prior to the +Mbed TLS repository split. Any relevant bug fixes made in the TF-PSA-Crypto +development branch should be backported to this branch to ensure proper +maintenance. This does not apply to Mbed TLS LTS branches created after +the repository split, such as mbedtls-4.1. + +## Backwards Compatibility for application code + +We maintain API compatibility in released versions of TF-PSA-Crypto. If you +have code that's working and secure with TF-PSA-Crypto x.y.z and does not rely +on undocumented features, then you should be able to re-compile it without +modification with any later release x.y'.z' with the same major version +number, and your code will still build, be secure, and work. + +Note that this guarantee only applies if you either use the default +compile-time configuration (`psa/crypto_config.h`) or the same modified +compile-time configuration. Changing compile-time configuration options can +result in an incompatible API or ABI, although features will generally not +affect unrelated features (for example, enabling or disabling a +cryptographic algorithm does not break code that does not use that +algorithm). + +Note that new releases of TF-PSA-Crypto may extend the API. Here are some +examples of changes that are common in minor releases of TF-PSA-Crypto, and are +not considered API compatibility breaks: + +* Adding or reordering fields in a structure or union. +* Removing a field from a structure, unless the field is documented as public. +* Adding items to an enum. +* Returning an error code that was not previously documented for a function + when a new error condition arises. +* Changing which error code is returned in a case where multiple error + conditions apply. +* Changing the behavior of a function from failing to succeeding, when the + change is a reasonable extension of the current behavior, i.e. the + addition of a new feature. + +There are rare exceptions where we break API compatibility: code that was +relying on something that became insecure in the meantime (for example, +crypto that was found to be weak) may need to be changed. In case security +comes in conflict with backwards compatibility, we will put security first, +but always attempt to provide a compatibility option. + +## Backward compatibility for the key store + +We maintain backward compatibility with previous versions of the +PSA Crypto persistent storage since Mbed TLS 2.25.0, provided that the +storage backend (PSA ITS implementation) is configured in a compatible way. +We intend to maintain this backward compatibility throughout a major version +of TF-PSA-Crypto (for example, all TF-PSA-Crypto 1.y versions will be able to +read keys written under any TF-PSA-Crypto 1.x with x <= y). + +Future major version upgrades (for example from 1.x to 2.y) may require the use +of an upgrade tool. + +Note that this guarantee does not currently fully extend to drivers, which +are an experimental feature. We intend to maintain compatibility with the +basic use of drivers from Mbed TLS 2.28.0 onwards, even if driver APIs +change. However, for more experimental parts of the driver interface, such +as the use of driver state, we do not yet guarantee backward compatibility. + +## Long-time support branches + +For the LTS branches, additionally we try very hard to also maintain ABI +compatibility (same definition as API except with re-linking instead of +re-compiling) and to avoid any increase in code size or RAM usage, or in the +minimum version of tools needed to build the code. The only exception, as +before, is in case those goals would conflict with fixing a security issue, we +will put security first but provide a compatibility option. (So far we never +had to break ABI compatibility in an LTS branch, but we occasionally had to +increase code size for a security fix.) + +For contributors, see the [Backwards Compatibility section of +CONTRIBUTING](CONTRIBUTING.md#backwards-compatibility). + +## Current Branches + +The following branches are currently maintained: + +- [main](https://github.com/Mbed-TLS/TF-PSA-Crypto/tree/main) +- [`development`](https://github.com/Mbed-TLS/TF-PSA-Crypto/) +- [`tf-psa-crypto-1.1`](https://github.com/Mbed-TLS/TF-PSA-Crypto/tree/tf-psa-crypto-1.1) + maintained until March 2029, see + . diff --git a/tf-psa-crypto/BUGS.md b/tf-psa-crypto/BUGS.md new file mode 100644 index 0000000000..8d83b5e8ff --- /dev/null +++ b/tf-psa-crypto/BUGS.md @@ -0,0 +1,21 @@ +## Known issues + +Known issues in TF-PSA-Crypto are [tracked on GitHub](https://github.com/Mbed-TLS/TF-PSA-Crypto/issues). + +## Reporting a bug + +If you think you've found a bug in TF-PSA-Crypto, please follow these steps: + +1. Make sure you're using the latest version of a + [maintained branch](BRANCHES.md): `main`, `development`, + or a long-time support branch. +2. Check [GitHub](https://github.com/Mbed-TLS/TF-PSA-Crypto/issues) to see if + your issue has already been reported. If not, … +3. If the issue is a security risk (for example: buffer overflow, + data leak), please report it confidentially as described in + [`SECURITY.md`](SECURITY.md). If not, … +4. Please [create an issue on GitHub](https://github.com/Mbed-TLS/TF-PSA-Crypto/issues). + +Please do not use GitHub for support questions. If you want to know +how to do something with TF-PSA-Crypto, please see [`SUPPORT.md`](SUPPORT.md) +for available documentation and support channels. diff --git a/tf-psa-crypto/CMakeLists.txt b/tf-psa-crypto/CMakeLists.txt new file mode 100644 index 0000000000..7b03958db0 --- /dev/null +++ b/tf-psa-crypto/CMakeLists.txt @@ -0,0 +1,587 @@ +# +# CMake build system design considerations: +# +# - Include directories: +# + Do not define include directories globally using the include_directories +# command but rather at the target level using the +# target_include_directories command. That way, it is easier to guarantee +# that targets are built using the proper list of include directories. +# + Use the PUBLIC and PRIVATE keywords to specify the scope of include +# directories. That way, a target linking to a library (using the +# target_link_libraries command) inherits from the library PUBLIC include +# directories and not from the PRIVATE ones. +# - TF_PSA_CRYPTO_TARGET_PREFIX: CMake targets are designed to be alterable by +# calling CMake in order to avoid target name clashes, via the use of +# TF_PSA_CRYPTO_TARGET_PREFIX. The value of this variable is prefixed to the +# tfpsacrypto and tfpsacrypto-apidoc targets. +# + +# We specify a minimum requirement of 3.10.2, but for now use 3.5.1 here +# until our infrastructure catches up. +# Espressif: Updating the version to 3.10.2. CMake versions +# older than 3.10 are getting deprecated +cmake_minimum_required(VERSION 3.10.2) + +include(CMakePackageConfigHelpers) + +# Include convenience functions for printing properties and variables, like +# cmake_print_properties(), cmake_print_variables(). +include(CMakePrintHelpers) + +# https://cmake.org/cmake/help/latest/policy/CMP0011.html +# Setting this policy is required in CMake >= 3.18.0, otherwise a warning is generated. The OLD +# policy setting is deprecated, and will be removed in future versions. +cmake_policy(SET CMP0011 NEW) +# https://cmake.org/cmake/help/latest/policy/CMP0012.html +# Setting the CMP0012 policy to NEW is required for FindPython3 to work with CMake 3.18.2 +# (there is a bug in this particular version), otherwise, setting the CMP0012 policy is required +# for CMake versions >= 3.18.3 otherwise a deprecated warning is generated. The OLD policy setting +# is deprecated and will be removed in future versions. +cmake_policy(SET CMP0012 NEW) + +set(TF_PSA_CRYPTO_VERSION 1.1.0) +set(TF_PSA_CRYPTO_SOVERSION 2) + +if(TEST_CPP) + project("TF-PSA-Crypto" + LANGUAGES C CXX + VERSION ${TF_PSA_CRYPTO_VERSION} + ) +else() + project("TF-PSA-Crypto" + LANGUAGES C + VERSION ${TF_PSA_CRYPTO_VERSION} + ) +endif() + +include(GNUInstallDirs) + +# Determine if TF-PSA-Crypto is being built as a subproject using add_subdirectory() +if(NOT DEFINED TF_PSA_CRYPTO_AS_SUBPROJECT) + set(TF_PSA_CRYPTO_AS_SUBPROJECT ON) + if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(TF_PSA_CRYPTO_AS_SUBPROJECT OFF) + endif() +endif() + +# Set the project, Mbed TLS and framework root directory. +set(TF_PSA_CRYPTO_FRAMEWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/framework) + +# Put the version numbers into relevant files +# set(version_number_files +# doxygen/input/doc_mainpage.h +# doxygen/tfpsacrypto.doxyfile) +# foreach(file ${version_number_files}) +# configure_file(${file}.in +# ${TF_PSA_CRYPTO_DIR}/${file}) +# endforeach(file) + +ADD_CUSTOM_TARGET(${TF_PSA_CRYPTO_TARGET_PREFIX}tfpsacrypto-apidoc + COMMAND doxygen tfpsacrypto.doxyfile + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doxygen) + +option(ENABLE_PROGRAMS "Build TF-PSA-Crypto programs." ON) + +option(TF_PSA_CRYPTO_FATAL_WARNINGS "Compiler warnings treated as errors" ON) +if(CMAKE_HOST_WIN32) + # N.B. The comment on the next line is significant! If you change it, + # edit the sed command in prepare_release.sh that modifies + # CMakeLists.txt. + option(GEN_FILES "Generate the auto-generated files as needed" OFF) # off in development +else() + option(GEN_FILES "Generate the auto-generated files as needed" ON) +endif() + +# Support for package config and install to be added later. +option(DISABLE_PACKAGE_CONFIG_AND_INSTALL "Disable package configuration, target export and installation" ${TF_PSA_CRYPTO_AS_SUBPROJECT}) + +if (CMAKE_C_SIMULATE_ID) + set(COMPILER_ID ${CMAKE_C_SIMULATE_ID}) +else() + set(COMPILER_ID ${CMAKE_C_COMPILER_ID}) +endif(CMAKE_C_SIMULATE_ID) + +string(REGEX MATCH "Clang" CMAKE_COMPILER_IS_CLANG "${COMPILER_ID}") +string(REGEX MATCH "GNU" CMAKE_COMPILER_IS_GNU "${COMPILER_ID}") +string(REGEX MATCH "IAR" CMAKE_COMPILER_IS_IAR "${COMPILER_ID}") +string(REGEX MATCH "MSVC" CMAKE_COMPILER_IS_MSVC "${COMPILER_ID}") + +# the test suites currently have compile errors with MSVC +if(CMAKE_COMPILER_IS_MSVC) + option(ENABLE_TESTING "Build TF-PSA-Crypto tests." OFF) +else() + option(ENABLE_TESTING "Build TF-PSA-Crypto tests." ON) +endif() +option(TF_PSA_CRYPTO_TEST_DRIVER "Build TF-PSA-Crypto test driver for driver dispatch testing" OFF) + +option(USE_STATIC_TF_PSA_CRYPTO_LIBRARY "Build TF-PSA-Crypto static library." ON) +option(USE_SHARED_TF_PSA_CRYPTO_LIBRARY "Build TF-PSA-Crypto shared library." OFF) +option(LINK_WITH_PTHREAD "Explicitly link Mbed TLS library to pthread." OFF) +option(LINK_WITH_TRUSTED_STORAGE "Explicitly link Mbed TLS library to trusted_storage." OFF) +option(MSVC_STATIC_RUNTIME "Build the libraries with /MT compiler flag" OFF) + +set(tfpsacrypto_target "${TF_PSA_CRYPTO_TARGET_PREFIX}tfpsacrypto") +if (USE_STATIC_TF_PSA_CRYPTO_LIBRARY) + set(tfpsacrypto_static_target ${tfpsacrypto_target}) +endif() +if(USE_STATIC_TF_PSA_CRYPTO_LIBRARY AND USE_SHARED_TF_PSA_CRYPTO_LIBRARY) + string(APPEND tfpsacrypto_static_target "_static") +endif() + +# Python 3 is only needed here to check for configuration warnings. +if(NOT CMAKE_VERSION VERSION_LESS 3.15.0) + set(Python3_FIND_STRATEGY LOCATION) + find_package(Python3 COMPONENTS Interpreter) + if(Python3_Interpreter_FOUND) + set(TF_PSA_CRYPTO_PYTHON_EXECUTABLE ${Python3_EXECUTABLE}) + endif() +else() + find_package(PythonInterp 3) + if(PYTHONINTERP_FOUND) + set(TF_PSA_CRYPTO_PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE}) + endif() +endif() + +# We now potentially need to link all executables against PThreads, if available +set(CMAKE_THREAD_PREFER_PTHREAD TRUE) +set(THREADS_PREFER_PTHREAD_FLAG TRUE) +find_package(Threads) + +# If this is the root project add longer list of available CMAKE_BUILD_TYPE values +if(NOT TF_PSA_CRYPTO_AS_SUBPROJECT) + set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} + CACHE STRING "Choose the type of build: None Debug Release Coverage ASan ASanDbg MemSan MemSanDbg Check CheckFull TSan TSanDbg" + FORCE) +endif() + +# Make TF_PSA_CRYPTO_CONFIG_FILE and TF_PSA_CRYPTO_USER_CONFIG_FILE into PATHs +set(TF_PSA_CRYPTO_CONFIG_FILE "" CACHE FILEPATH "TF-PSA-Crypto config file (overrides default).") +set(TF_PSA_CRYPTO_USER_CONFIG_FILE "" CACHE FILEPATH "TF-PSA-Crypto user config file (appended to default).") +set(TF_PSA_CRYPTO_CONFIG_NAME "" CACHE STRING "Name of the configuration to use (see config.py documentation)") + +if(NOT "${TF_PSA_CRYPTO_CONFIG_NAME}" STREQUAL "") + if(NOT "${TF_PSA_CRYPTO_CONFIG_FILE}" STREQUAL "") + message(FATAL_ERROR "TF_PSA_CRYPTO_CONFIG_NAME and TF_PSA_CRYPTO_CONFIG_FILE are incompatible.") + endif() +endif(NOT "${TF_PSA_CRYPTO_CONFIG_NAME}" STREQUAL "") + +# Create a symbolic link from ${base_name} in the binary directory +# to the corresponding path in the source directory. +# Note: Copies the file(s) on Windows. +function(tf_psa_crypto_link_to_source base_name) + set(link "${CMAKE_CURRENT_BINARY_DIR}/${base_name}") + set(target "${CMAKE_CURRENT_SOURCE_DIR}/${base_name}") + + # Linking to non-existent file is not desirable. At best you will have a + # dangling link, but when building in tree, this can create a symbolic link + # to itself. + if (EXISTS ${target} AND NOT EXISTS ${link}) + if (CMAKE_HOST_UNIX) + execute_process(COMMAND ln -s ${target} ${link} + RESULT_VARIABLE result + ERROR_VARIABLE output) + + if (NOT ${result} EQUAL 0) + message(FATAL_ERROR "Could not create symbolic link for: ${target} --> ${output}") + endif() + else() + if (IS_DIRECTORY ${target}) + file(GLOB_RECURSE files FOLLOW_SYMLINKS LIST_DIRECTORIES false RELATIVE ${target} "${target}/*") + foreach(file IN LISTS files) + configure_file("${target}/${file}" "${link}/${file}" COPYONLY) + endforeach(file) + else() + configure_file(${target} ${link} COPYONLY) + endif() + endif() + endif() +endfunction(tf_psa_crypto_link_to_source) + +# Get the filename without the final extension (i.e. convert "a.b.c" to "a.b") +function(tf_psa_crypto_get_name_without_last_ext dest_var full_name) + # Split into a list on '.' (but a cmake list is just a ';'-separated string) + string(REPLACE "." ";" ext_parts "${full_name}") + # Remove the last item if there are more than one + list(LENGTH ext_parts ext_parts_len) + if (${ext_parts_len} GREATER "1") + math(EXPR ext_parts_last_item "${ext_parts_len} - 1") + list(REMOVE_AT ext_parts ${ext_parts_last_item}) + endif() + # Convert back to a string by replacing separators with '.' + string(REPLACE ";" "." no_ext_name "${ext_parts}") + # Copy into the desired variable + set(${dest_var} ${no_ext_name} PARENT_SCOPE) +endfunction(tf_psa_crypto_get_name_without_last_ext) + +include(CheckCCompilerFlag) + +set(CMAKE_C_EXTENSIONS OFF) +# Espressif: We set C standard in ESP-IDF build system +# No need to set it here +# set(CMAKE_C_STANDARD 99) + +# Set base compile options to be used for the compilation of all C files of +# all targets. +function(tf_psa_crypto_set_base_compile_options target) + if(CMAKE_COMPILER_IS_GNU) + tf_psa_crypto_set_gnu_base_compile_options(${target}) + elseif(CMAKE_COMPILER_IS_CLANG) + tf_psa_crypto_set_clang_base_compile_options(${target}) + elseif(CMAKE_COMPILER_IS_IAR) + tf_psa_crypto_set_iar_base_compile_options(${target}) + elseif(CMAKE_COMPILER_IS_MSVC) + tf_psa_crypto_set_msvc_base_compile_options(${target}) + endif() + if(TF_PSA_CRYPTO_TEST_DRIVER) + target_compile_definitions(${target} + PRIVATE "-DPSA_CRYPTO_DRIVER_TEST" + "-DMBEDTLS_TEST_LIBTESTDRIVER1" + "-DTF_PSA_CRYPTO_TEST_LIBTESTDRIVER1" + ) + endif() +endfunction(tf_psa_crypto_set_base_compile_options) + +function(tf_psa_crypto_set_gnu_base_compile_options target) + # some warnings we want are not available with old GCC versions + # note: starting with CMake 2.8 we could use CMAKE_C_COMPILER_VERSION + execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion + OUTPUT_VARIABLE GCC_VERSION) + target_compile_options(${target} PRIVATE -Wall -Wextra -Wwrite-strings -Wmissing-prototypes) + if (GCC_VERSION VERSION_GREATER 3.0 OR GCC_VERSION VERSION_EQUAL 3.0) + target_compile_options(${target} PRIVATE -Wformat=2 -Wno-format-nonliteral) + endif() + if (GCC_VERSION VERSION_GREATER 4.3 OR GCC_VERSION VERSION_EQUAL 4.3) + target_compile_options(${target} PRIVATE -Wvla) + endif() + if (GCC_VERSION VERSION_GREATER 4.5 OR GCC_VERSION VERSION_EQUAL 4.5) + target_compile_options(${target} PRIVATE -Wlogical-op) + endif() + if (GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8) + target_compile_options(${target} PRIVATE -Wshadow) + endif() + if (GCC_VERSION VERSION_GREATER 5.0) + CHECK_C_COMPILER_FLAG("-Wformat-signedness" C_COMPILER_SUPPORTS_WFORMAT_SIGNEDNESS) + if(C_COMPILER_SUPPORTS_WFORMAT_SIGNEDNESS) + target_compile_options(${target} PRIVATE -Wformat-signedness) + endif() + endif() + if (GCC_VERSION VERSION_GREATER 7.0 OR GCC_VERSION VERSION_EQUAL 7.0) + target_compile_options(${target} PRIVATE -Wformat-overflow=2 -Wformat-truncation) + endif() + target_compile_options(${target} PRIVATE $<$:-O2>) + target_compile_options(${target} PRIVATE $<$:-O0 -g3>) + target_compile_options(${target} PRIVATE $<$:-O0 -g3 --coverage>) + set_target_properties(${target} PROPERTIES LINK_FLAGS_COVERAGE "--coverage") + # Old GCC versions hit a performance problem with test_suite_pkwrite + # "Private keey write check EC" tests when building with Asan+UBSan + # and -O3: those tests take more than 100x time than normal, with + # test_suite_pkwrite taking >3h on the CI. Observed with GCC 5.4 on + # Ubuntu 16.04 x86_64 and GCC 6.5 on Ubuntu 18.04 x86_64. + # GCC 7.5 and above on Ubuntu 18.04 appear fine. + # To avoid the performance problem, we use -O2 when GCC version is lower than 7.0. + # It doesn't slow down much even with modern compiler versions. + target_compile_options(${target} PRIVATE $<$:-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all>) + if (GCC_VERSION VERSION_LESS 7.0) + target_compile_options(${target} PRIVATE $<$:-O2>) + else() + target_compile_options(${target} PRIVATE $<$:-O3>) + endif() + set_target_properties(${target} PROPERTIES LINK_FLAGS_ASAN "-fsanitize=address -fsanitize=undefined") + target_compile_options(${target} PRIVATE $<$:-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls>) + set_target_properties(${target} PROPERTIES LINK_FLAGS_ASANDBG "-fsanitize=address -fsanitize=undefined") + target_compile_options(${target} PRIVATE $<$:-fsanitize=thread -O3>) + set_target_properties(${target} PROPERTIES LINK_FLAGS_TSAN "-fsanitize=thread") + target_compile_options(${target} PRIVATE $<$:-fsanitize=thread -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls>) + set_target_properties(${target} PROPERTIES LINK_FLAGS_TSANDBG "-fsanitize=thread") + target_compile_options(${target} PRIVATE $<$:-Os>) + target_compile_options(${target} PRIVATE $<$:-Os -Wcast-qual>) + + if(TF_PSA_CRYPTO_FATAL_WARNINGS) + target_compile_options(${target} PRIVATE -Werror) + endif(TF_PSA_CRYPTO_FATAL_WARNINGS) +endfunction(tf_psa_crypto_set_gnu_base_compile_options) + +function(tf_psa_crypto_set_clang_base_compile_options target) + target_compile_options(${target} PRIVATE -Wall -Wextra -Wwrite-strings -Wmissing-prototypes -Wpointer-arith -Wimplicit-fallthrough -Wshadow -Wvla -Wformat=2 -Wno-format-nonliteral) + target_compile_options(${target} PRIVATE $<$:-O2>) + target_compile_options(${target} PRIVATE $<$:-O0 -g3>) + target_compile_options(${target} PRIVATE $<$:-O0 -g3 --coverage>) + set_target_properties(${target} PROPERTIES LINK_FLAGS_COVERAGE "--coverage") + target_compile_options(${target} PRIVATE $<$:-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O3>) + set_target_properties(${target} PROPERTIES LINK_FLAGS_ASAN "-fsanitize=address -fsanitize=undefined") + target_compile_options(${target} PRIVATE $<$:-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls>) + set_target_properties(${target} PROPERTIES LINK_FLAGS_ASANDBG "-fsanitize=address -fsanitize=undefined") + target_compile_options(${target} PRIVATE $<$:-fsanitize=memory>) + set_target_properties(${target} PROPERTIES LINK_FLAGS_MEMSAN "-fsanitize=memory") + target_compile_options(${target} PRIVATE $<$:-fsanitize=memory -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2>) + set_target_properties(${target} PROPERTIES LINK_FLAGS_MEMSANDBG "-fsanitize=memory") + target_compile_options(${target} PRIVATE $<$:-fsanitize=thread -O3>) + set_target_properties(${target} PROPERTIES LINK_FLAGS_TSAN "-fsanitize=thread") + target_compile_options(${target} PRIVATE $<$:-fsanitize=thread -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls>) + set_target_properties(${target} PROPERTIES LINK_FLAGS_TSANDBG "-fsanitize=thread") + target_compile_options(${target} PRIVATE $<$:-Os>) + + if(TF_PSA_CRYPTO_FATAL_WARNINGS) + target_compile_options(${target} PRIVATE -Werror) + endif(TF_PSA_CRYPTO_FATAL_WARNINGS) +endfunction(tf_psa_crypto_set_clang_base_compile_options) + +function(tf_psa_crypto_set_iar_base_compile_options target) + target_compile_options(${target} PRIVATE --warn_about_c_style_casts) + target_compile_options(${target} PRIVATE $<$:-Ohz>) + target_compile_options(${target} PRIVATE $<$:--debug -On>) + + if(TF_PSA_CRYPTO_FATAL_WARNINGS) + target_compile_options(${target} PRIVATE --warnings_are_errors) + endif(TF_PSA_CRYPTO_FATAL_WARNINGS) +endfunction(tf_psa_crypto_set_iar_base_compile_options) + +function(tf_psa_crypto_set_msvc_base_compile_options target) + # Strictest warnings, UTF-8 source and execution charset + target_compile_options(${target} PRIVATE /W3 /utf-8) + + if(TF_PSA_CRYPTO_FATAL_WARNINGS) + target_compile_options(${target} PRIVATE /WX) + endif(TF_PSA_CRYPTO_FATAL_WARNINGS) + + if(MSVC_STATIC_RUNTIME) + foreach(flag_var + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_C_FLAGS_CHECK) + string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") + endforeach(flag_var) + endif() +endfunction(tf_psa_crypto_set_msvc_base_compile_options) + + +# Set extra compile options. These options are expected to be set for the +# compilation of the TF-PSA-Crypto library files. Not necessarily for the test +# or third party driver files. +function(tf_psa_crypto_set_extra_compile_options target) + if(CMAKE_COMPILER_IS_GNU) + tf_psa_crypto_set_gnu_extra_compile_options(${target}) + elseif(CMAKE_COMPILER_IS_CLANG) + tf_psa_crypto_set_clang_extra_compile_options(${target}) + endif() +endfunction(tf_psa_crypto_set_extra_compile_options) + +function(tf_psa_crypto_set_gnu_extra_compile_options target) + target_compile_options(${target} PRIVATE -Wmissing-declarations) +endfunction(tf_psa_crypto_set_gnu_extra_compile_options) + +function(tf_psa_crypto_set_clang_extra_compile_options target) + target_compile_options(${target} PRIVATE + -Wmissing-declarations + -Wdocumentation + -Wno-documentation-deprecated-sync + -Wunreachable-code + ) +endfunction(tf_psa_crypto_set_clang_extra_compile_options) + + +function(tf_psa_crypto_set_config_files_compile_definitions target) + if(TF_PSA_CRYPTO_CONFIG_FILE) + target_compile_definitions(${target} + PUBLIC TF_PSA_CRYPTO_CONFIG_FILE="${TF_PSA_CRYPTO_CONFIG_FILE}") + endif() + if(TF_PSA_CRYPTO_USER_CONFIG_FILE) + target_compile_definitions(${target} + PUBLIC TF_PSA_CRYPTO_USER_CONFIG_FILE="${TF_PSA_CRYPTO_USER_CONFIG_FILE}") + endif() +endfunction(tf_psa_crypto_set_config_files_compile_definitions) + +if(CMAKE_BUILD_TYPE STREQUAL "Check" AND TEST_CPP) + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS OFF) + if(CMAKE_COMPILER_IS_CLANG OR CMAKE_COMPILER_IS_GNU) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic") + endif() +endif() + +# Espressif: We do not use framework submodule to build TF-PSA-Crypto +# if (NOT EXISTS "${TF_PSA_CRYPTO_FRAMEWORK_DIR}/CMakeLists.txt") +# message(FATAL_ERROR "${TF_PSA_CRYPTO_FRAMEWORK_DIR}/CMakeLists.txt not found. Run `git submodule update --init` from the source tree to fetch the submodule contents.") +# endif() + +# +# Directories with internal headers. The headers in that directories are not +# exposed to applications and thus not installed. These headers are currently +# consumed by Mbed TLS, eventually not so when we've finished cleaning up. +# Here we list all the directories containing such headers but the ones from +# drivers, that are appended in `drivers/CMakeLists.txt`. +# +set(TF_PSA_CRYPTO_PRIVATE_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/core + ${CMAKE_CURRENT_SOURCE_DIR}/dispatch + ${CMAKE_CURRENT_SOURCE_DIR}/extras + ${CMAKE_CURRENT_SOURCE_DIR}/platform + ${CMAKE_CURRENT_SOURCE_DIR}/utilities +) + +# +# `drivers` must be added before `core` because the build of the main library +# set up in `core` depends on the list of available drivers, which is +# constructed in `drivers/CMakeLists.txt`. This list may include a generated +# test driver. +# +# add_subdirectory(framework) +add_subdirectory(include) +add_subdirectory(drivers) # must precede core +add_subdirectory(extras) +add_subdirectory(platform) +add_subdirectory(utilities) +add_subdirectory(core) +add_subdirectory(pkgconfig) + +# +# The C files in tests/src directory contain test code shared among test suites +# and programs. This shared test code is compiled and linked to test suites and +# programs objects as a set of compiled objects. The compiled objects are NOT +# built into a library that the test suite and program objects would link +# against as they link against the tfpsacrypto library. The reason is that such +# library is expected to have mutual dependencies with the aforementioned +# library and that there is as of today no portable way of handling such +# dependencies (only toolchain specific solutions). +# +# Thus the below definition of the `tf_psa_crypto_test` CMake library of +# objects target. This library of objects is used by tests and programs CMake +# files to define the test executables. +# +if(ENABLE_TESTING OR ENABLE_PROGRAMS) + file(GLOB TF_PSA_CRYPTO_TEST_FILES + ${TF_PSA_CRYPTO_FRAMEWORK_DIR}/tests/src/*.c + ${TF_PSA_CRYPTO_FRAMEWORK_DIR}/tests/src/drivers/*.c + tests/src/*.c) + add_library(tf_psa_crypto_test OBJECT ${TF_PSA_CRYPTO_TEST_FILES}) + tf_psa_crypto_set_base_compile_options(tf_psa_crypto_test) + if(GEN_FILES) + add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/tests/include/test/test_keys.h + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/tests/include/test + COMMAND + "${TF_PSA_CRYPTO_PYTHON_EXECUTABLE}" + "${TF_PSA_CRYPTO_FRAMEWORK_DIR}/scripts/generate_test_keys.py" + "--output" + "${CMAKE_CURRENT_BINARY_DIR}/tests/include/test/test_keys.h" + DEPENDS + ${TF_PSA_CRYPTO_FRAMEWORK_DIR}/scripts/generate_test_keys.py + ) + add_custom_target(tf_psa_crypto_test_keys_header + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/tests/include/test/test_keys.h) + add_dependencies(tf_psa_crypto_test tf_psa_crypto_test_keys_header) + if(TF_PSA_CRYPTO_TEST_DRIVER) + add_dependencies(tf_psa_crypto_test ${TF_PSA_CRYPTO_TEST_DRIVER_GENERATION_TARGETS}) + endif() + endif() + + file(WRITE + ${CMAKE_CURRENT_BINARY_DIR}/tests/seedfile + "This is a seedfile that contains 64 bytes ......................" + ) + + # Note: "tests/include/test" exists solely to provide access to + # "mbedtls/build_info.h". That header is an alias of + # "tf-psa-crypto/build_info.h". + # + # It is included in framework headers and C modules because those + # components are also used in the Mbed TLS context. + target_include_directories(tf_psa_crypto_test + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/tests/include + ${TF_PSA_CRYPTO_FRAMEWORK_DIR}/tests/include + tests/include + tests/include/test + # Add the build-tree include directory before the source-tree one + # so that generated headers in the build tree take precedence. + ${CMAKE_CURRENT_BINARY_DIR}/include + include + ${TF_PSA_CRYPTO_PRIVATE_INCLUDE_DIRS}) + + foreach(driver_target ${TF_PSA_CRYPTO_DRIVER_TARGETS}) + get_target_property(public_includes ${driver_target} INTERFACE_INCLUDE_DIRECTORIES) + target_include_directories(tf_psa_crypto_test PUBLIC ${public_includes}) + endforeach() + + # Request C11, needed for memory poisoning tests + set_target_properties(tf_psa_crypto_test PROPERTIES C_STANDARD 11) + tf_psa_crypto_set_config_files_compile_definitions(tf_psa_crypto_test) +endif() + +if(ENABLE_PROGRAMS) + add_subdirectory(programs) +endif() + +if(ENABLE_TESTING) + enable_testing() + + add_subdirectory(tests) + + # additional convenience targets for Unix only + if(UNIX AND (NOT TF_PSA_CRYPTO_AS_SUBPROJECT)) + # For coverage testing: + # 1. Build with: + # cmake -D CMAKE_BUILD_TYPE=Coverage /path/to/source && make + # 2. Run the relevant tests for the part of the code you're interested in. + # For the reference coverage measurement, see + # tests/scripts/basic-build-test.sh + # 3. Run framework/scripts/lcov.sh to generate an HTML report. + ADD_CUSTOM_TARGET(lcov + COMMAND framework/scripts/lcov.sh + ) + + ADD_CUSTOM_TARGET(memcheck + COMMAND sed -i.bak s+/usr/bin/valgrind+`which valgrind`+ DartConfiguration.tcl + COMMAND ctest -O memcheck.log -D ExperimentalMemCheck + COMMAND tail -n1 memcheck.log | grep 'Memory checking results:' > /dev/null + COMMAND rm -f memcheck.log + COMMAND mv DartConfiguration.tcl.bak DartConfiguration.tcl + ) + endif() + + # Make scripts needed for testing available in an out-of-source build. + if (NOT ${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) + tf_psa_crypto_link_to_source(scripts) + # Copy (don't link) DartConfiguration.tcl, needed for memcheck, to + # keep things simple with the sed commands in the memcheck target. + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/DartConfiguration.tcl + ${CMAKE_CURRENT_BINARY_DIR}/DartConfiguration.tcl COPYONLY) + endif() +endif() + +if(NOT DISABLE_PACKAGE_CONFIG_AND_INSTALL) + configure_package_config_file( + "cmake/TF-PSA-CryptoConfig.cmake.in" + "cmake/TF-PSA-CryptoConfig.cmake" + INSTALL_DESTINATION "cmake") + + write_basic_package_version_file( + "cmake/TF-PSA-CryptoConfigVersion.cmake" + COMPATIBILITY SameMajorVersion + VERSION "${TF_PSA_CRYPTO_VERSION}") + + install( + FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/TF-PSA-CryptoConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/cmake/TF-PSA-CryptoConfigVersion.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/TF-PSA-Crypto") + + export( + EXPORT TF-PSA-CryptoTargets + NAMESPACE TF-PSA-Crypto:: + FILE "cmake/TF-PSA-CryptoTargets.cmake") + + install( + EXPORT TF-PSA-CryptoTargets + NAMESPACE TF-PSA-Crypto:: + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/TF-PSA-Crypto" + FILE "TF-PSA-CryptoTargets.cmake") + + if(CMAKE_VERSION VERSION_GREATER 3.15 OR CMAKE_VERSION VERSION_EQUAL 3.15) + # Do not export the package by default + cmake_policy(SET CMP0090 NEW) + + # Make this package visible to the system + export(PACKAGE TF-PSA-Crypto) + endif() +endif() diff --git a/tf-psa-crypto/CONTRIBUTING.md b/tf-psa-crypto/CONTRIBUTING.md new file mode 100644 index 0000000000..18bcc21c66 --- /dev/null +++ b/tf-psa-crypto/CONTRIBUTING.md @@ -0,0 +1,95 @@ +Contributing +============ +We gratefully accept bug reports and contributions from the community. All PRs are reviewed by the project team / community, and may need some modifications to +be accepted. + +Quick Checklist for PR contributors +----------------------------------- +More details on all of these points may be found in the sections below. + +- [Sign-off](#license-and-copyright): all commits must be signed off. +- [Tests](#tests): please ensure the PR includes adequate tests. +- [Changelog](#documentation): if needed, please provide a changelog entry. +- [Backports](#long-term-support-branches): provide a backport if needed (it's fine to wait until the main PR is accepted). + +Coding Standards +---------------- +- Contributions should include tests, as mentioned in the [Tests](#tests) and [Continuous Integration](#continuous-integration-tests) sections. Please check that your contribution passes basic tests before submission, and check the CI results after making a pull request. +- The code should be written in a clean and readable style, and must follow [our coding standards](https://mbed-tls.readthedocs.io/en/latest/kb/development/mbedtls-coding-standards/). +- The code should be written in a portable generic way, that will benefit the whole community, and not only your own needs. +- The code should be secure, and will be reviewed from a security point of view as well. + +Making a Contribution +--------------------- +1. [Check for open issues](https://github.com/Mbed-TLS/TF-PSA-Crypto/issues) or [start a discussion](https://lists.trustedfirmware.org/mailman3/lists/mbed-tls.lists.trustedfirmware.org) around a feature idea or a bug. +1. Fork the [TF-PSA-Crypto repository on GitHub](https://github.com/Mbed-TLS/TF-PSA-Crypto) to start making your changes. As a general rule, you should use the ["development" branch](https://github.com/Mbed-TLS/TF-PSA-Crypto/tree/development) as a basis. +1. Write a test which shows that the bug was fixed or that the feature works as expected. +1. Send a pull request (PR) and work with us until it gets merged and published. Contributions may need some modifications, so a few rounds of review and fixing may be necessary. See our [review process guidelines](https://mbed-tls.readthedocs.io/en/latest/reviews/review-for-contributors/). +1. For quick merging, the contribution should be short, and concentrated on a single feature or topic. The larger the contribution is, the longer it would take to review it and merge it. + +Backwards Compatibility +----------------------- + +The project aims to minimise the impact on users upgrading to newer versions of the library and it should not be necessary for a user to make any changes to their own code to work with a newer version of the library. Unless the user has made an active decision to use newer features, a newer generation of the library or a change has been necessary due to a security issue or other significant software defect, no modifications to their own code should be necessary. To achieve this, API compatibility is maintained between different versions of TF-PSA-Crypto on the main development branch and in LTS (Long Term Support) branches, as described in [BRANCHES.md](BRANCHES.md). + +To minimise such disruption to users, where a change to the interface is required, all changes to the ABI or API, even on the main development branch where new features are added, need to be justifiable by either being a significant enhancement, new feature or bug fix which is best resolved by an interface change. If there is an API change, the contribution, if accepted, will be merged only when there is a major release. + +No changes are permitted to the definition of functions in the public interface which will change the API. Instead the interface can only be changed by its extension. Where changes to an existing interface are necessary, functions in the public interface which need to be changed are marked as 'deprecated'. If there is a strong reason to replace an existing function with one that has a slightly different interface (different prototype, or different documented behavior), create a new function with a new name with the desired interface. Keep the old function, but mark it as deprecated. + +Periodically, the library will remove deprecated functions from the library which will be a breaking change in the API, but such changes will be made only in a planned, structured way that gives sufficient notice to users of the library. + +Long Term Support Branches +-------------------------- +TF-PSA-Crypto aim to provide LTS (Long Term Support) branches, which are maintained continuously for a given period. The release date of the first 1.x LTS is yet to be determined. The LTS branches are provided to allow users of the library to have a maintained, stable version of the library which contains only security fixes and fixes for other defects, without encountering additional features or API extensions which may introduce issues or change the code size or RAM usage, which can be significant considerations on some platforms. To allow users to take advantage of the LTS branches, these branches maintain backwards compatibility for both the public API and ABI. + +When backporting to these branches please observe the following rules: + +1. Any change to the library which changes the API or ABI cannot be backported. +1. All bug fixes that correct a defect that is also present in an LTS branch must be backported to that LTS branch. If a bug fix introduces a change to the API such as a new function, the fix should be reworked to avoid the API change. API changes without very strong justification are unlikely to be accepted. +1. If a contribution is a new feature or enhancement, no backporting is required. Exceptions to this may be additional test cases or quality improvements such as changes to build or test scripts. + +It would be highly appreciated if contributions are backported to LTS branches in addition to the [development branch](https://github.com/Mbed-TLS/TF-PSA-Crypto/tree/development) by contributors. + +The list of maintained branches can be found in the [Current Branches section +of BRANCHES.md](BRANCHES.md#current-branches). + +Tests +----- +As mentioned, tests that show the correctness of the feature or bug fix should be added to the pull request, if no such tests exist. + +TF-PSA-Crypto includes a comprehensive set of test suites in the `tests/` directory that are dynamically generated to produce the actual test source files (e.g. `test_suite_psa_crypto.c`). These files are generated from a `function file` (e.g. `suites/test_suite_psa_crypto.function`) and a `data file` (e.g. `suites/test_suite_psa_crypto.data`). The function file contains the test functions. The data file contains the test cases, specified as parameters that will be passed to the test function. + +[A Knowledge Base article describing how to add additional tests is available on the Mbed TLS website](https://mbed-tls.readthedocs.io/en/latest/kb/development/test_suites/). + +A test script `tests/scripts/basic-build-test.sh` is available to show test coverage of the library. New code contributions should provide a similar level of code coverage to that which already exists for the library. + +Sample applications, if needed, should be modified as well. + +Continuous Integration Tests +---------------------------- +Once a PR has been made, the Continuous Integration (CI) tests are triggered and run. You should follow the result of the CI tests, and fix failures. + +Documentation +------------- +TF-PSA-Crypto is well documented, but if you think documentation is needed, speak out! + +1. All interfaces should be documented through Doxygen. New APIs should introduce Doxygen documentation. +1. Complex parts in the code should include comments. +1. If needed, a Readme file is advised. +1. If a [Knowledge Base (KB)](https://mbed-tls.readthedocs.io/en/latest/kb/) article should be added, write this as a comment in the PR description. +1. A [ChangeLog](https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/ChangeLog.d/00README.md) entry should be added for this contribution. + +License and Copyright +--------------------- + +Unless specifically indicated otherwise in a file, TF-PSA-Crypto files are provided under a dual [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) OR [GPL-2.0-or-later](https://spdx.org/licenses/GPL-2.0-or-later.html) license. See the [LICENSE](LICENSE) file for the full text of these licenses. This means that users may choose which of these licenses they take the code under. + +Contributors must accept that their contributions are made under both the Apache-2.0 AND [GPL-2.0-or-later](https://spdx.org/licenses/GPL-2.0-or-later.html) licenses. + +All new files should include the standard SPDX license identifier where possible, i.e. "SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later". + +The copyright on contributions is retained by the original authors of the code. Where possible for new files, this should be noted in a comment at the top of the file in the form: "Copyright The Mbed TLS Contributors". + +When contributing code to us, the committer and all authors are required to make the submission under the terms of the [Developer Certificate of Origin](dco.txt), confirming that the code submitted can (legally) become part of the project, and is submitted under both the Apache-2.0 AND GPL-2.0-or-later licenses. + +This is done by including the standard Git `Signed-off-by:` line in every commit message. If more than one person contributed to the commit, they should also add their own `Signed-off-by:` line. diff --git a/tf-psa-crypto/ChangeLog b/tf-psa-crypto/ChangeLog new file mode 100644 index 0000000000..b446664996 --- /dev/null +++ b/tf-psa-crypto/ChangeLog @@ -0,0 +1,653 @@ += TF-PSA-Crypto 1.1.0 branch released 2026-03-31 + +Removals + * The undocumented ability to load persistent keys outside the user key ID + range has been removed. (This does not affect + MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS.) + * The headers no longer define 'inline' as a macro. This was done on Arm + Compiler 5 and MSVC. The compiler versions that needed this definition are + no longer supported since TF-PSA-Crypto 1.0. + +Features + * The automatic computation of MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE has + been improved to take into account the following key types: + asymmetric keys, ciphers, AEADs, CMAC and HMAC. + * mbedtls_pk_write_pubkey_psa() is introduced to allow exporting the public + key from a PK context in a format that can easily be imported into PSA. + * Implement SHAKE (PSA_ALG_SHAKE128, PSA_ALG_SHAKE256). + * The device for reading entropy on platforms without a dedicated system + call can now be configured with MBEDTLS_PLATFORM_DEV_RANDOM or + mbedtls_platform_dev_random. + * Applications can use the new functions psa_random_reseed() to + request an immediate reseed of the PSA random generator, or + psa_random_deplete() to force a reseed on the next random generator call. + * Applications can call psa_random_set_prediction_resistance() to toggle + prediction resistance in the PSA random generator. + +Security + * The default device for reading entropy on platforms without a dedicated + system call is now /dev/random instead of /dev/urandom. This is safer + on Linux in case the application runs early after the kernel boots, + but may block needlessly on Linux <= 5.6. Reported by supers1ngular + (BayLibre). + * Fix missing validation of the peer's key in key agreement operations using + PSA_ALG_FFDH: low-order elements were not rejected as they should be. This + is a problem for protocols using FFDH that expect contributory behaviour, + that is, where neither party should be able to force the shared secret + into a small set. Reported independently by Eva Crystal (0xiviel) and ++ another reporter. + * Add tag length validation in mbedtls_ccm_finish() to prevent + out-of-bounds reads and mitigate potential application buffer + overflows where applications relied on the library to enforce + tag length constraints. + Reported by Eva Crystal (0xiviel). + * Fix a buffer overflow in psa_export_public_key() for FFDH keys when the + output buffer is too small. Found by Haruto Kimura (Stella). + * If an application called psa_crypto_init() then fork() and continued to + use cryptography APIs (possibly indirectly, e.g. for TLS), the random + generator states were duplicated. Fix this by forcing a RNG reseed in + the child process. CVE-2026-25835 + * Applications running in environments where the application state is + cloned (for example due to resuming a frozen system state multiple + times, or due to cloning a virtual machine image) should arrange to + reseed the random generator using one of the new functions + psa_random_reseed() or psa_random_deplete(). CVE-2026-25835 + +Bugfix + * Appease GCC 14.3's array bounds checker by inserting checks in mbedtls_xor + that bail before the byte-at-a-time loop when the array size is a constant + (using MBEDTLS_HAS_BUILTIN) and an exact multiple of the larger loop size. + * CMake now installs headers to `CMAKE_INSTALL_INCLUDEDIR` instead of the + hard-coded `include` directory. + * Fix CMake package version that was inconsistent with the product version. + Fixes #553. + * Fix CMake failure on Windows because of a native directory separator. + Fixes Mbed-TLS/mbedtls#10502. + * Partially fix a performance regression in RSA operations introduced by a + security fix in 1.0, by improving the performance of RSA private key + operations when MBEDTLS_RSA_NO_CRT is disabled, which is the default. + * Fix compilation errors in `aesce.c` in some Visual Studio builds. + Fixes #548. + * Interruptible operations (ECDH key agreement, ECC key generation) were not + actually interruptible (always completed in one go) in builds with ECDSA + disabled. + * Built-in SHA3 was included in the build even when SHA3 had a PSA + accelerator. Fix this. Fixes #542. + * Fix a bug that caused GCM tag calculations to fail, so that data was + correctly encrypted but could not be authenticated. The bug was only + observed with GCC 10.0 to 14.2 inclusive, when compiling with -O3, and + running without AESNI or AESCE. + Fixes #665. + * Fix a build failure with dietlibc. + * Some functions in PK were using large buffers (around 2KB in the default + configuration) on the stack, which was a problem in environments with a + small stack. Those buffers are now allocated on the heap, except in + configurations where ECC is the only supported key type in PK, making PK + still independent of the heap in such configurations (if the ECC driver + itself is not using the heap). Fixes #476. + +Changes + * ChaCha20 size and performance: add a Neon implementation of ChaCha20 for + Thumb2 and 32 and 64-bit Arm, for Armv7 onwards. At default settings, + this improves performance by around 2x to 2.7x on Aarch64. + * Add a new function, mbedtls_pk_get_key_type(), which returns the PSA + key type corresponding to the type of the key represented by the + given PK object. + * Running the unit tests now requires a heap (possibly from + MBEDTLS_MEMORY_BUFFER_ALLOC_C). They now use less stack (almost + 5000 bytes less). + * Static assertions in the library (`MBEDTLS_STATIC_ASSERT`) are now + always enabled, using indirect methods in pre-C11 compilers. This change + also fixes warnings in pedantic mode with GCC or Clang on some platforms. + * Tweak the detection of Unix-like platforms, which makes more system + interfaces (timing, threading) available on Haiku, QNX and Midipix. + * On MinGW, always use a standard-compliant printf function family. + * Non-driver files have been moved out of `drivers/builtin/src` into three + new directories at the root of the repository: + - `extras`: modules implemented on top of the PSA Cryptography API, or + providing functionality beyond it (for example, the LMS stateful hash + implementation currently). + - `platform`: modules implementing the platform abstraction layer. + - `utilities`: utility modules used by the built-in drivers, the PSA + Cryptography API implementation, modules in `extras`, and potentially + by security protocols such as TLS. + * A new directory `dispatch` has been added at the root of the repository + to eventually host all code that dispatches cryptographic operations to + drivers, such as `psa_crypto_driver_wrappers_no_static.c`. For the time + being, it only contains `psa_crypto_driver_wrappers_no_static.h`. + += TF-PSA-Crypto 1.0.0 branch released 2025-10-15 + +API changes + * The experimental functions psa_generate_key_ext() and + psa_key_derivation_output_key_ext() have been replaced by + psa_generate_key_custom() and psa_key_derivation_output_key_custom(). + They have almost exactly the same interface, but the variable-length + data is passed in a separate parameter instead of a flexible array + member. This resolves a build failure under C++ compilers that do not + support flexible array members (a C99 feature not adopted by C++). + Fixes #9020. + * The PSA and Mbed TLS error spaces are now unified. mbedtls_xxx() + functions can now return PSA_ERROR_xxx values. + This will not affect most applications since the error values are + between -32767 and -1 as before. + * Remove MBEDTLS_PK_RSA_ALT from the PK module. + * MBEDTLS_ERR_PK_SIG_LEN_MISMATCH is no longer a distinct error code. + A valid signature with trailing garbage is now reported as an invalid + signature with all algorithms. + * All API functions now use the PSA random generator psa_generate_random() + internally. As a consequence, functions no longer take RNG parameters. + Please refer to the migration guide at : + docs/4.0-migration-guide.md. + * Privatize the functions mbedtls_ecc_group_to_psa and + mbedtls_ecc_group_from_psa. + * Remove the functions mbedtls_ecc_group_to_psa() and + mbedtls_ecc_group_from_psa(), which are no longer meaningful since + ECC groups are no longer exposed directly in the API. + * mbedtls_pk_verify_ext() ignores the options parameter when an + MBEDTLS_PK_RSASSA_PSS context type is used. The function assumes that + salt length is any and that the hash algorithm used for message, encoding + and MGF1 is the same. An error will be returned if any of these assumptions + is false. + * Align the mbedtls_nist_kw_wrap() and mbedtls_nist_kw_unwrap() functions + with the PSA Crypto API. The functions mbedtls_nist_kw_wrap() and + mbedtls_nist_kw_unwrap() now take a PSA key identifier instead of a + plain-text key via a custom context. + * Remove mbedtls_pk_encrypt() and mbedtls_pk_decrypt(). Convert the + key to PSA and use the PSA functions instead, see the migration guide for + details. + * Change MBEDTLS_ERR_ECP_IN_PROGRESS to be an alias of + PSA_OPERATION_INCOMPLETE and MBEDTLS_ERR_RSA_VERIFY_FAILED to be an alias + of PSA_ERROR_INVALID_SIGNATURE. + * Rename mbedtls_pk_setup_opaque to mbedtls_pk_wrap_psa. + * The custom entropy collector callback mbedtls_hardware_poll() + (enabled by MBEDTLS_ENTROPY_HARDWARE_ALT) has been replaced by a + new callback mbedtls_platform_get_entropy() with different parameters + (enabled by MBEDTLS_PSA_DRIVER_GET_ENTROPY). See the new function's + documentation and “Custom entropy collector” in the migration guide. + * To build the library with only a nonvolatile seed and no actual entropy + source, you now need to enable the new option + MBEDTLS_ENTROPY_NO_SOURCES_OK. + * Due to the entropy configuration changes, if you write a configuration file + from scratch, the default entropy source MBEDTLS_PSA_BUILTIN_GET_ENTROPY + now needs to be enabled explicitly. + * The configuration options MBEDTLS_CTR_DRBG_RESEED_INTERVAL and + MBEDTLS_HMAC_DRBG_RESEED_INTERVAL have been replaced by a unified + setting of MBEDTLS_PSA_RNG_RESEED_INTERVAL. + * The configuration option MBEDTLS_ENTROPY_FORCE_SHA256 has been removed. + MBEDTLS_PSA_CRYPTO_RNG_HASH can now be used to select the entropy + module's hashing algorithm. + * The mutex functions provided by platforms where MBEDTLS_THREADING_ALT is + enabled have changed in minor ways: + - The type of mutex objects provided by the platform functions is + now called mbedtls_platform_mutex_t, distinct from the API type + mbedtls_threading_mutex_t. + - The mutex_init function now returns an error code. + - Mutex functions other than mutex_init can now assume that the mutex + has been successfully initialized. + * The Random Number Generator configuration options have been refactored. + The following options have been removed: + MBEDTLS_ENTROPY_C, MBEDTLS_ENTROPY_FORCE_SHA256, + MBEDTLS_ENTROPY_MAX_GATHER, MBEDTLS_ENTROPY_MAX_SOURCES, + MBEDTLS_CTR_DRBG_ENTROPY_LEN, MBEDTLS_CTR_DRBG_MAX_INPUT, + MBEDTLS_CTR_DRBG_MAX_REQUEST, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT, + MBEDTLS_CTR_DRBG_USE_128_BIT_KEY, MBEDTLS_HMAC_DRBG_MAX_INPUT, + MBEDTLS_HMAC_DRBG_MAX_REQUEST, MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT and + MBEDTLS_PSA_HMAC_DRBG_MD_TYPE. + The following options have been introduced: + MBEDTLS_PSA_CRYPTO_RNG_HASH and MBEDTLS_PSA_CRYPTO_RNG_STRENGTH. + See "Random number generation configuration" in the migration guide for + more information. + * The following PK interfaces are now private and should no longer be used. + mbedtls_pk_type_t + mbedtls_pk_debug_type + mbedtls_pk_debug_item + MBEDTLS_PK_DEBUG_MAX_ITEMS + mbedtls_pk_info_from_type() + mbedtls_pk_setup() + mbedtls_pk_get_len() + mbedtls_pk_can_do() + mbedtls_pk_can_do_ext() + mbedtls_pk_debug() + mbedtls_pk_get_name() + mbedtls_pk_get_type() + mbedtls_pk_rsa() + mbedtls_pk_ec() + mbedtls_pk_parse_subpubkey() + mbedtls_pk_write_pubkey() + mbedtls_pk_verify_new() + * The hmac parameter of the mbedtls_md_setup() function must now always be + set to 0 as HMAC is no longer supported by MD. To use HMAC, please use + the psa_mac_ API. + * Make the following error codes aliases of their PSA equivalents, where + xxx is a module, e.g. ASN1 or PK. + MBEDTLS_ERR_xxx_BAD_INPUT[_DATA] -> PSA_ERROR_INVALID_ARGUMENT + MBEDTLS_ERR_xxx_ALLOC_FAILED -> PSA_ERROR_INSUFFICIENT_MEMORY + MBEDTLS_ERR_xxx_[AUTH/VERIFY]_FAILED -> PSA_ERROR_INVALID_SIGNATURE + MBEDTLS_ERR_xxx_BUFFER_TOO_SMALL -> PSA_ERROR_BUFFER_TOO_SMALL + MBEDTLS_ERR_xxx_OUTPUT_TOO_LARGE -> PSA_ERROR_BUFFER_TOO_SMALL + MBEDTLS_ERR_xxx_INVALID_PADDING -> PSA_ERROR_INVALID_PADDING + * A PK context no longer associates specific algorithms with the key, except + when wrapping a PSA key. In particular, after mbedtls_pk_copy_from_psa() or + mbedtls_pk_copy_public_from_psa() on an RSA key, the functions + mbedtls_pk_get_psa_attributes(), mbedtls_pk_sign() and mbedtls_pk_verify() + will use PKCS#1v1.5 signature or encryption, regardless of the original + key's policy. + +Default behavior changes + * In a PSA-client-only build (i.e. MBEDTLS_PSA_CRYPTO_CLIENT && + !MBEDTLS_PSA_CRYPTO_C), do not automatically enable local crypto when the + corresponding PSA mechanism is enabled, since the server provides the + crypto. Fixes #9126. + * The PK module now always uses the PSA subsystem + to perform cryptographic operations, with a few exceptions documented + in docs/architecture/psa-migration/psa-limitations.md. This + corresponds to the behavior of Mbed TLS 3.x when + MBEDTLS_USE_PSA_CRYPTO is enabled. In effect, MBEDTLS_USE_PSA_CRYPTO + is now always enabled. + * psa_crypto_init() must be called before performing any cryptographic + operation, including indirect requests such as parsing a key or + certificate or starting a TLS handshake. + * The `PSA_WANT_XXX` symbols as defined in + tf-psa-crypto/include/psa/crypto_config.h are now always used in the + configuration of the cryptographic mechanisms exposed by the PSA API. + This corresponds to the configuration behavior of Mbed TLS 3.x when + MBEDTLS_PSA_CRYPTO_CONFIG is enabled. In effect, MBEDTLS_PSA_CRYPTO_CONFIG + is now always enabled and the configuration option has been removed. + +Requirement changes + * Implementations of MBEDTLS_THREADING_ALT must now provide condition + variables in addition to mutexes. + +Removals + * Drop support for crypto alt interface. Removes MBEDTLS_XXX_ALT options + at the module and function level for crypto mechanisms only. The remaining + alt interfaces for platform, threading and timing are unchanged. + Fixes #8149. + * Drop support for VIA Padlock. Removes MBEDTLS_PADLOCK_C. + Fixes #5903. + * Remove many MBEDTLS_ERR_xxx error codes, superseded by PSA_ERROR_xxx. + See the 4.0 migration guide for details. + * Support for dynamic secure elements (i.e. MBEDTLS_PSA_CRYPTO_SE_C) was + already marked as deprecated and it has been removed. + * Removed the MBEDTLS_PSA_INJECT_ENTROPY configuration option from + crypto_config.h. The functionality that this option was enabling will be + reintroduced as part of the work on issue #8150. + * MBEDTLS_NO_PLATFORM_ENTROPY and the previously deprecated + MBEDTLS_ENTROPY_HARDWARE_ALT are removed. See the documentation of + MBEDTLS_PLATFORM_GET_ENTROPY_ALT for a description on how the entropy + module gathers entropy data. + * MBEDTLS_ENTROPY_MIN_HARDWARE is also removed following the removal of + MBEDTLS_ENTROPY_HARDWARE_ALT. + * TF-PSA-Crypto does not provide an OID API. A subset of the OID + interfaces of Mbed TLS 3.x are now in the X.509 library in + Mbed TLS 4.x. + * Removed the MBEDTLS_SHA3_C configuration option from crypto_config.h. + SHA3 can now be configured with the PSA_WANT_SHA3_* options. + * The library no longer offers interfaces to look up values by OID + or OID by enum values. The compilation option MBEDTLS_OID_C no longer + exists. OID tables are included in the build automatically as needed. + OIDs that are not relevant to TF-PSA-Crypto have been removed. + * Remove the function mbedtls_asn1_get_mpi() from the public interface. + It is replaced by mbedtls_asn1_get_integer(). + * Remove mbedtls_asn1_write_mpi() from the public API. This has been replaced + by mbedtls_asn1_write_integer(), which does not use the legacy mbedtls_mpi + type. + * Remove the legacy HKDF module (mbedtls_hkdf_xxx enabled by + MBEDTLS_HKDF_C). Use PSA instead (psa_key_derivation_xxx with + PSA_ALG_HKDF, enabled by PSA_WANT_ALG_HKDF). + * Remove mbedtls_asn1_free_named_data(). Use + mbedtls_asn1_free_named_data_list() or + mbedtls_asn1_free_named_data_list_shallow() instead. + * The options MBEDTLS_NO_PLATFORM_ENTROPY, + MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES, MBEDTLS_ENTROPY_HARDWARE_ALT and + MBEDTLS_ENTROPY_MIN_HARDWARE have been removed. Entropy sources are + now controlled by MBEDTLS_PSA_BUILTIN_GET_ENTROPY and + MBEDTLS_PSA_DRIVER_GET_ENTROPY. See “Entropy configuration” in the + migration guide for more information. + * MBEDTLS_PLATFORM_GET_ENTROPY_ALT, introduced in TF-PSA-Crypto 1.0.0-beta, + has been removed in favor of MBEDTLS_PSA_DRIVER_GET_ENTROPY. + * Remove the PKCS12 module, which provided the ability to read keys + encrypted with PKCS#5 v1.5 PBES1 with a DES-based cipher. + * Removed the `psa_pake_set_password_key()` function to comply + with the PSA API 1.2 PAKE extension. + * Removed the `psa_pake_get_implicit_key()` function. Removed to comply + with PSA API 1.2 PAKE extension. + * Support for EC curves secp224r1, secp224k1, secp192k1 and secp192r1 is + removed. + * mbedtls_pk_rsassa_pss_options has been removed from the interface. + * The configuration options MBEDTLS_MD5_C, MBEDTLS_RIPEMD160_C, + MBEDTLS_SHA1_C, MBEDTLS_SHA224_C, MBEDTLS_SHA256_C, MBEDTLS_SHA384_C and + MBEDTLS_SHA512_C have been removed. Support for hash algorithms can now + only be enabled through the hash-related `PSA_WANT_XXX` symbols. See + psa-transition.md for more information. + + * The configuration options MBEDTLS_AES_C, MBEDTLS_ARIA_C, + MBEDTLS_CAMELLIA_C, MBEDTLS_CCM_C, MBEDTLS_CHACHA20_C, + MBEDTLS_CHACHAPOLY_C, MBEDTLS_CIPHER_C, MBEDTLS_CIPHER_MODE_CBC, + MBEDTLS_CIPHER_MODE_CFB, MBEDTLS_CIPHER_MODE_CTR, MBEDTLS_CIPHER_MODE_OFB, + MBEDTLS_CIPHER_MODE_XTS, MBEDTLS_CIPHER_NULL_CIPHER, + MBEDTLS_CIPHER_PADDING_PKCS7, MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS, + MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN, MBEDTLS_CIPHER_PADDING_ZEROS, + MBEDTLS_CMAC_C, MBEDTLS_DES_C MBEDTLS_GCM_C and MBEDTLS_POLY1305_C have + been removed. Support for ciphers and AEAD algorithms can now only be + enabled through the cipher and AEAD related `PSA_WANT_XXX` symbols. The + only padding mode now supported in CBC cipher mode is PKCS7. See + psa-transition.md for more information. + + * The configuration options MBEDTLS_GENPRIME, MBEDTLS_PKCS1_V15, + MBEDTLS_PKCS1_V21 and MBEDTLS_RSA_C have been removed. Support for + RSA algorithms can now only be enabled through the RSA-related + `PSA_WANT_XXX` symbols. See psa-transition.md for more information. + + * The configuration options MBEDTLS_ECDH_C, MBEDTLS_ECDSA_C, + MBEDTLS_ECDSA_DETERMINISTIC, MBEDTLS_ECJPAKE_C, MBEDTLS_ECP_C, + MBEDTLS_ECP_DP_BP256R1_ENABLED, MBEDTLS_ECP_DP_BP384R1_ENABLED, + MBEDTLS_ECP_DP_BP512R1_ENABLED, MBEDTLS_ECP_DP_CURVE25519_ENABLED, + MBEDTLS_ECP_DP_CURVE448_ENABLED, MBEDTLS_ECP_DP_SECP192K1_ENABLED, + MBEDTLS_ECP_DP_SECP192R1_ENABLED, MBEDTLS_ECP_DP_SECP224R1_ENABLED, + MBEDTLS_ECP_DP_SECP256K1_ENABLED, MBEDTLS_ECP_DP_SECP256R1_ENABLED, + MBEDTLS_ECP_DP_SECP384R1_ENABLED, MBEDTLS_ECP_DP_SECP521R1_ENABLE have + been removed. Support for algorithms based on elliptic curves can now + only be enabled through the elliptic-curve-related `PSA_WANT_XXX` symbols. + See psa-transition.md for more information. + + * The configuration option MBEDTLS_BIGNUM_C has been removed. Support for + big number calculations is now enabled internally only when required by + enabled asymmetric cryptographic algorithms. + * Removed the ability to customize psa_can_do_hash() and + psa_can_do_cipher(), which allowed hash or cipher operations to be + performed through a legacy implementation when PSA is not yet fully + initialized. + * The following options have been removed as + they are deprecated: + PSA_WANT_KEY_TYPE_ECC_KEY_PAIR + PSA_WANT_KEY_TYPE_RSA_KEY_PAIR + MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR + MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR + MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR + MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR + MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT + MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY + * Deprecated PSA key handle related functions and macros are removed: + psa_open_key() and psa_close_key() functions, PSA_KEY_HANDLE_INIT + macro and psa_key_handle_t type. + * Deprecated PSA custom Diffie-Hellman group support functions and macros + are removed: psa_get_key_domain_parameters() and + psa_set_key_domain_parameters() functions, PSA_DH_FAMILY_CUSTOM and + PSA_KEY_DOMAIN_PARAMETERS_SIZE macros. + * The following functions have been removed from the MD module: + mbedtls_md_list() + mbedtls_md_info_from_string() + mbedtls_md_get_name() + mbedtls_md_info_from_ctx() + mbedtls_md_file() + mbedtls_md_hmac_starts() + mbedtls_md_hmac_update() + mbedtls_md_hmac_finish() + mbedtls_md_hmac_reset() + mbedtls_md_hmac() + To use HMAC, please use the psa_mac_ API. Looking up hash algorithms by + name is no longer supported. + * Removed DES (including 3DES) + +Features + * Added new configuration option MBEDTLS_PSA_STATIC_KEY_SLOTS, which + uses static storage for keys, enabling malloc-less use of key slots. + The size of each buffer is given by the option + MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE. By default it accommodates the + largest PSA key enabled in the build. + * Add an interruptible version of generate key to the PSA interface. + See psa_generate_key_iop_setup() and related functions. + * Add an interruptible version of key agreement to the PSA interface. + See psa_key_agreement_iop_setup() and related functions. + * Add a new psa_key_agreement() PSA API to perform key agreement and return + an identifier for the newly created key. + * When the new compilation option MBEDTLS_PSA_KEY_STORE_DYNAMIC is enabled, + the number of volatile PSA keys is virtually unlimited, at the expense + of increased code size. This option is off by default, but enabled in + the default mbedtls_config.h. Fixes #9216. + * Add an interruptible version of export public-key to the PSA interface. + See psa_export_public_key_iop_setup() and related functions. + * MD module can now perform PSA dispatching also when + `MBEDTLS_PSA_CRYPTO_CLIENT && !MBEDTLS_PSA_CRYPTO_C`, even though this + configuration is not officially supported. This requires that a + PSA Crypto provider library which: + * supports the required `PSA_WANT_ALG_xxx` and + * implements `psa_can_do_hash()` on the client interface + is linked against Mbed TLS and that `psa_crypto_init()` is called before + performing any PSA call. + * Add a program (which_aes) that uses an internal function to print out + the current implementation of AES, i.e. software, AESCE, AESNI assembly, + or AESNI intrinsics. + * To supply a platform-specific entropy source, define the compilation option + MBEDTLS_PLATFORM_GET_ENTROPY_ALT and provide the callback function + mbedtls_platform_get_entropy_alt(). This function should typically access + a TRNG ("true hardware random generator") device on bare-metal platforms, + or call an operating system function to obtain cryptographic-quality random + data. Mbed TLS requires that a minimum of 32 bytes (not configurable) are + returned from this function for a successful entropy gathering round. + * The new function mbedtls_asn1_get_integer() parses an integer into a byte + array. It replaces mbedtls_asn1_get_mpi(). + * Add a new function mbedtls_asn1_write_integer() that encodes an arbitrary + precision integer into ASN.1 DER format. This function replaces + mbedtls_asn1_write_mpi(), which has been made internal-only. + * Introduce macros and functions for getting the current version of + TF-PSA-Crypto at build time and at runtime. These can be accessed + by including "tf-psa-crypto/version.h". + * Helper symbol MBEDTLS_PK_ALG_ECDSA is added to the public "mbedtls/pk.h" + header file. It exposes the ECDSA variant used by the PK module. + * The threading platform abstraction now exposes condition variables + in addition to mutexes. + * Function mbedtls_pk_can_do_psa() is added to allow testing PK context + capabilities against a specified algorithm and usage. + * Users can set the macro TF_PSA_CRYPTO_CONFIG_VERSION in the TF-PSA-Crypto + config file to maximize backward compatibility in case of future changes + to how the config file is interpreted. TF-PSA-Crypto will maintain + backward compatibility on functional matters (except at major version + changes, e.g. from 1.x.y to 2.0), but the config version may influence + other aspect such as optimisations, or experimental options. + +Security + * Fix a buffer underrun in mbedtls_pk_write_key_der() when + called on an opaque key, MBEDTLS_USE_PSA_CRYPTO is enabled, + and the output buffer is smaller than the actual output. + Fix a related buffer underrun in mbedtls_pk_write_key_pem() + when called on an opaque RSA key, MBEDTLS_USE_PSA_CRYPTO is enabled + and MBEDTLS_MPI_MAX_SIZE is smaller than needed for a 4096-bit RSA key. + CVE-2024-49195 + * Unlike previously documented, enabling MBEDTLS_PSA_HMAC_DRBG_MD_TYPE does + not cause the PSA subsystem to use HMAC_DRBG: it uses HMAC_DRBG only when + MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG and MBEDTLS_CTR_DRBG_C are disabled. + CVE-2024-45157 + * Fix a stack buffer overflow in mbedtls_ecdsa_der_to_raw() and + mbedtls_ecdsa_raw_to_der() when the bits parameter is larger than the + largest supported curve. In some configurations with PSA disabled, + all values of bits are affected. This never happens in internal library + calls, but can affect applications that call these functions directly. + CVE-2024-45158 + * Zeroize a temporary heap buffer used in psa_key_derivation_output_key() + when deriving an ECC key pair. + * Zeroize temporary heap buffers used in PSA operations. + * Fix a buffer overread in mbedtls_lms_import_public_key() when the input is + less than 3 bytes. Reported by Linh Le and Ngan Nguyen from Calif. + CVE-2025-49601 + * Fix a vulnerability in LMS verification through which an adversary could + get an invalid signature accepted if they could cause a hash accelerator + to fail. Found and reported by Linh Le and Ngan Nguyen from Calif. + CVE-2025-49600 + * On x86/amd64 platforms, with some compilers, when the library is + compiled with support for both AESNI and software AES and AESNI is + available in hardware, an adversary with fine control over which + threads make progress in a multithreaded program could force software + AES to be used for some time when the program starts. This could allow + the adversary to conduct timing attacks and potentially recover the + key. In particular, this attacker model may be possible against an SGX + enclave. + The same vulnerability affects GCM acceleration, which could allow + a similarly powerful adversary to craft GCM forgeries. + CVE-2025-52496 + * Fix a bug in mbedtls_asn1_store_named_data() where it would sometimes leave + an item in the output list in an inconsistent state with val.p == NULL but + val.len > 0. Functions using the structure after that, including + mbedtls_asn1_store_named_data() itself would then dereference a NULL + pointer. Applications that do not call this function are not affected. + Found by Linh Le and Ngan Nguyen from Calif. + CVE-2025-48965 + * Fix an integer underflow that could occur when parsing malformed PEM + keys, which could be used by an attacker capable of feeding encrypted + PEM keys to a user. This could cause a crash or information disclosure. + Found and reported by Linh Le and Ngan Nguyen from Calif. + CVE-2025-52497 + * Fix a timing side channel in the implementation of PKCS#7 padding + which would allow an attacker who can request decryption of arbitrary + ciphertexts to recover the plaintext through a timing oracle attack. + Reported by Ka Lok Wu from Stony Brook University and Doria Tang from + The Chinese University of Hong Kong. + CVE-2025-49087 + * Fix a timing side channel in CBC-PKCS7 decryption that could + allow an attacker who can submit chosen ciphertexts to recover + some plaintexts through a timing-based padding oracle attack. + Credits to Beat Heeb from Oberon microsystems AG. CVE-2025-59438 + * Fix a local timing side-channel in modular inversion and GCD that was + exploitable in RSA key generation and other RSA operations (see the full + advisory for details), allowing a local attacker to fully recover the + private key. This can be exploited on some Arm-v9 CPUs by an unprivileged + attacker running code on the same core (SSBleed), or when Trustzone-M is + used, by the non-secure side abusing timer interrupts (M-Step), and + probably in other similar settings as well. Found and reported + independently by: SSBleed: Chang Liu (Tsinghua University) and Trevor E. + Carlson (National University of Singapore); M-Step: Cristiano Rodrigues + (University of Minho), Marton Bognar (DistriNet, KU Leuven), Sandro Pinto + (University of Minho), Jo Van Bulck (DistriNet, KU Leuven). CVE-2025-54764 + +Bugfix + * MBEDTLS_ASN1_PARSE_C and MBEDTLS_ASN1_WRITE_C are now automatically enabled + as soon as MBEDTLS_RSA_C is enabled. Fixes #9041. + * Fix interference between PSA volatile keys and built-in keys + when MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS is enabled and + MBEDTLS_PSA_KEY_SLOT_COUNT is more than 4096. + * Fix missing constraints on the AES-NI inline assembly which is used on + GCC-like compilers when building AES for generic x86_64 targets. This + may have resulted in incorrect code with some compilers, depending on + optimizations. Fixes #9819. + * Fix rare concurrent access bug where attempting to operate on a + non-existent key while concurrently creating a new key could potentially + corrupt the key store. + * Fix invalid JSON schemas for driver descriptions used by + generate_driver_wrappers.py. + * Fix the build when MBEDTLS_PSA_CRYPTO_CONFIG is enabled and the built-in + CMAC is enabled, but no built-in unauthenticated cipher is enabled. + Fixes #9209. + * Fix issue of redefinition warning messages for _GNU_SOURCE in + entropy_poll.c and sha_256.c. There was a build warning during + building for linux platform. + Resolves #9026 + * Fix unintended performance regression when using short RSA public keys. + Fixes #9232. + * Fix error handling when creating a key in a dynamic secure element + (feature enabled by MBEDTLS_PSA_CRYPTO_SE_C). In a low memory condition, + the creation could return PSA_SUCCESS but using or destroying the key + would not work. Fixes #8537. + * Fix redefinition warnings when SECP192R1 and/or SECP192K1 are disabled. + Fixes #9029. + * Fix undefined behaviour (incrementing a NULL pointer by zero length) when + passing in zero length additional data to multipart AEAD. + * Document and enforce the limitation of mbedtls_psa_register_se_key() + to persistent keys. Resolves #9253. + * Fix a memory leak that could occur when failing to process an RSA + key through some PSA functions due to low memory conditions. + * Fix a compilation warning in pk.c when PSA is enabled and RSA is disabled. + * Fix psa_cipher_decrypt() with CCM* rejecting messages less than 3 bytes + long. Credit to Cryptofuzz. Fixes #9314. + * Fix undefined behavior in some cases when mbedtls_psa_raw_to_der() or + mbedtls_psa_der_to_raw() is called with bits=0. + * When MBEDTLS_PSA_CRYPTO_C was disabled and MBEDTLS_ECDSA_C enabled, + some code was defining 0-size arrays, resulting in compilation errors. + Fixed by disabling the offending code in configurations without PSA + Crypto, where it never worked. Fixes #9311. + * Remove Everest Visual Studio 2010 compatibility headers, which could + shadow standard CRT headers inttypes.h and stdbool.h with incomplete + implementatios if placed on the include path. + * Fix issue where psa_key_derivation_input_integer() is not detecting + bad state after an operation has been aborted. + * Fix failures of PSA multipart or interruptible operations when the + library or the application is built with a compiler where + "union foo x = {0}" does not initialize non-default members of the + union, such as GCC 15 and some versions of Clang 18. This affected MAC + multipart operations, MAC-based key derivation operations, interruptible + signature, interruptible verification, and potentially other operations + when using third-party drivers. This also affected one-shot MAC + operations using the built-in implementation. Fixes #9814. + * On entry to PSA driver entry points that set up a multipart operation + ("xxx_setup"), the operation object is supposed to be all-bits-zero. + This was sometimes not the case when an operation object is reused, + or with compilers where "union foo x = {0}" does not initialize + non-default members of the union. The PSA core now ensures that this + guarantee is met in all cases. Fixes #9975. + * Resolved build issue with C++ projects using TF-PSA-Crypto when compiling + with the MSVC toolset v142 and earlier. Fixes mbedtls issue #7087. + * Silence spurious -Wunterminated-string-initialization warnings introduced + by GCC 15. Fixes #9944. + * Fix a sloppy check in LMS public key import, which could lead to accepting + keys with a different LMS or LM-OTS types on some platforms. Specifically, + this could happen on platforms where enum types are smaller than 32 bits + and compiler optimization is enabled. Found and reported by Linh Le and + Ngan Nguyen from Calif. + * Fix a race condition on x86/amd64 platforms in AESNI support detection + that could lead to using software AES in some threads at the very + beginning of a multithreaded program. Reported by Solar Designer. + Fixes #9840. + * Fix mbedtls_base64_decode() on inputs that did not have the correct + number of trailing equal signs, or had 4*k+1 digits. They were accepted + as long as they had at most two trailing equal signs. They are now + rejected. Furthermore, before, on inputs with too few equal signs, the + function reported the correct size in *olen when it returned + MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL, but truncated the output to the + last multiple of 3 bytes. + * When calling mbedtls_asn1_write_raw_buffer() with NULL, 0 as the last two + arguments, undefined behaviour would be triggered, in the form of a call to + memcpy(..., NULL, 0). This was harmless in practice, but could trigger + complains from sanitizers or static analyzers. + * Fix occasional CMake parallel build failure when building both the + static and shared tfpsacrypto libraries. Fixes #286. + * PAKE returns PSA_ERROR_INVALID_SIGNATURE instead of PSA_ERROR_DATA_INVALID + when the signature in Schnorr NIZKP is invalid. + +Changes + * Cryptography and platform configuration options have been migrated + from the Mbed TLS library configuration file mbedtls_config.h to + crypto_config.h that is now the TF-PSA-Crypto configuration file. + The reference and test custom configuration files respectively in + configs/ and tests/configs/ have been updated accordingly. + To migrate custom Mbed TLS configurations where + MBEDTLS_PSA_CRYPTO_CONFIG is disabled, you should first adapt them + to the PSA configuration scheme based on PSA_WANT_XXX symbols + (see psa-conditional-inclusion-c.md for more information). + To migrate custom Mbed TLS configurations where + MBEDTLS_PSA_CRYPTO_CONFIG is enabled, you should migrate the + cryptographic and platform configuration options from mbedtls_config.h + to crypto_config.h (see the 4.0 configuration guide at + docs/4.0-migration-guide/configuration.md which includes + configuration details and examples). + * Improve performance of PSA key generation with ECC keys: it no longer + computes the public key (which was immediately discarded). Fixes #9732. + * Make the file p256-m.h internal, it is no longer installed or documented. + * Added the `key_confirmation` field to the PAKE cipher suite to conform to + PSA API 1.2 PAKE extension + * Added the `psa_pake_cs_get_key_confirmation()` function which retrieves + the value from a cipher suite, the `psa_pake_cs_set_key_confirmation()` + function which declares the value for a cipher suite + * Now the functionality of `psa_pake_set_password_key()` is implemented in + `psa_pake_setup()` function, as per the PSA API 1.2 PAKE extension. + * Changed the `PSA_ALG_JPAKE` macro to accommodate the hash algorithm + parameter, to be conformant to the PSA API 1.2 PAKE extension + * Added the `PSA_ALG_IS_JPAKE` macro to test whether a given algorithm is + JPAKE + * All tf-psa-crypto private headers were moved to a private subdirectory + * Implemented the `psa_pake_get_shared_key()` function, compliant with the + PSA API 1.2 PAKE extension, replacement for `psa_pake_get_implicit_key()` + += Mbed TLS 3.6.0 branch released 2024-03-28 +Please refer to the Mbed TLS changelog, available at +https://github.com/Mbed-TLS/mbedtls/blob/mbedtls-3.6.0/ChangeLog diff --git a/tf-psa-crypto/ChangeLog.d/00README.md b/tf-psa-crypto/ChangeLog.d/00README.md new file mode 100644 index 0000000000..7d14ad01c4 --- /dev/null +++ b/tf-psa-crypto/ChangeLog.d/00README.md @@ -0,0 +1,90 @@ +# Pending changelog entry directory + +This directory contains changelog entries that have not yet been merged +to the changelog file ([`../ChangeLog`](../ChangeLog)). + +## What requires a changelog entry? + +Write a changelog entry if there is a user-visible change. This includes: + +* Bug fixes in the library or in sample programs: fixing a security hole, + fixing broken behavior, fixing the build in some configuration or on some + platform, etc. +* New features in the library, new sample programs, or new platform support. +* Changes in existing behavior. These should be rare. Changes in features + that are documented as experimental may or may not be announced, depending + on the extent of the change and how widely we expect the feature to be used. + +We generally don't include changelog entries for: + +* Documentation improvements. +* Performance improvements, unless they are particularly significant. +* Changes to parts of the code base that users don't interact with directly, + such as test code and test data. +* Fixes for compiler warnings. Releases typically contain a number of fixes + of this kind, so we will only mention them in the Changelog if they are + particularly significant. + +Looking at older changelog entries is good practice for how to write a +changelog entry, but not for deciding whether to write one. + +## Changelog entry file format + +A changelog entry file must have the extension `*.txt` and must have the +following format: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Security + * Change description. + * Another change description. + +Features + * Yet another change description. This is a long change description that + spans multiple lines. + * Yet again another change description. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The permitted changelog entry categories are as follows: + + + API changes + Default behavior changes + Requirement changes + New deprecations + Removals + Features + Security + Bugfix + Changes + +Use “Changes” for anything that doesn't fit in the other categories. + +## How to write a changelog entry + +Each entry starts with three spaces, an asterisk and a space. Continuation +lines start with 5 spaces. Lines wrap at 79 characters. + +Write full English sentences with proper capitalization and punctuation. Use +the present tense. Use the imperative where applicable. For example: “Fix a +bug in mbedtls_xxx() ….” + +Include GitHub issue numbers where relevant. Use the format “#1234” for a +TF-PSA-Crypto issue. Add other external references such as CVE numbers where +applicable. + +Credit bug reporters where applicable. + +**Explain why, not how**. Remember that the audience is the users of the +library, not its developers. In particular, for a bug fix, explain the +consequences of the bug, not how the bug was fixed. For a new feature, explain +why one might be interested in the feature. For an API change or a deprecation, +explain how to update existing applications. + +See [existing entries](../ChangeLog) for examples. + +## How `ChangeLog` is updated + +Run [`../scripts/assemble_changelog.py`](../scripts/assemble_changelog.py) +from a Git working copy +to move the entries from files in `ChangeLog.d` to the main `ChangeLog` file. diff --git a/tf-psa-crypto/DartConfiguration.tcl b/tf-psa-crypto/DartConfiguration.tcl new file mode 100644 index 0000000000..af0578a581 --- /dev/null +++ b/tf-psa-crypto/DartConfiguration.tcl @@ -0,0 +1,4 @@ +Site: localhost +BuildName: Mbed TLS-test +CoverageCommand: /usr/bin/gcov +MemoryCheckCommand: /usr/bin/valgrind diff --git a/tf-psa-crypto/LICENSE b/tf-psa-crypto/LICENSE new file mode 100644 index 0000000000..4c47cb2a5a --- /dev/null +++ b/tf-psa-crypto/LICENSE @@ -0,0 +1,552 @@ +TF-PSA-Crypto files are provided under a dual [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) +OR [GPL-2.0-or-later](https://spdx.org/licenses/GPL-2.0-or-later.html) license. +This means that users may choose which of these licenses they take the code +under. + +The full text of each of these licenses is given below. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +=============================================================================== + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/tf-psa-crypto/README.md b/tf-psa-crypto/README.md new file mode 100644 index 0000000000..ada1e32126 --- /dev/null +++ b/tf-psa-crypto/README.md @@ -0,0 +1,388 @@ +README for TF-PSA-Crypto +======================== + +The TF-PSA-Crypto repository provides an implementation of the +[PSA Cryptography API version 1.2](https://arm-software.github.io/psa-api/crypto/1.2/), +with the limitation that the implementation of the [PAKE extension](https://arm-software.github.io/psa-api/crypto/1.2/ext-pake/) +still has minor non-compliances, such as returned error codes. + +The PSA Cryptography API implementation is organized around the +[PSA Cryptography driver interface](docs/proposed/psa-driver-interface.md) +aiming to ease the support of cryptographic accelerators and processors. + +PSA Cryptography API +--------------------- + +The [PSA Cryptography API](https://arm-software.github.io/psa-api/crypto/) +provides access to a set of cryptographic primitives. It has a dual purpose. +First, it can be used in a PSA-compliant platform to build services, such as +secure boot, secure storage and secure communication. Second, it can also be +used independently of other PSA components on any platform. + +The design goals of the PSA Cryptography API include: + +* The API distinguishes caller memory from internal memory, which allows the + library to be implemented in an isolated space for additional security. + Library calls can be implemented as direct function calls if isolation is not + desired, and as remote procedure calls if isolation is desired. +* The structure of internal data is hidden to the application, which allows + substituting alternative implementations at build time or run time, for example, + in order to take advantage of hardware accelerators. +* All access to the keys happens through key identifiers, which allows support + for external cryptoprocessors that is transparent to applications. +* The interface to algorithms is generic, favoring algorithm agility. +* The interface is designed to be easy to use and hard to accidentally misuse. + +We welcomes feedback on the design of the API. If you think something could be +improved, please open an issue on our Github repository. Alternatively, if you +prefer to provide your feedback privately, please email us at +[`mbed-crypto@arm.com`](mailto:mbed-crypto@arm.com). All feedback received by +email is treated confidentially. + +### PSA Cryptography API implementation in TF-PSA-Crypto + +TF-PSA-Crypto includes an implementation of the PSA Cryptography API. It covers +most, but not all algorithms. + +### PSA Cryptography driver interface + +TF-PSA-Crypto supports drivers for cryptographic accelerators, secure elements +and random generators. This is work in progress. Please note that the driver +interfaces are not fully stable yet and may change without notice. We intend to +preserve backward compatibility for application code (using the PSA Cryptography API), +but the code of the drivers may have to change in future minor releases of TF-PSA-Crypto. + +Please see the [PSA driver example and guide](docs/psa-driver-example-and-guide.md) +for information on writing a driver. + +Configuration +------------- + +The TF-PSA-Crypto repository should build out of the box on most systems. Its +configuration is based on C preprocessor macros defined in +`include/psa/crypto_config.h`. + +These configuration options are organized into seven groups: +1. Cryptographic mechanism selection (PSA API): PSA_WANT_xxx macros that + specify which parts of the PSA Cryptography API the user wants to enable, + e.g. cryptographic algorithms, key types, elliptic curves. +1. Platform abstraction layer: Options to port the library to different platforms. +1. General and test configuration options: Options that are test-specific or + not related to a particular part of the library. +1. Cryptographic mechanism selection (extended API): Options to enable + cryptographic mechanisms beyond the current PSA Cryptography API, such as LMS + or key wrapping. +1. Data format support: Options to enable support for various data formats, + such as ASN.1 or PEM. +1. PSA core: Options to configure components other than cryptographic mechanisms, + such as key management and random number generation. +1. Built-in drivers: Options to configure non-functional aspects of built-in + cryptographic mechanisms such as performance/size trade-offs. + +The file `include/psa/crypto_config.h` can be edited manually, or in a more +programmatic way using the Python script `scripts/config.py` (use `--help` for +usage instructions). + +We provide some non-standard configurations focused on specific use cases in the +`configs/` directory. You can read more about those in `configs/README.txt`. + +Documentation +------------- + +Documentation for the PSA Cryptography API is available [on GitHub](https://arm-software.github.io/psa-api/crypto/). + +To generate a local copy of the library documentation in HTML format: + +1. Make sure that [Doxygen](http://www.doxygen.nl/) is installed. +1. Run `cmake -B /path/to/build_dir /path/to/TF-PSA-Crypto/source` +1. Run `cmake --build /path/to/build_dir --target tfpsacrypto-apidoc` +1. Open one of the main generated HTML files: + * `apidoc/index.html` + * `apidoc/modules.html` or `apidoc/topics.html` + +Compiling +--------- + +The build system is CMake. +The CMake build system creates one library: libtfpsacrypto. + +### Tool versions + +You need the following tools to build the library from the main branch with the +provided CMake files. TF-PSA-Crypto minimum tool version requirements are set +based on the versions shipped in the latest or penultimate (depending on the +release cadence) long-term support releases of major Linux distributions, +namely at time of writing: Ubuntu 22.04, RHEL 9, and SLES 15 SP4. + +* A C99 toolchain (compiler, linker, archiver). We actively test with GCC 5.4, + Clang 3.8 and Arm Compiler 6.21. More recent versions should work. Slightly + older versions may work. +* Python 3.8 or later to generate some source files (see below), the test + code, and to generate sample programs. +* CMake 3.20.2 or later. +* A build system like Make or Ninja for which CMake can generate build files. +* Microsoft Visual Studio 2019 or later (if using Visual Studio). +* Doxygen 1.8.14 or later. + +### Git usage + +The supported branches (see [`BRANCHES.md`](BRANCHES.md)) use a [Git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules#_cloning_submodules), +[framework](https://github.com/TF-PSA-Crypto/mbedtls-framework). +Release tags also use Git submodules. + +After cloning or checking out a branch or tag, run: + ``` + git submodule update --init + ``` + to initialize and update the submodule before building. + +However, the official source release tarballs (e.g. [tf-psa-crypto-1.0.0.tar.bz2](https://github.com/Mbed-TLS/TF-PSA-Crypto/releases/download/tf-psa-crypto-1.0.0/tf-psa-crypto-1.0.0.tar.bz2)) +include the content of the submodule. + +### Generated source files in the development branch + +The source code of TF-PSA-Crypto includes some files that are automatically +generated by scripts and whose content depends only on the TF-PSA-Crypto source, +not on the platform or on the library configuration. These files are not included +in the development branch of TF-PSA-Crypto, but the generated files are included +in official releases. This section explains how to generate the missing files in +the development branch. + +The following tools are required: +* Python 3 and some Python packages, for some library source files, sample programs + and test data. To install the necessary packages, run: + ``` + python3 -m pip install --user -r scripts/basic.requirements.txt + ``` + Depending on your Python installation, you may need to invoke `python` instead + of `python3`. To install the packages system-wide or in a virtual environment, + omit the `--user` option. +* A C compiler for the host platform, for some test data. + +The scripts that generate the configuration-independent files will look for a +host C compiler in the following places (in order of preference): + +1. The `HOSTCC` environment variable. This can be used if `CC` is pointing to a + cross-compiler. +1. The `CC` environment variable. +1. An executable called `cc` in the current path. + +Note: If you have multiple toolchains installed, it is recommended to set `CC` +or `HOSTCC` to the intended host compiler before generating the files. + +Any of the following methods are available to generate the configuration-independent +files: + +* On non-Windows systems, when not cross-compiling, CMake generates the required + files automatically. +* Run `framework/scripts/make_generated_files.py` to generate all the + configuration-independent files. + +### CMake + +In order to build the source using CMake in a separate directory (recommended), +just enter at the command line: + + mkdir /path/to/build_dir && cd /path/to/build_dir + cmake /path/to/tf/psa/crypto/source + cmake --build . + +In order to run the tests, enter: + + ctest + +The test suites need Python to be built. If you don't have Python installed, +you'll want to disable the test suites with: + + cmake -DENABLE_TESTING=Off /path/to/tf/psa/crypto/source + +To configure CMake for building shared libraries, use: + + cmake -DUSE_SHARED_TF_PSA_CRYPTO_LIBRARY=On /path/to/tf/psa/crypto/source + +There are many different build modes available within the CMake build system. +Most of them are available for gcc and clang, though some are compiler-specific: + +- `Release`. This generates the default code without any unnecessary + information in the binary files. +- `Debug`. This generates debug information and disables optimization of the code. +- `ASan`. This instruments the code with AddressSanitizer to check for memory + errors. (This includes LeakSanitizer, with recent version of gcc and clang.) + (With recent version of clang, this mode also instruments the code with + UndefinedSanitizer to check for undefined behaviour.) +- `ASanDbg`. Same as ASan but slower, with debug information and better stack + traces. +- `MemSan`. This instruments the code with MemorySanitizer to check for + uninitialised memory reads. Experimental, needs recent clang on Linux/x86\_64. +- `MemSanDbg`. Same as MemSan but slower, with debug information, better stack + traces and origin tracking. +- `Check`. This activates the compiler warnings that depend on optimization and + treats all warnings as errors. +- `TSan`. This instruments the code with ThreadSanitizer to detect data races + and other threading-related concurrency issues at runtime. +- `TSanDbg`. Same as TSan but slower, with debug information, better stack + traces and origin tracking. + +Switching build modes in CMake is simple. For debug mode, enter at the command +line: + + cmake -D CMAKE_BUILD_TYPE=Debug /path/to/tf/psa/crypto/source + +To list other available CMake options, use: + + cmake -LH + +Note that, with CMake, you can't adjust the compiler or its flags after the +initial invocation of cmake. This means that `CC=your_cc make` and `make +CC=your_cc` will *not* work (similarly with `CFLAGS` and other variables). +These variables need to be adjusted when invoking cmake for the first time, +for example: + + CC=your_cc cmake /path/to/tf/psa/crypto/source + +If you already invoked cmake and want to change those settings, you need to +invoke the configuration phase of CMake again with the new settings. + +Note that it is possible to build in-place, use: + + cmake . + cmake --build . + +Regarding variables, also note that if you set CFLAGS when invoking cmake, +your value of CFLAGS doesn't override the content provided by CMake (depending +on the build mode as seen above), it's merely prepended to it. + +#### Consuming TF-PSA-Crypto + +TF-PSA-Crypto provides a CMake package configuration file for consumption as a +dependency in other CMake projects. You can load its CMake library target with: + + find_package(TF-PSA-Crypto) + +You can help CMake find the package: + +- By setting the variable `TF-PSA-Crypto_DIR` to `${YOUR_TF_PSA_CRYPTO_BUILD_DIR}/cmake`, + as shown in `programs/test/cmake_package/CMakeLists.txt`, or +- By adding the TF-PSA-Crypto installation prefix to `CMAKE_PREFIX_PATH`, + as shown in `programs/test/cmake_package_install/CMakeLists.txt`. + +After a successful `find_package(TF-PSA-Crypto)`, the target `TF-PSA-Crypto::tfpsacrypto` +is available. + +You can then use it directly through `target_link_libraries()`: + + add_executable(xyz) + + target_link_libraries(xyz PUBLIC TF-PSA-Crypto::tfpsacrypto) + +This will link the TF-PSA-Crypto library to your library or application, and +add its include directories to your target (transitively, in the case of +`PUBLIC` or `INTERFACE` link libraries). + +#### TF-PSA-Crypto as a subproject + +The TF-PSA-Crypto repository supports being built as a CMake subproject. One +can use `add_subdirectory()` from a parent CMake project to include +TF-PSA-Crypto as a subproject. + +### Microsoft Visual Studio + +The TF-PSA-Crypto library can be built with Microsoft Visual Studio Community +suitably installed as a CMake project. For a general documentation about +CMake projects in Visual Studio, please refer to its documentation. + +The following instructions have been tested on Microsoft Visual Studio Community +2019 Version 16.11.26. The TF-PSA-Crypto library and its tests build out of the +box with: +* Visual Studio Community installed with the default "Desktop development with C++" +and "Python development" workloads. +* Python libraries needed for code and test generation installed as defined +in basic.requirements.txt. Refer to the Visual Studio documentation of Python +environments. +* When cloning the TF-PSA-Crypto repository in Visual Studio, a +CMakeSettings.json is created at the root of the repository. In that file, add +the line `"environments": [ {"CC" : "cl"} ]` to the configuration. That way +when building the library and its tests, a CC environment variable is set with +value "cl". This is needed by Python scripts that generate test cases. The +CMakeSettings.json file can be edited in Visual Studio by following +Project > CMake Settings for TF-PSA-Crypto > Edit JSON. +* If necessary (it may have been done automatically when updating +CMakeSettings.json), generate the CMake cache: Project > Generate Cache +* Build the library: Build > Build All +* The test suites can then be run: Test > Run CTests for TF-PSA-Crypto + +Example programs +---------------- + +We've included example programs for different features and uses in +[`programs/`](programs/README.md). Please note that the goal of these sample +programs is to demonstrate specific features of the library, and the code may +need to be adapted to build a real-world application. + +Tests +----- + +The TF-PSA-Crypto repository includes an elaborate test suite in `tests/` that +initially requires Python to generate the tests files +(e.g. `test_suite_psa_crypto.c`). These files are generated from a +`function file` (e.g. `suites/test_suite_psa_crypto.function`) and a +`data file` (e.g. `suites/test_suite_psa_crypto.data`). The `function file` +contains the test functions. The `data file` contains the test cases, specified +as parameters that will be passed to the test function. + +Porting TF-PSA-Crypto +--------------------- + +TF-PSA-Crypto can be ported to many different architectures, OS's and platforms. +Before starting a port, you may find the following Knowledge Base articles useful: + +- [Porting Mbed TLS to a new environment or OS](https://mbed-tls.readthedocs.io/en/latest/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS/) +- [What external dependencies does Mbed TLS rely on?](https://mbed-tls.readthedocs.io/en/latest/kb/development/what-external-dependencies-does-mbedtls-rely-on/) +- [How do I configure Mbed TLS](https://mbed-tls.readthedocs.io/en/latest/kb/compiling-and-building/how-do-i-configure-mbedtls/) + +TF-PSA-Crypto is mostly written in portable C99; however, it has a few platform +requirements that go beyond the standard, but are met by most modern architectures: + +- Bytes must be 8 bits. +- All-bits-zero must be a valid representation of a null pointer. +- Signed integers must be represented using two's complement. +- `int` and `size_t` must be at least 32 bits wide. +- The types `uint8_t`, `uint16_t`, `uint32_t` and their signed equivalents must be available. +- Mixed-endian platforms are not supported. +- SIZE_MAX must be at least as big as INT_MAX and UINT_MAX. + +License +------- + +Unless specifically indicated otherwise in a file, TF-PSA-Crypto files are provided +under a dual [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) OR +[GPL-2.0-or-later](https://spdx.org/licenses/GPL-2.0-or-later.html) license. +See the [LICENSE](LICENSE) file for the full text of these licenses. + +### Third-party code included in TF-PSA-Crypto + +This project contains code from other projects. This code is located within the +`drivers/` directory. The original license text is included within project +subdirectories, where it differs from the normal Mbed TLS license, and/or in +source files. The projects are listed below: + +* `drivers/everest/`: Files stem from [Project Everest](https://project-everest.github.io/) + and are distributed under the Apache 2.0 license. +* `drivers/p256-m/p256-m/`: Files have been taken from the [p256-m](https://github.com/mpg/p256-m) + repository. The code in the original repository is distributed under the + Apache 2.0 license. It is distributed in TF-PSA-Crypto under a dual Apache-2.0 + OR GPL-2.0-or-later license with permission from the author. + +Contributing +------------ + +We gratefully accept bug reports and contributions from the community. Please +see the [contributing guidelines](CONTRIBUTING.md) for details on how to do this. + +Contact +------- + +* To report a security vulnerability in TF-PSA-Crypto, please email . For more information, see [`SECURITY.md`](SECURITY.md). +* To report a bug or request a feature in TF-PSA-Crypto, please [file an issue on GitHub](https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/new/choose). +* Please see [`SUPPORT.md`](SUPPORT.md) for other channels for discussion and +support about TF-PSA-Crypto. diff --git a/tf-psa-crypto/SECURITY.md b/tf-psa-crypto/SECURITY.md new file mode 100644 index 0000000000..46b7de53f9 --- /dev/null +++ b/tf-psa-crypto/SECURITY.md @@ -0,0 +1,146 @@ +## Reporting Vulnerabilities + +If you think you have found a security vulnerability in TF-PSA-Crypto, then +please send an email to the security team at +. + +## Security Incident Handling Process + +Our security process is detailed in our +[security +center](https://developer.trustedfirmware.org/w/mbed-tls/security-center/). + +Its primary goal is to ensure fixes are ready to be deployed when the issue +goes public. + +## Maintained branches + +Only the maintained branches, as listed in [`BRANCHES.md`](BRANCHES.md), +get security fixes. +Users are urged to always use the latest version of a maintained branch. + +## Threat model + +We classify attacks based on the capabilities of the attacker. + +### Remote attacks + +In this section, we consider an attacker who can observe and modify data sent +over the network. This includes observing the content and timing of individual +packets, as well as suppressing or delaying legitimate messages, and injecting +messages. + +The TF-PSA-Crypto library aims to fully protect against remote attacks. More +specifically, it aims to enable network protocol implementations that use it to +perform cryptographic operations, as well as applications based on such network +protocol implementations, to provide full protection against remote attacks. + +**Warning!** Block ciphers do not yet achieve full protection against attackers +who can measure the timing of packets with sufficient precision. For details +and workarounds see the [Block Ciphers](#block-ciphers) section. + +### Local attacks + +In this section, we consider an attacker who can run software on the same +machine. The attacker has insufficient privileges to directly access the +TF-PSA-Crypto library assets such as memory and files. + +#### Timing attacks + +The attacker is able to observe the timing of instructions executed by +the TF-PSA-Crypto library by leveraging shared hardware that both the +TF-PSA-Crypto library and the attacker have access to. Typical attack vectors +include cache timings, memory bus contention and branch prediction. + +TF-PSA-Crypto provides limited protection against timing attacks. The cost of +protecting against timing attacks widely varies depending on the granularity of +the measurements and the noise present. Therefore the protection in +TF-PSA-Crypto is limited. We are only aiming to provide protection against +**publicly documented attack techniques**. + +As attacks keep improving, so does TF-PSA-Crypto's protection. TF-PSA-Crypto is +moving towards a model of fully timing-invariant code, but has not reached this +point yet. + +**Remark:** Timing information can be observed over the network or through +physical side channels as well. Remote and physical timing attacks are covered +in the [Remote attacks](remote-attacks) and [Physical +attacks](physical-attacks) sections respectively. + +**Warning!** Block ciphers do not yet achieve full protection. For +details and workarounds see the [Block Ciphers](#block-ciphers) section. + +#### Local non-timing side channels + +The attacker code running on the platform has access to some sensor capable of +picking up information on the physical state of the hardware while the +TF-PSA-Crypto library is running. This could for example be an analogue-to-digital +converter on the platform that is located unfortunately enough to pick up the +CPU noise. + +TF-PSA-Crypto doesn't make any security guarantees against local non-timing-based +side channel attacks. If local non-timing attacks are present in a use case or +a user application's threat model, they need to be mitigated by the platform. + +#### Local fault injection attacks + +Software running on the same hardware can affect the physical state of the +device and introduce faults. + +TF-PSA-Crypto doesn't make any security guarantees against local fault injection +attacks. If local fault injection attacks are present in a use case or a user +application's threat model, they need to be mitigated by the platform. + +### Physical attacks + +In this section, we consider an attacker who has access to physical information +about the hardware the TF-PSA-Crypto library is running on and/or can alter the +physical state of the hardware (e.g. power analysis, radio emissions or fault +injection). + +TF-PSA-Crypto doesn't make any security guarantees against physical attacks. If +physical attacks are present in a use case or a user application's threat +model, they need to be mitigated by physical countermeasures. + +### Caveats + +#### Out-of-scope countermeasures + +TF-PSA-Crypto has evolved organically and a well defined threat model hasn't +always been present. Therefore, TF-PSA-Crypto might have countermeasures against +attacks outside the above defined threat model. + +The presence of such countermeasures don't mean that TF-PSA-Crypto provides +protection against a class of attacks outside of the above described threat +model. Neither does it mean that the failure of such a countermeasure is +considered a vulnerability. + +#### Block ciphers + +Currently there are four block ciphers in TF-PSA-Crypto: AES, CAMELLIA, ARIA and +DES. The pure software implementation of these block ciphers uses lookup +tables, which are vulnerable to timing attacks. + +These timing attacks can be physical, local or depending on network latency +even remote. The attacks can result in key recovery. + +**Workarounds:** + +- Turn on hardware acceleration for AES. This is supported only on selected + architectures and currently only available for AES. See configuration options + `TF_PSA_CRYPTO_AESCE_C` and `TF_PSA_CRYPTO_AESNI_C` for details. +- Add a secure alternative implementation (typically hardware acceleration) for + the vulnerable cipher. See the [PSA Cryptography Driver Interface]( + docs/proposed/psa-driver-interface.md) for more information. +- Use cryptographic mechanisms that are not based on block ciphers. In + particular, for authenticated encryption, use ChaCha20/Poly1305 instead of + block cipher modes. For random generation, use HMAC\_DRBG instead of CTR\_DRBG. + +#### Everest + +The HACL* implementation of X25519 taken from the Everest project only protects +against remote timing attacks. (See their [Security +Policy](https://github.com/hacl-star/hacl-star/blob/main/SECURITY.md).) + +The Everest variant is only used when `MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED` +configuration option is defined. This option is off by default. diff --git a/tf-psa-crypto/SUPPORT.md b/tf-psa-crypto/SUPPORT.md new file mode 100644 index 0000000000..972d2c48c0 --- /dev/null +++ b/tf-psa-crypto/SUPPORT.md @@ -0,0 +1,16 @@ +## Documentation + +Here are some useful sources of information about TF-PSA-Crypto: + +- API documentation, see the [Documentation section of the + README](README.md#documentation); +- the `docs` directory in the source tree; +- [Use PSA](https://mbed-tls.readthedocs.io/en/latest/getting_started/psa/); +- the [Mbed TLS Knowledge Base](https://mbed-tls.readthedocs.io/en/latest/kb/); +- the [Mbed TLS mailing-list + archives](https://lists.trustedfirmware.org/archives/list/mbed-tls@lists.trustedfirmware.org/). + +## Asking Questions + +If you can't find your answer in the above sources, please use the [Mbed TLS +mailing list](https://lists.trustedfirmware.org/mailman3/lists/mbed-tls.lists.trustedfirmware.org). diff --git a/tf-psa-crypto/cmake/.gitignore b/tf-psa-crypto/cmake/.gitignore new file mode 100644 index 0000000000..fc852627cf --- /dev/null +++ b/tf-psa-crypto/cmake/.gitignore @@ -0,0 +1 @@ +TF-PSA-CryptoConfig.cmake diff --git a/tf-psa-crypto/cmake/TF-PSA-CryptoConfig.cmake.in b/tf-psa-crypto/cmake/TF-PSA-CryptoConfig.cmake.in new file mode 100644 index 0000000000..94a9195e0b --- /dev/null +++ b/tf-psa-crypto/cmake/TF-PSA-CryptoConfig.cmake.in @@ -0,0 +1,3 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/TF-PSA-CryptoTargets.cmake") diff --git a/tf-psa-crypto/configs/README.txt b/tf-psa-crypto/configs/README.txt new file mode 100644 index 0000000000..ee1677b207 --- /dev/null +++ b/tf-psa-crypto/configs/README.txt @@ -0,0 +1,20 @@ +This directory contains example configuration files. + +The examples are generally focused on a particular usage case (eg, support for +a restricted number of cryptographic mechanisms) and aim at minimizing resource +usage for this target. They can be used as a basis for custom configurations. + +These files are complete replacements for the default crypto_config.h. To use +one of them, you can pick one of the following methods: + +1. Replace the default file include/psa/crypto_config.h with the chosen one. + +2. Use the TF_PSA_CRYPTO_CONFIG_FILE CMake option. For example, to build + out-of-tree with the crypto-config-ccm-aes-sha256.h configuration file: + + cmake -DTF_PSA_CRYPTO_CONFIG_FILE="configs/crypto-config-ccm-aes-sha256.h" \ + -B build-ccmonly + cmake --build build-ccmonly + +The second method also works if you want to keep your custom configuration +file outside the TF-PSA-Crypto tree. diff --git a/tf-psa-crypto/configs/crypto-config-ccm-aes-sha256.h b/tf-psa-crypto/configs/crypto-config-ccm-aes-sha256.h new file mode 100644 index 0000000000..1592708313 --- /dev/null +++ b/tf-psa-crypto/configs/crypto-config-ccm-aes-sha256.h @@ -0,0 +1,28 @@ +/** + * \file configs/crypto-config-ccm-aes-sha256.h + * + * \brief PSA crypto configuration with only symmetric cryptography: CCM-AES, + * SHA-256 and key derivation (uses HMAC). + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef PSA_CRYPTO_CONFIG_H +#define PSA_CRYPTO_CONFIG_H + +#define PSA_WANT_ALG_CCM 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_TLS12_PRF 1 +#define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 +#define PSA_WANT_KEY_TYPE_DERIVE 1 +#define PSA_WANT_KEY_TYPE_AES 1 +#define PSA_WANT_KEY_TYPE_RAW_DATA 1 + + +#define MBEDTLS_PSA_CRYPTO_C +#define MBEDTLS_CTR_DRBG_C +#define MBEDTLS_PSA_BUILTIN_GET_ENTROPY + +#endif /* PSA_CRYPTO_CONFIG_H */ diff --git a/tf-psa-crypto/configs/crypto-config-symmetric-only.h b/tf-psa-crypto/configs/crypto-config-symmetric-only.h new file mode 100644 index 0000000000..39e9e4d778 --- /dev/null +++ b/tf-psa-crypto/configs/crypto-config-symmetric-only.h @@ -0,0 +1,87 @@ +/** + * \file crypto-config-symmetric-only.h + * + * \brief Crypto configuration without any asymmetric cryptography. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +/** + * To be used in conjunction with configs/config-symmetric-only.h. */ + +#ifndef PSA_CRYPTO_CONFIG_H +#define PSA_CRYPTO_CONFIG_H + +#define PSA_WANT_ALG_CBC_NO_PADDING 1 +#define PSA_WANT_ALG_CBC_PKCS7 1 +#define PSA_WANT_ALG_CCM 1 +#define PSA_WANT_ALG_CCM_STAR_NO_TAG 1 +#define PSA_WANT_ALG_CFB 1 +#define PSA_WANT_ALG_CHACHA20_POLY1305 1 +#define PSA_WANT_ALG_CMAC 1 +#define PSA_WANT_ALG_CTR 1 +#define PSA_WANT_ALG_ECB_NO_PADDING 1 +#define PSA_WANT_ALG_GCM 1 +#define PSA_WANT_ALG_HKDF 1 +#define PSA_WANT_ALG_HKDF_EXTRACT 1 +#define PSA_WANT_ALG_HKDF_EXPAND 1 +#define PSA_WANT_ALG_HMAC 1 +#define PSA_WANT_ALG_MD5 1 +#define PSA_WANT_ALG_OFB 1 +#define PSA_WANT_ALG_RIPEMD160 1 +#define PSA_WANT_ALG_SHA_1 1 +#define PSA_WANT_ALG_STREAM_CIPHER 1 +#define PSA_WANT_ALG_SHA_224 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_SHA_384 1 +#define PSA_WANT_ALG_SHA_512 1 +#define PSA_WANT_ALG_SHA3_224 1 +#define PSA_WANT_ALG_SHA3_256 1 +#define PSA_WANT_ALG_SHA3_384 1 +#define PSA_WANT_ALG_SHA3_512 1 +#define PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS 1 +#define PSA_WANT_ALG_TLS12_PRF 1 +#define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 + +/* XTS is not yet supported via the PSA API in Mbed TLS. */ +//#define PSA_WANT_ALG_XTS 1 + +#define PSA_WANT_KEY_TYPE_AES 1 +#define PSA_WANT_KEY_TYPE_ARIA 1 +#define PSA_WANT_KEY_TYPE_CAMELLIA 1 +#define PSA_WANT_KEY_TYPE_CHACHA20 1 +#define PSA_WANT_KEY_TYPE_HMAC 1 + +#define MBEDTLS_SELF_TEST + +#define MBEDTLS_PSA_CRYPTO_C + +/* System support */ +//#define MBEDTLS_HAVE_ASM +#define MBEDTLS_HAVE_TIME +#define MBEDTLS_HAVE_TIME_DATE + +#define MBEDTLS_FS_IO +#define MBEDTLS_ENTROPY_NV_SEED + +/* Mbed TLS modules */ +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_BASE64_C +#define MBEDTLS_CTR_DRBG_C +#define MBEDTLS_ERROR_C +#define MBEDTLS_HMAC_DRBG_C +#define MBEDTLS_NIST_KW_C +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_PEM_WRITE_C +#define MBEDTLS_PKCS5_C +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_PSA_BUILTIN_GET_ENTROPY +#define MBEDTLS_PSA_CRYPTO_STORAGE_C +#define MBEDTLS_PSA_ITS_FILE_C + +//#define MBEDTLS_THREADING_C + +#endif /* PSA_CRYPTO_CONFIG_H */ diff --git a/tf-psa-crypto/configs/ext/README.md b/tf-psa-crypto/configs/ext/README.md new file mode 100644 index 0000000000..8dfcf497e1 --- /dev/null +++ b/tf-psa-crypto/configs/ext/README.md @@ -0,0 +1,22 @@ +Summary +------- + +The file: + +* crypto_config_profile_medium.h + +is copyright The Mbed TLS Contributors, and is distributed under the license normally +used by Mbed TLS: a dual Apache 2.0 or GPLv2-or-later license. + +Background +---------- + +The file crypto_config_profile_medium.h was derived from the two files crypto_config_profile_medium.h and tfm_mbedcrypto_config_profile_medium.h taken from the TF-M source code here: + +https://git.trustedfirmware.org/TF-M/trusted-firmware-m.git/tree/lib/ext/mbedcrypto/mbedcrypto_config + +Initially, it was derived according to the Mbed TLS configuration file split that occurred as part of the Mbed TLS repository split, see https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/config-split.md. It then evolved further during the rework of the cryptographic options for version 1.0 of the library, see https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/docs/architecture/0e-plans.md. + +In TF-M, the two original files are distributed under a 3-Clause BSD license, as noted at the top of the files. + +In Mbed TLS, with permission from the TF-M project, crypto_config_profile_medium.h is distributed under a dual [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) OR [GPL-2.0-or-later](https://spdx.org/licenses/GPL-2.0-or-later.html) license, with copyright assigned to The Mbed TLS Contributors. diff --git a/tf-psa-crypto/configs/ext/crypto_config_profile_medium.h b/tf-psa-crypto/configs/ext/crypto_config_profile_medium.h new file mode 100644 index 0000000000..710898dbfa --- /dev/null +++ b/tf-psa-crypto/configs/ext/crypto_config_profile_medium.h @@ -0,0 +1,620 @@ +/* + * Copyright (c) 2018-2023, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +/** + * \file psa/crypto_config.h + * \brief PSA crypto configuration options (set of defines) + * + */ + +#ifndef PROFILE_M_PSA_CRYPTO_CONFIG_H +#define PROFILE_M_PSA_CRYPTO_CONFIG_H + +/** + * \name SECTION: SECTION Cryptographic mechanism selection (PSA API) + * + * This section sets PSA API settings. + * \{ + */ +/* + * CBC-MAC is not yet supported via the PSA API in Mbed TLS. + */ +//#define PSA_WANT_ALG_CBC_MAC 1 +//#define PSA_WANT_ALG_CBC_NO_PADDING 1 +//#define PSA_WANT_ALG_CBC_PKCS7 1 +#define PSA_WANT_ALG_CCM 1 +//#define PSA_WANT_ALG_CCM_STAR_NO_TAG 1 +//#define PSA_WANT_ALG_CMAC 1 +//#define PSA_WANT_ALG_CFB 1 +//#define PSA_WANT_ALG_CHACHA20_POLY1305 1 +//#define PSA_WANT_ALG_CTR 1 +//#define PSA_WANT_ALG_DETERMINISTIC_ECDSA 1 +//#define PSA_WANT_ALG_ECB_NO_PADDING 1 +#define PSA_WANT_ALG_ECDH 1 +//#define PSA_WANT_ALG_FFDH 1 +#define PSA_WANT_ALG_ECDSA 1 +//#define PSA_WANT_ALG_JPAKE 1 +//#define PSA_WANT_ALG_GCM 1 +#define PSA_WANT_ALG_HKDF 1 +//#define PSA_WANT_ALG_HKDF_EXTRACT 1 +//#define PSA_WANT_ALG_HKDF_EXPAND 1 +#define PSA_WANT_ALG_HMAC 1 +//#define PSA_WANT_ALG_MD5 1 +//#define PSA_WANT_ALG_OFB 1 +//#define PSA_WANT_ALG_PBKDF2_HMAC 1 +//#define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1 +//#define PSA_WANT_ALG_RIPEMD160 1 +//#define PSA_WANT_ALG_RSA_OAEP 1 +//#define PSA_WANT_ALG_RSA_PKCS1V15_CRYPT 1 +//#define PSA_WANT_ALG_RSA_PKCS1V15_SIGN 1 +//#define PSA_WANT_ALG_RSA_PSS 1 +//#define PSA_WANT_ALG_SHA_1 1 +#define PSA_WANT_ALG_SHA_224 1 +#define PSA_WANT_ALG_SHA_256 1 +//#define PSA_WANT_ALG_SHA_384 1 +//#define PSA_WANT_ALG_SHA_512 1 +//#define PSA_WANT_ALG_SHA3_224 1 +//#define PSA_WANT_ALG_SHA3_256 1 +//#define PSA_WANT_ALG_SHA3_384 1 +//#define PSA_WANT_ALG_SHA3_512 1 +//#define PSA_WANT_ALG_STREAM_CIPHER 1 +#define PSA_WANT_ALG_TLS12_PRF 1 +#define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 +//#define PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS 1 + +//#define PSA_WANT_ECC_BRAINPOOL_P_R1_256 1 +//#define PSA_WANT_ECC_BRAINPOOL_P_R1_384 1 +//#define PSA_WANT_ECC_BRAINPOOL_P_R1_512 1 +//#define PSA_WANT_ECC_MONTGOMERY_255 1 +//#define PSA_WANT_ECC_MONTGOMERY_448 1 +//#define PSA_WANT_ECC_SECP_K1_256 1 +/* For secp256r1, consider enabling #MBEDTLS_PSA_P256M_DRIVER_ENABLED + * (see the description in psa/cypto_config.h for details). */ +#define PSA_WANT_ECC_SECP_R1_256 1 +//#define PSA_WANT_ECC_SECP_R1_384 1 +//#define PSA_WANT_ECC_SECP_R1_521 1 + +//#define PSA_WANT_DH_RFC7919_2048 1 +//#define PSA_WANT_DH_RFC7919_3072 1 +//#define PSA_WANT_DH_RFC7919_4096 1 +//#define PSA_WANT_DH_RFC7919_6144 1 +//#define PSA_WANT_DH_RFC7919_8192 1 + +#define PSA_WANT_KEY_TYPE_DERIVE 1 +//#define PSA_WANT_KEY_TYPE_PASSWORD 1 +//#define PSA_WANT_KEY_TYPE_PASSWORD_HASH 1 +#define PSA_WANT_KEY_TYPE_HMAC 1 +#define PSA_WANT_KEY_TYPE_AES 1 +//#define PSA_WANT_KEY_TYPE_ARIA 1 +//#define PSA_WANT_KEY_TYPE_CAMELLIA 1 +//#define PSA_WANT_KEY_TYPE_CHACHA20 1 +#define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1 +//#define PSA_WANT_KEY_TYPE_DH_PUBLIC_KEY 1 +#define PSA_WANT_KEY_TYPE_RAW_DATA 1 +//#define PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY 1 + +/* + * The following symbols extend and deprecate the legacy + * PSA_WANT_KEY_TYPE_xxx_KEY_PAIR ones. They include the usage of that key in + * the name's suffix. "_USE" is the most generic and it can be used to describe + * a generic suport, whereas other ones add more features on top of that and + * they are more specific. + */ +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 +//#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE 1 + +//#define PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC 1 +//#define PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT 1 +//#define PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT 1 +//#define PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE 1 +//#define PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_DERIVE 1 /* Not supported */ + +//#define PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC 1 +//#define PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT 1 +//#define PSA_WANT_KEY_TYPE_DH_KEY_PAIR_EXPORT 1 +//#define PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE 1 +//#define PSA_WANT_KEY_TYPE_DH_KEY_PAIR_DERIVE 1 /* Not supported */ +/** \} name SECTION Cryptographic mechanism selection (PSA API) */ + +/** + * \name SECTION: Platform abstraction layer + * + * This section sets platform specific settings. + * \{ + */ + +/** + * \def MBEDTLS_MEMORY_BUFFER_ALLOC_C + * + * Enable the buffer allocator implementation that makes use of a (stack) + * based buffer to 'allocate' dynamic memory. (replaces calloc() and free() + * calls) + * + * Module: platform/memory_buffer_alloc.c + * + * Requires: MBEDTLS_PLATFORM_C + * MBEDTLS_PLATFORM_MEMORY (to use it within Mbed TLS) + * + * Enable this module to enable the buffer memory allocator. + */ +#define MBEDTLS_MEMORY_BUFFER_ALLOC_C + +/** + * \def MBEDTLS_PLATFORM_C + * + * Enable the platform abstraction layer that allows you to re-assign + * functions like calloc(), free(), snprintf(), printf(), fprintf(), exit(). + * + * Enabling MBEDTLS_PLATFORM_C enables to use of MBEDTLS_PLATFORM_XXX_ALT + * or MBEDTLS_PLATFORM_XXX_MACRO directives, allowing the functions mentioned + * above to be specified at runtime or compile time respectively. + * + * \note This abstraction layer must be enabled on Windows (including MSYS2) + * as other modules rely on it for a fixed snprintf implementation. + * + * Module: platform/platform.c + * Caller: Most other .c files + * + * This module enables abstraction of common (libc) functions. + */ +#define MBEDTLS_PLATFORM_C + +/** + * \def MBEDTLS_PLATFORM_MEMORY + * + * Enable the memory allocation layer. + * + * By default Mbed TLS uses the system-provided calloc() and free(). + * This allows different allocators (self-implemented or provided) to be + * provided to the platform abstraction layer. + * + * Enabling #MBEDTLS_PLATFORM_MEMORY without the + * MBEDTLS_PLATFORM_{FREE,CALLOC}_MACROs will provide + * "mbedtls_platform_set_calloc_free()" allowing you to set an alternative calloc() and + * free() function pointer at runtime. + * + * Enabling #MBEDTLS_PLATFORM_MEMORY and specifying + * MBEDTLS_PLATFORM_{CALLOC,FREE}_MACROs will allow you to specify the + * alternate function at compile time. + * + * An overview of how the value of mbedtls_calloc is determined: + * + * - if !MBEDTLS_PLATFORM_MEMORY + * - mbedtls_calloc = calloc + * - if MBEDTLS_PLATFORM_MEMORY + * - if (MBEDTLS_PLATFORM_CALLOC_MACRO && MBEDTLS_PLATFORM_FREE_MACRO): + * - mbedtls_calloc = MBEDTLS_PLATFORM_CALLOC_MACRO + * - if !(MBEDTLS_PLATFORM_CALLOC_MACRO && MBEDTLS_PLATFORM_FREE_MACRO): + * - Dynamic setup via mbedtls_platform_set_calloc_free is now possible with a default value MBEDTLS_PLATFORM_STD_CALLOC. + * - How is MBEDTLS_PLATFORM_STD_CALLOC handled? + * - if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS: + * - MBEDTLS_PLATFORM_STD_CALLOC is not set to anything; + * - MBEDTLS_PLATFORM_STD_MEM_HDR can be included if present; + * - if !MBEDTLS_PLATFORM_NO_STD_FUNCTIONS: + * - if MBEDTLS_PLATFORM_STD_CALLOC is present: + * - User-defined MBEDTLS_PLATFORM_STD_CALLOC is respected; + * - if !MBEDTLS_PLATFORM_STD_CALLOC: + * - MBEDTLS_PLATFORM_STD_CALLOC = calloc + * + * - At this point the presence of MBEDTLS_PLATFORM_STD_CALLOC is checked. + * - if !MBEDTLS_PLATFORM_STD_CALLOC + * - MBEDTLS_PLATFORM_STD_CALLOC = uninitialized_calloc + * + * - mbedtls_calloc = MBEDTLS_PLATFORM_STD_CALLOC. + * + * Defining MBEDTLS_PLATFORM_CALLOC_MACRO and #MBEDTLS_PLATFORM_STD_CALLOC at the same time is not possible. + * MBEDTLS_PLATFORM_CALLOC_MACRO and MBEDTLS_PLATFORM_FREE_MACRO must both be defined or undefined at the same time. + * #MBEDTLS_PLATFORM_STD_CALLOC and #MBEDTLS_PLATFORM_STD_FREE do not have to be defined at the same time, as, if they are used, + * dynamic setup of these functions is possible. See the tree above to see how are they handled in all cases. + * An uninitialized #MBEDTLS_PLATFORM_STD_CALLOC always fails, returning a null pointer. + * An uninitialized #MBEDTLS_PLATFORM_STD_FREE does not do anything. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Enable this layer to allow use of alternative memory allocators. + */ +#define MBEDTLS_PLATFORM_MEMORY + +/** + * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + * + * Do not assign standard functions in the platform layer (e.g. calloc() to + * MBEDTLS_PLATFORM_STD_CALLOC and printf() to MBEDTLS_PLATFORM_STD_PRINTF) + * + * This makes sure there are no linking errors on platforms that do not support + * these functions. You will HAVE to provide alternatives, either at runtime + * via the platform_set_xxx() functions or at compile time by setting + * the MBEDTLS_PLATFORM_STD_XXX defines, or enabling a + * MBEDTLS_PLATFORM_XXX_MACRO. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Uncomment to prevent default assignment of standard functions in the + * platform layer. + */ +#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + +#define MBEDTLS_PLATFORM_PRINTF_ALT + +/* To use the following function macros, MBEDTLS_PLATFORM_C must be enabled. */ +/* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */ + +#include + +#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf +#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE EXIT_FAILURE +#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS EXIT_SUCCESS + +#define MBEDTLS_PLATFORM_STD_MEM_HDR + +/** \} name SECTION: Platform abstraction layer */ + +/** + * \name SECTION: PSA core + * + * This section sets PSA specific settings. + * \{ + */ +/** + * \def MBEDTLS_CTR_DRBG_C + * + * Enable the CTR_DRBG AES-based random generator. + * The CTR_DRBG generator uses AES-256 by default. + * To use AES-128 instead, set #MBEDTLS_PSA_CRYPTO_RNG_STRENGTH to 128. + * + * AES support can either be achieved through built-in AES or PSA. Built-in is + * the default option when present otherwise PSA is used. + * + * Module: drivers/builtin/src/ctr_drbg.c + * + * Requires: MBEDTLS_PSA_CRYPTO_C, PSA_WANT_KEY_TYPE_AES and + * PSA_WANT_ALG_ECB_NO_PADDING + * + * This module provides the CTR_DRBG AES random number generator. + */ +#define MBEDTLS_CTR_DRBG_C + +/** + * \def MBEDTLS_ENTROPY_NV_SEED + * + * Enable the non-volatile (NV) seed file-based entropy source. + * (Also enables the NV seed read/write functions in the platform layer) + * + * This is crucial (if not required) on systems that do not have a + * cryptographic entropy source (in hardware or kernel) available. + * + * Requires: MBEDTLS_PSA_CRYPTO_C, + * !MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + * MBEDTLS_PLATFORM_C + * + * \note The read/write functions that are used by the entropy source are + * determined in the platform layer, and can be modified at runtime and/or + * compile-time depending on the flags (MBEDTLS_PLATFORM_NV_SEED_*) used. + * + * \note If you use the default implementation functions that read a seedfile + * with regular fopen(), please make sure you make a seedfile with the + * proper name (defined in MBEDTLS_PLATFORM_STD_NV_SEED_FILE) and at + * least MBEDTLS_ENTROPY_BLOCK_SIZE bytes in size that can be read from + * and written to or you will get an entropy source error! The default + * implementation will only use the first MBEDTLS_ENTROPY_BLOCK_SIZE + * bytes from the file. + * + * \note The entropy collector will write to the seed file before entropy is + * given to an external source, to update it. + */ +#define MBEDTLS_ENTROPY_NV_SEED + +/** + * \def MBEDTLS_PSA_CRYPTO_C + * + * Enable the Platform Security Architecture cryptography API. + * + * Module: core/psa_crypto.c + * + * Requires: one of the following: + * - MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + * - MBEDTLS_CTR_DRBG_C + * - MBEDTLS_HMAC_DRBG_C + * + * If MBEDTLS_CTR_DRBG_C or MBEDTLS_HMAC_DRBG_C is used as the PSA + * random generator, then either PSA_WANT_ALG_SHA_256 or + * PSA_WANT_ALG_SHA_512 must be enabled for the entropy module. + * + * \note The PSA crypto subsystem prioritizes DRBG mechanisms as follows: + * - #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG, if enabled + * - CTR_DRBG (AES), seeded by the entropy module, if + * #MBEDTLS_CTR_DRBG_C is enabled + * - HMAC_DRBG, seeded by the entropy module, if + * #MBEDTLS_HMAC_DRBG_C is enabled + * + * A future version may reevaluate the prioritization of DRBG mechanisms. + */ +#define MBEDTLS_PSA_CRYPTO_C + +/** + * \def MBEDTLS_PSA_CRYPTO_SPM + * + * When MBEDTLS_PSA_CRYPTO_SPM is defined, the code is built for SPM (Secure + * Partition Manager) integration which separates the code into two parts: a + * NSPE (Non-Secure Process Environment) and an SPE (Secure Process + * Environment). + * + * If you enable this option, your build environment must include a header + * file `"crypto_spe.h"` (either in the `psa` subdirectory of the Mbed TLS + * header files, or in another directory on the compiler's include search + * path). Alternatively, your platform may customize the header + * `psa/crypto_platform.h`, in which case it can skip or replace the + * inclusion of `"crypto_spe.h"`. + * + * Module: core/psa_crypto.c + * Requires: MBEDTLS_PSA_CRYPTO_C + * + */ +#define MBEDTLS_PSA_CRYPTO_SPM + +/** + * \def MBEDTLS_PSA_CRYPTO_STORAGE_C + * + * Enable the Platform Security Architecture persistent key storage. + * + * Module: core/psa_crypto_storage.c + * + * Requires: MBEDTLS_PSA_CRYPTO_C, + * either MBEDTLS_PSA_ITS_FILE_C or a native implementation of + * the PSA ITS interface + */ +#define MBEDTLS_PSA_CRYPTO_STORAGE_C + +/** + * \def MBEDTLS_PSA_DRIVER_GET_ENTROPY + * + * Requires: MBEDTLS_PSA_CRYPTO_C, !MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + * + * Enable the custom entropy callback mbedtls_platform_get_entropy() + * (declared in mbedtls/platform.h). You need to provide this callback + * if you need an entropy source and the built-in entropy callback + * provided by #MBEDTLS_PSA_BUILTIN_GET_ENTROPY does not work on your platform. + * + * Enabling both #MBEDTLS_PSA_BUILTIN_GET_ENTROPY and + * #MBEDTLS_PSA_DRIVER_GET_ENTROPY is currently not supported. + * + * You do not need any entropy source in the following circumstances: + * + * - If your platform has a fast cryptographic-quality random generator, and + * you enable #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG and provide a random generator + * callback instead. + * - If your platform has no source of entropy at all, and you enable + * #MBEDTLS_ENTROPY_NV_SEED and provide a seed in nonvolatile memory + * during the provisioning of the device. + * - If you build the library with no random generator. + * Builds with no random generator are not officially supported yet, except + * client-only builds (#MBEDTLS_PSA_CRYPTO_CLIENT enabled and + * #MBEDTLS_PSA_CRYPTO_C disabled). + */ +//#define MBEDTLS_PSA_DRIVER_GET_ENTROPY + +/** + * \def MBEDTLS_PSA_CRYPTO_RNG_STRENGTH + * + * Minimum security strength (in bits) of the PSA RNG. + * + * \note Valid values: 128 or default of 256. + */ +#define MBEDTLS_PSA_CRYPTO_RNG_STRENGTH 128 + +/** \} name SECTION: PSA core */ + +/** + * \name SECTION: Builtin drivers + * + * This section sets driver specific settings. + * \{ + */ + +/** + * \def MBEDTLS_AES_ROM_TABLES + * + * Use precomputed AES tables stored in ROM. + * + * Uncomment this macro to use precomputed AES tables stored in ROM. + * Comment this macro to generate AES tables in RAM at runtime. + * + * Tradeoff: Using precomputed ROM tables reduces RAM usage by ~8kb + * (or ~2kb if \c MBEDTLS_AES_FEWER_TABLES is used) and reduces the + * initialization time before the first AES operation can be performed. + * It comes at the cost of additional ~8kb ROM use (resp. ~2kb if \c + * MBEDTLS_AES_FEWER_TABLES below is used), and potentially degraded + * performance if ROM access is slower than RAM access. + * + * This option is independent of \c MBEDTLS_AES_FEWER_TABLES. + */ +#define MBEDTLS_AES_ROM_TABLES + +/** + * \def MBEDTLS_AES_FEWER_TABLES + * + * Use less ROM/RAM for AES tables. + * + * Uncommenting this macro omits 75% of the AES tables from + * ROM / RAM (depending on the value of \c MBEDTLS_AES_ROM_TABLES) + * by computing their values on the fly during operations + * (the tables are entry-wise rotations of one another). + * + * Tradeoff: Uncommenting this reduces the RAM / ROM footprint + * by ~6kb but at the cost of more arithmetic operations during + * runtime. Specifically, one has to compare 4 accesses within + * different tables to 4 accesses with additional arithmetic + * operations within the same table. The performance gain/loss + * depends on the system and memory details. + * + * This option is independent of \c MBEDTLS_AES_ROM_TABLES. + */ +#define MBEDTLS_AES_FEWER_TABLES + +/** + * \def MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH + * + * Use only 128-bit keys in AES operations to save ROM. + * + * Uncomment this macro to remove support for AES operations that use 192- + * or 256-bit keys. + * + * Uncommenting this macro reduces the size of AES code by ~300 bytes + * on v8-M/Thumb2. + * + * Module: drivers/builtin/src/aes.c + * + * Requires: The AES built-in implementation + */ +#define MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH + +/** + * \def MBEDTLS_ECP_NIST_OPTIM + * + * Enable specific 'modulo p' routines for each NIST prime. + * Depending on the prime and architecture, makes operations 4 to 8 times + * faster on the corresponding curve. + * + * Comment this macro to disable NIST curves optimisation. + */ +#define MBEDTLS_ECP_NIST_OPTIM + +/** + * \def MBEDTLS_HAVE_ASM + * + * The compiler has support for asm(). + * + * Requires support for asm() in compiler. + * + * Used in: + * drivers/builtin/src/aesni.h + * drivers/builtin/src/aria.c + * drivers/builtin/src/bn_mul.h + * utilities/constant_time.c + * + * Required by: + * MBEDTLS_AESCE_C + * MBEDTLS_AESNI_C (on some platforms) + * + * Comment to disable the use of assembly code. + */ +#define MBEDTLS_HAVE_ASM + +/** + * Uncomment to enable p256-m. This is an alternative implementation of + * key generation, ECDH and (randomized) ECDSA on the curve SECP256R1. + * Compared to the default implementation: + * + * - p256-m has a much smaller code size and RAM footprint. + * - p256-m is only available via the PSA API. This includes the pk module. + * - p256-m does not support deterministic ECDSA, EC-JPAKE, custom protocols + * over the core arithmetic, or deterministic derivation of keys. + * + * We recommend enabling this option if your application uses the PSA API + * and the only elliptic curve support it needs is ECDH and ECDSA over + * SECP256R1. + * + * If you enable this option, you do not need to enable any ECC-related + * MBEDTLS_xxx option. You do need to separately request support for the + * cryptographic mechanisms through the PSA API: + * - #MBEDTLS_PSA_CRYPTO_C for PSA-based configuration; + * - #PSA_WANT_ECC_SECP_R1_256; + * - #PSA_WANT_ALG_ECDH and/or #PSA_WANT_ALG_ECDSA as needed; + * - #PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY, #PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC, + * #PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT, + * #PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT and/or + * #PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE as needed. + * + * \note To benefit from the smaller code size of p256-m, make sure that you + * do not enable any ECC-related option not supported by p256-m: this + * would cause the built-in ECC implementation to be built as well, in + * order to provide the required option. + * Make sure #PSA_WANT_ALG_DETERMINISTIC_ECDSA, #PSA_WANT_ALG_JPAKE and + * #PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE, and curves other than + * SECP256R1 are disabled as they are not supported by this driver. + * Also, avoid defining #MBEDTLS_PK_PARSE_EC_COMPRESSED or + * #MBEDTLS_PK_PARSE_EC_EXTENDED as those currently require a subset of + * the built-in ECC implementation, see docs/driver-only-builds.md. + */ +#define MBEDTLS_PSA_P256M_DRIVER_ENABLED + +/** + * \def MBEDTLS_SHA256_SMALLER + * + * Enable an implementation of SHA-256 that has lower ROM footprint but also + * lower performance. + * + * The default implementation is meant to be a reasonable compromise between + * performance and size. This version optimizes more aggressively for size at + * the expense of performance. Eg on Cortex-M4 it reduces the size of + * mbedtls_sha256_process() from ~2KB to ~0.5KB for a performance hit of about + * 30%. + * + * Uncomment to enable the smaller implementation of SHA256. + */ +#define MBEDTLS_SHA256_SMALLER + +/* ECP options */ +#define MBEDTLS_ECP_FIXED_POINT_OPTIM 0 /**< Disable fixed-point speed-up */ + +/** \} name SECTION: Builtin drivers */ + +/***********************************************************/ +/* Tweak the configuration to remove dependencies on TF-M. */ +/***********************************************************/ + +/* MBEDTLS_PSA_CRYPTO_SPM needs third-party files, so disable it. */ +#undef MBEDTLS_PSA_CRYPTO_SPM + +/* Disable buffer-based memory allocator. This isn't strictly required, + * but using the native allocator is faster and works better with + * memory management analysis frameworks such as ASan. */ +#undef MBEDTLS_MEMORY_BUFFER_ALLOC_C + +// This macro is enabled in TFM Medium but is disabled here because it is +// incompatible with baremetal builds in Mbed TLS. +#undef MBEDTLS_PSA_CRYPTO_STORAGE_C + +// This macro is enabled in TFM Medium but is disabled here because it is +// incompatible with baremetal builds in Mbed TLS. +#undef MBEDTLS_ENTROPY_NV_SEED + +// This macro is disabled in TFM Medium but enabled in integrations with +// supported hardware. Enable it because we need an entropy source in our +// test builds. +#define MBEDTLS_PSA_DRIVER_GET_ENTROPY + +// These platform-related TF-M settings are not useful here. +#undef MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#undef MBEDTLS_PLATFORM_STD_MEM_HDR +#undef MBEDTLS_PLATFORM_SNPRINTF_MACRO +#undef MBEDTLS_PLATFORM_PRINTF_ALT +#undef MBEDTLS_PLATFORM_STD_EXIT_SUCCESS +#undef MBEDTLS_PLATFORM_STD_EXIT_FAILURE + +/*********************************************************************** + * Local changes to crypto config below this delimiter + **********************************************************************/ + +// We expect TF-M to pick this up soon +#define MBEDTLS_BLOCK_CIPHER_NO_DECRYPT + +#if CRYPTO_NV_SEED +#include "tfm_mbedcrypto_config_extra_nv_seed.h" +#endif /* CRYPTO_NV_SEED */ + +#if !defined(CRYPTO_HW_ACCELERATOR) && defined(MBEDTLS_ENTROPY_NV_SEED) +#include "mbedtls_entropy_nv_seed_config.h" +#endif + +#ifdef CRYPTO_HW_ACCELERATOR +#include "crypto_accelerator_config.h" +#endif + +#endif /* PROFILE_M_PSA_CRYPTO_CONFIG_H */ diff --git a/tf-psa-crypto/core/.gitignore b/tf-psa-crypto/core/.gitignore new file mode 100644 index 0000000000..31c172c258 --- /dev/null +++ b/tf-psa-crypto/core/.gitignore @@ -0,0 +1,7 @@ +###START_GENERATED_FILES### +# /psa_crypto_driver_wrappers.h +# /psa_crypto_driver_wrappers_no_static.c +# /tf_psa_crypto_config_check_before.h +# /tf_psa_crypto_config_check_final.h +# /tf_psa_crypto_config_check_user.h +###END_GENERATED_FILES### diff --git a/tf-psa-crypto/core/CMakeLists.txt b/tf-psa-crypto/core/CMakeLists.txt new file mode 100644 index 0000000000..2475430ac6 --- /dev/null +++ b/tf-psa-crypto/core/CMakeLists.txt @@ -0,0 +1,215 @@ +file(GLOB src_crypto "${CMAKE_CURRENT_SOURCE_DIR}/*.c") + +# The generated file `psa_crypto_driver_wrappers_no_static.c` may exist in the +# source tree and therefore be picked up by the glob above. Remove it from +# `src_crypto` if present, then append it using a relative path. This ensures +# that the build system prefers the file from the build tree over the one in +# the source tree. +list(FIND src_crypto + "${CMAKE_CURRENT_SOURCE_DIR}/psa_crypto_driver_wrappers_no_static.c" + _idx) +if(NOT _idx EQUAL -1) + list(REMOVE_AT src_crypto ${_idx}) +endif() +list(APPEND src_crypto psa_crypto_driver_wrappers_no_static.c) + +if(GEN_FILES) + add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/psa_crypto_driver_wrappers.h + ${CMAKE_CURRENT_BINARY_DIR}/psa_crypto_driver_wrappers_no_static.c + COMMAND + ${TF_PSA_CRYPTO_PYTHON_EXECUTABLE} + ${PROJECT_SOURCE_DIR}/scripts/generate_driver_wrappers.py + ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS + ${PROJECT_SOURCE_DIR}/scripts/generate_driver_wrappers.py + ${PROJECT_SOURCE_DIR}/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.h.jinja + ${PROJECT_SOURCE_DIR}/scripts/data_files/driver_templates/psa_crypto_driver_wrappers_no_static.c.jinja + ) + + execute_process( + COMMAND + ${TF_PSA_CRYPTO_PYTHON_EXECUTABLE} + ${PROJECT_SOURCE_DIR}/scripts/generate_config_checks.py + --list-for-cmake "${CMAKE_CURRENT_BINARY_DIR}" + WORKING_DIRECTORY + ${PROJECT_SOURCE_DIR} + OUTPUT_VARIABLE + TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS) + + add_custom_command( + OUTPUT ${TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS} + COMMAND + ${TF_PSA_CRYPTO_PYTHON_EXECUTABLE} + ${PROJECT_SOURCE_DIR}/scripts/generate_config_checks.py + ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS + ${PROJECT_SOURCE_DIR}/scripts/generate_config_checks.py + ${TF_PSA_CRYPTO_FRAMEWORK_DIR}/scripts/mbedtls_framework/config_checks_generator.py + ) + + add_custom_target( + ${TF_PSA_CRYPTO_TARGET_PREFIX}libtfpsacrypto_generated_files_target + DEPENDS + "${CMAKE_CURRENT_BINARY_DIR}/psa_crypto_driver_wrappers.h" + "${CMAKE_CURRENT_BINARY_DIR}/psa_crypto_driver_wrappers_no_static.c" + ${TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS} + ) + + # List generated headers as sources explicitly. Normally CMake finds + # headers by tracing include directives, but if that happens before the + # generated headers are generated, this process doesn't find them. + list(APPEND src_crypto + "${CMAKE_CURRENT_BINARY_DIR}/psa_crypto_driver_wrappers.h" + ${TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS} + ) +endif(GEN_FILES) + +if(CMAKE_COMPILER_IS_GNUCC) + set(LIBS_C_FLAGS -Wmissing-declarations -Wmissing-prototypes) +endif(CMAKE_COMPILER_IS_GNUCC) + +if(CMAKE_COMPILER_IS_CLANG) + # Removed -Wdocumentation as it creates lots of noise + # from FreeRTOS header files + set(LIBS_C_FLAGS -Wmissing-declarations -Wmissing-prototypes -Wno-documentation-deprecated-sync -Wunreachable-code) +endif(CMAKE_COMPILER_IS_CLANG) + +if(CMAKE_COMPILER_IS_MSVC) + option(MSVC_STATIC_RUNTIME "Build the libraries with /MT compiler flag" OFF) + if(MSVC_STATIC_RUNTIME) + foreach(flag_var + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_C_FLAGS_CHECK) + string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") + endforeach(flag_var) + endif() +endif() + +if(CMAKE_C_COMPILER_ID MATCHES "AppleClang") + set(CMAKE_C_ARCHIVE_CREATE " Scr ") + set(CMAKE_C_ARCHIVE_FINISH " -no_warning_for_no_symbols -c ") +endif() +if(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang") + set(CMAKE_CXX_ARCHIVE_CREATE " Scr ") + set(CMAKE_CXX_ARCHIVE_FINISH " -no_warning_for_no_symbols -c ") +endif() + +if(WIN32) + set(libs ${libs} ws2_32 bcrypt) +endif(WIN32) + +if(LINK_WITH_PTHREAD) + set(libs ${libs} ${CMAKE_THREAD_LIBS_INIT}) +endif() + +if(LINK_WITH_TRUSTED_STORAGE) + set(libs ${libs} trusted_storage) +endif() + +if (NOT USE_STATIC_TF_PSA_CRYPTO_LIBRARY AND NOT USE_SHARED_TF_PSA_CRYPTO_LIBRARY) + message(FATAL_ERROR "Need to choose static or shared TF-PSA-Crypto build!") +endif(NOT USE_STATIC_TF_PSA_CRYPTO_LIBRARY AND NOT USE_SHARED_TF_PSA_CRYPTO_LIBRARY) + +set(tfpsacrypto_target "${TF_PSA_CRYPTO_TARGET_PREFIX}tfpsacrypto") +if (USE_STATIC_TF_PSA_CRYPTO_LIBRARY) + set(tfpsacrypto_static_target ${tfpsacrypto_target}) +endif() + +set(target_libraries ${tfpsacrypto_target}) +if(USE_STATIC_TF_PSA_CRYPTO_LIBRARY AND USE_SHARED_TF_PSA_CRYPTO_LIBRARY) + string(APPEND tfpsacrypto_static_target "_static") + list(APPEND target_libraries ${tfpsacrypto_static_target}) +endif() + +if(USE_STATIC_TF_PSA_CRYPTO_LIBRARY) + set(target_objects "") + foreach(driver_target ${TF_PSA_CRYPTO_DRIVER_STATIC_TARGETS}) + list(APPEND target_objects "$") + endforeach() + foreach(objlib_target ${TF_PSA_CRYPTO_OBJLIB_STATIC_TARGETS}) + list(APPEND target_objects "$") + endforeach() + add_library(${tfpsacrypto_static_target} STATIC + ${src_crypto} + ${target_objects}) + tf_psa_crypto_set_base_compile_options(${tfpsacrypto_static_target}) + tf_psa_crypto_set_extra_compile_options(${tfpsacrypto_static_target}) + set_target_properties(${tfpsacrypto_static_target} PROPERTIES OUTPUT_NAME tfpsacrypto) + target_link_libraries(${tfpsacrypto_static_target} PUBLIC ${libs} ${builtin_static_target} ${everest_static_target} ${p256m_static_target}) + + if(GEN_FILES) + add_dependencies(${tfpsacrypto_static_target} + ${TF_PSA_CRYPTO_TARGET_PREFIX}libtfpsacrypto_generated_files_target) + endif() +endif(USE_STATIC_TF_PSA_CRYPTO_LIBRARY) + +if(USE_SHARED_TF_PSA_CRYPTO_LIBRARY) + set(CMAKE_LIBRARY_PATH ${CMAKE_CURRENT_BINARY_DIR}) + set(target_objects "") + foreach(driver_target ${TF_PSA_CRYPTO_DRIVER_TARGETS}) + list(APPEND target_objects "$") + endforeach() + foreach(objlib_target ${TF_PSA_CRYPTO_OBJLIB_TARGETS}) + list(APPEND target_objects "$") + endforeach() + add_library(${tfpsacrypto_target} SHARED + ${src_crypto} + ${target_objects}) + tf_psa_crypto_set_base_compile_options(${tfpsacrypto_target}) + tf_psa_crypto_set_extra_compile_options(${tfpsacrypto_target}) + set_target_properties(${tfpsacrypto_target} PROPERTIES VERSION ${TF_PSA_CRYPTO_VERSION} SOVERSION ${TF_PSA_CRYPTO_SOVERSION}) + target_link_libraries(${tfpsacrypto_target} PUBLIC ${libs}) + + if(GEN_FILES) + add_dependencies(${tfpsacrypto_target} + ${TF_PSA_CRYPTO_TARGET_PREFIX}libtfpsacrypto_generated_files_target) + endif() +endif(USE_SHARED_TF_PSA_CRYPTO_LIBRARY) + +foreach(target IN LISTS target_libraries) + add_library(TF-PSA-Crypto::${target} ALIAS ${target}) # add_subdirectory support + target_include_directories(${target} + # Add the build-tree include directory before the source-tree one + # so that generated headers in the build tree take precedence. + PUBLIC $ + $ + $ + PRIVATE ${TF_PSA_CRYPTO_PRIVATE_INCLUDE_DIRS} + # Needed to include psa_crypto_driver_wrappers.h + ${CMAKE_CURRENT_BINARY_DIR}) + foreach(driver_target ${TF_PSA_CRYPTO_DRIVER_TARGETS}) + get_target_property(public_includes ${driver_target} INTERFACE_INCLUDE_DIRECTORIES) + foreach(dir IN LISTS public_includes) + target_include_directories(${target} PUBLIC $) + endforeach() + endforeach() + if(TF_PSA_CRYPTO_TEST_DRIVER) + # Note: "tests/include/test" exists solely to provide access to + # "mbedtls/build_info.h". That header is an alias of + # "tf-psa-crypto/build_info.h". + # + # It is included in framework headers and C modules because those + # components are also used in the Mbed TLS context. + target_include_directories(${target} + PRIVATE ${TF_PSA_CRYPTO_FRAMEWORK_DIR}/tests/include + ${PROJECT_SOURCE_DIR}/tests/include/test) + endif() + tf_psa_crypto_set_config_files_compile_definitions(${target}) + install( + TARGETS ${target} + EXPORT MbedTLSTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) + install( + TARGETS ${target} + EXPORT TF-PSA-CryptoTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) +endforeach(target) diff --git a/tf-psa-crypto/core/alignment.h b/tf-psa-crypto/core/alignment.h new file mode 100644 index 0000000000..a29fc5fb91 --- /dev/null +++ b/tf-psa-crypto/core/alignment.h @@ -0,0 +1,687 @@ +/** + * \file alignment.h + * + * \brief Utility code for dealing with unaligned memory accesses + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_ALIGNMENT_H +#define TF_PSA_CRYPTO_ALIGNMENT_H + +#include +#include +#include + +#if !defined(MBEDTLS_ALIGNMENT_DISABLE_EFFICENT_UNALIGNED_ACCESS) //no-check-names +/* + * Define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS for architectures where unaligned memory + * accesses are known to be efficient. + * + * All functions defined here will behave correctly regardless, but might be less + * efficient when this is not defined. + */ +#if defined(__ARM_FEATURE_UNALIGNED) \ + || defined(MBEDTLS_ARCH_IS_X86) || defined(MBEDTLS_ARCH_IS_X64) \ + || defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64) +/* + * __ARM_FEATURE_UNALIGNED is defined where appropriate by armcc, gcc 7, clang 9 + * (and later versions) for Arm v7 and later; all x86 platforms should have + * efficient unaligned access. + * + * https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#alignment + * specifies that on Windows-on-Arm64, unaligned access is safe (except for uncached + * device memory). + */ +#define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS +#endif /* __ARM_FEATURE_UNALIGNED || MBEDTLS_ARCH_IS_X86 || MBEDTLS_ARCH_IS_X64 || + * MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64 */ +#endif /* MBEDTLS_ALIGNMENT_DISABLE_EFFICENT_UNALIGNED_ACCESS */ //no-check-names + +#if defined(__IAR_SYSTEMS_ICC__) && \ + (defined(MBEDTLS_ARCH_IS_ARM64) || defined(MBEDTLS_ARCH_IS_ARM32) \ + || defined(__ICCRX__) || defined(__ICCRL78__) || defined(__ICCRISCV__)) +#pragma language=save +#pragma language=extended +#define MBEDTLS_POP_IAR_LANGUAGE_PRAGMA +/* IAR recommend this technique for accessing unaligned data in + * https://www.iar.com/knowledge/support/technical-notes/compiler/accessing-unaligned-data + * This results in a single load / store instruction (if unaligned access is supported). + * According to that document, this is only supported on certain architectures. + */ + #define UINT_UNALIGNED +typedef uint16_t __packed mbedtls_uint16_unaligned_t; +typedef uint32_t __packed mbedtls_uint32_unaligned_t; +typedef uint64_t __packed mbedtls_uint64_unaligned_t; +#elif defined(MBEDTLS_COMPILER_IS_GCC) && (MBEDTLS_GCC_VERSION >= 40504) && \ + ((MBEDTLS_GCC_VERSION < 60300) || (!defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS))) +/* + * gcc may generate a branch to memcpy for calls like `memcpy(dest, src, 4)` rather than + * generating some LDR or LDRB instructions (similar for stores). + * + * This is architecture dependent: x86-64 seems fine even with old gcc; 32-bit Arm + * is affected. To keep it simple, we enable for all architectures. + * + * For versions of gcc < 5.4.0 this issue always happens. + * For gcc < 6.3.0, this issue happens at -O0 + * For all versions, this issue happens iff unaligned access is not supported. + * + * For gcc 4.x, this implementation will generate byte-by-byte loads even if unaligned access is + * supported, which is correct but not optimal. + * + * For performance (and code size, in some cases), we want to avoid the branch and just generate + * some inline load/store instructions since the access is small and constant-size. + * + * The manual states: + * "The packed attribute specifies that a variable or structure field should have the smallest + * possible alignment—one byte for a variable" + * https://gcc.gnu.org/onlinedocs/gcc-4.5.4/gcc/Variable-Attributes.html + * + * Previous implementations used __attribute__((__aligned__(1)), but had issues with a gcc bug: + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94662 + * + * Tested with several versions of GCC from 4.5.0 up to 13.2.0 + * We don't enable for older than 4.5.0 as this has not been tested. + */ + #define UINT_UNALIGNED_STRUCT +typedef struct { + uint16_t x; +} __attribute__((packed, may_alias)) mbedtls_uint16_unaligned_t; +typedef struct { + uint32_t x; +} __attribute__((packed, may_alias)) mbedtls_uint32_unaligned_t; +typedef struct { + uint64_t x; +} __attribute__((packed, may_alias)) mbedtls_uint64_unaligned_t; + #endif + +/* + * We try to force mbedtls_(get|put)_unaligned_uintXX to be always inline, because this results + * in code that is both smaller and faster. IAR and gcc both benefit from this when optimising + * for size. + */ + +/** + * Read the unsigned 16 bits integer from the given address, which need not + * be aligned. + * + * \param p pointer to 2 bytes of data + * \return Data at the given address + */ +#if defined(__IAR_SYSTEMS_ICC__) +#pragma inline = forced +#elif defined(__GNUC__) +__attribute__((always_inline)) +#endif +static inline uint16_t mbedtls_get_unaligned_uint16(const void *p) +{ + uint16_t r; +#if defined(UINT_UNALIGNED) + mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p; + r = *p16; +#elif defined(UINT_UNALIGNED_STRUCT) + mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p; + r = p16->x; +#else + memcpy(&r, p, sizeof(r)); +#endif + return r; +} + +/** + * Write the unsigned 16 bits integer to the given address, which need not + * be aligned. + * + * \param p pointer to 2 bytes of data + * \param x data to write + */ +#if defined(__IAR_SYSTEMS_ICC__) +#pragma inline = forced +#elif defined(__GNUC__) +__attribute__((always_inline)) +#endif +static inline void mbedtls_put_unaligned_uint16(void *p, uint16_t x) +{ +#if defined(UINT_UNALIGNED) + mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p; + *p16 = x; +#elif defined(UINT_UNALIGNED_STRUCT) + mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p; + p16->x = x; +#else + memcpy(p, &x, sizeof(x)); +#endif +} + +/** + * Read the unsigned 32 bits integer from the given address, which need not + * be aligned. + * + * \param p pointer to 4 bytes of data + * \return Data at the given address + */ +#if defined(__IAR_SYSTEMS_ICC__) +#pragma inline = forced +#elif defined(__GNUC__) +__attribute__((always_inline)) +#endif +static inline uint32_t mbedtls_get_unaligned_uint32(const void *p) +{ + uint32_t r; +#if defined(UINT_UNALIGNED) + mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p; + r = *p32; +#elif defined(UINT_UNALIGNED_STRUCT) + mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p; + r = p32->x; +#else + memcpy(&r, p, sizeof(r)); +#endif + return r; +} + +/** + * Write the unsigned 32 bits integer to the given address, which need not + * be aligned. + * + * \param p pointer to 4 bytes of data + * \param x data to write + */ +#if defined(__IAR_SYSTEMS_ICC__) +#pragma inline = forced +#elif defined(__GNUC__) +__attribute__((always_inline)) +#endif +static inline void mbedtls_put_unaligned_uint32(void *p, uint32_t x) +{ +#if defined(UINT_UNALIGNED) + mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p; + *p32 = x; +#elif defined(UINT_UNALIGNED_STRUCT) + mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p; + p32->x = x; +#else + memcpy(p, &x, sizeof(x)); +#endif +} + +/** + * Read the unsigned 64 bits integer from the given address, which need not + * be aligned. + * + * \param p pointer to 8 bytes of data + * \return Data at the given address + */ +#if defined(__IAR_SYSTEMS_ICC__) +#pragma inline = forced +#elif defined(__GNUC__) +__attribute__((always_inline)) +#endif +static inline uint64_t mbedtls_get_unaligned_uint64(const void *p) +{ + uint64_t r; +#if defined(UINT_UNALIGNED) + mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p; + r = *p64; +#elif defined(UINT_UNALIGNED_STRUCT) + mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p; + r = p64->x; +#else + memcpy(&r, p, sizeof(r)); +#endif + return r; +} + +/** + * Write the unsigned 64 bits integer to the given address, which need not + * be aligned. + * + * \param p pointer to 8 bytes of data + * \param x data to write + */ +#if defined(__IAR_SYSTEMS_ICC__) +#pragma inline = forced +#elif defined(__GNUC__) +__attribute__((always_inline)) +#endif +static inline void mbedtls_put_unaligned_uint64(void *p, uint64_t x) +{ +#if defined(UINT_UNALIGNED) + mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p; + *p64 = x; +#elif defined(UINT_UNALIGNED_STRUCT) + mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p; + p64->x = x; +#else + memcpy(p, &x, sizeof(x)); +#endif +} + +#if defined(MBEDTLS_POP_IAR_LANGUAGE_PRAGMA) +#pragma language=restore +#endif + +/** Byte Reading Macros + * + * Given a multi-byte integer \p x, MBEDTLS_BYTE_n retrieves the n-th + * byte from x, where byte 0 is the least significant byte. + */ +#define MBEDTLS_BYTE_0(x) ((uint8_t) ((x) & 0xff)) +#define MBEDTLS_BYTE_1(x) ((uint8_t) (((x) >> 8) & 0xff)) +#define MBEDTLS_BYTE_2(x) ((uint8_t) (((x) >> 16) & 0xff)) +#define MBEDTLS_BYTE_3(x) ((uint8_t) (((x) >> 24) & 0xff)) +#define MBEDTLS_BYTE_4(x) ((uint8_t) (((x) >> 32) & 0xff)) +#define MBEDTLS_BYTE_5(x) ((uint8_t) (((x) >> 40) & 0xff)) +#define MBEDTLS_BYTE_6(x) ((uint8_t) (((x) >> 48) & 0xff)) +#define MBEDTLS_BYTE_7(x) ((uint8_t) (((x) >> 56) & 0xff)) + +/* + * Detect GCC built-in byteswap routines + */ +#if defined(__GNUC__) +#if MBEDTLS_GCC_VERSION >= 40800 +#define MBEDTLS_BSWAP16 __builtin_bswap16 +#endif +#if MBEDTLS_GCC_VERSION >= 40300 +#define MBEDTLS_BSWAP32 __builtin_bswap32 +#define MBEDTLS_BSWAP64 __builtin_bswap64 +#endif +#endif /* defined(__GNUC__) */ + +/* + * Detect Clang built-in byteswap routines + */ +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_bswap16) && !defined(MBEDTLS_BSWAP16) +#define MBEDTLS_BSWAP16 __builtin_bswap16 +#endif /* __has_builtin(__builtin_bswap16) */ +#if __has_builtin(__builtin_bswap32) && !defined(MBEDTLS_BSWAP32) +#define MBEDTLS_BSWAP32 __builtin_bswap32 +#endif /* __has_builtin(__builtin_bswap32) */ +#if __has_builtin(__builtin_bswap64) && !defined(MBEDTLS_BSWAP64) +#define MBEDTLS_BSWAP64 __builtin_bswap64 +#endif /* __has_builtin(__builtin_bswap64) */ +#endif /* defined(__clang__) && defined(__has_builtin) */ + +/* + * Detect MSVC built-in byteswap routines + */ +#if defined(_MSC_VER) +#if !defined(MBEDTLS_BSWAP16) +#define MBEDTLS_BSWAP16 _byteswap_ushort +#endif +#if !defined(MBEDTLS_BSWAP32) +#define MBEDTLS_BSWAP32 _byteswap_ulong +#endif +#if !defined(MBEDTLS_BSWAP64) +#define MBEDTLS_BSWAP64 _byteswap_uint64 +#endif +#endif /* defined(_MSC_VER) */ + +/* Detect armcc built-in byteswap routine */ +#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 410000) && !defined(MBEDTLS_BSWAP32) +#if defined(__ARM_ACLE) /* ARM Compiler 6 - earlier versions don't need a header */ +#include +#endif +#define MBEDTLS_BSWAP32 __rev +#endif + +/* Detect IAR built-in byteswap routine */ +#if defined(__IAR_SYSTEMS_ICC__) +#if defined(__ARM_ACLE) +#include +#define MBEDTLS_BSWAP16(x) ((uint16_t) __rev16((uint32_t) (x))) +#define MBEDTLS_BSWAP32 __rev +#define MBEDTLS_BSWAP64 __revll +#endif +#endif + +/* + * Where compiler built-ins are not present, fall back to C code that the + * compiler may be able to detect and transform into the relevant bswap or + * similar instruction. + */ +#if !defined(MBEDTLS_BSWAP16) +static inline uint16_t mbedtls_bswap16(uint16_t x) +{ + return + (x & 0x00ff) << 8 | + (x & 0xff00) >> 8; +} +#define MBEDTLS_BSWAP16 mbedtls_bswap16 +#endif /* !defined(MBEDTLS_BSWAP16) */ + +#if !defined(MBEDTLS_BSWAP32) +static inline uint32_t mbedtls_bswap32(uint32_t x) +{ + return + (x & 0x000000ff) << 24 | + (x & 0x0000ff00) << 8 | + (x & 0x00ff0000) >> 8 | + (x & 0xff000000) >> 24; +} +#define MBEDTLS_BSWAP32 mbedtls_bswap32 +#endif /* !defined(MBEDTLS_BSWAP32) */ + +#if !defined(MBEDTLS_BSWAP64) +static inline uint64_t mbedtls_bswap64(uint64_t x) +{ + return + (x & 0x00000000000000ffULL) << 56 | + (x & 0x000000000000ff00ULL) << 40 | + (x & 0x0000000000ff0000ULL) << 24 | + (x & 0x00000000ff000000ULL) << 8 | + (x & 0x000000ff00000000ULL) >> 8 | + (x & 0x0000ff0000000000ULL) >> 24 | + (x & 0x00ff000000000000ULL) >> 40 | + (x & 0xff00000000000000ULL) >> 56; +} +#define MBEDTLS_BSWAP64 mbedtls_bswap64 +#endif /* !defined(MBEDTLS_BSWAP64) */ + +#if !defined(__BYTE_ORDER__) + +#if defined(__LITTLE_ENDIAN__) +/* IAR defines __xxx_ENDIAN__, but not __BYTE_ORDER__ */ +#define MBEDTLS_IS_BIG_ENDIAN 0 +#elif defined(__BIG_ENDIAN__) +#define MBEDTLS_IS_BIG_ENDIAN 1 +#else +static const uint16_t mbedtls_byte_order_detector = { 0x100 }; +#define MBEDTLS_IS_BIG_ENDIAN (*((unsigned char *) (&mbedtls_byte_order_detector)) == 0x01) +#endif + +#else + +#if (__BYTE_ORDER__) == (__ORDER_BIG_ENDIAN__) +#define MBEDTLS_IS_BIG_ENDIAN 1 +#else +#define MBEDTLS_IS_BIG_ENDIAN 0 +#endif + +#endif /* !defined(__BYTE_ORDER__) */ + +/** + * Get the unsigned 32 bits integer corresponding to four bytes in + * big-endian order (MSB first). + * + * \param data Base address of the memory to get the four bytes from. + * \param offset Offset from \p data of the first and most significant + * byte of the four bytes to build the 32 bits unsigned + * integer from. + */ +#define MBEDTLS_GET_UINT32_BE(data, offset) \ + ((MBEDTLS_IS_BIG_ENDIAN) \ + ? mbedtls_get_unaligned_uint32((data) + (offset)) \ + : MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \ + ) + +/** + * Put in memory a 32 bits unsigned integer in big-endian order. + * + * \param n 32 bits unsigned integer to put in memory. + * \param data Base address of the memory where to put the 32 + * bits unsigned integer in. + * \param offset Offset from \p data where to put the most significant + * byte of the 32 bits unsigned integer \p n. + */ +#define MBEDTLS_PUT_UINT32_BE(n, data, offset) \ + { \ + if (MBEDTLS_IS_BIG_ENDIAN) \ + { \ + mbedtls_put_unaligned_uint32((data) + (offset), (uint32_t) (n)); \ + } \ + else \ + { \ + mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t) (n))); \ + } \ + } + +/** + * Get the unsigned 32 bits integer corresponding to four bytes in + * little-endian order (LSB first). + * + * \param data Base address of the memory to get the four bytes from. + * \param offset Offset from \p data of the first and least significant + * byte of the four bytes to build the 32 bits unsigned + * integer from. + */ +#define MBEDTLS_GET_UINT32_LE(data, offset) \ + ((MBEDTLS_IS_BIG_ENDIAN) \ + ? MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \ + : mbedtls_get_unaligned_uint32((data) + (offset)) \ + ) + + +/** + * Put in memory a 32 bits unsigned integer in little-endian order. + * + * \param n 32 bits unsigned integer to put in memory. + * \param data Base address of the memory where to put the 32 + * bits unsigned integer in. + * \param offset Offset from \p data where to put the least significant + * byte of the 32 bits unsigned integer \p n. + */ +#define MBEDTLS_PUT_UINT32_LE(n, data, offset) \ + { \ + if (MBEDTLS_IS_BIG_ENDIAN) \ + { \ + mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t) (n))); \ + } \ + else \ + { \ + mbedtls_put_unaligned_uint32((data) + (offset), ((uint32_t) (n))); \ + } \ + } + +/** + * Get the unsigned 16 bits integer corresponding to two bytes in + * little-endian order (LSB first). + * + * \param data Base address of the memory to get the two bytes from. + * \param offset Offset from \p data of the first and least significant + * byte of the two bytes to build the 16 bits unsigned + * integer from. + */ +#define MBEDTLS_GET_UINT16_LE(data, offset) \ + ((MBEDTLS_IS_BIG_ENDIAN) \ + ? MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \ + : mbedtls_get_unaligned_uint16((data) + (offset)) \ + ) + +/** + * Put in memory a 16 bits unsigned integer in little-endian order. + * + * \param n 16 bits unsigned integer to put in memory. + * \param data Base address of the memory where to put the 16 + * bits unsigned integer in. + * \param offset Offset from \p data where to put the least significant + * byte of the 16 bits unsigned integer \p n. + */ +#define MBEDTLS_PUT_UINT16_LE(n, data, offset) \ + { \ + if (MBEDTLS_IS_BIG_ENDIAN) \ + { \ + mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t) (n))); \ + } \ + else \ + { \ + mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t) (n)); \ + } \ + } + +/** + * Get the unsigned 16 bits integer corresponding to two bytes in + * big-endian order (MSB first). + * + * \param data Base address of the memory to get the two bytes from. + * \param offset Offset from \p data of the first and most significant + * byte of the two bytes to build the 16 bits unsigned + * integer from. + */ +#define MBEDTLS_GET_UINT16_BE(data, offset) \ + ((MBEDTLS_IS_BIG_ENDIAN) \ + ? mbedtls_get_unaligned_uint16((data) + (offset)) \ + : MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \ + ) + +/** + * Put in memory a 16 bits unsigned integer in big-endian order. + * + * \param n 16 bits unsigned integer to put in memory. + * \param data Base address of the memory where to put the 16 + * bits unsigned integer in. + * \param offset Offset from \p data where to put the most significant + * byte of the 16 bits unsigned integer \p n. + */ +#define MBEDTLS_PUT_UINT16_BE(n, data, offset) \ + { \ + if (MBEDTLS_IS_BIG_ENDIAN) \ + { \ + mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t) (n)); \ + } \ + else \ + { \ + mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t) (n))); \ + } \ + } + +/** + * Get the unsigned 24 bits integer corresponding to three bytes in + * big-endian order (MSB first). + * + * \param data Base address of the memory to get the three bytes from. + * \param offset Offset from \p data of the first and most significant + * byte of the three bytes to build the 24 bits unsigned + * integer from. + */ +#define MBEDTLS_GET_UINT24_BE(data, offset) \ + ( \ + ((uint32_t) (data)[(offset)] << 16) \ + | ((uint32_t) (data)[(offset) + 1] << 8) \ + | ((uint32_t) (data)[(offset) + 2]) \ + ) + +/** + * Put in memory a 24 bits unsigned integer in big-endian order. + * + * \param n 24 bits unsigned integer to put in memory. + * \param data Base address of the memory where to put the 24 + * bits unsigned integer in. + * \param offset Offset from \p data where to put the most significant + * byte of the 24 bits unsigned integer \p n. + */ +#define MBEDTLS_PUT_UINT24_BE(n, data, offset) \ + { \ + (data)[(offset)] = MBEDTLS_BYTE_2(n); \ + (data)[(offset) + 1] = MBEDTLS_BYTE_1(n); \ + (data)[(offset) + 2] = MBEDTLS_BYTE_0(n); \ + } + +/** + * Get the unsigned 24 bits integer corresponding to three bytes in + * little-endian order (LSB first). + * + * \param data Base address of the memory to get the three bytes from. + * \param offset Offset from \p data of the first and least significant + * byte of the three bytes to build the 24 bits unsigned + * integer from. + */ +#define MBEDTLS_GET_UINT24_LE(data, offset) \ + ( \ + ((uint32_t) (data)[(offset)]) \ + | ((uint32_t) (data)[(offset) + 1] << 8) \ + | ((uint32_t) (data)[(offset) + 2] << 16) \ + ) + +/** + * Put in memory a 24 bits unsigned integer in little-endian order. + * + * \param n 24 bits unsigned integer to put in memory. + * \param data Base address of the memory where to put the 24 + * bits unsigned integer in. + * \param offset Offset from \p data where to put the least significant + * byte of the 24 bits unsigned integer \p n. + */ +#define MBEDTLS_PUT_UINT24_LE(n, data, offset) \ + { \ + (data)[(offset)] = MBEDTLS_BYTE_0(n); \ + (data)[(offset) + 1] = MBEDTLS_BYTE_1(n); \ + (data)[(offset) + 2] = MBEDTLS_BYTE_2(n); \ + } + +/** + * Get the unsigned 64 bits integer corresponding to eight bytes in + * big-endian order (MSB first). + * + * \param data Base address of the memory to get the eight bytes from. + * \param offset Offset from \p data of the first and most significant + * byte of the eight bytes to build the 64 bits unsigned + * integer from. + */ +#define MBEDTLS_GET_UINT64_BE(data, offset) \ + ((MBEDTLS_IS_BIG_ENDIAN) \ + ? mbedtls_get_unaligned_uint64((data) + (offset)) \ + : MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \ + ) + +/** + * Put in memory a 64 bits unsigned integer in big-endian order. + * + * \param n 64 bits unsigned integer to put in memory. + * \param data Base address of the memory where to put the 64 + * bits unsigned integer in. + * \param offset Offset from \p data where to put the most significant + * byte of the 64 bits unsigned integer \p n. + */ +#define MBEDTLS_PUT_UINT64_BE(n, data, offset) \ + { \ + if (MBEDTLS_IS_BIG_ENDIAN) \ + { \ + mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t) (n)); \ + } \ + else \ + { \ + mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t) (n))); \ + } \ + } + +/** + * Get the unsigned 64 bits integer corresponding to eight bytes in + * little-endian order (LSB first). + * + * \param data Base address of the memory to get the eight bytes from. + * \param offset Offset from \p data of the first and least significant + * byte of the eight bytes to build the 64 bits unsigned + * integer from. + */ +#define MBEDTLS_GET_UINT64_LE(data, offset) \ + ((MBEDTLS_IS_BIG_ENDIAN) \ + ? MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \ + : mbedtls_get_unaligned_uint64((data) + (offset)) \ + ) + +/** + * Put in memory a 64 bits unsigned integer in little-endian order. + * + * \param n 64 bits unsigned integer to put in memory. + * \param data Base address of the memory where to put the 64 + * bits unsigned integer in. + * \param offset Offset from \p data where to put the least significant + * byte of the 64 bits unsigned integer \p n. + */ +#define MBEDTLS_PUT_UINT64_LE(n, data, offset) \ + { \ + if (MBEDTLS_IS_BIG_ENDIAN) \ + { \ + mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t) (n))); \ + } \ + else \ + { \ + mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t) (n)); \ + } \ + } + +#endif /* TF_PSA_CRYPTO_ALIGNMENT_H */ diff --git a/tf-psa-crypto/core/check_crypto_config.h b/tf-psa-crypto/core/check_crypto_config.h new file mode 100644 index 0000000000..070881ed90 --- /dev/null +++ b/tf-psa-crypto/core/check_crypto_config.h @@ -0,0 +1,111 @@ +/** + * \file check_crypto_config.h + * + * \brief Consistency checks for PSA configuration options + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +/* + * It is recommended to include this file from your crypto_config.h + * in order to catch dependency issues early. + */ + +#ifndef TF_PSA_CRYPTO_CHECK_CRYPTO_CONFIG_H +#define TF_PSA_CRYPTO_CHECK_CRYPTO_CONFIG_H + +#if defined(PSA_WANT_ALG_CCM) && \ + !(defined(PSA_WANT_KEY_TYPE_AES) || \ + defined(PSA_WANT_KEY_TYPE_CAMELLIA)) +#error "PSA_WANT_ALG_CCM defined, but not all prerequisites" +#endif + +#if defined(PSA_WANT_ALG_CMAC) && \ + !(defined(PSA_WANT_KEY_TYPE_AES) || \ + defined(PSA_WANT_KEY_TYPE_CAMELLIA)) +#error "PSA_WANT_ALG_CMAC defined, but not all prerequisites" +#endif + +#if defined(PSA_WANT_ALG_DETERMINISTIC_ECDSA) && \ + !(defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC) || \ + defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY)) +#error "PSA_WANT_ALG_DETERMINISTIC_ECDSA defined, but not all prerequisites" +#endif + +#if defined(PSA_WANT_ALG_ECDSA) && \ + !(defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC) || \ + defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY)) +#error "PSA_WANT_ALG_ECDSA defined, but not all prerequisites" +#endif + +#if defined(PSA_WANT_ALG_GCM) && \ + !(defined(PSA_WANT_KEY_TYPE_AES) || \ + defined(PSA_WANT_KEY_TYPE_CAMELLIA)) +#error "PSA_WANT_ALG_GCM defined, but not all prerequisites" +#endif + +#if defined(PSA_WANT_ALG_RSA_PKCS1V15_CRYPT) && \ + !(defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC) || \ + defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY)) +#error "PSA_WANT_ALG_RSA_PKCS1V15_CRYPT defined, but not all prerequisites" +#endif + +#if defined(PSA_WANT_ALG_RSA_PKCS1V15_SIGN) && \ + !(defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC) || \ + defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY)) +#error "PSA_WANT_ALG_RSA_PKCS1V15_SIGN defined, but not all prerequisites" +#endif + +#if defined(PSA_WANT_ALG_RSA_OAEP) && \ + !(defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC) || \ + defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY)) +#error "PSA_WANT_ALG_RSA_OAEP defined, but not all prerequisites" +#endif + +#if defined(PSA_WANT_ALG_RSA_PSS) && \ + !(defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC) || \ + defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY)) +#error "PSA_WANT_ALG_RSA_PSS defined, but not all prerequisites" +#endif + +#if (defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC) || \ + defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \ + defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \ + defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE) || \ + defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE)) && \ + !defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) +#error "PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_xxx defined, but not all prerequisites" +#endif + +#if (defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC) || \ + defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT) || \ + defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT) || \ + defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE)) && \ + !defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY) +#error "PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_xxx defined, but not all prerequisites" +#endif + +#if (defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC) || \ + defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT) || \ + defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_EXPORT) || \ + defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE)) && \ + !defined(PSA_WANT_KEY_TYPE_DH_PUBLIC_KEY) +#error "PSA_WANT_KEY_TYPE_DH_KEY_PAIR_xxx defined, but not all prerequisites" +#endif + +#if defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_DERIVE) +#error "PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_DERIVE defined, but feature is not supported" +#endif + +#if defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_DERIVE) +#error "PSA_WANT_KEY_TYPE_DH_KEY_PAIR_DERIVE defined, but feature is not supported" +#endif + +#if defined(PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS) && \ + !defined(PSA_WANT_ALG_SHA_256) +#error "PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS defined, but not all prerequisites" +#endif + +#endif /* TF_PSA_CRYPTO_CHECK_CRYPTO_CONFIG_H */ diff --git a/tf-psa-crypto/core/crypto-library.make b/tf-psa-crypto/core/crypto-library.make new file mode 100644 index 0000000000..c511ff8bae --- /dev/null +++ b/tf-psa-crypto/core/crypto-library.make @@ -0,0 +1,57 @@ +# Helper code for library/Makefile in Mbed TLS. +# This file is only meant to be included by library/Makefile in Mbed TLS and +# is unlikely to work in another context. + +ifeq (,$(BUILDING_LIBTESTDRIVER1)) +# List the generated files from crypto that are needed in the build, +# because we don't have the list in a consumable form. +TF_PSA_CRYPTO_LIBRARY_GENERATED_FILES := \ + $(TF_PSA_CRYPTO_CORE_PATH)/psa_crypto_driver_wrappers.h \ + $(TF_PSA_CRYPTO_CORE_PATH)/psa_crypto_driver_wrappers_no_static.c \ + $(TF_PSA_CRYPTO_CORE_PATH)/tf_psa_crypto_config_check_before.h \ + $(TF_PSA_CRYPTO_CORE_PATH)/tf_psa_crypto_config_check_final.h \ + $(TF_PSA_CRYPTO_CORE_PATH)/tf_psa_crypto_config_check_user.h + +GENERATED_WRAPPER_FILES = \ + $(TF_PSA_CRYPTO_CORE_PATH)/psa_crypto_driver_wrappers.h \ + $(TF_PSA_CRYPTO_CORE_PATH)/psa_crypto_driver_wrappers_no_static.c +$(GENERATED_WRAPPER_FILES): ../tf-psa-crypto/scripts/generate_driver_wrappers.py +$(GENERATED_WRAPPER_FILES): ../tf-psa-crypto/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.h.jinja +$(GENERATED_WRAPPER_FILES): ../tf-psa-crypto/scripts/data_files/driver_templates/psa_crypto_driver_wrappers_no_static.c.jinja +$(GENERATED_WRAPPER_FILES): + echo " Gen $(GENERATED_WRAPPER_FILES)" + $(PYTHON) ../tf-psa-crypto/scripts/generate_driver_wrappers.py $(TF_PSA_CRYPTO_CORE_PATH) + +$(TF_PSA_CRYPTO_CORE_PATH)/psa_crypto.o:$(TF_PSA_CRYPTO_CORE_PATH)/psa_crypto_driver_wrappers.h + +TF_PSA_CRYPTO_GENERATED_CONFIG_CHECK_FILES = $(shell $(PYTHON) \ + $(TF_PSA_CRYPTO_CORE_PATH)/../scripts/generate_config_checks.py \ + --list $(TF_PSA_CRYPTO_CORE_PATH)) +$(TF_PSA_CRYPTO_GENERATED_CONFIG_CHECK_FILES): $(gen_file_dep) \ + $(TF_PSA_CRYPTO_CORE_PATH)/../scripts/generate_config_checks.py \ + ../framework/scripts/mbedtls_framework/config_checks_generator.py +$(TF_PSA_CRYPTO_GENERATED_CONFIG_CHECK_FILES): + echo " Gen $(TF_PSA_CRYPTO_GENERATED_CONFIG_CHECK_FILES)" + $(PYTHON) $(TF_PSA_CRYPTO_CORE_PATH)/../scripts/generate_config_checks.py + +$(TF_PSA_CRYPTO_CORE_PATH)/tf_psa_crypto_config.o: $(TF_PSA_CRYPTO_GENERATED_CONFIG_CHECK_FILES) + +else # BUILDING_LIBTESTDRIVER1 empty? +# When building libtestdriver1, assume that the generated files are present +# and up-to-date. This way, we don't need the file generation scripts to +# work in the libtestdriver1 tree, where they might not find all the data +# files that they need. +TF_PSA_CRYPTO_LIBRARY_GENERATED_FILES := +endif # BUILDING_LIBTESTDRIVER1 empty? + +TF_PSA_CRYPTO_LIBRARY_OBJS := $(patsubst %.c, %.o,$(wildcard \ + $(TF_PSA_CRYPTO_CORE_PATH)/*.c \ + $(TF_PSA_CRYPTO_DRIVERS_BUILTIN_SRC_PATH)/*.c \ + $(TF_PSA_CRYPTO_PATH)/dispatch/*.c \ + $(TF_PSA_CRYPTO_PATH)/extras/*.c \ + $(TF_PSA_CRYPTO_PATH)/platform/*.c \ + $(TF_PSA_CRYPTO_PATH)/utilities/*.c)) +TF_PSA_CRYPTO_LIBRARY_GENERATED_OBJS = $(TF_PSA_CRYPTO_CORE_PATH)/psa_crypto_driver_wrappers_no_static.o +TF_PSA_CRYPTO_LIBRARY_OBJS := $(filter-out $(TF_PSA_CRYPTO_LIBRARY_GENERATED_OBJS),$(TF_PSA_CRYPTO_LIBRARY_OBJS)) +TF_PSA_CRYPTO_LIBRARY_OBJS += $(TF_PSA_CRYPTO_LIBRARY_GENERATED_OBJS) +TF_PSA_CRYPTO_LIBRARY_OBJS+=$(THIRDPARTY_CRYPTO_OBJECTS) diff --git a/tf-psa-crypto/core/psa_crypto.c b/tf-psa-crypto/core/psa_crypto.c new file mode 100644 index 0000000000..d7931d2254 --- /dev/null +++ b/tf-psa-crypto/core/psa_crypto.c @@ -0,0 +1,9805 @@ +/* + * PSA crypto layer on top of Mbed TLS crypto + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" +#include "psa_crypto_core_common.h" + +#if defined(MBEDTLS_PSA_CRYPTO_C) + +#include "check_crypto_config.h" +#include "psa/crypto.h" +#include "psa/crypto_values.h" + +#include "psa_crypto_cipher.h" +#include "psa_crypto_core.h" +#include "psa_crypto_invasive.h" +#include "psa_crypto_driver_wrappers.h" +#include "psa_crypto_driver_wrappers_no_static.h" +#include "psa_crypto_ecp.h" +#include "psa_crypto_ffdh.h" +#include "psa_crypto_hash.h" +#include "psa_crypto_mac.h" +#include "psa_crypto_rsa.h" +#include "psa_crypto_ecp.h" +#include "psa_crypto_slot_management.h" +/* Include internal declarations that are useful for implementing persistently + * stored keys. */ +#include "psa_crypto_storage.h" + +#include "psa_crypto_random.h" +#include "psa_crypto_random_impl.h" + +#include +#include +#include "mbedtls/platform.h" + +#include "mbedtls/private/aes.h" +#include "mbedtls/asn1.h" +#include "mbedtls/asn1write.h" +#include "mbedtls/private/bignum.h" +#include "mbedtls/private/camellia.h" +#include "mbedtls/private/chacha20.h" +#include "mbedtls/private/chachapoly.h" +#include "mbedtls/private/cipher.h" +#include "mbedtls/private/ccm.h" +#include "mbedtls/private/cmac.h" +#include "mbedtls/constant_time.h" +#include "mbedtls/private/ecp.h" +#include "mbedtls/private/entropy.h" +#include "mbedtls/private/error_common.h" +#include "mbedtls/private/gcm.h" +#include "mbedtls/private/md5.h" +#include "mbedtls/pk.h" +#if defined(MBEDTLS_PK_HAVE_PRIVATE_HEADER) +#include +#endif /* MBEDTLS_PK_HAVE_PRIVATE_HEADER */ +#include "pk_wrap.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" +#include "mbedtls/private/ripemd160.h" +#include "mbedtls/private/rsa.h" +#include "mbedtls/private/sha1.h" +#include "mbedtls/private/sha256.h" +#include "mbedtls/private/sha512.h" +#include "psa_util_internal.h" +#include "mbedtls/threading.h" +#include "threading_internal.h" + +#include "constant_time_internal.h" + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND) +#define BUILTIN_ALG_ANY_HKDF 1 +#endif + +/****************************************************************/ +/* Global data, support functions and library management */ +/****************************************************************/ + +static int key_type_is_raw_bytes(psa_key_type_t type) +{ + return PSA_KEY_TYPE_IS_UNSTRUCTURED(type); +} + +/* Values for psa_global_data_t::rng_state */ +#define RNG_NOT_INITIALIZED 0 +#define RNG_INITIALIZED 1 +#define RNG_SEEDED 2 + +/* IDs for PSA crypto subsystems. Starts at 1 to catch potential uninitialized + * variables as arguments. */ +typedef enum { + PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS = 1, + PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS, + PSA_CRYPTO_SUBSYSTEM_RNG, + PSA_CRYPTO_SUBSYSTEM_TRANSACTION, +} mbedtls_psa_crypto_subsystem; + +/* Initialization flags for global_data::initialized */ +#define PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS_INITIALIZED 0x01 +#define PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS_INITIALIZED 0x02 +#define PSA_CRYPTO_SUBSYSTEM_TRANSACTION_INITIALIZED 0x04 + +#define PSA_CRYPTO_SUBSYSTEM_ALL_INITIALISED ( \ + PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS_INITIALIZED | \ + PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS_INITIALIZED | \ + PSA_CRYPTO_SUBSYSTEM_TRANSACTION_INITIALIZED) + +typedef struct { + uint8_t initialized; + uint8_t rng_state; + mbedtls_psa_random_context_t rng; +} psa_global_data_t; + +static psa_global_data_t global_data; + +static uint8_t psa_get_initialized(void) +{ + uint8_t initialized; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + + initialized = global_data.rng_state == RNG_SEEDED; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + + initialized = + (initialized && (global_data.initialized == PSA_CRYPTO_SUBSYSTEM_ALL_INITIALISED)); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_unlock(&mbedtls_threading_psa_globaldata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + + return initialized; +} + +static uint8_t psa_get_drivers_initialized(void) +{ + uint8_t initialized; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + + initialized = (global_data.initialized & PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS_INITIALIZED) != 0; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_unlock(&mbedtls_threading_psa_globaldata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + + return initialized; +} + +int psa_is_ready_for_cipher(void) +{ + return psa_get_drivers_initialized(); +} + +/* Dummy version of a function removed in + * https://github.com/Mbed-TLS/TF-PSA-Crypto/pull/466 + * + * The function needs to remain available during a transition period + * for the sake of the PSA simulator, which lives in Mbed TLS. + * Once TF-PSA-Crypto no longer needs the function, + * `tests/psa-client-server/psasim/src/psa_sim_crypto_server.c` will + * need to be updated to no longer need the function, and it will be + * possible to remove the corresponding RPC call altogether. + */ +int psa_can_do_hash(psa_algorithm_t hash_alg) +{ + (void) hash_alg; + return 1; +} + +#define GUARD_MODULE_INITIALIZED \ + if (psa_get_initialized() == 0) \ + return PSA_ERROR_BAD_STATE; + +#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) + +/* Declare a local copy of an input buffer and a variable that will be used + * to store a pointer to the start of the buffer. + * + * Note: This macro must be called before any operations which may jump to + * the exit label, so that the local input copy object is safe to be freed. + * + * Assumptions: + * - input is the name of a pointer to the buffer to be copied + * - The name LOCAL_INPUT_COPY_OF_input is unused in the current scope + * - input_copy_name is a name that is unused in the current scope + */ +#define LOCAL_INPUT_DECLARE(input, input_copy_name) \ + psa_crypto_local_input_t LOCAL_INPUT_COPY_OF_##input = PSA_CRYPTO_LOCAL_INPUT_INIT; \ + const uint8_t *input_copy_name = NULL; + +/* Allocate a copy of the buffer input and set the pointer input_copy to + * point to the start of the copy. + * + * Assumptions: + * - psa_status_t status exists + * - An exit label is declared + * - input is the name of a pointer to the buffer to be copied + * - LOCAL_INPUT_DECLARE(input, input_copy) has previously been called + */ +#define LOCAL_INPUT_ALLOC(input, length, input_copy) \ + status = psa_crypto_local_input_alloc(input, length, \ + &LOCAL_INPUT_COPY_OF_##input); \ + if (status != PSA_SUCCESS) { \ + goto exit; \ + } \ + input_copy = LOCAL_INPUT_COPY_OF_##input.buffer; + +/* Free the local input copy allocated previously by LOCAL_INPUT_ALLOC() + * + * Assumptions: + * - input_copy is the name of the input copy pointer set by LOCAL_INPUT_ALLOC() + * - input is the name of the original buffer that was copied + */ +#define LOCAL_INPUT_FREE(input, input_copy) \ + input_copy = NULL; \ + psa_crypto_local_input_free(&LOCAL_INPUT_COPY_OF_##input); + +/* Declare a local copy of an output buffer and a variable that will be used + * to store a pointer to the start of the buffer. + * + * Note: This macro must be called before any operations which may jump to + * the exit label, so that the local output copy object is safe to be freed. + * + * Assumptions: + * - output is the name of a pointer to the buffer to be copied + * - The name LOCAL_OUTPUT_COPY_OF_output is unused in the current scope + * - output_copy_name is a name that is unused in the current scope + */ +#define LOCAL_OUTPUT_DECLARE(output, output_copy_name) \ + psa_crypto_local_output_t LOCAL_OUTPUT_COPY_OF_##output = PSA_CRYPTO_LOCAL_OUTPUT_INIT; \ + uint8_t *output_copy_name = NULL; + +/* Allocate a copy of the buffer output and set the pointer output_copy to + * point to the start of the copy. + * + * Assumptions: + * - psa_status_t status exists + * - An exit label is declared + * - output is the name of a pointer to the buffer to be copied + * - LOCAL_OUTPUT_DECLARE(output, output_copy) has previously been called + */ +#define LOCAL_OUTPUT_ALLOC(output, length, output_copy) \ + status = psa_crypto_local_output_alloc(output, length, \ + &LOCAL_OUTPUT_COPY_OF_##output); \ + if (status != PSA_SUCCESS) { \ + goto exit; \ + } \ + output_copy = LOCAL_OUTPUT_COPY_OF_##output.buffer; + +/* Free the local output copy allocated previously by LOCAL_OUTPUT_ALLOC() + * after first copying back its contents to the original buffer. + * + * Assumptions: + * - psa_status_t status exists + * - output_copy is the name of the output copy pointer set by LOCAL_OUTPUT_ALLOC() + * - output is the name of the original buffer that was copied + */ +#define LOCAL_OUTPUT_FREE(output, output_copy) \ + output_copy = NULL; \ + do { \ + psa_status_t local_output_status; \ + local_output_status = psa_crypto_local_output_free(&LOCAL_OUTPUT_COPY_OF_##output); \ + if (local_output_status != PSA_SUCCESS) { \ + /* Since this error case is an internal error, it's more serious than \ + * any existing error code and so it's fine to overwrite the existing \ + * status. */ \ + status = local_output_status; \ + } \ + } while (0) +#else /* !MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS */ +#define LOCAL_INPUT_DECLARE(input, input_copy_name) \ + const uint8_t *input_copy_name = NULL; +#define LOCAL_INPUT_ALLOC(input, length, input_copy) \ + input_copy = input; +#define LOCAL_INPUT_FREE(input, input_copy) \ + input_copy = NULL; +#define LOCAL_OUTPUT_DECLARE(output, output_copy_name) \ + uint8_t *output_copy_name = NULL; +#define LOCAL_OUTPUT_ALLOC(output, length, output_copy) \ + output_copy = output; +#define LOCAL_OUTPUT_FREE(output, output_copy) \ + output_copy = NULL; +#endif /* !MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS */ + + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_IMPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_PUBLIC_KEY) || \ + defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE) +static int psa_is_dh_key_size_valid(size_t bits) +{ + switch (bits) { +#if defined(PSA_WANT_DH_RFC7919_2048) + case 2048: + return 1; +#endif /* PSA_WANT_DH_RFC7919_2048 */ +#if defined(PSA_WANT_DH_RFC7919_3072) + case 3072: + return 1; +#endif /* PSA_WANT_DH_RFC7919_3072 */ +#if defined(PSA_WANT_DH_RFC7919_4096) + case 4096: + return 1; +#endif /* PSA_WANT_DH_RFC7919_4096 */ +#if defined(PSA_WANT_DH_RFC7919_6144) + case 6144: + return 1; +#endif /* PSA_WANT_DH_RFC7919_6144 */ +#if defined(PSA_WANT_DH_RFC7919_8192) + case 8192: + return 1; +#endif /* PSA_WANT_DH_RFC7919_8192 */ + default: + return 0; + } +} +#endif /* MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_IMPORT || + MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_PUBLIC_KEY || + PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE */ + +psa_status_t mbedtls_to_psa_error(int ret) +{ + /* Only legacy error codes need to be translated. + * Those are either a low-level error code (-127..-2) + * or a high-level error code (<= -0x1000). */ + if (ret > -0x1000 && ret < -0x80) { + return (psa_status_t) ret; + } + /* Mbed TLS error codes can combine a high-level error code and a + * low-level error code. The low-level error usually reflects the + * root cause better, so dispatch on that preferably. */ + int low_level_ret = -(-ret & 0x007f); + switch (low_level_ret != 0 ? low_level_ret : ret) { + case 0: + return PSA_SUCCESS; + +#if defined(MBEDTLS_AES_C) + case MBEDTLS_ERR_AES_INVALID_KEY_LENGTH: + case MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH: + return PSA_ERROR_NOT_SUPPORTED; +#endif + +#if defined(MBEDTLS_ASN1_PARSE_C) || defined(MBEDTLS_ASN1_WRITE_C) + case MBEDTLS_ERR_ASN1_OUT_OF_DATA: + case MBEDTLS_ERR_ASN1_UNEXPECTED_TAG: + case MBEDTLS_ERR_ASN1_INVALID_LENGTH: + case MBEDTLS_ERR_ASN1_LENGTH_MISMATCH: + case MBEDTLS_ERR_ASN1_INVALID_DATA: + return PSA_ERROR_INVALID_ARGUMENT; +#endif + +#if defined(MBEDTLS_CAMELLIA_C) + case MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH: + return PSA_ERROR_NOT_SUPPORTED; +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + case MBEDTLS_ERR_CHACHAPOLY_BAD_STATE: + return PSA_ERROR_BAD_STATE; +#endif + +#if defined(MBEDTLS_CIPHER_C) + case MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE: + return PSA_ERROR_NOT_SUPPORTED; + case MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED: + return PSA_ERROR_INVALID_ARGUMENT; + case MBEDTLS_ERR_CIPHER_INVALID_CONTEXT: + return PSA_ERROR_CORRUPTION_DETECTED; +#endif + +#if !(defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) || \ + defined(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE)) + /* Only check CTR_DRBG error codes if underlying mbedtls_xxx + * functions are passed a CTR_DRBG instance. */ + case MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED: + return PSA_ERROR_INSUFFICIENT_ENTROPY; + case MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG: + case MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG: + return PSA_ERROR_NOT_SUPPORTED; + case MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR: + return PSA_ERROR_INSUFFICIENT_ENTROPY; +#endif + + case MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED: + case MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE: + case MBEDTLS_ERR_ENTROPY_SOURCE_FAILED: + return PSA_ERROR_INSUFFICIENT_ENTROPY; + +#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) && \ + defined(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE) + /* Only check HMAC_DRBG error codes if underlying mbedtls_xxx + * functions are passed a HMAC_DRBG instance. */ + case MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED: + return PSA_ERROR_INSUFFICIENT_ENTROPY; + case MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG: + case MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG: + return PSA_ERROR_NOT_SUPPORTED; + case MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR: + return PSA_ERROR_INSUFFICIENT_ENTROPY; +#endif + +#if defined(MBEDTLS_MD_LIGHT) + case MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE: + return PSA_ERROR_NOT_SUPPORTED; +#if defined(MBEDTLS_FS_IO) + case MBEDTLS_ERR_MD_FILE_IO_ERROR: + return PSA_ERROR_STORAGE_FAILURE; +#endif +#endif + +#if defined(MBEDTLS_BIGNUM_C) +#if defined(MBEDTLS_FS_IO) + case MBEDTLS_ERR_MPI_FILE_IO_ERROR: + return PSA_ERROR_STORAGE_FAILURE; +#endif + case MBEDTLS_ERR_MPI_INVALID_CHARACTER: + return PSA_ERROR_INVALID_ARGUMENT; + case MBEDTLS_ERR_MPI_NEGATIVE_VALUE: + return PSA_ERROR_INVALID_ARGUMENT; + case MBEDTLS_ERR_MPI_DIVISION_BY_ZERO: + return PSA_ERROR_INVALID_ARGUMENT; + case MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: + return PSA_ERROR_INVALID_ARGUMENT; +#endif + +#if defined(MBEDTLS_PK_C) + case MBEDTLS_ERR_PK_TYPE_MISMATCH: + return PSA_ERROR_INVALID_ARGUMENT; +#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) || defined(MBEDTLS_FS_IO) || \ + defined(MBEDTLS_PSA_ITS_FILE_C) + case MBEDTLS_ERR_PK_FILE_IO_ERROR: + return PSA_ERROR_STORAGE_FAILURE; +#endif + case MBEDTLS_ERR_PK_KEY_INVALID_VERSION: + case MBEDTLS_ERR_PK_KEY_INVALID_FORMAT: + return PSA_ERROR_INVALID_ARGUMENT; + case MBEDTLS_ERR_PK_UNKNOWN_PK_ALG: + return PSA_ERROR_NOT_SUPPORTED; + case MBEDTLS_ERR_PK_PASSWORD_REQUIRED: + case MBEDTLS_ERR_PK_PASSWORD_MISMATCH: + return PSA_ERROR_NOT_PERMITTED; + case MBEDTLS_ERR_PK_INVALID_PUBKEY: + return PSA_ERROR_INVALID_ARGUMENT; + case MBEDTLS_ERR_PK_INVALID_ALG: + case MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE: + case MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE: + return PSA_ERROR_NOT_SUPPORTED; +#endif + + case MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED: + return PSA_ERROR_HARDWARE_FAILURE; + case MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED: + return PSA_ERROR_NOT_SUPPORTED; + +#if defined(MBEDTLS_RSA_C) + case MBEDTLS_ERR_RSA_KEY_GEN_FAILED: + return PSA_ERROR_HARDWARE_FAILURE; + case MBEDTLS_ERR_RSA_KEY_CHECK_FAILED: + return PSA_ERROR_INVALID_ARGUMENT; + case MBEDTLS_ERR_RSA_PUBLIC_FAILED: + case MBEDTLS_ERR_RSA_PRIVATE_FAILED: + return PSA_ERROR_CORRUPTION_DETECTED; + case MBEDTLS_ERR_RSA_RNG_FAILED: + return PSA_ERROR_INSUFFICIENT_ENTROPY; +#endif + + case MBEDTLS_ERR_ECP_INVALID_KEY: + return PSA_ERROR_INVALID_ARGUMENT; + + case MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED: + return PSA_ERROR_CORRUPTION_DETECTED; + + default: + return PSA_ERROR_GENERIC_ERROR; + } +} + +/** + * \brief For output buffers which contain "tags" + * (outputs that may be checked for validity like + * hashes, MACs and signatures), fill the unused + * part of the output buffer (the whole buffer on + * error, the trailing part on success) with + * something that isn't a valid tag (barring an + * attack on the tag and deliberately-crafted + * input), in case the caller doesn't check the + * return status properly. + * + * \param output_buffer Pointer to buffer to wipe. May not be NULL + * unless \p output_buffer_size is zero. + * \param status Status of function called to generate + * output_buffer originally + * \param output_buffer_size Size of output buffer. If zero, \p output_buffer + * could be NULL. + * \param output_buffer_length Length of data written to output_buffer, must be + * less than \p output_buffer_size + */ +static void psa_wipe_tag_output_buffer(uint8_t *output_buffer, psa_status_t status, + size_t output_buffer_size, size_t output_buffer_length) +{ + size_t offset = 0; + + if (output_buffer_size == 0) { + /* If output_buffer_size is 0 then we have nothing to do. We must not + call memset because output_buffer may be NULL in this case */ + return; + } + + if (status == PSA_SUCCESS) { + offset = output_buffer_length; + } + + memset(output_buffer + offset, '!', output_buffer_size - offset); +} + + +psa_status_t psa_validate_unstructured_key_bit_size(psa_key_type_t type, + size_t bits) +{ + /* Check that the bit size is acceptable for the key type */ + switch (type) { + case PSA_KEY_TYPE_RAW_DATA: + case PSA_KEY_TYPE_HMAC: + case PSA_KEY_TYPE_DERIVE: + case PSA_KEY_TYPE_PASSWORD: + case PSA_KEY_TYPE_PASSWORD_HASH: + break; +#if defined(PSA_WANT_KEY_TYPE_AES) + case PSA_KEY_TYPE_AES: + if (bits != 128 && bits != 192 && bits != 256) { + return PSA_ERROR_INVALID_ARGUMENT; + } + break; +#endif +#if defined(PSA_WANT_KEY_TYPE_ARIA) + case PSA_KEY_TYPE_ARIA: + if (bits != 128 && bits != 192 && bits != 256) { + return PSA_ERROR_INVALID_ARGUMENT; + } + break; +#endif +#if defined(PSA_WANT_KEY_TYPE_CAMELLIA) + case PSA_KEY_TYPE_CAMELLIA: + if (bits != 128 && bits != 192 && bits != 256) { + return PSA_ERROR_INVALID_ARGUMENT; + } + break; +#endif +#if defined(PSA_WANT_KEY_TYPE_CHACHA20) + case PSA_KEY_TYPE_CHACHA20: + if (bits != 256) { + return PSA_ERROR_INVALID_ARGUMENT; + } + break; +#endif + default: + return PSA_ERROR_NOT_SUPPORTED; + } + if (bits % 8 != 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return PSA_SUCCESS; +} + +/** Check whether a given key type is valid for use with a given MAC algorithm + * + * Upon successful return of this function, the behavior of #PSA_MAC_LENGTH + * when called with the validated \p algorithm and \p key_type is well-defined. + * + * \param[in] algorithm The specific MAC algorithm (can be wildcard). + * \param[in] key_type The key type of the key to be used with the + * \p algorithm. + * + * \retval #PSA_SUCCESS + * The \p key_type is valid for use with the \p algorithm + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The \p key_type is not valid for use with the \p algorithm + */ +MBEDTLS_STATIC_TESTABLE psa_status_t psa_mac_key_can_do( + psa_algorithm_t algorithm, + psa_key_type_t key_type) +{ + if (PSA_ALG_IS_HMAC(algorithm)) { + if (key_type == PSA_KEY_TYPE_HMAC) { + return PSA_SUCCESS; + } + } + + if (PSA_ALG_IS_BLOCK_CIPHER_MAC(algorithm)) { + /* Check that we're calling PSA_BLOCK_CIPHER_BLOCK_LENGTH with a cipher + * key. */ + if ((key_type & PSA_KEY_TYPE_CATEGORY_MASK) == + PSA_KEY_TYPE_CATEGORY_SYMMETRIC) { + /* PSA_BLOCK_CIPHER_BLOCK_LENGTH returns 1 for stream ciphers and + * the block length (larger than 1) for block ciphers. */ + if (PSA_BLOCK_CIPHER_BLOCK_LENGTH(key_type) > 1) { + return PSA_SUCCESS; + } + } + } + + return PSA_ERROR_INVALID_ARGUMENT; +} + +psa_status_t psa_allocate_buffer_to_slot(psa_key_slot_t *slot, + size_t buffer_length) +{ +#if defined(MBEDTLS_PSA_STATIC_KEY_SLOTS) + if (buffer_length > ((size_t) MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE)) { + return PSA_ERROR_NOT_SUPPORTED; + } +#else + if (slot->key.data != NULL) { + return PSA_ERROR_ALREADY_EXISTS; + } + + slot->key.data = mbedtls_calloc(1, buffer_length); + if (slot->key.data == NULL) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } +#endif + + slot->key.bytes = buffer_length; + return PSA_SUCCESS; +} + +psa_status_t psa_copy_key_material_into_slot(psa_key_slot_t *slot, + const uint8_t *data, + size_t data_length) +{ + psa_status_t status = psa_allocate_buffer_to_slot(slot, + data_length); + if (status != PSA_SUCCESS) { + return status; + } + + memcpy(slot->key.data, data, data_length); + return PSA_SUCCESS; +} + +psa_status_t psa_import_key_into_slot( + const psa_key_attributes_t *attributes, + const uint8_t *data, size_t data_length, + uint8_t *key_buffer, size_t key_buffer_size, + size_t *key_buffer_length, size_t *bits) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_type_t type = attributes->type; + + /* zero-length keys are never supported. */ + if (data_length == 0) { + return PSA_ERROR_NOT_SUPPORTED; + } + + if (key_type_is_raw_bytes(type)) { + *bits = PSA_BYTES_TO_BITS(data_length); + + status = psa_validate_unstructured_key_bit_size(attributes->type, + *bits); + if (status != PSA_SUCCESS) { + return status; + } + + /* Copy the key material. */ + memcpy(key_buffer, data, data_length); + *key_buffer_length = data_length; + (void) key_buffer_size; + + return PSA_SUCCESS; + } else if (PSA_KEY_TYPE_IS_ASYMMETRIC(type)) { +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_IMPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_PUBLIC_KEY) + if (PSA_KEY_TYPE_IS_DH(type)) { + if (psa_is_dh_key_size_valid(PSA_BYTES_TO_BITS(data_length)) == 0) { + return PSA_ERROR_NOT_SUPPORTED; + } + return mbedtls_psa_ffdh_import_key(attributes, + data, data_length, + key_buffer, key_buffer_size, + key_buffer_length, + bits); + } +#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_IMPORT) || + * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_PUBLIC_KEY) */ +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) + if (PSA_KEY_TYPE_IS_ECC(type)) { + return mbedtls_psa_ecp_import_key(attributes, + data, data_length, + key_buffer, key_buffer_size, + key_buffer_length, + bits); + } +#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || + * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) */ +#if (defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_IMPORT) && \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT)) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) + if (PSA_KEY_TYPE_IS_RSA(type)) { + return mbedtls_psa_rsa_import_key(attributes, + data, data_length, + key_buffer, key_buffer_size, + key_buffer_length, + bits); + } +#endif /* (defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_IMPORT) && + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT)) || + * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) */ + } + + return PSA_ERROR_NOT_SUPPORTED; +} + +/** Calculate the intersection of two algorithm usage policies. + * + * Return 0 (which allows no operation) on incompatibility. + */ +static psa_algorithm_t psa_key_policy_algorithm_intersection( + psa_key_type_t key_type, + psa_algorithm_t alg1, + psa_algorithm_t alg2) +{ + /* Common case: both sides actually specify the same policy. */ + if (alg1 == alg2) { + return alg1; + } + /* If the policies are from the same hash-and-sign family, check + * if one is a wildcard. If so the other has the specific algorithm. */ + if (PSA_ALG_IS_SIGN_HASH(alg1) && + PSA_ALG_IS_SIGN_HASH(alg2) && + (alg1 & ~PSA_ALG_HASH_MASK) == (alg2 & ~PSA_ALG_HASH_MASK)) { + if (PSA_ALG_SIGN_GET_HASH(alg1) == PSA_ALG_ANY_HASH) { + return alg2; + } + if (PSA_ALG_SIGN_GET_HASH(alg2) == PSA_ALG_ANY_HASH) { + return alg1; + } + } + /* If the policies are from the same AEAD family, check whether + * one of them is a minimum-tag-length wildcard. Calculate the most + * restrictive tag length. */ + if (PSA_ALG_IS_AEAD(alg1) && PSA_ALG_IS_AEAD(alg2) && + (PSA_ALG_AEAD_WITH_SHORTENED_TAG(alg1, 0) == + PSA_ALG_AEAD_WITH_SHORTENED_TAG(alg2, 0))) { + size_t alg1_len = PSA_ALG_AEAD_GET_TAG_LENGTH(alg1); + size_t alg2_len = PSA_ALG_AEAD_GET_TAG_LENGTH(alg2); + size_t restricted_len = alg1_len > alg2_len ? alg1_len : alg2_len; + + /* If both are wildcards, return most restrictive wildcard */ + if (((alg1 & PSA_ALG_AEAD_AT_LEAST_THIS_LENGTH_FLAG) != 0) && + ((alg2 & PSA_ALG_AEAD_AT_LEAST_THIS_LENGTH_FLAG) != 0)) { + return PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG( + alg1, restricted_len); + } + /* If only one is a wildcard, return specific algorithm if compatible. */ + if (((alg1 & PSA_ALG_AEAD_AT_LEAST_THIS_LENGTH_FLAG) != 0) && + (alg1_len <= alg2_len)) { + return alg2; + } + if (((alg2 & PSA_ALG_AEAD_AT_LEAST_THIS_LENGTH_FLAG) != 0) && + (alg2_len <= alg1_len)) { + return alg1; + } + } + /* If the policies are from the same MAC family, check whether one + * of them is a minimum-MAC-length policy. Calculate the most + * restrictive tag length. */ + if (PSA_ALG_IS_MAC(alg1) && PSA_ALG_IS_MAC(alg2) && + (PSA_ALG_FULL_LENGTH_MAC(alg1) == + PSA_ALG_FULL_LENGTH_MAC(alg2))) { + /* Validate the combination of key type and algorithm. Since the base + * algorithm of alg1 and alg2 are the same, we only need this once. */ + if (PSA_SUCCESS != psa_mac_key_can_do(alg1, key_type)) { + return 0; + } + + /* Get the (exact or at-least) output lengths for both sides of the + * requested intersection. None of the currently supported algorithms + * have an output length dependent on the actual key size, so setting it + * to a bogus value of 0 is currently OK. + * + * Note that for at-least-this-length wildcard algorithms, the output + * length is set to the shortest allowed length, which allows us to + * calculate the most restrictive tag length for the intersection. */ + size_t alg1_len = PSA_MAC_LENGTH(key_type, 0, alg1); + size_t alg2_len = PSA_MAC_LENGTH(key_type, 0, alg2); + size_t restricted_len = alg1_len > alg2_len ? alg1_len : alg2_len; + + /* If both are wildcards, return most restrictive wildcard */ + if (((alg1 & PSA_ALG_MAC_AT_LEAST_THIS_LENGTH_FLAG) != 0) && + ((alg2 & PSA_ALG_MAC_AT_LEAST_THIS_LENGTH_FLAG) != 0)) { + return PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(alg1, restricted_len); + } + + /* If only one is an at-least-this-length policy, the intersection would + * be the other (fixed-length) policy as long as said fixed length is + * equal to or larger than the shortest allowed length. */ + if ((alg1 & PSA_ALG_MAC_AT_LEAST_THIS_LENGTH_FLAG) != 0) { + return (alg1_len <= alg2_len) ? alg2 : 0; + } + if ((alg2 & PSA_ALG_MAC_AT_LEAST_THIS_LENGTH_FLAG) != 0) { + return (alg2_len <= alg1_len) ? alg1 : 0; + } + + /* If none of them are wildcards, check whether they define the same tag + * length. This is still possible here when one is default-length and + * the other specific-length. Ensure to always return the + * specific-length version for the intersection. */ + if (alg1_len == alg2_len) { + return PSA_ALG_TRUNCATED_MAC(alg1, alg1_len); + } + } + /* If the policies are incompatible, allow nothing. */ + return 0; +} + +static int psa_key_algorithm_permits(psa_key_type_t key_type, + psa_algorithm_t policy_alg, + psa_algorithm_t requested_alg) +{ + /* Common case: the policy only allows requested_alg. */ + if (requested_alg == policy_alg) { + return 1; + } + /* If policy_alg is a hash-and-sign with a wildcard for the hash, + * and requested_alg is the same hash-and-sign family with any hash, + * then requested_alg is compliant with policy_alg. */ + if (PSA_ALG_IS_SIGN_HASH(requested_alg) && + PSA_ALG_SIGN_GET_HASH(policy_alg) == PSA_ALG_ANY_HASH) { + return (policy_alg & ~PSA_ALG_HASH_MASK) == + (requested_alg & ~PSA_ALG_HASH_MASK); + } + /* If policy_alg is a wildcard AEAD algorithm of the same base as + * the requested algorithm, check the requested tag length to be + * equal-length or longer than the wildcard-specified length. */ + if (PSA_ALG_IS_AEAD(policy_alg) && + PSA_ALG_IS_AEAD(requested_alg) && + (PSA_ALG_AEAD_WITH_SHORTENED_TAG(policy_alg, 0) == + PSA_ALG_AEAD_WITH_SHORTENED_TAG(requested_alg, 0)) && + ((policy_alg & PSA_ALG_AEAD_AT_LEAST_THIS_LENGTH_FLAG) != 0)) { + return PSA_ALG_AEAD_GET_TAG_LENGTH(policy_alg) <= + PSA_ALG_AEAD_GET_TAG_LENGTH(requested_alg); + } + /* If policy_alg is a MAC algorithm of the same base as the requested + * algorithm, check whether their MAC lengths are compatible. */ + if (PSA_ALG_IS_MAC(policy_alg) && + PSA_ALG_IS_MAC(requested_alg) && + (PSA_ALG_FULL_LENGTH_MAC(policy_alg) == + PSA_ALG_FULL_LENGTH_MAC(requested_alg))) { + /* Validate the combination of key type and algorithm. Since the policy + * and requested algorithms are the same, we only need this once. */ + if (PSA_SUCCESS != psa_mac_key_can_do(policy_alg, key_type)) { + return 0; + } + + /* Get both the requested output length for the algorithm which is to be + * verified, and the default output length for the base algorithm. + * Note that none of the currently supported algorithms have an output + * length dependent on actual key size, so setting it to a bogus value + * of 0 is currently OK. */ + size_t requested_output_length = PSA_MAC_LENGTH( + key_type, 0, requested_alg); + size_t default_output_length = PSA_MAC_LENGTH( + key_type, 0, + PSA_ALG_FULL_LENGTH_MAC(requested_alg)); + + /* If the policy is default-length, only allow an algorithm with + * a declared exact-length matching the default. */ + if (PSA_MAC_TRUNCATED_LENGTH(policy_alg) == 0) { + return requested_output_length == default_output_length; + } + + /* If the requested algorithm is default-length, allow it if the policy + * length exactly matches the default length. */ + if (PSA_MAC_TRUNCATED_LENGTH(requested_alg) == 0 && + PSA_MAC_TRUNCATED_LENGTH(policy_alg) == default_output_length) { + return 1; + } + + /* If policy_alg is an at-least-this-length wildcard MAC algorithm, + * check for the requested MAC length to be equal to or longer than the + * minimum allowed length. */ + if ((policy_alg & PSA_ALG_MAC_AT_LEAST_THIS_LENGTH_FLAG) != 0) { + return PSA_MAC_TRUNCATED_LENGTH(policy_alg) <= + requested_output_length; + } + } + /* If policy_alg is a generic key agreement operation, then using it for + * a key derivation with that key agreement should also be allowed. This + * behaviour is expected to be defined in a future specification version. */ + if (PSA_ALG_IS_RAW_KEY_AGREEMENT(policy_alg) && + PSA_ALG_IS_KEY_AGREEMENT(requested_alg)) { + return PSA_ALG_KEY_AGREEMENT_GET_BASE(requested_alg) == + policy_alg; + } + + if (policy_alg == PSA_ALG_JPAKE_BETA && + PSA_ALG_IS_JPAKE(requested_alg)) { + /* Support the legacy encoding of JPAKE (from Mbed TLS 3.x) in + * key policies. This legacy encoding doesn't specify a hash, + * so allow any hash algorithm for the operation. We do this + * for the sake of persistent keys that were created with + * Mbed TLS 3.x. To keep the implementation and the tests simpler, + * we also allow this when creating new keys, but we don't make + * any promises about that. */ + return 1; + } + + /* If it isn't explicitly permitted, it's forbidden. */ + return 0; +} + +/** Test whether a policy permits an algorithm. + * + * The caller must test usage flags separately. + * + * \note This function requires providing the key type for which the policy is + * being validated, since some algorithm policy definitions (e.g. MAC) + * have different properties depending on what kind of cipher it is + * combined with. + * + * \retval PSA_SUCCESS When \p alg is a specific algorithm + * allowed by the \p policy. + * \retval PSA_ERROR_INVALID_ARGUMENT When \p alg is not a specific algorithm + * \retval PSA_ERROR_NOT_PERMITTED When \p alg is a specific algorithm, but + * the \p policy does not allow it. + */ +static psa_status_t psa_key_policy_permits(const psa_key_policy_t *policy, + psa_key_type_t key_type, + psa_algorithm_t alg) +{ + /* '0' is not a valid algorithm */ + if (alg == 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* A requested algorithm cannot be a wildcard. */ + if (PSA_ALG_IS_WILDCARD(alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (psa_key_algorithm_permits(key_type, policy->alg, alg) || + psa_key_algorithm_permits(key_type, policy->alg2, alg)) { + return PSA_SUCCESS; + } else { + return PSA_ERROR_NOT_PERMITTED; + } +} + +/** Restrict a key policy based on a constraint. + * + * \note This function requires providing the key type for which the policy is + * being restricted, since some algorithm policy definitions (e.g. MAC) + * have different properties depending on what kind of cipher it is + * combined with. + * + * \param[in] key_type The key type for which to restrict the policy + * \param[in,out] policy The policy to restrict. + * \param[in] constraint The policy constraint to apply. + * + * \retval #PSA_SUCCESS + * \c *policy contains the intersection of the original value of + * \c *policy and \c *constraint. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \c key_type, \c *policy and \c *constraint are incompatible. + * \c *policy is unchanged. + */ +static psa_status_t psa_restrict_key_policy( + psa_key_type_t key_type, + psa_key_policy_t *policy, + const psa_key_policy_t *constraint) +{ + psa_algorithm_t intersection_alg = + psa_key_policy_algorithm_intersection(key_type, policy->alg, + constraint->alg); + psa_algorithm_t intersection_alg2 = + psa_key_policy_algorithm_intersection(key_type, policy->alg2, + constraint->alg2); + if (intersection_alg == 0 && policy->alg != 0 && constraint->alg != 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (intersection_alg2 == 0 && policy->alg2 != 0 && constraint->alg2 != 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + policy->usage &= constraint->usage; + policy->alg = intersection_alg; + policy->alg2 = intersection_alg2; + return PSA_SUCCESS; +} + +/** Get the description of a key given its identifier and policy constraints + * and lock it. + * + * The key must have allow all the usage flags set in \p usage. If \p alg is + * nonzero, the key must allow operations with this algorithm. If \p alg is + * zero, the algorithm is not checked. + * + * In case of a persistent key, the function loads the description of the key + * into a key slot if not already done. + * + * On success, the returned key slot has been registered for reading. + * It is the responsibility of the caller to then unregister + * once they have finished reading the contents of the slot. + * The caller unregisters by calling psa_unregister_read() or + * psa_unregister_read_under_mutex(). psa_unregister_read() must be called + * if and only if the caller already holds the global key slot mutex + * (when mutexes are enabled). psa_unregister_read_under_mutex() encapsulates + * the unregister with mutex lock and unlock operations. + */ +static psa_status_t psa_get_and_lock_key_slot_with_policy( + mbedtls_svc_key_id_t key, + psa_key_slot_t **p_slot, + psa_key_usage_t usage, + psa_algorithm_t alg) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot = NULL; + + status = psa_get_and_lock_key_slot(key, p_slot); + if (status != PSA_SUCCESS) { + return status; + } + slot = *p_slot; + + /* Enforce that usage policy for the key slot contains all the flags + * required by the usage parameter. There is one exception: public + * keys can always be exported, so we treat public key objects as + * if they had the export flag. */ + if (PSA_KEY_TYPE_IS_PUBLIC_KEY(slot->attr.type)) { + usage &= ~PSA_KEY_USAGE_EXPORT; + } + + if ((slot->attr.policy.usage & usage) != usage) { + status = PSA_ERROR_NOT_PERMITTED; + goto error; + } + + /* Enforce that the usage policy permits the requested algorithm. */ + if (alg != 0) { + status = psa_key_policy_permits(&slot->attr.policy, + slot->attr.type, + alg); + if (status != PSA_SUCCESS) { + goto error; + } + } + + return PSA_SUCCESS; + +error: + *p_slot = NULL; + psa_unregister_read_under_mutex(slot); + + return status; +} + +/** Get a key slot containing a transparent key and lock it. + * + * A transparent key is a key for which the key material is directly + * available, as opposed to a key in a secure element and/or to be used + * by a secure element. + * + * This is a temporary function that may be used instead of + * psa_get_and_lock_key_slot_with_policy() when there is no opaque key support + * for a cryptographic operation. + * + * On success, the returned key slot has been registered for reading. + * It is the responsibility of the caller to then unregister + * once they have finished reading the contents of the slot. + * The caller unregisters by calling psa_unregister_read() or + * psa_unregister_read_under_mutex(). psa_unregister_read() must be called + * if and only if the caller already holds the global key slot mutex + * (when mutexes are enabled). psa_unregister_read_under_mutex() encapsulates + * psa_unregister_read() with mutex lock and unlock operations. + */ +static psa_status_t psa_get_and_lock_transparent_key_slot_with_policy( + mbedtls_svc_key_id_t key, + psa_key_slot_t **p_slot, + psa_key_usage_t usage, + psa_algorithm_t alg) +{ + psa_status_t status = psa_get_and_lock_key_slot_with_policy(key, p_slot, + usage, alg); + if (status != PSA_SUCCESS) { + return status; + } + + if (psa_key_lifetime_is_external((*p_slot)->attr.lifetime)) { + psa_unregister_read_under_mutex(*p_slot); + *p_slot = NULL; + return PSA_ERROR_NOT_SUPPORTED; + } + + return PSA_SUCCESS; +} + +psa_status_t psa_remove_key_data_from_memory(psa_key_slot_t *slot) +{ +#if defined(MBEDTLS_PSA_STATIC_KEY_SLOTS) + if (slot->key.bytes > 0) { + mbedtls_platform_zeroize(slot->key.data, MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE); + } +#else + if (slot->key.data != NULL) { + mbedtls_zeroize_and_free(slot->key.data, slot->key.bytes); + } + + slot->key.data = NULL; +#endif /* MBEDTLS_PSA_STATIC_KEY_SLOTS */ + + slot->key.bytes = 0; + + return PSA_SUCCESS; +} + +/** Completely wipe a slot in memory, including its policy. + * Persistent storage is not affected. */ +psa_status_t psa_wipe_key_slot(psa_key_slot_t *slot) +{ + psa_status_t status = psa_remove_key_data_from_memory(slot); + + /* + * As the return error code may not be handled in case of multiple errors, + * do our best to report an unexpected amount of registered readers or + * an unexpected state. + * Assert with MBEDTLS_TEST_HOOK_TEST_ASSERT that the slot is valid for + * wiping. + * if the MBEDTLS_TEST_HOOKS configuration option is enabled and the + * function is called as part of the execution of a test suite, the + * execution of the test suite is stopped in error if the assertion fails. + */ + switch (slot->state) { + case PSA_SLOT_FULL: + /* In this state psa_wipe_key_slot() must only be called if the + * caller is the last reader. */ + case PSA_SLOT_PENDING_DELETION: + /* In this state psa_wipe_key_slot() must only be called if the + * caller is the last reader. */ + if (slot->var.occupied.registered_readers != 1) { + MBEDTLS_TEST_HOOK_TEST_ASSERT(slot->var.occupied.registered_readers == 1); + status = PSA_ERROR_CORRUPTION_DETECTED; + } + break; + case PSA_SLOT_FILLING: + /* In this state registered_readers must be 0. */ + if (slot->var.occupied.registered_readers != 0) { + MBEDTLS_TEST_HOOK_TEST_ASSERT(slot->var.occupied.registered_readers == 0); + status = PSA_ERROR_CORRUPTION_DETECTED; + } + break; + case PSA_SLOT_EMPTY: + /* The slot is already empty, it cannot be wiped. */ + MBEDTLS_TEST_HOOK_TEST_ASSERT(slot->state != PSA_SLOT_EMPTY); + status = PSA_ERROR_CORRUPTION_DETECTED; + break; + default: + /* The slot's state is invalid. */ + status = PSA_ERROR_CORRUPTION_DETECTED; + } + +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) + size_t slice_index = slot->slice_index; +#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + + + /* Multipart operations may still be using the key. This is safe + * because all multipart operation objects are independent from + * the key slot: if they need to access the key after the setup + * phase, they have a copy of the key. Note that this means that + * key material can linger until all operations are completed. */ + /* At this point, key material and other type-specific content has + * been wiped. Clear remaining metadata. We can call memset and not + * zeroize because the metadata is not particularly sensitive. + * This memset also sets the slot's state to PSA_SLOT_EMPTY. */ + memset(slot, 0, sizeof(*slot)); + +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) + /* If the slot is already corrupted, something went deeply wrong, + * like a thread still using the slot or a stray pointer leading + * to the slot's memory being used for another object. Let the slot + * leak rather than make the corruption worse. */ + if (status == PSA_SUCCESS) { + status = psa_free_key_slot(slice_index, slot); + } +#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + + return status; +} + +psa_status_t psa_destroy_key(mbedtls_svc_key_id_t key) +{ + psa_key_slot_t *slot; + psa_status_t status; /* status of the last operation */ + psa_status_t overall_status = PSA_SUCCESS; + + if (mbedtls_svc_key_id_is_null(key)) { + return PSA_SUCCESS; + } + + /* + * Get the description of the key in a key slot, and register to read it. + * In the case of a persistent key, this will load the key description + * from persistent memory if not done yet. + * We cannot avoid this loading as without it we don't know if + * the key is operated by an SE or not and this information is needed by + * the current implementation. */ + status = psa_get_and_lock_key_slot(key, &slot); + if (status != PSA_SUCCESS) { + return status; + } + +#if defined(MBEDTLS_THREADING_C) + /* We cannot unlock between setting the state to PENDING_DELETION + * and destroying the key in storage, as otherwise another thread + * could load the key into a new slot and the key will not be + * fully destroyed. */ + PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_lock( + &mbedtls_threading_key_slot_mutex)); + + if (slot->state == PSA_SLOT_PENDING_DELETION) { + /* Another thread has destroyed the key between us locking the slot + * and us gaining the mutex. Unregister from the slot, + * and report that the key does not exist. */ + status = psa_unregister_read(slot); + + PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( + &mbedtls_threading_key_slot_mutex)); + return (status == PSA_SUCCESS) ? PSA_ERROR_INVALID_HANDLE : status; + } +#endif + /* Set the key slot containing the key description's state to + * PENDING_DELETION. This stops new operations from registering + * to read the slot. Current readers can safely continue to access + * the key within the slot; the last registered reader will + * automatically wipe the slot when they call psa_unregister_read(). + * If the key is persistent, we can now delete the copy of the key + * from memory. If the key is opaque, we require the driver to + * deal with the deletion. */ + overall_status = psa_key_slot_state_transition(slot, PSA_SLOT_FULL, + PSA_SLOT_PENDING_DELETION); + + if (overall_status != PSA_SUCCESS) { + goto exit; + } + + if (PSA_KEY_LIFETIME_IS_READ_ONLY(slot->attr.lifetime)) { + /* Refuse the destruction of a read-only key (which may or may not work + * if we attempt it, depending on whether the key is merely read-only + * by policy or actually physically read-only). + * Just do the best we can, which is to wipe the copy in memory + * (done in this function's cleanup code). */ + overall_status = PSA_ERROR_NOT_PERMITTED; + goto exit; + } + +#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) + if (!PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) { + /* Destroy the copy of the persistent key from storage. + * The slot will still hold a copy of the key until the last reader + * unregisters. */ + status = psa_destroy_persistent_key(slot->attr.id); + if (overall_status == PSA_SUCCESS) { + overall_status = status; + } + } +#endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */ + +exit: + /* Unregister from reading the slot. If we are the last active reader + * then this will wipe the slot. */ + status = psa_unregister_read(slot); + /* Prioritize CORRUPTION_DETECTED from unregistering over + * a storage error. */ + if (status != PSA_SUCCESS) { + overall_status = status; + } + +#if defined(MBEDTLS_THREADING_C) + /* Don't overwrite existing errors if the unlock fails. */ + status = overall_status; + PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( + &mbedtls_threading_key_slot_mutex)); +#endif + + return overall_status; +} + +/** Retrieve all the publicly-accessible attributes of a key. + */ +psa_status_t psa_get_key_attributes(mbedtls_svc_key_id_t key, + psa_key_attributes_t *attributes) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + + psa_reset_key_attributes(attributes); + + status = psa_get_and_lock_key_slot_with_policy(key, &slot, 0, 0); + if (status != PSA_SUCCESS) { + return status; + } + + *attributes = slot->attr; + + return psa_unregister_read_under_mutex(slot); +} + +static psa_status_t psa_export_key_buffer_internal(const uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *data, + size_t data_size, + size_t *data_length) +{ + if (key_buffer_size > data_size) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + memcpy(data, key_buffer, key_buffer_size); + memset(data + key_buffer_size, 0, + data_size - key_buffer_size); + *data_length = key_buffer_size; + return PSA_SUCCESS; +} + +psa_status_t psa_export_key_internal( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + uint8_t *data, size_t data_size, size_t *data_length) +{ + psa_key_type_t type = attributes->type; + + if (key_type_is_raw_bytes(type) || + PSA_KEY_TYPE_IS_RSA(type) || + PSA_KEY_TYPE_IS_ECC(type) || + PSA_KEY_TYPE_IS_DH(type)) { + return psa_export_key_buffer_internal( + key_buffer, key_buffer_size, + data, data_size, data_length); + } else { + /* This shouldn't happen in the reference implementation, but + it is valid for a special-purpose implementation to omit + support for exporting certain key types. */ + return PSA_ERROR_NOT_SUPPORTED; + } +} + +psa_status_t psa_export_key(mbedtls_svc_key_id_t key, + uint8_t *data_external, + size_t data_size, + size_t *data_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + LOCAL_OUTPUT_DECLARE(data_external, data); + + /* Reject a zero-length output buffer now, since this can never be a + * valid key representation. This way we know that data must be a valid + * pointer and we can do things like memset(data, ..., data_size). */ + if (data_size == 0) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + /* Set the key to empty now, so that even when there are errors, we always + * set data_length to a value between 0 and data_size. On error, setting + * the key to empty is a good choice because an empty key representation is + * unlikely to be accepted anywhere. */ + *data_length = 0; + + /* Export requires the EXPORT flag. There is an exception for public keys, + * which don't require any flag, but + * psa_get_and_lock_key_slot_with_policy() takes care of this. + */ + status = psa_get_and_lock_key_slot_with_policy(key, &slot, + PSA_KEY_USAGE_EXPORT, 0); + if (status != PSA_SUCCESS) { + return status; + } + + LOCAL_OUTPUT_ALLOC(data_external, data_size, data); + + status = psa_driver_wrapper_export_key(&slot->attr, + slot->key.data, slot->key.bytes, + data, data_size, data_length); + +#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) +exit: +#endif + unlock_status = psa_unregister_read_under_mutex(slot); + + LOCAL_OUTPUT_FREE(data_external, data); + return (status == PSA_SUCCESS) ? unlock_status : status; +} + +psa_status_t psa_export_public_key_internal( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *data, + size_t data_size, + size_t *data_length) +{ + psa_key_type_t type = attributes->type; + + if (PSA_KEY_TYPE_IS_PUBLIC_KEY(type) && + (PSA_KEY_TYPE_IS_RSA(type) || PSA_KEY_TYPE_IS_ECC(type) || + PSA_KEY_TYPE_IS_DH(type))) { + /* Exporting public -> public */ + return psa_export_key_buffer_internal( + key_buffer, key_buffer_size, + data, data_size, data_length); + } else if (PSA_KEY_TYPE_IS_RSA(type)) { +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) + return mbedtls_psa_rsa_export_public_key(attributes, + key_buffer, + key_buffer_size, + data, + data_size, + data_length); +#else + /* We don't know how to convert a private RSA key to public. */ + return PSA_ERROR_NOT_SUPPORTED; +#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT) || + * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) */ + } else if (PSA_KEY_TYPE_IS_ECC(type)) { +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) + return mbedtls_psa_ecp_export_public_key(attributes, + key_buffer, + key_buffer_size, + data, + data_size, + data_length); +#else + /* We don't know how to convert a private ECC key to public */ + return PSA_ERROR_NOT_SUPPORTED; +#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || + * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) */ + } else if (PSA_KEY_TYPE_IS_DH(type)) { +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_PUBLIC_KEY) + return mbedtls_psa_ffdh_export_public_key(attributes, + key_buffer, + key_buffer_size, + data, data_size, + data_length); +#else + return PSA_ERROR_NOT_SUPPORTED; +#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_EXPORT) || + * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_PUBLIC_KEY) */ + } else { + (void) key_buffer; + (void) key_buffer_size; + (void) data; + (void) data_size; + (void) data_length; + return PSA_ERROR_NOT_SUPPORTED; + } +} + +psa_status_t psa_export_public_key(mbedtls_svc_key_id_t key, + uint8_t *data_external, + size_t data_size, + size_t *data_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + + LOCAL_OUTPUT_DECLARE(data_external, data); + + /* Reject a zero-length output buffer now, since this can never be a + * valid key representation. This way we know that data must be a valid + * pointer and we can do things like memset(data, ..., data_size). */ + if (data_size == 0) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + /* Set the key to empty now, so that even when there are errors, we always + * set data_length to a value between 0 and data_size. On error, setting + * the key to empty is a good choice because an empty key representation is + * unlikely to be accepted anywhere. */ + *data_length = 0; + + /* Exporting a public key doesn't require a usage flag. */ + status = psa_get_and_lock_key_slot_with_policy(key, &slot, 0, 0); + if (status != PSA_SUCCESS) { + return status; + } + + LOCAL_OUTPUT_ALLOC(data_external, data_size, data); + + if (!PSA_KEY_TYPE_IS_ASYMMETRIC(slot->attr.type)) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + status = psa_driver_wrapper_export_public_key( + &slot->attr, slot->key.data, slot->key.bytes, + data, data_size, data_length); + +exit: + unlock_status = psa_unregister_read_under_mutex(slot); + + LOCAL_OUTPUT_FREE(data_external, data); + return (status == PSA_SUCCESS) ? unlock_status : status; +} + +/****************************************************************/ +/* Interruptible ECC Export Public-key */ +/****************************************************************/ + +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + (defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY)) +static psa_status_t psa_export_public_key_iop_abort_internal(psa_export_public_key_iop_t *operation) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (operation->id == 0) { + return PSA_SUCCESS; + } + + status = mbedtls_psa_ecp_export_public_key_iop_abort(&operation->ctx); + + memset(&operation->ctx, 0, sizeof(operation->ctx)); + + operation->id = 0; + + return status; +} +#endif + +uint32_t psa_export_public_key_iop_get_num_ops(psa_export_public_key_iop_t *operation) +{ +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + (defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY)) + return operation->num_ops; +#else + (void) operation; + return 0; +#endif +} + +psa_status_t psa_export_public_key_iop_setup(psa_export_public_key_iop_t *operation, + mbedtls_svc_key_id_t key) +{ +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + (defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY)) + + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_attributes_t key_attributes; + psa_key_type_t key_type; + psa_key_slot_t *slot = NULL; + + if (operation->id != 0 || operation->error_occurred) { + return PSA_ERROR_BAD_STATE; + } + + /* We only support the builtin/Mbed TLS driver for now. */ + operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID; + + operation->num_ops = 0; + + status = psa_get_and_lock_transparent_key_slot_with_policy(key, &slot, + 0, + 0); + if (status != PSA_SUCCESS) { + goto exit; + } + + key_attributes = slot->attr; + + key_type = psa_get_key_type(&key_attributes); + + if (!PSA_KEY_TYPE_IS_ASYMMETRIC(key_type)) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + if (!PSA_KEY_TYPE_IS_ECC(key_type)) { + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; + } + + status = mbedtls_psa_ecp_export_public_key_iop_setup(&operation->ctx, slot->key.data, + slot->key.bytes, &key_attributes); + +exit: + unlock_status = psa_unregister_read_under_mutex(slot); + if (status != PSA_SUCCESS) { + psa_export_public_key_iop_abort_internal(operation); + operation->error_occurred = 1; + return status; + } + return unlock_status; +#else + (void) operation; + (void) key; + return PSA_ERROR_NOT_SUPPORTED; +#endif +} + +psa_status_t psa_export_public_key_iop_complete(psa_export_public_key_iop_t *operation, + uint8_t *data, + size_t data_size, + size_t *data_length) +{ +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + (defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY)) + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (operation->id == 0 || operation->error_occurred) { + return PSA_ERROR_BAD_STATE; + } + + status = mbedtls_psa_ecp_export_public_key_iop_complete(&operation->ctx, data, data_size, + data_length); + + operation->num_ops = mbedtls_psa_ecp_export_public_key_iop_get_num_ops(&operation->ctx); + + if (status != PSA_OPERATION_INCOMPLETE) { + psa_export_public_key_iop_abort_internal(operation); + + if (status != PSA_SUCCESS) { + operation->error_occurred = 1; + } + } + + return status; +#else + (void) operation; + (void) data; + (void) data_size; + (void) data_length; + + return PSA_ERROR_BAD_STATE; +#endif +} + +psa_status_t psa_export_public_key_iop_abort(psa_export_public_key_iop_t *operation) +{ +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + (defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY)) + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + status = psa_export_public_key_iop_abort_internal(operation); + + operation->num_ops = 0; + operation->error_occurred = 0; + + return status; +#else + (void) operation; + return PSA_SUCCESS; +#endif +} + +/** Validate that a key policy is internally well-formed. + * + * This function only rejects invalid policies. It does not validate the + * consistency of the policy with respect to other attributes of the key + * such as the key type. + */ +static psa_status_t psa_validate_key_policy(const psa_key_policy_t *policy) +{ + /* Do not allow PSA_KEY_USAGE_DERIVE_PUBLIC until its numerical value + * is enshrined in an official specification. This way, it's ok if + * the value changes. Once we start allowing persistent keys with + * a numerical value, we're locked into the meaning of that numerical + * value, so don't do that if there's a risk that the value might change. + * + * We introduced PSA_KEY_USAGE_DERIVE_PUBLIC for the sake of + * mbedtls_pk_can_do_psa() and psa_check_key_usage(). At this point, + * it is never checked by an operation, so there is no compelling + * reason to set this flag in a key policy. + */ + if ((policy->usage & ~(PSA_KEY_USAGE_EXPORT | + PSA_KEY_USAGE_COPY | + PSA_KEY_USAGE_ENCRYPT | + PSA_KEY_USAGE_DECRYPT | + PSA_KEY_USAGE_SIGN_MESSAGE | + PSA_KEY_USAGE_VERIFY_MESSAGE | + PSA_KEY_USAGE_SIGN_HASH | + PSA_KEY_USAGE_VERIFY_HASH | + PSA_KEY_USAGE_VERIFY_DERIVATION | + PSA_KEY_USAGE_DERIVE)) != 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return PSA_SUCCESS; +} + +/** Validate the internal consistency of key attributes. + * + * This function only rejects invalid attribute values. If does not + * validate the consistency of the attributes with any key data that may + * be involved in the creation of the key. + * + * Call this function early in the key creation process. + * + * \param[in] attributes Key attributes for the new key. + * + */ +static psa_status_t psa_validate_key_attributes(const psa_key_attributes_t *attributes) +{ + psa_status_t status = PSA_ERROR_INVALID_ARGUMENT; + psa_key_lifetime_t lifetime = psa_get_key_lifetime(attributes); + mbedtls_svc_key_id_t key = psa_get_key_id(attributes); + + status = psa_validate_key_persistence(lifetime); + if (status != PSA_SUCCESS) { + return status; + } + + if (PSA_KEY_LIFETIME_IS_VOLATILE(lifetime)) { + if (MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key) != 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + } else { + if (!psa_key_id_is_user(MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key))) { + return PSA_ERROR_INVALID_ARGUMENT; + } + } + + status = psa_validate_key_policy(&attributes->policy); + if (status != PSA_SUCCESS) { + return status; + } + + /* Refuse to create overly large keys. + * Note that this doesn't trigger on import if the attributes don't + * explicitly specify a size (so psa_get_key_bits returns 0), so + * psa_import_key() needs its own checks. */ + if (psa_get_key_bits(attributes) > PSA_MAX_KEY_BITS) { + return PSA_ERROR_NOT_SUPPORTED; + } + + return PSA_SUCCESS; +} + +/** Prepare a key slot to receive key material. + * + * This function allocates a key slot and sets its metadata. + * + * If this function fails, call psa_fail_key_creation(). + * + * This function is intended to be used as follows: + * -# Call psa_start_key_creation() to allocate a key slot, prepare + * it with the specified attributes, and in case of a volatile key assign it + * a volatile key identifier. + * -# Populate the slot with the key material. + * -# Call psa_finish_key_creation() to finalize the creation of the slot. + * In case of failure at any step, stop the sequence and call + * psa_fail_key_creation(). + * + * On success, the key slot's state is PSA_SLOT_FILLING. + * It is the responsibility of the caller to change the slot's state to + * PSA_SLOT_EMPTY/FULL once key creation has finished. + * + * \param[in] attributes Key attributes for the new key. + * \param[out] p_slot On success, a pointer to the prepared slot. + * + * \retval #PSA_SUCCESS + * The key slot is ready to receive key material. + * \return If this function fails, the key slot is an invalid state. + * You must call psa_fail_key_creation() to wipe and free the slot. + */ +static psa_status_t psa_start_key_creation( + const psa_key_attributes_t *attributes, + psa_key_slot_t **p_slot) +{ + psa_status_t status; + + status = psa_validate_key_attributes(attributes); + if (status != PSA_SUCCESS) { + return status; + } + + int key_is_volatile = PSA_KEY_LIFETIME_IS_VOLATILE(attributes->lifetime); + psa_key_id_t volatile_key_id; + +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_RET(mbedtls_mutex_lock( + &mbedtls_threading_key_slot_mutex)); +#endif + status = psa_reserve_free_key_slot( + key_is_volatile ? &volatile_key_id : NULL, + p_slot); +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( + &mbedtls_threading_key_slot_mutex)); +#endif + if (status != PSA_SUCCESS) { + return status; + } + psa_key_slot_t *slot = *p_slot; + + /* We're storing the declared bit-size of the key. It's up to each + * creation mechanism to verify that this information is correct. + * It's automatically correct for mechanisms that use the bit-size as + * an input (generate, device) but not for those where the bit-size + * is optional (import, copy). In case of a volatile key, assign it the + * volatile key identifier associated to the slot returned to contain its + * definition. */ + + slot->attr = *attributes; + if (key_is_volatile) { +#if !defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER) + slot->attr.id = volatile_key_id; +#else + slot->attr.id.key_id = volatile_key_id; +#endif + } + + return PSA_SUCCESS; +} + +/** Finalize the creation of a key once its key material has been set. + * + * This entails writing the key to persistent storage. + * + * If this function fails, call psa_fail_key_creation(). + * See the documentation of psa_start_key_creation() for the intended use + * of this function. + * + * If the finalization succeeds, the function sets the key slot's state to + * PSA_SLOT_FULL, and the key slot can no longer be accessed as part of the + * key creation process. + * + * \param[in,out] slot Pointer to the slot with key material. + * \param[out] key On success, identifier of the key. Note that the + * key identifier is also stored in the key slot. + * + * \retval #PSA_SUCCESS + * The key was successfully created. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_STORAGE \emptydescription + * \retval #PSA_ERROR_ALREADY_EXISTS \emptydescription + * \retval #PSA_ERROR_DATA_INVALID \emptydescription + * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription + * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription + * + * \return If this function fails, the key slot is an invalid state. + * You must call psa_fail_key_creation() to wipe and free the slot. + */ +static psa_status_t psa_finish_key_creation( + psa_key_slot_t *slot, + mbedtls_svc_key_id_t *key) +{ + psa_status_t status = PSA_SUCCESS; + (void) slot; + +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_RET(mbedtls_mutex_lock( + &mbedtls_threading_key_slot_mutex)); +#endif + +#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) + if (!PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) { + /* Key material is saved in export representation in the slot, so + * just pass the slot buffer for storage. */ + status = psa_save_persistent_key(&slot->attr, + slot->key.data, + slot->key.bytes); + } +#endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */ + + if (status == PSA_SUCCESS) { + *key = slot->attr.id; + status = psa_key_slot_state_transition(slot, PSA_SLOT_FILLING, + PSA_SLOT_FULL); + if (status != PSA_SUCCESS) { + *key = MBEDTLS_SVC_KEY_ID_INIT; + } + } + +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( + &mbedtls_threading_key_slot_mutex)); +#endif + return status; +} + +/** Abort the creation of a key. + * + * You may call this function after calling psa_start_key_creation(), + * or after psa_finish_key_creation() fails. In other circumstances, this + * function may not clean up persistent storage. + * See the documentation of psa_start_key_creation() for the intended use + * of this function. Sets the slot's state to PSA_SLOT_EMPTY. + * + * \param[in,out] slot Pointer to the slot with key material. + */ +static void psa_fail_key_creation(psa_key_slot_t *slot) +{ + if (slot == NULL) { + return; + } + +#if defined(MBEDTLS_THREADING_C) + /* If the lock operation fails we still wipe the slot. + * Operations will no longer work after a failed lock, + * but we still need to wipe the slot of confidential data. */ + mbedtls_mutex_lock(&mbedtls_threading_key_slot_mutex); +#endif + + psa_wipe_key_slot(slot); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_unlock(&mbedtls_threading_key_slot_mutex); +#endif +} + +/** Validate optional attributes during key creation. + * + * Some key attributes are optional during key creation. If they are + * specified in the attributes structure, check that they are consistent + * with the data in the slot. + * + * This function should be called near the end of key creation, after + * the slot in memory is fully populated but before saving persistent data. + */ +static psa_status_t psa_validate_optional_attributes( + const psa_key_slot_t *slot, + const psa_key_attributes_t *attributes) +{ + if (attributes->type != 0) { + if (attributes->type != slot->attr.type) { + return PSA_ERROR_INVALID_ARGUMENT; + } + } + + if (attributes->bits != 0) { + if (attributes->bits != slot->attr.bits) { + return PSA_ERROR_INVALID_ARGUMENT; + } + } + + return PSA_SUCCESS; +} + +psa_status_t psa_import_key(const psa_key_attributes_t *attributes, + const uint8_t *data_external, + size_t data_length, + mbedtls_svc_key_id_t *key) +{ + psa_status_t status; + LOCAL_INPUT_DECLARE(data_external, data); + psa_key_slot_t *slot = NULL; + size_t bits; + size_t storage_size = data_length; + + *key = MBEDTLS_SVC_KEY_ID_INIT; + + /* Reject zero-length symmetric keys (including raw data key objects). + * This also rejects any key which might be encoded as an empty string, + * which is never valid. */ + if (data_length == 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* Ensure that the bytes-to-bits conversion cannot overflow. */ + if (data_length > SIZE_MAX / 8) { + return PSA_ERROR_NOT_SUPPORTED; + } + + LOCAL_INPUT_ALLOC(data_external, data_length, data); + + status = psa_start_key_creation(attributes, &slot); + if (status != PSA_SUCCESS) { + goto exit; + } + + /* In the case of a transparent key or an opaque key stored in local + * storage,we have to allocate a buffer to hold the imported key material. */ + if (slot->key.bytes == 0) { + if (psa_key_lifetime_is_external(attributes->lifetime)) { + status = psa_driver_wrapper_get_key_buffer_size_from_key_data( + attributes, data, data_length, &storage_size); + if (status != PSA_SUCCESS) { + goto exit; + } + } + status = psa_allocate_buffer_to_slot(slot, storage_size); + if (status != PSA_SUCCESS) { + goto exit; + } + } + + bits = slot->attr.bits; + status = psa_driver_wrapper_import_key(attributes, + data, data_length, + slot->key.data, + slot->key.bytes, + &slot->key.bytes, &bits); + if (status != PSA_SUCCESS) { + goto exit; + } + + if (slot->attr.bits == 0) { + slot->attr.bits = (psa_key_bits_t) bits; + } else if (bits != slot->attr.bits) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + /* Enforce a size limit, and in particular ensure that the bit + * size fits in its representation type.*/ + if (bits > PSA_MAX_KEY_BITS) { + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; + } + status = psa_validate_optional_attributes(slot, attributes); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_finish_key_creation(slot, key); +exit: + LOCAL_INPUT_FREE(data_external, data); + if (status != PSA_SUCCESS) { + psa_fail_key_creation(slot); + } + + return status; +} + +psa_status_t psa_copy_key(mbedtls_svc_key_id_t source_key, + const psa_key_attributes_t *specified_attributes, + mbedtls_svc_key_id_t *target_key) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *source_slot = NULL; + psa_key_slot_t *target_slot = NULL; + psa_key_attributes_t actual_attributes = *specified_attributes; + size_t storage_size = 0; + + *target_key = MBEDTLS_SVC_KEY_ID_INIT; + + status = psa_get_and_lock_key_slot_with_policy( + source_key, &source_slot, PSA_KEY_USAGE_COPY, 0); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_validate_optional_attributes(source_slot, + specified_attributes); + if (status != PSA_SUCCESS) { + goto exit; + } + + /* The target key type and number of bits have been validated by + * psa_validate_optional_attributes() to be either equal to zero or + * equal to the ones of the source key. So it is safe to inherit + * them from the source key now." + * */ + actual_attributes.bits = source_slot->attr.bits; + actual_attributes.type = source_slot->attr.type; + + + status = psa_restrict_key_policy(source_slot->attr.type, + &actual_attributes.policy, + &source_slot->attr.policy); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_start_key_creation(&actual_attributes, &target_slot); + if (status != PSA_SUCCESS) { + goto exit; + } + if (PSA_KEY_LIFETIME_GET_LOCATION(target_slot->attr.lifetime) != + PSA_KEY_LIFETIME_GET_LOCATION(source_slot->attr.lifetime)) { + /* + * If the source and target keys are stored in different locations, + * the source key would need to be exported as plaintext and re-imported + * in the other location. This has security implications which have not + * been fully mapped. For now, this can be achieved through + * appropriate API invocations from the application, if needed. + * */ + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; + } + /* + * When the source and target keys are within the same location, + * - For transparent keys it is a blind copy without any driver invocation, + * - For opaque keys this translates to an invocation of the drivers' + * copy_key entry point through the dispatch layer. + * */ + if (psa_key_lifetime_is_external(actual_attributes.lifetime)) { + status = psa_driver_wrapper_get_key_buffer_size(&actual_attributes, + &storage_size); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_allocate_buffer_to_slot(target_slot, storage_size); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_driver_wrapper_copy_key(&actual_attributes, + source_slot->key.data, + source_slot->key.bytes, + target_slot->key.data, + target_slot->key.bytes, + &target_slot->key.bytes); + if (status != PSA_SUCCESS) { + goto exit; + } + } else { + status = psa_copy_key_material_into_slot(target_slot, + source_slot->key.data, + source_slot->key.bytes); + if (status != PSA_SUCCESS) { + goto exit; + } + } + status = psa_finish_key_creation(target_slot, target_key); +exit: + if (status != PSA_SUCCESS) { + psa_fail_key_creation(target_slot); + } + + unlock_status = psa_unregister_read_under_mutex(source_slot); + + return (status == PSA_SUCCESS) ? unlock_status : status; +} + + + +/****************************************************************/ +/* Message digests */ +/****************************************************************/ + +static int is_hash_supported(psa_algorithm_t alg) +{ + switch (alg) { +#if defined(PSA_WANT_ALG_MD5) + case PSA_ALG_MD5: + return 1; +#endif +#if defined(PSA_WANT_ALG_RIPEMD160) + case PSA_ALG_RIPEMD160: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA_1) + case PSA_ALG_SHA_1: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA_224) + case PSA_ALG_SHA_224: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA_256) + case PSA_ALG_SHA_256: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA_384) + case PSA_ALG_SHA_384: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA_512) + case PSA_ALG_SHA_512: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA3_224) + case PSA_ALG_SHA3_224: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA3_256) + case PSA_ALG_SHA3_256: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA3_384) + case PSA_ALG_SHA3_384: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA3_512) + case PSA_ALG_SHA3_512: + return 1; +#endif + default: + return 0; + } +} + +psa_status_t psa_hash_abort(psa_hash_operation_t *operation) +{ + /* Aborting a non-active operation is allowed */ + if (operation->id == 0) { + return PSA_SUCCESS; + } + + psa_status_t status = psa_driver_wrapper_hash_abort(operation); + operation->id = 0; + + return status; +} + +psa_status_t psa_hash_setup(psa_hash_operation_t *operation, + psa_algorithm_t alg) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + /* A context must be freshly initialized before it can be set up. */ + if (operation->id != 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (!PSA_ALG_IS_HASH(alg)) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + /* Make sure the driver-dependent part of the operation is zeroed. + * This is a guarantee we make to drivers. Initializing the operation + * does not necessarily take care of it, since the context is a + * union and initializing a union does not necessarily initialize + * all of its members. */ + memset(&operation->ctx, 0, sizeof(operation->ctx)); + + status = psa_driver_wrapper_hash_setup(operation, alg); + +exit: + if (status != PSA_SUCCESS) { + psa_hash_abort(operation); + } + + return status; +} + +psa_status_t psa_hash_update(psa_hash_operation_t *operation, + const uint8_t *input_external, + size_t input_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_INPUT_DECLARE(input_external, input); + + if (operation->id == 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + /* Don't require hash implementations to behave correctly on a + * zero-length input, which may have an invalid pointer. */ + if (input_length == 0) { + return PSA_SUCCESS; + } + + LOCAL_INPUT_ALLOC(input_external, input_length, input); + status = psa_driver_wrapper_hash_update(operation, input, input_length); + +exit: + if (status != PSA_SUCCESS) { + psa_hash_abort(operation); + } + + LOCAL_INPUT_FREE(input_external, input); + return status; +} + +static psa_status_t psa_hash_finish_internal(psa_hash_operation_t *operation, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + *hash_length = 0; + if (operation->id == 0) { + return PSA_ERROR_BAD_STATE; + } + + status = psa_driver_wrapper_hash_finish( + operation, hash, hash_size, hash_length); + psa_hash_abort(operation); + + return status; +} + +psa_status_t psa_hash_finish(psa_hash_operation_t *operation, + uint8_t *hash_external, + size_t hash_size, + size_t *hash_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_OUTPUT_DECLARE(hash_external, hash); + + LOCAL_OUTPUT_ALLOC(hash_external, hash_size, hash); + status = psa_hash_finish_internal(operation, hash, hash_size, hash_length); + +#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) +exit: +#endif + LOCAL_OUTPUT_FREE(hash_external, hash); + return status; +} + +psa_status_t psa_hash_verify(psa_hash_operation_t *operation, + const uint8_t *hash_external, + size_t hash_length) +{ + uint8_t actual_hash[PSA_HASH_MAX_SIZE]; + size_t actual_hash_length; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_INPUT_DECLARE(hash_external, hash); + + status = psa_hash_finish_internal( + operation, + actual_hash, sizeof(actual_hash), + &actual_hash_length); + + if (status != PSA_SUCCESS) { + goto exit; + } + + if (actual_hash_length != hash_length) { + status = PSA_ERROR_INVALID_SIGNATURE; + goto exit; + } + + LOCAL_INPUT_ALLOC(hash_external, hash_length, hash); + if (mbedtls_ct_memcmp(hash, actual_hash, actual_hash_length) != 0) { + status = PSA_ERROR_INVALID_SIGNATURE; + } + +exit: + mbedtls_platform_zeroize(actual_hash, sizeof(actual_hash)); + if (status != PSA_SUCCESS) { + psa_hash_abort(operation); + } + LOCAL_INPUT_FREE(hash_external, hash); + return status; +} + +psa_status_t psa_hash_compute(psa_algorithm_t alg, + const uint8_t *input_external, size_t input_length, + uint8_t *hash_external, size_t hash_size, + size_t *hash_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_INPUT_DECLARE(input_external, input); + LOCAL_OUTPUT_DECLARE(hash_external, hash); + + *hash_length = 0; + if (!PSA_ALG_IS_HASH(alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + LOCAL_INPUT_ALLOC(input_external, input_length, input); + LOCAL_OUTPUT_ALLOC(hash_external, hash_size, hash); + status = psa_driver_wrapper_hash_compute(alg, input, input_length, + hash, hash_size, hash_length); + +#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) +exit: +#endif + LOCAL_INPUT_FREE(input_external, input); + LOCAL_OUTPUT_FREE(hash_external, hash); + return status; +} + +psa_status_t psa_hash_compare(psa_algorithm_t alg, + const uint8_t *input_external, size_t input_length, + const uint8_t *hash_external, size_t hash_length) +{ + uint8_t actual_hash[PSA_HASH_MAX_SIZE]; + size_t actual_hash_length; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + LOCAL_INPUT_DECLARE(input_external, input); + LOCAL_INPUT_DECLARE(hash_external, hash); + + if (!PSA_ALG_IS_HASH(alg)) { + status = PSA_ERROR_INVALID_ARGUMENT; + return status; + } + + LOCAL_INPUT_ALLOC(input_external, input_length, input); + status = psa_driver_wrapper_hash_compute( + alg, input, input_length, + actual_hash, sizeof(actual_hash), + &actual_hash_length); + if (status != PSA_SUCCESS) { + goto exit; + } + if (actual_hash_length != hash_length) { + status = PSA_ERROR_INVALID_SIGNATURE; + goto exit; + } + + LOCAL_INPUT_ALLOC(hash_external, hash_length, hash); + if (mbedtls_ct_memcmp(hash, actual_hash, actual_hash_length) != 0) { + status = PSA_ERROR_INVALID_SIGNATURE; + } + +exit: + mbedtls_platform_zeroize(actual_hash, sizeof(actual_hash)); + + LOCAL_INPUT_FREE(input_external, input); + LOCAL_INPUT_FREE(hash_external, hash); + + return status; +} + +psa_status_t psa_hash_clone(const psa_hash_operation_t *source_operation, + psa_hash_operation_t *target_operation) +{ + if (source_operation->id == 0 || + target_operation->id != 0) { + return PSA_ERROR_BAD_STATE; + } + + /* Make sure the driver-dependent part of the operation is zeroed. + * This is a guarantee we make to drivers. Initializing the operation + * does not necessarily take care of it, since the context is a + * union and initializing a union does not necessarily initialize + * all of its members. */ + memset(&target_operation->ctx, 0, sizeof(target_operation->ctx)); + + psa_status_t status = psa_driver_wrapper_hash_clone(source_operation, + target_operation); + if (status != PSA_SUCCESS) { + psa_hash_abort(target_operation); + } + + return status; +} + + +/****************************************************************/ +/* XOF */ +/****************************************************************/ + +psa_status_t psa_xof_abort(psa_xof_operation_t *operation) +{ + /* Aborting a non-active operation is allowed */ + if (operation->id == 0) { + return PSA_SUCCESS; + } + + psa_status_t status = psa_driver_wrapper_xof_abort(operation); + memset(operation, 0, sizeof(*operation)); + + return status; +} + +psa_status_t psa_xof_setup(psa_xof_operation_t *operation, + psa_algorithm_t alg) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + /* A context must be freshly initialized before it can be set up. */ + if (operation->id != 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (!PSA_ALG_IS_XOF(alg)) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + /* Make sure the driver-dependent part of the operation is zeroed. + * This is a guarantee we make to drivers. Initializing the operation + * does not necessarily take care of it, since the context is a + * union and initializing a union does not necessarily initialize + * all of its members. */ + memset(&operation->ctx, 0, sizeof(operation->ctx)); + + status = psa_driver_wrapper_xof_setup(operation, alg); + +exit: + if (status == PSA_SUCCESS) { + operation->active = 1; + if ((alg & PSA_ALG_XOF_CONTEXT_FLAG) != 0) { + /* So far there are no XOF algorithms with an optional context */ + operation->allows_context = 1; + operation->requires_context = 1; + } + } else { + psa_xof_abort(operation); + } + + return status; +} + +psa_status_t psa_xof_set_context(psa_xof_operation_t *operation, + const uint8_t *context_external, + size_t context_length) +{ + if (operation->id == 0) { + return PSA_ERROR_BAD_STATE; + } + if (!operation->active) { + return PSA_ERROR_BAD_STATE; + } + if (!operation->allows_context) { + return PSA_ERROR_BAD_STATE; + } + if (operation->has_context) { + return PSA_ERROR_BAD_STATE; + } + if (operation->has_input) { + return PSA_ERROR_BAD_STATE; + } + if (operation->has_output) { + return PSA_ERROR_BAD_STATE; + } + + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_INPUT_DECLARE(context_external, context); + + operation->has_context = 1; + + LOCAL_INPUT_ALLOC(context_external, context_length, context); + status = psa_driver_wrapper_xof_set_context(operation, + context, context_length); + // Label otherwise unused when MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS is enabled + goto exit; + +exit: + if (status != PSA_SUCCESS) { + psa_xof_abort(operation); + } + + LOCAL_INPUT_FREE(context_external, context); + return status; +} + +psa_status_t psa_xof_update(psa_xof_operation_t *operation, + const uint8_t *input_external, + size_t input_length) +{ + if (operation->id == 0) { + return PSA_ERROR_BAD_STATE; + } + if (!operation->active) { + return PSA_ERROR_BAD_STATE; + } + if (!operation->has_context && operation->requires_context) { + return PSA_ERROR_BAD_STATE; + } + if (operation->has_output) { + return PSA_ERROR_BAD_STATE; + } + + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_INPUT_DECLARE(input_external, input); + + operation->has_input = 1; + + /* Don't require XOF implementations to behave correctly on a + * zero-length input, which may have an invalid pointer. */ + if (input_length == 0) { + return PSA_SUCCESS; + } + + LOCAL_INPUT_ALLOC(input_external, input_length, input); + status = psa_driver_wrapper_xof_update(operation, input, input_length); + // Label otherwise unused when MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS is enabled + goto exit; + +exit: + if (status != PSA_SUCCESS) { + psa_xof_abort(operation); + } + + LOCAL_INPUT_FREE(input_external, input); + return status; +} + +psa_status_t psa_xof_output(psa_xof_operation_t *operation, + uint8_t *output_external, + size_t output_length) +{ + if (operation->id == 0) { + return PSA_ERROR_BAD_STATE; + } + if (!operation->active) { + return PSA_ERROR_BAD_STATE; + } + if (!operation->has_context && operation->requires_context) { + return PSA_ERROR_BAD_STATE; + } + + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_OUTPUT_DECLARE(output_external, output); + + operation->has_output = 1; + + /* Don't require XOF implementations to behave correctly on a + * zero-length output, which may have an invalid pointer. */ + if (output_length == 0) { + return PSA_SUCCESS; + } + + LOCAL_OUTPUT_ALLOC(output_external, output_length, output); + status = psa_driver_wrapper_xof_output(operation, output, output_length); + // Label otherwise unused when MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS is enabled + goto exit; + +exit: + if (status != PSA_SUCCESS) { + psa_xof_abort(operation); + } + + LOCAL_OUTPUT_FREE(output_external, output); + return status; +} + + + +/****************************************************************/ +/* MAC */ +/****************************************************************/ + +psa_status_t psa_mac_abort(psa_mac_operation_t *operation) +{ + /* Aborting a non-active operation is allowed */ + if (operation->id == 0) { + return PSA_SUCCESS; + } + + psa_status_t status = psa_driver_wrapper_mac_abort(operation); + operation->mac_size = 0; + operation->is_sign = 0; + operation->id = 0; + + return status; +} + +static psa_status_t psa_mac_finalize_alg_and_key_validation( + psa_algorithm_t alg, + const psa_key_attributes_t *attributes, + uint8_t *mac_size) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_type_t key_type = psa_get_key_type(attributes); + size_t key_bits = psa_get_key_bits(attributes); + + if (!PSA_ALG_IS_MAC(alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* Validate the combination of key type and algorithm */ + status = psa_mac_key_can_do(alg, key_type); + if (status != PSA_SUCCESS) { + return status; + } + + /* Get the output length for the algorithm and key combination */ + *mac_size = PSA_MAC_LENGTH(key_type, key_bits, alg); + + if (*mac_size < 4) { + /* A very short MAC is too short for security since it can be + * brute-forced. Ancient protocols with 32-bit MACs do exist, + * so we make this our minimum, even though 32 bits is still + * too small for security. */ + return PSA_ERROR_NOT_SUPPORTED; + } + + if (*mac_size > PSA_MAC_LENGTH(key_type, key_bits, + PSA_ALG_FULL_LENGTH_MAC(alg))) { + /* It's impossible to "truncate" to a larger length than the full length + * of the algorithm. */ + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (*mac_size > PSA_MAC_MAX_SIZE) { + /* PSA_MAC_LENGTH returns the correct length even for a MAC algorithm + * that is disabled in the compile-time configuration. The result can + * therefore be larger than PSA_MAC_MAX_SIZE, which does take the + * configuration into account. In this case, force a return of + * PSA_ERROR_NOT_SUPPORTED here. Otherwise psa_mac_verify(), or + * psa_mac_compute(mac_size=PSA_MAC_MAX_SIZE), would return + * PSA_ERROR_BUFFER_TOO_SMALL for an unsupported algorithm whose MAC size + * is larger than PSA_MAC_MAX_SIZE, which is misleading and which breaks + * systematically generated tests. */ + return PSA_ERROR_NOT_SUPPORTED; + } + + return PSA_SUCCESS; +} + +static psa_status_t psa_mac_setup(psa_mac_operation_t *operation, + mbedtls_svc_key_id_t key, + psa_algorithm_t alg, + int is_sign) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot = NULL; + + /* A context must be freshly initialized before it can be set up. */ + if (operation->id != 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + /* Make sure the driver-dependent part of the operation is zeroed. + * This is a guarantee we make to drivers. Initializing the operation + * does not necessarily take care of it, since the context is a + * union and initializing a union does not necessarily initialize + * all of its members. */ + memset(&operation->ctx, 0, sizeof(operation->ctx)); + + status = psa_get_and_lock_key_slot_with_policy( + key, + &slot, + is_sign ? PSA_KEY_USAGE_SIGN_MESSAGE : PSA_KEY_USAGE_VERIFY_MESSAGE, + alg); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_mac_finalize_alg_and_key_validation(alg, &slot->attr, + &operation->mac_size); + if (status != PSA_SUCCESS) { + goto exit; + } + + operation->is_sign = is_sign; + /* Dispatch the MAC setup call with validated input */ + if (is_sign) { + status = psa_driver_wrapper_mac_sign_setup(operation, + &slot->attr, + slot->key.data, + slot->key.bytes, + alg); + } else { + status = psa_driver_wrapper_mac_verify_setup(operation, + &slot->attr, + slot->key.data, + slot->key.bytes, + alg); + } + +exit: + if (status != PSA_SUCCESS) { + psa_mac_abort(operation); + } + + unlock_status = psa_unregister_read_under_mutex(slot); + + return (status == PSA_SUCCESS) ? unlock_status : status; +} + +psa_status_t psa_mac_sign_setup(psa_mac_operation_t *operation, + mbedtls_svc_key_id_t key, + psa_algorithm_t alg) +{ + return psa_mac_setup(operation, key, alg, 1); +} + +psa_status_t psa_mac_verify_setup(psa_mac_operation_t *operation, + mbedtls_svc_key_id_t key, + psa_algorithm_t alg) +{ + return psa_mac_setup(operation, key, alg, 0); +} + +psa_status_t psa_mac_update(psa_mac_operation_t *operation, + const uint8_t *input_external, + size_t input_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_INPUT_DECLARE(input_external, input); + + if (operation->id == 0) { + status = PSA_ERROR_BAD_STATE; + return status; + } + + /* Don't require hash implementations to behave correctly on a + * zero-length input, which may have an invalid pointer. */ + if (input_length == 0) { + status = PSA_SUCCESS; + return status; + } + + LOCAL_INPUT_ALLOC(input_external, input_length, input); + status = psa_driver_wrapper_mac_update(operation, input, input_length); + + if (status != PSA_SUCCESS) { + psa_mac_abort(operation); + } + +#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) +exit: +#endif + LOCAL_INPUT_FREE(input_external, input); + + return status; +} + +psa_status_t psa_mac_sign_finish(psa_mac_operation_t *operation, + uint8_t *mac_external, + size_t mac_size, + size_t *mac_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t abort_status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_OUTPUT_DECLARE(mac_external, mac); + LOCAL_OUTPUT_ALLOC(mac_external, mac_size, mac); + + if (operation->id == 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (!operation->is_sign) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + /* Sanity check. This will guarantee that mac_size != 0 (and so mac != NULL) + * once all the error checks are done. */ + if (operation->mac_size == 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (mac_size < operation->mac_size) { + status = PSA_ERROR_BUFFER_TOO_SMALL; + goto exit; + } + + + status = psa_driver_wrapper_mac_sign_finish(operation, + mac, operation->mac_size, + mac_length); + +exit: + /* In case of success, set the potential excess room in the output buffer + * to an invalid value, to avoid potentially leaking a longer MAC. + * In case of error, set the output length and content to a safe default, + * such that in case the caller misses an error check, the output would be + * an unachievable MAC. + */ + if (status != PSA_SUCCESS) { + *mac_length = mac_size; + operation->mac_size = 0; + } + + if (mac != NULL) { + psa_wipe_tag_output_buffer(mac, status, mac_size, *mac_length); + } + + abort_status = psa_mac_abort(operation); + LOCAL_OUTPUT_FREE(mac_external, mac); + + return status == PSA_SUCCESS ? abort_status : status; +} + +psa_status_t psa_mac_verify_finish(psa_mac_operation_t *operation, + const uint8_t *mac_external, + size_t mac_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t abort_status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_INPUT_DECLARE(mac_external, mac); + + if (operation->id == 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (operation->is_sign) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (operation->mac_size != mac_length) { + status = PSA_ERROR_INVALID_SIGNATURE; + goto exit; + } + + LOCAL_INPUT_ALLOC(mac_external, mac_length, mac); + status = psa_driver_wrapper_mac_verify_finish(operation, + mac, mac_length); + +exit: + abort_status = psa_mac_abort(operation); + LOCAL_INPUT_FREE(mac_external, mac); + + return status == PSA_SUCCESS ? abort_status : status; +} + +static psa_status_t psa_mac_compute_internal(mbedtls_svc_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *mac, + size_t mac_size, + size_t *mac_length, + int is_sign) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + uint8_t operation_mac_size = 0; + + status = psa_get_and_lock_key_slot_with_policy( + key, + &slot, + is_sign ? PSA_KEY_USAGE_SIGN_MESSAGE : PSA_KEY_USAGE_VERIFY_MESSAGE, + alg); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_mac_finalize_alg_and_key_validation(alg, &slot->attr, + &operation_mac_size); + if (status != PSA_SUCCESS) { + goto exit; + } + + if (mac_size < operation_mac_size) { + status = PSA_ERROR_BUFFER_TOO_SMALL; + goto exit; + } + + status = psa_driver_wrapper_mac_compute( + &slot->attr, + slot->key.data, slot->key.bytes, + alg, + input, input_length, + mac, operation_mac_size, mac_length); + +exit: + /* In case of success, set the potential excess room in the output buffer + * to an invalid value, to avoid potentially leaking a longer MAC. + * In case of error, set the output length and content to a safe default, + * such that in case the caller misses an error check, the output would be + * an unachievable MAC. + */ + if (status != PSA_SUCCESS) { + *mac_length = mac_size; + operation_mac_size = 0; + } + + psa_wipe_tag_output_buffer(mac, status, mac_size, *mac_length); + + unlock_status = psa_unregister_read_under_mutex(slot); + + return (status == PSA_SUCCESS) ? unlock_status : status; +} + +psa_status_t psa_mac_compute(mbedtls_svc_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input_external, + size_t input_length, + uint8_t *mac_external, + size_t mac_size, + size_t *mac_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_INPUT_DECLARE(input_external, input); + LOCAL_OUTPUT_DECLARE(mac_external, mac); + + LOCAL_INPUT_ALLOC(input_external, input_length, input); + LOCAL_OUTPUT_ALLOC(mac_external, mac_size, mac); + status = psa_mac_compute_internal(key, alg, + input, input_length, + mac, mac_size, mac_length, 1); + +#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) +exit: +#endif + LOCAL_INPUT_FREE(input_external, input); + LOCAL_OUTPUT_FREE(mac_external, mac); + + return status; +} + +psa_status_t psa_mac_verify(mbedtls_svc_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input_external, + size_t input_length, + const uint8_t *mac_external, + size_t mac_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + uint8_t actual_mac[PSA_MAC_MAX_SIZE]; + size_t actual_mac_length; + LOCAL_INPUT_DECLARE(input_external, input); + LOCAL_INPUT_DECLARE(mac_external, mac); + + LOCAL_INPUT_ALLOC(input_external, input_length, input); + status = psa_mac_compute_internal(key, alg, + input, input_length, + actual_mac, sizeof(actual_mac), + &actual_mac_length, 0); + if (status != PSA_SUCCESS) { + goto exit; + } + + if (mac_length != actual_mac_length) { + status = PSA_ERROR_INVALID_SIGNATURE; + goto exit; + } + + LOCAL_INPUT_ALLOC(mac_external, mac_length, mac); + if (mbedtls_ct_memcmp(mac, actual_mac, actual_mac_length) != 0) { + status = PSA_ERROR_INVALID_SIGNATURE; + goto exit; + } + +exit: + mbedtls_platform_zeroize(actual_mac, sizeof(actual_mac)); + LOCAL_INPUT_FREE(input_external, input); + LOCAL_INPUT_FREE(mac_external, mac); + + return status; +} + +/****************************************************************/ +/* Asymmetric cryptography */ +/****************************************************************/ + +static psa_status_t psa_sign_verify_check_alg(int input_is_message, + psa_algorithm_t alg) +{ + if (input_is_message) { + if (!PSA_ALG_IS_SIGN_MESSAGE(alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + } + + psa_algorithm_t hash_alg = 0; + if (PSA_ALG_IS_SIGN_HASH(alg)) { + hash_alg = PSA_ALG_SIGN_GET_HASH(alg); + } + + /* Now hash_alg==0 if alg by itself doesn't need a hash. + * This is good enough for sign-hash, but a guaranteed failure for + * sign-message which needs to hash first for all algorithms + * supported at the moment. */ + + if (hash_alg == 0 && input_is_message) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (hash_alg == PSA_ALG_ANY_HASH) { + return PSA_ERROR_INVALID_ARGUMENT; + } + /* Give up immediately if the hash is not supported. This has + * several advantages: + * - For mechanisms that don't use the hash at all (e.g. + * ECDSA verification, randomized ECDSA signature), without + * this check, the operation would succeed even though it has + * been given an invalid argument. This would not be insecure + * since the hash was not necessary, but it would be weird. + * - For mechanisms that do use the hash, we avoid an error + * deep inside the execution. In principle this doesn't matter, + * but there is a little more risk of a bug in error handling + * deep inside than in this preliminary check. + * - When calling a driver, the driver might be capable of using + * a hash that the core doesn't support. This could potentially + * result in a buffer overflow if the hash is larger than the + * maximum hash size assumed by the core. + * - Returning a consistent error makes it possible to test + * not-supported hashes in a consistent way. + */ + if (hash_alg != 0 && !is_hash_supported(hash_alg)) { + return PSA_ERROR_NOT_SUPPORTED; + } + + return PSA_SUCCESS; +} + +static psa_status_t psa_sign_internal(mbedtls_svc_key_id_t key, + int input_is_message, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + + *signature_length = 0; + + status = psa_sign_verify_check_alg(input_is_message, alg); + if (status != PSA_SUCCESS) { + return status; + } + + /* Immediately reject a zero-length signature buffer. This guarantees + * that signature must be a valid pointer. (On the other hand, the input + * buffer can in principle be empty since it doesn't actually have + * to be a hash.) */ + if (signature_size == 0) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + status = psa_get_and_lock_key_slot_with_policy( + key, &slot, + input_is_message ? PSA_KEY_USAGE_SIGN_MESSAGE : + PSA_KEY_USAGE_SIGN_HASH, + alg); + + if (status != PSA_SUCCESS) { + goto exit; + } + + if (!PSA_KEY_TYPE_IS_KEY_PAIR(slot->attr.type)) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + if (input_is_message) { + status = psa_driver_wrapper_sign_message( + &slot->attr, slot->key.data, slot->key.bytes, + alg, input, input_length, + signature, signature_size, signature_length); + } else { + + status = psa_driver_wrapper_sign_hash( + &slot->attr, slot->key.data, slot->key.bytes, + alg, input, input_length, + signature, signature_size, signature_length); + } + + +exit: + psa_wipe_tag_output_buffer(signature, status, signature_size, + *signature_length); + + unlock_status = psa_unregister_read_under_mutex(slot); + + return (status == PSA_SUCCESS) ? unlock_status : status; +} + +static psa_status_t psa_verify_internal(mbedtls_svc_key_id_t key, + int input_is_message, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *signature, + size_t signature_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + + status = psa_sign_verify_check_alg(input_is_message, alg); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_get_and_lock_key_slot_with_policy( + key, &slot, + input_is_message ? PSA_KEY_USAGE_VERIFY_MESSAGE : + PSA_KEY_USAGE_VERIFY_HASH, + alg); + + if (status != PSA_SUCCESS) { + return status; + } + + if (input_is_message) { + status = psa_driver_wrapper_verify_message( + &slot->attr, slot->key.data, slot->key.bytes, + alg, input, input_length, + signature, signature_length); + } else { + status = psa_driver_wrapper_verify_hash( + &slot->attr, slot->key.data, slot->key.bytes, + alg, input, input_length, + signature, signature_length); + } + + unlock_status = psa_unregister_read_under_mutex(slot); + + return (status == PSA_SUCCESS) ? unlock_status : status; + +} + +psa_status_t psa_sign_message_builtin( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (PSA_ALG_IS_SIGN_HASH(alg)) { + size_t hash_length; + uint8_t hash[PSA_HASH_MAX_SIZE]; + + status = psa_driver_wrapper_hash_compute( + PSA_ALG_SIGN_GET_HASH(alg), + input, input_length, + hash, sizeof(hash), &hash_length); + + if (status != PSA_SUCCESS) { + return status; + } + + return psa_driver_wrapper_sign_hash( + attributes, key_buffer, key_buffer_size, + alg, hash, hash_length, + signature, signature_size, signature_length); + } + + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_sign_message(mbedtls_svc_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input_external, + size_t input_length, + uint8_t *signature_external, + size_t signature_size, + size_t *signature_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_INPUT_DECLARE(input_external, input); + LOCAL_OUTPUT_DECLARE(signature_external, signature); + + LOCAL_INPUT_ALLOC(input_external, input_length, input); + LOCAL_OUTPUT_ALLOC(signature_external, signature_size, signature); + status = psa_sign_internal(key, 1, alg, input, input_length, signature, + signature_size, signature_length); + +#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) +exit: +#endif + LOCAL_INPUT_FREE(input_external, input); + LOCAL_OUTPUT_FREE(signature_external, signature); + return status; +} + +psa_status_t psa_verify_message_builtin( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *signature, + size_t signature_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (PSA_ALG_IS_SIGN_HASH(alg)) { + size_t hash_length; + uint8_t hash[PSA_HASH_MAX_SIZE]; + + status = psa_driver_wrapper_hash_compute( + PSA_ALG_SIGN_GET_HASH(alg), + input, input_length, + hash, sizeof(hash), &hash_length); + + if (status != PSA_SUCCESS) { + return status; + } + + return psa_driver_wrapper_verify_hash( + attributes, key_buffer, key_buffer_size, + alg, hash, hash_length, + signature, signature_length); + } + + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_verify_message(mbedtls_svc_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input_external, + size_t input_length, + const uint8_t *signature_external, + size_t signature_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_INPUT_DECLARE(input_external, input); + LOCAL_INPUT_DECLARE(signature_external, signature); + + LOCAL_INPUT_ALLOC(input_external, input_length, input); + LOCAL_INPUT_ALLOC(signature_external, signature_length, signature); + status = psa_verify_internal(key, 1, alg, input, input_length, signature, + signature_length); + +#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) +exit: +#endif + LOCAL_INPUT_FREE(input_external, input); + LOCAL_INPUT_FREE(signature_external, signature); + + return status; +} + +psa_status_t psa_sign_hash_builtin( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *hash, size_t hash_length, + uint8_t *signature, size_t signature_size, size_t *signature_length) +{ + if (attributes->type == PSA_KEY_TYPE_RSA_KEY_PAIR) { + if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) || + PSA_ALG_IS_RSA_PSS(alg)) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS) + return mbedtls_psa_rsa_sign_hash( + attributes, + key_buffer, key_buffer_size, + alg, hash, hash_length, + signature, signature_size, signature_length); +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS) */ + } else { + return PSA_ERROR_INVALID_ARGUMENT; + } + } else if (PSA_KEY_TYPE_IS_ECC(attributes->type)) { + if (PSA_ALG_IS_ECDSA(alg)) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) + return mbedtls_psa_ecdsa_sign_hash( + attributes, + key_buffer, key_buffer_size, + alg, hash, hash_length, + signature, signature_size, signature_length); +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) */ + } else { + return PSA_ERROR_INVALID_ARGUMENT; + } + } + + (void) key_buffer; + (void) key_buffer_size; + (void) hash; + (void) hash_length; + (void) signature; + (void) signature_size; + (void) signature_length; + + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_sign_hash(mbedtls_svc_key_id_t key, + psa_algorithm_t alg, + const uint8_t *hash_external, + size_t hash_length, + uint8_t *signature_external, + size_t signature_size, + size_t *signature_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_INPUT_DECLARE(hash_external, hash); + LOCAL_OUTPUT_DECLARE(signature_external, signature); + + LOCAL_INPUT_ALLOC(hash_external, hash_length, hash); + LOCAL_OUTPUT_ALLOC(signature_external, signature_size, signature); + status = psa_sign_internal(key, 0, alg, hash, hash_length, signature, + signature_size, signature_length); + +#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) +exit: +#endif + LOCAL_INPUT_FREE(hash_external, hash); + LOCAL_OUTPUT_FREE(signature_external, signature); + + return status; +} + +psa_status_t psa_verify_hash_builtin( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *hash, size_t hash_length, + const uint8_t *signature, size_t signature_length) +{ + if (PSA_KEY_TYPE_IS_RSA(attributes->type)) { + if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) || + PSA_ALG_IS_RSA_PSS(alg)) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS) + return mbedtls_psa_rsa_verify_hash( + attributes, + key_buffer, key_buffer_size, + alg, hash, hash_length, + signature, signature_length); +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS) */ + } else { + return PSA_ERROR_INVALID_ARGUMENT; + } + } else if (PSA_KEY_TYPE_IS_ECC(attributes->type)) { + if (PSA_ALG_IS_ECDSA(alg)) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) + return mbedtls_psa_ecdsa_verify_hash( + attributes, + key_buffer, key_buffer_size, + alg, hash, hash_length, + signature, signature_length); +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) */ + } else { + return PSA_ERROR_INVALID_ARGUMENT; + } + } + + (void) key_buffer; + (void) key_buffer_size; + (void) hash; + (void) hash_length; + (void) signature; + (void) signature_length; + + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_verify_hash(mbedtls_svc_key_id_t key, + psa_algorithm_t alg, + const uint8_t *hash_external, + size_t hash_length, + const uint8_t *signature_external, + size_t signature_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_INPUT_DECLARE(hash_external, hash); + LOCAL_INPUT_DECLARE(signature_external, signature); + + LOCAL_INPUT_ALLOC(hash_external, hash_length, hash); + LOCAL_INPUT_ALLOC(signature_external, signature_length, signature); + status = psa_verify_internal(key, 0, alg, hash, hash_length, signature, + signature_length); + +#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) +exit: +#endif + LOCAL_INPUT_FREE(hash_external, hash); + LOCAL_INPUT_FREE(signature_external, signature); + + return status; +} + +psa_status_t psa_asymmetric_encrypt(mbedtls_svc_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input_external, + size_t input_length, + const uint8_t *salt_external, + size_t salt_length, + uint8_t *output_external, + size_t output_size, + size_t *output_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + + LOCAL_INPUT_DECLARE(input_external, input); + LOCAL_INPUT_DECLARE(salt_external, salt); + LOCAL_OUTPUT_DECLARE(output_external, output); + + (void) input; + (void) input_length; + (void) salt; + (void) output; + (void) output_size; + + *output_length = 0; + + if (!PSA_ALG_IS_RSA_OAEP(alg) && salt_length != 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + status = psa_get_and_lock_key_slot_with_policy( + key, &slot, PSA_KEY_USAGE_ENCRYPT, alg); + if (status != PSA_SUCCESS) { + return status; + } + if (!(PSA_KEY_TYPE_IS_PUBLIC_KEY(slot->attr.type) || + PSA_KEY_TYPE_IS_KEY_PAIR(slot->attr.type))) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + LOCAL_INPUT_ALLOC(input_external, input_length, input); + LOCAL_INPUT_ALLOC(salt_external, salt_length, salt); + LOCAL_OUTPUT_ALLOC(output_external, output_size, output); + + status = psa_driver_wrapper_asymmetric_encrypt( + &slot->attr, slot->key.data, slot->key.bytes, + alg, input, input_length, salt, salt_length, + output, output_size, output_length); +exit: + unlock_status = psa_unregister_read_under_mutex(slot); + + LOCAL_INPUT_FREE(input_external, input); + LOCAL_INPUT_FREE(salt_external, salt); + LOCAL_OUTPUT_FREE(output_external, output); + + return (status == PSA_SUCCESS) ? unlock_status : status; +} + +psa_status_t psa_asymmetric_decrypt(mbedtls_svc_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input_external, + size_t input_length, + const uint8_t *salt_external, + size_t salt_length, + uint8_t *output_external, + size_t output_size, + size_t *output_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + + LOCAL_INPUT_DECLARE(input_external, input); + LOCAL_INPUT_DECLARE(salt_external, salt); + LOCAL_OUTPUT_DECLARE(output_external, output); + + (void) input; + (void) input_length; + (void) salt; + (void) output; + (void) output_size; + + *output_length = 0; + + if (!PSA_ALG_IS_RSA_OAEP(alg) && salt_length != 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + status = psa_get_and_lock_key_slot_with_policy( + key, &slot, PSA_KEY_USAGE_DECRYPT, alg); + if (status != PSA_SUCCESS) { + return status; + } + if (!PSA_KEY_TYPE_IS_KEY_PAIR(slot->attr.type)) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + LOCAL_INPUT_ALLOC(input_external, input_length, input); + LOCAL_INPUT_ALLOC(salt_external, salt_length, salt); + LOCAL_OUTPUT_ALLOC(output_external, output_size, output); + + status = psa_driver_wrapper_asymmetric_decrypt( + &slot->attr, slot->key.data, slot->key.bytes, + alg, input, input_length, salt, salt_length, + output, output_size, output_length); + +exit: + unlock_status = psa_unregister_read_under_mutex(slot); + + LOCAL_INPUT_FREE(input_external, input); + LOCAL_INPUT_FREE(salt_external, salt); + LOCAL_OUTPUT_FREE(output_external, output); + + return (status == PSA_SUCCESS) ? unlock_status : status; +} + +/****************************************************************/ +/* Asymmetric interruptible cryptography */ +/****************************************************************/ + +static uint32_t psa_interruptible_max_ops = PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED; + +void psa_interruptible_set_max_ops(uint32_t max_ops) +{ + psa_interruptible_max_ops = max_ops; +} + +uint32_t psa_interruptible_get_max_ops(void) +{ + return psa_interruptible_max_ops; +} + +uint32_t psa_sign_hash_get_num_ops( + const psa_sign_hash_interruptible_operation_t *operation) +{ + return operation->num_ops; +} + +uint32_t psa_verify_hash_get_num_ops( + const psa_verify_hash_interruptible_operation_t *operation) +{ + return operation->num_ops; +} + +static psa_status_t psa_sign_hash_abort_internal( + psa_sign_hash_interruptible_operation_t *operation) +{ + if (operation->id == 0) { + /* The object has (apparently) been initialized but it is not (yet) + * in use. It's ok to call abort on such an object, and there's + * nothing to do. */ + return PSA_SUCCESS; + } + + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + status = psa_driver_wrapper_sign_hash_abort(operation); + + operation->id = 0; + + /* Do not clear either the error_occurred or num_ops elements here as they + * only want to be cleared by the application calling abort, not by abort + * being called at completion of an operation. */ + + return status; +} + +psa_status_t psa_sign_hash_start( + psa_sign_hash_interruptible_operation_t *operation, + mbedtls_svc_key_id_t key, psa_algorithm_t alg, + const uint8_t *hash_external, size_t hash_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + + LOCAL_INPUT_DECLARE(hash_external, hash); + + /* Check that start has not been previously called, or operation has not + * previously errored. */ + if (operation->id != 0 || operation->error_occurred) { + return PSA_ERROR_BAD_STATE; + } + + /* Make sure the driver-dependent part of the operation is zeroed. + * This is a guarantee we make to drivers. Initializing the operation + * does not necessarily take care of it, since the context is a + * union and initializing a union does not necessarily initialize + * all of its members. */ + memset(&operation->ctx, 0, sizeof(operation->ctx)); + + status = psa_sign_verify_check_alg(0, alg); + if (status != PSA_SUCCESS) { + operation->error_occurred = 1; + return status; + } + + status = psa_get_and_lock_key_slot_with_policy(key, &slot, + PSA_KEY_USAGE_SIGN_HASH, + alg); + + if (status != PSA_SUCCESS) { + goto exit; + } + + if (!PSA_KEY_TYPE_IS_KEY_PAIR(slot->attr.type)) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + LOCAL_INPUT_ALLOC(hash_external, hash_length, hash); + + /* Ensure ops count gets reset, in case of operation re-use. */ + operation->num_ops = 0; + + status = psa_driver_wrapper_sign_hash_start(operation, &slot->attr, + slot->key.data, + slot->key.bytes, alg, + hash, hash_length); +exit: + + if (status != PSA_SUCCESS) { + operation->error_occurred = 1; + psa_sign_hash_abort_internal(operation); + } + + unlock_status = psa_unregister_read_under_mutex(slot); + + if (unlock_status != PSA_SUCCESS) { + operation->error_occurred = 1; + } + + LOCAL_INPUT_FREE(hash_external, hash); + + return (status == PSA_SUCCESS) ? unlock_status : status; +} + + +psa_status_t psa_sign_hash_complete( + psa_sign_hash_interruptible_operation_t *operation, + uint8_t *signature_external, size_t signature_size, + size_t *signature_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + LOCAL_OUTPUT_DECLARE(signature_external, signature); + + *signature_length = 0; + + /* Check that start has been called first, and that operation has not + * previously errored. */ + if (operation->id == 0 || operation->error_occurred) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + /* Immediately reject a zero-length signature buffer. This guarantees that + * signature must be a valid pointer. */ + if (signature_size == 0) { + status = PSA_ERROR_BUFFER_TOO_SMALL; + goto exit; + } + + LOCAL_OUTPUT_ALLOC(signature_external, signature_size, signature); + + status = psa_driver_wrapper_sign_hash_complete(operation, signature, + signature_size, + signature_length); + + /* Update ops count with work done. */ + operation->num_ops = psa_driver_wrapper_sign_hash_get_num_ops(operation); + +exit: + + if (signature != NULL) { + psa_wipe_tag_output_buffer(signature, status, signature_size, + *signature_length); + } + + if (status != PSA_OPERATION_INCOMPLETE) { + if (status != PSA_SUCCESS) { + operation->error_occurred = 1; + } + + psa_sign_hash_abort_internal(operation); + } + + LOCAL_OUTPUT_FREE(signature_external, signature); + + return status; +} + +psa_status_t psa_sign_hash_abort( + psa_sign_hash_interruptible_operation_t *operation) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + status = psa_sign_hash_abort_internal(operation); + + /* We clear the number of ops done here, so that it is not cleared when + * the operation fails or succeeds, only on manual abort. */ + operation->num_ops = 0; + + /* Likewise, failure state. */ + operation->error_occurred = 0; + + return status; +} + +static psa_status_t psa_verify_hash_abort_internal( + psa_verify_hash_interruptible_operation_t *operation) +{ + if (operation->id == 0) { + /* The object has (apparently) been initialized but it is not (yet) + * in use. It's ok to call abort on such an object, and there's + * nothing to do. */ + return PSA_SUCCESS; + } + + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + status = psa_driver_wrapper_verify_hash_abort(operation); + + operation->id = 0; + + /* Do not clear either the error_occurred or num_ops elements here as they + * only want to be cleared by the application calling abort, not by abort + * being called at completion of an operation. */ + + return status; +} + +psa_status_t psa_verify_hash_start( + psa_verify_hash_interruptible_operation_t *operation, + mbedtls_svc_key_id_t key, psa_algorithm_t alg, + const uint8_t *hash_external, size_t hash_length, + const uint8_t *signature_external, size_t signature_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + + LOCAL_INPUT_DECLARE(hash_external, hash); + LOCAL_INPUT_DECLARE(signature_external, signature); + + /* Check that start has not been previously called, or operation has not + * previously errored. */ + if (operation->id != 0 || operation->error_occurred) { + return PSA_ERROR_BAD_STATE; + } + + /* Make sure the driver-dependent part of the operation is zeroed. + * This is a guarantee we make to drivers. Initializing the operation + * does not necessarily take care of it, since the context is a + * union and initializing a union does not necessarily initialize + * all of its members. */ + memset(&operation->ctx, 0, sizeof(operation->ctx)); + + status = psa_sign_verify_check_alg(0, alg); + if (status != PSA_SUCCESS) { + operation->error_occurred = 1; + return status; + } + + status = psa_get_and_lock_key_slot_with_policy(key, &slot, + PSA_KEY_USAGE_VERIFY_HASH, + alg); + + if (status != PSA_SUCCESS) { + operation->error_occurred = 1; + return status; + } + + LOCAL_INPUT_ALLOC(hash_external, hash_length, hash); + LOCAL_INPUT_ALLOC(signature_external, signature_length, signature); + + /* Ensure ops count gets reset, in case of operation re-use. */ + operation->num_ops = 0; + + status = psa_driver_wrapper_verify_hash_start(operation, &slot->attr, + slot->key.data, + slot->key.bytes, + alg, hash, hash_length, + signature, signature_length); +#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) +exit: +#endif + + if (status != PSA_SUCCESS) { + operation->error_occurred = 1; + psa_verify_hash_abort_internal(operation); + } + + unlock_status = psa_unregister_read_under_mutex(slot); + + if (unlock_status != PSA_SUCCESS) { + operation->error_occurred = 1; + } + + LOCAL_INPUT_FREE(hash_external, hash); + LOCAL_INPUT_FREE(signature_external, signature); + + return (status == PSA_SUCCESS) ? unlock_status : status; +} + +psa_status_t psa_verify_hash_complete( + psa_verify_hash_interruptible_operation_t *operation) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + /* Check that start has been called first, and that operation has not + * previously errored. */ + if (operation->id == 0 || operation->error_occurred) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + status = psa_driver_wrapper_verify_hash_complete(operation); + + /* Update ops count with work done. */ + operation->num_ops = psa_driver_wrapper_verify_hash_get_num_ops( + operation); + +exit: + + if (status != PSA_OPERATION_INCOMPLETE) { + if (status != PSA_SUCCESS) { + operation->error_occurred = 1; + } + + psa_verify_hash_abort_internal(operation); + } + + return status; +} + +psa_status_t psa_verify_hash_abort( + psa_verify_hash_interruptible_operation_t *operation) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + status = psa_verify_hash_abort_internal(operation); + + /* We clear the number of ops done here, so that it is not cleared when + * the operation fails or succeeds, only on manual abort. */ + operation->num_ops = 0; + + /* Likewise, failure state. */ + operation->error_occurred = 0; + + return status; +} + +/****************************************************************/ +/* Asymmetric interruptible cryptography internal */ +/* implementations */ +/****************************************************************/ + +void mbedtls_psa_interruptible_set_max_ops(uint32_t max_ops) +{ + +#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \ + defined(MBEDTLS_ECP_RESTARTABLE) + + /* Internal implementation uses zero to indicate infinite number max ops, + * therefore avoid this value, and set to minimum possible. */ + if (max_ops == 0) { + max_ops = 1; + } + + mbedtls_ecp_set_max_ops(max_ops); +#else + (void) max_ops; +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) && + * defined( MBEDTLS_ECP_RESTARTABLE ) */ +} + +uint32_t mbedtls_psa_sign_hash_get_num_ops( + const mbedtls_psa_sign_hash_interruptible_operation_t *operation) +{ +#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \ + defined(MBEDTLS_ECP_RESTARTABLE) + + return operation->num_ops; +#else + (void) operation; + return 0; +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) && + * defined( MBEDTLS_ECP_RESTARTABLE ) */ +} + +uint32_t mbedtls_psa_verify_hash_get_num_ops( + const mbedtls_psa_verify_hash_interruptible_operation_t *operation) +{ + #if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \ + defined(MBEDTLS_ECP_RESTARTABLE) + + return operation->num_ops; +#else + (void) operation; + return 0; +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) && + * defined( MBEDTLS_ECP_RESTARTABLE ) */ +} + +/* Detect supported interruptible sign/verify mechanisms precisely. + * This is not strictly needed: we could accept everything, and let the + * code fail later during complete() if the mechanism is unsupported + * (e.g. attempting deterministic ECDSA when only the randomized variant + * is available). But it's easier for applications and especially for our + * test code to detect all not-supported errors during start(). + * + * Note that this function ignores the hash component. The core code + * is supposed to check the hash part by calling is_hash_supported(). + */ +static inline int can_do_interruptible_sign_verify(psa_algorithm_t alg) +{ +#if defined(MBEDTLS_ECP_RESTARTABLE) +#if defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) + if (PSA_ALG_IS_DETERMINISTIC_ECDSA(alg)) { + return 1; + } +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) + if (PSA_ALG_IS_RANDOMIZED_ECDSA(alg)) { + return 1; + } +#endif +#endif /* defined(MBEDTLS_ECP_RESTARTABLE) */ + (void) alg; + return 0; +} + +psa_status_t mbedtls_psa_sign_hash_start( + mbedtls_psa_sign_hash_interruptible_operation_t *operation, + const psa_key_attributes_t *attributes, const uint8_t *key_buffer, + size_t key_buffer_size, psa_algorithm_t alg, + const uint8_t *hash, size_t hash_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + size_t required_hash_length; + + if (!PSA_KEY_TYPE_IS_ECC_KEY_PAIR(attributes->type)) { + return PSA_ERROR_NOT_SUPPORTED; + } + psa_ecc_family_t curve = PSA_KEY_TYPE_ECC_GET_FAMILY(attributes->type); + if (!PSA_ECC_FAMILY_IS_WEIERSTRASS(curve)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (!can_do_interruptible_sign_verify(alg)) { + return PSA_ERROR_NOT_SUPPORTED; + } + +#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \ + defined(MBEDTLS_ECP_RESTARTABLE) + + mbedtls_ecdsa_restart_init(&operation->restart_ctx); + + /* Ensure num_ops is zero'ed in case of context re-use. */ + operation->num_ops = 0; + + status = mbedtls_psa_ecp_load_representation(attributes->type, + attributes->bits, + key_buffer, + key_buffer_size, + &operation->ctx); + + if (status != PSA_SUCCESS) { + return status; + } + + operation->coordinate_bytes = PSA_BITS_TO_BYTES( + operation->ctx->grp.nbits); + + psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH(alg); + operation->md_alg = mbedtls_md_type_from_psa_alg(hash_alg); + operation->alg = alg; + + /* We only need to store the same length of hash as the private key size + * here, it would be truncated by the internal implementation anyway. */ + required_hash_length = (hash_length < operation->coordinate_bytes ? + hash_length : operation->coordinate_bytes); + + if (required_hash_length > sizeof(operation->hash)) { + /* Shouldn't happen, but better safe than sorry. */ + return PSA_ERROR_CORRUPTION_DETECTED; + } + + memcpy(operation->hash, hash, required_hash_length); + operation->hash_length = required_hash_length; + + return PSA_SUCCESS; + +#else + (void) operation; + (void) key_buffer; + (void) key_buffer_size; + (void) alg; + (void) hash; + (void) hash_length; + (void) status; + (void) required_hash_length; + + return PSA_ERROR_NOT_SUPPORTED; +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) && + * defined( MBEDTLS_ECP_RESTARTABLE ) */ +} + +psa_status_t mbedtls_psa_sign_hash_complete( + mbedtls_psa_sign_hash_interruptible_operation_t *operation, + uint8_t *signature, size_t signature_size, + size_t *signature_length) +{ +#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \ + defined(MBEDTLS_ECP_RESTARTABLE) + + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi r; + mbedtls_mpi s; + + mbedtls_mpi_init(&r); + mbedtls_mpi_init(&s); + + /* Ensure max_ops is set to the current value (or default). */ + mbedtls_psa_interruptible_set_max_ops(psa_interruptible_get_max_ops()); + + if (signature_size < 2 * operation->coordinate_bytes) { + status = PSA_ERROR_BUFFER_TOO_SMALL; + goto exit; + } + + if (PSA_ALG_ECDSA_IS_DETERMINISTIC(operation->alg)) { + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) + status = mbedtls_to_psa_error( + mbedtls_ecdsa_sign_det_restartable(&operation->ctx->grp, + &r, + &s, + &operation->ctx->d, + operation->hash, + operation->hash_length, + operation->md_alg, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE, + &operation->restart_ctx)); +#else /* defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) */ + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) */ + } else { + status = mbedtls_to_psa_error( + mbedtls_ecdsa_sign_restartable(&operation->ctx->grp, + &r, + &s, + &operation->ctx->d, + operation->hash, + operation->hash_length, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE, + &operation->restart_ctx)); + } + + /* Hide the fact that the restart context only holds a delta of number of + * ops done during the last operation, not an absolute value. */ + operation->num_ops += operation->restart_ctx.ecp.ops_done; + + if (status == PSA_SUCCESS) { + status = mbedtls_to_psa_error( + mbedtls_mpi_write_binary(&r, + signature, + operation->coordinate_bytes) + ); + + if (status != PSA_SUCCESS) { + goto exit; + } + + status = mbedtls_to_psa_error( + mbedtls_mpi_write_binary(&s, + signature + + operation->coordinate_bytes, + operation->coordinate_bytes) + ); + + if (status != PSA_SUCCESS) { + goto exit; + } + + *signature_length = operation->coordinate_bytes * 2; + + status = PSA_SUCCESS; + } + +exit: + + mbedtls_mpi_free(&r); + mbedtls_mpi_free(&s); + return status; + + #else + + (void) operation; + (void) signature; + (void) signature_size; + (void) signature_length; + + return PSA_ERROR_NOT_SUPPORTED; + +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) && + * defined( MBEDTLS_ECP_RESTARTABLE ) */ +} + +psa_status_t mbedtls_psa_sign_hash_abort( + mbedtls_psa_sign_hash_interruptible_operation_t *operation) +{ + +#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \ + defined(MBEDTLS_ECP_RESTARTABLE) + + if (operation->ctx) { + mbedtls_ecdsa_free(operation->ctx); + mbedtls_free(operation->ctx); + operation->ctx = NULL; + } + + mbedtls_ecdsa_restart_free(&operation->restart_ctx); + + operation->num_ops = 0; + + return PSA_SUCCESS; + +#else + + (void) operation; + + return PSA_ERROR_NOT_SUPPORTED; + +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) && + * defined( MBEDTLS_ECP_RESTARTABLE ) */ +} + +psa_status_t mbedtls_psa_verify_hash_start( + mbedtls_psa_verify_hash_interruptible_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *hash, size_t hash_length, + const uint8_t *signature, size_t signature_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + size_t coordinate_bytes = 0; + size_t required_hash_length = 0; + + if (!PSA_KEY_TYPE_IS_ECC(attributes->type)) { + return PSA_ERROR_NOT_SUPPORTED; + } + psa_ecc_family_t curve = PSA_KEY_TYPE_ECC_GET_FAMILY(attributes->type); + if (!PSA_ECC_FAMILY_IS_WEIERSTRASS(curve)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (!can_do_interruptible_sign_verify(alg)) { + return PSA_ERROR_NOT_SUPPORTED; + } + +#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \ + defined(MBEDTLS_ECP_RESTARTABLE) + + mbedtls_ecdsa_restart_init(&operation->restart_ctx); + mbedtls_mpi_init(&operation->r); + mbedtls_mpi_init(&operation->s); + + /* Ensure num_ops is zero'ed in case of context re-use. */ + operation->num_ops = 0; + + status = mbedtls_psa_ecp_load_representation(attributes->type, + attributes->bits, + key_buffer, + key_buffer_size, + &operation->ctx); + + if (status != PSA_SUCCESS) { + return status; + } + + coordinate_bytes = PSA_BITS_TO_BYTES(operation->ctx->grp.nbits); + + if (signature_length != 2 * coordinate_bytes) { + return PSA_ERROR_INVALID_SIGNATURE; + } + + status = mbedtls_to_psa_error( + mbedtls_mpi_read_binary(&operation->r, + signature, + coordinate_bytes)); + + if (status != PSA_SUCCESS) { + return status; + } + + status = mbedtls_to_psa_error( + mbedtls_mpi_read_binary(&operation->s, + signature + + coordinate_bytes, + coordinate_bytes)); + + if (status != PSA_SUCCESS) { + return status; + } + + status = mbedtls_psa_ecp_load_public_part(operation->ctx); + + if (status != PSA_SUCCESS) { + return status; + } + + /* We only need to store the same length of hash as the private key size + * here, it would be truncated by the internal implementation anyway. */ + required_hash_length = (hash_length < coordinate_bytes ? hash_length : + coordinate_bytes); + + if (required_hash_length > sizeof(operation->hash)) { + /* Shouldn't happen, but better safe than sorry. */ + return PSA_ERROR_CORRUPTION_DETECTED; + } + + memcpy(operation->hash, hash, required_hash_length); + operation->hash_length = required_hash_length; + + return PSA_SUCCESS; +#else + (void) operation; + (void) key_buffer; + (void) key_buffer_size; + (void) alg; + (void) hash; + (void) hash_length; + (void) signature; + (void) signature_length; + (void) status; + (void) coordinate_bytes; + (void) required_hash_length; + + return PSA_ERROR_NOT_SUPPORTED; +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) && + * defined( MBEDTLS_ECP_RESTARTABLE ) */ +} + +psa_status_t mbedtls_psa_verify_hash_complete( + mbedtls_psa_verify_hash_interruptible_operation_t *operation) +{ + +#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \ + defined(MBEDTLS_ECP_RESTARTABLE) + + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + /* Ensure max_ops is set to the current value (or default). */ + mbedtls_psa_interruptible_set_max_ops(psa_interruptible_get_max_ops()); + + status = mbedtls_to_psa_error( + mbedtls_ecdsa_verify_restartable(&operation->ctx->grp, + operation->hash, + operation->hash_length, + &operation->ctx->Q, + &operation->r, + &operation->s, + &operation->restart_ctx)); + + /* Hide the fact that the restart context only holds a delta of number of + * ops done during the last operation, not an absolute value. */ + operation->num_ops += operation->restart_ctx.ecp.ops_done; + + return status; +#else + (void) operation; + + return PSA_ERROR_NOT_SUPPORTED; + +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) && + * defined( MBEDTLS_ECP_RESTARTABLE ) */ +} + +psa_status_t mbedtls_psa_verify_hash_abort( + mbedtls_psa_verify_hash_interruptible_operation_t *operation) +{ + +#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \ + defined(MBEDTLS_ECP_RESTARTABLE) + + if (operation->ctx) { + mbedtls_ecdsa_free(operation->ctx); + mbedtls_free(operation->ctx); + operation->ctx = NULL; + } + + mbedtls_ecdsa_restart_free(&operation->restart_ctx); + + operation->num_ops = 0; + + mbedtls_mpi_free(&operation->r); + mbedtls_mpi_free(&operation->s); + + return PSA_SUCCESS; + +#else + (void) operation; + + return PSA_ERROR_NOT_SUPPORTED; + +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) && + * defined( MBEDTLS_ECP_RESTARTABLE ) */ +} + +static psa_status_t psa_generate_random_internal(uint8_t *output, + size_t output_size) +{ + GUARD_MODULE_INITIALIZED; + +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + + psa_status_t status; + size_t output_length = 0; + status = mbedtls_psa_external_get_random(&global_data.rng, + output, output_size, + &output_length); + if (status != PSA_SUCCESS) { + return status; + } + /* Breaking up a request into smaller chunks is currently not supported + * for the external RNG interface. */ + if (output_length != output_size) { + return PSA_ERROR_INSUFFICIENT_ENTROPY; + } + return PSA_SUCCESS; + +#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ + return psa_random_internal_generate(&global_data.rng, + output, output_size); +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ +} + + +/****************************************************************/ +/* Symmetric cryptography */ +/****************************************************************/ + +static psa_status_t psa_cipher_setup(psa_cipher_operation_t *operation, + mbedtls_svc_key_id_t key, + psa_algorithm_t alg, + mbedtls_operation_t cipher_operation) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot = NULL; + psa_key_usage_t usage = (cipher_operation == MBEDTLS_ENCRYPT ? + PSA_KEY_USAGE_ENCRYPT : + PSA_KEY_USAGE_DECRYPT); + + /* A context must be freshly initialized before it can be set up. */ + if (operation->id != 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (!PSA_ALG_IS_CIPHER(alg)) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + status = psa_get_and_lock_key_slot_with_policy(key, &slot, usage, alg); + if (status != PSA_SUCCESS) { + goto exit; + } + + /* Initialize the operation struct members, except for id. The id member + * is used to indicate to psa_cipher_abort that there are resources to free, + * so we only set it (in the driver wrapper) after resources have been + * allocated/initialized. */ + operation->iv_set = 0; + if (alg == PSA_ALG_ECB_NO_PADDING) { + operation->iv_required = 0; + } else { + operation->iv_required = 1; + } + operation->default_iv_length = PSA_CIPHER_IV_LENGTH(slot->attr.type, alg); + + + /* Make sure the driver-dependent part of the operation is zeroed. + * This is a guarantee we make to drivers. Initializing the operation + * does not necessarily take care of it, since the context is a + * union and initializing a union does not necessarily initialize + * all of its members. */ + memset(&operation->ctx, 0, sizeof(operation->ctx)); + + /* Try doing the operation through a driver before using software fallback. */ + if (cipher_operation == MBEDTLS_ENCRYPT) { + status = psa_driver_wrapper_cipher_encrypt_setup(operation, + &slot->attr, + slot->key.data, + slot->key.bytes, + alg); + } else { + status = psa_driver_wrapper_cipher_decrypt_setup(operation, + &slot->attr, + slot->key.data, + slot->key.bytes, + alg); + } + +exit: + if (status != PSA_SUCCESS) { + psa_cipher_abort(operation); + } + + unlock_status = psa_unregister_read_under_mutex(slot); + + return (status == PSA_SUCCESS) ? unlock_status : status; +} + +psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation, + mbedtls_svc_key_id_t key, + psa_algorithm_t alg) +{ + return psa_cipher_setup(operation, key, alg, MBEDTLS_ENCRYPT); +} + +psa_status_t psa_cipher_decrypt_setup(psa_cipher_operation_t *operation, + mbedtls_svc_key_id_t key, + psa_algorithm_t alg) +{ + return psa_cipher_setup(operation, key, alg, MBEDTLS_DECRYPT); +} + +psa_status_t psa_cipher_generate_iv(psa_cipher_operation_t *operation, + uint8_t *iv_external, + size_t iv_size, + size_t *iv_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + size_t default_iv_length = 0; + + LOCAL_OUTPUT_DECLARE(iv_external, iv); + + if (operation->id == 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (operation->iv_set || !operation->iv_required) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + default_iv_length = operation->default_iv_length; + if (iv_size < default_iv_length) { + status = PSA_ERROR_BUFFER_TOO_SMALL; + goto exit; + } + + if (default_iv_length > PSA_CIPHER_IV_MAX_SIZE) { + status = PSA_ERROR_GENERIC_ERROR; + goto exit; + } + + LOCAL_OUTPUT_ALLOC(iv_external, default_iv_length, iv); + + status = psa_generate_random_internal(iv, default_iv_length); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_driver_wrapper_cipher_set_iv(operation, + iv, default_iv_length); + +exit: + if (status == PSA_SUCCESS) { + *iv_length = default_iv_length; + operation->iv_set = 1; + } else { + *iv_length = 0; + psa_cipher_abort(operation); + if (iv != NULL) { + mbedtls_platform_zeroize(iv, default_iv_length); + } + } + + LOCAL_OUTPUT_FREE(iv_external, iv); + return status; +} + +psa_status_t psa_cipher_set_iv(psa_cipher_operation_t *operation, + const uint8_t *iv_external, + size_t iv_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + LOCAL_INPUT_DECLARE(iv_external, iv); + + if (operation->id == 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (operation->iv_set || !operation->iv_required) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (iv_length > PSA_CIPHER_IV_MAX_SIZE) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + LOCAL_INPUT_ALLOC(iv_external, iv_length, iv); + + status = psa_driver_wrapper_cipher_set_iv(operation, + iv, + iv_length); + +exit: + if (status == PSA_SUCCESS) { + operation->iv_set = 1; + } else { + psa_cipher_abort(operation); + } + + LOCAL_INPUT_FREE(iv_external, iv); + + return status; +} + +psa_status_t psa_cipher_update(psa_cipher_operation_t *operation, + const uint8_t *input_external, + size_t input_length, + uint8_t *output_external, + size_t output_size, + size_t *output_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + LOCAL_INPUT_DECLARE(input_external, input); + LOCAL_OUTPUT_DECLARE(output_external, output); + + if (operation->id == 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (operation->iv_required && !operation->iv_set) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + LOCAL_INPUT_ALLOC(input_external, input_length, input); + LOCAL_OUTPUT_ALLOC(output_external, output_size, output); + + status = psa_driver_wrapper_cipher_update(operation, + input, + input_length, + output, + output_size, + output_length); + +exit: + if (status != PSA_SUCCESS) { + psa_cipher_abort(operation); + } + + LOCAL_INPUT_FREE(input_external, input); + LOCAL_OUTPUT_FREE(output_external, output); + + return status; +} + +psa_status_t psa_cipher_finish(psa_cipher_operation_t *operation, + uint8_t *output_external, + size_t output_size, + size_t *output_length) +{ + psa_status_t status = PSA_ERROR_GENERIC_ERROR; + + LOCAL_OUTPUT_DECLARE(output_external, output); + + if (operation->id == 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (operation->iv_required && !operation->iv_set) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + LOCAL_OUTPUT_ALLOC(output_external, output_size, output); + + status = psa_driver_wrapper_cipher_finish(operation, + output, + output_size, + output_length); + +exit: + /* C99 doesn't allow a declaration to follow a label */; + psa_status_t abort_status = psa_cipher_abort(operation); + /* Normally abort shouldn't fail unless the operation is in a bad + * state, in which case we'd expect finish to fail with the same error. + * So it doesn't matter much which call's error code we pick when both + * fail. However, in unauthenticated decryption specifically, the + * distinction between PSA_SUCCESS and PSA_ERROR_INVALID_PADDING is + * security-sensitive (risk of a padding oracle attack), so here we + * must not have a code path that depends on the value of status. */ + if (abort_status != PSA_SUCCESS) { + status = abort_status; + } + + /* Set *output_length to 0 if status != PSA_SUCCESS, without + * leaking the value of status through a timing side channel + * (status == PSA_ERROR_INVALID_PADDING is sensitive when doing + * unpadded decryption, due to the risk of padding oracle attack). */ + mbedtls_ct_condition_t success = + mbedtls_ct_bool_not(mbedtls_ct_bool(status)); + *output_length = mbedtls_ct_size_if_else_0(success, *output_length); + + LOCAL_OUTPUT_FREE(output_external, output); + + return status; +} + +psa_status_t psa_cipher_abort(psa_cipher_operation_t *operation) +{ + if (operation->id == 0) { + /* The object has (apparently) been initialized but it is not (yet) + * in use. It's ok to call abort on such an object, and there's + * nothing to do. */ + return PSA_SUCCESS; + } + + psa_driver_wrapper_cipher_abort(operation); + + operation->id = 0; + operation->iv_set = 0; + operation->iv_required = 0; + + return PSA_SUCCESS; +} + +psa_status_t psa_cipher_encrypt(mbedtls_svc_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input_external, + size_t input_length, + uint8_t *output_external, + size_t output_size, + size_t *output_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot = NULL; + uint8_t local_iv[PSA_CIPHER_IV_MAX_SIZE]; + size_t default_iv_length = 0; + + LOCAL_INPUT_DECLARE(input_external, input); + LOCAL_OUTPUT_DECLARE(output_external, output); + + if (!PSA_ALG_IS_CIPHER(alg)) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + status = psa_get_and_lock_key_slot_with_policy(key, &slot, + PSA_KEY_USAGE_ENCRYPT, + alg); + if (status != PSA_SUCCESS) { + goto exit; + } + + default_iv_length = PSA_CIPHER_IV_LENGTH(slot->attr.type, alg); + if (default_iv_length > PSA_CIPHER_IV_MAX_SIZE) { + status = PSA_ERROR_GENERIC_ERROR; + goto exit; + } + + if (default_iv_length > 0) { + if (output_size < default_iv_length) { + status = PSA_ERROR_BUFFER_TOO_SMALL; + goto exit; + } + + status = psa_generate_random_internal(local_iv, default_iv_length); + if (status != PSA_SUCCESS) { + goto exit; + } + } + + LOCAL_INPUT_ALLOC(input_external, input_length, input); + LOCAL_OUTPUT_ALLOC(output_external, output_size, output); + + status = psa_driver_wrapper_cipher_encrypt( + &slot->attr, slot->key.data, slot->key.bytes, + alg, local_iv, default_iv_length, input, input_length, + psa_crypto_buffer_offset(output, default_iv_length), + output_size - default_iv_length, output_length); + +exit: + unlock_status = psa_unregister_read_under_mutex(slot); + if (status == PSA_SUCCESS) { + status = unlock_status; + } + + if (status == PSA_SUCCESS) { + if (default_iv_length > 0) { + memcpy(output, local_iv, default_iv_length); + } + *output_length += default_iv_length; + } else { + *output_length = 0; + } + + LOCAL_INPUT_FREE(input_external, input); + LOCAL_OUTPUT_FREE(output_external, output); + + return status; +} + +psa_status_t psa_cipher_decrypt(mbedtls_svc_key_id_t key, + psa_algorithm_t alg, + const uint8_t *input_external, + size_t input_length, + uint8_t *output_external, + size_t output_size, + size_t *output_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot = NULL; + + LOCAL_INPUT_DECLARE(input_external, input); + LOCAL_OUTPUT_DECLARE(output_external, output); + + if (!PSA_ALG_IS_CIPHER(alg)) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + status = psa_get_and_lock_key_slot_with_policy(key, &slot, + PSA_KEY_USAGE_DECRYPT, + alg); + if (status != PSA_SUCCESS) { + goto exit; + } + + if (input_length < PSA_CIPHER_IV_LENGTH(slot->attr.type, alg)) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + LOCAL_INPUT_ALLOC(input_external, input_length, input); + LOCAL_OUTPUT_ALLOC(output_external, output_size, output); + + status = psa_driver_wrapper_cipher_decrypt( + &slot->attr, slot->key.data, slot->key.bytes, + alg, input, input_length, + output, output_size, output_length); + +exit: + unlock_status = psa_unregister_read_under_mutex(slot); + if (unlock_status != PSA_SUCCESS) { + status = unlock_status; + } + + /* Set *output_length to 0 if status != PSA_SUCCESS, without + * leaking the value of status through a timing side channel + * (status == PSA_ERROR_INVALID_PADDING is sensitive when doing + * unpadded decryption, due to the risk of padding oracle attack). */ + mbedtls_ct_condition_t success = + mbedtls_ct_bool_not(mbedtls_ct_bool(status)); + *output_length = mbedtls_ct_size_if_else_0(success, *output_length); + + LOCAL_INPUT_FREE(input_external, input); + LOCAL_OUTPUT_FREE(output_external, output); + + return status; +} + + +/****************************************************************/ +/* AEAD */ +/****************************************************************/ + +/* Helper function to get the base algorithm from its variants. */ +static psa_algorithm_t psa_aead_get_base_algorithm(psa_algorithm_t alg) +{ + return PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(alg); +} + +/* Helper function to perform common nonce length checks. */ +static psa_status_t psa_aead_check_nonce_length(psa_algorithm_t alg, + size_t nonce_length) +{ + psa_algorithm_t base_alg = psa_aead_get_base_algorithm(alg); + + switch (base_alg) { +#if defined(PSA_WANT_ALG_GCM) + case PSA_ALG_GCM: + /* Not checking max nonce size here as GCM spec allows almost + * arbitrarily large nonces. Please note that we do not generally + * recommend the usage of nonces of greater length than + * PSA_AEAD_NONCE_MAX_SIZE, as large nonces are hashed to a shorter + * size, which can then lead to collisions if you encrypt a very + * large number of messages.*/ + if (nonce_length != 0) { + return PSA_SUCCESS; + } + break; +#endif /* PSA_WANT_ALG_GCM */ +#if defined(PSA_WANT_ALG_CCM) + case PSA_ALG_CCM: + if (nonce_length >= 7 && nonce_length <= 13) { + return PSA_SUCCESS; + } + break; +#endif /* PSA_WANT_ALG_CCM */ +#if defined(PSA_WANT_ALG_CHACHA20_POLY1305) + case PSA_ALG_CHACHA20_POLY1305: + if (nonce_length == 12) { + return PSA_SUCCESS; + } else if (nonce_length == 8) { + return PSA_ERROR_NOT_SUPPORTED; + } + break; +#endif /* PSA_WANT_ALG_CHACHA20_POLY1305 */ + default: + (void) nonce_length; + return PSA_ERROR_NOT_SUPPORTED; + } + + return PSA_ERROR_INVALID_ARGUMENT; +} + +static psa_status_t psa_aead_check_algorithm(psa_algorithm_t alg) +{ + if (!PSA_ALG_IS_AEAD(alg) || PSA_ALG_IS_WILDCARD(alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return PSA_SUCCESS; +} + +psa_status_t psa_aead_encrypt(mbedtls_svc_key_id_t key, + psa_algorithm_t alg, + const uint8_t *nonce_external, + size_t nonce_length, + const uint8_t *additional_data_external, + size_t additional_data_length, + const uint8_t *plaintext_external, + size_t plaintext_length, + uint8_t *ciphertext_external, + size_t ciphertext_size, + size_t *ciphertext_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + + LOCAL_INPUT_DECLARE(nonce_external, nonce); + LOCAL_INPUT_DECLARE(additional_data_external, additional_data); + LOCAL_INPUT_DECLARE(plaintext_external, plaintext); + LOCAL_OUTPUT_DECLARE(ciphertext_external, ciphertext); + + *ciphertext_length = 0; + + status = psa_aead_check_algorithm(alg); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_get_and_lock_key_slot_with_policy( + key, &slot, PSA_KEY_USAGE_ENCRYPT, alg); + if (status != PSA_SUCCESS) { + return status; + } + + LOCAL_INPUT_ALLOC(nonce_external, nonce_length, nonce); + LOCAL_INPUT_ALLOC(additional_data_external, additional_data_length, additional_data); + LOCAL_INPUT_ALLOC(plaintext_external, plaintext_length, plaintext); + LOCAL_OUTPUT_ALLOC(ciphertext_external, ciphertext_size, ciphertext); + + status = psa_aead_check_nonce_length(alg, nonce_length); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_driver_wrapper_aead_encrypt( + &slot->attr, slot->key.data, slot->key.bytes, + alg, + nonce, nonce_length, + additional_data, additional_data_length, + plaintext, plaintext_length, + ciphertext, ciphertext_size, ciphertext_length); + + if (status != PSA_SUCCESS && ciphertext_size != 0) { + memset(ciphertext, 0, ciphertext_size); + } + +exit: + LOCAL_INPUT_FREE(nonce_external, nonce); + LOCAL_INPUT_FREE(additional_data_external, additional_data); + LOCAL_INPUT_FREE(plaintext_external, plaintext); + LOCAL_OUTPUT_FREE(ciphertext_external, ciphertext); + + psa_unregister_read_under_mutex(slot); + + return status; +} + +psa_status_t psa_aead_decrypt(mbedtls_svc_key_id_t key, + psa_algorithm_t alg, + const uint8_t *nonce_external, + size_t nonce_length, + const uint8_t *additional_data_external, + size_t additional_data_length, + const uint8_t *ciphertext_external, + size_t ciphertext_length, + uint8_t *plaintext_external, + size_t plaintext_size, + size_t *plaintext_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + + LOCAL_INPUT_DECLARE(nonce_external, nonce); + LOCAL_INPUT_DECLARE(additional_data_external, additional_data); + LOCAL_INPUT_DECLARE(ciphertext_external, ciphertext); + LOCAL_OUTPUT_DECLARE(plaintext_external, plaintext); + + *plaintext_length = 0; + + status = psa_aead_check_algorithm(alg); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_get_and_lock_key_slot_with_policy( + key, &slot, PSA_KEY_USAGE_DECRYPT, alg); + if (status != PSA_SUCCESS) { + return status; + } + + LOCAL_INPUT_ALLOC(nonce_external, nonce_length, nonce); + LOCAL_INPUT_ALLOC(additional_data_external, additional_data_length, + additional_data); + LOCAL_INPUT_ALLOC(ciphertext_external, ciphertext_length, ciphertext); + LOCAL_OUTPUT_ALLOC(plaintext_external, plaintext_size, plaintext); + + status = psa_aead_check_nonce_length(alg, nonce_length); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_driver_wrapper_aead_decrypt( + &slot->attr, slot->key.data, slot->key.bytes, + alg, + nonce, nonce_length, + additional_data, additional_data_length, + ciphertext, ciphertext_length, + plaintext, plaintext_size, plaintext_length); + + if (status != PSA_SUCCESS && plaintext_size != 0) { + memset(plaintext, 0, plaintext_size); + } + +exit: + LOCAL_INPUT_FREE(nonce_external, nonce); + LOCAL_INPUT_FREE(additional_data_external, additional_data); + LOCAL_INPUT_FREE(ciphertext_external, ciphertext); + LOCAL_OUTPUT_FREE(plaintext_external, plaintext); + + psa_unregister_read_under_mutex(slot); + + return status; +} + +static psa_status_t psa_validate_tag_length(psa_algorithm_t alg) +{ + const uint8_t tag_len = PSA_ALG_AEAD_GET_TAG_LENGTH(alg); + + switch (PSA_ALG_AEAD_WITH_SHORTENED_TAG(alg, 0)) { +#if defined(PSA_WANT_ALG_CCM) + case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, 0): + /* CCM allows the following tag lengths: 4, 6, 8, 10, 12, 14, 16.*/ + if (tag_len < 4 || tag_len > 16 || tag_len % 2) { + return PSA_ERROR_INVALID_ARGUMENT; + } + break; +#endif /* PSA_WANT_ALG_CCM */ + +#if defined(PSA_WANT_ALG_GCM) + case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, 0): + /* GCM allows the following tag lengths: 4, 8, 12, 13, 14, 15, 16. */ + if (tag_len != 4 && tag_len != 8 && (tag_len < 12 || tag_len > 16)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + break; +#endif /* PSA_WANT_ALG_GCM */ + +#if defined(PSA_WANT_ALG_CHACHA20_POLY1305) + case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CHACHA20_POLY1305, 0): + /* We only support the default tag length. */ + if (tag_len != 16) { + return PSA_ERROR_INVALID_ARGUMENT; + } + break; +#endif /* PSA_WANT_ALG_CHACHA20_POLY1305 */ + + default: + (void) tag_len; + return PSA_ERROR_NOT_SUPPORTED; + } + return PSA_SUCCESS; +} + +/* Set the key for a multipart authenticated operation. */ +static psa_status_t psa_aead_setup(psa_aead_operation_t *operation, + int is_encrypt, + mbedtls_svc_key_id_t key, + psa_algorithm_t alg) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot = NULL; + psa_key_usage_t key_usage = 0; + + status = psa_aead_check_algorithm(alg); + if (status != PSA_SUCCESS) { + goto exit; + } + + if (operation->id != 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (operation->nonce_set || operation->lengths_set || + operation->ad_started || operation->body_started) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + /* Make sure the driver-dependent part of the operation is zeroed. + * This is a guarantee we make to drivers. Initializing the operation + * does not necessarily take care of it, since the context is a + * union and initializing a union does not necessarily initialize + * all of its members. */ + memset(&operation->ctx, 0, sizeof(operation->ctx)); + + if (is_encrypt) { + key_usage = PSA_KEY_USAGE_ENCRYPT; + } else { + key_usage = PSA_KEY_USAGE_DECRYPT; + } + + status = psa_get_and_lock_key_slot_with_policy(key, &slot, key_usage, + alg); + if (status != PSA_SUCCESS) { + goto exit; + } + + if ((status = psa_validate_tag_length(alg)) != PSA_SUCCESS) { + goto exit; + } + + if (is_encrypt) { + status = psa_driver_wrapper_aead_encrypt_setup(operation, + &slot->attr, + slot->key.data, + slot->key.bytes, + alg); + } else { + status = psa_driver_wrapper_aead_decrypt_setup(operation, + &slot->attr, + slot->key.data, + slot->key.bytes, + alg); + } + if (status != PSA_SUCCESS) { + goto exit; + } + + operation->key_type = psa_get_key_type(&slot->attr); + +exit: + unlock_status = psa_unregister_read_under_mutex(slot); + + if (status == PSA_SUCCESS) { + status = unlock_status; + operation->alg = psa_aead_get_base_algorithm(alg); + operation->is_encrypt = is_encrypt; + } else { + psa_aead_abort(operation); + } + + return status; +} + +/* Set the key for a multipart authenticated encryption operation. */ +psa_status_t psa_aead_encrypt_setup(psa_aead_operation_t *operation, + mbedtls_svc_key_id_t key, + psa_algorithm_t alg) +{ + return psa_aead_setup(operation, 1, key, alg); +} + +/* Set the key for a multipart authenticated decryption operation. */ +psa_status_t psa_aead_decrypt_setup(psa_aead_operation_t *operation, + mbedtls_svc_key_id_t key, + psa_algorithm_t alg) +{ + return psa_aead_setup(operation, 0, key, alg); +} + +static psa_status_t psa_aead_set_nonce_internal(psa_aead_operation_t *operation, + const uint8_t *nonce, + size_t nonce_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (operation->id == 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (operation->nonce_set) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + status = psa_aead_check_nonce_length(operation->alg, nonce_length); + if (status != PSA_SUCCESS) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + status = psa_driver_wrapper_aead_set_nonce(operation, nonce, + nonce_length); + +exit: + if (status == PSA_SUCCESS) { + operation->nonce_set = 1; + } else { + psa_aead_abort(operation); + } + + return status; +} + +/* Generate a random nonce / IV for multipart AEAD operation */ +psa_status_t psa_aead_generate_nonce(psa_aead_operation_t *operation, + uint8_t *nonce_external, + size_t nonce_size, + size_t *nonce_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + uint8_t local_nonce[PSA_AEAD_NONCE_MAX_SIZE]; + size_t required_nonce_size = 0; + + LOCAL_OUTPUT_DECLARE(nonce_external, nonce); + LOCAL_OUTPUT_ALLOC(nonce_external, nonce_size, nonce); + + *nonce_length = 0; + + if (operation->id == 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (operation->nonce_set || !operation->is_encrypt) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + /* For CCM, this size may not be correct according to the PSA + * specification. The PSA Crypto 1.0.1 specification states: + * + * CCM encodes the plaintext length pLen in L octets, with L the smallest + * integer >= 2 where pLen < 2^(8L). The nonce length is then 15 - L bytes. + * + * However this restriction that L has to be the smallest integer is not + * applied in practice, and it is not implementable here since the + * plaintext length may or may not be known at this time. */ + required_nonce_size = PSA_AEAD_NONCE_LENGTH(operation->key_type, + operation->alg); + if (nonce_size < required_nonce_size) { + status = PSA_ERROR_BUFFER_TOO_SMALL; + goto exit; + } + + status = psa_generate_random_internal(local_nonce, required_nonce_size); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_aead_set_nonce_internal(operation, local_nonce, + required_nonce_size); + +exit: + if (status == PSA_SUCCESS) { + memcpy(nonce, local_nonce, required_nonce_size); + *nonce_length = required_nonce_size; + } else { + psa_aead_abort(operation); + } + + LOCAL_OUTPUT_FREE(nonce_external, nonce); + + return status; +} + +/* Set the nonce for a multipart authenticated encryption or decryption + operation.*/ +psa_status_t psa_aead_set_nonce(psa_aead_operation_t *operation, + const uint8_t *nonce_external, + size_t nonce_length) +{ + psa_status_t status; + + LOCAL_INPUT_DECLARE(nonce_external, nonce); + LOCAL_INPUT_ALLOC(nonce_external, nonce_length, nonce); + + status = psa_aead_set_nonce_internal(operation, nonce, nonce_length); + +/* Exit label is only needed for buffer copying, prevent unused warnings. */ +#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) +exit: +#endif + + LOCAL_INPUT_FREE(nonce_external, nonce); + + return status; +} + +/* Declare the lengths of the message and additional data for multipart AEAD. */ +psa_status_t psa_aead_set_lengths(psa_aead_operation_t *operation, + size_t ad_length, + size_t plaintext_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (operation->id == 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (operation->lengths_set || operation->ad_started || + operation->body_started) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + switch (operation->alg) { +#if defined(PSA_WANT_ALG_GCM) + case PSA_ALG_GCM: + /* Lengths can only be too large for GCM if size_t is bigger than 32 + * bits. Without the guard this code will generate warnings on 32bit + * builds. */ +#if SIZE_MAX > UINT32_MAX + if (((uint64_t) ad_length) >> 61 != 0 || + ((uint64_t) plaintext_length) > 0xFFFFFFFE0ull) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } +#endif + break; +#endif /* PSA_WANT_ALG_GCM */ +#if defined(PSA_WANT_ALG_CCM) + case PSA_ALG_CCM: + if (ad_length > 0xFF00) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + break; +#endif /* PSA_WANT_ALG_CCM */ +#if defined(PSA_WANT_ALG_CHACHA20_POLY1305) + case PSA_ALG_CHACHA20_POLY1305: + /* No length restrictions for ChaChaPoly. */ + break; +#endif /* PSA_WANT_ALG_CHACHA20_POLY1305 */ + default: + break; + } + + status = psa_driver_wrapper_aead_set_lengths(operation, ad_length, + plaintext_length); + +exit: + if (status == PSA_SUCCESS) { + operation->ad_remaining = ad_length; + operation->body_remaining = plaintext_length; + operation->lengths_set = 1; + } else { + psa_aead_abort(operation); + } + + return status; +} + +/* Pass additional data to an active multipart AEAD operation. */ +psa_status_t psa_aead_update_ad(psa_aead_operation_t *operation, + const uint8_t *input_external, + size_t input_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + LOCAL_INPUT_DECLARE(input_external, input); + LOCAL_INPUT_ALLOC(input_external, input_length, input); + + if (operation->id == 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (!operation->nonce_set || operation->body_started) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + /* No input to add (zero length), nothing to do. */ + if (input_length == 0) { + status = PSA_SUCCESS; + goto exit; + } + + if (operation->lengths_set) { + if (operation->ad_remaining < input_length) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + operation->ad_remaining -= input_length; + } +#if defined(PSA_WANT_ALG_CCM) + else if (operation->alg == PSA_ALG_CCM) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } +#endif /* PSA_WANT_ALG_CCM */ + + status = psa_driver_wrapper_aead_update_ad(operation, input, + input_length); + +exit: + if (status == PSA_SUCCESS) { + operation->ad_started = 1; + } else { + psa_aead_abort(operation); + } + + LOCAL_INPUT_FREE(input_external, input); + + return status; +} + +/* Encrypt or decrypt a message fragment in an active multipart AEAD + operation.*/ +psa_status_t psa_aead_update(psa_aead_operation_t *operation, + const uint8_t *input_external, + size_t input_length, + uint8_t *output_external, + size_t output_size, + size_t *output_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + + LOCAL_INPUT_DECLARE(input_external, input); + LOCAL_OUTPUT_DECLARE(output_external, output); + + LOCAL_INPUT_ALLOC(input_external, input_length, input); + LOCAL_OUTPUT_ALLOC(output_external, output_size, output); + + *output_length = 0; + + if (operation->id == 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (!operation->nonce_set) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (operation->lengths_set) { + /* Additional data length was supplied, but not all the additional + data was supplied.*/ + if (operation->ad_remaining != 0) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + /* Too much data provided. */ + if (operation->body_remaining < input_length) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + operation->body_remaining -= input_length; + } +#if defined(PSA_WANT_ALG_CCM) + else if (operation->alg == PSA_ALG_CCM) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } +#endif /* PSA_WANT_ALG_CCM */ + + status = psa_driver_wrapper_aead_update(operation, input, input_length, + output, output_size, + output_length); + +exit: + if (status == PSA_SUCCESS) { + operation->body_started = 1; + } else { + psa_aead_abort(operation); + } + + LOCAL_INPUT_FREE(input_external, input); + LOCAL_OUTPUT_FREE(output_external, output); + + return status; +} + +static psa_status_t psa_aead_final_checks(const psa_aead_operation_t *operation) +{ + if (operation->alg == PSA_ALG_CCM && !operation->lengths_set) { + return PSA_ERROR_BAD_STATE; + } + + if (operation->id == 0 || !operation->nonce_set) { + return PSA_ERROR_BAD_STATE; + } + + if (operation->lengths_set && (operation->ad_remaining != 0 || + operation->body_remaining != 0)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return PSA_SUCCESS; +} + +/* Finish encrypting a message in a multipart AEAD operation. */ +psa_status_t psa_aead_finish(psa_aead_operation_t *operation, + uint8_t *ciphertext_external, + size_t ciphertext_size, + size_t *ciphertext_length, + uint8_t *tag_external, + size_t tag_size, + size_t *tag_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + LOCAL_OUTPUT_DECLARE(ciphertext_external, ciphertext); + LOCAL_OUTPUT_DECLARE(tag_external, tag); + + LOCAL_OUTPUT_ALLOC(ciphertext_external, ciphertext_size, ciphertext); + LOCAL_OUTPUT_ALLOC(tag_external, tag_size, tag); + + *ciphertext_length = 0; + *tag_length = tag_size; + + status = psa_aead_final_checks(operation); + if (status != PSA_SUCCESS) { + goto exit; + } + + if (!operation->is_encrypt) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + status = psa_driver_wrapper_aead_finish(operation, ciphertext, + ciphertext_size, + ciphertext_length, + tag, tag_size, tag_length); + +exit: + + + /* In case the operation fails and the user fails to check for failure or + * the zero tag size, make sure the tag is set to something implausible. + * Even if the operation succeeds, make sure we clear the rest of the + * buffer to prevent potential leakage of anything previously placed in + * the same buffer.*/ + psa_wipe_tag_output_buffer(tag, status, tag_size, *tag_length); + + psa_aead_abort(operation); + + LOCAL_OUTPUT_FREE(ciphertext_external, ciphertext); + LOCAL_OUTPUT_FREE(tag_external, tag); + + return status; +} + +/* Finish authenticating and decrypting a message in a multipart AEAD + operation.*/ +psa_status_t psa_aead_verify(psa_aead_operation_t *operation, + uint8_t *plaintext_external, + size_t plaintext_size, + size_t *plaintext_length, + const uint8_t *tag_external, + size_t tag_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + LOCAL_OUTPUT_DECLARE(plaintext_external, plaintext); + LOCAL_INPUT_DECLARE(tag_external, tag); + + LOCAL_OUTPUT_ALLOC(plaintext_external, plaintext_size, plaintext); + LOCAL_INPUT_ALLOC(tag_external, tag_length, tag); + + *plaintext_length = 0; + + status = psa_aead_final_checks(operation); + if (status != PSA_SUCCESS) { + goto exit; + } + + if (operation->is_encrypt) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + status = psa_driver_wrapper_aead_verify(operation, plaintext, + plaintext_size, + plaintext_length, + tag, tag_length); + +exit: + psa_aead_abort(operation); + + LOCAL_OUTPUT_FREE(plaintext_external, plaintext); + LOCAL_INPUT_FREE(tag_external, tag); + + return status; +} + +/* Abort an AEAD operation. */ +psa_status_t psa_aead_abort(psa_aead_operation_t *operation) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (operation->id == 0) { + /* The object has (apparently) been initialized but it is not (yet) + * in use. It's ok to call abort on such an object, and there's + * nothing to do. */ + return PSA_SUCCESS; + } + + status = psa_driver_wrapper_aead_abort(operation); + + memset(operation, 0, sizeof(*operation)); + + return status; +} + +/****************************************************************/ +/* Key derivation: output generation */ +/****************************************************************/ + +#if defined(BUILTIN_ALG_ANY_HKDF) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS) || \ + defined(PSA_HAVE_SOFT_PBKDF2) +#define AT_LEAST_ONE_BUILTIN_KDF +#endif /* At least one builtin KDF */ + +#if defined(BUILTIN_ALG_ANY_HKDF) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) + +/** Internal helper to set up an HMAC operation with a key passed directly. + * + * \param[in,out] operation A MAC operation object. It does not need to + * be initialized. + * \param hash_alg The hash algorithm used for HMAC. + * \param hmac_key The HMAC key. + * \param hmac_key_length Length of \p hmac_key in bytes. + * + * \return A PSA status code. + */ +static psa_status_t psa_key_derivation_start_hmac( + psa_mac_operation_t *operation, + psa_algorithm_t hash_alg, + const uint8_t *hmac_key, + size_t hmac_key_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_set_key_type(&attributes, PSA_KEY_TYPE_HMAC); + psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(hmac_key_length)); + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH); + + /* Make sure the whole the operation is zeroed. + * It isn't enough to require the caller to initialize operation to + * PSA_MAC_OPERATION_INIT, since one field is a union and initializing + * a union does not necessarily initialize all of its members. + * psa_mac_setup() would handle PSA_MAC_OPERATION_INIT, but here we + * bypass it and call lower-level functions directly. */ + memset(operation, 0, sizeof(*operation)); + + operation->is_sign = 1; + operation->mac_size = PSA_HASH_LENGTH(hash_alg); + + status = psa_driver_wrapper_mac_sign_setup(operation, + &attributes, + hmac_key, hmac_key_length, + PSA_ALG_HMAC(hash_alg)); + + psa_reset_key_attributes(&attributes); + return status; +} +#endif /* KDF algorithms reliant on HMAC */ + +#define HKDF_STATE_INIT 0 /* no input yet */ +#define HKDF_STATE_STARTED 1 /* got salt */ +#define HKDF_STATE_KEYED 2 /* got key */ +#define HKDF_STATE_OUTPUT 3 /* output started */ + +static psa_algorithm_t psa_key_derivation_get_kdf_alg( + const psa_key_derivation_operation_t *operation) +{ + if (PSA_ALG_IS_KEY_AGREEMENT(operation->alg)) { + return PSA_ALG_KEY_AGREEMENT_GET_KDF(operation->alg); + } else { + return operation->alg; + } +} + +psa_status_t psa_key_derivation_abort(psa_key_derivation_operation_t *operation) +{ + psa_status_t status = PSA_SUCCESS; + psa_algorithm_t kdf_alg = psa_key_derivation_get_kdf_alg(operation); + if (kdf_alg == 0) { + /* The object has (apparently) been initialized but it is not + * in use. It's ok to call abort on such an object, and there's + * nothing to do. */ + } else +#if defined(BUILTIN_ALG_ANY_HKDF) + if (PSA_ALG_IS_ANY_HKDF(kdf_alg)) { + mbedtls_free(operation->ctx.hkdf.info); + status = psa_mac_abort(&operation->ctx.hkdf.hmac); + } else +#endif /* BUILTIN_ALG_ANY_HKDF */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) + if (PSA_ALG_IS_TLS12_PRF(kdf_alg) || + /* TLS-1.2 PSK-to-MS KDF uses the same core as TLS-1.2 PRF */ + PSA_ALG_IS_TLS12_PSK_TO_MS(kdf_alg)) { + if (operation->ctx.tls12_prf.secret != NULL) { + mbedtls_zeroize_and_free(operation->ctx.tls12_prf.secret, + operation->ctx.tls12_prf.secret_length); + } + + if (operation->ctx.tls12_prf.seed != NULL) { + mbedtls_zeroize_and_free(operation->ctx.tls12_prf.seed, + operation->ctx.tls12_prf.seed_length); + } + + if (operation->ctx.tls12_prf.label != NULL) { + mbedtls_zeroize_and_free(operation->ctx.tls12_prf.label, + operation->ctx.tls12_prf.label_length); + } +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) + if (operation->ctx.tls12_prf.other_secret != NULL) { + mbedtls_zeroize_and_free(operation->ctx.tls12_prf.other_secret, + operation->ctx.tls12_prf.other_secret_length); + } +#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */ + status = PSA_SUCCESS; + + /* We leave the fields Ai and output_block to be erased safely by the + * mbedtls_platform_zeroize() in the end of this function. */ + } else +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS) + if (kdf_alg == PSA_ALG_TLS12_ECJPAKE_TO_PMS) { + mbedtls_platform_zeroize(operation->ctx.tls12_ecjpake_to_pms.data, + sizeof(operation->ctx.tls12_ecjpake_to_pms.data)); + } else +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS) */ +#if defined(PSA_HAVE_SOFT_PBKDF2) + if (PSA_ALG_IS_PBKDF2(kdf_alg)) { + if (operation->ctx.pbkdf2.salt != NULL) { + mbedtls_zeroize_and_free(operation->ctx.pbkdf2.salt, + operation->ctx.pbkdf2.salt_length); + } + + status = PSA_SUCCESS; + } else +#endif /* defined(PSA_HAVE_SOFT_PBKDF2) */ + { + status = PSA_ERROR_BAD_STATE; + } + mbedtls_platform_zeroize(operation, sizeof(*operation)); + return status; +} + +psa_status_t psa_key_derivation_get_capacity(const psa_key_derivation_operation_t *operation, + size_t *capacity) +{ + if (operation->alg == 0) { + /* This is a blank key derivation operation. */ + return PSA_ERROR_BAD_STATE; + } + + *capacity = operation->capacity; + return PSA_SUCCESS; +} + +psa_status_t psa_key_derivation_set_capacity(psa_key_derivation_operation_t *operation, + size_t capacity) +{ + if (operation->alg == 0) { + return PSA_ERROR_BAD_STATE; + } + if (capacity > operation->capacity) { + return PSA_ERROR_INVALID_ARGUMENT; + } + operation->capacity = capacity; + return PSA_SUCCESS; +} + +#if defined(BUILTIN_ALG_ANY_HKDF) +/* Read some bytes from an HKDF-based operation. */ +static psa_status_t psa_key_derivation_hkdf_read(psa_hkdf_key_derivation_t *hkdf, + psa_algorithm_t kdf_alg, + uint8_t *output, + size_t output_length) +{ + psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH(kdf_alg); + uint8_t hash_length = PSA_HASH_LENGTH(hash_alg); + size_t hmac_output_length; + psa_status_t status; +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT) + const uint8_t last_block = PSA_ALG_IS_HKDF_EXTRACT(kdf_alg) ? 0 : 0xff; +#else + const uint8_t last_block = 0xff; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT */ + + if (hkdf->state < HKDF_STATE_KEYED || + (!hkdf->info_set +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT) + && !PSA_ALG_IS_HKDF_EXTRACT(kdf_alg) +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT */ + )) { + return PSA_ERROR_BAD_STATE; + } + hkdf->state = HKDF_STATE_OUTPUT; + + while (output_length != 0) { + /* Copy what remains of the current block */ + uint8_t n = hash_length - hkdf->offset_in_block; + if (n > output_length) { + n = (uint8_t) output_length; + } + memcpy(output, hkdf->output_block + hkdf->offset_in_block, n); + output += n; + output_length -= n; + hkdf->offset_in_block += n; + if (output_length == 0) { + break; + } + /* We can't be wanting more output after the last block, otherwise + * the capacity check in psa_key_derivation_output_bytes() would have + * prevented this call. It could happen only if the operation + * object was corrupted or if this function is called directly + * inside the library. */ + if (hkdf->block_number == last_block) { + return PSA_ERROR_BAD_STATE; + } + + /* We need a new block */ + ++hkdf->block_number; + hkdf->offset_in_block = 0; + + status = psa_key_derivation_start_hmac(&hkdf->hmac, + hash_alg, + hkdf->prk, + hash_length); + if (status != PSA_SUCCESS) { + return status; + } + + if (hkdf->block_number != 1) { + status = psa_mac_update(&hkdf->hmac, + hkdf->output_block, + hash_length); + if (status != PSA_SUCCESS) { + return status; + } + } + status = psa_mac_update(&hkdf->hmac, + hkdf->info, + hkdf->info_length); + if (status != PSA_SUCCESS) { + return status; + } + status = psa_mac_update(&hkdf->hmac, + &hkdf->block_number, 1); + if (status != PSA_SUCCESS) { + return status; + } + status = psa_mac_sign_finish(&hkdf->hmac, + hkdf->output_block, + sizeof(hkdf->output_block), + &hmac_output_length); + if (status != PSA_SUCCESS) { + return status; + } + } + + return PSA_SUCCESS; +} +#endif /* BUILTIN_ALG_ANY_HKDF */ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) +static psa_status_t psa_key_derivation_tls12_prf_generate_next_block( + psa_tls12_prf_key_derivation_t *tls12_prf, + psa_algorithm_t alg) +{ + psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH(alg); + uint8_t hash_length = PSA_HASH_LENGTH(hash_alg); + psa_mac_operation_t hmac; + size_t hmac_output_length; + psa_status_t status, cleanup_status; + + /* We can't be wanting more output after block 0xff, otherwise + * the capacity check in psa_key_derivation_output_bytes() would have + * prevented this call. It could happen only if the operation + * object was corrupted or if this function is called directly + * inside the library. */ + if (tls12_prf->block_number == 0xff) { + return PSA_ERROR_CORRUPTION_DETECTED; + } + + /* We need a new block */ + ++tls12_prf->block_number; + tls12_prf->left_in_block = hash_length; + + /* Recall the definition of the TLS-1.2-PRF from RFC 5246: + * + * PRF(secret, label, seed) = P_(secret, label + seed) + * + * P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + + * HMAC_hash(secret, A(2) + seed) + + * HMAC_hash(secret, A(3) + seed) + ... + * + * A(0) = seed + * A(i) = HMAC_hash(secret, A(i-1)) + * + * The `psa_tls12_prf_key_derivation` structure saves the block + * `HMAC_hash(secret, A(i) + seed)` from which the output + * is currently extracted as `output_block` and where i is + * `block_number`. + */ + + status = psa_key_derivation_start_hmac(&hmac, + hash_alg, + tls12_prf->secret, + tls12_prf->secret_length); + if (status != PSA_SUCCESS) { + goto cleanup; + } + + /* Calculate A(i) where i = tls12_prf->block_number. */ + if (tls12_prf->block_number == 1) { + /* A(1) = HMAC_hash(secret, A(0)), where A(0) = seed. (The RFC overloads + * the variable seed and in this instance means it in the context of the + * P_hash function, where seed = label + seed.) */ + status = psa_mac_update(&hmac, + tls12_prf->label, + tls12_prf->label_length); + if (status != PSA_SUCCESS) { + goto cleanup; + } + status = psa_mac_update(&hmac, + tls12_prf->seed, + tls12_prf->seed_length); + if (status != PSA_SUCCESS) { + goto cleanup; + } + } else { + /* A(i) = HMAC_hash(secret, A(i-1)) */ + status = psa_mac_update(&hmac, tls12_prf->Ai, hash_length); + if (status != PSA_SUCCESS) { + goto cleanup; + } + } + + status = psa_mac_sign_finish(&hmac, + tls12_prf->Ai, hash_length, + &hmac_output_length); + if (hmac_output_length != hash_length) { + status = PSA_ERROR_CORRUPTION_DETECTED; + } + if (status != PSA_SUCCESS) { + goto cleanup; + } + + /* Calculate HMAC_hash(secret, A(i) + label + seed). */ + status = psa_key_derivation_start_hmac(&hmac, + hash_alg, + tls12_prf->secret, + tls12_prf->secret_length); + if (status != PSA_SUCCESS) { + goto cleanup; + } + status = psa_mac_update(&hmac, tls12_prf->Ai, hash_length); + if (status != PSA_SUCCESS) { + goto cleanup; + } + status = psa_mac_update(&hmac, tls12_prf->label, tls12_prf->label_length); + if (status != PSA_SUCCESS) { + goto cleanup; + } + status = psa_mac_update(&hmac, tls12_prf->seed, tls12_prf->seed_length); + if (status != PSA_SUCCESS) { + goto cleanup; + } + status = psa_mac_sign_finish(&hmac, + tls12_prf->output_block, hash_length, + &hmac_output_length); + if (status != PSA_SUCCESS) { + goto cleanup; + } + + +cleanup: + cleanup_status = psa_mac_abort(&hmac); + if (status == PSA_SUCCESS && cleanup_status != PSA_SUCCESS) { + status = cleanup_status; + } + + return status; +} + +static psa_status_t psa_key_derivation_tls12_prf_read( + psa_tls12_prf_key_derivation_t *tls12_prf, + psa_algorithm_t alg, + uint8_t *output, + size_t output_length) +{ + psa_algorithm_t hash_alg = PSA_ALG_TLS12_PRF_GET_HASH(alg); + uint8_t hash_length = PSA_HASH_LENGTH(hash_alg); + psa_status_t status; + uint8_t offset, length; + + switch (tls12_prf->state) { + case PSA_TLS12_PRF_STATE_LABEL_SET: + tls12_prf->state = PSA_TLS12_PRF_STATE_OUTPUT; + break; + case PSA_TLS12_PRF_STATE_OUTPUT: + break; + default: + return PSA_ERROR_BAD_STATE; + } + + while (output_length != 0) { + /* Check if we have fully processed the current block. */ + if (tls12_prf->left_in_block == 0) { + status = psa_key_derivation_tls12_prf_generate_next_block(tls12_prf, + alg); + if (status != PSA_SUCCESS) { + return status; + } + + continue; + } + + if (tls12_prf->left_in_block > output_length) { + length = (uint8_t) output_length; + } else { + length = tls12_prf->left_in_block; + } + + offset = hash_length - tls12_prf->left_in_block; + memcpy(output, tls12_prf->output_block + offset, length); + output += length; + output_length -= length; + tls12_prf->left_in_block -= length; + } + + return PSA_SUCCESS; +} +#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF || + * MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS) +static psa_status_t psa_key_derivation_tls12_ecjpake_to_pms_read( + psa_tls12_ecjpake_to_pms_t *ecjpake, + uint8_t *output, + size_t output_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + size_t output_size = 0; + + if (output_length != 32) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + status = psa_hash_compute(PSA_ALG_SHA_256, ecjpake->data, + PSA_TLS12_ECJPAKE_TO_PMS_DATA_SIZE, output, output_length, + &output_size); + if (status != PSA_SUCCESS) { + return status; + } + + if (output_size != output_length) { + return PSA_ERROR_GENERIC_ERROR; + } + + return PSA_SUCCESS; +} +#endif + +#if defined(PSA_HAVE_SOFT_PBKDF2) +static psa_status_t psa_key_derivation_pbkdf2_generate_block( + psa_pbkdf2_key_derivation_t *pbkdf2, + psa_algorithm_t prf_alg, + uint8_t prf_output_length, + psa_key_attributes_t *attributes) +{ + psa_status_t status; + psa_mac_operation_t mac_operation; + /* Make sure the whole the operation is zeroed. + * PSA_MAC_OPERATION_INIT does not necessarily do it fully, + * since one field is a union and initializing a union does not + * necessarily initialize all of its members. + * psa_mac_setup() would do it, but here we bypass it and call + * lower-level functions directly. */ + memset(&mac_operation, 0, sizeof(mac_operation)); + size_t mac_output_length; + uint8_t U_i[PSA_MAC_MAX_SIZE]; + uint8_t *U_accumulator = pbkdf2->output_block; + uint64_t i; + uint8_t block_counter[4]; + + mac_operation.is_sign = 1; + mac_operation.mac_size = prf_output_length; + MBEDTLS_PUT_UINT32_BE(pbkdf2->block_number, block_counter, 0); + + status = psa_driver_wrapper_mac_sign_setup(&mac_operation, + attributes, + pbkdf2->password, + pbkdf2->password_length, + prf_alg); + if (status != PSA_SUCCESS) { + goto cleanup; + } + status = psa_mac_update(&mac_operation, pbkdf2->salt, pbkdf2->salt_length); + if (status != PSA_SUCCESS) { + goto cleanup; + } + status = psa_mac_update(&mac_operation, block_counter, sizeof(block_counter)); + if (status != PSA_SUCCESS) { + goto cleanup; + } + status = psa_mac_sign_finish(&mac_operation, U_i, sizeof(U_i), + &mac_output_length); + if (status != PSA_SUCCESS) { + goto cleanup; + } + + if (mac_output_length != prf_output_length) { + status = PSA_ERROR_CORRUPTION_DETECTED; + goto cleanup; + } + + memcpy(U_accumulator, U_i, prf_output_length); + + for (i = 1; i < pbkdf2->input_cost; i++) { + /* We are passing prf_output_length as mac_size because the driver + * function directly sets mac_output_length as mac_size upon success. + * See https://github.com/Mbed-TLS/mbedtls/issues/7801 */ + status = psa_driver_wrapper_mac_compute(attributes, + pbkdf2->password, + pbkdf2->password_length, + prf_alg, U_i, prf_output_length, + U_i, prf_output_length, + &mac_output_length); + if (status != PSA_SUCCESS) { + goto cleanup; + } + + mbedtls_xor(U_accumulator, U_accumulator, U_i, prf_output_length); + } + +cleanup: + /* Zeroise buffers to clear sensitive data from memory. */ + mbedtls_platform_zeroize(U_i, PSA_MAC_MAX_SIZE); + return status; +} + +static psa_status_t psa_key_derivation_pbkdf2_read( + psa_pbkdf2_key_derivation_t *pbkdf2, + psa_algorithm_t kdf_alg, + uint8_t *output, + size_t output_length) +{ + psa_status_t status; + psa_algorithm_t prf_alg; + uint8_t prf_output_length; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(pbkdf2->password_length)); + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_MESSAGE); + + if (PSA_ALG_IS_PBKDF2_HMAC(kdf_alg)) { + prf_alg = PSA_ALG_HMAC(PSA_ALG_PBKDF2_HMAC_GET_HASH(kdf_alg)); + prf_output_length = PSA_HASH_LENGTH(prf_alg); + psa_set_key_type(&attributes, PSA_KEY_TYPE_HMAC); + } else if (kdf_alg == PSA_ALG_PBKDF2_AES_CMAC_PRF_128) { + prf_alg = PSA_ALG_CMAC; + prf_output_length = PSA_MAC_LENGTH(PSA_KEY_TYPE_AES, 128U, PSA_ALG_CMAC); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + } else { + return PSA_ERROR_INVALID_ARGUMENT; + } + + switch (pbkdf2->state) { + case PSA_PBKDF2_STATE_PASSWORD_SET: + /* Initially we need a new block so bytes_used is equal to block size*/ + pbkdf2->bytes_used = prf_output_length; + pbkdf2->state = PSA_PBKDF2_STATE_OUTPUT; + break; + case PSA_PBKDF2_STATE_OUTPUT: + break; + default: + return PSA_ERROR_BAD_STATE; + } + + while (output_length != 0) { + uint8_t n = prf_output_length - pbkdf2->bytes_used; + if (n > output_length) { + n = (uint8_t) output_length; + } + memcpy(output, pbkdf2->output_block + pbkdf2->bytes_used, n); + output += n; + output_length -= n; + pbkdf2->bytes_used += n; + + if (output_length == 0) { + break; + } + + /* We need a new block */ + pbkdf2->bytes_used = 0; + pbkdf2->block_number++; + + status = psa_key_derivation_pbkdf2_generate_block(pbkdf2, prf_alg, + prf_output_length, + &attributes); + if (status != PSA_SUCCESS) { + return status; + } + } + + return PSA_SUCCESS; +} +#endif /* PSA_HAVE_SOFT_PBKDF2 */ + +psa_status_t psa_key_derivation_output_bytes( + psa_key_derivation_operation_t *operation, + uint8_t *output_external, + size_t output_length) +{ + psa_status_t status; + LOCAL_OUTPUT_DECLARE(output_external, output); + + psa_algorithm_t kdf_alg = psa_key_derivation_get_kdf_alg(operation); + + if (operation->alg == 0) { + /* This is a blank operation. */ + return PSA_ERROR_BAD_STATE; + } + + if (output_length == 0 && operation->capacity == 0) { + /* Edge case: this is a finished operation, and 0 bytes + * were requested. The right error in this case could + * be either INSUFFICIENT_CAPACITY or BAD_STATE. Return + * INSUFFICIENT_CAPACITY, which is right for a finished + * operation, for consistency with the case when + * output_length > 0. */ + return PSA_ERROR_INSUFFICIENT_DATA; + } + + LOCAL_OUTPUT_ALLOC(output_external, output_length, output); + if (output_length > operation->capacity) { + operation->capacity = 0; + /* Go through the error path to wipe all confidential data now + * that the operation object is useless. */ + status = PSA_ERROR_INSUFFICIENT_DATA; + goto exit; + } + + operation->capacity -= output_length; + +#if defined(BUILTIN_ALG_ANY_HKDF) + if (PSA_ALG_IS_ANY_HKDF(kdf_alg)) { + status = psa_key_derivation_hkdf_read(&operation->ctx.hkdf, kdf_alg, + output, output_length); + } else +#endif /* BUILTIN_ALG_ANY_HKDF */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) + if (PSA_ALG_IS_TLS12_PRF(kdf_alg) || + PSA_ALG_IS_TLS12_PSK_TO_MS(kdf_alg)) { + status = psa_key_derivation_tls12_prf_read(&operation->ctx.tls12_prf, + kdf_alg, output, + output_length); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF || + * MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS) + if (kdf_alg == PSA_ALG_TLS12_ECJPAKE_TO_PMS) { + status = psa_key_derivation_tls12_ecjpake_to_pms_read( + &operation->ctx.tls12_ecjpake_to_pms, output, output_length); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS */ +#if defined(PSA_HAVE_SOFT_PBKDF2) + if (PSA_ALG_IS_PBKDF2(kdf_alg)) { + status = psa_key_derivation_pbkdf2_read(&operation->ctx.pbkdf2, kdf_alg, + output, output_length); + } else +#endif /* PSA_HAVE_SOFT_PBKDF2 */ + + { + (void) kdf_alg; + status = PSA_ERROR_BAD_STATE; + LOCAL_OUTPUT_FREE(output_external, output); + + return status; + } + +exit: + if (status != PSA_SUCCESS) { + /* Preserve the algorithm upon errors, but clear all sensitive state. + * This allows us to differentiate between exhausted operations and + * blank operations, so we can return PSA_ERROR_BAD_STATE on blank + * operations. */ + psa_algorithm_t alg = operation->alg; + psa_key_derivation_abort(operation); + operation->alg = alg; + if (output != NULL) { + memset(output, '!', output_length); + } + } + + LOCAL_OUTPUT_FREE(output_external, output); + return status; +} + +/* + * ECC keys on a Weierstrass elliptic curve require the generation + * of a private key which is an integer + * in the range [1, N - 1], where N is the boundary of the private key domain: + * N is the prime p for Diffie-Hellman, or the order of the + * curve’s base point for ECC. + * + * Let m be the bit size of N, such that 2^m > N >= 2^(m-1). + * This function generates the private key using the following process: + * + * 1. Draw a byte string of length ceiling(m/8) bytes. + * 2. If m is not a multiple of 8, set the most significant + * (8 * ceiling(m/8) - m) bits of the first byte in the string to zero. + * 3. Convert the string to integer k by decoding it as a big-endian byte string. + * 4. If k > N - 2, discard the result and return to step 1. + * 5. Output k + 1 as the private key. + * + * This method allows compliance to NIST standards, specifically the methods titled + * Key-Pair Generation by Testing Candidates in the following publications: + * - NIST Special Publication 800-56A: Recommendation for Pair-Wise Key-Establishment + * Schemes Using Discrete Logarithm Cryptography [SP800-56A] §5.6.1.1.4 for + * Diffie-Hellman keys. + * + * - [SP800-56A] §5.6.1.2.2 or FIPS Publication 186-4: Digital Signature + * Standard (DSS) [FIPS186-4] §B.4.2 for elliptic curve keys. + * + * Note: Function allocates memory for *data buffer, so given *data should be + * always NULL. + */ +#if defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE) +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_DERIVE) +static psa_status_t psa_generate_derived_ecc_key_weierstrass_helper( + psa_key_slot_t *slot, + size_t bits, + psa_key_derivation_operation_t *operation, + uint8_t **data + ) +{ + unsigned key_out_of_range = 1; + mbedtls_mpi k; + mbedtls_mpi diff_N_2; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + size_t m; + size_t m_bytes = 0; + + mbedtls_mpi_init(&k); + mbedtls_mpi_init(&diff_N_2); + + psa_ecc_family_t curve = PSA_KEY_TYPE_ECC_GET_FAMILY( + slot->attr.type); + mbedtls_ecp_group_id grp_id = + mbedtls_ecc_group_from_psa(curve, bits); + + if (grp_id == MBEDTLS_ECP_DP_NONE) { + ret = MBEDTLS_ERR_ASN1_INVALID_DATA; + goto cleanup; + } + + mbedtls_ecp_group ecp_group; + mbedtls_ecp_group_init(&ecp_group); + + MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&ecp_group, grp_id)); + + /* N is the boundary of the private key domain (ecp_group.N). */ + /* Let m be the bit size of N. */ + m = ecp_group.nbits; + + m_bytes = PSA_BITS_TO_BYTES(m); + + /* Calculate N - 2 - it will be needed later. */ + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&diff_N_2, &ecp_group.N, 2)); + + /* Note: This function is always called with *data == NULL and it + * allocates memory for the data buffer. */ + *data = mbedtls_calloc(1, m_bytes); + if (*data == NULL) { + ret = MBEDTLS_ERR_ASN1_ALLOC_FAILED; + goto cleanup; + } + + while (key_out_of_range) { + /* 1. Draw a byte string of length ceiling(m/8) bytes. */ + if ((status = psa_key_derivation_output_bytes(operation, *data, m_bytes)) != 0) { + goto cleanup; + } + + /* 2. If m is not a multiple of 8 */ + if (m % 8 != 0) { + /* Set the most significant + * (8 * ceiling(m/8) - m) bits of the first byte in + * the string to zero. + */ + uint8_t clear_bit_mask = (1 << (m % 8)) - 1; + (*data)[0] &= clear_bit_mask; + } + + /* 3. Convert the string to integer k by decoding it as a + * big-endian byte string. + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&k, *data, m_bytes)); + + /* 4. If k > N - 2, discard the result and return to step 1. + * Result of comparison is returned. When it indicates error + * then this function is called again. + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_lt_mpi_ct(&diff_N_2, &k, &key_out_of_range)); + } + + /* 5. Output k + 1 as the private key. */ + MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&k, &k, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&k, *data, m_bytes)); +cleanup: + if (ret != 0) { + status = mbedtls_to_psa_error(ret); + } + if (status != PSA_SUCCESS) { + mbedtls_zeroize_and_free(*data, m_bytes); + *data = NULL; + } + mbedtls_mpi_free(&k); + mbedtls_mpi_free(&diff_N_2); + return status; +} + +/* ECC keys on a Montgomery elliptic curve draws a byte string whose length + * is determined by the curve, and sets the mandatory bits accordingly. That is: + * + * - Curve25519 (PSA_ECC_FAMILY_MONTGOMERY, 255 bits): + * draw a 32-byte string and process it as specified in + * Elliptic Curves for Security [RFC7748] §5. + * + * - Curve448 (PSA_ECC_FAMILY_MONTGOMERY, 448 bits): + * draw a 56-byte string and process it as specified in [RFC7748] §5. + * + * Note: Function allocates memory for *data buffer, so given *data should be + * always NULL. + */ + +static psa_status_t psa_generate_derived_ecc_key_montgomery_helper( + size_t bits, + psa_key_derivation_operation_t *operation, + uint8_t **data + ) +{ + size_t output_length; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + switch (bits) { + case 255: + output_length = 32; + break; + case 448: + output_length = 56; + break; + default: + return PSA_ERROR_INVALID_ARGUMENT; + break; + } + + *data = mbedtls_calloc(1, output_length); + + if (*data == NULL) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + + status = psa_key_derivation_output_bytes(operation, *data, output_length); + + if (status != PSA_SUCCESS) { + return status; + } + + switch (bits) { + case 255: + (*data)[0] &= 248; + (*data)[31] &= 127; + (*data)[31] |= 64; + break; + case 448: + (*data)[0] &= 252; + (*data)[55] |= 128; + break; + default: + return PSA_ERROR_CORRUPTION_DETECTED; + break; + } + + return status; +} +#else /* MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_DERIVE */ +static psa_status_t psa_generate_derived_ecc_key_weierstrass_helper( + psa_key_slot_t *slot, size_t bits, + psa_key_derivation_operation_t *operation, uint8_t **data) +{ + (void) slot; + (void) bits; + (void) operation; + (void) data; + return PSA_ERROR_NOT_SUPPORTED; +} + +static psa_status_t psa_generate_derived_ecc_key_montgomery_helper( + size_t bits, psa_key_derivation_operation_t *operation, uint8_t **data) +{ + (void) bits; + (void) operation; + (void) data; + return PSA_ERROR_NOT_SUPPORTED; +} +#endif /* MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_DERIVE */ +#endif /* PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE */ + +static psa_status_t psa_generate_derived_key_internal( + psa_key_slot_t *slot, + size_t bits, + psa_key_derivation_operation_t *operation) +{ + uint8_t *data = NULL; + size_t bytes = PSA_BITS_TO_BYTES(bits); + size_t storage_size = bytes; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (PSA_KEY_TYPE_IS_PUBLIC_KEY(slot->attr.type)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + +#if defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_DERIVE) + if (PSA_KEY_TYPE_IS_ECC(slot->attr.type)) { + psa_ecc_family_t curve = PSA_KEY_TYPE_ECC_GET_FAMILY(slot->attr.type); + if (PSA_ECC_FAMILY_IS_WEIERSTRASS(curve)) { + /* Weierstrass elliptic curve */ + status = psa_generate_derived_ecc_key_weierstrass_helper(slot, bits, operation, &data); + if (status != PSA_SUCCESS) { + goto exit; + } + } else { + /* Montgomery elliptic curve */ + status = psa_generate_derived_ecc_key_montgomery_helper(bits, operation, &data); + if (status != PSA_SUCCESS) { + goto exit; + } + } + } else +#endif /* defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE) || + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_DERIVE) */ + if (key_type_is_raw_bytes(slot->attr.type)) { + if (bits % 8 != 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + data = mbedtls_calloc(1, bytes); + if (data == NULL) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + + status = psa_key_derivation_output_bytes(operation, data, bytes); + if (status != PSA_SUCCESS) { + goto exit; + } + } else { + return PSA_ERROR_NOT_SUPPORTED; + } + + slot->attr.bits = (psa_key_bits_t) bits; + + if (psa_key_lifetime_is_external(slot->attr.lifetime)) { + status = psa_driver_wrapper_get_key_buffer_size(&slot->attr, + &storage_size); + if (status != PSA_SUCCESS) { + goto exit; + } + } + status = psa_allocate_buffer_to_slot(slot, storage_size); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_driver_wrapper_import_key(&slot->attr, + data, bytes, + slot->key.data, + slot->key.bytes, + &slot->key.bytes, &bits); + if (bits != slot->attr.bits) { + status = PSA_ERROR_INVALID_ARGUMENT; + } + +exit: + mbedtls_zeroize_and_free(data, bytes); + return status; +} + +static const psa_custom_key_parameters_t default_custom_production = + PSA_CUSTOM_KEY_PARAMETERS_INIT; + +int psa_custom_key_parameters_are_default( + const psa_custom_key_parameters_t *custom, + size_t custom_data_length) +{ + if (custom->flags != 0) { + return 0; + } + if (custom_data_length != 0) { + return 0; + } + return 1; +} + +psa_status_t psa_key_derivation_output_key_custom( + const psa_key_attributes_t *attributes, + psa_key_derivation_operation_t *operation, + const psa_custom_key_parameters_t *custom, + const uint8_t *custom_data, + size_t custom_data_length, + mbedtls_svc_key_id_t *key) +{ + psa_status_t status; + psa_key_slot_t *slot = NULL; + + *key = MBEDTLS_SVC_KEY_ID_INIT; + + /* Reject any attempt to create a zero-length key so that we don't + * risk tripping up later, e.g. on a malloc(0) that returns NULL. */ + if (psa_get_key_bits(attributes) == 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + (void) custom_data; /* We only accept 0-length data */ + if (!psa_custom_key_parameters_are_default(custom, custom_data_length)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (operation->alg == PSA_ALG_NONE) { + return PSA_ERROR_BAD_STATE; + } + + if (!operation->can_output_key) { + return PSA_ERROR_NOT_PERMITTED; + } + + status = psa_start_key_creation(attributes, &slot); + if (status == PSA_SUCCESS) { + status = psa_generate_derived_key_internal(slot, + attributes->bits, + operation); + } + if (status == PSA_SUCCESS) { + status = psa_finish_key_creation(slot, key); + } + if (status != PSA_SUCCESS) { + psa_fail_key_creation(slot); + } + + return status; +} + +psa_status_t psa_key_derivation_output_key( + const psa_key_attributes_t *attributes, + psa_key_derivation_operation_t *operation, + mbedtls_svc_key_id_t *key) +{ + return psa_key_derivation_output_key_custom(attributes, operation, + &default_custom_production, + NULL, 0, + key); +} + +psa_status_t psa_key_derivation_verify_bytes( + psa_key_derivation_operation_t *operation, + const uint8_t *expected, + size_t expected_length) +{ + (void) operation; + (void) expected; + (void) expected_length; + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_key_derivation_verify_key( + psa_key_derivation_operation_t *operation, + psa_key_id_t expected) +{ + (void) operation; + (void) expected; + return PSA_ERROR_NOT_SUPPORTED; +} + + +/****************************************************************/ +/* Key derivation: operation management */ +/****************************************************************/ + +#if defined(AT_LEAST_ONE_BUILTIN_KDF) +static int is_kdf_alg_supported(psa_algorithm_t kdf_alg) +{ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF) + if (PSA_ALG_IS_HKDF(kdf_alg)) { + return 1; + } +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT) + if (PSA_ALG_IS_HKDF_EXTRACT(kdf_alg)) { + return 1; + } +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND) + if (PSA_ALG_IS_HKDF_EXPAND(kdf_alg)) { + return 1; + } +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) + if (PSA_ALG_IS_TLS12_PRF(kdf_alg)) { + return 1; + } +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) + if (PSA_ALG_IS_TLS12_PSK_TO_MS(kdf_alg)) { + return 1; + } +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS) + if (kdf_alg == PSA_ALG_TLS12_ECJPAKE_TO_PMS) { + return 1; + } +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC) + if (PSA_ALG_IS_PBKDF2_HMAC(kdf_alg)) { + return 1; + } +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_AES_CMAC_PRF_128) + if (kdf_alg == PSA_ALG_PBKDF2_AES_CMAC_PRF_128) { + return 1; + } +#endif + return 0; +} + +static psa_status_t psa_hash_try_support(psa_algorithm_t alg) +{ + psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; + psa_status_t status = psa_hash_setup(&operation, alg); + psa_hash_abort(&operation); + return status; +} + +static psa_status_t psa_key_derivation_set_maximum_capacity( + psa_key_derivation_operation_t *operation, + psa_algorithm_t kdf_alg) +{ +#if defined(PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS) + if (kdf_alg == PSA_ALG_TLS12_ECJPAKE_TO_PMS) { + operation->capacity = PSA_HASH_LENGTH(PSA_ALG_SHA_256); + return PSA_SUCCESS; + } +#endif +#if defined(PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128) + if (kdf_alg == PSA_ALG_PBKDF2_AES_CMAC_PRF_128) { +#if (SIZE_MAX > UINT32_MAX) + operation->capacity = UINT32_MAX * (size_t) PSA_MAC_LENGTH( + PSA_KEY_TYPE_AES, + 128U, + PSA_ALG_CMAC); +#else + operation->capacity = SIZE_MAX; +#endif + return PSA_SUCCESS; + } +#endif /* PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 */ + + /* After this point, if kdf_alg is not valid then value of hash_alg may be + * invalid or meaningless but it does not affect this function */ + psa_algorithm_t hash_alg = PSA_ALG_GET_HASH(kdf_alg); + size_t hash_size = PSA_HASH_LENGTH(hash_alg); + if (hash_size == 0) { + return PSA_ERROR_NOT_SUPPORTED; + } + + /* Make sure that hash_alg is a supported hash algorithm. Otherwise + * we might fail later, which is somewhat unfriendly and potentially + * risk-prone. */ + psa_status_t status = psa_hash_try_support(hash_alg); + if (status != PSA_SUCCESS) { + return status; + } + +#if defined(PSA_WANT_ALG_HKDF) + if (PSA_ALG_IS_HKDF(kdf_alg)) { + operation->capacity = 255 * hash_size; + } else +#endif +#if defined(PSA_WANT_ALG_HKDF_EXTRACT) + if (PSA_ALG_IS_HKDF_EXTRACT(kdf_alg)) { + operation->capacity = hash_size; + } else +#endif +#if defined(PSA_WANT_ALG_HKDF_EXPAND) + if (PSA_ALG_IS_HKDF_EXPAND(kdf_alg)) { + operation->capacity = 255 * hash_size; + } else +#endif +#if defined(PSA_WANT_ALG_TLS12_PRF) + if (PSA_ALG_IS_TLS12_PRF(kdf_alg) && + (hash_alg == PSA_ALG_SHA_256 || hash_alg == PSA_ALG_SHA_384)) { + operation->capacity = SIZE_MAX; + } else +#endif +#if defined(PSA_WANT_ALG_TLS12_PSK_TO_MS) + if (PSA_ALG_IS_TLS12_PSK_TO_MS(kdf_alg) && + (hash_alg == PSA_ALG_SHA_256 || hash_alg == PSA_ALG_SHA_384)) { + /* Master Secret is always 48 bytes + * https://datatracker.ietf.org/doc/html/rfc5246.html#section-8.1 */ + operation->capacity = 48U; + } else +#endif +#if defined(PSA_WANT_ALG_PBKDF2_HMAC) + if (PSA_ALG_IS_PBKDF2_HMAC(kdf_alg)) { +#if (SIZE_MAX > UINT32_MAX) + operation->capacity = UINT32_MAX * hash_size; +#else + operation->capacity = SIZE_MAX; +#endif + } else +#endif /* PSA_WANT_ALG_PBKDF2_HMAC */ + { + (void) hash_size; + status = PSA_ERROR_NOT_SUPPORTED; + } + return status; +} + +static psa_status_t psa_key_derivation_setup_kdf( + psa_key_derivation_operation_t *operation, + psa_algorithm_t kdf_alg) +{ + /* Make sure that operation->ctx is properly zero-initialised. (Macro + * initialisers for this union leave some bytes unspecified.) */ + memset(&operation->ctx, 0, sizeof(operation->ctx)); + + /* Make sure that kdf_alg is a supported key derivation algorithm. */ + if (!is_kdf_alg_supported(kdf_alg)) { + return PSA_ERROR_NOT_SUPPORTED; + } + + psa_status_t status = psa_key_derivation_set_maximum_capacity(operation, + kdf_alg); + return status; +} + +static psa_status_t psa_key_agreement_try_support(psa_algorithm_t alg) +{ +#if defined(PSA_WANT_ALG_ECDH) + if (alg == PSA_ALG_ECDH) { + return PSA_SUCCESS; + } +#endif +#if defined(PSA_WANT_ALG_FFDH) + if (alg == PSA_ALG_FFDH) { + return PSA_SUCCESS; + } +#endif + (void) alg; + return PSA_ERROR_NOT_SUPPORTED; +} + +static int psa_key_derivation_allows_free_form_secret_input( + psa_algorithm_t kdf_alg) +{ +#if defined(PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS) + if (kdf_alg == PSA_ALG_TLS12_ECJPAKE_TO_PMS) { + return 0; + } +#endif + (void) kdf_alg; + return 1; +} +#endif /* AT_LEAST_ONE_BUILTIN_KDF */ + +psa_status_t psa_key_derivation_setup(psa_key_derivation_operation_t *operation, + psa_algorithm_t alg) +{ + psa_status_t status; + + if (operation->alg != 0) { + return PSA_ERROR_BAD_STATE; + } + + if (PSA_ALG_IS_RAW_KEY_AGREEMENT(alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } else if (PSA_ALG_IS_KEY_AGREEMENT(alg)) { +#if defined(AT_LEAST_ONE_BUILTIN_KDF) + psa_algorithm_t kdf_alg = PSA_ALG_KEY_AGREEMENT_GET_KDF(alg); + psa_algorithm_t ka_alg = PSA_ALG_KEY_AGREEMENT_GET_BASE(alg); + status = psa_key_agreement_try_support(ka_alg); + if (status != PSA_SUCCESS) { + return status; + } + if (!psa_key_derivation_allows_free_form_secret_input(kdf_alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + status = psa_key_derivation_setup_kdf(operation, kdf_alg); +#else + return PSA_ERROR_NOT_SUPPORTED; +#endif /* AT_LEAST_ONE_BUILTIN_KDF */ + } else if (PSA_ALG_IS_KEY_DERIVATION(alg)) { +#if defined(AT_LEAST_ONE_BUILTIN_KDF) + status = psa_key_derivation_setup_kdf(operation, alg); +#else + return PSA_ERROR_NOT_SUPPORTED; +#endif /* AT_LEAST_ONE_BUILTIN_KDF */ + } else { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (status == PSA_SUCCESS) { + operation->alg = alg; + } + return status; +} + +#if defined(BUILTIN_ALG_ANY_HKDF) +static psa_status_t psa_hkdf_input(psa_hkdf_key_derivation_t *hkdf, + psa_algorithm_t kdf_alg, + psa_key_derivation_step_t step, + const uint8_t *data, + size_t data_length) +{ + psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH(kdf_alg); + psa_status_t status; + switch (step) { + case PSA_KEY_DERIVATION_INPUT_SALT: +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND) + if (PSA_ALG_IS_HKDF_EXPAND(kdf_alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND */ + if (hkdf->state != HKDF_STATE_INIT) { + return PSA_ERROR_BAD_STATE; + } else { + status = psa_key_derivation_start_hmac(&hkdf->hmac, + hash_alg, + data, data_length); + if (status != PSA_SUCCESS) { + return status; + } + hkdf->state = HKDF_STATE_STARTED; + return PSA_SUCCESS; + } + case PSA_KEY_DERIVATION_INPUT_SECRET: +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND) + if (PSA_ALG_IS_HKDF_EXPAND(kdf_alg)) { + /* We shouldn't be in different state as HKDF_EXPAND only allows + * two inputs: SECRET (this case) and INFO which does not modify + * the state. It could happen only if the hkdf + * object was corrupted. */ + if (hkdf->state != HKDF_STATE_INIT) { + return PSA_ERROR_BAD_STATE; + } + + /* Allow only input that fits expected prk size */ + if (data_length != PSA_HASH_LENGTH(hash_alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + memcpy(hkdf->prk, data, data_length); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND */ + { + /* HKDF: If no salt was provided, use an empty salt. + * HKDF-EXTRACT: salt is mandatory. */ + if (hkdf->state == HKDF_STATE_INIT) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT) + if (PSA_ALG_IS_HKDF_EXTRACT(kdf_alg)) { + return PSA_ERROR_BAD_STATE; + } +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT */ + status = psa_key_derivation_start_hmac(&hkdf->hmac, + hash_alg, + NULL, 0); + if (status != PSA_SUCCESS) { + return status; + } + hkdf->state = HKDF_STATE_STARTED; + } + if (hkdf->state != HKDF_STATE_STARTED) { + return PSA_ERROR_BAD_STATE; + } + status = psa_mac_update(&hkdf->hmac, + data, data_length); + if (status != PSA_SUCCESS) { + return status; + } + status = psa_mac_sign_finish(&hkdf->hmac, + hkdf->prk, + sizeof(hkdf->prk), + &data_length); + if (status != PSA_SUCCESS) { + return status; + } + } + + hkdf->state = HKDF_STATE_KEYED; + hkdf->block_number = 0; +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT) + if (PSA_ALG_IS_HKDF_EXTRACT(kdf_alg)) { + /* The only block of output is the PRK. */ + memcpy(hkdf->output_block, hkdf->prk, PSA_HASH_LENGTH(hash_alg)); + hkdf->offset_in_block = 0; + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT */ + { + /* Block 0 is empty, and the next block will be + * generated by psa_key_derivation_hkdf_read(). */ + hkdf->offset_in_block = PSA_HASH_LENGTH(hash_alg); + } + + return PSA_SUCCESS; + case PSA_KEY_DERIVATION_INPUT_INFO: +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT) + if (PSA_ALG_IS_HKDF_EXTRACT(kdf_alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND) + if (PSA_ALG_IS_HKDF_EXPAND(kdf_alg) && + hkdf->state == HKDF_STATE_INIT) { + return PSA_ERROR_BAD_STATE; + } +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT */ + if (hkdf->state == HKDF_STATE_OUTPUT) { + return PSA_ERROR_BAD_STATE; + } + if (hkdf->info_set) { + return PSA_ERROR_BAD_STATE; + } + hkdf->info_length = data_length; + if (data_length != 0) { + hkdf->info = mbedtls_calloc(1, data_length); + if (hkdf->info == NULL) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + memcpy(hkdf->info, data, data_length); + } + hkdf->info_set = 1; + return PSA_SUCCESS; + default: + return PSA_ERROR_INVALID_ARGUMENT; + } +} +#endif /* BUILTIN_ALG_ANY_HKDF */ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) +static psa_status_t psa_tls12_prf_set_seed(psa_tls12_prf_key_derivation_t *prf, + const uint8_t *data, + size_t data_length) +{ + if (prf->state != PSA_TLS12_PRF_STATE_INIT) { + return PSA_ERROR_BAD_STATE; + } + + if (data_length != 0) { + prf->seed = mbedtls_calloc(1, data_length); + if (prf->seed == NULL) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + + memcpy(prf->seed, data, data_length); + prf->seed_length = data_length; + } + + prf->state = PSA_TLS12_PRF_STATE_SEED_SET; + + return PSA_SUCCESS; +} + +static psa_status_t psa_tls12_prf_set_key(psa_tls12_prf_key_derivation_t *prf, + const uint8_t *data, + size_t data_length) +{ + if (prf->state != PSA_TLS12_PRF_STATE_SEED_SET && + prf->state != PSA_TLS12_PRF_STATE_OTHER_KEY_SET) { + return PSA_ERROR_BAD_STATE; + } + + if (data_length != 0) { + prf->secret = mbedtls_calloc(1, data_length); + if (prf->secret == NULL) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + + memcpy(prf->secret, data, data_length); + prf->secret_length = data_length; + } + + prf->state = PSA_TLS12_PRF_STATE_KEY_SET; + + return PSA_SUCCESS; +} + +static psa_status_t psa_tls12_prf_set_label(psa_tls12_prf_key_derivation_t *prf, + const uint8_t *data, + size_t data_length) +{ + if (prf->state != PSA_TLS12_PRF_STATE_KEY_SET) { + return PSA_ERROR_BAD_STATE; + } + + if (data_length != 0) { + prf->label = mbedtls_calloc(1, data_length); + if (prf->label == NULL) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + + memcpy(prf->label, data, data_length); + prf->label_length = data_length; + } + + prf->state = PSA_TLS12_PRF_STATE_LABEL_SET; + + return PSA_SUCCESS; +} + +static psa_status_t psa_tls12_prf_input(psa_tls12_prf_key_derivation_t *prf, + psa_key_derivation_step_t step, + const uint8_t *data, + size_t data_length) +{ + switch (step) { + case PSA_KEY_DERIVATION_INPUT_SEED: + return psa_tls12_prf_set_seed(prf, data, data_length); + case PSA_KEY_DERIVATION_INPUT_SECRET: + return psa_tls12_prf_set_key(prf, data, data_length); + case PSA_KEY_DERIVATION_INPUT_LABEL: + return psa_tls12_prf_set_label(prf, data, data_length); + default: + return PSA_ERROR_INVALID_ARGUMENT; + } +} +#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || + * MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) +static psa_status_t psa_tls12_prf_psk_to_ms_set_key( + psa_tls12_prf_key_derivation_t *prf, + const uint8_t *data, + size_t data_length) +{ + psa_status_t status; + const size_t pms_len = (prf->state == PSA_TLS12_PRF_STATE_OTHER_KEY_SET ? + 4 + data_length + prf->other_secret_length : + 4 + 2 * data_length); + + if (data_length > PSA_TLS12_PSK_TO_MS_PSK_MAX_SIZE) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + uint8_t *pms = mbedtls_calloc(1, pms_len); + if (pms == NULL) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + uint8_t *cur = pms; + + /* pure-PSK: + * Quoting RFC 4279, Section 2: + * + * The premaster secret is formed as follows: if the PSK is N octets + * long, concatenate a uint16 with the value N, N zero octets, a second + * uint16 with the value N, and the PSK itself. + * + * mixed-PSK: + * In a ECDHE-PSK the premaster secret is formed as follows: + * concatenate a uint16 with the length of the other secret, + * the other secret itself, uint16 with the length of PSK, and the + * PSK itself. + * For details please check RFC 5489 for the definition of ECDHE-PSK. + */ + + if (prf->state == PSA_TLS12_PRF_STATE_OTHER_KEY_SET) { + *cur++ = MBEDTLS_BYTE_1(prf->other_secret_length); + *cur++ = MBEDTLS_BYTE_0(prf->other_secret_length); + if (prf->other_secret_length != 0) { + memcpy(cur, prf->other_secret, prf->other_secret_length); + mbedtls_platform_zeroize(prf->other_secret, prf->other_secret_length); + cur += prf->other_secret_length; + } + } else { + *cur++ = MBEDTLS_BYTE_1(data_length); + *cur++ = MBEDTLS_BYTE_0(data_length); + memset(cur, 0, data_length); + cur += data_length; + } + + *cur++ = MBEDTLS_BYTE_1(data_length); + *cur++ = MBEDTLS_BYTE_0(data_length); + memcpy(cur, data, data_length); + cur += data_length; + + status = psa_tls12_prf_set_key(prf, pms, (size_t) (cur - pms)); + + mbedtls_zeroize_and_free(pms, pms_len); + return status; +} + +static psa_status_t psa_tls12_prf_psk_to_ms_set_other_key( + psa_tls12_prf_key_derivation_t *prf, + const uint8_t *data, + size_t data_length) +{ + if (prf->state != PSA_TLS12_PRF_STATE_SEED_SET) { + return PSA_ERROR_BAD_STATE; + } + + if (data_length != 0) { + prf->other_secret = mbedtls_calloc(1, data_length); + if (prf->other_secret == NULL) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + + memcpy(prf->other_secret, data, data_length); + prf->other_secret_length = data_length; + } else { + prf->other_secret_length = 0; + } + + prf->state = PSA_TLS12_PRF_STATE_OTHER_KEY_SET; + + return PSA_SUCCESS; +} + +static psa_status_t psa_tls12_prf_psk_to_ms_input( + psa_tls12_prf_key_derivation_t *prf, + psa_key_derivation_step_t step, + const uint8_t *data, + size_t data_length) +{ + switch (step) { + case PSA_KEY_DERIVATION_INPUT_SECRET: + return psa_tls12_prf_psk_to_ms_set_key(prf, + data, data_length); + break; + case PSA_KEY_DERIVATION_INPUT_OTHER_SECRET: + return psa_tls12_prf_psk_to_ms_set_other_key(prf, + data, + data_length); + break; + default: + return psa_tls12_prf_input(prf, step, data, data_length); + break; + + } +} +#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS) +static psa_status_t psa_tls12_ecjpake_to_pms_input( + psa_tls12_ecjpake_to_pms_t *ecjpake, + psa_key_derivation_step_t step, + const uint8_t *data, + size_t data_length) +{ + if (data_length != PSA_TLS12_ECJPAKE_TO_PMS_INPUT_SIZE || + step != PSA_KEY_DERIVATION_INPUT_SECRET) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* Check if the passed point is in an uncompressed form */ + if (data[0] != 0x04) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* Only K.X has to be extracted - bytes 1 to 32 inclusive. */ + memcpy(ecjpake->data, data + 1, PSA_TLS12_ECJPAKE_TO_PMS_DATA_SIZE); + + return PSA_SUCCESS; +} +#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS */ + +#if defined(PSA_HAVE_SOFT_PBKDF2) +static psa_status_t psa_pbkdf2_set_input_cost( + psa_pbkdf2_key_derivation_t *pbkdf2, + psa_key_derivation_step_t step, + uint64_t data) +{ + if (step != PSA_KEY_DERIVATION_INPUT_COST) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (pbkdf2->state != PSA_PBKDF2_STATE_INIT) { + return PSA_ERROR_BAD_STATE; + } + + if (data > PSA_VENDOR_PBKDF2_MAX_ITERATIONS) { + return PSA_ERROR_NOT_SUPPORTED; + } + + if (data == 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + pbkdf2->input_cost = data; + pbkdf2->state = PSA_PBKDF2_STATE_INPUT_COST_SET; + + return PSA_SUCCESS; +} + +static psa_status_t psa_pbkdf2_set_salt(psa_pbkdf2_key_derivation_t *pbkdf2, + const uint8_t *data, + size_t data_length) +{ + if (pbkdf2->state == PSA_PBKDF2_STATE_INPUT_COST_SET) { + pbkdf2->state = PSA_PBKDF2_STATE_SALT_SET; + } else if (pbkdf2->state == PSA_PBKDF2_STATE_SALT_SET) { + /* Appending to existing salt. No state change. */ + } else { + return PSA_ERROR_BAD_STATE; + } + + if (data_length == 0) { + /* Appending an empty string, nothing to do. */ + } else { + uint8_t *next_salt; + + next_salt = mbedtls_calloc(1, data_length + pbkdf2->salt_length); + if (next_salt == NULL) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + + if (pbkdf2->salt_length != 0) { + memcpy(next_salt, pbkdf2->salt, pbkdf2->salt_length); + } + memcpy(next_salt + pbkdf2->salt_length, data, data_length); + pbkdf2->salt_length += data_length; + mbedtls_free(pbkdf2->salt); + pbkdf2->salt = next_salt; + } + return PSA_SUCCESS; +} + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC) +static psa_status_t psa_pbkdf2_hmac_set_password(psa_algorithm_t hash_alg, + const uint8_t *input, + size_t input_len, + uint8_t *output, + size_t *output_len) +{ + psa_status_t status = PSA_SUCCESS; + if (input_len > PSA_HASH_BLOCK_LENGTH(hash_alg)) { + return psa_hash_compute(hash_alg, input, input_len, output, + PSA_HMAC_MAX_HASH_BLOCK_SIZE, output_len); + } else if (input_len > 0) { + memcpy(output, input, input_len); + } + *output_len = PSA_HASH_BLOCK_LENGTH(hash_alg); + return status; +} +#endif /* MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC */ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_AES_CMAC_PRF_128) +static psa_status_t psa_pbkdf2_cmac_set_password(const uint8_t *input, + size_t input_len, + uint8_t *output, + size_t *output_len) +{ + psa_status_t status = PSA_SUCCESS; + if (input_len != PSA_MAC_LENGTH(PSA_KEY_TYPE_AES, 128U, PSA_ALG_CMAC)) { + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + uint8_t zeros[16] = { 0 }; + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(sizeof(zeros))); + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_MESSAGE); + /* Passing PSA_MAC_LENGTH(PSA_KEY_TYPE_AES, 128U, PSA_ALG_CMAC) as + * mac_size as the driver function sets mac_output_length = mac_size + * on success. See https://github.com/Mbed-TLS/mbedtls/issues/7801 */ + status = psa_driver_wrapper_mac_compute(&attributes, + zeros, sizeof(zeros), + PSA_ALG_CMAC, input, input_len, + output, + PSA_MAC_LENGTH(PSA_KEY_TYPE_AES, + 128U, + PSA_ALG_CMAC), + output_len); + } else { + memcpy(output, input, input_len); + *output_len = PSA_MAC_LENGTH(PSA_KEY_TYPE_AES, 128U, PSA_ALG_CMAC); + } + return status; +} +#endif /* MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_AES_CMAC_PRF_128 */ + +static psa_status_t psa_pbkdf2_set_password(psa_pbkdf2_key_derivation_t *pbkdf2, + psa_algorithm_t kdf_alg, + const uint8_t *data, + size_t data_length) +{ + psa_status_t status = PSA_SUCCESS; + if (pbkdf2->state != PSA_PBKDF2_STATE_SALT_SET) { + return PSA_ERROR_BAD_STATE; + } + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC) + if (PSA_ALG_IS_PBKDF2_HMAC(kdf_alg)) { + psa_algorithm_t hash_alg = PSA_ALG_PBKDF2_HMAC_GET_HASH(kdf_alg); + status = psa_pbkdf2_hmac_set_password(hash_alg, data, data_length, + pbkdf2->password, + &pbkdf2->password_length); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_AES_CMAC_PRF_128) + if (kdf_alg == PSA_ALG_PBKDF2_AES_CMAC_PRF_128) { + status = psa_pbkdf2_cmac_set_password(data, data_length, + pbkdf2->password, + &pbkdf2->password_length); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_AES_CMAC_PRF_128 */ + { + return PSA_ERROR_INVALID_ARGUMENT; + } + + pbkdf2->state = PSA_PBKDF2_STATE_PASSWORD_SET; + + return status; +} + +static psa_status_t psa_pbkdf2_input(psa_pbkdf2_key_derivation_t *pbkdf2, + psa_algorithm_t kdf_alg, + psa_key_derivation_step_t step, + const uint8_t *data, + size_t data_length) +{ + switch (step) { + case PSA_KEY_DERIVATION_INPUT_SALT: + return psa_pbkdf2_set_salt(pbkdf2, data, data_length); + case PSA_KEY_DERIVATION_INPUT_PASSWORD: + return psa_pbkdf2_set_password(pbkdf2, kdf_alg, data, data_length); + default: + return PSA_ERROR_INVALID_ARGUMENT; + } +} +#endif /* PSA_HAVE_SOFT_PBKDF2 */ + +/** Check whether the given key type is acceptable for the given + * input step of a key derivation. + * + * Secret inputs must have the type #PSA_KEY_TYPE_DERIVE. + * Non-secret inputs must have the type #PSA_KEY_TYPE_RAW_DATA. + * Both secret and non-secret inputs can alternatively have the type + * #PSA_KEY_TYPE_NONE, which is never the type of a key object, meaning + * that the input was passed as a buffer rather than via a key object. + */ +static int psa_key_derivation_check_input_type( + psa_key_derivation_step_t step, + psa_key_type_t key_type) +{ + switch (step) { + case PSA_KEY_DERIVATION_INPUT_SECRET: + if (key_type == PSA_KEY_TYPE_DERIVE) { + return PSA_SUCCESS; + } + if (key_type == PSA_KEY_TYPE_NONE) { + return PSA_SUCCESS; + } + break; + case PSA_KEY_DERIVATION_INPUT_OTHER_SECRET: + if (key_type == PSA_KEY_TYPE_DERIVE) { + return PSA_SUCCESS; + } + if (key_type == PSA_KEY_TYPE_NONE) { + return PSA_SUCCESS; + } + break; + case PSA_KEY_DERIVATION_INPUT_LABEL: + case PSA_KEY_DERIVATION_INPUT_SALT: + case PSA_KEY_DERIVATION_INPUT_INFO: + case PSA_KEY_DERIVATION_INPUT_SEED: + if (key_type == PSA_KEY_TYPE_RAW_DATA) { + return PSA_SUCCESS; + } + if (key_type == PSA_KEY_TYPE_NONE) { + return PSA_SUCCESS; + } + break; + case PSA_KEY_DERIVATION_INPUT_PASSWORD: + if (key_type == PSA_KEY_TYPE_PASSWORD) { + return PSA_SUCCESS; + } + if (key_type == PSA_KEY_TYPE_DERIVE) { + return PSA_SUCCESS; + } + if (key_type == PSA_KEY_TYPE_NONE) { + return PSA_SUCCESS; + } + break; + } + return PSA_ERROR_INVALID_ARGUMENT; +} + +static psa_status_t psa_key_derivation_input_internal( + psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + psa_key_type_t key_type, + const uint8_t *data, + size_t data_length) +{ + psa_status_t status; + psa_algorithm_t kdf_alg = psa_key_derivation_get_kdf_alg(operation); + + if (kdf_alg == PSA_ALG_NONE) { + /* This is a blank or aborted operation. */ + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + status = psa_key_derivation_check_input_type(step, key_type); + if (status != PSA_SUCCESS) { + goto exit; + } + +#if defined(BUILTIN_ALG_ANY_HKDF) + if (PSA_ALG_IS_ANY_HKDF(kdf_alg)) { + status = psa_hkdf_input(&operation->ctx.hkdf, kdf_alg, + step, data, data_length); + } else +#endif /* BUILTIN_ALG_ANY_HKDF */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) + if (PSA_ALG_IS_TLS12_PRF(kdf_alg)) { + status = psa_tls12_prf_input(&operation->ctx.tls12_prf, + step, data, data_length); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) + if (PSA_ALG_IS_TLS12_PSK_TO_MS(kdf_alg)) { + status = psa_tls12_prf_psk_to_ms_input(&operation->ctx.tls12_prf, + step, data, data_length); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS) + if (kdf_alg == PSA_ALG_TLS12_ECJPAKE_TO_PMS) { + status = psa_tls12_ecjpake_to_pms_input( + &operation->ctx.tls12_ecjpake_to_pms, step, data, data_length); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS */ +#if defined(PSA_HAVE_SOFT_PBKDF2) + if (PSA_ALG_IS_PBKDF2(kdf_alg)) { + status = psa_pbkdf2_input(&operation->ctx.pbkdf2, kdf_alg, + step, data, data_length); + } else +#endif /* PSA_HAVE_SOFT_PBKDF2 */ + { + /* This can't happen unless the operation object was not initialized */ + (void) data; + (void) data_length; + (void) kdf_alg; + return PSA_ERROR_BAD_STATE; + } + +exit: + if (status != PSA_SUCCESS) { + psa_key_derivation_abort(operation); + } + return status; +} + +static psa_status_t psa_key_derivation_input_integer_internal( + psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + uint64_t value) +{ + psa_status_t status; + psa_algorithm_t kdf_alg = psa_key_derivation_get_kdf_alg(operation); + + if (kdf_alg == PSA_ALG_NONE) { + /* This is a blank or aborted operation. */ + status = PSA_ERROR_BAD_STATE; + goto exit; + } + +#if defined(PSA_HAVE_SOFT_PBKDF2) + if (PSA_ALG_IS_PBKDF2(kdf_alg)) { + status = psa_pbkdf2_set_input_cost( + &operation->ctx.pbkdf2, step, value); + } else +#endif /* PSA_HAVE_SOFT_PBKDF2 */ + { + (void) step; + (void) value; + (void) kdf_alg; + status = PSA_ERROR_INVALID_ARGUMENT; + } + +exit: + if (status != PSA_SUCCESS) { + psa_key_derivation_abort(operation); + } + return status; +} + +psa_status_t psa_key_derivation_input_bytes( + psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + const uint8_t *data_external, + size_t data_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_INPUT_DECLARE(data_external, data); + + LOCAL_INPUT_ALLOC(data_external, data_length, data); + + status = psa_key_derivation_input_internal(operation, step, + PSA_KEY_TYPE_NONE, + data, data_length); +#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) +exit: +#endif + LOCAL_INPUT_FREE(data_external, data); + return status; +} + +psa_status_t psa_key_derivation_input_integer( + psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + uint64_t value) +{ + return psa_key_derivation_input_integer_internal(operation, step, value); +} + +psa_status_t psa_key_derivation_input_key( + psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + mbedtls_svc_key_id_t key) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + + status = psa_get_and_lock_transparent_key_slot_with_policy( + key, &slot, PSA_KEY_USAGE_DERIVE, operation->alg); + if (status != PSA_SUCCESS) { + psa_key_derivation_abort(operation); + return status; + } + + /* Passing a key object as a SECRET or PASSWORD input unlocks the + * permission to output to a key object. */ + if (step == PSA_KEY_DERIVATION_INPUT_SECRET || + step == PSA_KEY_DERIVATION_INPUT_PASSWORD) { + operation->can_output_key = 1; + } + + status = psa_key_derivation_input_internal(operation, + step, slot->attr.type, + slot->key.data, + slot->key.bytes); + + unlock_status = psa_unregister_read_under_mutex(slot); + + return (status == PSA_SUCCESS) ? unlock_status : status; +} + + + +/****************************************************************/ +/* Key agreement */ +/****************************************************************/ + +psa_status_t psa_key_agreement_raw_builtin(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *peer_key, + size_t peer_key_length, + uint8_t *shared_secret, + size_t shared_secret_size, + size_t *shared_secret_length) +{ + switch (alg) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) + case PSA_ALG_ECDH: + return mbedtls_psa_key_agreement_ecdh(attributes, key_buffer, + key_buffer_size, alg, + peer_key, peer_key_length, + shared_secret, + shared_secret_size, + shared_secret_length); +#endif /* MBEDTLS_PSA_BUILTIN_ALG_ECDH */ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_FFDH) + case PSA_ALG_FFDH: + return mbedtls_psa_ffdh_key_agreement(attributes, + peer_key, + peer_key_length, + key_buffer, + key_buffer_size, + shared_secret, + shared_secret_size, + shared_secret_length); +#endif /* MBEDTLS_PSA_BUILTIN_ALG_FFDH */ + + default: + (void) attributes; + (void) key_buffer; + (void) key_buffer_size; + (void) peer_key; + (void) peer_key_length; + (void) shared_secret; + (void) shared_secret_size; + (void) shared_secret_length; + return PSA_ERROR_NOT_SUPPORTED; + } +} + +/** Internal function for raw key agreement + * Calls the driver wrapper which will hand off key agreement task + * to the driver's implementation if a driver is present. + * Fallback specified in the driver wrapper is built-in raw key agreement + * (psa_key_agreement_raw_builtin). + */ +static psa_status_t psa_key_agreement_raw_internal(psa_algorithm_t alg, + psa_key_slot_t *private_key, + const uint8_t *peer_key, + size_t peer_key_length, + uint8_t *shared_secret, + size_t shared_secret_size, + size_t *shared_secret_length) +{ + if (!PSA_ALG_IS_RAW_KEY_AGREEMENT(alg)) { + return PSA_ERROR_NOT_SUPPORTED; + } + + return psa_driver_wrapper_key_agreement(&private_key->attr, + private_key->key.data, + private_key->key.bytes, alg, + peer_key, peer_key_length, + shared_secret, + shared_secret_size, + shared_secret_length); +} + +/* Note that if this function fails, you must call psa_key_derivation_abort() + * to potentially free embedded data structures and wipe confidential data. + */ +static psa_status_t psa_key_agreement_internal(psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + psa_key_slot_t *private_key, + const uint8_t *peer_key, + size_t peer_key_length) +{ + psa_status_t status; + uint8_t shared_secret[PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE] = { 0 }; + size_t shared_secret_length = 0; + psa_algorithm_t ka_alg = PSA_ALG_KEY_AGREEMENT_GET_BASE(operation->alg); + + /* Step 1: run the secret agreement algorithm to generate the shared + * secret. */ + status = psa_key_agreement_raw_internal(ka_alg, + private_key, + peer_key, peer_key_length, + shared_secret, + sizeof(shared_secret), + &shared_secret_length); + if (status != PSA_SUCCESS) { + goto exit; + } + + /* Step 2: set up the key derivation to generate key material from + * the shared secret. A shared secret is permitted wherever a key + * of type DERIVE is permitted. */ + status = psa_key_derivation_input_internal(operation, step, + PSA_KEY_TYPE_DERIVE, + shared_secret, + shared_secret_length); +exit: + mbedtls_platform_zeroize(shared_secret, shared_secret_length); + return status; +} + +psa_status_t psa_key_derivation_key_agreement(psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + mbedtls_svc_key_id_t private_key, + const uint8_t *peer_key_external, + size_t peer_key_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + LOCAL_INPUT_DECLARE(peer_key_external, peer_key); + + if (!PSA_ALG_IS_KEY_AGREEMENT(operation->alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + status = psa_get_and_lock_transparent_key_slot_with_policy( + private_key, &slot, PSA_KEY_USAGE_DERIVE, operation->alg); + if (status != PSA_SUCCESS) { + return status; + } + + LOCAL_INPUT_ALLOC(peer_key_external, peer_key_length, peer_key); + status = psa_key_agreement_internal(operation, step, + slot, + peer_key, peer_key_length); + +#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) +exit: +#endif + if (status != PSA_SUCCESS) { + psa_key_derivation_abort(operation); + } else { + /* If a private key has been added as SECRET, we allow the derived + * key material to be used as a key in PSA Crypto. */ + if (step == PSA_KEY_DERIVATION_INPUT_SECRET) { + operation->can_output_key = 1; + } + } + + unlock_status = psa_unregister_read_under_mutex(slot); + LOCAL_INPUT_FREE(peer_key_external, peer_key); + + return (status == PSA_SUCCESS) ? unlock_status : status; +} + +psa_status_t psa_raw_key_agreement(psa_algorithm_t alg, + mbedtls_svc_key_id_t private_key, + const uint8_t *peer_key_external, + size_t peer_key_length, + uint8_t *output_external, + size_t output_size, + size_t *output_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot = NULL; + size_t expected_length; + LOCAL_INPUT_DECLARE(peer_key_external, peer_key); + LOCAL_OUTPUT_DECLARE(output_external, output); + LOCAL_OUTPUT_ALLOC(output_external, output_size, output); + + if (!PSA_ALG_IS_KEY_AGREEMENT(alg)) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + status = psa_get_and_lock_transparent_key_slot_with_policy( + private_key, &slot, PSA_KEY_USAGE_DERIVE, alg); + if (status != PSA_SUCCESS) { + goto exit; + } + + /* PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE() is in general an upper bound + * for the output size. The PSA specification only guarantees that this + * function works if output_size >= PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(...), + * but it might be nice to allow smaller buffers if the output fits. + * At the time of writing this comment, for both FFDH and ECDH, + * PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE() is exact so the point is moot. */ + expected_length = + PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(slot->attr.type, slot->attr.bits); + if (output_size < expected_length) { + status = PSA_ERROR_BUFFER_TOO_SMALL; + goto exit; + } + + LOCAL_INPUT_ALLOC(peer_key_external, peer_key_length, peer_key); + status = psa_key_agreement_raw_internal(alg, slot, + peer_key, peer_key_length, + output, output_size, + output_length); + +exit: + /* Check for successful allocation of output, + * with an unsuccessful status. */ + if (output != NULL && status != PSA_SUCCESS) { + /* If an error happens and is not handled properly, the output + * may be used as a key to protect sensitive data. Arrange for such + * a key to be random, which is likely to result in decryption or + * verification errors. This is better than filling the buffer with + * some constant data such as zeros, which would result in the data + * being protected with a reproducible, easily knowable key. + */ + psa_generate_random_internal(output, output_size); + *output_length = output_size; + } + + if (output == NULL) { + /* output allocation failed. */ + *output_length = 0; + } + + unlock_status = psa_unregister_read_under_mutex(slot); + + LOCAL_INPUT_FREE(peer_key_external, peer_key); + LOCAL_OUTPUT_FREE(output_external, output); + return (status == PSA_SUCCESS) ? unlock_status : status; +} + +static psa_status_t validate_key_agreement_params(const psa_key_attributes_t *attributes, + psa_algorithm_t alg) +{ + psa_key_type_t key_type; + + if (!PSA_ALG_IS_RAW_KEY_AGREEMENT(alg)) { + return PSA_ERROR_NOT_SUPPORTED; + } + + key_type = psa_get_key_type(attributes); + if (key_type != PSA_KEY_TYPE_DERIVE && key_type != PSA_KEY_TYPE_RAW_DATA + && key_type != PSA_KEY_TYPE_HMAC && key_type != PSA_KEY_TYPE_PASSWORD) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return PSA_SUCCESS; +} + +psa_status_t psa_key_agreement(mbedtls_svc_key_id_t private_key, + const uint8_t *peer_key, + size_t peer_key_length, + psa_algorithm_t alg, + const psa_key_attributes_t *attributes, + mbedtls_svc_key_id_t *key) +{ + psa_status_t status; + uint8_t shared_secret[PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE]; + size_t shared_secret_len; + + *key = MBEDTLS_SVC_KEY_ID_INIT; + + status = validate_key_agreement_params(attributes, alg); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_raw_key_agreement(alg, private_key, peer_key, peer_key_length, shared_secret, + sizeof(shared_secret), &shared_secret_len); + + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_import_key(attributes, shared_secret, shared_secret_len, key); + + return status; +} + +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) + +static psa_status_t psa_key_agreement_iop_abort_internal(psa_key_agreement_iop_t *operation) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (operation->id == 0) { + return PSA_SUCCESS; + } + + status = mbedtls_psa_key_agreement_iop_abort(&operation->mbedtls_ctx); + + operation->id = 0; + + return status; +} +#endif + +uint32_t psa_key_agreement_iop_get_num_ops( + psa_key_agreement_iop_t *operation) +{ +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) + return operation->num_ops; +#else + (void) operation; + return 0; +#endif +} + +psa_status_t psa_key_agreement_iop_setup( + psa_key_agreement_iop_t *operation, + mbedtls_svc_key_id_t private_key, + const uint8_t *peer_key, + size_t peer_key_length, + psa_algorithm_t alg, + const psa_key_attributes_t *attributes) +{ +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot = NULL; + + if (operation->id != 0 || operation->error_occurred) { + return PSA_ERROR_BAD_STATE; + } + + status = validate_key_agreement_params(attributes, alg); + if (status != PSA_SUCCESS) { + operation->error_occurred = 1; + return status; + } + + status = psa_get_and_lock_transparent_key_slot_with_policy( + private_key, &slot, PSA_KEY_USAGE_DERIVE, alg); + if (status != PSA_SUCCESS) { + goto exit; + } + + /* We only support raw key agreement here, not combined with a key + * derivation. Also, for the time being, we only allow ECDH, not + * other key agreement algorithms. + * + * This check could come slightly earlier or later. Having it here + * gives consistent error codes with non-interruptible key agreement + * (psa_raw_key_agreement(), psa_key_agreement()) when the input + * parameters (including the key) are also invalid for + * non-interruptible key agreement. + */ + if (alg != PSA_ALG_ECDH) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + operation->attributes = *attributes; + + operation->num_ops = 0; + + /* To be removed later when driver dispatch is added. */ + operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID; + + status = mbedtls_psa_key_agreement_iop_setup(&operation->mbedtls_ctx, + &slot->attr, slot->key.data, + slot->key.bytes, peer_key, + peer_key_length); + + operation->num_ops = mbedtls_psa_key_agreement_iop_get_num_ops(&operation->mbedtls_ctx); + +exit: + unlock_status = psa_unregister_read_under_mutex(slot); + if (status != PSA_SUCCESS) { + operation->error_occurred = 1; + psa_key_agreement_iop_abort_internal(operation); + return status; + } + if (unlock_status != PSA_SUCCESS) { + operation->error_occurred = 1; + } + return unlock_status; +#else + (void) operation; + (void) private_key; + (void) peer_key; + (void) peer_key_length; + (void) alg; + (void) attributes; + return PSA_ERROR_NOT_SUPPORTED; +#endif +} + +psa_status_t psa_key_agreement_iop_complete( + psa_key_agreement_iop_t *operation, + mbedtls_svc_key_id_t *key) +{ +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) + + if (operation->id == 0 || operation->error_occurred) { + return PSA_ERROR_BAD_STATE; + } + + psa_status_t status; + uint8_t intermediate_key[PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE]; + size_t key_len = 0; + + status = mbedtls_psa_key_agreement_iop_complete(&operation->mbedtls_ctx, intermediate_key, + sizeof(intermediate_key), + &key_len); + + operation->num_ops = mbedtls_psa_key_agreement_iop_get_num_ops(&operation->mbedtls_ctx); + + if (status == PSA_SUCCESS) { + status = psa_import_key(&operation->attributes, intermediate_key, + key_len, key); + } + + if (status != PSA_OPERATION_INCOMPLETE) { + operation->error_occurred = 1; + psa_key_agreement_iop_abort_internal(operation); + } + mbedtls_platform_zeroize(intermediate_key, sizeof(intermediate_key)); + return status; +#else + (void) operation; + (void) key; + return PSA_ERROR_BAD_STATE; +#endif +} + +psa_status_t psa_key_agreement_iop_abort( + psa_key_agreement_iop_t *operation) +{ +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) + psa_status_t status; + + status = psa_key_agreement_iop_abort_internal(operation); + + operation->num_ops = 0; + operation->error_occurred = 0; + + return status; +#else + (void) operation; + return PSA_SUCCESS; +#endif +} + +/****************************************************************/ +/* Random generation */ +/****************************************************************/ + +/** Initialize the PSA random generator. + * + * Note: the mbedtls_threading_psa_rngdata_mutex should be held when calling + * this function if mutexes are enabled. + */ +static void mbedtls_psa_random_init(mbedtls_psa_random_context_t *rng) +{ +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + memset(rng, 0, sizeof(*rng)); +#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ + psa_random_internal_init(rng); +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ +} + +/** Deinitialize the PSA random generator. + * + * Note: the mbedtls_threading_psa_rngdata_mutex should be held when calling + * this function if mutexes are enabled. + */ +static void mbedtls_psa_random_free(mbedtls_psa_random_context_t *rng) +{ +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + memset(rng, 0, sizeof(*rng)); +#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ + psa_random_internal_free(rng); +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ +} + +/** Seed the PSA random generator. + */ +static psa_status_t mbedtls_psa_random_seed(mbedtls_psa_random_context_t *rng) +{ +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + /* Do nothing: the external RNG seeds itself. */ + (void) rng; + return PSA_SUCCESS; +#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ + return psa_random_internal_seed(rng); +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ +} + +psa_status_t psa_random_reseed(const uint8_t *perso, size_t perso_size) +{ + GUARD_MODULE_INITIALIZED; +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + (void) perso; + (void) perso_size; + return PSA_ERROR_NOT_SUPPORTED; +#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ +#if defined(MBEDTLS_THREADING_C) + if (mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex) != 0) { + return PSA_ERROR_SERVICE_FAILURE; + } +#endif /* defined(MBEDTLS_THREADING_C) */ + int ret = mbedtls_psa_drbg_reseed(&global_data.rng.drbg, + perso, perso_size); +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + return mbedtls_to_psa_error(ret); +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ +} + +psa_status_t psa_random_deplete(void) +{ + GUARD_MODULE_INITIALIZED; +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + return PSA_ERROR_NOT_SUPPORTED; +#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ +#if defined(MBEDTLS_THREADING_C) + if (mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex) != 0) { + return PSA_ERROR_SERVICE_FAILURE; + } +#endif /* defined(MBEDTLS_THREADING_C) */ + mbedtls_psa_drbg_deplete(&global_data.rng.drbg); +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + return PSA_SUCCESS; +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ +} + +psa_status_t psa_random_set_prediction_resistance(unsigned enabled) +{ + GUARD_MODULE_INITIALIZED; + +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + (void) enabled; + return PSA_ERROR_NOT_SUPPORTED; +#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ + + if (enabled != 0 && enabled != 1) { + return PSA_ERROR_INVALID_ARGUMENT; + } + +#if MBEDTLS_ENTROPY_TRUE_SOURCES > 0 +#if defined(MBEDTLS_THREADING_C) + if (mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex) != 0) { + return PSA_ERROR_SERVICE_FAILURE; + } +#endif /* defined(MBEDTLS_THREADING_C) */ + mbedtls_psa_drbg_set_prediction_resistance(&global_data.rng.drbg, enabled); +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + return PSA_SUCCESS; + +#else /* MBEDTLS_ENTROPY_TRUE_SOURCES > 0 */ + if (enabled) { + return PSA_ERROR_NOT_SUPPORTED; + } else { + return PSA_SUCCESS; + } + +#endif /* MBEDTLS_ENTROPY_TRUE_SOURCES > 0 */ +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ +} + +psa_status_t psa_generate_random(uint8_t *output_external, + size_t output_size) +{ + psa_status_t status; + + LOCAL_OUTPUT_DECLARE(output_external, output); + LOCAL_OUTPUT_ALLOC(output_external, output_size, output); + + status = psa_generate_random_internal(output, output_size); + +#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) +exit: +#endif + LOCAL_OUTPUT_FREE(output_external, output); + return status; +} + +/** Validate the key type and size for key generation + * + * \param type The key type + * \param bits The number of bits of the key + * + * \retval #PSA_SUCCESS + * The key type and size are valid. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The size in bits of the key is not valid. + * \retval #PSA_ERROR_NOT_SUPPORTED + * The type and/or the size in bits of the key or the combination of + * the two is not supported. + */ +static psa_status_t psa_validate_key_type_and_size_for_key_generation( + psa_key_type_t type, size_t bits) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (key_type_is_raw_bytes(type)) { + status = psa_validate_unstructured_key_bit_size(type, bits); + if (status != PSA_SUCCESS) { + return status; + } + } else +#if defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE) + if (PSA_KEY_TYPE_IS_RSA(type) && PSA_KEY_TYPE_IS_KEY_PAIR(type)) { + if (bits > PSA_VENDOR_RSA_MAX_KEY_BITS) { + return PSA_ERROR_NOT_SUPPORTED; + } + if (bits < PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS) { + return PSA_ERROR_NOT_SUPPORTED; + } + + /* Accept only byte-aligned keys, for the same reasons as + * in psa_import_rsa_key(). */ + if (bits % 8 != 0) { + return PSA_ERROR_NOT_SUPPORTED; + } + } else +#endif /* defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE) */ + +#if defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE) + if (PSA_KEY_TYPE_IS_ECC(type) && PSA_KEY_TYPE_IS_KEY_PAIR(type)) { + /* To avoid empty block, return successfully here. */ + return PSA_SUCCESS; + } else +#endif /* defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE) */ + +#if defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE) + if (PSA_KEY_TYPE_IS_DH(type) && PSA_KEY_TYPE_IS_KEY_PAIR(type)) { + if (psa_is_dh_key_size_valid(bits) == 0) { + return PSA_ERROR_NOT_SUPPORTED; + } + } else +#endif /* defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE) */ + { + return PSA_ERROR_NOT_SUPPORTED; + } + + return PSA_SUCCESS; +} + +psa_status_t psa_generate_key_internal( + const psa_key_attributes_t *attributes, + const psa_custom_key_parameters_t *custom, + const uint8_t *custom_data, + size_t custom_data_length, + uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_type_t type = attributes->type; + + /* Only used for RSA */ + (void) custom; + (void) custom_data; + (void) custom_data_length; + + if (key_type_is_raw_bytes(type)) { + status = psa_generate_random_internal(key_buffer, key_buffer_size); + if (status != PSA_SUCCESS) { + return status; + } + + } else + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE) + if (type == PSA_KEY_TYPE_RSA_KEY_PAIR) { + return mbedtls_psa_rsa_generate_key(attributes, + custom_data, custom_data_length, + key_buffer, + key_buffer_size, + key_buffer_length); + } else +#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE) */ + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE) + if (PSA_KEY_TYPE_IS_ECC(type) && PSA_KEY_TYPE_IS_KEY_PAIR(type)) { + return mbedtls_psa_ecp_generate_key(attributes, + key_buffer, + key_buffer_size, + key_buffer_length); + } else +#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE) */ + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_GENERATE) + if (PSA_KEY_TYPE_IS_DH(type) && PSA_KEY_TYPE_IS_KEY_PAIR(type)) { + return mbedtls_psa_ffdh_generate_key(attributes, + key_buffer, + key_buffer_size, + key_buffer_length); + } else +#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_GENERATE) */ + { + (void) key_buffer_length; + return PSA_ERROR_NOT_SUPPORTED; + } + + return PSA_SUCCESS; +} + +psa_status_t psa_generate_key_custom(const psa_key_attributes_t *attributes, + const psa_custom_key_parameters_t *custom, + const uint8_t *custom_data, + size_t custom_data_length, + mbedtls_svc_key_id_t *key) +{ + psa_status_t status; + psa_key_slot_t *slot = NULL; + size_t key_buffer_size; + + *key = MBEDTLS_SVC_KEY_ID_INIT; + + /* Reject any attempt to create a zero-length key so that we don't + * risk tripping up later, e.g. on a malloc(0) that returns NULL. */ + if (psa_get_key_bits(attributes) == 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* Reject any attempt to create a public key. */ + if (PSA_KEY_TYPE_IS_PUBLIC_KEY(attributes->type)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + +#if defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE) + if (attributes->type == PSA_KEY_TYPE_RSA_KEY_PAIR) { + if (custom->flags != 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + } else +#endif + if (!psa_custom_key_parameters_are_default(custom, custom_data_length)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + status = psa_start_key_creation(attributes, &slot); + if (status != PSA_SUCCESS) { + goto exit; + } + + /* In the case of a transparent key or an opaque key stored in local + * storage, we have to allocate a buffer to hold the generated key material. */ + if (slot->key.bytes == 0) { + if (PSA_KEY_LIFETIME_GET_LOCATION(attributes->lifetime) == + PSA_KEY_LOCATION_LOCAL_STORAGE) { + status = psa_validate_key_type_and_size_for_key_generation( + attributes->type, attributes->bits); + if (status != PSA_SUCCESS) { + goto exit; + } + + key_buffer_size = PSA_EXPORT_KEY_OUTPUT_SIZE( + attributes->type, + attributes->bits); + } else { + status = psa_driver_wrapper_get_key_buffer_size( + attributes, &key_buffer_size); + if (status != PSA_SUCCESS) { + goto exit; + } + } + + status = psa_allocate_buffer_to_slot(slot, key_buffer_size); + if (status != PSA_SUCCESS) { + goto exit; + } + } + + status = psa_driver_wrapper_generate_key(attributes, + custom, + custom_data, custom_data_length, + slot->key.data, slot->key.bytes, + &slot->key.bytes); + if (status != PSA_SUCCESS) { + psa_remove_key_data_from_memory(slot); + } + +exit: + if (status == PSA_SUCCESS) { + status = psa_finish_key_creation(slot, key); + } + if (status != PSA_SUCCESS) { + psa_fail_key_creation(slot); + } + + return status; +} + +psa_status_t psa_generate_key(const psa_key_attributes_t *attributes, + mbedtls_svc_key_id_t *key) +{ + return psa_generate_key_custom(attributes, + &default_custom_production, + NULL, 0, + key); +} + +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE) +static psa_status_t psa_generate_key_iop_abort_internal( + psa_generate_key_iop_t *operation) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (operation->id == 0) { + return PSA_SUCCESS; + } + + status = mbedtls_psa_ecp_generate_key_iop_abort(&operation->ctx); + + psa_reset_key_attributes(&operation->attributes); + + operation->id = 0; + + return status; +} +#endif + +uint32_t psa_generate_key_iop_get_num_ops( + psa_generate_key_iop_t *operation) +{ + return operation->num_ops; +} + +psa_status_t psa_generate_key_iop_setup( + psa_generate_key_iop_t *operation, + const psa_key_attributes_t *attributes) +{ +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE) + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_type_t type; + + type = psa_get_key_type(attributes); + + if (!PSA_KEY_TYPE_IS_ECC(type)) { + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; + } + + if (operation->id != 0 || operation->error_occurred) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (psa_get_key_bits(attributes) == 0) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + if (PSA_KEY_TYPE_IS_PUBLIC_KEY(type)) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + operation->attributes = *attributes; + + operation->num_ops = 0; + + /* We only support the builtin/Mbed TLS driver for now. */ + operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID; + + status = mbedtls_psa_ecp_generate_key_iop_setup(&operation->ctx, attributes); + +exit: + if (status != PSA_SUCCESS) { + operation->error_occurred = 1; + psa_generate_key_iop_abort_internal(operation); + } + + return status; +#else + (void) operation; + (void) attributes; + return PSA_ERROR_NOT_SUPPORTED; +#endif +} + +psa_status_t psa_generate_key_iop_complete( + psa_generate_key_iop_t *operation, + mbedtls_svc_key_id_t *key) +{ +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE) + psa_status_t status; + uint8_t key_data[PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS)+1] = { 0 }; + size_t key_len = 0; + + if (operation->id == 0 || operation->error_occurred) { + return PSA_ERROR_BAD_STATE; + } + + status = mbedtls_psa_ecp_generate_key_iop_complete(&operation->ctx, key_data, + sizeof(key_data), &key_len); + if (status != PSA_SUCCESS) { + goto exit; + } + + operation->num_ops = mbedtls_psa_generate_key_iop_get_num_ops(&operation->ctx); + + status = psa_import_key(&operation->attributes, + key_data + (sizeof(key_data) - key_len), + key_len, + key); + +exit: + if (status != PSA_OPERATION_INCOMPLETE) { + if (status != PSA_SUCCESS) { + operation->error_occurred = 1; + } + psa_generate_key_iop_abort_internal(operation); + } + + mbedtls_platform_zeroize(key_data, sizeof(key_data)); + return status; +#else + (void) operation; + (void) key; + + return PSA_ERROR_BAD_STATE; +#endif +} + +psa_status_t psa_generate_key_iop_abort( + psa_generate_key_iop_t *operation) +{ +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE) + psa_status_t status; + + status = psa_generate_key_iop_abort_internal(operation); + + operation->error_occurred = 0; + operation->num_ops = 0; + return status; +#else + (void) operation; + return PSA_SUCCESS; +#endif +} + + + +/****************************************************************/ +/* Module setup */ +/****************************************************************/ + +#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +psa_status_t mbedtls_psa_crypto_configure_entropy_sources( + void (* entropy_init)(mbedtls_entropy_context *ctx), + void (* entropy_free)(mbedtls_entropy_context *ctx)) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + + if (global_data.rng_state != RNG_NOT_INITIALIZED) { + status = PSA_ERROR_BAD_STATE; + } else { + global_data.rng.entropy_init = entropy_init; + global_data.rng.entropy_free = entropy_free; + status = PSA_SUCCESS; + } + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + + return status; +} +#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */ + +void mbedtls_psa_crypto_free(void) +{ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + + /* Nothing to do to free transaction. */ + if (global_data.initialized & PSA_CRYPTO_SUBSYSTEM_TRANSACTION_INITIALIZED) { + global_data.initialized &= ~PSA_CRYPTO_SUBSYSTEM_TRANSACTION_INITIALIZED; + } + + if (global_data.initialized & PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS_INITIALIZED) { + psa_wipe_all_key_slots(); + global_data.initialized &= ~PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS_INITIALIZED; + } + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_unlock(&mbedtls_threading_psa_globaldata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + + if (global_data.rng_state != RNG_NOT_INITIALIZED) { + mbedtls_psa_random_free(&global_data.rng); + } + global_data.rng_state = RNG_NOT_INITIALIZED; + mbedtls_platform_zeroize(&global_data.rng, sizeof(global_data.rng)); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + + /* Terminate drivers */ + if (global_data.initialized & PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS_INITIALIZED) { + psa_driver_wrapper_free(); + global_data.initialized &= ~PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS_INITIALIZED; + } + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_unlock(&mbedtls_threading_psa_globaldata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + +} + +static psa_status_t mbedtls_psa_crypto_init_subsystem(mbedtls_psa_crypto_subsystem subsystem) +{ + psa_status_t status = PSA_SUCCESS; + uint8_t driver_wrappers_initialized = 0; + + switch (subsystem) { + case PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS: + +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex)); +#endif /* defined(MBEDTLS_THREADING_C) */ + + if (!(global_data.initialized & PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS_INITIALIZED)) { + /* Init drivers */ + status = psa_driver_wrapper_init(); + + /* Drivers need shutdown regardless of startup errors. */ + global_data.initialized |= PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS_INITIALIZED; + + + } +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_unlock( + &mbedtls_threading_psa_globaldata_mutex)); +#endif /* defined(MBEDTLS_THREADING_C) */ + + break; + + case PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS: + +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex)); +#endif /* defined(MBEDTLS_THREADING_C) */ + + if (!(global_data.initialized & PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS_INITIALIZED)) { + status = psa_initialize_key_slots(); + + /* Need to wipe keys even if initialization fails. */ + global_data.initialized |= PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS_INITIALIZED; + + } +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_unlock( + &mbedtls_threading_psa_globaldata_mutex)); +#endif /* defined(MBEDTLS_THREADING_C) */ + + break; + + case PSA_CRYPTO_SUBSYSTEM_RNG: + +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex)); +#endif /* defined(MBEDTLS_THREADING_C) */ + + driver_wrappers_initialized = + (global_data.initialized & PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS_INITIALIZED); + +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_unlock( + &mbedtls_threading_psa_globaldata_mutex)); +#endif /* defined(MBEDTLS_THREADING_C) */ + + /* Need to use separate mutex here, as initialisation can require + * testing of init flags, which requires locking the global data + * mutex. */ +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex)); +#endif /* defined(MBEDTLS_THREADING_C) */ + + /* Initialize and seed the random generator. */ + if (global_data.rng_state == RNG_NOT_INITIALIZED && driver_wrappers_initialized) { + mbedtls_psa_random_init(&global_data.rng); + global_data.rng_state = RNG_INITIALIZED; + status = mbedtls_psa_random_seed(&global_data.rng); + if (status == PSA_SUCCESS) { + global_data.rng_state = RNG_SEEDED; + } + } + +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_unlock( + &mbedtls_threading_psa_rngdata_mutex)); +#endif /* defined(MBEDTLS_THREADING_C) */ + + break; + + case PSA_CRYPTO_SUBSYSTEM_TRANSACTION: + +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex)); +#endif /* defined(MBEDTLS_THREADING_C) */ + + if (!(global_data.initialized & PSA_CRYPTO_SUBSYSTEM_TRANSACTION_INITIALIZED)) { + global_data.initialized |= PSA_CRYPTO_SUBSYSTEM_TRANSACTION_INITIALIZED; + status = PSA_SUCCESS; + } + +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_GOTO_EXIT(mbedtls_mutex_unlock( + &mbedtls_threading_psa_globaldata_mutex)); +#endif /* defined(MBEDTLS_THREADING_C) */ + + break; + + default: + status = PSA_ERROR_CORRUPTION_DETECTED; + } + + /* Exit label only required when using threading macros. */ +#if defined(MBEDTLS_THREADING_C) +exit: +#endif /* defined(MBEDTLS_THREADING_C) */ + + return status; +} + +psa_status_t psa_crypto_init(void) +{ + psa_status_t status; + + /* Double initialization is explicitly allowed. Early out if everything is + * done. */ + if (psa_get_initialized()) { + return PSA_SUCCESS; + } + + status = mbedtls_psa_crypto_init_subsystem(PSA_CRYPTO_SUBSYSTEM_DRIVER_WRAPPERS); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = mbedtls_psa_crypto_init_subsystem(PSA_CRYPTO_SUBSYSTEM_KEY_SLOTS); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = mbedtls_psa_crypto_init_subsystem(PSA_CRYPTO_SUBSYSTEM_RNG); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = mbedtls_psa_crypto_init_subsystem(PSA_CRYPTO_SUBSYSTEM_TRANSACTION); + +exit: + + if (status != PSA_SUCCESS) { + mbedtls_psa_crypto_free(); + } + + return status; +} + + + +/****************************************************************/ +/* PAKE */ +/****************************************************************/ + +#if defined(PSA_WANT_ALG_SOME_PAKE) +psa_status_t psa_crypto_driver_pake_get_password_len( + const psa_crypto_driver_pake_inputs_t *inputs, + size_t *password_len) +{ + if (inputs->password_len == 0) { + return PSA_ERROR_BAD_STATE; + } + + *password_len = inputs->password_len; + + return PSA_SUCCESS; +} + +psa_status_t psa_crypto_driver_pake_get_password( + const psa_crypto_driver_pake_inputs_t *inputs, + uint8_t *buffer, size_t buffer_size, size_t *buffer_length) +{ + if (inputs->password_len == 0) { + return PSA_ERROR_BAD_STATE; + } + + if (buffer_size < inputs->password_len) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + memcpy(buffer, inputs->password, inputs->password_len); + *buffer_length = inputs->password_len; + + return PSA_SUCCESS; +} + +psa_status_t psa_crypto_driver_pake_get_user_len( + const psa_crypto_driver_pake_inputs_t *inputs, + size_t *user_len) +{ + if (inputs->user_len == 0) { + return PSA_ERROR_BAD_STATE; + } + + *user_len = inputs->user_len; + + return PSA_SUCCESS; +} + +psa_status_t psa_crypto_driver_pake_get_user( + const psa_crypto_driver_pake_inputs_t *inputs, + uint8_t *user_id, size_t user_id_size, size_t *user_id_len) +{ + if (inputs->user_len == 0) { + return PSA_ERROR_BAD_STATE; + } + + if (user_id_size < inputs->user_len) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + memcpy(user_id, inputs->user, inputs->user_len); + *user_id_len = inputs->user_len; + + return PSA_SUCCESS; +} + +psa_status_t psa_crypto_driver_pake_get_peer_len( + const psa_crypto_driver_pake_inputs_t *inputs, + size_t *peer_len) +{ + if (inputs->peer_len == 0) { + return PSA_ERROR_BAD_STATE; + } + + *peer_len = inputs->peer_len; + + return PSA_SUCCESS; +} + +psa_status_t psa_crypto_driver_pake_get_peer( + const psa_crypto_driver_pake_inputs_t *inputs, + uint8_t *peer_id, size_t peer_id_size, size_t *peer_id_length) +{ + if (inputs->peer_len == 0) { + return PSA_ERROR_BAD_STATE; + } + + if (peer_id_size < inputs->peer_len) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + memcpy(peer_id, inputs->peer, inputs->peer_len); + *peer_id_length = inputs->peer_len; + + return PSA_SUCCESS; +} + +psa_status_t psa_crypto_driver_pake_get_cipher_suite( + const psa_crypto_driver_pake_inputs_t *inputs, + psa_pake_cipher_suite_t *cipher_suite) +{ + if (inputs->cipher_suite.algorithm == PSA_ALG_NONE) { + return PSA_ERROR_BAD_STATE; + } + + *cipher_suite = inputs->cipher_suite; + + return PSA_SUCCESS; +} + +static psa_status_t psa_pake_set_password_key( + psa_pake_operation_t *operation, + mbedtls_svc_key_id_t password) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot = NULL; + psa_key_type_t type; + + if (operation->stage != PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + status = psa_get_and_lock_key_slot_with_policy(password, &slot, + PSA_KEY_USAGE_DERIVE, + operation->alg); + if (status != PSA_SUCCESS) { + goto exit; + } + + type = psa_get_key_type(&slot->attr); + + if (type != PSA_KEY_TYPE_PASSWORD && + type != PSA_KEY_TYPE_PASSWORD_HASH) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + operation->data.inputs.password = mbedtls_calloc(1, slot->key.bytes); + if (operation->data.inputs.password == NULL) { + status = PSA_ERROR_INSUFFICIENT_MEMORY; + goto exit; + } + + memcpy(operation->data.inputs.password, slot->key.data, slot->key.bytes); + operation->data.inputs.password_len = slot->key.bytes; + operation->data.inputs.attributes = slot->attr; + +exit: + if (status != PSA_SUCCESS) { + psa_pake_abort(operation); + } + unlock_status = psa_unregister_read_under_mutex(slot); + return (status == PSA_SUCCESS) ? unlock_status : status; +} + +psa_status_t psa_pake_setup( + psa_pake_operation_t *operation, + mbedtls_svc_key_id_t password_key, + const psa_pake_cipher_suite_t *cipher_suite) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (operation->stage != PSA_PAKE_OPERATION_STAGE_SETUP) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (PSA_ALG_IS_PAKE(cipher_suite->algorithm) == 0) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + /* Make sure the variable-purpose part of the operation is zeroed. + * Initializing the operation does not necessarily take care of it, + * since the context is a union and initializing a union does not + * necessarily initialize all of its members. */ + memset(&operation->data, 0, sizeof(operation->data)); + + operation->alg = cipher_suite->algorithm; + operation->primitive = PSA_PAKE_PRIMITIVE(cipher_suite->type, + cipher_suite->family, cipher_suite->bits); + operation->data.inputs.cipher_suite = *cipher_suite; + +#if defined(PSA_WANT_ALG_JPAKE) + if (PSA_ALG_IS_JPAKE(operation->alg)) { + psa_jpake_computation_stage_t *computation_stage = + &operation->computation_stage.jpake; + + memset(computation_stage, 0, sizeof(*computation_stage)); + computation_stage->step = PSA_PAKE_STEP_KEY_SHARE; + } else +#endif /* PSA_WANT_ALG_JPAKE */ + { + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; + } + + operation->stage = PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS; + + return psa_pake_set_password_key(operation, password_key); +exit: + psa_pake_abort(operation); + return status; +} + +psa_status_t psa_pake_set_user( + psa_pake_operation_t *operation, + const uint8_t *user_id_external, + size_t user_id_len) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_INPUT_DECLARE(user_id_external, user_id); + + if (operation->stage != PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (user_id_len == 0) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + if (operation->data.inputs.user_len != 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + operation->data.inputs.user = mbedtls_calloc(1, user_id_len); + if (operation->data.inputs.user == NULL) { + status = PSA_ERROR_INSUFFICIENT_MEMORY; + goto exit; + } + + LOCAL_INPUT_ALLOC(user_id_external, user_id_len, user_id); + + memcpy(operation->data.inputs.user, user_id, user_id_len); + operation->data.inputs.user_len = user_id_len; + + status = PSA_SUCCESS; + +exit: + LOCAL_INPUT_FREE(user_id_external, user_id); + if (status != PSA_SUCCESS) { + psa_pake_abort(operation); + } + return status; +} + +psa_status_t psa_pake_set_peer( + psa_pake_operation_t *operation, + const uint8_t *peer_id_external, + size_t peer_id_len) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + LOCAL_INPUT_DECLARE(peer_id_external, peer_id); + + if (operation->stage != PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (peer_id_len == 0) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + if (operation->data.inputs.peer_len != 0) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + operation->data.inputs.peer = mbedtls_calloc(1, peer_id_len); + if (operation->data.inputs.peer == NULL) { + status = PSA_ERROR_INSUFFICIENT_MEMORY; + goto exit; + } + + LOCAL_INPUT_ALLOC(peer_id_external, peer_id_len, peer_id); + + memcpy(operation->data.inputs.peer, peer_id, peer_id_len); + operation->data.inputs.peer_len = peer_id_len; + + status = PSA_SUCCESS; + +exit: + LOCAL_INPUT_FREE(peer_id_external, peer_id); + if (status != PSA_SUCCESS) { + psa_pake_abort(operation); + } + return status; +} + +psa_status_t psa_pake_set_role( + psa_pake_operation_t *operation, + psa_pake_role_t role) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (operation->stage != PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + +#if defined(PSA_WANT_ALG_JPAKE) + if (PSA_ALG_IS_JPAKE(operation->alg)) { + if (role == PSA_PAKE_ROLE_NONE) { + return PSA_SUCCESS; + } + status = PSA_ERROR_INVALID_ARGUMENT; + } else +#endif + { + (void) role; + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; + } +exit: + psa_pake_abort(operation); + return status; +} + +psa_status_t psa_pake_set_context( + psa_pake_operation_t *operation, + const uint8_t *context, size_t context_len) +{ + (void) operation; + (void) context; + (void) context_len; + return PSA_ERROR_NOT_SUPPORTED; +} + +/* Auxiliary function to convert core computation stage to single driver step. */ +#if defined(PSA_WANT_ALG_JPAKE) +static psa_crypto_driver_pake_step_t convert_jpake_computation_stage_to_driver_step( + psa_jpake_computation_stage_t *stage) +{ + psa_crypto_driver_pake_step_t key_share_step; + if (stage->round == PSA_JPAKE_FIRST) { + int is_x1; + + if (stage->io_mode == PSA_JPAKE_OUTPUT) { + is_x1 = (stage->outputs < 1); + } else { + is_x1 = (stage->inputs < 1); + } + + key_share_step = is_x1 ? + PSA_JPAKE_X1_STEP_KEY_SHARE : + PSA_JPAKE_X2_STEP_KEY_SHARE; + } else if (stage->round == PSA_JPAKE_SECOND) { + key_share_step = (stage->io_mode == PSA_JPAKE_OUTPUT) ? + PSA_JPAKE_X2S_STEP_KEY_SHARE : + PSA_JPAKE_X4S_STEP_KEY_SHARE; + } else { + return PSA_JPAKE_STEP_INVALID; + } + return (psa_crypto_driver_pake_step_t) (key_share_step + stage->step - PSA_PAKE_STEP_KEY_SHARE); +} +#endif /* PSA_WANT_ALG_JPAKE */ + +static psa_status_t psa_pake_complete_inputs( + psa_pake_operation_t *operation) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + /* Create copy of the inputs on stack as inputs share memory + with the driver context which will be setup by the driver. */ + psa_crypto_driver_pake_inputs_t inputs = operation->data.inputs; + + if (inputs.password_len == 0) { + return PSA_ERROR_BAD_STATE; + } + + if (PSA_ALG_IS_JPAKE(operation->alg)) { + if (inputs.user_len == 0 || inputs.peer_len == 0) { + return PSA_ERROR_BAD_STATE; + } + } + + /* Clear driver context */ + mbedtls_platform_zeroize(&operation->data, sizeof(operation->data)); + + status = psa_driver_wrapper_pake_setup(operation, &inputs); + + /* Driver is responsible for creating its own copy of the password. */ + mbedtls_zeroize_and_free(inputs.password, inputs.password_len); + + /* User and peer are translated to role. */ + mbedtls_free(inputs.user); + mbedtls_free(inputs.peer); + + if (status == PSA_SUCCESS) { +#if defined(PSA_WANT_ALG_JPAKE) + if (PSA_ALG_IS_JPAKE(operation->alg)) { + operation->stage = PSA_PAKE_OPERATION_STAGE_COMPUTATION; + } else +#endif /* PSA_WANT_ALG_JPAKE */ + { + status = PSA_ERROR_NOT_SUPPORTED; + } + } + return status; +} + +#if defined(PSA_WANT_ALG_JPAKE) +static psa_status_t psa_jpake_prologue( + psa_pake_operation_t *operation, + psa_pake_step_t step, + psa_jpake_io_mode_t io_mode) +{ + if (step != PSA_PAKE_STEP_KEY_SHARE && + step != PSA_PAKE_STEP_ZK_PUBLIC && + step != PSA_PAKE_STEP_ZK_PROOF) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + psa_jpake_computation_stage_t *computation_stage = + &operation->computation_stage.jpake; + + if (computation_stage->round != PSA_JPAKE_FIRST && + computation_stage->round != PSA_JPAKE_SECOND) { + return PSA_ERROR_BAD_STATE; + } + + /* Check that the step we are given is the one we were expecting */ + if (step != computation_stage->step) { + return PSA_ERROR_BAD_STATE; + } + + if (step == PSA_PAKE_STEP_KEY_SHARE && + computation_stage->inputs == 0 && + computation_stage->outputs == 0) { + /* Start of the round, so function decides whether we are inputting + * or outputting */ + computation_stage->io_mode = io_mode; + } else if (computation_stage->io_mode != io_mode) { + /* Middle of the round so the mode we are in must match the function + * called by the user */ + return PSA_ERROR_BAD_STATE; + } + + return PSA_SUCCESS; +} + +static psa_status_t psa_jpake_epilogue( + psa_pake_operation_t *operation, + psa_jpake_io_mode_t io_mode) +{ + psa_jpake_computation_stage_t *stage = + &operation->computation_stage.jpake; + + if (stage->step == PSA_PAKE_STEP_ZK_PROOF) { + /* End of an input/output */ + if (io_mode == PSA_JPAKE_INPUT) { + stage->inputs++; + if (stage->inputs == PSA_JPAKE_EXPECTED_INPUTS(stage->round)) { + stage->io_mode = PSA_JPAKE_OUTPUT; + } + } + if (io_mode == PSA_JPAKE_OUTPUT) { + stage->outputs++; + if (stage->outputs == PSA_JPAKE_EXPECTED_OUTPUTS(stage->round)) { + stage->io_mode = PSA_JPAKE_INPUT; + } + } + if (stage->inputs == PSA_JPAKE_EXPECTED_INPUTS(stage->round) && + stage->outputs == PSA_JPAKE_EXPECTED_OUTPUTS(stage->round)) { + /* End of a round, move to the next round */ + stage->inputs = 0; + stage->outputs = 0; + stage->round++; + } + stage->step = PSA_PAKE_STEP_KEY_SHARE; + } else { + stage->step++; + } + return PSA_SUCCESS; +} + +#endif /* PSA_WANT_ALG_JPAKE */ + +psa_status_t psa_pake_output( + psa_pake_operation_t *operation, + psa_pake_step_t step, + uint8_t *output_external, + size_t output_size, + size_t *output_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_crypto_driver_pake_step_t driver_step = PSA_JPAKE_STEP_INVALID; + LOCAL_OUTPUT_DECLARE(output_external, output); + *output_length = 0; + + if (operation->stage == PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) { + status = psa_pake_complete_inputs(operation); + if (status != PSA_SUCCESS) { + goto exit; + } + } + + if (operation->stage != PSA_PAKE_OPERATION_STAGE_COMPUTATION) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (output_size == 0) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + +#if defined(PSA_WANT_ALG_JPAKE) + if (PSA_ALG_IS_JPAKE(operation->alg)) { + status = psa_jpake_prologue(operation, step, PSA_JPAKE_OUTPUT); + if (status != PSA_SUCCESS) { + goto exit; + } + driver_step = convert_jpake_computation_stage_to_driver_step( + &operation->computation_stage.jpake); + } else +#endif /* PSA_WANT_ALG_JPAKE */ + { + (void) step; + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; + } + + LOCAL_OUTPUT_ALLOC(output_external, output_size, output); + + status = psa_driver_wrapper_pake_output(operation, driver_step, + output, output_size, output_length); + + if (status != PSA_SUCCESS) { + goto exit; + } + +#if defined(PSA_WANT_ALG_JPAKE) + if (PSA_ALG_IS_JPAKE(operation->alg)) { + status = psa_jpake_epilogue(operation, PSA_JPAKE_OUTPUT); + if (status != PSA_SUCCESS) { + goto exit; + } + } else +#endif /* PSA_WANT_ALG_JPAKE */ + { + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; + } + +exit: + LOCAL_OUTPUT_FREE(output_external, output); + if (status != PSA_SUCCESS) { + psa_pake_abort(operation); + } + return status; +} + +psa_status_t psa_pake_input( + psa_pake_operation_t *operation, + psa_pake_step_t step, + const uint8_t *input_external, + size_t input_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_crypto_driver_pake_step_t driver_step = PSA_JPAKE_STEP_INVALID; + const size_t max_input_length = (size_t) PSA_PAKE_INPUT_SIZE(operation->alg, + operation->primitive, + step); + LOCAL_INPUT_DECLARE(input_external, input); + + if (operation->stage == PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) { + status = psa_pake_complete_inputs(operation); + if (status != PSA_SUCCESS) { + goto exit; + } + } + + if (operation->stage != PSA_PAKE_OPERATION_STAGE_COMPUTATION) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + + if (input_length == 0 || input_length > max_input_length) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + +#if defined(PSA_WANT_ALG_JPAKE) + if (PSA_ALG_IS_JPAKE(operation->alg)) { + status = psa_jpake_prologue(operation, step, PSA_JPAKE_INPUT); + if (status != PSA_SUCCESS) { + goto exit; + } + driver_step = convert_jpake_computation_stage_to_driver_step( + &operation->computation_stage.jpake); + } else +#endif /* PSA_WANT_ALG_JPAKE */ + { + (void) step; + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; + } + + LOCAL_INPUT_ALLOC(input_external, input_length, input); + status = psa_driver_wrapper_pake_input(operation, driver_step, + input, input_length); + + if (status != PSA_SUCCESS) { + goto exit; + } + +#if defined(PSA_WANT_ALG_JPAKE) + if (PSA_ALG_IS_JPAKE(operation->alg)) { + status = psa_jpake_epilogue(operation, PSA_JPAKE_INPUT); + if (status != PSA_SUCCESS) { + goto exit; + } + } else +#endif /* PSA_WANT_ALG_JPAKE */ + { + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; + } + +exit: + LOCAL_INPUT_FREE(input_external, input); + if (status != PSA_SUCCESS) { + psa_pake_abort(operation); + } + return status; +} + +psa_status_t psa_pake_get_shared_key(psa_pake_operation_t *operation, + const psa_key_attributes_t *attributes, + mbedtls_svc_key_id_t *key) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t abort_status = PSA_ERROR_CORRUPTION_DETECTED; + uint8_t shared_key[MBEDTLS_PSA_JPAKE_BUFFER_SIZE]; + size_t shared_key_len = 0; + + if (operation->stage != PSA_PAKE_OPERATION_STAGE_COMPUTATION) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + +#if defined(PSA_WANT_ALG_JPAKE) + if (PSA_ALG_IS_JPAKE(operation->alg)) { + psa_jpake_computation_stage_t *computation_stage = + &operation->computation_stage.jpake; + if (computation_stage->round != PSA_JPAKE_FINISHED) { + status = PSA_ERROR_BAD_STATE; + goto exit; + } + } else +#endif /* PSA_WANT_ALG_JPAKE */ + { + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; + } + + status = psa_driver_wrapper_pake_get_shared_key(operation, + shared_key, + sizeof(shared_key), + &shared_key_len); + + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_import_key(attributes, shared_key, shared_key_len, key); + +exit: + + if (status != PSA_SUCCESS) { + *key = MBEDTLS_SVC_KEY_ID_INIT; + } + + abort_status = psa_pake_abort(operation); + + return status == PSA_SUCCESS ? abort_status : status; +} + +psa_status_t psa_pake_abort( + psa_pake_operation_t *operation) +{ + psa_status_t status = PSA_SUCCESS; + + if (operation->stage == PSA_PAKE_OPERATION_STAGE_COMPUTATION) { + status = psa_driver_wrapper_pake_abort(operation); + } + + if (operation->stage == PSA_PAKE_OPERATION_STAGE_COLLECT_INPUTS) { + if (operation->data.inputs.password != NULL) { + mbedtls_zeroize_and_free(operation->data.inputs.password, + operation->data.inputs.password_len); + } + if (operation->data.inputs.user != NULL) { + mbedtls_free(operation->data.inputs.user); + } + if (operation->data.inputs.peer != NULL) { + mbedtls_free(operation->data.inputs.peer); + } + } + memset(operation, 0, sizeof(psa_pake_operation_t)); + + return status; +} +#endif /* PSA_WANT_ALG_SOME_PAKE */ + +/* Memory copying test hooks. These are called before input copy, after input + * copy, before output copy and after output copy, respectively. + * They are used by memory-poisoning tests to temporarily unpoison buffers + * while they are copied. */ +#if defined(MBEDTLS_TEST_HOOKS) +void (*psa_input_pre_copy_hook)(const uint8_t *input, size_t input_len) = NULL; +void (*psa_input_post_copy_hook)(const uint8_t *input, size_t input_len) = NULL; +void (*psa_output_pre_copy_hook)(const uint8_t *output, size_t output_len) = NULL; +void (*psa_output_post_copy_hook)(const uint8_t *output, size_t output_len) = NULL; +#endif + +/** Copy from an input buffer to a local copy. + * + * \param[in] input Pointer to input buffer. + * \param[in] input_len Length of the input buffer. + * \param[out] input_copy Pointer to a local copy in which to store the input data. + * \param[out] input_copy_len Length of the local copy buffer. + * \return #PSA_SUCCESS, if the buffer was successfully + * copied. + * \return #PSA_ERROR_CORRUPTION_DETECTED, if the local + * copy is too small to hold contents of the + * input buffer. + */ +MBEDTLS_STATIC_TESTABLE +psa_status_t psa_crypto_copy_input(const uint8_t *input, size_t input_len, + uint8_t *input_copy, size_t input_copy_len) +{ + if (input_len > input_copy_len) { + return PSA_ERROR_CORRUPTION_DETECTED; + } + +#if defined(MBEDTLS_TEST_HOOKS) + if (psa_input_pre_copy_hook != NULL) { + psa_input_pre_copy_hook(input, input_len); + } +#endif + + if (input_len > 0) { + memcpy(input_copy, input, input_len); + } + +#if defined(MBEDTLS_TEST_HOOKS) + if (psa_input_post_copy_hook != NULL) { + psa_input_post_copy_hook(input, input_len); + } +#endif + + return PSA_SUCCESS; +} + +/** Copy from a local output buffer into a user-supplied one. + * + * \param[in] output_copy Pointer to a local buffer containing the output. + * \param[in] output_copy_len Length of the local buffer. + * \param[out] output Pointer to user-supplied output buffer. + * \param[out] output_len Length of the user-supplied output buffer. + * \return #PSA_SUCCESS, if the buffer was successfully + * copied. + * \return #PSA_ERROR_BUFFER_TOO_SMALL, if the + * user-supplied output buffer is too small to + * hold the contents of the local buffer. + */ +MBEDTLS_STATIC_TESTABLE +psa_status_t psa_crypto_copy_output(const uint8_t *output_copy, size_t output_copy_len, + uint8_t *output, size_t output_len) +{ + if (output_len < output_copy_len) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + +#if defined(MBEDTLS_TEST_HOOKS) + if (psa_output_pre_copy_hook != NULL) { + psa_output_pre_copy_hook(output, output_len); + } +#endif + + if (output_copy_len > 0) { + memcpy(output, output_copy, output_copy_len); + } + +#if defined(MBEDTLS_TEST_HOOKS) + if (psa_output_post_copy_hook != NULL) { + psa_output_post_copy_hook(output, output_len); + } +#endif + + return PSA_SUCCESS; +} + +psa_status_t psa_crypto_local_input_alloc(const uint8_t *input, size_t input_len, + psa_crypto_local_input_t *local_input) +{ + psa_status_t status; + + *local_input = PSA_CRYPTO_LOCAL_INPUT_INIT; + + if (input_len == 0) { + return PSA_SUCCESS; + } + + local_input->buffer = mbedtls_calloc(input_len, 1); + if (local_input->buffer == NULL) { + /* Since we dealt with the zero-length case above, we know that + * a NULL return value means a failure of allocation. */ + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + /* From now on, we must free local_input->buffer on error. */ + + local_input->length = input_len; + + status = psa_crypto_copy_input(input, input_len, + local_input->buffer, local_input->length); + if (status != PSA_SUCCESS) { + goto error; + } + + return PSA_SUCCESS; + +error: + mbedtls_zeroize_and_free(local_input->buffer, local_input->length); + local_input->buffer = NULL; + local_input->length = 0; + return status; +} + +void psa_crypto_local_input_free(psa_crypto_local_input_t *local_input) +{ + mbedtls_zeroize_and_free(local_input->buffer, local_input->length); + local_input->buffer = NULL; + local_input->length = 0; +} + +psa_status_t psa_crypto_local_output_alloc(uint8_t *output, size_t output_len, + psa_crypto_local_output_t *local_output) +{ + *local_output = PSA_CRYPTO_LOCAL_OUTPUT_INIT; + + if (output_len == 0) { + return PSA_SUCCESS; + } + local_output->buffer = mbedtls_calloc(output_len, 1); + if (local_output->buffer == NULL) { + /* Since we dealt with the zero-length case above, we know that + * a NULL return value means a failure of allocation. */ + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + local_output->length = output_len; + local_output->original = output; + + return PSA_SUCCESS; +} + +psa_status_t psa_crypto_local_output_free(psa_crypto_local_output_t *local_output) +{ + psa_status_t status; + + if (local_output->buffer == NULL) { + local_output->length = 0; + return PSA_SUCCESS; + } + if (local_output->original == NULL) { + /* We have an internal copy but nothing to copy back to. */ + return PSA_ERROR_CORRUPTION_DETECTED; + } + + status = psa_crypto_copy_output(local_output->buffer, local_output->length, + local_output->original, local_output->length); + if (status != PSA_SUCCESS) { + return status; + } + + mbedtls_zeroize_and_free(local_output->buffer, local_output->length); + local_output->buffer = NULL; + local_output->length = 0; + + return PSA_SUCCESS; +} + +#endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/tf-psa-crypto/core/psa_crypto_client.c b/tf-psa-crypto/core/psa_crypto_client.c new file mode 100644 index 0000000000..b0b615e726 --- /dev/null +++ b/tf-psa-crypto/core/psa_crypto_client.c @@ -0,0 +1,22 @@ +/* + * PSA crypto client code + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" +#include "psa/crypto.h" + +#if defined(MBEDTLS_PSA_CRYPTO_CLIENT) + +#include +#include "mbedtls/platform.h" + +void psa_reset_key_attributes(psa_key_attributes_t *attributes) +{ + memset(attributes, 0, sizeof(*attributes)); +} + +#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */ diff --git a/tf-psa-crypto/core/psa_crypto_core.h b/tf-psa-crypto/core/psa_crypto_core.h new file mode 100644 index 0000000000..5a7b48083e --- /dev/null +++ b/tf-psa-crypto/core/psa_crypto_core.h @@ -0,0 +1,972 @@ +/* + * PSA crypto core internal interfaces + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_CORE_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_CORE_H + +#include "tf-psa-crypto/build_info.h" + +#include "psa/crypto.h" +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +typedef enum { + PSA_SLOT_EMPTY = 0, + PSA_SLOT_FILLING, + PSA_SLOT_FULL, + PSA_SLOT_PENDING_DELETION, +} psa_key_slot_state_t; + +/** The data structure representing a key slot, containing key material + * and metadata for one key. + */ +typedef struct { + /* This field is accessed in a lot of places. Putting it first + * reduces the code size. */ + psa_key_attributes_t attr; + + /* + * The current state of the key slot, as described in + * docs/architecture/psa-thread-safety/psa-thread-safety.md. + * + * Library functions can modify the state of a key slot by calling + * psa_key_slot_state_transition. + * + * The state variable is used to help determine whether library functions + * which operate on the slot succeed. For example, psa_finish_key_creation, + * which transfers the state of a slot from PSA_SLOT_FILLING to + * PSA_SLOT_FULL, must fail with error code PSA_ERROR_CORRUPTION_DETECTED + * if the state of the slot is not PSA_SLOT_FILLING. + * + * Library functions which traverse the array of key slots only consider + * slots that are in a suitable state for the function. + * For example, psa_get_and_lock_key_slot_in_memory, which finds a slot + * containing a given key ID, will only check slots whose state variable is + * PSA_SLOT_FULL. + */ + psa_key_slot_state_t state; + +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) + /* The index of the slice containing this slot. + * This field must be filled if the slot contains a key + * (including keys being created or destroyed), and can be either + * filled or 0 when the slot is free. + * + * In most cases, the slice index can be deduced from the key identifer. + * We keep it in a separate field for robustness (it reduces the chance + * that a coding mistake in the key store will result in accessing the + * wrong slice), and also so that it's available even on code paths + * during creation or destruction where the key identifier might not be + * filled in. + * */ + uint8_t slice_index; +#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + + union { + struct { + /* The index of the next slot in the free list for this + * slice, relative * to the next array element. + * + * That is, 0 means the next slot, 1 means the next slot + * but one, etc. -1 would mean the slot itself. -2 means + * the previous slot, etc. + * + * If this is beyond the array length, the free list ends with the + * current element. + * + * The reason for this strange encoding is that 0 means the next + * element. This way, when we allocate a slice and initialize it + * to all-zero, the slice is ready for use, with a free list that + * consists of all the slots in order. + */ + int32_t next_free_relative_to_next; + } free; + + struct { + /* + * Number of functions registered as reading the material in the key slot. + * + * Library functions must not write directly to registered_readers + * + * A function must call psa_register_read(slot) before reading + * the current contents of the slot for an operation. + * They then must call psa_unregister_read(slot) once they have + * finished reading the current contents of the slot. If the key + * slot mutex is not held (when mutexes are enabled), this call + * must be done via a call to + * psa_unregister_read_under_mutex(slot). + * A function must call psa_key_slot_has_readers(slot) to check if + * the slot is in use for reading. + * + * This counter is used to prevent resetting the key slot while + * the library may access it. For example, such control is needed + * in the following scenarios: + * . In case of key slot starvation, all key slots contain the + * description of a key, and the library asks for the + * description of a persistent key not present in the + * key slots, the key slots currently accessed by the + * library cannot be reclaimed to free a key slot to load + * the persistent key. + * . In case of a multi-threaded application where one thread + * asks to close or purge or destroy a key while it is in use + * by the library through another thread. */ + size_t registered_readers; + } occupied; + } var; + + /* Dynamically allocated key data buffer. + * Format as specified in psa_export_key(). */ + struct key_data { +#if defined(MBEDTLS_PSA_STATIC_KEY_SLOTS) + uint8_t data[MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE]; +#else + uint8_t *data; +#endif + size_t bytes; + } key; +} psa_key_slot_t; + +#if defined(MBEDTLS_THREADING_C) + +/** Perform a mutex operation and return immediately upon failure. + * + * Returns PSA_ERROR_SERVICE_FAILURE if the operation fails + * and status was PSA_SUCCESS. + * + * Assumptions: + * psa_status_t status exists. + * f is a mutex operation which returns 0 upon success. + */ +#define PSA_THREADING_CHK_RET(f) \ + do \ + { \ + if ((f) != 0) { \ + if (status == PSA_SUCCESS) { \ + return PSA_ERROR_SERVICE_FAILURE; \ + } \ + return status; \ + } \ + } while (0); + +/** Perform a mutex operation and goto exit on failure. + * + * Sets status to PSA_ERROR_SERVICE_FAILURE if status was PSA_SUCCESS. + * + * Assumptions: + * psa_status_t status exists. + * Label exit: exists. + * f is a mutex operation which returns 0 upon success. + */ +#define PSA_THREADING_CHK_GOTO_EXIT(f) \ + do \ + { \ + if ((f) != 0) { \ + if (status == PSA_SUCCESS) { \ + status = PSA_ERROR_SERVICE_FAILURE; \ + } \ + goto exit; \ + } \ + } while (0); +#endif + +/** Test whether a key slot has any registered readers. + * If multi-threading is enabled, the caller must hold the + * global key slot mutex. + * + * \param[in] slot The key slot to test. + * + * \return 1 if the slot has any registered readers, 0 otherwise. + */ +static inline int psa_key_slot_has_readers(const psa_key_slot_t *slot) +{ + return slot->var.occupied.registered_readers > 0; +} + +/** Completely wipe a slot in memory, including its policy. + * + * Persistent storage is not affected. + * Sets the slot's state to PSA_SLOT_EMPTY. + * If multi-threading is enabled, the caller must hold the + * global key slot mutex. + * + * \param[in,out] slot The key slot to wipe. + * + * \retval #PSA_SUCCESS + * The slot has been successfully wiped. + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * The slot's state was PSA_SLOT_FULL or PSA_SLOT_PENDING_DELETION, and + * the amount of registered readers was not equal to 1. Or, + * the slot's state was PSA_SLOT_EMPTY. Or, + * the slot's state was PSA_SLOT_FILLING, and the amount + * of registered readers was not equal to 0. + */ +psa_status_t psa_wipe_key_slot(psa_key_slot_t *slot); + +/** Try to allocate a buffer to an empty key slot. + * + * \param[in,out] slot Key slot to attach buffer to. + * \param[in] buffer_length Requested size of the buffer. + * + * \retval #PSA_SUCCESS + * The buffer has been successfully allocated. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * Not enough memory was available for allocation. + * \retval #PSA_ERROR_ALREADY_EXISTS + * Trying to allocate a buffer to a non-empty key slot. + */ +psa_status_t psa_allocate_buffer_to_slot(psa_key_slot_t *slot, + size_t buffer_length); + +/** Wipe key data from a slot. Preserves metadata such as the policy. */ +psa_status_t psa_remove_key_data_from_memory(psa_key_slot_t *slot); + +/** Copy key data (in export format) into an empty key slot. + * + * This function assumes that the slot does not contain + * any key material yet. On failure, the slot content is unchanged. + * + * \param[in,out] slot Key slot to copy the key into. + * \param[in] data Buffer containing the key material. + * \param data_length Size of the key buffer. + * + * \retval #PSA_SUCCESS + * The key has been copied successfully. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * Not enough memory was available for allocation of the + * copy buffer. + * \retval #PSA_ERROR_ALREADY_EXISTS + * There was other key material already present in the slot. + */ +psa_status_t psa_copy_key_material_into_slot(psa_key_slot_t *slot, + const uint8_t *data, + size_t data_length); + +/** Convert an Mbed TLS error code to a PSA error code + * + * \note This function is provided solely for the convenience of + * Mbed TLS and may be removed at any time without notice. + * + * \param ret An Mbed TLS-thrown error code + * + * \return The corresponding PSA error code + */ +psa_status_t mbedtls_to_psa_error(int ret); + +/** Whether PSA is ready for a cipher operation. + * + * This is a legacy concept inherited from "driver-only" work in Mbed TLS 3.x. + * The block_cipher module uses this to determine whether to call a legacy + * module directly. This is necessary in some builds involving drivers, where + * the PSA RNG is powered by CTR_DRBG, but AES is not accelerated. This is + * an implementation kludge that should be fixed. + * https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/469 + */ +int psa_is_ready_for_cipher(void); + +/** Import a key in binary format. + * + * \note The signature of this function is that of a PSA driver + * import_key entry point. This function behaves as an import_key + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \param[in] attributes The attributes for the key to import. + * \param[in] data The buffer containing the key data in import + * format. + * \param[in] data_length Size of the \p data buffer in bytes. + * \param[out] key_buffer The buffer to contain the key data in output + * format upon successful return. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. This + * size is greater or equal to \p data_length. + * \param[out] key_buffer_length The length of the data written in \p + * key_buffer in bytes. + * \param[out] bits The key size in number of bits. + * + * \retval #PSA_SUCCESS The key was imported successfully. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The key data is not correctly formatted. + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t psa_import_key_into_slot( + const psa_key_attributes_t *attributes, + const uint8_t *data, size_t data_length, + uint8_t *key_buffer, size_t key_buffer_size, + size_t *key_buffer_length, size_t *bits); + +/** Export a key in binary format + * + * \note The signature of this function is that of a PSA driver export_key + * entry point. This function behaves as an export_key entry point as + * defined in the PSA driver interface specification. + * + * \param[in] attributes The attributes for the key to export. + * \param[in] key_buffer Material or context of the key to export. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[out] data Buffer where the key data is to be written. + * \param[in] data_size Size of the \p data buffer in bytes. + * \param[out] data_length On success, the number of bytes written in + * \p data + * + * \retval #PSA_SUCCESS The key was exported successfully. + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription + * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + */ +psa_status_t psa_export_key_internal( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + uint8_t *data, size_t data_size, size_t *data_length); + +/** Export a public key or the public part of a key pair in binary format. + * + * \note The signature of this function is that of a PSA driver + * export_public_key entry point. This function behaves as an + * export_public_key entry point as defined in the PSA driver interface + * specification. + * + * \param[in] attributes The attributes for the key to export. + * \param[in] key_buffer Material or context of the key to export. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[out] data Buffer where the key data is to be written. + * \param[in] data_size Size of the \p data buffer in bytes. + * \param[out] data_length On success, the number of bytes written in + * \p data + * + * \retval #PSA_SUCCESS The public key was exported successfully. + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription + * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + */ +psa_status_t psa_export_public_key_internal( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + uint8_t *data, size_t data_size, size_t *data_length); + +/** Whether a key custom production parameters structure is the default. + * + * Calls to a key generation driver with non-default custom production parameters + * require a driver supporting custom production parameters. + * + * \param[in] custom The key custom production parameters to check. + * \param custom_data_length Size of the associated variable-length data + * in bytes. + */ +int psa_custom_key_parameters_are_default( + const psa_custom_key_parameters_t *custom, + size_t custom_data_length); + +/** + * \brief Generate a key. + * + * \note The signature of the function is that of a PSA driver generate_key + * entry point. + * + * \param[in] attributes The attributes for the key to generate. + * \param[in] custom Custom parameters for the key generation. + * \param[in] custom_data Variable-length data associated with \c custom. + * \param custom_data_length Length of `custom_data` in bytes. + * \param[out] key_buffer Buffer where the key data is to be written. + * \param[in] key_buffer_size Size of \p key_buffer in bytes. + * \param[out] key_buffer_length On success, the number of bytes written in + * \p key_buffer. + * + * \retval #PSA_SUCCESS + * The key was generated successfully. + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_NOT_SUPPORTED + * Key size in bits or type not supported. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of \p key_buffer is too small. + */ +psa_status_t psa_generate_key_internal(const psa_key_attributes_t *attributes, + const psa_custom_key_parameters_t *custom, + const uint8_t *custom_data, + size_t custom_data_length, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length); + +/** Sign a message with a private key. For hash-and-sign algorithms, + * this includes the hashing step. + * + * \note The signature of this function is that of a PSA driver + * sign_message entry point. This function behaves as a sign_message + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \note This function will call the driver for psa_sign_hash + * and go through driver dispatch again. + * + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key context. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] alg A signature algorithm that is compatible with + * the type of the key. + * \param[in] input The input message to sign. + * \param[in] input_length Size of the \p input buffer in bytes. + * \param[out] signature Buffer where the signature is to be written. + * \param[in] signature_size Size of the \p signature buffer in bytes. + * \param[out] signature_length On success, the number of bytes + * that make up the returned signature value. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p signature buffer is too small. You can + * determine a sufficient buffer size by calling + * #PSA_SIGN_OUTPUT_SIZE(\c key_type, \c key_bits, \p alg) + * where \c key_type and \c key_bits are the type and bit-size + * respectively of the key. + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY \emptydescription + */ +psa_status_t psa_sign_message_builtin( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *input, size_t input_length, + uint8_t *signature, size_t signature_size, size_t *signature_length); + +/** Verify the signature of a message with a public key, using + * a hash-and-sign verification algorithm. + * + * \note The signature of this function is that of a PSA driver + * verify_message entry point. This function behaves as a verify_message + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \note This function will call the driver for psa_verify_hash + * and go through driver dispatch again. + * + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key context. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] alg A signature algorithm that is compatible with + * the type of the key. + * \param[in] input The message whose signature is to be verified. + * \param[in] input_length Size of the \p input buffer in bytes. + * \param[in] signature Buffer containing the signature to verify. + * \param[in] signature_length Size of the \p signature buffer in bytes. + * + * \retval #PSA_SUCCESS + * The signature is valid. + * \retval #PSA_ERROR_INVALID_SIGNATURE + * The calculation was performed successfully, but the passed + * signature is not a valid signature. + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + */ +psa_status_t psa_verify_message_builtin( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *input, size_t input_length, + const uint8_t *signature, size_t signature_length); + +/** Sign an already-calculated hash with a private key. + * + * \note The signature of this function is that of a PSA driver + * sign_hash entry point. This function behaves as a sign_hash + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key context. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] alg A signature algorithm that is compatible with + * the type of the key. + * \param[in] hash The hash or message to sign. + * \param[in] hash_length Size of the \p hash buffer in bytes. + * \param[out] signature Buffer where the signature is to be written. + * \param[in] signature_size Size of the \p signature buffer in bytes. + * \param[out] signature_length On success, the number of bytes + * that make up the returned signature value. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p signature buffer is too small. You can + * determine a sufficient buffer size by calling + * #PSA_SIGN_OUTPUT_SIZE(\c key_type, \c key_bits, \p alg) + * where \c key_type and \c key_bits are the type and bit-size + * respectively of the key. + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY \emptydescription + */ +psa_status_t psa_sign_hash_builtin( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *hash, size_t hash_length, + uint8_t *signature, size_t signature_size, size_t *signature_length); + +/** + * \brief Verify the signature a hash or short message using a public key. + * + * \note The signature of this function is that of a PSA driver + * verify_hash entry point. This function behaves as a verify_hash + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key context. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] alg A signature algorithm that is compatible with + * the type of the key. + * \param[in] hash The hash or message whose signature is to be + * verified. + * \param[in] hash_length Size of the \p hash buffer in bytes. + * \param[in] signature Buffer containing the signature to verify. + * \param[in] signature_length Size of the \p signature buffer in bytes. + * + * \retval #PSA_SUCCESS + * The signature is valid. + * \retval #PSA_ERROR_INVALID_SIGNATURE + * The calculation was performed successfully, but the passed + * signature is not a valid signature. + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + */ +psa_status_t psa_verify_hash_builtin( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *hash, size_t hash_length, + const uint8_t *signature, size_t signature_length); + +/** + * \brief Validate the key bit size for unstructured keys. + * + * \note Check that the bit size is acceptable for a given key type for + * unstructured keys. + * + * \param[in] type The key type + * \param[in] bits The number of bits of the key + * + * \retval #PSA_SUCCESS + * The key type and size are valid. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The size in bits of the key is not valid. + * \retval #PSA_ERROR_NOT_SUPPORTED + * The type and/or the size in bits of the key or the combination of + * the two is not supported. + */ +psa_status_t psa_validate_unstructured_key_bit_size(psa_key_type_t type, + size_t bits); + +/** Perform a key agreement and return the raw shared secret, using + built-in raw key agreement functions. + * + * \note The signature of this function is that of a PSA driver + * key_agreement entry point. This function behaves as a key_agreement + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the private key + * context. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in + * bytes. + * \param[in] alg A key agreement algorithm that is + * compatible with the type of the key. + * \param[in] peer_key The buffer containing the key context + * of the peer's public key. + * \param[in] peer_key_length Size of the \p peer_key buffer in + * bytes. + * \param[out] shared_secret The buffer to which the shared secret + * is to be written. + * \param[in] shared_secret_size Size of the \p shared_secret buffer in + * bytes. + * \param[out] shared_secret_length On success, the number of bytes that make + * up the returned shared secret. + * \retval #PSA_SUCCESS + * Success. Shared secret successfully calculated. + * \retval #PSA_ERROR_INVALID_HANDLE \emptydescription + * \retval #PSA_ERROR_NOT_PERMITTED \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \p alg is not a key agreement algorithm, or + * \p private_key is not compatible with \p alg, + * or \p peer_key is not valid for \p alg or not compatible with + * \p private_key. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * \p shared_secret_size is too small + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p alg is not a supported key agreement algorithm. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription + * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription + * \retval #PSA_ERROR_BAD_STATE \emptydescription + */ +psa_status_t psa_key_agreement_raw_builtin( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *peer_key, + size_t peer_key_length, + uint8_t *shared_secret, + size_t shared_secret_size, + size_t *shared_secret_length); + +/** + * \brief Set the maximum number of ops allowed to be executed by an + * interruptible function in a single call. + * + * \note The signature of this function is that of a PSA driver + * interruptible_set_max_ops entry point. This function behaves as an + * interruptible_set_max_ops entry point as defined in the PSA driver + * interface specification for transparent drivers. + * + * \param[in] max_ops The maximum number of ops to be executed in a + * single call, this can be a number from 0 to + * #PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED, where 0 + * is obviously the least amount of work done per + * call. + */ +void mbedtls_psa_interruptible_set_max_ops(uint32_t max_ops); + +/** + * \brief Get the maximum number of ops allowed to be executed by an + * interruptible function in a single call. + * + * \note The signature of this function is that of a PSA driver + * interruptible_get_max_ops entry point. This function behaves as an + * interruptible_get_max_ops entry point as defined in the PSA driver + * interface specification for transparent drivers. + * + * \return Maximum number of ops allowed to be executed + * by an interruptible function in a single call. + */ +uint32_t mbedtls_psa_interruptible_get_max_ops(void); + +/** + * \brief Get the number of ops that a hash signing operation has taken for the + * previous call. If no call or work has taken place, this will return + * zero. + * + * \note The signature of this function is that of a PSA driver + * sign_hash_get_num_ops entry point. This function behaves as an + * sign_hash_get_num_ops entry point as defined in the PSA driver + * interface specification for transparent drivers. + * + * \param operation The \c + * mbedtls_psa_sign_hash_interruptible_operation_t + * to use. This must be initialized first. + * + * \return Number of ops that were completed + * in the last call to \c + * mbedtls_psa_sign_hash_complete(). + */ +uint32_t mbedtls_psa_sign_hash_get_num_ops( + const mbedtls_psa_sign_hash_interruptible_operation_t *operation); + +/** + * \brief Get the number of ops that a hash verification operation has taken for + * the previous call. If no call or work has taken place, this will + * return zero. + * + * \note The signature of this function is that of a PSA driver + * verify_hash_get_num_ops entry point. This function behaves as an + * verify_hash_get_num_ops entry point as defined in the PSA driver + * interface specification for transparent drivers. + * + * \param operation The \c + * mbedtls_psa_verify_hash_interruptible_operation_t + * to use. This must be initialized first. + * + * \return Number of ops that were completed + * in the last call to \c + * mbedtls_psa_verify_hash_complete(). + */ +uint32_t mbedtls_psa_verify_hash_get_num_ops( + const mbedtls_psa_verify_hash_interruptible_operation_t *operation); + +/** + * \brief Start signing a hash or short message with a private key, in an + * interruptible manner. + * + * \note The signature of this function is that of a PSA driver + * sign_hash_start entry point. This function behaves as a + * sign_hash_start entry point as defined in the PSA driver interface + * specification for transparent drivers. + * + * \param[in] operation The \c + * mbedtls_psa_sign_hash_interruptible_operation_t + * to use. This must be initialized first. + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key context. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] alg A signature algorithm that is compatible with + * the type of the key. + * \param[in] hash The hash or message to sign. + * \param hash_length Size of the \p hash buffer in bytes. + * + * \retval #PSA_SUCCESS + * The operation started successfully - call \c psa_sign_hash_complete() + * with the same context to complete the operation + * \retval #PSA_ERROR_INVALID_ARGUMENT + * An unsupported, incorrectly formatted or incorrect type of key was + * used. + * \retval #PSA_ERROR_NOT_SUPPORTED Either no internal interruptible operations + * are currently supported, or the key type is currently unsupported. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * There was insufficient memory to load the key representation. + */ +psa_status_t mbedtls_psa_sign_hash_start( + mbedtls_psa_sign_hash_interruptible_operation_t *operation, + const psa_key_attributes_t *attributes, const uint8_t *key_buffer, + size_t key_buffer_size, psa_algorithm_t alg, + const uint8_t *hash, size_t hash_length); + +/** + * \brief Continue and eventually complete the action of signing a hash or + * short message with a private key, in an interruptible manner. + * + * \note The signature of this function is that of a PSA driver + * sign_hash_complete entry point. This function behaves as a + * sign_hash_complete entry point as defined in the PSA driver interface + * specification for transparent drivers. + * + * \param[in] operation The \c + * mbedtls_psa_sign_hash_interruptible_operation_t + * to use. This must be initialized first. + * + * \param[out] signature Buffer where the signature is to be written. + * \param signature_size Size of the \p signature buffer in bytes. This + * must be appropriate for the selected + * algorithm and key. + * \param[out] signature_length On success, the number of bytes that make up + * the returned signature value. + * + * \retval #PSA_SUCCESS + * Operation completed successfully + * + * \retval #PSA_OPERATION_INCOMPLETE + * Operation was interrupted due to the setting of \c + * psa_interruptible_set_max_ops(), there is still work to be done, + * please call this function again with the same operation object. + * + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p signature buffer is too small. You can + * determine a sufficient buffer size by calling + * #PSA_SIGN_OUTPUT_SIZE(\c key_type, \c key_bits, \p alg) + * where \c key_type and \c key_bits are the type and bit-size + * respectively of \p key. + * + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY \emptydescription + */ +psa_status_t mbedtls_psa_sign_hash_complete( + mbedtls_psa_sign_hash_interruptible_operation_t *operation, + uint8_t *signature, size_t signature_size, + size_t *signature_length); + +/** + * \brief Abort a sign hash operation. + * + * \note The signature of this function is that of a PSA driver sign_hash_abort + * entry point. This function behaves as a sign_hash_abort entry point as + * defined in the PSA driver interface specification for transparent + * drivers. + * + * \param[in] operation The \c + * mbedtls_psa_sign_hash_interruptible_operation_t + * to abort. + * + * \retval #PSA_SUCCESS + * The operation was aborted successfully. + */ +psa_status_t mbedtls_psa_sign_hash_abort( + mbedtls_psa_sign_hash_interruptible_operation_t *operation); + +/** + * \brief Start reading and verifying a hash or short message, in an + * interruptible manner. + * + * \note The signature of this function is that of a PSA driver + * verify_hash_start entry point. This function behaves as a + * verify_hash_start entry point as defined in the PSA driver interface + * specification for transparent drivers. + * + * \param[in] operation The \c + * mbedtls_psa_verify_hash_interruptible_operation_t + * to use. This must be initialized first. + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key context. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] alg A signature algorithm that is compatible with + * the type of the key. + * \param[in] hash The hash whose signature is to be verified. + * \param hash_length Size of the \p hash buffer in bytes. + * \param[in] signature Buffer containing the signature to verify. + * \param signature_length Size of the \p signature buffer in bytes. + * + * \retval #PSA_SUCCESS + * The operation started successfully - call \c psa_sign_hash_complete() + * with the same context to complete the operation + * \retval #PSA_ERROR_INVALID_ARGUMENT + * An unsupported or incorrect type of key was used. + * \retval #PSA_ERROR_NOT_SUPPORTED + * Either no internal interruptible operations are currently supported, + * or the key type is currently unsupported. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * There was insufficient memory either to load the key representation, + * or to prepare the operation. + */ +psa_status_t mbedtls_psa_verify_hash_start( + mbedtls_psa_verify_hash_interruptible_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *hash, size_t hash_length, + const uint8_t *signature, size_t signature_length); + +/** + * \brief Continue and eventually complete the action of signing a hash or + * short message with a private key, in an interruptible manner. + * + * \note The signature of this function is that of a PSA driver + * sign_hash_complete entry point. This function behaves as a + * sign_hash_complete entry point as defined in the PSA driver interface + * specification for transparent drivers. + * + * \param[in] operation The \c + * mbedtls_psa_sign_hash_interruptible_operation_t + * to use. This must be initialized first. + * + * \retval #PSA_SUCCESS + * Operation completed successfully, and the passed signature is valid. + * + * \retval #PSA_OPERATION_INCOMPLETE + * Operation was interrupted due to the setting of \c + * psa_interruptible_set_max_ops(), there is still work to be done, + * please call this function again with the same operation object. + * + * \retval #PSA_ERROR_INVALID_SIGNATURE + * The calculation was performed successfully, but the passed + * signature is not a valid signature. + * + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + */ +psa_status_t mbedtls_psa_verify_hash_complete( + mbedtls_psa_verify_hash_interruptible_operation_t *operation); + +/** + * \brief Abort a verify signed hash operation. + * + * \note The signature of this function is that of a PSA driver + * verify_hash_abort entry point. This function behaves as a + * verify_hash_abort entry point as defined in the PSA driver interface + * specification for transparent drivers. + * + * \param[in] operation The \c + * mbedtls_psa_verify_hash_interruptible_operation_t + * to abort. + * + * \retval #PSA_SUCCESS + * The operation was aborted successfully. + */ +psa_status_t mbedtls_psa_verify_hash_abort( + mbedtls_psa_verify_hash_interruptible_operation_t *operation); + +typedef struct psa_crypto_local_input_s { + uint8_t *buffer; + size_t length; +} psa_crypto_local_input_t; + +#define PSA_CRYPTO_LOCAL_INPUT_INIT ((psa_crypto_local_input_t) { NULL, 0 }) + +/** Allocate a local copy of an input buffer and copy the contents into it. + * + * \param[in] input Pointer to input buffer. + * \param[in] input_len Length of the input buffer. + * \param[out] local_input Pointer to a psa_crypto_local_input_t struct + * containing a local input copy. + * \return #PSA_SUCCESS, if the buffer was successfully + * copied. + * \return #PSA_ERROR_INSUFFICIENT_MEMORY, if a copy of + * the buffer cannot be allocated. + */ +psa_status_t psa_crypto_local_input_alloc(const uint8_t *input, size_t input_len, + psa_crypto_local_input_t *local_input); + +/** Free a local copy of an input buffer. + * + * \param[in] local_input Pointer to a psa_crypto_local_input_t struct + * populated by a previous call to + * psa_crypto_local_input_alloc(). + */ +void psa_crypto_local_input_free(psa_crypto_local_input_t *local_input); + +typedef struct psa_crypto_local_output_s { + uint8_t *original; + uint8_t *buffer; + size_t length; +} psa_crypto_local_output_t; + +#define PSA_CRYPTO_LOCAL_OUTPUT_INIT ((psa_crypto_local_output_t) { NULL, NULL, 0 }) + +/** Allocate a local copy of an output buffer. + * + * \note This does not copy any data from the original + * output buffer but only allocates a buffer + * whose contents will be copied back to the + * original in a future call to + * psa_crypto_local_output_free(). + * + * \param[in] output Pointer to output buffer. + * \param[in] output_len Length of the output buffer. + * \param[out] local_output Pointer to a psa_crypto_local_output_t struct to + * populate with the local output copy. + * \return #PSA_SUCCESS, if the buffer was successfully + * copied. + * \return #PSA_ERROR_INSUFFICIENT_MEMORY, if a copy of + * the buffer cannot be allocated. + */ +psa_status_t psa_crypto_local_output_alloc(uint8_t *output, size_t output_len, + psa_crypto_local_output_t *local_output); + +/** Copy from a local copy of an output buffer back to the original, then + * free the local copy. + * + * \param[in] local_output Pointer to a psa_crypto_local_output_t struct + * populated by a previous call to + * psa_crypto_local_output_alloc(). + * \return #PSA_SUCCESS, if the local output was + * successfully copied back to the original. + * \return #PSA_ERROR_CORRUPTION_DETECTED, if the output + * could not be copied back to the original. + */ +psa_status_t psa_crypto_local_output_free(psa_crypto_local_output_t *local_output); + +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_CORE_H */ diff --git a/tf-psa-crypto/core/psa_crypto_core_common.h b/tf-psa-crypto/core/psa_crypto_core_common.h new file mode 100644 index 0000000000..29af111d84 --- /dev/null +++ b/tf-psa-crypto/core/psa_crypto_core_common.h @@ -0,0 +1,52 @@ +/** + * \file psa_crypto_core_common.h + * + * \brief Utility macros for internal use in the PSA cryptography core. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_CORE_COMMON_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_CORE_COMMON_H + +/** Return an offset into a buffer. + * + * This is just the addition of an offset to a pointer, except that this + * function also accepts an offset of 0 into a buffer whose pointer is null. + * (`p + n` has undefined behavior when `p` is null, even when `n == 0`. + * A null pointer is a valid buffer pointer when the size is 0, for example + * as the result of `malloc(0)` on some platforms.) + * + * \param p Pointer to a buffer of at least n bytes. + * This may be \p NULL if \p n is zero. + * \param n An offset in bytes. + * \return Pointer to offset \p n in the buffer \p p. + * Note that this is only a valid pointer if the size of the + * buffer is at least \p n + 1. + */ +static inline unsigned char *psa_crypto_buffer_offset( + unsigned char *p, size_t n) +{ + return p == NULL ? NULL : p + n; +} + +/** Return an offset into a read-only buffer. + * + * Similar to mbedtls_buffer_offset(), but for const pointers. + * + * \param p Pointer to a buffer of at least n bytes. + * This may be \p NULL if \p n is zero. + * \param n An offset in bytes. + * \return Pointer to offset \p n in the buffer \p p. + * Note that this is only a valid pointer if the size of the + * buffer is at least \p n + 1. + */ +static inline const unsigned char *psa_crypto_buffer_offset_const( + const unsigned char *p, size_t n) +{ + return p == NULL ? NULL : p + n; +} + +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_CORE_COMMON_H */ diff --git a/tf-psa-crypto/core/psa_crypto_driver_wrappers.h b/tf-psa-crypto/core/psa_crypto_driver_wrappers.h new file mode 100644 index 0000000000..0f66833450 --- /dev/null +++ b/tf-psa-crypto/core/psa_crypto_driver_wrappers.h @@ -0,0 +1,3657 @@ +/* + * Functions to delegate cryptographic operations to an available + * and appropriate accelerator. + * Warning: This file is now auto-generated. + */ +/* Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + + +/* BEGIN-common headers */ +#include "tf_psa_crypto_common.h" +#include "psa_crypto_aead.h" +#include "psa_crypto_cipher.h" +#include "psa_crypto_core.h" +#include "psa_crypto_driver_wrappers_no_static.h" +#include "psa_crypto_hash.h" +#include "psa_crypto_xof.h" +#include "psa_crypto_mac.h" +#include "psa_crypto_pake.h" +#include "psa_crypto_rsa.h" + +#if defined(TF_PSA_CRYPTO_PQCP_MLDSA_ENABLED) +#include "psa_crypto_mldsa.h" +#endif + +#include "mbedtls/platform.h" +#include "mbedtls/constant_time.h" +/* END-common headers */ + +#if defined(MBEDTLS_PSA_CRYPTO_C) + +/* BEGIN-driver headers */ +/* Headers for mbedtls_test opaque driver */ +#if defined(PSA_CRYPTO_DRIVER_TEST) +#include "test/drivers/test_driver.h" + +#endif +/* Headers for mbedtls_test transparent driver */ +#if defined(PSA_CRYPTO_DRIVER_TEST) +#include "test/drivers/test_driver.h" + +#endif +/* Headers for p256 transparent driver */ +#if defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED) +#include "../drivers/p256-m/p256-m_driver_entrypoints.h" + +#endif + +/* Headers for esp_sha transparent driver */ +#if defined(ESP_SHA_DRIVER_ENABLED) +#include "../../../port/psa_driver/include/psa_crypto_driver_esp_sha.h" + +#endif + +#if defined(ESP_HMAC_TRANSPARENT_DRIVER_ENABLED) +#include "../../../port/psa_driver/include/psa_crypto_driver_esp_hmac_transparent.h" + +#endif + +/* Headers for esp_aes transparent driver */ +#if defined(ESP_AES_DRIVER_ENABLED) +#include "../../../port/psa_driver/include/psa_crypto_driver_esp_aes.h" +#include "../../../port/psa_driver/include/psa_crypto_driver_esp_aes_gcm.h" +#endif + +#if defined(ESP_MD5_DRIVER_ENABLED) +#include "../../../port/psa_driver/include/psa_crypto_driver_esp_md5.h" + +#endif + +#if defined(ESP_HMAC_OPAQUE_DRIVER_ENABLED) +#include "../../../port/psa_driver/include/psa_crypto_driver_esp_hmac_opaque.h" + +#endif + +/* Headers for esp_ecdsa opaque driver */ +#if defined(ESP_ECDSA_DRIVER_ENABLED) +#include "../../../port/psa_driver/include/psa_crypto_driver_esp_ecdsa.h" + +#endif + +#if defined(ESP_RSA_DS_DRIVER_ENABLED) +#include "../../../port/psa_driver/include/psa_crypto_driver_esp_rsa_ds.h" + +#endif + +#if defined(ESP_CMAC_DRIVER_ENABLED) +#include "../../../port/psa_driver/include/psa_crypto_driver_esp_cmac.h" + +#endif +/* END-driver headers */ + +/* Auto-generated values depending on which drivers are registered. + * ID 0 is reserved for unallocated operations. + * ID 1 is reserved for the Mbed TLS software driver. */ +/* BEGIN-driver id definition */ +#define PSA_CRYPTO_MBED_TLS_DRIVER_ID (1) +#define MBEDTLS_TEST_OPAQUE_DRIVER_ID (2) +#define MBEDTLS_TEST_TRANSPARENT_DRIVER_ID (3) +#define P256_TRANSPARENT_DRIVER_ID (4) +#define ESP_SHA_TRANSPARENT_DRIVER_ID (5) +#define ESP_AES_TRANSPARENT_DRIVER_ID (6) +#define ESP_MD5_TRANSPARENT_DRIVER_ID (7) +#define ESP_ECDSA_TRANSPARENT_DRIVER_ID (8) +#define ESP_ECDSA_OPAQUE_DRIVER_ID (9) +#define ESP_RSA_DS_OPAQUE_DRIVER_ID (10) +#define ESP_CMAC_TRANSPARENT_DRIVER_ID (11) +#define ESP_HMAC_TRANSPARENT_DRIVER_ID (12) +#define ESP_HMAC_OPAQUE_DRIVER_ID (13) + +/* END-driver id */ + +/* BEGIN-Common Macro definitions */ + +/* END-Common Macro definitions */ + +static inline psa_status_t psa_driver_wrapper_init( void ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_init( ); + if( status != PSA_SUCCESS ) + return( status ); + + status = mbedtls_test_opaque_init( ); + if( status != PSA_SUCCESS ) + return( status ); +#endif + + (void) status; + return( PSA_SUCCESS ); +} + +static inline void psa_driver_wrapper_free( void ) +{ +#if defined(PSA_CRYPTO_DRIVER_TEST) + mbedtls_test_transparent_free( ); + mbedtls_test_opaque_free( ); +#endif +} + +/* Start delegation functions */ +static inline psa_status_t psa_driver_wrapper_sign_message( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_signature_sign_message( + attributes, + key_buffer, + key_buffer_size, + alg, + input, + input_length, + signature, + signature_size, + signature_length ); + /* Declared with fallback == true */ + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + break; + + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LOCATION: + status = mbedtls_test_opaque_signature_sign_message( + attributes, + key_buffer, + key_buffer_size, + alg, + input, + input_length, + signature, + signature_size, + signature_length ); + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); + break; +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + /* Key is declared with a lifetime not known to us */ + (void)status; + break; + } + + return( psa_sign_message_builtin( attributes, + key_buffer, + key_buffer_size, + alg, + input, + input_length, + signature, + signature_size, + signature_length ) ); +} + +static inline psa_status_t psa_driver_wrapper_verify_message( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *signature, + size_t signature_length ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_signature_verify_message( + attributes, + key_buffer, + key_buffer_size, + alg, + input, + input_length, + signature, + signature_length ); + /* Declared with fallback == true */ + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + break; + + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LOCATION: + return( mbedtls_test_opaque_signature_verify_message( + attributes, + key_buffer, + key_buffer_size, + alg, + input, + input_length, + signature, + signature_length ) ); + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); + break; +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + /* Key is declared with a lifetime not known to us */ + (void)status; + break; + } + + return( psa_verify_message_builtin( attributes, + key_buffer, + key_buffer_size, + alg, + input, + input_length, + signature, + signature_length ) ); +} + +static inline psa_status_t psa_driver_wrapper_sign_hash( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *hash, size_t hash_length, + uint8_t *signature, size_t signature_size, size_t *signature_length ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_signature_sign_hash( attributes, + key_buffer, + key_buffer_size, + alg, + hash, + hash_length, + signature, + signature_size, + signature_length ); + /* Declared with fallback == true */ + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined (MBEDTLS_PSA_P256M_DRIVER_ENABLED) + if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) && + PSA_ALG_IS_RANDOMIZED_ECDSA(alg) && + PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)) == PSA_ECC_FAMILY_SECP_R1 && + psa_get_key_bits(attributes) == 256 ) + { + status = p256_transparent_sign_hash( attributes, + key_buffer, + key_buffer_size, + alg, + hash, + hash_length, + signature, + signature_size, + signature_length ); + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); + } +#endif /* MBEDTLS_PSA_P256M_DRIVER_ENABLED */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + /* Fell through, meaning no accelerator supports this operation */ + return( psa_sign_hash_builtin( attributes, + key_buffer, + key_buffer_size, + alg, + hash, + hash_length, + signature, + signature_size, + signature_length ) ); + + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LOCATION: + return( mbedtls_test_opaque_signature_sign_hash( attributes, + key_buffer, + key_buffer_size, + alg, + hash, + hash_length, + signature, + signature_size, + signature_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_SIGN_DRIVER_ENABLED) + case PSA_KEY_LOCATION_ESP_ECDSA: + if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) && + PSA_ALG_IS_ECDSA(alg) && PSA_ALG_IS_ECDSA( psa_get_key_algorithm(attributes) ) && + PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)) == PSA_ECC_FAMILY_SECP_R1) + { + return ( esp_ecdsa_opaque_sign_hash( attributes, + key_buffer, + key_buffer_size, + alg, + hash, + hash_length, + signature, + signature_size, + signature_length ) ); + } + return PSA_ERROR_INVALID_ARGUMENT; +#endif /* defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_SIGN_DRIVER_ENABLED) */ +#if defined(ESP_RSA_DS_DRIVER_ENABLED) + case PSA_KEY_LOCATION_ESP_RSA_DS: + if( PSA_KEY_TYPE_IS_RSA( psa_get_key_type(attributes) ) && + (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) || PSA_ALG_IS_RSA_PSS(alg))) + { + return( esp_rsa_ds_opaque_signature_sign_hash( attributes, + key_buffer, + key_buffer_size, + alg, + hash, + hash_length, + signature, + signature_size, + signature_length ) ); + } + return PSA_ERROR_INVALID_ARGUMENT; +#endif /* ESP_RSA_DS_DRIVER_ENABLED */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + /* Key is declared with a lifetime not known to us */ + (void)status; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_verify_hash( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *hash, size_t hash_length, + const uint8_t *signature, size_t signature_length ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_VERIFY_DRIVER_ENABLED) + if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) && + PSA_ALG_IS_ECDSA(alg) && PSA_ALG_IS_ECDSA( psa_get_key_algorithm(attributes) ) && + PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)) == PSA_ECC_FAMILY_SECP_R1) + { + status = esp_ecdsa_transparent_verify_hash( attributes, + key_buffer, + key_buffer_size, + alg, + hash, + hash_length, + signature, + signature_length ); + + if ( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); + } +#endif /* defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_VERIFY_DRIVER_ENABLED) */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_signature_verify_hash( + attributes, + key_buffer, + key_buffer_size, + alg, + hash, + hash_length, + signature, + signature_length ); + /* Declared with fallback == true */ + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined (MBEDTLS_PSA_P256M_DRIVER_ENABLED) + if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) && + PSA_ALG_IS_ECDSA(alg) && + PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)) == PSA_ECC_FAMILY_SECP_R1 && + psa_get_key_bits(attributes) == 256 ) + { + status = p256_transparent_verify_hash( attributes, + key_buffer, + key_buffer_size, + alg, + hash, + hash_length, + signature, + signature_length ); + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); + } +#endif /* MBEDTLS_PSA_P256M_DRIVER_ENABLED */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + return( psa_verify_hash_builtin( attributes, + key_buffer, + key_buffer_size, + alg, + hash, + hash_length, + signature, + signature_length ) ); + + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LOCATION: + return( mbedtls_test_opaque_signature_verify_hash( attributes, + key_buffer, + key_buffer_size, + alg, + hash, + hash_length, + signature, + signature_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_VERIFY_DRIVER_ENABLED) + case PSA_KEY_LOCATION_ESP_ECDSA: + if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) && + PSA_ALG_IS_ECDSA(alg) && PSA_ALG_IS_ECDSA( psa_get_key_algorithm(attributes) ) && + PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)) == PSA_ECC_FAMILY_SECP_R1) + { + return esp_ecdsa_transparent_verify_hash( attributes, + key_buffer, + key_buffer_size, + alg, + hash, + hash_length, + signature, + signature_length ); + } + return PSA_ERROR_INVALID_ARGUMENT; +#endif /* defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_VERIFY_DRIVER_ENABLED) */ + +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + /* Key is declared with a lifetime not known to us */ + (void)status; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline uint32_t psa_driver_wrapper_sign_hash_get_num_ops( + psa_sign_hash_interruptible_operation_t *operation ) +{ + switch( operation->id ) + { + /* If uninitialised, return 0, as no work can have been done. */ + case 0: + return 0; + + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return(mbedtls_psa_sign_hash_get_num_ops(&operation->ctx.mbedtls_ctx)); + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + /* Add test driver tests here */ + +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + } + + /* Can't happen (see discussion in #8271) */ + return 0; +} + +static inline uint32_t psa_driver_wrapper_verify_hash_get_num_ops( + psa_verify_hash_interruptible_operation_t *operation ) +{ + switch( operation->id ) + { + /* If uninitialised, return 0, as no work can have been done. */ + case 0: + return 0; + + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return (mbedtls_psa_verify_hash_get_num_ops(&operation->ctx.mbedtls_ctx)); + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + /* Add test driver tests here */ + +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + } + + /* Can't happen (see discussion in #8271) */ + return 0; +} + +static inline psa_status_t psa_driver_wrapper_sign_hash_start( + psa_sign_hash_interruptible_operation_t *operation, + const psa_key_attributes_t *attributes, const uint8_t *key_buffer, + size_t key_buffer_size, psa_algorithm_t alg, + const uint8_t *hash, size_t hash_length ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION( + psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + + /* Add test driver tests here */ + + /* Declared with fallback == true */ + +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + /* Fell through, meaning no accelerator supports this operation */ + operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID; + status = mbedtls_psa_sign_hash_start( &operation->ctx.mbedtls_ctx, + attributes, + key_buffer, key_buffer_size, + alg, hash, hash_length ); + break; + + /* Add cases for opaque driver here */ +#if defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_SIGN_DRIVER_ENABLED) + case PSA_KEY_LOCATION_ESP_ECDSA: + if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) && + PSA_ALG_IS_ECDSA(alg) && PSA_ALG_IS_ECDSA( psa_get_key_algorithm(attributes) ) && + PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)) == PSA_ECC_FAMILY_SECP_R1) + { + status = esp_ecdsa_opaque_sign_hash_start( &operation->ctx.esp_ecdsa_opaque_sign_hash_ctx, + attributes, + key_buffer, key_buffer_size, + alg, hash, hash_length ); + if (status == PSA_SUCCESS) { + operation->id = ESP_ECDSA_OPAQUE_DRIVER_ID; + } + return status; + } else { + return PSA_ERROR_INVALID_ARGUMENT; + } +#endif /* defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_SIGN_DRIVER_ENABLED) */ + +#if defined(ESP_RSA_DS_DRIVER_ENABLED) + case PSA_KEY_LOCATION_ESP_RSA_DS: + if( PSA_KEY_TYPE_IS_RSA( psa_get_key_type(attributes) ) && + (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) || PSA_ALG_IS_RSA_PSS(alg))) + { + status = esp_rsa_ds_opaque_sign_hash_start( &operation->ctx.esp_rsa_ds_opaque_sign_hash_ctx, + attributes, + key_buffer, key_buffer_size, + alg, hash, hash_length ); + if (status == PSA_SUCCESS) { + operation->id = ESP_RSA_DS_OPAQUE_DRIVER_ID; + } + return status; + } else { + return PSA_ERROR_INVALID_ARGUMENT; + } + +#endif /* defined(ESP_RSA_DS_DRIVER_ENABLED) */ + default: + /* Key is declared with a lifetime not known to us */ + status = PSA_ERROR_INVALID_ARGUMENT; + break; + } + + return( status ); +} + +static inline psa_status_t psa_driver_wrapper_sign_hash_complete( + psa_sign_hash_interruptible_operation_t *operation, + uint8_t *signature, size_t signature_size, + size_t *signature_length ) +{ + switch( operation->id ) + { + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_sign_hash_complete( &operation->ctx.mbedtls_ctx, + signature, signature_size, + signature_length ) ); + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + /* Add test driver tests here */ + +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_SIGN_DRIVER_ENABLED) + case ESP_ECDSA_OPAQUE_DRIVER_ID: + return esp_ecdsa_opaque_sign_hash_complete( &operation->ctx.esp_ecdsa_opaque_sign_hash_ctx, + signature, signature_size, + signature_length ); +#endif /* defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_SIGN_DRIVER_ENABLED) */ +#if defined(ESP_RSA_DS_DRIVER_ENABLED) + case ESP_RSA_DS_OPAQUE_DRIVER_ID: + return esp_rsa_ds_opaque_sign_hash_complete( &operation->ctx.esp_rsa_ds_opaque_sign_hash_ctx, + signature, signature_size, + signature_length ); +#endif /* defined(ESP_RSA_DS_DRIVER_ENABLED) */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + } + + ( void ) signature; + ( void ) signature_size; + ( void ) signature_length; + + return( PSA_ERROR_INVALID_ARGUMENT ); +} + +static inline psa_status_t psa_driver_wrapper_sign_hash_abort( + psa_sign_hash_interruptible_operation_t *operation ) +{ + switch( operation->id ) + { + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_sign_hash_abort( &operation->ctx.mbedtls_ctx ) ); + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + /* Add test driver tests here */ + +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_SIGN_DRIVER_ENABLED) + case ESP_ECDSA_OPAQUE_DRIVER_ID: + return esp_ecdsa_opaque_sign_hash_abort( &operation->ctx.esp_ecdsa_opaque_sign_hash_ctx ); +#endif /* defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_SIGN_DRIVER_ENABLED) */ +#if defined(ESP_RSA_DS_DRIVER_ENABLED) + case ESP_RSA_DS_OPAQUE_DRIVER_ID: + return esp_rsa_ds_opaque_sign_hash_abort( &operation->ctx.esp_rsa_ds_opaque_sign_hash_ctx ); +#endif /* defined(ESP_RSA_DS_DRIVER_ENABLED) */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + } + + return( PSA_ERROR_INVALID_ARGUMENT ); +} + +static inline psa_status_t psa_driver_wrapper_verify_hash_start( + psa_verify_hash_interruptible_operation_t *operation, + const psa_key_attributes_t *attributes, const uint8_t *key_buffer, + size_t key_buffer_size, psa_algorithm_t alg, + const uint8_t *hash, size_t hash_length, + const uint8_t *signature, size_t signature_length ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION( + psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + + /* Add test driver tests here */ +#if defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_VERIFY_DRIVER_ENABLED) + if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) && + PSA_ALG_IS_ECDSA(alg) && PSA_ALG_IS_ECDSA( psa_get_key_algorithm(attributes) ) && + PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)) == PSA_ECC_FAMILY_SECP_R1) + { + status = esp_ecdsa_transparent_verify_hash_start( &operation->ctx.esp_ecdsa_transparent_verify_hash_ctx, + attributes, + key_buffer, + key_buffer_size, + alg, hash, hash_length, signature, signature_length ); + if (status == PSA_SUCCESS) { + operation->id = ESP_ECDSA_TRANSPARENT_DRIVER_ID; + } + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); + } +#endif /* defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_VERIFY_DRIVER_ENABLED) */ + + /* Declared with fallback == true */ + +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + /* Fell through, meaning no accelerator supports this operation */ + operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID; + status = mbedtls_psa_verify_hash_start( &operation->ctx.mbedtls_ctx, + attributes, + key_buffer, key_buffer_size, + alg, hash, hash_length, + signature, signature_length ); + break; + + /* Add cases for opaque driver here */ + +#if defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_VERIFY_DRIVER_ENABLED) + case PSA_KEY_LOCATION_ESP_ECDSA: + if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) && + PSA_ALG_IS_ECDSA(alg) && PSA_ALG_IS_ECDSA( psa_get_key_algorithm(attributes) ) && + PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)) == PSA_ECC_FAMILY_SECP_R1) + { + status = esp_ecdsa_transparent_verify_hash_start( &operation->ctx.esp_ecdsa_transparent_verify_hash_ctx, + attributes, + key_buffer, + key_buffer_size, + alg, hash, hash_length, signature, signature_length ); + if (status == PSA_SUCCESS) { + operation->id = ESP_ECDSA_TRANSPARENT_DRIVER_ID; + } + return status; + } else { + return PSA_ERROR_INVALID_ARGUMENT; + } + +#endif /* defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_VERIFY_DRIVER_ENABLED) */ + + default: + /* Key is declared with a lifetime not known to us */ + status = PSA_ERROR_INVALID_ARGUMENT; + break; + } + + return( status ); +} + +static inline psa_status_t psa_driver_wrapper_verify_hash_complete( + psa_verify_hash_interruptible_operation_t *operation ) +{ + switch( operation->id ) + { + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_verify_hash_complete( + &operation->ctx.mbedtls_ctx + ) ); + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + /* Add test driver tests here */ + +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_VERIFY_DRIVER_ENABLED) + case ESP_ECDSA_TRANSPARENT_DRIVER_ID: + return esp_ecdsa_transparent_verify_hash_complete( &operation->ctx.esp_ecdsa_transparent_verify_hash_ctx ); +#endif /* defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_VERIFY_DRIVER_ENABLED) */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + } + + return( PSA_ERROR_INVALID_ARGUMENT ); +} + +static inline psa_status_t psa_driver_wrapper_verify_hash_abort( + psa_verify_hash_interruptible_operation_t *operation ) +{ + switch( operation->id ) + { + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_verify_hash_abort( &operation->ctx.mbedtls_ctx + ) ); + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + /* Add test driver tests here */ + +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_VERIFY_DRIVER_ENABLED) + case ESP_ECDSA_TRANSPARENT_DRIVER_ID: + return esp_ecdsa_transparent_verify_hash_abort( &operation->ctx.esp_ecdsa_transparent_verify_hash_ctx ); +#endif /* defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_VERIFY_DRIVER_ENABLED) */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + } + + return( PSA_ERROR_INVALID_ARGUMENT ); +} + +/** Calculate the key buffer size required to store the key material of a key + * associated with an opaque driver from input key data. + * + * \param[in] attributes The key attributes + * \param[in] data The input key data. + * \param[in] data_length The input data length. + * \param[out] key_buffer_size Minimum buffer size to contain the key material. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + */ +static inline psa_status_t psa_driver_wrapper_get_key_buffer_size_from_key_data( + const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + size_t *key_buffer_size ) +{ + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + psa_key_type_t key_type = psa_get_key_type(attributes); + + *key_buffer_size = 0; + switch( location ) + { +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LOCATION: + *key_buffer_size = mbedtls_test_opaque_size_function( key_type, + PSA_BYTES_TO_BITS( data_length ) ); + return( ( *key_buffer_size != 0 ) ? + PSA_SUCCESS : PSA_ERROR_NOT_SUPPORTED ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_SIGN_DRIVER_ENABLED) + case PSA_KEY_LOCATION_ESP_ECDSA: + *key_buffer_size = esp_ecdsa_opaque_size_function( key_type, + PSA_BYTES_TO_BITS( data_length ) ); + return( ( *key_buffer_size != 0 ) ? + PSA_SUCCESS : PSA_ERROR_NOT_SUPPORTED ); +#endif /* defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_SIGN_DRIVER_ENABLED) */ +#if defined(ESP_RSA_DS_DRIVER_ENABLED) + case PSA_KEY_LOCATION_ESP_RSA_DS: + *key_buffer_size = esp_rsa_ds_opaque_size_function( key_type, + PSA_BYTES_TO_BITS( data_length ) ); + return( ( *key_buffer_size != 0 ) ? + PSA_SUCCESS : PSA_ERROR_NOT_SUPPORTED ); +#endif /* ESP_RSA_DS_DRIVER_ENABLED */ + +#if defined(ESP_HMAC_OPAQUE_DRIVER_ENABLED) + case PSA_KEY_LOCATION_ESP_HMAC: + *key_buffer_size = esp_hmac_opaque_size_function(key_type, + PSA_BYTES_TO_BITS( data_length ) ); + return( ( *key_buffer_size != 0 ) ? + PSA_SUCCESS : PSA_ERROR_NOT_SUPPORTED ); +#endif /* defined(ESP_HMAC_OPAQUE_DRIVER_ENABLED) */ + + default: + (void)key_type; + (void)data; + (void)data_length; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_generate_key( + const psa_key_attributes_t *attributes, + const psa_custom_key_parameters_t *custom, + const uint8_t *custom_data, size_t custom_data_length, + uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(attributes)); + +#if defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE) + int is_default_production = + psa_custom_key_parameters_are_default(custom, custom_data_length); + if( location != PSA_KEY_LOCATION_LOCAL_STORAGE && !is_default_production ) + { + /* We don't support passing custom production parameters + * to drivers yet. */ + return PSA_ERROR_NOT_SUPPORTED; + } +#else + int is_default_production = 1; + (void) is_default_production; +#endif + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) + /* Transparent drivers are limited to generating asymmetric keys. */ + /* We don't support passing custom production parameters + * to drivers yet. */ + if( PSA_KEY_TYPE_IS_ASYMMETRIC( psa_get_key_type(attributes) ) && + is_default_production ) + { + /* Cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_generate_key( + attributes, key_buffer, key_buffer_size, + key_buffer_length ); + /* Declared with fallback == true */ + if( status != PSA_ERROR_NOT_SUPPORTED ) + break; +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED) + if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) && + psa_get_key_type(attributes) == PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1) && + psa_get_key_bits(attributes) == 256 ) + { + status = p256_transparent_generate_key( attributes, + key_buffer, + key_buffer_size, + key_buffer_length ); + if( status != PSA_ERROR_NOT_SUPPORTED ) + break; + } + +#endif /* MBEDTLS_PSA_P256M_DRIVER_ENABLED */ + } +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + /* Software fallback */ + status = psa_generate_key_internal( + attributes, custom, custom_data, custom_data_length, + key_buffer, key_buffer_size, key_buffer_length ); + break; + + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LOCATION: + status = mbedtls_test_opaque_generate_key( + attributes, key_buffer, key_buffer_size, key_buffer_length ); + break; +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + default: + /* Key is declared with a lifetime not known to us */ + status = PSA_ERROR_INVALID_ARGUMENT; + break; + } + + return( status ); +} + +static inline psa_status_t psa_driver_wrapper_import_key( + const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length, + size_t *bits ) +{ + + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION( + psa_get_key_lifetime( attributes ) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) + +#if (defined(PSA_CRYPTO_DRIVER_TEST) ) + status = mbedtls_test_transparent_import_key + (attributes, + data, + data_length, + key_buffer, + key_buffer_size, + key_buffer_length, + bits + ); + + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif + +#if (defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED) ) + status = p256_transparent_import_key + (attributes, + data, + data_length, + key_buffer, + key_buffer_size, + key_buffer_length, + bits + ); + + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif + + +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + /* Fell through, meaning no accelerator supports this operation */ + return( psa_import_key_into_slot( attributes, + data, data_length, + key_buffer, key_buffer_size, + key_buffer_length, bits ) ); + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) + +#if (defined(PSA_CRYPTO_DRIVER_TEST) ) + case 0x7fffff: + return( mbedtls_test_opaque_import_key + (attributes, + data, + data_length, + key_buffer, + key_buffer_size, + key_buffer_length, + bits + )); +#endif + +#if defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_SIGN_DRIVER_ENABLED) + case PSA_KEY_LOCATION_ESP_ECDSA: + return( esp_ecdsa_opaque_import_key( + attributes, + data, data_length, + key_buffer, key_buffer_size, + key_buffer_length, bits ) ); +#endif /* defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_SIGN_DRIVER_ENABLED) */ +#if defined(ESP_HMAC_OPAQUE_DRIVER_ENABLED) + case PSA_KEY_LOCATION_ESP_HMAC: + return( esp_hmac_import_key_opaque( + attributes, + data, data_length, + key_buffer, key_buffer_size, + key_buffer_length, bits ) ); +#endif /* defined(ESP_HMAC_OPAQUE_DRIVER_ENABLED) */ + +#if defined(ESP_RSA_DS_DRIVER_ENABLED) + case PSA_KEY_LOCATION_ESP_RSA_DS: + return( esp_rsa_ds_opaque_import_key + (attributes, + data, + data_length, + key_buffer, + key_buffer_size, + key_buffer_length, + bits + )); +#endif /* ESP_RSA_DS_DRIVER_ENABLED */ + +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + (void)status; + return( PSA_ERROR_INVALID_ARGUMENT ); + } + +} + +static inline psa_status_t psa_driver_wrapper_export_key( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + uint8_t *data, size_t data_size, size_t *data_length ) + +{ + + psa_status_t status = PSA_ERROR_INVALID_ARGUMENT; + psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION( + psa_get_key_lifetime( attributes ) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + return( psa_export_key_internal( attributes, + key_buffer, + key_buffer_size, + data, + data_size, + data_length ) ); + + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) + +#if (defined(PSA_CRYPTO_DRIVER_TEST) ) + case 0x7fffff: + return( mbedtls_test_opaque_export_key + (attributes, + key_buffer, + key_buffer_size, + data, + data_size, + data_length + )); +#endif + + +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + /* Key is declared with a lifetime not known to us */ + return( status ); + } + +} + +static inline psa_status_t psa_driver_wrapper_copy_key( + psa_key_attributes_t *attributes, + const uint8_t *source_key, size_t source_key_length, + uint8_t *target_key_buffer, size_t target_key_buffer_size, + size_t *target_key_buffer_length ) +{ + + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) + +#if (defined(PSA_CRYPTO_DRIVER_TEST) ) + case 0x7fffff: + return( mbedtls_test_opaque_copy_key + (attributes, + source_key, + source_key_length, + target_key_buffer, + target_key_buffer_size, + target_key_buffer_length + )); +#endif + + +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + (void)source_key; + (void)source_key_length; + (void)target_key_buffer; + (void)target_key_buffer_size; + (void)target_key_buffer_length; + status = PSA_ERROR_INVALID_ARGUMENT; + } + return( status ); + +} + +/* + * Cipher functions + */ +static inline psa_status_t psa_driver_wrapper_cipher_encrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *iv, + size_t iv_length, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + status = esp_aes_cipher_encrypt(attributes, + key_buffer, + key_buffer_size, + alg, + iv, + iv_length, + input, + input_length, + output, + output_size, + output_length ); + + if ( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_cipher_encrypt( attributes, + key_buffer, + key_buffer_size, + alg, + iv, + iv_length, + input, + input_length, + output, + output_size, + output_length ); + /* Declared with fallback == true */ + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + +#if defined(MBEDTLS_PSA_BUILTIN_CIPHER) + return( mbedtls_psa_cipher_encrypt( attributes, + key_buffer, + key_buffer_size, + alg, + iv, + iv_length, + input, + input_length, + output, + output_size, + output_length ) ); +#else + return( PSA_ERROR_NOT_SUPPORTED ); +#endif /* MBEDTLS_PSA_BUILTIN_CIPHER */ + + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LOCATION: + return( mbedtls_test_opaque_cipher_encrypt( attributes, + key_buffer, + key_buffer_size, + alg, + iv, + iv_length, + input, + input_length, + output, + output_size, + output_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + default: + /* Key is declared with a lifetime not known to us */ + (void)status; + (void)key_buffer; + (void)key_buffer_size; + (void)alg; + (void)iv; + (void)iv_length; + (void)input; + (void)input_length; + (void)output; + (void)output_size; + (void)output_length; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_cipher_decrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + status = esp_aes_cipher_decrypt(attributes, + key_buffer, + key_buffer_size, + alg, + input, + input_length, + output, + output_size, + output_length ); + if ( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_cipher_decrypt( attributes, + key_buffer, + key_buffer_size, + alg, + input, + input_length, + output, + output_size, + output_length ); + /* Declared with fallback == true */ + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + +#if defined(MBEDTLS_PSA_BUILTIN_CIPHER) + return( mbedtls_psa_cipher_decrypt( attributes, + key_buffer, + key_buffer_size, + alg, + input, + input_length, + output, + output_size, + output_length ) ); +#else + return( PSA_ERROR_NOT_SUPPORTED ); +#endif /* MBEDTLS_PSA_BUILTIN_CIPHER */ + + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LOCATION: + return( mbedtls_test_opaque_cipher_decrypt( attributes, + key_buffer, + key_buffer_size, + alg, + input, + input_length, + output, + output_size, + output_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + default: + /* Key is declared with a lifetime not known to us */ + (void)status; + (void)key_buffer; + (void)key_buffer_size; + (void)alg; + (void)input; + (void)input_length; + (void)output; + (void)output_size; + (void)output_length; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_cipher_encrypt_setup( + psa_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + status = esp_aes_cipher_encrypt_setup( &operation->ctx.esp_aes_ctx, + attributes, + key_buffer, + key_buffer_size, + alg ); + if ( status == PSA_SUCCESS ) { + operation->id = ESP_AES_TRANSPARENT_DRIVER_ID; + } + if ( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_cipher_encrypt_setup( + &operation->ctx.transparent_test_driver_ctx, + attributes, + key_buffer, + key_buffer_size, + alg ); + /* Declared with fallback == true */ + if( status == PSA_SUCCESS ) + operation->id = MBEDTLS_TEST_TRANSPARENT_DRIVER_ID; + + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ +#if defined(MBEDTLS_PSA_BUILTIN_CIPHER) + /* Fell through, meaning no accelerator supports this operation */ + status = mbedtls_psa_cipher_encrypt_setup( &operation->ctx.mbedtls_ctx, + attributes, + key_buffer, + key_buffer_size, + alg ); + if( status == PSA_SUCCESS ) + operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID; + + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* MBEDTLS_PSA_BUILTIN_CIPHER */ + return( PSA_ERROR_NOT_SUPPORTED ); + + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LOCATION: + status = mbedtls_test_opaque_cipher_encrypt_setup( + &operation->ctx.opaque_test_driver_ctx, + attributes, + key_buffer, key_buffer_size, + alg ); + + if( status == PSA_SUCCESS ) + operation->id = MBEDTLS_TEST_OPAQUE_DRIVER_ID; + + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + /* Key is declared with a lifetime not known to us */ + (void)status; + (void)operation; + (void)key_buffer; + (void)key_buffer_size; + (void)alg; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_cipher_decrypt_setup( + psa_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg ) +{ + psa_status_t status = PSA_ERROR_INVALID_ARGUMENT; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + status = esp_aes_cipher_decrypt_setup( &operation->ctx.esp_aes_ctx, + attributes, + key_buffer, + key_buffer_size, + alg ); + if ( status == PSA_SUCCESS ) { + operation->id = ESP_AES_TRANSPARENT_DRIVER_ID; + } + if ( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_cipher_decrypt_setup( + &operation->ctx.transparent_test_driver_ctx, + attributes, + key_buffer, + key_buffer_size, + alg ); + /* Declared with fallback == true */ + if( status == PSA_SUCCESS ) + operation->id = MBEDTLS_TEST_TRANSPARENT_DRIVER_ID; + + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ +#if defined(MBEDTLS_PSA_BUILTIN_CIPHER) + /* Fell through, meaning no accelerator supports this operation */ + status = mbedtls_psa_cipher_decrypt_setup( &operation->ctx.mbedtls_ctx, + attributes, + key_buffer, + key_buffer_size, + alg ); + if( status == PSA_SUCCESS ) + operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID; + + return( status ); +#else /* MBEDTLS_PSA_BUILTIN_CIPHER */ + return( PSA_ERROR_NOT_SUPPORTED ); +#endif /* MBEDTLS_PSA_BUILTIN_CIPHER */ + + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LOCATION: + status = mbedtls_test_opaque_cipher_decrypt_setup( + &operation->ctx.opaque_test_driver_ctx, + attributes, + key_buffer, key_buffer_size, + alg ); + + if( status == PSA_SUCCESS ) + operation->id = MBEDTLS_TEST_OPAQUE_DRIVER_ID; + + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + /* Key is declared with a lifetime not known to us */ + (void)status; + (void)operation; + (void)key_buffer; + (void)key_buffer_size; + (void)alg; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_cipher_set_iv( + psa_cipher_operation_t *operation, + const uint8_t *iv, + size_t iv_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_CIPHER) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_cipher_set_iv( &operation->ctx.mbedtls_ctx, + iv, + iv_length ) ); +#endif /* MBEDTLS_PSA_BUILTIN_CIPHER */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + case ESP_AES_TRANSPARENT_DRIVER_ID: + return( esp_aes_cipher_set_iv( + &operation->ctx.esp_aes_ctx, + iv, iv_length ) ); +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_cipher_set_iv( + &operation->ctx.transparent_test_driver_ctx, + iv, iv_length ) ); + + case MBEDTLS_TEST_OPAQUE_DRIVER_ID: + return( mbedtls_test_opaque_cipher_set_iv( + &operation->ctx.opaque_test_driver_ctx, + iv, iv_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + } + + (void)iv; + (void)iv_length; + + return( PSA_ERROR_INVALID_ARGUMENT ); +} + +static inline psa_status_t psa_driver_wrapper_cipher_update( + psa_cipher_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_CIPHER) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_cipher_update( &operation->ctx.mbedtls_ctx, + input, + input_length, + output, + output_size, + output_length ) ); +#endif /* MBEDTLS_PSA_BUILTIN_CIPHER */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + case ESP_AES_TRANSPARENT_DRIVER_ID: + return( esp_aes_cipher_update( &operation->ctx.esp_aes_ctx, + input, + input_length, + output, + output_size, + output_length ) ); +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_cipher_update( + &operation->ctx.transparent_test_driver_ctx, + input, input_length, + output, output_size, output_length ) ); + + case MBEDTLS_TEST_OPAQUE_DRIVER_ID: + return( mbedtls_test_opaque_cipher_update( + &operation->ctx.opaque_test_driver_ctx, + input, input_length, + output, output_size, output_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + } + + (void)input; + (void)input_length; + (void)output; + (void)output_size; + (void)output_length; + + return( PSA_ERROR_INVALID_ARGUMENT ); +} + +static inline psa_status_t psa_driver_wrapper_cipher_finish( + psa_cipher_operation_t *operation, + uint8_t *output, + size_t output_size, + size_t *output_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_CIPHER) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_cipher_finish( &operation->ctx.mbedtls_ctx, + output, + output_size, + output_length ) ); +#endif /* MBEDTLS_PSA_BUILTIN_CIPHER */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + case ESP_AES_TRANSPARENT_DRIVER_ID: + return( esp_aes_cipher_finish( &operation->ctx.esp_aes_ctx, + output, + output_size, + output_length ) ); +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_cipher_finish( + &operation->ctx.transparent_test_driver_ctx, + output, output_size, output_length ) ); + + case MBEDTLS_TEST_OPAQUE_DRIVER_ID: + return( mbedtls_test_opaque_cipher_finish( + &operation->ctx.opaque_test_driver_ctx, + output, output_size, output_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + } + + (void)output; + (void)output_size; + (void)output_length; + + return( PSA_ERROR_INVALID_ARGUMENT ); +} + +static inline psa_status_t psa_driver_wrapper_cipher_abort( + psa_cipher_operation_t *operation ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_CIPHER) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_cipher_abort( &operation->ctx.mbedtls_ctx ) ); +#endif /* MBEDTLS_PSA_BUILTIN_CIPHER */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + case ESP_AES_TRANSPARENT_DRIVER_ID: + return( esp_aes_cipher_abort( &operation->ctx.esp_aes_ctx ) ); +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + status = mbedtls_test_transparent_cipher_abort( + &operation->ctx.transparent_test_driver_ctx ); + mbedtls_platform_zeroize( + &operation->ctx.transparent_test_driver_ctx, + sizeof( operation->ctx.transparent_test_driver_ctx ) ); + return( status ); + + case MBEDTLS_TEST_OPAQUE_DRIVER_ID: + status = mbedtls_test_opaque_cipher_abort( + &operation->ctx.opaque_test_driver_ctx ); + mbedtls_platform_zeroize( + &operation->ctx.opaque_test_driver_ctx, + sizeof( operation->ctx.opaque_test_driver_ctx ) ); + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + } + + (void)status; + return( PSA_ERROR_INVALID_ARGUMENT ); +} + +/* + * Hashing functions + */ +static inline psa_status_t psa_driver_wrapper_hash_compute( + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + /* Try accelerators first */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_hash_compute( + alg, input, input_length, hash, hash_size, hash_length ); + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ + +#if defined(ESP_SHA_DRIVER_ENABLED) + status = esp_sha_hash_compute(alg, input, input_length, + hash, hash_size, hash_length ); + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* ESP_SHA_DRIVER_ENABLED */ + +#if defined(ESP_MD5_DRIVER_ENABLED) + status = esp_md5_hash_compute(alg, input, input_length, + hash, hash_size, hash_length ); + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* ESP_MD5_DRIVER_ENABLED */ + +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + /* If software fallback is compiled in, try fallback */ +#if defined(MBEDTLS_PSA_BUILTIN_HASH) + status = mbedtls_psa_hash_compute( alg, input, input_length, + hash, hash_size, hash_length ); + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif + (void) status; + (void) alg; + (void) input; + (void) input_length; + (void) hash; + (void) hash_size; + (void) hash_length; + + return( PSA_ERROR_NOT_SUPPORTED ); +} + +static inline psa_status_t psa_driver_wrapper_hash_setup( + psa_hash_operation_t *operation, + psa_algorithm_t alg ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + /* Try setup on accelerators first */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_hash_setup( + &operation->ctx.test_driver_ctx, alg ); + if( status == PSA_SUCCESS ) + operation->id = MBEDTLS_TEST_TRANSPARENT_DRIVER_ID; + + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif + +#if defined(ESP_SHA_DRIVER_ENABLED) + status = esp_sha_hash_setup(&operation->ctx.esp_ctx, alg); + if( status == PSA_SUCCESS ) + operation->id = ESP_SHA_TRANSPARENT_DRIVER_ID; + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* ESP_SHA_DRIVER_ENABLED */ + +#if defined(ESP_MD5_DRIVER_ENABLED) + status = esp_md5_hash_setup(&operation->ctx.md5_ctx, alg); + if( status == PSA_SUCCESS ) + operation->id = ESP_MD5_TRANSPARENT_DRIVER_ID; + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* ESP_MD5_DRIVER_ENABLED */ + +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + /* If software fallback is compiled in, try fallback */ +#if defined(MBEDTLS_PSA_BUILTIN_HASH) + status = mbedtls_psa_hash_setup( &operation->ctx.mbedtls_ctx, alg ); + if( status == PSA_SUCCESS ) + operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID; + + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif + /* Nothing left to try if we fall through here */ + (void) status; + (void) operation; + (void) alg; + return( PSA_ERROR_NOT_SUPPORTED ); +} + +static inline psa_status_t psa_driver_wrapper_hash_clone( + const psa_hash_operation_t *source_operation, + psa_hash_operation_t *target_operation ) +{ + switch( source_operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_HASH) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + target_operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID; + return( mbedtls_psa_hash_clone( &source_operation->ctx.mbedtls_ctx, + &target_operation->ctx.mbedtls_ctx ) ); +#endif +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_SHA_DRIVER_ENABLED) + case ESP_SHA_TRANSPARENT_DRIVER_ID: + target_operation->id = ESP_SHA_TRANSPARENT_DRIVER_ID; + return( esp_sha_hash_clone( + &source_operation->ctx.esp_ctx, + &target_operation->ctx.esp_ctx ) ); +#endif /* ESP_SHA_DRIVER_ENABLED */ +#if defined(ESP_MD5_DRIVER_ENABLED) + case ESP_MD5_TRANSPARENT_DRIVER_ID: + target_operation->id = ESP_MD5_TRANSPARENT_DRIVER_ID; + return( esp_md5_hash_clone( + &source_operation->ctx.md5_ctx, + &target_operation->ctx.md5_ctx ) ); +#endif /* ESP_MD5_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + target_operation->id = MBEDTLS_TEST_TRANSPARENT_DRIVER_ID; + return( mbedtls_test_transparent_hash_clone( + &source_operation->ctx.test_driver_ctx, + &target_operation->ctx.test_driver_ctx ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + (void) target_operation; + return( PSA_ERROR_BAD_STATE ); + } +} + +static inline psa_status_t psa_driver_wrapper_hash_update( + psa_hash_operation_t *operation, + const uint8_t *input, + size_t input_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_HASH) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_hash_update( &operation->ctx.mbedtls_ctx, + input, input_length ) ); +#endif +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_hash_update( + &operation->ctx.test_driver_ctx, + input, input_length ) ); +#endif +#if defined(ESP_SHA_DRIVER_ENABLED) + case ESP_SHA_TRANSPARENT_DRIVER_ID: + return( esp_sha_hash_update( + &operation->ctx.esp_ctx, + input, input_length ) ); +#endif /* ESP_SHA_DRIVER_ENABLED */ +#if defined(ESP_MD5_DRIVER_ENABLED) + case ESP_MD5_TRANSPARENT_DRIVER_ID: + return( esp_md5_hash_update( + &operation->ctx.md5_ctx, + input, input_length ) ); +#endif /* ESP_MD5_DRIVER_ENABLED */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + (void) input; + (void) input_length; + return( PSA_ERROR_BAD_STATE ); + } +} + +static inline psa_status_t psa_driver_wrapper_hash_finish( + psa_hash_operation_t *operation, + uint8_t *hash, + size_t hash_size, + size_t *hash_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_HASH) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_hash_finish( &operation->ctx.mbedtls_ctx, + hash, hash_size, hash_length ) ); +#endif +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_hash_finish( + &operation->ctx.test_driver_ctx, + hash, hash_size, hash_length ) ); +#endif + +#if defined(ESP_SHA_DRIVER_ENABLED) + case ESP_SHA_TRANSPARENT_DRIVER_ID: + return( esp_sha_hash_finish( + &operation->ctx.esp_ctx, + hash, hash_size, hash_length ) ); +#endif /* ESP_SHA_DRIVER_ENABLED */ +#if defined(ESP_MD5_DRIVER_ENABLED) + case ESP_MD5_TRANSPARENT_DRIVER_ID: + return( esp_md5_hash_finish( + &operation->ctx.md5_ctx, + hash, hash_size, hash_length ) ); +#endif /* ESP_MD5_DRIVER_ENABLED */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + (void) hash; + (void) hash_size; + (void) hash_length; + return( PSA_ERROR_BAD_STATE ); + } +} + +static inline psa_status_t psa_driver_wrapper_hash_abort( + psa_hash_operation_t *operation ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_HASH) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_hash_abort( &operation->ctx.mbedtls_ctx ) ); +#endif +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_hash_abort( + &operation->ctx.test_driver_ctx ) ); +#endif +#if defined(ESP_SHA_DRIVER_ENABLED) + case ESP_SHA_TRANSPARENT_DRIVER_ID: + return( esp_sha_hash_abort( + &operation->ctx.esp_ctx ) ); +#endif /* ESP_SHA_DRIVER_ENABLED */ +#if defined(ESP_MD5_DRIVER_ENABLED) + case ESP_MD5_TRANSPARENT_DRIVER_ID: + return( esp_md5_hash_abort( + &operation->ctx.md5_ctx ) ); +#endif /* ESP_MD5_DRIVER_ENABLED */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + return( PSA_ERROR_BAD_STATE ); + } +} + +/* + * XOF functions + */ +static inline psa_status_t psa_driver_wrapper_xof_setup( + psa_xof_operation_t *operation, + psa_algorithm_t alg ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + /* Try setup on accelerators first */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_xof_setup( + &operation->ctx.test_driver_ctx, alg ); + if( status == PSA_SUCCESS ) + operation->id = MBEDTLS_TEST_TRANSPARENT_DRIVER_ID; + + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif + + /* If software fallback is compiled in, try fallback */ +#if defined(MBEDTLS_PSA_BUILTIN_XOF) + status = mbedtls_psa_xof_setup( &operation->ctx.mbedtls_ctx, alg ); + if( status == PSA_SUCCESS ) + operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID; + + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif + /* Nothing left to try if we fall through here */ + (void) status; + (void) operation; + (void) alg; + return( PSA_ERROR_NOT_SUPPORTED ); +} + +static inline psa_status_t psa_driver_wrapper_xof_set_context( + psa_xof_operation_t *operation, + const uint8_t *context, + size_t context_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_XOF) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_xof_set_context( &operation->ctx.mbedtls_ctx, + context, context_length ) ); +#endif +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_xof_set_context( + &operation->ctx.test_driver_ctx, + context, context_length ) ); +#endif + default: + (void) context; + (void) context_length; + return( PSA_ERROR_BAD_STATE ); + } +} + +static inline psa_status_t psa_driver_wrapper_xof_update( + psa_xof_operation_t *operation, + const uint8_t *input, + size_t input_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_XOF) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_xof_update( &operation->ctx.mbedtls_ctx, + input, input_length ) ); +#endif +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_xof_update( + &operation->ctx.test_driver_ctx, + input, input_length ) ); +#endif + default: + (void) input; + (void) input_length; + return( PSA_ERROR_BAD_STATE ); + } +} + +static inline psa_status_t psa_driver_wrapper_xof_output( + psa_xof_operation_t *operation, + uint8_t *output, + size_t output_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_XOF) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_xof_output( &operation->ctx.mbedtls_ctx, + output, output_length ) ); +#endif +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_xof_output( + &operation->ctx.test_driver_ctx, + output, output_length ) ); +#endif + default: + (void) output; + (void) output_length; + return( PSA_ERROR_BAD_STATE ); + } +} + +static inline psa_status_t psa_driver_wrapper_xof_abort( + psa_xof_operation_t *operation ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_XOF) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_xof_abort( &operation->ctx.mbedtls_ctx ) ); +#endif +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_xof_abort( + &operation->ctx.test_driver_ctx ) ); +#endif + default: + return( PSA_ERROR_BAD_STATE ); + } +} + +/* + * AEAD functions + */ +static inline psa_status_t psa_driver_wrapper_aead_encrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *nonce, size_t nonce_length, + const uint8_t *additional_data, size_t additional_data_length, + const uint8_t *plaintext, size_t plaintext_length, + uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_length ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + status = esp_crypto_aes_gcm_encrypt( + attributes, key_buffer, key_buffer_size, + alg, + nonce, nonce_length, + additional_data, additional_data_length, + plaintext, plaintext_length, + ciphertext, ciphertext_size, ciphertext_length ); +#ifdef MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK + if( status != PSA_ERROR_NOT_SUPPORTED ) +#endif /* MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK */ + { + return( status ); + } +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_aead_encrypt( + attributes, key_buffer, key_buffer_size, + alg, + nonce, nonce_length, + additional_data, additional_data_length, + plaintext, plaintext_length, + ciphertext, ciphertext_size, ciphertext_length ); + /* Declared with fallback == true */ + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + /* Fell through, meaning no accelerator supports this operation */ +#if defined(MBEDTLS_PSA_BUILTIN_AEAD) + return( mbedtls_psa_aead_encrypt( + attributes, key_buffer, key_buffer_size, + alg, + nonce, nonce_length, + additional_data, additional_data_length, + plaintext, plaintext_length, + ciphertext, ciphertext_size, ciphertext_length ) ); +#else + return( PSA_ERROR_NOT_SUPPORTED ); +#endif + + /* Add cases for opaque driver here */ + + default: + /* Key is declared with a lifetime not known to us */ + (void)status; + (void) key_buffer; (void) key_buffer_size; + (void) alg; + (void) nonce; (void) nonce_length; + (void) additional_data; (void) additional_data_length; + (void) plaintext; (void) plaintext_length; + (void) ciphertext; (void) ciphertext_size; (void) ciphertext_length; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_aead_decrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *nonce, size_t nonce_length, + const uint8_t *additional_data, size_t additional_data_length, + const uint8_t *ciphertext, size_t ciphertext_length, + uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_length ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + status = esp_crypto_aes_gcm_decrypt( + attributes, key_buffer, key_buffer_size, + alg, + nonce, nonce_length, + additional_data, additional_data_length, + ciphertext, ciphertext_length, + plaintext, plaintext_size, plaintext_length ); +#ifdef MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK + if( status != PSA_ERROR_NOT_SUPPORTED ) +#endif /* MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK */ + { + return( status ); + } +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_aead_decrypt( + attributes, key_buffer, key_buffer_size, + alg, + nonce, nonce_length, + additional_data, additional_data_length, + ciphertext, ciphertext_length, + plaintext, plaintext_size, plaintext_length ); + /* Declared with fallback == true */ + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + /* Fell through, meaning no accelerator supports this operation */ +#if defined(MBEDTLS_PSA_BUILTIN_AEAD) + return( mbedtls_psa_aead_decrypt( + attributes, key_buffer, key_buffer_size, + alg, + nonce, nonce_length, + additional_data, additional_data_length, + ciphertext, ciphertext_length, + plaintext, plaintext_size, plaintext_length ) ); +#else + return( PSA_ERROR_NOT_SUPPORTED ); +#endif + + /* Add cases for opaque driver here */ + + default: + /* Key is declared with a lifetime not known to us */ + (void)status; + (void) key_buffer; (void) key_buffer_size; + (void) alg; + (void) nonce; (void) nonce_length; + (void) additional_data; (void) additional_data_length; + (void) ciphertext; (void) ciphertext_length; + (void) plaintext; (void) plaintext_size; (void) plaintext_length; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_aead_encrypt_setup( + psa_aead_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + status = esp_crypto_aes_gcm_encrypt_setup( + &operation->ctx.esp_aes_gcm_ctx, + attributes, key_buffer, key_buffer_size, + alg); + if ( status == PSA_SUCCESS ) { + operation->id = ESP_AES_TRANSPARENT_DRIVER_ID; + } +#ifdef MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK + if( status != PSA_ERROR_NOT_SUPPORTED ) +#endif /* MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK */ + { + return( status ); + } +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + operation->id = MBEDTLS_TEST_TRANSPARENT_DRIVER_ID; + status = mbedtls_test_transparent_aead_encrypt_setup( + &operation->ctx.transparent_test_driver_ctx, + attributes, key_buffer, key_buffer_size, + alg ); + + /* Declared with fallback == true */ + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + /* Fell through, meaning no accelerator supports this operation */ +#if defined(MBEDTLS_PSA_BUILTIN_AEAD) + operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID; + status = mbedtls_psa_aead_encrypt_setup( + &operation->ctx.mbedtls_ctx, attributes, + key_buffer, key_buffer_size, + alg ); + return( status ); +#else + return( PSA_ERROR_NOT_SUPPORTED ); +#endif + + /* Add cases for opaque driver here */ + + default: + /* Key is declared with a lifetime not known to us */ + (void)status; + (void) operation; + (void) key_buffer; (void) key_buffer_size; + (void) alg; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_aead_decrypt_setup( + psa_aead_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + status = esp_crypto_aes_gcm_decrypt_setup( + &operation->ctx.esp_aes_gcm_ctx, + attributes, key_buffer, key_buffer_size, + alg); + if ( status == PSA_SUCCESS ) { + operation->id = ESP_AES_TRANSPARENT_DRIVER_ID; + } +#ifdef MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK + if( status != PSA_ERROR_NOT_SUPPORTED ) +#endif /* MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK */ + { + return( status ); + } +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + operation->id = MBEDTLS_TEST_TRANSPARENT_DRIVER_ID; + status = mbedtls_test_transparent_aead_decrypt_setup( + &operation->ctx.transparent_test_driver_ctx, + attributes, + key_buffer, key_buffer_size, + alg ); + + /* Declared with fallback == true */ + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + /* Fell through, meaning no accelerator supports this operation */ +#if defined(MBEDTLS_PSA_BUILTIN_AEAD) + operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID; + status = mbedtls_psa_aead_decrypt_setup( + &operation->ctx.mbedtls_ctx, + attributes, + key_buffer, key_buffer_size, + alg ); + return( status ); +#else + return( PSA_ERROR_NOT_SUPPORTED ); +#endif + /* Add cases for opaque driver here */ + + default: + /* Key is declared with a lifetime not known to us */ + (void)status; + (void) operation; + (void) key_buffer; (void)key_buffer_size; + (void) alg; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_aead_set_nonce( + psa_aead_operation_t *operation, + const uint8_t *nonce, + size_t nonce_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_AEAD) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_aead_set_nonce( &operation->ctx.mbedtls_ctx, + nonce, + nonce_length ) ); + +#endif /* MBEDTLS_PSA_BUILTIN_AEAD */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + case ESP_AES_TRANSPARENT_DRIVER_ID: + return esp_crypto_aes_gcm_set_nonce( + &operation->ctx.esp_aes_gcm_ctx, + nonce, + nonce_length); +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_aead_set_nonce( + &operation->ctx.transparent_test_driver_ctx, + nonce, nonce_length ) ); + + /* Add cases for opaque driver here */ + +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + } + + (void)nonce; + (void)nonce_length; + + return( PSA_ERROR_INVALID_ARGUMENT ); +} + +static inline psa_status_t psa_driver_wrapper_aead_set_lengths( + psa_aead_operation_t *operation, + size_t ad_length, + size_t plaintext_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_AEAD) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_aead_set_lengths( &operation->ctx.mbedtls_ctx, + ad_length, + plaintext_length ) ); + +#endif /* MBEDTLS_PSA_BUILTIN_AEAD */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + case ESP_AES_TRANSPARENT_DRIVER_ID: + return PSA_SUCCESS; +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_aead_set_lengths( + &operation->ctx.transparent_test_driver_ctx, + ad_length, plaintext_length ) ); + + /* Add cases for opaque driver here */ + +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + } + + (void)ad_length; + (void)plaintext_length; + + return( PSA_ERROR_INVALID_ARGUMENT ); +} + +static inline psa_status_t psa_driver_wrapper_aead_update_ad( + psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_AEAD) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_aead_update_ad( &operation->ctx.mbedtls_ctx, + input, + input_length ) ); + +#endif /* MBEDTLS_PSA_BUILTIN_AEAD */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + case ESP_AES_TRANSPARENT_DRIVER_ID: + return esp_crypto_aes_gcm_update_ad( + &operation->ctx.esp_aes_gcm_ctx, + input, + input_length); +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_aead_update_ad( + &operation->ctx.transparent_test_driver_ctx, + input, input_length ) ); + + /* Add cases for opaque driver here */ + +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + } + + (void)input; + (void)input_length; + + return( PSA_ERROR_INVALID_ARGUMENT ); +} + +static inline psa_status_t psa_driver_wrapper_aead_update( + psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_AEAD) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_aead_update( &operation->ctx.mbedtls_ctx, + input, input_length, + output, output_size, + output_length ) ); + +#endif /* MBEDTLS_PSA_BUILTIN_AEAD */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + case ESP_AES_TRANSPARENT_DRIVER_ID: + return esp_crypto_aes_gcm_update( + &operation->ctx.esp_aes_gcm_ctx, + input, input_length, output, output_size, output_length); +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_aead_update( + &operation->ctx.transparent_test_driver_ctx, + input, input_length, output, output_size, + output_length ) ); + + /* Add cases for opaque driver here */ + +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + } + + (void)input; + (void)input_length; + (void)output; + (void)output_size; + (void)output_length; + + return( PSA_ERROR_INVALID_ARGUMENT ); +} + +static inline psa_status_t psa_driver_wrapper_aead_finish( + psa_aead_operation_t *operation, + uint8_t *ciphertext, + size_t ciphertext_size, + size_t *ciphertext_length, + uint8_t *tag, + size_t tag_size, + size_t *tag_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_AEAD) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_aead_finish( &operation->ctx.mbedtls_ctx, + ciphertext, + ciphertext_size, + ciphertext_length, tag, + tag_size, tag_length ) ); + +#endif /* MBEDTLS_PSA_BUILTIN_AEAD */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + case ESP_AES_TRANSPARENT_DRIVER_ID: + return esp_crypto_aes_gcm_finish( + &operation->ctx.esp_aes_gcm_ctx, + ciphertext, ciphertext_size, ciphertext_length, tag, tag_size, tag_length); +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_aead_finish( + &operation->ctx.transparent_test_driver_ctx, + ciphertext, ciphertext_size, + ciphertext_length, tag, tag_size, tag_length ) ); + + /* Add cases for opaque driver here */ + +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + } + + (void)ciphertext; + (void)ciphertext_size; + (void)ciphertext_length; + (void)tag; + (void)tag_size; + (void)tag_length; + + return( PSA_ERROR_INVALID_ARGUMENT ); +} + +static inline psa_status_t psa_driver_wrapper_aead_verify( + psa_aead_operation_t *operation, + uint8_t *plaintext, + size_t plaintext_size, + size_t *plaintext_length, + const uint8_t *tag, + size_t tag_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_AEAD) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + { + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + uint8_t check_tag[PSA_AEAD_TAG_MAX_SIZE]; + size_t check_tag_length; + + status = mbedtls_psa_aead_finish( &operation->ctx.mbedtls_ctx, + plaintext, + plaintext_size, + plaintext_length, + check_tag, + sizeof( check_tag ), + &check_tag_length ); + + if( status == PSA_SUCCESS ) + { + if( tag_length != check_tag_length || + mbedtls_ct_memcmp( tag, check_tag, tag_length ) + != 0 ) + status = PSA_ERROR_INVALID_SIGNATURE; + } + + mbedtls_platform_zeroize( check_tag, sizeof( check_tag ) ); + + return( status ); + } + +#endif /* MBEDTLS_PSA_BUILTIN_AEAD */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + case ESP_AES_TRANSPARENT_DRIVER_ID: + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + uint8_t check_tag[PSA_AEAD_TAG_MAX_SIZE]; + size_t check_tag_length; + + status = esp_crypto_aes_gcm_finish(&operation->ctx.esp_aes_gcm_ctx, + plaintext, plaintext_size, plaintext_length, check_tag, sizeof(check_tag), &check_tag_length); + + if(status == PSA_SUCCESS) { + if(tag_length != check_tag_length || mbedtls_ct_memcmp(tag, check_tag, tag_length) != 0) { + status = PSA_ERROR_INVALID_SIGNATURE; + } + } + + mbedtls_platform_zeroize(check_tag, sizeof(check_tag)); + + return(status); +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_aead_verify( + &operation->ctx.transparent_test_driver_ctx, + plaintext, plaintext_size, + plaintext_length, tag, tag_length ) ); + + /* Add cases for opaque driver here */ + +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + } + + (void)plaintext; + (void)plaintext_size; + (void)plaintext_length; + (void)tag; + (void)tag_length; + + return( PSA_ERROR_INVALID_ARGUMENT ); +} + +static inline psa_status_t psa_driver_wrapper_aead_abort( + psa_aead_operation_t *operation ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_AEAD) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_aead_abort( &operation->ctx.mbedtls_ctx ) ); + +#endif /* MBEDTLS_PSA_BUILTIN_AEAD */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_AES_DRIVER_ENABLED) + case ESP_AES_TRANSPARENT_DRIVER_ID: + return (esp_crypto_aes_gcm_abort(&operation->ctx.esp_aes_gcm_ctx)); +#endif /* ESP_AES_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_aead_abort( + &operation->ctx.transparent_test_driver_ctx ) ); + + /* Add cases for opaque driver here */ + +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + } + + return( PSA_ERROR_INVALID_ARGUMENT ); +} + +/* + * MAC functions + */ +static inline psa_status_t psa_driver_wrapper_mac_compute( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *mac, + size_t mac_size, + size_t *mac_length ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_CMAC_DRIVER_ENABLED) + if (PSA_ALG_FULL_LENGTH_MAC(alg) == PSA_ALG_CMAC) { + status = esp_cmac_compute(attributes, key_buffer, key_buffer_size, alg, + input, input_length, + mac, mac_size, mac_length ); + if (status != PSA_ERROR_NOT_SUPPORTED) { + return status; + } + } +#endif /* ESP_CMAC_DRIVER_ENABLED */ +#if defined(ESP_HMAC_TRANSPARENT_DRIVER_ENABLED) + if (PSA_ALG_IS_HMAC(alg)) { + status = esp_hmac_compute_transparent( + attributes, key_buffer, key_buffer_size, alg, + input, input_length, + mac, mac_size, mac_length ); + if (status != PSA_ERROR_NOT_SUPPORTED) { + return status; + } + } +#endif /* ESP_HMAC_TRANSPARENT_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_mac_compute( + attributes, key_buffer, key_buffer_size, alg, + input, input_length, + mac, mac_size, mac_length ); + /* Declared with fallback == true */ + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ +#if defined(MBEDTLS_PSA_BUILTIN_MAC) + /* Fell through, meaning no accelerator supports this operation */ + status = mbedtls_psa_mac_compute( + attributes, key_buffer, key_buffer_size, alg, + input, input_length, + mac, mac_size, mac_length ); + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* MBEDTLS_PSA_BUILTIN_MAC */ + return( PSA_ERROR_NOT_SUPPORTED ); + + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LOCATION: + status = mbedtls_test_opaque_mac_compute( + attributes, key_buffer, key_buffer_size, alg, + input, input_length, + mac, mac_size, mac_length ); + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(ESP_HMAC_OPAQUE_DRIVER_ENABLED) + case PSA_KEY_LOCATION_ESP_HMAC: + if (PSA_ALG_IS_HMAC(alg)) { + status = esp_hmac_compute_opaque( + attributes, key_buffer, key_buffer_size, alg, + input, input_length, + mac, mac_size, mac_length ); + return( status ); + } else { + return PSA_ERROR_INVALID_ARGUMENT; + } +#endif /* ESP_HMAC_OPAQUE_DRIVER_ENABLED */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + /* Key is declared with a lifetime not known to us */ + (void) key_buffer; + (void) key_buffer_size; + (void) alg; + (void) input; + (void) input_length; + (void) mac; + (void) mac_size; + (void) mac_length; + (void) status; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_mac_sign_setup( + psa_mac_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_CMAC_DRIVER_ENABLED) + if (PSA_ALG_FULL_LENGTH_MAC(alg) == PSA_ALG_CMAC) { + status = esp_cmac_setup( &operation->ctx.esp_cmac_ctx, + attributes, + key_buffer, key_buffer_size, + alg ); + if( status == PSA_SUCCESS ) + operation->id = ESP_CMAC_TRANSPARENT_DRIVER_ID; + if (status != PSA_ERROR_NOT_SUPPORTED) { + return status; + } + } else +#endif /* ESP_CMAC_DRIVER_ENABLED */ +#if defined(ESP_HMAC_TRANSPARENT_DRIVER_ENABLED) + if (PSA_ALG_IS_HMAC(alg)) { + status = esp_hmac_setup_transparent( &operation->ctx.esp_hmac_transparent_ctx, + attributes, + key_buffer, key_buffer_size, + alg ); + if ( status == PSA_SUCCESS ) + operation->id = ESP_HMAC_TRANSPARENT_DRIVER_ID; + if (status != PSA_ERROR_NOT_SUPPORTED) { + return status; + } + } +#endif /* ESP_HMAC_TRANSPARENT_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_mac_sign_setup( + &operation->ctx.transparent_test_driver_ctx, + attributes, + key_buffer, key_buffer_size, + alg ); + /* Declared with fallback == true */ + if( status == PSA_SUCCESS ) + operation->id = MBEDTLS_TEST_TRANSPARENT_DRIVER_ID; + + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ +#if defined(MBEDTLS_PSA_BUILTIN_MAC) + /* Fell through, meaning no accelerator supports this operation */ + status = mbedtls_psa_mac_sign_setup( &operation->ctx.mbedtls_ctx, + attributes, + key_buffer, key_buffer_size, + alg ); + if( status == PSA_SUCCESS ) + operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID; + + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* MBEDTLS_PSA_BUILTIN_MAC */ + return( PSA_ERROR_NOT_SUPPORTED ); + + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LOCATION: + status = mbedtls_test_opaque_mac_sign_setup( + &operation->ctx.opaque_test_driver_ctx, + attributes, + key_buffer, key_buffer_size, + alg ); + + if( status == PSA_SUCCESS ) + operation->id = MBEDTLS_TEST_OPAQUE_DRIVER_ID; + + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(ESP_HMAC_OPAQUE_DRIVER_ENABLED) + case PSA_KEY_LOCATION_ESP_HMAC: + if (PSA_ALG_IS_HMAC(alg)) { + status = esp_hmac_setup_opaque( + &operation->ctx.esp_hmac_opaque_ctx, + attributes, key_buffer, key_buffer_size, alg ); + if ( status == PSA_SUCCESS ) + operation->id = ESP_HMAC_OPAQUE_DRIVER_ID; + return( status ); + } else { + return PSA_ERROR_INVALID_ARGUMENT; + } +#endif /* ESP_HMAC_OPAQUE_DRIVER_ENABLED */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + /* Key is declared with a lifetime not known to us */ + (void) status; + (void) operation; + (void) key_buffer; + (void) key_buffer_size; + (void) alg; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_mac_verify_setup( + psa_mac_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_CMAC_DRIVER_ENABLED) + if (PSA_ALG_FULL_LENGTH_MAC(alg) == PSA_ALG_CMAC) { + status = esp_cmac_setup( &operation->ctx.esp_cmac_ctx, + attributes, + key_buffer, key_buffer_size, + alg ); + if( status == PSA_SUCCESS ) + operation->id = ESP_CMAC_TRANSPARENT_DRIVER_ID; + if (status != PSA_ERROR_NOT_SUPPORTED) { + return status; + } + } else +#endif /* ESP_CMAC_DRIVER_ENABLED */ +#if defined(ESP_HMAC_TRANSPARENT_DRIVER_ENABLED) + if (PSA_ALG_IS_HMAC(alg)) { + status = esp_hmac_setup_transparent( &operation->ctx.esp_hmac_transparent_ctx, + attributes, + key_buffer, key_buffer_size, + alg ); + if (status == PSA_SUCCESS) + operation->id = ESP_HMAC_TRANSPARENT_DRIVER_ID; + if (status != PSA_ERROR_NOT_SUPPORTED) { + return status; + } + } +#endif /* ESP_HMAC_TRANSPARENT_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_mac_verify_setup( + &operation->ctx.transparent_test_driver_ctx, + attributes, + key_buffer, key_buffer_size, + alg ); + /* Declared with fallback == true */ + if( status == PSA_SUCCESS ) + operation->id = MBEDTLS_TEST_TRANSPARENT_DRIVER_ID; + + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ +#if defined(MBEDTLS_PSA_BUILTIN_MAC) + /* Fell through, meaning no accelerator supports this operation */ + status = mbedtls_psa_mac_verify_setup( &operation->ctx.mbedtls_ctx, + attributes, + key_buffer, key_buffer_size, + alg ); + if( status == PSA_SUCCESS ) + operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID; + + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* MBEDTLS_PSA_BUILTIN_MAC */ + return( PSA_ERROR_NOT_SUPPORTED ); + + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LOCATION: + status = mbedtls_test_opaque_mac_verify_setup( + &operation->ctx.opaque_test_driver_ctx, + attributes, + key_buffer, key_buffer_size, + alg ); + + if( status == PSA_SUCCESS ) + operation->id = MBEDTLS_TEST_OPAQUE_DRIVER_ID; + + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(ESP_HMAC_OPAQUE_DRIVER_ENABLED) + case PSA_KEY_LOCATION_ESP_HMAC: + if (PSA_ALG_IS_HMAC(alg)) { + status = esp_hmac_setup_opaque( + &operation->ctx.esp_hmac_opaque_ctx, + attributes, key_buffer, key_buffer_size, alg ); + if ( status == PSA_SUCCESS ) + operation->id = ESP_HMAC_OPAQUE_DRIVER_ID; + return( status ); + } else { + return PSA_ERROR_INVALID_ARGUMENT; + } +#endif /* ESP_HMAC_OPAQUE_DRIVER_ENABLED */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + /* Key is declared with a lifetime not known to us */ + (void) status; + (void) operation; + (void) key_buffer; + (void) key_buffer_size; + (void) alg; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_mac_update( + psa_mac_operation_t *operation, + const uint8_t *input, + size_t input_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_MAC) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_mac_update( &operation->ctx.mbedtls_ctx, + input, input_length ) ); +#endif /* MBEDTLS_PSA_BUILTIN_MAC */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_CMAC_DRIVER_ENABLED) + case ESP_CMAC_TRANSPARENT_DRIVER_ID: + return (esp_cmac_update( &operation->ctx.esp_cmac_ctx, + input, input_length )); +#endif /* ESP_CMAC_DRIVER_ENABLED */ +#if defined(ESP_HMAC_TRANSPARENT_DRIVER_ENABLED) + case ESP_HMAC_TRANSPARENT_DRIVER_ID: + return (esp_hmac_update_transparent( &operation->ctx.esp_hmac_transparent_ctx, + input, input_length )); +#endif /* ESP_HMAC_TRANSPARENT_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_mac_update( + &operation->ctx.transparent_test_driver_ctx, + input, input_length ) ); + + case MBEDTLS_TEST_OPAQUE_DRIVER_ID: + return( mbedtls_test_opaque_mac_update( + &operation->ctx.opaque_test_driver_ctx, + input, input_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(ESP_HMAC_OPAQUE_DRIVER_ENABLED) + case ESP_HMAC_OPAQUE_DRIVER_ID: + return (esp_hmac_update_opaque( &operation->ctx.esp_hmac_opaque_ctx, + input, input_length )); +#endif /* ESP_HMAC_OPAQUE_DRIVER_ENABLED */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + (void) input; + (void) input_length; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_mac_sign_finish( + psa_mac_operation_t *operation, + uint8_t *mac, + size_t mac_size, + size_t *mac_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_MAC) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_mac_sign_finish( &operation->ctx.mbedtls_ctx, + mac, mac_size, mac_length ) ); +#endif /* MBEDTLS_PSA_BUILTIN_MAC */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_CMAC_DRIVER_ENABLED) + case ESP_CMAC_TRANSPARENT_DRIVER_ID: + return (esp_cmac_finish( &operation->ctx.esp_cmac_ctx, + mac, mac_size, mac_length )); +#endif /* ESP_CMAC_DRIVER_ENABLED */ +#if defined(ESP_HMAC_TRANSPARENT_DRIVER_ENABLED) + case ESP_HMAC_TRANSPARENT_DRIVER_ID: + return (esp_hmac_finish_transparent( &operation->ctx.esp_hmac_transparent_ctx, + mac, mac_size, mac_length )); +#endif /* ESP_HMAC_TRANSPARENT_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_mac_sign_finish( + &operation->ctx.transparent_test_driver_ctx, + mac, mac_size, mac_length ) ); + + case MBEDTLS_TEST_OPAQUE_DRIVER_ID: + return( mbedtls_test_opaque_mac_sign_finish( + &operation->ctx.opaque_test_driver_ctx, + mac, mac_size, mac_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(ESP_HMAC_OPAQUE_DRIVER_ENABLED) + case ESP_HMAC_OPAQUE_DRIVER_ID: + return (esp_hmac_finish_opaque( &operation->ctx.esp_hmac_opaque_ctx, + mac, mac_size, mac_length )); +#endif /* ESP_HMAC_OPAQUE_DRIVER_ENABLED */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + (void) mac; + (void) mac_size; + (void) mac_length; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_mac_verify_finish( + psa_mac_operation_t *operation, + const uint8_t *mac, + size_t mac_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_MAC) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_mac_verify_finish( &operation->ctx.mbedtls_ctx, + mac, mac_length ) ); +#endif /* MBEDTLS_PSA_BUILTIN_MAC */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_CMAC_DRIVER_ENABLED) + case ESP_CMAC_TRANSPARENT_DRIVER_ID: + return (esp_cmac_verify_finish( &operation->ctx.esp_cmac_ctx, + mac, mac_length )); +#endif /* ESP_CMAC_DRIVER_ENABLED */ +#if defined(ESP_HMAC_TRANSPARENT_DRIVER_ENABLED) + case ESP_HMAC_TRANSPARENT_DRIVER_ID: + return (esp_hmac_verify_finish_transparent( &operation->ctx.esp_hmac_transparent_ctx, + mac, mac_length )); +#endif /* ESP_HMAC_TRANSPARENT_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_mac_verify_finish( + &operation->ctx.transparent_test_driver_ctx, + mac, mac_length ) ); + + case MBEDTLS_TEST_OPAQUE_DRIVER_ID: + return( mbedtls_test_opaque_mac_verify_finish( + &operation->ctx.opaque_test_driver_ctx, + mac, mac_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(ESP_HMAC_OPAQUE_DRIVER_ENABLED) + case ESP_HMAC_OPAQUE_DRIVER_ID: + return (esp_hmac_verify_finish_opaque( &operation->ctx.esp_hmac_opaque_ctx, + mac, mac_length )); +#endif /* ESP_HMAC_OPAQUE_DRIVER_ENABLED */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + (void) mac; + (void) mac_length; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_mac_abort( + psa_mac_operation_t *operation ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_MAC) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_mac_abort( &operation->ctx.mbedtls_ctx ) ); +#endif /* MBEDTLS_PSA_BUILTIN_MAC */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(ESP_CMAC_DRIVER_ENABLED) + case ESP_CMAC_TRANSPARENT_DRIVER_ID: + return (esp_cmac_abort( &operation->ctx.esp_cmac_ctx )); +#endif /* ESP_CMAC_DRIVER_ENABLED */ +#if defined(ESP_HMAC_TRANSPARENT_DRIVER_ENABLED) + case ESP_HMAC_TRANSPARENT_DRIVER_ID: + return (esp_hmac_abort_transparent( &operation->ctx.esp_hmac_transparent_ctx )); +#endif /* ESP_HMAC_TRANSPARENT_DRIVER_ENABLED */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_mac_abort( + &operation->ctx.transparent_test_driver_ctx ) ); + case MBEDTLS_TEST_OPAQUE_DRIVER_ID: + return( mbedtls_test_opaque_mac_abort( + &operation->ctx.opaque_test_driver_ctx ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(ESP_HMAC_OPAQUE_DRIVER_ENABLED) + case ESP_HMAC_OPAQUE_DRIVER_ID: + return (esp_hmac_abort_opaque( &operation->ctx.esp_hmac_opaque_ctx )); +#endif /* ESP_HMAC_OPAQUE_DRIVER_ENABLED */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +/* + * Asymmetric cryptography + */ +static inline psa_status_t psa_driver_wrapper_asymmetric_encrypt( + const psa_key_attributes_t *attributes, const uint8_t *key_buffer, + size_t key_buffer_size, psa_algorithm_t alg, const uint8_t *input, + size_t input_length, const uint8_t *salt, size_t salt_length, + uint8_t *output, size_t output_size, size_t *output_length ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_asymmetric_encrypt( attributes, + key_buffer, key_buffer_size, alg, input, input_length, + salt, salt_length, output, output_size, + output_length ); + /* Declared with fallback == true */ + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + return( mbedtls_psa_asymmetric_encrypt( attributes, + key_buffer, key_buffer_size, alg, input, input_length, + salt, salt_length, output, output_size, output_length ) + ); + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LOCATION: + return( mbedtls_test_opaque_asymmetric_encrypt( attributes, + key_buffer, key_buffer_size, alg, input, input_length, + salt, salt_length, output, output_size, output_length ) + ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + default: + /* Key is declared with a lifetime not known to us */ + (void)status; + (void)key_buffer; + (void)key_buffer_size; + (void)alg; + (void)input; + (void)input_length; + (void)salt; + (void)salt_length; + (void)output; + (void)output_size; + (void)output_length; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_asymmetric_decrypt( + const psa_key_attributes_t *attributes, const uint8_t *key_buffer, + size_t key_buffer_size, psa_algorithm_t alg, const uint8_t *input, + size_t input_length, const uint8_t *salt, size_t salt_length, + uint8_t *output, size_t output_size, size_t *output_length ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_asymmetric_decrypt( attributes, + key_buffer, key_buffer_size, alg, input, input_length, + salt, salt_length, output, output_size, + output_length ); + /* Declared with fallback == true */ + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + return( mbedtls_psa_asymmetric_decrypt( attributes, + key_buffer, key_buffer_size, alg,input, input_length, + salt, salt_length, output, output_size, + output_length ) ); + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LOCATION: + return( mbedtls_test_opaque_asymmetric_decrypt( attributes, + key_buffer, key_buffer_size, alg, input, input_length, + salt, salt_length, output, output_size, + output_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(ESP_RSA_DS_DRIVER_ENABLED) + case PSA_KEY_LOCATION_ESP_RSA_DS: + return( esp_rsa_ds_opaque_asymmetric_decrypt( attributes, + key_buffer, key_buffer_size, alg, input, input_length, + salt, salt_length, output, output_size, + output_length )); +#endif /* ESP_RSA_DS_DRIVER_ENABLED */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + default: + /* Key is declared with a lifetime not known to us */ + (void)status; + (void)key_buffer; + (void)key_buffer_size; + (void)alg; + (void)input; + (void)input_length; + (void)salt; + (void)salt_length; + (void)output; + (void)output_size; + (void)output_length; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_key_agreement( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *peer_key, + size_t peer_key_length, + uint8_t *shared_secret, + size_t shared_secret_size, + size_t *shared_secret_length + ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = + mbedtls_test_transparent_key_agreement( attributes, + key_buffer, key_buffer_size, alg, peer_key, + peer_key_length, shared_secret, shared_secret_size, + shared_secret_length ); + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED) + if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) && + PSA_ALG_IS_ECDH(alg) && + PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)) == PSA_ECC_FAMILY_SECP_R1 && + psa_get_key_bits(attributes) == 256 ) + { + status = p256_transparent_key_agreement( attributes, + key_buffer, + key_buffer_size, + alg, + peer_key, + peer_key_length, + shared_secret, + shared_secret_size, + shared_secret_length ); + if( status != PSA_ERROR_NOT_SUPPORTED) + return( status ); + } +#endif /* MBEDTLS_PSA_P256M_DRIVER_ENABLED */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + /* Software Fallback */ + status = psa_key_agreement_raw_builtin( attributes, + key_buffer, + key_buffer_size, + alg, + peer_key, + peer_key_length, + shared_secret, + shared_secret_size, + shared_secret_length ); + return( status ); +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LOCATION: + return( mbedtls_test_opaque_key_agreement( attributes, + key_buffer, key_buffer_size, alg, peer_key, + peer_key_length, shared_secret, shared_secret_size, + shared_secret_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + + default: + (void) attributes; + (void) key_buffer; + (void) key_buffer_size; + (void) peer_key; + (void) peer_key_length; + (void) shared_secret; + (void) shared_secret_size; + (void) shared_secret_length; + return( PSA_ERROR_NOT_SUPPORTED ); + + } +} + +static inline psa_status_t psa_driver_wrapper_pake_setup( + psa_pake_operation_t *operation, + const psa_crypto_driver_pake_inputs_t *inputs ) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + psa_key_location_t location = + PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime( &inputs->attributes ) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ + status = PSA_ERROR_NOT_SUPPORTED; +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = mbedtls_test_transparent_pake_setup( + &operation->data.ctx.transparent_test_driver_ctx, + inputs ); + if( status == PSA_SUCCESS ) + operation->id = MBEDTLS_TEST_TRANSPARENT_DRIVER_ID; + /* Declared with fallback == true */ + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ +#if defined(MBEDTLS_PSA_BUILTIN_PAKE) + status = mbedtls_psa_pake_setup( &operation->data.ctx.mbedtls_ctx, + inputs ); + if( status == PSA_SUCCESS ) + operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID; +#endif + return status; + /* Add cases for opaque driver here */ + default: + /* Key is declared with a lifetime not known to us */ + (void)operation; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_pake_output( + psa_pake_operation_t *operation, + psa_crypto_driver_pake_step_t step, + uint8_t *output, + size_t output_size, + size_t *output_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_PAKE) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_pake_output( &operation->data.ctx.mbedtls_ctx, step, + output, output_size, output_length ) ); +#endif /* MBEDTLS_PSA_BUILTIN_PAKE */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_pake_output( + &operation->data.ctx.transparent_test_driver_ctx, + step, output, output_size, output_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + (void) step; + (void) output; + (void) output_size; + (void) output_length; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_pake_input( + psa_pake_operation_t *operation, + psa_crypto_driver_pake_step_t step, + const uint8_t *input, + size_t input_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_PAKE) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_pake_input( &operation->data.ctx.mbedtls_ctx, + step, input, + input_length ) ); +#endif /* MBEDTLS_PSA_BUILTIN_PAKE */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_pake_input( + &operation->data.ctx.transparent_test_driver_ctx, + step, + input, input_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + (void) step; + (void) input; + (void) input_length; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_pake_get_shared_key( + psa_pake_operation_t *operation, + uint8_t *output, size_t output_size, + size_t *output_length ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_PAKE) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_pake_get_implicit_key( &operation->data.ctx.mbedtls_ctx, + output, output_size, output_length ) ); +#endif /* MBEDTLS_PSA_BUILTIN_PAKE */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_pake_get_implicit_key( + &operation->data.ctx.transparent_test_driver_ctx, + output, output_size, output_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + (void) output; + (void) output_size; + (void) output_length; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +static inline psa_status_t psa_driver_wrapper_pake_abort( + psa_pake_operation_t * operation ) +{ + switch( operation->id ) + { +#if defined(MBEDTLS_PSA_BUILTIN_PAKE) + case PSA_CRYPTO_MBED_TLS_DRIVER_ID: + return( mbedtls_psa_pake_abort( &operation->data.ctx.mbedtls_ctx ) ); +#endif /* MBEDTLS_PSA_BUILTIN_PAKE */ + +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +#if defined(PSA_CRYPTO_DRIVER_TEST) + case MBEDTLS_TEST_TRANSPARENT_DRIVER_ID: + return( mbedtls_test_transparent_pake_abort( + &operation->data.ctx.transparent_test_driver_ctx ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +#endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/tf-psa-crypto/core/psa_crypto_driver_wrappers_no_static.c b/tf-psa-crypto/core/psa_crypto_driver_wrappers_no_static.c new file mode 100644 index 0000000000..345faed4b0 --- /dev/null +++ b/tf-psa-crypto/core/psa_crypto_driver_wrappers_no_static.c @@ -0,0 +1,249 @@ +/* + * Functions to delegate cryptographic operations to an available + * and appropriate accelerator. + * Warning: This file is now auto-generated. + */ +/* Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + + +/* BEGIN-common headers */ +#include "tf_psa_crypto_common.h" +#include "psa_crypto_aead.h" +#include "psa_crypto_cipher.h" +#include "psa_crypto_core.h" +#include "psa_crypto_driver_wrappers_no_static.h" +#include "psa_crypto_hash.h" +#include "psa_crypto_mac.h" +#include "psa_crypto_pake.h" +#include "psa_crypto_rsa.h" + +#if defined(TF_PSA_CRYPTO_PQCP_MLDSA_ENABLED) +#include "psa_crypto_mldsa.h" +#endif + +#include "mbedtls/platform.h" +/* END-common headers */ + +#if defined(MBEDTLS_PSA_CRYPTO_C) + +/* BEGIN-driver headers */ +/* Headers for mbedtls_test opaque driver */ +#if defined(PSA_CRYPTO_DRIVER_TEST) +#include "test/drivers/test_driver.h" + +#endif +/* Headers for mbedtls_test transparent driver */ +#if defined(PSA_CRYPTO_DRIVER_TEST) +#include "test/drivers/test_driver.h" + +#endif +/* Headers for p256 transparent driver */ +#if defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED) +#include "../drivers/p256-m/p256-m_driver_entrypoints.h" + +#endif +/* Headers for esp_ecdsa opaque driver */ +#if defined(ESP_ECDSA_DRIVER_ENABLED) +#include "../../../port/psa_driver/include/psa_crypto_driver_esp_ecdsa.h" + +#endif + +/* END-driver headers */ + +/* Auto-generated values depending on which drivers are registered. + * ID 0 is reserved for unallocated operations. + * ID 1 is reserved for the Mbed TLS software driver. */ +/* BEGIN-driver id definition */ +#define PSA_CRYPTO_MBED_TLS_DRIVER_ID (1) +#define MBEDTLS_TEST_OPAQUE_DRIVER_ID (2) +#define MBEDTLS_TEST_TRANSPARENT_DRIVER_ID (3) +#define P256_TRANSPARENT_DRIVER_ID (4) + +/* END-driver id */ + +/* BEGIN-Common Macro definitions */ + +/* END-Common Macro definitions */ + +/** Get the key buffer size required to store the key material of a key + * associated with an opaque driver. + * + * \param[in] attributes The key attributes. + * \param[out] key_buffer_size Minimum buffer size to contain the key material + * + * \retval #PSA_SUCCESS + * The minimum size for a buffer to contain the key material has been + * returned successfully. + * \retval #PSA_ERROR_NOT_SUPPORTED + * The type and/or the size in bits of the key or the combination of + * the two is not supported. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The key is declared with a lifetime not known to us. + */ +psa_status_t psa_driver_wrapper_get_key_buffer_size( + const psa_key_attributes_t *attributes, + size_t *key_buffer_size ) +{ + psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + psa_key_type_t key_type = psa_get_key_type(attributes); + size_t key_bits = psa_get_key_bits(attributes); + + *key_buffer_size = 0; + switch( location ) + { +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LOCATION: +#if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS) + /* Emulate property 'builtin_key_size' */ + if( psa_key_id_is_builtin( + MBEDTLS_SVC_KEY_ID_GET_KEY_ID( + psa_get_key_id( attributes ) ) ) ) + { + *key_buffer_size = sizeof( psa_drv_slot_number_t ); + return( PSA_SUCCESS ); + } +#endif /* MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */ + *key_buffer_size = mbedtls_test_opaque_size_function( key_type, + key_bits ); + return( ( *key_buffer_size != 0 ) ? + PSA_SUCCESS : PSA_ERROR_NOT_SUPPORTED ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ + + default: + (void)key_type; + (void)key_bits; + return( PSA_ERROR_INVALID_ARGUMENT ); + } +} + +psa_status_t psa_driver_wrapper_export_public_key( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + uint8_t *data, size_t data_size, size_t *data_length ) + +{ + + psa_status_t status = PSA_ERROR_INVALID_ARGUMENT; + psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION( + psa_get_key_lifetime( attributes ) ); + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) + +#if (defined(PSA_CRYPTO_DRIVER_TEST) ) + status = mbedtls_test_transparent_export_public_key + (attributes, + key_buffer, + key_buffer_size, + data, + data_size, + data_length + ); + + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif + +#if (defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED) ) + status = p256_transparent_export_public_key + (attributes, + key_buffer, + key_buffer_size, + data, + data_size, + data_length + ); + + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif + + +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + /* Fell through, meaning no accelerator supports this operation */ + return( psa_export_public_key_internal( attributes, + key_buffer, + key_buffer_size, + data, + data_size, + data_length ) ); + + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) + +#if (defined(PSA_CRYPTO_DRIVER_TEST) ) + case 0x7fffff: + return( mbedtls_test_opaque_export_public_key + (attributes, + key_buffer, + key_buffer_size, + data, + data_size, + data_length + )); +#endif +#if defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_SIGN_DRIVER_ENABLED) + case PSA_KEY_LOCATION_ESP_ECDSA: + if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) && + PSA_ALG_IS_ECDSA( psa_get_key_algorithm(attributes) ) && + PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)) == PSA_ECC_FAMILY_SECP_R1) + { + return ( esp_ecdsa_opaque_export_public_key( + attributes, + key_buffer, + key_buffer_size, + data, + data_size, + data_length ) ); + } + return PSA_ERROR_INVALID_ARGUMENT; +#endif /* defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_SIGN_DRIVER_ENABLED) */ +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + /* Key is declared with a lifetime not known to us */ + return( status ); + } + +} + +psa_status_t psa_driver_wrapper_get_builtin_key( + psa_drv_slot_number_t slot_number, + psa_key_attributes_t *attributes, + uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length ) +{ + + psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) ); + switch( location ) + { +#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) + +#if (defined(PSA_CRYPTO_DRIVER_TEST) ) + case 0x7fffff: + return( mbedtls_test_opaque_get_builtin_key + (slot_number, + attributes, + key_buffer, + key_buffer_size, + key_buffer_length + )); +#endif + + +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ + default: + (void) slot_number; + (void) key_buffer; + (void) key_buffer_size; + (void) key_buffer_length; + return( PSA_ERROR_DOES_NOT_EXIST ); + } + +} + +#endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/tf-psa-crypto/core/psa_crypto_invasive.h b/tf-psa-crypto/core/psa_crypto_invasive.h new file mode 100644 index 0000000000..a17d5573d8 --- /dev/null +++ b/tf-psa-crypto/core/psa_crypto_invasive.h @@ -0,0 +1,85 @@ +/** + * \file psa_crypto_invasive.h + * + * \brief PSA cryptography module: invasive interfaces for test only. + * + * The interfaces in this file are intended for testing purposes only. + * They MUST NOT be made available to clients over IPC in integrations + * with isolation, and they SHOULD NOT be made available in library + * integrations except when building the library for testing. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_INVASIVE_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_INVASIVE_H + +#include "tf-psa-crypto/build_info.h" + +#include "psa/crypto.h" +#include "tf_psa_crypto_common.h" + +#include "mbedtls/private/entropy.h" + +#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +/** \brief Configure entropy sources. + * + * This function may only be called before a call to psa_crypto_init(), + * or after a call to mbedtls_psa_crypto_free() and before any + * subsequent call to psa_crypto_init(). + * + * This function is only intended for test purposes. The functionality + * it provides is also useful for system integrators, but + * system integrators should configure entropy drivers instead of + * breaking through to the Mbed TLS API. + * + * \param entropy_init Function to initialize the entropy context + * and set up the desired entropy sources. + * It is called by psa_crypto_init(). + * By default this is mbedtls_entropy_init(). + * This function cannot report failures directly. + * To indicate a failure, set the entropy context + * to a state where mbedtls_entropy_func() will + * return an error. + * \param entropy_free Function to free the entropy context + * and associated resources. + * It is called by mbedtls_psa_crypto_free(). + * By default this is mbedtls_entropy_free(). + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_NOT_PERMITTED + * The caller does not have the permission to configure + * entropy sources. + * \retval #PSA_ERROR_BAD_STATE + * The library has already been initialized. + */ +psa_status_t mbedtls_psa_crypto_configure_entropy_sources( + void (* entropy_init)(mbedtls_entropy_context *ctx), + void (* entropy_free)(mbedtls_entropy_context *ctx)); +#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */ + +#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_PSA_CRYPTO_C) +psa_status_t psa_mac_key_can_do( + psa_algorithm_t algorithm, + psa_key_type_t key_type); + +psa_status_t psa_crypto_copy_input(const uint8_t *input, size_t input_len, + uint8_t *input_copy, size_t input_copy_len); + +psa_status_t psa_crypto_copy_output(const uint8_t *output_copy, size_t output_copy_len, + uint8_t *output, size_t output_len); + +/* + * Test hooks to use for memory unpoisoning/poisoning in copy functions. + */ +extern void (*psa_input_pre_copy_hook)(const uint8_t *input, size_t input_len); +extern void (*psa_input_post_copy_hook)(const uint8_t *input, size_t input_len); +extern void (*psa_output_pre_copy_hook)(const uint8_t *output, size_t output_len); +extern void (*psa_output_post_copy_hook)(const uint8_t *output, size_t output_len); + +#endif /* MBEDTLS_TEST_HOOKS && MBEDTLS_PSA_CRYPTO_C */ + +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_INVASIVE_H */ diff --git a/tf-psa-crypto/core/psa_crypto_its.h b/tf-psa-crypto/core/psa_crypto_its.h new file mode 100644 index 0000000000..ed294fd36a --- /dev/null +++ b/tf-psa-crypto/core/psa_crypto_its.h @@ -0,0 +1,131 @@ +/** \file psa_crypto_its.h + * \brief Interface of trusted storage that crypto is built on. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_ITS_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_ITS_H + +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \brief Flags used when creating a data entry + */ +typedef uint32_t psa_storage_create_flags_t; + +/** \brief A type for UIDs used for identifying data + */ +typedef uint64_t psa_storage_uid_t; + +#define PSA_STORAGE_FLAG_NONE 0 /**< No flags to pass */ +#define PSA_STORAGE_FLAG_WRITE_ONCE (1 << 0) /**< The data associated with the uid will not be able to be modified or deleted. Intended to be used to set bits in `psa_storage_create_flags_t`*/ + +/** + * \brief A container for metadata associated with a specific uid + */ +struct psa_storage_info_t { + uint32_t size; /**< The size of the data associated with a uid **/ + psa_storage_create_flags_t flags; /**< The flags set when the uid was created **/ +}; + +/** Flag indicating that \ref psa_storage_create and \ref psa_storage_set_extended are supported */ +#define PSA_STORAGE_SUPPORT_SET_EXTENDED (1 << 0) + +#define PSA_ITS_API_VERSION_MAJOR 1 /**< The major version number of the PSA ITS API. It will be incremented on significant updates that may include breaking changes */ +#define PSA_ITS_API_VERSION_MINOR 1 /**< The minor version number of the PSA ITS API. It will be incremented in small updates that are unlikely to include breaking changes */ + +/** + * \brief create a new or modify an existing uid/value pair + * + * \param[in] uid the identifier for the data + * \param[in] data_length The size in bytes of the data in `p_data` + * \param[in] p_data A buffer containing the data + * \param[in] create_flags The flags that the data will be stored with + * + * \return A status indicating the success/failure of the operation + * + * \retval #PSA_SUCCESS The operation completed successfully + * \retval #PSA_ERROR_NOT_PERMITTED The operation failed because the provided `uid` value was already created with PSA_STORAGE_FLAG_WRITE_ONCE + * \retval #PSA_ERROR_NOT_SUPPORTED The operation failed because one or more of the flags provided in `create_flags` is not supported or is not valid + * \retval #PSA_ERROR_INSUFFICIENT_STORAGE The operation failed because there was insufficient space on the storage medium + * \retval #PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) + * \retval #PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided pointers(`p_data`) + * is invalid, for example is `NULL` or references memory the caller cannot access + */ +psa_status_t psa_its_set(psa_storage_uid_t uid, + uint32_t data_length, + const void *p_data, + psa_storage_create_flags_t create_flags); + +/** + * \brief Retrieve the value associated with a provided uid + * + * \param[in] uid The uid value + * \param[in] data_offset The starting offset of the data requested + * \param[in] data_length the amount of data requested (and the minimum allocated size of the `p_data` buffer) + * \param[out] p_data The buffer where the data will be placed upon successful completion + * \param[out] p_data_length The amount of data returned in the p_data buffer + * + * + * \return A status indicating the success/failure of the operation + * + * \retval #PSA_SUCCESS The operation completed successfully + * \retval #PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided `uid` value was not found in the storage + * \retval #PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) + * \retval #PSA_ERROR_DATA_CORRUPT The operation failed because stored data has been corrupted + * \retval #PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided pointers(`p_data`, `p_data_length`) + * is invalid. For example is `NULL` or references memory the caller cannot access. + * In addition, this can also happen if an invalid offset was provided. + */ +psa_status_t psa_its_get(psa_storage_uid_t uid, + uint32_t data_offset, + uint32_t data_length, + void *p_data, + size_t *p_data_length); + +/** + * \brief Retrieve the metadata about the provided uid + * + * \param[in] uid The uid value + * \param[out] p_info A pointer to the `psa_storage_info_t` struct that will be populated with the metadata + * + * \return A status indicating the success/failure of the operation + * + * \retval #PSA_SUCCESS The operation completed successfully + * \retval #PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided uid value was not found in the storage + * \retval #PSA_ERROR_DATA_CORRUPT The operation failed because stored data has been corrupted + * \retval #PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided pointers(`p_info`) + * is invalid, for example is `NULL` or references memory the caller cannot access + */ +psa_status_t psa_its_get_info(psa_storage_uid_t uid, + struct psa_storage_info_t *p_info); + +/** + * \brief Remove the provided key and its associated data from the storage + * + * \param[in] uid The uid value + * + * \return A status indicating the success/failure of the operation + * + * \retval #PSA_SUCCESS The operation completed successfully + * \retval #PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided key value was not found in the storage + * \retval #PSA_ERROR_NOT_PERMITTED The operation failed because the provided key value was created with PSA_STORAGE_FLAG_WRITE_ONCE + * \retval #PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) + */ +psa_status_t psa_its_remove(psa_storage_uid_t uid); + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_ITS_H */ diff --git a/tf-psa-crypto/core/psa_crypto_random.c b/tf-psa-crypto/core/psa_crypto_random.c new file mode 100644 index 0000000000..1e2cda923c --- /dev/null +++ b/tf-psa-crypto/core/psa_crypto_random.c @@ -0,0 +1,168 @@ +/* + * PSA crypto random generator. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_PSA_CRYPTO_C) && !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + +#include "psa_crypto_core.h" +#include "psa_crypto_random.h" +#include "psa_crypto_random_impl.h" +#include "threading_internal.h" + +#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) +/* For getpid(), for fork protection */ +#include +#if defined(MBEDTLS_HAVE_TIME) +#include +#else +/* For gettimeofday(), for fork protection without actual entropy */ +#include +#endif +#endif + +void psa_random_internal_init(mbedtls_psa_random_context_t *rng) +{ + /* Set default configuration if + * mbedtls_psa_crypto_configure_entropy_sources() hasn't been called. */ + if (rng->entropy_init == NULL) { + rng->entropy_init = mbedtls_entropy_init; + } + if (rng->entropy_free == NULL) { + rng->entropy_free = mbedtls_entropy_free; + } + + rng->entropy_init(&rng->entropy); + + mbedtls_psa_drbg_init(&rng->drbg); +} + +void psa_random_internal_free(mbedtls_psa_random_context_t *rng) +{ + mbedtls_psa_drbg_free(&rng->drbg); + rng->entropy_free(&rng->entropy); +} +psa_status_t psa_random_internal_seed(mbedtls_psa_random_context_t *rng) +{ + const unsigned char drbg_seed[] = "PSA"; + int ret = mbedtls_psa_drbg_seed(&rng->drbg, &rng->entropy, + drbg_seed, sizeof(drbg_seed) - 1); +#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) + rng->pid = getpid(); +#endif + return mbedtls_to_psa_error(ret); +} + +#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) +static psa_status_t psa_random_internal_reseed_child( + mbedtls_psa_random_context_t *rng, + intmax_t pid) +{ + /* Reseeding from actual entropy gives the child a unique RNG state + * which the parent process cannot predict, and wipes the + * parent's RNG state from the child. + * + * However, in some library configurations, there is no actual + * entropy source, only a nonvolatile seed (MBEDTLS_ENTROPY_NV_SEED + * enabled and no actual entropy source enabled). In such a + * configuration, the reseed operation is deterministic and + * always injects the same content, so with the DRBG reseed + * process alone, for example, two child processes forked in + * close sequence would end up with the same RNG state. + + * To avoid this, we use a personalization string that has a high + * likelihood of being unique. This way, the child has a unique state. + * The parent can predict the child's RNG state until the next time + * it reseeds or generates some random output, but that's + * unavoidable in the absence of actual entropy. + */ + struct { + /* Using the PID mostly guarantees that each child gets a + * unique state. */ + /* Use intmax_t, not pid_t, because some Unix-like platforms + * don't define pid_t, or more likely nowadays they define + * pid_t but only with certain platform macros which might not + * be the exact ones we use. In practice, this only costs + * a couple of instructions to pass and compare two words + * rather than one. + */ + intmax_t pid; + /* In case an old child had died and its PID is reused for + * a new child of the same process, also include the time. */ +#if defined(MBEDTLS_HAVE_TIME) + mbedtls_ms_time_t now; +#else + struct timeval now; +#endif + } perso; + memset(&perso, 0, sizeof(perso)); + perso.pid = pid; +#if defined(MBEDTLS_HAVE_TIME) + perso.now = mbedtls_ms_time(); +#else + /* We don't have mbedtls_ms_time(), but the platform has getpid(). + * Use gettimeofday(), which is a classic Unix function. Modern POSIX + * has stopped requiring gettimeofday() (in favor of clock_gettime()), + * but this is fallback code for restricted configurations, so it's + * more likely to be used on embedded platforms that only have a subset + * of Unix APIs and are more likely to have the classic gettimeofday(). */ + if (gettimeofday(&perso.now, NULL) == -1) { + return PSA_ERROR_INSUFFICIENT_ENTROPY; + } +#endif + int ret = mbedtls_psa_drbg_reseed(&rng->drbg, + (unsigned char *) &perso, sizeof(perso)); + return mbedtls_to_psa_error(ret); +} +#endif /* MBEDTLS_PLATFORM_IS_UNIXLIKE */ + +psa_status_t psa_random_internal_generate( + mbedtls_psa_random_context_t *rng, + uint8_t *output, size_t output_size) +{ +#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) + intmax_t pid = getpid(); + if (pid != rng->pid) { + /* This is a (grand...)child of the original process, but + * we inherited the RNG state from our parent. We must reseed! */ +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + psa_status_t status = psa_random_internal_reseed_child(rng, pid); + if (status == PSA_SUCCESS) { + rng->pid = pid; + } +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + if (status != PSA_SUCCESS) { + return status; + } + } +#endif /* MBEDTLS_PLATFORM_IS_UNIXLIKE */ + + while (output_size > 0) { + size_t request_size = + (output_size > MBEDTLS_PSA_RANDOM_MAX_REQUEST ? + MBEDTLS_PSA_RANDOM_MAX_REQUEST : + output_size); +#if defined(MBEDTLS_CTR_DRBG_C) + int ret = mbedtls_ctr_drbg_random(&rng->drbg, output, request_size); +#elif defined(MBEDTLS_HMAC_DRBG_C) + int ret = mbedtls_hmac_drbg_random(&rng->drbg, output, request_size); +#endif /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C */ + if (ret != 0) { + return mbedtls_to_psa_error(ret); + } + output_size -= request_size; + output += request_size; + } + return PSA_SUCCESS; +} + +#endif /* MBEDTLS_PSA_CRYPTO_C && !MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ diff --git a/tf-psa-crypto/core/psa_crypto_random.h b/tf-psa-crypto/core/psa_crypto_random.h new file mode 100644 index 0000000000..0e66426482 --- /dev/null +++ b/tf-psa-crypto/core/psa_crypto_random.h @@ -0,0 +1,72 @@ +/* + * PSA crypto random generator internal functions. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_RANDOM_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_RANDOM_H + +#include "tf_psa_crypto_common.h" + +#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + +#include +#include "psa_crypto_random_impl.h" + +/** Initialize the PSA random generator. + * + * \param[out] rng The random generator context to initialize. + */ +void psa_random_internal_init(mbedtls_psa_random_context_t *rng); + +/** Deinitialize the PSA random generator. + * + * \param[in,out] rng The random generator context to deinitialize. + */ +void psa_random_internal_free(mbedtls_psa_random_context_t *rng); + +/** Seed the PSA random generator. + * + * \note This function is not thread-safe. + * + * \param[in,out] rng The random generator context to seed. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY + * The entropy source failed. + */ +psa_status_t psa_random_internal_seed(mbedtls_psa_random_context_t *rng); + +/** + * \brief Generate random bytes. Like psa_generate_random(), but for use + * inside the library. + * + * This function is thread-safe. + * + * \warning This function **can** fail! Callers MUST check the return status + * and MUST NOT use the content of the output buffer if the return + * status is not #PSA_SUCCESS. + * + * \param[in,out] rng The random generator context to seed. + * \param[out] output Output buffer for the generated data. + * \param output_size Number of bytes to generate and output. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY + * The random generator needed to reseed, and the entropy + * source failed. + * \retval #PSA_ERROR_HARDWARE_FAILURE + * A hardware accelerator failed. + */ +psa_status_t psa_random_internal_generate( + mbedtls_psa_random_context_t *rng, + uint8_t *output, size_t output_size); + +#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */ + +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_RANDOM_H */ diff --git a/tf-psa-crypto/core/psa_crypto_random_impl.h b/tf-psa-crypto/core/psa_crypto_random_impl.h new file mode 100644 index 0000000000..aca70429ba --- /dev/null +++ b/tf-psa-crypto/core/psa_crypto_random_impl.h @@ -0,0 +1,215 @@ +/** \file psa_crypto_random_impl.h + * + * \brief PSA crypto random generator implementation abstraction. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_RANDOM_IMPL_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_RANDOM_IMPL_H + +#include "mbedtls/psa_util.h" + +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + +typedef mbedtls_psa_external_random_context_t mbedtls_psa_random_context_t; + +#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ + +#include "mbedtls/private/entropy.h" +#include "mbedtls/private/error_common.h" + +#if !defined(PSA_WANT_ALG_SHA_256) +MBEDTLS_STATIC_ASSERT(MBEDTLS_PSA_CRYPTO_RNG_HASH != PSA_ALG_SHA_256, + "SHA_256 used as the hash for the random generator, but not enabled"); +#endif + +#if !defined(PSA_WANT_ALG_SHA_512) +MBEDTLS_STATIC_ASSERT(MBEDTLS_PSA_CRYPTO_RNG_HASH != PSA_ALG_SHA_512, + "SHA_512 used as the hash for the random generator, but not enabled"); +#endif + +MBEDTLS_STATIC_ASSERT((MBEDTLS_PSA_CRYPTO_RNG_HASH == PSA_ALG_SHA_256) || \ + (MBEDTLS_PSA_CRYPTO_RNG_HASH == PSA_ALG_SHA_512), + "Invalid hashing algorithm for MBEDTLS_PSA_CRYPTO_RNG_HASH"); + +MBEDTLS_STATIC_ASSERT(PSA_BYTES_TO_BITS(PSA_HASH_LENGTH( + MBEDTLS_PSA_CRYPTO_RNG_HASH)) + >= MBEDTLS_PSA_CRYPTO_RNG_STRENGTH, + "The hash size (in bits) of MBEDTLS_PSA_CRYPTO_RNG_HASH must be at least MBEDTLS_PSA_CRYPTO_RNG_STRENGTH"); + +/* Choose a DRBG based on configuration and availability */ +#if defined(MBEDTLS_CTR_DRBG_C) + +#include "mbedtls/private/ctr_drbg.h" + +#if (MBEDTLS_PSA_CRYPTO_RNG_STRENGTH > 128) && \ + defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) +#error "CTR_DRBG cannot meet the configured RNG strength using only 128-bit AES keys." +#endif + +#if MBEDTLS_PSA_CRYPTO_RNG_STRENGTH > PSA_BYTES_TO_BITS(MBEDTLS_CTR_DRBG_KEYSIZE) +#error "The CTR_DRBG key size (in bits) must be at least MBEDTLS_PSA_CRYPTO_RNG_STRENGTH" +#endif + +#undef MBEDTLS_PSA_HMAC_DRBG_MD_TYPE + +#elif defined(MBEDTLS_HMAC_DRBG_C) + +#include "mbedtls/private/hmac_drbg.h" +#define MBEDTLS_PSA_HMAC_DRBG_MD_TYPE MBEDTLS_ENTROPY_MD + +#else /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C*/ + +#error "No DRBG module available for the psa_crypto module." + +#endif /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C*/ + +/* The maximum number of bytes that mbedtls_psa_get_random() is expected to return. */ +#if defined(MBEDTLS_CTR_DRBG_C) +#define MBEDTLS_PSA_RANDOM_MAX_REQUEST MBEDTLS_CTR_DRBG_MAX_REQUEST +#elif defined(MBEDTLS_HMAC_DRBG_C) +#define MBEDTLS_PSA_RANDOM_MAX_REQUEST MBEDTLS_HMAC_DRBG_MAX_REQUEST +#endif + +#if defined(MBEDTLS_CTR_DRBG_C) +typedef mbedtls_ctr_drbg_context mbedtls_psa_drbg_context_t; +#elif defined(MBEDTLS_HMAC_DRBG_C) +typedef mbedtls_hmac_drbg_context mbedtls_psa_drbg_context_t; +#endif /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C */ + +typedef struct { + void (* entropy_init)(mbedtls_entropy_context *ctx); + void (* entropy_free)(mbedtls_entropy_context *ctx); + mbedtls_entropy_context entropy; + mbedtls_psa_drbg_context_t drbg; +#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) + /* Fork protection: normally pid = getpid(). If the value changes, + * we are in a (grand)*child of the original process, so reseed + * the RNG to ensure that the child and the original process have + * distinct RNG states. See psa_random_internal_generate(). + * + * The type is intmax_t, not pid_t, for portability reasons: + * pid_t is defined in `unistd.h`, but on some platforms, it may + * only be defined if a certain compatibility level is requested + * by defining a macro such as _POSIX_C_SOURCE or _XOPEN_SOURCE. + * The macro needs to be defined before any system header, which + * may be hard to do in some C files that include this header + * (e.g. test suites). So we sidestep this complication, at the + * cost of possibly a few more instructions to compare pid values. + */ + intmax_t pid; +#endif +} mbedtls_psa_random_context_t; + +/** Initialize the PSA DRBG. + * + * \param p_rng Pointer to the Mbed TLS DRBG state. + */ +static inline void mbedtls_psa_drbg_init(mbedtls_psa_drbg_context_t *p_rng) +{ +#if defined(MBEDTLS_CTR_DRBG_C) + mbedtls_ctr_drbg_init(p_rng); +#elif defined(MBEDTLS_HMAC_DRBG_C) + mbedtls_hmac_drbg_init(p_rng); +#endif +} + +/** Deinitialize the PSA DRBG. + * + * \param p_rng Pointer to the Mbed TLS DRBG state. + */ +static inline void mbedtls_psa_drbg_free(mbedtls_psa_drbg_context_t *p_rng) +{ +#if defined(MBEDTLS_CTR_DRBG_C) + mbedtls_ctr_drbg_free(p_rng); +#elif defined(MBEDTLS_HMAC_DRBG_C) + mbedtls_hmac_drbg_free(p_rng); +#endif +} + +/** Seed the PSA DRBG. + * + * \param drbg_ctx The DRBG context to seed. + * It must be initialized but not active. + * \param entropy An entropy context to read the seed from. + * \param custom The personalization string. + * This can be \c NULL, in which case the personalization + * string is empty regardless of the value of \p len. + * \param len The length of the personalization string. + * + * \return \c 0 on success. + * \return An Mbed TLS error code (\c MBEDTLS_ERR_xxx) on failure. + */ +static inline int mbedtls_psa_drbg_seed(mbedtls_psa_drbg_context_t *drbg_ctx, + mbedtls_entropy_context *entropy, + const unsigned char *custom, size_t len) +{ +#if defined(MBEDTLS_CTR_DRBG_C) + return mbedtls_ctr_drbg_seed(drbg_ctx, mbedtls_entropy_func, entropy, custom, len); +#elif defined(MBEDTLS_HMAC_DRBG_C) + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE); + return mbedtls_hmac_drbg_seed(drbg_ctx, md_info, mbedtls_entropy_func, entropy, custom, len); +#endif /* MBEDTLS_HMAC_DRBG_C */ +} + +/** Reseed the PSA DRBG. + * + * \param drbg_ctx The DRBG context to reseed. + * It must be active. + * \param additional Additional data to inject. + * \param len The length of \p additional in bytes. + * This can be 0 to simply reseed from the entropy source. + * + * \return \c 0 on success. + * \return An Mbed TLS error code (\c MBEDTLS_ERR_xxx) on failure. + */ +static inline int mbedtls_psa_drbg_reseed(mbedtls_psa_drbg_context_t *drbg_ctx, + const unsigned char *additional, + size_t len) +{ +#if defined(MBEDTLS_CTR_DRBG_C) + return mbedtls_ctr_drbg_reseed(drbg_ctx, additional, len); +#elif defined(MBEDTLS_HMAC_DRBG_C) + return mbedtls_hmac_drbg_reseed(drbg_ctx, additional, len); +#endif +} + +/** Deplete the PSA DRBG, i.e. cause it to reseed the next time it is used. + * + * \note This function is not thread-safe. + * + * \param drbg_ctx The DRBG context to deplete. + * It must be active. + */ +static inline void mbedtls_psa_drbg_deplete(mbedtls_psa_drbg_context_t *drbg_ctx) +{ + drbg_ctx->reseed_counter = drbg_ctx->reseed_interval; +} + +#if MBEDTLS_ENTROPY_TRUE_SOURCES > 0 +/** Set prediction resistance in the PSA DRBG. + * + * \note This function is not thread-safe. + * + * \param drbg_ctx The DRBG context to reconfigure. + * It must be active. + * \param enabled \c 1 to enable, or \c 0 to disable. + */ +static inline void mbedtls_psa_drbg_set_prediction_resistance( + mbedtls_psa_drbg_context_t *drbg_ctx, + unsigned enabled) +{ +#if defined(MBEDTLS_CTR_DRBG_C) + mbedtls_ctr_drbg_set_prediction_resistance(drbg_ctx, enabled); +#elif defined(MBEDTLS_HMAC_DRBG_C) + mbedtls_hmac_drbg_set_prediction_resistance(drbg_ctx, enabled); +#endif +} +#endif /* MBEDTLS_ENTROPY_TRUE_SOURCES > 0 */ + +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ + +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_RANDOM_IMPL_H */ diff --git a/tf-psa-crypto/core/psa_crypto_slot_management.c b/tf-psa-crypto/core/psa_crypto_slot_management.c new file mode 100644 index 0000000000..d0b4dcd668 --- /dev/null +++ b/tf-psa-crypto/core/psa_crypto_slot_management.c @@ -0,0 +1,998 @@ +/* + * PSA crypto layer on top of Mbed TLS crypto + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_PSA_CRYPTO_C) + +#include "psa/crypto.h" + +#include "psa_crypto_core.h" +#include "psa_crypto_driver_wrappers_no_static.h" +#include "psa_crypto_slot_management.h" +#include "psa_crypto_storage.h" + +#include +#include +#include "mbedtls/platform.h" +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#include "threading_internal.h" +#endif + + + +/* Make sure we have distinct ranges of key identifiers for distinct + * purposes. */ +MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_USER_MIN < PSA_KEY_ID_USER_MAX, + "Empty user key ID range"); +MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VENDOR_MIN < PSA_KEY_ID_VENDOR_MAX, + "Empty vendor key ID range"); +MBEDTLS_STATIC_ASSERT(MBEDTLS_PSA_KEY_ID_BUILTIN_MIN <= MBEDTLS_PSA_KEY_ID_BUILTIN_MAX, + "Empty builtin key ID range"); +MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VOLATILE_MIN <= PSA_KEY_ID_VOLATILE_MAX, + "Empty volatile key ID range"); + +MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_USER_MAX < PSA_KEY_ID_VENDOR_MIN || + PSA_KEY_ID_VENDOR_MAX < PSA_KEY_ID_USER_MIN, + "Overlap between user key IDs and vendor key IDs"); + +MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VENDOR_MIN <= MBEDTLS_PSA_KEY_ID_BUILTIN_MIN && + MBEDTLS_PSA_KEY_ID_BUILTIN_MAX <= PSA_KEY_ID_VENDOR_MAX, + "Builtin key identifiers are not in the vendor range"); + +MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VENDOR_MIN <= PSA_KEY_ID_VOLATILE_MIN && + PSA_KEY_ID_VOLATILE_MAX <= PSA_KEY_ID_VENDOR_MAX, + "Volatile key identifiers are not in the vendor range"); + +MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VOLATILE_MAX < MBEDTLS_PSA_KEY_ID_BUILTIN_MIN || + MBEDTLS_PSA_KEY_ID_BUILTIN_MAX < PSA_KEY_ID_VOLATILE_MIN, + "Overlap between builtin key IDs and volatile key IDs"); + + + +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) + +/* Dynamic key store. + * + * The key store consists of multiple slices. + * + * The volatile keys are stored in variable-sized tables called slices. + * Slices are allocated on demand and deallocated when possible. + * The size of slices increases exponentially, so the average overhead + * (number of slots that are allocated but not used) is roughly + * proportional to the number of keys (with a factor that grows + * when the key store is fragmented). + * + * One slice is dedicated to the cache of persistent and built-in keys. + * For simplicity, they are separated from volatile keys. This cache + * slice has a fixed size and has the slice index KEY_SLOT_CACHE_SLICE_INDEX, + * located after the slices for volatile keys. + */ + +/* Size of the last slice containing the cache of persistent and built-in keys. */ +#define PERSISTENT_KEY_CACHE_COUNT MBEDTLS_PSA_KEY_SLOT_COUNT + +/* Volatile keys are stored in slices 0 through + * (KEY_SLOT_VOLATILE_SLICE_COUNT - 1) inclusive. + * Each slice is twice the size of the previous slice. + * Volatile key identifiers encode the slice number as follows: + * bits 30..31: 0b10 (mandated by the PSA Crypto specification). + * bits 25..29: slice index (0...KEY_SLOT_VOLATILE_SLICE_COUNT-1) + * bits 0..24: slot index in slice + */ +#define KEY_ID_SLOT_INDEX_WIDTH 25u +#define KEY_ID_SLICE_INDEX_WIDTH 5u + +#define KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH 16u +#define KEY_SLOT_VOLATILE_SLICE_COUNT 22u +#define KEY_SLICE_COUNT (KEY_SLOT_VOLATILE_SLICE_COUNT + 1u) +#define KEY_SLOT_CACHE_SLICE_INDEX KEY_SLOT_VOLATILE_SLICE_COUNT + + +/* Check that the length of the largest slice (calculated as + * KEY_SLICE_LENGTH_MAX below) does not overflow size_t. We use + * an indirect method in case the calculation of KEY_SLICE_LENGTH_MAX + * itself overflows uintmax_t: if (BASE_LENGTH << c) + * overflows size_t then BASE_LENGTH > SIZE_MAX >> c. + */ +#if (KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH > \ + SIZE_MAX >> (KEY_SLOT_VOLATILE_SLICE_COUNT - 1)) +#error "Maximum slice length overflows size_t" +#endif + +#if KEY_ID_SLICE_INDEX_WIDTH + KEY_ID_SLOT_INDEX_WIDTH > 30 +#error "Not enough room in volatile key IDs for slice index and slot index" +#endif +#if KEY_SLOT_VOLATILE_SLICE_COUNT > (1 << KEY_ID_SLICE_INDEX_WIDTH) +#error "Too many slices to fit the slice index in a volatile key ID" +#endif +#define KEY_SLICE_LENGTH_MAX \ + (KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH << (KEY_SLOT_VOLATILE_SLICE_COUNT - 1)) +#if KEY_SLICE_LENGTH_MAX > 1 << KEY_ID_SLOT_INDEX_WIDTH +#error "Not enough room in volatile key IDs for a slot index in the largest slice" +#endif +#if KEY_ID_SLICE_INDEX_WIDTH > 8 +#error "Slice index does not fit in uint8_t for psa_key_slot_t::slice_index" +#endif + + +/* Calculate the volatile key id to use for a given slot. + * This function assumes valid parameter values. */ +static psa_key_id_t volatile_key_id_of_index(size_t slice_idx, + size_t slot_idx) +{ + /* We assert above that the slice and slot indexes fit in separate + * bit-fields inside psa_key_id_t, which is a 32-bit type per the + * PSA Cryptography specification. */ + return (psa_key_id_t) (0x40000000u | + (slice_idx << KEY_ID_SLOT_INDEX_WIDTH) | + slot_idx); +} + +/* Calculate the slice containing the given volatile key. + * This function assumes valid parameter values. */ +static size_t slice_index_of_volatile_key_id(psa_key_id_t key_id) +{ + size_t mask = (1LU << KEY_ID_SLICE_INDEX_WIDTH) - 1; + return (key_id >> KEY_ID_SLOT_INDEX_WIDTH) & mask; +} + +/* Calculate the index of the slot containing the given volatile key. + * This function assumes valid parameter values. */ +static size_t slot_index_of_volatile_key_id(psa_key_id_t key_id) +{ + return key_id & ((1LU << KEY_ID_SLOT_INDEX_WIDTH) - 1); +} + +/* In global_data.first_free_slot_index, use this special value to + * indicate that the slice is full. */ +#define FREE_SLOT_INDEX_NONE ((size_t) -1) + +#if defined(MBEDTLS_TEST_HOOKS) +size_t psa_key_slot_volatile_slice_count(void) +{ + return KEY_SLOT_VOLATILE_SLICE_COUNT; +} +#endif + +#else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + +/* Static key store. + * + * All the keys (volatile or persistent) are in a single slice. + * We only use slices as a concept to allow some differences between + * static and dynamic key store management to be buried in auxiliary + * functions. + */ + +#define PERSISTENT_KEY_CACHE_COUNT MBEDTLS_PSA_KEY_SLOT_COUNT +#define KEY_SLICE_COUNT 1u +#define KEY_SLOT_CACHE_SLICE_INDEX 0 + +#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + + +typedef struct { +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) + psa_key_slot_t *key_slices[KEY_SLICE_COUNT]; + size_t first_free_slot_index[KEY_SLOT_VOLATILE_SLICE_COUNT]; +#else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + psa_key_slot_t key_slots[MBEDTLS_PSA_KEY_SLOT_COUNT]; +#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + uint8_t key_slots_initialized; +} psa_global_data_t; + +static psa_global_data_t global_data; + +static uint8_t psa_get_key_slots_initialized(void) +{ + uint8_t initialized; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + + initialized = global_data.key_slots_initialized; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_unlock(&mbedtls_threading_psa_globaldata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + + return initialized; +} + + + +/** The length of the given slice in the key slot table. + * + * \param slice_idx The slice number. It must satisfy + * 0 <= slice_idx < KEY_SLICE_COUNT. + * + * \return The number of elements in the given slice. + */ +static inline size_t key_slice_length(size_t slice_idx); + +/** Get a pointer to the slot where the given volatile key is located. + * + * \param key_id The key identifier. It must be a valid volatile key + * identifier. + * \return A pointer to the only slot that the given key + * can be in. Note that the slot may be empty or + * contain a different key. + */ +static inline psa_key_slot_t *get_volatile_key_slot(psa_key_id_t key_id); + +/** Get a pointer to an entry in the persistent key cache. + * + * \param slot_idx The index in the table. It must satisfy + * 0 <= slot_idx < PERSISTENT_KEY_CACHE_COUNT. + * \return A pointer to the slot containing the given + * persistent key cache entry. + */ +static inline psa_key_slot_t *get_persistent_key_slot(size_t slot_idx); + +/** Get a pointer to a slot given by slice and index. + * + * \param slice_idx The slice number. It must satisfy + * 0 <= slice_idx < KEY_SLICE_COUNT. + * \param slot_idx An index in the given slice. It must satisfy + * 0 <= slot_idx < key_slice_length(slice_idx). + * + * \return A pointer to the given slot. + */ +static inline psa_key_slot_t *get_key_slot(size_t slice_idx, size_t slot_idx); + +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) + +#if defined(MBEDTLS_TEST_HOOKS) +size_t (*mbedtls_test_hook_psa_volatile_key_slice_length)(size_t slice_idx) = NULL; +#endif + +static inline size_t key_slice_length(size_t slice_idx) +{ + if (slice_idx == KEY_SLOT_CACHE_SLICE_INDEX) { + return PERSISTENT_KEY_CACHE_COUNT; + } else { +#if defined(MBEDTLS_TEST_HOOKS) + if (mbedtls_test_hook_psa_volatile_key_slice_length != NULL) { + return mbedtls_test_hook_psa_volatile_key_slice_length(slice_idx); + } +#endif + return KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH << slice_idx; + } +} + +static inline psa_key_slot_t *get_volatile_key_slot(psa_key_id_t key_id) +{ + size_t slice_idx = slice_index_of_volatile_key_id(key_id); + if (slice_idx >= KEY_SLOT_VOLATILE_SLICE_COUNT) { + return NULL; + } + size_t slot_idx = slot_index_of_volatile_key_id(key_id); + if (slot_idx >= key_slice_length(slice_idx)) { + return NULL; + } + psa_key_slot_t *slice = global_data.key_slices[slice_idx]; + if (slice == NULL) { + return NULL; + } + return &slice[slot_idx]; +} + +static inline psa_key_slot_t *get_persistent_key_slot(size_t slot_idx) +{ + return &global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX][slot_idx]; +} + +static inline psa_key_slot_t *get_key_slot(size_t slice_idx, size_t slot_idx) +{ + return &global_data.key_slices[slice_idx][slot_idx]; +} + +#else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + +static inline size_t key_slice_length(size_t slice_idx) +{ + (void) slice_idx; + return ARRAY_LENGTH(global_data.key_slots); +} + +static inline psa_key_slot_t *get_volatile_key_slot(psa_key_id_t key_id) +{ + MBEDTLS_STATIC_ASSERT(ARRAY_LENGTH(global_data.key_slots) <= + PSA_KEY_ID_VOLATILE_MAX - PSA_KEY_ID_VOLATILE_MIN + 1, + "The key slot array is larger than the volatile key ID range"); + return &global_data.key_slots[key_id - PSA_KEY_ID_VOLATILE_MIN]; +} + +static inline psa_key_slot_t *get_persistent_key_slot(size_t slot_idx) +{ + return &global_data.key_slots[slot_idx]; +} + +static inline psa_key_slot_t *get_key_slot(size_t slice_idx, size_t slot_idx) +{ + (void) slice_idx; + return &global_data.key_slots[slot_idx]; +} + +#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + +/** Get the description in memory of a key given its identifier and lock it. + * + * The descriptions of volatile keys and loaded persistent keys are + * stored in key slots. This function returns a pointer to the key slot + * containing the description of a key given its identifier. + * + * The function searches the key slots containing the description of the key + * with \p key identifier. The function does only read accesses to the key + * slots. The function does not load any persistent key thus does not access + * any storage. + * + * For volatile key identifiers, only one key slot is queried as a volatile + * key with identifier key_id can only be stored in slot of index + * ( key_id - #PSA_KEY_ID_VOLATILE_MIN ). + * + * On success, the function locks the key slot. It is the responsibility of + * the caller to unlock the key slot when it does not access it anymore. + * + * If multi-threading is enabled, the caller must hold the + * global key slot mutex. + * + * \param key Key identifier to query. + * \param[out] p_slot On success, `*p_slot` contains a pointer to the + * key slot containing the description of the key + * identified by \p key. + * + * \retval #PSA_SUCCESS + * The pointer to the key slot containing the description of the key + * identified by \p key was returned. + * \retval #PSA_ERROR_INVALID_HANDLE + * \p key is not a valid key identifier. + * \retval #PSA_ERROR_DOES_NOT_EXIST + * There is no key with key identifier \p key in the key slots. + */ +static psa_status_t psa_get_and_lock_key_slot_in_memory( + mbedtls_svc_key_id_t key, psa_key_slot_t **p_slot) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_id_t key_id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key); + size_t slot_idx; + psa_key_slot_t *slot = NULL; + + if (psa_key_id_is_volatile(key_id)) { + slot = get_volatile_key_slot(key_id); + + /* Check if both the PSA key identifier key_id and the owner + * identifier of key match those of the key slot. */ + if (slot != NULL && + slot->state == PSA_SLOT_FULL && + mbedtls_svc_key_id_equal(key, slot->attr.id)) { + status = PSA_SUCCESS; + } else { + status = PSA_ERROR_DOES_NOT_EXIST; + } + } else if (psa_key_id_is_user(key_id) || psa_key_id_is_builtin(key_id)) { + for (slot_idx = 0; slot_idx < PERSISTENT_KEY_CACHE_COUNT; slot_idx++) { + slot = get_persistent_key_slot(slot_idx); + /* Only consider slots which are in a full state. */ + if ((slot->state == PSA_SLOT_FULL) && + (mbedtls_svc_key_id_equal(key, slot->attr.id))) { + break; + } + } + status = (slot_idx < MBEDTLS_PSA_KEY_SLOT_COUNT) ? + PSA_SUCCESS : PSA_ERROR_DOES_NOT_EXIST; + } else { + return PSA_ERROR_INVALID_HANDLE; + } + + if (status == PSA_SUCCESS) { + status = psa_register_read(slot); + if (status == PSA_SUCCESS) { + *p_slot = slot; + } + } + + return status; +} + +psa_status_t psa_initialize_key_slots(void) +{ +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) + global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX] = + mbedtls_calloc(PERSISTENT_KEY_CACHE_COUNT, + sizeof(*global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX])); + if (global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX] == NULL) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } +#else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + /* Nothing to do: program startup and psa_wipe_all_key_slots() both + * guarantee that the key slots are initialized to all-zero, which + * means that all the key slots are in a valid, empty state. The global + * data mutex is already held when calling this function, so no need to + * lock it here, to set the flag. */ +#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + + global_data.key_slots_initialized = 1; + return PSA_SUCCESS; +} + +void psa_wipe_all_key_slots(void) +{ + for (size_t slice_idx = 0; slice_idx < KEY_SLICE_COUNT; slice_idx++) { +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) + if (global_data.key_slices[slice_idx] == NULL) { + continue; + } +#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + for (size_t slot_idx = 0; slot_idx < key_slice_length(slice_idx); slot_idx++) { + psa_key_slot_t *slot = get_key_slot(slice_idx, slot_idx); +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) + /* When MBEDTLS_PSA_KEY_STORE_DYNAMIC is disabled, calling + * psa_wipe_key_slot() on an unused slot is useless, but it + * happens to work (because we flip the state to PENDING_DELETION). + * + * When MBEDTLS_PSA_KEY_STORE_DYNAMIC is enabled, + * psa_wipe_key_slot() needs to have a valid slice_index + * field, but that value might not be correct in a + * free slot, so we must not call it. + * + * Bypass the call to psa_wipe_key_slot() if the slot is empty, + * but only if MBEDTLS_PSA_KEY_STORE_DYNAMIC is enabled, to save + * a few bytes of code size otherwise. + */ + if (slot->state == PSA_SLOT_EMPTY) { + continue; + } +#endif + slot->var.occupied.registered_readers = 1; + slot->state = PSA_SLOT_PENDING_DELETION; + (void) psa_wipe_key_slot(slot); + } +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) + mbedtls_free(global_data.key_slices[slice_idx]); + global_data.key_slices[slice_idx] = NULL; +#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + } + +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) + for (size_t slice_idx = 0; slice_idx < KEY_SLOT_VOLATILE_SLICE_COUNT; slice_idx++) { + global_data.first_free_slot_index[slice_idx] = 0; + } +#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + + /* The global data mutex is already held when calling this function. */ + global_data.key_slots_initialized = 0; +} + +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) + +static psa_status_t psa_allocate_volatile_key_slot(psa_key_id_t *key_id, + psa_key_slot_t **p_slot) +{ + size_t slice_idx; + for (slice_idx = 0; slice_idx < KEY_SLOT_VOLATILE_SLICE_COUNT; slice_idx++) { + if (global_data.first_free_slot_index[slice_idx] != FREE_SLOT_INDEX_NONE) { + break; + } + } + if (slice_idx == KEY_SLOT_VOLATILE_SLICE_COUNT) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + + if (global_data.key_slices[slice_idx] == NULL) { + global_data.key_slices[slice_idx] = + mbedtls_calloc(key_slice_length(slice_idx), + sizeof(psa_key_slot_t)); + if (global_data.key_slices[slice_idx] == NULL) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + } + psa_key_slot_t *slice = global_data.key_slices[slice_idx]; + + size_t slot_idx = global_data.first_free_slot_index[slice_idx]; + *key_id = volatile_key_id_of_index(slice_idx, slot_idx); + + psa_key_slot_t *slot = &slice[slot_idx]; + size_t next_free = slot_idx + 1 + slot->var.free.next_free_relative_to_next; + if (next_free >= key_slice_length(slice_idx)) { + next_free = FREE_SLOT_INDEX_NONE; + } + global_data.first_free_slot_index[slice_idx] = next_free; + /* The .next_free field is not meaningful when the slot is not free, + * so give it the same content as freshly initialized memory. */ + slot->var.free.next_free_relative_to_next = 0; + + psa_status_t status = psa_key_slot_state_transition(slot, + PSA_SLOT_EMPTY, + PSA_SLOT_FILLING); + if (status != PSA_SUCCESS) { + /* The only reason for failure is if the slot state was not empty. + * This indicates that something has gone horribly wrong. + * In this case, we leave the slot out of the free list, and stop + * modifying it. This minimizes any further corruption. The slot + * is a memory leak, but that's a lesser evil. */ + return status; + } + + *p_slot = slot; + /* We assert at compile time that the slice index fits in uint8_t. */ + slot->slice_index = (uint8_t) slice_idx; + return PSA_SUCCESS; +} + +psa_status_t psa_free_key_slot(size_t slice_idx, + psa_key_slot_t *slot) +{ + + if (slice_idx == KEY_SLOT_CACHE_SLICE_INDEX) { + /* This is a cache entry. We don't maintain a free list, so + * there's nothing to do. */ + return PSA_SUCCESS; + } + if (slice_idx >= KEY_SLOT_VOLATILE_SLICE_COUNT) { + return PSA_ERROR_CORRUPTION_DETECTED; + } + + psa_key_slot_t *slice = global_data.key_slices[slice_idx]; + psa_key_slot_t *slice_end = slice + key_slice_length(slice_idx); + if (slot < slice || slot >= slice_end) { + /* The slot isn't actually in the slice! We can't detect that + * condition for sure, because the pointer comparison itself is + * undefined behavior in that case. That same condition makes the + * subtraction to calculate the slot index also UB. + * Give up now to avoid causing further corruption. + */ + return PSA_ERROR_CORRUPTION_DETECTED; + } + size_t slot_idx = slot - slice; + + size_t next_free = global_data.first_free_slot_index[slice_idx]; + if (next_free >= key_slice_length(slice_idx)) { + /* The slot was full. The newly freed slot thus becomes the + * end of the free list. */ + next_free = key_slice_length(slice_idx); + } + global_data.first_free_slot_index[slice_idx] = slot_idx; + slot->var.free.next_free_relative_to_next = + (int32_t) next_free - (int32_t) slot_idx - 1; + + return PSA_SUCCESS; +} +#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + +psa_status_t psa_reserve_free_key_slot(psa_key_id_t *volatile_key_id, + psa_key_slot_t **p_slot) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + size_t slot_idx; + psa_key_slot_t *selected_slot, *unused_persistent_key_slot; + + if (!psa_get_key_slots_initialized()) { + status = PSA_ERROR_BAD_STATE; + goto error; + } + +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) + if (volatile_key_id != NULL) { + return psa_allocate_volatile_key_slot(volatile_key_id, p_slot); + } +#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + + /* With a dynamic key store, allocate an entry in the cache slice, + * applicable only to non-volatile keys that get cached in RAM. + * With a static key store, allocate an entry in the sole slice, + * applicable to all keys. */ + selected_slot = unused_persistent_key_slot = NULL; + for (slot_idx = 0; slot_idx < PERSISTENT_KEY_CACHE_COUNT; slot_idx++) { + psa_key_slot_t *slot = get_key_slot(KEY_SLOT_CACHE_SLICE_INDEX, slot_idx); + if (slot->state == PSA_SLOT_EMPTY) { + selected_slot = slot; + break; + } + + if ((unused_persistent_key_slot == NULL) && + (slot->state == PSA_SLOT_FULL) && + (!psa_key_slot_has_readers(slot)) && + (!PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime))) { + unused_persistent_key_slot = slot; + } + } + + /* + * If there is no unused key slot and there is at least one unlocked key + * slot containing the description of a persistent key, recycle the first + * such key slot we encountered. If we later need to operate on the + * persistent key we are evicting now, we will reload its description from + * storage. + */ + if ((selected_slot == NULL) && + (unused_persistent_key_slot != NULL)) { + selected_slot = unused_persistent_key_slot; + psa_register_read(selected_slot); + status = psa_wipe_key_slot(selected_slot); + if (status != PSA_SUCCESS) { + goto error; + } + } + + if (selected_slot != NULL) { + status = psa_key_slot_state_transition(selected_slot, PSA_SLOT_EMPTY, + PSA_SLOT_FILLING); + if (status != PSA_SUCCESS) { + goto error; + } + +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) + selected_slot->slice_index = KEY_SLOT_CACHE_SLICE_INDEX; +#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + +#if !defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) + if (volatile_key_id != NULL) { + /* Refresh slot_idx, for when the slot is not the original + * selected_slot but rather unused_persistent_key_slot. */ + slot_idx = selected_slot - global_data.key_slots; + *volatile_key_id = PSA_KEY_ID_VOLATILE_MIN + (psa_key_id_t) slot_idx; + } +#endif + *p_slot = selected_slot; + + return PSA_SUCCESS; + } + status = PSA_ERROR_INSUFFICIENT_MEMORY; + +error: + *p_slot = NULL; + + return status; +} + +#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) +static psa_status_t psa_load_persistent_key_into_slot(psa_key_slot_t *slot) +{ + psa_status_t status = PSA_SUCCESS; + uint8_t *key_data = NULL; + size_t key_data_length = 0; + + if (!psa_key_id_is_user(MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id))) { + return PSA_ERROR_DOES_NOT_EXIST; + } + + status = psa_load_persistent_key(&slot->attr, + &key_data, &key_data_length); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_copy_key_material_into_slot(slot, key_data, key_data_length); + if (status != PSA_SUCCESS) { + goto exit; + } + +exit: + psa_free_persistent_key_data(key_data, key_data_length); + return status; +} +#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */ + +#if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS) + +static psa_status_t psa_load_builtin_key_into_slot(psa_key_slot_t *slot) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_VOLATILE; + psa_drv_slot_number_t slot_number = 0; + size_t key_buffer_size = 0; + size_t key_buffer_length = 0; + + if (!psa_key_id_is_builtin( + MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id))) { + return PSA_ERROR_DOES_NOT_EXIST; + } + + /* Check the platform function to see whether this key actually exists */ + status = mbedtls_psa_platform_get_builtin_key( + slot->attr.id, &lifetime, &slot_number); + if (status != PSA_SUCCESS) { + return status; + } + + /* Set required key attributes to ensure get_builtin_key can retrieve the + * full attributes. */ + psa_set_key_id(&attributes, slot->attr.id); + psa_set_key_lifetime(&attributes, lifetime); + + /* Get the full key attributes from the driver in order to be able to + * calculate the required buffer size. */ + status = psa_driver_wrapper_get_builtin_key( + slot_number, &attributes, + NULL, 0, NULL); + if (status != PSA_ERROR_BUFFER_TOO_SMALL) { + /* Builtin keys cannot be defined by the attributes alone */ + if (status == PSA_SUCCESS) { + status = PSA_ERROR_CORRUPTION_DETECTED; + } + return status; + } + + /* If the key should exist according to the platform, then ask the driver + * what its expected size is. */ + status = psa_driver_wrapper_get_key_buffer_size(&attributes, + &key_buffer_size); + if (status != PSA_SUCCESS) { + return status; + } + + /* Allocate a buffer of the required size and load the builtin key directly + * into the (now properly sized) slot buffer. */ + status = psa_allocate_buffer_to_slot(slot, key_buffer_size); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_driver_wrapper_get_builtin_key( + slot_number, &attributes, + slot->key.data, slot->key.bytes, &key_buffer_length); + if (status != PSA_SUCCESS) { + goto exit; + } + + /* Copy actual key length and core attributes into the slot on success */ + slot->key.bytes = key_buffer_length; + slot->attr = attributes; +exit: + if (status != PSA_SUCCESS) { + psa_remove_key_data_from_memory(slot); + } + return status; +} +#endif /* MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */ + +psa_status_t psa_get_and_lock_key_slot(mbedtls_svc_key_id_t key, + psa_key_slot_t **p_slot) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + *p_slot = NULL; + if (!psa_get_key_slots_initialized()) { + return PSA_ERROR_BAD_STATE; + } + +#if defined(MBEDTLS_THREADING_C) + /* We need to set status as success, otherwise CORRUPTION_DETECTED + * would be returned if the lock fails. */ + status = PSA_SUCCESS; + /* If the key is persistent and not loaded, we cannot unlock the mutex + * between checking if the key is loaded and setting the slot as FULL, + * as otherwise another thread may load and then destroy the key + * in the meantime. */ + PSA_THREADING_CHK_RET(mbedtls_mutex_lock( + &mbedtls_threading_key_slot_mutex)); +#endif + /* + * On success, the pointer to the slot is passed directly to the caller + * thus no need to unlock the key slot here. + */ + status = psa_get_and_lock_key_slot_in_memory(key, p_slot); + if (status != PSA_ERROR_DOES_NOT_EXIST) { +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( + &mbedtls_threading_key_slot_mutex)); +#endif + return status; + } + + /* Loading keys from storage requires support for such a mechanism */ +#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) || \ + defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS) + + status = psa_reserve_free_key_slot(NULL, p_slot); + if (status != PSA_SUCCESS) { +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( + &mbedtls_threading_key_slot_mutex)); +#endif + return status; + } + + (*p_slot)->attr.id = key; + (*p_slot)->attr.lifetime = PSA_KEY_LIFETIME_PERSISTENT; + + status = PSA_ERROR_DOES_NOT_EXIST; +#if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS) + /* Load keys in the 'builtin' range through their own interface */ + status = psa_load_builtin_key_into_slot(*p_slot); +#endif /* MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */ + +#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) + if (status == PSA_ERROR_DOES_NOT_EXIST) { + status = psa_load_persistent_key_into_slot(*p_slot); + } +#endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */ + + if (status != PSA_SUCCESS) { + psa_wipe_key_slot(*p_slot); + + /* If the key does not exist, we need to return + * PSA_ERROR_INVALID_HANDLE. */ + if (status == PSA_ERROR_DOES_NOT_EXIST) { + status = PSA_ERROR_INVALID_HANDLE; + } + } else { + /* Add implicit usage flags. */ + psa_extend_key_usage_flags(&(*p_slot)->attr.policy.usage); + + psa_key_slot_state_transition((*p_slot), PSA_SLOT_FILLING, + PSA_SLOT_FULL); + status = psa_register_read(*p_slot); + } + +#else /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */ + status = PSA_ERROR_INVALID_HANDLE; +#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */ + + if (status != PSA_SUCCESS) { + *p_slot = NULL; + } +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( + &mbedtls_threading_key_slot_mutex)); +#endif + return status; +} + +psa_status_t psa_unregister_read(psa_key_slot_t *slot) +{ + if (slot == NULL) { + return PSA_SUCCESS; + } + if ((slot->state != PSA_SLOT_FULL) && + (slot->state != PSA_SLOT_PENDING_DELETION)) { + return PSA_ERROR_CORRUPTION_DETECTED; + } + + /* If we are the last reader and the slot is marked for deletion, + * we must wipe the slot here. */ + if ((slot->state == PSA_SLOT_PENDING_DELETION) && + (slot->var.occupied.registered_readers == 1)) { + return psa_wipe_key_slot(slot); + } + + if (psa_key_slot_has_readers(slot)) { + slot->var.occupied.registered_readers--; + return PSA_SUCCESS; + } + + /* + * As the return error code may not be handled in case of multiple errors, + * do our best to report if there are no registered readers. Assert with + * MBEDTLS_TEST_HOOK_TEST_ASSERT that there are registered readers: + * if the MBEDTLS_TEST_HOOKS configuration option is enabled and + * the function is called as part of the execution of a test suite, the + * execution of the test suite is stopped in error if the assertion fails. + */ + MBEDTLS_TEST_HOOK_TEST_ASSERT(psa_key_slot_has_readers(slot)); + return PSA_ERROR_CORRUPTION_DETECTED; +} + +psa_status_t psa_unregister_read_under_mutex(psa_key_slot_t *slot) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; +#if defined(MBEDTLS_THREADING_C) + /* We need to set status as success, otherwise CORRUPTION_DETECTED + * would be returned if the lock fails. */ + status = PSA_SUCCESS; + PSA_THREADING_CHK_RET(mbedtls_mutex_lock( + &mbedtls_threading_key_slot_mutex)); +#endif + status = psa_unregister_read(slot); +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( + &mbedtls_threading_key_slot_mutex)); +#endif + return status; +} + +psa_status_t psa_validate_key_persistence(psa_key_lifetime_t lifetime) +{ + if (PSA_KEY_LIFETIME_IS_VOLATILE(lifetime)) { + /* Volatile keys are always supported */ + return PSA_SUCCESS; + } else { + /* Persistent keys require storage support */ +#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) + if (PSA_KEY_LIFETIME_IS_READ_ONLY(lifetime)) { + return PSA_ERROR_INVALID_ARGUMENT; + } else { + return PSA_SUCCESS; + } +#else /* MBEDTLS_PSA_CRYPTO_STORAGE_C */ + return PSA_ERROR_NOT_SUPPORTED; +#endif /* !MBEDTLS_PSA_CRYPTO_STORAGE_C */ + } +} + +psa_status_t psa_purge_key(mbedtls_svc_key_id_t key) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_t *slot; + +#if defined(MBEDTLS_THREADING_C) + /* We need to set status as success, otherwise CORRUPTION_DETECTED + * would be returned if the lock fails. */ + status = PSA_SUCCESS; + PSA_THREADING_CHK_RET(mbedtls_mutex_lock( + &mbedtls_threading_key_slot_mutex)); +#endif + status = psa_get_and_lock_key_slot_in_memory(key, &slot); + if (status != PSA_SUCCESS) { +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( + &mbedtls_threading_key_slot_mutex)); +#endif + return status; + } + + if ((!PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) && + (slot->var.occupied.registered_readers == 1)) { + status = psa_wipe_key_slot(slot); + } else { + status = psa_unregister_read(slot); + } +#if defined(MBEDTLS_THREADING_C) + PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( + &mbedtls_threading_key_slot_mutex)); +#endif + + return status; +} + +void mbedtls_psa_get_stats(mbedtls_psa_stats_t *stats) +{ + memset(stats, 0, sizeof(*stats)); + + for (size_t slice_idx = 0; slice_idx < KEY_SLICE_COUNT; slice_idx++) { +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) + if (global_data.key_slices[slice_idx] == NULL) { + continue; + } +#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + for (size_t slot_idx = 0; slot_idx < key_slice_length(slice_idx); slot_idx++) { + const psa_key_slot_t *slot = get_key_slot(slice_idx, slot_idx); + if (slot->state == PSA_SLOT_EMPTY) { + ++stats->empty_slots; + continue; + } + if (psa_key_slot_has_readers(slot)) { + ++stats->locked_slots; + } + if (PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) { + ++stats->volatile_slots; + } else { + psa_key_id_t id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id); + ++stats->persistent_slots; + if (id > stats->max_open_internal_key_id) { + stats->max_open_internal_key_id = id; + } + } + if (PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime) != + PSA_KEY_LOCATION_LOCAL_STORAGE) { + psa_key_id_t id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id); + ++stats->external_slots; + if (id > stats->max_open_external_key_id) { + stats->max_open_external_key_id = id; + } + } + } + } +} + +#endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/tf-psa-crypto/core/psa_crypto_slot_management.h b/tf-psa-crypto/core/psa_crypto_slot_management.h new file mode 100644 index 0000000000..669edc9bf1 --- /dev/null +++ b/tf-psa-crypto/core/psa_crypto_slot_management.h @@ -0,0 +1,330 @@ +/* + * PSA crypto layer on top of Mbed TLS crypto + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_SLOT_MANAGEMENT_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_SLOT_MANAGEMENT_H + +#include "psa/crypto.h" +#include "psa_crypto_core.h" + +/** Range of volatile key identifiers. + * + * The first #MBEDTLS_PSA_KEY_SLOT_COUNT identifiers of the implementation + * range of key identifiers are reserved for volatile key identifiers. + * + * If \c id is a a volatile key identifier, #PSA_KEY_ID_VOLATILE_MIN - \c id + * indicates the key slot containing the volatile key definition. See + * psa_crypto_slot_management.c for details. + */ + +/** The minimum value for a volatile key identifier. + */ +#define PSA_KEY_ID_VOLATILE_MIN PSA_KEY_ID_VENDOR_MIN + +/** The maximum value for a volatile key identifier. + */ +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) +#define PSA_KEY_ID_VOLATILE_MAX (MBEDTLS_PSA_KEY_ID_BUILTIN_MIN - 1) +#else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ +#define PSA_KEY_ID_VOLATILE_MAX \ + (PSA_KEY_ID_VOLATILE_MIN + MBEDTLS_PSA_KEY_SLOT_COUNT - 1) +#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + +/** Test whether a key identifier is a volatile key identifier. + * + * \param key_id Key identifier to test. + * + * \retval 1 + * The key identifier is a volatile key identifier. + * \retval 0 + * The key identifier is not a volatile key identifier. + */ +static inline int psa_key_id_is_volatile(psa_key_id_t key_id) +{ + return (key_id >= PSA_KEY_ID_VOLATILE_MIN) && + (key_id <= PSA_KEY_ID_VOLATILE_MAX); +} + +/** Get the description of a key given its identifier and lock it. + * + * The descriptions of volatile keys and loaded persistent keys are stored in + * key slots. This function returns a pointer to the key slot containing the + * description of a key given its identifier. + * + * In case of a persistent key, the function loads the description of the key + * into a key slot if not already done. + * + * On success, the returned key slot has been registered for reading. + * It is the responsibility of the caller to call psa_unregister_read(slot) + * when they have finished reading the contents of the slot. + * + * On failure, `*p_slot` is set to NULL. This ensures that it is always valid + * to call psa_unregister_read on the returned slot. + * + * \param key Key identifier to query. + * \param[out] p_slot On success, `*p_slot` contains a pointer to the + * key slot containing the description of the key + * identified by \p key. + * + * \retval #PSA_SUCCESS + * \p *p_slot contains a pointer to the key slot containing the + * description of the key identified by \p key. + * The key slot counter has been incremented. + * \retval #PSA_ERROR_BAD_STATE + * The library has not been initialized. + * \retval #PSA_ERROR_INVALID_HANDLE + * \p key is not a valid key identifier. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \p key is a persistent key identifier. The implementation does not + * have sufficient resources to load the persistent key. This can be + * due to a lack of empty key slot, or available memory. + * \retval #PSA_ERROR_DOES_NOT_EXIST + * There is no key with key identifier \p key. + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription + * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription + */ +psa_status_t psa_get_and_lock_key_slot(mbedtls_svc_key_id_t key, + psa_key_slot_t **p_slot); + +/** Initialize the key slot structures. + * + * \retval #PSA_SUCCESS + * Currently this function always succeeds. + */ +psa_status_t psa_initialize_key_slots(void); + +#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) +/* Allow test code to customize the key slice length. We use this in tests + * that exhaust the key store to reach a full key store in reasonable time + * and memory. + * + * The length of each slice must be between 1 and + * (1 << KEY_ID_SLOT_INDEX_WIDTH) inclusive. + * + * The length for a given slice index must not change while + * the key store is initialized. + */ +extern size_t (*mbedtls_test_hook_psa_volatile_key_slice_length)( + size_t slice_idx); + +/* The number of volatile key slices. */ +size_t psa_key_slot_volatile_slice_count(void); +#endif + +/** Delete all data from key slots in memory. + * This function is not thread safe, it wipes every key slot regardless of + * state and reader count. It should only be called when no slot is in use. + * + * This does not affect persistent storage. */ +void psa_wipe_all_key_slots(void); + +/** Find a free key slot and reserve it to be filled with a key. + * + * This function finds a key slot that is free, + * sets its state to PSA_SLOT_FILLING and then returns the slot. + * + * On success, the key slot's state is PSA_SLOT_FILLING. + * It is the responsibility of the caller to change the slot's state to + * PSA_SLOT_EMPTY/FULL once key creation has finished. + * + * If multi-threading is enabled, the caller must hold the + * global key slot mutex. + * + * \param[out] volatile_key_id - If null, reserve a cache slot for + * a persistent or built-in key. + * - If non-null, allocate a slot for + * a volatile key. On success, + * \p *volatile_key_id is the + * identifier corresponding to the + * returned slot. It is the caller's + * responsibility to set this key identifier + * in the attributes. + * \param[out] p_slot On success, a pointer to the slot. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * There were no free key slots. + * When #MBEDTLS_PSA_KEY_STORE_DYNAMIC is enabled, there was not + * enough memory to allocate more slots. + * \retval #PSA_ERROR_BAD_STATE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * This function attempted to operate on a key slot which was in an + * unexpected state. + */ +psa_status_t psa_reserve_free_key_slot(psa_key_id_t *volatile_key_id, + psa_key_slot_t **p_slot); + +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) +/** Return a key slot to the free list. + * + * Call this function when a slot obtained from psa_reserve_free_key_slot() + * is no longer in use. + * + * If multi-threading is enabled, the caller must hold the + * global key slot mutex. + * + * \param slice_idx The slice containing the slot. + * This is `slot->slice_index` when the slot + * is obtained from psa_reserve_free_key_slot(). + * \param slot The key slot. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * This function attempted to operate on a key slot which was in an + * unexpected state. + */ +psa_status_t psa_free_key_slot(size_t slice_idx, + psa_key_slot_t *slot); +#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ + +/** Change the state of a key slot. + * + * This function changes the state of the key slot from expected_state to + * new state. If the state of the slot was not expected_state, the state is + * unchanged. + * + * If multi-threading is enabled, the caller must hold the + * global key slot mutex. + * + * \param[in] slot The key slot. + * \param[in] expected_state The current state of the slot. + * \param[in] new_state The new state of the slot. + * + * \retval #PSA_SUCCESS + The key slot's state variable is new_state. + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * The slot's state was not expected_state. + */ +static inline psa_status_t psa_key_slot_state_transition( + psa_key_slot_t *slot, psa_key_slot_state_t expected_state, + psa_key_slot_state_t new_state) +{ + if (slot->state != expected_state) { + return PSA_ERROR_CORRUPTION_DETECTED; + } + slot->state = new_state; + return PSA_SUCCESS; +} + +/** Register as a reader of a key slot. + * + * This function increments the key slot registered reader counter by one. + * If multi-threading is enabled, the caller must hold the + * global key slot mutex. + * + * \param[in] slot The key slot. + * + * \retval #PSA_SUCCESS + The key slot registered reader counter was incremented. + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * The reader counter already reached its maximum value and was not + * increased, or the slot's state was not PSA_SLOT_FULL. + */ +static inline psa_status_t psa_register_read(psa_key_slot_t *slot) +{ + if ((slot->state != PSA_SLOT_FULL) || + (slot->var.occupied.registered_readers >= SIZE_MAX)) { + return PSA_ERROR_CORRUPTION_DETECTED; + } + slot->var.occupied.registered_readers++; + + return PSA_SUCCESS; +} + +/** Unregister from reading a key slot. + * + * This function decrements the key slot registered reader counter by one. + * If the state of the slot is PSA_SLOT_PENDING_DELETION, + * and there is only one registered reader (the caller), + * this function will call psa_wipe_key_slot(). + * If multi-threading is enabled, the caller must hold the + * global key slot mutex. + * + * \note To ease the handling of errors in retrieving a key slot + * a NULL input pointer is valid, and the function returns + * successfully without doing anything in that case. + * + * \param[in] slot The key slot. + * \retval #PSA_SUCCESS + * \p slot is NULL or the key slot reader counter has been + * decremented (and potentially wiped) successfully. + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * The slot's state was neither PSA_SLOT_FULL nor + * PSA_SLOT_PENDING_DELETION. + * Or a wipe was attempted and the slot's state was not + * PSA_SLOT_PENDING_DELETION. + * Or registered_readers was equal to 0. + */ +psa_status_t psa_unregister_read(psa_key_slot_t *slot); + +/** Wrap a call to psa_unregister_read in the global key slot mutex. + * + * If threading is disabled, this simply calls psa_unregister_read. + * + * \note To ease the handling of errors in retrieving a key slot + * a NULL input pointer is valid, and the function returns + * successfully without doing anything in that case. + * + * \param[in] slot The key slot. + * \retval #PSA_SUCCESS + * \p slot is NULL or the key slot reader counter has been + * decremented (and potentially wiped) successfully. + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * The slot's state was neither PSA_SLOT_FULL nor + * PSA_SLOT_PENDING_DELETION. + * Or a wipe was attempted and the slot's state was not + * PSA_SLOT_PENDING_DELETION. + * Or registered_readers was equal to 0. + */ +psa_status_t psa_unregister_read_under_mutex(psa_key_slot_t *slot); + +/** Test whether a lifetime designates a key in an external cryptoprocessor. + * + * \param lifetime The lifetime to test. + * + * \retval 1 + * The lifetime designates an external key. There should be a + * registered driver for this lifetime, otherwise the key cannot + * be created or manipulated. + * \retval 0 + * The lifetime designates a key that is volatile or in internal + * storage. + */ +static inline int psa_key_lifetime_is_external(psa_key_lifetime_t lifetime) +{ + return PSA_KEY_LIFETIME_GET_LOCATION(lifetime) + != PSA_KEY_LOCATION_LOCAL_STORAGE; +} + +/** Validate the persistence of a key. + * + * \param[in] lifetime The key lifetime attribute. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_NOT_SUPPORTED The key is persistent but persistent keys + * are not supported. + */ +psa_status_t psa_validate_key_persistence(psa_key_lifetime_t lifetime); + +/** Test whether a key identifier belongs to the user key range. + * + * \param key_id Key identifier to test. + * + * \retval 1 + * The key identifier is a user key identifier. + * \retval 0 + * The key identifier is not a user key identifier. + */ +static inline int psa_key_id_is_user(psa_key_id_t key_id) +{ + return (key_id >= PSA_KEY_ID_USER_MIN) && + (key_id <= PSA_KEY_ID_USER_MAX); +} + +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_SLOT_MANAGEMENT_H */ diff --git a/tf-psa-crypto/core/psa_crypto_storage.c b/tf-psa-crypto/core/psa_crypto_storage.c new file mode 100644 index 0000000000..05755c3122 --- /dev/null +++ b/tf-psa-crypto/core/psa_crypto_storage.c @@ -0,0 +1,400 @@ +/* + * PSA persistent key storage + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) + +#include +#include + +#include "psa/crypto.h" +#include "psa_crypto_storage.h" +#include "mbedtls/platform_util.h" + +#if defined(MBEDTLS_PSA_ITS_FILE_C) +#include "psa_crypto_its.h" +#else /* Native ITS implementation */ +#include "psa/error.h" +#include "psa/internal_trusted_storage.h" +#endif + +#include "mbedtls/platform.h" + + + +/****************************************************************/ +/* Key storage */ +/****************************************************************/ + +/* Determine a file name (ITS file identifier) for the given key identifier. + * The file name must be distinct from any file that is used for a purpose + * other than storing a key. Currently, the only such file is the random seed + * file whose name is PSA_CRYPTO_ITS_RANDOM_SEED_UID and whose value is + * 0xFFFFFF52. */ +static psa_storage_uid_t psa_its_identifier_of_slot(mbedtls_svc_key_id_t key) +{ +#if defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER) + /* Encode the owner in the upper 32 bits. This means that if + * owner values are nonzero (as they are on a PSA platform), + * no key file will ever have a value less than 0x100000000, so + * the whole range 0..0xffffffff is available for non-key files. */ + uint32_t unsigned_owner_id = MBEDTLS_SVC_KEY_ID_GET_OWNER_ID(key); + return ((uint64_t) unsigned_owner_id << 32) | + MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key); +#else + /* Use the key id directly as a file name. + * psa_is_key_id_valid() in psa_crypto_slot_management.c + * is responsible for ensuring that key identifiers do not have a + * value that is reserved for non-key files. */ + return key; +#endif +} + +/** + * \brief Load persistent data for the given key slot number. + * + * This function reads data from a storage backend and returns the data in a + * buffer. + * + * \param key Persistent identifier of the key to be loaded. This + * should be an occupied storage location. + * \param[out] data Buffer where the data is to be written. + * \param data_size Size of the \c data buffer in bytes. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_DATA_INVALID \emptydescription + * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription + * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription + * \retval #PSA_ERROR_DOES_NOT_EXIST \emptydescription + */ +static psa_status_t psa_crypto_storage_load( + const mbedtls_svc_key_id_t key, uint8_t *data, size_t data_size) +{ + psa_status_t status; + psa_storage_uid_t data_identifier = psa_its_identifier_of_slot(key); + struct psa_storage_info_t data_identifier_info; + size_t data_length = 0; + + status = psa_its_get_info(data_identifier, &data_identifier_info); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_its_get(data_identifier, 0, (uint32_t) data_size, data, &data_length); + if (data_size != data_length) { + return PSA_ERROR_DATA_INVALID; + } + + return status; +} + +int psa_is_key_present_in_storage(const mbedtls_svc_key_id_t key) +{ + psa_status_t ret; + psa_storage_uid_t data_identifier = psa_its_identifier_of_slot(key); + struct psa_storage_info_t data_identifier_info; + + ret = psa_its_get_info(data_identifier, &data_identifier_info); + + if (ret == PSA_ERROR_DOES_NOT_EXIST) { + return 0; + } + return 1; +} + +/** + * \brief Store persistent data for the given key slot number. + * + * This function stores the given data buffer to a persistent storage. + * + * \param key Persistent identifier of the key to be stored. This + * should be an unoccupied storage location. + * \param[in] data Buffer containing the data to be stored. + * \param data_length The number of bytes + * that make up the data. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_STORAGE \emptydescription + * \retval #PSA_ERROR_ALREADY_EXISTS \emptydescription + * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription + * \retval #PSA_ERROR_DATA_INVALID \emptydescription + */ +static psa_status_t psa_crypto_storage_store(const mbedtls_svc_key_id_t key, + const uint8_t *data, + size_t data_length) +{ + psa_status_t status; + psa_storage_uid_t data_identifier = psa_its_identifier_of_slot(key); + struct psa_storage_info_t data_identifier_info; + + if (psa_is_key_present_in_storage(key) == 1) { + return PSA_ERROR_ALREADY_EXISTS; + } + + status = psa_its_set(data_identifier, (uint32_t) data_length, data, 0); + if (status != PSA_SUCCESS) { + return PSA_ERROR_DATA_INVALID; + } + + status = psa_its_get_info(data_identifier, &data_identifier_info); + if (status != PSA_SUCCESS) { + goto exit; + } + + if (data_identifier_info.size != data_length) { + status = PSA_ERROR_DATA_INVALID; + goto exit; + } + +exit: + if (status != PSA_SUCCESS) { + /* Remove the file in case we managed to create it but something + * went wrong. It's ok if the file doesn't exist. If the file exists + * but the removal fails, we're already reporting an error so there's + * nothing else we can do. */ + (void) psa_its_remove(data_identifier); + } + return status; +} + +psa_status_t psa_destroy_persistent_key(const mbedtls_svc_key_id_t key) +{ + psa_status_t ret; + psa_storage_uid_t data_identifier = psa_its_identifier_of_slot(key); + struct psa_storage_info_t data_identifier_info; + + ret = psa_its_get_info(data_identifier, &data_identifier_info); + if (ret == PSA_ERROR_DOES_NOT_EXIST) { + return PSA_SUCCESS; + } + + if (psa_its_remove(data_identifier) != PSA_SUCCESS) { + return PSA_ERROR_DATA_INVALID; + } + + ret = psa_its_get_info(data_identifier, &data_identifier_info); + if (ret != PSA_ERROR_DOES_NOT_EXIST) { + return PSA_ERROR_DATA_INVALID; + } + + return PSA_SUCCESS; +} + +/** + * \brief Get data length for given key slot number. + * + * \param key Persistent identifier whose stored data length + * is to be obtained. + * \param[out] data_length The number of bytes that make up the data. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription + * \retval #PSA_ERROR_DOES_NOT_EXIST \emptydescription + * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription + */ +static psa_status_t psa_crypto_storage_get_data_length( + const mbedtls_svc_key_id_t key, + size_t *data_length) +{ + psa_status_t status; + psa_storage_uid_t data_identifier = psa_its_identifier_of_slot(key); + struct psa_storage_info_t data_identifier_info; + + status = psa_its_get_info(data_identifier, &data_identifier_info); + if (status != PSA_SUCCESS) { + return status; + } + + *data_length = (size_t) data_identifier_info.size; + + return PSA_SUCCESS; +} + +/** + * Persistent key storage magic header. + */ +#define PSA_KEY_STORAGE_MAGIC_HEADER "PSA\0KEY" +#define PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH (sizeof(PSA_KEY_STORAGE_MAGIC_HEADER)) + +typedef struct { + uint8_t magic[PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH]; + uint8_t version[4]; + uint8_t lifetime[sizeof(psa_key_lifetime_t)]; + uint8_t type[2]; + uint8_t bits[2]; + uint8_t policy[sizeof(psa_key_policy_t)]; + uint8_t data_len[4]; + uint8_t key_data[]; +} psa_persistent_key_storage_format; + +void psa_format_key_data_for_storage(const uint8_t *data, + const size_t data_length, + const psa_key_attributes_t *attr, + uint8_t *storage_data) +{ + psa_persistent_key_storage_format *storage_format = + (psa_persistent_key_storage_format *) storage_data; + + memcpy(storage_format->magic, PSA_KEY_STORAGE_MAGIC_HEADER, + PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH); + MBEDTLS_PUT_UINT32_LE(0, storage_format->version, 0); + MBEDTLS_PUT_UINT32_LE(attr->lifetime, storage_format->lifetime, 0); + MBEDTLS_PUT_UINT16_LE((uint16_t) attr->type, storage_format->type, 0); + MBEDTLS_PUT_UINT16_LE((uint16_t) attr->bits, storage_format->bits, 0); + MBEDTLS_PUT_UINT32_LE(attr->policy.usage, storage_format->policy, 0); + MBEDTLS_PUT_UINT32_LE(attr->policy.alg, storage_format->policy, sizeof(uint32_t)); + MBEDTLS_PUT_UINT32_LE(attr->policy.alg2, storage_format->policy, 2 * sizeof(uint32_t)); + MBEDTLS_PUT_UINT32_LE(data_length, storage_format->data_len, 0); + memcpy(storage_format->key_data, data, data_length); +} + +static psa_status_t check_magic_header(const uint8_t *data) +{ + if (memcmp(data, PSA_KEY_STORAGE_MAGIC_HEADER, + PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH) != 0) { + return PSA_ERROR_DATA_INVALID; + } + return PSA_SUCCESS; +} + +psa_status_t psa_parse_key_data_from_storage(const uint8_t *storage_data, + size_t storage_data_length, + uint8_t **key_data, + size_t *key_data_length, + psa_key_attributes_t *attr) +{ + psa_status_t status; + const psa_persistent_key_storage_format *storage_format = + (const psa_persistent_key_storage_format *) storage_data; + uint32_t version; + + if (storage_data_length < sizeof(*storage_format)) { + return PSA_ERROR_DATA_INVALID; + } + + status = check_magic_header(storage_data); + if (status != PSA_SUCCESS) { + return status; + } + + version = MBEDTLS_GET_UINT32_LE(storage_format->version, 0); + if (version != 0) { + return PSA_ERROR_DATA_INVALID; + } + + *key_data_length = MBEDTLS_GET_UINT32_LE(storage_format->data_len, 0); + if (*key_data_length > (storage_data_length - sizeof(*storage_format)) || + *key_data_length > PSA_CRYPTO_MAX_STORAGE_SIZE) { + return PSA_ERROR_DATA_INVALID; + } + + if (*key_data_length == 0) { + *key_data = NULL; + } else { + *key_data = mbedtls_calloc(1, *key_data_length); + if (*key_data == NULL) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + memcpy(*key_data, storage_format->key_data, *key_data_length); + } + + attr->lifetime = MBEDTLS_GET_UINT32_LE(storage_format->lifetime, 0); + attr->type = MBEDTLS_GET_UINT16_LE(storage_format->type, 0); + attr->bits = MBEDTLS_GET_UINT16_LE(storage_format->bits, 0); + attr->policy.usage = MBEDTLS_GET_UINT32_LE(storage_format->policy, 0); + attr->policy.alg = MBEDTLS_GET_UINT32_LE(storage_format->policy, sizeof(uint32_t)); + attr->policy.alg2 = MBEDTLS_GET_UINT32_LE(storage_format->policy, 2 * sizeof(uint32_t)); + + return PSA_SUCCESS; +} + +psa_status_t psa_save_persistent_key(const psa_key_attributes_t *attr, + const uint8_t *data, + const size_t data_length) +{ + size_t storage_data_length; + uint8_t *storage_data; + psa_status_t status; + + /* All keys saved to persistent storage always have a key context */ + if (data == NULL || data_length == 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (data_length > PSA_CRYPTO_MAX_STORAGE_SIZE) { + return PSA_ERROR_INSUFFICIENT_STORAGE; + } + storage_data_length = data_length + sizeof(psa_persistent_key_storage_format); + + storage_data = mbedtls_calloc(1, storage_data_length); + if (storage_data == NULL) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + + psa_format_key_data_for_storage(data, data_length, attr, storage_data); + + status = psa_crypto_storage_store(attr->id, + storage_data, storage_data_length); + + mbedtls_zeroize_and_free(storage_data, storage_data_length); + + return status; +} + +void psa_free_persistent_key_data(uint8_t *key_data, size_t key_data_length) +{ + mbedtls_zeroize_and_free(key_data, key_data_length); +} + +psa_status_t psa_load_persistent_key(psa_key_attributes_t *attr, + uint8_t **data, + size_t *data_length) +{ + psa_status_t status = PSA_SUCCESS; + uint8_t *loaded_data; + size_t storage_data_length = 0; + mbedtls_svc_key_id_t key = attr->id; + + status = psa_crypto_storage_get_data_length(key, &storage_data_length); + if (status != PSA_SUCCESS) { + return status; + } + + loaded_data = mbedtls_calloc(1, storage_data_length); + + if (loaded_data == NULL) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + + status = psa_crypto_storage_load(key, loaded_data, storage_data_length); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_parse_key_data_from_storage(loaded_data, storage_data_length, + data, data_length, attr); + + /* All keys saved to persistent storage always have a key context */ + if (status == PSA_SUCCESS && + (*data == NULL || *data_length == 0)) { + status = PSA_ERROR_STORAGE_FAILURE; + } + +exit: + mbedtls_zeroize_and_free(loaded_data, storage_data_length); + return status; +} + + + +/****************************************************************/ +/* The end */ +/****************************************************************/ + +#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */ diff --git a/tf-psa-crypto/core/psa_crypto_storage.h b/tf-psa-crypto/core/psa_crypto_storage.h new file mode 100644 index 0000000000..b1b4c0a7ad --- /dev/null +++ b/tf-psa-crypto/core/psa_crypto_storage.h @@ -0,0 +1,201 @@ +/** + * \file psa_crypto_storage.h + * + * \brief PSA cryptography module: Mbed TLS key storage + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_STORAGE_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_STORAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "psa/crypto.h" + +#include +#include + +/* Limit the maximum key size in storage. */ +#if defined(MBEDTLS_PSA_STATIC_KEY_SLOTS) +/* Reflect the maximum size for the key buffer. */ +#define PSA_CRYPTO_MAX_STORAGE_SIZE (MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE) +#else +/* Just set an upper boundary but it should have no effect since the key size + * is limited in memory. */ +#define PSA_CRYPTO_MAX_STORAGE_SIZE (PSA_BITS_TO_BYTES(PSA_MAX_KEY_BITS)) +#endif + +/* Sanity check: a file size must fit in 32 bits. Allow a generous + * 64kB of metadata. */ +#if PSA_CRYPTO_MAX_STORAGE_SIZE > 0xffff0000 +#error "PSA_CRYPTO_MAX_STORAGE_SIZE > 0xffff0000" +#endif + +/** The maximum permitted persistent slot number. + * + * In Mbed Crypto 0.1.0b: + * - Using the file backend, all key ids are ok except 0. + * - Using the ITS backend, all key ids are ok except 0xFFFFFF52 + * (#PSA_CRYPTO_ITS_RANDOM_SEED_UID) for which the file contains the + * device's random seed (if this feature is enabled). + * - Only key ids from 1 to #MBEDTLS_PSA_KEY_SLOT_COUNT are actually used. + * + * Since we need to preserve the random seed, avoid using that key slot. + * Reserve a whole range of key slots just in case something else comes up. + * + * This limitation will probably become moot when we implement client + * separation for key storage. + */ +#define PSA_MAX_PERSISTENT_KEY_IDENTIFIER PSA_KEY_ID_VENDOR_MAX + +/** + * \brief Checks if persistent data is stored for the given key slot number + * + * This function checks if any key data or metadata exists for the key slot in + * the persistent storage. + * + * \param key Persistent identifier to check. + * + * \retval 0 + * No persistent data present for slot number + * \retval 1 + * Persistent data present for slot number + */ +int psa_is_key_present_in_storage(const mbedtls_svc_key_id_t key); + +/** + * \brief Format key data and metadata and save to a location for given key + * slot. + * + * This function formats the key data and metadata and saves it to a + * persistent storage backend. The storage location corresponding to the + * key slot must be empty, otherwise this function will fail. This function + * should be called after loading the key into an internal slot to ensure the + * persistent key is not saved into a storage location corresponding to an + * already occupied non-persistent key, as well as ensuring the key data is + * validated. + * + * Note: This function will only succeed for key buffers which are not + * empty. If passed a NULL pointer or zero-length, the function will fail + * with #PSA_ERROR_INVALID_ARGUMENT. + * + * \param[in] attr The attributes of the key to save. + * The key identifier field in the attributes + * determines the key's location. + * \param[in] data Buffer containing the key data. + * \param data_length The number of bytes that make up the key data. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_STORAGE \emptydescription + * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription + * \retval #PSA_ERROR_ALREADY_EXISTS \emptydescription + * \retval #PSA_ERROR_DATA_INVALID \emptydescription + * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription + */ +psa_status_t psa_save_persistent_key(const psa_key_attributes_t *attr, + const uint8_t *data, + const size_t data_length); + +/** + * \brief Parses key data and metadata and load persistent key for given + * key slot number. + * + * This function reads from a storage backend, parses the key data and + * metadata and writes them to the appropriate output parameters. + * + * Note: This function allocates a buffer and returns a pointer to it through + * the data parameter. On successful return, the pointer is guaranteed to be + * valid and the buffer contains at least one byte of data. + * psa_free_persistent_key_data() must be called on the data buffer + * afterwards to zeroize and free this buffer. + * + * \param[in,out] attr On input, the key identifier field identifies + * the key to load. Other fields are ignored. + * On success, the attribute structure contains + * the key metadata that was loaded from storage. + * \param[out] data Pointer to an allocated key data buffer on return. + * \param[out] data_length The number of bytes that make up the key data. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_DATA_INVALID \emptydescription + * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription + * \retval #PSA_ERROR_DOES_NOT_EXIST \emptydescription + */ +psa_status_t psa_load_persistent_key(psa_key_attributes_t *attr, + uint8_t **data, + size_t *data_length); + +/** + * \brief Remove persistent data for the given key slot number. + * + * \param key Persistent identifier of the key to remove + * from persistent storage. + * + * \retval #PSA_SUCCESS + * The key was successfully removed, + * or the key did not exist. + * \retval #PSA_ERROR_DATA_INVALID \emptydescription + */ +psa_status_t psa_destroy_persistent_key(const mbedtls_svc_key_id_t key); + +/** + * \brief Free the temporary buffer allocated by psa_load_persistent_key(). + * + * This function must be called at some point after psa_load_persistent_key() + * to zeroize and free the memory allocated to the buffer in that function. + * + * \param key_data Buffer for the key data. + * \param key_data_length Size of the key data buffer. + * + */ +void psa_free_persistent_key_data(uint8_t *key_data, size_t key_data_length); + +/** + * \brief Formats key data and metadata for persistent storage + * + * \param[in] data Buffer containing the key data. + * \param data_length Length of the key data buffer. + * \param[in] attr The core attributes of the key. + * \param[out] storage_data Output buffer for the formatted data. + * + */ +void psa_format_key_data_for_storage(const uint8_t *data, + const size_t data_length, + const psa_key_attributes_t *attr, + uint8_t *storage_data); + +/** + * \brief Parses persistent storage data into key data and metadata + * + * \param[in] storage_data Buffer for the storage data. + * \param storage_data_length Length of the storage data buffer + * \param[out] key_data On output, pointer to a newly allocated buffer + * containing the key data. This must be freed + * using psa_free_persistent_key_data() + * \param[out] key_data_length Length of the key data buffer + * \param[out] attr On success, the attribute structure is filled + * with the loaded key metadata. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_DATA_INVALID \emptydescription + */ +psa_status_t psa_parse_key_data_from_storage(const uint8_t *storage_data, + size_t storage_data_length, + uint8_t **key_data, + size_t *key_data_length, + psa_key_attributes_t *attr); + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_STORAGE_H */ diff --git a/tf-psa-crypto/core/psa_its_file.c b/tf-psa-crypto/core/psa_its_file.c new file mode 100644 index 0000000000..79290b29eb --- /dev/null +++ b/tf-psa-crypto/core/psa_its_file.c @@ -0,0 +1,254 @@ +/* + * PSA ITS simulator over stdio files. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_PSA_ITS_FILE_C) + +#include "mbedtls/platform.h" + +#if defined(_WIN32) +#include +#endif + +#include "psa_crypto_its.h" + +#include +#include +#include +#include + +#if !defined(PSA_ITS_STORAGE_PREFIX) +#define PSA_ITS_STORAGE_PREFIX "" +#endif + +#define PSA_ITS_STORAGE_FILENAME_PATTERN "%08x%08x" +#define PSA_ITS_STORAGE_SUFFIX ".psa_its" +#define PSA_ITS_STORAGE_FILENAME_LENGTH \ + (sizeof(PSA_ITS_STORAGE_PREFIX) - 1 + /*prefix without terminating 0*/ \ + 16 + /*UID (64-bit number in hex)*/ \ + sizeof(PSA_ITS_STORAGE_SUFFIX) - 1 + /*suffix without terminating 0*/ \ + 1 /*terminating null byte*/) +#define PSA_ITS_STORAGE_TEMP \ + PSA_ITS_STORAGE_PREFIX "tempfile" PSA_ITS_STORAGE_SUFFIX + +/* The maximum value of psa_storage_info_t.size */ +#define PSA_ITS_MAX_SIZE 0xffffffff + +#define PSA_ITS_MAGIC_STRING "PSA\0ITS\0" +#define PSA_ITS_MAGIC_LENGTH 8 + +/* As rename fails on Windows if the new filepath already exists, + * use MoveFileExA with the MOVEFILE_REPLACE_EXISTING flag instead. + * Returns 0 on success, nonzero on failure. */ +#if defined(_WIN32) +#define rename_replace_existing(oldpath, newpath) \ + (!MoveFileExA(oldpath, newpath, MOVEFILE_REPLACE_EXISTING)) +#else +#define rename_replace_existing(oldpath, newpath) rename(oldpath, newpath) +#endif + +typedef struct { + uint8_t magic[PSA_ITS_MAGIC_LENGTH]; + uint8_t size[sizeof(uint32_t)]; + uint8_t flags[sizeof(psa_storage_create_flags_t)]; +} psa_its_file_header_t; + +static void psa_its_fill_filename(psa_storage_uid_t uid, char *filename) +{ + /* Break up the UID into two 32-bit pieces so as not to rely on + * long long support in snprintf. */ + mbedtls_snprintf(filename, PSA_ITS_STORAGE_FILENAME_LENGTH, + "%s" PSA_ITS_STORAGE_FILENAME_PATTERN "%s", + PSA_ITS_STORAGE_PREFIX, + (unsigned) (uid >> 32), + (unsigned) (uid & 0xffffffff), + PSA_ITS_STORAGE_SUFFIX); +} + +static psa_status_t psa_its_read_file(psa_storage_uid_t uid, + struct psa_storage_info_t *p_info, + FILE **p_stream) +{ + char filename[PSA_ITS_STORAGE_FILENAME_LENGTH]; + psa_its_file_header_t header; + size_t n; + + *p_stream = NULL; + psa_its_fill_filename(uid, filename); + *p_stream = fopen(filename, "rb"); + if (*p_stream == NULL) { + return PSA_ERROR_DOES_NOT_EXIST; + } + + /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ + mbedtls_setbuf(*p_stream, NULL); + + n = fread(&header, 1, sizeof(header), *p_stream); + if (n != sizeof(header)) { + return PSA_ERROR_DATA_CORRUPT; + } + if (memcmp(header.magic, PSA_ITS_MAGIC_STRING, + PSA_ITS_MAGIC_LENGTH) != 0) { + return PSA_ERROR_DATA_CORRUPT; + } + + p_info->size = MBEDTLS_GET_UINT32_LE(header.size, 0); + p_info->flags = MBEDTLS_GET_UINT32_LE(header.flags, 0); + + return PSA_SUCCESS; +} + +psa_status_t psa_its_get_info(psa_storage_uid_t uid, + struct psa_storage_info_t *p_info) +{ + psa_status_t status; + FILE *stream = NULL; + status = psa_its_read_file(uid, p_info, &stream); + if (stream != NULL) { + fclose(stream); + } + return status; +} + +psa_status_t psa_its_get(psa_storage_uid_t uid, + uint32_t data_offset, + uint32_t data_length, + void *p_data, + size_t *p_data_length) +{ + psa_status_t status; + FILE *stream = NULL; + size_t n; + struct psa_storage_info_t info; + + status = psa_its_read_file(uid, &info, &stream); + if (status != PSA_SUCCESS) { + goto exit; + } + status = PSA_ERROR_INVALID_ARGUMENT; + if (data_offset + data_length < data_offset) { + goto exit; + } +#if SIZE_MAX < 0xffffffff + if (data_offset + data_length > SIZE_MAX) { + goto exit; + } +#endif + if (data_offset + data_length > info.size) { + goto exit; + } + + status = PSA_ERROR_STORAGE_FAILURE; +#if LONG_MAX < 0xffffffff + while (data_offset > LONG_MAX) { + if (fseek(stream, LONG_MAX, SEEK_CUR) != 0) { + goto exit; + } + data_offset -= LONG_MAX; + } +#endif + if (fseek(stream, data_offset, SEEK_CUR) != 0) { + goto exit; + } + n = fread(p_data, 1, data_length, stream); + if (n != data_length) { + goto exit; + } + status = PSA_SUCCESS; + if (p_data_length != NULL) { + *p_data_length = n; + } + +exit: + if (stream != NULL) { + fclose(stream); + } + return status; +} + +psa_status_t psa_its_set(psa_storage_uid_t uid, + uint32_t data_length, + const void *p_data, + psa_storage_create_flags_t create_flags) +{ + if (uid == 0) { + return PSA_ERROR_INVALID_HANDLE; + } + + psa_status_t status = PSA_ERROR_STORAGE_FAILURE; + char filename[PSA_ITS_STORAGE_FILENAME_LENGTH]; + FILE *stream = NULL; + psa_its_file_header_t header; + size_t n; + + memcpy(header.magic, PSA_ITS_MAGIC_STRING, PSA_ITS_MAGIC_LENGTH); + MBEDTLS_PUT_UINT32_LE(data_length, header.size, 0); + MBEDTLS_PUT_UINT32_LE(create_flags, header.flags, 0); + + psa_its_fill_filename(uid, filename); + stream = fopen(PSA_ITS_STORAGE_TEMP, "wb"); + + if (stream == NULL) { + goto exit; + } + + /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ + mbedtls_setbuf(stream, NULL); + + status = PSA_ERROR_INSUFFICIENT_STORAGE; + n = fwrite(&header, 1, sizeof(header), stream); + if (n != sizeof(header)) { + goto exit; + } + if (data_length != 0) { + n = fwrite(p_data, 1, data_length, stream); + if (n != data_length) { + goto exit; + } + } + status = PSA_SUCCESS; + +exit: + if (stream != NULL) { + int ret = fclose(stream); + if (status == PSA_SUCCESS && ret != 0) { + status = PSA_ERROR_INSUFFICIENT_STORAGE; + } + } + if (status == PSA_SUCCESS) { + if (rename_replace_existing(PSA_ITS_STORAGE_TEMP, filename) != 0) { + status = PSA_ERROR_STORAGE_FAILURE; + } + } + /* The temporary file may still exist, but only in failure cases where + * we're already reporting an error. So there's nothing we can do on + * failure. If the function succeeded, and in some error cases, the + * temporary file doesn't exist and so remove() is expected to fail. + * Thus we just ignore the return status of remove(). */ + (void) remove(PSA_ITS_STORAGE_TEMP); + return status; +} + +psa_status_t psa_its_remove(psa_storage_uid_t uid) +{ + char filename[PSA_ITS_STORAGE_FILENAME_LENGTH]; + FILE *stream; + psa_its_fill_filename(uid, filename); + stream = fopen(filename, "rb"); + if (stream == NULL) { + return PSA_ERROR_DOES_NOT_EXIST; + } + fclose(stream); + if (remove(filename) != 0) { + return PSA_ERROR_STORAGE_FAILURE; + } + return PSA_SUCCESS; +} + +#endif /* MBEDTLS_PSA_ITS_FILE_C */ diff --git a/tf-psa-crypto/core/psa_util.c b/tf-psa-crypto/core/psa_util.c new file mode 100644 index 0000000000..5d5c109452 --- /dev/null +++ b/tf-psa-crypto/core/psa_util.c @@ -0,0 +1,295 @@ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +/* This is needed for MBEDTLS_ERR_XXX macros */ +#include + +#if defined(MBEDTLS_ASN1_WRITE_C) +#include +#include +#endif + +#include + +#if defined(MBEDTLS_PSA_CRYPTO_CLIENT) + +#include +#include + +/* Wrapper function allowing the classic API to use the PSA RNG. + * + * `mbedtls_psa_get_random(MBEDTLS_PSA_RANDOM_STATE, ...)` calls + * `psa_generate_random(...)`. The state parameter is ignored since the + * PSA API doesn't support passing an explicit state. + */ +int mbedtls_psa_get_random(void *p_rng, + unsigned char *output, + size_t output_size) +{ + /* This function takes a pointer to the RNG state because that's what + * classic mbedtls functions using an RNG expect. The PSA RNG manages + * its own state internally and doesn't let the caller access that state. + * So we just ignore the state parameter, and in practice we'll pass + * NULL. */ + (void) p_rng; + psa_status_t status = psa_generate_random(output, output_size); + if (status == PSA_SUCCESS) { + return 0; + } else { + return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; + } +} + +#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */ + +#if defined(PSA_HAVE_ALG_SOME_ECDSA) + +/** + * \brief Convert a single raw coordinate to DER ASN.1 format. The output der + * buffer is filled backward (i.e. starting from its end). + * + * \param raw_buf Buffer containing the raw coordinate to be + * converted. + * \param raw_len Length of raw_buf in bytes. This must be > 0. + * \param der_buf_start Pointer to the beginning of the buffer which + * will be filled with the DER converted data. + * \param der_buf_end End of the buffer used to store the DER output. + * + * \return On success, the amount of data (in bytes) written to + * the DER buffer. + * \return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL if the provided der + * buffer is too small to contain all the converted data. + * \return MBEDTLS_ERR_ASN1_INVALID_DATA if the input raw + * coordinate is null (i.e. all zeros). + * + * \warning Raw and der buffer must not be overlapping. + */ +static int convert_raw_to_der_single_int(const unsigned char *raw_buf, size_t raw_len, + unsigned char *der_buf_start, + unsigned char *der_buf_end) +{ + unsigned char *p = der_buf_end; + int len; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + /* ASN.1 DER encoding requires minimal length, so skip leading 0s. + * Provided input MPIs should not be 0, but as a failsafe measure, still + * detect that and return error in case. */ + while (*raw_buf == 0x00) { + ++raw_buf; + --raw_len; + if (raw_len == 0) { + return MBEDTLS_ERR_ASN1_INVALID_DATA; + } + } + len = (int) raw_len; + + /* Copy the raw coordinate to the end of der_buf. */ + if ((p - der_buf_start) < len) { + return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL; + } + p -= len; + memcpy(p, raw_buf, len); + + /* If MSb is 1, ASN.1 requires that we prepend a 0. */ + if (*p & 0x80) { + if ((p - der_buf_start) < 1) { + return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL; + } + --p; + *p = 0x00; + ++len; + } + + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&p, der_buf_start, len)); + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&p, der_buf_start, MBEDTLS_ASN1_INTEGER)); + + return len; +} + +int mbedtls_ecdsa_raw_to_der(size_t bits, const unsigned char *raw, size_t raw_len, + unsigned char *der, size_t der_size, size_t *der_len) +{ + unsigned char r[PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS)]; + unsigned char s[PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS)]; + const size_t coordinate_len = PSA_BITS_TO_BYTES(bits); + size_t len = 0; + unsigned char *p = der + der_size; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if (bits == 0) { + return MBEDTLS_ERR_ASN1_INVALID_DATA; + } + if (raw_len != (2 * coordinate_len)) { + return MBEDTLS_ERR_ASN1_INVALID_DATA; + } + if (coordinate_len > sizeof(r)) { + return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL; + } + + /* Since raw and der buffers might overlap, dump r and s before starting + * the conversion. */ + memcpy(r, raw, coordinate_len); + memcpy(s, raw + coordinate_len, coordinate_len); + + /* der buffer will initially be written starting from its end so we pick s + * first and then r. */ + ret = convert_raw_to_der_single_int(s, coordinate_len, der, p); + if (ret < 0) { + return ret; + } + p -= ret; + len += ret; + + ret = convert_raw_to_der_single_int(r, coordinate_len, der, p); + if (ret < 0) { + return ret; + } + p -= ret; + len += ret; + + /* Add ASN.1 header (len + tag). */ + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&p, der, len)); + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&p, der, + MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE)); + + /* memmove the content of der buffer to its beginnig. */ + memmove(der, p, len); + *der_len = len; + + return 0; +} + +/** + * \brief Convert a single integer from ASN.1 DER format to raw. + * + * \param der Buffer containing the DER integer value to be + * converted. + * \param der_len Length of the der buffer in bytes. + * \param raw Output buffer that will be filled with the + * converted data. This should be at least + * coordinate_size bytes and it must be zeroed before + * calling this function. + * \param coordinate_size Size (in bytes) of a single coordinate in raw + * format. + * + * \return On success, the amount of DER data parsed from the + * provided der buffer. + * \return MBEDTLS_ERR_ASN1_UNEXPECTED_TAG if the integer tag + * is missing in the der buffer. + * \return MBEDTLS_ERR_ASN1_LENGTH_MISMATCH if the integer + * is null (i.e. all zeros) or if the output raw buffer + * is too small to contain the converted raw value. + * + * \warning Der and raw buffers must not be overlapping. + */ +static int convert_der_to_raw_single_int(unsigned char *der, size_t der_len, + unsigned char *raw, size_t coordinate_size) +{ + unsigned char *p = der; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t unpadded_len, padding_len = 0; + + /* Get the length of ASN.1 element (i.e. the integer we need to parse). */ + ret = mbedtls_asn1_get_tag(&p, p + der_len, &unpadded_len, + MBEDTLS_ASN1_INTEGER); + if (ret != 0) { + return ret; + } + + /* It's invalid to have: + * - unpadded_len == 0. + * - MSb set without a leading 0x00 (leading 0x00 is checked below). */ + if (((unpadded_len == 0) || (*p & 0x80) != 0)) { + return MBEDTLS_ERR_ASN1_INVALID_DATA; + } + + /* Skip possible leading zero */ + if (*p == 0x00) { + p++; + unpadded_len--; + /* It is not allowed to have more than 1 leading zero. + * Ignore the case in which unpadded_len = 0 because that's a 0 encoded + * in ASN.1 format (i.e. 020100). */ + if ((unpadded_len > 0) && (*p == 0x00)) { + return MBEDTLS_ERR_ASN1_INVALID_DATA; + } + } + + if (unpadded_len > coordinate_size) { + /* Parsed number is longer than the maximum expected value. */ + return MBEDTLS_ERR_ASN1_INVALID_DATA; + } + padding_len = coordinate_size - unpadded_len; + /* raw buffer was already zeroed by the calling function so zero-padding + * operation is skipped here. */ + memcpy(raw + padding_len, p, unpadded_len); + p += unpadded_len; + + return (int) (p - der); +} + +int mbedtls_ecdsa_der_to_raw(size_t bits, const unsigned char *der, size_t der_len, + unsigned char *raw, size_t raw_size, size_t *raw_len) +{ + unsigned char raw_tmp[PSA_VENDOR_ECDSA_SIGNATURE_MAX_SIZE]; + unsigned char *p = (unsigned char *) der; + size_t data_len; + size_t coordinate_size = PSA_BITS_TO_BYTES(bits); + int ret; + + if (bits == 0) { + return MBEDTLS_ERR_ASN1_INVALID_DATA; + } + /* The output raw buffer should be at least twice the size of a raw + * coordinate in order to store r and s. */ + if (raw_size < coordinate_size * 2) { + return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL; + } + if (2 * coordinate_size > sizeof(raw_tmp)) { + return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL; + } + + /* Check that the provided input DER buffer has the right header. */ + ret = mbedtls_asn1_get_tag(&p, der + der_len, &data_len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); + if (ret != 0) { + return ret; + } + + memset(raw_tmp, 0, 2 * coordinate_size); + + /* Extract r */ + ret = convert_der_to_raw_single_int(p, data_len, raw_tmp, coordinate_size); + if (ret < 0) { + return ret; + } + p += ret; + data_len -= ret; + + /* Extract s */ + ret = convert_der_to_raw_single_int(p, data_len, raw_tmp + coordinate_size, + coordinate_size); + if (ret < 0) { + return ret; + } + p += ret; + data_len -= ret; + + /* Check that we consumed all the input der data. */ + if ((size_t) (p - der) != der_len) { + return MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + } + + memcpy(raw, raw_tmp, 2 * coordinate_size); + *raw_len = 2 * coordinate_size; + + return 0; +} + +#endif /* PSA_HAVE_ALG_SOME_ECDSA */ diff --git a/tf-psa-crypto/core/tf_psa_crypto_check_config.h b/tf-psa-crypto/core/tf_psa_crypto_check_config.h new file mode 100644 index 0000000000..5b6b35bf21 --- /dev/null +++ b/tf-psa-crypto/core/tf_psa_crypto_check_config.h @@ -0,0 +1,598 @@ +/** + * \file tf-psa-crypto/check_config.h + * + * \brief Consistency checks for configuration options + * + * This is an internal header. Do not include it directly. + * + * This header is included automatically by all public TF-PSA-Crypto headers + * (via tf-psa-crypto/build_info.h). Do not include it directly in a + * configuration file such as psa/crypto_config.h or #TF_PSA_CRYPTO_USER_CONFIG_FILE! + * It would run at the wrong time due to missing derived symbols. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_TF_PSA_CRYPTO_CHECK_CONFIG_H +#define TF_PSA_CRYPTO_TF_PSA_CRYPTO_CHECK_CONFIG_H + +/* *INDENT-OFF* */ + +/* + * We assume CHAR_BIT is 8 in many places. In practice, this is true on our + * target platforms, so not an issue, but let's just be extra sure. + */ +#include +#if CHAR_BIT != 8 +#error "Mbed TLS requires a platform with 8-bit chars" +#endif + +#include + +#if defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER <= 1900) +#if !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_C is required on Windows" +#endif +/* See auto-enabling SNPRINTF_ALT and VSNPRINTF_ALT + * in */ +#endif /* _MINGW32__ || (_MSC_VER && (_MSC_VER <= 1900)) */ + +#if defined(MBEDTLS_DEPRECATED_WARNING) && \ + !defined(__GNUC__) && !defined(__clang__) +#error "MBEDTLS_DEPRECATED_WARNING only works with GCC and Clang" +#endif + +/* Limitations on ECC key types acceleration: if we have any of `PUBLIC_KEY`, + * `KEY_PAIR_BASIC`, `KEY_PAIR_IMPORT`, `KEY_PAIR_EXPORT` then we must have + * all 4 of them. + */ +#if defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_PUBLIC_KEY) || \ + defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_BASIC) || \ + defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \ + defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_EXPORT) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_PUBLIC_KEY) || \ + !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_BASIC) || \ + !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \ + !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_EXPORT) +#error "Unsupported partial support for ECC key type acceleration, see docs/driver-only-builds.md" +#endif /* not all of public, basic, import, export */ +#endif /* one of public, basic, import, export */ + +/* Limitations on ECC curves acceleration: partial curve acceleration is only + * supported with crypto excluding PK, X.509 or TLS. + * Note: no need to check X.509 as it depends on PK. */ +#if defined(MBEDTLS_PSA_ACCEL_ECC_BRAINPOOL_P_R1_256) || \ + defined(MBEDTLS_PSA_ACCEL_ECC_BRAINPOOL_P_R1_384) || \ + defined(MBEDTLS_PSA_ACCEL_ECC_BRAINPOOL_P_R1_512) || \ + defined(MBEDTLS_PSA_ACCEL_ECC_MONTGOMERY_255) || \ + defined(MBEDTLS_PSA_ACCEL_ECC_MONTGOMERY_448) || \ + defined(MBEDTLS_PSA_ACCEL_ECC_SECP_K1_256) || \ + defined(MBEDTLS_PSA_ACCEL_ECC_SECP_R1_256) || \ + defined(MBEDTLS_PSA_ACCEL_ECC_SECP_R1_384) || \ + defined(MBEDTLS_PSA_ACCEL_ECC_SECP_R1_521) +#if defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_CURVES) +#if defined(MBEDTLS_PK_C) +#error "Unsupported partial support for ECC curves acceleration, see docs/driver-only-builds.md" +#endif /* modules beyond what's supported */ +#endif /* not all curves accelerated */ +#endif /* some curve accelerated */ + +#if defined(MBEDTLS_CTR_DRBG_C) && !(defined(MBEDTLS_AES_C) || \ + (defined(MBEDTLS_PSA_CRYPTO_CLIENT) && defined(PSA_WANT_KEY_TYPE_AES) && \ + defined(PSA_WANT_ALG_ECB_NO_PADDING))) +#error "MBEDTLS_CTR_DRBG_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_CMAC_C) && \ + ( !defined(MBEDTLS_CIPHER_C ) || !defined(MBEDTLS_AES_C) ) +#error "MBEDTLS_CMAC_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +#if defined(PSA_WANT_ALG_CBC_NO_PADDING) +#error "MBEDTLS_BLOCK_CIPHER_NO_DECRYPT and PSA_WANT_ALG_CBC_NO_PADDING cannot be defined simultaneously" +#endif +#if defined(PSA_WANT_ALG_CBC_PKCS7) +#error "MBEDTLS_BLOCK_CIPHER_NO_DECRYPT and PSA_WANT_ALG_CBC_PKCS7 cannot be defined simultaneously" +#endif +#if defined(PSA_WANT_ALG_ECB_NO_PADDING) +#error "MBEDTLS_BLOCK_CIPHER_NO_DECRYPT and PSA_WANT_ALG_ECB_NO_PADDING cannot be defined simultaneously" +#endif +#if defined(MBEDTLS_NIST_KW_C) +#error "MBEDTLS_BLOCK_CIPHER_NO_DECRYPT and MBEDTLS_NIST_KW_C cannot be defined simultaneously" +#endif +#endif + +#if defined(MBEDTLS_ECDSA_C) && \ + !( defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) ) +#error "Built-in ECDSA implementation enabled but no suitable curve" +#endif + +#if defined(MBEDTLS_PK_C) +#if defined(PSA_HAVE_ALG_ECDSA_SIGN) && !defined(MBEDTLS_ASN1_WRITE_C) +#error "MBEDTLS_PK_C needs MBEDTLS_ASN1_WRITE_C for ECDSA signature" +#endif +#if defined(PSA_HAVE_ALG_ECDSA_VERIFY) && !defined(MBEDTLS_ASN1_PARSE_C) +#error "MBEDTLS_PK_C needs MBEDTLS_ASN1_PARSE_C for ECDSA verification" +#endif +#endif /* MBEDTLS_PK_C */ + +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + !defined(MBEDTLS_ECP_C) +#error "MBEDTLS_ECP_RESTARTABLE defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_LIGHT) && ( !defined(MBEDTLS_BIGNUM_C) || ( \ + !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) ) ) +#error "Generic elliptic curve module or a subset enabled, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ENTROPY_C) +# if !defined(MBEDTLS_ENTROPY_HAVE_SOURCES) + /* The entropy module needs at least one entropy source, such as + * #MBEDTLS_PSA_BUILTIN_GET_ENTROPY or #MBEDTLS_PSA_DRIVER_GET_ENTROPY + * or #MBEDTLS_ENTROPY_NV_SEED. + * + * If your platform has a cryptographic-quality random generator, + * enable #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG. + */ +# error "Entropy module enabled, but no sources" +# elif MBEDTLS_ENTROPY_TRUE_SOURCES == 0 +# if !defined(MBEDTLS_ENTROPY_NO_SOURCES_OK) + /* Having only the NV seed as an entropy source weakens security. + * To indicate that this is acceptable, define + * MBEDTLS_ENTROPY_NO_SOURCES_OK. */ +# error "Entropy module enabled, but no true sources" +# endif +# endif +#endif + +#if defined(MBEDTLS_ENTROPY_C) && \ + !(defined(PSA_WANT_ALG_SHA_512) || defined(PSA_WANT_ALG_SHA_256)) +#error "Entropy module enabled but neither SHA-256 nor SHA-512 is available" +#endif + +#if (MBEDTLS_PSA_CRYPTO_RNG_STRENGTH != 128) && \ + (MBEDTLS_PSA_CRYPTO_RNG_STRENGTH != 256) +#error "MBEDTLS_PSA_CRYPTO_RNG_STRENGTH must be 128 or 256" +#endif + +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) +#define MBEDTLS_HAS_MEMSAN // #undef at the end of this paragraph +#endif +#endif +#if defined(MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN) && !defined(MBEDTLS_HAS_MEMSAN) +#error "MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN requires building with MemorySanitizer" +#endif +#if defined(MBEDTLS_HAS_MEMSAN) && defined(MBEDTLS_HAVE_ASM) +#error "MemorySanitizer does not support assembly implementation" +#endif +#undef MBEDTLS_HAS_MEMSAN // temporary macro defined above + +#if defined(MBEDTLS_CCM_C) && \ + !(defined(MBEDTLS_CCM_GCM_CAN_AES) || defined(MBEDTLS_CCM_GCM_CAN_ARIA) || \ + defined(MBEDTLS_CCM_GCM_CAN_CAMELLIA)) +#error "Built-in CCM implementation enabled, but not all prerequisites" +#endif + +#if defined(MBEDTLS_GCM_C) && \ + !(defined(MBEDTLS_CCM_GCM_CAN_AES) || defined(MBEDTLS_CCM_GCM_CAN_ARIA) || \ + defined(MBEDTLS_CCM_GCM_CAN_CAMELLIA)) +#error "Built-in GCM implementation enabled, but not all prerequisites" +#endif + +#if defined(MBEDTLS_HMAC_DRBG_C) && !defined(MBEDTLS_MD_C) +#error "MBEDTLS_HMAC_DRBG_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_MD_C) && \ + !defined(PSA_WANT_ALG_MD5) && \ + !defined(PSA_WANT_ALG_RIPEMD160) && \ + !defined(PSA_WANT_ALG_SHA_1) && \ + !defined(PSA_WANT_ALG_SHA_224) && \ + !defined(PSA_WANT_ALG_SHA_256) && \ + !defined(PSA_WANT_ALG_SHA_384) && \ + !defined(PSA_WANT_ALG_SHA_512) && \ + !defined(PSA_WANT_ALG_SHA3_224) && \ + !defined(PSA_WANT_ALG_SHA3_256) && \ + !defined(PSA_WANT_ALG_SHA3_384) && \ + !defined(PSA_WANT_ALG_SHA3_512) +#error "MBEDTLS_MD_C defined, but no hash algorithm" +#endif + +#if defined(MBEDTLS_LMS_C) && \ + ! ( defined(MBEDTLS_PSA_CRYPTO_CLIENT) && defined(PSA_WANT_ALG_SHA_256) ) +#error "MBEDTLS_LMS_C requires MBEDTLS_PSA_CRYPTO_C and PSA_WANT_ALG_SHA_256" +#endif + +#if defined(MBEDTLS_LMS_PRIVATE) && \ + ( !defined(MBEDTLS_LMS_C) ) +#error "MBEDTLS_LMS_PRIVATE requires MBEDTLS_LMS_C" +#endif + +#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) && \ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) ) +#error "MBEDTLS_MEMORY_BUFFER_ALLOC_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_MEMORY_BACKTRACE) && !defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) +#error "MBEDTLS_MEMORY_BACKTRACE defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_MEMORY_DEBUG) && !defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) +#error "MBEDTLS_MEMORY_DEBUG defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) && !defined(MBEDTLS_BASE64_C) +#error "MBEDTLS_PEM_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PEM_WRITE_C) && !defined(MBEDTLS_BASE64_C) +#error "MBEDTLS_PEM_WRITE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PK_C) && \ + !defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY) && !defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) +#error "MBEDTLS_PK_C defined, but neither PSA_WANT_KEY_TYPE_[ECC|RSA]_PUBLIC_KEY are" +#endif + +#if defined(MBEDTLS_PK_C) && !defined(MBEDTLS_PSA_CRYPTO_CLIENT) +#error "MBEDTLS_PK_C defined, but not MBEDTLS_PSA_CRYPTO_CLIENT" +#endif + +#if defined(MBEDTLS_PK_PARSE_C) && \ + (!defined(MBEDTLS_ASN1_PARSE_C) || \ + !defined(MBEDTLS_PK_C)) +#error "MBEDTLS_PK_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PK_WRITE_C) && \ + (!defined(MBEDTLS_ASN1_WRITE_C) || \ + !defined(MBEDTLS_PK_C)) +#error "MBEDTLS_PK_WRITE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_EXIT_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_EXIT_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_EXIT_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_EXIT) ||\ + defined(MBEDTLS_PLATFORM_EXIT_ALT) ) +#error "MBEDTLS_PLATFORM_EXIT_MACRO and MBEDTLS_PLATFORM_STD_EXIT/MBEDTLS_PLATFORM_EXIT_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_SETBUF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_SETBUF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_SETBUF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_SETBUF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_SETBUF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_SETBUF) ||\ + defined(MBEDTLS_PLATFORM_SETBUF_ALT) ) +#error "MBEDTLS_PLATFORM_SETBUF_MACRO and MBEDTLS_PLATFORM_STD_SETBUF/MBEDTLS_PLATFORM_SETBUF_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_ALT) &&\ + ( !defined(MBEDTLS_PLATFORM_C) ||\ + !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_TIME_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) ||\ + !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_TIME_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_MS_TIME_TYPE_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_MS_TIME_TYPE_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_MS_TIME_ALT) && \ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_MS_TIME_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) ||\ + !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_TIME) ||\ + defined(MBEDTLS_PLATFORM_TIME_ALT) ) +#error "MBEDTLS_PLATFORM_TIME_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_TIME) ||\ + defined(MBEDTLS_PLATFORM_TIME_ALT) ) +#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_FPRINTF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_FPRINTF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_FPRINTF) ||\ + defined(MBEDTLS_PLATFORM_FPRINTF_ALT) ) +#error "MBEDTLS_PLATFORM_FPRINTF_MACRO and MBEDTLS_PLATFORM_STD_FPRINTF/MBEDTLS_PLATFORM_FPRINTF_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) ) +#error "MBEDTLS_PLATFORM_FREE_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\ + defined(MBEDTLS_PLATFORM_STD_FREE) +#error "MBEDTLS_PLATFORM_FREE_MACRO and MBEDTLS_PLATFORM_STD_FREE cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && !defined(MBEDTLS_PLATFORM_CALLOC_MACRO) +#error "MBEDTLS_PLATFORM_CALLOC_MACRO must be defined if MBEDTLS_PLATFORM_FREE_MACRO is" +#endif + +#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) ) +#error "MBEDTLS_PLATFORM_CALLOC_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\ + defined(MBEDTLS_PLATFORM_STD_CALLOC) +#error "MBEDTLS_PLATFORM_CALLOC_MACRO and MBEDTLS_PLATFORM_STD_CALLOC cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) && !defined(MBEDTLS_PLATFORM_FREE_MACRO) +#error "MBEDTLS_PLATFORM_FREE_MACRO must be defined if MBEDTLS_PLATFORM_CALLOC_MACRO is" +#endif + +#if defined(MBEDTLS_PLATFORM_MEMORY) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_MEMORY defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_PRINTF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_PRINTF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_PRINTF) ||\ + defined(MBEDTLS_PLATFORM_PRINTF_ALT) ) +#error "MBEDTLS_PLATFORM_PRINTF_MACRO and MBEDTLS_PLATFORM_STD_PRINTF/MBEDTLS_PLATFORM_PRINTF_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_SNPRINTF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_SNPRINTF) ||\ + defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) ) +#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO and MBEDTLS_PLATFORM_STD_SNPRINTF/MBEDTLS_PLATFORM_SNPRINTF_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_VSNPRINTF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_VSNPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_VSNPRINTF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_VSNPRINTF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_VSNPRINTF) ||\ + defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT) ) +#error "MBEDTLS_PLATFORM_VSNPRINTF_MACRO and MBEDTLS_PLATFORM_STD_VSNPRINTF/MBEDTLS_PLATFORM_VSNPRINTF_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR) &&\ + !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) +#error "MBEDTLS_PLATFORM_STD_MEM_HDR defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY) +#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_FREE) && !defined(MBEDTLS_PLATFORM_MEMORY) +#error "MBEDTLS_PLATFORM_STD_FREE defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_EXIT) &&\ + !defined(MBEDTLS_PLATFORM_EXIT_ALT) +#error "MBEDTLS_PLATFORM_STD_EXIT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_TIME) &&\ + ( !defined(MBEDTLS_PLATFORM_TIME_ALT) ||\ + !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_STD_TIME defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_FPRINTF) &&\ + !defined(MBEDTLS_PLATFORM_FPRINTF_ALT) +#error "MBEDTLS_PLATFORM_STD_FPRINTF defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_PRINTF) &&\ + !defined(MBEDTLS_PLATFORM_PRINTF_ALT) +#error "MBEDTLS_PLATFORM_STD_PRINTF defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_SNPRINTF) &&\ + !defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) +#error "MBEDTLS_PLATFORM_STD_SNPRINTF defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ENTROPY_NV_SEED) &&\ + (!defined(MBEDTLS_PSA_CRYPTO_C) || !defined(MBEDTLS_PLATFORM_C)) +#error "MBEDTLS_ENTROPY_NV_SEED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ENTROPY_NV_SEED) && defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +#error "MBEDTLS_ENTROPY_NV_SEED has no effect when MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG is enabled" +#endif + +#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) &&\ + !defined(MBEDTLS_ENTROPY_NV_SEED) +#error "MBEDTLS_PLATFORM_NV_SEED_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) &&\ + !defined(MBEDTLS_PLATFORM_NV_SEED_ALT) +#error "MBEDTLS_PLATFORM_STD_NV_SEED_READ defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) &&\ + !defined(MBEDTLS_PLATFORM_NV_SEED_ALT) +#error "MBEDTLS_PLATFORM_STD_NV_SEED_WRITE defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) ||\ + defined(MBEDTLS_PLATFORM_NV_SEED_ALT) ) +#error "MBEDTLS_PLATFORM_NV_SEED_READ_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_READ cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) ||\ + defined(MBEDTLS_PLATFORM_NV_SEED_ALT) ) +#error "MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_WRITE cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PSA_CRYPTO_C) && \ + !(defined(MBEDTLS_CTR_DRBG_C) || defined(MBEDTLS_HMAC_DRBG_C) || \ + defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)) +#error "MBEDTLS_PSA_CRYPTO_C defined, but missing RNG" +#endif + +#if defined(MBEDTLS_PSA_CRYPTO_C) && defined(PSA_HAVE_SOFT_BLOCK_MODE) && \ + defined(PSA_HAVE_SOFT_BLOCK_CIPHER) && !defined(MBEDTLS_CIPHER_C) +#error "MBEDTLS_PSA_CRYPTO_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PSA_CRYPTO_SPM) && !defined(MBEDTLS_PSA_CRYPTO_C) +#error "MBEDTLS_PSA_CRYPTO_SPM defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) && \ + ! defined(MBEDTLS_PSA_CRYPTO_C) +#error "MBEDTLS_PSA_CRYPTO_STORAGE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) && \ + defined(MBEDTLS_PSA_STATIC_KEY_SLOTS) +#error "MBEDTLS_PSA_KEY_STORE_DYNAMIC and MBEDTLS_PSA_STATIC_KEY_SLOTS cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PSA_ITS_FILE_C) && \ + !defined(MBEDTLS_FS_IO) +#error "MBEDTLS_PSA_ITS_FILE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT) && \ + defined(MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY) +#error "Must only define one of MBEDTLS_SHA512_USE_A64_CRYPTO_*" +#endif + +#if defined(MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT) || \ + defined(MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY) +#if !defined(MBEDTLS_SHA512_C) +#error "MBEDTLS_SHA512_USE_A64_CRYPTO_* defined without the SHA-512 built-in implementation" +#endif + +#endif /* MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT || MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY */ + +#if defined(MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY) && !defined(__aarch64__) +#error "MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY defined on non-Aarch64 system" +#endif + +#if defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT) && \ + defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY) +#error "Must only define one of MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_*" +#endif + +#if defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT) || \ + defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY) +#if !defined(MBEDTLS_SHA256_C) +#error "MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_* defined without the SHA-256 built-in implementation" +#endif + +#endif + +#if defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY) && !defined(MBEDTLS_ARCH_IS_ARMV8_A) +#error "MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY defined on non-Armv8-A system" +#endif + +#if defined(MBEDTLS_THREADING_PTHREAD) +#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL) +#error "MBEDTLS_THREADING_PTHREAD defined, but not all prerequisites" +#endif +#define MBEDTLS_THREADING_IMPL // undef at the end of this paragraph +#endif +#if defined(MBEDTLS_THREADING_ALT) +#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL) +#error "MBEDTLS_THREADING_ALT defined, but not all prerequisites" +#endif +#define MBEDTLS_THREADING_IMPL // undef at the end of this paragraph +#endif +#if defined(MBEDTLS_THREADING_C) && !defined(MBEDTLS_THREADING_IMPL) +#error "MBEDTLS_THREADING_C defined, single threading implementation required" +#endif +#undef MBEDTLS_THREADING_IMPL // temporary macro defined above + +#if defined(MBEDTLS_HAVE_INT32) && defined(MBEDTLS_HAVE_INT64) +#error "MBEDTLS_HAVE_INT32 and MBEDTLS_HAVE_INT64 cannot be defined simultaneously" +#endif /* MBEDTLS_HAVE_INT32 && MBEDTLS_HAVE_INT64 */ + +#if ( defined(MBEDTLS_HAVE_INT32) || defined(MBEDTLS_HAVE_INT64) ) && \ + defined(MBEDTLS_HAVE_ASM) +#error "MBEDTLS_HAVE_INT32/MBEDTLS_HAVE_INT64 and MBEDTLS_HAVE_ASM cannot be defined simultaneously" +#endif /* (MBEDTLS_HAVE_INT32 || MBEDTLS_HAVE_INT64) && MBEDTLS_HAVE_ASM */ + +#if (defined(PSA_WANT_ECC_SECP_R1_192) || defined(PSA_WANT_ECC_SECP_K1_192)) //no-check-names +#error "PSA_WANT_ECC_SECP_R1_192 and PSA_WANT_ECC_SECP_K1_192 are no longer supported" +#endif + +/* *INDENT-ON* */ +#endif /* TF_PSA_CRYPTO_TF_PSA_CRYPTO_CHECK_CONFIG_H */ diff --git a/tf-psa-crypto/core/tf_psa_crypto_common.h b/tf-psa-crypto/core/tf_psa_crypto_common.h new file mode 100644 index 0000000000..3aaf5c9835 --- /dev/null +++ b/tf-psa-crypto/core/tf_psa_crypto_common.h @@ -0,0 +1,628 @@ +/** + * \file tf_psa_crypto_common.h + * + * \brief Utility macros for internal use in the library. + * + * This file should be included as the first thing in all library C files. + * It must not be included by sample programs, since sample programs + * illustrate what you can do without the library sources. + * It may be included (often indirectly) by test code that isn't purely + * black-box testing. + * + * This file takes care of setting up requirements for platform headers. + * It includes the library configuration and derived macros. + * It additionally defines various utility macros and other definitions + * (but no function declarations). + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_TF_PSA_CRYPTO_COMMON_H +#define TF_PSA_CRYPTO_TF_PSA_CRYPTO_COMMON_H + +/* Before including any system header, declare some macros to tell system + * headers what we expect of them. */ +#include "tf_psa_crypto_platform_requirements.h" + +/* From this point onwards, ensure we have the library configuration and + * the configuration-derived macros. */ +#include "tf-psa-crypto/build_info.h" + +#include "alignment.h" + +#include +#include +#include +#include + +#if defined(__ARM_NEON) +#include +#define MBEDTLS_HAVE_NEON_INTRINSICS +#elif defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64) +#include +#define MBEDTLS_HAVE_NEON_INTRINSICS +#endif + +/* Decide whether we're built for a Unix-like platform. + */ +#if defined(MBEDTLS_TEST_PLATFORM_IS_NOT_UNIXLIKE) //no-check-names +/* We may be building on a Unix-like platform, but for test purposes, + * do not try to use Unix features. */ +#elif defined(_WIN32) +/* If Windows platform interfaces are available, we use them, even if + * a Unix-like might also to be available. */ +/* defined(_WIN32) ==> we can include */ +#elif defined(unix) || defined(__unix) || defined(__unix__) || \ + (defined(__APPLE__) && defined(__MACH__)) || \ + defined(__HAIKU__) || \ + defined(__midipix__) || \ + /* Add other Unix-like platform indicators here ^^^^ */ 0 +/* defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) ==> we can include */ +#define MBEDTLS_PLATFORM_IS_UNIXLIKE +#endif + +/** Helper to define a function as static except when building invasive tests. + * + * If a function is only used inside its own source file and should be + * declared `static` to allow the compiler to optimize for code size, + * but that function has unit tests, define it with + * ``` + * MBEDTLS_STATIC_TESTABLE int mbedtls_foo(...) { ... } + * ``` + * and declare it in a header in the `library/` directory with + * ``` + * #if defined(MBEDTLS_TEST_HOOKS) + * int mbedtls_foo(...); + * #endif + * ``` + */ +#if defined(MBEDTLS_TEST_HOOKS) +#define MBEDTLS_STATIC_TESTABLE +#else +#define MBEDTLS_STATIC_TESTABLE static +#endif + +#if defined(MBEDTLS_TEST_HOOKS) +extern void (*mbedtls_test_hook_test_fail)(const char *test, int line, const char *file); +#define MBEDTLS_TEST_HOOK_TEST_ASSERT(TEST) \ + do { \ + if ((!(TEST)) && ((*mbedtls_test_hook_test_fail) != NULL)) \ + { \ + (*mbedtls_test_hook_test_fail)( #TEST, __LINE__, __FILE__); \ + } \ + } while (0) +#else +#define MBEDTLS_TEST_HOOK_TEST_ASSERT(TEST) +#endif /* defined(MBEDTLS_TEST_HOOKS) */ + +/** \def ARRAY_LENGTH + * Return the number of elements of a static or stack array. + * + * \param array A value of array (not pointer) type. + * + * \return The number of elements of the array. + */ +/* A correct implementation of ARRAY_LENGTH, but which silently gives + * a nonsensical result if called with a pointer rather than an array. */ +#define ARRAY_LENGTH_UNSAFE(array) \ + (sizeof(array) / sizeof(*(array))) + +#if defined(__GNUC__) +/* Test if arg and &(arg)[0] have the same type. This is true if arg is + * an array but not if it's a pointer. */ +#define IS_ARRAY_NOT_POINTER(arg) \ + (!__builtin_types_compatible_p(__typeof__(arg), \ + __typeof__(&(arg)[0]))) +/* A compile-time constant with the value 0. If `const_expr` is not a + * compile-time constant with a nonzero value, cause a compile-time error. */ +#define STATIC_ASSERT_EXPR(const_expr) \ + (0 && sizeof(struct { unsigned int STATIC_ASSERT : (const_expr) ? 1 : -1; })) + +/* Return the scalar value `value` (possibly promoted). This is a compile-time + * constant if `value` is. `condition` must be a compile-time constant. + * If `condition` is false, arrange to cause a compile-time error. */ +#define STATIC_ASSERT_THEN_RETURN(condition, value) \ + (STATIC_ASSERT_EXPR(condition) ? 0 : (value)) + +#define ARRAY_LENGTH(array) \ + (STATIC_ASSERT_THEN_RETURN(IS_ARRAY_NOT_POINTER(array), \ + ARRAY_LENGTH_UNSAFE(array))) + +#else +/* If we aren't sure the compiler supports our non-standard tricks, + * fall back to the unsafe implementation. */ +#define ARRAY_LENGTH(array) ARRAY_LENGTH_UNSAFE(array) +#endif + +#if defined(__has_builtin) +#define MBEDTLS_HAS_BUILTIN(x) __has_builtin(x) +#else +#define MBEDTLS_HAS_BUILTIN(x) 0 +#endif + +/** Allow library to access its structs' private members. + * + * Although structs defined in header files are publicly available, + * their members are private and should not be accessed by the user. + */ +#define MBEDTLS_ALLOW_PRIVATE_ACCESS + +/** + * \brief Securely zeroize a buffer then free it. + * + * Similar to making consecutive calls to + * \c mbedtls_platform_zeroize() and \c mbedtls_free(), but has + * code size savings, and potential for optimisation in the future. + * + * Guaranteed to be a no-op if \p buf is \c NULL and \p len is 0. + * + * \param buf Buffer to be zeroized then freed. + * \param len Length of the buffer in bytes + */ +void mbedtls_zeroize_and_free(void *buf, size_t len); + +/** Return an offset into a buffer. + * + * This is just the addition of an offset to a pointer, except that this + * function also accepts an offset of 0 into a buffer whose pointer is null. + * (`p + n` has undefined behavior when `p` is null, even when `n == 0`. + * A null pointer is a valid buffer pointer when the size is 0, for example + * as the result of `malloc(0)` on some platforms.) + * + * \param p Pointer to a buffer of at least n bytes. + * This may be \p NULL if \p n is zero. + * \param n An offset in bytes. + * \return Pointer to offset \p n in the buffer \p p. + * Note that this is only a valid pointer if the size of the + * buffer is at least \p n + 1. + */ +static inline unsigned char *mbedtls_buffer_offset( + unsigned char *p, size_t n) +{ + return p == NULL ? NULL : p + n; +} + +/** Return an offset into a read-only buffer. + * + * Similar to mbedtls_buffer_offset(), but for const pointers. + * + * \param p Pointer to a buffer of at least n bytes. + * This may be \p NULL if \p n is zero. + * \param n An offset in bytes. + * \return Pointer to offset \p n in the buffer \p p. + * Note that this is only a valid pointer if the size of the + * buffer is at least \p n + 1. + */ +static inline const unsigned char *mbedtls_buffer_offset_const( + const unsigned char *p, size_t n) +{ + return p == NULL ? NULL : p + n; +} + +/* Always inline mbedtls_xor() for similar reasons as mbedtls_xor_no_simd(). */ +#if defined(__IAR_SYSTEMS_ICC__) +#pragma inline = forced +#elif defined(__GNUC__) +__attribute__((always_inline)) +#endif +/** + * Perform a fast block XOR operation, such that + * r[i] = a[i] ^ b[i] where 0 <= i < n + * + * \param r Pointer to result (buffer of at least \p n bytes). \p r + * may be equal to either \p a or \p b, but behaviour when + * it overlaps in other ways is undefined. + * \param a Pointer to input (buffer of at least \p n bytes) + * \param b Pointer to input (buffer of at least \p n bytes) + * \param n Number of bytes to process. + * + * \note Depending on the situation, it may be faster to use either mbedtls_xor() or + * mbedtls_xor_no_simd() (these are functionally equivalent). + * If the result is used immediately after the xor operation in non-SIMD code (e.g, in + * AES-CBC), there may be additional latency to transfer the data from SIMD to scalar + * registers, and in this case, mbedtls_xor_no_simd() may be faster. In other cases where + * the result is not used immediately (e.g., in AES-CTR), mbedtls_xor() may be faster. + * For targets without SIMD support, they will behave the same. + */ +static inline void mbedtls_xor(unsigned char *r, + const unsigned char *a, + const unsigned char *b, + size_t n) +{ + size_t i = 0; +#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) +#if defined(MBEDTLS_HAVE_NEON_INTRINSICS) && \ + (!(defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_GCC_VERSION < 70300)) + /* Old GCC versions generate a warning here, so disable the NEON path for these compilers */ + for (; (i + 16) <= n; i += 16) { + uint8x16_t v1 = vld1q_u8(a + i); + uint8x16_t v2 = vld1q_u8(b + i); + uint8x16_t x = veorq_u8(v1, v2); + vst1q_u8(r + i, x); + } +#if defined(__IAR_SYSTEMS_ICC__) + /* This if statement helps some compilers (e.g., IAR) optimise out the byte-by-byte tail case + * where n is a constant multiple of 16. + * For other compilers (e.g. recent gcc and clang) it makes no difference if n is a compile-time + * constant, and is a very small perf regression if n is not a compile-time constant. */ + if (n % 16 == 0) { + return; + } +#endif +#if defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_HAS_BUILTIN(__builtin_constant_p) + /* Some GCC versions (e.g. 14.3) with compile-time array bounds checking are confused + * when the byte-by-byte tail case is unused because the length is a constant multiple + * of 16. Eliminate a run-time check by only doing this for constant values. */ + if (__builtin_constant_p(n) && n % 16 == 0) { + return; + } +#endif +#elif defined(MBEDTLS_ARCH_IS_X64) || defined(MBEDTLS_ARCH_IS_ARM64) + /* This codepath probably only makes sense on architectures with 64-bit registers */ + for (; (i + 8) <= n; i += 8) { + uint64_t x = mbedtls_get_unaligned_uint64(a + i) ^ mbedtls_get_unaligned_uint64(b + i); + mbedtls_put_unaligned_uint64(r + i, x); + } +#if defined(__IAR_SYSTEMS_ICC__) + if (n % 8 == 0) { + return; + } +#endif +#if defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_HAS_BUILTIN(__builtin_constant_p) + /* Some GCC versions (e.g. 14.3) with compile-time array bounds checking are confused + * when the byte-by-byte tail case is unused because the length is a constant multiple + * of 8. Eliminate a run-time check by only doing this for constant values. */ + if (__builtin_constant_p(n) && n % 8 == 0) { + return; + } +#endif +#else + for (; (i + 4) <= n; i += 4) { + uint32_t x = mbedtls_get_unaligned_uint32(a + i) ^ mbedtls_get_unaligned_uint32(b + i); + mbedtls_put_unaligned_uint32(r + i, x); + } +#if defined(__IAR_SYSTEMS_ICC__) + if (n % 4 == 0) { + return; + } +#endif +#if defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_HAS_BUILTIN(__builtin_constant_p) + /* Some GCC versions (e.g. 14.3) with compile-time array bounds checking are confused + * when the byte-by-byte tail case is unused because the length is a constant multiple + * of 4. Eliminate a run-time check by only doing this for constant values. */ + if (__builtin_constant_p(n) && n % 4 == 0) { + return; + } +#endif +#endif +#endif + for (; i < n; i++) { + r[i] = a[i] ^ b[i]; + } +} + +/* Always inline mbedtls_xor_no_simd() as we see significant perf regressions when it does not get + * inlined (e.g., observed about 3x perf difference in gcm_mult_largetable with gcc 7 - 12) */ +#if defined(__IAR_SYSTEMS_ICC__) +#pragma inline = forced +#elif defined(__GNUC__) +__attribute__((always_inline)) +#endif +/** + * Perform a fast block XOR operation, such that + * r[i] = a[i] ^ b[i] where 0 <= i < n + * + * In some situations, this can perform better than mbedtls_xor() (e.g., it's about 5% + * better in AES-CBC). + * + * \param r Pointer to result (buffer of at least \p n bytes). \p r + * may be equal to either \p a or \p b, but behaviour when + * it overlaps in other ways is undefined. + * \param a Pointer to input (buffer of at least \p n bytes) + * \param b Pointer to input (buffer of at least \p n bytes) + * \param n Number of bytes to process. + * + * \note Depending on the situation, it may be faster to use either mbedtls_xor() or + * mbedtls_xor_no_simd() (these are functionally equivalent). + * If the result is used immediately after the xor operation in non-SIMD code (e.g, in + * AES-CBC), there may be additional latency to transfer the data from SIMD to scalar + * registers, and in this case, mbedtls_xor_no_simd() may be faster. In other cases where + * the result is not used immediately (e.g., in AES-CTR), mbedtls_xor() may be faster. + * For targets without SIMD support, they will behave the same. + */ +static inline void mbedtls_xor_no_simd(unsigned char *r, + const unsigned char *a, + const unsigned char *b, + size_t n) +{ + size_t i = 0; +#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) +#if defined(MBEDTLS_ARCH_IS_X64) || defined(MBEDTLS_ARCH_IS_ARM64) + /* This codepath probably only makes sense on architectures with 64-bit registers */ + for (; (i + 8) <= n; i += 8) { + uint64_t x = mbedtls_get_unaligned_uint64(a + i) ^ mbedtls_get_unaligned_uint64(b + i); + mbedtls_put_unaligned_uint64(r + i, x); + } +#if defined(__IAR_SYSTEMS_ICC__) + /* This if statement helps some compilers (e.g., IAR) optimise out the byte-by-byte tail case + * where n is a constant multiple of 8. + * For other compilers (e.g. recent gcc and clang) it makes no difference if n is a compile-time + * constant, and is a very small perf regression if n is not a compile-time constant. */ + if (n % 8 == 0) { + return; + } +#endif +#else + for (; (i + 4) <= n; i += 4) { + uint32_t x = mbedtls_get_unaligned_uint32(a + i) ^ mbedtls_get_unaligned_uint32(b + i); + mbedtls_put_unaligned_uint32(r + i, x); + } +#if defined(__IAR_SYSTEMS_ICC__) + if (n % 4 == 0) { + return; + } +#endif +#endif +#endif + for (; i < n; i++) { + r[i] = a[i] ^ b[i]; + } +} + +/* Fix MSVC C99 compatible issue + * MSVC support __func__ from visual studio 2015( 1900 ) + * Use MSVC predefine macro to avoid name check fail. + */ +#if (defined(_MSC_VER) && (_MSC_VER <= 1900)) +#define /*no-check-names*/ __func__ __FUNCTION__ +#endif + +/* Define `asm` for compilers which don't define it. */ +/* *INDENT-OFF* */ +#ifndef asm +#if defined(__IAR_SYSTEMS_ICC__) +#define asm __asm +#else +#define asm __asm__ +#endif +#endif +/* *INDENT-ON* */ + +/* + * Define the constraint used for read-only pointer operands to aarch64 asm. + * + * This is normally the usual "r", but for aarch64_32 (aka ILP32, + * as found in watchos), "p" is required to avoid warnings from clang. + * + * Note that clang does not recognise '+p' or '=p', and armclang + * does not recognise 'p' at all. Therefore, to update a pointer from + * aarch64 assembly, it is necessary to use something like: + * + * uintptr_t uptr = (uintptr_t) ptr; + * asm( "ldr x4, [%x0], #8" ... : "+r" (uptr) : : ) + * ptr = (void*) uptr; + * + * Note that the "x" in "%x0" is neccessary; writing "%0" will cause warnings. + */ +#if defined(__aarch64__) && defined(MBEDTLS_HAVE_ASM) +#if UINTPTR_MAX == 0xfffffffful +/* ILP32: Specify the pointer operand slightly differently, as per #7787. */ +#define MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT "p" +#elif UINTPTR_MAX == 0xfffffffffffffffful +/* Normal case (64-bit pointers): use "r" as the constraint for pointer operands to asm */ +#define MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT "r" +#else +#error "Unrecognised pointer size for aarch64" +#endif +#endif + +/** \def MBEDTLS_STATIC_ASSERT + * + * A static assert macro, equivalent to `static_assert` or `_Static_assert` + * in modern C. + * + * You can use `MBEDTLS_STATIC_ASSERT(expr, msg)` in any position where a + * declaration is permitted, both at the toplevel and within a function. + * This macro may not be used inside an expression (see #STATIC_ASSERT_EXPR, + * available on fewer platforms). + * + * \param expr An expression which must be a compile-time constant with + * an integer value. This doesn't have to be a preprocessor + * constant, for example it can use `sizeof`. + * The compilation fails if the value is 0. + * \param msg An error messsage to display if the value of \p expr is 0. + */ +#if __STDC_VERSION__ >= 202311L +/* static_assert is a keyword since C23 */ +#define MBEDTLS_STATIC_ASSERT(expr, msg) static_assert(expr, msg) + +#elif __STDC_VERSION__ >= 201112L +/* _Static_assert is a keyword since C11 */ +#define MBEDTLS_STATIC_ASSERT(expr, msg) _Static_assert(expr, msg) + +#elif defined(static_assert) && !defined(__STRICT_ANSI__) +/* If static_assert is defined as a macro, presumably from + * included above, then trust that it is what we expect. + * This is a common extension even before C11. + * However, don't use it if it looks like a build with `gcc -c99 -pedantic` + * or `clang -c99 -pedantic`, because they would complain about the use of + * a feature that doesn't exist in C99. + */ +#define MBEDTLS_STATIC_ASSERT(expr, msg) static_assert(expr, msg) + +#elif defined(_MSC_VER) +/* MSVC has `static_assert` as a keyword (not a macro) since + * Visual Studio 2010. + */ +#define MBEDTLS_STATIC_ASSERT(expr, msg) static_assert(expr, msg) + +#elif defined(__GNUC__) && \ + ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) && \ + !defined(__STRICT_ANSI__) +/* _Static_assert is a keyword since GCC 4.6. + * However, don't use it if it looks like a build with `gcc -c99 -pedantic` + * or `clang -c99 -pedantic`, because they would complain about the use of + * a feature that doesn't exist in C99. + */ +#define MBEDTLS_STATIC_ASSERT(expr, msg) _Static_assert(expr, msg) + +#elif defined(__COUNTER__) +/* Fall back to a hack that works in practice with non-ancient GCC-like + * compilers and MSVC, and doesn't trigger `-Wredundant-decls`. + * + * See the `#else` block below for an explanation. Here, we add another + * layer to make the declared name unique using the special preprocessor + * token `__COUNTER__`. + */ +#define MBEDTLS_STATIC_ASSERT_COUNTER(expr, counter) \ + struct mbedtls_static_assert_anchor##counter { \ + unsigned int STATIC_ASSERT : (expr) ? 1 : -1; \ + } +#define MBEDTLS_STATIC_ASSERT_WRAP(expr, counter) \ + MBEDTLS_STATIC_ASSERT_COUNTER(expr, counter) +#define MBEDTLS_STATIC_ASSERT(expr, msg) \ + MBEDTLS_STATIC_ASSERT_WRAP(expr, __COUNTER__) + +#else +/* Fall back to a hack that works in practice with almost all C compilers. + * + * Constraints: + * - Must be valid C99 when `expr` is a constant expression with a nonzero value. + * - Must compile without warnings on known compilers when `expr` is a + * constant expression with a nonzero value. + * - Must be valid both at file scope and inside a function. + * - Must allow multiple static assertions in the same scope. + * - Must not rely on `__LINE__` to create unique identifiers, since this + * could lead to collisions, e.g. if `MBEDTLS_STATIC_ASSERT` is used in + * a header, or if a macro expands to multiple uses of + * `MBEDTLS_STATIC_ASSERT`. + * - Should result in an error when `expr` evaluates to 0. + * + * How it works: + * - Ostensibly declare a function. This function will never be used, but + * declaring a function that won't be used is routine. + * - The function's name is in our namespace, so we just need to avoid that + * name for any other purpose. + * - Declaring the same function with the same prototype multiple times is + * also common (it triggers `gcc -Wredundant-decls`, but we handle + * non-ancient GCC separately above). + * - The function returns a pointer to an array. + * - The array size involves parsing an anonymous struct declaration. + * - The struct declaration contains a bit-field whose width is 1 if the + * assertion is true, and -1 otherwise. This is a constraint violation, + * requiring a diagnostic. + * + * Limitations: + * - If you have multiple static assertions in the same scope, + * `gcc -Wredundant-decls` complains. + * - When the assertion fails, some compilers complain about a negative + * bit-field width without displaying the problematic line, so the message + * is not visible. + * + * On Godbolt compiler explorer, the only failures I could find are: + * - CCC (Claude C Compiler) as of 2026-03-02 ignores the assertion. + * - Chibicc 2020-12-07 ignores the assertion. + * - LC3 (trunk) ignores the assertion. + * - MSVC warns about assertions, whether they pass or not: + * "warning C4116: unnamed type definition in parentheses" + * This doesn't matter because non-ancient MSVC supports __COUNTER__, + * which is covered above. + * - ppci 0.5.5 complains of a syntax error. + * - SDCC 4.5.0 (and earlier) complains if there are multiple assertions in + * the same scope, even if they pass: + * "extern definition for 'mbedtls_static_assert_anchor' mismatches with declaration." + * - x86 tendra (trunk) complains if there are multiple assertions in + * the same scope, even if they pass: + * " The types 'int ( * ( void ) ) []' and 'int ( * ( void ) ) []' are incompatible." + * - vast (trunk) complains about assertions at function scope, + * even if they pass: + * "unexpected error: failed to legalize operation 'll.func' that was explicitly marked illegal" + * This doesn't matter because it supports __COUNTER__, which is covered + * above. + */ +#define MBEDTLS_STATIC_ASSERT(expr, msg) \ + extern int (*mbedtls_static_assert_anchor(void))[sizeof(struct { \ + int STATIC_ASSERT : (expr) ? 1 : -1; \ + })] +#endif + +/* Define compiler branch hints */ +#if MBEDTLS_HAS_BUILTIN(__builtin_expect) +#define MBEDTLS_LIKELY(x) __builtin_expect(!!(x), 1) +#define MBEDTLS_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define MBEDTLS_LIKELY(x) x +#define MBEDTLS_UNLIKELY(x) x +#endif + +/* MBEDTLS_ASSUME may be used to provide additional information to the compiler + * which can result in smaller code-size. */ +#if MBEDTLS_HAS_BUILTIN(__builtin_assume) +/* clang provides __builtin_assume */ +#define MBEDTLS_ASSUME(x) __builtin_assume(x) +#elif MBEDTLS_HAS_BUILTIN(__builtin_unreachable) +/* gcc and IAR can use __builtin_unreachable */ +#define MBEDTLS_ASSUME(x) do { if (!(x)) __builtin_unreachable(); } while (0) +#elif defined(_MSC_VER) +/* Supported by MSVC since VS 2005 */ +#define MBEDTLS_ASSUME(x) __assume(x) +#else +#define MBEDTLS_ASSUME(x) do { } while (0) +#endif + +/* For gcc -Os, override with -O2 for a given function. + * + * This will not affect behaviour for other optimisation settings, e.g. -O0. + */ +#if defined(MBEDTLS_COMPILER_IS_GCC) && defined(__OPTIMIZE_SIZE__) +#define MBEDTLS_OPTIMIZE_FOR_PERFORMANCE __attribute__((optimize("-O2"))) +#else +#define MBEDTLS_OPTIMIZE_FOR_PERFORMANCE +#endif + +/* Suppress compiler warnings for unused functions and variables. */ +#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__has_attribute) +# if __has_attribute(unused) +# define MBEDTLS_MAYBE_UNUSED __attribute__((unused)) +# endif +#endif +#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__GNUC__) +# define MBEDTLS_MAYBE_UNUSED __attribute__((unused)) +#endif +#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__IAR_SYSTEMS_ICC__) && defined(__VER__) +/* IAR does support __attribute__((unused)), but only if the -e flag (extended language support) + * is given; the pragma always works. + * Unfortunately the pragma affects the rest of the file where it is used, but this is harmless. + * Check for version 5.2 or later - this pragma may be supported by earlier versions, but I wasn't + * able to find documentation). + */ +# if (__VER__ >= 5020000) +# define MBEDTLS_MAYBE_UNUSED _Pragma("diag_suppress=Pe177") +# endif +#endif +#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(_MSC_VER) +# define MBEDTLS_MAYBE_UNUSED __pragma(warning(suppress:4189)) +#endif +#if !defined(MBEDTLS_MAYBE_UNUSED) +# define MBEDTLS_MAYBE_UNUSED +#endif + +/* GCC >= 15 has a warning 'unterminated-string-initialization' which complains if you initialize + * a string into an array without space for a terminating NULL character. In some places in the + * codebase this behaviour is intended, so we add the macro MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING + * to suppress the warning in these places. + */ +#if defined(__has_attribute) +#if __has_attribute(nonstring) +#define MBEDTLS_HAS_ATTRIBUTE_NONSTRING +#endif /* __has_attribute(nonstring) */ +#endif /* __has_attribute */ +#if defined(MBEDTLS_HAS_ATTRIBUTE_NONSTRING) +#define MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING __attribute__((nonstring)) +#else +#define MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING +#endif /* MBEDTLS_HAS_ATTRIBUTE_NONSTRING */ + +#endif /* TF_PSA_CRYPTO_TF_PSA_CRYPTO_COMMON_H */ diff --git a/tf-psa-crypto/core/tf_psa_crypto_config.c b/tf-psa-crypto/core/tf_psa_crypto_config.c new file mode 100644 index 0000000000..95c8ae6a63 --- /dev/null +++ b/tf-psa-crypto/core/tf_psa_crypto_config.c @@ -0,0 +1,70 @@ +/* + * TF-PSA-Crypto configuration checks + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +/* Detect whether this is a normal build of the library, or a build of + * libtestdriver1, where all identifiers starting with normal prefixes + * have LIBTESTDRIVER1_ prepended. Do this without relying on + * any headers, since this has to happen before we include + * tf_psa_crypto/build_info.h. + * + * In the libtestdriver1 build, the next two code lines are + * `#define LIBTESTDRIVER_FOO 1` and + * `#if LIBTESTDRIVER_FOO == LIBTESTDRIVER_FOO` so the conditional is true. + * In a normal build, `LIBTESTDRIVER1_TF_PSA_CRYPTO_MARKER` remains + * undefined so the conditional is false. + */ +#define TF_PSA_CRYPTO_MARKER 1 +#if LIBTESTDRIVER1_TF_PSA_CRYPTO_MARKER == TF_PSA_CRYPTO_MARKER +#define TF_PSA_CRYPTO_WE_ARE_IN_LIBTESTDRIVER1 +#endif +#undef TF_PSA_CRYPTO_MARKER + +/* Completely byass generated config checks in libtestdriver1, where + * they aren't useful (when building test drivers, we can bypass + * normal configuration mechanisms if we want). + * This way we don't have to make them work. Since we bypass the + * header inclusions, the build system doesn't even need to know how + * to generate files with the right names and in the right locations. + */ +#if !defined(TF_PSA_CRYPTO_WE_ARE_IN_LIBTESTDRIVER1) +/* Consistency checks on the user's configuration. + * Check that it doesn't define macros that we assume are under full + * control of the library, or options from past major versions that + * no longer have any effect. + * These headers are automatically generated. See + * framework/scripts/mbedtls_framework/config_checks_generator.py + * + * This here is the first stage, before including the user config. + */ +#include "tf_psa_crypto_config_check_before.h" +/* The second stage, after including the user config but before doing + * any subsequent adjustment, will be included by build_info.h. */ +#define TF_PSA_CRYPTO_INCLUDE_AFTER_RAW_CONFIG "tf_psa_crypto_config_check_user.h" +#endif /* !defined(TF_PSA_CRYPTO_WE_ARE_IN_LIBTESTDRIVER1) */ + +#include + +/* Consistency checks in the configuration: check for incompatible options, + * missing options when at least one of a set needs to be enabled, etc. */ +/* Manually written checks */ +#include "tf_psa_crypto_check_config.h" + +#if !defined(TF_PSA_CRYPTO_WE_ARE_IN_LIBTESTDRIVER1) +/* Automatically generated checks (final stage after config adjustment) */ +#include "tf_psa_crypto_config_check_final.h" +#endif /* !defined(TF_PSA_CRYPTO_WE_ARE_IN_LIBTESTDRIVER1) */ + +/* For MBEDTLS_STATIC_ASSERT */ +#include "tf_psa_crypto_common.h" +/* For PSA_HASH_LENGTH */ +#include + +/* Additional domain-specific checks */ +#if defined(MBEDTLS_PSA_CRYPTO_C) +#include "psa_crypto_random_impl.h" +#endif diff --git a/tf-psa-crypto/core/tf_psa_crypto_config_check_before.h b/tf-psa-crypto/core/tf_psa_crypto_config_check_before.h new file mode 100644 index 0000000000..cdf68fac54 --- /dev/null +++ b/tf-psa-crypto/core/tf_psa_crypto_config_check_before.h @@ -0,0 +1,12 @@ +/* tf_psa_crypto_config_check_before.h (generated part of tf_psa_crypto_config.c). */ +/* Automatically generated by generate_config_checks.py. Do not edit! */ + +#if !defined(TF_PSA_CRYPTO_CONFIG_CHECK_BYPASS) //no-check-names + +/* *INDENT-OFF* */ + +/* *INDENT-ON* */ + +#endif /* !defined(TF_PSA_CRYPTO_CONFIG_CHECK_BYPASS) */ //no-check-names + +/* End of automatically generated tf_psa_crypto_config_check_before.h */ diff --git a/tf-psa-crypto/core/tf_psa_crypto_config_check_final.h b/tf-psa-crypto/core/tf_psa_crypto_config_check_final.h new file mode 100644 index 0000000000..2fe4855d91 --- /dev/null +++ b/tf-psa-crypto/core/tf_psa_crypto_config_check_final.h @@ -0,0 +1,12 @@ +/* tf_psa_crypto_config_check_final.h (generated part of tf_psa_crypto_config.c). */ +/* Automatically generated by generate_config_checks.py. Do not edit! */ + +#if !defined(TF_PSA_CRYPTO_CONFIG_CHECK_BYPASS) //no-check-names + +/* *INDENT-OFF* */ + +/* *INDENT-ON* */ + +#endif /* !defined(TF_PSA_CRYPTO_CONFIG_CHECK_BYPASS) */ //no-check-names + +/* End of automatically generated tf_psa_crypto_config_check_final.h */ diff --git a/tf-psa-crypto/core/tf_psa_crypto_config_check_user.h b/tf-psa-crypto/core/tf_psa_crypto_config_check_user.h new file mode 100644 index 0000000000..56cb4543d4 --- /dev/null +++ b/tf-psa-crypto/core/tf_psa_crypto_config_check_user.h @@ -0,0 +1,1216 @@ +/* tf_psa_crypto_config_check_user.h (generated part of tf_psa_crypto_config.c). */ +/* Automatically generated by generate_config_checks.py. Do not edit! */ + +#if !defined(TF_PSA_CRYPTO_CONFIG_CHECK_BYPASS) //no-check-names + +/* *INDENT-OFF* */ + +#if defined(MBEDTLS_AES_ALT) //no-check-names +# error "MBEDTLS_AES_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_AES_C) //no-check-names +# error "MBEDTLS_AES_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_AES_DECRYPT_ALT) //no-check-names +# error "MBEDTLS_AES_DECRYPT_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_AES_ENCRYPT_ALT) //no-check-names +# error "MBEDTLS_AES_ENCRYPT_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_AES_SETKEY_DEC_ALT) //no-check-names +# error "MBEDTLS_AES_SETKEY_DEC_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_AES_SETKEY_ENC_ALT) //no-check-names +# error "MBEDTLS_AES_SETKEY_ENC_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ARIA_ALT) //no-check-names +# error "MBEDTLS_ARIA_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ARIA_C) //no-check-names +# error "MBEDTLS_ARIA_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_BIGNUM_C) //no-check-names +# error "MBEDTLS_BIGNUM_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CAMELLIA_ALT) //no-check-names +# error "MBEDTLS_CAMELLIA_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CAMELLIA_C) //no-check-names +# error "MBEDTLS_CAMELLIA_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CCM_ALT) //no-check-names +# error "MBEDTLS_CCM_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CCM_C) //no-check-names +# error "MBEDTLS_CCM_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CHACHA20_ALT) //no-check-names +# error "MBEDTLS_CHACHA20_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CHACHA20_C) //no-check-names +# error "MBEDTLS_CHACHA20_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CHACHAPOLY_ALT) //no-check-names +# error "MBEDTLS_CHACHAPOLY_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) //no-check-names +# error "MBEDTLS_CHACHAPOLY_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CIPHER_C) //no-check-names +# error "MBEDTLS_CIPHER_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CBC) //no-check-names +# error "MBEDTLS_CIPHER_MODE_CBC was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CFB) //no-check-names +# error "MBEDTLS_CIPHER_MODE_CFB was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CTR) //no-check-names +# error "MBEDTLS_CIPHER_MODE_CTR was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CIPHER_MODE_OFB) //no-check-names +# error "MBEDTLS_CIPHER_MODE_OFB was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CIPHER_MODE_XTS) //no-check-names +# error "MBEDTLS_CIPHER_MODE_XTS was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) //no-check-names +# error "MBEDTLS_CIPHER_NULL_CIPHER was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) //no-check-names +# error "MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) //no-check-names +# error "MBEDTLS_CIPHER_PADDING_PKCS7 was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS) //no-check-names +# error "MBEDTLS_CIPHER_PADDING_ZEROS was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) //no-check-names +# error "MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CMAC_ALT) //no-check-names +# error "MBEDTLS_CMAC_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CMAC_C) //no-check-names +# error "MBEDTLS_CMAC_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) //no-check-names +# error "MBEDTLS_CTR_DRBG_ENTROPY_LEN was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CTR_DRBG_MAX_INPUT) //no-check-names +# error "MBEDTLS_CTR_DRBG_MAX_INPUT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CTR_DRBG_MAX_REQUEST) //no-check-names +# error "MBEDTLS_CTR_DRBG_MAX_REQUEST was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) //no-check-names +# error "MBEDTLS_CTR_DRBG_MAX_SEED_INPUT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CTR_DRBG_RESEED_INTERVAL) //no-check-names +# error "MBEDTLS_CTR_DRBG_RESEED_INTERVAL was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY) //no-check-names +# error "MBEDTLS_CTR_DRBG_USE_128_BIT_KEY was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_DES3_CRYPT_ECB_ALT) //no-check-names +# error "MBEDTLS_DES3_CRYPT_ECB_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_DES_ALT) //no-check-names +# error "MBEDTLS_DES_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_DES_C) //no-check-names +# error "MBEDTLS_DES_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_DES_CRYPT_ECB_ALT) //no-check-names +# error "MBEDTLS_DES_CRYPT_ECB_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_DES_SETKEY_ALT) //no-check-names +# error "MBEDTLS_DES_SETKEY_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_DHM_ALT) //no-check-names +# error "MBEDTLS_DHM_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_DHM_C) //no-check-names +# error "MBEDTLS_DHM_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECDH_C) //no-check-names +# error "MBEDTLS_ECDH_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT) //no-check-names +# error "MBEDTLS_ECDH_COMPUTE_SHARED_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT) //no-check-names +# error "MBEDTLS_ECDH_GEN_PUBLIC_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECDSA_C) //no-check-names +# error "MBEDTLS_ECDSA_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) //no-check-names +# error "MBEDTLS_ECDSA_DETERMINISTIC was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECDSA_GENKEY_ALT) //no-check-names +# error "MBEDTLS_ECDSA_GENKEY_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECDSA_SIGN_ALT) //no-check-names +# error "MBEDTLS_ECDSA_SIGN_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECDSA_VERIFY_ALT) //no-check-names +# error "MBEDTLS_ECDSA_VERIFY_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECJPAKE_ALT) //no-check-names +# error "MBEDTLS_ECJPAKE_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECJPAKE_C) //no-check-names +# error "MBEDTLS_ECJPAKE_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_ADD_MIXED_ALT) //no-check-names +# error "MBEDTLS_ECP_ADD_MIXED_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_ALT) //no-check-names +# error "MBEDTLS_ECP_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_C) //no-check-names +# error "MBEDTLS_ECP_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) //no-check-names +# error "MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) //no-check-names +# error "MBEDTLS_ECP_DOUBLE_JAC_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) //no-check-names +# error "MBEDTLS_ECP_DP_BP256R1_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) //no-check-names +# error "MBEDTLS_ECP_DP_BP384R1_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) //no-check-names +# error "MBEDTLS_ECP_DP_BP512R1_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) //no-check-names +# error "MBEDTLS_ECP_DP_CURVE25519_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) //no-check-names +# error "MBEDTLS_ECP_DP_CURVE448_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) //no-check-names +# error "MBEDTLS_ECP_DP_SECP192K1_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) //no-check-names +# error "MBEDTLS_ECP_DP_SECP192R1_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) //no-check-names +# error "MBEDTLS_ECP_DP_SECP224K1_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) //no-check-names +# error "MBEDTLS_ECP_DP_SECP224R1_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) //no-check-names +# error "MBEDTLS_ECP_DP_SECP256K1_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) //no-check-names +# error "MBEDTLS_ECP_DP_SECP256R1_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) //no-check-names +# error "MBEDTLS_ECP_DP_SECP384R1_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) //no-check-names +# error "MBEDTLS_ECP_DP_SECP521R1_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_INTERNAL_ALT) //no-check-names +# error "MBEDTLS_ECP_INTERNAL_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) //no-check-names +# error "MBEDTLS_ECP_NORMALIZE_JAC_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) //no-check-names +# error "MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) //no-check-names +# error "MBEDTLS_ECP_NORMALIZE_MXZ_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_NO_FALLBACK) //no-check-names +# error "MBEDTLS_ECP_NO_FALLBACK was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) //no-check-names +# error "MBEDTLS_ECP_RANDOMIZE_JAC_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) //no-check-names +# error "MBEDTLS_ECP_RANDOMIZE_MXZ_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ENTROPY_C) //no-check-names +# error "MBEDTLS_ENTROPY_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ENTROPY_FORCE_SHA256) //no-check-names +# error "MBEDTLS_ENTROPY_FORCE_SHA256 was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) //no-check-names +# error "MBEDTLS_ENTROPY_HARDWARE_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ENTROPY_MAX_GATHER) //no-check-names +# error "MBEDTLS_ENTROPY_MAX_GATHER was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ENTROPY_MAX_SOURCES) //no-check-names +# error "MBEDTLS_ENTROPY_MAX_SOURCES was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_ENTROPY_MIN_HARDWARE) //no-check-names +# error "MBEDTLS_ENTROPY_MIN_HARDWARE was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_GCM_ALT) //no-check-names +# error "MBEDTLS_GCM_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_GCM_C) //no-check-names +# error "MBEDTLS_GCM_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_GENPRIME) //no-check-names +# error "MBEDTLS_GENPRIME was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_HKDF_C) //no-check-names +# error "MBEDTLS_HKDF_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_HMAC_DRBG_MAX_INPUT) //no-check-names +# error "MBEDTLS_HMAC_DRBG_MAX_INPUT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_HMAC_DRBG_MAX_REQUEST) //no-check-names +# error "MBEDTLS_HMAC_DRBG_MAX_REQUEST was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT) //no-check-names +# error "MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_HMAC_DRBG_RESEED_INTERVAL) //no-check-names +# error "MBEDTLS_HMAC_DRBG_RESEED_INTERVAL was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) //no-check-names +# error "MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) //no-check-names +# error "MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) //no-check-names +# error "MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) //no-check-names +# error "MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) //no-check-names +# error "MBEDTLS_KEY_EXCHANGE_RSA_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) //no-check-names +# error "MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_MD5_ALT) //no-check-names +# error "MBEDTLS_MD5_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_MD5_C) //no-check-names +# error "MBEDTLS_MD5_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_MD5_PROCESS_ALT) //no-check-names +# error "MBEDTLS_MD5_PROCESS_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_NIST_KW_ALT) //no-check-names +# error "MBEDTLS_NIST_KW_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) //no-check-names +# error "MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_NO_PLATFORM_ENTROPY) //no-check-names +# error "MBEDTLS_NO_PLATFORM_ENTROPY was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_OID_C) //no-check-names +# error "MBEDTLS_OID_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_PADLOCK_C) //no-check-names +# error "MBEDTLS_PADLOCK_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_PKCS12_C) //no-check-names +# error "MBEDTLS_PKCS12_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_PKCS1_V15) //no-check-names +# error "MBEDTLS_PKCS1_V15 was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_PKCS1_V21) //no-check-names +# error "MBEDTLS_PKCS1_V21 was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) //no-check-names +# error "MBEDTLS_PK_RSA_ALT_SUPPORT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_POLY1305_ALT) //no-check-names +# error "MBEDTLS_POLY1305_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_POLY1305_C) //no-check-names +# error "MBEDTLS_POLY1305_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_PSA_CRYPTO_CONFIG_FILE) //no-check-names +# error "MBEDTLS_PSA_CRYPTO_CONFIG_FILE was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_PSA_CRYPTO_SE_C) //no-check-names +# error "MBEDTLS_PSA_CRYPTO_SE_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE) //no-check-names +# error "MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE) //no-check-names +# error "MBEDTLS_PSA_HMAC_DRBG_MD_TYPE was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_PSA_INJECT_ENTROPY) //no-check-names +# error "MBEDTLS_PSA_INJECT_ENTROPY was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_RIPEMD160_ALT) //no-check-names +# error "MBEDTLS_RIPEMD160_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_RIPEMD160_C) //no-check-names +# error "MBEDTLS_RIPEMD160_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_RIPEMD160_PROCESS_ALT) //no-check-names +# error "MBEDTLS_RIPEMD160_PROCESS_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_RSA_ALT) //no-check-names +# error "MBEDTLS_RSA_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_RSA_C) //no-check-names +# error "MBEDTLS_RSA_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_SHA1_ALT) //no-check-names +# error "MBEDTLS_SHA1_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_SHA1_C) //no-check-names +# error "MBEDTLS_SHA1_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_SHA1_PROCESS_ALT) //no-check-names +# error "MBEDTLS_SHA1_PROCESS_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_SHA224_C) //no-check-names +# error "MBEDTLS_SHA224_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_SHA256_ALT) //no-check-names +# error "MBEDTLS_SHA256_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_SHA256_C) //no-check-names +# error "MBEDTLS_SHA256_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_SHA256_PROCESS_ALT) //no-check-names +# error "MBEDTLS_SHA256_PROCESS_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT) //no-check-names +# error "MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY) //no-check-names +# error "MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_SHA384_C) //no-check-names +# error "MBEDTLS_SHA384_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_SHA3_C) //no-check-names +# error "MBEDTLS_SHA3_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_SHA512_ALT) //no-check-names +# error "MBEDTLS_SHA512_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_SHA512_C) //no-check-names +# error "MBEDTLS_SHA512_C was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_SHA512_PROCESS_ALT) //no-check-names +# error "MBEDTLS_SHA512_PROCESS_ALT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME) //no-check-names +# error "MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT) //no-check-names +# error "MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(PSA_WANT_ECC_SECP_K1_192) //no-check-names +# error "PSA_WANT_ECC_SECP_K1_192 was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(PSA_WANT_ECC_SECP_R1_192) //no-check-names +# error "PSA_WANT_ECC_SECP_R1_192 was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(PSA_WANT_ECC_SECP_R1_224) //no-check-names +# error "PSA_WANT_ECC_SECP_R1_224 was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(PSA_WANT_KEY_TYPE_DES) //no-check-names +# error "PSA_WANT_KEY_TYPE_DES was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR) //no-check-names +# error "PSA_WANT_KEY_TYPE_ECC_KEY_PAIR was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR) //no-check-names +# error "PSA_WANT_KEY_TYPE_RSA_KEY_PAIR was removed in TF-PSA_Crypto 1.0." //no-check-names +#endif + +#if defined(MBEDTLS_BLOCK_CIPHER_AES_VIA_LEGACY) +# error "MBEDTLS_BLOCK_CIPHER_AES_VIA_LEGACY is not a valid configuration option." +#endif + +#if defined(MBEDTLS_BLOCK_CIPHER_AES_VIA_PSA) +# error "MBEDTLS_BLOCK_CIPHER_AES_VIA_PSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_BLOCK_CIPHER_ARIA_VIA_LEGACY) +# error "MBEDTLS_BLOCK_CIPHER_ARIA_VIA_LEGACY is not a valid configuration option." +#endif + +#if defined(MBEDTLS_BLOCK_CIPHER_ARIA_VIA_PSA) +# error "MBEDTLS_BLOCK_CIPHER_ARIA_VIA_PSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_BLOCK_CIPHER_C) +# error "MBEDTLS_BLOCK_CIPHER_C is not a valid configuration option." +#endif + +#if defined(MBEDTLS_BLOCK_CIPHER_CAMELLIA_VIA_LEGACY) +# error "MBEDTLS_BLOCK_CIPHER_CAMELLIA_VIA_LEGACY is not a valid configuration option." +#endif + +#if defined(MBEDTLS_BLOCK_CIPHER_CAMELLIA_VIA_PSA) +# error "MBEDTLS_BLOCK_CIPHER_CAMELLIA_VIA_PSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_BLOCK_CIPHER_CAN_AES) +# error "MBEDTLS_BLOCK_CIPHER_CAN_AES is not a valid configuration option." +#endif + +#if defined(MBEDTLS_BLOCK_CIPHER_CAN_ARIA) +# error "MBEDTLS_BLOCK_CIPHER_CAN_ARIA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_BLOCK_CIPHER_CAN_CAMELLIA) +# error "MBEDTLS_BLOCK_CIPHER_CAN_CAMELLIA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA) +# error "MBEDTLS_BLOCK_CIPHER_SOME_PSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_CAN_ECDH) +# error "MBEDTLS_CAN_ECDH is not a valid configuration option." +#endif + +#if defined(MBEDTLS_CCM_GCM_CAN_AES) +# error "MBEDTLS_CCM_GCM_CAN_AES is not a valid configuration option." +#endif + +#if defined(MBEDTLS_CCM_GCM_CAN_ARIA) +# error "MBEDTLS_CCM_GCM_CAN_ARIA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_CCM_GCM_CAN_CAMELLIA) +# error "MBEDTLS_CCM_GCM_CAN_CAMELLIA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_ECP_LIGHT) +# error "MBEDTLS_ECP_LIGHT is not a valid configuration option." +#endif + +#if defined(MBEDTLS_ENTROPY_HAVE_SOURCES) +# error "MBEDTLS_ENTROPY_HAVE_SOURCES is not a valid configuration option." +#endif + +#if defined(MBEDTLS_ENTROPY_TRUE_SOURCES) +# error "MBEDTLS_ENTROPY_TRUE_SOURCES is not a valid configuration option." +#endif + +#if defined(MBEDTLS_MD_LIGHT) +# error "MBEDTLS_MD_LIGHT is not a valid configuration option." +#endif + +#if defined(MBEDTLS_MD_MD5_VIA_PSA) +# error "MBEDTLS_MD_MD5_VIA_PSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_MD_RIPEMD160_VIA_PSA) +# error "MBEDTLS_MD_RIPEMD160_VIA_PSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_MD_SHA1_VIA_PSA) +# error "MBEDTLS_MD_SHA1_VIA_PSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_MD_SHA224_VIA_PSA) +# error "MBEDTLS_MD_SHA224_VIA_PSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_MD_SHA256_VIA_PSA) +# error "MBEDTLS_MD_SHA256_VIA_PSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_MD_SHA384_VIA_PSA) +# error "MBEDTLS_MD_SHA384_VIA_PSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_MD_SHA3_224_VIA_PSA) +# error "MBEDTLS_MD_SHA3_224_VIA_PSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_MD_SHA3_256_VIA_PSA) +# error "MBEDTLS_MD_SHA3_256_VIA_PSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_MD_SHA3_384_VIA_PSA) +# error "MBEDTLS_MD_SHA3_384_VIA_PSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_MD_SHA3_512_VIA_PSA) +# error "MBEDTLS_MD_SHA3_512_VIA_PSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_MD_SHA512_VIA_PSA) +# error "MBEDTLS_MD_SHA512_VIA_PSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_MD_SOME_LEGACY) +# error "MBEDTLS_MD_SOME_LEGACY is not a valid configuration option." +#endif + +#if defined(MBEDTLS_MD_SOME_PSA) +# error "MBEDTLS_MD_SOME_PSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_NO_PADDING) +# error "MBEDTLS_PSA_BUILTIN_ALG_CBC_NO_PADDING is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_PKCS7) +# error "MBEDTLS_PSA_BUILTIN_ALG_CBC_PKCS7 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) +# error "MBEDTLS_PSA_BUILTIN_ALG_CCM is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM_STAR_NO_TAG) +# error "MBEDTLS_PSA_BUILTIN_ALG_CCM_STAR_NO_TAG is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CFB) +# error "MBEDTLS_PSA_BUILTIN_ALG_CFB is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) +# error "MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC) +# error "MBEDTLS_PSA_BUILTIN_ALG_CMAC is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CTR) +# error "MBEDTLS_PSA_BUILTIN_ALG_CTR is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) +# error "MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING) +# error "MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) +# error "MBEDTLS_PSA_BUILTIN_ALG_ECDH is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) +# error "MBEDTLS_PSA_BUILTIN_ALG_ECDSA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_FFDH) +# error "MBEDTLS_PSA_BUILTIN_ALG_FFDH is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) +# error "MBEDTLS_PSA_BUILTIN_ALG_GCM is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF) +# error "MBEDTLS_PSA_BUILTIN_ALG_HKDF is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND) +# error "MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT) +# error "MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC) +# error "MBEDTLS_PSA_BUILTIN_ALG_HMAC is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE) +# error "MBEDTLS_PSA_BUILTIN_ALG_JPAKE is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_MD5) +# error "MBEDTLS_PSA_BUILTIN_ALG_MD5 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_OFB) +# error "MBEDTLS_PSA_BUILTIN_ALG_OFB is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_AES_CMAC_PRF_128) +# error "MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_AES_CMAC_PRF_128 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC) +# error "MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RIPEMD160) +# error "MBEDTLS_PSA_BUILTIN_ALG_RIPEMD160 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) +# error "MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) +# error "MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) +# error "MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS) +# error "MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) +# error "MBEDTLS_PSA_BUILTIN_ALG_SHA3_224 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) +# error "MBEDTLS_PSA_BUILTIN_ALG_SHA3_256 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) +# error "MBEDTLS_PSA_BUILTIN_ALG_SHA3_384 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512) +# error "MBEDTLS_PSA_BUILTIN_ALG_SHA3_512 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_SOME_HASH) +# error "MBEDTLS_PSA_BUILTIN_ALG_SHA3_SOME_HASH is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHAKE128) +# error "MBEDTLS_PSA_BUILTIN_ALG_SHAKE128 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHAKE256) +# error "MBEDTLS_PSA_BUILTIN_ALG_SHAKE256 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_1) +# error "MBEDTLS_PSA_BUILTIN_ALG_SHA_1 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_224) +# error "MBEDTLS_PSA_BUILTIN_ALG_SHA_224 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_256) +# error "MBEDTLS_PSA_BUILTIN_ALG_SHA_256 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_384) +# error "MBEDTLS_PSA_BUILTIN_ALG_SHA_384 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_512) +# error "MBEDTLS_PSA_BUILTIN_ALG_SHA_512 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SOME_SHAKE) +# error "MBEDTLS_PSA_BUILTIN_ALG_SOME_SHAKE is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_STREAM_CIPHER) +# error "MBEDTLS_PSA_BUILTIN_ALG_STREAM_CIPHER is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS) +# error "MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) +# error "MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) +# error "MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_XTS) +# error "MBEDTLS_PSA_BUILTIN_ALG_XTS is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_DH_RFC7919_2048) +# error "MBEDTLS_PSA_BUILTIN_DH_RFC7919_2048 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_DH_RFC7919_3072) +# error "MBEDTLS_PSA_BUILTIN_DH_RFC7919_3072 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_DH_RFC7919_4096) +# error "MBEDTLS_PSA_BUILTIN_DH_RFC7919_4096 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_DH_RFC7919_6144) +# error "MBEDTLS_PSA_BUILTIN_DH_RFC7919_6144 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_DH_RFC7919_8192) +# error "MBEDTLS_PSA_BUILTIN_DH_RFC7919_8192 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ECC_BRAINPOOL_P_R1_256) +# error "MBEDTLS_PSA_BUILTIN_ECC_BRAINPOOL_P_R1_256 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ECC_BRAINPOOL_P_R1_384) +# error "MBEDTLS_PSA_BUILTIN_ECC_BRAINPOOL_P_R1_384 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ECC_BRAINPOOL_P_R1_512) +# error "MBEDTLS_PSA_BUILTIN_ECC_BRAINPOOL_P_R1_512 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_255) +# error "MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_255 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_448) +# error "MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_448 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ECC_SECP_K1_256) +# error "MBEDTLS_PSA_BUILTIN_ECC_SECP_K1_256 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_256) +# error "MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_256 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_384) +# error "MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_384 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_521) +# error "MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_521 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_GET_ENTROPY_DEFINED) +# error "MBEDTLS_PSA_BUILTIN_GET_ENTROPY_DEFINED is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_AES) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_AES is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ARIA) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_ARIA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_CAMELLIA) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_CAMELLIA is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_CHACHA20) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_CHACHA20 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_BASIC) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_BASIC is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_EXPORT) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_EXPORT is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_GENERATE) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_GENERATE is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_IMPORT) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_IMPORT is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_PUBLIC_KEY) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_PUBLIC_KEY is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_BASIC) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_BASIC is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_DERIVE) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_DERIVE is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_BASIC) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_BASIC is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_IMPORT) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_IMPORT is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) +# error "MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_PAKE) +# error "MBEDTLS_PSA_BUILTIN_PAKE is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_ALGS) +# error "MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_ALGS is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_GROUPS) +# error "MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_GROUPS is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_KEY_TYPES) +# error "MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_KEY_TYPES is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_DRIVER_GET_ENTROPY_DEFINED) +# error "MBEDTLS_PSA_DRIVER_GET_ENTROPY_DEFINED is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_ALGS) +# error "MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_ALGS is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_CURVES) +# error "MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_CURVES is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES) +# error "MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES_BASIC) +# error "MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES_BASIC is not a valid configuration option." +#endif + +#if defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_WEIERSTRASS_CURVES) +# error "MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_WEIERSTRASS_CURVES is not a valid configuration option." +#endif + +#if defined(MBEDTLS_SHA3_WANT_SHAKE128) +# error "MBEDTLS_SHA3_WANT_SHAKE128 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_SHA3_WANT_SHAKE256) +# error "MBEDTLS_SHA3_WANT_SHAKE256 is not a valid configuration option." +#endif + +#if defined(MBEDTLS_SSL_HAVE_AEAD) +# error "MBEDTLS_SSL_HAVE_AEAD is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_ALG_ECDSA_SIGN) +# error "PSA_HAVE_ALG_ECDSA_SIGN is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_ALG_ECDSA_VERIFY) +# error "PSA_HAVE_ALG_ECDSA_VERIFY is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_ALG_RSA_PKCS1V15_SIGN) +# error "PSA_HAVE_ALG_RSA_PKCS1V15_SIGN is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY) +# error "PSA_HAVE_ALG_RSA_PKCS1V15_VERIFY is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_ALG_RSA_PSS_SIGN) +# error "PSA_HAVE_ALG_RSA_PSS_SIGN is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_ALG_RSA_PSS_VERIFY) +# error "PSA_HAVE_ALG_RSA_PSS_VERIFY is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_ALG_SOME_ECDSA) +# error "PSA_HAVE_ALG_SOME_ECDSA is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_ALG_SOME_RSA_SIGN) +# error "PSA_HAVE_ALG_SOME_RSA_SIGN is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_ALG_SOME_RSA_SIGN_OR_VERIFY) +# error "PSA_HAVE_ALG_SOME_RSA_SIGN_OR_VERIFY is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_ALG_SOME_RSA_VERIFY) +# error "PSA_HAVE_ALG_SOME_RSA_VERIFY is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_SOFT_BLOCK_CIPHER) +# error "PSA_HAVE_SOFT_BLOCK_CIPHER is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_SOFT_BLOCK_MODE) +# error "PSA_HAVE_SOFT_BLOCK_MODE is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_SOFT_KEY_TYPE_AES) +# error "PSA_HAVE_SOFT_KEY_TYPE_AES is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_SOFT_KEY_TYPE_ARIA) +# error "PSA_HAVE_SOFT_KEY_TYPE_ARIA is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_SOFT_KEY_TYPE_CAMELLIA) +# error "PSA_HAVE_SOFT_KEY_TYPE_CAMELLIA is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_SOFT_PBKDF2) +# error "PSA_HAVE_SOFT_PBKDF2 is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_SOFT_PBKDF2_CMAC) +# error "PSA_HAVE_SOFT_PBKDF2_CMAC is not a valid configuration option." +#endif + +#if defined(PSA_HAVE_SOFT_PBKDF2_HMAC) +# error "PSA_HAVE_SOFT_PBKDF2_HMAC is not a valid configuration option." +#endif + +#if defined(PSA_WANT_ALG_ECDSA_ANY) +# error "PSA_WANT_ALG_ECDSA_ANY is not a valid configuration option." +#endif + +#if defined(PSA_WANT_ALG_RSA_PKCS1V15_SIGN_RAW) +# error "PSA_WANT_ALG_RSA_PKCS1V15_SIGN_RAW is not a valid configuration option." +#endif + +#if defined(PSA_WANT_ALG_RSA_PSS_ANY_SALT) +# error "PSA_WANT_ALG_RSA_PSS_ANY_SALT is not a valid configuration option." +#endif + +#if defined(PSA_WANT_ALG_SOME_PAKE) +# error "PSA_WANT_ALG_SOME_PAKE is not a valid configuration option." +#endif + +#if defined(TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CONFIG_ADJUST_TEST_ACCELERATORS_H) +# error "TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CONFIG_ADJUST_TEST_ACCELERATORS_H is not a valid configuration option." +#endif + +#if defined(TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_ADJUST_CONFIG_ENABLE_BUILTINS_H) +# error "TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_ADJUST_CONFIG_ENABLE_BUILTINS_H is not a valid configuration option." +#endif + +#if defined(TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_ADJUST_CONFIG_TWEAK_BUILTINS_H) +# error "TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_ADJUST_CONFIG_TWEAK_BUILTINS_H is not a valid configuration option." +#endif + +#if defined(TF_PSA_CRYPTO_PRIVATE_CRYPTO_ADJUST_CONFIG_AUTO_ENABLED_H) +# error "TF_PSA_CRYPTO_PRIVATE_CRYPTO_ADJUST_CONFIG_AUTO_ENABLED_H is not a valid configuration option." +#endif + +#if defined(TF_PSA_CRYPTO_PRIVATE_CRYPTO_ADJUST_CONFIG_DEPENDENCIES_H) +# error "TF_PSA_CRYPTO_PRIVATE_CRYPTO_ADJUST_CONFIG_DEPENDENCIES_H is not a valid configuration option." +#endif + +#if defined(TF_PSA_CRYPTO_PRIVATE_CRYPTO_ADJUST_CONFIG_DERIVED_H) +# error "TF_PSA_CRYPTO_PRIVATE_CRYPTO_ADJUST_CONFIG_DERIVED_H is not a valid configuration option." +#endif + +#if defined(TF_PSA_CRYPTO_PRIVATE_CRYPTO_ADJUST_CONFIG_KEY_PAIR_TYPES_H) +# error "TF_PSA_CRYPTO_PRIVATE_CRYPTO_ADJUST_CONFIG_KEY_PAIR_TYPES_H is not a valid configuration option." +#endif + +#if defined(TF_PSA_CRYPTO_PRIVATE_CRYPTO_ADJUST_CONFIG_SUPPORT_H) +# error "TF_PSA_CRYPTO_PRIVATE_CRYPTO_ADJUST_CONFIG_SUPPORT_H is not a valid configuration option." +#endif + +#if defined(TF_PSA_CRYPTO_PRIVATE_CRYPTO_ADJUST_CONFIG_SYNONYMS_H) +# error "TF_PSA_CRYPTO_PRIVATE_CRYPTO_ADJUST_CONFIG_SYNONYMS_H is not a valid configuration option." +#endif + +/* *INDENT-ON* */ + +#endif /* !defined(TF_PSA_CRYPTO_CONFIG_CHECK_BYPASS) */ //no-check-names + +/* End of automatically generated tf_psa_crypto_config_check_user.h */ diff --git a/tf-psa-crypto/core/tf_psa_crypto_platform_requirements.h b/tf-psa-crypto/core/tf_psa_crypto_platform_requirements.h new file mode 100644 index 0000000000..4acb758d4f --- /dev/null +++ b/tf-psa-crypto/core/tf_psa_crypto_platform_requirements.h @@ -0,0 +1,62 @@ +/** + * \file tf_psa_crypto_platform_requirements.h + * + * \brief Declare macros that tell system headers what we expect of them. + * + * This file must be included before any system header, and so in particular + * before build_info.h (which includes the user config, which may include + * system headers). + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_TF_PSA_CRYPTO_PLATFORM_REQUIREMENTS_H +#define TF_PSA_CRYPTO_TF_PSA_CRYPTO_PLATFORM_REQUIREMENTS_H + +#ifndef __STDC_WANT_LIB_EXT1__ +/* Ask for the C11 gmtime_s() and memset_s() if available */ +#define __STDC_WANT_LIB_EXT1__ 1 +#endif + +#if !defined(_POSIX_C_SOURCE) +/* For standards-compliant access to + * clock_gettime(), gmtime_r(), ... + */ +#define _POSIX_C_SOURCE 200112L +#endif + +/* With GNU libc, define all the things, even when compiling with -pedantic. */ +#if !defined(_GNU_SOURCE) +#define _GNU_SOURCE +#endif + +/* On NetBSD, needed to include , which we do in platform_util.c + * to get sysctl() and KERN_ARND. */ +#if defined(__NetBSD__) && !defined(_NETBSD_SOURCE) +#define _NETBSD_SOURCE +#endif + +/* On OpenBSD, needed to make declare explicit_bzero() + * ( doesn't declare it). Not used on FreeBSD or NetBSD, + * but causes Glibc to complain. */ +#if defined(__OpenBSD__) && !defined(_BSD_SOURCE) +#define _BSD_SOURCE +#endif + +/* On Mingw-w64, force the use of a C99-compliant printf() and friends. + * This is necessary on older versions of Mingw and/or Windows runtimes + * where snprintf does not always zero-terminate the buffer, and does + * not support formats such as "%zu" for size_t and "%lld" for long long. + * + * Defining __USE_MINGW_ANSI_STDIO=0 may work and provide a small code size + * and performance benefit for some combinations of older Mingw and Windows + * versions. Do this at your own risk and make sure that least + * test_suite_platform_printf passes. + */ +#if !defined(__USE_MINGW_ANSI_STDIO) +#define __USE_MINGW_ANSI_STDIO 1 +#endif + +#endif /* TF_PSA_CRYPTO_TF_PSA_CRYPTO_PLATFORM_REQUIREMENTS_H */ diff --git a/tf-psa-crypto/core/tf_psa_crypto_version.c b/tf-psa-crypto/core/tf_psa_crypto_version.c new file mode 100644 index 0000000000..c8af5c09a1 --- /dev/null +++ b/tf-psa-crypto/core/tf_psa_crypto_version.c @@ -0,0 +1,28 @@ +/* + * Version information + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(TF_PSA_CRYPTO_VERSION) +#include "tf-psa-crypto/version.h" + +unsigned int tf_psa_crypto_version_get_number(void) +{ + return TF_PSA_CRYPTO_VERSION_NUMBER; +} + +const char *tf_psa_crypto_version_get_string(void) +{ + return TF_PSA_CRYPTO_VERSION_STRING; +} + +const char *tf_psa_crypto_version_get_string_full(void) +{ + return TF_PSA_CRYPTO_VERSION_STRING_FULL; +} + +#endif /* TF_PSA_CRYPTO_VERSION */ diff --git a/tf-psa-crypto/dco.txt b/tf-psa-crypto/dco.txt new file mode 100644 index 0000000000..8201f99215 --- /dev/null +++ b/tf-psa-crypto/dco.txt @@ -0,0 +1,37 @@ +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +1 Letterman Drive +Suite D4700 +San Francisco, CA, 94129 + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. diff --git a/tf-psa-crypto/dispatch/psa_crypto_driver_wrappers_no_static.h b/tf-psa-crypto/dispatch/psa_crypto_driver_wrappers_no_static.h new file mode 100644 index 0000000000..78a0c464ff --- /dev/null +++ b/tf-psa-crypto/dispatch/psa_crypto_driver_wrappers_no_static.h @@ -0,0 +1,31 @@ +/* + * Function signatures for functionality that can be provided by + * cryptographic accelerators. + */ +/* Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_DRIVER_WRAPPERS_NO_STATIC_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_DRIVER_WRAPPERS_NO_STATIC_H + +#include "psa/crypto.h" +#include "psa/crypto_driver_common.h" + +psa_status_t psa_driver_wrapper_export_public_key( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + uint8_t *data, size_t data_size, size_t *data_length); + +psa_status_t psa_driver_wrapper_get_key_buffer_size( + const psa_key_attributes_t *attributes, + size_t *key_buffer_size); + +psa_status_t psa_driver_wrapper_get_builtin_key( + psa_drv_slot_number_t slot_number, + psa_key_attributes_t *attributes, + uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length); + +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_DRIVER_WRAPPERS_NO_STATIC_H */ + +/* End of automatically generated file. */ diff --git a/tf-psa-crypto/docs/1.0-migration-guide.md b/tf-psa-crypto/docs/1.0-migration-guide.md new file mode 100644 index 0000000000..1e514f4728 --- /dev/null +++ b/tf-psa-crypto/docs/1.0-migration-guide.md @@ -0,0 +1,1076 @@ +# Migrating from Mbed TLS 3.x to TF-PSA-Crypto 1.0 + +This guide details the steps required to migrate from Mbed TLS version 3.x to +TF-PSA-Crypto version 1.0 or greater. TF-PSA-Crypto 1.0 introduces a new major version of the cryptography part of Mbed TLS, going together with Mbed TLS 4.0. Many interfaces have changed, so users and integrators might need to change their own code in order to make it work with TF-PSA-Crypto. + +Here's the list of breaking changes; each entry should help you answer these +two questions: (1) am I affected? (2) if yes, what's my migration path? + +The changes are detailed below. Here is a summary of the main points: + +- Mbed TLS has been split between two products: TF-PSA-Crypto for cryptography, and Mbed TLS for X.509 and (D)TLS. +- CMake is now the only supported build system. +- The cryptography API is now mostly the PSA API: most legacy cryptography APIs have been removed. Some non-PSA APIs remain for features that PSA does not cover. +- In the same vein, third-party implementations of cryptographic mechanisms must be provided as PSA drivers: ALT implementations are no longer supported. +- In the same vein, the random generator configuration has been adapted and simplified. +- Some obsolete cryptographic mechanisms are no longer supported. +- The PSA PAKE interface has been updated to follow the final PSA specification. + +## CMake as the only build system +TF-PSA-Crypto uses CMake exclusively to configure and drive its build process. +There is no support for the GNU Make and Microsoft Visual Studio project-based build systems as there is in Mbed TLS 3.x. + +See the `Compiling` section in README.md for instructions on building the TF-PSA-Crypto library and tests with CMake. + +### Translating Make commands to CMake + +With no GNU Make support, all build, test, and installation operations must be performed using CMake. +This section provides a quick reference for translating common `make` commands into their CMake equivalents. + +#### Basic build workflow + +Run `cmake -S . -B build` once before building to configure the build and generate native build files (e.g., Makefiles) in the `build` directory. +This sets up an out-of-tree build, which is recommended. + +| Make command | CMake equivalent | Description | +|----------------|------------------------------------------------|------------------------------------------------------------------| +| `make` | `cmake --build build` | Build the library, programs, and tests in the `build` directory. | +| `make test` | `ctest --test-dir build` | Run the tests produced by the previous build. | +| `make clean` | `cmake --build build --target clean` | Remove build artifacts produced by the previous build. | +| `make install` | `cmake --install build --prefix build/install` | Install the built library, headers, and tests to `build/install`. | + +#### Building specific targets + +Unless otherwise specified, the CMake command in the table below should be preceded by a `cmake -S . -B build` call to configure the build and generate build files in the `build` directory. + +| Make command | CMake equivalent | Description | +|-----------------|---------------------------------------------------------------------|---------------------------| +| `make lib` | `cmake --build build --target tfpsacrypto` | Build only the library. | +| `make tests` | `cmake -S . -B build -DENABLE_PROGRAMS=Off && cmake --build build` | Build test suites. | +| `make programs` | `cmake --build build --target tfpsacrypto-programs` | Build example programs. | +| `make apidoc` | `cmake --build build --target tfpsacrypto-apidoc` | Build documentation. | + +Target names may differ slightly; use `cmake --build build --target help` to list all available CMake targets. + +There is no CMake equivalent for `make generated_files` or `make neat`. +Generated files are automatically created in the build tree with `cmake --build build` and removed with `cmake --build build --target clean`. +If you need to build the generated files in the source tree without involving CMake, you can call `framework/scripts/make_generated_files.py`. + +There is currently no equivalent for `make uninstall` in the TF-PSA-Crypto CMake build system. + +#### Common build options + +The following table illustrates the approximate CMake equivalents of common make commands. +Most CMake examples show only the configuration step, others (like installation) correspond to different stages of the build process. + +| Make usage | CMake usage | Description | +|----------------------------|-------------------------------------------------------------|----------------------| +| `make DEBUG=1` | `cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug` | Build in debug mode. | +| `make SHARED=1` | `cmake -S . -B build -DUSE_SHARED_TF_PSA_CRYPTO_LIBRARY=On` | Also build shared libraries. | +| `make GEN_FILES=""` | `cmake -S . -B build -DGEN_FILES=OFF` | Skip generating files (not a strict equivalent). | +| `make DESTDIR=install_dir` | `cmake --install build --prefix install_dir` | Specify installation path. | +| `make CC=clang` | `cmake -S . -B build -DCMAKE_C_COMPILER=clang` | Set the compiler. | +| `make CFLAGS='-O2 -Wall'` | `cmake -S . -B build -DCMAKE_C_FLAGS="-O2 -Wall"` | Set compiler flags. | + +## Repository split +In Mbed TLS 4.0, the Mbed TLS project was split into two repositories: +- [Mbed TLS](https://github.com/Mbed-TLS/mbedtls): provides TLS and X.509 functionality. +- [TF-PSA-Crypto](https://github.com/Mbed-TLS/TF-PSA-Crypto): provides the standalone cryptography library, notably including the PSA Cryptography API. + +If you use only the cryptography part, you should consider migrating to TF-PSA-Crypto. + +### File and directory relocations + +The following table summarizes the file and directory relocations resulting from the repository split between Mbed TLS and TF-PSA-Crypto. +These changes reflect the move of cryptographic, cryptographic-adjacent, and platform components from Mbed TLS into the present TF-PSA-Crypto repository. + +| Original location in Mbed TLS tree | New location(s) | Notes | +|-----------------------------------------|----------------------------------------------------------|-------| +| `library/*` | `core/`
`drivers/builtin/src/` | Contains cryptographic, cryptographic-adjacent (e.g., ASN.1, Base64), and platform C modules and headers. | +| `include/mbedtls/*` | `include/mbedtls/`
`drivers/builtin/include/private/` | Public headers moved to `include/mbedtls`; now internal headers moved to `include/private`. | +| `include/psa` | `include/psa` | All PSA headers consolidated here. | +| `3rdparty/everest`
`3rdparty/p256-m` | `drivers/everest`
`drivers/p256-m` | Third-party crypto driver implementations. | + +### Configuration file split +All cryptography and platform configuration options have been moved from the Mbed TLS configuration file to `include/psa/crypto_config.h`, which is the configuration file of TF-PSA-Crypto. See [Compile-time configuration](#compile-time-configuration) for more details. + +TF-PSA-Crypto also provides the `scripts/config.py` Python script to adjust your configuration. This script updates `include/psa/crypto_config.h`. + +There have been significant changes in the cryptography configuration options: +- See [psa-transition.md](psa-transition.md#compile-time-configuration). +- See also the following sections: + - [PSA as the only cryptography API](#psa-as-the-only-cryptography-api) and its sub-section [Impact on the library Configuration](#impact-on-the-library-configuration) + - [Random number generation configuration](#random-number-generation-configuration) + +### Impact on some usages of the library + +#### Linking directly to a built library + +The TF-PSA-Crypto CMake build system provides the cryptography libraries under the name, `libtfpsacrypto.` in the `core` directory. +Thus both the name of the libraries and their location have changed compared to Mbed TLS. +You may also need to update include paths to the public header files, see [File and Directory Relocations](#file-and-directory-relocations) for details. + +#### Using TF-PSA-Crypto as a CMake subproject + +The base name of the static and shared cryptography libraries is now `tfpsacrypto`, formerly `mbedcrypto`. +As before, this base name is also the base name of CMake targets to build the libraries. +If your CMake scripts reference a cryptography library target, you need to update its name accordingly. + +For example, the following CMake code: +``` +target_link_libraries(mytarget PRIVATE mbedcrypto) +``` +should be updated to: +``` +target_link_libraries(mytarget PRIVATE tfpsacrypto) +``` + +You can refer to the following example demonstrating how to consume TF-PSA-Crypto as a CMake subproject: +- `programs/test/cmake_subproject` + +#### Using TF-PSA-Crypto as a CMake package + +The same renaming applies to the cryptography library targets provided by the TF-PSA-Crypto CMake package. +The CMake package name has also changed from `MbedTLS` to `TF-PSA-Crypto`. + +For example, the following CMake code: +``` +find_package(MbedTLS REQUIRED) +target_link_libraries(myapp PRIVATE MbedTLS::mbedcrypto) +``` +should be updated to: +``` +find_package(TF-PSA-Crypto REQUIRED) +target_link_libraries(myapp PRIVATE TF-PSA-Crypto::tfpsacrypto) +``` + +You can also refer to the following example programs demonstrating how to consume TF-PSA-Crypto as a CMake package: +- `programs/test/cmake_package` +- `programs/test/cmake_package_install` + +#### Using the TF-PSA-Crypto pkg-config file + +The TF-PSA-Crypto CMake build system provides the pkg-config file `tfpsacrypto.pc`, formerly `mbedcrypto.pc`. You will need to update the file name in your scripts. + +#### Using TF-PSA-Crypto as an installed library + +The TF-PSA-Crypto CMake build system installs the cryptography libraries `libtfpsacrypto.`, formerly `libmbedcrypto.`. +Thus, you will need to link against `libtfpsacrypto.` instead of `libmbedcrypto.`. + +Regarding the headers, the main change is the relocation of some headers to subdirectories called `private`. +These headers are installed primarily to satisfy compiler dependencies. +Others remain for historical reasons and may be cleaned up in later versions of the library. + +We strongly recommend not relying on the declarations in these headers, as they may be removed or modified without notice, see [Private Declarations](#private-declarations). + +Finally, note the new `include/tf-psa-crypto` directory, which contains the TF-PSA-Crypto version and build-time configuration headers. + +### Audience-Specific Notes + +#### Application Developers using a distribution package +- See [Impact on usages of the library](#impact-on-some-usages-of-the-library) for the possible impacts on: + - Linking against the cryptography library or CMake targets. + - Using the TF-PSA-Crypto pkg-config file. + - Using TF-PSA-Crypto as an installed library. + +### Developer or package maintainers +If you build or distribute TF-PSA-Crypto: +- The build system is CMake. Makefiles and Visual Studio projects are not supported. +- Review [File and directory relocations](#file-and-directory-relocations) for updated paths. +- See [Impact on usages of the library](#impact-on-some-usages-of-the-library) for the possible impacts on: + - Linking against the cryptography library or CMake targets. + - Using the TF-PSA-Crypto pkg-config file. + - Using TF-PSA-Crypto as an installed library. +- The configuration file is `include/psa/crypto_config.h` (see [Configuration file split](#configuration-file-split)). +- If you want to distribute both the cryptography and the X.509 and/or TLS components, you need to package Mbed TLS together with its bundled TF-PSA-Crypto. + +### Platform Integrators +If you integrate TF-PSA-Crypto with a platform or hardware drivers: +- Platform-specific configuration options are now handled in `include/psa/crypto_config.h`. +- Review [File and directory relocations](#file-and-directory-relocations) for the location of platform components in TF-PSA-Crypto. + +## Compile-time configuration + +### Configuration file split + +Whether you are using TF-PSA-Crypto as a standalone project or as part of Mbed TLS, all the configuration options that are relevant to TF-PSA-Crypto must be configured in one of its configuration files, namely: + +* `TF_PSA_CRYPTO_CONFIG_FILE`, if set on the preprocessor command line; +* otherwise ``; +* additionally `TF_PSA_CRYPTO_USER_CONFIG_FILE`, if set. + +The macros `MBEDTLS_PSA_CRYPTO_CONFIG_FILE` and `MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE` are no longer recognized. Use `TF_PSA_CRYPTO_CONFIG_FILE` and `TF_PSA_CRYPTO_USER_CONFIG_FILE` instead. + +Configuration options that are relevant to X.509 or TLS should still be set in the Mbed TLS configuration file (`MBEDTLS_CONFIG_FILE` or ``, plus `MBEDTLS_USER_CONFIG_FILE` if it is set). However, you can define all the options in the crypto configuration, and Mbed TLS will pick them up. + +Generally speaking, the options that must be configured in TF-PSA-Crypto are: + +* options related to platform settings; +* options related to the choice of cryptographic mechanisms included in the build; +* options related to the inner workings of cryptographic mechanisms, such as size/memory/performance compromises; +* options related to crypto-adjacent features, such as ASN.1 and Base64. + +See `include/psa/crypto_config.h` in TF-PSA-Crypto and `include/mbedtls/mbedtls_config.h` in Mbed TLS for details. + +Notably, `` is no longer limited to `PSA_WANT_xxx` options. + +Note that many options related to cryptography have changed; this is covered in other sections of this document. + +### Split of `build_info.h` and `version.h` + +TF-PSA-Crypto has a header file `` which includes the configuration file and provides the adjusted configuration macros, similar to `` in Mbed TLS. + +TF-PSA-Crypto exposes its version through ``, similar to `` in Mbed TLS. + +### Removal of `check_config.h` + +The header `mbedtls/check_config.h` is no longer present. Including it from user configuration files was already obsolete in Mbed TLS 3.x, since it enforces properties of the configuration as adjusted by `mbedtls/build_info.h`, not properties that the user configuration is expected to meet. + +## PSA as the only cryptography API + +The PSA Crypto API is now the only API for cryptographic primitives. + +For general guidance on migrating to the PSA Crypto API, consult the +[PSA transition guide](psa-transition.md). Note that most of the suggested migrations also work in the Mbed TLS 3.6 long-time support branch, provided that the library is configured suitably (`MBEDTLS_USE_PSA_CRYPTO` and `MBEDTLS_PSA_CRYPTO_CONFIG` enabled). + +### Impact on application code + +The PK module uses PSA for cryptographic operations. This corresponds to the behavior of Mbed TLS 3.x when `MBEDTLS_USE_PSA_CRYPTO` is enabled. In effect, `MBEDTLS_USE_PSA_CRYPTO` is now always enabled. + +`psa_crypto_init()` must be called before performing any cryptographic operation. + +A few functions take different parameters to migrate them to the PSA API. See “[Function prototype changes](#function-prototype-changes)”. + +### No random generator instantiation + +Formerly, applications using various cryptographic features needed to provide a random generator, generally by instantiating an entropy context (`mbedtls_entropy_context`) and a DRBG context (`mbedtls_ctr_drbg_context` or `mbedtls_hmac_drbg_context`). This is no longer necessary, or possible. All features that require a random generator (RNG) now use the one provided by the PSA subsystem. + +Instead, applications that use random generators or keys (even public keys) need to call `psa_crypto_init()` before any cryptographic operation or key management operation. + +See also [function prototype changes](#function-prototype-changes), many of which are related to the move from RNG callbacks to a global RNG. + +### Impact on the library configuration + +The choice of supported cryptographic mechanisms is now based on `PSA_WANT_xxx` macros instead of legacy configuration macros such as `MBEDTLS_RSA_C`, `MBEDTLS_PKCS1_V15`, etc. This corresponds to the behavior of Mbed TLS 3.x when `MBEDTLS_PSA_CRYPTO_CONFIG` is enabled. In effect, `MBEDTLS_PSA_CRYPTO_CONFIG` is now always enabled. + +For information on which configuration macros are affected and their new PSA equivalent, consult the [PSA transition guide](psa-transition.md). + +See also the section [“Random number generation configuration”](#random-number-generation-configuration). + +### No direct access to specific algorithms + +All modules that are specific to a particular cryptographic mechanism have been removed from the API. There are a few exceptions, for some mechanisms that are not yet present in the PSA API: `mbedtls/lms.h` and `mbedtls/nist_kw.h` remain part of the API. + +The high-level legacy module `mbedtls/cipher.h` has also been removed. The high-level legacy modules `mbedtls/md.h` and `mbedtls/pk.h` remain present with reduced functionality (see “[Reduced `md.h`](#reduced-mdh)” and “[PK module](#pk-module)”). TF-PSA-Crypto also retains non-PSA interfaces for data formats, platform support and miscellaneous utility functions. + +In full detail, the following header files, and their former content, are no longer available. + +``` +everest/Hacl_Curve25519.h +everest/everest.h +everest/kremlib.h +everest/kremlib/*.h +everest/kremlin/*.h +everest/kremlin/internal/*.h +everest/vs2013/*.h +everest/x25519.h +mbedtls/aes.h +mbedtls/aria.h +mbedtls/bignum.h +mbedtls/block_cipher.h +mbedtls/camellia.h +mbedtls/ccm.h +mbedtls/chacha20.h +mbedtls/chachapoly.h +mbedtls/cipher.h +mbedtls/cmac.h +mbedtls/ctr_drbg.h +mbedtls/des.h +mbedtls/dhm.h +mbedtls/ecdh.h +mbedtls/ecdsa.h +mbedtls/ecjpake.h +mbedtls/ecp.h +mbedtls/entropy.h +mbedtls/gcm.h +mbedtls/hkdf.h +mbedtls/hmac_drbg.h +mbedtls/md5.h +mbedtls/pkcs12.h +mbedtls/pkcs5.h +mbedtls/poly1305.h +mbedtls/ripemd160.h +mbedtls/rsa.h +mbedtls/sha1.h +mbedtls/sha256.h +mbedtls/sha3.h +mbedtls/sha512.h +``` + +If your application was using functions from these headers, please see +[`docs/psa-transition.md`](psa-transition.md) for ways to migrate to +the PSA API instead. + +Some of the associated types still need to be visible to the compiler. For example, `mbedtls_aes_context` is used to define `psa_cipher_operation_t`. These types are still available when building application code, but we recommend that you no longer use them directly. The structure, the semantics and even the existence of these types may change without notice. + +### Other removed functions related to low-level cryptography APIs + +The functions `mbedtls_ecc_group_to_psa()` and `mbedtls_ecc_group_from_psa()` have been removed. They are no longer meaningful since the low-level representation of elliptic curve groups is no longer part of the API. + +### Removal of alternative cryptographic module implementations + +TF-PSA-Crypto no longer supports replacing a whole cryptographic module or an individual cryptographic function by defining a macro `MBEDTLS_xxx_ALT` and providing a custom implementation of the same interface. Instead, use PSA transparent drivers (i.e. accelerator drivers). + +The PK module no longer supports `MBEDTLS_PK_RSA_ALT`. Instead, for opaque keys (RSA or otherwise), use PSA opaque drivers. + +## Private declarations + +Since Mbed TLS 3.0, some things that are declared in a public header are not part of the stable application programming interface (API), but instead are considered private. Private elements may be removed or may have their semantics changed in a future minor release without notice. + +### Understanding private declarations in public headers + +In TF-PSA-Crypto 1.x, private elements in header files include: + +* Anything appearing in a header file whose path contains `/private` (unless re-exported and documented in another non-private header). +* Structure and union fields declared with `MBEDTLS_PRIVATE(field_name)` in the source code, and appearing as `private_field_name` in the rendered documentation. (This was already the case since Mbed TLS 3.0.) +* Any preprocessor macro that is not documented with a Doxygen comment. + In the source code, Doxygen comments start with `/**` or `/*!`. If a macro only has a comment above that starts with `/*`, the macro is considered private. + In the rendered documentation, private macros appear with only an automatically rendered parameter list, value and location, but no custom text. +* Any declaration that is guarded by the preprocessor macro `MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS`. + +### Usage of private declarations + +Some private declarations are present in public headers for technical reasons, because they need to be visible to the compiler. Others are present for historical reasons and may be cleaned up in later versions of the library. We strongly recommend against relying on these declarations, since they may be removed or may have their semantics changed without notice. + +Note that Mbed TLS 4.0 still relies on some private interfaces of TF-PSA-Crypto 1.0. We expect to remove this reliance gradually in future minor releases. + +Sample programs have not been fully updated yet and some of them might still +use APIs that are no longer public. You can recognize them by the fact that they +define the macro `MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS` (or +`MBEDTLS_ALLOW_PRIVATE_ACCESS`) at the very top (before including headers). When +you see one of these two macros in a sample program, be aware it has not been +updated and parts of it do not demonstrate current practice. + +We strongly recommend against defining `MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS` or +`MBEDTLS_ALLOW_PRIVATE_ACCESS` in your own application. If you do so, your code +may not compile or work with future minor releases. If there's something you +want to do that you feel can only be achieved by using one of these two macros, +please reach out on github or the mailing list. + +## Error codes + +### Unified error code space + +The convention still applies that functions return 0 for success and a negative value between -32767 and -1 on error. PSA functions (`psa_xxx()` or `mbedtls_psa_xxx()`) still return a `PSA_ERROR_xxx` error codes. Non-PSA functions (`mbedtls_xxx()` excluding `mbedtls_psa_xxx()`) can return either `PSA_ERROR_xxx` or `MBEDTLS_ERR_xxx` error codes. + +There may be cases where an `MBEDTLS_ERR_xxx` constant has the same numerical value as a `PSA_ERROR_xxx`. In such cases, they have the same meaning: they are different names for the same error condition. + +### Simplified legacy error codes + +All values returned by a function to indicate an error now have a defined constant named `MBEDTLS_ERR_xxx` or `PSA_ERROR_xxx`. Functions no longer return the sum of a “low-level” and a “high-level” error code. + +Generally, functions that used to return the sum of two error codes now return the low-level code. However, as before, the exact error code returned in a given scenario can change without notice unless the condition is specifically described in the function's documentation and no other condition is applicable. + +As a consequence, the functions `mbedtls_low_level_strerr()` and `mbedtls_high_level_strerr()` no longer exist. + +### Removed English error messages + +TF-PSA-Crypto does not provide English text corresponding to error codes. The functionality provided by `mbedtls_strerror()` in `mbedtls/error.h` is still present in Mbed TLS. + +### Removed error code names + +Many legacy error codes have been removed in favor of PSA error codes. Generally, functions that returned a legacy error code in the table below in Mbed TLS 3.6 now return the PSA error code listed on the same row. Similarly, callbacks should apply the same changes to error code, unless there has been a relevant change to the callback's interface. + +| Legacy constant (Mbed TLS 3.6) | PSA constant (TF-PSA-Crypto 1.0) | +|--------------------------------------------|----------------------------------| +| `MBEDTLS_ERR_AES_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_ARIA_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_ASN1_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` | +| `MBEDTLS_ERR_ASN1_BUF_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` | +| `MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` | +| `MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_CCM_AUTH_FAILED` | `PSA_ERROR_INVALID_SIGNATURE` | +| `MBEDTLS_ERR_CCM_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED` | `PSA_ERROR_INVALID_SIGNATURE` | +| `MBEDTLS_ERR_CIPHER_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` | +| `MBEDTLS_ERR_CIPHER_AUTH_FAILED` | `PSA_ERROR_INVALID_SIGNATURE` | +| `MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_CIPHER_INVALID_PADDING` | `PSA_ERROR_INVALID_PADDING` | +| `MBEDTLS_ERR_ECP_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` | +| `MBEDTLS_ERR_ECP_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` | +| `MBEDTLS_ERR_ECP_IN_PROGRESS` | `PSA_OPERATION_INCOMPLETE` | +| `MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH` | `PSA_ERROR_INVALID_SIGNATURE` | +| `MBEDTLS_ERR_ECP_VERIFY_FAILED` | `PSA_ERROR_INVALID_SIGNATURE` | +| `MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED` | `PSA_ERROR_CORRUPTION_DETECTED` | +| `MBEDTLS_ERR_ERROR_GENERIC_ERROR` | `PSA_ERROR_GENERIC_ERROR` | +| `MBEDTLS_ERR_GCM_AUTH_FAILED` | `PSA_ERROR_INVALID_SIGNATURE` | +| `MBEDTLS_ERR_GCM_BAD_INPUT` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_GCM_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` | +| `MBEDTLS_ERR_LMS_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` | +| `MBEDTLS_ERR_LMS_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` | +| `MBEDTLS_ERR_MD_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` | +| `MBEDTLS_ERR_MD_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_MPI_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` | +| `MBEDTLS_ERR_MPI_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` | +| `MBEDTLS_ERR_OID_NOT_FOUND` | `PSA_ERROR_NOT_SUPPORTED` | +| `MBEDTLS_ERR_PEM_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` | +| `MBEDTLS_ERR_PEM_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_PK_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` | +| `MBEDTLS_ERR_PK_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_PK_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` | +| `MBEDTLS_ERR_PK_SIG_LEN_MISMATCH` | `PSA_ERROR_INVALID_SIGNATURE` | +| `MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED` | `PSA_ERROR_NOT_SUPPORTED` | +| `MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED` | `PSA_ERROR_HARDWARE_FAILURE` | +| `MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_RSA_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_RSA_INVALID_PADDING` | `PSA_ERROR_INVALID_PADDING` | +| `MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE` | `PSA_ERROR_BUFFER_TOO_SMALL` | +| `MBEDTLS_ERR_SHA1_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_SHA256_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_SHA3_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_SHA512_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | + +## Feature removals + +### Removal of self-test interfaces + +TF-PSA-Crypto 1.0 does not provide a ready-made self-test interface; one may be added in a future version of the library. + +If you need self-tests for compliance, you may perform them by invoking normal API functions with sample data. + +As a consequence, the compilation option `MBEDTLS_SELF_TEST` does not provide direct benefits in TF-PSA-Crypto 1.0. However, it allows the sample program `programs/test/selftest.c` in Mbed TLS to run self tests of cryptographic mechanisms. + +### Removed hardware support + +Acceleration for VIA Padlock (`MBEDTLS_PADLOCK_C`) is no longer provided. + +The deprecated and incomplete support for dynamic registration of secure element drivers (`MBEDTLS_PSA_CRYPTO_SE_C`) has been removed. Use compile-time secure element drivers instead. + +See also [the removal of ALT interfaces](#removal-of-alternative-cryptographic-module-implementations). + +### Removed obsolete cryptographic mechanisms + +Some obsolescent cryptographic mechanisms have been removed: + +* The library no longer supports DES (including 3DES). All supported block ciphers now have 128-bit blocks. As a consequence, the PKCS12 module, which provided the obsolete PBE mode for private key encryption that does not support stronger ciphers, has been removed. +* The library no longer supports elliptic curves whose size is 224 bits or less. The following curves are no longer supported: secp192r1, secp192k1, secp224k1, secp224r1. Use larger curves such as secp256r1. + +### Removed obsolete PSA functions + +Some PSA Crypto API functions dating back from before the 1.0 version of the API, or that were experimental, have been removed: + +* `psa_open_key()`, `psa_close_key()`, and auxiliary functions and macros related to handles. Persistent keys are opened implicitly since Mbed TLS 2.25. +* `psa_set_key_domain_parameters()`, `psa_get_key_domain_parameters()` and related macros. This feature was primarily intended to support custom finite-field Diffie-Hellman (FFDH) groups, but this was never implemented. To generate an RSA key with a custom public exponent, use `psa_generate_key_custom()`, introduced in Mbed TLS 3.6.1. +* `psa_generate_key_ext()`, `psa_key_derivation_output_key_ext` and related types and macros. Use `psa_generate_key_custom()` or `psa_key_derivation_output_key_custom()` instead. + +## Function prototype changes + +A number of existing functions now take a different list of arguments, mostly to migrate them to the PSA API. + +### Public functions no longer take a RNG callback + +Functions that need randomness no longer take an RNG callback in the form of `f_rng, p_rng` arguments. Instead, they use the PSA Crypto random generator (accessible as `psa_generate_random()`). All software using the LMS or PK modules must call `psa_crypto_init()` before calling any of the functions listed here. + +### RNG removal in LMS + +The following function prototypes have been changed in `mbedtls/lms.h`: + +```c +int mbedtls_lms_generate_private_key(mbedtls_lms_private_t *ctx, mbedtls_lms_algorithm_type_t type, mbedtls_lmots_algorithm_type_t otstype, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *seed, size_t seed_size); + +int mbedtls_lms_sign(mbedtls_lms_private_t *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *msg, unsigned int msg_size, unsigned char *sig, size_t sig_size, size_t *sig_len); +``` + + +to + +```c +int mbedtls_lms_generate_private_key(mbedtls_lms_private_t *ctx, mbedtls_lms_algorithm_type_t type, mbedtls_lmots_algorithm_type_t otstype, + const unsigned char *seed, size_t seed_size); + +int mbedtls_lms_sign(mbedtls_lms_private_t *ctx, + const unsigned char *msg, unsigned int msg_size, unsigned char *sig, size_t sig_size, size_t *sig_len); +``` + +### RNG removal in PK + +The following function prototypes have been changed in `mbedtls/pk.h`: + +```c +int mbedtls_pk_sign_restartable(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_pk_restart_ctx *rs_ctx); + +int mbedtls_pk_check_pair(const mbedtls_pk_context *pub, const mbedtls_pk_context *prv, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +int mbedtls_pk_sign(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng); + +int mbedtls_pk_sign_ext(mbedtls_pk_type_t pk_type, mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +int mbedtls_pk_parse_key(mbedtls_pk_context *ctx, const unsigned char *key, size_t keylen, const unsigned char *pwd, size_t pwdlen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng); + +int mbedtls_pk_parse_keyfile(mbedtls_pk_context *ctx, const char *path, const char *password, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng); + +typedef int (*mbedtls_pk_rsa_alt_sign_func)(void *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash, unsigned char *sig); +``` + +to + +```c +int mbedtls_pk_sign_restartable(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len, + mbedtls_pk_restart_ctx *rs_ctx); + +int mbedtls_pk_check_pair(const mbedtls_pk_context *pub, const mbedtls_pk_context *prv); + +int mbedtls_pk_sign(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len); + +int mbedtls_pk_sign_ext(mbedtls_pk_type_t pk_type, mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len); + +int mbedtls_pk_parse_key(mbedtls_pk_context *ctx, const unsigned char *key, size_t keylen, const unsigned char *pwd, size_t pwdlen); + +int mbedtls_pk_parse_keyfile(mbedtls_pk_context *ctx, const char *path, const char *password); + +typedef int (*mbedtls_pk_rsa_alt_sign_func)(void *ctx, + mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash, unsigned char *sig); +``` + +### Changes to NIST_KW + +The NIST\_KW module remains part of TF-PSA-Crypto, since it does not have a PSA equivalent yet. However, its interface has changed, to use PSA key identifiers instead of a plaintext key via a custom context. + +The following function prototypes have been changed in `mbedtls/nist_kw.h`: + +```c +int mbedtls_nist_kw_wrap(mbedtls_nist_kw_context *ctx, + mbedtls_nist_kw_mode_t mode, + const unsigned char *input, size_t in_len, + unsigned char *output, size_t *out_len, size_t out_size); +int mbedtls_nist_kw_unwrap(mbedtls_nist_kw_context *ctx, + mbedtls_nist_kw_mode_t mode, + const unsigned char *input, size_t in_len, + unsigned char *output, size_t *out_len, size_t out_size); +``` + +to + +```c +psa_status_t mbedtls_nist_kw_wrap(mbedtls_svc_key_id_t key, + mbedtls_nist_kw_mode_t mode, + const unsigned char *input, size_t input_length, + unsigned char *output, size_t output_size, + size_t *output_length); +psa_status_t mbedtls_nist_kw_unwrap(mbedtls_svc_key_id_t key, + mbedtls_nist_kw_mode_t mode, + const unsigned char *input, size_t input_length, + unsigned char *output, size_t output_size, + size_t *output_length); +``` + +Note that in addition to the change to keys, the last two parameters for the output buffer size and the length of the actual output have been swapped, to align the order of parameters with PSA Crypto APIs. + +The type `mbedtls_nist_kw_context` and the functions `mbedtls_nist_kw_init()`, `mbedtls_nist_kw_free()` and `mbedtls_nist_kw_setkey()` have been removed, since the interface no longer involves a specific context object for NIST\_KW. + +Also, the function `mbedtls_nist_kw_self_test()` has been removed. TF-PSA-Crypto 1.0 does not provide a ready-made self-test interface; one may be added in a future version of the library. + +### Changes to ASN.1 functions + +As a consequence of the removal of the type `mbedtls_mpi` (provided by `mbedtls/bignum.h`) from public interfaces, the ASN.1 functions to parse and write integers have changed. + +The following functions have been removed from the API: + +```c +// mbedtls/asn1.h +int mbedtls_asn1_get_mpi(unsigned char **p, const unsigned char *end, + mbedtls_mpi *X); + +// mbedtls/asn1write.h +int mbedtls_asn1_write_mpi(unsigned char **p, const unsigned char *start, + const mbedtls_mpi *X); +``` + +You can use the following new functions instead: + +```c +// mbedtls/asn1.h +int mbedtls_asn1_get_integer(unsigned char **p, const unsigned char *end, + unsigned char **head, size_t *length); + +// mbedtls/asn1write.h +int mbedtls_asn1_write_integer(unsigned char **p, + unsigned char *start, + const unsigned char *integer, + size_t integer_length); +``` + +Both new functions use a big-endian byte buffer as the representation. + +Note some differences in the semantics of the new parsing function: + +* `mbedtls_asn1_get_integer()` rejects negative integers. (`mbedtls_asn1_get_mpi()` misparsed them, using the sign bit as a value bit). +* `mbedtls_asn1_get_integer()` does not allocate memory. It returns a pointer inside the ASN.1 representation. + +## Threading platform abstraction + +### Extension to condition variables + +The threading abstraction now includes primitives for condition variables in addition to mutexes. + +As before, implementations of `MBEDTLS_THREADING_ALT` need to provide a header file `"threading_alt.h"`, and to call the function `mbedtls_threading_set_alt()` before any call to other TF-PSA-Crypto or Mbed TLS functions. The header file `"threading_alt.h"` now needs to define the following elements: + +* The type `mbedtls_platform_mutex_t`, which is the type of mutex arguments passed to the platform functions. This type is now distinct from the type `mbedtls_threading_mutex_t` which library code and applications use. +* The type `mbedtls_platform_condition_variable_t`, which is the type of condition variable arguments passed to the platform functions. + +### Changes to the mutex primitives + +The type of mutex objects provided by the platform functions is now called `mbedtls_platform_mutex_t`, distinct from the API type `mbedtls_threading_mutex_t`. + +The `mutex_init` primitive now returns a status code instead of `void`. + +The documentation in `include/mbedtls/threading.h` now clarifies the expectations on mutex primitives. These expectations are somewhat relaxed from the mostly undocumented expectations in previous versions: mutex functions other than `mutex_init` can now assume that the mutex has been successfully initialized. + +Platform threading primitives should now return the following error codes: + +* `MBEDTLS_ERR_THREADING_USAGE_ERROR` to report a runtime failure (renamed from `MBEDTLS_ERR_THREADING_MUTEX_ERROR`, which is now an alias provided only for backward compatibility). +* `PSA_ERROR_BAD_STATE` only to report a library state error. If an error is detected in the state of a synchronization object, please return `MBEDTLS_ERR_THREADING_USAGE_ERROR` instead. +* `PSA_ERROR_INSUFFICIENT_MEMORY` to report resource exhaustion. + +## Random number generation configuration + +TF-PSA-Crypto no longer exposes the internals of the PSA random number generator. The entropy, CTR_DRBG, and HMAC_DRBG modules from Mbed TLS 3.6 are now for internal use only. As a result, their configuration has been updated, both to simplify them and to prepare for PSA entropy and random number generation drivers, which will be introduced in a future minor release. + +The overall structure of the random number generator in TF-PSA-Crypto remains the same as in Mbed TLS 3.x. It consists of either: +* an external random number generator (when `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is enabled), or +* a deterministic random number generator (CTR_DRBG or HMAC_DRBG) seeded with entropy by the entropy module. + +### Entropy configuration + +TF-PSA-Crypto does not expose an entropy interface to applications. The entropy module of Mbed TLS 3.6 is now for internal use only. As a consequence, its configuration has changed, both to simplify it and to prepare for PSA entropy drivers which will be added in a future minor release. + +#### If you have a fast cryptographic-quality external random generator + +If you have a fast, cryptographic-quality source of random data, enable `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` and provide the callback function `mbedtls_psa_external_get_random()`. This is unchanged since Mbed TLS 2.26. + +#### If the built-in entropy source works for you + +TF-PSA-Crypto, like Mbed TLS, recognizes the system entropy sources on some popular operating systems, and enables them by default. If you are writing your own configuration, you now need to define the option `MBEDTLS_PSA_BUILTIN_GET_ENTROPY`. (This is different from Mbed TLS 2.x and 3.x, where the built-in entropy sources were included unless the option `MBEDTLS_NO_PLATFORM_ENTROPY` was defined.) + +#### If you have a custom entropy source + +To provide a custom entropy source, disable `MBEDTLS_PSA_BUILTIN_GET_ENTROPY` and enable `MBEDTLS_PSA_DRIVER_GET_ENTROPY`. You will need to provide the callback function `mbedtls_platform_get_entropy()`. See [“Custom entropy collector”](#custom-entropy-collector) below for more details. + +#### If you have no entropy source + +If your hardware does not have any entropy source, you can use a non-volatile RNG seed which is injected from a trusted external source during device manufacturing or provisioning. Enable the option `MBEDTLS_ENTROPY_NV_SEED`, which is unchanged from previous versions of the library. + +In TF-PSA-Crypto, when the non-volatile seed is the only (pseudo) entropy source, you also need to enable the option `MBEDTLS_ENTROPY_NO_SOURCES_OK`. + +### Comparison of entropy source configurations + +TF-PSA-Crypto 1.0 supports the same entropy sources as Mbed TLS 3.6, but the way to configure them has changed. + +* The negative option `MBEDTLS_NO_PLATFORM_ENTROPY` to disable the default entropy collector for Unix-like and Windows platforms no longer exists. It has been replaced by the positive option `MBEDTLS_PSA_BUILTIN_GET_ENTROPY`, which is enabled by default. +* The option `MBEDTLS_ENTROPY_HARDWARE_ALT`, which allows you to provide a custom entropy collector, has been renamed to `MBEDTLS_PSA_DRIVER_GET_ENTROPY`. This replaces `MBEDTLS_ENTROPY_HARDWARE_ALT`. The callback has a different name and prototype as described in “[Custom hardware collector](#custom-entropy-collector)”. +* The option `MBEDTLS_ENTROPY_NV_SEED` to enable a non-volatile seed is unchanged. However, if this is your only entropy source, you must now enable the new option `MBEDTLS_ENTROPY_NO_SOURCES_OK`. + +The following table describes common configurations. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ConfigurationMbed TLS 3.6TF-PSA-Crypto 1.0
Unix, Linux, Windows(default)(default)
Embedded platform +
+#define MBEDTLS_NO_PLATFORM_ENTROPY
+#define MBEDTLS_ENTROPY_HARDWARE_ALT
+      
+
+
+#undef MBEDTLS_PSA_BUILTIN_GET_ENTROPY
+#define MBEDTLS_PSA_DRIVER_GET_ENTROPY
+      
+
Fast external crypto RNG +
+#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+#undef MBEDTLS_ENTROPY_C
+#undef MBEDTLS_CTR_DRBG_C
+      
+
+
+#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+#undef MBEDTLS_ENTROPY_C
+#undef MBEDTLS_CTR_DRBG_C
+      
+
NV seed only +
+#define MBEDTLS_NO_PLATFORM_ENTROPY
+#define MBEDTLS_ENTROPY_NV_SEED
+      
+
+
+#undef MBEDTLS_PSA_BUILTIN_GET_ENTROPY
+#define MBEDTLS_ENTROPY_NV_SEED
+#define MBEDTLS_ENTROPY_NO_SOURCES_OK
+      
+
No entropy at all +
+#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
+      
+
+ not supported +
+ +#### Custom entropy collector + +The custom entropy collector callback function has changed, to make it match the upcoming PSA entropy driver specification. + +Formerly, the callback was enabled by `MBEDTLS_ENTROPY_HARDWARE_ALT` and had the following prototype: +```c +// from +int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, + size_t *olen); +``` + +The new callback is enabled by `MBEDTLS_PSA_DRIVER_GET_ENTROPY` and has the following prototype: +```c +// from +int mbedtls_platform_get_entropy(psa_driver_get_entropy_flags_t flags, + size_t *estimate_bits, + unsigned char *output, size_t output_size); +``` + +The `data` parameter was previously always `NULL`, and has been removed. + +The new parameter `flags` is a bit-mask of flags that allows the caller to request special behaviors, such as avoiding blocking. The callback should return `PSA_ERROR_NOT_SUPPORTED` if it sees a flag that it does not support. As of TF-PSA-Crypto 1.0, `flags` is always 0. + +The former callback could return less entropy than expected by only filling part of the buffer, and setting `*olen` to a value that is less than `output_size`. The new callback does not have an `olen` parameter, and the caller now reads the whole buffer. The new parameter `estimate_bits` is intended to allow the callback to report that it has accumulated less entropy than expected. However, this is not supported yet in TF-PSA-Crypto 1.0. + +The new output parameter `estimate_bits` is the amount of entropy that the callback has placed in the output buffer. As of TF-PSA-Crypto 1.0, the output must have full entropy, thus `estimate_bits` must be equal to `8 * output_size`. A future version of TF-PSA-Crypto will allow entropy sources to report smaller amounts. + +To indicate that entropy is not currently available, the legacy error code `MBEDTLS_ERR_ENTROPY_SOURCE_FAILED` has been replaced by `PSA_ERROR_INSUFFICIENT_ENTROPY`. + +#### Removed entropy options + +The option `MBEDTLS_ENTROPY_MIN_HARDWARE` has been removed. The entropy module requests the amount that it needs for the chosen security strength. + +The option `MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES` has removed since it is no longer meaningful, now that the entropy module is private. TF-PSA-Crypto 1.0 does not support platforms without an entropy source. This ability will be reintroduced in a future minor release. + +#### PSA entropy injection + +The configuration option `MBEDTLS_PSA_INJECT_ENTROPY` has been removed. TF-PSA-Crypto 1.0 does not provide a way to store an entropy seed in the key store. This will be reimplemented in a future minor version. + +### Configuration of the DRBG + +As in previous versions of Mbed TLS, the PSA random generator in TF-PSA-Crypto uses CTR_DRBG with AES if `MBEDTLS_CTR_DRBG_C` is enabled, and HMAC_DRBG otherwise (requiring `MBEDTLS_HMAC_DRBG_C` to be enabled). + +The DRBG modules are not exposed directly, they are only used internally. + +In addition to the choice of DRBG module and entropy sources, the built-in random number generator is now configured through only three options: + +* `MBEDTLS_PSA_CRYPTO_RNG_HASH`: Selects the hash algorithm used by the entropy and HMAC_DRBG modules. This option replaces both `MBEDTLS_PSA_HMAC_DRBG_MD_TYPE` and `MBEDTLS_ENTROPY_FORCE_SHA256`. +* `MBEDTLS_PSA_RNG_RESEED_INTERVAL`: Sets the reseed interval for both CTR_DRBG and HMAC_DRBG. It replaces `MBEDTLS_CTR_DRBG_RESEED_INTERVAL` and `MBEDTLS_HMAC_DRBG_RESEED_INTERVAL`. +* `MBEDTLS_PSA_CRYPTO_RNG_STRENGTH`: Specifies the security strength in bits. The default is 256 bits. If you previously enabled `MBEDTLS_CTR_DRBG_USE_128_BIT_KEY` in Mbed TLS 3.6, you should now set `MBEDTLS_PSA_CRYPTO_RNG_STRENGTH` to 128, although this is not recommended. + +The option `MBEDTLS_ENTROPY_C` has been removed. The entropy module is now automatically enabled when `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is disabled. +The following Mbed TLS 3.6 configuration options have been removed without any counterpart in TF-PSA-Crypto. Their corresponding APIs were also removed, making these options no longer relevant: +`MBEDTLS_ENTROPY_MAX_GATHER`, `MBEDTLS_ENTROPY_MAX_SOURCES`, `MBEDTLS_CTR_DRBG_ENTROPY_LEN`, `MBEDTLS_CTR_DRBG_MAX_INPUT`, `MBEDTLS_CTR_DRBG_MAX_REQUEST`, `MBEDTLS_CTR_DRBG_MAX_SEED_INPUT`, `MBEDTLS_HMAC_DRBG_MAX_INPUT`, `MBEDTLS_HMAC_DRBG_MAX_REQUEST`, and `MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT`. + +## Reduced `md.h` + +PSA is now the preferred interface for computing hashes and HMAC. See [“Hashes and MAC” in the PSA transition guide](psa-transition.md#hashes-and-mac) for more information. + +TF-PSA-Crypto 1.x still has a header file `` to facilitate the transition. Its functionality is limited to calculating hashes: + +* `mbedtls_md_setup()` now requires the `hmac` parameter to be 0. Use the PSA API for HMAC calculations. +* The HMAC functions `mbedtls_md_hmac_xxx()` are no longer available. +* The metadata functions `mbedtls_md_list()`, `mbedtls_md_info_from_string()`, `mbedtls_md_get_name()` and `mbedtls_md_info_from_ctx()` have been removed. The library does not associate names to individual algorithms any longer. +* The function `mbedtls_md_file()` has been removed. To hash a file, load it into memory manually. Load it piecewise and call `mbedtls_md_update()` or `psa_hash_update()` in a loop if the file may be large. + +## PK module + +The PK module for asymmetric cryptography is still present in TF-PSA-Crypto 1.x, but with a somewhat reduced scope compared to Mbed TLS. The main goal of PK is now to parse and format key pairs and public keys. PK also retains signature functions, to facilitate the transition from previous versions. The main differences compared to Mbed TLS 3.6 and below are: + +* PK objects no longer expose the underlying representation. It is now unspecified in most cases whether a PK object stores key material directly, or a PSA key identifier. +* PK objects no longer have any policy attached to them. This mostly affects RSA keys, which no longer “remember” whether they are meant to be used with PKCS#1v1.5 or PSS/OAEP. + +### Changes to PK metadata + +The type `mbedtls_pk_type_t` has been removed from the API. This type could convey different kinds of information, depending on where it was used: + +* Information about the representation of a PK context (distinguishing between transparent and opaque objects containing the same type of key). This information is no longer exposed. + +* Which signature algorithm to use (distinguishing between PKCS#1v1.5 and PSS for RSA keys), mostly for the sake of X.509. This information is now represented as `mbedtls_pk_sigalg_t`, using enum constants with tweaked names: + + | Old `mbedtls_pk_type_t` name | New `mbedtls_pk_sigalg_t` name | + | ---------------------------- | ------------------------------ | + | `MBEDTLS_PK_NONE` | `MBEDTLS_PK_SIGALG_NONE` | + | `MBEDTLS_PK_RSA` | `MBEDTLS_PK_SIGALG_RSA_PKCS1V15` | + | `MBEDTLS_PK_RSASSA_PSS` | `MBEDTLS_PK_SIGALG_RSA_PSS` | + | `MBEDTLS_PK_ECDSA` or `MBEDTLS_PK_ECKEY` | `MBEDTLS_PK_SIGALG_ECDSA` | + +* Policy information after parsing a key (only relevant for ECC keys marked as ECDH-only). This is now tracked internally and reflected in rejecting the key for signature or verification in `mbedtls_pk_get_psa_attributes()` and in operation functions. + + +As a consequence, the functions `mbedtls_pk_get_type()`, `mbedtls_pk_get_name()` and `mbedtls_pk_info_from_type()` and have been removed. The type `mbedtls_pk_info_t` is no longer part of the API. + +The function `mbedtls_pk_get_len()` has also been removed. It was not very meaningful since it did not convey the length of the key representation, but the size in bytes of the representation of one number associated with the key. As before, you can use `mbedtls_pk_get_bitlen()` to get the key size in the usual cryptographic sense. The size of a formatted key representation depends on the format, and there is no API function to determine it. (For the short export formats of PSA, you can use macros such as `PSA_EXPORT_KEY_OUTPUT_SIZE()`, `PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE()`, `PSA_EXPORT_KEY_PAIR_MAX_SIZE`, `PSA_EXPORT_PUBLIC_KEY_MAX_SIZE`.) + +### Checking the capabilities of a PK context + +The function `mbedtls_pk_can_do()`, based on the polysemic `mbedtls_pk_type_t`, has been removed. The function `mbedtls_pk_can_do_ext()`, based on PSA metadata, has been renamed to `mbedtls_pk_can_do_psa()`. It now supports public-key operations as well as private-key operations. + +### Loss of policy information for RSA keys + +The PK module no longer partially keeps track of whether an RSA key is intended for use with PKCS#1v1.5 or PKCS#1v2.1 (PSS or OAEP) algorithms. Functions that consume a PK object (`mbedtls_pk_get_psa_attributes()`, `mbedtls_pk_sign()`, `mbedtls_pk_verify()`) now always default to PKCS#1v1.5, except for PK contexts populated with `mbedtls_pk_wrap_psa()` where they use the primary algorithm in the key's policy. + +Note in particular that the functions `mbedtls_pk_copy_from_psa()` and `mbedtls_pk_copy_public_from_psa()` are now equivalent to exporting and re-importing the key, losing all policy information. For example, calling `mbedtls_pk_copy_from_psa()` on a key whose policy specifies PSS as the single allowed algorithm, then calling `mbedtls_pk_sign()`, results in a PKCS#1v1.5 signature. Call `mbedtls_pk_sign_ext()` or `mbedtls_pk_verify_ext()` if you want to specify the signature algorithm explicitly. + +### Removal of transparent PK contexts + +It is no longer possible to directly inspect a PK context to act on its underlying RSA or ECC context. The representation of a key in PK is now always an implementation detail. + +As a consequence, the functions `mbedtls_pk_setup()`, `mbedtls_pk_rsa()` and `mbedtls_pk_ec()` have been removed. + +### Changes to opaque PK contexts + +The library no longer supports an alternative representation of RSA keys in PK (`MBEDTLS_PK_RSA_ALT_SUPPORT` compilation option, PK context type `MBEDTLS_PK_RSA_ALT`). See [“RSA-ALT interface” in the PSA transition guide](psa-transition.md#rsa-alt-interface). + +A PK object can still wrap around an PSA key, which was formerly known as “opaque” PK objects of type `MBEDTLS_PK_OPAQUE`. The function `mbedtls_pk_setup_opaque()` has been renamed to `mbedtls_pk_wrap_psa()`, to reflect the fact that the PSA key is not necessarily “opaque” in PSA terminology. The PK module now hides the distinction between “wrapping” and “non-wrapping” PK contexts as much as possible, and in particular there is no simple metadata query to distinguish “wrapping” keys like the former `mbedtls_pk_get_type()`. + +### Fewer operations in PK + +The functions `mbedtls_pk_encrypt()` and `mbedtls_pk_decrypt()` have been removed. Use `psa_asymmetric_encrypt()` and `psa_asymmetric_decrypt()` instead. See [“Asymmetric encryption and decryption” in the PSA transition guide](psa-transition.md#rsa-alt-interface) for more information. + +If you have a key as a PK context and you wish to use it with PSA operation functions, use the functions `mbedtls_pk_get_psa_attributes()` and `mbedtls_pk_import_into_psa()` to obtain a PSA key identifier. See the documentation of these functions or [“Creating a PSA key via PK” in the PSA transition guide](psa-transition.md#creating-a-psa-key-via-pk) for more information. + +### Miscellaneous changes to PK signature and verification + +The `type` argument to `mbedtls_pk_sign_ext()` and `mbedtls_pk_verify_ext()` now has the type `mbedtls_pk_sigalg_t`. See [“Changes to PK metadata”](#changes-to-pk-metadata). + +The function `mbedtls_pk_verify_ext()` no longer supports a custom salt length for RSA-PSS. It always allows signatures with any salt length. The PSA API offers `psa_verify_hash()` with `PSA_ALG_RSA_PSS` to enforce the most commonly used salt length. + +`MBEDTLS_ERR_PK_SIG_LEN_MISMATCH` is no longer a distinct error code. A valid signature with trailing garbage is now reported as an invalid signature with all algorithms. + +The PK module continues to favor deterministic ECDSA over randomized ECDSA when both are possible. This may change in the future. The new macro `MBEDTLS_PK_ALG_ECDSA(hash_alg)` indicates which variant PK favors. It is equivalent to either `PSA_ALG_DETERMINISTIC_ECDSA(hash_alg)` or `PSA_ALG_ECDSA(hash_alg)`. + +### Changes in resources consumed by PK objects + +The implementation of the type `mbedtls_pk_context` has changed in ways that do not directly affect functionality, but affect resource consumption and memory partitioning. + +Historically, at least in the default configuration, a PK context stored all the key material in a heap-allocated object. In TF-PSA-Crypto 1.0, a PK context now contains: + +* the public key, in a fixed-size buffer that is directly in the `mbedtls_pk_context` structure; +* the private key (if available), in the PSA key store. + +This may change in future minor versions of TF-PSA-Crypto. + +### Other miscellaneous changes in PK + +Since PSA has a built-in random generator, all `(f_rng, p_rng)` arguments to PK functions have been removed. + +`mbedtls_pk_debug()` and the associated types have been removed. This was intended solely for internal consumption by the debug module, and tied to internal details of the legacy representation of keys. If you need equivalent functionality in TF-PSA-Crypto, export the key. + +The auxiliary functions `mbedtls_pk_parse_subpubkey()` and `mbedtls_pk_write_pubkey()` are no longer exposed. Use `mbedtls_pk_parse_public_key()` and `mbedtls_pk_write_pubkey_der()` instead. + +## OID module + +The compilation option `MBEDTLS_OID_C` no longer exists. OID tables are included in the build automatically as needed for parsing and writing keys and signatures. + +TF-PSA-Crypto does not have interfaces to look up values by OID or OID by enum values. + +Functions to convert between binary and dotted string OID representations (`mbedtls_oid_get_numeric_string()` and `mbedtls_oid_from_numeric_string()`) are still available, but they are now in the X.509 library in Mbed TLS. The header file `` is now in Mbed TLS, not in TF-PSA-Crypto. + +TF-PSA-Crypto does not expose OID values through macros, the way Mbed TLS 3.x and earlier did. + +## Changes to the PAKE interface + +The PAKE interface in TF-PSA-Crypto 1.0 has been updated to match PSA Crypto API [1.2 Final](https://arm-software.github.io/psa-api/crypto/1.2/ext-pake/) PAKE extension, which is the same version that has been integrated into the main specification of PSA Crypto [version 1.3](https://arm-software.github.io/psa-api/crypto/1.3/). + +In Mbed TLS 3.6, the PAKE interface implemented version [1.1 Beta](https://arm-software.github.io/psa-api/crypto/1.1/ext-pake/) of the PAKE extension. There has been a number of [changes between the beta and the final version](https://arm-software.github.io/psa-api/crypto/1.2/ext-pake/appendix/history.html#changes-between-beta-1-and-final) of the API. The changes that require applications to update their code are detailed in the following subsections. + +Note that TF-PSA-Crypto 1.0 still only implements `PSA_ALG_JPAKE` (and only on elliptic curves, specifically only on secp256r1). Support for SPAKE2+ is likely to be added in a future version but is not there yet. + +### Combine `psa_pake_set_password_key()` with `psa_pake_setup()` + +The function `psa_pake_set_password_key()` has been removed. Its `key` argument is now passed to `psa_pake_setup()` which has gained a new `key` parameter. + +Before: + +``` +status = psa_pake_setup(&operation, &cipher_suite); +if (status != PSA_SUCCESS) // error handling omitted for brevity +status = psa_pake_set_password_key(&operation, key); +if (status != PSA_SUCCESS) // error handling omitted for brevity +``` + +Now: + +``` +status = psa_pake_setup(&operation, key, &cipher_suite); +if (status != PSA_SUCCESS) // error handling omitted for brevity +``` + +### Move the hash algorithm parameter into the algorithm identifier + +The function `psa_pake_cs_set_hash()` has been removed. Its `hash` argument is now passed to `PSA_ALG_JPAKE()` which is now a function-like macro with one parameter. + +Before: + +``` +psa_pake_cs_set_algorithm(&cipher_suite, PSA_ALG_JPAKE); +psa_pake_cs_set_hash(&cipher_suite, PSA_ALG_SHA_256); +``` + +Now: + +``` +psa_pake_cs_set_algorithm(&cipher_suite, PSA_ALG_JPAKE(PSA_ALG_SHA_256)); +``` + +To check if a given algorithm is J-PAKE, the new `PSA_ALG_IS_JPAKE()` macro has been added. + +Before: `if (alg == PSA_ALG_JPAKE)` + +Now: `if (PSA_ALG_IS_JPAKE(alg))` + +The function `psa_pake_cs_get_hash()` has also been removed. + +### Replace `psa_pake_get_implicit_key()` with `psa_pake_get_shared_key()` + +The function `psa_pake_get_implicit_key()`, which injects the shared secret into a key derivation operation, has been removed. Its replacement is `psa_pake_get_shared_key()` which stores the shared secret in a new key. That new key can then be used as part of a key derivation operation. + +Before: + +``` +// omitted: set up pake_op and do the PAKE key exchange + +psa_algorithm_t alg = PSA_ALG_TLS12_ECJPAKE_TO_PMS; // for example +psa_key_derivation_operation_t derivation = PSA_KEY_DERIVATION_OPERATION_INIT; +status = psa_key_derivation_setup(&derivation, alg); +if (status != PSA_SUCCESS) // error handling omitted for brevity + +status = psa_pake_get_implicit_key(&pake_op, &derivation); +if (status != PSA_SUCCESS) // error handling omitted for brevity + +// omitted: finish key derivation (output/verify, then abort) +``` + +Now: + +``` +// omitted: set up pake_op and do the PAKE key exchange + +psa_algorithm_t alg = PSA_ALG_TLS12_ECJPAKE_TO_PMS; // for example +psa_key_derivation_operation_t derivation = PSA_KEY_DERIVATION_OPERATION_INIT; +status = psa_key_derivation_setup(&derivation, alg); +if (status != PSA_SUCCESS) // error handling omitted for brevity + +psa_key_id_t shared_key_id = (psa_key_id_t) 0; +psa_key_attributes_t shared_key_attributes = PSA_KEY_ATTRIBUTES_INIT; +psa_set_key_usage_flags(&shared_key_attributes, PSA_KEY_USAGE_DERIVE); +psa_set_key_algorithm(&shared_key_attributes, alg); // same as derivation +psa_set_key_type(&shared_key_attributes, PSA_KEY_TYPE_DERIVE); + +status = psa_pake_get_shared_key(&pake_op, + &shared_key_attributes, + &shared_key_id); +if (status != PSA_SUCCESS) // error handling omitted for brevity +psa_reset_key_attributes(&shared_key_attributes); + +status = psa_key_derivation_input_key(&derivation_op, + PSA_KEY_DERIVATION_INPUT_SECRET, + shared_key_id); +if (status != PSA_SUCCESS) // error handling omitted for brevity + +// omitted: finish key derivation (output/verify, then abort) + +psa_destroy_key(shared_key_id); // after key derivation is complete +``` + +Note that the new function is more flexible: instead of using the shared secret +only for key derivation, you can also directly use it as an HMAC key by setting +the appropriate key type and policy, for example: + +``` +psa_key_id_t shared_key_id = (psa_key_id_t) 0; +psa_algorithm_t alg = PSA_ALG_HMAC(PSA_ALG_SHA_256); // or other hash + +psa_key_attributes_t shared_key_attributes = PSA_KEY_ATTRIBUTES_INIT; +psa_set_key_usage_flags(&shared_key_attributes, PSA_KEY_USAGE_SIGN_MESSAGE); + // or VERIFY_MESSAGE +psa_set_key_algorithm(&shared_key_attributes, alg); +psa_set_key_type(&shared_key_attributes, PSA_KEY_TYPE_HMAC); + +status = psa_pake_get_shared_key(&pake_op, + &shared_key_attributes, + &shared_key_id); +if (status != PSA_SUCCESS) // error handling omitted for brevity +``` + +See [the specification](https://arm-software.github.io/psa-api/crypto/1.3/api/ops/pake.html#c.psa_pake_get_shared_key) for details. Note that the J-PAKE shared secret is not uniformly pseudorandom, so it can only be used for key derivation and HMAC. + +### Persistent keys with a PAKE policy + +TF-PSA-Crypto can read persistent keys created with an algorithm policy that specifies the Mbed TLS 3.x encoding of `PSA_ALG_JPAKE`. Such a policy now allows cipher suites with `PSA_ALG_JPAKE(hash_alg)` for any hash algorithm. It appears as `PSA_ALG_JPAKE_BETA` when querying the policy with `psa_get_key_algorithm()`. + +### Remaining limitations to JPAKE in TF-PSA-Crypto 1.0.0 + +The following limitations apply to both Mbed TLS 3.x and TF-PSA-Crypto 1.0.0: + +- The [only supported primitive](https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/503) is ECC on the curve secp256r1, i.e. `PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256)`. +- The [only supported hash algorithm](https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/504) is SHA-256, i.e. `PSA_ALG_SHA_256`. +- When using the built-in implementation, [the user ID and the peer ID](https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/502) must be `"client"` (6-byte string) or `"server"` (6-byte string). + Third-party drivers may or may not have this limitation. diff --git a/tf-psa-crypto/docs/4.0-migration-guide/README b/tf-psa-crypto/docs/4.0-migration-guide/README new file mode 100644 index 0000000000..6122f56477 --- /dev/null +++ b/tf-psa-crypto/docs/4.0-migration-guide/README @@ -0,0 +1,22 @@ +This directory contains sections intended for the migration guide +from Mbed TLS 3.6 to TF-PSA-Crypto 1.0 + Mbed TLS 4.0. + +The files in this document should be markdown files with the .md +extension. They should generally contain level-2 sections (## title). +The files will be consolidated into a single cohesive document or +document set shortly before the .0 releases. + +The reason to have multiple files is that each strand of work can create +one file, without worrying about where to fit in the document structure. +We'll worry about the general structure once we have the content. +Furthermore, placing different strands of work in separate files will +avoid merge conflicts (as would happen e.g. if parallel strands of +work append to the same file in concurrent pull requests). + +Files can be placed in the docs/4.0-migration-guide indifferently in +mbedtls or TF-PSA-Crypto, as convenient. + +Documentation that is specifically about migrating from the legacy +crypto API to the PSA crypto API should be added to the existing +docs/psa-transition.md instead. + diff --git a/tf-psa-crypto/docs/4.0-migration-guide/configuration.md b/tf-psa-crypto/docs/4.0-migration-guide/configuration.md new file mode 100644 index 0000000000..aaf8f2e7eb --- /dev/null +++ b/tf-psa-crypto/docs/4.0-migration-guide/configuration.md @@ -0,0 +1,36 @@ +## Compile-time configuration + +### Configuration file split + +Whether you are using TF-PSA-Crypto as a standalone project or as part of Mbed TLS, all the configuration options that are relevant to TF-PSA-Crypto must be configured in one of its configuration files, namely: + +* `TF_PSA_CRYPTO_CONFIG_FILE`, if set on the preprocessor command line; +* otherwise ``; +* additionally `TF_PSA_CRYPTO_USER_CONFIG_FILE`, if set. + +The macros `MBEDTLS_PSA_CRYPTO_CONFIG_FILE` and `MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE` are no longer recognized. Use `TF_PSA_CRYPTO_CONFIG_FILE` and `TF_PSA_CRYPTO_USER_CONFIG_FILE` instead + +Configuration options that are relevant to X.509 or TLS should still be set in the Mbed TLS configuration file (`MBEDTLS_CONFIG_FILE` or ``, plus `MBEDTLS_USER_CONFIG_FILE` if it is set). However, you can define all options in the crypto configuration, and Mbed TLS will pick them up. + +Generally speaking, the options that must be configured in TF-PSA-Crypto are: + +* options related to platform settings; +* options related to the choice of cryptographic mechanisms included in the build; +* options related to the inner workings of cryptographic mechanisms, such as size/memory/performance compromises; +* options related to crypto-adjacent features, such as ASN.1 and Base64. + +See `include/psa/crypto_config.h` in TF-PSA-Crypto and `include/mbedtls/mbedtls_config.h` in Mbed TLS for details. + +Notably, `` is no longer limited to `PSA_WANT_xxx` options. + +Note that many options related to cryptography have changed; this is covered in other sections of this document. + +### Split of `build_info.h` and `version.h` + +TF-PSA-Crypto has a header file `` which includes the configuration file and provides the adjusted configuration macros, similar to `` in Mbed TLS. + +TF-PSA-Crypto exposes its version through ``, similar to `` in Mbed TLS. + +### Removal of `check_config.h` + +The header `mbedtls/check_config.h` is no longer present. Including it from user configuration files was already obsolete in Mbed TLS 3.x, since it enforces properties of the configuration as adjusted by `mbedtls/build_info.h`, not properties that the user configuration is expected to meet. diff --git a/tf-psa-crypto/docs/4.0-migration-guide/error-codes.md b/tf-psa-crypto/docs/4.0-migration-guide/error-codes.md new file mode 100644 index 0000000000..d7e5394aed --- /dev/null +++ b/tf-psa-crypto/docs/4.0-migration-guide/error-codes.md @@ -0,0 +1,77 @@ +## Error codes + +### Unified error code space + +The convention still applies that functions return 0 for success and a negative value between -32767 and -1 on error. PSA functions (`psa_xxx()` or `mbedtls_psa_xxx()`) still return a `PSA_ERROR_xxx` error codes. Non-PSA functions (`mbedtls_xxx()` excluding `mbedtls_psa_xxx()`) can return either `PSA_ERROR_xxx` or `MBEDTLS_ERR_xxx` error codes. + +There may be cases where an `MBEDTLS_ERR_xxx` constant has the same numerical value as a `PSA_ERROR_xxx`. In such cases, they have the same meaning: they are different names for the same error condition. + +### Simplified legacy error codes + +All values returned by a function to indicate an error now have a defined constant named `MBEDTLS_ERR_xxx` or `PSA_ERROR_xxx`. Functions no longer return the sum of a “low-level” and a “high-level” error code. + +Generally, functions that used to return the sum of two error codes now return the low-level code. However, as before, the exact error code returned in a given scenario can change without notice unless the condition is specifically described in the function's documentation and no other condition is applicable. + +As a consequence, the functions `mbedtls_low_level_strerr()` and `mbedtls_high_level_strerr()` no longer exist. + +### Removed English error messages + +TF-PSA-Crypto does not provide English text corresponding to error codes. The functionality provided by `mbedtls_strerror()` in `mbedtls/error.h` is still present in Mbed TLS. + +### Removed error code names + +Many legacy error codes have been removed in favor of PSA error codes. Generally, functions that returned a legacy error code in the table below in Mbed TLS 3.6 now return the PSA error code listed on the same row. Similarly, callbacks should apply the same changes to error code, unless there has been a relevant change to the callback's interface. + +| Legacy constant (Mbed TLS 3.6) | PSA constant (TF-PSA-Crypto 1.0) | +|--------------------------------------------|----------------------------------| +| `MBEDTLS_ERR_AES_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_ARIA_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_ASN1_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` | +| `MBEDTLS_ERR_ASN1_BUF_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` | +| `MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` | +| `MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_CCM_AUTH_FAILED` | `PSA_ERROR_INVALID_SIGNATURE` | +| `MBEDTLS_ERR_CCM_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED` | `PSA_ERROR_INVALID_SIGNATURE` | +| `MBEDTLS_ERR_CIPHER_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` | +| `MBEDTLS_ERR_CIPHER_AUTH_FAILED` | `PSA_ERROR_INVALID_SIGNATURE` | +| `MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_CIPHER_INVALID_PADDING` | `PSA_ERROR_INVALID_PADDING` | +| `MBEDTLS_ERR_ECP_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` | +| `MBEDTLS_ERR_ECP_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` | +| `MBEDTLS_ERR_ECP_IN_PROGRESS` | `PSA_OPERATION_INCOMPLETE` | +| `MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH` | `PSA_ERROR_INVALID_SIGNATURE` | +| `MBEDTLS_ERR_ECP_VERIFY_FAILED` | `PSA_ERROR_INVALID_SIGNATURE` | +| `MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED` | `PSA_ERROR_CORRUPTION_DETECTED` | +| `MBEDTLS_ERR_ERROR_GENERIC_ERROR` | `PSA_ERROR_GENERIC_ERROR` | +| `MBEDTLS_ERR_GCM_AUTH_FAILED` | `PSA_ERROR_INVALID_SIGNATURE` | +| `MBEDTLS_ERR_GCM_BAD_INPUT` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_GCM_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` | +| `MBEDTLS_ERR_LMS_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` | +| `MBEDTLS_ERR_LMS_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` | +| `MBEDTLS_ERR_MD_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` | +| `MBEDTLS_ERR_MD_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_MPI_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` | +| `MBEDTLS_ERR_MPI_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` | +| `MBEDTLS_ERR_OID_NOT_FOUND` | `PSA_ERROR_NOT_SUPPORTED` | +| `MBEDTLS_ERR_PEM_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` | +| `MBEDTLS_ERR_PEM_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_PK_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` | +| `MBEDTLS_ERR_PK_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_PK_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` | +| `MBEDTLS_ERR_PK_SIG_LEN_MISMATCH` | `PSA_ERROR_INVALID_SIGNATURE` | +| `MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED` | `PSA_ERROR_NOT_SUPPORTED` | +| `MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED` | `PSA_ERROR_HARDWARE_FAILURE` | +| `MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_RSA_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_RSA_INVALID_PADDING` | `PSA_ERROR_INVALID_PADDING` | +| `MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE` | `PSA_ERROR_BUFFER_TOO_SMALL` | +| `MBEDTLS_ERR_SHA1_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_SHA256_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_SHA3_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | +| `MBEDTLS_ERR_SHA512_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` | diff --git a/tf-psa-crypto/docs/4.0-migration-guide/feature-removals.md b/tf-psa-crypto/docs/4.0-migration-guide/feature-removals.md new file mode 100644 index 0000000000..204b51290f --- /dev/null +++ b/tf-psa-crypto/docs/4.0-migration-guide/feature-removals.md @@ -0,0 +1,32 @@ +## Feature removals + +### Removal of self-test interfaces + +TF-PSA-Crypto 1.0 does not provide a ready-made self-test interface; one may be added in a future version of the library. + +If you need self-tests for compliance, you may perform them by invoking normal API functions with sample data. + +As a consequence, the compilation option `MBEDTLS_SELF_TEST` does not provide direct benefits in TF-PSA-Crypto 1.0. However, it allows the sample program `programs/test/selftest.c` in Mbed TLS to run self tests of cryptographic mechanisms. + +### Removed hardware support + +Acceleration for VIA Padlock (`MBEDTLS_PADLOCK_C`) is no longer provided. + +The deprecated and incomplete support for dynamic registration of secure element drivers (`MBEDTLS_PSA_CRYPTO_SE_C`) has been removed. Use compile-time secure element drivers instead. + +See also [the removal of ALT interfaces](#removal-of-alternative-cryptographic-module-implementations). + +### Removed obsolete cryptographic mechanisms + +Some obsolescent cryptographic mechanisms have been removed: + +* The library no longer supports DES (including 3DES). All supported block ciphers now have 128-bit blocks. As a consequence, the PKCS12 module, which provided the obsolete PBE mode for private key encryption that does not support stronger ciphers, has been removed. +* The library no longer supports elliptic curves whose size is 224 bits or less. The following curves are no longer supported: secp192r1, secp192k1, secp224k1, secp224r1. Use larger curves such as secp256r1. + +### Removed obsolete PSA functions + +Some PSA Crypto API functions dating back from before the 1.0 version of the API, or that were experimental, have been removed: + +* `psa_open_key()`, `psa_close_key()`, and auxiliary functions and macros related to handles. Persistent keys are opened implicitly since Mbed TLS 2.25. +* `psa_set_key_domain_parameters()`, `psa_get_key_domain_parameters()` and related macros. This feature was primarily intended to support custom finite-field Diffie-Hellman (FFDH) groups, but this was never implemented. To generate an RSA key with a custom public exponent, use `psa_generate_key_custom()`, introduced in Mbed TLS 3.6.1. +* `psa_generate_key_ext()`, `psa_key_derivation_output_key_ext` and related types and macros. Use `psa_generate_key_custom()` or `psa_key_derivation_output_key_custom()` instead. diff --git a/tf-psa-crypto/docs/4.0-migration-guide/function-prototype-changes.md b/tf-psa-crypto/docs/4.0-migration-guide/function-prototype-changes.md new file mode 100644 index 0000000000..6f8f9b237d --- /dev/null +++ b/tf-psa-crypto/docs/4.0-migration-guide/function-prototype-changes.md @@ -0,0 +1,162 @@ +## Function prototype changes + +A number of existing functions now take a different list of arguments, mostly to migrate them to the PSA API. + +### Public functions no longer take a RNG callback + +Functions that need randomness no longer take an RNG callback in the form of `f_rng, p_rng` arguments. Instead, they use the PSA Crypto random generator (accessible as `psa_generate_random()`). All software using the LMS or PK modules must call `psa_crypto_init()` before calling any of the functions listed here. + +### RNG removal in LMS + +The following function prototypes have been changed in `mbedtls/lms.h`: + +```c +int mbedtls_lms_generate_private_key(mbedtls_lms_private_t *ctx, mbedtls_lms_algorithm_type_t type, mbedtls_lmots_algorithm_type_t otstype, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *seed, size_t seed_size); + +int mbedtls_lms_sign(mbedtls_lms_private_t *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *msg, unsigned int msg_size, unsigned char *sig, size_t sig_size, size_t *sig_len); +``` + + +to + +```c +int mbedtls_lms_generate_private_key(mbedtls_lms_private_t *ctx, mbedtls_lms_algorithm_type_t type, mbedtls_lmots_algorithm_type_t otstype, + const unsigned char *seed, size_t seed_size); + +int mbedtls_lms_sign(mbedtls_lms_private_t *ctx, + const unsigned char *msg, unsigned int msg_size, unsigned char *sig, size_t sig_size, size_t *sig_len); +``` + +### RNG removal in PK + +The following function prototypes have been changed in `mbedtls/pk.h`: + +```c +int mbedtls_pk_sign_restartable(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_pk_restart_ctx *rs_ctx); + +int mbedtls_pk_check_pair(const mbedtls_pk_context *pub, const mbedtls_pk_context *prv, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +int mbedtls_pk_sign(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng); + +int mbedtls_pk_sign_ext(mbedtls_pk_type_t pk_type, mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +int mbedtls_pk_parse_key(mbedtls_pk_context *ctx, const unsigned char *key, size_t keylen, const unsigned char *pwd, size_t pwdlen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng); + +int mbedtls_pk_parse_keyfile(mbedtls_pk_context *ctx, const char *path, const char *password, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng); + +typedef int (*mbedtls_pk_rsa_alt_sign_func)(void *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash, unsigned char *sig); +``` + +to + +```c +int mbedtls_pk_sign_restartable(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len, + mbedtls_pk_restart_ctx *rs_ctx); + +int mbedtls_pk_check_pair(const mbedtls_pk_context *pub, const mbedtls_pk_context *prv); + +int mbedtls_pk_sign(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len); + +int mbedtls_pk_sign_ext(mbedtls_pk_type_t pk_type, mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len); + +int mbedtls_pk_parse_key(mbedtls_pk_context *ctx, const unsigned char *key, size_t keylen, const unsigned char *pwd, size_t pwdlen); + +int mbedtls_pk_parse_keyfile(mbedtls_pk_context *ctx, const char *path, const char *password); + +typedef int (*mbedtls_pk_rsa_alt_sign_func)(void *ctx, + mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash, unsigned char *sig); +``` + +### Changes to NIST_KW + +The NIST\_KW module remains part of TF-PSA-Crypto, since it does not have a PSA equivalent yet. However, its interface has changed, to use PSA key identifiers instead of a plaintext key via a custom context. + +The following function prototypes have been changed in `mbedtls/nist_kw.h`: + +```c +int mbedtls_nist_kw_wrap(mbedtls_nist_kw_context *ctx, + mbedtls_nist_kw_mode_t mode, + const unsigned char *input, size_t in_len, + unsigned char *output, size_t *out_len, size_t out_size); +int mbedtls_nist_kw_unwrap(mbedtls_nist_kw_context *ctx, + mbedtls_nist_kw_mode_t mode, + const unsigned char *input, size_t in_len, + unsigned char *output, size_t *out_len, size_t out_size); +``` + +to + +```c +psa_status_t mbedtls_nist_kw_wrap(mbedtls_svc_key_id_t key, + mbedtls_nist_kw_mode_t mode, + const unsigned char *input, size_t input_length, + unsigned char *output, size_t output_size, + size_t *output_length); +psa_status_t mbedtls_nist_kw_unwrap(mbedtls_svc_key_id_t key, + mbedtls_nist_kw_mode_t mode, + const unsigned char *input, size_t input_length, + unsigned char *output, size_t output_size, + size_t *output_length); +``` + +Note that in addition to the change to keys, the last two parameters for the output buffer size and the length of the actual output have been swapped, to align the order of parameters with PSA Crypto APIs. + +The type `mbedtls_nist_kw_context` and the functions `mbedtls_nist_kw_init()`, `mbedtls_nist_kw_free()` and `mbedtls_nist_kw_setkey()` have been removed, since the interface no longer involves a specific context object for NIST\_KW. + +Also, the function `mbedtls_nist_kw_self_test()` has been removed. TF-PSA-Crypto 1.0 does not provide a ready-made self-test interface; one may be added in a future version of the library. + +### Changes to ASN.1 functions + +As a consequence of the removal of the type `mbedtls_mpi` (provided by `mbedtls/bignum.h`) from public interfaces, the ASN.1 functions to parse and write integers have changed. + +The following functions have been removed from the API: + +```c +// mbedtls/asn1.h +int mbedtls_asn1_get_mpi(unsigned char **p, const unsigned char *end, + mbedtls_mpi *X); + +// mbedtls/asn1write.h +int mbedtls_asn1_write_mpi(unsigned char **p, const unsigned char *start, + const mbedtls_mpi *X); +``` + +You can use the following new functions instead: + +```c +// mbedtls/asn1.h +int mbedtls_asn1_get_integer(unsigned char **p, const unsigned char *end, + unsigned char **head, size_t *length); + +// mbedtls/asn1write.h +int mbedtls_asn1_write_integer(unsigned char **p, + unsigned char *start, + const unsigned char *integer, + size_t integer_length); +``` + +Both new functions use a big-endian byte buffer as the representation. + +Note some differences in the semantics of the new parsing function: + +* `mbedtls_asn1_get_integer()` rejects negative integers. (`mbedtls_asn1_get_mpi()` misparsed them, using the sign bit as a value bit). +* `mbedtls_asn1_get_integer()` does not allocate memory. It returns a pointer inside the ASN.1 representation. diff --git a/tf-psa-crypto/docs/4.0-migration-guide/md.md b/tf-psa-crypto/docs/4.0-migration-guide/md.md new file mode 100644 index 0000000000..af54e6c191 --- /dev/null +++ b/tf-psa-crypto/docs/4.0-migration-guide/md.md @@ -0,0 +1,10 @@ +## Reduced `md.h` + +PSA is now the preferred interface for computing hashes and HMAC. See [“Hashes and MAC” in the PSA transition guide](psa-transition.md#hashes-and-mac) for more information. + +TF-PSA-Crypto 1.x still has a header file `` to facilitate the transition. Its functionality is limited to calculating hashes: + +* `mbedtls_md_setup()` now requires the `hmac` parameter to be 0. Use the PSA API for HMAC calculations. +* The HMAC functions `mbedtls_md_hmac_xxx()` are no longer available. +* The metadata functions `mbedtls_md_list()`, `mbedtls_md_info_from_string()`, `mbedtls_md_get_name()` and `mbedtls_md_info_from_ctx()` have been removed. The library does not associate names to individual algorithms any longer. +* The function `mbedtls_md_file()` has been removed. To hash a file, load it into memory manually. Load it piecewise and call `mbedtls_md_update()` or `psa_hash_update()` in a loop if the file may be large. diff --git a/tf-psa-crypto/docs/4.0-migration-guide/oid.md b/tf-psa-crypto/docs/4.0-migration-guide/oid.md new file mode 100644 index 0000000000..66e2ac61e1 --- /dev/null +++ b/tf-psa-crypto/docs/4.0-migration-guide/oid.md @@ -0,0 +1,9 @@ +## OID module + +The compilation option `MBEDTLS_OID_C` no longer exists. OID tables are included in the build automatically as needed for parsing and writing keys and signatures. + +TF-PSA-Crypto does not have interfaces to look up values by OID or OID by enum values. + +Functions to convert between binary and dotted string OID representations (`mbedtls_oid_get_numeric_string()` and `mbedtls_oid_from_numeric_string()`) are still available, but they are now in the X.509 library in Mbed TLS. The header file `` is now in Mbed TLS, not in TF-PSA-Crypto. + +TF-PSA-Crypto does not expose OID values through macros, the way Mbed TLS 3.x and earlier did. diff --git a/tf-psa-crypto/docs/4.0-migration-guide/pake.md b/tf-psa-crypto/docs/4.0-migration-guide/pake.md new file mode 100644 index 0000000000..6026dc6d2a --- /dev/null +++ b/tf-psa-crypto/docs/4.0-migration-guide/pake.md @@ -0,0 +1,126 @@ +## Changes to the PAKE interface + +The PAKE interface in TF-PSA-Crypto 1.0 has been updated to match PSA Crypto API [1.2 Final](https://arm-software.github.io/psa-api/crypto/1.2/ext-pake/) PAKE extension, which is the same version that has been integrated into the main specification of PSA Crypto [version 1.3](https://arm-software.github.io/psa-api/crypto/1.3/). + +In Mbed TLS 3.6, the PAKE interface implemented version [1.1 Beta](https://arm-software.github.io/psa-api/crypto/1.1/ext-pake/) of the PAKE extension. There has been a number of [changes between the beta and the final version](https://arm-software.github.io/psa-api/crypto/1.2/ext-pake/appendix/history.html#changes-between-beta-1-and-final) of the API. The changes that require applications to update their code are detailed in the following subsections. + +Note that TF-PSA-Crypto 1.0 still only implements `PSA_ALG_JPAKE` (and only on elliptic curves, specifically only on secp256r1). Support for SPAKE2+ is likely to be added in a future version but is not there yet. + +### Combine `psa_pake_set_password_key()` with `psa_pake_setup()` + +The function `psa_pake_set_password_key()` has been removed. Its `key` argument is now passed to `psa_pake_setup()` which has gained a new `key` parameter. + +Before: + +``` +status = psa_pake_setup(&operation, &cipher_suite); +if (status != PSA_SUCCESS) // error handling ommited for brevity +status = psa_pake_set_password_key(&operation, key); +if (status != PSA_SUCCESS) // error handling ommited for brevity +``` + +Now: + +``` +status = psa_pake_setup(&operation, key, &cipher_suite); +if (status != PSA_SUCCESS) // error handling ommited for brevity +``` + +### Move the hash algorithm parameter into the algorithm identifier + +The function `psa_pake_cs_set_hash()` has been removed. Its `hash` argument is now passed to `PSA_ALG_JPAKE()` which is now a function-like macro with one parameter. + +Before: + +``` +psa_pake_cs_set_algorithm(&cipher_suite, PSA_ALG_JPAKE); +psa_pake_cs_set_hash(&cipher_suite, PSA_ALG_SHA_256); +``` + +Now: + +``` +psa_pake_cs_set_algorithm(&cipher_suite, PSA_ALG_JPAKE(PSA_ALG_SHA_256)); +``` + +To check if a given algorithm is J-PAKE, the new `PSA_ALG_IS_JPAKE()` macro has been added. + +Before: `if (alg == PSA_ALG_JPAKE)` + +Now: `if (PSA_ALG_IS_JPAKE(alg))` + +The function `psa_pake_cs_get_hash()` has also been removed. + +### Replace `psa_pake_get_implicit_key()` with `psa_pake_get_shared_key()` + +The function `psa_pake_get_implicit_key()`, which injects the shared secret into a key derivation operation, has been removed. Its replacement is `psa_pake_get_shared_key()` which stores the shared secret in a new key. That new key can then be used as part of a key derivation operation. + +Before: + +``` +// ommited: set up pake_op and do the PAKE key exchange + +psa_algorithm_t alg = PSA_ALG_TLS12_ECJPAKE_TO_PMS; // for example +psa_key_derivation_operation_t derivation = PSA_KEY_DERIVATION_OPERATION_INIT; +status = psa_key_derivation_setup(&derivation, alg); +if (status != PSA_SUCCESS) // error handling ommited for brevity + +status = psa_pake_get_implicit_key(&pake_op, &derivation); +if (status != PSA_SUCCESS) // error handling ommited for brevity + +// ommited: finish key derivation (output/verify, then abort) +``` + +Now: + +``` +// ommited: set up pake_op and do the PAKE key exchange + +psa_algorithm_t alg = PSA_ALG_TLS12_ECJPAKE_TO_PMS; // for example +psa_key_derivation_operation_t derivation = PSA_KEY_DERIVATION_OPERATION_INIT; +status = psa_key_derivation_setup(&derivation, alg); +if (status != PSA_SUCCESS) // error handling ommited for brevity + +psa_key_id_t shared_key_id = (psa_key_id_t) 0; +psa_key_attributes_t shared_key_attributes = PSA_KEY_ATTRIBUTES_INIT; +psa_set_key_usage_flags(&shared_key_attributes, PSA_KEY_USAGE_DERIVE); +psa_set_key_algorithm(&shared_key_attributes, alg); // same as derivation +psa_set_key_type(&shared_key_attributes, PSA_KEY_TYPE_DERIVE); + +status = psa_pake_get_shared_key(&pake_op, + &shared_key_attributes, + &shared_key_id); +if (status != PSA_SUCCESS) // error handling ommited for brevity +psa_reset_key_attributes(&shared_key_attributes); + +status = psa_key_derivation_input_key(&derivation_op, + PSA_KEY_DERIVATION_INPUT_SECRET, + shared_key_id); +if (status != PSA_SUCCESS) // error handling ommited for brevity + +// ommited: finish key derivation (output/verify, then abort) + +psa_destroy_key(shared_key_id); // after key derivation is complete +``` + +Note that the new function is more flexible: instead of using the shared secret +only for key derivation, you can also directly use it as an HMAC key by setting +the appropriate key type and policy, for example: + +``` +psa_key_id_t shared_key_id = (psa_key_id_t) 0; +psa_algorithm_t alg = PSA_ALG_HMAC(PSA_ALG_SHA_256); // or other hash + +psa_key_attributes_t shared_key_attributes = PSA_KEY_ATTRIBUTES_INIT; +psa_set_key_usage_flags(&shared_key_attributes, PSA_KEY_USAGE_SIGN_MESSAGE); + // or VERIFY_MESSAGE +psa_set_key_algorithm(&shared_key_attributes, alg); +psa_set_key_type(&shared_key_attributes, PSA_KEY_TYPE_HMAC); + +status = psa_pake_get_shared_key(&pake_op, + &shared_key_attributes, + &shared_key_id); +if (status != PSA_SUCCESS) // error handling ommited for brevity +``` + +See [the specification](https://arm-software.github.io/psa-api/crypto/1.3/api/ops/pake.html#c.psa_pake_get_shared_key) for details. Note that the J-PAKE shared secret is not uniformly pseudorandom, so it can only be used for key derivation and HMAC. diff --git a/tf-psa-crypto/docs/4.0-migration-guide/pk.md b/tf-psa-crypto/docs/4.0-migration-guide/pk.md new file mode 100644 index 0000000000..65a2b59f01 --- /dev/null +++ b/tf-psa-crypto/docs/4.0-migration-guide/pk.md @@ -0,0 +1,85 @@ +## PK module + +The PK module for asymmetric cryptography is still present in TF-PSA-Crypto 1.x, but with a somewhat reduced scope compared to Mbed TLS. The main goal of PK is now to parse and format key pairs and public keys. PK also retains signature functions, to facilitate the transition from previous versions. The main differences compared to Mbed TLS 3.6 and below are: + +* PK objects no longer expose the underlying representation. It is now unspecified in most cases whether a PK object stores key material directly, or a PSA key identifier. +* PK objects no longer have any policy attached to them. This mostly affects RSA keys, which no longer “remember” whether they are meant to be used with PKCS#1v1.5 or PSS/OAEP. + +### Changes to PK metadata + +The type `mbedtls_pk_type_t` has been removed from the API. This type could convey different kinds of information, depending on where it was used: + +* Information about the representation of a PK context (distinguishing between transparent and opaque objects containing the same type of key). This information is no longer exposed. + +* Which signature algorithm to use (distinguishing between PKCS#1v1.5 and PSS for RSA keys), mostly for the sake of X.509. This information is now represented as `mbedtls_pk_sigalg_t`, using enum constants with tweaked names: + + | Old `mbedtls_pk_type_t` name | New `mbedtls_pk_sigalg_t` name | + | ---------------------------- | ------------------------------ | + | `MBEDTLS_PK_NONE` | `MBEDTLS_PK_SIGALG_NONE` | + | `MBEDTLS_PK_RSA` | `MBEDTLS_PK_SIGALG_RSA_PKCS1V15` | + | `MBEDTLS_PK_RSASSA_PSS` | `MBEDTLS_PK_SIGALG_RSA_PSS` | + | `MBEDTLS_PK_ECDSA` or `MBEDTLS_PK_ECKEY` | `MBEDTLS_PK_SIGALG_ECDSA` | + +* Policy information after parsing a key (only relevant for ECC keys marked as ECDH-only). This is now tracked internally and reflected in rejecting the key for signature or verification in `mbedtls_pk_get_psa_attributes()` and in operation functions. + + +As a consequence, the functions `mbedtls_pk_get_type()`, `mbedtls_pk_get_name()` and `mbedtls_pk_info_from_type()` and have been removed. The type `mbedtls_pk_info_t` is no longer part of the API. + +The function `mbedtls_pk_get_len()` has also been removed. It was not very meaningful since it did not convey the length of the key representation, but the size in bytes of the representation of one number associated with the key. As before, you can use `mbedtls_pk_get_bitlen()` to get the key size in the usual cryptographic sense. The size of a formatted key representation depends on the format, and there is no API function to determine it. (For the short export formats of PSA, you can use macros such as `PSA_EXPORT_KEY_OUTPUT_SIZE()`, `PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE()`, `PSA_EXPORT_KEY_PAIR_MAX_SIZE`, `PSA_EXPORT_PUBLIC_KEY_MAX_SIZE`.) + +### Checking the capabilities of a PK context + +The function `mbedtls_pk_can_do()`, based on the polysemic `mbedtls_pk_type_t`, has been removed. The function `mbedtls_pk_can_do_ext()`, based on PSA metadata, has been renamed to `mbedtls_pk_can_do_psa()`. It now supports public-key operations as well as private-key operations. + +### Loss of policy information for RSA keys + +The PK module no longer partially keeps track of whether an RSA key is intended for use with PKCS#1v1.5 or PKCS#1v2.1 (PSS or OAEP) algorithms. Functions that consume a PK object (`mbedtls_pk_get_psa_attributes()`, `mbedtls_pk_sign()`, `mbedtls_pk_verify()`) now always default to PKCS#1v1.5, except for PK contexts populated with `mbedtls_pk_wrap_psa()` where they use the primary algorithm in the key's policy. + +Note in particular that the functions `mbedtls_pk_copy_from_psa()` and `mbedtls_pk_copy_public_from_psa()` are now equivalent to exporting and re-importing the key, losing all policy information. For example, calling `mbedtls_pk_copy_from_psa()` on a key whose policy specifies PSS as the single allowed algorithm, then calling `mbedtls_pk_sign()`, results in a PKCS#1v1.5 signature. Call `mbedtls_pk_sign_ext()` or `mbedtls_pk_verify_ext()` if you want to specify the signature algorithm explicitly. + +### Removal of transparent PK contexts + +It is no longer possible to directly inspect a PK context to act on its underlying RSA or ECC context. The representation of a key in PK is now always an implementation detail. + +As a consequence, the functions `mbedtls_pk_setup()`, `mbedtls_pk_rsa()` and `mbedtls_pk_ec()` have been removed. + +### Changes to opaque PK contexts + +The library no longer supports an alternative representation of RSA keys in PK (`MBEDTLS_PK_RSA_ALT_SUPPORT` compilation option, PK context type `MBEDTLS_PK_RSA_ALT`). See [“RSA-ALT interface” in the PSA transition guide](psa-transition.md#rsa-alt-interface). + +A PK object can still wrap around an PSA key, which was formerly known as “opaque” PK objects of type `MBEDTLS_PK_OPAQUE`. The function `mbedtls_pk_setup_opaque()` has been renamed to `mbedtls_pk_wrap_psa()`, to reflect the fact that the PSA key is not necessarily “opaque” in PSA terminology. The PK module now hides the distinction between “wrapping” and “non-wrapping” PK contexts as much as possible, and in particular there is no simple metadata query to distinguish “wrapping” keys like the former `mbedtls_pk_get_type()`. + +### Fewer operations in PK + +The functions `mbedtls_pk_encrypt()` and `mbedtls_pk_decrypt()` have been removed. Use `psa_asymmetric_encrypt()` and `psa_asymmetric_decrypt()` instead. See [“Asymmetric encryption and decryption” in the PSA transition guide](psa-transition.md#rsa-alt-interface) for more information. + +If you have a key as a PK context and you wish to use it with PSA operation functions, use the functions `mbedtls_pk_get_psa_attributes()` and `mbedtls_pk_import_into_psa()` to obtain a PSA key identifier. See the documentation of these functions or [“Creating a PSA key via PK” in the PSA transition guide](psa-transition.md#creating-a-psa-key-via-pk) for more information. + +### Miscellaneous changes to PK signature and verification + +The `type` argument to `mbedtls_pk_sign_ext()` and `mbedtls_pk_verify_ext()` now has the type `mbedtls_pk_sigalg_t`. See [“Changes to PK metadata”](#changes-to-pk-metadata). + +The function `mbedtls_pk_verify_ext()` no longer supports a custom salt length for RSA-PSS. It always allows signatures with any salt length. The PSA API offers `psa_verify_hash()` with `PSA_ALG_RSA_PSS` to enforce the most commonly used salt length. + +`MBEDTLS_ERR_PK_SIG_LEN_MISMATCH` is no longer a distinct error code. A valid signature with trailing garbage is now reported as an invalid signature with all algorithms. + +The PK module continues to favor deterministic ECDSA over randomized ECDSA when both are possible. This may change in the future. The new macro `MBEDTLS_PK_ALG_ECDSA(hash_alg)` indicates which variant PK favors. It is equivalent to either `PSA_ALG_DETERMINISTIC_ECDSA(hash_alg)` or `PSA_ALG_ECDSA(hash_alg)`. + +### Changes in resources consumed by PK objects + +The implementation of the type `mbedtls_pk_context` has changed in ways that do not directly affect functionality, but affect resource consumption and memory partitioning. + +Historically, at least in the default configuration, a PK context stored all the key material in a heap-allocated object. In TF-PSA-Crypto 1.0, a PK context now contains: + +* the public key, in a fixed-size buffer that is directly in the `mbedtls_pk_context` structure; +* the private key (if available), in the PSA key store. + +This may change in future minor versions of TF-PSA-Crypto. + +### Other miscellaneous changes in PK + +Since PSA has a built-in random generator, all `(f_rng, p_rng)` arguments to PK functions have been removed. + +`mbedtls_pk_debug()` and the associated types have been removed. This was intended solely for internal consumption by the debug module, and tied to internal details of the legacy representation of keys. If you need equivalent functionality in TF-PSA-Crypto, export the key. + +The auxiliary functions `mbedtls_pk_parse_subpubkey()` and `mbedtls_pk_write_pubkey()` are no longer exposed. Use `mbedtls_pk_parse_public_key()` and `mbedtls_pk_write_pubkey_der()` instead. diff --git a/tf-psa-crypto/docs/4.0-migration-guide/private-decls.md b/tf-psa-crypto/docs/4.0-migration-guide/private-decls.md new file mode 100644 index 0000000000..4d5d5dcd54 --- /dev/null +++ b/tf-psa-crypto/docs/4.0-migration-guide/private-decls.md @@ -0,0 +1,33 @@ +## Private declarations + +Since Mbed TLS 3.0, some things that are declared in a public header are not part of the stable application programming interface (API), but instead are considered private. Private elements may be removed or may have their semantics changed in a future minor release without notice. + +### Understanding private declarations in public headers + +In TF-PSA-Crypto 1.x, private elements in header files include: + +* Anything appearing in a header file whose path contains `/private` (unless re-exported and documented in another non-private header). +* Structure and union fields declared with `MBEDTLS_PRIVATE(field_name)` in the source code, and appearing as `private_field_name` in the rendered documentation. (This was already the case since Mbed TLS 3.0.) +* Any preprocessor macro that is not documented with a Doxygen comment. + In the source code, Doxygen comments start with `/**` or `/*!`. If a macro only has a comment above that starts with `/*`, the macro is considered private. + In the rendered documentation, private macros appear with only an automatically rendered parameter list, value and location, but no custom text. +* Any declaration that is guarded by the preprocessor macro `MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS`. + +### Usage of private declarations + +Some private declarations are present in public headers for technical reasons, because they need to be visible to the compiler. Others are present for historical reasons and may be cleaned up in later versions of the library. We strongly recommend against relying on these declarations, since they may be removed or may have their semantics changed without notice. + +Note that Mbed TLS 4.0 still relies on some private interfaces of TF-PSA-Crypto 1.0. We expect to remove this reliance gradually in future minor releases. + +Sample programs have not been fully updated yet and some of them might still +use APIs that are no longer public. You can recognize them by the fact that they +define the macro `MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS` (or +`MBEDTLS_ALLOW_PRIVATE_ACCESS`) at the very top (before including headers). When +you see one of these two macros in a sample program, be aware it has not been +updated and parts of it do not demonstrate current practice. + +We strongly recommend against defining `MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS` or +`MBEDTLS_ALLOW_PRIVATE_ACCESS` in your own application. If you do so, your code +may not compile or work with future minor releases. If there's something you +want to do that you feel can only be achieved by using one of these two macros, +please reach out on github or the mailing list. diff --git a/tf-psa-crypto/docs/4.0-migration-guide/private-decls/00README b/tf-psa-crypto/docs/4.0-migration-guide/private-decls/00README new file mode 100644 index 0000000000..9dae2fdf0f --- /dev/null +++ b/tf-psa-crypto/docs/4.0-migration-guide/private-decls/00README @@ -0,0 +1,5 @@ +Temporary sub-directory to avoid conflicts in private-decls.md. +Will be merged back to private-decls.md as part of +https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/232 + +One file per header, with .md extension (and valid markdown content). diff --git a/tf-psa-crypto/docs/4.0-migration-guide/psa-only.md b/tf-psa-crypto/docs/4.0-migration-guide/psa-only.md new file mode 100644 index 0000000000..abe63fcdb4 --- /dev/null +++ b/tf-psa-crypto/docs/4.0-migration-guide/psa-only.md @@ -0,0 +1,96 @@ +## PSA as the only cryptography API + +The PSA Crypto API is now the only API for cryptographic primitives. + +For general guidance on migrating to the PSA Crypto API, consult the +[PSA transition guide](../psa-transition.md). Note that most of the suggested migrations also work in the Mbed TLS 3.6 long-time support branch, provided that the library is configured suitably (`MBEDTLS_USE_PSA_CRYPTO` and `MBEDTLS_PSA_CRYPTO_CONFIG` enabled). + +### Impact on application code + +The PK module uses PSA for cryptographic operations. This corresponds to the behavior of Mbed TLS 3.x when `MBEDTLS_USE_PSA_CRYPTO` is enabled. In effect, `MBEDTLS_USE_PSA_CRYPTO` is now always enabled. + +`psa_crypto_init()` must be called before performing any cryptographic operation. + +A few functions take different parameters to migrate them to the PSA API. See “[Function prototype changes](#function-prototype-changes)”. + +### No random generator instantiation + +Formerly, applications using various cryptographic features needed to provide a random generator, generally by instantiating an entropy context (`mbedtls_entropy_context`) and a DRBG context (`mbedtls_ctr_drbg_context` or `mbedtls_hmac_drbg_context`). This is no longer necessary, or possible. All features that require a random generator (RNG) now use the one provided by the PSA subsystem. + +Instead, applications that use random generators or keys (even public keys) need to call `psa_crypto_init()` before any cryptographic operation or key management operation. + +See also [function prototype changes](#function-prototype-changes), many of which are related to the move from RNG callbacks to a global RNG. + +### Impact on the library configuration + +The choice of supported cryptographic mechanisms is now based on `PSA_WANT_xxx` macros instead of legacy configuration macros such as `MBEDTLS_RSA_C`, `MBEDTLS_PKCS1_V15`, etc. This corresponds to the behavior of Mbed TLS 3.x when `MBEDTLS_PSA_CRYPTO_CONFIG` is enabled. In effect, `MBEDTLS_PSA_CRYPTO_CONFIG` is now always enabled. + +For information on which configuration macros are affected and their new PSA equivalent, consult the [PSA transition guide](../psa-transition.md). + +See also the section [“Random number generation configuration”](#random-number-generation-configuration). + +### No direct access to specific algorithms + +All modules that are specific to a particular cryptographic mechanism have been removed from the API. There are a few exceptions, for some mechanisms that are not yet present in the PSA API: `mbedtls/lms.h` and `mbedtls/nist_kw.h` remain part of the API. + +The high-level legacy module `mbedtls/cipher.h` has also been removed. The high-level legacy modules `mbedtls/md.h` and `mbedtls/pk.h` remain present with reduced functionality (see “[Changes to MD and PK](#changes-to-md-and-pk)”). TF-PSA-Crypto also retains non-PSA interfaces for data formats, platform support and miscellaneous utility functions. + +In full detail, the following header files, and their former content, are no longer available. + +``` +everest/Hacl_Curve25519.h +everest/everest.h +everest/kremlib.h +everest/kremlib/*.h +everest/kremlin/*.h +everest/kremlin/internal/*.h +everest/vs2013/*.h +everest/x25519.h +mbedtls/aes.h +mbedtls/aria.h +mbedtls/bignum.h +mbedtls/block_cipher.h +mbedtls/camellia.h +mbedtls/ccm.h +mbedtls/chacha20.h +mbedtls/chachapoly.h +mbedtls/cipher.h +mbedtls/cmac.h +mbedtls/ctr_drbg.h +mbedtls/des.h +mbedtls/dhm.h +mbedtls/ecdh.h +mbedtls/ecdsa.h +mbedtls/ecjpake.h +mbedtls/ecp.h +mbedtls/entropy.h +mbedtls/gcm.h +mbedtls/hkdf.h +mbedtls/hmac_drbg.h +mbedtls/md5.h +mbedtls/pkcs12.h +mbedtls/pkcs5.h +mbedtls/poly1305.h +mbedtls/ripemd160.h +mbedtls/rsa.h +mbedtls/sha1.h +mbedtls/sha256.h +mbedtls/sha3.h +mbedtls/sha512.h +``` + +If your application was using functions from these headers, please see +[`docs/psa-transition.md`](../psa-transition.md) for ways to migrate to +the PSA API instead. + +Some of the associated types still need to be visible to the compiler. For example, `mbedtls_aes_context` is used to define `psa_cipher_operation_t`. These types are still available when building application code, but we recommend that you no longer use them directly. The structure, the semantics and even the existence of these types may change without notice. + +### Other removed functions related to low-level cryptography APIs + +The functions `mbedtls_ecc_group_to_psa()` and `mbedtls_ecc_group_from_psa()` have been removed. They are no longer meaningful since the low-level representation of elliptic curve groups is no longer part of the API. + +### Removal of alternative cryptographic module implementations + +TF-PSA-Crypto no longer supports replacing a whole cryptographic module or an individual cryptographic function by defining a macro `MBEDTLS_xxx_ALT` and providing a custom implementation of the same interface. Instead, use PSA transparent drivers (i.e. accelerator drivers). + +The PK module no longer supports `MBEDTLS_PK_RSA_ALT`. Instead, for opaque keys (RSA or otherwise), use PSA opaque drivers. diff --git a/tf-psa-crypto/docs/4.0-migration-guide/rng.md b/tf-psa-crypto/docs/4.0-migration-guide/rng.md new file mode 100644 index 0000000000..6b8b93f70e --- /dev/null +++ b/tf-psa-crypto/docs/4.0-migration-guide/rng.md @@ -0,0 +1,176 @@ +## Random number generation configuration + +TF-PSA-Crypto no longer exposes the internals of the PSA random number generator. The entropy, CTR_DRBG, and HMAC_DRBG modules from Mbed TLS 3.6 are now for internal use only. As a result, their configuration has been updated, both to simplify them and to prepare for PSA entropy and random number generation drivers, which will be introduced in a future minor release. + +The overall structure of the random number generator in TF-PSA-Crypto remains the same as in Mbed TLS 3.x. It consists of either: +* an external random number generator (when `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is enabled), or +* a deterministic random number generator (CTR_DRBG or HMAC_DRBG) seeded with entropy by the entropy module. + +### Entropy configuration + +TF-PSA-Crypto does not expose an entropy interface to applications. The entropy module of Mbed TLS 3.6 is now for internal use only. As a consequence, its configuration has changed, both to simplify it and to prepare for PSA entropy drivers which will be added in a future minor release. + +#### If you have a fast cryptographic-quality external random generator + +If you have a fast, cryptographic-quality source of random data, enable `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` and provide the callback function `mbedtls_psa_external_get_random()`. This is unchanged since Mbed TLS 2.26. + +#### If the built-in entropy source works for you + +TF-PSA-Crypto, like Mbed TLS, recognizes the system entropy sources on some popular operating systems, and enables them by default. If you are writing your own configuration, you now need to define the option `MBEDTLS_PSA_BUILTIN_GET_ENTROPY`. (This is different from Mbed TLS 2.x and 3.x, where the built-in entropy sources were included unless the option `MBEDTLS_NO_PLATFORM_ENTROPY` was defined.) + +#### If you have a custom entropy source + +To provide a custom entropy source, disable `MBEDTLS_PSA_BUILTIN_GET_ENTROPY` and enable `MBEDTLS_PSA_DRIVER_GET_ENTROPY`. You will need to provide the callback function `mbedtls_platform_get_entropy()`. See [“Custom entropy collector”](#custom-entropy-collector) below for more details. + +#### If you have no entropy source + +If your hardware does not have any entropy source, you can use a non-volatile RNG seed which is injected from a trusted external source during device manufacturing or provisioning. Enable the option `MBEDTLS_ENTROPY_NV_SEED`, which is unchanged from previous versions of the library. + +In TF-PSA-Crypto, when the non-volatile seed is the only (pseudo) entropy source, you also need to enable the option `MBEDTLS_ENTROPY_NO_SOURCES_OK`. + +### Comparison of entropy source configurations + +TF-PSA-Crypto 1.0 supports the same entropy sources as Mbed TLS 3.6, but the way to configure them has changed. + +* The negative option `MBEDTLS_NO_PLATFORM_ENTROPY` to disable the default entropy collector for Unix-like and Windows platforms no longer exists. It has been replaced by the positive option `MBEDTLS_PSA_BUILTIN_GET_ENTROPY`, which is enabled by default. +* The option `MBEDTLS_ENTROPY_HARDWARE_ALT`, which allows you to provide a custom entropy collector, has been renamed to `MBEDTLS_PSA_DRIVER_GET_ENTROPY`. This replaces `MBEDTLS_ENTROPY_HARDWARE_ALT`. The callback has a different name and prototype as described in “[Custom hardware collector](#custom-entropy-collector)”. +* The option `MBEDTLS_ENTROPY_NV_SEED` to enable a non-volatile seed is unchanged. However, if this is your only entropy source, you must now enable the new option `MBEDTLS_ENTROPY_NO_SOURCES_OK`. + +The following table describes common configurations. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ConfigurationMbed TLS 3.6TF-PSA-Crypto 1.0
Unix, Linux, Windows(default)(default)
Embedded platform +
+#define MBEDTLS_NO_PLATFORM_ENTROPY
+#define MBEDTLS_ENTROPY_HARDWARE_ALT
+      
+
+
+#undef MBEDTLS_PSA_BUILTIN_GET_ENTROPY
+#define MBEDTLS_PSA_DRIVER_GET_ENTROPY
+      
+
Fast external crypto RNG +
+#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+#undef MBEDTLS_ENTROPY_C
+#undef MBEDTLS_CTR_DRBG_C
+      
+
+
+#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+#undef MBEDTLS_ENTROPY_C
+#undef MBEDTLS_CTR_DRBG_C
+      
+
NV seed only +
+#define MBEDTLS_NO_PLATFORM_ENTROPY
+#define MBEDTLS_ENTROPY_NV_SEED
+      
+
+
+#undef MBEDTLS_PSA_BUILTIN_GET_ENTROPY
+#define MBEDTLS_ENTROPY_NV_SEED
+#define MBEDTLS_ENTROPY_NO_SOURCES_OK
+      
+
No entropy at all +
+#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
+      
+
+ not supported +
+ +#### Custom entropy collector + +The custom entropy collector callback function has changed, to make it match the upcoming PSA entropy driver specification. + +Formerly, the callback was enabled by `MBEDTLS_ENTROPY_HARDWARE_ALT` and had the following prototype: +```c +// from +int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, + size_t *olen); +``` + +The new callback is enabled by `MBEDTLS_PSA_DRIVER_GET_ENTROPY` and has the following prototype: +```c +``` + +to: + +```c +// from +int mbedtls_platform_get_entropy(psa_driver_get_entropy_flags_t flags, + size_t *estimate_bits, + unsigned char *output, size_t output_size); +``` + +The `data` parameter was previously always `NULL`, and has been removed. + +The new parameter `flags` is a bit-mask of flags that allows the caller to request special behaviors, such as avoiding blocking. The callback should return `PSA_ERROR_NOT_SUPPORTED` if it sees a flag that it does not support. As of TF-PSA-Crypto 1.0, `flags` is always 0. + +The former callback could return less entropy than expected by only filling part of the buffer, and setting `*olen` to a value that is less than `output_size`. The new callback does not have an `olen` parameter, and the caller now reads the whole buffer. The new parameter `estimate_bits` is intended to allow the callback to report that it has accumulated less entropy than expected. However, this is not supported yet in TF-PSA-Crypto 1.0. + +The new output parameter `estimate_bits` is the amount of entropy that the callback has placed in the output buffer. As of TF-PSA-Crypto 1.0, the output must have full entropy, thus `estimate_bits` must be equal to `8 * output_size`. A future version of TF-PSA-Crypto will allow entropy sources to report smaller amounts. + +To indicate that entropy is not currently available, the legacy error code `MBEDTLS_ERR_ENTROPY_SOURCE_FAILED` has been replaced by `PSA_ERROR_INSUFFICIENT_ENTROPY`. + +#### Removed entropy options + +The option `MBEDTLS_ENTROPY_MIN_HARDWARE` has been removed. The entropy module requests the amount that it needs for the chosen security strength. + +The option `MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES` has removed since it is no longer meaningful, now that the entropy module is private. TF-PSA-Crypto 1.0 does not support platforms without an entropy source. This ability will be reintroduced in a future minor release. + +#### PSA entropy injection + +The configuration option `MBEDTLS_PSA_INJECT_ENTROPY` has been removed. TF-PSA-Crypto 1.0 does not provide a way to store an entropy seed in the key store. This will be reimplemented in a future minor version. + +### Configuration of the DRBG + +As in previous versions of Mbed TLS, the PSA random generator in TF-PSA-Crypto uses CTR_DRBG with AES if `MBEDTLS_CTR_DRBG_C` is enabled, and HMAC_DRBG otherwise (requiring `MBEDTLS_HMAC_DRBG_C` to be enabled). + +The DRBG modules are not exposed directly, they are only used internally. + +In addition to the choice of DRBG module and entropy sources, the built-in random number generator is now configured through only three options: + +* `MBEDTLS_PSA_CRYPTO_RNG_HASH`: Selects the hash algorithm used by the entropy and HMAC_DRBG modules. This option replaces both `MBEDTLS_PSA_HMAC_DRBG_MD_TYPE` and `MBEDTLS_ENTROPY_FORCE_SHA256`. +* `MBEDTLS_PSA_RNG_RESEED_INTERVAL`: Sets the reseed interval for both CTR_DRBG and HMAC_DRBG. It replaces `MBEDTLS_CTR_DRBG_RESEED_INTERVAL` and `MBEDTLS_HMAC_DRBG_RESEED_INTERVAL`. +* `MBEDTLS_PSA_CRYPTO_RNG_STRENGTH`: Specifies the security strength in bits. The default is 256 bits. If you previously enabled `MBEDTLS_CTR_DRBG_USE_128_BIT_KEY` in Mbed TLS 3.6, you should now set `MBEDTLS_PSA_CRYPTO_RNG_STRENGTH` to 128, although this is not recommended. + +The option `MBEDTLS_ENTROPY_C` has been removed. The entropy module is now automatically enabled when `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is disabled. +The following Mbed TLS 3.6 configuration options have been removed without any counterpart in TF-PSA-Crypto. Their corresponding APIs were also removed, making these options no longer relevant: +`MBEDTLS_ENTROPY_MAX_GATHER`, `MBEDTLS_ENTROPY_MAX_SOURCES`, `MBEDTLS_CTR_DRBG_ENTROPY_LEN`, `MBEDTLS_CTR_DRBG_MAX_INPUT`, `MBEDTLS_CTR_DRBG_MAX_REQUEST`, `MBEDTLS_CTR_DRBG_MAX_SEED_INPUT`, `MBEDTLS_HMAC_DRBG_MAX_INPUT`, `MBEDTLS_HMAC_DRBG_MAX_REQUEST`, and `MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT`. diff --git a/tf-psa-crypto/docs/4.0-migration-guide/threading.md b/tf-psa-crypto/docs/4.0-migration-guide/threading.md new file mode 100644 index 0000000000..c071bb968f --- /dev/null +++ b/tf-psa-crypto/docs/4.0-migration-guide/threading.md @@ -0,0 +1,24 @@ +## Threading platform abstraction + +### Extension to condition variables + +The threading abstraction now includes primitives for condition variables in addition to mutexes. + +As before, implementations of `MBEDTLS_THREADING_ALT` need to provide a header file `"threading_alt.h"`, and to call the function `mbedtls_threading_set_alt()` before any call to other TF-PSA-Crypto or Mbed TLS functions. The header file `"threading_alt.h"` now needs to define the following elements: + +* The type `mbedtls_platform_mutex_t`, which is the type of mutex arguments passed to the platform functions. This type is now distinct from the type `mbedtls_threading_mutex_t` which library code and applications use. +* The type `mbedtls_platform_condition_variable_t`, which is the type of condition variable arguments passed to the platform functions. + +### Changes to the mutex primitives + +The type of mutex objects provided by the platform functions is now called `mbedtls_platform_mutex_t`, distinct from the API type `mbedtls_threading_mutex_t`. + +The `mutex_init` primitive now returns a status code instead of `void`. + +The documentation in `include/mbedtls/threading.h` now clarifies the expectations on mutex primitives. These expectations are somewhat relaxed from the mostly undocumented expectations in previous versions: mutex functions other than `mutex_init` can now assume that the mutex has been successfully initialized. + +Platform threading primitives should now return the following error codes: + +* `MBEDTLS_ERR_THREADING_USAGE_ERROR` to report a runtime failure (renamed from `MBEDTLS_ERR_THREADING_MUTEX_ERROR`, which is now an alias provided only for backward compatibility). +* `PSA_ERROR_BAD_STATE` only to report a library state error. If an error is detected in the state of a synchronization object, please return `MBEDTLS_ERR_THREADING_USAGE_ERROR` instead. +* `PSA_ERROR_INSUFFICIENT_MEMORY` to report resource exhaustion. diff --git a/tf-psa-crypto/docs/architecture/0e-plans.md b/tf-psa-crypto/docs/architecture/0e-plans.md new file mode 100644 index 0000000000..e3be2a6b26 --- /dev/null +++ b/tf-psa-crypto/docs/architecture/0e-plans.md @@ -0,0 +1,1359 @@ +TF-PSA-Crypto minimal interfaces +================================ + +## Introduction + +This document describes plans for a minimalist TF-PSA-Crypto, tentatively called TF-PSA-Crypto 0ε, and a matching Mbed TLS consuming it. The general idea is to start from PSA interfaces, and expose additional interfaces to provide functionality that PSA does not currently offer. Most additional interfaces will be existing ones, but they can be new interfaces if it makes more sense. + +Mbed TLS will continue using internal interfaces of TF-PSA-Crypto, even after the release of TF-PSA-Crypto 1.0 and Mbed TLS 4.0. However, it is an objective that some 4.x version will no longer need to use any internal interface of TF-PSA-Crypto. As a result, we will remove some functionality from Mbed TLS. In the 0ε version, it is an objective that no public interface of Mbed TLS will expose an internal interface of TF-PSA-Crypto. + +Note that the name “TF-PSA-Crypto 0ε” is for convenience only. At this time, we are not planning a release of this version. We are planning a beta release of TF-PSA-Crypto before the 1.0 release, but this may come before or after the 0ε described in this document. + +This document is about C-level interfaces for applications and integration. Other aspects of the project, such as build and test scripts, are out of scope. + +## Glossary + +This document uses a few unusual terms, and a few generic terms with a specific meaning. This section explains those terms. + +**0ε**: a version of TF-PSA-Crypto that minimally meets the formal requirements for TF-PSA-Crypto 1.0. This may not be something we want to release, for example because it lacks critical features, is insufficiently tested, has insufficient documentation, or would be too much of a burden to maintain. It comes before the TF-PSA-Crypto **MVP**. + +**1.0**: The first ever stable release of TF-PSA-Crypto. Its publicly documented APIs will remain supported throughout the lifecycle of TF-PSA-Crypto 1.x. + +**3ε**: A version of Mbed TLS corresponding to TF-PSA-Crypto 0ε. + +**4.0**: The first stable release of Mbed TLS consuming TF-PSA-Crypto. Its publicly documented APIs will remain supported throughout the lifecycle of Mbed TLS 4.x. + +**Alpha**: A release of TF-PSA-Crypto or Mbed TLS that is not widely advertized and that may have known major gaps that make it unsuitable for **MVP** or even **0ε/3ε**. There are no commitments to API stability. + +**Beta**: A release of TF-PSA-Crypto or Mbed TLS that is advertized to integrators and application writers and that may have known minor gaps that make it unsuitable for **MVP** or even **0ε/3ε**. There are no commitments to API stability. + +**Exposed** (interface): An interface (such as a header, type, function or configuration option) that is not publicly documented and not part of the stable API, but that is visible to the compiler when building application code. A typical example is types that are used in fields of structs whose content is not stable, but that it must be possible to allocate on the stack or statically. + +**Internal** (interface): an interface of a part of TF-PSA-Crypto or Mbed TLS that is only used by other parts of the same project, and is not visible outside of the project. In particular, Mbed TLS cannot use internal interfaces of TF-PSA-Crypto. + +**MVP** (minimum viable product): A version of TF-PSA-Crypto and a corresponding version of Mbed TLS that meet the requirements for TF-PSA-Crypto 1.0, and that would be acceptable for a 1.0/4.0 release. + +**Private** (interface): An interface (such as a header, type, function or macro) that is not publicly documented, and that may change or be removed without warning. This is the opposite of **public**. To the extent that it is practical, the library should prevent applications from accidentally relying on private interfaces, but some private interfaces have to be **exposed**. + +**Public** (interface): An interface (such as a header, type, function or configuration option) that is publicly documented, and that is covered by API stability guarantees within a major version of TF-PSA-Crypto or Mbed TLS. This is the opposite of **private**, and does not include **exposed** interfaces. + +The **Split** (repository split): the split between TF-PSA-Crypto and Mbed TLS, where `tf-psa-crypto` became a submodule instead of a subdirectory. This happened on 2024-12-16. + +## Project goals + +### Starting point + +Our starting point is TF-PSA-Crypto and Mbed TLS as of the repository split, or equivalently as of 2025-01-01. Compared with Mbed TLS 3.6: + +* `MBEDTLS_USE_PSA_CRYPTO` is always enabled: PK, X.509 and TLS always use PSA APIs for cryptography, except for a few limitations documented in [`use-psa-crypto.md`](https://github.com/Mbed-TLS/mbedtls/blob/mbedtls-3.6/docs/use-psa-crypto.md). +* `MBEDTLS_PSA_CRYPTO_CONFIG` is always enabled: only `PSA_WANT_xxx` symbols can be used to configure which cryptographic mechanisms are enabled, not `MBEDTLS_xxx`. +* The only public interfaces in TF-PSA-Crypto are the ones in `` (including interfaces in `include/psa/crypto_*.h` which are exposed indirectly via `crypto.h`). The crypto interfaces in `` are considered private, but not marked as such, at the start of the project. + +### Feature goals + +Ideally, TF-PSA-Crypto 1.0 and Mbed TLS 4.0 would have the same features as Mbed TLS 3.6, except for a small set of features that we have decided to remove (e.g. obsolescent cryptographic mechanisms). This would include creating PSA interfaces where 3.6 only has non-PSA (Mbed TLS legacy) interfaces. + +By removing legacy crypto interfaces, we are removing many features for which no corresponding PSA interface exists. For example: + +* Configuring an entropy source relies on `` +* Parsing or formatting a key in common formats relies on ``. +* X.509 fundamentally relies on some features that are not strictly speaking cryptography, but are implemented in TF-PSA-Crypto which needs them for its own use as well: ASN.1 (`` and ``), PEM (``). +* Parsing or constructing X.509 extensions tends to require ASN.1 functions. + +Given the available time and resources, we cannot ensure that 1.0/4.0 will be suitable for all the same use cases as 3.6. However, compared to the project starting point, we will bring back essential use cases. The use cases listed just above are examples of essential features that we want to provide in 0ε. More use cases can be brought back later by exposing more internal legacy interfaces or designing new PSA interfaces. + +### Maintainability goals + +We don't want to keep maintaining the legacy crypto APIs. They are too low-level, and we want the ability to fully migrate to PSA APIs for cryptography. + +This goal will mainly act as a moderator on bringing back features by just exposing legacy interfaces. + +For example, we do not want the type `mbedtls_mpi` to be part of the 0ε or 1.0/4.0 API, because it leaks the internal representation of integers, and this limits us when doing optimizations and security improvements. + +### Quality goals + +TF-PSA-Crypto and Mbed TLS must continue to be high-quality products. Given our limited bandwidth, 0ε and possibly even 1.0/4.0 may compromise on some aspects of quality. However, this needs to be balanced carefully, and not all aspects of quality are up for compromise. As an extreme example, security shall not be compromised at any point. + +Some considerations on quality have come up: + +* Documentation in the 1.0/4.0 release must be good enough for users and should match our standards for 3.6. We may skip some documentation tasks in 0ε, but the remaining tasks should be clearly identified. +* For users who migrate from 3.6, there should be a clear upgrade path, and there should be an easy way for users to ensure that they have finished migrating, i.e. that they are no longer accidentally using an interface that is now private. This aspect may be compromised in 0ε, although it is not clear whether this is desirable, since having a clear way to flag uses of legacy APIs is a convenient way of evaluating whether 0ε is fit for purpose. +* We have few sample programs for the PSA API. It is unfortunately likely that this will continue past the TF-PSA-Crypto 1.0 release. +* At this point, the TF-PSA-Crypto project does not have self-reliant testing. As outlined in the introduction above, this is out of scope of this document. + +### Project 0ε goals + +1. In TF-PSA-Crypto, ensure a clear separation between public interfaces (part of the API stability promise) and private interfaces (which may change at any time, even if they are used in Mbed TLS code, or embedded in private structure types). +2. Remove selected features of Mbed TLS. This is mainly driven by the desire to stop maintaining some features that cannot be easily provided without legacy crypto APIs. +3. Expose selected legacy interfaces to fill some functionality gaps. In a few cases, this can also include new interfaces, generally tweaks on the legacy interface (e.g. replacing an `mbedtls_mpi*` argument of a public function by a byte array). + +## Hiding low-level cryptography interfaces + +### Deciding what to hide + +#### Degrees of public interfaces + +There are several potential criteria for whether an interface is part of the library's stable API. Roughly from the most permissive to the most restrictive: + +* Declared in a public header. +* Declared in a public header, without a comment indicating that it's private or unstable. +* Present in the rendered documentation. +* Present in the rendered documentation, and not documented as unstable. + +In [`BRANCHES.md`](https://github.com/Mbed-TLS/mbedtls/blob/development/BRANCHES.md#backwards-compatibility-for-application-code), we promise backward compatibility for “code that's working and secure with Mbed TLS x.y.z and does not rely on undocumented features”. That roughly corresponds to the most restrictive criteria. + +#### Exposed interfaces + +There are two main reasons why interfaces are declared in public headers, but not part of the stable API of the library: + +* Historically, all non-static functions were declared in public headers. This started changing during the Mbed TLS 2.x era, and Mbed TLS 3.6.0 removed most of the remaining functions that were declared in a public header with a comment stating that they were not part of the API. However, some functions may have been missed, or may become non-desired in the API in 4.0/1.0. +* Several elements have to be visible to the compiler, even though they are not part of the public interface. In particular: + * The definition of types, where we only promise the stability of the existence of the type, but not of how it is implemented. These are **opaque types**. + * The existence of types whose purpose is to define opaque types. These have to be in a header that is visible to the compiler, but we don't want to make any stability commitment about them. For example, `mbedtls_aes_context` is needed to define the opaque type `psa_cipher_operation_t`. Let us call such types **exposed types**. + * The implementation of static inline functions. This is generally not a problem since you can't do anything other than call the function anyway. + * **Intermediate macros** which were only intended to define other macros and not intended to be stable. There are many such macros in `psa/crypto_values.h` and `psa/crypto_sizes.h`, for example. They are identified by not having Doxygen documentation, but this is discreet. + +For the 0ε target, and likely even the 1.0/4.0 release, we aim to make the situation not worse than it is in 3.6. We don't plan to go on a hunt for ambiguous declarations in headers, but we should make sure we don't create new ambiguities. In particular, if an interface was part of the public API of Mbed TLS 3.6, but we don't consider it part of the public API of 1.0/4.0, we should make this clear, preferably by ensuring that applications won't compile if they try to use such interfaces. + +#### Quasi-private interfaces of TF-PSA-Crypto + +The separation between TF-PSA-Crypto and Mbed TLS adds another layer of complexity: some interfaces are considered private in TF-PSA-Crypto, but are still used in Mbed TLS. This includes code used in the library itself, or in test code, or in sample programs. This excludes code guarded by `!defined(MBEDTLS_USE_PSA_CRYPTO)` which is still present but never built. Given the engineering bandwidth available for the Mbed TLS 4.0 release, we know that we will not be able to eliminate such interfaces. + +Note that private interfaces of TF-PSA-Crypto may only be used internally in Mbed TLS. They may not leak though the public interface of Mbed TLS. This is an objective for 0ε as well as for the 4.0 release. (Exposed interfaces of TF-PSA-Crypto may be exposed in Mbed TLS as well.) + +It is a common use case that TF-PSA-Crypto is integrated on a platform as part of the basic board support package (BSP). It may be a lightweight integration with just a default configuration file and some platform customization, or a more elaborate integration such as TF-M which runs the bulk of the crypto library in a separate runtime environment. In the latter case, the source code of the customized crypto library might even not be present when compiling Mbed TLS. + +To allow such builds, the interfaces of TF-PSA-Crypto that are used internally in Mbed TLS will be declared in public headers, but in such a way that applications cannot use them without going out of their way. + +#### Categories of crypto headers + +At the start of the 0ε work, all legacy headers of TF-PSA-Crypto are located under `drivers/*/include`. This includes the definitions of many exposed types, as well as many TF-PSA-Crypto interfaces used by Mbed TLS. Thus it is impossible to build TF-PSA-Crypto or Mbed TLS without having these headers in the include path (except maybe some configurations that exclusively use third-party PSA drivers). + +For the 0ε target, we will separate headers that are only needed to compile TF-PSA-Crypto itself from headers that are needed when compiling applications or Mbed TLS. We distinguish three categories of headers: + +* Public legacy headers: they contain public interfaces of TF-PSA-Crypto. For example, `"mbedtls/platform.h"` and `"mbedtls/asn1.h"`. Just move them wholesale. +* Exposed headers: these headers do not define any public interface, but they define exposed interfaces, typically types. For example, `"mbedtls/aes.h"` (where the type `mbedtls_aes_context` needs to be exposed, but the functions `mbedtls_aes_xxx()` are only meant to be used inside TF-PSA-Crypto). We will move these headers to a public directory, but ensure that exposed interfaces are clearly documented as such and that private interfaces are not casually usable by applications. See [“Hiding functions in an exposed header”](#hiding-functions-in-an-exposed-header). +* Purely private headers: these headers only define interfaces used to compile TF-PSA-Crypto itself, not interfaces that are exposed or that are used by Mbed TLS. In the long term, most mixed-use headers should be split into an exposed part (typically defining only types and perhaps macros) and a private part. + +### Analysis of legacy crypto headers + +#### Table of legacy crypto headers + +The following table lists the headers that, as of the repository split, are located in `tf-psa-crypto/drivers/builtin/include/mbedtls/`. This is essentially the crypto or platform headers formerly in `include/mbedtls/` in Mbed TLS. + +| Header | Function prefix | Fate | Notes | +| ------ | --------------- | ---- | ----- | +| `aes.h` | `mbedtls_aes_` | Expose | [context types](#headers-with-context-types) | +| `aria.h` | `mbedtls_aria_` | Expose | [context types](#headers-with-context-types) | +| `asn1.h` | `mbedtls_asn1_` | Public | [cryptography-adjacent](#cryptography-adjacent-headers) | +| `asn1write.h` | `mbedtls_asn1_write_` | Public | [cryptography-adjacent](#cryptography-adjacent-headers) | +| `base64.h` | `mbedtls_base64_` | TBD | [Base64 and PEM](#base64-and-pem) | +| `bignum.h` | `mbedtls_mpi_` | Expose | [context types](#headers-with-context-types) | +| `block_ciper.h` | `mbedtls_block_cipher_` | Expose | [context types](#headers-with-context-types) | +| `build_info.h` | `MBEDTLS_` | Exposed | [can be made fully private](#headers-that-can-be-made-fully-private) | +| `camellia.h` | `mbedtls_camellia_` | Expose | [context types](#headers-with-context-types) | +| `ccm.h` | `mbedtls_ccm_` | Expose | [context types](#headers-with-context-types) | +| `chacha20.h` | `mbedtls_chacha20_` | Expose | [context types](#headers-with-context-types) | +| `chachapoly.h` | `mbedtls_chachapoly_` | Expose | [context types](#headers-with-context-types) | +| `cipher.h` | `mbedtls_cipher_` | Expose | [context types](#headers-with-context-types) | +| `cmac.h` | `mbedtls_cipher_cmac_` | Expose | [context types](#headers-with-context-types) | +| `config_adjust_*.h` | N/A | Exposed | [Only for exposed macros ](#headers-that-remain-exposed-for-exposed-macros) | +| `config_psa.h` | N/A | Exposed | [Only for exposed macros ](#headers-that-remain-exposed-for-exposed-macros) | +| `constant_time.h` | `mbedtls_ct_` | Public | [cryptography-adjacent](#cryptography-adjacent-headers) | +| `ctr_drbg.h` | `mbedtls_ctr_drbg_` | Private | [Internal eventually](#headers-that-will-become-internal-eventually) | +| `des.h` | `mbedtls_des_` | Expose | [context types](#headers-with-context-types) | +| `dhm.h` | `mbedtls_dhm_` | Private | [can be made fully private](#headers-that-can-be-made-fully-private) | +| `ecdh.h` | `mbedtls_ecdh_` | Expose | [context types](#headers-with-context-types) | +| `ecdsa.h` | `mbedtls_ecdsa_` | Expose | [context types](#headers-with-context-types) | +| `ecjpake.h` | `mbedtls_ecjpake_` | Expose | [context types](#headers-with-context-types) | +| `ecp.h` | `mbedtls_ecp_` | Expose | [context types](#headers-with-context-types) | +| `entropy.h` | `mbedtls_entropy_` | Private | [Internal eventually](#headers-that-will-become-internal-eventually) | +| `error_common.h` | `mbedtls_*err*` | Private | [Internal eventually](#headers-that-will-become-internal-eventually) | +| `gcm.h` | `mbedtls_gcm_` | Expose | [context types](#headers-with-context-types) | +| `hkdf.h` | `mbedtls_hkdf_` | Delete | [Mbed-TLS/mbedtls#9150](https://github.com/Mbed-TLS/mbedtls/issues/9150) | +| `hmac_drbg.h` | `mbedtls_hmac_drbg_` | Private | [can be made fully private](#headers-that-can-be-made-fully-private) with a little work | +| `lms.h` | `mbedtls_lms_` | Public | [no PSA equivalent](#cryptographic-mechanisms-with-no-psa-equivalent) | +| `md.h` | `mbedtls_md_` | Expose | [context types](#headers-with-context-types), but likely [Public hash-only `md.h`](#public-hash-only-mdh) | +| `md5.h` | `mbedtls_md5_` | Expose | [context types](#headers-with-context-types) | +| `memory_buffer_alloc.h` | `mbedtls_memory_buffer_alloc_` | Public | [Platform headers](#platform-headers) | +| `nist_kw.h` | `mbedtls_nist_kw_` | Public | [no PSA equivalent](#cryptographic-mechanisms-with-no-psa-equivalent) | +| `oid.h` | `mbedtls_oid_` | Private | [OID interface](#oid-interface) | +| `pem.h` | `mbedtls_pem_` | TBD | [Base64 and PEM](#base64-and-pem) | +| `pk.h` | `mbedtls_pk_` | Public | [cryptography-adjacent](#cryptography-adjacent-headers) | +| `pkcs12.h` | `mbedtls_pkcs12_` | Private | [can be made fully private](#headers-that-can-be-made-fully-private) | +| `pkcs5.h` | `mbedtls_pkcs5_` | Private | [can be made fully private](#headers-that-can-be-made-fully-private) | +| `platform.h` | `mbedtls_platform_` | Public | [Platform headers](#platform-headers) | +| `platform_time.h` | `mbedtls_*time*` | Public | [Platform headers](#platform-headers) | +| `platform_util.h` | `mbedtls_platform_` | Public | [Platform headers](#platform-headers) | +| `poly1305.h` | `mbedtls_poly1305_` | Expose | [context types](#headers-with-context-types) | +| `private_access.h` | N/A | Exposed | [Only for exposed macros ](#headers-that-remain-exposed-for-exposed-macros) | +| `psa_util.h` | N/A | Public | [remains public](#headers-that-remain-public) but see [Private types in `psa_util.h`](#private-types-in-psa_utilh) | +| `ripemd160.h` | `mbedtls_ripemd160_` | Expose | [context types](#headers-with-context-types) | +| `rsa.h` | `mbedtls_rsa_` | Private | [can be made fully private](#headers-that-can-be-made-fully-private) with a little work | +| `sha1.h` | `mbedtls_sha1_` | Expose | [context types](#headers-with-context-types) | +| `sha256.h` | `mbedtls_sha256_` | Expose | [context types](#headers-with-context-types) | +| `sha3.h` | `mbedtls_sha3_` | Expose | [context types](#headers-with-context-types) | +| `sha512.h` | `mbedtls_sha512_` | Expose | [context types](#headers-with-context-types) | +| `threading.h` | `mbedtls_threading_` | Public | [Platform headers](#platform-headers) | +| `timing.h` | `mbedtls_timing_` | Delete | Move to mbedtls (done) | + +For contributed drivers, see: + +* Everest: Expose [Everest](#privatization-of-everest-headers). +* p256-m: [fully private](#headers-that-can-be-made-fully-private). + +#### Cryptographic mechanisms with no PSA equivalent + +The header files listed in this section define cryptographic mechanisms which do not currently fit well in the PSA API, are useful, and have an acceptable ad hoc interface. We will therefore keep this interface in TF-PSA-Crypto 1.x, possibly with minor tweaks to make them fit a PSA-only API. They may evolve later in the life of TF-PSA-Crypto 1.x. + +* `lms.h`: The PSA API does not support stateful signatures yet. This is planned, but the API design is still under discussion. This is a critical feature in TF-A, hence considered necessary in the TF-PSA-Crypto MVP. +* `nist_kw.h`: The PSA API does not have an encoding for KW. It is under discussion, but it is mostly used to wrap key material or blobs containing key material, rather than to directly manipulate text, which complicates the API design. This is a request from many silicon vendors, hence considered necessary in the TF-PSA-Crypto MVP. + +#### Cryptography-adjacent headers + +The following header files define cryptography-adjacent interfaces which we have no plans to replace. + +* `asn1.h`, `asn1write.h`: ASN.1, needed for key parsing/writing as well as for X.509. +* `constant_time.h`: This header defines `mbedtls_ct_memcmp()` which is in the public API because it is useful to application code (including but not limited to the TLS layer in Mbed TLS). +* `pk.h`: There is no equivalent PSA API. (One is planned, but the design won't be ready until after 1.0.) This is critical for parsing and writing keys. We plan to keep parts of the existing `pk.h` for parsing, writing and signature, and to remove `mbedtls_pk_type_t`, encrypt/decrypt and a few other bits. For 0ε, `pk.h` goes into the public category, and we will remove parts of it. Continued in https://github.com/Mbed-TLS/mbedtls/issues/8452 . + +We will therefore keep those headers public in TF-PSA-Crypto 0ε and 1.x. + +#### Base64 and PEM + +Base64 and PEM are cryptography-adjacent interfaces which we have no plans to replace. In particular, they are outside the scope of PSA APIs. + +PEM is used: + +* Inside the crypto library, to parse and write keys. +* Inside the Mbed TLS library, to parse and write X.509 objects. +* In application code, very occasionally. (Examples: [Fire-evacuation-guidance-system-IoT](https://github.com/2nd-Chance/Fire-evacuation-guidance-system-IoT/blob/33031a8255fe1ae516ddd58f1baa808801cd3abf/iotivity/resource/csdk/security/src/credresource.c#L3185) (dead project), [SiLabs Bluetooth attestation server](https://github.com/SiliconLabs/bluetooth_applications/blob/3eb0f3c9e234ada1f10714fb9376fcbc8e95807f/bluetooth_secure_attestation/bt_secure_attestation_server/src/ecdh_util3.c#L375)) + +The use of PEM inside the Mbed TLS library is intrinsic. It doesn't leak through the API of Mbed TLS, but Mbed TLS cannot be implemented without PEM. This is different from other private modules that Mbed TLS currently calls internally, but will no longer need to call once Mbed TLS has fully migrated to PSA. Thus, in the long term, TF-PSA-Crypto needs to expose its PEM API to Mbed TLS. (We reject the hypotheses of independent PEM implementations, or of making PEM its own library, as too much maintenance work.) + +The current PEM interface is unsatisfactory. We would like to improve it (https://github.com/Mbed-TLS/mbedtls/issues/9374) but it is unlikely that we will have enough bandwidth to do so before the 1.0 release. We need to make the PEM interface public to reach the milestone where Mbed TLS stops relying on private interfaces of TF-PSA-Crypto. We can choose to make it public now, or wait until later. Waiting is only advantageous if we believe that we will have enough bandwidth to actually clean up the PEM interface. + +Base64 is used: + +* Inside the crypto library, to implement PEM. +* In the `pem2der` sample program. +* In Mbed TLS SSL test programs, for context serialization. (It's not clear to me why we encode in Base64 rather than binary.) +* In the Mbed TLS sample program `ssl_mail_client`, for a tiny bit of SMTP that requires Base64. +* In application code, sometimes, for miscellaneous things, often not directly related to cryptography. On the one hand, many of these uses are out of scope. On the other hand, since TF-PSA-Crypto has a Base64 implementation anyway, users who like TF-PSA-Crypto for its small code size would be justifiably disappointed not to have a Base64 interface. + +Conclusion: we will keep the existing `pem.h` and `base64.h` as public interfaces in TF-PSA-Crypto 0ε. If we have time before the 1.0 release, we will improve the APIs. + +#### OID interface + +`oid.h` and `MBEDTLS_OID_C` are in charge of defining all the OIDs used internally or by application code. This is a known problem which can result in applications wasting code size on many OIDs that they don't care about. We are planning a redesign: https://github.com/Mbed-TLS/mbedtls/issues/9380 . + +At this point, we do not consider this critical for TF-PSA-Crypto 1.0, and we are likely to work on it during the lifetime of TF-PSA-Crypto 1.x. This may change if we reevaluate the priority based on concrete use cases. In the meantime, `oid.h` will become private, but will remain used in Mbed TLS. + +#### Platform headers + +Due to a lack of bandwidth, we are not planning any major changes to most platform interfaces. As of the 0ε target, the following platform-related headers remain public. + +* `memory_buffer_alloc.h`: a feature used by some applications, with close to 0 maintenance cost for us. +* `platform.h`, `platform_time.h`, `platform_util.h`: platform abstractions. We would like to adapt them, but we do not think we will have time in before 1.0, so this will have to wait until the next major version. +* `threading.h`: We want to change the threading abstraction, but this is out of scope of the 0ε project. https://github.com/Mbed-TLS/mbedtls/issues/8455 + +### Plans for hiding + +In an exposed header, the minimum work for 0ε is: + +* Ensure that exposed interfaces are not listed in the rendered Doxygen documentation. +* Ensure that applications cannot inadvertently call private functions that are declared in exposed headers. + +Note that due to a lack of bandwidth, sample programs may keep using private interfaces. + +#### TF-PSA-Crypto header locations + +We distinguish between four categories of headers: + +* Public headers define public, stable APIs. +* Exposed headers define exposed interfaces, as well as private interfaces used by Mbed TLS. They need to be present when building Mbed TLS, but their content must clearly be excluded from the stable API. +* Private headers do not define any exposed interfaces, but they are used by Mbed TLS for the time being. They need to be present when building Mbed TLS, but their content must clearly be excluded from the stable API. +* Internal headers are only needed when building TF-PSA-Crypto itself. Their content must clearly be excluded from the stable API. + +The following table summarizes the characteristics of each category and their location in TF-PSA-Crypto 0ε. + +| Category | Location | Installed? | Doxygen? | Visible to Mbed TLS? | +| -------- | -------- | ---------------- | +| Public | `include/mbedtls` | yes | yes | yes | +| Exposed | `drivers/*/include/mbedtls/private` | yes | no | yes | +| Private | `drivers/*/include/mbedtls/private` | yes for now | no | yes | +| Internal | anything except `**/include/mbedtls/*.h` | no | no | no | + +We will arrange so that: + +* Public interfaces are available to consuming projects and visible in the rendered documentation. +* Exposed and private interfaces are available to consuming projects, but not visible in the rendered documentation and clearly not public for someone who reads the header files themselves. It would be convenient to have separate locations for permanently exposed interfaces (e.g. types appearing in operation contexts) and temporarily exposed interfaces (legacy functions that Mbed TLS is still using), but this is not necessry. +* Internal interfaces are available only inside TF-PSA-Crypto, not to consuming projects. Like exposed interfaces, the documentation (rendered or by direct header reading) clearly conveys that they are not part of the API. + +#### Hiding functions in an exposed header + +For TF-PSA-Crypto 0ε, all private functions defined in private headers will be guarded by `defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS)`. We define this macro when building TF-PSA-Crypto and Mbed TLS, but applications should not define it, and our Doxygen build will not define it. + +This is similar to `MBEDTLS_ALLOW_PRIVATE_ACCESS` to “bless” access to structure fields. + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/219): in TF-PSA-Crypto, in `private_access.h`, define `MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS` when `MBEDTLS_ALLOW_PRIVATE_ACCESS` is defined. Add `#define MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS` just before the first `#include` in every program under `programs` that calls `mbedtls_xxx` functions (just `benchmark.c` at the time of writing). + +Since `MBEDTLS_ALLOW_PRIVATE_ACCESS` implies `MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS`, and `tf_psa_crypto_common.h` enables `MBEDTLS_ALLOW_PRIVATE_ACCESS`, parts of the code base that already allow access to private structure fields (library, unit tests) will automatically have access to private functions. + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/10082): in Mbed TLS, add `#define MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS` just before the first `#include` in every program under `programs`, except the ones that already have `MBEDTLS_ALLOW_PRIVATE_ACCESS`. The reason to add it program by program is that later we can validate that an individual program no longer requires private identifiers by removing `#define MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS` from that particular program. This is a prerequisite for any privatization in TF-PSA-Crypto that privatizes something used in Mbed TLS. + +Prototype: https://github.com/Mbed-TLS/TF-PSA-Crypto/pull/132 + +Thus, for the 0ε milestone, in each affected header, we just need to place `#ifdef` guards around the function declarations. + +Rationale: + +* This is a small amount of work. +* This requires few changes to the code, and they are very localized, so it will not disrupt other work happening in parallel. + +Additionally, each header may itself be public or not: do we still want applications to `#include `? A header that contains exposed declarations must be exposed, but does not need to be public. See [Move private headers](#move-private-headers). + +#### Separating private interfaces from exposed interfaces + +If a private interface of TF-PSA-Crypto is declared in an exposed header, in the medium term, we should move it to a private header. Note that we can only do that if the interface is not called from Mbed TLS code. + +At some point, perhaps after the 1.0 release, we expect that all the functions declared in an exposed header will be private and will not be called by Mbed TLS. That point may be reached at different times for different headers. When we reach that point for a header, we can run a script to move the declarations guarded by `MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS` to an internal header file and adjust `#include` directives accordingly. + +### Analysis of privatization by header + +#### Headers that remain public + +The headers listed below declare functionality that has no PSA equivalent and that is desirable in 1.0/4.0. We will just move these headers to the public include directory. We may make further changes to some of these headers, but it is out of scope of this chapter. + +``` +asn1.h +asn1write.h +base64.h +constant_time.h +lms.h +memory_buffer_alloc.h +nist_kw.h +pem.h +pk.h +platform.h +platform_time.h +platform_util.h +psa_util.h +threading.h +``` + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/223): Move TF-PSA-Crypto public headers to `/include/mbedtls`. + +#### Headers that remain exposed for exposed macros + +The following headers solely define exposed macros, and must remain exposed. They can be excluded from Doxygen parsing, but they shouldn't contain Doxygen comments anyway, and currently mostly don't apart from `\file` comments. + +``` +config_adjust_legacy_from_psa.h +config_adjust_psa_superset_legacy.h +config_adjust_test_accelerators.h +config_psa.h +private_access.h +``` + +#### Headers with context types + +The headers listed below are used in operation context types. The types that they define must remain exposed, and possibly some macros as well. The functions that they declare will be made private by guarding them with `MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS`. + +``` +aes.h +aria.h +bignum.h +block_cipher.h +camellia.h +ccm.h +chacha20.h +chachapoly.h +cipher.h +cmac.h +des.h +ecdh.h +ecdsa.h +ecjpake.h +ecp.h +gcm.h +md.h +md5.h +poly1305.h +ripemd160.h +sha1.h +sha256.h +sha3.h +sha512.h +``` + +Main loss of functionality: + +* Self-test functions. See [PSA self-test interface](#psa-self-test-interface) +* Access to bignum and ECC arithmetic. We've decided that this is acceptable. + +Note: see also [Everest](#privatization-of-everest-headers). + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/224): Privatize functions in low-level hash headers. + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/225: Privatize functions in cipher primitive headers. + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/226): Privatize functions in cipher mode headers. + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/227): Privatize functions in low-level asymmetric crypto headers. + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/220): Privatize functions in `cipher.h`. + +See [Public hash-only `md.h`](#public-hash-only-mdh) regarding `md.h`. + +#### Headers that can be made fully private + +The headers listed below are not used in Mbed TLS, except in places that should be removed and can be removed easily. + +``` +build_info.h +dhm.h +hmac_drbg.h +pkcs12.h +pkcs5.h +rsa.h +``` + +Places where some of these headers are used: + +* `library/ssl_*.c` (for DHM in TLS 1.2, which is going to be removed: https://github.com/Mbed-TLS/mbedtls/issues/9685) +* `programs/fuzz/fuzz_*key.c` (to fuzz RSA functions that are now private) +* `programs/ssl/ssl_test_lib.c` (HMAC\_DRBG; can move to only using the PSA RNG) +* `programs/test/benchmark.c` (HMAC\_DRBG) +* `programs/test/selftest.c` +* `scripts/data_files/query_config.fmt` + +Main loss of functionality: + +* Finite-field Diffie-Hellman with arbitrary groups. We've decided that this is acceptable. See “[Removal of low-level DHM](#removal-of-low-level-dhm)”. +* Custom RSA mechanisms. We've decided that this is acceptable. +* PKCS5 and PKCS12 mechanisms except as exposed by the pk module. We've decided that this is acceptable. +* HMAC\_DRBG in itself (i.e. outside of deterministic ECDSA and for the PSA Crypto RNG instance). We intend to restore this functionality through a PSA API, but the API isn't designed yet, so this will happen after 1.0 and not with the existing API. + +`drivers/builtin/include/mbedtls/build_info.h` is a special case that exists only as a transition for the sake of our source files contains `#include ` and that must be buildable against either TF-PSA-Crypto or Mbed TLS. It should be removed: https://github.com/Mbed-TLS/mbedtls/issues/9862 . + +We will make these headers internal after 0ε. For 0ε, they can remain private. + +#### Headers that will become internal eventually + +The headers listed below should be private, but are currently used in Mbed TLS to an extent that makes it hard to remove before the 1.0/4.0 release. As a result, they need to remain exposed to Mbed TLS, but should be clearly indicated as not part of the stable API. + +``` +ctr_drbg.h +entropy.h +error_common.h +oid.h +``` + +Main loss of functionality: + +* CTR\_DRBG in itself (i.e. other than for the PSA Crypto RNG instance). We intend to restore this functionality through a PSA API, but the API isn't designed yet, so this will happen after 1.0 and not with the existing API. +* Direct access to entropy sources. We've decided that this is acceptable. +* The ability to configure entropy sources on a platform. This is not an acceptable loss. In the long term (likely after 1.0), this will be resolved by the PSA crypto random driver API. In the short term, we will expose a modified `mbedtls_hardware_poll()` (https://github.com/Mbed-TLS/mbedtls/issues/9618) through `mbedtls/platform.h`. +* `MBEDTLS_ERROR_ADD` will no longer be used after https://github.com/Mbed-TLS/mbedtls/pull/9926 . + +We will make these headers internal after 0ε. For 0ε, they can remain private. + +#### Move private headers + +Move private and exposed headers so that they are always under a subdirectory called `.../private`. This is a simple way of conveying that their content is not part of the public API both to humans and to programs. In particular, this makes it clear to human readers that the header's content is not part of the public API, even after the headers are installed. (Merely relying on the layout of the source tree does not help after installation.) + +Note that public headers can include private headers, since some private headers define exposed types and macros. + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/10087): Move TF-PSA-Crypto private headers from `drivers/builtin/include/mbedtls` to `drivers/builtin/include/mbedtls/private`. Move mbedtls private headers from `include/mbedtls` to `include/mbedtls/private`. This requires coordinated action between the three repositories. + +OPEN: is this really necessary? If we don't do this, attempts to call exposed functions will fail thanks to `MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS` (see “[Hiding functions in an exposed header](#hiding-functions-in-an-exposed-header)”). But this preprocessor guard is discrete and users are likely to miss it, leading to frustration when their code mysteriously doesn't compile. + +#### Privatization of Everest headers + +Everest headers (`drivers/everest/include/everest/include/**/*.h`) contain some exposed types: they are exposed via `mbedtls_ecdh_context` from `mbedtls/ecdh.h` which is exposed via `mbedtls_psa_key_agreement_interruptible_operation_t` indirectly from `psa/crypto.h`. The rest of their content is private (to be consumed only by `ecdh.c`) or internal (to be consumed only by `everest/**/*.c`) definitions. + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/230): For 0ε, guard everything that isn't an exposed type (or necessary macros, if any) by `MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS`. + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/229): For 0ε, move Everest headers so that they are installed under `$PREFIX/include/tf-psa-crypto/private`. + +#### Privatization of 256-m headers + +P256-m headers only declare private functions (called by PSA driver wrappers). They do not expose anything. So they can be made internal to TF-PSA-Crypto. + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/228): do not install `p256/p256-m.h`. + +### Renaming mbedtls interfaces that remain public + +Some existing `mbedtls_xxx` interfaces declared in `` headers will remain public in TF-PSA-Crypto 1.0 (e.g. `mbedtls_asn1_xxx` from ``). Arguably, since they are no longer in Mbed TLS but in TF-PSA-Crypto, the interfaces should be renamed to `tfc_xxx` in ``. + +Prioritization: + +* Feature: irrelevant. +* Maintainability: negative, since it would complicate backports. +* Quality: dubious. It's better for new users to have API names that reflect the product names. But it's worse for existing users who would have more code to rewrite. + +At the moment, renaming existing interfaces (headers files, types, functions, macros, etc.) is out of scope of 0ε. + +## Private interfaces leaking through public interfaces + +Public interface elements must be usable without requiring private interfaces. Concretely, a public function must not have an argument type or a return type that uses a private type. + +### Legacy type report + +Output of `scripts/legacy_report.py -DMBEDTLS_USER_CONFIG_FILE='<../tests/configs/user_config_no_deprecated.h>' -I include -I tf-psa-crypto/include -I tf-psa-crypto/drivers/builtin/include include/mbedtls/*.h tf-psa-crypto/drivers/builtin/include/mbedtls/{asn1.h,asn1write.h,base64.h,constant_time.h,lms.h,memory_buffer_alloc.h,nist_kw.h,pem.h,pk.h,platform.h,platform_time.h,platform_util.h,psa_util.h,threading.h}` from https://github.com/gilles-peskine-arm/mbedtls/tree/legacy-unstable-headers-detect + +``` +tf-psa-crypto/drivers/builtin/include/mbedtls/pk.h:1035:36: mbedtls_pk_rsa#return: mbedtls_rsa_context * +tf-psa-crypto/drivers/builtin/include/mbedtls/pk.h:1058:36: mbedtls_pk_ec#return: mbedtls_ecp_keypair * +tf-psa-crypto/drivers/builtin/include/mbedtls/asn1.h:543:39: mbedtls_asn1_get_mpi#3=X: mbedtls_mpi * +include/mbedtls/ssl_ticket.h:126:52: mbedtls_ssl_ticket_setup#4=cipher: mbedtls_cipher_type_t +tf-psa-crypto/drivers/builtin/include/mbedtls/asn1write.h:104:47: mbedtls_asn1_write_mpi#3=X: const mbedtls_mpi * +tf-psa-crypto/drivers/builtin/include/mbedtls/nist_kw.h:78:48: mbedtls_nist_kw_setkey#2=cipher: mbedtls_cipher_id_t +tf-psa-crypto/drivers/builtin/include/mbedtls/psa_util.h:87:64: mbedtls_ecc_group_to_psa#1=grpid: mbedtls_ecp_group_id +tf-psa-crypto/drivers/builtin/include/mbedtls/psa_util.h:102:22: mbedtls_ecc_group_from_psa#return: mbedtls_ecp_group_id +``` + +### Private types in `pk.h` + +`pk.h` only exposes private types through deprecated functions which will be removed from the [Shrunk-down `pk.h`](#shrunk-down-pkh). + +### Private types in `asn1.h` and `asn1write.h` + +The ASN.1 interfaces use `mbedtls_mpi` for INTEGER parsing/writing. This must change to a byte array. This is filed as https://github.com/Mbed-TLS/mbedtls/issues/9373 and https://github.com/Mbed-TLS/mbedtls/issues/9372 . + +### Private types in `nist_kw.h` + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/9382): `nist_kw.h` must switch from a legacy cipher ID to a PSA key type. + +### Private types in `psa_util.h` + +The functions `mbedtls_ecc_group_to_psa()` and `mbedtls_ecc_group_from_psa()` are no longer relevant for public use since the legacy side of the conversion is no longer a public interface. They are not used in Mbed TLS. They should be moved to an internal header. + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/231): Move the declarations of `mbedtls_ecc_group_to_psa()` and `mbedtls_ecc_group_from_psa()` to `pk_internal.h`. + +### Private types in `ssl_ticket.h` + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/9874): `ssl_ticket.h` uses a legacy cipher type to specify the AEAD mechanism to use for tickets. Switch to a PSA key type and algorithm. + +### Leaking error codes + +#### About leaking error codes + +Non-PSA functions signal errors by returning an `MBEDTLS_ERR_xxx` error code. They return the type `int`, so this does not appear in type-based analyses. + +In Mbed TLS 3, all error codes are declared and documented in public headers. Since all error codes are part of the official API, functions cannot return undocumented error codes, by construction. (This assumes that we use `MBEDTLS_ERR_xxx` constants when we decide which error code to return, which we do.) + +Many of the error codes in TF-PSA-Crypto are declared in headers that are becoming private, either exposed or not. These error codes are generally intended for functions declared in the same module, however they may also be used in other modules, in particular when module A calls functions from module B and forwards error codes from module B. This can cause three problems: + +* Mbed TLS code checks for specific error codes from crypto functions. These error codes must remain exposed. +* Specific error codes appear in TF-PSA-Crypto or Mbed TLS documentation. These error codes are thus effectively public, and the declaration of the `MBEDTLS_ERR_xxx` constant should remain public. +* Public functions return error codes that are now private, thus undocumented. This is a quality problem for users. It is not critical to resolve this problem before the 1.0 release, because if the specific error code is not documented, a future minor release can either start documenting the error code or change the function's behavior to make it return a documented error code instead. + +#### Assumptions on error codes + +In Mbed TLS up to 3.x, all error codes are values between -32767 and -1, with 0 meaning success. There are two types of status codes: + +* `psa_status_t`, returned by PSA functions (`psa_xxx()` or `mbedtls_psa_xxx()`). Success is `PSA_SUCCESS == 0` and errors are `PSA_ERROR_xxx` constants. +* `int`, returned by Mbed TLS functions (`mbedtls_xxx()` except `mbedtls_psa_xxx()`). Success is 0. Mbed TLS error codes (legacy errors) have the form `low + high` where `-127 <= low <= 0` and `high` is either 0 or of the form `-128 * n` for `16 <= n <= 255` (this is an unambiguous decomposition) (`low == high == 0` is the success value). + +Having to convert between the two error code spaces costs significant code size. It also adds complexity and we occasionally have bugs where we forget to convert. Thus it would be desirable not to have this distinction. + +It is already the case in Mbed TLS 3.x that a PSA error value cannot be equal to a legacy error, because we avoid assigning values in a range that would overlap. (PSA error codes are in the range [-255, -128], while legacy error codes are either in the range [-127, -1] (low) or [-32767, -4096] (high or high+low).) + +In many places, a high-level module adds a constant to the error code returned by a low-level module. This requires the low-level module to return a low-level error (where the high part is 0). If the low-level module changes to return a PSA error, the addition will not result in an unambiguous value. + +#### Unified error code space + +To avoid constraining the refactoring of low-level interfaces and low-level modules, as well as simplify the rework of high-level modules, we will do a little upfront work to unify the error code space: https://github.com/Mbed-TLS/mbedtls/issues/9619#issuecomment-2612664288 + +Once that is done: + +* `MBEDTLS_ERROR_ADD` is a no-op (it just returns one of its arguments — currently the low-level code). New code does not need to bother. +* Any legacy error code can be removed from the public documentation and made an alias of a PSA error code. +* New code can just pick PSA error codes when convenient. +* All conversions between error codes can be removed. (This can, but probably shouldn't, be done all at once. If done piecewise, this needs to be divided adequately in the sense that when a function stops converting its error codes, its callers must stop expecting converted error codes.) + +#### Publicly documented private error codes + +Output of `grep -P 'MBEDTLS_ERR_(?!ASN1_|BASE64_|LMS_|NET_|NIST_KW_|PEM_|PKCS7_|PK_|PLATFORM_|SSL_|THREADING_|X509_|XXX)' include/mbedtls/*.h tf-psa-crypto/drivers/builtin/include/mbedtls/{asn1.h,asn1write.h,base64.h,constant_time.h,lms.h,memory_buffer_alloc.h,nist_kw.h,pem.h,pk.h,platform.h,platform_time.h,platform_util.h,psa_util.h,threading.h}`: + +``` +include/mbedtls/x509.h: * MBEDTLS_ERR_OID_BUF_TOO_SMALL in case of error +include/mbedtls/x509_crt.h: * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of +tf-psa-crypto/drivers/builtin/include/mbedtls/nist_kw.h: * \return \c MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA for any invalid input. +tf-psa-crypto/drivers/builtin/include/mbedtls/nist_kw.h: * \return \c MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE for 128-bit block ciphers +tf-psa-crypto/drivers/builtin/include/mbedtls/nist_kw.h: * \return \c MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA for invalid input length. +tf-psa-crypto/drivers/builtin/include/mbedtls/nist_kw.h: * \return \c MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA for invalid input length. +tf-psa-crypto/drivers/builtin/include/mbedtls/nist_kw.h: * \return \c MBEDTLS_ERR_CIPHER_AUTH_FAILED for verification failure of the ciphertext. +tf-psa-crypto/drivers/builtin/include/mbedtls/pk.h: * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of +tf-psa-crypto/drivers/builtin/include/mbedtls/pk.h: * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of +tf-psa-crypto/drivers/builtin/include/mbedtls/psa_util.h: * \return An `MBEDTLS_ERR_ENTROPY_xxx`, +tf-psa-crypto/drivers/builtin/include/mbedtls/psa_util.h: * `MBEDTLS_ERR_CTR_DRBG_xxx` or +tf-psa-crypto/drivers/builtin/include/mbedtls/psa_util.h: * `MBEDTLS_ERR_HMAC_DRBG_xxx` on error. +``` + +This tells us which error codes are documented in public headers but defined in private headers. Note that there are likely to be many error codes that are not specifically documented (or only vaguely, e.g. “a specific X509 or PEM error code”), but in such cases we can change which error is returned in a minor release. + +To fix these cases: + +* Make `MBEDTLS_ERR_OID_BUF_TOO_SMALL` an alias of `PSA_ERROR_BUFFER_TOO_SMALL`. +* Make `MBEDTLS_ERR_ECP_IN_PROGRESS` an alias of `PSA_OPERATION_INCOMPLETE`. +* When moving NIST\_KW to the PSA API (https://github.com/Mbed-TLS/mbedtls/issues/9382), for error conditions that are discovered inside `nist_kw.c`, make it return PSA error codes. Errors from lower-level functions can just be propagated without conversion. +* In `psa_util.h`, the documented legacy error code categories are for `mbedtls_psa_get_random`, which is no longer needed. See [Shrunk-down `psa_util.h`](#shrunk-down-psa_utilh). + +#### Unifying error codes + +Ideally we should unify legacy error codes with PSA error codes that have the same meaning. Note that this includes unifying legacy error codes since these tend to be per-module. For example, ideally, all `MBEDTLS_ERR_xxx_ALLOC_FAILED` errors would change to `PSA_ERROR_INSUFFICIENT_MEMORY`. + +A legacy error name (`MBEDTLS_ERR_xxx`) can be made an alias for a PSA error: just change `#define MBEDTLS_ERR_xxx -0xNNN` to `#define MBEDTLS_ERR_xxx PSA_ERROR_yyy`. https://github.com/Mbed-TLS/mbedtls/pull/9926 does a few to show that it works. + +See https://github.com/Mbed-TLS/mbedtls/issues/8501 . This is beyond the code of 0ε and 4ε, but we may do some of it on an ad hoc basis. + +Note that if we want to be able to remove all error code translations (to save code size and complexity), we need to use PSA errors in all low-level modules, including ones that remain public such as ASN.1. In a 1.x minor release, we can declare that `MBEDTLS_ERR_xxx` is now a PSA error by giving it a new name `PSA_ERROR_xxx`, but not by making it an alias of an existing `PSA_ERROR_xxx`, since aliasing errors is an API break. + +## Changes to compilation options + +### Strategy for removing a compilation option + +#### Types of compilation option removals + +There are ways in which a compilation option can be removed from the public interface: + +* The option is no longer referenced in the code base. Setting it is harmless. +* The option is still present in the code base, but now implied by other options. This is notably the case for legacy crypto options that are now always controlled via `PSA_WANT_xxx` (`MBEDTLS_PSA_CRYPTO_CONFIG` always on). Setting it may cause the configuration to be inconsistent, so we should complain if the option is set through a configuration file (`mbedtls/mbedtls_config.h`, `psa/crypto_config.h` or similar) rather than internally (in `*/config_adjust*.h`). +* The option is still present in the code base and not set automatically, but it is not part of the public interface, and will be removed in 1.x/4.x. This happens when we remove a feature that tests still rely on (for example, directly removing some small elliptic curves ([#8136](https://github.com/Mbed-TLS/mbedtls/issues/8136)) would remove some test coverage). We should complain if the option is set, unless it is set from our own test scripts. + +#### How to remove a legacy configuration option + +Goal: complain if a user tries to set an option in the configuration file (`mbedtls/mbedtls_config.h`, `psa/crypto_config.h` or similar), for options that existed in 3.x but have become internal in 1.0/4.0. + +This concerns, in particular, legacy crypto options that are now always controlled via `PSA_WANT_xxx` (`MBEDTLS_PSA_CRYPTO_CONFIG` always on). + +Note that users may be setting crypto options in the Mbed TLS configuration, which is included after the config adjustments in TF-PSA-Crypto have set some legacy symbols. We need a complaint if TF-PSA-Crypto's `build_info.h` does not set some legacy option and the user's `mbedtls_config.h` then sets it. How can we do this? + +* Remember the state of all implied options before including the Mbed TLS configuration, then check if it has changed. This requires a lot of boilerplate. This doesn't cause a complaint if the Mbed TLS configuration sets an implied option redundantly, only if it sets an implied option that should no longer be set. +* Set implied options to an expansion that is a nonzero integer (e.g. 0xdeadc0f1) when doing config adjustments. After reading the Mbed TLS configuration, reject implied options that are defined but false (which is the case for `#if FOO` when `FOO` is defined with an empty expansion). This causes a complaint if the Mbed TLS configuration sets an option redundantly, but the reason for the complaint is not clear from the error message (macro redefinition warning). +* Rename all implied options internally. This would be ideal, but it's a lot of work, including work in the framework, so it is not achievable for 0ε. +* Temporarily rename implied options around the inclusion of the Mbed TLS configuration (e.g. `#ifdef FOO #define REMEMBER_FOO #undef FOO #endif` before, and `#ifdef FOO #error #endif #ifdef REMEMBER_FOO #define FOO #endif` after). This requires a lot of boilerplate. +* Split `build_info.h` differently so that we can have all user configuration, then the removed-option checks, then the config adjustments. This doesn't seem doable since the application code may have included a crypto header before any mbedtls header. + +Requiring a lot of boilerplate is not much of a problem. The code follows a systematic pattern and can be generated easily. This code is unlikely to change throughout 1.x/4.x, so we can generate it and check it in as part of the 0ε work. + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/10147): in `build_info.h`, after including the user configuration file but before the configuration adjustments, include a header that has `#error` directives for each preprocessor symbol that was a configuration option in 3.6 but no longer is in 1.0/4.0. Suggested header names: + +* `mbedtls/check_config_removed.h` +* `tf-psa-crypto/check_config_removed.h` + +#### How to remove a feature option from the interface + +Goal: have a way for an option to be forbidden to users, but allowed in our test scripts. + +This concerns options controlling features that we want to remove, but that we still rely on. For example DES to decrypt some test keys, or small elliptic curves used in some curve-agnostic testing. + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/10147): define a new option in `psa/crypto_config.h` called `TF_PSA_CRYPTO_ALLOW_REMOVED_FEATURES`, disabled by default. Let it be enabled in the `full` configuration. Add a section in `psa/crypto_config.h` for removed options with a comment explaining that the options in this section are not part of the interface. In `config.py`, exclude this whole section from the `realfull` configuration. + +Then, to remove a feature option `FOO` from the interface without removing it from the code base: + +* Keep `//#define FOO` in `psa/crypto_config.h`, but remove its documentation and move the line to the removed features section. +* In any `all.sh` component that enables the option from the default configuration rather than from the `full` configuration, explicitly enable `TF_PSA_CRYPTO_ALLOW_REMOVED_FEATURES`. +* We should not do this for any option that is enabled in a sample configuration. + +### Analysis of legacy crypto options + +#### List of boolean legacy crypto options + +Legacy crypto boolean options: `perl -l -ne 'print $1 if /#define +(MBEDTLS_\w+)($| *\/)/' tf-psa-crypto/include/psa/crypto_config.h | sort` + +``` +MBEDTLS_AESCE_C +MBEDTLS_AESNI_C +MBEDTLS_AES_C +MBEDTLS_AES_FEWER_TABLES +MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH +MBEDTLS_AES_ROM_TABLES +MBEDTLS_AES_USE_HARDWARE_ONLY +MBEDTLS_ARIA_C +MBEDTLS_ASN1_PARSE_C +MBEDTLS_ASN1_WRITE_C +MBEDTLS_BASE64_C +MBEDTLS_BIGNUM_C +MBEDTLS_BLOCK_CIPHER_NO_DECRYPT +MBEDTLS_CAMELLIA_C +MBEDTLS_CAMELLIA_SMALL_MEMORY +MBEDTLS_CCM_C +MBEDTLS_CHACHA20_C +MBEDTLS_CHACHAPOLY_C +MBEDTLS_CHECK_RETURN_WARNING +MBEDTLS_CIPHER_C +MBEDTLS_CIPHER_MODE_CBC +MBEDTLS_CIPHER_MODE_CFB +MBEDTLS_CIPHER_MODE_CTR +MBEDTLS_CIPHER_MODE_OFB +MBEDTLS_CIPHER_MODE_XTS +MBEDTLS_CIPHER_NULL_CIPHER +MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +MBEDTLS_CIPHER_PADDING_PKCS7 +MBEDTLS_CIPHER_PADDING_ZEROS +MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +MBEDTLS_CMAC_C +MBEDTLS_CTR_DRBG_C +MBEDTLS_CTR_DRBG_USE_128_BIT_KEY +MBEDTLS_DEPRECATED_REMOVED +MBEDTLS_DEPRECATED_WARNING +MBEDTLS_DES_C +MBEDTLS_DHM_C +MBEDTLS_ECDH_C +MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED +MBEDTLS_ECDSA_C +MBEDTLS_ECDSA_DETERMINISTIC +MBEDTLS_ECJPAKE_C +MBEDTLS_ECP_C +MBEDTLS_ECP_DP_BP256R1_ENABLED +MBEDTLS_ECP_DP_BP384R1_ENABLED +MBEDTLS_ECP_DP_BP512R1_ENABLED +MBEDTLS_ECP_DP_CURVE25519_ENABLED +MBEDTLS_ECP_DP_CURVE448_ENABLED +MBEDTLS_ECP_DP_SECP192K1_ENABLED +MBEDTLS_ECP_DP_SECP192R1_ENABLED +MBEDTLS_ECP_DP_SECP224K1_ENABLED +MBEDTLS_ECP_DP_SECP224R1_ENABLED +MBEDTLS_ECP_DP_SECP256K1_ENABLED +MBEDTLS_ECP_DP_SECP256R1_ENABLED +MBEDTLS_ECP_DP_SECP384R1_ENABLED +MBEDTLS_ECP_DP_SECP521R1_ENABLED +MBEDTLS_ECP_NIST_OPTIM +MBEDTLS_ECP_RESTARTABLE +MBEDTLS_ECP_WITH_MPI_UINT +MBEDTLS_ENTROPY_C +MBEDTLS_ENTROPY_FORCE_SHA256 +MBEDTLS_ENTROPY_HARDWARE_ALT +MBEDTLS_ENTROPY_NV_SEED +MBEDTLS_FS_IO +MBEDTLS_GCM_C +MBEDTLS_GCM_LARGE_TABLE +MBEDTLS_GENPRIME +MBEDTLS_HAVE_ASM +MBEDTLS_HAVE_SSE2 +MBEDTLS_HAVE_TIME +MBEDTLS_HAVE_TIME_DATE +MBEDTLS_HKDF_C +MBEDTLS_HMAC_DRBG_C +MBEDTLS_LMS_C +MBEDTLS_LMS_PRIVATE +MBEDTLS_MD5_C +MBEDTLS_MD_C +MBEDTLS_MEMORY_BACKTRACE +MBEDTLS_MEMORY_BUFFER_ALLOC_C +MBEDTLS_MEMORY_DEBUG +MBEDTLS_NIST_KW_C +MBEDTLS_NO_64BIT_MULTIPLICATION +MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES +MBEDTLS_NO_PLATFORM_ENTROPY +MBEDTLS_NO_UDBL_DIVISION +MBEDTLS_OID_C +MBEDTLS_PEM_PARSE_C +MBEDTLS_PEM_WRITE_C +MBEDTLS_PKCS12_C +MBEDTLS_PKCS1_V15 +MBEDTLS_PKCS1_V21 +MBEDTLS_PKCS5_C +MBEDTLS_PK_C +MBEDTLS_PK_PARSE_C +MBEDTLS_PK_PARSE_EC_COMPRESSED +MBEDTLS_PK_PARSE_EC_EXTENDED +MBEDTLS_PK_RSA_ALT_SUPPORT +MBEDTLS_PK_WRITE_C +MBEDTLS_PLATFORM_C +MBEDTLS_PLATFORM_EXIT_ALT +MBEDTLS_PLATFORM_FPRINTF_ALT +MBEDTLS_PLATFORM_GMTIME_R_ALT +MBEDTLS_PLATFORM_MEMORY +MBEDTLS_PLATFORM_MS_TIME_ALT +MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +MBEDTLS_PLATFORM_NV_SEED_ALT +MBEDTLS_PLATFORM_PRINTF_ALT +MBEDTLS_PLATFORM_SETBUF_ALT +MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT +MBEDTLS_PLATFORM_SNPRINTF_ALT +MBEDTLS_PLATFORM_TIME_ALT +MBEDTLS_PLATFORM_VSNPRINTF_ALT +MBEDTLS_PLATFORM_ZEROIZE_ALT +MBEDTLS_POLY1305_C +MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS +MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS +MBEDTLS_PSA_CRYPTO_C +MBEDTLS_PSA_CRYPTO_CLIENT +MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG +MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER +MBEDTLS_PSA_CRYPTO_SE_C +MBEDTLS_PSA_CRYPTO_SPM +MBEDTLS_PSA_CRYPTO_STORAGE_C +MBEDTLS_PSA_INJECT_ENTROPY +MBEDTLS_PSA_ITS_FILE_C +MBEDTLS_PSA_KEY_STORE_DYNAMIC +MBEDTLS_PSA_P256M_DRIVER_ENABLED +MBEDTLS_PSA_STATIC_KEY_SLOTS +MBEDTLS_RIPEMD160_C +MBEDTLS_RSA_C +MBEDTLS_RSA_NO_CRT +MBEDTLS_SELF_TEST +MBEDTLS_SHA1_C +MBEDTLS_SHA224_C +MBEDTLS_SHA256_C +MBEDTLS_SHA256_SMALLER +MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT +MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY +MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT +MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY +MBEDTLS_SHA384_C +MBEDTLS_SHA3_C +MBEDTLS_SHA512_C +MBEDTLS_SHA512_SMALLER +MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT +MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY +MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN +MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND +MBEDTLS_TEST_HOOKS +MBEDTLS_THREADING_ALT +MBEDTLS_THREADING_C +MBEDTLS_THREADING_PTHREAD +``` + +#### Boolean options that can be set indirectly + +Options that can be set via adjustment, and can currently also be set directly. Such options are likely to be redundant, however not all of them are. + +`perl -l -ne 'print $1 if /#define +(MBEDTLS_\w+)($| *\/)/' tf-psa-crypto/include/psa/crypto_adjust_* tf-psa-crypto/drivers/builtin/include/mbedtls/*adjust* | sort -u | comm -12 - <(perl -l -ne 'print $1 if /#define +(MBEDTLS_\w+)($| *\/)/' tf-psa-crypto/include/psa/crypto_config.h | sort)` + +| Option | Replacement | Notes | +| ------ | ----------- | ----- | +| `MBEDTLS_AES_C` | `PSA_WANT_KEY_TYPE_AES` | | +| `MBEDTLS_ARIA_C` | `PSA_WANT_KEY_TYPE_ARIA` | | +| `MBEDTLS_ASN1_PARSE_C` | Keep | [Changes to ASN.1 enablement](#changes-to-asn1-enablement) | +| `MBEDTLS_ASN1_WRITE_C` | Keep | [Changes to ASN.1 enablement](#changes-to-asn1-enablement) | +| `MBEDTLS_BIGNUM_C` | Remove | Enabled as needed by asymmetric crypto | +| `MBEDTLS_CAMELLIA_C` | `PSA_WANT_KEY_TYPE_CAMELLIA` | | +| `MBEDTLS_CCM_C` | `PSA_WANT_ALG_CCM` | | +| `MBEDTLS_CHACHA20_C` | `PSA_WANT_KEY_TYPE_CHACHA20` | | +| `MBEDTLS_CHACHAPOLY_C` | `PSA_WANT_ALG_CHACHA20_POLY1305` | | +| `MBEDTLS_CIPHER_C` | Remove | Enabled as needed by cipher modes | +| `MBEDTLS_CIPHER_MODE_CBC` | `PSA_WANT_ALG_CBC_PKCS7`, `PSA_WANT_ALG_CBC_NO_PADDING` | | +| `MBEDTLS_CIPHER_MODE_CFB` | `PSA_WANT_ALG_CFB` | | +| `MBEDTLS_CIPHER_MODE_CTR` | `PSA_WANT_ALG_CTR` | | +| `MBEDTLS_CIPHER_MODE_OFB` | `PSA_WANT_ALG_OFB` | | +| `MBEDTLS_CIPHER_PADDING_PKCS7` | `PSA_WANT_ALG_CBC_PKCS7` | | +| `MBEDTLS_CMAC_C` | `PSA_WANT_ALG_CMAC` | | +| `MBEDTLS_DES_C` | `PSA_WANT_KEY_TYPE_DES` | May be removed: [Mbed-TLS/mbedtls#9164](https://github.com/Mbed-TLS/mbedtls/issues/9164) | +| `MBEDTLS_ECDH_C` | `PSA_WANT_ALG_ECDH` | | +| `MBEDTLS_ECDSA_C` | `PSA_WANT_ALG_ECDSA`, `PSA_WANT_ALG_DETERMINISTIC_ECDSA` | | +| `MBEDTLS_ECDSA_DETERMINISTIC` | `PSA_WANT_ALG_DETERMINISTIC_ECDSA` | | +| `MBEDTLS_ECJPAKE_C` | `PSA_WANT_ALG_JPAKE` + `PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE` | | +| `MBEDTLS_ECP_C` | Remove | Enabled as needed by ECC mechanisms | +| `MBEDTLS_ECP_DP_BP256R1_ENABLED` | `PSA_WANT_ECC_BRAINPOOL_P_R1_256` | | +| `MBEDTLS_ECP_DP_BP384R1_ENABLED` | `PSA_WANT_ECC_BRAINPOOL_P_R1_384` | | +| `MBEDTLS_ECP_DP_BP512R1_ENABLED` | `PSA_WANT_ECC_BRAINPOOL_P_R1_512` | | +| `MBEDTLS_ECP_DP_CURVE25519_ENABLED` | `PSA_WANT_ECC_MONTGOMERY_255` | | +| `MBEDTLS_ECP_DP_CURVE448_ENABLED` | `PSA_WANT_ECC_MONTGOMERY_448` | | +| `MBEDTLS_ECP_DP_SECP192K1_ENABLED` | `PSA_WANT_ECC_SECP_K1_192` | May be removed: [Mbed-TLS/mbedtls#8136](https://github.com/Mbed-TLS/mbedtls/issues/8136) | +| `MBEDTLS_ECP_DP_SECP192R1_ENABLED` | `PSA_WANT_ECC_SECP_R1_192` | May be removed: [Mbed-TLS/mbedtls#8136](https://github.com/Mbed-TLS/mbedtls/issues/8136) | +| `MBEDTLS_ECP_DP_SECP224R1_ENABLED` | `PSA_WANT_ECC_SECP_R1_224` | May be removed: [Mbed-TLS/mbedtls#8136](https://github.com/Mbed-TLS/mbedtls/issues/8136) | +| `MBEDTLS_ECP_DP_SECP256K1_ENABLED` | `PSA_WANT_ECC_SECP_K1_256` | | +| `MBEDTLS_ECP_DP_SECP256R1_ENABLED` | `PSA_WANT_ECC_SECP_R1_256` | | +| `MBEDTLS_ECP_DP_SECP384R1_ENABLED` | `PSA_WANT_ECC_SECP_R1_384` | | +| `MBEDTLS_ECP_DP_SECP521R1_ENABLED` | `PSA_WANT_ECC_SECP_R1_521` | | +| `MBEDTLS_GCM_C` | `PSA_WANT_ALG_GCM` | | +| `MBEDTLS_GENPRIME` | `PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE` | | +| `MBEDTLS_HMAC_DRBG_C` | TBD | [Changes to RNG options](#changes-to-rng-options) | +| `MBEDTLS_MD5_C` | `PSA_WANT_ALG_MD5` | | +| `MBEDTLS_MD_C` | Keep | Reduced to what was `MBEDTLS_MD_LIGHT`: [Public hash-only `md.h`](#public-hash-only-mdh) | +| `MBEDTLS_OID_C` | Keep | [OID conditional compilation](#oid-conditional-compilation) | +| `MBEDTLS_PKCS1_V15` | `PSA_WANT_ALG_RSA_PKCS1V15_CRYPT`, `PSA_WANT_ALG_RSA_PKCS1V15_SIGN` | | +| `MBEDTLS_PKCS1_V21` | `PSA_WANT_ALG_RSA_OAEP`, `PSA_WANT_ALG_RSA_PSS` | | +| `MBEDTLS_PK_PARSE_EC_COMPRESSED` | Keep | | +| `MBEDTLS_PLATFORM_SNPRINTF_ALT` | Keep | | +| `MBEDTLS_PLATFORM_VSNPRINTF_ALT` | Keep | | +| `MBEDTLS_POLY1305_C` | `PSA_WANT_ALG_CHACHA20_POLY1305` | | +| `MBEDTLS_PSA_CRYPTO_CLIENT` | Keep | maybe [revise client/server inclusion](#revise-clientserver-inclusion) | +| `MBEDTLS_RIPEMD160_C` | `PSA_WANT_ALG_RIPEMD160` | | +| `MBEDTLS_RSA_C` | `PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY` | | +| `MBEDTLS_SHA1_C` | `PSA_WANT_ALG_SHA_1` | | +| `MBEDTLS_SHA224_C` | `PSA_WANT_ALG_SHA_224` | | +| `MBEDTLS_SHA256_C` | `PSA_WANT_ALG_SHA_256` | | +| `MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT` | Keep | Only currently auto-enabled from a deprecated synonym | +| `MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY` | Keep | Only currently auto-enabled from a deprecated synonym | +| `MBEDTLS_SHA384_C` | `PSA_WANT_ALG_SHA_384` | | +| `MBEDTLS_SHA3_C` | `PSA_WANT_ALG_SHA_3` | | +| `MBEDTLS_SHA512_C` | `PSA_WANT_ALG_SHA_512` | | + +#### Boolean options that cannot be set indirectly + +Options that can currently be set directly, and cannot be set via adjustment. Such options are likely to be still relevant. However, some may have become irrelevant, for example if they configure a module that is being removed. + +`perl -l -ne 'print $1 if /#define +(MBEDTLS_\w+)($| *\/)/' tf-psa-crypto/include/psa/crypto_adjust_* tf-psa-crypto/drivers/builtin/include/mbedtls/*adjust* | sort -u | comm -13 - <(perl -l -ne 'print $1 if /#define +(MBEDTLS_\w+)($| *\/)/' tf-psa-crypto/include/psa/crypto_config.h | sort)` + +| Option | Fate | Notes | +| ------ | ---- | ----- | +| `MBEDTLS_AESCE_C` | Keep | Tune built-in crypto | +| `MBEDTLS_AESNI_C` | Keep | Tune built-in crypto | +| `MBEDTLS_AES_FEWER_TABLES` | Keep | Tune built-in crypto | +| `MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH` | Keep | Feature selection not available through `PSA_WANT` | +| `MBEDTLS_AES_ROM_TABLES` | Keep | Tune built-in crypto | +| `MBEDTLS_AES_USE_HARDWARE_ONLY` | Keep | Tune built-in crypto | +| `MBEDTLS_BASE64_C` | Keep | Crypto-adjacent feature, [remains public](#headers-that-remain-public) | +| `MBEDTLS_BLOCK_CIPHER_NO_DECRYPT` | Keep in 0ε | Should be deduced from `PSA_WANT`: [Mbed-TLS/mbedtls#9163](https://github.com/Mbed-TLS/mbedtls/issues/9163) | +| `MBEDTLS_CAMELLIA_SMALL_MEMORY` | Keep | Tune built-in crypto | +| `MBEDTLS_CHECK_RETURN_WARNING` | Keep | Platform feature | +| `MBEDTLS_CIPHER_MODE_XTS` | Remove (keep the code) | [XTS migration](#xts-migration) | +| `MBEDTLS_CIPHER_NULL_CIPHER` | Remove | No longer used by TLS | +| `MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS` | Remove | [Obsolete cipher padding modes](#obsolete-cipher-padding-modes) | +| `MBEDTLS_CIPHER_PADDING_ZEROS` | Remove | [Obsolete cipher padding modes](#obsolete-cipher-padding-modes) | +| `MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN` | Remove | [Obsolete cipher padding modes](#obsolete-cipher-padding-modes) | +| `MBEDTLS_CTR_DRBG_C` | TBD | [Changes to RNG options](#changes-to-rng-options) | +| `MBEDTLS_CTR_DRBG_USE_128_BIT_KEY` | TBD | [Changes to RNG options](#changes-to-rng-options) | +| `MBEDTLS_DEPRECATED_REMOVED` | Keep | Generic feature support | +| `MBEDTLS_DEPRECATED_WARNING` | Keep | Generic feature support | +| `MBEDTLS_DHM_C` | Remove | Dead code: [removal of low-level DHM](#removal-of-low-level-dhm) | +| `MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED` | Keep | Tune built-in crypto | +| `MBEDTLS_ECP_DP_SECP224K1_ENABLED` | Remove | [Removal of small elliptic curves](#removal-of-small-elliptic-curves) | +| `MBEDTLS_ECP_NIST_OPTIM` | Keep | Tune built-in crypto | +| `MBEDTLS_ECP_RESTARTABLE` | Keep | No corresponding PSA option yet | +| `MBEDTLS_ECP_WITH_MPI_UINT` | Keep | Tune built-in crypto | +| `MBEDTLS_ENTROPY_C` | Remove (now implied) | See [Builds without entropy](#builds-without-entropy) | +| `MBEDTLS_ENTROPY_FORCE_SHA256` | TBD | [Changes to RNG options](#changes-to-rng-options) | +| `MBEDTLS_ENTROPY_HARDWARE_ALT` | Keep | Now enables a slightly different callback: [Mbed-TLS/mbedtls#9618](https://github.com/Mbed-TLS/mbedtls/issues/9618) | +| `MBEDTLS_ENTROPY_NV_SEED` | Keep | Platform feature | +| `MBEDTLS_FS_IO` | Keep | Platform configuration | +| `MBEDTLS_GCM_LARGE_TABLE` | Keep | Tune built-in crypto | +| `MBEDTLS_HAVE_ASM` | Keep | Tune built-in crypto | +| `MBEDTLS_HAVE_SSE2` | Keep | Tune built-in crypto | +| `MBEDTLS_HAVE_TIME` | Move | [Move time options back to Mbed TLS](#move-time-options-back-to-mbed-tls) | +| `MBEDTLS_HAVE_TIME_DATE` | Move | [Move time options back to Mbed TLS](#move-time-options-back-to-mbed-tls) | +| `MBEDTLS_HKDF_C` | Remove | Not used by PSA: [Mbed-TLS/mbedtls#9150](https://github.com/Mbed-TLS/mbedtls/issues/9150) | +| `MBEDTLS_LMS_C` | Keep | Crypto not yet in PSA | +| `MBEDTLS_LMS_PRIVATE` | Keep | Crypto not yet in PSA | +| `MBEDTLS_MEMORY_BACKTRACE` | Keep | Platform feature | +| `MBEDTLS_MEMORY_BUFFER_ALLOC_C` | Keep | Platform feature | +| `MBEDTLS_MEMORY_DEBUG` | Keep | Platform feature | +| `MBEDTLS_NIST_KW_C` | Keep | Crypto not yet in PSA | +| `MBEDTLS_NO_64BIT_MULTIPLICATION` | Keep | Tune built-in crypto | +| `MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES` | TBD | [Changes to RNG options](#changes-to-rng-options) | +| `MBEDTLS_NO_PLATFORM_ENTROPY` | TBD | [Changes to RNG options](#changes-to-rng-options) | +| `MBEDTLS_NO_UDBL_DIVISION` | Keep | Tune built-in crypto | +| `MBEDTLS_PEM_PARSE_C` | Keep | Crypto-adjacent feature, [remains public](#headers-that-remain-public) | +| `MBEDTLS_PEM_WRITE_C` | Keep | Crypto-adjacent feature, [remains public](#headers-that-remain-public) | +| `MBEDTLS_PKCS12_C` | Keep | No longer an exposed API, but functionality accessed through PK. Need doc update. | +| `MBEDTLS_PKCS5_C` | Keep | No longer an exposed API, but functionality accessed through PK. Need doc update. | +| `MBEDTLS_PK_C` | Keep | No PSA equivalent yet | +| `MBEDTLS_PK_PARSE_C` | Keep | No PSA equivalent yet | +| `MBEDTLS_PK_PARSE_EC_EXTENDED` | Keep | No PSA equivalent yet | +| `MBEDTLS_PK_RSA_ALT_SUPPORT` | Remove | Feature subsumed by PSA drivers | +| `MBEDTLS_PK_WRITE_C` | Keep | No PSA equivalent yet | +| `MBEDTLS_PLATFORM_C` | Keep | Platform configuration | +| `MBEDTLS_PLATFORM_EXIT_ALT` | Keep | Platform configuration | +| `MBEDTLS_PLATFORM_FPRINTF_ALT` | Keep | Platform configuration | +| `MBEDTLS_PLATFORM_GMTIME_R_ALT` | Move | [Move time options back to Mbed TLS](#move-time-options-back-to-mbed-tls) | +| `MBEDTLS_PLATFORM_MEMORY` | Keep | Platform configuration | +| `MBEDTLS_PLATFORM_MS_TIME_ALT` | Move | [Move time options back to Mbed TLS](#move-time-options-back-to-mbed-tls) | +| `MBEDTLS_PLATFORM_NO_STD_FUNCTIONS` | Keep | Platform configuration | +| `MBEDTLS_PLATFORM_NV_SEED_ALT` | Keep | Platform configuration | +| `MBEDTLS_PLATFORM_PRINTF_ALT` | Keep | Platform configuration | +| `MBEDTLS_PLATFORM_SETBUF_ALT` | Keep | Platform configuration | +| `MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT` | Keep | Platform configuration | +| `MBEDTLS_PLATFORM_TIME_ALT` | Move | [Move time options back to Mbed TLS](#move-time-options-back-to-mbed-tls) | +| `MBEDTLS_PLATFORM_ZEROIZE_ALT` | Keep | Platform configuration | +| `MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS` | Keep | Tune built-in crypto | +| `MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS` | Keep | Core feature | +| `MBEDTLS_PSA_CRYPTO_C` | Keep | Core feature; maybe [revise client/server inclusion](#revise-clientserver-inclusion) | +| `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` | Keep | Platform configuration | +| `MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER` | Keep | Platform configuration | +| `MBEDTLS_PSA_CRYPTO_SE_C` | Remove | [Mbed-TLS/mbedtls#8151](https://github.com/Mbed-TLS/mbedtls/issues/8151) | +| `MBEDTLS_PSA_CRYPTO_SPM` | Keep | Core feature; maybe [revise client/server inclusion](#revise-clientserver-inclusion) | +| `MBEDTLS_PSA_CRYPTO_STORAGE_C` | Keep | Core feature | +| `MBEDTLS_PSA_INJECT_ENTROPY` | Remove | [Mbed-TLS/mbedtls#9707](https://github.com/Mbed-TLS/mbedtls/issues/9707) | +| `MBEDTLS_PSA_ITS_FILE_C` | Keep | Platform configuration | +| `MBEDTLS_PSA_KEY_STORE_DYNAMIC` | Keep | Core feature; maybe [revise key store selection](#revise-key-store-selection) | +| `MBEDTLS_PSA_P256M_DRIVER_ENABLED` | Keep | Tune built-in crypto | +| `MBEDTLS_PSA_STATIC_KEY_SLOTS` | Keep | Core feature; maybe [revise key store selection](#revise-key-store-selection) | +| `MBEDTLS_RSA_NO_CRT` | Remove | [Mbed-TLS/TF-PSA-Crypto#114](https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/114); not in 0ε because it can become a no-op after 1.0 | +| `MBEDTLS_SELF_TEST` | Remove | [PSA self-test interface](#psa-self-test-interface) | +| `MBEDTLS_SHA256_SMALLER` | Keep | Tune built-in crypto | +| `MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT` | Keep | Tune built-in crypto | +| `MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY` | Keep | Tune built-in crypto | +| `MBEDTLS_SHA512_SMALLER` | Keep | Tune built-in crypto | +| `MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT` | Keep | Tune built-in crypto | +| `MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY` | Keep | Tune built-in crypto | +| `MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN` | Remove (for test only) | [Remove test-related platform options](#remove-test-related-platform-options) | +| `MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND` | Remove (for test only) | [Remove test-related platform options](#remove-test-related-platform-options) | +| `MBEDTLS_TEST_HOOKS` | Keep | Test injection feature (discussed in [Remove test-related platform options](#remove-test-related-platform-options)) | +| `MBEDTLS_THREADING_ALT` | Keep | as `MBEDTLS_THREADING_C` | +| `MBEDTLS_THREADING_C` | Keep | We plan to revise the threading abstraction after 0ε: [Mbed-TLS/mbedtls#8455](https://github.com/Mbed-TLS/mbedtls/issues/8455) | +| `MBEDTLS_THREADING_PTHREAD` | Keep | as `MBEDTLS_THREADING_C` | + +#### Legacy options in `all.sh` + +We have finished migrating `all.sh` to `MBEDTLS_PSA_CRYPTO_CONFIG`, so in principle, it should not rely on setting legacy options. There are still many occurrences of [boolean options that can be set indirectly](#boolean-options-that-can-be-set-indirectly) (and thus are likely to be removed). Almost all are `config.py unset` that are only present because we're disabling a mechanism through PSA and we want to avoid it coming back through the legacy API where it's enabled by default or by `full`, hence we can remove the `unset` statements once the option is no longer present in `crypto_config.h`. + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/10148): validate this. By making the legacy option default-off and excluded from `full`, then comparing the outcome files? (Removing the option may affect [`depends.py`](#legacy-options-in-dependspy) until the ongoing work there is finished.) + +#### Legacy options in `depends.py` + +At the time of writing, `depends.py` still works with legacy options. A migration to PSA options is in progress ([“TF-PSA-Crypto all.sh components” epic](https://github.com/orgs/Mbed-TLS/projects/18)). For the 0ε work, we assume that this migration is finished. + +#### Non-boolean options + +Non-boolean options are likely to remain relevant since PSA has no equivalent. However, some may have become irrelevant, for example if they configure a module that is being removed. + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/10149): check non-boolean options, other than RNG options, to see if any should be removed or adapted. + +### Changes to RNG options + +#### Impacted RNG modules + +The RNG used when `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is disabled consists of three modules: + +* Entropy (`entropy.c` and `entropy_poll.c`): gather entropy which then needs to be fed to a DRBG (deterministic random bit generator, also called a PRNG for pseudo-random number generator). +* CTR\_DRBG, a NIST-approved DRBG relying on the AES block cipher. +* HMAC\_DRBG, a NIST-approved DRBG relying on a hash algorithm. + +These modules remain relevant internally, but they are becoming fully private. (See “[Headers that can be made fully private](#headers-that-can-be-made-fully-private)” and “[Headers that will become internal eventually](#headers-that-will-become-internal-eventually)”.) We will likely expose CTR\_DRBG and HMAC\_DRBG as programming interfaces in a later minor version of TF-PSA-Crypto 1.x, but this is out of scope for TF-PSA-Crypto 1.0, and will likely wait until there is an official PSA interface. + +Entropy and CTR\_DRBG are only used to instantiate the PSA RNG. HMAC\_DRBG is also used internally for deterministic ECDSA. + +#### Impacted RNG options + +The following boolean options inherited from Mbed TLS 3.x control the random generator used by PSA, and are not tied to any function or callback exposed by TF-PSA-Crypto 0ε or 1.0. + +``` +MBEDTLS_CTR_DRBG_C +MBEDTLS_CTR_DRBG_USE_128_BIT_KEY +MBEDTLS_ENTROPY_FORCE_SHA256 +MBEDTLS_HMAC_DRBG_C +MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES +MBEDTLS_NO_PLATFORM_ENTROPY +``` + +They are complemented by the following non-boolean options: + +``` +MBEDTLS_CTR_DRBG_ENTROPY_LEN +MBEDTLS_CTR_DRBG_MAX_INPUT +MBEDTLS_CTR_DRBG_MAX_REQUEST +MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +MBEDTLS_CTR_DRBG_RESEED_INTERVAL +MBEDTLS_ENTROPY_MAX_GATHER +MBEDTLS_ENTROPY_MAX_SOURCES +MBEDTLS_ENTROPY_MIN_HARDWARE +MBEDTLS_HMAC_DRBG_MAX_INPUT +MBEDTLS_HMAC_DRBG_MAX_REQUEST +MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT +MBEDTLS_HMAC_DRBG_RESEED_INTERVAL +MBEDTLS_PSA_HMAC_DRBG_MD_TYPE +``` + +#### High-level view of RNG interfaces + +The random generator subsystem is not directly exposed to applications. It exists only to feed `psa_generate_random()` and other APIs that require randomness (either for their result or for blinding). + +The random generator subsystem has an interface with drivers, which is not implemented yet and will likely not be implemented until after TF-PSA-Crypto 1.0. This interface is described in the [PSA Cryptoprocessor Driver Interface draft specification](https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/docs/proposed/psa-driver-interface.md): [entropy collection entry point](https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/docs/proposed/psa-driver-interface.md#entropy-collection-entry-point) and [random generation entry points](https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/docs/proposed/psa-driver-interface.md#random-generation-entry-points). + +Beyond the entry points, the random generator also has a configuration interface which tunes its security parameters and performance/code-size/memory-usage compromises: + +* Which DRBG to use (we offer CTR\_DRBG and HMAC\_DRBG). [security, code size, performance] +* Which low-level algorithms and key sizes to use (AES size for CTR\_DRBG, hash used in HMAC\_DRBG, hash used to accumulate entropy). [security, performance] +* How much entropy is considered good enough — in total and for each source. [security, performance] +* Whether to use entropy sources, a seed file, or both. +* Various sizes of intermediate buffers. [performance, memory usage, security] + +#### Towards a minimal set of RNG options + +This section is about the parameters of the DRBG (including how it communicates with the entropy module) and the internal workings of the entropy module. Entropy sources, and builds with `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` enabled, are out of scope here. + +Many of the [RNG options](#impacted-rng-options) are mostly meaningless now that the DRBG modules and the entropy module are no longer public. In this section, we determine which options are still relevant, either because they are algorithm choices or because they are a security/resources compromise. + +For notions of strength, we follow [NIST SP 800-90A r1](https://doi.org/10.6028/NIST.SP.800-90Ar1) (especially table 2 p. 38 for HMAC\_DRBG) and table 3 p. 49 for CTR\_DRBG), and [NIST SP 800-57 part 1 r1](https://doi.org/10.6028/NIST.SP.800-57pt1r5) §5.6.1. + +The RNG uses the following algorithms: + +* A hash function in the entropy module, to update the accumulator. The size of the hash gives the strength (the inputs are not chosen by an adversary unless they have complete control, so collisions are irrelevant) (except for hashes smaller than 32 bits, for which SP 800-57 specifies a smaller strength). Mbed TLS picks between SHA-256 and SHA-512 based on availability and on `MBEDTLS_ENTROPY_FORCE_SHA256`. +* A hash function in HMAC\_DRBG. The size of the hash gives the strength. Mbed TLS 3.6 allows any supported hash function, configured with `MBEDTLS_PSA_HMAC_DRBG_MD_TYPE`. +* A block cipher in CTR\_DRBG. The key size gives the strength. The library only supports AES, and defaults to 256 bits unless overridden by `MBEDTLS_CTR_DRBG_USE_128_BIT_KEY`. + +When using HMAC\_DRBG, there is no particular reason to use a different hash algorithm for the DRBG and for the entropy accumulator. + +For the choice of DRBG, we preserve the existing behavior: pick CTR\_DRBG if enabled in the build, otherwise HMAC\_DRBG. There is no particular reason to change at this point. + +#### New RNG options + +We can deduce the sizes used in entropy and for DRBG internals from just two settings: + +* `MBEDTLS_PSA_CRYPTO_RNG_STRENGTH` indicating the minimum strength of the RNG. Only 128 and 256 are meant to be useful values. Default to 256. +* `MBEDTLS_PSA_CRYPTO_RNG_HASH` indicating which hash algorithm to use for the entropy module, and for HMAC\_DRBG if configured. Default to SHA-256. + +For CTR\_DRBG, use AES-256 if `MBEDTLS_PSA_CRYPTO_RNG_STRENGTH > 128` and AES-128 otherwise. + +In addition, we unify some DRBG options which currently exist separately for CTR\_DRBG and HMAC\_DRBG: + +* `MBEDTLS_PSA_RNG_RESEED_INTERVAL`: inteeger, becomes the value of `MBEDTLS_CTR_DRBG_RESEED_INTERVAL` and `MBEDTLS_HMAC_DRBG_RESEED_INTERVAL`. + +#### Investigation of `MBEDTLS_ENTROPY_BLOCK_SIZE` + +The size of the hash used by the entropy module becomes the value of `MBEDTLS_ENTROPY_BLOCK_SIZE`. This size is used in several places in the entropy module: + +* Size of the NV seed. +* Size collected from each entropy source. +* Size of the internal entropy accumulator that mixes all the sources (including the NV seed). +* Maximum size returned by `mbedtls_entropy_func()` (the function that DRBG modules call). + +The length requested by a DRBG is `ctx->entropy_len`, which, for default instantiations (the only ones that matter in TF-PSA-Crypto 1.0), is: + +* For CTR\_DRBG: `MBEDTLS_CTR_DRBG_ENTROPY_LEN`. In Mbed TLS 3.6, and since the PolarSSL days, this is 48 if entropy uses SHA-512 and 32 if entropy uses SHA-256. Per NIST strength specifications (SP 800-90Ar1 table 3), `MBEDTLS_PSA_CRYPTO_RNG_STRENGTH` would be sufficient. +* For HMAC\_DRBG: 32 for all hashes of 256 bits and above. + +In conclusion, if we don't worry about hashes that are less than 256 bits, then we can systematically have the DRBG request 32 bytes, and the entropy module will always deliver. + +#### Removed DRBG length options + +Remove the following as configuration options (they may still be used internally): + +* `MBEDTLS_ENTROPY_C`: now an internal detail. Enable it automatically if `MBEDTLS_PSA_CRYPTO_C` is enabled (so not in client-only builds) and `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is disabled. +* `MBEDTLS_CTR_DRBG_USE_128_BIT_KEY`: deduced from `MBEDTLS_PSA_CRYPTO_RNG_STRENGTH`. +* `MBEDTLS_ENTROPY_FORCE_SHA256`: superseded by `MBEDTLS_PSA_CRYPTO_RNG_HASH`. +* `MBEDTLS_CTR_DRBG_ENTROPY_LEN`: 32 per “[Investigation of `MBEDTLS_ENTROPY_BLOCK_SIZE`](#investigation-of-mbedtls_entropy_block_size)”. +* `MBEDTLS_CTR_DRBG_MAX_INPUT`: only relevant for custom instantiations which are no longer possible. Do not touch in 1.0, other than hiding it. +* `MBEDTLS_CTR_DRBG_MAX_REQUEST`: this is the maximum size of a request, reflected through `MBEDTLS_PSA_RANDOM_MAX_REQUEST`. The current default is 1024 bytes. It's a minor compromise of stack usage vs performance. We may consider exposing `MBEDTLS_PSA_RANDOM_MAX_REQUEST` later if needs be. +* `MBEDTLS_CTR_DRBG_MAX_SEED_INPUT`: the default value 384 is always fine (we can reduce it later). This needs to be at least `entropy_len + nonce_len + additional_len` where, in the default instantiation, `entropy_len` is `MBEDTLS_CTR_DRBG_ENTROPY_LEN`, `nonce_len` is at most `(MBEDTLS_CTR_DRBG_ENTROPY_LEN + 1) / 2` and `additional_len` is 0. +* `MBEDTLS_CTR_DRBG_RESEED_INTERVAL`: now `MBEDTLS_PSA_RNG_RESEED_INTERVAL`. +* `MBEDTLS_ENTROPY_MAX_GATHER`: no longer relevant. Can remain the default (128 bytes) which is sufficient for the maximum possible strength of the RNG subsystem (512 bits). +* `MBEDTLS_ENTROPY_MAX_SOURCES`: no longer relevant since there can only be two entropy sources at most (platform or custom entropy source, and NV seed). Can be hard-coded to 2. +* `MBEDTLS_ENTROPY_MIN_HARDWARE`: not relevant since there is only one source which must provide the whole entropy. Removed in [#212](https://github.com/Mbed-TLS/TF-PSA-Crypto/pull/212) resolving [Mbed-TLS/mbedtls#9618](https://github.com/Mbed-TLS/mbedtls/issues/9618). +* `MBEDTLS_HMAC_DRBG_MAX_INPUT`: same as `MBEDTLS_CTR_DRBG_MAX_INPUT` (not relevant for deterministic ECDSA). ECDSA only needs the size of the private key (so up to 66 bytes, for secp521r1). +* `MBEDTLS_HMAC_DRBG_MAX_REQUEST`: same as `MBEDTLS_CTR_DRBG_MAX_REQUEST`. +* `MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT`: same as `MBEDTLS_CTR_DRBG_MAX_SEED_INPUT`. ECDSA passes `2*n` bits where `n` is the size of the private key in bits (so up to 131 bytes, for secp521r1). +* `MBEDTLS_HMAC_DRBG_RESEED_INTERVAL`: now `MBEDTLS_PSA_RNG_RESEED_INTERVAL`. +* `MBEDTLS_PSA_HMAC_DRBG_MD_TYPE`: deduced from `MBEDTLS_PSA_CRYPTO_RNG_HASH`. + +#### RNG algorithm and length options: summary + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/328): implement the new configuration options described in “[New RNG options](#new-rng-options)”. Remove the options described in “[Removed DRBG length options](#removed-drbg-length-options)” from `psa/crypto_config.h`, keeping the macros set from remaining options as described. Replace the current configuration checks in `check_config.h` as described below (the new checks may be in `check_config.h` or in other, possibly internal headers). Also, remove the warnings about `MBEDTLS_CTR_DRBG_USE_128_BIT_KEY` in the makefiles. They are no longer relevant: now, if you select a 128-bit RNG strength, that's a very explicit choice. + +The new configuration checks ensure that the RNG configuration options achieve the strength in bits specified as `MBEDTLS_PSA_CRYPTO_RNG_STRENGTH`. Overall we should have the following checks: + +* At least one of CTR\_DRBG or HMAC\_DRBG must be enabled (already enforced in `psa_crypto_random_impl.h`). +* If CTR\_DRBG is used, the AES key size is chosen based on the strength. A strength of more than 256 is an error. +* If HMAC\_DRBG is used, the size of the hash must be at least `MBEDTLS_PSA_CRYPTO_RNG_STRENGTH`. +* The size of the hash `MBEDTLS_PSA_CRYPTO_RNG_HASH` must be at least 256 bits (32 bytes). We could in principle support smaller hashes, but we would need more complex strength calculations, and nobody needs this in 2025. + +#### Builds without entropy + +TF-PSA-Crypto 0ε and in all likelihood TF-PSA-Crypto 1.0 cannot be built without either an entropy source, or entropy stored in a file (NV seed). Builds without entropy are useful, for example, to only perform signature verification, so this is something we plan to support in the future. + +For the time being, any build of the PSA core will continue to require `MBEDTLS_ENTROPY_C` which requires either an entropy source or an NV seed. + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/9618): Require entropy. Change `MBEDTLS_ENTROPY_HARDWARE_ALT` to be simpler and more suitable for TF-PSA-Crypto: + +* Add a parameter to the entropy callback to convey how much entropy is present in the output. For the time being, the output must have full entropy, but in the future TF-PSA-Crypto will allow it to be less. +* Rename the entropy callback. +* Simplify RNG options by only giving the choice between the platform default source and a custom source. We don't need both. + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/307): [Mbed-TLS/mbedtls#9618](https://github.com/Mbed-TLS/mbedtls/issues/9618) removes the possibility of builds with only an NV seed. This is critical for some of our users, including some TF-M builds. Restore this ability. Test it on the CI (done for 3.6 in https://github.com/Mbed-TLS/mbedtls/pull/10210). + +### Changes to platform support options + +Due to a lack of bandwidth, we do not plan any significant changes in the platform support layer. + +#### Remove test-related platform options + +For historical reasons, a few test-specific options are present in `mbedtls_config.h` in Mbed TLS 3.6, and have made their way into `crypto_config.h` in TF-PSA-Crypto. These options have no effect on the build of the library, only on test framework code and unit tests. + +Task: Remove the following options from `crypto_config.h` and adjust the corresponding test code to pass `-D` to the compiler instead of calling `crypto_config.h`: + +``` +MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN +MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND +``` + +Note: `MBEDTLS_TEST_HOOKS` is different because it does influence the build of the library. Going by our invasive testing guidelines, all invasive testing is gated by this single option plus a runtime activation mechanism. Since `MBEDTLS_TEST_HOOKS` is enabled by `config.py full`, it needs to remain in the official configuration file (or else we would need to add nontrivial code to take care of it). Thus we are not changing anything related to `MBEDTLS_TEST_HOOKS`. It will gate the test hooks both in TF-PSA-Crypto and Mbed TLS since there is no reason to separate the two. + +#### Move time options back to Mbed TLS + +The options `MBEDTLS_HAVE_TIME`, `MBEDTLS_HAVE_TIME_DATE` are not used in crypto, only in X.509 and TLS. + +`MBEDTLS_HAVE_TIME` is used in the timing module which was historically used in the crypto library, but only for the sake of being a weak entropy source (removed in Mbed TLS 3.0) and for the benchmark program. The benchmark program is still relevant, but that doesn't justify a timing abstraction in TF-PSA-Crypto, and the timing module went into the Mbed TLS repository. + +Task: + +* Move `MBEDTLS_HAVE_TIME` and `MBEDTLS_HAVE_TIME_DATE` back to Mbed TLS. +* Move time-related platform function options (`MBEDTLS_PLATFORM_TIME_ALT`, `MBEDTLS_PLATFORM_MS_TIME_ALT`, `MBEDTLS_PLATFORM_MS_TIME_TYPE_MACRO`, `MBEDTLS_PLATFORM_MS_TIME_ALT`, `MBEDTLS_PLATFORM_GMTIME_R_ALT`) back to Mbed TLS. +* Move the declaration of `mbedtls_platform_gmtime_r` to `platform_time.h`. +* Move `platform_time.h` back to Mbed TLS. +* Move the corresponding function definitions from `platform*.c` to Mbed TLS. +* Move the corresponding tests in `test_suite_platform` to Mbed TLS. + +Rationale: saves maintenance complexity and simplifies the user interface, compared to the current situation where time-related interfaces are split between the two repositories. + +### Compilation options for non-cryptographic features + +#### Counter inclusions in ASN.1 + +The functions `mbedtls_asn1_get_len` and `mbedtls_asn1_get_tag` are enabled when `MBEDTLS_ASN1_WRITE_C` is enabled, even if `MBEDTLS_ASN1_PARSE_C` is disabled. The functions `mbedtls_asn1_write_len` and `mbedtls_asn1_write_tag` are enabled when `MBEDTLS_ASN1_PARSE_C` is enabled, even if `MBEDTLS_ASN1_WRITE_C` is disabled. This is for the sake of X.509 code, and until [Mbed-TLS/TF-PSA-Crypto#143](https://github.com/Mbed-TLS/TF-PSA-Crypto/pull/143), the dependencies were `MBEDTLS_X509_CREATE_C` for the get functions and `MBEDTLS_X509_USE_C` for the write functions. + +The counter-direction uses of these functions in X.509 arose from hexstring support in distinguished names which was introduced in [Mbed-TLS/mbedtls#8025](https://github.com/Mbed-TLS/mbedtls/pull/8025). At this point, it is not clear to me whether counter-direction functions are intrinsically needed to support this aspect of X.509, or if it's a logical consequence of a plausible design decision we made on data representation, or if it's just an implementation convenience that is no longer so convenient when ASN.1 and X.509 are in separate projects. The counter-direction uses are: + +* In `mbedtls_x509_dn_gets`, which is used to inspect X.509 parsing results, we use `mbedtls_asn1_write_len` and `mbedtls_asn1_write_tag` to format a name containing special characters as a hexstring. `mbedtls_asn1_write_tag` is trivial and could be made a simple assignment. `mbedtls_asn1_write_len` is less trivial because it needs logic to encode lengths (different encoding methods under and over 128, per DER rules), but it could reasonably be reimplemented. Using ASN.1 functions there adds overhead to conform to their interface, and so doesn't make the code smaller or simpler. +* In `mbedtls_x509_string_to_names`, which is used to prepare data for X.509 writing, we use `mbedtls_asn1_get_len` to parse a hex-encoded name. We don't use `mbedtls_asn1_get_tag` because several tags are permitted. We could reimplement the length parsing logic here, but it's nontrivial and would make the code here slightly more complex. + +Although names are typically shorter than 128 bytes, there is no official limit. Per https://stackoverflow.com/questions/1253575/does-the-ldap-protocol-limit-the-length-of-a-dn there is no limit for X.509 or LDAP, and ActiveDirectory allows 255 characters, so we should at least support up to 65535 octets (the next length encoding threshold after 128). + +In the short term, we have an undocumented interface: `MBEDTLS_ASN1_PARSE_C` enables two write functions and `MBEDTLS_ASN1_WRITE_C` enables two parse functions. + +In the longer term, plausible solutions include: + +* Making the short-term workaround of enabling counter-direction functions official. +* Having `MBEDTLS_X509_USE_C` require `MBEDTLS_ASN1_WRITE_C` in addition to `MBEDTLS_ASN1_PARSE_C`, and having `MBEDTLS_X509_CREATE_C` require `MBEDTLS_ASN1_PARSE_C` in addition to `MBEDTLS_ASN1_WRITE_C`. +* Changing the X.509 code to reimplement the logic it needs, rather than use ASN.1 functions which don't fit the calling code well. +* One of the above solutions for USE and a different one for CREATE. + +#### OID conditional compilation + +The compilation option `MBEDTLS_OID_C` guards the whole OID module (`oid.c`). Some OID table and support functions are further guarded according to the cryptographic mechanisms and library interfaces that are enabled. However, some OIDs that are generically useful in X.509 and not used directly by any other crypto code (e.g. `MBEDTLS_OID_X509_EXT_xxx`) are always included when `MBEDTLS_OID_C` is enabled. Furthermore, many OIDs for X.509 are guarded by `!defined(MBEDTLS_X509_REMOVE_INFO)`, which is a not a crypto option and therefore cannot appear in TF-PSA-Crypto (since we want to make it possible to build TF-PSA-Crypto independently of Mbed TLS). + +From the perspective of the TF-PSA-Crypto build, there are three levels of OID inclusion: + +1. Only as needed in crypto. +2. (1) plus the core set for X.509 (subject to available cryptographic mechanisms where relevant). +3. (2) plus the extra data for `mbedtls_x509_crt_info()` and friends. + +We either need public compilation options with this level of inclusion, or to move the X.509 parts of `oid.c` to the X.509 library (obviously preferable, but requiring more upfront work). + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/10124): move the X.509 parts of `oid.c` to the X.509 library. + +### Changes to option implications + +#### Changes to ASN.1 enablement + +Currently, `MBEDTLS_ASN1_PARSE_C` and `MBEDTLS_ASN1_WRITE_C` are automatically enabled: + +* If `MBEDTLS_RSA_C` is enabled. This is needed for RSA key import and export. We don't try to optimize code size when import or export of a key type is disabled, so this can stay. As part of internal refactoring, it will change to `PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY` eventually. +* If `PSA_WANT_ALG_ECDSA` or `PSA_WANT_ALG_DETERMINISTIC_ECDSA` is built in. This used to be required to convert between ASN.1 and raw signature formats internally back when PSA was built on top of the legacy API, but today I think it isn't needed. However, it is needed for `MBEDTLS_ECDSA_C`. We do expose the signature conversion functions `mbedtls_ecdsa_raw_to_der` and `mbedtls_ecdsa_der_to_raw` when an ECDSA signature is enabled through PSA (built-in or not), but we automatically enable the necessary ASN.1 functions regardless of the ASN.1 configuration. + +So we have an optimization here to not auto-enable all of ASN.1 for built-in ECDSA. This will require removing or changing the guards on `mbedtls_ecdsa_read_signature()` and `mbedtls_ecdsa_write_signature()` and friends, which are now private functions. + +### Non-critical changes to compilation options + +The changes discussed in this section would make for a more user-friendly API, but would not reduce our maintenance burden. As a consequence, we are treating them as low priority. They may not be fully fleshed out. + +#### Revise client/server inclusion + +Now that PSA is “always on”, what does it mean for `MBEDTLS_PSA_CRYPTO_C`, `MBEDTLS_PSA_CRYPTO_CLIENT` and `MBEDTLS_PSA_CRYPTO_SPM`? We no longer officially support builds without any PSA parts, but we do support server-only or client-only builds, so there is no part of the code that is actually mandatory. + +* A library build (the most common case) defines `MBEDTLS_PSA_CRYPTO_C` (which implies `MBEDTLS_PSA_CRYPTO_CLIENT`). +* A client-only build defines `MBEDTLS_PSA_CRYPTO_CLIENT` and little to no else. +* A server-only build defines `MBEDTLS_PSA_CRYPTO_C` and `MBEDTLS_PSA_CRYPTO_SPM`. + +Strongly related: https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/112 + +#### Revise key store selection + +For historical reasons, we have three key store architectures: + +* Purely static, when `MBEDTLS_PSA_STATIC_KEY_SLOTS` is enabled. Key slots are allocated statically, and the core does not use `malloc()`. This only allows a small number of keys determined at compile time, and keys have a size limit that is determined at compile time. The memory usage is determined at compile time, regardless of how full the key store is. This achieves the smallest code size, but has major limitations. +* Hybrid, when neither `MBEDTLS_PSA_KEY_STORE_DYNAMIC` nor `MBEDTLS_PSA_STATIC_KEY_SLOTS` is enabled. This is the original design, with a static array of key slots (for simplicity) and dynamic allocation of key data. Compared to the fully dynamic key store, this only allows a small number of keys determined at compile time, but achieves a small code size (almost on par with the static key store if `malloc()` is present anyway). Compared to the static key store, it wastes less memory when only a fraction of the key store is used, and has no specific limit on the size of keys. +* Fully dynamic, when `MBEDTLS_PSA_KEY_STORE_DYNAMIC` is enabled (default). Key slots and key data are both allocated dynamically. This has no practical limitations, but larger code size. + +Should we keep all three? Since `MBEDTLS_PSA_KEY_STORE_DYNAMIC` is the default (because that's what you need e.g. in a Linux distribution package), should we change to defining a symbol for the hybrid key store? + +## Changes to public crypto headers + +### Public hash-only `md.h` + +To be considered for 1.0: make a subset of `md.h` public. Only hashes, not HMAC. As a starting point, this would be `MBEDTLS_MD_LIGHT`, which is known to work in many configurations, although we don't have to stick to it. + +Reasons to do this: + +* The upfront cost is small: we can take the existing `md.h` and just remove the HMAC-related code and some of the metadata-related interfaces. +* This is already tested as `MBEDTLS_MD_LIGHT`. +* As a thin wrapper over PSA (we would not keep direct calls to low-level modules), the maintenance cost is very small. +* It is used in a very large number of places, both in Mbed TLS and in third-party code. Keeping it around will both save us work during the lifetime of TF-PSA-Crypto 1.x and Mbed TLS 4.x, and facilitate the transition for our users. +* If we don't do this, then we'll have to change some code in Mbed TLS. In the `full` configuration, Mbed TLS links to several md functions: `mbedtls_md`, `mbedtls_md_error_from_psa`, `mbedtls_md_get_size`, `mbedtls_md_info_from_type` (in addition to macros, enum constants and static inline functions from `mbedtls/md.h`). + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/8450): Privatize the parts of `md.h` that are not MD-light. + +### Shrunk-down `pk.h` + +We treat the evolution of `pk.h` as a project with its own design document and task breakdown. + +https://github.com/Mbed-TLS/mbedtls/issues/8452 + +https://github.com/Mbed-TLS/TF-PSA-Crypto/pull/203 + +### Shrunk-down `psa_util.h` + +Only some of the interface elements in `mbedtls/psa_util.h` remain useful. + +| Name | Uses | Fate | +| ---- | ---- | ---- | +| `mbedtls_psa_get_random` | crypto internal, `ssl_test_lib.c` | Deprecate | +| `MBEDTLS_PSA_RANDOM_STATE` | same as `mbedtls_psa_get_random` | Deprecate | +| `mbedtls_ecc_group_to_psa` | crypto internal | Internalize | +| `mbedtls_ecc_group_from_psa` | crypto internal | Internalize | +| `mbedtls_md_psa_alg_from_type` | crypto internal, SSL library | Privatize, deprecate or remove? | +| `mbedtls_md_type_from_psa_alg` | crypto internal, SSL library | Privatize, deprecate or remove? | +| `mbedtls_ecdsa_raw_to_der` | crypto internal | Keep public | +| `mbedtls_ecdsa_der_to_raw` | crypto internal | Keep public | + +The RNG wrapper function `mbedtls_psa_get_random` (and the associated constant `MBEDTLS_PSA_RANDOM_STATE`) has a negligible cost for us and can help users transition their code. Keep it, but mark it as deprecated, possibly inlined, and change it (code and documentation) to just return the return value of `psa_generate_random`. + +The ECC group conversion functions are now purely private since the type `mbedtls_ecp_group_id` is private. They aren't used by Mbed TLS, so move their declaration to an internal header. + +The digest algorithm conversion functions are heavily used in TLS code (mostly if not exclusively TLS 1.3). They perform a very simple conversion, so it should be easy to get rid of them. However, as long as `mbedtls_md_type_t` still exists (see [Public hash-only `md.h`](#public-hash-only-mdh)), it could make sense to have them as public functions in `md.h`. + +The ECDSA signature format conversion functions are used to implement `mbedtls_pk_{sign,verify}`, but they are also useful to applications. Keep them. We may move them to a different header name though (`psa/crypto_extra.h`?). + +## Loss of functionality + +Some loss of functionality is accepted in TF-PSA-Crypto 1.x and Mbed TLS 4.x compared to Mbed TLS 3.6. This section discusses some of the loss, with no expectation of exhaustivity. + +### Loss of cipher modes + +#### XTS migration + +As of Mbed TLS 3.6, the PSA API specification includes XTS mode (`PSA_ALG_XTS`), but the Mbed TLS implementation does not support it yet. It is planned to be added ([Mbed-TLS/mbedtls#6384](https://github.com/Mbed-TLS/mbedtls/issues/6384)) but we currently plan to do that after the TF-PSA-Crypto 1.0 release. + +In the meantime, XTS code remains in `cipher.c` and low-level crypto modules, but it is unreachable. + +#### Obsolete cipher padding modes + +We plan to remove all cipher padding modes other than PKCS7. We are not aware of a compelling use case for these modes. If there is a need for them, we would require them to be added to the PSA API specification. + +``` +MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +MBEDTLS_CIPHER_PADDING_ZEROS +MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +``` + +### Loss of asymmetric cryptography + +#### Removal of small elliptic curves + +We would like to remove all elliptic curves smaller than 250 bits, because they are largely unused and uncomfortably close to being insecure. This is planned in [Mbed-TLS/mbedtls#8136](https://github.com/Mbed-TLS/mbedtls/issues/8136). + +In the specific case of secp224k1, it is annoying to implement (because it is the only curve where private keys and public coordinates do not have the same bit size). We have not implemented it in PSA and do not plan to do so. As a consequence, all code guarded by `MBEDTLS_ECP_DP_SECP224K1_ENABLED` is now dead code. + +#### Removal of low-level DHM + +We are removing the low-level DHM module for finite-field Diffie-Hellman (FFDH). FFDH remains available in the PSA API, but only with a small set of predefined groups, whereas the legacy API supports arbitrary groups. + +The PSA code is not based on the DHM module (it calls bignum directly), so the DHM module is now dead code. + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/9956): Remove `dhm.h`, `dhm.c`, `MBEDTLS_DHM_C`, `test_suite_dhm`. + +### PSA self-test interface + +TF-PSA-Crypto 0ε, and in all likelihood 1.0, will not have a self-test interface. This feature is necessary for some security certifications, and otherwise useless. It is good to have because it's a commonly expected feature in a crypto provider, but it's also acceptable to wait until we see how important it is for our users. + +The current implementation is not available for all mechanisms and is tied to the legacy interface, so it would be of limited usefuless to expose it. A PSA interface should work for all mechanisms and should not be tied to the built-in interface. We would have to rewrite most of the code anyway. + +Keeping the self-test code around with a promise that it keeps working will slow us down when we refactor low-level crypto. Keeping the self-test code around as dead code is not useful. + +Hence for 0ε we will remove `MBEDTLS_SELF_TEST` and the guarded code. diff --git a/tf-psa-crypto/docs/architecture/mbed-crypto-storage-specification.md b/tf-psa-crypto/docs/architecture/mbed-crypto-storage-specification.md new file mode 100644 index 0000000000..b7bc15b3d8 --- /dev/null +++ b/tf-psa-crypto/docs/architecture/mbed-crypto-storage-specification.md @@ -0,0 +1,472 @@ +Mbed TLS storage specification +================================= + +This document specifies how Mbed TLS uses storage. +Key storage was originally introduced in a product called Mbed Crypto, which was re-distributed via Mbed TLS and has since been merged into Mbed TLS. +This document contains historical information both from before and after this merge. + +Mbed Crypto may be upgraded on an existing device with the storage preserved. Therefore: + +1. Any change may break existing installations and may require an upgrade path. +1. This document retains historical information about all past released versions. Do not remove information from this document unless it has always been incorrect or it is about a version that you are sure was never released. + +Mbed Crypto 0.1.0 +----------------- + +Tags: mbedcrypto-0.1.0b, mbedcrypto-0.1.0b2 + +Released in November 2018.
+Integrated in Mbed OS 5.11. + +Supported backends: + +* [PSA ITS](#file-namespace-on-its-for-0.1.0) +* [C stdio](#file-namespace-on-stdio-for-0.1.0) + +Supported features: + +* [Persistent transparent keys](#key-file-format-for-0.1.0) designated by a [slot number](#key-names-for-0.1.0). +* [Nonvolatile random seed](#nonvolatile-random-seed-file-format-for-0.1.0) on ITS only. + +This is a beta release, and we do not promise backward compatibility, with one exception: + +> On Mbed OS, if a device has a nonvolatile random seed file produced with Mbed OS 5.11.x and is upgraded to a later version of Mbed OS, the nonvolatile random seed file is preserved or upgraded. + +We do not make any promises regarding key storage, or regarding the nonvolatile random seed file on other platforms. + +### Key names for 0.1.0 + +Information about each key is stored in a dedicated file whose name is constructed from the key identifier. The way in which the file name is constructed depends on the storage backend. The content of the file is described [below](#key-file-format-for-0.1.0). + +The valid values for a key identifier are the range from 1 to 0xfffeffff. This limitation on the range is not documented in user-facing documentation: according to the user-facing documentation, arbitrary 32-bit values are valid. + +The code uses the following constant in an internal header (note that despite the name, this value is actually one plus the maximum permitted value): + + #define PSA_MAX_PERSISTENT_KEY_IDENTIFIER 0xffff0000 + +There is a shared namespace for all callers. + +### Key file format for 0.1.0 + +All integers are encoded in little-endian order in 8-bit bytes. + +The layout of a key file is: + +* magic (8 bytes): `"PSA\0KEY\0"` +* version (4 bytes): 0 +* type (4 bytes): `psa_key_type_t` value +* policy usage flags (4 bytes): `psa_key_usage_t` value +* policy usage algorithm (4 bytes): `psa_algorithm_t` value +* key material length (4 bytes) +* key material: output of `psa_export_key` +* Any trailing data is rejected on load. + +### Nonvolatile random seed file format for 0.1.0 + +The nonvolatile random seed file contains a seed for the random generator. If present, it is rewritten at each boot as part of the random generator initialization. + +The file format is just the seed as a byte string with no metadata or encoding of any kind. + +### File namespace on ITS for 0.1.0 + +Assumption: ITS provides a 32-bit file identifier namespace. The Crypto service can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace. + +* File 0: unused. +* Files 1 through 0xfffeffff: [content](#key-file-format-for-0.1.0) of the [key whose identifier is the file identifier](#key-names-for-0.1.0). +* File 0xffffff52 (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`): [nonvolatile random seed](#nonvolatile-random-seed-file-format-for-0.1.0). +* Files 0xffff0000 through 0xffffff51, 0xffffff53 through 0xffffffff: unused. + +### File namespace on stdio for 0.1.0 + +Assumption: C stdio, allowing names containing lowercase letters, digits and underscores, of length up to 23. + +An undocumented build-time configuration value `CRYPTO_STORAGE_FILE_LOCATION` allows storing the key files in a directory other than the current directory. This value is simply prepended to the file name (so it must end with a directory separator to put the keys in a different directory). + +* `CRYPTO_STORAGE_FILE_LOCATION "psa_key_slot_0"`: used as a temporary file. Must be writable. May be overwritten or deleted if present. +* `sprintf(CRYPTO_STORAGE_FILE_LOCATION "psa_key_slot_%lu", key_id)` [content](#key-file-format-for-0.1.0) of the [key whose identifier](#key-names-for-0.1.0) is `key_id`. +* Other files: unused. + +Mbed Crypto 1.0.0 +----------------- + +Tags: mbedcrypto-1.0.0d4, mbedcrypto-1.0.0 + +Released in February 2019.
+Integrated in Mbed OS 5.12. + +Supported integrations: + +* [PSA platform](#file-namespace-on-a-psa-platform-for-1.0.0) +* [library using PSA ITS](#file-namespace-on-its-as-a-library-for-1.0.0) +* [library using C stdio](#file-namespace-on-stdio-for-1.0.0) + +Supported features: + +* [Persistent transparent keys](#key-file-format-for-1.0.0) designated by a [key identifier and owner](#key-names-for-1.0.0). +* [Nonvolatile random seed](#nonvolatile-random-seed-file-format-for-1.0.0) on ITS only. + +Backward compatibility commitments: TBD + +### Key names for 1.0.0 + +Information about each key is stored in a dedicated file designated by the key identifier. In integrations where there is no concept of key owner (in particular, in library integrations), the key identifier is exactly the key identifier as defined in the PSA Cryptography API specification (`psa_key_id_t`). In integrations where there is a concept of key owner (integration into a service for example), the key identifier is made of an owner identifier (its semantics and type are integration specific) and of the key identifier (`psa_key_id_t`) from the key owner point of view. + +The way in which the file name is constructed from the key identifier depends on the storage backend. The content of the file is described [below](#key-file-format-for-1.0.0). + +* Library integration: the key file name is just the key identifier as defined in the PSA crypto specification. This is a 32-bit value. +* PSA service integration: the key file name is `(uint64_t)owner_uid << 32 | key_id` where `key_id` is the key identifier from the owner point of view and `owner_uid` (of type `int32_t`) is the calling partition identifier provided to the server by the partition manager. This is a 64-bit value. + +### Key file format for 1.0.0 + +The layout is identical to [0.1.0](#key-file-format-for-0.1.0) so far. However note that the encoding of key types, algorithms and key material has changed, therefore the storage format is not compatible (despite using the same value in the version field so far). + +### Nonvolatile random seed file format for 1.0.0 + +The nonvolatile random seed file contains a seed for the random generator. If present, it is rewritten at each boot as part of the random generator initialization. + +The file format is just the seed as a byte string with no metadata or encoding of any kind. + +This is unchanged since [the feature was introduced in Mbed Crypto 0.1.0](#nonvolatile-random-seed-file-format-for-0.1.0). + +### File namespace on a PSA platform for 1.0.0 + +Assumption: ITS provides a 64-bit file identifier namespace. The Crypto service can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace. + +Assumption: the owner identifier is a nonzero value of type `int32_t`. + +* Files 0 through 0xffffff51, 0xffffff53 through 0xffffffff: unused, reserved for internal use of the crypto library or crypto service. +* File 0xffffff52 (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`): [nonvolatile random seed](#nonvolatile-random-seed-file-format-for-0.1.0). +* Files 0x100000000 through 0xffffffffffff: [content](#key-file-format-for-1.0.0) of the [key whose identifier is the file identifier](#key-names-for-1.0.0). The upper 32 bits determine the owner. + +### File namespace on ITS as a library for 1.0.0 + +Assumption: ITS provides a 64-bit file identifier namespace. The entity using the crypto library can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace. + +This is a library integration, so there is no owner. The key file identifier is identical to the key identifier. + +* File 0: unused. +* Files 1 through 0xfffeffff: [content](#key-file-format-for-1.0.0) of the [key whose identifier is the file identifier](#key-names-for-1.0.0). +* File 0xffffff52 (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`): [nonvolatile random seed](#nonvolatile-random-seed-file-format-for-1.0.0). +* Files 0xffff0000 through 0xffffff51, 0xffffff53 through 0xffffffff, 0x100000000 through 0xffffffffffffffff: unused. + +### File namespace on stdio for 1.0.0 + +This is a library integration, so there is no owner. The key file identifier is identical to the key identifier. + +[Identical to 0.1.0](#file-namespace-on-stdio-for-0.1.0). + +### Upgrade from 0.1.0 to 1.0.0. + +* Delete files 1 through 0xfffeffff, which contain keys in a format that is no longer supported. + +### Suggested changes to make before 1.0.0 + +The library integration and the PSA platform integration use different sets of file names. This is annoyingly non-uniform. For example, if we want to store non-key files, we have room in different ranges (0 through 0xffffffff on a PSA platform, 0xffff0000 through 0xffffffffffffffff in a library integration). + +It would simplify things to always have a 32-bit owner, with a nonzero value, and thus reserve the range 0–0xffffffff for internal library use. + +Mbed Crypto 1.1.0 +----------------- + +Tags: mbedcrypto-1.1.0 + +Released in early June 2019.
+Integrated in Mbed OS 5.13. + +Changes since [1.0.0](#mbed-crypto-1.0.0): + +* The stdio backend for storage has been replaced by an implementation of [PSA ITS over stdio](#file-namespace-on-stdio-for-1.1.0). +* [Some changes in the key file format](#key-file-format-for-1.1.0). + +### File namespace on stdio for 1.1.0 + +Assumption: C stdio, allowing names containing lowercase letters, digits and underscores, of length up to 23. + +An undocumented build-time configuration value `PSA_ITS_STORAGE_PREFIX` allows storing the key files in a directory other than the current directory. This value is simply prepended to the file name (so it must end with a directory separator to put the keys in a different directory). + +* `PSA_ITS_STORAGE_PREFIX "tempfile.psa_its"`: used as a temporary file. Must be writable. May be overwritten or deleted if present. +* `sprintf(PSA_ITS_STORAGE_PREFIX "%016llx.psa_its", key_id)`: a key or non-key file. The `key_id` in the name is the 64-bit file identifier, which is the [key identifier](#key-names-for-mbed-tls-2.25.0) for a key file or some reserved identifier for a non-key file (currently: only the [nonvolatile random seed](#nonvolatile-random-seed-file-format-for-1.0.0)). The contents of the file are: + * Magic header (8 bytes): `"PSA\0ITS\0"` + * File contents. + +### Key file format for 1.1.0 + +The key file format is identical to [1.0.0](#key-file-format-for-1.0.0), except for the following changes: + +* A new policy field, marked as [NEW:1.1.0] below. +* The encoding of key types, algorithms and key material has changed, therefore the storage format is not compatible (despite using the same value in the version field so far). + +A self-contained description of the file layout follows. + +All integers are encoded in little-endian order in 8-bit bytes. + +The layout of a key file is: + +* magic (8 bytes): `"PSA\0KEY\0"` +* version (4 bytes): 0 +* type (4 bytes): `psa_key_type_t` value +* policy usage flags (4 bytes): `psa_key_usage_t` value +* policy usage algorithm (4 bytes): `psa_algorithm_t` value +* policy enrollment algorithm (4 bytes): `psa_algorithm_t` value [NEW:1.1.0] +* key material length (4 bytes) +* key material: output of `psa_export_key` +* Any trailing data is rejected on load. + +Mbed Crypto TBD +--------------- + +Tags: TBD + +Released in TBD 2019.
+Integrated in Mbed OS TBD. + +### Changes introduced in TBD + +* The layout of a key file now has a lifetime field before the type field. +* Key files can store references to keys in a secure element. In such key files, the key material contains the slot number. + +### File namespace on a PSA platform on TBD + +Assumption: ITS provides a 64-bit file identifier namespace. The Crypto service can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace. + +Assumption: the owner identifier is a nonzero value of type `int32_t`. + +* Files 0 through 0xfffeffff: unused. +* Files 0xffff0000 through 0xffffffff: reserved for internal use of the crypto library or crypto service. See [non-key files](#non-key-files-on-tbd). +* Files 0x100000000 through 0xffffffffffff: [content](#key-file-format-for-1.0.0) of the [key whose identifier is the file identifier](#key-names-for-1.0.0). The upper 32 bits determine the owner. + +### File namespace on ITS as a library on TBD + +Assumption: ITS provides a 64-bit file identifier namespace. The entity using the crypto library can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace. + +This is a library integration, so there is no owner. The key file identifier is identical to the key identifier. + +* File 0: unused. +* Files 1 through 0xfffeffff: [content](#key-file-format-for-1.0.0) of the [key whose identifier is the file identifier](#key-names-for-1.0.0). +* Files 0xffff0000 through 0xffffffff: reserved for internal use of the crypto library or crypto service. See [non-key files](#non-key-files-on-tbd). +* Files 0x100000000 through 0xffffffffffffffff: unused. + +### Non-key files on TBD + +File identifiers in the range 0xffff0000 through 0xffffffff are reserved for internal use in Mbed Crypto. + +* Files 0xfffffe02 through 0xfffffeff (`PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE + lifetime`): secure element driver storage. The content of the file is the secure element driver's persistent data. +* File 0xffffff52 (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`): [nonvolatile random seed](#nonvolatile-random-seed-file-format-for-1.0.0). +* File 0xffffff54 (`PSA_CRYPTO_ITS_TRANSACTION_UID`): [transaction file](#transaction-file-format-for-tbd). +* Other files are unused and reserved for future use. + +### Key file format for TBD + +All integers are encoded in little-endian order in 8-bit bytes except where otherwise indicated. + +The layout of a key file is: + +* magic (8 bytes): `"PSA\0KEY\0"`. +* version (4 bytes): 0. +* lifetime (4 bytes): `psa_key_lifetime_t` value. +* type (4 bytes): `psa_key_type_t` value. +* policy usage flags (4 bytes): `psa_key_usage_t` value. +* policy usage algorithm (4 bytes): `psa_algorithm_t` value. +* policy enrollment algorithm (4 bytes): `psa_algorithm_t` value. +* key material length (4 bytes). +* key material: + * For a transparent key: output of `psa_export_key`. + * For an opaque key (unified driver interface): driver-specific opaque key blob. + * For an opaque key (key in a secure element): slot number (8 bytes), in platform endianness. +* Any trailing data is rejected on load. + +### Transaction file format for TBD + +The transaction file contains data about an ongoing action that cannot be completed atomically. It exists only if there is an ongoing transaction. + +All integers are encoded in platform endianness. + +All currently existing transactions concern a key in a secure element. + +The layout of a transaction file is: + +* type (2 bytes): the [transaction type](#transaction-types-on-tbd). +* unused (2 bytes) +* lifetime (4 bytes): `psa_key_lifetime_t` value that corresponds to a key in a secure element. +* slot number (8 bytes): `psa_key_slot_number_t` value. This is the unique designation of the key for the secure element driver. +* key identifier (4 bytes in a library integration, 8 bytes on a PSA platform): the internal representation of the key identifier. On a PSA platform, this encodes the key owner in the same way as [in file identifiers for key files](#file-namespace-on-a-psa-platform-on-tbd)). + +#### Transaction types on TBD + +* 0x0001: key creation. The following locations may or may not contain data about the key that is being created: + * The slot in the secure element designated by the slot number. + * The file containing the key metadata designated by the key identifier. + * The driver persistent data. +* 0x0002: key destruction. The following locations may or may not still contain data about the key that is being destroyed: + * The slot in the secure element designated by the slot number. + * The file containing the key metadata designated by the key identifier. + * The driver persistent data. + +Mbed Crypto TBD +--------------- + +Tags: TBD + +Released in TBD 2020.
+Integrated in Mbed OS TBD. + +### Changes introduced in TBD + +* The type field has been split into a type and a bits field of 2 bytes each. + +### Key file format for TBD + +All integers are encoded in little-endian order in 8-bit bytes except where otherwise indicated. + +The layout of a key file is: + +* magic (8 bytes): `"PSA\0KEY\0"`. +* version (4 bytes): 0. +* lifetime (4 bytes): `psa_key_lifetime_t` value. +* type (2 bytes): `psa_key_type_t` value. +* bits (2 bytes): `psa_key_bits_t` value. +* policy usage flags (4 bytes): `psa_key_usage_t` value. +* policy usage algorithm (4 bytes): `psa_algorithm_t` value. +* policy enrollment algorithm (4 bytes): `psa_algorithm_t` value. +* key material length (4 bytes). +* key material: + * For a transparent key: output of `psa_export_key`. + * For an opaque key (unified driver interface): driver-specific opaque key blob. + * For an opaque key (key in a secure element): slot number (8 bytes), in platform endianness. +* Any trailing data is rejected on load. + +Mbed TLS 2.25.0 +--------------- + +Tags: `mbedtls-2.25.0`, `mbedtls-2.26.0`, `mbedtls-2.27.0`, `mbedtls-2.28.0`, `mbedtls-3.0.0`, `mbedtls-3.1.0` + +First released in December 2020. + +Note: this is the first version that is officially supported. The version number is still 0. + +Backward compatibility commitments: we promise backward compatibility for stored keys when Mbed TLS is upgraded from x to y if x >= 2.25 and y < 4. See [`BRANCHES.md`](../../BRANCHES.md) for more details. + +Supported integrations: + +* [PSA platform](#file-namespace-on-a-psa-platform-on-mbed-tls-2.25.0) +* [library using PSA ITS](#file-namespace-on-its-as-a-library-on-mbed-tls-2.25.0) +* [library using C stdio](#file-namespace-on-stdio-for-mbed-tls-2.25.0) + +Supported features: + +* [Persistent keys](#key-file-format-for-mbed-tls-2.25.0) designated by a [key identifier and owner](#key-names-for-mbed-tls-2.25.0). Keys can be: + * Transparent, stored in the export format. + * Opaque, using the PSA driver interface with statically registered drivers. The driver determines the content of the opaque key blob. + * Opaque, using the deprecated secure element interface with dynamically registered drivers (`MBEDTLS_PSA_CRYPTO_SE_C`). The driver picks a slot number which is stored in the place of the key material. +* [Nonvolatile random seed](#nonvolatile-random-seed-file-format-for-mbed-tls-2.25.0) on ITS only. + +### Changes introduced in Mbed TLS 2.25.0 + +* The numerical encodings of `psa_key_type_t`, `psa_key_usage_t` and `psa_algorithm_t` have changed. + +### File namespace on a PSA platform on Mbed TLS 2.25.0 + +Assumption: ITS provides a 64-bit file identifier namespace. The Crypto service can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace. + +Assumption: the owner identifier is a nonzero value of type `int32_t`. + +* Files 0 through 0xfffeffff: unused. +* Files 0xffff0000 through 0xffffffff: reserved for internal use of the crypto library or crypto service. See [non-key files](#non-key-files-on-mbed-tls-2.25.0). +* Files 0x100000000 through 0xffffffffffff: [content](#key-file-format-for-mbed-tls-2.25.0) of the [key whose identifier is the file identifier](#key-names-for-mbed-tls-2.25.0). The upper 32 bits determine the owner. + +### File namespace on ITS as a library on Mbed TLS 2.25.0 + +Assumption: ITS provides a 64-bit file identifier namespace. The entity using the crypto library can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace. + +This is a library integration, so there is no owner. The key file identifier is identical to the key identifier. + +* File 0: unused. +* Files 1 through 0xfffeffff: [content](#key-file-format-for-mbed-tls-2.25.0) of the [key whose identifier is the file identifier](#key-names-for-mbed-tls-2.25.0). +* Files 0xffff0000 through 0xffffffff: reserved for internal use of the crypto library or crypto service. See [non-key files](#non-key-files-on-mbed-tls-2.25.0). +* Files 0x100000000 through 0xffffffffffffffff: unused. + +### File namespace on stdio for Mbed TLS 2.25.0 + +Assumption: C stdio, allowing names containing lowercase letters, digits and underscores, of length up to 23. + +An undocumented build-time configuration value `PSA_ITS_STORAGE_PREFIX` allows storing the key files in a directory other than the current directory. This value is simply prepended to the file name (so it must end with a directory separator to put the keys in a different directory). + +* `PSA_ITS_STORAGE_PREFIX "tempfile.psa_its"`: used as a temporary file. Must be writable. May be overwritten or deleted if present. +* `sprintf(PSA_ITS_STORAGE_PREFIX "%016llx.psa_its", key_id)`: a key or non-key file. The `key_id` in the name is the 64-bit file identifier, which is the [key identifier](#key-names-for-mbed-tls-2.25.0) for a key file or some reserved identifier for a [non-key file](#non-key-files-on-mbed-tls-2.25.0). The contents of the file are: + * Magic header (8 bytes): `"PSA\0ITS\0"` + * File contents. + +### Key names for Mbed TLS 2.25.0 + +Information about each key is stored in a dedicated file designated by the key identifier. In integrations where there is no concept of key owner (in particular, in library integrations), the key identifier is exactly the key identifier as defined in the PSA Cryptography API specification (`psa_key_id_t`). In integrations where there is a concept of key owner (integration into a service for example), the key identifier is made of an owner identifier (its semantics and type are integration specific) and of the key identifier (`psa_key_id_t`) from the key owner point of view. + +The way in which the file name is constructed from the key identifier depends on the storage backend. The content of the file is described [below](#key-file-format-for-mbed-tls-2.25.0). + +* Library integration: the key file name is just the key identifier as defined in the PSA crypto specification. This is a 32-bit value which must be in the range 0x00000001..0x3fffffff (`PSA_KEY_ID_USER_MIN`..`PSA_KEY_ID_USER_MAX`). +* PSA service integration: the key file name is `(uint64_t)owner_uid << 32 | key_id` where `key_id` is the key identifier from the owner point of view and `owner_uid` (of type `int32_t`) is the calling partition identifier provided to the server by the partition manager. This is a 64-bit value. + +### Key file format for Mbed TLS 2.25.0 + +All integers are encoded in little-endian order in 8-bit bytes except where otherwise indicated. + +The layout of a key file is: + +* magic (8 bytes): `"PSA\0KEY\0"`. +* version (4 bytes): 0. +* lifetime (4 bytes): `psa_key_lifetime_t` value. +* type (2 bytes): `psa_key_type_t` value. +* bits (2 bytes): `psa_key_bits_t` value. +* policy usage flags (4 bytes): `psa_key_usage_t` value. +* policy usage algorithm (4 bytes): `psa_algorithm_t` value. +* policy enrollment algorithm (4 bytes): `psa_algorithm_t` value. +* key material length (4 bytes). +* key material: + * For a transparent key: output of `psa_export_key`. + * For an opaque key (unified driver interface): driver-specific opaque key blob. + * For an opaque key (key in a dynamic secure element): slot number (8 bytes), in platform endianness. +* Any trailing data is rejected on load. + +### Non-key files on Mbed TLS 2.25.0 + +File identifiers that are outside the range of persistent key identifiers are reserved for internal use by the library. The only identifiers currently in use have the owner id (top 32 bits) set to 0. + +* Files 0xfffffe02 through 0xfffffeff (`PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE + lifetime`): dynamic secure element driver storage. The content of the file is the secure element driver's persistent data. +* File 0xffffff52 (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`): [nonvolatile random seed](#nonvolatile-random-seed-file-format-for-mbed-tls-2.25.0). +* File 0xffffff54 (`PSA_CRYPTO_ITS_TRANSACTION_UID`): [transaction file](#transaction-file-format-for-mbed-tls-2.25.0). +* Other files are unused and reserved for future use. + +### Nonvolatile random seed file format for Mbed TLS 2.25.0 + +[Identical to Mbed Crypto 0.1.0](#nonvolatile-random-seed-file-format-for-0.1.0). + +### Transaction file format for Mbed TLS 2.25.0 + +The transaction file contains data about an ongoing action that cannot be completed atomically. It exists only if there is an ongoing transaction. + +All integers are encoded in platform endianness. + +All currently existing transactions concern a key in a dynamic secure element. + +The layout of a transaction file is: + +* type (2 bytes): the [transaction type](#transaction-types-on-mbed-tls-2.25.0). +* unused (2 bytes) +* lifetime (4 bytes): `psa_key_lifetime_t` value that corresponds to a key in a secure element. +* slot number (8 bytes): `psa_key_slot_number_t` value. This is the unique designation of the key for the secure element driver. +* key identifier (4 bytes in a library integration, 8 bytes on a PSA platform): the internal representation of the key identifier. On a PSA platform, this encodes the key owner in the same way as [in file identifiers for key files](#file-namespace-on-a-psa-platform-on-mbed-tls-2.25.0)). + +#### Transaction types on Mbed TLS 2.25.0 + +* 0x0001: key creation. The following locations may or may not contain data about the key that is being created: + * The slot in the secure element designated by the slot number. + * The file containing the key metadata designated by the key identifier. + * The driver persistent data. +* 0x0002: key destruction. The following locations may or may not still contain data about the key that is being destroyed: + * The slot in the secure element designated by the slot number. + * The file containing the key metadata designated by the key identifier. + * The driver persistent data. + + +## TF-PSA-Crypto 1.0 + +The dynamic secure element interface `MBEDTLS_PSA_CRYPTO_SE_C` is removed. As a consequence files identifiers 0xfffffe02 through 0xfffffeff are no more used by the secure element driver storage. diff --git a/tf-psa-crypto/docs/architecture/pk-4.md b/tf-psa-crypto/docs/architecture/pk-4.md new file mode 100644 index 0000000000..151f5533bc --- /dev/null +++ b/tf-psa-crypto/docs/architecture/pk-4.md @@ -0,0 +1,568 @@ +The PK module in TF-PSA-Crypto 1 and Mbed TLS 4 +=============================================== + +The goal of this document is to describe the evolution of the `pk.h` interface from Mbed TLS 3.x going into TF-PSA-Crypto 1.0 and Mbed TLS 4.0. + +## Requirements + +### Project goal + +The goal of the PK-4.0 project is to make minimal changes to the `pk.h` interface to make it suitable for TF-PSA-Crypto 1.0, and for consumption in Mbed TLS 4.0. We want to preserve the essential features of PK, while removing aspects of the interface that will make it difficult to finish the migration to PSA, and minimize the amount of work to be done before the 1.0/4.0 releases. + +In the short term, before the 1.0/4.0 releases, we will make parts of `pk.h` private, and provide replacements where needed. The goal of the project is to make the desired parts private (i.e. no longer part of the documented API), and to ensure that the replacements are working. The old API can still be used under the hood in Mbed TLS. + +In the medium term, in TF-PSA-Crypto 1.x and Mbed TLS 4.x, we will remove the internal uses of private APIs from Mbed TLS and TF-PSA-Crypto, then remove the implementation of those private APIs. + +In the long term, we want to fully replace `pk.h` with PSA APIs. This is a work topic for the PSA Crypto API working group. The API design is still at an early stage, far too early to be taken into account here. + +### Essential functionality of PK + +The following functionality does not exist in PSA, but we consider it absolutely necessary for TF-PSA-Crypto: + +* The ability to construct a PSA key from a PK key and vice versa. +* The ability to parse a key in various commonplace formats. These formats include metadata indicating the key type, so this cannot be a simple extension of `psa_import_key`. +* The ability to write a key in various commonplace formats. + +In addition, we choose to retain the following functionality, because it is easier to keep it in PK than to reimplement it where it is used: + +* A sign/verify interface, using a signature format that's ready for X.509 and TLS. + +Any other functionality in the `pk.h` interface in TF-PSA-Crypto will either be justified by these needs (e.g. metadata queries, object creation and destruction), or left over from Mbed TLS 3.x if there's no particular reason to remove it. Everything else will be made private. + +### Functionality that is removed from PK + +The following features are deliberately removed from the PK API. (They may remain as private interfaces until TF-PSA-Crypto 1.x.) + +* The ability to inspect how data is stored in PK contexts: opaque-or-not, `mbedtls_pk_ec()`, `mbedtls_pk_rsa()`, `mbedtls_pk_get_type()`, `mbedtls_pk_info_t`, etc. +* The ability to construct a PK context manually: `mbedtls_pk_setup()`. +* Direct support for opaque keys (`mbedtls_pk_setup_opaque()`, `mbedtls_pk_setup_rsa_alt()`, etc.). Go via PSA instead. +* The poorly defined type `mbedtls_pk_type_t` and the associated function `mbedtls_pk_can_do()`. Use PSA metadata instead. +* Mechanism names: `mbedtls_pk_get_name()`. +* The RSA-oriented length function: `mbedtls_pk_get_len()`. Use `mbedtls_pk_get_bitlen()`. +* Encrypt/decrypt: `mbedtls_pk_decrypt()`, `mbedtls_pk_encrypt()`. Use PSA. + +### Design philosophy for the new PK + +We retain the concept of a “PK context”, which can either be empty or contain a public key or contain a key pair. The new PK handles key parsing and writing, and has convenience functions to sign with a key. + +A PK context has the following conceptual properties: + +* A PSA key type (key pair or public key). This is `PSA_KEY_TYPE_NONE` for an empty context. +* Key material that matches the key type. This can be directly in the PK object, or indirectly via a PSA key identifier. +* Optionally, an associated PSA key identifier. The PSA key may be owned by the PK context and destroyed when the context is destroyed, or it may be referenced by the PK context and left alone when the context is destroyed. + +The PK module does not enforce key policies. In particular, it is possible to copy a PK context into a context with a different signature algorithm. + +### Private interfaces + +In this document, a ***private*** interface is one that is not documented. Applications should not use private interfaces, and we do not promise any kind of stability about them. Mbed TLS can use private interfaces of TF-PSA-Crypto, but in the medium term (over the lifetime of TF-PSA-Crypto 1.x and Mbed TLS 4.x), it should stop doing so. Public interfaces must not rely on private interfaces, for example a private type cannot be used in the prototype of a public function. However, public types can have a private implementation (we guarantee that the type will keep existing, but it may be implemented differently, typically adding and removing fields in a structure). + +An ***internal*** interface is only usable inside TF-PSA-Crypto. + +## Use case studies + +### RSA in TLS + +#### How Mbed TLS currently uses RSA + +In Mbed TLS 4.x, TLS 1.2 cipher suites using RSA encryption are not supported. Thus we only care about RSA as a signature algorithm. This subsection studies how the TLS subsystem uses RSA. + +TLS 1.2 normally uses PKCS#1v1.5. However, if an Mbed TLS client advertizes support for both TLS 1.2 and 1.3 and advertizes support for PSS-based signature algorithms, some servers may select PSS in TLS 1.2, and the Mbed TLS client supports that. In this case, the TLS 1.2 `ssl_parse_server_key_exchange()` checks an RSA-PSS signature using a public key that it finds as a `mbedtls_pk_context` in the peer's certificate. The public key is only used for a single algorithm, but the algorithm is not yet known when the PK object is created. + +TLS 1.3 has a verification mechanism with the same data flow in `ssl_tls13_parse_certificate_verify()`. In TLS 1.3, this is done both on the client side and on the server side. + +TLS 1.3 servers may need to produce either a PKCS#1v1.5 or a PSS signature, based on which signature algorithm the server selects among those offered by the client. The private key is a `mbedtls_pk_context` object passed to `mbedtls_conf_own_cert()`. The SSL configuration stores a chained list of key/certificate pairs, with no length limit. The same private key may be used a different RSA algorithm in each connection. The server commits to a private key and to a certificate chain at the same time, based on the keys it has available and their compatibility with the offered signature algorithms. + +#### Dual-algorithm RSA verification + +In both TLS and X.509, we want the following control flow: + +1. Parse a certificate, creating a PK context containing a public key. +2. Determine which signature verification algorithm to use. This information does not come from the certiciate. +3. Verify a signature according to the chosen algorithm. + +In Mbed TLS 3.6, the parsing step always results in an object where the key is public present in plain text (either in PSA import format or as a representation involving MPI objects). The verification step either calls built-in code or imports the key into PSA. In the latter case, it can freely choose the algorithm. Even if we change the data flow later to create a PSA key sooner, it will always be possible to export the public key, thus we do not need to take any particular precautions for future-proofing. + +The ideal interface here is something similar to `mbedtls_pk_verify_ext()`, with a free selection of the verification algorithm at the time of verification. + +It would be possible to create multiple PK contexts after parsing, one with each potential signature algorithm. However there is no incentive to do so. It would add complexity and memory consumption for no benefit. + +#### Dual-algorithm RSA signature + +The control flow for a TLS server using an RSA private key is as follows: + +1. Construct a PK context around the private key. There are two ways: + + * Parse a key file. Optionally, change some metadata associated with the key. + * Wrap an existing PSA key (opaque PK context). There is no way to change its policy. + +2. Pass the PK context alongside a matching certificate to `mbedtls_ssl_conf_own_cert()`. Note that the same certificate is commonly used with the same key for both PKCS#1v1.5 and PSS. + +3. Establish a connection and reach the point in the construction of the ServerKeyExchange message where the key in question is chosen, with a signature algorithm that can indicate either PKCS#1v1.5 or PSS. + +4. Use the chosen algorithm to produce a signature. + +In order to make it possible to use the same RSA key with both algorithm, some action is necessary at one of these steps. + +At step 1, in Mbed TLS 3.6, RSA keys resulting from parsing can always be used for both algorithms, but this is not necessarily the case for opaque keys. (It can only be the case if the PSA key uses the “enrollment algorithm” policy feature, which is a proprietary extension of TF-PSA-Crypto that is not supported on some platforms such as TF-M.) Thus, if we want a single workflow for all cases, it has to be a **strict workflow**, where the application using TLS must pass two PK contexts if it wants to allow both algorithms. In the case of a PK context resulting from parsing, there must be some indication of which RSA algorithm will be chosen (this is to be documented in the PK module — parsing an RSA key defaults to PKCS#1v1.5). In this workflow, the signature operation always involves the algorithm associated with the PK context: there is no analog of `mbedtls_pk_sign_ext()`. The strict workflow has the downside that it requires each PK object to have a single associated algorithm, which was considered and discarded (see “[Rejected `mbedtls_pk_set_algorithm()`](#rejected-mbedtls_pk_set_algorithm)”). + +We may also consider a **duplication workflow**. In this workflow, at step 2, when `mbedtls_ssl_conf_own_cert()` sees a PK context that could be used for both algorithms (e.g. a PK context that wraps an exportable key, or a PK context that wraps a key whose policy allows both algorithms), it adds two entries to the key/certificate list: the original PK object, and a copied object with the other protocol. This seems complicated, especially with respect to resource management (the SSL configuration object does not own the keys and certificates, but it would have to own the copy made here). Also this workflow is currently broken in TLS 1.3, since it only checks the public key from the certificate, not the private key ([#10233](https://github.com/Mbed-TLS/mbedtls/issues/10233)). Hence we will not consider this workflow further. + +Steps 3 and 4 are performed in near succession for each connection, therefore there is no meaningful difference between an action taken at step 3 or step 4, and we will consider them together. Step 3 needs to determine whether the key is compatible with a given signature algorithm offered by the client. Therefore it must be able to tell when a key allows both algorithms. Then step 4 needs to use the chosen signature algorithm, using a function similar to `mbedtls_pk_sign_ext()`. Depending on how the PK context was constructed, this may be done in different ways (just pass the right algorithm to `psa_sign_hash()` if the PSA key allows it, pass the right algorithm when importing a key that wasn't in PSA already, copy the key, etc.). This is a **cheating workflow**. + +Conclusion: we will continue to use the current cheating workflow. This approach minimizes the changes in how PK object construction determines which algorithms the key can be used with, and in how to query which algorithms a PK object can be used with. + +The main cost of this approach is that we are committing to supporting permissive PK objects, as in, PK objects that can be used with any algorithm that the key type permits. This means that throughout the lifetime of TF-PSA-Crypto 1.x, we will continue to have code in the implementation of `mbedtls_pk_sign_ext()` that possibly exports an underlying PSA key to re-import it under a different policy. This is not ideal, but has the benefit of interface simplicity (PK doesn't do policy, period) and an easy migration from Mbed TLS 3.6 to TF-PSA-Crypto 1.x + Mbed TLS 4.x for both users and us implementers. + +#### Enforcing the workflow + +If the effective capabilities of `mbedtls_ssl_conf_own_cert()` change, we need to be careful not to end up in a situation where: + +1. An application works fine with Mbed TLS 3.6, relying only on documented behavior. +2. The application still works in practice with Mbed TLS 4.0, but now relies on behavior that is no longer documented. +3. The application breaks when TF-PSA-Crypto 1.x moves to more PSA in PK (the change that is likely to be problematic being when `mbedtls_pk_parse_key()` starts constructing a PSA key for RSA key pairs). + +We should make sure that `mbedtls_ssl_conf_own_cert()` is strict on what it accepts even in the 4.0 release, and validate this through tests. See [“Interface stability testing”](#interface-stability-testing). + +## API elements + +### PK context type + +#### Keep `mbedtls_pk_context` + +We keep `mbedtls_pk_context` largely as it is now. It will be reworked after 1.0 as needed. Keep: + +``` +mbedtls_pk_context +mbedtls_pk_init() +mbedtls_pk_free() +``` + +Also keep the following metadata access function: + +``` +mbedtls_pk_can_do_ext() +``` + +#### Meaning of `mbedtls_pk_type_t` + +`mbedtls_pk_type_t` has several subtly different meanings: + +* How the key is represented in a `mbedtls_pk_context`, with additional policy information for EC keys. Can be anything except `MBEDTLS_PK_RSAPSS`. +* Key type from parsing. Can be `MBEDTLS_PK_RSA`, `MBEDTLS_PK_ECKEY` or `MBEDTLS_PK_ECKEY_DH`. Note that obtaining `MBEDTLS_PK_ECKEY_DH` from parsing is fully untested. +* Signature algorithm in X.509. Can be `MBEDTLS_PK_RSA`, `MBEDTLS_PK_RSAPSS` or `MBEDTLS_PK_ECDSA`. +* In invocations of `mbedtls_pk_can_do()`, and possibly elsewhere in local variables or internal functions, it can be a union of two or more of the above. + +In TF-PSA-Crypto, we don't want to expose the distinction between `MBEDTLS_PK_OPAQUE` (purely PSA-backed key) and other key types (non-PSA-backed, or partially PSA-backed in the case of ECC keys). We also don't want to guarantee the subtle distinctions between `MBEDTLS_PK_ECKEY`, `MBEDTLS_PK_ECKEY_DH` and `MBEDTLS_PK_ECDSA`. Hence the type `mbedtls_pk_type_t` will become private. + +#### Public uses of `mbedtls_pk_type_t` or `mbedtls_pk_get_type()` + +Public headers and sample programs are considered public. Library code (including Mbed TLS), test code and test programs are not considered public. + +* In X.509 types, to specify an X.509 signature algorithm. See “[New type for signature algorithms](#new-type-for-signature-algorithms)”. +* In several of `programs/pkey/*.c`, to differentiate between RSA and ECC. See “[Use new APIs to distinguish between RSA and ECC in sample programs](#use-new-apis-to-distinguish-between-rsa-and-ecc-in-sample-programs)”. + +#### New type for signature algorithms + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/346): Define a new type `mbedtls_pk_sigalg_t` which is a subset of `mbedtls_pk_type_t`, containing only the values that are meaningful as a signature algorithm in an X.509 structure. Prototyped in [#204](https://github.com/Mbed-TLS/TF-PSA-Crypto/pull/204). + +``` +typedef enum { + MBEDTLS_PK_SIGALG_NONE = MBEDTLS_PK_NONE, + MBEDTLS_PK_SIGALG_RSA = MBEDTLS_PK_RSA, + MBEDTLS_PK_SIGALG_ECDSA = MBEDTLS_PK_ECDSA, + MBEDTLS_PK_SIGALG_RSASSA_PSS = MBEDTLS_PK_RSASSA_PSS, +} mbedtls_pk_sigalg_t; +``` + +Keep the same numerical values as `mbedtls_pk_type_t`, so that a `mbedtls_pk_sigalg_t` value can be cast to `mbedtls_pk_type_t` in library code that still uses this deprecated type. + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/10264): Move `x509*.h` to the new type. + +This task together with the changes to `mbedtls_pk_sign_ext()` and `mbedtls_pk_verify_ext()` described in “[Signature functionality](#signature-functionality)” remove the need for `mbedtls_pk_type_t` to be in the public API of Mbed TLS. Follow-up: make it (and `mbedtls_pk_get_type()`) private in “[Privatization](#privatization)”. + +Maybe define public aliases for backward compatibility (it costs us pretty much nothing, and will facilitate the transition). +``` +MBEDTLS_PK_NONE = MBEDTLS_PK_SIGALG_NONE +MBEDTLS_PK_RSA = MBEDTLS_PK_SIGALG_RSA +MBEDTLS_PK_RSASSA_PSS = MBEDTLS_PK_SIGALG_RSASSA_PSS +MBEDTLS_PK_ECDSA = MBEDTLS_PK_SIGALG_ECDSA +MBEDTLS_PK_ECKEY = MBEDTLS_PK_SIGALG_ECDSA +``` + +TODO: investigate merging `MBEDTLS_PK_ECKEY` with `MBEDTLS_PK_ECDSA`. Do we rely on the difference anywhere that's still relevant? + +#### `mbedtls_pk_can_do()` + +Remove `mbedtls_pk_can_do()` from the public API. + +Everyone should use PSA metadata instead. For example, the question “can this key do RSA?” (`mbedtls_pk_can_do(pk, MBEDTLS_PK_RSA)`) is ambiguous since the answer depends on the desired algorithm, so users should instead call `mbedtls_pk_can_do_ext()` which takes an algorithm as a parameter. + +#### `mbedtls_pk_get_name()` + +PK no longer has a concept of a name for a key type or algorithm. + +#### Custom PK context data + +PK no longer supports custom setup and inspection of a PK object, thus we remove the following elements from the public API, to be done in “[Privatization](#privatization)”: + +* `mbedtls_pk_setup()`. Construct from a PSA key or by parsing instead. +* `mbedtls_pk_ec()`, `mbedtls_pk_rsa()`. All code must also work when a PK context is backed by a PSA key. + +#### `mbedtls_pk_check_pair()` + +Keep `mbedtls_pk_check_pair()`. It's no burden to implement. + +### Changes to `mbedtls_pk_can_do_ext` + +#### Semantics of `mbedtls_pk_can_do_ext` in Mbed TLS 3.6 + +We keep `mbedtls_pk_can_do_ext()` because it's useful to check what a key can do after parsing it. It is partially redundant with `mbedtls_pk_get_psa_attributes()`, but it's sometimes more convenient, already implemented, and easy to implement for any evolution of PK that can accommodate `mbedtls_pk_get_psa_attributes()`. + +The semantics of `mbedtls_pk_can_do_ext()` in Mbed TLS 3.6 is somewhat weird with respect to public keys. Although the function is advertised as “Tell if context can do the operation given by PSA algorithm”, that is not quite true. The function takes an algorithm and a usage flag (or a mask thereof), with only private-key usage flags allowed. But it accepts public keys, which could only do the corresponding public-key operation. For example, +``` +mbedtls_pk_can_do_ext(pk, PSA_ALG_ECDSA(PSA_ALG_SHA_256), PSA_KEY_USAGE_SIGN_HASH) +``` +is true for a builtin ECC key object containing only the public part of the key. +This is misleading and not documented. + +#### New semantics of `mbedtls_pk_can_do_ext` + +We should change the meaning of the usage flag to indicate what operations can actually be performed on the key: + +* `PSA_KEY_USAGE_SIGN_HASH` means a key pair that can be used to sign; +* `PSA_KEY_USAGE_VERIFY_HASH` means a public key or key pair that can be used to verify; +* `PSA_KEY_USAGE_DECRYPT` means a key pair that can be used to decrypt; +* `PSA_KEY_USAGE_ENCRYPT` means a public key or key pair that can be used to encrypt; +* `PSA_KEY_USAGE_DERIVE` means a key pair that can be used as the private side in a key agreement; +* `PSA_KEY_USAGE_DERIVE_PUBLIC`: flag for a key pair or public key that can be used as the public side in a key agreement. This flag does not currently exist in PSA, and [may be added as part of adding s similar function to the PSA API](https://github.com/ARM-software/psa-api/issues/279). In the meantime, give it the value 0x80000000. Note that changing the value will be an ABI change. + +This will be closer to how `mbedtls_pk_get_psa_attributes()` works. + +To ease the transition, we will call the new function `mbedtls_pk_can_do_psa`. We will keep the current `mbedtls_pk_can_do_ext` as a private function until Mbed TLS stops using it (a [GitHub code search](https://github.com/search?q=%22mbedtls_pk_can_do_ext%28%22+path%3A*.c+NOT+path%3A**%2Fpk.c+NOT+path%3A**%2Fssl_*.c+NOT+path%3A**%2Fx509_c%3F%3F.c+NOT+path%3A**%2Ftest_suite_pk*.c&type=code&ref=advsearch) suggests application developers don't use this function). + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/351): Implement and unit-test `mbedtls_pk_can_do_psa()`. Reuse most of the code of `mbedtls_pk_can_do_ext()` (it will probably help to break it into smaller functions). Should be done before 1.0, but can be done after. + +#### Migrating to `mbedtls_pk_can_do_psa` + +Note that the change of semantics on public keys will break [`ssl_pick_cert()`](https://github.com/Mbed-TLS/mbedtls/blob/mbedtls-3.6.3/library/ssl_tls12_server.c#L687) and [`ssl_tls13_pick_key_cert()`](https://github.com/Mbed-TLS/mbedtls/blob/mbedtls-3.6.3/library/ssl_tls13_server.c#L1115), as they rely on calling `mbedtls_pk_can_do_ext()` on the public key from the certificate. However, this should be an easy fix: just change these invocations to use `PSA_KEY_USAGE_VERIFY_HASH` as the usage to check. + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/10266): migrate TLS to `mbedtls_pk_can_do_psa()`. Can be done after 4.0. + +### PSA bridges + +The new PK needs to have bridges between PK contexts and PSA keys. + +Given a key in one form, there are two ways to obtain a key in the other form: + +* Make a copy of the key data, so that the destination object lives independently from the source object. This is far easier to use in terms of resource management. However, it may not be possible if the source object's policy makes it impossible to copy. This can be the case with PSA keys, and also with PK contexts if they wrap around a non-copiable PSA key. +* Create an object that aliases the source object: wrap a PSA key in a PK context, or peek at the underlying PSA key of a PK context. The wrapper/underlying object is only valid as long as the source object is valid. A PK context created by wrapping an existing PSA key does not destroy the PSA key. Resource management is tricky, but this has a low overhead and works for keys whose material cannot be copied. + +There is currently no way to access the underlying PSA key of a PK context. A nw function to [access the underlying PSA key of a PK context](#access-the-underlying-psa-key-of-a-pk-context) is not planned for TF-PSA-Crypto 1.0. + +#### Choice of ECDSA variant + +PK sometimes needs to choose between ECDSA variants, when it builds PSA attributes for an ECC key: + +* To import an ECC key during parsing, and to sign with a built-in ECC key, when `MBEDTLS_PK_USE_PSA_EC_DATA` is enabled. This uses the macro `MBEDTLS_PK_ALG_ECDSA` defined in `mbedtls/pk.h`. +* In `mbedtls_pk_get_psa_attributes()` to choose the default policy for an ECC key used for signature. + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/345): change `MBEDTLS_PK_PSA_ALG_ECDSA_MAYBE_DET` to a public macro `MBEDTLS_PK_ALG_ECDSA`. Switch `mbedtls_pk_get_psa_attributes()` to it. This is nice but not critical for 1.0. + +#### `mbedtls_pk_get_psa_attributes()` + +Keep `mbedtls_pk_get_psa_attributes()`. + +Notes: + +* An ECC public key in SubjectPublicKeyInfo format (possibly embedded in a key pair) can specify one of two algorithms: id-ecPublicKey (allows ECDSA signature) or id-ecDH (should not be used for signature). This is encoded in the old API through the PK type: id-ecDH leads to `MBEDTLS_PK_ECKEY_DH`. This is untested (we have no test key with id-ecDH; backlog issue: https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/206). In the new API, you can find out whether a key had id-ecPublicKey or id-ecDH by looking at the algorithm chosen by `mbedtls_pk_get_psa_attributes()`. + +* Arguably, since PK is now specialized towards signatures, we could remove the `usage` argument from `mbedtls_pk_get_psa_attributes()`, and make the function work only for a sign/verify usage. However, I don't think this would be right, especially because PK only handles signature: after parsing a key, to use it for something other than signature, you need to use PSA, which means you need to call `mbedtls_pk_get_psa_attributes()` then `mbedtls_pk_import_into_psa()` to create a PSA key with your desired non-signature algorithm. Also, the usage parameter allows for extracting the public part of a key when you don't know whether you have a public key or a key pair, which is very convenient in some cases such as managing a key store. + +#### Copy between PK and PSA + +Keep the following functions, which create a PK context from a PSA key and vice versa: +``` +mbedtls_pk_import_into_psa() +mbedtls_pk_copy_from_psa() +mbedtls_pk_copy_public_from_psa() +``` + +#### Wrap a PSA key in PK + +There is already a function to wrap a PSA private key in a PK context: `mbedtls_pk_setup_opaque()`. The function's name no longer makes sense, since there is no longer a concept of “opaque” PK contexts, and no longer a ”setup“ operation on PK contexts. + +ACTION (crypto-opaque): rename `mbedtls_pk_setup_opaque()` to `mbedtls_pk_wrap_psa()` and adjust the documentation accordingly. (Updating internal references to “opaque” is out of scope and will be done later: [Update terminology from “opaque” to “wrapped”](#update-terminology-from-opaque-to-wrapped).) Prototyped in [#204](https://github.com/Mbed-TLS/TF-PSA-Crypto/pull/204). + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/205): remove mentions of operations other than sign and verify from the documentation. Prototyped in [#204](https://github.com/Mbed-TLS/TF-PSA-Crypto/pull/204). + +The function is somewhat dangerous, since the PK context will silently become invalid if the PSA key is destroyed. Experience in 3.x has shown the function to be handy nonetheless, so we shouldn't remove it without clear alternatives. + +The current function has some limitations. We should lift them soon (“[Remove limitations of `mbedtls_pk_wrap_psa()`](#remove-limitations-of-mbedtls_pk_wrap_psa)”), but it isn't a deal breaker for TF-PSA-Crypto 1.0. + +### Key parsing and writing + +Keep: +``` +mbedtls_pk_parse_key() +mbedtls_pk_parse_public_key() +mbedtls_pk_write_key_der() +mbedtls_pk_write_pubkey_der() +mbedtls_pk_write_pubkey_pem() +mbedtls_pk_write_key_pem() +``` + +Keep: +``` +mbedtls_pk_parse_keyfile() +mbedtls_pk_parse_public_keyfile() +``` + +### Signature conveniences + +#### Signature functionality + +Keep the following: +``` +MBEDTLS_PK_SIGNATURE_MAX_SIZE +``` + +Keep the following: +``` +mbedtls_pk_verify() +mbedtls_pk_sign() +``` + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/347): document that `mbedtls_pk_sign()` and `mbedtls_pk_verify()` are legacy functions, that perform the same algorithm that `mbedtls_pk_get_psa_attributes()` would perform under the hood if given a sign or verify usage. + +Tweak the following: +``` +mbedtls_pk_verify_ext() +mbedtls_pk_sign_ext() +``` + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/348, https://github.com/Mbed-TLS/mbedtls/issues/10265, https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/349): remove the `options` parameter to `mbedtls_pk_verify_ext`. Note that we have a changelog entry announcing that it's ignored, this changelog entry needs to be replaced. + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/346): for `mbedtls_pk_sign_ext()` and `mbedtls_pk_verify_ext()`, change the `mbedtls_pk_type_t type` parameter (whose type is being removed from the API) to `mbedtls_pk_sigalg_t sigalg`. See “[New type for signature algorithms](new-type-for-signature-algorithms)”. + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/5544): remove `MBEDTLS_ERR_PK_SIG_LEN_MISMATCH`. It's mostly useless for RSA, and it doesn't even work for ECDSA. + +#### Restartable signature functionality + +It's more convenient to keep using PK for restartable signature in X.509, for the same reason as non-restartable signature. So restartable PK should keep existing, so we might as well keep it public. + +Keep: +``` +mbedtls_pk_restart_ctx +mbedtls_pk_restart_init() +mbedtls_pk_restart_free() +mbedtls_pk_verify_restartable() +mbedtls_pk_sign_restartable() +``` + +No changes to the function's implementation: restartable behavior is only available for built-in ECDSA when built-in restartable ECC is enabled, but the function always works (in a non-restartable way if restartable is not possible). + +There is a risk that the current API will be suboptimal when we port its implementation. However, I think this risk is low, since this is basically the interface that X.509 likes, and the primary goal of PK is to support X.509. If X.509 needs more adaptation than expected to migrate to PSA, PK is the natural place for the adaptation code. + +### Removals + +#### Removed functions + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/pull/297): remove the encrypt/decrypt functions. + +``` +mbedtls_pk_decrypt() +mbedtls_pk_encrypt() +``` + +#### Privatization + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/343): Create a header `/include/mbedtls/private/pk_private.h`. At first, it just includes `../pk.h`. + +ACTION (https://github.com/Mbed-TLS/mbedtls-framework/issues/178): Conditionally include `mbedtls/private/pk_private.h` in the framework. + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/10263): Conditionally include `mbedtls/private/pk_private.h` in Mbed TLS. + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/344): Move all private API elements to `mbedtls/private/pk_private.h`: + +``` +mbedtls_pk_type_t +mbedtls_pk_rsassa_pss_options +mbedtls_pk_debug_type +mbedtls_pk_debug_item +MBEDTLS_PK_DEBUG_MAX_ITEMS +mbedtls_pk_info_from_type() +mbedtls_pk_setup() +mbedtls_pk_get_len() +mbedtls_pk_can_do() +mbedtls_pk_can_do_ext() +mbedtls_pk_debug() +mbedtls_pk_get_name() +mbedtls_pk_get_type() +mbedtls_pk_rsa() +mbedtls_pk_ec() +mbedtls_pk_parse_subpubkey() +mbedtls_pk_write_pubkey() +``` + +Follow-up: [Make private API elements internal](#make-private-api-elements-internal) + +#### Documentation update after privatization + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/205): remove all mentions of private API elements from the public documentation. + +This includes both direct mentions (where a type name, constant name or function name is mentioned), and indirect mentions (e.g. “verify\_ext”, “context has been set up”). + +#### Remove RSA-ALT + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/208): Remove the option `MBEDTLS_PK_RSA_ALT_SUPPORT` and all code guarded by it, as well as `MBEDTLS_PK_RSA_ALT`. + +### Documentation updates + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/209): update the PSA transition guide. + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/209): write the 1.0 migration guide. + +ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/209): write changelog entries. + +## Changes in PK consumers + +No changes are needed in X.509 before Mbed TLS 4.0. One area of TLS may need some tweaks: [private key selection in TLS servers](#changes-to-private-key-selection). + +### Changes to private key selection in TLS + +A TLS server can have multiple key-certificate pairs configured with `mbedtls_ssl_conf_own_cert()`. In principle, the server goes through the list of cipher suites (TLS 1.2) or signature algorithms (TLS 1.3) offered by the client, and picks the first one for which a key-certificate pair exists. See “[Dual-algorithm RSA signature](dual-algorithm-rsa-signature)” for a more detailed description. + +There are known problems with the current implementation: + +* [#10208](https://github.com/Mbed-TLS/mbedtls/issues/10208): for RSA keys, TLS 1.2 correctly checks the compatibility of the private key. But to perform the actual signature, it calls `mbedtls_pk_sign()`, so it uses the key's primary algorithm, which might not be the one required by the protocol (PKCS#1v1.5 for RSA keys). +* [#10220](https://github.com/Mbed-TLS/mbedtls/issues/10220): for ECDSA keys of type `MBEDTLS_PK_OPAQUE`, TLS 1.2 insists on randomized ECDSA, but the key may only permit deterministic ECDSA. +* [#10233](https://github.com/Mbed-TLS/mbedtls/issues/10233): TLS 1.3 can't cope with multiple private keys for the same certificate. + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/10075): determine how to pass keys to `mbedtls_ssl_conf_own_cert()` in Mbed TLS 4.0, in the sense of documenting an official way to do it, ensuring that this way works, and ensuring that applications using the old way fails (unless we decide to preserve the old way throughout the lifetime of Mbed TLS 4.x and TF-PSA-Crypto 1.x). + +This isn't a problem for verification because as a last resort, it's always possible to export a public key and re-import it with a different policy. + +Note: the conclusion of this investigation is that with the current design, no particular precautions are needed here. + +## Testing + +### Unit tests + +For the most part, the testing work is a matter of adapting the existing tests, and of creating unit tests for the new interfaces. This work is distributed throughout the coding tasks. + +### Interface stability testing + +One of the [project goals](#project-goal) is to prepare for moving crypto to be fully PSA, and in particular PK to be purely a wrapper around PSA keys, at least for private keys. We want to avoid breaking application code in TF-PSA-Crypto 1.x if the code worked with TF-PSA-Crypto 1.0. Normally our stability guarantee does not apply to applications that use undocumented behavior. However, it may happen that an application worked fine with Mbed TLS 3.6 and was relying only on documented behavior, and TF-PSA-Crypto 1.0 or Mbed TLS 4.0 stops documenting a critical aspect of the behavior, but in practice the application still works with 1.0/4.0. To reduce user frustration, we would like to minimize such cases. Thus the API in TF-PSA-Crypto 1.0 and Mbed TLS 4.0 should be strict and should reject “permissive” behavior that could work now, but would not be easy to migrate to PSA. + +Given the choice of keeping PK permissive ([signature functionality](#signature-functionality) keeping `mbedtls_pk_sign_ext()`, cheating workflow chosen for [dual-algorithm RSA signature](#dual-algorithm-rsa-signature)), the combined behavior of PK and TLS remains mostly unchanged from Mbed TLS 3.6. + +ACTION (https://github.com/Mbed-TLS/mbedtls/issues/10160): test `mbedtls_ssl_conf_own_cert()` to ensure that it doesn't cheat on key policies. Note: this would be nice, but at this point, it does not seem critical to do it before the 1.0/4.0 release. However, if we don't implement the tests, we do need to be mindful of not breaking cases that are currently possible. A draft exists in [#10217](https://github.com/Mbed-TLS/mbedtls/pull/10217). + +## Open questions + +### Parsing and writing + +#### Remove file parsing functions? + +Should we remove the file parsing functions `mbedtls_pk_parse_keyfile()` and `mbedtls_pk_parse_public_keyfile()`? They look misplaced in a library that generally doesn't access files. But it isn't really difficult to keep them. + +These functions are used in test code and sample programs. + +### Rejected: `mbedtls_pk_set_algorithm` + +An earlier draft of this document proposed that every PK context would have an associated signature algorithm, which could be set with the function `mbedtls_pk_set_algorithm`. This algorithm was used for `mbedtls_pk_sign` and `mbedtls_pk_verify`. There were no `_ext` versions of these functions: users were supposed to import the key into PSA. + +#### Effectiveness of `mbedtls_pk_set_algorithm` + +How do I parse an RSA key, and then select PSS? More generally, how do I indicate what policy to use after parsing a key? + +In my original draft, you can parse an RSA key and then call `mbedtls_pk_set_algorithm()` to select an algorithm other than the default (which is PKCS#1v1.5 signature). This may not be the right design: it won't work when we change PK to always go through PSA for RSA key pairs (i.e. making them systematically opaque in the old sense). + +An alternative approach is to require copying the key after parsing. This is what we're effectively doing when the application wants to use the key through PSA: it calls `mbedtls_pk_parse_xxx()`, then `mbedtls_pk_import_into_psa()` (after which it can free the intermediate PK object). But what if the application wants to use the key through PK? The current workflow can be: + +* `mbedtls_pk_set_algorithm()` — but as noted above this is not future-proof. +* `mbedtls_pk_import_into_psa()` then `mbedtls_pk_copy_from_psa()`. Inefficient but ok. If that's the intended way to do it, we need to document it clearly, and maybe we should remove `mbedtls_pk_set_algorithm()`? +* A new function `mbedtls_pk_copy()` allowing a policy change? + +#### Why `mbedtls_pk_set_algorithm` was rejected + +`mbedtls_pk_set_algorithm()` had to mutate the PK object, because the normal intended workflow was to parse a key, then inspect its type, then call `mbedtls_pk_set_algorithm()`. But this made it possible to mutate an object after passing it to a function, which could have unintended effect. Furthermore, this function could fail, since it may need to allocate resources (to copy the key, when it's already in PSA and the new algorithm isn't permitted by the key's policy). + +The main intent of `mbedtls_pk_set_algorithm()` was to allow mimicking current flows involving `mbedtls_pk_sign()` and `mbedtls_pk_verify()`. However, on closer inspection, this didn't work so well. In particular, a major driving goal was to keep the internal workings TLS layer mostly unchanged from Mbed TLS 3.6, but change the way users had to call `mbedtls_pk_conf_own_cert()` (see “[RSA in TLS](#rsa-in-tls)”). This would both save time for the preparation of Mbed TLS 4.0, and serve as a sample of what implementers of other protocols might face. + +However, it turns out that the way TLS 1.2 and TLS 1.3 use PK private keys is buggy in different ways: + +* [#10208](https://github.com/Mbed-TLS/mbedtls/issues/10208): TLS 1.2 calls `mbedtls_pk_sign()`, so it uses the key's primary algorithm, which might not be the one required by the protocol (PKCS#1v1.5 for RSA keys). +* [#10233](https://github.com/Mbed-TLS/mbedtls/issues/10233): TLS 1.3 can't cope with multiple private keys for the same certificate. + +These are issues in 3.6, so fixing them is desirable. But their impact is relatively minor in 3.6 because they're uncommon cases. On the other hand, in 4.0, they become more relevant, which risked adding a signficant amount of work to be done before 4.0. + +Architecturally, #10208 highlights how having an algorithm associated with a PK object is inherently fragile. Hence the current design removes this concept, and instead orients the user of the PK module towards explicitly choosing the signature algorithm. + +### Resource management + +#### Access the underlying PSA key of a PK context + +Should we provide a function to access the underlying PSA key of a PK context, if there is one? + +This would be new work, and does not seem to be needed at the moment. If the PK context was created from a PSA key, the application might as well use the original PSA key. If the PK context was created by parsing, `mbedtls_pk_import_into_psa()` works, and does not require a special case if the PK context does not have an underlying PSA key. + +If we add this in the future, it will be considerably easier if all PK contexts have an underlying PSA key, or at least all PK contexts containing a private key have an underlying PSA key. + +Note that this function would be somewhat dangerous, like `mbedtls_pk_wrap_psa()`, since the PK object becomes invalid if the PSA key is destroyed independently, and the PSA key identifier becomes invalid if the PK context is destroyed. It is impossible to detect invalid uses at runtime since the PSA key identifier may be reused. + +## Later tasks + +The tasks described in this section do not need to be done before the 1.0/4.0 release. This section is incomplete. + +### Missing functionality + +#### Remove limitations of `mbedtls_pk_wrap_psa()` + +Remove the limitations of wrapped keys: + +* Implement verify for wrapped RSA keys. +* Implement check-pair for wrapped RSA keys. + +### Migrate library and test code + +#### Update terminology from “opaque” to “wrapped” + +Update the library code to change the obsolete terminology “opaque” (as in e.g. `MBEDTLS_PK_OPAQUE`) to “wrapped”. + +Originally, PK contexts could wrap a PSA key in order to support non-exportable keys kept in a secure partition, using a PSA implementation with client-server isolation. Thus the useful purpose of wrapping a PSA key was to make the key opaque, hence the name. In TF-PSA-Crypto, we plan to evolve to making PK keys contain a PSA key in more situations. What will matter is whether the underlying PSA key is owned by the PK context (and destroyed when the context is freed), or not (thus surviving when the context is freed). A key owned by the PK context could still potentially be opaque. Hence the distinction should be between _wrapped_ and _owned_ PSA keys. + +#### Retire `MBEDTLS_PK_ECDSA` + +It is no longer possible to construct a PK object with the legacy type `MBEDTLS_PK_ECDSA`. So get rid of the code that handles it, and remove `MBEDTLS_PK_ECDSA`. + +#### Replace all uses of `mbedtls_pk_type_t`, `mbedtls_pk_get_type()` and `mbedtls_pk_can_do()` in X.509 library and test code + +#### Replace all uses of `mbedtls_pk_type_t`, `mbedtls_pk_get_type()` and `mbedtls_pk_can_do()` in TLS library and test code + +#### Get rid of `mbedtls_pk_can_do()` + +Once it's no longer used anywhere, we can stop implementing it. + +#### Get rid of `mbedtls_pk_info` + +Dispatch based on an enum rather than a method table. This simplifies the code. + +#### Make `mbedtls_pk_type_t` internal + +Goal: `mbedtls_pk_type_t` is only used inside `pk*.c` and in PK unit tests. It may still be exposed in the `mbedtls_pk_context` type. + +### Migrate sample programs + +#### Use new APIs to distinguish between RSA and ECC in sample programs + +### Removals + +#### Make private API elements internal + +As much as possible, make private API elements internal. That is, instead of being declared in a public header, declare them in `pk_internal.h` which should not be included by anything except `pk*.c` and PK unit tests. + +This should ideally be done little by little, when we eliminate the uses of these elements in Mbed TLS. + +#### Remove deprecated former API elements once they are no longer used diff --git a/tf-psa-crypto/docs/architecture/psa-crypto-implementation-structure.md b/tf-psa-crypto/docs/architecture/psa-crypto-implementation-structure.md new file mode 100644 index 0000000000..5948d572ff --- /dev/null +++ b/tf-psa-crypto/docs/architecture/psa-crypto-implementation-structure.md @@ -0,0 +1,173 @@ +PSA Cryptography API implementation and PSA driver interface +=========================================================== + +## Introduction + +The [PSA Cryptography API specification](https://armmbed.github.io/mbed-crypto/psa/#application-programming-interface) defines an interface to cryptographic operations for which the Mbed TLS library provides a reference implementation. The PSA Cryptography API specification is complemented by the PSA driver interface specification which defines an interface for cryptoprocessor drivers. + +This document describes the high level organization of the Mbed TLS PSA Cryptography API implementation which is tightly related to the PSA driver interface. + +## High level organization of the Mbed TLS PSA Cryptography API implementation +In one sentence, the Mbed TLS PSA Cryptography API implementation is made of a core and PSA drivers as defined in the PSA driver interface. The key point is that software cryptographic operations are organized as PSA drivers: they interact with the core through the PSA driver interface. + +### Rationale + +* Addressing software and hardware cryptographic implementations through the same C interface reduces the core code size and its call graph complexity. The core and its dispatching to software and hardware implementations are consequently easier to test and validate. +* The organization of the software cryptographic implementations in drivers promotes modularization of those implementations. +* As hardware capabilities, software cryptographic functionalities can be described by a JSON driver description file as defined in the PSA driver interface. +* Along with JSON driver description files, the PSA driver specification defines the deliverables for a driver to be included into the Mbed TLS PSA Cryptography implementation. This provides a natural framework to integrate third party or alternative software implementations of cryptographic operations. + +## The Mbed TLS PSA Cryptography API implementation core + +The core implements all the APIs as defined in the PSA Cryptography API specification but does not perform on its own any cryptographic operation. The core relies on PSA drivers to actually +perform the cryptographic operations. The core is responsible for: + +* the key store. +* checking PSA API arguments and translating them into valid arguments for the necessary calls to the PSA driver interface. +* dispatching the cryptographic operations to the appropriate PSA drivers. + +The sketch of an Mbed TLS PSA cryptographic API implementation is thus: +```C +psa_status_t psa_api( ... ) +{ + psa_status_t status; + + /* Pre driver interface call processing: validation of arguments, building + * of arguments for the call to the driver interface, ... */ + + ... + + /* Call to the driver interface */ + status = psa_driver_wrapper_( ... ); + if( status != PSA_SUCCESS ) + return( status ); + + /* Post driver interface call processing: validation of the values returned + * by the driver, finalization of the values to return to the caller, + * clean-up in case of error ... */ +} +``` +The code of most PSA APIs is expected to match precisely the above layout. However, it is likely that the code structure of some APIs will be more complicated with several calls to the driver interface, mainly to encompass a larger variety of hardware designs. For example, to encompass hardware accelerators that are capable of verifying a MAC and those that are only capable of computing a MAC, the psa_mac_verify() API could call first psa_driver_wrapper_mac_verify() and then fallback to psa_driver_wrapper_mac_compute(). + +The implementations of `psa_driver_wrapper_` functions are generated by the build system based on the JSON driver description files of the various PSA drivers making up the Mbed TLS PSA Cryptography API implementation. The implementations are splited into two parts. The static ones are generated in a psa_crypto_driver_wrappers.h header file, the non-static ones are generated in a psa_crypto_driver_wrappers_no_static.c C file and the function prototypes declared in a psa_crypto_driver_wrappers_no_static.h header file. + +The psa_driver_wrapper_() functions dispatch cryptographic operations to accelerator drivers, secure element drivers as well as to the software implementations of cryptographic operations. + +Note that the implementation allows to build the library with only a C compiler by shipping a generated file corresponding to a pure software implementation. The driver entry points and their code in this generated file are guarded by pre-processor directives based on PSA_WANT_xyz macros (see [Conditional inclusion of cryptographic mechanism through the PSA API in Mbed TLS](psa-conditional-inclusion-c.html). That way, it is possible to compile and include in the library only the desired cryptographic operations. + +### Key creation + +Key creation implementation in Mbed TLS PSA core is articulated around three internal functions: psa_start_key_creation(), psa_finish_key_creation() and psa_fail_key_creation(). Implementations of key creation PSA APIs, namely psa_import_key(), psa_generate_key(), psa_key_derivation_output_key() and psa_copy_key() go by the following sequence: + 1. Check the input parameters. + 2. Call psa_start_key_creation() that allocates a key slot, prepares it with the specified key attributes, and in case of a volatile key assign it a volatile key identifier. + 3. Generate or copy the key material into the key slot. This entails the allocation of the buffer to store the key material. + 4. Call psa_finish_key_creation() that mostly saves persistent keys into persistent storage. + +In case of any error occurring at step 3 or 4, psa_fail_key_creation() is called. It wipes and cleans the slot especially the key material: reset to zero of the RAM memory that contained the key material, free the allocated buffer. + + +## Mbed TLS PSA Cryptography API implementation drivers + +A driver of the Mbed TLS PSA Cryptography API implementation (Mbed TLS PSA driver in the following) is a driver in the sense that it is compliant with the PSA driver interface specification. But it is not an actual driver that drives some hardware. It implements cryptographic operations purely in software. + +An Mbed TLS PSA driver C file is named psa_crypto_.c and its associated header file psa_crypto_.h. The functions implementing a driver entry point as defined in the PSA driver interface specification are named as mbedtls_psa__(). As an example, the psa_crypto_rsa.c and psa_crypto_rsa.h are the files containing the Mbed TLS PSA driver implementing RSA cryptographic operations. This RSA driver implements among other entry points the "import_key" entry point. The function implementing this entry point is named mbedtls_psa_rsa_import_key(). + +## How to implement a new cryptographic mechanism + +Summary of files to modify when adding a new algorithm or key type: + +* [ ] PSA Crypto API draft, if not already done — [PSA standardization](#psa-standardization) +* [ ] `include/psa/crypto_values.h` or `include/psa/crypto_extra.h` — [New functions and macros](#new-functions-and-macros) +* [ ] `include/psa/crypto_config.h`, `tests/configs/crypto_config_test_driver_extension.h` — [Preprocessor symbols](#preprocessor-symbols) +* Occasionally `library/check_crypto_config.h` — [Preprocessor symbols](#preprocessor-symbols) +* [ ] `include/mbedtls/config_psa.h` — [Preprocessor symbols](#preprocessor-symbols) +* [ ] `library/psa_crypto.c`, `library/psa_crypto_*.[hc]` — [Implementation of the mechanisms](#implementation-of-the-mechanisms) +* [ ] `include/psa/crypto_builtin_*.h` — [Translucent data structures](#translucent-data-structures) +* [ ] `tests/suites/test_suite_psa_crypto_metadata.data` — [New functions and macros](#new-functions-and-macros) +* (If adding `PSA_IS_xxx`) `tests/suites/test_suite_psa_crypto_metadata.function` — [New functions and macros](#new-functions-and-macros) +* [ ] `tests/suites/test_suite_psa_crypto*.data`, `tests/suites/test_suite_psa_crypto*.function` — [Unit tests](#unit-tests) +* [ ] `framework/scripts/mbedtls_framework/crypto_knowledge.py`, `framework/scripts/mbedtls_framework/asymmetric_key_data.py` — [Unit tests](#unit-tests) +* [ ] `ChangeLog.d/*.txt` — changelog entry + +Summary of files to modify when adding new API functions: + +* [ ] `include/psa/crypto.h` and `include/psa/crypto_sizes.h`, or `include/psa/crypto_extra.h` — [New functions and macros](#new-functions-and-macros) +* [ ] `library/psa_crypto.c`, `scripts/data_files/driver_templates/*.jinja` — [Implementation of the mechanisms](#implementation-of-the-mechanisms) +* [ ] If adding stateful functions: `include/psa/crypto_struct.h`, `include/psa/crypto_builtin_*.h`, `include/psa/crypto_driver_contexts_*.h` — [Translucent data structures](#translucent-data-structures) +* [ ] `tests/suites/test_suite_psa_crypto.data`, `tests/suites/test_suite_psa_crypto.function`, `tests/suites/test_suite_psa_crypto_driver_wrappers.*` — [Unit tests](#unit-tests) + +Note that this is just a basic guide. In some cases, you won't need to change all the files listed here. In some cases, you may need to change other files. + +### PSA standardization + +Typically, if there's enough demand for a cryptographic mechanism in Mbed TLS, there's enough demand for it to be part of the official PSA Cryptography specification. Therefore the first step before implementing a new mechanism should be to approach the PSA Cryptography working group in Arm for standardization. + +At the time of writing, all cryptographic mechanisms that are accessible through `psa_xxx` APIs in in Mbed TLS are current or upcoming PSA standards. Mbed TLS implements some extensions to the PSA API that offer extra integration customization or extra key policies. + +Mbed TLS routinely implements cryptographic mechanisms that are not yet part of a published PSA standard, but that are scheduled to be part of a future version of the standard. The Mbed TLS implementation validates the feasibility of the upcoming PSA standard. The PSA Cryptography working group and the Mbed TLS development team communicate during the elaboration of the new interfaces. + +### New functions and macros + +If a mechanism requires new functions, they should follow the design guidelines in the PSA Cryptography API specification. + +Functions that are part of the current or upcoming API are declared in `include/psa/crypto.h`, apart from structure accessors defined in `include/psa/crypto_struct.h`. Functions that have output buffers have associated sufficient-output-size macros in `include/psa/crypto_sizes.h`. + +Constants (algorithm identifiers, key type identifiers, etc.) and associated destructor macros (e.g. `PSA_IS_xxx()`) are defined in `include/psa/crypto_values.h`. + +Functions and macros that are not intended for standardization, or that are at a stage where the draft standard might still evolve significantly, are declared in `include/psa/crypto_extra.h`. + +The PSA Cryptography API specification defines both names and values for certain kinds of constants: algorithms (`PSA_ALG_xxx`), key types (`PSA_KEY_TYPE_xxx`), ECC curve families (`PSA_ECC_FAMILY_xxx`), DH group families (`PSA_DH_FAMILY_xxx`). If Mbed TLS defines an algorithm or a key type that is not part of a current or upcoming PSA standard, pick a value with the `VENDOR` flag set. If Mbed TLS defines an ECC curve or DH group family that is not part of a current or upcoming PSA standard, define a vendor key type and use the family identifier only with this vendor key type. + +New constants must have a test case in `tests/suites/test_suite_psa_crypto_metadata.data` that verifies that `PSA_IS_xxx` macros behave properly with the new constant. New `PSA_IS_xxx` macros must be declared in `tests/suites/test_suite_psa_crypto_metadata.function`. + +### Preprocessor symbols + +Each cryptographic mechanism is optional and can be selected by the application at build time. For each feature `PSA_ttt_xxx`: + +* The feature is available to applications when the preprocessor symbol `PSA_WANT_ttt_xxx` is defined. These symbols are set in the application configuration file `include/psa/crypto_config.h` (or `MBEDTLS_PSA_CRYPTO_CONFIG_FILE`, plus `MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE`), with code in `include/mbedtls/config_psa.h` deducing the necessary underlying `MBEDTLS_xxx` symbols. +* For transparent keys (keys that are not in a secure element), the feature is implemented by Mbed TLS if `MBEDTLS_PSA_BUILTIN_ttt_xxx` is defined, and by an accelerator driver if `MBEDTLS_PSA_ACCEL_ttt_xxx` is defined. `MBEDTLS_PSA_BUILTIN_ttt_xxx` constants are set in `include/mbedtls/config_psa.h` based on the application requests `PSA_WANT_ttt_xxx` and the accelerator driver declarations `MBEDTLS_PSA_ACCEL_ttt_xxx`. +* For the testing of the driver dispatch code, `tests/configs/crypto_config_test_driver_extension.h` sets additional `MBEDTLS_PSA_ACCEL_xxx` symbols. + +For more details, see *[Conditional inclusion of cryptographic mechanism through the PSA API in Mbed TLS](../proposed/psa-conditional-inclusion-c.html)*. + +Some mechanisms require other mechanisms. For example, you can't do GCM without a block cipher, or RSA-PSS without RSA keys. When mechanism A requires mechanism B, `include/mbedtls/config_psa.h` ensures that B is enabled whenever A is enabled. When mechanism A requires at least one of a set {B1, B2, B3, ...} but there is no particular reason why enabling A would enable any of the specific Bi's, it's up to the application to choose Bi's and the file `library/check_crypto_config.h` contains compile-time constraints to ensure that at least one Bi is enabled. + +### Implementation of the mechanisms + +The general structure of a cryptographic operation function is: + +1. API function defined in `library/psa_crypto.c`. The entry point performs generic checks that don't depend on whether the mechanism is implemented in software or in a driver and looks up keys in the key store. +2. Driver dispatch code in `scripts/data_files/driver_templates/psa_crypto_driver_wrappers.h.jinja`, `scripts/data_files/driver_templates/psa_crypto_driver_wrappers_no_static.c.jinja` or files included from there. +3. Built-in implementation in `library/psa_crypto_*.c` (with function declarations in the corresponding `.h` file). These files typically contain the implementation of modes of operation over basic building blocks that are defined elsewhere. For example, HMAC is implemented in `library/psa_crypto_mac.c` but the underlying hash functions are implemented in `library/sha*.c` and `library/md*.c`. +4. Basic cryptographic building blocks in `library/*.c`. + +When implementing a new algorithm or key type, there are typically things to change in `library/crypto.c` (e.g. buffer size calculations, algorithm/key-type compatibility) and in the built-in implementation, but not in the driver dispatch code. + +### Translucent data structures + +Some mechanisms require state to be kept between function calls. Keys and key-like data is kept in the key store, which PSA manages internally. Other state, for example the state of multipart operations, is kept in structures allocated by the caller. + +The size of operation structures needs to be known at compile time, since callers may allocate them on the stack. Therefore these structures are defined in a public header: `include/psa/crypto_struct.h` for the parts that are independent of the underlying implementation, `include/psa/crypto_builtin_*` for parts that are specific to the Mbed TLS built-in implementation, `include/psa/crypto_driver_*.h` for structures implemented by drivers. + +### Unit tests + +A number of unit tests are automatically generated by `framework/scripts/generate_psa_tests.py` based on the algorithms and key types declared in `include/psa/crypto_values.h` and `include/psa/crypto_extra.h`: + +* Attempt to create a key with a key type that is not supported. +* Attempt to perform an operation with a combination of key type and algorithm that is not valid or not supported. +* Storage and retrieval of a persistent key. + +When adding a new key type or algorithm: + +* `framework/scripts/mbedtls_framework/crypto_knowledge.py` contains knowledge about the compatibility of key types, key sizes and algorithms. +* `framework/scripts/mbedtls_framework/asymmetric_key_data.py` contains valid key data for asymmetric key types. + +Other things need to be tested manually, either in `tests/suites/test_sutie_psa_crypto.data` or in another file. For example (this is not an exhaustive list): + +* Known answer tests. +* Potential edge cases (e.g. data less/equal/more than the block size, number equal to zero in asymmetric cryptography). +* Tests with invalid keys (e.g. wrong size or format). +* Tests with invalid data (e.g. wrong size or format, output buffer too small, invalid padding). +* For new functions: incorrect function call sequence, driver dispatch (in `tests/suites/test_suite_psa_crypto_driver_wrappers.*`). +* For key derivation algorithms: variation on the sequence of input steps, variation on the output size. + diff --git a/tf-psa-crypto/docs/architecture/psa-keystore-design.md b/tf-psa-crypto/docs/architecture/psa-keystore-design.md new file mode 100644 index 0000000000..be082a812a --- /dev/null +++ b/tf-psa-crypto/docs/architecture/psa-keystore-design.md @@ -0,0 +1,214 @@ +PSA key store design +==================== + +## Introduction + +This document describes the architecture of the key storage in memory in the Mbed TLS and TF-PSA-Crypto implementation of the PSA Cryptography API. + +In the PSA Cryptography API, cryptographic operations access key materials via a key identifier (key ID for short). Applications must first create a key object, which allocates storage in memory for the key material and metadata. This storage is under the control of the library and may be located in a different memory space such as a trusted execution environment or a secure element. + +The storage of persistent keys is out of scope of this document. See the [Mbed Crypto storage specification](mbed-crypto-storage-specification.md). + +## Key slot management interface + +### Key store and key slots + +The **key store** consists of a collection of **key slots**. Each key slot contains the metadata for one key, as well as the key material or a reference to the key material. + +A key slot has the type `psa_key_slot_t`. The key store is a global object which is private inside `psa_crypto_slot_management.c`. + +### Key slot entry points + +The following operations allocate a key slot by calling `psa_reserve_free_key_slot()`: + +* **Creating** a key object, through means such as import, random generation, deterministic derivation, copy, or registration of an existing key that is stored in protected hardware (secure element, hardware unique key (HUK)). +* **Loading** a persistent key from storage, or loading a built-in key. This is done through `psa_get_and_lock_key_slot()`, which calls `psa_reserve_free_key_slot()` and loads the key if applicable. + +The following operations free a key slot by calling `psa_wipe_key_slot()` and, if applicable, `psa_free_key_slot()`: + +* **Destroying** a key. +* **Purging** a persistent key from memory, either explicitly at the application's request or to free memory. + +Deinitializing the PSA Crypto subsystem with `mbedtls_psa_crypto_free()` destroys all volatile keys and purges all persistent keys. + +The library accesses key slots in the following scenarios: + +* while the key is being created or loaded; +* while the key is being destroyed or purged; +* while the key metadata or key material is being accessed. + +### Key slot states + +The state of a key slot is indicated by its `state` field of type `psa_key_slot_state_t`, which can be: + +* `PSA_SLOT_EMPTY`: a slot that occupies memory but does not currently contain a key. +* `PSA_SLOT_FILLING`: a slot that is being filled to create or load a key. +* `PSA_SLOT_FULL`: a slot containing a key. +* `PSA_SLOT_PENDING_DELETION`: a slot whose key is being destroy or purged. + +These states are mostly useful for concurrency. See [Concurrency](#concurrency) below and [key slot states in the PSA thread safety specification](psa-thread-safety/psa-thread-safety.md#key-slot-states). + +#### Concurrency + +In a multithreaded environment, since Mbed TLS 3.6.0, each key slot is protected by a reader-writer lock. (In earlier versions, the key store was not thread-safe.) The lock is controlled by a single global mutex `mbedtls_threading_psa_globaldata_mutex`. The concurrency state of the slot is indicated by the state and the `registered_readers` field: + +* `EMPTY` or `FULL` state, `registered_readers == 0`: the slot is not in use by any thread. +* `FULL` state, `registered_readers != 0`: the slot is being read. +* `FILLING` or `PENDING_DELETION` state: the slot is being written. + +For more information, see [PSA thread safety](psa-thread-safety/psa-thread-safety.md). + +Note that a slot must not be moved in memory while it is being read or written. + +## Key slot management implementations + +### Key store implementation variants + +There are three variants of the key store implementation, responding to different needs. + +* Hybrid key store ([static key slots](#static-key-store) with dynamic key data): the key store is a statically allocated array of slots, of size `MBEDTLS_PSA_KEY_SLOT_COUNT`. Key material is allocated on the heap. This is the historical implementation. It remains the default in the Mbed TLS 3.6 long-time support (LTS) branch when using a handwritten `mbedtls_config.h`, as is common on resource-constrained platforms, because the alternatives have tradeoffs (key size limit and larger RAM usage at rest for the static key store, larger code size and more risk due to code complexity for the dynamic key store). +* Fully [static key store](#static-key-store) (since Mbed TLS 3.6.3): the key store is a statically allocated array of slots, of size `MBEDTLS_PSA_KEY_SLOT_COUNT`. Each key slot contains the key representation directly, and the key representation must be no more than `MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE` bytes. This is intended for very constrained devices that do not have a heap. +* [Dynamic key store](#dynamic-key-store) (since Mbed TLS 3.6.1): the key store is dynamically allocated as multiple slices on the heap, with a size that adjusts to the application's usage. Key material is allocated on the heap. Compared to the hybrid key store, the code size and RAM consumption are larger. This is intended for higher-end devices where applications are not expected to have a highly predicatable resource usage. This is the default implementation when using the default `mbedtls_config.h` file, as is common on platforms such as Linux, starting with Mbed TLS 3.6.1. + +#### Future improvement: merging the key store variants + +In the future, we may reduce the number of key store variants to just two, perhaps even one. + +We introduced the variants other than the hybrid key store in a patch release of a long-time support version. As a consequence, we wanted to minimize making changes to the default build (when not using the supplied `mbedtls_config.h`, as explained above), to minimize the risk of bugs and the increase in code size. These considerations will not apply in future major or minor releases, so the default key store can change later. + +The static key store could become a runtime decision, where only keys larger than some threshold require the use of heap memory. The reasons not to do this in Mbed TLS 3.6.x are that this increases complexity somewhat (slightly more code size, and more risk), and this changes the RAM usage profile somewhat. + +A major constraint on the design of the dynamic key store is the need to preserve slot pointers while a slot may be accessed by another thread (see [“Concurrency”](#concurrency)). With the concurrency primitives available in Mbed TLS 3.x, it is very hard to move a key slot in memory, because there could be an indefinite wait until some other thread has finished accessing the slot. This pushed towards the slice-based organisation described below, where each slice is allocated for the long term. In particular, slices cannot be compacted (compacting would be moving slots out of a sparsely-used slice to free it). Better concurrency primitives (e.g. condition variables or semaphores), together with a `realloc()` primitive, could allow freeing unused memory more aggressively, which could make the dynamic key store not detrimental in RAM usage compared to the historical hybrid key store. + +#### Slice abstraction + +Some parts of the key slot management code use **key slices** as an abstraction. A key slice is an array of key slots. Key slices are identified by an index which is a small non-negative integer. + +* With a [static key store](#static-key-store), there is a single, statically allocated slice, with the index 0. +* With a [dynamic key store](#dynamic-key-store), there is statically allocated array of pointers to key slices. The index of a slice is the index in that array. The slices are allocated on the heap as needed. + +#### Key identifiers and slot location + +When creating a volatile key, the slice containing the slot and index of the slot in its slice determine the key identifier. When accessing a volatile key, the slice and the slot index in the slice are calculated from the key identifier. The encoding of the slot location in the volatile key identifier is different for a [static](#volatile-key-identifiers-in-the-static-key-store) or [dynamic](#volatile-key-identifiers-in-the-dynamic-key-store) key store. + +### Static key store + +The static key store is the historical implementation. The key store is a statically allocated array of slots, of size `MBEDTLS_PSA_KEY_SLOT_COUNT`. This value is an upper bound for the total number of volatile keys plus loaded keys. + +Since Mbed TLS 3.6.3, there are two variants for the static key store: a hybrid variant (default), and a fully-static variant enabled by the configuration option `MBEDTLS_PSA_STATIC_KEY_SLOTS`. The two variants have the same key store management: the only difference is in how the memory for key data is managed. With fully static key slots, the key data is directly inside the slot, and limited to `MBEDTLS_PSA_KEY_SLOT_BUFFER_SIZE` bytes. With the hybrid key store, the slot contains a pointer to the key data, which is allocated on the heap. + +#### Volatile key identifiers in the static key store + +For easy lookup, a volatile key whose index is `id` is stored at the index `id - PSA_KEY_ID_VOLATILE_MIN`. + +#### Key creation with a static key store + +To create a key, `psa_reserve_free_key_slot()` searches the key slot array until it finds one that is empty. If there are none, the code looks for a persistent key that can be purged (see [“Persistent key cache”](#persistent-key-cache)), and purges it. If no slot is free and no slot contains a purgeable key, the key creation fails. + +#### Freeing a key slot with a static key store + +With a static key store, `psa_wipe_key_slot()` destroys or purges a key by freeing any associated resources, then setting the key slot to the empty state. The slot is then ready for reuse. + +### Dynamic key store + +The dynamic key store allows a large number of keys, at the expense of more complex memory management. + +The dynamic key store was added in Mbed TLS 3.6.1. It is enabled by `MBEDTLS_PSA_KEY_STORE_DYNAMIC`, which is enabled by default since Mbed TLS 3.6.1. + +#### Dynamic key slot performance characteristics + +Key management and key access have $O(1)$ amortized performance, and mostly $O(1)$ performance for actions involving keys. More precisely: + +* Access to an existing volatile key takes $O(1)$ time. +* Access to a persistent key (including creation and destruction) takes time that is linear in `MBEDTLS_PSA_KEY_SLOT_COUNT`. +* Allocating a key takes amortized $O(1)$ time. Usually the time is $O(s)$ where $s$ is the number of slices (which is a hard-coded value less than $30$), but when creating $k$ volatile keys, at most $\log(k)$ creations will involve calls to `calloc()`, totalling $O(k)$ memory. +* Destroying a volatile key takes $O(1)$ time as of Mbed TLS 3.6.1. Later improvements to memory consumption are likely to involve calls to `free()` which may total $O(k)$ memory where $k$ is the maximum number of volatile keys. + +#### Key slices in the dynamic key store + +The key slot is organized in slices, which are dynamically arrays of key slot. The number of slices is determined at compile time. The key store contains a static array of pointers to slices. + +Volatile keys and loaded keys (persistent or built-in) are stored in separate slices. +Key slices number 0 to `KEY_SLOT_VOLATILE_SLICE_COUNT - 1` contain only volatile keys. +One key slice contains only loaded keys: that key slice is thus the cache slice. See [“Persistent key cache”](persistent-key-cache) for how the cache is managed. + +#### Volatile key identifiers in the dynamic key store + +A volatile key identifier encodes the slice index and the slot index at separate bit positions. That is, `key_id = BASE | slice_index | slot_index` where the bits set in `BASE`, `slice_index` and `slot_index` do not overlap. + +#### From key slot to key slice + +Some parts of the slot management code need to determine which key slice contains a key slot when given a pointer to the key slot. In principle, the key slice is uniquely determined from the key identifier which is located in the slot: + +* for a volatile key identifier, the [slice index is encoded in the key identifier](#volatile-key-identifiers-in-the-dynamic-key-store); +* for a persistent key identifier or built-in key identifier, [the slot is in the sole cache slice](#key-slices-in-the-dynamic-key-store). + +Nonetheless, we store the slice index as a field in the slot, for two reasons: + +* It is more robust in case the slice assignment becomes more complex in the future or is somehow buggy. +* It allows the slot to slice correspondence to work even if the key identifier field has not been filled yet or has been wiped. The implementation in Mbed TLS 3.6.1 requires this because `psa_wipe_key_slot()` wipes the slot, then calls `psa_free_key_slot()`, which needs to determine the slice. Keeping the slice index as a separate field allows us to better separate the concerns of key liveness and slot liveness. A redesign of the internal interfaces could improve this, but would be too disruptive in the 3.6 LTS branch. + +#### Length of the volatile key slices + +The volatile key slices have exponentially increasing length: each slice is twice as long as the previous one. Thus if the length of slice 0 is `B` and there are `N` slices, then there are `B * (2^N - 1)` slots. + +As of Mbed TLS 3.6.1, the maximum number of volatile key slots is less than the theoretical maximum of 2^30 - 2^16 (0x10000000..0x7ffeffff, the largest range of key identifiers reserved for the PSA Crypto implementation that does not overlap the range for built-in keys). The reason is that we limit the slot index to 2^25-1 so that the [encoding of volatile key identifiers](#volatile-key-identifiers-in-the-dynamic-key-store) has 25 bits for the slot index. + +When `MBEDTLS_TEST_HOOKS` is enabled, the length of key slices can be overridden. We use this in tests that need to fill the key store. + +#### Free list + +Each volatile key slice has a **free list**. This is a linked list of all the slots in the slice that are free. The global data contains a static array of free list heads, i.e. the index of a free slot in the slice. Each free slot contains the index of the next free slot in that slice's free list. The end of the list is indicated by an index that is larger than the length of the slice. If the list is empty, the head contains an index that is larger than the length. + +As a small optimization, a free slot does not actually contain the index of the next slot, but the index of the next free slot on the list _relative to the next slot in the array_. For example, 0 indicates that the next free slot is the slot immediately after the current slot. This fact is the reason for the encoding: a slice freshly obtained from `calloc` has all of its slots in the free list in order. The value 1 indicates that there is one element between this slot and the next free slot. The next element of the free list can come before the current slot: -2 indicates that it's the slot immediately before, -3 is two slots before, and so on (-1 is impossible). In general, the absolute index of the next slot after slot `i` in the free list is `i + 1 slice[i].next_free_relative_to_next`. + +#### Dynamic key slot allocation + +To create a volatile key, `psa_reserve_free_key_slot()` searches the free lists of each allocated slice until it finds a slice that is not full. If all allocated slices are full, the code allocates a new slice at the lowest possible slice index. If all possible slices are already allocated and full, the key creation fails. + +The newly allocated slot is removed from the slice's free list. + +We only allocate a slice of size `B * 2^k` if there are already `B * (2^k - 1)` occupied slots. Thus the memory overhead is at most `B` slots plus the number of occupied slots, i.e. the memory consumption for slots is at most twice the required memory plus a small constant overhead. + +#### Dynamic key slot deallocation + +When destroying a volatile key, `psa_wipe_key_slot()` calls `psa_free_key_slot()`. This function adds the newly freed slot to the head of the free list. + +##### Future improvement: slice deallocation + +As of Mbed TLS 3.6.1, `psa_free_key_slot()` does not deallocate slices. Thus the memory consumption for slots never decreases (except when the PSA crypto subsystem is deinitialized). Freeing key slices intelligently would be a desirable improvement. + +We should not free a key slice as soon as it becomes empty, because that would cause large allocations and deallocations if there are slices full of long-lived keys, and then one slice keeps being allocate and deallocated for the occasional short-lived keys. Rather, there should be some hysteresis, e.g. only deallocate a slice if there are at least T free slots in the previous slice. [#9435](https://github.com/Mbed-TLS/mbedtls/issues/9435) + +Note that currently, the slice array contains one sequence of allocated slices followed by one sequence of unallocated slices. Mixing allocated and unallocated slices may make some parts of the code a little more complex, and should be tested thoroughly. + +### Persistent key cache + +Persistent keys and built-in keys need to be loaded into the in-memory key store each time they are accessed: + +* while creating them; +* to access their metadata; +* to start performing an operation with the key; +* when destroying the key. + +To avoid frequent storage access, we cache persistent keys in memory. This cache also applies to built-in keys. + +With the [static key store](#static-key-store), a non-empty slot can contain either a volatile key or a cache entry for a persistent or built-in key. With the [dynamic key store](#dynamic-key-store), volatile keys and cached keys are placed in separate [slices](#key-slices-in-the-dynamic-key-store). + +The persistent key cache is a fixed-size array of `MBEDTLS_PSA_KEY_SLOT_COUNT` slots. In the static key store, this array is shared with volatile keys. In the dynamic key store, the cache is a separate array that does not contain volatile keys. + +#### Accessing a persistent key + +`psa_get_and_lock_key_slot()` automatically loads persistent and built-in keys if the specified key identifier is in the corresponding range. To that effect, it traverses the key cache to see if a key with the given identifier is already loaded. If not, it loads the key. This cache walk takes time that is proportional to the cache size. + +#### Cache eviction + +A key slot must be allocated in the cache slice: + +* to create a volatile key (static key store only); +* to create a persistent key; +* to load a persistent or built-in key. + +If the cache slice is full, the code will try to evict an entry. Only slots that do not have readers can be evicted (see [“Concurrency”](#concurrency)). In the static key store, slots containing volatile keys cannot be evicted. + +As of Mbed TLS 3.6.1, there is no tracking of a key's usage frequency or age. The slot eviction code picks the first evictable slot it finds in its traversal order. We have not reasoned about or experimented with different strategies. diff --git a/tf-psa-crypto/docs/architecture/psa-shared-memory.md b/tf-psa-crypto/docs/architecture/psa-shared-memory.md new file mode 100644 index 0000000000..09ac317ea6 --- /dev/null +++ b/tf-psa-crypto/docs/architecture/psa-shared-memory.md @@ -0,0 +1,685 @@ +PSA API functions and shared memory +=================================== + +## Introduction + +This document discusses the security architecture of systems where PSA API functions might receive arguments that are in memory that is shared with an untrusted process. On such systems, the untrusted process might access a shared memory buffer while the cryptography library is using it, and thus cause unexpected behavior in the cryptography code. + +### Core assumptions + +We assume the following scope limitations: + +* Only PSA Crypto API functions are in scope (including Mbed TLS extensions to the official API specification). Legacy crypto, X.509, TLS, or any other function which is not called `psa_xxx` is out of scope. +* We only consider [input buffers](https://arm-software.github.io/psa-api/crypto/1.1/overview/conventions.html#input-buffer-sizes) and [output buffers](https://arm-software.github.io/psa-api/crypto/1.1/overview/conventions.html#output-buffer-sizes). Any other data is assumed to be in non-shared memory. + +## System architecture discussion + +### Architecture overview + +We consider a system that has memory separation between partitions: a partition can't access another partition's memory directly. Partitions are meant to be isolated from each other: a partition may only affect the integrity of another partition via well-defined system interfaces. For example, this can be a Unix/POSIX-like system that isolates processes, or isolation between the secure world and the non-secure world relying on a mechanism such as TrustZone, or isolation between secure-world applications on such a system. + +More precisely, we consider such a system where our PSA Crypto implementation is running inside one partition, called the **crypto service**. The crypto service receives remote procedure calls (RPC) from other partitions, validates their arguments (e.g. validation of key identifier ownership), and calls a PSA Crypto API function. This document is concerned with environments where the arguments passed to a PSA Crypto API function may be in shared memory (as opposed to environments where the inputs are always copied into memory that is solely accessible by the crypto service before calling the API function, and likewise with output buffers after the function returns). + +When the data is accessible to another partition, there is a risk that this other partition will access it while the crypto implementation is working. Although this could be prevented by suspending the whole system while crypto is working, such a limitation is rarely desirable and most systems don't offer a way to do it. (Even systems that have absolute thread priorities, and where crypto has a higher priority than any untrusted partition, may be vulnerable due to having multiple cores or asynchronous data transfers with peripherals.) + +The crypto service must guarantee that it behaves as if the rest of the world was suspended while it is executed. A behavior that is only possible if an untrusted entity accesses a buffer while the crypto service is processing the data is a security violation. + +### Risks and vulnerabilities + +We consider a security architecture with two or three entities: + +* a crypto service, which offers PSA crypto API calls over RPC (remote procedure call) using shared memory for some input or output arguments; +* a client of the crypto service, which makes a RPC to the crypto service; +* in some scenarios, a client of the client, which makes a RPC to the crypto client which re-shares the memory with the crypto service. + +The behavior of RPC is defined for in terms of values of inputs and outputs. This models an ideal world where the content of input and output buffers is not accessible outside the crypto service while it is processing an RPC. It is a security violation if the crypto service behaves in a way that cannot be achieved by setting the inputs before the RPC call, and reading the outputs after the RPC call is finished. + +#### Read-read inconsistency + +If an input argument is in shared memory, there is a risk of a **read-read inconsistency**: + +1. The crypto code reads part of the input and validates it, or injects it into a calculation. +2. The client (or client's client) modifies the input. +3. The crypto code reads the same part again, and performs an action which would be impossible if the input had had the same value all along. + +Vulnerability example (parsing): suppose the input contains data with a type-length-value or length-value encoding (for example, importing an RSA key). The crypto code reads the length field and checks that it fits within the buffer. (This could be the length of the overall data, or the length of an embedded field) Later, the crypto code reads the length again and uses it without validation. A malicious client can modify the length field in the shared memory between the two reads and thus cause a buffer overread on the second read. + +Vulnerability example (dual processing): consider an RPC to perform authenticated encryption, using a mechanism with an encrypt-and-MAC structure. The authenticated encryption implementation separately calculates the ciphertext and the MAC from the plaintext. A client sets the plaintext input to `"PPPP"`, then starts the RPC call, then changes the input buffer to `"QQQQ"` while the crypto service is working. + +* Any of `enc("PPPP")+mac("PPPP")`, `enc("PPQQ")+mac("PPQQ")` or `enc("QQQQ")+mac("QQQQ")` are valid outputs: they are outputs that can be produced by this authenticated encryption RPC. +* If the authenticated encryption calculates the ciphertext before the client changes the output buffer and calculates the MAC after that change, reading the input buffer again each time, the output will be `enc("PPPP")+mac("QQQQ")`. There is no input that can lead to this output, hence this behavior violates the security guarantees of the crypto service. + +#### Write-read inconsistency + +If an output argument is in shared memory, there is a risk of a **write-read inconsistency**: + +1. The crypto code writes some intermediate data into the output buffer. +2. The client (or client's client) modifies the intermediate data. +3. The crypto code reads the intermediate data back and continues the calculation, leading to an outcome that would not be possible if the intermediate data had not been modified. + +Vulnerability example: suppose that an RSA signature function works by formatting the data in place in the output buffer, then applying the RSA private-key operation in place. (This is how `mbedtls_rsa_pkcs1_sign` works.) A malicious client may write badly formatted data into the buffer, so that the private-key operation is not a valid signature (e.g. it could be a decryption), violating the RSA key's usage policy. + +Vulnerability example with chained calls: we consider the same RSA signature operation as before. In this example, we additionally assume that the data to sign comes from an attestation application which signs some data on behalf of a final client: the key and the data to sign are under the attestation application's control, and the final client must not be able to obtain arbitrary signatures. The final client shares an output buffer for the signature with the attestation application, and the attestation application re-shares this buffer with the crypto service. A malicious final client can modify the intermediate data and thus sign arbitrary data. + +#### Write-write disclosure + +If an output argument is in shared memory, there is a risk of a **write-write disclosure**: + +1. The crypto code writes some intermediate data into the output buffer. This intermediate data must remain confidential. +2. The client (or client's client) reads the intermediate data. +3. The crypto code overwrites the intermediate data. + +Vulnerability example with chained calls (temporary exposure): an application encrypts some data, and lets its clients store the ciphertext. Clients may not have access to the plaintext. To save memory, when it calls the crypto service, it passes an output buffer that is in the final client's memory. Suppose the encryption mechanism works by copying its input to the output buffer then encrypting in place (for example, to simplify considerations related to overlap, or because the implementation relies on a low-level API that works in place). In this scenario, the plaintext is exposed to the final client while the encryption in progress, which violates the confidentiality of the plaintext. + +Vulnerability example with chained calls (backtrack): we consider a provisioning application that provides a data encryption service on behalf of multiple clients, using a single shared key. Clients are not allowed to access each other's data. The provisioning application isolates clients by including the client identity in the associated data. Suppose that an AEAD decryption function processes the ciphertext incrementally by simultaneously writing the plaintext to the output buffer and calculating the tag. (This is how AEAD decryption usually works.) At the end, if the tag is wrong, the decryption function wipes the output buffer. Assume that the output buffer for the plaintext is shared from the client to the provisioning application, which re-shares it with the crypto service. A malicious client can read another client (the victim)'s encrypted data by passing the ciphertext to the provisioning application, which will attempt to decrypt it with associated data identifying the requesting client. Although the operation will fail beacuse the tag is wrong, the malicious client still reads the victim plaintext. + +#### Write-read feedback + +If a function both has an input argument and an output argument in shared memory, and processes its input incrementally to emit output incrementally, the following sequence of events is possible: + +1. The crypto code processes part of the input and writes the corresponding part of the output. +2. The client reads the early output and uses that to calculate the next part of the input. +3. The crypto code processes the rest of the input. + +There are cryptographic mechanisms for which this breaks security properties. An example is [CBC encryption](https://link.springer.com/content/pdf/10.1007/3-540-45708-9_2.pdf): if the client can choose the content of a plaintext block after seeing the immediately preceding ciphertext block, this gives the client a decryption oracle. This is a security violation if the key policy only allowed the client to encrypt, not to decrypt. + +TODO: is this a risk we want to take into account? Although this extends the possible behaviors of the one-shot interface, the client can do the same thing legitimately with the multipart interface. + +### Possible countermeasures + +In this section, we briefly discuss generic countermeasures. + +#### Copying + +Copying is a valid countermeasure. It is conceptually simple. However, it is often unattractive because it requires additional memory and time. + +Note that although copying is very easy to write into a program, there is a risk that a compiler (especially with whole-program optimization) may optimize the copy away, if it does not understand that copies between shared memory and non-shared memory are semantically meaningful. + +Example: the PSA Firmware Framework 1.0 forbids shared memory between partitions. This restriction is lifted in version 1.1 due to concerns over RAM usage. + +#### Careful accesses + +The following rules guarantee that shared memory cannot result in a security violation other than [write-read feedback](#write-read-feedback): + +* Never read the same input twice at the same index. +* Never read back from an output. +* Never write to the output twice at the same index. + * This rule can usefully be relaxed in many circumstances. It is ok to write data that is independent of the inputs (and not otherwise confidential), then overwrite it. For example, it is ok to zero the output buffer before starting to process the input. + +These rules are very difficult to enforce. + +Example: these are the rules that a GlobalPlatform TEE Trusted Application (application running on the secure side of TrustZone on Cortex-A) must follow. + +## Protection requirements + +### Responsibility for protection + +A call to a crypto service to perform a crypto operation involves the following components: + +1. The remote procedure call framework provided by the operating system. +2. The code of the crypto service. +3. The code of the PSA Crypto dispatch layer (also known as the core), which is provided by Mbed TLS. +4. The driver implementing the cryptographic mechanism, which may be provided by Mbed TLS (built-in driver) or by a third-party driver. + +The [PSA Crypto API specification](https://arm-software.github.io/psa-api/crypto/1.1/overview/conventions.html#stability-of-parameters) puts the responsibility for protection on the implementation of the PSA Crypto API, i.e. (3) or (4). + +> In an environment with multiple threads or with shared memory, the implementation carefully accesses non-overlapping buffer parameters in order to prevent any security risk resulting from the content of the buffer being modified or observed during the execution of the function. (...) + +In Mbed TLS 2.x and 3.x up to and including 3.5.0, there is no defense against buffers in shared memory. The responsibility shifts to (1) or (2), but this is not documented. + +In the remainder of this chapter, we will discuss how to implement this high-level requirement where it belongs: inside the implementation of the PSA Crypto API. Note that this allows two possible levels: in the dispatch layer (independently of the implementation of each mechanism) or in the driver (specific to each implementation). + +#### Protection in the dispatch layer + +The dispatch layer has no control over how the driver layer will access buffers. Therefore the only possible protection at this layer method is to ensure that drivers have no access to shared memory. This means that any buffer located in shared memory must be copied into or out of a buffer in memory owned by the crypto service (heap or stack). This adds inefficiency, mostly in terms of RAM usage. + +For buffers with a small static size limit, this is something we often do for convenience, especially with output buffers. However, as of Mbed TLS 3.5.0, it is not done systematically. + +It is ok to skip the copy if it is known for sure that a buffer is not in shared memory. However, the location of the buffer is not under the control of Mbed TLS. This means skipping the copy would have to be a compile-time or run-time option which has to be set by the application using Mbed TLS. This is both an additional maintenance cost (more code to analyze, more testing burden), and a residual security risk in case the party who is responsible for setting this option does not set it correctly. As a consequence, Mbed TLS will not offer this configurability unless there is a compelling argument. + +#### Protection in the driver layer + +Putting the responsibility for protection in the driver layer increases the overall amount of work since there are more driver implementations than dispatch implementations. (This is true even inside Mbed TLS: almost all API functions have multiple underlying implementations, one for each algorithm.) It also increases the risk to the ecosystem since some drivers might not protect correctly. Therefore having drivers be responsible for protection is only a good choice if there is a definite benefit to it, compared to allocating an internal buffer and copying. An expected benefit in some cases is that there are practical protection methods other than copying. + +Some cryptographic mechanisms are naturally implemented by processing the input in a single pass, with a low risk of ever reading the same byte twice, and by writing the final output directly into the output buffer. For such mechanism, it is sensible to mandate that drivers respect these rules. + +In the next section, we will analyze how susceptible various cryptographic mechanisms are to shared memory vulnerabilities. + +### Susceptibility of different mechanisms + +#### Operations involving small buffers + +For operations involving **small buffers**, the cost of copying is low. For many of those, the risk of not copying is high: + +* Any parsing of formatted data has a high risk of [read-read inconsistency](#read-read-inconsistency). +* An internal review shows that for RSA operations, it is natural for an implementation to have a [write-read inconsistency](#write-read-inconsistency) or a [write-write disclosure](#write-write-disclosure). + +Note that in this context, a “small buffer” is one with a size limit that is known at compile time, and small enough that copying the data is not prohibitive. For example, an RSA key fits in a small buffer. A hash input is not a small buffer, even if it happens to be only a few bytes long in one particular call. + +The following buffers are considered small buffers: + +* Any input or output directly related to asymmetric cryptography (signature, encryption/decryption, key exchange, PAKE), including key import and export. + * Note that this does not include inputs or outputs that are not processed by an asymmetric primitives, for example the message input to `psa_sign_message` or `psa_verify_message`. +* Cooked key derivation output. +* The output of a hash or MAC operation. + +**Design decision: the dispatch layer shall copy all small buffers**. + +#### Symmetric cryptography inputs with small output + +Message inputs to hash, MAC and key derivation operations are at a low risk of [read-read inconsistency](#read-read-inconsistency) because they are unformatted data, and for all specified algorithms, it is natural to process the input one byte at a time. + +**Design decision: require symmetric cryptography drivers to read their input without a risk of read-read inconsistency**. + +TODO: what about IV/nonce inputs? They are typically small, but don't necessarily have a static size limit (e.g. GCM recommends a 12-byte nonce, but also allows large nonces). + +#### Key derivation outputs + +Key derivation typically emits its output as a stream, with no error condition detected after setup other than operational failures (e.g. communication failure with an accelerator) or running out of data to emit (which can easily be checked before emitting any data, since the data size is known in advance). + +(Note that this is about raw byte output, not about cooked key derivation, i.e. deriving a structured key, which is considered a [small buffer](#operations-involving-small-buffers).) + +**Design decision: require key derivation drivers to emit their output without reading back from the output buffer**. + +#### Cipher and AEAD + +AEAD decryption is at risk of [write-write disclosure](#write-write-disclosure) when the tag does not match. + +AEAD encryption and decryption are at risk of [read-read inconsistency](#read-read-inconsistency) if they process the input multiple times, which is natural in a number of cases: + +* when encrypting with an encrypt-and-authenticate or authenticate-then-encrypt structure (one read to calculate the authentication tag and another read to encrypt); +* when decrypting with an encrypt-then-authenticate structure (one read to decrypt and one read to calculate the authentication tag); +* with SIV modes (not yet present in the PSA API, but likely to come one day) (one full pass to calculate the IV, then another full pass for the core authenticated encryption); + +Cipher and AEAD outputs are at risk of [write-read inconsistency](#write-read-inconsistency) and [write-write disclosure](#write-write-disclosure) if they are implemented by copying the input into the output buffer with `memmove`, then processing the data in place. In particular, this approach makes it easy to fully support overlapping, since `memmove` will take care of overlapping cases correctly, which is otherwise hard to do portably (C99 does not offer an efficient, portable way to check whether two buffers overlap). + +**Design decision: the dispatch layer shall allocate an intermediate buffer for cipher and AEAD plaintext/ciphertext inputs and outputs**. + +Note that this can be a single buffer for the input and the output if the driver supports in-place operation (which it is supposed to, since it is supposed to support arbitrary overlap, although this is not always the case in Mbed TLS, a [known issue](https://github.com/Mbed-TLS/mbedtls/issues/3266)). A side benefit of doing this intermediate copy is that overlap will be supported. + +For all currently implemented AEAD modes, the associated data is only processed once to calculate an intermediate value of the authentication tag. + +**Design decision: for now, require AEAD drivers to read the additional data without a risk of read-read inconsistency**. Make a note to revisit this when we start supporting an SIV mode, at which point the dispatch layer shall copy the input for modes that are not known to be low-risk. + +#### Message signature + +For signature algorithms with a hash-and-sign framework, the input to sign/verify-message is passed to a hash, and thus can follow the same rules as [symmetric cryptography inputs with small output](#symmetric-cryptography-inputs-with-small-output). This is also true for `PSA_ALG_RSA_PKCS1V15_SIGN_RAW`, which is the only non-hash-and-sign signature mechanism implemented in Mbed TLS 3.5. This is not true for PureEdDSA (`#PSA_ALG_PURE_EDDSA`), which is not yet implemented: [PureEdDSA signature](https://www.rfc-editor.org/rfc/rfc8032#section-5.1.6) processes the message twice. (However, PureEdDSA verification only processes the message once.) + +**Design decision: for now, require sign/verify-message drivers to read their input without a risk of read-read inconsistency**. Make a note to revisit this when we start supporting PureEdDSA, at which point the dispatch layer shall copy the input for algorithms such as PureEdDSA that are not known to be low-risk. + +## Design of shared memory protection + +This section explains how Mbed TLS implements the shared memory protection strategy summarized below. + +### Shared memory protection strategy + +* The core (dispatch layer) shall make a copy of the following buffers, so that drivers do not receive arguments that are in shared memory: + * Any input or output from asymmetric cryptography (signature, encryption/decryption, key exchange, PAKE), including key import and export. + * Plaintext/ciphertext inputs and outputs for cipher and AEAD. + * The output of a hash or MAC operation. + * Cooked key derivation output. + +* A document shall explain the requirements on drivers for arguments whose access needs to be protected: + * Hash and MAC input. + * Cipher/AEAD IV/nonce (to be confirmed). + * AEAD associated data (to be confirmed). + * Key derivation input (excluding key agreement). + * Raw key derivation output (excluding cooked key derivation output). + +* The built-in implementations of cryptographic mechanisms with arguments whose access needs to be protected shall protect those arguments. + +Justification: see “[Susceptibility of different mechanisms](#susceptibility-of-different-mechanisms)”. + +### Implementation of copying + +Copy what needs copying. This is broadly straightforward, however there are a few things to consider. + +#### Compiler optimization of copies + +It is unclear whether the compiler will attempt to optimize away copying operations. + +Once the copying code is implemented, it should be evaluated to see whether compiler optimization is a problem. Specifically, for the major compilers supported by Mbed TLS: +* Write a small program that uses a PSA function which copies inputs or outputs. +* Build the program with link-time optimization / full-program optimization enabled (e.g. `-flto` with `gcc`). Try also enabling the most extreme optimization options such as `-Ofast` (`gcc`) and `-Oz` (`clang`). +* Inspect the generated code with `objdump` or a similar tool to see if copying operations are preserved. + +If copying behaviour is preserved by all major compilers then assume that compiler optimization is not a problem. + +If copying behaviour is optimized away by the compiler, further investigation is needed. Experiment with using the `volatile` keyword to force the compiler not to optimize accesses to the copied buffers. If the `volatile` keyword is not sufficient, we may be able to use compiler or target-specific techniques to prevent optimization, for example memory barriers or empty `asm` blocks. These may be implemented and verified for important platforms while retaining a C implementation that is likely to be correct on most platforms as a fallback - the same approach taken by the constant-time module. + +**Open questions: Will the compiler optimize away copies? If so, can it be prevented from doing so in a portable way?** + +#### Copying code + +We may either copy buffers on an ad-hoc basis using `memcpy()` in each PSA function, or use a unified set of functions for copying input and output data. The advantages of the latter are obvious: + +* Any test hooks need only be added in one place. +* Copying code must only be reviewed for correctness in one place, rather than in all functions where it occurs. +* Copy bypass is simpler as we can just replace these functions with no-ops in a single place. +* Any complexity needed to prevent the compiler optimizing copies away does not have to be duplicated. + +On the other hand, the only advantage of ad-hoc copying is slightly greater flexibility. + +**Design decision: Create a unified set of functions for copying input and output data.** + +#### Copying in multipart APIs + +Multipart APIs may follow one of 2 possible approaches for copying of input: + +##### 1. Allocate a buffer and copy input on each call to `update()` + +This is simple and mirrors the approach for one-shot APIs nicely. However, allocating memory in the middle of a multi-part operation is likely to be bad for performance. Multipart APIs are designed in part for systems that do not have time to perform an operation at once, so introducing poor performance may be a problem here. + +**Open question: Does memory allocation in `update()` cause a performance problem? If so, to what extent?** + +##### 2. Allocate a buffer at the start of the operation and subdivide calls to `update()` + +In this approach, input and output buffers are allocated at the start of the operation that are large enough to hold the expected average call to `update()`. When `update()` is called with larger buffers than these, the PSA API layer makes multiple calls to the driver, chopping the input into chunks of the temporary buffer size and filling the output from the results until the operation is finished. + +This would be more complicated than approach (1) and introduces some extra issues. For example, if one of the intermediate calls to the driver's `update()` returns an error, it is not possible for the driver's state to be rolled back to before the first call to `update()`. It is unclear how this could be solved. + +However, this approach would reduce memory usage in some cases and prevent memory allocation during an operation. Additionally, since the input and output buffers would be fixed-size it would be possible to allocate them statically, avoiding the need for any dynamic memory allocation at all. + +**Design decision: Initially use approach (1) and treat approach (2) as an optimization to be done if necessary.** + +### Validation of copying + +#### Validation of copying by review + +This is fairly self-explanatory. Review all functions that use shared memory and ensure that they each copy memory. This is the simplest strategy to implement but is less reliable than automated validation. + +#### Validation of copying with memory pools + +Proposed general idea: have tests where the test code calling API functions allocates memory in a certain pool, and code in the library allocates memory in a different pool. Test drivers check that needs-copying arguments are within the library pool, not within the test pool. + +#### Validation of copying by memory poisoning + +Proposed general idea: in test code, “poison” the memory area used by input and output parameters that must be copied. Poisoning means something that prevents accessing memory while it is poisoned. This could be via memory protection (allocate with `mmap` then disable access with `mprotect`), or some kind of poisoning for an analyzer such as MSan or Valgrind. + +In the library, the code that does the copying temporarily unpoisons the memory by calling a test hook. + +```c +static void copy_to_user(void *copy_buffer, void *const input_buffer, size_t length) { +#if defined(MBEDTLS_TEST_HOOKS) + if (memory_poison_hook != NULL) { + memory_poison_hook(copy_buffer, length); + } +#endif + memcpy(copy_buffer, input_buffer, length); +#if defined(MBEDTLS_TEST_HOOKS) + if (memory_unpoison_hook != NULL) { + memory_unpoison_hook(copy_buffer, length); + } +#endif +} +``` +The reason to poison the memory before calling the library, rather than after the copy-in (and symmetrically for output buffers) is so that the test will fail if we forget to copy, or we copy the wrong thing. This would not be the case if we relied on the library's copy function to do the poisoning: that would only validate that the driver code does not access the memory on the condition that the copy is done as expected. + +##### Options for implementing poisoning + +There are several different ways that poisoning could be implemented: + +1. Using Valgrind's memcheck tool. Valgrind provides a macro `VALGRIND_MAKE_MEM_NO_ACCESS` that allows manual memory poisoning. Valgrind memory poisoning is already used for constant-flow testing in Mbed TLS. +2. Using Memory Sanitizer (MSan), which allows us to mark memory as uninitialized. This is also used for constant-flow testing. It is suitable for input buffers only, since it allows us to detect when a poisoned buffer is read but not when it is written. +3. Using Address Sanitizer (ASan). This provides `ASAN_POISON_MEMORY_REGION` which marks memory as inaccessible. +4. Allocating buffers separate pages and calling `mprotect()` to set pages as inaccessible. This has the disadvantage that we will have to manually ensure that buffers sit in their own pages, which likely means making a copy. +5. Filling buffers with random data, keeping a copy of the original. For input buffers, keep a copy of the original and copy it back once the PSA function returns. For output buffers, fill them with random data and keep a separate copy of it. In the memory poisoning hooks, compare the copy of random data with the original to ensure that the output buffer has not been written directly. + +Approach (2) is insufficient for the full testing we require as we need to be able to check both input and output buffers. + +Approach (5) is simple and requires no extra tooling. It is likely to have good performance as it does not use any sanitizers. However, it requires the memory poisoning test hooks to maintain extra copies of the buffers, which seems difficult to implement in practice. Additionally, it does not precisely test the property we want to validate, so we are relying on the tests to fail if given random data as input. It is possible (if unlikely) that the PSA function will access the poisoned buffer without causing the test to fail. This becomes more likely when we consider test cases that call PSA functions on incorrect inputs to check that the correct error is returned. For these reasons, this memory poisoning approach seems unsuitable. + +All three remaining approaches are suitable for our purposes. However, approach (4) is more complex than the other two. To implement it, we would need to allocate poisoned buffers in separate memory pages. They would require special handling and test code would likely have to be designed around this special handling. + +Meanwhile, approaches (1) and (3) are much more convenient. We are simply required to call a special macro on some buffer that was allocated by us and the sanitizer takes care of everything else. Of these two, ASan appears to have a limitation related to buffer alignment. From code comments quoted in [the documentation](https://github.com/google/sanitizers/wiki/AddressSanitizerManualPoisoning): + +> This function is not guaranteed to poison the whole region - it may poison only subregion of [addr, addr+size) due to ASan alignment restrictions. + +Specifically, ASan will round the buffer size down to 8 bytes before poisoning due to details of its implementation. For more information on this, see [Microsoft documentation of this feature](https://learn.microsoft.com/en-us/cpp/sanitizers/asan-runtime?view=msvc-170#alignment-requirements-for-addresssanitizer-poisoning). + +It should be possible to work around this by manually rounding buffer lengths up to the nearest multiple of 8 in the poisoning function, although it's remotely possible that this will cause other problems. Valgrind does not appear to have this limitation (unless Valgrind is simply more poorly documented). However, running tests under Valgrind causes a much greater slowdown compared with ASan. As a result, it would be beneficial to implement support for both Valgrind and ASan, to give the extra flexibility to choose either performance or accuracy as required. This should be simple as both have very similar memory poisoning interfaces. + +**Design decision: Implement memory poisoning tests with both Valgrind's memcheck and ASan manual poisoning.** + +##### Validation with new tests + +Validation with newly created tests would be simpler to implement than using existing tests, since the tests can be written to take into account memory poisoning. It is also possible to build such a testsuite using existing tests as a starting point - `mbedtls_test_psa_exercise_key` is a test helper that already exercises many PSA operations on a key. This would need to be extended to cover operations without keys (e.g. hashes) and multipart operations, but it provides a good base from which to build all of the required testing. + +Additionally, we can ensure that all functions are exercised by automatically generating test data files. + +##### Validation with existing tests + +An alternative approach would be to integrate memory poisoning validation with existing tests. This has two main advantages: + +* All of the tests are written already, potentially saving development time. +* The code coverage of these tests is greater than would be achievable writing new tests from scratch. In practice this advantage is small as buffer copying will take place in the dispatch layer. The tests are therefore independent of the values of parameters passed to the driver, so extra coverage in these parameters does not gain anything. + +It may be possible to transparently implement memory poisoning so that existing tests can work without modification. This would be achieved by replacing the implementation of `malloc()` with one that allocates poisoned buffers. However, there are some difficulties with this: + +* Not all buffers allocated by tests are used as inputs and outputs to PSA functions being tested. +* Those buffers that are inputs to a PSA function need to be unpoisoned right up until the function is called, so that they can be filled with input data. +* Those buffers that are outputs from a PSA function need to be unpoisoned straight after the function returns, so that they can be read to check the output is correct. + +These issues may be solved by creating some kind of test wrapper around every PSA function call that poisons the memory. However, it is unclear how straightforward this will be in practice. If this is simple to achieve, the extra coverage and time saved on new tests will be a benefit. If not, writing new tests is the best strategy. + +**Design decision: Add memory poisoning transparently to existing tests.** + +#### Discussion of copying validation + +Of all discussed approaches, validation by memory poisoning appears as the best. This is because it: + +* Does not require complex linking against different versions of `malloc()` (as is the case with the memory pool approach). +* Allows automated testing (unlike the review approach). + +**Design decision: Use a memory poisoning approach to validate copying.** + +### Shared memory protection requirements + +TODO: write document and reference it here. + +### Validation of careful access for built-in drivers + +For PSA functions whose inputs and outputs are not copied, it is important that we validate that the builtin drivers are correctly accessing their inputs and outputs so as not to cause a security issue. Specifically, we must check that each memory location in a shared buffer is not accessed more than once by a driver function. In this section we examine various possible methods for performing this validation. + +Note: We are focusing on read-read inconsistencies for now, as most of the cases where we aren't copying are inputs. + +#### Review + +As with validation of copying, the simplest method of validation we can implement is careful code review. This is the least desirable method of validation for several reasons: + +1. It is tedious for the reviewers. +2. Reviewers are prone to make mistakes (especially when performing tedious tasks). +3. It requires engineering time linear in the number of PSA functions to be tested. +4. It cannot assure the quality of third-party drivers, whereas automated tests can be ported to any driver implementation in principle. + +If all other approaches turn out to be prohibitively difficult, code review exists as a fallback option. However, it should be understood that this is far from ideal. + +#### Tests using `mprotect()` + +Checking that a memory location is not accessed more than once may be achieved by using `mprotect()` on a Linux system to cause a segmentation fault whenever a memory access happens. Tests based on this approach are sketched below. + +##### Linux mprotect+ptrace + +Idea: call `mmap` to allocate memory for arguments and `mprotect` to deny or reenable access. Use `ptrace` from a parent process to react to SIGSEGV from a denied access. On SIGSEGV happening in the faulting region: + +1. Use `ptrace` to execute a `mprotect` system call in the child to enable access. TODO: How? `ptrace` can modify registers and memory in the child, which includes changing parameters of a syscall that's about to be executed, but not directly cause the child process to execute a syscall that it wasn't about to execute. +2. Use `ptrace` with `PTRACE_SINGLESTEP` to re-execute the failed load/store instrution. +3. Use `ptrace` to execute a `mprotect` system call in the child to disable access. +4. Use `PTRACE_CONT` to resume the child execution. + +Record the addresses that are accessed. Mark the test as failed if the same address is read twice. + +##### Debugger + mprotect + +Idea: call `mmap` to allocate memory for arguments and `mprotect` to deny or reenable access. Use a debugger to handle SIGSEGV (Gdb: set signal catchpoint). If the segfault was due to accessing the protected region: + +1. Execute `mprotect` to allow access. +2. Single-step the load/store instruction. +3. Execute `mprotect` to disable access. +4. Continue execution. + +Record the addresses that are accessed. Mark the test as failed if the same address is read twice. This part might be hard to do in the gdb language, so we may want to just log the addresses and then use a separate program to analyze the logs, or do the gdb tasks from Python. + +#### Instrumentation (Valgrind) + +An alternative approach is to use a dynamic instrumentation tool (the most obvious being Valgrind) to trace memory accesses and check that each of the important memory addresses is accessed no more than once. + +Valgrind has no tool specifically that checks the property that we are looking for. However, it is possible to generate a memory trace with Valgrind using the following: + +``` +valgrind --tool=lackey --trace-mem=yes --log-file=logfile ./myprogram +``` +This will execute `myprogram` and dump a record of every memory access to `logfile`, with its address and data width. If `myprogram` is a test that does the following: + +1. Set up input and output buffers for a PSA function call. +2. Leak the start and end address of each buffer via `print()`. +3. Write data into the input buffer exactly once. +4. Call the PSA function. +5. Read data from the output buffer exactly once. + +Then it should be possible to parse the output from the program and from Valgrind and check that each location was accessed exactly twice: once by the program's setup and once by the PSA function. + +#### Fixed Virtual Platform testing + +It may be possible to measure double accesses by running tests on a Fixed Virtual Platform such as Corstone 310 ecosystem FVP, available [here](https://developer.arm.com/downloads/-/arm-ecosystem-fvps). There exists a pre-packaged example program for the Corstone 310 FVP available as part of the Open IoT SDK [here](https://git.gitlab.arm.com/iot/open-iot-sdk/examples/sdk-examples/-/tree/main/examples/mbedtls/cmsis-rtx/corstone-310) that could provide a starting point for a set of tests. + +Running on an FVP allows two approaches to careful-access testing: + +* Convenient scripted use of a debugger with [Iris](https://developer.arm.com/documentation/101196/latest/). This allows memory watchpoints to be set, perhaps more flexibly than with GDB. +* Tracing of all memory accesses with [Tarmac Trace](https://developer.arm.com/documentation/100964/1123/Plug-ins-for-Fast-Models/TarmacTrace). To validate the single-access properties, the [processor memory access trace source](https://developer.arm.com/documentation/100964/1123/Plug-ins-for-Fast-Models/TarmacTrace/Processor-memory-access-trace) can be used to output all memory accesses happening on the FVP. This output can then be easily parsed and processed to ensure that the input and output buffers are accessed only once. The addresses of buffers can either be leaked by the program through printing to the serial port or set to fixed values in the FVP's linker script. + +#### Discussion of careful-access validation + +The best approach for validating the correctness of memory accesses is an open question that requires further investigation. To answer this question, each of the test strategies discussed above must be prototyped as follows: + +1. Take 1-2 days to create a basic prototype of a test that uses the approach. +2. Document the prototype - write a short guide that can be followed to arrive at the same prototype. +3. Evaluate the prototype according to its usefulness. The criteria of evaluation should include: + * Ease of implementation - Was the prototype simple to implement? Having implemented it, is it simple to extend it to do all of the required testing? + * Flexibility - Could the prototype be extended to cover other careful-access testing that may be needed in future? + * Performance - Does the test method perform well? Will it cause significant slowdown to CI jobs? + * Ease of reproduction - Does the prototype require a particular platform or tool to be set up? How easy would it be for an external user to run the prototype? + * Comprehensibility - Accounting for the lower code quality of a prototype, would developers unfamiliar with the tests based on the prototype be able to understand them easily? + * Portability - How well can this approach be ported to multiple platforms? This would allow us to ensure that there are no double-accesses due to a bug that only affects a specific target. + +Once each prototype is complete, choose the best approach to implement the careful-access testing. Implement tests using this approach for each of the PSA interfaces that require careful-access testing: + +* Hash +* MAC +* AEAD (additional data only) +* Key derivation +* Asymmetric signature (input only) + +##### New vs existing tests + +Most of the test methods discussed above need extra setup. Some require leaking of buffer bounds, predictable memory access patterns or allocation of special buffers. FVP testing even requires the tests to be run on a non-host target. + +With this complexity in mind it does not seem feasible to run careful-access tests using existing testsuites. Instead, new tests should be written that exercise the drivers in the required way. Fortunately, the only interfaces that need testing are hash, MAC, AEAD (testing over AD only), Key derivation and Asymmetric signature, which limits the number of new tests that must be written. + +#### Validation of validation for careful-access + +In order to ensure that the careful-access validation works, it is necessary to write tests to check that we can correctly detect careful-access violations when they occur. To do this, write a test function that: + +* Reads its input multiple times at the same location. +* Writes to its output multiple times at the same location. + +Then, write a careful-access test for this function and ensure that it fails. + +## Analysis of argument protection in built-in drivers + +TODO: analyze the built-in implementations of mechanisms for which there is a requirement on drivers. By code inspection, how satisfied are we that they meet the requirement? + +## Copy bypass + +For efficiency, we are likely to want mechanisms to bypass the copy and process buffers directly in builds that are not affected by shared memory considerations. + +Expand this section to document any mechanisms that bypass the copy. + +Make sure that such mechanisms preserve the guarantees when buffers overlap. + +## Detailed design + +### Implementation by module + +Module | Input protection strategy | Output protection strategy | Notes +---|---|---|--- +Hash and MAC | Careful access | Careful access | Low risk of multiple-access as the input and output are raw unformatted data. +Cipher | Copying | Copying | +AEAD | Copying (careful access for additional data) | Copying | +Key derivation | Careful access | Careful access | +Asymmetric signature | Careful access | Copying | Inputs to signatures are passed to a hash. This will no longer hold once PureEdDSA support is implemented. +Asymmetric encryption | Copying | Copying | +Key agreement | Copying | Copying | +PAKE | Copying | Copying | +Key import / export | Copying | Copying | Keys may be imported and exported in DER format, which is a structured format and therefore susceptible to read-read inconsistencies and potentially write-read inconsistencies. + +### Copying functions + +As discussed in [Copying code](#copying-code), it is simpler to use a single unified API for copying. Therefore, we create the following functions: + +* `psa_crypto_copy_input(const uint8_t *input, size_t input_length, uint8_t *input_copy, size_t input_copy_length)` +* `psa_crypto_copy_output(const uint8_t *output_copy, size_t output_copy_length, uint8_t *output, size_t output_length)` + +These seem to be a repeat of the same function, however it is useful to retain two separate functions for input and output parameters so that we can use different test hooks in each when using memory poisoning for tests. + +Given that the majority of functions will be allocating memory on the heap to copy, it is helpful to build convenience functions that allocate the memory as well. + +In order to keep track of allocated copies on the heap, we can create new structs: + +```c +typedef struct psa_crypto_local_input_s { + uint8_t *buffer; + size_t length; +} psa_crypto_local_input_t; + +typedef struct psa_crypto_local_output_s { + uint8_t *original; + uint8_t *buffer; + size_t length; +} psa_crypto_local_output_t; +``` + +These may be used to keep track of input and output copies' state, and ensure that their length is always stored with them. In the case of output copies, we keep a pointer to the original buffer so that it is easy to perform a writeback to the original once we have finished outputting. + +With these structs we may create 2 pairs of functions, one pair for input copies: + +```c +psa_status_t psa_crypto_local_input_alloc(const uint8_t *input, size_t input_len, + psa_crypto_local_input_t *local_input); + +void psa_crypto_local_input_free(psa_crypto_local_input_t *local_input); +``` + +* `psa_crypto_local_input_alloc()` calls `calloc()` to allocate a new buffer of length `input_len`, copies the contents across from `input`. It then stores `input_len` and the pointer to the copy in the struct `local_input`. +* `psa_crypto_local_input_free()` calls `free()` on the local input that is referred to by `local_input` and sets the pointer in the struct to `NULL`. + +We also create a pair of functions for output copies: + +```c +psa_status_t psa_crypto_local_output_alloc(uint8_t *output, size_t output_len, + psa_crypto_local_output_t *local_output); + +psa_status_t psa_crypto_local_output_free(psa_crypto_local_output_t *local_output); +``` + +* `psa_crypto_local_output_alloc()` calls `calloc()` to allocate a new buffer of length `output_len` and stores `output_len` and the pointer to the buffer in the struct `local_output`. It also stores a pointer to `output` in `local_output->original`. +* `psa_crypto_local_output_free()` copies the contents of the output buffer `local_output->buffer` into the buffer `local_output->original`, calls `free()` on `local_output->buffer` and sets it to `NULL`. + +Some PSA functions may not use these convenience functions as they may have local optimizations that reduce memory usage. For example, ciphers may be able to use a single intermediate buffer for both input and output. + +In order to abstract the management of the copy state further, to make it simpler to add, we create the following 6 convenience macros: + +For inputs: + +* `LOCAL_INPUT_DECLARE(input, input_copy_name)`, which declares and initializes a `psa_crypto_local_input_t` and a pointer with the name `input_copy_name` in the current scope. +* `LOCAL_INPUT_ALLOC(input, input_size, input_copy)`, which tries to allocate an input using `psa_crypto_local_input_alloc()`. On failure, it sets an error code and jumps to an exit label. On success, it sets `input_copy` to point to the copy of the buffer. +* `LOCAL_INPUT_FREE(input, input_copy)`, which frees the input copy using `psa_crypto_local_input_free()` and sets `input_copy` to `NULL`. + +For outputs: + +* `LOCAL_OUTPUT_DECLARE(output, output_copy_name)`, analogous to `LOCAL_INPUT_DECLARE()` for `psa_crypto_local_output_t`. +* `LOCAL_OUTPUT_ALLOC(output, output_size, output_copy)`, analogous to `LOCAL_INPUT_ALLOC()` for outputs, calling `psa_crypto_local_output_alloc()`. +* `LOCAL_OUTPUT_FREE(output, output_copy)`, analogous to `LOCAL_INPUT_FREE()` for outputs. If the `psa_crypto_local_output_t` is in an invalid state (the copy pointer is valid, but the original pointer is `NULL`) this macro sets an error status. + +These macros allow PSA functions to have copying added while keeping the code mostly unmodified. Consider a hypothetical PSA function: + +```c +psa_status_t psa_foo(const uint8_t *input, size_t input_length, + uint8_t *output, size_t output_size, size_t *output_length) +{ + /* Do some operation on input and output */ +} +``` + +By changing the name of the input and output parameters, we can retain the original variable name as the name of the local copy while using a new name (e.g. with the suffix `_external`) for the original buffer. This allows copying to be added near-seamlessly as follows: + +```c +psa_status_t psa_foo(const uint8_t *input_external, size_t input_length, + uint8_t *output_external, size_t output_size, size_t *output_length) +{ + psa_status_t status; + + LOCAL_INPUT_DECLARE(input_external, input); + LOCAL_OUTPUT_DECLARE(output_external, output); + + LOCAL_INPUT_ALLOC(input_external, input); + LOCAL_OUTPUT_ALLOC(output_external, output); + + /* Do some operation on input and output */ + +exit: + LOCAL_INPUT_FREE(input_external, input); + LOCAL_OUTPUT_FREE(output_external, output); +} +``` + +A second advantage of using macros for the copying (other than simple convenience) is that it allows copying to be easily disabled by defining alternate macros that function as no-ops. Since buffer copying is specific to systems where shared memory is passed to PSA functions, it is useful to be able to disable it where it is not needed, to save code size. + +To this end, the macros above are defined conditionally on a new config option, `MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS`, which may be set whenever PSA functions are assumed to have exclusive access to their input and output buffers. When `MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS` is set, the macros do not perform copying. + +### Implementation of copying validation + +As discussed in the [design exploration of copying validation](#validation-of-copying), the best strategy for validation of copies appears to be validation by memory poisoning, implemented using Valgrind and ASan. + +To perform memory poisoning, we must implement the functions alluded to in [Validation of copying by memory poisoning](#validation-of-copying-by-memory-poisoning): +```c +void mbedtls_test_memory_poison(const unsigned char *ptr, size_t size); +void mbedtls_test_memory_unpoison(const unsigned char *ptr, size_t size); +``` +This should poison or unpoison the given buffer, respectively. + +* `mbedtls_test_memory_poison()` is equivalent to calling `VALGRIND_MAKE_MEM_NOACCESS(ptr, size)` or `ASAN_POISON_MEMORY_REGION(ptr, size)`. +* `mbedtls_test_memory_unpoison()` is equivalent to calling `VALGRIND_MAKE_MEM_DEFINED(ptr, size)` or `ASAN_UNPOISON_MEMORY_REGION(ptr, size)`. + +The PSA copying function must then have test hooks implemented as outlined in [Validation of copying by memory poisoning](#validation-of-copying-by-memory-poisoning). + +As discussed in [the design exploration](#validation-with-existing-tests), the preferred approach for implementing copy-testing is to implement it transparently using existing tests. This is specified in more detail below. + +#### Transparent allocation-based memory poisoning + +In order to implement transparent memory poisoning we require a wrapper around all PSA function calls that poisons any input and output buffers. + +The easiest way to do this is to create wrapper functions that poison the memory and then `#define` PSA function names to be wrapped versions of themselves. For example, to replace `psa_aead_update()`: +```c +psa_status_t mem_poison_psa_aead_update(psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + mbedtls_test_memory_poison(input, input_length); + mbedtls_test_memory_poison(output, output_size); + psa_status_t status = psa_aead_update(operation, input, input_length, + output, output_size, output_length); + mbedtls_test_memory_unpoison(input, input_length); + mbedtls_test_memory_unpoison(output, output_size); + + return status; +} + +#define psa_aead_update(...) mem_poison_psa_aead_update(__VA_ARGS__) +``` + +There now exists a more generic mechanism for making exactly this kind of transformation - the PSA test wrappers, which exist in the files `tests/include/test/psa_test_wrappers.h` and `tests/src/psa_test_wrappers.c`. These are wrappers around all PSA functions that allow testing code to be inserted at the start and end of a PSA function call. + +The test wrappers are generated by a script, although they are not automatically generated as part of the build process. Instead, they are checked into source control and must be manually updated when functions change by running `framework/scripts/generate_psa_wrappers.py`. + +Poisoning code is added to these test wrappers where relevant in order to pre-poison and post-unpoison the parameters to the functions. + +#### Configuration of poisoning tests + +Since the memory poisoning tests will require the use of interfaces specific to the sanitizers used to poison memory, they must only be enabled when we are building with ASan or Valgrind. For now, we can auto-detect ASan at compile-time and set an option: `MBEDTLS_TEST_MEMORY_CAN_POISON`. When this option is enabled, we build with memory-poisoning support. This enables transparent testing with ASan without needing any extra configuration options. + +Auto-detection and memory-poisoning with Valgrind is left for future work. + +#### Validation of validation for copying + +To make sure that we can correctly detect functions that access their input/output buffers rather than the copies, it would be best to write a test function that misbehaves and test it with memory poisoning. Specifically, the function should: + +* Read its input buffer and after calling the input-buffer-copying function to create a local copy of its input. +* Write to its output buffer before and after calling the output-buffer-copying function to copy-back its output. + +Then, we could write a test that uses this function with memory poisoning and ensure that it fails. Since we are expecting a failure due to memory-poisoning, we would run this test separately from the rest of the memory-poisoning testing. + +This testing is implemented in `framework/tests/programs/metatest.c`, which is a program designed to check that test failures happen correctly. It may be run via the script `tests/scripts/run-metatests.sh`. diff --git a/tf-psa-crypto/docs/architecture/psa-storage-resilience.md b/tf-psa-crypto/docs/architecture/psa-storage-resilience.md new file mode 100644 index 0000000000..6df85efd46 --- /dev/null +++ b/tf-psa-crypto/docs/architecture/psa-storage-resilience.md @@ -0,0 +1,530 @@ +# PSA storage resilience design + +## Introduction + +The PSA crypto subsystem includes a persistent key store. It is possible to create a persistent key and read it back later. This must work even if the underlying storage exhibits non-nominal behavior. In this document, _resilience_ means correct behavior of the key store even under if the underlying platform behaves in a non-nominal, but still partially controlled way. + +At this point, we are only concerned about one specific form of resilience: to a system crash or power loss. That is, we assume that the underlying platform behaves nominally, except that occasionally it may restart. In the field, this can happen due to a sudden loss of power. + +This document explores the problem space, defines a library design and a test design. + +## Resilience goals for API functions + +**Goal: PSA Crypto API functions are atomic and committing.** + +_Atomic_ means that when an application calls an API function, as far as the application is concerned, at any given point in time, the system is either in a state where the function has not started yet, or in a state where the function has returned. The application never needs to worry about an intermediate state. + +_Committing_ means that when a function returns, the data has been written to the persistent storage. As a consequence, if the system restarts during a sequence of storage modifications $M_1, M_2, \ldots, M_n$, we know that when the system restarts, a prefix of the sequence has been performed. For example, there will never be a situation where $M_2$ has been performed but not $M_1$. + +The committing property is important not only for sequences of operations, but also when reporting the result of an operation to an external system. For example, if a key creation function in the PSA Crypto API reports to the application that a key has been created, and the application reports to a server that the key has been created, it is guaranteed that the key exists even if the system restarts. + +## Assumptions on the underlying file storage + +PSA relies on a PSA ITS (Internal Trusted Storage) interface, which exposes a simple API. There are two functions to modify files: + +* `set()` writes a whole file (either creating it, or replacing the previous content). +* `remove()` removes a file (returning a specific error code if the file does not exist). + +**Assumption: the underlying ITS functions are atomic and committing.** + +Since the underlying functions are atomic, the content of a file is always a version that was previously passed to `set()`. We do not try to handle the case where a file might be partially written. + +## Overview of API functions + +For a transparent key, all key management operations (creation or destruction) on persistent keys rely on a single call to the underlying storage (`set()` for a key creation, `remove()` for a key destruction). This also holds for an opaque key stored in a secure element that does not have its own key store: in this case, the core stores a wrapped (i.e. encrypted) copy of the key material, but this does not impact how the core interacts with the storage. Other API functions do not modify the storage. + +The following case requires extra work related to resilience: + +* [Key management for stateful secure element keys](#designing-key-management-for-secure-element-keys). + +As a consequence, apart from the listed cases, the API calls inherit directly from the [resilience properties of the underyling storage](#assumptions-on-the-underlying-file-storage). We do not need to take any special precautions in the library design, and we do not need to perform any testing of resilience for transparent keys. + +(This section was last updated for Mbed TLS 3.4.0 implementing PSA Crypto API 1.1.) + +## Designing key management for secure element keys + +In this section, we use “(stateful) secure element key” to mean a key stored in a stateful secure element, i.e. a secure element that stores keys. This excludes keys in a stateleess secure element for which the core stores a wrapped copy of the key. We study the problem of how key management in stateful secure elements interacts with storage and explore the design space. + +### Assumptions on stateful secure elements + +**Assumption: driver calls for key management in stateful secure elements are atomic and committing.** + +(For stateless secure elements, this assumption is vacuously true.) + +### Dual management of keys: the problem + +For a secure element key, key management requires a commitment on both sites. For example, consider a successful key creation operation: + +1. The core sends a request to the secure element to create a key. +2. The secure element modifies its key store to create the key. +3. The secure element reports to the core that the key has been created. +4. The core reports to the application that the key has been created. + +If the core loses power between steps 1 and 2, the key does not exist yet. This is fine from an application's perspective since the core has not committed to the key's existence, but the core needs to take care not to leave resources in storage that are related to the non-existent key. If the core loses power between steps 2 and 3, the key exists in the secure element. From an application's perspective, the core may either report that the key exists or that it does not exist, but in the latter case, the core needs to free the key in the secure element, to avoid leaving behind inaccessible resources. + +As a consequence, the content of the storage cannot remain the same between the end of step 1 and the end of step 3, since the core must behave differently depending on whether step 2 has taken place. + +Accomplishing a transaction across system boundaries is a well-known problem in database management, with a well-known solution: two-phase commit. + +### Overview of two-phase commit with stateful secure elements + +With a key in a stateful secure element, a successful creation process goes as follows (see [“Key management in a secure element with storage” in the driver interface specification](../../proposed/psa-driver-interface.html#key-management-in-a-secure-element-with-storage)): + +1. The core calls the driver's `"allocate_key"` entry point. +2. The driver allocates a unique identifier _D_ for the key. This is unrelated to the key identifier _A_ used by the application interface. This step must not modify the state of the secure element. +3. The core updates the storage to indicate that key identifier _A_ has the identifier _D_ in the driver, and that _A_ is in a half-created state. +4. The core calls the driver's key creation entry point, passing it the driver's chosen identifier _D_. +5. The driver creates the key in the secure element. When this happens, it concludes the voting phase of the two-phase commit: effectively, the secure element decides to commit. (It is however possible to revert this commitment by giving the secure element the order to destroy the key.) +6. The core updates the storage to indicate that _A_ is now in a fully created state. This concludes the commit phase of the two-phase commit. + +If there is a loss of power: + +* Before step 3: the system state has not changed at all. As far as the world is concerned, the key creation attempt never happened. +* Between step 3 and step 6: upon restart, the core needs to find out whether the secure element completed step 5 or not, and reconcile the state of the storage with the state of the secure element. +* After step 6: the key has been created successfully. + +Key destruction goes as follows: + +1. The core updates the storage indicating that the key is being destroyed. +2. The core calls the driver's `"destroy_key"` entry point. +3. The secure element destroys the key. +4. The core updates the storage to indicate that the key has been destroyed. + +If there is a loss of power: + +* Before step 1: the system state has not changed at all. As far as the world is concerned, the key destruction attempt never happened. +* Between step 1 and step 4: upon restart, the core needs to find out whether the secure element completed step 3 or not, and reconcile the state of the storage with the state of the secure element. +* After step 4: the key has been destroyed successfully. + +In both cases, upon restart, the core needs to perform a transaction recovery. When a power loss happens, the core decides whether to commit or abort the transaction. + +Note that the analysis in this section assumes that the driver does not update its persistent state during a key management operation (or at least not in a way that is influences the key management process — for example, it might renew an authorization token). + +### Optimization considerations for transactions + +We assume that power failures are rare. Therefore we will primarily optimize for the normal case. Transaction recovery needs to be practical, but does not have to be fully optimized. + +The main quantity we will optimize for is the number of storage updates in the nominal case. This is good for performance because storage writes are likely to dominate the runtime in some hardware configurations where storage writes are slow and communication with the secure element is fast, for key management operations that require a small amount of computation. In addition, minimizing the number of storage updates is good for the longevity of flash media. + +#### Information available during recovery + +The PSA ITS API does not support enumerating files in storage: an ITS call can only access one file identifier. Therefore transaction recovery cannot be done by traversing files whose name is or encodes the key identifier. It must start by traversing a small number of files whose names are independent of the key identifiers involved. + +#### Minimum effort for a transaction + +Per the [assumptions on the underlying file storage](#assumptions-on-the-underlying-file-storage), each atomic operation in the internal storage concerns a single file: either removing it, or setting its content. Furthermore there is no way to enumerate the files in storage. + +A key creation function must transform the internal storage from a state where file `id` does not exist, to a state where file `id` exists and has its desired final content (containing the key attributes and the driver's key identifier). The situation is similar with key destruction, except that the initial and final states are exchanged. Neither the initial state nor the final state reference `id` otherwise. + +For a key that is not in a stateful element, the transaction consists of a single write operation. As discussed previously, this is not possible with a stateful secure element because the state of the internal storage needs to change both before and after the state change in the secure element. No other single-write algorithm works. + +If there is a power failure around the time of changing the state of the secure element, there must be information in the internal storage that indicates that key `id` has a transaction in progress. The file `id` cannot be used for this purpose because there is no way to enumerate all keys (and even if there was, it would not be practical). Therefore the transaction will need to modify some other file `t` with a fixed name (a name that doesn't depend on the key). Since the final system state should be identical to the initial state except for the file `id`, the minimum number of storage operations for a transaction is 3: + +* Write (create or update) a file `t` referencing `id`. +* Write the final state of `id`. +* Restore `t` to its initial state. + +The strategies discussed in the [overview above](#overview-of-two-phase-commit-with-stateful-secure-elements) follow this pattern, with `t` being the file containing the transaction list that the recovery consults. We have just proved that this pattern is optimal. + +Note that this pattern requires the state of `id` to be modified only once. In particular, if a key management involves writing an intermediate state for `id` before modifying the secure element state and writing a different state after that, this will require a total of 4 updates to internal storage. Since we want to minimize the number of storage updates, we will not explore designs that involved updating `id` twice or more. + +### Recovery strategies + +When the core starts, it needs to know about transaction(s) that need to be resumed. This information will be stored in a persistent “transaction list”, with one entry per key. In this section, we explore recovery strategies, and we determine what the transaction list needs to contain as well as when it needs to be updated. Other sections will explore the format of the transaction list, as well as how many keys it needs to contain. + +#### Exploring the recovery decision tree + +There are four cases for recovery when a transaction is in progress. In each case, the core can either decide to commit the transaction (which may require replaying the interrupted part) or abort it (which may require a rewind in the secure element). It may call the secure element driver's `"get_key_attributes"` entry point to find out whether the key is present. + +* Key creation, key not present in the secure element: + * Committing means replaying the driver call in the key creation. This requires all the input, for example the data to import. This seems impractical in general. Also, the second driver call require a new call to `"allocate_key"` which will in general changing the key's driver identifier, which complicates state management in the core. Given the likely complexity, we exclude this strategy. + * Aborting means removing any trace of the key creation. +* Key creation, key present in the secure element: + * Committing means finishing the update of the core's persistent state, as would have been done if the transaction had not been interrupted. + * Aborting means destroying the key in the secure element and removing any local storage used for that key. +* Key destruction, key not present in the secure element: + * Committing means finishing the update of the core's persistent state, as would have been done if the transaction had not been interrupted, by removing any remaining local storage used for that key. + * Aborting would mean re-creating the key in the secure element, which is impossible in general since the key material is no longer present. +* Key destruction, key present in the secure element: + * Committing means finishing the update of the core's persistent state, as would have been done if the transaction had not been interrupted, by removing any remaining local storage used for that key and destroying the key in the secure element. + * Aborting means keeping the key. This requires no action on the secure element, and is only practical locally if the local storage is intact. + +#### Comparing recovery strategies + +From the analysis above, assuming that all keys are treated in the same way, there are 4 possible strategies. + +* [Always follow the state of the secure element](#exploring-the-follow-the-secure-element-strategy). This requires the secure element driver to have a `"get_key_attributes"` entry point. Recovery means resuming the operation where it left off. For key creation, this means that the key metadata needs to be saved before calling the secure element's key creation entry point. +* Minimize the information processing: [always destroy the key](#exploring-the-always-destroy-strategy), i.e. abort all key creations and commit all key destructions. This does not require querying the state of the secure element. This does not require any special precautions to preserve information about the key during the transaction. It simplifies recovery in that the recovery process might not even need to know whether it's recovering a key creation or a key destruction. +* Follow the state of the secure element for key creation, but always go ahead with key destruction. This requires the secure element driver to have a `"get_key_attributes"` entry point. Compared to always following the state of the secure element, this has the advantage of maximizing the chance that a command to destroy key material is effective. Compared to always destroying the key, this has a performance advantage if a key creation is interrupted. These do not seem like decisive advantages, so we will not consider this strategy further. +* Always abort key creation, but follow the state of the secure element for key destruction. I can't think of a good reason to choose this strategy. + +Requiring the driver to have a `"get_key_attributes"` entry point is potentially problematic because some secure elements don't have room to store key attributes: a key slot always exists, and it's up to the user to remember what, if anything, they put in it. The driver has to remember anyway, so that it can find a free slot when creating a key. But with a recovery strategy that doesn't involve a `"get_key_attributes"` entry point, the driver design is easier: the driver doesn't need to protect the information about slots in use against a power failure, the core takes care of that. + +#### Exploring the follow-the-secure-element strategy + +Each entry in the transaction list contains the API key identifier, the key lifetime (or at least the location), the driver key identifier (not constant-size), and an indication of whether the key is being created or destroyed. + +For key creation, we have all the information to store in the key file once the `"allocate_key"` call returns. We must store all the information that will go in the key file before calling the driver's key creation entry point. Therefore the normal sequence of operations is: + +1. Call the driver's `"allocate_key"` entry point. +2. Add the key to the transaction list, indicating that it is being created. +3. Write the key file. +4. Call the driver's key creation entry point. +5. Remove the key from the transaction list. + +During recovery, for each key in the transaction list that was being created: + +* If the key exists in the secure element, just remove it from the transaction list. +* If the key does not exist in the secure element, first remove the key file if it is present, then remove the key from the transaction list. + +For key destruction, we need to preserve the key file until after the key has been destroyed. Therefore the normal sequence of operations is: + +1. Add the key to the transaction list, indicating that it is being destroyed. +2. Call the driver's `"destroy_key"` entry point. +3. Remove the key file. +4. Remove the key from the transaction list. + +During recovery, for each key in the transaction list that was being created: + +* If the key exists in the secure element, call the driver's `"destroy_key"` entry point, then remove the key file, and finally remote the key from the transaction lits. +* If the key does not exist in the secure element, remove the key file if it is still present, then remove the key from the transaction list. + +#### Exploring the always-destroy strategy + +Each entry in the transaction list contains the API key identifier, the key lifetime (or at least the location), and the driver key identifier (not constant-size). + +For key creation, we do not need to store the key's metadata until it has been created in the secure element. Therefore the normal sequence of operations is: + +1. Call the driver's `"allocate_key"` entry point. +2. Add the key to the transaction list. +3. Call the driver's key creation entry point. +4. Write the key file. +5. Remove the key from the transaction list. + +For key destruction, we can remove the key file before contacting the secure element. Therefore the normal sequence of operations is: + +1. Add the key to the transaction list. +2. Remove the key file. +3. Call the driver's `"destroy_key"` entry point. +4. Remove the key from the transaction list. + +Recovery means removing all traces of all keys on the transaction list. This means following the destruction process, starting after the point where the key has been added to the transaction list, and ignoring any failure of a removal action if the item to remove does not exist: + +1. Remove the key file, treating `DOES_NOT_EXIST` as a success. +2. Call the driver's `"destroy_key"` entry point, treating `DOES_NOT_EXIST` as a success. +3. Remove the key from the transaction list. + +#### Always-destroy strategy with a simpler transaction file + +We can modify the [always-destroy strategy](#exploring-the-always-destroy-strategy) to make the transaction file simpler: if we ensure that the key file always exists if the key exists in the secure element, then the transaction list does not need to include the driver key identifier: it can be read from the key file. + +For key creation, we need to store the key's metadata before creating in the secure element. Therefore the normal sequence of operations is: + +1. Call the driver's `"allocate_key"` entry point. +2. Add the key to the transaction list. +3. Write the key file. +4. Call the driver's key creation entry point. +5. Remove the key from the transaction list. + +For key destruction, we need to contact the secure element before removing the key file. Therefore the normal sequence of operations is: + +1. Add the key to the transaction list. +2. Call the driver's `"destroy_key"` entry point. +3. Remove the key file. +4. Remove the key from the transaction list. + +Recovery means removing all traces of all keys on the transaction list. This means following the destruction process, starting after the point where the key has been added to the transaction list, and ignoring any failure of a removal action if the item to remove does not exist: + +1. Load the driver key identifier from the key file. If the key file does not exist, skip to step 4. +2. Call the driver's `"destroy_key"` entry point, treating `DOES_NOT_EXIST` as a success. +3. Remove the key file, treating `DOES_NOT_EXIST` as a success. +4. Remove the key from the transaction list. + +Compared with the basic always-destroy strategy: + +* The transaction file handling is simpler since its entries have a fixed size. +* The flow of information is somewhat different from transparent keys and keys in stateless secure elements: we aren't just replacing “create the key material” by “tell the secure element to create the key material”, those happen at different times. But there's a different flow for stateful secure elements anyway, since the call to `"allocate_key"` has no analog in the stateless secure element or transparent cases. + +#### Assisting secure element drivers with recovery + +The actions of the secure element driver may themselves be non-atomic. So the driver must be given a chance to perform recovery. + +To simplify the design of the driver, the core should guarantee that the driver will know if a transaction was in progress and the core cannot be sure about the state of the secure element. Merely calling a read-only entry point such as `"get_key_attributes"` does not provide enough information to the driver for it to know that it should actively perform recovery related to that key. + +This gives an advantage to the “always destroy” strategy. Under this strategy, if the key might be in a transitional state, the core will request a key destruction from the driver. This means that, if the driver has per-key auxiliary data to clean up, it can bundle that as part of the key's destruction. + +### Testing non-atomic processes + +In this section, we discuss how to test non-atomic processes that must implement an atomic and committing interface. As discussed in [“Overview of API functions”](#overview-of-api-functions), this concerns key management in stateful secure elements. + +#### Naive test strategy for non-atomic processes + +Non-atomic processes consist of a series of atomic, committing steps. + +Our general strategy to test them is as follows: every time there is a modification of persistent state, either in storage or in the (simulated) secure element, try both the nominal case and simulating a power loss. If a power loss occurs, restart the system (i.e. clean up and call `psa_crypto_init()`), and check that the system ends up in a consistent state. + +Note that this creates a binary tree of possibilities: after each state modification, there may or may not be a restart, and after that different state modifications may occur, each of which may or may not be followed by a restart. + +For example, consider testing of one key creation operation (see [“Overview of two-phase commit with stateful secure elements”](#overview-of-two-phase-commit-with-stateful-secure-elements), under the simplifying assumption that each storage update step, as well as the recovery after a restart, each make a single (atomic) storage modification and no secure element access. The nominal case consists of three state modifications: storage modification (start transaction), creation on the secure element, storage modification (commit transaction). We need to test the following sequences: + +* Start transaction, restart, recovery. +* Start transaction, secure element operation, restart, recovery. +* Start transaction, secure element operation, commit transaction. + +If, for example, recovery consists of two atomic steps, the tree of possibilities expands and may be infinite: + +* Start transaction, restart, recovery step 1, restart, recovery step 1, recovery step 2. +* Start transaction, restart, recovery step 1, restart, recovery step 1, restart, recovery step 1, recovery step 2. +* Start transaction, restart, recovery step 1, restart, recovery step 1, restart, recovery step 1, restart, recovery step 1, recovery step 2. +* etc. +* Start transaction, secure element operation, restart, ... +* Start transaction, secure element operation, commit transaction. + +In order to limit the possibilities, we need to make some assumptions about the recovery step. For example, if we have confidence that recovery step 1 is idempotent (i.e. doing it twice is the same as doing it once), we don't need to test what happens in execution sequences that take recovery step 1 more than twice in a row. + +### Splitting normal behavior and transaction recovery + +We introduce an abstraction level in transaction recovery: + +* Normal operation must maintain a certain invariant on the state of the world (internal storage and secure element). +* Transaction recovery is defined over all states of the world that satisfy this invariant. + +This separation of concerns greatly facilitates testing, since it is now split into two parts: + +* During the testing of normal operation, we can use read-only invasive testing to ensure that the invariant is maintained. No modification of normal behavior (such as simulated power failures) is necessary. +* Testing of transaction recovery is independent of how the system state was reached. We only need to artificially construct a representative sample of system states that match the invariant. Transaction recovery is itself an operation that must respect the invariant, and so we do not need any special testing for the case of an interrupted recovery. + +Another benefit of this approach is that it is easier to specify and test what happens if the library is updated on a device with leftovers from an interrupted transaction. We will require and test that the new version of the library supports recovery of the old library's states, without worrying how those states were reached. + +#### Towards an invariant for transactions + +As discussed in the section [“Recovery strategies”](#recovery-strategies), the information about active transactions is stored in a transaction list file. The name of the transaction list file does not depend on the identifiers of the keys in the list, but there may be more than one transaction list, for example one per secure element. If so, each transaction list can be considered independently. + +When no transaction is in progress, the transaction list does not exist, or is empty. The empty case must be supported because this is the initial state of the filesystem. When no transaction is in progress, the state of the secure element must be consistent with references to keys in that secure element contained in key files. More generally, if a key is not in the transaction list, then the key must be present in the secure element if and only if the key file is in the internal storage. + +For the purposes of the state invariant, it matters whether the transaction list file contains the driver key identifier, or if the driver key identifier is only stored in the key file. This is because the core needs to know the driver key id in order to access the secure element. If the transaction list does not contain the driver key identifier, and the key file does not exist, the key must not be present in the secure element. + +We thus have two scenarios, each with their own invariant: one where the transaction list contains only key identifiers, and one where it also contains the secure element's key identifier (as well as the location of the secure element if this is not encoded in the name of the transaction list file). + +#### Storage invariant if the transaction list contains application key identifiers only + +Invariants: + +* If the file `id` does not exist, then no resources corresponding to that key are in a secure element. This holds whether `id` is in the transaction list or not. +* If `id` is not in the transaction list and the file `id` exists and references a key in a stateful secure element, then the key is present in the secure element. + +If `id` is in the transaction list and the file `id` exists, the key may or may not be present in the secure element. + +The invariant imposes constraints on the [order of operations for the two-phase commit](#overview-of-two-phase-commit-with-stateful-secure-elements): key creation must create `id` before calling the secure element's key creation entry point, and key destruction must remove `id` after calling the secure element's key destruction entry point. + +For recovery: + +* If the file `id` does not exist, then nothing needs to be done for recovery, other than removing `id` from the transaction list. +* If the file `id` exists: + * It is correct to destroy the key in the secure element (treating a `DOES_NOT_EXIST` error as a success), then remove `id`. + * It is correct to check whether the key exists in the secure element, and if it does, keep it and keep `id`. If not, remove `id` from the internal storage. + +#### Storage invariant if the transaction list contains driver key identifiers + +Invariants: + +* If `id` is not in the transaction list and the file `id` does not exist, then no resources corresponding to that key are in a secure element. +* If `id` is not in the transaction list and the file `id` exists, then the key is present in the secure element. + +If `id` is in the transaction list, neither the state of `id` in the internal storage nor the state of the key in the secure element is known. + +For recovery: + +* If the file `id` does not exist, then destroy the key in the secure element (treating a `DOES_NOT_EXIST` error as a success). +* If the file `id` exists: + * It is correct to destroy the key in the secure element (treating a `DOES_NOT_EXIST` error as a success), then remove `id`. + * It is correct to check whether the key exists in the secure element, and if it does, keep it and keep `id`. If not, remove `id` from the internal storage. + +#### Coverage of states that respect the invariant + +For a given key, we have to consider three a priori independent boolean states: + +* Whether the key file exists. +* Whether the key is in the secure element. +* Whether the key is in the transaction list. + +There is full coverage for one key if we have tests of recovery for the states among these $2^3 = 8$ possibilities that satisfy the storage invariant. + +In addition, testing should adequately cover the case of multiple keys in the transaction list. How much coverage is adequate depends on the layout of the list as well as white-box considerations of how the list is manipulated. + +### Choice of a transaction design + +#### Chosen transaction algorithm + +Based on [“Optimization considerations for transactions”](#optimization-considerations-for-transactions), we choose a transaction algorithm that consists in the following operations: + +1. Add the key identifier to the transaction list. +2. Call the secure element's key creation or destruction entry point. +3. Remove the key identifier from the transaction list. + +In addition, before or after step 2, create or remove the key file in the internal storage. + +In order to conveniently support multiple transactions at the same time, we pick the simplest possible layout for the transaction list: a simple array of key identifiers. Since the transaction list does not contain the driver key identifier: + +* During key creation, create the key file in internal storage in the internal storage before calling the secure element's key creation entry point. +* During key destruction, call the secure element's key destruction entry point before removing the key file in internal storage. + +This choice of algorithm does not require the secure element driver to have a `"get_key_attributes"` entry point. + +#### Chosen storage invariant + +The [storage invariant](#storage-invariant-if-the-transaction-list-contains-application-key-identifiers-only) is as follows: + +* If the file `id` does not exist, then no resources corresponding to that key are in a secure element. This holds whether `id` is in the transaction list or not. +* If `id` is not in the transaction list and the file `id` exists and references a key in a stateful secure element, then the key is present in the secure element. +* If `id` is in the transaction list and a key exists by that identifier, the key's location is a stateful secure element. + +#### Chosen recovery process + +To [assist secure element drivers with recovery](#assisting-secure-element-drivers-with-recovery), we pick the [always-destroy recovery strategy with a simple transaction file](#always-destroy-strategy-with-a-simpler-transaction-file). The the recovery process is as follows: + +* If the file `id` does not exist, then nothing needs to be done for recovery, other than removing `id` from the transaction list. +* If the file `id` exists, call the secure element's key destruction entry point (treating a `DOES_NOT_EXIST` error as a success), then remove `id`. + +## Specification of key management in stateful secure elements + +This section only concerns stateful secure elements as discussed in [“Designing key management for secure element keys”](#designing-key-management-for-secure-element-keys), i.e. secure elements with an `"allocate_key"` entry point. The design follows the general principle described in [“Overview of two-phase commit with stateful secure elements”](#overview-of-two-phase-commit-with-stateful-secure-elements) and the specific choices justified in [“Choice of a transaction design”](choice-of-a-transaction-design). + +### Transaction list file manipulation + +The transaction list is a simple array of key identifiers. + +To add a key identifier to the list: + +1. Load the current list from the transaction list if it exists and it is not already cached in memory. +2. Append the key identifier to the array. +3. Write the updated list file. + +To remove a key identifier from the list: + +1. Load the current list if it is not already cached in memory. It is an error if the file does not exist since it must contain this identifier. +2. Remove the key identifier from the array. If it wasn't the last element in array, move array elements to fill the hole. +3. If the list is now empty, remove the transaction list file. Otherwise write the updated list to the file. + +### Key creation process in the core + +Let _A_ be the application key identifier. + +1. Call the driver's `"allocate_key"` entry point, obtaining the driver key identifier _D_ chosen by the driver. +2. Add _A_ [to the transaction list file](#transaction-list-file-manipulation). +3. Create the key file _A_ in the internal storage. Note that this is done at a different time from what happens when creating a transparent key or a key in a stateless secure element: in those cases, creating the key file happens after the actual creation of the key material. +4. Call the secure element's key creation entry point. +5. Remove _A_ [from the transaction list file](#transaction-list-file-manipulation). + +If any step fails: + +* If the secure element's key creation entry point has been called and succeeded, call the secure element's destroy entry point. +* If the key file has been created in the internal storage, remove it. +* Remove the key from the transaction list. + +Note that this process is identical to key destruction, except that the key is already in the transaction list. + +### Key destruction process in the core + +Let _A_ be the application key identifier. + +We assume that the key is loaded in a key slot in memory: the core needs to know the key's location in order to determine whether the key is in a stateful secure element, and if so to know the driver key identifier. A possible optimization would be to load only that information in local variables, without occupying a key store; this has the advantage that key destruction works even if the key store is full. + +1. Add _A_ [to the transaction list file](#transaction-list-file-manipulation). +2. Call the secure element's `"destroy_key"` entry point. +3. Remove the key file _A_ from the internal storage. +4. Remove _A_ [from the transaction list file](#transaction-list-file-manipulation). +5. Free the corresponding key slot in memory. + +If any step fails, remember the error but continue the process, to destroy the resources associated with the key as much as is practical. + +### Transaction recovery + +For each key _A_ in the transaction list file, if the file _A_ exists in the internal storage: + +1. Load the key into a key slot in memory (to get its location and the driver key identifier, although we could get the location from the transaction list). +2. Call the secure element's `"destroy_key"` entry point. +3. Remove the key file _A_ from the internal storage. +4. Remove _A_ [from the transaction list file](#transaction-list-file-manipulation). +5. Free the corresponding key slot in memory. + +The transaction list file can be processed in any order. + +It is correct to update the transaction list after recovering each key, or to only delete the transaction list file once the recovery is over. + +### Concrete format of the transaction list file + +The transaction list file contains a [fixed header](#transaction-list-header-format) followed by a list of [fixed-size elements](#transaction-list-element-format). + +The file uid is `PSA_CRYPTO_ITS_TRANSACTION_LIST_UID` = 0xffffff53. + +#### Transaction list header format + +* Version (2 bytes): 0x0003. (Chosen to differ from the first two bytes of a [dynamic secure element transaction file](#dynamic-secure-element-transaction-file), to reduce the risk of a mix-up.) +* Key name size (2 bytes): `sizeof(psa_storage_uid_t)`. Storing this size avoids reading bad data if Mbed TLS is upgraded to a different integration that names keys differently. + +#### Transaction list element format + +In practice, there will rarely be more than one active transaction at a time, so the size of an element is not critical for efficiency. Therefore, in addition to the key identifier which is required, we add some potentially useful information in case it becomes useful later. We do not put the driver key identifier because its size is not a constant. + +* Key id: `sizeof(psa_storage_uid_t)` bytes. +* Key lifetime: 4 bytes (`sizeof(psa_key_lifetime_t)`). Currently unused during recovery. +* Operation type: 1 byte. Currently unused during recovery. + * 0: destroy key. + * 1: import key. + * 2: generate key. + * 3: derive key. + * 4: import key. +* Padding: 3 bytes. Reserved for future use. Currently unused during recovery. + +## Testing key management in secure elements + +### Instrumentation for checking the storage invariant + +#### Test hook locations + +When `MBEDTLS_TEST_HOOKS` is enabled, each call to `psa_its_set()` or `psa_its_remove()` also calls a test hook, passing the file UID as an argument to the hook. + +When a stateful secure element driver is present in the build, we use this hook to verify that the storage respects the [storage invariant](#chosen-storage-invariant). In addition, if there is some information about key ongoing operation (set explicitly by the test function as a global variable in the test framework), the hook tests that the content of the storage is compatible with the ongoing operation. + +#### Test hook behavior + +The storage invariant check cannot check all keys in storage, and does not need to (for example, it would be pointless to check anything about transparent keys). It checks the following keys: + +* When invoked from the test hook on a key file: on that key. +* When invoked from the test hook on the transaction file: on all the keys listed in the transaction file. +* When invoked from a test secure element: on the specified key. + +#### Test hook extra data + +Some tests set global variables to indicate which persistent keys they manipulate. We instrument at least some of these tests to also indicate what operation is in progress on the key. See the GitHub issues or the source code for details. + +### Testing of transaction recovery + +When no secure element driver is present in the build, the presence of a transaction list file during initialization is an error. + +#### Recovery testing process + +When the stateful test secure element driver is present in the build, we run test cases on a representative selection of states of the internal storage and the test secure element. Each test case for transaction recovery has the following form: + +1. Create the initial state: + * Create a transaction list file with a certain content. + * Create key files that we want to have in the test. + * Call the secure element test driver to create keys without going throught the PSA API. +2. Call `psa_crypto_init()`. Expect success if the initial state satisfies the [storage invariant](#chosen-storage-invariant) and failure otherwise. +3. On success, check that the expected keys exist, and that keys that are expected to have been destroyed by recovery do not exist. +4. Clean up the storage and the secure element test driver's state. + +#### States to test recovery on + +For a given key located in a secure element, the following combination of states are possible: + +* Key file: present, absent. +* Key in secure element: present, absent. +* Key in the transaction file: no, creation (import), destruction. + +We test all $2 \times 2 \times 3 = 12$ possibilities, each in its own test case. In each case, call the test function that checks the storage invariant and check that its result is as expected. Then, if the storage invariant is met, follow the [recovery testing process](#recovery-testing-process). + +In addition, have at least one positive test case for each creation method other than import, to ensure that we don't reject a valid value. + +Note: testing of a damaged filesystem (including a filesystem that doesn't meet the invariant) is out of scope of the present document. diff --git a/tf-psa-crypto/docs/architecture/psa-thread-safety/key-slot-state-transitions.png b/tf-psa-crypto/docs/architecture/psa-thread-safety/key-slot-state-transitions.png new file mode 100644 index 0000000000..08e4cc080e Binary files /dev/null and b/tf-psa-crypto/docs/architecture/psa-thread-safety/key-slot-state-transitions.png differ diff --git a/tf-psa-crypto/docs/architecture/psa-thread-safety/psa-thread-safety.md b/tf-psa-crypto/docs/architecture/psa-thread-safety/psa-thread-safety.md new file mode 100644 index 0000000000..edb94c56ba --- /dev/null +++ b/tf-psa-crypto/docs/architecture/psa-thread-safety/psa-thread-safety.md @@ -0,0 +1,367 @@ +# Thread-safety of the PSA subsystem + +Currently, PSA Crypto API calls in Mbed TLS releases are not thread-safe. + +As of Mbed TLS 3.6, an MVP for making the [PSA Crypto key management API](https://arm-software.github.io/psa-api/crypto/1.1/api/keys/management.html) and [`psa_crypto_init`](https://arm-software.github.io/psa-api/crypto/1.1/api/library/library.html#c.psa_crypto_init) thread-safe has been implemented. Implementations which only ever call PSA functions from a single thread are not affected by this new feature. + +Summary of recent work: + +- Key Store: + - Slot states are described in the [Key slot states](#key-slot-states) section. They guarantee safe concurrent access to slot contents. + - Key slots are protected by a global mutex, as described in [Key store consistency and abstraction function](#key-store-consistency-and-abstraction-function). + - Key destruction strategy abiding by [Key destruction guarantees](#key-destruction-guarantees), with an implementation discussed in [Key destruction implementation](#key-destruction-implementation). +- `global_data` variables in `psa_crypto.c` and `psa_crypto_slot_management.c` are now protected by mutexes, as described in the [Global data](#global-data) section. +- The testing system has now been made thread-safe. Tests can now spin up multiple threads, see [Thread-safe testing](#thread-safe-testing) for details. +- Some multithreaded testing of the key management API has been added, this is outlined in [Testing-and-analysis](#testing-and-analysis). +- The solution uses the pre-existing `MBEDTLS_THREADING_C` threading abstraction. +- The core makes no additional guarantees for drivers. See [Driver policy](#driver-policy) for details. + +The other functions in the PSA Crypto API are planned to be made thread-safe in future, but currently we are not testing this. + +## Overview of the document + +* The [Guarantees](#guarantees) section describes the properties that are followed when PSA functions are invoked by multiple threads. +* The [Usage guide](#usage-guide) section gives guidance on initializing, using and freeing PSA when using multiple threads. +* The [Current strategy](#current-strategy) section describes how thread-safety of key management and `global_data` is achieved. +* The [Testing and analysis](#testing-and-analysis) section discusses the state of our testing, as well as how this testing will be extended in future. +* The [Future work](#future-work) section outlines our long-term goals for thread-safety; it also analyses how we might go about achieving these goals. + +## Definitions + +*Concurrent calls* + +The PSA specification defines concurrent calls as: "In some environments, an application can make calls to the Crypto API in separate threads. In such an environment, concurrent calls are two or more calls to the API whose execution can overlap in time." (See PSA documentation [here](https://arm-software.github.io/psa-api/crypto/1.1/overview/conventions.html#concurrent-calls).) + +*Thread-safety* + +In general, a system is thread-safe if any valid set of concurrent calls is handled as if the effect and return code of every call is equivalent to some sequential ordering. We implement a weaker notion of thread-safety, we only guarantee thread-safety in the circumstances described in the [PSA Concurrent calling conventions](#psa-concurrent-calling-conventions) section. + +## Guarantees + +### Correctness out of the box + +Building with `MBEDTLS_PSA_CRYPTO_C` and `MBEDTLS_THREADING_C` gives code which is correct; there are no race-conditions, deadlocks or livelocks when concurrently calling any set of PSA key management functions once `psa_crypto_init` has been called (see the [Initialization](#initialization) section for details on how to correctly initialize the PSA subsystem when using multiple threads). + +We do not test or support calling other PSA API functions concurrently. + +There is no busy-waiting in our implementation, every API call completes in a finite number of steps regardless of the locking policy of the underlying mutexes. + +When only considering key management functions: Mbed TLS 3.6 abides by the minimum expectation for concurrent calls set by the PSA specification (see [PSA Concurrent calling conventions](#psa-concurrent-calling-conventions)). + +#### PSA Concurrent calling conventions + +These are the conventions which are planned to be added to the PSA 1.2 specification, Mbed TLS 3.6 abides by these when only considering [key management functions](https://arm-software.github.io/psa-api/crypto/1.1/api/keys/management.html): + +> The result of two or more concurrent calls must be consistent with the same set of calls being executed sequentially in some order, provided that the calls obey the following constraints: +> +> * There is no overlap between an output parameter of one call and an input or output parameter of another call. Overlap between input parameters is permitted. +> +> * A call to `psa_destroy_key()` must not overlap with a concurrent call to any of the following functions: +> - Any call where the same key identifier is a parameter to the call. +> - Any call in a multi-part operation, where the same key identifier was used as a parameter to a previous step in the multi-part operation. +> +> * Concurrent calls must not use the same operation object. +> +> If any of these constraints are violated, the behaviour is undefined. +> +> The consistency requirement does not apply to errors that arise from resource failures or limitations. For example, errors resulting from resource exhaustion can arise in concurrent execution that do not arise in sequential execution. +> +> As an example of this rule: suppose two calls are executed concurrently which both attempt to create a new key with the same key identifier that is not already in the key store. Then: +> * If one call returns `PSA_ERROR_ALREADY_EXISTS`, then the other call must succeed. +> * If one of the calls succeeds, then the other must fail: either with `PSA_ERROR_ALREADY_EXISTS` or some other error status. +> * Both calls can fail with error codes that are not `PSA_ERROR_ALREADY_EXISTS`. +> +> If the application concurrently modifies an input parameter while a function call is in progress, the behaviour is undefined. + +### Backwards compatibility + +Code which was working prior to Mbed TLS 3.6 will still work. Implementations which only ever call PSA functions from a single thread, or which protect all PSA calls using a mutex, are not affected by this new feature. If an application previously worked with a 3.X version, it will still work on version 3.6. + +### Supported threading implementations + +Currently, the only threading library with support shipped in the code base is pthread (enabled by `MBEDTLS_THREADING_PTHREAD`). The only concurrency primitives we use are mutexes, see [Condition variables](#condition-variables) for discussion about implementing new primitives in future major releases. + +Users can add support to any platform which has mutexes using the Mbed TLS platform abstraction layer (see `include/mbedtls/threading.h` for details). + +We intend to ship support for other platforms including Windows in future releases. + +### Key destruction guarantees + +Much like all other API calls, `psa_destroy_key` does not block indefinitely, and when `psa_destroy_key` returns: + +1. The key identifier does not exist. This is a functional requirement for persistent keys: any thread can immediately create a new key with the same identifier. +2. The resources from the key have been freed. This allows threads to create similar keys immediately after destruction, regardless of resources. + +When `psa_destroy_key` is called on a key that is in use, guarantee 2 may be violated. This is consistent with the PSA specification requirements, as destruction of a key in use is undefined. + +In future versions we aim to enforce stronger requirements for key destruction, see [Long term key destruction requirements](#long-term-key-destruction-requirements) for details. + +### Driver policy + +The core makes no additional guarantees for drivers. Driver entry points may be called concurrently from multiple threads. Threads can concurrently call entry points using the same key, there is also no protection from destroying a key which is in use. + +### Random number generators + +The PSA RNG can be accessed both from various PSA functions, and from application code via `mbedtls_psa_get_random`. + +When using the built-in RNG implementations, i.e. when `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is disabled, querying the RNG is thread-safe (`mbedtls_psa_random_init` and `mbedtls_psa_random_seed` are only thread-safe when called while holding `mbedtls_threading_psa_rngdata_mutex`. `mbedtls_psa_random_free` is not thread-safe). + +When `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is enabled, it is down to the external implementation to ensure thread-safety, should threading be enabled. + +## Usage guide + +### Initialization + +The PSA subsystem is initialized via a call to [`psa_crypto_init`](https://arm-software.github.io/psa-api/crypto/1.1/api/library/library.html#c.psa_crypto_init). This is a thread-safe function, and multiple calls to `psa_crypto_init` are explicitly allowed. It is valid to have multiple threads each calling `psa_crypto_init` followed by a call to any PSA key management function (if the init succeeds). + +### General usage + +Once initialized, threads can use any PSA function if there is no overlap between their calls. All threads share the same set of keys, as soon as one thread returns from creating/loading a key via a key management API call the key can be used by any thread. If multiple threads attempt to load the same persistent key, with the same key identifier, only one thread can succeed - the others will return `PSA_ERROR_ALREADY_EXISTS`. + +Applications may need careful handling of resource management errors. As explained in ([PSA Concurrent calling conventions](#psa-concurrent-calling-conventions)), operations in progress can have memory related side effects. It is possible for a lack of resources to cause errors which do not arise in sequential execution. For example, multiple threads attempting to load the same persistent key can lead to some threads returning `PSA_ERROR_INSUFFICIENT_MEMORY` if the key is not currently in the key store - while trying to load a persistent key into the key store a thread temporarily reserves a free key slot. + +If a mutex operation fails, which only happens if the mutex implementation fails, the error code `PSA_ERROR_SERVICE_FAILURE` will be returned. If this code is returned, execution of the PSA subsystem must be stopped. All functions which have internal mutex locks and unlocks (except for when the lock/unlock occurs in a function that has no return value) will return with this error code in this situation. + +### Freeing + +There is no thread-safe way to free all PSA resources. This is because any such operation would need to wait for all other threads to complete their tasks before wiping resources. + +`mbedtls_psa_crypto_free` must only be called by a single thread once all threads have completed their operations. + +## Current strategy + +This section describes how we have implemented thread-safety. There is discussion of: techniques, internal properties for enforcing thread-safe access, how the system stays consistent and our abstraction model. + +### Protected resources + +#### Global data + +We have added a mutex `mbedtls_threading_psa_globaldata_mutex` defined in `include/mbedtls/threading.h`, which is used to make `psa_crypto_init` thread-safe. + +There are two `psa_global_data_t` structs, each with a single instance `global_data`: + +* The struct in `library/psa_crypto.c` is protected by `mbedtls_threading_psa_globaldata_mutex`. The RNG fields within this struct are not protected by this mutex, and are not always thread-safe (see [Random number generators](#random-number-generators)). +* The struct in `library/psa_crypto_slot_management.c` has two fields: `key_slots` is protected as described in [Key slots](#key-slots), `key_slots_initialized` is protected by the global data mutex. + +#### Mutex usage + +A deadlock would occur if a thread attempts to lock a mutex while already holding it. Functions which need to be called while holding the global mutex have documentation to say this. + +To avoid performance degradation, functions must hold mutexes for as short a time as possible. In particular, they must not start expensive operations (eg. doing cryptography) while holding the mutex. + +#### Key slots + + +Keys are stored internally in a global array of key slots known as the "key store", defined in `library/psa_slot_management.c`. + +##### Key slot states + +Each key slot has a state variable and a `registered_readers` counter. These two variables dictate whether an operation can access a slot, and in what way the slot can be used. + +There are four possible states for a key slot: + +* `PSA_SLOT_EMPTY`: no thread is currently accessing the slot, and no information is stored in the slot. Any thread is able to change the slot's state to `PSA_SLOT_FILLING` and begin to load data into the slot. +* `PSA_SLOT_FILLING`: one thread is currently loading or creating material to fill the slot, this thread is responsible for the next state transition. Other threads cannot read the contents of a slot which is in this state. +* `PSA_SLOT_FULL`: the slot contains a key, and any thread is able to use the key after registering as a reader, increasing `registered_readers` by 1. +* `PSA_SLOT_PENDING_DELETION`: the key within the slot has been destroyed or marked for destruction, but at least one thread is still registered as a reader (`registered_readers > 0`). No thread can register to read this slot. The slot must not be wiped until the last reader unregisters. It is during the last unregister that the contents of the slot are wiped, and the slot's state is set to `PSA_SLOT_EMPTY`. + +###### Key slot state transition diagram +![](key-slot-state-transitions.png) + +In the state transition diagram above, an arrow between two states `q1` and `q2` with label `f` indicates that if the state of a slot is `q1` immediately before `f`'s linearization point, it may be `q2` immediately after `f`'s linearization point. Internal functions have italicized labels. The `PSA_SLOT_PENDING_DELETION -> PSA_SLOT_EMPTY` transition can be done by any function which calls `psa_unregister_read`. + +The state transition diagram can be generated in https://app.diagrams.net/ via this [url](https://viewer.diagrams.net/?tags=%7B%7D&highlight=0000ff&edit=_blank&layers=1&nav=1#R3Vxbd5s4EP4t%2B%2BDH5CBxf6zrJJvW7aYn7W7dFx9qZFstBg7gW379CnMxkoUtY%2BGQ%2BiVISCPQjD59mhnSU98vNg%2BRE84%2FBS7yelBxNz110IMQAEsnf9KabVZjmHnFLMJu3mhf8YxfUF6p5LVL7KKYapgEgZfgkK6cBL6PJglV50RRsKabTQOPHjV0Zuig4nnieIe1%2F2E3mWe1FjT39X8jPJsXIwPDzu4snKJx%2Fibx3HGDdaVKveup76MgSLKrxeY98tLJK%2BYl63dfc7d8sAj5iUiHH%2BBlOP338cP6i%2B37%2Ff7oV%2Fjr442aSVk53jJ%2F4R40PCKv7%2BIVuZyll%2FffhsOimsiv3OE0njvxOEKOi6K4uPszYtuzUnbzk2yLSScPTvRLCv31HCfoOXQm6Z01MbF0hGThkRIgl04cZkqf4g1yS1HVScnnaYWiBG0qVfkkPaBggZJoS5rkdzUrV1hhsUpeXlf0n1fNK6ov6pzc4mal5L1SyEWulzN0BABHSeyM%2Be671NpJaeI5cYwn9ERFwdJ30xkaKKREJifafs9v7QqjamGwqbYbbIvSBidlJ3I9qtTvu6SFoketNuJgGU3QabtMnGiGkiPttKwdcqlVfKjbiu50ju6Kugh5ToJX9NrnKTQf4SnA5M1qTUc3GJvI3jvvVV2rrCDTvrUrP4sSq6mM2GyaDsTurK2chAsMENaiBC7WcBg746UfoRmOExTtEKCy2HH9UieaGzo%2Fya5BL2wPz%2FzUmInloIhUpOsXE1h%2Bl99YYNdNZfQjFOMX5%2BdOXmpzYToLu3nR%2Bz19wLXC48uMRYpyc8lHofCbhyDKLVRMm1LZDbzMwAoxgOkSTKcxakfpIjvD3aenr6O3CfOdQ3lbOsrneK1U8BocxetyXygLo2qhZl9ojvJQEOVBt1CetpwDNBYG%2BRObRcuoXvDSU6g%2BdbA3%2Fo224wkB9QQH%2FlvD9WJhdRHXc8mQEsr2bw%2FkDzf2%2B8fh8PHzQ6exWjVeGas1kb3xrFPTX3%2FcsenVlaSLKOnp7vNgZ%2B6CehrcDe%2B%2BPv7z%2BW3qqHOkx2yL84ifUZudhZtznsKJdYrzwE5xHqiQzc%2FSoAnI2VTTDXoX1DXj1gS6CS1TJwWVES9KiIDBMCvtuozIEkEMLkciZAVFKzSeRgjtuFLsBQmfJwkCDXeYmExAwuViXBw6OWpnOVuBC12kbKUY7VosDfD4hnyYvNWbHA6zXq96POyWEzCFSkUpoNIgqEaDGkhdewVWqpZiNgNLTWHAkti6yphk237B5oA5xT6O5wLHyjcGXOVSvRi5bogVabZJQ5cqx0ItrtQrABmPkzO6nCzJRuqWFOx6YQ1xN1lzRBMNa6idQjStiNmWMdyGHi%2FdYASxB4sawCI24GwrzfLlWf%2FANo2NpqIcfy7ItAcn2mvWMfnkInvipotn0NcmAD9MQu8FLR%2Fxs%2F7uaSN2nq1hpyejMpew0pqwTzNKKjYkMZKx47tjL5j8Lvn2%2BPtFA6VyJ14Q7wj8Wb3CJbHaaq%2BDwf8wel7iuIxdDqgWvZou5Oe5ZJr0Q%2F1ae5zKS6mQQtarG5SgT6PCztuN5GiCG1u3IjnQhJSV6HrDjQ3UOdauxMRV3gmRi1UuipMo2F6OcXLwtLMQVy5jCS4IzTLoM2CxDC403xuaTdktQByXicj32nKJ%2Bym0Oh8X28e3bnltVYbX6k1D1arJOBsEibssi6t3NDR1w3YBeI4uLinUymYc9ZJwBxRujjY9CNzZuUqSjLAnlIarFj2hon4DvdPwY4Cm8MOkyhjtJUByra547orZHXCpzgKKtPSXFFCKrpKJDO3mbCP9ha%2FXK2VWn4aGJjDUHE50QTjp2Gmtxkt3NpxAhs0Y7WXe8c0O1tKZhr42eZ61NQ4PqdPbdV8dX%2FYywsvlF05yIRGorwSJPKrNaFJ6iKaxX6oryMTEGxoHSFTNvIWWpWtQszUbqpbKyqVCy1AIts6NnpC3qY4CbPohTEW9NaFS%2FtTjbwTso8IAOEeY3vzJ2gnKcLP23%2FKnMcdBQQJgKrpFc0hJFLKNbJwnvNwMp3BsWbMvqx%2F3Hye%2BH3I%2FjJHDGanEmkZf47XGGEWzFruViqMyOTI667YSxmX9hCNNHmPk2pwQYUxxBi%2FCIEsRPMtPP0M%2BipykgYM%2FCM%2BPJaT00kURXu3yfsbBMgmX1DOfn1X9GlB5FB0kIKWuAe65%2BGLvHSX0almMsLMJDCeyCeScfv6wT%2FdEAyKimUz7YFkRebtSbpNNu7IPcs6F8zEZQaIh4L0gqUvww0j7vh7F%2FW9ujL7iR%2FfmYWy1QF0KOy2JxzmWSicnvP4nF93KumPJi9n4UMmQFxOKWea550bW3W9qcrPiuCZdz4yaJ4x1gVwcXb8SyAWwDTlsQmUijIxPogmYkeL%2B3%2BJkzff%2FXEi9%2Bx8%3D). +##### Key slot access primitives + +The state of a key slot is updated via the internal function `psa_key_slot_state_transition`. To change the state of `slot` from `expected_state` to `new_state`, when `new_state` is not `PSA_SLOT_EMPTY`, one must call `psa_key_slot_state_transition(slot, expected_state, new_state)`; if the state was not `expected_state` then `PSA_ERROR_CORRUPTION_DETECTED` is returned. The sole reason for having an expected state parameter here is to help guarantee that our functions work as expected, this error code cannot occur without an internal coding error. + +Changing a slot's state to `PSA_SLOT_EMPTY` is done via `psa_wipe_key_slot`, this function wipes the entirety of the key slot. + +The reader count of a slot is incremented via `psa_register_read`, and decremented via `psa_unregister_read`. Library functions register to read a slot via the `psa_get_and_lock_key_slot_X` functions, read from the slot, then call `psa_unregister_read` to make known that they have finished reading the slot's contents. + +##### Key store consistency and abstraction function + +The key store is protected by a single global mutex `mbedtls_threading_key_slot_mutex`. + +We maintain the consistency of the key store by ensuring that all reads and writes to `slot->state` and `slot->registered_readers` are performed under `mbedtls_threading_key_slot_mutex`. All the access primitives described above must be called while the mutex is held; there is a convenience function `psa_unregister_read_under_mutex` which wraps a call to `psa_unregister_read` in a mutex lock/unlock pair. + +A thread can only traverse the key store while holding `mbedtls_threading_key_slot_mutex`, the set of keys within the key store which the thread holding the mutex can access is equivalent to the set: + + {mbedtls_svc_key_id_t k : (\exists slot := &global_data.key_slots[i]) [ + (slot->state == PSA_SLOT_FULL) && + (slot->attr.id == k)]} + +The union of this set and the set of persistent keys not currently loaded into slots is our abstraction function for the key store, any key not in this union does not currently exist as far as the code is concerned (even if the key is in a slot which has a `PSA_SLOT_FILLING` or `PSA_SLOT_PENDING_DELETION` state). Attempting to start using any key which is not a member of the union will result in a `PSA_ERROR_INVALID_HANDLE` error code. + +##### Locking and unlocking the mutex + +If a lock or unlock operation fails and this is the first failure within a function, the function will return `PSA_ERROR_SERVICE_FAILURE`. If a lock or unlock operation fails after a different failure has been identified, the status code is not overwritten. + +We have defined a set of macros in `library/psa_crypto_core.h` to capture the common pattern of (un)locking the mutex and returning or jumping to an exit label upon failure. + +##### Key creation and loading + +To load a new key into a slot, the following internal utility functions are used: + +* `psa_reserve_free_key_slot` - This function, which must be called under `mbedtls_threading_key_slot_mutex`, iterates through the key store to find a slot whose state is `PSA_SLOT_EMPTY`. If found, it reserves the slot by setting its state to `PSA_SLOT_FILLING`. If not found, it will see if there are any persistent keys loaded which do not have any readers, if there are it will kick one such key out of the key store. +* `psa_start_key_creation` - This function wraps around `psa_reserve_free_key_slot`, if a slot has been found then the slot id is set. This second step is not done under the mutex, at this point the calling thread has exclusive access to the slot. +* `psa_finish_key_creation` - After the contents of the key have been loaded (again this loading is not done under the mutex), the thread calls `psa_finish_key_creation`. This function takes the mutex, checks that the key does not exist in the key store (this check cannot be done before this stage), sets the slot's state to `PSA_SLOT_FULL` and releases the mutex. Upon success, any thread is immediately able to use the new key. +* `psa_fail_key_creation` - If there is a failure at any point in the key creation stage, this clean-up function takes the mutex, wipes the slot, and releases the mutex. Immediately after this unlock, any thread can start to use the slot for another key load. + +##### Re-loading persistent keys + +As described above, persistent keys can be kicked out of the key slot array provided they are not currently being used (`registered_readers == 0`). When attempting to use a persistent key that has been kicked out of a slot, the call to `psa_get_and_lock_key_slot` will see that the key is not in a slot, call `psa_reserve_free_key_slot` and load the key back into the reserved slot. This entire sequence is done during a single mutex lock, which is necessary for thread-safety (see documentation of `psa_get_and_lock_key_slot`). + +If `psa_reserve_free_key_slot` cannot find a suitable slot, the key cannot be loaded back in. This will lead to a `PSA_ERROR_INSUFFICIENT_MEMORY` error. + +##### Using existing keys + +One-shot operations follow a standard pattern when using an existing key: + +* They call one of the `psa_get_and_lock_key_slot_X` functions, which then finds the key and registers the thread as a reader. +* They operate on the key slot, usually copying the key into a separate buffer to be used by the operation. This step is not performed under the key slot mutex. +* Once finished, they call `psa_unregister_read_under_mutex`. + +Multi-part and restartable operations each have a "setup" function where the key is passed in, these functions follow the above pattern. The key is copied into the `operation` object, and the thread unregisters from reading the key (the operations do not access the key slots again). The copy of the key will not be destroyed during a call to `psa_destroy_key`, the thread running the operation is responsible for deleting its copy in the clean-up. This may need to change to enforce the long term key requirements ([Long term key destruction requirements](#long-term-key-destruction-requirements)). + +##### Key destruction implementation + +The locking strategy here is explained in `library/psa_crypto.c`. The destroying thread (the thread calling `psa_destroy_key`) does not always wipe the key slot. The destroying thread registers to read the key, sets the slot's state to `PSA_SLOT_PENDING_DELETION`, wipes the slot from memory if the key is persistent, and then unregisters from reading the slot. + +`psa_unregister_read` internally calls `psa_wipe_key_slot` if and only if the slot's state is `PSA_SLOT_PENDING_DELETION` and the slot's registered reader counter is equal to 1. This implements a "last one out closes the door" approach. The final thread to unregister from reading a destroyed key will automatically wipe the contents of the slot; no readers remain to reference the slot post deletion, so there cannot be corruption. + +### linearizability of the system + +To satisfy the requirements in [Correctness out of the box](#correctness-out-of-the-box), we require our functions to be "linearizable" (under certain constraints). This means that any (constraint satisfying) set of concurrent calls are performed as if they were executed in some sequential order. + +The standard way of reasoning that this is the case is to identify a "linearization point" for each call, this is a single execution step where the function takes effect (this is usually a step in which the effects of the call become visible to other threads). If every call has a linearization point, the set of calls is equivalent to sequentially performing the calls in order of when their linearization point occurred. + +We only require linearizability to hold in the case where a resource-management error is not returned. In a set of concurrent calls, it is permitted for a call c to fail with a `PSA_ERROR_INSUFFICIENT_MEMORY` return code even if there does not exist a sequential ordering of the calls in which c returns this error. Even if such an error occurs, all calls are still required to be functionally correct. + +To help justify that our system is linearizable, here are the linearization points/planned linearization points of each PSA call : + +* Key creation functions (including `psa_copy_key`) - The linearization point for a successful call is the mutex unlock within `psa_finish_key_creation`; it is at this point that the key becomes visible to other threads. The linearization point for a failed call is the closest mutex unlock after the failure is first identified. +* `psa_destroy_key` - The linearization point for a successful destruction is the mutex unlock, the slot is now in the state `PSA_SLOT_PENDING_DELETION` meaning that the key has been destroyed. For failures, the linearization point is the same. +* `psa_purge_key`, `psa_close_key` - The linearization point is the mutex unlock after wiping the slot for a success, or unregistering for a failure. +* One shot operations - The linearization point is the final unlock of the mutex within `psa_get_and_lock_key_slot`, as that is the point in which it is decided whether or not the key exists. +* Multi-part operations - The linearization point of the key input function is the final unlock of the mutex within `psa_get_and_lock_key_slot`. All other steps have no non resource-related side effects (except for key derivation, covered in the key creation functions). + +Please note that one shot operations and multi-part operations are not yet considered thread-safe, as we have not yet tested whether they rely on unprotected global resources. The key slot access in these operations is thread-safe. + +## Testing and analysis + +### Thread-safe testing + +It is now possible for individual tests to spin up multiple threads. This work has made the global variables used in tests thread-safe. If multiple threads fail a test assert, the first failure will be reported with correct line numbers. + +Although the `step` feature used in some tests is thread-safe, it may produce unexpected results for multi-threaded tests. `mbedtls_test_set_step` or `mbedtls_test_increment_step` calls within threads can happen in any order, thus may not produce the desired result when precise ordering is required. + +### Current state of testing + +Our testing is a work in progress. It is not feasible to run our traditional, single-threaded, tests in such a way that tests concurrency. We need to write new test suites for concurrency testing. + +Our tests currently only run on pthread, we hope to expand this in the future (our API already allows this). + +We run tests using [ThreadSanitizer](https://clang.llvm.org/docs/ThreadSanitizer.html) to detect data races. We test the key store, and test that our key slot state system is enforced. We also test the thread-safety of `psa_crypto_init`. + +Currently, not every API call is tested, we also cannot feasibly test every combination of concurrent API calls. API calls can in general be split into a few categories, each category calling the same internal key management functions in the same order - it is the internal functions that are in charge of locking mutexes and interacting with the key store; we test the thread-safety of these functions. + +Since we do not run every cryptographic operation concurrently, we do not test that operations are free of unexpected global variables. + +### Expanding testing + +Through future work on testing, it would be good to: + +* For every API call, have a test which runs multiple copies of the call simultaneously. +* After implementing other threading platforms, expand the tests to these platforms. +* Have increased testing for kicking persistent keys out of slots. +* Explicitly test that all global variables are protected, for this we would need to cover every operation in a concurrent scenario while running ThreadSanitizer. +* Run tests on more threading implementations, once these implementations are supported. + +### Performance + +Key loading does somewhat run in parallel, deriving the key and copying it key into the slot is not done under any mutex. + +Key destruction is entirely sequential, this is required for persistent keys to stop issues with re-loading keys which cannot otherwise be avoided without changing our approach to thread-safety. + + +## Future work + +### Long term requirements + +As explained previously, we eventually aim to make the entirety of the PSA API thread-safe. This will build on the work that we have already completed. This requires a full suite of testing, see [Expanding testing](#expanding-testing) for details. + +### Long term performance requirements + +Our plan for cryptographic operations is that they are not performed under any global mutex. One-shot operations and multi-part operations will each only hold the global mutex for finding the relevant key in the key slot, and unregistering as a reader after the operation, using their own operation-specific mutexes to guard any shared data that they use. + +We aim to eventually replace some/all of the mutexes with RWLocks, if possible. + +### Long term key destruction requirements + +The [PSA Crypto Key destruction specification](https://arm-software.github.io/psa-api/crypto/1.1/api/keys/management.html#key-destruction) mandates that implementations make a best effort to ensure that the key material cannot be recovered. In the long term, it would be good to guarantee that `psa_destroy_key` wipes all copies of the key material. + +Here are our long term key destruction goals: + +`psa_destroy_key` does not block indefinitely, and when `psa_destroy_key` returns: + +1. The key identifier does not exist. This is a functional requirement for persistent keys: any thread can immediately create a new key with the same identifier. +2. The resources from the key have been freed. This allows threads to create similar keys immediately after destruction, regardless of resources. +4. No copy of the key material exists. Rationale: this is a security requirement. We do not have this requirement yet, but we need to document this as a security weakness, and we would like to satisfy this security requirement in the future. + +#### Condition variables + +It would be ideal to add these to a future major version; we cannot add these as requirements to the default `MBEDTLS_THREADING_C` for backwards compatibility reasons. + +Condition variables would enable us to fulfil the final requirement in [Long term key destruction requirements](#long-term-key-destruction-requirements). Destruction would then work as follows: + + * When a thread calls `psa_destroy_key`, they continue as normal until the `psa_unregister_read` call. + * Instead of calling `psa_unregister_read`, the thread waits until the condition `slot->registered_readers == 1` is true (the destroying thread is the final reader). + * At this point, the destroying thread directly calls `psa_wipe_key_slot`. + +A few changes are needed for this to follow our destruction requirements: + + * Multi-part operations will need to remain registered as readers of their key slot until their copy of the key is destroyed, i.e. at the end of the finish/abort call. + * The functionality where `psa_unregister_read` can wipe the key slot will need to be removed, slot wiping is now only done by the destroying/wiping thread. + +### Protecting operation contexts + +Currently, we rely on the crypto service to ensure that the same operation is not invoked concurrently. This abides by the PSA Crypto API Specification ([PSA Concurrent calling conventions](#psa-concurrent-calling-conventions)). + +Concurrent access to the same operation object can compromise the crypto service. For example, if the operation context has a pointer (depending on the compiler and the platform, the pointer assignment may or may not be atomic). This violates the functional correctness requirement of the crypto service. + +If, in future, we want to protect against this within the library then operations will require a status field protected by a global mutex. On entry, API calls would check the state and return an error if the state is ACTIVE. If the state is INACTIVE, then the call will set the state to ACTIVE, do the operation section and then restore the state to INACTIVE before returning. + +### Future driver work + +A future policy we may wish to enforce for drivers is: + +* By default, each driver only has at most one entry point active at any given time. In other words, each driver has its own exclusive lock. +* Drivers have an optional `"thread_safe"` boolean property. If true, it allows concurrent calls to this driver. +* Even with a thread-safe driver, the core never starts the destruction of a key while there are operations in progress on it, and never performs concurrent calls on the same multipart operation. + +In the non-thread-safe case we have these natural assumptions/requirements: + +1. Drivers don't call the core for any operation for which they provide an entry point. +2. The core doesn't hold the driver mutex between calls to entry points. + +With these, the only way of a deadlock is when there are several drivers with circular dependencies. That is, Driver A makes a call that is dispatched to Driver B; upon executing this call Driver B makes a call that is dispatched to Driver A. For example Driver A does CCM, which calls driver B to do CBC-MAC, which in turn calls Driver A to perform AES. + +Potential ways for resolving this: + +1. Non-thread-safe drivers must not call the core. +2. Provide a new public API that drivers can safely call. +3. Make the dispatch layer public for drivers to call. +4. There is a whitelist of core APIs that drivers can call. Drivers providing entry points to these must not make a call to the core when handling these calls. (Drivers are still allowed to call any core API that can't have a driver entry point.) + +The first is too restrictive, the second and the third would require making it a stable API, and would likely increase the code size for a relatively rare feature. We are choosing the fourth as that is the most viable option. + +**Thread-safe drivers:** + +A driver would be non-thread-safe if the `thread-safe` property is set to true. + +To make re-entrancy in non-thread-safe drivers work, thread-safe drivers must not make a call to the core when handling a call that is on the non-thread-safe driver core API whitelist. + +Thread-safe drivers have fewer guarantees from the core and need to implement more complex logic. We can reasonably expect them to be more flexible in terms of re-entrancy as well. At this point it is hard to see what further guarantees would be useful and feasible. Therefore, we don't provide any further guarantees for now. + +Thread-safe drivers must not make any assumption about the operation of the core beyond what is discussed here. diff --git a/tf-psa-crypto/docs/driver-only-builds.md b/tf-psa-crypto/docs/driver-only-builds.md new file mode 100644 index 0000000000..24735972eb --- /dev/null +++ b/tf-psa-crypto/docs/driver-only-builds.md @@ -0,0 +1,432 @@ +This document explains how to create builds of Mbed TLS where some +cryptographic mechanisms are provided only by PSA drivers (that is, no +built-in implementation of those algorithms), from a user's perspective. + +This is useful to save code size for people who are using either a hardware +accelerator, or an alternative software implementation that is more +aggressively optimized for code size than the default one in Mbed TLS. + +General considerations +---------------------- + +This document assumes that you already have a working driver. +Otherwise, please see the [PSA driver example and +guide](psa-driver-example-and-guide.md) for information on writing a +driver. + +For each mechanism you want provided only by your driver: + +- Define the corresponding `PSA_WANT` macro in `psa/crypto_config.h` - this + means the algorithm will be available in the PSA Crypto API. +- Define the corresponding `MBEDTLS_PSA_ACCEL` in your build. This could be + defined in `psa/crypto_config.h` or your compiler's command line. This +informs the PSA code that an accelerator is available for this mechanism. +- Undefine / comment out the corresponding `MBEDTLS_xxx_C` macro in + `mbedtls/mbedtls_config.h`. This ensures the built-in implementation is not +included in the build. + +For example, if you want SHA-256 to be provided only by a driver, you'll want +`PSA_WANT_ALG_SHA_256` and `MBEDTLS_PSA_ACCEL_SHA_256` defined, and +`MBEDTLS_SHA256_C` undefined. + +Recall that applications must call `psa_crypto_init()` prior to performing any +cryptographic or key management operation. + +Mechanisms covered +------------------ + +For now, only the following (families of) mechanisms are supported: + +- hashes: SHA-3, SHA-2, SHA-1, MD5, etc. +- elliptic-curve cryptography (ECC): ECDH, ECDSA, EC J-PAKE, ECC key types. +- finite-field Diffie-Hellman: FFDH algorithm, DH key types. +- RSA: PKCS#1 v1.5 and v2.1 signature and encryption algorithms, RSA key types + (for now, only crypto, no X.509 or TLS support). +- AEADs: + - GCM and CCM with AES, ARIA and Camellia key types + - ChachaPoly with ChaCha20 Key type +- Unauthenticated ciphers: + - key types: AES, ARIA, Camellia + - modes: ECB, CBC, CTR, CFB, OFB, XTS + +For each family listed above, all the mentioned alorithms/key types are also +all the mechanisms that exist in PSA API. + +Supported means that when those are provided only by drivers, everything +(including PK, X.509 and TLS) should work in the same way as if the mechanisms +where built-in, except as documented in the "Limitations" sub-sections of the +sections dedicated to each family below. + +Hashes +------ + +It is possible to have all hash operations provided only by a driver. + +More precisely: + +- you can enable `PSA_WANT_ALG_SHA_256` without `MBEDTLS_SHA256_C`, provided + you have `MBEDTLS_PSA_ACCEL_ALG_SHA_256` enabled; +- and similarly for all supported hash algorithms: `MD5`, `RIPEMD160`, + `SHA_1`, `SHA_224`, `SHA_256`, `SHA_384`, `SHA_512`, `SHA3_224`, `SHA3_256`, +`SHA3_384`, `SHA3_512`. + +In such a build, all crypto operations (via the PSA Crypto API, or non-PSA +APIs), as well as X.509 and TLS, will work as usual, except that direct calls +to low-level hash APIs (`mbedtls_sha256()` etc.) are not possible for the +modules that are disabled. + +You need to call `psa_crypto_init()` before any crypto operation that uses +a hash algorithm that is provided only by a driver, as mentioned in [General +considerations](#general-considerations) above. + +If you want to check at compile-time whether a certain hash algorithm is +available in the present build of Mbed TLS, regardless of whether it's +provided by a driver or built-in, you should use `PSA_WANT_ALG_xxx` from +`psa/crypto.h`. + +### HMAC + +In addition to accelerated hash operations, it is also possible to accelerate +HMAC by enabling and accelerating: +- HMAC algorithm and key type, i.e. `[PSA_WANT|MBEDTLS_PSA_ACCEL]_ALG_HMAC` and + `[PSA_WANT|MBEDTLS_PSA_ACCEL]KEY_TYPE_HMAC`. +- Required hash algorithm(s) as explained in [Hashes](#hashes) section. + +In such a build it is possible to disable legacy HMAC support by disabling +`MBEDTLS_MD_C` and still getting crypto operations, X.509 and TLS to work as +usual. Exceptions are: +- As mentioned in [Hashes](#hashes) direct calls to legacy lo-level hash APIs + (`mbedtls_sha256()` etc.) will not be possible for the legacy modules that + are disabled. +- Legacy HMAC support (`mbedtls_md_hmac_xxx()`) won't be possible. +- `MBEDTLS_PKCS[5|7]_C` and `MBEDTLS_HMAC_DRBG_C` since they + depend on the legacy implementation of HMAC. + - disabling HMAC_DRBG_C cause deterministic ECDSA (i.e. + `MBEDTLS_DETERMINISTIC_ECDSA` on the legacy side and + `PSA_WANT_ALG_DETERMINISTIC_ECDSA` on the PSA one) to be not available. + +Elliptic-curve cryptography (ECC) +--------------------------------- + +It is possible to have most ECC operations provided only by a driver: + +- the ECDH, ECDSA and EC J-PAKE algorithms; +- key import, export, and random generation. + +More precisely, if: + +- you have driver support for ECC public and using private keys (that is, +`MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_PUBLIC_KEY` and +`MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_BASIC` are enabled), and +- you have driver support for all ECC curves that are enabled (that is, for + each `PSA_WANT_ECC_xxx` macro enabled, the corresponding +`MBEDTLS_PSA_ACCEL_ECC_xxx` macros is enabled as well); + +then you can: + +- enable `PSA_WANT_ALG_ECDH` without `MBEDTLS_ECDH_C`, provided + `MBEDTLS_PSA_ACCEL_ALG_ECDH` is enabled +- enable `PSA_WANT_ALG_ECDSA` without `MBEDTLS_ECDSA_C`, provided + `MBEDTLS_PSA_ACCEL_ALG_ECDSA` is enabled; +- enable `PSA_WANT_ALG_JPAKE` without `MBEDTLS_ECJPAKE_C`, provided + `MBEDTLS_PSA_ACCEL_ALG_JPAKE` is enabled. + +In addition, if: + +- none of `MBEDTLS_ECDH_C`, `MBEDTLS_ECDSA_C`, `MBEDTLS_ECJPAKE_C` are enabled + (see conditions above), and +- you have driver support for all enabled ECC key pair operations - that is, + for each `PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_xxx` macro enabled, the +corresponding `MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_xxx` macros is also +enabled, + +then you can also disable `MBEDTLS_ECP_C`. However, a small subset of it might +still be included in the build, see limitations sub-section below. + +In addition, if: + +- `MBEDTLS_ECP_C` is fully removed (see limitation sub-section below), +- and support for RSA key types and algorithms is either fully disabled or + fully provided by a driver, +- and support for DH key types and the FFDH algorithm is either disabled or + fully provided by a driver, + +then you can also disable `MBEDTLS_BIGNUM_C`. + +In such builds, all crypto operations via the PSA Crypto API will work as +usual, as well as the PK, X.509 and TLS modules, with the following exceptions: + +- direct calls to APIs from the disabled modules are not possible; +- PK, X.509 and TLS will not support restartable ECC operations (see + limitation sub-section below). + +If you want to check at compile-time whether a certain curve is available in +the present build of Mbed TLS, regardless of whether ECC is provided by a +driver or built-in, you should use `PSA_WANT_ECC_xxx` from + `psa/crypto.h`. + +Note that for externally-provided drivers, the integrator is responsible for +ensuring the appropriate `MBEDTLS_PSA_ACCEL_xxx` macros are defined. However, +for the p256-m driver that's provided with the library, those macros are +automatically defined when enabling `MBEDTLS_PSA_P256M_DRIVER_ENABLED`. + +### Limitations regarding fully removing `ecp.c` + +A limited subset of `ecp.c` will still be automatically re-enabled if any of +the following is enabled: + +- `MBEDTLS_PK_PARSE_EC_COMPRESSED` - support for parsing ECC keys where the + public part is in compressed format; +- `MBEDTLS_PK_PARSE_EC_EXTENDED` - support for parsing ECC keys where the + curve is identified not by name, but by explicit parameters; +- `PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE` - support for deterministic + derivation of an ECC keypair with `psa_key_derivation_output_key()`. + +Note: when any of the above options is enabled, a subset of `ecp.c` will +automatically be included in the build in order to support it. Therefore +you can still disable `MBEDTLS_ECP_C` in `mbedtls_config.h` and this will +result in some code size savings, but not as much as when none of the +above features are enabled. + +We do have plans to support each of these with `ecp.c` fully removed in the +future, however there is no established timeline. If you're interested, please +let us know, so we can take it into consideration in our planning. + +### Limitations regarding restartable / interruptible ECC operations + +At the moment, there is no driver support for interruptible operations +(see `psa_sign_hash_start()` + `psa_sign_hash_complete()` etc.) so as a +consequence these are not supported in builds without `MBEDTLS_ECDSA_C`. + +Similarly, there is no PSA support for interruptible ECDH operations so these +are not supported without `ECDH_C`. See also limitations regarding restartable +operations in [the documentation of +MBEDTLS_ECP_RESTARTABLE](include/psa/crypto_config.h). + +Again, we have plans to support this in the future but not with an established +timeline, please let us know if you're interested. + +### Limitations regarding "mixed" builds (driver and built-in) + +In order for a build to be driver-only (no built-in implementation), all the +requested algorithms, key types (key operations) and curves must be +accelerated (plus a few other restrictions, see "Limitations regarding fully +removing `ecp.c`" above). However, what if you have an accelerator that only +supports some algorithms, some key types (key operations), or some curves, but +want to have more enabled in you build? + +It is possible to have acceleration for only a subset of the requested +algorithms. In this case, the built-in implementation of the accelerated +algorithms will be disabled, provided all the requested curves and key types +that can be used with this algorithm are also declared as accelerated. + +There is very limited support for having acceleration for only a subset of the +requested key type operations. The only configuration that's tested is that of +a driver accelerating `PUBLIC_KEY`, `KEY_PAIR_BASIC`, `KEY_PAIR_IMPORT`, +`KEY_PAIR_EXPORT` but not `KEY_PAIR_GENERATE`. (Note: currently the driver +interface does not support `KEY_PAIR_DERIVE`.) + +There is limited support for having acceleration for only a subset of the +requested curves. In such builds, only the PSA API is currently tested and +working; there are known issues in PK, and X.509 and TLS are untested. + +Finite-field Diffie-Hellman +--------------------------- + +Support is pretty similar to the "Elliptic-curve cryptography (ECC)" section +above. +Key management and usage can be enabled by means of the usual `PSA_WANT` + +`MBEDTLS_PSA_ACCEL` pairs: + +- `[PSA_WANT|MBEDTLS_PSA_ACCEL]_KEY_TYPE_DH_PUBLIC_KEY`; +- `[PSA_WANT|MBEDTLS_PSA_ACCEL]_KEY_TYPE_DH_KEY_PAIR_BASIC`; +- `[PSA_WANT|MBEDTLS_PSA_ACCEL]_KEY_TYPE_DH_KEY_PAIR_IMPORT`; +- `[PSA_WANT|MBEDTLS_PSA_ACCEL]_KEY_TYPE_DH_KEY_PAIR_EXPORT`; +- `[PSA_WANT|MBEDTLS_PSA_ACCEL]_KEY_TYPE_DH_KEY_PAIR_GENERATE`; + +The same holds for the associated algorithm: +`[PSA_WANT|MBEDTLS_PSA_ACCEL]_ALG_FFDH` allow builds accelerating FFDH and +removing builtin support. + +Note that the PSA API only supports FFDH with RFC 7919 groups. +In theory TLS 1.2 allows custom FFDH groups to be used in DHE key exchanges, but +since DHE-RSA and DHE-PSK key exchanges support has been removed from Mbed TLS, +PSA API limitation to RFC 7919 groups is not a problem. +TLS 1.3 is also fine because the protocol itself does not allows custom FFDH +groups. + +RSA +--- + +It is possible for all RSA operations to be provided only by a driver. + +More precisely, if: + +- all the RSA algorithms that are enabled (`PSA_WANT_ALG_RSA_*`) are also + accelerated (`MBEDTLS_PSA_ACCEL_ALG_RSA_*`), +- and all the RSA key types that are enabled (`PSA_WANT_KEY_TYPE_RSA_*`) are + also accelerated (`MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_*`), + +then you can disable `MBEDTLS_RSA_C`, `MBEDTLS_PKCS1_V15` and +`MBEDTLS_PKCS1_V21`, and RSA will still work in PSA Crypto. + +### Limitations on RSA acceleration + +Unlike other mechanisms, for now in configurations with driver-only RSA, only +PSA Crypto works. In particular, PK, X.509 and TLS will _not_ work with +driver-only RSA. + +Currently (early 2024) we don't have plans to extend this support. If you're +interested in wider driver-only support for RSA, please let us know. + +Ciphers (unauthenticated and AEAD) +---------------------------------- + +It is possible to have all ciphers and AEAD operations provided only by a +driver. More precisely, for each desired combination of key type and +algorithm/mode you can: + +- Enable desired PSA key type(s): + - `PSA_WANT_KEY_TYPE_AES`, + - `PSA_WANT_KEY_TYPE_ARIA`, + - `PSA_WANT_KEY_TYPE_CAMELLIA`, + - `PSA_WANT_KEY_TYPE_CHACHA20`, +- Enable desired PSA algorithm(s): + - Unauthenticated ciphers modes: + - `PSA_WANT_ALG_CBC_NO_PADDING`, + - `PSA_WANT_ALG_CBC_PKCS7`, + - `PSA_WANT_ALG_CCM_STAR_NO_TAG`, + - `PSA_WANT_ALG_CFB`, + - `PSA_WANT_ALG_CTR`, + - `PSA_WANT_ALG_ECB_NO_PADDING`, + - `PSA_WANT_ALG_OFB`, + - `PSA_WANT_ALG_STREAM_CIPHER`. + - AEADs: + - `PSA_WANT_ALG_CCM`, + - `PSA_WANT_ALG_GCM`, + - `PSA_WANT_ALG_CHACHA20_POLY1305`. +- Enable `MBEDTLS_PSA_ACCEL_[KEY_TYPE_xxx|ALG_yyy]` symbol(s) which correspond + to the `PSA_WANT_KEY_TYPE_xxx` and `PSA_WANT_ALG_yyy` of the previous steps. +- Disable builtin support of key types: + - `MBEDTLS_AES_C`, + - `MBEDTLS_ARIA_C`, + - `MBEDTLS_CAMELLIA_C`, + - `MBEDTLS_CHACHA20_C`. + and algorithms/modes: + - `MBEDTLS_CBC_C`, + - `MBEDTLS_CFB_C`, + - `MBEDTLS_CTR_C`, + - `MBEDTLS_OFB_C`, + - `MBEDTLS_XTS_C`, + - `MBEDTLS_CCM_C`, + - `MBEDTLS_GCM_C`, + - `MBEDTLS_CHACHAPOLY_C`, + - `MBEDTLS_NULL_CIPHER`. + +Once a key type and related algorithm are accelerated, all the PSA Crypto APIs +will work, as well as X.509 and TLS but some non-PSA APIs will be absent or +have reduced functionality, see [Restrictions](#restrictions) for details. + +### Restrictions + +- If an algorithm other than CCM and GCM (see + ["Partial acceleration for CCM/GCM"](#partial-acceleration-for-ccmgcm) below) + is enabled but not accelerated, then all key types that can be used with it + will need to be built-in. +- If a key type is enabled but not accelerated, then all algorithms that can be + used with it will need to be built-in. + +Some legacy modules can't take advantage of PSA drivers yet, and will either +need to be disabled, or have reduced features when the built-in implementations +of some ciphers are removed: + +- `MBEDTLS_NIST_KW_C` needs built-in AES: it must be disabled when + `MBEDTLS_AES_C` is disabled. +- `MBEDTLS_CMAC_C` needs built-in AES: it must be disabled when + `MBEDTLS_AES_C` is disabled. (Note: if there is driver support for + CMAC and all compatible key types, then `PSA_WANT_ALG_CMAC` can be enabled + without `MBEDTLS_CMAC_C` and CMAC will be usable with `psa_max_xxx` APIs.) +- `MBEDTLS_CIPHER_C`: the `mbedtls_cipher_xxx()` APIs will only work with + ciphers that are built-in - that is, both the underlying cipher + (eg `MBEDTLS_AES_C`) and the mode (eg `MBEDTLS_CIPHER_MODE_CBC` or + `MBEDTLS_GCM_C`). +- `MBEDTLS_PKCS5_C`: encryption/decryption (PBES2, PBE) will only work with + ciphers that are built-in. +- PEM decryption will only work with ciphers that are built-in. +- PK parse will only be able to parse encrypted keys using built-in ciphers. + +Note that if you also disable `MBEDTLS_CIPHER_C`, there will be additional +restrictions, see [Disabling `MBEDTLS_CIPHER_C`](#disabling-mbedtls_cipher_c). + +### Legacy <-> PSA matching + +Note that the relationship between legacy (i.e. `MBEDTLS_xxx_C`) and PSA +(i.e. `PSA_WANT_xxx`) symbols is not always 1:1. For example: + +- ECB mode is always enabled in the legacy configuration for each key type that + allows it (AES, ARIA, Camellia), whereas it must be explicitly enabled + in PSA with `PSA_WANT_ALG_ECB_NO_PADDING`. +- In the legacy API, `MBEDTLS_CHACHA20_C` enables the ChaCha20 stream cipher, and + enabling `MBEDTLS_CHACHAPOLY_C` also enables the ChaCha20-Poly1305 AEAD. In the + PSA API, you need to enable `PSA_KEY_TYPE_CHACHA20` for both, plus + `PSA_ALG_STREAM_CIPHER` or `PSA_ALG_CHACHA20_POLY1305` as desired. +- The legacy symbol `MBEDTLS_CCM_C` adds support for both cipher and AEAD, + whereas in PSA there are 2 different symbols: `PSA_WANT_ALG_CCM_STAR_NO_TAG` + and `PSA_WANT_ALG_CCM`, respectively. + +### Partial acceleration for CCM/GCM + +[This section depends on #8598 so it might be updated while that PR progresses.] + +In case legacy CCM/GCM algorithms are enabled, it is still possible to benefit +from PSA acceleration of the underlying block cipher by enabling support for +ECB mode (`PSA_WANT_ALG_ECB_NO_PADDING` + `MBEDTLS_PSA_ACCEL_ALG_ECB_NO_PADDING`) +together with desired key type(s) (`PSA_WANT_KEY_TYPE_[AES|ARIA|CAMELLIA]` + +`MBEDTLS_PSA_ACCEL_KEY_TYPE_[AES|ARIA|CAMELLIA]`). + +In such configurations it is possible to: + +- Use CCM and GCM via the PSA Crypto APIs. +- Use CCM and GCM via legacy functions `mbedtls_[ccm|gcm]_xxx()` (but not the + legacy functions `mbedtls_cipher_xxx()`). +- Disable legacy key types (`MBEDTLS_[AES|ARIA|CAMELLIA]_C`) if there is no + other dependency requiring them. + +ChaChaPoly has no such feature, so it requires full acceleration (key type + +algorithm) in order to work with a driver. + +### CTR-DRBG + +The legacy CTR-DRBG module (enabled by `MBEDTLS_CTR_DRBG_C`) can also benefit +from PSA acceleration if both of the following conditions are met: + +- The legacy AES module (`MBEDTLS_AES_C`) is not enabled and +- AES is supported on the PSA side together with ECB mode, i.e. + `PSA_WANT_KEY_TYPE_AES` + `PSA_WANT_ALG_ECB_NO_PADDING`. + +### Disabling `MBEDTLS_CIPHER_C` + +It is possible to save code size by disabling MBEDTLS_CIPHER_C when all of the +following conditions are met: + +- The application is not using the `mbedtls_cipher_` API. +- In PSA, all unauthenticated (that is, non-AEAD) ciphers are either disabled or + fully accelerated (that is, all compatible key types are accelerated too). +- `MBEDTLS_NIST_KW` is disabled. +- `MBEDTLS_CMAC_C` is disabled. (Note: support for CMAC in PSA can be provided by + a driver.) + +In such a build, everything will work as usual except for the following: + +- Encryption/decryption functions from the PKCS5 and PKCS12 module will not be + available (only key derivation functions). +- Parsing of PKCS5- or PKCS12-encrypted keys in PK parse will fail. + +Note: AEAD ciphers (CCM, GCM, ChachaPoly) do not have a dependency on +MBEDTLS_CIPHER_C even when using the built-in implementations. + +If you also have some ciphers fully accelerated and the built-ins removed, see +[Restrictions](#restrictions) for restrictions related to removing the built-ins. + + + diff --git a/tf-psa-crypto/docs/proposed/psa-conditional-inclusion-c.md b/tf-psa-crypto/docs/proposed/psa-conditional-inclusion-c.md new file mode 100644 index 0000000000..4645430cd5 --- /dev/null +++ b/tf-psa-crypto/docs/proposed/psa-conditional-inclusion-c.md @@ -0,0 +1,241 @@ +Conditional inclusion of cryptographic mechanism through the PSA API in Mbed TLS +================================================================================ + +This document is a proposed interface for deciding at build time which cryptographic mechanisms to include in the PSA Cryptography interface. + +This is currently a proposal for Mbed TLS. It is not currently on track for standardization in PSA. + +## Introduction + +### Purpose of this specification + +The [PSA Cryptography API specification](https://armmbed.github.io/mbed-crypto/psa/#application-programming-interface) specifies the interface between a PSA Cryptography implementation and an application. The interface defines a number of categories of cryptographic algorithms (hashes, MAC, signatures, etc.). In each category, a typical implementation offers many algorithms (e.g. for signatures: RSA-PKCS#1v1.5, RSA-PSS, ECDSA). When building the implementation for a specific use case, it is often desirable to include only a subset of the available cryptographic mechanisms, primarily in order to reduce the code footprint of the compiled system. + +The present document proposes a way for an application using the PSA cryptography interface to declare which mechanisms it requires. + +### Conditional inclusion of legacy cryptography modules + +Mbed TLS offers a way to select which cryptographic mechanisms are included in a build through its configuration file (`mbedtls_config.h`). This mechanism is based on two main sets of symbols: `MBEDTLS_xxx_C` controls the availability of the mechanism to the application, and `MBEDTLS_xxx_ALT` controls the availability of an alternative implementation, so the software implementation is only included if `MBEDTLS_xxx_C` is defined but not `MBEDTLS_xxx_ALT`. + +### PSA evolution + +In the PSA cryptography interface, the **core** (built-in implementations of cryptographic mechanisms) can be augmented with drivers. **Transparent drivers** replace the built-in implementation of a cryptographic mechanism (or, with **fallback**, the built-in implementation is tried if the driver only has partial support for the mechanism). **Opaque drivers** implement cryptographic mechanisms on keys which are stored in a separate domain such as a secure element, for which the core only does key management and dispatch using wrapped key blobs or key identifiers. + +The current model is difficult to adapt to the PSA interface for several reasons. The `MBEDTLS_xxx_ALT` symbols are somewhat inconsistent, and in particular do not work well for asymmetric cryptography. For example, many parts of the ECC code have no `MBEDTLS_xxx_ALT` symbol, so a platform with ECC acceleration that can perform all ECDSA and ECDH operations in the accelerator would still embark the `bignum` module and large parts of the `ecp_curves`, `ecp` and `ecdsa` modules. Also the availability of a transparent driver for a mechanism does not translate directly to `MBEDTLS_xxx` symbols. + +### Requirements + +[Req.interface] The application can declare which cryptographic mechanisms it needs. + +[Req.inclusion] If the application does not require a mechanism, a suitably configured Mbed TLS build must not include it. The granularity of mechanisms must work for typical use cases and has [acceptable limitations](#acceptable-limitations). + +[Req.drivers] If a PSA driver is available in the build, a suitably configured Mbed TLS build must not include the corresponding software code (unless a software fallback is needed). + +[Req.c] The configuration mechanism consists of C preprocessor definitions, and the build does not require tools other than a C compiler. This is necessary to allow building an application and Mbed TLS in development environments that do not allow third-party tools. + +[Req.adaptability] The implementation of the mechanism must be adaptable with future evolution of the PSA cryptography specifications and Mbed TLS. Therefore the interface must remain sufficiently simple and abstract. + +### Acceptable limitations + +[Limitation.matrix] If a mechanism is defined by a combination of algorithms and key types, for example a block cipher mode (CBC, CTR, CFB, …) and a block permutation (AES, CAMELLIA, ARIA, …), there is no requirement to include only specific combinations. + +[Limitation.direction] For mechanisms that have multiple directions (for example encrypt/decrypt, sign/verify), there is no requirement to include only one direction. + +[Limitation.size] There is no requirement to include only support for certain key sizes. + +[Limitation.multipart] Where there are multiple ways to perform an operation, for example single-part and multi-part, there is no mechanism to select only one or a subset of the possible ways. + +## Interface + +### PSA Crypto configuration file + +The PSA Crypto configuration file `psa/crypto_config.h` defines a series of symbols of the form `PSA_WANT_xxx` where `xxx` describes the feature that the symbol enables. The symbols are documented in the section [“PSA Crypto configuration symbols”](#psa-crypto-configuration-symbols) below. +The necessary software implementations of cryptographic algorithms are included based on the content of the PSA Crypto configuration file. For example, the code in `aes.c` is enabled if `psa/crypto_config.h` contains `PSA_WANT_KEY_TYPE_AES`. + +### PSA Crypto configuration symbols + +#### Configuration symbol syntax + +A PSA Crypto configuration symbol is a C preprocessor symbol whose name starts with `PSA_WANT_`. + +* If the symbol is not defined, the corresponding feature is not included. +* If the symbol is defined to a preprocessor expression with the value `1`, the corresponding feature is included. +* If the symbol is defined with a different value, the behavior is currently undefined and reserved for future use. + +#### Configuration symbol usage + +The presence of a symbol `PSA_WANT_xxx` in the Mbed TLS configuration determines whether a feature is available through the PSA API. These symbols should be used in any place that requires conditional compilation based on the availability of a cryptographic mechanism through the PSA API, including: + +* In Mbed TLS test code. +* In Mbed TLS library code, for example in TLS to determine which cipher suites to enable. +* In application code that provides additional features based on cryptographic capabilities, for example additional key parsing and formatting functions, or cipher suite availability for network protocols. + +#### Configuration symbol semantics + +If a feature is not requested for inclusion in the PSA Crypto configuration file, it may still be included in the build, either because the feature has been requested in some other way, or because the library does not support the exclusion of this feature. Mbed TLS should make a best effort to support the exclusion of all features, but in some cases this may be judged too much effort for too little benefit. + +#### Configuration symbols for key types + +For most constant or constructor macros of the form `PSA_KEY_TYPE_xxx`, the symbol **`PSA_WANT_KEY_TYPE_xxx`** indicates that support for this key type is desired. + +As an exception, starting in Mbed TLS 3.5.0, for `KEY_PAIR` types (that is, private keys for asymmetric cryptography), the feature selection is more fine-grained, with an additional suffix: +* `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_BASIC` enables basic support for the key type, and in particular support for operations with a key of that type for enabled algorithms. This is automatically enabled if any of the other `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_yyy` options is enabled. +* `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_IMPORT` enables support for `psa_import_key` to import a key of that type. +* `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_GENERATE` enables support for `psa_generate_key` to randomly generate a key of that type. +* `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_DERIVE` enables support for `psa_key_derivation_output_key` to deterministically derive a key of that type. +* `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_EXPORT` enables support for `psa_export_key` to export a key of that type. + +For asymmetric cryptography, `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_BASIC` determines whether private-key operations are desired, and `PSA_WANT_KEY_TYPE_xxx_PUBLIC_KEY` determines whether public-key operations are desired. `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_BASIC` implicitly enables `PSA_WANT_KEY_TYPE_xxx_PUBLIC_KEY`, as well as support for `psa_export_public_key` on the private key: there is no way to only include private-key operations (which typically saves little code). + +Note: the implementation is always free to include support for more than what was explicitly requested. (For example, as of Mbed TLS 3.5.0, `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_BASIC` implicitly enables import and export support for that key type, but this may not be the case in future versions.) Applications should always request support for all operations they need, rather than rely on them being implicitly enabled by the implementation. The only thing that is documented and guaranteed in the future is as follows: `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_yyy` -> `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_BASIC` -> `PSA_WANT_KEY_TYPE_xxx_PUBLIC_KEY`. + +#### Configuration symbols for elliptic curves + +For elliptic curve key types, only the specified curves are included. To include a curve, include a symbol of the form **`PSA_WANT_ECC_family_size`**. For example: `PSA_WANT_ECC_SECP_R1_256` for secp256r1, `PSA_WANT_ECC_MONTGOMERY_255` for Curve25519. It is an error to require an ECC key type but no curve, and Mbed TLS will reject this at compile time. + +Rationale: this is a deviation of the general principle that `PSA_ECC_FAMILY_xxx` would have a corresponding symbol `PSA_WANT_ECC_FAMILY_xxx`. This deviation is justified by the fact that it is very common to wish to include only certain curves in a family, and that can lead to a significant gain in code size. + +#### Configuration symbols for Diffie-Hellman groups + +There are no configuration symbols for Diffie-Hellman groups (`PSA_DH_GROUP_xxx`). + +Rationale: Finite-field Diffie-Hellman code is usually not specialized for any particular group, so reducing the number of available groups at compile time only saves a little code space. Constrained implementations tend to omit FFDH anyway, so the small code size gain is not important. + +#### Configuration symbols for algorithms + +For each constant or constructor macro of the form `PSA_ALG_xxx`, the symbol **`PSA_WANT_ALG_xxx`** indicates that support for this algorithm is desired. + +For parametrized algorithms, the `PSA_WANT_ALG_xxx` symbol indicates whether the base mechanism is supported. Parameters must themselves be included through their own `PSA_WANT_ALG_xxx` symbols. It is an error to include a base mechanism without at least one possible parameter, and Mbed TLS will reject this at compile time. For example, `PSA_WANT_ALG_ECDSA` requires the inclusion of randomized ECDSA for all hash algorithms whose corresponding symbol `PSA_WANT_ALG_xxx` is enabled. + +## Implementation + +### Additional non-public symbols + +#### Accounting for transparent drivers + +In addition to the [configuration symbols](#psa-crypto-configuration-symbols), we need two parallel or mostly parallel sets of symbols: + +* **`MBEDTLS_PSA_ACCEL_xxx`** indicates whether a fully-featured, fallback-free transparent driver is available. +* **`MBEDTLS_PSA_BUILTIN_xxx`** indicates whether the software implementation is needed. + +`MBEDTLS_PSA_ACCEL_xxx` is one of the outputs of the transpilation of a driver description, alongside the glue code for calling the drivers. + +`MBEDTLS_PSA_BUILTIN_xxx` is enabled when `PSA_WANT_xxx` is enabled and `MBEDTLS_PSA_ACCEL_xxx` is disabled. + +These symbols are not part of the public interface of Mbed TLS towards applications or to drivers, regardless of whether the symbols are actually visible. + +### Architecture of symbol definitions + +#### Definition of configuration symbols + +The header file `mbedtls/mbedtls_config.h` defines all the `MBEDTLS_xxx_C` configuration symbols, including the ones deduced from the PSA Crypto configuration. It does this by including the new header file **`mbedtls/config_psa.h`**, which defines the `MBEDTLS_PSA_BUILTIN_xxx` symbols and deduces the corresponding `MBEDTLS_xxx_C` (and other) symbols. + +`mbedtls/config_psa.h` includes `psa/crypto_config.h`, the user-editable file that defines application requirements. + +#### Summary of definitions of configuration symbols + +`mbedtls/config_psa.h` includes `mbedtls/crypto_drivers.h`, a header file generated by the transpilation of the driver descriptions. It defines `MBEDTLS_PSA_ACCEL_xxx` symbols according to the availability of transparent drivers without fallback. + +The following table summarizes where symbols are defined depending on the configuration mode. + +* (U) indicates a symbol that is defined by the user (application). +* (D) indicates a symbol that is deduced from other symbols by code that ships with Mbed TLS. +* (G) indicates a symbol that is generated from driver descriptions. + +| Symbols | | +| ------------------------- | --------------------------------- | +| `MBEDTLS_xxx_C` | `mbedtls/mbedtls_config.h` (U) or | +| | `mbedtls/config_psa.h` (D) | +| `PSA_WANT_xxx` | `psa/crypto_config.h` (U) | +| `MBEDTLS_PSA_BUILTIN_xxx` | `mbedtls/config_psa.h` (D) | +| `MBEDTLS_PSA_ACCEL_xxx` | `mbedtls/crypto_drivers.h` (G) | + +#### Visibility of internal symbols + +Ideally, the `MBEDTLS_PSA_ACCEL_xxx` and `MBEDTLS_PSA_BUILTIN_xxx` symbols should not be visible to application code or driver code, since they are not part of the public interface of the library. However these symbols are needed to deduce whether to include library modules (for example `MBEDTLS_AES_C` has to be enabled if `MBEDTLS_PSA_BUILTIN_KEY_TYPE_AES` is enabled), which makes it difficult to keep them private. + +#### Compile-time checks + +The header file **`library/psa_check_config.h`** applies sanity checks to the configuration, throwing `#error` if something is wrong. + +A mechanism similar to `mbedtls/check_config.h` detects errors such as enabling ECDSA but no curve. + +Since configuration symbols must be undefined or 1, any other value should trigger an `#error`. + +#### Automatic generation of preprocessor symbol manipulations + +A lot of the preprocessor symbol manipulation is systematic calculations that analyze the configuration. `mbedtls/config_psa.h` and `library/psa_check_config.h` should be generated automatically, in the same manner as `version_features.c`. + +### Structure of PSA Crypto library code + +#### Conditional inclusion of library entry points + +An entry point can be eliminated entirely if no algorithm requires it. + +#### Conditional inclusion of mechanism-specific code + +Code that is specific to certain key types or to certain algorithms must be guarded by the applicable symbols: `PSA_WANT_xxx` for code that is independent of the application, and `MBEDTLS_PSA_BUILTIN_xxx` for code that calls an Mbed TLS software implementation. + +## PSA standardization + +### JSON configuration mechanism + +At the time of writing, the preferred configuration mechanism for a PSA service is in JSON syntax. The translation from JSON to build instructions is not specified by PSA. + +For PSA Crypto, the preferred configuration mechanism would be similar to capability specifications of transparent drivers. The same JSON properties that are used to mean “this driver can perform that mechanism” in a driver description would be used to mean “the application wants to perform that mechanism” in the application configuration. + +### From JSON to C + +The JSON capability language allows a more fine-grained selection than the C mechanism proposed here. For example, it allows requesting only single-part mechanisms, only certain key sizes, or only certain combinations of algorithms and key types. + +The JSON capability language can be translated approximately to the boolean symbol mechanism proposed here. The approximation considers a feature to be enabled if any part of it is enabled. For example, if there is a capability for AES-CTR and one for CAMELLIA-GCM, the translation to boolean symbols will also include AES-GCM and CAMELLIA-CTR. If there is a capability for AES-128, the translation will also include AES-192 and AES-256. + +The boolean symbol mechanism proposed here can be translated to a list of JSON capabilities: for each included algorithm, include a capability with that algorithm, the key types that apply to that algorithm, no size restriction, and all the entry points that apply to that algorithm. + +## Open questions + +### Open questions about the interface + +#### Naming of symbols + +The names of [elliptic curve symbols](#configuration-symbols-for-elliptic-curves) are a bit weird: `SECP_R1_256` instead of `SECP256R1`, `MONTGOMERY_255` instead of `CURVE25519`. Should we make them more classical, but less systematic? + +#### Impossible combinations + +What does it mean to have `PSA_WANT_ALG_ECDSA` enabled but with only Curve25519? Is it a mandatory error? + +#### Diffie-Hellman + +Way to request only specific groups? Not a priority: constrained devices don't do FFDH. Specify it as may change in future versions. + +#### Coexistence with the current Mbed TLS configuration + +The two mechanisms have very different designs. Is there serious potential for confusion? Do we understand how the combinations work? + +### Open questions about the design + +#### Algorithms without a key type or vice versa + +Is it realistic to mandate a compile-time error if a key type is required, but no matching algorithm, or vice versa? Is it always the right thing, for example if there is an opaque driver that manipulates this key type? + +#### Opaque-only mechanisms + +If a mechanism should only be supported in an opaque driver, what does the core need to know about it? Do we have all the information we need? + +This is especially relevant to suppress a mechanism completely if there is no matching algorithm. For example, if there is no transparent implementation of RSA or ECDSA, `psa_sign_hash` and `psa_verify_hash` may still be needed if there is an opaque signature driver. + +### Open questions about the implementation + +#### Testability + +Is this proposal decently testable? There are a lot of combinations. What combinations should we test? + + diff --git a/tf-psa-crypto/docs/proposed/psa-driver-developer-guide.md b/tf-psa-crypto/docs/proposed/psa-driver-developer-guide.md new file mode 100644 index 0000000000..6b207c824a --- /dev/null +++ b/tf-psa-crypto/docs/proposed/psa-driver-developer-guide.md @@ -0,0 +1,52 @@ +PSA Cryptoprocessor driver developer's guide +============================================ + +**This is a specification of work in progress. The implementation is not yet merged into Mbed TLS.** +For a description of the current state of drivers Mbed TLS, see our [PSA Cryptoprocessor driver development examples](../psa-driver-example-and-guide.html). + +This document describes how to write drivers of cryptoprocessors such as accelerators and secure elements for the PSA cryptography subsystem of Mbed TLS. + +This document focuses on behavior that is specific to Mbed TLS. For a reference of the interface between Mbed TLS and drivers, refer to the [PSA Cryptoprocessor Driver Interface specification](psa-driver-interface.html). + +The interface is not fully implemented in Mbed TLS yet. Please note that the interface may still change: until further notice, we do not guarantee backward compatibility with existing driver code. + +## Introduction + +### Purpose + +The PSA cryptography driver interface provides a way to build Mbed TLS with additional code that implements certain cryptographic primitives. This is primarily intended to support platform-specific hardware. + +There are two types of drivers: + +* **Transparent** drivers implement cryptographic operations on keys that are provided in cleartext at the beginning of each operation. They are typically used for hardware **accelerators**. When a transparent driver is available for a particular combination of parameters (cryptographic algorithm, key type and size, etc.), it is used instead of the default software implementation. Transparent drivers can also be pure software implementations that are distributed as plug-ins to a PSA Crypto implementation. +* **Opaque** drivers implement cryptographic operations on keys that can only be used inside a protected environment such as a **secure element**, a hardware security module, a smartcard, a secure enclave, etc. An opaque driver is invoked for the specific key location that the driver is registered for: the dispatch is based on the key's lifetime. + +### Deliverables for a driver + +To write a driver, you need to implement some functions with C linkage, and to declare these functions in a **driver description file**. The driver description file declares which functions the driver implements and what cryptographic mechanisms they support. Depending on the driver type, you may also need to define some C types and macros in a header file. + +The concrete syntax for a driver description file is JSON. The structure of this JSON file is specified in the section [“Driver description syntax”](psa-driver-interface.html#driver-description-syntax) of the PSA cryptography driver interface specification. + +A driver therefore consists of: + +* A driver description file (in JSON format). +* C header files defining the types required by the driver description. The names of these header files is declared in the driver description file. +* An object file compiled for the target platform defining the functions required by the driver description. Implementations may allow drivers to be provided as source files and compiled with the core instead of being pre-compiled. + +## Driver C interfaces + +Mbed TLS calls driver entry points [as specified in the PSA Cryptography Driver Interface specification](psa-driver-interface.html#driver-entry-points) except as otherwise indicated in this section. + +## Mbed TLS extensions + +The driver description can include Mbed TLS extensions (marked by the namespace "mbedtls"). Mbed TLS extensions are meant to extend/help integrating the driver into the library's infrastructure. +* `"mbedtls/h_condition"` (optional, string) can include complex preprocessor definitions to conditionally include header files for a given driver. +* `"mbedtls/c_condition"` (optional, string) can include complex preprocessor definitions to conditionally enable dispatch capabilities for a driver. + +## Building and testing your driver + + + +## Dependencies on the Mbed TLS configuration + + diff --git a/tf-psa-crypto/docs/proposed/psa-driver-integration-guide.md b/tf-psa-crypto/docs/proposed/psa-driver-integration-guide.md new file mode 100644 index 0000000000..8b3b4041c5 --- /dev/null +++ b/tf-psa-crypto/docs/proposed/psa-driver-integration-guide.md @@ -0,0 +1,39 @@ +Building Mbed TLS with PSA cryptoprocessor drivers +================================================== + +**This is a specification of work in progress. The implementation is not yet merged into Mbed TLS.** +For a description of the current state of drivers Mbed TLS, see our [PSA Cryptoprocessor driver development examples](../psa-driver-example-and-guide.html). + +This document describes how to build Mbed TLS with additional cryptoprocessor drivers that follow the PSA cryptoprocessor driver interface. + +The interface is not fully implemented in Mbed TLS yet. Please note that the interface may still change: until further notice, we do not guarantee backward compatibility with existing driver code. + +## Introduction + +The PSA cryptography driver interface provides a way to build Mbed TLS with additional code that implements certain cryptographic primitives. This is primarily intended to support platform-specific hardware. + +Note that such drivers are only available through the PSA cryptography API (crypto functions beginning with `psa_`, and X.509 and TLS interfaces that reference PSA types). + +Concretely speaking, a driver consists of one or more **driver description files** in JSON format and some code to include in the build. The driver code can either be provided in binary form as additional object file to link, or in source form. + +## How to build Mbed TLS with drivers + +To build Mbed TLS with drivers: + +1. Pass the driver description files through the Make variable `PSA_DRIVERS` when building the library. + + ``` + cd /path/to/mbedtls + make PSA_DRIVERS="/path/to/acme/driver.json /path/to/nadir/driver.json" lib + ``` + +2. Link your application with the implementation of the driver functions. + + ``` + cd /path/to/application + ld myapp.o -L/path/to/acme -lacmedriver -L/path/to/nadir -lnadirdriver -L/path/to/mbedtls -lmbedcrypto + ``` + + + + diff --git a/tf-psa-crypto/docs/proposed/psa-driver-interface.md b/tf-psa-crypto/docs/proposed/psa-driver-interface.md new file mode 100644 index 0000000000..03dc800149 --- /dev/null +++ b/tf-psa-crypto/docs/proposed/psa-driver-interface.md @@ -0,0 +1,1467 @@ +PSA Cryptoprocessor Driver Interface +==================================== + +This document describes an interface for cryptoprocessor drivers in the PSA cryptography API. This interface complements the [PSA Cryptography API specification](https://armmbed.github.io/mbed-crypto/psa/#application-programming-interface), which describes the interface between a PSA Cryptography implementation and an application. + +This specification is work in progress and should be considered to be in a beta stage. There is ongoing work to implement this interface in Mbed TLS, which is the reference implementation of the PSA Cryptography API. At this stage, Arm does not expect major changes, but minor changes are expected based on experience from the first implementation and on external feedback. + +For a practical guide, with a description of the current state of drivers Mbed TLS, see our [PSA Cryptoprocessor driver development examples](../psa-driver-example-and-guide.html). + +## Introduction + +### Purpose of the driver interface + +The PSA Cryptography API defines an interface that allows applications to perform cryptographic operations in a uniform way regardless of how the operations are performed. Under the hood, different keys may be stored and used in different hardware or in different logical partitions, and different algorithms may involve different hardware or software components. + +The driver interface allows implementations of the PSA Cryptography API to be built compositionally. An implementation of the PSA Cryptography API is composed of a **core** and zero or more **drivers**. The core handles key management, enforces key usage policies, and dispatches cryptographic operations either to the applicable driver or to built-in code. + +Functions in the PSA Cryptography API invoke functions in the core. Code from the core calls drivers as described in the present document. + +### Types of drivers + +The PSA Cryptography driver interface supports two types of cryptoprocessors, and accordingly two types of drivers. + +* **Transparent** drivers implement cryptographic operations on keys that are provided in cleartext at the beginning of each operation. They are typically used for hardware **accelerators**. When a transparent driver is available for a particular combination of parameters (cryptographic algorithm, key type and size, etc.), it is used instead of the default software implementation. Transparent drivers can also be pure software implementations that are distributed as plug-ins to a PSA Cryptography implementation (for example, an alternative implementation with different performance characteristics, or a certified implementation). +* **Opaque** drivers implement cryptographic operations on keys that can only be used inside a protected environment such as a **secure element**, a hardware security module, a smartcard, a secure enclave, etc. An opaque driver is invoked for the specific [key location](#lifetimes-and-locations) that the driver is registered for: the dispatch is based on the key's lifetime. + +### Requirements + +The present specification was designed to fulfill the following high-level requirements. + +[Req.plugins] It is possible to combine multiple drivers from different providers into the same implementation, without any prior arrangement other than choosing certain names and values from disjoint namespaces. + +[Req.compile] It is possible to compile the code of each driver and of the core separately, and link them together. A small amount of glue code may need to be compiled once the list of drivers is available. + +[Req.types] Support drivers for the following types of hardware: accelerators that operate on keys in cleartext; cryptoprocessors that can wrap keys with a built-in keys but not store user keys; and cryptoprocessors that store key material. + +[Req.portable] The interface between drivers and the core does not involve any platform-specific consideration. Driver calls are simple C function calls. Interactions with platform-specific hardware happen only inside the driver (and in fact a driver need not involve any hardware at all). + +[Req.location] Applications can tell which location values correspond to which secure element drivers. + +[Req.fallback] Accelerator drivers can specify that they do not fully support a cryptographic mechanism and that a fallback to core code may be necessary. Conversely, if an accelerator fully supports cryptographic mechanism, the core must be able to omit code for this mechanism. + +[Req.mechanisms] Drivers can specify which mechanisms they support. A driver's code will not be invoked for cryptographic mechanisms that it does not support. + +## Overview of drivers + +### Deliverables for a driver + +To write a driver, you need to implement some functions with C linkage, and to declare these functions in a **driver description file**. The driver description file declares which functions the driver implements and what cryptographic mechanisms they support. If the driver description references custom types, macros or constants, you also need to provide C header files defining those elements. + +The concrete syntax for a driver description file is JSON. The structure of this JSON file is specified in the section [“Driver description syntax”](#driver-description-syntax). + +A driver therefore consists of: + +* A driver description file (in JSON format). +* C header files defining the types required by the driver description. The names of these header files are declared in the driver description file. +* An object file compiled for the target platform defining the entry point functions specified by the driver description. Implementations may allow drivers to be provided as source files and compiled with the core instead of being pre-compiled. + +How to provide the driver description file, the C header files and the object code is implementation-dependent. + +### Driver description syntax + +The concrete syntax for a driver description file is JSON. + +In addition to the properties described here, any JSON object may have a property called `"_comment"` of type string, which will be ignored. + +PSA Cryptography core implementations may support additional properties. Such properties must use names consisting of the implementation's name, a slash, and additional characters. For example, the Yoyodyne implementation may use property names such as `"yoyodyne/foo"` and `"yoyodyne/widgets/girth"`. + +#### Driver description list + +PSA Cryptography core implementations should support multiple drivers. The driver description files are passed to the implementation as an ordered list in an unspecified manner. This may be, for example, a list of file names passed on a command line, or a JSON list whose elements are individual driver descriptions. + +#### Driver description top-level element + +A driver description is a JSON object containing the following properties: + +* `"prefix"` (mandatory, string). This must be a valid, non-empty prefix for a C identifier. All the types and functions provided by the driver have a name that starts with this prefix unless overridden with a `"name"` element in the applicable capability as described below. +* `"type"` (mandatory, string). One of `"transparent"` or `"opaque"`. +* `"headers"` (optional, array of strings). A list of header files. These header files must define the types, macros and constants referenced by the driver description. They may declare the entry point functions, but this is not required. They may include other PSA headers and standard headers of the platform. Whether they may include other headers is implementation-specific. If omitted, the list of headers is empty. The header files must be present at the specified location relative to a directory on the compiler's include path when compiling glue code between the core and the drivers. +* `"capabilities"` (mandatory, array of [capabilities](#driver-description-capability)). +A list of **capabilities**. Each capability describes a family of functions that the driver implements for a certain class of cryptographic mechanisms. +* `"key_context"` (not permitted for transparent drivers, mandatory for opaque drivers): information about the [representation of keys](#key-format-for-opaque-drivers). +* `"persistent_state_size"` (not permitted for transparent drivers, optional for opaque drivers, integer or string). The size in bytes of the [persistent state of the driver](#opaque-driver-persistent-state). This may be either a non-negative integer or a C constant expression of type `size_t`. +* `"location"` (not permitted for transparent drivers, optional for opaque drivers, integer or string). The [location value](#lifetimes-and-locations) for which this driver is invoked. In other words, this determines the lifetimes for which the driver is invoked. This may be either a non-negative integer or a C constant expression of type `psa_key_location_t`. + +### Driver description capability + +#### Capability syntax + +A capability declares a family of functions that the driver implements for a certain class of cryptographic mechanisms. The capability specifies which key types and algorithms are covered and the names of the types and functions that implement it. + +A capability is a JSON object containing the following properties: + +* `"entry_points"` (mandatory, list of strings). Each element is the name of a [driver entry point](#driver-entry-points) or driver entry point family. An entry point is a function defined by the driver. If specified, the core will invoke this capability of the driver only when performing one of the specified operations. The driver must implement all the specified entry points, as well as the types if applicable. +* `"algorithms"` (optional, list of strings). Each element is an [algorithm specification](#algorithm-specifications). If specified, the core will invoke this capability of the driver only when performing one of the specified algorithms. If omitted, the core will invoke this capability for all applicable algorithms. +* `"key_types"` (optional, list of strings). Each element is a [key type specification](#key-type-specifications). If specified, the core will invoke this capability of the driver only for operations involving a key with one of the specified key types. If omitted, the core will invoke this capability of the driver for all applicable key types. +* `"key_sizes"` (optional, list of integers). If specified, the core will invoke this capability of the driver only for operations involving a key with one of the specified key sizes. If omitted, the core will invoke this capability of the driver for all applicable key sizes. Key sizes are expressed in bits. +* `"names"` (optional, object). A mapping from entry point names described by the `"entry_points"` property, to the name of the C function in the driver that implements the corresponding function. If a function is not listed here, name of the driver function that implements it is the driver's prefix followed by an underscore (`_`) followed by the function name. If this property is omitted, it is equivalent to an empty object (so each entry point *suffix* is implemented by a function called *prefix*`_`*suffix*). +* `"fallback"` (optional for transparent drivers, not permitted for opaque drivers, boolean). If present and true, the driver may return `PSA_ERROR_NOT_SUPPORTED`, in which case the core should call another driver or use built-in code to perform this operation. If absent or false, the driver is expected to fully support the mechanisms described by this capability. See the section “[Fallback](#fallback)” for more information. + +#### Capability semantics + +When the PSA Cryptography implementation performs a cryptographic mechanism, it invokes available driver entry points as described in the section [“Driver entry points”](#driver-entry-points). + +A driver is considered available for a cryptographic mechanism that invokes a given entry point if all of the following conditions are met: + +* The driver specification includes a capability whose `"entry_points"` list either includes the entry point or includes an entry point family that includes the entry point. +* If the mechanism involves an algorithm: + * either the capability does not have an `"algorithms"` property; + * or the value of the capability's `"algorithms"` property includes an [algorithm specification](#algorithm-specifications) that matches this algorithm. +* If the mechanism involves a key: + * either the key is transparent (its location is `PSA_KEY_LOCATION_LOCAL_STORAGE`) and the driver is transparent; + * or the key is opaque (its location is not `PSA_KEY_LOCATION_LOCAL_STORAGE`) and the driver is an opaque driver whose location is the key's location. +* If the mechanism involves a key: + * either the capability does not have a `"key_types"` property; + * or the value of the capability's `"key_types"` property includes a [key type specification](#key-type-specifications) that matches this algorithm. +* If the mechanism involves a key: + * either the capability does not have a `"key_sizes"` property; + * or the value of the capability's `"key_sizes"` property includes the key's size. + +If a driver includes multiple applicable capabilities for a given combination of entry point, algorithm, key type and key size, and all the capabilities map the entry point to the same function name, the driver is considered available for this cryptographic mechanism. If a driver includes multiple applicable capabilities for a given combination of entry point, algorithm, key type and key size, and at least two of these capabilities map the entry point to the different function names, the driver specification is invalid. + +If multiple transparent drivers have applicable capabilities for a given combination of entry point, algorithm, key type and key size, the first matching driver in the [specification list](#driver-description-list) is invoked. If the capability has [fallback](#fallback) enabled and the first driver returns `PSA_ERROR_NOT_SUPPORTED`, the next matching driver is invoked, and so on. + +If multiple opaque drivers have the same location, the list of driver specifications is invalid. + +#### Capability examples + +Example 1: the following capability declares that the driver can perform deterministic ECDSA signatures (but not signature verification) using any hash algorithm and any curve that the core supports. If the prefix of this driver is `"acme"`, the function that performs the signature is called `acme_sign_hash`. +``` +{ + "entry_points": ["sign_hash"], + "algorithms": ["PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_ANY_HASH)"], +} +``` + +Example 2: the following capability declares that the driver can perform deterministic ECDSA signatures using SHA-256 or SHA-384 with a SECP256R1 or SECP384R1 private key (with either hash being possible in combination with either curve). If the prefix of this driver is `"acme"`, the function that performs the signature is called `acme_sign_hash`. +``` +{ + "entry_points": ["sign_hash"], + "algorithms": ["PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)", + "PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_384)"], + "key_types": ["PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)"], + "key_sizes": [256, 384] +} +``` + +### Algorithm and key specifications + +#### Algorithm specifications + +An algorithm specification is a string consisting of a `PSA_ALG_xxx` macro that specifies a cryptographic algorithm or an algorithm wildcard policy defined by the PSA Cryptography API. If the macro takes arguments, the string must have the syntax of a C macro call and each argument must be an algorithm specification or a decimal or hexadecimal literal with no suffix, depending on the expected type of argument. + +Spaces are optional after commas. Whether other whitespace is permitted is implementation-specific. + +Valid examples: +``` +PSA_ALG_SHA_256 +PSA_ALG_HMAC(PSA_ALG_SHA_256) +PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)) +PSA_ALG_RSA_PSS(PSA_ALG_ANY_HASH) +``` + +#### Key type specifications + +An algorithm specification is a string consisting of a `PSA_KEY_TYPE_xxx` macro that specifies a key type defined by the PSA Cryptography API. If the macro takes an argument, the string must have the syntax of a C macro call and each argument must be the name of a constant of suitable type (curve or group). + +The name `_` may be used instead of a curve or group to indicate that the capability concerns all curves or groups. + +Valid examples: +``` +PSA_KEY_TYPE_AES +PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1) +PSA_KEY_TYPE_ECC_KEY_PAIR(_) +``` + +### Driver entry points + +#### Overview of driver entry points + +Drivers define functions, each of which implements an aspect of a capability of a driver, such as a cryptographic operation, a part of a cryptographic operation, or a key management action. These functions are called the **entry points** of the driver. Most driver entry points correspond to a particular function in the PSA Cryptography API. For example, if a call to `psa_sign_hash()` is dispatched to a driver, it invokes the driver's `sign_hash` function. + +All driver entry points return a status of type `psa_status_t` which should use the status codes documented for PSA services in general and for PSA Cryptography in particular: `PSA_SUCCESS` indicates that the function succeeded, and `PSA_ERROR_xxx` values indicate that an error occurred. + +The signature of a driver entry point generally looks like the signature of the PSA Cryptography API that it implements, with some modifications. This section gives an overview of modifications that apply to whole classes of entry points. Refer to the reference section for each entry point or entry point family for details. + +* For entry points that operate on an existing key, the `psa_key_id_t` parameter is replaced by a sequence of three parameters that describe the key: + 1. `const psa_key_attributes_t *attributes`: the key attributes. + 2. `const uint8_t *key_buffer`: a key material or key context buffer. + 3. `size_t key_buffer_size`: the size of the key buffer in bytes. + + For transparent drivers, the key buffer contains the key material, in the same format as defined for `psa_export_key()` and `psa_export_public_key()` in the PSA Cryptography API. For opaque drivers, the content of the key buffer is entirely up to the driver. + +* For entry points that involve a multi-part operation, the operation state type (`psa_XXX_operation_t`) is replaced by a driver-specific operation state type (*prefix*`_XXX_operation_t`). + +* For entry points that are involved in key creation, the `psa_key_id_t *` output parameter is replaced by a sequence of parameters that convey the key context: + 1. `uint8_t *key_buffer`: a buffer for the key material or key context. + 2. `size_t key_buffer_size`: the size of the key buffer in bytes. + 2. `size_t *key_buffer_length`: the length of the data written to the key buffer in bytes. + +Some entry points are grouped in families that must be implemented as a whole. If a driver supports an entry point family, it must provide all the entry points in the family. + +Drivers can also have entry points related to random generation. A transparent driver can provide a [random generation interface](#random-generation-entry-points). Separately, transparent and opaque drivers can have [entropy collection entry points](#entropy-collection-entry-point). + +#### General considerations on driver entry point parameters + +Buffer parameters for driver entry points obey the following conventions: + +* An input buffer has the type `const uint8_t *` and is immediately followed by a parameter of type `size_t` that indicates the buffer size. +* An output buffer has the type `uint8_t *` and is immediately followed by a parameter of type `size_t` that indicates the buffer size. A third parameter of type `size_t *` is provided to report the actual length of the data written in the buffer if the function succeeds. +* An in-out buffer has the type `uint8_t *` and is immediately followed by a parameter of type `size_t` that indicates the buffer size. In-out buffers are only used when the input and the output have the same length. + +Buffers of size 0 may be represented with either a null pointer or a non-null pointer. + +Input buffers and other input-only parameters (`const` pointers) may be in read-only memory. Overlap is possible between input buffers, and between an input buffer and an output buffer, but not between two output buffers or between a non-buffer parameter and another parameter. + +#### Driver entry points for single-part cryptographic operations + +The following driver entry points perform a cryptographic operation in one shot (single-part operation): + +* `"hash_compute"` (transparent drivers only): calculation of a hash. Called by `psa_hash_compute()` and `psa_hash_compare()`. To verify a hash with `psa_hash_compare()`, the core calls the driver's `"hash_compute"` entry point and compares the result with the reference hash value. +* `"mac_compute"`: calculation of a MAC. Called by `psa_mac_compute()` and possibly `psa_mac_verify()`. To verify a mac with `psa_mac_verify()`, the core calls an applicable driver's `"mac_verify"` entry point if there is one, otherwise the core calls an applicable driver's `"mac_compute"` entry point and compares the result with the reference MAC value. +* `"mac_verify"`: verification of a MAC. Called by `psa_mac_verify()`. This entry point is mainly useful for drivers of secure elements that verify a MAC without revealing the correct MAC. Although transparent drivers may implement this entry point in addition to `"mac_compute"`, it is generally not useful because the core can call the `"mac_compute"` entry point and compare with the expected MAC value. +* `"cipher_encrypt"`: unauthenticated symmetric cipher encryption. Called by `psa_cipher_encrypt()`. +* `"cipher_decrypt"`: unauthenticated symmetric cipher decryption. Called by `psa_cipher_decrypt()`. +* `"aead_encrypt"`: authenticated encryption with associated data. Called by `psa_aead_encrypt()`. +* `"aead_decrypt"`: authenticated decryption with associated data. Called by `psa_aead_decrypt()`. +* `"asymmetric_encrypt"`: asymmetric encryption. Called by `psa_asymmetric_encrypt()`. +* `"asymmetric_decrypt"`: asymmetric decryption. Called by `psa_asymmetric_decrypt()`. +* `"sign_hash"`: signature of an already calculated hash. Called by `psa_sign_hash()` and possibly `psa_sign_message()`. To sign a message with `psa_sign_message()`, the core calls an applicable driver's `"sign_message"` entry point if there is one, otherwise the core calls an applicable driver's `"hash_compute"` entry point followed by an applicable driver's `"sign_hash"` entry point. +* `"verify_hash"`: verification of an already calculated hash. Called by `psa_verify_hash()` and possibly `psa_verify_message()`. To verify a message with `psa_verify_message()`, the core calls an applicable driver's `"verify_message"` entry point if there is one, otherwise the core calls an applicable driver's `"hash_compute"` entry point followed by an applicable driver's `"verify_hash"` entry point. +* `"sign_message"`: signature of a message. Called by `psa_sign_message()`. +* `"verify_message"`: verification of a message. Called by `psa_verify_message()`. +* `"key_agreement"`: key agreement without a subsequent key derivation. Called by `psa_raw_key_agreement()` and possibly `psa_key_derivation_key_agreement()`. + +### Driver entry points for multi-part operations + +#### General considerations on multi-part operations + +The entry points that implement each step of a multi-part operation are grouped into a family. A driver that implements a multi-part operation must define all of the entry points in this family as well as a type that represents the operation context. The lifecycle of a driver operation context is similar to the lifecycle of an API operation context: + +1. The core initializes operation context objects to either all-bits-zero or to logical zero (`{0}`), at its discretion. +1. The core calls the `xxx_setup` entry point for this operation family. If this fails, the core destroys the operation context object without calling any other driver entry point on it. +1. The core calls other entry points that manipulate the operation context object, respecting the constraints. +1. If any entry point fails, the core calls the driver's `xxx_abort` entry point for this operation family, then destroys the operation context object without calling any other driver entry point on it. +1. If a “finish” entry point fails, the core destroys the operation context object without calling any other driver entry point on it. The finish entry points are: *prefix*`_mac_sign_finish`, *prefix*`_mac_verify_finish`, *prefix*`_cipher_finish`, *prefix*`_aead_finish`, *prefix*`_aead_verify`. + +If a driver implements a multi-part operation but not the corresponding single-part operation, the core calls the driver's multipart operation entry points to perform the single-part operation. + +#### Multi-part operation entry point family `"hash_multipart"` + +This family corresponds to the calculation of a hash in multiple steps. + +This family applies to transparent drivers only. + +This family requires the following type and entry points: + +* Type `"hash_operation_t"`: the type of a hash operation context. It must be possible to copy a hash operation context byte by byte, therefore hash operation contexts must not contain any embedded pointers (except pointers to global data that do not change after the setup step). +* `"hash_setup"`: called by `psa_hash_setup()`. +* `"hash_update"`: called by `psa_hash_update()`. +* `"hash_finish"`: called by `psa_hash_finish()` and `psa_hash_verify()`. +* `"hash_abort"`: called by all multi-part hash functions of the PSA Cryptography API. + +To verify a hash with `psa_hash_verify()`, the core calls the driver's *prefix*`_hash_finish` entry point and compares the result with the reference hash value. + +For example, a driver with the prefix `"acme"` that implements the `"hash_multipart"` entry point family must define the following type and entry points (assuming that the capability does not use the `"names"` property to declare different type and entry point names): + +``` +typedef ... acme_hash_operation_t; +psa_status_t acme_hash_setup(acme_hash_operation_t *operation, + psa_algorithm_t alg); +psa_status_t acme_hash_update(acme_hash_operation_t *operation, + const uint8_t *input, + size_t input_length); +psa_status_t acme_hash_finish(acme_hash_operation_t *operation, + uint8_t *hash, + size_t hash_size, + size_t *hash_length); +psa_status_t acme_hash_abort(acme_hash_operation_t *operation); +``` + +#### Operation family `"mac_multipart"` + +TODO + +#### Operation family `"mac_verify_multipart"` + +TODO + +#### Operation family `"cipher_encrypt_multipart"` + +TODO + +#### Operation family `"cipher_decrypt_multipart"` + +TODO + +#### Operation family `"aead_encrypt_multipart"` + +TODO + +#### Operation family `"aead_decrypt_multipart"` + +TODO + +### Driver entry points for key derivation + +Key derivation is more complex than other multipart operations for several reasons: + +* There are multiple inputs and outputs. +* Multiple drivers can be involved. This happens when an operation combines a key agreement and a subsequent symmetric key derivation, each of which can have independent drivers. This also happens when deriving an asymmetric key, where processing the secret input and generating the key output might involve different drivers. +* When multiple drivers are involved, they are not always independent: if the secret input is managed by an opaque driver, it might not allow the core to retrieve the intermediate output and pass it to another driver. +* The involvement of an opaque driver cannot be determined as soon as the operation is set up (since `psa_key_derivation_setup()` does not determine the key input). + +#### Key derivation driver dispatch logic + +The core decides whether to dispatch a key derivation operation to a driver based on the location associated with the input step `PSA_KEY_DERIVATION_INPUT_SECRET`. + +1. If this step is passed via `psa_key_derivation_input_key()` for a key in a secure element: + * If the driver for this secure element implements the `"key_derivation"` family for the specified algorithm, the core calls that driver's `"key_derivation_setup"` and subsequent entry points. + Note that for all currently specified algorithms, the key type for the secret input does not matter. + * Otherwise the core calls the secure element driver's [`"export_key"`](#key-management-with-opaque-drivers) entry point. +2. Otherwise ([or on fallback?](#fallback-for-key-derivation-in-opaque-drivers)), if there is a transparent driver for the specified algorithm, the core calls that driver's `"key_derivation_setup"` and subsequent entry points. +3. Otherwise, or on fallback, the core uses its built-in implementation. + +#### Summary of entry points for the operation family `"key_derivation"` + +A key derivation driver has the following entry points: + +* `"key_derivation_setup"` (mandatory): always the first entry point to be called. This entry point provides the [initial inputs](#key-derivation-driver-initial-inputs). See [“Key derivation driver setup”](#key-derivation-driver-setup). +* `"key_derivation_input_step"` (mandatory if the driver supports a key derivation algorithm with long inputs, otherwise ignored): provide an extra input for the key derivation. This entry point is only mandatory in drivers that support algorithms that have extra inputs. See [“Key derivation driver long inputs”](#key-derivation-driver-long-inputs). +* `"key_derivation_output_bytes"` (mandatory): derive cryptographic material and output it. See [“Key derivation driver outputs”](#key-derivation-driver-outputs). +* `"key_derivation_output_key"`, `"key_derivation_verify_bytes"`, `"key_derivation_verify_key"` (optional, opaque drivers only): derive key material which remains inside the same secure element. See [“Key derivation driver outputs”](#key-derivation-driver-outputs). +* `"key_derivation_set_capacity"` (mandatory for opaque drivers that implement `"key_derivation_output_key"` for “cooked”, i.e. non-raw-data key types; ignored for other opaque drivers; not permitted for transparent drivers): update the capacity policy on the operation. See [“Key derivation driver operation capacity”](#key-derivation-driver-operation-capacity). +* `"key_derivation_abort"` (mandatory): always the last entry point to be called. + +For naming purposes, here and in the following subsection, this specification takes the example of a driver with the prefix `"acme"` that implements the `"key_derivation"` entry point family with a capability that does not use the `"names"` property to declare different type and entry point names. Such a driver must implement the following type and functions, as well as the entry points listed above and described in the following subsections: +``` +typedef ... acme_key_derivation_operation_t; +psa_status_t acme_key_derivation_abort(acme_key_derivation_operation_t *operation); +``` + +#### Key derivation driver initial inputs + +The core conveys the initial inputs for a key derivation via an opaque data structure of type `psa_crypto_driver_key_derivation_inputs_t`. + +``` +typedef ... psa_crypto_driver_key_derivation_inputs_t; // implementation-specific type +``` + +A driver receiving an argument that points to a `psa_crypto_driver_key_derivation_inputs_t` can retrieve its contents by calling one of the type-specific functions below. To determine the correct function, the driver can call `psa_crypto_driver_key_derivation_get_input_type()`. + +``` +enum psa_crypto_driver_key_derivation_input_type_t { + PSA_KEY_DERIVATION_INPUT_TYPE_INVALID = 0, + PSA_KEY_DERIVATION_INPUT_TYPE_OMITTED, + PSA_KEY_DERIVATION_INPUT_TYPE_BYTES, + PSA_KEY_DERIVATION_INPUT_TYPE_KEY, + PSA_KEY_DERIVATION_INPUT_TYPE_INTEGER, + // Implementations may add other values, and may freely choose the + // numerical values for each identifer except as explicitly specified + // above. +}; +psa_crypto_driver_key_derivation_input_type_t psa_crypto_driver_key_derivation_get_input_type( + const psa_crypto_driver_key_derivation_inputs_t *inputs, + psa_key_derivation_step_t step); +``` + +The function `psa_crypto_driver_key_derivation_get_input_type()` determines whether a given step is present and how to access its value: + +* `PSA_KEY_DERIVATION_INPUT_TYPE_INVALID`: the step is invalid for the algorithm of the operation that the inputs are for. +* `PSA_KEY_DERIVATION_INPUT_TYPE_OMITTED`: the step is optional for the algorithm of the operation that the inputs are for, and has been omitted. +* `PSA_KEY_DERIVATION_INPUT_TYPE_BYTES`: the step is valid and present and is a transparent byte string. Call `psa_crypto_driver_key_derivation_get_input_size()` to obtain the size of the input data. Call `psa_crypto_driver_key_derivation_get_input_bytes()` to make a copy of the input data (design note: [why a copy?](#key-derivation-inputs-and-buffer-ownership)). +* `PSA_KEY_DERIVATION_INPUT_TYPE_KEY`: the step is valid and present and is a byte string passed via a key object. Call `psa_crypto_driver_key_derivation_get_input_key()` to obtain a pointer to the key context. +* `PSA_KEY_DERIVATION_INPUT_TYPE_INTEGER`: the step is valid and present and is an integer. Call `psa_crypto_driver_key_derivation_get_input_integer()` to retrieve the integer value. + +``` +psa_status_t psa_crypto_driver_key_derivation_get_input_size( + const psa_crypto_driver_key_derivation_inputs_t *inputs, + psa_key_derivation_step_t step, + size_t *size); +psa_status_t psa_crypto_driver_key_derivation_get_input_bytes( + const psa_crypto_driver_key_derivation_inputs_t *inputs, + psa_key_derivation_step_t step, + uint8_t *buffer, size_t buffer_size, size_t *buffer_length); +psa_status_t psa_crypto_driver_key_derivation_get_input_key( + const psa_crypto_driver_key_derivation_inputs_t *inputs, + psa_key_derivation_step_t step, + const psa_key_attributes_t *attributes, + uint8_t** p_key_buffer, size_t *key_buffer_size); +psa_status_t psa_crypto_driver_key_derivation_get_input_integer( + const psa_crypto_driver_key_derivation_inputs_t *inputs, + psa_key_derivation_step_t step, + uint64_t *value); +``` + +The get-data functions take the following parameters: + +* The first parameter `inputs` must be a pointer passed by the core to a key derivation driver setup entry point which has not returned yet. +* The `step` parameter indicates the input step whose content the driver wants to retrieve. +* On a successful invocation of `psa_crypto_driver_key_derivation_get_input_size`, the core sets `*size` to the size of the specified input in bytes. +* On a successful invocation of `psa_crypto_driver_key_derivation_get_input_bytes`, the core fills the first *N* bytes of `buffer` with the specified input and sets `*buffer_length` to *N*, where *N* is the length of the input in bytes. The value of `buffer_size` must be at least *N*, otherwise this function fails with the status `PSA_ERROR_BUFFER_TOO_SMALL`. +* On a successful invocation of `psa_crypto_driver_key_derivation_get_input_key`, the core sets `*key_buffer` to a pointer to a buffer containing the key context and `*key_buffer_size` to the size of the key context in bytes. The key context buffer remains valid for the duration of the driver entry point. If the driver needs to access the key context after the current entry point returns, it must make a copy of the key context. +* On a successful invocation of `psa_crypto_driver_key_derivation_get_input_integer`, the core sets `*value` to the value of the specified input. + +These functions can return the following statuses: + +* `PSA_SUCCESS`: the call succeeded and the requested value has been copied to the output parameter (`size`, `buffer`, `value` or `p_key_buffer`) and if applicable the size of the value has been written to the applicable parameter (`buffer_length`, `key_buffer_size`). +* `PSA_ERROR_DOES_NOT_EXIST`: the input step is valid for this particular algorithm, but it is not part of the initial inputs. This is not a fatal error. The driver will receive the input later as a [long input](#key-derivation-driver-long-inputs). +* `PSA_ERROR_INVALID_ARGUMENT`: the input type is not compatible with this function or was omitted. Call `psa_crypto_driver_key_derivation_get_input_type()` to find out the actual type of this input step. This is not a fatal error and the driver can, for example, subsequently call the appropriate function on the same step. +* `PSA_ERROR_BUFFER_TOO_SMALL` (`psa_crypto_driver_key_derivation_get_input_bytes` only): the output buffer is too small. This is not a fatal error and the driver can, for example, subsequently call the same function again with a larger buffer. Call `psa_crypto_driver_key_derivation_get_input_size` to obtain the required size. +* The core may return other errors such as `PSA_ERROR_CORRUPTION_DETECTED` or `PSA_ERROR_COMMUNICATION_FAILURE` to convey implementation-specific error conditions. Portable drivers should treat such conditions as fatal errors. + +#### Key derivation driver setup + +A key derivation driver must implement the following entry point: +``` +psa_status_t acme_key_derivation_setup( + acme_key_derivation_operation_t *operation, + psa_algorithm_t alg, + const psa_crypto_driver_key_derivation_inputs_t *inputs); +``` + +* `operation` is a zero-initialized operation object. +* `alg` is the algorithm for the key derivation operation. It does not include a key agreement component. +* `inputs` is an opaque pointer to the [initial inputs](#key-derivation-driver-initial-inputs) for the key derivation. + +#### Key derivation driver long inputs + +Some key derivation algorithms take long inputs which it would not be practical to pass in the [initial inputs](#key-derivation-driver-initial-inputs). A driver that implements a key derivation algorithm that takes such inputs must provide a `"key_derivation_input_step"` entry point. The core calls this entry point for all the long inputs after calling `"acme_key_derivation_setup"`. A long input step may be fragmented into multiple calls of `psa_key_derivation_input_bytes()`, and the core may reassemble or refragment those fragments before passing them to the driver. Calls to this entry point for different step values occur in an unspecified order and may be interspersed. + +``` +psa_status_t acme_key_derivation_input_step( + acme_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + const uint8_t *input, size_t input_length); +``` + +At the time of writing, no standard key derivation algorithm has long inputs. It is likely that such algorithms will be added in the future. + +#### Key derivation driver operation capacity + +The core keeps track of an operation's capacity and enforces it. The core guarantees that it will not request output beyond the capacity of the operation, with one exception: opaque drivers that support [`"key_derivation_output_key"`](#key-derivation-driver-outputs), i.e. for key types where the derived key material is not a direct copy of the key derivation's output stream. + +Such drivers must enforce the capacity limitation and must return `PSA_ERROR_INSUFFICIENT_CAPACITY` from any output request that exceeds the operation's capacity. Such drivers must provide the following entry point: +``` +psa_status_t acme_key_derivation_set_capacity( + acme_key_derivation_operation_t *operation, + size_t capacity); +``` +`capacity` is guaranteed to be less or equal to any value previously set through this entry point, and is guaranteed not to be `PSA_KEY_DERIVATION_UNLIMITED_CAPACITY`. + +If this entry point has not been called, the operation has an unlimited capacity. + +#### Key derivation driver outputs + +A key derivation driver must provide the following entry point: +``` +psa_status_t acme_key_derivation_output_bytes( + acme_key_derivation_operation_t *operation, + uint8_t *output, size_t length); +``` + +An opaque key derivation driver may provide the following entry points: +``` +psa_status_t acme_key_derivation_output_key( + const psa_key_attributes_t *attributes, + acme_key_derivation_operation_t *operation, + uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length); +psa_status_t acme_key_derivation_verify_bytes( + acme_key_derivation_operation_t *operation, + const uint8_t *expected output, size_t length); +psa_status_t acme_key_derivation_verify_key( + acme_key_derivation_operation_t *operation, + uint8_t *key_buffer, size_t key_buffer_size); +``` + +The core calls a key derivation driver's output entry point when the application calls `psa_key_derivation_output_bytes()`, `psa_key_derivation_output_key()`, `psa_key_derivation_verify_bytes()` or `psa_key_derivation_verify_key()`. + +If the key derivation's `PSA_KEY_DERIVATION_INPUT_SECRET` input is in a secure element and the derivation operation is handled by that secure element, the core performs the following steps: + +* For a call to `psa_key_derivation_output_key()`: + + 1. If the derived key is in the same secure element, if the driver has an `"key_derivation_output_key"` entry point, call that entry point. If the driver has no such entry point, or if that entry point returns `PSA_ERROR_NOT_SUPPORTED`, continue with the following steps, otherwise stop. + 1. If the driver's capabilities indicate that its `"import_key"` entry point does not support the derived key, stop and return `PSA_ERROR_NOT_SUPPORTED`. + 1. Otherwise proceed as for `psa_key_derivation_output_bytes()`, then import the resulting key material. + +* For a call to `psa_key_derivation_verify_key()`: + 1. If the driver has a `"key_derivation_verify_key"` entry point, call it and stop. + 1. Call the driver's `"export_key"` entry point on the key object that contains the expected value, then proceed as for `psa_key_derivation_verify_bytes()`. + +* For a call to `psa_key_derivation_verify_bytes()`: + 1. If the driver has a `"key_derivation_verify_bytes"` entry point, call that entry point on the expected output, then stop. + 1. Otherwise, proceed as for `psa_key_derivation_output_bytes()`, and compare the resulting output to the expected output inside the core. + +* For a call to `psa_key_derivation_output_bytes()`: + 1. Call the `"key_derivation_output_bytes"` entry point. The core may call this entry point multiple times to implement a single call from the application when deriving a cooked (non-raw) key as described below, or if the output size exceeds some implementation limit. + +If the key derivation operation is not handled by an opaque driver as described above, the core calls the `"key_derivation_output_bytes"` from the applicable transparent driver (or multiple drivers in succession if fallback applies). In some cases, the core then calls additional entry points in the same or another driver: + +* For a call to `psa_key_derivation_output_key()` for some key types, the core calls a transparent driver's `"derive_key"` entry point. See [“Transparent cooked key derivation”](#transparent-cooked-key-derivation). +* For a call to `psa_key_derivation_output_key()` where the derived key is in a secure element, call that secure element driver's `"import_key"` entry point. + +#### Transparent cooked key derivation + +Key derivation is said to be *raw* for some key types, where the key material of a derived (8×*n*)-bit key consists of the next *n* bytes of output from the key derivation, and *cooked* otherwise. When deriving a raw key, the core only calls the driver's `"output_bytes"` entry point, except when deriving a key entirely inside a secure element as described in [“Key derivation driver outputs”](#key-derivation-driver-outputs). When deriving a cooked key, the core calls a transparent driver's `"derive_key"` entry point if available. + +A capability for cooked key derivation contains the following properties (this is not a subset of [the usual entry point properties](#capability-syntax)): + +* `"entry_points"` (mandatory, list of strings). Must be `["derive_key"]`. +* `"derived_types"` (mandatory, list of strings). Each element is a [key type specification](#key-type-specifications). This capability only applies when deriving a key of the specified type. +* `"derived_sizes"` (optional, list of integers). Each element is a size for the derived key, in bits. This capability only applies when deriving a key of the specified sizes. If absent, this capability applies to all sizes for the specified types. +* `"memory"` (optional, boolean). If present and true, the driver must define a type `"derive_key_memory_t"` and the core will allocate an object of that type as specified below. +* `"names"` (optional, object). A mapping from entry point names to C function and type names, as usual. +* `"fallback"` (optional, boolean). If present and true, the driver may return `PSA_ERROR_NOT_SUPPORTED` if it only partially supports the specified mechanism, as usual. + +A transparent driver with the prefix `"acme"` that implements cooked key derivation must provide the following type and function: + +``` +typedef ... acme_derive_key_memory_t; // only if the "memory" property is true +psa_status_t acme_derive_key( + const psa_key_attributes_t *attributes, + const uint8_t *input, size_t input_length, + acme_derive_key_memory_t *memory, // if the "memory" property is false: void* + uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length); +``` + +* `attributes` contains the attributes of the specified key. Note that only the key type and the bit-size are guaranteed to be set. +* `input` is a buffer of `input_length` bytes which contains the raw key stream, i.e. the data that `psa_key_derivation_output_bytes()` would return. +* If `"memory"` property in the driver capability is true, `memory` is a data structure that the driver may use to store data between successive calls of the `"derive_key"` entry point to derive the same key. If the `"memory"` property is false or absent, the `memory` parameter is a null pointer. +* `key_buffer` is a buffer for the output material, in the appropriate [export format](#key-format-for-transparent-drivers) for the key type. Its size is `key_buffer_size` bytes. +* On success, `*key_buffer_length` must contain the number of bytes written to `key_buffer`. + +This entry point may return the following statuses: + +* `PSA_SUCCESS`: a key was derived successfully. The driver has placed the representation of the key in `key_buffer`. +* `PSA_ERROR_NOT_SUPPORTED` (for the first call only) (only if fallback is enabled): the driver cannot fulfill this request, but a fallback driver might. +* `PSA_ERROR_INSUFFICIENT_DATA`: the core must call the `"derive_key"` entry point again with the same `memory` object and with subsequent data from the key stream. +* Any other error is a fatal error. + +The core calls the `"derive_key"` entry point in a loop until it returns a status other than `PSA_ERROR_INSUFFICIENT_DATA`. Each call has a successive fragment of the key stream. The `memory` object is guaranteed to be the same for successive calls, but note that its address may change between calls. Before the first call, `*memory` is initialized to all-bits-zero. + +For standard key types, the `"derive_key"` entry point is called with a certain input length as follows: + +* `PSA_KEY_TYPE_DES`: the length of the key. +* `PSA_KEY_TYPE_ECC_KEY_PAIR(…)`, `PSA_KEY_TYPE_DH_KEY_PAIR(…)`: $m$ bytes, where the bit-size of the key $n$ satisfies $8 (m-1) < n \le 8 m$. +* `PSA_KEY_TYPE_RSA_KEY_PAIR`: an implementation-defined length. A future version of this specification may specify a length. +* Other key types: not applicable. + +See [“Open questions around cooked key derivation”](#open-questions-around-cooked-key-derivation) for some points that may not be fully settled. + +#### Key agreement + +The core always decouples key agreement from symmetric key derivation. + +To implement a call to `psa_key_derivation_key_agreement()` where the private key is in a secure element that has a `"key_agreement_to_key"` entry point which is applicable for the given key type and algorithm, the core calls the secure element driver as follows: + +1. Call the `"key_agreement_to_key"` entry point to create a key object containing the shared secret. The key object is volatile and has the type `PSA_KEY_TYPE_DERIVE`. +2. Call the `"key_derivation_setup"` entry point, passing the resulting key object . +3. Perform the rest of the key derivation, up to and including the call to the `"key_derivation_abort"` entry point. +4. Call the `"destroy_key"` entry point to destroy the key containing the key object. + +In other cases, the core treats `psa_key_derivation_key_agreement()` as if it was a call to `psa_raw_key_agreement()` followed by a call to `psa_key_derivation_input_bytes()` on the shared secret. + +The entry points related to key agreement have the following prototypes for a driver with the prefix `"acme"`: +``` +psa_status_t acme_key_agreement(psa_algorithm_t alg, + const psa_key_attributes_t *our_attributes, + const uint8_t *our_key_buffer, + size_t our_key_buffer_length, + const uint8_t *peer_key, + size_t peer_key_length, + uint8_t *output, + size_t output_size, + size_t *output_length); +psa_status_t acme_key_agreement_to_key(psa_algorithm_t alg, + const psa_key_attributes_t *our_attributes, + const uint8_t *our_key_buffer, + size_t our_key_buffer_length, + const uint8_t *peer_key, + size_t peer_key_length, + const psa_key_attributes_t *shared_secret_attributes, + uint8_t *shared_secret_key_buffer, + size_t shared_secret_key_buffer_size, + size_t *shared_secret_key_buffer_length); +``` + +Note that unlike most other key creation entry points, in `"acme_key_agreement_to_key"`, the attributes for the shared secret are not placed near the beginning, but rather grouped with the other parameters related to the shared secret at the end of the parameter list. This is to avoid potential confusion with the attributes of the private key that is passed as an input. + +### Driver entry points for PAKE + +A PAKE operation is divided into two stages: collecting inputs and computation. Core side is responsible for keeping inputs and core set-data functions do not have driver entry points. Collected inputs are available for drivers via get-data functions for `password`, `role` and `cipher_suite`. + +### PAKE driver dispatch logic +The core decides whether to dispatch a PAKE operation to a driver based on the location of the provided password. +When all inputs are collected and `"psa_pake_output"` or `"psa_pake_input"` is called for the first time `"pake_setup"` driver entry point is invoked. + +1. If the location of the `password` is the local storage +- if there is a transparent driver for the specified ciphersuite, the core calls that driver's `"pake_setup"` and subsequent entry points. +- otherwise, or on fallback, the core uses its built-in implementation. +2. If the location of the `password` is the location of a secure element +- the core calls the `"pake_setup"` entry point of the secure element driver and subsequent entry points. + +### Summary of entry points for PAKE + +A PAKE driver has the following entry points: +* `"pake_setup"` (mandatory): always the first entry point to be called. It is called when all inputs are collected and the computation stage starts. +* `"pake_output"` (mandatory): derive cryptographic material for the specified step and output it. +* `"pake_input"` (mandatory): provides cryptographic material in the format appropriate for the specified step. +* `"pake_get_implicit_key"` (mandatory): returns implicitly confirmed shared secret from a PAKE. +* `"pake_abort"` (mandatory): always the last entry point to be called. + +For naming purposes, here and in the following subsection, this specification takes the example of a driver with the prefix `"acme"` that implements the PAKE entry point family with a capability that does not use the `"names"` property to declare different type and entry point names. Such a driver must implement the following type and functions, as well as the entry points listed above and described in the following subsections: +``` +typedef ... acme_pake_operation_t; +psa_status_t acme_pake_abort( acme_pake_operation_t *operation ); +``` + +#### PAKE driver inputs + +The core conveys the initial inputs for a PAKE operation via an opaque data structure of type `psa_crypto_driver_pake_inputs_t`. + +``` +typedef ... psa_crypto_driver_pake_inputs_t; // implementation-specific type +``` + +A driver receiving an argument that points to a `psa_crypto_driver_pake_inputs_t` can retrieve its contents by calling one of the get-data functions below. + +``` +psa_status_t psa_crypto_driver_pake_get_password_len( +    const psa_crypto_driver_pake_inputs_t *inputs, +    size_t *password_len); + +psa_status_t psa_crypto_driver_pake_get_password_bytes( +    const psa_crypto_driver_pake_inputs_t *inputs, +    uint8_t *buffer, size_t buffer_size, size_t *buffer_length); + +psa_status_t psa_crypto_driver_pake_get_password_key( +    const psa_crypto_driver_pake_inputs_t *inputs, +    uint8_t** p_key_buffer, size_t *key_buffer_size, + const psa_key_attributes_t *attributes); + +psa_status_t psa_crypto_driver_pake_get_user_len( +    const psa_crypto_driver_pake_inputs_t *inputs, +    size_t *user_len); + +psa_status_t psa_crypto_driver_pake_get_user( + const psa_crypto_driver_pake_inputs_t *inputs, + uint8_t *user_id, size_t user_id_size, size_t *user_id_len); + +psa_status_t psa_crypto_driver_pake_get_peer_len( +    const psa_crypto_driver_pake_inputs_t *inputs, +    size_t *peer_len); + +psa_status_t psa_crypto_driver_pake_get_peer( + const psa_crypto_driver_pake_inputs_t *inputs, + uint8_t *peer_id, size_t peer_id_size, size_t *peer_id_length); + +psa_status_t psa_crypto_driver_pake_get_cipher_suite( +    const psa_crypto_driver_pake_inputs_t *inputs, +    psa_pake_cipher_suite_t *cipher_suite); +``` +The get-data functions take the following parameters: + +The first parameter `inputs` must be a pointer passed by the core to a PAKE driver setup entry point. +Next parameters are return buffers (must not be null pointers). + +These functions can return the following statuses: +* `PSA_SUCCESS`: value has been successfully obtained +* `PSA_ERROR_BAD_STATE`: the inputs are not ready +* `PSA_ERROR_BUFFER_TOO_SMALL` (`psa_crypto_driver_pake_get_password_bytes` and `psa_crypto_driver_pake_get_password_key` only): the output buffer is too small. This is not a fatal error and the driver can, for example, subsequently call the same function again with a larger buffer. Call `psa_crypto_driver_pake_get_password_len` to obtain the required size. + +#### PAKE driver setup + +``` +psa_status_t acme_pake_setup( acme_pake_operation_t *operation, +                              const psa_crypto_driver_pake_inputs_t *inputs ); +``` + +* `operation` is a zero-initialized operation object. +* `inputs` is an opaque pointer to the [inputs](#pake-driver-inputs) for the PAKE operation. + +The setup driver function should preserve the inputs using get-data functions. + +The pointer output by `psa_crypto_driver_pake_get_password_key` is only valid until the "pake_setup" entry point returns. Opaque drivers must copy all relevant data from the key buffer during the "pake_setup" entry point and must not store the pointer itself. + +#### PAKE driver output + +``` +psa_status_t acme_pake_output(acme_pake_operation_t *operation, +                              psa_crypto_driver_pake_step_t step, +                              uint8_t *output, +                              size_t output_size, +                              size_t *output_length); +``` + +* `operation` is an operation object. +* `step` computation step based on which driver should perform an action. +* `output` buffer where the output is to be written. +* `output_size` size of the output buffer in bytes. +* `output_length` the number of bytes of the returned output. + +For `PSA_ALG_JPAKE` the following steps are available for output operation: +`step` can be one of the following values: +* `PSA_JPAKE_X1_STEP_KEY_SHARE`     Round 1: output our key share (for ephemeral private key X1) +* `PSA_JPAKE_X1_STEP_ZK_PUBLIC`     Round 1: output Schnorr NIZKP public key for the X1 key +* `PSA_JPAKE_X1_STEP_ZK_PROOF`      Round 1: output Schnorr NIZKP proof for the X1 key +* `PSA_JPAKE_X2_STEP_KEY_SHARE`     Round 1: output our key share (for ephemeral private key X2) +* `PSA_JPAKE_X2_STEP_ZK_PUBLIC`     Round 1: output Schnorr NIZKP public key for the X2 key +* `PSA_JPAKE_X2_STEP_ZK_PROOF`      Round 1: output Schnorr NIZKP proof for the X2 key +* `PSA_JPAKE_X2S_STEP_KEY_SHARE`    Round 2: output our X2S key +* `PSA_JPAKE_X2S_STEP_ZK_PUBLIC`    Round 2: output Schnorr NIZKP public key for the X2S key +* `PSA_JPAKE_X2S_STEP_ZK_PROOF`     Round 2: output Schnorr NIZKP proof for the X2S key + +#### PAKE driver input +``` +psa_status_t acme_pake_input(acme_pake_operation_t *operation, +                            psa_crypto_driver_pake_step_t step, +                             uint8_t *input, +                             size_t input_size); +``` + +* `operation` is an operation object. +* `step` computation step based on which driver should perform an action. +* `input` buffer containing the input. +* `input_length` length of the input in bytes. + +For `PSA_ALG_JPAKE` the following steps are available for input operation: +* `PSA_JPAKE_X1_STEP_KEY_SHARE`     Round 1: input key share from peer (for ephemeral private key X1) +* `PSA_JPAKE_X1_STEP_ZK_PUBLIC`     Round 1: input Schnorr NIZKP public key for the X1 key +* `PSA_JPAKE_X1_STEP_ZK_PROOF`      Round 1: input Schnorr NIZKP proof for the X1 key +* `PSA_JPAKE_X2_STEP_KEY_SHARE`     Round 1: input key share from peer (for ephemeral private key X2) +* `PSA_JPAKE_X2_STEP_ZK_PUBLIC`     Round 1: input Schnorr NIZKP public key for the X2 key +* `PSA_JPAKE_X2_STEP_ZK_PROOF`      Round 1: input Schnorr NIZKP proof for the X2 key +* `PSA_JPAKE_X4S_STEP_KEY_SHARE`    Round 2: input X4S key from peer +* `PSA_JPAKE_X4S_STEP_ZK_PUBLIC`    Round 2: input Schnorr NIZKP public key for the X4S key +* `PSA_JPAKE_X4S_STEP_ZK_PROOF`     Round 2: input Schnorr NIZKP proof for the X4S key + +The core checks that `input_length` is not greater than `PSA_PAKE_INPUT_SIZE(alg, prim, step)` and +the driver can rely on that. + +### PAKE driver get implicit key + +``` +psa_status_t acme_pake_get_implicit_key( +                            acme_pake_operation_t *operation, +                            uint8_t *output, size_t output_size, + size_t *output_length ); +``` + +* `operation` The driver PAKE operation object to use. +* `output` Buffer where the implicit key is to be written. +* `output_size` Size of the output buffer in bytes. +* `output_length` On success, the number of bytes of the implicit key. + +### Driver entry points for key management + +The driver entry points for key management differ significantly between [transparent drivers](#key-management-with-transparent-drivers) and [opaque drivers](#key-management-with-opaque-drivers). This section describes common elements. Refer to the applicable section for each driver type for more information. + +The entry points that create or format key data have the following prototypes for a driver with the prefix `"acme"`: + +``` +psa_status_t acme_import_key(const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length, + size_t *bits); // additional parameter, see below +psa_status_t acme_generate_key(const psa_key_attributes_t *attributes, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length); +``` +Additionally, opaque drivers can create keys through their [`"key_derivation_output_key"`](#key-derivation-driver-outputs) and [`"key_agreement_key"`](#key-agreement) entry points. Transparent drivers can create key material through their [`"derive_key"`](#transparent-cooked-key-derivation) entry point. + +TODO: copy + +* The key attributes (`attributes`) have the same semantics as in the PSA Cryptography application interface. +* For the `"import_key"` entry point, the input in the `data` buffer is either the export format or an implementation-specific format that the core documents as an acceptable input format for `psa_import_key()`. +* The size of the key data buffer `key_buffer` is sufficient for the internal representation of the key. For a transparent driver, this is the key's [export format](#key-format-for-transparent-drivers). For an opaque driver, this is the size determined from the driver description and the key attributes, as specified in the section [“Key format for opaque drivers”](#key-format-for-opaque-drivers). +* For an opaque driver with an `"allocate_key"` entry point, the content of the key data buffer on entry is the output of that entry point. +* The `"import_key"` entry point must determine or validate the key size and set `*bits` as described in the section [“Key size determination on import”](#key-size-determination-on-import) below. + +All key creation entry points must ensure that the resulting key is valid as specified in the section [“Key validation”](#key-validation) below. This is primarily important for import entry points since the key data comes from the application. + +#### Key size determination on import + +The `"import_key"` entry point must determine or validate the key size. +The PSA Cryptography API exposes the key size as part of the key attributes. +When importing a key, the key size recorded in the key attributes can be either a size specified by the caller of the API (who may not be trusted), or `0` which indicates that the size must be calculated from the data. + +When the core calls the `"import_key"` entry point to process a call to `psa_import_key`, it passes an `attributes` structure such that `psa_get_key_bits(attributes)` is the size passed by the caller of `psa_import_key`. If this size is `0`, the `"import_key"` entry point must set the `bits` input-output parameter to the correct key size. The semantics of `bits` is as follows: + +* The core sets `*bits` to `psa_get_key_bits(attributes)` before calling the `"import_key"` entry point. +* If `*bits == 0`, the driver must determine the key size from the data and set `*bits` to this size. If the key size cannot be determined from the data, the driver must return `PSA_ERROR_INVALID_ARGUMENT` (as of version 1.0 of the PSA Cryptography API specification, it is possible to determine the key size for all standard key types). +* If `*bits != 0`, the driver must check the value of `*bits` against the data and return `PSA_ERROR_INVALID_ARGUMENT` if it does not match. If the driver entry point changes `*bits` to a different value but returns `PSA_SUCCESS`, the core will consider the key as invalid and the import will fail. + +#### Key validation + +Key creation entry points must produce valid key data. Key data is _valid_ if operations involving the key are guaranteed to work functionally and not to cause indirect security loss. Operation functions are supposed to receive valid keys, and should not have to check and report invalid keys. For example: + +* If a cryptographic mechanism is defined as having keying material of a certain size, or if the keying material involves integers that have to be in a certain range, key creation must ensure that the keying material has an appropriate size and falls within an appropriate range. +* If a cryptographic operation involves a division by an integer which is provided as part of a key, key creation must ensure that this integer is nonzero. +* If a cryptographic operation involves two keys A and B (or more), then the creation of A must ensure that using it does not risk compromising B. This applies even if A's policy does not explicitly allow a problematic operation, but A is exportable. In particular, public keys that can potentially be used for key agreement are considered invalid and must not be created if they risk compromising the private key. +* On the other hand, it is acceptable for import to accept a key that cannot be verified as valid if using this key would at most compromise the key itself and material that is secured with this key. For example, RSA key import does not need to verify that the primes are actually prime. Key import may accept an insecure key if the consequences of the insecurity are no worse than a leak of the key prior to its import. + +With opaque drivers, the key context can only be used by code from the same driver, so key validity is primarily intended to report key creation errors at creation time rather than during an operation. With transparent drivers, the key context can potentially be used by code from a different provider, so key validity is critical for interoperability. + +This section describes some minimal validity requirements for standard key types. + +* For symmetric key types, check that the key size is suitable for the type. +* For DES (`PSA_KEY_TYPE_DES`), additionally verify the parity bits. +* For RSA (`PSA_KEY_TYPE_RSA_PUBLIC_KEY`, `PSA_KEY_TYPE_RSA_KEY_PAIR`), check the syntax of the key and make sanity checks on its components. TODO: what sanity checks? Value ranges (e.g. p < n), sanity checks such as parity, minimum and maximum size, what else? +* For elliptic curve private keys (`PSA_KEY_TYPE_ECC_KEY_PAIR`), check the size and range. TODO: what else? +* For elliptic curve public keys (`PSA_KEY_TYPE_ECC_PUBLIC_KEY`), check the size and range, and that the point is on the curve. TODO: what else? + +### Entropy collection entry point + +A driver can declare an entropy source by providing a `"get_entropy"` entry point. This entry point has the following prototype for a driver with the prefix `"acme"`: + +``` +typedef uint32_t psa_driver_get_entropy_flags_t; + +psa_status_t acme_get_entropy(psa_driver_get_entropy_flags_t flags, + size_t *estimate_bits, + uint8_t *output, + size_t output_size); +``` + +The semantics of the parameters is as follows: + +* `flags`: a bit-mask of [entropy collection flags](#entropy-collection-flags). +* `estimate_bits`: on success, an estimate of the amount of entropy that is present in the `output` buffer, in bits. This must be at least `1` on success. The value is ignored on failure. Drivers should return a conservative estimate, even in circumstances where the quality of the entropy source is degraded due to environmental conditions (e.g. undervolting, low temperature, etc.). +* `output`: on success, this buffer contains non-deterministic data with an estimated entropy of at least `*estimate_bits` bits. When the entropy is coming from a hardware peripheral, this should preferably be raw or lightly conditioned measurements from a physical process, such that statistical tests run over a sufficiently large amount of output can confirm the entropy estimates. But this specification also permits entropy sources that are fully conditioned, for example when the PSA Cryptography system is running as an application in an operating system and `"get_entropy"` returns data from the random generator in the operating system's kernel. +* `output_size`: the size of the `output` buffer in bytes. This size should be large enough to allow a driver to pass unconditioned data with a low density of entropy; for example a peripheral that returns eight bytes of data with an estimated one bit of entropy cannot provide meaningful output in less than 8 bytes. + +Note that there is no output parameter indicating how many bytes the driver wrote to the buffer. Such an output length indication is not necessary because the entropy may be located anywhere in the buffer, so the driver may write less than `output_size` bytes but the core does not need to know this. The output parameter `estimate_bits` contains the amount of entropy, expressed in bits, which may be significantly less than `output_size * 8`. + +The entry point may return the following statuses: + +* `PSA_SUCCESS`: success. The output buffer contains some entropy. +* `PSA_ERROR_INSUFFICIENT_ENTROPY`: no entropy is available without blocking. This is only permitted if the `PSA_DRIVER_GET_ENTROPY_NONBLOCK` flag is set. The core may call `get_entropy` again later, giving time for entropy to be gathered or for adverse environmental conditions to be rectified. +* `PSA_ERROR_NOT_SUPPORTED`: a flag is not recognized. The core may try again with different flags. +* Other error codes indicate a transient or permanent failure of the entropy source. + +Unlike most other entry points, if multiple transparent drivers include a `"get_entropy"` point, the core will call all of them (as well as the entry points from opaque drivers). Fallback is not applicable to `"get_entropy"`. + +#### Entropy collection flags + +* `PSA_DRIVER_GET_ENTROPY_NONBLOCK`: If this flag is clean, the driver should block until it has at least one bit of entropy. If this flag is set, the driver should avoid blocking if no entropy is readily available. +* `PSA_DRIVER_GET_ENTROPY_KEEPALIVE`: This flag is intended to help with energy management for entropy-generating peripherals. If this flag is set, the driver should expect another call to `acme_get_entropy` after a short time. If this flag is clear, the core is not expecting to call the `"get_entropy"` entry point again within a short amount of time (but it may do so nonetheless). + +A very simple core can just pass `flags=0`. All entropy drivers should support this case. + +If the entry point returns `PSA_ERROR_NOT_SUPPORTED`, the core may try calling the entry point again with fewer flags. Drivers should be consistent from one call to the next with respect to which flags they support. The core may cache an acceptable flag mask on its first call to an entry point. + +#### Entropy collection and blocking + +The intent of the `NONBLOCK` and `KEEPALIVE` [flags](#entropy-collection-flags) is to support drivers for TRNG (True Random Number Generator, i.e. an entropy source peripheral) that have a long ramp-up time, especially on platforms with multiple entropy sources. + +Here is a suggested call sequence for entropy collection that leverages these flags: + +1. The core makes a first round of calls to `"get_entropy"` on every source with the `NONBLOCK` flag set and the `KEEPALIVE` flag set, so that drivers can prepare the TRNG peripheral. +2. The core makes a second round of calls with the `NONBLOCK` flag clear and the `KEEPALIVE` flag clear to gather needed entropy. +3. If the second round does not collect enough entropy, the core makes more similar rounds, until the total amount of collected entropy is sufficient. + +### Miscellaneous driver entry points + +#### Driver initialization + +A driver may declare an `"init"` entry point in a capability with no algorithm, key type or key size. If so, the core calls this entry point once during the initialization of the PSA Cryptography subsystem. If the init entry point of any driver fails, the initialization of the PSA Cryptography subsystem fails. + +When multiple drivers have an init entry point, the order in which they are called is unspecified. It is also unspecified whether other drivers' `"init"` entry points are called if one or more init entry point fails. + +On platforms where the PSA Cryptography implementation is a subsystem of a single application, the initialization of the PSA Cryptography subsystem takes place during the call to `psa_crypto_init()`. On platforms where the PSA Cryptography implementation is separate from the application or applications, the initialization of the PSA Cryptography subsystem takes place before or during the first time an application calls `psa_crypto_init()`. + +The init entry point does not take any parameter. + +### Combining multiple drivers + +To declare a cryptoprocessor can handle both cleartext and wrapped keys, you need to provide two driver descriptions, one for a transparent driver and one for an opaque driver. You can use the mapping in capabilities' `"names"` property to arrange for multiple driver entry points to map to the same C function. + +## Transparent drivers + +### Key format for transparent drivers + +The format of a key for transparent drivers is the same as in applications. Refer to the documentation of [`psa_export_key()`](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html#c.psa_export_key) and [`psa_export_public_key()`](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html#c.psa_export_public_key) in the PSA Cryptography API specification. For custom key types defined by an implementation, refer to the documentation of that implementation. + +### Key management with transparent drivers + +Transparent drivers may provide the following key management entry points: + +* [`"import_key"`](#key-import-with-transparent-drivers): called by `psa_import_key()`, only when importing a key pair or a public key (key such that `PSA_KEY_TYPE_IS_ASYMMETRIC` is true). +* `"generate_key"`: called by `psa_generate_key()`, only when generating a key pair (key such that `PSA_KEY_TYPE_IS_KEY_PAIR` is true). +* `"key_derivation_output_key"`: called by `psa_key_derivation_output_key()`, only when deriving a key pair (key such that `PSA_KEY_TYPE_IS_KEY_PAIR` is true). +* `"export_public_key"`: called by the core to obtain the public key of a key pair. The core may call this function at any time to obtain the public key, which can be for `psa_export_public_key()` but also at other times, including during a cryptographic operation that requires the public key such as a call to `psa_verify_message()` on a key pair object. + +Transparent drivers are not involved when exporting, copying or destroying keys, or when importing, generating or deriving symmetric keys. + +#### Key import with transparent drivers + +As discussed in [the general section about key management entry points](#driver-entry-points-for-key-management), the key import entry points has the following prototype for a driver with the prefix `"acme"`: +``` +psa_status_t acme_import_key(const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length, + size_t *bits); +``` + +This entry point has several roles: + +1. Parse the key data in the input buffer `data`. The driver must support the export format for the key types that the entry point is declared for. It may support additional formats as specified in the description of [`psa_import_key()`](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html#c.psa_export_key) in the PSA Cryptography API specification. +2. Validate the key data. The necessary validation is described in the section [“Key validation”](#key-validation) above. +3. [Determine the key size](#key-size-determination-on-import) and output it through `*bits`. +4. Copy the validated key data from `data` to `key_buffer`. The output must be in the canonical format documented for [`psa_export_key()`](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html#c.psa_export_key) or [`psa_export_public_key()`](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html#c.psa_export_public_key), so if the input is not in this format, the entry point must convert it. + +### Random generation entry points + +A transparent driver may provide an operation family that can be used as a cryptographic random number generator. The random generation mechanism must obey the following requirements: + +* The random output must be of cryptographic quality, with a uniform distribution. Therefore, if the random generator includes an entropy source, this entropy source must be fed through a CSPRNG (cryptographically secure pseudo-random number generator). +* Random generation is expected to be fast. (If a device can provide entropy but is slow at generating random data, declare it as an [entropy driver](#entropy-collection-entry-point) instead.) +* The random generator should be able to incorporate entropy provided by an outside source. If it isn't, the random generator can only be used if it's the only entropy source on the platform. (A random generator peripheral can be declared as an [entropy source](#entropy-collection-entry-point) instead of a random generator; this way the core will combine it with other entropy sources.) +* The random generator may either be deterministic (in the sense that it always returns the same data when given the same entropy inputs) or non-deterministic (including its own entropy source). In other words, this interface is suitable both for PRNG (pseudo-random number generator, also known as DRBG (deterministic random bit generator)) and for NRBG (non-deterministic random bit generator). + +If no driver implements the random generation entry point family, the core provides an unspecified random generation mechanism. + +This operation family requires the following type, entry points and parameters (TODO: where exactly are the parameters in the JSON structure?): + +* Type `"random_context_t"`: the type of a random generation context. +* `"init_random"` (entry point, optional): if this function is present, [the core calls it once](#random-generator-initialization) after allocating a `"random_context_t"` object. +* `"add_entropy"` (entry point, optional): the core calls this function to [inject entropy](#entropy-injection). This entry point is optional if the driver is for a peripheral that includes an entropy source of its own, however [random generator drivers without entropy injection](#random-generator-drivers-without-entropy-injection) have limited portability since they can only be used on platforms with no other entropy source. This entry point is mandatory if `"initial_entropy_size"` is nonzero. +* `"get_random"` (entry point, mandatory): the core calls this function whenever it needs to [obtain random data](#the-get_random-entry-point). +* `"initial_entropy_size"` (integer, mandatory): the minimum number of bytes of entropy that the core must supply before the driver can output random data. This can be `0` if the driver is for a peripheral that includes an entropy source of its own. +* `"reseed_entropy_size"` (integer, optional): the minimum number of bytes of entropy that the core should supply via [`"add_entropy"`](#entropy-injection) when the driver runs out of entropy. This value is also a hint for the size to supply if the core makes additional calls to `"add_entropy"`, for example to enforce prediction resistance. If omitted, the core should pass an amount of entropy corresponding to the expected security strength of the device (for example, pass 32 bytes of entropy when reseeding to achieve a security strength of 256 bits). If specified, the core should pass the larger of `"reseed_entropy_size"` and the amount corresponding to the security strength. + +Random generation is not parametrized by an algorithm. The choice of algorithm is up to the driver. + +#### Random generator initialization + +The `"init_random"` entry point has the following prototype for a driver with the prefix `"acme"`: + +``` +psa_status_t acme_init_random(acme_random_context_t *context); +``` + +The core calls this entry point once after allocating a random generation context. Initially, the context object is all-bits-zero. + +If a driver does not have an `"init_random"` entry point, the context object passed to the first call to `"add_entropy"` or `"get_random"` will be all-bits-zero. + +#### Entropy injection + +The `"add_entropy"` entry point has the following prototype for a driver with the prefix `"acme"`: + +``` +psa_status_t acme_add_entropy(acme_random_context_t *context, + const uint8_t *entropy, + size_t entropy_size); +``` + +The semantics of the parameters is as follows: + +* `context`: a random generation context. On the first call to `"add_entropy"`, this object has been initialized by a call to the driver's `"init_random"` entry point if one is present, and to all-bits-zero otherwise. +* `entropy`: a buffer containing full-entropy data to seed the random generator. “Full-entropy” means that the data is uniformly distributed and independent of any other observable quantity. +* `entropy_size`: the size of the `entropy` buffer in bytes. It is guaranteed to be at least `1`, but it may be smaller than the amount of entropy that the driver needs to deliver random data, in which case the core will call the `"add_entropy"` entry point again to supply more entropy. + +The core calls this function to supply entropy to the driver. The driver must mix this entropy into its internal state. The driver must mix the whole supplied entropy, even if there is more than what the driver requires, to ensure that all entropy sources are mixed into the random generator state. The driver may mix additional entropy of its own. + +The core may call this function at any time. For example, to enforce prediction resistance, the core can call `"add_entropy"` immediately after each call to `"get_random"`. The core must call this function in two circumstances: + +* Before the first call to the `"get_random"` entry point, to supply `"initial_entropy_size"` bytes of entropy. +* After a call to the `"get_random"` entry point returns less than the required amount of random data, to supply at least `"reseed_entropy_size"` bytes of entropy. + +When the driver requires entropy, the core can supply it with one or more successive calls to the `"add_entropy"` entry point. If the required entropy size is zero, the core does not need to call `"add_entropy"`. + +#### Combining entropy sources with a random generation driver + +This section provides guidance on combining one or more [entropy sources](#entropy-collection-entry-point) (each having a `"get_entropy"` entry point) with a random generation driver (with an `"add_entropy"` entry point). + +Note that `"get_entropy"` returns data with an estimated amount of entropy that is in general less than the buffer size. The core must apply a mixing algorithm to the output of `"get_entropy"` to obtain full-entropy data. + +For example, the core may use a simple mixing scheme based on a pseudorandom function family $(F_k)$ with an $E$-bit output where $E = 8 \cdot \mathtt{entropy_size}$ and $\mathtt{entropy_size}$ is the desired amount of entropy in bytes (typically the random driver's `"initial_entropy_size"` property for the initial seeding and the `"reseed_entropy_size"` property for subsequent reseeding). The core calls the `"get_entropy"` points of the available entropy drivers, outputting a string $s_i$ and an entropy estimate $e_i$ on the $i$th call. It does so until the total entropy estimate $e_1 + e_2 + \ldots + e_n$ is at least $E$. The core then calculates $F_k(0)$ where $k = s_1 || s_2 || \ldots || s_n$. This value is a string of $\mathtt{entropy_size}$, and since $(F_k)$ is a pseudorandom function family, $F_k(0)$ is uniformly distributed over strings of $\mathtt{entropy_size}$ bytes. Therefore $F_k(0)$ is a suitable value to pass to `"add_entropy"`. + +Note that the mechanism above is only given as an example. Implementations may choose a different mechanism, for example involving multiple pools or intermediate compression functions. + +#### Random generator drivers without entropy injection + +Random generator drivers should have the capability to inject additional entropy through the `"add_entropy"` entry point. This ensures that the random generator depends on all the entropy sources that are available on the platform. A driver where a call to `"add_entropy"` does not affect the state of the random generator is not compliant with this specification. + +However, a driver may omit the `"add_entropy"` entry point. This limits the driver's portability: implementations of the PSA Cryptography specification may reject drivers without an `"add_entropy"` entry point, or only accept such drivers in certain configurations. In particular, the `"add_entropy"` entry point is required if: + +* the integration of PSA Cryptography includes an entropy source that is outside the driver; or +* the core saves random data in persistent storage to be preserved across platform resets. + +#### The `"get_random"` entry point + +The `"get_random"` entry point has the following prototype for a driver with the prefix `"acme"`: + +``` +psa_status_t acme_get_random(acme_random_context_t *context, + uint8_t *output, + size_t output_size, + size_t *output_length); +``` + +The semantics of the parameters is as follows: + +* `context`: a random generation context. If the driver's `"initial_entropy_size"` property is nonzero, the core must have called `"add_entropy"` at least once with a total of at least `"initial_entropy_size"` bytes of entropy before it calls `"get_random"`. Alternatively, if the driver's `"initial_entropy_size"` property is zero and the core did not call `"add_entropy"`, or if the driver has no `"add_entropy"` entry point, the core must have called `"init_random"` if present, and otherwise the context is all-bits zero. +* `output`: on success (including partial success), the first `*output_length` bytes of this buffer contain cryptographic-quality random data. The output is not used on error. +* `output_size`: the size of the `output` buffer in bytes. +* `*output_length`: on success (including partial success), the number of bytes of random data that the driver has written to the `output` buffer. This is preferably `output_size`, but the driver is allowed to return less data if it runs out of entropy as described below. The core sets this value to 0 on entry. The value is not used on error. + +The driver may return the following status codes: + +* `PSA_SUCCESS`: the `output` buffer contains `*output_length` bytes of cryptographic-quality random data. Note that this may be less than `output_size`; in this case the core should call the driver's `"add_entropy"` method to supply at least `"reseed_entropy_size"` bytes of entropy before calling `"get_random"` again. +* `PSA_ERROR_INSUFFICIENT_ENTROPY`: the core must supply additional entropy by calling the `"add_entropy"` entry point with at least `"reseed_entropy_size"` bytes. +* `PSA_ERROR_NOT_SUPPORTED`: the random generator is not available. This is only permitted if the driver specification for random generation has the [fallback property](#fallback) enabled. +* Other error codes such as `PSA_ERROR_COMMUNICATION_FAILURE` or `PSA_ERROR_HARDWARE_FAILURE` indicate a transient or permanent error. + +### Fallback + +Sometimes cryptographic accelerators only support certain cryptographic mechanisms partially. The capability description language allows specifying some restrictions, including restrictions on key sizes, but it cannot cover all the possibilities that may arise in practice. Furthermore, it may be desirable to deploy the same binary image on different devices, only some of which have a cryptographic accelerators. +For these purposes, a transparent driver can declare that it only supports a [capability](#driver-description-capability) partially, by setting the capability's `"fallback"` property to true. + +If a transparent driver entry point is part of a capability which has a true `"fallback"` property and returns `PSA_ERROR_NOT_SUPPORTED`, the core will call the next transparent driver that supports the mechanism, if there is one. The core considers drivers in the order given by the [driver description list](#driver-description-list). + +If all the available drivers have fallback enabled and return `PSA_ERROR_NOT_SUPPORTED`, the core will perform the operation using built-in code. +As soon as a driver returns any value other than `PSA_ERROR_NOT_SUPPORTED` (`PSA_SUCCESS` or a different error code), this value is returned to the application, without attempting to call any other driver or built-in code. + +If a transparent driver entry point is part of a capability where the `"fallback"` property is false or omitted, the core should not include any other code for this capability, whether built in or in another transparent driver. + +## Opaque drivers + +Opaque drivers allow a PSA Cryptography implementation to delegate cryptographic operations to a separate environment that might not allow exporting key material in cleartext. The opaque driver interface is designed so that the core never inspects the representation of a key. The opaque driver interface is designed to support two subtypes of cryptoprocessors: + +* Some cryptoprocessors do not have persistent storage for individual keys. The representation of a key is the key material wrapped with a master key which is located in the cryptoprocessor and never exported from it. The core stores this wrapped key material on behalf of the cryptoprocessor. +* Some cryptoprocessors have persistent storage for individual keys. The representation of a key is an identifier such as label or slot number. The core stores this identifier. + +### Key format for opaque drivers + +The format of a key for opaque drivers is an opaque blob. The content of this blob is fully up to the driver. The core merely stores this blob. + +Note that since the core stores the key context blob as it is in memory, it must only contain data that is meaningful after a reboot. In particular, it must not contain any pointers or transient handles. + +The `"key_context"` property in the [driver description](#driver-description-top-level-element) specifies how to calculate the size of the key context as a function of the key type and size. This is an object with the following properties: + +* `"base_size"` (integer or string, optional): this many bytes are included in every key context. If omitted, this value defaults to 0. +* `"key_pair_size"` (integer or string, optional): this many bytes are included in every key context for a key pair. If omitted, this value defaults to 0. +* `"public_key_size"` (integer or string, optional): this many bytes are included in every key context for a public key. If omitted, this value defaults to 0. +* `"symmetric_factor"` (integer or string, optional): every key context for a symmetric key includes this many times the key size. If omitted, this value defaults to 0. +* `"store_public_key"` (boolean, optional): If specified and true, for a key pair, the key context includes space for the public key. If omitted or false, no additional space is added for the public key. +* `"size_function"` (string, optional): the name of a function that returns the number of bytes that the driver needs in a key context for a key. This may be a pointer to function. This must be a C identifier; more complex expressions are not permitted. If the core uses this function, it supersedes all the other properties except for `"builtin_key_size"` (where applicable, if present). +* `"builtin_key_size"` (integer or string, optional): If specified, this overrides all other methods (including the `"size_function"` entry point) to determine the size of the key context for [built-in keys](#built-in-keys). This allows drivers to efficiently represent application keys as wrapped key material, but built-in keys by an internal identifier that takes up less space. + +The integer properties must be C language constants. A typical value for `"base_size"` is `sizeof(acme_key_context_t)` where `acme_key_context_t` is a type defined in a driver header file. + +#### Size of a dynamically allocated key context + +If the core supports dynamic allocation for the key context and chooses to use it, and the driver specification includes the `"size_function"` property, the size of the key context is at least +``` +size_function(key_type, key_bits) +``` +where `size_function` is the function named in the `"size_function"` property, `key_type` is the key type and `key_bits` is the key size in bits. The prototype of the size function is +``` +size_t size_function(psa_key_type_t key_type, size_t key_bits); +``` + +#### Size of a statically allocated key context + +If the core does not support dynamic allocation for the key context or chooses not to use it, or if the driver specification does not include the `"size_function"` property, the size of the key context for a key of type `key_type` and of size `key_bits` bits is: + +* For a key pair (`PSA_KEY_TYPE_IS_KEY_PAIR(key_type)` is true): + ``` + base_size + key_pair_size + public_key_overhead + ``` + where `public_key_overhead = PSA_EXPORT_PUBLIC_KEY_MAX_SIZE(key_type, key_bits)` if the `"store_public_key"` property is true and `public_key_overhead = 0` otherwise. + +* For a public key (`PSA_KEY_TYPE_IS_PUBLIC_KEY(key_type)` is true): + ``` + base_size + public_key_size + ``` + +* For a symmetric key (not a key pair or public key): + ``` + base_size + symmetric_factor * key_bytes + ``` + where `key_bytes = ((key_bits + 7) / 8)` is the key size in bytes. + +#### Key context size for a secure element with storage + +If the key is stored in the secure element and the driver only needs to store a label for the key, use `"base_size"` as the size of the label plus any other metadata that the driver needs to store, and omit the other properties. + +If the key is stored in the secure element, but the secure element does not store the public part of a key pair and cannot recompute it on demand, additionally use the `"store_public_key"` property with the value `true`. Note that this only influences the size of the key context: the driver code must copy the public key to the key context and retrieve it on demand in its `export_public_key` entry point. + +#### Key context size for a secure element without storage + +If the key is stored in wrapped form outside the secure element, and the wrapped form of the key plus any metadata has up to *N* bytes of overhead, use *N* as the value of the `"base_size"` property and set the `"symmetric_factor"` property to 1. Set the `"key_pair_size"` and `"public_key_size"` properties appropriately for the largest supported key pair and the largest supported public key respectively. + +### Key management with opaque drivers + +Opaque drivers may provide the following key management entry points: + +* `"export_key"`: called by `psa_export_key()`, or by `psa_copy_key()` when copying a key from or to a different [location](#lifetimes-and-locations), or [as a fallback for key derivation](#key-derivation-driver-dispatch-logic). +* `"export_public_key"`: called by the core to obtain the public key of a key pair. The core may call this entry point at any time to obtain the public key, which can be for `psa_export_public_key()` but also at other times, including during a cryptographic operation that requires the public key such as a call to `psa_verify_message()` on a key pair object. +* `"import_key"`: called by `psa_import_key()`, or by `psa_copy_key()` when copying a key from another location. +* `"generate_key"`: called by `psa_generate_key()`. +* `"key_derivation_output_key"`: called by `psa_key_derivation_output_key()`. +* `"copy_key"`: called by `psa_copy_key()` when copying a key within the same [location](#lifetimes-and-locations). +* `"get_builtin_key"`: called by functions that access a key to retrieve information about a [built-in key](#built-in-keys). + +In addition, secure elements that store the key material internally must provide the following two entry points: + +* `"allocate_key"`: called by `psa_import_key()`, `psa_generate_key()`, `psa_key_derivation_output_key()` or `psa_copy_key()` before creating a key in the location of this driver. +* `"destroy_key"`: called by `psa_destroy_key()`. + +#### Key creation in a secure element without storage + +This section describes the key creation process for secure elements that do not store the key material. The driver must obtain a wrapped form of the key material which the core will store. A driver for such a secure element has no `"allocate_key"` or `"destroy_key"` entry point. + +When creating a key with an opaque driver which does not have an `"allocate_key"` or `"destroy_key"` entry point: + +1. The core allocates memory for the key context. +2. The core calls the driver's import, generate, derive or copy entry point. +3. The core saves the resulting wrapped key material and any other data that the key context may contain. + +To destroy a key, the core simply destroys the wrapped key material, without invoking driver code. + +#### Key management in a secure element with storage + +This section describes the key creation and key destruction processes for secure elements that have persistent storage for the key material. A driver for such a secure element has two mandatory entry points: + +* `"allocate_key"`: this function obtains an internal identifier for the key. This may be, for example, a unique label or a slot number. +* `"destroy_key"`: this function invalidates the internal identifier and destroys the associated key material. + +These functions have the following prototypes for a driver with the prefix `"acme"`: +``` +psa_status_t acme_allocate_key(const psa_key_attributes_t *attributes, + uint8_t *key_buffer, + size_t key_buffer_size); +psa_status_t acme_destroy_key(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size); +``` + +When creating a persistent key with an opaque driver which has an `"allocate_key"` entry point: + +1. The core calls the driver's `"allocate_key"` entry point. This function typically allocates an internal identifier for the key without modifying the state of the secure element and stores the identifier in the key context. This function should not modify the state of the secure element. It may modify the copy of the persistent state of the driver in memory. + +1. The core saves the key context to persistent storage. + +1. The core calls the driver's key creation entry point. + +1. The core saves the updated key context to persistent storage. + +If a failure occurs after the `"allocate_key"` step but before the call to the second driver entry point, the core will do one of the following: + +* Fail the creation of the key without indicating this to the driver. This can happen, in particular, if the device loses power immediately after the key allocation entry point returns. +* Call the driver's `"destroy_key"` entry point. + +To destroy a key, the core calls the driver's `"destroy_key"` entry point. + +Note that the key allocation and destruction entry points must not rely solely on the key identifier in the key attributes to identify a key. Some implementations of the PSA Cryptography API store keys on behalf of multiple clients, and different clients may use the same key identifier to designate different keys. The manner in which the core distinguishes keys that have the same identifier but are part of the key namespace for different clients is implementation-dependent and is not accessible to drivers. Some typical strategies to allocate an internal key identifier are: + +* Maintain a set of free slot numbers which is stored either in the secure element or in the driver's persistent storage. To allocate a key slot, find a free slot number, mark it as occupied and store the number in the key context. When the key is destroyed, mark the slot number as free. +* Maintain a monotonic counter with a practically unbounded range in the secure element or in the driver's persistent storage. To allocate a key slot, increment the counter and store the current value in the key context. Destroying a key does not change the counter. + +TODO: explain constraints on how the driver updates its persistent state for resilience + +TODO: some of the above doesn't apply to volatile keys + +#### Key creation entry points in opaque drivers + +The key creation entry points have the following prototypes for a driver with the prefix `"acme"`: + +``` +psa_status_t acme_import_key(const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length, + size_t *bits); +psa_status_t acme_generate_key(const psa_key_attributes_t *attributes, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length); +``` + +If the driver has an [`"allocate_key"` entry point](#key-management-in-a-secure-element-with-storage), the core calls the `"allocate_key"` entry point with the same attributes on the same key buffer before calling the key creation entry point. + +TODO: derivation, copy + +#### Key export entry points in opaque drivers + +The key export entry points have the following prototypes for a driver with the prefix `"acme"`: + +``` +psa_status_t acme_export_key(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *data, + size_t data_size, + size_t *data_length); +psa_status_t acme_export_public_key(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *data, + size_t data_size, + size_t *data_length); +``` + +The core will only call `acme_export_public_key` on a private key. Drivers implementers may choose to store the public key in the key context buffer or to recalculate it on demand. If the key context includes the public key, it needs to have an adequate size; see [“Key format for opaque drivers”](#key-format-for-opaque-drivers). + +The core guarantees that the size of the output buffer (`data_size`) is sufficient to export any key with the given attributes. The driver must set `*data_length` to the exact size of the exported key. + +### Opaque driver persistent state + +The core maintains persistent state on behalf of an opaque driver. This persistent state consists of a single byte array whose size is given by the `"persistent_state_size"` property in the [driver description](#driver-description-top-level-element). + +The core loads the persistent state in memory before it calls the driver's [init entry point](#driver-initialization). It is adjusted to match the size declared by the driver, in case a driver upgrade changes the size: + +* The first time the driver is loaded on a system, the persistent state is all-bits-zero. +* If the stored persistent state is smaller than the declared size, the core pads the persistent state with all-bits-zero at the end. +* If the stored persistent state is larger than the declared size, the core truncates the persistent state to the declared size. + +The core provides the following callback functions, which an opaque driver may call while it is processing a call from the driver: +``` +psa_status_t psa_crypto_driver_get_persistent_state(uint_8_t **persistent_state_ptr); +psa_status_t psa_crypto_driver_commit_persistent_state(size_t from, size_t length); +``` + +`psa_crypto_driver_get_persistent_state` sets `*persistent_state_ptr` to a pointer to the first byte of the persistent state. This pointer remains valid during a call to a driver entry point. Once the entry point returns, the pointer is no longer valid. The core guarantees that calls to `psa_crypto_driver_get_persistent_state` within the same entry point return the same address for the persistent state, but this address may change between calls to an entry point. + +`psa_crypto_driver_commit_persistent_state` updates the persistent state in persistent storage. Only the portion at byte offsets `from` inclusive to `from + length` exclusive is guaranteed to be updated; it is unspecified whether changes made to other parts of the state are taken into account. The driver must call this function after updating the persistent state in memory and before returning from the entry point, otherwise it is unspecified whether the persistent state is updated. + +The core will not update the persistent state in storage while an entry point is running except when the entry point calls `psa_crypto_driver_commit_persistent_state`. It may update the persistent state in storage after an entry point returns. + +In a multithreaded environment, the driver may only call these two functions from the thread that is executing the entry point. + +#### Built-in keys + +Opaque drivers may declare built-in keys. Built-in keys can be accessed, but not created, through the PSA Cryptography API. + +A built-in key is identified by its location and its **slot number**. Drivers that support built-in keys must provide a `"get_builtin_key"` entry point to retrieve the key data and metadata. The core calls this entry point when it needs to access the key, typically because the application requested an operation on the key. The core may keep information about the key in cache, and successive calls to access the same slot number should return the same data. This entry point has the following prototype: + +``` +psa_status_t acme_get_builtin_key(psa_drv_slot_number_t slot_number, + psa_key_attributes_t *attributes, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length); +``` + +If this function returns `PSA_SUCCESS` or `PSA_ERROR_BUFFER_TOO_SMALL`, it must fill `attributes` with the attributes of the key (except for the key identifier). On success, this function must also fill `key_buffer` with the key context. + +On entry, `psa_get_key_lifetime(attributes)` is the location at which the driver was declared and a persistence level with which the platform is attempting to register the key. The driver entry point may choose to change the lifetime (`psa_set_key_lifetime(attributes, lifetime)`) of the reported key attributes to one with the same location but a different persistence level, in case the driver has more specific knowledge about the actual persistence level of the key which is being retrieved. For example, if a driver knows it cannot delete a key, it may override the persistence level in the lifetime to `PSA_KEY_PERSISTENCE_READ_ONLY`. The standard attributes other than the key identifier and lifetime have the value conveyed by `PSA_KEY_ATTRIBUTES_INIT`. + +The output parameter `key_buffer` points to a writable buffer of `key_buffer_size` bytes. If the driver has a [`"builtin_key_size"` property](#key-format-for-opaque-drivers) property, `key_buffer_size` has this value, otherwise `key_buffer_size` has the value determined from the key type and size. + +Typically, for a built-in key, the key context is a reference to key material that is kept inside the secure element, similar to the format returned by [`"allocate_key"`](#key-management-in-a-secure-element-with-storage). A driver may have built-in keys even if it doesn't have an `"allocate_key"` entry point. + +This entry point may return the following status values: + +* `PSA_SUCCESS`: the requested key exists, and the output parameters `attributes` and `key_buffer` contain the key metadata and key context respectively, and `*key_buffer_length` contains the length of the data written to `key_buffer`. +* `PSA_ERROR_BUFFER_TOO_SMALL`: `key_buffer_size` is insufficient. In this case, the driver must pass the key's attributes in `*attributes`. In particular, `get_builtin_key(slot_number, &attributes, NULL, 0)` is a way for the core to obtain the key's attributes. +* `PSA_ERROR_DOES_NOT_EXIST`: the requested key does not exist. +* Other error codes such as `PSA_ERROR_COMMUNICATION_FAILURE` or `PSA_ERROR_HARDWARE_FAILURE` indicate a transient or permanent error. + +The core will pass authorized requests to destroy a built-in key to the [`"destroy_key"`](#key-management-in-a-secure-element-with-storage) entry point if there is one. If built-in keys must not be destroyed, it is up to the driver to reject such requests. + +## How to use drivers from an application + +### Using transparent drivers + +Transparent drivers linked into the library are automatically used for the mechanisms that they implement. + +### Using opaque drivers + +Each opaque driver is assigned a [location](#lifetimes-and-locations). The driver is invoked for all actions that use a key in that location. A key's location is indicated by its lifetime. The application chooses the key's lifetime when it creates the key. + +For example, the following snippet creates an AES-GCM key which is only accessible inside the secure element designated by the location `PSA_KEY_LOCATION_acme`. +``` +psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; +psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( + PSA_KEY_PERSISTENCE_DEFAULT, PSA_KEY_LOCATION_acme)); +psa_set_key_identifier(&attributes, 42); +psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); +psa_set_key_size(&attributes, 128); +psa_set_key_algorithm(&attributes, PSA_ALG_GCM); +psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); +psa_key_id_t key; +psa_generate_key(&attributes, &key); +``` + +## Using opaque drivers from an application + +### Lifetimes and locations + +The PSA Cryptography API, version 1.0.0, defines [lifetimes](https://armmbed.github.io/mbed-crypto/html/api/keys/attributes.html?highlight=psa_key_lifetime_t#c.psa_key_lifetime_t) as an attribute of a key that indicates where the key is stored and which application and system actions will create and destroy it. The lifetime is expressed as a 32-bit value (`typedef uint32_t psa_key_lifetime_t`). An upcoming version of the PSA Cryptography API defines more structure for lifetime values to separate these two aspects of the lifetime: + +* Bits 0–7 are a _persistence level_. This value indicates what device management actions can cause it to be destroyed. In particular, it indicates whether the key is volatile or persistent. +* Bits 8–31 are a _location indicator_. This value indicates where the key material is stored and where operations on the key are performed. Location values can be stored in a variable of type `psa_key_location_t`. + +An opaque driver is attached to a specific location. Keys in the default location (`PSA_KEY_LOCATION_LOCAL_STORAGE = 0`) are transparent: the core has direct access to the key material. For keys in a location that is managed by an opaque driver, only the secure element has access to the key material and can perform operations on the key, while the core only manipulates a wrapped form of the key or an identifier of the key. + +### Creating a key in a secure element + +The core defines a compile-time constant for each opaque driver indicating its location called `PSA_KEY_LOCATION_`*prefix* where *prefix* is the value of the `"prefix"` property in the driver description. For convenience, Mbed TLS also declares a compile-time constant for the corresponding lifetime with the default persistence called `PSA_KEY_LIFETIME_`*prefix*. Therefore, to declare an opaque key in the location with the prefix `foo` with the default persistence, call `psa_set_key_lifetime` during the key creation as follows: +``` +psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_foo); +``` + +To declare a volatile key: +``` +psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( + PSA_KEY_LOCATION_foo, + PSA_KEY_PERSISTENCE_VOLATILE)); +``` + +Generally speaking, to declare a key with a specified persistence: +``` +psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( + PSA_KEY_LOCATION_foo, + persistence)); +``` + +## Open questions + +### Value representation + +#### Integers + +It would be better if there was a uniform requirement on integer values. Do they have to be JSON integers? C preprocessor integers (which could be e.g. a macro defined in some header file)? C compile-time constants (allowing `sizeof`)? + +This choice is partly driven by the use of the values, so they might not be uniform. Note that if the value can be zero and it's plausible that the core would want to statically allocate an array of the given size, the core needs to know whether the value is 0 so that it could use code like +``` +#if ACME_FOO_SIZE != 0 + uint8_t foo[ACME_FOO_SIZE]; +#endif +``` + +### Driver declarations + +#### Declaring driver entry points + +The core may want to provide declarations for the driver entry points so that it can compile code using them. At the time of writing this paragraph, the driver headers must define types but there is no obligation for them to declare functions. The core knows what the function names and argument types are, so it can generate prototypes. + +It should be ok for driver functions to be function-like macros or function pointers. + +#### Driver location values + +How does a driver author decide which location values to use? It should be possible to combine drivers from different sources. Use the same vendor assignment as for PSA services? + +Can the driver assembly process generate distinct location values as needed? This can be convenient, but it's also risky: if you upgrade a device, you need the location values to be the same between builds. + +The current plan is for Arm to maintain a registry of vendors and assign a location namespace to each vendor. Parts of the namespace would be reserved for implementations and integrators. + +#### Multiple transparent drivers + +When multiple transparent drivers implement the same mechanism, which one is called? The first one? The last one? Unspecified? Or is this an error (excluding capabilities with fallback enabled)? + +The current choice is that the first one is used, which allows having a preference order on drivers, but may mask integration errors. + +### Driver function interfaces + +#### Driver function parameter conventions + +Should 0-size buffers be guaranteed to have a non-null pointers? + +Should drivers really have to cope with overlap? + +Should the core guarantee that the output buffer size has the size indicated by the applicable buffer size macro (which may be an overestimation)? + +#### Key derivation inputs and buffer ownership + +Why is `psa_crypto_driver_key_derivation_get_input_bytes` a copy, rather than giving a pointer? + +The main reason is to avoid complex buffer ownership. A driver entry point does not own memory after the entry point return. This is generally necessary because an API function does not own memory after the entry point returns. In the case of key derivation inputs, this could be relaxed because the driver entry point is making callbacks to the core: these functions could return a pointer that is valid until the driver entry point returns, which would allow the driver to process the data immediately (e.g. hash it rather than copy it). + +### Partial computations in drivers + +#### Substitution points + +Earlier drafts of the driver interface had a concept of _substitution points_: places in the calculation where a driver may be called. Some hardware doesn't do the whole calculation, but only the “main” part. This goes both for transparent and opaque drivers. Some common examples: + +* A processor that performs the RSA exponentiation, but not the padding. The driver should be able to leverage the padding code in the core. +* A processor that performs a block cipher operation only for a single block, or only in ECB mode, or only in CTR mode. The core would perform the block mode (CBC, CTR, CCM, ...). + +This concept, or some other way to reuse portable code such as specifying inner functions like `psa_rsa_pad` in the core, should be added to the specification. + +### Key management + +#### Mixing drivers in key derivation + +How does `psa_key_derivation_output_key` work when the extraction part and the expansion part use different drivers? + +#### Public key calculation + +ECC key pairs are represented as the private key value only. The public key needs to be calculated from that. Both transparent drivers and opaque drivers provide a function to calculate the public key (`"export_public_key"`). + +The specification doesn't mention when the public key might be calculated. The core may calculate it on creation, on demand, or anything in between. Opaque drivers have a choice of storing the public key in the key context or calculating it on demand and can convey whether the core should store the public key with the `"store_public_key"` property. Is this good enough or should the specification include non-functional requirements? + +#### Symmetric key validation with transparent drivers + +Should the entry point be called for symmetric keys as well? + +#### Support for custom import formats + +[“Driver entry points for key management”](#driver-entry-points-for-key-management) states that the input to `"import_key"` can be an implementation-defined format. Is this a good idea? It reduces driver portability, since a core that accepts a custom format would not work with a driver that doesn't accept this format. On the other hand, if a driver accepts a custom format, the core should let it through because the driver presumably handles it more efficiently (in terms of speed and code size) than the core could. + +Allowing custom formats also causes a problem with import: the core can't know the size of the key representation until it knows the bit-size of the key, but determining the bit-size of the key is part of the job of the `"import_key"` entry point. For standard key types, this could plausibly be an issue for RSA private keys, where an implementation might accept a custom format that omits the CRT parameters (or that omits *d*). + +### Opaque drivers + +#### Opaque driver persistent state + +The driver is allowed to update the state at any time. Is this ok? + +An example use case for updating the persistent state at arbitrary times is to renew a key that is used to encrypt communications between the application processor and the secure element. + +`psa_crypto_driver_get_persistent_state` does not identify the calling driver, so the driver needs to remember which driver it's calling. This may require a thread-local variable in a multithreaded core. Is this ok? + +#### Open questions around cooked key derivation + +`"derive_key"` is not a clear name. Can we use a better one? + +For the `"derive_key"` entry point, how does the core choose `input_length`? Doesn't the driver know better? Should there be a driver entry point to determine the length, or should there be a callback that allows the driver to retrieve the input? Note that for some key types, it's impossible to predict the amount of input in advance, because it depends on some complex calculation or even on random data, e.g. if doing a randomized pseudo-primality test. However, for all key types except RSA, the specification mandates how the key is derived, which practically dictates how the pseudorandom key stream is consumed. So it's probably ok. + +#### Fallback for key derivation in opaque drivers + +Should [dispatch to an opaque driver](#key-derivation-driver-dispatch-logic) allow fallback, so that if `"key_derivation_setup"` returns `PSA_ERROR_NOT_SUPPORTED` then the core exports the key from the secure element instead? + +Should the ["`key_derivation_output_key`"](#key-derivation-driver-outputs) capability indicate which key types the driver can derive? How should fallback work? For example, consider a secure element that implements HMAC, HKDF and ECDSA, and that can derive an HMAC key from HKDF without exporting intermediate material but can only import or randomly generate ECC keys. How does this driver convey that it can't derive an ECC key with HKDF, but it can let the core do this and import the resulting key? + +### Randomness + +#### Input to `"add_entropy"` + +Should the input to the [`"add_entropy"` entry point](#entropy-injection) be a full-entropy buffer (with data from all entropy sources already mixed), raw entropy direct from the entropy sources, or give the core a choice? + +* Raw data: drivers must implement entropy mixing. `"add_entropy"` needs an extra parameter to indicate the amount of entropy in the data. The core must not do any conditioning. +* Choice: drivers must implement entropy mixing. `"add_entropy"` needs an extra parameter to indicate the amount of entropy in the data. The core may do conditioning if it wants, but doesn't have to. +* Full entropy: drivers don't need to do entropy mixing. + +#### Flags for `"get_entropy"` + +Are the [entropy collection flags](#entropy-collection-flags) well-chosen? + +#### Random generator instantiations + +May the core instantiate a random generation context more than once? In other words, can there be multiple objects of type `acme_random_context_t`? + +Functionally, one RNG is as good as any. If the core wants some parts of the system to use a deterministic generator for reproducibility, it can't use this interface anyway, since the RNG is not necessarily deterministic. However, for performance on multiprocessor systems, a multithreaded core could prefer to use one RNG instance per thread. + + diff --git a/tf-psa-crypto/docs/proposed/psa-driver-wrappers-codegen-migration-guide.md b/tf-psa-crypto/docs/proposed/psa-driver-wrappers-codegen-migration-guide.md new file mode 100644 index 0000000000..f9b108ddfd --- /dev/null +++ b/tf-psa-crypto/docs/proposed/psa-driver-wrappers-codegen-migration-guide.md @@ -0,0 +1,40 @@ +Migrating to an auto generated psa_crypto_driver_wrappers.h file +================================================================ + +This document describes how to migrate to the auto generated psa_crypto_driver_wrappers.h file. +It is meant to give the library user migration guidelines while the Mbed TLS project tides over multiple minor revs of version 1.0, after which this will be merged into psa-driver-interface.md. + +For a practical guide with a description of the current state of drivers Mbed TLS, see our [PSA Cryptoprocessor driver development examples](../psa-driver-example-and-guide.md). + +## Introduction + +The design of the Driver Wrappers code generation is based on the design proposal https://github.com/Mbed-TLS/mbedtls/pull/5067 +During the process of implementation there might be minor variations wrt versioning and broader implementation specific ideas, but the design remains the same. + +## Prerequisites + +Python3, Jinja2 rev 2.10.1 and jsonschema rev 3.2.0 + +## Feature Version + +1.1 + +### What's critical for a migrating user + +The Driver Wrapper auto generation project is designed to use a python templating library ( Jinja2 ) to render templates based on drivers that are defined using a Driver description JSON file(s). + +While that is the larger goal, for version 1.1 here's what's changed + +#### What's changed + +(1) psa_crypto_driver_wrappers.h will from this point on be auto generated. +(2) The auto generation is based on the template file at **scripts/data_files/driver_templates/psa_crypto_driver_wrappers.h.jinja**. +(3) The driver JSONS to be used for generating the psa_crypto_driver_wrappers.h file can be found at **scripts/data_files/driver_jsons/** as their default location, this path includes the schemas against which the driver schemas will be validated (driver_opaque_schema.json, driver_transparent_schema.json) and a driverlist.json which specifies the drivers to be considered and the order in which they want to be called into. The default location for driverlist.json and driver JSONS can be overloaded by passing an argument --json-dir while running the script generate_driver_wrappers.py. +(4) While the complete driver wrapper templating support is yet to come in, if the library user sees a need to patch psa_crypto_driver_wrappers.h file, the user will need to patch into the template file as needed (psa_crypto_driver_wrappers.h.jinja). + +#### How to set your driver up + +Please refer to psa-driver-interface.md for information on how a driver schema can be written. +One can also refer to the example test drivers/ JSON schemas under **scripts/data_files/driver_jsons/**. + +The JSON file 'driverlist.json' is meant to be edited by the user to reflect the drivers one wants to use on a device. The order in which the drivers are passed is also essential if/when there are multiple transparent drivers on a given system to retain the same order in the templating. diff --git a/tf-psa-crypto/docs/psa-driver-example-and-guide.md b/tf-psa-crypto/docs/psa-driver-example-and-guide.md new file mode 100644 index 0000000000..b392a85e0a --- /dev/null +++ b/tf-psa-crypto/docs/psa-driver-example-and-guide.md @@ -0,0 +1,179 @@ +# PSA Cryptoprocessor driver development examples + +As of Mbed TLS 3.4.0, the PSA Driver Interface has only been partially implemented. As a result, the deliverables for writing a driver and the method for integrating a driver with Mbed TLS will vary depending on the operation being accelerated. This document describes how to write and integrate cryptoprocessor drivers depending on which operation or driver type is being implemented. + +The `docs/proposed/` directory contains three documents which pertain to the proposed, work-in-progress driver system. The [PSA Driver Interface](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-interface.md) describes how drivers will interface with Mbed TLS in the future, as well as driver types, operation types, and entry points. As many key terms and concepts used in the examples in this document are defined in the PSA Driver Interface, it is recommended that developers read it prior to starting work on implementing drivers. +The PSA Driver [Developer](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-developer-guide.md) Guide describes the deliverables for writing a driver that can be used with Mbed TLS, and the PSA Driver [Integration](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-integration-guide.md) Guide describes how a driver can be built alongside Mbed TLS. + +## Contents: +[Background on how Mbed TLS calls drivers](#background-on-how-mbed-tls-calls-drivers)\ +[Process for Entry Points where auto-generation is implemented](#process-for-entry-points-where-auto-generation-is-implemented) \ +[Process for Entry Points where auto-generation is not implemented](#process-for-entry-points-where-auto-generation-is-not-implemented) \ +[Example: Manually integrating a software accelerator alongside Mbed TLS](#example-manually-integrating-a-software-accelerator-alongside-mbed-tls) + +## Background on how Mbed TLS calls drivers + +The PSA Driver Interface specification specifies which cryptographic operations can be accelerated by third-party drivers. Operations that are completed within one step (one function call), such as verifying a signature, are called *Single-Part Operations*. On the other hand, operations that consist of multiple steps implemented by different functions called sequentially are called *Multi-Part Operations*. Single-part operations implemented by a driver will have one entry point, while multi-part operations will have multiple: one for each step. + +There are two types of drivers: *transparent* or *opaque*. See below an excerpt from the PSA Driver Interface specification defining them: +* **Transparent** drivers implement cryptographic operations on keys that are provided in cleartext at the beginning of each operation. They are typically used for hardware **accelerators**. When a transparent driver is available for a particular combination of parameters (cryptographic algorithm, key type and size, etc.), it is used instead of the default software implementation. Transparent drivers can also be pure software implementations that are distributed as plug-ins to a PSA Cryptography implementation (for example, an alternative implementation with different performance characteristics, or a certified implementation). +* **Opaque** drivers implement cryptographic operations on keys that can only be used inside a protected environment such as a **secure element**, a hardware security module, a smartcard, a secure enclave, etc. An opaque driver is invoked for the specific [key location](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-interface.md#lifetimes-and-locations) that the driver is registered for: the dispatch is based on the key's lifetime. + +Mbed TLS contains a **driver dispatch layer** (also called a driver wrapper layer). For each cryptographic operation that supports driver acceleration (or sub-part of a multi-part operation), the library calls the corresponding function in the driver wrapper. Using flags set at compile time, the driver wrapper ascertains whether any present drivers support the operation. When no such driver is present, the built-in library implementation is called as a fallback (if allowed). When a compatible driver is present, the driver wrapper calls the driver entry point function provided by the driver author. + +The long-term goal is for the driver dispatch layer to be auto-generated using a JSON driver description file provided by the driver author. +For some cryptographic operations, this auto-generation logic has already been implemented. When accelerating these operations, the instructions in the above documents can be followed. For the remaining operations which do not yet support auto-generation of the driver wrapper, developers will have to manually edit the driver dispatch layer and call their driver's entry point functions from there. + +Auto-generation of the driver wrapper is supported for the operation entry points specified in the table below. Certain operations are only permitted for opaque drivers. All other operation entry points do not support auto-generation of the driver wrapper. + +| Transparent Driver | Opaque Driver | +|---------------------|---------------------| +| `import_key` | `import_key` | +| `export_public_key` | `export_public_key` | +| | `export_key` | +| | `copy_key` | +| | `get_builtin_key` | + +### Process for Entry Points where auto-generation is implemented + +If the driver is accelerating operations whose entry points are in the above table, the instructions in the driver [developer](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-developer-guide.md) and [integration](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-integration-guide.md) guides should be followed. + +There are three deliverables for creating such a driver. These are: + - A driver description file (in JSON format). + - C header files defining the types required by the driver description. The names of these header files are declared in the driver description file. + - An object file compiled for the target platform defining the functions required by the driver description. Implementations may allow drivers to be provided as source files and compiled with the core instead of being pre-compiled. + +The Mbed TLS driver tests for the aforementioned entry points provide examples of how these deliverables can be implemented. For sample driver description JSON files, see [`mbedtls_test_transparent_driver.json`](https://github.com/Mbed-TLS/mbedtls/blob/development/tf-psa-crypto/scripts/data_files/driver_jsons/mbedtls_test_transparent_driver.json) or [`mbedtls_test_opaque_driver.json`](https://github.com/Mbed-TLS/mbedtls/blob/development/tf-psa-crypto/scripts/data_files/driver_jsons/mbedtls_test_transparent_driver.json). The header file required by the driver description is [`test_driver.h`](https://github.com/Mbed-TLS/mbedtls/blob/development/framework/tests/include/test/drivers/test_driver.h). As Mbed TLS tests are built from source, there is no object file for the test driver. However, the source for the test driver can be found under `framework/tests/src/drivers`. + +### Process for Entry Points where auto-generation is not implemented + +If the driver is accelerating operations whose entry points are not present in the table, a different process is followed where the developer manually edits the driver dispatch layer. The following steps describe this process. Steps 1, 2, 3, and 7 only need to be done once *per driver*. Steps 4, 5, and 6 must be done *for each single-part operation* or *for each sub-part of a multi-part operation* implemented by the driver. + +**1. Choose a driver prefix and a macro name that indicates whether the driver is enabled** \ +A driver prefix is simply a word (often the name of the driver) that all functions/macros associated with the driver should begin with. This is similar to how most functions/macros in Mbed TLS begin with `PSA_XXX/psa_xxx` or `MBEDTLS_XXX/mbedtls_xxx`. The macro name can follow the form `DRIVER_PREFIX_ENABLED` or something similar; it will be used to indicate the driver is available to be called. When building with the driver present, define this macro at compile time. + +**2. Include the following in one of the driver header files:** +``` +#if defined(DRIVER_PREFIX_ENABLED) +#ifndef PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT +#define PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT +#endif + +// other definitions here + +#endif +``` + +**3. Conditionally include header files required by the driver** +Include any header files required by the driver in `psa_crypto_driver_wrappers.h`, placing the `#include` statements within an `#if defined` block which checks if the driver is available: +``` +#if defined(DRIVER_PREFIX_ENABLED) +#include ... +#endif +``` + + +**4. For each operation being accelerated, locate the function in the driver dispatch layer that corresponds to the entry point of that operation.** \ +The file `psa_crypto_driver_wrappers.h.jinja` and `psa_crypto_driver_wrappers_no_static.c.jinja` contains the driver wrapper functions. For the entry points that have driver wrapper auto-generation implemented, the functions have been replaced with `jinja` templating logic. While the file has a `.jinja` extension, the driver wrapper functions for the remaining entry points are simple C functions. The names of these functions are of the form `psa_driver_wrapper` followed by the entry point name. So, for example, the function `psa_driver_wrapper_sign_hash()` corresponds to the `sign_hash` entry point. + +**5. If a driver entry point function has been provided then ensure it has the same signature as the driver wrapper function.** \ +If one has not been provided then write one. Its name should begin with the driver prefix, followed by transparent/opaque (depending on driver type), and end with the entry point name. It should have the same signature as the driver wrapper function. The purpose of the entry point function is to take arguments in PSA format for the implemented operation and return outputs/status codes in PSA format. \ +*Return Codes:* +* `PSA_SUCCESS`: Successful Execution +* `PSA_ERROR_NOT_SUPPORTED`: Input arguments are correct, but the driver does not support the operation. If a transparent driver returns this then it allows fallback to another driver or software implementation. +* `PSA_ERROR_XXX`: Any other PSA error code, see API documentation + +**6. Modify the driver wrapper function** \ +Each driver wrapper function contains a `switch` statement which checks the location of the key. If the key is stored in local storage, then operations are performed by a transparent driver. If it is stored elsewhere, then operations are performed by an opaque driver. + * **Transparent drivers:** Calls to driver entry points go under `case PSA_KEY_LOCATION_LOCAL_STORAGE`. + * **Opaque Drivers** Calls to driver entry points go in a separate `case` block corresponding to the key location. + + +The diagram below shows the layout of a driver wrapper function which can dispatch to two transparent drivers `Foo` and `Bar`, and one opaque driver `Baz`. + + ``` +psa_driver_wrapper_xxx() +├── switch(location) +| | +| ├── case PSA_KEY_LOCATION_LOCAL_STORAGE //transparent driver +| | ├── #if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +| | | ├── #if defined(FOO_DRIVER_PREFIX_ENABLED) +| | | | ├── if(//conditions for foo driver capibilities) +| | | | ├── foo_driver_transparent_xxx() //call to driver entry point +| | | | ├── if (status != PSA_ERROR_NOT_SUPPORTED) return status +| | | ├── #endif +| | | ├── #if defined(BAR_DRIVER_PREFIX_ENABLED) +| | | | ├── if(//conditions for bar driver capibilities) +| | | | ├── bar_driver_transparent_xxx() //call to driver entry point +| | | | ├── if (status != PSA_ERROR_NOT_SUPPORTED) return status +| | | ├── #endif +| | ├── #endif +| | +| ├── case SECURE_ELEMENT_LOCATION //opaque driver +| | ├── #if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) +| | | ├── #if defined(BAZ_DRIVER_PREFIX_ENABLED) +| | | | ├── if(//conditions for baz driver capibilities) +| | | | ├── baz_driver_opaque_xxx() //call to driver entry point +| | | | ├── if (status != PSA_ERROR_NOT_SUPPORTED) return status +| | | ├── #endif +| | ├── #endif +└── return psa_xxx_builtin() // fall back to built in implementation + ``` + +All code related to driver calls within each `case` must be contained between `#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)` and a corresponding `#endif`. Within this block, each individual driver's compatibility checks and call to the entry point must be contained between `#if defined(DRIVER_PREFIX_ENABLED)` and a corresponding `#endif`. Checks that involve accessing key material using PSA macros, such as determining the key type or number of bits, must be done in the driver wrapper. + +**7. Build Mbed TLS with the driver** +This guide assumes you are building Mbed TLS from source alongside your project. If building with a driver present, the chosen driver macro (`DRIVER_PREFIX_ENABLED`) must be defined. This can be done in two ways: +* *At compile time via flags.* This is the preferred option when your project uses Mbed TLS mostly out-of-the-box without significantly modifying the configuration. This can be done by passing the option via `CFLAGS`. + * **Make**: + ``` + make CFLAGS="-DDRIVER_PREFIX_ENABLED" + ``` + * **CMake**: CFLAGS must be passed to CMake when it is invoked. Invoke CMake with + + ``` + CFLAGS="-DDRIVER_PREFIX_ENABLED" cmake path/to/source + ``` +* *Providing a user config file.* This is the preferred option when your project requires a custom configuration that is significantly different to the default. Define the macro for the driver, along with any other custom configurations in a separate header file, then use `config.py`, to set `MBEDTLS_USER_CONFIG_FILE`, providing the path to the defined header file. This will include your custom config file after the default. If you wish to completely replace the default config file, set `MBEDTLS_CONFIG_FILE` instead. + +### Example: Manually integrating a software accelerator alongside Mbed TLS + +[p256-m](https://github.com/mpg/p256-m) is a minimalistic implementation of ECDH and ECDSA on the NIST P-256 curve, specifically optimized for use in constrained 32-bit environments. It started out as an independent project and has been integrated in Mbed TLS as a PSA transparent driver. The source code of p256-m and the driver entry points is located in the Mbed TLS source tree under `drivers/p256-m`. In this section, we will look at how this integration was done. + +The Mbed TLS build system includes the instructions needed to build p256-m. To build with and use p256-m, set the macro `MBEDTLS_PSA_P256M_DRIVER_ENABLED` using `config.py`, then build as usual using make/cmake. From the root of the `mbedtls/` directory, run: + + python3 scripts/config.py set MBEDTLS_PSA_P256M_DRIVER_ENABLED + make + +(You need extra steps if you want to disable the built-in implementation of ECC algorithms, which includes more features than p256-m. Refer to the documentation of `MBEDTLS_PSA_P256M_DRIVER_ENABLED` and [`driver-only-builds.md`](driver-only-builds.md) for more information.) + +The driver prefix for p256-m is `P256`/`p256`. +The p256-m driver implements the following entry points: `"import_key"`, `"export_public_key"`, `"generate_key"`, `"key_agreement"`, `"sign_hash"`, `"verify_hash"`. +There are no entry points for `"sign_message"` and `"verify_message"`, which are not necessary for a sign-and-hash algorithm. The core still implements these functions by doing the hashes and then calling the sign/verify-hash entry points. +The driver entry point functions can be found in `p256m_driver_entrypoints.[hc]`. These functions act as an interface between Mbed TLS and p256-m; converting between PSA and p256-m argument formats and performing sanity checks. If the driver's status codes differ from PSA's, it is recommended to implement a status code translation function. The function `p256_to_psa_error()` converts error codes returned by p256-m into PSA error codes. + +The driver wrapper functions in `psa_crypto_driver_wrappers.h.jinja` for all four entry points have also been modified. The code block below shows the additions made to `psa_driver_wrapper_sign_hash()`. In adherence to the defined process, all code related to the driver call is placed within a check for `MBEDTLS_PSA_P256M_DRIVER_ENABLED`. p256-m only supports non-deterministic ECDSA using keys based on NIST P256; these constraints are enforced through checks (see the `if` statement). Checks that involve accessing key attributes, (e.g. checking key type or bits) **must** be performed in the driver wrapper. This is because this information is marked private and may not be accessed outside the library. Other checks can be performed here or in the entry point function. The status returned by the driver is propagated up the call hierarchy **unless** the driver does not support the operation (i.e. return `PSA_ERROR_NOT_SUPPORTED`). In that case the next available driver/built-in implementation is called. + +``` +#if defined (MBEDTLS_PSA_P256M_DRIVER_ENABLED) + if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) && + PSA_ALG_IS_ECDSA(alg) && + !PSA_ALG_ECDSA_IS_DETERMINISTIC( alg ) && + PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)) == PSA_ECC_FAMILY_SECP_R1 && + psa_get_key_bits(attributes) == 256 ) + { + status = p256_transparent_sign_hash( attributes, + key_buffer, + key_buffer_size, + alg, + hash, + hash_length, + signature, + signature_size, + signature_length ); + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); + } +#endif /* MBEDTLS_PSA_P256M_DRIVER_ENABLED */ +``` +Following this, p256-m is now ready to use alongside Mbed TLS as a software accelerator. If `MBEDTLS_PSA_P256M_DRIVER_ENABLED` is set in the config, p256-m's implementations of key generation, ECDH, and ECDSA will be used where applicable. diff --git a/tf-psa-crypto/docs/psa-transition.md b/tf-psa-crypto/docs/psa-transition.md new file mode 100644 index 0000000000..89208fc9de --- /dev/null +++ b/tf-psa-crypto/docs/psa-transition.md @@ -0,0 +1,1330 @@ +# Transitioning to the PSA API + +> I have code written for `mbedtls_` cryptography APIs. How do I migrate to `psa_` APIs? + +## Introduction + +TF-PSA-Crypto, the successor of Mbed TLS 3.x for cryptography, replaces most `mbedtls_xxx` cryptography APIs with newer `psa_xxx` APIs. This guide is intended to help migrate existing applications that used Mbed TLS for cryptography. It aims to cover common use cases, but cannot cover all possible scenarios. + +### Suggested reading + +This document is long, but you probably don't need to read all of it. You should start with the following sections: + +1. [Where can I find documentation?](#where-can-i-find-documentation) +2. [General considerations](#general-considerations) + +Then use the [summary of API modules](#summary-of-api-modules), the table of contents or a text search to locate the sections that interest you, based on what legacy interfaces your code is currently using. + +### Where can I find documentation? + +**Tutorial**: See the [getting started guide](https://mbed-tls.readthedocs.io/en/latest/getting_started/psa/). + +**Reference**: The [PSA Crypto API specification](https://arm-software.github.io/psa-api/crypto/) is available online. TF-PSA-Crypto implements a large subset of the specification which is documented in the [`psa/crypto*.h` headers](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto_8h/). + +### Additional resources + +* [TF-PSA-Crypto open issues](https://github.com/Mbed-TLS/TF-PSA-Crypto/issues) (some [Mbed TLS issues](https://github.com/Mbed-TLS/mbedtls/issues) may also still be relevant) +* [PSA API open issues](https://github.com/ARM-software/psa-api/issues) (not just cryptography APIs) +* [Mbed TLS mailing list](https://lists.trustedfirmware.org/mailman3/lists/mbed-tls.lists.trustedfirmware.org/) (also covers TF-PSA-Crypto) + +### Why change the API? + +* Mbed TLS APIs are traditionally very transparent: the caller can access internal fields of operations. This is less true in the 3.x major version than before, but still the case to some extent. This offers applications some flexibility, but it removes flexibility from the implementation. For example, it is hard to support hardware acceleration, because the API constrains how the data must be represented. PSA APIs were designed to be more opaque, giving more freedom to the implementation. +* Mbed TLS legacy APIs require key material to be present in the application memory. The PSA Crypto API natively supports operations on keys stored in an external [location](https://arm-software.github.io/psa-api/crypto/1.1/api/keys/lifetimes.html#c.psa_key_location_t) (secure enclave, secure element, HSM, etc.). +* PSA APIs have [consistent conventions](https://arm-software.github.io/psa-api/crypto/1.1/overview/conventions.html#parameter-conventions) which many legacy APIs in Mbed TLS do not follow. For example, many legacy cryptography functions require the caller to know how large an output buffer needs to be based on the selected algorithm, whereas in the PSA API, all buffer arguments have a well-defined size and those sizes are checked. +* Mbed TLS legacy APIs require passing around a random generator argument where needed. This has historically been problematic with functions that were created without an RNG argument but later needed one as part of a security countermeasure. The PSA crypto subsystem maintains a global random generator, resolving this problem. + +### Migration timeline + +* Mbed TLS 2.15.0 (Nov 2018): first release with a draft implementation of the PSA API. +* Mbed TLS 2.18.0 (Jun 2019): The PSA API is available in the default build. +* Mbed TLS 3.1.0 (Dec 2021): TLS 1.3 support is the first major feature that requires the PSA API. +* TF-PSA-Crypto 1.0.0 (Oct 2025): Removal of most legacy crypto APIs. Drop support for builds without the PSA subsystem and for legacy configuration of cryptographic mechanisms. + The corresponding release Mbed TLS 4.0.0 drops support for cryptography calls that bypass PSA. +* TF-PSA-Crypto 2.0.0 (??): Removal of the remaining non-PSA crypto APIs. + +### Compatibility with Mbed TLS 3.6 + +Most of the new APIs suggested in this document are already present in Mbed TLS in the [3.6 long-time support branch](https://github.com/Mbed-TLS/mbedtls/tree/mbedtls-3.6). This document should indicate which features were added in TF-PSA-Crypto 1.x. However, if your application needs to be compatible with both Mbed TLS 3.6 and TF-PSA-Crypto 1.x, we invite you to consult the [PSA transition guide for Mbed TLS 3.6](https://github.com/Mbed-TLS/mbedtls/blob/mbedtls-3.6/docs/psa-transition.md). + +## General considerations + +### Configuration of the PSA subsystem + +To make the PSA cryptography API available, make sure that the configuration option [`MBEDTLS_PSA_CRYPTO_C`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/mbedtls__config_8h/#c.MBEDTLS_PSA_CRYPTO_C) is enabled. (It is enabled in the default configuration.) + +PSA uses a different set of configuration symbols to express which cryptographic mechanisms are enabled in the build. See the section “[Cryptographic mechanism availability](#cryptographic-mechanism-availability)”. If you are migrating from a configuration where `MBEDTLS_PSA_CRYPTO_CONFIG` is enabled, or if you are mostly relying on the default configuration for cryptography, there will be few or no changes between Mbed TLS 3.6 and TF-PSA-Crypto 1.0. But if you were explicitly specifying a set of cryptographic mechanisms using `MBEDTLS_xxx` options, you will need to migrate your configuration to the new mechanism. + +Note that in Mbed TLS 3.x, the whole library configuration could be in `mbedtls/mbedtls_config.h` (or `MBEDTLS_CONFIG_FILE`) plus optionally `MBEDTLS_USER_CONFIG_FILE`. In TF-PSA-Crypto, the configuration must be in `psa/crypto_config.h` (or `TF_PSA_CRYPTO_CONFIG_FILE`) plus optionally `TF_PSA_CRYPTO_USER_CONFIG_FILE`. + +The Mbed TLS 4.x configuration file should not try to modify any option consumed by TF-PSA-Crypto: this would make Mbed TLS's use of cryptography inconsistent with what the crypto library provides. However, it is ok to redundantly set a TF-PSA-Crypto option in the Mbed TLS configuration if it was already set to the same value in the TF-PSA-Crypto configuration; this allows using the same file as `TF_PSA_CRYPTO_CONFIG_FILE` and `MBEDTLS_CONFIG_FILE`. + +### Header files + +Applications only need to include a single header file for all cryptographic mechanisms: +``` +#include +``` + +Note that you may want to keep other crypto header files for functionality that is not provided by the PSA API, such as `` for NIST KW/KWP (not yet exposed through PSA), `` for key pair and public key parsing and formatting, `` for ASN.1 parsing, etc. + +### General application layout + +Before any cryptographic operation, call [`psa_crypto_init`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__initialization/#group__initialization_1ga2de150803fc2f7dc6101d5af7e921dd9) and check that it succeeds. (A failure indicates an abnormal system state from which most applications cannot recover.) + +If you wish to free all resources associated with PSA cryptography, call [`mbedtls_psa_crypto_free`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__extra_8h/#_CPPv423mbedtls_psa_crypto_freev). + +The PSA subsystem has an internal random generator. As a consequence, you do not need to instantiate one manually (no need to create an `mbedtls_entropy_context` and an `mbedtls_xxx_drbg_context`). + +### Error codes + +Mbed TLS functions return a status of type `int`: 0 for success (or occasionally a positive value which is the output length), or a negative value, traditionally `MBEDTLS_ERR_xxx`, indicating an error. + +PSA functions return a status of type [`psa_status_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__error/#group__error_1ga05676e70ba5c6a7565aff3c36677c1f9): `PSA_SUCCESS == 0` for success, or a negative value [`PSA_ERROR_xxx`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__error/) indicating an error. + +In Mbed TLS 3.x, there is no overlap between `MBEDTLS_ERR_xxx` values and `PSA_ERROR_xxx` values. Thus applications that propagate error codes do not need to keep track of whether a value was initially reported as `psa_status_t` (`PSA_ERROR_xxx`) or `int` (Mbed TLS error codes). + +Since TF-PSA-Crypto 1.0, the error sets have been fully merged. Many former `MBEDTLS_ERR_xxx` error codes have been merged with `PSA_ERROR_xxx` error codes with similar semantics. Functions returning `int` can return `PSA_ERROR_xxx` values, and some `MBEDTLS_ERR_xxx` constants are now aliases to a `PSA_ERROR_xxx` value. This also applies to Mbed TLS 4.0 onwards. + +### Memory management + +Apart from keys, as described in “[Key management](#key-management)” below, APIs that need to preserve state between function calls store this state in a structure allocated by the calling code. For example, multipart operations store state in a multipart operation object. + +All PSA operation objects must be zero-initialized (or equivalently, initialized with the provided `PSA_XXX_INIT` macro or `psa_xxx_init()` function) before calling any API function. + +Functions that output data require an output buffer of sufficient size. For all PSA crypto API functions that have an output buffer, there is a corresponding macro, generally called `PSA_XXX_OUTPUT_SIZE`, that calculates a sufficient size for the output buffer, given the relevant parameters. In some cases, there may be macros with less precision which can be resolved at compile time. For example, for the size of a buffer containing a hash, you can use `PSA_HASH_LENGTH(hash_alg)` where `hash_alg` is a specific hash algorithm, or `PSA_HASH_MAX_SIZE` for a buffer that is long enough for any supported hash. See the relevant sections of this document and of the reference documentation for more details. + +#### Key management + +One of the major differences between the legacy API and the PSA API is that in the PSA API, access to keys is indirect. Operations that require a key take a parameter of type [`psa_key_id_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__types_8h/#_CPPv412psa_key_id_t), which is an identifier for the key. This allows the API to be used with keys that are not directly accessible to the application, for example because they are stored in a secure environment that does not allow the key material to be exported. + +To use a key: + +1. First create a key object with a key creation function. The two most common ones are [`psa_import_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga0336ea76bf30587ab204a8296462327b) if you have the key material available and [`psa_generate_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__random/#group__random_1ga1985eae417dfbccedf50d5fff54ea8c5) to create a random key. The key creation function has the key identifier as an output parameter. +2. Use the key as desired, passing the key identifier obtained during the key creation. +3. Finally destroy the key object with [`psa_destroy_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__management/#group__key__management_1ga5f52644312291335682fbc0292c43cd2). + +See “[Cipher key management](#cipher-key-management)”, “[MAC key management](#mac-key-management)”, “[Key lifecycle for asymmetric cryptography](#key-lifecycle-for-asymmetric-cryptography)”, “[Creating keys for asymmetric cryptography](#creating-keys-for-asymmetric-cryptography)” and “[Diffie-Hellman key pair management](#diffie-hellman-key-pair-management)” for more details about key management in specific workflows, including information about choosing the key's attributes. + +If you need access to the key material, call [`psa_export_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga668e35be8d2852ad3feeef74ac6f75bf). If you need the public key corresponding to a key pair object, call [`psa_export_public_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1gaf22ae73312217aaede2ea02cdebb6062). + +Note that a key consumes a key store entry, which is distinct from heap memory, until it is destroyed or the application exits. (This is not true for persistent keys, which instead consume disk space. Since persistent keys have no analog in the legacy API, we will not discuss them further in this document.) + +## Summary of API modules + +| Header | Function prefix | PSA equivalent | +| ------ | --------------- | -------------- | +| `aes.h` | `mbedtls_aes_` | [Symmetric encryption](#symmetric-encryption) | +| `aria.h` | `mbedtls_aria_` | [Symmetric encryption](#symmetric-encryption) | +| `asn1.h` | `mbedtls_asn1_` | No change ([PK format support interfaces](#pk-format-support-interfaces)) | +| `asn1write.h` | `mbedtls_asn1_write_` | No change ([PK format support interfaces](#pk-format-support-interfaces)) | +| `base64.h` | `mbedtls_base64_` | No change ([PK format support interfaces](#pk-format-support-interfaces)) | +| `bignum.h` | `mbedtls_mpi_` | None (no low-level arithmetic) | +| `build_info.h` | `MBEDTLS_` | Belongs in Mbed TLS, but see also `tf-psa-crypto/build_info.h` | +| `camellia.h` | `mbedtls_camellia_` | [Symmetric encryption](#symmetric-encryption) | +| `ccm.h` | `mbedtls_ccm_` | [Symmetric encryption](#symmetric-encryption), [Authenticated cipher operations](#authenticated-cipher-operations) | +| `chacha20.h` | `mbedtls_chacha20_` | [Symmetric encryption](#symmetric-encryption) | +| `chachapoly.h` | `mbedtls_chachapoly_` | [Symmetric encryption](#symmetric-encryption), [Authenticated cipher operations](#authenticated-cipher-operations) | +| `check_config.h` | N/A | No public APIs (internal support header) | +| `cipher.h` | `mbedtls_cipher_` | [Symmetric encryption](#symmetric-encryption) | +| `cmac.h` | `mbedtls_cipher_cmac_` | [Hashes and MAC](#hashes-and-mac), [MAC calculation](#mac-calculation) | +| `compat-2.x.h` | various | None (transitional APIs) | +| `config_psa.h` | N/A | No public APIs (internal support header) | +| `constant_time.h` | `mbedtls_ct_` | [Constant-time functions](#constant-time-functions) | +| `ctr_drbg.h` | `mbedtls_ctr_drbg_` | [Random generation interface](#random-generation-interface), [Deterministic pseudorandom generation](#deterministic-pseudorandom-generation) | +| `des.h` | `mbedtls_des_` | [Symmetric encryption](#symmetric-encryption) | +| `dhm.h` | `mbedtls_dhm_` | [Asymmetric cryptography](#asymmetric-cryptography) | +| `ecdh.h` | `mbedtls_ecdh_` | [Asymmetric cryptography](#asymmetric-cryptography) | +| `ecdsa.h` | `mbedtls_ecdsa_` | [Asymmetric cryptography](#asymmetric-cryptography) | +| `ecjpake.h` | `mbedtls_ecjpake_` | [EC-JPAKE](#ec-jpake) | +| `ecp.h` | `mbedtls_ecp_` | [Asymmetric cryptography](#asymmetric-cryptography) | +| `entropy.h` | `mbedtls_entropy_` | [Random generation interface](#random-generation-interface), [Entropy sources](#entropy-sources) | +| `error.h` | `mbedtls_*err*` | [Error messages](#error-messages) | +| `gcm.h` | `mbedtls_gcm_` | [Symmetric encryption](#symmetric-encryption), [Authenticated cipher operations](#authenticated-cipher-operations) | +| `hkdf.h` | `mbedtls_hkdf_` | [HKDF](#hkdf) | +| `hmac_drbg.h` | `mbedtls_hmac_drbg_` | [Random generation interface](#random-generation-interface), [Deterministic pseudorandom generation](#deterministic-pseudorandom-generation) | +| `lms.h` | `mbedtls_lms_` | No change ([LMS signatures](#lms-signatures)) | +| `mbedtls_config.h` | `MBEDTLS_` | [Compile-time configuration](#compile-time-configuration) | +| `md.h` | `mbedtls_md_` | [Hashes and MAC](#hashes-and-mac) | +| `md5.h` | `mbedtls_md5_` | [Hashes and MAC](#hashes-and-mac) | +| `memory_buffer_alloc.h` | `mbedtls_memory_buffer_alloc_` | No change (not a crypto API) | +| `nist_kw.h` | `mbedtls_nist_kw_` | [NIST KW and KWP](#nist-kw-and-kwp) | +| `oid.h` | `mbedtls_oid_` | [PK format support interfaces](#pk-format-support-interfaces) | +| `pem.h` | `mbedtls_pem_` | No change ([PK format support interfaces](#pk-format-support-interfaces)) | +| `pk.h` | `mbedtls_pk_` | [Asymmetric cryptography](#asymmetric-cryptography) | +| `pkcs5.h` | `mbedtls_pkcs5_` | [PKCS#5 module](#pkcs5-module) | +| `pkcs12.h` | `mbedtls_pkcs12_` | [PKCS#12 module](#pkcs12-module) | +| `platform.h` | `mbedtls_platform_` | No change (not a crypto API) | +| `platform_time.h` | `mbedtls_*time*` | No change (not a crypto API) | +| `platform_util.h` | `mbedtls_platform_` | No change (not a crypto API) | +| `poly1305.h` | `mbedtls_poly1305_` | None (but there is Chacha20-Poly1305 [AEAD](#symmetric-encryption)) | +| `private_access.h` | N/A | No public APIs (internal support header) | +| `psa_util.h` | various | No change (functions specific to removed legacy APIs have been removed in TF-PSA-Crypto 1.0) | +| `ripemd160.h` | `mbedtls_ripemd160_` | [Hashes and MAC](#hashes-and-mac) | +| `rsa.h` | `mbedtls_rsa_` | [Asymmetric cryptography](#asymmetric-cryptography) | +| `sha1.h` | `mbedtls_sha1_` | [Hashes and MAC](#hashes-and-mac) | +| `sha3.h` | `mbedtls_sha3_` | [Hashes and MAC](#hashes-and-mac) | +| `sha256.h` | `mbedtls_sha256_` | [Hashes and MAC](#hashes-and-mac) | +| `sha512.h` | `mbedtls_sha512_` | [Hashes and MAC](#hashes-and-mac) | +| `threading.h` | `mbedtls_threading_` | No change (not a crypto API) | + +## Compile-time configuration + +### Cryptographic mechanism availability + +#### Crypto configuration file + +The cryptographic mechanisms available through the PSA API are determined by the contents of the header file `"psa/crypto_config.h"`. You can override the file location with the macro [`TF_PSA_CRYPTO_CONFIG_FILE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/mbedtls__config_8h/#mbedtls__config_8h_1a25f7e358caa101570cb9519705c2b873), and you can set [`TF_PSA_CRYPTO_USER_CONFIG_FILE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/mbedtls__config_8h/#mbedtls__config_8h_1abd1870cc0d2681183a3018a7247cb137) to the path of an additional file (similar to `MBEDTLS_CONFIG_FILE` and `MBEDTLS_USER_CONFIG_FILE` for legacy configuration symbols). + +3.x note: `TF_PSA_CRYPTO_CONFIG_FILE` and `TF_PSA_CRYPTO_USER_CONFIG_FILE` were called `MBEDTLS_PSA_CRYPTO_CONFIG_FILE` and `MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE` respectively in Mbed TLS 3.x. + +#### General rules for `PSA_WANT_xxx` + +The availability of cryptographic mechanisms in the PSA API is based on a systematic pattern: + +* To make `PSA_ALG_aaa` available, enable `PSA_WANT_ALG_aaa`. + For parametrized algorithms, there is a `PSA_WANT_` symbol both for the main macro and for each argument. For example, to make `PSA_ALG_HMAC(PSA_ALG_SHA_256)` available, enable both `PSA_WANT_ALG_HMAC` and `PSA_WANT_ALG_SHA_256`. + +* To make `PSA_KEY_TYPE_ttt` available, enable `PSA_WANT_KEY_TYPE_ttt`. + + As an exception, starting in Mbed TLS 3.5.0, for key pair types, the feature selection is more fine-grained, with an additional suffix: + * `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_BASIC` enables basic support for the key type, and in particular support for operations with a key of that type for enabled algorithms. This is automatically enabled if any of the other `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_yyy` options are enabled. + * `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_IMPORT` enables support for `psa_import_key` to import a key of that type. + * `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_GENERATE` enables support for `psa_generate_key` to randomly generate a key of that type. + * `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_DERIVE` enables support for `psa_key_derivation_output_key` to deterministically derive a key of that type. + * `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_EXPORT` enables support for `psa_export_key` to export a key of that type. + + Enabling any support for a key pair type automatically enables support for the corresponding public key type, as well as support for `psa_export_public_key` on the private key. + +* To make `PSA_ECC_FAMILY_fff` available for size sss, enable `PSA_WANT_ECC_fff_sss`. + +Note that all `PSA_WANT_xxx` symbols must be set to a non-zero value. In particular, setting `PSA_WANT_xxx` to an empty value may not be handled consistently. + +#### A small `PSA_WANT` configuration example + +For example, the following configuration enables hashing with SHA-256, AEAD with AES-GCM, signature with deterministic ECDSA using SHA-256 on the curve secp256r1 using a randomly generated key as well as the corresponding verification, and ECDH key exchange on secp256r1 and Curve25519. + +``` +#define PSA_WANT_ALG_SHA_256 1 + +#define PSA_WANT_KEY_TYPE_AES 1 +#define PSA_WANT_ALG_GCM 1 + +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 +// ^^ implicitly enables PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC, PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY +#define PSA_WANT_ECC_SECP_R1_256 1 // secp256r1 (suitable for ECDSA and ECDH) +#define PSA_WANT_ECC_MONTGOMERY_255 1 // Curve25519 (suitable for ECDH) +#define PSA_WANT_ALG_DETERMINISTIC_ECDSA 1 +#define PSA_WANT_ALG_ECDH +``` + +#### Automatically translating legacy configurations + +If you have a working configuration file with legacy configuration options (i.e. an Mbed TLS 3.x configuration that did not enable `MBEDTLS_PSA_CRYPTO_CONFIG`), build **Mbed TLS 3.6** and run the program + +``` +programs/test/query_compile_time_config -l +``` + +(Note that you cannot use TF-PSA-Crypto for this: it would not recognize the legacy configuration options.) + +The lines with `PSA_WANT_...=1` should constitute a PSA configuration that is similar to your legacy configuration. That is, for every line `PSA_WANT_XXX=1` in the output of `query_compile_time_config -l`, make sure the line `#define PSA_WANT_XXX 1` is enabled in `include/psa/crypto_config.h` (or alternate `TF_PSA_CRYPTO_CONFIG_FILE`). You use the following bash/Linux/macOS shell snippet to automate this translation: + +``` +programs/test/query_compile_time_config -l | sed -n 's/^\(PSA_WANT_.*\)=1/#define \1/p' +``` + +Please review the result as the configuration may not be fully equivalent in all cases. It will generally provide at least the same features, but sometimes this translation results in more than desired. + +Note that this only generates the new selection of cryptographic mechanisms. You will also need to remove config lines that set legacy crypto options. Note also that TF-PSA-Crypto 1.0 has changed a few other options; see the [1.0 migration guide](1.0-migration-guide.md#configuration-of-tf-psa-crypto) for more information. + +#### Implicit activation of crypto features + +If a mechanism is not enabled by `PSA_WANT_xxx`, TF-PSA-Crypto will normally not include it. This allows builds that use few features to have a small code size. However, this is not guaranteed: a mechanism that is not explicitly requested can be enabled because it is a dependency of another configuration option, because it is used internally, or because the granularity is not fine enough to distinguish between it and another mechanism that is requested. + +These automatic enablement rules may change in future versions of TF-PSA-Crypto, so you should not rely on them. Declare what you use. + +### Optimization options + +When PSA Crypto mechanisms are implemented by the built-in code from TF-PSA-Crypto, the legacy optimization options (e.g. `MBEDTLS_SHA256_SMALLER`, `MBEDTLS_ECP_WINDOW_SIZE`, etc.) apply to the PSA implementation as well (they invoke the same code under the hood). + +The PSA Crypto API may use accelerator drivers. In this case any options controlling the driver behavior are driver-specific. + +### Alternative implementations (`MBEDTLS_xxx_ALT` options) + +In the Mbed TLS legacy interface, you can replace some cryptographic primitives and modes by an alternative implementation, by enabling configuration options of the form `MBEDTLS_xxx_ALT` and linking with your own implementation of the affected function or module. This feature does not exist in TF-PSA-Crypto. + +The corresponding PSA feature is accelerator drivers. To implement an accelerator driver, see the [PSA cryptoprocessor driver example and guide](https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/docs/psa-driver-example-and-guide.md). See the [Guide to driver-only builds](https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/docs/driver-only-builds.md) for more information. + +### Self-tests + +There is currently [no PSA equivalent to the self-tests](https://github.com/Mbed-TLS/mbedtls/issues/7781) enabled by `MBEDTLS_SELF_TEST`. + +## Miscellaneous support modules + +### Error messages + +As of TF-PSA-Crypto 1.0, there is no equivalent to the error messages provided by `mbedtls_strerror`. However, you can use the companion program `programs/psa/psa_constant_names` to convert various numbers (`psa_status_t`, `psa_algorithm_t`, `psa_key_type_t`, `psa_ecc_family_t`, `psa_dh_family_t`, `psa_key_usage_t`) to a programmer-friendly representation. The conversion doesn't depend on the library configuration or the target platform, so you can use a native build of this program even if you cross-compile your application. + +``` +$ programs/psa/psa_constant_names error -138 +PSA_ERROR_BUFFER_TOO_SMALL +$ programs/psa/psa_constant_names type 0x7112 +PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1) +$ programs/psa/psa_constant_names alg 0x06000609 +PSA_ALG_ECDSA(PSA_ALG_SHA_256) +``` + +Since TF-PSA-Crypto 1.0, legacy functions always return an `MBEDTLS_ERR_xxx` constant or a `psa_status_t` constant (`PSA_SUCCESS`, `PSA_OPERATION_INCOMPLETE` or `PSA_ERROR_xxx`). Functions no longer return values that are the sum of a “low-level” and a “high-level” error code. + +### Constant-time functions + +The PSA API does not have an equivalent to the timing-side-channel-resistance utility functions in `mbedtls/constant_time.h`. Continue using `mbedtls/constant_time.h` as needed. + +Note that the PSA API does include features that reduce the need for `mbedtls_ct_memcmp`: + +* To compare a MAC with a reference value, use `psa_mac_verify` rather than `psa_mac_compute` followed by `mbedtls_ct_memcmp`, or use `psa_mac_verify_setup` and `psa_mac_verify_finish` in the multi-part case. See “[MAC calculation](#mac-calculation)”. +* The AEAD decryption functions take care of verifying the tag. See “[Authenticated cipher operations](#authenticated-cipher-operations)”. + +## Symmetric encryption + +All PSA APIs have algorithm agility, where the functions depend only on the nature of the operation and the choice of a specific algorithm comes from an argument. There is no special API for a particular block cipher (`aes.h`, `aria.h`, `camellia.h`, `des.h`), a particular block cipher mode (`ccm.h`, `gcm.h`) or a particular stream cipher (`chacha20.h`, `chachapoly.h`). To migrate code using those low-level modules, please follow the recommendations in the following sections, using the same principles as the corresponding `cipher.h` API. + +### Cipher mechanism selection + +Instead of `mbedtls_cipher_id_t` (`MBEDTLS_CIPHER_ID_xxx` constants), `mbedtls_cipher_type_t` (`MBEDTLS_CIPHER_base_size_mode` constants), `mbedtls_cipher_mode_t` (`MBEDTLS_CIPHER_MODE_xxx` constants) and `mbedtls_cipher_padding_t` (`MBEDTLS_CIPHER_PADDING_xxx` constants), use the [`PSA_KEY_TYPE_xxx` and `PSA_ALG_xxx` constants](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/). + +For modes that are based on a block cipher, the key type encodes the choice of block cipher: +[`PSA_KEY_TYPE_AES`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga6ee54579dcf278c677eda4bb1a29575e), +[`PSA_KEY_TYPE_ARIA`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#c.PSA_KEY_TYPE_ARIA), +[`PSA_KEY_TYPE_CAMELLIA`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gad8e5da742343fd5519f9d8a630c2ed81), +[`PSA_KEY_TYPE_DES`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga577562bfbbc691c820d55ec308333138). +The algorithm encodes the mode and if relevant the padding type: + +* Unauthenticated cipher modes: + [`PSA_ALG_CTR`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gad318309706a769cffdc64e4c7e06b2e9), + [`PSA_ALG_CFB`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga0088c933e01d671f263a9a1f177cb5bc), + [`PSA_ALG_OFB`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gae96bb421fa634c6fa8f571f0112f1ddb), + [`PSA_ALG_XTS`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gaa722c0e426a797fd6d99623f59748125), + [`PSA_ALG_ECB_NO_PADDING`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gab8f0609cd0f12cccc9c950fd5a81a0e3), + [`PSA_ALG_CBC_NO_PADDING`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gacb332d72716958880ee7f97d8365ae66), + [`PSA_ALG_CBC_PKCS7`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gaef50d2e9716eb6d476046608e4e0c78c), + [`PSA_ALG_CCM_STAR_NO_TAG`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga89627bb27ec3ce642853ab8554a88572). +* Other padding modes, which are obsolete, are not available in the PSA API. If you need them, handle the padding in your application code and use the `NO_PADDING` algorithm. +* AEAD modes: + [`PSA_ALG_CCM`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gac2c0e7d21f1b2df5e76bcb4a8f84273c), + [`PSA_ALG_GCM`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga0d7d02b15aaae490d38277d99f1c637c). +* KW/KWP modes are not available in the PSA API at the time of writing. + +For the ChaCha20 unauthenticated cipher, use [`PSA_KEY_TYPE_CHACHA20`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga901548883b3bce56cc21c3a22cf8d93c) with [`PSA_ALG_STREAM_CIPHER`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gad98c105198f7428f7d1dffcb2cd398cd). +For the Chacha20+Poly1305 AEAD, use [`PSA_KEY_TYPE_CHACHA20`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga901548883b3bce56cc21c3a22cf8d93c) with [`PSA_ALG_CHACHA20_POLY1305`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga1fec55093541640a71bdd022d4adfb9c) + +### Cipher mechanism availability + +For each key type value `PSA_KEY_TYPE_xxx`, the symbol `PSA_WANT_KEY_TYPE_xxx` is defined with a non-zero value if the library is built with support for that key type. For each algorithm value `PSA_ALG_yyy`, the symbol `PSA_WANT_ALG_yyy` is defined with a non-zero value if the library is built with support for that algorithm. Note that for a mechanism to be supported, both the key type and the algorithm must be supported. + +For example, to test if AES-CBC-PKCS7 is supported, in the legacy API, you could write: +``` +#if defined(MBEDTLS_AES_C) && \ + defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_CIPHER_PADDING_PKCS7) +``` +The equivalent in the PSA API is +``` +#if PSA_WANT_KEY_TYPE_AES && PSA_WANT_ALG_CBC_PKCS7 +``` + +### Cipher metadata + +Both APIs express key sizes in bits. Note however that in the PSA API, the size of a _buffer_ is always expressed in bytes, even if that buffer contains a key. + +The following table lists corresponding PSA macros for maximum-size macros that take all supported algorithms into account. + +| Legacy macro | PSA macro | +| ------------ | --------- | +| `MBEDTLS_MAX_IV_LENGTH` | [`PSA_CIPHER_IV_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_CIPHER_IV_MAX_SIZE), [`PSA_AEAD_NONCE_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#crypto__sizes_8h_1ac2a332765ba4ccfc24935d6f7f48fcc7) | +| `MBEDTLS_MAX_BLOCK_LENGTH` | [`PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE) | +| `MBEDTLS_MAX_KEY_LENGTH` | no equivalent| + +There is no equivalent to the type `mbedtls_cipher_info_t` and the functions `mbedtls_cipher_info_from_type` and `mbedtls_cipher_info_from_values` in the PSA API because it is unnecessary. All macros and functions operate directly on key type values (`psa_key_type_t`, `PSA_KEY_TYPE_xxx` constants) and algorithm values (`psa_algorithm_t`, `PSA_ALG_xxx` constants). + +| Legacy function | PSA macro | +| --------------- | --------- | +| `mbedtls_cipher_info_get_iv_size` | [`PSA_CIPHER_IV_LENGTH`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_CIPHER_IV_LENGTH), [`PSA_AEAD_NONCE_LENGTH`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_AEAD_NONCE_LENGTH) | +| `mbedtls_cipher_info_get_block_size` | not available (use specific macros for the IV, nonce or tag length) | + +The following features have no PSA equivalent: + +* `mbedtls_cipher_list`: the PSA API does not currently have a discovery mechanism for cryptographic mechanisms, but one may be added in the future. +* `mbedtls_cipher_info_has_variable_key_bitlen`, `mbedtls_cipher_info_has_variable_iv_size`: the PSA API does not currently have such mechanism for high-level metadata information. +* `mbedtls_cipher_info_from_string`: there is no equivalent of Mbed TLS's lookup based on a (nonstandard) name. + +### Cipher key management + +The legacy API and the PSA API have a different organization of operations in several respects: + +* In the legacy API, each operation object contains the necessary key material. In the PSA API, an operation object contains a reference to a key object. To perform a cryptographic operation, you must create a key object first. However, for a one-shot operation, you do not need an operation object, just a single function call. +* The legacy API uses the same interface for authenticated and non-authenticated ciphers, while the PSA API has separate functions. +* The legacy API uses the same functions for encryption and decryption, while the PSA API has separate functions where applicable. + +Here is an overview of the lifecycle of a key object. + +1. First define the attributes of the key by filling a [`psa_key_attributes_t` structure](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga0ec645e1fdafe59d591104451ebf5680). You need to set the following parameters: + * Call [`psa_set_key_type`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga6857ef0ecb3fa844d4536939d9c64025) to set the key type to the desired `PSA_KEY_TYPE_xxx` value (see “[Cipher mechanism selection](#cipher-mechanism-selection)”). + * Call [`psa_set_key_bits`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gaf61683ac87f87687a40262b5afbfa018) to set the key's size in bits. This is optional with `psa_import_key`, which determines the key size from the length of the key material. + * Call [`psa_set_key_algorithm`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gaeb8341ca52baa0279475ea3fd3bcdc98) to set the algorithm to the desired `PSA_ALG_xxx` value (see “[Cipher mechanism selection](#cipher-mechanism-selection)”). By design, the same key cannot be used with multiple algorithms. + * Call [`psa_set_key_usage_flags`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga42a65b3c4522ce9b67ea5ea7720e17de) to enable at least [`PSA_KEY_USAGE_ENCRYPT`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__policy/#c.PSA_KEY_USAGE_ENCRYPT) or [`PSA_KEY_USAGE_DECRYPT`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__policy/#c.PSA_KEY_USAGE_DECRYPT), depending on which direction you want to use the key in. To allow both directions, use the flag mask `PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT`. The same policy flags cover authenticated and non-authenticated encryption/decryption. +2. Call one of the key creation functions, passing the attributes defined in the previous step, to get an identifier of type [`psa_key_id_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__types_8h/#_CPPv412psa_key_id_t) to the key object. + * Use [`psa_import_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga0336ea76bf30587ab204a8296462327b) to directly import key material. + * If the key is randomly generated, use [`psa_generate_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__random/#group__random_1ga1985eae417dfbccedf50d5fff54ea8c5). + * If the key is derived from other material (for example from a key exchange), use the [key derivation interface](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/) and create the key with [`psa_key_derivation_output_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1gada7a6e17222ea9e7a6be6864a00316e1). +3. Call the functions in the following sections to perform operations on the key. The same key object can be used in multiple operations. +4. To free the resources used by the key object, call [`psa_destroy_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__management/#group__key__management_1ga5f52644312291335682fbc0292c43cd2) after all operations with that key are finished. + +### Unauthenticated cipher operations + +Recall the workflow of an unauthenticated cipher operation in the legacy Mbed TLS cipher API: + +1. Create a cipher context of type `mbedtls_cipher_context_t` and initialize it with `mbedtls_cipher_init`. +2. Establish the operation parameters (algorithm, key, mode) with `mbedtls_cipher_setup`, `mbedtls_cipher_setkey` (or `mbedtls_cipher_setup_psa`), `mbedtls_cipher_set_padding_mode` if applicable. +3. Set the IV with `mbedtls_cipher_set_iv` (except for ECB which does not use an IV). +4. For a one-shot operation, call `mbedtls_cipher_crypt`. To pass the input in multiple parts, call `mbedtls_cipher_update` as many times as necessary followed by `mbedtls_cipher_finish`. +5. Finally free the resources associated with the operation object by calling `mbedtls_cipher_free`. + +For a one-shot operation (where the whole plaintext or ciphertext is passed as a single input), the equivalent workflow with the PSA API is to call a single function: + +* [`psa_cipher_encrypt`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__cipher/#group__cipher_1ga61f02fbfa681c2659546eca52277dbf1) to perform encryption with a random IV of the default size (indicated by [`PSA_CIPHER_IV_LENGTH`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_CIPHER_IV_LENGTH)). (To encrypt with a specified IV, use the multi-part API described below.) You can use the macro [`PSA_CIPHER_ENCRYPT_OUTPUT_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_CIPHER_ENCRYPT_OUTPUT_SIZE) or [`PSA_CIPHER_ENCRYPT_OUTPUT_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_CIPHER_ENCRYPT_OUTPUT_MAX_SIZE) to determine a sufficient size for the output buffer. +* [`psa_cipher_decrypt`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__cipher/#group__cipher_1gab3593f5f14d8c0431dd306d80929215e) to perform decryption with a specified IV. You can use the macro [`PSA_CIPHER_DECRYPT_OUTPUT_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_CIPHER_DECRYPT_OUTPUT_SIZE) or [`PSA_CIPHER_DECRYPT_OUTPUT_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_CIPHER_DECRYPT_OUTPUT_MAX_SIZE) to determine a sufficient size for the output buffer. + +For a multi-part operation, the equivalent workflow with the PSA API is as follows: + +1. Create an operation object of type [`psa_cipher_operation_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__cipher/#group__cipher_1ga1399de29db657e3737bb09927aae51fa) and zero-initialize it (or use the corresponding `INIT` macro). +2. Select the key and algorithm with [`psa_cipher_encrypt_setup`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__cipher/#group__cipher_1ga587374c0eb8137a572f8e2fc409bb2b4) or [`psa_cipher_decrypt_setup`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__cipher/#group__cipher_1gaa4ba3a167066eaef2ea49abc5dcd1d4b) depending on the desired direction. +3. When encrypting with a random IV, use [`psa_cipher_generate_iv`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__cipher/#group__cipher_1ga29fd7d32a5729226a2f73e7b6487bd8a). When encrypting with a chosen IV, or when decrypting, set the IV with [`psa_cipher_set_iv`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__cipher/#group__cipher_1ga9caddac1a429a5032d6d4a907fb70ba1). Skip this step with ECB since it does not use an IV. +4. Call [`psa_cipher_update`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__cipher/#group__cipher_1gac3ca27ac6682917c48247d01fd96cd0f) as many times as needed. You can use [`PSA_CIPHER_UPDATE_OUTPUT_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_CIPHER_UPDATE_OUTPUT_SIZE) or [`PSA_CIPHER_UPDATE_OUTPUT_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#crypto__sizes_8h_1ab1f6598efd6a7dc56e7ad7e34719eb32) to determine a sufficient size for the output buffer. +5. Call [`psa_cipher_finish`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__cipher/#group__cipher_1ga1dcb58b8befe23f8a4d7a1d49c99249b) to obtain the last part of the output. You can use [`PSA_CIPHER_FINISH_OUTPUT_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_CIPHER_FINISH_OUTPUT_SIZE) or [`PSA_CIPHER_FINISH_OUTPUT_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_CIPHER_FINISH_OUTPUT_MAX_SIZE) to determine a sufficient size for the output buffer. + +If you need to interrupt the operation after calling the setup function without calling the finish function, call [`psa_cipher_abort`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__cipher/#group__cipher_1gaad482cdca2098bca0620596aaa02eaa4). + +### Authenticated cipher operations + +Recall the workflow of an authenticated cipher operation in the legacy Mbed TLS cipher API (or similar workflows in the `chachapoly`, `ccm` and `gcm` modules): + +1. Create a cipher context of type `mbedtls_cipher_context_t` and initialize it with `mbedtls_cipher_init`. +2. Establish the operation parameters (algorithm, key, mode) with `mbedtls_cipher_setup`, `mbedtls_cipher_setkey` (or `mbedtls_cipher_setup_psa`), `mbedtls_cipher_set_padding_mode` if applicable. +3. Set the nonce with `mbedtls_cipher_set_iv` (or the `starts` function for low-level modules). For CCM, which requires direct use of the `ccm` module, also call `mbedtls_ccm_set_lengths` to set the length of the additional data and of the plaintext. +4. Call `mbedtls_cipher_update_ad` to pass the unencrypted additional data. +5. Call `mbedtls_cipher_update` as many times as necessary to pass the input plaintext or ciphertext. +6. Call `mbedtls_cipher_finish` to obtain the last part of the output. Then call `mbedtls_cipher_write_tag` (when encrypting) or `mbedtls_cipher_check_tag` (when decrypting) to process the authentication tag. +7. Finally free the resources associated with the operation object by calling `mbedtls_cipher_free`. + +Steps 3–6 can be replaced by a single call to `mbedtls_cipher_auth_encrypt_ext` or `mbedtls_cipher_auth_decrypt_ext` for a one-shot operation (where the whole plaintext or ciphertext is passed as a single input). + +For a one-shot operation, the PSA API allows you to call a single function: + +* [`psa_aead_encrypt`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__aead/#group__aead_1gae72e1eb3c2da3ebd843bb9c8db8df509) to perform authenticated encryption with a random nonce of the default size (indicated by [`PSA_AEAD_NONCE_LENGTH`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_AEAD_NONCE_LENGTH)), with the authentication tag written at the end of the output. (To encrypt with a specified nonce, or to separate the tag from the rest of the ciphertext, use the multi-part API described below.) You can use the macro [`PSA_AEAD_ENCRYPT_OUTPUT_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_AEAD_ENCRYPT_OUTPUT_SIZE) or [`PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE) to determine a sufficient size for the output buffer. +* [`psa_aead_decrypt`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__aead/#group__aead_1gae799f6196a22d50c216c947e0320d3ba) to perform authenticated decryption of a ciphertext with the authentication tag at the end. (If the tag is separate, use the multi-part API described below.) You can use the macro [`PSA_AEAD_DECRYPT_OUTPUT_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_CIPHER_DECRYPT_OUTPUT_SIZE) or [`PSA_AEAD_DECRYPT_OUTPUT_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_CIPHER_DECRYPT_OUTPUT_MAX_SIZE) to determine a sufficient size for the output buffer. + +For a multi-part operation, the equivalent workflow with the PSA API is as follows: + +1. Create an operation object of type [`psa_aead_operation_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__aead/#group__aead_1ga14f6a01afbaa8c5b3d8c5d345cbaa3ed) and zero-initialize it (or use the corresponding `INIT` macro). +2. Select the key and algorithm with [`psa_aead_encrypt_setup`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__aead/#group__aead_1ga2732c40ce8f3619d41359a329e9b46c4) or [`psa_aead_decrypt_setup`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__aead/#group__aead_1gaaa5c5018e67a7a6514b7e76b9a14de26) depending on the desired direction. +3. When encrypting with a random nonce, use [`psa_aead_generate_nonce`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__aead/#group__aead_1ga5799df1c555efd35970b65be51cb07d1). When encrypting with a chosen nonce, or when decrypting, set the nonce with [`psa_aead_set_nonce`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__aead/#group__aead_1ga59132751a6f843d038924cb217b5e13b). If the algorithm is CCM, you must also call [`psa_aead_set_lengths`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__aead/#group__aead_1gad3431e28d05002c2a7b0760610176050) before or after setting the nonce (for other algorithms, this is permitted but not needed). +4. Call [`psa_aead_update_ad`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__aead/#group__aead_1ga6d0eed03f832e5c9c91cb8adf2882569) as many times as needed. +5. Call [`psa_aead_update`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__aead/#group__aead_1gaf6d49864951ca42136b4a9b71ea26e5c) as many times as needed. You can use [`PSA_AEAD_UPDATE_OUTPUT_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_AEAD_UPDATE_OUTPUT_SIZE) or [`PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE) to determine a sufficient size for the output buffer. +6. Finally: + * When encrypting, call [`psa_aead_finish`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__aead/#group__aead_1ga759791bbe1763b377c3b5447641f1fc8) to obtain the last part of the ciphertext and the authentication tag. You can use [`PSA_AEAD_FINISH_OUTPUT_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_AEAD_FINISH_OUTPUT_SIZE) or [`PSA_AEAD_FINISH_OUTPUT_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_AEAD_FINISH_OUTPUT_MAX_SIZE) to determine a sufficient size for the output buffer. + * When decrypting, call [`psa_aead_verify`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__aead/#group__aead_1gae0280e2e61a185b893c36d858453f0d0) to obtain the last part of the plaintext and check the authentication tag. You can use [`PSA_AEAD_VERIFY_OUTPUT_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_AEAD_VERIFY_OUTPUT_SIZE) or [`PSA_AEAD_VERIFY_OUTPUT_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_AEAD_VERIFY_OUTPUT_MAX_SIZE) to determine a sufficient size for the output buffer. + +If you need to interrupt the operation after calling the setup function without calling the finish or verify function, call [`psa_aead_abort`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__aead/#group__aead_1gae8a5f93d92318c8f592ee9fbb9d36ba0). + +### Miscellaneous cipher operation management + +The equivalent of `mbedtls_cipher_reset` is to call [`psa_cipher_abort`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__cipher/#group__cipher_1gaad482cdca2098bca0620596aaa02eaa4) or [`psa_aead_abort`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__aead/#group__aead_1gae8a5f93d92318c8f592ee9fbb9d36ba0). Note that you must set the key again with a setup function: the PSA API does not have a special way to reuse an operation object with the same key. + +There is no equivalent for the `mbedtls_cipher_get_xxx` functions to extract information from an ongoing PSA cipher or AEAD operation. Applications that need this information will need to save it from the key and operation parameters. + +### NIST KW and KWP + +TF-PSA-Crypto 1.0 does not yet have a PSA API for key wrapping. We plan to implement the upcoming PSA API in a future minor version. In the meantime, you can continue using the legacy module ``. The API of this module was tweaked in TF-PSA-Crypto 1.0, compared to Mbed TLS 3.6, to take the wrapping key as a PSA key identifier as input instead of a custom context. See the [1.0/4.0 migration guide](1.0-migration-guide.md#changes-to-nist_kw) for more information. + +## Hashes and MAC + +The PSA API groups functions by purpose rather than by underlying primitive: there is a MAC API (equivalent to `md.h` for HMAC, and `cmac.h` for CMAC) and a hash API (equivalent to `md.h` for hashing). There is no special API for a particular hash algorithm (`md5.h`, `sha1.h`, `sha256.h`, `sha512.h`, `sha3.h`). To migrate code using those low-level modules, please follow the recommendations in the following section, using the same principles as the corresponding `md.h` API. + +Note that `` is still available in TF-PSA-Crypto 1.x, for hash operations only. It is a thin wrapper over the corresponding PSA function. In TF-PSA-Crypto, `` does not support HMAC, so applications using HMAC will need to migrate to PSA. + +The PSA API does not have a direct interface for the AES-CMAC-PRF-128 algorithm from RFC 4615 calculated by `mbedtls_aes_cmac_prf_128` at the time of writing. You can implement it using the MAC interface with an AES key and the CMAC algorithm. + +### Hash mechanism selection + +The equivalent to `mbedtls_md_type_t` and `MBEDTLS_MD_XXX` constants is the type `psa_algorithm_t` and `PSA_ALG_xxx` constants (the type encompasses all categories of cryptographic algorithms, not just hashes). PSA offers a similar selection of algorithms, but note that SHA-1 and SHA-2 are spelled slightly differently. + +| Mbed TLS constant | PSA constant | +| ---------------------- | ------------------- | +| `MBEDTLS_MD_MD5` | `PSA_ALG_MD5` | +| `MBEDTLS_MD_SHA1` | `PSA_ALG_SHA_1` | +| `MBEDTLS_MD_SHA224` | `PSA_ALG_SHA_224` | +| `MBEDTLS_MD_SHA256` | `PSA_ALG_SHA_256` | +| `MBEDTLS_MD_SHA384` | `PSA_ALG_SHA_384` | +| `MBEDTLS_MD_SHA512` | `PSA_ALG_SHA_512` | +| `MBEDTLS_MD_RIPEMD160` | `PSA_ALG_RIPEMD160` | +| `MBEDTLS_MD_SHA3_224` | `PSA_ALG_SHA3_224` | +| `MBEDTLS_MD_SHA3_256` | `PSA_ALG_SHA3_256` | +| `MBEDTLS_MD_SHA3_384` | `PSA_ALG_SHA3_384` | +| `MBEDTLS_MD_SHA3_512` | `PSA_ALG_SHA3_512` | + +The following helper functions from `` can be used to convert between the two types: + +- `mbedtls_md_psa_alg_from_type()` converts from legacy `mbedtls_md_type_t` to PSA's `psa_algorithm_t`. +- `mbedtls_md_type_from_psa_alg()` converts from PSA's `psa_algorithm_t` to legacy `mbedtls_md_type_t`. + +### MAC mechanism selection + +PSA Crypto has a generic API with the same functions for all MAC mechanisms. The mechanism is determined by a combination of an algorithm value of type [`psa_algorithm_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gac2e4d47f1300d73c2f829a6d99252d69) and a key type value of type [`psa_key_type_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga63fce6880ca5933b5d6baa257febf1f6). + +* For HMAC, the algorithm is [`PSA_ALG_HMAC`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga70f397425684b3efcde1e0e34c28261f)`(hash)` where `hash` is the underlying hash algorithm (see “[Hash mechanism selection](#hash-mechanism-selection)”), + for example `PSA_ALG_HMAC(PSA_ALG_SHA_256)` for HMAC-SHA-256. + The key type is [`PSA_KEY_TYPE_HMAC`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__values_8h/#c.PSA_KEY_TYPE_HMAC) regardless of the hash algorithm. +* For CMAC, the algorithm is [`PSA_ALG_CMAC`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__values_8h/#c.PSA_ALG_CMAC) regardless of the underlying block cipher. The key type determines the block cipher: + [`PSA_KEY_TYPE_AES`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga6ee54579dcf278c677eda4bb1a29575e), + [`PSA_KEY_TYPE_ARIA`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#c.PSA_KEY_TYPE_ARIA), + [`PSA_KEY_TYPE_CAMELLIA`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gad8e5da742343fd5519f9d8a630c2ed81) or + [`PSA_KEY_TYPE_DES`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga577562bfbbc691c820d55ec308333138). + +### Hash and MAC mechanism availability + +For each key type value `PSA_KEY_TYPE_xxx`, the symbol `PSA_WANT_KEY_TYPE_xxx` is defined with a non-zero value if the library is built with support for that key type. For each algorithm value `PSA_ALG_yyy`, the symbol `PSA_WANT_ALG_yyy` is defined with a non-zero value if the library is built with support for that algorithm. For a compound mechanism, all parts must be supported. In particular, for HMAC, all three of `PSA_WANT_KEY_TYPE_HMAC`, `PSA_WANT_ALG_HMAC` and the underlying hash must be enabled. (A configuration with only one of `PSA_WANT_KEY_TYPE_HMAC` and `PSA_WANT_ALG_HMAC` is technically possible but not useful.) + +For example, to test if HMAC-SHA-256 is supported, in the legacy API, you could write: +``` +#if defined(MBEDTLS_MD_C) && defined(MBEDTLS_SHA256_C) +``` +The equivalent in the PSA API is +``` +#if PSA_WANT_KEY_TYPE_HMAC && PSA_WANT_ALG_HMAC && PSA_WANT_ALG_SHA_256 +``` + +To test if AES-CMAC is supported, in the legacy API, you could write: +``` +if defined(MBEDTLS_AES_C) && defined(MBEDTLS_CMAC_C) +``` +The equivalent in the PSA API is +``` +#if PSA_WANT_KEY_TYPE_AES && PSA_WANT_ALG_CMAC +``` + +### Hash algorithm metadata + +There is no equivalent to the type `mbedtls_md_info_t` and the functions `mbedtls_md_info_from_type` and `mbedtls_md_get_type` in the PSA API because it is unnecessary. All macros and functions operate directly on algorithm (`psa_algorithm_t`, `PSA_ALG_xxx` constants). + +| Legacy macro | PSA macro | +| ------------ | --------- | +| `MBEDTLS_MD_MAX_SIZE` | [`PSA_HASH_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_HASH_MAX_SIZE) | +| `MBEDTLS_MD_MAX_BLOCK_SIZE` | [`PSA_HMAC_MAX_HASH_BLOCK_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_HMAC_MAX_HASH_BLOCK_SIZE) | +| `mbedtls_md_get_size` | [`PSA_HASH_LENGTH`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_HASH_LENGTH) | +| `mbedtls_md_get_size_from_type` | [`PSA_HASH_LENGTH`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_HASH_LENGTH) | + +The following features have no PSA equivalent: + +* `mbedtls_md_list`: the PSA API does not currently have a discovery mechanism for cryptographic mechanisms, but one may be added in the future. +* `mbedtls_md_info_from_ctx` +* `mbedtls_cipher_info_from_string`, `mbedtls_md_get_name`: there is no equivalent of Mbed TLS's lookup based on a (nonstandard) name. + +### Hash calculation + +TF-PSA-Crypto will still support the `` interface for hash calculations throughout the 1.x version range, so migrating to PSA for this use case is optional. + +The equivalent of `mbedtls_md` for a one-shot hash calculation is [`psa_hash_compute`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__hash/#group__hash_1gac69f7f19d96a56c28cf3799d11b12156). In addition, to compare the hash of a message with an expected value, you can call [`psa_hash_compare`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__hash/#group__hash_1ga0c08f4797bec96b886c8c8d7acc2a553) instead of `mbedtls_md` followed by `memcmp` or a constant-time equivalent. + +For a multi-part hash calculation, the legacy process is as follows: + +1. Create a digest context of type `mbedtls_md_context_t` and initialize it with `mbedtls_md_init`. +2. Call `mbedtls_md_setup` to select the hash algorithm, with `hmac=0`. Then call `mbedtls_md_starts` to start the hash operation. +3. Call `mbedtls_md_update` as many times as necessary. +4. Call `mbedtls_md_finish`. If verifying the hash against an expected value, compare the result with the expected value. +5. Finally free the resources associated with the operation object by calling `mbedtls_md_free`. + +The equivalent process in the PSA API is as follows: + +1. Create an operation object of type [`psa_hash_operation_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__hash/#group__hash_1ga3c4205d2ce66c4095fc5c78c25273fab) and zero-initialize it (or use the corresponding `INIT` macro). +2. Call [`psa_hash_setup`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__hash/#group__hash_1ga8d72896cf70fc4d514c5c6b978912515) to specify the algorithm. +3. Call [`psa_hash_update`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__hash/#group__hash_1ga65b16ef97d7f650899b7db4b7d1112ff) as many times as necessary. +4. To obtain the hash, call [`psa_hash_finish`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__hash/#group__hash_1ga4795fd06a0067b0adcd92e9627b8c97e). Alternatively, to verify the hash against an expected value, call [`psa_hash_verify`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__hash/#group__hash_1ga7be923c5700c9c70ef77ee9b76d1a5c0). + +If you need to interrupt the operation after calling the setup function without calling the finish or verify function, call [`psa_hash_abort`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__hash/#group__hash_1gab0b4d5f9912a615559497a467b532928). + +There is no equivalent to `mbedtls_md_file` in the PSA API. Load the file data and calculate its hash. + +### MAC key management + +The legacy API and the PSA API have a different organization of operations in several respects: + +* In the legacy API, each operation object contains the necessary key material. In the PSA API, an operation object contains a reference to a key object. To perform a cryptographic operation, you must create a key object first. However, for a one-shot operation, you do not need an operation object, just a single function call. +* The legacy API uses the same interface for authenticated and non-authenticated ciphers, while the PSA API has separate functions. +* The legacy API uses the same functions for encryption and decryption, while the PSA API has separate functions where applicable. + +Here is an overview of the lifecycle of a key object. + +1. First define the attributes of the key by filling a [`psa_key_attributes_t` structure](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga0ec645e1fdafe59d591104451ebf5680). You need to set the following parameters: + * Call [`psa_set_key_type`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga6857ef0ecb3fa844d4536939d9c64025) to set the key type to the desired `PSA_KEY_TYPE_xxx` value (see “[Cipher mechanism selection](#cipher-mechanism-selection)”). + * Call [`psa_set_key_bits`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gaf61683ac87f87687a40262b5afbfa018) to set the key's size in bits. This is optional with `psa_import_key`, which determines the key size from the length of the key material. + * Call [`psa_set_key_algorithm`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gaeb8341ca52baa0279475ea3fd3bcdc98) to set the algorithm to the desired `PSA_ALG_xxx` value (see “[Cipher mechanism selection](#cipher-mechanism-selection)”). By design, the same key cannot be used with multiple algorithms. + * Call [`psa_set_key_usage_flags`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga42a65b3c4522ce9b67ea5ea7720e17de) to enable at least [`PSA_KEY_USAGE_SIGN_MESSAGE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__policy/#c.PSA_KEY_USAGE_SIGN_MESSAGE) to calculate a MAC or [`PSA_KEY_USAGE_VERIFY_MESSAGE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__policy/#c.PSA_KEY_USAGE_VERIFY_MESSAGE) to verify the MAC of a message. To allow both directions, use the flag mask `PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE`. +2. Call one of the key creation functions, passing the attributes defined in the previous step, to get an identifier of type [`psa_key_id_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__types_8h/#_CPPv412psa_key_id_t) to the key object. + * Use [`psa_import_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga0336ea76bf30587ab204a8296462327b) to directly import key material. + * If the key is randomly generated, use [`psa_generate_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__random/#group__random_1ga1985eae417dfbccedf50d5fff54ea8c5). + * If the key is derived from other material (for example from a key exchange), use the [key derivation interface](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/) and create the key with [`psa_key_derivation_output_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1gada7a6e17222ea9e7a6be6864a00316e1). +3. Call the functions in the following sections to perform operations on the key. The same key object can be used in multiple operations. +4. To free the resources used by the key object, call [`psa_destroy_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__management/#group__key__management_1ga5f52644312291335682fbc0292c43cd2) after all operations with that key are finished. + +### MAC calculation + +The process for a HMAC operation in the legacy API is as follows: + +1. Create a digest context of type `mbedtls_md_context_t` and initialize it with `mbedtls_md_init`. +2. Call `mbedtls_md_setup` to select the hash algorithm, with `hmac=1`. Then call `mbedtls_md_hmac_starts` to set the key. +3. Call `mbedtls_md_hmac_update` as many times as necessary. +4. Call `mbedtls_md_hmac_finish`. If verifying the MAC against an expected value, compare the result with the expected value. Note that this comparison should be in constant time to avoid a side channel vulnerability, for example using `mbedtls_ct_memcmp`. +5. Finally free the resources associated with the operation object by calling `mbedtls_md_free`. + +The process for a CMAC operation in the legacy API is as follows: + +1. Create a cipher context of type `mbedtls_cipher_context_t` and initialize it with `mbedtls_cipher_init`. +2. Call `mbedtls_cipher_setup` to select the block cipher. Then call `mbedtls_md_cmac_starts` to set the key. +3. Call `mbedtls_cipher_cmac_update` as many times as necessary. +4. Call `mbedtls_cipher_cmac_finish`. If verifying the MAC against an expected value, compare the result with the expected value. Note that this comparison should be in constant time to avoid a side channel vulnerability, for example using `mbedtls_ct_memcmp`. +5. Finally free the resources associated with the operation object by calling `mbedtls_cipher_free`. + +The process in the PSA API to calculate a MAC is as follows: + +1. Create an operation object of type [`psa_mac_operation_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group___m_a_c/#group___m_a_c_1ga78f0838b0c4e3db28b26355624d4bd37) and zero-initialize it (or use the corresponding `INIT` macro). +2. Call [`psa_mac_sign_setup`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group___m_a_c/#group___m_a_c_1ga03bc3e3c0b7e55b20d2a238e418d46cd) to specify the algorithm and the key. See “[MAC key management](#mac-key-management)” for how to obtain a key identifier. +3. Call [`psa_mac_update`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group___m_a_c/#group___m_a_c_1ga5560af371497babefe03c9da4e8a1c05) as many times as necessary. +4. To obtain the MAC, call [`psa_mac_sign_finish`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group___m_a_c/#group___m_a_c_1gac22bc0125580c96724a09226cfbc97f2). + +To verify a MAC against an expected value, use the following process instead: + +1. Create an operation object of type [`psa_mac_operation_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group___m_a_c/#group___m_a_c_1ga78f0838b0c4e3db28b26355624d4bd37) and zero-initialize it (or use the corresponding `INIT` macro). +2. Call [`psa_mac_verify_setup`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group___m_a_c/#group___m_a_c_1ga08ae327fcbc5f8e201172fe11e536984) to specify the algorithm and the key. See “[MAC key management](#mac-key-management)” for how to obtain a key identifier. +3. Call [`psa_mac_update`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group___m_a_c/#group___m_a_c_1ga5560af371497babefe03c9da4e8a1c05) as many times as necessary. +4. To verify the MAC against an expected value, call [`psa_mac_verify_finish`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group___m_a_c/#group___m_a_c_1gac92b2930d6728e1be4d011c05d485822). + +If you need to interrupt the operation after calling the setup function without calling the finish function, call [`psa_mac_abort`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group___m_a_c/#group___m_a_c_1gacd8dd54855ba1bc0a03f104f252884fd). + +The PSA API also offers functions for a one-shot MAC calculation, similar to `mbedtls_cipher_cmac` and `mbedtls_md_hmac`: + +* [`psa_mac_compute`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group___m_a_c/#group___m_a_c_1gabf02ebd3595ea15436967092b5d52878) to calculate the MAC of a buffer in memory. +* [`psa_mac_verify`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group___m_a_c/#group___m_a_c_1gaf6988545df5d5e2466c34d753443b15a) to verify the MAC of a buffer in memory against an expected value. + +In both cases, see “[MAC key management](#mac-key-management)” for how to obtain a key identifier. + +### Miscellaneous hash or MAC operation management + +The equivalent of `mbedtls_md_reset`, `mbedtls_md_hmac_reset` or `mbedtls_cmac_reset` is to call [`psa_hash_abort`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__hash/#group__hash_1gab0b4d5f9912a615559497a467b532928) or [`psa_mac_abort`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group___m_a_c/#group___m_a_c_1gacd8dd54855ba1bc0a03f104f252884fd). Note that you must call a setup function to specify the algorithm and the key (for MAC) again, and they can be different ones. + +The equivalent of `mbedtls_md_clone` to clone a hash operation is [`psa_hash_clone`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__hash/#group__hash_1ga39673348f3302b4646bd780034a5aeda). A PSA MAC operation cannot be cloned. + +## Key derivation + +### HKDF + +PSA Crypto provides access to HKDF, HKDF-Extract and HKDF-Expand via its [key derivation interface](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/). This is a generic interface using an operation object with one function call for each input and one function call for each output. + +1. Create an operation object of type [`psa_key_derivation_operation_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1ga5f099b63799a0959c3d46718c86c2609) and zero-initialize it (or use the corresponding `INIT` macro). +2. Call [`psa_key_derivation_setup`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1gac0b6a76e45cceb1862752bf041701859) to select the algorithm, which is a value of type [`psa_algorithm_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gac2e4d47f1300d73c2f829a6d99252d69). For HKDF and variants, use one of the macros [`PSA_ALG_HKDF`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__values_8h/#c.PSA_ALG_HKDF), [`PSA_ALG_HKDF_EXTRACT`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__values_8h/#c.PSA_ALG_HKDF_EXTRACT) or [`PSA_ALG_HKDF_EXPAND`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__values_8h/#c.PSA_ALG_HKDF_EXPAND) with the [hash algorithm](#hash-mechanism-selection) passed as an argument. For example `PSA_ALG_HKDF(PSA_ALG_SHA_256)` selects HKDF-SHA-256. +3. Call [`psa_key_derivation_input_bytes`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1ga8fd934dfb0ca45cbf89542ef2a5494c2) on each of the inputs in the order listed below. (Use [`psa_key_derivation_input_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1gab2d7ce8705dd8e4a093f4b8a21a0c15a) instead for an input that is a PSA key object.) The input step value for each step is as follows: + 1. [`PSA_KEY_DERIVATION_INPUT_SALT`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__derivation/#group__derivation_1gab62757fb125243562c3947a752470d4a) for the salt used during the extraction step. Omit this step for HKDF-Expand. For HKDF, you may omit this step if the salt is empty. + 2. [`PSA_KEY_DERIVATION_INPUT_SECRET`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__derivation/#group__derivation_1ga0ddfbe764baba995c402b1b0ef59392e) for the secret input. + 3. [`PSA_KEY_DERIVATION_INPUT_INFO`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__derivation/#group__derivation_1gacef8df989e09c769233f4b779acb5b7d) for the info string used during the expansion step. Omit this step for HKDF-Extract. +4. Call [`psa_key_derivation_output_bytes`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1ga06b7eb34a2fa88965f68e3d023fa12b9) to obtain the output of the derivation. You may call this function more than once to retrieve the output in successive chunks. Use [`psa_key_derivation_output_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1gada7a6e17222ea9e7a6be6864a00316e1) instead if you want to use a chunk as a PSA key. +5. Call [`psa_key_derivation_abort`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1ga90fdd2716124d0bd258826184824675f) to free the resources associated with the key derivation object. + +### PKCS#5 module + +Applications currently using `mbedtls_pkcs5_pbkdf2_hmac` or `mbedtls_pkcs5_pbkdf2_hmac_ext` can switch to the PSA key derivation API for PBKDF2. This is a generic interface using an operation object with one function call for each input and one function call for each output. + +1. Create an operation object of type [`psa_key_derivation_operation_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1ga5f099b63799a0959c3d46718c86c2609) and zero-initialize it (or use the corresponding `INIT` macro). +2. Call [`psa_key_derivation_setup`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1gac0b6a76e45cceb1862752bf041701859) to select the algorithm, which is a value of type [`psa_algorithm_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gac2e4d47f1300d73c2f829a6d99252d69). For PBKDF2-HMAC, select `PSA_ALG_PBKDF2_HMAC(hash)` where `hash` is the underlying hash algorithm (see “[Hash mechanism selection](#hash-mechanism-selection)”). +3. Call `psa_key_derivation_input_cost` with the step `PSA_KEY_DERIVATION_INPUT_COST` to select the iteration count. +4. Call [`psa_key_derivation_input_bytes`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1ga8fd934dfb0ca45cbf89542ef2a5494c2) on each of the inputs in the order listed below. (Use [`psa_key_derivation_input_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1gab2d7ce8705dd8e4a093f4b8a21a0c15a) instead for an input that is a PSA key object.) The input step value for each step is as follows: + 1. [`PSA_KEY_DERIVATION_INPUT_SALT`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__derivation/#group__derivation_1gab62757fb125243562c3947a752470d4a) for the salt used during the extraction step. You may repeat this step to pass the salt in pieces (for example a salt and a pepper). + 2. [`PSA_KEY_DERIVATION_INPUT_SECRET`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__derivation/#group__derivation_1ga0ddfbe764baba995c402b1b0ef59392e) for the password. +5. Call [`psa_key_derivation_output_bytes`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1ga06b7eb34a2fa88965f68e3d023fa12b9) to obtain the output of the derivation. You may call this function more than once to retrieve the output in successive chunks. + Use [`psa_key_derivation_output_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1gada7a6e17222ea9e7a6be6864a00316e1) instead if you want to use a chunk as a PSA key. + If you want to verify the output against an expected value (for authentication, rather than to derive key material), call [`psa_key_derivation_verify_bytes`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1gaf01520beb7ba932143ffe733b0795b08) or [`psa_key_derivation_verify_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1gac041714e34a94742e8ee006ac7dfea5a) instead of `psa_key_derivation_output_bytes`. (Available since Mbed TLS 3.6.0.) +6. Call [`psa_key_derivation_abort`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1ga90fdd2716124d0bd258826184824675f) to free the resources associated with the key derivation object. + +The function `mbedtls_pkcs5_pbes2` was only intended as a support function to parse encrypted private keys in the PK module. It has no PSA equivalent. + +### PKCS#12 module + +The functions `mbedtls_pkcs12_derivation` and `mbedtls_pkcs12_pbe` were only intended as support functions to parse encrypted private keys in the PK module. They have no PSA equivalent. + +## Random generation + +### Random generation interface + +The PSA subsystem has an internal random generator. As a consequence, you do not need to instantiate one manually, so most applications using PSA crypto do not need the interfaces from `entropy.h`, `ctr_drbg.h` and `hmac_drbg.h`. See the next sections for remaining use cases for [entropy](#entropy-sources) and [DRBG](#deterministic-pseudorandom-generation). + +The PSA API uses its internal random generator to generate keys (`psa_generate_key`), nonces for encryption (`psa_cipher_generate_iv`, `psa_cipher_encrypt`, `psa_aead_generate_nonce`, `psa_aead_encrypt`, `psa_asymmetric_encrypt`), and other random material as needed. If you need random data for some other purposes, call [`psa_generate_random`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__random/#group__random_1ga1985eae417dfbccedf50d5fff54ea8c5) instead of `mbedtls_ctr_drbg_random` or `mbedtls_hmac_drbg_random`. + +You will need to remove the Mbed TLS RNG boilerplate: calls to `mbedtls_entropy_init`, `mbedtls_ctr_drbg_init`, `mbedtls_ctr_drbg_seed`, `mbedtls_ctr_drbg_random`, `mbedtls_ctr_drbg_free` and `mbedtls_entropy_free` (or `hmac_drbg` equivalents of the `ctr_drbg` functions). + +TF-PSA-Crypto 1.x and Mbed TLS 4.x functions do not take RNG callbacks. If your code includes calls to internal functions or third-party functions that take RNG callbacks as parameters, include the header file `` and use: + +* [`mbedtls_psa_get_random`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/psa__util_8h/#_CPPv422mbedtls_psa_get_randomPvPh6size_t) as the `f_rng` argument; +* [`MBEDTLS_PSA_RANDOM_STATE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/psa__util_8h/#c.MBEDTLS_PSA_RANDOM_STATE) as the `p_rng` argument. + +### Entropy sources + +The PSA random generator always uses the entropy source(s) configured at compile time. TF-PSA-Crypto 1.0.0 made major changes to how entropy sources are configured, compared with Mbed TLS 3.x. In TF-PSA-Crypto 1.0.0, PSA uses exactly one of three possible entropy sources, depending on which compilation option is enabled: + +* `MBEDTLS_PSA_BUILTIN_GET_ENTROPY` (default): built-in platform entropy sources (Linux, other Unix-like systems, Windows). +* `#MBEDTLS_PSA_DRIVER_GET_ENTROPY`: the user-provided callback `mbedtls_platform_get_entropy()`, querying a low-rate entropy source. +* `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG`: the user-provided callback `mbedtls_psa_external_get_random()`, a high-rate cryptographic-quality random source. + +For more details, see the [1.0/4.0 migration guide](1.0-migration-guide.md#entropy-configuration) and the documentation of these options. + +### Deterministic pseudorandom generation + +The PSA API does not currently have a dedicated interface for pseudorandom generation. The [key derivation interface](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/) can serve a similar purpose in some applications, but it does not offer CTR\_DRBG or HMAC\_DRBG. + +We expect to add PSA APIs to DRBG mechanisms in a future version of TF-PSA-Crypto. + +## Asymmetric cryptography + +The PSA API supports the same algorithm families for asymmetric cryptography as the legacy API: RSA (see “[RSA mechanism selection](#rsa-mechanism-selection)”), elliptic curve cryptography (see “[ECC mechanism selection](#elliptic-curve-mechanism-selection)” and “[EC-JPAKE](#ec-jpake)”) and finite-field Diffie-Hellman (see “[Diffie-Hellman mechanism selection](#diffie-hellman-mechanism-selection)”). + +### Key lifecycle for asymmetric cryptography + +In the PSA API, keys are referenced by an identifier of type [`psa_key_id_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__types_8h/#_CPPv412psa_key_id_t). +(Some documentation references [`mbedtls_svc_key_id_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__types_8h/#_CPPv420mbedtls_svc_key_id_t); the two types are identical except when the library is configured for use in a multi-client cryptography service.) +The PSA key identifier tends to play the same role as an `mbedtls_pk_context`, `mbedtls_rsa_context` or `mbedtls_ecp_keypair` structure in the legacy API. However, there are major differences in the way the two APIs can be used to create keys or to obtain information about a key. + +Here is an overview of the lifecycle of a PSA key object. + +1. First define the attributes of the key by filling a [`psa_key_attributes_t` structure](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga0ec645e1fdafe59d591104451ebf5680). You need to set the following parameters: + * Call [`psa_set_key_type`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga6857ef0ecb3fa844d4536939d9c64025) to set the key type to the desired `PSA_KEY_TYPE_xxx` value (see “[RSA mechanism selection](#rsa-mechanism-selection)”, “[Elliptic curve mechanism selection](#elliptic-curve-mechanism-selection)” and “[Diffie-Hellman mechanism selection](#diffie-hellman-mechanism-selection)”). + * Call [`psa_set_key_bits`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gaf61683ac87f87687a40262b5afbfa018) to set the key's conceptual size in bits. This is optional with `psa_import_key`, which determines the key size from the length of the key material. + * Call [`psa_set_key_algorithm`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gaeb8341ca52baa0279475ea3fd3bcdc98) to set the permitted algorithm to the desired `PSA_ALG_xxx` value (see “[RSA mechanism selection](#rsa-mechanism-selection)”, “[Elliptic curve mechanism selection](#elliptic-curve-mechanism-selection)” and “[Diffie-Hellman mechanism selection](#diffie-hellman-mechanism-selection)” as well as “[Public-key cryptography policies](#public-key-cryptography-policies)”). + * Call [`psa_set_key_usage_flags`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga42a65b3c4522ce9b67ea5ea7720e17de) to enable the desired usage types (see “[Public-key cryptography policies](#public-key-cryptography-policies)”). +2. Call one of the key creation functions, passing the attributes defined in the previous step, to get an identifier of type [`psa_key_id_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__types_8h/#_CPPv412psa_key_id_t) to the key object. + * Use [`psa_import_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga0336ea76bf30587ab204a8296462327b) to directly import key material. + * If the key is randomly generated, use [`psa_generate_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__random/#group__random_1ga1985eae417dfbccedf50d5fff54ea8c5). + * If the key is derived from other material (for example from a key exchange), use the [key derivation interface](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/) and create the key with [`psa_key_derivation_output_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1gada7a6e17222ea9e7a6be6864a00316e1). +3. Call the functions in the following sections to perform operations on the key. The same key object can be used in multiple operations. +4. To free the resources used by the key object, call [`psa_destroy_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__management/#group__key__management_1ga5f52644312291335682fbc0292c43cd2) after all operations with that key are finished. + +### Public-key cryptography policies + +A key's policy indicates what algorithm(s) it can be used with (usage algorithm policy) and what operations are permitted (usage flags). + +The following table lists the relevant usage flags for asymmetric cryptography. You can pass those flags (combined with bitwise-or) to [`psa_set_key_usage_flags`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga42a65b3c4522ce9b67ea5ea7720e17de). + +| Usage | Flag | +| ----- | ---- | +| export public key | 0 (always permitted) | +| export private key | [`PSA_KEY_USAGE_EXPORT`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__policy/#group__policy_1ga7dddccdd1303176e87a4d20c87b589ed) | +| Sign a message directly | [`PSA_KEY_USAGE_SIGN_MESSAGE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__policy/#group__policy_1ga552117ac92b79500cae87d4e65a85c54) | +| Sign an already-calculated hash | at least one of [`PSA_KEY_USAGE_SIGN_MESSAGE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__policy/#group__policy_1ga552117ac92b79500cae87d4e65a85c54) or [`PSA_KEY_USAGE_SIGN_HASH`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__policy/#group__policy_1ga552117ac92b79500cae87d4e65a85c54) | +| Verify a message directly | [`PSA_KEY_USAGE_VERIFY_MESSAGE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__policy/#group__policy_1gabea7ec4173f4f943110329ac2953b2b1) | +| Verify an already-calculated hash | at least one of [`PSA_KEY_USAGE_VERIFY_MESSAGE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__policy/#group__policy_1gabea7ec4173f4f943110329ac2953b2b1) or [`PSA_KEY_USAGE_VERIFY_HASH`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__policy/#group__policy_1gafadf131ef2182045e3483d03aadaa1bd) | +| Encryption | [`PSA_KEY_USAGE_ENCRYPT`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__policy/#group__policy_1ga75153b296d045d529d97203a6a995dad) | +| Decryption | [`PSA_KEY_USAGE_DECRYPT`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__policy/#group__policy_1gac3f2d2e5983db1edde9f142ca9bf8e6a) | +| Key agreement | [`PSA_KEY_USAGE_DERIVE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__policy/#group__policy_1gaf19022acc5ef23cf12477f632b48a0b2) | + +The sections “[RSA mechanism selection](#rsa-mechanism-selection)”, “[Elliptic curve mechanism selection](#elliptic-curve-mechanism-selection)” and “[Diffie-Hellman mechanism selection](#diffie-hellman-mechanism-selection)” cover the available algorithm values for each key type. Normally, a key can only be used with a single algorithm, following standard good practice. However, there are two ways to relax this requirement. + +* Many signature algorithms encode a hash algorithm. Sometimes the same key may need to be used to sign messages with multiple different hashes. In an algorithm policy, you can use [`PSA_ALG_ANY_HASH`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__values_8h/#c.PSA_ALG_ANY_HASH) instead of a hash algorithm value to allow the key to be used with any hash. For example, `psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PSS(PSA_ALG_ANY_HASH))` allows the key to be used with RSASSA-PSS, with different hash algorithms in each operation. +* In addition to the algorithm (or wildcard) selected with [`psa_set_key_algorithm`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gaeb8341ca52baa0279475ea3fd3bcdc98), you can use [`psa_set_key_enrollment_algorithm`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gaffa134b74aa52aa3ed9397fcab4005aa) to permit a second algorithm (or wildcard). This is intended for scenarios where a key is normally used with a single algorithm, but needs to be used with a different algorithm for enrollment (such as an ECDH key for which an ECDSA proof-of-possession is also required). + +### Asymmetric cryptographic mechanisms + +#### RSA mechanism selection + +The former PK types `MBEDTLS_PK_RSA`, `MBEDTLS_PK_RSASSA_PSS` and `MBEDTLS_PK_RSA_ALT` correspond to RSA key types in the PSA API. In the PSA API, key pairs and public keys are separate object types. +See “[RSA-ALT interface](#rsa-alt-interface)” for more information about `MBEDTLS_PK_RSA_ALT`. + +The PSA API uses policies and algorithm parameters rather than key types to distinguish between RSA-based mechanisms. The PSA algorithm selection corresponds to the `mbedtls_pk_sigalg_type_t` (formerly `mbedtls_pk_type_t`) value passed to `mbedtls_pk_{sign,verify}_ext`. It also replaces the use of `mbedtls_rsa_set_padding` on an `mbedtls_rsa_context` object. See the list of algorithms below and the signature and encryption sections for more information. + +An RSA public key has the type [`PSA_KEY_TYPE_RSA_PUBLIC_KEY`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga9ba0878f56c8bcd1995ac017a74f513b). + +An RSA key pair has the type [`PSA_KEY_TYPE_RSA_KEY_PAIR`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga11745b110166e927e2abeabc7d532051). A key with this type can be used both for private-key and public-key operations (there is no separate key type for a private key without the corresponding public key). +You can always use a private key for operations on the corresponding public key (as long as the policy permits it). + +The following cryptographic algorithms work with RSA keys: + +* PKCS#1v1.5 RSA signature: [`PSA_ALG_RSA_PKCS1V15_SIGN`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga702ff75385a6ae7d4247033f479439af), [`PSA_ALG_RSA_PKCS1V15_SIGN_RAW`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga4215e2a78dcf834e9a625927faa2a817). +* PKCS#1v1.5 RSA encryption: [`PSA_ALG_RSA_PKCS1V15_CRYPT`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga4c540d3abe43fb9abcb94f2bc51acef9). +* PKCS#1 RSASSA-PSS signature: [`PSA_ALG_RSA_PSS`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga62152bf4cb4bf6aace5e1be8f143564d), [`PSA_ALG_RSA_PSS_ANY_SALT`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga9b7355a2cd6bde88177634d539127f2b). +* PKCS#1 RSAES-OAEP encryption: [`PSA_ALG_RSA_OAEP`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gaa1235dc3fdd9839c6c1b1a9857344c76). + +#### Elliptic curve mechanism selection + +The former PK types `MBEDTLS_PK_ECKEY`, `MBEDTLS_PK_ECKEY_DH` and `MBEDTLS_PK_ECDSA` correspond to elliptic-curve key types in the PSA API. In the PSA API, key pairs and public keys are separate object types. The PSA API uses policies and algorithm parameters rather than key types to distinguish between the PK EC types. + +An ECC public key has the type [`PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve)`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gad54c03d3b47020e571a72cd01d978cf2) where `curve` is a curve family identifier. + +An ECC key pair has the type [`PSA_KEY_TYPE_ECC_KEY_PAIR(curve)`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga0b6f5d4d5037c54ffa850d8059c32df0) where `curve` is a curve family identifier. A key with this type can be used both for private-key and public-key operations (there is no separate key type for a private key without the corresponding public key). +You can always use a private key for operations on the corresponding public key (as long as the policy permits it). + +A curve is fully determined by a curve family identifier and the private key size in bits. The following table gives the correspondence between legacy and PSA elliptic curve designations (when TF-PSA-Crypto 1.0 implements the given curve). + +| Mbed TLS legacy curve identifier | PSA curve family | Curve bit-size | +| -------------------------------- | ---------------- | -------------- | +| `MBEDTLS_ECP_DP_SECP192R1` | not supported | N/A | +| `MBEDTLS_ECP_DP_SECP224R1` | not supported | N/A | +| `MBEDTLS_ECP_DP_SECP256R1` | [`PSA_ECC_FAMILY_SECP_R1`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga48bb340b5544ba617b0f5b89542665a7) | 256 | +| `MBEDTLS_ECP_DP_SECP384R1` | [`PSA_ECC_FAMILY_SECP_R1`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga48bb340b5544ba617b0f5b89542665a7) | 384 | +| `MBEDTLS_ECP_DP_SECP521R1` | [`PSA_ECC_FAMILY_SECP_R1`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga48bb340b5544ba617b0f5b89542665a7) | 521 | +| `MBEDTLS_ECP_DP_BP256R1` | [`PSA_ECC_FAMILY_BRAINPOOL_P_R1`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gac1643f1baf38b30d07c20a6eac697f15) | 256 | +| `MBEDTLS_ECP_DP_BP384R1` | [`PSA_ECC_FAMILY_BRAINPOOL_P_R1`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gac1643f1baf38b30d07c20a6eac697f15) | 384 | +| `MBEDTLS_ECP_DP_BP512R1` | [`PSA_ECC_FAMILY_BRAINPOOL_P_R1`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gac1643f1baf38b30d07c20a6eac697f15) | 512 | +| `MBEDTLS_ECP_DP_CURVE25519` | [`PSA_ECC_FAMILY_MONTGOMERY`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga1f624c5cdaf25b21287af33024e1aff8) | 255 | +| `MBEDTLS_ECP_DP_SECP192K1` | not supported | N/A | +| `MBEDTLS_ECP_DP_SECP224K1` | not supported | N/A | +| `MBEDTLS_ECP_DP_SECP256K1` | [`PSA_ECC_FAMILY_SECP_K1`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga48bb340b5544ba617b0f5b89542665a7) | 256 | +| `MBEDTLS_ECP_DP_CURVE448` | [`PSA_ECC_FAMILY_MONTGOMERY`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga1f624c5cdaf25b21287af33024e1aff8) | 448 | + +The following cryptographic algorithms work with ECC keys: + +* ECDH key agreement (including X25519 and X448): [`PSA_ALG_ECDH`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gab2dbcf71b63785e7dd7b54a100edee43). +* ECDSA: [`PSA_ALG_ECDSA`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga7e3ce9f514a227d5ba5d8318870452e3), [`PSA_ALG_ECDSA_ANY`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga51d6b6044a62e33cae0cf64bfc3b22a4), [`PSA_ALG_DETERMINISTIC_ECDSA`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga11da566bcd341661c8de921e2ca5ed03). +* EC-JPAKE (see “[EC-JPAKE](#ec-jpake)”. + +#### Diffie-Hellman mechanism selection + +A finite-field Diffie-Hellman key pair has the type [`PSA_KEY_TYPE_DH_KEY_PAIR(group)`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gab4f857c4cd56f5fe65ded421e61bcc8c) where `group` is a group family as explained below. + +A finite-field Diffie-Hellman public key has the type [`PSA_KEY_TYPE_DH_PUBLIC_KEY(group)`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gaa22f0f2ea89b929f2fadc19890cc5d5c) where `group` is a group family as explained below. Due to the design of the API, there is rarely a need to use Diffie-Hellman public key objects. + +The PSA API only supports Diffie-Hellman with predefined groups. A group is fully determined by a group family identifier and the public key size in bits. + +| Mbed TLS DH group P value | PSA DH group family | Bit-size | +| ------------------------- | ------------------- | -------- | +| `MBEDTLS_DHM_RFC7919_FFDHE2048_P_BIN` | [`PSA_DH_FAMILY_RFC7919`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga7be917e67fe4a567fb36864035822ff7) | 2048 | +| `MBEDTLS_DHM_RFC7919_FFDHE3072_P_BIN` | [`PSA_DH_FAMILY_RFC7919`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga7be917e67fe4a567fb36864035822ff7) | 3072 | +| `MBEDTLS_DHM_RFC7919_FFDHE4096_P_BIN` | [`PSA_DH_FAMILY_RFC7919`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga7be917e67fe4a567fb36864035822ff7) | 4096 | +| `MBEDTLS_DHM_RFC7919_FFDHE6144_P_BIN` | [`PSA_DH_FAMILY_RFC7919`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga7be917e67fe4a567fb36864035822ff7) | 6144 | +| `MBEDTLS_DHM_RFC7919_FFDHE8192_P_BIN` | [`PSA_DH_FAMILY_RFC7919`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga7be917e67fe4a567fb36864035822ff7) | 8192 | + +A finite-field Diffie-Hellman key can be used for key agreement with the algorithm [`PSA_ALG_FFDH`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga0ebbb6f93a05b6511e6f108ffd2d1eb4). + +### Creating keys for asymmetric cryptography + +To generate a random key pair, call [`psa_generate_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__random/#group__random_1ga1985eae417dfbccedf50d5fff54ea8c5). Compared with the low-level functions from the legacy API (`mbedtls_rsa_gen_key`, `mbedtls_ecp_gen_privkey`, `mbedtls_ecp_gen_keypair`, `mbedtls_ecp_gen_keypair_base`, `mbedtls_ecdsa_genkey`), this directly creates an object that can be used with high-level APIs, but removes some of the flexibility. Note that if you want to export the generated private key, you must pass the flag [`PSA_KEY_USAGE_EXPORT`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__policy/#group__policy_1ga7dddccdd1303176e87a4d20c87b589ed) to [`psa_set_key_usage_flags`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga42a65b3c4522ce9b67ea5ea7720e17de). Exporting the public key with [`psa_export_public_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1gaf22ae73312217aaede2ea02cdebb6062) is always permitted. + +For RSA keys, `psa_generate_key` uses 65537 as the public exponent. You can use [`psa_generate_key_custom`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__random/#ga0415617443afe42a712027bbb8ad89f0) to select a different public exponent. As of TF-PSA-Crypto 1.0.0, selecting a different public exponent is only supported with the built-in RSA implementation, not with PSA drivers. + +To create a key object from existing material, use [`psa_import_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga0336ea76bf30587ab204a8296462327b). This function has the same basic goal as the PK parse functions (`mbedtls_pk_parse_key`, `mbedtls_pk_parse_public_key`, `mbedtls_pk_parse_subpubkey`), but only supports a single format that just contains the number(s) that make up the key, with very little metadata. The table below summarizes the PSA import/export format for key pairs and public keys; see the documentation of [`psa_export_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga668e35be8d2852ad3feeef74ac6f75bf) and [`psa_export_public_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1gaf22ae73312217aaede2ea02cdebb6062) for more details. + +| Key type | PSA import/export format | +| -------- | ------------------------ | +| RSA key pair | PKCS#1 RSAPrivateKey DER encoding (including both private exponent and CRT parameters) | +| RSA public key | PKCS#1 RSAPublicKey DER encoding | +| ECC key pair | Fixed-length private value (not containing the public key) | +| ECC public key (Weierstrass curve) | Fixed-length uncompressed point | +| ECC public key (Montgomery curve) | Fixed-length public value | +| FFDH key pair | Fixed-length private value (not containing the public key) | +| FFDH public key | Fixed-length public value | + +There is no equivalent of `mbedtls_pk_parse_keyfile` and `mbedtls_pk_parse_public_keyfile`. Either call the legacy function or load the file data manually. + +A future extension of the PSA API will support other import formats. Until those are implemented, see the following subsection for how to use the PK module for key parsing and construct a PSA key object from the PK object. + +### Creating a PSA key via PK + +You can use the PK module as an intermediate step to create an RSA or ECC key for use with PSA. This is useful for parsing a key in a format that the PK module supports, but `psa_import_key` doesn't. An advantage of the formats supported by PK is that they contain enough metadata to determine the key type, thus PK's parsing functions do not take a key type as input. + +To construct a PSA key by parsing it with a PK function: + +1. First create a PK object with the desired key material, using `mbedtls_pk_parse_key()` or `mbedtls_pk_parse_keyfile()`, `mbedtls_pk_parse_public_key()` or `mbedtls_pk_parse_public_keyfile()`. +2. Call [`mbedtls_pk_get_psa_attributes`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/pk_8h/#pk_8h_1a7aa7b33cffb6981d95d1632631de9244) to fill PSA attributes corresponding to the PK key. Pass one of the following values as the `usage` parameter: + * `PSA_KEY_USAGE_SIGN_HASH` or `PSA_KEY_USAGE_SIGN_MESSAGE` for a key pair used for signing. + * `PSA_KEY_USAGE_DECRYPT` for a key pair used for decryption. + * `PSA_KEY_USAGE_DERIVE` for a key pair used for key agreement. + * `PSA_KEY_USAGE_VERIFY_HASH` or `PSA_KEY_USAGE_VERIFY_MESSAGE` for a public key pair used for signature verification. + * `PSA_KEY_USAGE_ENCRYPT` for a key pair used for encryption. +3. Optionally, tweak the attributes (this is rarely necessary). For example: + * Call [`psa_set_key_usage_flags`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga42a65b3c4522ce9b67ea5ea7720e17de), [`psa_set_key_algorithm`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gaeb8341ca52baa0279475ea3fd3bcdc98) and/or [`psa_set_key_enrollment_algorithm`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__extra_8h/#group__attributes_1gaffa134b74aa52aa3ed9397fcab4005aa) to change the key's policy (by default, it allows what can be done through the PK module). + · Call [`psa_set_key_id`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gae48fcfdc72a23e7499957d7f54ff5a64) and perhaps [`psa_set_key_lifetime`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gac03ccf09ca6d36cc3d5b43f8303db6f7) if you wish to create a PSA persistent key. +4. Call [`mbedtls_pk_import_into_psa`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/pk_8h/#pk_8h_1ad59835d14832daf0f4b4bd0a4555abb9) to import the key into the PSA key store. +5. You can now free the PK object with `mbedtls_pk_free`. + +Here is some sample code illustrating the above process, with error checking omitted. + +``` +mbedtls_pk_context pk; +mbedtls_pk_init(&pk); +mbedtls_pk_parse_key(&pk, key_buffer, key_buffer_length, NULL, 0, + mbedtls_psa_get_random, MBEDTLS_PSA_RANDOM_STATE); +psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; +mbedtls_pk_get_psa_attributes(&pk, PSA_KEY_USAGE_SIGN_HASH, &attributes); +psa_key_id_t key_id; +mbedtls_pk_import_into_psa(&pk, &attributes, &key_id); +mbedtls_pk_free(&pk); +psa_sign_hash(key_id, ...); +``` + +### Key pair and public key metadata + +There is no equivalent to the type `mbedtls_pk_info_t` and the functions `mbedtls_pk_info_from_type` in the PSA API because it is unnecessary. All macros and functions operate directly on key type values (`psa_key_type_t`, `PSA_KEY_TYPE_xxx` constants) and algorithm values (`psa_algorithm_t`, `PSA_ALG_xxx` constants). + +You can call [`psa_get_key_attributes`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gacbbf5c11eac6cd70c87ffb936e1b9be2) to populate a structure with the attributes of a key, then functions such as [`psa_get_key_type`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gae4fb812af4f57aa1ad85e335a865b918) and [`psa_get_key_bits`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga5bee85c2164ad3d4c0d42501241eeb06) to obtain a key's type (`PSA_KEY_TYPE_xxx` value) and size (nominal size in bits). + +The bit-size from `psa_get_key_bits` is the same as the one from `mbedtls_pk_get_bitlen`. To convert to bytes as `mbedtls_pk_get_len` or `mbedtls_rsa_get_len` do, you can use the macro `PSA_BITS_TO_BYTES`. However, note that the PSA API has generic macros for each related buffer size (export, signature size, etc.), so you should generally use those instead. The present document lists those macros where it explains the usage of the corresponding function. + +Most code that calls `mbedtls_pk_get_type` or `mbedtls_pk_can_do` only requires the key's type as reported by [`psa_get_key_type`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gae4fb812af4f57aa1ad85e335a865b918). If you need more information, you can call `mbedtls_pk_can_do_psa()`, which checks the compatibility between a key object and a mechanism. This function is new in TF-PSA-Crypto 1.0, and generalizes the function [`mbedtls_pk_can_do_ext`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/pk_8h/#pk_8h_1a256d3e8d4323a45aafa7d2b6c59a36f6) from Mbed TLS 3.x. If needed, you can also access a key's policy from its attributes with [`psa_get_key_usage_flags`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gaa1af20f142ca722222c6d98678a0c448), [`psa_get_key_algorithm`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gac255da850a00bbed925390044f016b34) and [`psa_get_key_enrollment_algorithm`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga39803b62a97198cf630854db9b53c588). The algorithm policy also conveys the padding and hash information provided by the legacy functions `mbedtls_rsa_get_padding_mode` and `mbedtls_rsa_get_md_alg`. + +### Exporting a public key or a key pair + +To export a PSA key pair or public key, call [`psa_export_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga668e35be8d2852ad3feeef74ac6f75bf). If the key is a key pair, its policy must allow `PSA_KEY_USAGE_EXPORT` (see “[Public-key cryptography policies](#public-key-cryptography-policies)”). + +To export a PSA public key or to export the public key of a PSA key pair object, call [`psa_export_public_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1gaf22ae73312217aaede2ea02cdebb6062). This is always permitted regardless of the key's policy. + +The export format is the same format used for `psa_import_key`, described in “[Creating keys for asymmetric cryptography](#creating-keys-for-asymmetric-cryptography)” above. + +A future extension of the PSA API will support other export formats. Until those are implemented, see “[Exposing a PSA key via PK](#exposing-a-psa-key-via-pk)” for ways to use the PK module to format a PSA key. + +#### Exposing a PSA key via PK + +This section discusses how to use a PSA key in a context that requires a PK object, such as PK formatting functions (`mbedtls_pk_write_key_der`, `mbedtls_pk_write_pubkey_der`, `mbedtls_pk_write_pubkey_pem`, `mbedtls_pk_write_key_pem` or `mbedtls_pk_write_pubkey`), Mbed TLS X.509 functions, Mbed TLS SSL functions, or another API that involves `mbedtls_pk_context` objects. The PSA key must be an RSA or ECC key since the PK module does not support DH keys. Three functions from `pk.h` help with that: + +* [`mbedtls_pk_copy_from_psa`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/pk_8h/#pk_8h_1ab8e88836fd9ee344ffe630c40447bd08) copies a PSA key into a PK object. The PSA key must be exportable. The PK object remains valid even if the PSA key is destroyed. +* [`mbedtls_pk_copy_public_from_psa`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/pk_8h/#pk_8h_1a2a50247a528889c12ea0ddddb8b15a4e) copies the public part of a PSA key into a PK object. The PK object remains valid even if the PSA key is destroyed. +* `mbedtls_pk_wrap_psa` (new under this name in TF-PSA-Crypto 1.0, corresponding to [`mbedtls_pk_setup_opaque`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/pk_8h/#pk_8h_1a4c04ac22ab9c1ae09cc29438c308bf05) in Mbed TLS 3.x) sets up a PK object that wraps the PSA key. This PK object can only be used as permitted by the PSA key's policy. The PK object contains a reference to the PSA key identifier, therefore the PSA key must not be destroyed as long as the PK object remains alive. + +Here is some sample code illustrating how to use the PK module to format a PSA public key or the public key of a PSA key pair. +``` +int write_psa_pubkey(psa_key_id_t key_id, + unsigned char *buf, size_t size, size_t *len) { + mbedtls_pk_context pk; + mbedtls_pk_init(&pk); + int ret = mbedtls_pk_copy_public_from_psa(key_id, &pk); + if (ret != 0) goto exit; + ret = mbedtls_pk_write_pubkey_der(&pk, buf, size); + if (ret < 0) goto exit; + *len = ret; + memmove(buf, buf + size - ret, ret); + ret = 0; +exit: + mbedtls_pk_free(&pk); +} +``` + +#### Restartable public key export + +Code that uses restartable ECC (see “[Restartable ECDSA signature](#restartable-ecdsa-signature)) may require an interruptible way to calculate the public key from an object containing only the private key. The legacy API did not provide an explicit way to do it, but this could be done by invoking `mbedtls_ecp_mul_restart()` to do the computation manually. + +As of TF-PSA-Crypto 1.0, PSA ECC key pair objects in fact only contain the private key, and `psa_export_public_key()` calculates the public key on each call. If needed, you can use the interruptible variant of this function, first released in TF-PSA-Crypto 1.0. + +1. Call [`psa_export_public_key_iop_setup()`](https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/include/psa/crypto.h) to start the interruptible key agreement operation. +2. Call [`psa_export_public_key_iop_complete()`](https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/include/psa/crypto.h) repeatedly until it returns a status other than `PSA_OPERATION_INCOMPLETE`. + +If you need to cancel the operation after calling the start function without waiting for the loop calling the complete function to finish, call `psa_export_public_key_iop_abort()`. + +Call [`psa_interruptible_set_max_ops`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__interruptible__hash/#group__interruptible__hash_1ga6d86790b31657c13705214f373af869e) to set the number of basic operations per call. This is the same unit as `mbedtls_ecp_set_max_ops`. You can retrieve the current value with [`psa_interruptible_get_max_ops`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__interruptible__hash/#group__interruptible__hash_1ga73e66a6d93f2690b626fcea20ada62b2). The value is [`PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__interruptible/#group__interruptible_1gad19c1da7f6b7d59d5873d5b68eb943d4) if operations are not restartable, which corresponds to `mbedtls_ecp_restart_is_enabled()` being false. + + +### Signature operations + +The equivalent of `mbedtls_pk_sign` or `mbedtls_pk_sign_ext` to sign an already calculated hash is [`psa_sign_hash`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__asymmetric/#group__asymmetric_1ga785e746a31a7b2a35ae5175c5ace3c5c). +The key must be a key pair allowing the usage `PSA_KEY_USAGE_SIGN_HASH` (see “[Public-key cryptography policies](#public-key-cryptography-policies)”). +Use [`PSA_SIGN_OUTPUT_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_SIGN_OUTPUT_SIZE) or [`PSA_SIGNATURE_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_SIGNATURE_MAX_SIZE) (similar to `MBEDTLS_PK_SIGNATURE_MAX_SIZE`) to determine a sufficient size for the output buffer. +This is also the equivalent of the type-specific functions `mbedtls_rsa_pkcs1_sign`, `mbedtls_rsa_rsassa_pkcs1_v15_sign`, `mbedtls_rsa_rsassa_pss_sign`, `mbedtls_rsa_rsassa_pss_sign_ext`, `mbedtls_ecdsa_sign`, `mbedtls_ecdsa_sign_det_ext` and `mbedtls_ecdsa_write_signature`. Note that the PSA API uses the raw format for ECDSA signatures, not the ASN.1 format; see “[ECDSA signature](#ecdsa-signature)” for more details. + +The equivalent of `mbedtls_pk_verify` or `mbedtls_pk_verify_ext` to verify an already calculated hash is [`psa_verify_hash`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__asymmetric/#group__asymmetric_1gae2ffbf01e5266391aff22b101a49f5f5). +The key must be a public key (or a key pair) allowing the usage `PSA_KEY_USAGE_VERIFY_HASH` (see “[Public-key cryptography policies](#public-key-cryptography-policies)”). +This is also the equivalent of the type-specific functions `mbedtls_rsa_pkcs1_verify`, `mbedtls_rsa_rsassa_pkcs1_v15_verify`, `mbedtls_rsa_rsassa_pss_verify`, `mbedtls_rsa_rsassa_pss_verify_ext`, `mbedtls_ecdsa_verify` and `mbedtls_ecdsa_read_signature`. Note that the PSA API uses the raw format for ECDSA signatures, not the ASN.1 format; see “[ECDSA signature](#ecdsa-signature)” for more details. + +Generally, `psa_sign_hash` and `psa_verify_hash` require the input to have the correct length for the hash (this has historically not always been enforced in the corresponding legacy APIs). + +See also “[Restartable ECDSA signature](#restartable-ecdsa-signature)” for a restartable variant of this API. + +The PSA API also has functions [`psa_sign_message`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__asymmetric/#group__asymmetric_1ga963ecadae9c38c85826f9a13cf1529b9) and [`psa_verify_message`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__asymmetric/#group__asymmetric_1ga01c11f480b185a4268bebd013df7c14c). These functions combine the hash calculation with the signature calculation or verification. +For `psa_sign_message`, either the usage flag `PSA_KEY_USAGE_SIGN_MESSAGE` or `PSA_KEY_USAGE_SIGN_HASH` is sufficient. +For `psa_verify_message`, either the usage flag `PSA_KEY_USAGE_VERIFY_MESSAGE` or `PSA_KEY_USAGE_VERIFY_HASH` is sufficient. + +Most signature algorithms involve a hash algorithm. See “[Hash mechanism selection](#hash-mechanism-selection)”. + +The following subsections describe the PSA signature mechanisms that correspond to legacy Mbed TLS mechanisms. + +#### ECDSA signature + +**Note: in the PSA API, the format of an ECDSA signature is the raw fixed-size format. This is different from the legacy API** which uses the ASN.1 DER format for ECDSA signatures. To convert between the two formats, use [`mbedtls_ecdsa_raw_to_der`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/psa__util_8h/#group__psa__tls__helpers_1ga9295799b5437bdff8ce8abd524c5ef2e) or [`mbedtls_ecdsa_der_to_raw`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/psa__util_8h/#group__psa__tls__helpers_1ga33b3cf65d5992ccc724b7ee00186ae61) from ``. + + + +ECDSA is the mechanism provided by `mbedtls_pk_sign` and `mbedtls_pk_verify` for ECDSA keys, as well as by `mbedtls_ecdsa_sign`, `mbedtls_ecdsa_sign_det_ext`, `mbedtls_ecdsa_write_signature`, `mbedtls_ecdsa_verify` and `mbedtls_ecdsa_read_signature`. + +The PSA API offers three algorithm constructors for ECDSA. They differ only for signature, and have exactly the same behavior for verification. + +* [`PSA_ALG_ECDSA(hash)`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga7e3ce9f514a227d5ba5d8318870452e3) is a randomized ECDSA signature of a hash calculated with the algorithm `hash`. +* [`PSA_ALG_ECDSA_ANY`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga51d6b6044a62e33cae0cf64bfc3b22a4) is equivalent to `PSA_ALG_ECDSA`, but does not require specifying a hash as part of the algorithm. It can only be used with `psa_sign_hash` and `psa_verify_hash`, with no constraint on the length of the hash. +* [`PSA_ALG_DETERMINISTIC_ECDSA(hash)`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga11da566bcd341661c8de921e2ca5ed03) is a deterministic ECDSA signature of a hash calculated with the algorithm `hash`. This is the same as the functionality offered by `MBEDTLS_ECDSA_DETERMINISTIC` in the legacy API. + * For `psa_sign_message` with `PSA_ALG_DETERMINISTIC_ECDSA`, the same hash algorithm is used to hash the message and to parametrize the deterministic signature generation. + +Unlike the legacy API, where `mbedtls_pk_sign` and `mbedtls_ecdsa_write_signature` automatically select deterministic ECDSA if both are available, the PSA API requires the application to select the preferred variant. ECDSA verification cannot distinguish between randomized and deterministic ECDSA (except in so far as if the same message is signed twice and the signatures are different, then at least one of the signatures is not the determinstic variant), so in most cases switching between the two is a compatible change. + +Since TF-PSA-Crypto 1.0, the PK module provides the macro `MBEDTLS_PK_ALG_ECDSA(hash)`, which is equivalent to either `PSA_ALG_ECDSA(hash)` or `PSA_ALG_DETERMINISTIC_ECDSA(hash)`. This macro indicates which ECDSA variant the function `mbedtls_pk_sign()` uses (except when constrained by the key's policy). + +#### Restartable ECDSA signature + +The legacy API includes an API for “restartable” ECC operations: the operation returns after doing partial computation, and can be resumed. This is intended for highly constrained devices where long cryptographic calculations need to be broken up to poll some inputs, where interrupt-based scheduling is not desired. The legacy API for signature consists of the functions `mbedtls_pk_sign_restartable`, `mbedtls_pk_verify_restartable`, `mbedtls_ecdsa_sign_restartable`, `mbedtls_ecdsa_verify_restartable`, `mbedtls_ecdsa_write_signature_restartable`, `mbedtls_ecdsa_read_signature_restartable`, as well as several configuration and data manipulation functions. + +The PSA API offers similar functionality via “interruptible” public-key operations. As of TF-PSA-Crypto 1.0, it is only implemented for ECDSA and ECDH (see “[Restartable key agreement](#restartable-key-agreement)”), for the same curves as the legacy API. (Mbed TLS 3.6 only has interruptible ECDSA signature, not ECDH key agrement.) At the time of writing, no extension is planned to other curves or other algorithms. + +The flow of operations for an interruptible signature operation is as follows: + +1. Create an operation object of type [`psa_sign_hash_interruptible_operation_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__interruptible__hash/#group__interruptible__hash_1ga6948d4653175b1b530a265540066a7e7) and zero-initialize it (or use the corresponding `INIT` macro). +2. Call [`psa_sign_hash_start`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__interruptible__hash/#group__interruptible__hash_1ga441988da830205182b3e791352537fac) with the private key object and the hash to verify. +3. Call [`psa_sign_hash_complete`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__interruptible__hash/#group__interruptible__hash_1ga79849aaa7004a85d2ffbc4b658a333dd) repeatedly until it returns a status other than `PSA_OPERATION_INCOMPLETE`. + +The flow of operations for an interruptible signature verification operation is as follows: + +1. Create an operation object of type [`psa_verify_hash_interruptible_operation_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__interruptible__hash/#group__interruptible__hash_1ga537054cf4909ad1426331ae4ce7148bb) and zero-initialize it (or use the corresponding `INIT` macro). +2. Call [`psa_verify_hash_start`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__interruptible__hash/#group__interruptible__hash_1ga912eb51fb94056858f451f276ee289cb) with the private key object and the hash and signature to verify. +3. Call [`psa_verify_hash_complete`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__interruptible__hash/#group__interruptible__hash_1ga67fe82352bc2f8c0343e231a70a5bc7d) repeatedly until it returns a status other than `PSA_OPERATION_INCOMPLETE`. + +If you need to cancel the operation after calling the start function without waiting for the loop calling the complete function to finish, call [`psa_sign_hash_abort`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__interruptible__hash/#group__interruptible__hash_1gae893a4813aa8e03bd201fe4f1bbbb403) or [`psa_verify_hash_abort`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__interruptible__hash/#group__interruptible__hash_1ga18dc9c0cc27d590c5e3b186094d90f88). + +Call [`psa_interruptible_set_max_ops`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__interruptible__hash/#group__interruptible__hash_1ga6d86790b31657c13705214f373af869e) to set the number of basic operations per call. This is the same unit as `mbedtls_ecp_set_max_ops`. You can retrieve the current value with [`psa_interruptible_get_max_ops`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__interruptible__hash/#group__interruptible__hash_1ga73e66a6d93f2690b626fcea20ada62b2). The value is [`PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__interruptible/#group__interruptible_1gad19c1da7f6b7d59d5873d5b68eb943d4) if operations are not restartable, which corresponds to `mbedtls_ecp_restart_is_enabled()` being false. + +#### PKCS#1 v1.5 RSA signature + +This mechanism corresponds to `mbedtls_pk_sign`, `mbedtls_pk_verify`, `mbedtls_rsa_pkcs1_sign` and `mbedtls_rsa_pkcs1_verify` for an RSA key, unless PSS has been selected with `mbedtls_rsa_set_padding` on the underlying RSA key context. This mechanism also corresponds to `mbedtls_rsa_rsassa_pkcs1_v15_sign` and `mbedtls_rsa_rsassa_pkcs1_v15_verify`. + +The PSA API has two algorithm constructors: + +* [`PSA_ALG_RSA_PKCS1V15_SIGN(hash)`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga702ff75385a6ae7d4247033f479439af) formats the hash as specified in PKCS#1. The hash algorithm corresponds to the `md_alg` parameter of the legacy functions. +* [`PSA_ALG_RSA_PKCS1V15_SIGN_RAW`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga4215e2a78dcf834e9a625927faa2a817) uses the “hash” input in lieu of a DigestInfo structure. This is the same as calling the legacy functions with `md_alg=MBEDTLS_MD_NONE`. + +#### PKCS#1 RSASSA-PSS signature + +This mechanism corresponds to `mbedtls_pk_sign_ext` and `mbedtls_pk_verify_ext` for an RSA key, as well as `mbedtls_pk_sign`, `mbedtls_pk_verify`, `mbedtls_rsa_pkcs1_sign` and `mbedtls_rsa_pkcs1_verify` if PSS has been selected on the underlying RSA context with `mbedlts_rsa_set_padding`. +It also corresponds to `mbedtls_rsa_rsassa_pss_sign` and `mbedtls_rsa_rsassa_pss_sign_ext`, `mbedtls_rsa_rsassa_pss_verify` and `mbedtls_rsa_rsassa_pss_verify_ext`. + +The PSA API has two algorithm constructors: [`PSA_ALG_RSA_PSS(hash)`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga62152bf4cb4bf6aace5e1be8f143564d) and [`PSA_ALG_RSA_PSS_ANY_SALT(hash)`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga9b7355a2cd6bde88177634d539127f2b). They differ only for verification, and have exactly the same behavior for signature. The hash algorithm `hash` corresponds to the `md_alg` parameter passed to the legacy API. It is used to hash the message, to create the salted hash, and for the mask generation with MGF1. The PSA API does not support using different hash algorithms for these different purposes. + +With respect to the salt length: + +* When signing, the salt is random, and the salt length is the largest possible salt length up to the hash length. This is the same as passing `MBEDTLS_RSA_SALT_LEN_ANY` as the salt length to `xxx_ext` legacy functions or using a legacy function that does not have a `saltlen` argument. +* When verifying, `PSA_ALG_RSA_PSS` requires the the salt length to the largest possible salt length up to the hash length (i.e. the same that would be used for signing). +* When verifying, `PSA_ALG_RSA_PSS_ANY_SALT` accepts any salt length. This is the same as passing `MBEDTLS_RSA_SALT_LEN_ANY` as the salt length to `xxx_ext` legacy functions or using a legacy function that does not have a `saltlen` argument. + +### Asymmetric encryption and decryption + +The equivalent of `mbedtls_pk_encrypt`, `mbedtls_rsa_pkcs1_encrypt`, `mbedtls_rsa_rsaes_pkcs1_v15_encrypt` or `mbedtls_rsa_rsaes_oaep_encrypt` to encrypt a short message (typically a symmetric key) is [`psa_asymmetric_encrypt`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__asymmetric/#group__asymmetric_1gaa17f61e4ddafd1823d2c834b3706c290). +The key must be a public key (or a key pair) allowing the usage `PSA_KEY_USAGE_ENCRYPT` (see “[Public-key cryptography policies](#public-key-cryptography-policies)”). +Use the macro [`PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#crypto__sizes_8h_1a66ba3bd93e5ec52870ccc3848778bad8) or [`PSA_ASYMMETRIC_ENCRYPT_OUTPUT_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_ASYMMETRIC_ENCRYPT_OUTPUT_MAX_SIZE) to determine the output buffer size. + +The equivalent of `mbedtls_pk_decrypt`, `mbedtls_rsa_pkcs1_decrypt`, `mbedtls_rsa_rsaes_pkcs1_v15_decrypt` or `mbedtls_rsa_rsaes_oaep_decrypt` to decrypt a short message (typically a symmetric key) is [`psa_asymmetric_decrypt`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__asymmetric/#group__asymmetric_1ga4f968756f6b22aab362b598b202d83d7). +The key must be a key pair allowing the usage `PSA_KEY_USAGE_DECRYPT` (see “[Public-key cryptography policies](#public-key-cryptography-policies)”). +Use the macro [`PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#crypto__sizes_8h_1a61a246f3eac41989821d982e56fea6c1) or [`PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE) to determine the output buffer size. + +The following subsections describe the PSA asymmetric encryption mechanisms that correspond to legacy Mbed TLS mechanisms. + +#### RSA PKCS#1v1.5 encryption + +This is the mechanism used by the PK functions and by `mbedtls_rsa_pkcs1_{encrypt,decrypt}` unless `mbedtls_rsa_set_padding` has been called on the underlying RSA key context. +This is also the mechanism used by `mbedtls_rsa_rsaes_pkcs1_v15_{encrypt,decrypt}`. + +The PSA algorithm is [`PSA_ALG_RSA_PKCS1V15_CRYPT`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga4c540d3abe43fb9abcb94f2bc51acef9). + +Beware that PKCS#1v1.5 decryption is subject to padding oracle attacks. Revealing when `psa_asymmetric_decrypt` returns `PSA_ERROR_INVALID_PADDING` may allow an adversary to decrypt arbitrary ciphertexts. + +#### RSA RSAES-OAEP + +This is the mechanism used by `mbedtls_rsa_rsaes_oaep_{encrypt,decrypt}`. + +The PSA algorithm is [`PSA_ALG_RSA_OAEP(hash)`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gaa1235dc3fdd9839c6c1b1a9857344c76) where `hash` is a hash algorithm value (`PSA_ALG_xxx`, see “[Hash mechanism selection](#hash-mechanism-selection)”). + +As with the PK API, the mask generation is MGF1, the label is empty, and the same hash algorithm is used for MGF1 and to hash the label. The PSA API does not offer a way to choose a different label or a different hash algorithm for the label. + +### Private-public key consistency + +There is no direct equivalent of the functions `mbedtls_rsa_check_privkey`, `mbedtls_rsa_check_pubkey`,`mbedtls_ecp_check_privkey`, `mbedtls_ecp_check_pubkey`. The PSA API performs some basic checks when it imports a key, and may perform additional checks before performing an operation if needed, so it will never perform an operation on a key that does not satisfy these checks, but the details of when the check is performed may change between versions of the library. + +The legacy API provides the function `mbedtls_pk_check_pair`, which can be used to check the consistency between a private key and a public key. To perform such a check with the PSA API, you can export the public keys; this works because the PSA representation of public keys is canonical. + +* Prepare a key object containing the private key, for example with [`psa_import_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga0336ea76bf30587ab204a8296462327b). +* Prepare a key object containing the public key, for example with [`psa_import_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga0336ea76bf30587ab204a8296462327b). +* Export both public keys with [`psa_export_public_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1gaf22ae73312217aaede2ea02cdebb6062) (this is possible regardless of the usage policies on the keys) and compare the output. + ``` + // Error checking omitted + unsigned char pub1[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE]; + unsigned char pub2[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE]; + size_t length1, length2; + psa_export_public_key(key1, pub1, sizeof(pub1), &length1); + psa_export_public_key(key2, pub2, sizeof(pub2), &length2); + if (length1 == length2 && !memcmp(pub1, pub2, length1)) + puts("The keys match"); + else + puts("The keys do not match"); + ``` + +### PK functionality with no PSA equivalent + +There is no PSA equivalent of the debug functionality provided by `mbedtls_pk_debug`. Use `psa_export_key` to export the key if desired. + +There is no PSA equivalent to Mbed TLS's custom key type names exposed by `mbedtls_pk_get_name`. + +### Key agreement + +The PSA API has a generic interface for key agreement, covering the main use of both `ecdh.h` and `dhm.h`. + + + +#### Diffie-Hellman key pair management + +The PSA API manipulates keys as such, rather than via an operation context. Thus, to use Diffie-Hellman, you need to create a key object, then perform the key exchange, then destroy the key. There is no equivalent to the types `mbedtls_ecdh_context` and `mbedtls_dhm_context`. + +Here is an overview of the lifecycle of a key object. + +1. First define the attributes of the key by filling a [`psa_key_attributes_t` structure](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga0ec645e1fdafe59d591104451ebf5680). You need to set the following parameters: + * Call [`psa_set_key_type`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga6857ef0ecb3fa844d4536939d9c64025) to set the key type to the desired `PSA_KEY_TYPE_xxx` value: + * [`PSA_KEY_TYPE_DH_KEY_PAIR(group)`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gab4f857c4cd56f5fe65ded421e61bcc8c) for finite-field Diffie-Hellman (see “[Diffie-Hellman mechanism selection](#diffie-hellman-mechanism-selection)”). + * [`PSA_KEY_TYPE_ECC_KEY_PAIR(curve)`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga0b6f5d4d5037c54ffa850d8059c32df0) for elliptic-curve Diffie-Hellman (see “[Elliptic curve mechanism selection](#elliptic-curve-mechanism-selection)”). + * Call [`psa_set_key_bits`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gaf61683ac87f87687a40262b5afbfa018) to set the private key size in bits. This is optional with `psa_import_key`, which determines the key size from the length of the key material. + * Call [`psa_set_key_algorithm`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gaeb8341ca52baa0279475ea3fd3bcdc98) to select the appropriate algorithm: + * [`PSA_ALG_ECDH`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1gab2dbcf71b63785e7dd7b54a100edee43) or [`PSA_ALG_FFDH`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga0ebbb6f93a05b6511e6f108ffd2d1eb4) for a raw key agreement. + * [`PSA_ALG_KEY_AGREEMENT(ka, kdf)`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__crypto__types/#group__crypto__types_1ga78bb81cffb87a635c247725eeb2a2682) if the key will be used as part of a key derivation, where: + * `ka` is either `PSA_ALG_ECDH` or `PSA_ALG_FFDH`. + * `kdf` is a key derivation algorithm. + * Call [`psa_set_key_usage_flags`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga42a65b3c4522ce9b67ea5ea7720e17de) to enable at least [`PSA_KEY_USAGE_DERIVE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__policy/#c.PSA_KEY_USAGE_DERIVE). See “[Public-key cryptography policies](#public-key-cryptography-policies)” for more information. +2. Call one of the key creation functions, passing the attributes defined in the previous step, to get an identifier of type [`psa_key_id_t`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__types_8h/#_CPPv412psa_key_id_t) to the key object. + * Use [`psa_generate_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__random/#group__random_1ga1985eae417dfbccedf50d5fff54ea8c5) to generate a random key. This is normally the case for a Diffie-Hellman key. + * Use [`psa_import_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga0336ea76bf30587ab204a8296462327b) to directly import key material. + * If the key is derived deterministically from other material, use the [key derivation interface](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/) and create the key with [`psa_key_derivation_output_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1gada7a6e17222ea9e7a6be6864a00316e1). +3. Call the functions in the following sections to perform operations on the key. The same key object can be used in multiple operations. +4. To free the resources used by the key object, call [`psa_destroy_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__management/#group__key__management_1ga5f52644312291335682fbc0292c43cd2) after all operations with that key are finished. + +#### Performing a key agreement + +Call [`psa_export_public_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1gaf22ae73312217aaede2ea02cdebb6062) to obtain the public key that needs to be sent to the other party. +Use the macros [`PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE) or [`PSA_EXPORT_PUBLIC_KEY_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_EXPORT_PUBLIC_KEY_MAX_SIZE) to determine a sufficient size for the output buffer. + +Call [`psa_raw_key_agreement`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1ga90fdd2716124d0bd258826184824675f) to calculate the shared secret from your private key and the other party's public key. +Use the macros [`PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE) or [`PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE) to determine a sufficient size for the output buffer. + +Call [`psa_key_derivation_key_agreement`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1ga2cd5a8ac906747d3204ec442db78745f) instead of `psa_raw_key_agreement` to use the resulting shared secret as the secret input to a key derivation. See “[HKDF](#hkdf)” for an example of the key derivation interface. + +#### Translating a legacy key agreement contextless workflow + +A typical workflow for ECDH using the legacy API without a context object is: + +1. Initialize objects: + * `mbedtls_ecp_group grp` for the curve; + * `mbedtls_mpi our_priv` for our private key; + * `mbedtls_ecp_point our_pub` for our public key; + * `mbedtls_ecp_point their_pub` for their public key (this may be the same variable as `our_pub` if the application does not need to hold both at the same time); + * `mbedtls_mpi z` for the shared secret (this may be the same variable as `our_priv` when doing ephemeral ECDH). +2. Call `mbedtls_ecp_group_load` on `grp` to select the curve. +3. Call `mbedtls_ecdh_gen_public` on `grp`, `our_priv` (output) and `our_pub` (output) to generate a key pair and retrieve the corresponding public key. +4. Send `our_pub` to the peer. Retrieve the peer's public key and import it into `their_pub`. These two actions may be performed in either order. +5. Call `mbedtls_ecdh_compute_shared` on `grp`, `z` (output), `their_pub` and `our_priv`. Use the raw shared secret `z`, typically, to construct a shared key. +6. Free `grp`, `our_priv`, `our_pub`, `their_pub` and `z`. + +The corresponding workflow with the PSA API is as follows: + +1. Initialize objects: + * `psa_key_id_t our_key`: a handle to our key pair; + * `psa_key_attributes_t attributes`: key attributes used in steps 2–3;; + * `our_pub`: a buffer of size [`PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(key_type, bits)`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE) (where `key_type` is the value passed to `psa_set_key_size` in step 2) or [`PSA_EXPORT_PUBLIC_KEY_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_EXPORT_PUBLIC_KEY_MAX_SIZE) to hold our key. + * `their_pub`: a buffer of the same size, to hold the peer's key. This can be the same as `our_pub` if the application does not need to hold both at the same time; + * `shared_secret`: a buffer of size [`PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(key_type, bits)`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE) or [`PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE) (if not using a key derivation operation). +2. Prepare an attribute structure as described in “[Diffie-Hellman key pair management](#diffie-hellman-key-pair-management)”, in particular selecting the curve with `psa_set_key_type`. +3. Call [`psa_generate_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__random/#group__random_1ga1985eae417dfbccedf50d5fff54ea8c5) on `attributes` and `our_key` (output) to generate a key pair, then [`psa_export_public_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1gaf22ae73312217aaede2ea02cdebb6062) on `our_key` and `our_pub` (output) to obtain our public key. +4. Send `our_pub` to the peer. Retrieve the peer's public key and import it into `their_pub`. These two actions may be performed in either order. +5. Call [`psa_raw_key_agreement`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1ga90fdd2716124d0bd258826184824675f) on `our_key`, `their_pub` and `shared_secret` (output). + Alternatively, call `psa_key_derivation_key_agreement` to use the shared secret directly in a key derivation operation (see “[Performing a key agreement](#performing-a-key-agreement)”). +6. Call [`psa_destroy_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__management/#group__key__management_1ga5f52644312291335682fbc0292c43cd2) on `key_id`, and free the memory buffers. + +Steps 4–6 are only performed once for a "true" ephemeral Diffie-Hellman. They may be repeated multiple times for a "fake ephemeral" Diffie-Hellman where the same private key is used for multiple key exchanges, but it not saved. + +#### Translating a legacy ephemeral key agreement TLS server workflow + +The legacy API offers the following workflow for an ephemeral Diffie-Hellman key agreement in a TLS 1.2 server. The PSA version of this workflow can also be used with other protocols, on the side of the party that selects the curve or group and sends its public key first. + +1. Setup phase: + 1. Initialize a context of type `mbedtls_ecdh_context` or `mbedtls_dhm_context` with `mbedtls_ecdh_init` or `mbedtls_dhm_init`. + 2. Call `mbedtls_ecdh_setup` or `mbedtls_dhm_set_group` to select the curve or group. + 3. Call `mbedtls_ecdh_make_params` or `mbedtls_dhm_make_params` to generate our key pair and obtain a TLS ServerKeyExchange message encoding the selected curve/group and our public key. +2. Send the ServerKeyExchange message to the peer. +3. Retrieve the peer's public key. +4. Call `mbedtls_ecdh_read_public` or `mbedtls_dhm_read_public` on the peer's public key, then call `mbedtls_ecdh_calc_secret` or `mbedtls_dhm_calc_secret` to calculate the shared secret. +5. Free the context with `mbedtls_ecdh_free` or `mbedtls_dhm_free`. + +The corresponding workflow with the PSA API is as follows: + +1. Setup phase: + 1. Generate an ECDH or DHM key pair with `psa_generate_key` as described in “[Diffie-Hellman key pair management](#diffie-hellman-key-pair-management)”. + 2. Call [`psa_export_public_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1gaf22ae73312217aaede2ea02cdebb6062) to obtain our public key. + 3. Format a ServerKeyExchange message containing the curve/group selection and our public key. +2. Send the ServerKeyExchange message to the peer. +3. Retrieve the peer's public key. +4. Call [`psa_raw_key_agreement`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1ga90fdd2716124d0bd258826184824675f) on `our_key`, `their_pub` and `shared_secret` (output). + Alternatively, call `psa_key_derivation_key_agreement` to use the shared secret directly in a key derivation operation (see “[Performing a key agreement](#performing-a-key-agreement)”). +5. Call [`psa_destroy_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__management/#group__key__management_1ga5f52644312291335682fbc0292c43cd2) to free the resources associated with our key pair. + +#### Translating a legacy ephemeral key agreement TLS client workflow + +The legacy API offers the following workflow for an ephemeral Diffie-Hellman key agreement in a TLS 1.2 client. The PSA version of this workflow can also be used with other protocols, on the side of the party that receives a message indicating both the choice of curve or group, and the peer's public key. + +1. Upon reception of a TLS ServerKeyExchange message received from the peer, which encodes the selected curve/group and the peer's public key: + 1. Initialize a context of type `mbedtls_ecdh_context` or `mbedtls_dhm_context` with `mbedtls_ecdh_init` or `mbedtls_dhm_init`. + 2. Call `mbedtls_ecdh_read_params` or `mbedtls_dhm_read_params` to input the data from the ServerKeyExchange message. +2. Call `mbedtls_ecdh_make_public` or `mbedtls_dh_make_public` to generate our private key and export our public key. +3. Send our public key to the peer. +4. Call `mbedtls_ecdh_calc_secret` or `mbedtls_dhm_calc_secret` to calculate the shared secret. +5. Free the context with `mbedtls_ecdh_free` or `mbedtls_dhm_free`. + +The corresponding workflow with the PSA API is as follows: + +1. Upon reception of a TLS ServerKeyExchange message received from the peer, which encodes the selected curve/group and the peer's public key: + 1. Decode the selected curve/group and use this to determine a PSA key type (`PSA_KEY_TYPE_ECC_KEY_PAIR(curve)` or `PSA_KEY_TYPE_DH_KEY_PAIR(group)`), a key size and an algorithm. +2. Generate an ECDH or DHM key pair with `psa_generate_key` as described in “[Diffie-Hellman key pair management](#diffie-hellman-key-pair-management)”. + Call [`psa_export_public_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1gaf22ae73312217aaede2ea02cdebb6062) to obtain our public key. +3. Send our public key to the peer. +4. Call [`psa_raw_key_agreement`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__derivation/#group__key__derivation_1ga90fdd2716124d0bd258826184824675f) on `our_key`, `their_pub` and `shared_secret` (output). + Alternatively, call `psa_key_derivation_key_agreement` to use the shared secret directly in a key derivation operation (see “[Performing a key agreement](#performing-a-key-agreement)”). +5. Call [`psa_destroy_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__key__management/#group__key__management_1ga5f52644312291335682fbc0292c43cd2) to free the resources associated with our key pair. + +#### ECDH and DHM metadata functions + +You can obtain data and metadata from an ECDH key agreement through the PSA API as follows: + +* With either side, accessing the group: call [`psa_get_key_attributes`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gacbbf5c11eac6cd70c87ffb936e1b9be2) on the key identifier, then [`psa_get_key_type`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gae4fb812af4f57aa1ad85e335a865b918) and [`psa_get_key_bits`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga5bee85c2164ad3d4c0d42501241eeb06) to obtain metadata about the key. +* Accessing our public key: call [`psa_export_public_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1gaf22ae73312217aaede2ea02cdebb6062) on the PSA key identifier. +* Accessing our private key: call [`psa_export_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga668e35be8d2852ad3feeef74ac6f75bf) on the key identifier. Note that the key policy must allow `PSA_KEY_USAGE_EXPORT` (see “[Public-key cryptography policies](#public-key-cryptography-policies)”). +* Accessing the peer's public key: there is no PSA equivalent since the PSA API only uses the peer's public key to immediately calculate the shared secret. If your application needs the peer's public key for some other purpose, store it separately. + +The functions `mbedtls_dhm_get_bitlen`, `mbedtls_dhm_get_len` and `mbedtls_dhm_get_value` allow the caller to obtain metadata about the keys used for the key exchange. The PSA equivalents access the key identifier: + +* `mbedtls_dhm_get_bitlen`, `mbedtls_dhm_get_len`: call [`psa_get_key_attributes`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gacbbf5c11eac6cd70c87ffb936e1b9be2) on the PSA key identifier, then [`psa_get_key_bits`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1ga5bee85c2164ad3d4c0d42501241eeb06). +* `mbedtls_dhm_get_value` for `MBEDTLS_DHM_PARAM_X` (our private key): call [`psa_export_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga668e35be8d2852ad3feeef74ac6f75bf) on the key identifier. Note that the key policy must allow `PSA_KEY_USAGE_EXPORT` (see “[Public-key cryptography policies](#public-key-cryptography-policies)”). +* `mbedtls_dhm_get_value` for `MBEDTLS_DHM_PARAM_GX` (our public key): call [`psa_export_public_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1gaf22ae73312217aaede2ea02cdebb6062) on the PSA key identifier. +* `mbedtls_dhm_get_value` for `MBEDTLS_DHM_PARAM_GY` (peer's public key): the there is no PSA equivalent since the PSA API only uses the peer's public key to immediately calculate the shared secret. If your application needs the peer's public key for some other purpose, store it separately. +* `mbedtls_dhm_get_value` for `MBEDTLS_DHM_PARAM_K` (shared secret): this is the value calculated by `psa_raw_key_agreement` or `psa_key_derivation_key_agreement`. If you need to use it multiple times (for example to derive multiple values independently), call `psa_raw_key_agreement` and make a copy. +* `mbedtls_dhm_get_value` for `MBEDTLS_DHM_PARAM_P` or `MBEDTLS_DHM_PARAM_G` (group parameters): [there is no PSA API to retrieve these values](https://github.com/Mbed-TLS/mbedtls/issues/7780). + +The PSA API for finite-field Diffie-Hellman only supports predefined groups. Therefore there is no equivalent to `mbedtls_dhm_parse_dhm`, `mbedtls_dhm_parse_dhmfile`, and the `MBEDTLS_DHM_xxx_BIN` macros. + +#### Restartable key agreement + +The legacy API includes an API for “restartable” ECC operations: the operation returns after doing partial computation, and can be resumed. This is intended for highly constrained devices where long cryptographic calculations need to be broken up to poll some inputs, where interrupt-based scheduling is not desired. The legacy API for ECDH is the same as the ordinary ECDH API, with an extra call to `mbedtls_ecdh_enable_restart()` on the ECDH context. The PSA API uses a different set of functions, available since TF-PSA-Crypto 1.0. + +1. Call [`psa_key_agreement_iop_setup()`](https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/include/psa/crypto.h) to start the interruptible key agreement operation. +2. Call [`psa_key_agreement_iop_complete()`](https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/include/psa/crypto.h) repeatedly until it returns a status other than `PSA_OPERATION_INCOMPLETE`. + +If you need to cancel the operation after calling the start function without waiting for the loop calling the complete function to finish, call `psa_key_agreement_iop_abort()`. + +Call [`psa_interruptible_set_max_ops`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__interruptible__hash/#group__interruptible__hash_1ga6d86790b31657c13705214f373af869e) to set the number of basic operations per call. This is the same unit as `mbedtls_ecp_set_max_ops`. You can retrieve the current value with [`psa_interruptible_get_max_ops`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__interruptible__hash/#group__interruptible__hash_1ga73e66a6d93f2690b626fcea20ada62b2). The value is [`PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__interruptible/#group__interruptible_1gad19c1da7f6b7d59d5873d5b68eb943d4) if operations are not restartable, which corresponds to `mbedtls_ecp_restart_is_enabled()` being false. + +### Additional information about Elliptic-curve cryptography + +#### Information about a curve + +The legacy API identifies a curve by an `MBEDTLS_ECP_DP_xxx` value of type `mbedtls_ecp_group_id`. The PSA API identifies a curve by a `PSA_ECC_FAMILY_xxx` value and the private value's bit-size. See “[Elliptic curve mechanism selection](#elliptic-curve-mechanism-selection)” for the correspondence between the two sets of values. + +There is no PSA equivalent of the `mbedtls_ecp_group` data structure (and so no equivalent to `mbedtls_ecp_group_init`, `mbedtls_ecp_group_load`, `mbedtls_ecp_group_copy` and `mbedtls_ecp_group_free`) or of the `mbedtls_ecp_curve_info` data structure (and so no equivalent to `mbedtls_ecp_curve_info_from_grp_id`) because they are not needed. All API elements identify the curve directly by its family and size. + +The bit-size used by the PSA API is the size of the private key. For most curves, the PSA bit-size, the `bit_size` field in `mbedtls_ecp_curve_info`, the `nbits` field in `mbedtls_ecp_group` and the `pbits` field in `mbedtls_ecp_group` are the same. The following table lists curves for which they are different. + +| Curve | `grp->nbits` | `grp->pbits` | `curve_info->bit_size` | PSA bit-size | +| ----- | ------------ | ------------ | ---------------------- | ------------ | +| Curve25519 | 253 | 255 | 256 | 255 | +| Curve448 | 446 | 448 | 448 | 448 | + +There is no exact PSA equivalent of the type `mbedtls_ecp_curve_type` and the function `mbedtls_ecp_get_type`, but the curve family encodes the same information. `PSA_ECC_FAMILY_MONTGOMERY` is the only Montgomery family. All other families supported in TF-PSA-Crypto 1.0 are short Weierstrass families. + +There is no PSA equivalent for the following functionality: + +* The `name` field of `mbedtls_ecp_curve_info`, and the function `mbedtls_ecp_curve_info_from_name`. There is no equivalent of Mbed TLS's lookup based on the name used for the curve in TLS specifications. +* The `tls_id` field of `mbedtls_ecp_curve_info`, the constant `MBEDTLS_ECP_TLS_NAMED_CURVE`, and the functions `mbedtls_ecp_curve_info_from_tls_id`, `mbedtls_ecp_tls_read_group`, `mbedtls_ecp_tls_read_group_id` and `mbedtls_ecp_tls_write_group`. The PSA crypto API does not have this dedicated support for the TLS protocol. +* Retrieving the parameters of a curve from the fields of an `mbedtls_ecp_group` structure. + +#### Information about supported curves + +The PSA API does not currently have a discovery mechanism for cryptographic mechanisms (although one may be added in the future). Thus there is no equivalent for `MBEDTLS_ECP_DP_MAX` and the functions `mbedtls_ecp_curve_list` and `mbedtls_ecp_grp_id_list`. + +The API provides macros that give the maximum supported sizes for various kinds of objects. The following table lists equivalents for `MBEDTLS_ECP_MAX_xxx` macros. + +| Legacy macro | PSA equivalent | +| ------------ | -------------- | +| `MBEDTLS_ECP_MAX_BITS` | [`PSA_VENDOR_ECC_MAX_CURVE_BITS`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_VENDOR_ECC_MAX_CURVE_BITS) | +| `MBEDTLS_ECP_MAX_BYTES` | `PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS)` | +| `MBEDTLS_ECP_MAX_PT_LEN` | [`PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS)`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__sizes_8h/#c.PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE) | + +#### Restartable ECC + +The PSA API supports the equivalent of restartable operations, but only for signatures at the time of writing. See “[Restartable ECDSA signature](#restartable-ecdsa-signature)”. + +There is no PSA API for elliptic curve arithmetic as such, and therefore no equivalent of `mbedtls_ecp_restart_ctx` and functions that operate on it. + +There is PSA no equivalent of the `MBEDTLS_ECP_OPS_xxx` constants. + +#### ECC functionality with no PSA equivalent + +There is no PSA equivalent of `mbedtls_ecdsa_can_do` and `mbedtls_ecdh_can_do` to query the capabilities of a curve at runtime. Check the documentation of each curve family to see what algorithms it supports. + +There is no PSA equivalent to the types `mbedtls_ecdsa_context` and `mbedtls_ecdsa_restart_ctx`, and to basic ECDSA context manipulation functions including `mbedtls_ecdsa_from_keypair`, because they are not needed: the PSA API does not have ECDSA-specific context types. + +#### No curve arithmetic + +The PSA API is a cryptography API, not an arithmetic API. As a consequence, there is no PSA equivalent for the ECC arithmetic functionality exposed by `ecp.h`: + +* Manipulation of point objects and input-output: the type `mbedtls_ecp_point` and functions operating on it (`mbedtls_ecp_point_xxx`, `mbedtls_ecp_copy`, `mbedtls_ecp_{set,is}_zero`, `mbedtls_ecp_tls_{read,write}_point`). Note that the PSA export format for public keys corresponds to the uncompressed point format (`MBEDTLS_ECP_PF_UNCOMPRESSED`), so [`psa_import_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga0336ea76bf30587ab204a8296462327b), [`psa_export_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga668e35be8d2852ad3feeef74ac6f75bf) and [`psa_export_public_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1gaf22ae73312217aaede2ea02cdebb6062) are equivalent to `mbedtls_ecp_point_read_binary` and `mbedtls_ecp_point_write_binary` for uncompressed points. The PSA API does not currently support compressed points, but it is likely that such support will be added in the future. +* Manipulation of key pairs as such, with a bridge to bignum arithmetic (`mbedtls_ecp_keypair` type, `mbedtls_ecp_export`). However, the PSA export format for ECC private keys used by [`psa_import_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga0336ea76bf30587ab204a8296462327b), [`psa_export_key`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__import__export/#group__import__export_1ga668e35be8d2852ad3feeef74ac6f75bf) is the same as the format used by `mbedtls_ecp_read_key` and `mbedtls_ecp_write_key_ext`. +* Elliptic curve arithmetic (`mbedtls_ecp_mul`, `mbedtls_ecp_muladd` and their restartable variants). + +### Additional information about RSA + +#### RSA-ALT interface + +Implementers of the RSA-ALT interface (`MBEDTLS_PK_RSA_ALT` pk type, `mbedtls_pk_setup_rsa_alt` setup function) must migrate to the [PSA cryptoprocessor driver interface](https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/docs/psa-driver-example-and-guide.md). + +* If the purpose of the ALT interface is acceleration only: use the accelerator driver interface. This is fully transparent to application code. +* If the purpose of the ALT interface is to isolate the private key in a high-security environment: use the opaque driver interface. This is mostly transparent to user code. Code that uses a key via its key identifier does not need to know whether the key is transparent (equivalent of `MBEDTLS_PK_RSA`) or opaque (equivalent of `MBEDTLS_PK_RSA_ALT`). When creating a key, it will be transparent by default; to create an opaque key, call [`psa_set_key_lifetime`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gac03ccf09ca6d36cc3d5b43f8303db6f7) to set the key's location to the chosen location value for the driver, e.g. + ``` + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( + PSA_KEY_PERSISTENCE_VOLATILE, MY_RSA_DRIVER_LOCATION)); + ``` + +The PSA subsystem uses its internal random generator both for randomized algorithms and to generate blinding values. As a consequence, none of the API functions take an RNG parameter. + +#### RSA functionality with no PSA equivalent + +The PSA API does not provide direct access to the exponentiation primitive as with `mbedtls_rsa_public` and `mbedtls_rsa_private`. If you need an RSA-based mechanism that is not supported by the PSA API, please [submit an issue on GitHub](https://github.com/ARM-software/psa-api/issues) so that we can extend the API to support it. + +The PSA API does not support constructing RSA keys progressively from numbers, like the legacy functions `mbedtls_rsa_import`, `mbedtls_rsa_import_raw` and `mbedtls_rsa_complete`. You will need to construct the standard ASN.1 representation and call `psa_import_key()` (see “[Creating keys for asymmetric cryptography](#creating-keys-for-asymmetric-cryptography)”). + +There is no direct equivalent of `mbedtls_rsa_export`, `mbedtls_rsa_export_raw` and `mbedtls_rsa_export_crt` to export some of the numbers in a key. You can export the whole key with `psa_export_key`, or with `psa_export_public_key` to export the public key from a key pair object. See also “[Exporting a public key or a key pair](#exporting-a-public-key-or-a-key-pair)”. + +A PSA key object is immutable, so there is no need for an equivalent of `mbedtls_rsa_copy`. (There is a function `psa_copy_key`, but it is only useful to make a copy of a key with a different policy of ownership; both concepts are out of scope of this document since they have no equivalent in the legacy API.) + +### LMS signatures + +A future version of TF-PSA-Crypto will likely support LMS keys and signatures through the PSA API (`psa_generate_key`, `psa_export_public_key`, `psa_import_key`, `psa_sign_hash`, `psa_verify_hash`, etc.). For the time being, `mbedtls/lms.h` is the only interface to LMS. + +### PK format support interfaces + +The interfaces in `base64.h`, `asn1.h`, `asn1write.h` and `pem.h` are intended to support X.509 and key file formats. Since these APIs are not directly about cryptography, there is no PSA replacement in Mbed TLS 3.6 or in TF-PSA-Crypto 1.0. + +TF-PSA-Crypto 1.0 removes direct access to OID values and functions formerly in `mbedtls/oid.h`. OID lookup is only used internally to parse and write keys and other objects. + +In the ASN.1 modules, the functions `mbedtls_asn1_get_mpi` and `mbedtls_asn1_write_mpi` have been replaced by `mbedtls_asn1_get_integer` and `mbedtls_asn1_write_integer`. See the [TF-PSA-Crypto 1.0 migration guide](1.0-migration-guide.md#changes-to-asn-1-functions) for more information. + +## EC-JPAKE + +The PSA API exposes EC-JPAKE via the algorithm [`PSA_ALG_JPAKE`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/crypto__extra_8h/#c.PSA_ALG_JPAKE) and the PAKE API functions. + +Please note a few differences between the two APIs: the legacy API is geared towards the use of EC-JPAKE in TLS 1.2, whereas the PSA API is protocol-agnostic. + +* The PSA API is finer-grained and offers more flexibility in message ordering. Where the legacy API makes a single function call, the PSA API may require multiple calls. +* The legacy API uses the TLS 1.2 wire format in the input or output format of several functions. In particular, one of the messages embeds the curve identifier in the TLS protocol. The PSA API uses protocol-agnostic formats. +* The legacy API always applies the key derivation specified by TLS 1.2 to the shared secret. With the PSA API, use a key derivation with `PSA_ALG_TLS12_ECJPAKE_TO_PMS` for the same calculation. + +TF-PSA-Crypto implements the official PSA Crypto PAKE API 1.2. Note that Mbed TLS 3.6 implements a beta version of the PAKE API, which is not fully compatible. diff --git a/tf-psa-crypto/doxygen/.gitignore b/tf-psa-crypto/doxygen/.gitignore new file mode 100644 index 0000000000..3d1b31d63d --- /dev/null +++ b/tf-psa-crypto/doxygen/.gitignore @@ -0,0 +1 @@ +tfpsacrypto.doxyfile diff --git a/tf-psa-crypto/doxygen/input/.gitignore b/tf-psa-crypto/doxygen/input/.gitignore new file mode 100644 index 0000000000..b806578c4a --- /dev/null +++ b/tf-psa-crypto/doxygen/input/.gitignore @@ -0,0 +1 @@ +doc_mainpage.h diff --git a/tf-psa-crypto/doxygen/input/doc_mainpage.h.in b/tf-psa-crypto/doxygen/input/doc_mainpage.h.in new file mode 100644 index 0000000000..dc63738bdf --- /dev/null +++ b/tf-psa-crypto/doxygen/input/doc_mainpage.h.in @@ -0,0 +1,51 @@ +/** + * \file doc_mainpage.h + * + * \brief Main page documentation file. + */ +/* + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +/** + * @mainpage v@TF-PSA-Crypto_VERSION@ source code documentation + * + * This documentation describes the application programming interface (API) + * of TF-PSA-Crypto. + * It was automatically generated from specially formatted comment blocks in + * TF-PSA-Crypto's source code using [Doxygen](https://www.doxygen.nl). + * + * ## Main entry points + * + * You can explore the full API from the “Files” or “Files list” section. + * Locate the header file for the module that you are interested in and + * explore its contents. + * + * Some parts of the API are best explored from the “Topics” or + * “Group list” section. + * This is notably the case for the PSA Cryptography API. + * Note that many parts of the API are not classified under a topic and + * can only be seen through the file structure. + * + * For information on configuring the library at compile time, see the + * configuration header file psa/crypto_config.h. + * + * ## Private interfaces + * + * For technical reasons, the rendered documentation includes elements + * that are not considered part of the stable API. Private elements may + * be removed or may have their semantics changed in a future minor release + * without notice. + * + * The following elements are considered private: + * + * - Any header file whose path contains `/private`, and its contents + * (unless re-exported and documented in another non-private header). + * - Any structure or union field whose name starts with `private_`. + * - Any preprocessor macro that is just listed with its automatically + * rendered parameter list, value and location. Macros are part of + * the API only if their documentation has custom text. + * + */ diff --git a/tf-psa-crypto/doxygen/tfpsacrypto.doxyfile.in b/tf-psa-crypto/doxygen/tfpsacrypto.doxyfile.in new file mode 100644 index 0000000000..9bee0d92ba --- /dev/null +++ b/tf-psa-crypto/doxygen/tfpsacrypto.doxyfile.in @@ -0,0 +1,54 @@ +PROJECT_NAME = "TF-PSA-Crypto v@TF-PSA-Crypto_VERSION@" +OUTPUT_DIRECTORY = ../apidoc/ +FULL_PATH_NAMES = NO +OPTIMIZE_OUTPUT_FOR_C = YES +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +CASE_SENSE_NAMES = NO +INPUT = ../include input ../tests/include/alt-dummy +FILE_PATTERNS = *.h +EXCLUDE = ../include/mbedtls/private +RECURSIVE = YES +EXCLUDE_SYMLINKS = YES +SOURCE_BROWSER = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +ALPHABETICAL_INDEX = NO +HTML_OUTPUT = . +HTML_TIMESTAMP = YES +SEARCHENGINE = YES +GENERATE_LATEX = NO +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +INCLUDE_PATH = ../include ../drivers/builtin/include +EXPAND_AS_DEFINED = MBEDTLS_PRIVATE +CLASS_DIAGRAMS = NO +HAVE_DOT = YES +DOT_GRAPH_MAX_NODES = 200 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = YES + +# We mostly use \retval declarations to document which error codes a function +# can return. The reader can follow the hyperlink to the definition of the +# constant to get the generic documentation of that error code. If we don't +# have anything to say about the specific error code for the specific +# function, we can leave the description part of the \retval command blank. +# This is perfectly valid as far as Doxygen is concerned. However, with +# Clang >=15, the -Wdocumentation option emits a warning for empty +# descriptions. +# https://github.com/Mbed-TLS/mbedtls/issues/6960 +# https://github.com/llvm/llvm-project/issues/60315 +# As a workaround, you can write something like +# \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription +# This avoids writing redundant text and keeps Clang happy. +ALIASES += emptydescription="" + +# Define away macros that make parsing definitions difficult. +# MBEDTLS_DEPRECATED is not included in this list as it's important to +# display deprecated status in the documentation. +PREDEFINED = "MBEDTLS_CHECK_RETURN_CRITICAL=" \ + "MBEDTLS_CHECK_RETURN_TYPICAL=" \ + "MBEDTLS_CHECK_RETURN_OPTIONAL=" \ + "MBEDTLS_PRINTF_ATTRIBUTE(a,b)=" \ + "__DOXYGEN__" \ diff --git a/tf-psa-crypto/drivers/CMakeLists.txt b/tf-psa-crypto/drivers/CMakeLists.txt new file mode 100644 index 0000000000..1b571d9e08 --- /dev/null +++ b/tf-psa-crypto/drivers/CMakeLists.txt @@ -0,0 +1,116 @@ +set(drivers + builtin + everest + p256-m + pqcp +) + +# Drivers currently depend on each other through the indirect inclusion of +# `crypto_driver_contexts_*.h` headers, so all driver include paths must be +# visible when building each driver. TF_PSA_CRYPTO_DRIVERS_INCLUDE_DIRS +# provides these include paths. +set(TF_PSA_CRYPTO_DRIVERS_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/builtin/include + ${CMAKE_CURRENT_SOURCE_DIR}/everest/include + ${CMAKE_CURRENT_SOURCE_DIR}/p256-m + ${CMAKE_CURRENT_SOURCE_DIR}/pqcp/include +) + +if(CMAKE_COMPILER_IS_MSVC) + if(MSVC_STATIC_RUNTIME) + foreach(flag_var + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_C_FLAGS_CHECK) + string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") + endforeach(flag_var) + endif() +endif() + +if(TF_PSA_CRYPTO_TEST_DRIVER) + # Use `libtestdriver1` as the driver name to align with the name used so + # far for driver dispatch testing in Mbed TLS. This allows to reuse most + # of the test driver code as it is. + list(APPEND drivers libtestdriver1) + list(APPEND TF_PSA_CRYPTO_DRIVERS_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/libtestdriver1/include) + + # TF_PSA_CRYPTO_TEST_DRIVER_GENERATION_TARGETS: + # The list of targets involved in generating the test drivers. Test code + # includes driver headers, and drivers indirectly include headers from + # other drivers, so driver and test object targets must not start building + # until test driver generation has completed. The variable + # TF_PSA_CRYPTO_TEST_DRIVER_GENERATION_TARGETS provides the list of generation + # targets that driver and test targets should depend on. + set(TF_PSA_CRYPTO_TEST_DRIVER_GENERATION_TARGETS "libtestdriver1_generation") + set(TF_PSA_CRYPTO_TEST_DRIVER_GENERATION_TARGETS + "${TF_PSA_CRYPTO_TEST_DRIVER_GENERATION_TARGETS}" PARENT_SCOPE) + + # In the build tree, create a `drivers/libtestdriver1` directory, copy + # `tests/scripts/libtestdriver1.cmake` to it as `CMakeLists.txt`, and add + # that directory as a subdirectory. This causes the test driver tree + # defined in `libtestdriver1.cmake` to be configured and built as part of + # the main build. The libtestdriver1 code is generated and compiled in the + # build tree, similarly to an in-source-tree build. + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/libtestdriver1) + configure_file( + ${PROJECT_SOURCE_DIR}/tests/scripts/libtestdriver1.cmake + ${CMAKE_CURRENT_BINARY_DIR}/libtestdriver1/CMakeLists.txt + COPYONLY + ) + add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/libtestdriver1 + ${CMAKE_CURRENT_BINARY_DIR}/libtestdriver1) +endif() + +# Lists of driver targets. +# +# TF_PSA_CRYPTO_DRIVER_STATIC_TARGETS: +# The list of driver targets to use when building the static library +# (defined only if USE_STATIC_TF_PSA_CRYPTO_LIBRARY is enabled). +# +# TF_PSA_CRYPTO_DRIVER_TARGETS: +# The list of driver targets to use when building the shared library. +# If shared-library support is disabled, this list is identical to +# TF_PSA_CRYPTO_DRIVER_STATIC_TARGETS. +# +# Notes: +# - TF_PSA_CRYPTO_DRIVER_TARGETS is not limited to shared builds; it may be +# used whenever the static/shared distinction does not matter (e.g. when +# collecting include directories from driver targets). +# +set(driver_targets "") +foreach(driver ${drivers}) + list(APPEND driver_targets "${TF_PSA_CRYPTO_TARGET_PREFIX}${driver}") +endforeach() + +if (USE_STATIC_TF_PSA_CRYPTO_LIBRARY) + if(NOT USE_SHARED_TF_PSA_CRYPTO_LIBRARY) + set(driver_static_targets ${driver_targets}) + else() + set(driver_static_targets "") + foreach(target ${driver_targets}) + list(APPEND driver_static_targets "${target}_static") + endforeach() + endif() +endif() + +set(TF_PSA_CRYPTO_DRIVERS "${drivers}" PARENT_SCOPE) +set(TF_PSA_CRYPTO_DRIVER_STATIC_TARGETS "${driver_static_targets}" PARENT_SCOPE) +set(TF_PSA_CRYPTO_DRIVER_TARGETS "${driver_targets}" PARENT_SCOPE) + +add_subdirectory(everest) +add_subdirectory(p256-m) +add_subdirectory(builtin) +add_subdirectory(pqcp) + +# +# Add to the list of directories with internal headers the driver ones that +# must be visible by core and tests code. +# Done after adding the driver sub-directories as drivers do not need to see +# each other internal headers. +# +list(APPEND TF_PSA_CRYPTO_PRIVATE_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/builtin/src + ${CMAKE_CURRENT_SOURCE_DIR}/pqcp/src +) +set(TF_PSA_CRYPTO_PRIVATE_INCLUDE_DIRS + "${TF_PSA_CRYPTO_PRIVATE_INCLUDE_DIRS}" PARENT_SCOPE) diff --git a/tf-psa-crypto/drivers/builtin/CMakeLists.txt b/tf-psa-crypto/drivers/builtin/CMakeLists.txt new file mode 100644 index 0000000000..c2b93fde43 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/CMakeLists.txt @@ -0,0 +1,3 @@ +file(GLOB builtin_src_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} src/*.c) +set(tf_psa_crypto_driver "builtin") +include(${PROJECT_SOURCE_DIR}/drivers/driver.cmake) diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/aes.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/aes.h new file mode 100644 index 0000000000..d9ea37a2f5 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/aes.h @@ -0,0 +1,607 @@ +/** + * \file aes.h + * + * \brief This file contains AES definitions and functions. + * + * The Advanced Encryption Standard (AES) specifies a FIPS-approved + * cryptographic algorithm that can be used to protect electronic + * data. + * + * The AES algorithm is a symmetric block cipher that can + * encrypt and decrypt information. For more information, see + * FIPS Publication 197: Advanced Encryption Standard and + * ISO/IEC 18033-2:2006: Information technology -- Security + * techniques -- Encryption algorithms -- Part 2: Asymmetric + * ciphers. + * + * The AES-XTS block mode is standardized by NIST SP 800-38E + * + * and described in detail by IEEE P1619 + * . + */ + +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_AES_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_AES_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" +#include "mbedtls/platform_util.h" + +#include +#include + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/* aesni.c relies on these values! */ +#define MBEDTLS_AES_ENCRYPT 1 /**< AES encryption. */ +#define MBEDTLS_AES_DECRYPT 0 /**< AES decryption. */ +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +/* Error codes in range 0x0020-0x0022 */ +/** Invalid key length. */ +#define MBEDTLS_ERR_AES_INVALID_KEY_LENGTH -0x0020 +/** Invalid data input length. */ +#define MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH -0x0022 + +/** Invalid input data. */ +#define MBEDTLS_ERR_AES_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief The AES context-type definition. + */ +typedef struct mbedtls_aes_context { + int MBEDTLS_PRIVATE(nr); /*!< The number of rounds. */ + size_t MBEDTLS_PRIVATE(rk_offset); /*!< The offset in array elements to AES + round keys in the buffer. */ +#if defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + uint32_t MBEDTLS_PRIVATE(buf)[44]; /*!< Aligned data buffer to hold + 10 round keys for 128-bit case. */ +#else + uint32_t MBEDTLS_PRIVATE(buf)[68]; /*!< Unaligned data buffer. This buffer can + hold 32 extra Bytes, which can be used for + simplifying key expansion in the 256-bit + case by generating an extra round key. */ +#endif /* MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH */ +} +mbedtls_aes_context; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/** + * \brief The AES XTS context-type definition. + */ +typedef struct mbedtls_aes_xts_context { + mbedtls_aes_context MBEDTLS_PRIVATE(crypt); /*!< The AES context to use for AES block + encryption or decryption. */ + mbedtls_aes_context MBEDTLS_PRIVATE(tweak); /*!< The AES context used for tweak + computation. */ +} mbedtls_aes_xts_context; +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +typedef enum { + MBEDTLS_AES_IMP_UNKNOWN = -1, + MBEDTLS_AES_IMP_SOFTWARE, + MBEDTLS_AES_IMP_AESCE, + MBEDTLS_AES_IMP_AESNI_ASM, + MBEDTLS_AES_IMP_AESNI_INTRINSICS, +} mbedtls_aes_implementation; + +/** + * \brief This function initializes the specified AES context. + * + * It must be the first API called before using + * the context. + * + * \param ctx The AES context to initialize. This must not be \c NULL. + */ +void mbedtls_aes_init(mbedtls_aes_context *ctx); + +/** + * \brief This function releases and clears the specified AES context. + * + * \param ctx The AES context to clear. + * If this is \c NULL, this function does nothing. + * Otherwise, the context must have been at least initialized. + */ +void mbedtls_aes_free(mbedtls_aes_context *ctx); + +/** + * \brief This function returns the AES implementation. + * + * The options are: unknown, software AES, AESCE, AESNI + * assembly, and AESNI intrinsics. + * + * \return The enum corresponding to the AES implementation. + */ +mbedtls_aes_implementation mbedtls_aes_get_implementation(void); + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/** + * \brief This function initializes the specified AES XTS context. + * + * It must be the first API called before using + * the context. + * + * \param ctx The AES XTS context to initialize. This must not be \c NULL. + */ +void mbedtls_aes_xts_init(mbedtls_aes_xts_context *ctx); + +/** + * \brief This function releases and clears the specified AES XTS context. + * + * \param ctx The AES XTS context to clear. + * If this is \c NULL, this function does nothing. + * Otherwise, the context must have been at least initialized. + */ +void mbedtls_aes_xts_free(mbedtls_aes_xts_context *ctx); +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +/** + * \brief This function sets the encryption key. + * + * \param ctx The AES context to which the key should be bound. + * It must be initialized. + * \param key The encryption key. + * This must be a readable buffer of size \p keybits bits. + * \param keybits The size of data passed in bits. Valid options are: + *
  • 128 bits
  • + *
  • 192 bits
  • + *
  • 256 bits
+ * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. + */ +MBEDTLS_CHECK_RETURN_TYPICAL +int mbedtls_aes_setkey_enc(mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits); + +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +/** + * \brief This function sets the decryption key. + * + * \param ctx The AES context to which the key should be bound. + * It must be initialized. + * \param key The decryption key. + * This must be a readable buffer of size \p keybits bits. + * \param keybits The size of data passed. Valid options are: + *
  • 128 bits
  • + *
  • 192 bits
  • + *
  • 256 bits
+ * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. + */ +MBEDTLS_CHECK_RETURN_TYPICAL +int mbedtls_aes_setkey_dec(mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits); +#endif /* !MBEDTLS_BLOCK_CIPHER_NO_DECRYPT */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/** + * \brief This function prepares an XTS context for encryption and + * sets the encryption key. + * + * \param ctx The AES XTS context to which the key should be bound. + * It must be initialized. + * \param key The encryption key. This is comprised of the XTS key1 + * concatenated with the XTS key2. + * This must be a readable buffer of size \p keybits bits. + * \param keybits The size of \p key passed in bits. Valid options are: + *
  • 256 bits (each of key1 and key2 is a 128-bit key)
  • + *
  • 512 bits (each of key1 and key2 is a 256-bit key)
+ * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. + */ +MBEDTLS_CHECK_RETURN_TYPICAL +int mbedtls_aes_xts_setkey_enc(mbedtls_aes_xts_context *ctx, + const unsigned char *key, + unsigned int keybits); + +/** + * \brief This function prepares an XTS context for decryption and + * sets the decryption key. + * + * \param ctx The AES XTS context to which the key should be bound. + * It must be initialized. + * \param key The decryption key. This is comprised of the XTS key1 + * concatenated with the XTS key2. + * This must be a readable buffer of size \p keybits bits. + * \param keybits The size of \p key passed in bits. Valid options are: + *
  • 256 bits (each of key1 and key2 is a 128-bit key)
  • + *
  • 512 bits (each of key1 and key2 is a 256-bit key)
+ * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. + */ +MBEDTLS_CHECK_RETURN_TYPICAL +int mbedtls_aes_xts_setkey_dec(mbedtls_aes_xts_context *ctx, + const unsigned char *key, + unsigned int keybits); +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +/** + * \brief This function performs an AES single-block encryption or + * decryption operation. + * + * It performs the operation defined in the \p mode parameter + * (encrypt or decrypt), on the input data buffer defined in + * the \p input parameter. + * + * mbedtls_aes_init(), and either mbedtls_aes_setkey_enc() or + * mbedtls_aes_setkey_dec() must be called before the first + * call to this API with the same context. + * + * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. + * \param mode The AES operation: MBEDTLS_AES_ENCRYPT or + * MBEDTLS_AES_DECRYPT. + * \param input The buffer holding the input data. + * It must be readable and at least \c 16 Bytes long. + * \param output The buffer where the output data will be written. + * It must be writeable and at least \c 16 Bytes long. + + * \return \c 0 on success. + */ +MBEDTLS_CHECK_RETURN_TYPICAL +int mbedtls_aes_crypt_ecb(mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16]); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief This function performs an AES-CBC encryption or decryption operation + * on full blocks. + * + * It performs the operation defined in the \p mode + * parameter (encrypt/decrypt), on the input data buffer defined in + * the \p input parameter. + * + * It can be called as many times as needed, until all the input + * data is processed. mbedtls_aes_init(), and either + * mbedtls_aes_setkey_enc() or mbedtls_aes_setkey_dec() must be called + * before the first call to this API with the same context. + * + * \note This function operates on full blocks, that is, the input size + * must be a multiple of the AES block size of \c 16 Bytes. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the same function again on the next + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If you need to retain the contents of the IV, you should + * either save it manually or use the cipher module instead. + * + * + * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. + * \param mode The AES operation: MBEDTLS_AES_ENCRYPT or + * MBEDTLS_AES_DECRYPT. + * \param length The length of the input data in Bytes. This must be a + * multiple of the block size (\c 16 Bytes). + * \param iv Initialization vector (updated after use). + * It must be a readable and writeable buffer of \c 16 Bytes. + * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. + * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH + * on failure. + */ +MBEDTLS_CHECK_RETURN_TYPICAL +int mbedtls_aes_crypt_cbc(mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/** + * \brief This function performs an AES-XTS encryption or decryption + * operation for an entire XTS data unit. + * + * AES-XTS encrypts or decrypts blocks based on their location as + * defined by a data unit number. The data unit number must be + * provided by \p data_unit. + * + * NIST SP 800-38E limits the maximum size of a data unit to 2^20 + * AES blocks. If the data unit is larger than this, this function + * returns #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH. + * + * \param ctx The AES XTS context to use for AES XTS operations. + * It must be initialized and bound to a key. + * \param mode The AES operation: MBEDTLS_AES_ENCRYPT or + * MBEDTLS_AES_DECRYPT. + * \param length The length of a data unit in Bytes. This can be any + * length between 16 bytes and 2^24 bytes inclusive + * (between 1 and 2^20 block cipher blocks). + * \param data_unit The address of the data unit encoded as an array of 16 + * bytes in little-endian format. For disk encryption, this + * is typically the index of the block device sector that + * contains the data. + * \param input The buffer holding the input data (which is an entire + * data unit). This function reads \p length Bytes from \p + * input. + * \param output The buffer holding the output data (which is an entire + * data unit). This function writes \p length Bytes to \p + * output. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH if \p length is + * smaller than an AES block in size (16 Bytes) or if \p + * length is larger than 2^20 blocks (16 MiB). + */ +MBEDTLS_CHECK_RETURN_TYPICAL +int mbedtls_aes_crypt_xts(mbedtls_aes_xts_context *ctx, + int mode, + size_t length, + const unsigned char data_unit[16], + const unsigned char *input, + unsigned char *output); +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief This function performs an AES-CFB128 encryption or decryption + * operation. + * + * It performs the operation defined in the \p mode + * parameter (encrypt or decrypt), on the input data buffer + * defined in the \p input parameter. + * + * For CFB, you must set up the context with mbedtls_aes_setkey_enc(), + * regardless of whether you are performing an encryption or decryption + * operation, that is, regardless of the \p mode parameter. This is + * because CFB mode uses the same key schedule for encryption and + * decryption. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the same function again on the next + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If you need to retain the contents of the + * IV, you must either save it manually or use the cipher + * module instead. + * + * + * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. + * \param mode The AES operation: MBEDTLS_AES_ENCRYPT or + * MBEDTLS_AES_DECRYPT. + * \param length The length of the input data in Bytes. + * \param iv_off The offset in IV (updated after use). + * It must point to a valid \c size_t. + * \param iv The initialization vector (updated after use). + * It must be a readable and writeable buffer of \c 16 Bytes. + * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. + * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. + * + * \return \c 0 on success. + */ +MBEDTLS_CHECK_RETURN_TYPICAL +int mbedtls_aes_crypt_cfb128(mbedtls_aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output); + +/** + * \brief This function performs an AES-CFB8 encryption or decryption + * operation. + * + * It performs the operation defined in the \p mode + * parameter (encrypt/decrypt), on the input data buffer defined + * in the \p input parameter. + * + * Due to the nature of CFB, you must use the same key schedule for + * both encryption and decryption operations. Therefore, you must + * use the context initialized with mbedtls_aes_setkey_enc() for + * both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the same function again on the next + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * + * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. + * \param mode The AES operation: MBEDTLS_AES_ENCRYPT or + * MBEDTLS_AES_DECRYPT + * \param length The length of the input data. + * \param iv The initialization vector (updated after use). + * It must be a readable and writeable buffer of \c 16 Bytes. + * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. + * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. + * + * \return \c 0 on success. + */ +MBEDTLS_CHECK_RETURN_TYPICAL +int mbedtls_aes_crypt_cfb8(mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output); +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) +/** + * \brief This function performs an AES-OFB (Output Feedback Mode) + * encryption or decryption operation. + * + * For OFB, you must set up the context with + * mbedtls_aes_setkey_enc(), regardless of whether you are + * performing an encryption or decryption operation. This is + * because OFB mode uses the same key schedule for encryption and + * decryption. + * + * The OFB operation is identical for encryption or decryption, + * therefore no operation mode needs to be specified. + * + * \note Upon exit, the content of iv, the Initialisation Vector, is + * updated so that you can call the same function again on the next + * block(s) of data and get the same result as if it was encrypted + * in one call. This allows a "streaming" usage, by initialising + * iv_off to 0 before the first call, and preserving its value + * between calls. + * + * For non-streaming use, the iv should be initialised on each call + * to a unique value, and iv_off set to 0 on each call. + * + * If you need to retain the contents of the initialisation vector, + * you must either save it manually or use the cipher module + * instead. + * + * \warning For the OFB mode, the initialisation vector must be unique + * every encryption operation. Reuse of an initialisation vector + * will compromise security. + * + * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. + * \param length The length of the input data. + * \param iv_off The offset in IV (updated after use). + * It must point to a valid \c size_t. + * \param iv The initialization vector (updated after use). + * It must be a readable and writeable buffer of \c 16 Bytes. + * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. + * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. + * + * \return \c 0 on success. + */ +MBEDTLS_CHECK_RETURN_TYPICAL +int mbedtls_aes_crypt_ofb(mbedtls_aes_context *ctx, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output); + +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief This function performs an AES-CTR encryption or decryption + * operation. + * + * Due to the nature of CTR, you must use the same key schedule + * for both encryption and decryption operations. Therefore, you + * must use the context initialized with mbedtls_aes_setkey_enc() + * for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. + * + * \warning You must never reuse a nonce value with the same key. Doing so + * would void the encryption for the two messages encrypted with + * the same nonce and key. + * + * There are two common strategies for managing nonces with CTR: + * + * 1. You can handle everything as a single message processed over + * successive calls to this function. In that case, you want to + * set \p nonce_counter and \p nc_off to 0 for the first call, and + * then preserve the values of \p nonce_counter, \p nc_off and \p + * stream_block across calls to this function as they will be + * updated by this function. + * + * With this strategy, you must not encrypt more than 2**128 + * blocks of data with the same key. + * + * 2. You can encrypt separate messages by dividing the \p + * nonce_counter buffer in two areas: the first one used for a + * per-message nonce, handled by yourself, and the second one + * updated by this function internally. + * + * For example, you might reserve the first 12 bytes for the + * per-message nonce, and the last 4 bytes for internal use. In that + * case, before calling this function on a new message you need to + * set the first 12 bytes of \p nonce_counter to your chosen nonce + * value, the last 4 to 0, and \p nc_off to 0 (which will cause \p + * stream_block to be ignored). That way, you can encrypt at most + * 2**96 messages of up to 2**32 blocks each with the same key. + * + * The per-message nonce (or information sufficient to reconstruct + * it) needs to be communicated with the ciphertext and must be unique. + * The recommended way to ensure uniqueness is to use a message + * counter. An alternative is to generate random nonces, but this + * limits the number of messages that can be securely encrypted: + * for example, with 96-bit random nonces, you should not encrypt + * more than 2**32 messages with the same key. + * + * Note that for both strategies, sizes are measured in blocks and + * that an AES block is 16 bytes. + * + * \warning Upon return, \p stream_block contains sensitive data. Its + * content must not be written to insecure storage and should be + * securely discarded as soon as it's no longer needed. + * + * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. + * \param length The length of the input data. + * \param nc_off The offset in the current \p stream_block, for + * resuming within the current cipher stream. The + * offset pointer should be 0 at the start of a stream. + * It must point to a valid \c size_t. + * \param nonce_counter The 128-bit nonce and counter. + * It must be a readable-writeable buffer of \c 16 Bytes. + * \param stream_block The saved stream block for resuming. This is + * overwritten by the function. + * It must be a readable-writeable buffer of \c 16 Bytes. + * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. + * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. + * + * \return \c 0 on success. + */ +MBEDTLS_CHECK_RETURN_TYPICAL +int mbedtls_aes_crypt_ctr(mbedtls_aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +MBEDTLS_CHECK_RETURN_CRITICAL +int mbedtls_aes_self_test(int verbose); + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_AES_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/aria.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/aria.h new file mode 100644 index 0000000000..44523bcd20 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/aria.h @@ -0,0 +1,342 @@ +/** + * \file aria.h + * + * \brief ARIA block cipher + * + * The ARIA algorithm is a symmetric block cipher that can encrypt and + * decrypt information. It is defined by the Korean Agency for + * Technology and Standards (KATS) in KS X 1213:2004 (in + * Korean, but see http://210.104.33.10/ARIA/index-e.html in English) + * and also described by the IETF in RFC 5794. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ARIA_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ARIA_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +#include +#include + +#include "mbedtls/platform_util.h" + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +#define MBEDTLS_ARIA_ENCRYPT 1 /**< ARIA encryption. */ +#define MBEDTLS_ARIA_DECRYPT 0 /**< ARIA decryption. */ +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#define MBEDTLS_ARIA_BLOCKSIZE 16 /**< ARIA block size in bytes. */ +#define MBEDTLS_ARIA_MAX_ROUNDS 16 /**< Maximum number of rounds in ARIA. */ +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +#define MBEDTLS_ARIA_MAX_KEYSIZE 32 /**< Maximum size of an ARIA key in bytes. */ +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +/** Bad input data. */ +#define MBEDTLS_ERR_ARIA_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT + +/** Invalid data input length. */ +#define MBEDTLS_ERR_ARIA_INVALID_INPUT_LENGTH -0x005E + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief The ARIA context-type definition. + */ +typedef struct mbedtls_aria_context { + unsigned char MBEDTLS_PRIVATE(nr); /*!< The number of rounds (12, 14 or 16) */ + /*! The ARIA round keys. */ + uint32_t MBEDTLS_PRIVATE(rk)[MBEDTLS_ARIA_MAX_ROUNDS + 1][MBEDTLS_ARIA_BLOCKSIZE / 4]; +} +mbedtls_aria_context; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief This function initializes the specified ARIA context. + * + * It must be the first API called before using + * the context. + * + * \param ctx The ARIA context to initialize. This must not be \c NULL. + */ +void mbedtls_aria_init(mbedtls_aria_context *ctx); + +/** + * \brief This function releases and clears the specified ARIA context. + * + * \param ctx The ARIA context to clear. This may be \c NULL, in which + * case this function returns immediately. If it is not \c NULL, + * it must point to an initialized ARIA context. + */ +void mbedtls_aria_free(mbedtls_aria_context *ctx); + +/** + * \brief This function sets the encryption key. + * + * \param ctx The ARIA context to which the key should be bound. + * This must be initialized. + * \param key The encryption key. This must be a readable buffer + * of size \p keybits Bits. + * \param keybits The size of \p key in Bits. Valid options are: + *
  • 128 bits
  • + *
  • 192 bits
  • + *
  • 256 bits
+ * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_setkey_enc(mbedtls_aria_context *ctx, + const unsigned char *key, + unsigned int keybits); + +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +/** + * \brief This function sets the decryption key. + * + * \param ctx The ARIA context to which the key should be bound. + * This must be initialized. + * \param key The decryption key. This must be a readable buffer + * of size \p keybits Bits. + * \param keybits The size of data passed. Valid options are: + *
  • 128 bits
  • + *
  • 192 bits
  • + *
  • 256 bits
+ * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_setkey_dec(mbedtls_aria_context *ctx, + const unsigned char *key, + unsigned int keybits); +#endif /* !MBEDTLS_BLOCK_CIPHER_NO_DECRYPT */ + +/** + * \brief This function performs an ARIA single-block encryption or + * decryption operation. + * + * It performs encryption or decryption (depending on whether + * the key was set for encryption on decryption) on the input + * data buffer defined in the \p input parameter. + * + * mbedtls_aria_init(), and either mbedtls_aria_setkey_enc() or + * mbedtls_aria_setkey_dec() must be called before the first + * call to this API with the same context. + * + * \param ctx The ARIA context to use for encryption or decryption. + * This must be initialized and bound to a key. + * \param input The 16-Byte buffer holding the input data. + * \param output The 16-Byte buffer holding the output data. + + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_crypt_ecb(mbedtls_aria_context *ctx, + const unsigned char input[MBEDTLS_ARIA_BLOCKSIZE], + unsigned char output[MBEDTLS_ARIA_BLOCKSIZE]); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief This function performs an ARIA-CBC encryption or decryption operation + * on full blocks. + * + * It performs the operation defined in the \p mode + * parameter (encrypt/decrypt), on the input data buffer defined in + * the \p input parameter. + * + * It can be called as many times as needed, until all the input + * data is processed. mbedtls_aria_init(), and either + * mbedtls_aria_setkey_enc() or mbedtls_aria_setkey_dec() must be called + * before the first call to this API with the same context. + * + * \note This function operates on aligned blocks, that is, the input size + * must be a multiple of the ARIA block size of 16 Bytes. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the same function again on the next + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If you need to retain the contents of the IV, you should + * either save it manually or use the cipher module instead. + * + * + * \param ctx The ARIA context to use for encryption or decryption. + * This must be initialized and bound to a key. + * \param mode The mode of operation. This must be either + * MBEDTLS_ARIA_ENCRYPT for encryption, or + * MBEDTLS_ARIA_DECRYPT for decryption. + * \param length The length of the input data in Bytes. This must be a + * multiple of the block size (16 Bytes). + * \param iv Initialization vector (updated after use). + * This must be a readable buffer of size 16 Bytes. + * \param input The buffer holding the input data. This must + * be a readable buffer of length \p length Bytes. + * \param output The buffer holding the output data. This must + * be a writable buffer of length \p length Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_crypt_cbc(mbedtls_aria_context *ctx, + int mode, + size_t length, + unsigned char iv[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief This function performs an ARIA-CFB128 encryption or decryption + * operation. + * + * It performs the operation defined in the \p mode + * parameter (encrypt or decrypt), on the input data buffer + * defined in the \p input parameter. + * + * For CFB, you must set up the context with mbedtls_aria_setkey_enc(), + * regardless of whether you are performing an encryption or decryption + * operation, that is, regardless of the \p mode parameter. This is + * because CFB mode uses the same key schedule for encryption and + * decryption. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the same function again on the next + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If you need to retain the contents of the + * IV, you must either save it manually or use the cipher + * module instead. + * + * + * \param ctx The ARIA context to use for encryption or decryption. + * This must be initialized and bound to a key. + * \param mode The mode of operation. This must be either + * MBEDTLS_ARIA_ENCRYPT for encryption, or + * MBEDTLS_ARIA_DECRYPT for decryption. + * \param length The length of the input data \p input in Bytes. + * \param iv_off The offset in IV (updated after use). + * This must not be larger than 15. + * \param iv The initialization vector (updated after use). + * This must be a readable buffer of size 16 Bytes. + * \param input The buffer holding the input data. This must + * be a readable buffer of length \p length Bytes. + * \param output The buffer holding the output data. This must + * be a writable buffer of length \p length Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_crypt_cfb128(mbedtls_aria_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output); +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief This function performs an ARIA-CTR encryption or decryption + * operation. + * + * Due to the nature of CTR, you must use the same key schedule + * for both encryption and decryption operations. Therefore, you + * must use the context initialized with mbedtls_aria_setkey_enc() + * for both MBEDTLS_ARIA_ENCRYPT and MBEDTLS_ARIA_DECRYPT. + * + * \warning You must never reuse a nonce value with the same key. Doing so + * would void the encryption for the two messages encrypted with + * the same nonce and key. + * + * There are two common strategies for managing nonces with CTR: + * + * 1. You can handle everything as a single message processed over + * successive calls to this function. In that case, you want to + * set \p nonce_counter and \p nc_off to 0 for the first call, and + * then preserve the values of \p nonce_counter, \p nc_off and \p + * stream_block across calls to this function as they will be + * updated by this function. + * + * With this strategy, you must not encrypt more than 2**128 + * blocks of data with the same key. + * + * 2. You can encrypt separate messages by dividing the \p + * nonce_counter buffer in two areas: the first one used for a + * per-message nonce, handled by yourself, and the second one + * updated by this function internally. + * + * For example, you might reserve the first 12 bytes for the + * per-message nonce, and the last 4 bytes for internal use. In that + * case, before calling this function on a new message you need to + * set the first 12 bytes of \p nonce_counter to your chosen nonce + * value, the last 4 to 0, and \p nc_off to 0 (which will cause \p + * stream_block to be ignored). That way, you can encrypt at most + * 2**96 messages of up to 2**32 blocks each with the same key. + * + * The per-message nonce (or information sufficient to reconstruct + * it) needs to be communicated with the ciphertext and must be unique. + * The recommended way to ensure uniqueness is to use a message + * counter. An alternative is to generate random nonces, but this + * limits the number of messages that can be securely encrypted: + * for example, with 96-bit random nonces, you should not encrypt + * more than 2**32 messages with the same key. + * + * Note that for both strategies, sizes are measured in blocks and + * that an ARIA block is 16 bytes. + * + * \warning Upon return, \p stream_block contains sensitive data. Its + * content must not be written to insecure storage and should be + * securely discarded as soon as it's no longer needed. + * + * \param ctx The ARIA context to use for encryption or decryption. + * This must be initialized and bound to a key. + * \param length The length of the input data \p input in Bytes. + * \param nc_off The offset in Bytes in the current \p stream_block, + * for resuming within the current cipher stream. The + * offset pointer should be \c 0 at the start of a + * stream. This must not be larger than \c 15 Bytes. + * \param nonce_counter The 128-bit nonce and counter. This must point to + * a read/write buffer of length \c 16 bytes. + * \param stream_block The saved stream block for resuming. This must + * point to a read/write buffer of length \c 16 bytes. + * This is overwritten by the function. + * \param input The buffer holding the input data. This must + * be a readable buffer of length \p length Bytes. + * \param output The buffer holding the output data. This must + * be a writable buffer of length \p length Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_crypt_ctr(mbedtls_aria_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[MBEDTLS_ARIA_BLOCKSIZE], + unsigned char stream_block[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine. + * + * \return \c 0 on success, or \c 1 on failure. + */ +int mbedtls_aria_self_test(int verbose); +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ARIA_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/bignum.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/bignum.h new file mode 100644 index 0000000000..7d5bb06554 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/bignum.h @@ -0,0 +1,1135 @@ +/** + * \file bignum.h + * + * \brief Multi-precision integer library + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_BIGNUM_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_BIGNUM_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" +#include "psa/crypto_values.h" + +#include +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +/** An error occurred while reading from or writing to a file. */ +#define MBEDTLS_ERR_MPI_FILE_IO_ERROR -0x0002 +/** Bad input parameters to function. */ +#define MBEDTLS_ERR_MPI_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT +/** There is an invalid character in the digit string. */ +#define MBEDTLS_ERR_MPI_INVALID_CHARACTER -0x0006 +/** The buffer is too small to write to. */ +#define MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL PSA_ERROR_BUFFER_TOO_SMALL +/** The input arguments are negative or result in illegal output. */ +#define MBEDTLS_ERR_MPI_NEGATIVE_VALUE -0x000A +/** The input argument for division is zero, which is not allowed. */ +#define MBEDTLS_ERR_MPI_DIVISION_BY_ZERO -0x000C +/** The input arguments are not acceptable. */ +#define MBEDTLS_ERR_MPI_NOT_ACCEPTABLE -0x000E +/** Memory allocation failed. */ +#define MBEDTLS_ERR_MPI_ALLOC_FAILED PSA_ERROR_INSUFFICIENT_MEMORY + +#define MBEDTLS_MPI_CHK(f) \ + do \ + { \ + if ((ret = (f)) != 0) \ + goto cleanup; \ + } while (0) + +/* + * Maximum size MPIs are allowed to grow to in number of limbs. + */ +#define MBEDTLS_MPI_MAX_LIMBS 10000 + +#if !defined(MBEDTLS_MPI_WINDOW_SIZE) +/* + * Maximum window size used for modular exponentiation. Default: 3 + * Minimum value: 1. Maximum value: 6. + * + * Result is an array of ( 2 ** MBEDTLS_MPI_WINDOW_SIZE ) MPIs used + * for the sliding window calculation. (So 8 by default) + * + * Reduction in size, reduces speed. + */ +#define MBEDTLS_MPI_WINDOW_SIZE 3 /**< Maximum window size used. */ +#endif /* !MBEDTLS_MPI_WINDOW_SIZE */ + +#if !defined(MBEDTLS_MPI_MAX_SIZE) +/* + * Maximum size of MPIs allowed in bits and bytes for user-MPIs. + * ( Default: 512 bytes => 4096 bits, Maximum tested: 2048 bytes => 16384 bits ) + * + * Note: Calculations can temporarily result in larger MPIs. So the number + * of limbs required (MBEDTLS_MPI_MAX_LIMBS) is higher. + */ +#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ +#endif /* !MBEDTLS_MPI_MAX_SIZE */ + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +#define MBEDTLS_MPI_MAX_BITS (8 * MBEDTLS_MPI_MAX_SIZE) /**< Maximum number of bits for usable MPIs. */ + +/* + * When reading from files with mbedtls_mpi_read_file() and writing to files with + * mbedtls_mpi_write_file() the buffer should have space + * for a (short) label, the MPI (in the provided radix), the newline + * characters and the '\0'. + * + * By default we assume at least a 10 char label, a minimum radix of 10 + * (decimal) and a maximum of 4096 bit numbers (1234 decimal chars). + * Autosized at compile time for at least a 10 char label, a minimum radix + * of 10 (decimal) for a number of MBEDTLS_MPI_MAX_BITS size. + * + * This used to be statically sized to 1250 for a maximum of 4096 bit + * numbers (1234 decimal chars). + * + * Calculate using the formula: + * MBEDTLS_MPI_RW_BUFFER_SIZE = ceil(MBEDTLS_MPI_MAX_BITS / ln(10) * ln(2)) + + * LabelSize + 6 + */ +#define MBEDTLS_MPI_MAX_BITS_SCALE100 (100 * MBEDTLS_MPI_MAX_BITS) +#define MBEDTLS_LN_2_DIV_LN_10_SCALE100 332 +#define MBEDTLS_MPI_RW_BUFFER_SIZE (((MBEDTLS_MPI_MAX_BITS_SCALE100 + \ + MBEDTLS_LN_2_DIV_LN_10_SCALE100 - 1) / \ + MBEDTLS_LN_2_DIV_LN_10_SCALE100) + 10 + 6) +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +/* + * Define the base integer type, architecture-wise. + * + * 32 or 64-bit integer types can be forced regardless of the underlying + * architecture by defining MBEDTLS_HAVE_INT32 or MBEDTLS_HAVE_INT64 + * respectively and undefining MBEDTLS_HAVE_ASM. + * + * Double-width integers (e.g. 128-bit in 64-bit architectures) can be + * disabled by defining MBEDTLS_NO_UDBL_DIVISION. + */ +#if !defined(MBEDTLS_HAVE_INT32) + #if defined(_MSC_VER) && defined(_M_AMD64) +/* Always choose 64-bit when using MSC */ + #if !defined(MBEDTLS_HAVE_INT64) + #define MBEDTLS_HAVE_INT64 + #endif /* !MBEDTLS_HAVE_INT64 */ +typedef int64_t mbedtls_mpi_sint; +typedef uint64_t mbedtls_mpi_uint; +#define MBEDTLS_MPI_UINT_MAX UINT64_MAX + #elif defined(__GNUC__) && ( \ + defined(__amd64__) || defined(__x86_64__) || \ + defined(__ppc64__) || defined(__powerpc64__) || \ + defined(__ia64__) || defined(__alpha__) || \ + (defined(__sparc__) && defined(__arch64__)) || \ + defined(__s390x__) || defined(__mips64) || \ + defined(__aarch64__)) + #if !defined(MBEDTLS_HAVE_INT64) + #define MBEDTLS_HAVE_INT64 + #endif /* MBEDTLS_HAVE_INT64 */ +typedef int64_t mbedtls_mpi_sint; +typedef uint64_t mbedtls_mpi_uint; +#define MBEDTLS_MPI_UINT_MAX UINT64_MAX + #if !defined(MBEDTLS_NO_UDBL_DIVISION) +/* mbedtls_t_udbl defined as 128-bit unsigned int */ +typedef unsigned int mbedtls_t_udbl __attribute__((mode(TI))); + #define MBEDTLS_HAVE_UDBL + #endif /* !MBEDTLS_NO_UDBL_DIVISION */ + #elif defined(__ARMCC_VERSION) && defined(__aarch64__) +/* + * __ARMCC_VERSION is defined for both armcc and armclang and + * __aarch64__ is only defined by armclang when compiling 64-bit code + */ + #if !defined(MBEDTLS_HAVE_INT64) + #define MBEDTLS_HAVE_INT64 + #endif /* !MBEDTLS_HAVE_INT64 */ +typedef int64_t mbedtls_mpi_sint; +typedef uint64_t mbedtls_mpi_uint; +#define MBEDTLS_MPI_UINT_MAX UINT64_MAX + #if !defined(MBEDTLS_NO_UDBL_DIVISION) +/* mbedtls_t_udbl defined as 128-bit unsigned int */ +typedef __uint128_t mbedtls_t_udbl; + #define MBEDTLS_HAVE_UDBL + #endif /* !MBEDTLS_NO_UDBL_DIVISION */ + #elif defined(MBEDTLS_HAVE_INT64) +/* Force 64-bit integers with unknown compiler */ +typedef int64_t mbedtls_mpi_sint; +typedef uint64_t mbedtls_mpi_uint; +#define MBEDTLS_MPI_UINT_MAX UINT64_MAX + #endif +#endif /* !MBEDTLS_HAVE_INT32 */ + +#if !defined(MBEDTLS_HAVE_INT64) +/* Default to 32-bit compilation */ + #if !defined(MBEDTLS_HAVE_INT32) + #define MBEDTLS_HAVE_INT32 + #endif /* !MBEDTLS_HAVE_INT32 */ +typedef int32_t mbedtls_mpi_sint; +typedef uint32_t mbedtls_mpi_uint; +#define MBEDTLS_MPI_UINT_MAX UINT32_MAX + #if !defined(MBEDTLS_NO_UDBL_DIVISION) +typedef uint64_t mbedtls_t_udbl; + #define MBEDTLS_HAVE_UDBL + #endif /* !MBEDTLS_NO_UDBL_DIVISION */ +#endif /* !MBEDTLS_HAVE_INT64 */ + +/* + * Sanity check that exactly one of MBEDTLS_HAVE_INT32 or MBEDTLS_HAVE_INT64 is defined, + * so that code elsewhere doesn't have to check. + */ +#if (!(defined(MBEDTLS_HAVE_INT32) || defined(MBEDTLS_HAVE_INT64))) || \ + (defined(MBEDTLS_HAVE_INT32) && defined(MBEDTLS_HAVE_INT64)) +#error "Only 32-bit or 64-bit limbs are supported in bignum" +#endif + +/** \typedef mbedtls_mpi_uint + * \brief The type of machine digits in a bignum, called _limbs_. + * + * This is always an unsigned integer type with no padding bits. The size + * is platform-dependent. + */ + +/** \typedef mbedtls_mpi_sint + * \brief The signed type corresponding to #mbedtls_mpi_uint. + * + * This is always an signed integer type with no padding bits. The size + * is platform-dependent. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MPI structure + */ +typedef struct mbedtls_mpi { + /** Pointer to limbs. + * + * This may be \c NULL if \c n is 0. + */ + mbedtls_mpi_uint *MBEDTLS_PRIVATE(p); + + /** Sign: -1 if the mpi is negative, 1 otherwise. + * + * The number 0 must be represented with `s = +1`. Although many library + * functions treat all-limbs-zero as equivalent to a valid representation + * of 0 regardless of the sign bit, there are exceptions, so bignum + * functions and external callers must always set \c s to +1 for the + * number zero. + * + * Note that this implies that calloc() or `... = {0}` does not create + * a valid MPI representation. You must call mbedtls_mpi_init(). + */ + signed short MBEDTLS_PRIVATE(s); + + /** Total number of limbs in \c p. */ + unsigned short MBEDTLS_PRIVATE(n); + /* Make sure that MBEDTLS_MPI_MAX_LIMBS fits in n. + * Use the same limit value on all platforms so that we don't have to + * think about different behavior on the rare platforms where + * unsigned short can store values larger than the minimum required by + * the C language, which is 65535. + */ +#if MBEDTLS_MPI_MAX_LIMBS > 65535 +#error "MBEDTLS_MPI_MAX_LIMBS > 65535 is not supported" +#endif +} +mbedtls_mpi; + +#define MBEDTLS_MPI_INIT { 0, 1, 0 } + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief Initialize an MPI context. + * + * This makes the MPI ready to be set or freed, + * but does not define a value for the MPI. + * + * \param X The MPI context to initialize. This must not be \c NULL. + */ +void mbedtls_mpi_init(mbedtls_mpi *X); + +/** + * \brief This function frees the components of an MPI context. + * + * \param X The MPI context to be cleared. This may be \c NULL, + * in which case this function is a no-op. If it is + * not \c NULL, it must point to an initialized MPI. + */ +void mbedtls_mpi_free(mbedtls_mpi *X); + +/** + * \brief Enlarge an MPI to the specified number of limbs. + * + * \note This function does nothing if the MPI is + * already large enough. + * + * \param X The MPI to grow. It must be initialized. + * \param nblimbs The target number of limbs. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_mpi_grow(mbedtls_mpi *X, size_t nblimbs); + +/** + * \brief This function resizes an MPI downwards, keeping at least the + * specified number of limbs. + * + * If \c X is smaller than \c nblimbs, it is resized up + * instead. + * + * \param X The MPI to shrink. This must point to an initialized MPI. + * \param nblimbs The minimum number of limbs to keep. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * (this can only happen when resizing up). + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_mpi_shrink(mbedtls_mpi *X, size_t nblimbs); + +/** + * \brief Make a copy of an MPI. + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param Y The source MPI. This must point to an initialized MPI. + * + * \note The limb-buffer in the destination MPI is enlarged + * if necessary to hold the value in the source MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_mpi_copy(mbedtls_mpi *X, const mbedtls_mpi *Y); + +/** + * \brief Swap the contents of two MPIs. + * + * \param X The first MPI. It must be initialized. + * \param Y The second MPI. It must be initialized. + */ +void mbedtls_mpi_swap(mbedtls_mpi *X, mbedtls_mpi *Y); + +/** + * \brief Perform a safe conditional copy of MPI which doesn't + * reveal whether the condition was true or not. + * + * \param X The MPI to conditionally assign to. This must point + * to an initialized MPI. + * \param Y The MPI to be assigned from. This must point to an + * initialized MPI. + * \param assign The condition deciding whether to perform the + * assignment or not. Must be either 0 or 1: + * * \c 1: Perform the assignment `X = Y`. + * * \c 0: Keep the original value of \p X. + * + * \note This function is equivalent to + * `if( assign ) mbedtls_mpi_copy( X, Y );` + * except that it avoids leaking any information about whether + * the assignment was done or not (the above code may leak + * information through branch prediction and/or memory access + * patterns analysis). + * + * \warning If \p assign is neither 0 nor 1, the result of this function + * is indeterminate, and the resulting value in \p X might be + * neither its original value nor the value in \p Y. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign); + +/** + * \brief Perform a safe conditional swap which doesn't + * reveal whether the condition was true or not. + * + * \param X The first MPI. This must be initialized. + * \param Y The second MPI. This must be initialized. + * \param swap The condition deciding whether to perform + * the swap or not. Must be either 0 or 1: + * * \c 1: Swap the values of \p X and \p Y. + * * \c 0: Keep the original values of \p X and \p Y. + * + * \note This function is equivalent to + * if( swap ) mbedtls_mpi_swap( X, Y ); + * except that it avoids leaking any information about whether + * the swap was done or not (the above code may leak + * information through branch prediction and/or memory access + * patterns analysis). + * + * \warning If \p swap is neither 0 nor 1, the result of this function + * is indeterminate, and both \p X and \p Y might end up with + * values different to either of the original ones. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. + * + */ +int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap); + +/** + * \brief Store integer value in MPI. + * + * \param X The MPI to set. This must be initialized. + * \param z The value to use. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_mpi_lset(mbedtls_mpi *X, mbedtls_mpi_sint z); + +/** + * \brief Get a specific bit from an MPI. + * + * \param X The MPI to query. This must be initialized. + * \param pos Zero-based index of the bit to query. + * + * \return \c 0 or \c 1 on success, depending on whether bit \c pos + * of \c X is unset or set. + * \return A negative error code on failure. + */ +int mbedtls_mpi_get_bit(const mbedtls_mpi *X, size_t pos); + +/** + * \brief Modify a specific bit in an MPI. + * + * \note This function will grow the target MPI if necessary to set a + * bit to \c 1 in a not yet existing limb. It will not grow if + * the bit should be set to \c 0. + * + * \param X The MPI to modify. This must be initialized. + * \param pos Zero-based index of the bit to modify. + * \param val The desired value of bit \c pos: \c 0 or \c 1. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_mpi_set_bit(mbedtls_mpi *X, size_t pos, unsigned char val); + +/** + * \brief Return the number of bits of value \c 0 before the + * least significant bit of value \c 1. + * + * \note This is the same as the zero-based index of + * the least significant bit of value \c 1. + * + * \param X The MPI to query. + * + * \return The number of bits of value \c 0 before the least significant + * bit of value \c 1 in \p X. + */ +size_t mbedtls_mpi_lsb(const mbedtls_mpi *X); + +/** + * \brief Return the number of bits up to and including the most + * significant bit of value \c 1. + * + * * \note This is same as the one-based index of the most + * significant bit of value \c 1. + * + * \param X The MPI to query. This must point to an initialized MPI. + * + * \return The number of bits up to and including the most + * significant bit of value \c 1. + */ +size_t mbedtls_mpi_bitlen(const mbedtls_mpi *X); + +/** + * \brief Return the total size of an MPI value in bytes. + * + * \param X The MPI to use. This must point to an initialized MPI. + * + * \note The value returned by this function may be less than + * the number of bytes used to store \p X internally. + * This happens if and only if there are trailing bytes + * of value zero. + * + * \return The least number of bytes capable of storing + * the absolute value of \p X. + */ +size_t mbedtls_mpi_size(const mbedtls_mpi *X); + +/** + * \brief Import an MPI from an ASCII string. + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param radix The numeric base of the input string. + * \param s Null-terminated string buffer. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_mpi_read_string(mbedtls_mpi *X, int radix, const char *s); + +/** + * \brief Export an MPI to an ASCII string. + * + * \param X The source MPI. This must point to an initialized MPI. + * \param radix The numeric base of the output string. + * \param buf The buffer to write the string to. This must be writable + * buffer of length \p buflen Bytes. + * \param buflen The available size in Bytes of \p buf. + * \param olen The address at which to store the length of the string + * written, including the final \c NULL byte. This must + * not be \c NULL. + * + * \note You can call this function with `buflen == 0` to obtain the + * minimum required buffer size in `*olen`. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if the target buffer \p buf + * is too small to hold the value of \p X in the desired base. + * In this case, `*olen` is nonetheless updated to contain the + * size of \p buf required for a successful call. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_write_string(const mbedtls_mpi *X, int radix, + char *buf, size_t buflen, size_t *olen); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Read an MPI from a line in an opened file. + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param radix The numeric base of the string representation used + * in the source line. + * \param fin The input file handle to use. This must not be \c NULL. + * + * \note On success, this function advances the file stream + * to the end of the current line or to EOF. + * + * The function returns \c 0 on an empty line. + * + * Leading whitespaces are ignored, as is a + * '0x' prefix for radix \c 16. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if the file read buffer + * is too small. + * \return Another negative error code on failure. + */ +int mbedtls_mpi_read_file(mbedtls_mpi *X, int radix, FILE *fin); + +/** + * \brief Export an MPI into an opened file. + * + * \param p A string prefix to emit prior to the MPI data. + * For example, this might be a label, or "0x" when + * printing in base \c 16. This may be \c NULL if no prefix + * is needed. + * \param X The source MPI. This must point to an initialized MPI. + * \param radix The numeric base to be used in the emitted string. + * \param fout The output file handle. This may be \c NULL, in which case + * the output is written to \c stdout. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_mpi_write_file(const char *p, const mbedtls_mpi *X, + int radix, FILE *fout); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Import an MPI from unsigned big endian binary data. + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param buf The input buffer. This must be a readable buffer of length + * \p buflen Bytes. + * \param buflen The length of the input buffer \p buf in Bytes. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_read_binary(mbedtls_mpi *X, const unsigned char *buf, + size_t buflen); + +/** + * \brief Import X from unsigned binary data, little endian + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param buf The input buffer. This must be a readable buffer of length + * \p buflen Bytes. + * \param buflen The length of the input buffer \p buf in Bytes. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_read_binary_le(mbedtls_mpi *X, + const unsigned char *buf, size_t buflen); + +/** + * \brief Export X into unsigned binary data, big endian. + * Always fills the whole buffer, which will start with zeros + * if the number is smaller. + * + * \param X The source MPI. This must point to an initialized MPI. + * \param buf The output buffer. This must be a writable buffer of length + * \p buflen Bytes. + * \param buflen The size of the output buffer \p buf in Bytes. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p buf isn't + * large enough to hold the value of \p X. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_write_binary(const mbedtls_mpi *X, unsigned char *buf, + size_t buflen); + +/** + * \brief Export X into unsigned binary data, little endian. + * Always fills the whole buffer, which will end with zeros + * if the number is smaller. + * + * \param X The source MPI. This must point to an initialized MPI. + * \param buf The output buffer. This must be a writable buffer of length + * \p buflen Bytes. + * \param buflen The size of the output buffer \p buf in Bytes. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p buf isn't + * large enough to hold the value of \p X. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_write_binary_le(const mbedtls_mpi *X, + unsigned char *buf, size_t buflen); + +/** + * \brief Perform a left-shift on an MPI: X <<= count + * + * \param X The MPI to shift. This must point to an initialized MPI. + * The MPI pointed by \p X may be resized to fit + * the resulting number. + * \param count The number of bits to shift by. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_shift_l(mbedtls_mpi *X, size_t count); + +/** + * \brief Perform a right-shift on an MPI: X >>= count + * + * \param X The MPI to shift. This must point to an initialized MPI. + * \param count The number of bits to shift by. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_shift_r(mbedtls_mpi *X, size_t count); + +/** + * \brief Compare the absolute values of two MPIs. + * + * \param X The left-hand MPI. This must point to an initialized MPI. + * \param Y The right-hand MPI. This must point to an initialized MPI. + * + * \return \c 1 if `|X|` is greater than `|Y|`. + * \return \c -1 if `|X|` is lesser than `|Y|`. + * \return \c 0 if `|X|` is equal to `|Y|`. + */ +int mbedtls_mpi_cmp_abs(const mbedtls_mpi *X, const mbedtls_mpi *Y); + +/** + * \brief Compare two MPIs. + * + * \param X The left-hand MPI. This must point to an initialized MPI. + * \param Y The right-hand MPI. This must point to an initialized MPI. + * + * \return \c 1 if \p X is greater than \p Y. + * \return \c -1 if \p X is lesser than \p Y. + * \return \c 0 if \p X is equal to \p Y. + */ +int mbedtls_mpi_cmp_mpi(const mbedtls_mpi *X, const mbedtls_mpi *Y); + +/** + * \brief Check if an MPI is less than the other in constant time. + * + * \param X The left-hand MPI. This must point to an initialized MPI + * with the same allocated length as Y. + * \param Y The right-hand MPI. This must point to an initialized MPI + * with the same allocated length as X. + * \param ret The result of the comparison: + * \c 1 if \p X is less than \p Y. + * \c 0 if \p X is greater than or equal to \p Y. + * + * \return 0 on success. + * \return MBEDTLS_ERR_MPI_BAD_INPUT_DATA if the allocated length of + * the two input MPIs is not the same. + */ +int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X, const mbedtls_mpi *Y, + unsigned *ret); + +/** + * \brief Compare an MPI with an integer. + * + * \param X The left-hand MPI. This must point to an initialized MPI. + * \param z The integer value to compare \p X to. + * + * \return \c 1 if \p X is greater than \p z. + * \return \c -1 if \p X is lesser than \p z. + * \return \c 0 if \p X is equal to \p z. + */ +int mbedtls_mpi_cmp_int(const mbedtls_mpi *X, mbedtls_mpi_sint z); + +/** + * \brief Perform an unsigned addition of MPIs: X = |A| + |B| + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The first summand. This must point to an initialized MPI. + * \param B The second summand. This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_add_abs(mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *B); + +/** + * \brief Perform an unsigned subtraction of MPIs: X = |A| - |B| + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The minuend. This must point to an initialized MPI. + * \param B The subtrahend. This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_NEGATIVE_VALUE if \p B is greater than \p A. + * \return Another negative error code on different kinds of failure. + * + */ +int mbedtls_mpi_sub_abs(mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *B); + +/** + * \brief Perform a signed addition of MPIs: X = A + B + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The first summand. This must point to an initialized MPI. + * \param B The second summand. This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_add_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *B); + +/** + * \brief Perform a signed subtraction of MPIs: X = A - B + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The minuend. This must point to an initialized MPI. + * \param B The subtrahend. This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_sub_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *B); + +/** + * \brief Perform a signed addition of an MPI and an integer: X = A + b + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The first summand. This must point to an initialized MPI. + * \param b The second summand. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_add_int(mbedtls_mpi *X, const mbedtls_mpi *A, + mbedtls_mpi_sint b); + +/** + * \brief Perform a signed subtraction of an MPI and an integer: + * X = A - b + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The minuend. This must point to an initialized MPI. + * \param b The subtrahend. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_sub_int(mbedtls_mpi *X, const mbedtls_mpi *A, + mbedtls_mpi_sint b); + +/** + * \brief Perform a multiplication of two MPIs: X = A * B + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The first factor. This must point to an initialized MPI. + * \param B The second factor. This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + * + */ +int mbedtls_mpi_mul_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *B); + +/** + * \brief Perform a multiplication of an MPI with an unsigned integer: + * X = A * b + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The first factor. This must point to an initialized MPI. + * \param b The second factor. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + * + */ +int mbedtls_mpi_mul_int(mbedtls_mpi *X, const mbedtls_mpi *A, + mbedtls_mpi_uint b); + +/** + * \brief Perform a division with remainder of two MPIs: + * A = Q * B + R + * + * \param Q The destination MPI for the quotient. + * This may be \c NULL if the value of the + * quotient is not needed. This must not alias A or B. + * \param R The destination MPI for the remainder value. + * This may be \c NULL if the value of the + * remainder is not needed. This must not alias A or B. + * \param A The dividend. This must point to an initialized MPI. + * \param B The divisor. This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return #MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if \p B equals zero. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_div_mpi(mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, + const mbedtls_mpi *B); + +/** + * \brief Perform a division with remainder of an MPI by an integer: + * A = Q * b + R + * + * \param Q The destination MPI for the quotient. + * This may be \c NULL if the value of the + * quotient is not needed. This must not alias A. + * \param R The destination MPI for the remainder value. + * This may be \c NULL if the value of the + * remainder is not needed. This must not alias A. + * \param A The dividend. This must point to an initialized MPi. + * \param b The divisor. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return #MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if \p b equals zero. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_div_int(mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, + mbedtls_mpi_sint b); + +/** + * \brief Perform a modular reduction. R = A mod B + * + * \param R The destination MPI for the residue value. + * This must point to an initialized MPI. + * \param A The MPI to compute the residue of. + * This must point to an initialized MPI. + * \param B The base of the modular reduction. + * This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if \p B equals zero. + * \return #MBEDTLS_ERR_MPI_NEGATIVE_VALUE if \p B is negative. + * \return Another negative error code on different kinds of failure. + * + */ +int mbedtls_mpi_mod_mpi(mbedtls_mpi *R, const mbedtls_mpi *A, + const mbedtls_mpi *B); + +/** + * \brief Perform a modular reduction with respect to an integer. + * r = A mod b + * + * \param r The address at which to store the residue. + * This must not be \c NULL. + * \param A The MPI to compute the residue of. + * This must point to an initialized MPi. + * \param b The integer base of the modular reduction. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if \p b equals zero. + * \return #MBEDTLS_ERR_MPI_NEGATIVE_VALUE if \p b is negative. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_mod_int(mbedtls_mpi_uint *r, const mbedtls_mpi *A, + mbedtls_mpi_sint b); + +/** + * \brief Perform a modular exponentiation: X = A^E mod N + * + * \param X The destination MPI. This must point to an initialized MPI. + * This must not alias E or N. + * \param A The base of the exponentiation. + * This must point to an initialized MPI. + * \param E The exponent MPI. This must point to an initialized MPI. + * \param N The base for the modular reduction. This must point to an + * initialized MPI. + * \param prec_RR A helper MPI depending solely on \p N which can be used to + * speed-up multiple modular exponentiations for the same value + * of \p N. This may be \c NULL. If it is not \c NULL, it must + * point to an initialized MPI. If it hasn't been used after + * the call to mbedtls_mpi_init(), this function will compute + * the helper value and store it in \p prec_RR for reuse on + * subsequent calls to this function. Otherwise, the function + * will assume that \p prec_RR holds the helper value set by a + * previous call to mbedtls_mpi_exp_mod(), and reuse it. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \c N is negative or + * even, or if \c E is negative. + * \return Another negative error code on different kinds of failures. + * + */ +int mbedtls_mpi_exp_mod(mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *E, const mbedtls_mpi *N, + mbedtls_mpi *prec_RR); + +/** + * \brief Fill an MPI with a number of random bytes. + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param size The number of random bytes to generate. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context argument. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on failure. + * + * \note The bytes obtained from the RNG are interpreted + * as a big-endian representation of an MPI; this can + * be relevant in applications like deterministic ECDSA. + */ +int mbedtls_mpi_fill_random(mbedtls_mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +/** Generate a random number uniformly in a range. + * + * This function generates a random number between \p min inclusive and + * \p N exclusive. + * + * The procedure complies with RFC 6979 §3.3 (deterministic ECDSA) + * when the RNG is a suitably parametrized instance of HMAC_DRBG + * and \p min is \c 1. + * + * \note There are `N - min` possible outputs. The lower bound + * \p min can be reached, but the upper bound \p N cannot. + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param min The minimum value to return. + * It must be nonnegative. + * \param N The upper bound of the range, exclusive. + * In other words, this is one plus the maximum value to return. + * \p N must be strictly larger than \p min. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p min or \p N is invalid + * or if they are incompatible. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if the implementation was + * unable to find a suitable value within a limited number + * of attempts. This has a negligible probability if \p N + * is significantly larger than \p min, which is the case + * for all usual cryptographic applications. + * \return Another negative error code on failure. + */ +int mbedtls_mpi_random(mbedtls_mpi *X, + mbedtls_mpi_sint min, + const mbedtls_mpi *N, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +/** + * \brief Compute the greatest common divisor: G = gcd(A, B) + * + * \param G The destination MPI. This must point to an initialized MPI. + * This will always be positive or 0. + * \param A The first operand. This must point to an initialized MPI. + * \param B The second operand. This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_gcd(mbedtls_mpi *G, const mbedtls_mpi *A, + const mbedtls_mpi *B); + +/** + * \brief Compute the modular inverse: X = A^-1 mod N + * + * \param X The destination MPI. This must point to an initialized MPI. + * The value returned on success will be between [1, N-1]. + * \param A The MPI to calculate the modular inverse of. This must point + * to an initialized MPI. This value can be negative, in which + * case a positive answer will still be returned in \p X. + * \param N The base of the modular inversion. This must point to an + * initialized MPI and be greater than one. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p N is less than + * or equal to one. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if \p A has no modular + * inverse with respect to \p N. + */ +int mbedtls_mpi_inv_mod(mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *N); + +/** + * \brief Miller-Rabin primality test. + * + * \warning If \p X is potentially generated by an adversary, for example + * when validating cryptographic parameters that you didn't + * generate yourself and that are supposed to be prime, then + * \p rounds should be at least the half of the security + * strength of the cryptographic algorithm. On the other hand, + * if \p X is chosen uniformly or non-adversarially (as is the + * case when mbedtls_mpi_gen_prime calls this function), then + * \p rounds can be much lower. + * + * \param X The MPI to check for primality. + * This must point to an initialized MPI. + * \param rounds The number of bases to perform the Miller-Rabin primality + * test for. The probability of returning 0 on a composite is + * at most 2-2*\p rounds . + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. + * This may be \c NULL if \p f_rng doesn't use + * a context parameter. + * + * \return \c 0 if successful, i.e. \p X is probably prime. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if \p X is not prime. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_mpi_is_prime_ext(const mbedtls_mpi *X, int rounds, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); +/** + * \brief Flags for mbedtls_mpi_gen_prime() + * + * Each of these flags is a constraint on the result X returned by + * mbedtls_mpi_gen_prime(). + */ +typedef enum { + MBEDTLS_MPI_GEN_PRIME_FLAG_DH = 0x0001, /**< (X-1)/2 is prime too */ + MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR = 0x0002, /**< lower error rate from 2-80 to 2-128 */ +} mbedtls_mpi_gen_prime_flag_t; + +/** + * \brief Generate a prime number. + * + * \param X The destination MPI to store the generated prime in. + * This must point to an initialized MPi. + * \param nbits The required size of the destination MPI in bits. + * This must be between \c 3 and #MBEDTLS_MPI_MAX_BITS. + * \param flags A mask of flags of type #mbedtls_mpi_gen_prime_flag_t. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. + * This may be \c NULL if \p f_rng doesn't use + * a context parameter. + * + * \return \c 0 if successful, in which case \p X holds a + * probably prime number. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if `nbits` is not between + * \c 3 and #MBEDTLS_MPI_MAX_BITS. + */ +int mbedtls_mpi_gen_prime(mbedtls_mpi *X, size_t nbits, int flags, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +/** + * \brief Retrieve an integer ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * Legacy function, which is now for internal use only. + * Please use mbedtls_asn1_get_integer() instead. + * + * \param p On entry, \c *p points to the start of the ASN.1 element. + * On successful completion, \c *p points to the first byte + * beyond the ASN.1 element. + * On error, the value of \c *p is undefined. + * \param end End of data. + * \param X On success, the parsed value. + * + * \return 0 if successful. + * \return An ASN.1 error code if the input does not start with + * a valid ASN.1 INTEGER. + * \return #MBEDTLS_ERR_ASN1_INVALID_LENGTH if the parsed value does + * not fit in an \c int. + * \return An MPI error code if the parsed value is too large. + */ +int mbedtls_asn1_get_mpi(unsigned char **p, + const unsigned char *end, + mbedtls_mpi *X); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_mpi_self_test(int verbose); + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ +/** + * \brief Write an arbitrary-precision number (#MBEDTLS_ASN1_INTEGER) + * in ASN.1 format. + * + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param X The MPI to write. + * It must be non-negative. + * + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_asn1_write_mpi(unsigned char **p, const unsigned char *start, + const mbedtls_mpi *X); + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_BIGNUM_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/block_cipher.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/block_cipher.h new file mode 100644 index 0000000000..7a2ccf22f0 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/block_cipher.h @@ -0,0 +1,76 @@ +/** + * \file block_cipher.h + * + * \brief Internal abstraction layer. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_BLOCK_CIPHER_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_BLOCK_CIPHER_H + +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +#if defined(MBEDTLS_AES_C) +#include "mbedtls/private/aes.h" +#endif +#if defined(MBEDTLS_ARIA_C) +#include "mbedtls/private/aria.h" +#endif +#if defined(MBEDTLS_CAMELLIA_C) +#include "mbedtls/private/camellia.h" +#endif + +#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA) +#include "psa/crypto_types.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + MBEDTLS_BLOCK_CIPHER_ID_NONE = 0, /**< Unset. */ + MBEDTLS_BLOCK_CIPHER_ID_AES, /**< The AES cipher. */ + MBEDTLS_BLOCK_CIPHER_ID_CAMELLIA, /**< The Camellia cipher. */ + MBEDTLS_BLOCK_CIPHER_ID_ARIA, /**< The Aria cipher. */ +} mbedtls_block_cipher_id_t; + +/** + * Used internally to indicate whether a context uses legacy or PSA. + * + * Internal use only. + */ +typedef enum { + MBEDTLS_BLOCK_CIPHER_ENGINE_LEGACY = 0, + MBEDTLS_BLOCK_CIPHER_ENGINE_PSA, +} mbedtls_block_cipher_engine_t; + +typedef struct { + mbedtls_block_cipher_id_t MBEDTLS_PRIVATE(id); +#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA) + mbedtls_block_cipher_engine_t MBEDTLS_PRIVATE(engine); + mbedtls_svc_key_id_t MBEDTLS_PRIVATE(psa_key_id); +#endif + union { + unsigned dummy; /* Make the union non-empty even with no supported algorithms. */ +#if defined(MBEDTLS_AES_C) + mbedtls_aes_context MBEDTLS_PRIVATE(aes); +#endif +#if defined(MBEDTLS_ARIA_C) + mbedtls_aria_context MBEDTLS_PRIVATE(aria); +#endif +#if defined(MBEDTLS_CAMELLIA_C) + mbedtls_camellia_context MBEDTLS_PRIVATE(camellia); +#endif + } MBEDTLS_PRIVATE(ctx); +} mbedtls_block_cipher_context_t; + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_BLOCK_CIPHER_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/camellia.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/camellia.h new file mode 100644 index 0000000000..ac8a55cfb5 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/camellia.h @@ -0,0 +1,302 @@ +/** + * \file camellia.h + * + * \brief Camellia block cipher + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CAMELLIA_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CAMELLIA_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +#include +#include + +#include "mbedtls/platform_util.h" + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +#define MBEDTLS_CAMELLIA_ENCRYPT 1 +#define MBEDTLS_CAMELLIA_DECRYPT 0 +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +/** Bad input data. */ +#define MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT + +/** Invalid data input length. */ +#define MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH -0x0026 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief CAMELLIA context structure + */ +typedef struct mbedtls_camellia_context { + int MBEDTLS_PRIVATE(nr); /*!< number of rounds */ + uint32_t MBEDTLS_PRIVATE(rk)[68]; /*!< CAMELLIA round keys */ +} +mbedtls_camellia_context; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief Initialize a CAMELLIA context. + * + * \param ctx The CAMELLIA context to be initialized. + * This must not be \c NULL. + */ +void mbedtls_camellia_init(mbedtls_camellia_context *ctx); + +/** + * \brief Clear a CAMELLIA context. + * + * \param ctx The CAMELLIA context to be cleared. This may be \c NULL, + * in which case this function returns immediately. If it is not + * \c NULL, it must be initialized. + */ +void mbedtls_camellia_free(mbedtls_camellia_context *ctx); + +/** + * \brief Perform a CAMELLIA key schedule operation for encryption. + * + * \param ctx The CAMELLIA context to use. This must be initialized. + * \param key The encryption key to use. This must be a readable buffer + * of size \p keybits Bits. + * \param keybits The length of \p key in Bits. This must be either \c 128, + * \c 192 or \c 256. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_camellia_setkey_enc(mbedtls_camellia_context *ctx, + const unsigned char *key, + unsigned int keybits); + +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +/** + * \brief Perform a CAMELLIA key schedule operation for decryption. + * + * \param ctx The CAMELLIA context to use. This must be initialized. + * \param key The decryption key. This must be a readable buffer + * of size \p keybits Bits. + * \param keybits The length of \p key in Bits. This must be either \c 128, + * \c 192 or \c 256. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_camellia_setkey_dec(mbedtls_camellia_context *ctx, + const unsigned char *key, + unsigned int keybits); +#endif /* !MBEDTLS_BLOCK_CIPHER_NO_DECRYPT */ + +/** + * \brief Perform a CAMELLIA-ECB block encryption/decryption operation. + * + * \param ctx The CAMELLIA context to use. This must be initialized + * and bound to a key. + * \param mode The mode of operation. This must be either + * MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT. + * \param input The input block. This must be a readable buffer + * of size \c 16 Bytes. + * \param output The output block. This must be a writable buffer + * of size \c 16 Bytes. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_camellia_crypt_ecb(mbedtls_camellia_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16]); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief Perform a CAMELLIA-CBC buffer encryption/decryption operation. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx The CAMELLIA context to use. This must be initialized + * and bound to a key. + * \param mode The mode of operation. This must be either + * MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT. + * \param length The length in Bytes of the input data \p input. + * This must be a multiple of \c 16 Bytes. + * \param iv The initialization vector. This must be a read/write buffer + * of length \c 16 Bytes. It is updated to allow streaming + * use as explained above. + * \param input The buffer holding the input data. This must point to a + * readable buffer of length \p length Bytes. + * \param output The buffer holding the output data. This must point to a + * writable buffer of length \p length Bytes. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_camellia_crypt_cbc(mbedtls_camellia_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief Perform a CAMELLIA-CFB128 buffer encryption/decryption + * operation. + * + * \note Due to the nature of CFB mode, you should use the same + * key for both encryption and decryption. In particular, calls + * to this function should be preceded by a key-schedule via + * mbedtls_camellia_setkey_enc() regardless of whether \p mode + * is MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx The CAMELLIA context to use. This must be initialized + * and bound to a key. + * \param mode The mode of operation. This must be either + * MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT. + * \param length The length of the input data \p input. Any value is allowed. + * \param iv_off The current offset in the IV. This must be smaller + * than \c 16 Bytes. It is updated after this call to allow + * the aforementioned streaming usage. + * \param iv The initialization vector. This must be a read/write buffer + * of length \c 16 Bytes. It is updated after this call to + * allow the aforementioned streaming usage. + * \param input The buffer holding the input data. This must be a readable + * buffer of size \p length Bytes. + * \param output The buffer to hold the output data. This must be a writable + * buffer of length \p length Bytes. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_camellia_crypt_cfb128(mbedtls_camellia_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output); +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief Perform a CAMELLIA-CTR buffer encryption/decryption operation. + * + * *note Due to the nature of CTR mode, you should use the same + * key for both encryption and decryption. In particular, calls + * to this function should be preceded by a key-schedule via + * mbedtls_camellia_setkey_enc() regardless of whether the mode + * is MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT. + * + * \warning You must never reuse a nonce value with the same key. Doing so + * would void the encryption for the two messages encrypted with + * the same nonce and key. + * + * There are two common strategies for managing nonces with CTR: + * + * 1. You can handle everything as a single message processed over + * successive calls to this function. In that case, you want to + * set \p nonce_counter and \p nc_off to 0 for the first call, and + * then preserve the values of \p nonce_counter, \p nc_off and \p + * stream_block across calls to this function as they will be + * updated by this function. + * + * With this strategy, you must not encrypt more than 2**128 + * blocks of data with the same key. + * + * 2. You can encrypt separate messages by dividing the \p + * nonce_counter buffer in two areas: the first one used for a + * per-message nonce, handled by yourself, and the second one + * updated by this function internally. + * + * For example, you might reserve the first \c 12 Bytes for the + * per-message nonce, and the last \c 4 Bytes for internal use. + * In that case, before calling this function on a new message you + * need to set the first \c 12 Bytes of \p nonce_counter to your + * chosen nonce value, the last four to \c 0, and \p nc_off to \c 0 + * (which will cause \p stream_block to be ignored). That way, you + * can encrypt at most \c 2**96 messages of up to \c 2**32 blocks + * each with the same key. + * + * The per-message nonce (or information sufficient to reconstruct + * it) needs to be communicated with the ciphertext and must be + * unique. The recommended way to ensure uniqueness is to use a + * message counter. An alternative is to generate random nonces, + * but this limits the number of messages that can be securely + * encrypted: for example, with 96-bit random nonces, you should + * not encrypt more than 2**32 messages with the same key. + * + * Note that for both strategies, sizes are measured in blocks and + * that a CAMELLIA block is \c 16 Bytes. + * + * \warning Upon return, \p stream_block contains sensitive data. Its + * content must not be written to insecure storage and should be + * securely discarded as soon as it's no longer needed. + * + * \param ctx The CAMELLIA context to use. This must be initialized + * and bound to a key. + * \param length The length of the input data \p input in Bytes. + * Any value is allowed. + * \param nc_off The offset in the current \p stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be \c 0 at the start of a stream. It is updated + * at the end of this call. + * \param nonce_counter The 128-bit nonce and counter. This must be a read/write + * buffer of length \c 16 Bytes. + * \param stream_block The saved stream-block for resuming. This must be a + * read/write buffer of length \c 16 Bytes. + * \param input The input data stream. This must be a readable buffer of + * size \p length Bytes. + * \param output The output data stream. This must be a writable buffer + * of size \p length Bytes. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_camellia_crypt_ctr(mbedtls_camellia_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_camellia_self_test(int verbose); + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CAMELLIA_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ccm.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ccm.h new file mode 100644 index 0000000000..0fcc9963d3 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ccm.h @@ -0,0 +1,523 @@ +/** + * \file ccm.h + * + * \brief This file provides an API for the CCM authenticated encryption + * mode for block ciphers. + * + * CCM combines Counter mode encryption with CBC-MAC authentication + * for 128-bit block ciphers. + * + * Input to CCM includes the following elements: + *
  • Payload - data that is both authenticated and encrypted.
  • + *
  • Associated data (Adata) - data that is authenticated but not + * encrypted, For example, a header.
  • + *
  • Nonce - A unique value that is assigned to the payload and the + * associated data.
+ * + * Definition of CCM: + * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf + * RFC 3610 "Counter with CBC-MAC (CCM)" + * + * Related: + * RFC 5116 "An Interface and Algorithms for Authenticated Encryption" + * + * Definition of CCM*: + * IEEE 802.15.4 - IEEE Standard for Local and metropolitan area networks + * Integer representation is fixed most-significant-octet-first order and + * the representation of octets is most-significant-bit-first order. This is + * consistent with RFC 3610. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CCM_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CCM_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +#include "mbedtls/private/cipher.h" + +#if defined(MBEDTLS_BLOCK_CIPHER_C) +#include "mbedtls/private/block_cipher.h" +#endif + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +#define MBEDTLS_CCM_DECRYPT 0 +#define MBEDTLS_CCM_ENCRYPT 1 +#define MBEDTLS_CCM_STAR_DECRYPT 2 +#define MBEDTLS_CCM_STAR_ENCRYPT 3 +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +/** Bad input parameters to the function. */ +#define MBEDTLS_ERR_CCM_BAD_INPUT PSA_ERROR_INVALID_ARGUMENT +/** Authenticated decryption failed. */ +#define MBEDTLS_ERR_CCM_AUTH_FAILED PSA_ERROR_INVALID_SIGNATURE + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief The CCM context-type definition. The CCM context is passed + * to the APIs called. + */ +typedef struct mbedtls_ccm_context { + unsigned char MBEDTLS_PRIVATE(y)[16]; /*!< The Y working buffer */ + unsigned char MBEDTLS_PRIVATE(ctr)[16]; /*!< The counter buffer */ + size_t MBEDTLS_PRIVATE(plaintext_len); /*!< Total plaintext length */ + size_t MBEDTLS_PRIVATE(add_len); /*!< Total authentication data length */ + size_t MBEDTLS_PRIVATE(tag_len); /*!< Total tag length */ + size_t MBEDTLS_PRIVATE(processed); /*!< Track how many bytes of input data + were processed (chunked input). + Used independently for both auth data + and plaintext/ciphertext. + This variable is set to zero after + auth data input is finished. */ + unsigned int MBEDTLS_PRIVATE(q); /*!< The Q working value */ + unsigned int MBEDTLS_PRIVATE(mode); /*!< The operation to perform: + MBEDTLS_CCM_ENCRYPT or + MBEDTLS_CCM_DECRYPT or + MBEDTLS_CCM_STAR_ENCRYPT or + MBEDTLS_CCM_STAR_DECRYPT. */ +#if defined(MBEDTLS_BLOCK_CIPHER_C) + mbedtls_block_cipher_context_t MBEDTLS_PRIVATE(block_cipher_ctx); /*!< The cipher context used. */ +#else + mbedtls_cipher_context_t MBEDTLS_PRIVATE(cipher_ctx); /*!< The cipher context used. */ +#endif + int MBEDTLS_PRIVATE(state); /*!< Working value holding context's + state. Used for chunked data input */ +} +mbedtls_ccm_context; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief This function initializes the specified CCM context, + * to make references valid, and prepare the context + * for mbedtls_ccm_setkey() or mbedtls_ccm_free(). + * + * \param ctx The CCM context to initialize. This must not be \c NULL. + */ +void mbedtls_ccm_init(mbedtls_ccm_context *ctx); + +/** + * \brief This function initializes the CCM context set in the + * \p ctx parameter and sets the encryption key. + * + * \param ctx The CCM context to initialize. This must be an initialized + * context. + * \param cipher The 128-bit block cipher to use. + * \param key The encryption key. This must not be \c NULL. + * \param keybits The key size in bits. This must be acceptable by the cipher. + * + * \return \c 0 on success. + * \return A CCM or cipher-specific error code on failure. + */ +int mbedtls_ccm_setkey(mbedtls_ccm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits); + +/** + * \brief This function releases and clears the specified CCM context + * and underlying cipher sub-context. + * + * \param ctx The CCM context to clear. If this is \c NULL, the function + * has no effect. Otherwise, this must be initialized. + */ +void mbedtls_ccm_free(mbedtls_ccm_context *ctx); + +/** + * \brief This function encrypts a buffer using CCM. + * + * \note The tag is written to a separate buffer. To concatenate + * the \p tag with the \p output, as done in RFC-3610: + * Counter with CBC-MAC (CCM), use + * \p tag = \p output + \p length, and make sure that the + * output buffer is at least \p length + \p tag_len wide. + * + * \param ctx The CCM context to use for encryption. This must be + * initialized and bound to a key. + * \param length The length of the input data in Bytes. + * \param iv The initialization vector (nonce). This must be a readable + * buffer of at least \p iv_len Bytes. + * \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12, + * or 13. The length L of the message length field is + * 15 - \p iv_len. + * \param ad The additional data field. If \p ad_len is greater than + * zero, \p ad must be a readable buffer of at least that + * length. + * \param ad_len The length of additional data in Bytes. + * This must be less than `2^16 - 2^8`. + * \param input The buffer holding the input data. If \p length is greater + * than zero, \p input must be a readable buffer of at least + * that length. + * \param output The buffer holding the output data. If \p length is greater + * than zero, \p output must be a writable buffer of at least + * that length. + * \param tag The buffer holding the authentication field. This must be a + * writable buffer of at least \p tag_len Bytes. + * \param tag_len The length of the authentication field to generate in Bytes: + * 4, 6, 8, 10, 12, 14 or 16. + * + * \return \c 0 on success. + * \return A CCM or cipher-specific error code on failure. + */ +int mbedtls_ccm_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len); + +/** + * \brief This function encrypts a buffer using CCM*. + * + * \note The tag is written to a separate buffer. To concatenate + * the \p tag with the \p output, as done in RFC-3610: + * Counter with CBC-MAC (CCM), use + * \p tag = \p output + \p length, and make sure that the + * output buffer is at least \p length + \p tag_len wide. + * + * \note When using this function in a variable tag length context, + * the tag length has to be encoded into the \p iv passed to + * this function. + * + * \param ctx The CCM context to use for encryption. This must be + * initialized and bound to a key. + * \param length The length of the input data in Bytes. + * For tag length = 0, input length is ignored. + * \param iv The initialization vector (nonce). This must be a readable + * buffer of at least \p iv_len Bytes. + * \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12, + * or 13. The length L of the message length field is + * 15 - \p iv_len. + * \param ad The additional data field. This must be a readable buffer of + * at least \p ad_len Bytes. + * \param ad_len The length of additional data in Bytes. + * This must be less than 2^16 - 2^8. + * \param input The buffer holding the input data. If \p length is greater + * than zero, \p input must be a readable buffer of at least + * that length. + * \param output The buffer holding the output data. If \p length is greater + * than zero, \p output must be a writable buffer of at least + * that length. + * \param tag The buffer holding the authentication field. This must be a + * writable buffer of at least \p tag_len Bytes. + * \param tag_len The length of the authentication field to generate in Bytes: + * 0, 4, 6, 8, 10, 12, 14 or 16. + * + * \warning Passing \c 0 as \p tag_len means that the message is no + * longer authenticated. + * + * \return \c 0 on success. + * \return A CCM or cipher-specific error code on failure. + */ +int mbedtls_ccm_star_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len); + +/** + * \brief This function performs a CCM authenticated decryption of a + * buffer. + * + * \param ctx The CCM context to use for decryption. This must be + * initialized and bound to a key. + * \param length The length of the input data in Bytes. + * \param iv The initialization vector (nonce). This must be a readable + * buffer of at least \p iv_len Bytes. + * \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12, + * or 13. The length L of the message length field is + * 15 - \p iv_len. + * \param ad The additional data field. This must be a readable buffer + * of at least that \p ad_len Bytes.. + * \param ad_len The length of additional data in Bytes. + * This must be less than 2^16 - 2^8. + * \param input The buffer holding the input data. If \p length is greater + * than zero, \p input must be a readable buffer of at least + * that length. + * \param output The buffer holding the output data. If \p length is greater + * than zero, \p output must be a writable buffer of at least + * that length. + * \param tag The buffer holding the authentication field. This must be a + * readable buffer of at least \p tag_len Bytes. + * \param tag_len The length of the authentication field to generate in Bytes: + * 4, 6, 8, 10, 12, 14 or 16. + * + * \return \c 0 on success. This indicates that the message is authentic. + * \return #MBEDTLS_ERR_CCM_AUTH_FAILED if the tag does not match. + * \return A cipher-specific error code on calculation failure. + */ +int mbedtls_ccm_auth_decrypt(mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, unsigned char *output, + const unsigned char *tag, size_t tag_len); + +/** + * \brief This function performs a CCM* authenticated decryption of a + * buffer. + * + * \note When using this function in a variable tag length context, + * the tag length has to be decoded from \p iv and passed to + * this function as \p tag_len. (\p tag needs to be adjusted + * accordingly.) + * + * \param ctx The CCM context to use for decryption. This must be + * initialized and bound to a key. + * \param length The length of the input data in Bytes. + * For tag length = 0, input length is ignored. + * \param iv The initialization vector (nonce). This must be a readable + * buffer of at least \p iv_len Bytes. + * \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12, + * or 13. The length L of the message length field is + * 15 - \p iv_len. + * \param ad The additional data field. This must be a readable buffer of + * at least that \p ad_len Bytes. + * \param ad_len The length of additional data in Bytes. + * This must be less than 2^16 - 2^8. + * \param input The buffer holding the input data. If \p length is greater + * than zero, \p input must be a readable buffer of at least + * that length. + * \param output The buffer holding the output data. If \p length is greater + * than zero, \p output must be a writable buffer of at least + * that length. + * \param tag The buffer holding the authentication field. This must be a + * readable buffer of at least \p tag_len Bytes. + * \param tag_len The length of the authentication field in Bytes. + * 0, 4, 6, 8, 10, 12, 14 or 16. + * + * \warning Passing \c 0 as \p tag_len means that the message is nos + * longer authenticated. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CCM_AUTH_FAILED if the tag does not match. + * \return A cipher-specific error code on calculation failure. + */ +int mbedtls_ccm_star_auth_decrypt(mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, unsigned char *output, + const unsigned char *tag, size_t tag_len); + +/** + * \brief This function starts a CCM encryption or decryption + * operation. + * + * This function and mbedtls_ccm_set_lengths() must be called + * before calling mbedtls_ccm_update_ad() or + * mbedtls_ccm_update(). This function can be called before + * or after mbedtls_ccm_set_lengths(). + * + * \note This function is not implemented in Mbed TLS yet. + * + * \param ctx The CCM context. This must be initialized. + * \param mode The operation to perform: MBEDTLS_CCM_ENCRYPT or + * MBEDTLS_CCM_DECRYPT or MBEDTLS_CCM_STAR_ENCRYPT or + * MBEDTLS_CCM_STAR_DECRYPT. + * \param iv The initialization vector. This must be a readable buffer + * of at least \p iv_len Bytes. + * \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12, + * or 13. The length L of the message length field is + * 15 - \p iv_len. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CCM_BAD_INPUT on failure: + * \p ctx is in an invalid state, + * \p mode is invalid, + * \p iv_len is invalid (lower than \c 7 or greater than + * \c 13). + */ +int mbedtls_ccm_starts(mbedtls_ccm_context *ctx, + int mode, + const unsigned char *iv, + size_t iv_len); + +/** + * \brief This function declares the lengths of the message + * and additional data for a CCM encryption or decryption + * operation. + * + * This function and mbedtls_ccm_starts() must be called + * before calling mbedtls_ccm_update_ad() or + * mbedtls_ccm_update(). This function can be called before + * or after mbedtls_ccm_starts(). + * + * \note This function is not implemented in Mbed TLS yet. + * + * \param ctx The CCM context. This must be initialized. + * \param total_ad_len The total length of additional data in bytes. + * This must be less than `2^16 - 2^8`. + * \param plaintext_len The length in bytes of the plaintext to encrypt or + * result of the decryption (thus not encompassing the + * additional data that are not encrypted). + * \param tag_len The length of the tag to generate in Bytes: + * 4, 6, 8, 10, 12, 14 or 16. + * For CCM*, zero is also valid. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CCM_BAD_INPUT on failure: + * \p ctx is in an invalid state, + * \p total_ad_len is greater than \c 0xFF00. + */ +int mbedtls_ccm_set_lengths(mbedtls_ccm_context *ctx, + size_t total_ad_len, + size_t plaintext_len, + size_t tag_len); + +/** + * \brief This function feeds an input buffer as associated data + * (authenticated but not encrypted data) in a CCM + * encryption or decryption operation. + * + * You may call this function zero, one or more times + * to pass successive parts of the additional data. The + * lengths \p ad_len of the data parts should eventually add + * up exactly to the total length of additional data + * \c total_ad_len passed to mbedtls_ccm_set_lengths(). You + * may not call this function after calling + * mbedtls_ccm_update(). + * + * \note This function is not implemented in Mbed TLS yet. + * + * \param ctx The CCM context. This must have been started with + * mbedtls_ccm_starts(), the lengths of the message and + * additional data must have been declared with + * mbedtls_ccm_set_lengths() and this must not have yet + * received any input with mbedtls_ccm_update(). + * \param ad The buffer holding the additional data, or \c NULL + * if \p ad_len is \c 0. + * \param ad_len The length of the additional data. If \c 0, + * \p ad may be \c NULL. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CCM_BAD_INPUT on failure: + * \p ctx is in an invalid state, + * total input length too long. + */ +int mbedtls_ccm_update_ad(mbedtls_ccm_context *ctx, + const unsigned char *ad, + size_t ad_len); + +/** + * \brief This function feeds an input buffer into an ongoing CCM + * encryption or decryption operation. + * + * You may call this function zero, one or more times + * to pass successive parts of the input: the plaintext to + * encrypt, or the ciphertext (not including the tag) to + * decrypt. After the last part of the input, call + * mbedtls_ccm_finish(). The lengths \p input_len of the + * data parts should eventually add up exactly to the + * plaintext length \c plaintext_len passed to + * mbedtls_ccm_set_lengths(). + * + * This function may produce output in one of the following + * ways: + * - Immediate output: the output length is always equal + * to the input length. + * - Buffered output: except for the last part of input data, + * the output consists of a whole number of 16-byte blocks. + * If the total input length so far (not including + * associated data) is 16 \* *B* + *A* with *A* < 16 then + * the total output length is 16 \* *B*. + * For the last part of input data, the output length is + * equal to the input length plus the number of bytes (*A*) + * buffered in the previous call to the function (if any). + * The function uses the plaintext length + * \c plaintext_len passed to mbedtls_ccm_set_lengths() + * to detect the last part of input data. + * + * In particular: + * - It is always correct to call this function with + * \p output_size >= \p input_len + 15. + * - If \p input_len is a multiple of 16 for all the calls + * to this function during an operation (not necessary for + * the last one) then it is correct to use \p output_size + * =\p input_len. + * + * \note This function is not implemented in Mbed TLS yet. + * + * \param ctx The CCM context. This must have been started with + * mbedtls_ccm_starts() and the lengths of the message and + * additional data must have been declared with + * mbedtls_ccm_set_lengths(). + * \param input The buffer holding the input data. If \p input_len + * is greater than zero, this must be a readable buffer + * of at least \p input_len bytes. + * \param input_len The length of the input data in bytes. + * \param output The buffer for the output data. If \p output_size + * is greater than zero, this must be a writable buffer of + * at least \p output_size bytes. + * \param output_size The size of the output buffer in bytes. + * See the function description regarding the output size. + * \param output_len On success, \p *output_len contains the actual + * length of the output written in \p output. + * On failure, the content of \p *output_len is + * unspecified. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CCM_BAD_INPUT on failure: + * \p ctx is in an invalid state, + * total input length too long, + * or \p output_size too small. + */ +int mbedtls_ccm_update(mbedtls_ccm_context *ctx, + const unsigned char *input, size_t input_len, + unsigned char *output, size_t output_size, + size_t *output_len); + +/** + * \brief This function finishes the CCM operation and generates + * the authentication tag. + * + * It wraps up the CCM stream, and generates the + * tag. The tag can have a maximum length of 16 Bytes. + * + * \note This function is not implemented in Mbed TLS yet. + * + * \param ctx The CCM context. This must have been started with + * mbedtls_ccm_starts() and the lengths of the message and + * additional data must have been declared with + * mbedtls_ccm_set_lengths(). + * \param tag The buffer for holding the tag. If \p tag_len is greater + * than zero, this must be a writable buffer of at least \p + * tag_len Bytes. + * \param tag_len The length of the tag. Must match the tag length passed to + * mbedtls_ccm_set_lengths() function. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CCM_BAD_INPUT on failure: + * \p ctx is in an invalid state, + * invalid value of \p tag_len, + * the total amount of additional data passed to + * mbedtls_ccm_update_ad() was lower than the total length of + * additional data \c total_ad_len passed to + * mbedtls_ccm_set_lengths(), + * the total amount of input data passed to + * mbedtls_ccm_update() was lower than the plaintext length + * \c plaintext_len passed to mbedtls_ccm_set_lengths(). + */ +int mbedtls_ccm_finish(mbedtls_ccm_context *ctx, + unsigned char *tag, size_t tag_len); + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_CCM_GCM_CAN_AES) +/** + * \brief The CCM checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_ccm_self_test(int verbose); +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CCM_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/chacha20.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/chacha20.h new file mode 100644 index 0000000000..3ed5b3e3fd --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/chacha20.h @@ -0,0 +1,201 @@ +/** + * \file chacha20.h + * + * \brief This file contains ChaCha20 definitions and functions. + * + * ChaCha20 is a stream cipher that can encrypt and decrypt + * information. ChaCha was created by Daniel Bernstein as a variant of + * its Salsa cipher https://cr.yp.to/chacha/chacha-20080128.pdf + * ChaCha20 is the variant with 20 rounds, that was also standardized + * in RFC 7539. + * + * \author Daniel King + */ + +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CHACHA20_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CHACHA20_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +#include +#include + +#define MBEDTLS_CHACHA20_BLOCK_SIZE_BYTES (4U * 16U) + +/** Invalid input parameter(s). */ +#define MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct mbedtls_chacha20_context { + uint32_t MBEDTLS_PRIVATE(state)[16]; /*! The state (before round operations). */ + uint8_t MBEDTLS_PRIVATE(keystream8)[64]; /*! Leftover keystream bytes. */ + size_t MBEDTLS_PRIVATE(keystream_bytes_used); /*! Number of keystream bytes already used. */ +} +mbedtls_chacha20_context; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief This function initializes the specified ChaCha20 context. + * + * It must be the first API called before using + * the context. + * + * It is usually followed by calls to + * \c mbedtls_chacha20_setkey() and + * \c mbedtls_chacha20_starts(), then one or more calls to + * to \c mbedtls_chacha20_update(), and finally to + * \c mbedtls_chacha20_free(). + * + * \param ctx The ChaCha20 context to initialize. + * This must not be \c NULL. + */ +void mbedtls_chacha20_init(mbedtls_chacha20_context *ctx); + +/** + * \brief This function releases and clears the specified + * ChaCha20 context. + * + * \param ctx The ChaCha20 context to clear. This may be \c NULL, + * in which case this function is a no-op. If it is not + * \c NULL, it must point to an initialized context. + * + */ +void mbedtls_chacha20_free(mbedtls_chacha20_context *ctx); + +/** + * \brief This function sets the encryption/decryption key. + * + * \note After using this function, you must also call + * \c mbedtls_chacha20_starts() to set a nonce before you + * start encrypting/decrypting data with + * \c mbedtls_chacha_update(). + * + * \param ctx The ChaCha20 context to which the key should be bound. + * It must be initialized. + * \param key The encryption/decryption key. This must be \c 32 Bytes + * in length. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA if ctx or key is NULL. + */ +int mbedtls_chacha20_setkey(mbedtls_chacha20_context *ctx, + const unsigned char key[32]); + +/** + * \brief This function sets the nonce and initial counter value. + * + * \note A ChaCha20 context can be re-used with the same key by + * calling this function to change the nonce. + * + * \warning You must never use the same nonce twice with the same key. + * This would void any confidentiality guarantees for the + * messages encrypted with the same nonce and key. + * + * \param ctx The ChaCha20 context to which the nonce should be bound. + * It must be initialized and bound to a key. + * \param nonce The nonce. This must be \c 12 Bytes in size. + * \param counter The initial counter value. This is usually \c 0. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA if ctx or nonce is + * NULL. + */ +int mbedtls_chacha20_starts(mbedtls_chacha20_context *ctx, + const unsigned char nonce[12], + uint32_t counter); + +/** + * \brief This function encrypts or decrypts data. + * + * Since ChaCha20 is a stream cipher, the same operation is + * used for encrypting and decrypting data. + * + * \note The \p input and \p output pointers must either be equal or + * point to non-overlapping buffers. + * + * \note \c mbedtls_chacha20_setkey() and + * \c mbedtls_chacha20_starts() must be called at least once + * to setup the context before this function can be called. + * + * \note This function can be called multiple times in a row in + * order to encrypt of decrypt data piecewise with the same + * key and nonce. + * + * \param ctx The ChaCha20 context to use for encryption or decryption. + * It must be initialized and bound to a key and nonce. + * \param size The length of the input data in Bytes. + * \param input The buffer holding the input data. + * This pointer can be \c NULL if `size == 0`. + * \param output The buffer holding the output data. + * This must be able to hold \p size Bytes. + * This pointer can be \c NULL if `size == 0`. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chacha20_update(mbedtls_chacha20_context *ctx, + size_t size, + const unsigned char *input, + unsigned char *output); + +/** + * \brief This function encrypts or decrypts data with ChaCha20 and + * the given key and nonce. + * + * Since ChaCha20 is a stream cipher, the same operation is + * used for encrypting and decrypting data. + * + * \warning You must never use the same (key, nonce) pair more than + * once. This would void any confidentiality guarantees for + * the messages encrypted with the same nonce and key. + * + * \note The \p input and \p output pointers must either be equal or + * point to non-overlapping buffers. + * + * \param key The encryption/decryption key. + * This must be \c 32 Bytes in length. + * \param nonce The nonce. This must be \c 12 Bytes in size. + * \param counter The initial counter value. This is usually \c 0. + * \param size The length of the input data in Bytes. + * \param input The buffer holding the input data. + * This pointer can be \c NULL if `size == 0`. + * \param output The buffer holding the output data. + * This must be able to hold \p size Bytes. + * This pointer can be \c NULL if `size == 0`. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chacha20_crypt(const unsigned char key[32], + const unsigned char nonce[12], + uint32_t counter, + size_t size, + const unsigned char *input, + unsigned char *output); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief The ChaCha20 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_chacha20_self_test(int verbose); +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CHACHA20_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/chachapoly.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/chachapoly.h new file mode 100644 index 0000000000..5e3f7dcb11 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/chachapoly.h @@ -0,0 +1,339 @@ +/** + * \file chachapoly.h + * + * \brief This file contains the AEAD-ChaCha20-Poly1305 definitions and + * functions. + * + * ChaCha20-Poly1305 is an algorithm for Authenticated Encryption + * with Associated Data (AEAD) that can be used to encrypt and + * authenticate data. It is based on ChaCha20 and Poly1305 by Daniel + * Bernstein and was standardized in RFC 7539. + * + * \author Daniel King + */ + +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CHACHAPOLY_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CHACHAPOLY_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +/* for shared error codes */ +#include "mbedtls/private/poly1305.h" + +/** The requested operation is not permitted in the current state. */ +#define MBEDTLS_ERR_CHACHAPOLY_BAD_STATE -0x0054 +/** Authenticated decryption failed: data was not authentic. */ +#define MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED PSA_ERROR_INVALID_SIGNATURE + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + MBEDTLS_CHACHAPOLY_ENCRYPT, /**< The mode value for performing encryption. */ + MBEDTLS_CHACHAPOLY_DECRYPT /**< The mode value for performing decryption. */ +} +mbedtls_chachapoly_mode_t; + +#include "mbedtls/private/chacha20.h" + +typedef struct mbedtls_chachapoly_context { + mbedtls_chacha20_context MBEDTLS_PRIVATE(chacha20_ctx); /**< The ChaCha20 context. */ + mbedtls_poly1305_context MBEDTLS_PRIVATE(poly1305_ctx); /**< The Poly1305 context. */ + uint64_t MBEDTLS_PRIVATE(aad_len); /**< The length (bytes) of the Additional Authenticated Data. */ + uint64_t MBEDTLS_PRIVATE(ciphertext_len); /**< The length (bytes) of the ciphertext. */ + int MBEDTLS_PRIVATE(state); /**< The current state of the context. */ + mbedtls_chachapoly_mode_t MBEDTLS_PRIVATE(mode); /**< Cipher mode (encrypt or decrypt). */ +} +mbedtls_chachapoly_context; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief This function initializes the specified ChaCha20-Poly1305 context. + * + * It must be the first API called before using + * the context. It must be followed by a call to + * \c mbedtls_chachapoly_setkey() before any operation can be + * done, and to \c mbedtls_chachapoly_free() once all + * operations with that context have been finished. + * + * In order to encrypt or decrypt full messages at once, for + * each message you should make a single call to + * \c mbedtls_chachapoly_crypt_and_tag() or + * \c mbedtls_chachapoly_auth_decrypt(). + * + * In order to encrypt messages piecewise, for each + * message you should make a call to + * \c mbedtls_chachapoly_starts(), then 0 or more calls to + * \c mbedtls_chachapoly_update_aad(), then 0 or more calls to + * \c mbedtls_chachapoly_update(), then one call to + * \c mbedtls_chachapoly_finish(). + * + * \warning Decryption with the piecewise API is discouraged! Always + * use \c mbedtls_chachapoly_auth_decrypt() when possible! + * + * If however this is not possible because the data is too + * large to fit in memory, you need to: + * + * - call \c mbedtls_chachapoly_starts() and (if needed) + * \c mbedtls_chachapoly_update_aad() as above, + * - call \c mbedtls_chachapoly_update() multiple times and + * ensure its output (the plaintext) is NOT used in any other + * way than placing it in temporary storage at this point, + * - call \c mbedtls_chachapoly_finish() to compute the + * authentication tag and compared it in constant time to the + * tag received with the ciphertext. + * + * If the tags are not equal, you must immediately discard + * all previous outputs of \c mbedtls_chachapoly_update(), + * otherwise you can now safely use the plaintext. + * + * \param ctx The ChachaPoly context to initialize. Must not be \c NULL. + */ +void mbedtls_chachapoly_init(mbedtls_chachapoly_context *ctx); + +/** + * \brief This function releases and clears the specified + * ChaCha20-Poly1305 context. + * + * \param ctx The ChachaPoly context to clear. This may be \c NULL, in which + * case this function is a no-op. + */ +void mbedtls_chachapoly_free(mbedtls_chachapoly_context *ctx); + +/** + * \brief This function sets the ChaCha20-Poly1305 + * symmetric encryption key. + * + * \param ctx The ChaCha20-Poly1305 context to which the key should be + * bound. This must be initialized. + * \param key The \c 256 Bit (\c 32 Bytes) key. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chachapoly_setkey(mbedtls_chachapoly_context *ctx, + const unsigned char key[32]); + +/** + * \brief This function starts a ChaCha20-Poly1305 encryption or + * decryption operation. + * + * \warning You must never use the same nonce twice with the same key. + * This would void any confidentiality and authenticity + * guarantees for the messages encrypted with the same nonce + * and key. + * + * \note If the context is being used for AAD only (no data to + * encrypt or decrypt) then \p mode can be set to any value. + * + * \warning Decryption with the piecewise API is discouraged, see the + * warning on \c mbedtls_chachapoly_init(). + * + * \param ctx The ChaCha20-Poly1305 context. This must be initialized + * and bound to a key. + * \param nonce The nonce/IV to use for the message. + * This must be a readable buffer of length \c 12 Bytes. + * \param mode The operation to perform: #MBEDTLS_CHACHAPOLY_ENCRYPT or + * #MBEDTLS_CHACHAPOLY_DECRYPT (discouraged, see warning). + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chachapoly_starts(mbedtls_chachapoly_context *ctx, + const unsigned char nonce[12], + mbedtls_chachapoly_mode_t mode); + +/** + * \brief This function feeds additional data to be authenticated + * into an ongoing ChaCha20-Poly1305 operation. + * + * The Additional Authenticated Data (AAD), also called + * Associated Data (AD) is only authenticated but not + * encrypted nor included in the encrypted output. It is + * usually transmitted separately from the ciphertext or + * computed locally by each party. + * + * \note This function is called before data is encrypted/decrypted. + * I.e. call this function to process the AAD before calling + * \c mbedtls_chachapoly_update(). + * + * You may call this function multiple times to process + * an arbitrary amount of AAD. It is permitted to call + * this function 0 times, if no AAD is used. + * + * This function cannot be called any more if data has + * been processed by \c mbedtls_chachapoly_update(), + * or if the context has been finished. + * + * \warning Decryption with the piecewise API is discouraged, see the + * warning on \c mbedtls_chachapoly_init(). + * + * \param ctx The ChaCha20-Poly1305 context. This must be initialized + * and bound to a key. + * \param aad_len The length in Bytes of the AAD. The length has no + * restrictions. + * \param aad Buffer containing the AAD. + * This pointer can be \c NULL if `aad_len == 0`. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA + * if \p ctx or \p aad are NULL. + * \return #MBEDTLS_ERR_CHACHAPOLY_BAD_STATE + * if the operations has not been started or has been + * finished, or if the AAD has been finished. + */ +int mbedtls_chachapoly_update_aad(mbedtls_chachapoly_context *ctx, + const unsigned char *aad, + size_t aad_len); + +/** + * \brief Thus function feeds data to be encrypted or decrypted + * into an on-going ChaCha20-Poly1305 + * operation. + * + * The direction (encryption or decryption) depends on the + * mode that was given when calling + * \c mbedtls_chachapoly_starts(). + * + * You may call this function multiple times to process + * an arbitrary amount of data. It is permitted to call + * this function 0 times, if no data is to be encrypted + * or decrypted. + * + * \warning Decryption with the piecewise API is discouraged, see the + * warning on \c mbedtls_chachapoly_init(). + * + * \param ctx The ChaCha20-Poly1305 context to use. This must be initialized. + * \param len The length (in bytes) of the data to encrypt or decrypt. + * \param input The buffer containing the data to encrypt or decrypt. + * This pointer can be \c NULL if `len == 0`. + * \param output The buffer to where the encrypted or decrypted data is + * written. This must be able to hold \p len bytes. + * This pointer can be \c NULL if `len == 0`. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHAPOLY_BAD_STATE + * if the operation has not been started or has been + * finished. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_chachapoly_update(mbedtls_chachapoly_context *ctx, + size_t len, + const unsigned char *input, + unsigned char *output); + +/** + * \brief This function finished the ChaCha20-Poly1305 operation and + * generates the MAC (authentication tag). + * + * \param ctx The ChaCha20-Poly1305 context to use. This must be initialized. + * \param mac The buffer to where the 128-bit (16 bytes) MAC is written. + * + * \warning Decryption with the piecewise API is discouraged, see the + * warning on \c mbedtls_chachapoly_init(). + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHAPOLY_BAD_STATE + * if the operation has not been started or has been + * finished. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_chachapoly_finish(mbedtls_chachapoly_context *ctx, + unsigned char mac[16]); + +/** + * \brief This function performs a complete ChaCha20-Poly1305 + * authenticated encryption with the previously-set key. + * + * \note Before using this function, you must set the key with + * \c mbedtls_chachapoly_setkey(). + * + * \warning You must never use the same nonce twice with the same key. + * This would void any confidentiality and authenticity + * guarantees for the messages encrypted with the same nonce + * and key. + * + * \param ctx The ChaCha20-Poly1305 context to use (holds the key). + * This must be initialized. + * \param length The length (in bytes) of the data to encrypt or decrypt. + * \param nonce The 96-bit (12 bytes) nonce/IV to use. + * \param aad The buffer containing the additional authenticated + * data (AAD). This pointer can be \c NULL if `aad_len == 0`. + * \param aad_len The length (in bytes) of the AAD data to process. + * \param input The buffer containing the data to encrypt or decrypt. + * This pointer can be \c NULL if `ilen == 0`. + * \param output The buffer to where the encrypted or decrypted data + * is written. This pointer can be \c NULL if `ilen == 0`. + * \param tag The buffer to where the computed 128-bit (16 bytes) MAC + * is written. This must not be \c NULL. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chachapoly_encrypt_and_tag(mbedtls_chachapoly_context *ctx, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char *input, + unsigned char *output, + unsigned char tag[16]); + +/** + * \brief This function performs a complete ChaCha20-Poly1305 + * authenticated decryption with the previously-set key. + * + * \note Before using this function, you must set the key with + * \c mbedtls_chachapoly_setkey(). + * + * \param ctx The ChaCha20-Poly1305 context to use (holds the key). + * \param length The length (in Bytes) of the data to decrypt. + * \param nonce The \c 96 Bit (\c 12 bytes) nonce/IV to use. + * \param aad The buffer containing the additional authenticated data (AAD). + * This pointer can be \c NULL if `aad_len == 0`. + * \param aad_len The length (in bytes) of the AAD data to process. + * \param tag The buffer holding the authentication tag. + * This must be a readable buffer of length \c 16 Bytes. + * \param input The buffer containing the data to decrypt. + * This pointer can be \c NULL if `ilen == 0`. + * \param output The buffer to where the decrypted data is written. + * This pointer can be \c NULL if `ilen == 0`. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED + * if the data was not authentic. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_chachapoly_auth_decrypt(mbedtls_chachapoly_context *ctx, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char tag[16], + const unsigned char *input, + unsigned char *output); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief The ChaCha20-Poly1305 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_chachapoly_self_test(int verbose); +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CHACHAPOLY_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/cipher.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/cipher.h new file mode 100644 index 0000000000..4493ca059f --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/cipher.h @@ -0,0 +1,1173 @@ +/** + * \file cipher.h + * + * \brief This file contains an abstraction interface for use with the cipher + * primitives provided by the library. It provides a common interface to all of + * the available cipher operations. + * + * \author Adriaan de Jong + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CIPHER_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CIPHER_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" +#include "psa/crypto_values.h" + +#include +#include "mbedtls/platform_util.h" + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +#define MBEDTLS_CIPHER_MODE_AEAD +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#define MBEDTLS_CIPHER_MODE_WITH_PADDING +#endif + +#if defined(MBEDTLS_CHACHA20_C) +#define MBEDTLS_CIPHER_MODE_STREAM +#endif + +/** The selected feature is not available. */ +#define MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE -0x6080 +/** Bad input parameters. */ +#define MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT +/** Failed to allocate memory. */ +#define MBEDTLS_ERR_CIPHER_ALLOC_FAILED PSA_ERROR_INSUFFICIENT_MEMORY +/** Input data contains invalid padding and is rejected. */ +#define MBEDTLS_ERR_CIPHER_INVALID_PADDING PSA_ERROR_INVALID_PADDING +/** Decryption of block requires a full block. */ +#define MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED -0x6280 +/** Authentication failed (for AEAD modes). */ +#define MBEDTLS_ERR_CIPHER_AUTH_FAILED PSA_ERROR_INVALID_SIGNATURE +/** The context is invalid. For example, because it was freed. */ +#define MBEDTLS_ERR_CIPHER_INVALID_CONTEXT -0x6380 + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +#define MBEDTLS_CIPHER_VARIABLE_IV_LEN 0x01 /**< Cipher accepts IVs of variable length. */ +#define MBEDTLS_CIPHER_VARIABLE_KEY_LEN 0x02 /**< Cipher accepts keys of variable length. */ +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Supported cipher types. + */ +typedef enum { + MBEDTLS_CIPHER_ID_NONE = 0, /**< Placeholder to mark the end of cipher ID lists. */ + MBEDTLS_CIPHER_ID_NULL, /**< The identity cipher, treated as a stream cipher. */ + MBEDTLS_CIPHER_ID_AES, /**< The AES cipher. */ + MBEDTLS_CIPHER_ID_CAMELLIA, /**< The Camellia cipher. */ + MBEDTLS_CIPHER_ID_ARIA, /**< The Aria cipher. */ + MBEDTLS_CIPHER_ID_CHACHA20, /**< The ChaCha20 cipher. */ +} mbedtls_cipher_id_t; + +/** + * \brief Supported {cipher type, cipher mode} pairs. + */ +typedef enum { + MBEDTLS_CIPHER_NONE = 0, /**< Placeholder to mark the end of cipher-pair lists. */ + MBEDTLS_CIPHER_NULL, /**< The identity stream cipher. */ + MBEDTLS_CIPHER_AES_128_ECB, /**< AES cipher with 128-bit ECB mode. */ + MBEDTLS_CIPHER_AES_192_ECB, /**< AES cipher with 192-bit ECB mode. */ + MBEDTLS_CIPHER_AES_256_ECB, /**< AES cipher with 256-bit ECB mode. */ + MBEDTLS_CIPHER_AES_128_CBC, /**< AES cipher with 128-bit CBC mode. */ + MBEDTLS_CIPHER_AES_192_CBC, /**< AES cipher with 192-bit CBC mode. */ + MBEDTLS_CIPHER_AES_256_CBC, /**< AES cipher with 256-bit CBC mode. */ + MBEDTLS_CIPHER_AES_128_CFB128, /**< AES cipher with 128-bit CFB128 mode. */ + MBEDTLS_CIPHER_AES_192_CFB128, /**< AES cipher with 192-bit CFB128 mode. */ + MBEDTLS_CIPHER_AES_256_CFB128, /**< AES cipher with 256-bit CFB128 mode. */ + MBEDTLS_CIPHER_AES_128_CTR, /**< AES cipher with 128-bit CTR mode. */ + MBEDTLS_CIPHER_AES_192_CTR, /**< AES cipher with 192-bit CTR mode. */ + MBEDTLS_CIPHER_AES_256_CTR, /**< AES cipher with 256-bit CTR mode. */ + MBEDTLS_CIPHER_AES_128_GCM, /**< AES cipher with 128-bit GCM mode. */ + MBEDTLS_CIPHER_AES_192_GCM, /**< AES cipher with 192-bit GCM mode. */ + MBEDTLS_CIPHER_AES_256_GCM, /**< AES cipher with 256-bit GCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_ECB, /**< Camellia cipher with 128-bit ECB mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_ECB, /**< Camellia cipher with 192-bit ECB mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_ECB, /**< Camellia cipher with 256-bit ECB mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_CBC, /**< Camellia cipher with 128-bit CBC mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_CBC, /**< Camellia cipher with 192-bit CBC mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_CBC, /**< Camellia cipher with 256-bit CBC mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_CFB128, /**< Camellia cipher with 128-bit CFB128 mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_CFB128, /**< Camellia cipher with 192-bit CFB128 mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_CFB128, /**< Camellia cipher with 256-bit CFB128 mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_CTR, /**< Camellia cipher with 128-bit CTR mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_CTR, /**< Camellia cipher with 192-bit CTR mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_CTR, /**< Camellia cipher with 256-bit CTR mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_GCM, /**< Camellia cipher with 128-bit GCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_GCM, /**< Camellia cipher with 192-bit GCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_GCM, /**< Camellia cipher with 256-bit GCM mode. */ + MBEDTLS_CIPHER_AES_128_CCM, /**< AES cipher with 128-bit CCM mode. */ + MBEDTLS_CIPHER_AES_192_CCM, /**< AES cipher with 192-bit CCM mode. */ + MBEDTLS_CIPHER_AES_256_CCM, /**< AES cipher with 256-bit CCM mode. */ + MBEDTLS_CIPHER_AES_128_CCM_STAR_NO_TAG, /**< AES cipher with 128-bit CCM_STAR_NO_TAG mode. */ + MBEDTLS_CIPHER_AES_192_CCM_STAR_NO_TAG, /**< AES cipher with 192-bit CCM_STAR_NO_TAG mode. */ + MBEDTLS_CIPHER_AES_256_CCM_STAR_NO_TAG, /**< AES cipher with 256-bit CCM_STAR_NO_TAG mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_CCM, /**< Camellia cipher with 128-bit CCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_CCM, /**< Camellia cipher with 192-bit CCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_CCM, /**< Camellia cipher with 256-bit CCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_CCM_STAR_NO_TAG, /**< Camellia cipher with 128-bit CCM_STAR_NO_TAG mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_CCM_STAR_NO_TAG, /**< Camellia cipher with 192-bit CCM_STAR_NO_TAG mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_CCM_STAR_NO_TAG, /**< Camellia cipher with 256-bit CCM_STAR_NO_TAG mode. */ + MBEDTLS_CIPHER_ARIA_128_ECB, /**< Aria cipher with 128-bit key and ECB mode. */ + MBEDTLS_CIPHER_ARIA_192_ECB, /**< Aria cipher with 192-bit key and ECB mode. */ + MBEDTLS_CIPHER_ARIA_256_ECB, /**< Aria cipher with 256-bit key and ECB mode. */ + MBEDTLS_CIPHER_ARIA_128_CBC, /**< Aria cipher with 128-bit key and CBC mode. */ + MBEDTLS_CIPHER_ARIA_192_CBC, /**< Aria cipher with 192-bit key and CBC mode. */ + MBEDTLS_CIPHER_ARIA_256_CBC, /**< Aria cipher with 256-bit key and CBC mode. */ + MBEDTLS_CIPHER_ARIA_128_CFB128, /**< Aria cipher with 128-bit key and CFB-128 mode. */ + MBEDTLS_CIPHER_ARIA_192_CFB128, /**< Aria cipher with 192-bit key and CFB-128 mode. */ + MBEDTLS_CIPHER_ARIA_256_CFB128, /**< Aria cipher with 256-bit key and CFB-128 mode. */ + MBEDTLS_CIPHER_ARIA_128_CTR, /**< Aria cipher with 128-bit key and CTR mode. */ + MBEDTLS_CIPHER_ARIA_192_CTR, /**< Aria cipher with 192-bit key and CTR mode. */ + MBEDTLS_CIPHER_ARIA_256_CTR, /**< Aria cipher with 256-bit key and CTR mode. */ + MBEDTLS_CIPHER_ARIA_128_GCM, /**< Aria cipher with 128-bit key and GCM mode. */ + MBEDTLS_CIPHER_ARIA_192_GCM, /**< Aria cipher with 192-bit key and GCM mode. */ + MBEDTLS_CIPHER_ARIA_256_GCM, /**< Aria cipher with 256-bit key and GCM mode. */ + MBEDTLS_CIPHER_ARIA_128_CCM, /**< Aria cipher with 128-bit key and CCM mode. */ + MBEDTLS_CIPHER_ARIA_192_CCM, /**< Aria cipher with 192-bit key and CCM mode. */ + MBEDTLS_CIPHER_ARIA_256_CCM, /**< Aria cipher with 256-bit key and CCM mode. */ + MBEDTLS_CIPHER_ARIA_128_CCM_STAR_NO_TAG, /**< Aria cipher with 128-bit key and CCM_STAR_NO_TAG mode. */ + MBEDTLS_CIPHER_ARIA_192_CCM_STAR_NO_TAG, /**< Aria cipher with 192-bit key and CCM_STAR_NO_TAG mode. */ + MBEDTLS_CIPHER_ARIA_256_CCM_STAR_NO_TAG, /**< Aria cipher with 256-bit key and CCM_STAR_NO_TAG mode. */ + MBEDTLS_CIPHER_AES_128_OFB, /**< AES 128-bit cipher in OFB mode. */ + MBEDTLS_CIPHER_AES_192_OFB, /**< AES 192-bit cipher in OFB mode. */ + MBEDTLS_CIPHER_AES_256_OFB, /**< AES 256-bit cipher in OFB mode. */ + MBEDTLS_CIPHER_AES_128_XTS, /**< AES 128-bit cipher in XTS block mode. */ + MBEDTLS_CIPHER_AES_256_XTS, /**< AES 256-bit cipher in XTS block mode. */ + MBEDTLS_CIPHER_CHACHA20, /**< ChaCha20 stream cipher. */ + MBEDTLS_CIPHER_CHACHA20_POLY1305, /**< ChaCha20-Poly1305 AEAD cipher. */ + MBEDTLS_CIPHER_AES_128_KW, /**< AES cipher with 128-bit NIST KW mode. */ + MBEDTLS_CIPHER_AES_192_KW, /**< AES cipher with 192-bit NIST KW mode. */ + MBEDTLS_CIPHER_AES_256_KW, /**< AES cipher with 256-bit NIST KW mode. */ + MBEDTLS_CIPHER_AES_128_KWP, /**< AES cipher with 128-bit NIST KWP mode. */ + MBEDTLS_CIPHER_AES_192_KWP, /**< AES cipher with 192-bit NIST KWP mode. */ + MBEDTLS_CIPHER_AES_256_KWP, /**< AES cipher with 256-bit NIST KWP mode. */ +} mbedtls_cipher_type_t; + +/** Supported cipher modes. */ +typedef enum { + MBEDTLS_MODE_NONE = 0, /**< None. */ + MBEDTLS_MODE_ECB, /**< The ECB cipher mode. */ + MBEDTLS_MODE_CBC, /**< The CBC cipher mode. */ + MBEDTLS_MODE_CFB, /**< The CFB cipher mode. */ + MBEDTLS_MODE_OFB, /**< The OFB cipher mode. */ + MBEDTLS_MODE_CTR, /**< The CTR cipher mode. */ + MBEDTLS_MODE_GCM, /**< The GCM cipher mode. */ + MBEDTLS_MODE_STREAM, /**< The stream cipher mode. */ + MBEDTLS_MODE_CCM, /**< The CCM cipher mode. */ + MBEDTLS_MODE_CCM_STAR_NO_TAG, /**< The CCM*-no-tag cipher mode. */ + MBEDTLS_MODE_XTS, /**< The XTS cipher mode. */ + MBEDTLS_MODE_CHACHAPOLY, /**< The ChaCha-Poly cipher mode. */ + MBEDTLS_MODE_KW, /**< The SP800-38F KW mode */ + MBEDTLS_MODE_KWP, /**< The SP800-38F KWP mode */ +} mbedtls_cipher_mode_t; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** Supported cipher padding types. */ +typedef enum { + MBEDTLS_PADDING_PKCS7 = 0, /**< PKCS7 padding (default). */ + MBEDTLS_PADDING_NONE, /**< Never pad (full blocks only). */ +} mbedtls_cipher_padding_t; +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +/** Type of operation. */ +typedef enum { + MBEDTLS_OPERATION_NONE = -1, + MBEDTLS_DECRYPT = 0, + MBEDTLS_ENCRYPT, +} mbedtls_operation_t; + +/** Maximum length of any IV, in Bytes. */ +/* This should ideally be derived automatically from list of ciphers. + */ +#define MBEDTLS_MAX_IV_LENGTH 16 + +/** Maximum block size of any cipher, in Bytes. */ +/* This should ideally be derived automatically from list of ciphers. + */ +#define MBEDTLS_MAX_BLOCK_LENGTH 16 + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** Maximum key length, in Bytes. */ +/* This should ideally be derived automatically from list of ciphers. + * For now, only check whether XTS is enabled which uses 64 Byte keys, + * and use 32 Bytes as an upper bound for the maximum key length otherwise. + */ +#if defined(MBEDTLS_CIPHER_MODE_XTS) +#define MBEDTLS_MAX_KEY_LENGTH 64 +#else +#define MBEDTLS_MAX_KEY_LENGTH 32 +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +/** + * Base cipher information (opaque struct). + */ +typedef struct mbedtls_cipher_base_t mbedtls_cipher_base_t; +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +/** + * CMAC context (opaque struct). + */ +typedef struct mbedtls_cmac_context_t mbedtls_cmac_context_t; + +/** + * Cipher information. Allows calling cipher functions + * in a generic way. + * + * \note The library does not support custom cipher info structures, + * only built-in structures returned by the functions + * mbedtls_cipher_info_from_string(), + * mbedtls_cipher_info_from_type(), + * mbedtls_cipher_info_from_values(), + * mbedtls_cipher_info_from_psa(). + * + * \note Some fields store a value that has been right-shifted to save + * code-size, so should not be used directly. The accessor + * functions adjust for this and return the "natural" value. + */ +typedef struct mbedtls_cipher_info_t { + /** Name of the cipher. */ + const char *MBEDTLS_PRIVATE(name); + + /** The block size, in bytes. */ + unsigned int MBEDTLS_PRIVATE(block_size) : 5; + + /** IV or nonce size, in bytes (right shifted by MBEDTLS_IV_SIZE_SHIFT). + * For ciphers that accept variable IV sizes, + * this is the recommended size. + */ + unsigned int MBEDTLS_PRIVATE(iv_size) : 3; + + /** The cipher key length, in bits (right shifted by MBEDTLS_KEY_BITLEN_SHIFT). + * This is the default length for variable sized ciphers. + */ + unsigned int MBEDTLS_PRIVATE(key_bitlen) : 4; + + /** The cipher mode (as per mbedtls_cipher_mode_t). + * For example, MBEDTLS_MODE_CBC. + */ + unsigned int MBEDTLS_PRIVATE(mode) : 4; + + /** Full cipher identifier (as per mbedtls_cipher_type_t). + * For example, MBEDTLS_CIPHER_AES_256_CBC. + * + * This could be 7 bits, but 8 bits retains byte alignment for the + * next field, which reduces code size to access that field. + */ + unsigned int MBEDTLS_PRIVATE(type) : 8; + + /** Bitflag comprised of MBEDTLS_CIPHER_VARIABLE_IV_LEN and + * MBEDTLS_CIPHER_VARIABLE_KEY_LEN indicating whether the + * cipher supports variable IV or variable key sizes, respectively. + */ + unsigned int MBEDTLS_PRIVATE(flags) : 2; + + /** Index to LUT for base cipher information and functions. */ + unsigned int MBEDTLS_PRIVATE(base_idx) : 5; + +} mbedtls_cipher_info_t; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/* For internal use only. + * These are used to more compactly represent the fields above. */ +#define MBEDTLS_KEY_BITLEN_SHIFT 6 +#define MBEDTLS_IV_SIZE_SHIFT 2 +#endif + +/** + * Generic cipher context. + */ +typedef struct mbedtls_cipher_context_t { + /** Information about the associated cipher. */ + const mbedtls_cipher_info_t *MBEDTLS_PRIVATE(cipher_info); + + /** Key length to use. */ + int MBEDTLS_PRIVATE(key_bitlen); + + /** Operation that the key of the context has been + * initialized for. + */ + mbedtls_operation_t MBEDTLS_PRIVATE(operation); + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) + /** Padding functions to use, if relevant for + * the specific cipher mode. + */ + void(*MBEDTLS_PRIVATE(add_padding))(unsigned char *output, size_t olen, + size_t data_len); + /* Report invalid-padding condition through the output parameter + * invalid_padding. To minimize changes in Mbed TLS 3.6, where this + * declaration is in a public header, use the public type size_t + * rather than the internal type mbedtls_ct_condition_t. */ + int(*MBEDTLS_PRIVATE(get_padding))(unsigned char *input, size_t ilen, + size_t *data_len, + size_t *invalid_padding); +#endif + + /** Buffer for input that has not been processed yet. */ + unsigned char MBEDTLS_PRIVATE(unprocessed_data)[MBEDTLS_MAX_BLOCK_LENGTH]; + + /** Number of Bytes that have not been processed yet. */ + size_t MBEDTLS_PRIVATE(unprocessed_len); + + /** Current IV or NONCE_COUNTER for CTR-mode, data unit (or sector) number + * for XTS-mode. */ + unsigned char MBEDTLS_PRIVATE(iv)[MBEDTLS_MAX_IV_LENGTH]; + + /** IV size in Bytes, for ciphers with variable-length IVs. */ + size_t MBEDTLS_PRIVATE(iv_size); + + /** The cipher-specific context. */ + void *MBEDTLS_PRIVATE(cipher_ctx); + +#if defined(MBEDTLS_CMAC_C) + /** CMAC-specific context. */ + mbedtls_cmac_context_t *MBEDTLS_PRIVATE(cmac_ctx); +#endif + +} mbedtls_cipher_context_t; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief This function retrieves the list of ciphers supported + * by the generic cipher module. + * + * For any cipher identifier in the returned list, you can + * obtain the corresponding generic cipher information structure + * via mbedtls_cipher_info_from_type(), which can then be used + * to prepare a cipher context via mbedtls_cipher_setup(). + * + * + * \return A statically-allocated array of cipher identifiers + * of type cipher_type_t. The last entry is zero. + */ +const int *mbedtls_cipher_list(void); + +/** + * \brief This function retrieves the cipher-information + * structure associated with the given cipher name. + * + * \param cipher_name Name of the cipher to search for. This must not be + * \c NULL. + * + * \return The cipher information structure associated with the + * given \p cipher_name. + * \return \c NULL if the associated cipher information is not found. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string(const char *cipher_name); + +/** + * \brief This function retrieves the cipher-information + * structure associated with the given cipher type. + * + * \param cipher_type Type of the cipher to search for. + * + * \return The cipher information structure associated with the + * given \p cipher_type. + * \return \c NULL if the associated cipher information is not found. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type(const mbedtls_cipher_type_t cipher_type); + +/** + * \brief This function retrieves the cipher-information + * structure associated with the given cipher ID, + * key size and mode. + * + * \param cipher_id The ID of the cipher to search for. For example, + * #MBEDTLS_CIPHER_ID_AES. + * \param key_bitlen The length of the key in bits. + * \param mode The cipher mode. For example, #MBEDTLS_MODE_CBC. + * + * \return The cipher information structure associated with the + * given \p cipher_id. + * \return \c NULL if the associated cipher information is not found. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values(const mbedtls_cipher_id_t cipher_id, + int key_bitlen, + const mbedtls_cipher_mode_t mode); + +/** + * \brief Retrieve the identifier for a cipher info structure. + * + * \param[in] info The cipher info structure to query. + * This may be \c NULL. + * + * \return The full cipher identifier (\c MBEDTLS_CIPHER_xxx). + * \return #MBEDTLS_CIPHER_NONE if \p info is \c NULL. + */ +static inline mbedtls_cipher_type_t mbedtls_cipher_info_get_type( + const mbedtls_cipher_info_t *info) +{ + if (info == NULL) { + return MBEDTLS_CIPHER_NONE; + } else { + return (mbedtls_cipher_type_t) info->MBEDTLS_PRIVATE(type); + } +} + +/** + * \brief Retrieve the operation mode for a cipher info structure. + * + * \param[in] info The cipher info structure to query. + * This may be \c NULL. + * + * \return The cipher mode (\c MBEDTLS_MODE_xxx). + * \return #MBEDTLS_MODE_NONE if \p info is \c NULL. + */ +static inline mbedtls_cipher_mode_t mbedtls_cipher_info_get_mode( + const mbedtls_cipher_info_t *info) +{ + if (info == NULL) { + return MBEDTLS_MODE_NONE; + } else { + return (mbedtls_cipher_mode_t) info->MBEDTLS_PRIVATE(mode); + } +} + +/** + * \brief Retrieve the key size for a cipher info structure. + * + * \param[in] info The cipher info structure to query. + * This may be \c NULL. + * + * \return The key length in bits. + * For variable-sized ciphers, this is the default length. + * \return \c 0 if \p info is \c NULL. + */ +static inline size_t mbedtls_cipher_info_get_key_bitlen( + const mbedtls_cipher_info_t *info) +{ + if (info == NULL) { + return 0; + } else { + return ((size_t) info->MBEDTLS_PRIVATE(key_bitlen)) << MBEDTLS_KEY_BITLEN_SHIFT; + } +} + +/** + * \brief Retrieve the human-readable name for a + * cipher info structure. + * + * \param[in] info The cipher info structure to query. + * This may be \c NULL. + * + * \return The cipher name, which is a human readable string, + * with static storage duration. + * \return \c NULL if \p info is \c NULL. + */ +static inline const char *mbedtls_cipher_info_get_name( + const mbedtls_cipher_info_t *info) +{ + if (info == NULL) { + return NULL; + } else { + return info->MBEDTLS_PRIVATE(name); + } +} + +/** + * \brief This function returns the size of the IV or nonce + * for the cipher info structure, in bytes. + * + * \param info The cipher info structure. This may be \c NULL. + * + * \return The recommended IV size. + * \return \c 0 for ciphers not using an IV or a nonce. + * \return \c 0 if \p info is \c NULL. + */ +static inline size_t mbedtls_cipher_info_get_iv_size( + const mbedtls_cipher_info_t *info) +{ + if (info == NULL) { + return 0; + } + + return ((size_t) info->MBEDTLS_PRIVATE(iv_size)) << MBEDTLS_IV_SIZE_SHIFT; +} + +/** + * \brief This function returns the block size of the given + * cipher info structure in bytes. + * + * \param info The cipher info structure. This may be \c NULL. + * + * \return The block size of the cipher. + * \return \c 1 if the cipher is a stream cipher. + * \return \c 0 if \p info is \c NULL. + */ +static inline size_t mbedtls_cipher_info_get_block_size( + const mbedtls_cipher_info_t *info) +{ + if (info == NULL) { + return 0; + } + + return (size_t) (info->MBEDTLS_PRIVATE(block_size)); +} + +/** + * \brief This function returns a non-zero value if the key length for + * the given cipher is variable. + * + * \param info The cipher info structure. This may be \c NULL. + * + * \return Non-zero if the key length is variable, \c 0 otherwise. + * \return \c 0 if the given pointer is \c NULL. + */ +static inline int mbedtls_cipher_info_has_variable_key_bitlen( + const mbedtls_cipher_info_t *info) +{ + if (info == NULL) { + return 0; + } + + return info->MBEDTLS_PRIVATE(flags) & MBEDTLS_CIPHER_VARIABLE_KEY_LEN; +} + +/** + * \brief This function returns a non-zero value if the IV size for + * the given cipher is variable. + * + * \param info The cipher info structure. This may be \c NULL. + * + * \return Non-zero if the IV size is variable, \c 0 otherwise. + * \return \c 0 if the given pointer is \c NULL. + */ +static inline int mbedtls_cipher_info_has_variable_iv_size( + const mbedtls_cipher_info_t *info) +{ + if (info == NULL) { + return 0; + } + + return info->MBEDTLS_PRIVATE(flags) & MBEDTLS_CIPHER_VARIABLE_IV_LEN; +} + +/** + * \brief This function initializes a \p ctx as NONE. + * + * \param ctx The context to be initialized. This must not be \c NULL. + */ +void mbedtls_cipher_init(mbedtls_cipher_context_t *ctx); + +/** + * \brief This function frees and clears the cipher-specific + * context of \p ctx. Freeing \p ctx itself remains the + * responsibility of the caller. + * + * \param ctx The context to be freed. If this is \c NULL, the + * function has no effect, otherwise this must point to an + * initialized context. + */ +void mbedtls_cipher_free(mbedtls_cipher_context_t *ctx); + + +/** + * \brief This function prepares a cipher context for + * use with the given cipher primitive. + * + * \note After calling this function, you should call + * mbedtls_cipher_setkey() and, if the mode uses padding, + * mbedtls_cipher_set_padding_mode(), then for each + * message to encrypt or decrypt with this key, either: + * - mbedtls_cipher_crypt() for one-shot processing with + * non-AEAD modes; + * - mbedtls_cipher_auth_encrypt_ext() or + * mbedtls_cipher_auth_decrypt_ext() for one-shot + * processing with AEAD modes; + * - for multi-part processing, see the documentation of + * mbedtls_cipher_reset(). + * + * \param ctx The context to prepare. This must be initialized by + * a call to mbedtls_cipher_init() first. + * \param cipher_info The cipher to use. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_ALLOC_FAILED if allocation of the + * cipher-specific context fails. + */ +int mbedtls_cipher_setup(mbedtls_cipher_context_t *ctx, + const mbedtls_cipher_info_t *cipher_info); + +/** + * \brief This function returns the block size of the given cipher + * in bytes. + * + * \param ctx The context of the cipher. + * + * \return The block size of the underlying cipher. + * \return \c 1 if the cipher is a stream cipher. + * \return \c 0 if \p ctx has not been initialized. + */ +static inline unsigned int mbedtls_cipher_get_block_size( + const mbedtls_cipher_context_t *ctx) +{ + if (ctx->MBEDTLS_PRIVATE(cipher_info) == NULL) { + return 0; + } + + return (unsigned int) ctx->MBEDTLS_PRIVATE(cipher_info)->MBEDTLS_PRIVATE(block_size); +} + +/** + * \brief This function returns the mode of operation for + * the cipher. For example, MBEDTLS_MODE_CBC. + * + * \param ctx The context of the cipher. This must be initialized. + * + * \return The mode of operation. + * \return #MBEDTLS_MODE_NONE if \p ctx has not been initialized. + */ +static inline mbedtls_cipher_mode_t mbedtls_cipher_get_cipher_mode( + const mbedtls_cipher_context_t *ctx) +{ + if (ctx->MBEDTLS_PRIVATE(cipher_info) == NULL) { + return MBEDTLS_MODE_NONE; + } + + return (mbedtls_cipher_mode_t) ctx->MBEDTLS_PRIVATE(cipher_info)->MBEDTLS_PRIVATE(mode); +} + +/** + * \brief This function returns the size of the IV or nonce + * of the cipher, in Bytes. + * + * \param ctx The context of the cipher. This must be initialized. + * + * \return The recommended IV size if no IV has been set. + * \return \c 0 for ciphers not using an IV or a nonce. + * \return The actual size if an IV has been set. + */ +static inline int mbedtls_cipher_get_iv_size( + const mbedtls_cipher_context_t *ctx) +{ + if (ctx->MBEDTLS_PRIVATE(cipher_info) == NULL) { + return 0; + } + + if (ctx->MBEDTLS_PRIVATE(iv_size) != 0) { + return (int) ctx->MBEDTLS_PRIVATE(iv_size); + } + + return (int) (((int) ctx->MBEDTLS_PRIVATE(cipher_info)->MBEDTLS_PRIVATE(iv_size)) << + MBEDTLS_IV_SIZE_SHIFT); +} + +/** + * \brief This function returns the type of the given cipher. + * + * \param ctx The context of the cipher. This must be initialized. + * + * \return The type of the cipher. + * \return #MBEDTLS_CIPHER_NONE if \p ctx has not been initialized. + */ +static inline mbedtls_cipher_type_t mbedtls_cipher_get_type( + const mbedtls_cipher_context_t *ctx) +{ + if (ctx->MBEDTLS_PRIVATE(cipher_info) == NULL) { + return MBEDTLS_CIPHER_NONE; + } + + return (mbedtls_cipher_type_t) ctx->MBEDTLS_PRIVATE(cipher_info)->MBEDTLS_PRIVATE(type); +} + +/** + * \brief This function returns the name of the given cipher + * as a string. + * + * \param ctx The context of the cipher. This must be initialized. + * + * \return The name of the cipher. + * \return NULL if \p ctx has not been not initialized. + */ +static inline const char *mbedtls_cipher_get_name( + const mbedtls_cipher_context_t *ctx) +{ + if (ctx->MBEDTLS_PRIVATE(cipher_info) == NULL) { + return 0; + } + + return ctx->MBEDTLS_PRIVATE(cipher_info)->MBEDTLS_PRIVATE(name); +} + +/** + * \brief This function returns the key length of the cipher. + * + * \param ctx The context of the cipher. This must be initialized. + * + * \return The key length of the cipher in bits. + * \return 0 if \p ctx has not been + * initialized. + */ +static inline int mbedtls_cipher_get_key_bitlen( + const mbedtls_cipher_context_t *ctx) +{ + if (ctx->MBEDTLS_PRIVATE(cipher_info) == NULL) { + return 0; + } + + return (int) ctx->MBEDTLS_PRIVATE(cipher_info)->MBEDTLS_PRIVATE(key_bitlen) << + MBEDTLS_KEY_BITLEN_SHIFT; +} + +/** + * \brief This function returns the operation of the given cipher. + * + * \param ctx The context of the cipher. This must be initialized. + * + * \return The type of operation: #MBEDTLS_ENCRYPT or #MBEDTLS_DECRYPT. + * \return #MBEDTLS_OPERATION_NONE if \p ctx has not been initialized. + */ +static inline mbedtls_operation_t mbedtls_cipher_get_operation( + const mbedtls_cipher_context_t *ctx) +{ + if (ctx->MBEDTLS_PRIVATE(cipher_info) == NULL) { + return MBEDTLS_OPERATION_NONE; + } + + return ctx->MBEDTLS_PRIVATE(operation); +} + +/** + * \brief This function sets the key to use with the given context. + * + * \param ctx The generic cipher context. This must be initialized and + * bound to a cipher information structure. + * \param key The key to use. This must be a readable buffer of at + * least \p key_bitlen Bits. + * \param key_bitlen The key length to use, in Bits. + * \param operation The operation that the key will be used for: + * #MBEDTLS_ENCRYPT or #MBEDTLS_DECRYPT. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_setkey(mbedtls_cipher_context_t *ctx, + const unsigned char *key, + int key_bitlen, + const mbedtls_operation_t operation); + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) +/** + * \brief This function sets the padding mode, for cipher modes + * that use padding. + * + * + * \param ctx The generic cipher context. This must be initialized and + * bound to a cipher information structure. + * \param mode The padding mode. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE + * if the selected padding mode is not supported. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if the cipher mode + * does not support padding. + */ +int mbedtls_cipher_set_padding_mode(mbedtls_cipher_context_t *ctx, + mbedtls_cipher_padding_t mode); +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + +/** + * \brief This function sets the initialization vector (IV) + * or nonce. + * + * \note Some ciphers do not use IVs nor nonce. For these + * ciphers, this function has no effect. + * + * \note For #MBEDTLS_CIPHER_CHACHA20, the nonce length must + * be 12, and the initial counter value is 0. + * + * \note For #MBEDTLS_CIPHER_CHACHA20_POLY1305, the nonce length + * must be 12. + * + * \param ctx The generic cipher context. This must be initialized and + * bound to a cipher information structure. + * \param iv The IV to use, or NONCE_COUNTER for CTR-mode ciphers. This + * must be a readable buffer of at least \p iv_len Bytes. + * \param iv_len The IV length for ciphers with variable-size IV. + * This parameter is discarded by ciphers with fixed-size IV. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + */ +int mbedtls_cipher_set_iv(mbedtls_cipher_context_t *ctx, + const unsigned char *iv, + size_t iv_len); + +/** + * \brief This function resets the cipher state. + * + * \note With non-AEAD ciphers, the order of calls for each message + * is as follows: + * 1. mbedtls_cipher_set_iv() if the mode uses an IV/nonce; + * 2. mbedtls_cipher_reset(); + * 3. mbedtls_cipher_update() zero, one or more times; + * 4. mbedtls_cipher_finish_padded() (recommended for decryption + * if the mode uses padding) or mbedtls_cipher_finish(). + * . + * This sequence can be repeated to encrypt or decrypt multiple + * messages with the same key. + * + * \note With AEAD ciphers, the order of calls for each message + * is as follows: + * 1. mbedtls_cipher_set_iv() if the mode uses an IV/nonce; + * 2. mbedtls_cipher_reset(); + * 3. mbedtls_cipher_update_ad(); + * 4. mbedtls_cipher_update() zero, one or more times; + * 5. mbedtls_cipher_finish() (or mbedtls_cipher_finish_padded()); + * 6. mbedtls_cipher_check_tag() (for decryption) or + * mbedtls_cipher_write_tag() (for encryption). + * . + * This sequence can be repeated to encrypt or decrypt multiple + * messages with the same key. + * + * \param ctx The generic cipher context. This must be bound to a key. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + */ +int mbedtls_cipher_reset(mbedtls_cipher_context_t *ctx); + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +/** + * \brief This function adds additional data for AEAD ciphers. + * Currently supported with GCM and ChaCha20+Poly1305. + * + * \param ctx The generic cipher context. This must be initialized. + * \param ad The additional data to use. This must be a readable + * buffer of at least \p ad_len Bytes. + * \param ad_len The length of \p ad in Bytes. + * + * \return \c 0 on success. + * \return A specific error code on failure. + */ +int mbedtls_cipher_update_ad(mbedtls_cipher_context_t *ctx, + const unsigned char *ad, size_t ad_len); +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ + +/** + * \brief The generic cipher update function. It encrypts or + * decrypts using the given cipher context. Writes as + * many block-sized blocks of data as possible to output. + * Any data that cannot be written immediately is either + * added to the next block, or flushed when + * mbedtls_cipher_finish() or mbedtls_cipher_finish_padded() + * is called. + * Exception: For MBEDTLS_MODE_ECB, expects a single block + * in size. For example, 16 Bytes for AES. + * + * \param ctx The generic cipher context. This must be initialized and + * bound to a key. + * \param input The buffer holding the input data. This must be a + * readable buffer of at least \p ilen Bytes. + * \param ilen The length of the input data. + * \param output The buffer for the output data. This must be able to + * hold at least `ilen + block_size`. This must not be the + * same buffer as \p input. + * \param olen The length of the output data, to be updated with the + * actual number of Bytes written. This must not be + * \c NULL. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE on an + * unsupported mode for a cipher. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_update(mbedtls_cipher_context_t *ctx, + const unsigned char *input, + size_t ilen, unsigned char *output, + size_t *olen); + +/** + * \brief The generic cipher finalization function. If data still + * needs to be flushed from an incomplete block, the data + * contained in it is padded to the size of + * the last block, and written to the \p output buffer. + * + * \warning This function reports invalid padding through an error + * code. Adversaries may be able to decrypt encrypted + * data if they can submit chosen ciphertexts and + * detect whether it has valid padding or not, + * either through direct observation or through a side + * channel such as timing. This is known as a + * padding oracle attack. + * Therefore applications that call this function for + * decryption with a cipher that involves padding + * should take care around error handling. Preferably, + * such applications should use + * mbedtls_cipher_finish_padded() instead of this function. + * + * \param ctx The generic cipher context. This must be initialized and + * bound to a key. + * \param output The buffer to write data to. This needs to be a writable + * buffer of at least block_size Bytes. + * \param olen The length of the data written to the \p output buffer. + * This may not be \c NULL. + * Note that when decrypting in a mode with padding, + * the actual output length is sensitive and may be + * used to mount a padding oracle attack (see warning + * above), although less efficiently than through + * the invalid-padding condition. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED on decryption + * expecting a full block but not receiving one. + * \return #MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding + * while decrypting. Note that invalid-padding errors + * should be handled carefully; see the warning above. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx, + unsigned char *output, size_t *olen); + +/** + * \brief The generic cipher finalization function. If data still + * needs to be flushed from an incomplete block, the data + * contained in it is padded to the size of + * the last block, and written to the \p output buffer. + * + * \note This function is similar to mbedtls_cipher_finish(). + * The only difference is that it reports invalid padding + * decryption differently, through the \p invalid_padding + * parameter rather than an error code. + * For encryption, and in modes without padding (including + * all authenticated modes), this function is identical + * to mbedtls_cipher_finish(). + * + * \param[in,out] ctx The generic cipher context. This must be initialized and + * bound to a key. + * \param[out] output The buffer to write data to. This needs to be a writable + * buffer of at least block_size Bytes. + * \param[out] olen The length of the data written to the \p output buffer. + * This may not be \c NULL. + * Note that when decrypting in a mode with padding, + * the actual output length is sensitive and may be + * used to mount a padding oracle attack (see warning + * on mbedtls_cipher_finish()). + * \param[out] invalid_padding + * If this function returns \c 0 on decryption, + * \p *invalid_padding is \c 0 if the ciphertext was + * valid, and all-bits-one if the ciphertext had invalid + * padding. + * On encryption, or in a mode without padding (including + * all authenticated modes), \p *invalid_padding is \c 0 + * on success. + * The value in \p *invalid_padding is unspecified if + * this function returns a nonzero status. + * + * \return \c 0 on success. + * Also \c 0 for decryption with invalid padding. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED on decryption + * expecting a full block but not receiving one. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_finish_padded(mbedtls_cipher_context_t *ctx, + unsigned char *output, size_t *olen, + size_t *invalid_padding); + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +/** + * \brief This function writes a tag for AEAD ciphers. + * Currently supported with GCM and ChaCha20+Poly1305. + * This must be called after mbedtls_cipher_finish() + * or mbedtls_cipher_finish_padded(). + * + * \param ctx The generic cipher context. This must be initialized, + * bound to a key, and have just completed a cipher + * operation through mbedtls_cipher_finish() the tag for + * which should be written. + * \param tag The buffer to write the tag to. This must be a writable + * buffer of at least \p tag_len Bytes. + * \param tag_len The length of the tag to write. + * + * \return \c 0 on success. + * \return A specific error code on failure. + */ +int mbedtls_cipher_write_tag(mbedtls_cipher_context_t *ctx, + unsigned char *tag, size_t tag_len); + +/** + * \brief This function checks the tag for AEAD ciphers. + * Currently supported with GCM and ChaCha20+Poly1305. + * This must be called after mbedtls_cipher_finish() + * or mbedtls_cipher_finish_padded(). + * + * \param ctx The generic cipher context. This must be initialized. + * \param tag The buffer holding the tag. This must be a readable + * buffer of at least \p tag_len Bytes. + * \param tag_len The length of the tag to check. + * + * \return \c 0 on success. + * \return A specific error code on failure. + */ +int mbedtls_cipher_check_tag(mbedtls_cipher_context_t *ctx, + const unsigned char *tag, size_t tag_len); +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ + +/** + * \brief The generic all-in-one encryption/decryption function, + * for all ciphers except AEAD constructs. + * + * \param ctx The generic cipher context. This must be initialized. + * \param iv The IV to use, or NONCE_COUNTER for CTR-mode ciphers. + * This must be a readable buffer of at least \p iv_len + * Bytes. + * \param iv_len The IV length for ciphers with variable-size IV. + * This parameter is discarded by ciphers with fixed-size + * IV. + * \param input The buffer holding the input data. This must be a + * readable buffer of at least \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * \param output The buffer for the output data. This must be able to + * hold at least `ilen + block_size`. This must not be the + * same buffer as \p input. + * \param olen The length of the output data, to be updated with the + * actual number of Bytes written. This must not be + * \c NULL. + * + * \note Some ciphers do not use IVs nor nonce. For these + * ciphers, use \p iv = NULL and \p iv_len = 0. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED on decryption + * expecting a full block but not receiving one. + * \return #MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding + * while decrypting. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_crypt(mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen); + +#if defined(MBEDTLS_CIPHER_MODE_AEAD) +/** + * \brief The authenticated encryption (AEAD) function. + * + * \note For AEAD modes, the tag will be appended to the + * ciphertext, as recommended by RFC 5116. + * + * \param ctx The generic cipher context. This must be initialized and + * bound to a key, with an AEAD algorithm. + * \param iv The nonce to use. This must be a readable buffer of + * at least \p iv_len Bytes and may be \c NULL if \p + * iv_len is \c 0. + * \param iv_len The length of the nonce. For AEAD ciphers, this must + * satisfy the constraints imposed by the cipher used. + * \param ad The additional data to authenticate. This must be a + * readable buffer of at least \p ad_len Bytes, and may + * be \c NULL is \p ad_len is \c 0. + * \param ad_len The length of \p ad + * \param input The buffer holding the input data. This must be a + * readable buffer of at least \p ilen Bytes, and may be + * \c NULL if \p ilen is \c 0. + * \param ilen The length of the input data. + * \param output The buffer for the output data. This must be a + * writable buffer of at least \p output_len Bytes, and + * must not be \c NULL. + * \param output_len The length of the \p output buffer in Bytes. For AEAD + * ciphers, this must be at least \p ilen + \p tag_len. + * (rounded up to a multiple of 8 if KWP is used); + * \p ilen + 15 is always a safe value. + * \param olen This will be filled with the actual number of Bytes + * written to the \p output buffer. This must point to a + * writable object of type \c size_t. + * \param tag_len The desired length of the authentication tag. For AEAD + * ciphers, this must match the constraints imposed by + * the cipher used, and in particular must not be \c 0. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_auth_encrypt_ext(mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t output_len, + size_t *olen, size_t tag_len); + +/** + * \brief The authenticated encryption (AEAD) function. + * + * \note If the data is not authentic, then the output buffer + * is zeroed out to prevent the unauthentic plaintext being + * used, making this interface safer. + * + * \note For AEAD modes, the tag must be appended to the + * ciphertext, as recommended by RFC 5116. + * + * \param ctx The generic cipher context. This must be initialized and + * bound to a key, with an AEAD algorithm. + * \param iv The nonce to use. This must be a readable buffer of + * at least \p iv_len Bytes and may be \c NULL if \p + * iv_len is \c 0. + * \param iv_len The length of the nonce. For AEAD ciphers, this must + * satisfy the constraints imposed by the cipher used. + * \param ad The additional data to authenticate. This must be a + * readable buffer of at least \p ad_len Bytes, and may + * be \c NULL is \p ad_len is \c 0. + * \param ad_len The length of \p ad. + * \param input The buffer holding the input data. This must be a + * readable buffer of at least \p ilen Bytes, and may be + * \c NULL if \p ilen is \c 0. + * \param ilen The length of the input data. For AEAD ciphers this + * must be at least \p tag_len. + * \param output The buffer for the output data. This must be a + * writable buffer of at least \p output_len Bytes, and + * may be \c NULL if \p output_len is \c 0. + * \param output_len The length of the \p output buffer in Bytes. For AEAD + * ciphers, this must be at least \p ilen - \p tag_len. + * \param olen This will be filled with the actual number of Bytes + * written to the \p output buffer. This must point to a + * writable object of type \c size_t. + * \param tag_len The actual length of the authentication tag. For AEAD + * ciphers, this must match the constraints imposed by + * the cipher used, and in particular must not be \c 0. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_AUTH_FAILED if data is not authentic. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_auth_decrypt_ext(mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t output_len, + size_t *olen, size_t tag_len); +#endif /* MBEDTLS_CIPHER_MODE_AEAD */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CIPHER_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/cmac.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/cmac.h new file mode 100644 index 0000000000..ecaf926374 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/cmac.h @@ -0,0 +1,209 @@ +/** + * \file cmac.h + * + * \brief This file contains CMAC definitions and functions. + * + * The Cipher-based Message Authentication Code (CMAC) Mode for + * Authentication is defined in RFC-4493: The AES-CMAC Algorithm. + * It is supported with AES and DES. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CMAC_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CMAC_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +#include "mbedtls/private/cipher.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +#define MBEDTLS_AES_BLOCK_SIZE 16 +#define MBEDTLS_DES3_BLOCK_SIZE 8 + +/* We don't support Camellia or ARIA in this module */ +#if defined(MBEDTLS_AES_C) +#define MBEDTLS_CMAC_MAX_BLOCK_SIZE 16 /**< The longest block used by CMAC is that of AES. */ +#else +#define MBEDTLS_CMAC_MAX_BLOCK_SIZE 8 /**< The longest block used by CMAC is that of 3DES. */ +#endif /* MBEDTLS_AES_C */ +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * The CMAC context structure. + */ +struct mbedtls_cmac_context_t { + /** The internal state of the CMAC algorithm. */ + unsigned char MBEDTLS_PRIVATE(state)[MBEDTLS_CMAC_MAX_BLOCK_SIZE]; + + /** Unprocessed data - either data that was not block aligned and is still + * pending processing, or the final block. */ + unsigned char MBEDTLS_PRIVATE(unprocessed_block)[MBEDTLS_CMAC_MAX_BLOCK_SIZE]; + + /** The length of data pending processing. */ + size_t MBEDTLS_PRIVATE(unprocessed_len); +}; + +/** + * \brief This function starts a new CMAC computation + * by setting the CMAC key, and preparing to authenticate + * the input data. + * It must be called with an initialized cipher context. + * + * Once this function has completed, data can be supplied + * to the CMAC computation by calling + * mbedtls_cipher_cmac_update(). + * + * To start a CMAC computation using the same key as a previous + * CMAC computation, use mbedtls_cipher_cmac_finish(). + * + * \param ctx The cipher context used for the CMAC operation, initialized + * as one of the following types: MBEDTLS_CIPHER_AES_128_ECB, + * MBEDTLS_CIPHER_AES_192_ECB or MBEDTLS_CIPHER_AES_256_ECB. + * \param key The CMAC key. + * \param keybits The length of the CMAC key in bits. + * Must be supported by the cipher. + * + * \return \c 0 on success. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_cmac_starts(mbedtls_cipher_context_t *ctx, + const unsigned char *key, size_t keybits); + +/** + * \brief This function feeds an input buffer into an ongoing CMAC + * computation. + * + * The CMAC computation must have previously been started + * by calling mbedtls_cipher_cmac_starts() or + * mbedtls_cipher_cmac_reset(). + * + * Call this function as many times as needed to input the + * data to be authenticated. + * Once all of the required data has been input, + * call mbedtls_cipher_cmac_finish() to obtain the result + * of the CMAC operation. + * + * \param ctx The cipher context used for the CMAC operation. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA + * if parameter verification fails. + */ +int mbedtls_cipher_cmac_update(mbedtls_cipher_context_t *ctx, + const unsigned char *input, size_t ilen); + +/** + * \brief This function finishes an ongoing CMAC operation, and + * writes the result to the output buffer. + * + * It should be followed either by + * mbedtls_cipher_cmac_reset(), which starts another CMAC + * operation with the same key, or mbedtls_cipher_free(), + * which clears the cipher context. + * + * \param ctx The cipher context used for the CMAC operation. + * \param output The output buffer for the CMAC checksum result. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA + * if parameter verification fails. + */ +int mbedtls_cipher_cmac_finish(mbedtls_cipher_context_t *ctx, + unsigned char *output); + +/** + * \brief This function starts a new CMAC operation with the same + * key as the previous one. + * + * It should be called after finishing the previous CMAC + * operation with mbedtls_cipher_cmac_finish(). + * After calling this function, + * call mbedtls_cipher_cmac_update() to supply the new + * CMAC operation with data. + * + * \param ctx The cipher context used for the CMAC operation. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA + * if parameter verification fails. + */ +int mbedtls_cipher_cmac_reset(mbedtls_cipher_context_t *ctx); + +/** + * \brief This function calculates the full generic CMAC + * on the input buffer with the provided key. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The CMAC result is calculated as + * output = generic CMAC(cmac key, input buffer). + * + * \param cipher_info The cipher information. + * \param key The CMAC key. + * \param keylen The length of the CMAC key in bits. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * \param output The buffer for the generic CMAC result. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA + * if parameter verification fails. + */ +int mbedtls_cipher_cmac(const mbedtls_cipher_info_t *cipher_info, + const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output); + +#if defined(MBEDTLS_AES_C) +/** + * \brief This function implements the AES-CMAC-PRF-128 pseudorandom + * function, as defined in + * RFC-4615: The Advanced Encryption Standard-Cipher-based + * Message Authentication Code-Pseudo-Random Function-128 + * (AES-CMAC-PRF-128) Algorithm for the Internet Key + * Exchange Protocol (IKE). + * + * \param key The key to use. + * \param key_len The key length in Bytes. + * \param input The buffer holding the input data. + * \param in_len The length of the input data in Bytes. + * \param output The buffer holding the generated 16 Bytes of + * pseudorandom output. + * + * \return \c 0 on success. + */ +int mbedtls_aes_cmac_prf_128(const unsigned char *key, size_t key_len, + const unsigned char *input, size_t in_len, + unsigned char output[16]); +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +/** + * \brief The CMAC checkup routine. + * + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_cmac_self_test(int verbose); +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C*/ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CMAC_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/config_adjust_test_accelerators.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/config_adjust_test_accelerators.h new file mode 100644 index 0000000000..7e1f4bc310 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/config_adjust_test_accelerators.h @@ -0,0 +1,111 @@ +/** + * \file mbedtls/config_adjust_test_accelerators.h + * \brief Declare the transparent test drivers as accelerators + * + * This is an internal header for test purposes only. Do not include it directly. + * + * The purpose of this header is to keep executing as long as necessary some + * driver-only related unit test cases when running the test_psa_crypto_drivers + * all.sh component (namely test cases in test_suite_block_cipher and + * test_suite_md.psa). It is expected that as the 4.x work progress these test + * cases will not be necessary anymore and: + * . test_psa_crypto_drivers scope is restricted to running the + * test_suite_psa_crypto_driver_wrappers test suite: test of the dispatch to + * drivers and fallbacks. + * . this file can be removed. + * + * This header is used as part of a build containing all the built-in drivers + * and all the transparent test drivers as wrappers around the built-in + * drivers. All the built-in drivers and the transparent test drivers are + * included in the build by starting from a full configuration (config.py full) + * and defining PSA_CRYPTO_DRIVER_TEST when building + * (make CFLAGS="-DPSA_CRYPTO_DRIVER_TEST ..."). + * + * The purpose of this header is to declare the transparent test drivers as + * accelerators just after infering the built-in drivers + * (crypto_adjust_config_enable_builtins.h). Not before the inclusion of + * crypto_adjust_config_enable_builtins.h in the build_info.h sequence of header + * inclusions as this would remove the built-in drivers. Just after to set up + * properly the internal macros introduced as part of the driver only work + * (mainly if not only in crypto_adjust_config_tweak_builtins.h). + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CONFIG_ADJUST_TEST_ACCELERATORS_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CONFIG_ADJUST_TEST_ACCELERATORS_H + +/* Declare the accelerator driver for all cryptographic mechanisms for which + * the test driver is implemented. This is copied from psa/crypto_config.h + * with the parts not implemented by the test driver commented out. */ +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_DERIVE //no-check-names +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_PASSWORD //no-check-names +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_PASSWORD_HASH //no-check-names +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_HMAC //no-check-names +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_AES +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_ARIA +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_CAMELLIA +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_CHACHA20 +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_PUBLIC_KEY +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_BASIC +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_IMPORT +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_EXPORT +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_GENERATE +//#define MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_DERIVE +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_PUBLIC_KEY +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_BASIC +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_IMPORT +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_EXPORT +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_GENERATE +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_RAW_DATA //no-check-names +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR_BASIC +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR_IMPORT +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR_EXPORT +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR_GENERATE +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_PUBLIC_KEY + +#define MBEDTLS_PSA_ACCEL_ALG_CBC_NO_PADDING +#define MBEDTLS_PSA_ACCEL_ALG_CBC_PKCS7 +#define MBEDTLS_PSA_ACCEL_ALG_CCM +#define MBEDTLS_PSA_ACCEL_ALG_CCM_STAR_NO_TAG +#define MBEDTLS_PSA_ACCEL_ALG_CMAC +#define MBEDTLS_PSA_ACCEL_ALG_CFB +#define MBEDTLS_PSA_ACCEL_ALG_CHACHA20_POLY1305 +#define MBEDTLS_PSA_ACCEL_ALG_CTR +#define MBEDTLS_PSA_ACCEL_ALG_DETERMINISTIC_ECDSA +#define MBEDTLS_PSA_ACCEL_ALG_ECB_NO_PADDING +#define MBEDTLS_PSA_ACCEL_ALG_ECDH +#define MBEDTLS_PSA_ACCEL_ALG_FFDH +#define MBEDTLS_PSA_ACCEL_ALG_ECDSA +#define MBEDTLS_PSA_ACCEL_ALG_JPAKE +#define MBEDTLS_PSA_ACCEL_ALG_GCM +//#define MBEDTLS_PSA_ACCEL_ALG_HKDF +//#define MBEDTLS_PSA_ACCEL_ALG_HKDF_EXTRACT +//#define MBEDTLS_PSA_ACCEL_ALG_HKDF_EXPAND +#define MBEDTLS_PSA_ACCEL_ALG_HMAC +#define MBEDTLS_PSA_ACCEL_ALG_MD5 +#define MBEDTLS_PSA_ACCEL_ALG_OFB +//#define MBEDTLS_PSA_ACCEL_ALG_PBKDF2_HMAC +//#define MBEDTLS_PSA_ACCEL_ALG_PBKDF2_AES_CMAC_PRF_128 +#define MBEDTLS_PSA_ACCEL_ALG_RIPEMD160 +#define MBEDTLS_PSA_ACCEL_ALG_RSA_OAEP +#define MBEDTLS_PSA_ACCEL_ALG_RSA_PKCS1V15_CRYPT +#define MBEDTLS_PSA_ACCEL_ALG_RSA_PKCS1V15_SIGN +#define MBEDTLS_PSA_ACCEL_ALG_RSA_PSS +#define MBEDTLS_PSA_ACCEL_ALG_SHA_1 +#define MBEDTLS_PSA_ACCEL_ALG_SHA_224 +#define MBEDTLS_PSA_ACCEL_ALG_SHA_256 +#define MBEDTLS_PSA_ACCEL_ALG_SHA_384 +#define MBEDTLS_PSA_ACCEL_ALG_SHA_512 +#define MBEDTLS_PSA_ACCEL_ALG_SHA3_224 +#define MBEDTLS_PSA_ACCEL_ALG_SHA3_256 +#define MBEDTLS_PSA_ACCEL_ALG_SHA3_384 +#define MBEDTLS_PSA_ACCEL_ALG_SHA3_512 +#define MBEDTLS_PSA_ACCEL_ALG_STREAM_CIPHER +//#define MBEDTLS_PSA_ACCEL_ALG_TLS12_PRF +//#define MBEDTLS_PSA_ACCEL_ALG_TLS12_PSK_TO_MS +//#define MBEDTLS_PSA_ACCEL_ALG_TLS12_ECJPAKE_TO_PMS + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CONFIG_ADJUST_TEST_ACCELERATORS_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/crypto_adjust_config_enable_builtins.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/crypto_adjust_config_enable_builtins.h new file mode 100644 index 0000000000..54792d3247 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/crypto_adjust_config_enable_builtins.h @@ -0,0 +1,820 @@ +/** + * \file mbedtls/private/crypto_adjust_config_enable_builtins.h + * \brief Adjust PSA configuration: activate built-in implementations + * + * This is an internal header. Do not include it directly. + * + * Activate built-in implementations of cryptographic mechanisms as needed to + * fulfill the needs of the PSA configuration. Generally speaking, we activate + * a built-in mechanism if it's needed for a requested PSA mechanism and there + * is no PSA driver for it. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_ADJUST_CONFIG_ENABLE_BUILTINS_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_ADJUST_CONFIG_ENABLE_BUILTINS_H + +/* Define appropriate ACCEL macros for the p256-m driver. + * In the future, those should be generated from the drivers JSON description. + */ +#if defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED) +#define MBEDTLS_PSA_ACCEL_ECC_SECP_R1_256 +#define MBEDTLS_PSA_ACCEL_ALG_ECDSA +#define MBEDTLS_PSA_ACCEL_ALG_ECDH +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_PUBLIC_KEY +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_BASIC +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_IMPORT +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_EXPORT +#define MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_GENERATE +#endif + +/* + * ECC: support for a feature is controlled by a triplet or a pair: + * (curve, key_type public/basic, alg) or (curve, key_type_). + * + * A triplet/pair is accelerated if all of is components are accelerated; + * otherwise each component needs to be built in. + * + * We proceed in two passes: + * 1. Check if acceleration is complete for curves, key types, algs. + * 2. Then enable built-ins for each thing that's either not accelerated of + * doesn't have complete acceleration of the other triplet/pair components. + * + * Note: this needs psa/crypto_adjust_keypair_types.h to have been included + * already, so that we know the full set of key types that are requested. + */ + +/* ECC: curves: is acceleration complete? */ +#if (defined(PSA_WANT_ECC_BRAINPOOL_P_R1_256) && \ + !defined(MBEDTLS_PSA_ACCEL_ECC_BRAINPOOL_P_R1_256)) || \ + (defined(PSA_WANT_ECC_BRAINPOOL_P_R1_384) && \ + !defined(MBEDTLS_PSA_ACCEL_ECC_BRAINPOOL_P_R1_384)) || \ + (defined(PSA_WANT_ECC_BRAINPOOL_P_R1_512) && \ + !defined(MBEDTLS_PSA_ACCEL_ECC_BRAINPOOL_P_R1_512)) || \ + (defined(PSA_WANT_ECC_SECP_R1_256) && !defined(MBEDTLS_PSA_ACCEL_ECC_SECP_R1_256)) || \ + (defined(PSA_WANT_ECC_SECP_R1_384) && !defined(MBEDTLS_PSA_ACCEL_ECC_SECP_R1_384)) || \ + (defined(PSA_WANT_ECC_SECP_R1_521) && !defined(MBEDTLS_PSA_ACCEL_ECC_SECP_R1_521)) || \ + (defined(PSA_WANT_ECC_SECP_K1_256) && !defined(MBEDTLS_PSA_ACCEL_ECC_SECP_K1_256)) +#define MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_CURVES +#define MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_WEIERSTRASS_CURVES +#endif + +#if (defined(PSA_WANT_ECC_MONTGOMERY_255) && !defined(MBEDTLS_PSA_ACCEL_ECC_MONTGOMERY_255)) || \ + (defined(PSA_WANT_ECC_MONTGOMERY_448) && !defined(MBEDTLS_PSA_ACCEL_ECC_MONTGOMERY_448)) +#define MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_CURVES +#endif + +/* ECC: algs: is acceleration complete? */ +#if (defined(PSA_WANT_ALG_ECDH) && !defined(MBEDTLS_PSA_ACCEL_ALG_ECDH)) || \ + (defined(PSA_WANT_ALG_ECDSA) && !defined(MBEDTLS_PSA_ACCEL_ALG_ECDSA)) || \ + (defined(PSA_WANT_ALG_DETERMINISTIC_ECDSA) && \ + !defined(MBEDTLS_PSA_ACCEL_ALG_DETERMINISTIC_ECDSA)) || \ + (defined(PSA_WANT_ALG_JPAKE) && !defined(MBEDTLS_PSA_ACCEL_ALG_JPAKE)) +#define MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_ALGS +#endif + +/* ECC: key types: is acceleration complete? */ +#if (defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) && \ + !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_PUBLIC_KEY)) || \ + (defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC) && \ + !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_BASIC)) +#define MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES_BASIC +#endif + +/* Note: the condition about key derivation is always true as DERIVE can't be + * accelerated yet */ +#if (defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) && \ + !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_PUBLIC_KEY)) || \ + (defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC) && \ + !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_BASIC)) || \ + (defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT) && \ + !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_IMPORT)) || \ + (defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT) && \ + !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_EXPORT)) || \ + (defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE) && \ + !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_GENERATE)) || \ + (defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE) && \ + !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_DERIVE)) +#define MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES +#endif + +/* ECC: curves: enable built-ins as needed. + * + * We need the curve built-in: + * - if it's not accelerated, or + * - if there's a key type with missing acceleration, or + * - if there's a alg with missing acceleration. + */ +#if defined(PSA_WANT_ECC_BRAINPOOL_P_R1_256) +#if !defined(MBEDTLS_PSA_ACCEL_ECC_BRAINPOOL_P_R1_256) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_ALGS) +#define MBEDTLS_PSA_BUILTIN_ECC_BRAINPOOL_P_R1_256 1 +#define MBEDTLS_ECP_DP_BP256R1_ENABLED +#endif /* missing accel */ +#endif /* PSA_WANT_ECC_BRAINPOOL_P_R1_256 */ + +#if defined(PSA_WANT_ECC_BRAINPOOL_P_R1_384) +#if !defined(MBEDTLS_PSA_ACCEL_ECC_BRAINPOOL_P_R1_384) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_ALGS) +#define MBEDTLS_PSA_BUILTIN_ECC_BRAINPOOL_P_R1_384 1 +#define MBEDTLS_ECP_DP_BP384R1_ENABLED +#endif /* missing accel */ +#endif /* PSA_WANT_ECC_BRAINPOOL_P_R1_384 */ + +#if defined(PSA_WANT_ECC_BRAINPOOL_P_R1_512) +#if !defined(MBEDTLS_PSA_ACCEL_ECC_BRAINPOOL_P_R1_512) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_ALGS) +#define MBEDTLS_PSA_BUILTIN_ECC_BRAINPOOL_P_R1_512 1 +#define MBEDTLS_ECP_DP_BP512R1_ENABLED +#endif /* missing accel */ +#endif /* PSA_WANT_ECC_BRAINPOOL_P_R1_512 */ + +#if defined(PSA_WANT_ECC_MONTGOMERY_255) +#if !defined(MBEDTLS_PSA_ACCEL_ECC_MONTGOMERY_255) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_ALGS) +#define MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_255 1 +#define MBEDTLS_ECP_DP_CURVE25519_ENABLED +#endif /* missing accel */ +#endif /* PSA_WANT_ECC_MONTGOMERY_255 */ + +#if defined(PSA_WANT_ECC_MONTGOMERY_448) +#if !defined(MBEDTLS_PSA_ACCEL_ECC_MONTGOMERY_448) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_ALGS) +#define MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_448 1 +#define MBEDTLS_ECP_DP_CURVE448_ENABLED +#endif /* missing accel */ +#endif /* PSA_WANT_ECC_MONTGOMERY_448 */ + +#if defined(PSA_WANT_ECC_SECP_R1_256) +#if !defined(MBEDTLS_PSA_ACCEL_ECC_SECP_R1_256) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_ALGS) +#define MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_256 1 +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#endif /* missing accel */ +#endif /* PSA_WANT_ECC_SECP_R1_256 */ + +#if defined(PSA_WANT_ECC_SECP_R1_384) +#if !defined(MBEDTLS_PSA_ACCEL_ECC_SECP_R1_384) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_ALGS) +#define MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_384 1 +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +#endif /* missing accel */ +#endif /* PSA_WANT_ECC_SECP_R1_384 */ + +#if defined(PSA_WANT_ECC_SECP_R1_521) +#if !defined(MBEDTLS_PSA_ACCEL_ECC_SECP_R1_521) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_ALGS) +#define MBEDTLS_PSA_BUILTIN_ECC_SECP_R1_521 1 +#define MBEDTLS_ECP_DP_SECP521R1_ENABLED +#endif /* missing accel */ +#endif /* PSA_WANT_ECC_SECP_R1_521 */ + +#if defined(PSA_WANT_ECC_SECP_K1_256) +#if !defined(MBEDTLS_PSA_ACCEL_ECC_SECP_K1_256) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_ALGS) +#define MBEDTLS_PSA_BUILTIN_ECC_SECP_K1_256 1 +#define MBEDTLS_ECP_DP_SECP256K1_ENABLED +#endif /* missing accel */ +#endif /* PSA_WANT_ECC_SECP_K1_256 */ + +/* ECC: algs: enable built-ins as needed. + * + * We need the alg built-in: + * - if it's not accelerated, or + * - if there's a relevant curve (see below) with missing acceleration, or + * - if there's a key type among (public, basic) with missing acceleration. + * + * Relevant curves are: + * - all curves for ECDH + * - Weierstrass curves for (deterministic) ECDSA + * - secp256r1 for EC J-PAKE + */ +#if defined(PSA_WANT_ALG_DETERMINISTIC_ECDSA) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_DETERMINISTIC_ECDSA) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_WEIERSTRASS_CURVES) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES_BASIC) +#define MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA 1 +#define MBEDTLS_ECDSA_DETERMINISTIC +#define MBEDTLS_HMAC_DRBG_C +#define MBEDTLS_MD_C +#define MBEDTLS_ECDSA_C +#define MBEDTLS_ECP_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#endif /* missing accel */ +#endif /* PSA_WANT_ALG_DETERMINISTIC_ECDSA */ + +#if defined(PSA_WANT_ALG_ECDH) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_ECDH) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_CURVES) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES_BASIC) +#define MBEDTLS_PSA_BUILTIN_ALG_ECDH 1 +#define MBEDTLS_ECP_C +#define MBEDTLS_BIGNUM_C +#endif /* missing accel */ +#endif /* PSA_WANT_ALG_ECDH */ + +#if defined(PSA_WANT_ALG_ECDSA) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_WEIERSTRASS_CURVES) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES_BASIC) +#define MBEDTLS_PSA_BUILTIN_ALG_ECDSA 1 +#define MBEDTLS_ECDSA_C +#define MBEDTLS_ECP_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#endif /* missing accel */ +#endif /* PSA_WANT_ALG_ECDSA */ + +#if defined(PSA_WANT_ALG_JPAKE) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_JPAKE) || \ + !defined(MBEDTLS_PSA_ACCEL_ECC_SECP_R1_256) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_KEY_TYPES_BASIC) +#define MBEDTLS_PSA_BUILTIN_PAKE 1 +#define MBEDTLS_PSA_BUILTIN_ALG_JPAKE 1 +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_ECP_C +#define MBEDTLS_ECJPAKE_C +#endif /* missing accel */ +#endif /* PSA_WANT_ALG_JPAKE */ + +/* ECC: key types: enable built-ins as needed. + * + * We need the key type built-in: + * - if it's not accelerated, or + * - if there's a curve with missing acceleration, or + * - only for public/basic: if there's an alg with missing acceleration. + */ +#if defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_PUBLIC_KEY) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_CURVES) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_ALGS) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY 1 +#endif /* missing accel */ +#endif /* PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY */ + +#if defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_BASIC) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_CURVES) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_ALGS) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 +#endif /* missing accel */ +#endif /* PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC */ + +#if defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_CURVES) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 +#endif /* missing accel */ +#endif /* PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT */ + +#if defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_CURVES) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 +#endif /* missing accel */ +#endif /* PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT */ + +#if defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_GENERATE) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_CURVES) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 +#endif /* missing accel */ +#endif /* PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE */ + +/* Note: the condition is always true as DERIVE can't be accelerated yet */ +#if defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_DERIVE) || \ + defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_CURVES) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_DERIVE 1 +#endif /* missing accel */ +#endif /* !MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_DERIVE */ + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_BASIC) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_DERIVE) +#define MBEDTLS_ECP_LIGHT +#define MBEDTLS_BIGNUM_C +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE) +#define MBEDTLS_ECP_C +#define MBEDTLS_BIGNUM_C +#endif + +/* End of ECC section */ + +/* + * DH key types follow the same pattern used above for EC keys. They are defined + * by a triplet (group, key_type, alg). A triplet is accelerated if all its + * component are accelerated, otherwise each component needs to be builtin. + */ + +/* DH: groups: is acceleration complete? */ +#if (defined(PSA_WANT_DH_RFC7919_2048) && !defined(MBEDTLS_PSA_ACCEL_DH_RFC7919_2048)) || \ + (defined(PSA_WANT_DH_RFC7919_3072) && !defined(MBEDTLS_PSA_ACCEL_DH_RFC7919_3072)) || \ + (defined(PSA_WANT_DH_RFC7919_4096) && !defined(MBEDTLS_PSA_ACCEL_DH_RFC7919_4096)) || \ + (defined(PSA_WANT_DH_RFC7919_6144) && !defined(MBEDTLS_PSA_ACCEL_DH_RFC7919_6144)) || \ + (defined(PSA_WANT_DH_RFC7919_8192) && !defined(MBEDTLS_PSA_ACCEL_DH_RFC7919_8192)) +#define MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_GROUPS +#endif + +/* DH: algs: is acceleration complete? */ +#if defined(PSA_WANT_ALG_FFDH) && !defined(MBEDTLS_PSA_ACCEL_ALG_FFDH) +#define MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_ALGS +#endif + +/* DH: key types: is acceleration complete? */ +#if (defined(PSA_WANT_KEY_TYPE_DH_PUBLIC_KEY) && \ + !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_PUBLIC_KEY)) || \ + (defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC) && \ + !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_BASIC)) || \ + (defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT) && \ + !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_IMPORT)) || \ + (defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_EXPORT) && \ + !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_EXPORT)) || \ + (defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE) && \ + !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_GENERATE)) +#define MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_KEY_TYPES +#endif + +#if defined(PSA_WANT_DH_RFC7919_2048) +#if !defined(MBEDTLS_PSA_ACCEL_DH_RFC7919_2048) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_ALGS) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_KEY_TYPES) +#define MBEDTLS_PSA_BUILTIN_DH_RFC7919_2048 1 +#endif /* !MBEDTLS_PSA_BUILTIN_DH_RFC7919_2048 */ +#endif /* PSA_WANT_DH_RFC7919_2048 */ + +#if defined(PSA_WANT_DH_RFC7919_3072) +#if !defined(MBEDTLS_PSA_ACCEL_DH_RFC7919_3072) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_ALGS) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_KEY_TYPES) +#define MBEDTLS_PSA_BUILTIN_DH_RFC7919_3072 1 +#endif /* !MBEDTLS_PSA_BUILTIN_DH_RFC7919_3072 */ +#endif /* PSA_WANT_DH_RFC7919_3072 */ + +#if defined(PSA_WANT_DH_RFC7919_4096) +#if !defined(MBEDTLS_PSA_ACCEL_DH_RFC7919_4096) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_ALGS) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_KEY_TYPES) +#define MBEDTLS_PSA_BUILTIN_DH_RFC7919_4096 1 +#endif /* !MBEDTLS_PSA_BUILTIN_DH_RFC7919_4096 */ +#endif /* PSA_WANT_DH_RFC7919_4096 */ + +#if defined(PSA_WANT_DH_RFC7919_6144) +#if !defined(MBEDTLS_PSA_ACCEL_DH_RFC7919_6144) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_ALGS) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_KEY_TYPES) +#define MBEDTLS_PSA_BUILTIN_DH_RFC7919_6144 1 +#endif /* !MBEDTLS_PSA_BUILTIN_DH_RFC7919_6144 */ +#endif /* PSA_WANT_DH_RFC7919_6144 */ + +#if defined(PSA_WANT_DH_RFC7919_8192) +#if !defined(MBEDTLS_PSA_ACCEL_DH_RFC7919_8192) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_ALGS) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_KEY_TYPES) +#define MBEDTLS_PSA_BUILTIN_DH_RFC7919_8192 1 +#endif /* !MBEDTLS_PSA_BUILTIN_DH_RFC7919_8192 */ +#endif /* PSA_WANT_DH_RFC7919_8192 */ + +#if defined(PSA_WANT_ALG_FFDH) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_FFDH) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_GROUPS) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_KEY_TYPES) +#define MBEDTLS_PSA_BUILTIN_ALG_FFDH 1 +#define MBEDTLS_BIGNUM_C +#endif /* !MBEDTLS_PSA_ACCEL_ALG_FFDH */ +#endif /* PSA_WANT_ALG_FFDH */ + +#if defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_IMPORT) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_GROUPS) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_ALGS) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_IMPORT 1 +#endif /* !MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_IMPORT */ +#endif /* PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT */ + +#if defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_EXPORT) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_GROUPS) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_ALGS) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_EXPORT 1 +#endif /* !MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_EXPORT */ +#endif /* PSA_WANT_KEY_TYPE_DH_KEY_PAIR_EXPORT */ + +#if defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_GENERATE) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_GENERATE 1 +#endif /* !MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_GENERATE */ +#endif /* PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE */ + +#if defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_BASIC) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_GROUPS) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_ALGS) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_BASIC 1 +#endif /* !MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_BASIC */ +#endif /* PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC */ + +#if defined(PSA_WANT_KEY_TYPE_DH_PUBLIC_KEY) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_PUBLIC_KEY) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_GROUPS) || \ + defined(MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_ALGS) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_PUBLIC_KEY 1 +#define MBEDTLS_BIGNUM_C +#endif /* !MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_PUBLIC_KEY */ +#endif /* PSA_WANT_KEY_TYPE_DH_PUBLIC_KEY */ + +/* End of DH section */ + +#if defined(PSA_WANT_ALG_HKDF) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_HKDF) +#define MBEDTLS_PSA_BUILTIN_ALG_HKDF 1 +#endif /* !MBEDTLS_PSA_ACCEL_ALG_HKDF */ +#endif /* PSA_WANT_ALG_HKDF */ + +#if defined(PSA_WANT_ALG_HKDF_EXTRACT) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_HKDF_EXTRACT) +#define MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT 1 +#endif /* !MBEDTLS_PSA_ACCEL_ALG_HKDF_EXTRACT */ +#endif /* PSA_WANT_ALG_HKDF_EXTRACT */ + +#if defined(PSA_WANT_ALG_HKDF_EXPAND) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_HKDF_EXPAND) +#define MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND 1 +#endif /* !MBEDTLS_PSA_ACCEL_ALG_HKDF_EXPAND */ +#endif /* PSA_WANT_ALG_HKDF_EXPAND */ + +#if defined(PSA_WANT_ALG_HMAC) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_HMAC) +#define MBEDTLS_PSA_BUILTIN_ALG_HMAC 1 +#endif /* !MBEDTLS_PSA_ACCEL_ALG_HMAC */ +#endif /* PSA_WANT_ALG_HMAC */ + +#if defined(PSA_WANT_ALG_MD5) && !defined(MBEDTLS_PSA_ACCEL_ALG_MD5) +#define MBEDTLS_PSA_BUILTIN_ALG_MD5 1 +#define MBEDTLS_MD5_C +#endif + +#if defined(PSA_WANT_ALG_RIPEMD160) && !defined(MBEDTLS_PSA_ACCEL_ALG_RIPEMD160) +#define MBEDTLS_PSA_BUILTIN_ALG_RIPEMD160 1 +#define MBEDTLS_RIPEMD160_C +#endif + +#if defined(PSA_WANT_ALG_RSA_OAEP) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_RSA_OAEP) +#define MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP 1 +#define MBEDTLS_RSA_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_PKCS1_V21 +#endif /* !MBEDTLS_PSA_ACCEL_ALG_RSA_OAEP */ +#endif /* PSA_WANT_ALG_RSA_OAEP */ + +#if defined(PSA_WANT_ALG_RSA_PKCS1V15_CRYPT) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_RSA_PKCS1V15_CRYPT) +#define MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT 1 +#define MBEDTLS_RSA_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_PKCS1_V15 +#endif /* !MBEDTLS_PSA_ACCEL_ALG_RSA_PKCS1V15_CRYPT */ +#endif /* PSA_WANT_ALG_RSA_PKCS1V15_CRYPT */ + +#if defined(PSA_WANT_ALG_RSA_PKCS1V15_SIGN) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_RSA_PKCS1V15_SIGN) +#define MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN 1 +#define MBEDTLS_RSA_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_PKCS1_V15 +#endif /* !MBEDTLS_PSA_ACCEL_ALG_RSA_PKCS1V15_SIGN */ +#endif /* PSA_WANT_ALG_RSA_PKCS1V15_SIGN */ + +#if defined(PSA_WANT_ALG_RSA_PSS) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_RSA_PSS) +#define MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS 1 +#define MBEDTLS_RSA_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_PKCS1_V21 +#endif /* !MBEDTLS_PSA_ACCEL_ALG_RSA_PSS */ +#endif /* PSA_WANT_ALG_RSA_PSS */ + +#if defined(PSA_WANT_ALG_SHA_1) && !defined(MBEDTLS_PSA_ACCEL_ALG_SHA_1) +#define MBEDTLS_PSA_BUILTIN_ALG_SHA_1 1 +#define MBEDTLS_SHA1_C +#endif + +#if defined(PSA_WANT_ALG_SHA_224) && !defined(MBEDTLS_PSA_ACCEL_ALG_SHA_224) +#define MBEDTLS_PSA_BUILTIN_ALG_SHA_224 1 +#define MBEDTLS_SHA224_C +#endif + +#if defined(PSA_WANT_ALG_SHA_256) && !defined(MBEDTLS_PSA_ACCEL_ALG_SHA_256) +#define MBEDTLS_PSA_BUILTIN_ALG_SHA_256 1 +#define MBEDTLS_SHA256_C +#endif + +#if defined(PSA_WANT_ALG_SHA_384) && !defined(MBEDTLS_PSA_ACCEL_ALG_SHA_384) +#define MBEDTLS_PSA_BUILTIN_ALG_SHA_384 1 +#define MBEDTLS_SHA384_C +#endif + +#if defined(PSA_WANT_ALG_SHA_512) && !defined(MBEDTLS_PSA_ACCEL_ALG_SHA_512) +#define MBEDTLS_PSA_BUILTIN_ALG_SHA_512 1 +#define MBEDTLS_SHA512_C +#endif + +#if defined(PSA_WANT_ALG_SHA3_224) && !defined(MBEDTLS_PSA_ACCEL_ALG_SHA3_224) +#define MBEDTLS_PSA_BUILTIN_ALG_SHA3_224 1 +#endif + +#if defined(PSA_WANT_ALG_SHA3_256) && !defined(MBEDTLS_PSA_ACCEL_ALG_SHA3_256) +#define MBEDTLS_PSA_BUILTIN_ALG_SHA3_256 1 +#endif + +#if defined(PSA_WANT_ALG_SHA3_384) && !defined(MBEDTLS_PSA_ACCEL_ALG_SHA3_384) +#define MBEDTLS_PSA_BUILTIN_ALG_SHA3_384 1 +#endif + +#if defined(PSA_WANT_ALG_SHA3_512) && !defined(MBEDTLS_PSA_ACCEL_ALG_SHA3_512) +#define MBEDTLS_PSA_BUILTIN_ALG_SHA3_512 1 +#endif + +#if defined(PSA_WANT_ALG_PBKDF2_HMAC) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_PBKDF2_HMAC) +#define MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC 1 +#define PSA_HAVE_SOFT_PBKDF2_HMAC 1 +#endif /* !MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC */ +#endif /* PSA_WANT_ALG_PBKDF2_HMAC */ + +#if defined(PSA_WANT_ALG_TLS12_PRF) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_TLS12_PRF) +#define MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF 1 +#endif /* !MBEDTLS_PSA_ACCEL_ALG_TLS12_PRF */ +#endif /* PSA_WANT_ALG_TLS12_PRF */ + +#if defined(PSA_WANT_ALG_TLS12_PSK_TO_MS) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_TLS12_PSK_TO_MS) +#define MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS 1 +#endif /* !MBEDTLS_PSA_ACCEL_ALG_TLS12_PSK_TO_MS */ +#endif /* PSA_WANT_ALG_TLS12_PSK_TO_MS */ + +#if defined(PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_TLS12_ECJPAKE_TO_PMS) +#define MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS 1 +#endif /* !MBEDTLS_PSA_ACCEL_ALG_TLS12_ECJPAKE_TO_PMS */ +#endif /* PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS */ + +#if defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR_IMPORT) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_IMPORT 1 +#endif /* !MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR_IMPORT */ +#endif /* PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT */ + +#if defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR_EXPORT) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT 1 +#endif /* !MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR_EXPORT */ +#endif /* PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT */ + +#if defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR_GENERATE) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE 1 +#define MBEDTLS_GENPRIME +#endif /* !MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR_GENERATE */ +#endif /* PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE */ + +#if defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR_BASIC) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_BASIC 1 +#endif /* !MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR_BASIC */ +#endif /* PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC */ + +#if defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_PUBLIC_KEY) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY 1 +#define MBEDTLS_RSA_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#endif /* !MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_PUBLIC_KEY */ +#endif /* PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY */ + +/* If any of the block modes are requested that don't have an + * associated HW assist, define PSA_HAVE_SOFT_BLOCK_MODE for checking + * in the block cipher key types. */ +#if (defined(PSA_WANT_ALG_CTR) && !defined(MBEDTLS_PSA_ACCEL_ALG_CTR)) || \ + (defined(PSA_WANT_ALG_CFB) && !defined(MBEDTLS_PSA_ACCEL_ALG_CFB)) || \ + (defined(PSA_WANT_ALG_OFB) && !defined(MBEDTLS_PSA_ACCEL_ALG_OFB)) || \ + (defined(PSA_WANT_ALG_ECB_NO_PADDING) && !defined(MBEDTLS_PSA_ACCEL_ALG_ECB_NO_PADDING)) || \ + (defined(PSA_WANT_ALG_CBC_NO_PADDING) && !defined(MBEDTLS_PSA_ACCEL_ALG_CBC_NO_PADDING)) || \ + (defined(PSA_WANT_ALG_CBC_PKCS7) && !defined(MBEDTLS_PSA_ACCEL_ALG_CBC_PKCS7)) || \ + (defined(PSA_WANT_ALG_CMAC) && !defined(MBEDTLS_PSA_ACCEL_ALG_CMAC)) +#define PSA_HAVE_SOFT_BLOCK_MODE 1 +#endif + +#if defined(PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_PBKDF2_AES_CMAC_PRF_128) +#define MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_AES_CMAC_PRF_128 1 +#define PSA_HAVE_SOFT_PBKDF2_CMAC 1 +#endif /* !MBEDTLS_PSA_ACCEL_ALG_PBKDF2_AES_CMAC_PRF_128 */ +#endif /* PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 */ + +#if defined(PSA_WANT_KEY_TYPE_AES) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_AES) +#define PSA_HAVE_SOFT_KEY_TYPE_AES 1 +#endif /* !MBEDTLS_PSA_ACCEL_KEY_TYPE_AES */ +#if defined(PSA_HAVE_SOFT_KEY_TYPE_AES) || \ + defined(PSA_HAVE_SOFT_BLOCK_MODE) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_AES 1 +#define MBEDTLS_AES_C +#endif /* PSA_HAVE_SOFT_KEY_TYPE_AES || PSA_HAVE_SOFT_BLOCK_MODE */ +#endif /* PSA_WANT_KEY_TYPE_AES */ + +#if defined(PSA_WANT_KEY_TYPE_ARIA) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ARIA) +#define PSA_HAVE_SOFT_KEY_TYPE_ARIA 1 +#endif /* !MBEDTLS_PSA_ACCEL_KEY_TYPE_ARIA */ +#if defined(PSA_HAVE_SOFT_KEY_TYPE_ARIA) || \ + defined(PSA_HAVE_SOFT_BLOCK_MODE) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_ARIA 1 +#define MBEDTLS_ARIA_C +#endif /* PSA_HAVE_SOFT_KEY_TYPE_ARIA || PSA_HAVE_SOFT_BLOCK_MODE */ +#endif /* PSA_WANT_KEY_TYPE_ARIA */ + +#if defined(PSA_WANT_KEY_TYPE_CAMELLIA) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_CAMELLIA) +#define PSA_HAVE_SOFT_KEY_TYPE_CAMELLIA 1 +#endif /* !MBEDTLS_PSA_ACCEL_KEY_TYPE_CAMELLIA */ +#if defined(PSA_HAVE_SOFT_KEY_TYPE_CAMELLIA) || \ + defined(PSA_HAVE_SOFT_BLOCK_MODE) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_CAMELLIA 1 +#define MBEDTLS_CAMELLIA_C +#endif /* PSA_HAVE_SOFT_KEY_TYPE_CAMELLIA || PSA_HAVE_SOFT_BLOCK_MODE */ +#endif /* PSA_WANT_KEY_TYPE_CAMELLIA */ + +#if defined(PSA_WANT_ALG_STREAM_CIPHER) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_STREAM_CIPHER) +#define MBEDTLS_PSA_BUILTIN_ALG_STREAM_CIPHER 1 +#endif /* MBEDTLS_PSA_ACCEL_ALG_STREAM_CIPHER */ +#endif /* PSA_WANT_ALG_STREAM_CIPHER */ + +#if defined(PSA_WANT_KEY_TYPE_CHACHA20) +#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_CHACHA20) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_STREAM_CIPHER) +#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_CHACHA20 1 +#define MBEDTLS_CHACHA20_C +#endif /*!MBEDTLS_PSA_ACCEL_KEY_TYPE_CHACHA20 */ +#endif /* PSA_WANT_KEY_TYPE_CHACHA20 */ + +/* If any of the software block ciphers are selected, define + * PSA_HAVE_SOFT_BLOCK_CIPHER, which can be used in any of these + * situations. */ +#if defined(PSA_HAVE_SOFT_KEY_TYPE_AES) || \ + defined(PSA_HAVE_SOFT_KEY_TYPE_ARIA) || \ + defined(PSA_HAVE_SOFT_KEY_TYPE_CAMELLIA) +#define PSA_HAVE_SOFT_BLOCK_CIPHER 1 +#endif + +#if defined(PSA_WANT_ALG_CMAC) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_CMAC) || \ + defined(PSA_HAVE_SOFT_BLOCK_CIPHER) +#define MBEDTLS_PSA_BUILTIN_ALG_CMAC 1 +#define MBEDTLS_CMAC_C +#endif /* !MBEDTLS_PSA_ACCEL_ALG_CMAC */ +#endif /* PSA_WANT_ALG_CMAC */ + +#if defined(PSA_HAVE_SOFT_PBKDF2_HMAC) || \ + defined(PSA_HAVE_SOFT_PBKDF2_CMAC) +#define PSA_HAVE_SOFT_PBKDF2 1 +#endif /* PSA_HAVE_SOFT_PBKDF2_HMAC || PSA_HAVE_SOFT_PBKDF2_CMAC */ + +#if defined(PSA_WANT_ALG_CTR) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_CTR) || \ + defined(PSA_HAVE_SOFT_BLOCK_CIPHER) +#define MBEDTLS_PSA_BUILTIN_ALG_CTR 1 +#define MBEDTLS_CIPHER_MODE_CTR +#endif +#endif /* PSA_WANT_ALG_CTR */ + +#if defined(PSA_WANT_ALG_CFB) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_CFB) || \ + defined(PSA_HAVE_SOFT_BLOCK_CIPHER) +#define MBEDTLS_PSA_BUILTIN_ALG_CFB 1 +#define MBEDTLS_CIPHER_MODE_CFB +#endif +#endif /* PSA_WANT_ALG_CFB */ + +#if defined(PSA_WANT_ALG_OFB) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_OFB) || \ + defined(PSA_HAVE_SOFT_BLOCK_CIPHER) +#define MBEDTLS_PSA_BUILTIN_ALG_OFB 1 +#define MBEDTLS_CIPHER_MODE_OFB +#endif +#endif /* PSA_WANT_ALG_OFB */ + +/* Placeholder for future support of XTS through the PSA API. + * For now, this appeases check_names.py by ensuring that + * MBEDTLS_CIPHER_MODE_XTS is defined somewhere, as it would + * otherwise not be defined in any headers. + */ +#if 0 +#if !defined(MBEDTLS_PSA_ACCEL_ALG_XTS) || \ + defined(PSA_HAVE_SOFT_BLOCK_CIPHER) +#define MBEDTLS_PSA_BUILTIN_ALG_XTS 1 +#define MBEDTLS_CIPHER_MODE_XTS +#endif +#endif + +#if defined(PSA_WANT_ALG_ECB_NO_PADDING) && \ + !defined(MBEDTLS_PSA_ACCEL_ALG_ECB_NO_PADDING) +#define MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING 1 +#endif + +#if defined(PSA_WANT_ALG_CBC_NO_PADDING) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_CBC_NO_PADDING) || \ + defined(PSA_HAVE_SOFT_BLOCK_CIPHER) +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_PSA_BUILTIN_ALG_CBC_NO_PADDING 1 +#endif +#endif /* PSA_WANT_ALG_CBC_NO_PADDING */ + +#if defined(PSA_WANT_ALG_CBC_PKCS7) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_CBC_PKCS7) || \ + defined(PSA_HAVE_SOFT_BLOCK_CIPHER) +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_PSA_BUILTIN_ALG_CBC_PKCS7 1 +#define MBEDTLS_CIPHER_PADDING_PKCS7 +#endif +#endif /* PSA_WANT_ALG_CBC_PKCS7 */ + +#if defined(PSA_WANT_ALG_CCM) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_CCM) || \ + defined(PSA_HAVE_SOFT_KEY_TYPE_AES) || \ + defined(PSA_HAVE_SOFT_KEY_TYPE_ARIA) || \ + defined(PSA_HAVE_SOFT_KEY_TYPE_CAMELLIA) +#define MBEDTLS_PSA_BUILTIN_ALG_CCM 1 +#define MBEDTLS_CCM_C +#endif +#endif /* PSA_WANT_ALG_CCM */ + +#if defined(PSA_WANT_ALG_CCM_STAR_NO_TAG) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_CCM_STAR_NO_TAG) || \ + defined(PSA_HAVE_SOFT_KEY_TYPE_AES) || \ + defined(PSA_HAVE_SOFT_KEY_TYPE_ARIA) || \ + defined(PSA_HAVE_SOFT_KEY_TYPE_CAMELLIA) +#define MBEDTLS_PSA_BUILTIN_ALG_CCM_STAR_NO_TAG 1 +#define MBEDTLS_CCM_C +#endif +#endif /* PSA_WANT_ALG_CCM_STAR_NO_TAG */ + +#if defined(PSA_WANT_ALG_GCM) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_GCM) || \ + defined(PSA_HAVE_SOFT_KEY_TYPE_AES) || \ + defined(PSA_HAVE_SOFT_KEY_TYPE_ARIA) || \ + defined(PSA_HAVE_SOFT_KEY_TYPE_CAMELLIA) +#define MBEDTLS_PSA_BUILTIN_ALG_GCM 1 +#define MBEDTLS_GCM_C +#endif +#endif /* PSA_WANT_ALG_GCM */ + +#if defined(PSA_WANT_ALG_CHACHA20_POLY1305) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_CHACHA20_POLY1305) +#if defined(PSA_WANT_KEY_TYPE_CHACHA20) +#define MBEDTLS_CHACHAPOLY_C +#define MBEDTLS_CHACHA20_C +#define MBEDTLS_POLY1305_C +#define MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 1 +#endif /* PSA_WANT_KEY_TYPE_CHACHA20 */ +#endif /* !MBEDTLS_PSA_ACCEL_ALG_CHACHA20_POLY1305 */ +#endif /* PSA_WANT_ALG_CHACHA20_POLY1305 */ + +#if defined(PSA_WANT_ALG_SHAKE128) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_SHAKE128) +#define MBEDTLS_PSA_BUILTIN_ALG_SHAKE128 +#endif /* !MBEDTLS_PSA_ACCEL_ALG_SHAKE128 */ +#endif /* PSA_WANT_ALG_SHAKE128 */ + +#if defined(PSA_WANT_ALG_SHAKE256) +#if !defined(MBEDTLS_PSA_ACCEL_ALG_SHAKE256) +#define MBEDTLS_PSA_BUILTIN_ALG_SHAKE256 +#endif /* !MBEDTLS_PSA_ACCEL_ALG_SHAKE256 */ +#endif /* PSA_WANT_ALG_SHAKE256 */ + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_ADJUST_CONFIG_ENABLE_BUILTINS_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/crypto_adjust_config_tweak_builtins.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/crypto_adjust_config_tweak_builtins.h new file mode 100644 index 0000000000..a7cfff2e3a --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/crypto_adjust_config_tweak_builtins.h @@ -0,0 +1,203 @@ +/** + * \file mbedtls/private/crypto_adjust_config_tweak_builtins.h + * \brief Adjust macros used by legacy built-in crypto modules + * + * This is an internal header. Do not include it directly. + * + * Automatically enable certain parts of the cryptography implementation + * that are required by other parts. Also define some internal symbols + * that are derived from public ones. This file is about individual + * modules that lie below PSA, not about the PSA configuration. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_ADJUST_CONFIG_TWEAK_BUILTINS_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_ADJUST_CONFIG_TWEAK_BUILTINS_H + +/** + * \def MBEDTLS_USE_PSA_CRYPTO + * + * Make the X.509 and TLS libraries use PSA for cryptographic operations as + * much as possible, and enable new APIs for using keys handled by PSA Crypto. + * + * \note This is a legacy symbol which still exists for backward compatibility. + * Up to Mbed TLS 3.x, it was not enabled by default. Now it is always + * enabled, and it will eventually disappear from the code base. This + * is not part of the public API of TF-PSA-Crypto or of Mbed TLS >=4.0. + */ +#define MBEDTLS_USE_PSA_CRYPTO + +/* Whether any hash based on sha3 is enabled in psa_crypto_hash.c. */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512) +#define MBEDTLS_PSA_BUILTIN_ALG_SHA3_SOME_HASH +#endif + +/* Whether any XOF based on sha3 is enabled in psa_crypto_xof.c. */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHAKE128) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_SHAKE256) +#define MBEDTLS_PSA_BUILTIN_ALG_SOME_SHAKE +#endif + +/* If a SHAKE variant is enabled in psa_crypto_xof.c, tell sha3.c that we + * want it. + * + * Note that the PSA API (following NIST standards) defines hash algorithms + * that are SHAKE128 or SHAKE256 with a specific output lengths. From the + * perspective of sha3.c, these are just users of SHAKE128/SHAKE256, but + * from the perspective of psa_crypto_hash.c and psa_crypto_xof.c, + * they are hashes and not XOF. So, for example, if the SHAKE256/512 hash + * algorithm is enabled in the PSA API (for Ed448ph) but the SHAKE256 XOF + * algorithm is disabled, then MBEDTLS_PSA_BUILTIN_ALG_SHAKE256 will be + * disabled but we'll still need to enable MBEDTLS_SHA3_WANT_SHAKE256. + */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHAKE128) +#define MBEDTLS_SHA3_WANT_SHAKE128 +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHAKE256) +#define MBEDTLS_SHA3_WANT_SHAKE256 +#endif + +/* Whether any Keccak variant is enabled, i.e. the bulk of sha3.c. */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_SOME_HASH) || \ + defined(MBEDTLS_SHA3_WANT_SHAKE128) || defined(MBEDTLS_SHA3_WANT_SHAKE256) +#define MBEDTLS_SHA3_C +#endif + +/* Auto-enable CIPHER_C when any of the unauthenticated ciphers is builtin + * in PSA. */ +#if defined(MBEDTLS_PSA_CRYPTO_C) && \ + (defined(MBEDTLS_PSA_BUILTIN_ALG_STREAM_CIPHER) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_CTR) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_CFB) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_OFB) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_NO_PADDING) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_PKCS7) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_CCM_STAR_NO_TAG) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC)) +#define MBEDTLS_CIPHER_C +#endif + +/* BLOCK_CIPHER module can dispatch to PSA when: + * - PSA is enabled and drivers have been initialized + * - desired key type is supported on the PSA side + * If the above conditions are not met, but the legacy support is enabled, then + * BLOCK_CIPHER will dynamically fallback to it. + * + * In case BLOCK_CIPHER is defined (see below) the following symbols/helpers + * can be used to define its capabilities: + * - MBEDTLS_BLOCK_CIPHER_SOME_PSA: there is at least 1 key type between AES, + * ARIA and Camellia which is supported through a driver; + * - MBEDTLS_BLOCK_CIPHER_xxx_VIA_PSA: xxx key type is supported through a + * driver; + * - MBEDTLS_BLOCK_CIPHER_xxx_VIA_LEGACY: xxx key type is supported through + * a legacy module (i.e. MBEDTLS_xxx_C) + */ +#if defined(MBEDTLS_PSA_CRYPTO_C) +#if defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_AES) +#define MBEDTLS_BLOCK_CIPHER_AES_VIA_PSA +#define MBEDTLS_BLOCK_CIPHER_SOME_PSA +#endif +#if defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ARIA) +#define MBEDTLS_BLOCK_CIPHER_ARIA_VIA_PSA +#define MBEDTLS_BLOCK_CIPHER_SOME_PSA +#endif +#if defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_CAMELLIA) +#define MBEDTLS_BLOCK_CIPHER_CAMELLIA_VIA_PSA +#define MBEDTLS_BLOCK_CIPHER_SOME_PSA +#endif +#endif /* MBEDTLS_PSA_CRYPTO_C */ + +#if defined(MBEDTLS_AES_C) +#define MBEDTLS_BLOCK_CIPHER_AES_VIA_LEGACY +#endif +#if defined(MBEDTLS_ARIA_C) +#define MBEDTLS_BLOCK_CIPHER_ARIA_VIA_LEGACY +#endif +#if defined(MBEDTLS_CAMELLIA_C) +#define MBEDTLS_BLOCK_CIPHER_CAMELLIA_VIA_LEGACY +#endif + +/* Helpers to state that BLOCK_CIPHER module supports AES, ARIA and/or Camellia + * block ciphers via either PSA or legacy. */ +#if defined(MBEDTLS_BLOCK_CIPHER_AES_VIA_PSA) || \ + defined(MBEDTLS_BLOCK_CIPHER_AES_VIA_LEGACY) +#define MBEDTLS_BLOCK_CIPHER_CAN_AES +#endif +#if defined(MBEDTLS_BLOCK_CIPHER_ARIA_VIA_PSA) || \ + defined(MBEDTLS_BLOCK_CIPHER_ARIA_VIA_LEGACY) +#define MBEDTLS_BLOCK_CIPHER_CAN_ARIA +#endif +#if defined(MBEDTLS_BLOCK_CIPHER_CAMELLIA_VIA_PSA) || \ + defined(MBEDTLS_BLOCK_CIPHER_CAMELLIA_VIA_LEGACY) +#define MBEDTLS_BLOCK_CIPHER_CAN_CAMELLIA +#endif + +/* GCM_C and CCM_C can either depend on (in order of preference) BLOCK_CIPHER_C + * or CIPHER_C. The former is auto-enabled when: + * - CIPHER_C is not defined, which is also the legacy solution; + * - BLOCK_CIPHER_SOME_PSA because in this case BLOCK_CIPHER can take advantage + * of the driver's acceleration. + */ +#if (defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C)) && \ + (!defined(MBEDTLS_CIPHER_C) || defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA)) +#define MBEDTLS_BLOCK_CIPHER_C +#endif + +/* Helpers for GCM/CCM capabilities */ +#if (defined(MBEDTLS_CIPHER_C) && defined(MBEDTLS_AES_C)) || \ + (defined(MBEDTLS_BLOCK_CIPHER_C) && defined(MBEDTLS_BLOCK_CIPHER_CAN_AES)) +#define MBEDTLS_CCM_GCM_CAN_AES +#endif + +#if (defined(MBEDTLS_CIPHER_C) && defined(MBEDTLS_ARIA_C)) || \ + (defined(MBEDTLS_BLOCK_CIPHER_C) && defined(MBEDTLS_BLOCK_CIPHER_CAN_ARIA)) +#define MBEDTLS_CCM_GCM_CAN_ARIA +#endif + +#if (defined(MBEDTLS_CIPHER_C) && defined(MBEDTLS_CAMELLIA_C)) || \ + (defined(MBEDTLS_BLOCK_CIPHER_C) && defined(MBEDTLS_BLOCK_CIPHER_CAN_CAMELLIA)) +#define MBEDTLS_CCM_GCM_CAN_CAMELLIA +#endif + +/* MBEDTLS_ECP_LIGHT is auto-enabled by the following symbols: + * - MBEDTLS_ECP_C because now it consists of MBEDTLS_ECP_LIGHT plus functions + * for curve arithmetic. As a consequence if MBEDTLS_ECP_C is required for + * some reason, then MBEDTLS_ECP_LIGHT should be enabled as well. + * - MBEDTLS_PK_PARSE_EC_EXTENDED and MBEDTLS_PK_PARSE_EC_COMPRESSED because + * these features are not supported in PSA so the only way to have them is + * to enable the built-in solution. + * Both of them are temporary dependencies: + * - PK_PARSE_EC_EXTENDED will be removed after #7779 and #7789 + * - support for compressed points should also be added to PSA, but in this + * case there is no associated issue to track it yet. + * - PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE because Weierstrass key derivation + * still depends on ECP_LIGHT. + */ +#if defined(MBEDTLS_ECP_C) || \ + defined(MBEDTLS_PK_PARSE_EC_EXTENDED) || \ + defined(MBEDTLS_PK_PARSE_EC_COMPRESSED) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_DERIVE) +#define MBEDTLS_ECP_LIGHT +#endif + +/* Legacy helper, still used by mbedtls_check_config.h */ +#if defined(PSA_WANT_ALG_ECDH) +#define MBEDTLS_CAN_ECDH +#endif + +/* Historically pkparse did not check the CBC padding when decrypting + * a key. This was a bug, which is now fixed. As a consequence, pkparse + * now needs PKCS7 padding support, but existing configurations might not + * enable it, so we enable it here. */ +#if defined(MBEDTLS_PK_PARSE_C) && defined(MBEDTLS_PKCS5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) +#define MBEDTLS_CIPHER_PADDING_PKCS7 +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_ADJUST_CONFIG_TWEAK_BUILTINS_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/crypto_builtin_composites.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/crypto_builtin_composites.h new file mode 100644 index 0000000000..da4e2a8a8c --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/crypto_builtin_composites.h @@ -0,0 +1,269 @@ +/** + * \file crypto_builtin_composites.h + * + * \brief Context structure declaration of the Mbed TLS software-based PSA + * drivers called through the PSA Crypto driver dispatch layer. This file + * contains the context structures of those algorithms which need to rely on + * other algorithms, i.e. are 'composite' algorithms. + * + * \note This file may not be included directly. Applications must + * include psa/crypto.h. + * + * \note This header and its content are not part of the Mbed TLS API and + * applications must not depend on it. Its main purpose is to define the + * multi-part state objects of the Mbed TLS software-based PSA drivers. The + * definitions of these objects are then used by crypto_struct.h to define the + * implementation-defined types of PSA multi-part state objects. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_BUILTIN_COMPOSITES_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_BUILTIN_COMPOSITES_H +#include "mbedtls/private_access.h" + +#include + +#include "mbedtls/private/cmac.h" +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) +#include "mbedtls/private/gcm.h" +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) +#include "mbedtls/private/ccm.h" +#endif +#include "mbedtls/private/chachapoly.h" + +/* + * MAC multi-part operation definitions. + */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC) +#define MBEDTLS_PSA_BUILTIN_MAC +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC) || defined(PSA_CRYPTO_DRIVER_TEST) +typedef struct { + /** The HMAC algorithm in use */ + psa_algorithm_t MBEDTLS_PRIVATE(alg); + /** The hash context. */ + struct psa_hash_operation_s hash_ctx; + /** The HMAC part of the context. */ + uint8_t MBEDTLS_PRIVATE(opad)[PSA_HMAC_MAX_HASH_BLOCK_SIZE]; +} mbedtls_psa_hmac_operation_t; + +#define MBEDTLS_PSA_HMAC_OPERATION_INIT { 0, PSA_HASH_OPERATION_INIT, { 0 } } +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */ + +typedef struct { + psa_algorithm_t MBEDTLS_PRIVATE(alg); + union { + unsigned MBEDTLS_PRIVATE(dummy); /* Make the union non-empty even with no supported algorithms. */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC) || defined(PSA_CRYPTO_DRIVER_TEST) + mbedtls_psa_hmac_operation_t MBEDTLS_PRIVATE(hmac); +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC) || defined(PSA_CRYPTO_DRIVER_TEST) + mbedtls_cipher_context_t MBEDTLS_PRIVATE(cmac); +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */ + } MBEDTLS_PRIVATE(ctx); +} mbedtls_psa_mac_operation_t; + +#define MBEDTLS_PSA_MAC_OPERATION_INIT { 0, { 0 } } + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) +#define MBEDTLS_PSA_BUILTIN_AEAD 1 +#endif + +/* Context structure for the Mbed TLS AEAD implementation. */ +typedef struct { + psa_algorithm_t MBEDTLS_PRIVATE(alg); + psa_key_type_t MBEDTLS_PRIVATE(key_type); + + unsigned int MBEDTLS_PRIVATE(is_encrypt) : 1; + + uint8_t MBEDTLS_PRIVATE(tag_length); + + union { + unsigned dummy; /* Enable easier initializing of the union. */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) + mbedtls_ccm_context MBEDTLS_PRIVATE(ccm); +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) + mbedtls_gcm_context MBEDTLS_PRIVATE(gcm); +#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) + mbedtls_chachapoly_context MBEDTLS_PRIVATE(chachapoly); +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ + + } ctx; + +} mbedtls_psa_aead_operation_t; + +#define MBEDTLS_PSA_AEAD_OPERATION_INIT { 0, 0, 0, 0, { 0 } } + +#include "mbedtls/private/ecdsa.h" + +/* Context structure for the Mbed TLS interruptible sign hash implementation. */ +typedef struct { +#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \ + defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecdsa_context *MBEDTLS_PRIVATE(ctx); + mbedtls_ecdsa_restart_ctx MBEDTLS_PRIVATE(restart_ctx); + + uint32_t MBEDTLS_PRIVATE(num_ops); + + size_t MBEDTLS_PRIVATE(coordinate_bytes); + psa_algorithm_t MBEDTLS_PRIVATE(alg); + mbedtls_md_type_t MBEDTLS_PRIVATE(md_alg); + uint8_t MBEDTLS_PRIVATE(hash)[PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS)]; + size_t MBEDTLS_PRIVATE(hash_length); + +#else + /* Make the struct non-empty if algs not supported. */ + unsigned MBEDTLS_PRIVATE(dummy); + +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) && + * defined( MBEDTLS_ECP_RESTARTABLE ) */ +} mbedtls_psa_sign_hash_interruptible_operation_t; + +#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \ + defined(MBEDTLS_ECP_RESTARTABLE) +#define MBEDTLS_PSA_SIGN_HASH_INTERRUPTIBLE_OPERATION_INIT { { 0 }, { 0 }, 0, 0, 0, 0, 0, 0 } +#else +#define MBEDTLS_PSA_SIGN_HASH_INTERRUPTIBLE_OPERATION_INIT { 0 } +#endif + +/* Context structure for the Mbed TLS interruptible verify hash + * implementation.*/ +typedef struct { +#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \ + defined(MBEDTLS_ECP_RESTARTABLE) + + mbedtls_ecdsa_context *MBEDTLS_PRIVATE(ctx); + mbedtls_ecdsa_restart_ctx MBEDTLS_PRIVATE(restart_ctx); + + uint32_t MBEDTLS_PRIVATE(num_ops); + + uint8_t MBEDTLS_PRIVATE(hash)[PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS)]; + size_t MBEDTLS_PRIVATE(hash_length); + + mbedtls_mpi MBEDTLS_PRIVATE(r); + mbedtls_mpi MBEDTLS_PRIVATE(s); + +#else + /* Make the struct non-empty if algs not supported. */ + unsigned MBEDTLS_PRIVATE(dummy); + +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) && + * defined( MBEDTLS_ECP_RESTARTABLE ) */ + +} mbedtls_psa_verify_hash_interruptible_operation_t; + +#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \ + defined(MBEDTLS_ECP_RESTARTABLE) +#define MBEDTLS_VERIFY_SIGN_HASH_INTERRUPTIBLE_OPERATION_INIT { { 0 }, { 0 }, 0, 0, 0, 0, { 0 }, \ + { 0 } } +#else +#define MBEDTLS_VERIFY_SIGN_HASH_INTERRUPTIBLE_OPERATION_INIT { 0 } +#endif + + +/* EC-JPAKE operation definitions */ + +#include "mbedtls/private/ecjpake.h" + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE) +#define MBEDTLS_PSA_BUILTIN_PAKE 1 +#endif + +/* Note: the format for mbedtls_ecjpake_read/write function has an extra + * length byte for each step, plus an extra 3 bytes for ECParameters in the + * server's 2nd round. */ +#define MBEDTLS_PSA_JPAKE_BUFFER_SIZE ((3 + 1 + 65 + 1 + 65 + 1 + 32) * 2) + +typedef struct { + psa_algorithm_t MBEDTLS_PRIVATE(alg); + + uint8_t *MBEDTLS_PRIVATE(password); + size_t MBEDTLS_PRIVATE(password_len); +#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE) + mbedtls_ecjpake_role MBEDTLS_PRIVATE(role); + uint8_t MBEDTLS_PRIVATE(buffer[MBEDTLS_PSA_JPAKE_BUFFER_SIZE]); + size_t MBEDTLS_PRIVATE(buffer_length); + size_t MBEDTLS_PRIVATE(buffer_offset); +#endif + /* Context structure for the Mbed TLS EC-JPAKE implementation. */ + union { + unsigned int MBEDTLS_PRIVATE(dummy); +#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE) + mbedtls_ecjpake_context MBEDTLS_PRIVATE(jpake); +#endif + } MBEDTLS_PRIVATE(ctx); + +} mbedtls_psa_pake_operation_t; + +#define MBEDTLS_PSA_PAKE_OPERATION_INIT { { 0 } } + +typedef struct { +#if defined(MBEDTLS_ECP_C) + mbedtls_ecp_keypair MBEDTLS_PRIVATE(ecp); + uint32_t num_ops; +#else + /* Make the struct non-empty if algs not supported. */ + unsigned MBEDTLS_PRIVATE(dummy); +#endif +} mbedtls_psa_generate_key_iop_t; + +#if defined(MBEDTLS_ECP_C) +#define MBEDTLS_PSA_GENERATE_KEY_IOP_INIT { MBEDTLS_ECP_KEYPAIR_INIT, 0 } +#else +#define MBEDTLS_PSA_GENERATE_KEY_IOP_INIT { 0 } +#endif + +/* Context structure for the Mbed TLS interruptible key agreement implementation. */ +typedef struct { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) && defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_keypair *MBEDTLS_PRIVATE(our_key); + mbedtls_ecp_keypair *MBEDTLS_PRIVATE(their_key); + mbedtls_ecp_restart_ctx MBEDTLS_PRIVATE(rs); + uint32_t MBEDTLS_PRIVATE(num_ops); +#else + /* Make the struct non-empty if algs not supported. */ + unsigned MBEDTLS_PRIVATE(dummy); +#endif +} mbedtls_psa_key_agreement_interruptible_operation_t; + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) && defined(MBEDTLS_ECP_RESTARTABLE) +#define MBEDTLS_PSA_KEY_AGREEMENT_IOP_INIT { NULL, NULL, MBEDTLS_ECP_RESTART_INIT, 0 } +#else +#define MBEDTLS_PSA_KEY_AGREEMENT_IOP_INIT { 0 } +#endif + +/* Context structure for the Mbed TLS interruptible export public-key implementation. */ +typedef struct { +#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_keypair *MBEDTLS_PRIVATE(key); + mbedtls_ecp_restart_ctx MBEDTLS_PRIVATE(restart_ctx); + uint32_t MBEDTLS_PRIVATE(num_ops); +#else + /* Make the struct non-empty if algs not supported. */ + unsigned MBEDTLS_PRIVATE(dummy); +#endif +} mbedtls_psa_export_public_key_iop_t; + +#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_ECP_RESTARTABLE) +#define MBEDTLS_PSA_EXPORT_PUBLIC_KEY_IOP_INIT { NULL, MBEDTLS_ECP_RESTART_INIT, 0 } +#else +#define MBEDTLS_PSA_EXPORT_PUBLIC_KEY_IOP_INIT { 0 } +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_BUILTIN_COMPOSITES_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/crypto_builtin_key_derivation.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/crypto_builtin_key_derivation.h new file mode 100644 index 0000000000..6ff3ff9df1 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/crypto_builtin_key_derivation.h @@ -0,0 +1,120 @@ +/** + * \file crypto_builtin_key_derivation.h + * + * \brief Context structure declaration of the Mbed TLS software-based PSA + * drivers called through the PSA Crypto driver dispatch layer. This file + * contains the context structures of key derivation algorithms which need to + * rely on other algorithms. + * + * \note This file may not be included directly. Applications must + * include psa/crypto.h. + * + * \note This header and its content are not part of the Mbed TLS API and + * applications must not depend on it. Its main purpose is to define the + * multi-part state objects of the Mbed TLS software-based PSA drivers. The + * definitions of these objects are then used by crypto_struct.h to define the + * implementation-defined types of PSA multi-part state objects. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_BUILTIN_KEY_DERIVATION_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_BUILTIN_KEY_DERIVATION_H +#include "mbedtls/private_access.h" + +#include + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND) +typedef struct { + uint8_t *MBEDTLS_PRIVATE(info); + size_t MBEDTLS_PRIVATE(info_length); +#if PSA_HASH_MAX_SIZE > 0xff +#error "PSA_HASH_MAX_SIZE does not fit in uint8_t" +#endif + uint8_t MBEDTLS_PRIVATE(offset_in_block); + uint8_t MBEDTLS_PRIVATE(block_number); + unsigned int MBEDTLS_PRIVATE(state) : 2; + unsigned int MBEDTLS_PRIVATE(info_set) : 1; + uint8_t MBEDTLS_PRIVATE(output_block)[PSA_HASH_MAX_SIZE]; + uint8_t MBEDTLS_PRIVATE(prk)[PSA_HASH_MAX_SIZE]; + struct psa_mac_operation_s MBEDTLS_PRIVATE(hmac); +} psa_hkdf_key_derivation_t; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF || + MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT || + MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS) +typedef struct { + uint8_t MBEDTLS_PRIVATE(data)[PSA_TLS12_ECJPAKE_TO_PMS_DATA_SIZE]; +} psa_tls12_ecjpake_to_pms_t; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS */ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) +typedef enum { + PSA_TLS12_PRF_STATE_INIT, /* no input provided */ + PSA_TLS12_PRF_STATE_SEED_SET, /* seed has been set */ + PSA_TLS12_PRF_STATE_OTHER_KEY_SET, /* other key has been set - optional */ + PSA_TLS12_PRF_STATE_KEY_SET, /* key has been set */ + PSA_TLS12_PRF_STATE_LABEL_SET, /* label has been set */ + PSA_TLS12_PRF_STATE_OUTPUT /* output has been started */ +} psa_tls12_prf_key_derivation_state_t; + +typedef struct psa_tls12_prf_key_derivation_s { +#if PSA_HASH_MAX_SIZE > 0xff +#error "PSA_HASH_MAX_SIZE does not fit in uint8_t" +#endif + + /* Indicates how many bytes in the current HMAC block have + * not yet been read by the user. */ + uint8_t MBEDTLS_PRIVATE(left_in_block); + + /* The 1-based number of the block. */ + uint8_t MBEDTLS_PRIVATE(block_number); + + psa_tls12_prf_key_derivation_state_t MBEDTLS_PRIVATE(state); + + uint8_t *MBEDTLS_PRIVATE(secret); + size_t MBEDTLS_PRIVATE(secret_length); + uint8_t *MBEDTLS_PRIVATE(seed); + size_t MBEDTLS_PRIVATE(seed_length); + uint8_t *MBEDTLS_PRIVATE(label); + size_t MBEDTLS_PRIVATE(label_length); +#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) + uint8_t *MBEDTLS_PRIVATE(other_secret); + size_t MBEDTLS_PRIVATE(other_secret_length); +#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */ + + uint8_t MBEDTLS_PRIVATE(Ai)[PSA_HASH_MAX_SIZE]; + + /* `HMAC_hash( prk, A( i ) + seed )` in the notation of RFC 5246, Sect. 5. */ + uint8_t MBEDTLS_PRIVATE(output_block)[PSA_HASH_MAX_SIZE]; +} psa_tls12_prf_key_derivation_t; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || + * MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */ +#if defined(PSA_HAVE_SOFT_PBKDF2) +typedef enum { + PSA_PBKDF2_STATE_INIT, /* no input provided */ + PSA_PBKDF2_STATE_INPUT_COST_SET, /* input cost has been set */ + PSA_PBKDF2_STATE_SALT_SET, /* salt has been set */ + PSA_PBKDF2_STATE_PASSWORD_SET, /* password has been set */ + PSA_PBKDF2_STATE_OUTPUT /* output has been started */ +} psa_pbkdf2_key_derivation_state_t; + +typedef struct { + psa_pbkdf2_key_derivation_state_t MBEDTLS_PRIVATE(state); + uint64_t MBEDTLS_PRIVATE(input_cost); + uint8_t *MBEDTLS_PRIVATE(salt); + size_t MBEDTLS_PRIVATE(salt_length); + uint8_t MBEDTLS_PRIVATE(password)[PSA_HMAC_MAX_HASH_BLOCK_SIZE]; + size_t MBEDTLS_PRIVATE(password_length); + uint8_t MBEDTLS_PRIVATE(output_block)[PSA_HASH_MAX_SIZE]; + uint8_t MBEDTLS_PRIVATE(bytes_used); + uint32_t MBEDTLS_PRIVATE(block_number); +} psa_pbkdf2_key_derivation_t; +#endif /* PSA_HAVE_SOFT_PBKDF2 */ + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_BUILTIN_KEY_DERIVATION_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/crypto_builtin_primitives.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/crypto_builtin_primitives.h new file mode 100644 index 0000000000..b21bee4515 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/crypto_builtin_primitives.h @@ -0,0 +1,136 @@ +/** + * \file crypto_builtin_primitives.h + * + * \brief Context structure declaration of the Mbed TLS software-based PSA + * drivers called through the PSA Crypto driver dispatch layer. This file + * contains the context structures of those algorithms which do not rely on + * other algorithms, i.e. are 'primitive' algorithms. + * + * \note This file may not be included directly. Applications must + * include psa/crypto.h. + * + * \note This header and its content are not part of the Mbed TLS API and + * applications must not depend on it. Its main purpose is to define the + * multi-part state objects of the Mbed TLS software-based PSA drivers. The + * definitions of these objects are then used by crypto_struct.h to define the + * implementation-defined types of PSA multi-part state objects. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_BUILTIN_PRIMITIVES_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_BUILTIN_PRIMITIVES_H +#include "mbedtls/private_access.h" + +#include + +/* + * Hash multi-part operation definitions. + */ + +#include "mbedtls/private/md5.h" +#include "mbedtls/private/ripemd160.h" +#include "mbedtls/private/sha1.h" +#include "mbedtls/private/sha256.h" +#include "mbedtls/private/sha512.h" +#include "mbedtls/private/sha3.h" + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_MD5) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_RIPEMD160) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_1) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_224) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_256) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_384) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_512) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512) +#define MBEDTLS_PSA_BUILTIN_HASH +#endif + +typedef struct { + psa_algorithm_t MBEDTLS_PRIVATE(alg); + union { + unsigned dummy; /* Make the union non-empty even with no supported algorithms. */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_MD5) + mbedtls_md5_context md5; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RIPEMD160) + mbedtls_ripemd160_context ripemd160; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_1) + mbedtls_sha1_context sha1; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_256) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_224) + mbedtls_sha256_context sha256; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_512) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_384) + mbedtls_sha512_context sha512; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_SOME_HASH) + mbedtls_sha3_context sha3; +#endif + } MBEDTLS_PRIVATE(ctx); +} mbedtls_psa_hash_operation_t; + +#define MBEDTLS_PSA_HASH_OPERATION_INIT { 0, { 0 } } + +/* + * XOF (extendable-output functions) multi-part operation definitions. + */ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHAKE128) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_SHAKE256) || \ + 0 +#define MBEDTLS_PSA_BUILTIN_XOF +#endif + +typedef struct { + psa_algorithm_t MBEDTLS_PRIVATE(alg); + uint8_t have_output; + union { + unsigned dummy; /* Make the union non-empty even with no supported algorithms. */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SOME_SHAKE) + mbedtls_sha3_context shake; +#endif + } MBEDTLS_PRIVATE(ctx); +} mbedtls_psa_xof_operation_t; + +#define MBEDTLS_PSA_XOF_OPERATION_INIT { 0, { 0 } } + +/* + * Cipher multi-part operation definitions. + */ + +#include "mbedtls/private/cipher.h" + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_STREAM_CIPHER) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_CTR) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_CFB) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_OFB) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_NO_PADDING) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_PKCS7) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_CCM_STAR_NO_TAG) +#define MBEDTLS_PSA_BUILTIN_CIPHER 1 +#endif + +typedef struct { + /* Context structure for the Mbed TLS cipher implementation. */ + psa_algorithm_t MBEDTLS_PRIVATE(alg); + uint8_t MBEDTLS_PRIVATE(iv_length); + uint8_t MBEDTLS_PRIVATE(block_length); + union { + unsigned int MBEDTLS_PRIVATE(dummy); + mbedtls_cipher_context_t MBEDTLS_PRIVATE(cipher); + } MBEDTLS_PRIVATE(ctx); +} mbedtls_psa_cipher_operation_t; + +#define MBEDTLS_PSA_CIPHER_OPERATION_INIT { 0, 0, 0, { 0 } } + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CRYPTO_BUILTIN_PRIMITIVES_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ctr_drbg.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ctr_drbg.h new file mode 100644 index 0000000000..090416849d --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ctr_drbg.h @@ -0,0 +1,554 @@ +/** + * \file ctr_drbg.h + * + * \brief This file contains definitions and functions for the + * CTR_DRBG pseudorandom generator. + * + * CTR_DRBG is a standardized way of building a PRNG from a block-cipher + * in counter mode operation, as defined in NIST SP 800-90A: + * Recommendation for Random Number Generation Using Deterministic Random + * Bit Generators. + * + * The Mbed TLS implementation of CTR_DRBG uses AES-256 (default) or AES-128 + * (if #MBEDTLS_PSA_CRYPTO_RNG_STRENGTH is 128) as the underlying block cipher, + * with a derivation function. + * + * The security strength as defined in NIST SP 800-90A is + * 128 bits when AES-128 is used and 256 bits otherwise, provided that + * #MBEDTLS_CTR_DRBG_ENTROPY_LEN is kept at its default value and that the DRBG + * instance is set up with default parameters. See the documentation of + * mbedtls_ctr_drbg_seed() for more information. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CTR_DRBG_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CTR_DRBG_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +/* The CTR_DRBG implementation can either directly call the low-level AES + * module (gated by MBEDTLS_AES_C) or call the PSA API to perform AES + * operations. Calling the AES module directly is the default, both for + * maximum backward compatibility and because it's a bit more efficient + * (less glue code). + * + * When MBEDTLS_AES_C is disabled, the CTR_DRBG module calls PSA crypto and + * thus benefits from the PSA AES accelerator driver. + * It is technically possible to enable MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO + * to use PSA even when MBEDTLS_AES_C is enabled, but there is very little + * reason to do so other than testing purposes and this is not officially + * supported. + */ +#if !defined(MBEDTLS_AES_C) +#define MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO +#endif + +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) +#include "psa/crypto.h" +#else +#include "mbedtls/private/aes.h" +#endif + +#include "mbedtls/private/entropy.h" + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +/** The entropy source failed. */ +#define MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED -0x0034 +/** The requested random buffer length is too big. */ +#define MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG -0x0036 +/** The input (entropy + additional data) is too large. */ +#define MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG -0x0038 +/** Read or write error in file. */ +#define MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR -0x003A + +#define MBEDTLS_CTR_DRBG_BLOCKSIZE 16 /**< The block size used by the cipher. */ + +#if MBEDTLS_PSA_CRYPTO_RNG_STRENGTH == 128 +#define MBEDTLS_CTR_DRBG_USE_128_BIT_KEY +#define MBEDTLS_CTR_DRBG_KEYSIZE 16 +/**< The key size in bytes used by the cipher. + * + * Compile-time choice: 16 bytes (128 bits) + * because #MBEDTLS_PSA_CRYPTO_RNG_STRENGTH is 128. + */ +#else +#define MBEDTLS_CTR_DRBG_KEYSIZE 32 +/**< The key size in bytes used by the cipher. + * + * Compile-time choice: 32 bytes (256 bits) + * because #MBEDTLS_PSA_CRYPTO_RNG_STRENGTH is NOT 128. + */ +#endif + +#define MBEDTLS_CTR_DRBG_KEYBITS (MBEDTLS_CTR_DRBG_KEYSIZE * 8) /**< The key size for the DRBG operation, in bits. */ +#define MBEDTLS_CTR_DRBG_SEEDLEN (MBEDTLS_CTR_DRBG_KEYSIZE + MBEDTLS_CTR_DRBG_BLOCKSIZE) /**< The seed length, calculated as (counter + AES key). */ + +#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 32 +/**< The amount of entropy used per seed by default, in bytes. */ + +#if !defined(MBEDTLS_PSA_RNG_RESEED_INTERVAL) +#define MBEDTLS_PSA_RNG_RESEED_INTERVAL 10000 +/**< The interval before reseed is performed by default. */ +#endif + +#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 +/**< The maximum number of additional input Bytes. */ +#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 +/**< The maximum number of requested Bytes per call. */ +#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 +/**< The maximum size of seed or reseed buffer in bytes. */ + +#define MBEDTLS_CTR_DRBG_PR_OFF 0 +/**< Prediction resistance is disabled. */ +#define MBEDTLS_CTR_DRBG_PR_ON 1 +/**< Prediction resistance is enabled. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if MBEDTLS_CTR_DRBG_ENTROPY_LEN >= MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2 +/** The default length of the nonce read from the entropy source. + * + * This is \c 0 because a single read from the entropy source is sufficient + * to include a nonce. + * See the documentation of mbedtls_ctr_drbg_seed() for more information. + */ +#define MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN 0 +#else +/** The default length of the nonce read from the entropy source. + * + * This is half of the default entropy length because a single read from + * the entropy source does not provide enough material to form a nonce. + * See the documentation of mbedtls_ctr_drbg_seed() for more information. + */ +#define MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN (MBEDTLS_CTR_DRBG_ENTROPY_LEN + 1) / 2 +#endif + +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) +typedef struct mbedtls_ctr_drbg_psa_context { + mbedtls_svc_key_id_t key_id; + psa_cipher_operation_t operation; +} mbedtls_ctr_drbg_psa_context; +#endif + +/** + * \brief The CTR_DRBG context structure. + */ +typedef struct mbedtls_ctr_drbg_context { + unsigned char MBEDTLS_PRIVATE(counter)[16]; /*!< The counter (V). */ + int MBEDTLS_PRIVATE(reseed_counter); /*!< The reseed counter. + * This is the number of requests that have + * been made since the last (re)seeding. + * Before the initial seeding, this field + * contains the amount of entropy in bytes + * to use as a nonce for the initial seeding, + * or -1 if no nonce length has been explicitly + * set (see mbedtls_ctr_drbg_set_nonce_len()). + */ + int MBEDTLS_PRIVATE(prediction_resistance); /*!< This determines whether prediction + resistance is enabled, that is + whether to systematically reseed before + each random generation. */ + size_t MBEDTLS_PRIVATE(entropy_len); /*!< The amount of entropy grabbed on each + seed or reseed operation, in bytes. */ + int MBEDTLS_PRIVATE(reseed_interval); /*!< The reseed interval. + * This is the maximum number of requests + * that can be made between reseedings. */ + +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) + mbedtls_ctr_drbg_psa_context MBEDTLS_PRIVATE(psa_ctx); /*!< The PSA context. */ +#else + mbedtls_aes_context MBEDTLS_PRIVATE(aes_ctx); /*!< The AES context. */ +#endif + + /* + * Callbacks (Entropy) + */ + int(*MBEDTLS_PRIVATE(f_entropy))(void *, unsigned char *, size_t); + /*!< The entropy callback function. */ + + void *MBEDTLS_PRIVATE(p_entropy); /*!< The context for the entropy function. */ + +#if defined(MBEDTLS_THREADING_C) + /* Invariant: the mutex is initialized if and only if f_entropy != NULL. + * This means that the mutex is initialized during the initial seeding + * in mbedtls_ctr_drbg_seed() and freed in mbedtls_ctr_drbg_free(). + * + * Note that this invariant may change without notice. Do not rely on it + * and do not access the mutex directly in application code. + */ + mbedtls_threading_mutex_t MBEDTLS_PRIVATE(mutex); +#endif +} +mbedtls_ctr_drbg_context; + +/** + * \brief This function initializes the CTR_DRBG context, + * and prepares it for mbedtls_ctr_drbg_seed() + * or mbedtls_ctr_drbg_free(). + * + * \note The reseed interval is + * #MBEDTLS_PSA_RNG_RESEED_INTERVAL by default. + * You can override it by calling + * mbedtls_ctr_drbg_set_reseed_interval(). + * + * \param ctx The CTR_DRBG context to initialize. + */ +void mbedtls_ctr_drbg_init(mbedtls_ctr_drbg_context *ctx); + +/** + * \brief This function seeds and sets up the CTR_DRBG + * entropy source for future reseeds. + * + * A typical choice for the \p f_entropy and \p p_entropy parameters is + * to use the entropy module: + * - \p f_entropy is mbedtls_entropy_func(); + * - \p p_entropy is an instance of ::mbedtls_entropy_context initialized + * with mbedtls_entropy_init() (which registers the platform's default + * entropy sources). + * + * The entropy length is #MBEDTLS_CTR_DRBG_ENTROPY_LEN by default. + * You can override it by calling mbedtls_ctr_drbg_set_entropy_len(). + * + * The entropy nonce length is: + * - \c 0 if the entropy length is at least 3/2 times the entropy length, + * which guarantees that the security strength is the maximum permitted + * by the key size and entropy length according to NIST SP 800-90A §10.2.1; + * - Half the entropy length otherwise. + * You can override it by calling mbedtls_ctr_drbg_set_nonce_len(). + * With the default entropy length, the entropy nonce length is + * #MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN. + * + * You can provide a nonce and personalization string in addition to the + * entropy source, to make this instantiation as unique as possible. + * See SP 800-90A §8.6.7 for more details about nonces. + * + * The _seed_material_ value passed to the derivation function in + * the CTR_DRBG Instantiate Process described in NIST SP 800-90A §10.2.1.3.2 + * is the concatenation of the following strings: + * - A string obtained by calling \p f_entropy function for the entropy + * length. + */ +#if MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN == 0 +/** + * - If mbedtls_ctr_drbg_set_nonce_len() has been called, a string + * obtained by calling \p f_entropy function for the specified length. + */ +#else +/** + * - A string obtained by calling \p f_entropy function for the entropy nonce + * length. If the entropy nonce length is \c 0, this function does not + * make a second call to \p f_entropy. + */ +#endif +#if defined(MBEDTLS_THREADING_C) +/** + * \note When Mbed TLS is built with threading support, + * after this function returns successfully, + * it is safe to call mbedtls_ctr_drbg_random() + * from multiple threads. Other operations, including + * reseeding, are not thread-safe. + */ +#endif /* MBEDTLS_THREADING_C */ +/** + * - The \p custom string. + * + * \note To achieve the nominal security strength permitted + * by CTR_DRBG, the entropy length must be: + * - at least 16 bytes for a 128-bit strength + * (maximum achievable strength when using AES-128); + * - at least 32 bytes for a 256-bit strength + * (maximum achievable strength when using AES-256). + * + * In addition, if you do not pass a nonce in \p custom, + * the sum of the entropy length + * and the entropy nonce length must be: + * - at least 24 bytes for a 128-bit strength + * (maximum achievable strength when using AES-128); + * - at least 48 bytes for a 256-bit strength + * (maximum achievable strength when using AES-256). + * + * \param ctx The CTR_DRBG context to seed. + * It must have been initialized with + * mbedtls_ctr_drbg_init(). + * After a successful call to mbedtls_ctr_drbg_seed(), + * you may not call mbedtls_ctr_drbg_seed() again on + * the same context unless you call + * mbedtls_ctr_drbg_free() and mbedtls_ctr_drbg_init() + * again first. + * After a failed call to mbedtls_ctr_drbg_seed(), + * you must call mbedtls_ctr_drbg_free(). + * \param f_entropy The entropy callback, taking as arguments the + * \p p_entropy context, the buffer to fill, and the + * length of the buffer. + * \p f_entropy is always called with a buffer size + * less than or equal to the entropy length. + * \param p_entropy The entropy context to pass to \p f_entropy. + * \param custom The personalization string. + * This can be \c NULL, in which case the personalization + * string is empty regardless of the value of \p len. + * \param len The length of the personalization string. + * This must be at most + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + * - #MBEDTLS_CTR_DRBG_ENTROPY_LEN. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on failure. + */ +int mbedtls_ctr_drbg_seed(mbedtls_ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len); + +/** + * \brief This function resets CTR_DRBG context to the state immediately + * after initial call of mbedtls_ctr_drbg_init(). + * + * \param ctx The CTR_DRBG context to clear. + */ +void mbedtls_ctr_drbg_free(mbedtls_ctr_drbg_context *ctx); + +/** + * \brief This function turns prediction resistance on or off. + * The default value is off. + * + * \note If enabled, entropy is gathered at the beginning of + * every call to mbedtls_ctr_drbg_random_with_add() + * or mbedtls_ctr_drbg_random(). + * Only use this if your entropy source has sufficient + * throughput. + * + * \param ctx The CTR_DRBG context. + * \param resistance #MBEDTLS_CTR_DRBG_PR_ON or #MBEDTLS_CTR_DRBG_PR_OFF. + */ +void mbedtls_ctr_drbg_set_prediction_resistance(mbedtls_ctr_drbg_context *ctx, + int resistance); + +/** + * \brief This function sets the amount of entropy grabbed on each + * seed or reseed. + * + * The default value is #MBEDTLS_CTR_DRBG_ENTROPY_LEN. + * + * \note The security strength of CTR_DRBG is bounded by the + * entropy length. Thus: + * - When using AES-256 (#MBEDTLS_PSA_CRYPTO_RNG_STRENGTH + * is 256, which is the default), + * \p len must be at least 32 (in bytes) + * to achieve a 256-bit strength. + * - When using AES-128 (#MBEDTLS_PSA_CRYPTO_RNG_STRENGTH + * is 128) \p len must be at least 16 (in bytes) to + * achieve a 128-bit strength. + * + * \param ctx The CTR_DRBG context. + * \param len The amount of entropy to grab, in bytes. + * This must be at most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + * and at most the maximum length accepted by the + * entropy function that is set in the context. + */ +void mbedtls_ctr_drbg_set_entropy_len(mbedtls_ctr_drbg_context *ctx, + size_t len); + +/** + * \brief This function sets the amount of entropy grabbed + * as a nonce for the initial seeding. + * + * Call this function before calling mbedtls_ctr_drbg_seed() to read + * a nonce from the entropy source during the initial seeding. + * + * \param ctx The CTR_DRBG context. + * \param len The amount of entropy to grab for the nonce, in bytes. + * This must be at most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + * and at most the maximum length accepted by the + * entropy function that is set in the context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG if \p len is + * more than #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + * if the initial seeding has already taken place. + */ +int mbedtls_ctr_drbg_set_nonce_len(mbedtls_ctr_drbg_context *ctx, + size_t len); + +/** + * \brief This function sets the reseed interval. + * + * The reseed interval is the number of calls to mbedtls_ctr_drbg_random() + * or mbedtls_ctr_drbg_random_with_add() after which the entropy function + * is called again. + * + * The default value is #MBEDTLS_PSA_RNG_RESEED_INTERVAL. + * + * \param ctx The CTR_DRBG context. + * \param interval The reseed interval. + */ +void mbedtls_ctr_drbg_set_reseed_interval(mbedtls_ctr_drbg_context *ctx, + int interval); + +/** + * \brief This function reseeds the CTR_DRBG context, that is + * extracts data from the entropy source. + * + * \note This function is not thread-safe. It is not safe + * to call this function if another thread might be + * concurrently obtaining random numbers from the same + * context or updating or reseeding the same context. + * + * \param ctx The CTR_DRBG context. + * \param additional Additional data to add to the state. Can be \c NULL. + * \param len The length of the additional data. + * This must be less than + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - \c entropy_len + * where \c entropy_len is the entropy length + * configured for the context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on failure. + */ +int mbedtls_ctr_drbg_reseed(mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t len); + +/** + * \brief This function updates the state of the CTR_DRBG context. + * + * \note This function is not thread-safe. It is not safe + * to call this function if another thread might be + * concurrently obtaining random numbers from the same + * context or updating or reseeding the same context. + * + * \param ctx The CTR_DRBG context. + * \param additional The data to update the state with. This must not be + * \c NULL unless \p add_len is \c 0. + * \param add_len Length of \p additional in bytes. This must be at + * most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG if + * \p add_len is more than + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT. + * \return An error from the underlying AES cipher on failure. + */ +int mbedtls_ctr_drbg_update(mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, + size_t add_len); + +/** + * \brief This function updates a CTR_DRBG instance with additional + * data and uses it to generate random data. + * + * This function automatically reseeds if the reseed counter is exceeded + * or prediction resistance is enabled. + * + * \note This function is not thread-safe. It is not safe + * to call this function if another thread might be + * concurrently obtaining random numbers from the same + * context or updating or reseeding the same context. + * + * \param p_rng The CTR_DRBG context. This must be a pointer to a + * #mbedtls_ctr_drbg_context structure. + * \param output The buffer to fill. + * \param output_len The length of the buffer in bytes. + * \param additional Additional data to update. Can be \c NULL, in which + * case the additional data is empty regardless of + * the value of \p add_len. + * \param add_len The length of the additional data + * if \p additional is not \c NULL. + * This must be less than #MBEDTLS_CTR_DRBG_MAX_INPUT + * and less than + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - \c entropy_len + * where \c entropy_len is the entropy length + * configured for the context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or + * #MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG on failure. + */ +int mbedtls_ctr_drbg_random_with_add(void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, size_t add_len); + +/** + * \brief This function uses CTR_DRBG to generate random data. + * + * This function automatically reseeds if the reseed counter is exceeded + * or prediction resistance is enabled. + */ +#if defined(MBEDTLS_THREADING_C) +/** + * \note When Mbed TLS is built with threading support, + * it is safe to call mbedtls_ctr_drbg_random() + * from multiple threads. Other operations, including + * reseeding, are not thread-safe. + */ +#endif /* MBEDTLS_THREADING_C */ +/** + * \param p_rng The CTR_DRBG context. This must be a pointer to a + * #mbedtls_ctr_drbg_context structure. + * \param output The buffer to fill. + * \param output_len The length of the buffer in bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or + * #MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG on failure. + */ +int mbedtls_ctr_drbg_random(void *p_rng, + unsigned char *output, size_t output_len); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief This function writes a seed file. + * + * \param ctx The CTR_DRBG context. + * \param path The name of the file. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on reseed + * failure. + */ +int mbedtls_ctr_drbg_write_seed_file(mbedtls_ctr_drbg_context *ctx, const char *path); + +/** + * \brief This function reads and updates a seed file. The seed + * is added to this instance. + * + * \param ctx The CTR_DRBG context. + * \param path The name of the file. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on + * reseed failure. + * \return #MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG if the existing + * seed file is too large. + */ +int mbedtls_ctr_drbg_update_seed_file(mbedtls_ctr_drbg_context *ctx, const char *path); +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief The CTR_DRBG checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_ctr_drbg_self_test(int verbose); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CTR_DRBG_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ecdsa.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ecdsa.h new file mode 100644 index 0000000000..5fd2f1549a --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ecdsa.h @@ -0,0 +1,667 @@ +/** + * \file ecdsa.h + * + * \brief This file contains ECDSA definitions and functions. + * + * The Elliptic Curve Digital Signature Algorithm (ECDSA) is defined in + * Standards for Efficient Cryptography Group (SECG): + * SEC1 Elliptic Curve Cryptography. + * The use of ECDSA for TLS is defined in RFC-4492: Elliptic Curve + * Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS). + * + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ECDSA_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ECDSA_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +#include "mbedtls/private/ecp.h" +#include "mbedtls/md.h" + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief Maximum ECDSA signature size for a given curve bit size + * + * \param bits Curve size in bits + * \return Maximum signature size in bytes + * + * \note This macro returns a compile-time constant if its argument + * is one. It may evaluate its argument multiple times. + */ +/* + * Ecdsa-Sig-Value ::= SEQUENCE { + * r INTEGER, + * s INTEGER + * } + * + * For each of r and s, the value (V) may include an extra initial "0" bit. + */ +#define MBEDTLS_ECDSA_MAX_SIG_LEN(bits) \ + (/*T,L of SEQUENCE*/ ((bits) >= 61 * 8 ? 3 : 2) + \ + /*T,L of r,s*/ 2 * (((bits) >= 127 * 8 ? 3 : 2) + \ + /*V of r,s*/ ((bits) + 8) / 8)) + +/** The maximal size of an ECDSA signature in Bytes. */ +#define MBEDTLS_ECDSA_MAX_LEN MBEDTLS_ECDSA_MAX_SIG_LEN(MBEDTLS_ECP_MAX_BITS) +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief The ECDSA context structure. + * + * \warning Performing multiple operations concurrently on the same + * ECDSA context is not supported; objects of this type + * should not be shared between multiple threads. + * + * \note pk_wrap module assumes that "ecdsa_context" is identical + * to "ecp_keypair" (see for example structure + * "mbedtls_eckey_info" where ECDSA sign/verify functions + * are used also for EC key) + */ +typedef mbedtls_ecp_keypair mbedtls_ecdsa_context; + +#if defined(MBEDTLS_ECP_RESTARTABLE) + +/** + * \brief Internal restart context for ecdsa_verify() + * + * \note Opaque struct, defined in ecdsa.c + */ +typedef struct mbedtls_ecdsa_restart_ver mbedtls_ecdsa_restart_ver_ctx; + +/** + * \brief Internal restart context for ecdsa_sign() + * + * \note Opaque struct, defined in ecdsa.c + */ +typedef struct mbedtls_ecdsa_restart_sig mbedtls_ecdsa_restart_sig_ctx; + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +/** + * \brief Internal restart context for ecdsa_sign_det() + * + * \note Opaque struct, defined in ecdsa.c + */ +typedef struct mbedtls_ecdsa_restart_det mbedtls_ecdsa_restart_det_ctx; +#endif + +/** + * \brief General context for resuming ECDSA operations + */ +typedef struct { + mbedtls_ecp_restart_ctx MBEDTLS_PRIVATE(ecp); /*!< base context for ECP restart and + shared administrative info */ + mbedtls_ecdsa_restart_ver_ctx *MBEDTLS_PRIVATE(ver); /*!< ecdsa_verify() sub-context */ + mbedtls_ecdsa_restart_sig_ctx *MBEDTLS_PRIVATE(sig); /*!< ecdsa_sign() sub-context */ +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + mbedtls_ecdsa_restart_det_ctx *MBEDTLS_PRIVATE(det); /*!< ecdsa_sign_det() sub-context */ +#endif +} mbedtls_ecdsa_restart_ctx; + +#else /* MBEDTLS_ECP_RESTARTABLE */ + +/* Now we can declare functions that take a pointer to that */ +typedef void mbedtls_ecdsa_restart_ctx; + +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief This function checks whether a given group can be used + * for ECDSA. + * + * \param gid The ECP group ID to check. + * + * \return \c 1 if the group can be used, \c 0 otherwise + */ +int mbedtls_ecdsa_can_do(mbedtls_ecp_group_id gid); + +/** + * \brief This function computes the ECDSA signature of a + * previously-hashed message. + * + * \note The deterministic version implemented in + * mbedtls_ecdsa_sign_det_ext() is usually preferred. + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated + * as defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.3, step 5. + * + * \see ecp.h + * + * \param grp The context for the elliptic curve to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param r The MPI context in which to store the first part + * the signature. This must be initialized. + * \param s The MPI context in which to store the second part + * the signature. This must be initialized. + * \param d The private signing key. This must be initialized. + * \param buf The content to be signed. This is usually the hash of + * the original data to be signed. This must be a readable + * buffer of length \p blen Bytes. It may be \c NULL if + * \p blen is zero. + * \param blen The length of \p buf in Bytes. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context parameter. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX + * or \c MBEDTLS_MPI_XXX error code on failure. + */ +int mbedtls_ecdsa_sign(mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng); + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +/** + * \brief This function computes the ECDSA signature of a + * previously-hashed message, deterministic version. + * + * For more information, see RFC-6979: Deterministic + * Usage of the Digital Signature Algorithm (DSA) and Elliptic + * Curve Digital Signature Algorithm (ECDSA). + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.3, step 5. + * + * \see ecp.h + * + * \param grp The context for the elliptic curve to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param r The MPI context in which to store the first part + * the signature. This must be initialized. + * \param s The MPI context in which to store the second part + * the signature. This must be initialized. + * \param d The private signing key. This must be initialized + * and setup, for example through mbedtls_ecp_gen_privkey(). + * \param buf The hashed content to be signed. This must be a readable + * buffer of length \p blen Bytes. It may be \c NULL if + * \p blen is zero. + * \param blen The length of \p buf in Bytes. + * \param md_alg The hash algorithm used to hash the original data. + * \param f_rng_blind The RNG function used for blinding. This must not be + * \c NULL. + * \param p_rng_blind The RNG context to be passed to \p f_rng_blind. This + * may be \c NULL if \p f_rng_blind doesn't need a context + * parameter. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX + * error code on failure. + */ +int mbedtls_ecdsa_sign_det_ext(mbedtls_ecp_group *grp, mbedtls_mpi *r, + mbedtls_mpi *s, const mbedtls_mpi *d, + const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg, + int (*f_rng_blind)(void *, unsigned char *, size_t), + void *p_rng_blind); +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +/** + * \brief This function computes the ECDSA signature of a + * previously-hashed message, in a restartable way. + * + * \note The deterministic version implemented in + * mbedtls_ecdsa_sign_det_restartable() is usually + * preferred. + * + * \note This function is like \c mbedtls_ecdsa_sign() but + * it can return early and restart according to the + * limit set with \c mbedtls_ecp_set_max_ops() to + * reduce blocking. + * + * \note If the bitlength of the message hash is larger + * than the bitlength of the group order, then the + * hash is truncated as defined in Standards for + * Efficient Cryptography Group (SECG): SEC1 Elliptic + * Curve Cryptography, section 4.1.3, step 5. + * + * \see ecp.h + * + * \param grp The context for the elliptic curve to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param r The MPI context in which to store the first part + * the signature. This must be initialized. + * \param s The MPI context in which to store the second part + * the signature. This must be initialized. + * \param d The private signing key. This must be initialized + * and setup, for example through + * mbedtls_ecp_gen_privkey(). + * \param buf The hashed content to be signed. This must be a readable + * buffer of length \p blen Bytes. It may be \c NULL if + * \p blen is zero. + * \param blen The length of \p buf in Bytes. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context parameter. + * \param f_rng_blind The RNG function used for blinding. This must not be + * \c NULL. + * \param p_rng_blind The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context parameter. + * \param rs_ctx The restart context to use. This may be \c NULL + * to disable restarting. If it is not \c NULL, it + * must point to an initialized restart context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c + * mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX, \c + * MBEDTLS_ERR_MPI_XXX or \c MBEDTLS_ERR_ASN1_XXX + * error code on failure. + */ +int mbedtls_ecdsa_sign_restartable( + mbedtls_ecp_group *grp, + mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, + const unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int (*f_rng_blind)(void *, unsigned char *, size_t), + void *p_rng_blind, + mbedtls_ecdsa_restart_ctx *rs_ctx); + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + +/** + * \brief This function computes the ECDSA signature of a + * previously-hashed message, in a restartable way. + * + * \note This function is like \c + * mbedtls_ecdsa_sign_det_ext() but it can return + * early and restart according to the limit set with + * \c mbedtls_ecp_set_max_ops() to reduce blocking. + * + * \note If the bitlength of the message hash is larger + * than the bitlength of the group order, then the + * hash is truncated as defined in Standards for + * Efficient Cryptography Group (SECG): SEC1 Elliptic + * Curve Cryptography, section 4.1.3, step 5. + * + * \see ecp.h + * + * \param grp The context for the elliptic curve to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param r The MPI context in which to store the first part + * the signature. This must be initialized. + * \param s The MPI context in which to store the second part + * the signature. This must be initialized. + * \param d The private signing key. This must be initialized + * and setup, for example through + * mbedtls_ecp_gen_privkey(). + * \param buf The hashed content to be signed. This must be a readable + * buffer of length \p blen Bytes. It may be \c NULL if + * \p blen is zero. + * \param blen The length of \p buf in Bytes. + * \param md_alg The hash algorithm used to hash the original data. + * \param f_rng_blind The RNG function used for blinding. This must not be + * \c NULL. + * \param p_rng_blind The RNG context to be passed to \p f_rng_blind. This may be + * \c NULL if \p f_rng_blind doesn't need a context parameter. + * \param rs_ctx The restart context to use. This may be \c NULL + * to disable restarting. If it is not \c NULL, it + * must point to an initialized restart context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c + * mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX, \c + * MBEDTLS_ERR_MPI_XXX or \c MBEDTLS_ERR_ASN1_XXX + * error code on failure. + */ +int mbedtls_ecdsa_sign_det_restartable( + mbedtls_ecp_group *grp, + mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg, + int (*f_rng_blind)(void *, unsigned char *, size_t), + void *p_rng_blind, + mbedtls_ecdsa_restart_ctx *rs_ctx); + +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +/** + * \brief This function verifies the ECDSA signature of a + * previously-hashed message. + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.4, step 3. + * + * \see ecp.h + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param buf The hashed content that was signed. This must be a readable + * buffer of length \p blen Bytes. It may be \c NULL if + * \p blen is zero. + * \param blen The length of \p buf in Bytes. + * \param Q The public key to use for verification. This must be + * initialized and setup. + * \param r The first integer of the signature. + * This must be initialized. + * \param s The second integer of the signature. + * This must be initialized. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX + * error code on failure. + */ +int mbedtls_ecdsa_verify(mbedtls_ecp_group *grp, + const unsigned char *buf, size_t blen, + const mbedtls_ecp_point *Q, const mbedtls_mpi *r, + const mbedtls_mpi *s); + +/** + * \brief This function verifies the ECDSA signature of a + * previously-hashed message, in a restartable manner + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.4, step 3. + * + * \see ecp.h + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param buf The hashed content that was signed. This must be a readable + * buffer of length \p blen Bytes. It may be \c NULL if + * \p blen is zero. + * \param blen The length of \p buf in Bytes. + * \param Q The public key to use for verification. This must be + * initialized and setup. + * \param r The first integer of the signature. + * This must be initialized. + * \param s The second integer of the signature. + * This must be initialized. + * \param rs_ctx The restart context to use. This may be \c NULL to disable + * restarting. If it is not \c NULL, it must point to an + * initialized restart context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX + * error code on failure. + */ +int mbedtls_ecdsa_verify_restartable(mbedtls_ecp_group *grp, + const unsigned char *buf, size_t blen, + const mbedtls_ecp_point *Q, + const mbedtls_mpi *r, + const mbedtls_mpi *s, + mbedtls_ecdsa_restart_ctx *rs_ctx); + +/** + * \brief This function computes the ECDSA signature and writes it + * to a buffer, serialized as defined in RFC-4492: + * Elliptic Curve Cryptography (ECC) Cipher Suites for + * Transport Layer Security (TLS). + * + * \warning It is not thread-safe to use the same context in + * multiple threads. + * + * \note The deterministic version is used if + * #MBEDTLS_ECDSA_DETERMINISTIC is defined. For more + * information, see RFC-6979: Deterministic Usage + * of the Digital Signature Algorithm (DSA) and Elliptic + * Curve Digital Signature Algorithm (ECDSA). + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.3, step 5. + * + * \see ecp.h + * + * \param ctx The ECDSA context to use. This must be initialized + * and have a group and private key bound to it, for example + * via mbedtls_ecdsa_genkey() or mbedtls_ecdsa_from_keypair(). + * \param md_alg The message digest that was used to hash the message. + * \param hash The message hash to be signed. This must be a readable + * buffer of length \p hlen Bytes. + * \param hlen The length of the hash \p hash in Bytes. + * \param sig The buffer to which to write the signature. This must be a + * writable buffer of length at least twice as large as the + * size of the curve used, plus 9. For example, 73 Bytes if + * a 256-bit curve is used. A buffer length of + * #MBEDTLS_ECDSA_MAX_LEN is always safe. + * \param sig_size The size of the \p sig buffer in bytes. + * \param slen The address at which to store the actual length of + * the signature written. Must not be \c NULL. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't use a context. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX, \c MBEDTLS_ERR_MPI_XXX or + * \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_ecdsa_write_signature(mbedtls_ecdsa_context *ctx, + mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t sig_size, size_t *slen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +/** + * \brief This function computes the ECDSA signature and writes it + * to a buffer, in a restartable way. + * + * \see \c mbedtls_ecdsa_write_signature() + * + * \note This function is like \c mbedtls_ecdsa_write_signature() + * but it can return early and restart according to the limit + * set with \c mbedtls_ecp_set_max_ops() to reduce blocking. + * + * \param ctx The ECDSA context to use. This must be initialized + * and have a group and private key bound to it, for example + * via mbedtls_ecdsa_genkey() or mbedtls_ecdsa_from_keypair(). + * \param md_alg The message digest that was used to hash the message. + * \param hash The message hash to be signed. This must be a readable + * buffer of length \p hlen Bytes. + * \param hlen The length of the hash \p hash in Bytes. + * \param sig The buffer to which to write the signature. This must be a + * writable buffer of length at least twice as large as the + * size of the curve used, plus 9. For example, 73 Bytes if + * a 256-bit curve is used. A buffer length of + * #MBEDTLS_ECDSA_MAX_LEN is always safe. + * \param sig_size The size of the \p sig buffer in bytes. + * \param slen The address at which to store the actual length of + * the signature written. Must not be \c NULL. + * \param f_rng The RNG function. This must not be \c NULL if + * #MBEDTLS_ECDSA_DETERMINISTIC is unset. Otherwise, + * it is unused and may be set to \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't use a context. + * \param rs_ctx The restart context to use. This may be \c NULL to disable + * restarting. If it is not \c NULL, it must point to an + * initialized restart context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX, \c MBEDTLS_ERR_MPI_XXX or + * \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_ecdsa_write_signature_restartable(mbedtls_ecdsa_context *ctx, + mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t sig_size, size_t *slen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_ecdsa_restart_ctx *rs_ctx); + +/** + * \brief This function reads and verifies an ECDSA signature. + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.4, step 3. + * + * \see ecp.h + * + * \param ctx The ECDSA context to use. This must be initialized + * and have a group and public key bound to it. + * \param hash The message hash that was signed. This must be a readable + * buffer of length \p hlen Bytes. + * \param hlen The size of the hash \p hash. + * \param sig The signature to read and verify. This must be a readable + * buffer of length \p slen Bytes. + * \param slen The size of \p sig in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid. + * \return #MBEDTLS_ERR_ECP_VERIFY_FAILED if there is a valid + * signature in \p sig, but its length is less than \p siglen. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_ERR_MPI_XXX + * error code on failure for any other reason. + */ +int mbedtls_ecdsa_read_signature(mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + const unsigned char *sig, size_t slen); + +/** + * \brief This function reads and verifies an ECDSA signature, + * in a restartable way. + * + * \see \c mbedtls_ecdsa_read_signature() + * + * \note This function is like \c mbedtls_ecdsa_read_signature() + * but it can return early and restart according to the limit + * set with \c mbedtls_ecp_set_max_ops() to reduce blocking. + * + * \param ctx The ECDSA context to use. This must be initialized + * and have a group and public key bound to it. + * \param hash The message hash that was signed. This must be a readable + * buffer of length \p hlen Bytes. + * \param hlen The size of the hash \p hash. + * \param sig The signature to read and verify. This must be a readable + * buffer of length \p slen Bytes. + * \param slen The size of \p sig in Bytes. + * \param rs_ctx The restart context to use. This may be \c NULL to disable + * restarting. If it is not \c NULL, it must point to an + * initialized restart context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid. + * \return #MBEDTLS_ERR_ECP_VERIFY_FAILED if there is a valid + * signature in \p sig, but its length is less than \p siglen. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_ERR_MPI_XXX + * error code on failure for any other reason. + */ +int mbedtls_ecdsa_read_signature_restartable(mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + const unsigned char *sig, size_t slen, + mbedtls_ecdsa_restart_ctx *rs_ctx); + +/** + * \brief This function generates an ECDSA keypair on the given curve. + * + * \see ecp.h + * + * \param ctx The ECDSA context to store the keypair in. + * This must be initialized. + * \param gid The elliptic curve to use. One of the various + * \c MBEDTLS_ECP_DP_XXX macros depending on configuration. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX code on failure. + */ +int mbedtls_ecdsa_genkey(mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng); + +/** + * \brief This function sets up an ECDSA context from an EC key pair. + * + * \see ecp.h + * + * \param ctx The ECDSA context to setup. This must be initialized. + * \param key The EC key to use. This must be initialized and hold + * a private-public key pair or a public key. In the former + * case, the ECDSA context may be used for signature creation + * and verification after this call. In the latter case, it + * may be used for signature verification. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX code on failure. + */ +int mbedtls_ecdsa_from_keypair(mbedtls_ecdsa_context *ctx, + const mbedtls_ecp_keypair *key); + +/** + * \brief This function initializes an ECDSA context. + * + * \param ctx The ECDSA context to initialize. + * This must not be \c NULL. + */ +void mbedtls_ecdsa_init(mbedtls_ecdsa_context *ctx); + +/** + * \brief This function frees an ECDSA context. + * + * \param ctx The ECDSA context to free. This may be \c NULL, + * in which case this function does nothing. If it + * is not \c NULL, it must be initialized. + */ +void mbedtls_ecdsa_free(mbedtls_ecdsa_context *ctx); + +#if defined(MBEDTLS_ECP_RESTARTABLE) +/** + * \brief Initialize a restart context. + * + * \param ctx The restart context to initialize. + * This must not be \c NULL. + */ +void mbedtls_ecdsa_restart_init(mbedtls_ecdsa_restart_ctx *ctx); + +/** + * \brief Free the components of a restart context. + * + * \param ctx The restart context to free. This may be \c NULL, + * in which case this function does nothing. If it + * is not \c NULL, it must be initialized. + */ +void mbedtls_ecdsa_restart_free(mbedtls_ecdsa_restart_ctx *ctx); +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ECDSA_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ecjpake.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ecjpake.h new file mode 100644 index 0000000000..c9bc0aa378 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ecjpake.h @@ -0,0 +1,296 @@ +/** + * \file ecjpake.h + * + * \brief Elliptic curve J-PAKE + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ECJPAKE_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ECJPAKE_H +#include "mbedtls/private_access.h" + +/* + * J-PAKE is a password-authenticated key exchange that allows deriving a + * strong shared secret from a (potentially low entropy) pre-shared + * passphrase, with forward secrecy and mutual authentication. + * https://en.wikipedia.org/wiki/Password_Authenticated_Key_Exchange_by_Juggling + * + * This file implements the Elliptic Curve variant of J-PAKE, + * as defined in Chapter 7.4 of the Thread v1.0 Specification, + * available to members of the Thread Group http://threadgroup.org/ + * + * As the J-PAKE algorithm is inherently symmetric, so is our API. + * Each party needs to send its first round message, in any order, to the + * other party, then each sends its second round message, in any order. + * The payloads are serialized in a way suitable for use in TLS, but could + * also be use outside TLS. + */ +#include "tf-psa-crypto/build_info.h" + +#include "mbedtls/private/ecp.h" +#include "mbedtls/md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Roles in the EC J-PAKE exchange + */ +typedef enum { + MBEDTLS_ECJPAKE_CLIENT = 0, /**< Client */ + MBEDTLS_ECJPAKE_SERVER, /**< Server */ + MBEDTLS_ECJPAKE_NONE, /**< Undefined */ +} mbedtls_ecjpake_role; + +/** + * EC J-PAKE context structure. + * + * J-PAKE is a symmetric protocol, except for the identifiers used in + * Zero-Knowledge Proofs, and the serialization of the second message + * (KeyExchange) as defined by the Thread spec. + * + * In order to benefit from this symmetry, we choose a different naming + * convention from the Thread v1.0 spec. Correspondence is indicated in the + * description as a pair C: client name, S: server name + */ +typedef struct mbedtls_ecjpake_context { + mbedtls_md_type_t MBEDTLS_PRIVATE(md_type); /**< Hash to use */ + mbedtls_ecp_group MBEDTLS_PRIVATE(grp); /**< Elliptic curve */ + mbedtls_ecjpake_role MBEDTLS_PRIVATE(role); /**< Are we client or server? */ + int MBEDTLS_PRIVATE(point_format); /**< Format for point export */ + + mbedtls_ecp_point MBEDTLS_PRIVATE(Xm1); /**< My public key 1 C: X1, S: X3 */ + mbedtls_ecp_point MBEDTLS_PRIVATE(Xm2); /**< My public key 2 C: X2, S: X4 */ + mbedtls_ecp_point MBEDTLS_PRIVATE(Xp1); /**< Peer public key 1 C: X3, S: X1 */ + mbedtls_ecp_point MBEDTLS_PRIVATE(Xp2); /**< Peer public key 2 C: X4, S: X2 */ + mbedtls_ecp_point MBEDTLS_PRIVATE(Xp); /**< Peer public key C: Xs, S: Xc */ + + mbedtls_mpi MBEDTLS_PRIVATE(xm1); /**< My private key 1 C: x1, S: x3 */ + mbedtls_mpi MBEDTLS_PRIVATE(xm2); /**< My private key 2 C: x2, S: x4 */ + + mbedtls_mpi MBEDTLS_PRIVATE(s); /**< Pre-shared secret (passphrase) */ +} mbedtls_ecjpake_context; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief Initialize an ECJPAKE context. + * + * \param ctx The ECJPAKE context to initialize. + * This must not be \c NULL. + */ +void mbedtls_ecjpake_init(mbedtls_ecjpake_context *ctx); + +/** + * \brief Set up an ECJPAKE context for use. + * + * \note Currently the only values for hash/curve allowed by the + * standard are #MBEDTLS_MD_SHA256/#MBEDTLS_ECP_DP_SECP256R1. + * + * \param ctx The ECJPAKE context to set up. This must be initialized. + * \param role The role of the caller. This must be either + * #MBEDTLS_ECJPAKE_CLIENT or #MBEDTLS_ECJPAKE_SERVER. + * \param hash The identifier of the hash function to use, + * for example #MBEDTLS_MD_SHA256. + * \param curve The identifier of the elliptic curve to use, + * for example #MBEDTLS_ECP_DP_SECP256R1. + * \param secret The pre-shared secret (passphrase). This must be + * a readable not empty buffer of length \p len Bytes. It need + * only be valid for the duration of this call. + * \param len The length of the pre-shared secret \p secret. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_ecjpake_setup(mbedtls_ecjpake_context *ctx, + mbedtls_ecjpake_role role, + mbedtls_md_type_t hash, + mbedtls_ecp_group_id curve, + const unsigned char *secret, + size_t len); + +/** + * \brief Set the point format for future reads and writes. + * + * \param ctx The ECJPAKE context to configure. + * \param point_format The point format to use: + * #MBEDTLS_ECP_PF_UNCOMPRESSED (default) + * or #MBEDTLS_ECP_PF_COMPRESSED. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if \p point_format + * is invalid. + */ +int mbedtls_ecjpake_set_point_format(mbedtls_ecjpake_context *ctx, + int point_format); + +/** + * \brief Check if an ECJPAKE context is ready for use. + * + * \param ctx The ECJPAKE context to check. This must be + * initialized. + * + * \return \c 0 if the context is ready for use. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA otherwise. + */ +int mbedtls_ecjpake_check(const mbedtls_ecjpake_context *ctx); + +/** + * \brief Generate and write the first round message + * (TLS: contents of the Client/ServerHello extension, + * excluding extension type and length bytes). + * + * \param ctx The ECJPAKE context to use. This must be + * initialized and set up. + * \param buf The buffer to write the contents to. This must be a + * writable buffer of length \p len Bytes. + * \param len The length of \p buf in Bytes. + * \param olen The address at which to store the total number + * of Bytes written to \p buf. This must not be \c NULL. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. This + * may be \c NULL if \p f_rng doesn't use a context. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_ecjpake_write_round_one(mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +/** + * \brief Read and process the first round message + * (TLS: contents of the Client/ServerHello extension, + * excluding extension type and length bytes). + * + * \param ctx The ECJPAKE context to use. This must be initialized + * and set up. + * \param buf The buffer holding the first round message. This must + * be a readable buffer of length \p len Bytes. + * \param len The length in Bytes of \p buf. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_ecjpake_read_round_one(mbedtls_ecjpake_context *ctx, + const unsigned char *buf, + size_t len); + +/** + * \brief Generate and write the second round message + * (TLS: contents of the Client/ServerKeyExchange). + * + * \param ctx The ECJPAKE context to use. This must be initialized, + * set up, and already have performed round one. + * \param buf The buffer to write the round two contents to. + * This must be a writable buffer of length \p len Bytes. + * \param len The size of \p buf in Bytes. + * \param olen The address at which to store the total number of Bytes + * written to \p buf. This must not be \c NULL. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. This + * may be \c NULL if \p f_rng doesn't use a context. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_ecjpake_write_round_two(mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +/** + * \brief Read and process the second round message + * (TLS: contents of the Client/ServerKeyExchange). + * + * \param ctx The ECJPAKE context to use. This must be initialized + * and set up and already have performed round one. + * \param buf The buffer holding the second round message. This must + * be a readable buffer of length \p len Bytes. + * \param len The length in Bytes of \p buf. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_ecjpake_read_round_two(mbedtls_ecjpake_context *ctx, + const unsigned char *buf, + size_t len); + +/** + * \brief Derive the shared secret + * (TLS: Pre-Master Secret). + * + * \param ctx The ECJPAKE context to use. This must be initialized, + * set up and have performed both round one and two. + * \param buf The buffer to write the derived secret to. This must + * be a writable buffer of length \p len Bytes. + * \param len The length of \p buf in Bytes. + * \param olen The address at which to store the total number of Bytes + * written to \p buf. This must not be \c NULL. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. This + * may be \c NULL if \p f_rng doesn't use a context. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_ecjpake_derive_secret(mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +/** + * \brief Write the shared key material to be passed to a Key + * Derivation Function as described in RFC8236. + * + * \param ctx The ECJPAKE context to use. This must be initialized, + * set up and have performed both round one and two. + * \param buf The buffer to write the derived secret to. This must + * be a writable buffer of length \p len Bytes. + * \param len The length of \p buf in Bytes. + * \param olen The address at which to store the total number of bytes + * written to \p buf. This must not be \c NULL. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. This + * may be \c NULL if \p f_rng doesn't use a context. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_ecjpake_write_shared_key(mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +/** + * \brief This clears an ECJPAKE context and frees any + * embedded data structure. + * + * \param ctx The ECJPAKE context to free. This may be \c NULL, + * in which case this function does nothing. If it is not + * \c NULL, it must point to an initialized ECJPAKE context. + */ +void mbedtls_ecjpake_free(mbedtls_ecjpake_context *ctx); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_ecjpake_self_test(int verbose); + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ECJPAKE_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ecp.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ecp.h new file mode 100644 index 0000000000..bd2b454fed --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ecp.h @@ -0,0 +1,1463 @@ +/** + * \file ecp.h + * + * \brief This file provides an API for Elliptic Curves over GF(P) (ECP). + * + * The use of ECP in cryptography and TLS is defined in + * Standards for Efficient Cryptography Group (SECG): SEC1 + * Elliptic Curve Cryptography and + * RFC-4492: Elliptic Curve Cryptography (ECC) Cipher Suites + * for Transport Layer Security (TLS). + * + * RFC-2409: The Internet Key Exchange (IKE) defines ECP + * group types. + * + */ + +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ECP_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ECP_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" +#include "mbedtls/platform_util.h" + +#include "mbedtls/private/bignum.h" + +/* + * ECP error codes + */ +/** Bad input parameters to function. */ +#define MBEDTLS_ERR_ECP_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT +/** The buffer is too small to write to. */ +#define MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL PSA_ERROR_BUFFER_TOO_SMALL +/** The requested feature is not available, for example, the requested curve is not supported. */ +#define MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE PSA_ERROR_NOT_SUPPORTED +/** The signature is not valid. */ +#define MBEDTLS_ERR_ECP_VERIFY_FAILED PSA_ERROR_INVALID_SIGNATURE +/** Memory allocation failed. */ +#define MBEDTLS_ERR_ECP_ALLOC_FAILED PSA_ERROR_INSUFFICIENT_MEMORY +/** Generation of random value, such as ephemeral key, failed. */ +#define MBEDTLS_ERR_ECP_RANDOM_FAILED PSA_ERROR_INSUFFICIENT_ENTROPY +/** Invalid private or public key. */ +#define MBEDTLS_ERR_ECP_INVALID_KEY -0x4C80 +/** Operation in progress, call again with the same parameters to continue. */ +#define MBEDTLS_ERR_ECP_IN_PROGRESS PSA_OPERATION_INCOMPLETE + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/* Flags indicating whether to include code that is specific to certain + * types of curves. These flags are for internal library use only. */ +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +#define MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED +#endif +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) || \ + defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) +#define MBEDTLS_ECP_MONTGOMERY_ENABLED +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED OR MBEDTLS_ECP_DP_CURVE448_ENABLED */ +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Domain-parameter identifiers: curve, subgroup, and generator. + * + * \note Only curves over prime fields are supported. + * + * \warning This library does not support validation of arbitrary domain + * parameters. Therefore, only standardized domain parameters from trusted + * sources should be used. See mbedtls_ecp_group_load(). + */ +/* Note: when adding a new curve: + * - Add it at the end of this enum, otherwise you'll break the ABI by + * changing the numerical value for existing curves. + * - Increment MBEDTLS_ECP_DP_MAX below if needed. + * - Update the calculation of MBEDTLS_ECP_MAX_BITS below. + * - Add the corresponding MBEDTLS_ECP_DP_xxx_ENABLED macro definition to + * mbedtls_config.h. + * - List the curve as a dependency of MBEDTLS_ECP_C and + * MBEDTLS_ECDSA_C if supported in check_config.h. + * - Add the curve to the appropriate curve type macro + * MBEDTLS_ECP_yyy_ENABLED above. + * - Add the necessary definitions to ecp_curves.c. + * - Add the curve to the ecp_supported_curves array in ecp.c. + * - Add the curve to applicable profiles in x509_crt.c. + * - Add the curve to applicable presets in ssl_tls.c. + */ +typedef enum { + MBEDTLS_ECP_DP_NONE = 0, /*!< Curve not defined. */ + MBEDTLS_ECP_DP_SECP256R1, /*!< Domain parameters for the 256-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_SECP384R1, /*!< Domain parameters for the 384-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_SECP521R1, /*!< Domain parameters for the 521-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_BP256R1, /*!< Domain parameters for 256-bit Brainpool curve. */ + MBEDTLS_ECP_DP_BP384R1, /*!< Domain parameters for 384-bit Brainpool curve. */ + MBEDTLS_ECP_DP_BP512R1, /*!< Domain parameters for 512-bit Brainpool curve. */ + MBEDTLS_ECP_DP_CURVE25519, /*!< Domain parameters for Curve25519. */ + MBEDTLS_ECP_DP_SECP256K1, /*!< Domain parameters for 256-bit "Koblitz" curve. */ + MBEDTLS_ECP_DP_CURVE448, /*!< Domain parameters for Curve448. */ +} mbedtls_ecp_group_id; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * The number of supported curves, plus one for #MBEDTLS_ECP_DP_NONE. + */ +#define MBEDTLS_ECP_DP_MAX 14 + +/* + * Curve types + */ +typedef enum { + MBEDTLS_ECP_TYPE_NONE = 0, + MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS, /* y^2 = x^3 + a x + b */ + MBEDTLS_ECP_TYPE_MONTGOMERY, /* y^2 = x^3 + a x^2 + x */ +} mbedtls_ecp_curve_type; + +/** + * Curve information, for use by other modules. + * + * The fields of this structure are part of the public API and can be + * accessed directly by applications. Future versions of the library may + * add extra fields or reorder existing fields. + */ +typedef struct mbedtls_ecp_curve_info { + mbedtls_ecp_group_id grp_id; /*!< An internal identifier. */ + uint16_t tls_id; /*!< The TLS NamedCurve identifier. */ + uint16_t bit_size; /*!< The curve size in bits. */ + const char *name; /*!< A human-friendly name. */ +} mbedtls_ecp_curve_info; +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +/** + * \brief The ECP point structure, in Jacobian coordinates. + * + * \note All functions expect and return points satisfying + * the following condition: Z == 0 or + * Z == 1. Other values of \p Z are + * used only by internal functions. + * The point is zero, or "at infinity", if Z == 0. + * Otherwise, \p X and \p Y are its standard (affine) + * coordinates. + */ +typedef struct mbedtls_ecp_point { + mbedtls_mpi MBEDTLS_PRIVATE(X); /*!< The X coordinate of the ECP point. */ + mbedtls_mpi MBEDTLS_PRIVATE(Y); /*!< The Y coordinate of the ECP point. */ + mbedtls_mpi MBEDTLS_PRIVATE(Z); /*!< The Z coordinate of the ECP point. */ +} +mbedtls_ecp_point; + +#define MBEDTLS_ECP_POINT_INIT { MBEDTLS_MPI_INIT, MBEDTLS_MPI_INIT, MBEDTLS_MPI_INIT } + +/** + * \brief The ECP group structure. + * + * We consider two types of curve equations: + *
  • Short Weierstrass: y^2 = x^3 + A x + B mod P + * (SEC1 + RFC-4492)
  • + *
  • Montgomery: y^2 = x^3 + A x^2 + x mod P (Curve25519, + * Curve448)
+ * In both cases, the generator (\p G) for a prime-order subgroup is fixed. + * + * For Short Weierstrass, this subgroup is the whole curve, and its + * cardinality is denoted by \p N. Our code requires that \p N is an + * odd prime as mbedtls_ecp_mul() requires an odd number, and + * mbedtls_ecdsa_sign() requires that it is prime for blinding purposes. + * + * The default implementation only initializes \p A without setting it to the + * authentic value for curves with A = -3(SECP256R1, etc), in which + * case you need to load \p A by yourself when using domain parameters directly, + * for example: + * \code + * mbedtls_mpi_init(&A); + * mbedtls_ecp_group_init(&grp); + * CHECK_RETURN(mbedtls_ecp_group_load(&grp, grp_id)); + * if (mbedtls_ecp_group_a_is_minus_3(&grp)) { + * CHECK_RETURN(mbedtls_mpi_sub_int(&A, &grp.P, 3)); + * } else { + * CHECK_RETURN(mbedtls_mpi_copy(&A, &grp.A)); + * } + * + * do_something_with_a(&A); + * + * cleanup: + * mbedtls_mpi_free(&A); + * mbedtls_ecp_group_free(&grp); + * \endcode + * + * For Montgomery curves, we do not store \p A, but (A + 2) / 4, + * which is the quantity used in the formulas. Additionally, \p nbits is + * not the size of \p N but the required size for private keys. + * + * If \p modp is NULL, reduction modulo \p P is done using a generic algorithm. + * Otherwise, \p modp must point to a function that takes an \p mbedtls_mpi in the + * range of 0..2^(2*pbits)-1, and transforms it in-place to an integer + * which is congruent mod \p P to the given MPI, and is close enough to \p pbits + * in size, so that it may be efficiently brought in the 0..P-1 range by a few + * additions or subtractions. Therefore, it is only an approximate modular + * reduction. It must return 0 on success and non-zero on failure. + * + * \note Alternative implementations of the ECP module must obey the + * following constraints. + * * Group IDs must be distinct: if two group structures have + * the same ID, then they must be identical. + * * The fields \c id, \c P, \c A, \c B, \c G, \c N, + * \c pbits and \c nbits must have the same type and semantics + * as in the built-in implementation. + * They must be available for reading, but direct modification + * of these fields does not need to be supported. + * They do not need to be at the same offset in the structure. + */ +typedef struct mbedtls_ecp_group { + mbedtls_ecp_group_id id; /*!< An internal group identifier. */ + mbedtls_mpi P; /*!< The prime modulus of the base field. */ + mbedtls_mpi A; /*!< For Short Weierstrass: \p A in the equation. Note that + \p A is not set to the authentic value in some cases. + Refer to detailed description of ::mbedtls_ecp_group if + using domain parameters in the structure. + For Montgomery curves: (A + 2) / 4. */ + mbedtls_mpi B; /*!< For Short Weierstrass: \p B in the equation. + For Montgomery curves: unused. */ + mbedtls_ecp_point G; /*!< The generator of the subgroup used. */ + mbedtls_mpi N; /*!< The order of \p G. */ + size_t pbits; /*!< The number of bits in \p P.*/ + size_t nbits; /*!< For Short Weierstrass: The number of bits in \p P. + For Montgomery curves: the number of bits in the + private keys. */ + /* End of public fields */ + + unsigned int MBEDTLS_PRIVATE(h); /*!< \internal 1 if the constants are static. */ + int(*MBEDTLS_PRIVATE(modp))(mbedtls_mpi *); /*!< The function for fast pseudo-reduction + mod \p P (see above).*/ + int(*MBEDTLS_PRIVATE(t_pre))(mbedtls_ecp_point *, void *); /*!< Unused. */ + int(*MBEDTLS_PRIVATE(t_post))(mbedtls_ecp_point *, void *); /*!< Unused. */ + void *MBEDTLS_PRIVATE(t_data); /*!< Unused. */ + mbedtls_ecp_point *MBEDTLS_PRIVATE(T); /*!< Pre-computed points for ecp_mul_comb(). */ + size_t MBEDTLS_PRIVATE(T_size); /*!< The number of dynamic allocated pre-computed points. */ +} +mbedtls_ecp_group; + +#define MBEDTLS_ECP_GROUP_INIT { MBEDTLS_ECP_DP_NONE, MBEDTLS_MPI_INIT, MBEDTLS_MPI_INIT, \ + MBEDTLS_MPI_INIT, MBEDTLS_ECP_POINT_INIT, MBEDTLS_MPI_INIT, \ + 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0 } + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in mbedtls_config.h, or define them using the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_ECP_WINDOW_SIZE) +/* + * Maximum "window" size used for point multiplication. + * Default: a point where higher memory usage yields diminishing performance + * returns. + * Minimum value: 2. Maximum value: 7. + * + * Result is an array of at most ( 1 << ( MBEDTLS_ECP_WINDOW_SIZE - 1 ) ) + * points used for point multiplication. This value is directly tied to EC + * peak memory usage, so decreasing it by one should roughly cut memory usage + * by two (if large curves are in use). + * + * Reduction in size may reduce speed, but larger curves are impacted first. + * Sample performances (in ECDHE handshakes/s, with FIXED_POINT_OPTIM = 1): + * w-size: 6 5 4 3 2 + * 521 145 141 135 120 97 + * 384 214 209 198 177 146 + * 256 320 320 303 262 226 + * 224 475 475 453 398 342 + * 192 640 640 633 587 476 + */ +#define MBEDTLS_ECP_WINDOW_SIZE 4 /**< The maximum window size used. */ +#endif /* MBEDTLS_ECP_WINDOW_SIZE */ + +#if !defined(MBEDTLS_ECP_FIXED_POINT_OPTIM) +/* + * Trade code size for speed on fixed-point multiplication. + * + * This speeds up repeated multiplication of the generator (that is, the + * multiplication in ECDSA signatures, and half of the multiplications in + * ECDSA verification and ECDHE) by a factor roughly 3 to 4. + * + * For each n-bit Short Weierstrass curve that is enabled, this adds 4n bytes + * of code size if n < 384 and 8n otherwise. + * + * Change this value to 0 to reduce code size. + */ +#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up. */ +#endif /* MBEDTLS_ECP_FIXED_POINT_OPTIM */ + +/** \} name SECTION: Module settings */ + +/** + * The maximum size of the groups, that is, of \c N and \c P. + */ +#if !defined(MBEDTLS_ECP_LIGHT) +/* Dummy definition to help code that has optional ECP support and + * defines an MBEDTLS_ECP_MAX_BYTES-sized array unconditionally. */ +#define MBEDTLS_ECP_MAX_BITS 1 +/* Note: the curves must be listed in DECREASING size! */ +#elif defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +#define MBEDTLS_ECP_MAX_BITS 521 +#elif defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) +#define MBEDTLS_ECP_MAX_BITS 512 +#elif defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) +#define MBEDTLS_ECP_MAX_BITS 448 +#elif defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) +#define MBEDTLS_ECP_MAX_BITS 384 +#elif defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +#define MBEDTLS_ECP_MAX_BITS 384 +#elif defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) +#define MBEDTLS_ECP_MAX_BITS 256 +#elif defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +#define MBEDTLS_ECP_MAX_BITS 256 +#elif defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +#define MBEDTLS_ECP_MAX_BITS 256 +#elif defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +#define MBEDTLS_ECP_MAX_BITS 255 +#else /* !MBEDTLS_ECP_LIGHT */ +#error "Missing definition of MBEDTLS_ECP_MAX_BITS" +#endif /* !MBEDTLS_ECP_LIGHT */ + +#define MBEDTLS_ECP_MAX_BYTES ((MBEDTLS_ECP_MAX_BITS + 7) / 8) +#define MBEDTLS_ECP_MAX_PT_LEN (2 * MBEDTLS_ECP_MAX_BYTES + 1) + +#if defined(MBEDTLS_ECP_RESTARTABLE) + +/** + * \brief Internal restart context for multiplication + * + * \note Opaque struct + */ +typedef struct mbedtls_ecp_restart_mul mbedtls_ecp_restart_mul_ctx; + +/** + * \brief Internal restart context for ecp_muladd() + * + * \note Opaque struct + */ +typedef struct mbedtls_ecp_restart_muladd mbedtls_ecp_restart_muladd_ctx; + +/** + * \brief General context for resuming ECC operations + */ +typedef struct { + unsigned MBEDTLS_PRIVATE(ops_done); /*!< current ops count */ + unsigned MBEDTLS_PRIVATE(depth); /*!< call depth (0 = top-level) */ + mbedtls_ecp_restart_mul_ctx *MBEDTLS_PRIVATE(rsm); /*!< ecp_mul_comb() sub-context */ + mbedtls_ecp_restart_muladd_ctx *MBEDTLS_PRIVATE(ma); /*!< ecp_muladd() sub-context */ +} mbedtls_ecp_restart_ctx; + +#define MBEDTLS_ECP_RESTART_INIT { 0, 0, NULL, NULL } + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/* + * Operation counts for restartable functions + */ +#define MBEDTLS_ECP_OPS_CHK 3 /*!< basic ops count for ecp_check_pubkey() */ +#define MBEDTLS_ECP_OPS_DBL 8 /*!< basic ops count for ecp_double_jac() */ +#define MBEDTLS_ECP_OPS_ADD 11 /*!< basic ops count for see ecp_add_mixed() */ +#define MBEDTLS_ECP_OPS_INV 120 /*!< empirical equivalent for mpi_mod_inv() */ + +/** + * \brief Internal; for restartable functions in other modules. + * Check and update basic ops budget. + * + * \param grp Group structure + * \param rs_ctx Restart context + * \param ops Number of basic ops to do + * + * \return \c 0 if doing \p ops basic ops is still allowed, + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS otherwise. + */ +int mbedtls_ecp_check_budget(const mbedtls_ecp_group *grp, + mbedtls_ecp_restart_ctx *rs_ctx, + unsigned ops); + +/* Utility macro for checking and updating ops budget */ +#define MBEDTLS_ECP_BUDGET(ops) \ + MBEDTLS_MPI_CHK(mbedtls_ecp_check_budget(grp, rs_ctx, \ + (unsigned) (ops))); +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#else /* MBEDTLS_ECP_RESTARTABLE */ + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +#define MBEDTLS_ECP_BUDGET(ops) /* no-op; for compatibility */ +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +/* We want to declare restartable versions of existing functions anyway */ +typedef void mbedtls_ecp_restart_ctx; + +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +/** + * \brief The ECP key-pair structure. + * + * A generic key-pair that may be used for ECDSA and fixed ECDH, for example. + * + * \note Members are deliberately in the same order as in the + * ::mbedtls_ecdsa_context structure. + */ +typedef struct mbedtls_ecp_keypair { + mbedtls_ecp_group MBEDTLS_PRIVATE(grp); /*!< Elliptic curve and base point */ + mbedtls_mpi MBEDTLS_PRIVATE(d); /*!< our secret value */ + mbedtls_ecp_point MBEDTLS_PRIVATE(Q); /*!< our public value */ +} +mbedtls_ecp_keypair; + +#define MBEDTLS_ECP_KEYPAIR_INIT { MBEDTLS_ECP_GROUP_INIT, MBEDTLS_MPI_INIT, \ + MBEDTLS_ECP_POINT_INIT } + +/** + * The uncompressed point format for Short Weierstrass curves + * (MBEDTLS_ECP_DP_SECP_XXX and MBEDTLS_ECP_DP_BP_XXX). + */ +#define MBEDTLS_ECP_PF_UNCOMPRESSED 0 +/** + * The compressed point format for Short Weierstrass curves + * (MBEDTLS_ECP_DP_SECP_XXX and MBEDTLS_ECP_DP_BP_XXX). + */ +#define MBEDTLS_ECP_PF_COMPRESSED 1 + +/* + * Some other constants from RFC 4492 + */ +#define MBEDTLS_ECP_TLS_NAMED_CURVE 3 /**< The named_curve of ECCurveType. */ + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +#if defined(MBEDTLS_ECP_RESTARTABLE) +/** + * \brief Set the maximum number of basic operations done in a row. + * + * If more operations are needed to complete a computation, + * #MBEDTLS_ERR_ECP_IN_PROGRESS will be returned by the + * function performing the computation. It is then the + * caller's responsibility to either call again with the same + * parameters until it returns 0 or an error code; or to free + * the restart context if the operation is to be aborted. + * + * It is strictly required that all input parameters and the + * restart context be the same on successive calls for the + * same operation, but output parameters need not be the + * same; they must not be used until the function finally + * returns 0. + * + * This only applies to functions whose documentation + * mentions they may return #MBEDTLS_ERR_ECP_IN_PROGRESS. + * For functions that accept a "restart context" + * argument, passing NULL disables restart and makes the + * function equivalent to the function with the same name + * with \c _restartable removed. For functions in the ECDH + * module, restart is disabled unless the function accepts + * an "ECDH context" argument and + * mbedtls_ecdh_enable_restart() was previously called on + * that context. For function in the SSL module, restart is + * only enabled for specific sides and key exchanges + * (currently only for clients and ECDHE-ECDSA). + * + * \warning Using the PSA interruptible interfaces with keys in local + * storage and no accelerator driver will also call this + * function to set the values specified via those interfaces, + * overwriting values previously set. Care should be taken if + * mixing these two interfaces. + * + * \param max_ops Maximum number of basic operations done in a row. + * Default: 0 (unlimited). + * Lower (non-zero) values mean ECC functions will block for + * a lesser maximum amount of time. + * + * \note A "basic operation" is defined as a rough equivalent of a + * multiplication in GF(p) for the NIST P-256 curve. + * As an indication, with default settings, a scalar + * multiplication (full run of \c mbedtls_ecp_mul()) is: + * - about 3300 basic operations for P-256 + * - about 9400 basic operations for P-384 + * + * \note Very low values are not always respected: sometimes + * functions need to block for a minimum number of + * operations, and will do so even if max_ops is set to a + * lower value. That minimum depends on the curve size, and + * can be made lower by decreasing the value of + * \c MBEDTLS_ECP_WINDOW_SIZE. As an indication, here is the + * lowest effective value for various curves and values of + * that parameter (w for short): + * w=6 w=5 w=4 w=3 w=2 + * P-256 208 208 160 136 124 + * P-384 682 416 320 272 248 + * P-521 1364 832 640 544 496 + * + * \note This setting is currently ignored by Curve25519. + */ +void mbedtls_ecp_set_max_ops(unsigned max_ops); + +/** + * \brief Check if restart is enabled (max_ops != 0) + * + * \return \c 0 if \c max_ops == 0 (restart disabled) + * \return \c 1 otherwise (restart enabled) + */ +int mbedtls_ecp_restart_is_enabled(void); +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +/* + * Get the type of a curve + */ +mbedtls_ecp_curve_type mbedtls_ecp_get_type(const mbedtls_ecp_group *grp); + +/** + * \brief This function retrieves the information defined in + * mbedtls_ecp_curve_info() for all supported curves. + * + * \note This function returns information about all curves + * supported by the library. Some curves may not be + * supported for all algorithms. Call + * mbedtls_ecdsa_can_do() to check if a curve is + * supported for ECDSA. + * + * \return A statically allocated array. The last entry is 0. + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list(void); + +/** + * \brief This function retrieves the list of internal group + * identifiers of all supported curves in the order of + * preference. + * + * \note This function returns information about all curves + * supported by the library. Some curves may not be + * supported for all algorithms. Call + * mbedtls_ecdsa_can_do() to check if a curve is + * supported for ECDSA. + * + * \return A statically allocated array, + * terminated with MBEDTLS_ECP_DP_NONE. + */ +const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list(void); + +/** + * \brief This function retrieves curve information from an internal + * group identifier. + * + * \param grp_id An \c MBEDTLS_ECP_DP_XXX value. + * + * \return The associated curve information on success. + * \return NULL on failure. + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id(mbedtls_ecp_group_id grp_id); + +/** + * \brief This function retrieves curve information from a TLS + * NamedCurve value. + * + * \param tls_id An \c MBEDTLS_ECP_DP_XXX value. + * + * \return The associated curve information on success. + * \return NULL on failure. + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id(uint16_t tls_id); + +/** + * \brief This function retrieves curve information from a + * human-readable name. + * + * \param name The human-readable name. + * + * \return The associated curve information on success. + * \return NULL on failure. + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name(const char *name); + +/** + * \brief This function initializes a point as zero. + * + * \param pt The point to initialize. + */ +void mbedtls_ecp_point_init(mbedtls_ecp_point *pt); + +/** + * \brief This function initializes an ECP group context + * without loading any domain parameters. + * + * \note After this function is called, domain parameters + * for various ECP groups can be loaded through the + * mbedtls_ecp_group_load() or mbedtls_ecp_tls_read_group() + * functions. + */ +void mbedtls_ecp_group_init(mbedtls_ecp_group *grp); + +/** + * \brief This function initializes a key pair as an invalid one. + * + * \param key The key pair to initialize. + */ +void mbedtls_ecp_keypair_init(mbedtls_ecp_keypair *key); + +/** + * \brief This function frees the components of a point. + * + * \param pt The point to free. + */ +void mbedtls_ecp_point_free(mbedtls_ecp_point *pt); + +/** + * \brief This function frees the components of an ECP group. + * + * \param grp The group to free. This may be \c NULL, in which + * case this function returns immediately. If it is not + * \c NULL, it must point to an initialized ECP group. + */ +void mbedtls_ecp_group_free(mbedtls_ecp_group *grp); + +/** + * \brief This function frees the components of a key pair. + * + * \param key The key pair to free. This may be \c NULL, in which + * case this function returns immediately. If it is not + * \c NULL, it must point to an initialized ECP key pair. + */ +void mbedtls_ecp_keypair_free(mbedtls_ecp_keypair *key); + +#if defined(MBEDTLS_ECP_RESTARTABLE) +/** + * \brief Initialize a restart context. + * + * \param ctx The restart context to initialize. This must + * not be \c NULL. + */ +void mbedtls_ecp_restart_init(mbedtls_ecp_restart_ctx *ctx); + +/** + * \brief Free the components of a restart context. + * + * \param ctx The restart context to free. This may be \c NULL, in which + * case this function returns immediately. If it is not + * \c NULL, it must point to an initialized restart context. + */ +void mbedtls_ecp_restart_free(mbedtls_ecp_restart_ctx *ctx); +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +/** + * \brief This function copies the contents of point \p Q into + * point \p P. + * + * \param P The destination point. This must be initialized. + * \param Q The source point. This must be initialized. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return Another negative error code for other kinds of failure. + */ +int mbedtls_ecp_copy(mbedtls_ecp_point *P, const mbedtls_ecp_point *Q); + +/** + * \brief This function copies the contents of group \p src into + * group \p dst. + * + * \param dst The destination group. This must be initialized. + * \param src The source group. This must be initialized. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_group_copy(mbedtls_ecp_group *dst, + const mbedtls_ecp_group *src); + +/** + * \brief This function sets a point to the point at infinity. + * + * \param pt The point to set. This must be initialized. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_set_zero(mbedtls_ecp_point *pt); + +/** + * \brief This function checks if a point is the point at infinity. + * + * \param pt The point to test. This must be initialized. + * + * \return \c 1 if the point is zero. + * \return \c 0 if the point is non-zero. + * \return A negative error code on failure. + */ +int mbedtls_ecp_is_zero(mbedtls_ecp_point *pt); + +/** + * \brief This function compares two points. + * + * \note This assumes that the points are normalized. Otherwise, + * they may compare as "not equal" even if they are. + * + * \param P The first point to compare. This must be initialized. + * \param Q The second point to compare. This must be initialized. + * + * \return \c 0 if the points are equal. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the points are not equal. + */ +int mbedtls_ecp_point_cmp(const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q); + +/** + * \brief This function imports a non-zero point from two ASCII + * strings. + * + * \param P The destination point. This must be initialized. + * \param radix The numeric base of the input. + * \param x The first affine coordinate, as a null-terminated string. + * \param y The second affine coordinate, as a null-terminated string. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_MPI_XXX error code on failure. + */ +int mbedtls_ecp_point_read_string(mbedtls_ecp_point *P, int radix, + const char *x, const char *y); + +/** + * \brief This function exports a point into unsigned binary data. + * + * \param grp The group to which the point should belong. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param P The point to export. This must be initialized. + * \param format The point format. This must be either + * #MBEDTLS_ECP_PF_COMPRESSED or #MBEDTLS_ECP_PF_UNCOMPRESSED. + * (For groups without these formats, this parameter is + * ignored. But it still has to be either of the above + * values.) + * \param olen The address at which to store the length of + * the output in Bytes. This must not be \c NULL. + * \param buf The output buffer. This must be a writable buffer + * of length \p buflen Bytes. + * \param buflen The length of the output buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the output buffer + * is too small to hold the point. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the point format + * or the export for the given group is not implemented. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_point_write_binary(const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *P, + int format, size_t *olen, + unsigned char *buf, size_t buflen); + +/** + * \brief This function imports a point from unsigned binary data. + * + * \note This function does not check that the point actually + * belongs to the given group, see mbedtls_ecp_check_pubkey() + * for that. + * + * \note For compressed points, see #MBEDTLS_ECP_PF_COMPRESSED for + * limitations. + * + * \param grp The group to which the point should belong. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param P The destination context to import the point to. + * This must be initialized. + * \param buf The input buffer. This must be a readable buffer + * of length \p ilen Bytes. + * \param ilen The length of the input buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the input is invalid. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the import for the + * given group is not implemented. + */ +int mbedtls_ecp_point_read_binary(const mbedtls_ecp_group *grp, + mbedtls_ecp_point *P, + const unsigned char *buf, size_t ilen); + +/** + * \brief This function imports a point from a TLS ECPoint record. + * + * \note On function return, \p *buf is updated to point immediately + * after the ECPoint record. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param pt The destination point. + * \param buf The address of the pointer to the start of the input buffer. + * \param len The length of the buffer. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_MPI_XXX error code on initialization + * failure. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. + */ +int mbedtls_ecp_tls_read_point(const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt, + const unsigned char **buf, size_t len); + +/** + * \brief This function exports a point as a TLS ECPoint record + * defined in RFC 4492, Section 5.4. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param pt The point to be exported. This must be initialized. + * \param format The point format to use. This must be either + * #MBEDTLS_ECP_PF_COMPRESSED or #MBEDTLS_ECP_PF_UNCOMPRESSED. + * \param olen The address at which to store the length in Bytes + * of the data written. + * \param buf The target buffer. This must be a writable buffer of + * length \p blen Bytes. + * \param blen The length of the target buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the input is invalid. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the target buffer + * is too small to hold the exported point. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_tls_write_point(const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *pt, + int format, size_t *olen, + unsigned char *buf, size_t blen); + +/** + * \brief This function sets up an ECP group context + * from a standardized set of domain parameters. + * + * \note The index should be a value of the NamedCurve enum, + * as defined in RFC-4492: Elliptic Curve Cryptography + * (ECC) Cipher Suites for Transport Layer Security (TLS), + * usually in the form of an \c MBEDTLS_ECP_DP_XXX macro. + * + * \param grp The group context to setup. This must be initialized. + * \param id The identifier of the domain parameter set to load. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if \p id doesn't + * correspond to a known group. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_group_load(mbedtls_ecp_group *grp, mbedtls_ecp_group_id id); + +/** + * \brief This function sets up an ECP group context from a TLS + * ECParameters record as defined in RFC 4492, Section 5.4. + * + * \note The read pointer \p buf is updated to point right after + * the ECParameters record on exit. + * + * \param grp The group context to setup. This must be initialized. + * \param buf The address of the pointer to the start of the input buffer. + * \param len The length of the input buffer \c *buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the group is not + * recognized. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_tls_read_group(mbedtls_ecp_group *grp, + const unsigned char **buf, size_t len); + +/** + * \brief This function extracts an elliptic curve group ID from a + * TLS ECParameters record as defined in RFC 4492, Section 5.4. + * + * \note The read pointer \p buf is updated to point right after + * the ECParameters record on exit. + * + * \param grp The address at which to store the group id. + * This must not be \c NULL. + * \param buf The address of the pointer to the start of the input buffer. + * \param len The length of the input buffer \c *buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the group is not + * recognized. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_tls_read_group_id(mbedtls_ecp_group_id *grp, + const unsigned char **buf, + size_t len); +/** + * \brief This function exports an elliptic curve as a TLS + * ECParameters record as defined in RFC 4492, Section 5.4. + * + * \param grp The ECP group to be exported. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param olen The address at which to store the number of Bytes written. + * This must not be \c NULL. + * \param buf The buffer to write to. This must be a writable buffer + * of length \p blen Bytes. + * \param blen The length of the output buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the output + * buffer is too small to hold the exported group. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_tls_write_group(const mbedtls_ecp_group *grp, + size_t *olen, + unsigned char *buf, size_t blen); + +/** + * \brief This function performs a scalar multiplication of a point + * by an integer: \p R = \p m * \p P. + * + * It is not thread-safe to use same group in multiple threads. + * + * \note To prevent timing attacks, this function + * executes the exact same sequence of base-field + * operations for any valid \p m. It avoids any if-branch or + * array index depending on the value of \p m. It also uses + * \p f_rng to randomize some intermediate results. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param R The point in which to store the result of the calculation. + * This must be initialized. + * \param m The integer by which to multiply. This must be initialized. + * \param P The point to multiply. This must be initialized. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be \c + * NULL if \p f_rng doesn't need a context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m is not a valid private + * key, or \p P is not a valid public key. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_mul(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng); + +/** + * \brief This function performs multiplication of a point by + * an integer: \p R = \p m * \p P in a restartable way. + * + * \see mbedtls_ecp_mul() + * + * \note This function does the same as \c mbedtls_ecp_mul(), but + * it can return early and restart according to the limit set + * with \c mbedtls_ecp_set_max_ops() to reduce blocking. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param R The point in which to store the result of the calculation. + * This must be initialized. + * \param m The integer by which to multiply. This must be initialized. + * \param P The point to multiply. This must be initialized. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be \c + * NULL if \p f_rng doesn't need a context. + * \param rs_ctx The restart context (NULL disables restart). + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m is not a valid private + * key, or \p P is not a valid public key. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_mul_restartable(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx); + +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) +/** + * \brief This function checks if domain parameter A of the curve is + * \c -3. + * + * \note This function is only defined for short Weierstrass curves. + * It may not be included in builds without any short + * Weierstrass curve. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * + * \return \c 1 if A = -3. + * \return \c 0 Otherwise. + */ +static inline int mbedtls_ecp_group_a_is_minus_3(const mbedtls_ecp_group *grp) +{ + return grp->A.MBEDTLS_PRIVATE(p) == NULL; +} + +/** + * \brief This function performs multiplication and addition of two + * points by integers: \p R = \p m * \p P + \p n * \p Q + * + * It is not thread-safe to use same group in multiple threads. + * + * \note In contrast to mbedtls_ecp_mul(), this function does not + * guarantee a constant execution flow and timing. + * + * \note This function is only defined for short Weierstrass curves. + * It may not be included in builds without any short + * Weierstrass curve. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param R The point in which to store the result of the calculation. + * This must be initialized. + * \param m The integer by which to multiply \p P. + * This must be initialized. + * \param P The point to multiply by \p m. This must be initialized. + * \param n The integer by which to multiply \p Q. + * This must be initialized. + * \param Q The point to be multiplied by \p n. + * This must be initialized. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m or \p n are not + * valid private keys, or \p P or \p Q are not valid public + * keys. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if \p grp does not + * designate a short Weierstrass curve. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_muladd(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + const mbedtls_mpi *n, const mbedtls_ecp_point *Q); + +/** + * \brief This function performs multiplication and addition of two + * points by integers: \p R = \p m * \p P + \p n * \p Q in a + * restartable way. + * + * \see \c mbedtls_ecp_muladd() + * + * \note This function works the same as \c mbedtls_ecp_muladd(), + * but it can return early and restart according to the limit + * set with \c mbedtls_ecp_set_max_ops() to reduce blocking. + * + * \note This function is only defined for short Weierstrass curves. + * It may not be included in builds without any short + * Weierstrass curve. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param R The point in which to store the result of the calculation. + * This must be initialized. + * \param m The integer by which to multiply \p P. + * This must be initialized. + * \param P The point to multiply by \p m. This must be initialized. + * \param n The integer by which to multiply \p Q. + * This must be initialized. + * \param Q The point to be multiplied by \p n. + * This must be initialized. + * \param rs_ctx The restart context (NULL disables restart). + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m or \p n are not + * valid private keys, or \p P or \p Q are not valid public + * keys. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if \p grp does not + * designate a short Weierstrass curve. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_muladd_restartable( + mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + const mbedtls_mpi *n, const mbedtls_ecp_point *Q, + mbedtls_ecp_restart_ctx *rs_ctx); +#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ + +/** + * \brief This function checks that a point is a valid public key + * on this curve. + * + * It only checks that the point is non-zero, has + * valid coordinates and lies on the curve. It does not verify + * that it is indeed a multiple of \c G. This additional + * check is computationally more expensive, is not required + * by standards, and should not be necessary if the group + * used has a small cofactor. In particular, it is useless for + * the NIST groups which all have a cofactor of 1. + * + * \note This function uses bare components rather than an + * ::mbedtls_ecp_keypair structure, to ease use with other + * structures, such as ::mbedtls_ecdh_context or + * ::mbedtls_ecdsa_context. + * + * \param grp The ECP group the point should belong to. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param pt The point to check. This must be initialized. + * + * \return \c 0 if the point is a valid public key. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if the point is not + * a valid public key for the given curve. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_check_pubkey(const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *pt); + +/** + * \brief This function checks that an \c mbedtls_mpi is a + * valid private key for this curve. + * + * \note This function uses bare components rather than an + * ::mbedtls_ecp_keypair structure to ease use with other + * structures, such as ::mbedtls_ecdh_context or + * ::mbedtls_ecdsa_context. + * + * \param grp The ECP group the private key should belong to. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param d The integer to check. This must be initialized. + * + * \return \c 0 if the point is a valid private key. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if the point is not a valid + * private key for the given curve. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_check_privkey(const mbedtls_ecp_group *grp, + const mbedtls_mpi *d); + +/** + * \brief This function generates a private key. + * + * \param grp The ECP group to generate a private key for. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param d The destination MPI (secret part). This must be initialized. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code + * on failure. + */ +int mbedtls_ecp_gen_privkey(const mbedtls_ecp_group *grp, + mbedtls_mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +/** + * \brief This function generates a keypair with a configurable base + * point. + * + * \note This function uses bare components rather than an + * ::mbedtls_ecp_keypair structure to ease use with other + * structures, such as ::mbedtls_ecdh_context or + * ::mbedtls_ecdsa_context. + * + * \param grp The ECP group to generate a key pair for. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param G The base point to use. This must be initialized + * and belong to \p grp. It replaces the default base + * point \c grp->G used by mbedtls_ecp_gen_keypair(). + * \param d The destination MPI (secret part). + * This must be initialized. + * \param Q The destination point (public part). + * This must be initialized. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may + * be \c NULL if \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code + * on failure. + */ +int mbedtls_ecp_gen_keypair_base(mbedtls_ecp_group *grp, + const mbedtls_ecp_point *G, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +/** + * \brief This function generates an ECP keypair. + * + * \note This function uses bare components rather than an + * ::mbedtls_ecp_keypair structure to ease use with other + * structures, such as ::mbedtls_ecdh_context or + * ::mbedtls_ecdsa_context. + * + * \param grp The ECP group to generate a key pair for. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param d The destination MPI (secret part). + * This must be initialized. + * \param Q The destination point (public part). + * This must be initialized. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may + * be \c NULL if \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code + * on failure. + */ +int mbedtls_ecp_gen_keypair(mbedtls_ecp_group *grp, mbedtls_mpi *d, + mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +/** + * \brief This function generates an ECP key. + * + * \param grp_id The ECP group identifier. + * \param key The destination key. This must be initialized. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may + * be \c NULL if \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code + * on failure. + */ +int mbedtls_ecp_gen_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +/** \brief Set the public key in a key pair object. + * + * \note This function does not check that the point actually + * belongs to the given group. Call mbedtls_ecp_check_pubkey() + * on \p Q before calling this function to check that. + * + * \note This function does not check that the public key matches + * the private key that is already in \p key, if any. + * To check the consistency of the resulting key pair object, + * call mbedtls_ecp_check_pub_priv() after setting both + * the public key and the private key. + * + * \param grp_id The ECP group identifier. + * \param key The key pair object. It must be initialized. + * If its group has already been set, it must match \p grp_id. + * If its group has not been set, it will be set to \p grp_id. + * If the public key has already been set, it is overwritten. + * \param Q The public key to copy. This must be a point on the + * curve indicated by \p grp_id. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if \p key does not + * match \p grp_id. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the operation for + * the group is not implemented. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_set_public_key(mbedtls_ecp_group_id grp_id, + mbedtls_ecp_keypair *key, + const mbedtls_ecp_point *Q); + +/** + * \brief This function reads an elliptic curve private key. + * + * \note This function does not set the public key in the + * key pair object. Without a public key, the key pair object + * cannot be used with operations that require the public key. + * Call mbedtls_ecp_keypair_calc_public() to set the public + * key from the private key. Alternatively, you can call + * mbedtls_ecp_set_public_key() to set the public key part, + * and then optionally mbedtls_ecp_check_pub_priv() to check + * that the private and public parts are consistent. + * + * \note If a public key has already been set in the key pair + * object, this function does not check that it is consistent + * with the private key. Call mbedtls_ecp_check_pub_priv() + * after setting both the public key and the private key + * to make that check. + * + * \param grp_id The ECP group identifier. + * \param key The destination key. + * \param buf The buffer containing the binary representation of the + * key. (Big endian integer for Weierstrass curves, byte + * string for Montgomery curves.) + * \param buflen The length of the buffer in bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY error if the key is + * invalid. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the operation for + * the group is not implemented. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, + const unsigned char *buf, size_t buflen); + +/** + * \brief This function exports an elliptic curve private key. + * + * \param key The private key. + * \param olen On success, the length of the private key. + * This is always (`grp->nbits` + 7) / 8 bytes + * where `grp->nbits` is the private key size in bits. + * \param buf The output buffer for containing the binary representation + * of the key. + * \param buflen The total length of the buffer in bytes. + * #MBEDTLS_ECP_MAX_BYTES is always sufficient. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the \p key + * representation is larger than the available space in \p buf. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if no private key is + * set in \p key. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_ecp_write_key_ext(const mbedtls_ecp_keypair *key, + size_t *olen, unsigned char *buf, size_t buflen); + +/** + * \brief This function exports an elliptic curve public key. + * + * \note If the public key was not set in \p key, + * the output is unspecified. Future versions + * may return an error in that case. + * + * \param key The public key. + * \param format The point format. This must be either + * #MBEDTLS_ECP_PF_COMPRESSED or #MBEDTLS_ECP_PF_UNCOMPRESSED. + * (For groups without these formats, this parameter is + * ignored. But it still has to be either of the above + * values.) + * \param olen The address at which to store the length of + * the output in Bytes. This must not be \c NULL. + * \param buf The output buffer. This must be a writable buffer + * of length \p buflen Bytes. + * \param buflen The length of the output buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the output buffer + * is too small to hold the point. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the point format + * or the export for the given group is not implemented. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_write_public_key(const mbedtls_ecp_keypair *key, + int format, size_t *olen, + unsigned char *buf, size_t buflen); + +/** + * \brief This function checks that the keypair objects + * \p pub and \p prv have the same group and the + * same public point, and that the private key in + * \p prv is consistent with the public key. + * + * \param pub The keypair structure holding the public key. This + * must be initialized. If it contains a private key, that + * part is ignored. + * \param prv The keypair structure holding the full keypair. + * This must be initialized. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be \c + * NULL if \p f_rng doesn't need a context. + * + * \return \c 0 on success, meaning that the keys are valid and match. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the keys are invalid or do not match. + * \return An \c MBEDTLS_ERR_ECP_XXX or an \c MBEDTLS_ERR_MPI_XXX + * error code on calculation failure. + */ +int mbedtls_ecp_check_pub_priv( + const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng); + +/** \brief Calculate the public key from a private key in a key pair. + * + * \param key A keypair structure. It must have a private key set. + * If the public key is set, it will be overwritten. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be \c + * NULL if \p f_rng doesn't need a context. + * + * \return \c 0 on success. The key pair object can be used for + * operations that require the public key. + * \return An \c MBEDTLS_ERR_ECP_XXX or an \c MBEDTLS_ERR_MPI_XXX + * error code on calculation failure. + */ +int mbedtls_ecp_keypair_calc_public( + mbedtls_ecp_keypair *key, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng); + +/** \brief Query the group that a key pair belongs to. + * + * \param key The key pair to query. + * + * \return The group ID for the group registered in the key pair + * object. + * This is \c MBEDTLS_ECP_DP_NONE if no group has been set + * in the key pair object. + */ +mbedtls_ecp_group_id mbedtls_ecp_keypair_get_group_id( + const mbedtls_ecp_keypair *key); + +/** + * \brief This function exports generic key-pair parameters. + * + * Each of the output parameters can be a null pointer + * if you do not need that parameter. + * + * \note If the private key or the public key was not set in \p key, + * the corresponding output is unspecified. Future versions + * may return an error in that case. + * + * \param key The key pair to export from. + * \param grp Slot for exported ECP group. + * It must either be null or point to an initialized ECP group. + * \param d Slot for the exported secret value. + * It must either be null or point to an initialized mpi. + * \param Q Slot for the exported public value. + * It must either be null or point to an initialized ECP point. + * + * \return \c 0 on success, + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if key id doesn't + * correspond to a known group. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_export(const mbedtls_ecp_keypair *key, mbedtls_ecp_group *grp, + mbedtls_mpi *d, mbedtls_ecp_point *Q); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief The ECP checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_ecp_self_test(int verbose); + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ECP_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/entropy.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/entropy.h new file mode 100644 index 0000000000..ed3c882a54 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/entropy.h @@ -0,0 +1,253 @@ +/** + * \file entropy.h + * + * \brief Entropy accumulator implementation + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ENTROPY_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ENTROPY_H +#include "mbedtls/private_access.h" +#include "mbedtls/psa_util.h" + +#include "tf-psa-crypto/build_info.h" + +#include + +#include "mbedtls/md.h" + +#define MBEDTLS_ENTROPY_BLOCK_SIZE PSA_HASH_LENGTH(MBEDTLS_PSA_CRYPTO_RNG_HASH) +/* For MBEDTLS_ENTROPY_MD convert PSA_ALG_SHA_256/512 -> MBEDTLS_MD_SHA256/512 */ +#define MBEDTLS_ENTROPY_MD (mbedtls_md_type_from_psa_alg(MBEDTLS_PSA_CRYPTO_RNG_HASH)) + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + + +/** Critical entropy source failure. */ +#define MBEDTLS_ERR_ENTROPY_SOURCE_FAILED PSA_ERROR_INSUFFICIENT_ENTROPY +/** No more sources can be added. */ +#define MBEDTLS_ERR_ENTROPY_MAX_SOURCES -0x003E +/** No sources have been added to poll. */ +#define MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED -0x0040 +/** No strong sources have been added to poll. */ +#define MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE -0x003D +/** Read/write error in file. */ +#define MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR -0x003F + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in mbedtls_config.h or define them on the compiler command line. + * \{ + */ + +#define MBEDTLS_ENTROPY_MAX_SOURCES 4 /**< Maximum number of sources supported. Should be just 2 eventually. */ +#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ + +/** \} name SECTION: Module settings */ + +#define MBEDTLS_ENTROPY_MAX_SEED_SIZE 1024 /**< Maximum size of seed we read from seed file */ +#define MBEDTLS_ENTROPY_SOURCE_MANUAL MBEDTLS_ENTROPY_MAX_SOURCES + +#define MBEDTLS_ENTROPY_SOURCE_STRONG 1 /**< Entropy source is strong */ +#define MBEDTLS_ENTROPY_SOURCE_WEAK 0 /**< Entropy source is weak */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Entropy poll callback pointer + * + * \param data Callback-specific data pointer + * \param output Data to fill + * \param len Maximum size to provide + * \param olen The actual amount of bytes put into the buffer (Can be 0) + * + * \return 0 if no critical failures occurred, + * MBEDTLS_ERR_ENTROPY_SOURCE_FAILED otherwise + */ +typedef int (*mbedtls_entropy_f_source_ptr)(void *data, unsigned char *output, size_t len, + size_t *olen); + +/** + * \brief Entropy source state + */ +typedef struct mbedtls_entropy_source_state { + mbedtls_entropy_f_source_ptr MBEDTLS_PRIVATE(f_source); /**< The entropy source callback */ + void *MBEDTLS_PRIVATE(p_source); /**< The callback data pointer */ + size_t MBEDTLS_PRIVATE(size); /**< Amount received in bytes */ + size_t MBEDTLS_PRIVATE(threshold); /**< Minimum bytes required before release */ + int MBEDTLS_PRIVATE(strong); /**< Is the source strong? */ +} +mbedtls_entropy_source_state; + +/** + * \brief Entropy context structure + */ +typedef struct mbedtls_entropy_context { + mbedtls_md_context_t MBEDTLS_PRIVATE(accumulator); + int MBEDTLS_PRIVATE(accumulator_started); /* 0 after init. + * 1 after the first update. + * -1 after free. */ + int MBEDTLS_PRIVATE(source_count); /* Number of entries used in source. */ + mbedtls_entropy_source_state MBEDTLS_PRIVATE(source)[MBEDTLS_ENTROPY_MAX_SOURCES]; +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t MBEDTLS_PRIVATE(mutex); /*!< mutex */ +#endif +#if defined(MBEDTLS_ENTROPY_NV_SEED) + int MBEDTLS_PRIVATE(initial_entropy_run); +#endif +} +mbedtls_entropy_context; + +/** + * \brief Initialize the context + * + * \param ctx Entropy context to initialize + */ +void mbedtls_entropy_init(mbedtls_entropy_context *ctx); + +/** + * \brief Free the data in the context + * + * \param ctx Entropy context to free + */ +void mbedtls_entropy_free(mbedtls_entropy_context *ctx); + +/** + * \brief Adds an entropy source to poll + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param ctx Entropy context + * \param f_source Entropy function + * \param p_source Function data + * \param threshold Minimum required from source before entropy is released + * ( with mbedtls_entropy_func() ) (in bytes) + * \param strong MBEDTLS_ENTROPY_SOURCE_STRONG or + * MBEDTLS_ENTROPY_SOURCE_WEAK. + * At least one strong source needs to be added. + * Weaker sources (such as the cycle counter) can be used as + * a complement. + * + * \return 0 if successful or MBEDTLS_ERR_ENTROPY_MAX_SOURCES + */ +int mbedtls_entropy_add_source(mbedtls_entropy_context *ctx, + mbedtls_entropy_f_source_ptr f_source, void *p_source, + size_t threshold, int strong); + +/** + * \brief Trigger an extra gather poll for the accumulator + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param ctx Entropy context + * + * \return 0 if successful, or MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_gather(mbedtls_entropy_context *ctx); + +/** + * \brief Retrieve entropy from the accumulator + * (Maximum length: MBEDTLS_ENTROPY_BLOCK_SIZE) + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param data Entropy context + * \param output Buffer to fill + * \param len Number of bytes desired, must be at most MBEDTLS_ENTROPY_BLOCK_SIZE + * + * \return 0 if successful, or MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_func(void *data, unsigned char *output, size_t len); + +/** + * \brief Add data to the accumulator manually + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param ctx Entropy context + * \param data Data to add + * \param len Length of data + * + * \return 0 if successful + */ +int mbedtls_entropy_update_manual(mbedtls_entropy_context *ctx, + const unsigned char *data, size_t len); + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +/** + * \brief Trigger an update of the seed file in NV by using the + * current entropy pool. + * + * \param ctx Entropy context + * + * \return 0 if successful + */ +int mbedtls_entropy_update_nv_seed(mbedtls_entropy_context *ctx); +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Write a seed file + * + * \param ctx Entropy context + * \param path Name of the file + * + * \return 0 if successful, + * MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR on file error, or + * MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_write_seed_file(mbedtls_entropy_context *ctx, const char *path); + +/** + * \brief Read and update a seed file. Seed is added to this + * instance. No more than MBEDTLS_ENTROPY_MAX_SEED_SIZE bytes are + * read from the seed file. The rest is ignored. + * + * \param ctx Entropy context + * \param path Name of the file + * + * \return 0 if successful, + * MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR on file error, + * MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_update_seed_file(mbedtls_entropy_context *ctx, const char *path); +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * This module self-test also calls the entropy self-test, + * mbedtls_entropy_source_self_test(); + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_entropy_self_test(int verbose); + +#if defined(MBEDTLS_PSA_DRIVER_GET_ENTROPY) +/** + * \brief Checkup routine + * + * Verifies the integrity of the hardware entropy source + * provided by the function 'mbedtls_hardware_poll()'. + * + * Note this is the only hardware entropy source that is known + * at link time, and other entropy sources configured + * dynamically at runtime by the function + * mbedtls_entropy_add_source() will not be tested. + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_entropy_source_self_test(int verbose); +#endif /* MBEDTLS_PSA_DRIVER_GET_ENTROPY */ +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ENTROPY_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/error_common.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/error_common.h new file mode 100644 index 0000000000..143366ed62 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/error_common.h @@ -0,0 +1,79 @@ +/** + * \file error_common.h + * + * \brief Error codes + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ERROR_COMMON_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ERROR_COMMON_H + +#include "tf-psa-crypto/build_info.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Generic error */ +#define MBEDTLS_ERR_ERROR_GENERIC_ERROR PSA_ERROR_GENERIC_ERROR +/* This is a bug in the library */ +#define MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED PSA_ERROR_CORRUPTION_DETECTED + +/* Hardware accelerator failed */ +#define MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED PSA_ERROR_HARDWARE_FAILURE +/* The requested feature is not supported by the platform */ +#define MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED PSA_ERROR_NOT_SUPPORTED + +/** + * \brief Combines a high-level and low-level error code together. + * + * Wrapper macro for mbedtls_error_add(). See that function for + * more details. + */ +#define MBEDTLS_ERROR_ADD(high, low) \ + mbedtls_error_add(high, low) + +/** + * \brief Combines a high-level and low-level error code together. + * + * This function can be called directly however it is usually + * called via the #MBEDTLS_ERROR_ADD macro. + * + * While a value of zero is not a negative error code, it is still an + * error code (that denotes success) and can be combined with both a + * negative error code or another value of zero. + * + * \note The distinction between low-level and high-level error codes is + * obsolete since TF-PSA-Crypto 1.0 and Mbed TLS 4.0. It is still + * present in the code due to the heritage from Mbed TLS <=3, + * where low-level and high-level error codes could be added. + * New code should not make this distinction and should just + * propagate errors returned by lower-level modules unless there + * is a good reason to report a different error code in the + * higher-level module. + * + * \param high High-level error code, i.e. error code from the module + * that is reporting the error. + * This can be 0 to just propagate a low-level error. + * \param low Low-level error code, i.e. error code returned by + * a lower-level function. + * This can be 0 to just return a high-level error. + */ +static inline int mbedtls_error_add(int high, int low) +{ + /* We give priority to the lower-level error code, because this + * is usually the right choice. For example, if a low-level module + * runs out of memory, this should not be converted to a high-level + * error code such as invalid-signature. */ + return low ? low : high; +} + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ERROR_COMMON_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/gcm.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/gcm.h new file mode 100644 index 0000000000..d9b0435bc5 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/gcm.h @@ -0,0 +1,382 @@ +/** + * \file gcm.h + * + * \brief This file contains GCM definitions and functions. + * + * The Galois/Counter Mode (GCM) for 128-bit block ciphers is defined + * in D. McGrew, J. Viega, The Galois/Counter Mode of Operation + * (GCM), Natl. Inst. Stand. Technol. + * + * For more information on GCM, see NIST SP 800-38D: Recommendation for + * Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC. + * + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_GCM_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_GCM_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +#include "mbedtls/private/cipher.h" + +#if defined(MBEDTLS_BLOCK_CIPHER_C) +#include "mbedtls/private/block_cipher.h" +#endif + +#include + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +#define MBEDTLS_GCM_ENCRYPT 1 +#define MBEDTLS_GCM_DECRYPT 0 +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +/** Authenticated decryption failed. */ +#define MBEDTLS_ERR_GCM_AUTH_FAILED PSA_ERROR_INVALID_SIGNATURE +/** Bad input parameters to function. */ +#define MBEDTLS_ERR_GCM_BAD_INPUT PSA_ERROR_INVALID_ARGUMENT +/** An output buffer is too small. */ +#define MBEDTLS_ERR_GCM_BUFFER_TOO_SMALL PSA_ERROR_BUFFER_TOO_SMALL + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_GCM_LARGE_TABLE) +#define MBEDTLS_GCM_HTABLE_SIZE 256 +#else +#define MBEDTLS_GCM_HTABLE_SIZE 16 +#endif + +/** + * \brief The GCM context structure. + */ +typedef struct mbedtls_gcm_context { +#if defined(MBEDTLS_BLOCK_CIPHER_C) + mbedtls_block_cipher_context_t MBEDTLS_PRIVATE(block_cipher_ctx); /*!< The cipher context used. */ +#else + mbedtls_cipher_context_t MBEDTLS_PRIVATE(cipher_ctx); /*!< The cipher context used. */ +#endif + uint64_t MBEDTLS_PRIVATE(H)[MBEDTLS_GCM_HTABLE_SIZE][2]; /*!< Precalculated HTable. */ + uint64_t MBEDTLS_PRIVATE(len); /*!< The total length of the encrypted data. */ + uint64_t MBEDTLS_PRIVATE(add_len); /*!< The total length of the additional data. */ + unsigned char MBEDTLS_PRIVATE(base_ectr)[16]; /*!< The first ECTR for tag. */ + unsigned char MBEDTLS_PRIVATE(y)[16]; /*!< The Y working value. */ + unsigned char MBEDTLS_PRIVATE(buf)[16]; /*!< The buf working value. */ + unsigned char MBEDTLS_PRIVATE(mode); /*!< The operation to perform: + MBEDTLS_GCM_ENCRYPT or + MBEDTLS_GCM_DECRYPT. */ + unsigned char MBEDTLS_PRIVATE(acceleration); /*!< The acceleration to use. */ +} +mbedtls_gcm_context; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief This function initializes the specified GCM context, + * to make references valid, and prepares the context + * for mbedtls_gcm_setkey() or mbedtls_gcm_free(). + * + * The function does not bind the GCM context to a particular + * cipher, nor set the key. For this purpose, use + * mbedtls_gcm_setkey(). + * + * \param ctx The GCM context to initialize. This must not be \c NULL. + */ +void mbedtls_gcm_init(mbedtls_gcm_context *ctx); + +/** + * \brief This function associates a GCM context with a + * cipher algorithm and a key. + * + * \param ctx The GCM context. This must be initialized. + * \param cipher The 128-bit block cipher to use. + * \param key The encryption key. This must be a readable buffer of at + * least \p keybits bits. + * \param keybits The key size in bits. Valid options are: + *
  • 128 bits
  • + *
  • 192 bits
  • + *
  • 256 bits
+ * + * \return \c 0 on success. + * \return A cipher-specific error code on failure. + */ +int mbedtls_gcm_setkey(mbedtls_gcm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits); + +/** + * \brief This function performs GCM encryption or decryption of a buffer. + * + * \note The output buffer \p output can be the same as the input + * buffer \p input. If \p output is greater than \p input, they + * cannot overlap. + * + * \warning When this function performs a decryption, it outputs the + * authentication tag and does not verify that the data is + * authentic. You should use this function to perform encryption + * only. For decryption, use mbedtls_gcm_auth_decrypt() instead. + * + * \param ctx The GCM context to use for encryption or decryption. This + * must be initialized. + * \param mode The operation to perform: + * - MBEDTLS_GCM_ENCRYPT to perform authenticated encryption. + * The ciphertext is written to \p output and the + * authentication tag is written to \p tag. + * - MBEDTLS_GCM_DECRYPT to perform decryption. + * The plaintext is written to \p output and the + * authentication tag is written to \p tag. + * Note that this mode is not recommended, because it does + * not verify the authenticity of the data. For this reason, + * you should use mbedtls_gcm_auth_decrypt() instead of + * calling this function in decryption mode. + * \param length The length of the input data, which is equal to the length + * of the output data. + * \param iv The initialization vector. This must be a readable buffer of + * at least \p iv_len Bytes. + * \param iv_len The length of the IV. + * \param add The buffer holding the additional data. This must be of at + * least that size in Bytes. + * \param add_len The length of the additional data. + * \param input The buffer holding the input data. If \p length is greater + * than zero, this must be a readable buffer of at least that + * size in Bytes. + * \param output The buffer for holding the output data. If \p length is greater + * than zero, this must be a writable buffer of at least that + * size in Bytes. + * \param tag_len The length of the tag to generate. + * \param tag The buffer for holding the tag. This must be a writable + * buffer of at least \p tag_len Bytes. + * + * \return \c 0 if the encryption or decryption was performed + * successfully. Note that in MBEDTLS_GCM_DECRYPT mode, + * this does not indicate that the data is authentic. + * \return #MBEDTLS_ERR_GCM_BAD_INPUT if the lengths or pointers are + * not valid or a cipher-specific error code if the encryption + * or decryption failed. + */ +int mbedtls_gcm_crypt_and_tag(mbedtls_gcm_context *ctx, + int mode, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *input, + unsigned char *output, + size_t tag_len, + unsigned char *tag); + +/** + * \brief This function performs a GCM authenticated decryption of a + * buffer. + * + * \note The output buffer \p output can be the same as the input + * buffer \p input. If \p output is greater than \p input, they + * cannot overlap. + * + * \param ctx The GCM context. This must be initialized. + * \param length The length of the ciphertext to decrypt, which is also + * the length of the decrypted plaintext. + * \param iv The initialization vector. This must be a readable buffer + * of at least \p iv_len Bytes. + * \param iv_len The length of the IV. + * \param add The buffer holding the additional data. This must be of at + * least that size in Bytes. + * \param add_len The length of the additional data. + * \param tag The buffer holding the tag to verify. This must be a + * readable buffer of at least \p tag_len Bytes. + * \param tag_len The length of the tag to verify. + * \param input The buffer holding the ciphertext. If \p length is greater + * than zero, this must be a readable buffer of at least that + * size. + * \param output The buffer for holding the decrypted plaintext. If \p length + * is greater than zero, this must be a writable buffer of at + * least that size. + * + * \return \c 0 if successful and authenticated. + * \return #MBEDTLS_ERR_GCM_AUTH_FAILED if the tag does not match. + * \return #MBEDTLS_ERR_GCM_BAD_INPUT if the lengths or pointers are + * not valid or a cipher-specific error code if the decryption + * failed. + */ +int mbedtls_gcm_auth_decrypt(mbedtls_gcm_context *ctx, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *tag, + size_t tag_len, + const unsigned char *input, + unsigned char *output); + +/** + * \brief This function starts a GCM encryption or decryption + * operation. + * + * \param ctx The GCM context. This must be initialized. + * \param mode The operation to perform: MBEDTLS_GCM_ENCRYPT or + * MBEDTLS_GCM_DECRYPT. + * \param iv The initialization vector. This must be a readable buffer of + * at least \p iv_len Bytes. + * \param iv_len The length of the IV. + * + * \return \c 0 on success. + */ +int mbedtls_gcm_starts(mbedtls_gcm_context *ctx, + int mode, + const unsigned char *iv, + size_t iv_len); + +/** + * \brief This function feeds an input buffer as associated data + * (authenticated but not encrypted data) in a GCM + * encryption or decryption operation. + * + * Call this function after mbedtls_gcm_starts() to pass + * the associated data. If the associated data is empty, + * you do not need to call this function. You may not + * call this function after calling mbedtls_cipher_update(). + * + * \param ctx The GCM context. This must have been started with + * mbedtls_gcm_starts() and must not have yet received + * any input with mbedtls_gcm_update(). + * \param add The buffer holding the additional data, or \c NULL + * if \p add_len is \c 0. + * \param add_len The length of the additional data. If \c 0, + * \p add may be \c NULL. + * + * \return \c 0 on success. + */ +int mbedtls_gcm_update_ad(mbedtls_gcm_context *ctx, + const unsigned char *add, + size_t add_len); + +/** + * \brief This function feeds an input buffer into an ongoing GCM + * encryption or decryption operation. + * + * You may call this function zero, one or more times + * to pass successive parts of the input: the plaintext to + * encrypt, or the ciphertext (not including the tag) to + * decrypt. After the last part of the input, call + * mbedtls_gcm_finish(). + * + * This function may produce output in one of the following + * ways: + * - Immediate output: the output length is always equal + * to the input length. + * - Buffered output: the output consists of a whole number + * of 16-byte blocks. If the total input length so far + * (not including associated data) is 16 \* *B* + *A* + * with *A* < 16 then the total output length is 16 \* *B*. + * + * In particular: + * - It is always correct to call this function with + * \p output_size >= \p input_length + 15. + * - If \p input_length is a multiple of 16 for all the calls + * to this function during an operation, then it is + * correct to use \p output_size = \p input_length. + * + * \note The output buffer \p output can be the same as the input + * buffer \p input. If \p output is greater than \p input, they + * cannot overlap. + * + * \param ctx The GCM context. This must be initialized. + * \param input The buffer holding the input data. If \p input_length + * is greater than zero, this must be a readable buffer + * of at least \p input_length bytes. + * \param input_length The length of the input data in bytes. + * \param output The buffer for the output data. If \p output_size + * is greater than zero, this must be a writable buffer of + * of at least \p output_size bytes. + * \param output_size The size of the output buffer in bytes. + * See the function description regarding the output size. + * \param output_length On success, \p *output_length contains the actual + * length of the output written in \p output. + * On failure, the content of \p *output_length is + * unspecified. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_GCM_BAD_INPUT on failure: + * total input length too long, + * unsupported input/output buffer overlap detected, + * or \p output_size too small. + */ +int mbedtls_gcm_update(mbedtls_gcm_context *ctx, + const unsigned char *input, size_t input_length, + unsigned char *output, size_t output_size, + size_t *output_length); + +/** + * \brief This function finishes the GCM operation and generates + * the authentication tag. + * + * It wraps up the GCM stream, and generates the + * tag. The tag can have a maximum length of 16 Bytes. + * + * \param ctx The GCM context. This must be initialized. + * \param tag The buffer for holding the tag. This must be a writable + * buffer of at least \p tag_len Bytes. + * \param tag_len The length of the tag to generate. This must be at least + * four. + * \param output The buffer for the final output. + * If \p output_size is nonzero, this must be a writable + * buffer of at least \p output_size bytes. + * \param output_size The size of the \p output buffer in bytes. + * This must be large enough for the output that + * mbedtls_gcm_update() has not produced. In particular: + * - If mbedtls_gcm_update() produces immediate output, + * or if the total input size is a multiple of \c 16, + * then mbedtls_gcm_finish() never produces any output, + * so \p output_size can be \c 0. + * - \p output_size never needs to be more than \c 15. + * \param output_length On success, \p *output_length contains the actual + * length of the output written in \p output. + * On failure, the content of \p *output_length is + * unspecified. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_GCM_BAD_INPUT on failure: + * invalid value of \p tag_len, + * or \p output_size too small. + */ +int mbedtls_gcm_finish(mbedtls_gcm_context *ctx, + unsigned char *output, size_t output_size, + size_t *output_length, + unsigned char *tag, size_t tag_len); + +/** + * \brief This function clears a GCM context and the underlying + * cipher sub-context. + * + * \param ctx The GCM context to clear. If this is \c NULL, the call has + * no effect. Otherwise, this must be initialized. + */ +void mbedtls_gcm_free(mbedtls_gcm_context *ctx); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief The GCM checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_gcm_self_test(int verbose); + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_GCM_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/hmac_drbg.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/hmac_drbg.h new file mode 100644 index 0000000000..8dfeeb3c38 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/hmac_drbg.h @@ -0,0 +1,426 @@ +/** + * \file hmac_drbg.h + * + * \brief The HMAC_DRBG pseudorandom generator. + * + * This module implements the HMAC_DRBG pseudorandom generator described + * in NIST SP 800-90A: Recommendation for Random Number Generation Using + * Deterministic Random Bit Generators. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_HMAC_DRBG_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_HMAC_DRBG_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +#include "mbedtls/md.h" + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +/* + * Error codes + */ +/** Too many random requested in single call. */ +#define MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG -0x0003 +/** Input too large (Entropy + additional). */ +#define MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG -0x0005 +/** Read/write error in file. */ +#define MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR -0x0007 +/** The entropy source failed. */ +#define MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED -0x0009 + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in mbedtls_config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_PSA_RNG_RESEED_INTERVAL) +#define MBEDTLS_PSA_RNG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +#endif + +#define MBEDTLS_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +#define MBEDTLS_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/** \} name SECTION: Module settings */ + +#define MBEDTLS_HMAC_DRBG_PR_OFF 0 /**< No prediction resistance */ +#define MBEDTLS_HMAC_DRBG_PR_ON 1 /**< Prediction resistance enabled */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * HMAC_DRBG context. + */ +typedef struct mbedtls_hmac_drbg_context { + /* Working state: the key K is not stored explicitly, + * but is implied by the HMAC context */ + mbedtls_md_context_t MBEDTLS_PRIVATE(md_ctx); /*!< HMAC context (inc. K) */ + unsigned char MBEDTLS_PRIVATE(V)[MBEDTLS_MD_MAX_SIZE]; /*!< V in the spec */ + int MBEDTLS_PRIVATE(reseed_counter); /*!< reseed counter */ + + /* Administrative state */ + size_t MBEDTLS_PRIVATE(entropy_len); /*!< entropy bytes grabbed on each (re)seed */ + int MBEDTLS_PRIVATE(prediction_resistance); /*!< enable prediction resistance (Automatic + reseed before every random generation) */ + int MBEDTLS_PRIVATE(reseed_interval); /*!< reseed interval */ + + /* Callbacks */ + int(*MBEDTLS_PRIVATE(f_entropy))(void *, unsigned char *, size_t); /*!< entropy function */ + void *MBEDTLS_PRIVATE(p_entropy); /*!< context for the entropy function */ + +#if defined(MBEDTLS_THREADING_C) + /* Invariant: the mutex is initialized if and only if + * md_ctx->md_info != NULL. This means that the mutex is initialized + * during the initial seeding in mbedtls_hmac_drbg_seed() or + * mbedtls_hmac_drbg_seed_buf() and freed in mbedtls_ctr_drbg_free(). + * + * Note that this invariant may change without notice. Do not rely on it + * and do not access the mutex directly in application code. + */ + mbedtls_threading_mutex_t MBEDTLS_PRIVATE(mutex); +#endif +} mbedtls_hmac_drbg_context; + +/** + * \brief HMAC_DRBG context initialization. + * + * This function makes the context ready for mbedtls_hmac_drbg_seed(), + * mbedtls_hmac_drbg_seed_buf() or mbedtls_hmac_drbg_free(). + * + * \note The reseed interval is #MBEDTLS_PSA_RNG_RESEED_INTERVAL + * by default. Override this value by calling + * mbedtls_hmac_drbg_set_reseed_interval(). + * + * \param ctx HMAC_DRBG context to be initialized. + */ +void mbedtls_hmac_drbg_init(mbedtls_hmac_drbg_context *ctx); + +/** + * \brief HMAC_DRBG initial seeding. + * + * Set the initial seed and set up the entropy source for future reseeds. + * + * A typical choice for the \p f_entropy and \p p_entropy parameters is + * to use the entropy module: + * - \p f_entropy is mbedtls_entropy_func(); + * - \p p_entropy is an instance of ::mbedtls_entropy_context initialized + * with mbedtls_entropy_init() (which registers the platform's default + * entropy sources). + * + * You can provide a personalization string in addition to the + * entropy source, to make this instantiation as unique as possible. + * + * \note By default, the security strength as defined by NIST is: + * - 128 bits if \p md_info is SHA-1; + * - 192 bits if \p md_info is SHA-224; + * - 256 bits if \p md_info is SHA-256, SHA-384 or SHA-512. + * Note that SHA-256 is just as efficient as SHA-224. + * The security strength can be reduced if a smaller + * entropy length is set with + * mbedtls_hmac_drbg_set_entropy_len(). + * + * \note The default entropy length is the security strength + * (converted from bits to bytes). You can override + * it by calling mbedtls_hmac_drbg_set_entropy_len(). + * + * \note During the initial seeding, this function calls + * the entropy source to obtain a nonce + * whose length is half the entropy length. + */ +#if defined(MBEDTLS_THREADING_C) +/** + * \note When Mbed TLS is built with threading support, + * after this function returns successfully, + * it is safe to call mbedtls_hmac_drbg_random() + * from multiple threads. Other operations, including + * reseeding, are not thread-safe. + */ +#endif /* MBEDTLS_THREADING_C */ +/** + * \param ctx HMAC_DRBG context to be seeded. + * \param md_info MD algorithm to use for HMAC_DRBG. + * \param f_entropy The entropy callback, taking as arguments the + * \p p_entropy context, the buffer to fill, and the + * length of the buffer. + * \p f_entropy is always called with a length that is + * less than or equal to the entropy length. + * \param p_entropy The entropy context to pass to \p f_entropy. + * \param custom The personalization string. + * This can be \c NULL, in which case the personalization + * string is empty regardless of the value of \p len. + * \param len The length of the personalization string. + * This must be at most #MBEDTLS_HMAC_DRBG_MAX_INPUT + * and also at most + * #MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT - \c entropy_len * 3 / 2 + * where \c entropy_len is the entropy length + * described above. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA if \p md_info is + * invalid. + * \return #MBEDTLS_ERR_MD_ALLOC_FAILED if there was not enough + * memory to allocate context data. + * \return #MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED + * if the call to \p f_entropy failed. + */ +int mbedtls_hmac_drbg_seed(mbedtls_hmac_drbg_context *ctx, + const mbedtls_md_info_t *md_info, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len); + +/** + * \brief Initialisation of simplified HMAC_DRBG (never reseeds). + * + * This function is meant for use in algorithms that need a pseudorandom + * input such as deterministic ECDSA. + */ +#if defined(MBEDTLS_THREADING_C) +/** + * \note When Mbed TLS is built with threading support, + * after this function returns successfully, + * it is safe to call mbedtls_hmac_drbg_random() + * from multiple threads. Other operations, including + * reseeding, are not thread-safe. + */ +#endif /* MBEDTLS_THREADING_C */ +/** + * \param ctx HMAC_DRBG context to be initialised. + * \param md_info MD algorithm to use for HMAC_DRBG. + * \param data Concatenation of the initial entropy string and + * the additional data. + * \param data_len Length of \p data in bytes. + * + * \return \c 0 if successful. or + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA if \p md_info is + * invalid. + * \return #MBEDTLS_ERR_MD_ALLOC_FAILED if there was not enough + * memory to allocate context data. + */ +int mbedtls_hmac_drbg_seed_buf(mbedtls_hmac_drbg_context *ctx, + const mbedtls_md_info_t *md_info, + const unsigned char *data, size_t data_len); + +/** + * \brief This function turns prediction resistance on or off. + * The default value is off. + * + * \note If enabled, entropy is gathered at the beginning of + * every call to mbedtls_hmac_drbg_random_with_add() + * or mbedtls_hmac_drbg_random(). + * Only use this if your entropy source has sufficient + * throughput. + * + * \param ctx The HMAC_DRBG context. + * \param resistance #MBEDTLS_HMAC_DRBG_PR_ON or #MBEDTLS_HMAC_DRBG_PR_OFF. + */ +void mbedtls_hmac_drbg_set_prediction_resistance(mbedtls_hmac_drbg_context *ctx, + int resistance); + +/** + * \brief This function sets the amount of entropy grabbed on each + * seed or reseed. + * + * See the documentation of mbedtls_hmac_drbg_seed() for the default value. + * + * \param ctx The HMAC_DRBG context. + * \param len The amount of entropy to grab, in bytes. + */ +void mbedtls_hmac_drbg_set_entropy_len(mbedtls_hmac_drbg_context *ctx, + size_t len); + +/** + * \brief Set the reseed interval. + * + * The reseed interval is the number of calls to mbedtls_hmac_drbg_random() + * or mbedtls_hmac_drbg_random_with_add() after which the entropy function + * is called again. + * + * The default value is #MBEDTLS_PSA_RNG_RESEED_INTERVAL. + * + * \param ctx The HMAC_DRBG context. + * \param interval The reseed interval. + */ +void mbedtls_hmac_drbg_set_reseed_interval(mbedtls_hmac_drbg_context *ctx, + int interval); + +/** + * \brief This function updates the state of the HMAC_DRBG context. + * + * \note This function is not thread-safe. It is not safe + * to call this function if another thread might be + * concurrently obtaining random numbers from the same + * context or updating or reseeding the same context. + * + * \param ctx The HMAC_DRBG context. + * \param additional The data to update the state with. + * If this is \c NULL, there is no additional data. + * \param add_len Length of \p additional in bytes. + * Unused if \p additional is \c NULL. + * + * \return \c 0 on success, or an error from the underlying + * hash calculation. + */ +int mbedtls_hmac_drbg_update(mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t add_len); + +/** + * \brief This function reseeds the HMAC_DRBG context, that is + * extracts data from the entropy source. + * + * \note This function is not thread-safe. It is not safe + * to call this function if another thread might be + * concurrently obtaining random numbers from the same + * context or updating or reseeding the same context. + * + * \param ctx The HMAC_DRBG context. + * \param additional Additional data to add to the state. + * If this is \c NULL, there is no additional data + * and \p len should be \c 0. + * \param len The length of the additional data. + * This must be at most #MBEDTLS_HMAC_DRBG_MAX_INPUT + * and also at most + * #MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT - \c entropy_len + * where \c entropy_len is the entropy length + * (see mbedtls_hmac_drbg_set_entropy_len()). + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED + * if a call to the entropy function failed. + */ +int mbedtls_hmac_drbg_reseed(mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t len); + +/** + * \brief This function updates an HMAC_DRBG instance with additional + * data and uses it to generate random data. + * + * This function automatically reseeds if the reseed counter is exceeded + * or prediction resistance is enabled. + * + * \note This function is not thread-safe. It is not safe + * to call this function if another thread might be + * concurrently obtaining random numbers from the same + * context or updating or reseeding the same context. + * + * \param p_rng The HMAC_DRBG context. This must be a pointer to a + * #mbedtls_hmac_drbg_context structure. + * \param output The buffer to fill. + * \param output_len The length of the buffer in bytes. + * This must be at most #MBEDTLS_HMAC_DRBG_MAX_REQUEST. + * \param additional Additional data to update with. + * If this is \c NULL, there is no additional data + * and \p add_len should be \c 0. + * \param add_len The length of the additional data. + * This must be at most #MBEDTLS_HMAC_DRBG_MAX_INPUT. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED + * if a call to the entropy source failed. + * \return #MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG if + * \p output_len > #MBEDTLS_HMAC_DRBG_MAX_REQUEST. + * \return #MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG if + * \p add_len > #MBEDTLS_HMAC_DRBG_MAX_INPUT. + */ +int mbedtls_hmac_drbg_random_with_add(void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, + size_t add_len); + +/** + * \brief This function uses HMAC_DRBG to generate random data. + * + * This function automatically reseeds if the reseed counter is exceeded + * or prediction resistance is enabled. + */ +#if defined(MBEDTLS_THREADING_C) +/** + * \note When Mbed TLS is built with threading support, + * it is safe to call mbedtls_ctr_drbg_random() + * from multiple threads. Other operations, including + * reseeding, are not thread-safe. + */ +#endif /* MBEDTLS_THREADING_C */ +/** + * \param p_rng The HMAC_DRBG context. This must be a pointer to a + * #mbedtls_hmac_drbg_context structure. + * \param output The buffer to fill. + * \param out_len The length of the buffer in bytes. + * This must be at most #MBEDTLS_HMAC_DRBG_MAX_REQUEST. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED + * if a call to the entropy source failed. + * \return #MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG if + * \p out_len > #MBEDTLS_HMAC_DRBG_MAX_REQUEST. + */ +int mbedtls_hmac_drbg_random(void *p_rng, unsigned char *output, size_t out_len); + +/** + * \brief This function resets HMAC_DRBG context to the state immediately + * after initial call of mbedtls_hmac_drbg_init(). + * + * \param ctx The HMAC_DRBG context to free. + */ +void mbedtls_hmac_drbg_free(mbedtls_hmac_drbg_context *ctx); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief This function writes a seed file. + * + * \param ctx The HMAC_DRBG context. + * \param path The name of the file. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR on file error. + * \return #MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED on reseed + * failure. + */ +int mbedtls_hmac_drbg_write_seed_file(mbedtls_hmac_drbg_context *ctx, const char *path); + +/** + * \brief This function reads and updates a seed file. The seed + * is added to this instance. + * + * \param ctx The HMAC_DRBG context. + * \param path The name of the file. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR on file error. + * \return #MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED on + * reseed failure. + * \return #MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG if the existing + * seed file is too large. + */ +int mbedtls_hmac_drbg_update_seed_file(mbedtls_hmac_drbg_context *ctx, const char *path); +#endif /* MBEDTLS_FS_IO */ + + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief The HMAC_DRBG Checkup routine. + * + * \return \c 0 if successful. + * \return \c 1 if the test failed. + */ +int mbedtls_hmac_drbg_self_test(int verbose); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_HMAC_DRBG_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/md5.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/md5.h new file mode 100644 index 0000000000..dac9abddf6 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/md5.h @@ -0,0 +1,169 @@ +/** + * \file md5.h + * + * \brief MD5 message digest algorithm (hash function) + * + * \warning MD5 is considered a weak message digest and its use constitutes a + * security risk. We recommend considering stronger message + * digests instead. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_MD5_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_MD5_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD5 context structure + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +typedef struct mbedtls_md5_context { + uint32_t MBEDTLS_PRIVATE(total)[2]; /*!< number of bytes processed */ + uint32_t MBEDTLS_PRIVATE(state)[4]; /*!< intermediate digest state */ + unsigned char MBEDTLS_PRIVATE(buffer)[64]; /*!< data block being processed */ +} +mbedtls_md5_context; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief Initialize MD5 context + * + * \param ctx MD5 context to be initialized + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +void mbedtls_md5_init(mbedtls_md5_context *ctx); + +/** + * \brief Clear MD5 context + * + * \param ctx MD5 context to be cleared + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +void mbedtls_md5_free(mbedtls_md5_context *ctx); + +/** + * \brief Clone (the state of) an MD5 context + * + * \param dst The destination context + * \param src The context to be cloned + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +void mbedtls_md5_clone(mbedtls_md5_context *dst, + const mbedtls_md5_context *src); + +/** + * \brief MD5 context setup + * + * \param ctx context to be initialized + * + * \return 0 if successful + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md5_starts(mbedtls_md5_context *ctx); + +/** + * \brief MD5 process buffer + * + * \param ctx MD5 context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \return 0 if successful + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md5_update(mbedtls_md5_context *ctx, + const unsigned char *input, + size_t ilen); + +/** + * \brief MD5 final digest + * + * \param ctx MD5 context + * \param output MD5 checksum result + * + * \return 0 if successful + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md5_finish(mbedtls_md5_context *ctx, + unsigned char output[16]); + +/** + * \brief Output = MD5( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD5 checksum result + * + * \return 0 if successful + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md5(const unsigned char *input, + size_t ilen, + unsigned char output[16]); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md5_self_test(int verbose); + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_MD5_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/pkcs5.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/pkcs5.h new file mode 100644 index 0000000000..94c56f1cbb --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/pkcs5.h @@ -0,0 +1,123 @@ +/** + * \file pkcs5.h + * + * \brief PKCS#5 functions + * + * \author Mathias Olsson + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_PKCS5_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_PKCS5_H + +#include "tf-psa-crypto/build_info.h" +#include "mbedtls/platform_util.h" + +#include "mbedtls/asn1.h" +#include "mbedtls/md.h" +#include "mbedtls/private/cipher.h" + +#include +#include + +/** Bad input parameters to function. */ +#define MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT +/** Unexpected ASN.1 data. */ +#define MBEDTLS_ERR_PKCS5_INVALID_FORMAT -0x2f00 +/** Requested encryption or digest alg not available. */ +#define MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE -0x2e80 +/** Given private key password does not allow for correct decryption. */ +#define MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH -0x2e00 + +#define MBEDTLS_PKCS5_DECRYPT MBEDTLS_DECRYPT +#define MBEDTLS_PKCS5_ENCRYPT MBEDTLS_ENCRYPT + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_ASN1_PARSE_C) && defined(MBEDTLS_CIPHER_C) + +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) + +/** + * \brief PKCS#5 PBES2 function + * + * \warning When decrypting: + * - This function validates the CBC padding and returns + * #MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH if the padding is + * invalid. Note that this can help active adversaries + * attempting to brute-forcing the password. Note also that + * there is no guarantee that an invalid password will be + * detected (the chances of a valid padding with a random + * password are about 1/255). + * + * \param pbe_params the ASN.1 algorithm parameters + * \param mode either #MBEDTLS_PKCS5_DECRYPT or #MBEDTLS_PKCS5_ENCRYPT + * \param pwd password to use when generating key + * \param pwdlen length of password + * \param data data to process + * \param datalen length of data + * \param output Output buffer. + * On success, it contains the decrypted data. + * On failure, the content is indetermidate. + * For decryption, there must be enough room for \p datalen + * bytes. + * For encryption, there must be enough room for + * \p datalen + 1 bytes, rounded up to the block size of + * the block cipher identified by \p pbe_params. + * \param output_size size of output buffer. + * This must be big enough to accommodate for output plus + * padding data. + * \param output_len On success, length of actual data written to the output buffer. + * + * \returns 0 on success, or a MBEDTLS_ERR_XXX code if parsing or decryption fails. + */ +int mbedtls_pkcs5_pbes2_ext(const mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t datalen, + unsigned char *output, size_t output_size, + size_t *output_len); + +#endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */ + +#endif /* MBEDTLS_ASN1_PARSE_C && MBEDTLS_CIPHER_C*/ + +/** + * \brief PKCS#5 PBKDF2 using HMAC without using the HMAC context + * + * \param md_type Hash algorithm used + * \param password Password to use when generating key + * \param plen Length of password + * \param salt Salt to use when generating key + * \param slen Length of salt + * \param iteration_count Iteration count + * \param key_length Length of generated key in bytes + * \param output Generated key. Must be at least as big as key_length + * + * \returns 0 on success, or a MBEDTLS_ERR_XXX code if verification fails. + */ +int mbedtls_pkcs5_pbkdf2_hmac_ext(mbedtls_md_type_t md_type, + const unsigned char *password, + size_t plen, const unsigned char *salt, size_t slen, + unsigned int iteration_count, + uint32_t key_length, unsigned char *output); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_pkcs5_self_test(int verbose); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_PKCS5_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/poly1305.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/poly1305.h new file mode 100644 index 0000000000..4c0c9970e3 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/poly1305.h @@ -0,0 +1,165 @@ +/** + * \file poly1305.h + * + * \brief This file contains Poly1305 definitions and functions. + * + * Poly1305 is a one-time message authenticator that can be used to + * authenticate messages. Poly1305-AES was created by Daniel + * Bernstein https://cr.yp.to/mac/poly1305-20050329.pdf The generic + * Poly1305 algorithm (not tied to AES) was also standardized in RFC + * 7539. + * + * \author Daniel King + */ + +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_POLY1305_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_POLY1305_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +#include +#include + +/** Invalid input parameter(s). */ +#define MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct mbedtls_poly1305_context { + uint32_t MBEDTLS_PRIVATE(r)[4]; /** The value for 'r' (low 128 bits of the key). */ + uint32_t MBEDTLS_PRIVATE(s)[4]; /** The value for 's' (high 128 bits of the key). */ + uint32_t MBEDTLS_PRIVATE(acc)[5]; /** The accumulator number. */ + uint8_t MBEDTLS_PRIVATE(queue)[16]; /** The current partial block of data. */ + size_t MBEDTLS_PRIVATE(queue_len); /** The number of bytes stored in 'queue'. */ +} +mbedtls_poly1305_context; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief This function initializes the specified Poly1305 context. + * + * It must be the first API called before using + * the context. + * + * It is usually followed by a call to + * \c mbedtls_poly1305_starts(), then one or more calls to + * \c mbedtls_poly1305_update(), then one call to + * \c mbedtls_poly1305_finish(), then finally + * \c mbedtls_poly1305_free(). + * + * \param ctx The Poly1305 context to initialize. This must + * not be \c NULL. + */ +void mbedtls_poly1305_init(mbedtls_poly1305_context *ctx); + +/** + * \brief This function releases and clears the specified + * Poly1305 context. + * + * \param ctx The Poly1305 context to clear. This may be \c NULL, in which + * case this function is a no-op. If it is not \c NULL, it must + * point to an initialized Poly1305 context. + */ +void mbedtls_poly1305_free(mbedtls_poly1305_context *ctx); + +/** + * \brief This function sets the one-time authentication key. + * + * \warning The key must be unique and unpredictable for each + * invocation of Poly1305. + * + * \param ctx The Poly1305 context to which the key should be bound. + * This must be initialized. + * \param key The buffer containing the \c 32 Byte (\c 256 Bit) key. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_poly1305_starts(mbedtls_poly1305_context *ctx, + const unsigned char key[32]); + +/** + * \brief This functions feeds an input buffer into an ongoing + * Poly1305 computation. + * + * It is called between \c mbedtls_cipher_poly1305_starts() and + * \c mbedtls_cipher_poly1305_finish(). + * It can be called repeatedly to process a stream of data. + * + * \param ctx The Poly1305 context to use for the Poly1305 operation. + * This must be initialized and bound to a key. + * \param ilen The length of the input data in Bytes. + * Any value is accepted. + * \param input The buffer holding the input data. + * This pointer can be \c NULL if `ilen == 0`. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_poly1305_update(mbedtls_poly1305_context *ctx, + const unsigned char *input, + size_t ilen); + +/** + * \brief This function generates the Poly1305 Message + * Authentication Code (MAC). + * + * \param ctx The Poly1305 context to use for the Poly1305 operation. + * This must be initialized and bound to a key. + * \param mac The buffer to where the MAC is written. This must + * be a writable buffer of length \c 16 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_poly1305_finish(mbedtls_poly1305_context *ctx, + unsigned char mac[16]); + +/** + * \brief This function calculates the Poly1305 MAC of the input + * buffer with the provided key. + * + * \warning The key must be unique and unpredictable for each + * invocation of Poly1305. + * + * \param key The buffer containing the \c 32 Byte (\c 256 Bit) key. + * \param ilen The length of the input data in Bytes. + * Any value is accepted. + * \param input The buffer holding the input data. + * This pointer can be \c NULL if `ilen == 0`. + * \param mac The buffer to where the MAC is written. This must be + * a writable buffer of length \c 16 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_poly1305_mac(const unsigned char key[32], + const unsigned char *input, + size_t ilen, + unsigned char mac[16]); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief The Poly1305 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_poly1305_self_test(int verbose); +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_POLY1305_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ripemd160.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ripemd160.h new file mode 100644 index 0000000000..602b634020 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/ripemd160.h @@ -0,0 +1,120 @@ +/** + * \file ripemd160.h + * + * \brief RIPE MD-160 message digest + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_RIPEMD160_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_RIPEMD160_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief RIPEMD-160 context structure + */ +typedef struct mbedtls_ripemd160_context { + uint32_t MBEDTLS_PRIVATE(total)[2]; /*!< number of bytes processed */ + uint32_t MBEDTLS_PRIVATE(state)[5]; /*!< intermediate digest state */ + unsigned char MBEDTLS_PRIVATE(buffer)[64]; /*!< data block being processed */ +} +mbedtls_ripemd160_context; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief Initialize RIPEMD-160 context + * + * \param ctx RIPEMD-160 context to be initialized + */ +void mbedtls_ripemd160_init(mbedtls_ripemd160_context *ctx); + +/** + * \brief Clear RIPEMD-160 context + * + * \param ctx RIPEMD-160 context to be cleared + */ +void mbedtls_ripemd160_free(mbedtls_ripemd160_context *ctx); + +/** + * \brief Clone (the state of) a RIPEMD-160 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_ripemd160_clone(mbedtls_ripemd160_context *dst, + const mbedtls_ripemd160_context *src); + +/** + * \brief RIPEMD-160 context setup + * + * \param ctx context to be initialized + * + * \return 0 if successful + */ +int mbedtls_ripemd160_starts(mbedtls_ripemd160_context *ctx); + +/** + * \brief RIPEMD-160 process buffer + * + * \param ctx RIPEMD-160 context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \return 0 if successful + */ +int mbedtls_ripemd160_update(mbedtls_ripemd160_context *ctx, + const unsigned char *input, + size_t ilen); + +/** + * \brief RIPEMD-160 final digest + * + * \param ctx RIPEMD-160 context + * \param output RIPEMD-160 checksum result + * + * \return 0 if successful + */ +int mbedtls_ripemd160_finish(mbedtls_ripemd160_context *ctx, + unsigned char output[20]); + +/** + * \brief Output = RIPEMD-160( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output RIPEMD-160 checksum result + * + * \return 0 if successful + */ +int mbedtls_ripemd160(const unsigned char *input, + size_t ilen, + unsigned char output[20]); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_ripemd160_self_test(int verbose); + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_RIPEMD160_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/rsa.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/rsa.h new file mode 100644 index 0000000000..5fb7dda2f7 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/rsa.h @@ -0,0 +1,821 @@ +/** + * \file rsa.h + * + * \brief This file provides an API for the RSA public-key cryptosystem. + * + * The RSA public-key cryptosystem is defined in Public-Key + * Cryptography Standards (PKCS) #1 v1.5: RSA Encryption + * and Public-Key Cryptography Standards (PKCS) #1 v2.1: + * RSA Cryptography Specifications. + * + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_RSA_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_RSA_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +#include "mbedtls/private/bignum.h" +#include "mbedtls/md.h" + +/* + * RSA Error codes + */ +/** Bad input parameters to function. */ +#define MBEDTLS_ERR_RSA_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT +/** Input data contains invalid padding and is rejected. */ +#define MBEDTLS_ERR_RSA_INVALID_PADDING PSA_ERROR_INVALID_PADDING +/** Something failed during generation of a key. */ +#define MBEDTLS_ERR_RSA_KEY_GEN_FAILED -0x4180 +/** Key failed to pass the validity check of the library. */ +#define MBEDTLS_ERR_RSA_KEY_CHECK_FAILED -0x4200 +/** The public key operation failed. */ +#define MBEDTLS_ERR_RSA_PUBLIC_FAILED -0x4280 +/** The private key operation failed. */ +#define MBEDTLS_ERR_RSA_PRIVATE_FAILED -0x4300 +/** The PKCS#1 verification failed. */ +#define MBEDTLS_ERR_RSA_VERIFY_FAILED PSA_ERROR_INVALID_SIGNATURE +/** The output buffer for decryption is not large enough. */ +#define MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE PSA_ERROR_BUFFER_TOO_SMALL +/** The random generator failed to generate non-zeros. */ +#define MBEDTLS_ERR_RSA_RNG_FAILED -0x4480 + +/* + * RSA constants + */ + +#define MBEDTLS_RSA_PKCS_V15 0 /**< Use PKCS#1 v1.5 encoding. */ +#define MBEDTLS_RSA_PKCS_V21 1 /**< Use PKCS#1 v2.1 encoding. */ + +#define MBEDTLS_RSA_SIGN 1 /**< Identifier for RSA signature operations. */ +#define MBEDTLS_RSA_CRYPT 2 /**< Identifier for RSA encryption and decryption operations. */ + +#define MBEDTLS_RSA_SALT_LEN_ANY -1 + +/* + * The above constants may be used even if the RSA module is compile out, + * eg for alternative (PKCS#11) RSA implementations in the PK layers. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_RSA_GEN_KEY_MIN_BITS) +#define MBEDTLS_RSA_GEN_KEY_MIN_BITS 1024 +#elif MBEDTLS_RSA_GEN_KEY_MIN_BITS < 128 +#error "MBEDTLS_RSA_GEN_KEY_MIN_BITS must be at least 128 bits" +#endif + +/** + * \brief The RSA context structure. + */ +typedef struct mbedtls_rsa_context { + size_t MBEDTLS_PRIVATE(len); /*!< The size of \p N in Bytes. */ + + mbedtls_mpi MBEDTLS_PRIVATE(N); /*!< The public modulus. */ + mbedtls_mpi MBEDTLS_PRIVATE(E); /*!< The public exponent. */ + + mbedtls_mpi MBEDTLS_PRIVATE(D); /*!< The private exponent. */ + mbedtls_mpi MBEDTLS_PRIVATE(P); /*!< The first prime factor. */ + mbedtls_mpi MBEDTLS_PRIVATE(Q); /*!< The second prime factor. */ + + mbedtls_mpi MBEDTLS_PRIVATE(DP); /*!< D % (P - 1). */ + mbedtls_mpi MBEDTLS_PRIVATE(DQ); /*!< D % (Q - 1). */ + mbedtls_mpi MBEDTLS_PRIVATE(QP); /*!< 1 / (Q % P). */ + + mbedtls_mpi MBEDTLS_PRIVATE(RN); /*!< cached R^2 mod N. */ + + mbedtls_mpi MBEDTLS_PRIVATE(RP); /*!< cached R^2 mod P. */ + mbedtls_mpi MBEDTLS_PRIVATE(RQ); /*!< cached R^2 mod Q. */ + + mbedtls_mpi MBEDTLS_PRIVATE(Vi); /*!< The cached blinding value. */ + mbedtls_mpi MBEDTLS_PRIVATE(Vf); /*!< The cached un-blinding value. */ + + int MBEDTLS_PRIVATE(padding); /*!< Selects padding mode: + #MBEDTLS_RSA_PKCS_V15 for 1.5 padding and + #MBEDTLS_RSA_PKCS_V21 for OAEP or PSS. */ + int MBEDTLS_PRIVATE(hash_id); /*!< Hash identifier of mbedtls_md_type_t type, + as specified in md.h for use in the MGF + mask generating function used in the + EME-OAEP and EMSA-PSS encodings. */ +} +mbedtls_rsa_context; + +/** + * \brief This function initializes an RSA context. + * + * \note This function initializes the padding and the hash + * identifier to respectively #MBEDTLS_RSA_PKCS_V15 and + * #MBEDTLS_MD_NONE. See mbedtls_rsa_set_padding() for more + * information about those parameters. + * + * \param ctx The RSA context to initialize. This must not be \c NULL. + */ +void mbedtls_rsa_init(mbedtls_rsa_context *ctx); + +/** + * \brief This function sets padding for an already initialized RSA + * context. + * + * \note Set padding to #MBEDTLS_RSA_PKCS_V21 for the RSAES-OAEP + * encryption scheme and the RSASSA-PSS signature scheme. + * + * \note The \p hash_id parameter is ignored when using + * #MBEDTLS_RSA_PKCS_V15 padding. + * + * \note The choice of padding mode is strictly enforced for private + * key operations, since there might be security concerns in + * mixing padding modes. For public key operations it is + * a default value, which can be overridden by calling specific + * \c mbedtls_rsa_rsaes_xxx or \c mbedtls_rsa_rsassa_xxx + * functions. + * + * \note The hash selected in \p hash_id is always used for OEAP + * encryption. For PSS signatures, it is always used for + * making signatures, but can be overridden for verifying them. + * If set to #MBEDTLS_MD_NONE, it is always overridden. + * + * \param ctx The initialized RSA context to be configured. + * \param padding The padding mode to use. This must be either + * #MBEDTLS_RSA_PKCS_V15 or #MBEDTLS_RSA_PKCS_V21. + * \param hash_id The hash identifier for PSS or OAEP, if \p padding is + * #MBEDTLS_RSA_PKCS_V21. #MBEDTLS_MD_NONE is accepted by this + * function but may be not suitable for some operations. + * Ignored if \p padding is #MBEDTLS_RSA_PKCS_V15. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_RSA_INVALID_PADDING failure: + * \p padding or \p hash_id is invalid. + */ +int mbedtls_rsa_set_padding(mbedtls_rsa_context *ctx, int padding, + mbedtls_md_type_t hash_id); + +/** + * \brief This function retrieves padding mode of initialized + * RSA context. + * + * \param ctx The initialized RSA context. + * + * \return RSA padding mode. + * + */ +int mbedtls_rsa_get_padding_mode(const mbedtls_rsa_context *ctx); + +/** + * \brief This function retrieves hash identifier of mbedtls_md_type_t + * type. + * + * \param ctx The initialized RSA context. + * + * \return Hash identifier of mbedtls_md_type_t type. + * + */ +int mbedtls_rsa_get_md_alg(const mbedtls_rsa_context *ctx); + +/** + * \brief This function retrieves the length of the RSA modulus in bits. + * + * \param ctx The initialized RSA context. + * + * \return The length of the RSA modulus in bits. + * + */ +size_t mbedtls_rsa_get_bitlen(const mbedtls_rsa_context *ctx); + +/** + * \brief This function retrieves the length of RSA modulus in Bytes. + * + * \param ctx The initialized RSA context. + * + * \return The length of the RSA modulus in Bytes. + * + */ +size_t mbedtls_rsa_get_len(const mbedtls_rsa_context *ctx); + +/** + * \brief This function generates an RSA keypair. + * + * \note mbedtls_rsa_init() must be called before this function, + * to set up the RSA context. + * + * \param ctx The initialized RSA context used to hold the key. + * \param f_rng The RNG function to be used for key generation. + * This is mandatory and must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. + * This may be \c NULL if \p f_rng doesn't need a context. + * \param nbits The size of the public key in bits. + * \param exponent The public exponent to use. For example, \c 65537. + * This must be odd and greater than \c 1. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_gen_key(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + unsigned int nbits, int exponent); + +/** + * \brief This function checks if a context contains at least an RSA + * public key. + * + * If the function runs successfully, it is guaranteed that + * enough information is present to perform an RSA public key + * operation using mbedtls_rsa_public(). + * + * \param ctx The initialized RSA context to check. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + * + */ +int mbedtls_rsa_check_pubkey(const mbedtls_rsa_context *ctx); + +/** + * \brief This function checks if a context contains an RSA private key + * and perform basic consistency checks. + * + * \note The consistency checks performed by this function not only + * ensure that mbedtls_rsa_private() can be called successfully + * on the given context, but that the various parameters are + * mutually consistent with high probability, in the sense that + * mbedtls_rsa_public() and mbedtls_rsa_private() are inverses. + * + * \warning This function should catch accidental misconfigurations + * like swapping of parameters, but it cannot establish full + * trust in the quality of the key material that was used to setup + * the given RSA context. This function is not expected to perform + * extended quality assessments like checking that the prime + * factors are safe. Additionally, it is the responsibility of the + * user to ensure the trustworthiness of the source of his RSA + * parameters, which goes beyond what is effectively checkable + * by the library. + * + * \param ctx The initialized RSA context to check. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_check_privkey(const mbedtls_rsa_context *ctx); + +/** + * \brief This function checks a public-private RSA key pair. + * + * It checks each of the contexts, and makes sure they match. + * + * \param pub The initialized RSA context holding the public key. + * \param prv The initialized RSA context holding the private key. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_check_pub_priv(const mbedtls_rsa_context *pub, + const mbedtls_rsa_context *prv); + +/** + * \brief This function performs an RSA public key operation. + * + * \param ctx The initialized RSA context to use. + * \param input The input buffer. This must be a readable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * \param output The output buffer. This must be a writable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \note This function does not handle message padding. + * + * \note Make sure to set \p input[0] = 0 or ensure that + * input is smaller than \c N. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_public(mbedtls_rsa_context *ctx, + const unsigned char *input, + unsigned char *output); + +/** + * \brief This function performs an RSA private key operation. + * + * \note Blinding is used if and only if a PRNG is provided. + * + * \note If blinding is used, both the base of exponentiation + * and the exponent are blinded, providing protection + * against some side-channel attacks. + * + * \warning It is deprecated and a security risk to not provide + * a PRNG here and thereby prevent the use of blinding. + * Future versions of the library may enforce the presence + * of a PRNG. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function, used for blinding. It is mandatory. + * \param p_rng The RNG context to pass to \p f_rng. This may be \c NULL + * if \p f_rng doesn't need a context. + * \param input The input buffer. This must be a readable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * \param output The output buffer. This must be a writable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + * + */ +int mbedtls_rsa_private(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *input, + unsigned char *output); + +/** + * \brief This function adds the message padding, then performs an RSA + * operation. + * + * It is the generic wrapper for performing a PKCS#1 encryption + * operation. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG to use. It is used for padding generation + * and it is mandatory. + * \param p_rng The RNG context to be passed to \p f_rng. May be + * \c NULL if \p f_rng doesn't need a context argument. + * \param ilen The length of the plaintext in Bytes. + * \param input The input data to encrypt. This must be a readable + * buffer of size \p ilen Bytes. It may be \c NULL if + * `ilen == 0`. + * \param output The output buffer. This must be a writable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_pkcs1_encrypt(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + size_t ilen, + const unsigned char *input, + unsigned char *output); + +/** + * \brief This function performs a PKCS#1 v1.5 encryption operation + * (RSAES-PKCS1-v1_5-ENCRYPT). + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function to use. It is mandatory and used for + * padding generation. + * \param p_rng The RNG context to be passed to \p f_rng. This may + * be \c NULL if \p f_rng doesn't need a context argument. + * \param ilen The length of the plaintext in Bytes. + * \param input The input data to encrypt. This must be a readable + * buffer of size \p ilen Bytes. It may be \c NULL if + * `ilen == 0`. + * \param output The output buffer. This must be a writable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsaes_pkcs1_v15_encrypt(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + size_t ilen, + const unsigned char *input, + unsigned char *output); + +/** + * \brief This function performs a PKCS#1 v2.1 OAEP encryption + * operation (RSAES-OAEP-ENCRYPT). + * + * \note The output buffer must be as large as the size + * of ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function to use. This is needed for padding + * generation and is mandatory. + * \param p_rng The RNG context to be passed to \p f_rng. This may + * be \c NULL if \p f_rng doesn't need a context argument. + * \param label The buffer holding the custom label to use. + * This must be a readable buffer of length \p label_len + * Bytes. It may be \c NULL if \p label_len is \c 0. + * \param label_len The length of the label in Bytes. + * \param ilen The length of the plaintext buffer \p input in Bytes. + * \param input The input data to encrypt. This must be a readable + * buffer of size \p ilen Bytes. It may be \c NULL if + * `ilen == 0`. + * \param output The output buffer. This must be a writable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsaes_oaep_encrypt(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *label, size_t label_len, + size_t ilen, + const unsigned char *input, + unsigned char *output); + +/** + * \brief This function performs an RSA operation, then removes the + * message padding. + * + * It is the generic wrapper for performing a PKCS#1 decryption + * operation. + * + * \warning When \p ctx->padding is set to #MBEDTLS_RSA_PKCS_V15, + * mbedtls_rsa_rsaes_pkcs1_v15_decrypt() is called, which is an + * inherently dangerous function (CWE-242). + * + * \note The output buffer length \c output_max_len should be + * as large as the size \p ctx->len of \p ctx->N (for example, + * 128 Bytes if RSA-1024 is used) to be able to hold an + * arbitrary decrypted message. If it is not large enough to + * hold the decryption of the particular ciphertext provided, + * the function returns \c MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function. This is used for blinding and is + * mandatory; see mbedtls_rsa_private() for more. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context. + * \param olen The address at which to store the length of + * the plaintext. This must not be \c NULL. + * \param input The ciphertext buffer. This must be a readable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * \param output The buffer used to hold the plaintext. This must + * be a writable buffer of length \p output_max_len Bytes. + * \param output_max_len The length in Bytes of the output buffer \p output. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_pkcs1_decrypt(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len); + +/** + * \brief This function performs a PKCS#1 v1.5 decryption + * operation (RSAES-PKCS1-v1_5-DECRYPT). + * + * \warning This is an inherently dangerous function (CWE-242). Unless + * it is used in a side channel free and safe way (eg. + * implementing the TLS protocol as per 7.4.7.1 of RFC 5246), + * the calling code is vulnerable. + * + * \note The output buffer length \c output_max_len should be + * as large as the size \p ctx->len of \p ctx->N, for example, + * 128 Bytes if RSA-1024 is used, to be able to hold an + * arbitrary decrypted message. If it is not large enough to + * hold the decryption of the particular ciphertext provided, + * the function returns #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function. This is used for blinding and is + * mandatory; see mbedtls_rsa_private() for more. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context. + * \param olen The address at which to store the length of + * the plaintext. This must not be \c NULL. + * \param input The ciphertext buffer. This must be a readable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * \param output The buffer used to hold the plaintext. This must + * be a writable buffer of length \p output_max_len Bytes. + * \param output_max_len The length in Bytes of the output buffer \p output. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + * + */ +int mbedtls_rsa_rsaes_pkcs1_v15_decrypt(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len); + +/** + * \brief This function performs a PKCS#1 v2.1 OAEP decryption + * operation (RSAES-OAEP-DECRYPT). + * + * \note The output buffer length \c output_max_len should be + * as large as the size \p ctx->len of \p ctx->N, for + * example, 128 Bytes if RSA-1024 is used, to be able to + * hold an arbitrary decrypted message. If it is not + * large enough to hold the decryption of the particular + * ciphertext provided, the function returns + * #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function. This is used for blinding and is + * mandatory. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context. + * \param label The buffer holding the custom label to use. + * This must be a readable buffer of length \p label_len + * Bytes. It may be \c NULL if \p label_len is \c 0. + * \param label_len The length of the label in Bytes. + * \param olen The address at which to store the length of + * the plaintext. This must not be \c NULL. + * \param input The ciphertext buffer. This must be a readable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * \param output The buffer used to hold the plaintext. This must + * be a writable buffer of length \p output_max_len Bytes. + * \param output_max_len The length in Bytes of the output buffer \p output. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsaes_oaep_decrypt(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *label, size_t label_len, + size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len); + +/** + * \brief This function performs a private RSA operation to sign + * a message digest using PKCS#1. + * + * It is the generic wrapper for performing a PKCS#1 + * signature. + * + * \note The \p sig buffer must be as large as the size + * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \note For PKCS#1 v2.1 encoding, see comments on + * mbedtls_rsa_rsassa_pss_sign_ext() for details on + * \p md_alg and \p hash_id. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function to use. This is mandatory and + * must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be \c NULL + * if \p f_rng doesn't need a context argument. + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest or raw data in Bytes. + * If \p md_alg is not #MBEDTLS_MD_NONE, this must match the + * output length of the corresponding hash algorithm. + * \param hash The buffer holding the message digest or raw data. + * This must be a readable buffer of at least \p hashlen Bytes. + * \param sig The buffer to hold the signature. This must be a writable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. A buffer length of + * #MBEDTLS_MPI_MAX_SIZE is always safe. + * + * \return \c 0 if the signing operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_pkcs1_sign(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig); + +/** + * \brief This function performs a PKCS#1 v1.5 signature + * operation (RSASSA-PKCS1-v1_5-SIGN). + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function. This is used for blinding and is + * mandatory; see mbedtls_rsa_private() for more. + * \param p_rng The RNG context to be passed to \p f_rng. This may be \c NULL + * if \p f_rng doesn't need a context argument. + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest or raw data in Bytes. + * If \p md_alg is not #MBEDTLS_MD_NONE, this must match the + * output length of the corresponding hash algorithm. + * \param hash The buffer holding the message digest or raw data. + * This must be a readable buffer of at least \p hashlen Bytes. + * \param sig The buffer to hold the signature. This must be a writable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. A buffer length of + * #MBEDTLS_MPI_MAX_SIZE is always safe. + * + * \return \c 0 if the signing operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsassa_pkcs1_v15_sign(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig); + +#if defined(MBEDTLS_PKCS1_V21) +/** + * \brief This function performs a PKCS#1 v2.1 PSS signature + * operation (RSASSA-PSS-SIGN). + * + * \note The \c hash_id set in \p ctx by calling + * mbedtls_rsa_set_padding() selects the hash used for the + * encoding operation and for the mask generation function + * (MGF1). For more details on the encoding operation and the + * mask generation function, consult RFC-3447: Public-Key + * Cryptography Standards (PKCS) #1 v2.1: RSA Cryptography + * Specifications. + * + * \note This function enforces that the provided salt length complies + * with FIPS 186-4 §5.5 (e) and RFC 8017 (PKCS#1 v2.2) §9.1.1 + * step 3. The constraint is that the hash length plus the salt + * length plus 2 bytes must be at most the key length. If this + * constraint is not met, this function returns + * #MBEDTLS_ERR_RSA_BAD_INPUT_DATA. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function. It is mandatory and must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be \c NULL + * if \p f_rng doesn't need a context argument. + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest or raw data in Bytes. + * If \p md_alg is not #MBEDTLS_MD_NONE, this must match the + * output length of the corresponding hash algorithm. + * \param hash The buffer holding the message digest or raw data. + * This must be a readable buffer of at least \p hashlen Bytes. + * \param saltlen The length of the salt that should be used. + * If passed #MBEDTLS_RSA_SALT_LEN_ANY, the function will use + * the largest possible salt length up to the hash length, + * which is the largest permitted by some standards including + * FIPS 186-4 §5.5. + * \param sig The buffer to hold the signature. This must be a writable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. A buffer length of + * #MBEDTLS_MPI_MAX_SIZE is always safe. + * + * \return \c 0 if the signing operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsassa_pss_sign_ext(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + int saltlen, + unsigned char *sig); + +#endif /* MBEDTLS_PKCS1_V21 */ + +/** + * \brief This function performs a public RSA operation and checks + * the message digest. + * + * This is the generic wrapper for performing a PKCS#1 + * verification. + * + * \note For PKCS#1 v2.1 encoding, see comments on + * mbedtls_rsa_rsassa_pss_verify_ext() about \c md_alg and + * \c hash_id. + * + * \param ctx The initialized RSA public key context to use. + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest or raw data in Bytes. + * If \p md_alg is not #MBEDTLS_MD_NONE, this must match the + * output length of the corresponding hash algorithm. + * \param hash The buffer holding the message digest or raw data. + * This must be a readable buffer of at least \p hashlen Bytes. + * \param sig The buffer holding the signature. This must be a readable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 if the verify operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_pkcs1_verify(mbedtls_rsa_context *ctx, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig); + +/** + * \brief This function performs a PKCS#1 v1.5 verification + * operation (RSASSA-PKCS1-v1_5-VERIFY). + * + * \param ctx The initialized RSA public key context to use. + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest or raw data in Bytes. + * If \p md_alg is not #MBEDTLS_MD_NONE, this must match the + * output length of the corresponding hash algorithm. + * \param hash The buffer holding the message digest or raw data. + * This must be a readable buffer of at least \p hashlen Bytes. + * \param sig The buffer holding the signature. This must be a readable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 if the verify operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsassa_pkcs1_v15_verify(mbedtls_rsa_context *ctx, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig); + +/** + * \brief This function performs a PKCS#1 v2.1 PSS verification + * operation (RSASSA-PSS-VERIFY). + * + * \note The \p sig buffer must be as large as the size + * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \note The \c hash_id set in \p ctx by mbedtls_rsa_set_padding() is + * ignored. + * + * \param ctx The initialized RSA public key context to use. + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest or raw data in Bytes. + * If \p md_alg is not #MBEDTLS_MD_NONE, this must match the + * output length of the corresponding hash algorithm. + * \param hash The buffer holding the message digest or raw data. + * This must be a readable buffer of at least \p hashlen Bytes. + * \param mgf1_hash_id The message digest algorithm used for the + * verification operation and the mask generation + * function (MGF1). For more details on the encoding + * operation and the mask generation function, consult + * RFC-3447: Public-Key Cryptography Standards + * (PKCS) #1 v2.1: RSA Cryptography + * Specifications. + * \param expected_salt_len The length of the salt used in padding. Use + * #MBEDTLS_RSA_SALT_LEN_ANY to accept any salt length. + * \param sig The buffer holding the signature. This must be a readable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 if the verify operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsassa_pss_verify_ext(mbedtls_rsa_context *ctx, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + mbedtls_md_type_t mgf1_hash_id, + int expected_salt_len, + const unsigned char *sig); + +/** + * \brief This function copies the components of an RSA context. + * + * \param dst The destination context. This must be initialized. + * \param src The source context. This must be initialized. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory allocation failure. + */ +int mbedtls_rsa_copy(mbedtls_rsa_context *dst, const mbedtls_rsa_context *src); + +/** + * \brief This function frees the components of an RSA key. + * + * \param ctx The RSA context to free. May be \c NULL, in which case + * this function is a no-op. If it is not \c NULL, it must + * point to an initialized RSA context. + */ +void mbedtls_rsa_free(mbedtls_rsa_context *ctx); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief The RSA checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_rsa_self_test(int verbose); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_RSA_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/sha1.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/sha1.h new file mode 100644 index 0000000000..9867e9660e --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/sha1.h @@ -0,0 +1,196 @@ +/** + * \file sha1.h + * + * \brief This file contains SHA-1 definitions and functions. + * + * The Secure Hash Algorithm 1 (SHA-1) cryptographic hash function is defined in + * FIPS 180-4: Secure Hash Standard (SHS). + * + * \warning SHA-1 is considered a weak message digest and its use constitutes + * a security risk. We recommend considering stronger message + * digests instead. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_SHA1_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_SHA1_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +#include +#include + +/** SHA-1 input data was malformed. */ +#define MBEDTLS_ERR_SHA1_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief The SHA-1 context structure. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +typedef struct mbedtls_sha1_context { + uint32_t MBEDTLS_PRIVATE(total)[2]; /*!< The number of Bytes processed. */ + uint32_t MBEDTLS_PRIVATE(state)[5]; /*!< The intermediate digest state. */ + unsigned char MBEDTLS_PRIVATE(buffer)[64]; /*!< The data block being processed. */ +} +mbedtls_sha1_context; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief This function initializes a SHA-1 context. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param ctx The SHA-1 context to initialize. + * This must not be \c NULL. + * + */ +void mbedtls_sha1_init(mbedtls_sha1_context *ctx); + +/** + * \brief This function clears a SHA-1 context. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param ctx The SHA-1 context to clear. This may be \c NULL, + * in which case this function does nothing. If it is + * not \c NULL, it must point to an initialized + * SHA-1 context. + * + */ +void mbedtls_sha1_free(mbedtls_sha1_context *ctx); + +/** + * \brief This function clones the state of a SHA-1 context. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param dst The SHA-1 context to clone to. This must be initialized. + * \param src The SHA-1 context to clone from. This must be initialized. + * + */ +void mbedtls_sha1_clone(mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src); + +/** + * \brief This function starts a SHA-1 checksum calculation. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param ctx The SHA-1 context to initialize. This must be initialized. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_sha1_starts(mbedtls_sha1_context *ctx); + +/** + * \brief This function feeds an input buffer into an ongoing SHA-1 + * checksum calculation. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param ctx The SHA-1 context. This must be initialized + * and have a hash operation started. + * \param input The buffer holding the input data. + * This must be a readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data \p input in Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha1_update(mbedtls_sha1_context *ctx, + const unsigned char *input, + size_t ilen); + +/** + * \brief This function finishes the SHA-1 operation, and writes + * the result to the output buffer. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param ctx The SHA-1 context to use. This must be initialized and + * have a hash operation started. + * \param output The SHA-1 checksum result. This must be a writable + * buffer of length \c 20 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha1_finish(mbedtls_sha1_context *ctx, + unsigned char output[20]); + +/** + * \brief This function calculates the SHA-1 checksum of a buffer. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The SHA-1 result is calculated as + * output = SHA-1(input buffer). + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param input The buffer holding the input data. + * This must be a readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data \p input in Bytes. + * \param output The SHA-1 checksum result. + * This must be a writable buffer of length \c 20 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_sha1(const unsigned char *input, + size_t ilen, + unsigned char output[20]); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief The SHA-1 checkup routine. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \return \c 0 on success. + * \return \c 1 on failure. + * + */ +int mbedtls_sha1_self_test(int verbose); + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_SHA1_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/sha256.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/sha256.h new file mode 100644 index 0000000000..217d282855 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/sha256.h @@ -0,0 +1,180 @@ +/** + * \file sha256.h + * + * \brief This file contains SHA-224 and SHA-256 definitions and functions. + * + * The Secure Hash Algorithms 224 and 256 (SHA-224 and SHA-256) cryptographic + * hash functions are defined in FIPS 180-4: Secure Hash Standard (SHS). + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_SHA256_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_SHA256_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +#include +#include + +/** SHA-256 input data was malformed. */ +#define MBEDTLS_ERR_SHA256_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief The SHA-256 context structure. + * + * The structure is used both for SHA-256 and for SHA-224 + * checksum calculations. The choice between these two is + * made in the call to mbedtls_sha256_starts(). + */ +typedef struct mbedtls_sha256_context { + unsigned char MBEDTLS_PRIVATE(buffer)[64]; /*!< The data block being processed. */ + uint32_t MBEDTLS_PRIVATE(total)[2]; /*!< The number of Bytes processed. */ + uint32_t MBEDTLS_PRIVATE(state)[8]; /*!< The intermediate digest state. */ +#if defined(MBEDTLS_SHA224_C) + int MBEDTLS_PRIVATE(is224); /*!< Determines which function to use: + 0: Use SHA-256, or 1: Use SHA-224. */ +#endif +} +mbedtls_sha256_context; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief This function initializes a SHA-256 context. + * + * \param ctx The SHA-256 context to initialize. This must not be \c NULL. + */ +void mbedtls_sha256_init(mbedtls_sha256_context *ctx); + +/** + * \brief This function clears a SHA-256 context. + * + * \param ctx The SHA-256 context to clear. This may be \c NULL, in which + * case this function returns immediately. If it is not \c NULL, + * it must point to an initialized SHA-256 context. + */ +void mbedtls_sha256_free(mbedtls_sha256_context *ctx); + +/** + * \brief This function clones the state of a SHA-256 context. + * + * \param dst The destination context. This must be initialized. + * \param src The context to clone. This must be initialized. + */ +void mbedtls_sha256_clone(mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src); + +/** + * \brief This function starts a SHA-224 or SHA-256 checksum + * calculation. + * + * \param ctx The context to use. This must be initialized. + * \param is224 This determines which function to use. This must be + * either \c 0 for SHA-256, or \c 1 for SHA-224. + * + * \note is224 must be defined accordingly to the enabled + * MBEDTLS_SHA224_C/MBEDTLS_SHA256_C symbols otherwise the + * function will return #MBEDTLS_ERR_SHA512_BAD_INPUT_DATA. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha256_starts(mbedtls_sha256_context *ctx, int is224); + +/** + * \brief This function feeds an input buffer into an ongoing + * SHA-256 checksum calculation. + * + * \param ctx The SHA-256 context. This must be initialized + * and have a hash operation started. + * \param input The buffer holding the data. This must be a readable + * buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha256_update(mbedtls_sha256_context *ctx, + const unsigned char *input, + size_t ilen); + +/** + * \brief This function finishes the SHA-256 operation, and writes + * the result to the output buffer. + * + * \param ctx The SHA-256 context. This must be initialized + * and have a hash operation started. + * \param output The SHA-224 or SHA-256 checksum result. + * This must be a writable buffer of length \c 32 bytes + * for SHA-256, \c 28 bytes for SHA-224. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha256_finish(mbedtls_sha256_context *ctx, + unsigned char *output); + +/** + * \brief This function calculates the SHA-224 or SHA-256 + * checksum of a buffer. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The SHA-256 result is calculated as + * output = SHA-256(input buffer). + * + * \param input The buffer holding the data. This must be a readable + * buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * \param output The SHA-224 or SHA-256 checksum result. + * This must be a writable buffer of length \c 32 bytes + * for SHA-256, \c 28 bytes for SHA-224. + * \param is224 Determines which function to use. This must be + * either \c 0 for SHA-256, or \c 1 for SHA-224. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha256(const unsigned char *input, + size_t ilen, + unsigned char *output, + int is224); + +#if defined(MBEDTLS_SELF_TEST) + +#if defined(MBEDTLS_SHA224_C) +/** + * \brief The SHA-224 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_sha224_self_test(int verbose); +#endif /* MBEDTLS_SHA224_C */ + +#if defined(MBEDTLS_SHA256_C) +/** + * \brief The SHA-256 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_sha256_self_test(int verbose); +#endif /* MBEDTLS_SHA256_C */ + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_SHA256_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/sha3.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/sha3.h new file mode 100644 index 0000000000..b84e6a8765 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/sha3.h @@ -0,0 +1,189 @@ +/** + * \file sha3.h + * + * \brief This file contains SHA-3 and SHAKE definitions and functions. + * + * The Secure Hash Algorithms cryptographic + * hash functions are defined in FIPS 202: SHA-3 Standard: + * Permutation-Based Hash and Extendable-Output Functions . + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_SHA3_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_SHA3_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** SHA-3 input data was malformed. */ +#define MBEDTLS_ERR_SHA3_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * SHA-3 or SHAKE family id. + * + * It identifies the family (SHA3-256, SHA3-512, etc.) + */ + +typedef enum { + MBEDTLS_SHA3_NONE = 0, /*!< Operation not defined. */ + MBEDTLS_SHA3_224, /*!< SHA3-224 */ + MBEDTLS_SHA3_256, /*!< SHA3-256 */ + MBEDTLS_SHA3_384, /*!< SHA3-384 */ + MBEDTLS_SHA3_512, /*!< SHA3-512 */ + MBEDTLS_SHA3_SHAKE128, /*!< SHA3-SHAKE128 */ + MBEDTLS_SHA3_SHAKE256, /*!< SHA3-SHAKE256 */ +} mbedtls_sha3_id; +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +/** + * \brief The SHA-3 context structure. + * + * The structure is used SHA-3 checksum calculations. + */ +typedef struct { + uint64_t MBEDTLS_PRIVATE(state[25]); + uint32_t MBEDTLS_PRIVATE(index); + uint16_t MBEDTLS_PRIVATE(olen); + uint16_t MBEDTLS_PRIVATE(max_block_size); + uint8_t MBEDTLS_PRIVATE(finished); +} +mbedtls_sha3_context; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief This function initializes a SHA-3 or SHAKE context. + * + * \param ctx The SHA-3 context to initialize. This must not be \c NULL. + */ +void mbedtls_sha3_init(mbedtls_sha3_context *ctx); + +/** + * \brief This function clears a SHA-3 or SHAKE context. + * + * \param ctx The SHA-3 context to clear. This may be \c NULL, in which + * case this function returns immediately. If it is not \c NULL, + * it must point to an initialized SHA-3 context. + */ +void mbedtls_sha3_free(mbedtls_sha3_context *ctx); + +/** + * \brief This function clones the state of a SHA-3 or SHAKE context. + * + * \param dst The destination context. This must be initialized. + * \param src The context to clone. This must be initialized. + */ +void mbedtls_sha3_clone(mbedtls_sha3_context *dst, + const mbedtls_sha3_context *src); + +/** + * \brief This function starts a SHA-3 checksum or SHAKE XOF + * calculation. + * + * \param ctx The context to use. This must be initialized. + * \param id The id of the SHA-3 or SHAKE family. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha3_starts(mbedtls_sha3_context *ctx, mbedtls_sha3_id id); + +/** + * \brief This function feeds an input buffer into an ongoing + * SHA-3 or SHAKE calculation. + * + * \param ctx The SHA-3 context. This must be initialized + * and have a hash operation started. + * \param input The buffer holding the data. This must be a readable + * buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha3_update(mbedtls_sha3_context *ctx, + const uint8_t *input, + size_t ilen); + +/** + * \brief This function finishes the SHA-3 operation, and writes + * the result to the output buffer. + * + * In a SHA-3 calculation, this function must be called + * exactly once, and \p olen must be the length of the + * hash variant chosen in mbedtls_sha3_starts(). + * In a SHAKE calculation, this function may be called + * any number of times to obtain successive chunks of + * the XOF output. + * + * \param ctx The SHA-3 context. This must be initialized + * and have a hash operation started. + * \param output The SHA-3 checksum result. + * This must be a writable buffer of length \c olen bytes. + * \param olen Defines the length of output buffer (in bytes). For SHA-3 224, SHA-3 256, + * SHA-3 384 and SHA-3 512 \c olen must equal to 28, 32, 48 and 64, + * respectively. + * For SHAKE128 and SHAKE256 it can be an arbitrary number. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha3_finish(mbedtls_sha3_context *ctx, + uint8_t *output, size_t olen); + +/** + * \brief This function calculates the SHA-3 checksum + * or XOF output of a buffer. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The SHA-3 result is calculated as + * output = SHA-3(id, input buffer, d). + * + * \param id The id of the SHA-3 family. + * \param input The buffer holding the data. This must be a readable + * buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * \param output The SHA-3 checksum result. + * This must be a writable buffer of length \c olen bytes. + * \param olen Defines the length of output buffer (in bytes). For SHA-3 224, SHA-3 256, + * SHA-3 384 and SHA-3 512 \c olen must equal to 28, 32, 48 and 64, + * respectively. + * For SHAKE128 and SHAKE256 it can be an arbitrary number. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha3(mbedtls_sha3_id id, const uint8_t *input, + size_t ilen, + uint8_t *output, + size_t olen); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine for the algorithms implemented + * by this module: SHA3-224, SHA3-256, SHA3-384, SHA3-512. + * + * \return 0 if successful, or 1 if the test failed. + */ +int mbedtls_sha3_self_test(int verbose); +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_SHA3_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private/sha512.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/sha512.h new file mode 100644 index 0000000000..b450f1c014 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private/sha512.h @@ -0,0 +1,188 @@ +/** + * \file sha512.h + * \brief This file contains SHA-384 and SHA-512 definitions and functions. + * + * The Secure Hash Algorithms 384 and 512 (SHA-384 and SHA-512) cryptographic + * hash functions are defined in FIPS 180-4: Secure Hash Standard (SHS). + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_SHA512_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_SHA512_H +#include "mbedtls/private_access.h" + +#include "tf-psa-crypto/build_info.h" + +#include +#include + +/** SHA-512 input data was malformed. */ +#define MBEDTLS_ERR_SHA512_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief The SHA-512 context structure. + * + * The structure is used both for SHA-384 and for SHA-512 + * checksum calculations. The choice between these two is + * made in the call to mbedtls_sha512_starts(). + */ +typedef struct mbedtls_sha512_context { + uint64_t MBEDTLS_PRIVATE(total)[2]; /*!< The number of Bytes processed. */ + uint64_t MBEDTLS_PRIVATE(state)[8]; /*!< The intermediate digest state. */ + unsigned char MBEDTLS_PRIVATE(buffer)[128]; /*!< The data block being processed. */ +#if defined(MBEDTLS_SHA384_C) + int MBEDTLS_PRIVATE(is384); /*!< Determines which function to use: + 0: Use SHA-512, or 1: Use SHA-384. */ +#endif +} +mbedtls_sha512_context; + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) +/** + * \brief This function initializes a SHA-512 context. + * + * \param ctx The SHA-512 context to initialize. This must + * not be \c NULL. + */ +void mbedtls_sha512_init(mbedtls_sha512_context *ctx); + +/** + * \brief This function clears a SHA-512 context. + * + * \param ctx The SHA-512 context to clear. This may be \c NULL, + * in which case this function does nothing. If it + * is not \c NULL, it must point to an initialized + * SHA-512 context. + */ +void mbedtls_sha512_free(mbedtls_sha512_context *ctx); + +/** + * \brief This function clones the state of a SHA-512 context. + * + * \param dst The destination context. This must be initialized. + * \param src The context to clone. This must be initialized. + */ +void mbedtls_sha512_clone(mbedtls_sha512_context *dst, + const mbedtls_sha512_context *src); + +/** + * \brief This function starts a SHA-384 or SHA-512 checksum + * calculation. + * + * \param ctx The SHA-512 context to use. This must be initialized. + * \param is384 Determines which function to use. This must be + * either \c 0 for SHA-512, or \c 1 for SHA-384. + * + * \note is384 must be defined accordingly to the enabled + * MBEDTLS_SHA384_C/MBEDTLS_SHA512_C symbols otherwise the + * function will return #MBEDTLS_ERR_SHA512_BAD_INPUT_DATA. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha512_starts(mbedtls_sha512_context *ctx, int is384); + +/** + * \brief This function feeds an input buffer into an ongoing + * SHA-512 checksum calculation. + * + * \param ctx The SHA-512 context. This must be initialized + * and have a hash operation started. + * \param input The buffer holding the input data. This must + * be a readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha512_update(mbedtls_sha512_context *ctx, + const unsigned char *input, + size_t ilen); + +/** + * \brief This function finishes the SHA-512 operation, and writes + * the result to the output buffer. + * + * \param ctx The SHA-512 context. This must be initialized + * and have a hash operation started. + * \param output The SHA-384 or SHA-512 checksum result. + * This must be a writable buffer of length \c 64 bytes + * for SHA-512, \c 48 bytes for SHA-384. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha512_finish(mbedtls_sha512_context *ctx, + unsigned char *output); + +/** + * \brief This function calculates the SHA-512 or SHA-384 + * checksum of a buffer. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The SHA-512 result is calculated as + * output = SHA-512(input buffer). + * + * \param input The buffer holding the input data. This must be + * a readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * \param output The SHA-384 or SHA-512 checksum result. + * This must be a writable buffer of length \c 64 bytes + * for SHA-512, \c 48 bytes for SHA-384. + * \param is384 Determines which function to use. This must be either + * \c 0 for SHA-512, or \c 1 for SHA-384. + * + * \note is384 must be defined accordingly with the supported + * symbols in the config file. If: + * - is384 is 0, but \c MBEDTLS_SHA384_C is not defined, or + * - is384 is 1, but \c MBEDTLS_SHA512_C is not defined + * then the function will return + * #MBEDTLS_ERR_SHA512_BAD_INPUT_DATA. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha512(const unsigned char *input, + size_t ilen, + unsigned char *output, + int is384); + +#if defined(MBEDTLS_SELF_TEST) + +#if defined(MBEDTLS_SHA384_C) +/** + * \brief The SHA-384 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_sha384_self_test(int verbose); +#endif /* MBEDTLS_SHA384_C */ + +#if defined(MBEDTLS_SHA512_C) +/** + * \brief The SHA-512 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_sha512_self_test(int verbose); +#endif /* MBEDTLS_SHA512_C */ + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_SHA512_H */ diff --git a/tf-psa-crypto/drivers/builtin/include/mbedtls/private_access.h b/tf-psa-crypto/drivers/builtin/include/mbedtls/private_access.h new file mode 100644 index 0000000000..b4ff4762e2 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/include/mbedtls/private_access.h @@ -0,0 +1,53 @@ +/** + * \file private_access.h + * + * \brief Optionally activate declarations of private identifiers + * in public headers. + * + * This header is reserved for internal use in TF-PSA-Crypto and Mbed TLS. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ACCESS_H +#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ACCESS_H + +#ifndef MBEDTLS_ALLOW_PRIVATE_ACCESS +/* Public use: do not declare private identifiers. */ + +/* Pseudo-hide an identifier (typically a struct or union member) by giving + * it the prefix `private_`. + * + * Typical usage: + * ``` + * typedef struct { + * int MBEDTLS_PRIVATE(foo); // private member (not part of the public API, + * // but part of the ABI) + * int bar; // public member (covered by API stability guarantees) + * } mbedtls_some_type_t; + * ``` + */ +#define MBEDTLS_PRIVATE(member) private_##member + +#else +/* Private use: declare private identifiers. */ + +#define MBEDTLS_PRIVATE(member) member + +/* Activate declarations guarded by this macro. + * + * Typical usage: + * ``` + * typedef ... mbedtls_some_type_t; // built-in crypto type + * #if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) + * int mbedtls_some_function(...); // built-in crypto function + * #endif // MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS + * ``` + */ +#define MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS + +#endif + +#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ACCESS_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/.gitignore b/tf-psa-crypto/drivers/builtin/src/.gitignore new file mode 100644 index 0000000000..9e36d25c01 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/.gitignore @@ -0,0 +1,3 @@ +###START_GENERATED_FILES### +/error.c +###END_GENERATED_FILES### diff --git a/tf-psa-crypto/drivers/builtin/src/aes.c b/tf-psa-crypto/drivers/builtin/src/aes.c new file mode 100644 index 0000000000..0bb4ff4896 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/aes.c @@ -0,0 +1,2236 @@ +/* + * FIPS-197 compliant AES implementation + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +/* + * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. + * + * https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/aes-development/rijndael-ammended.pdf + * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_AES_C) + +#include + +#include "mbedtls/private/aes.h" +#include "mbedtls/platform.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#if defined(MBEDTLS_AES_USE_HARDWARE_ONLY) +#if !((defined(MBEDTLS_ARCH_IS_ARMV8_A) && defined(MBEDTLS_AESCE_C)) || \ + (defined(MBEDTLS_ARCH_IS_X64) && defined(MBEDTLS_AESNI_C)) || \ + (defined(MBEDTLS_ARCH_IS_X86) && defined(MBEDTLS_AESNI_C))) +#error "MBEDTLS_AES_USE_HARDWARE_ONLY defined, but not all prerequisites" +#endif +#endif + +#if defined(MBEDTLS_AESNI_C) +#include "aesni.h" +#endif +#if defined(MBEDTLS_AESCE_C) +#include "aesce.h" +#endif + +#include "mbedtls/platform.h" +#include "ctr.h" + +/* + * This is a convenience shorthand macro to check if we need reverse S-box and + * reverse tables. It's private and only defined in this file. + */ +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +#define MBEDTLS_AES_NEED_REVERSE_TABLES +#endif + +#if defined(MBEDTLS_AES_ROM_TABLES) +/* + * Forward S-box + */ +MBEDTLS_MAYBE_UNUSED static const unsigned char FSb[256] = +{ + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, + 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, + 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, + 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, + 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, + 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, + 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, + 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, + 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, + 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, + 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, + 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 +}; + +/* + * Forward tables + */ +#define FT \ +\ + V(A5, 63, 63, C6), V(84, 7C, 7C, F8), V(99, 77, 77, EE), V(8D, 7B, 7B, F6), \ + V(0D, F2, F2, FF), V(BD, 6B, 6B, D6), V(B1, 6F, 6F, DE), V(54, C5, C5, 91), \ + V(50, 30, 30, 60), V(03, 01, 01, 02), V(A9, 67, 67, CE), V(7D, 2B, 2B, 56), \ + V(19, FE, FE, E7), V(62, D7, D7, B5), V(E6, AB, AB, 4D), V(9A, 76, 76, EC), \ + V(45, CA, CA, 8F), V(9D, 82, 82, 1F), V(40, C9, C9, 89), V(87, 7D, 7D, FA), \ + V(15, FA, FA, EF), V(EB, 59, 59, B2), V(C9, 47, 47, 8E), V(0B, F0, F0, FB), \ + V(EC, AD, AD, 41), V(67, D4, D4, B3), V(FD, A2, A2, 5F), V(EA, AF, AF, 45), \ + V(BF, 9C, 9C, 23), V(F7, A4, A4, 53), V(96, 72, 72, E4), V(5B, C0, C0, 9B), \ + V(C2, B7, B7, 75), V(1C, FD, FD, E1), V(AE, 93, 93, 3D), V(6A, 26, 26, 4C), \ + V(5A, 36, 36, 6C), V(41, 3F, 3F, 7E), V(02, F7, F7, F5), V(4F, CC, CC, 83), \ + V(5C, 34, 34, 68), V(F4, A5, A5, 51), V(34, E5, E5, D1), V(08, F1, F1, F9), \ + V(93, 71, 71, E2), V(73, D8, D8, AB), V(53, 31, 31, 62), V(3F, 15, 15, 2A), \ + V(0C, 04, 04, 08), V(52, C7, C7, 95), V(65, 23, 23, 46), V(5E, C3, C3, 9D), \ + V(28, 18, 18, 30), V(A1, 96, 96, 37), V(0F, 05, 05, 0A), V(B5, 9A, 9A, 2F), \ + V(09, 07, 07, 0E), V(36, 12, 12, 24), V(9B, 80, 80, 1B), V(3D, E2, E2, DF), \ + V(26, EB, EB, CD), V(69, 27, 27, 4E), V(CD, B2, B2, 7F), V(9F, 75, 75, EA), \ + V(1B, 09, 09, 12), V(9E, 83, 83, 1D), V(74, 2C, 2C, 58), V(2E, 1A, 1A, 34), \ + V(2D, 1B, 1B, 36), V(B2, 6E, 6E, DC), V(EE, 5A, 5A, B4), V(FB, A0, A0, 5B), \ + V(F6, 52, 52, A4), V(4D, 3B, 3B, 76), V(61, D6, D6, B7), V(CE, B3, B3, 7D), \ + V(7B, 29, 29, 52), V(3E, E3, E3, DD), V(71, 2F, 2F, 5E), V(97, 84, 84, 13), \ + V(F5, 53, 53, A6), V(68, D1, D1, B9), V(00, 00, 00, 00), V(2C, ED, ED, C1), \ + V(60, 20, 20, 40), V(1F, FC, FC, E3), V(C8, B1, B1, 79), V(ED, 5B, 5B, B6), \ + V(BE, 6A, 6A, D4), V(46, CB, CB, 8D), V(D9, BE, BE, 67), V(4B, 39, 39, 72), \ + V(DE, 4A, 4A, 94), V(D4, 4C, 4C, 98), V(E8, 58, 58, B0), V(4A, CF, CF, 85), \ + V(6B, D0, D0, BB), V(2A, EF, EF, C5), V(E5, AA, AA, 4F), V(16, FB, FB, ED), \ + V(C5, 43, 43, 86), V(D7, 4D, 4D, 9A), V(55, 33, 33, 66), V(94, 85, 85, 11), \ + V(CF, 45, 45, 8A), V(10, F9, F9, E9), V(06, 02, 02, 04), V(81, 7F, 7F, FE), \ + V(F0, 50, 50, A0), V(44, 3C, 3C, 78), V(BA, 9F, 9F, 25), V(E3, A8, A8, 4B), \ + V(F3, 51, 51, A2), V(FE, A3, A3, 5D), V(C0, 40, 40, 80), V(8A, 8F, 8F, 05), \ + V(AD, 92, 92, 3F), V(BC, 9D, 9D, 21), V(48, 38, 38, 70), V(04, F5, F5, F1), \ + V(DF, BC, BC, 63), V(C1, B6, B6, 77), V(75, DA, DA, AF), V(63, 21, 21, 42), \ + V(30, 10, 10, 20), V(1A, FF, FF, E5), V(0E, F3, F3, FD), V(6D, D2, D2, BF), \ + V(4C, CD, CD, 81), V(14, 0C, 0C, 18), V(35, 13, 13, 26), V(2F, EC, EC, C3), \ + V(E1, 5F, 5F, BE), V(A2, 97, 97, 35), V(CC, 44, 44, 88), V(39, 17, 17, 2E), \ + V(57, C4, C4, 93), V(F2, A7, A7, 55), V(82, 7E, 7E, FC), V(47, 3D, 3D, 7A), \ + V(AC, 64, 64, C8), V(E7, 5D, 5D, BA), V(2B, 19, 19, 32), V(95, 73, 73, E6), \ + V(A0, 60, 60, C0), V(98, 81, 81, 19), V(D1, 4F, 4F, 9E), V(7F, DC, DC, A3), \ + V(66, 22, 22, 44), V(7E, 2A, 2A, 54), V(AB, 90, 90, 3B), V(83, 88, 88, 0B), \ + V(CA, 46, 46, 8C), V(29, EE, EE, C7), V(D3, B8, B8, 6B), V(3C, 14, 14, 28), \ + V(79, DE, DE, A7), V(E2, 5E, 5E, BC), V(1D, 0B, 0B, 16), V(76, DB, DB, AD), \ + V(3B, E0, E0, DB), V(56, 32, 32, 64), V(4E, 3A, 3A, 74), V(1E, 0A, 0A, 14), \ + V(DB, 49, 49, 92), V(0A, 06, 06, 0C), V(6C, 24, 24, 48), V(E4, 5C, 5C, B8), \ + V(5D, C2, C2, 9F), V(6E, D3, D3, BD), V(EF, AC, AC, 43), V(A6, 62, 62, C4), \ + V(A8, 91, 91, 39), V(A4, 95, 95, 31), V(37, E4, E4, D3), V(8B, 79, 79, F2), \ + V(32, E7, E7, D5), V(43, C8, C8, 8B), V(59, 37, 37, 6E), V(B7, 6D, 6D, DA), \ + V(8C, 8D, 8D, 01), V(64, D5, D5, B1), V(D2, 4E, 4E, 9C), V(E0, A9, A9, 49), \ + V(B4, 6C, 6C, D8), V(FA, 56, 56, AC), V(07, F4, F4, F3), V(25, EA, EA, CF), \ + V(AF, 65, 65, CA), V(8E, 7A, 7A, F4), V(E9, AE, AE, 47), V(18, 08, 08, 10), \ + V(D5, BA, BA, 6F), V(88, 78, 78, F0), V(6F, 25, 25, 4A), V(72, 2E, 2E, 5C), \ + V(24, 1C, 1C, 38), V(F1, A6, A6, 57), V(C7, B4, B4, 73), V(51, C6, C6, 97), \ + V(23, E8, E8, CB), V(7C, DD, DD, A1), V(9C, 74, 74, E8), V(21, 1F, 1F, 3E), \ + V(DD, 4B, 4B, 96), V(DC, BD, BD, 61), V(86, 8B, 8B, 0D), V(85, 8A, 8A, 0F), \ + V(90, 70, 70, E0), V(42, 3E, 3E, 7C), V(C4, B5, B5, 71), V(AA, 66, 66, CC), \ + V(D8, 48, 48, 90), V(05, 03, 03, 06), V(01, F6, F6, F7), V(12, 0E, 0E, 1C), \ + V(A3, 61, 61, C2), V(5F, 35, 35, 6A), V(F9, 57, 57, AE), V(D0, B9, B9, 69), \ + V(91, 86, 86, 17), V(58, C1, C1, 99), V(27, 1D, 1D, 3A), V(B9, 9E, 9E, 27), \ + V(38, E1, E1, D9), V(13, F8, F8, EB), V(B3, 98, 98, 2B), V(33, 11, 11, 22), \ + V(BB, 69, 69, D2), V(70, D9, D9, A9), V(89, 8E, 8E, 07), V(A7, 94, 94, 33), \ + V(B6, 9B, 9B, 2D), V(22, 1E, 1E, 3C), V(92, 87, 87, 15), V(20, E9, E9, C9), \ + V(49, CE, CE, 87), V(FF, 55, 55, AA), V(78, 28, 28, 50), V(7A, DF, DF, A5), \ + V(8F, 8C, 8C, 03), V(F8, A1, A1, 59), V(80, 89, 89, 09), V(17, 0D, 0D, 1A), \ + V(DA, BF, BF, 65), V(31, E6, E6, D7), V(C6, 42, 42, 84), V(B8, 68, 68, D0), \ + V(C3, 41, 41, 82), V(B0, 99, 99, 29), V(77, 2D, 2D, 5A), V(11, 0F, 0F, 1E), \ + V(CB, B0, B0, 7B), V(FC, 54, 54, A8), V(D6, BB, BB, 6D), V(3A, 16, 16, 2C) + +#define V(a, b, c, d) 0x##a##b##c##d +MBEDTLS_MAYBE_UNUSED static const uint32_t FT0[256] = { FT }; +#undef V + +#define V(a, b, c, d) 0x##b##c##d##a +MBEDTLS_MAYBE_UNUSED static const uint32_t FT1[256] = { FT }; +#undef V + +#define V(a, b, c, d) 0x##c##d##a##b +MBEDTLS_MAYBE_UNUSED static const uint32_t FT2[256] = { FT }; +#undef V + +#define V(a, b, c, d) 0x##d##a##b##c +MBEDTLS_MAYBE_UNUSED static const uint32_t FT3[256] = { FT }; +#undef V + +#undef FT + +/* + * Reverse S-box + */ +MBEDTLS_MAYBE_UNUSED static const unsigned char RSb[256] = +{ + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, + 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, + 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, + 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, + 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, + 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, + 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, + 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, + 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, + 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, + 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, + 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D +}; + +/* + * Reverse tables + */ +#define RT \ +\ + V(50, A7, F4, 51), V(53, 65, 41, 7E), V(C3, A4, 17, 1A), V(96, 5E, 27, 3A), \ + V(CB, 6B, AB, 3B), V(F1, 45, 9D, 1F), V(AB, 58, FA, AC), V(93, 03, E3, 4B), \ + V(55, FA, 30, 20), V(F6, 6D, 76, AD), V(91, 76, CC, 88), V(25, 4C, 02, F5), \ + V(FC, D7, E5, 4F), V(D7, CB, 2A, C5), V(80, 44, 35, 26), V(8F, A3, 62, B5), \ + V(49, 5A, B1, DE), V(67, 1B, BA, 25), V(98, 0E, EA, 45), V(E1, C0, FE, 5D), \ + V(02, 75, 2F, C3), V(12, F0, 4C, 81), V(A3, 97, 46, 8D), V(C6, F9, D3, 6B), \ + V(E7, 5F, 8F, 03), V(95, 9C, 92, 15), V(EB, 7A, 6D, BF), V(DA, 59, 52, 95), \ + V(2D, 83, BE, D4), V(D3, 21, 74, 58), V(29, 69, E0, 49), V(44, C8, C9, 8E), \ + V(6A, 89, C2, 75), V(78, 79, 8E, F4), V(6B, 3E, 58, 99), V(DD, 71, B9, 27), \ + V(B6, 4F, E1, BE), V(17, AD, 88, F0), V(66, AC, 20, C9), V(B4, 3A, CE, 7D), \ + V(18, 4A, DF, 63), V(82, 31, 1A, E5), V(60, 33, 51, 97), V(45, 7F, 53, 62), \ + V(E0, 77, 64, B1), V(84, AE, 6B, BB), V(1C, A0, 81, FE), V(94, 2B, 08, F9), \ + V(58, 68, 48, 70), V(19, FD, 45, 8F), V(87, 6C, DE, 94), V(B7, F8, 7B, 52), \ + V(23, D3, 73, AB), V(E2, 02, 4B, 72), V(57, 8F, 1F, E3), V(2A, AB, 55, 66), \ + V(07, 28, EB, B2), V(03, C2, B5, 2F), V(9A, 7B, C5, 86), V(A5, 08, 37, D3), \ + V(F2, 87, 28, 30), V(B2, A5, BF, 23), V(BA, 6A, 03, 02), V(5C, 82, 16, ED), \ + V(2B, 1C, CF, 8A), V(92, B4, 79, A7), V(F0, F2, 07, F3), V(A1, E2, 69, 4E), \ + V(CD, F4, DA, 65), V(D5, BE, 05, 06), V(1F, 62, 34, D1), V(8A, FE, A6, C4), \ + V(9D, 53, 2E, 34), V(A0, 55, F3, A2), V(32, E1, 8A, 05), V(75, EB, F6, A4), \ + V(39, EC, 83, 0B), V(AA, EF, 60, 40), V(06, 9F, 71, 5E), V(51, 10, 6E, BD), \ + V(F9, 8A, 21, 3E), V(3D, 06, DD, 96), V(AE, 05, 3E, DD), V(46, BD, E6, 4D), \ + V(B5, 8D, 54, 91), V(05, 5D, C4, 71), V(6F, D4, 06, 04), V(FF, 15, 50, 60), \ + V(24, FB, 98, 19), V(97, E9, BD, D6), V(CC, 43, 40, 89), V(77, 9E, D9, 67), \ + V(BD, 42, E8, B0), V(88, 8B, 89, 07), V(38, 5B, 19, E7), V(DB, EE, C8, 79), \ + V(47, 0A, 7C, A1), V(E9, 0F, 42, 7C), V(C9, 1E, 84, F8), V(00, 00, 00, 00), \ + V(83, 86, 80, 09), V(48, ED, 2B, 32), V(AC, 70, 11, 1E), V(4E, 72, 5A, 6C), \ + V(FB, FF, 0E, FD), V(56, 38, 85, 0F), V(1E, D5, AE, 3D), V(27, 39, 2D, 36), \ + V(64, D9, 0F, 0A), V(21, A6, 5C, 68), V(D1, 54, 5B, 9B), V(3A, 2E, 36, 24), \ + V(B1, 67, 0A, 0C), V(0F, E7, 57, 93), V(D2, 96, EE, B4), V(9E, 91, 9B, 1B), \ + V(4F, C5, C0, 80), V(A2, 20, DC, 61), V(69, 4B, 77, 5A), V(16, 1A, 12, 1C), \ + V(0A, BA, 93, E2), V(E5, 2A, A0, C0), V(43, E0, 22, 3C), V(1D, 17, 1B, 12), \ + V(0B, 0D, 09, 0E), V(AD, C7, 8B, F2), V(B9, A8, B6, 2D), V(C8, A9, 1E, 14), \ + V(85, 19, F1, 57), V(4C, 07, 75, AF), V(BB, DD, 99, EE), V(FD, 60, 7F, A3), \ + V(9F, 26, 01, F7), V(BC, F5, 72, 5C), V(C5, 3B, 66, 44), V(34, 7E, FB, 5B), \ + V(76, 29, 43, 8B), V(DC, C6, 23, CB), V(68, FC, ED, B6), V(63, F1, E4, B8), \ + V(CA, DC, 31, D7), V(10, 85, 63, 42), V(40, 22, 97, 13), V(20, 11, C6, 84), \ + V(7D, 24, 4A, 85), V(F8, 3D, BB, D2), V(11, 32, F9, AE), V(6D, A1, 29, C7), \ + V(4B, 2F, 9E, 1D), V(F3, 30, B2, DC), V(EC, 52, 86, 0D), V(D0, E3, C1, 77), \ + V(6C, 16, B3, 2B), V(99, B9, 70, A9), V(FA, 48, 94, 11), V(22, 64, E9, 47), \ + V(C4, 8C, FC, A8), V(1A, 3F, F0, A0), V(D8, 2C, 7D, 56), V(EF, 90, 33, 22), \ + V(C7, 4E, 49, 87), V(C1, D1, 38, D9), V(FE, A2, CA, 8C), V(36, 0B, D4, 98), \ + V(CF, 81, F5, A6), V(28, DE, 7A, A5), V(26, 8E, B7, DA), V(A4, BF, AD, 3F), \ + V(E4, 9D, 3A, 2C), V(0D, 92, 78, 50), V(9B, CC, 5F, 6A), V(62, 46, 7E, 54), \ + V(C2, 13, 8D, F6), V(E8, B8, D8, 90), V(5E, F7, 39, 2E), V(F5, AF, C3, 82), \ + V(BE, 80, 5D, 9F), V(7C, 93, D0, 69), V(A9, 2D, D5, 6F), V(B3, 12, 25, CF), \ + V(3B, 99, AC, C8), V(A7, 7D, 18, 10), V(6E, 63, 9C, E8), V(7B, BB, 3B, DB), \ + V(09, 78, 26, CD), V(F4, 18, 59, 6E), V(01, B7, 9A, EC), V(A8, 9A, 4F, 83), \ + V(65, 6E, 95, E6), V(7E, E6, FF, AA), V(08, CF, BC, 21), V(E6, E8, 15, EF), \ + V(D9, 9B, E7, BA), V(CE, 36, 6F, 4A), V(D4, 09, 9F, EA), V(D6, 7C, B0, 29), \ + V(AF, B2, A4, 31), V(31, 23, 3F, 2A), V(30, 94, A5, C6), V(C0, 66, A2, 35), \ + V(37, BC, 4E, 74), V(A6, CA, 82, FC), V(B0, D0, 90, E0), V(15, D8, A7, 33), \ + V(4A, 98, 04, F1), V(F7, DA, EC, 41), V(0E, 50, CD, 7F), V(2F, F6, 91, 17), \ + V(8D, D6, 4D, 76), V(4D, B0, EF, 43), V(54, 4D, AA, CC), V(DF, 04, 96, E4), \ + V(E3, B5, D1, 9E), V(1B, 88, 6A, 4C), V(B8, 1F, 2C, C1), V(7F, 51, 65, 46), \ + V(04, EA, 5E, 9D), V(5D, 35, 8C, 01), V(73, 74, 87, FA), V(2E, 41, 0B, FB), \ + V(5A, 1D, 67, B3), V(52, D2, DB, 92), V(33, 56, 10, E9), V(13, 47, D6, 6D), \ + V(8C, 61, D7, 9A), V(7A, 0C, A1, 37), V(8E, 14, F8, 59), V(89, 3C, 13, EB), \ + V(EE, 27, A9, CE), V(35, C9, 61, B7), V(ED, E5, 1C, E1), V(3C, B1, 47, 7A), \ + V(59, DF, D2, 9C), V(3F, 73, F2, 55), V(79, CE, 14, 18), V(BF, 37, C7, 73), \ + V(EA, CD, F7, 53), V(5B, AA, FD, 5F), V(14, 6F, 3D, DF), V(86, DB, 44, 78), \ + V(81, F3, AF, CA), V(3E, C4, 68, B9), V(2C, 34, 24, 38), V(5F, 40, A3, C2), \ + V(72, C3, 1D, 16), V(0C, 25, E2, BC), V(8B, 49, 3C, 28), V(41, 95, 0D, FF), \ + V(71, 01, A8, 39), V(DE, B3, 0C, 08), V(9C, E4, B4, D8), V(90, C1, 56, 64), \ + V(61, 84, CB, 7B), V(70, B6, 32, D5), V(74, 5C, 6C, 48), V(42, 57, B8, D0) + + +#define V(a, b, c, d) 0x##a##b##c##d +MBEDTLS_MAYBE_UNUSED static const uint32_t RT0[256] = { RT }; +#undef V + +#define V(a, b, c, d) 0x##b##c##d##a +MBEDTLS_MAYBE_UNUSED static const uint32_t RT1[256] = { RT }; +#undef V + +#define V(a, b, c, d) 0x##c##d##a##b +MBEDTLS_MAYBE_UNUSED static const uint32_t RT2[256] = { RT }; +#undef V + +#define V(a, b, c, d) 0x##d##a##b##c +MBEDTLS_MAYBE_UNUSED static const uint32_t RT3[256] = { RT }; +#undef V + +#undef RT + +/* + * Round constants + */ +MBEDTLS_MAYBE_UNUSED static const uint32_t round_constants[10] = +{ + 0x00000001, 0x00000002, 0x00000004, 0x00000008, + 0x00000010, 0x00000020, 0x00000040, 0x00000080, + 0x0000001B, 0x00000036 +}; + +#else /* MBEDTLS_AES_ROM_TABLES */ + +/* + * Forward S-box & tables + */ +MBEDTLS_MAYBE_UNUSED static unsigned char FSb[256]; +MBEDTLS_MAYBE_UNUSED static uint32_t FT0[256]; +MBEDTLS_MAYBE_UNUSED static uint32_t FT1[256]; +MBEDTLS_MAYBE_UNUSED static uint32_t FT2[256]; +MBEDTLS_MAYBE_UNUSED static uint32_t FT3[256]; + +/* + * Reverse S-box & tables + */ +MBEDTLS_MAYBE_UNUSED static unsigned char RSb[256]; + +MBEDTLS_MAYBE_UNUSED static uint32_t RT0[256]; +MBEDTLS_MAYBE_UNUSED static uint32_t RT1[256]; +MBEDTLS_MAYBE_UNUSED static uint32_t RT2[256]; +MBEDTLS_MAYBE_UNUSED static uint32_t RT3[256]; + +/* + * Round constants + */ +MBEDTLS_MAYBE_UNUSED static uint32_t round_constants[10]; + +/* + * Tables generation code + */ +#define ROTL8(x) (((x) << 8) & 0xFFFFFFFF) | ((x) >> 24) +#define XTIME(x) (((x) << 1) ^ (((x) & 0x80) ? 0x1B : 0x00)) +#define MUL(x, y) (((x) && (y)) ? pow[(log[(x)]+log[(y)]) % 255] : 0) + +MBEDTLS_MAYBE_UNUSED static int aes_init_done = 0; + +MBEDTLS_MAYBE_UNUSED static void aes_gen_tables(void) +{ + int i; + uint8_t x, y, z; + uint8_t pow[256]; + uint8_t log[256]; + + /* + * compute pow and log tables over GF(2^8) + */ + for (i = 0, x = 1; i < 256; i++) { + pow[i] = x; + log[x] = (uint8_t) i; + x ^= XTIME(x); + } + + /* + * calculate the round constants + */ + for (i = 0, x = 1; i < 10; i++) { + round_constants[i] = x; + x = XTIME(x); + } + + /* + * generate the forward and reverse S-boxes + */ + FSb[0x00] = 0x63; +#if defined(MBEDTLS_AES_NEED_REVERSE_TABLES) + RSb[0x63] = 0x00; +#endif + + for (i = 1; i < 256; i++) { + x = pow[255 - log[i]]; + + y = x; y = (y << 1) | (y >> 7); + x ^= y; y = (y << 1) | (y >> 7); + x ^= y; y = (y << 1) | (y >> 7); + x ^= y; y = (y << 1) | (y >> 7); + x ^= y ^ 0x63; + + FSb[i] = x; +#if defined(MBEDTLS_AES_NEED_REVERSE_TABLES) + RSb[x] = (unsigned char) i; +#endif + } + + /* + * generate the forward and reverse tables + */ + for (i = 0; i < 256; i++) { + x = FSb[i]; + y = XTIME(x); + z = y ^ x; + + FT0[i] = ((uint32_t) y) ^ + ((uint32_t) x << 8) ^ + ((uint32_t) x << 16) ^ + ((uint32_t) z << 24); + +#if !defined(MBEDTLS_AES_FEWER_TABLES) + FT1[i] = ROTL8(FT0[i]); + FT2[i] = ROTL8(FT1[i]); + FT3[i] = ROTL8(FT2[i]); +#endif /* !MBEDTLS_AES_FEWER_TABLES */ + +#if defined(MBEDTLS_AES_NEED_REVERSE_TABLES) + x = RSb[i]; + + RT0[i] = ((uint32_t) MUL(0x0E, x)) ^ + ((uint32_t) MUL(0x09, x) << 8) ^ + ((uint32_t) MUL(0x0D, x) << 16) ^ + ((uint32_t) MUL(0x0B, x) << 24); + +#if !defined(MBEDTLS_AES_FEWER_TABLES) + RT1[i] = ROTL8(RT0[i]); + RT2[i] = ROTL8(RT1[i]); + RT3[i] = ROTL8(RT2[i]); +#endif /* !MBEDTLS_AES_FEWER_TABLES */ +#endif /* MBEDTLS_AES_NEED_REVERSE_TABLES */ + } +} + +#undef ROTL8 + +#endif /* MBEDTLS_AES_ROM_TABLES */ + +#if defined(MBEDTLS_AES_FEWER_TABLES) + +#define ROTL8(x) ((uint32_t) ((x) << 8) + (uint32_t) ((x) >> 24)) +#define ROTL16(x) ((uint32_t) ((x) << 16) + (uint32_t) ((x) >> 16)) +#define ROTL24(x) ((uint32_t) ((x) << 24) + (uint32_t) ((x) >> 8)) + +#define AES_RT0(idx) RT0[idx] +#define AES_RT1(idx) ROTL8(RT0[idx]) +#define AES_RT2(idx) ROTL16(RT0[idx]) +#define AES_RT3(idx) ROTL24(RT0[idx]) + +#define AES_FT0(idx) FT0[idx] +#define AES_FT1(idx) ROTL8(FT0[idx]) +#define AES_FT2(idx) ROTL16(FT0[idx]) +#define AES_FT3(idx) ROTL24(FT0[idx]) + +#else /* MBEDTLS_AES_FEWER_TABLES */ + +#define AES_RT0(idx) RT0[idx] +#define AES_RT1(idx) RT1[idx] +#define AES_RT2(idx) RT2[idx] +#define AES_RT3(idx) RT3[idx] + +#define AES_FT0(idx) FT0[idx] +#define AES_FT1(idx) FT1[idx] +#define AES_FT2(idx) FT2[idx] +#define AES_FT3(idx) FT3[idx] + +#endif /* MBEDTLS_AES_FEWER_TABLES */ + +void mbedtls_aes_init(mbedtls_aes_context *ctx) +{ + memset(ctx, 0, sizeof(mbedtls_aes_context)); +} + +void mbedtls_aes_free(mbedtls_aes_context *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_aes_context)); +} + +mbedtls_aes_implementation mbedtls_aes_get_implementation(void) +{ +#if defined(MBEDTLS_AESNI_HAVE_CODE) + if (mbedtls_aesni_has_support(MBEDTLS_AESNI_AES)) { +#if MBEDTLS_AESNI_HAVE_CODE == 1 + return MBEDTLS_AES_IMP_AESNI_ASM; +#elif MBEDTLS_AESNI_HAVE_CODE == 2 + return MBEDTLS_AES_IMP_AESNI_INTRINSICS; +#endif /* MBEDTLS_AESNI_HAVE_CODE == 1 || 2 */ + } +#endif /* MBEDTLS_AESNI_HAVE_CODE */ + +#if defined(MBEDTLS_AESCE_HAVE_CODE) + if (MBEDTLS_AESCE_HAS_SUPPORT()) { + return MBEDTLS_AES_IMP_AESCE; + } +#endif + +#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) + return MBEDTLS_AES_IMP_SOFTWARE; +#endif + return MBEDTLS_AES_IMP_UNKNOWN; +} + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +void mbedtls_aes_xts_init(mbedtls_aes_xts_context *ctx) +{ + mbedtls_aes_init(&ctx->crypt); + mbedtls_aes_init(&ctx->tweak); +} + +void mbedtls_aes_xts_free(mbedtls_aes_xts_context *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_aes_free(&ctx->crypt); + mbedtls_aes_free(&ctx->tweak); +} +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +/* Some implementations need the round keys to be aligned. + * Return an offset to be added to buf, such that (buf + offset) is + * correctly aligned. + * Note that the offset is in units of elements of buf, i.e. 32-bit words, + * i.e. an offset of 1 means 4 bytes and so on. + */ +#if defined(MBEDTLS_AESNI_C) && MBEDTLS_AESNI_HAVE_CODE == 2 +#define MAY_NEED_TO_ALIGN +#endif + +MBEDTLS_MAYBE_UNUSED static unsigned mbedtls_aes_rk_offset(uint32_t *buf) +{ +#if defined(MAY_NEED_TO_ALIGN) + int align_16_bytes = 0; + +#if defined(MBEDTLS_AESNI_C) && MBEDTLS_AESNI_HAVE_CODE == 2 + if (mbedtls_aesni_has_support(MBEDTLS_AESNI_AES)) { + align_16_bytes = 1; + } +#endif + + if (align_16_bytes) { + /* These implementations needs 16-byte alignment + * for the round key array. */ + unsigned delta = ((uintptr_t) buf & 0x0000000fU) / 4; + if (delta == 0) { + return 0; + } else { + return 4 - delta; // 16 bytes = 4 uint32_t + } + } +#else /* MAY_NEED_TO_ALIGN */ + (void) buf; +#endif /* MAY_NEED_TO_ALIGN */ + + return 0; +} + +/* + * AES key schedule (encryption) + */ +int mbedtls_aes_setkey_enc(mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits) +{ + uint32_t *RK; + + switch (keybits) { + case 128: ctx->nr = 10; break; +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + case 192: ctx->nr = 12; break; + case 256: ctx->nr = 14; break; +#endif /* !MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH */ + default: return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + +#if !defined(MBEDTLS_AES_ROM_TABLES) + if (aes_init_done == 0) { + aes_gen_tables(); + aes_init_done = 1; + } +#endif + + ctx->rk_offset = mbedtls_aes_rk_offset(ctx->buf); + RK = ctx->buf + ctx->rk_offset; + +#if defined(MBEDTLS_AESNI_HAVE_CODE) + if (mbedtls_aesni_has_support(MBEDTLS_AESNI_AES)) { + return mbedtls_aesni_setkey_enc((unsigned char *) RK, key, keybits); + } +#endif + +#if defined(MBEDTLS_AESCE_HAVE_CODE) + if (MBEDTLS_AESCE_HAS_SUPPORT()) { + return mbedtls_aesce_setkey_enc((unsigned char *) RK, key, keybits); + } +#endif + +#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) + for (unsigned int i = 0; i < (keybits >> 5); i++) { + RK[i] = MBEDTLS_GET_UINT32_LE(key, i << 2); + } + + switch (ctx->nr) { + case 10: + + for (unsigned int i = 0; i < 10; i++, RK += 4) { + RK[4] = RK[0] ^ round_constants[i] ^ + ((uint32_t) FSb[MBEDTLS_BYTE_1(RK[3])]) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_2(RK[3])] << 8) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_3(RK[3])] << 16) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_0(RK[3])] << 24); + + RK[5] = RK[1] ^ RK[4]; + RK[6] = RK[2] ^ RK[5]; + RK[7] = RK[3] ^ RK[6]; + } + break; + +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + case 12: + + for (unsigned int i = 0; i < 8; i++, RK += 6) { + RK[6] = RK[0] ^ round_constants[i] ^ + ((uint32_t) FSb[MBEDTLS_BYTE_1(RK[5])]) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_2(RK[5])] << 8) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_3(RK[5])] << 16) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_0(RK[5])] << 24); + + RK[7] = RK[1] ^ RK[6]; + RK[8] = RK[2] ^ RK[7]; + RK[9] = RK[3] ^ RK[8]; + RK[10] = RK[4] ^ RK[9]; + RK[11] = RK[5] ^ RK[10]; + } + break; + + case 14: + + for (unsigned int i = 0; i < 7; i++, RK += 8) { + RK[8] = RK[0] ^ round_constants[i] ^ + ((uint32_t) FSb[MBEDTLS_BYTE_1(RK[7])]) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_2(RK[7])] << 8) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_3(RK[7])] << 16) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_0(RK[7])] << 24); + + RK[9] = RK[1] ^ RK[8]; + RK[10] = RK[2] ^ RK[9]; + RK[11] = RK[3] ^ RK[10]; + + RK[12] = RK[4] ^ + ((uint32_t) FSb[MBEDTLS_BYTE_0(RK[11])]) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_1(RK[11])] << 8) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_2(RK[11])] << 16) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_3(RK[11])] << 24); + + RK[13] = RK[5] ^ RK[12]; + RK[14] = RK[6] ^ RK[13]; + RK[15] = RK[7] ^ RK[14]; + } + break; +#endif /* !MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH */ + } + + return 0; +#endif /* !MBEDTLS_AES_USE_HARDWARE_ONLY */ +} + +/* + * AES key schedule (decryption) + */ +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +int mbedtls_aes_setkey_dec(mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits) +{ +#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) + uint32_t *SK; +#endif + int ret; + mbedtls_aes_context cty; + uint32_t *RK; + + + mbedtls_aes_init(&cty); + + ctx->rk_offset = mbedtls_aes_rk_offset(ctx->buf); + RK = ctx->buf + ctx->rk_offset; + + /* Also checks keybits */ + if ((ret = mbedtls_aes_setkey_enc(&cty, key, keybits)) != 0) { + goto exit; + } + + ctx->nr = cty.nr; + +#if defined(MBEDTLS_AESNI_HAVE_CODE) + if (mbedtls_aesni_has_support(MBEDTLS_AESNI_AES)) { + mbedtls_aesni_inverse_key((unsigned char *) RK, + (const unsigned char *) (cty.buf + cty.rk_offset), ctx->nr); + goto exit; + } +#endif + +#if defined(MBEDTLS_AESCE_HAVE_CODE) + if (MBEDTLS_AESCE_HAS_SUPPORT()) { + mbedtls_aesce_inverse_key( + (unsigned char *) RK, + (const unsigned char *) (cty.buf + cty.rk_offset), + ctx->nr); + goto exit; + } +#endif + +#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) + SK = cty.buf + cty.rk_offset + cty.nr * 4; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + SK -= 8; + for (int i = ctx->nr - 1; i > 0; i--, SK -= 8) { + for (int j = 0; j < 4; j++, SK++) { + *RK++ = AES_RT0(FSb[MBEDTLS_BYTE_0(*SK)]) ^ + AES_RT1(FSb[MBEDTLS_BYTE_1(*SK)]) ^ + AES_RT2(FSb[MBEDTLS_BYTE_2(*SK)]) ^ + AES_RT3(FSb[MBEDTLS_BYTE_3(*SK)]); + } + } + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; +#endif /* !MBEDTLS_AES_USE_HARDWARE_ONLY */ +exit: + mbedtls_aes_free(&cty); + + return ret; +} +#endif /* !MBEDTLS_BLOCK_CIPHER_NO_DECRYPT */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +static int mbedtls_aes_xts_decode_keys(const unsigned char *key, + unsigned int keybits, + const unsigned char **key1, + unsigned int *key1bits, + const unsigned char **key2, + unsigned int *key2bits) +{ + const unsigned int half_keybits = keybits / 2; + const unsigned int half_keybytes = half_keybits / 8; + + switch (keybits) { + case 256: break; + case 512: break; + default: return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + + *key1bits = half_keybits; + *key2bits = half_keybits; + *key1 = &key[0]; + *key2 = &key[half_keybytes]; + + return 0; +} + +int mbedtls_aes_xts_setkey_enc(mbedtls_aes_xts_context *ctx, + const unsigned char *key, + unsigned int keybits) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + const unsigned char *key1, *key2; + unsigned int key1bits, key2bits; + + ret = mbedtls_aes_xts_decode_keys(key, keybits, &key1, &key1bits, + &key2, &key2bits); + if (ret != 0) { + return ret; + } + + /* Set the tweak key. Always set tweak key for the encryption mode. */ + ret = mbedtls_aes_setkey_enc(&ctx->tweak, key2, key2bits); + if (ret != 0) { + return ret; + } + + /* Set crypt key for encryption. */ + return mbedtls_aes_setkey_enc(&ctx->crypt, key1, key1bits); +} + +int mbedtls_aes_xts_setkey_dec(mbedtls_aes_xts_context *ctx, + const unsigned char *key, + unsigned int keybits) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + const unsigned char *key1, *key2; + unsigned int key1bits, key2bits; + + ret = mbedtls_aes_xts_decode_keys(key, keybits, &key1, &key1bits, + &key2, &key2bits); + if (ret != 0) { + return ret; + } + + /* Set the tweak key. Always set tweak key for encryption. */ + ret = mbedtls_aes_setkey_enc(&ctx->tweak, key2, key2bits); + if (ret != 0) { + return ret; + } + + /* Set crypt key for decryption. */ + return mbedtls_aes_setkey_dec(&ctx->crypt, key1, key1bits); +} +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#define AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \ + do \ + { \ + (X0) = *RK++ ^ AES_FT0(MBEDTLS_BYTE_0(Y0)) ^ \ + AES_FT1(MBEDTLS_BYTE_1(Y1)) ^ \ + AES_FT2(MBEDTLS_BYTE_2(Y2)) ^ \ + AES_FT3(MBEDTLS_BYTE_3(Y3)); \ + \ + (X1) = *RK++ ^ AES_FT0(MBEDTLS_BYTE_0(Y1)) ^ \ + AES_FT1(MBEDTLS_BYTE_1(Y2)) ^ \ + AES_FT2(MBEDTLS_BYTE_2(Y3)) ^ \ + AES_FT3(MBEDTLS_BYTE_3(Y0)); \ + \ + (X2) = *RK++ ^ AES_FT0(MBEDTLS_BYTE_0(Y2)) ^ \ + AES_FT1(MBEDTLS_BYTE_1(Y3)) ^ \ + AES_FT2(MBEDTLS_BYTE_2(Y0)) ^ \ + AES_FT3(MBEDTLS_BYTE_3(Y1)); \ + \ + (X3) = *RK++ ^ AES_FT0(MBEDTLS_BYTE_0(Y3)) ^ \ + AES_FT1(MBEDTLS_BYTE_1(Y0)) ^ \ + AES_FT2(MBEDTLS_BYTE_2(Y1)) ^ \ + AES_FT3(MBEDTLS_BYTE_3(Y2)); \ + } while (0) + +#define AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \ + do \ + { \ + (X0) = *RK++ ^ AES_RT0(MBEDTLS_BYTE_0(Y0)) ^ \ + AES_RT1(MBEDTLS_BYTE_1(Y3)) ^ \ + AES_RT2(MBEDTLS_BYTE_2(Y2)) ^ \ + AES_RT3(MBEDTLS_BYTE_3(Y1)); \ + \ + (X1) = *RK++ ^ AES_RT0(MBEDTLS_BYTE_0(Y1)) ^ \ + AES_RT1(MBEDTLS_BYTE_1(Y0)) ^ \ + AES_RT2(MBEDTLS_BYTE_2(Y3)) ^ \ + AES_RT3(MBEDTLS_BYTE_3(Y2)); \ + \ + (X2) = *RK++ ^ AES_RT0(MBEDTLS_BYTE_0(Y2)) ^ \ + AES_RT1(MBEDTLS_BYTE_1(Y1)) ^ \ + AES_RT2(MBEDTLS_BYTE_2(Y0)) ^ \ + AES_RT3(MBEDTLS_BYTE_3(Y3)); \ + \ + (X3) = *RK++ ^ AES_RT0(MBEDTLS_BYTE_0(Y3)) ^ \ + AES_RT1(MBEDTLS_BYTE_1(Y2)) ^ \ + AES_RT2(MBEDTLS_BYTE_2(Y1)) ^ \ + AES_RT3(MBEDTLS_BYTE_3(Y0)); \ + } while (0) + +#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) +/* + * AES-ECB block encryption + */ +MBEDTLS_CHECK_RETURN_TYPICAL +static int mbedtls_internal_aes_encrypt(mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16]) +{ + int i; + uint32_t *RK = ctx->buf + ctx->rk_offset; + struct { + uint32_t X[4]; + uint32_t Y[4]; + } t; + + t.X[0] = MBEDTLS_GET_UINT32_LE(input, 0); t.X[0] ^= *RK++; + t.X[1] = MBEDTLS_GET_UINT32_LE(input, 4); t.X[1] ^= *RK++; + t.X[2] = MBEDTLS_GET_UINT32_LE(input, 8); t.X[2] ^= *RK++; + t.X[3] = MBEDTLS_GET_UINT32_LE(input, 12); t.X[3] ^= *RK++; + + for (i = (ctx->nr >> 1) - 1; i > 0; i--) { + AES_FROUND(t.Y[0], t.Y[1], t.Y[2], t.Y[3], t.X[0], t.X[1], t.X[2], t.X[3]); + AES_FROUND(t.X[0], t.X[1], t.X[2], t.X[3], t.Y[0], t.Y[1], t.Y[2], t.Y[3]); + } + + AES_FROUND(t.Y[0], t.Y[1], t.Y[2], t.Y[3], t.X[0], t.X[1], t.X[2], t.X[3]); + + t.X[0] = *RK++ ^ \ + ((uint32_t) FSb[MBEDTLS_BYTE_0(t.Y[0])]) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_1(t.Y[1])] << 8) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_2(t.Y[2])] << 16) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_3(t.Y[3])] << 24); + + t.X[1] = *RK++ ^ \ + ((uint32_t) FSb[MBEDTLS_BYTE_0(t.Y[1])]) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_1(t.Y[2])] << 8) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_2(t.Y[3])] << 16) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_3(t.Y[0])] << 24); + + t.X[2] = *RK++ ^ \ + ((uint32_t) FSb[MBEDTLS_BYTE_0(t.Y[2])]) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_1(t.Y[3])] << 8) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_2(t.Y[0])] << 16) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_3(t.Y[1])] << 24); + + t.X[3] = *RK++ ^ \ + ((uint32_t) FSb[MBEDTLS_BYTE_0(t.Y[3])]) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_1(t.Y[0])] << 8) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_2(t.Y[1])] << 16) ^ + ((uint32_t) FSb[MBEDTLS_BYTE_3(t.Y[2])] << 24); + + MBEDTLS_PUT_UINT32_LE(t.X[0], output, 0); + MBEDTLS_PUT_UINT32_LE(t.X[1], output, 4); + MBEDTLS_PUT_UINT32_LE(t.X[2], output, 8); + MBEDTLS_PUT_UINT32_LE(t.X[3], output, 12); + + mbedtls_platform_zeroize(&t, sizeof(t)); + + return 0; +} + +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +/* + * AES-ECB block decryption + */ +MBEDTLS_CHECK_RETURN_TYPICAL +static int mbedtls_internal_aes_decrypt(mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16]) +{ + int i; + uint32_t *RK = ctx->buf + ctx->rk_offset; + struct { + uint32_t X[4]; + uint32_t Y[4]; + } t; + + t.X[0] = MBEDTLS_GET_UINT32_LE(input, 0); t.X[0] ^= *RK++; + t.X[1] = MBEDTLS_GET_UINT32_LE(input, 4); t.X[1] ^= *RK++; + t.X[2] = MBEDTLS_GET_UINT32_LE(input, 8); t.X[2] ^= *RK++; + t.X[3] = MBEDTLS_GET_UINT32_LE(input, 12); t.X[3] ^= *RK++; + + for (i = (ctx->nr >> 1) - 1; i > 0; i--) { + AES_RROUND(t.Y[0], t.Y[1], t.Y[2], t.Y[3], t.X[0], t.X[1], t.X[2], t.X[3]); + AES_RROUND(t.X[0], t.X[1], t.X[2], t.X[3], t.Y[0], t.Y[1], t.Y[2], t.Y[3]); + } + + AES_RROUND(t.Y[0], t.Y[1], t.Y[2], t.Y[3], t.X[0], t.X[1], t.X[2], t.X[3]); + + t.X[0] = *RK++ ^ \ + ((uint32_t) RSb[MBEDTLS_BYTE_0(t.Y[0])]) ^ + ((uint32_t) RSb[MBEDTLS_BYTE_1(t.Y[3])] << 8) ^ + ((uint32_t) RSb[MBEDTLS_BYTE_2(t.Y[2])] << 16) ^ + ((uint32_t) RSb[MBEDTLS_BYTE_3(t.Y[1])] << 24); + + t.X[1] = *RK++ ^ \ + ((uint32_t) RSb[MBEDTLS_BYTE_0(t.Y[1])]) ^ + ((uint32_t) RSb[MBEDTLS_BYTE_1(t.Y[0])] << 8) ^ + ((uint32_t) RSb[MBEDTLS_BYTE_2(t.Y[3])] << 16) ^ + ((uint32_t) RSb[MBEDTLS_BYTE_3(t.Y[2])] << 24); + + t.X[2] = *RK++ ^ \ + ((uint32_t) RSb[MBEDTLS_BYTE_0(t.Y[2])]) ^ + ((uint32_t) RSb[MBEDTLS_BYTE_1(t.Y[1])] << 8) ^ + ((uint32_t) RSb[MBEDTLS_BYTE_2(t.Y[0])] << 16) ^ + ((uint32_t) RSb[MBEDTLS_BYTE_3(t.Y[3])] << 24); + + t.X[3] = *RK++ ^ \ + ((uint32_t) RSb[MBEDTLS_BYTE_0(t.Y[3])]) ^ + ((uint32_t) RSb[MBEDTLS_BYTE_1(t.Y[2])] << 8) ^ + ((uint32_t) RSb[MBEDTLS_BYTE_2(t.Y[1])] << 16) ^ + ((uint32_t) RSb[MBEDTLS_BYTE_3(t.Y[0])] << 24); + + MBEDTLS_PUT_UINT32_LE(t.X[0], output, 0); + MBEDTLS_PUT_UINT32_LE(t.X[1], output, 4); + MBEDTLS_PUT_UINT32_LE(t.X[2], output, 8); + MBEDTLS_PUT_UINT32_LE(t.X[3], output, 12); + + mbedtls_platform_zeroize(&t, sizeof(t)); + + return 0; +} +#endif /* !MBEDTLS_BLOCK_CIPHER_NO_DECRYPT */ +#endif /* !MBEDTLS_AES_USE_HARDWARE_ONLY */ +/* + * Our intrinsics-based implementation of AESNI requires the round keys to be + * aligned on a 16-byte boundary. We take care of this before creating them, + * but the AES context may have moved (this can happen if the library is + * called from a language with managed memory), and in later calls it might + * have a different alignment with respect to 16-byte memory. So we may need + * to realign. + */ +#if defined(MAY_NEED_TO_ALIGN) +MBEDTLS_MAYBE_UNUSED static void aes_maybe_realign(mbedtls_aes_context *ctx) +{ + unsigned new_offset = mbedtls_aes_rk_offset(ctx->buf); + if (new_offset != ctx->rk_offset) { + memmove(ctx->buf + new_offset, // new address + ctx->buf + ctx->rk_offset, // current address + (ctx->nr + 1) * 16); // number of round keys * bytes per rk + ctx->rk_offset = new_offset; + } +} +#endif /* MAY_NEED_TO_ALIGN */ +/* + * AES-ECB block encryption/decryption + */ +int mbedtls_aes_crypt_ecb(mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16]) +{ + if (mode != MBEDTLS_AES_ENCRYPT && mode != MBEDTLS_AES_DECRYPT) { + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + +#if defined(MAY_NEED_TO_ALIGN) + aes_maybe_realign(ctx); +#endif + +#if defined(MBEDTLS_AESNI_HAVE_CODE) + if (mbedtls_aesni_has_support(MBEDTLS_AESNI_AES)) { + return mbedtls_aesni_crypt_ecb(ctx, mode, input, output); + } +#endif + +#if defined(MBEDTLS_AESCE_HAVE_CODE) + if (MBEDTLS_AESCE_HAS_SUPPORT()) { + return mbedtls_aesce_crypt_ecb(ctx, mode, input, output); + } +#endif + +#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + if (mode == MBEDTLS_AES_DECRYPT) { + return mbedtls_internal_aes_decrypt(ctx, input, output); + } else +#endif + { + return mbedtls_internal_aes_encrypt(ctx, input, output); + } +#endif /* !MBEDTLS_AES_USE_HARDWARE_ONLY */ +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + +/* + * AES-CBC buffer encryption/decryption + */ +int mbedtls_aes_crypt_cbc(mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char temp[16]; + + if (mode != MBEDTLS_AES_ENCRYPT && mode != MBEDTLS_AES_DECRYPT) { + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + + /* Nothing to do if length is zero. */ + if (length == 0) { + return 0; + } + + if (length % 16) { + return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; + } + + const unsigned char *ivp = iv; + + if (mode == MBEDTLS_AES_DECRYPT) { + while (length > 0) { + memcpy(temp, input, 16); + ret = mbedtls_aes_crypt_ecb(ctx, mode, input, output); + if (ret != 0) { + goto exit; + } + /* Avoid using the NEON implementation of mbedtls_xor. Because of the dependency on + * the result for the next block in CBC, and the cost of transferring that data from + * NEON registers, NEON is slower on aarch64. */ + mbedtls_xor_no_simd(output, output, iv, 16); + + memcpy(iv, temp, 16); + + input += 16; + output += 16; + length -= 16; + } + } else { + while (length > 0) { + mbedtls_xor_no_simd(output, input, ivp, 16); + + ret = mbedtls_aes_crypt_ecb(ctx, mode, output, output); + if (ret != 0) { + goto exit; + } + ivp = output; + + input += 16; + output += 16; + length -= 16; + } + memcpy(iv, ivp, 16); + } + ret = 0; + +exit: + return ret; +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) + +typedef unsigned char mbedtls_be128[16]; + +/* + * GF(2^128) multiplication function + * + * This function multiplies a field element by x in the polynomial field + * representation. It uses 64-bit word operations to gain speed but compensates + * for machine endianness and hence works correctly on both big and little + * endian machines. + */ +#if defined(MBEDTLS_AESCE_C) || defined(MBEDTLS_AESNI_C) +MBEDTLS_OPTIMIZE_FOR_PERFORMANCE +#endif +static inline void mbedtls_gf128mul_x_ble(unsigned char r[16], + const unsigned char x[16]) +{ + uint64_t a, b, ra, rb; + + a = MBEDTLS_GET_UINT64_LE(x, 0); + b = MBEDTLS_GET_UINT64_LE(x, 8); + + ra = (a << 1) ^ 0x0087 >> (8 - ((b >> 63) << 3)); + rb = (a >> 63) | (b << 1); + + MBEDTLS_PUT_UINT64_LE(ra, r, 0); + MBEDTLS_PUT_UINT64_LE(rb, r, 8); +} + +/* + * AES-XTS buffer encryption/decryption + * + * Use of MBEDTLS_OPTIMIZE_FOR_PERFORMANCE here and for mbedtls_gf128mul_x_ble() + * is a 3x performance improvement for gcc -Os, if we have hardware AES support. + */ +#if defined(MBEDTLS_AESCE_C) || defined(MBEDTLS_AESNI_C) +MBEDTLS_OPTIMIZE_FOR_PERFORMANCE +#endif +int mbedtls_aes_crypt_xts(mbedtls_aes_xts_context *ctx, + int mode, + size_t length, + const unsigned char data_unit[16], + const unsigned char *input, + unsigned char *output) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t blocks = length / 16; + size_t leftover = length % 16; + unsigned char tweak[16]; + unsigned char prev_tweak[16]; + unsigned char tmp[16]; + + if (mode != MBEDTLS_AES_ENCRYPT && mode != MBEDTLS_AES_DECRYPT) { + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + + /* Data units must be at least 16 bytes long. */ + if (length < 16) { + return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; + } + + /* NIST SP 800-38E disallows data units larger than 2**20 blocks. */ + if (length > (1 << 20) * 16) { + return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; + } + + /* Compute the tweak. */ + ret = mbedtls_aes_crypt_ecb(&ctx->tweak, MBEDTLS_AES_ENCRYPT, + data_unit, tweak); + if (ret != 0) { + return ret; + } + + while (blocks--) { + if (MBEDTLS_UNLIKELY(leftover && (mode == MBEDTLS_AES_DECRYPT) && blocks == 0)) { + /* We are on the last block in a decrypt operation that has + * leftover bytes, so we need to use the next tweak for this block, + * and this tweak for the leftover bytes. Save the current tweak for + * the leftovers and then update the current tweak for use on this, + * the last full block. */ + memcpy(prev_tweak, tweak, sizeof(tweak)); + mbedtls_gf128mul_x_ble(tweak, tweak); + } + + mbedtls_xor(tmp, input, tweak, 16); + + ret = mbedtls_aes_crypt_ecb(&ctx->crypt, mode, tmp, tmp); + if (ret != 0) { + return ret; + } + + mbedtls_xor(output, tmp, tweak, 16); + + /* Update the tweak for the next block. */ + mbedtls_gf128mul_x_ble(tweak, tweak); + + output += 16; + input += 16; + } + + if (leftover) { + /* If we are on the leftover bytes in a decrypt operation, we need to + * use the previous tweak for these bytes (as saved in prev_tweak). */ + unsigned char *t = mode == MBEDTLS_AES_DECRYPT ? prev_tweak : tweak; + + /* We are now on the final part of the data unit, which doesn't divide + * evenly by 16. It's time for ciphertext stealing. */ + size_t i; + unsigned char *prev_output = output - 16; + + /* Copy ciphertext bytes from the previous block to our output for each + * byte of ciphertext we won't steal. */ + for (i = 0; i < leftover; i++) { + output[i] = prev_output[i]; + } + + /* Copy the remainder of the input for this final round. */ + mbedtls_xor(tmp, input, t, leftover); + + /* Copy ciphertext bytes from the previous block for input in this + * round. */ + mbedtls_xor(tmp + i, prev_output + i, t + i, 16 - i); + + ret = mbedtls_aes_crypt_ecb(&ctx->crypt, mode, tmp, tmp); + if (ret != 0) { + return ret; + } + + /* Write the result back to the previous block, overriding the previous + * output we copied. */ + mbedtls_xor(prev_output, tmp, t, 16); + } + + return 0; +} +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * AES-CFB128 buffer encryption/decryption + */ +int mbedtls_aes_crypt_cfb128(mbedtls_aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output) +{ + int c; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t n; + + if (mode != MBEDTLS_AES_ENCRYPT && mode != MBEDTLS_AES_DECRYPT) { + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + + n = *iv_off; + + if (n > 15) { + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + + if (mode == MBEDTLS_AES_DECRYPT) { + while (length--) { + if (n == 0) { + ret = mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, iv, iv); + if (ret != 0) { + goto exit; + } + } + + c = *input++; + *output++ = (unsigned char) (c ^ iv[n]); + iv[n] = (unsigned char) c; + + n = (n + 1) & 0x0F; + } + } else { + while (length--) { + if (n == 0) { + ret = mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, iv, iv); + if (ret != 0) { + goto exit; + } + } + + iv[n] = *output++ = (unsigned char) (iv[n] ^ *input++); + + n = (n + 1) & 0x0F; + } + } + + *iv_off = n; + ret = 0; + +exit: + return ret; +} + +/* + * AES-CFB8 buffer encryption/decryption + */ +int mbedtls_aes_crypt_cfb8(mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char c; + unsigned char ov[17]; + + if (mode != MBEDTLS_AES_ENCRYPT && mode != MBEDTLS_AES_DECRYPT) { + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + while (length--) { + memcpy(ov, iv, 16); + ret = mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, iv, iv); + if (ret != 0) { + goto exit; + } + + if (mode == MBEDTLS_AES_DECRYPT) { + ov[16] = *input; + } + + c = *output++ = (unsigned char) (iv[0] ^ *input++); + + if (mode == MBEDTLS_AES_ENCRYPT) { + ov[16] = c; + } + + memcpy(iv, ov + 1, 16); + } + ret = 0; + +exit: + return ret; +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) +/* + * AES-OFB (Output Feedback Mode) buffer encryption/decryption + */ +int mbedtls_aes_crypt_ofb(mbedtls_aes_context *ctx, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output) +{ + int ret = 0; + size_t n; + + n = *iv_off; + + if (n > 15) { + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + + while (length--) { + if (n == 0) { + ret = mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, iv, iv); + if (ret != 0) { + goto exit; + } + } + *output++ = *input++ ^ iv[n]; + + n = (n + 1) & 0x0F; + } + + *iv_off = n; + +exit: + return ret; +} +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * AES-CTR buffer encryption/decryption + */ +int mbedtls_aes_crypt_ctr(mbedtls_aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + size_t offset = *nc_off; + + if (offset > 0x0F) { + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + + for (size_t i = 0; i < length;) { + size_t n = 16; + if (offset == 0) { + ret = mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, nonce_counter, stream_block); + if (ret != 0) { + goto exit; + } + mbedtls_ctr_increment_counter(nonce_counter); + } else { + n -= offset; + } + + if (n > (length - i)) { + n = (length - i); + } + mbedtls_xor(&output[i], &input[i], &stream_block[offset], n); + // offset might be non-zero for the last block, but in that case, we don't use it again + offset = 0; + i += n; + } + + // capture offset for future resumption + *nc_off = (*nc_off + length) % 16; + + ret = 0; + +exit: + return ret; +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * AES test vectors from: + * + * http://csrc.nist.gov/archive/aes/rijndael/rijndael-vals.zip + */ +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +static const unsigned char aes_test_ecb_dec[][16] = +{ + { 0x44, 0x41, 0x6A, 0xC2, 0xD1, 0xF5, 0x3C, 0x58, + 0x33, 0x03, 0x91, 0x7E, 0x6B, 0xE9, 0xEB, 0xE0 }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { 0x48, 0xE3, 0x1E, 0x9E, 0x25, 0x67, 0x18, 0xF2, + 0x92, 0x29, 0x31, 0x9C, 0x19, 0xF1, 0x5B, 0xA4 }, + { 0x05, 0x8C, 0xCF, 0xFD, 0xBB, 0xCB, 0x38, 0x2D, + 0x1F, 0x6F, 0x56, 0x58, 0x5D, 0x8A, 0x4A, 0xDE } +#endif +}; +#endif + +static const unsigned char aes_test_ecb_enc[][16] = +{ + { 0xC3, 0x4C, 0x05, 0x2C, 0xC0, 0xDA, 0x8D, 0x73, + 0x45, 0x1A, 0xFE, 0x5F, 0x03, 0xBE, 0x29, 0x7F }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { 0xF3, 0xF6, 0x75, 0x2A, 0xE8, 0xD7, 0x83, 0x11, + 0x38, 0xF0, 0x41, 0x56, 0x06, 0x31, 0xB1, 0x14 }, + { 0x8B, 0x79, 0xEE, 0xCC, 0x93, 0xA0, 0xEE, 0x5D, + 0xFF, 0x30, 0xB4, 0xEA, 0x21, 0x63, 0x6D, 0xA4 } +#endif +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const unsigned char aes_test_cbc_dec[][16] = +{ + { 0xFA, 0xCA, 0x37, 0xE0, 0xB0, 0xC8, 0x53, 0x73, + 0xDF, 0x70, 0x6E, 0x73, 0xF7, 0xC9, 0xAF, 0x86 }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { 0x5D, 0xF6, 0x78, 0xDD, 0x17, 0xBA, 0x4E, 0x75, + 0xB6, 0x17, 0x68, 0xC6, 0xAD, 0xEF, 0x7C, 0x7B }, + { 0x48, 0x04, 0xE1, 0x81, 0x8F, 0xE6, 0x29, 0x75, + 0x19, 0xA3, 0xE8, 0x8C, 0x57, 0x31, 0x04, 0x13 } +#endif +}; + +static const unsigned char aes_test_cbc_enc[][16] = +{ + { 0x8A, 0x05, 0xFC, 0x5E, 0x09, 0x5A, 0xF4, 0x84, + 0x8A, 0x08, 0xD3, 0x28, 0xD3, 0x68, 0x8E, 0x3D }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { 0x7B, 0xD9, 0x66, 0xD5, 0x3A, 0xD8, 0xC1, 0xBB, + 0x85, 0xD2, 0xAD, 0xFA, 0xE8, 0x7B, 0xB1, 0x04 }, + { 0xFE, 0x3C, 0x53, 0x65, 0x3E, 0x2F, 0x45, 0xB5, + 0x6F, 0xCD, 0x88, 0xB2, 0xCC, 0x89, 0x8F, 0xF0 } +#endif +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * AES-CFB128 test vectors from: + * + * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + */ +static const unsigned char aes_test_cfb128_key[][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B }, + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +#endif +}; + +static const unsigned char aes_test_cfb128_iv[16] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F +}; + +static const unsigned char aes_test_cfb128_pt[64] = +{ + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, + 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, + 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, + 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 +}; + +static const unsigned char aes_test_cfb128_ct[][64] = +{ + { 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20, + 0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A, + 0xC8, 0xA6, 0x45, 0x37, 0xA0, 0xB3, 0xA9, 0x3F, + 0xCD, 0xE3, 0xCD, 0xAD, 0x9F, 0x1C, 0xE5, 0x8B, + 0x26, 0x75, 0x1F, 0x67, 0xA3, 0xCB, 0xB1, 0x40, + 0xB1, 0x80, 0x8C, 0xF1, 0x87, 0xA4, 0xF4, 0xDF, + 0xC0, 0x4B, 0x05, 0x35, 0x7C, 0x5D, 0x1C, 0x0E, + 0xEA, 0xC4, 0xC6, 0x6F, 0x9F, 0xF7, 0xF2, 0xE6 }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB, + 0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74, + 0x67, 0xCE, 0x7F, 0x7F, 0x81, 0x17, 0x36, 0x21, + 0x96, 0x1A, 0x2B, 0x70, 0x17, 0x1D, 0x3D, 0x7A, + 0x2E, 0x1E, 0x8A, 0x1D, 0xD5, 0x9B, 0x88, 0xB1, + 0xC8, 0xE6, 0x0F, 0xED, 0x1E, 0xFA, 0xC4, 0xC9, + 0xC0, 0x5F, 0x9F, 0x9C, 0xA9, 0x83, 0x4F, 0xA0, + 0x42, 0xAE, 0x8F, 0xBA, 0x58, 0x4B, 0x09, 0xFF }, + { 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B, + 0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60, + 0x39, 0xFF, 0xED, 0x14, 0x3B, 0x28, 0xB1, 0xC8, + 0x32, 0x11, 0x3C, 0x63, 0x31, 0xE5, 0x40, 0x7B, + 0xDF, 0x10, 0x13, 0x24, 0x15, 0xE5, 0x4B, 0x92, + 0xA1, 0x3E, 0xD0, 0xA8, 0x26, 0x7A, 0xE2, 0xF9, + 0x75, 0xA3, 0x85, 0x74, 0x1A, 0xB9, 0xCE, 0xF8, + 0x20, 0x31, 0x62, 0x3D, 0x55, 0xB1, 0xE4, 0x71 } +#endif +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) +/* + * AES-OFB test vectors from: + * + * https://csrc.nist.gov/publications/detail/sp/800-38a/final + */ +static const unsigned char aes_test_ofb_key[][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B }, + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +#endif +}; + +static const unsigned char aes_test_ofb_iv[16] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F +}; + +static const unsigned char aes_test_ofb_pt[64] = +{ + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, + 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, + 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, + 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 +}; + +static const unsigned char aes_test_ofb_ct[][64] = +{ + { 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20, + 0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A, + 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, + 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25, + 0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, + 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc, + 0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, + 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB, + 0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74, + 0xfc, 0xc2, 0x8b, 0x8d, 0x4c, 0x63, 0x83, 0x7c, + 0x09, 0xe8, 0x17, 0x00, 0xc1, 0x10, 0x04, 0x01, + 0x8d, 0x9a, 0x9a, 0xea, 0xc0, 0xf6, 0x59, 0x6f, + 0x55, 0x9c, 0x6d, 0x4d, 0xaf, 0x59, 0xa5, 0xf2, + 0x6d, 0x9f, 0x20, 0x08, 0x57, 0xca, 0x6c, 0x3e, + 0x9c, 0xac, 0x52, 0x4b, 0xd9, 0xac, 0xc9, 0x2a }, + { 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B, + 0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60, + 0x4f, 0xeb, 0xdc, 0x67, 0x40, 0xd2, 0x0b, 0x3a, + 0xc8, 0x8f, 0x6a, 0xd8, 0x2a, 0x4f, 0xb0, 0x8d, + 0x71, 0xab, 0x47, 0xa0, 0x86, 0xe8, 0x6e, 0xed, + 0xf3, 0x9d, 0x1c, 0x5b, 0xba, 0x97, 0xc4, 0x08, + 0x01, 0x26, 0x14, 0x1d, 0x67, 0xf3, 0x7b, 0xe8, + 0x53, 0x8f, 0x5a, 0x8b, 0xe7, 0x40, 0xe4, 0x84 } +#endif +}; +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * AES-CTR test vectors from: + * + * http://www.faqs.org/rfcs/rfc3686.html + */ + +static const unsigned char aes_test_ctr_key[][16] = +{ + { 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC, + 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E }, + { 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7, + 0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63 }, + { 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8, + 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC } +}; + +static const unsigned char aes_test_ctr_nonce_counter[][16] = +{ + { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59, + 0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F, + 0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01 } +}; + +static const unsigned char aes_test_ctr_pt[][48] = +{ + { 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62, + 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23 } +}; + +static const unsigned char aes_test_ctr_ct[][48] = +{ + { 0xE4, 0x09, 0x5D, 0x4F, 0xB7, 0xA7, 0xB3, 0x79, + 0x2D, 0x61, 0x75, 0xA3, 0x26, 0x13, 0x11, 0xB8 }, + { 0x51, 0x04, 0xA1, 0x06, 0x16, 0x8A, 0x72, 0xD9, + 0x79, 0x0D, 0x41, 0xEE, 0x8E, 0xDA, 0xD3, 0x88, + 0xEB, 0x2E, 0x1E, 0xFC, 0x46, 0xDA, 0x57, 0xC8, + 0xFC, 0xE6, 0x30, 0xDF, 0x91, 0x41, 0xBE, 0x28 }, + { 0xC1, 0xCF, 0x48, 0xA8, 0x9F, 0x2F, 0xFD, 0xD9, + 0xCF, 0x46, 0x52, 0xE9, 0xEF, 0xDB, 0x72, 0xD7, + 0x45, 0x40, 0xA4, 0x2B, 0xDE, 0x6D, 0x78, 0x36, + 0xD5, 0x9A, 0x5C, 0xEA, 0xAE, 0xF3, 0x10, 0x53, + 0x25, 0xB2, 0x07, 0x2F } +}; + +static const int aes_test_ctr_len[3] = +{ 16, 32, 36 }; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/* + * AES-XTS test vectors from: + * + * IEEE P1619/D16 Annex B + * https://web.archive.org/web/20150629024421/http://grouper.ieee.org/groups/1619/email/pdf00086.pdf + * (Archived from original at http://grouper.ieee.org/groups/1619/email/pdf00086.pdf) + */ +static const unsigned char aes_test_xts_key[][32] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }, + { 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, + 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }, +}; + +static const unsigned char aes_test_xts_pt32[][32] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }, + { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }, +}; + +static const unsigned char aes_test_xts_ct32[][32] = +{ + { 0x91, 0x7c, 0xf6, 0x9e, 0xbd, 0x68, 0xb2, 0xec, + 0x9b, 0x9f, 0xe9, 0xa3, 0xea, 0xdd, 0xa6, 0x92, + 0xcd, 0x43, 0xd2, 0xf5, 0x95, 0x98, 0xed, 0x85, + 0x8c, 0x02, 0xc2, 0x65, 0x2f, 0xbf, 0x92, 0x2e }, + { 0xc4, 0x54, 0x18, 0x5e, 0x6a, 0x16, 0x93, 0x6e, + 0x39, 0x33, 0x40, 0x38, 0xac, 0xef, 0x83, 0x8b, + 0xfb, 0x18, 0x6f, 0xff, 0x74, 0x80, 0xad, 0xc4, + 0x28, 0x93, 0x82, 0xec, 0xd6, 0xd3, 0x94, 0xf0 }, + { 0xaf, 0x85, 0x33, 0x6b, 0x59, 0x7a, 0xfc, 0x1a, + 0x90, 0x0b, 0x2e, 0xb2, 0x1e, 0xc9, 0x49, 0xd2, + 0x92, 0xdf, 0x4c, 0x04, 0x7e, 0x0b, 0x21, 0x53, + 0x21, 0x86, 0xa5, 0x97, 0x1a, 0x22, 0x7a, 0x89 }, +}; + +static const unsigned char aes_test_xts_data_unit[][16] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +}; + +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +/* + * Checkup routine + */ +int mbedtls_aes_self_test(int verbose) +{ + int ret = 0, i, j, u, mode; + unsigned int keybits; + unsigned char key[32]; + unsigned char buf[64]; + const unsigned char *aes_tests; +#if defined(MBEDTLS_CIPHER_MODE_CBC) || defined(MBEDTLS_CIPHER_MODE_CFB) || \ + defined(MBEDTLS_CIPHER_MODE_OFB) + unsigned char iv[16]; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CBC) + unsigned char prv[16]; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) || defined(MBEDTLS_CIPHER_MODE_CFB) || \ + defined(MBEDTLS_CIPHER_MODE_OFB) + size_t offset; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) || defined(MBEDTLS_CIPHER_MODE_XTS) + int len; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + unsigned char nonce_counter[16]; + unsigned char stream_block[16]; +#endif + mbedtls_aes_context ctx; + + memset(key, 0, 32); + mbedtls_aes_init(&ctx); + + if (verbose != 0) { + mbedtls_aes_implementation aes_imp = mbedtls_aes_get_implementation(); + switch (aes_imp) { + case MBEDTLS_AES_IMP_AESNI_ASM: + mbedtls_printf(" AES note: AESNI code present (assembly implementation).\n"); + mbedtls_printf(" AES note: using AESNI.\n"); + break; + case MBEDTLS_AES_IMP_AESNI_INTRINSICS: + mbedtls_printf(" AES note: AESNI code present (intrinsics implementation).\n"); + mbedtls_printf(" AES note: using AESNI.\n"); + break; + case MBEDTLS_AES_IMP_AESCE: + mbedtls_printf(" AES note: using AESCE.\n"); + break; + case MBEDTLS_AES_IMP_SOFTWARE: + mbedtls_printf(" AES note: built-in implementation.\n"); + break; + case MBEDTLS_AES_IMP_UNKNOWN: + break; + } + } + + /* + * ECB mode + */ + { + static const int num_tests = + sizeof(aes_test_ecb_enc) / sizeof(*aes_test_ecb_enc); + + for (i = 0; i < num_tests << 1; i++) { + u = i >> 1; + keybits = 128 + u * 64; + mode = i & 1; + + if (verbose != 0) { + mbedtls_printf(" AES-ECB-%3u (%s): ", keybits, + (mode == MBEDTLS_AES_DECRYPT) ? "dec" : "enc"); + } +#if defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + if (mode == MBEDTLS_AES_DECRYPT) { + if (verbose != 0) { + mbedtls_printf("skipped\n"); + } + continue; + } +#endif + + memset(buf, 0, 16); + +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + if (mode == MBEDTLS_AES_DECRYPT) { + ret = mbedtls_aes_setkey_dec(&ctx, key, keybits); + aes_tests = aes_test_ecb_dec[u]; + } else +#endif + { + ret = mbedtls_aes_setkey_enc(&ctx, key, keybits); + aes_tests = aes_test_ecb_enc[u]; + } + + if (ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192) { + mbedtls_printf("skipped\n"); + continue; + } else if (ret != 0) { + goto exit; + } + + for (j = 0; j < 10000; j++) { + ret = mbedtls_aes_crypt_ecb(&ctx, mode, buf, buf); + if (ret != 0) { + goto exit; + } + } + + if (memcmp(buf, aes_tests, 16) != 0) { + ret = 1; + goto exit; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + } + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /* + * CBC mode + */ + { + static const int num_tests = + sizeof(aes_test_cbc_dec) / sizeof(*aes_test_cbc_dec); + + for (i = 0; i < num_tests << 1; i++) { + u = i >> 1; + keybits = 128 + u * 64; + mode = i & 1; + + if (verbose != 0) { + mbedtls_printf(" AES-CBC-%3u (%s): ", keybits, + (mode == MBEDTLS_AES_DECRYPT) ? "dec" : "enc"); + } + + memset(iv, 0, 16); + memset(prv, 0, 16); + memset(buf, 0, 16); + + if (mode == MBEDTLS_AES_DECRYPT) { + ret = mbedtls_aes_setkey_dec(&ctx, key, keybits); + aes_tests = aes_test_cbc_dec[u]; + } else { + ret = mbedtls_aes_setkey_enc(&ctx, key, keybits); + aes_tests = aes_test_cbc_enc[u]; + } + + if (ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192) { + mbedtls_printf("skipped\n"); + continue; + } else if (ret != 0) { + goto exit; + } + + for (j = 0; j < 10000; j++) { + if (mode == MBEDTLS_AES_ENCRYPT) { + unsigned char tmp[16]; + + memcpy(tmp, prv, 16); + memcpy(prv, buf, 16); + memcpy(buf, tmp, 16); + } + + ret = mbedtls_aes_crypt_cbc(&ctx, mode, 16, iv, buf, buf); + if (ret != 0) { + goto exit; + } + + } + + if (memcmp(buf, aes_tests, 16) != 0) { + ret = 1; + goto exit; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + /* + * CFB128 mode + */ + { + static const int num_tests = + sizeof(aes_test_cfb128_key) / sizeof(*aes_test_cfb128_key); + + for (i = 0; i < num_tests << 1; i++) { + u = i >> 1; + keybits = 128 + u * 64; + mode = i & 1; + + if (verbose != 0) { + mbedtls_printf(" AES-CFB128-%3u (%s): ", keybits, + (mode == MBEDTLS_AES_DECRYPT) ? "dec" : "enc"); + } + + memcpy(iv, aes_test_cfb128_iv, 16); + memcpy(key, aes_test_cfb128_key[u], keybits / 8); + + offset = 0; + ret = mbedtls_aes_setkey_enc(&ctx, key, keybits); + + if (ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192) { + mbedtls_printf("skipped\n"); + continue; + } else if (ret != 0) { + goto exit; + } + + if (mode == MBEDTLS_AES_DECRYPT) { + memcpy(buf, aes_test_cfb128_ct[u], 64); + aes_tests = aes_test_cfb128_pt; + } else { + memcpy(buf, aes_test_cfb128_pt, 64); + aes_tests = aes_test_cfb128_ct[u]; + } + + ret = mbedtls_aes_crypt_cfb128(&ctx, mode, 64, &offset, iv, buf, buf); + if (ret != 0) { + goto exit; + } + + if (memcmp(buf, aes_tests, 64) != 0) { + ret = 1; + goto exit; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + } +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) + /* + * OFB mode + */ + { + static const int num_tests = + sizeof(aes_test_ofb_key) / sizeof(*aes_test_ofb_key); + + for (i = 0; i < num_tests << 1; i++) { + u = i >> 1; + keybits = 128 + u * 64; + mode = i & 1; + + if (verbose != 0) { + mbedtls_printf(" AES-OFB-%3u (%s): ", keybits, + (mode == MBEDTLS_AES_DECRYPT) ? "dec" : "enc"); + } + + memcpy(iv, aes_test_ofb_iv, 16); + memcpy(key, aes_test_ofb_key[u], keybits / 8); + + offset = 0; + ret = mbedtls_aes_setkey_enc(&ctx, key, keybits); + + if (ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192) { + mbedtls_printf("skipped\n"); + continue; + } else if (ret != 0) { + goto exit; + } + + if (mode == MBEDTLS_AES_DECRYPT) { + memcpy(buf, aes_test_ofb_ct[u], 64); + aes_tests = aes_test_ofb_pt; + } else { + memcpy(buf, aes_test_ofb_pt, 64); + aes_tests = aes_test_ofb_ct[u]; + } + + ret = mbedtls_aes_crypt_ofb(&ctx, 64, &offset, iv, buf, buf); + if (ret != 0) { + goto exit; + } + + if (memcmp(buf, aes_tests, 64) != 0) { + ret = 1; + goto exit; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + } +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + /* + * CTR mode + */ + { + static const int num_tests = + sizeof(aes_test_ctr_key) / sizeof(*aes_test_ctr_key); + + for (i = 0; i < num_tests << 1; i++) { + u = i >> 1; + mode = i & 1; + + if (verbose != 0) { + mbedtls_printf(" AES-CTR-128 (%s): ", + (mode == MBEDTLS_AES_DECRYPT) ? "dec" : "enc"); + } + + memcpy(nonce_counter, aes_test_ctr_nonce_counter[u], 16); + memcpy(key, aes_test_ctr_key[u], 16); + + offset = 0; + if ((ret = mbedtls_aes_setkey_enc(&ctx, key, 128)) != 0) { + goto exit; + } + + len = aes_test_ctr_len[u]; + + if (mode == MBEDTLS_AES_DECRYPT) { + memcpy(buf, aes_test_ctr_ct[u], len); + aes_tests = aes_test_ctr_pt[u]; + } else { + memcpy(buf, aes_test_ctr_pt[u], len); + aes_tests = aes_test_ctr_ct[u]; + } + + ret = mbedtls_aes_crypt_ctr(&ctx, len, &offset, nonce_counter, + stream_block, buf, buf); + if (ret != 0) { + goto exit; + } + + if (memcmp(buf, aes_tests, len) != 0) { + ret = 1; + goto exit; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) + /* + * XTS mode + */ + { + static const int num_tests = + sizeof(aes_test_xts_key) / sizeof(*aes_test_xts_key); + mbedtls_aes_xts_context ctx_xts; + + mbedtls_aes_xts_init(&ctx_xts); + + for (i = 0; i < num_tests << 1; i++) { + const unsigned char *data_unit; + u = i >> 1; + mode = i & 1; + + if (verbose != 0) { + mbedtls_printf(" AES-XTS-128 (%s): ", + (mode == MBEDTLS_AES_DECRYPT) ? "dec" : "enc"); + } + + memset(key, 0, sizeof(key)); + memcpy(key, aes_test_xts_key[u], 32); + data_unit = aes_test_xts_data_unit[u]; + + len = sizeof(*aes_test_xts_ct32); + + if (mode == MBEDTLS_AES_DECRYPT) { + ret = mbedtls_aes_xts_setkey_dec(&ctx_xts, key, 256); + if (ret != 0) { + goto exit; + } + memcpy(buf, aes_test_xts_ct32[u], len); + aes_tests = aes_test_xts_pt32[u]; + } else { + ret = mbedtls_aes_xts_setkey_enc(&ctx_xts, key, 256); + if (ret != 0) { + goto exit; + } + memcpy(buf, aes_test_xts_pt32[u], len); + aes_tests = aes_test_xts_ct32[u]; + } + + + ret = mbedtls_aes_crypt_xts(&ctx_xts, mode, len, data_unit, + buf, buf); + if (ret != 0) { + goto exit; + } + + if (memcmp(buf, aes_tests, len) != 0) { + ret = 1; + goto exit; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + mbedtls_aes_xts_free(&ctx_xts); + } +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + + ret = 0; + +exit: + if (ret != 0 && verbose != 0) { + mbedtls_printf("failed\n"); + } + + mbedtls_aes_free(&ctx); + + return ret; +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_AES_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/aesce.c b/tf-psa-crypto/drivers/builtin/src/aesce.c new file mode 100644 index 0000000000..01ccc3fb2c --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/aesce.c @@ -0,0 +1,624 @@ +/* + * Armv8-A Cryptographic Extension support functions for Aarch64 + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#if defined(__clang__) && (__clang_major__ >= 4) + +/* Ideally, we would simply use MBEDTLS_ARCH_IS_ARMV8_A in the following #if, + * but that is defined by build_info.h, and we need this block to happen first. */ +#if defined(__ARM_ARCH) +#if __ARM_ARCH >= 8 +#define MBEDTLS_AESCE_ARCH_IS_ARMV8_A +#endif +#endif + +#if defined(MBEDTLS_AESCE_ARCH_IS_ARMV8_A) && !defined(__ARM_FEATURE_CRYPTO) +/* The intrinsic declaration are guarded by predefined ACLE macros in clang: + * these are normally only enabled by the -march option on the command line. + * By defining the macros ourselves we gain access to those declarations without + * requiring -march on the command line. + * + * `arm_neon.h` is included by tf_psa_crypto_common.h, so we put these defines + * at the top of this file, before any includes. This is necessary with + * Clang <=15.x. With Clang 16.0 and above, these macro definitions are + * no longer required, but they're harmless. See + * https://reviews.llvm.org/D131064 + */ +#define __ARM_FEATURE_CRYPTO 1 +/* See: https://arm-software.github.io/acle/main/acle.html#cryptographic-extensions + * + * `__ARM_FEATURE_CRYPTO` is deprecated, but we need to continue to specify it + * for older compilers. + */ +#define __ARM_FEATURE_AES 1 +#define MBEDTLS_ENABLE_ARM_CRYPTO_EXTENSIONS_COMPILER_FLAG +#endif + +#endif /* defined(__clang__) && (__clang_major__ >= 4) */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_AESCE_C) + +#include + +#include "aesce.h" + +#if defined(MBEDTLS_AESCE_HAVE_CODE) + +/* Compiler version checks. */ +#if defined(__clang__) +# if defined(MBEDTLS_ARCH_IS_ARM32) && (__clang_major__ < 11) +# error "Minimum version of Clang for MBEDTLS_AESCE_C on 32-bit Arm or Thumb is 11.0." +# elif defined(MBEDTLS_ARCH_IS_ARM64) && (__clang_major__ < 4) +# error "Minimum version of Clang for MBEDTLS_AESCE_C on aarch64 is 4.0." +# endif +#elif defined(__GNUC__) +# if __GNUC__ < 6 +# error "Minimum version of GCC for MBEDTLS_AESCE_C is 6.0." +# endif +#elif defined(_MSC_VER) +/* TODO: We haven't verified MSVC from 1920 to 1928. If someone verified that, + * please update this and document of `MBEDTLS_AESCE_C` in + * `mbedtls_config.h`. */ +# if _MSC_VER < 1929 +# error "Minimum version of MSVC for MBEDTLS_AESCE_C is 2019 version 16.11.2." +# endif +#elif defined(__ARMCC_VERSION) +# if defined(MBEDTLS_ARCH_IS_ARM32) && (__ARMCC_VERSION < 6200002) +/* TODO: We haven't verified armclang for 32-bit Arm/Thumb prior to 6.20. + * If someone verified that, please update this and document of + * `MBEDTLS_AESCE_C` in `mbedtls_config.h`. */ +# error "Minimum version of armclang for MBEDTLS_AESCE_C on 32-bit Arm is 6.20." +# elif defined(MBEDTLS_ARCH_IS_ARM64) && (__ARMCC_VERSION < 6060000) +# error "Minimum version of armclang for MBEDTLS_AESCE_C on aarch64 is 6.6." +# endif +#endif + +#if !(defined(__ARM_FEATURE_CRYPTO) || defined(__ARM_FEATURE_AES)) || \ + defined(MBEDTLS_ENABLE_ARM_CRYPTO_EXTENSIONS_COMPILER_FLAG) +# if defined(__ARMCOMPILER_VERSION) +# if __ARMCOMPILER_VERSION <= 6090000 +# error "Must use minimum -march=armv8-a+crypto for MBEDTLS_AESCE_C" +# else +# pragma clang attribute push (__attribute__((target("aes"))), apply_to=function) +# define MBEDTLS_POP_TARGET_PRAGMA +# endif +# elif defined(__clang__) +# if __clang_major__ < 7 +# pragma clang attribute push (__attribute__((target("crypto"))), apply_to=function) +# else +# pragma clang attribute push (__attribute__((target("aes"))), apply_to=function) +# endif +# define MBEDTLS_POP_TARGET_PRAGMA +# elif defined(__GNUC__) +# pragma GCC push_options +# pragma GCC target ("+crypto") +# define MBEDTLS_POP_TARGET_PRAGMA +# elif defined(_MSC_VER) +# error "Required feature(__ARM_FEATURE_AES) is not enabled." +# endif +#endif /* !(__ARM_FEATURE_CRYPTO || __ARM_FEATURE_AES) || + MBEDTLS_ENABLE_ARM_CRYPTO_EXTENSIONS_COMPILER_FLAG */ + +#if defined(__linux__) && !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) + +#include +#if !defined(HWCAP_NEON) +#define HWCAP_NEON (1 << 12) +#endif +#if !defined(HWCAP2_AES) +#define HWCAP2_AES (1 << 0) +#endif +#if !defined(HWCAP_AES) +#define HWCAP_AES (1 << 3) +#endif +#if !defined(HWCAP_ASIMD) +#define HWCAP_ASIMD (1 << 1) +#endif + +signed char mbedtls_aesce_has_support_result = -1; + +#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) +/* + * AES instruction support detection routine + */ +int mbedtls_aesce_has_support_impl(void) +{ + /* To avoid many calls to getauxval, cache the result. This is + * thread-safe, because we store the result in a char so cannot + * be vulnerable to non-atomic updates. + * It is possible that we could end up setting result more than + * once, but that is harmless. + */ + if (mbedtls_aesce_has_support_result == -1) { +#if defined(MBEDTLS_ARCH_IS_ARM32) + unsigned long auxval = getauxval(AT_HWCAP); + unsigned long auxval2 = getauxval(AT_HWCAP2); + if (((auxval & HWCAP_NEON) == HWCAP_NEON) && + ((auxval2 & HWCAP2_AES) == HWCAP2_AES)) { + mbedtls_aesce_has_support_result = 1; + } else { + mbedtls_aesce_has_support_result = 0; + } +#else + unsigned long auxval = getauxval(AT_HWCAP); + if ((auxval & (HWCAP_ASIMD | HWCAP_AES)) == + (HWCAP_ASIMD | HWCAP_AES)) { + mbedtls_aesce_has_support_result = 1; + } else { + mbedtls_aesce_has_support_result = 0; + } +#endif + } + return mbedtls_aesce_has_support_result; +} +#endif + +#endif /* defined(__linux__) && !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) */ + +/* Single round of AESCE encryption */ +#define AESCE_ENCRYPT_ROUND \ + block = vaeseq_u8(block, vld1q_u8(keys)); \ + block = vaesmcq_u8(block); \ + keys += 16 +/* Two rounds of AESCE encryption */ +#define AESCE_ENCRYPT_ROUND_X2 AESCE_ENCRYPT_ROUND; AESCE_ENCRYPT_ROUND + +MBEDTLS_OPTIMIZE_FOR_PERFORMANCE +static uint8x16_t aesce_encrypt_block(uint8x16_t block, + unsigned char *keys, + int rounds) +{ + /* 10, 12 or 14 rounds. Unroll loop. */ + if (rounds == 10) { + goto rounds_10; + } + if (rounds == 12) { + goto rounds_12; + } + AESCE_ENCRYPT_ROUND_X2; +rounds_12: + AESCE_ENCRYPT_ROUND_X2; +rounds_10: + AESCE_ENCRYPT_ROUND_X2; + AESCE_ENCRYPT_ROUND_X2; + AESCE_ENCRYPT_ROUND_X2; + AESCE_ENCRYPT_ROUND_X2; + AESCE_ENCRYPT_ROUND; + + /* AES AddRoundKey for the previous round. + * SubBytes, ShiftRows for the final round. */ + block = vaeseq_u8(block, vld1q_u8(keys)); + keys += 16; + + /* Final round: no MixColumns */ + + /* Final AddRoundKey */ + block = veorq_u8(block, vld1q_u8(keys)); + + return block; +} + +/* Single round of AESCE decryption + * + * AES AddRoundKey, SubBytes, ShiftRows + * + * block = vaesdq_u8(block, vld1q_u8(keys)); + * + * AES inverse MixColumns for the next round. + * + * This means that we switch the order of the inverse AddRoundKey and + * inverse MixColumns operations. We have to do this as AddRoundKey is + * done in an atomic instruction together with the inverses of SubBytes + * and ShiftRows. + * + * It works because MixColumns is a linear operation over GF(2^8) and + * AddRoundKey is an exclusive or, which is equivalent to addition over + * GF(2^8). (The inverse of MixColumns needs to be applied to the + * affected round keys separately which has been done when the + * decryption round keys were calculated.) + * + * block = vaesimcq_u8(block); + */ +#define AESCE_DECRYPT_ROUND \ + block = vaesdq_u8(block, vld1q_u8(keys)); \ + block = vaesimcq_u8(block); \ + keys += 16 +/* Two rounds of AESCE decryption */ +#define AESCE_DECRYPT_ROUND_X2 AESCE_DECRYPT_ROUND; AESCE_DECRYPT_ROUND + +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +static uint8x16_t aesce_decrypt_block(uint8x16_t block, + unsigned char *keys, + int rounds) +{ + /* 10, 12 or 14 rounds. Unroll loop. */ + if (rounds == 10) { + goto rounds_10; + } + if (rounds == 12) { + goto rounds_12; + } + AESCE_DECRYPT_ROUND_X2; +rounds_12: + AESCE_DECRYPT_ROUND_X2; +rounds_10: + AESCE_DECRYPT_ROUND_X2; + AESCE_DECRYPT_ROUND_X2; + AESCE_DECRYPT_ROUND_X2; + AESCE_DECRYPT_ROUND_X2; + AESCE_DECRYPT_ROUND; + + /* The inverses of AES AddRoundKey, SubBytes, ShiftRows finishing up the + * last full round. */ + block = vaesdq_u8(block, vld1q_u8(keys)); + keys += 16; + + /* Inverse AddRoundKey for inverting the initial round key addition. */ + block = veorq_u8(block, vld1q_u8(keys)); + + return block; +} +#endif + +/* + * AES-ECB block en(de)cryption + */ +int mbedtls_aesce_crypt_ecb(mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16]) +{ + uint8x16_t block = vld1q_u8(&input[0]); + unsigned char *keys = (unsigned char *) (ctx->buf + ctx->rk_offset); + +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + if (mode == MBEDTLS_AES_DECRYPT) { + block = aesce_decrypt_block(block, keys, ctx->nr); + } else +#else + (void) mode; +#endif + { + block = aesce_encrypt_block(block, keys, ctx->nr); + } + vst1q_u8(&output[0], block); + + return 0; +} + +/* + * Compute decryption round keys from encryption round keys + */ +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +void mbedtls_aesce_inverse_key(unsigned char *invkey, + const unsigned char *fwdkey, + int nr) +{ + int i, j; + j = nr; + vst1q_u8(invkey, vld1q_u8(fwdkey + j * 16)); + for (i = 1, j--; j > 0; i++, j--) { + vst1q_u8(invkey + i * 16, + vaesimcq_u8(vld1q_u8(fwdkey + j * 16))); + } + vst1q_u8(invkey + i * 16, vld1q_u8(fwdkey + j * 16)); + +} +#endif + +static inline uint32_t aes_rot_word(uint32_t word) +{ + return (word << (32 - 8)) | (word >> 8); +} + +static inline uint32_t aes_sub_word(uint32_t in) +{ + uint8x16_t v = vreinterpretq_u8_u32(vdupq_n_u32(in)); + uint8x16_t zero = vdupq_n_u8(0); + + /* vaeseq_u8 does both SubBytes and ShiftRows. Taking the first row yields + * the correct result as ShiftRows doesn't change the first row. */ + v = vaeseq_u8(zero, v); + return vgetq_lane_u32(vreinterpretq_u32_u8(v), 0); +} + +/* + * Key expansion function + */ +static void aesce_setkey_enc(unsigned char *rk, + const unsigned char *key, + const size_t key_bit_length) +{ + static uint8_t const rcon[] = { 0x01, 0x02, 0x04, 0x08, 0x10, + 0x20, 0x40, 0x80, 0x1b, 0x36 }; + /* See https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf + * - Section 5, Nr = Nk + 6 + * - Section 5.2, the length of round keys is Nb*(Nr+1) + */ + const size_t key_len_in_words = key_bit_length / 32; /* Nk */ + const size_t round_key_len_in_words = 4; /* Nb */ + const size_t rounds_needed = key_len_in_words + 6; /* Nr */ + const size_t round_keys_len_in_words = + round_key_len_in_words * (rounds_needed + 1); /* Nb*(Nr+1) */ + const uint32_t *rko_end = (uint32_t *) rk + round_keys_len_in_words; + + memcpy(rk, key, key_len_in_words * 4); + + for (uint32_t *rki = (uint32_t *) rk; + rki + key_len_in_words < rko_end; + rki += key_len_in_words) { + + size_t iteration = (size_t) (rki - (uint32_t *) rk) / key_len_in_words; + uint32_t *rko; + rko = rki + key_len_in_words; + rko[0] = aes_rot_word(aes_sub_word(rki[key_len_in_words - 1])); + rko[0] ^= rcon[iteration] ^ rki[0]; + rko[1] = rko[0] ^ rki[1]; + rko[2] = rko[1] ^ rki[2]; + rko[3] = rko[2] ^ rki[3]; + if (rko + key_len_in_words > rko_end) { + /* Do not write overflow words.*/ + continue; + } +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + switch (key_bit_length) { + case 128: + break; + case 192: + rko[4] = rko[3] ^ rki[4]; + rko[5] = rko[4] ^ rki[5]; + break; + case 256: + rko[4] = aes_sub_word(rko[3]) ^ rki[4]; + rko[5] = rko[4] ^ rki[5]; + rko[6] = rko[5] ^ rki[6]; + rko[7] = rko[6] ^ rki[7]; + break; + } +#endif /* !MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH */ + } +} + +/* + * Key expansion, wrapper + */ +int mbedtls_aesce_setkey_enc(unsigned char *rk, + const unsigned char *key, + size_t bits) +{ + switch (bits) { + case 128: + case 192: + case 256: + aesce_setkey_enc(rk, key, bits); + break; + default: + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + + return 0; +} + +#if defined(MBEDTLS_GCM_C) + +#if defined(MBEDTLS_ARCH_IS_ARM32) + +#if defined(__clang__) +/* On clang for A32/T32, work around some missing intrinsics and types which are listed in + * [ACLE](https://arm-software.github.io/acle/neon_intrinsics/advsimd.html#polynomial-1) + * These are only required for GCM. + */ +#define vreinterpretq_u64_p64(a) ((uint64x2_t) a) + +typedef uint8x16_t poly128_t; + +static inline poly128_t vmull_p64(poly64_t a, poly64_t b) +{ + poly128_t r; + asm ("vmull.p64 %[r], %[a], %[b]" : [r] "=w" (r) : [a] "w" (a), [b] "w" (b) :); + return r; +} + +/* This is set to cause some more missing intrinsics to be defined below */ +#define COMMON_MISSING_INTRINSICS + +static inline poly128_t vmull_high_p64(poly64x2_t a, poly64x2_t b) +{ + return vmull_p64((poly64_t) (vget_high_u64((uint64x2_t) a)), + (poly64_t) (vget_high_u64((uint64x2_t) b))); +} + +#endif /* defined(__clang__) */ + +static inline uint8x16_t vrbitq_u8(uint8x16_t x) +{ + /* There is no vrbitq_u8 instruction in A32/T32, so provide + * an equivalent non-Neon implementation. Reverse bit order in each + * byte with 4x rbit, rev. */ + asm ("ldm %[p], { r2-r5 } \n\t" + "rbit r2, r2 \n\t" + "rev r2, r2 \n\t" + "rbit r3, r3 \n\t" + "rev r3, r3 \n\t" + "rbit r4, r4 \n\t" + "rev r4, r4 \n\t" + "rbit r5, r5 \n\t" + "rev r5, r5 \n\t" + "stm %[p], { r2-r5 } \n\t" + : + /* Output: 16 bytes of memory pointed to by &x */ + "+m" (*(uint8_t(*)[16]) &x) + : + [p] "r" (&x) + : + "r2", "r3", "r4", "r5" + ); + return x; +} + +#endif /* defined(MBEDTLS_ARCH_IS_ARM32) */ + +#if defined(MBEDTLS_COMPILER_IS_GCC) && __GNUC__ == 5 +/* Some intrinsics are not available for GCC 5.X. */ +#define COMMON_MISSING_INTRINSICS +#endif /* MBEDTLS_COMPILER_IS_GCC && __GNUC__ == 5 */ + + +#if defined(COMMON_MISSING_INTRINSICS) + +/* Missing intrinsics common to both GCC 5, and Clang on 32-bit */ + +#define vreinterpretq_p64_u8(a) ((poly64x2_t) a) +#define vreinterpretq_u8_p128(a) ((uint8x16_t) a) + +static inline poly64x1_t vget_low_p64(poly64x2_t a) +{ + uint64x1_t r = vget_low_u64(vreinterpretq_u64_p64(a)); + return (poly64x1_t) r; + +} + +#endif /* COMMON_MISSING_INTRINSICS */ + +/* vmull_p64/vmull_high_p64 wrappers. + * + * Older compilers miss some intrinsic functions for `poly*_t`. We use + * uint8x16_t and uint8x16x3_t as input/output parameters. + */ +#if defined(MBEDTLS_COMPILER_IS_GCC) +/* GCC reports incompatible type error without cast. GCC think poly64_t and + * poly64x1_t are different, that is different with MSVC and Clang. */ +#define MBEDTLS_VMULL_P64(a, b) vmull_p64((poly64_t) a, (poly64_t) b) +#else +/* MSVC reports `error C2440: 'type cast'` with cast. Clang does not report + * error with/without cast. And I think poly64_t and poly64x1_t are same, no + * cast for clang also. */ +#define MBEDTLS_VMULL_P64(a, b) vmull_p64(a, b) +#endif /* MBEDTLS_COMPILER_IS_GCC */ + +static inline uint8x16_t pmull_low(uint8x16_t a, uint8x16_t b) +{ + + return vreinterpretq_u8_p128( + MBEDTLS_VMULL_P64( + (poly64_t) vget_low_p64(vreinterpretq_p64_u8(a)), + (poly64_t) vget_low_p64(vreinterpretq_p64_u8(b)) + )); +} + +static inline uint8x16_t pmull_high(uint8x16_t a, uint8x16_t b) +{ + return vreinterpretq_u8_p128( + vmull_high_p64(vreinterpretq_p64_u8(a), + vreinterpretq_p64_u8(b))); +} + +/* GHASH does 128b polynomial multiplication on block in GF(2^128) defined by + * `x^128 + x^7 + x^2 + x + 1`. + * + * Arm64 only has 64b->128b polynomial multipliers, we need to do 4 64b + * multiplies to generate a 128b. + * + * `poly_mult_128` executes polynomial multiplication and outputs 256b that + * represented by 3 128b due to code size optimization. + * + * Output layout: + * | | | | + * |------------|-------------|-------------| + * | ret.val[0] | h3:h2:00:00 | high 128b | + * | ret.val[1] | :m2:m1:00 | middle 128b | + * | ret.val[2] | : :l1:l0 | low 128b | + */ +static inline uint8x16x3_t poly_mult_128(uint8x16_t a, uint8x16_t b) +{ + uint8x16x3_t ret; + uint8x16_t h, m, l; /* retval high/middle/low */ + uint8x16_t c, d, e; + + h = pmull_high(a, b); /* h3:h2:00:00 = a1*b1 */ + l = pmull_low(a, b); /* : :l1:l0 = a0*b0 */ + c = vextq_u8(b, b, 8); /* :c1:c0 = b0:b1 */ + d = pmull_high(a, c); /* :d2:d1:00 = a1*b0 */ + e = pmull_low(a, c); /* :e2:e1:00 = a0*b1 */ + m = veorq_u8(d, e); /* :m2:m1:00 = d + e */ + + ret.val[0] = h; + ret.val[1] = m; + ret.val[2] = l; + return ret; +} + +/* + * Modulo reduction. + * + * See: https://www.researchgate.net/publication/285612706_Implementing_GCM_on_ARMv8 + * + * Section 4.3 + * + * Modular reduction is slightly more complex. Write the GCM modulus as f(z) = + * z^128 +r(z), where r(z) = z^7+z^2+z+ 1. The well known approach is to + * consider that z^128 ≡r(z) (mod z^128 +r(z)), allowing us to write the 256-bit + * operand to be reduced as a(z) = h(z)z^128 +l(z)≡h(z)r(z) + l(z). That is, we + * simply multiply the higher part of the operand by r(z) and add it to l(z). If + * the result is still larger than 128 bits, we reduce again. + */ +static inline uint8x16_t poly_mult_reduce(uint8x16x3_t input) +{ + uint8x16_t const ZERO = vdupq_n_u8(0); + + uint64x2_t r = vreinterpretq_u64_u8(vdupq_n_u8(0x87)); +#if defined(__GNUC__) + /* use 'asm' as an optimisation barrier to prevent loading MODULO from + * memory. It is for GNUC compatible compilers. + */ + asm volatile ("" : "+w" (r)); +#endif + uint8x16_t const MODULO = vreinterpretq_u8_u64(vshrq_n_u64(r, 64 - 8)); + uint8x16_t h, m, l; /* input high/middle/low 128b */ + uint8x16_t c, d, e, f, g, n, o; + h = input.val[0]; /* h3:h2:00:00 */ + m = input.val[1]; /* :m2:m1:00 */ + l = input.val[2]; /* : :l1:l0 */ + c = pmull_high(h, MODULO); /* :c2:c1:00 = reduction of h3 */ + d = pmull_low(h, MODULO); /* : :d1:d0 = reduction of h2 */ + e = veorq_u8(c, m); /* :e2:e1:00 = m2:m1:00 + c2:c1:00 */ + f = pmull_high(e, MODULO); /* : :f1:f0 = reduction of e2 */ + g = vextq_u8(ZERO, e, 8); /* : :g1:00 = e1:00 */ + n = veorq_u8(d, l); /* : :n1:n0 = d1:d0 + l1:l0 */ + o = veorq_u8(n, f); /* o1:o0 = f1:f0 + n1:n0 */ + return veorq_u8(o, g); /* = o1:o0 + g1:00 */ +} + +/* + * GCM multiplication: c = a times b in GF(2^128) + */ +void mbedtls_aesce_gcm_mult(unsigned char c[16], + const unsigned char a[16], + const unsigned char b[16]) +{ + uint8x16_t va, vb, vc; + va = vrbitq_u8(vld1q_u8(&a[0])); + vb = vrbitq_u8(vld1q_u8(&b[0])); + vc = vrbitq_u8(poly_mult_reduce(poly_mult_128(va, vb))); + vst1q_u8(&c[0], vc); +} + +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_POP_TARGET_PRAGMA) +#if defined(__clang__) +#pragma clang attribute pop +#elif defined(__GNUC__) +#pragma GCC pop_options +#endif +#undef MBEDTLS_POP_TARGET_PRAGMA +#endif + +#endif /* MBEDTLS_AESCE_HAVE_CODE */ + +#endif /* MBEDTLS_AESCE_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/aesce.h b/tf-psa-crypto/drivers/builtin/src/aesce.h new file mode 100644 index 0000000000..fcc4acdff6 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/aesce.h @@ -0,0 +1,135 @@ +/** + * \file aesce.h + * + * \brief Support hardware AES acceleration on Armv8-A processors with + * the Armv8-A Cryptographic Extension. + * + * \warning These functions are only for internal use by other library + * functions; you must not call them directly. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_AESCE_H +#define TF_PSA_CRYPTO_AESCE_H + +#include "tf_psa_crypto_common.h" + +#include "mbedtls/private/aes.h" + + +#if defined(MBEDTLS_AESCE_C) \ + && defined(MBEDTLS_ARCH_IS_ARMV8_A) && defined(MBEDTLS_HAVE_NEON_INTRINSICS) \ + && (defined(MBEDTLS_COMPILER_IS_GCC) || defined(__clang__) || defined(MSC_VER)) + +/* MBEDTLS_AESCE_HAVE_CODE is defined if we have a suitable target platform, and a + * potentially suitable compiler (compiler version & flags are not checked when defining + * this). */ +#define MBEDTLS_AESCE_HAVE_CODE + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__linux__) && !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) + +extern signed char mbedtls_aesce_has_support_result; + +/** + * \brief Internal function to detect the crypto extension in CPUs. + * + * \return 1 if CPU has support for the feature, 0 otherwise + */ +int mbedtls_aesce_has_support_impl(void); + +#define MBEDTLS_AESCE_HAS_SUPPORT() (mbedtls_aesce_has_support_result == -1 ? \ + mbedtls_aesce_has_support_impl() : \ + mbedtls_aesce_has_support_result) + +#else /* defined(__linux__) && !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) */ + +/* If we are not on Linux, we can't detect support so assume that it's supported. + * Similarly, assume support if MBEDTLS_AES_USE_HARDWARE_ONLY is set. + */ +#define MBEDTLS_AESCE_HAS_SUPPORT() 1 + +#endif /* defined(__linux__) && !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) */ + +/** + * \brief Internal AES-ECB block encryption and decryption + * + * \warning This assumes that the context specifies either 10, 12 or 14 + * rounds and will behave incorrectly if this is not the case. + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 on success (cannot fail) + */ +int mbedtls_aesce_crypt_ecb(mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16]); + +/** + * \brief Internal GCM multiplication: c = a * b in GF(2^128) + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. + * + * \param c Result + * \param a First operand + * \param b Second operand + * + * \note Both operands and result are bit strings interpreted as + * elements of GF(2^128) as per the GCM spec. + */ +void mbedtls_aesce_gcm_mult(unsigned char c[16], + const unsigned char a[16], + const unsigned char b[16]); + + +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +/** + * \brief Internal round key inversion. This function computes + * decryption round keys from the encryption round keys. + * + * \param invkey Round keys for the equivalent inverse cipher + * \param fwdkey Original round keys (for encryption) + * \param nr Number of rounds (that is, number of round keys minus one) + */ +void mbedtls_aesce_inverse_key(unsigned char *invkey, + const unsigned char *fwdkey, + int nr); +#endif /* !MBEDTLS_BLOCK_CIPHER_NO_DECRYPT */ + +/** + * \brief Internal key expansion for encryption + * + * \param rk Destination buffer where the round keys are written + * \param key Encryption key + * \param bits Key size in bits (must be 128, 192 or 256) + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH + */ +int mbedtls_aesce_setkey_enc(unsigned char *rk, + const unsigned char *key, + size_t bits); + +#ifdef __cplusplus +} +#endif + +#else + +#if defined(MBEDTLS_AES_USE_HARDWARE_ONLY) && defined(MBEDTLS_ARCH_IS_ARMV8_A) +#error "AES hardware acceleration not supported on this platform / compiler" +#endif + +#endif /* MBEDTLS_AESCE_C && MBEDTLS_ARCH_IS_ARMV8_A && MBEDTLS_HAVE_NEON_INTRINSICS && + (MBEDTLS_COMPILER_IS_GCC || __clang__ || MSC_VER) */ + +#endif /* TF_PSA_CRYPTO_AESCE_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/aesni.c b/tf-psa-crypto/drivers/builtin/src/aesni.c new file mode 100644 index 0000000000..dc4bd5d80c --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/aesni.c @@ -0,0 +1,846 @@ +/* + * AES-NI support functions + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +/* + * [AES-WP] https://www.intel.com/content/www/us/en/developer/articles/tool/intel-advanced-encryption-standard-aes-instructions-set.html + * [CLMUL-WP] https://www.intel.com/content/www/us/en/develop/download/intel-carry-less-multiplication-instruction-and-its-usage-for-computing-the-gcm-mode.html + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_AESNI_C) + +#include "aesni.h" + +#include + +#if defined(MBEDTLS_AESNI_HAVE_CODE) + +#if MBEDTLS_AESNI_HAVE_CODE == 2 +#if defined(__GNUC__) +#include +#elif defined(_MSC_VER) +#include +#else +#error "`__cpuid` required by MBEDTLS_AESNI_C is not supported by the compiler" +#endif +#include +#endif + +#if defined(MBEDTLS_ARCH_IS_X86) +#if defined(MBEDTLS_COMPILER_IS_GCC) +#pragma GCC push_options +#pragma GCC target ("pclmul,sse2,aes") +#define MBEDTLS_POP_TARGET_PRAGMA +#elif defined(__clang__) && (__clang_major__ >= 5) +#pragma clang attribute push (__attribute__((target("pclmul,sse2,aes"))), apply_to=function) +#define MBEDTLS_POP_TARGET_PRAGMA +#endif +#endif + +#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) +/* + * AES-NI support detection routine + */ +int mbedtls_aesni_has_support(unsigned int what) +{ + /* To avoid a race condition, tell the compiler that the assignment + * `done = 1` and the assignment to `c` may not be reordered. + * https://github.com/Mbed-TLS/mbedtls/issues/9840 + * + * Note that we may also be worried about memory access reordering, + * but fortunately the x86 memory model is not too wild: stores + * from the same thread are observed consistently by other threads. + * (See example 8-1 in Sewell et al., "x86-TSO: A Rigorous and Usable + * Programmer’s Model for x86 Multiprocessors", CACM, 2010, + * https://www.cl.cam.ac.uk/~pes20/weakmemory/cacm.pdf) + */ + static volatile int done = 0; + static volatile unsigned int c = 0; + + if (!done) { +#if MBEDTLS_AESNI_HAVE_CODE == 2 + static int info[4] = { 0, 0, 0, 0 }; +#if defined(_MSC_VER) + __cpuid(info, 1); +#else + __cpuid(1, info[0], info[1], info[2], info[3]); +#endif + c = info[2]; +#else /* AESNI using asm */ + asm ("movl $1, %%eax \n\t" + "cpuid \n\t" + : "=c" (c) + : + : "eax", "ebx", "edx"); +#endif /* MBEDTLS_AESNI_HAVE_CODE */ + done = 1; + } + + return (c & what) != 0; +} +#endif /* !MBEDTLS_AES_USE_HARDWARE_ONLY */ + +#if MBEDTLS_AESNI_HAVE_CODE == 2 + +/* + * AES-NI AES-ECB block en(de)cryption + */ +int mbedtls_aesni_crypt_ecb(mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16]) +{ + const __m128i *rk = (const __m128i *) (ctx->buf + ctx->rk_offset); + unsigned nr = ctx->nr; // Number of remaining rounds + + // Load round key 0 + __m128i state; + memcpy(&state, input, 16); + state = _mm_xor_si128(state, rk[0]); // state ^= *rk; + ++rk; + --nr; + +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + if (mode == MBEDTLS_AES_DECRYPT) { + while (nr != 0) { + state = _mm_aesdec_si128(state, *rk); + ++rk; + --nr; + } + state = _mm_aesdeclast_si128(state, *rk); + } else +#else + (void) mode; +#endif + { + while (nr != 0) { + state = _mm_aesenc_si128(state, *rk); + ++rk; + --nr; + } + state = _mm_aesenclast_si128(state, *rk); + } + + memcpy(output, &state, 16); + return 0; +} + +/* + * GCM multiplication: c = a times b in GF(2^128) + * Based on [CLMUL-WP] algorithms 1 (with equation 27) and 5. + */ + +static void gcm_clmul(const __m128i aa, const __m128i bb, + __m128i *cc, __m128i *dd) +{ + /* + * Caryless multiplication dd:cc = aa * bb + * using [CLMUL-WP] algorithm 1 (p. 12). + */ + *cc = _mm_clmulepi64_si128(aa, bb, 0x00); // a0*b0 = c1:c0 + *dd = _mm_clmulepi64_si128(aa, bb, 0x11); // a1*b1 = d1:d0 + __m128i ee = _mm_clmulepi64_si128(aa, bb, 0x10); // a0*b1 = e1:e0 + __m128i ff = _mm_clmulepi64_si128(aa, bb, 0x01); // a1*b0 = f1:f0 + ff = _mm_xor_si128(ff, ee); // e1+f1:e0+f0 + ee = ff; // e1+f1:e0+f0 + ff = _mm_srli_si128(ff, 8); // 0:e1+f1 + ee = _mm_slli_si128(ee, 8); // e0+f0:0 + *dd = _mm_xor_si128(*dd, ff); // d1:d0+e1+f1 + *cc = _mm_xor_si128(*cc, ee); // c1+e0+f0:c0 +} + +static void gcm_shift(__m128i *cc, __m128i *dd) +{ + /* [CMUCL-WP] Algorithm 5 Step 1: shift cc:dd one bit to the left, + * taking advantage of [CLMUL-WP] eq 27 (p. 18). */ + // // *cc = r1:r0 + // // *dd = r3:r2 + __m128i cc_lo = _mm_slli_epi64(*cc, 1); // r1<<1:r0<<1 + __m128i dd_lo = _mm_slli_epi64(*dd, 1); // r3<<1:r2<<1 + __m128i cc_hi = _mm_srli_epi64(*cc, 63); // r1>>63:r0>>63 + __m128i dd_hi = _mm_srli_epi64(*dd, 63); // r3>>63:r2>>63 + __m128i xmm5 = _mm_srli_si128(cc_hi, 8); // 0:r1>>63 + cc_hi = _mm_slli_si128(cc_hi, 8); // r0>>63:0 + dd_hi = _mm_slli_si128(dd_hi, 8); // 0:r1>>63 + + *cc = _mm_or_si128(cc_lo, cc_hi); // r1<<1|r0>>63:r0<<1 + *dd = _mm_or_si128(_mm_or_si128(dd_lo, dd_hi), xmm5); // r3<<1|r2>>62:r2<<1|r1>>63 +} + +static __m128i gcm_reduce(__m128i xx) +{ + // // xx = x1:x0 + /* [CLMUL-WP] Algorithm 5 Step 2 */ + __m128i aa = _mm_slli_epi64(xx, 63); // x1<<63:x0<<63 = stuff:a + __m128i bb = _mm_slli_epi64(xx, 62); // x1<<62:x0<<62 = stuff:b + __m128i cc = _mm_slli_epi64(xx, 57); // x1<<57:x0<<57 = stuff:c + __m128i dd = _mm_slli_si128(_mm_xor_si128(_mm_xor_si128(aa, bb), cc), 8); // a+b+c:0 + return _mm_xor_si128(dd, xx); // x1+a+b+c:x0 = d:x0 +} + +static __m128i gcm_mix(__m128i dx) +{ + /* [CLMUL-WP] Algorithm 5 Steps 3 and 4 */ + __m128i ee = _mm_srli_epi64(dx, 1); // e1:x0>>1 = e1:e0' + __m128i ff = _mm_srli_epi64(dx, 2); // f1:x0>>2 = f1:f0' + __m128i gg = _mm_srli_epi64(dx, 7); // g1:x0>>7 = g1:g0' + + // e0'+f0'+g0' is almost e0+f0+g0, except for some missing + // bits carried from d. Now get those bits back in. + __m128i eh = _mm_slli_epi64(dx, 63); // d<<63:stuff + __m128i fh = _mm_slli_epi64(dx, 62); // d<<62:stuff + __m128i gh = _mm_slli_epi64(dx, 57); // d<<57:stuff + __m128i hh = _mm_srli_si128(_mm_xor_si128(_mm_xor_si128(eh, fh), gh), 8); // 0:missing bits of d + + return _mm_xor_si128(_mm_xor_si128(_mm_xor_si128(_mm_xor_si128(ee, ff), gg), hh), dx); +} + +void mbedtls_aesni_gcm_mult(unsigned char c[16], + const unsigned char a[16], + const unsigned char b[16]) +{ + __m128i aa = { 0 }, bb = { 0 }, cc, dd; + + /* The inputs are in big-endian order, so byte-reverse them */ + for (size_t i = 0; i < 16; i++) { + ((uint8_t *) &aa)[i] = a[15 - i]; + ((uint8_t *) &bb)[i] = b[15 - i]; + } + + gcm_clmul(aa, bb, &cc, &dd); + gcm_shift(&cc, &dd); + /* + * Now reduce modulo the GCM polynomial x^128 + x^7 + x^2 + x + 1 + * using [CLMUL-WP] algorithm 5 (p. 18). + * Currently dd:cc holds x3:x2:x1:x0 (already shifted). + */ + __m128i dx = gcm_reduce(cc); + __m128i xh = gcm_mix(dx); + cc = _mm_xor_si128(xh, dd); // x3+h1:x2+h0 + + /* Now byte-reverse the outputs */ + for (size_t i = 0; i < 16; i++) { + c[i] = ((uint8_t *) &cc)[15 - i]; + } + + return; +} + +/* + * Compute decryption round keys from encryption round keys + */ +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +void mbedtls_aesni_inverse_key(unsigned char *invkey, + const unsigned char *fwdkey, int nr) +{ + __m128i *ik = (__m128i *) invkey; + const __m128i *fk = (const __m128i *) fwdkey + nr; + + *ik = *fk; + for (--fk, ++ik; fk > (const __m128i *) fwdkey; --fk, ++ik) { + *ik = _mm_aesimc_si128(*fk); + } + *ik = *fk; +} +#endif + +/* + * Key expansion, 128-bit case + */ +static __m128i aesni_set_rk_128(__m128i state, __m128i xword) +{ + /* + * Finish generating the next round key. + * + * On entry state is r3:r2:r1:r0 and xword is X:stuff:stuff:stuff + * with X = rot( sub( r3 ) ) ^ RCON (obtained with AESKEYGENASSIST). + * + * On exit, xword is r7:r6:r5:r4 + * with r4 = X + r0, r5 = r4 + r1, r6 = r5 + r2, r7 = r6 + r3 + * and this is returned, to be written to the round key buffer. + */ + xword = _mm_shuffle_epi32(xword, 0xff); // X:X:X:X + xword = _mm_xor_si128(xword, state); // X+r3:X+r2:X+r1:r4 + state = _mm_slli_si128(state, 4); // r2:r1:r0:0 + xword = _mm_xor_si128(xword, state); // X+r3+r2:X+r2+r1:r5:r4 + state = _mm_slli_si128(state, 4); // r1:r0:0:0 + xword = _mm_xor_si128(xword, state); // X+r3+r2+r1:r6:r5:r4 + state = _mm_slli_si128(state, 4); // r0:0:0:0 + state = _mm_xor_si128(xword, state); // r7:r6:r5:r4 + return state; +} + +static void aesni_setkey_enc_128(unsigned char *rk_bytes, + const unsigned char *key) +{ + __m128i *rk = (__m128i *) rk_bytes; + + memcpy(&rk[0], key, 16); + rk[1] = aesni_set_rk_128(rk[0], _mm_aeskeygenassist_si128(rk[0], 0x01)); + rk[2] = aesni_set_rk_128(rk[1], _mm_aeskeygenassist_si128(rk[1], 0x02)); + rk[3] = aesni_set_rk_128(rk[2], _mm_aeskeygenassist_si128(rk[2], 0x04)); + rk[4] = aesni_set_rk_128(rk[3], _mm_aeskeygenassist_si128(rk[3], 0x08)); + rk[5] = aesni_set_rk_128(rk[4], _mm_aeskeygenassist_si128(rk[4], 0x10)); + rk[6] = aesni_set_rk_128(rk[5], _mm_aeskeygenassist_si128(rk[5], 0x20)); + rk[7] = aesni_set_rk_128(rk[6], _mm_aeskeygenassist_si128(rk[6], 0x40)); + rk[8] = aesni_set_rk_128(rk[7], _mm_aeskeygenassist_si128(rk[7], 0x80)); + rk[9] = aesni_set_rk_128(rk[8], _mm_aeskeygenassist_si128(rk[8], 0x1B)); + rk[10] = aesni_set_rk_128(rk[9], _mm_aeskeygenassist_si128(rk[9], 0x36)); +} + +/* + * Key expansion, 192-bit case + */ +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) +static void aesni_set_rk_192(__m128i *state0, __m128i *state1, __m128i xword, + unsigned char *rk) +{ + /* + * Finish generating the next 6 quarter-keys. + * + * On entry state0 is r3:r2:r1:r0, state1 is stuff:stuff:r5:r4 + * and xword is stuff:stuff:X:stuff with X = rot( sub( r3 ) ) ^ RCON + * (obtained with AESKEYGENASSIST). + * + * On exit, state0 is r9:r8:r7:r6 and state1 is stuff:stuff:r11:r10 + * and those are written to the round key buffer. + */ + xword = _mm_shuffle_epi32(xword, 0x55); // X:X:X:X + xword = _mm_xor_si128(xword, *state0); // X+r3:X+r2:X+r1:X+r0 + *state0 = _mm_slli_si128(*state0, 4); // r2:r1:r0:0 + xword = _mm_xor_si128(xword, *state0); // X+r3+r2:X+r2+r1:X+r1+r0:X+r0 + *state0 = _mm_slli_si128(*state0, 4); // r1:r0:0:0 + xword = _mm_xor_si128(xword, *state0); // X+r3+r2+r1:X+r2+r1+r0:X+r1+r0:X+r0 + *state0 = _mm_slli_si128(*state0, 4); // r0:0:0:0 + xword = _mm_xor_si128(xword, *state0); // X+r3+r2+r1+r0:X+r2+r1+r0:X+r1+r0:X+r0 + *state0 = xword; // = r9:r8:r7:r6 + + xword = _mm_shuffle_epi32(xword, 0xff); // r9:r9:r9:r9 + xword = _mm_xor_si128(xword, *state1); // stuff:stuff:r9+r5:r9+r4 + *state1 = _mm_slli_si128(*state1, 4); // stuff:stuff:r4:0 + xword = _mm_xor_si128(xword, *state1); // stuff:stuff:r9+r5+r4:r9+r4 + *state1 = xword; // = stuff:stuff:r11:r10 + + /* Store state0 and the low half of state1 into rk, which is conceptually + * an array of 24-byte elements. Since 24 is not a multiple of 16, + * rk is not necessarily aligned so just `*rk = *state0` doesn't work. */ + memcpy(rk, state0, 16); + memcpy(rk + 16, state1, 8); +} + +static void aesni_setkey_enc_192(unsigned char *rk, + const unsigned char *key) +{ + /* First round: use original key */ + memcpy(rk, key, 24); + /* aes.c guarantees that rk is aligned on a 16-byte boundary. */ + __m128i state0 = ((__m128i *) rk)[0]; + __m128i state1 = _mm_loadl_epi64(((__m128i *) rk) + 1); + + aesni_set_rk_192(&state0, &state1, _mm_aeskeygenassist_si128(state1, 0x01), rk + 24 * 1); + aesni_set_rk_192(&state0, &state1, _mm_aeskeygenassist_si128(state1, 0x02), rk + 24 * 2); + aesni_set_rk_192(&state0, &state1, _mm_aeskeygenassist_si128(state1, 0x04), rk + 24 * 3); + aesni_set_rk_192(&state0, &state1, _mm_aeskeygenassist_si128(state1, 0x08), rk + 24 * 4); + aesni_set_rk_192(&state0, &state1, _mm_aeskeygenassist_si128(state1, 0x10), rk + 24 * 5); + aesni_set_rk_192(&state0, &state1, _mm_aeskeygenassist_si128(state1, 0x20), rk + 24 * 6); + aesni_set_rk_192(&state0, &state1, _mm_aeskeygenassist_si128(state1, 0x40), rk + 24 * 7); + aesni_set_rk_192(&state0, &state1, _mm_aeskeygenassist_si128(state1, 0x80), rk + 24 * 8); +} +#endif /* !MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH */ + +/* + * Key expansion, 256-bit case + */ +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) +static void aesni_set_rk_256(__m128i state0, __m128i state1, __m128i xword, + __m128i *rk0, __m128i *rk1) +{ + /* + * Finish generating the next two round keys. + * + * On entry state0 is r3:r2:r1:r0, state1 is r7:r6:r5:r4 and + * xword is X:stuff:stuff:stuff with X = rot( sub( r7 )) ^ RCON + * (obtained with AESKEYGENASSIST). + * + * On exit, *rk0 is r11:r10:r9:r8 and *rk1 is r15:r14:r13:r12 + */ + xword = _mm_shuffle_epi32(xword, 0xff); + xword = _mm_xor_si128(xword, state0); + state0 = _mm_slli_si128(state0, 4); + xword = _mm_xor_si128(xword, state0); + state0 = _mm_slli_si128(state0, 4); + xword = _mm_xor_si128(xword, state0); + state0 = _mm_slli_si128(state0, 4); + state0 = _mm_xor_si128(state0, xword); + *rk0 = state0; + + /* Set xword to stuff:Y:stuff:stuff with Y = subword( r11 ) + * and proceed to generate next round key from there */ + xword = _mm_aeskeygenassist_si128(state0, 0x00); + xword = _mm_shuffle_epi32(xword, 0xaa); + xword = _mm_xor_si128(xword, state1); + state1 = _mm_slli_si128(state1, 4); + xword = _mm_xor_si128(xword, state1); + state1 = _mm_slli_si128(state1, 4); + xword = _mm_xor_si128(xword, state1); + state1 = _mm_slli_si128(state1, 4); + state1 = _mm_xor_si128(state1, xword); + *rk1 = state1; +} + +static void aesni_setkey_enc_256(unsigned char *rk_bytes, + const unsigned char *key) +{ + __m128i *rk = (__m128i *) rk_bytes; + + memcpy(&rk[0], key, 16); + memcpy(&rk[1], key + 16, 16); + + /* + * Main "loop" - Generating one more key than necessary, + * see definition of mbedtls_aes_context.buf + */ + aesni_set_rk_256(rk[0], rk[1], _mm_aeskeygenassist_si128(rk[1], 0x01), &rk[2], &rk[3]); + aesni_set_rk_256(rk[2], rk[3], _mm_aeskeygenassist_si128(rk[3], 0x02), &rk[4], &rk[5]); + aesni_set_rk_256(rk[4], rk[5], _mm_aeskeygenassist_si128(rk[5], 0x04), &rk[6], &rk[7]); + aesni_set_rk_256(rk[6], rk[7], _mm_aeskeygenassist_si128(rk[7], 0x08), &rk[8], &rk[9]); + aesni_set_rk_256(rk[8], rk[9], _mm_aeskeygenassist_si128(rk[9], 0x10), &rk[10], &rk[11]); + aesni_set_rk_256(rk[10], rk[11], _mm_aeskeygenassist_si128(rk[11], 0x20), &rk[12], &rk[13]); + aesni_set_rk_256(rk[12], rk[13], _mm_aeskeygenassist_si128(rk[13], 0x40), &rk[14], &rk[15]); +} +#endif /* !MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH */ + +#if defined(MBEDTLS_POP_TARGET_PRAGMA) +#if defined(__clang__) +#pragma clang attribute pop +#elif defined(__GNUC__) +#pragma GCC pop_options +#endif +#undef MBEDTLS_POP_TARGET_PRAGMA +#endif + +#else /* MBEDTLS_AESNI_HAVE_CODE == 1 */ + +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) +#warning \ + "MBEDTLS_AESNI_C is known to cause spurious error reports with some memory sanitizers as they do not understand the assembly code." +#endif +#endif + +/* + * Binutils needs to be at least 2.19 to support AES-NI instructions. + * Unfortunately, a lot of users have a lower version now (2014-04). + * Emit bytecode directly in order to support "old" version of gas. + * + * Opcodes from the Intel architecture reference manual, vol. 3. + * We always use registers, so we don't need prefixes for memory operands. + * Operand macros are in gas order (src, dst) as opposed to Intel order + * (dst, src) in order to blend better into the surrounding assembly code. + */ +#define AESDEC(regs) ".byte 0x66,0x0F,0x38,0xDE," regs "\n\t" +#define AESDECLAST(regs) ".byte 0x66,0x0F,0x38,0xDF," regs "\n\t" +#define AESENC(regs) ".byte 0x66,0x0F,0x38,0xDC," regs "\n\t" +#define AESENCLAST(regs) ".byte 0x66,0x0F,0x38,0xDD," regs "\n\t" +#define AESIMC(regs) ".byte 0x66,0x0F,0x38,0xDB," regs "\n\t" +#define AESKEYGENA(regs, imm) ".byte 0x66,0x0F,0x3A,0xDF," regs "," imm "\n\t" +#define PCLMULQDQ(regs, imm) ".byte 0x66,0x0F,0x3A,0x44," regs "," imm "\n\t" + +#define xmm0_xmm0 "0xC0" +#define xmm0_xmm1 "0xC8" +#define xmm0_xmm2 "0xD0" +#define xmm0_xmm3 "0xD8" +#define xmm0_xmm4 "0xE0" +#define xmm1_xmm0 "0xC1" +#define xmm1_xmm2 "0xD1" + +/* + * AES-NI AES-ECB block en(de)cryption + */ +int mbedtls_aesni_crypt_ecb(mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16]) +{ + asm ("movdqu (%3), %%xmm0 \n\t" // load input + "movdqu (%1), %%xmm1 \n\t" // load round key 0 + "pxor %%xmm1, %%xmm0 \n\t" // round 0 + "add $16, %1 \n\t" // point to next round key + "subl $1, %0 \n\t" // normal rounds = nr - 1 + "test %2, %2 \n\t" // mode? + "jz 2f \n\t" // 0 = decrypt + + "1: \n\t" // encryption loop + "movdqu (%1), %%xmm1 \n\t" // load round key + AESENC(xmm1_xmm0) // do round + "add $16, %1 \n\t" // point to next round key + "subl $1, %0 \n\t" // loop + "jnz 1b \n\t" + "movdqu (%1), %%xmm1 \n\t" // load round key + AESENCLAST(xmm1_xmm0) // last round +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + "jmp 3f \n\t" + + "2: \n\t" // decryption loop + "movdqu (%1), %%xmm1 \n\t" + AESDEC(xmm1_xmm0) // do round + "add $16, %1 \n\t" + "subl $1, %0 \n\t" + "jnz 2b \n\t" + "movdqu (%1), %%xmm1 \n\t" // load round key + AESDECLAST(xmm1_xmm0) // last round +#endif + + "3: \n\t" + "movdqu %%xmm0, (%4) \n\t" // export output + : + : "r" (ctx->nr), "r" (ctx->buf + ctx->rk_offset), "r" (mode), "r" (input), "r" (output) + : "memory", "cc", "xmm0", "xmm1", "0", "1"); + + + return 0; +} + +/* + * GCM multiplication: c = a times b in GF(2^128) + * Based on [CLMUL-WP] algorithms 1 (with equation 27) and 5. + */ +void mbedtls_aesni_gcm_mult(unsigned char c[16], + const unsigned char a[16], + const unsigned char b[16]) +{ + unsigned char aa[16], bb[16], cc[16]; + size_t i; + + /* The inputs are in big-endian order, so byte-reverse them */ + for (i = 0; i < 16; i++) { + aa[i] = a[15 - i]; + bb[i] = b[15 - i]; + } + + asm ("movdqu (%0), %%xmm0 \n\t" // a1:a0 + "movdqu (%1), %%xmm1 \n\t" // b1:b0 + + /* + * Caryless multiplication xmm2:xmm1 = xmm0 * xmm1 + * using [CLMUL-WP] algorithm 1 (p. 12). + */ + "movdqa %%xmm1, %%xmm2 \n\t" // copy of b1:b0 + "movdqa %%xmm1, %%xmm3 \n\t" // same + "movdqa %%xmm1, %%xmm4 \n\t" // same + PCLMULQDQ(xmm0_xmm1, "0x00") // a0*b0 = c1:c0 + PCLMULQDQ(xmm0_xmm2, "0x11") // a1*b1 = d1:d0 + PCLMULQDQ(xmm0_xmm3, "0x10") // a0*b1 = e1:e0 + PCLMULQDQ(xmm0_xmm4, "0x01") // a1*b0 = f1:f0 + "pxor %%xmm3, %%xmm4 \n\t" // e1+f1:e0+f0 + "movdqa %%xmm4, %%xmm3 \n\t" // same + "psrldq $8, %%xmm4 \n\t" // 0:e1+f1 + "pslldq $8, %%xmm3 \n\t" // e0+f0:0 + "pxor %%xmm4, %%xmm2 \n\t" // d1:d0+e1+f1 + "pxor %%xmm3, %%xmm1 \n\t" // c1+e0+f1:c0 + + /* + * Now shift the result one bit to the left, + * taking advantage of [CLMUL-WP] eq 27 (p. 18) + */ + "movdqa %%xmm1, %%xmm3 \n\t" // r1:r0 + "movdqa %%xmm2, %%xmm4 \n\t" // r3:r2 + "psllq $1, %%xmm1 \n\t" // r1<<1:r0<<1 + "psllq $1, %%xmm2 \n\t" // r3<<1:r2<<1 + "psrlq $63, %%xmm3 \n\t" // r1>>63:r0>>63 + "psrlq $63, %%xmm4 \n\t" // r3>>63:r2>>63 + "movdqa %%xmm3, %%xmm5 \n\t" // r1>>63:r0>>63 + "pslldq $8, %%xmm3 \n\t" // r0>>63:0 + "pslldq $8, %%xmm4 \n\t" // r2>>63:0 + "psrldq $8, %%xmm5 \n\t" // 0:r1>>63 + "por %%xmm3, %%xmm1 \n\t" // r1<<1|r0>>63:r0<<1 + "por %%xmm4, %%xmm2 \n\t" // r3<<1|r2>>62:r2<<1 + "por %%xmm5, %%xmm2 \n\t" // r3<<1|r2>>62:r2<<1|r1>>63 + + /* + * Now reduce modulo the GCM polynomial x^128 + x^7 + x^2 + x + 1 + * using [CLMUL-WP] algorithm 5 (p. 18). + * Currently xmm2:xmm1 holds x3:x2:x1:x0 (already shifted). + */ + /* Step 2 (1) */ + "movdqa %%xmm1, %%xmm3 \n\t" // x1:x0 + "movdqa %%xmm1, %%xmm4 \n\t" // same + "movdqa %%xmm1, %%xmm5 \n\t" // same + "psllq $63, %%xmm3 \n\t" // x1<<63:x0<<63 = stuff:a + "psllq $62, %%xmm4 \n\t" // x1<<62:x0<<62 = stuff:b + "psllq $57, %%xmm5 \n\t" // x1<<57:x0<<57 = stuff:c + + /* Step 2 (2) */ + "pxor %%xmm4, %%xmm3 \n\t" // stuff:a+b + "pxor %%xmm5, %%xmm3 \n\t" // stuff:a+b+c + "pslldq $8, %%xmm3 \n\t" // a+b+c:0 + "pxor %%xmm3, %%xmm1 \n\t" // x1+a+b+c:x0 = d:x0 + + /* Steps 3 and 4 */ + "movdqa %%xmm1,%%xmm0 \n\t" // d:x0 + "movdqa %%xmm1,%%xmm4 \n\t" // same + "movdqa %%xmm1,%%xmm5 \n\t" // same + "psrlq $1, %%xmm0 \n\t" // e1:x0>>1 = e1:e0' + "psrlq $2, %%xmm4 \n\t" // f1:x0>>2 = f1:f0' + "psrlq $7, %%xmm5 \n\t" // g1:x0>>7 = g1:g0' + "pxor %%xmm4, %%xmm0 \n\t" // e1+f1:e0'+f0' + "pxor %%xmm5, %%xmm0 \n\t" // e1+f1+g1:e0'+f0'+g0' + // e0'+f0'+g0' is almost e0+f0+g0, ex\tcept for some missing + // bits carried from d. Now get those\t bits back in. + "movdqa %%xmm1,%%xmm3 \n\t" // d:x0 + "movdqa %%xmm1,%%xmm4 \n\t" // same + "movdqa %%xmm1,%%xmm5 \n\t" // same + "psllq $63, %%xmm3 \n\t" // d<<63:stuff + "psllq $62, %%xmm4 \n\t" // d<<62:stuff + "psllq $57, %%xmm5 \n\t" // d<<57:stuff + "pxor %%xmm4, %%xmm3 \n\t" // d<<63+d<<62:stuff + "pxor %%xmm5, %%xmm3 \n\t" // missing bits of d:stuff + "psrldq $8, %%xmm3 \n\t" // 0:missing bits of d + "pxor %%xmm3, %%xmm0 \n\t" // e1+f1+g1:e0+f0+g0 + "pxor %%xmm1, %%xmm0 \n\t" // h1:h0 + "pxor %%xmm2, %%xmm0 \n\t" // x3+h1:x2+h0 + + "movdqu %%xmm0, (%2) \n\t" // done + : + : "r" (aa), "r" (bb), "r" (cc) + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); + + /* Now byte-reverse the outputs */ + for (i = 0; i < 16; i++) { + c[i] = cc[15 - i]; + } + + return; +} + +/* + * Compute decryption round keys from encryption round keys + */ +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +void mbedtls_aesni_inverse_key(unsigned char *invkey, + const unsigned char *fwdkey, int nr) +{ + unsigned char *ik = invkey; + const unsigned char *fk = fwdkey + 16 * nr; + + memcpy(ik, fk, 16); + + for (fk -= 16, ik += 16; fk > fwdkey; fk -= 16, ik += 16) { + asm ("movdqu (%0), %%xmm0 \n\t" + AESIMC(xmm0_xmm0) + "movdqu %%xmm0, (%1) \n\t" + : + : "r" (fk), "r" (ik) + : "memory", "xmm0"); + } + + memcpy(ik, fk, 16); +} +#endif + +/* + * Key expansion, 128-bit case + */ +static void aesni_setkey_enc_128(unsigned char *rk, + const unsigned char *key) +{ + asm ("movdqu (%1), %%xmm0 \n\t" // copy the original key + "movdqu %%xmm0, (%0) \n\t" // as round key 0 + "jmp 2f \n\t" // skip auxiliary routine + + /* + * Finish generating the next round key. + * + * On entry xmm0 is r3:r2:r1:r0 and xmm1 is X:stuff:stuff:stuff + * with X = rot( sub( r3 ) ) ^ RCON. + * + * On exit, xmm0 is r7:r6:r5:r4 + * with r4 = X + r0, r5 = r4 + r1, r6 = r5 + r2, r7 = r6 + r3 + * and those are written to the round key buffer. + */ + "1: \n\t" + "pshufd $0xff, %%xmm1, %%xmm1 \n\t" // X:X:X:X + "pxor %%xmm0, %%xmm1 \n\t" // X+r3:X+r2:X+r1:r4 + "pslldq $4, %%xmm0 \n\t" // r2:r1:r0:0 + "pxor %%xmm0, %%xmm1 \n\t" // X+r3+r2:X+r2+r1:r5:r4 + "pslldq $4, %%xmm0 \n\t" // etc + "pxor %%xmm0, %%xmm1 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm1, %%xmm0 \n\t" // update xmm0 for next time! + "add $16, %0 \n\t" // point to next round key + "movdqu %%xmm0, (%0) \n\t" // write it + "ret \n\t" + + /* Main "loop" */ + "2: \n\t" + AESKEYGENA(xmm0_xmm1, "0x01") "call 1b \n\t" + AESKEYGENA(xmm0_xmm1, "0x02") "call 1b \n\t" + AESKEYGENA(xmm0_xmm1, "0x04") "call 1b \n\t" + AESKEYGENA(xmm0_xmm1, "0x08") "call 1b \n\t" + AESKEYGENA(xmm0_xmm1, "0x10") "call 1b \n\t" + AESKEYGENA(xmm0_xmm1, "0x20") "call 1b \n\t" + AESKEYGENA(xmm0_xmm1, "0x40") "call 1b \n\t" + AESKEYGENA(xmm0_xmm1, "0x80") "call 1b \n\t" + AESKEYGENA(xmm0_xmm1, "0x1B") "call 1b \n\t" + AESKEYGENA(xmm0_xmm1, "0x36") "call 1b \n\t" + : + : "r" (rk), "r" (key) + : "memory", "cc", "xmm0", "xmm1", "0"); +} + +/* + * Key expansion, 192-bit case + */ +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) +static void aesni_setkey_enc_192(unsigned char *rk, + const unsigned char *key) +{ + asm ("movdqu (%1), %%xmm0 \n\t" // copy original round key + "movdqu %%xmm0, (%0) \n\t" + "add $16, %0 \n\t" + "movq 16(%1), %%xmm1 \n\t" + "movq %%xmm1, (%0) \n\t" + "add $8, %0 \n\t" + "jmp 2f \n\t" // skip auxiliary routine + + /* + * Finish generating the next 6 quarter-keys. + * + * On entry xmm0 is r3:r2:r1:r0, xmm1 is stuff:stuff:r5:r4 + * and xmm2 is stuff:stuff:X:stuff with X = rot( sub( r3 ) ) ^ RCON. + * + * On exit, xmm0 is r9:r8:r7:r6 and xmm1 is stuff:stuff:r11:r10 + * and those are written to the round key buffer. + */ + "1: \n\t" + "pshufd $0x55, %%xmm2, %%xmm2 \n\t" // X:X:X:X + "pxor %%xmm0, %%xmm2 \n\t" // X+r3:X+r2:X+r1:r4 + "pslldq $4, %%xmm0 \n\t" // etc + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm2, %%xmm0 \n\t" // update xmm0 = r9:r8:r7:r6 + "movdqu %%xmm0, (%0) \n\t" + "add $16, %0 \n\t" + "pshufd $0xff, %%xmm0, %%xmm2 \n\t" // r9:r9:r9:r9 + "pxor %%xmm1, %%xmm2 \n\t" // stuff:stuff:r9+r5:r10 + "pslldq $4, %%xmm1 \n\t" // r2:r1:r0:0 + "pxor %%xmm2, %%xmm1 \n\t" // xmm1 = stuff:stuff:r11:r10 + "movq %%xmm1, (%0) \n\t" + "add $8, %0 \n\t" + "ret \n\t" + + "2: \n\t" + AESKEYGENA(xmm1_xmm2, "0x01") "call 1b \n\t" + AESKEYGENA(xmm1_xmm2, "0x02") "call 1b \n\t" + AESKEYGENA(xmm1_xmm2, "0x04") "call 1b \n\t" + AESKEYGENA(xmm1_xmm2, "0x08") "call 1b \n\t" + AESKEYGENA(xmm1_xmm2, "0x10") "call 1b \n\t" + AESKEYGENA(xmm1_xmm2, "0x20") "call 1b \n\t" + AESKEYGENA(xmm1_xmm2, "0x40") "call 1b \n\t" + AESKEYGENA(xmm1_xmm2, "0x80") "call 1b \n\t" + + : + : "r" (rk), "r" (key) + : "memory", "cc", "xmm0", "xmm1", "xmm2", "0"); +} +#endif /* !MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH */ + +/* + * Key expansion, 256-bit case + */ +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) +static void aesni_setkey_enc_256(unsigned char *rk, + const unsigned char *key) +{ + asm ("movdqu (%1), %%xmm0 \n\t" + "movdqu %%xmm0, (%0) \n\t" + "add $16, %0 \n\t" + "movdqu 16(%1), %%xmm1 \n\t" + "movdqu %%xmm1, (%0) \n\t" + "jmp 2f \n\t" // skip auxiliary routine + + /* + * Finish generating the next two round keys. + * + * On entry xmm0 is r3:r2:r1:r0, xmm1 is r7:r6:r5:r4 and + * xmm2 is X:stuff:stuff:stuff with X = rot( sub( r7 )) ^ RCON + * + * On exit, xmm0 is r11:r10:r9:r8 and xmm1 is r15:r14:r13:r12 + * and those have been written to the output buffer. + */ + "1: \n\t" + "pshufd $0xff, %%xmm2, %%xmm2 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm2, %%xmm0 \n\t" + "add $16, %0 \n\t" + "movdqu %%xmm0, (%0) \n\t" + + /* Set xmm2 to stuff:Y:stuff:stuff with Y = subword( r11 ) + * and proceed to generate next round key from there */ + AESKEYGENA(xmm0_xmm2, "0x00") + "pshufd $0xaa, %%xmm2, %%xmm2 \n\t" + "pxor %%xmm1, %%xmm2 \n\t" + "pslldq $4, %%xmm1 \n\t" + "pxor %%xmm1, %%xmm2 \n\t" + "pslldq $4, %%xmm1 \n\t" + "pxor %%xmm1, %%xmm2 \n\t" + "pslldq $4, %%xmm1 \n\t" + "pxor %%xmm2, %%xmm1 \n\t" + "add $16, %0 \n\t" + "movdqu %%xmm1, (%0) \n\t" + "ret \n\t" + + /* + * Main "loop" - Generating one more key than necessary, + * see definition of mbedtls_aes_context.buf + */ + "2: \n\t" + AESKEYGENA(xmm1_xmm2, "0x01") "call 1b \n\t" + AESKEYGENA(xmm1_xmm2, "0x02") "call 1b \n\t" + AESKEYGENA(xmm1_xmm2, "0x04") "call 1b \n\t" + AESKEYGENA(xmm1_xmm2, "0x08") "call 1b \n\t" + AESKEYGENA(xmm1_xmm2, "0x10") "call 1b \n\t" + AESKEYGENA(xmm1_xmm2, "0x20") "call 1b \n\t" + AESKEYGENA(xmm1_xmm2, "0x40") "call 1b \n\t" + : + : "r" (rk), "r" (key) + : "memory", "cc", "xmm0", "xmm1", "xmm2", "0"); +} +#endif /* !MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH */ + +#endif /* MBEDTLS_AESNI_HAVE_CODE */ + +/* + * Key expansion, wrapper + */ +int mbedtls_aesni_setkey_enc(unsigned char *rk, + const unsigned char *key, + size_t bits) +{ + switch (bits) { + case 128: aesni_setkey_enc_128(rk, key); break; +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + case 192: aesni_setkey_enc_192(rk, key); break; + case 256: aesni_setkey_enc_256(rk, key); break; +#endif /* !MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH */ + default: return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + + return 0; +} + +#endif /* MBEDTLS_AESNI_HAVE_CODE */ + +#endif /* MBEDTLS_AESNI_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/aesni.h b/tf-psa-crypto/drivers/builtin/src/aesni.h new file mode 100644 index 0000000000..ee0468d2f7 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/aesni.h @@ -0,0 +1,162 @@ +/** + * \file aesni.h + * + * \brief AES-NI for hardware AES acceleration on some Intel processors + * + * \warning These functions are only for internal use by other library + * functions; you must not call them directly. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_AESNI_H +#define TF_PSA_CRYPTO_AESNI_H + +#include "tf-psa-crypto/build_info.h" + +#include "mbedtls/private/aes.h" + +#define MBEDTLS_AESNI_AES 0x02000000u +#define MBEDTLS_AESNI_CLMUL 0x00000002u + +#if defined(MBEDTLS_AESNI_C) && \ + (defined(MBEDTLS_ARCH_IS_X64) || defined(MBEDTLS_ARCH_IS_X86)) + +/* Can we do AESNI with intrinsics? + * (Only implemented with certain compilers, only for certain targets.) + */ +#undef MBEDTLS_AESNI_HAVE_INTRINSICS +#if defined(_MSC_VER) && !defined(__clang__) +/* Visual Studio supports AESNI intrinsics since VS 2008 SP1. We only support + * VS 2013 and up for other reasons anyway, so no need to check the version. */ +#define MBEDTLS_AESNI_HAVE_INTRINSICS +#endif +/* GCC-like compilers: currently, we only support intrinsics if the requisite + * target flag is enabled when building the library (e.g. `gcc -mpclmul -msse2` + * or `clang -maes -mpclmul`). */ +#if (defined(__GNUC__) || defined(__clang__)) && defined(__AES__) && defined(__PCLMUL__) +#define MBEDTLS_AESNI_HAVE_INTRINSICS +#endif +/* For 32-bit, we only support intrinsics */ +#if defined(MBEDTLS_ARCH_IS_X86) && (defined(__GNUC__) || defined(__clang__)) +#define MBEDTLS_AESNI_HAVE_INTRINSICS +#endif + +/* Choose the implementation of AESNI, if one is available. + * + * Favor the intrinsics-based implementation if it's available, for better + * maintainability. + * Performance is about the same (see #7380). + * In the long run, we will likely remove the assembly implementation. */ +#if defined(MBEDTLS_AESNI_HAVE_INTRINSICS) +#define MBEDTLS_AESNI_HAVE_CODE 2 // via intrinsics +#elif defined(MBEDTLS_HAVE_ASM) && \ + (defined(__GNUC__) || defined(__clang__)) && defined(MBEDTLS_ARCH_IS_X64) +/* Can we do AESNI with inline assembly? + * (Only implemented with gas syntax, only for 64-bit.) + */ +#define MBEDTLS_AESNI_HAVE_CODE 1 // via assembly +#else +#error "MBEDTLS_AESNI_C defined, but neither intrinsics nor assembly available" +#endif + +#if defined(MBEDTLS_AESNI_HAVE_CODE) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Internal function to detect the AES-NI feature in CPUs. + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. + * + * \param what The feature to detect + * (MBEDTLS_AESNI_AES or MBEDTLS_AESNI_CLMUL) + * + * \return 1 if CPU has support for the feature, 0 otherwise + */ +#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) +int mbedtls_aesni_has_support(unsigned int what); +#else +#define mbedtls_aesni_has_support(what) 1 +#endif + +/** + * \brief Internal AES-NI AES-ECB block encryption and decryption + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 on success (cannot fail) + */ +int mbedtls_aesni_crypt_ecb(mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16]); + +/** + * \brief Internal GCM multiplication: c = a * b in GF(2^128) + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. + * + * \param c Result + * \param a First operand + * \param b Second operand + * + * \note Both operands and result are bit strings interpreted as + * elements of GF(2^128) as per the GCM spec. + */ +void mbedtls_aesni_gcm_mult(unsigned char c[16], + const unsigned char a[16], + const unsigned char b[16]); + +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +/** + * \brief Internal round key inversion. This function computes + * decryption round keys from the encryption round keys. + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. + * + * \param invkey Round keys for the equivalent inverse cipher + * \param fwdkey Original round keys (for encryption) + * \param nr Number of rounds (that is, number of round keys minus one) + */ +void mbedtls_aesni_inverse_key(unsigned char *invkey, + const unsigned char *fwdkey, + int nr); +#endif /* !MBEDTLS_BLOCK_CIPHER_NO_DECRYPT */ + +/** + * \brief Internal key expansion for encryption + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. + * + * \param rk Destination buffer where the round keys are written + * \param key Encryption key + * \param bits Key size in bits (must be 128, 192 or 256) + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH + */ +int mbedtls_aesni_setkey_enc(unsigned char *rk, + const unsigned char *key, + size_t bits); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_AESNI_HAVE_CODE */ +#endif /* MBEDTLS_AESNI_C && (MBEDTLS_ARCH_IS_X64 || MBEDTLS_ARCH_IS_X86) */ + +#endif /* TF_PSA_CRYPTO_AESNI_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/aria.c b/tf-psa-crypto/drivers/builtin/src/aria.c new file mode 100644 index 0000000000..da56de7b94 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/aria.c @@ -0,0 +1,966 @@ +/* + * ARIA implementation + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +/* + * This implementation is based on the following standards: + * [1] http://210.104.33.10/ARIA/doc/ARIA-specification-e.pdf + * [2] https://tools.ietf.org/html/rfc5794 + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_ARIA_C) + +#include "mbedtls/private/aria.h" + +#include + +#include "mbedtls/platform.h" + +#include "mbedtls/platform_util.h" + +/* + * modify byte order: ( A B C D ) -> ( B A D C ), i.e. swap pairs of bytes + * + * This is submatrix P1 in [1] Appendix B.1 + * + * Common compilers fail to translate this to minimal number of instructions, + * so let's provide asm versions for common platforms with C fallback. + */ +#if defined(MBEDTLS_HAVE_ASM) +#if defined(__arm__) /* rev16 available from v6 up */ +/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */ +#if defined(__GNUC__) && \ + (!defined(__ARMCC_VERSION) || __ARMCC_VERSION >= 6000000) && \ + __ARM_ARCH >= 6 +static inline uint32_t aria_p1(uint32_t x) +{ + uint32_t r; + __asm("rev16 %0, %1" : "=l" (r) : "l" (x)); + return r; +} +#define ARIA_P1 aria_p1 +#elif defined(__ARMCC_VERSION) && __ARMCC_VERSION < 6000000 && \ + (__TARGET_ARCH_ARM >= 6 || __TARGET_ARCH_THUMB >= 3) +static inline uint32_t aria_p1(uint32_t x) +{ + uint32_t r; + __asm("rev16 r, x"); + return r; +} +#define ARIA_P1 aria_p1 +#endif +#endif /* arm */ +#if defined(__GNUC__) && \ + defined(__i386__) || defined(__amd64__) || defined(__x86_64__) +/* I couldn't find an Intel equivalent of rev16, so two instructions */ +#define ARIA_P1(x) ARIA_P2(ARIA_P3(x)) +#endif /* x86 gnuc */ +#endif /* MBEDTLS_HAVE_ASM && GNUC */ +#if !defined(ARIA_P1) +#define ARIA_P1(x) ((((x) >> 8) & 0x00FF00FF) ^ (((x) & 0x00FF00FF) << 8)) +#endif + +/* + * modify byte order: ( A B C D ) -> ( C D A B ), i.e. rotate by 16 bits + * + * This is submatrix P2 in [1] Appendix B.1 + * + * Common compilers will translate this to a single instruction. + */ +#define ARIA_P2(x) (((x) >> 16) ^ ((x) << 16)) + +/* + * modify byte order: ( A B C D ) -> ( D C B A ), i.e. change endianness + * + * This is submatrix P3 in [1] Appendix B.1 + */ +#define ARIA_P3(x) MBEDTLS_BSWAP32(x) + +/* + * ARIA Affine Transform + * (a, b, c, d) = state in/out + * + * If we denote the first byte of input by 0, ..., the last byte by f, + * then inputs are: a = 0123, b = 4567, c = 89ab, d = cdef. + * + * Reading [1] 2.4 or [2] 2.4.3 in columns and performing simple + * rearrangements on adjacent pairs, output is: + * + * a = 3210 + 4545 + 6767 + 88aa + 99bb + dccd + effe + * = 3210 + 4567 + 6745 + 89ab + 98ba + dcfe + efcd + * b = 0101 + 2323 + 5476 + 8998 + baab + eecc + ffdd + * = 0123 + 2301 + 5476 + 89ab + ba98 + efcd + fedc + * c = 0022 + 1133 + 4554 + 7667 + ab89 + dcdc + fefe + * = 0123 + 1032 + 4567 + 7654 + ab89 + dcfe + fedc + * d = 1001 + 2332 + 6644 + 7755 + 9898 + baba + cdef + * = 1032 + 2301 + 6745 + 7654 + 98ba + ba98 + cdef + * + * Note: another presentation of the A transform can be found as the first + * half of App. B.1 in [1] in terms of 4-byte operators P1, P2, P3 and P4. + * The implementation below uses only P1 and P2 as they are sufficient. + */ +static inline void aria_a(uint32_t *a, uint32_t *b, + uint32_t *c, uint32_t *d) +{ + uint32_t ta, tb, tc; + ta = *b; // 4567 + *b = *a; // 0123 + *a = ARIA_P2(ta); // 6745 + tb = ARIA_P2(*d); // efcd + *d = ARIA_P1(*c); // 98ba + *c = ARIA_P1(tb); // fedc + ta ^= *d; // 4567+98ba + tc = ARIA_P2(*b); // 2301 + ta = ARIA_P1(ta) ^ tc ^ *c; // 2301+5476+89ab+fedc + tb ^= ARIA_P2(*d); // ba98+efcd + tc ^= ARIA_P1(*a); // 2301+7654 + *b ^= ta ^ tb; // 0123+2301+5476+89ab+ba98+efcd+fedc OUT + tb = ARIA_P2(tb) ^ ta; // 2301+5476+89ab+98ba+cdef+fedc + *a ^= ARIA_P1(tb); // 3210+4567+6745+89ab+98ba+dcfe+efcd OUT + ta = ARIA_P2(ta); // 0123+7654+ab89+dcfe + *d ^= ARIA_P1(ta) ^ tc; // 1032+2301+6745+7654+98ba+ba98+cdef OUT + tc = ARIA_P2(tc); // 0123+5476 + *c ^= ARIA_P1(tc) ^ ta; // 0123+1032+4567+7654+ab89+dcfe+fedc OUT +} + +/* + * ARIA Substitution Layer SL1 / SL2 + * (a, b, c, d) = state in/out + * (sa, sb, sc, sd) = 256 8-bit S-Boxes (see below) + * + * By passing sb1, sb2, is1, is2 as S-Boxes you get SL1 + * By passing is1, is2, sb1, sb2 as S-Boxes you get SL2 + */ +static inline void aria_sl(uint32_t *a, uint32_t *b, + uint32_t *c, uint32_t *d, + const uint8_t sa[256], const uint8_t sb[256], + const uint8_t sc[256], const uint8_t sd[256]) +{ + *a = ((uint32_t) sa[MBEDTLS_BYTE_0(*a)]) ^ + (((uint32_t) sb[MBEDTLS_BYTE_1(*a)]) << 8) ^ + (((uint32_t) sc[MBEDTLS_BYTE_2(*a)]) << 16) ^ + (((uint32_t) sd[MBEDTLS_BYTE_3(*a)]) << 24); + *b = ((uint32_t) sa[MBEDTLS_BYTE_0(*b)]) ^ + (((uint32_t) sb[MBEDTLS_BYTE_1(*b)]) << 8) ^ + (((uint32_t) sc[MBEDTLS_BYTE_2(*b)]) << 16) ^ + (((uint32_t) sd[MBEDTLS_BYTE_3(*b)]) << 24); + *c = ((uint32_t) sa[MBEDTLS_BYTE_0(*c)]) ^ + (((uint32_t) sb[MBEDTLS_BYTE_1(*c)]) << 8) ^ + (((uint32_t) sc[MBEDTLS_BYTE_2(*c)]) << 16) ^ + (((uint32_t) sd[MBEDTLS_BYTE_3(*c)]) << 24); + *d = ((uint32_t) sa[MBEDTLS_BYTE_0(*d)]) ^ + (((uint32_t) sb[MBEDTLS_BYTE_1(*d)]) << 8) ^ + (((uint32_t) sc[MBEDTLS_BYTE_2(*d)]) << 16) ^ + (((uint32_t) sd[MBEDTLS_BYTE_3(*d)]) << 24); +} + +/* + * S-Boxes + */ +static const uint8_t aria_sb1[256] = +{ + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, + 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, + 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, + 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, + 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, + 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, + 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, + 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, + 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, + 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, + 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, + 0xB0, 0x54, 0xBB, 0x16 +}; + +static const uint8_t aria_sb2[256] = +{ + 0xE2, 0x4E, 0x54, 0xFC, 0x94, 0xC2, 0x4A, 0xCC, 0x62, 0x0D, 0x6A, 0x46, + 0x3C, 0x4D, 0x8B, 0xD1, 0x5E, 0xFA, 0x64, 0xCB, 0xB4, 0x97, 0xBE, 0x2B, + 0xBC, 0x77, 0x2E, 0x03, 0xD3, 0x19, 0x59, 0xC1, 0x1D, 0x06, 0x41, 0x6B, + 0x55, 0xF0, 0x99, 0x69, 0xEA, 0x9C, 0x18, 0xAE, 0x63, 0xDF, 0xE7, 0xBB, + 0x00, 0x73, 0x66, 0xFB, 0x96, 0x4C, 0x85, 0xE4, 0x3A, 0x09, 0x45, 0xAA, + 0x0F, 0xEE, 0x10, 0xEB, 0x2D, 0x7F, 0xF4, 0x29, 0xAC, 0xCF, 0xAD, 0x91, + 0x8D, 0x78, 0xC8, 0x95, 0xF9, 0x2F, 0xCE, 0xCD, 0x08, 0x7A, 0x88, 0x38, + 0x5C, 0x83, 0x2A, 0x28, 0x47, 0xDB, 0xB8, 0xC7, 0x93, 0xA4, 0x12, 0x53, + 0xFF, 0x87, 0x0E, 0x31, 0x36, 0x21, 0x58, 0x48, 0x01, 0x8E, 0x37, 0x74, + 0x32, 0xCA, 0xE9, 0xB1, 0xB7, 0xAB, 0x0C, 0xD7, 0xC4, 0x56, 0x42, 0x26, + 0x07, 0x98, 0x60, 0xD9, 0xB6, 0xB9, 0x11, 0x40, 0xEC, 0x20, 0x8C, 0xBD, + 0xA0, 0xC9, 0x84, 0x04, 0x49, 0x23, 0xF1, 0x4F, 0x50, 0x1F, 0x13, 0xDC, + 0xD8, 0xC0, 0x9E, 0x57, 0xE3, 0xC3, 0x7B, 0x65, 0x3B, 0x02, 0x8F, 0x3E, + 0xE8, 0x25, 0x92, 0xE5, 0x15, 0xDD, 0xFD, 0x17, 0xA9, 0xBF, 0xD4, 0x9A, + 0x7E, 0xC5, 0x39, 0x67, 0xFE, 0x76, 0x9D, 0x43, 0xA7, 0xE1, 0xD0, 0xF5, + 0x68, 0xF2, 0x1B, 0x34, 0x70, 0x05, 0xA3, 0x8A, 0xD5, 0x79, 0x86, 0xA8, + 0x30, 0xC6, 0x51, 0x4B, 0x1E, 0xA6, 0x27, 0xF6, 0x35, 0xD2, 0x6E, 0x24, + 0x16, 0x82, 0x5F, 0xDA, 0xE6, 0x75, 0xA2, 0xEF, 0x2C, 0xB2, 0x1C, 0x9F, + 0x5D, 0x6F, 0x80, 0x0A, 0x72, 0x44, 0x9B, 0x6C, 0x90, 0x0B, 0x5B, 0x33, + 0x7D, 0x5A, 0x52, 0xF3, 0x61, 0xA1, 0xF7, 0xB0, 0xD6, 0x3F, 0x7C, 0x6D, + 0xED, 0x14, 0xE0, 0xA5, 0x3D, 0x22, 0xB3, 0xF8, 0x89, 0xDE, 0x71, 0x1A, + 0xAF, 0xBA, 0xB5, 0x81 +}; + +static const uint8_t aria_is1[256] = +{ + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, + 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, + 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, + 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, + 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, + 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, + 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, + 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, + 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, + 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, + 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, + 0x55, 0x21, 0x0C, 0x7D +}; + +static const uint8_t aria_is2[256] = +{ + 0x30, 0x68, 0x99, 0x1B, 0x87, 0xB9, 0x21, 0x78, 0x50, 0x39, 0xDB, 0xE1, + 0x72, 0x09, 0x62, 0x3C, 0x3E, 0x7E, 0x5E, 0x8E, 0xF1, 0xA0, 0xCC, 0xA3, + 0x2A, 0x1D, 0xFB, 0xB6, 0xD6, 0x20, 0xC4, 0x8D, 0x81, 0x65, 0xF5, 0x89, + 0xCB, 0x9D, 0x77, 0xC6, 0x57, 0x43, 0x56, 0x17, 0xD4, 0x40, 0x1A, 0x4D, + 0xC0, 0x63, 0x6C, 0xE3, 0xB7, 0xC8, 0x64, 0x6A, 0x53, 0xAA, 0x38, 0x98, + 0x0C, 0xF4, 0x9B, 0xED, 0x7F, 0x22, 0x76, 0xAF, 0xDD, 0x3A, 0x0B, 0x58, + 0x67, 0x88, 0x06, 0xC3, 0x35, 0x0D, 0x01, 0x8B, 0x8C, 0xC2, 0xE6, 0x5F, + 0x02, 0x24, 0x75, 0x93, 0x66, 0x1E, 0xE5, 0xE2, 0x54, 0xD8, 0x10, 0xCE, + 0x7A, 0xE8, 0x08, 0x2C, 0x12, 0x97, 0x32, 0xAB, 0xB4, 0x27, 0x0A, 0x23, + 0xDF, 0xEF, 0xCA, 0xD9, 0xB8, 0xFA, 0xDC, 0x31, 0x6B, 0xD1, 0xAD, 0x19, + 0x49, 0xBD, 0x51, 0x96, 0xEE, 0xE4, 0xA8, 0x41, 0xDA, 0xFF, 0xCD, 0x55, + 0x86, 0x36, 0xBE, 0x61, 0x52, 0xF8, 0xBB, 0x0E, 0x82, 0x48, 0x69, 0x9A, + 0xE0, 0x47, 0x9E, 0x5C, 0x04, 0x4B, 0x34, 0x15, 0x79, 0x26, 0xA7, 0xDE, + 0x29, 0xAE, 0x92, 0xD7, 0x84, 0xE9, 0xD2, 0xBA, 0x5D, 0xF3, 0xC5, 0xB0, + 0xBF, 0xA4, 0x3B, 0x71, 0x44, 0x46, 0x2B, 0xFC, 0xEB, 0x6F, 0xD5, 0xF6, + 0x14, 0xFE, 0x7C, 0x70, 0x5A, 0x7D, 0xFD, 0x2F, 0x18, 0x83, 0x16, 0xA5, + 0x91, 0x1F, 0x05, 0x95, 0x74, 0xA9, 0xC1, 0x5B, 0x4A, 0x85, 0x6D, 0x13, + 0x07, 0x4F, 0x4E, 0x45, 0xB2, 0x0F, 0xC9, 0x1C, 0xA6, 0xBC, 0xEC, 0x73, + 0x90, 0x7B, 0xCF, 0x59, 0x8F, 0xA1, 0xF9, 0x2D, 0xF2, 0xB1, 0x00, 0x94, + 0x37, 0x9F, 0xD0, 0x2E, 0x9C, 0x6E, 0x28, 0x3F, 0x80, 0xF0, 0x3D, 0xD3, + 0x25, 0x8A, 0xB5, 0xE7, 0x42, 0xB3, 0xC7, 0xEA, 0xF7, 0x4C, 0x11, 0x33, + 0x03, 0xA2, 0xAC, 0x60 +}; + +/* + * Helper for key schedule: r = FO( p, k ) ^ x + */ +static void aria_fo_xor(uint32_t r[4], const uint32_t p[4], + const uint32_t k[4], const uint32_t x[4]) +{ + uint32_t a, b, c, d; + + a = p[0] ^ k[0]; + b = p[1] ^ k[1]; + c = p[2] ^ k[2]; + d = p[3] ^ k[3]; + + aria_sl(&a, &b, &c, &d, aria_sb1, aria_sb2, aria_is1, aria_is2); + aria_a(&a, &b, &c, &d); + + r[0] = a ^ x[0]; + r[1] = b ^ x[1]; + r[2] = c ^ x[2]; + r[3] = d ^ x[3]; +} + +/* + * Helper for key schedule: r = FE( p, k ) ^ x + */ +static void aria_fe_xor(uint32_t r[4], const uint32_t p[4], + const uint32_t k[4], const uint32_t x[4]) +{ + uint32_t a, b, c, d; + + a = p[0] ^ k[0]; + b = p[1] ^ k[1]; + c = p[2] ^ k[2]; + d = p[3] ^ k[3]; + + aria_sl(&a, &b, &c, &d, aria_is1, aria_is2, aria_sb1, aria_sb2); + aria_a(&a, &b, &c, &d); + + r[0] = a ^ x[0]; + r[1] = b ^ x[1]; + r[2] = c ^ x[2]; + r[3] = d ^ x[3]; +} + +/* + * Big endian 128-bit rotation: r = a ^ (b <<< n), used only in key setup. + * + * We chose to store bytes into 32-bit words in little-endian format (see + * MBEDTLS_GET_UINT32_LE / MBEDTLS_PUT_UINT32_LE ) so we need to reverse + * bytes here. + */ +static void aria_rot128(uint32_t r[4], const uint32_t a[4], + const uint32_t b[4], uint8_t n) +{ + uint8_t i, j; + uint32_t t, u; + + const uint8_t n1 = n % 32; // bit offset + const uint8_t n2 = n1 ? 32 - n1 : 0; // reverse bit offset + + j = (n / 32) % 4; // initial word offset + t = ARIA_P3(b[j]); // big endian + for (i = 0; i < 4; i++) { + j = (j + 1) % 4; // get next word, big endian + u = ARIA_P3(b[j]); + t <<= n1; // rotate + t |= u >> n2; + t = ARIA_P3(t); // back to little endian + r[i] = a[i] ^ t; // store + t = u; // move to next word + } +} + +/* + * Set encryption key + */ +int mbedtls_aria_setkey_enc(mbedtls_aria_context *ctx, + const unsigned char *key, unsigned int keybits) +{ + /* round constant masks */ + const uint32_t rc[3][4] = + { + { 0xB7C17C51, 0x940A2227, 0xE8AB13FE, 0xE06E9AFA }, + { 0xCC4AB16D, 0x20C8219E, 0xD5B128FF, 0xB0E25DEF }, + { 0x1D3792DB, 0x70E92621, 0x75972403, 0x0EC9E804 } + }; + + int i; + uint32_t w[4][4], *w2; + + if (keybits != 128 && keybits != 192 && keybits != 256) { + return MBEDTLS_ERR_ARIA_BAD_INPUT_DATA; + } + + /* Copy key to W0 (and potential remainder to W1) */ + w[0][0] = MBEDTLS_GET_UINT32_LE(key, 0); + w[0][1] = MBEDTLS_GET_UINT32_LE(key, 4); + w[0][2] = MBEDTLS_GET_UINT32_LE(key, 8); + w[0][3] = MBEDTLS_GET_UINT32_LE(key, 12); + + memset(w[1], 0, 16); + if (keybits >= 192) { + w[1][0] = MBEDTLS_GET_UINT32_LE(key, 16); // 192 bit key + w[1][1] = MBEDTLS_GET_UINT32_LE(key, 20); + } + if (keybits == 256) { + w[1][2] = MBEDTLS_GET_UINT32_LE(key, 24); // 256 bit key + w[1][3] = MBEDTLS_GET_UINT32_LE(key, 28); + } + + i = (keybits - 128) >> 6; // index: 0, 1, 2 + ctx->nr = 12 + 2 * i; // no. rounds: 12, 14, 16 + + aria_fo_xor(w[1], w[0], rc[i], w[1]); // W1 = FO(W0, CK1) ^ KR + i = i < 2 ? i + 1 : 0; + aria_fe_xor(w[2], w[1], rc[i], w[0]); // W2 = FE(W1, CK2) ^ W0 + i = i < 2 ? i + 1 : 0; + aria_fo_xor(w[3], w[2], rc[i], w[1]); // W3 = FO(W2, CK3) ^ W1 + + for (i = 0; i < 4; i++) { // create round keys + w2 = w[(i + 1) & 3]; + aria_rot128(ctx->rk[i], w[i], w2, 128 - 19); + aria_rot128(ctx->rk[i + 4], w[i], w2, 128 - 31); + aria_rot128(ctx->rk[i + 8], w[i], w2, 61); + aria_rot128(ctx->rk[i + 12], w[i], w2, 31); + } + aria_rot128(ctx->rk[16], w[0], w[1], 19); + + /* w holds enough info to reconstruct the round keys */ + mbedtls_platform_zeroize(w, sizeof(w)); + + return 0; +} + +/* + * Set decryption key + */ +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +int mbedtls_aria_setkey_dec(mbedtls_aria_context *ctx, + const unsigned char *key, unsigned int keybits) +{ + int i, j, k, ret; + + ret = mbedtls_aria_setkey_enc(ctx, key, keybits); + if (ret != 0) { + return ret; + } + + /* flip the order of round keys */ + for (i = 0, j = ctx->nr; i < j; i++, j--) { + for (k = 0; k < 4; k++) { + uint32_t t = ctx->rk[i][k]; + ctx->rk[i][k] = ctx->rk[j][k]; + ctx->rk[j][k] = t; + } + } + + /* apply affine transform to middle keys */ + for (i = 1; i < ctx->nr; i++) { + aria_a(&ctx->rk[i][0], &ctx->rk[i][1], + &ctx->rk[i][2], &ctx->rk[i][3]); + } + + return 0; +} +#endif /* !MBEDTLS_BLOCK_CIPHER_NO_DECRYPT */ + +/* + * Encrypt a block + */ +int mbedtls_aria_crypt_ecb(mbedtls_aria_context *ctx, + const unsigned char input[MBEDTLS_ARIA_BLOCKSIZE], + unsigned char output[MBEDTLS_ARIA_BLOCKSIZE]) +{ + int i; + + uint32_t a, b, c, d; + + a = MBEDTLS_GET_UINT32_LE(input, 0); + b = MBEDTLS_GET_UINT32_LE(input, 4); + c = MBEDTLS_GET_UINT32_LE(input, 8); + d = MBEDTLS_GET_UINT32_LE(input, 12); + + i = 0; + while (1) { + a ^= ctx->rk[i][0]; + b ^= ctx->rk[i][1]; + c ^= ctx->rk[i][2]; + d ^= ctx->rk[i][3]; + i++; + + aria_sl(&a, &b, &c, &d, aria_sb1, aria_sb2, aria_is1, aria_is2); + aria_a(&a, &b, &c, &d); + + a ^= ctx->rk[i][0]; + b ^= ctx->rk[i][1]; + c ^= ctx->rk[i][2]; + d ^= ctx->rk[i][3]; + i++; + + aria_sl(&a, &b, &c, &d, aria_is1, aria_is2, aria_sb1, aria_sb2); + if (i >= ctx->nr) { + break; + } + aria_a(&a, &b, &c, &d); + } + + /* final key mixing */ + a ^= ctx->rk[i][0]; + b ^= ctx->rk[i][1]; + c ^= ctx->rk[i][2]; + d ^= ctx->rk[i][3]; + + MBEDTLS_PUT_UINT32_LE(a, output, 0); + MBEDTLS_PUT_UINT32_LE(b, output, 4); + MBEDTLS_PUT_UINT32_LE(c, output, 8); + MBEDTLS_PUT_UINT32_LE(d, output, 12); + + return 0; +} + +/* Initialize context */ +void mbedtls_aria_init(mbedtls_aria_context *ctx) +{ + memset(ctx, 0, sizeof(mbedtls_aria_context)); +} + +/* Clear context */ +void mbedtls_aria_free(mbedtls_aria_context *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_aria_context)); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * ARIA-CBC buffer encryption/decryption + */ +int mbedtls_aria_crypt_cbc(mbedtls_aria_context *ctx, + int mode, + size_t length, + unsigned char iv[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output) +{ + unsigned char temp[MBEDTLS_ARIA_BLOCKSIZE]; + + if ((mode != MBEDTLS_ARIA_ENCRYPT) && (mode != MBEDTLS_ARIA_DECRYPT)) { + return MBEDTLS_ERR_ARIA_BAD_INPUT_DATA; + } + + if (length % MBEDTLS_ARIA_BLOCKSIZE) { + return MBEDTLS_ERR_ARIA_INVALID_INPUT_LENGTH; + } + + if (mode == MBEDTLS_ARIA_DECRYPT) { + while (length > 0) { + memcpy(temp, input, MBEDTLS_ARIA_BLOCKSIZE); + mbedtls_aria_crypt_ecb(ctx, input, output); + + mbedtls_xor(output, output, iv, MBEDTLS_ARIA_BLOCKSIZE); + + memcpy(iv, temp, MBEDTLS_ARIA_BLOCKSIZE); + + input += MBEDTLS_ARIA_BLOCKSIZE; + output += MBEDTLS_ARIA_BLOCKSIZE; + length -= MBEDTLS_ARIA_BLOCKSIZE; + } + } else { + while (length > 0) { + mbedtls_xor(output, input, iv, MBEDTLS_ARIA_BLOCKSIZE); + + mbedtls_aria_crypt_ecb(ctx, output, output); + memcpy(iv, output, MBEDTLS_ARIA_BLOCKSIZE); + + input += MBEDTLS_ARIA_BLOCKSIZE; + output += MBEDTLS_ARIA_BLOCKSIZE; + length -= MBEDTLS_ARIA_BLOCKSIZE; + } + } + + return 0; +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * ARIA-CFB128 buffer encryption/decryption + */ +int mbedtls_aria_crypt_cfb128(mbedtls_aria_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output) +{ + unsigned char c; + size_t n; + + if ((mode != MBEDTLS_ARIA_ENCRYPT) && (mode != MBEDTLS_ARIA_DECRYPT)) { + return MBEDTLS_ERR_ARIA_BAD_INPUT_DATA; + } + + n = *iv_off; + + /* An overly large value of n can lead to an unlimited + * buffer overflow. */ + if (n >= MBEDTLS_ARIA_BLOCKSIZE) { + return MBEDTLS_ERR_ARIA_BAD_INPUT_DATA; + } + + if (mode == MBEDTLS_ARIA_DECRYPT) { + while (length--) { + if (n == 0) { + mbedtls_aria_crypt_ecb(ctx, iv, iv); + } + + c = *input++; + *output++ = c ^ iv[n]; + iv[n] = c; + + n = (n + 1) & 0x0F; + } + } else { + while (length--) { + if (n == 0) { + mbedtls_aria_crypt_ecb(ctx, iv, iv); + } + + iv[n] = *output++ = (unsigned char) (iv[n] ^ *input++); + + n = (n + 1) & 0x0F; + } + } + + *iv_off = n; + + return 0; +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * ARIA-CTR buffer encryption/decryption + */ +int mbedtls_aria_crypt_ctr(mbedtls_aria_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[MBEDTLS_ARIA_BLOCKSIZE], + unsigned char stream_block[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output) +{ + int c, i; + size_t n; + + n = *nc_off; + /* An overly large value of n can lead to an unlimited + * buffer overflow. */ + if (n >= MBEDTLS_ARIA_BLOCKSIZE) { + return MBEDTLS_ERR_ARIA_BAD_INPUT_DATA; + } + + while (length--) { + if (n == 0) { + mbedtls_aria_crypt_ecb(ctx, nonce_counter, + stream_block); + + for (i = MBEDTLS_ARIA_BLOCKSIZE; i > 0; i--) { + if (++nonce_counter[i - 1] != 0) { + break; + } + } + } + c = *input++; + *output++ = (unsigned char) (c ^ stream_block[n]); + + n = (n + 1) & 0x0F; + } + + *nc_off = n; + + return 0; +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_SELF_TEST) + +/* + * Basic ARIA ECB test vectors from RFC 5794 + */ +static const uint8_t aria_test1_ecb_key[32] = // test key +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 128 bit + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, // 192 bit + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F // 256 bit +}; + +static const uint8_t aria_test1_ecb_pt[MBEDTLS_ARIA_BLOCKSIZE] = // plaintext +{ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // same for all + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF // key sizes +}; + +static const uint8_t aria_test1_ecb_ct[3][MBEDTLS_ARIA_BLOCKSIZE] = // ciphertext +{ + { 0xD7, 0x18, 0xFB, 0xD6, 0xAB, 0x64, 0x4C, 0x73, // 128 bit + 0x9D, 0xA9, 0x5F, 0x3B, 0xE6, 0x45, 0x17, 0x78 }, + { 0x26, 0x44, 0x9C, 0x18, 0x05, 0xDB, 0xE7, 0xAA, // 192 bit + 0x25, 0xA4, 0x68, 0xCE, 0x26, 0x3A, 0x9E, 0x79 }, + { 0xF9, 0x2B, 0xD7, 0xC7, 0x9F, 0xB7, 0x2E, 0x2F, // 256 bit + 0x2B, 0x8F, 0x80, 0xC1, 0x97, 0x2D, 0x24, 0xFC } +}; + +/* + * Mode tests from "Test Vectors for ARIA" Version 1.0 + * http://210.104.33.10/ARIA/doc/ARIA-testvector-e.pdf + */ +#if (defined(MBEDTLS_CIPHER_MODE_CBC) || defined(MBEDTLS_CIPHER_MODE_CFB) || \ + defined(MBEDTLS_CIPHER_MODE_CTR)) +static const uint8_t aria_test2_key[32] = +{ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // 128 bit + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // 192 bit + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff // 256 bit +}; + +static const uint8_t aria_test2_pt[48] = +{ + 0x11, 0x11, 0x11, 0x11, 0xaa, 0xaa, 0xaa, 0xaa, // same for all + 0x11, 0x11, 0x11, 0x11, 0xbb, 0xbb, 0xbb, 0xbb, + 0x11, 0x11, 0x11, 0x11, 0xcc, 0xcc, 0xcc, 0xcc, + 0x11, 0x11, 0x11, 0x11, 0xdd, 0xdd, 0xdd, 0xdd, + 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, 0xaa, + 0x22, 0x22, 0x22, 0x22, 0xbb, 0xbb, 0xbb, 0xbb, +}; +#endif + +#if (defined(MBEDTLS_CIPHER_MODE_CBC) || defined(MBEDTLS_CIPHER_MODE_CFB)) +static const uint8_t aria_test2_iv[MBEDTLS_ARIA_BLOCKSIZE] = +{ + 0x0f, 0x1e, 0x2d, 0x3c, 0x4b, 0x5a, 0x69, 0x78, // same for CBC, CFB + 0x87, 0x96, 0xa5, 0xb4, 0xc3, 0xd2, 0xe1, 0xf0 // CTR has zero IV +}; +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const uint8_t aria_test2_cbc_ct[3][48] = // CBC ciphertext +{ + { 0x49, 0xd6, 0x18, 0x60, 0xb1, 0x49, 0x09, 0x10, // 128-bit key + 0x9c, 0xef, 0x0d, 0x22, 0xa9, 0x26, 0x81, 0x34, + 0xfa, 0xdf, 0x9f, 0xb2, 0x31, 0x51, 0xe9, 0x64, + 0x5f, 0xba, 0x75, 0x01, 0x8b, 0xdb, 0x15, 0x38, + 0xb5, 0x33, 0x34, 0x63, 0x4b, 0xbf, 0x7d, 0x4c, + 0xd4, 0xb5, 0x37, 0x70, 0x33, 0x06, 0x0c, 0x15 }, + { 0xaf, 0xe6, 0xcf, 0x23, 0x97, 0x4b, 0x53, 0x3c, // 192-bit key + 0x67, 0x2a, 0x82, 0x62, 0x64, 0xea, 0x78, 0x5f, + 0x4e, 0x4f, 0x7f, 0x78, 0x0d, 0xc7, 0xf3, 0xf1, + 0xe0, 0x96, 0x2b, 0x80, 0x90, 0x23, 0x86, 0xd5, + 0x14, 0xe9, 0xc3, 0xe7, 0x72, 0x59, 0xde, 0x92, + 0xdd, 0x11, 0x02, 0xff, 0xab, 0x08, 0x6c, 0x1e }, + { 0x52, 0x3a, 0x8a, 0x80, 0x6a, 0xe6, 0x21, 0xf1, // 256-bit key + 0x55, 0xfd, 0xd2, 0x8d, 0xbc, 0x34, 0xe1, 0xab, + 0x7b, 0x9b, 0x42, 0x43, 0x2a, 0xd8, 0xb2, 0xef, + 0xb9, 0x6e, 0x23, 0xb1, 0x3f, 0x0a, 0x6e, 0x52, + 0xf3, 0x61, 0x85, 0xd5, 0x0a, 0xd0, 0x02, 0xc5, + 0xf6, 0x01, 0xbe, 0xe5, 0x49, 0x3f, 0x11, 0x8b } +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const uint8_t aria_test2_cfb_ct[3][48] = // CFB ciphertext +{ + { 0x37, 0x20, 0xe5, 0x3b, 0xa7, 0xd6, 0x15, 0x38, // 128-bit key + 0x34, 0x06, 0xb0, 0x9f, 0x0a, 0x05, 0xa2, 0x00, + 0xc0, 0x7c, 0x21, 0xe6, 0x37, 0x0f, 0x41, 0x3a, + 0x5d, 0x13, 0x25, 0x00, 0xa6, 0x82, 0x85, 0x01, + 0x7c, 0x61, 0xb4, 0x34, 0xc7, 0xb7, 0xca, 0x96, + 0x85, 0xa5, 0x10, 0x71, 0x86, 0x1e, 0x4d, 0x4b }, + { 0x41, 0x71, 0xf7, 0x19, 0x2b, 0xf4, 0x49, 0x54, // 192-bit key + 0x94, 0xd2, 0x73, 0x61, 0x29, 0x64, 0x0f, 0x5c, + 0x4d, 0x87, 0xa9, 0xa2, 0x13, 0x66, 0x4c, 0x94, + 0x48, 0x47, 0x7c, 0x6e, 0xcc, 0x20, 0x13, 0x59, + 0x8d, 0x97, 0x66, 0x95, 0x2d, 0xd8, 0xc3, 0x86, + 0x8f, 0x17, 0xe3, 0x6e, 0xf6, 0x6f, 0xd8, 0x4b }, + { 0x26, 0x83, 0x47, 0x05, 0xb0, 0xf2, 0xc0, 0xe2, // 256-bit key + 0x58, 0x8d, 0x4a, 0x7f, 0x09, 0x00, 0x96, 0x35, + 0xf2, 0x8b, 0xb9, 0x3d, 0x8c, 0x31, 0xf8, 0x70, + 0xec, 0x1e, 0x0b, 0xdb, 0x08, 0x2b, 0x66, 0xfa, + 0x40, 0x2d, 0xd9, 0xc2, 0x02, 0xbe, 0x30, 0x0c, + 0x45, 0x17, 0xd1, 0x96, 0xb1, 0x4d, 0x4c, 0xe1 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const uint8_t aria_test2_ctr_ct[3][48] = // CTR ciphertext +{ + { 0xac, 0x5d, 0x7d, 0xe8, 0x05, 0xa0, 0xbf, 0x1c, // 128-bit key + 0x57, 0xc8, 0x54, 0x50, 0x1a, 0xf6, 0x0f, 0xa1, + 0x14, 0x97, 0xe2, 0xa3, 0x45, 0x19, 0xde, 0xa1, + 0x56, 0x9e, 0x91, 0xe5, 0xb5, 0xcc, 0xae, 0x2f, + 0xf3, 0xbf, 0xa1, 0xbf, 0x97, 0x5f, 0x45, 0x71, + 0xf4, 0x8b, 0xe1, 0x91, 0x61, 0x35, 0x46, 0xc3 }, + { 0x08, 0x62, 0x5c, 0xa8, 0xfe, 0x56, 0x9c, 0x19, // 192-bit key + 0xba, 0x7a, 0xf3, 0x76, 0x0a, 0x6e, 0xd1, 0xce, + 0xf4, 0xd1, 0x99, 0x26, 0x3e, 0x99, 0x9d, 0xde, + 0x14, 0x08, 0x2d, 0xbb, 0xa7, 0x56, 0x0b, 0x79, + 0xa4, 0xc6, 0xb4, 0x56, 0xb8, 0x70, 0x7d, 0xce, + 0x75, 0x1f, 0x98, 0x54, 0xf1, 0x88, 0x93, 0xdf }, + { 0x30, 0x02, 0x6c, 0x32, 0x96, 0x66, 0x14, 0x17, // 256-bit key + 0x21, 0x17, 0x8b, 0x99, 0xc0, 0xa1, 0xf1, 0xb2, + 0xf0, 0x69, 0x40, 0x25, 0x3f, 0x7b, 0x30, 0x89, + 0xe2, 0xa3, 0x0e, 0xa8, 0x6a, 0xa3, 0xc8, 0x8f, + 0x59, 0x40, 0xf0, 0x5a, 0xd7, 0xee, 0x41, 0xd7, + 0x13, 0x47, 0xbb, 0x72, 0x61, 0xe3, 0x48, 0xf1 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#define ARIA_SELF_TEST_ASSERT(cond) \ + do { \ + if (cond) { \ + if (verbose) \ + mbedtls_printf("failed\n"); \ + goto exit; \ + } else { \ + if (verbose) \ + mbedtls_printf("passed\n"); \ + } \ + } while (0) + +/* + * Checkup routine + */ +int mbedtls_aria_self_test(int verbose) +{ + int i; + uint8_t blk[MBEDTLS_ARIA_BLOCKSIZE]; + mbedtls_aria_context ctx; + int ret = 1; + +#if (defined(MBEDTLS_CIPHER_MODE_CFB) || defined(MBEDTLS_CIPHER_MODE_CTR)) + size_t j; +#endif + +#if (defined(MBEDTLS_CIPHER_MODE_CBC) || \ + defined(MBEDTLS_CIPHER_MODE_CFB) || \ + defined(MBEDTLS_CIPHER_MODE_CTR)) + uint8_t buf[48], iv[MBEDTLS_ARIA_BLOCKSIZE]; +#endif + + mbedtls_aria_init(&ctx); + + /* + * Test set 1 + */ + for (i = 0; i < 3; i++) { + /* test ECB encryption */ + if (verbose) { + mbedtls_printf(" ARIA-ECB-%d (enc): ", 128 + 64 * i); + } + mbedtls_aria_setkey_enc(&ctx, aria_test1_ecb_key, 128 + 64 * i); + mbedtls_aria_crypt_ecb(&ctx, aria_test1_ecb_pt, blk); + ARIA_SELF_TEST_ASSERT( + memcmp(blk, aria_test1_ecb_ct[i], MBEDTLS_ARIA_BLOCKSIZE) + != 0); + + /* test ECB decryption */ + if (verbose) { + mbedtls_printf(" ARIA-ECB-%d (dec): ", 128 + 64 * i); +#if defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + mbedtls_printf("skipped\n"); +#endif + } + +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + mbedtls_aria_setkey_dec(&ctx, aria_test1_ecb_key, 128 + 64 * i); + mbedtls_aria_crypt_ecb(&ctx, aria_test1_ecb_ct[i], blk); + ARIA_SELF_TEST_ASSERT( + memcmp(blk, aria_test1_ecb_pt, MBEDTLS_ARIA_BLOCKSIZE) + != 0); +#endif + } + if (verbose) { + mbedtls_printf("\n"); + } + + /* + * Test set 2 + */ +#if defined(MBEDTLS_CIPHER_MODE_CBC) + for (i = 0; i < 3; i++) { + /* Test CBC encryption */ + if (verbose) { + mbedtls_printf(" ARIA-CBC-%d (enc): ", 128 + 64 * i); + } + mbedtls_aria_setkey_enc(&ctx, aria_test2_key, 128 + 64 * i); + memcpy(iv, aria_test2_iv, MBEDTLS_ARIA_BLOCKSIZE); + memset(buf, 0x55, sizeof(buf)); + mbedtls_aria_crypt_cbc(&ctx, MBEDTLS_ARIA_ENCRYPT, 48, iv, + aria_test2_pt, buf); + ARIA_SELF_TEST_ASSERT(memcmp(buf, aria_test2_cbc_ct[i], 48) + != 0); + + /* Test CBC decryption */ + if (verbose) { + mbedtls_printf(" ARIA-CBC-%d (dec): ", 128 + 64 * i); + } + mbedtls_aria_setkey_dec(&ctx, aria_test2_key, 128 + 64 * i); + memcpy(iv, aria_test2_iv, MBEDTLS_ARIA_BLOCKSIZE); + memset(buf, 0xAA, sizeof(buf)); + mbedtls_aria_crypt_cbc(&ctx, MBEDTLS_ARIA_DECRYPT, 48, iv, + aria_test2_cbc_ct[i], buf); + ARIA_SELF_TEST_ASSERT(memcmp(buf, aria_test2_pt, 48) != 0); + } + if (verbose) { + mbedtls_printf("\n"); + } + +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + for (i = 0; i < 3; i++) { + /* Test CFB encryption */ + if (verbose) { + mbedtls_printf(" ARIA-CFB-%d (enc): ", 128 + 64 * i); + } + mbedtls_aria_setkey_enc(&ctx, aria_test2_key, 128 + 64 * i); + memcpy(iv, aria_test2_iv, MBEDTLS_ARIA_BLOCKSIZE); + memset(buf, 0x55, sizeof(buf)); + j = 0; + mbedtls_aria_crypt_cfb128(&ctx, MBEDTLS_ARIA_ENCRYPT, 48, &j, iv, + aria_test2_pt, buf); + ARIA_SELF_TEST_ASSERT(memcmp(buf, aria_test2_cfb_ct[i], 48) != 0); + + /* Test CFB decryption */ + if (verbose) { + mbedtls_printf(" ARIA-CFB-%d (dec): ", 128 + 64 * i); + } + mbedtls_aria_setkey_enc(&ctx, aria_test2_key, 128 + 64 * i); + memcpy(iv, aria_test2_iv, MBEDTLS_ARIA_BLOCKSIZE); + memset(buf, 0xAA, sizeof(buf)); + j = 0; + mbedtls_aria_crypt_cfb128(&ctx, MBEDTLS_ARIA_DECRYPT, 48, &j, + iv, aria_test2_cfb_ct[i], buf); + ARIA_SELF_TEST_ASSERT(memcmp(buf, aria_test2_pt, 48) != 0); + } + if (verbose) { + mbedtls_printf("\n"); + } +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + for (i = 0; i < 3; i++) { + /* Test CTR encryption */ + if (verbose) { + mbedtls_printf(" ARIA-CTR-%d (enc): ", 128 + 64 * i); + } + mbedtls_aria_setkey_enc(&ctx, aria_test2_key, 128 + 64 * i); + memset(iv, 0, MBEDTLS_ARIA_BLOCKSIZE); // IV = 0 + memset(buf, 0x55, sizeof(buf)); + j = 0; + mbedtls_aria_crypt_ctr(&ctx, 48, &j, iv, blk, + aria_test2_pt, buf); + ARIA_SELF_TEST_ASSERT(memcmp(buf, aria_test2_ctr_ct[i], 48) != 0); + + /* Test CTR decryption */ + if (verbose) { + mbedtls_printf(" ARIA-CTR-%d (dec): ", 128 + 64 * i); + } + mbedtls_aria_setkey_enc(&ctx, aria_test2_key, 128 + 64 * i); + memset(iv, 0, MBEDTLS_ARIA_BLOCKSIZE); // IV = 0 + memset(buf, 0xAA, sizeof(buf)); + j = 0; + mbedtls_aria_crypt_ctr(&ctx, 48, &j, iv, blk, + aria_test2_ctr_ct[i], buf); + ARIA_SELF_TEST_ASSERT(memcmp(buf, aria_test2_pt, 48) != 0); + } + if (verbose) { + mbedtls_printf("\n"); + } +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + + ret = 0; + +exit: + mbedtls_aria_free(&ctx); + return ret; +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ARIA_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/bignum.c b/tf-psa-crypto/drivers/builtin/src/bignum.c new file mode 100644 index 0000000000..825741e8df --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/bignum.c @@ -0,0 +1,2647 @@ +/* + * Multi-precision integer library + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +/* + * The following sources were referenced in the design of this Multi-precision + * Integer library: + * + * [1] Handbook of Applied Cryptography - 1997 + * Menezes, van Oorschot and Vanstone + * + * [2] Multi-Precision Math + * Tom St Denis + * https://github.com/libtom/libtommath/blob/develop/tommath.pdf + * + * [3] GNU Multi-Precision Arithmetic Library + * https://gmplib.org/manual/index.html + * + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_BIGNUM_C) + +#include "mbedtls/private/bignum.h" +#include "mbedtls/bignum.h" +#include "bignum_core.h" +#include "bignum_internal.h" +#include "bn_mul.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" +#include "constant_time_internal.h" + +#include +#include + +#include "mbedtls/platform.h" + +#if !defined(MBEDTLS_BIGNUM_ALT) + +/* + * Conditionally select an MPI sign in constant time. + * (MPI sign is the field s in mbedtls_mpi. It is unsigned short and only 1 and -1 are valid + * values.) + */ +static inline signed short mbedtls_ct_mpi_sign_if(mbedtls_ct_condition_t cond, + signed short sign1, signed short sign2) +{ + return (signed short) mbedtls_ct_uint_if(cond, sign1 + 1, sign2 + 1) - 1; +} + +/* + * Compare signed values in constant time + */ +int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X, + const mbedtls_mpi *Y, + unsigned *ret) +{ + mbedtls_ct_condition_t different_sign, X_is_negative, Y_is_negative, result; + + if (X->n != Y->n) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + /* + * Set N_is_negative to MBEDTLS_CT_FALSE if N >= 0, MBEDTLS_CT_TRUE if N < 0. + * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0. + */ + X_is_negative = mbedtls_ct_bool((X->s & 2) >> 1); + Y_is_negative = mbedtls_ct_bool((Y->s & 2) >> 1); + + /* + * If the signs are different, then the positive operand is the bigger. + * That is if X is negative (X_is_negative == 1), then X < Y is true and it + * is false if X is positive (X_is_negative == 0). + */ + different_sign = mbedtls_ct_bool_ne(X_is_negative, Y_is_negative); // true if different sign + result = mbedtls_ct_bool_and(different_sign, X_is_negative); + + /* + * Assuming signs are the same, compare X and Y. We switch the comparison + * order if they are negative so that we get the right result, regardles of + * sign. + */ + + /* This array is used to conditionally swap the pointers in const time */ + void * const p[2] = { X->p, Y->p }; + size_t i = mbedtls_ct_size_if_else_0(X_is_negative, 1); + mbedtls_ct_condition_t lt = mbedtls_mpi_core_lt_ct(p[i], p[i ^ 1], X->n); + + /* + * Store in result iff the signs are the same (i.e., iff different_sign == false). If + * the signs differ, result has already been set, so we don't change it. + */ + result = mbedtls_ct_bool_or(result, + mbedtls_ct_bool_and(mbedtls_ct_bool_not(different_sign), lt)); + + *ret = mbedtls_ct_uint_if_else_0(result, 1); + + return 0; +} + +/* + * Conditionally assign X = Y, without leaking information + * about whether the assignment was made or not. + * (Leaking information about the respective sizes of X and Y is ok however.) + */ +#if defined(_MSC_VER) && defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64) && \ + (_MSC_FULL_VER < 193131103) +/* + * MSVC miscompiles this function if it's inlined prior to Visual Studio 2022 version 17.1. See: + * https://developercommunity.visualstudio.com/t/c-compiler-miscompiles-part-of-mbedtls-library-on/1646989 + */ +__declspec(noinline) +#endif +int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X, + const mbedtls_mpi *Y, + unsigned char assign) +{ + int ret = 0; + + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n)); + + { + mbedtls_ct_condition_t do_assign = mbedtls_ct_bool(assign); + + X->s = mbedtls_ct_mpi_sign_if(do_assign, Y->s, X->s); + + mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, do_assign); + + mbedtls_ct_condition_t do_not_assign = mbedtls_ct_bool_not(do_assign); + for (size_t i = Y->n; i < X->n; i++) { + X->p[i] = mbedtls_ct_mpi_uint_if_else_0(do_not_assign, X->p[i]); + } + } + +cleanup: + return ret; +} + +/* + * Conditionally swap X and Y, without leaking information + * about whether the swap was made or not. + * Here it is not ok to simply swap the pointers, which would lead to + * different memory access patterns when X and Y are used afterwards. + */ +int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X, + mbedtls_mpi *Y, + unsigned char swap) +{ + int ret = 0; + int s; + + if (X == Y) { + return 0; + } + + mbedtls_ct_condition_t do_swap = mbedtls_ct_bool(swap); + + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n)); + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n)); + + s = X->s; + X->s = mbedtls_ct_mpi_sign_if(do_swap, Y->s, X->s); + Y->s = mbedtls_ct_mpi_sign_if(do_swap, s, Y->s); + + mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, do_swap); + +cleanup: + return ret; +} + +/* Implementation that should never be optimized out by the compiler */ +#define mbedtls_mpi_zeroize_and_free(v, n) mbedtls_zeroize_and_free(v, ciL * (n)) + +/* + * Initialize one MPI + */ +void mbedtls_mpi_init(mbedtls_mpi *X) +{ + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Unallocate one MPI + */ +void mbedtls_mpi_free(mbedtls_mpi *X) +{ + if (X == NULL) { + return; + } + + if (X->p != NULL) { + mbedtls_mpi_zeroize_and_free(X->p, X->n); + } + + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Enlarge to the specified number of limbs + */ +int mbedtls_mpi_grow(mbedtls_mpi *X, size_t nblimbs) +{ + mbedtls_mpi_uint *p; + + if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) { + return MBEDTLS_ERR_MPI_ALLOC_FAILED; + } + + if (X->n < nblimbs) { + if ((p = (mbedtls_mpi_uint *) mbedtls_calloc(nblimbs, ciL)) == NULL) { + return MBEDTLS_ERR_MPI_ALLOC_FAILED; + } + + if (X->p != NULL) { + memcpy(p, X->p, X->n * ciL); + mbedtls_mpi_zeroize_and_free(X->p, X->n); + } + + /* nblimbs fits in n because we ensure that MBEDTLS_MPI_MAX_LIMBS + * fits, and we've checked that nblimbs <= MBEDTLS_MPI_MAX_LIMBS. */ + X->n = (unsigned short) nblimbs; + X->p = p; + } + + return 0; +} + +/* + * Resize down as much as possible, + * while keeping at least the specified number of limbs + */ +int mbedtls_mpi_shrink(mbedtls_mpi *X, size_t nblimbs) +{ + mbedtls_mpi_uint *p; + size_t i; + + if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) { + return MBEDTLS_ERR_MPI_ALLOC_FAILED; + } + + /* Actually resize up if there are currently fewer than nblimbs limbs. */ + if (X->n <= nblimbs) { + return mbedtls_mpi_grow(X, nblimbs); + } + /* After this point, then X->n > nblimbs and in particular X->n > 0. */ + + for (i = X->n - 1; i > 0; i--) { + if (X->p[i] != 0) { + break; + } + } + i++; + + if (i < nblimbs) { + i = nblimbs; + } + + if ((p = (mbedtls_mpi_uint *) mbedtls_calloc(i, ciL)) == NULL) { + return MBEDTLS_ERR_MPI_ALLOC_FAILED; + } + + if (X->p != NULL) { + memcpy(p, X->p, i * ciL); + mbedtls_mpi_zeroize_and_free(X->p, X->n); + } + + /* i fits in n because we ensure that MBEDTLS_MPI_MAX_LIMBS + * fits, and we've checked that i <= nblimbs <= MBEDTLS_MPI_MAX_LIMBS. */ + X->n = (unsigned short) i; + X->p = p; + + return 0; +} + +/* Resize X to have exactly n limbs and set it to 0. */ +static int mbedtls_mpi_resize_clear(mbedtls_mpi *X, size_t limbs) +{ + if (limbs == 0) { + mbedtls_mpi_free(X); + return 0; + } else if (X->n == limbs) { + memset(X->p, 0, limbs * ciL); + X->s = 1; + return 0; + } else { + mbedtls_mpi_free(X); + return mbedtls_mpi_grow(X, limbs); + } +} + +/* + * Copy the contents of Y into X. + * + * This function is not constant-time. Leading zeros in Y may be removed. + * + * Ensure that X does not shrink. This is not guaranteed by the public API, + * but some code in the bignum module might still rely on this property. + */ +int mbedtls_mpi_copy(mbedtls_mpi *X, const mbedtls_mpi *Y) +{ + int ret = 0; + size_t i; + + if (X == Y) { + return 0; + } + + if (Y->n == 0) { + if (X->n != 0) { + X->s = 1; + memset(X->p, 0, X->n * ciL); + } + return 0; + } + + for (i = Y->n - 1; i > 0; i--) { + if (Y->p[i] != 0) { + break; + } + } + i++; + + X->s = Y->s; + + if (X->n < i) { + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i)); + } else { + memset(X->p + i, 0, (X->n - i) * ciL); + } + + memcpy(X->p, Y->p, i * ciL); + +cleanup: + + return ret; +} + +/* + * Swap the contents of X and Y + */ +void mbedtls_mpi_swap(mbedtls_mpi *X, mbedtls_mpi *Y) +{ + mbedtls_mpi T; + + memcpy(&T, X, sizeof(mbedtls_mpi)); + memcpy(X, Y, sizeof(mbedtls_mpi)); + memcpy(Y, &T, sizeof(mbedtls_mpi)); +} + +static inline mbedtls_mpi_uint mpi_sint_abs(mbedtls_mpi_sint z) +{ + if (z >= 0) { + return z; + } + /* Take care to handle the most negative value (-2^(biL-1)) correctly. + * A naive -z would have undefined behavior. + * Write this in a way that makes popular compilers happy (GCC, Clang, + * MSVC). */ + return (mbedtls_mpi_uint) 0 - (mbedtls_mpi_uint) z; +} + +/* Convert x to a sign, i.e. to 1, if x is positive, or -1, if x is negative. + * This looks awkward but generates smaller code than (x < 0 ? -1 : 1) */ +#define TO_SIGN(x) ((mbedtls_mpi_sint) (((mbedtls_mpi_uint) x) >> (biL - 1)) * -2 + 1) + +/* + * Set value from integer + */ +int mbedtls_mpi_lset(mbedtls_mpi *X, mbedtls_mpi_sint z) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, 1)); + memset(X->p, 0, X->n * ciL); + + X->p[0] = mpi_sint_abs(z); + X->s = TO_SIGN(z); + +cleanup: + + return ret; +} + +/* + * Get a specific bit + */ +int mbedtls_mpi_get_bit(const mbedtls_mpi *X, size_t pos) +{ + if (X->n * biL <= pos) { + return 0; + } + + return (X->p[pos / biL] >> (pos % biL)) & 0x01; +} + +/* + * Set a bit to a specific value of 0 or 1 + */ +int mbedtls_mpi_set_bit(mbedtls_mpi *X, size_t pos, unsigned char val) +{ + int ret = 0; + size_t off = pos / biL; + size_t idx = pos % biL; + + if (val != 0 && val != 1) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + if (X->n * biL <= pos) { + if (val == 0) { + return 0; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, off + 1)); + } + + X->p[off] &= ~((mbedtls_mpi_uint) 0x01 << idx); + X->p[off] |= (mbedtls_mpi_uint) val << idx; + +cleanup: + + return ret; +} + +#if defined(__has_builtin) +#if (MBEDTLS_MPI_UINT_MAX == UINT_MAX) && __has_builtin(__builtin_ctz) + #define mbedtls_mpi_uint_ctz __builtin_ctz +#elif (MBEDTLS_MPI_UINT_MAX == ULONG_MAX) && __has_builtin(__builtin_ctzl) + #define mbedtls_mpi_uint_ctz __builtin_ctzl +#elif (MBEDTLS_MPI_UINT_MAX == ULLONG_MAX) && __has_builtin(__builtin_ctzll) + #define mbedtls_mpi_uint_ctz __builtin_ctzll +#endif +#endif + +#if !defined(mbedtls_mpi_uint_ctz) +static size_t mbedtls_mpi_uint_ctz(mbedtls_mpi_uint x) +{ + size_t count = 0; + mbedtls_ct_condition_t done = MBEDTLS_CT_FALSE; + + for (size_t i = 0; i < biL; i++) { + mbedtls_ct_condition_t non_zero = mbedtls_ct_bool((x >> i) & 1); + done = mbedtls_ct_bool_or(done, non_zero); + count = mbedtls_ct_size_if(done, count, i + 1); + } + + return count; +} +#endif + +/* + * Return the number of less significant zero-bits + */ +size_t mbedtls_mpi_lsb(const mbedtls_mpi *X) +{ + size_t i; + + for (i = 0; i < X->n; i++) { + if (X->p[i] != 0) { + return i * biL + mbedtls_mpi_uint_ctz(X->p[i]); + } + } + + return 0; +} + +/* + * Return the number of bits + */ +size_t mbedtls_mpi_bitlen(const mbedtls_mpi *X) +{ + return mbedtls_mpi_core_bitlen(X->p, X->n); +} + +/* + * Return the total size in bytes + */ +size_t mbedtls_mpi_size(const mbedtls_mpi *X) +{ + return (mbedtls_mpi_bitlen(X) + 7) >> 3; +} + +/* + * Convert an ASCII character to digit value + */ +static int mpi_get_digit(mbedtls_mpi_uint *d, int radix, char c) +{ + *d = 255; + + if (c >= 0x30 && c <= 0x39) { + *d = c - 0x30; + } + if (c >= 0x41 && c <= 0x46) { + *d = c - 0x37; + } + if (c >= 0x61 && c <= 0x66) { + *d = c - 0x57; + } + + if (*d >= (mbedtls_mpi_uint) radix) { + return MBEDTLS_ERR_MPI_INVALID_CHARACTER; + } + + return 0; +} + +/* + * Import from an ASCII string + */ +int mbedtls_mpi_read_string(mbedtls_mpi *X, int radix, const char *s) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t i, j, slen, n; + int sign = 1; + mbedtls_mpi_uint d; + mbedtls_mpi T; + + if (radix < 2 || radix > 16) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + mbedtls_mpi_init(&T); + + if (s[0] == 0) { + mbedtls_mpi_free(X); + return 0; + } + + if (s[0] == '-') { + ++s; + sign = -1; + } + + slen = strlen(s); + + if (radix == 16) { + if (slen > SIZE_MAX >> 2) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + n = BITS_TO_LIMBS(slen << 2); + + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n)); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0)); + + for (i = slen, j = 0; i > 0; i--, j++) { + MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i - 1])); + X->p[j / (2 * ciL)] |= d << ((j % (2 * ciL)) << 2); + } + } else { + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0)); + + for (i = 0; i < slen; i++) { + MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i])); + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T, X, radix)); + MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, &T, d)); + } + } + + if (sign < 0 && mbedtls_mpi_bitlen(X) != 0) { + X->s = -1; + } + +cleanup: + + mbedtls_mpi_free(&T); + + return ret; +} + +/* + * Helper to write the digits high-order first. + */ +static int mpi_write_hlp(mbedtls_mpi *X, int radix, + char **p, const size_t buflen) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi_uint r; + size_t length = 0; + char *p_end = *p + buflen; + + do { + if (length >= buflen) { + return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, radix)); + MBEDTLS_MPI_CHK(mbedtls_mpi_div_int(X, NULL, X, radix)); + /* + * Write the residue in the current position, as an ASCII character. + */ + if (r < 0xA) { + *(--p_end) = (char) ('0' + r); + } else { + *(--p_end) = (char) ('A' + (r - 0xA)); + } + + length++; + } while (mbedtls_mpi_cmp_int(X, 0) != 0); + + memmove(*p, p_end, length); + *p += length; + +cleanup: + + return ret; +} + +/* + * Export into an ASCII string + */ +int mbedtls_mpi_write_string(const mbedtls_mpi *X, int radix, + char *buf, size_t buflen, size_t *olen) +{ + int ret = 0; + size_t n; + char *p; + mbedtls_mpi T; + + if (radix < 2 || radix > 16) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + n = mbedtls_mpi_bitlen(X); /* Number of bits necessary to present `n`. */ + if (radix >= 4) { + n >>= 1; /* Number of 4-adic digits necessary to present + * `n`. If radix > 4, this might be a strict + * overapproximation of the number of + * radix-adic digits needed to present `n`. */ + } + if (radix >= 16) { + n >>= 1; /* Number of hexadecimal digits necessary to + * present `n`. */ + + } + n += 1; /* Terminating null byte */ + n += 1; /* Compensate for the divisions above, which round down `n` + * in case it's not even. */ + n += 1; /* Potential '-'-sign. */ + n += (n & 1); /* Make n even to have enough space for hexadecimal writing, + * which always uses an even number of hex-digits. */ + + if (buflen < n) { + *olen = n; + return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL; + } + + p = buf; + mbedtls_mpi_init(&T); + + if (X->s == -1) { + *p++ = '-'; + buflen--; + } + + if (radix == 16) { + int c; + size_t i, j, k; + + for (i = X->n, k = 0; i > 0; i--) { + for (j = ciL; j > 0; j--) { + c = (X->p[i - 1] >> ((j - 1) << 3)) & 0xFF; + + if (c == 0 && k == 0 && (i + j) != 2) { + continue; + } + + *(p++) = "0123456789ABCDEF" [c / 16]; + *(p++) = "0123456789ABCDEF" [c % 16]; + k = 1; + } + } + } else { + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T, X)); + + if (T.s == -1) { + T.s = 1; + } + + MBEDTLS_MPI_CHK(mpi_write_hlp(&T, radix, &p, buflen)); + } + + *p++ = '\0'; + *olen = (size_t) (p - buf); + +cleanup: + + mbedtls_mpi_free(&T); + + return ret; +} + +#if defined(MBEDTLS_FS_IO) +/* + * Read X from an opened file + */ +int mbedtls_mpi_read_file(mbedtls_mpi *X, int radix, FILE *fin) +{ + mbedtls_mpi_uint d; + size_t slen; + char *p; + /* + * Buffer should have space for (short) label and decimal formatted MPI, + * newline characters and '\0' + */ + char s[MBEDTLS_MPI_RW_BUFFER_SIZE]; + + if (radix < 2 || radix > 16) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + memset(s, 0, sizeof(s)); + if (fgets(s, sizeof(s) - 1, fin) == NULL) { + return MBEDTLS_ERR_MPI_FILE_IO_ERROR; + } + + slen = strlen(s); + if (slen == sizeof(s) - 2) { + return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL; + } + + if (slen > 0 && s[slen - 1] == '\n') { + slen--; s[slen] = '\0'; + } + if (slen > 0 && s[slen - 1] == '\r') { + slen--; s[slen] = '\0'; + } + + p = s + slen; + while (p-- > s) { + if (mpi_get_digit(&d, radix, *p) != 0) { + break; + } + } + + return mbedtls_mpi_read_string(X, radix, p + 1); +} + +/* + * Write X into an opened file (or stdout if fout == NULL) + */ +int mbedtls_mpi_write_file(const char *p, const mbedtls_mpi *X, int radix, FILE *fout) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t n, slen, plen; + /* + * Buffer should have space for (short) label and decimal formatted MPI, + * newline characters and '\0' + */ + char s[MBEDTLS_MPI_RW_BUFFER_SIZE]; + + if (radix < 2 || radix > 16) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + memset(s, 0, sizeof(s)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_write_string(X, radix, s, sizeof(s) - 2, &n)); + + if (p == NULL) { + p = ""; + } + + plen = strlen(p); + slen = strlen(s); + s[slen++] = '\r'; + s[slen++] = '\n'; + + if (fout != NULL) { + if (fwrite(p, 1, plen, fout) != plen || + fwrite(s, 1, slen, fout) != slen) { + return MBEDTLS_ERR_MPI_FILE_IO_ERROR; + } + } else { + mbedtls_printf("%s%s", p, s); + } + +cleanup: + + return ret; +} +#endif /* MBEDTLS_FS_IO */ + +/* + * Import X from unsigned binary data, little endian + * + * This function is guaranteed to return an MPI with exactly the necessary + * number of limbs (in particular, it does not skip 0s in the input). + */ +int mbedtls_mpi_read_binary_le(mbedtls_mpi *X, + const unsigned char *buf, size_t buflen) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + const size_t limbs = CHARS_TO_LIMBS(buflen); + + /* Ensure that target MPI has exactly the necessary number of limbs */ + MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_le(X->p, X->n, buf, buflen)); + +cleanup: + + /* + * This function is also used to import keys. However, wiping the buffers + * upon failure is not necessary because failure only can happen before any + * input is copied. + */ + return ret; +} + +/* + * Import X from unsigned binary data, big endian + * + * This function is guaranteed to return an MPI with exactly the necessary + * number of limbs (in particular, it does not skip 0s in the input). + */ +int mbedtls_mpi_read_binary(mbedtls_mpi *X, const unsigned char *buf, size_t buflen) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + const size_t limbs = CHARS_TO_LIMBS(buflen); + + /* Ensure that target MPI has exactly the necessary number of limbs */ + MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_be(X->p, X->n, buf, buflen)); + +cleanup: + + /* + * This function is also used to import keys. However, wiping the buffers + * upon failure is not necessary because failure only can happen before any + * input is copied. + */ + return ret; +} + +/* + * Export X into unsigned binary data, little endian + */ +int mbedtls_mpi_write_binary_le(const mbedtls_mpi *X, + unsigned char *buf, size_t buflen) +{ + return mbedtls_mpi_core_write_le(X->p, X->n, buf, buflen); +} + +/* + * Export X into unsigned binary data, big endian + */ +int mbedtls_mpi_write_binary(const mbedtls_mpi *X, + unsigned char *buf, size_t buflen) +{ + return mbedtls_mpi_core_write_be(X->p, X->n, buf, buflen); +} + +/* + * Left-shift: X <<= count + */ +int mbedtls_mpi_shift_l(mbedtls_mpi *X, size_t count) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t i; + + i = mbedtls_mpi_bitlen(X) + count; + + if (X->n * biL < i) { + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, BITS_TO_LIMBS(i))); + } + + ret = 0; + + mbedtls_mpi_core_shift_l(X->p, X->n, count); +cleanup: + + return ret; +} + +/* + * Right-shift: X >>= count + */ +int mbedtls_mpi_shift_r(mbedtls_mpi *X, size_t count) +{ + if (X->n != 0) { + mbedtls_mpi_core_shift_r(X->p, X->n, count); + } + return 0; +} + +/* + * Compare unsigned values + */ +int mbedtls_mpi_cmp_abs(const mbedtls_mpi *X, const mbedtls_mpi *Y) +{ + size_t i, j; + + for (i = X->n; i > 0; i--) { + if (X->p[i - 1] != 0) { + break; + } + } + + for (j = Y->n; j > 0; j--) { + if (Y->p[j - 1] != 0) { + break; + } + } + + /* If i == j == 0, i.e. abs(X) == abs(Y), + * we end up returning 0 at the end of the function. */ + + if (i > j) { + return 1; + } + if (j > i) { + return -1; + } + + for (; i > 0; i--) { + if (X->p[i - 1] > Y->p[i - 1]) { + return 1; + } + if (X->p[i - 1] < Y->p[i - 1]) { + return -1; + } + } + + return 0; +} + +/* + * Compare signed values + */ +int mbedtls_mpi_cmp_mpi(const mbedtls_mpi *X, const mbedtls_mpi *Y) +{ + size_t i, j; + + for (i = X->n; i > 0; i--) { + if (X->p[i - 1] != 0) { + break; + } + } + + for (j = Y->n; j > 0; j--) { + if (Y->p[j - 1] != 0) { + break; + } + } + + if (i == 0 && j == 0) { + return 0; + } + + if (i > j) { + return X->s; + } + if (j > i) { + return -Y->s; + } + + if (X->s > 0 && Y->s < 0) { + return 1; + } + if (Y->s > 0 && X->s < 0) { + return -1; + } + + for (; i > 0; i--) { + if (X->p[i - 1] > Y->p[i - 1]) { + return X->s; + } + if (X->p[i - 1] < Y->p[i - 1]) { + return -X->s; + } + } + + return 0; +} + +/* + * Compare signed values + */ +int mbedtls_mpi_cmp_int(const mbedtls_mpi *X, mbedtls_mpi_sint z) +{ + mbedtls_mpi Y; + mbedtls_mpi_uint p[1]; + + *p = mpi_sint_abs(z); + Y.s = TO_SIGN(z); + Y.n = 1; + Y.p = p; + + return mbedtls_mpi_cmp_mpi(X, &Y); +} + +/* + * Unsigned addition: X = |A| + |B| (HAC 14.7) + */ +int mbedtls_mpi_add_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t j; + mbedtls_mpi_uint *p; + mbedtls_mpi_uint c; + + if (X == B) { + const mbedtls_mpi *T = A; A = X; B = T; + } + + if (X != A) { + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A)); + } + + /* + * X must always be positive as a result of unsigned additions. + */ + X->s = 1; + + for (j = B->n; j > 0; j--) { + if (B->p[j - 1] != 0) { + break; + } + } + + /* Exit early to avoid undefined behavior on NULL+0 when X->n == 0 + * and B is 0 (of any size). */ + if (j == 0) { + return 0; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j)); + + /* j is the number of non-zero limbs of B. Add those to X. */ + + p = X->p; + + c = mbedtls_mpi_core_add(p, p, B->p, j); + + p += j; + + /* Now propagate any carry */ + + while (c != 0) { + if (j >= X->n) { + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j + 1)); + p = X->p + j; + } + + *p += c; c = (*p < c); j++; p++; + } + +cleanup: + + return ret; +} + +/* + * Unsigned subtraction: X = |A| - |B| (HAC 14.9, 14.10) + */ +int mbedtls_mpi_sub_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t n; + mbedtls_mpi_uint carry; + + for (n = B->n; n > 0; n--) { + if (B->p[n - 1] != 0) { + break; + } + } + if (n > A->n) { + /* B >= (2^ciL)^n > A */ + ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE; + goto cleanup; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, A->n)); + + /* Set the high limbs of X to match A. Don't touch the lower limbs + * because X might be aliased to B, and we must not overwrite the + * significant digits of B. */ + if (A->n > n && A != X) { + memcpy(X->p + n, A->p + n, (A->n - n) * ciL); + } + if (X->n > A->n) { + memset(X->p + A->n, 0, (X->n - A->n) * ciL); + } + + carry = mbedtls_mpi_core_sub(X->p, A->p, B->p, n); + if (carry != 0) { + /* Propagate the carry through the rest of X. */ + carry = mbedtls_mpi_core_sub_int(X->p + n, X->p + n, carry, X->n - n); + + /* If we have further carry/borrow, the result is negative. */ + if (carry != 0) { + ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE; + goto cleanup; + } + } + + /* X should always be positive as a result of unsigned subtractions. */ + X->s = 1; + +cleanup: + return ret; +} + +/* Common function for signed addition and subtraction. + * Calculate A + B * flip_B where flip_B is 1 or -1. + */ +static int add_sub_mpi(mbedtls_mpi *X, + const mbedtls_mpi *A, const mbedtls_mpi *B, + int flip_B) +{ + int ret, s; + + s = A->s; + if (A->s * B->s * flip_B < 0) { + int cmp = mbedtls_mpi_cmp_abs(A, B); + if (cmp >= 0) { + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, A, B)); + /* If |A| = |B|, the result is 0 and we must set the sign bit + * to +1 regardless of which of A or B was negative. Otherwise, + * since |A| > |B|, the sign is the sign of A. */ + X->s = cmp == 0 ? 1 : s; + } else { + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, B, A)); + /* Since |A| < |B|, the sign is the opposite of A. */ + X->s = -s; + } + } else { + MBEDTLS_MPI_CHK(mbedtls_mpi_add_abs(X, A, B)); + X->s = s; + } + +cleanup: + + return ret; +} + +/* + * Signed addition: X = A + B + */ +int mbedtls_mpi_add_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B) +{ + return add_sub_mpi(X, A, B, 1); +} + +/* + * Signed subtraction: X = A - B + */ +int mbedtls_mpi_sub_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B) +{ + return add_sub_mpi(X, A, B, -1); +} + +/* + * Signed addition: X = A + b + */ +int mbedtls_mpi_add_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b) +{ + mbedtls_mpi B; + mbedtls_mpi_uint p[1]; + + p[0] = mpi_sint_abs(b); + B.s = TO_SIGN(b); + B.n = 1; + B.p = p; + + return mbedtls_mpi_add_mpi(X, A, &B); +} + +/* + * Signed subtraction: X = A - b + */ +int mbedtls_mpi_sub_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b) +{ + mbedtls_mpi B; + mbedtls_mpi_uint p[1]; + + p[0] = mpi_sint_abs(b); + B.s = TO_SIGN(b); + B.n = 1; + B.p = p; + + return mbedtls_mpi_sub_mpi(X, A, &B); +} + +#if !defined(MBEDTLS_MPI_MUL_MPI_ALT) + +/* + * Baseline multiplication: X = A * B (HAC 14.12) + */ +int mbedtls_mpi_mul_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t i, j; + mbedtls_mpi TA, TB; + int result_is_zero = 0; + + mbedtls_mpi_init(&TA); + mbedtls_mpi_init(&TB); + + if (X == A) { + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A)); A = &TA; + } + if (X == B) { + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B)); B = &TB; + } + + for (i = A->n; i > 0; i--) { + if (A->p[i - 1] != 0) { + break; + } + } + if (i == 0) { + result_is_zero = 1; + } + + for (j = B->n; j > 0; j--) { + if (B->p[j - 1] != 0) { + break; + } + } + if (j == 0) { + result_is_zero = 1; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i + j)); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0)); + + mbedtls_mpi_core_mul(X->p, A->p, i, B->p, j); + + /* If the result is 0, we don't shortcut the operation, which reduces + * but does not eliminate side channels leaking the zero-ness. We do + * need to take care to set the sign bit properly since the library does + * not fully support an MPI object with a value of 0 and s == -1. */ + if (result_is_zero) { + X->s = 1; + } else { + X->s = A->s * B->s; + } + +cleanup: + + mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TA); + + return ret; +} + +/* + * Baseline multiplication: X = A * b + */ +int mbedtls_mpi_mul_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b) +{ + size_t n = A->n; + while (n > 0 && A->p[n - 1] == 0) { + --n; + } + + /* The general method below doesn't work if b==0. */ + if (b == 0 || n == 0) { + return mbedtls_mpi_lset(X, 0); + } + + /* Calculate A*b as A + A*(b-1) to take advantage of mbedtls_mpi_core_mla */ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + /* In general, A * b requires 1 limb more than b. If + * A->p[n - 1] * b / b == A->p[n - 1], then A * b fits in the same + * number of limbs as A and the call to grow() is not required since + * copy() will take care of the growth if needed. However, experimentally, + * making the call to grow() unconditional causes slightly fewer + * calls to calloc() in ECP code, presumably because it reuses the + * same mpi for a while and this way the mpi is more likely to directly + * grow to its final size. + * + * Note that calculating A*b as 0 + A*b doesn't work as-is because + * A,X can be the same. */ + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n + 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A)); + mbedtls_mpi_core_mla(X->p, X->n, A->p, n, b - 1); + +cleanup: + return ret; +} + +#endif /* !MBEDTLS_MPI_MUL_MPI_ALT */ + +/* + * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and + * mbedtls_mpi_uint divisor, d + */ +static mbedtls_mpi_uint mbedtls_int_div_int(mbedtls_mpi_uint u1, + mbedtls_mpi_uint u0, + mbedtls_mpi_uint d, + mbedtls_mpi_uint *r) +{ +#if defined(MBEDTLS_HAVE_UDBL) + mbedtls_t_udbl dividend, quotient; +#else + const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH; + const mbedtls_mpi_uint uint_halfword_mask = ((mbedtls_mpi_uint) 1 << biH) - 1; + mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient; + mbedtls_mpi_uint u0_msw, u0_lsw; + size_t s; +#endif + + /* + * Check for overflow + */ + if (0 == d || u1 >= d) { + if (r != NULL) { + *r = ~(mbedtls_mpi_uint) 0u; + } + + return ~(mbedtls_mpi_uint) 0u; + } + +#if defined(MBEDTLS_HAVE_UDBL) + dividend = (mbedtls_t_udbl) u1 << biL; + dividend |= (mbedtls_t_udbl) u0; + quotient = dividend / d; + if (quotient > ((mbedtls_t_udbl) 1 << biL) - 1) { + quotient = ((mbedtls_t_udbl) 1 << biL) - 1; + } + + if (r != NULL) { + *r = (mbedtls_mpi_uint) (dividend - (quotient * d)); + } + + return (mbedtls_mpi_uint) quotient; +#else + + /* + * Algorithm D, Section 4.3.1 - The Art of Computer Programming + * Vol. 2 - Seminumerical Algorithms, Knuth + */ + + /* + * Normalize the divisor, d, and dividend, u0, u1 + */ + s = mbedtls_mpi_core_clz(d); + d = d << s; + + u1 = u1 << s; + u1 |= (u0 >> (biL - s)) & (-(mbedtls_mpi_sint) s >> (biL - 1)); + u0 = u0 << s; + + d1 = d >> biH; + d0 = d & uint_halfword_mask; + + u0_msw = u0 >> biH; + u0_lsw = u0 & uint_halfword_mask; + + /* + * Find the first quotient and remainder + */ + q1 = u1 / d1; + r0 = u1 - d1 * q1; + + while (q1 >= radix || (q1 * d0 > radix * r0 + u0_msw)) { + q1 -= 1; + r0 += d1; + + if (r0 >= radix) { + break; + } + } + + rAX = (u1 * radix) + (u0_msw - q1 * d); + q0 = rAX / d1; + r0 = rAX - q0 * d1; + + while (q0 >= radix || (q0 * d0 > radix * r0 + u0_lsw)) { + q0 -= 1; + r0 += d1; + + if (r0 >= radix) { + break; + } + } + + if (r != NULL) { + *r = (rAX * radix + u0_lsw - q0 * d) >> s; + } + + quotient = q1 * radix + q0; + + return quotient; +#endif +} + +/* + * Division by mbedtls_mpi: A = Q * B + R (HAC 14.20) + */ +int mbedtls_mpi_div_mpi(mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, + const mbedtls_mpi *B) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t i, n, t, k; + mbedtls_mpi X, Y, Z, T1, T2; + mbedtls_mpi_uint TP2[3]; + + if (mbedtls_mpi_cmp_int(B, 0) == 0) { + return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO; + } + + mbedtls_mpi_init(&X); mbedtls_mpi_init(&Y); mbedtls_mpi_init(&Z); + mbedtls_mpi_init(&T1); + /* + * Avoid dynamic memory allocations for constant-size T2. + * + * T2 is used for comparison only and the 3 limbs are assigned explicitly, + * so nobody increase the size of the MPI and we're safe to use an on-stack + * buffer. + */ + T2.s = 1; + T2.n = sizeof(TP2) / sizeof(*TP2); + T2.p = TP2; + + if (mbedtls_mpi_cmp_abs(A, B) < 0) { + if (Q != NULL) { + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(Q, 0)); + } + if (R != NULL) { + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, A)); + } + return 0; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&X, A)); + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, B)); + X.s = Y.s = 1; + + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&Z, A->n + 2)); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Z, 0)); + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&T1, A->n + 2)); + + k = mbedtls_mpi_bitlen(&Y) % biL; + if (k < biL - 1) { + k = biL - 1 - k; + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&X, k)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, k)); + } else { + k = 0; + } + + n = X.n - 1; + t = Y.n - 1; + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, biL * (n - t))); + + while (mbedtls_mpi_cmp_mpi(&X, &Y) >= 0) { + Z.p[n - t]++; + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &Y)); + } + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, biL * (n - t))); + + for (i = n; i > t; i--) { + if (X.p[i] >= Y.p[t]) { + Z.p[i - t - 1] = ~(mbedtls_mpi_uint) 0u; + } else { + Z.p[i - t - 1] = mbedtls_int_div_int(X.p[i], X.p[i - 1], + Y.p[t], NULL); + } + + T2.p[0] = (i < 2) ? 0 : X.p[i - 2]; + T2.p[1] = (i < 1) ? 0 : X.p[i - 1]; + T2.p[2] = X.p[i]; + + Z.p[i - t - 1]++; + do { + Z.p[i - t - 1]--; + + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&T1, 0)); + T1.p[0] = (t < 1) ? 0 : Y.p[t - 1]; + T1.p[1] = Y.p[t]; + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &T1, Z.p[i - t - 1])); + } while (mbedtls_mpi_cmp_mpi(&T1, &T2) > 0); + + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &Y, Z.p[i - t - 1])); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1))); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &T1)); + + if (mbedtls_mpi_cmp_int(&X, 0) < 0) { + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T1, &Y)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1))); + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&X, &X, &T1)); + Z.p[i - t - 1]--; + } + } + + if (Q != NULL) { + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(Q, &Z)); + Q->s = A->s * B->s; + } + + if (R != NULL) { + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&X, k)); + X.s = A->s; + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, &X)); + + if (mbedtls_mpi_cmp_int(R, 0) == 0) { + R->s = 1; + } + } + +cleanup: + + mbedtls_mpi_free(&X); mbedtls_mpi_free(&Y); mbedtls_mpi_free(&Z); + mbedtls_mpi_free(&T1); + mbedtls_platform_zeroize(TP2, sizeof(TP2)); + + return ret; +} + +/* + * Division by int: A = Q * b + R + */ +int mbedtls_mpi_div_int(mbedtls_mpi *Q, mbedtls_mpi *R, + const mbedtls_mpi *A, + mbedtls_mpi_sint b) +{ + mbedtls_mpi B; + mbedtls_mpi_uint p[1]; + + p[0] = mpi_sint_abs(b); + B.s = TO_SIGN(b); + B.n = 1; + B.p = p; + + return mbedtls_mpi_div_mpi(Q, R, A, &B); +} + +/* + * Modulo: R = A mod B + */ +int mbedtls_mpi_mod_mpi(mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if (mbedtls_mpi_cmp_int(B, 0) < 0) { + return MBEDTLS_ERR_MPI_NEGATIVE_VALUE; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(NULL, R, A, B)); + + while (mbedtls_mpi_cmp_int(R, 0) < 0) { + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(R, R, B)); + } + + while (mbedtls_mpi_cmp_mpi(R, B) >= 0) { + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(R, R, B)); + } + +cleanup: + + return ret; +} + +/* + * Modulo: r = A mod b + */ +int mbedtls_mpi_mod_int(mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b) +{ + size_t i; + mbedtls_mpi_uint x, y, z; + + if (b == 0) { + return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO; + } + + if (b < 0) { + return MBEDTLS_ERR_MPI_NEGATIVE_VALUE; + } + + /* + * handle trivial cases + */ + if (b == 1 || A->n == 0) { + *r = 0; + return 0; + } + + if (b == 2) { + *r = A->p[0] & 1; + return 0; + } + + /* + * general case + */ + for (i = A->n, y = 0; i > 0; i--) { + x = A->p[i - 1]; + y = (y << biH) | (x >> biH); + z = y / b; + y -= z * b; + + x <<= biH; + y = (y << biH) | (x >> biH); + z = y / b; + y -= z * b; + } + + /* + * If A is negative, then the current y represents a negative value. + * Flipping it to the positive side. + */ + if (A->s < 0 && y != 0) { + y = b - y; + } + + *r = y; + + return 0; +} + +#if !defined(MBEDTLS_MPI_EXP_MOD_ALT) || defined(MBEDTLS_MPI_EXP_MOD_ALT_FALLBACK) + +/* + * Warning! If the parameter E_public has MBEDTLS_MPI_IS_PUBLIC as its value, + * this function is not constant time with respect to the exponent (parameter E). + */ +static int mbedtls_mpi_exp_mod_optionally_safe(mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *E, int E_public, + const mbedtls_mpi *N, mbedtls_mpi *prec_RR) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if (mbedtls_mpi_cmp_int(N, 0) <= 0 || (N->p[0] & 1) == 0) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + if (mbedtls_mpi_cmp_int(E, 0) < 0) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + if (mbedtls_mpi_bitlen(E) > MBEDTLS_MPI_MAX_BITS || + mbedtls_mpi_bitlen(N) > MBEDTLS_MPI_MAX_BITS) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + /* + * Ensure that the exponent that we are passing to the core is not NULL. + */ + if (E->n == 0) { + ret = mbedtls_mpi_lset(X, 1); + return ret; + } + + /* + * Allocate working memory for mbedtls_mpi_core_exp_mod() + */ + size_t T_limbs = mbedtls_mpi_core_exp_mod_working_limbs(N->n, E->n); + mbedtls_mpi_uint *T = (mbedtls_mpi_uint *) mbedtls_calloc(T_limbs, sizeof(mbedtls_mpi_uint)); + if (T == NULL) { + return MBEDTLS_ERR_MPI_ALLOC_FAILED; + } + + mbedtls_mpi RR; + mbedtls_mpi_init(&RR); + + /* + * If 1st call, pre-compute R^2 mod N + */ + if (prec_RR == NULL || prec_RR->p == NULL) { + MBEDTLS_MPI_CHK(mbedtls_mpi_core_get_mont_r2_unsafe(&RR, N)); + + if (prec_RR != NULL) { + *prec_RR = RR; + } + } else { + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(prec_RR, N->n)); + RR = *prec_RR; + } + + /* + * To preserve constness we need to make a copy of A. Using X for this to + * save memory. + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A)); + + /* + * Compensate for negative A (and correct at the end). + */ + X->s = 1; + + /* + * Make sure that X is in a form that is safe for consumption by + * the core functions. + * + * - The core functions will not touch the limbs of X above N->n. The + * result will be correct if those limbs are 0, which the mod call + * ensures. + * - Also, X must have at least as many limbs as N for the calls to the + * core functions. + */ + if (mbedtls_mpi_cmp_mpi(X, N) >= 0) { + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(X, X, N)); + } + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, N->n)); + + /* + * Convert to and from Montgomery around mbedtls_mpi_core_exp_mod(). + */ + { + mbedtls_mpi_uint mm = mbedtls_mpi_core_montmul_init(N->p); + mbedtls_mpi_core_to_mont_rep(X->p, X->p, N->p, N->n, mm, RR.p, T); + if (E_public == MBEDTLS_MPI_IS_PUBLIC) { + mbedtls_mpi_core_exp_mod_unsafe(X->p, X->p, N->p, N->n, E->p, E->n, RR.p, T); + } else { + mbedtls_mpi_core_exp_mod(X->p, X->p, N->p, N->n, E->p, E->n, RR.p, T); + } + mbedtls_mpi_core_from_mont_rep(X->p, X->p, N->p, N->n, mm, T); + } + + /* + * Correct for negative A. + */ + if (A->s == -1 && (E->p[0] & 1) != 0) { + mbedtls_ct_condition_t is_x_non_zero = mbedtls_mpi_core_check_zero_ct(X->p, X->n); + X->s = mbedtls_ct_mpi_sign_if(is_x_non_zero, -1, 1); + + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(X, N, X)); + } + +cleanup: + + mbedtls_mpi_zeroize_and_free(T, T_limbs); + + if (prec_RR == NULL || prec_RR->p == NULL) { + mbedtls_mpi_free(&RR); + } + + return ret; +} + +#if !defined(MBEDTLS_MPI_EXP_MOD_ALT_FALLBACK) +int mbedtls_mpi_exp_mod(mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *E, const mbedtls_mpi *N, + mbedtls_mpi *prec_RR) +#else +int mbedtls_mpi_exp_mod_soft(mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *E, const mbedtls_mpi *N, + mbedtls_mpi *prec_RR) +#endif + +{ + return mbedtls_mpi_exp_mod_optionally_safe(X, A, E, MBEDTLS_MPI_IS_SECRET, N, prec_RR); +} +#endif /* !MBEDTLS_MPI_EXP_MOD_ALT || MBEDTLS_MPI_EXP_MOD_ALT_FALLBACK */ + +int mbedtls_mpi_exp_mod_unsafe(mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *E, const mbedtls_mpi *N, + mbedtls_mpi *prec_RR) +{ +#if defined(MBEDTLS_MPI_EXP_MOD_ALT) + return mbedtls_mpi_exp_mod(X, A, E, N, prec_RR); +#else + return mbedtls_mpi_exp_mod_optionally_safe(X, A, E, MBEDTLS_MPI_IS_PUBLIC, N, prec_RR); +#endif /* MBEDTLS_MPI_EXP_MOD_ALT */ +} + +/* Constant-time GCD and/or modinv with odd modulus and A <= N */ +int mbedtls_mpi_gcd_modinv_odd(mbedtls_mpi *G, + mbedtls_mpi *I, + const mbedtls_mpi *A, + const mbedtls_mpi *N) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi local_g; + mbedtls_mpi_uint *T = NULL; + const size_t T_factor = I != NULL ? 5 : 4; + const mbedtls_mpi_uint zero = 0; + + /* Check requirements on A and N */ + if (mbedtls_mpi_cmp_int(A, 0) < 0 || + mbedtls_mpi_cmp_mpi(A, N) > 0 || + mbedtls_mpi_get_bit(N, 0) != 1 || + (I != NULL && mbedtls_mpi_cmp_int(N, 1) == 0)) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + /* Check aliasing requirements */ + if (A == N || (I != NULL && (I == N || G == N))) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + mbedtls_mpi_init(&local_g); + + if (G == NULL) { + G = &local_g; + } + + /* We can't modify the values of G or I before use in the main function, + * as they could be aliased to A or N. */ + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(G, N->n)); + if (I != NULL) { + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(I, N->n)); + } + + T = mbedtls_calloc(sizeof(mbedtls_mpi_uint) * N->n, T_factor); + if (T == NULL) { + ret = MBEDTLS_ERR_MPI_ALLOC_FAILED; + goto cleanup; + } + + mbedtls_mpi_uint *Ip = I != NULL ? I->p : NULL; + /* If A is 0 (null), then A->p would be null, and A->n would be 0, + * which would be an issue if A->p and A->n were passed to + * mbedtls_mpi_core_gcd_modinv_odd below. */ + const mbedtls_mpi_uint *Ap = A->p != NULL ? A->p : &zero; + size_t An = A->n >= N->n ? N->n : A->p != NULL ? A->n : 1; + mbedtls_mpi_core_gcd_modinv_odd(G->p, Ip, Ap, An, N->p, N->n, T); + + G->s = 1; + if (I != NULL) { + I->s = 1; + } + + if (G->n > N->n) { + memset(G->p + N->n, 0, ciL * (G->n - N->n)); + } + if (I != NULL && I->n > N->n) { + memset(I->p + N->n, 0, ciL * (I->n - N->n)); + } + +cleanup: + mbedtls_mpi_free(&local_g); + mbedtls_free(T); + return ret; +} + +/* + * Greatest common divisor: G = gcd(A, B) + * Wrapper around mbedtls_mpi_gcd_modinv() that removes its restrictions. + */ +int mbedtls_mpi_gcd(mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi TA, TB; + + mbedtls_mpi_init(&TA); mbedtls_mpi_init(&TB); + + /* Make copies and take absolute values */ + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A)); + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B)); + TA.s = TB.s = 1; + + /* Make the two values the same (non-zero) number of limbs. + * This is needed to use mbedtls_mpi_core functions below. */ + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&TA, TB.n != 0 ? TB.n : 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&TB, TA.n)); // non-zero from above + + /* Handle special cases (that don't happen in crypto usage) */ + if (mbedtls_mpi_core_check_zero_ct(TA.p, TA.n) == MBEDTLS_CT_FALSE) { + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(G, &TB)); // GCD(0, B) = abs(B) + goto cleanup; + } + if (mbedtls_mpi_core_check_zero_ct(TB.p, TB.n) == MBEDTLS_CT_FALSE) { + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(G, &TA)); // GCD(A, 0) = abs(A) + goto cleanup; + } + + /* Make boths inputs odd by putting powers of 2 on the side */ + const size_t za = mbedtls_mpi_lsb(&TA); + const size_t zb = mbedtls_mpi_lsb(&TB); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, za)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, zb)); + + /* Ensure A <= B: if B < A, swap them */ + mbedtls_ct_condition_t swap = mbedtls_mpi_core_lt_ct(TB.p, TA.p, TA.n); + mbedtls_mpi_core_cond_swap(TA.p, TB.p, TA.n, swap); + + MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(G, NULL, &TA, &TB)); + + /* Re-inject the power of 2 we had previously put aside */ + size_t zg = za > zb ? zb : za; // zg = min(za, zb) + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(G, zg)); + +cleanup: + + mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TB); + + return ret; +} + +/* + * Fill X with size bytes of random. + * The bytes returned from the RNG are used in a specific order which + * is suitable for deterministic ECDSA (see the specification of + * mbedtls_mpi_random() and the implementation in mbedtls_mpi_fill_random()). + */ +int mbedtls_mpi_fill_random(mbedtls_mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + const size_t limbs = CHARS_TO_LIMBS(size); + + /* Ensure that target MPI has exactly the necessary number of limbs */ + MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs)); + if (size == 0) { + return 0; + } + + ret = mbedtls_mpi_core_fill_random(X->p, X->n, size, f_rng, p_rng); + +cleanup: + return ret; +} + +int mbedtls_mpi_random(mbedtls_mpi *X, + mbedtls_mpi_sint min, + const mbedtls_mpi *N, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + if (min < 0) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + if (mbedtls_mpi_cmp_int(N, min) <= 0) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + /* Ensure that target MPI has exactly the same number of limbs + * as the upper bound, even if the upper bound has leading zeros. + * This is necessary for mbedtls_mpi_core_random. */ + int ret = mbedtls_mpi_resize_clear(X, N->n); + if (ret != 0) { + return ret; + } + + return mbedtls_mpi_core_random(X->p, min, N->p, X->n, f_rng, p_rng); +} + +/* + * Modular inverse: X = A^-1 mod N with N odd (and A any range) + */ +int mbedtls_mpi_inv_mod_odd(mbedtls_mpi *X, + const mbedtls_mpi *A, + const mbedtls_mpi *N) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi T, G; + + mbedtls_mpi_init(&T); + mbedtls_mpi_init(&G); + + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&T, A, N)); + MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&G, &T, &T, N)); + if (mbedtls_mpi_cmp_int(&G, 1) != 0) { + ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + goto cleanup; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, &T)); + +cleanup: + mbedtls_mpi_free(&T); + mbedtls_mpi_free(&G); + + return ret; +} + +/* + * Compute X = A^-1 mod N with N even, A odd and 1 < A < N. + * + * This is not obvious because our constant-time modinv function only works with + * an odd modulus, and here the modulus is even. The idea is that computing a + * a^-1 mod b is really just computing the u coefficient in the Bézout relation + * a*u + b*v = 1 (assuming gcd(a,b) = 1, i.e. the inverse exists). But if we know + * one of u, v in this relation then the other is easy to find. So we can + * actually start by computing N^-1 mod A with gives us "the wrong half" of the + * Bézout relation, from which we'll deduce the interesting half A^-1 mod N. + * + * Return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if the inverse doesn't exist. + */ +int mbedtls_mpi_inv_mod_even_in_range(mbedtls_mpi *X, + mbedtls_mpi const *A, + mbedtls_mpi const *N) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi I, G; + + mbedtls_mpi_init(&I); + mbedtls_mpi_init(&G); + + /* Set I = N^-1 mod A */ + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&I, N, A)); + MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&G, &I, &I, A)); + if (mbedtls_mpi_cmp_int(&G, 1) != 0) { + ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + goto cleanup; + } + + /* We know N * I = 1 + k * A for some k, which we can easily compute + * as k = (N*I - 1) / A (we know there will be no remainder). */ + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&I, &I, N)); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&I, &I, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(&G, NULL, &I, A)); + + /* Now we have a Bézout relation N * (previous value of I) - G * A = 1, + * so A^-1 mod N is -G mod N, which is N - G. + * Note that 0 < k < N since 0 < I < A, so G (k) is already in range. */ + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(X, N, &G)); + +cleanup: + mbedtls_mpi_free(&I); + mbedtls_mpi_free(&G); + return ret; +} + +/* + * Compute X = A^-1 mod N with N even and A odd (but in any range). + * + * Return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if the inverse doesn't exist. + */ +static int mbedtls_mpi_inv_mod_even(mbedtls_mpi *X, + mbedtls_mpi const *A, + mbedtls_mpi const *N) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi AA; + + mbedtls_mpi_init(&AA); + + /* Bring A in the range [0, N). */ + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&AA, A, N)); + + /* We know A >= 0 but the next function wants A > 1 */ + int cmp = mbedtls_mpi_cmp_int(&AA, 1); + if (cmp < 0) { // AA == 0 + ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + goto cleanup; + } + if (cmp == 0) { // AA = 1 + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 1)); + goto cleanup; + } + + /* Now we know 1 < A < N, N is even and AA is still odd */ + MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod_even_in_range(X, &AA, N)); + +cleanup: + mbedtls_mpi_free(&AA); + return ret; +} + +/* + * Modular inverse: X = A^-1 mod N + * + * Wrapper around mbedtls_mpi_gcd_modinv_odd() that lifts its limitations. + */ +int mbedtls_mpi_inv_mod(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N) +{ + if (mbedtls_mpi_cmp_int(N, 1) <= 0) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + if (mbedtls_mpi_get_bit(N, 0) == 1) { + return mbedtls_mpi_inv_mod_odd(X, A, N); + } + + if (mbedtls_mpi_get_bit(A, 0) == 1) { + return mbedtls_mpi_inv_mod_even(X, A, N); + } + + /* If A and N are both even, 2 divides their GCD, so no inverse. */ + return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; +} + +#if defined(MBEDTLS_GENPRIME) + +/* Gaps between primes, starting at 3. https://oeis.org/A001223 */ +static const unsigned char small_prime_gaps[] = { + 2, 2, 4, 2, 4, 2, 4, 6, + 2, 6, 4, 2, 4, 6, 6, 2, + 6, 4, 2, 6, 4, 6, 8, 4, + 2, 4, 2, 4, 14, 4, 6, 2, + 10, 2, 6, 6, 4, 6, 6, 2, + 10, 2, 4, 2, 12, 12, 4, 2, + 4, 6, 2, 10, 6, 6, 6, 2, + 6, 4, 2, 10, 14, 4, 2, 4, + 14, 6, 10, 2, 4, 6, 8, 6, + 6, 4, 6, 8, 4, 8, 10, 2, + 10, 2, 6, 4, 6, 8, 4, 2, + 4, 12, 8, 4, 8, 4, 6, 12, + 2, 18, 6, 10, 6, 6, 2, 6, + 10, 6, 6, 2, 6, 6, 4, 2, + 12, 10, 2, 4, 6, 6, 2, 12, + 4, 6, 8, 10, 8, 10, 8, 6, + 6, 4, 8, 6, 4, 8, 4, 14, + 10, 12, 2, 10, 2, 4, 2, 10, + 14, 4, 2, 4, 14, 4, 2, 4, + 20, 4, 8, 10, 8, 4, 6, 6, + 14, 4, 6, 6, 8, 6, /*reaches 997*/ + 0 /* the last entry is effectively unused */ +}; + +/* + * Small divisors test (X must be positive) + * + * Return values: + * 0: no small factor (possible prime, more tests needed) + * 1: certain prime + * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime + * other negative: error + */ +static int mpi_check_small_factors(const mbedtls_mpi *X) +{ + int ret = 0; + size_t i; + mbedtls_mpi_uint r; + unsigned p = 3; /* The first odd prime */ + + if ((X->p[0] & 1) == 0) { + return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + } + + for (i = 0; i < sizeof(small_prime_gaps); p += small_prime_gaps[i], i++) { + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, p)); + if (r == 0) { + if (mbedtls_mpi_cmp_int(X, p) == 0) { + return 1; + } else { + return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + } + } + } + +cleanup: + return ret; +} + +/* + * Miller-Rabin pseudo-primality test (HAC 4.24) + */ +static int mpi_miller_rabin(const mbedtls_mpi *X, size_t rounds, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + int ret, count; + size_t i, j, k, s; + mbedtls_mpi W, R, T, A, RR; + + mbedtls_mpi_init(&W); mbedtls_mpi_init(&R); + mbedtls_mpi_init(&T); mbedtls_mpi_init(&A); + mbedtls_mpi_init(&RR); + + /* + * W = |X| - 1 + * R = W >> lsb( W ) + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&W, X, 1)); + s = mbedtls_mpi_lsb(&W); + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R, &W)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&R, s)); + + for (i = 0; i < rounds; i++) { + /* + * pick a random A, 1 < A < |X| - 1 + */ + count = 0; + do { + MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&A, X->n * ciL, f_rng, p_rng)); + + j = mbedtls_mpi_bitlen(&A); + k = mbedtls_mpi_bitlen(&W); + if (j > k) { + A.p[A.n - 1] &= ((mbedtls_mpi_uint) 1 << (k - (A.n - 1) * biL - 1)) - 1; + } + + if (count++ > 30) { + ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + goto cleanup; + } + + } while (mbedtls_mpi_cmp_mpi(&A, &W) >= 0 || + mbedtls_mpi_cmp_int(&A, 1) <= 0); + + /* + * A = A^R mod |X| + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&A, &A, &R, X, &RR)); + + if (mbedtls_mpi_cmp_mpi(&A, &W) == 0 || + mbedtls_mpi_cmp_int(&A, 1) == 0) { + continue; + } + + j = 1; + while (j < s && mbedtls_mpi_cmp_mpi(&A, &W) != 0) { + /* + * A = A * A mod |X| + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&T, &A, &A)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&A, &T, X)); + + if (mbedtls_mpi_cmp_int(&A, 1) == 0) { + break; + } + + j++; + } + + /* + * not prime if A != |X| - 1 or A == 1 + */ + if (mbedtls_mpi_cmp_mpi(&A, &W) != 0 || + mbedtls_mpi_cmp_int(&A, 1) == 0) { + ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + break; + } + } + +cleanup: + mbedtls_mpi_free(&W); mbedtls_mpi_free(&R); + mbedtls_mpi_free(&T); mbedtls_mpi_free(&A); + mbedtls_mpi_free(&RR); + + return ret; +} + +/* + * Pseudo-primality test: small factors, then Miller-Rabin + */ +int mbedtls_mpi_is_prime_ext(const mbedtls_mpi *X, int rounds, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi XX; + + XX.s = 1; + XX.n = X->n; + XX.p = X->p; + + if (mbedtls_mpi_cmp_int(&XX, 0) == 0 || + mbedtls_mpi_cmp_int(&XX, 1) == 0) { + return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + } + + if (mbedtls_mpi_cmp_int(&XX, 2) == 0) { + return 0; + } + + if ((ret = mpi_check_small_factors(&XX)) != 0) { + if (ret == 1) { + return 0; + } + + return ret; + } + + return mpi_miller_rabin(&XX, rounds, f_rng, p_rng); +} + +/* + * Prime number generation + * + * To generate an RSA key in a way recommended by FIPS 186-4, both primes must + * be either 1024 bits or 1536 bits long, and flags must contain + * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR. + */ +int mbedtls_mpi_gen_prime(mbedtls_mpi *X, size_t nbits, int flags, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ +#ifdef MBEDTLS_HAVE_INT64 +// ceil(2^63.5) +#define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL +#else +// ceil(2^31.5) +#define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U +#endif + int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + size_t k, n; + int rounds; + mbedtls_mpi_uint r; + mbedtls_mpi Y; + + if (nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + mbedtls_mpi_init(&Y); + + n = BITS_TO_LIMBS(nbits); + + if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR) == 0) { + /* + * 2^-80 error probability, number of rounds chosen per HAC, table 4.4 + */ + rounds = ((nbits >= 1300) ? 2 : (nbits >= 850) ? 3 : + (nbits >= 650) ? 4 : (nbits >= 350) ? 8 : + (nbits >= 250) ? 12 : (nbits >= 150) ? 18 : 27); + } else { + /* + * 2^-100 error probability, number of rounds computed based on HAC, + * fact 4.48 + */ + rounds = ((nbits >= 1450) ? 4 : (nbits >= 1150) ? 5 : + (nbits >= 1000) ? 6 : (nbits >= 850) ? 7 : + (nbits >= 750) ? 8 : (nbits >= 500) ? 13 : + (nbits >= 250) ? 28 : (nbits >= 150) ? 40 : 51); + } + + while (1) { + MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(X, n * ciL, f_rng, p_rng)); + /* make sure generated number is at least (nbits-1)+0.5 bits (FIPS 186-4 §B.3.3 steps 4.4, 5.5) */ + if (X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2) { + continue; + } + + k = n * biL; + if (k > nbits) { + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(X, k - nbits)); + } + X->p[0] |= 1; + + if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH) == 0) { + ret = mbedtls_mpi_is_prime_ext(X, rounds, f_rng, p_rng); + + if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) { + goto cleanup; + } + } else { + /* + * A necessary condition for Y and X = 2Y + 1 to be prime + * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3). + * Make sure it is satisfied, while keeping X = 3 mod 4 + */ + + X->p[0] |= 2; + + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, 3)); + if (r == 0) { + MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 8)); + } else if (r == 1) { + MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 4)); + } + + /* Set Y = (X-1) / 2, which is X / 2 because X is odd */ + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, X)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, 1)); + + while (1) { + /* + * First, check small factors for X and Y + * before doing Miller-Rabin on any of them + */ + if ((ret = mpi_check_small_factors(X)) == 0 && + (ret = mpi_check_small_factors(&Y)) == 0 && + (ret = mpi_miller_rabin(X, rounds, f_rng, p_rng)) + == 0 && + (ret = mpi_miller_rabin(&Y, rounds, f_rng, p_rng)) + == 0) { + goto cleanup; + } + + if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) { + goto cleanup; + } + + /* + * Next candidates. We want to preserve Y = (X-1) / 2 and + * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3) + * so up Y by 6 and X by 12. + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 12)); + MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&Y, &Y, 6)); + } + } + } + +cleanup: + + mbedtls_mpi_free(&Y); + + return ret; +} + +#endif /* MBEDTLS_GENPRIME */ +#endif /* MBEDTLS_MPI_EXP_MOD_ALT */ + + +#if defined(MBEDTLS_ASN1_WRITE_C) +#include "mbedtls/asn1.h" +#include "mbedtls/asn1write.h" +int mbedtls_asn1_write_mpi(unsigned char **p, const unsigned char *start, const mbedtls_mpi *X) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t len = 0; + + // Write the MPI + // + len = mbedtls_mpi_size(X); + + /* DER represents 0 with a sign bit (0=nonnegative) and 7 value bits, not + * as 0 digits. We need to end up with 020100, not with 0200. */ + if (len == 0) { + len = 1; + } + + if (*p < start || (size_t) (*p - start) < len) { + return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL; + } + + (*p) -= len; + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(X, *p, len)); + + // DER format assumes 2s complement for numbers, so the leftmost bit + // should be 0 for positive numbers and 1 for negative numbers. + // + if (X->s == 1 && **p & 0x80) { + if (*p - start < 1) { + return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL; + } + + *--(*p) = 0x00; + len += 1; + } + + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len)); + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_INTEGER)); + + ret = (int) len; + +cleanup: + return ret; +} +#endif /* MBEDTLS_ASN1_WRITE_C */ + +#if defined(MBEDTLS_ASN1_PARSE_C) +#include "mbedtls/asn1.h" +int mbedtls_asn1_get_mpi(unsigned char **p, + const unsigned char *end, + mbedtls_mpi *X) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t len; + + if ((ret = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_INTEGER)) != 0) { + return ret; + } + + ret = mbedtls_mpi_read_binary(X, *p, len); + + *p += len; + + return ret; +} +#endif /* MBEDTLS_ASN1_PARSE_C */ + +#if defined(MBEDTLS_SELF_TEST) + +#define GCD_PAIR_COUNT 3 + +static const int gcd_pairs[GCD_PAIR_COUNT][3] = +{ + { 693, 609, 21 }, + { 1764, 868, 28 }, + { 768454923, 542167814, 1 } +}; + +/* + * Checkup routine + */ +int mbedtls_mpi_self_test(int verbose) +{ + int ret, i; + mbedtls_mpi A, E, N, X, Y, U, V; + + mbedtls_mpi_init(&A); mbedtls_mpi_init(&E); mbedtls_mpi_init(&N); mbedtls_mpi_init(&X); + mbedtls_mpi_init(&Y); mbedtls_mpi_init(&U); mbedtls_mpi_init(&V); + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&A, 16, + "EFE021C2645FD1DC586E69184AF4A31E" \ + "D5F53E93B5F123FA41680867BA110131" \ + "944FE7952E2517337780CB0DB80E61AA" \ + "E7C8DDC6C5C6AADEB34EB38A2F40D5E6")); + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&E, 16, + "B2E7EFD37075B9F03FF989C7C5051C20" \ + "34D2A323810251127E7BF8625A4F49A5" \ + "F3E27F4DA8BD59C47D6DAABA4C8127BD" \ + "5B5C25763222FEFCCFC38B832366C29E")); + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 16, + "0066A198186C18C10B2F5ED9B522752A" \ + "9830B69916E535C8F047518A889A43A5" \ + "94B6BED27A168D31D4A52F88925AA8F5")); + + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&X, &A, &N)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16, + "602AB7ECA597A3D6B56FF9829A5E8B85" \ + "9E857EA95A03512E2BAE7391688D264A" \ + "A5663B0341DB9CCFD2C4C5F421FEC814" \ + "8001B72E848A38CAE1C65F78E56ABDEF" \ + "E12D3C039B8A02D6BE593F0BBBDA56F1" \ + "ECF677152EF804370C1A305CAF3B5BF1" \ + "30879B56C61DE584A0F53A2447A51E")); + + if (verbose != 0) { + mbedtls_printf(" MPI test #1 (mul_mpi): "); + } + + if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + ret = 1; + goto cleanup; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(&X, &Y, &A, &N)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16, + "256567336059E52CAE22925474705F39A94")); + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&V, 16, + "6613F26162223DF488E9CD48CC132C7A" \ + "0AC93C701B001B092E4E5B9F73BCD27B" \ + "9EE50D0657C77F374E903CDFA4C642")); + + if (verbose != 0) { + mbedtls_printf(" MPI test #2 (div_mpi): "); + } + + if (mbedtls_mpi_cmp_mpi(&X, &U) != 0 || + mbedtls_mpi_cmp_mpi(&Y, &V) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + ret = 1; + goto cleanup; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&X, &A, &E, &N, NULL)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16, + "36E139AEA55215609D2816998ED020BB" \ + "BD96C37890F65171D948E9BC7CBAA4D9" \ + "325D24D6A3C12710F10A09FA08AB87")); + + if (verbose != 0) { + mbedtls_printf(" MPI test #3 (exp_mod): "); + } + + if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + ret = 1; + goto cleanup; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&X, &A, &N)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16, + "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \ + "C3DBA76456363A10869622EAC2DD84EC" \ + "C5B8A74DAC4D09E03B5E0BE779F2DF61")); + + if (verbose != 0) { + mbedtls_printf(" MPI test #4 (inv_mod): "); + } + + if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + ret = 1; + goto cleanup; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + + if (verbose != 0) { + mbedtls_printf(" MPI test #5 (simple gcd): "); + } + + for (i = 0; i < GCD_PAIR_COUNT; i++) { + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&X, gcd_pairs[i][0])); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Y, gcd_pairs[i][1])); + + MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&A, &X, &Y)); + + if (mbedtls_mpi_cmp_int(&A, gcd_pairs[i][2]) != 0) { + if (verbose != 0) { + mbedtls_printf("failed at %d\n", i); + } + + ret = 1; + goto cleanup; + } + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + +cleanup: + + if (ret != 0 && verbose != 0) { + mbedtls_printf("Unexpected error, return code = %08X\n", (unsigned int) ret); + } + + mbedtls_mpi_free(&A); mbedtls_mpi_free(&E); mbedtls_mpi_free(&N); mbedtls_mpi_free(&X); + mbedtls_mpi_free(&Y); mbedtls_mpi_free(&U); mbedtls_mpi_free(&V); + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + return ret; +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_BIGNUM_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/bignum_core.c b/tf-psa-crypto/drivers/builtin/src/bignum_core.c new file mode 100644 index 0000000000..fc1b537c72 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/bignum_core.c @@ -0,0 +1,1242 @@ +/* + * Core bignum functions + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_BIGNUM_C) + +#include +#include + +#include "mbedtls/private/error_common.h" +#include "mbedtls/platform_util.h" +#include "constant_time_internal.h" + +#include "mbedtls/platform.h" + +#include "bignum_core.h" +#include "bignum_core_invasive.h" +#include "bignum_internal.h" +#include "bn_mul.h" +#include "constant_time_internal.h" + +size_t mbedtls_mpi_core_clz(mbedtls_mpi_uint a) +{ +#if defined(__has_builtin) +#if (MBEDTLS_MPI_UINT_MAX == UINT_MAX) && __has_builtin(__builtin_clz) + #define core_clz __builtin_clz +#elif (MBEDTLS_MPI_UINT_MAX == ULONG_MAX) && __has_builtin(__builtin_clzl) + #define core_clz __builtin_clzl +#elif (MBEDTLS_MPI_UINT_MAX == ULLONG_MAX) && __has_builtin(__builtin_clzll) + #define core_clz __builtin_clzll +#endif +#endif +#if defined(core_clz) + return (size_t) core_clz(a); +#else + size_t j; + mbedtls_mpi_uint mask = (mbedtls_mpi_uint) 1 << (biL - 1); + + for (j = 0; j < biL; j++) { + if (a & mask) { + break; + } + + mask >>= 1; + } + + return j; +#endif +} + +size_t mbedtls_mpi_core_bitlen(const mbedtls_mpi_uint *A, size_t A_limbs) +{ + int i; + size_t j; + + for (i = ((int) A_limbs) - 1; i >= 0; i--) { + if (A[i] != 0) { + j = biL - mbedtls_mpi_core_clz(A[i]); + return (i * biL) + j; + } + } + + return 0; +} + +static mbedtls_mpi_uint mpi_bigendian_to_host(mbedtls_mpi_uint a) +{ + if (MBEDTLS_IS_BIG_ENDIAN) { + /* Nothing to do on bigendian systems. */ + return a; + } else { +#if defined(MBEDTLS_HAVE_INT32) + return (mbedtls_mpi_uint) MBEDTLS_BSWAP32(a); +#elif defined(MBEDTLS_HAVE_INT64) + return (mbedtls_mpi_uint) MBEDTLS_BSWAP64(a); +#endif + } +} + +void mbedtls_mpi_core_bigendian_to_host(mbedtls_mpi_uint *A, + size_t A_limbs) +{ + mbedtls_mpi_uint *cur_limb_left; + mbedtls_mpi_uint *cur_limb_right; + if (A_limbs == 0) { + return; + } + + /* + * Traverse limbs and + * - adapt byte-order in each limb + * - swap the limbs themselves. + * For that, simultaneously traverse the limbs from left to right + * and from right to left, as long as the left index is not bigger + * than the right index (it's not a problem if limbs is odd and the + * indices coincide in the last iteration). + */ + for (cur_limb_left = A, cur_limb_right = A + (A_limbs - 1); + cur_limb_left <= cur_limb_right; + cur_limb_left++, cur_limb_right--) { + mbedtls_mpi_uint tmp; + /* Note that if cur_limb_left == cur_limb_right, + * this code effectively swaps the bytes only once. */ + tmp = mpi_bigendian_to_host(*cur_limb_left); + *cur_limb_left = mpi_bigendian_to_host(*cur_limb_right); + *cur_limb_right = tmp; + } +} + +/* Whether min <= A, in constant time. + * A_limbs must be at least 1. */ +mbedtls_ct_condition_t mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min, + const mbedtls_mpi_uint *A, + size_t A_limbs) +{ + /* min <= least significant limb? */ + mbedtls_ct_condition_t min_le_lsl = mbedtls_ct_uint_ge(A[0], min); + + /* limbs other than the least significant one are all zero? */ + mbedtls_ct_condition_t msll_mask = MBEDTLS_CT_FALSE; + for (size_t i = 1; i < A_limbs; i++) { + msll_mask = mbedtls_ct_bool_or(msll_mask, mbedtls_ct_bool(A[i])); + } + + /* min <= A iff the lowest limb of A is >= min or the other limbs + * are not all zero. */ + return mbedtls_ct_bool_or(msll_mask, min_le_lsl); +} + +mbedtls_ct_condition_t mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + size_t limbs) +{ + mbedtls_ct_condition_t ret = MBEDTLS_CT_FALSE, cond = MBEDTLS_CT_FALSE, done = MBEDTLS_CT_FALSE; + + for (size_t i = limbs; i > 0; i--) { + /* + * If B[i - 1] < A[i - 1] then A < B is false and the result must + * remain 0. + * + * Again even if we can make a decision, we just mark the result and + * the fact that we are done and continue looping. + */ + cond = mbedtls_ct_uint_lt(B[i - 1], A[i - 1]); + done = mbedtls_ct_bool_or(done, cond); + + /* + * If A[i - 1] < B[i - 1] then A < B is true. + * + * Again even if we can make a decision, we just mark the result and + * the fact that we are done and continue looping. + */ + cond = mbedtls_ct_uint_lt(A[i - 1], B[i - 1]); + ret = mbedtls_ct_bool_or(ret, mbedtls_ct_bool_and(cond, mbedtls_ct_bool_not(done))); + done = mbedtls_ct_bool_or(done, cond); + } + + /* + * If all the limbs were equal, then the numbers are equal, A < B is false + * and leaving the result 0 is correct. + */ + + return ret; +} + +void mbedtls_mpi_core_cond_assign(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + size_t limbs, + mbedtls_ct_condition_t assign) +{ + if (X == A) { + return; + } + + /* This function is very performance-sensitive for RSA. For this reason + * we have the loop below, instead of calling mbedtls_ct_memcpy_if + * (this is more optimal since here we don't have to handle the case where + * we copy awkwardly sized data). + */ + for (size_t i = 0; i < limbs; i++) { + X[i] = mbedtls_ct_mpi_uint_if(assign, A[i], X[i]); + } +} + +void mbedtls_mpi_core_cond_swap(mbedtls_mpi_uint *X, + mbedtls_mpi_uint *Y, + size_t limbs, + mbedtls_ct_condition_t swap) +{ + if (X == Y) { + return; + } + + for (size_t i = 0; i < limbs; i++) { + mbedtls_mpi_uint tmp = X[i]; + X[i] = mbedtls_ct_mpi_uint_if(swap, Y[i], X[i]); + Y[i] = mbedtls_ct_mpi_uint_if(swap, tmp, Y[i]); + } +} + +int mbedtls_mpi_core_read_le(mbedtls_mpi_uint *X, + size_t X_limbs, + const unsigned char *input, + size_t input_length) +{ + const size_t limbs = CHARS_TO_LIMBS(input_length); + + if (X_limbs < limbs) { + return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL; + } + + if (X != NULL) { + memset(X, 0, X_limbs * ciL); + + for (size_t i = 0; i < input_length; i++) { + size_t offset = ((i % ciL) << 3); + X[i / ciL] |= ((mbedtls_mpi_uint) input[i]) << offset; + } + } + + return 0; +} + +int mbedtls_mpi_core_read_be(mbedtls_mpi_uint *X, + size_t X_limbs, + const unsigned char *input, + size_t input_length) +{ + const size_t limbs = CHARS_TO_LIMBS(input_length); + + if (X_limbs < limbs) { + return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL; + } + + /* If X_limbs is 0, input_length must also be 0 (from previous test). + * Nothing to do. */ + if (X_limbs == 0) { + return 0; + } + + memset(X, 0, X_limbs * ciL); + + /* memcpy() with (NULL, 0) is undefined behaviour */ + if (input_length != 0) { + size_t overhead = (X_limbs * ciL) - input_length; + unsigned char *Xp = (unsigned char *) X; + memcpy(Xp + overhead, input, input_length); + } + + mbedtls_mpi_core_bigendian_to_host(X, X_limbs); + + return 0; +} + +int mbedtls_mpi_core_write_le(const mbedtls_mpi_uint *A, + size_t A_limbs, + unsigned char *output, + size_t output_length) +{ + size_t stored_bytes = A_limbs * ciL; + size_t bytes_to_copy; + + if (stored_bytes < output_length) { + bytes_to_copy = stored_bytes; + } else { + bytes_to_copy = output_length; + + /* The output buffer is smaller than the allocated size of A. + * However A may fit if its leading bytes are zero. */ + for (size_t i = bytes_to_copy; i < stored_bytes; i++) { + if (GET_BYTE(A, i) != 0) { + return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL; + } + } + } + + for (size_t i = 0; i < bytes_to_copy; i++) { + output[i] = GET_BYTE(A, i); + } + + if (stored_bytes < output_length) { + /* Write trailing 0 bytes */ + memset(output + stored_bytes, 0, output_length - stored_bytes); + } + + return 0; +} + +int mbedtls_mpi_core_write_be(const mbedtls_mpi_uint *X, + size_t X_limbs, + unsigned char *output, + size_t output_length) +{ + size_t stored_bytes; + size_t bytes_to_copy; + unsigned char *p; + + stored_bytes = X_limbs * ciL; + + if (stored_bytes < output_length) { + /* There is enough space in the output buffer. Write initial + * null bytes and record the position at which to start + * writing the significant bytes. In this case, the execution + * trace of this function does not depend on the value of the + * number. */ + bytes_to_copy = stored_bytes; + p = output + output_length - stored_bytes; + memset(output, 0, output_length - stored_bytes); + } else { + /* The output buffer is smaller than the allocated size of X. + * However X may fit if its leading bytes are zero. */ + bytes_to_copy = output_length; + p = output; + for (size_t i = bytes_to_copy; i < stored_bytes; i++) { + if (GET_BYTE(X, i) != 0) { + return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL; + } + } + } + + for (size_t i = 0; i < bytes_to_copy; i++) { + p[bytes_to_copy - i - 1] = GET_BYTE(X, i); + } + + return 0; +} + +void mbedtls_mpi_core_shift_r(mbedtls_mpi_uint *X, size_t limbs, + size_t count) +{ + size_t i, v0, v1; + mbedtls_mpi_uint r0 = 0, r1; + + v0 = count / biL; + v1 = count & (biL - 1); + + if (v0 > limbs || (v0 == limbs && v1 > 0)) { + memset(X, 0, limbs * ciL); + return; + } + + /* + * shift by count / limb_size + */ + if (v0 > 0) { + for (i = 0; i < limbs - v0; i++) { + X[i] = X[i + v0]; + } + + for (; i < limbs; i++) { + X[i] = 0; + } + } + + /* + * shift by count % limb_size + */ + if (v1 > 0) { + for (i = limbs; i > 0; i--) { + r1 = X[i - 1] << (biL - v1); + X[i - 1] >>= v1; + X[i - 1] |= r0; + r0 = r1; + } + } +} + +void mbedtls_mpi_core_shift_l(mbedtls_mpi_uint *X, size_t limbs, + size_t count) +{ + size_t i, v0, v1; + mbedtls_mpi_uint r0 = 0, r1; + + v0 = count / (biL); + v1 = count & (biL - 1); + + /* + * shift by count / limb_size + */ + if (v0 > 0) { + for (i = limbs; i > v0; i--) { + X[i - 1] = X[i - v0 - 1]; + } + + for (; i > 0; i--) { + X[i - 1] = 0; + } + } + + /* + * shift by count % limb_size + */ + if (v1 > 0) { + for (i = v0; i < limbs; i++) { + r1 = X[i] >> (biL - v1); + X[i] <<= v1; + X[i] |= r0; + r0 = r1; + } + } +} + +mbedtls_mpi_uint mbedtls_mpi_core_add(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + size_t limbs) +{ + mbedtls_mpi_uint c = 0; + + for (size_t i = 0; i < limbs; i++) { + mbedtls_mpi_uint t = c + A[i]; + c = (t < A[i]); + t += B[i]; + c += (t < B[i]); + X[i] = t; + } + + return c; +} + +mbedtls_mpi_uint mbedtls_mpi_core_add_if(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + size_t limbs, + unsigned cond) +{ + mbedtls_mpi_uint c = 0; + + mbedtls_ct_condition_t do_add = mbedtls_ct_bool(cond); + + for (size_t i = 0; i < limbs; i++) { + mbedtls_mpi_uint add = mbedtls_ct_mpi_uint_if_else_0(do_add, A[i]); + mbedtls_mpi_uint t = c + X[i]; + c = (t < X[i]); + t += add; + c += (t < add); + X[i] = t; + } + + return c; +} + +mbedtls_mpi_uint mbedtls_mpi_core_sub(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + size_t limbs) +{ + mbedtls_mpi_uint c = 0; + + for (size_t i = 0; i < limbs; i++) { + mbedtls_mpi_uint z = mbedtls_ct_mpi_uint_if(mbedtls_ct_uint_lt(A[i], c), + 1, 0); + mbedtls_mpi_uint t = A[i] - c; + c = mbedtls_ct_mpi_uint_if(mbedtls_ct_uint_lt(t, B[i]), 1, 0) + z; + X[i] = t - B[i]; + } + + return c; +} + +mbedtls_mpi_uint mbedtls_mpi_core_mla(mbedtls_mpi_uint *d, size_t d_len, + const mbedtls_mpi_uint *s, size_t s_len, + mbedtls_mpi_uint b) +{ + mbedtls_mpi_uint c = 0; /* carry */ + /* + * It is a documented precondition of this function that d_len >= s_len. + * If that's not the case, we swap these round: this turns what would be + * a buffer overflow into an incorrect result. + */ + if (d_len < s_len) { + s_len = d_len; + } + size_t excess_len = d_len - s_len; + size_t steps_x8 = s_len / 8; + size_t steps_x1 = s_len & 7; + + while (steps_x8--) { + MULADDC_X8_INIT + MULADDC_X8_CORE + MULADDC_X8_STOP + } + + while (steps_x1--) { + MULADDC_X1_INIT + MULADDC_X1_CORE + MULADDC_X1_STOP + } + + while (excess_len--) { + *d += c; + c = mbedtls_ct_mpi_uint_if(mbedtls_ct_uint_lt(*d, c), 1, 0); + d++; + } + + return c; +} + +void mbedtls_mpi_core_mul(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, size_t A_limbs, + const mbedtls_mpi_uint *B, size_t B_limbs) +{ + memset(X, 0, (A_limbs + B_limbs) * ciL); + + for (size_t i = 0; i < B_limbs; i++) { + (void) mbedtls_mpi_core_mla(X + i, A_limbs + 1, A, A_limbs, B[i]); + } +} + +/* + * Fast Montgomery initialization (thanks to Tom St Denis). + */ +mbedtls_mpi_uint mbedtls_mpi_core_montmul_init(const mbedtls_mpi_uint *N) +{ + mbedtls_mpi_uint x = N[0]; + + x += ((N[0] + 2) & 4) << 1; + + for (unsigned int i = biL; i >= 8; i /= 2) { + x *= (2 - (N[0] * x)); + } + + return ~x + 1; +} + +void mbedtls_mpi_core_montmul(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + size_t B_limbs, + const mbedtls_mpi_uint *N, + size_t AN_limbs, + mbedtls_mpi_uint mm, + mbedtls_mpi_uint *T) +{ + memset(T, 0, (2 * AN_limbs + 1) * ciL); + + for (size_t i = 0; i < AN_limbs; i++) { + /* T = (T + u0*B + u1*N) / 2^biL */ + mbedtls_mpi_uint u0 = A[i]; + mbedtls_mpi_uint u1 = (T[0] + u0 * B[0]) * mm; + + (void) mbedtls_mpi_core_mla(T, AN_limbs + 2, B, B_limbs, u0); + (void) mbedtls_mpi_core_mla(T, AN_limbs + 2, N, AN_limbs, u1); + + T++; + } + + /* + * The result we want is (T >= N) ? T - N : T. + * + * For better constant-time properties in this function, we always do the + * subtraction, with the result in X. + * + * We also look to see if there was any carry in the final additions in the + * loop above. + */ + + mbedtls_mpi_uint carry = T[AN_limbs]; + mbedtls_mpi_uint borrow = mbedtls_mpi_core_sub(X, T, N, AN_limbs); + + /* + * Using R as the Montgomery radix (auxiliary modulus) i.e. 2^(biL*AN_limbs): + * + * T can be in one of 3 ranges: + * + * 1) T < N : (carry, borrow) = (0, 1): we want T + * 2) N <= T < R : (carry, borrow) = (0, 0): we want X + * 3) T >= R : (carry, borrow) = (1, 1): we want X + * + * and (carry, borrow) = (1, 0) can't happen. + * + * So the correct return value is already in X if (carry ^ borrow) = 0, + * but is in (the lower AN_limbs limbs of) T if (carry ^ borrow) = 1. + */ + mbedtls_ct_memcpy_if(mbedtls_ct_bool(carry ^ borrow), + (unsigned char *) X, + (unsigned char *) T, + NULL, + AN_limbs * sizeof(mbedtls_mpi_uint)); +} + +int mbedtls_mpi_core_get_mont_r2_unsafe(mbedtls_mpi *X, + const mbedtls_mpi *N) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(X, N->n * 2 * biL)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(X, X, N)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shrink(X, N->n)); + +cleanup: + return ret; +} + +MBEDTLS_STATIC_TESTABLE +void mbedtls_mpi_core_ct_uint_table_lookup(mbedtls_mpi_uint *dest, + const mbedtls_mpi_uint *table, + size_t limbs, + size_t count, + size_t index) +{ + for (size_t i = 0; i < count; i++, table += limbs) { + mbedtls_ct_condition_t assign = mbedtls_ct_uint_eq(i, index); + mbedtls_mpi_core_cond_assign(dest, table, limbs, assign); + } +} + +/* Fill X with n_bytes random bytes. + * X must already have room for those bytes. + * The ordering of the bytes returned from the RNG is suitable for + * deterministic ECDSA (see RFC 6979 §3.3 and the specification of + * mbedtls_mpi_core_random()). + */ +int mbedtls_mpi_core_fill_random( + mbedtls_mpi_uint *X, size_t X_limbs, + size_t n_bytes, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + const size_t limbs = CHARS_TO_LIMBS(n_bytes); + const size_t overhead = (limbs * ciL) - n_bytes; + + if (X_limbs < limbs) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + memset(X, 0, overhead); + memset((unsigned char *) X + limbs * ciL, 0, (X_limbs - limbs) * ciL); + MBEDTLS_MPI_CHK(f_rng(p_rng, (unsigned char *) X + overhead, n_bytes)); + mbedtls_mpi_core_bigendian_to_host(X, limbs); + +cleanup: + return ret; +} + +int mbedtls_mpi_core_random(mbedtls_mpi_uint *X, + mbedtls_mpi_uint min, + const mbedtls_mpi_uint *N, + size_t limbs, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + mbedtls_ct_condition_t ge_lower = MBEDTLS_CT_TRUE, lt_upper = MBEDTLS_CT_FALSE; + size_t n_bits = mbedtls_mpi_core_bitlen(N, limbs); + size_t n_bytes = (n_bits + 7) / 8; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + /* + * When min == 0, each try has at worst a probability 1/2 of failing + * (the msb has a probability 1/2 of being 0, and then the result will + * be < N), so after 30 tries failure probability is a most 2**(-30). + * + * When N is just below a power of 2, as is the case when generating + * a random scalar on most elliptic curves, 1 try is enough with + * overwhelming probability. When N is just above a power of 2 + * each try has a probability of failing that is almost 1/2. + * + * The probabilities are almost the same if min is nonzero but negligible + * compared to N. This is always the case when N is crypto-sized, but + * it's convenient to support small N for testing purposes. When N + * is small, use a higher repeat count, otherwise the probability of + * failure is macroscopic. + */ + int count = (n_bytes > 4 ? 30 : 250); + + /* + * Match the procedure given in RFC 6979 §3.3 (deterministic ECDSA) + * when f_rng is a suitably parametrized instance of HMAC_DRBG: + * - use the same byte ordering; + * - keep the leftmost n_bits bits of the generated octet string; + * - try until result is in the desired range. + * This also avoids any bias, which is especially important for ECDSA. + */ + do { + MBEDTLS_MPI_CHK(mbedtls_mpi_core_fill_random(X, limbs, + n_bytes, + f_rng, p_rng)); + mbedtls_mpi_core_shift_r(X, limbs, 8 * n_bytes - n_bits); + + if (--count == 0) { + ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + goto cleanup; + } + + ge_lower = mbedtls_mpi_core_uint_le_mpi(min, X, limbs); + lt_upper = mbedtls_mpi_core_lt_ct(X, N, limbs); + } while (mbedtls_ct_bool_and(ge_lower, lt_upper) == MBEDTLS_CT_FALSE); + +cleanup: + return ret; +} + +static size_t exp_mod_get_window_size(size_t Ebits) +{ +#if MBEDTLS_MPI_WINDOW_SIZE >= 6 + return (Ebits > 671) ? 6 : (Ebits > 239) ? 5 : (Ebits > 79) ? 4 : 1; +#elif MBEDTLS_MPI_WINDOW_SIZE == 5 + return (Ebits > 239) ? 5 : (Ebits > 79) ? 4 : 1; +#elif MBEDTLS_MPI_WINDOW_SIZE > 1 + return (Ebits > 79) ? MBEDTLS_MPI_WINDOW_SIZE : 1; +#else + (void) Ebits; + return 1; +#endif +} + +size_t mbedtls_mpi_core_exp_mod_working_limbs(size_t AN_limbs, size_t E_limbs) +{ + const size_t wsize = exp_mod_get_window_size(E_limbs * biL); + const size_t welem = ((size_t) 1) << wsize; + + /* How big does each part of the working memory pool need to be? */ + const size_t table_limbs = welem * AN_limbs; + const size_t select_limbs = AN_limbs; + const size_t temp_limbs = 2 * AN_limbs + 1; + + return table_limbs + select_limbs + temp_limbs; +} + +static void exp_mod_precompute_window(const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *N, + size_t AN_limbs, + mbedtls_mpi_uint mm, + const mbedtls_mpi_uint *RR, + size_t welem, + mbedtls_mpi_uint *Wtable, + mbedtls_mpi_uint *temp) +{ + /* W[0] = 1 (in Montgomery presentation) */ + memset(Wtable, 0, AN_limbs * ciL); + Wtable[0] = 1; + mbedtls_mpi_core_montmul(Wtable, Wtable, RR, AN_limbs, N, AN_limbs, mm, temp); + + /* W[1] = A (already in Montgomery presentation) */ + mbedtls_mpi_uint *W1 = Wtable + AN_limbs; + memcpy(W1, A, AN_limbs * ciL); + + /* W[i+1] = W[i] * W[1], i >= 2 */ + mbedtls_mpi_uint *Wprev = W1; + for (size_t i = 2; i < welem; i++) { + mbedtls_mpi_uint *Wcur = Wprev + AN_limbs; + mbedtls_mpi_core_montmul(Wcur, Wprev, W1, AN_limbs, N, AN_limbs, mm, temp); + Wprev = Wcur; + } +} + +#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C) +void (*mbedtls_safe_codepath_hook)(void) = NULL; +void (*mbedtls_unsafe_codepath_hook)(void) = NULL; +#endif + +/* + * This function calculates the indices of the exponent where the exponentiation algorithm should + * start processing. + * + * Warning! If the parameter E_public has MBEDTLS_MPI_IS_PUBLIC as its value, + * this function is not constant time with respect to the exponent (parameter E). + */ +static inline void exp_mod_calc_first_bit_optionally_safe(const mbedtls_mpi_uint *E, + size_t E_limbs, + int E_public, + size_t *E_limb_index, + size_t *E_bit_index) +{ + if (E_public == MBEDTLS_MPI_IS_PUBLIC) { + /* + * Skip leading zero bits. + */ + size_t E_bits = mbedtls_mpi_core_bitlen(E, E_limbs); + if (E_bits == 0) { + /* + * If E is 0 mbedtls_mpi_core_bitlen() returns 0. Even if that is the case, we will want + * to represent it as a single 0 bit and as such the bitlength will be 1. + */ + E_bits = 1; + } + + *E_limb_index = E_bits / biL; + *E_bit_index = E_bits % biL; + +#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C) + if (mbedtls_unsafe_codepath_hook != NULL) { + mbedtls_unsafe_codepath_hook(); + } +#endif + } else { + /* + * Here we need to be constant time with respect to E and can't do anything better than + * start at the first allocated bit. + */ + *E_limb_index = E_limbs; + *E_bit_index = 0; +#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C) + if (mbedtls_safe_codepath_hook != NULL) { + mbedtls_safe_codepath_hook(); + } +#endif + } +} + +/* + * Warning! If the parameter window_public has MBEDTLS_MPI_IS_PUBLIC as its value, this function is + * not constant time with respect to the window parameter and consequently the exponent of the + * exponentiation (parameter E of mbedtls_mpi_core_exp_mod_optionally_safe). + */ +static inline void exp_mod_table_lookup_optionally_safe(mbedtls_mpi_uint *Wselect, + mbedtls_mpi_uint *Wtable, + size_t AN_limbs, size_t welem, + mbedtls_mpi_uint window, + int window_public) +{ + if (window_public == MBEDTLS_MPI_IS_PUBLIC) { + memcpy(Wselect, Wtable + window * AN_limbs, AN_limbs * ciL); +#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C) + if (mbedtls_unsafe_codepath_hook != NULL) { + mbedtls_unsafe_codepath_hook(); + } +#endif + } else { + /* Select Wtable[window] without leaking window through + * memory access patterns. */ + mbedtls_mpi_core_ct_uint_table_lookup(Wselect, Wtable, + AN_limbs, welem, window); +#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C) + if (mbedtls_safe_codepath_hook != NULL) { + mbedtls_safe_codepath_hook(); + } +#endif + } +} + +/* Exponentiation: X := A^E mod N. + * + * Warning! If the parameter E_public has MBEDTLS_MPI_IS_PUBLIC as its value, + * this function is not constant time with respect to the exponent (parameter E). + * + * A must already be in Montgomery form. + * + * As in other bignum functions, assume that AN_limbs and E_limbs are nonzero. + * + * RR must contain 2^{2*biL} mod N. + * + * The algorithm is a variant of Left-to-right k-ary exponentiation: HAC 14.82 + * (The difference is that the body in our loop processes a single bit instead + * of a full window.) + */ +static void mbedtls_mpi_core_exp_mod_optionally_safe(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *N, + size_t AN_limbs, + const mbedtls_mpi_uint *E, + size_t E_limbs, + int E_public, + const mbedtls_mpi_uint *RR, + mbedtls_mpi_uint *T) +{ + /* We'll process the bits of E from most significant + * (limb_index=E_limbs-1, E_bit_index=biL-1) to least significant + * (limb_index=0, E_bit_index=0). */ + size_t E_limb_index = E_limbs; + size_t E_bit_index = 0; + exp_mod_calc_first_bit_optionally_safe(E, E_limbs, E_public, + &E_limb_index, &E_bit_index); + + const size_t wsize = exp_mod_get_window_size(E_limb_index * biL); + const size_t welem = ((size_t) 1) << wsize; + + /* This is how we will use the temporary storage T, which must have space + * for table_limbs, select_limbs and (2 * AN_limbs + 1) for montmul. */ + const size_t table_limbs = welem * AN_limbs; + const size_t select_limbs = AN_limbs; + + /* Pointers to specific parts of the temporary working memory pool */ + mbedtls_mpi_uint *const Wtable = T; + mbedtls_mpi_uint *const Wselect = Wtable + table_limbs; + mbedtls_mpi_uint *const temp = Wselect + select_limbs; + + /* + * Window precomputation + */ + + const mbedtls_mpi_uint mm = mbedtls_mpi_core_montmul_init(N); + + /* Set Wtable[i] = A^i (in Montgomery representation) */ + exp_mod_precompute_window(A, N, AN_limbs, + mm, RR, + welem, Wtable, temp); + + /* + * Fixed window exponentiation + */ + + /* X = 1 (in Montgomery presentation) initially */ + memcpy(X, Wtable, AN_limbs * ciL); + + /* At any given time, window contains window_bits bits from E. + * window_bits can go up to wsize. */ + size_t window_bits = 0; + mbedtls_mpi_uint window = 0; + + do { + /* Square */ + mbedtls_mpi_core_montmul(X, X, X, AN_limbs, N, AN_limbs, mm, temp); + + /* Move to the next bit of the exponent */ + if (E_bit_index == 0) { + --E_limb_index; + E_bit_index = biL - 1; + } else { + --E_bit_index; + } + /* Insert next exponent bit into window */ + ++window_bits; + window <<= 1; + window |= (E[E_limb_index] >> E_bit_index) & 1; + + /* Clear window if it's full. Also clear the window at the end, + * when we've finished processing the exponent. */ + if (window_bits == wsize || + (E_bit_index == 0 && E_limb_index == 0)) { + + exp_mod_table_lookup_optionally_safe(Wselect, Wtable, AN_limbs, welem, + window, E_public); + /* Multiply X by the selected element. */ + mbedtls_mpi_core_montmul(X, X, Wselect, AN_limbs, N, AN_limbs, mm, + temp); + window = 0; + window_bits = 0; + } + } while (!(E_bit_index == 0 && E_limb_index == 0)); +} + +void mbedtls_mpi_core_exp_mod(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *N, size_t AN_limbs, + const mbedtls_mpi_uint *E, size_t E_limbs, + const mbedtls_mpi_uint *RR, + mbedtls_mpi_uint *T) +{ + mbedtls_mpi_core_exp_mod_optionally_safe(X, + A, + N, + AN_limbs, + E, + E_limbs, + MBEDTLS_MPI_IS_SECRET, + RR, + T); +} + +void mbedtls_mpi_core_exp_mod_unsafe(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *N, size_t AN_limbs, + const mbedtls_mpi_uint *E, size_t E_limbs, + const mbedtls_mpi_uint *RR, + mbedtls_mpi_uint *T) +{ + mbedtls_mpi_core_exp_mod_optionally_safe(X, + A, + N, + AN_limbs, + E, + E_limbs, + MBEDTLS_MPI_IS_PUBLIC, + RR, + T); +} + +mbedtls_mpi_uint mbedtls_mpi_core_sub_int(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + mbedtls_mpi_uint c, /* doubles as carry */ + size_t limbs) +{ + for (size_t i = 0; i < limbs; i++) { + mbedtls_mpi_uint s = A[i]; + mbedtls_mpi_uint t = s - c; + c = (t > s); + X[i] = t; + } + + return c; +} + +mbedtls_ct_condition_t mbedtls_mpi_core_check_zero_ct(const mbedtls_mpi_uint *A, + size_t limbs) +{ + volatile const mbedtls_mpi_uint *force_read_A = A; + mbedtls_mpi_uint bits = 0; + + for (size_t i = 0; i < limbs; i++) { + bits |= force_read_A[i]; + } + + return mbedtls_ct_bool(bits); +} + +void mbedtls_mpi_core_to_mont_rep(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *N, + size_t AN_limbs, + mbedtls_mpi_uint mm, + const mbedtls_mpi_uint *rr, + mbedtls_mpi_uint *T) +{ + mbedtls_mpi_core_montmul(X, A, rr, AN_limbs, N, AN_limbs, mm, T); +} + +void mbedtls_mpi_core_from_mont_rep(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *N, + size_t AN_limbs, + mbedtls_mpi_uint mm, + mbedtls_mpi_uint *T) +{ + const mbedtls_mpi_uint Rinv = 1; /* 1/R in Mont. rep => 1 */ + + mbedtls_mpi_core_montmul(X, A, &Rinv, 1, N, AN_limbs, mm, T); +} + +/* + * Compute X = A - B mod N. + * Both A and B must be in [0, N) and so will the output. + */ +static void mpi_core_sub_mod(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + const mbedtls_mpi_uint *N, + size_t limbs) +{ + mbedtls_mpi_uint c = mbedtls_mpi_core_sub(X, A, B, limbs); + (void) mbedtls_mpi_core_add_if(X, N, limbs, (unsigned) c); +} + +/* + * Divide X by 2 mod N in place, assuming N is odd. + * The input must be in [0, N) and so will the output. + */ +MBEDTLS_STATIC_TESTABLE +void mbedtls_mpi_core_div2_mod_odd(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *N, + size_t limbs) +{ + /* If X is odd, add N to make it even before shifting. */ + unsigned odd = (unsigned) X[0] & 1; + mbedtls_mpi_uint c = mbedtls_mpi_core_add_if(X, N, limbs, odd); + mbedtls_mpi_core_shift_r(X, limbs, 1); + X[limbs - 1] |= c << (biL - 1); +} + +/* + * Constant-time GCD and modular inversion - odd modulus. + * + * Pre-conditions: see public documentation. + * + * See https://www.jstage.jst.go.jp/article/transinf/E106.D/9/E106.D_2022ICP0009/_pdf + * + * The paper gives two computationally equivalent algorithms: Alg 7 (readable) + * and Alg 8 (constant-time). We use a third version that's hopefully both: + * + * u, v = A, N # N is called p in the paper but doesn't have to be prime + * q, r = 0, 1 + * repeat bits(A_limbs + N_limbs) times: + * d = v - u # t1 in Alg 7 + * t1 = (u and v both odd) ? u : d # t1 in Alg 8 + * t2 = (u and v both odd) ? d : (u odd) ? v : u # t2 in Alg 8 + * t2 >>= 1 + * swap = t1 > t2 # similar to s, z in Alg 8 + * u, v = (swap) ? t2, t1 : t1, t2 + * + * d = r - q mod N # t2 in Alg 7 + * t1 = (u and v both odd) ? q : d # t3 in Alg 8 + * t2 = (u and v both odd) ? d : (u odd) ? r : q # t4 Alg 8 + * t2 /= 2 mod N # see below (pre_com) + * q, r = (swap) ? t2, t1 : t1, t2 + * return v, q # v: GCD, see Alg 6; q: no mult by pre_com, see below + * + * The ternary operators in the above pseudo-code need to be realised in a + * constant-time fashion. We use conditional assign for t1, t2 and conditional + * swap for the final update. (Note: the similarity between branches of Alg 7 + * are highlighted in tables 2 and 3 and the surrounding text.) + * + * Also, we re-order operations, grouping things related to the inverse, which + * facilitates making its computation optional, and requires fewer temporaries. + * + * The only actual change from the paper is dropping the trick with pre_com, + * which I think complicates things for no benefit. + * See the comment on the big I != NULL block below for details. + */ +void mbedtls_mpi_core_gcd_modinv_odd(mbedtls_mpi_uint *G, + mbedtls_mpi_uint *I, + const mbedtls_mpi_uint *A, + size_t A_limbs, + const mbedtls_mpi_uint *N, + size_t N_limbs, + mbedtls_mpi_uint *T) +{ + /* GCD and modinv, names common to Alg 7 and Alg 8 */ + mbedtls_mpi_uint *u = T + 0 * N_limbs; + mbedtls_mpi_uint *v = G; + + /* GCD and modinv, my name (t1, t2 from Alg 7) */ + mbedtls_mpi_uint *d = T + 1 * N_limbs; + + /* GCD and modinv, names from Alg 8 (note: t1, t2 from Alg 7 are d above) */ + mbedtls_mpi_uint *t1 = T + 2 * N_limbs; + mbedtls_mpi_uint *t2 = T + 3 * N_limbs; + + /* modinv only, names common to Alg 7 and Alg 8 */ + mbedtls_mpi_uint *q = I; + mbedtls_mpi_uint *r = I != NULL ? T + 4 * N_limbs : NULL; + + /* + * Initial values: + * u, v = A, N + * q, r = 0, 1 + * + * We only write to G (aka v) after reading from inputs (A and N), which + * allows aliasing, except with N when I != NULL, as then we'll be operating + * mod N on q and r later - see the public documentation. + */ + if (A_limbs > N_limbs) { + /* Violating this precondition should not result in memory errors. */ + A_limbs = N_limbs; + } + memcpy(u, A, A_limbs * ciL); + memset((char *) u + A_limbs * ciL, 0, (N_limbs - A_limbs) * ciL); + + /* Avoid possible UB with memcpy when src == dst. */ + if (v != N) { + memcpy(v, N, N_limbs * ciL); + } + + if (I != NULL) { + memset(q, 0, N_limbs * ciL); + + memset(r, 0, N_limbs * ciL); + r[0] = 1; + } + + /* + * At each step, out of u, v, v - u we keep one, shift another, and discard + * the third, then update (u, v) with the ordered result. + * Then we mirror those actions with q, r, r - q mod N. + * + * Loop invariants: + * u <= v (on entry: A <= N) + * GCD(u, v) == GCD(A, N) (on entry: trivial) + * v = A * q mod N (on entry: N = A * 0 mod N) + * u = A * r mod N (on entry: A = A * 1 mod N) + * q, r in [0, N) (on entry: 0, 1) + * + * On exit: + * u = 0 + * v = GCD(A, N) = A * q mod N + * if v == 1 then 1 = A * q mod N ie q is A's inverse mod N + * r = 0 + * + * The exit state is a fixed point of the loop's body. + * Alg 7 and Alg 8 use 2 * bitlen(N) iterations but Theorem 2 (above in the + * paper) says bitlen(A) + bitlen(N) is actually enough. + */ + for (size_t i = 0; i < (A_limbs + N_limbs) * biL; i++) { + /* s, z in Alg 8 - use meaningful names instead */ + mbedtls_ct_condition_t u_odd = mbedtls_ct_bool(u[0] & 1); + mbedtls_ct_condition_t v_odd = mbedtls_ct_bool(v[0] & 1); + + /* Other conditions that will be useful below */ + mbedtls_ct_condition_t u_odd_v_odd = mbedtls_ct_bool_and(u_odd, v_odd); + mbedtls_ct_condition_t v_even = mbedtls_ct_bool_not(v_odd); + mbedtls_ct_condition_t u_odd_v_even = mbedtls_ct_bool_and(u_odd, v_even); + + /* This is called t1 in Alg 7 (no name in Alg 8). + * We know that u <= v so there is no carry */ + (void) mbedtls_mpi_core_sub(d, v, u, N_limbs); + + /* t1 (the thing that's kept) can be d (default) or u (if t2 is d) */ + memcpy(t1, d, N_limbs * ciL); + mbedtls_mpi_core_cond_assign(t1, u, N_limbs, u_odd_v_odd); + + /* t2 (the thing that's shifted) can be u (if even), or v (if even), + * or d (which is even if both u and v were odd) */ + memcpy(t2, u, N_limbs * ciL); + mbedtls_mpi_core_cond_assign(t2, v, N_limbs, u_odd_v_even); + mbedtls_mpi_core_cond_assign(t2, d, N_limbs, u_odd_v_odd); + + mbedtls_mpi_core_shift_r(t2, N_limbs, 1); // t2 is even + + /* Update u, v and re-order them if needed */ + memcpy(u, t1, N_limbs * ciL); + memcpy(v, t2, N_limbs * ciL); + mbedtls_ct_condition_t swap = mbedtls_mpi_core_lt_ct(v, u, N_limbs); + mbedtls_mpi_core_cond_swap(u, v, N_limbs, swap); + + /* Now, if modinv was requested, do the same with q, r, but: + * - decisions still based on u and v (their initial values); + * - operations are now mod N; + * - we re-use t1, t2 for what the paper calls t3, t4 in Alg 8. + * + * Here we slightly diverge from the paper and instead do the obvious + * thing that preserves the invariants involving q and r: mirror + * operations on u and v, ie also divide by 2 here (mod N). + * + * The paper uses a trick where it replaces division by 2 with + * multiplication by 2 here, and compensates in the end by multiplying + * by pre_com, which is probably intended as an optimisation. + * + * However I believe it's not actually an optimisation, since + * constant-time modular multiplication by 2 (left-shift + conditional + * subtract) is just as costly as constant-time modular division by 2 + * (conditional add + right-shift). So, skip it and keep things simple. + */ + if (I != NULL) { + /* This is called t2 in Alg 7 (no name in Alg 8). */ + mpi_core_sub_mod(d, q, r, N, N_limbs); + + /* t3 (the thing that's kept) */ + memcpy(t1, d, N_limbs * ciL); + mbedtls_mpi_core_cond_assign(t1, r, N_limbs, u_odd_v_odd); + + /* t4 (the thing that's shifted) */ + memcpy(t2, r, N_limbs * ciL); + mbedtls_mpi_core_cond_assign(t2, q, N_limbs, u_odd_v_even); + mbedtls_mpi_core_cond_assign(t2, d, N_limbs, u_odd_v_odd); + + mbedtls_mpi_core_div2_mod_odd(t2, N, N_limbs); + + /* Update and possibly swap */ + memcpy(r, t1, N_limbs * ciL); + memcpy(q, t2, N_limbs * ciL); + mbedtls_mpi_core_cond_swap(r, q, N_limbs, swap); + } + } + + /* G and I already hold the correct values by virtue of being aliased */ +} + +#endif /* MBEDTLS_BIGNUM_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/bignum_core.h b/tf-psa-crypto/drivers/builtin/src/bignum_core.h new file mode 100644 index 0000000000..72b6332e43 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/bignum_core.h @@ -0,0 +1,879 @@ +/** + * Core bignum functions + * + * This interface should only be used by the legacy bignum module (bignum.h) + * and the modular bignum modules (bignum_mod.c, bignum_mod_raw.c). All other + * modules should use the high-level modular bignum interface (bignum_mod.h) + * or the legacy bignum interface (bignum.h). + * + * This module is about processing non-negative integers with a fixed upper + * bound that's of the form 2^n-1 where n is a multiple of #biL. + * These can be thought of integers written in base 2^#biL with a fixed + * number of digits. Digits in this base are called *limbs*. + * Many operations treat these numbers as the principal representation of + * a number modulo 2^n or a smaller bound. + * + * The functions in this module obey the following conventions unless + * explicitly indicated otherwise: + * + * - **Overflow**: some functions indicate overflow from the range + * [0, 2^n-1] by returning carry parameters, while others operate + * modulo and so cannot overflow. This should be clear from the function + * documentation. + * - **Bignum parameters**: Bignums are passed as pointers to an array of + * limbs. A limb has the type #mbedtls_mpi_uint. Unless otherwise specified: + * - Bignum parameters called \p A, \p B, ... are inputs, and are + * not modified by the function. + * - For operations modulo some number, the modulus is called \p N + * and is input-only. + * - Bignum parameters called \p X, \p Y are outputs or input-output. + * The initial content of output-only parameters is ignored. + * - Some functions use different names that reflect traditional + * naming of operands of certain operations (e.g. + * divisor/dividend/quotient/remainder). + * - \p T is a temporary storage area. The initial content of such + * parameter is ignored and the final content is unspecified. + * - **Bignum sizes**: bignum sizes are always expressed in limbs. + * Most functions work on bignums of a given size and take a single + * \p limbs parameter that applies to all parameters that are limb arrays. + * All bignum sizes must be at least 1 and must be significantly less than + * #SIZE_MAX. The behavior if a size is 0 is undefined. The behavior if the + * total size of all parameters overflows #SIZE_MAX is undefined. + * - **Parameter ordering**: for bignum parameters, outputs come before inputs. + * Temporaries come last. + * - **Aliasing**: in general, output bignums may be aliased to one or more + * inputs. As an exception, parameters that are documented as a modulus value + * may not be aliased to an output. Outputs may not be aliased to one another. + * Temporaries may not be aliased to any other parameter. + * - **Overlap**: apart from aliasing of limb array pointers (where two + * arguments are equal pointers), overlap is not supported and may result + * in undefined behavior. + * - **Error handling**: This is a low-level module. Functions generally do not + * try to protect against invalid arguments such as nonsensical sizes or + * null pointers. Note that some functions that operate on bignums of + * different sizes have constraints about their size, and violating those + * constraints may lead to buffer overflows. + * - **Modular representatives**: functions that operate modulo \p N expect + * all modular inputs to be in the range [0, \p N - 1] and guarantee outputs + * in the range [0, \p N - 1]. If an input is out of range, outputs are + * fully unspecified, though bignum values out of range should not cause + * buffer overflows (beware that this is not extensively tested). + */ + +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_BIGNUM_CORE_H +#define TF_PSA_CRYPTO_BIGNUM_CORE_H + +#include "tf_psa_crypto_common.h" + +#include "mbedtls/private/bignum.h" + +#include "constant_time_internal.h" + +#define ciL (sizeof(mbedtls_mpi_uint)) /** chars in limb */ +#define biL (ciL << 3) /** bits in limb */ +#define biH (ciL << 2) /** half limb size */ + +/* + * Convert between bits/chars and number of limbs + * Divide first in order to avoid potential overflows + */ +#define BITS_TO_LIMBS(i) ((i) / biL + ((i) % biL != 0)) +#define CHARS_TO_LIMBS(i) ((i) / ciL + ((i) % ciL != 0)) +/* Get a specific byte, without range checks. */ +#define GET_BYTE(X, i) \ + (((X)[(i) / ciL] >> (((i) % ciL) * 8)) & 0xff) + +/* Constants to identify whether a value is public or secret. If a parameter is marked as secret by + * this constant, the function must be constant time with respect to the parameter. + * + * This is only needed for functions with the _optionally_safe postfix. All other functions have + * fixed behavior that can't be changed at runtime and are constant time with respect to their + * parameters as prescribed by their documentation or by conventions in their module's documentation. + * + * Parameters should be named X_public where X is the name of the + * corresponding input parameter. + * + * Implementation should always check using + * if (X_public == MBEDTLS_MPI_IS_PUBLIC) { + * // unsafe path + * } else { + * // safe path + * } + * not the other way round, in order to prevent misuse. (That is, if a value + * other than the two below is passed, default to the safe path.) + * + * The value of MBEDTLS_MPI_IS_PUBLIC is chosen in a way that is unlikely to happen by accident, but + * which can be used as an immediate value in a Thumb2 comparison (for code size). */ +#define MBEDTLS_MPI_IS_PUBLIC 0x2a2a2a2a +#define MBEDTLS_MPI_IS_SECRET 0 +#if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C) +// Default value for testing that is neither MBEDTLS_MPI_IS_PUBLIC nor MBEDTLS_MPI_IS_SECRET +#define MBEDTLS_MPI_IS_TEST 1 +#endif + +/** Count leading zero bits in a given integer. + * + * \warning The result is undefined if \p a == 0 + * + * \param a Integer to count leading zero bits. + * + * \return The number of leading zero bits in \p a, if \p a != 0. + * If \p a == 0, the result is undefined. + */ +size_t mbedtls_mpi_core_clz(mbedtls_mpi_uint a); + +/** Return the minimum number of bits required to represent the value held + * in the MPI. + * + * \note This function returns 0 if all the limbs of \p A are 0. + * + * \param[in] A The address of the MPI. + * \param A_limbs The number of limbs of \p A. + * + * \return The number of bits in \p A. + */ +size_t mbedtls_mpi_core_bitlen(const mbedtls_mpi_uint *A, size_t A_limbs); + +/** Convert a big-endian byte array aligned to the size of mbedtls_mpi_uint + * into the storage form used by mbedtls_mpi. + * + * \param[in,out] A The address of the MPI. + * \param A_limbs The number of limbs of \p A. + */ +void mbedtls_mpi_core_bigendian_to_host(mbedtls_mpi_uint *A, + size_t A_limbs); + +/** \brief Compare a machine integer with an MPI. + * + * This function operates in constant time with respect + * to the values of \p min and \p A. + * + * \param min A machine integer. + * \param[in] A An MPI. + * \param A_limbs The number of limbs of \p A. + * This must be at least 1. + * + * \return MBEDTLS_CT_TRUE if \p min is less than or equal to \p A, otherwise MBEDTLS_CT_FALSE. + */ +mbedtls_ct_condition_t mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min, + const mbedtls_mpi_uint *A, + size_t A_limbs); + +/** + * \brief Check if one unsigned MPI is less than another in constant + * time. + * + * \param A The left-hand MPI. This must point to an array of limbs + * with the same allocated length as \p B. + * \param B The right-hand MPI. This must point to an array of limbs + * with the same allocated length as \p A. + * \param limbs The number of limbs in \p A and \p B. + * This must not be 0. + * + * \return MBEDTLS_CT_TRUE if \p A is less than \p B. + * MBEDTLS_CT_FALSE if \p A is greater than or equal to \p B. + */ +mbedtls_ct_condition_t mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + size_t limbs); + +/** + * \brief Perform a safe conditional copy of an MPI which doesn't reveal + * whether assignment was done or not. + * + * \param[out] X The address of the destination MPI. + * This must be initialized. Must have enough limbs to + * store the full value of \p A. + * \param[in] A The address of the source MPI. This must be initialized. + * \param limbs The number of limbs of \p A. + * \param assign The condition deciding whether to perform the + * assignment or not. Callers will need to use + * the constant time interface (e.g. `mbedtls_ct_bool()`) + * to construct this argument. + * + * \note This function avoids leaking any information about whether + * the assignment was done or not. + */ +void mbedtls_mpi_core_cond_assign(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + size_t limbs, + mbedtls_ct_condition_t assign); + +/** + * \brief Perform a safe conditional swap of two MPIs which doesn't reveal + * whether the swap was done or not. + * + * \param[in,out] X The address of the first MPI. + * This must be initialized. + * \param[in,out] Y The address of the second MPI. + * This must be initialized. + * \param limbs The number of limbs of \p X and \p Y. + * \param swap The condition deciding whether to perform + * the swap or not. + * + * \note This function avoids leaking any information about whether + * the swap was done or not. + */ +void mbedtls_mpi_core_cond_swap(mbedtls_mpi_uint *X, + mbedtls_mpi_uint *Y, + size_t limbs, + mbedtls_ct_condition_t swap); + +/** Import X from unsigned binary data, little-endian. + * + * The MPI needs to have enough limbs to store the full value (including any + * most significant zero bytes in the input). + * + * \param[out] X The address of the MPI. + * \param X_limbs The number of limbs of \p X. + * \param[in] input The input buffer to import from. + * \param input_length The length bytes of \p input. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p X isn't + * large enough to hold the value in \p input. + */ +int mbedtls_mpi_core_read_le(mbedtls_mpi_uint *X, + size_t X_limbs, + const unsigned char *input, + size_t input_length); + +/** Import X from unsigned binary data, big-endian. + * + * The MPI needs to have enough limbs to store the full value (including any + * most significant zero bytes in the input). + * + * \param[out] X The address of the MPI. + * May only be #NULL if \p X_limbs is 0 and \p input_length + * is 0. + * \param X_limbs The number of limbs of \p X. + * \param[in] input The input buffer to import from. + * May only be #NULL if \p input_length is 0. + * \param input_length The length in bytes of \p input. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p X isn't + * large enough to hold the value in \p input. + */ +int mbedtls_mpi_core_read_be(mbedtls_mpi_uint *X, + size_t X_limbs, + const unsigned char *input, + size_t input_length); + +/** Export A into unsigned binary data, little-endian. + * + * \note If \p output is shorter than \p A the export is still successful if the + * value held in \p A fits in the buffer (that is, if enough of the most + * significant bytes of \p A are 0). + * + * \param[in] A The address of the MPI. + * \param A_limbs The number of limbs of \p A. + * \param[out] output The output buffer to export to. + * \param output_length The length in bytes of \p output. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p output isn't + * large enough to hold the value of \p A. + */ +int mbedtls_mpi_core_write_le(const mbedtls_mpi_uint *A, + size_t A_limbs, + unsigned char *output, + size_t output_length); + +/** Export A into unsigned binary data, big-endian. + * + * \note If \p output is shorter than \p A the export is still successful if the + * value held in \p A fits in the buffer (that is, if enough of the most + * significant bytes of \p A are 0). + * + * \param[in] A The address of the MPI. + * \param A_limbs The number of limbs of \p A. + * \param[out] output The output buffer to export to. + * \param output_length The length in bytes of \p output. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p output isn't + * large enough to hold the value of \p A. + */ +int mbedtls_mpi_core_write_be(const mbedtls_mpi_uint *A, + size_t A_limbs, + unsigned char *output, + size_t output_length); + +/** \brief Shift an MPI in-place right by a number of bits. + * + * Shifting by more bits than there are bit positions + * in \p X is valid and results in setting \p X to 0. + * + * This function's execution time depends on the value + * of \p count (and of course \p limbs). + * + * \param[in,out] X The number to shift. + * \param limbs The number of limbs of \p X. This must be at least 1. + * \param count The number of bits to shift by. + */ +void mbedtls_mpi_core_shift_r(mbedtls_mpi_uint *X, size_t limbs, + size_t count); + +/** + * \brief Shift an MPI in-place left by a number of bits. + * + * Shifting by more bits than there are bit positions + * in \p X will produce an unspecified result. + * + * This function's execution time depends on the value + * of \p count (and of course \p limbs). + * \param[in,out] X The number to shift. + * \param limbs The number of limbs of \p X. This must be at least 1. + * \param count The number of bits to shift by. + */ +void mbedtls_mpi_core_shift_l(mbedtls_mpi_uint *X, size_t limbs, + size_t count); + +/** + * \brief Add two fixed-size large unsigned integers, returning the carry. + * + * Calculates `A + B` where `A` and `B` have the same size. + * + * This function operates modulo `2^(biL*limbs)` and returns the carry + * (1 if there was a wraparound, and 0 otherwise). + * + * \p X may be aliased to \p A or \p B. + * + * \param[out] X The result of the addition. + * \param[in] A Little-endian presentation of the left operand. + * \param[in] B Little-endian presentation of the right operand. + * \param limbs Number of limbs of \p X, \p A and \p B. + * + * \return 1 if `A + B >= 2^(biL*limbs)`, 0 otherwise. + */ +mbedtls_mpi_uint mbedtls_mpi_core_add(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + size_t limbs); + +/** + * \brief Conditional addition of two fixed-size large unsigned integers, + * returning the carry. + * + * Functionally equivalent to + * + * ``` + * if( cond ) + * X += A; + * return carry; + * ``` + * + * This function operates modulo `2^(biL*limbs)`. + * + * \param[in,out] X The pointer to the (little-endian) array + * representing the bignum to accumulate onto. + * \param[in] A The pointer to the (little-endian) array + * representing the bignum to conditionally add + * to \p X. This may be aliased to \p X but may not + * overlap otherwise. + * \param limbs Number of limbs of \p X and \p A. + * \param cond Condition bit dictating whether addition should + * happen or not. This must be \c 0 or \c 1. + * + * \warning If \p cond is neither 0 nor 1, the result of this function + * is unspecified, and the resulting value in \p X might be + * neither its original value nor \p X + \p A. + * + * \return 1 if `X + cond * A >= 2^(biL*limbs)`, 0 otherwise. + */ +mbedtls_mpi_uint mbedtls_mpi_core_add_if(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + size_t limbs, + unsigned cond); + +/** + * \brief Subtract two fixed-size large unsigned integers, returning the borrow. + * + * Calculate `A - B` where \p A and \p B have the same size. + * This function operates modulo `2^(biL*limbs)` and returns the carry + * (1 if there was a wraparound, i.e. if `A < B`, and 0 otherwise). + * + * \p X may be aliased to \p A or \p B, or even both, but may not overlap + * either otherwise. + * + * This function operates in constant time with respect to the values + * of \p A and \p B. + * + * \param[out] X The result of the subtraction. + * \param[in] A Little-endian presentation of left operand. + * \param[in] B Little-endian presentation of right operand. + * \param limbs Number of limbs of \p X, \p A and \p B. + * + * \return 1 if `A < B`. + * 0 if `A >= B`. + */ +mbedtls_mpi_uint mbedtls_mpi_core_sub(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + size_t limbs); + +/** + * \brief Perform a fixed-size multiply accumulate operation: X += b * A + * + * \p X may be aliased to \p A (when \p X_limbs == \p A_limbs), but may not + * otherwise overlap. + * + * This function operates modulo `2^(biL*X_limbs)`. + * + * This function operates in constant time with respect to the values + * of \p X and \p A and \p b. + * + * \param[in,out] X The pointer to the (little-endian) array + * representing the bignum to accumulate onto. + * \param X_limbs The number of limbs of \p X. This must be + * at least \p A_limbs. + * \param[in] A The pointer to the (little-endian) array + * representing the bignum to multiply with. + * This may be aliased to \p X but may not overlap + * otherwise. + * \param A_limbs The number of limbs of \p A. + * \param b X scalar to multiply with. + * + * \return The carry at the end of the operation. + */ +mbedtls_mpi_uint mbedtls_mpi_core_mla(mbedtls_mpi_uint *X, size_t X_limbs, + const mbedtls_mpi_uint *A, size_t A_limbs, + mbedtls_mpi_uint b); + +/** + * \brief Perform a known-size multiplication + * + * \p X may not be aliased to any of the inputs for this function. + * \p A may be aliased to \p B. + * + * \param[out] X The pointer to the (little-endian) array to receive + * the product of \p A_limbs and \p B_limbs. + * This must be of length \p A_limbs + \p B_limbs. + * \param[in] A The pointer to the (little-endian) array + * representing the first factor. + * \param A_limbs The number of limbs in \p A. + * \param[in] B The pointer to the (little-endian) array + * representing the second factor. + * \param B_limbs The number of limbs in \p B. + */ +void mbedtls_mpi_core_mul(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, size_t A_limbs, + const mbedtls_mpi_uint *B, size_t B_limbs); + +/** + * \brief Calculate initialisation value for fast Montgomery modular + * multiplication + * + * \param[in] N Little-endian presentation of the modulus. This must have + * at least one limb. + * + * \return The initialisation value for fast Montgomery modular multiplication + */ +mbedtls_mpi_uint mbedtls_mpi_core_montmul_init(const mbedtls_mpi_uint *N); + +/** + * \brief Montgomery multiplication: X = A * B * R^-1 mod N (HAC 14.36) + * + * \p A and \p B must be in canonical form. That is, < \p N. + * + * \p X may be aliased to \p A or \p N, or even \p B (if \p AN_limbs == + * \p B_limbs) but may not overlap any parameters otherwise. + * + * \p A and \p B may alias each other, if \p AN_limbs == \p B_limbs. They may + * not alias \p N (since they must be in canonical form, they cannot == \p N). + * + * This function operates in constant time with respect + * to the values of \p A, \p B and \p N. + * + * + * \param[out] X The destination MPI, as a little-endian array of + * length \p AN_limbs. + * On successful completion, X contains the result of + * the multiplication `A * B * R^-1` mod N where + * `R = 2^(biL*AN_limbs)`. + * \param[in] A Little-endian presentation of first operand. + * Must have the same number of limbs as \p N. + * \param[in] B Little-endian presentation of second operand. + * \param[in] B_limbs The number of limbs in \p B. + * Must be <= \p AN_limbs. + * \param[in] N Little-endian presentation of the modulus. + * This must be odd, and have exactly the same number + * of limbs as \p A. + * It may alias \p X, but must not alias or otherwise + * overlap any of the other parameters. + * \param[in] AN_limbs The number of limbs in \p X, \p A and \p N. + * \param mm The Montgomery constant for \p N: -N^-1 mod 2^biL. + * This can be calculated by `mbedtls_mpi_core_montmul_init()`. + * \param[in,out] T Temporary storage of size at least 2*AN_limbs+1 limbs. + * Its initial content is unused and + * its final content is indeterminate. + * It must not alias or otherwise overlap any of the + * other parameters. + */ +void mbedtls_mpi_core_montmul(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, size_t B_limbs, + const mbedtls_mpi_uint *N, size_t AN_limbs, + mbedtls_mpi_uint mm, mbedtls_mpi_uint *T); + +/** + * \brief Calculate the square of the Montgomery constant. (Needed + * for conversion and operations in Montgomery form.) + * + * \param[out] X A pointer to the result of the calculation of + * the square of the Montgomery constant: + * 2^{2*n*biL} mod N. + * \param[in] N Little-endian presentation of the modulus, which must be odd. + * + * \return 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if there is not enough space + * to store the value of Montgomery constant squared. + * \return #MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if \p N modulus is zero. + * \return #MBEDTLS_ERR_MPI_NEGATIVE_VALUE if \p N modulus is negative. + */ +int mbedtls_mpi_core_get_mont_r2_unsafe(mbedtls_mpi *X, + const mbedtls_mpi *N); + +#if defined(MBEDTLS_TEST_HOOKS) +/** + * Copy an MPI from a table without leaking the index. + * + * \param dest The destination buffer. This must point to a writable + * buffer of at least \p limbs limbs. + * \param table The address of the table. This must point to a readable + * array of \p count elements of \p limbs limbs each. + * \param limbs The number of limbs in each table entry. + * \param count The number of entries in \p table. + * \param index The (secret) table index to look up. This must be in the + * range `0 .. count-1`. + */ +void mbedtls_mpi_core_ct_uint_table_lookup(mbedtls_mpi_uint *dest, + const mbedtls_mpi_uint *table, + size_t limbs, + size_t count, + size_t index); +#endif /* MBEDTLS_TEST_HOOKS */ + +/** + * \brief Fill an integer with a number of random bytes. + * + * \param X The destination MPI. + * \param X_limbs The number of limbs of \p X. + * \param bytes The number of random bytes to generate. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context argument. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p X does not have + * enough room for \p bytes bytes. + * \return A negative error code on RNG failure. + * + * \note The bytes obtained from the RNG are interpreted + * as a big-endian representation of an MPI; this can + * be relevant in applications like deterministic ECDSA. + */ +int mbedtls_mpi_core_fill_random(mbedtls_mpi_uint *X, size_t X_limbs, + size_t bytes, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +/** Generate a random number uniformly in a range. + * + * This function generates a random number between \p min inclusive and + * \p N exclusive. + * + * The procedure complies with RFC 6979 §3.3 (deterministic ECDSA) + * when the RNG is a suitably parametrized instance of HMAC_DRBG + * and \p min is \c 1. + * + * \note There are `N - min` possible outputs. The lower bound + * \p min can be reached, but the upper bound \p N cannot. + * + * \param X The destination MPI, with \p limbs limbs. + * It must not be aliased with \p N or otherwise overlap it. + * \param min The minimum value to return. + * \param N The upper bound of the range, exclusive, with \p limbs limbs. + * In other words, this is one plus the maximum value to return. + * \p N must be strictly larger than \p min. + * \param limbs The number of limbs of \p N and \p X. + * This must not be 0. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if the implementation was + * unable to find a suitable value within a limited number + * of attempts. This has a negligible probability if \p N + * is significantly larger than \p min, which is the case + * for all usual cryptographic applications. + */ +int mbedtls_mpi_core_random(mbedtls_mpi_uint *X, + mbedtls_mpi_uint min, + const mbedtls_mpi_uint *N, + size_t limbs, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +/** + * \brief Returns the number of limbs of working memory required for + * a call to `mbedtls_mpi_core_exp_mod()`. + * + * \note This will always be at least + * `mbedtls_mpi_core_montmul_working_limbs(AN_limbs)`, + * i.e. sufficient for a call to `mbedtls_mpi_core_montmul()`. + * + * \param AN_limbs The number of limbs in the input `A` and the modulus `N` + * (they must be the same size) that will be given to + * `mbedtls_mpi_core_exp_mod()`. + * \param E_limbs The number of limbs in the exponent `E` that will be given + * to `mbedtls_mpi_core_exp_mod()`. + * + * \return The number of limbs of working memory required by + * `mbedtls_mpi_core_exp_mod()`. + */ +size_t mbedtls_mpi_core_exp_mod_working_limbs(size_t AN_limbs, size_t E_limbs); + +/** + * \brief Perform a modular exponentiation with public or secret exponent: + * X = A^E mod N, where \p A is already in Montgomery form. + * + * \warning This function is not constant time with respect to \p E (the exponent). + * + * \p X may be aliased to \p A, but not to \p RR or \p E, even if \p E_limbs == + * \p AN_limbs. + * + * \param[out] X The destination MPI, as a little endian array of length + * \p AN_limbs. + * \param[in] A The base MPI, as a little endian array of length \p AN_limbs. + * Must be in Montgomery form. + * \param[in] N The modulus, as a little endian array of length \p AN_limbs. + * \param AN_limbs The number of limbs in \p X, \p A, \p N, \p RR. + * \param[in] E The exponent, as a little endian array of length \p E_limbs. + * \param E_limbs The number of limbs in \p E. + * \param[in] RR The precomputed residue of 2^{2*biL} modulo N, as a little + * endian array of length \p AN_limbs. + * \param[in,out] T Temporary storage of at least the number of limbs returned + * by `mbedtls_mpi_core_exp_mod_working_limbs()`. + * Its initial content is unused and its final content is + * indeterminate. + * It must not alias or otherwise overlap any of the other + * parameters. + * It is up to the caller to zeroize \p T when it is no + * longer needed, and before freeing it if it was dynamically + * allocated. + */ +void mbedtls_mpi_core_exp_mod_unsafe(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *N, size_t AN_limbs, + const mbedtls_mpi_uint *E, size_t E_limbs, + const mbedtls_mpi_uint *RR, + mbedtls_mpi_uint *T); + +/** + * \brief Perform a modular exponentiation with secret exponent: + * X = A^E mod N, where \p A is already in Montgomery form. + * + * \p X may be aliased to \p A, but not to \p RR or \p E, even if \p E_limbs == + * \p AN_limbs. + * + * This function operates in constant time with respect + * to the values of \p A, \p N and \p E. + * + * \param[out] X The destination MPI, as a little endian array of length + * \p AN_limbs. + * \param[in] A The base MPI, as a little endian array of length \p AN_limbs. + * Must be in Montgomery form. + * \param[in] N The modulus, as a little endian array of length \p AN_limbs. + * \param AN_limbs The number of limbs in \p X, \p A, \p N, \p RR. + * \param[in] E The exponent, as a little endian array of length \p E_limbs. + * \param E_limbs The number of limbs in \p E. + * \param[in] RR The precomputed residue of 2^{2*biL} modulo N, as a little + * endian array of length \p AN_limbs. + * \param[in,out] T Temporary storage of at least the number of limbs returned + * by `mbedtls_mpi_core_exp_mod_working_limbs()`. + * Its initial content is unused and its final content is + * indeterminate. + * It must not alias or otherwise overlap any of the other + * parameters. + * It is up to the caller to zeroize \p T when it is no + * longer needed, and before freeing it if it was dynamically + * allocated. + */ +void mbedtls_mpi_core_exp_mod(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *N, size_t AN_limbs, + const mbedtls_mpi_uint *E, size_t E_limbs, + const mbedtls_mpi_uint *RR, + mbedtls_mpi_uint *T); + +/** + * \brief Subtract unsigned integer from known-size large unsigned integers. + * Return the borrow. + * + * \param[out] X The result of the subtraction. + * \param[in] A The left operand. + * \param b The unsigned scalar to subtract. + * \param limbs Number of limbs of \p X and \p A. + * + * \return 1 if `A < b`. + * 0 if `A >= b`. + */ +mbedtls_mpi_uint mbedtls_mpi_core_sub_int(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + mbedtls_mpi_uint b, + size_t limbs); + +/** + * \brief Determine if a given MPI has the value \c 0 in constant time with + * respect to the value (but not with respect to the number of limbs). + * + * \param[in] A The MPI to test. + * \param limbs Number of limbs in \p A. + * + * \return MBEDTLS_CT_FALSE if `A == 0` + * MBEDTLS_CT_TRUE if `A != 0`. + */ +mbedtls_ct_condition_t mbedtls_mpi_core_check_zero_ct(const mbedtls_mpi_uint *A, + size_t limbs); + +/** + * \brief Returns the number of limbs of working memory required for + * a call to `mbedtls_mpi_core_montmul()`. + * + * \param AN_limbs The number of limbs in the input `A` and the modulus `N` + * (they must be the same size) that will be given to + * `mbedtls_mpi_core_montmul()` or one of the other functions + * that specifies this as the amount of working memory needed. + * + * \return The number of limbs of working memory required by + * `mbedtls_mpi_core_montmul()` (or other similar function). + */ +static inline size_t mbedtls_mpi_core_montmul_working_limbs(size_t AN_limbs) +{ + return 2 * AN_limbs + 1; +} + +/** Convert an MPI into Montgomery form. + * + * \p X may be aliased to \p A, but may not otherwise overlap it. + * + * \p X may not alias \p N (it is in canonical form, so must be strictly less + * than \p N). Nor may it alias or overlap \p rr (this is unlikely to be + * required in practice.) + * + * This function is a thin wrapper around `mbedtls_mpi_core_montmul()` that is + * an alternative to calling `mbedtls_mpi_mod_raw_to_mont_rep()` when we + * don't want to allocate memory. + * + * \param[out] X The result of the conversion. + * Must have the same number of limbs as \p A. + * \param[in] A The MPI to convert into Montgomery form. + * Must have the same number of limbs as the modulus. + * \param[in] N The address of the modulus, which gives the size of + * the base `R` = 2^(biL*N->limbs). + * \param[in] AN_limbs The number of limbs in \p X, \p A, \p N and \p rr. + * \param mm The Montgomery constant for \p N: -N^-1 mod 2^biL. + * This can be determined by calling + * `mbedtls_mpi_core_montmul_init()`. + * \param[in] rr The residue for `2^{2*n*biL} mod N`. + * \param[in,out] T Temporary storage of size at least + * `mbedtls_mpi_core_montmul_working_limbs(AN_limbs)` + * limbs. + * Its initial content is unused and + * its final content is indeterminate. + * It must not alias or otherwise overlap any of the + * other parameters. + */ +void mbedtls_mpi_core_to_mont_rep(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *N, + size_t AN_limbs, + mbedtls_mpi_uint mm, + const mbedtls_mpi_uint *rr, + mbedtls_mpi_uint *T); + +/** Convert an MPI from Montgomery form. + * + * \p X may be aliased to \p A, but may not otherwise overlap it. + * + * \p X may not alias \p N (it is in canonical form, so must be strictly less + * than \p N). + * + * This function is a thin wrapper around `mbedtls_mpi_core_montmul()` that is + * an alternative to calling `mbedtls_mpi_mod_raw_from_mont_rep()` when we + * don't want to allocate memory. + * + * \param[out] X The result of the conversion. + * Must have the same number of limbs as \p A. + * \param[in] A The MPI to convert from Montgomery form. + * Must have the same number of limbs as the modulus. + * \param[in] N The address of the modulus, which gives the size of + * the base `R` = 2^(biL*N->limbs). + * \param[in] AN_limbs The number of limbs in \p X, \p A and \p N. + * \param mm The Montgomery constant for \p N: -N^-1 mod 2^biL. + * This can be determined by calling + * `mbedtls_mpi_core_montmul_init()`. + * \param[in,out] T Temporary storage of size at least + * `mbedtls_mpi_core_montmul_working_limbs(AN_limbs)` + * limbs. + * Its initial content is unused and + * its final content is indeterminate. + * It must not alias or otherwise overlap any of the + * other parameters. + */ +void mbedtls_mpi_core_from_mont_rep(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *N, + size_t AN_limbs, + mbedtls_mpi_uint mm, + mbedtls_mpi_uint *T); + +/** Compute GCD(A, N) and optionally the inverse of A mod N if it exists. + * + * Requires N to be odd, 0 <= A <= N and A_limbs <= N_limbs. + * When I != NULL, N (the modulus) must be greater than 1. + * + * A and N may not alias each other. + * When I == NULL (computing only the GCD), G may alias A or N. + * When I != NULL (computing the modular inverse), G or I may alias A + * but none of them may alias N (the modulus). + * + * If any of the above preconditions is not met, output values are unspecified. + * + * \param[out] G The GCD of \p A and \p N. + * Must have the same number of limbs as \p N. + * \param[out] I The inverse of \p A modulo \p N if it exists (that is, + * if \p G above is 1 on exit); indeterminate otherwise. + * This must either be NULL (to only compute the GCD), + * or have the same number of limbs as \p N. + * \param[in] A The 1st operand of GCD and number to invert. + * This value must be less than or equal to \p N. + * \param A_limbs The number of limbs of \p A. + * Must be less than or equal to \p N_limbs. + * \param[in] N The 2nd operand of GCD and modulus for inversion. + * This value must be odd. + * If I != NULL this value must be greater than 1. + * \param N_limbs The number of limbs of \p N. + * \param[in,out] T Temporary storage of size at least 5 * N_limbs limbs, + * or 4 * N_limbs if \p I is NULL (GCD only). + * Its initial content is unused and + * its final content is indeterminate. + * It must not alias or otherwise overlap any of the + * other parameters. + */ +void mbedtls_mpi_core_gcd_modinv_odd(mbedtls_mpi_uint *G, + mbedtls_mpi_uint *I, + const mbedtls_mpi_uint *A, + size_t A_limbs, + const mbedtls_mpi_uint *N, + size_t N_limbs, + mbedtls_mpi_uint *T); + +#endif /* TF_PSA_CRYPTO_BIGNUM_CORE_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/bignum_core_invasive.h b/tf-psa-crypto/drivers/builtin/src/bignum_core_invasive.h new file mode 100644 index 0000000000..9bc4041a92 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/bignum_core_invasive.h @@ -0,0 +1,38 @@ +/** + * \file bignum_core_invasive.h + * + * \brief Function declarations for invasive functions of bignum core. + */ +/** + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_BIGNUM_CORE_INVASIVE_H +#define TF_PSA_CRYPTO_BIGNUM_CORE_INVASIVE_H + +#include "bignum_core.h" + +#if defined(MBEDTLS_TEST_HOOKS) + +#if !defined(MBEDTLS_THREADING_C) + +extern void (*mbedtls_safe_codepath_hook)(void); +extern void (*mbedtls_unsafe_codepath_hook)(void); + +#endif /* !MBEDTLS_THREADING_C */ + +/** Divide X by 2 mod N in place, assuming N is odd. + * + * \param[in,out] X The value to divide by 2 mod \p N. + * \param[in] N The modulus. Must be odd. + * \param[in] limbs The number of limbs in \p X and \p N. + */ +MBEDTLS_STATIC_TESTABLE +void mbedtls_mpi_core_div2_mod_odd(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *N, + size_t limbs); + +#endif /* MBEDTLS_TEST_HOOKS */ + +#endif /* TF_PSA_CRYPTO_BIGNUM_CORE_INVASIVE_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/bignum_internal.h b/tf-psa-crypto/drivers/builtin/src/bignum_internal.h new file mode 100644 index 0000000000..7a14c0e8f9 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/bignum_internal.h @@ -0,0 +1,164 @@ +/** + * \file bignum_internal.h + * + * \brief Internal-only bignum public-key cryptosystem API. + * + * This file declares bignum-related functions that are to be used + * only from within the Mbed TLS library itself. + * + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_BIGNUM_INTERNAL_H +#define TF_PSA_CRYPTO_BIGNUM_INTERNAL_H + +#include "constant_time_internal.h" + +/** + * \brief Perform a modular exponentiation: X = A^E mod N + * + * \warning This function is not constant time with respect to \p E (the exponent). + * + * \param X The destination MPI. This must point to an initialized MPI. + * This must not alias E or N. + * \param A The base of the exponentiation. + * This must point to an initialized MPI. + * \param E The exponent MPI. This must point to an initialized MPI. + * \param N The base for the modular reduction. This must point to an + * initialized MPI. + * \param prec_RR A helper MPI depending solely on \p N which can be used to + * speed-up multiple modular exponentiations for the same value + * of \p N. This may be \c NULL. If it is not \c NULL, it must + * point to an initialized MPI. If it hasn't been used after + * the call to mbedtls_mpi_init(), this function will compute + * the helper value and store it in \p prec_RR for reuse on + * subsequent calls to this function. Otherwise, the function + * will assume that \p prec_RR holds the helper value set by a + * previous call to mbedtls_mpi_exp_mod(), and reuse it. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \c N is negative or + * even, or if \c E is negative. + * \return Another negative error code on different kinds of failures. + * + */ +int mbedtls_mpi_exp_mod_unsafe(mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *E, const mbedtls_mpi *N, + mbedtls_mpi *prec_RR); + +/** + * \brief A wrapper around a constant time function to compute + * GCD(A, N) and/or A^-1 mod N if it exists. + * + * \warning Requires N to be odd, and 0 <= A <= N. Additionally, if + * I != NULL, requires N > 1. + * The wrapper part of this function is not constant time. + * + * \note A and N must not alias each other. + * When I == NULL (computing only the GCD), G can alias A or N. + * When I != NULL (computing the modular inverse), G or I can + * alias A, but neither of them can alias N (the modulus). + * + * \param[out] G The GCD of \p A and \p N. + * This may be NULL, to only compute I. + * \param[out] I The inverse of \p A modulo \p N if it exists (that is, + * if \p G above is 1 on exit), in the range [1, \p N); + * indeterminate otherwise. + * This may be NULL, to only compute G. + * \param[in] A The 1st operand of GCD and number to invert. + * This value must be less than or equal to \p N. + * \param[in] N The 2nd operand of GCD and modulus for inversion. + * Must be odd or the results are indeterminate. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if preconditions were not + * met. + */ +int mbedtls_mpi_gcd_modinv_odd(mbedtls_mpi *G, + mbedtls_mpi *I, + const mbedtls_mpi *A, + const mbedtls_mpi *N); + +/** + * \brief Modular inverse: X = A^-1 mod N with N odd + * + * \param[out] X The inverse of \p A modulo \p N in the range [1, \p N) + * on success; indeterminate otherwise. + * \param[in] A The number to invert. + * \param[in] N The modulus. Must be odd and greater than 1. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if preconditions were not + * met. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if A is not invertible mod N. + */ +int mbedtls_mpi_inv_mod_odd(mbedtls_mpi *X, + const mbedtls_mpi *A, + const mbedtls_mpi *N); + +/** + * \brief Modular inverse: X = A^-1 mod N with N even, + * A odd and 1 < A < N. + * + * \param[out] X The inverse of \p A modulo \p N in the range [1, \p N) + * on success; indeterminate otherwise. + * \param[in] A The number to invert. Must be odd, greated than 1 + * and less than \p N. + * \param[in] N The modulus. Must be even and greater than 1. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if preconditions were not + * met. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if A is not invertible mod N. + */ +int mbedtls_mpi_inv_mod_even_in_range(mbedtls_mpi *X, + mbedtls_mpi const *A, + mbedtls_mpi const *N); + +/** Choose between two mbedtls_mpi_uint values. + * + * Functionally equivalent to: + * + * condition ? if1 : if0. + * + * \param condition Condition to test. + * \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE. + * \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE. + * + * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0. + */ +static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition, + mbedtls_mpi_uint if1, + mbedtls_mpi_uint if0) +{ + return (mbedtls_mpi_uint) mbedtls_ct_if(condition, + (mbedtls_ct_uint_t) if1, + (mbedtls_ct_uint_t) if0); +} + +/** Choose between an mbedtls_mpi_uint value and 0. + * + * Functionally equivalent to: + * + * condition ? if1 : 0. + * + * Functionally equivalent to mbedtls_ct_mpi_uint_if(condition, if1, 0) but + * results in smaller code size. + * + * \param condition Condition to test. + * \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE. + * + * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0. + */ +static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if_else_0( + mbedtls_ct_condition_t condition, mbedtls_mpi_uint if1) +{ + return (mbedtls_mpi_uint) (condition & if1); +} +#endif /* TF_PSA_CRYPTO_BIGNUM_INTERNAL_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/bignum_mod.c b/tf-psa-crypto/drivers/builtin/src/bignum_mod.c new file mode 100644 index 0000000000..63d0c483d9 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/bignum_mod.c @@ -0,0 +1,394 @@ +/** + * Modular bignum functions + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_BIGNUM_C) && defined(MBEDTLS_ECP_WITH_MPI_UINT) + +#include + +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" +#include "mbedtls/private/bignum.h" + +#include "mbedtls/platform.h" + +#include "bignum_core.h" +#include "bignum_mod.h" +#include "bignum_mod_raw.h" +#include "constant_time_internal.h" + +int mbedtls_mpi_mod_residue_setup(mbedtls_mpi_mod_residue *r, + const mbedtls_mpi_mod_modulus *N, + mbedtls_mpi_uint *p, + size_t p_limbs) +{ + if (p_limbs != N->limbs || !mbedtls_mpi_core_lt_ct(p, N->p, N->limbs)) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + r->limbs = N->limbs; + r->p = p; + + return 0; +} + +void mbedtls_mpi_mod_residue_release(mbedtls_mpi_mod_residue *r) +{ + if (r == NULL) { + return; + } + + r->limbs = 0; + r->p = NULL; +} + +void mbedtls_mpi_mod_modulus_init(mbedtls_mpi_mod_modulus *N) +{ + if (N == NULL) { + return; + } + + N->p = NULL; + N->limbs = 0; + N->bits = 0; + N->int_rep = MBEDTLS_MPI_MOD_REP_INVALID; +} + +void mbedtls_mpi_mod_modulus_free(mbedtls_mpi_mod_modulus *N) +{ + if (N == NULL) { + return; + } + + switch (N->int_rep) { + case MBEDTLS_MPI_MOD_REP_MONTGOMERY: + if (N->rep.mont.rr != NULL) { + mbedtls_zeroize_and_free((mbedtls_mpi_uint *) N->rep.mont.rr, + N->limbs * sizeof(mbedtls_mpi_uint)); + N->rep.mont.rr = NULL; + } + N->rep.mont.mm = 0; + break; + case MBEDTLS_MPI_MOD_REP_OPT_RED: + N->rep.ored.modp = NULL; + break; + case MBEDTLS_MPI_MOD_REP_INVALID: + break; + } + + N->p = NULL; + N->limbs = 0; + N->bits = 0; + N->int_rep = MBEDTLS_MPI_MOD_REP_INVALID; +} + +static int set_mont_const_square(const mbedtls_mpi_uint **X, + const mbedtls_mpi_uint *A, + size_t limbs) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi N; + mbedtls_mpi RR; + *X = NULL; + + mbedtls_mpi_init(&N); + mbedtls_mpi_init(&RR); + + if (A == NULL || limbs == 0 || limbs >= (MBEDTLS_MPI_MAX_LIMBS / 2) - 2) { + goto cleanup; + } + + if (mbedtls_mpi_grow(&N, limbs)) { + goto cleanup; + } + + memcpy(N.p, A, sizeof(mbedtls_mpi_uint) * limbs); + + ret = mbedtls_mpi_core_get_mont_r2_unsafe(&RR, &N); + + if (ret == 0) { + *X = RR.p; + RR.p = NULL; + } + +cleanup: + mbedtls_mpi_free(&N); + mbedtls_mpi_free(&RR); + ret = (ret != 0) ? MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED : 0; + return ret; +} + +static inline void standard_modulus_setup(mbedtls_mpi_mod_modulus *N, + const mbedtls_mpi_uint *p, + size_t p_limbs, + mbedtls_mpi_mod_rep_selector int_rep) +{ + N->p = p; + N->limbs = p_limbs; + N->bits = mbedtls_mpi_core_bitlen(p, p_limbs); + N->int_rep = int_rep; +} + +int mbedtls_mpi_mod_modulus_setup(mbedtls_mpi_mod_modulus *N, + const mbedtls_mpi_uint *p, + size_t p_limbs) +{ + int ret = 0; + standard_modulus_setup(N, p, p_limbs, MBEDTLS_MPI_MOD_REP_MONTGOMERY); + N->rep.mont.mm = mbedtls_mpi_core_montmul_init(N->p); + ret = set_mont_const_square(&N->rep.mont.rr, N->p, N->limbs); + + if (ret != 0) { + mbedtls_mpi_mod_modulus_free(N); + } + + return ret; +} + +int mbedtls_mpi_mod_optred_modulus_setup(mbedtls_mpi_mod_modulus *N, + const mbedtls_mpi_uint *p, + size_t p_limbs, + mbedtls_mpi_modp_fn modp) +{ + standard_modulus_setup(N, p, p_limbs, MBEDTLS_MPI_MOD_REP_OPT_RED); + N->rep.ored.modp = modp; + return 0; +} + +int mbedtls_mpi_mod_mul(mbedtls_mpi_mod_residue *X, + const mbedtls_mpi_mod_residue *A, + const mbedtls_mpi_mod_residue *B, + const mbedtls_mpi_mod_modulus *N) +{ + if (N->limbs == 0) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + if (X->limbs != N->limbs || A->limbs != N->limbs || B->limbs != N->limbs) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + mbedtls_mpi_uint *T = mbedtls_calloc(N->limbs * 2 + 1, ciL); + if (T == NULL) { + return MBEDTLS_ERR_MPI_ALLOC_FAILED; + } + + mbedtls_mpi_mod_raw_mul(X->p, A->p, B->p, N, T); + + mbedtls_free(T); + + return 0; +} + +int mbedtls_mpi_mod_sub(mbedtls_mpi_mod_residue *X, + const mbedtls_mpi_mod_residue *A, + const mbedtls_mpi_mod_residue *B, + const mbedtls_mpi_mod_modulus *N) +{ + if (X->limbs != N->limbs || A->limbs != N->limbs || B->limbs != N->limbs) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + mbedtls_mpi_mod_raw_sub(X->p, A->p, B->p, N); + + return 0; +} + +static int mbedtls_mpi_mod_inv_mont(mbedtls_mpi_mod_residue *X, + const mbedtls_mpi_mod_residue *A, + const mbedtls_mpi_mod_modulus *N, + mbedtls_mpi_uint *working_memory) +{ + /* Input already in Montgomery form, so there's little to do */ + mbedtls_mpi_mod_raw_inv_prime(X->p, A->p, + N->p, N->limbs, + N->rep.mont.rr, + working_memory); + return 0; +} + +static int mbedtls_mpi_mod_inv_non_mont(mbedtls_mpi_mod_residue *X, + const mbedtls_mpi_mod_residue *A, + const mbedtls_mpi_mod_modulus *N, + mbedtls_mpi_uint *working_memory) +{ + /* Need to convert input into Montgomery form */ + + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + mbedtls_mpi_mod_modulus Nmont; + mbedtls_mpi_mod_modulus_init(&Nmont); + + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_modulus_setup(&Nmont, N->p, N->limbs)); + + /* We'll use X->p to hold the Montgomery form of the input A->p */ + mbedtls_mpi_core_to_mont_rep(X->p, A->p, Nmont.p, Nmont.limbs, + Nmont.rep.mont.mm, Nmont.rep.mont.rr, + working_memory); + + mbedtls_mpi_mod_raw_inv_prime(X->p, X->p, + Nmont.p, Nmont.limbs, + Nmont.rep.mont.rr, + working_memory); + + /* And convert back from Montgomery form */ + + mbedtls_mpi_core_from_mont_rep(X->p, X->p, Nmont.p, Nmont.limbs, + Nmont.rep.mont.mm, working_memory); + +cleanup: + mbedtls_mpi_mod_modulus_free(&Nmont); + return ret; +} + +int mbedtls_mpi_mod_inv(mbedtls_mpi_mod_residue *X, + const mbedtls_mpi_mod_residue *A, + const mbedtls_mpi_mod_modulus *N) +{ + if (X->limbs != N->limbs || A->limbs != N->limbs) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + /* Zero has the same value regardless of Montgomery form or not */ + if (mbedtls_mpi_core_check_zero_ct(A->p, A->limbs) == 0) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + size_t working_limbs = + mbedtls_mpi_mod_raw_inv_prime_working_limbs(N->limbs); + + mbedtls_mpi_uint *working_memory = mbedtls_calloc(working_limbs, + sizeof(mbedtls_mpi_uint)); + if (working_memory == NULL) { + return MBEDTLS_ERR_MPI_ALLOC_FAILED; + } + + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + switch (N->int_rep) { + case MBEDTLS_MPI_MOD_REP_MONTGOMERY: + ret = mbedtls_mpi_mod_inv_mont(X, A, N, working_memory); + break; + case MBEDTLS_MPI_MOD_REP_OPT_RED: + ret = mbedtls_mpi_mod_inv_non_mont(X, A, N, working_memory); + break; + default: + ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + break; + } + + mbedtls_zeroize_and_free(working_memory, + working_limbs * sizeof(mbedtls_mpi_uint)); + + return ret; +} + +int mbedtls_mpi_mod_add(mbedtls_mpi_mod_residue *X, + const mbedtls_mpi_mod_residue *A, + const mbedtls_mpi_mod_residue *B, + const mbedtls_mpi_mod_modulus *N) +{ + if (X->limbs != N->limbs || A->limbs != N->limbs || B->limbs != N->limbs) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + mbedtls_mpi_mod_raw_add(X->p, A->p, B->p, N); + + return 0; +} + +int mbedtls_mpi_mod_random(mbedtls_mpi_mod_residue *X, + mbedtls_mpi_uint min, + const mbedtls_mpi_mod_modulus *N, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + if (X->limbs != N->limbs) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + return mbedtls_mpi_mod_raw_random(X->p, min, N, f_rng, p_rng); +} + +int mbedtls_mpi_mod_read(mbedtls_mpi_mod_residue *r, + const mbedtls_mpi_mod_modulus *N, + const unsigned char *buf, + size_t buflen, + mbedtls_mpi_mod_ext_rep ext_rep) +{ + int ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + + /* Do our best to check if r and m have been set up */ + if (r->limbs == 0 || N->limbs == 0) { + goto cleanup; + } + if (r->limbs != N->limbs) { + goto cleanup; + } + + ret = mbedtls_mpi_mod_raw_read(r->p, N, buf, buflen, ext_rep); + if (ret != 0) { + goto cleanup; + } + + r->limbs = N->limbs; + + ret = mbedtls_mpi_mod_raw_canonical_to_modulus_rep(r->p, N); + +cleanup: + return ret; +} + +int mbedtls_mpi_mod_write(const mbedtls_mpi_mod_residue *r, + const mbedtls_mpi_mod_modulus *N, + unsigned char *buf, + size_t buflen, + mbedtls_mpi_mod_ext_rep ext_rep) +{ + /* Do our best to check if r and m have been set up */ + if (r->limbs == 0 || N->limbs == 0) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + if (r->limbs != N->limbs) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi_uint *working_memory = r->p; + size_t working_memory_len = sizeof(mbedtls_mpi_uint) * r->limbs; + + if (N->int_rep == MBEDTLS_MPI_MOD_REP_MONTGOMERY) { + + working_memory = mbedtls_calloc(r->limbs, sizeof(mbedtls_mpi_uint)); + + if (working_memory == NULL) { + ret = MBEDTLS_ERR_MPI_ALLOC_FAILED; + goto cleanup; + } + + memcpy(working_memory, r->p, working_memory_len); + + ret = mbedtls_mpi_mod_raw_from_mont_rep(working_memory, N); + if (ret != 0) { + goto cleanup; + } + } + + ret = mbedtls_mpi_mod_raw_write(working_memory, N, buf, buflen, ext_rep); + +cleanup: + + if (N->int_rep == MBEDTLS_MPI_MOD_REP_MONTGOMERY && + working_memory != NULL) { + + mbedtls_zeroize_and_free(working_memory, working_memory_len); + } + + return ret; +} + +#endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ECP_WITH_MPI_UINT */ diff --git a/tf-psa-crypto/drivers/builtin/src/bignum_mod.h b/tf-psa-crypto/drivers/builtin/src/bignum_mod.h new file mode 100644 index 0000000000..6d2db59257 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/bignum_mod.h @@ -0,0 +1,452 @@ +/** + * Modular bignum functions + * + * This module implements operations on integers modulo some fixed modulus. + * + * The functions in this module obey the following conventions unless + * explicitly indicated otherwise: + * + * - **Modulus parameters**: the modulus is passed as a pointer to a structure + * of type #mbedtls_mpi_mod_modulus. The structure must be set up with an + * array of limbs storing the bignum value of the modulus. The modulus must + * be odd and is assumed to have no leading zeroes. The modulus is usually + * named \c N and is usually input-only. Functions which take a parameter + * of type \c const #mbedtls_mpi_mod_modulus* must not modify its value. + * - **Bignum parameters**: Bignums are passed as pointers to an array of + * limbs or to a #mbedtls_mpi_mod_residue structure. A limb has the type + * #mbedtls_mpi_uint. Residues must be initialized before use, and must be + * associated with the modulus \c N. Unless otherwise specified: + * - Bignum parameters called \c A, \c B, ... are inputs and are not + * modified by the function. Functions which take a parameter of + * type \c const #mbedtls_mpi_mod_residue* must not modify its value. + * - Bignum parameters called \c X, \c Y, ... are outputs or input-output. + * The initial bignum value of output-only parameters is ignored, but + * they must be set up and associated with the modulus \c N. Some + * functions (typically constant-flow) require that the limbs in an + * output residue are initialized. + * - Bignum parameters called \c p are inputs used to set up a modulus or + * residue. These must be pointers to an array of limbs. + * - \c T is a temporary storage area. The initial content of such a + * parameter is ignored and the final content is unspecified. + * - Some functions use different names, such as \c r for the residue. + * - **Bignum sizes**: bignum sizes are always expressed in limbs. Both + * #mbedtls_mpi_mod_modulus and #mbedtls_mpi_mod_residue have a \c limbs + * member storing its size. All bignum parameters must have the same + * number of limbs as the modulus. All bignum sizes must be at least 1 and + * must be significantly less than #SIZE_MAX. The behavior if a size is 0 is + * undefined. + * - **Bignum representation**: the representation of inputs and outputs is + * specified by the \c int_rep field of the modulus. + * - **Parameter ordering**: for bignum parameters, outputs come before inputs. + * The modulus is passed after residues. Temporaries come last. + * - **Aliasing**: in general, output bignums may be aliased to one or more + * inputs. Modulus values may not be aliased to any other parameter. Outputs + * may not be aliased to one another. Temporaries may not be aliased to any + * other parameter. + * - **Overlap**: apart from aliasing of residue pointers (where two residue + * arguments are equal pointers), overlap is not supported and may result + * in undefined behavior. + * - **Error handling**: functions generally check compatibility of input + * sizes. Most functions will not check that input values are in canonical + * form (i.e. that \c A < \c N), this is only checked during setup of a + * residue structure. + * - **Modular representatives**: all functions expect inputs to be in the + * range [0, \c N - 1] and guarantee outputs in the range [0, \c N - 1]. + * Residues are set up with an associated modulus, and operations are only + * guaranteed to work if the modulus is associated with all residue + * parameters. If a residue is passed with a modulus other than the one it + * is associated with, then it may be out of range. If an input is out of + * range, outputs are fully unspecified, though bignum values out of range + * should not cause buffer overflows (beware that this is not extensively + * tested). + */ + +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_BIGNUM_MOD_H +#define TF_PSA_CRYPTO_BIGNUM_MOD_H + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_BIGNUM_C) +#include "mbedtls/private/bignum.h" +#endif + +/** How residues associated with a modulus are represented. + * + * This also determines which fields of the modulus structure are valid and + * what their contents are (see #mbedtls_mpi_mod_modulus). + */ +typedef enum { + /** Representation not chosen (makes the modulus structure invalid). */ + MBEDTLS_MPI_MOD_REP_INVALID = 0, + /* Skip 1 as it is slightly easier to accidentally pass to functions. */ + /** Montgomery representation. */ + MBEDTLS_MPI_MOD_REP_MONTGOMERY = 2, + /* Optimised reduction available. This indicates a coordinate modulus (P) + * and one or more of the following have been configured: + * - A nist curve (MBEDTLS_ECP_DP_SECPXXXR1_ENABLED) & MBEDTLS_ECP_NIST_OPTIM. + * - A Kobliz Curve. + * - A Fast Reduction Curve CURVE25519 or CURVE448. */ + MBEDTLS_MPI_MOD_REP_OPT_RED, +} mbedtls_mpi_mod_rep_selector; + +/* Make mbedtls_mpi_mod_rep_selector and mbedtls_mpi_mod_ext_rep disjoint to + * make it easier to catch when they are accidentally swapped. */ +typedef enum { + MBEDTLS_MPI_MOD_EXT_REP_INVALID = 0, + MBEDTLS_MPI_MOD_EXT_REP_LE = 8, + MBEDTLS_MPI_MOD_EXT_REP_BE +} mbedtls_mpi_mod_ext_rep; + +typedef struct { + mbedtls_mpi_uint *p; + size_t limbs; +} mbedtls_mpi_mod_residue; + +typedef struct { + mbedtls_mpi_uint const *rr; /* The residue for 2^{2*n*biL} mod N */ + mbedtls_mpi_uint mm; /* Montgomery const for -N^{-1} mod 2^{ciL} */ +} mbedtls_mpi_mont_struct; + +typedef int (*mbedtls_mpi_modp_fn)(mbedtls_mpi_uint *X, size_t X_limbs); + +typedef struct { + mbedtls_mpi_modp_fn modp; /* The optimised reduction function pointer */ +} mbedtls_mpi_opt_red_struct; + +typedef struct { + const mbedtls_mpi_uint *p; + size_t limbs; // number of limbs + size_t bits; // bitlen of p + mbedtls_mpi_mod_rep_selector int_rep; // selector to signal the active member of the union + union rep { + /* if int_rep == #MBEDTLS_MPI_MOD_REP_MONTGOMERY */ + mbedtls_mpi_mont_struct mont; + /* if int_rep == #MBEDTLS_MPI_MOD_REP_OPT_RED */ + mbedtls_mpi_opt_red_struct ored; + } rep; +} mbedtls_mpi_mod_modulus; + +/** Setup a residue structure. + * + * The residue will be set up with the buffer \p p and modulus \p N. + * + * The memory pointed to by \p p will be used by the resulting residue structure. + * The value at the pointed-to memory will be the initial value of \p r and must + * hold a value that is less than the modulus. This value will be used as-is + * and interpreted according to the value of the `N->int_rep` field. + * + * The modulus \p N will be the modulus associated with \p r. The residue \p r + * should only be used in operations where the modulus is \p N. + * + * \param[out] r The address of the residue to setup. + * \param[in] N The address of the modulus related to \p r. + * \param[in] p The address of the limb array containing the value of \p r. + * The memory pointed to by \p p will be used by \p r and must + * not be modified in any way until after + * mbedtls_mpi_mod_residue_release() is called. The data + * pointed to by \p p must be less than the modulus (the value + * pointed to by `N->p`) and already in the representation + * indicated by `N->int_rep`. + * \param p_limbs The number of limbs of \p p. Must be the same as the number + * of limbs in the modulus \p N. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p p_limbs is less than the + * limbs in \p N or if \p p is not less than \p N. + */ +int mbedtls_mpi_mod_residue_setup(mbedtls_mpi_mod_residue *r, + const mbedtls_mpi_mod_modulus *N, + mbedtls_mpi_uint *p, + size_t p_limbs); + +/** Unbind elements of a residue structure. + * + * This function removes the reference to the limb array that was passed to + * mbedtls_mpi_mod_residue_setup() to make it safe to free or use again. + * + * This function invalidates \p r and it must not be used until after + * mbedtls_mpi_mod_residue_setup() is called on it again. + * + * \param[out] r The address of residue to release. + */ +void mbedtls_mpi_mod_residue_release(mbedtls_mpi_mod_residue *r); + +/** Initialize a modulus structure. + * + * \param[out] N The address of the modulus structure to initialize. + */ +void mbedtls_mpi_mod_modulus_init(mbedtls_mpi_mod_modulus *N); + +/** Setup a modulus structure. + * + * \param[out] N The address of the modulus structure to populate. + * \param[in] p The address of the limb array storing the value of \p N. + * The memory pointed to by \p p will be used by \p N and must + * not be modified in any way until after + * mbedtls_mpi_mod_modulus_free() is called. + * \param p_limbs The number of limbs of \p p. + * + * \return \c 0 if successful. + */ +int mbedtls_mpi_mod_modulus_setup(mbedtls_mpi_mod_modulus *N, + const mbedtls_mpi_uint *p, + size_t p_limbs); + +/** Setup an optimised-reduction compatible modulus structure. + * + * \param[out] N The address of the modulus structure to populate. + * \param[in] p The address of the limb array storing the value of \p N. + * The memory pointed to by \p p will be used by \p N and must + * not be modified in any way until after + * mbedtls_mpi_mod_modulus_free() is called. + * \param p_limbs The number of limbs of \p p. + * \param modp A pointer to the optimised reduction function to use. \p p. + * + * \return \c 0 if successful. + */ +int mbedtls_mpi_mod_optred_modulus_setup(mbedtls_mpi_mod_modulus *N, + const mbedtls_mpi_uint *p, + size_t p_limbs, + mbedtls_mpi_modp_fn modp); + +/** Free elements of a modulus structure. + * + * This function frees any memory allocated by mbedtls_mpi_mod_modulus_setup(). + * + * \warning This function does not free the limb array passed to + * mbedtls_mpi_mod_modulus_setup() only removes the reference to it, + * making it safe to free or to use it again. + * + * \param[in,out] N The address of the modulus structure to free. + */ +void mbedtls_mpi_mod_modulus_free(mbedtls_mpi_mod_modulus *N); + +/** \brief Multiply two residues, returning the residue modulo the specified + * modulus. + * + * \note Currently handles the case when `N->int_rep` is + * MBEDTLS_MPI_MOD_REP_MONTGOMERY. + * + * The size of the operation is determined by \p N. \p A, \p B and \p X must + * all be associated with the modulus \p N and must all have the same number + * of limbs as \p N. + * + * \p X may be aliased to \p A or \p B, or even both, but may not overlap + * either otherwise. They may not alias \p N (since they must be in canonical + * form, they cannot == \p N). + * + * \param[out] X The address of the result MPI. Must have the same + * number of limbs as \p N. + * On successful completion, \p X contains the result of + * the multiplication `A * B * R^-1` mod N where + * `R = 2^(biL * N->limbs)`. + * \param[in] A The address of the first MPI. + * \param[in] B The address of the second MPI. + * \param[in] N The address of the modulus. Used to perform a modulo + * operation on the result of the multiplication. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if all the parameters do not + * have the same number of limbs or \p N is invalid. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + */ +int mbedtls_mpi_mod_mul(mbedtls_mpi_mod_residue *X, + const mbedtls_mpi_mod_residue *A, + const mbedtls_mpi_mod_residue *B, + const mbedtls_mpi_mod_modulus *N); + +/** + * \brief Perform a fixed-size modular subtraction. + * + * Calculate `A - B modulo N`. + * + * \p A, \p B and \p X must all have the same number of limbs as \p N. + * + * \p X may be aliased to \p A or \p B, or even both, but may not overlap + * either otherwise. + * + * \note This function does not check that \p A or \p B are in canonical + * form (that is, are < \p N) - that will have been done by + * mbedtls_mpi_mod_residue_setup(). + * + * \param[out] X The address of the result MPI. Must be initialized. + * Must have the same number of limbs as the modulus \p N. + * \param[in] A The address of the first MPI. + * \param[in] B The address of the second MPI. + * \param[in] N The address of the modulus. Used to perform a modulo + * operation on the result of the subtraction. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if the given MPIs do not + * have the correct number of limbs. + */ +int mbedtls_mpi_mod_sub(mbedtls_mpi_mod_residue *X, + const mbedtls_mpi_mod_residue *A, + const mbedtls_mpi_mod_residue *B, + const mbedtls_mpi_mod_modulus *N); + +/** + * \brief Perform modular inversion of an MPI with respect to a modulus \p N. + * + * \p A and \p X must be associated with the modulus \p N and will therefore + * have the same number of limbs as \p N. + * + * \p X may be aliased to \p A. + * + * \warning Currently only supports prime moduli, but does not check for them. + * + * \param[out] X The modular inverse of \p A with respect to \p N. + * \param[in] A The number to calculate the modular inverse of. + * Must not be 0. + * \param[in] N The modulus to use. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p A and \p N do not + * have the same number of limbs. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p A is zero. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if couldn't allocate enough + * memory (needed for conversion to and from Mongtomery form + * when not in Montgomery form already, and for temporary use + * by the inversion calculation itself). + */ + +int mbedtls_mpi_mod_inv(mbedtls_mpi_mod_residue *X, + const mbedtls_mpi_mod_residue *A, + const mbedtls_mpi_mod_modulus *N); +/** + * \brief Perform a fixed-size modular addition. + * + * Calculate `A + B modulo N`. + * + * \p A, \p B and \p X must all be associated with the modulus \p N and must + * all have the same number of limbs as \p N. + * + * \p X may be aliased to \p A or \p B, or even both, but may not overlap + * either otherwise. + * + * \note This function does not check that \p A or \p B are in canonical + * form (that is, are < \p N) - that will have been done by + * mbedtls_mpi_mod_residue_setup(). + * + * \param[out] X The address of the result residue. Must be initialized. + * Must have the same number of limbs as the modulus \p N. + * \param[in] A The address of the first input residue. + * \param[in] B The address of the second input residue. + * \param[in] N The address of the modulus. Used to perform a modulo + * operation on the result of the addition. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if the given MPIs do not + * have the correct number of limbs. + */ +int mbedtls_mpi_mod_add(mbedtls_mpi_mod_residue *X, + const mbedtls_mpi_mod_residue *A, + const mbedtls_mpi_mod_residue *B, + const mbedtls_mpi_mod_modulus *N); + +/** Generate a random number uniformly in a range. + * + * This function generates a random number between \p min inclusive and + * \p N exclusive. + * + * The procedure complies with RFC 6979 §3.3 (deterministic ECDSA) + * when the RNG is a suitably parametrized instance of HMAC_DRBG + * and \p min is \c 1. + * + * \note There are `N - min` possible outputs. The lower bound + * \p min can be reached, but the upper bound \p N cannot. + * + * \param X The destination residue. + * \param min The minimum value to return. It must be strictly smaller + * than \b N. + * \param N The modulus. + * This is the upper bound of the output range, exclusive. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if the implementation was + * unable to find a suitable value within a limited number + * of attempts. This has a negligible probability if \p N + * is significantly larger than \p min, which is the case + * for all usual cryptographic applications. + */ +int mbedtls_mpi_mod_random(mbedtls_mpi_mod_residue *X, + mbedtls_mpi_uint min, + const mbedtls_mpi_mod_modulus *N, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +/** Read a residue from a byte buffer. + * + * The residue will be automatically converted to the internal representation + * based on the value of the `N->int_rep` field. + * + * The modulus \p N will be the modulus associated with \p r. The residue \p r + * should only be used in operations where the modulus is \p N or a modulus + * equivalent to \p N (in the sense that all their fields or memory pointed by + * their fields hold the same value). + * + * \param[out] r The address of the residue. It must have exactly the same + * number of limbs as the modulus \p N. + * \param[in] N The address of the modulus. + * \param[in] buf The input buffer to import from. + * \param buflen The length in bytes of \p buf. + * \param ext_rep The endianness of the number in the input buffer. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p r isn't + * large enough to hold the value in \p buf. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p ext_rep + * is invalid or the value in the buffer is not less than \p N. + */ +int mbedtls_mpi_mod_read(mbedtls_mpi_mod_residue *r, + const mbedtls_mpi_mod_modulus *N, + const unsigned char *buf, + size_t buflen, + mbedtls_mpi_mod_ext_rep ext_rep); + +/** Write a residue into a byte buffer. + * + * The modulus \p N must be the modulus associated with \p r (see + * mbedtls_mpi_mod_residue_setup() and mbedtls_mpi_mod_read()). + * + * The residue will be automatically converted from the internal representation + * based on the value of `N->int_rep` field. + * + * \warning If the buffer is smaller than `N->bits`, the number of + * leading zeroes is leaked through timing. If \p r is + * secret, the caller must ensure that \p buflen is at least + * (`N->bits`+7)/8. + * + * \param[in] r The address of the residue. It must have the same number of + * limbs as the modulus \p N. (\p r is an input parameter, but + * its value will be modified during execution and restored + * before the function returns.) + * \param[in] N The address of the modulus associated with \p r. + * \param[out] buf The output buffer to export to. + * \param buflen The length in bytes of \p buf. + * \param ext_rep The endianness in which the number should be written into + * the output buffer. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p buf isn't + * large enough to hold the value of \p r (without leading + * zeroes). + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p ext_rep is invalid. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if couldn't allocate enough + * memory for conversion. Can occur only for moduli with + * MBEDTLS_MPI_MOD_REP_MONTGOMERY. + */ +int mbedtls_mpi_mod_write(const mbedtls_mpi_mod_residue *r, + const mbedtls_mpi_mod_modulus *N, + unsigned char *buf, + size_t buflen, + mbedtls_mpi_mod_ext_rep ext_rep); + +#endif /* TF_PSA_CRYPTO_BIGNUM_MOD_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/bignum_mod_raw.c b/tf-psa-crypto/drivers/builtin/src/bignum_mod_raw.c new file mode 100644 index 0000000000..559408f768 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/bignum_mod_raw.c @@ -0,0 +1,276 @@ +/* + * Low-level modular bignum functions + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_BIGNUM_C) && defined(MBEDTLS_ECP_WITH_MPI_UINT) + +#include + +#include "mbedtls/private/error_common.h" +#include "mbedtls/platform_util.h" + +#include "mbedtls/platform.h" + +#include "bignum_core.h" +#include "bignum_mod_raw.h" +#include "bignum_mod.h" +#include "constant_time_internal.h" + +#include "bignum_mod_raw_invasive.h" + +void mbedtls_mpi_mod_raw_cond_assign(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_mod_modulus *N, + unsigned char assign) +{ + mbedtls_mpi_core_cond_assign(X, A, N->limbs, mbedtls_ct_bool(assign)); +} + +void mbedtls_mpi_mod_raw_cond_swap(mbedtls_mpi_uint *X, + mbedtls_mpi_uint *Y, + const mbedtls_mpi_mod_modulus *N, + unsigned char swap) +{ + mbedtls_mpi_core_cond_swap(X, Y, N->limbs, mbedtls_ct_bool(swap)); +} + +int mbedtls_mpi_mod_raw_read(mbedtls_mpi_uint *X, + const mbedtls_mpi_mod_modulus *N, + const unsigned char *input, + size_t input_length, + mbedtls_mpi_mod_ext_rep ext_rep) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + switch (ext_rep) { + case MBEDTLS_MPI_MOD_EXT_REP_LE: + ret = mbedtls_mpi_core_read_le(X, N->limbs, + input, input_length); + break; + case MBEDTLS_MPI_MOD_EXT_REP_BE: + ret = mbedtls_mpi_core_read_be(X, N->limbs, + input, input_length); + break; + default: + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + if (ret != 0) { + goto cleanup; + } + + if (!mbedtls_mpi_core_lt_ct(X, N->p, N->limbs)) { + ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + goto cleanup; + } + +cleanup: + + return ret; +} + +int mbedtls_mpi_mod_raw_write(const mbedtls_mpi_uint *A, + const mbedtls_mpi_mod_modulus *N, + unsigned char *output, + size_t output_length, + mbedtls_mpi_mod_ext_rep ext_rep) +{ + switch (ext_rep) { + case MBEDTLS_MPI_MOD_EXT_REP_LE: + return mbedtls_mpi_core_write_le(A, N->limbs, + output, output_length); + case MBEDTLS_MPI_MOD_EXT_REP_BE: + return mbedtls_mpi_core_write_be(A, N->limbs, + output, output_length); + default: + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } +} + +void mbedtls_mpi_mod_raw_sub(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + const mbedtls_mpi_mod_modulus *N) +{ + mbedtls_mpi_uint c = mbedtls_mpi_core_sub(X, A, B, N->limbs); + + (void) mbedtls_mpi_core_add_if(X, N->p, N->limbs, (unsigned) c); +} + +MBEDTLS_STATIC_TESTABLE +void mbedtls_mpi_mod_raw_fix_quasi_reduction(mbedtls_mpi_uint *X, + const mbedtls_mpi_mod_modulus *N) +{ + mbedtls_mpi_uint c = mbedtls_mpi_core_sub(X, X, N->p, N->limbs); + + (void) mbedtls_mpi_core_add_if(X, N->p, N->limbs, (unsigned) c); +} + + +void mbedtls_mpi_mod_raw_mul(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + const mbedtls_mpi_mod_modulus *N, + mbedtls_mpi_uint *T) +{ + /* Standard (A * B) multiplication stored into pre-allocated T + * buffer of fixed limb size of (2N + 1). + * + * The space may not not fully filled by when + * MBEDTLS_MPI_MOD_REP_OPT_RED is used. */ + const size_t T_limbs = BITS_TO_LIMBS(N->bits) * 2; + switch (N->int_rep) { + case MBEDTLS_MPI_MOD_REP_MONTGOMERY: + mbedtls_mpi_core_montmul(X, A, B, N->limbs, N->p, N->limbs, + N->rep.mont.mm, T); + break; + case MBEDTLS_MPI_MOD_REP_OPT_RED: + mbedtls_mpi_core_mul(T, A, N->limbs, B, N->limbs); + + /* Optimised Reduction */ + (*N->rep.ored.modp)(T, T_limbs); + + /* Convert back to canonical representation */ + mbedtls_mpi_mod_raw_fix_quasi_reduction(T, N); + memcpy(X, T, N->limbs * sizeof(mbedtls_mpi_uint)); + break; + default: + break; + } + +} + +size_t mbedtls_mpi_mod_raw_inv_prime_working_limbs(size_t AN_limbs) +{ + /* mbedtls_mpi_mod_raw_inv_prime() needs a temporary for the exponent, + * which will be the same size as the modulus and input (AN_limbs), + * and additional space to pass to mbedtls_mpi_core_exp_mod(). */ + return AN_limbs + + mbedtls_mpi_core_exp_mod_working_limbs(AN_limbs, AN_limbs); +} + +void mbedtls_mpi_mod_raw_inv_prime(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *N, + size_t AN_limbs, + const mbedtls_mpi_uint *RR, + mbedtls_mpi_uint *T) +{ + /* Inversion by power: g^|G| = 1 => g^(-1) = g^(|G|-1), and + * |G| = N - 1, so we want + * g^(|G|-1) = g^(N - 2) + */ + + /* Use the first AN_limbs of T to hold N - 2 */ + mbedtls_mpi_uint *Nminus2 = T; + (void) mbedtls_mpi_core_sub_int(Nminus2, N, 2, AN_limbs); + + /* Rest of T is given to exp_mod for its working space */ + mbedtls_mpi_core_exp_mod(X, + A, N, AN_limbs, Nminus2, AN_limbs, + RR, T + AN_limbs); +} + +void mbedtls_mpi_mod_raw_add(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + const mbedtls_mpi_mod_modulus *N) +{ + mbedtls_mpi_uint carry, borrow; + carry = mbedtls_mpi_core_add(X, A, B, N->limbs); + borrow = mbedtls_mpi_core_sub(X, X, N->p, N->limbs); + (void) mbedtls_mpi_core_add_if(X, N->p, N->limbs, (unsigned) (carry ^ borrow)); +} + +int mbedtls_mpi_mod_raw_canonical_to_modulus_rep( + mbedtls_mpi_uint *X, + const mbedtls_mpi_mod_modulus *N) +{ + switch (N->int_rep) { + case MBEDTLS_MPI_MOD_REP_MONTGOMERY: + return mbedtls_mpi_mod_raw_to_mont_rep(X, N); + case MBEDTLS_MPI_MOD_REP_OPT_RED: + return 0; + default: + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } +} + +int mbedtls_mpi_mod_raw_modulus_to_canonical_rep( + mbedtls_mpi_uint *X, + const mbedtls_mpi_mod_modulus *N) +{ + switch (N->int_rep) { + case MBEDTLS_MPI_MOD_REP_MONTGOMERY: + return mbedtls_mpi_mod_raw_from_mont_rep(X, N); + case MBEDTLS_MPI_MOD_REP_OPT_RED: + return 0; + default: + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } +} + +int mbedtls_mpi_mod_raw_random(mbedtls_mpi_uint *X, + mbedtls_mpi_uint min, + const mbedtls_mpi_mod_modulus *N, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + int ret = mbedtls_mpi_core_random(X, min, N->p, N->limbs, f_rng, p_rng); + if (ret != 0) { + return ret; + } + return mbedtls_mpi_mod_raw_canonical_to_modulus_rep(X, N); +} + +int mbedtls_mpi_mod_raw_to_mont_rep(mbedtls_mpi_uint *X, + const mbedtls_mpi_mod_modulus *N) +{ + mbedtls_mpi_uint *T; + const size_t t_limbs = mbedtls_mpi_core_montmul_working_limbs(N->limbs); + + if ((T = (mbedtls_mpi_uint *) mbedtls_calloc(t_limbs, ciL)) == NULL) { + return MBEDTLS_ERR_MPI_ALLOC_FAILED; + } + + mbedtls_mpi_core_to_mont_rep(X, X, N->p, N->limbs, + N->rep.mont.mm, N->rep.mont.rr, T); + + mbedtls_zeroize_and_free(T, t_limbs * ciL); + return 0; +} + +int mbedtls_mpi_mod_raw_from_mont_rep(mbedtls_mpi_uint *X, + const mbedtls_mpi_mod_modulus *N) +{ + const size_t t_limbs = mbedtls_mpi_core_montmul_working_limbs(N->limbs); + mbedtls_mpi_uint *T; + + if ((T = (mbedtls_mpi_uint *) mbedtls_calloc(t_limbs, ciL)) == NULL) { + return MBEDTLS_ERR_MPI_ALLOC_FAILED; + } + + mbedtls_mpi_core_from_mont_rep(X, X, N->p, N->limbs, N->rep.mont.mm, T); + + mbedtls_zeroize_and_free(T, t_limbs * ciL); + return 0; +} + +void mbedtls_mpi_mod_raw_neg(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_mod_modulus *N) +{ + mbedtls_mpi_core_sub(X, N->p, A, N->limbs); + + /* If A=0 initially, then X=N now. Detect this by + * subtracting N and catching the carry. */ + mbedtls_mpi_uint borrow = mbedtls_mpi_core_sub(X, X, N->p, N->limbs); + (void) mbedtls_mpi_core_add_if(X, N->p, N->limbs, (unsigned) borrow); +} + +#endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ECP_WITH_MPI_UINT */ diff --git a/tf-psa-crypto/drivers/builtin/src/bignum_mod_raw.h b/tf-psa-crypto/drivers/builtin/src/bignum_mod_raw.h new file mode 100644 index 0000000000..5cbee11aec --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/bignum_mod_raw.h @@ -0,0 +1,416 @@ +/** + * Low-level modular bignum functions + * + * This interface should only be used by the higher-level modular bignum + * module (bignum_mod.c) and the ECP module (ecp.c, ecp_curves.c). All other + * modules should use the high-level modular bignum interface (bignum_mod.h) + * or the legacy bignum interface (bignum.h). + * + * This is a low-level interface to operations on integers modulo which + * has no protection against passing invalid arguments such as arrays of + * the wrong size. The functions in bignum_mod.h provide a higher-level + * interface that includes protections against accidental misuse, at the + * expense of code size and sometimes more cumbersome memory management. + * + * The functions in this module obey the following conventions unless + * explicitly indicated otherwise: + * - **Modulus parameters**: the modulus is passed as a pointer to a structure + * of type #mbedtls_mpi_mod_modulus. The structure must be set up with an + * array of limbs storing the bignum value of the modulus. The modulus must + * be odd and is assumed to have no leading zeroes. The modulus is usually + * named \c N and is usually input-only. + * - **Bignum parameters**: Bignums are passed as pointers to an array of + * limbs. A limb has the type #mbedtls_mpi_uint. Unless otherwise specified: + * - Bignum parameters called \c A, \c B, ... are inputs, and are not + * modified by the function. + * - Bignum parameters called \c X, \c Y are outputs or input-output. + * The initial content of output-only parameters is ignored. + * - \c T is a temporary storage area. The initial content of such a + * parameter is ignored and the final content is unspecified. + * - **Bignum sizes**: bignum sizes are usually expressed by the \c limbs + * member of the modulus argument. All bignum parameters must have the same + * number of limbs as the modulus. All bignum sizes must be at least 1 and + * must be significantly less than #SIZE_MAX. The behavior if a size is 0 is + * undefined. + * - **Bignum representation**: the representation of inputs and outputs is + * specified by the \c int_rep field of the modulus for arithmetic + * functions. Utility functions may allow for different representation. + * - **Parameter ordering**: for bignum parameters, outputs come before inputs. + * The modulus is passed after other bignum input parameters. Temporaries + * come last. + * - **Aliasing**: in general, output bignums may be aliased to one or more + * inputs. Modulus values may not be aliased to any other parameter. Outputs + * may not be aliased to one another. Temporaries may not be aliased to any + * other parameter. + * - **Overlap**: apart from aliasing of limb array pointers (where two + * arguments are equal pointers), overlap is not supported and may result + * in undefined behavior. + * - **Error handling**: This is a low-level module. Functions generally do not + * try to protect against invalid arguments such as nonsensical sizes or + * null pointers. Note that passing bignums with a different size than the + * modulus may lead to buffer overflows. Some functions which allocate + * memory or handle reading/writing of bignums will return an error if + * memory allocation fails or if buffer sizes are invalid. + * - **Modular representatives**: all functions expect inputs to be in the + * range [0, \c N - 1] and guarantee outputs in the range [0, \c N - 1]. If + * an input is out of range, outputs are fully unspecified, though bignum + * values out of range should not cause buffer overflows (beware that this is + * not extensively tested). + */ + +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_BIGNUM_MOD_RAW_H +#define TF_PSA_CRYPTO_BIGNUM_MOD_RAW_H + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_BIGNUM_C) +#include "mbedtls/private/bignum.h" +#endif + +#include "bignum_mod.h" + +/** + * \brief Perform a safe conditional copy of an MPI which doesn't reveal + * whether the assignment was done or not. + * + * The size to copy is determined by \p N. + * + * \param[out] X The address of the destination MPI. + * This must be initialized. Must have enough limbs to + * store the full value of \p A. + * \param[in] A The address of the source MPI. This must be initialized. + * \param[in] N The address of the modulus related to \p X and \p A. + * \param assign The condition deciding whether to perform the + * assignment or not. Must be either 0 or 1: + * * \c 1: Perform the assignment `X = A`. + * * \c 0: Keep the original value of \p X. + * + * \note This function avoids leaking any information about whether + * the assignment was done or not. + * + * \warning If \p assign is neither 0 nor 1, the result of this function + * is indeterminate, and the resulting value in \p X might be + * neither its original value nor the value in \p A. + */ +void mbedtls_mpi_mod_raw_cond_assign(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_mod_modulus *N, + unsigned char assign); + +/** + * \brief Perform a safe conditional swap of two MPIs which doesn't reveal + * whether the swap was done or not. + * + * The size to swap is determined by \p N. + * + * \param[in,out] X The address of the first MPI. This must be initialized. + * \param[in,out] Y The address of the second MPI. This must be initialized. + * \param[in] N The address of the modulus related to \p X and \p Y. + * \param swap The condition deciding whether to perform + * the swap or not. Must be either 0 or 1: + * * \c 1: Swap the values of \p X and \p Y. + * * \c 0: Keep the original values of \p X and \p Y. + * + * \note This function avoids leaking any information about whether + * the swap was done or not. + * + * \warning If \p swap is neither 0 nor 1, the result of this function + * is indeterminate, and both \p X and \p Y might end up with + * values different to either of the original ones. + */ +void mbedtls_mpi_mod_raw_cond_swap(mbedtls_mpi_uint *X, + mbedtls_mpi_uint *Y, + const mbedtls_mpi_mod_modulus *N, + unsigned char swap); + +/** Import X from unsigned binary data. + * + * The MPI needs to have enough limbs to store the full value (including any + * most significant zero bytes in the input). + * + * \param[out] X The address of the MPI. The size is determined by \p N. + * (In particular, it must have at least as many limbs as + * the modulus \p N.) + * \param[in] N The address of the modulus related to \p X. + * \param[in] input The input buffer to import from. + * \param input_length The length in bytes of \p input. + * \param ext_rep The endianness of the number in the input buffer. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p X isn't + * large enough to hold the value in \p input. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if the external representation + * of \p N is invalid or \p X is not less than \p N. + */ +int mbedtls_mpi_mod_raw_read(mbedtls_mpi_uint *X, + const mbedtls_mpi_mod_modulus *N, + const unsigned char *input, + size_t input_length, + mbedtls_mpi_mod_ext_rep ext_rep); + +/** Export A into unsigned binary data. + * + * \param[in] A The address of the MPI. The size is determined by \p N. + * (In particular, it must have at least as many limbs as + * the modulus \p N.) + * \param[in] N The address of the modulus related to \p A. + * \param[out] output The output buffer to export to. + * \param output_length The length in bytes of \p output. + * \param ext_rep The endianness in which the number should be written into the output buffer. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p output isn't + * large enough to hold the value of \p A. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if the external representation + * of \p N is invalid. + */ +int mbedtls_mpi_mod_raw_write(const mbedtls_mpi_uint *A, + const mbedtls_mpi_mod_modulus *N, + unsigned char *output, + size_t output_length, + mbedtls_mpi_mod_ext_rep ext_rep); + +/** \brief Subtract two MPIs, returning the residue modulo the specified + * modulus. + * + * The size of the operation is determined by \p N. \p A and \p B must have + * the same number of limbs as \p N. + * + * \p X may be aliased to \p A or \p B, or even both, but may not overlap + * either otherwise. + * + * \param[out] X The address of the result MPI. + * This must be initialized. Must have enough limbs to + * store the full value of the result. + * \param[in] A The address of the first MPI. This must be initialized. + * \param[in] B The address of the second MPI. This must be initialized. + * \param[in] N The address of the modulus. Used to perform a modulo + * operation on the result of the subtraction. + */ +void mbedtls_mpi_mod_raw_sub(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + const mbedtls_mpi_mod_modulus *N); + +/** \brief Multiply two MPIs, returning the residue modulo the specified + * modulus. + * + * \note Currently handles the case when `N->int_rep` is + * MBEDTLS_MPI_MOD_REP_MONTGOMERY. + * + * The size of the operation is determined by \p N. \p A, \p B and \p X must + * all be associated with the modulus \p N and must all have the same number + * of limbs as \p N. + * + * \p X may be aliased to \p A or \p B, or even both, but may not overlap + * either otherwise. They may not alias \p N (since they must be in canonical + * form, they cannot == \p N). + * + * \param[out] X The address of the result MPI. Must have the same + * number of limbs as \p N. + * On successful completion, \p X contains the result of + * the multiplication `A * B * R^-1` mod N where + * `R = 2^(biL * N->limbs)`. + * \param[in] A The address of the first MPI. + * \param[in] B The address of the second MPI. + * \param[in] N The address of the modulus. Used to perform a modulo + * operation on the result of the multiplication. + * \param[in,out] T Temporary storage of size at least 2 * N->limbs + 1 + * limbs. Its initial content is unused and + * its final content is indeterminate. + * It must not alias or otherwise overlap any of the + * other parameters. + */ +void mbedtls_mpi_mod_raw_mul(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + const mbedtls_mpi_mod_modulus *N, + mbedtls_mpi_uint *T); + +/** + * \brief Returns the number of limbs of working memory required for + * a call to `mbedtls_mpi_mod_raw_inv_prime()`. + * + * \note This will always be at least + * `mbedtls_mpi_core_montmul_working_limbs(AN_limbs)`, + * i.e. sufficient for a call to `mbedtls_mpi_core_montmul()`. + * + * \param AN_limbs The number of limbs in the input `A` and the modulus `N` + * (they must be the same size) that will be given to + * `mbedtls_mpi_mod_raw_inv_prime()`. + * + * \return The number of limbs of working memory required by + * `mbedtls_mpi_mod_raw_inv_prime()`. + */ +size_t mbedtls_mpi_mod_raw_inv_prime_working_limbs(size_t AN_limbs); + +/** + * \brief Perform fixed-width modular inversion of a Montgomery-form MPI with + * respect to a modulus \p N that must be prime. + * + * \p X may be aliased to \p A, but not to \p N or \p RR. + * + * \param[out] X The modular inverse of \p A with respect to \p N. + * Will be in Montgomery form. + * \param[in] A The number to calculate the modular inverse of. + * Must be in Montgomery form. Must not be 0. + * \param[in] N The modulus, as a little-endian array of length \p AN_limbs. + * Must be prime. + * \param AN_limbs The number of limbs in \p A, \p N and \p RR. + * \param[in] RR The precomputed residue of 2^{2*biL} modulo N, as a little- + * endian array of length \p AN_limbs. + * \param[in,out] T Temporary storage of at least the number of limbs returned + * by `mbedtls_mpi_mod_raw_inv_prime_working_limbs()`. + * Its initial content is unused and its final content is + * indeterminate. + * It must not alias or otherwise overlap any of the other + * parameters. + * It is up to the caller to zeroize \p T when it is no + * longer needed, and before freeing it if it was dynamically + * allocated. + */ +void mbedtls_mpi_mod_raw_inv_prime(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *N, + size_t AN_limbs, + const mbedtls_mpi_uint *RR, + mbedtls_mpi_uint *T); + +/** + * \brief Perform a known-size modular addition. + * + * Calculate `A + B modulo N`. + * + * The number of limbs in each operand, and the result, is given by the + * modulus \p N. + * + * \p X may be aliased to \p A or \p B, or even both, but may not overlap + * either otherwise. + * + * \param[out] X The result of the modular addition. + * \param[in] A Little-endian presentation of the left operand. This + * must be smaller than \p N. + * \param[in] B Little-endian presentation of the right operand. This + * must be smaller than \p N. + * \param[in] N The address of the modulus. + */ +void mbedtls_mpi_mod_raw_add(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + const mbedtls_mpi_mod_modulus *N); + +/** Convert an MPI from canonical representation (little-endian limb array) + * to the representation associated with the modulus. + * + * \param[in,out] X The limb array to convert. + * It must have as many limbs as \p N. + * It is converted in place. + * If this function returns an error, the content of \p X + * is unspecified. + * \param[in] N The modulus structure. + * + * \return \c 0 if successful. + * Otherwise an \c MBEDTLS_ERR_MPI_xxx error code. + */ +int mbedtls_mpi_mod_raw_canonical_to_modulus_rep( + mbedtls_mpi_uint *X, + const mbedtls_mpi_mod_modulus *N); + +/** Convert an MPI from the representation associated with the modulus + * to canonical representation (little-endian limb array). + * + * \param[in,out] X The limb array to convert. + * It must have as many limbs as \p N. + * It is converted in place. + * If this function returns an error, the content of \p X + * is unspecified. + * \param[in] N The modulus structure. + * + * \return \c 0 if successful. + * Otherwise an \c MBEDTLS_ERR_MPI_xxx error code. + */ +int mbedtls_mpi_mod_raw_modulus_to_canonical_rep( + mbedtls_mpi_uint *X, + const mbedtls_mpi_mod_modulus *N); + +/** Generate a random number uniformly in a range. + * + * This function generates a random number between \p min inclusive and + * \p N exclusive. + * + * The procedure complies with RFC 6979 §3.3 (deterministic ECDSA) + * when the RNG is a suitably parametrized instance of HMAC_DRBG + * and \p min is \c 1. + * + * \note There are `N - min` possible outputs. The lower bound + * \p min can be reached, but the upper bound \p N cannot. + * + * \param X The destination MPI, in canonical representation modulo \p N. + * It must not be aliased with \p N or otherwise overlap it. + * \param min The minimum value to return. It must be strictly smaller + * than \b N. + * \param N The modulus. + * This is the upper bound of the output range, exclusive. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if the implementation was + * unable to find a suitable value within a limited number + * of attempts. This has a negligible probability if \p N + * is significantly larger than \p min, which is the case + * for all usual cryptographic applications. + */ +int mbedtls_mpi_mod_raw_random(mbedtls_mpi_uint *X, + mbedtls_mpi_uint min, + const mbedtls_mpi_mod_modulus *N, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +/** Convert an MPI into Montgomery form. + * + * \param X The address of the MPI. + * Must have the same number of limbs as \p N. + * \param N The address of the modulus, which gives the size of + * the base `R` = 2^(biL*N->limbs). + * + * \return \c 0 if successful. + */ +int mbedtls_mpi_mod_raw_to_mont_rep(mbedtls_mpi_uint *X, + const mbedtls_mpi_mod_modulus *N); + +/** Convert an MPI back from Montgomery representation. + * + * \param X The address of the MPI. + * Must have the same number of limbs as \p N. + * \param N The address of the modulus, which gives the size of + * the base `R`= 2^(biL*N->limbs). + * + * \return \c 0 if successful. + */ +int mbedtls_mpi_mod_raw_from_mont_rep(mbedtls_mpi_uint *X, + const mbedtls_mpi_mod_modulus *N); + +/** \brief Perform fixed width modular negation. + * + * The size of the operation is determined by \p N. \p A must have + * the same number of limbs as \p N. + * + * \p X may be aliased to \p A. + * + * \param[out] X The result of the modular negation. + * This must be initialized. + * \param[in] A Little-endian presentation of the input operand. This + * must be less than or equal to \p N. + * \param[in] N The modulus to use. + */ +void mbedtls_mpi_mod_raw_neg(mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *A, + const mbedtls_mpi_mod_modulus *N); + +#endif /* TF_PSA_CRYPTO_BIGNUM_MOD_RAW_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/bignum_mod_raw_invasive.h b/tf-psa-crypto/drivers/builtin/src/bignum_mod_raw_invasive.h new file mode 100644 index 0000000000..7c33b529fc --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/bignum_mod_raw_invasive.h @@ -0,0 +1,34 @@ +/** + * \file bignum_mod_raw_invasive.h + * + * \brief Function declarations for invasive functions of Low-level + * modular bignum. + */ +/** + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_BIGNUM_MOD_RAW_INVASIVE_H +#define TF_PSA_CRYPTO_BIGNUM_MOD_RAW_INVASIVE_H + +#include "tf_psa_crypto_common.h" +#include "mbedtls/private/bignum.h" +#include "bignum_mod.h" + +#if defined(MBEDTLS_TEST_HOOKS) + +/** Convert the result of a quasi-reduction to its canonical representative. + * + * \param[in,out] X The address of the MPI to be converted. Must have the + * same number of limbs as \p N. The input value must + * be in range 0 <= X < 2N. + * \param[in] N The address of the modulus. + */ +MBEDTLS_STATIC_TESTABLE +void mbedtls_mpi_mod_raw_fix_quasi_reduction(mbedtls_mpi_uint *X, + const mbedtls_mpi_mod_modulus *N); + +#endif /* MBEDTLS_TEST_HOOKS */ + +#endif /* TF_PSA_CRYPTO_BIGNUM_MOD_RAW_INVASIVE_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/block_cipher.c b/tf-psa-crypto/drivers/builtin/src/block_cipher.c new file mode 100644 index 0000000000..90662637e3 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/block_cipher.c @@ -0,0 +1,207 @@ +/** + * \file block_cipher.c + * + * \brief Lightweight abstraction layer for block ciphers with 128 bit blocks, + * for use by the GCM and CCM modules. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA) +#include "psa/crypto.h" +#include "psa_crypto_core.h" +#include "psa_util_internal.h" +#endif + +#include "block_cipher_internal.h" + +#if defined(MBEDTLS_BLOCK_CIPHER_C) + +#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA) +static psa_key_type_t psa_key_type_from_block_cipher_id(mbedtls_block_cipher_id_t cipher_id) +{ + switch (cipher_id) { +#if defined(MBEDTLS_BLOCK_CIPHER_AES_VIA_PSA) + case MBEDTLS_BLOCK_CIPHER_ID_AES: + return PSA_KEY_TYPE_AES; +#endif +#if defined(MBEDTLS_BLOCK_CIPHER_ARIA_VIA_PSA) + case MBEDTLS_BLOCK_CIPHER_ID_ARIA: + return PSA_KEY_TYPE_ARIA; +#endif +#if defined(MBEDTLS_BLOCK_CIPHER_CAMELLIA_VIA_PSA) + case MBEDTLS_BLOCK_CIPHER_ID_CAMELLIA: + return PSA_KEY_TYPE_CAMELLIA; +#endif + default: + return PSA_KEY_TYPE_NONE; + } +} + +static int mbedtls_cipher_error_from_psa(psa_status_t status) +{ + return PSA_TO_MBEDTLS_ERR_LIST(status, psa_to_cipher_errors, + psa_generic_status_to_mbedtls); +} +#endif /* MBEDTLS_BLOCK_CIPHER_SOME_PSA */ + +void mbedtls_block_cipher_free(mbedtls_block_cipher_context_t *ctx) +{ + if (ctx == NULL) { + return; + } + +#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA) + if (ctx->engine == MBEDTLS_BLOCK_CIPHER_ENGINE_PSA) { + psa_destroy_key(ctx->psa_key_id); + return; + } +#endif + switch (ctx->id) { +#if defined(MBEDTLS_AES_C) + case MBEDTLS_BLOCK_CIPHER_ID_AES: + mbedtls_aes_free(&ctx->ctx.aes); + break; +#endif +#if defined(MBEDTLS_ARIA_C) + case MBEDTLS_BLOCK_CIPHER_ID_ARIA: + mbedtls_aria_free(&ctx->ctx.aria); + break; +#endif +#if defined(MBEDTLS_CAMELLIA_C) + case MBEDTLS_BLOCK_CIPHER_ID_CAMELLIA: + mbedtls_camellia_free(&ctx->ctx.camellia); + break; +#endif + default: + break; + } + ctx->id = MBEDTLS_BLOCK_CIPHER_ID_NONE; +} + +int mbedtls_block_cipher_setup(mbedtls_block_cipher_context_t *ctx, + mbedtls_cipher_id_t cipher_id) +{ + ctx->id = (cipher_id == MBEDTLS_CIPHER_ID_AES) ? MBEDTLS_BLOCK_CIPHER_ID_AES : + (cipher_id == MBEDTLS_CIPHER_ID_ARIA) ? MBEDTLS_BLOCK_CIPHER_ID_ARIA : + (cipher_id == MBEDTLS_CIPHER_ID_CAMELLIA) ? MBEDTLS_BLOCK_CIPHER_ID_CAMELLIA : + MBEDTLS_BLOCK_CIPHER_ID_NONE; + +#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA) + psa_key_type_t psa_key_type = psa_key_type_from_block_cipher_id(ctx->id); + if (psa_key_type != PSA_KEY_TYPE_NONE && + psa_is_ready_for_cipher()) { + ctx->engine = MBEDTLS_BLOCK_CIPHER_ENGINE_PSA; + return 0; + } + ctx->engine = MBEDTLS_BLOCK_CIPHER_ENGINE_LEGACY; +#endif + + switch (ctx->id) { +#if defined(MBEDTLS_AES_C) + case MBEDTLS_BLOCK_CIPHER_ID_AES: + mbedtls_aes_init(&ctx->ctx.aes); + return 0; +#endif +#if defined(MBEDTLS_ARIA_C) + case MBEDTLS_BLOCK_CIPHER_ID_ARIA: + mbedtls_aria_init(&ctx->ctx.aria); + return 0; +#endif +#if defined(MBEDTLS_CAMELLIA_C) + case MBEDTLS_BLOCK_CIPHER_ID_CAMELLIA: + mbedtls_camellia_init(&ctx->ctx.camellia); + return 0; +#endif + default: + ctx->id = MBEDTLS_BLOCK_CIPHER_ID_NONE; + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } +} + +int mbedtls_block_cipher_setkey(mbedtls_block_cipher_context_t *ctx, + const unsigned char *key, + unsigned key_bitlen) +{ +#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA) + if (ctx->engine == MBEDTLS_BLOCK_CIPHER_ENGINE_PSA) { + psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT; + psa_status_t status; + + psa_set_key_type(&key_attr, psa_key_type_from_block_cipher_id(ctx->id)); + psa_set_key_bits(&key_attr, key_bitlen); + psa_set_key_algorithm(&key_attr, PSA_ALG_ECB_NO_PADDING); + psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_ENCRYPT); + + status = psa_import_key(&key_attr, key, PSA_BITS_TO_BYTES(key_bitlen), &ctx->psa_key_id); + if (status != PSA_SUCCESS) { + return mbedtls_cipher_error_from_psa(status); + } + psa_reset_key_attributes(&key_attr); + + return 0; + } +#endif /* MBEDTLS_BLOCK_CIPHER_SOME_PSA */ + + switch (ctx->id) { +#if defined(MBEDTLS_AES_C) + case MBEDTLS_BLOCK_CIPHER_ID_AES: + return mbedtls_aes_setkey_enc(&ctx->ctx.aes, key, key_bitlen); +#endif +#if defined(MBEDTLS_ARIA_C) + case MBEDTLS_BLOCK_CIPHER_ID_ARIA: + return mbedtls_aria_setkey_enc(&ctx->ctx.aria, key, key_bitlen); +#endif +#if defined(MBEDTLS_CAMELLIA_C) + case MBEDTLS_BLOCK_CIPHER_ID_CAMELLIA: + return mbedtls_camellia_setkey_enc(&ctx->ctx.camellia, key, key_bitlen); +#endif + default: + return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT; + } +} + +int mbedtls_block_cipher_encrypt(mbedtls_block_cipher_context_t *ctx, + const unsigned char input[16], + unsigned char output[16]) +{ +#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA) + if (ctx->engine == MBEDTLS_BLOCK_CIPHER_ENGINE_PSA) { + psa_status_t status; + size_t olen; + + status = psa_cipher_encrypt(ctx->psa_key_id, PSA_ALG_ECB_NO_PADDING, + input, 16, output, 16, &olen); + if (status != PSA_SUCCESS) { + return mbedtls_cipher_error_from_psa(status); + } + return 0; + } +#endif /* MBEDTLS_BLOCK_CIPHER_SOME_PSA */ + + switch (ctx->id) { +#if defined(MBEDTLS_AES_C) + case MBEDTLS_BLOCK_CIPHER_ID_AES: + return mbedtls_aes_crypt_ecb(&ctx->ctx.aes, MBEDTLS_AES_ENCRYPT, + input, output); +#endif +#if defined(MBEDTLS_ARIA_C) + case MBEDTLS_BLOCK_CIPHER_ID_ARIA: + return mbedtls_aria_crypt_ecb(&ctx->ctx.aria, input, output); +#endif +#if defined(MBEDTLS_CAMELLIA_C) + case MBEDTLS_BLOCK_CIPHER_ID_CAMELLIA: + return mbedtls_camellia_crypt_ecb(&ctx->ctx.camellia, + MBEDTLS_CAMELLIA_ENCRYPT, + input, output); +#endif + default: + return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT; + } +} + +#endif /* MBEDTLS_BLOCK_CIPHER_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/block_cipher_internal.h b/tf-psa-crypto/drivers/builtin/src/block_cipher_internal.h new file mode 100644 index 0000000000..bdcacfef17 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/block_cipher_internal.h @@ -0,0 +1,99 @@ +/** + * \file block_cipher_internal.h + * + * \brief Lightweight abstraction layer for block ciphers with 128 bit blocks, + * for use by the GCM and CCM modules. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_BLOCK_CIPHER_INTERNAL_H +#define TF_PSA_CRYPTO_BLOCK_CIPHER_INTERNAL_H + +#include "tf-psa-crypto/build_info.h" + +#include "mbedtls/private/cipher.h" + +#include "mbedtls/private/block_cipher.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initialize the context. + * This must be the first API call before using the context. + * + * \param ctx The context to initialize. + */ +static inline void mbedtls_block_cipher_init(mbedtls_block_cipher_context_t *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); +} + +/** + * \brief Set the block cipher to use with this context. + * This must be called after mbedtls_block_cipher_init(). + * + * \param ctx The context to set up. + * \param cipher_id The identifier of the cipher to use. + * This must be either AES, ARIA or Camellia. + * Warning: this is a ::mbedtls_cipher_id_t, + * not a ::mbedtls_block_cipher_id_t! + * + * \retval \c 0 on success. + * \retval #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if \p cipher_id was + * invalid. + */ +int mbedtls_block_cipher_setup(mbedtls_block_cipher_context_t *ctx, + mbedtls_cipher_id_t cipher_id); + +/** + * \brief Set the key into the context. + * + * \param ctx The context to configure. + * \param key The buffer holding the key material. + * \param key_bitlen The size of the key in bits. + * + * \retval \c 0 on success. + * \retval #MBEDTLS_ERR_CIPHER_INVALID_CONTEXT if the context was not + * properly set up before calling this function. + * \retval One of #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH, + * #MBEDTLS_ERR_ARIA_BAD_INPUT_DATA, + * #MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA if \p key_bitlen is + * invalid. + */ +int mbedtls_block_cipher_setkey(mbedtls_block_cipher_context_t *ctx, + const unsigned char *key, + unsigned key_bitlen); + +/** + * \brief Encrypt one block (16 bytes) with the configured key. + * + * \param ctx The context holding the key. + * \param input The buffer holding the input block. Must be 16 bytes. + * \param output The buffer to which the output block will be written. + * Must be writable and 16 bytes long. + * This must either not overlap with \p input, or be equal. + * + * \retval \c 0 on success. + * \retval #MBEDTLS_ERR_CIPHER_INVALID_CONTEXT if the context was not + * properly set up before calling this function. + * \retval Another negative value if encryption failed. + */ +int mbedtls_block_cipher_encrypt(mbedtls_block_cipher_context_t *ctx, + const unsigned char input[16], + unsigned char output[16]); +/** + * \brief Clear the context. + * + * \param ctx The context to clear. + */ +void mbedtls_block_cipher_free(mbedtls_block_cipher_context_t *ctx); + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_BLOCK_CIPHER_INTERNAL_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/bn_mul.h b/tf-psa-crypto/drivers/builtin/src/bn_mul.h new file mode 100644 index 0000000000..d68f8d4f9b --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/bn_mul.h @@ -0,0 +1,1094 @@ +/** + * \file bn_mul.h + * + * \brief Multi-precision integer library + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +/* + * Multiply source vector [s] with b, add result + * to destination vector [d] and set carry c. + * + * Currently supports: + * + * . IA-32 (386+) . AMD64 / EM64T + * . IA-32 (SSE2) . Motorola 68000 + * . PowerPC, 32-bit . MicroBlaze + * . PowerPC, 64-bit . TriCore + * . SPARC v8 . ARM v3+ + * . Alpha . MIPS32 + * . C, longlong . C, generic + */ +#ifndef TF_PSA_CRYPTO_BN_MUL_H +#define TF_PSA_CRYPTO_BN_MUL_H + +#include "tf-psa-crypto/build_info.h" + +#include "mbedtls/private/bignum.h" + + +/* + * Conversion macros for embedded constants: + * build lists of mbedtls_mpi_uint's from lists of unsigned char's grouped by 8, 4 or 2 + */ +#if defined(MBEDTLS_HAVE_INT32) + +#define MBEDTLS_BYTES_TO_T_UINT_4(a, b, c, d) \ + ((mbedtls_mpi_uint) (a) << 0) | \ + ((mbedtls_mpi_uint) (b) << 8) | \ + ((mbedtls_mpi_uint) (c) << 16) | \ + ((mbedtls_mpi_uint) (d) << 24) + +#define MBEDTLS_BYTES_TO_T_UINT_2(a, b) \ + MBEDTLS_BYTES_TO_T_UINT_4(a, b, 0, 0) + +#define MBEDTLS_BYTES_TO_T_UINT_8(a, b, c, d, e, f, g, h) \ + MBEDTLS_BYTES_TO_T_UINT_4(a, b, c, d), \ + MBEDTLS_BYTES_TO_T_UINT_4(e, f, g, h) + +#else /* 64-bits */ + +#define MBEDTLS_BYTES_TO_T_UINT_8(a, b, c, d, e, f, g, h) \ + ((mbedtls_mpi_uint) (a) << 0) | \ + ((mbedtls_mpi_uint) (b) << 8) | \ + ((mbedtls_mpi_uint) (c) << 16) | \ + ((mbedtls_mpi_uint) (d) << 24) | \ + ((mbedtls_mpi_uint) (e) << 32) | \ + ((mbedtls_mpi_uint) (f) << 40) | \ + ((mbedtls_mpi_uint) (g) << 48) | \ + ((mbedtls_mpi_uint) (h) << 56) + +#define MBEDTLS_BYTES_TO_T_UINT_4(a, b, c, d) \ + MBEDTLS_BYTES_TO_T_UINT_8(a, b, c, d, 0, 0, 0, 0) + +#define MBEDTLS_BYTES_TO_T_UINT_2(a, b) \ + MBEDTLS_BYTES_TO_T_UINT_8(a, b, 0, 0, 0, 0, 0, 0) + +#endif /* bits in mbedtls_mpi_uint */ + +/* *INDENT-OFF* */ +#if defined(MBEDTLS_HAVE_ASM) + +/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */ +#if defined(__GNUC__) && \ + ( !defined(__ARMCC_VERSION) || __ARMCC_VERSION >= 6000000 ) + +/* + * GCC < 5.0 treated the x86 ebx (which is used for the GOT) as a + * fixed reserved register when building as PIC, leading to errors + * like: bn_mul.h:46:13: error: PIC register clobbered by 'ebx' in 'asm' + * + * This is fixed by an improved register allocator in GCC 5+. From the + * release notes: + * Register allocation improvements: Reuse of the PIC hard register, + * instead of using a fixed register, was implemented on x86/x86-64 + * targets. This improves generated PIC code performance as more hard + * registers can be used. + */ +#if defined(__GNUC__) && __GNUC__ < 5 && defined(__PIC__) +#define MULADDC_CANNOT_USE_EBX +#endif + +/* + * Disable use of the i386 assembly code below if option -O0, to disable all + * compiler optimisations, is passed, detected with __OPTIMIZE__ + * This is done as the number of registers used in the assembly code doesn't + * work with the -O0 option. + */ +#if defined(__i386__) && defined(__OPTIMIZE__) && !defined(MULADDC_CANNOT_USE_EBX) + +#define MULADDC_X1_INIT \ + { mbedtls_mpi_uint t; \ + asm( \ + "movl %%ebx, %0 \n\t" \ + "movl %5, %%esi \n\t" \ + "movl %6, %%edi \n\t" \ + "movl %7, %%ecx \n\t" \ + "movl %8, %%ebx \n\t" + +#define MULADDC_X1_CORE \ + "lodsl \n\t" \ + "mull %%ebx \n\t" \ + "addl %%ecx, %%eax \n\t" \ + "adcl $0, %%edx \n\t" \ + "addl (%%edi), %%eax \n\t" \ + "adcl $0, %%edx \n\t" \ + "movl %%edx, %%ecx \n\t" \ + "stosl \n\t" + +#define MULADDC_X1_STOP \ + "movl %4, %%ebx \n\t" \ + "movl %%ecx, %1 \n\t" \ + "movl %%edi, %2 \n\t" \ + "movl %%esi, %3 \n\t" \ + : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ + : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ + : "eax", "ebx", "ecx", "edx", "esi", "edi" \ + ); } + +#if defined(MBEDTLS_HAVE_SSE2) + +#define MULADDC_X8_INIT MULADDC_X1_INIT + +#define MULADDC_X8_CORE \ + "movd %%ecx, %%mm1 \n\t" \ + "movd %%ebx, %%mm0 \n\t" \ + "movd (%%edi), %%mm3 \n\t" \ + "paddq %%mm3, %%mm1 \n\t" \ + "movd (%%esi), %%mm2 \n\t" \ + "pmuludq %%mm0, %%mm2 \n\t" \ + "movd 4(%%esi), %%mm4 \n\t" \ + "pmuludq %%mm0, %%mm4 \n\t" \ + "movd 8(%%esi), %%mm6 \n\t" \ + "pmuludq %%mm0, %%mm6 \n\t" \ + "movd 12(%%esi), %%mm7 \n\t" \ + "pmuludq %%mm0, %%mm7 \n\t" \ + "paddq %%mm2, %%mm1 \n\t" \ + "movd 4(%%edi), %%mm3 \n\t" \ + "paddq %%mm4, %%mm3 \n\t" \ + "movd 8(%%edi), %%mm5 \n\t" \ + "paddq %%mm6, %%mm5 \n\t" \ + "movd 12(%%edi), %%mm4 \n\t" \ + "paddq %%mm4, %%mm7 \n\t" \ + "movd %%mm1, (%%edi) \n\t" \ + "movd 16(%%esi), %%mm2 \n\t" \ + "pmuludq %%mm0, %%mm2 \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "movd 20(%%esi), %%mm4 \n\t" \ + "pmuludq %%mm0, %%mm4 \n\t" \ + "paddq %%mm3, %%mm1 \n\t" \ + "movd 24(%%esi), %%mm6 \n\t" \ + "pmuludq %%mm0, %%mm6 \n\t" \ + "movd %%mm1, 4(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "movd 28(%%esi), %%mm3 \n\t" \ + "pmuludq %%mm0, %%mm3 \n\t" \ + "paddq %%mm5, %%mm1 \n\t" \ + "movd 16(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm2 \n\t" \ + "movd %%mm1, 8(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm7, %%mm1 \n\t" \ + "movd 20(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm4 \n\t" \ + "movd %%mm1, 12(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm2, %%mm1 \n\t" \ + "movd 24(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm6 \n\t" \ + "movd %%mm1, 16(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm4, %%mm1 \n\t" \ + "movd 28(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm3 \n\t" \ + "movd %%mm1, 20(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm6, %%mm1 \n\t" \ + "movd %%mm1, 24(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm3, %%mm1 \n\t" \ + "movd %%mm1, 28(%%edi) \n\t" \ + "addl $32, %%edi \n\t" \ + "addl $32, %%esi \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "movd %%mm1, %%ecx \n\t" + +#define MULADDC_X8_STOP \ + "emms \n\t" \ + "movl %4, %%ebx \n\t" \ + "movl %%ecx, %1 \n\t" \ + "movl %%edi, %2 \n\t" \ + "movl %%esi, %3 \n\t" \ + : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ + : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ + : "eax", "ebx", "ecx", "edx", "esi", "edi" \ + ); } \ + +#endif /* SSE2 */ + +#endif /* i386 */ + +#if defined(__amd64__) || defined (__x86_64__) + +#define MULADDC_X1_INIT \ + asm( \ + "xorq %%r8, %%r8\n" + +#define MULADDC_X1_CORE \ + "movq (%%rsi), %%rax\n" \ + "mulq %%rbx\n" \ + "addq $8, %%rsi\n" \ + "addq %%rcx, %%rax\n" \ + "movq %%r8, %%rcx\n" \ + "adcq $0, %%rdx\n" \ + "nop \n" \ + "addq %%rax, (%%rdi)\n" \ + "adcq %%rdx, %%rcx\n" \ + "addq $8, %%rdi\n" + +#define MULADDC_X1_STOP \ + : "+c" (c), "+D" (d), "+S" (s), "+m" (*(uint64_t (*)[16]) d) \ + : "b" (b), "m" (*(const uint64_t (*)[16]) s) \ + : "rax", "rdx", "r8" \ + ); + +#endif /* AMD64 */ + +// The following assembly code assumes that a pointer will fit in a 64-bit register +// (including ILP32 __aarch64__ ABIs such as on watchOS, hence the 2^32 - 1) +#if defined(__aarch64__) && (UINTPTR_MAX == 0xfffffffful || UINTPTR_MAX == 0xfffffffffffffffful) + +/* + * There are some issues around different compilers requiring different constraint + * syntax for updating pointers from assembly code (see notes for + * MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT in tf_psa_crypto_common.h), especially on aarch64_32 (aka ILP32). + * + * For this reason we cast the pointers to/from uintptr_t here. + */ +#define MULADDC_X1_INIT \ + do { uintptr_t muladdc_d = (uintptr_t) d, muladdc_s = (uintptr_t) s; asm( + +#define MULADDC_X1_CORE \ + "ldr x4, [%x2], #8 \n\t" \ + "ldr x5, [%x1] \n\t" \ + "mul x6, x4, %4 \n\t" \ + "umulh x7, x4, %4 \n\t" \ + "adds x5, x5, x6 \n\t" \ + "adc x7, x7, xzr \n\t" \ + "adds x5, x5, %0 \n\t" \ + "adc %0, x7, xzr \n\t" \ + "str x5, [%x1], #8 \n\t" + +#define MULADDC_X1_STOP \ + : "+r" (c), \ + "+r" (muladdc_d), \ + "+r" (muladdc_s), \ + "+m" (*(uint64_t (*)[16]) d) \ + : "r" (b), "m" (*(const uint64_t (*)[16]) s) \ + : "x4", "x5", "x6", "x7", "cc" \ + ); d = (mbedtls_mpi_uint *)muladdc_d; s = (mbedtls_mpi_uint *)muladdc_s; } while (0); + +#endif /* Aarch64 */ + +#if defined(__mc68020__) || defined(__mcpu32__) + +#define MULADDC_X1_INIT \ + asm( \ + "movl %3, %%a2 \n\t" \ + "movl %4, %%a3 \n\t" \ + "movl %5, %%d3 \n\t" \ + "movl %6, %%d2 \n\t" \ + "moveq #0, %%d0 \n\t" + +#define MULADDC_X1_CORE \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "moveq #0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "addxl %%d4, %%d3 \n\t" + +#define MULADDC_X1_STOP \ + "movl %%d3, %0 \n\t" \ + "movl %%a3, %1 \n\t" \ + "movl %%a2, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "d0", "d1", "d2", "d3", "d4", "a2", "a3" \ + ); + +#define MULADDC_X8_INIT MULADDC_X1_INIT + +#define MULADDC_X8_CORE \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "addxl %%d0, %%d3 \n\t" + +#define MULADDC_X8_STOP MULADDC_X1_STOP + +#endif /* MC68000 */ + +#if defined(__powerpc64__) || defined(__ppc64__) + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_X1_INIT \ + asm( \ + "ld r3, %3 \n\t" \ + "ld r4, %4 \n\t" \ + "ld r5, %5 \n\t" \ + "ld r6, %6 \n\t" \ + "addi r3, r3, -8 \n\t" \ + "addi r4, r4, -8 \n\t" \ + "addic r5, r5, 0 \n\t" + +#define MULADDC_X1_CORE \ + "ldu r7, 8(r3) \n\t" \ + "mulld r8, r7, r6 \n\t" \ + "mulhdu r9, r7, r6 \n\t" \ + "adde r8, r8, r5 \n\t" \ + "ld r7, 8(r4) \n\t" \ + "addze r5, r9 \n\t" \ + "addc r8, r8, r7 \n\t" \ + "stdu r8, 8(r4) \n\t" + +#define MULADDC_X1_STOP \ + "addze r5, r5 \n\t" \ + "addi r4, r4, 8 \n\t" \ + "addi r3, r3, 8 \n\t" \ + "std r5, %0 \n\t" \ + "std r4, %1 \n\t" \ + "std r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + + +#else /* __MACH__ && __APPLE__ */ + +#define MULADDC_X1_INIT \ + asm( \ + "ld %%r3, %3 \n\t" \ + "ld %%r4, %4 \n\t" \ + "ld %%r5, %5 \n\t" \ + "ld %%r6, %6 \n\t" \ + "addi %%r3, %%r3, -8 \n\t" \ + "addi %%r4, %%r4, -8 \n\t" \ + "addic %%r5, %%r5, 0 \n\t" + +#define MULADDC_X1_CORE \ + "ldu %%r7, 8(%%r3) \n\t" \ + "mulld %%r8, %%r7, %%r6 \n\t" \ + "mulhdu %%r9, %%r7, %%r6 \n\t" \ + "adde %%r8, %%r8, %%r5 \n\t" \ + "ld %%r7, 8(%%r4) \n\t" \ + "addze %%r5, %%r9 \n\t" \ + "addc %%r8, %%r8, %%r7 \n\t" \ + "stdu %%r8, 8(%%r4) \n\t" + +#define MULADDC_X1_STOP \ + "addze %%r5, %%r5 \n\t" \ + "addi %%r4, %%r4, 8 \n\t" \ + "addi %%r3, %%r3, 8 \n\t" \ + "std %%r5, %0 \n\t" \ + "std %%r4, %1 \n\t" \ + "std %%r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + +#endif /* __MACH__ && __APPLE__ */ + +#elif defined(__powerpc__) || defined(__ppc__) /* end PPC64/begin PPC32 */ + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_X1_INIT \ + asm( \ + "lwz r3, %3 \n\t" \ + "lwz r4, %4 \n\t" \ + "lwz r5, %5 \n\t" \ + "lwz r6, %6 \n\t" \ + "addi r3, r3, -4 \n\t" \ + "addi r4, r4, -4 \n\t" \ + "addic r5, r5, 0 \n\t" + +#define MULADDC_X1_CORE \ + "lwzu r7, 4(r3) \n\t" \ + "mullw r8, r7, r6 \n\t" \ + "mulhwu r9, r7, r6 \n\t" \ + "adde r8, r8, r5 \n\t" \ + "lwz r7, 4(r4) \n\t" \ + "addze r5, r9 \n\t" \ + "addc r8, r8, r7 \n\t" \ + "stwu r8, 4(r4) \n\t" + +#define MULADDC_X1_STOP \ + "addze r5, r5 \n\t" \ + "addi r4, r4, 4 \n\t" \ + "addi r3, r3, 4 \n\t" \ + "stw r5, %0 \n\t" \ + "stw r4, %1 \n\t" \ + "stw r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + +#else /* __MACH__ && __APPLE__ */ + +#define MULADDC_X1_INIT \ + asm( \ + "lwz %%r3, %3 \n\t" \ + "lwz %%r4, %4 \n\t" \ + "lwz %%r5, %5 \n\t" \ + "lwz %%r6, %6 \n\t" \ + "addi %%r3, %%r3, -4 \n\t" \ + "addi %%r4, %%r4, -4 \n\t" \ + "addic %%r5, %%r5, 0 \n\t" + +#define MULADDC_X1_CORE \ + "lwzu %%r7, 4(%%r3) \n\t" \ + "mullw %%r8, %%r7, %%r6 \n\t" \ + "mulhwu %%r9, %%r7, %%r6 \n\t" \ + "adde %%r8, %%r8, %%r5 \n\t" \ + "lwz %%r7, 4(%%r4) \n\t" \ + "addze %%r5, %%r9 \n\t" \ + "addc %%r8, %%r8, %%r7 \n\t" \ + "stwu %%r8, 4(%%r4) \n\t" + +#define MULADDC_X1_STOP \ + "addze %%r5, %%r5 \n\t" \ + "addi %%r4, %%r4, 4 \n\t" \ + "addi %%r3, %%r3, 4 \n\t" \ + "stw %%r5, %0 \n\t" \ + "stw %%r4, %1 \n\t" \ + "stw %%r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + +#endif /* __MACH__ && __APPLE__ */ + +#endif /* PPC32 */ + +/* + * The Sparc(64) assembly is reported to be broken. + * Disable it for now, until we're able to fix it. + */ +#if 0 && defined(__sparc__) +#if defined(__sparc64__) + +#define MULADDC_X1_INIT \ + asm( \ + "ldx %3, %%o0 \n\t" \ + "ldx %4, %%o1 \n\t" \ + "ld %5, %%o2 \n\t" \ + "ld %6, %%o3 \n\t" + +#define MULADDC_X1_CORE \ + "ld [%%o0], %%o4 \n\t" \ + "inc 4, %%o0 \n\t" \ + "ld [%%o1], %%o5 \n\t" \ + "umul %%o3, %%o4, %%o4 \n\t" \ + "addcc %%o4, %%o2, %%o4 \n\t" \ + "rd %%y, %%g1 \n\t" \ + "addx %%g1, 0, %%g1 \n\t" \ + "addcc %%o4, %%o5, %%o4 \n\t" \ + "st %%o4, [%%o1] \n\t" \ + "addx %%g1, 0, %%o2 \n\t" \ + "inc 4, %%o1 \n\t" + +#define MULADDC_X1_STOP \ + "st %%o2, %0 \n\t" \ + "stx %%o1, %1 \n\t" \ + "stx %%o0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "g1", "o0", "o1", "o2", "o3", "o4", \ + "o5" \ + ); + +#else /* __sparc64__ */ + +#define MULADDC_X1_INIT \ + asm( \ + "ld %3, %%o0 \n\t" \ + "ld %4, %%o1 \n\t" \ + "ld %5, %%o2 \n\t" \ + "ld %6, %%o3 \n\t" + +#define MULADDC_X1_CORE \ + "ld [%%o0], %%o4 \n\t" \ + "inc 4, %%o0 \n\t" \ + "ld [%%o1], %%o5 \n\t" \ + "umul %%o3, %%o4, %%o4 \n\t" \ + "addcc %%o4, %%o2, %%o4 \n\t" \ + "rd %%y, %%g1 \n\t" \ + "addx %%g1, 0, %%g1 \n\t" \ + "addcc %%o4, %%o5, %%o4 \n\t" \ + "st %%o4, [%%o1] \n\t" \ + "addx %%g1, 0, %%o2 \n\t" \ + "inc 4, %%o1 \n\t" + +#define MULADDC_X1_STOP \ + "st %%o2, %0 \n\t" \ + "st %%o1, %1 \n\t" \ + "st %%o0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "g1", "o0", "o1", "o2", "o3", "o4", \ + "o5" \ + ); + +#endif /* __sparc64__ */ +#endif /* __sparc__ */ + +#if defined(__microblaze__) || defined(microblaze) + +#define MULADDC_X1_INIT \ + asm( \ + "lwi r3, %3 \n\t" \ + "lwi r4, %4 \n\t" \ + "lwi r5, %5 \n\t" \ + "lwi r6, %6 \n\t" \ + "andi r7, r6, 0xffff \n\t" \ + "bsrli r6, r6, 16 \n\t" + +#if(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#define MULADDC_LHUI \ + "lhui r9, r3, 0 \n\t" \ + "addi r3, r3, 2 \n\t" \ + "lhui r8, r3, 0 \n\t" +#else +#define MULADDC_LHUI \ + "lhui r8, r3, 0 \n\t" \ + "addi r3, r3, 2 \n\t" \ + "lhui r9, r3, 0 \n\t" +#endif + +#define MULADDC_X1_CORE \ + MULADDC_LHUI \ + "addi r3, r3, 2 \n\t" \ + "mul r10, r9, r6 \n\t" \ + "mul r11, r8, r7 \n\t" \ + "mul r12, r9, r7 \n\t" \ + "mul r13, r8, r6 \n\t" \ + "bsrli r8, r10, 16 \n\t" \ + "bsrli r9, r11, 16 \n\t" \ + "add r13, r13, r8 \n\t" \ + "add r13, r13, r9 \n\t" \ + "bslli r10, r10, 16 \n\t" \ + "bslli r11, r11, 16 \n\t" \ + "add r12, r12, r10 \n\t" \ + "addc r13, r13, r0 \n\t" \ + "add r12, r12, r11 \n\t" \ + "addc r13, r13, r0 \n\t" \ + "lwi r10, r4, 0 \n\t" \ + "add r12, r12, r10 \n\t" \ + "addc r13, r13, r0 \n\t" \ + "add r12, r12, r5 \n\t" \ + "addc r5, r13, r0 \n\t" \ + "swi r12, r4, 0 \n\t" \ + "addi r4, r4, 4 \n\t" + +#define MULADDC_X1_STOP \ + "swi r5, %0 \n\t" \ + "swi r4, %1 \n\t" \ + "swi r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", \ + "r9", "r10", "r11", "r12", "r13" \ + ); + +#endif /* MicroBlaze */ + +#if defined(__tricore__) + +#define MULADDC_X1_INIT \ + asm( \ + "ld.a %%a2, %3 \n\t" \ + "ld.a %%a3, %4 \n\t" \ + "ld.w %%d4, %5 \n\t" \ + "ld.w %%d1, %6 \n\t" \ + "xor %%d5, %%d5 \n\t" + +#define MULADDC_X1_CORE \ + "ld.w %%d0, [%%a2+] \n\t" \ + "madd.u %%e2, %%e4, %%d0, %%d1 \n\t" \ + "ld.w %%d0, [%%a3] \n\t" \ + "addx %%d2, %%d2, %%d0 \n\t" \ + "addc %%d3, %%d3, 0 \n\t" \ + "mov %%d4, %%d3 \n\t" \ + "st.w [%%a3+], %%d2 \n\t" + +#define MULADDC_X1_STOP \ + "st.w %0, %%d4 \n\t" \ + "st.a %1, %%a3 \n\t" \ + "st.a %2, %%a2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "d0", "d1", "e2", "d4", "a2", "a3" \ + ); + +#endif /* TriCore */ + +#if defined(__arm__) + +#if defined(__thumb__) && !defined(__thumb2__) +#if defined(MBEDTLS_COMPILER_IS_GCC) +/* + * Thumb 1 ISA. This code path has only been tested successfully on gcc; + * it does not compile on clang or armclang. + */ + +#if !defined(__OPTIMIZE__) && defined(__GNUC__) +/* + * Note, gcc -O0 by default uses r7 for the frame pointer, so it complains about + * our use of r7 below, unless -fomit-frame-pointer is passed. + * + * On the other hand, -fomit-frame-pointer is implied by any -Ox options with + * x !=0, which we can detect using __OPTIMIZE__ (which is also defined by + * clang and armcc5 under the same conditions). + * + * If gcc needs to use r7, we use r1 as a scratch register and have a few extra + * instructions to preserve/restore it; otherwise, we can use r7 and avoid + * the preserve/restore overhead. + */ +#define MULADDC_SCRATCH "RS .req r1 \n\t" +#define MULADDC_PRESERVE_SCRATCH "mov r10, r1 \n\t" +#define MULADDC_RESTORE_SCRATCH "mov r1, r10 \n\t" +#define MULADDC_SCRATCH_CLOBBER "r10" +#else /* !defined(__OPTIMIZE__) && defined(__GNUC__) */ +#define MULADDC_SCRATCH "RS .req r7 \n\t" +#define MULADDC_PRESERVE_SCRATCH "" +#define MULADDC_RESTORE_SCRATCH "" +#define MULADDC_SCRATCH_CLOBBER "r7" +#endif /* !defined(__OPTIMIZE__) && defined(__GNUC__) */ + +#define MULADDC_X1_INIT \ + asm( \ + MULADDC_SCRATCH \ + "ldr r0, %3 \n\t" \ + "ldr r1, %4 \n\t" \ + "ldr r2, %5 \n\t" \ + "ldr r3, %6 \n\t" \ + "lsr r4, r3, #16 \n\t" \ + "mov r9, r4 \n\t" \ + "lsl r4, r3, #16 \n\t" \ + "lsr r4, r4, #16 \n\t" \ + "mov r8, r4 \n\t" \ + + +#define MULADDC_X1_CORE \ + MULADDC_PRESERVE_SCRATCH \ + "ldmia r0!, {r6} \n\t" \ + "lsr RS, r6, #16 \n\t" \ + "lsl r6, r6, #16 \n\t" \ + "lsr r6, r6, #16 \n\t" \ + "mov r4, r8 \n\t" \ + "mul r4, r6 \n\t" \ + "mov r3, r9 \n\t" \ + "mul r6, r3 \n\t" \ + "mov r5, r9 \n\t" \ + "mul r5, RS \n\t" \ + "mov r3, r8 \n\t" \ + "mul RS, r3 \n\t" \ + "lsr r3, r6, #16 \n\t" \ + "add r5, r5, r3 \n\t" \ + "lsr r3, RS, #16 \n\t" \ + "add r5, r5, r3 \n\t" \ + "add r4, r4, r2 \n\t" \ + "mov r2, #0 \n\t" \ + "adc r5, r2 \n\t" \ + "lsl r3, r6, #16 \n\t" \ + "add r4, r4, r3 \n\t" \ + "adc r5, r2 \n\t" \ + "lsl r3, RS, #16 \n\t" \ + "add r4, r4, r3 \n\t" \ + "adc r5, r2 \n\t" \ + MULADDC_RESTORE_SCRATCH \ + "ldr r3, [r1] \n\t" \ + "add r4, r4, r3 \n\t" \ + "adc r2, r5 \n\t" \ + "stmia r1!, {r4} \n\t" + +#define MULADDC_X1_STOP \ + "str r2, %0 \n\t" \ + "str r1, %1 \n\t" \ + "str r0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", MULADDC_SCRATCH_CLOBBER, "r8", "r9", "cc" \ + ); +#endif /* !defined(__ARMCC_VERSION) && !defined(__clang__) */ + +#elif (__ARM_ARCH >= 6) && \ + defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1) +/* Armv6-M (or later) with DSP Instruction Set Extensions. + * Requires support for either Thumb 2 or Arm ISA. + */ + +#define MULADDC_X1_INIT \ + { \ + mbedtls_mpi_uint tmp_a, tmp_b; \ + asm volatile ( + +#define MULADDC_X1_CORE \ + ".p2align 2 \n\t" \ + "ldr %[a], [%[in]], #4 \n\t" \ + "ldr %[b], [%[acc]] \n\t" \ + "umaal %[b], %[carry], %[scalar], %[a] \n\t" \ + "str %[b], [%[acc]], #4 \n\t" + +#define MULADDC_X1_STOP \ + : [a] "=&r" (tmp_a), \ + [b] "=&r" (tmp_b), \ + [in] "+r" (s), \ + [acc] "+r" (d), \ + [carry] "+l" (c) \ + : [scalar] "r" (b) \ + : "memory" \ + ); \ + } + +#define MULADDC_X2_INIT \ + { \ + mbedtls_mpi_uint tmp_a0, tmp_b0; \ + mbedtls_mpi_uint tmp_a1, tmp_b1; \ + asm volatile ( + + /* - Make sure loop is 4-byte aligned to avoid stalls + * upon repeated non-word aligned instructions in + * some microarchitectures. + * - Don't use ldm with post-increment or back-to-back + * loads with post-increment and same address register + * to avoid stalls on some microarchitectures. + * - Bunch loads and stores to reduce latency on some + * microarchitectures. E.g., on Cortex-M4, the first + * in a series of load/store operations has latency + * 2 cycles, while subsequent loads/stores are single-cycle. */ +#define MULADDC_X2_CORE \ + ".p2align 2 \n\t" \ + "ldr %[a0], [%[in]], #+8 \n\t" \ + "ldr %[b0], [%[acc]], #+8 \n\t" \ + "ldr %[a1], [%[in], #-4] \n\t" \ + "ldr %[b1], [%[acc], #-4] \n\t" \ + "umaal %[b0], %[carry], %[scalar], %[a0] \n\t" \ + "umaal %[b1], %[carry], %[scalar], %[a1] \n\t" \ + "str %[b0], [%[acc], #-8] \n\t" \ + "str %[b1], [%[acc], #-4] \n\t" + +#define MULADDC_X2_STOP \ + : [a0] "=&r" (tmp_a0), \ + [b0] "=&r" (tmp_b0), \ + [a1] "=&r" (tmp_a1), \ + [b1] "=&r" (tmp_b1), \ + [in] "+r" (s), \ + [acc] "+r" (d), \ + [carry] "+l" (c) \ + : [scalar] "r" (b) \ + : "memory" \ + ); \ + } + +#else /* Thumb 2 or Arm ISA, without DSP extensions */ + +#define MULADDC_X1_INIT \ + asm( \ + "ldr r0, %3 \n\t" \ + "ldr r1, %4 \n\t" \ + "ldr r2, %5 \n\t" \ + "ldr r3, %6 \n\t" + +#define MULADDC_X1_CORE \ + "ldr r4, [r0], #4 \n\t" \ + "mov r5, #0 \n\t" \ + "ldr r6, [r1] \n\t" \ + "umlal r2, r5, r3, r4 \n\t" \ + "adds r4, r6, r2 \n\t" \ + "adc r2, r5, #0 \n\t" \ + "str r4, [r1], #4 \n\t" + +#define MULADDC_X1_STOP \ + "str r2, %0 \n\t" \ + "str r1, %1 \n\t" \ + "str r0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", "cc" \ + ); + +#endif /* ISA codepath selection */ + +#endif /* defined(__arm__) */ + +#if defined(__alpha__) + +#define MULADDC_X1_INIT \ + asm( \ + "ldq $1, %3 \n\t" \ + "ldq $2, %4 \n\t" \ + "ldq $3, %5 \n\t" \ + "ldq $4, %6 \n\t" + +#define MULADDC_X1_CORE \ + "ldq $6, 0($1) \n\t" \ + "addq $1, 8, $1 \n\t" \ + "mulq $6, $4, $7 \n\t" \ + "umulh $6, $4, $6 \n\t" \ + "addq $7, $3, $7 \n\t" \ + "cmpult $7, $3, $3 \n\t" \ + "ldq $5, 0($2) \n\t" \ + "addq $7, $5, $7 \n\t" \ + "cmpult $7, $5, $5 \n\t" \ + "stq $7, 0($2) \n\t" \ + "addq $2, 8, $2 \n\t" \ + "addq $6, $3, $3 \n\t" \ + "addq $5, $3, $3 \n\t" + +#define MULADDC_X1_STOP \ + "stq $3, %0 \n\t" \ + "stq $2, %1 \n\t" \ + "stq $1, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "$1", "$2", "$3", "$4", "$5", "$6", "$7" \ + ); +#endif /* Alpha */ + +#if defined(__mips__) && !defined(__mips64) + +#define MULADDC_X1_INIT \ + asm( \ + "lw $10, %3 \n\t" \ + "lw $11, %4 \n\t" \ + "lw $12, %5 \n\t" \ + "lw $13, %6 \n\t" + +#define MULADDC_X1_CORE \ + "lw $14, 0($10) \n\t" \ + "multu $13, $14 \n\t" \ + "addi $10, $10, 4 \n\t" \ + "mflo $14 \n\t" \ + "mfhi $9 \n\t" \ + "addu $14, $12, $14 \n\t" \ + "lw $15, 0($11) \n\t" \ + "sltu $12, $14, $12 \n\t" \ + "addu $15, $14, $15 \n\t" \ + "sltu $14, $15, $14 \n\t" \ + "addu $12, $12, $9 \n\t" \ + "sw $15, 0($11) \n\t" \ + "addu $12, $12, $14 \n\t" \ + "addi $11, $11, 4 \n\t" + +#define MULADDC_X1_STOP \ + "sw $12, %0 \n\t" \ + "sw $11, %1 \n\t" \ + "sw $10, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "$9", "$10", "$11", "$12", "$13", "$14", "$15", "lo", "hi" \ + ); + +#endif /* MIPS */ +#endif /* GNUC */ + +#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) + +#define MULADDC_X1_INIT \ + __asm mov esi, s \ + __asm mov edi, d \ + __asm mov ecx, c \ + __asm mov ebx, b + +#define MULADDC_X1_CORE \ + __asm lodsd \ + __asm mul ebx \ + __asm add eax, ecx \ + __asm adc edx, 0 \ + __asm add eax, [edi] \ + __asm adc edx, 0 \ + __asm mov ecx, edx \ + __asm stosd + +#define MULADDC_X1_STOP \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi + +#if defined(MBEDTLS_HAVE_SSE2) + +#define EMIT __asm _emit + +#define MULADDC_X8_INIT MULADDC_X1_INIT + +#define MULADDC_X8_CORE \ + EMIT 0x0F EMIT 0x6E EMIT 0xC9 \ + EMIT 0x0F EMIT 0x6E EMIT 0xC3 \ + EMIT 0x0F EMIT 0x6E EMIT 0x1F \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x16 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x04 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x08 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x7E EMIT 0x0C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x5F EMIT 0x04 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x08 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xEE \ + EMIT 0x0F EMIT 0x6E EMIT 0x67 EMIT 0x0C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xFC \ + EMIT 0x0F EMIT 0x7E EMIT 0x0F \ + EMIT 0x0F EMIT 0x6E EMIT 0x56 EMIT 0x10 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x14 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x18 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x04 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x5E EMIT 0x1C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCD \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x10 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xD5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x08 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCF \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x14 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xE5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x0C \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x18 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xF5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x10 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x1C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDD \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x14 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCE \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x18 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x1C \ + EMIT 0x83 EMIT 0xC7 EMIT 0x20 \ + EMIT 0x83 EMIT 0xC6 EMIT 0x20 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x7E EMIT 0xC9 + +#define MULADDC_X8_STOP \ + EMIT 0x0F EMIT 0x77 \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi + +#endif /* SSE2 */ +#endif /* MSVC */ + +#endif /* MBEDTLS_HAVE_ASM */ + +#if !defined(MULADDC_X1_CORE) +#if defined(MBEDTLS_HAVE_UDBL) + +#define MULADDC_X1_INIT \ +{ \ + mbedtls_t_udbl r; \ + mbedtls_mpi_uint r0, r1; + +#define MULADDC_X1_CORE \ + r = *(s++) * (mbedtls_t_udbl) b; \ + r0 = (mbedtls_mpi_uint) r; \ + r1 = (mbedtls_mpi_uint)( r >> biL ); \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_X1_STOP \ +} + +#else /* MBEDTLS_HAVE_UDBL */ + +#define MULADDC_X1_INIT \ +{ \ + mbedtls_mpi_uint s0, s1, b0, b1; \ + mbedtls_mpi_uint r0, r1, rx, ry; \ + b0 = ( b << biH ) >> biH; \ + b1 = ( b >> biH ); + +#define MULADDC_X1_CORE \ + s0 = ( *s << biH ) >> biH; \ + s1 = ( *s >> biH ); s++; \ + rx = s0 * b1; r0 = s0 * b0; \ + ry = s1 * b0; r1 = s1 * b1; \ + r1 += ( rx >> biH ); \ + r1 += ( ry >> biH ); \ + rx <<= biH; ry <<= biH; \ + r0 += rx; r1 += (r0 < rx); \ + r0 += ry; r1 += (r0 < ry); \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_X1_STOP \ +} + +#endif /* C (longlong) */ +#endif /* C (generic) */ + +#if !defined(MULADDC_X2_CORE) +#define MULADDC_X2_INIT MULADDC_X1_INIT +#define MULADDC_X2_STOP MULADDC_X1_STOP +#define MULADDC_X2_CORE MULADDC_X1_CORE MULADDC_X1_CORE +#endif /* MULADDC_X2_CORE */ + +#if !defined(MULADDC_X4_CORE) +#define MULADDC_X4_INIT MULADDC_X2_INIT +#define MULADDC_X4_STOP MULADDC_X2_STOP +#define MULADDC_X4_CORE MULADDC_X2_CORE MULADDC_X2_CORE +#endif /* MULADDC_X4_CORE */ + +#if !defined(MULADDC_X8_CORE) +#define MULADDC_X8_INIT MULADDC_X4_INIT +#define MULADDC_X8_STOP MULADDC_X4_STOP +#define MULADDC_X8_CORE MULADDC_X4_CORE MULADDC_X4_CORE +#endif /* MULADDC_X8_CORE */ + +/* *INDENT-ON* */ +#endif /* TF_PSA_CRYPTO_BN_MUL_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/camellia.c b/tf-psa-crypto/drivers/builtin/src/camellia.c new file mode 100644 index 0000000000..0007f792ac --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/camellia.c @@ -0,0 +1,1055 @@ +/* + * Camellia implementation + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +/* + * The Camellia block cipher was designed by NTT and Mitsubishi Electric + * Corporation. + * + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/01espec.pdf + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_CAMELLIA_C) + +#include "mbedtls/private/camellia.h" +#include "mbedtls/platform_util.h" + +#include + +#include "mbedtls/platform.h" + +static const unsigned char SIGMA_CHARS[6][8] = +{ + { 0xa0, 0x9e, 0x66, 0x7f, 0x3b, 0xcc, 0x90, 0x8b }, + { 0xb6, 0x7a, 0xe8, 0x58, 0x4c, 0xaa, 0x73, 0xb2 }, + { 0xc6, 0xef, 0x37, 0x2f, 0xe9, 0x4f, 0x82, 0xbe }, + { 0x54, 0xff, 0x53, 0xa5, 0xf1, 0xd3, 0x6f, 0x1c }, + { 0x10, 0xe5, 0x27, 0xfa, 0xde, 0x68, 0x2d, 0x1d }, + { 0xb0, 0x56, 0x88, 0xc2, 0xb3, 0xe6, 0xc1, 0xfd } +}; + +#if defined(MBEDTLS_CAMELLIA_SMALL_MEMORY) + +static const unsigned char FSb[256] = +{ + 112, 130, 44, 236, 179, 39, 192, 229, 228, 133, 87, 53, 234, 12, 174, 65, + 35, 239, 107, 147, 69, 25, 165, 33, 237, 14, 79, 78, 29, 101, 146, 189, + 134, 184, 175, 143, 124, 235, 31, 206, 62, 48, 220, 95, 94, 197, 11, 26, + 166, 225, 57, 202, 213, 71, 93, 61, 217, 1, 90, 214, 81, 86, 108, 77, + 139, 13, 154, 102, 251, 204, 176, 45, 116, 18, 43, 32, 240, 177, 132, 153, + 223, 76, 203, 194, 52, 126, 118, 5, 109, 183, 169, 49, 209, 23, 4, 215, + 20, 88, 58, 97, 222, 27, 17, 28, 50, 15, 156, 22, 83, 24, 242, 34, + 254, 68, 207, 178, 195, 181, 122, 145, 36, 8, 232, 168, 96, 252, 105, 80, + 170, 208, 160, 125, 161, 137, 98, 151, 84, 91, 30, 149, 224, 255, 100, 210, + 16, 196, 0, 72, 163, 247, 117, 219, 138, 3, 230, 218, 9, 63, 221, 148, + 135, 92, 131, 2, 205, 74, 144, 51, 115, 103, 246, 243, 157, 127, 191, 226, + 82, 155, 216, 38, 200, 55, 198, 59, 129, 150, 111, 75, 19, 190, 99, 46, + 233, 121, 167, 140, 159, 110, 188, 142, 41, 245, 249, 182, 47, 253, 180, 89, + 120, 152, 6, 106, 231, 70, 113, 186, 212, 37, 171, 66, 136, 162, 141, 250, + 114, 7, 185, 85, 248, 238, 172, 10, 54, 73, 42, 104, 60, 56, 241, 164, + 64, 40, 211, 123, 187, 201, 67, 193, 21, 227, 173, 244, 119, 199, 128, 158 +}; + +#define SBOX1(n) FSb[(n)] +#define SBOX2(n) (unsigned char) ((FSb[(n)] >> 7 ^ FSb[(n)] << 1) & 0xff) +#define SBOX3(n) (unsigned char) ((FSb[(n)] >> 1 ^ FSb[(n)] << 7) & 0xff) +#define SBOX4(n) FSb[((n) << 1 ^ (n) >> 7) &0xff] + +#else /* MBEDTLS_CAMELLIA_SMALL_MEMORY */ + +static const unsigned char FSb[256] = +{ + 112, 130, 44, 236, 179, 39, 192, 229, 228, 133, 87, 53, 234, 12, 174, 65, + 35, 239, 107, 147, 69, 25, 165, 33, 237, 14, 79, 78, 29, 101, 146, 189, + 134, 184, 175, 143, 124, 235, 31, 206, 62, 48, 220, 95, 94, 197, 11, 26, + 166, 225, 57, 202, 213, 71, 93, 61, 217, 1, 90, 214, 81, 86, 108, 77, + 139, 13, 154, 102, 251, 204, 176, 45, 116, 18, 43, 32, 240, 177, 132, 153, + 223, 76, 203, 194, 52, 126, 118, 5, 109, 183, 169, 49, 209, 23, 4, 215, + 20, 88, 58, 97, 222, 27, 17, 28, 50, 15, 156, 22, 83, 24, 242, 34, + 254, 68, 207, 178, 195, 181, 122, 145, 36, 8, 232, 168, 96, 252, 105, 80, + 170, 208, 160, 125, 161, 137, 98, 151, 84, 91, 30, 149, 224, 255, 100, 210, + 16, 196, 0, 72, 163, 247, 117, 219, 138, 3, 230, 218, 9, 63, 221, 148, + 135, 92, 131, 2, 205, 74, 144, 51, 115, 103, 246, 243, 157, 127, 191, 226, + 82, 155, 216, 38, 200, 55, 198, 59, 129, 150, 111, 75, 19, 190, 99, 46, + 233, 121, 167, 140, 159, 110, 188, 142, 41, 245, 249, 182, 47, 253, 180, 89, + 120, 152, 6, 106, 231, 70, 113, 186, 212, 37, 171, 66, 136, 162, 141, 250, + 114, 7, 185, 85, 248, 238, 172, 10, 54, 73, 42, 104, 60, 56, 241, 164, + 64, 40, 211, 123, 187, 201, 67, 193, 21, 227, 173, 244, 119, 199, 128, 158 +}; + +static const unsigned char FSb2[256] = +{ + 224, 5, 88, 217, 103, 78, 129, 203, 201, 11, 174, 106, 213, 24, 93, 130, + 70, 223, 214, 39, 138, 50, 75, 66, 219, 28, 158, 156, 58, 202, 37, 123, + 13, 113, 95, 31, 248, 215, 62, 157, 124, 96, 185, 190, 188, 139, 22, 52, + 77, 195, 114, 149, 171, 142, 186, 122, 179, 2, 180, 173, 162, 172, 216, 154, + 23, 26, 53, 204, 247, 153, 97, 90, 232, 36, 86, 64, 225, 99, 9, 51, + 191, 152, 151, 133, 104, 252, 236, 10, 218, 111, 83, 98, 163, 46, 8, 175, + 40, 176, 116, 194, 189, 54, 34, 56, 100, 30, 57, 44, 166, 48, 229, 68, + 253, 136, 159, 101, 135, 107, 244, 35, 72, 16, 209, 81, 192, 249, 210, 160, + 85, 161, 65, 250, 67, 19, 196, 47, 168, 182, 60, 43, 193, 255, 200, 165, + 32, 137, 0, 144, 71, 239, 234, 183, 21, 6, 205, 181, 18, 126, 187, 41, + 15, 184, 7, 4, 155, 148, 33, 102, 230, 206, 237, 231, 59, 254, 127, 197, + 164, 55, 177, 76, 145, 110, 141, 118, 3, 45, 222, 150, 38, 125, 198, 92, + 211, 242, 79, 25, 63, 220, 121, 29, 82, 235, 243, 109, 94, 251, 105, 178, + 240, 49, 12, 212, 207, 140, 226, 117, 169, 74, 87, 132, 17, 69, 27, 245, + 228, 14, 115, 170, 241, 221, 89, 20, 108, 146, 84, 208, 120, 112, 227, 73, + 128, 80, 167, 246, 119, 147, 134, 131, 42, 199, 91, 233, 238, 143, 1, 61 +}; + +static const unsigned char FSb3[256] = +{ + 56, 65, 22, 118, 217, 147, 96, 242, 114, 194, 171, 154, 117, 6, 87, 160, + 145, 247, 181, 201, 162, 140, 210, 144, 246, 7, 167, 39, 142, 178, 73, 222, + 67, 92, 215, 199, 62, 245, 143, 103, 31, 24, 110, 175, 47, 226, 133, 13, + 83, 240, 156, 101, 234, 163, 174, 158, 236, 128, 45, 107, 168, 43, 54, 166, + 197, 134, 77, 51, 253, 102, 88, 150, 58, 9, 149, 16, 120, 216, 66, 204, + 239, 38, 229, 97, 26, 63, 59, 130, 182, 219, 212, 152, 232, 139, 2, 235, + 10, 44, 29, 176, 111, 141, 136, 14, 25, 135, 78, 11, 169, 12, 121, 17, + 127, 34, 231, 89, 225, 218, 61, 200, 18, 4, 116, 84, 48, 126, 180, 40, + 85, 104, 80, 190, 208, 196, 49, 203, 42, 173, 15, 202, 112, 255, 50, 105, + 8, 98, 0, 36, 209, 251, 186, 237, 69, 129, 115, 109, 132, 159, 238, 74, + 195, 46, 193, 1, 230, 37, 72, 153, 185, 179, 123, 249, 206, 191, 223, 113, + 41, 205, 108, 19, 100, 155, 99, 157, 192, 75, 183, 165, 137, 95, 177, 23, + 244, 188, 211, 70, 207, 55, 94, 71, 148, 250, 252, 91, 151, 254, 90, 172, + 60, 76, 3, 53, 243, 35, 184, 93, 106, 146, 213, 33, 68, 81, 198, 125, + 57, 131, 220, 170, 124, 119, 86, 5, 27, 164, 21, 52, 30, 28, 248, 82, + 32, 20, 233, 189, 221, 228, 161, 224, 138, 241, 214, 122, 187, 227, 64, 79 +}; + +static const unsigned char FSb4[256] = +{ + 112, 44, 179, 192, 228, 87, 234, 174, 35, 107, 69, 165, 237, 79, 29, 146, + 134, 175, 124, 31, 62, 220, 94, 11, 166, 57, 213, 93, 217, 90, 81, 108, + 139, 154, 251, 176, 116, 43, 240, 132, 223, 203, 52, 118, 109, 169, 209, 4, + 20, 58, 222, 17, 50, 156, 83, 242, 254, 207, 195, 122, 36, 232, 96, 105, + 170, 160, 161, 98, 84, 30, 224, 100, 16, 0, 163, 117, 138, 230, 9, 221, + 135, 131, 205, 144, 115, 246, 157, 191, 82, 216, 200, 198, 129, 111, 19, 99, + 233, 167, 159, 188, 41, 249, 47, 180, 120, 6, 231, 113, 212, 171, 136, 141, + 114, 185, 248, 172, 54, 42, 60, 241, 64, 211, 187, 67, 21, 173, 119, 128, + 130, 236, 39, 229, 133, 53, 12, 65, 239, 147, 25, 33, 14, 78, 101, 189, + 184, 143, 235, 206, 48, 95, 197, 26, 225, 202, 71, 61, 1, 214, 86, 77, + 13, 102, 204, 45, 18, 32, 177, 153, 76, 194, 126, 5, 183, 49, 23, 215, + 88, 97, 27, 28, 15, 22, 24, 34, 68, 178, 181, 145, 8, 168, 252, 80, + 208, 125, 137, 151, 91, 149, 255, 210, 196, 72, 247, 219, 3, 218, 63, 148, + 92, 2, 74, 51, 103, 243, 127, 226, 155, 38, 55, 59, 150, 75, 190, 46, + 121, 140, 110, 142, 245, 182, 253, 89, 152, 106, 70, 186, 37, 66, 162, 250, + 7, 85, 238, 10, 73, 104, 56, 164, 40, 123, 201, 193, 227, 244, 199, 158 +}; + +#define SBOX1(n) FSb[(n)] +#define SBOX2(n) FSb2[(n)] +#define SBOX3(n) FSb3[(n)] +#define SBOX4(n) FSb4[(n)] + +#endif /* MBEDTLS_CAMELLIA_SMALL_MEMORY */ + +static const unsigned char shifts[2][4][4] = +{ + { + { 1, 1, 1, 1 }, /* KL */ + { 0, 0, 0, 0 }, /* KR */ + { 1, 1, 1, 1 }, /* KA */ + { 0, 0, 0, 0 } /* KB */ + }, + { + { 1, 0, 1, 1 }, /* KL */ + { 1, 1, 0, 1 }, /* KR */ + { 1, 1, 1, 0 }, /* KA */ + { 1, 1, 0, 1 } /* KB */ + } +}; + +static const signed char indexes[2][4][20] = +{ + { + { 0, 1, 2, 3, 8, 9, 10, 11, 38, 39, + 36, 37, 23, 20, 21, 22, 27, -1, -1, 26 }, /* KL -> RK */ + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /* KR -> RK */ + { 4, 5, 6, 7, 12, 13, 14, 15, 16, 17, + 18, 19, -1, 24, 25, -1, 31, 28, 29, 30 }, /* KA -> RK */ + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } /* KB -> RK */ + }, + { + { 0, 1, 2, 3, 61, 62, 63, 60, -1, -1, + -1, -1, 27, 24, 25, 26, 35, 32, 33, 34 }, /* KL -> RK */ + { -1, -1, -1, -1, 8, 9, 10, 11, 16, 17, + 18, 19, -1, -1, -1, -1, 39, 36, 37, 38 }, /* KR -> RK */ + { -1, -1, -1, -1, 12, 13, 14, 15, 58, 59, + 56, 57, 31, 28, 29, 30, -1, -1, -1, -1 }, /* KA -> RK */ + { 4, 5, 6, 7, 65, 66, 67, 64, 20, 21, + 22, 23, -1, -1, -1, -1, 43, 40, 41, 42 } /* KB -> RK */ + } +}; + +static const signed char transposes[2][20] = +{ + { + 21, 22, 23, 20, + -1, -1, -1, -1, + 18, 19, 16, 17, + 11, 8, 9, 10, + 15, 12, 13, 14 + }, + { + 25, 26, 27, 24, + 29, 30, 31, 28, + 18, 19, 16, 17, + -1, -1, -1, -1, + -1, -1, -1, -1 + } +}; + +/* Shift macro for 128 bit strings with rotation smaller than 32 bits (!) */ +#define ROTL(DEST, SRC, SHIFT) \ + { \ + (DEST)[0] = (SRC)[0] << (SHIFT) ^ (SRC)[1] >> (32 - (SHIFT)); \ + (DEST)[1] = (SRC)[1] << (SHIFT) ^ (SRC)[2] >> (32 - (SHIFT)); \ + (DEST)[2] = (SRC)[2] << (SHIFT) ^ (SRC)[3] >> (32 - (SHIFT)); \ + (DEST)[3] = (SRC)[3] << (SHIFT) ^ (SRC)[0] >> (32 - (SHIFT)); \ + } + +#define FL(XL, XR, KL, KR) \ + { \ + (XR) = ((((XL) &(KL)) << 1) | (((XL) &(KL)) >> 31)) ^ (XR); \ + (XL) = ((XR) | (KR)) ^ (XL); \ + } + +#define FLInv(YL, YR, KL, KR) \ + { \ + (YL) = ((YR) | (KR)) ^ (YL); \ + (YR) = ((((YL) &(KL)) << 1) | (((YL) &(KL)) >> 31)) ^ (YR); \ + } + +#define SHIFT_AND_PLACE(INDEX, OFFSET) \ + { \ + TK[0] = KC[(OFFSET) * 4 + 0]; \ + TK[1] = KC[(OFFSET) * 4 + 1]; \ + TK[2] = KC[(OFFSET) * 4 + 2]; \ + TK[3] = KC[(OFFSET) * 4 + 3]; \ + \ + for (i = 1; i <= 4; i++) \ + if (shifts[(INDEX)][(OFFSET)][i -1]) \ + ROTL(TK + i * 4, TK, (15 * i) % 32); \ + \ + for (i = 0; i < 20; i++) \ + if (indexes[(INDEX)][(OFFSET)][i] != -1) { \ + RK[indexes[(INDEX)][(OFFSET)][i]] = TK[i]; \ + } \ + } + +static void camellia_feistel(const uint32_t x[2], const uint32_t k[2], + uint32_t z[2]) +{ + uint32_t I0, I1; + I0 = x[0] ^ k[0]; + I1 = x[1] ^ k[1]; + + I0 = ((uint32_t) SBOX1(MBEDTLS_BYTE_3(I0)) << 24) | + ((uint32_t) SBOX2(MBEDTLS_BYTE_2(I0)) << 16) | + ((uint32_t) SBOX3(MBEDTLS_BYTE_1(I0)) << 8) | + ((uint32_t) SBOX4(MBEDTLS_BYTE_0(I0))); + I1 = ((uint32_t) SBOX2(MBEDTLS_BYTE_3(I1)) << 24) | + ((uint32_t) SBOX3(MBEDTLS_BYTE_2(I1)) << 16) | + ((uint32_t) SBOX4(MBEDTLS_BYTE_1(I1)) << 8) | + ((uint32_t) SBOX1(MBEDTLS_BYTE_0(I1))); + + I0 ^= (I1 << 8) | (I1 >> 24); + I1 ^= (I0 << 16) | (I0 >> 16); + I0 ^= (I1 >> 8) | (I1 << 24); + I1 ^= (I0 >> 8) | (I0 << 24); + + z[0] ^= I1; + z[1] ^= I0; +} + +void mbedtls_camellia_init(mbedtls_camellia_context *ctx) +{ + memset(ctx, 0, sizeof(mbedtls_camellia_context)); +} + +void mbedtls_camellia_free(mbedtls_camellia_context *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_camellia_context)); +} + +/* + * Camellia key schedule (encryption) + */ +int mbedtls_camellia_setkey_enc(mbedtls_camellia_context *ctx, + const unsigned char *key, + unsigned int keybits) +{ + int idx; + size_t i; + uint32_t *RK; + unsigned char t[64]; + uint32_t SIGMA[6][2]; + uint32_t KC[16]; + uint32_t TK[20]; + + RK = ctx->rk; + + memset(t, 0, 64); + memset(RK, 0, sizeof(ctx->rk)); + + switch (keybits) { + case 128: ctx->nr = 3; idx = 0; break; + case 192: + case 256: ctx->nr = 4; idx = 1; break; + default: return MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA; + } + + for (i = 0; i < keybits / 8; ++i) { + t[i] = key[i]; + } + + if (keybits == 192) { + for (i = 0; i < 8; i++) { + t[24 + i] = ~t[16 + i]; + } + } + + /* + * Prepare SIGMA values + */ + for (i = 0; i < 6; i++) { + SIGMA[i][0] = MBEDTLS_GET_UINT32_BE(SIGMA_CHARS[i], 0); + SIGMA[i][1] = MBEDTLS_GET_UINT32_BE(SIGMA_CHARS[i], 4); + } + + /* + * Key storage in KC + * Order: KL, KR, KA, KB + */ + memset(KC, 0, sizeof(KC)); + + /* Store KL, KR */ + for (i = 0; i < 8; i++) { + KC[i] = MBEDTLS_GET_UINT32_BE(t, i * 4); + } + + /* Generate KA */ + for (i = 0; i < 4; ++i) { + KC[8 + i] = KC[i] ^ KC[4 + i]; + } + + camellia_feistel(KC + 8, SIGMA[0], KC + 10); + camellia_feistel(KC + 10, SIGMA[1], KC + 8); + + for (i = 0; i < 4; ++i) { + KC[8 + i] ^= KC[i]; + } + + camellia_feistel(KC + 8, SIGMA[2], KC + 10); + camellia_feistel(KC + 10, SIGMA[3], KC + 8); + + if (keybits > 128) { + /* Generate KB */ + for (i = 0; i < 4; ++i) { + KC[12 + i] = KC[4 + i] ^ KC[8 + i]; + } + + camellia_feistel(KC + 12, SIGMA[4], KC + 14); + camellia_feistel(KC + 14, SIGMA[5], KC + 12); + } + + /* + * Generating subkeys + */ + + /* Manipulating KL */ + SHIFT_AND_PLACE(idx, 0); + + /* Manipulating KR */ + if (keybits > 128) { + SHIFT_AND_PLACE(idx, 1); + } + + /* Manipulating KA */ + SHIFT_AND_PLACE(idx, 2); + + /* Manipulating KB */ + if (keybits > 128) { + SHIFT_AND_PLACE(idx, 3); + } + + /* Do transpositions */ + for (i = 0; i < 20; i++) { + if (transposes[idx][i] != -1) { + RK[32 + 12 * idx + i] = RK[transposes[idx][i]]; + } + } + + return 0; +} + +/* + * Camellia key schedule (decryption) + */ +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +int mbedtls_camellia_setkey_dec(mbedtls_camellia_context *ctx, + const unsigned char *key, + unsigned int keybits) +{ + int idx, ret; + size_t i; + mbedtls_camellia_context cty; + uint32_t *RK; + uint32_t *SK; + + mbedtls_camellia_init(&cty); + + /* Also checks keybits */ + if ((ret = mbedtls_camellia_setkey_enc(&cty, key, keybits)) != 0) { + goto exit; + } + + ctx->nr = cty.nr; + idx = (ctx->nr == 4); + + RK = ctx->rk; + SK = cty.rk + 24 * 2 + 8 * idx * 2; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + for (i = 22 + 8 * idx, SK -= 6; i > 0; i--, SK -= 4) { + *RK++ = *SK++; + *RK++ = *SK++; + } + + SK -= 2; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + +exit: + mbedtls_camellia_free(&cty); + + return ret; +} +#endif /* !MBEDTLS_BLOCK_CIPHER_NO_DECRYPT */ + +/* + * Camellia-ECB block encryption/decryption + */ +int mbedtls_camellia_crypt_ecb(mbedtls_camellia_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16]) +{ + int NR; + uint32_t *RK, X[4]; + if (mode != MBEDTLS_CAMELLIA_ENCRYPT && mode != MBEDTLS_CAMELLIA_DECRYPT) { + return MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA; + } + + ((void) mode); + + NR = ctx->nr; + RK = ctx->rk; + + X[0] = MBEDTLS_GET_UINT32_BE(input, 0); + X[1] = MBEDTLS_GET_UINT32_BE(input, 4); + X[2] = MBEDTLS_GET_UINT32_BE(input, 8); + X[3] = MBEDTLS_GET_UINT32_BE(input, 12); + + X[0] ^= *RK++; + X[1] ^= *RK++; + X[2] ^= *RK++; + X[3] ^= *RK++; + + while (NR) { + --NR; + camellia_feistel(X, RK, X + 2); + RK += 2; + camellia_feistel(X + 2, RK, X); + RK += 2; + camellia_feistel(X, RK, X + 2); + RK += 2; + camellia_feistel(X + 2, RK, X); + RK += 2; + camellia_feistel(X, RK, X + 2); + RK += 2; + camellia_feistel(X + 2, RK, X); + RK += 2; + + if (NR) { + FL(X[0], X[1], RK[0], RK[1]); + RK += 2; + FLInv(X[2], X[3], RK[0], RK[1]); + RK += 2; + } + } + + X[2] ^= *RK++; + X[3] ^= *RK++; + X[0] ^= *RK++; + X[1] ^= *RK++; + + MBEDTLS_PUT_UINT32_BE(X[2], output, 0); + MBEDTLS_PUT_UINT32_BE(X[3], output, 4); + MBEDTLS_PUT_UINT32_BE(X[0], output, 8); + MBEDTLS_PUT_UINT32_BE(X[1], output, 12); + + return 0; +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * Camellia-CBC buffer encryption/decryption + */ +int mbedtls_camellia_crypt_cbc(mbedtls_camellia_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output) +{ + unsigned char temp[16]; + if (mode != MBEDTLS_CAMELLIA_ENCRYPT && mode != MBEDTLS_CAMELLIA_DECRYPT) { + return MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA; + } + + if (length % 16) { + return MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH; + } + + if (mode == MBEDTLS_CAMELLIA_DECRYPT) { + while (length > 0) { + memcpy(temp, input, 16); + mbedtls_camellia_crypt_ecb(ctx, mode, input, output); + + mbedtls_xor(output, output, iv, 16); + + memcpy(iv, temp, 16); + + input += 16; + output += 16; + length -= 16; + } + } else { + while (length > 0) { + mbedtls_xor(output, input, iv, 16); + + mbedtls_camellia_crypt_ecb(ctx, mode, output, output); + memcpy(iv, output, 16); + + input += 16; + output += 16; + length -= 16; + } + } + + return 0; +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * Camellia-CFB128 buffer encryption/decryption + */ +int mbedtls_camellia_crypt_cfb128(mbedtls_camellia_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output) +{ + int c; + size_t n; + if (mode != MBEDTLS_CAMELLIA_ENCRYPT && mode != MBEDTLS_CAMELLIA_DECRYPT) { + return MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA; + } + + n = *iv_off; + if (n >= 16) { + return MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA; + } + + if (mode == MBEDTLS_CAMELLIA_DECRYPT) { + while (length--) { + if (n == 0) { + mbedtls_camellia_crypt_ecb(ctx, MBEDTLS_CAMELLIA_ENCRYPT, iv, iv); + } + + c = *input++; + *output++ = (unsigned char) (c ^ iv[n]); + iv[n] = (unsigned char) c; + + n = (n + 1) & 0x0F; + } + } else { + while (length--) { + if (n == 0) { + mbedtls_camellia_crypt_ecb(ctx, MBEDTLS_CAMELLIA_ENCRYPT, iv, iv); + } + + iv[n] = *output++ = (unsigned char) (iv[n] ^ *input++); + + n = (n + 1) & 0x0F; + } + } + + *iv_off = n; + + return 0; +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * Camellia-CTR buffer encryption/decryption + */ +int mbedtls_camellia_crypt_ctr(mbedtls_camellia_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output) +{ + int c, i; + size_t n; + + n = *nc_off; + if (n >= 16) { + return MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA; + } + + while (length--) { + if (n == 0) { + mbedtls_camellia_crypt_ecb(ctx, MBEDTLS_CAMELLIA_ENCRYPT, nonce_counter, + stream_block); + + for (i = 16; i > 0; i--) { + if (++nonce_counter[i - 1] != 0) { + break; + } + } + } + c = *input++; + *output++ = (unsigned char) (c ^ stream_block[n]); + + n = (n + 1) & 0x0F; + } + + *nc_off = n; + + return 0; +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_SELF_TEST) + +/* + * Camellia test vectors from: + * + * http://info.isl.ntt.co.jp/crypt/eng/camellia/technology.html: + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/cryptrec/intermediate.txt + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/cryptrec/t_camellia.txt + * (For each bitlength: Key 0, Nr 39) + */ +#define CAMELLIA_TESTS_ECB 2 + +static const unsigned char camellia_test_ecb_key[3][CAMELLIA_TESTS_ECB][32] = +{ + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, +}; + +static const unsigned char camellia_test_ecb_plain[CAMELLIA_TESTS_ECB][16] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char camellia_test_ecb_cipher[3][CAMELLIA_TESTS_ECB][16] = +{ + { + { 0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73, + 0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43 }, + { 0x38, 0x3C, 0x6C, 0x2A, 0xAB, 0xEF, 0x7F, 0xDE, + 0x25, 0xCD, 0x47, 0x0B, 0xF7, 0x74, 0xA3, 0x31 } + }, + { + { 0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9, 0x96, 0xf8, + 0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9 }, + { 0xD1, 0x76, 0x3F, 0xC0, 0x19, 0xD7, 0x7C, 0xC9, + 0x30, 0xBF, 0xF2, 0xA5, 0x6F, 0x7C, 0x93, 0x64 } + }, + { + { 0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c, + 0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09 }, + { 0x05, 0x03, 0xFB, 0x10, 0xAB, 0x24, 0x1E, 0x7C, + 0xF4, 0x5D, 0x8C, 0xDE, 0xEE, 0x47, 0x43, 0x35 } + } +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#define CAMELLIA_TESTS_CBC 3 + +static const unsigned char camellia_test_cbc_key[3][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C } + , + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B } + , + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +}; + +static const unsigned char camellia_test_cbc_iv[16] = + +{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F } +; + +static const unsigned char camellia_test_cbc_plain[CAMELLIA_TESTS_CBC][16] = +{ + { 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A }, + { 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51 }, + { 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF } + +}; + +static const unsigned char camellia_test_cbc_cipher[3][CAMELLIA_TESTS_CBC][16] = +{ + { + { 0x16, 0x07, 0xCF, 0x49, 0x4B, 0x36, 0xBB, 0xF0, + 0x0D, 0xAE, 0xB0, 0xB5, 0x03, 0xC8, 0x31, 0xAB }, + { 0xA2, 0xF2, 0xCF, 0x67, 0x16, 0x29, 0xEF, 0x78, + 0x40, 0xC5, 0xA5, 0xDF, 0xB5, 0x07, 0x48, 0x87 }, + { 0x0F, 0x06, 0x16, 0x50, 0x08, 0xCF, 0x8B, 0x8B, + 0x5A, 0x63, 0x58, 0x63, 0x62, 0x54, 0x3E, 0x54 } + }, + { + { 0x2A, 0x48, 0x30, 0xAB, 0x5A, 0xC4, 0xA1, 0xA2, + 0x40, 0x59, 0x55, 0xFD, 0x21, 0x95, 0xCF, 0x93 }, + { 0x5D, 0x5A, 0x86, 0x9B, 0xD1, 0x4C, 0xE5, 0x42, + 0x64, 0xF8, 0x92, 0xA6, 0xDD, 0x2E, 0xC3, 0xD5 }, + { 0x37, 0xD3, 0x59, 0xC3, 0x34, 0x98, 0x36, 0xD8, + 0x84, 0xE3, 0x10, 0xAD, 0xDF, 0x68, 0xC4, 0x49 } + }, + { + { 0xE6, 0xCF, 0xA3, 0x5F, 0xC0, 0x2B, 0x13, 0x4A, + 0x4D, 0x2C, 0x0B, 0x67, 0x37, 0xAC, 0x3E, 0xDA }, + { 0x36, 0xCB, 0xEB, 0x73, 0xBD, 0x50, 0x4B, 0x40, + 0x70, 0xB1, 0xB7, 0xDE, 0x2B, 0x21, 0xEB, 0x50 }, + { 0xE3, 0x1A, 0x60, 0x55, 0x29, 0x7D, 0x96, 0xCA, + 0x33, 0x30, 0xCD, 0xF1, 0xB1, 0x86, 0x0A, 0x83 } + } +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * Camellia-CTR test vectors from: + * + * http://www.faqs.org/rfcs/rfc5528.html + */ + +static const unsigned char camellia_test_ctr_key[3][16] = +{ + { 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC, + 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E }, + { 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7, + 0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63 }, + { 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8, + 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC } +}; + +static const unsigned char camellia_test_ctr_nonce_counter[3][16] = +{ + { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59, + 0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F, + 0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01 } +}; + +static const unsigned char camellia_test_ctr_pt[3][48] = +{ + { 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62, + 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23 } +}; + +static const unsigned char camellia_test_ctr_ct[3][48] = +{ + { 0xD0, 0x9D, 0xC2, 0x9A, 0x82, 0x14, 0x61, 0x9A, + 0x20, 0x87, 0x7C, 0x76, 0xDB, 0x1F, 0x0B, 0x3F }, + { 0xDB, 0xF3, 0xC7, 0x8D, 0xC0, 0x83, 0x96, 0xD4, + 0xDA, 0x7C, 0x90, 0x77, 0x65, 0xBB, 0xCB, 0x44, + 0x2B, 0x8E, 0x8E, 0x0F, 0x31, 0xF0, 0xDC, 0xA7, + 0x2C, 0x74, 0x17, 0xE3, 0x53, 0x60, 0xE0, 0x48 }, + { 0xB1, 0x9D, 0x1F, 0xCD, 0xCB, 0x75, 0xEB, 0x88, + 0x2F, 0x84, 0x9C, 0xE2, 0x4D, 0x85, 0xCF, 0x73, + 0x9C, 0xE6, 0x4B, 0x2B, 0x5C, 0x9D, 0x73, 0xF1, + 0x4F, 0x2D, 0x5D, 0x9D, 0xCE, 0x98, 0x89, 0xCD, + 0xDF, 0x50, 0x86, 0x96 } +}; + +static const int camellia_test_ctr_len[3] = +{ 16, 32, 36 }; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +/* + * Checkup routine + */ +int mbedtls_camellia_self_test(int verbose) +{ + int i, j, u, v; + unsigned char key[32]; + unsigned char buf[64]; + unsigned char src[16]; + unsigned char dst[16]; +#if defined(MBEDTLS_CIPHER_MODE_CBC) + unsigned char iv[16]; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + size_t offset, len; + unsigned char nonce_counter[16]; + unsigned char stream_block[16]; +#endif + int ret = 1; + + mbedtls_camellia_context ctx; + + mbedtls_camellia_init(&ctx); + memset(key, 0, 32); + + for (j = 0; j < 6; j++) { + u = j >> 1; + v = j & 1; + + if (verbose != 0) { + mbedtls_printf(" CAMELLIA-ECB-%3d (%s): ", 128 + u * 64, + (v == MBEDTLS_CAMELLIA_DECRYPT) ? "dec" : "enc"); + } + +#if defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + if (v == MBEDTLS_CAMELLIA_DECRYPT) { + if (verbose != 0) { + mbedtls_printf("skipped\n"); + } + continue; + } +#endif + + for (i = 0; i < CAMELLIA_TESTS_ECB; i++) { + memcpy(key, camellia_test_ecb_key[u][i], 16 + 8 * u); + +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + if (v == MBEDTLS_CAMELLIA_DECRYPT) { + mbedtls_camellia_setkey_dec(&ctx, key, 128 + u * 64); + memcpy(src, camellia_test_ecb_cipher[u][i], 16); + memcpy(dst, camellia_test_ecb_plain[i], 16); + } else +#endif + { /* MBEDTLS_CAMELLIA_ENCRYPT */ + mbedtls_camellia_setkey_enc(&ctx, key, 128 + u * 64); + memcpy(src, camellia_test_ecb_plain[i], 16); + memcpy(dst, camellia_test_ecb_cipher[u][i], 16); + } + + mbedtls_camellia_crypt_ecb(&ctx, v, src, buf); + + if (memcmp(buf, dst, 16) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + goto exit; + } + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /* + * CBC mode + */ + for (j = 0; j < 6; j++) { + u = j >> 1; + v = j & 1; + + if (verbose != 0) { + mbedtls_printf(" CAMELLIA-CBC-%3d (%s): ", 128 + u * 64, + (v == MBEDTLS_CAMELLIA_DECRYPT) ? "dec" : "enc"); + } + + memcpy(src, camellia_test_cbc_iv, 16); + memcpy(dst, camellia_test_cbc_iv, 16); + memcpy(key, camellia_test_cbc_key[u], 16 + 8 * u); + + if (v == MBEDTLS_CAMELLIA_DECRYPT) { + mbedtls_camellia_setkey_dec(&ctx, key, 128 + u * 64); + } else { + mbedtls_camellia_setkey_enc(&ctx, key, 128 + u * 64); + } + + for (i = 0; i < CAMELLIA_TESTS_CBC; i++) { + + if (v == MBEDTLS_CAMELLIA_DECRYPT) { + memcpy(iv, src, 16); + memcpy(src, camellia_test_cbc_cipher[u][i], 16); + memcpy(dst, camellia_test_cbc_plain[i], 16); + } else { /* MBEDTLS_CAMELLIA_ENCRYPT */ + memcpy(iv, dst, 16); + memcpy(src, camellia_test_cbc_plain[i], 16); + memcpy(dst, camellia_test_cbc_cipher[u][i], 16); + } + + mbedtls_camellia_crypt_cbc(&ctx, v, 16, iv, src, buf); + + if (memcmp(buf, dst, 16) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + goto exit; + } + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + if (verbose != 0) { + mbedtls_printf("\n"); + } + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + /* + * CTR mode + */ + for (i = 0; i < 6; i++) { + u = i >> 1; + v = i & 1; + + if (verbose != 0) { + mbedtls_printf(" CAMELLIA-CTR-128 (%s): ", + (v == MBEDTLS_CAMELLIA_DECRYPT) ? "dec" : "enc"); + } + + memcpy(nonce_counter, camellia_test_ctr_nonce_counter[u], 16); + memcpy(key, camellia_test_ctr_key[u], 16); + + offset = 0; + mbedtls_camellia_setkey_enc(&ctx, key, 128); + + if (v == MBEDTLS_CAMELLIA_DECRYPT) { + len = camellia_test_ctr_len[u]; + memcpy(buf, camellia_test_ctr_ct[u], len); + + mbedtls_camellia_crypt_ctr(&ctx, len, &offset, nonce_counter, stream_block, + buf, buf); + + if (memcmp(buf, camellia_test_ctr_pt[u], len) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + goto exit; + } + } else { + len = camellia_test_ctr_len[u]; + memcpy(buf, camellia_test_ctr_pt[u], len); + + mbedtls_camellia_crypt_ctr(&ctx, len, &offset, nonce_counter, stream_block, + buf, buf); + + if (memcmp(buf, camellia_test_ctr_ct[u], len) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + goto exit; + } + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + + ret = 0; + +exit: + mbedtls_camellia_free(&ctx); + return ret; +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CAMELLIA_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/ccm.c b/tf-psa-crypto/drivers/builtin/src/ccm.c new file mode 100644 index 0000000000..742513c68d --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/ccm.c @@ -0,0 +1,773 @@ +/* + * NIST SP800-38C compliant CCM implementation + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +/* + * Definition of CCM: + * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf + * RFC 3610 "Counter with CBC-MAC (CCM)" + * + * Related: + * RFC 5116 "An Interface and Algorithms for Authenticated Encryption" + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_CCM_C) + +#include "mbedtls/private/ccm.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" +#include "mbedtls/constant_time.h" + +#if defined(MBEDTLS_BLOCK_CIPHER_C) +#include "block_cipher_internal.h" +#endif + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ +#endif /* MBEDTLS_PLATFORM_C */ + +/* + * Initialize context + */ +void mbedtls_ccm_init(mbedtls_ccm_context *ctx) +{ + memset(ctx, 0, sizeof(mbedtls_ccm_context)); +} + +int mbedtls_ccm_setkey(mbedtls_ccm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + +#if defined(MBEDTLS_BLOCK_CIPHER_C) + mbedtls_block_cipher_free(&ctx->block_cipher_ctx); + + if ((ret = mbedtls_block_cipher_setup(&ctx->block_cipher_ctx, cipher)) != 0) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + if ((ret = mbedtls_block_cipher_setkey(&ctx->block_cipher_ctx, key, keybits)) != 0) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } +#else + const mbedtls_cipher_info_t *cipher_info; + + cipher_info = mbedtls_cipher_info_from_values(cipher, keybits, + MBEDTLS_MODE_ECB); + if (cipher_info == NULL) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + if (mbedtls_cipher_info_get_block_size(cipher_info) != 16) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + mbedtls_cipher_free(&ctx->cipher_ctx); + + if ((ret = mbedtls_cipher_setup(&ctx->cipher_ctx, cipher_info)) != 0) { + return ret; + } + + if ((ret = mbedtls_cipher_setkey(&ctx->cipher_ctx, key, keybits, + MBEDTLS_ENCRYPT)) != 0) { + return ret; + } +#endif + + return ret; +} + +/* + * Free context + */ +void mbedtls_ccm_free(mbedtls_ccm_context *ctx) +{ + if (ctx == NULL) { + return; + } +#if defined(MBEDTLS_BLOCK_CIPHER_C) + mbedtls_block_cipher_free(&ctx->block_cipher_ctx); +#else + mbedtls_cipher_free(&ctx->cipher_ctx); +#endif + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ccm_context)); +} + +#define CCM_STATE__CLEAR 0 +#define CCM_STATE__STARTED (1 << 0) +#define CCM_STATE__LENGTHS_SET (1 << 1) +#define CCM_STATE__AUTH_DATA_STARTED (1 << 2) +#define CCM_STATE__AUTH_DATA_FINISHED (1 << 3) +#define CCM_STATE__ERROR (1 << 4) + +/* + * Encrypt or decrypt a partial block with CTR + */ +static int mbedtls_ccm_crypt(mbedtls_ccm_context *ctx, + size_t offset, size_t use_len, + const unsigned char *input, + unsigned char *output) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char tmp_buf[16] = { 0 }; + +#if defined(MBEDTLS_BLOCK_CIPHER_C) + ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->ctr, tmp_buf); +#else + size_t olen = 0; + ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->ctr, 16, tmp_buf, &olen); +#endif + if (ret != 0) { + ctx->state |= CCM_STATE__ERROR; + mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf)); + return ret; + } + + mbedtls_xor(output, input, tmp_buf + offset, use_len); + + mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf)); + return ret; +} + +static void mbedtls_ccm_clear_state(mbedtls_ccm_context *ctx) +{ + ctx->state = CCM_STATE__CLEAR; + memset(ctx->y, 0, 16); + memset(ctx->ctr, 0, 16); +} + +static int ccm_calculate_first_block_if_ready(mbedtls_ccm_context *ctx) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char i; + size_t len_left; +#if !defined(MBEDTLS_BLOCK_CIPHER_C) + size_t olen; +#endif + + /* length calculation can be done only after both + * mbedtls_ccm_starts() and mbedtls_ccm_set_lengths() have been executed + */ + if (!(ctx->state & CCM_STATE__STARTED) || !(ctx->state & CCM_STATE__LENGTHS_SET)) { + return 0; + } + + /* CCM expects non-empty tag. + * CCM* allows empty tag. For CCM* without tag, the tag calculation is skipped. + */ + if (ctx->tag_len == 0) { + if (ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT || ctx->mode == MBEDTLS_CCM_STAR_DECRYPT) { + ctx->plaintext_len = 0; + return 0; + } else { + ctx->state |= CCM_STATE__ERROR; + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + } + + /* + * First block: + * 0 .. 0 flags + * 1 .. iv_len nonce (aka iv) - set by: mbedtls_ccm_starts() + * iv_len+1 .. 15 length + * + * With flags as (bits): + * 7 0 + * 6 add present? + * 5 .. 3 (t - 2) / 2 + * 2 .. 0 q - 1 + */ + ctx->y[0] |= (ctx->add_len > 0) << 6; + ctx->y[0] |= ((ctx->tag_len - 2) / 2) << 3; + ctx->y[0] |= ctx->q - 1; + + for (i = 0, len_left = ctx->plaintext_len; i < ctx->q; i++, len_left >>= 8) { + ctx->y[15-i] = MBEDTLS_BYTE_0(len_left); + } + + if (len_left > 0) { + ctx->state |= CCM_STATE__ERROR; + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + /* Start CBC-MAC with first block*/ +#if defined(MBEDTLS_BLOCK_CIPHER_C) + ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y); +#else + ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen); +#endif + if (ret != 0) { + ctx->state |= CCM_STATE__ERROR; + return ret; + } + + return 0; +} + +int mbedtls_ccm_starts(mbedtls_ccm_context *ctx, + int mode, + const unsigned char *iv, + size_t iv_len) +{ + /* Also implies q is within bounds */ + if (iv_len < 7 || iv_len > 13) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + ctx->mode = mode; + ctx->q = 16 - 1 - (unsigned char) iv_len; + + /* + * Prepare counter block for encryption: + * 0 .. 0 flags + * 1 .. iv_len nonce (aka iv) + * iv_len+1 .. 15 counter (initially 1) + * + * With flags as (bits): + * 7 .. 3 0 + * 2 .. 0 q - 1 + */ + memset(ctx->ctr, 0, 16); + ctx->ctr[0] = ctx->q - 1; + memcpy(ctx->ctr + 1, iv, iv_len); + memset(ctx->ctr + 1 + iv_len, 0, ctx->q); + ctx->ctr[15] = 1; + + /* + * See ccm_calculate_first_block_if_ready() for block layout description + */ + memcpy(ctx->y + 1, iv, iv_len); + + ctx->state |= CCM_STATE__STARTED; + return ccm_calculate_first_block_if_ready(ctx); +} + +int mbedtls_ccm_set_lengths(mbedtls_ccm_context *ctx, + size_t total_ad_len, + size_t plaintext_len, + size_t tag_len) +{ + /* + * Check length requirements: SP800-38C A.1 + * Additional requirement: a < 2^16 - 2^8 to simplify the code. + * 'length' checked later (when writing it to the first block) + * + * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4). + */ + if (tag_len == 2 || tag_len > 16 || tag_len % 2 != 0) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + if (total_ad_len >= 0xFF00) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + ctx->plaintext_len = plaintext_len; + ctx->add_len = total_ad_len; + ctx->tag_len = tag_len; + ctx->processed = 0; + + ctx->state |= CCM_STATE__LENGTHS_SET; + return ccm_calculate_first_block_if_ready(ctx); +} + +int mbedtls_ccm_update_ad(mbedtls_ccm_context *ctx, + const unsigned char *add, + size_t add_len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t use_len, offset; +#if !defined(MBEDTLS_BLOCK_CIPHER_C) + size_t olen; +#endif + + if (ctx->state & CCM_STATE__ERROR) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + if (add_len > 0) { + if (ctx->state & CCM_STATE__AUTH_DATA_FINISHED) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + if (!(ctx->state & CCM_STATE__AUTH_DATA_STARTED)) { + if (add_len > ctx->add_len) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + ctx->y[0] ^= (unsigned char) ((ctx->add_len >> 8) & 0xFF); + ctx->y[1] ^= (unsigned char) ((ctx->add_len) & 0xFF); + + ctx->state |= CCM_STATE__AUTH_DATA_STARTED; + } else if (ctx->processed + add_len > ctx->add_len) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + while (add_len > 0) { + offset = (ctx->processed + 2) % 16; /* account for y[0] and y[1] + * holding total auth data length */ + use_len = 16 - offset; + + if (use_len > add_len) { + use_len = add_len; + } + + mbedtls_xor(ctx->y + offset, ctx->y + offset, add, use_len); + + ctx->processed += use_len; + add_len -= use_len; + add += use_len; + + if (use_len + offset == 16 || ctx->processed == ctx->add_len) { +#if defined(MBEDTLS_BLOCK_CIPHER_C) + ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y); +#else + ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen); +#endif + if (ret != 0) { + ctx->state |= CCM_STATE__ERROR; + return ret; + } + } + } + + if (ctx->processed == ctx->add_len) { + ctx->state |= CCM_STATE__AUTH_DATA_FINISHED; + ctx->processed = 0; // prepare for mbedtls_ccm_update() + } + } + + return 0; +} + +int mbedtls_ccm_update(mbedtls_ccm_context *ctx, + const unsigned char *input, size_t input_len, + unsigned char *output, size_t output_size, + size_t *output_len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char i; + size_t use_len, offset; +#if !defined(MBEDTLS_BLOCK_CIPHER_C) + size_t olen; +#endif + + unsigned char local_output[16]; + + if (ctx->state & CCM_STATE__ERROR) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + /* Check against plaintext length only if performing operation with + * authentication + */ + if (ctx->tag_len != 0 && ctx->processed + input_len > ctx->plaintext_len) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + if (output_size < input_len) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + *output_len = input_len; + + ret = 0; + + while (input_len > 0) { + offset = ctx->processed % 16; + + use_len = 16 - offset; + + if (use_len > input_len) { + use_len = input_len; + } + + ctx->processed += use_len; + + if (ctx->mode == MBEDTLS_CCM_ENCRYPT || \ + ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT) { + mbedtls_xor(ctx->y + offset, ctx->y + offset, input, use_len); + + if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) { +#if defined(MBEDTLS_BLOCK_CIPHER_C) + ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y); +#else + ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen); +#endif + if (ret != 0) { + ctx->state |= CCM_STATE__ERROR; + goto exit; + } + } + + ret = mbedtls_ccm_crypt(ctx, offset, use_len, input, output); + if (ret != 0) { + goto exit; + } + } + + if (ctx->mode == MBEDTLS_CCM_DECRYPT || \ + ctx->mode == MBEDTLS_CCM_STAR_DECRYPT) { + /* Since output may be in shared memory, we cannot be sure that + * it will contain what we wrote to it. Therefore, we should avoid using + * it as input to any operations. + * Write decrypted data to local_output to avoid using output variable as + * input in the XOR operation for Y. + */ + ret = mbedtls_ccm_crypt(ctx, offset, use_len, input, local_output); + if (ret != 0) { + goto exit; + } + + mbedtls_xor(ctx->y + offset, ctx->y + offset, local_output, use_len); + + memcpy(output, local_output, use_len); + + if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) { +#if defined(MBEDTLS_BLOCK_CIPHER_C) + ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y); +#else + ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen); +#endif + if (ret != 0) { + ctx->state |= CCM_STATE__ERROR; + goto exit; + } + } + } + + if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) { + for (i = 0; i < ctx->q; i++) { + if (++(ctx->ctr)[15-i] != 0) { + break; + } + } + } + + input_len -= use_len; + input += use_len; + output += use_len; + } + +exit: + mbedtls_platform_zeroize(local_output, 16); + + return ret; +} + +int mbedtls_ccm_finish(mbedtls_ccm_context *ctx, + unsigned char *tag, size_t tag_len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char i; + + if (ctx->state & CCM_STATE__ERROR) { + return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + } + + if (!(ctx->state & CCM_STATE__STARTED)) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + if (!(ctx->state & CCM_STATE__LENGTHS_SET)) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + if (ctx->add_len > 0 && !(ctx->state & CCM_STATE__AUTH_DATA_FINISHED)) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + if (ctx->plaintext_len > 0 && ctx->processed != ctx->plaintext_len) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + if (tag_len != ctx->tag_len) { + return MBEDTLS_ERR_CCM_BAD_INPUT; + } + + /* + * Authentication: reset counter and crypt/mask internal tag + */ + for (i = 0; i < ctx->q; i++) { + ctx->ctr[15-i] = 0; + } + + ret = mbedtls_ccm_crypt(ctx, 0, 16, ctx->y, ctx->y); + if (ret != 0) { + return ret; + } + if (tag != NULL) { + memcpy(tag, ctx->y, tag_len); + } + mbedtls_ccm_clear_state(ctx); + + return 0; +} + +/* + * Authenticated encryption or decryption + */ +static int ccm_auth_crypt(mbedtls_ccm_context *ctx, int mode, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t olen; + + if ((ret = mbedtls_ccm_starts(ctx, mode, iv, iv_len)) != 0) { + return ret; + } + + if ((ret = mbedtls_ccm_set_lengths(ctx, add_len, length, tag_len)) != 0) { + return ret; + } + + if ((ret = mbedtls_ccm_update_ad(ctx, add, add_len)) != 0) { + return ret; + } + + if ((ret = mbedtls_ccm_update(ctx, input, length, + output, length, &olen)) != 0) { + return ret; + } + + if ((ret = mbedtls_ccm_finish(ctx, tag, tag_len)) != 0) { + return ret; + } + + return 0; +} + +/* + * Authenticated encryption + */ +int mbedtls_ccm_star_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len) +{ + return ccm_auth_crypt(ctx, MBEDTLS_CCM_STAR_ENCRYPT, length, iv, iv_len, + add, add_len, input, output, tag, tag_len); +} + +int mbedtls_ccm_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len) +{ + return ccm_auth_crypt(ctx, MBEDTLS_CCM_ENCRYPT, length, iv, iv_len, + add, add_len, input, output, tag, tag_len); +} + +/* + * Authenticated decryption + */ +static int mbedtls_ccm_compare_tags(const unsigned char *tag1, + const unsigned char *tag2, + size_t tag_len) +{ + /* Check tag in "constant-time" */ + int diff = mbedtls_ct_memcmp(tag1, tag2, tag_len); + + if (diff != 0) { + return MBEDTLS_ERR_CCM_AUTH_FAILED; + } + + return 0; +} + +static int ccm_auth_decrypt(mbedtls_ccm_context *ctx, int mode, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + const unsigned char *tag, size_t tag_len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char check_tag[16]; + + if ((ret = ccm_auth_crypt(ctx, mode, length, + iv, iv_len, add, add_len, + input, output, check_tag, tag_len)) != 0) { + return ret; + } + + if ((ret = mbedtls_ccm_compare_tags(tag, check_tag, tag_len)) != 0) { + mbedtls_platform_zeroize(output, length); + return ret; + } + + return 0; +} + +int mbedtls_ccm_star_auth_decrypt(mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + const unsigned char *tag, size_t tag_len) +{ + return ccm_auth_decrypt(ctx, MBEDTLS_CCM_STAR_DECRYPT, length, + iv, iv_len, add, add_len, + input, output, tag, tag_len); +} + +int mbedtls_ccm_auth_decrypt(mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + const unsigned char *tag, size_t tag_len) +{ + return ccm_auth_decrypt(ctx, MBEDTLS_CCM_DECRYPT, length, + iv, iv_len, add, add_len, + input, output, tag, tag_len); +} + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_CCM_GCM_CAN_AES) +/* + * Examples 1 to 3 from SP800-38C Appendix C + */ + +#define NB_TESTS 3 +#define CCM_SELFTEST_PT_MAX_LEN 24 +#define CCM_SELFTEST_CT_MAX_LEN 32 +/* + * The data is the same for all tests, only the used length changes + */ +static const unsigned char key_test_data[] = { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f +}; + +static const unsigned char iv_test_data[] = { + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b +}; + +static const unsigned char ad_test_data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13 +}; + +static const unsigned char msg_test_data[CCM_SELFTEST_PT_MAX_LEN] = { + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, +}; + +static const size_t iv_len_test_data[NB_TESTS] = { 7, 8, 12 }; +static const size_t add_len_test_data[NB_TESTS] = { 8, 16, 20 }; +static const size_t msg_len_test_data[NB_TESTS] = { 4, 16, 24 }; +static const size_t tag_len_test_data[NB_TESTS] = { 4, 6, 8 }; + +static const unsigned char res_test_data[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = { + { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d }, + { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62, + 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d, + 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd }, + { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a, + 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b, + 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5, + 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 } +}; + +int mbedtls_ccm_self_test(int verbose) +{ + mbedtls_ccm_context ctx; + /* + * Some hardware accelerators require the input and output buffers + * would be in RAM, because the flash is not accessible. + * Use buffers on the stack to hold the test vectors data. + */ + unsigned char plaintext[CCM_SELFTEST_PT_MAX_LEN]; + unsigned char ciphertext[CCM_SELFTEST_CT_MAX_LEN]; + size_t i; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + mbedtls_ccm_init(&ctx); + + if (mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key_test_data, + 8 * sizeof(key_test_data)) != 0) { + if (verbose != 0) { + mbedtls_printf(" CCM: setup failed"); + } + + return 1; + } + + for (i = 0; i < NB_TESTS; i++) { + if (verbose != 0) { + mbedtls_printf(" CCM-AES #%u: ", (unsigned int) i + 1); + } + + memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN); + memset(ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN); + memcpy(plaintext, msg_test_data, msg_len_test_data[i]); + + ret = mbedtls_ccm_encrypt_and_tag(&ctx, msg_len_test_data[i], + iv_test_data, iv_len_test_data[i], + ad_test_data, add_len_test_data[i], + plaintext, ciphertext, + ciphertext + msg_len_test_data[i], + tag_len_test_data[i]); + + if (ret != 0 || + memcmp(ciphertext, res_test_data[i], + msg_len_test_data[i] + tag_len_test_data[i]) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + return 1; + } + memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN); + + ret = mbedtls_ccm_auth_decrypt(&ctx, msg_len_test_data[i], + iv_test_data, iv_len_test_data[i], + ad_test_data, add_len_test_data[i], + ciphertext, plaintext, + ciphertext + msg_len_test_data[i], + tag_len_test_data[i]); + + if (ret != 0 || + memcmp(plaintext, msg_test_data, msg_len_test_data[i]) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + return 1; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + + mbedtls_ccm_free(&ctx); + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + return 0; +} + +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#endif /* MBEDTLS_CCM_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/chacha20.c b/tf-psa-crypto/drivers/builtin/src/chacha20.c new file mode 100644 index 0000000000..19b1ad882b --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/chacha20.c @@ -0,0 +1,514 @@ +/** + * \file chacha20.c + * + * \brief ChaCha20 cipher. + * + * \author Daniel King + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_CHACHA20_C) + +#include "chacha20_neon.h" + +#include "mbedtls/private/chacha20.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#include +#include + +#include "mbedtls/platform.h" + +#define CHACHA20_CTR_INDEX (12U) + +#if MBEDTLS_CHACHA20_NEON_MULTIBLOCK == 0 + +#define ROTL32(value, amount) \ + ((uint32_t) ((value) << (amount)) | ((value) >> (32 - (amount)))) + +/** + * \brief ChaCha20 quarter round operation. + * + * The quarter round is defined as follows (from RFC 7539): + * 1. a += b; d ^= a; d <<<= 16; + * 2. c += d; b ^= c; b <<<= 12; + * 3. a += b; d ^= a; d <<<= 8; + * 4. c += d; b ^= c; b <<<= 7; + * + * \param state ChaCha20 state to modify. + * \param a The index of 'a' in the state. + * \param b The index of 'b' in the state. + * \param c The index of 'c' in the state. + * \param d The index of 'd' in the state. + */ +static inline void chacha20_quarter_round(uint32_t state[16], + size_t a, + size_t b, + size_t c, + size_t d) +{ + /* a += b; d ^= a; d <<<= 16; */ + state[a] += state[b]; + state[d] ^= state[a]; + state[d] = ROTL32(state[d], 16); + + /* c += d; b ^= c; b <<<= 12 */ + state[c] += state[d]; + state[b] ^= state[c]; + state[b] = ROTL32(state[b], 12); + + /* a += b; d ^= a; d <<<= 8; */ + state[a] += state[b]; + state[d] ^= state[a]; + state[d] = ROTL32(state[d], 8); + + /* c += d; b ^= c; b <<<= 7; */ + state[c] += state[d]; + state[b] ^= state[c]; + state[b] = ROTL32(state[b], 7); +} + +/** + * \brief Perform the ChaCha20 inner block operation. + * + * This function performs two rounds: the column round and the + * diagonal round. + * + * \param state The ChaCha20 state to update. + */ +static void chacha20_inner_block(uint32_t state[16]) +{ + chacha20_quarter_round(state, 0, 4, 8, 12); + chacha20_quarter_round(state, 1, 5, 9, 13); + chacha20_quarter_round(state, 2, 6, 10, 14); + chacha20_quarter_round(state, 3, 7, 11, 15); + + chacha20_quarter_round(state, 0, 5, 10, 15); + chacha20_quarter_round(state, 1, 6, 11, 12); + chacha20_quarter_round(state, 2, 7, 8, 13); + chacha20_quarter_round(state, 3, 4, 9, 14); +} + +/** + * \brief Generates a keystream block. + * + * \param initial_state The initial ChaCha20 state (key, nonce, counter). + * \param keystream Generated keystream bytes are written to this buffer. + */ +static void chacha20_block(const uint32_t initial_state[16], + unsigned char keystream[64]) +{ + uint32_t working_state[16]; + size_t i; + + memcpy(working_state, + initial_state, + MBEDTLS_CHACHA20_BLOCK_SIZE_BYTES); + + for (i = 0U; i < 10U; i++) { + chacha20_inner_block(working_state); + } + + working_state[0] += initial_state[0]; + working_state[1] += initial_state[1]; + working_state[2] += initial_state[2]; + working_state[3] += initial_state[3]; + working_state[4] += initial_state[4]; + working_state[5] += initial_state[5]; + working_state[6] += initial_state[6]; + working_state[7] += initial_state[7]; + working_state[8] += initial_state[8]; + working_state[9] += initial_state[9]; + working_state[10] += initial_state[10]; + working_state[11] += initial_state[11]; + working_state[12] += initial_state[12]; + working_state[13] += initial_state[13]; + working_state[14] += initial_state[14]; + working_state[15] += initial_state[15]; + + for (i = 0U; i < 16; i++) { + size_t offset = i * 4U; + + MBEDTLS_PUT_UINT32_LE(working_state[i], keystream, offset); + } + + mbedtls_platform_zeroize(working_state, sizeof(working_state)); +} + +#endif /* MBEDTLS_CHACHA20_NEON_MULTIBLOCK == 0 */ + +void mbedtls_chacha20_init(mbedtls_chacha20_context *ctx) +{ + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_chacha20_context)); + + /* Initially, there's no keystream bytes available */ + ctx->keystream_bytes_used = MBEDTLS_CHACHA20_BLOCK_SIZE_BYTES; +} + +void mbedtls_chacha20_free(mbedtls_chacha20_context *ctx) +{ + if (ctx != NULL) { + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_chacha20_context)); + } +} + +int mbedtls_chacha20_setkey(mbedtls_chacha20_context *ctx, + const unsigned char key[32]) +{ + /* ChaCha20 constants - the string "expand 32-byte k" */ + static const char EXPAND_32_BYTE_K[16] + MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING = "expand 32-byte k"; + if (MBEDTLS_IS_BIG_ENDIAN) { + ctx->state[0] = MBEDTLS_GET_UINT32_LE(EXPAND_32_BYTE_K, 0); + ctx->state[1] = MBEDTLS_GET_UINT32_LE(EXPAND_32_BYTE_K, 4); + ctx->state[2] = MBEDTLS_GET_UINT32_LE(EXPAND_32_BYTE_K, 8); + ctx->state[3] = MBEDTLS_GET_UINT32_LE(EXPAND_32_BYTE_K, 12); + } else { + memcpy(ctx->state, EXPAND_32_BYTE_K, 16); + } + + /* Set key */ + if (MBEDTLS_IS_BIG_ENDIAN) { + ctx->state[4] = MBEDTLS_GET_UINT32_LE(key, 0); + ctx->state[5] = MBEDTLS_GET_UINT32_LE(key, 4); + ctx->state[6] = MBEDTLS_GET_UINT32_LE(key, 8); + ctx->state[7] = MBEDTLS_GET_UINT32_LE(key, 12); + ctx->state[8] = MBEDTLS_GET_UINT32_LE(key, 16); + ctx->state[9] = MBEDTLS_GET_UINT32_LE(key, 20); + ctx->state[10] = MBEDTLS_GET_UINT32_LE(key, 24); + ctx->state[11] = MBEDTLS_GET_UINT32_LE(key, 28); + } else { + memcpy(&ctx->state[4], key, 32); + } + + return 0; +} + +int mbedtls_chacha20_starts(mbedtls_chacha20_context *ctx, + const unsigned char nonce[12], + uint32_t counter) +{ + /* Counter */ + ctx->state[12] = counter; + + /* Nonce */ + if (MBEDTLS_IS_BIG_ENDIAN) { + ctx->state[13] = MBEDTLS_GET_UINT32_LE(nonce, 0); + ctx->state[14] = MBEDTLS_GET_UINT32_LE(nonce, 4); + ctx->state[15] = MBEDTLS_GET_UINT32_LE(nonce, 8); + } else { + memcpy(&ctx->state[13], nonce, 12); + } + + mbedtls_platform_zeroize(ctx->keystream8, sizeof(ctx->keystream8)); + + /* Initially, there's no keystream bytes available */ + ctx->keystream_bytes_used = MBEDTLS_CHACHA20_BLOCK_SIZE_BYTES; + + return 0; +} + +#if MBEDTLS_CHACHA20_NEON_MULTIBLOCK == 0 + +int mbedtls_chacha20_update(mbedtls_chacha20_context *ctx, + size_t size, + const unsigned char *input, + unsigned char *output) +{ + size_t offset = 0U; + + /* Use leftover keystream bytes, if available */ + while (ctx->keystream_bytes_used < MBEDTLS_CHACHA20_BLOCK_SIZE_BYTES && size > 0) { + output[offset] = input[offset] + ^ ctx->keystream8[ctx->keystream_bytes_used]; + + ctx->keystream_bytes_used++; + offset++; + size--; + } + + /* Process full blocks */ + while (size >= MBEDTLS_CHACHA20_BLOCK_SIZE_BYTES) { + /* Generate new keystream block and increment counter */ + chacha20_block(ctx->state, ctx->keystream8); + ctx->state[CHACHA20_CTR_INDEX]++; + + mbedtls_xor(output + offset, input + offset, ctx->keystream8, 64U); + + offset += MBEDTLS_CHACHA20_BLOCK_SIZE_BYTES; + size -= MBEDTLS_CHACHA20_BLOCK_SIZE_BYTES; + } + + /* Last (partial) block */ + if (size > 0U) { + /* Generate new keystream block and increment counter */ + chacha20_block(ctx->state, ctx->keystream8); + ctx->state[CHACHA20_CTR_INDEX]++; + + mbedtls_xor(output + offset, input + offset, ctx->keystream8, size); + + ctx->keystream_bytes_used = size; + + } + + return 0; +} + +#endif /* MBEDTLS_CHACHA20_NEON_MULTIBLOCK == 0 */ + +int mbedtls_chacha20_crypt(const unsigned char key[32], + const unsigned char nonce[12], + uint32_t counter, + size_t data_len, + const unsigned char *input, + unsigned char *output) +{ + mbedtls_chacha20_context ctx; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + mbedtls_chacha20_init(&ctx); + + ret = mbedtls_chacha20_setkey(&ctx, key); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_chacha20_starts(&ctx, nonce, counter); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_chacha20_update(&ctx, data_len, input, output); + +cleanup: + mbedtls_chacha20_free(&ctx); + return ret; +} + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char test_keys[2][32] = +{ + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + } +}; + +static const unsigned char test_nonces[2][12] = +{ + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02 + } +}; + +static const uint32_t test_counters[2] = +{ + 0U, + 1U +}; + +static const unsigned char test_input[2][375] = +{ + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + { + 0x41, 0x6e, 0x79, 0x20, 0x73, 0x75, 0x62, 0x6d, + 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, + 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45, + 0x54, 0x46, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, + 0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x20, 0x66, + 0x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, + 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x72, + 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, + 0x20, 0x61, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46, + 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, + 0x74, 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x20, + 0x6f, 0x72, 0x20, 0x52, 0x46, 0x43, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49, + 0x45, 0x54, 0x46, 0x20, 0x61, 0x63, 0x74, 0x69, + 0x76, 0x69, 0x74, 0x79, 0x20, 0x69, 0x73, 0x20, + 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72, + 0x65, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x22, 0x49, + 0x45, 0x54, 0x46, 0x20, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x2e, 0x20, 0x53, 0x75, 0x63, 0x68, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x20, 0x6f, 0x72, 0x61, 0x6c, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45, + 0x54, 0x46, 0x20, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20, + 0x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, 0x73, 0x20, + 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x20, 0x63, + 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x61, + 0x64, 0x65, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6e, + 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x6f, + 0x72, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x2c, + 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61, + 0x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f + } +}; + +static const unsigned char test_output[2][375] = +{ + { + 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, + 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28, + 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, + 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7, + 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d, + 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37, + 0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c, + 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86 + }, + { + 0xa3, 0xfb, 0xf0, 0x7d, 0xf3, 0xfa, 0x2f, 0xde, + 0x4f, 0x37, 0x6c, 0xa2, 0x3e, 0x82, 0x73, 0x70, + 0x41, 0x60, 0x5d, 0x9f, 0x4f, 0x4f, 0x57, 0xbd, + 0x8c, 0xff, 0x2c, 0x1d, 0x4b, 0x79, 0x55, 0xec, + 0x2a, 0x97, 0x94, 0x8b, 0xd3, 0x72, 0x29, 0x15, + 0xc8, 0xf3, 0xd3, 0x37, 0xf7, 0xd3, 0x70, 0x05, + 0x0e, 0x9e, 0x96, 0xd6, 0x47, 0xb7, 0xc3, 0x9f, + 0x56, 0xe0, 0x31, 0xca, 0x5e, 0xb6, 0x25, 0x0d, + 0x40, 0x42, 0xe0, 0x27, 0x85, 0xec, 0xec, 0xfa, + 0x4b, 0x4b, 0xb5, 0xe8, 0xea, 0xd0, 0x44, 0x0e, + 0x20, 0xb6, 0xe8, 0xdb, 0x09, 0xd8, 0x81, 0xa7, + 0xc6, 0x13, 0x2f, 0x42, 0x0e, 0x52, 0x79, 0x50, + 0x42, 0xbd, 0xfa, 0x77, 0x73, 0xd8, 0xa9, 0x05, + 0x14, 0x47, 0xb3, 0x29, 0x1c, 0xe1, 0x41, 0x1c, + 0x68, 0x04, 0x65, 0x55, 0x2a, 0xa6, 0xc4, 0x05, + 0xb7, 0x76, 0x4d, 0x5e, 0x87, 0xbe, 0xa8, 0x5a, + 0xd0, 0x0f, 0x84, 0x49, 0xed, 0x8f, 0x72, 0xd0, + 0xd6, 0x62, 0xab, 0x05, 0x26, 0x91, 0xca, 0x66, + 0x42, 0x4b, 0xc8, 0x6d, 0x2d, 0xf8, 0x0e, 0xa4, + 0x1f, 0x43, 0xab, 0xf9, 0x37, 0xd3, 0x25, 0x9d, + 0xc4, 0xb2, 0xd0, 0xdf, 0xb4, 0x8a, 0x6c, 0x91, + 0x39, 0xdd, 0xd7, 0xf7, 0x69, 0x66, 0xe9, 0x28, + 0xe6, 0x35, 0x55, 0x3b, 0xa7, 0x6c, 0x5c, 0x87, + 0x9d, 0x7b, 0x35, 0xd4, 0x9e, 0xb2, 0xe6, 0x2b, + 0x08, 0x71, 0xcd, 0xac, 0x63, 0x89, 0x39, 0xe2, + 0x5e, 0x8a, 0x1e, 0x0e, 0xf9, 0xd5, 0x28, 0x0f, + 0xa8, 0xca, 0x32, 0x8b, 0x35, 0x1c, 0x3c, 0x76, + 0x59, 0x89, 0xcb, 0xcf, 0x3d, 0xaa, 0x8b, 0x6c, + 0xcc, 0x3a, 0xaf, 0x9f, 0x39, 0x79, 0xc9, 0x2b, + 0x37, 0x20, 0xfc, 0x88, 0xdc, 0x95, 0xed, 0x84, + 0xa1, 0xbe, 0x05, 0x9c, 0x64, 0x99, 0xb9, 0xfd, + 0xa2, 0x36, 0xe7, 0xe8, 0x18, 0xb0, 0x4b, 0x0b, + 0xc3, 0x9c, 0x1e, 0x87, 0x6b, 0x19, 0x3b, 0xfe, + 0x55, 0x69, 0x75, 0x3f, 0x88, 0x12, 0x8c, 0xc0, + 0x8a, 0xaa, 0x9b, 0x63, 0xd1, 0xa1, 0x6f, 0x80, + 0xef, 0x25, 0x54, 0xd7, 0x18, 0x9c, 0x41, 0x1f, + 0x58, 0x69, 0xca, 0x52, 0xc5, 0xb8, 0x3f, 0xa3, + 0x6f, 0xf2, 0x16, 0xb9, 0xc1, 0xd3, 0x00, 0x62, + 0xbe, 0xbc, 0xfd, 0x2d, 0xc5, 0xbc, 0xe0, 0x91, + 0x19, 0x34, 0xfd, 0xa7, 0x9a, 0x86, 0xf6, 0xe6, + 0x98, 0xce, 0xd7, 0x59, 0xc3, 0xff, 0x9b, 0x64, + 0x77, 0x33, 0x8f, 0x3d, 0xa4, 0xf9, 0xcd, 0x85, + 0x14, 0xea, 0x99, 0x82, 0xcc, 0xaf, 0xb3, 0x41, + 0xb2, 0x38, 0x4d, 0xd9, 0x02, 0xf3, 0xd1, 0xab, + 0x7a, 0xc6, 0x1d, 0xd2, 0x9c, 0x6f, 0x21, 0xba, + 0x5b, 0x86, 0x2f, 0x37, 0x30, 0xe3, 0x7c, 0xfd, + 0xc4, 0xfd, 0x80, 0x6c, 0x22, 0xf2, 0x21 + } +}; + +static const size_t test_lengths[2] = +{ + 64U, + 375U +}; + +/* Make sure no other definition is already present. */ +#undef ASSERT + +#define ASSERT(cond, args) \ + do \ + { \ + if (!(cond)) \ + { \ + if (verbose != 0) \ + mbedtls_printf args; \ + \ + return -1; \ + } \ + } \ + while (0) + +int mbedtls_chacha20_self_test(int verbose) +{ + unsigned char output[381]; + unsigned i; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + for (i = 0U; i < 2U; i++) { + if (verbose != 0) { + mbedtls_printf(" ChaCha20 test %u ", i); + } + + ret = mbedtls_chacha20_crypt(test_keys[i], + test_nonces[i], + test_counters[i], + test_lengths[i], + test_input[i], + output); + + ASSERT(0 == ret, ("error code: %i\n", ret)); + + ASSERT(0 == memcmp(output, test_output[i], test_lengths[i]), + ("failed (output)\n")); + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + return 0; +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* !MBEDTLS_CHACHA20_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/chacha20_neon.c b/tf-psa-crypto/drivers/builtin/src/chacha20_neon.c new file mode 100644 index 0000000000..76c9ba4103 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/chacha20_neon.c @@ -0,0 +1,259 @@ +/** + * \file chacha20_neon.c + * + * \brief Neon implementation of ChaCha20 + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" +#include "chacha20_neon.h" + +#if defined(MBEDTLS_CHACHA20_C) && (MBEDTLS_CHACHA20_NEON_MULTIBLOCK != 0) + +#include "mbedtls/private/chacha20.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#include +#include + +#include "mbedtls/platform.h" + +// Tested on all combinations of Armv7 arm/thumb2; Armv8 arm/thumb2/aarch64; Armv8 aarch64_be on +// clang 14, gcc 11, and some more recent versions. + +typedef struct { + uint32x4_t a, b, c, d; +} chacha20_neon_regs_t; + +// Define rotate-left operations that rotate within each 32-bit element in a 128-bit vector. +static inline uint32x4_t chacha20_neon_vrotlq_16_u32(uint32x4_t v) +{ + return vreinterpretq_u32_u16(vrev32q_u16(vreinterpretq_u16_u32(v))); +} + +static inline uint32x4_t chacha20_neon_vrotlq_12_u32(uint32x4_t v) +{ + uint32x4_t x = vshlq_n_u32(v, 12); + return vsriq_n_u32(x, v, 20); +} + +static inline uint32x4_t chacha20_neon_vrotlq_8_u32(uint32x4_t v) +{ + uint32x4_t result; +#if defined(MBEDTLS_ARCH_IS_ARM64) + // This implementation is slightly faster, but only supported on 64-bit Arm + // Table look-up which results in an 8-bit rotate-left within each 32-bit element + const uint8_t idx_rotl8[16] = { 3, 0, 1, 2, 7, 4, 5, 6, 11, 8, 9, 10, 15, 12, 13, 14 }; + const uint8x16_t vrotl8_tbl = vld1q_u8(idx_rotl8); + result = vreinterpretq_u32_u8(vqtbl1q_u8(vreinterpretq_u8_u32(v), vrotl8_tbl)); +#else + uint32x4_t a = vshlq_n_u32(v, 8); + result = vsriq_n_u32(a, v, 24); +#endif + return result; +} + +static inline uint32x4_t chacha20_neon_vrotlq_7_u32(uint32x4_t v) +{ + uint32x4_t x = vshlq_n_u32(v, 7); + return vsriq_n_u32(x, v, 25); +} + +// Increment the 32-bit element within v that corresponds to the ChaCha20 counter +static inline uint32x4_t chacha20_neon_inc_counter(uint32x4_t v) +{ + /* { 1, 0, 0, 0 } */ + uint32x4_t counter_increment = vcombine_u32(vcreate_u32(1), vdup_n_u32(0)); + return vaddq_u32(v, counter_increment); +} + +static inline chacha20_neon_regs_t chacha20_neon_singlepass(chacha20_neon_regs_t r) +{ + for (unsigned i = 0; i < 2; i++) { + r.a = vaddq_u32(r.a, r.b); // r.a += b + r.d = veorq_u32(r.d, r.a); // r.d ^= a + r.d = chacha20_neon_vrotlq_16_u32(r.d); // r.d <<<= 16 + + r.c = vaddq_u32(r.c, r.d); // r.c += d + r.b = veorq_u32(r.b, r.c); // r.b ^= c + r.b = chacha20_neon_vrotlq_12_u32(r.b); // r.b <<<= 12 + + r.a = vaddq_u32(r.a, r.b); // r.a += b + r.d = veorq_u32(r.d, r.a); // r.d ^= a + r.d = chacha20_neon_vrotlq_8_u32(r.d); // r.d <<<= 8 + + r.c = vaddq_u32(r.c, r.d); // r.c += d + r.b = veorq_u32(r.b, r.c); // r.b ^= c + r.b = chacha20_neon_vrotlq_7_u32(r.b); // r.b <<<= 7 + + // re-order b, c and d for the diagonal rounds + r.c = vextq_u32(r.c, r.c, 2); + if (i == 0) { + r.b = vextq_u32(r.b, r.b, 1); + r.d = vextq_u32(r.d, r.d, 3); + } else { + // restore element order in b, c, d + r.b = vextq_u32(r.b, r.b, 3); + r.d = vextq_u32(r.d, r.d, 1); + } + } + + return r; +} + +static inline void chacha20_neon_finish_block(chacha20_neon_regs_t r, + chacha20_neon_regs_t r_original, + uint8_t **output, + const uint8_t **input) +{ + const uint8_t *i = *input; + uint8_t *o = *output; + + r.a = vaddq_u32(r.a, r_original.a); + r.b = vaddq_u32(r.b, r_original.b); + r.c = vaddq_u32(r.c, r_original.c); + r.d = vaddq_u32(r.d, r_original.d); + + vst1q_u8(o + 0, veorq_u8(vld1q_u8(i + 0), vreinterpretq_u8_u32(r.a))); + vst1q_u8(o + 16, veorq_u8(vld1q_u8(i + 16), vreinterpretq_u8_u32(r.b))); + vst1q_u8(o + 32, veorq_u8(vld1q_u8(i + 32), vreinterpretq_u8_u32(r.c))); + vst1q_u8(o + 48, veorq_u8(vld1q_u8(i + 48), vreinterpretq_u8_u32(r.d))); + + *input = i + MBEDTLS_CHACHA20_BLOCK_SIZE_BYTES; + *output = o + MBEDTLS_CHACHA20_BLOCK_SIZE_BYTES; +} + +// Prevent gcc from rolling up the (manually unrolled) interleaved block loops +MBEDTLS_OPTIMIZE_FOR_PERFORMANCE +static inline uint32x4_t chacha20_neon_blocks(chacha20_neon_regs_t r_original, + uint8_t *output, + const uint8_t *input, + size_t blocks) +{ + // Assuming 32 regs, with 4 for original values plus 4 for scratch, with 4 regs per block, + // we should be able to process up to 24/4 = 6 blocks simultaneously. + // Testing confirms that perf indeed increases with more blocks, and then falls off after 6. + + for (;;) { + chacha20_neon_regs_t r[6]; + + // It's essential to unroll these loops to benefit from interleaving multiple blocks. + // If MBEDTLS_CHACHA20_NEON_MULTIBLOCK < 6, gcc and clang will optimise away the unused bits + r[0] = r_original; + r[1] = r_original; + r[2] = r_original; + r[3] = r_original; + r[4] = r_original; + r[5] = r_original; + r[1].d = chacha20_neon_inc_counter(r[0].d); + r[2].d = chacha20_neon_inc_counter(r[1].d); + r[3].d = chacha20_neon_inc_counter(r[2].d); + r[4].d = chacha20_neon_inc_counter(r[3].d); + r[5].d = chacha20_neon_inc_counter(r[4].d); + + for (unsigned i = 0; i < 10; i++) { + r[0] = chacha20_neon_singlepass(r[0]); + r[1] = chacha20_neon_singlepass(r[1]); + r[2] = chacha20_neon_singlepass(r[2]); + r[3] = chacha20_neon_singlepass(r[3]); + r[4] = chacha20_neon_singlepass(r[4]); + r[5] = chacha20_neon_singlepass(r[5]); + } + + chacha20_neon_finish_block(r[0], r_original, &output, &input); + r_original.d = chacha20_neon_inc_counter(r_original.d); + if (--blocks == 0) { + return r_original.d; + } +#if MBEDTLS_CHACHA20_NEON_MULTIBLOCK >= 2 + chacha20_neon_finish_block(r[1], r_original, &output, &input); + r_original.d = chacha20_neon_inc_counter(r_original.d); + if (--blocks == 0) { + return r_original.d; + } +#endif +#if MBEDTLS_CHACHA20_NEON_MULTIBLOCK >= 3 + chacha20_neon_finish_block(r[2], r_original, &output, &input); + r_original.d = chacha20_neon_inc_counter(r_original.d); + if (--blocks == 0) { + return r_original.d; + } +#endif +#if MBEDTLS_CHACHA20_NEON_MULTIBLOCK >= 4 + chacha20_neon_finish_block(r[3], r_original, &output, &input); + r_original.d = chacha20_neon_inc_counter(r_original.d); + if (--blocks == 0) { + return r_original.d; + } +#endif +#if MBEDTLS_CHACHA20_NEON_MULTIBLOCK >= 5 + chacha20_neon_finish_block(r[4], r_original, &output, &input); + r_original.d = chacha20_neon_inc_counter(r_original.d); + if (--blocks == 0) { + return r_original.d; + } +#endif +#if MBEDTLS_CHACHA20_NEON_MULTIBLOCK >= 6 + chacha20_neon_finish_block(r[5], r_original, &output, &input); + r_original.d = chacha20_neon_inc_counter(r_original.d); + if (--blocks == 0) { + return r_original.d; + } +#endif + } +} + +int mbedtls_chacha20_update(mbedtls_chacha20_context *ctx, + size_t size, + const unsigned char *input, + unsigned char *output) +{ + size_t offset = 0U; + + /* Use leftover keystream bytes, if available */ + while (ctx->keystream_bytes_used < MBEDTLS_CHACHA20_BLOCK_SIZE_BYTES && size > 0) { + output[offset] = input[offset] + ^ ctx->keystream8[ctx->keystream_bytes_used]; + + ctx->keystream_bytes_used++; + offset++; + size--; + } + + /* Load state into NEON registers */ + chacha20_neon_regs_t state; + state.a = vld1q_u32(&ctx->state[0]); + state.b = vld1q_u32(&ctx->state[4]); + state.c = vld1q_u32(&ctx->state[8]); + state.d = vld1q_u32(&ctx->state[12]); + + /* Process full blocks */ + if (size >= MBEDTLS_CHACHA20_BLOCK_SIZE_BYTES) { + size_t blocks = size / MBEDTLS_CHACHA20_BLOCK_SIZE_BYTES; + state.d = chacha20_neon_blocks(state, output + offset, input + offset, blocks); + + offset += MBEDTLS_CHACHA20_BLOCK_SIZE_BYTES * blocks; + size -= MBEDTLS_CHACHA20_BLOCK_SIZE_BYTES * blocks; + } + + /* Last (partial) block */ + if (size > 0U) { + /* Generate new keystream block and increment counter */ + memset(ctx->keystream8, 0, MBEDTLS_CHACHA20_BLOCK_SIZE_BYTES); + state.d = chacha20_neon_blocks(state, ctx->keystream8, ctx->keystream8, 1); + + mbedtls_xor_no_simd(output + offset, input + offset, ctx->keystream8, size); + + ctx->keystream_bytes_used = size; + } + + /* Capture state */ + vst1q_u32(&ctx->state[12], state.d); + + return 0; +} + +#endif /* defined(MBEDTLS_CHACHA20_C) && (MBEDTLS_CHACHA20_NEON_MULTIBLOCK != 0) */ diff --git a/tf-psa-crypto/drivers/builtin/src/chacha20_neon.h b/tf-psa-crypto/drivers/builtin/src/chacha20_neon.h new file mode 100644 index 0000000000..024f21017a --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/chacha20_neon.h @@ -0,0 +1,62 @@ +/** + * \file chacha20_neon.h + * + * \brief Neon implementation of ChaCha20 + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_CHACHA20_NEON_H +#define TF_PSA_CRYPTO_CHACHA20_NEON_H + +#include "tf_psa_crypto_common.h" + +/* + * The Neon implementation can be configured to process multiple blocks in parallel; increasing the + * number of blocks gains a lot of performance, but adds on average around 250 bytes of code size + * for each additional block. + * + * This is controlled by setting MBEDTLS_CHACHA20_NEON_MULTIBLOCK in the range [0..6] (0 selects + * the scalar implementation; 1 selects single-block Neon; 2..6 select multi-block Neon). + * + * The default (i.e., if MBEDTLS_CHACHA20_NEON_MULTIBLOCK is not set) selects the fastest variant + * which has better code size than the scalar implementation (based on testing for Aarch64 on clang + * and gcc). + * + * Size & performance notes for Neon implementation from informal tests on Aarch64 + * (applies to both gcc and clang except as noted): + * - When single-block is selected, this saves around 400-550 bytes of code-size c.f. the scalar + * implementation + * - Multi-block Neon is smaller and faster than scalar (up to 2 blocks for gcc, 3 for clang) + * - Code size increases consistently with number of blocks + * - Performance increases with number of blocks (except at 5 which is slightly slower than 4) + * - Performance is within a few % for gcc vs clang at all settings + * - Performance at 4 blocks roughly matches our hardware accelerated AES-GCM impl with + * better code size + * - Performance is worse at 7 or more blocks, due to running out of Neon registers + */ + +#if !defined(MBEDTLS_HAVE_NEON_INTRINSICS) +// Select scalar implementation if Neon not available + #define MBEDTLS_CHACHA20_NEON_MULTIBLOCK 0 +#elif !defined(MBEDTLS_CHACHA20_NEON_MULTIBLOCK) +// By default, select the best performing option that is not a code-size regression (based on +// measurements from recent gcc and clang). +#if defined(MBEDTLS_ARCH_IS_THUMB) + #if defined(MBEDTLS_COMPILER_IS_GCC) + #define MBEDTLS_CHACHA20_NEON_MULTIBLOCK 1 + #else + #define MBEDTLS_CHACHA20_NEON_MULTIBLOCK 2 + #endif +#elif defined(MBEDTLS_ARCH_IS_ARM64) + #define MBEDTLS_CHACHA20_NEON_MULTIBLOCK 3 +#else + #if defined(MBEDTLS_COMPILER_IS_GCC) + #define MBEDTLS_CHACHA20_NEON_MULTIBLOCK 2 + #else + #define MBEDTLS_CHACHA20_NEON_MULTIBLOCK 3 + #endif +#endif +#endif + +#endif /* TF_PSA_CRYPTO_CHACHA20_NEON_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/chachapoly.c b/tf-psa-crypto/drivers/builtin/src/chachapoly.c new file mode 100644 index 0000000000..22aa7cdcc2 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/chachapoly.c @@ -0,0 +1,474 @@ +/** + * \file chachapoly.c + * + * \brief ChaCha20-Poly1305 AEAD construction based on RFC 7539. + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_CHACHAPOLY_C) + +#include "mbedtls/private/chachapoly.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" +#include "mbedtls/constant_time.h" + +#include + +#include "mbedtls/platform.h" + +#define CHACHAPOLY_STATE_INIT (0) +#define CHACHAPOLY_STATE_AAD (1) +#define CHACHAPOLY_STATE_CIPHERTEXT (2) /* Encrypting or decrypting */ +#define CHACHAPOLY_STATE_FINISHED (3) + +/** + * \brief Adds nul bytes to pad the AAD for Poly1305. + * + * \param ctx The ChaCha20-Poly1305 context. + */ +static int chachapoly_pad_aad(mbedtls_chachapoly_context *ctx) +{ + uint32_t partial_block_len = (uint32_t) (ctx->aad_len % 16U); + unsigned char zeroes[15]; + + if (partial_block_len == 0U) { + return 0; + } + + memset(zeroes, 0, sizeof(zeroes)); + + return mbedtls_poly1305_update(&ctx->poly1305_ctx, + zeroes, + 16U - partial_block_len); +} + +/** + * \brief Adds nul bytes to pad the ciphertext for Poly1305. + * + * \param ctx The ChaCha20-Poly1305 context. + */ +static int chachapoly_pad_ciphertext(mbedtls_chachapoly_context *ctx) +{ + uint32_t partial_block_len = (uint32_t) (ctx->ciphertext_len % 16U); + unsigned char zeroes[15]; + + if (partial_block_len == 0U) { + return 0; + } + + memset(zeroes, 0, sizeof(zeroes)); + return mbedtls_poly1305_update(&ctx->poly1305_ctx, + zeroes, + 16U - partial_block_len); +} + +void mbedtls_chachapoly_init(mbedtls_chachapoly_context *ctx) +{ + mbedtls_chacha20_init(&ctx->chacha20_ctx); + mbedtls_poly1305_init(&ctx->poly1305_ctx); + ctx->aad_len = 0U; + ctx->ciphertext_len = 0U; + ctx->state = CHACHAPOLY_STATE_INIT; + ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT; +} + +void mbedtls_chachapoly_free(mbedtls_chachapoly_context *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_chacha20_free(&ctx->chacha20_ctx); + mbedtls_poly1305_free(&ctx->poly1305_ctx); + ctx->aad_len = 0U; + ctx->ciphertext_len = 0U; + ctx->state = CHACHAPOLY_STATE_INIT; + ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT; +} + +int mbedtls_chachapoly_setkey(mbedtls_chachapoly_context *ctx, + const unsigned char key[32]) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + ret = mbedtls_chacha20_setkey(&ctx->chacha20_ctx, key); + + return ret; +} + +int mbedtls_chachapoly_starts(mbedtls_chachapoly_context *ctx, + const unsigned char nonce[12], + mbedtls_chachapoly_mode_t mode) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char poly1305_key[64]; + + /* Set counter = 0, will be update to 1 when generating Poly1305 key */ + ret = mbedtls_chacha20_starts(&ctx->chacha20_ctx, nonce, 0U); + if (ret != 0) { + goto cleanup; + } + + /* Generate the Poly1305 key by getting the ChaCha20 keystream output with + * counter = 0. This is the same as encrypting a buffer of zeroes. + * Only the first 256-bits (32 bytes) of the key is used for Poly1305. + * The other 256 bits are discarded. + */ + memset(poly1305_key, 0, sizeof(poly1305_key)); + ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, sizeof(poly1305_key), + poly1305_key, poly1305_key); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_poly1305_starts(&ctx->poly1305_ctx, poly1305_key); + + if (ret == 0) { + ctx->aad_len = 0U; + ctx->ciphertext_len = 0U; + ctx->state = CHACHAPOLY_STATE_AAD; + ctx->mode = mode; + } + +cleanup: + mbedtls_platform_zeroize(poly1305_key, 64U); + return ret; +} + +int mbedtls_chachapoly_update_aad(mbedtls_chachapoly_context *ctx, + const unsigned char *aad, + size_t aad_len) +{ + if (ctx->state != CHACHAPOLY_STATE_AAD) { + return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE; + } + + ctx->aad_len += aad_len; + + return mbedtls_poly1305_update(&ctx->poly1305_ctx, aad, aad_len); +} + +int mbedtls_chachapoly_update(mbedtls_chachapoly_context *ctx, + size_t len, + const unsigned char *input, + unsigned char *output) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if ((ctx->state != CHACHAPOLY_STATE_AAD) && + (ctx->state != CHACHAPOLY_STATE_CIPHERTEXT)) { + return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE; + } + + if (ctx->state == CHACHAPOLY_STATE_AAD) { + ctx->state = CHACHAPOLY_STATE_CIPHERTEXT; + + ret = chachapoly_pad_aad(ctx); + if (ret != 0) { + return ret; + } + } + + ctx->ciphertext_len += len; + + if (ctx->mode == MBEDTLS_CHACHAPOLY_ENCRYPT) { + ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, len, input, output); + if (ret != 0) { + return ret; + } + + ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, output, len); + if (ret != 0) { + return ret; + } + } else { /* DECRYPT */ + ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, input, len); + if (ret != 0) { + return ret; + } + + ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, len, input, output); + if (ret != 0) { + return ret; + } + } + + return 0; +} + +int mbedtls_chachapoly_finish(mbedtls_chachapoly_context *ctx, + unsigned char mac[16]) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char len_block[16]; + + if (ctx->state == CHACHAPOLY_STATE_INIT) { + return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE; + } + + if (ctx->state == CHACHAPOLY_STATE_AAD) { + ret = chachapoly_pad_aad(ctx); + if (ret != 0) { + return ret; + } + } else if (ctx->state == CHACHAPOLY_STATE_CIPHERTEXT) { + ret = chachapoly_pad_ciphertext(ctx); + if (ret != 0) { + return ret; + } + } + + ctx->state = CHACHAPOLY_STATE_FINISHED; + + /* The lengths of the AAD and ciphertext are processed by + * Poly1305 as the final 128-bit block, encoded as little-endian integers. + */ + MBEDTLS_PUT_UINT64_LE(ctx->aad_len, len_block, 0); + MBEDTLS_PUT_UINT64_LE(ctx->ciphertext_len, len_block, 8); + + ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, len_block, 16U); + if (ret != 0) { + return ret; + } + + ret = mbedtls_poly1305_finish(&ctx->poly1305_ctx, mac); + + return ret; +} + +static int chachapoly_crypt_and_tag(mbedtls_chachapoly_context *ctx, + mbedtls_chachapoly_mode_t mode, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char *input, + unsigned char *output, + unsigned char tag[16]) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + ret = mbedtls_chachapoly_starts(ctx, nonce, mode); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_chachapoly_update_aad(ctx, aad, aad_len); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_chachapoly_update(ctx, length, input, output); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_chachapoly_finish(ctx, tag); + +cleanup: + return ret; +} + +int mbedtls_chachapoly_encrypt_and_tag(mbedtls_chachapoly_context *ctx, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char *input, + unsigned char *output, + unsigned char tag[16]) +{ + return chachapoly_crypt_and_tag(ctx, MBEDTLS_CHACHAPOLY_ENCRYPT, + length, nonce, aad, aad_len, + input, output, tag); +} + +int mbedtls_chachapoly_auth_decrypt(mbedtls_chachapoly_context *ctx, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char tag[16], + const unsigned char *input, + unsigned char *output) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char check_tag[16]; + int diff; + + if ((ret = chachapoly_crypt_and_tag(ctx, + MBEDTLS_CHACHAPOLY_DECRYPT, length, nonce, + aad, aad_len, input, output, check_tag)) != 0) { + return ret; + } + + /* Check tag in "constant-time" */ + diff = mbedtls_ct_memcmp(tag, check_tag, sizeof(check_tag)); + + if (diff != 0) { + mbedtls_platform_zeroize(output, length); + return MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED; + } + + return 0; +} + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char test_key[1][32] = +{ + { + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f + } +}; + +static const unsigned char test_nonce[1][12] = +{ + { + 0x07, 0x00, 0x00, 0x00, /* 32-bit common part */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 /* 64-bit IV */ + } +}; + +static const unsigned char test_aad[1][12] = +{ + { + 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7 + } +}; + +static const size_t test_aad_len[1] = +{ + 12U +}; + +static const unsigned char test_input[1][114] = +{ + { + 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, + 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, + 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, + 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, + 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, + 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, + 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73, + 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, + 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, + 0x74, 0x2e + } +}; + +static const unsigned char test_output[1][114] = +{ + { + 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, + 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2, + 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, + 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, + 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12, + 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b, + 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, + 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36, + 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c, + 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, + 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94, + 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc, + 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, + 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b, + 0x61, 0x16 + } +}; + +static const size_t test_input_len[1] = +{ + 114U +}; + +static const unsigned char test_mac[1][16] = +{ + { + 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a, + 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91 + } +}; + +/* Make sure no other definition is already present. */ +#undef ASSERT + +#define ASSERT(cond, args) \ + do \ + { \ + if (!(cond)) \ + { \ + if (verbose != 0) \ + mbedtls_printf args; \ + \ + return -1; \ + } \ + } \ + while (0) + +int mbedtls_chachapoly_self_test(int verbose) +{ + mbedtls_chachapoly_context ctx; + unsigned i; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char output[200]; + unsigned char mac[16]; + + for (i = 0U; i < 1U; i++) { + if (verbose != 0) { + mbedtls_printf(" ChaCha20-Poly1305 test %u ", i); + } + + mbedtls_chachapoly_init(&ctx); + + ret = mbedtls_chachapoly_setkey(&ctx, test_key[i]); + ASSERT(0 == ret, ("setkey() error code: %i\n", ret)); + + ret = mbedtls_chachapoly_encrypt_and_tag(&ctx, + test_input_len[i], + test_nonce[i], + test_aad[i], + test_aad_len[i], + test_input[i], + output, + mac); + + ASSERT(0 == ret, ("crypt_and_tag() error code: %i\n", ret)); + + ASSERT(0 == memcmp(output, test_output[i], test_input_len[i]), + ("failure (wrong output)\n")); + + ASSERT(0 == memcmp(mac, test_mac[i], 16U), + ("failure (wrong MAC)\n")); + + mbedtls_chachapoly_free(&ctx); + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + return 0; +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CHACHAPOLY_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/cipher.c b/tf-psa-crypto/drivers/builtin/src/cipher.c new file mode 100644 index 0000000000..dd44872729 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/cipher.c @@ -0,0 +1,1126 @@ +/** + * \file cipher.c + * + * \brief Generic cipher wrapper for Mbed TLS + * + * \author Adriaan de Jong + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_CIPHER_C) + +#include "mbedtls/private/cipher.h" +#include "cipher_invasive.h" +#include "cipher_wrap.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" +#include "mbedtls/constant_time.h" +#include "constant_time_internal.h" + +#include +#include + +#if defined(MBEDTLS_CHACHAPOLY_C) +#include "mbedtls/private/chachapoly.h" +#endif + +#if defined(MBEDTLS_GCM_C) +#include "mbedtls/private/gcm.h" +#endif + +#if defined(MBEDTLS_CCM_C) +#include "mbedtls/private/ccm.h" +#endif + +#if defined(MBEDTLS_CHACHA20_C) +#include "mbedtls/private/chacha20.h" +#endif + +#if defined(MBEDTLS_CMAC_C) +#include "mbedtls/private/cmac.h" +#endif + +#include "mbedtls/platform.h" + +static int supported_init = 0; + +static inline const mbedtls_cipher_base_t *mbedtls_cipher_get_base( + const mbedtls_cipher_info_t *info) +{ + return mbedtls_cipher_base_lookup_table[info->base_idx]; +} + +const int *mbedtls_cipher_list(void) +{ + const mbedtls_cipher_definition_t *def; + int *type; + + if (!supported_init) { + def = mbedtls_cipher_definitions; + type = mbedtls_cipher_supported; + + while (def->type != 0) { + *type++ = (*def++).type; + } + + *type = 0; + + supported_init = 1; + } + + return mbedtls_cipher_supported; +} + +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( + const mbedtls_cipher_type_t cipher_type) +{ + const mbedtls_cipher_definition_t *def; + + for (def = mbedtls_cipher_definitions; def->info != NULL; def++) { + if (def->type == cipher_type) { + return def->info; + } + } + + return NULL; +} + +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( + const char *cipher_name) +{ + const mbedtls_cipher_definition_t *def; + + if (NULL == cipher_name) { + return NULL; + } + + for (def = mbedtls_cipher_definitions; def->info != NULL; def++) { + if (!strcmp(def->info->name, cipher_name)) { + return def->info; + } + } + + return NULL; +} + +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( + const mbedtls_cipher_id_t cipher_id, + int key_bitlen, + const mbedtls_cipher_mode_t mode) +{ + const mbedtls_cipher_definition_t *def; + + for (def = mbedtls_cipher_definitions; def->info != NULL; def++) { + if (mbedtls_cipher_get_base(def->info)->cipher == cipher_id && + mbedtls_cipher_info_get_key_bitlen(def->info) == (unsigned) key_bitlen && + def->info->mode == mode) { + return def->info; + } + } + + return NULL; +} + +void mbedtls_cipher_init(mbedtls_cipher_context_t *ctx) +{ + memset(ctx, 0, sizeof(mbedtls_cipher_context_t)); +} + +void mbedtls_cipher_free(mbedtls_cipher_context_t *ctx) +{ + if (ctx == NULL) { + return; + } + +#if defined(MBEDTLS_CMAC_C) + if (ctx->cmac_ctx) { + mbedtls_zeroize_and_free(ctx->cmac_ctx, + sizeof(mbedtls_cmac_context_t)); + } +#endif + + if (ctx->cipher_ctx) { + mbedtls_cipher_get_base(ctx->cipher_info)->ctx_free_func(ctx->cipher_ctx); + } + + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_cipher_context_t)); +} + +int mbedtls_cipher_setup(mbedtls_cipher_context_t *ctx, + const mbedtls_cipher_info_t *cipher_info) +{ + if (cipher_info == NULL) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + memset(ctx, 0, sizeof(mbedtls_cipher_context_t)); + + if (mbedtls_cipher_get_base(cipher_info)->ctx_alloc_func != NULL) { + ctx->cipher_ctx = mbedtls_cipher_get_base(cipher_info)->ctx_alloc_func(); + if (ctx->cipher_ctx == NULL) { + return MBEDTLS_ERR_CIPHER_ALLOC_FAILED; + } + } + + ctx->cipher_info = cipher_info; + + return 0; +} + +int mbedtls_cipher_setkey(mbedtls_cipher_context_t *ctx, + const unsigned char *key, + int key_bitlen, + const mbedtls_operation_t operation) +{ + if (operation != MBEDTLS_ENCRYPT && operation != MBEDTLS_DECRYPT) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + if (ctx->cipher_info == NULL) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } +#if defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + if (MBEDTLS_MODE_ECB == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode) && + MBEDTLS_DECRYPT == operation) { + return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + } +#endif + + if ((ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN) == 0 && + (int) mbedtls_cipher_info_get_key_bitlen(ctx->cipher_info) != key_bitlen) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + ctx->key_bitlen = key_bitlen; + ctx->operation = operation; + +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + /* + * For OFB, CFB and CTR mode always use the encryption key schedule + */ + if (MBEDTLS_ENCRYPT == operation || + MBEDTLS_MODE_CFB == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode) || + MBEDTLS_MODE_OFB == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode) || + MBEDTLS_MODE_CTR == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) { + return mbedtls_cipher_get_base(ctx->cipher_info)->setkey_enc_func(ctx->cipher_ctx, key, + ctx->key_bitlen); + } + + if (MBEDTLS_DECRYPT == operation) { + return mbedtls_cipher_get_base(ctx->cipher_info)->setkey_dec_func(ctx->cipher_ctx, key, + ctx->key_bitlen); + } +#else + if (operation == MBEDTLS_ENCRYPT || operation == MBEDTLS_DECRYPT) { + return mbedtls_cipher_get_base(ctx->cipher_info)->setkey_enc_func(ctx->cipher_ctx, key, + ctx->key_bitlen); + } +#endif + + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; +} + +int mbedtls_cipher_set_iv(mbedtls_cipher_context_t *ctx, + const unsigned char *iv, + size_t iv_len) +{ + size_t actual_iv_size; + + if (ctx->cipher_info == NULL) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + /* avoid buffer overflow in ctx->iv */ + if (iv_len > MBEDTLS_MAX_IV_LENGTH) { + return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + } + + if ((ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_IV_LEN) != 0) { + actual_iv_size = iv_len; + } else { + actual_iv_size = mbedtls_cipher_info_get_iv_size(ctx->cipher_info); + + /* avoid reading past the end of input buffer */ + if (actual_iv_size > iv_len) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + } + +#if defined(MBEDTLS_CHACHA20_C) + if (((mbedtls_cipher_type_t) ctx->cipher_info->type) == MBEDTLS_CIPHER_CHACHA20) { + /* Even though the actual_iv_size is overwritten with a correct value + * of 12 from the cipher info, return an error to indicate that + * the input iv_len is wrong. */ + if (iv_len != 12) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + if (0 != mbedtls_chacha20_starts((mbedtls_chacha20_context *) ctx->cipher_ctx, + iv, + 0U)) { /* Initial counter value */ + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + } +#if defined(MBEDTLS_CHACHAPOLY_C) + if (((mbedtls_cipher_type_t) ctx->cipher_info->type) == MBEDTLS_CIPHER_CHACHA20_POLY1305 && + iv_len != 12) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } +#endif +#endif + +#if defined(MBEDTLS_GCM_C) + if (MBEDTLS_MODE_GCM == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) { + return mbedtls_gcm_starts((mbedtls_gcm_context *) ctx->cipher_ctx, + ctx->operation, + iv, iv_len); + } +#endif + +#if defined(MBEDTLS_CCM_C) + if (MBEDTLS_MODE_CCM_STAR_NO_TAG == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) { + int set_lengths_result; + int ccm_star_mode; + + set_lengths_result = mbedtls_ccm_set_lengths( + (mbedtls_ccm_context *) ctx->cipher_ctx, + 0, 0, 0); + if (set_lengths_result != 0) { + return set_lengths_result; + } + + if (ctx->operation == MBEDTLS_DECRYPT) { + ccm_star_mode = MBEDTLS_CCM_STAR_DECRYPT; + } else if (ctx->operation == MBEDTLS_ENCRYPT) { + ccm_star_mode = MBEDTLS_CCM_STAR_ENCRYPT; + } else { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + return mbedtls_ccm_starts((mbedtls_ccm_context *) ctx->cipher_ctx, + ccm_star_mode, + iv, iv_len); + } +#endif + + if (actual_iv_size != 0) { + memcpy(ctx->iv, iv, actual_iv_size); + ctx->iv_size = actual_iv_size; + } + + return 0; +} + +int mbedtls_cipher_reset(mbedtls_cipher_context_t *ctx) +{ + if (ctx->cipher_info == NULL) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + ctx->unprocessed_len = 0; + + return 0; +} + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +int mbedtls_cipher_update_ad(mbedtls_cipher_context_t *ctx, + const unsigned char *ad, size_t ad_len) +{ + if (ctx->cipher_info == NULL) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + +#if defined(MBEDTLS_GCM_C) + if (MBEDTLS_MODE_GCM == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) { + return mbedtls_gcm_update_ad((mbedtls_gcm_context *) ctx->cipher_ctx, + ad, ad_len); + } +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + if (MBEDTLS_CIPHER_CHACHA20_POLY1305 == ((mbedtls_cipher_type_t) ctx->cipher_info->type)) { + int result; + mbedtls_chachapoly_mode_t mode; + + mode = (ctx->operation == MBEDTLS_ENCRYPT) + ? MBEDTLS_CHACHAPOLY_ENCRYPT + : MBEDTLS_CHACHAPOLY_DECRYPT; + + result = mbedtls_chachapoly_starts((mbedtls_chachapoly_context *) ctx->cipher_ctx, + ctx->iv, + mode); + if (result != 0) { + return result; + } + + return mbedtls_chachapoly_update_aad((mbedtls_chachapoly_context *) ctx->cipher_ctx, + ad, ad_len); + } +#endif + + return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; +} +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ + +int mbedtls_cipher_update(mbedtls_cipher_context_t *ctx, const unsigned char *input, + size_t ilen, unsigned char *output, size_t *olen) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t block_size; + + if (ctx->cipher_info == NULL) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + *olen = 0; + block_size = mbedtls_cipher_get_block_size(ctx); + if (0 == block_size) { + return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT; + } + + if (((mbedtls_cipher_mode_t) ctx->cipher_info->mode) == MBEDTLS_MODE_ECB) { + if (ilen != block_size) { + return MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED; + } + + *olen = ilen; + + if (0 != (ret = mbedtls_cipher_get_base(ctx->cipher_info)->ecb_func(ctx->cipher_ctx, + ctx->operation, input, + output))) { + return ret; + } + + return 0; + } + +#if defined(MBEDTLS_GCM_C) + if (((mbedtls_cipher_mode_t) ctx->cipher_info->mode) == MBEDTLS_MODE_GCM) { + return mbedtls_gcm_update((mbedtls_gcm_context *) ctx->cipher_ctx, + input, ilen, + output, ilen, olen); + } +#endif + +#if defined(MBEDTLS_CCM_C) + if (((mbedtls_cipher_mode_t) ctx->cipher_info->mode) == MBEDTLS_MODE_CCM_STAR_NO_TAG) { + return mbedtls_ccm_update((mbedtls_ccm_context *) ctx->cipher_ctx, + input, ilen, + output, ilen, olen); + } +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + if (((mbedtls_cipher_type_t) ctx->cipher_info->type) == MBEDTLS_CIPHER_CHACHA20_POLY1305) { + *olen = ilen; + return mbedtls_chachapoly_update((mbedtls_chachapoly_context *) ctx->cipher_ctx, + ilen, input, output); + } +#endif + + if (input == output && + (ctx->unprocessed_len != 0 || ilen % block_size)) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + if (((mbedtls_cipher_mode_t) ctx->cipher_info->mode) == MBEDTLS_MODE_CBC) { + size_t copy_len = 0; + + /* + * If there is not enough data for a full block, cache it. + */ + if ((ctx->operation == MBEDTLS_DECRYPT && NULL != ctx->add_padding && + ilen <= block_size - ctx->unprocessed_len) || + (ctx->operation == MBEDTLS_DECRYPT && NULL == ctx->add_padding && + ilen < block_size - ctx->unprocessed_len) || + (ctx->operation == MBEDTLS_ENCRYPT && + ilen < block_size - ctx->unprocessed_len)) { + memcpy(&(ctx->unprocessed_data[ctx->unprocessed_len]), input, + ilen); + + ctx->unprocessed_len += ilen; + return 0; + } + + /* + * Process cached data first + */ + if (0 != ctx->unprocessed_len) { + copy_len = block_size - ctx->unprocessed_len; + + memcpy(&(ctx->unprocessed_data[ctx->unprocessed_len]), input, + copy_len); + + if (0 != (ret = mbedtls_cipher_get_base(ctx->cipher_info)->cbc_func(ctx->cipher_ctx, + ctx->operation, + block_size, ctx->iv, + ctx-> + unprocessed_data, + output))) { + return ret; + } + + *olen += block_size; + output += block_size; + ctx->unprocessed_len = 0; + + input += copy_len; + ilen -= copy_len; + } + + /* + * Cache final, incomplete block + */ + if (0 != ilen) { + /* Encryption: only cache partial blocks + * Decryption w/ padding: always keep at least one whole block + * Decryption w/o padding: only cache partial blocks + */ + copy_len = ilen % block_size; + if (copy_len == 0 && + ctx->operation == MBEDTLS_DECRYPT && + NULL != ctx->add_padding) { + copy_len = block_size; + } + + memcpy(ctx->unprocessed_data, &(input[ilen - copy_len]), + copy_len); + + ctx->unprocessed_len += copy_len; + ilen -= copy_len; + } + + /* + * Process remaining full blocks + */ + if (ilen) { + if (0 != (ret = mbedtls_cipher_get_base(ctx->cipher_info)->cbc_func(ctx->cipher_ctx, + ctx->operation, + ilen, ctx->iv, + input, + output))) { + return ret; + } + + *olen += ilen; + } + + return 0; + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + if (((mbedtls_cipher_mode_t) ctx->cipher_info->mode) == MBEDTLS_MODE_CFB) { + if (0 != (ret = mbedtls_cipher_get_base(ctx->cipher_info)->cfb_func(ctx->cipher_ctx, + ctx->operation, ilen, + &ctx->unprocessed_len, + ctx->iv, + input, output))) { + return ret; + } + + *olen = ilen; + + return 0; + } +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) + if (((mbedtls_cipher_mode_t) ctx->cipher_info->mode) == MBEDTLS_MODE_OFB) { + if (0 != (ret = mbedtls_cipher_get_base(ctx->cipher_info)->ofb_func(ctx->cipher_ctx, + ilen, + &ctx->unprocessed_len, + ctx->iv, + input, output))) { + return ret; + } + + *olen = ilen; + + return 0; + } +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + if (((mbedtls_cipher_mode_t) ctx->cipher_info->mode) == MBEDTLS_MODE_CTR) { + if (0 != (ret = mbedtls_cipher_get_base(ctx->cipher_info)->ctr_func(ctx->cipher_ctx, + ilen, + &ctx->unprocessed_len, + ctx->iv, + ctx->unprocessed_data, + input, output))) { + return ret; + } + + *olen = ilen; + + return 0; + } +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) + if (((mbedtls_cipher_mode_t) ctx->cipher_info->mode) == MBEDTLS_MODE_XTS) { + if (ctx->unprocessed_len > 0) { + /* We can only process an entire data unit at a time. */ + return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + } + + ret = mbedtls_cipher_get_base(ctx->cipher_info)->xts_func(ctx->cipher_ctx, + ctx->operation, + ilen, + ctx->iv, + input, + output); + if (ret != 0) { + return ret; + } + + *olen = ilen; + + return 0; + } +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + if (((mbedtls_cipher_mode_t) ctx->cipher_info->mode) == MBEDTLS_MODE_STREAM) { + if (0 != (ret = mbedtls_cipher_get_base(ctx->cipher_info)->stream_func(ctx->cipher_ctx, + ilen, input, + output))) { + return ret; + } + + *olen = ilen; + + return 0; + } +#endif /* MBEDTLS_CIPHER_MODE_STREAM */ + + return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; +} + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) +/* + * PKCS7 (and PKCS5) padding: fill with ll bytes, with ll = padding_len + */ +static void add_pkcs_padding(unsigned char *output, size_t output_len, + size_t data_len) +{ + size_t padding_len = output_len - data_len; + unsigned char i; + + for (i = 0; i < padding_len; i++) { + output[data_len + i] = (unsigned char) padding_len; + } +} + +/* + * Get the length of the PKCS7 padding. + * + * Note: input_len must be the block size of the cipher. + */ +MBEDTLS_STATIC_TESTABLE int mbedtls_get_pkcs_padding(unsigned char *input, + size_t input_len, + size_t *data_len, + size_t *invalid_padding) +{ + size_t i, pad_idx; + unsigned char padding_len; + + if (NULL == input || NULL == data_len) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + padding_len = input[input_len - 1]; + + mbedtls_ct_condition_t bad = mbedtls_ct_uint_gt(padding_len, input_len); + bad = mbedtls_ct_bool_or(bad, mbedtls_ct_uint_eq(padding_len, 0)); + + /* The number of bytes checked must be independent of padding_len, + * so pick input_len, which is usually 8 or 16 (one block) */ + pad_idx = input_len - padding_len; + for (i = 0; i < input_len; i++) { + mbedtls_ct_condition_t in_padding = mbedtls_ct_uint_ge(i, pad_idx); + mbedtls_ct_condition_t different = mbedtls_ct_uint_ne(input[i], padding_len); + bad = mbedtls_ct_bool_or(bad, mbedtls_ct_bool_and(in_padding, different)); + } + + /* If the padding is invalid, set the output length to 0 */ + *data_len = mbedtls_ct_if(bad, 0, input_len - padding_len); + + *invalid_padding = mbedtls_ct_size_if_else_0(bad, SIZE_MAX); + return 0; +} +#endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */ + +/* + * No padding: don't pad :) + * + * There is no add_padding function (check for NULL in mbedtls_cipher_finish) + * but a trivial get_padding function + */ +static int get_no_padding(unsigned char *input, size_t input_len, + size_t *data_len, size_t *invalid_padding) +{ + if (NULL == input || NULL == data_len) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + *data_len = input_len; + *invalid_padding = 0; + return 0; +} +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + +int mbedtls_cipher_finish_padded(mbedtls_cipher_context_t *ctx, + unsigned char *output, size_t *olen, + size_t *invalid_padding) +{ + if (ctx->cipher_info == NULL) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + *olen = 0; + *invalid_padding = 0; + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) + /* CBC mode requires padding so we make sure a call to + * mbedtls_cipher_set_padding_mode has been done successfully. */ + if (MBEDTLS_MODE_CBC == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) { + if (ctx->get_padding == NULL) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + } +#endif + + if (MBEDTLS_MODE_CFB == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode) || + MBEDTLS_MODE_OFB == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode) || + MBEDTLS_MODE_CTR == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode) || + MBEDTLS_MODE_GCM == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode) || + MBEDTLS_MODE_CCM_STAR_NO_TAG == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode) || + MBEDTLS_MODE_XTS == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode) || + MBEDTLS_MODE_STREAM == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) { + return 0; + } + + if ((MBEDTLS_CIPHER_CHACHA20 == ((mbedtls_cipher_type_t) ctx->cipher_info->type)) || + (MBEDTLS_CIPHER_CHACHA20_POLY1305 == ((mbedtls_cipher_type_t) ctx->cipher_info->type))) { + return 0; + } + + if (MBEDTLS_MODE_ECB == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) { + if (ctx->unprocessed_len != 0) { + return MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED; + } + + return 0; + } + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + if (MBEDTLS_MODE_CBC == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) { + int ret = 0; + + if (MBEDTLS_ENCRYPT == ctx->operation) { + /* check for 'no padding' mode */ + if (NULL == ctx->add_padding) { + if (0 != ctx->unprocessed_len) { + return MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED; + } + + return 0; + } + + ctx->add_padding(ctx->unprocessed_data, mbedtls_cipher_get_iv_size(ctx), + ctx->unprocessed_len); + } else if (mbedtls_cipher_get_block_size(ctx) != ctx->unprocessed_len) { + /* + * For decrypt operations, expect a full block, + * or an empty block if no padding + */ + if (NULL == ctx->add_padding && 0 == ctx->unprocessed_len) { + return 0; + } + + return MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED; + } + + /* cipher block */ + if (0 != (ret = mbedtls_cipher_get_base(ctx->cipher_info)->cbc_func(ctx->cipher_ctx, + ctx->operation, + mbedtls_cipher_get_block_size( + ctx), + ctx->iv, + ctx->unprocessed_data, + output))) { + return ret; + } + + /* Set output size for decryption */ + if (MBEDTLS_DECRYPT == ctx->operation) { + return ctx->get_padding(output, mbedtls_cipher_get_block_size(ctx), + olen, invalid_padding); + } + + /* Set output size for encryption */ + *olen = mbedtls_cipher_get_block_size(ctx); + return 0; + } +#else + ((void) output); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; +} + +int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx, + unsigned char *output, size_t *olen) +{ + size_t invalid_padding = 0; + int ret = mbedtls_cipher_finish_padded(ctx, output, olen, + &invalid_padding); + if (ret == 0) { + ret = mbedtls_ct_error_if_else_0(invalid_padding, + MBEDTLS_ERR_CIPHER_INVALID_PADDING); + } + return ret; +} + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) +int mbedtls_cipher_set_padding_mode(mbedtls_cipher_context_t *ctx, + mbedtls_cipher_padding_t mode) +{ + if (NULL == ctx->cipher_info || + MBEDTLS_MODE_CBC != ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + switch (mode) { + +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) + case MBEDTLS_PADDING_PKCS7: + ctx->add_padding = add_pkcs_padding; + ctx->get_padding = mbedtls_get_pkcs_padding; + break; +#endif + case MBEDTLS_PADDING_NONE: + ctx->add_padding = NULL; + ctx->get_padding = get_no_padding; + break; + + default: + return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + } + + return 0; +} +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +int mbedtls_cipher_write_tag(mbedtls_cipher_context_t *ctx, + unsigned char *tag, size_t tag_len) +{ + if (ctx->cipher_info == NULL) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + if (MBEDTLS_ENCRYPT != ctx->operation) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + +#if defined(MBEDTLS_GCM_C) + if (MBEDTLS_MODE_GCM == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) { + size_t output_length; + /* The code here doesn't yet support alternative implementations + * that can delay up to a block of output. */ + return mbedtls_gcm_finish((mbedtls_gcm_context *) ctx->cipher_ctx, + NULL, 0, &output_length, + tag, tag_len); + } +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + if (MBEDTLS_CIPHER_CHACHA20_POLY1305 == ((mbedtls_cipher_type_t) ctx->cipher_info->type)) { + /* Don't allow truncated MAC for Poly1305 */ + if (tag_len != 16U) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + return mbedtls_chachapoly_finish( + (mbedtls_chachapoly_context *) ctx->cipher_ctx, tag); + } +#endif + + return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; +} + +int mbedtls_cipher_check_tag(mbedtls_cipher_context_t *ctx, + const unsigned char *tag, size_t tag_len) +{ + unsigned char check_tag[16]; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if (ctx->cipher_info == NULL) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + if (MBEDTLS_DECRYPT != ctx->operation) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + /* Status to return on a non-authenticated algorithm. */ + ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + +#if defined(MBEDTLS_GCM_C) + if (MBEDTLS_MODE_GCM == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) { + size_t output_length; + /* The code here doesn't yet support alternative implementations + * that can delay up to a block of output. */ + + if (tag_len > sizeof(check_tag)) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + if (0 != (ret = mbedtls_gcm_finish( + (mbedtls_gcm_context *) ctx->cipher_ctx, + NULL, 0, &output_length, + check_tag, tag_len))) { + return ret; + } + + /* Check the tag in "constant-time" */ + if (mbedtls_ct_memcmp(tag, check_tag, tag_len) != 0) { + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + goto exit; + } + } +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CHACHAPOLY_C) + if (MBEDTLS_CIPHER_CHACHA20_POLY1305 == ((mbedtls_cipher_type_t) ctx->cipher_info->type)) { + /* Don't allow truncated MAC for Poly1305 */ + if (tag_len != sizeof(check_tag)) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + ret = mbedtls_chachapoly_finish( + (mbedtls_chachapoly_context *) ctx->cipher_ctx, check_tag); + if (ret != 0) { + return ret; + } + + /* Check the tag in "constant-time" */ + if (mbedtls_ct_memcmp(tag, check_tag, tag_len) != 0) { + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + goto exit; + } + } +#endif /* MBEDTLS_CHACHAPOLY_C */ + +exit: + mbedtls_platform_zeroize(check_tag, tag_len); + return ret; +} +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ + +/* + * Packet-oriented wrapper for non-AEAD modes + */ +int mbedtls_cipher_crypt(mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t finish_olen; + + if ((ret = mbedtls_cipher_set_iv(ctx, iv, iv_len)) != 0) { + return ret; + } + + if ((ret = mbedtls_cipher_reset(ctx)) != 0) { + return ret; + } + + if ((ret = mbedtls_cipher_update(ctx, input, ilen, + output, olen)) != 0) { + return ret; + } + + size_t invalid_padding = 0; + if ((ret = mbedtls_cipher_finish_padded(ctx, output + *olen, + &finish_olen, + &invalid_padding)) != 0) { + return ret; + } + *olen += finish_olen; + + ret = mbedtls_ct_error_if_else_0(invalid_padding, + MBEDTLS_ERR_CIPHER_INVALID_PADDING); + return ret; +} + +#if defined(MBEDTLS_CIPHER_MODE_AEAD) +/* + * Packet-oriented encryption for AEAD modes: internal function used by + * mbedtls_cipher_auth_encrypt_ext(). + */ +static int mbedtls_cipher_aead_encrypt(mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + unsigned char *tag, size_t tag_len) +{ + +#if defined(MBEDTLS_GCM_C) + if (MBEDTLS_MODE_GCM == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) { + *olen = ilen; + return mbedtls_gcm_crypt_and_tag(ctx->cipher_ctx, MBEDTLS_GCM_ENCRYPT, + ilen, iv, iv_len, ad, ad_len, + input, output, tag_len, tag); + } +#endif /* MBEDTLS_GCM_C */ +#if defined(MBEDTLS_CCM_C) + if (MBEDTLS_MODE_CCM == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) { + *olen = ilen; + return mbedtls_ccm_encrypt_and_tag(ctx->cipher_ctx, ilen, + iv, iv_len, ad, ad_len, input, output, + tag, tag_len); + } +#endif /* MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CHACHAPOLY_C) + if (MBEDTLS_CIPHER_CHACHA20_POLY1305 == ((mbedtls_cipher_type_t) ctx->cipher_info->type)) { + /* ChachaPoly has fixed length nonce and MAC (tag) */ + if ((iv_len != mbedtls_cipher_info_get_iv_size(ctx->cipher_info)) || + (tag_len != 16U)) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + *olen = ilen; + return mbedtls_chachapoly_encrypt_and_tag(ctx->cipher_ctx, + ilen, iv, ad, ad_len, input, output, tag); + } +#endif /* MBEDTLS_CHACHAPOLY_C */ + + return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; +} + +/* + * Packet-oriented encryption for AEAD modes: internal function used by + * mbedtls_cipher_auth_encrypt_ext(). + */ +static int mbedtls_cipher_aead_decrypt(mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + const unsigned char *tag, size_t tag_len) +{ + +#if defined(MBEDTLS_GCM_C) + if (MBEDTLS_MODE_GCM == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) { + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + *olen = ilen; + ret = mbedtls_gcm_auth_decrypt(ctx->cipher_ctx, ilen, + iv, iv_len, ad, ad_len, + tag, tag_len, input, output); + + if (ret == MBEDTLS_ERR_GCM_AUTH_FAILED) { + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + } + + return ret; + } +#endif /* MBEDTLS_GCM_C */ +#if defined(MBEDTLS_CCM_C) + if (MBEDTLS_MODE_CCM == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) { + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + *olen = ilen; + ret = mbedtls_ccm_auth_decrypt(ctx->cipher_ctx, ilen, + iv, iv_len, ad, ad_len, + input, output, tag, tag_len); + + if (ret == MBEDTLS_ERR_CCM_AUTH_FAILED) { + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + } + + return ret; + } +#endif /* MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CHACHAPOLY_C) + if (MBEDTLS_CIPHER_CHACHA20_POLY1305 == ((mbedtls_cipher_type_t) ctx->cipher_info->type)) { + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + /* ChachaPoly has fixed length nonce and MAC (tag) */ + if ((iv_len != mbedtls_cipher_info_get_iv_size(ctx->cipher_info)) || + (tag_len != 16U)) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + *olen = ilen; + ret = mbedtls_chachapoly_auth_decrypt(ctx->cipher_ctx, ilen, + iv, ad, ad_len, tag, input, output); + + if (ret == MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED) { + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + } + + return ret; + } +#endif /* MBEDTLS_CHACHAPOLY_C */ + + return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; +} +#endif /* MBEDTLS_CIPHER_MODE_AEAD */ + +#if defined(MBEDTLS_CIPHER_MODE_AEAD) +/* + * Packet-oriented encryption for AEAD: public function. + */ +int mbedtls_cipher_auth_encrypt_ext(mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t output_len, + size_t *olen, size_t tag_len) +{ + /* AEAD case: check length before passing on to shared function */ + if (output_len < ilen + tag_len) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + int ret = mbedtls_cipher_aead_encrypt(ctx, iv, iv_len, ad, ad_len, + input, ilen, output, olen, + output + ilen, tag_len); + *olen += tag_len; + return ret; +} + +/* + * Packet-oriented decryption for AEAD: public function. + */ +int mbedtls_cipher_auth_decrypt_ext(mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t output_len, + size_t *olen, size_t tag_len) +{ + /* AEAD case: check length before passing on to shared function */ + if (ilen < tag_len || output_len < ilen - tag_len) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + return mbedtls_cipher_aead_decrypt(ctx, iv, iv_len, ad, ad_len, + input, ilen - tag_len, output, olen, + input + ilen - tag_len, tag_len); +} +#endif /* MBEDTLS_CIPHER_MODE_AEAD */ + +#endif /* MBEDTLS_CIPHER_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/cipher_invasive.h b/tf-psa-crypto/drivers/builtin/src/cipher_invasive.h new file mode 100644 index 0000000000..a89cc0caa4 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/cipher_invasive.h @@ -0,0 +1,28 @@ +/** + * \file cipher_invasive.h + * + * \brief Cipher module: interfaces for invasive testing only. + * + * The interfaces in this file are intended for testing purposes only. + * They SHOULD NOT be made available in library integrations except when + * building the library for testing. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_CIPHER_INVASIVE_H +#define TF_PSA_CRYPTO_CIPHER_INVASIVE_H + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_CIPHER_C) + +MBEDTLS_STATIC_TESTABLE int mbedtls_get_pkcs_padding(unsigned char *input, + size_t input_len, + size_t *data_len, + size_t *invalid_padding); + +#endif + +#endif /* TF_PSA_CRYPTO_CIPHER_INVASIVE_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/cipher_wrap.c b/tf-psa-crypto/drivers/builtin/src/cipher_wrap.c new file mode 100644 index 0000000000..4d45d6f6f5 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/cipher_wrap.c @@ -0,0 +1,1937 @@ +/** + * \file cipher_wrap.c + * + * \brief Generic cipher wrapper for Mbed TLS + * + * \author Adriaan de Jong + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_CIPHER_C) + +#include "cipher_wrap.h" +#include "mbedtls/private/error_common.h" + +#if defined(MBEDTLS_CHACHAPOLY_C) +#include "mbedtls/private/chachapoly.h" +#endif + +#if defined(MBEDTLS_AES_C) +#include "mbedtls/private/aes.h" +#endif + +#if defined(MBEDTLS_CAMELLIA_C) +#include "mbedtls/private/camellia.h" +#endif + +#if defined(MBEDTLS_ARIA_C) +#include "mbedtls/private/aria.h" +#endif + +#if defined(MBEDTLS_CHACHA20_C) +#include "mbedtls/private/chacha20.h" +#endif + +#if defined(MBEDTLS_GCM_C) +#include "mbedtls/private/gcm.h" +#endif + +#if defined(MBEDTLS_CCM_C) +#include "mbedtls/private/ccm.h" +#endif + +#include "mbedtls/platform.h" + +enum mbedtls_cipher_base_index { +#if defined(MBEDTLS_AES_C) + MBEDTLS_CIPHER_BASE_INDEX_AES, +#endif +#if defined(MBEDTLS_ARIA_C) + MBEDTLS_CIPHER_BASE_INDEX_ARIA, +#endif +#if defined(MBEDTLS_CAMELLIA_C) + MBEDTLS_CIPHER_BASE_INDEX_CAMELLIA, +#endif +#if defined(MBEDTLS_CIPHER_HAVE_CCM_AES_VIA_LEGACY_OR_USE_PSA) + MBEDTLS_CIPHER_BASE_INDEX_CCM_AES, +#endif +#if defined(MBEDTLS_CCM_C) && defined(MBEDTLS_ARIA_C) + MBEDTLS_CIPHER_BASE_INDEX_CCM_ARIA, +#endif +#if defined(MBEDTLS_CCM_C) && defined(MBEDTLS_CAMELLIA_C) + MBEDTLS_CIPHER_BASE_INDEX_CCM_CAMELLIA, +#endif +#if defined(MBEDTLS_CHACHA20_C) + MBEDTLS_CIPHER_BASE_INDEX_CHACHA20_BASE, +#endif +#if defined(MBEDTLS_CHACHAPOLY_C) + MBEDTLS_CIPHER_BASE_INDEX_CHACHAPOLY_BASE, +#endif +#if defined(MBEDTLS_CIPHER_HAVE_GCM_AES_VIA_LEGACY_OR_USE_PSA) + MBEDTLS_CIPHER_BASE_INDEX_GCM_AES, +#endif +#if defined(MBEDTLS_GCM_C) && defined(MBEDTLS_ARIA_C) + MBEDTLS_CIPHER_BASE_INDEX_GCM_ARIA, +#endif +#if defined(MBEDTLS_GCM_C) && defined(MBEDTLS_CAMELLIA_C) + MBEDTLS_CIPHER_BASE_INDEX_GCM_CAMELLIA, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) && defined(MBEDTLS_AES_C) + MBEDTLS_CIPHER_BASE_INDEX_XTS_AES, +#endif + /* Prevent compile failure due to empty enum */ + MBEDTLS_CIPHER_BASE_PREVENT_EMPTY_ENUM +}; + +#if defined(MBEDTLS_GCM_C) && \ + (defined(MBEDTLS_CIPHER_HAVE_GCM_AES_VIA_LEGACY_OR_USE_PSA) || \ + defined(MBEDTLS_ARIA_C) || defined(MBEDTLS_CAMELLIA_C)) +/* shared by all GCM ciphers */ +static void *gcm_ctx_alloc(void) +{ + void *ctx = mbedtls_calloc(1, sizeof(mbedtls_gcm_context)); + + if (ctx != NULL) { + mbedtls_gcm_init((mbedtls_gcm_context *) ctx); + } + + return ctx; +} + +static void gcm_ctx_free(void *ctx) +{ + mbedtls_gcm_free(ctx); + mbedtls_free(ctx); +} +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) && \ + (defined(MBEDTLS_CIPHER_HAVE_CCM_AES_VIA_LEGACY_OR_USE_PSA) || \ + defined(MBEDTLS_ARIA_C) || defined(MBEDTLS_CAMELLIA_C)) +/* shared by all CCM ciphers */ +static void *ccm_ctx_alloc(void) +{ + void *ctx = mbedtls_calloc(1, sizeof(mbedtls_ccm_context)); + + if (ctx != NULL) { + mbedtls_ccm_init((mbedtls_ccm_context *) ctx); + } + + return ctx; +} + +static void ccm_ctx_free(void *ctx) +{ + mbedtls_ccm_free(ctx); + mbedtls_free(ctx); +} +#endif /* MBEDTLS_CCM_C */ + +#if defined(MBEDTLS_AES_C) + +static int aes_crypt_ecb_wrap(void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output) +{ + return mbedtls_aes_crypt_ecb((mbedtls_aes_context *) ctx, operation, input, output); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int aes_crypt_cbc_wrap(void *ctx, mbedtls_operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output) +{ + return mbedtls_aes_crypt_cbc((mbedtls_aes_context *) ctx, operation, length, iv, input, + output); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int aes_crypt_cfb128_wrap(void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output) +{ + return mbedtls_aes_crypt_cfb128((mbedtls_aes_context *) ctx, operation, length, iv_off, iv, + input, output); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) +static int aes_crypt_ofb_wrap(void *ctx, size_t length, size_t *iv_off, + unsigned char *iv, const unsigned char *input, unsigned char *output) +{ + return mbedtls_aes_crypt_ofb((mbedtls_aes_context *) ctx, length, iv_off, + iv, input, output); +} +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int aes_crypt_ctr_wrap(void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output) +{ + return mbedtls_aes_crypt_ctr((mbedtls_aes_context *) ctx, length, nc_off, nonce_counter, + stream_block, input, output); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +static int aes_crypt_xts_wrap(void *ctx, mbedtls_operation_t operation, + size_t length, + const unsigned char data_unit[16], + const unsigned char *input, + unsigned char *output) +{ + mbedtls_aes_xts_context *xts_ctx = ctx; + int mode; + + switch (operation) { + case MBEDTLS_ENCRYPT: + mode = MBEDTLS_AES_ENCRYPT; + break; + case MBEDTLS_DECRYPT: + mode = MBEDTLS_AES_DECRYPT; + break; + default: + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + return mbedtls_aes_crypt_xts(xts_ctx, mode, length, + data_unit, input, output); +} +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +static int aes_setkey_dec_wrap(void *ctx, const unsigned char *key, + unsigned int key_bitlen) +{ + return mbedtls_aes_setkey_dec((mbedtls_aes_context *) ctx, key, key_bitlen); +} +#endif + +static int aes_setkey_enc_wrap(void *ctx, const unsigned char *key, + unsigned int key_bitlen) +{ + return mbedtls_aes_setkey_enc((mbedtls_aes_context *) ctx, key, key_bitlen); +} + +static void *aes_ctx_alloc(void) +{ + mbedtls_aes_context *aes = mbedtls_calloc(1, sizeof(mbedtls_aes_context)); + + if (aes == NULL) { + return NULL; + } + + mbedtls_aes_init(aes); + + return aes; +} + +static void aes_ctx_free(void *ctx) +{ + mbedtls_aes_free((mbedtls_aes_context *) ctx); + mbedtls_free(ctx); +} + +static const mbedtls_cipher_base_t aes_info = { + MBEDTLS_CIPHER_ID_AES, + aes_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + aes_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + aes_crypt_cfb128_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + aes_crypt_ofb_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + aes_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + aes_setkey_enc_wrap, +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + aes_setkey_dec_wrap, +#endif + aes_ctx_alloc, + aes_ctx_free +}; + +static const mbedtls_cipher_info_t aes_128_ecb_info = { + "AES-128-ECB", + 16, + 0 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_ECB, + MBEDTLS_CIPHER_AES_128_ECB, + 0, + MBEDTLS_CIPHER_BASE_INDEX_AES +}; + +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) +static const mbedtls_cipher_info_t aes_192_ecb_info = { + "AES-192-ECB", + 16, + 0 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_ECB, + MBEDTLS_CIPHER_AES_192_ECB, + 0, + MBEDTLS_CIPHER_BASE_INDEX_AES +}; + +static const mbedtls_cipher_info_t aes_256_ecb_info = { + "AES-256-ECB", + 16, + 0 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_ECB, + MBEDTLS_CIPHER_AES_256_ECB, + 0, + MBEDTLS_CIPHER_BASE_INDEX_AES +}; +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t aes_128_cbc_info = { + "AES-128-CBC", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CBC, + MBEDTLS_CIPHER_AES_128_CBC, + 0, + MBEDTLS_CIPHER_BASE_INDEX_AES +}; + +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) +static const mbedtls_cipher_info_t aes_192_cbc_info = { + "AES-192-CBC", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CBC, + MBEDTLS_CIPHER_AES_192_CBC, + 0, + MBEDTLS_CIPHER_BASE_INDEX_AES +}; + +static const mbedtls_cipher_info_t aes_256_cbc_info = { + "AES-256-CBC", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CBC, + MBEDTLS_CIPHER_AES_256_CBC, + 0, + MBEDTLS_CIPHER_BASE_INDEX_AES +}; +#endif +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t aes_128_cfb128_info = { + "AES-128-CFB128", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CFB, + MBEDTLS_CIPHER_AES_128_CFB128, + 0, + MBEDTLS_CIPHER_BASE_INDEX_AES +}; + +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) +static const mbedtls_cipher_info_t aes_192_cfb128_info = { + "AES-192-CFB128", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CFB, + MBEDTLS_CIPHER_AES_192_CFB128, + 0, + MBEDTLS_CIPHER_BASE_INDEX_AES +}; + +static const mbedtls_cipher_info_t aes_256_cfb128_info = { + "AES-256-CFB128", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CFB, + MBEDTLS_CIPHER_AES_256_CFB128, + 0, + MBEDTLS_CIPHER_BASE_INDEX_AES +}; +#endif +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) +static const mbedtls_cipher_info_t aes_128_ofb_info = { + "AES-128-OFB", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_OFB, + MBEDTLS_CIPHER_AES_128_OFB, + 0, + MBEDTLS_CIPHER_BASE_INDEX_AES +}; + +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) +static const mbedtls_cipher_info_t aes_192_ofb_info = { + "AES-192-OFB", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_OFB, + MBEDTLS_CIPHER_AES_192_OFB, + 0, + MBEDTLS_CIPHER_BASE_INDEX_AES +}; + +static const mbedtls_cipher_info_t aes_256_ofb_info = { + "AES-256-OFB", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_OFB, + MBEDTLS_CIPHER_AES_256_OFB, + 0, + MBEDTLS_CIPHER_BASE_INDEX_AES +}; +#endif +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t aes_128_ctr_info = { + "AES-128-CTR", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CTR, + MBEDTLS_CIPHER_AES_128_CTR, + 0, + MBEDTLS_CIPHER_BASE_INDEX_AES +}; + +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) +static const mbedtls_cipher_info_t aes_192_ctr_info = { + "AES-192-CTR", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CTR, + MBEDTLS_CIPHER_AES_192_CTR, + 0, + MBEDTLS_CIPHER_BASE_INDEX_AES +}; + +static const mbedtls_cipher_info_t aes_256_ctr_info = { + "AES-256-CTR", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CTR, + MBEDTLS_CIPHER_AES_256_CTR, + 0, + MBEDTLS_CIPHER_BASE_INDEX_AES +}; +#endif +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +static int xts_aes_setkey_enc_wrap(void *ctx, const unsigned char *key, + unsigned int key_bitlen) +{ + mbedtls_aes_xts_context *xts_ctx = ctx; + return mbedtls_aes_xts_setkey_enc(xts_ctx, key, key_bitlen); +} + +static int xts_aes_setkey_dec_wrap(void *ctx, const unsigned char *key, + unsigned int key_bitlen) +{ + mbedtls_aes_xts_context *xts_ctx = ctx; + return mbedtls_aes_xts_setkey_dec(xts_ctx, key, key_bitlen); +} + +static void *xts_aes_ctx_alloc(void) +{ + mbedtls_aes_xts_context *xts_ctx = mbedtls_calloc(1, sizeof(*xts_ctx)); + + if (xts_ctx != NULL) { + mbedtls_aes_xts_init(xts_ctx); + } + + return xts_ctx; +} + +static void xts_aes_ctx_free(void *ctx) +{ + mbedtls_aes_xts_context *xts_ctx = ctx; + + if (xts_ctx == NULL) { + return; + } + + mbedtls_aes_xts_free(xts_ctx); + mbedtls_free(xts_ctx); +} + +static const mbedtls_cipher_base_t xts_aes_info = { + MBEDTLS_CIPHER_ID_AES, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + aes_crypt_xts_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + xts_aes_setkey_enc_wrap, + xts_aes_setkey_dec_wrap, + xts_aes_ctx_alloc, + xts_aes_ctx_free +}; + +static const mbedtls_cipher_info_t aes_128_xts_info = { + "AES-128-XTS", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_XTS, + MBEDTLS_CIPHER_AES_128_XTS, + 0, + MBEDTLS_CIPHER_BASE_INDEX_XTS_AES +}; + +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) +static const mbedtls_cipher_info_t aes_256_xts_info = { + "AES-256-XTS", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 512 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_XTS, + MBEDTLS_CIPHER_AES_256_XTS, + 0, + MBEDTLS_CIPHER_BASE_INDEX_XTS_AES +}; +#endif +#endif /* MBEDTLS_CIPHER_MODE_XTS */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_GCM_C) && defined(MBEDTLS_CCM_GCM_CAN_AES) +static int gcm_aes_setkey_wrap(void *ctx, const unsigned char *key, + unsigned int key_bitlen) +{ + return mbedtls_gcm_setkey((mbedtls_gcm_context *) ctx, MBEDTLS_CIPHER_ID_AES, + key, key_bitlen); +} +#endif /* MBEDTLS_GCM_C && MBEDTLS_CCM_GCM_CAN_AES */ + +#if defined(MBEDTLS_CIPHER_HAVE_GCM_AES_VIA_LEGACY_OR_USE_PSA) +static const mbedtls_cipher_base_t gcm_aes_info = { + MBEDTLS_CIPHER_ID_AES, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif +#if defined(MBEDTLS_GCM_C) + gcm_aes_setkey_wrap, +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + gcm_aes_setkey_wrap, +#endif + gcm_ctx_alloc, + gcm_ctx_free, +#else + NULL, + NULL, + NULL, + NULL, +#endif /* MBEDTLS_GCM_C */ +}; +#endif /* MBEDTLS_CIPHER_HAVE_GCM_AES_VIA_LEGACY_OR_USE_PSA */ + +#if defined(MBEDTLS_CIPHER_HAVE_GCM_AES_VIA_LEGACY_OR_USE_PSA) +static const mbedtls_cipher_info_t aes_128_gcm_info = { + "AES-128-GCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_GCM, + MBEDTLS_CIPHER_AES_128_GCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_GCM_AES +}; + +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) +static const mbedtls_cipher_info_t aes_192_gcm_info = { + "AES-192-GCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_GCM, + MBEDTLS_CIPHER_AES_192_GCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_GCM_AES +}; + +static const mbedtls_cipher_info_t aes_256_gcm_info = { + "AES-256-GCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_GCM, + MBEDTLS_CIPHER_AES_256_GCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_GCM_AES +}; +#endif +#endif /* MBEDTLS_CIPHER_HAVE_GCM_AES_VIA_LEGACY_OR_USE_PSA */ + +#if defined(MBEDTLS_CCM_C) && defined(MBEDTLS_CCM_GCM_CAN_AES) +static int ccm_aes_setkey_wrap(void *ctx, const unsigned char *key, + unsigned int key_bitlen) +{ + return mbedtls_ccm_setkey((mbedtls_ccm_context *) ctx, MBEDTLS_CIPHER_ID_AES, + key, key_bitlen); +} +#endif /* MBEDTLS_CCM_C && MBEDTLS_CCM_GCM_CAN_AES */ + +#if defined(MBEDTLS_CIPHER_HAVE_CCM_AES_VIA_LEGACY_OR_USE_PSA) +static const mbedtls_cipher_base_t ccm_aes_info = { + MBEDTLS_CIPHER_ID_AES, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif +#if defined(MBEDTLS_CCM_C) + ccm_aes_setkey_wrap, +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + ccm_aes_setkey_wrap, +#endif + ccm_ctx_alloc, + ccm_ctx_free, +#else + NULL, + NULL, + NULL, + NULL, +#endif +}; +#endif /* MBEDTLS_CIPHER_HAVE_CCM_AES_VIA_LEGACY_OR_USE_PSA */ + +#if defined(MBEDTLS_CIPHER_HAVE_CCM_AES_VIA_LEGACY_OR_USE_PSA) +static const mbedtls_cipher_info_t aes_128_ccm_info = { + "AES-128-CCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM, + MBEDTLS_CIPHER_AES_128_CCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_AES +}; + +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) +static const mbedtls_cipher_info_t aes_192_ccm_info = { + "AES-192-CCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM, + MBEDTLS_CIPHER_AES_192_CCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_AES +}; + +static const mbedtls_cipher_info_t aes_256_ccm_info = { + "AES-256-CCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM, + MBEDTLS_CIPHER_AES_256_CCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_AES +}; +#endif +#endif /* MBEDTLS_CIPHER_HAVE_CCM_AES_VIA_LEGACY_OR_USE_PSA */ + +#if defined(MBEDTLS_CIPHER_HAVE_CCM_STAR_NO_TAG_AES_VIA_LEGACY_OR_USE_PSA) +static const mbedtls_cipher_info_t aes_128_ccm_star_no_tag_info = { + "AES-128-CCM*-NO-TAG", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_AES_128_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_AES +}; + +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) +static const mbedtls_cipher_info_t aes_192_ccm_star_no_tag_info = { + "AES-192-CCM*-NO-TAG", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_AES_192_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_AES +}; + +static const mbedtls_cipher_info_t aes_256_ccm_star_no_tag_info = { + "AES-256-CCM*-NO-TAG", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_AES_256_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_AES +}; +#endif +#endif /* MBEDTLS_CIPHER_HAVE_CCM_STAR_NO_TAG_AES_VIA_LEGACY_OR_USE_PSA */ + + +#if defined(MBEDTLS_CAMELLIA_C) + +static int camellia_crypt_ecb_wrap(void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output) +{ + return mbedtls_camellia_crypt_ecb((mbedtls_camellia_context *) ctx, operation, input, + output); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int camellia_crypt_cbc_wrap(void *ctx, mbedtls_operation_t operation, + size_t length, unsigned char *iv, + const unsigned char *input, unsigned char *output) +{ + return mbedtls_camellia_crypt_cbc((mbedtls_camellia_context *) ctx, operation, length, iv, + input, output); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int camellia_crypt_cfb128_wrap(void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output) +{ + return mbedtls_camellia_crypt_cfb128((mbedtls_camellia_context *) ctx, operation, length, + iv_off, iv, input, output); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int camellia_crypt_ctr_wrap(void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output) +{ + return mbedtls_camellia_crypt_ctr((mbedtls_camellia_context *) ctx, length, nc_off, + nonce_counter, stream_block, input, output); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +static int camellia_setkey_dec_wrap(void *ctx, const unsigned char *key, + unsigned int key_bitlen) +{ + return mbedtls_camellia_setkey_dec((mbedtls_camellia_context *) ctx, key, key_bitlen); +} +#endif + +static int camellia_setkey_enc_wrap(void *ctx, const unsigned char *key, + unsigned int key_bitlen) +{ + return mbedtls_camellia_setkey_enc((mbedtls_camellia_context *) ctx, key, key_bitlen); +} + +static void *camellia_ctx_alloc(void) +{ + mbedtls_camellia_context *ctx; + ctx = mbedtls_calloc(1, sizeof(mbedtls_camellia_context)); + + if (ctx == NULL) { + return NULL; + } + + mbedtls_camellia_init(ctx); + + return ctx; +} + +static void camellia_ctx_free(void *ctx) +{ + mbedtls_camellia_free((mbedtls_camellia_context *) ctx); + mbedtls_free(ctx); +} + +static const mbedtls_cipher_base_t camellia_info = { + MBEDTLS_CIPHER_ID_CAMELLIA, + camellia_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + camellia_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + camellia_crypt_cfb128_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + camellia_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + camellia_setkey_enc_wrap, +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + camellia_setkey_dec_wrap, +#endif + camellia_ctx_alloc, + camellia_ctx_free +}; + +static const mbedtls_cipher_info_t camellia_128_ecb_info = { + "CAMELLIA-128-ECB", + 16, + 0 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_ECB, + MBEDTLS_CIPHER_CAMELLIA_128_ECB, + 0, + MBEDTLS_CIPHER_BASE_INDEX_CAMELLIA +}; + +static const mbedtls_cipher_info_t camellia_192_ecb_info = { + "CAMELLIA-192-ECB", + 16, + 0 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_ECB, + MBEDTLS_CIPHER_CAMELLIA_192_ECB, + 0, + MBEDTLS_CIPHER_BASE_INDEX_CAMELLIA +}; + +static const mbedtls_cipher_info_t camellia_256_ecb_info = { + "CAMELLIA-256-ECB", + 16, + 0 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_ECB, + MBEDTLS_CIPHER_CAMELLIA_256_ECB, + 0, + MBEDTLS_CIPHER_BASE_INDEX_CAMELLIA +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t camellia_128_cbc_info = { + "CAMELLIA-128-CBC", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CBC, + MBEDTLS_CIPHER_CAMELLIA_128_CBC, + 0, + MBEDTLS_CIPHER_BASE_INDEX_CAMELLIA +}; + +static const mbedtls_cipher_info_t camellia_192_cbc_info = { + "CAMELLIA-192-CBC", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CBC, + MBEDTLS_CIPHER_CAMELLIA_192_CBC, + 0, + MBEDTLS_CIPHER_BASE_INDEX_CAMELLIA +}; + +static const mbedtls_cipher_info_t camellia_256_cbc_info = { + "CAMELLIA-256-CBC", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CBC, + MBEDTLS_CIPHER_CAMELLIA_256_CBC, + 0, + MBEDTLS_CIPHER_BASE_INDEX_CAMELLIA +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t camellia_128_cfb128_info = { + "CAMELLIA-128-CFB128", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CFB, + MBEDTLS_CIPHER_CAMELLIA_128_CFB128, + 0, + MBEDTLS_CIPHER_BASE_INDEX_CAMELLIA +}; + +static const mbedtls_cipher_info_t camellia_192_cfb128_info = { + "CAMELLIA-192-CFB128", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CFB, + MBEDTLS_CIPHER_CAMELLIA_192_CFB128, + 0, + MBEDTLS_CIPHER_BASE_INDEX_CAMELLIA +}; + +static const mbedtls_cipher_info_t camellia_256_cfb128_info = { + "CAMELLIA-256-CFB128", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CFB, + MBEDTLS_CIPHER_CAMELLIA_256_CFB128, + 0, + MBEDTLS_CIPHER_BASE_INDEX_CAMELLIA +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t camellia_128_ctr_info = { + "CAMELLIA-128-CTR", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CTR, + MBEDTLS_CIPHER_CAMELLIA_128_CTR, + 0, + MBEDTLS_CIPHER_BASE_INDEX_CAMELLIA +}; + +static const mbedtls_cipher_info_t camellia_192_ctr_info = { + "CAMELLIA-192-CTR", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CTR, + MBEDTLS_CIPHER_CAMELLIA_192_CTR, + 0, + MBEDTLS_CIPHER_BASE_INDEX_CAMELLIA +}; + +static const mbedtls_cipher_info_t camellia_256_ctr_info = { + "CAMELLIA-256-CTR", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CTR, + MBEDTLS_CIPHER_CAMELLIA_256_CTR, + 0, + MBEDTLS_CIPHER_BASE_INDEX_CAMELLIA +}; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_GCM_C) +static int gcm_camellia_setkey_wrap(void *ctx, const unsigned char *key, + unsigned int key_bitlen) +{ + return mbedtls_gcm_setkey((mbedtls_gcm_context *) ctx, MBEDTLS_CIPHER_ID_CAMELLIA, + key, key_bitlen); +} + +static const mbedtls_cipher_base_t gcm_camellia_info = { + MBEDTLS_CIPHER_ID_CAMELLIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + gcm_camellia_setkey_wrap, +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + gcm_camellia_setkey_wrap, +#endif + gcm_ctx_alloc, + gcm_ctx_free, +}; + +static const mbedtls_cipher_info_t camellia_128_gcm_info = { + "CAMELLIA-128-GCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_GCM, + MBEDTLS_CIPHER_CAMELLIA_128_GCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_GCM_CAMELLIA +}; + +static const mbedtls_cipher_info_t camellia_192_gcm_info = { + "CAMELLIA-192-GCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_GCM, + MBEDTLS_CIPHER_CAMELLIA_192_GCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_GCM_CAMELLIA +}; + +static const mbedtls_cipher_info_t camellia_256_gcm_info = { + "CAMELLIA-256-GCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_GCM, + MBEDTLS_CIPHER_CAMELLIA_256_GCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_GCM_CAMELLIA +}; +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +static int ccm_camellia_setkey_wrap(void *ctx, const unsigned char *key, + unsigned int key_bitlen) +{ + return mbedtls_ccm_setkey((mbedtls_ccm_context *) ctx, MBEDTLS_CIPHER_ID_CAMELLIA, + key, key_bitlen); +} + +static const mbedtls_cipher_base_t ccm_camellia_info = { + MBEDTLS_CIPHER_ID_CAMELLIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + ccm_camellia_setkey_wrap, +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + ccm_camellia_setkey_wrap, +#endif + ccm_ctx_alloc, + ccm_ctx_free, +}; + +static const mbedtls_cipher_info_t camellia_128_ccm_info = { + "CAMELLIA-128-CCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM, + MBEDTLS_CIPHER_CAMELLIA_128_CCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_CAMELLIA +}; + +static const mbedtls_cipher_info_t camellia_192_ccm_info = { + "CAMELLIA-192-CCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM, + MBEDTLS_CIPHER_CAMELLIA_192_CCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_CAMELLIA +}; + +static const mbedtls_cipher_info_t camellia_256_ccm_info = { + "CAMELLIA-256-CCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM, + MBEDTLS_CIPHER_CAMELLIA_256_CCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_CAMELLIA +}; + +static const mbedtls_cipher_info_t camellia_128_ccm_star_no_tag_info = { + "CAMELLIA-128-CCM*-NO-TAG", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_CAMELLIA_128_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_CAMELLIA +}; + +static const mbedtls_cipher_info_t camellia_192_ccm_star_no_tag_info = { + "CAMELLIA-192-CCM*-NO-TAG", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_CAMELLIA_192_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_CAMELLIA +}; + +static const mbedtls_cipher_info_t camellia_256_ccm_star_no_tag_info = { + "CAMELLIA-256-CCM*-NO-TAG", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_CAMELLIA_256_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_CAMELLIA +}; +#endif /* MBEDTLS_CCM_C */ + +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_ARIA_C) + +static int aria_crypt_ecb_wrap(void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output) +{ + (void) operation; + return mbedtls_aria_crypt_ecb((mbedtls_aria_context *) ctx, input, + output); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int aria_crypt_cbc_wrap(void *ctx, mbedtls_operation_t operation, + size_t length, unsigned char *iv, + const unsigned char *input, unsigned char *output) +{ + return mbedtls_aria_crypt_cbc((mbedtls_aria_context *) ctx, operation, length, iv, + input, output); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int aria_crypt_cfb128_wrap(void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output) +{ + return mbedtls_aria_crypt_cfb128((mbedtls_aria_context *) ctx, operation, length, + iv_off, iv, input, output); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int aria_crypt_ctr_wrap(void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output) +{ + return mbedtls_aria_crypt_ctr((mbedtls_aria_context *) ctx, length, nc_off, + nonce_counter, stream_block, input, output); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) +static int aria_setkey_dec_wrap(void *ctx, const unsigned char *key, + unsigned int key_bitlen) +{ + return mbedtls_aria_setkey_dec((mbedtls_aria_context *) ctx, key, key_bitlen); +} +#endif + +static int aria_setkey_enc_wrap(void *ctx, const unsigned char *key, + unsigned int key_bitlen) +{ + return mbedtls_aria_setkey_enc((mbedtls_aria_context *) ctx, key, key_bitlen); +} + +static void *aria_ctx_alloc(void) +{ + mbedtls_aria_context *ctx; + ctx = mbedtls_calloc(1, sizeof(mbedtls_aria_context)); + + if (ctx == NULL) { + return NULL; + } + + mbedtls_aria_init(ctx); + + return ctx; +} + +static void aria_ctx_free(void *ctx) +{ + mbedtls_aria_free((mbedtls_aria_context *) ctx); + mbedtls_free(ctx); +} + +static const mbedtls_cipher_base_t aria_info = { + MBEDTLS_CIPHER_ID_ARIA, + aria_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + aria_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + aria_crypt_cfb128_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + aria_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + aria_setkey_enc_wrap, +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + aria_setkey_dec_wrap, +#endif + aria_ctx_alloc, + aria_ctx_free +}; + +static const mbedtls_cipher_info_t aria_128_ecb_info = { + "ARIA-128-ECB", + 16, + 0 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_ECB, + MBEDTLS_CIPHER_ARIA_128_ECB, + 0, + MBEDTLS_CIPHER_BASE_INDEX_ARIA +}; + +static const mbedtls_cipher_info_t aria_192_ecb_info = { + "ARIA-192-ECB", + 16, + 0 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_ECB, + MBEDTLS_CIPHER_ARIA_192_ECB, + 0, + MBEDTLS_CIPHER_BASE_INDEX_ARIA +}; + +static const mbedtls_cipher_info_t aria_256_ecb_info = { + "ARIA-256-ECB", + 16, + 0 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_ECB, + MBEDTLS_CIPHER_ARIA_256_ECB, + 0, + MBEDTLS_CIPHER_BASE_INDEX_ARIA +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t aria_128_cbc_info = { + "ARIA-128-CBC", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CBC, + MBEDTLS_CIPHER_ARIA_128_CBC, + 0, + MBEDTLS_CIPHER_BASE_INDEX_ARIA +}; + +static const mbedtls_cipher_info_t aria_192_cbc_info = { + "ARIA-192-CBC", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CBC, + MBEDTLS_CIPHER_ARIA_192_CBC, + 0, + MBEDTLS_CIPHER_BASE_INDEX_ARIA +}; + +static const mbedtls_cipher_info_t aria_256_cbc_info = { + "ARIA-256-CBC", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CBC, + MBEDTLS_CIPHER_ARIA_256_CBC, + 0, + MBEDTLS_CIPHER_BASE_INDEX_ARIA +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t aria_128_cfb128_info = { + "ARIA-128-CFB128", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CFB, + MBEDTLS_CIPHER_ARIA_128_CFB128, + 0, + MBEDTLS_CIPHER_BASE_INDEX_ARIA +}; + +static const mbedtls_cipher_info_t aria_192_cfb128_info = { + "ARIA-192-CFB128", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CFB, + MBEDTLS_CIPHER_ARIA_192_CFB128, + 0, + MBEDTLS_CIPHER_BASE_INDEX_ARIA +}; + +static const mbedtls_cipher_info_t aria_256_cfb128_info = { + "ARIA-256-CFB128", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CFB, + MBEDTLS_CIPHER_ARIA_256_CFB128, + 0, + MBEDTLS_CIPHER_BASE_INDEX_ARIA +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t aria_128_ctr_info = { + "ARIA-128-CTR", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CTR, + MBEDTLS_CIPHER_ARIA_128_CTR, + 0, + MBEDTLS_CIPHER_BASE_INDEX_ARIA +}; + +static const mbedtls_cipher_info_t aria_192_ctr_info = { + "ARIA-192-CTR", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CTR, + MBEDTLS_CIPHER_ARIA_192_CTR, + 0, + MBEDTLS_CIPHER_BASE_INDEX_ARIA +}; + +static const mbedtls_cipher_info_t aria_256_ctr_info = { + "ARIA-256-CTR", + 16, + 16 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CTR, + MBEDTLS_CIPHER_ARIA_256_CTR, + 0, + MBEDTLS_CIPHER_BASE_INDEX_ARIA +}; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_GCM_C) +static int gcm_aria_setkey_wrap(void *ctx, const unsigned char *key, + unsigned int key_bitlen) +{ + return mbedtls_gcm_setkey((mbedtls_gcm_context *) ctx, MBEDTLS_CIPHER_ID_ARIA, + key, key_bitlen); +} + +static const mbedtls_cipher_base_t gcm_aria_info = { + MBEDTLS_CIPHER_ID_ARIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + gcm_aria_setkey_wrap, +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + gcm_aria_setkey_wrap, +#endif + gcm_ctx_alloc, + gcm_ctx_free, +}; + +static const mbedtls_cipher_info_t aria_128_gcm_info = { + "ARIA-128-GCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_GCM, + MBEDTLS_CIPHER_ARIA_128_GCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_GCM_ARIA +}; + +static const mbedtls_cipher_info_t aria_192_gcm_info = { + "ARIA-192-GCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_GCM, + MBEDTLS_CIPHER_ARIA_192_GCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_GCM_ARIA +}; + +static const mbedtls_cipher_info_t aria_256_gcm_info = { + "ARIA-256-GCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_GCM, + MBEDTLS_CIPHER_ARIA_256_GCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_GCM_ARIA +}; +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +static int ccm_aria_setkey_wrap(void *ctx, const unsigned char *key, + unsigned int key_bitlen) +{ + return mbedtls_ccm_setkey((mbedtls_ccm_context *) ctx, MBEDTLS_CIPHER_ID_ARIA, + key, key_bitlen); +} + +static const mbedtls_cipher_base_t ccm_aria_info = { + MBEDTLS_CIPHER_ID_ARIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + ccm_aria_setkey_wrap, +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + ccm_aria_setkey_wrap, +#endif + ccm_ctx_alloc, + ccm_ctx_free, +}; + +static const mbedtls_cipher_info_t aria_128_ccm_info = { + "ARIA-128-CCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM, + MBEDTLS_CIPHER_ARIA_128_CCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_ARIA +}; + +static const mbedtls_cipher_info_t aria_192_ccm_info = { + "ARIA-192-CCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM, + MBEDTLS_CIPHER_ARIA_192_CCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_ARIA +}; + +static const mbedtls_cipher_info_t aria_256_ccm_info = { + "ARIA-256-CCM", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM, + MBEDTLS_CIPHER_ARIA_256_CCM, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_ARIA +}; + +static const mbedtls_cipher_info_t aria_128_ccm_star_no_tag_info = { + "ARIA-128-CCM*-NO-TAG", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 128 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_ARIA_128_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_ARIA +}; + +static const mbedtls_cipher_info_t aria_192_ccm_star_no_tag_info = { + "ARIA-192-CCM*-NO-TAG", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 192 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_ARIA_192_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_ARIA +}; + +static const mbedtls_cipher_info_t aria_256_ccm_star_no_tag_info = { + "ARIA-256-CCM*-NO-TAG", + 16, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_ARIA_256_CCM_STAR_NO_TAG, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + MBEDTLS_CIPHER_BASE_INDEX_CCM_ARIA +}; +#endif /* MBEDTLS_CCM_C */ + +#endif /* MBEDTLS_ARIA_C */ + +#if defined(MBEDTLS_CHACHA20_C) + +static int chacha20_setkey_wrap(void *ctx, const unsigned char *key, + unsigned int key_bitlen) +{ + if (key_bitlen != 256U) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + if (0 != mbedtls_chacha20_setkey((mbedtls_chacha20_context *) ctx, key)) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + return 0; +} + +static int chacha20_stream_wrap(void *ctx, size_t length, + const unsigned char *input, + unsigned char *output) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + ret = mbedtls_chacha20_update(ctx, length, input, output); + if (ret == MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + return ret; +} + +static void *chacha20_ctx_alloc(void) +{ + mbedtls_chacha20_context *ctx; + ctx = mbedtls_calloc(1, sizeof(mbedtls_chacha20_context)); + + if (ctx == NULL) { + return NULL; + } + + mbedtls_chacha20_init(ctx); + + return ctx; +} + +static void chacha20_ctx_free(void *ctx) +{ + mbedtls_chacha20_free((mbedtls_chacha20_context *) ctx); + mbedtls_free(ctx); +} + +static const mbedtls_cipher_base_t chacha20_base_info = { + MBEDTLS_CIPHER_ID_CHACHA20, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + chacha20_stream_wrap, +#endif + chacha20_setkey_wrap, +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + chacha20_setkey_wrap, +#endif + chacha20_ctx_alloc, + chacha20_ctx_free +}; +static const mbedtls_cipher_info_t chacha20_info = { + "CHACHA20", + 1, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_STREAM, + MBEDTLS_CIPHER_CHACHA20, + 0, + MBEDTLS_CIPHER_BASE_INDEX_CHACHA20_BASE +}; +#endif /* MBEDTLS_CHACHA20_C */ + +#if defined(MBEDTLS_CHACHAPOLY_C) + +static int chachapoly_setkey_wrap(void *ctx, + const unsigned char *key, + unsigned int key_bitlen) +{ + if (key_bitlen != 256U) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + if (0 != mbedtls_chachapoly_setkey((mbedtls_chachapoly_context *) ctx, key)) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + return 0; +} + +static void *chachapoly_ctx_alloc(void) +{ + mbedtls_chachapoly_context *ctx; + ctx = mbedtls_calloc(1, sizeof(mbedtls_chachapoly_context)); + + if (ctx == NULL) { + return NULL; + } + + mbedtls_chachapoly_init(ctx); + + return ctx; +} + +static void chachapoly_ctx_free(void *ctx) +{ + mbedtls_chachapoly_free((mbedtls_chachapoly_context *) ctx); + mbedtls_free(ctx); +} + +static const mbedtls_cipher_base_t chachapoly_base_info = { + MBEDTLS_CIPHER_ID_CHACHA20, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + chachapoly_setkey_wrap, +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + chachapoly_setkey_wrap, +#endif + chachapoly_ctx_alloc, + chachapoly_ctx_free +}; +static const mbedtls_cipher_info_t chachapoly_info = { + "CHACHA20-POLY1305", + 1, + 12 >> MBEDTLS_IV_SIZE_SHIFT, + 256 >> MBEDTLS_KEY_BITLEN_SHIFT, + MBEDTLS_MODE_CHACHAPOLY, + MBEDTLS_CIPHER_CHACHA20_POLY1305, + 0, + MBEDTLS_CIPHER_BASE_INDEX_CHACHAPOLY_BASE +}; +#endif /* MBEDTLS_CHACHAPOLY_C */ + +const mbedtls_cipher_definition_t mbedtls_cipher_definitions[] = +{ +#if defined(MBEDTLS_AES_C) + { MBEDTLS_CIPHER_AES_128_ECB, &aes_128_ecb_info }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { MBEDTLS_CIPHER_AES_192_ECB, &aes_192_ecb_info }, + { MBEDTLS_CIPHER_AES_256_ECB, &aes_256_ecb_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_AES_128_CBC, &aes_128_cbc_info }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { MBEDTLS_CIPHER_AES_192_CBC, &aes_192_cbc_info }, + { MBEDTLS_CIPHER_AES_256_CBC, &aes_256_cbc_info }, +#endif +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_AES_128_CFB128, &aes_128_cfb128_info }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { MBEDTLS_CIPHER_AES_192_CFB128, &aes_192_cfb128_info }, + { MBEDTLS_CIPHER_AES_256_CFB128, &aes_256_cfb128_info }, +#endif +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + { MBEDTLS_CIPHER_AES_128_OFB, &aes_128_ofb_info }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { MBEDTLS_CIPHER_AES_192_OFB, &aes_192_ofb_info }, + { MBEDTLS_CIPHER_AES_256_OFB, &aes_256_ofb_info }, +#endif +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_AES_128_CTR, &aes_128_ctr_info }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { MBEDTLS_CIPHER_AES_192_CTR, &aes_192_ctr_info }, + { MBEDTLS_CIPHER_AES_256_CTR, &aes_256_ctr_info }, +#endif +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + { MBEDTLS_CIPHER_AES_128_XTS, &aes_128_xts_info }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { MBEDTLS_CIPHER_AES_256_XTS, &aes_256_xts_info }, +#endif +#endif +#endif /* MBEDTLS_AES_C */ +#if defined(MBEDTLS_CIPHER_HAVE_GCM_AES_VIA_LEGACY_OR_USE_PSA) + { MBEDTLS_CIPHER_AES_128_GCM, &aes_128_gcm_info }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { MBEDTLS_CIPHER_AES_192_GCM, &aes_192_gcm_info }, + { MBEDTLS_CIPHER_AES_256_GCM, &aes_256_gcm_info }, +#endif +#endif +#if defined(MBEDTLS_CIPHER_HAVE_CCM_AES_VIA_LEGACY_OR_USE_PSA) + { MBEDTLS_CIPHER_AES_128_CCM, &aes_128_ccm_info }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { MBEDTLS_CIPHER_AES_192_CCM, &aes_192_ccm_info }, + { MBEDTLS_CIPHER_AES_256_CCM, &aes_256_ccm_info }, +#endif +#endif +#if defined(MBEDTLS_CIPHER_HAVE_CCM_STAR_NO_TAG_AES_VIA_LEGACY_OR_USE_PSA) + { MBEDTLS_CIPHER_AES_128_CCM_STAR_NO_TAG, &aes_128_ccm_star_no_tag_info }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { MBEDTLS_CIPHER_AES_192_CCM_STAR_NO_TAG, &aes_192_ccm_star_no_tag_info }, + { MBEDTLS_CIPHER_AES_256_CCM_STAR_NO_TAG, &aes_256_ccm_star_no_tag_info }, +#endif +#endif + +#if defined(MBEDTLS_CAMELLIA_C) + { MBEDTLS_CIPHER_CAMELLIA_128_ECB, &camellia_128_ecb_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_ECB, &camellia_192_ecb_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_ECB, &camellia_256_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_CAMELLIA_128_CBC, &camellia_128_cbc_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CBC, &camellia_192_cbc_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CBC, &camellia_256_cbc_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_CAMELLIA_128_CFB128, &camellia_128_cfb128_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CFB128, &camellia_192_cfb128_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CFB128, &camellia_256_cfb128_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_CAMELLIA_128_CTR, &camellia_128_ctr_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CTR, &camellia_192_ctr_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CTR, &camellia_256_ctr_info }, +#endif +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_CIPHER_CAMELLIA_128_GCM, &camellia_128_gcm_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_GCM, &camellia_192_gcm_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_GCM, &camellia_256_gcm_info }, +#endif +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_CIPHER_CAMELLIA_128_CCM, &camellia_128_ccm_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CCM, &camellia_192_ccm_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CCM, &camellia_256_ccm_info }, + { MBEDTLS_CIPHER_CAMELLIA_128_CCM_STAR_NO_TAG, &camellia_128_ccm_star_no_tag_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CCM_STAR_NO_TAG, &camellia_192_ccm_star_no_tag_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CCM_STAR_NO_TAG, &camellia_256_ccm_star_no_tag_info }, +#endif +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_ARIA_C) + { MBEDTLS_CIPHER_ARIA_128_ECB, &aria_128_ecb_info }, + { MBEDTLS_CIPHER_ARIA_192_ECB, &aria_192_ecb_info }, + { MBEDTLS_CIPHER_ARIA_256_ECB, &aria_256_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_ARIA_128_CBC, &aria_128_cbc_info }, + { MBEDTLS_CIPHER_ARIA_192_CBC, &aria_192_cbc_info }, + { MBEDTLS_CIPHER_ARIA_256_CBC, &aria_256_cbc_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_ARIA_128_CFB128, &aria_128_cfb128_info }, + { MBEDTLS_CIPHER_ARIA_192_CFB128, &aria_192_cfb128_info }, + { MBEDTLS_CIPHER_ARIA_256_CFB128, &aria_256_cfb128_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_ARIA_128_CTR, &aria_128_ctr_info }, + { MBEDTLS_CIPHER_ARIA_192_CTR, &aria_192_ctr_info }, + { MBEDTLS_CIPHER_ARIA_256_CTR, &aria_256_ctr_info }, +#endif +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_CIPHER_ARIA_128_GCM, &aria_128_gcm_info }, + { MBEDTLS_CIPHER_ARIA_192_GCM, &aria_192_gcm_info }, + { MBEDTLS_CIPHER_ARIA_256_GCM, &aria_256_gcm_info }, +#endif +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_CIPHER_ARIA_128_CCM, &aria_128_ccm_info }, + { MBEDTLS_CIPHER_ARIA_192_CCM, &aria_192_ccm_info }, + { MBEDTLS_CIPHER_ARIA_256_CCM, &aria_256_ccm_info }, + { MBEDTLS_CIPHER_ARIA_128_CCM_STAR_NO_TAG, &aria_128_ccm_star_no_tag_info }, + { MBEDTLS_CIPHER_ARIA_192_CCM_STAR_NO_TAG, &aria_192_ccm_star_no_tag_info }, + { MBEDTLS_CIPHER_ARIA_256_CCM_STAR_NO_TAG, &aria_256_ccm_star_no_tag_info }, +#endif +#endif /* MBEDTLS_ARIA_C */ + +#if defined(MBEDTLS_CHACHA20_C) + { MBEDTLS_CIPHER_CHACHA20, &chacha20_info }, +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + { MBEDTLS_CIPHER_CHACHA20_POLY1305, &chachapoly_info }, +#endif + + { MBEDTLS_CIPHER_NONE, NULL } +}; + +#define NUM_CIPHERS (sizeof(mbedtls_cipher_definitions) / \ + sizeof(mbedtls_cipher_definitions[0])) +int mbedtls_cipher_supported[NUM_CIPHERS]; + +const mbedtls_cipher_base_t * const mbedtls_cipher_base_lookup_table[] = { +#if defined(MBEDTLS_AES_C) + [MBEDTLS_CIPHER_BASE_INDEX_AES] = &aes_info, +#endif +#if defined(MBEDTLS_ARIA_C) + [MBEDTLS_CIPHER_BASE_INDEX_ARIA] = &aria_info, +#endif +#if defined(MBEDTLS_CAMELLIA_C) + [MBEDTLS_CIPHER_BASE_INDEX_CAMELLIA] = &camellia_info, +#endif +#if defined(MBEDTLS_CIPHER_HAVE_CCM_AES_VIA_LEGACY_OR_USE_PSA) + [MBEDTLS_CIPHER_BASE_INDEX_CCM_AES] = &ccm_aes_info, +#endif +#if defined(MBEDTLS_CCM_C) && defined(MBEDTLS_ARIA_C) + [MBEDTLS_CIPHER_BASE_INDEX_CCM_ARIA] = &ccm_aria_info, +#endif +#if defined(MBEDTLS_CCM_C) && defined(MBEDTLS_CAMELLIA_C) + [MBEDTLS_CIPHER_BASE_INDEX_CCM_CAMELLIA] = &ccm_camellia_info, +#endif +#if defined(MBEDTLS_CHACHA20_C) + [MBEDTLS_CIPHER_BASE_INDEX_CHACHA20_BASE] = &chacha20_base_info, +#endif +#if defined(MBEDTLS_CHACHAPOLY_C) + [MBEDTLS_CIPHER_BASE_INDEX_CHACHAPOLY_BASE] = &chachapoly_base_info, +#endif +#if defined(MBEDTLS_CIPHER_HAVE_GCM_AES_VIA_LEGACY_OR_USE_PSA) + [MBEDTLS_CIPHER_BASE_INDEX_GCM_AES] = &gcm_aes_info, +#endif +#if defined(MBEDTLS_GCM_C) && defined(MBEDTLS_ARIA_C) + [MBEDTLS_CIPHER_BASE_INDEX_GCM_ARIA] = &gcm_aria_info, +#endif +#if defined(MBEDTLS_GCM_C) && defined(MBEDTLS_CAMELLIA_C) + [MBEDTLS_CIPHER_BASE_INDEX_GCM_CAMELLIA] = &gcm_camellia_info, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) && defined(MBEDTLS_AES_C) + [MBEDTLS_CIPHER_BASE_INDEX_XTS_AES] = &xts_aes_info +#endif +}; + +#endif /* MBEDTLS_CIPHER_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/cipher_wrap.h b/tf-psa-crypto/drivers/builtin/src/cipher_wrap.h new file mode 100644 index 0000000000..0a90f839f3 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/cipher_wrap.h @@ -0,0 +1,173 @@ +/** + * \file cipher_wrap.h + * + * \brief Cipher wrappers. + * + * \author Adriaan de Jong + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_CIPHER_WRAP_H +#define TF_PSA_CRYPTO_CIPHER_WRAP_H + +#include "tf-psa-crypto/build_info.h" + +#include "mbedtls/private/cipher.h" + +#include "psa/crypto.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Support for GCM either through Mbed TLS SW implementation or PSA */ +#if defined(MBEDTLS_GCM_C) || defined(PSA_WANT_ALG_GCM) +#define MBEDTLS_CIPHER_HAVE_GCM_VIA_LEGACY_OR_USE_PSA +#endif + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_AES_C)) || \ + (defined(PSA_WANT_ALG_GCM) && defined(PSA_WANT_KEY_TYPE_AES)) +#define MBEDTLS_CIPHER_HAVE_GCM_AES_VIA_LEGACY_OR_USE_PSA +#endif + +#if defined(MBEDTLS_CCM_C) || \ + defined(PSA_WANT_ALG_CCM) +#define MBEDTLS_CIPHER_HAVE_CCM_VIA_LEGACY_OR_USE_PSA +#endif + +#if (defined(MBEDTLS_CCM_C) && defined(MBEDTLS_AES_C)) || \ + (defined(PSA_WANT_ALG_CCM) && defined(PSA_WANT_KEY_TYPE_AES)) +#define MBEDTLS_CIPHER_HAVE_CCM_AES_VIA_LEGACY_OR_USE_PSA +#endif + +#if defined(MBEDTLS_CCM_C) || \ + defined(PSA_WANT_ALG_CCM_STAR_NO_TAG) +#define MBEDTLS_CIPHER_HAVE_CCM_STAR_NO_TAG_VIA_LEGACY_OR_USE_PSA +#endif + +#if (defined(MBEDTLS_CCM_C) && defined(MBEDTLS_AES_C)) || \ + (defined(PSA_WANT_ALG_CCM_STAR_NO_TAG) && \ + defined(PSA_WANT_KEY_TYPE_AES)) +#define MBEDTLS_CIPHER_HAVE_CCM_STAR_NO_TAG_AES_VIA_LEGACY_OR_USE_PSA +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) || \ + defined(PSA_WANT_ALG_CHACHA20_POLY1305) +#define MBEDTLS_CIPHER_HAVE_CHACHAPOLY_VIA_LEGACY_OR_USE_PSA +#endif + +#if defined(MBEDTLS_CIPHER_HAVE_GCM_VIA_LEGACY_OR_USE_PSA) || \ + defined(MBEDTLS_CIPHER_HAVE_CCM_VIA_LEGACY_OR_USE_PSA) || \ + defined(MBEDTLS_CIPHER_HAVE_CCM_STAR_NO_TAG_VIA_LEGACY_OR_USE_PSA) || \ + defined(MBEDTLS_CIPHER_HAVE_CHACHAPOLY_VIA_LEGACY_OR_USE_PSA) +#define MBEDTLS_CIPHER_HAVE_SOME_AEAD_VIA_LEGACY_OR_USE_PSA +#endif + +/** + * Base cipher information. The non-mode specific functions and values. + */ +struct mbedtls_cipher_base_t { + /** Base Cipher type (e.g. MBEDTLS_CIPHER_ID_AES) */ + mbedtls_cipher_id_t cipher; + + /** Encrypt using ECB */ + int (*ecb_func)(void *ctx, mbedtls_operation_t mode, + const unsigned char *input, unsigned char *output); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /** Encrypt using CBC */ + int (*cbc_func)(void *ctx, mbedtls_operation_t mode, size_t length, + unsigned char *iv, const unsigned char *input, + unsigned char *output); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + /** Encrypt using CFB (Full length) */ + int (*cfb_func)(void *ctx, mbedtls_operation_t mode, size_t length, size_t *iv_off, + unsigned char *iv, const unsigned char *input, + unsigned char *output); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_OFB) + /** Encrypt using OFB (Full length) */ + int (*ofb_func)(void *ctx, size_t length, size_t *iv_off, + unsigned char *iv, + const unsigned char *input, + unsigned char *output); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + /** Encrypt using CTR */ + int (*ctr_func)(void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_XTS) + /** Encrypt or decrypt using XTS. */ + int (*xts_func)(void *ctx, mbedtls_operation_t mode, size_t length, + const unsigned char data_unit[16], + const unsigned char *input, unsigned char *output); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + /** Encrypt using STREAM */ + int (*stream_func)(void *ctx, size_t length, + const unsigned char *input, unsigned char *output); +#endif + + /** Set key for encryption purposes */ + int (*setkey_enc_func)(void *ctx, const unsigned char *key, + unsigned int key_bitlen); + +#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) + /** Set key for decryption purposes */ + int (*setkey_dec_func)(void *ctx, const unsigned char *key, + unsigned int key_bitlen); +#endif + + /** Allocate a new context */ + void * (*ctx_alloc_func)(void); + + /** Free the given context */ + void (*ctx_free_func)(void *ctx); + +}; + +typedef struct { + mbedtls_cipher_type_t type; + const mbedtls_cipher_info_t *info; +} mbedtls_cipher_definition_t; + +typedef enum { + MBEDTLS_CIPHER_PSA_KEY_UNSET = 0, + MBEDTLS_CIPHER_PSA_KEY_OWNED, /* Used for PSA-based cipher contexts which */ + /* use raw key material internally imported */ + /* as a volatile key, and which hence need */ + /* to destroy that key when the context is */ + /* freed. */ + MBEDTLS_CIPHER_PSA_KEY_NOT_OWNED, /* Used for PSA-based cipher contexts */ + /* which use a key provided by the */ + /* user, and which hence will not be */ + /* destroyed when the context is freed. */ +} mbedtls_cipher_psa_key_ownership; + +typedef struct { + psa_algorithm_t alg; + mbedtls_svc_key_id_t slot; + mbedtls_cipher_psa_key_ownership slot_state; +} mbedtls_cipher_context_psa; + +extern const mbedtls_cipher_definition_t mbedtls_cipher_definitions[]; + +extern int mbedtls_cipher_supported[]; + +extern const mbedtls_cipher_base_t * const mbedtls_cipher_base_lookup_table[]; + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_CIPHER_WRAP_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/cmac.c b/tf-psa-crypto/drivers/builtin/src/cmac.c new file mode 100644 index 0000000000..626cdf8920 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/cmac.c @@ -0,0 +1,911 @@ +/** + * \file cmac.c + * + * \brief NIST SP800-38B compliant CMAC implementation for AES and 3DES + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +/* + * References: + * + * - NIST SP 800-38B Recommendation for Block Cipher Modes of Operation: The + * CMAC Mode for Authentication + * http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38b.pdf + * + * - RFC 4493 - The AES-CMAC Algorithm + * https://tools.ietf.org/html/rfc4493 + * + * - RFC 4615 - The Advanced Encryption Standard-Cipher-based Message + * Authentication Code-Pseudo-Random Function-128 (AES-CMAC-PRF-128) + * Algorithm for the Internet Key Exchange Protocol (IKE) + * https://tools.ietf.org/html/rfc4615 + * + * Additional test vectors: ISO/IEC 9797-1 + * + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_CMAC_C) + +#include "mbedtls/private/cmac.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" +#include "mbedtls/platform.h" +#include "constant_time_internal.h" + +#include + +/* + * Multiplication by u in the Galois field of GF(2^n) + * + * As explained in NIST SP 800-38B, this can be computed: + * + * If MSB(p) = 0, then p = (p << 1) + * If MSB(p) = 1, then p = (p << 1) ^ R_n + * with R_64 = 0x1B and R_128 = 0x87 + * + * Input and output MUST NOT point to the same buffer + * Block size must be 8 bytes or 16 bytes - the block sizes for DES and AES. + */ +static int cmac_multiply_by_u(unsigned char *output, + const unsigned char *input, + size_t blocksize) +{ + const unsigned char R_128 = 0x87; + unsigned char R_n; + uint32_t overflow = 0x00; + int i; + + if (blocksize == MBEDTLS_AES_BLOCK_SIZE) { + R_n = R_128; + } else { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + for (i = (int) blocksize - 4; i >= 0; i -= 4) { + uint32_t i32 = MBEDTLS_GET_UINT32_BE(&input[i], 0); + uint32_t new_overflow = i32 >> 31; + i32 = (i32 << 1) | overflow; + MBEDTLS_PUT_UINT32_BE(i32, &output[i], 0); + overflow = new_overflow; + } + + R_n = (unsigned char) mbedtls_ct_uint_if_else_0(mbedtls_ct_bool(input[0] >> 7), R_n); + output[blocksize - 1] ^= R_n; + + return 0; +} + +/* + * Generate subkeys + * + * - as specified by RFC 4493, section 2.3 Subkey Generation Algorithm + */ +static int cmac_generate_subkeys(mbedtls_cipher_context_t *ctx, + unsigned char *K1, unsigned char *K2) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char L[MBEDTLS_CMAC_MAX_BLOCK_SIZE]; + size_t olen, block_size; + + mbedtls_platform_zeroize(L, sizeof(L)); + + block_size = mbedtls_cipher_info_get_block_size(ctx->cipher_info); + + /* Calculate Ek(0) */ + if ((ret = mbedtls_cipher_update(ctx, L, block_size, L, &olen)) != 0) { + goto exit; + } + + /* + * Generate K1 and K2 + */ + if ((ret = cmac_multiply_by_u(K1, L, block_size)) != 0) { + goto exit; + } + + if ((ret = cmac_multiply_by_u(K2, K1, block_size)) != 0) { + goto exit; + } + +exit: + mbedtls_platform_zeroize(L, sizeof(L)); + + return ret; +} + +/* + * Create padded last block from (partial) last block. + * + * We can't use the padding option from the cipher layer, as it only works for + * CBC and we use ECB mode, and anyway we need to XOR K1 or K2 in addition. + */ +static void cmac_pad(unsigned char padded_block[MBEDTLS_CMAC_MAX_BLOCK_SIZE], + size_t padded_block_len, + const unsigned char *last_block, + size_t last_block_len) +{ + size_t j; + + for (j = 0; j < padded_block_len; j++) { + if (j < last_block_len) { + padded_block[j] = last_block[j]; + } else if (j == last_block_len) { + padded_block[j] = 0x80; + } else { + padded_block[j] = 0x00; + } + } +} + +int mbedtls_cipher_cmac_starts(mbedtls_cipher_context_t *ctx, + const unsigned char *key, size_t keybits) +{ + mbedtls_cipher_type_t type; + mbedtls_cmac_context_t *cmac_ctx; + int retval; + + if (ctx == NULL || ctx->cipher_info == NULL || key == NULL) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + if ((retval = mbedtls_cipher_setkey(ctx, key, (int) keybits, + MBEDTLS_ENCRYPT)) != 0) { + return retval; + } + + type = mbedtls_cipher_info_get_type(ctx->cipher_info); + + switch (type) { + case MBEDTLS_CIPHER_AES_128_ECB: + case MBEDTLS_CIPHER_AES_192_ECB: + case MBEDTLS_CIPHER_AES_256_ECB: + break; + default: + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + /* Allocated and initialise in the cipher context memory for the CMAC + * context */ + cmac_ctx = mbedtls_calloc(1, sizeof(mbedtls_cmac_context_t)); + if (cmac_ctx == NULL) { + return MBEDTLS_ERR_CIPHER_ALLOC_FAILED; + } + + ctx->cmac_ctx = cmac_ctx; + + mbedtls_platform_zeroize(cmac_ctx->state, sizeof(cmac_ctx->state)); + + return 0; +} + +int mbedtls_cipher_cmac_update(mbedtls_cipher_context_t *ctx, + const unsigned char *input, size_t ilen) +{ + mbedtls_cmac_context_t *cmac_ctx; + unsigned char *state; + int ret = 0; + size_t n, j, olen, block_size; + + if (ctx == NULL || ctx->cipher_info == NULL || input == NULL || + ctx->cmac_ctx == NULL) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + cmac_ctx = ctx->cmac_ctx; + block_size = mbedtls_cipher_info_get_block_size(ctx->cipher_info); + state = ctx->cmac_ctx->state; + + /* Without the MBEDTLS_ASSUME below, gcc -O3 will generate a warning of the form + * error: writing 16 bytes into a region of size 0 [-Werror=stringop-overflow=] */ + MBEDTLS_ASSUME(block_size <= MBEDTLS_CMAC_MAX_BLOCK_SIZE); + + /* Is there data still to process from the last call, that's greater in + * size than a block? */ + if (cmac_ctx->unprocessed_len > 0 && + ilen > block_size - cmac_ctx->unprocessed_len) { + memcpy(&cmac_ctx->unprocessed_block[cmac_ctx->unprocessed_len], + input, + block_size - cmac_ctx->unprocessed_len); + + mbedtls_xor_no_simd(state, cmac_ctx->unprocessed_block, state, block_size); + + if ((ret = mbedtls_cipher_update(ctx, state, block_size, state, + &olen)) != 0) { + goto exit; + } + + input += block_size - cmac_ctx->unprocessed_len; + ilen -= block_size - cmac_ctx->unprocessed_len; + cmac_ctx->unprocessed_len = 0; + } + + /* n is the number of blocks including any final partial block */ + n = (ilen + block_size - 1) / block_size; + + /* Iterate across the input data in block sized chunks, excluding any + * final partial or complete block */ + for (j = 1; j < n; j++) { + mbedtls_xor_no_simd(state, input, state, block_size); + + if ((ret = mbedtls_cipher_update(ctx, state, block_size, state, + &olen)) != 0) { + goto exit; + } + + ilen -= block_size; + input += block_size; + } + + /* If there is data left over that wasn't aligned to a block */ + if (ilen > 0) { + memcpy(&cmac_ctx->unprocessed_block[cmac_ctx->unprocessed_len], + input, + ilen); + cmac_ctx->unprocessed_len += ilen; + } + +exit: + return ret; +} + +int mbedtls_cipher_cmac_finish(mbedtls_cipher_context_t *ctx, + unsigned char *output) +{ + mbedtls_cmac_context_t *cmac_ctx; + unsigned char *state, *last_block; + unsigned char K1[MBEDTLS_CMAC_MAX_BLOCK_SIZE]; + unsigned char K2[MBEDTLS_CMAC_MAX_BLOCK_SIZE]; + unsigned char M_last[MBEDTLS_CMAC_MAX_BLOCK_SIZE]; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t olen, block_size; + + if (ctx == NULL || ctx->cipher_info == NULL || ctx->cmac_ctx == NULL || + output == NULL) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + cmac_ctx = ctx->cmac_ctx; + block_size = mbedtls_cipher_info_get_block_size(ctx->cipher_info); + MBEDTLS_ASSUME(block_size <= MBEDTLS_CMAC_MAX_BLOCK_SIZE); // silence GCC warning + state = cmac_ctx->state; + + mbedtls_platform_zeroize(K1, sizeof(K1)); + mbedtls_platform_zeroize(K2, sizeof(K2)); + cmac_generate_subkeys(ctx, K1, K2); + + last_block = cmac_ctx->unprocessed_block; + + /* Calculate last block */ + if (cmac_ctx->unprocessed_len < block_size) { + cmac_pad(M_last, block_size, last_block, cmac_ctx->unprocessed_len); + mbedtls_xor(M_last, M_last, K2, block_size); + } else { + /* Last block is complete block */ + mbedtls_xor(M_last, last_block, K1, block_size); + } + + + mbedtls_xor(state, M_last, state, block_size); + if ((ret = mbedtls_cipher_update(ctx, state, block_size, state, + &olen)) != 0) { + goto exit; + } + + memcpy(output, state, block_size); + +exit: + /* Wipe the generated keys on the stack, and any other transients to avoid + * side channel leakage */ + mbedtls_platform_zeroize(K1, sizeof(K1)); + mbedtls_platform_zeroize(K2, sizeof(K2)); + + cmac_ctx->unprocessed_len = 0; + mbedtls_platform_zeroize(cmac_ctx->unprocessed_block, + sizeof(cmac_ctx->unprocessed_block)); + + mbedtls_platform_zeroize(state, MBEDTLS_CMAC_MAX_BLOCK_SIZE); + return ret; +} + +int mbedtls_cipher_cmac_reset(mbedtls_cipher_context_t *ctx) +{ + mbedtls_cmac_context_t *cmac_ctx; + + if (ctx == NULL || ctx->cipher_info == NULL || ctx->cmac_ctx == NULL) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + cmac_ctx = ctx->cmac_ctx; + + /* Reset the internal state */ + cmac_ctx->unprocessed_len = 0; + mbedtls_platform_zeroize(cmac_ctx->unprocessed_block, + sizeof(cmac_ctx->unprocessed_block)); + mbedtls_platform_zeroize(cmac_ctx->state, + sizeof(cmac_ctx->state)); + + return 0; +} + +int mbedtls_cipher_cmac(const mbedtls_cipher_info_t *cipher_info, + const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output) +{ + mbedtls_cipher_context_t ctx; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if (cipher_info == NULL || key == NULL || input == NULL || output == NULL) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + mbedtls_cipher_init(&ctx); + + if ((ret = mbedtls_cipher_setup(&ctx, cipher_info)) != 0) { + goto exit; + } + + ret = mbedtls_cipher_cmac_starts(&ctx, key, keylen); + if (ret != 0) { + goto exit; + } + + ret = mbedtls_cipher_cmac_update(&ctx, input, ilen); + if (ret != 0) { + goto exit; + } + + ret = mbedtls_cipher_cmac_finish(&ctx, output); + +exit: + mbedtls_cipher_free(&ctx); + + return ret; +} + +#if defined(MBEDTLS_AES_C) +/* + * Implementation of AES-CMAC-PRF-128 defined in RFC 4615 + */ +int mbedtls_aes_cmac_prf_128(const unsigned char *key, size_t key_length, + const unsigned char *input, size_t in_len, + unsigned char output[16]) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + const mbedtls_cipher_info_t *cipher_info; + unsigned char zero_key[MBEDTLS_AES_BLOCK_SIZE]; + unsigned char int_key[MBEDTLS_AES_BLOCK_SIZE]; + + if (key == NULL || input == NULL || output == NULL) { + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB); + if (cipher_info == NULL) { + /* Failing at this point must be due to a build issue */ + ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + goto exit; + } + + if (key_length == MBEDTLS_AES_BLOCK_SIZE) { + /* Use key as is */ + memcpy(int_key, key, MBEDTLS_AES_BLOCK_SIZE); + } else { + memset(zero_key, 0, MBEDTLS_AES_BLOCK_SIZE); + + ret = mbedtls_cipher_cmac(cipher_info, zero_key, 128, key, + key_length, int_key); + if (ret != 0) { + goto exit; + } + } + + ret = mbedtls_cipher_cmac(cipher_info, int_key, 128, input, in_len, + output); + +exit: + mbedtls_platform_zeroize(int_key, sizeof(int_key)); + + return ret; +} +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * CMAC test data for SP800-38B + * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/AES_CMAC.pdf + * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/TDES_CMAC.pdf + * + * AES-CMAC-PRF-128 test data from RFC 4615 + * https://tools.ietf.org/html/rfc4615#page-4 + */ + +#define NB_CMAC_TESTS_PER_KEY 4 +#define NB_PRF_TESTS 3 + +#if defined(MBEDTLS_AES_C) +/* All CMAC test inputs are truncated from the same 64 byte buffer. */ +static const unsigned char test_message[] = { + /* PT */ + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 +}; +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_AES_C) +/* Truncation point of message for AES CMAC tests */ +static const unsigned int aes_message_lengths[NB_CMAC_TESTS_PER_KEY] = { + /* Mlen */ + 0, + 16, + 20, + 64 +}; + +/* CMAC-AES128 Test Data */ +static const unsigned char aes_128_key[16] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c +}; +static const unsigned char aes_128_subkeys[2][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* K1 */ + 0xfb, 0xee, 0xd6, 0x18, 0x35, 0x71, 0x33, 0x66, + 0x7c, 0x85, 0xe0, 0x8f, 0x72, 0x36, 0xa8, 0xde + }, + { + /* K2 */ + 0xf7, 0xdd, 0xac, 0x30, 0x6a, 0xe2, 0x66, 0xcc, + 0xf9, 0x0b, 0xc1, 0x1e, 0xe4, 0x6d, 0x51, 0x3b + } +}; +static const unsigned char aes_128_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_AES_BLOCK_SIZE] = +{ + { + /* Example #1 */ + 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, + 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 + }, + { + /* Example #2 */ + 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, + 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c + }, + { + /* Example #3 */ + 0x7d, 0x85, 0x44, 0x9e, 0xa6, 0xea, 0x19, 0xc8, + 0x23, 0xa7, 0xbf, 0x78, 0x83, 0x7d, 0xfa, 0xde + }, + { + /* Example #4 */ + 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, + 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe + } +}; + +/* CMAC-AES192 Test Data */ +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) +static const unsigned char aes_192_key[24] = { + 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, + 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, + 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b +}; +static const unsigned char aes_192_subkeys[2][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* K1 */ + 0x44, 0x8a, 0x5b, 0x1c, 0x93, 0x51, 0x4b, 0x27, + 0x3e, 0xe6, 0x43, 0x9d, 0xd4, 0xda, 0xa2, 0x96 + }, + { + /* K2 */ + 0x89, 0x14, 0xb6, 0x39, 0x26, 0xa2, 0x96, 0x4e, + 0x7d, 0xcc, 0x87, 0x3b, 0xa9, 0xb5, 0x45, 0x2c + } +}; +static const unsigned char aes_192_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_AES_BLOCK_SIZE] = +{ + { + /* Example #1 */ + 0xd1, 0x7d, 0xdf, 0x46, 0xad, 0xaa, 0xcd, 0xe5, + 0x31, 0xca, 0xc4, 0x83, 0xde, 0x7a, 0x93, 0x67 + }, + { + /* Example #2 */ + 0x9e, 0x99, 0xa7, 0xbf, 0x31, 0xe7, 0x10, 0x90, + 0x06, 0x62, 0xf6, 0x5e, 0x61, 0x7c, 0x51, 0x84 + }, + { + /* Example #3 */ + 0x3d, 0x75, 0xc1, 0x94, 0xed, 0x96, 0x07, 0x04, + 0x44, 0xa9, 0xfa, 0x7e, 0xc7, 0x40, 0xec, 0xf8 + }, + { + /* Example #4 */ + 0xa1, 0xd5, 0xdf, 0x0e, 0xed, 0x79, 0x0f, 0x79, + 0x4d, 0x77, 0x58, 0x96, 0x59, 0xf3, 0x9a, 0x11 + } +}; +#endif /* !MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH */ + +/* CMAC-AES256 Test Data */ +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) +static const unsigned char aes_256_key[32] = { + 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 +}; +static const unsigned char aes_256_subkeys[2][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* K1 */ + 0xca, 0xd1, 0xed, 0x03, 0x29, 0x9e, 0xed, 0xac, + 0x2e, 0x9a, 0x99, 0x80, 0x86, 0x21, 0x50, 0x2f + }, + { + /* K2 */ + 0x95, 0xa3, 0xda, 0x06, 0x53, 0x3d, 0xdb, 0x58, + 0x5d, 0x35, 0x33, 0x01, 0x0c, 0x42, 0xa0, 0xd9 + } +}; +static const unsigned char aes_256_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_AES_BLOCK_SIZE] = +{ + { + /* Example #1 */ + 0x02, 0x89, 0x62, 0xf6, 0x1b, 0x7b, 0xf8, 0x9e, + 0xfc, 0x6b, 0x55, 0x1f, 0x46, 0x67, 0xd9, 0x83 + }, + { + /* Example #2 */ + 0x28, 0xa7, 0x02, 0x3f, 0x45, 0x2e, 0x8f, 0x82, + 0xbd, 0x4b, 0xf2, 0x8d, 0x8c, 0x37, 0xc3, 0x5c + }, + { + /* Example #3 */ + 0x15, 0x67, 0x27, 0xdc, 0x08, 0x78, 0x94, 0x4a, + 0x02, 0x3c, 0x1f, 0xe0, 0x3b, 0xad, 0x6d, 0x93 + }, + { + /* Example #4 */ + 0xe1, 0x99, 0x21, 0x90, 0x54, 0x9f, 0x6e, 0xd5, + 0x69, 0x6a, 0x2c, 0x05, 0x6c, 0x31, 0x54, 0x10 + } +}; +#endif /* !MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_AES_C) +/* AES AES-CMAC-PRF-128 Test Data */ +static const unsigned char PRFK[] = { + /* Key */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0xed, 0xcb +}; + +/* Sizes in bytes */ +static const size_t PRFKlen[NB_PRF_TESTS] = { + 18, + 16, + 10 +}; + +/* Message */ +static const unsigned char PRFM[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13 +}; + +static const unsigned char PRFT[NB_PRF_TESTS][16] = { + { + 0x84, 0xa3, 0x48, 0xa4, 0xa4, 0x5d, 0x23, 0x5b, + 0xab, 0xff, 0xfc, 0x0d, 0x2b, 0x4d, 0xa0, 0x9a + }, + { + 0x98, 0x0a, 0xe8, 0x7b, 0x5f, 0x4c, 0x9c, 0x52, + 0x14, 0xf5, 0xb6, 0xa8, 0x45, 0x5e, 0x4c, 0x2d + }, + { + 0x29, 0x0d, 0x9e, 0x11, 0x2e, 0xdb, 0x09, 0xee, + 0x14, 0x1f, 0xcf, 0x64, 0xc0, 0xb7, 0x2f, 0x3d + } +}; +#endif /* MBEDTLS_AES_C */ + +static int cmac_test_subkeys(int verbose, + const char *testname, + const unsigned char *key, + int keybits, + const unsigned char *subkeys, + mbedtls_cipher_type_t cipher_type, + int block_size, + int num_tests) +{ + int i, ret = 0; + mbedtls_cipher_context_t ctx; + const mbedtls_cipher_info_t *cipher_info; + unsigned char K1[MBEDTLS_CMAC_MAX_BLOCK_SIZE]; + unsigned char K2[MBEDTLS_CMAC_MAX_BLOCK_SIZE]; + + cipher_info = mbedtls_cipher_info_from_type(cipher_type); + if (cipher_info == NULL) { + /* Failing at this point must be due to a build issue */ + return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + } + + for (i = 0; i < num_tests; i++) { + if (verbose != 0) { + mbedtls_printf(" %s CMAC subkey #%d: ", testname, i + 1); + } + + mbedtls_cipher_init(&ctx); + + if ((ret = mbedtls_cipher_setup(&ctx, cipher_info)) != 0) { + if (verbose != 0) { + mbedtls_printf("test execution failed\n"); + } + + goto cleanup; + } + + if ((ret = mbedtls_cipher_setkey(&ctx, key, keybits, + MBEDTLS_ENCRYPT)) != 0) { + /* When CMAC is implemented by an alternative implementation, or + * the underlying primitive itself is implemented alternatively, + * AES-192 may be unavailable. This should not cause the selftest + * function to fail. */ + if ((ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED || + ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE) && + cipher_type == MBEDTLS_CIPHER_AES_192_ECB) { + if (verbose != 0) { + mbedtls_printf("skipped\n"); + } + goto next_test; + } + + if (verbose != 0) { + mbedtls_printf("test execution failed\n"); + } + + goto cleanup; + } + + ret = cmac_generate_subkeys(&ctx, K1, K2); + if (ret != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + goto cleanup; + } + + if ((ret = memcmp(K1, subkeys, block_size)) != 0 || + (ret = memcmp(K2, &subkeys[block_size], block_size)) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + goto cleanup; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + +next_test: + mbedtls_cipher_free(&ctx); + } + + ret = 0; + goto exit; + +cleanup: + mbedtls_cipher_free(&ctx); + +exit: + return ret; +} + +static int cmac_test_wth_cipher(int verbose, + const char *testname, + const unsigned char *key, + int keybits, + const unsigned char *messages, + const unsigned int message_lengths[4], + const unsigned char *expected_result, + mbedtls_cipher_type_t cipher_type, + int block_size, + int num_tests) +{ + const mbedtls_cipher_info_t *cipher_info; + int i, ret = 0; + unsigned char output[MBEDTLS_CMAC_MAX_BLOCK_SIZE]; + + cipher_info = mbedtls_cipher_info_from_type(cipher_type); + if (cipher_info == NULL) { + /* Failing at this point must be due to a build issue */ + ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + goto exit; + } + + for (i = 0; i < num_tests; i++) { + if (verbose != 0) { + mbedtls_printf(" %s CMAC #%d: ", testname, i + 1); + } + + if ((ret = mbedtls_cipher_cmac(cipher_info, key, keybits, messages, + message_lengths[i], output)) != 0) { + /* When CMAC is implemented by an alternative implementation, or + * the underlying primitive itself is implemented alternatively, + * AES-192 and/or 3DES may be unavailable. This should not cause + * the selftest function to fail. */ + if ((ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED || + ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE) && + (cipher_type == MBEDTLS_CIPHER_AES_192_ECB)) { + if (verbose != 0) { + mbedtls_printf("skipped\n"); + } + continue; + } + + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + goto exit; + } + + if ((ret = memcmp(output, &expected_result[i * block_size], block_size)) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + goto exit; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + ret = 0; + +exit: + return ret; +} + +#if defined(MBEDTLS_AES_C) +static int test_aes128_cmac_prf(int verbose) +{ + int i; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char output[MBEDTLS_AES_BLOCK_SIZE]; + + for (i = 0; i < NB_PRF_TESTS; i++) { + mbedtls_printf(" AES CMAC 128 PRF #%d: ", i); + ret = mbedtls_aes_cmac_prf_128(PRFK, PRFKlen[i], PRFM, 20, output); + if (ret != 0 || + memcmp(output, PRFT[i], MBEDTLS_AES_BLOCK_SIZE) != 0) { + + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + return ret; + } else if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + return ret; +} +#endif /* MBEDTLS_AES_C */ + +int mbedtls_cmac_self_test(int verbose) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + +#if defined(MBEDTLS_AES_C) + /* AES-128 */ + if ((ret = cmac_test_subkeys(verbose, + "AES 128", + aes_128_key, + 128, + (const unsigned char *) aes_128_subkeys, + MBEDTLS_CIPHER_AES_128_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY)) != 0) { + return ret; + } + + if ((ret = cmac_test_wth_cipher(verbose, + "AES 128", + aes_128_key, + 128, + test_message, + aes_message_lengths, + (const unsigned char *) aes_128_expected_result, + MBEDTLS_CIPHER_AES_128_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY)) != 0) { + return ret; + } + + /* AES-192 */ +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + if ((ret = cmac_test_subkeys(verbose, + "AES 192", + aes_192_key, + 192, + (const unsigned char *) aes_192_subkeys, + MBEDTLS_CIPHER_AES_192_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY)) != 0) { + return ret; + } + + if ((ret = cmac_test_wth_cipher(verbose, + "AES 192", + aes_192_key, + 192, + test_message, + aes_message_lengths, + (const unsigned char *) aes_192_expected_result, + MBEDTLS_CIPHER_AES_192_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY)) != 0) { + return ret; + } +#endif /* !MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH */ + + /* AES-256 */ +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + if ((ret = cmac_test_subkeys(verbose, + "AES 256", + aes_256_key, + 256, + (const unsigned char *) aes_256_subkeys, + MBEDTLS_CIPHER_AES_256_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY)) != 0) { + return ret; + } + + if ((ret = cmac_test_wth_cipher(verbose, + "AES 256", + aes_256_key, + 256, + test_message, + aes_message_lengths, + (const unsigned char *) aes_256_expected_result, + MBEDTLS_CIPHER_AES_256_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY)) != 0) { + return ret; + } +#endif /* !MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH */ +#endif /* MBEDTLS_AES_C */ + + +#if defined(MBEDTLS_AES_C) + if ((ret = test_aes128_cmac_prf(verbose)) != 0) { + return ret; + } +#endif /* MBEDTLS_AES_C */ + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + return 0; +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CMAC_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/ctr.h b/tf-psa-crypto/drivers/builtin/src/ctr.h new file mode 100644 index 0000000000..69be68ea03 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/ctr.h @@ -0,0 +1,35 @@ +/** + * \file ctr.h + * + * \brief This file contains common functionality for counter algorithms. + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_CTR_H +#define TF_PSA_CRYPTO_CTR_H + +#include "tf_psa_crypto_common.h" + +/** + * \brief Increment a big-endian 16-byte value. + * This is quite performance-sensitive for AES-CTR and CTR-DRBG. + * + * \param n A 16-byte value to be incremented. + */ +static inline void mbedtls_ctr_increment_counter(uint8_t n[16]) +{ + // The 32-bit version seems to perform about the same as a 64-bit version + // on 64-bit architectures, so no need to define a 64-bit version. + for (int i = 3;; i--) { + uint32_t x = MBEDTLS_GET_UINT32_BE(n, i << 2); + x += 1; + MBEDTLS_PUT_UINT32_BE(x, n, i << 2); + if (x != 0 || i == 0) { + break; + } + } +} + +#endif /* TF_PSA_CRYPTO_CTR_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/ctr_drbg.c b/tf-psa-crypto/drivers/builtin/src/ctr_drbg.c new file mode 100644 index 0000000000..b359df73d8 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/ctr_drbg.c @@ -0,0 +1,1017 @@ +/* + * CTR_DRBG implementation based on AES-256 (NIST SP 800-90) + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +/* + * The NIST SP 800-90 DRBGs are described in the following publication. + * + * https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-90r.pdf + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_CTR_DRBG_C) + +#include "ctr.h" +#include "mbedtls/private/ctr_drbg.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#include +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +/* Using error translation functions from PSA to MbedTLS */ +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) +#include "psa_util_internal.h" +#endif + +#include "mbedtls/platform.h" + +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) +static psa_status_t ctr_drbg_setup_psa_context(mbedtls_ctr_drbg_psa_context *psa_ctx, + unsigned char *key, size_t key_len) +{ + psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT; + psa_status_t status; + + psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&key_attr, PSA_ALG_ECB_NO_PADDING); + psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES); + status = psa_import_key(&key_attr, key, key_len, &psa_ctx->key_id); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_cipher_encrypt_setup(&psa_ctx->operation, psa_ctx->key_id, PSA_ALG_ECB_NO_PADDING); + if (status != PSA_SUCCESS) { + goto exit; + } + +exit: + psa_reset_key_attributes(&key_attr); + return status; +} + +static void ctr_drbg_destroy_psa_contex(mbedtls_ctr_drbg_psa_context *psa_ctx) +{ + psa_cipher_abort(&psa_ctx->operation); + psa_destroy_key(psa_ctx->key_id); + + psa_ctx->operation = psa_cipher_operation_init(); + psa_ctx->key_id = MBEDTLS_SVC_KEY_ID_INIT; +} +#endif + +/* + * CTR_DRBG context initialization + */ +void mbedtls_ctr_drbg_init(mbedtls_ctr_drbg_context *ctx) +{ + memset(ctx, 0, sizeof(mbedtls_ctr_drbg_context)); +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) + ctx->psa_ctx.key_id = MBEDTLS_SVC_KEY_ID_INIT; + ctx->psa_ctx.operation = psa_cipher_operation_init(); +#else + mbedtls_aes_init(&ctx->aes_ctx); +#endif + /* Indicate that the entropy nonce length is not set explicitly. + * See mbedtls_ctr_drbg_set_nonce_len(). */ + ctx->reseed_counter = -1; + + ctx->reseed_interval = MBEDTLS_PSA_RNG_RESEED_INTERVAL; +} + +/* + * This function resets CTR_DRBG context to the state immediately + * after initial call of mbedtls_ctr_drbg_init(). + */ +void mbedtls_ctr_drbg_free(mbedtls_ctr_drbg_context *ctx) +{ + if (ctx == NULL) { + return; + } + +#if defined(MBEDTLS_THREADING_C) + /* The mutex is initialized iff f_entropy is set. */ + if (ctx->f_entropy != NULL) { + mbedtls_mutex_free(&ctx->mutex); + } +#endif +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) + ctr_drbg_destroy_psa_contex(&ctx->psa_ctx); +#else + mbedtls_aes_free(&ctx->aes_ctx); +#endif + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ctr_drbg_context)); + ctx->reseed_interval = MBEDTLS_PSA_RNG_RESEED_INTERVAL; + ctx->reseed_counter = -1; +} + +void mbedtls_ctr_drbg_set_prediction_resistance(mbedtls_ctr_drbg_context *ctx, + int resistance) +{ + ctx->prediction_resistance = resistance; +} + +void mbedtls_ctr_drbg_set_entropy_len(mbedtls_ctr_drbg_context *ctx, + size_t len) +{ + ctx->entropy_len = len; +} + +int mbedtls_ctr_drbg_set_nonce_len(mbedtls_ctr_drbg_context *ctx, + size_t len) +{ + /* If mbedtls_ctr_drbg_seed() has already been called, it's + * too late. Return the error code that's closest to making sense. */ + if (ctx->f_entropy != NULL) { + return MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED; + } + + if (len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) { + return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG; + } + + /* This shouldn't be an issue because + * MBEDTLS_CTR_DRBG_MAX_SEED_INPUT < INT_MAX in any sensible + * configuration, but make sure anyway. */ + if (len > INT_MAX) { + return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG; + } + + /* For backward compatibility with Mbed TLS <= 2.19, store the + * entropy nonce length in a field that already exists, but isn't + * used until after the initial seeding. */ + /* Due to the capping of len above, the value fits in an int. */ + ctx->reseed_counter = (int) len; + return 0; +} + +void mbedtls_ctr_drbg_set_reseed_interval(mbedtls_ctr_drbg_context *ctx, + int interval) +{ + ctx->reseed_interval = interval; +} + +static int block_cipher_df(unsigned char *output, + const unsigned char *data, size_t data_len) +{ + unsigned char buf[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + + MBEDTLS_CTR_DRBG_BLOCKSIZE + 16]; + unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN]; + unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE]; + unsigned char chain[MBEDTLS_CTR_DRBG_BLOCKSIZE]; + unsigned char *p, *iv; + int ret = 0; +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) + psa_status_t status; + size_t tmp_len; + mbedtls_ctr_drbg_psa_context psa_ctx; + + psa_ctx.key_id = MBEDTLS_SVC_KEY_ID_INIT; + psa_ctx.operation = psa_cipher_operation_init(); +#else + mbedtls_aes_context aes_ctx; +#endif + + int i, j; + size_t buf_len, use_len; + + if (data_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) { + return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG; + } + + memset(buf, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + + MBEDTLS_CTR_DRBG_BLOCKSIZE + 16); + + /* + * Construct IV (16 bytes) and S in buffer + * IV = Counter (in 32-bits) padded to 16 with zeroes + * S = Length input string (in 32-bits) || Length of output (in 32-bits) || + * data || 0x80 + * (Total is padded to a multiple of 16-bytes with zeroes) + */ + p = buf + MBEDTLS_CTR_DRBG_BLOCKSIZE; + MBEDTLS_PUT_UINT32_BE(data_len, p, 0); + p += 4 + 3; + *p++ = MBEDTLS_CTR_DRBG_SEEDLEN; + memcpy(p, data, data_len); + p[data_len] = 0x80; + + buf_len = MBEDTLS_CTR_DRBG_BLOCKSIZE + 8 + data_len + 1; + + for (i = 0; i < MBEDTLS_CTR_DRBG_KEYSIZE; i++) { + key[i] = i; + } + +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) + status = ctr_drbg_setup_psa_context(&psa_ctx, key, sizeof(key)); + if (status != PSA_SUCCESS) { + ret = psa_generic_status_to_mbedtls(status); + goto exit; + } +#else + mbedtls_aes_init(&aes_ctx); + + if ((ret = mbedtls_aes_setkey_enc(&aes_ctx, key, + MBEDTLS_CTR_DRBG_KEYBITS)) != 0) { + goto exit; + } +#endif + + /* + * Reduce data to MBEDTLS_CTR_DRBG_SEEDLEN bytes of data + */ + for (j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE) { + p = buf; + memset(chain, 0, MBEDTLS_CTR_DRBG_BLOCKSIZE); + use_len = buf_len; + + while (use_len > 0) { + mbedtls_xor(chain, chain, p, MBEDTLS_CTR_DRBG_BLOCKSIZE); + p += MBEDTLS_CTR_DRBG_BLOCKSIZE; + use_len -= (use_len >= MBEDTLS_CTR_DRBG_BLOCKSIZE) ? + MBEDTLS_CTR_DRBG_BLOCKSIZE : use_len; + +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) + status = psa_cipher_update(&psa_ctx.operation, chain, MBEDTLS_CTR_DRBG_BLOCKSIZE, + chain, MBEDTLS_CTR_DRBG_BLOCKSIZE, &tmp_len); + if (status != PSA_SUCCESS) { + ret = psa_generic_status_to_mbedtls(status); + goto exit; + } +#else + if ((ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, + chain, chain)) != 0) { + goto exit; + } +#endif + } + + memcpy(tmp + j, chain, MBEDTLS_CTR_DRBG_BLOCKSIZE); + + /* + * Update IV + */ + buf[3]++; + } + + /* + * Do final encryption with reduced data + */ +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) + ctr_drbg_destroy_psa_contex(&psa_ctx); + + status = ctr_drbg_setup_psa_context(&psa_ctx, tmp, MBEDTLS_CTR_DRBG_KEYSIZE); + if (status != PSA_SUCCESS) { + ret = psa_generic_status_to_mbedtls(status); + goto exit; + } +#else + if ((ret = mbedtls_aes_setkey_enc(&aes_ctx, tmp, + MBEDTLS_CTR_DRBG_KEYBITS)) != 0) { + goto exit; + } +#endif + iv = tmp + MBEDTLS_CTR_DRBG_KEYSIZE; + p = output; + + for (j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE) { +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) + status = psa_cipher_update(&psa_ctx.operation, iv, MBEDTLS_CTR_DRBG_BLOCKSIZE, + iv, MBEDTLS_CTR_DRBG_BLOCKSIZE, &tmp_len); + if (status != PSA_SUCCESS) { + ret = psa_generic_status_to_mbedtls(status); + goto exit; + } +#else + if ((ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, + iv, iv)) != 0) { + goto exit; + } +#endif + memcpy(p, iv, MBEDTLS_CTR_DRBG_BLOCKSIZE); + p += MBEDTLS_CTR_DRBG_BLOCKSIZE; + } +exit: +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) + ctr_drbg_destroy_psa_contex(&psa_ctx); +#else + mbedtls_aes_free(&aes_ctx); +#endif + /* + * tidy up the stack + */ + mbedtls_platform_zeroize(buf, sizeof(buf)); + mbedtls_platform_zeroize(tmp, sizeof(tmp)); + mbedtls_platform_zeroize(key, sizeof(key)); + mbedtls_platform_zeroize(chain, sizeof(chain)); + if (0 != ret) { + /* + * wipe partial seed from memory + */ + mbedtls_platform_zeroize(output, MBEDTLS_CTR_DRBG_SEEDLEN); + } + + return ret; +} + +/* CTR_DRBG_Update (SP 800-90A §10.2.1.2) + * ctr_drbg_update_internal(ctx, provided_data) + * implements + * CTR_DRBG_Update(provided_data, Key, V) + * with inputs and outputs + * ctx->aes_ctx = Key + * ctx->counter = V + */ +static int ctr_drbg_update_internal(mbedtls_ctr_drbg_context *ctx, + const unsigned char data[MBEDTLS_CTR_DRBG_SEEDLEN]) +{ + unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN]; + unsigned char *p = tmp; + int j; + int ret = 0; +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) + psa_status_t status; + size_t tmp_len; +#endif + + memset(tmp, 0, MBEDTLS_CTR_DRBG_SEEDLEN); + + for (j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE) { + /* + * Increase counter + */ + mbedtls_ctr_increment_counter(ctx->counter); + + /* + * Crypt counter block + */ +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) + status = psa_cipher_update(&ctx->psa_ctx.operation, ctx->counter, sizeof(ctx->counter), + p, MBEDTLS_CTR_DRBG_BLOCKSIZE, &tmp_len); + if (status != PSA_SUCCESS) { + ret = psa_generic_status_to_mbedtls(status); + goto exit; + } +#else + if ((ret = mbedtls_aes_crypt_ecb(&ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, + ctx->counter, p)) != 0) { + goto exit; + } +#endif + + p += MBEDTLS_CTR_DRBG_BLOCKSIZE; + } + + mbedtls_xor(tmp, tmp, data, MBEDTLS_CTR_DRBG_SEEDLEN); + + /* + * Update key and counter + */ +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) + ctr_drbg_destroy_psa_contex(&ctx->psa_ctx); + + status = ctr_drbg_setup_psa_context(&ctx->psa_ctx, tmp, MBEDTLS_CTR_DRBG_KEYSIZE); + if (status != PSA_SUCCESS) { + ret = psa_generic_status_to_mbedtls(status); + goto exit; + } +#else + if ((ret = mbedtls_aes_setkey_enc(&ctx->aes_ctx, tmp, + MBEDTLS_CTR_DRBG_KEYBITS)) != 0) { + goto exit; + } +#endif + memcpy(ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE, + MBEDTLS_CTR_DRBG_BLOCKSIZE); + +exit: + mbedtls_platform_zeroize(tmp, sizeof(tmp)); + return ret; +} + +/* CTR_DRBG_Instantiate with derivation function (SP 800-90A §10.2.1.3.2) + * mbedtls_ctr_drbg_update(ctx, additional, add_len) + * implements + * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string, + * security_strength) -> initial_working_state + * with inputs + * ctx->counter = all-bits-0 + * ctx->aes_ctx = context from all-bits-0 key + * additional[:add_len] = entropy_input || nonce || personalization_string + * and with outputs + * ctx = initial_working_state + */ +int mbedtls_ctr_drbg_update(mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, + size_t add_len) +{ + unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN]; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if (add_len == 0) { + return 0; + } + + if ((ret = block_cipher_df(add_input, additional, add_len)) != 0) { + goto exit; + } + if ((ret = ctr_drbg_update_internal(ctx, add_input)) != 0) { + goto exit; + } + +exit: + mbedtls_platform_zeroize(add_input, sizeof(add_input)); + return ret; +} + +/* CTR_DRBG_Reseed with derivation function (SP 800-90A §10.2.1.4.2) + * mbedtls_ctr_drbg_reseed(ctx, additional, len, nonce_len) + * implements + * CTR_DRBG_Reseed(working_state, entropy_input, additional_input) + * -> new_working_state + * with inputs + * ctx contains working_state + * additional[:len] = additional_input + * and entropy_input comes from calling ctx->f_entropy + * for (ctx->entropy_len + nonce_len) bytes + * and with output + * ctx contains new_working_state + */ +static int mbedtls_ctr_drbg_reseed_internal(mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, + size_t len, + size_t nonce_len) +{ + unsigned char seed[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT]; + size_t seedlen = 0; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if (ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) { + return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG; + } + if (nonce_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len) { + return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG; + } + if (len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len - nonce_len) { + return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG; + } + + memset(seed, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT); + + /* Gather entropy_len bytes of entropy to seed state. */ + if (0 != ctx->f_entropy(ctx->p_entropy, seed, ctx->entropy_len)) { + return MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED; + } + seedlen += ctx->entropy_len; + + /* Gather entropy for a nonce if requested. */ + if (nonce_len != 0) { + if (0 != ctx->f_entropy(ctx->p_entropy, seed + seedlen, nonce_len)) { + return MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED; + } + seedlen += nonce_len; + } + + /* Add additional data if provided. */ + if (additional != NULL && len != 0) { + memcpy(seed + seedlen, additional, len); + seedlen += len; + } + + /* Reduce to 384 bits. */ + if ((ret = block_cipher_df(seed, seed, seedlen)) != 0) { + goto exit; + } + + /* Update state. */ + if ((ret = ctr_drbg_update_internal(ctx, seed)) != 0) { + goto exit; + } + ctx->reseed_counter = 0; + +exit: + mbedtls_platform_zeroize(seed, sizeof(seed)); + return ret; +} + +int mbedtls_ctr_drbg_reseed(mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t len) +{ + return mbedtls_ctr_drbg_reseed_internal(ctx, additional, len, 0); +} + +/* Return a "good" nonce length for CTR_DRBG. The chosen nonce length + * is sufficient to achieve the maximum security strength given the key + * size and entropy length. If there is enough entropy in the initial + * call to the entropy function to serve as both the entropy input and + * the nonce, don't make a second call to get a nonce. */ +static size_t good_nonce_len(size_t entropy_len) +{ + if (entropy_len >= MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2) { + return 0; + } else { + return (entropy_len + 1) / 2; + } +} + +/* CTR_DRBG_Instantiate with derivation function (SP 800-90A §10.2.1.3.2) + * mbedtls_ctr_drbg_seed(ctx, f_entropy, p_entropy, custom, len) + * implements + * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string, + * security_strength) -> initial_working_state + * with inputs + * custom[:len] = nonce || personalization_string + * where entropy_input comes from f_entropy for ctx->entropy_len bytes + * and with outputs + * ctx = initial_working_state + */ +int mbedtls_ctr_drbg_seed(mbedtls_ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE]; + size_t nonce_len; + + memset(key, 0, MBEDTLS_CTR_DRBG_KEYSIZE); + + /* The mutex is initialized iff f_entropy is set. */ +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init(&ctx->mutex); +#endif + + ctx->f_entropy = f_entropy; + ctx->p_entropy = p_entropy; + + if (ctx->entropy_len == 0) { + ctx->entropy_len = MBEDTLS_CTR_DRBG_ENTROPY_LEN; + } + /* ctx->reseed_counter contains the desired amount of entropy to + * grab for a nonce (see mbedtls_ctr_drbg_set_nonce_len()). + * If it's -1, indicating that the entropy nonce length was not set + * explicitly, use a sufficiently large nonce for security. */ + nonce_len = (ctx->reseed_counter >= 0 ? + (size_t) ctx->reseed_counter : + good_nonce_len(ctx->entropy_len)); + + /* Initialize with an empty key. */ +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) + psa_status_t status; + + status = ctr_drbg_setup_psa_context(&ctx->psa_ctx, key, MBEDTLS_CTR_DRBG_KEYSIZE); + if (status != PSA_SUCCESS) { + ret = psa_generic_status_to_mbedtls(status); + return status; + } +#else + if ((ret = mbedtls_aes_setkey_enc(&ctx->aes_ctx, key, + MBEDTLS_CTR_DRBG_KEYBITS)) != 0) { + return ret; + } +#endif + + /* Do the initial seeding. */ + if ((ret = mbedtls_ctr_drbg_reseed_internal(ctx, custom, len, + nonce_len)) != 0) { + return ret; + } + return 0; +} + +/* CTR_DRBG_Generate with derivation function (SP 800-90A §10.2.1.5.2) + * mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, additional, add_len) + * implements + * CTR_DRBG_Reseed(working_state, entropy_input, additional[:add_len]) + * -> working_state_after_reseed + * if required, then + * CTR_DRBG_Generate(working_state_after_reseed, + * requested_number_of_bits, additional_input) + * -> status, returned_bits, new_working_state + * with inputs + * ctx contains working_state + * requested_number_of_bits = 8 * output_len + * additional[:add_len] = additional_input + * and entropy_input comes from calling ctx->f_entropy + * and with outputs + * status = SUCCESS (this function does the reseed internally) + * returned_bits = output[:output_len] + * ctx contains new_working_state + */ +int mbedtls_ctr_drbg_random_with_add(void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, size_t add_len) +{ + int ret = 0; + mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng; + unsigned char *p = output; + struct { + unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN]; + unsigned char tmp[MBEDTLS_CTR_DRBG_BLOCKSIZE]; + } locals; + size_t use_len; + + if (output_len > MBEDTLS_CTR_DRBG_MAX_REQUEST) { + return MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG; + } + + if (add_len > MBEDTLS_CTR_DRBG_MAX_INPUT) { + return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG; + } + + memset(locals.add_input, 0, MBEDTLS_CTR_DRBG_SEEDLEN); + + if (ctx->reseed_counter >= ctx->reseed_interval || + ctx->prediction_resistance) { + if ((ret = mbedtls_ctr_drbg_reseed(ctx, additional, add_len)) != 0) { + return ret; + } + add_len = 0; + } + + if (add_len > 0) { + if ((ret = block_cipher_df(locals.add_input, additional, add_len)) != 0) { + goto exit; + } + if ((ret = ctr_drbg_update_internal(ctx, locals.add_input)) != 0) { + goto exit; + } + } + + while (output_len > 0) { + /* + * Increase counter (treat it as a 128-bit big-endian integer). + */ + mbedtls_ctr_increment_counter(ctx->counter); + + /* + * Crypt counter block + */ +#if defined(MBEDTLS_CTR_DRBG_USE_PSA_CRYPTO) + psa_status_t status; + size_t tmp_len; + + status = psa_cipher_update(&ctx->psa_ctx.operation, ctx->counter, sizeof(ctx->counter), + locals.tmp, MBEDTLS_CTR_DRBG_BLOCKSIZE, &tmp_len); + if (status != PSA_SUCCESS) { + ret = psa_generic_status_to_mbedtls(status); + goto exit; + } +#else + if ((ret = mbedtls_aes_crypt_ecb(&ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, + ctx->counter, locals.tmp)) != 0) { + goto exit; + } +#endif + + use_len = (output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE) + ? MBEDTLS_CTR_DRBG_BLOCKSIZE : output_len; + /* + * Copy random block to destination + */ + memcpy(p, locals.tmp, use_len); + p += use_len; + output_len -= use_len; + } + + if ((ret = ctr_drbg_update_internal(ctx, locals.add_input)) != 0) { + goto exit; + } + + ctx->reseed_counter++; + +exit: + mbedtls_platform_zeroize(&locals, sizeof(locals)); + return ret; +} + +int mbedtls_ctr_drbg_random(void *p_rng, unsigned char *output, + size_t output_len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng; + +#if defined(MBEDTLS_THREADING_C) + if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) { + return ret; + } +#endif + + ret = mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, NULL, 0); + +#if defined(MBEDTLS_THREADING_C) + if (mbedtls_mutex_unlock(&ctx->mutex) != 0) { + return MBEDTLS_ERR_THREADING_MUTEX_ERROR; + } +#endif + + return ret; +} + +#if defined(MBEDTLS_FS_IO) +int mbedtls_ctr_drbg_write_seed_file(mbedtls_ctr_drbg_context *ctx, + const char *path) +{ + int ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; + FILE *f; + unsigned char buf[MBEDTLS_CTR_DRBG_MAX_INPUT]; + + if ((f = fopen(path, "wb")) == NULL) { + return MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; + } + + /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ + mbedtls_setbuf(f, NULL); + + if ((ret = mbedtls_ctr_drbg_random(ctx, buf, + MBEDTLS_CTR_DRBG_MAX_INPUT)) != 0) { + goto exit; + } + + if (fwrite(buf, 1, MBEDTLS_CTR_DRBG_MAX_INPUT, f) != + MBEDTLS_CTR_DRBG_MAX_INPUT) { + ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; + } else { + ret = 0; + } + +exit: + mbedtls_platform_zeroize(buf, sizeof(buf)); + + fclose(f); + return ret; +} + +int mbedtls_ctr_drbg_update_seed_file(mbedtls_ctr_drbg_context *ctx, + const char *path) +{ + int ret = 0; + FILE *f = NULL; + size_t n; + unsigned char buf[MBEDTLS_CTR_DRBG_MAX_INPUT]; + unsigned char c; + + if ((f = fopen(path, "rb")) == NULL) { + return MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; + } + + /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ + mbedtls_setbuf(f, NULL); + + n = fread(buf, 1, sizeof(buf), f); + if (fread(&c, 1, 1, f) != 0) { + ret = MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG; + goto exit; + } + if (n == 0 || ferror(f)) { + ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; + goto exit; + } + fclose(f); + f = NULL; + + ret = mbedtls_ctr_drbg_update(ctx, buf, n); + +exit: + mbedtls_platform_zeroize(buf, sizeof(buf)); + if (f != NULL) { + fclose(f); + } + if (ret != 0) { + return ret; + } + return mbedtls_ctr_drbg_write_seed_file(ctx, path); +} +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_SELF_TEST) + +/* The CTR_DRBG NIST test vectors used here are available at + * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/drbg/drbgtestvectors.zip + * + * The parameters used to derive the test data are: + * + * [AES-128 use df] + * [PredictionResistance = True/False] + * [EntropyInputLen = 128] + * [NonceLen = 64] + * [PersonalizationStringLen = 128] + * [AdditionalInputLen = 0] + * [ReturnedBitsLen = 512] + * + * [AES-256 use df] + * [PredictionResistance = True/False] + * [EntropyInputLen = 256] + * [NonceLen = 128] + * [PersonalizationStringLen = 256] + * [AdditionalInputLen = 0] + * [ReturnedBitsLen = 512] + * + */ + +#if defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY) +static const unsigned char entropy_source_pr[] = +{ 0x04, 0xd9, 0x49, 0xa6, 0xdc, 0xe8, 0x6e, 0xbb, + 0xf1, 0x08, 0x77, 0x2b, 0x9e, 0x08, 0xca, 0x92, + 0x65, 0x16, 0xda, 0x99, 0xa2, 0x59, 0xf3, 0xe8, + 0x38, 0x7e, 0x3f, 0x6b, 0x51, 0x70, 0x7b, 0x20, + 0xec, 0x53, 0xd0, 0x66, 0xc3, 0x0f, 0xe3, 0xb0, + 0xe0, 0x86, 0xa6, 0xaa, 0x5f, 0x72, 0x2f, 0xad, + 0xf7, 0xef, 0x06, 0xb8, 0xd6, 0x9c, 0x9d, 0xe8 }; + +static const unsigned char entropy_source_nopr[] = +{ 0x07, 0x0d, 0x59, 0x63, 0x98, 0x73, 0xa5, 0x45, + 0x27, 0x38, 0x22, 0x7b, 0x76, 0x85, 0xd1, 0xa9, + 0x74, 0x18, 0x1f, 0x3c, 0x22, 0xf6, 0x49, 0x20, + 0x4a, 0x47, 0xc2, 0xf3, 0x85, 0x16, 0xb4, 0x6f, + 0x00, 0x2e, 0x71, 0xda, 0xed, 0x16, 0x9b, 0x5c }; + +static const unsigned char pers_pr[] = +{ 0xbf, 0xa4, 0x9a, 0x8f, 0x7b, 0xd8, 0xb1, 0x7a, + 0x9d, 0xfa, 0x45, 0xed, 0x21, 0x52, 0xb3, 0xad }; + +static const unsigned char pers_nopr[] = +{ 0x4e, 0x61, 0x79, 0xd4, 0xc2, 0x72, 0xa1, 0x4c, + 0xf1, 0x3d, 0xf6, 0x5e, 0xa3, 0xa6, 0xe5, 0x0f }; + +static const unsigned char result_pr[] = +{ 0xc9, 0x0a, 0xaf, 0x85, 0x89, 0x71, 0x44, 0x66, + 0x4f, 0x25, 0x0b, 0x2b, 0xde, 0xd8, 0xfa, 0xff, + 0x52, 0x5a, 0x1b, 0x32, 0x5e, 0x41, 0x7a, 0x10, + 0x1f, 0xef, 0x1e, 0x62, 0x23, 0xe9, 0x20, 0x30, + 0xc9, 0x0d, 0xad, 0x69, 0xb4, 0x9c, 0x5b, 0xf4, + 0x87, 0x42, 0xd5, 0xae, 0x5e, 0x5e, 0x43, 0xcc, + 0xd9, 0xfd, 0x0b, 0x93, 0x4a, 0xe3, 0xd4, 0x06, + 0x37, 0x36, 0x0f, 0x3f, 0x72, 0x82, 0x0c, 0xcf }; + +static const unsigned char result_nopr[] = +{ 0x31, 0xc9, 0x91, 0x09, 0xf8, 0xc5, 0x10, 0x13, + 0x3c, 0xd3, 0x96, 0xf9, 0xbc, 0x2c, 0x12, 0xc0, + 0x7c, 0xc1, 0x61, 0x5f, 0xa3, 0x09, 0x99, 0xaf, + 0xd7, 0xf2, 0x36, 0xfd, 0x40, 0x1a, 0x8b, 0xf2, + 0x33, 0x38, 0xee, 0x1d, 0x03, 0x5f, 0x83, 0xb7, + 0xa2, 0x53, 0xdc, 0xee, 0x18, 0xfc, 0xa7, 0xf2, + 0xee, 0x96, 0xc6, 0xc2, 0xcd, 0x0c, 0xff, 0x02, + 0x76, 0x70, 0x69, 0xaa, 0x69, 0xd1, 0x3b, 0xe8 }; +#else /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */ + +static const unsigned char entropy_source_pr[] = +{ 0xca, 0x58, 0xfd, 0xf2, 0xb9, 0x77, 0xcb, 0x49, + 0xd4, 0xe0, 0x5b, 0xe2, 0x39, 0x50, 0xd9, 0x8a, + 0x6a, 0xb3, 0xc5, 0x2f, 0xdf, 0x74, 0xd5, 0x85, + 0x8f, 0xd1, 0xba, 0x64, 0x54, 0x7b, 0xdb, 0x1e, + 0xc5, 0xea, 0x24, 0xc0, 0xfa, 0x0c, 0x90, 0x15, + 0x09, 0x20, 0x92, 0x42, 0x32, 0x36, 0x45, 0x45, + 0x7d, 0x20, 0x76, 0x6b, 0xcf, 0xa2, 0x15, 0xc8, + 0x2f, 0x9f, 0xbc, 0x88, 0x3f, 0x80, 0xd1, 0x2c, + 0xb7, 0x16, 0xd1, 0x80, 0x9e, 0xe1, 0xc9, 0xb3, + 0x88, 0x1b, 0x21, 0x45, 0xef, 0xa1, 0x7f, 0xce, + 0xc8, 0x92, 0x35, 0x55, 0x2a, 0xd9, 0x1d, 0x8e, + 0x12, 0x38, 0xac, 0x01, 0x4e, 0x38, 0x18, 0x76, + 0x9c, 0xf2, 0xb6, 0xd4, 0x13, 0xb6, 0x2c, 0x77, + 0xc0, 0xe7, 0xe6, 0x0c, 0x47, 0x44, 0x95, 0xbe }; + +static const unsigned char entropy_source_nopr[] = +{ 0x4c, 0xfb, 0x21, 0x86, 0x73, 0x34, 0x6d, 0x9d, + 0x50, 0xc9, 0x22, 0xe4, 0x9b, 0x0d, 0xfc, 0xd0, + 0x90, 0xad, 0xf0, 0x4f, 0x5c, 0x3b, 0xa4, 0x73, + 0x27, 0xdf, 0xcd, 0x6f, 0xa6, 0x3a, 0x78, 0x5c, + 0x01, 0x69, 0x62, 0xa7, 0xfd, 0x27, 0x87, 0xa2, + 0x4b, 0xf6, 0xbe, 0x47, 0xef, 0x37, 0x83, 0xf1, + 0xb7, 0xec, 0x46, 0x07, 0x23, 0x63, 0x83, 0x4a, + 0x1b, 0x01, 0x33, 0xf2, 0xc2, 0x38, 0x91, 0xdb, + 0x4f, 0x11, 0xa6, 0x86, 0x51, 0xf2, 0x3e, 0x3a, + 0x8b, 0x1f, 0xdc, 0x03, 0xb1, 0x92, 0xc7, 0xe7 }; + +static const unsigned char pers_pr[] = +{ 0x5a, 0x70, 0x95, 0xe9, 0x81, 0x40, 0x52, 0x33, + 0x91, 0x53, 0x7e, 0x75, 0xd6, 0x19, 0x9d, 0x1e, + 0xad, 0x0d, 0xc6, 0xa7, 0xde, 0x6c, 0x1f, 0xe0, + 0xea, 0x18, 0x33, 0xa8, 0x7e, 0x06, 0x20, 0xe9 }; + +static const unsigned char pers_nopr[] = +{ 0x88, 0xee, 0xb8, 0xe0, 0xe8, 0x3b, 0xf3, 0x29, + 0x4b, 0xda, 0xcd, 0x60, 0x99, 0xeb, 0xe4, 0xbf, + 0x55, 0xec, 0xd9, 0x11, 0x3f, 0x71, 0xe5, 0xeb, + 0xcb, 0x45, 0x75, 0xf3, 0xd6, 0xa6, 0x8a, 0x6b }; + +static const unsigned char result_pr[] = +{ 0xce, 0x2f, 0xdb, 0xb6, 0xd9, 0xb7, 0x39, 0x85, + 0x04, 0xc5, 0xc0, 0x42, 0xc2, 0x31, 0xc6, 0x1d, + 0x9b, 0x5a, 0x59, 0xf8, 0x7e, 0x0d, 0xcc, 0x62, + 0x7b, 0x65, 0x11, 0x55, 0x10, 0xeb, 0x9e, 0x3d, + 0xa4, 0xfb, 0x1c, 0x6a, 0x18, 0xc0, 0x74, 0xdb, + 0xdd, 0xe7, 0x02, 0x23, 0x63, 0x21, 0xd0, 0x39, + 0xf9, 0xa7, 0xc4, 0x52, 0x84, 0x3b, 0x49, 0x40, + 0x72, 0x2b, 0xb0, 0x6c, 0x9c, 0xdb, 0xc3, 0x43 }; + +static const unsigned char result_nopr[] = +{ 0xa5, 0x51, 0x80, 0xa1, 0x90, 0xbe, 0xf3, 0xad, + 0xaf, 0x28, 0xf6, 0xb7, 0x95, 0xe9, 0xf1, 0xf3, + 0xd6, 0xdf, 0xa1, 0xb2, 0x7d, 0xd0, 0x46, 0x7b, + 0x0c, 0x75, 0xf5, 0xfa, 0x93, 0x1e, 0x97, 0x14, + 0x75, 0xb2, 0x7c, 0xae, 0x03, 0xa2, 0x96, 0x54, + 0xe2, 0xf4, 0x09, 0x66, 0xea, 0x33, 0x64, 0x30, + 0x40, 0xd1, 0x40, 0x0f, 0xe6, 0x77, 0x87, 0x3a, + 0xf8, 0x09, 0x7c, 0x1f, 0xe9, 0xf0, 0x02, 0x98 }; +#endif /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */ + +static size_t test_offset; +static int ctr_drbg_self_test_entropy(void *data, unsigned char *buf, + size_t len) +{ + const unsigned char *p = data; + memcpy(buf, p + test_offset, len); + test_offset += len; + return 0; +} + +#define CHK(c) if ((c) != 0) \ + { \ + if (verbose != 0) \ + mbedtls_printf("failed\n"); \ + return 1; \ + } + +#define SELF_TEST_OUTPUT_DISCARD_LENGTH 64 + +/* + * Checkup routine + */ +int mbedtls_ctr_drbg_self_test(int verbose) +{ + mbedtls_ctr_drbg_context ctx; + unsigned char buf[sizeof(result_pr)]; + + mbedtls_ctr_drbg_init(&ctx); + + /* + * Based on a NIST CTR_DRBG test vector (PR = True) + */ + if (verbose != 0) { + mbedtls_printf(" CTR_DRBG (PR = TRUE) : "); + } + + test_offset = 0; + mbedtls_ctr_drbg_set_entropy_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE); + mbedtls_ctr_drbg_set_nonce_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE / 2); + CHK(mbedtls_ctr_drbg_seed(&ctx, + ctr_drbg_self_test_entropy, + (void *) entropy_source_pr, + pers_pr, MBEDTLS_CTR_DRBG_KEYSIZE)); + mbedtls_ctr_drbg_set_prediction_resistance(&ctx, MBEDTLS_CTR_DRBG_PR_ON); + CHK(mbedtls_ctr_drbg_random(&ctx, buf, SELF_TEST_OUTPUT_DISCARD_LENGTH)); + CHK(mbedtls_ctr_drbg_random(&ctx, buf, sizeof(result_pr))); + CHK(memcmp(buf, result_pr, sizeof(result_pr))); + + mbedtls_ctr_drbg_free(&ctx); + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + + /* + * Based on a NIST CTR_DRBG test vector (PR = FALSE) + */ + if (verbose != 0) { + mbedtls_printf(" CTR_DRBG (PR = FALSE): "); + } + + mbedtls_ctr_drbg_init(&ctx); + + test_offset = 0; + mbedtls_ctr_drbg_set_entropy_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE); + mbedtls_ctr_drbg_set_nonce_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE / 2); + CHK(mbedtls_ctr_drbg_seed(&ctx, + ctr_drbg_self_test_entropy, + (void *) entropy_source_nopr, + pers_nopr, MBEDTLS_CTR_DRBG_KEYSIZE)); + CHK(mbedtls_ctr_drbg_reseed(&ctx, NULL, 0)); + CHK(mbedtls_ctr_drbg_random(&ctx, buf, SELF_TEST_OUTPUT_DISCARD_LENGTH)); + CHK(mbedtls_ctr_drbg_random(&ctx, buf, sizeof(result_nopr))); + CHK(memcmp(buf, result_nopr, sizeof(result_nopr))); + + mbedtls_ctr_drbg_free(&ctx); + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + return 0; +} +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CTR_DRBG_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/ecdsa.c b/tf-psa-crypto/drivers/builtin/src/ecdsa.c new file mode 100644 index 0000000000..90a5fe17cf --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/ecdsa.c @@ -0,0 +1,826 @@ +/* + * Elliptic curve DSA + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +/* + * References: + * + * SEC1 https://www.secg.org/sec1-v2.pdf + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_ECDSA_C) + +#include "mbedtls/private/ecdsa.h" +#include "mbedtls/asn1write.h" +#include "bignum_internal.h" + +#include + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +#include "mbedtls/private/hmac_drbg.h" +#endif + +#include "mbedtls/platform.h" + +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#if defined(MBEDTLS_ECP_RESTARTABLE) + +/* + * Sub-context for ecdsa_verify() + */ +struct mbedtls_ecdsa_restart_ver { + mbedtls_mpi u1, u2; /* intermediate values */ + enum { /* what to do next? */ + ecdsa_ver_init = 0, /* getting started */ + ecdsa_ver_muladd, /* muladd step */ + } state; +}; + +/* + * Init verify restart sub-context + */ +static void ecdsa_restart_ver_init(mbedtls_ecdsa_restart_ver_ctx *ctx) +{ + mbedtls_mpi_init(&ctx->u1); + mbedtls_mpi_init(&ctx->u2); + ctx->state = ecdsa_ver_init; +} + +/* + * Free the components of a verify restart sub-context + */ +static void ecdsa_restart_ver_free(mbedtls_ecdsa_restart_ver_ctx *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_mpi_free(&ctx->u1); + mbedtls_mpi_free(&ctx->u2); + + ecdsa_restart_ver_init(ctx); +} + +/* + * Sub-context for ecdsa_sign() + */ +struct mbedtls_ecdsa_restart_sig { + int sign_tries; + int key_tries; + mbedtls_mpi k; /* per-signature random */ + mbedtls_mpi r; /* r value */ + enum { /* what to do next? */ + ecdsa_sig_init = 0, /* getting started */ + ecdsa_sig_mul, /* doing ecp_mul() */ + ecdsa_sig_modn, /* mod N computations */ + } state; +}; + +/* + * Init verify sign sub-context + */ +static void ecdsa_restart_sig_init(mbedtls_ecdsa_restart_sig_ctx *ctx) +{ + ctx->sign_tries = 0; + ctx->key_tries = 0; + mbedtls_mpi_init(&ctx->k); + mbedtls_mpi_init(&ctx->r); + ctx->state = ecdsa_sig_init; +} + +/* + * Free the components of a sign restart sub-context + */ +static void ecdsa_restart_sig_free(mbedtls_ecdsa_restart_sig_ctx *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_mpi_free(&ctx->k); + mbedtls_mpi_free(&ctx->r); +} + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +/* + * Sub-context for ecdsa_sign_det() + */ +struct mbedtls_ecdsa_restart_det { + mbedtls_hmac_drbg_context rng_ctx; /* DRBG state */ + enum { /* what to do next? */ + ecdsa_det_init = 0, /* getting started */ + ecdsa_det_sign, /* make signature */ + } state; +}; + +/* + * Init verify sign_det sub-context + */ +static void ecdsa_restart_det_init(mbedtls_ecdsa_restart_det_ctx *ctx) +{ + mbedtls_hmac_drbg_init(&ctx->rng_ctx); + ctx->state = ecdsa_det_init; +} + +/* + * Free the components of a sign_det restart sub-context + */ +static void ecdsa_restart_det_free(mbedtls_ecdsa_restart_det_ctx *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_hmac_drbg_free(&ctx->rng_ctx); + + ecdsa_restart_det_init(ctx); +} +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +#define ECDSA_RS_ECP (rs_ctx == NULL ? NULL : &rs_ctx->ecp) + +/* Utility macro for checking and updating ops budget */ +#define ECDSA_BUDGET(ops) \ + MBEDTLS_MPI_CHK(mbedtls_ecp_check_budget(grp, ECDSA_RS_ECP, ops)); + +/* Call this when entering a function that needs its own sub-context */ +#define ECDSA_RS_ENTER(SUB) do { \ + /* reset ops count for this call if top-level */ \ + if (rs_ctx != NULL && rs_ctx->ecp.depth++ == 0) \ + rs_ctx->ecp.ops_done = 0; \ + \ + /* set up our own sub-context if needed */ \ + if (mbedtls_ecp_restart_is_enabled() && \ + rs_ctx != NULL && rs_ctx->SUB == NULL) \ + { \ + rs_ctx->SUB = mbedtls_calloc(1, sizeof(*rs_ctx->SUB)); \ + if (rs_ctx->SUB == NULL) \ + return MBEDTLS_ERR_ECP_ALLOC_FAILED; \ + \ + ecdsa_restart_## SUB ##_init(rs_ctx->SUB); \ + } \ +} while (0) + +/* Call this when leaving a function that needs its own sub-context */ +#define ECDSA_RS_LEAVE(SUB) do { \ + /* clear our sub-context when not in progress (done or error) */ \ + if (rs_ctx != NULL && rs_ctx->SUB != NULL && \ + ret != MBEDTLS_ERR_ECP_IN_PROGRESS) \ + { \ + ecdsa_restart_## SUB ##_free(rs_ctx->SUB); \ + mbedtls_free(rs_ctx->SUB); \ + rs_ctx->SUB = NULL; \ + } \ + \ + if (rs_ctx != NULL) \ + rs_ctx->ecp.depth--; \ +} while (0) + +#else /* MBEDTLS_ECP_RESTARTABLE */ + +#define ECDSA_RS_ECP NULL + +#define ECDSA_BUDGET(ops) /* no-op; for compatibility */ + +#define ECDSA_RS_ENTER(SUB) (void) rs_ctx +#define ECDSA_RS_LEAVE(SUB) (void) rs_ctx + +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +/* + * Derive a suitable integer for group grp from a buffer of length len + * SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3 + */ +static int derive_mpi(const mbedtls_ecp_group *grp, mbedtls_mpi *x, + const unsigned char *buf, size_t blen) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t n_size = (grp->nbits + 7) / 8; + size_t use_size = blen > n_size ? n_size : blen; + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(x, buf, use_size)); + if (use_size * 8 > grp->nbits) { + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(x, use_size * 8 - grp->nbits)); + } + + /* While at it, reduce modulo N */ + if (mbedtls_mpi_cmp_mpi(x, &grp->N) >= 0) { + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(x, x, &grp->N)); + } + +cleanup: + return ret; +} + +int mbedtls_ecdsa_can_do(mbedtls_ecp_group_id gid) +{ + switch (gid) { +#ifdef MBEDTLS_ECP_DP_CURVE25519_ENABLED + case MBEDTLS_ECP_DP_CURVE25519: return 0; +#endif +#ifdef MBEDTLS_ECP_DP_CURVE448_ENABLED + case MBEDTLS_ECP_DP_CURVE448: return 0; +#endif + default: return 1; + } +} + +/* + * Compute ECDSA signature of a hashed message (SEC1 4.1.3) + * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message) + */ +int mbedtls_ecdsa_sign_restartable(mbedtls_ecp_group *grp, + mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + int (*f_rng_blind)(void *, unsigned char *, size_t), + void *p_rng_blind, + mbedtls_ecdsa_restart_ctx *rs_ctx) +{ + int ret, key_tries, sign_tries; + int *p_sign_tries = &sign_tries, *p_key_tries = &key_tries; + mbedtls_ecp_point R; + mbedtls_mpi k, e; + mbedtls_mpi *pk = &k, *pr = r; + + /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ + if (!mbedtls_ecdsa_can_do(grp->id) || grp->N.p == NULL) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* Make sure d is in range 1..n-1 */ + if (mbedtls_mpi_cmp_int(d, 1) < 0 || mbedtls_mpi_cmp_mpi(d, &grp->N) >= 0) { + return MBEDTLS_ERR_ECP_INVALID_KEY; + } + + mbedtls_ecp_point_init(&R); + mbedtls_mpi_init(&k); mbedtls_mpi_init(&e); + + ECDSA_RS_ENTER(sig); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->sig != NULL) { + /* redirect to our context */ + p_sign_tries = &rs_ctx->sig->sign_tries; + p_key_tries = &rs_ctx->sig->key_tries; + pk = &rs_ctx->sig->k; + pr = &rs_ctx->sig->r; + + /* jump to current step */ + if (rs_ctx->sig->state == ecdsa_sig_mul) { + goto mul; + } + if (rs_ctx->sig->state == ecdsa_sig_modn) { + goto modn; + } + } +#endif /* MBEDTLS_ECP_RESTARTABLE */ + + *p_sign_tries = 0; + do { + if ((*p_sign_tries)++ > 10) { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; + goto cleanup; + } + + /* + * Steps 1-3: generate a suitable ephemeral keypair + * and set r = xR mod n + */ + *p_key_tries = 0; + do { + if ((*p_key_tries)++ > 10) { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; + goto cleanup; + } + + MBEDTLS_MPI_CHK(mbedtls_ecp_gen_privkey(grp, pk, f_rng, p_rng)); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->sig != NULL) { + rs_ctx->sig->state = ecdsa_sig_mul; + } + +mul: +#endif + MBEDTLS_MPI_CHK(mbedtls_ecp_mul_restartable(grp, &R, pk, &grp->G, + f_rng_blind, + p_rng_blind, + ECDSA_RS_ECP)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(pr, &R.X, &grp->N)); + } while (mbedtls_mpi_cmp_int(pr, 0) == 0); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->sig != NULL) { + rs_ctx->sig->state = ecdsa_sig_modn; + } + +modn: +#endif + /* + * Accounting for everything up to the end of the loop + * (step 6, but checking now avoids saving e and t) + */ + ECDSA_BUDGET(MBEDTLS_ECP_OPS_INV + 4); + + /* + * Step 5: derive MPI from hashed message + */ + MBEDTLS_MPI_CHK(derive_mpi(grp, &e, buf, blen)); + + /* + * Step 6: compute s = (e + r * d) / k + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(s, pr, d)); + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&e, &e, s)); + MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(NULL, s, pk, &grp->N)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(s, s, &e)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(s, s, &grp->N)); + } while (mbedtls_mpi_cmp_int(s, 0) == 0); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->sig != NULL) { + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(r, pr)); + } +#endif + +cleanup: + mbedtls_ecp_point_free(&R); + mbedtls_mpi_free(&k); mbedtls_mpi_free(&e); + + ECDSA_RS_LEAVE(sig); + + return ret; +} + +/* + * Compute ECDSA signature of a hashed message + */ +int mbedtls_ecdsa_sign(mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) +{ + /* Use the same RNG for both blinding and ephemeral key generation */ + return mbedtls_ecdsa_sign_restartable(grp, r, s, d, buf, blen, + f_rng, p_rng, f_rng, p_rng, NULL); +} + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +/* + * Deterministic signature wrapper + * + * note: The f_rng_blind parameter must not be NULL. + * + */ +int mbedtls_ecdsa_sign_det_restartable(mbedtls_ecp_group *grp, + mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg, + int (*f_rng_blind)(void *, unsigned char *, size_t), + void *p_rng_blind, + mbedtls_ecdsa_restart_ctx *rs_ctx) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_hmac_drbg_context rng_ctx; + mbedtls_hmac_drbg_context *p_rng = &rng_ctx; + unsigned char data[2 * MBEDTLS_ECP_MAX_BYTES]; + size_t grp_len = (grp->nbits + 7) / 8; + const mbedtls_md_info_t *md_info; + mbedtls_mpi h; + + if ((md_info = mbedtls_md_info_from_type(md_alg)) == NULL) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + mbedtls_mpi_init(&h); + mbedtls_hmac_drbg_init(&rng_ctx); + + ECDSA_RS_ENTER(det); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->det != NULL) { + /* redirect to our context */ + p_rng = &rs_ctx->det->rng_ctx; + + /* jump to current step */ + if (rs_ctx->det->state == ecdsa_det_sign) { + goto sign; + } + } +#endif /* MBEDTLS_ECP_RESTARTABLE */ + + /* Use private key and message hash (reduced) to initialize HMAC_DRBG */ + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(d, data, grp_len)); + MBEDTLS_MPI_CHK(derive_mpi(grp, &h, buf, blen)); + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&h, data + grp_len, grp_len)); + MBEDTLS_MPI_CHK(mbedtls_hmac_drbg_seed_buf(p_rng, md_info, data, 2 * grp_len)); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->det != NULL) { + rs_ctx->det->state = ecdsa_det_sign; + } + +sign: +#endif + ret = mbedtls_ecdsa_sign_restartable(grp, r, s, d, buf, blen, + mbedtls_hmac_drbg_random, p_rng, + f_rng_blind, p_rng_blind, rs_ctx); + +cleanup: + mbedtls_hmac_drbg_free(&rng_ctx); + mbedtls_mpi_free(&h); + + ECDSA_RS_LEAVE(det); + + return ret; +} + +/* + * Deterministic signature wrapper + */ +int mbedtls_ecdsa_sign_det_ext(mbedtls_ecp_group *grp, mbedtls_mpi *r, + mbedtls_mpi *s, const mbedtls_mpi *d, + const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg, + int (*f_rng_blind)(void *, unsigned char *, + size_t), + void *p_rng_blind) +{ + return mbedtls_ecdsa_sign_det_restartable(grp, r, s, d, buf, blen, md_alg, + f_rng_blind, p_rng_blind, NULL); +} +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +/* + * Verify ECDSA signature of hashed message (SEC1 4.1.4) + * Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message) + */ +int mbedtls_ecdsa_verify_restartable(mbedtls_ecp_group *grp, + const unsigned char *buf, size_t blen, + const mbedtls_ecp_point *Q, + const mbedtls_mpi *r, + const mbedtls_mpi *s, + mbedtls_ecdsa_restart_ctx *rs_ctx) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi e, s_inv, u1, u2; + mbedtls_ecp_point R; + mbedtls_mpi *pu1 = &u1, *pu2 = &u2; + + mbedtls_ecp_point_init(&R); + mbedtls_mpi_init(&e); mbedtls_mpi_init(&s_inv); + mbedtls_mpi_init(&u1); mbedtls_mpi_init(&u2); + + /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ + if (!mbedtls_ecdsa_can_do(grp->id) || grp->N.p == NULL) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + ECDSA_RS_ENTER(ver); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->ver != NULL) { + /* redirect to our context */ + pu1 = &rs_ctx->ver->u1; + pu2 = &rs_ctx->ver->u2; + + /* jump to current step */ + if (rs_ctx->ver->state == ecdsa_ver_muladd) { + goto muladd; + } + } +#endif /* MBEDTLS_ECP_RESTARTABLE */ + + /* + * Step 1: make sure r and s are in range 1..n-1 + */ + if (mbedtls_mpi_cmp_int(r, 1) < 0 || mbedtls_mpi_cmp_mpi(r, &grp->N) >= 0 || + mbedtls_mpi_cmp_int(s, 1) < 0 || mbedtls_mpi_cmp_mpi(s, &grp->N) >= 0) { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + + /* + * Step 3: derive MPI from hashed message + */ + MBEDTLS_MPI_CHK(derive_mpi(grp, &e, buf, blen)); + + /* + * Step 4: u1 = e / s mod n, u2 = r / s mod n + */ + ECDSA_BUDGET(MBEDTLS_ECP_OPS_CHK + MBEDTLS_ECP_OPS_INV + 2); + + MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(NULL, &s_inv, s, &grp->N)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(pu1, &e, &s_inv)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(pu1, pu1, &grp->N)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(pu2, r, &s_inv)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(pu2, pu2, &grp->N)); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->ver != NULL) { + rs_ctx->ver->state = ecdsa_ver_muladd; + } + +muladd: +#endif + /* + * Step 5: R = u1 G + u2 Q + */ + MBEDTLS_MPI_CHK(mbedtls_ecp_muladd_restartable(grp, + &R, pu1, &grp->G, pu2, Q, ECDSA_RS_ECP)); + + if (mbedtls_ecp_is_zero(&R)) { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + + /* + * Step 6: convert xR to an integer (no-op) + * Step 7: reduce xR mod n (gives v) + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&R.X, &R.X, &grp->N)); + + /* + * Step 8: check if v (that is, R.X) is equal to r + */ + if (mbedtls_mpi_cmp_mpi(&R.X, r) != 0) { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + +cleanup: + mbedtls_ecp_point_free(&R); + mbedtls_mpi_free(&e); mbedtls_mpi_free(&s_inv); + mbedtls_mpi_free(&u1); mbedtls_mpi_free(&u2); + + ECDSA_RS_LEAVE(ver); + + return ret; +} + +/* + * Verify ECDSA signature of hashed message + */ +int mbedtls_ecdsa_verify(mbedtls_ecp_group *grp, + const unsigned char *buf, size_t blen, + const mbedtls_ecp_point *Q, + const mbedtls_mpi *r, + const mbedtls_mpi *s) +{ + return mbedtls_ecdsa_verify_restartable(grp, buf, blen, Q, r, s, NULL); +} + +/* + * Convert a signature (given by context) to ASN.1 + */ +static int ecdsa_signature_to_asn1(const mbedtls_mpi *r, const mbedtls_mpi *s, + unsigned char *sig, size_t sig_size, + size_t *slen) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char buf[MBEDTLS_ECDSA_MAX_LEN] = { 0 }; + unsigned char *p = buf + sizeof(buf); + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_mpi(&p, buf, s)); + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_mpi(&p, buf, r)); + + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&p, buf, len)); + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&p, buf, + MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE)); + + if (len > sig_size) { + return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + } + + memcpy(sig, p, len); + *slen = len; + + return 0; +} + +/* + * Compute and write signature + */ +int mbedtls_ecdsa_write_signature_restartable(mbedtls_ecdsa_context *ctx, + mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t sig_size, size_t *slen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_ecdsa_restart_ctx *rs_ctx) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi r, s; + if (f_rng == NULL) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + mbedtls_mpi_init(&r); + mbedtls_mpi_init(&s); + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + MBEDTLS_MPI_CHK(mbedtls_ecdsa_sign_det_restartable(&ctx->grp, &r, &s, &ctx->d, + hash, hlen, md_alg, f_rng, + p_rng, rs_ctx)); +#else + (void) md_alg; + + /* Use the same RNG for both blinding and ephemeral key generation */ + MBEDTLS_MPI_CHK(mbedtls_ecdsa_sign_restartable(&ctx->grp, &r, &s, &ctx->d, + hash, hlen, f_rng, p_rng, f_rng, + p_rng, rs_ctx)); +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + + MBEDTLS_MPI_CHK(ecdsa_signature_to_asn1(&r, &s, sig, sig_size, slen)); + +cleanup: + mbedtls_mpi_free(&r); + mbedtls_mpi_free(&s); + + return ret; +} + +/* + * Compute and write signature + */ +int mbedtls_ecdsa_write_signature(mbedtls_ecdsa_context *ctx, + mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t sig_size, size_t *slen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + return mbedtls_ecdsa_write_signature_restartable( + ctx, md_alg, hash, hlen, sig, sig_size, slen, + f_rng, p_rng, NULL); +} + +/* + * Read and check signature + */ +int mbedtls_ecdsa_read_signature(mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + const unsigned char *sig, size_t slen) +{ + return mbedtls_ecdsa_read_signature_restartable( + ctx, hash, hlen, sig, slen, NULL); +} + +/* + * Restartable read and check signature + */ +int mbedtls_ecdsa_read_signature_restartable(mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + const unsigned char *sig, size_t slen, + mbedtls_ecdsa_restart_ctx *rs_ctx) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char *p = (unsigned char *) sig; + const unsigned char *end = sig + slen; + size_t len; + mbedtls_mpi r, s; + mbedtls_mpi_init(&r); + mbedtls_mpi_init(&s); + + if ((ret = mbedtls_asn1_get_tag(&p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { + ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + if (p + len != end) { + ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_ECP_BAD_INPUT_DATA, + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); + goto cleanup; + } + + if ((ret = mbedtls_asn1_get_mpi(&p, end, &r)) != 0 || + (ret = mbedtls_asn1_get_mpi(&p, end, &s)) != 0) { + ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + if ((ret = mbedtls_ecdsa_verify_restartable(&ctx->grp, hash, hlen, + &ctx->Q, &r, &s, rs_ctx)) != 0) { + goto cleanup; + } + + /* At this point we know that the buffer starts with a valid signature. + * Return 0 if the buffer just contains the signature, and a specific + * error code if the valid signature is followed by more data. */ + if (p != end) { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + } + +cleanup: + mbedtls_mpi_free(&r); + mbedtls_mpi_free(&s); + + return ret; +} + +/* + * Generate key pair + */ +int mbedtls_ecdsa_genkey(mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) +{ + int ret = 0; + ret = mbedtls_ecp_group_load(&ctx->grp, gid); + if (ret != 0) { + return ret; + } + + return mbedtls_ecp_gen_keypair(&ctx->grp, &ctx->d, + &ctx->Q, f_rng, p_rng); +} + +/* + * Set context from an mbedtls_ecp_keypair + */ +int mbedtls_ecdsa_from_keypair(mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + if ((ret = mbedtls_ecp_group_copy(&ctx->grp, &key->grp)) != 0 || + (ret = mbedtls_mpi_copy(&ctx->d, &key->d)) != 0 || + (ret = mbedtls_ecp_copy(&ctx->Q, &key->Q)) != 0) { + mbedtls_ecdsa_free(ctx); + } + + return ret; +} + +/* + * Initialize context + */ +void mbedtls_ecdsa_init(mbedtls_ecdsa_context *ctx) +{ + mbedtls_ecp_keypair_init(ctx); +} + +/* + * Free context + */ +void mbedtls_ecdsa_free(mbedtls_ecdsa_context *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_ecp_keypair_free(ctx); +} + +#if defined(MBEDTLS_ECP_RESTARTABLE) +/* + * Initialize a restart context + */ +void mbedtls_ecdsa_restart_init(mbedtls_ecdsa_restart_ctx *ctx) +{ + mbedtls_ecp_restart_init(&ctx->ecp); + + ctx->ver = NULL; + ctx->sig = NULL; +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + ctx->det = NULL; +#endif +} + +/* + * Free the components of a restart context + */ +void mbedtls_ecdsa_restart_free(mbedtls_ecdsa_restart_ctx *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_ecp_restart_free(&ctx->ecp); + + ecdsa_restart_ver_free(ctx->ver); + mbedtls_free(ctx->ver); + ctx->ver = NULL; + + ecdsa_restart_sig_free(ctx->sig); + mbedtls_free(ctx->sig); + ctx->sig = NULL; + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + ecdsa_restart_det_free(ctx->det); + mbedtls_free(ctx->det); + ctx->det = NULL; +#endif +} +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +#endif /* MBEDTLS_ECDSA_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/ecjpake.c b/tf-psa-crypto/drivers/builtin/src/ecjpake.c new file mode 100644 index 0000000000..ad1baefd5c --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/ecjpake.c @@ -0,0 +1,1206 @@ +/* + * Elliptic curve J-PAKE + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +/* + * References in the code are to the Thread v1.0 Specification, + * available to members of the Thread Group http://threadgroup.org/ + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_ECJPAKE_C) + +#include "mbedtls/private/ecjpake.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#include + +/* + * Convert a mbedtls_ecjpake_role to identifier string + */ +static const char * const ecjpake_id[] = { + "client", + "server" +}; + +#define ID_MINE (ecjpake_id[ctx->role]) +#define ID_PEER (ecjpake_id[1 - ctx->role]) + +/** + * Helper to Compute a hash from md_type + */ +static int mbedtls_ecjpake_compute_hash(mbedtls_md_type_t md_type, + const unsigned char *input, size_t ilen, + unsigned char *output) +{ + return mbedtls_md(mbedtls_md_info_from_type(md_type), + input, ilen, output); +} + +/* + * Initialize context + */ +void mbedtls_ecjpake_init(mbedtls_ecjpake_context *ctx) +{ + ctx->md_type = MBEDTLS_MD_NONE; + mbedtls_ecp_group_init(&ctx->grp); + ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; + + mbedtls_ecp_point_init(&ctx->Xm1); + mbedtls_ecp_point_init(&ctx->Xm2); + mbedtls_ecp_point_init(&ctx->Xp1); + mbedtls_ecp_point_init(&ctx->Xp2); + mbedtls_ecp_point_init(&ctx->Xp); + + mbedtls_mpi_init(&ctx->xm1); + mbedtls_mpi_init(&ctx->xm2); + mbedtls_mpi_init(&ctx->s); +} + +/* + * Free context + */ +void mbedtls_ecjpake_free(mbedtls_ecjpake_context *ctx) +{ + if (ctx == NULL) { + return; + } + + ctx->md_type = MBEDTLS_MD_NONE; + mbedtls_ecp_group_free(&ctx->grp); + + mbedtls_ecp_point_free(&ctx->Xm1); + mbedtls_ecp_point_free(&ctx->Xm2); + mbedtls_ecp_point_free(&ctx->Xp1); + mbedtls_ecp_point_free(&ctx->Xp2); + mbedtls_ecp_point_free(&ctx->Xp); + + mbedtls_mpi_free(&ctx->xm1); + mbedtls_mpi_free(&ctx->xm2); + mbedtls_mpi_free(&ctx->s); +} + +/* + * Setup context + */ +int mbedtls_ecjpake_setup(mbedtls_ecjpake_context *ctx, + mbedtls_ecjpake_role role, + mbedtls_md_type_t hash, + mbedtls_ecp_group_id curve, + const unsigned char *secret, + size_t len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if (role != MBEDTLS_ECJPAKE_CLIENT && role != MBEDTLS_ECJPAKE_SERVER) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + ctx->role = role; + + if ((mbedtls_md_info_from_type(hash)) == NULL) { + return MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE; + } + + ctx->md_type = hash; + + MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&ctx->grp, curve)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->s, secret, len)); + +cleanup: + if (ret != 0) { + mbedtls_ecjpake_free(ctx); + } + + return ret; +} + +int mbedtls_ecjpake_set_point_format(mbedtls_ecjpake_context *ctx, + int point_format) +{ + switch (point_format) { + case MBEDTLS_ECP_PF_UNCOMPRESSED: + case MBEDTLS_ECP_PF_COMPRESSED: + ctx->point_format = point_format; + return 0; + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +} + +/* + * Check if context is ready for use + */ +int mbedtls_ecjpake_check(const mbedtls_ecjpake_context *ctx) +{ + if (ctx->md_type == MBEDTLS_MD_NONE || + ctx->grp.id == MBEDTLS_ECP_DP_NONE || + ctx->s.p == NULL) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + return 0; +} + +/* + * Write a point plus its length to a buffer + */ +static int ecjpake_write_len_point(unsigned char **p, + const unsigned char *end, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *P) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t len; + + /* Need at least 4 for length plus 1 for point */ + if (end < *p || end - *p < 5) { + return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + } + + ret = mbedtls_ecp_point_write_binary(grp, P, pf, + &len, *p + 4, (size_t) (end - (*p + 4))); + if (ret != 0) { + return ret; + } + + MBEDTLS_PUT_UINT32_BE(len, *p, 0); + + *p += 4 + len; + + return 0; +} + +/* + * Size of the temporary buffer for ecjpake_hash: + * 3 EC points plus their length, plus ID and its length (4 + 6 bytes) + */ +#define ECJPAKE_HASH_BUF_LEN (3 * (4 + MBEDTLS_ECP_MAX_PT_LEN) + 4 + 6) + +/* + * Compute hash for ZKP (7.4.2.2.2.1) + */ +static int ecjpake_hash(const mbedtls_md_type_t md_type, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + const mbedtls_ecp_point *V, + const mbedtls_ecp_point *X, + const char *id, + mbedtls_mpi *h) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char buf[ECJPAKE_HASH_BUF_LEN]; + unsigned char *p = buf; + const unsigned char *end = buf + sizeof(buf); + const size_t id_len = strlen(id); + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + + /* Write things to temporary buffer */ + MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, G)); + MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, V)); + MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, X)); + + if (end - p < 4) { + return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + } + + MBEDTLS_PUT_UINT32_BE(id_len, p, 0); + p += 4; + + if (end < p || (size_t) (end - p) < id_len) { + return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + } + + memcpy(p, id, id_len); + p += id_len; + + /* Compute hash */ + MBEDTLS_MPI_CHK(mbedtls_ecjpake_compute_hash(md_type, + buf, (size_t) (p - buf), hash)); + + /* Turn it into an integer mod n */ + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(h, hash, + mbedtls_md_get_size_from_type(md_type))); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(h, h, &grp->N)); + +cleanup: + return ret; +} + +/* + * Parse a ECShnorrZKP (7.4.2.2.2) and verify it (7.4.2.3.3) + */ +static int ecjpake_zkp_read(const mbedtls_md_type_t md_type, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + const mbedtls_ecp_point *X, + const char *id, + const unsigned char **p, + const unsigned char *end) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_point V, VV; + mbedtls_mpi r, h; + size_t r_len; + + mbedtls_ecp_point_init(&V); + mbedtls_ecp_point_init(&VV); + mbedtls_mpi_init(&r); + mbedtls_mpi_init(&h); + + /* + * struct { + * ECPoint V; + * opaque r<1..2^8-1>; + * } ECSchnorrZKP; + */ + if (end < *p) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_point(grp, &V, p, (size_t) (end - *p))); + + if (end < *p || (size_t) (end - *p) < 1) { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + r_len = *(*p)++; + + if (end < *p || (size_t) (end - *p) < r_len || r_len == 0) { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&r, *p, r_len)); + *p += r_len; + + /* + * Verification + */ + MBEDTLS_MPI_CHK(ecjpake_hash(md_type, grp, pf, G, &V, X, id, &h)); + MBEDTLS_MPI_CHK(mbedtls_ecp_muladd((mbedtls_ecp_group *) grp, + &VV, &h, X, &r, G)); + + if (mbedtls_ecp_point_cmp(&VV, &V) != 0) { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + +cleanup: + mbedtls_ecp_point_free(&V); + mbedtls_ecp_point_free(&VV); + mbedtls_mpi_free(&r); + mbedtls_mpi_free(&h); + + return ret; +} + +/* + * Generate ZKP (7.4.2.3.2) and write it as ECSchnorrZKP (7.4.2.2.2) + */ +static int ecjpake_zkp_write(const mbedtls_md_type_t md_type, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + const mbedtls_mpi *x, + const mbedtls_ecp_point *X, + const char *id, + unsigned char **p, + const unsigned char *end, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_point V; + mbedtls_mpi v; + mbedtls_mpi h; /* later recycled to hold r */ + size_t len; + + if (end < *p) { + return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + } + + mbedtls_ecp_point_init(&V); + mbedtls_mpi_init(&v); + mbedtls_mpi_init(&h); + + /* Compute signature */ + MBEDTLS_MPI_CHK(mbedtls_ecp_gen_keypair_base((mbedtls_ecp_group *) grp, + G, &v, &V, f_rng, p_rng)); + MBEDTLS_MPI_CHK(ecjpake_hash(md_type, grp, pf, G, &V, X, id, &h)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&h, &h, x)); /* x*h */ + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&h, &v, &h)); /* v - x*h */ + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&h, &h, &grp->N)); /* r */ + + /* Write it out */ + MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(grp, &V, + pf, &len, *p, (size_t) (end - *p))); + *p += len; + + len = mbedtls_mpi_size(&h); /* actually r */ + if (end < *p || (size_t) (end - *p) < 1 + len || len > 255) { + ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + goto cleanup; + } + + *(*p)++ = MBEDTLS_BYTE_0(len); + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&h, *p, len)); /* r */ + *p += len; + +cleanup: + mbedtls_ecp_point_free(&V); + mbedtls_mpi_free(&v); + mbedtls_mpi_free(&h); + + return ret; +} + +/* + * Parse a ECJPAKEKeyKP (7.4.2.2.1) and check proof + * Output: verified public key X + */ +static int ecjpake_kkp_read(const mbedtls_md_type_t md_type, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + mbedtls_ecp_point *X, + const char *id, + const unsigned char **p, + const unsigned char *end) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if (end < *p) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* + * struct { + * ECPoint X; + * ECSchnorrZKP zkp; + * } ECJPAKEKeyKP; + */ + MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_point(grp, X, p, (size_t) (end - *p))); + if (mbedtls_ecp_is_zero(X)) { + ret = MBEDTLS_ERR_ECP_INVALID_KEY; + goto cleanup; + } + + MBEDTLS_MPI_CHK(ecjpake_zkp_read(md_type, grp, pf, G, X, id, p, end)); + +cleanup: + return ret; +} + +/* + * Generate an ECJPAKEKeyKP + * Output: the serialized structure, plus private/public key pair + */ +static int ecjpake_kkp_write(const mbedtls_md_type_t md_type, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + mbedtls_mpi *x, + mbedtls_ecp_point *X, + const char *id, + unsigned char **p, + const unsigned char *end, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t len; + + if (end < *p) { + return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + } + + /* Generate key (7.4.2.3.1) and write it out */ + MBEDTLS_MPI_CHK(mbedtls_ecp_gen_keypair_base((mbedtls_ecp_group *) grp, G, x, X, + f_rng, p_rng)); + MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(grp, X, + pf, &len, *p, (size_t) (end - *p))); + *p += len; + + /* Generate and write proof */ + MBEDTLS_MPI_CHK(ecjpake_zkp_write(md_type, grp, pf, G, x, X, id, + p, end, f_rng, p_rng)); + +cleanup: + return ret; +} + +/* + * Read a ECJPAKEKeyKPPairList (7.4.2.3) and check proofs + * Outputs: verified peer public keys Xa, Xb + */ +static int ecjpake_kkpp_read(const mbedtls_md_type_t md_type, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + mbedtls_ecp_point *Xa, + mbedtls_ecp_point *Xb, + const char *id, + const unsigned char *buf, + size_t len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + const unsigned char *p = buf; + const unsigned char *end = buf + len; + + /* + * struct { + * ECJPAKEKeyKP ecjpake_key_kp_pair_list[2]; + * } ECJPAKEKeyKPPairList; + */ + MBEDTLS_MPI_CHK(ecjpake_kkp_read(md_type, grp, pf, G, Xa, id, &p, end)); + MBEDTLS_MPI_CHK(ecjpake_kkp_read(md_type, grp, pf, G, Xb, id, &p, end)); + + if (p != end) { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + +cleanup: + return ret; +} + +/* + * Generate a ECJPAKEKeyKPPairList + * Outputs: the serialized structure, plus two private/public key pairs + */ +static int ecjpake_kkpp_write(const mbedtls_md_type_t md_type, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + mbedtls_mpi *xm1, + mbedtls_ecp_point *Xa, + mbedtls_mpi *xm2, + mbedtls_ecp_point *Xb, + const char *id, + unsigned char *buf, + size_t len, + size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char *p = buf; + const unsigned char *end = buf + len; + + MBEDTLS_MPI_CHK(ecjpake_kkp_write(md_type, grp, pf, G, xm1, Xa, id, + &p, end, f_rng, p_rng)); + MBEDTLS_MPI_CHK(ecjpake_kkp_write(md_type, grp, pf, G, xm2, Xb, id, + &p, end, f_rng, p_rng)); + + *olen = (size_t) (p - buf); + +cleanup: + return ret; +} + +/* + * Read and process the first round message + */ +int mbedtls_ecjpake_read_round_one(mbedtls_ecjpake_context *ctx, + const unsigned char *buf, + size_t len) +{ + return ecjpake_kkpp_read(ctx->md_type, &ctx->grp, ctx->point_format, + &ctx->grp.G, + &ctx->Xp1, &ctx->Xp2, ID_PEER, + buf, len); +} + +/* + * Generate and write the first round message + */ +int mbedtls_ecjpake_write_round_one(mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + return ecjpake_kkpp_write(ctx->md_type, &ctx->grp, ctx->point_format, + &ctx->grp.G, + &ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2, + ID_MINE, buf, len, olen, f_rng, p_rng); +} + +/* + * Compute the sum of three points R = A + B + C + */ +static int ecjpake_ecp_add3(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point *A, + const mbedtls_ecp_point *B, + const mbedtls_ecp_point *C) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi one; + + mbedtls_mpi_init(&one); + + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&one, 1)); + MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(grp, R, &one, A, &one, B)); + MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(grp, R, &one, R, &one, C)); + +cleanup: + mbedtls_mpi_free(&one); + + return ret; +} + +/* + * Read and process second round message (C: 7.4.2.5, S: 7.4.2.6) + */ +int mbedtls_ecjpake_read_round_two(mbedtls_ecjpake_context *ctx, + const unsigned char *buf, + size_t len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + const unsigned char *p = buf; + const unsigned char *end = buf + len; + mbedtls_ecp_group grp; + mbedtls_ecp_point G; /* C: GB, S: GA */ + + mbedtls_ecp_group_init(&grp); + mbedtls_ecp_point_init(&G); + + /* + * Server: GA = X3 + X4 + X1 (7.4.2.6.1) + * Client: GB = X1 + X2 + X3 (7.4.2.5.1) + * Unified: G = Xm1 + Xm2 + Xp1 + * We need that before parsing in order to check Xp as we read it + */ + MBEDTLS_MPI_CHK(ecjpake_ecp_add3(&ctx->grp, &G, + &ctx->Xm1, &ctx->Xm2, &ctx->Xp1)); + + /* + * struct { + * ECParameters curve_params; // only client reading server msg + * ECJPAKEKeyKP ecjpake_key_kp; + * } Client/ServerECJPAKEParams; + */ + if (ctx->role == MBEDTLS_ECJPAKE_CLIENT) { + MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_group(&grp, &p, len)); + if (grp.id != ctx->grp.id) { + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + goto cleanup; + } + } + + MBEDTLS_MPI_CHK(ecjpake_kkp_read(ctx->md_type, &ctx->grp, + ctx->point_format, + &G, &ctx->Xp, ID_PEER, &p, end)); + + if (p != end) { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + +cleanup: + mbedtls_ecp_group_free(&grp); + mbedtls_ecp_point_free(&G); + + return ret; +} + +/* + * Compute R = +/- X * S mod N, taking care not to leak S + */ +static int ecjpake_mul_secret(mbedtls_mpi *R, int sign, + const mbedtls_mpi *X, + const mbedtls_mpi *S, + const mbedtls_mpi *N, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi b; /* Blinding value, then s + N * blinding */ + + mbedtls_mpi_init(&b); + + /* b = s + rnd-128-bit * N */ + MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&b, 16, f_rng, p_rng)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&b, &b, N)); + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&b, &b, S)); + + /* R = sign * X * b mod N */ + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(R, X, &b)); + R->s *= sign; + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(R, R, N)); + +cleanup: + mbedtls_mpi_free(&b); + + return ret; +} + +/* + * Generate and write the second round message (S: 7.4.2.5, C: 7.4.2.6) + */ +int mbedtls_ecjpake_write_round_two(mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_point G; /* C: GA, S: GB */ + mbedtls_ecp_point Xm; /* C: Xc, S: Xs */ + mbedtls_mpi xm; /* C: xc, S: xs */ + unsigned char *p = buf; + const unsigned char *end = buf + len; + size_t ec_len; + + mbedtls_ecp_point_init(&G); + mbedtls_ecp_point_init(&Xm); + mbedtls_mpi_init(&xm); + + /* + * First generate private/public key pair (S: 7.4.2.5.1, C: 7.4.2.6.1) + * + * Client: GA = X1 + X3 + X4 | xs = x2 * s | Xc = xc * GA + * Server: GB = X3 + X1 + X2 | xs = x4 * s | Xs = xs * GB + * Unified: G = Xm1 + Xp1 + Xp2 | xm = xm2 * s | Xm = xm * G + */ + MBEDTLS_MPI_CHK(ecjpake_ecp_add3(&ctx->grp, &G, + &ctx->Xp1, &ctx->Xp2, &ctx->Xm1)); + MBEDTLS_MPI_CHK(ecjpake_mul_secret(&xm, 1, &ctx->xm2, &ctx->s, + &ctx->grp.N, f_rng, p_rng)); + MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &Xm, &xm, &G, f_rng, p_rng)); + + /* + * Now write things out + * + * struct { + * ECParameters curve_params; // only server writing its message + * ECJPAKEKeyKP ecjpake_key_kp; + * } Client/ServerECJPAKEParams; + */ + if (ctx->role == MBEDTLS_ECJPAKE_SERVER) { + if (end < p) { + ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + goto cleanup; + } + MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_group(&ctx->grp, &ec_len, + p, (size_t) (end - p))); + p += ec_len; + } + + if (end < p) { + ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + goto cleanup; + } + MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(&ctx->grp, &Xm, + ctx->point_format, &ec_len, p, (size_t) (end - p))); + p += ec_len; + + MBEDTLS_MPI_CHK(ecjpake_zkp_write(ctx->md_type, &ctx->grp, + ctx->point_format, + &G, &xm, &Xm, ID_MINE, + &p, end, f_rng, p_rng)); + + *olen = (size_t) (p - buf); + +cleanup: + mbedtls_ecp_point_free(&G); + mbedtls_ecp_point_free(&Xm); + mbedtls_mpi_free(&xm); + + return ret; +} + +/* + * Derive PMS (7.4.2.7 / 7.4.2.8) + */ +static int mbedtls_ecjpake_derive_k(mbedtls_ecjpake_context *ctx, + mbedtls_ecp_point *K, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi m_xm2_s, one; + + mbedtls_mpi_init(&m_xm2_s); + mbedtls_mpi_init(&one); + + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&one, 1)); + + /* + * Client: K = ( Xs - X4 * x2 * s ) * x2 + * Server: K = ( Xc - X2 * x4 * s ) * x4 + * Unified: K = ( Xp - Xp2 * xm2 * s ) * xm2 + */ + MBEDTLS_MPI_CHK(ecjpake_mul_secret(&m_xm2_s, -1, &ctx->xm2, &ctx->s, + &ctx->grp.N, f_rng, p_rng)); + MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(&ctx->grp, K, + &one, &ctx->Xp, + &m_xm2_s, &ctx->Xp2)); + MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, K, &ctx->xm2, K, + f_rng, p_rng)); + +cleanup: + mbedtls_mpi_free(&m_xm2_s); + mbedtls_mpi_free(&one); + + return ret; +} + +int mbedtls_ecjpake_derive_secret(mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_point K; + unsigned char kx[MBEDTLS_ECP_MAX_BYTES]; + size_t x_bytes; + + *olen = mbedtls_md_get_size_from_type(ctx->md_type); + if (len < *olen) { + return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + } + + mbedtls_ecp_point_init(&K); + + ret = mbedtls_ecjpake_derive_k(ctx, &K, f_rng, p_rng); + if (ret) { + goto cleanup; + } + + /* PMS = SHA-256( K.X ) */ + x_bytes = (ctx->grp.pbits + 7) / 8; + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&K.X, kx, x_bytes)); + MBEDTLS_MPI_CHK(mbedtls_ecjpake_compute_hash(ctx->md_type, + kx, x_bytes, buf)); + +cleanup: + mbedtls_ecp_point_free(&K); + + return ret; +} + +int mbedtls_ecjpake_write_shared_key(mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_point K; + + mbedtls_ecp_point_init(&K); + + ret = mbedtls_ecjpake_derive_k(ctx, &K, f_rng, p_rng); + if (ret) { + goto cleanup; + } + + ret = mbedtls_ecp_point_write_binary(&ctx->grp, &K, ctx->point_format, + olen, buf, len); + if (ret != 0) { + goto cleanup; + } + +cleanup: + mbedtls_ecp_point_free(&K); + + return ret; +} + +#undef ID_MINE +#undef ID_PEER + +#if defined(MBEDTLS_SELF_TEST) + +#include "mbedtls/platform.h" + +#if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + !defined(PSA_WANT_ALG_SHA_256) +int mbedtls_ecjpake_self_test(int verbose) +{ + (void) verbose; + return 0; +} +#else + +static const unsigned char ecjpake_test_password[] = { + 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x6a, 0x70, 0x61, 0x6b, 0x65, 0x74, + 0x65, 0x73, 0x74 +}; + +static const unsigned char ecjpake_test_x1[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x21 +}; + +static const unsigned char ecjpake_test_x2[] = { + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, + 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81 +}; + +static const unsigned char ecjpake_test_x3[] = { + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, + 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81 +}; + +static const unsigned char ecjpake_test_x4[] = { + 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, + 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, + 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe1 +}; + +static const unsigned char ecjpake_test_cli_one[] = { + 0x41, 0x04, 0xac, 0xcf, 0x01, 0x06, 0xef, 0x85, 0x8f, 0xa2, 0xd9, 0x19, + 0x33, 0x13, 0x46, 0x80, 0x5a, 0x78, 0xb5, 0x8b, 0xba, 0xd0, 0xb8, 0x44, + 0xe5, 0xc7, 0x89, 0x28, 0x79, 0x14, 0x61, 0x87, 0xdd, 0x26, 0x66, 0xad, + 0xa7, 0x81, 0xbb, 0x7f, 0x11, 0x13, 0x72, 0x25, 0x1a, 0x89, 0x10, 0x62, + 0x1f, 0x63, 0x4d, 0xf1, 0x28, 0xac, 0x48, 0xe3, 0x81, 0xfd, 0x6e, 0xf9, + 0x06, 0x07, 0x31, 0xf6, 0x94, 0xa4, 0x41, 0x04, 0x1d, 0xd0, 0xbd, 0x5d, + 0x45, 0x66, 0xc9, 0xbe, 0xd9, 0xce, 0x7d, 0xe7, 0x01, 0xb5, 0xe8, 0x2e, + 0x08, 0xe8, 0x4b, 0x73, 0x04, 0x66, 0x01, 0x8a, 0xb9, 0x03, 0xc7, 0x9e, + 0xb9, 0x82, 0x17, 0x22, 0x36, 0xc0, 0xc1, 0x72, 0x8a, 0xe4, 0xbf, 0x73, + 0x61, 0x0d, 0x34, 0xde, 0x44, 0x24, 0x6e, 0xf3, 0xd9, 0xc0, 0x5a, 0x22, + 0x36, 0xfb, 0x66, 0xa6, 0x58, 0x3d, 0x74, 0x49, 0x30, 0x8b, 0xab, 0xce, + 0x20, 0x72, 0xfe, 0x16, 0x66, 0x29, 0x92, 0xe9, 0x23, 0x5c, 0x25, 0x00, + 0x2f, 0x11, 0xb1, 0x50, 0x87, 0xb8, 0x27, 0x38, 0xe0, 0x3c, 0x94, 0x5b, + 0xf7, 0xa2, 0x99, 0x5d, 0xda, 0x1e, 0x98, 0x34, 0x58, 0x41, 0x04, 0x7e, + 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, 0xd7, 0x92, 0x62, + 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, 0x40, 0x9a, 0xc5, + 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, 0x79, 0x0a, 0xeb, + 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, 0xd1, 0xc3, 0x35, + 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, 0xe3, 0x2b, 0xb0, + 0x13, 0xbb, 0x2b, 0x41, 0x04, 0xa4, 0x95, 0x58, 0xd3, 0x2e, 0xd1, 0xeb, + 0xfc, 0x18, 0x16, 0xaf, 0x4f, 0xf0, 0x9b, 0x55, 0xfc, 0xb4, 0xca, 0x47, + 0xb2, 0xa0, 0x2d, 0x1e, 0x7c, 0xaf, 0x11, 0x79, 0xea, 0x3f, 0xe1, 0x39, + 0x5b, 0x22, 0xb8, 0x61, 0x96, 0x40, 0x16, 0xfa, 0xba, 0xf7, 0x2c, 0x97, + 0x56, 0x95, 0xd9, 0x3d, 0x4d, 0xf0, 0xe5, 0x19, 0x7f, 0xe9, 0xf0, 0x40, + 0x63, 0x4e, 0xd5, 0x97, 0x64, 0x93, 0x77, 0x87, 0xbe, 0x20, 0xbc, 0x4d, + 0xee, 0xbb, 0xf9, 0xb8, 0xd6, 0x0a, 0x33, 0x5f, 0x04, 0x6c, 0xa3, 0xaa, + 0x94, 0x1e, 0x45, 0x86, 0x4c, 0x7c, 0xad, 0xef, 0x9c, 0xf7, 0x5b, 0x3d, + 0x8b, 0x01, 0x0e, 0x44, 0x3e, 0xf0 +}; + +static const unsigned char ecjpake_test_srv_one[] = { + 0x41, 0x04, 0x7e, 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, + 0xd7, 0x92, 0x62, 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, + 0x40, 0x9a, 0xc5, 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, + 0x79, 0x0a, 0xeb, 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, + 0xd1, 0xc3, 0x35, 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, + 0xe3, 0x2b, 0xb0, 0x13, 0xbb, 0x2b, 0x41, 0x04, 0x09, 0xf8, 0x5b, 0x3d, + 0x20, 0xeb, 0xd7, 0x88, 0x5c, 0xe4, 0x64, 0xc0, 0x8d, 0x05, 0x6d, 0x64, + 0x28, 0xfe, 0x4d, 0xd9, 0x28, 0x7a, 0xa3, 0x65, 0xf1, 0x31, 0xf4, 0x36, + 0x0f, 0xf3, 0x86, 0xd8, 0x46, 0x89, 0x8b, 0xc4, 0xb4, 0x15, 0x83, 0xc2, + 0xa5, 0x19, 0x7f, 0x65, 0xd7, 0x87, 0x42, 0x74, 0x6c, 0x12, 0xa5, 0xec, + 0x0a, 0x4f, 0xfe, 0x2f, 0x27, 0x0a, 0x75, 0x0a, 0x1d, 0x8f, 0xb5, 0x16, + 0x20, 0x93, 0x4d, 0x74, 0xeb, 0x43, 0xe5, 0x4d, 0xf4, 0x24, 0xfd, 0x96, + 0x30, 0x6c, 0x01, 0x17, 0xbf, 0x13, 0x1a, 0xfa, 0xbf, 0x90, 0xa9, 0xd3, + 0x3d, 0x11, 0x98, 0xd9, 0x05, 0x19, 0x37, 0x35, 0x14, 0x41, 0x04, 0x19, + 0x0a, 0x07, 0x70, 0x0f, 0xfa, 0x4b, 0xe6, 0xae, 0x1d, 0x79, 0xee, 0x0f, + 0x06, 0xae, 0xb5, 0x44, 0xcd, 0x5a, 0xdd, 0xaa, 0xbe, 0xdf, 0x70, 0xf8, + 0x62, 0x33, 0x21, 0x33, 0x2c, 0x54, 0xf3, 0x55, 0xf0, 0xfb, 0xfe, 0xc7, + 0x83, 0xed, 0x35, 0x9e, 0x5d, 0x0b, 0xf7, 0x37, 0x7a, 0x0f, 0xc4, 0xea, + 0x7a, 0xce, 0x47, 0x3c, 0x9c, 0x11, 0x2b, 0x41, 0xcc, 0xd4, 0x1a, 0xc5, + 0x6a, 0x56, 0x12, 0x41, 0x04, 0x36, 0x0a, 0x1c, 0xea, 0x33, 0xfc, 0xe6, + 0x41, 0x15, 0x64, 0x58, 0xe0, 0xa4, 0xea, 0xc2, 0x19, 0xe9, 0x68, 0x31, + 0xe6, 0xae, 0xbc, 0x88, 0xb3, 0xf3, 0x75, 0x2f, 0x93, 0xa0, 0x28, 0x1d, + 0x1b, 0xf1, 0xfb, 0x10, 0x60, 0x51, 0xdb, 0x96, 0x94, 0xa8, 0xd6, 0xe8, + 0x62, 0xa5, 0xef, 0x13, 0x24, 0xa3, 0xd9, 0xe2, 0x78, 0x94, 0xf1, 0xee, + 0x4f, 0x7c, 0x59, 0x19, 0x99, 0x65, 0xa8, 0xdd, 0x4a, 0x20, 0x91, 0x84, + 0x7d, 0x2d, 0x22, 0xdf, 0x3e, 0xe5, 0x5f, 0xaa, 0x2a, 0x3f, 0xb3, 0x3f, + 0xd2, 0xd1, 0xe0, 0x55, 0xa0, 0x7a, 0x7c, 0x61, 0xec, 0xfb, 0x8d, 0x80, + 0xec, 0x00, 0xc2, 0xc9, 0xeb, 0x12 +}; + +static const unsigned char ecjpake_test_srv_two[] = { + 0x03, 0x00, 0x17, 0x41, 0x04, 0x0f, 0xb2, 0x2b, 0x1d, 0x5d, 0x11, 0x23, + 0xe0, 0xef, 0x9f, 0xeb, 0x9d, 0x8a, 0x2e, 0x59, 0x0a, 0x1f, 0x4d, 0x7c, + 0xed, 0x2c, 0x2b, 0x06, 0x58, 0x6e, 0x8f, 0x2a, 0x16, 0xd4, 0xeb, 0x2f, + 0xda, 0x43, 0x28, 0xa2, 0x0b, 0x07, 0xd8, 0xfd, 0x66, 0x76, 0x54, 0xca, + 0x18, 0xc5, 0x4e, 0x32, 0xa3, 0x33, 0xa0, 0x84, 0x54, 0x51, 0xe9, 0x26, + 0xee, 0x88, 0x04, 0xfd, 0x7a, 0xf0, 0xaa, 0xa7, 0xa6, 0x41, 0x04, 0x55, + 0x16, 0xea, 0x3e, 0x54, 0xa0, 0xd5, 0xd8, 0xb2, 0xce, 0x78, 0x6b, 0x38, + 0xd3, 0x83, 0x37, 0x00, 0x29, 0xa5, 0xdb, 0xe4, 0x45, 0x9c, 0x9d, 0xd6, + 0x01, 0xb4, 0x08, 0xa2, 0x4a, 0xe6, 0x46, 0x5c, 0x8a, 0xc9, 0x05, 0xb9, + 0xeb, 0x03, 0xb5, 0xd3, 0x69, 0x1c, 0x13, 0x9e, 0xf8, 0x3f, 0x1c, 0xd4, + 0x20, 0x0f, 0x6c, 0x9c, 0xd4, 0xec, 0x39, 0x22, 0x18, 0xa5, 0x9e, 0xd2, + 0x43, 0xd3, 0xc8, 0x20, 0xff, 0x72, 0x4a, 0x9a, 0x70, 0xb8, 0x8c, 0xb8, + 0x6f, 0x20, 0xb4, 0x34, 0xc6, 0x86, 0x5a, 0xa1, 0xcd, 0x79, 0x06, 0xdd, + 0x7c, 0x9b, 0xce, 0x35, 0x25, 0xf5, 0x08, 0x27, 0x6f, 0x26, 0x83, 0x6c +}; + +static const unsigned char ecjpake_test_cli_two[] = { + 0x41, 0x04, 0x69, 0xd5, 0x4e, 0xe8, 0x5e, 0x90, 0xce, 0x3f, 0x12, 0x46, + 0x74, 0x2d, 0xe5, 0x07, 0xe9, 0x39, 0xe8, 0x1d, 0x1d, 0xc1, 0xc5, 0xcb, + 0x98, 0x8b, 0x58, 0xc3, 0x10, 0xc9, 0xfd, 0xd9, 0x52, 0x4d, 0x93, 0x72, + 0x0b, 0x45, 0x54, 0x1c, 0x83, 0xee, 0x88, 0x41, 0x19, 0x1d, 0xa7, 0xce, + 0xd8, 0x6e, 0x33, 0x12, 0xd4, 0x36, 0x23, 0xc1, 0xd6, 0x3e, 0x74, 0x98, + 0x9a, 0xba, 0x4a, 0xff, 0xd1, 0xee, 0x41, 0x04, 0x07, 0x7e, 0x8c, 0x31, + 0xe2, 0x0e, 0x6b, 0xed, 0xb7, 0x60, 0xc1, 0x35, 0x93, 0xe6, 0x9f, 0x15, + 0xbe, 0x85, 0xc2, 0x7d, 0x68, 0xcd, 0x09, 0xcc, 0xb8, 0xc4, 0x18, 0x36, + 0x08, 0x91, 0x7c, 0x5c, 0x3d, 0x40, 0x9f, 0xac, 0x39, 0xfe, 0xfe, 0xe8, + 0x2f, 0x72, 0x92, 0xd3, 0x6f, 0x0d, 0x23, 0xe0, 0x55, 0x91, 0x3f, 0x45, + 0xa5, 0x2b, 0x85, 0xdd, 0x8a, 0x20, 0x52, 0xe9, 0xe1, 0x29, 0xbb, 0x4d, + 0x20, 0x0f, 0x01, 0x1f, 0x19, 0x48, 0x35, 0x35, 0xa6, 0xe8, 0x9a, 0x58, + 0x0c, 0x9b, 0x00, 0x03, 0xba, 0xf2, 0x14, 0x62, 0xec, 0xe9, 0x1a, 0x82, + 0xcc, 0x38, 0xdb, 0xdc, 0xae, 0x60, 0xd9, 0xc5, 0x4c +}; + +static const unsigned char ecjpake_test_shared_key[] = { + 0x04, 0x01, 0xab, 0xe9, 0xf2, 0xc7, 0x3a, 0x99, 0x14, 0xcb, 0x1f, 0x80, + 0xfb, 0x9d, 0xdb, 0x7e, 0x00, 0x12, 0xa8, 0x9c, 0x2f, 0x39, 0x27, 0x79, + 0xf9, 0x64, 0x40, 0x14, 0x75, 0xea, 0xc1, 0x31, 0x28, 0x43, 0x8f, 0xe1, + 0x12, 0x41, 0xd6, 0xc1, 0xe5, 0x5f, 0x7b, 0x80, 0x88, 0x94, 0xc9, 0xc0, + 0x27, 0xa3, 0x34, 0x41, 0xf5, 0xcb, 0xa1, 0xfe, 0x6c, 0xc7, 0xe6, 0x12, + 0x17, 0xc3, 0xde, 0x27, 0xb4, +}; + +static const unsigned char ecjpake_test_pms[] = { + 0xf3, 0xd4, 0x7f, 0x59, 0x98, 0x44, 0xdb, 0x92, 0xa5, 0x69, 0xbb, 0xe7, + 0x98, 0x1e, 0x39, 0xd9, 0x31, 0xfd, 0x74, 0x3b, 0xf2, 0x2e, 0x98, 0xf9, + 0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51 +}; + +/* + * PRNG for test - !!!INSECURE NEVER USE IN PRODUCTION!!! + * + * This is the linear congruential generator from numerical recipes, + * except we only use the low byte as the output. See + * https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use + */ +static int self_test_rng(void *ctx, unsigned char *out, size_t len) +{ + static uint32_t state = 42; + + (void) ctx; + + for (size_t i = 0; i < len; i++) { + state = state * 1664525u + 1013904223u; + out[i] = (unsigned char) state; + } + + return 0; +} + +/* Load my private keys and generate the corresponding public keys */ +static int ecjpake_test_load(mbedtls_ecjpake_context *ctx, + const unsigned char *xm1, size_t len1, + const unsigned char *xm2, size_t len2) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->xm1, xm1, len1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->xm2, xm2, len2)); + MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &ctx->Xm1, &ctx->xm1, + &ctx->grp.G, self_test_rng, NULL)); + MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &ctx->Xm2, &ctx->xm2, + &ctx->grp.G, self_test_rng, NULL)); + +cleanup: + return ret; +} + +/* For tests we don't need a secure RNG; + * use the LGC from Numerical Recipes for simplicity */ +static int ecjpake_lgc(void *p, unsigned char *out, size_t len) +{ + static uint32_t x = 42; + (void) p; + + while (len > 0) { + size_t use_len = len > 4 ? 4 : len; + x = 1664525 * x + 1013904223; + memcpy(out, &x, use_len); + out += use_len; + len -= use_len; + } + + return 0; +} + +#define TEST_ASSERT(x) \ + do { \ + if (x) \ + ret = 0; \ + else \ + { \ + ret = 1; \ + goto cleanup; \ + } \ + } while (0) + +/* + * Checkup routine + */ +int mbedtls_ecjpake_self_test(int verbose) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_ecjpake_context cli; + mbedtls_ecjpake_context srv; + unsigned char buf[512], pms[32]; + size_t len, pmslen; + + mbedtls_ecjpake_init(&cli); + mbedtls_ecjpake_init(&srv); + + if (verbose != 0) { + mbedtls_printf(" ECJPAKE test #0 (setup): "); + } + + TEST_ASSERT(mbedtls_ecjpake_setup(&cli, MBEDTLS_ECJPAKE_CLIENT, + MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1, + ecjpake_test_password, + sizeof(ecjpake_test_password)) == 0); + + TEST_ASSERT(mbedtls_ecjpake_setup(&srv, MBEDTLS_ECJPAKE_SERVER, + MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1, + ecjpake_test_password, + sizeof(ecjpake_test_password)) == 0); + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + + if (verbose != 0) { + mbedtls_printf(" ECJPAKE test #1 (random handshake): "); + } + + TEST_ASSERT(mbedtls_ecjpake_write_round_one(&cli, + buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0); + + TEST_ASSERT(mbedtls_ecjpake_read_round_one(&srv, buf, len) == 0); + + TEST_ASSERT(mbedtls_ecjpake_write_round_one(&srv, + buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0); + + TEST_ASSERT(mbedtls_ecjpake_read_round_one(&cli, buf, len) == 0); + + TEST_ASSERT(mbedtls_ecjpake_write_round_two(&srv, + buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0); + + TEST_ASSERT(mbedtls_ecjpake_read_round_two(&cli, buf, len) == 0); + + TEST_ASSERT(mbedtls_ecjpake_derive_secret(&cli, + pms, sizeof(pms), &pmslen, ecjpake_lgc, NULL) == 0); + + TEST_ASSERT(mbedtls_ecjpake_write_round_two(&cli, + buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0); + + TEST_ASSERT(mbedtls_ecjpake_read_round_two(&srv, buf, len) == 0); + + TEST_ASSERT(mbedtls_ecjpake_derive_secret(&srv, + buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0); + + TEST_ASSERT(len == pmslen); + TEST_ASSERT(memcmp(buf, pms, len) == 0); + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + + /* 'reference handshake' tests can only be run against implementations + * for which we have 100% control over how the random ephemeral keys + * are generated. This is only the case for the internal Mbed TLS + * implementation, so these tests are skipped in case the internal + * implementation is swapped out for an alternative one. */ + if (verbose != 0) { + mbedtls_printf(" ECJPAKE test #2 (reference handshake): "); + } + + /* Simulate generation of round one */ + MBEDTLS_MPI_CHK(ecjpake_test_load(&cli, + ecjpake_test_x1, sizeof(ecjpake_test_x1), + ecjpake_test_x2, sizeof(ecjpake_test_x2))); + + MBEDTLS_MPI_CHK(ecjpake_test_load(&srv, + ecjpake_test_x3, sizeof(ecjpake_test_x3), + ecjpake_test_x4, sizeof(ecjpake_test_x4))); + + /* Read round one */ + TEST_ASSERT(mbedtls_ecjpake_read_round_one(&srv, + ecjpake_test_cli_one, + sizeof(ecjpake_test_cli_one)) == 0); + + TEST_ASSERT(mbedtls_ecjpake_read_round_one(&cli, + ecjpake_test_srv_one, + sizeof(ecjpake_test_srv_one)) == 0); + + /* Skip generation of round two, read round two */ + TEST_ASSERT(mbedtls_ecjpake_read_round_two(&cli, + ecjpake_test_srv_two, + sizeof(ecjpake_test_srv_two)) == 0); + + TEST_ASSERT(mbedtls_ecjpake_read_round_two(&srv, + ecjpake_test_cli_two, + sizeof(ecjpake_test_cli_two)) == 0); + + /* Server derives PMS */ + TEST_ASSERT(mbedtls_ecjpake_derive_secret(&srv, + buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0); + + TEST_ASSERT(len == sizeof(ecjpake_test_pms)); + TEST_ASSERT(memcmp(buf, ecjpake_test_pms, len) == 0); + + /* Server derives K as unsigned binary data */ + TEST_ASSERT(mbedtls_ecjpake_write_shared_key(&srv, + buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0); + + TEST_ASSERT(len == sizeof(ecjpake_test_shared_key)); + TEST_ASSERT(memcmp(buf, ecjpake_test_shared_key, len) == 0); + + memset(buf, 0, len); /* Avoid interferences with next step */ + + /* Client derives PMS */ + TEST_ASSERT(mbedtls_ecjpake_derive_secret(&cli, + buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0); + + TEST_ASSERT(len == sizeof(ecjpake_test_pms)); + TEST_ASSERT(memcmp(buf, ecjpake_test_pms, len) == 0); + + /* Client derives K as unsigned binary data */ + TEST_ASSERT(mbedtls_ecjpake_write_shared_key(&cli, + buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0); + + TEST_ASSERT(len == sizeof(ecjpake_test_shared_key)); + TEST_ASSERT(memcmp(buf, ecjpake_test_shared_key, len) == 0); + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + +cleanup: + mbedtls_ecjpake_free(&cli); + mbedtls_ecjpake_free(&srv); + + if (ret != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + ret = 1; + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + return ret; +} + +#undef TEST_ASSERT + +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && PSA_WANT_ALG_SHA_256 */ + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ECJPAKE_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/ecp.c b/tf-psa-crypto/drivers/builtin/src/ecp.c new file mode 100644 index 0000000000..fbdab4ca51 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/ecp.c @@ -0,0 +1,3519 @@ +/* + * Elliptic curves over GF(p): generic functions + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +/* + * References: + * + * SEC1 https://www.secg.org/sec1-v2.pdf + * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone + * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf + * RFC 4492 for the related TLS structures and constants + * - https://www.rfc-editor.org/rfc/rfc4492 + * RFC 7748 for the Curve448 and Curve25519 curve definitions + * - https://www.rfc-editor.org/rfc/rfc7748 + * + * [Curve25519] https://cr.yp.to/ecdh/curve25519-20060209.pdf + * + * [2] CORON, Jean-S'ebastien. Resistance against differential power analysis + * for elliptic curve cryptosystems. In : Cryptographic Hardware and + * Embedded Systems. Springer Berlin Heidelberg, 1999. p. 292-302. + * + * + * [3] HEDABOU, Mustapha, PINEL, Pierre, et B'EN'ETEAU, Lucien. A comb method to + * render ECC resistant against Side Channel Attacks. IACR Cryptology + * ePrint Archive, 2004, vol. 2004, p. 342. + * + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_ECP_LIGHT) + +#include "mbedtls/private/ecp.h" +#include "mbedtls/ecp.h" +#include "mbedtls/threading.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#include "bn_mul.h" +#include "bignum_internal.h" +#include "ecp_invasive.h" + +#include + +#include "mbedtls/platform.h" + +#if defined(MBEDTLS_SELF_TEST) +/* + * Counts of point addition and doubling, and field multiplications. + * Used to test resistance of point multiplication to simple timing attacks. + */ +#if defined(MBEDTLS_ECP_C) +static unsigned long add_count, dbl_count; +#endif /* MBEDTLS_ECP_C */ +static unsigned long mul_count; +#endif + +#if defined(MBEDTLS_ECP_RESTARTABLE) +/* + * Maximum number of "basic operations" to be done in a row. + * + * Default value 0 means that ECC operations will not yield. + * Note that regardless of the value of ecp_max_ops, always at + * least one step is performed before yielding. + * + * Setting ecp_max_ops=1 can be suitable for testing purposes + * as it will interrupt computation at all possible points. + */ +static unsigned ecp_max_ops = 0; + +/* + * Set ecp_max_ops + */ +void mbedtls_ecp_set_max_ops(unsigned max_ops) +{ + ecp_max_ops = max_ops; +} + +/* + * Check if restart is enabled + */ +int mbedtls_ecp_restart_is_enabled(void) +{ + return ecp_max_ops != 0; +} + +/* + * Restart sub-context for ecp_mul_comb() + */ +struct mbedtls_ecp_restart_mul { + mbedtls_ecp_point R; /* current intermediate result */ + size_t i; /* current index in various loops, 0 outside */ + mbedtls_ecp_point *T; /* table for precomputed points */ + unsigned char T_size; /* number of points in table T */ + enum { /* what were we doing last time we returned? */ + ecp_rsm_init = 0, /* nothing so far, dummy initial state */ + ecp_rsm_pre_dbl, /* precompute 2^n multiples */ + ecp_rsm_pre_norm_dbl, /* normalize precomputed 2^n multiples */ + ecp_rsm_pre_add, /* precompute remaining points by adding */ + ecp_rsm_pre_norm_add, /* normalize all precomputed points */ + ecp_rsm_comb_core, /* ecp_mul_comb_core() */ + ecp_rsm_final_norm, /* do the final normalization */ + } state; +}; + +/* + * Init restart_mul sub-context + */ +static void ecp_restart_rsm_init(mbedtls_ecp_restart_mul_ctx *ctx) +{ + mbedtls_ecp_point_init(&ctx->R); + ctx->i = 0; + ctx->T = NULL; + ctx->T_size = 0; + ctx->state = ecp_rsm_init; +} + +/* + * Free the components of a restart_mul sub-context + */ +static void ecp_restart_rsm_free(mbedtls_ecp_restart_mul_ctx *ctx) +{ + unsigned char i; + + if (ctx == NULL) { + return; + } + + mbedtls_ecp_point_free(&ctx->R); + + if (ctx->T != NULL) { + for (i = 0; i < ctx->T_size; i++) { + mbedtls_ecp_point_free(ctx->T + i); + } + mbedtls_free(ctx->T); + } + + ecp_restart_rsm_init(ctx); +} + +/* + * Restart context for ecp_muladd() + */ +struct mbedtls_ecp_restart_muladd { + mbedtls_ecp_point mP; /* mP value */ + mbedtls_ecp_point R; /* R intermediate result */ + enum { /* what should we do next? */ + ecp_rsma_mul1 = 0, /* first multiplication */ + ecp_rsma_mul2, /* second multiplication */ + ecp_rsma_add, /* addition */ + ecp_rsma_norm, /* normalization */ + } state; +}; + +/* + * Init restart_muladd sub-context + */ +static void ecp_restart_ma_init(mbedtls_ecp_restart_muladd_ctx *ctx) +{ + mbedtls_ecp_point_init(&ctx->mP); + mbedtls_ecp_point_init(&ctx->R); + ctx->state = ecp_rsma_mul1; +} + +/* + * Free the components of a restart_muladd sub-context + */ +static void ecp_restart_ma_free(mbedtls_ecp_restart_muladd_ctx *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_ecp_point_free(&ctx->mP); + mbedtls_ecp_point_free(&ctx->R); + + ecp_restart_ma_init(ctx); +} + +/* + * Initialize a restart context + */ +void mbedtls_ecp_restart_init(mbedtls_ecp_restart_ctx *ctx) +{ + ctx->ops_done = 0; + ctx->depth = 0; + ctx->rsm = NULL; + ctx->ma = NULL; +} + +/* + * Free the components of a restart context + */ +void mbedtls_ecp_restart_free(mbedtls_ecp_restart_ctx *ctx) +{ + if (ctx == NULL) { + return; + } + + ecp_restart_rsm_free(ctx->rsm); + mbedtls_free(ctx->rsm); + + ecp_restart_ma_free(ctx->ma); + mbedtls_free(ctx->ma); + + mbedtls_ecp_restart_init(ctx); +} + +/* + * Check if we can do the next step + */ +int mbedtls_ecp_check_budget(const mbedtls_ecp_group *grp, + mbedtls_ecp_restart_ctx *rs_ctx, + unsigned ops) +{ + if (rs_ctx != NULL && ecp_max_ops != 0) { + /* scale depending on curve size: the chosen reference is 256-bit, + * and multiplication is quadratic. Round to the closest integer. */ + if (grp->pbits >= 512) { + ops *= 4; + } else if (grp->pbits >= 384) { + ops *= 2; + } + + /* Avoid infinite loops: always allow first step. + * Because of that, however, it's not generally true + * that ops_done <= ecp_max_ops, so the check + * ops_done > ecp_max_ops below is mandatory. */ + if ((rs_ctx->ops_done != 0) && + (rs_ctx->ops_done > ecp_max_ops || + ops > ecp_max_ops - rs_ctx->ops_done)) { + return MBEDTLS_ERR_ECP_IN_PROGRESS; + } + + /* update running count */ + rs_ctx->ops_done += ops; + } + + return 0; +} + +/* Call this when entering a function that needs its own sub-context */ +#define ECP_RS_ENTER(SUB) do { \ + /* reset ops count for this call if top-level */ \ + if (rs_ctx != NULL && rs_ctx->depth++ == 0) \ + rs_ctx->ops_done = 0; \ + \ + /* set up our own sub-context if needed */ \ + if (mbedtls_ecp_restart_is_enabled() && \ + rs_ctx != NULL && rs_ctx->SUB == NULL) \ + { \ + rs_ctx->SUB = mbedtls_calloc(1, sizeof(*rs_ctx->SUB)); \ + if (rs_ctx->SUB == NULL) \ + return MBEDTLS_ERR_ECP_ALLOC_FAILED; \ + \ + ecp_restart_## SUB ##_init(rs_ctx->SUB); \ + } \ +} while (0) + +/* Call this when leaving a function that needs its own sub-context */ +#define ECP_RS_LEAVE(SUB) do { \ + /* clear our sub-context when not in progress (done or error) */ \ + if (rs_ctx != NULL && rs_ctx->SUB != NULL && \ + ret != MBEDTLS_ERR_ECP_IN_PROGRESS) \ + { \ + ecp_restart_## SUB ##_free(rs_ctx->SUB); \ + mbedtls_free(rs_ctx->SUB); \ + rs_ctx->SUB = NULL; \ + } \ + \ + if (rs_ctx != NULL) \ + rs_ctx->depth--; \ +} while (0) + +#else /* MBEDTLS_ECP_RESTARTABLE */ + +#define ECP_RS_ENTER(sub) (void) rs_ctx; +#define ECP_RS_LEAVE(sub) (void) rs_ctx; + +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +#if defined(MBEDTLS_ECP_C) +static void mpi_init_many(mbedtls_mpi *arr, size_t size) +{ + while (size--) { + mbedtls_mpi_init(arr++); + } +} + +static void mpi_free_many(mbedtls_mpi *arr, size_t size) +{ + while (size--) { + mbedtls_mpi_free(arr++); + } +} +#endif /* MBEDTLS_ECP_C */ + +/* + * List of supported curves: + * - internal ID + * - TLS NamedCurve ID (RFC 4492 sec. 5.1.1, RFC 7071 sec. 2, RFC 8446 sec. 4.2.7) + * - size in bits + * - readable name + * + * Curves are listed in order: largest curves first, and for a given size, + * fastest curves first. + * + * Reminder: update profiles in x509_crt.c and ssl_tls.c when adding a new curve! + */ +static const mbedtls_ecp_curve_info ecp_supported_curves[] = +{ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + { MBEDTLS_ECP_DP_SECP521R1, 25, 521, "secp521r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + { MBEDTLS_ECP_DP_BP512R1, 28, 512, "brainpoolP512r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + { MBEDTLS_ECP_DP_SECP384R1, 24, 384, "secp384r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + { MBEDTLS_ECP_DP_BP384R1, 27, 384, "brainpoolP384r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + { MBEDTLS_ECP_DP_SECP256R1, 23, 256, "secp256r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + { MBEDTLS_ECP_DP_SECP256K1, 22, 256, "secp256k1" }, +#endif +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + { MBEDTLS_ECP_DP_BP256R1, 26, 256, "brainpoolP256r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + { MBEDTLS_ECP_DP_CURVE25519, 29, 256, "x25519" }, +#endif +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + { MBEDTLS_ECP_DP_CURVE448, 30, 448, "x448" }, +#endif + { MBEDTLS_ECP_DP_NONE, 0, 0, NULL }, +}; + +#define ECP_NB_CURVES sizeof(ecp_supported_curves) / \ + sizeof(ecp_supported_curves[0]) + +static mbedtls_ecp_group_id ecp_supported_grp_id[ECP_NB_CURVES]; + +/* + * List of supported curves and associated info + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list(void) +{ + return ecp_supported_curves; +} + +/* + * List of supported curves, group ID only + */ +const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list(void) +{ + static int init_done = 0; + + if (!init_done) { + size_t i = 0; + const mbedtls_ecp_curve_info *curve_info; + + for (curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++) { + ecp_supported_grp_id[i++] = curve_info->grp_id; + } + ecp_supported_grp_id[i] = MBEDTLS_ECP_DP_NONE; + + init_done = 1; + } + + return ecp_supported_grp_id; +} + +/* + * Get the curve info for the internal identifier + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id(mbedtls_ecp_group_id grp_id) +{ + const mbedtls_ecp_curve_info *curve_info; + + for (curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++) { + if (curve_info->grp_id == grp_id) { + return curve_info; + } + } + + return NULL; +} + +/* + * Get the curve info from the TLS identifier + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id(uint16_t tls_id) +{ + const mbedtls_ecp_curve_info *curve_info; + + for (curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++) { + if (curve_info->tls_id == tls_id) { + return curve_info; + } + } + + return NULL; +} + +/* + * Get the curve info from the name + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name(const char *name) +{ + const mbedtls_ecp_curve_info *curve_info; + + if (name == NULL) { + return NULL; + } + + for (curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++) { + if (strcmp(curve_info->name, name) == 0) { + return curve_info; + } + } + + return NULL; +} + +/* + * Get the type of a curve + */ +mbedtls_ecp_curve_type mbedtls_ecp_get_type(const mbedtls_ecp_group *grp) +{ + if (grp->G.X.p == NULL) { + return MBEDTLS_ECP_TYPE_NONE; + } + + if (grp->G.Y.p == NULL) { + return MBEDTLS_ECP_TYPE_MONTGOMERY; + } else { + return MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS; + } +} + +/* + * Initialize (the components of) a point + */ +void mbedtls_ecp_point_init(mbedtls_ecp_point *pt) +{ + mbedtls_mpi_init(&pt->X); + mbedtls_mpi_init(&pt->Y); + mbedtls_mpi_init(&pt->Z); +} + +/* + * Initialize (the components of) a group + */ +void mbedtls_ecp_group_init(mbedtls_ecp_group *grp) +{ + grp->id = MBEDTLS_ECP_DP_NONE; + mbedtls_mpi_init(&grp->P); + mbedtls_mpi_init(&grp->A); + mbedtls_mpi_init(&grp->B); + mbedtls_ecp_point_init(&grp->G); + mbedtls_mpi_init(&grp->N); + grp->pbits = 0; + grp->nbits = 0; + grp->h = 0; + grp->modp = NULL; + grp->t_pre = NULL; + grp->t_post = NULL; + grp->t_data = NULL; + grp->T = NULL; + grp->T_size = 0; +} + +/* + * Initialize (the components of) a key pair + */ +void mbedtls_ecp_keypair_init(mbedtls_ecp_keypair *key) +{ + mbedtls_ecp_group_init(&key->grp); + mbedtls_mpi_init(&key->d); + mbedtls_ecp_point_init(&key->Q); +} + +/* + * Unallocate (the components of) a point + */ +void mbedtls_ecp_point_free(mbedtls_ecp_point *pt) +{ + if (pt == NULL) { + return; + } + + mbedtls_mpi_free(&(pt->X)); + mbedtls_mpi_free(&(pt->Y)); + mbedtls_mpi_free(&(pt->Z)); +} + +/* + * Check that the comb table (grp->T) is static initialized. + */ +static int ecp_group_is_static_comb_table(const mbedtls_ecp_group *grp) +{ +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 + return grp->T != NULL && grp->T_size == 0; +#else + (void) grp; + return 0; +#endif +} + +/* + * Unallocate (the components of) a group + */ +void mbedtls_ecp_group_free(mbedtls_ecp_group *grp) +{ + size_t i; + + if (grp == NULL) { + return; + } + + if (grp->h != 1) { + mbedtls_mpi_free(&grp->A); + mbedtls_mpi_free(&grp->B); + mbedtls_ecp_point_free(&grp->G); + +#if !defined(MBEDTLS_ECP_WITH_MPI_UINT) + mbedtls_mpi_free(&grp->N); + mbedtls_mpi_free(&grp->P); +#endif + } + + if (!ecp_group_is_static_comb_table(grp) && grp->T != NULL) { + for (i = 0; i < grp->T_size; i++) { + mbedtls_ecp_point_free(&grp->T[i]); + } + mbedtls_free(grp->T); + } + + mbedtls_platform_zeroize(grp, sizeof(mbedtls_ecp_group)); +} + +/* + * Unallocate (the components of) a key pair + */ +void mbedtls_ecp_keypair_free(mbedtls_ecp_keypair *key) +{ + if (key == NULL) { + return; + } + + mbedtls_ecp_group_free(&key->grp); + mbedtls_mpi_free(&key->d); + mbedtls_ecp_point_free(&key->Q); +} + +/* + * Copy the contents of a point + */ +int mbedtls_ecp_copy(mbedtls_ecp_point *P, const mbedtls_ecp_point *Q) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&P->X, &Q->X)); + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&P->Y, &Q->Y)); + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&P->Z, &Q->Z)); + +cleanup: + return ret; +} + +/* + * Copy the contents of a group object + */ +int mbedtls_ecp_group_copy(mbedtls_ecp_group *dst, const mbedtls_ecp_group *src) +{ + return mbedtls_ecp_group_load(dst, src->id); +} + +/* + * Set point to zero + */ +int mbedtls_ecp_set_zero(mbedtls_ecp_point *pt) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->X, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Y, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 0)); + +cleanup: + return ret; +} + +/* + * Tell if a point is zero + */ +int mbedtls_ecp_is_zero(mbedtls_ecp_point *pt) +{ + return mbedtls_mpi_cmp_int(&pt->Z, 0) == 0; +} + +/* + * Compare two points lazily + */ +int mbedtls_ecp_point_cmp(const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q) +{ + if (mbedtls_mpi_cmp_mpi(&P->X, &Q->X) == 0 && + mbedtls_mpi_cmp_mpi(&P->Y, &Q->Y) == 0 && + mbedtls_mpi_cmp_mpi(&P->Z, &Q->Z) == 0) { + return 0; + } + + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; +} + +/* + * Import a non-zero point from ASCII strings + */ +int mbedtls_ecp_point_read_string(mbedtls_ecp_point *P, int radix, + const char *x, const char *y) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&P->X, radix, x)); + MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&P->Y, radix, y)); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&P->Z, 1)); + +cleanup: + return ret; +} + +/* + * Export a point into unsigned binary data (SEC1 2.3.3 and RFC7748) + */ +int mbedtls_ecp_point_write_binary(const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *P, + int format, size_t *olen, + unsigned char *buf, size_t buflen) +{ + int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + size_t plen; + if (format != MBEDTLS_ECP_PF_UNCOMPRESSED && + format != MBEDTLS_ECP_PF_COMPRESSED) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + plen = mbedtls_mpi_size(&grp->P); + +#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) + (void) format; /* Montgomery curves always use the same point format */ + if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { + *olen = plen; + if (buflen < *olen) { + return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary_le(&P->X, buf, plen)); + } +#endif +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) + if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { + /* + * Common case: P == 0 + */ + if (mbedtls_mpi_cmp_int(&P->Z, 0) == 0) { + if (buflen < 1) { + return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + } + + buf[0] = 0x00; + *olen = 1; + + return 0; + } + + if (format == MBEDTLS_ECP_PF_UNCOMPRESSED) { + *olen = 2 * plen + 1; + + if (buflen < *olen) { + return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + } + + buf[0] = 0x04; + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&P->X, buf + 1, plen)); + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&P->Y, buf + 1 + plen, plen)); + } else if (format == MBEDTLS_ECP_PF_COMPRESSED) { + *olen = plen + 1; + + if (buflen < *olen) { + return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + } + + buf[0] = 0x02 + mbedtls_mpi_get_bit(&P->Y, 0); + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&P->X, buf + 1, plen)); + } + } +#endif + +cleanup: + return ret; +} + +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) +static int mbedtls_ecp_sw_derive_y(const mbedtls_ecp_group *grp, + const mbedtls_mpi *X, + mbedtls_mpi *Y, + int parity_bit); +#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ + +/* + * Import a point from unsigned binary data (SEC1 2.3.4 and RFC7748) + */ +int mbedtls_ecp_point_read_binary(const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt, + const unsigned char *buf, size_t ilen) +{ + int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + size_t plen; + if (ilen < 1) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + plen = mbedtls_mpi_size(&grp->P); + +#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) + if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { + if (plen != ilen) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary_le(&pt->X, buf, plen)); + mbedtls_mpi_free(&pt->Y); + + if (grp->id == MBEDTLS_ECP_DP_CURVE25519) { + /* Set most significant bit to 0 as prescribed in RFC7748 §5 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&pt->X, plen * 8 - 1, 0)); + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 1)); + } +#endif +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) + if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { + if (buf[0] == 0x00) { + if (ilen == 1) { + return mbedtls_ecp_set_zero(pt); + } else { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + } + + if (ilen < 1 + plen) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pt->X, buf + 1, plen)); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 1)); + + if (buf[0] == 0x04) { + /* format == MBEDTLS_ECP_PF_UNCOMPRESSED */ + if (ilen != 1 + plen * 2) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + return mbedtls_mpi_read_binary(&pt->Y, buf + 1 + plen, plen); + } else if (buf[0] == 0x02 || buf[0] == 0x03) { + /* format == MBEDTLS_ECP_PF_COMPRESSED */ + if (ilen != 1 + plen) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + return mbedtls_ecp_sw_derive_y(grp, &pt->X, &pt->Y, + (buf[0] & 1)); + } else { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + } +#endif + +cleanup: + return ret; +} + +/* + * Import a point from a TLS ECPoint record (RFC 4492) + * struct { + * opaque point <1..2^8-1>; + * } ECPoint; + */ +int mbedtls_ecp_tls_read_point(const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt, + const unsigned char **buf, size_t buf_len) +{ + unsigned char data_len; + const unsigned char *buf_start; + /* + * We must have at least two bytes (1 for length, at least one for data) + */ + if (buf_len < 2) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + data_len = *(*buf)++; + if (data_len < 1 || data_len > buf_len - 1) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* + * Save buffer start for read_binary and update buf + */ + buf_start = *buf; + *buf += data_len; + + return mbedtls_ecp_point_read_binary(grp, pt, buf_start, data_len); +} + +/* + * Export a point as a TLS ECPoint record (RFC 4492) + * struct { + * opaque point <1..2^8-1>; + * } ECPoint; + */ +int mbedtls_ecp_tls_write_point(const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt, + int format, size_t *olen, + unsigned char *buf, size_t blen) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + if (format != MBEDTLS_ECP_PF_UNCOMPRESSED && + format != MBEDTLS_ECP_PF_COMPRESSED) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* + * buffer length must be at least one, for our length byte + */ + if (blen < 1) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + if ((ret = mbedtls_ecp_point_write_binary(grp, pt, format, + olen, buf + 1, blen - 1)) != 0) { + return ret; + } + + /* + * write length to the first byte and update total length + */ + buf[0] = (unsigned char) *olen; + ++*olen; + + return 0; +} + +/* + * Set a group from an ECParameters record (RFC 4492) + */ +int mbedtls_ecp_tls_read_group(mbedtls_ecp_group *grp, + const unsigned char **buf, size_t len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_group_id grp_id; + if ((ret = mbedtls_ecp_tls_read_group_id(&grp_id, buf, len)) != 0) { + return ret; + } + + return mbedtls_ecp_group_load(grp, grp_id); +} + +/* + * Read a group id from an ECParameters record (RFC 4492) and convert it to + * mbedtls_ecp_group_id. + */ +int mbedtls_ecp_tls_read_group_id(mbedtls_ecp_group_id *grp, + const unsigned char **buf, size_t len) +{ + uint16_t tls_id; + const mbedtls_ecp_curve_info *curve_info; + /* + * We expect at least three bytes (see below) + */ + if (len < 3) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* + * First byte is curve_type; only named_curve is handled + */ + if (*(*buf)++ != MBEDTLS_ECP_TLS_NAMED_CURVE) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* + * Next two bytes are the namedcurve value + */ + tls_id = MBEDTLS_GET_UINT16_BE(*buf, 0); + *buf += 2; + + if ((curve_info = mbedtls_ecp_curve_info_from_tls_id(tls_id)) == NULL) { + return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + } + + *grp = curve_info->grp_id; + + return 0; +} + +/* + * Write the ECParameters record corresponding to a group (RFC 4492) + */ +int mbedtls_ecp_tls_write_group(const mbedtls_ecp_group *grp, size_t *olen, + unsigned char *buf, size_t blen) +{ + const mbedtls_ecp_curve_info *curve_info; + if ((curve_info = mbedtls_ecp_curve_info_from_grp_id(grp->id)) == NULL) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* + * We are going to write 3 bytes (see below) + */ + *olen = 3; + if (blen < *olen) { + return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + } + + /* + * First byte is curve_type, always named_curve + */ + *buf++ = MBEDTLS_ECP_TLS_NAMED_CURVE; + + /* + * Next two bytes are the namedcurve value + */ + MBEDTLS_PUT_UINT16_BE(curve_info->tls_id, buf, 0); + + return 0; +} + +/* + * Wrapper around fast quasi-modp functions, with fall-back to mbedtls_mpi_mod_mpi. + * See the documentation of struct mbedtls_ecp_group. + * + * This function is in the critial loop for mbedtls_ecp_mul, so pay attention to perf. + */ +static int ecp_modp(mbedtls_mpi *N, const mbedtls_ecp_group *grp) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if (grp->modp == NULL) { + return mbedtls_mpi_mod_mpi(N, N, &grp->P); + } + + /* N->s < 0 is a much faster test, which fails only if N is 0 */ + if ((N->s < 0 && mbedtls_mpi_cmp_int(N, 0) != 0) || + mbedtls_mpi_bitlen(N) > 2 * grp->pbits) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + MBEDTLS_MPI_CHK(grp->modp(N)); + + /* N->s < 0 is a much faster test, which fails only if N is 0 */ + while (N->s < 0 && mbedtls_mpi_cmp_int(N, 0) != 0) { + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(N, N, &grp->P)); + } + + while (mbedtls_mpi_cmp_mpi(N, &grp->P) >= 0) { + /* we known P, N and the result are positive */ + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(N, N, &grp->P)); + } + +cleanup: + return ret; +} + +/* + * Fast mod-p functions expect their argument to be in the 0..p^2 range. + * + * In order to guarantee that, we need to ensure that operands of + * mbedtls_mpi_mul_mpi are in the 0..p range. So, after each operation we will + * bring the result back to this range. + * + * The following macros are shortcuts for doing that. + */ + +/* + * Reduce a mbedtls_mpi mod p in-place, general case, to use after mbedtls_mpi_mul_mpi + */ +#if defined(MBEDTLS_SELF_TEST) +#define INC_MUL_COUNT mul_count++; +#else +#define INC_MUL_COUNT +#endif + +#define MOD_MUL(N) \ + do \ + { \ + MBEDTLS_MPI_CHK(ecp_modp(&(N), grp)); \ + INC_MUL_COUNT \ + } while (0) + +static inline int mbedtls_mpi_mul_mod(const mbedtls_ecp_group *grp, + mbedtls_mpi *X, + const mbedtls_mpi *A, + const mbedtls_mpi *B) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(X, A, B)); + MOD_MUL(*X); +cleanup: + return ret; +} + +/* + * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_sub_mpi + * N->s < 0 is a very fast test, which fails only if N is 0 + */ +#define MOD_SUB(N) \ + do { \ + while ((N)->s < 0 && mbedtls_mpi_cmp_int((N), 0) != 0) \ + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi((N), (N), &grp->P)); \ + } while (0) + +MBEDTLS_MAYBE_UNUSED +static inline int mbedtls_mpi_sub_mod(const mbedtls_ecp_group *grp, + mbedtls_mpi *X, + const mbedtls_mpi *A, + const mbedtls_mpi *B) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(X, A, B)); + MOD_SUB(X); +cleanup: + return ret; +} + +/* + * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_add_mpi and mbedtls_mpi_mul_int. + * We known P, N and the result are positive, so sub_abs is correct, and + * a bit faster. + */ +#define MOD_ADD(N) \ + while (mbedtls_mpi_cmp_mpi((N), &grp->P) >= 0) \ + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs((N), (N), &grp->P)) + +static inline int mbedtls_mpi_add_mod(const mbedtls_ecp_group *grp, + mbedtls_mpi *X, + const mbedtls_mpi *A, + const mbedtls_mpi *B) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(X, A, B)); + MOD_ADD(X); +cleanup: + return ret; +} + +MBEDTLS_MAYBE_UNUSED +static inline int mbedtls_mpi_mul_int_mod(const mbedtls_ecp_group *grp, + mbedtls_mpi *X, + const mbedtls_mpi *A, + mbedtls_mpi_uint c) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(X, A, c)); + MOD_ADD(X); +cleanup: + return ret; +} + +MBEDTLS_MAYBE_UNUSED +static inline int mbedtls_mpi_sub_int_mod(const mbedtls_ecp_group *grp, + mbedtls_mpi *X, + const mbedtls_mpi *A, + mbedtls_mpi_uint c) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(X, A, c)); + MOD_SUB(X); +cleanup: + return ret; +} + +#define MPI_ECP_SUB_INT(X, A, c) \ + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int_mod(grp, X, A, c)) + +MBEDTLS_MAYBE_UNUSED +static inline int mbedtls_mpi_shift_l_mod(const mbedtls_ecp_group *grp, + mbedtls_mpi *X, + size_t count) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(X, count)); + MOD_ADD(X); +cleanup: + return ret; +} + +/* + * Macro wrappers around ECP modular arithmetic + * + * Currently, these wrappers are defined via the bignum module. + */ + +#define MPI_ECP_ADD(X, A, B) \ + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, X, A, B)) + +#define MPI_ECP_SUB(X, A, B) \ + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, X, A, B)) + +#define MPI_ECP_MUL(X, A, B) \ + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, X, A, B)) + +#define MPI_ECP_SQR(X, A) \ + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, X, A, A)) + +#define MPI_ECP_MUL_INT(X, A, c) \ + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int_mod(grp, X, A, c)) + +#define MPI_ECP_INV(dst, src) \ + MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(NULL, (dst), (src), &grp->P)) + +#define MPI_ECP_MOV(X, A) \ + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A)) + +#define MPI_ECP_SHIFT_L(X, count) \ + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l_mod(grp, X, count)) + +#define MPI_ECP_LSET(X, c) \ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, c)) + +#define MPI_ECP_CMP_INT(X, c) \ + mbedtls_mpi_cmp_int(X, c) + +#define MPI_ECP_CMP(X, Y) \ + mbedtls_mpi_cmp_mpi(X, Y) + +/* Needs f_rng, p_rng to be defined. */ +#define MPI_ECP_RAND(X) \ + MBEDTLS_MPI_CHK(mbedtls_mpi_random((X), 2, &grp->P, f_rng, p_rng)) + +/* Conditional negation + * Needs grp and a temporary MPI tmp to be defined. */ +#define MPI_ECP_COND_NEG(X, cond) \ + do \ + { \ + unsigned char nonzero = mbedtls_mpi_cmp_int((X), 0) != 0; \ + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&tmp, &grp->P, (X))); \ + MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign((X), &tmp, \ + nonzero & cond)); \ + } while (0) + +#define MPI_ECP_NEG(X) MPI_ECP_COND_NEG((X), 1) + +#define MPI_ECP_VALID(X) \ + ((X)->p != NULL) + +#define MPI_ECP_COND_ASSIGN(X, Y, cond) \ + MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign((X), (Y), (cond))) + +#define MPI_ECP_COND_SWAP(X, Y, cond) \ + MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap((X), (Y), (cond))) + +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) + +/* + * Computes the right-hand side of the Short Weierstrass equation + * RHS = X^3 + A X + B + */ +static int ecp_sw_rhs(const mbedtls_ecp_group *grp, + mbedtls_mpi *rhs, + const mbedtls_mpi *X) +{ + int ret; + + /* Compute X^3 + A X + B as X (X^2 + A) + B */ + MPI_ECP_SQR(rhs, X); + + /* Special case for A = -3 */ + if (mbedtls_ecp_group_a_is_minus_3(grp)) { + MPI_ECP_SUB_INT(rhs, rhs, 3); + } else { + MPI_ECP_ADD(rhs, rhs, &grp->A); + } + + MPI_ECP_MUL(rhs, rhs, X); + MPI_ECP_ADD(rhs, rhs, &grp->B); + +cleanup: + return ret; +} + +/* + * Derive Y from X and a parity bit + */ +static int mbedtls_ecp_sw_derive_y(const mbedtls_ecp_group *grp, + const mbedtls_mpi *X, + mbedtls_mpi *Y, + int parity_bit) +{ + /* w = y^2 = x^3 + ax + b + * y = sqrt(w) = w^((p+1)/4) mod p (for prime p where p = 3 mod 4) + * + * Note: this method for extracting square root does not validate that w + * was indeed a square so this function will return garbage in Y if X + * does not correspond to a point on the curve. + */ + + /* Check prerequisite p = 3 mod 4 */ + if (mbedtls_mpi_get_bit(&grp->P, 0) != 1 || + mbedtls_mpi_get_bit(&grp->P, 1) != 1) { + return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + } + + int ret; + mbedtls_mpi exp; + mbedtls_mpi_init(&exp); + + /* use Y to store intermediate result, actually w above */ + MBEDTLS_MPI_CHK(ecp_sw_rhs(grp, Y, X)); + + /* w = y^2 */ /* Y contains y^2 intermediate result */ + /* exp = ((p+1)/4) */ + MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&exp, &grp->P, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&exp, 2)); + /* sqrt(w) = w^((p+1)/4) mod p (for prime p where p = 3 mod 4) */ + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(Y, Y /*y^2*/, &exp, &grp->P, NULL)); + + /* check parity bit match or else invert Y */ + /* This quick inversion implementation is valid because Y != 0 for all + * Short Weierstrass curves supported by mbedtls, as each supported curve + * has an order that is a large prime, so each supported curve does not + * have any point of order 2, and a point with Y == 0 would be of order 2 */ + if (mbedtls_mpi_get_bit(Y, 0) != parity_bit) { + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(Y, &grp->P, Y)); + } + +cleanup: + + mbedtls_mpi_free(&exp); + return ret; +} +#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ + +#if defined(MBEDTLS_ECP_C) +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) +/* + * For curves in short Weierstrass form, we do all the internal operations in + * Jacobian coordinates. + * + * For multiplication, we'll use a comb method with countermeasures against + * SPA, hence timing attacks. + */ + +/* + * Normalize jacobian coordinates so that Z == 0 || Z == 1 (GECC 3.2.1) + * Cost: 1N := 1I + 3M + 1S + */ +static int ecp_normalize_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt) +{ + if (MPI_ECP_CMP_INT(&pt->Z, 0) == 0) { + return 0; + } + + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi T; + mbedtls_mpi_init(&T); + + MPI_ECP_INV(&T, &pt->Z); /* T <- 1 / Z */ + MPI_ECP_MUL(&pt->Y, &pt->Y, &T); /* Y' <- Y*T = Y / Z */ + MPI_ECP_SQR(&T, &T); /* T <- T^2 = 1 / Z^2 */ + MPI_ECP_MUL(&pt->X, &pt->X, &T); /* X <- X * T = X / Z^2 */ + MPI_ECP_MUL(&pt->Y, &pt->Y, &T); /* Y'' <- Y' * T = Y / Z^3 */ + + MPI_ECP_LSET(&pt->Z, 1); + +cleanup: + + mbedtls_mpi_free(&T); + + return ret; +} + + +#if !defined(MBEDTLS_ECP_MUL_ALT) +/* + * Normalize jacobian coordinates of an array of (pointers to) points, + * using Montgomery's trick to perform only one inversion mod P. + * (See for example Cohen's "A Course in Computational Algebraic Number + * Theory", Algorithm 10.3.4.) + * + * Warning: fails (returning an error) if one of the points is zero! + * This should never happen, see choice of w in ecp_mul_comb(). + * + * Cost: 1N(t) := 1I + (6t - 3)M + 1S + */ +static int ecp_normalize_jac_many(const mbedtls_ecp_group *grp, + mbedtls_ecp_point *T[], size_t T_size) +{ + if (T_size < 2) { + return ecp_normalize_jac(grp, *T); + } + + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t i; + mbedtls_mpi *c, t; + + if ((c = mbedtls_calloc(T_size, sizeof(mbedtls_mpi))) == NULL) { + return MBEDTLS_ERR_ECP_ALLOC_FAILED; + } + + mbedtls_mpi_init(&t); + + mpi_init_many(c, T_size); + /* + * c[i] = Z_0 * ... * Z_i, i = 0,..,n := T_size-1 + */ + MPI_ECP_MOV(&c[0], &T[0]->Z); + for (i = 1; i < T_size; i++) { + MPI_ECP_MUL(&c[i], &c[i-1], &T[i]->Z); + } + + /* + * c[n] = 1 / (Z_0 * ... * Z_n) mod P + */ + MPI_ECP_INV(&c[T_size-1], &c[T_size-1]); + + for (i = T_size - 1;; i--) { + /* At the start of iteration i (note that i decrements), we have + * - c[j] = Z_0 * .... * Z_j for j < i, + * - c[j] = 1 / (Z_0 * .... * Z_j) for j == i, + * + * This is maintained via + * - c[i-1] <- c[i] * Z_i + * + * We also derive 1/Z_i = c[i] * c[i-1] for i>0 and use that + * to do the actual normalization. For i==0, we already have + * c[0] = 1 / Z_0. + */ + + if (i > 0) { + /* Compute 1/Z_i and establish invariant for the next iteration. */ + MPI_ECP_MUL(&t, &c[i], &c[i-1]); + MPI_ECP_MUL(&c[i-1], &c[i], &T[i]->Z); + } else { + MPI_ECP_MOV(&t, &c[0]); + } + + /* Now t holds 1 / Z_i; normalize as in ecp_normalize_jac() */ + MPI_ECP_MUL(&T[i]->Y, &T[i]->Y, &t); + MPI_ECP_SQR(&t, &t); + MPI_ECP_MUL(&T[i]->X, &T[i]->X, &t); + MPI_ECP_MUL(&T[i]->Y, &T[i]->Y, &t); + + /* + * Post-precessing: reclaim some memory by shrinking coordinates + * - not storing Z (always 1) + * - shrinking other coordinates, but still keeping the same number of + * limbs as P, as otherwise it will too likely be regrown too fast. + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_shrink(&T[i]->X, grp->P.n)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shrink(&T[i]->Y, grp->P.n)); + + MPI_ECP_LSET(&T[i]->Z, 1); + + if (i == 0) { + break; + } + } + +cleanup: + + mbedtls_mpi_free(&t); + mpi_free_many(c, T_size); + mbedtls_free(c); + + return ret; +} + +/* + * Conditional point inversion: Q -> -Q = (Q.X, -Q.Y, Q.Z) without leak. + * "inv" must be 0 (don't invert) or 1 (invert) or the result will be invalid + */ +static int ecp_safe_invert_jac(const mbedtls_ecp_group *grp, + mbedtls_ecp_point *Q, + unsigned char inv) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi tmp; + mbedtls_mpi_init(&tmp); + + MPI_ECP_COND_NEG(&Q->Y, inv); + +cleanup: + mbedtls_mpi_free(&tmp); + return ret; +} + +#endif /* MBEDTLS_ECP_MUL_ALT */ + +/* + * Point doubling R = 2 P, Jacobian coordinates + * + * Based on http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-1998-cmo-2 . + * + * We follow the variable naming fairly closely. The formula variations that trade a MUL for a SQR + * (plus a few ADDs) aren't useful as our bignum implementation doesn't distinguish squaring. + * + * Standard optimizations are applied when curve parameter A is one of { 0, -3 }. + * + * Cost: 1D := 3M + 4S (A == 0) + * 4M + 4S (A == -3) + * 3M + 6S + 1a otherwise + */ +static int ecp_double_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point *P, + mbedtls_mpi tmp[4]) +{ +#if defined(MBEDTLS_SELF_TEST) + dbl_count++; +#endif + + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + /* Special case for A = -3 */ + if (mbedtls_ecp_group_a_is_minus_3(grp)) { + /* tmp[0] <- M = 3(X + Z^2)(X - Z^2) */ + MPI_ECP_SQR(&tmp[1], &P->Z); + MPI_ECP_ADD(&tmp[2], &P->X, &tmp[1]); + MPI_ECP_SUB(&tmp[3], &P->X, &tmp[1]); + MPI_ECP_MUL(&tmp[1], &tmp[2], &tmp[3]); + MPI_ECP_MUL_INT(&tmp[0], &tmp[1], 3); + } else { + /* tmp[0] <- M = 3.X^2 + A.Z^4 */ + MPI_ECP_SQR(&tmp[1], &P->X); + MPI_ECP_MUL_INT(&tmp[0], &tmp[1], 3); + + /* Optimize away for "koblitz" curves with A = 0 */ + if (MPI_ECP_CMP_INT(&grp->A, 0) != 0) { + /* M += A.Z^4 */ + MPI_ECP_SQR(&tmp[1], &P->Z); + MPI_ECP_SQR(&tmp[2], &tmp[1]); + MPI_ECP_MUL(&tmp[1], &tmp[2], &grp->A); + MPI_ECP_ADD(&tmp[0], &tmp[0], &tmp[1]); + } + } + + /* tmp[1] <- S = 4.X.Y^2 */ + MPI_ECP_SQR(&tmp[2], &P->Y); + MPI_ECP_SHIFT_L(&tmp[2], 1); + MPI_ECP_MUL(&tmp[1], &P->X, &tmp[2]); + MPI_ECP_SHIFT_L(&tmp[1], 1); + + /* tmp[3] <- U = 8.Y^4 */ + MPI_ECP_SQR(&tmp[3], &tmp[2]); + MPI_ECP_SHIFT_L(&tmp[3], 1); + + /* tmp[2] <- T = M^2 - 2.S */ + MPI_ECP_SQR(&tmp[2], &tmp[0]); + MPI_ECP_SUB(&tmp[2], &tmp[2], &tmp[1]); + MPI_ECP_SUB(&tmp[2], &tmp[2], &tmp[1]); + + /* tmp[1] <- S = M(S - T) - U */ + MPI_ECP_SUB(&tmp[1], &tmp[1], &tmp[2]); + MPI_ECP_MUL(&tmp[1], &tmp[1], &tmp[0]); + MPI_ECP_SUB(&tmp[1], &tmp[1], &tmp[3]); + + /* tmp[3] <- U = 2.Y.Z */ + MPI_ECP_MUL(&tmp[3], &P->Y, &P->Z); + MPI_ECP_SHIFT_L(&tmp[3], 1); + + /* Store results */ + MPI_ECP_MOV(&R->X, &tmp[2]); + MPI_ECP_MOV(&R->Y, &tmp[1]); + MPI_ECP_MOV(&R->Z, &tmp[3]); + +cleanup: + + return ret; +} + +/* + * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22) + * + * The coordinates of Q must be normalized (= affine), + * but those of P don't need to. R is not normalized. + * + * P,Q,R may alias, but only at the level of EC points: they must be either + * equal as pointers, or disjoint (including the coordinate data buffers). + * Fine-grained aliasing at the level of coordinates is not supported. + * + * Special cases: (1) P or Q is zero, (2) R is zero, (3) P == Q. + * None of these cases can happen as intermediate step in ecp_mul_comb(): + * - at each step, P, Q and R are multiples of the base point, the factor + * being less than its order, so none of them is zero; + * - Q is an odd multiple of the base point, P an even multiple, + * due to the choice of precomputed points in the modified comb method. + * So branches for these cases do not leak secret information. + * + * Cost: 1A := 8M + 3S + */ +static int ecp_add_mixed(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q, + mbedtls_mpi tmp[4]) +{ +#if defined(MBEDTLS_SELF_TEST) + add_count++; +#endif + + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + /* NOTE: Aliasing between input and output is allowed, so one has to make + * sure that at the point X,Y,Z are written, {P,Q}->{X,Y,Z} are no + * longer read from. */ + mbedtls_mpi * const X = &R->X; + mbedtls_mpi * const Y = &R->Y; + mbedtls_mpi * const Z = &R->Z; + + if (!MPI_ECP_VALID(&Q->Z)) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* + * Trivial cases: P == 0 or Q == 0 (case 1) + */ + if (MPI_ECP_CMP_INT(&P->Z, 0) == 0) { + return mbedtls_ecp_copy(R, Q); + } + + if (MPI_ECP_CMP_INT(&Q->Z, 0) == 0) { + return mbedtls_ecp_copy(R, P); + } + + /* + * Make sure Q coordinates are normalized + */ + if (MPI_ECP_CMP_INT(&Q->Z, 1) != 0) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + MPI_ECP_SQR(&tmp[0], &P->Z); + MPI_ECP_MUL(&tmp[1], &tmp[0], &P->Z); + MPI_ECP_MUL(&tmp[0], &tmp[0], &Q->X); + MPI_ECP_MUL(&tmp[1], &tmp[1], &Q->Y); + MPI_ECP_SUB(&tmp[0], &tmp[0], &P->X); + MPI_ECP_SUB(&tmp[1], &tmp[1], &P->Y); + + /* Special cases (2) and (3) */ + if (MPI_ECP_CMP_INT(&tmp[0], 0) == 0) { + if (MPI_ECP_CMP_INT(&tmp[1], 0) == 0) { + ret = ecp_double_jac(grp, R, P, tmp); + goto cleanup; + } else { + ret = mbedtls_ecp_set_zero(R); + goto cleanup; + } + } + + /* {P,Q}->Z no longer used, so OK to write to Z even if there's aliasing. */ + MPI_ECP_MUL(Z, &P->Z, &tmp[0]); + MPI_ECP_SQR(&tmp[2], &tmp[0]); + MPI_ECP_MUL(&tmp[3], &tmp[2], &tmp[0]); + MPI_ECP_MUL(&tmp[2], &tmp[2], &P->X); + + MPI_ECP_MOV(&tmp[0], &tmp[2]); + MPI_ECP_SHIFT_L(&tmp[0], 1); + + /* {P,Q}->X no longer used, so OK to write to X even if there's aliasing. */ + MPI_ECP_SQR(X, &tmp[1]); + MPI_ECP_SUB(X, X, &tmp[0]); + MPI_ECP_SUB(X, X, &tmp[3]); + MPI_ECP_SUB(&tmp[2], &tmp[2], X); + MPI_ECP_MUL(&tmp[2], &tmp[2], &tmp[1]); + MPI_ECP_MUL(&tmp[3], &tmp[3], &P->Y); + /* {P,Q}->Y no longer used, so OK to write to Y even if there's aliasing. */ + MPI_ECP_SUB(Y, &tmp[2], &tmp[3]); + +cleanup: + + return ret; +} + +#if !defined(MBEDTLS_ECP_MUL_ALT) + +/* + * Randomize jacobian coordinates: + * (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l + * This is sort of the reverse operation of ecp_normalize_jac(). + * + * This countermeasure was first suggested in [2]. + */ +static int ecp_randomize_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi l; + + mbedtls_mpi_init(&l); + + /* Generate l such that 1 < l < p */ + MPI_ECP_RAND(&l); + + /* Z' = l * Z */ + MPI_ECP_MUL(&pt->Z, &pt->Z, &l); + + /* Y' = l * Y */ + MPI_ECP_MUL(&pt->Y, &pt->Y, &l); + + /* X' = l^2 * X */ + MPI_ECP_SQR(&l, &l); + MPI_ECP_MUL(&pt->X, &pt->X, &l); + + /* Y'' = l^2 * Y' = l^3 * Y */ + MPI_ECP_MUL(&pt->Y, &pt->Y, &l); + +cleanup: + mbedtls_mpi_free(&l); + + if (ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; + } + return ret; +} + +/* + * Check and define parameters used by the comb method (see below for details) + */ +#if MBEDTLS_ECP_WINDOW_SIZE < 2 || MBEDTLS_ECP_WINDOW_SIZE > 7 +#error "MBEDTLS_ECP_WINDOW_SIZE out of bounds" +#endif + +/* d = ceil( n / w ) */ +#define COMB_MAX_D (MBEDTLS_ECP_MAX_BITS + 1) / 2 + +/* number of precomputed points */ +#define COMB_MAX_PRE (1 << (MBEDTLS_ECP_WINDOW_SIZE - 1)) + +/* + * Compute the representation of m that will be used with our comb method. + * + * The basic comb method is described in GECC 3.44 for example. We use a + * modified version that provides resistance to SPA by avoiding zero + * digits in the representation as in [3]. We modify the method further by + * requiring that all K_i be odd, which has the small cost that our + * representation uses one more K_i, due to carries, but saves on the size of + * the precomputed table. + * + * Summary of the comb method and its modifications: + * + * - The goal is to compute m*P for some w*d-bit integer m. + * + * - The basic comb method splits m into the w-bit integers + * x[0] .. x[d-1] where x[i] consists of the bits in m whose + * index has residue i modulo d, and computes m * P as + * S[x[0]] + 2 * S[x[1]] + .. + 2^(d-1) S[x[d-1]], where + * S[i_{w-1} .. i_0] := i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + i_0 P. + * + * - If it happens that, say, x[i+1]=0 (=> S[x[i+1]]=0), one can replace the sum by + * .. + 2^{i-1} S[x[i-1]] - 2^i S[x[i]] + 2^{i+1} S[x[i]] + 2^{i+2} S[x[i+2]] .., + * thereby successively converting it into a form where all summands + * are nonzero, at the cost of negative summands. This is the basic idea of [3]. + * + * - More generally, even if x[i+1] != 0, we can first transform the sum as + * .. - 2^i S[x[i]] + 2^{i+1} ( S[x[i]] + S[x[i+1]] ) + 2^{i+2} S[x[i+2]] .., + * and then replace S[x[i]] + S[x[i+1]] = S[x[i] ^ x[i+1]] + 2 S[x[i] & x[i+1]]. + * Performing and iterating this procedure for those x[i] that are even + * (keeping track of carry), we can transform the original sum into one of the form + * S[x'[0]] +- 2 S[x'[1]] +- .. +- 2^{d-1} S[x'[d-1]] + 2^d S[x'[d]] + * with all x'[i] odd. It is therefore only necessary to know S at odd indices, + * which is why we are only computing half of it in the first place in + * ecp_precompute_comb and accessing it with index abs(i) / 2 in ecp_select_comb. + * + * - For the sake of compactness, only the seven low-order bits of x[i] + * are used to represent its absolute value (K_i in the paper), and the msb + * of x[i] encodes the sign (s_i in the paper): it is set if and only if + * if s_i == -1; + * + * Calling conventions: + * - x is an array of size d + 1 + * - w is the size, ie number of teeth, of the comb, and must be between + * 2 and 7 (in practice, between 2 and MBEDTLS_ECP_WINDOW_SIZE) + * - m is the MPI, expected to be odd and such that bitlength(m) <= w * d + * (the result will be incorrect if these assumptions are not satisfied) + */ +static void ecp_comb_recode_core(unsigned char x[], size_t d, + unsigned char w, const mbedtls_mpi *m) +{ + size_t i, j; + unsigned char c, cc, adjust; + + memset(x, 0, d+1); + + /* First get the classical comb values (except for x_d = 0) */ + for (i = 0; i < d; i++) { + for (j = 0; j < w; j++) { + x[i] |= mbedtls_mpi_get_bit(m, i + d * j) << j; + } + } + + /* Now make sure x_1 .. x_d are odd */ + c = 0; + for (i = 1; i <= d; i++) { + /* Add carry and update it */ + cc = x[i] & c; + x[i] = x[i] ^ c; + c = cc; + + /* Adjust if needed, avoiding branches */ + adjust = 1 - (x[i] & 0x01); + c |= x[i] & (x[i-1] * adjust); + x[i] = x[i] ^ (x[i-1] * adjust); + x[i-1] |= adjust << 7; + } +} + +/* + * Precompute points for the adapted comb method + * + * Assumption: T must be able to hold 2^{w - 1} elements. + * + * Operation: If i = i_{w-1} ... i_1 is the binary representation of i, + * sets T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P. + * + * Cost: d(w-1) D + (2^{w-1} - 1) A + 1 N(w-1) + 1 N(2^{w-1} - 1) + * + * Note: Even comb values (those where P would be omitted from the + * sum defining T[i] above) are not needed in our adaption + * the comb method. See ecp_comb_recode_core(). + * + * This function currently works in four steps: + * (1) [dbl] Computation of intermediate T[i] for 2-power values of i + * (2) [norm_dbl] Normalization of coordinates of these T[i] + * (3) [add] Computation of all T[i] + * (4) [norm_add] Normalization of all T[i] + * + * Step 1 can be interrupted but not the others; together with the final + * coordinate normalization they are the largest steps done at once, depending + * on the window size. Here are operation counts for P-256: + * + * step (2) (3) (4) + * w = 5 142 165 208 + * w = 4 136 77 160 + * w = 3 130 33 136 + * w = 2 124 11 124 + * + * So if ECC operations are blocking for too long even with a low max_ops + * value, it's useful to set MBEDTLS_ECP_WINDOW_SIZE to a lower value in order + * to minimize maximum blocking time. + */ +static int ecp_precompute_comb(const mbedtls_ecp_group *grp, + mbedtls_ecp_point T[], const mbedtls_ecp_point *P, + unsigned char w, size_t d, + mbedtls_ecp_restart_ctx *rs_ctx) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char i; + size_t j = 0; + const unsigned char T_size = 1U << (w - 1); + mbedtls_ecp_point *cur, *TT[COMB_MAX_PRE - 1] = { NULL }; + + mbedtls_mpi tmp[4]; + + mpi_init_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->rsm != NULL) { + if (rs_ctx->rsm->state == ecp_rsm_pre_dbl) { + goto dbl; + } + if (rs_ctx->rsm->state == ecp_rsm_pre_norm_dbl) { + goto norm_dbl; + } + if (rs_ctx->rsm->state == ecp_rsm_pre_add) { + goto add; + } + if (rs_ctx->rsm->state == ecp_rsm_pre_norm_add) { + goto norm_add; + } + } +#else + (void) rs_ctx; +#endif + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->rsm != NULL) { + rs_ctx->rsm->state = ecp_rsm_pre_dbl; + + /* initial state for the loop */ + rs_ctx->rsm->i = 0; + } + +dbl: +#endif + /* + * Set T[0] = P and + * T[2^{l-1}] = 2^{dl} P for l = 1 .. w-1 (this is not the final value) + */ + MBEDTLS_MPI_CHK(mbedtls_ecp_copy(&T[0], P)); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->i != 0) { + j = rs_ctx->rsm->i; + } else +#endif + j = 0; + + for (; j < d * (w - 1); j++) { + MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_DBL); + + i = 1U << (j / d); + cur = T + i; + + if (j % d == 0) { + MBEDTLS_MPI_CHK(mbedtls_ecp_copy(cur, T + (i >> 1))); + } + + MBEDTLS_MPI_CHK(ecp_double_jac(grp, cur, cur, tmp)); + } + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->rsm != NULL) { + rs_ctx->rsm->state = ecp_rsm_pre_norm_dbl; + } + +norm_dbl: +#endif + /* + * Normalize current elements in T to allow them to be used in + * ecp_add_mixed() below, which requires one normalized input. + * + * As T has holes, use an auxiliary array of pointers to elements in T. + * + */ + j = 0; + for (i = 1; i < T_size; i <<= 1) { + TT[j++] = T + i; + } + + MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_INV + 6 * j - 2); + + MBEDTLS_MPI_CHK(ecp_normalize_jac_many(grp, TT, j)); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->rsm != NULL) { + rs_ctx->rsm->state = ecp_rsm_pre_add; + } + +add: +#endif + /* + * Compute the remaining ones using the minimal number of additions + * Be careful to update T[2^l] only after using it! + */ + MBEDTLS_ECP_BUDGET((T_size - 1) * MBEDTLS_ECP_OPS_ADD); + + for (i = 1; i < T_size; i <<= 1) { + j = i; + while (j--) { + MBEDTLS_MPI_CHK(ecp_add_mixed(grp, &T[i + j], &T[j], &T[i], tmp)); + } + } + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->rsm != NULL) { + rs_ctx->rsm->state = ecp_rsm_pre_norm_add; + } + +norm_add: +#endif + /* + * Normalize final elements in T. Even though there are no holes now, we + * still need the auxiliary array for homogeneity with the previous + * call. Also, skip T[0] which is already normalised, being a copy of P. + */ + for (j = 0; j + 1 < T_size; j++) { + TT[j] = T + j + 1; + } + + MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_INV + 6 * j - 2); + + MBEDTLS_MPI_CHK(ecp_normalize_jac_many(grp, TT, j)); + + /* Free Z coordinate (=1 after normalization) to save RAM. + * This makes T[i] invalid as mbedtls_ecp_points, but this is OK + * since from this point onwards, they are only accessed indirectly + * via the getter function ecp_select_comb() which does set the + * target's Z coordinate to 1. */ + for (i = 0; i < T_size; i++) { + mbedtls_mpi_free(&T[i].Z); + } + +cleanup: + + mpi_free_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->rsm != NULL && + ret == MBEDTLS_ERR_ECP_IN_PROGRESS) { + if (rs_ctx->rsm->state == ecp_rsm_pre_dbl) { + rs_ctx->rsm->i = j; + } + } +#endif + + return ret; +} + +/* + * Select precomputed point: R = sign(i) * T[ abs(i) / 2 ] + * + * See ecp_comb_recode_core() for background + */ +static int ecp_select_comb(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point T[], unsigned char T_size, + unsigned char i) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char ii, j; + + /* Ignore the "sign" bit and scale down */ + ii = (i & 0x7Fu) >> 1; + + /* Read the whole table to thwart cache-based timing attacks */ + for (j = 0; j < T_size; j++) { + MPI_ECP_COND_ASSIGN(&R->X, &T[j].X, j == ii); + MPI_ECP_COND_ASSIGN(&R->Y, &T[j].Y, j == ii); + } + + /* Safely invert result if i is "negative" */ + MBEDTLS_MPI_CHK(ecp_safe_invert_jac(grp, R, i >> 7)); + + MPI_ECP_LSET(&R->Z, 1); + +cleanup: + return ret; +} + +/* + * Core multiplication algorithm for the (modified) comb method. + * This part is actually common with the basic comb method (GECC 3.44) + * + * Cost: d A + d D + 1 R + */ +static int ecp_mul_comb_core(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point T[], unsigned char T_size, + const unsigned char x[], size_t d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_point Txi; + mbedtls_mpi tmp[4]; + size_t i; + + mbedtls_ecp_point_init(&Txi); + mpi_init_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); + +#if !defined(MBEDTLS_ECP_RESTARTABLE) + (void) rs_ctx; +#endif + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->rsm != NULL && + rs_ctx->rsm->state != ecp_rsm_comb_core) { + rs_ctx->rsm->i = 0; + rs_ctx->rsm->state = ecp_rsm_comb_core; + } + + /* new 'if' instead of nested for the sake of the 'else' branch */ + if (rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->i != 0) { + /* restore current index (R already pointing to rs_ctx->rsm->R) */ + i = rs_ctx->rsm->i; + } else +#endif + { + /* Start with a non-zero point and randomize its coordinates */ + i = d; + MBEDTLS_MPI_CHK(ecp_select_comb(grp, R, T, T_size, x[i])); + if (f_rng != 0) { + MBEDTLS_MPI_CHK(ecp_randomize_jac(grp, R, f_rng, p_rng)); + } + } + + while (i != 0) { + MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_DBL + MBEDTLS_ECP_OPS_ADD); + --i; + + MBEDTLS_MPI_CHK(ecp_double_jac(grp, R, R, tmp)); + MBEDTLS_MPI_CHK(ecp_select_comb(grp, &Txi, T, T_size, x[i])); + MBEDTLS_MPI_CHK(ecp_add_mixed(grp, R, R, &Txi, tmp)); + } + +cleanup: + + mbedtls_ecp_point_free(&Txi); + mpi_free_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->rsm != NULL && + ret == MBEDTLS_ERR_ECP_IN_PROGRESS) { + rs_ctx->rsm->i = i; + /* no need to save R, already pointing to rs_ctx->rsm->R */ + } +#endif + + return ret; +} + +/* + * Recode the scalar to get constant-time comb multiplication + * + * As the actual scalar recoding needs an odd scalar as a starting point, + * this wrapper ensures that by replacing m by N - m if necessary, and + * informs the caller that the result of multiplication will be negated. + * + * This works because we only support large prime order for Short Weierstrass + * curves, so N is always odd hence either m or N - m is. + * + * See ecp_comb_recode_core() for background. + */ +static int ecp_comb_recode_scalar(const mbedtls_ecp_group *grp, + const mbedtls_mpi *m, + unsigned char k[COMB_MAX_D + 1], + size_t d, + unsigned char w, + unsigned char *parity_trick) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi M, mm; + + mbedtls_mpi_init(&M); + mbedtls_mpi_init(&mm); + + /* N is always odd (see above), just make extra sure */ + if (mbedtls_mpi_get_bit(&grp->N, 0) != 1) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* do we need the parity trick? */ + *parity_trick = (mbedtls_mpi_get_bit(m, 0) == 0); + + /* execute parity fix in constant time */ + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&M, m)); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&mm, &grp->N, m)); + MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(&M, &mm, *parity_trick)); + + /* actual scalar recoding */ + ecp_comb_recode_core(k, d, w, &M); + +cleanup: + mbedtls_mpi_free(&mm); + mbedtls_mpi_free(&M); + + return ret; +} + +/* + * Perform comb multiplication (for short Weierstrass curves) + * once the auxiliary table has been pre-computed. + * + * Scalar recoding may use a parity trick that makes us compute -m * P, + * if that is the case we'll need to recover m * P at the end. + */ +static int ecp_mul_comb_after_precomp(const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, + const mbedtls_mpi *m, + const mbedtls_ecp_point *T, + unsigned char T_size, + unsigned char w, + size_t d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char parity_trick; + unsigned char k[COMB_MAX_D + 1]; + mbedtls_ecp_point *RR = R; + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->rsm != NULL) { + RR = &rs_ctx->rsm->R; + + if (rs_ctx->rsm->state == ecp_rsm_final_norm) { + goto final_norm; + } + } +#endif + + MBEDTLS_MPI_CHK(ecp_comb_recode_scalar(grp, m, k, d, w, + &parity_trick)); + MBEDTLS_MPI_CHK(ecp_mul_comb_core(grp, RR, T, T_size, k, d, + f_rng, p_rng, rs_ctx)); + MBEDTLS_MPI_CHK(ecp_safe_invert_jac(grp, RR, parity_trick)); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->rsm != NULL) { + rs_ctx->rsm->state = ecp_rsm_final_norm; + } + +final_norm: + MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_INV); +#endif + MBEDTLS_MPI_CHK(ecp_normalize_jac(grp, RR)); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->rsm != NULL) { + MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, RR)); + } +#endif + +cleanup: + return ret; +} + +/* + * Pick window size based on curve size and whether we optimize for base point + */ +static unsigned char ecp_pick_window_size(const mbedtls_ecp_group *grp, + unsigned char p_eq_g) +{ + unsigned char w; + + /* + * Minimize the number of multiplications, that is minimize + * 10 * d * w + 18 * 2^(w-1) + 11 * d + 7 * w, with d = ceil( nbits / w ) + * (see costs of the various parts, with 1S = 1M) + */ + w = grp->nbits >= 384 ? 5 : 4; + + /* + * If P == G, pre-compute a bit more, since this may be re-used later. + * Just adding one avoids upping the cost of the first mul too much, + * and the memory cost too. + */ + if (p_eq_g) { + w++; + } + + /* + * If static comb table may not be used (!p_eq_g) or static comb table does + * not exists, make sure w is within bounds. + * (The last test is useful only for very small curves in the test suite.) + * + * The user reduces MBEDTLS_ECP_WINDOW_SIZE does not changes the size of + * static comb table, because the size of static comb table is fixed when + * it is generated. + */ +#if (MBEDTLS_ECP_WINDOW_SIZE < 6) + if ((!p_eq_g || !ecp_group_is_static_comb_table(grp)) && w > MBEDTLS_ECP_WINDOW_SIZE) { + w = MBEDTLS_ECP_WINDOW_SIZE; + } +#endif + if (w >= grp->nbits) { + w = 2; + } + + return w; +} + +/* + * Multiplication using the comb method - for curves in short Weierstrass form + * + * This function is mainly responsible for administrative work: + * - managing the restart context if enabled + * - managing the table of precomputed points (passed between the below two + * functions): allocation, computation, ownership transfer, freeing. + * + * It delegates the actual arithmetic work to: + * ecp_precompute_comb() and ecp_mul_comb_with_precomp() + * + * See comments on ecp_comb_recode_core() regarding the computation strategy. + */ +static int ecp_mul_comb(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char w, p_eq_g, i; + size_t d; + unsigned char T_size = 0, T_ok = 0; + mbedtls_ecp_point *T = NULL; + + ECP_RS_ENTER(rsm); + + /* Is P the base point ? */ +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 + p_eq_g = (MPI_ECP_CMP(&P->Y, &grp->G.Y) == 0 && + MPI_ECP_CMP(&P->X, &grp->G.X) == 0); +#else + p_eq_g = 0; +#endif + + /* Pick window size and deduce related sizes */ + w = ecp_pick_window_size(grp, p_eq_g); + T_size = 1U << (w - 1); + d = (grp->nbits + w - 1) / w; + + /* Pre-computed table: do we have it already for the base point? */ + if (p_eq_g && grp->T != NULL) { + /* second pointer to the same table, will be deleted on exit */ + T = grp->T; + T_ok = 1; + } else +#if defined(MBEDTLS_ECP_RESTARTABLE) + /* Pre-computed table: do we have one in progress? complete? */ + if (rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->T != NULL) { + /* transfer ownership of T from rsm to local function */ + T = rs_ctx->rsm->T; + rs_ctx->rsm->T = NULL; + rs_ctx->rsm->T_size = 0; + + /* This effectively jumps to the call to mul_comb_after_precomp() */ + T_ok = rs_ctx->rsm->state >= ecp_rsm_comb_core; + } else +#endif + /* Allocate table if we didn't have any */ + { + T = mbedtls_calloc(T_size, sizeof(mbedtls_ecp_point)); + if (T == NULL) { + ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; + goto cleanup; + } + + for (i = 0; i < T_size; i++) { + mbedtls_ecp_point_init(&T[i]); + } + + T_ok = 0; + } + + /* Compute table (or finish computing it) if not done already */ + if (!T_ok) { + MBEDTLS_MPI_CHK(ecp_precompute_comb(grp, T, P, w, d, rs_ctx)); + + if (p_eq_g) { + /* almost transfer ownership of T to the group, but keep a copy of + * the pointer to use for calling the next function more easily */ + grp->T = T; + grp->T_size = T_size; + } + } + + /* Actual comb multiplication using precomputed points */ + MBEDTLS_MPI_CHK(ecp_mul_comb_after_precomp(grp, R, m, + T, T_size, w, d, + f_rng, p_rng, rs_ctx)); + +cleanup: + + /* does T belong to the group? */ + if (T == grp->T) { + T = NULL; + } + + /* does T belong to the restart context? */ +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->rsm != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS && T != NULL) { + /* transfer ownership of T from local function to rsm */ + rs_ctx->rsm->T_size = T_size; + rs_ctx->rsm->T = T; + T = NULL; + } +#endif + + /* did T belong to us? then let's destroy it! */ + if (T != NULL) { + for (i = 0; i < T_size; i++) { + mbedtls_ecp_point_free(&T[i]); + } + mbedtls_free(T); + } + + /* prevent caller from using invalid value */ + int should_free_R = (ret != 0); +#if defined(MBEDTLS_ECP_RESTARTABLE) + /* don't free R while in progress in case R == P */ + if (ret == MBEDTLS_ERR_ECP_IN_PROGRESS) { + should_free_R = 0; + } +#endif + if (should_free_R) { + mbedtls_ecp_point_free(R); + } + + ECP_RS_LEAVE(rsm); + + return ret; +} + + +#endif /* MBEDTLS_ECP_MUL_ALT */ + +#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ + +#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) +/* + * For Montgomery curves, we do all the internal arithmetic in projective + * coordinates. Import/export of points uses only the x coordinates, which is + * internally represented as X / Z. + * + * For scalar multiplication, we'll use a Montgomery ladder. + */ + +#if !defined(MBEDTLS_ECP_MUL_ALT) + +/* + * Normalize Montgomery x/z coordinates: X = X/Z, Z = 1 + * Cost: 1M + 1I + */ +static int ecp_normalize_mxz(const mbedtls_ecp_group *grp, mbedtls_ecp_point *P) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + MPI_ECP_INV(&P->Z, &P->Z); + MPI_ECP_MUL(&P->X, &P->X, &P->Z); + MPI_ECP_LSET(&P->Z, 1); + +cleanup: + return ret; +} + +/* + * Randomize projective x/z coordinates: + * (X, Z) -> (l X, l Z) for random l + * This is sort of the reverse operation of ecp_normalize_mxz(). + * + * This countermeasure was first suggested in [2]. + * Cost: 2M + */ +static int ecp_randomize_mxz(const mbedtls_ecp_group *grp, mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi l; + mbedtls_mpi_init(&l); + + /* Generate l such that 1 < l < p */ + MPI_ECP_RAND(&l); + + MPI_ECP_MUL(&P->X, &P->X, &l); + MPI_ECP_MUL(&P->Z, &P->Z, &l); + +cleanup: + mbedtls_mpi_free(&l); + + if (ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; + } + return ret; +} + +/* + * Double-and-add: R = 2P, S = P + Q, with d = X(P - Q), + * for Montgomery curves in x/z coordinates. + * + * http://www.hyperelliptic.org/EFD/g1p/auto-code/montgom/xz/ladder/mladd-1987-m.op3 + * with + * d = X1 + * P = (X2, Z2) + * Q = (X3, Z3) + * R = (X4, Z4) + * S = (X5, Z5) + * and eliminating temporary variables tO, ..., t4. + * + * Cost: 5M + 4S + */ +static int ecp_double_add_mxz(const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, mbedtls_ecp_point *S, + const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q, + const mbedtls_mpi *d, + mbedtls_mpi T[4]) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + MPI_ECP_ADD(&T[0], &P->X, &P->Z); /* Pp := PX + PZ */ + MPI_ECP_SUB(&T[1], &P->X, &P->Z); /* Pm := PX - PZ */ + MPI_ECP_ADD(&T[2], &Q->X, &Q->Z); /* Qp := QX + XZ */ + MPI_ECP_SUB(&T[3], &Q->X, &Q->Z); /* Qm := QX - QZ */ + MPI_ECP_MUL(&T[3], &T[3], &T[0]); /* Qm * Pp */ + MPI_ECP_MUL(&T[2], &T[2], &T[1]); /* Qp * Pm */ + MPI_ECP_SQR(&T[0], &T[0]); /* Pp^2 */ + MPI_ECP_SQR(&T[1], &T[1]); /* Pm^2 */ + MPI_ECP_MUL(&R->X, &T[0], &T[1]); /* Pp^2 * Pm^2 */ + MPI_ECP_SUB(&T[0], &T[0], &T[1]); /* Pp^2 - Pm^2 */ + MPI_ECP_MUL(&R->Z, &grp->A, &T[0]); /* A * (Pp^2 - Pm^2) */ + MPI_ECP_ADD(&R->Z, &T[1], &R->Z); /* [ A * (Pp^2-Pm^2) ] + Pm^2 */ + MPI_ECP_ADD(&S->X, &T[3], &T[2]); /* Qm*Pp + Qp*Pm */ + MPI_ECP_SQR(&S->X, &S->X); /* (Qm*Pp + Qp*Pm)^2 */ + MPI_ECP_SUB(&S->Z, &T[3], &T[2]); /* Qm*Pp - Qp*Pm */ + MPI_ECP_SQR(&S->Z, &S->Z); /* (Qm*Pp - Qp*Pm)^2 */ + MPI_ECP_MUL(&S->Z, d, &S->Z); /* d * ( Qm*Pp - Qp*Pm )^2 */ + MPI_ECP_MUL(&R->Z, &T[0], &R->Z); /* [A*(Pp^2-Pm^2)+Pm^2]*(Pp^2-Pm^2) */ + +cleanup: + + return ret; +} + +/* + * Multiplication with Montgomery ladder in x/z coordinates, + * for curves in Montgomery form + */ +static int ecp_mul_mxz(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t i; + unsigned char b; + mbedtls_ecp_point RP; + mbedtls_mpi PX; + mbedtls_mpi tmp[4]; + mbedtls_ecp_point_init(&RP); mbedtls_mpi_init(&PX); + + mpi_init_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); + + if (f_rng == NULL) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* Save PX and read from P before writing to R, in case P == R */ + MPI_ECP_MOV(&PX, &P->X); + MBEDTLS_MPI_CHK(mbedtls_ecp_copy(&RP, P)); + + /* Set R to zero in modified x/z coordinates */ + MPI_ECP_LSET(&R->X, 1); + MPI_ECP_LSET(&R->Z, 0); + mbedtls_mpi_free(&R->Y); + + /* RP.X might be slightly larger than P, so reduce it */ + MOD_ADD(&RP.X); + + /* Randomize coordinates of the starting point */ + MBEDTLS_MPI_CHK(ecp_randomize_mxz(grp, &RP, f_rng, p_rng)); + + /* Loop invariant: R = result so far, RP = R + P */ + i = grp->nbits + 1; /* one past the (zero-based) required msb for private keys */ + while (i-- > 0) { + b = mbedtls_mpi_get_bit(m, i); + /* + * if (b) R = 2R + P else R = 2R, + * which is: + * if (b) double_add( RP, R, RP, R ) + * else double_add( R, RP, R, RP ) + * but using safe conditional swaps to avoid leaks + */ + MPI_ECP_COND_SWAP(&R->X, &RP.X, b); + MPI_ECP_COND_SWAP(&R->Z, &RP.Z, b); + MBEDTLS_MPI_CHK(ecp_double_add_mxz(grp, R, &RP, R, &RP, &PX, tmp)); + MPI_ECP_COND_SWAP(&R->X, &RP.X, b); + MPI_ECP_COND_SWAP(&R->Z, &RP.Z, b); + } + + MBEDTLS_MPI_CHK(ecp_normalize_mxz(grp, R)); + +cleanup: + mbedtls_ecp_point_free(&RP); mbedtls_mpi_free(&PX); + + mpi_free_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); + return ret; +} + +#endif /* MBEDTLS_ECP_MUL_ALT */ + +#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ + +#if !defined(MBEDTLS_ECP_MUL_ALT) + +/* + * Restartable multiplication R = m * P + * + * This internal function can be called without an RNG in case where we know + * the inputs are not sensitive. + */ +#if defined(MBEDTLS_ECP_MUL_ALT_SOFT_FALLBACK) +int ecp_mul_restartable_internal_soft(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx) +#else +static int ecp_mul_restartable_internal(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx) +#endif /* MBEDTLS_ECP_MUL_ALT_SOFT_FALLBACK */ +{ + int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + +#if defined(MBEDTLS_ECP_RESTARTABLE) + /* reset ops count for this call if top-level */ + if (rs_ctx != NULL && rs_ctx->depth++ == 0) { + rs_ctx->ops_done = 0; + } +#else + (void) rs_ctx; +#endif + + int restarting = 0; +#if defined(MBEDTLS_ECP_RESTARTABLE) + restarting = (rs_ctx != NULL && rs_ctx->rsm != NULL); +#endif + /* skip argument check when restarting */ + if (!restarting) { + /* check_privkey is free */ + MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_CHK); + + /* Common sanity checks */ + MBEDTLS_MPI_CHK(mbedtls_ecp_check_privkey(grp, m)); + MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(grp, P)); + } + + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; +#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) + if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { + MBEDTLS_MPI_CHK(ecp_mul_mxz(grp, R, m, P, f_rng, p_rng)); + } +#endif +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) + if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { + MBEDTLS_MPI_CHK(ecp_mul_comb(grp, R, m, P, f_rng, p_rng, rs_ctx)); + } +#endif + +cleanup: + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL) { + rs_ctx->depth--; + } +#endif + + return ret; +} + +#endif /* !MBEDTLS_ECP_MUL_ALT */ + +/* + * Restartable multiplication R = m * P + */ +int mbedtls_ecp_mul_restartable(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx) +{ + if (f_rng == NULL) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + return ecp_mul_restartable_internal(grp, R, m, P, f_rng, p_rng, rs_ctx); +} + +/* + * Multiplication R = m * P + */ +int mbedtls_ecp_mul(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) +{ + return mbedtls_ecp_mul_restartable(grp, R, m, P, f_rng, p_rng, NULL); +} +#endif /* MBEDTLS_ECP_C */ + +#if !defined(MBEDTLS_ECP_VERIFY_ALT) + +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) +/* + * Check that an affine point is valid as a public key, + * short weierstrass curves (SEC1 3.2.3.1) + */ +static int ecp_check_pubkey_sw(const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi YY, RHS; + + /* pt coordinates must be normalized for our checks */ + if (mbedtls_mpi_cmp_int(&pt->X, 0) < 0 || + mbedtls_mpi_cmp_int(&pt->Y, 0) < 0 || + mbedtls_mpi_cmp_mpi(&pt->X, &grp->P) >= 0 || + mbedtls_mpi_cmp_mpi(&pt->Y, &grp->P) >= 0) { + return MBEDTLS_ERR_ECP_INVALID_KEY; + } + + mbedtls_mpi_init(&YY); mbedtls_mpi_init(&RHS); + + /* + * YY = Y^2 + * RHS = X^3 + A X + B + */ + MPI_ECP_SQR(&YY, &pt->Y); + MBEDTLS_MPI_CHK(ecp_sw_rhs(grp, &RHS, &pt->X)); + + if (MPI_ECP_CMP(&YY, &RHS) != 0) { + ret = MBEDTLS_ERR_ECP_INVALID_KEY; + } + +cleanup: + + mbedtls_mpi_free(&YY); mbedtls_mpi_free(&RHS); + + return ret; +} +#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ +#endif /* MBEDTLS_ECP_VERIFY_ALT */ + +#if defined(MBEDTLS_ECP_C) +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) +/* + * R = m * P with shortcuts for m == 0, m == 1 and m == -1 + * NOT constant-time - ONLY for short Weierstrass! + */ +static int mbedtls_ecp_mul_shortcuts(mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, + const mbedtls_mpi *m, + const mbedtls_ecp_point *P, + mbedtls_ecp_restart_ctx *rs_ctx) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi tmp; + mbedtls_mpi_init(&tmp); + + if (mbedtls_mpi_cmp_int(m, 0) == 0) { + MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(grp, P)); + MBEDTLS_MPI_CHK(mbedtls_ecp_set_zero(R)); + } else if (mbedtls_mpi_cmp_int(m, 1) == 0) { + MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(grp, P)); + MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, P)); + } else if (mbedtls_mpi_cmp_int(m, -1) == 0) { + MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(grp, P)); + MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, P)); + MPI_ECP_NEG(&R->Y); + } else { + MBEDTLS_MPI_CHK(ecp_mul_restartable_internal(grp, R, m, P, + NULL, NULL, rs_ctx)); + } + +cleanup: + mbedtls_mpi_free(&tmp); + + return ret; +} + +/* + * Restartable linear combination + * NOT constant-time + */ +int mbedtls_ecp_muladd_restartable( + mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + const mbedtls_mpi *n, const mbedtls_ecp_point *Q, + mbedtls_ecp_restart_ctx *rs_ctx) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_point mP; + mbedtls_ecp_point *pmP = &mP; + mbedtls_ecp_point *pR = R; + mbedtls_mpi tmp[4]; + if (mbedtls_ecp_get_type(grp) != MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { + return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + } + + mbedtls_ecp_point_init(&mP); + mpi_init_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); + + ECP_RS_ENTER(ma); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->ma != NULL) { + /* redirect intermediate results to restart context */ + pmP = &rs_ctx->ma->mP; + pR = &rs_ctx->ma->R; + + /* jump to next operation */ + if (rs_ctx->ma->state == ecp_rsma_mul2) { + goto mul2; + } + if (rs_ctx->ma->state == ecp_rsma_add) { + goto add; + } + if (rs_ctx->ma->state == ecp_rsma_norm) { + goto norm; + } + } +#endif /* MBEDTLS_ECP_RESTARTABLE */ + + MBEDTLS_MPI_CHK(mbedtls_ecp_mul_shortcuts(grp, pmP, m, P, rs_ctx)); +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->ma != NULL) { + rs_ctx->ma->state = ecp_rsma_mul2; + } + +mul2: +#endif + MBEDTLS_MPI_CHK(mbedtls_ecp_mul_shortcuts(grp, pR, n, Q, rs_ctx)); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->ma != NULL) { + rs_ctx->ma->state = ecp_rsma_add; + } + +add: +#endif + MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_ADD); + MBEDTLS_MPI_CHK(ecp_add_mixed(grp, pR, pmP, pR, tmp)); +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->ma != NULL) { + rs_ctx->ma->state = ecp_rsma_norm; + } + +norm: +#endif + MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_INV); + MBEDTLS_MPI_CHK(ecp_normalize_jac(grp, pR)); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if (rs_ctx != NULL && rs_ctx->ma != NULL) { + MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, pR)); + } +#endif + +cleanup: + + mpi_free_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); + + mbedtls_ecp_point_free(&mP); + + ECP_RS_LEAVE(ma); + + return ret; +} + +/* + * Linear combination + * NOT constant-time + */ +int mbedtls_ecp_muladd(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + const mbedtls_mpi *n, const mbedtls_ecp_point *Q) +{ + return mbedtls_ecp_muladd_restartable(grp, R, m, P, n, Q, NULL); +} +#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ +#endif /* MBEDTLS_ECP_C */ + +#if !defined(MBEDTLS_ECP_VERIFY_ALT) +#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +#define ECP_MPI_INIT(_p, _n) { .p = (mbedtls_mpi_uint *) (_p), .s = 1, .n = (_n) } +#define ECP_MPI_INIT_ARRAY(x) \ + ECP_MPI_INIT(x, sizeof(x) / sizeof(mbedtls_mpi_uint)) +/* + * Constants for the two points other than 0, 1, -1 (mod p) in + * https://cr.yp.to/ecdh.html#validate + * See ecp_check_pubkey_x25519(). + */ +static const mbedtls_mpi_uint x25519_bad_point_1[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a), + MBEDTLS_BYTES_TO_T_UINT_8(0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00), +}; +static const mbedtls_mpi_uint x25519_bad_point_2[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24), + MBEDTLS_BYTES_TO_T_UINT_8(0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86), + MBEDTLS_BYTES_TO_T_UINT_8(0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57), +}; +static const mbedtls_mpi ecp_x25519_bad_point_1 = ECP_MPI_INIT_ARRAY( + x25519_bad_point_1); +static const mbedtls_mpi ecp_x25519_bad_point_2 = ECP_MPI_INIT_ARRAY( + x25519_bad_point_2); +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +/* + * Check that the input point is not one of the low-order points. + * This is recommended by the "May the Fourth" paper: + * https://eprint.iacr.org/2017/806.pdf + * Those points are never sent by an honest peer. + */ +static int ecp_check_bad_points_mx(const mbedtls_mpi *X, const mbedtls_mpi *P, + const mbedtls_ecp_group_id grp_id) +{ + int ret; + mbedtls_mpi XmP; + + mbedtls_mpi_init(&XmP); + + /* Reduce X mod P so that we only need to check values less than P. + * We know X < 2^256 so we can proceed by subtraction. */ + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&XmP, X)); + while (mbedtls_mpi_cmp_mpi(&XmP, P) >= 0) { + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&XmP, &XmP, P)); + } + + /* Check against the known bad values that are less than P. For Curve448 + * these are 0, 1 and -1. For Curve25519 we check the values less than P + * from the following list: https://cr.yp.to/ecdh.html#validate */ + if (mbedtls_mpi_cmp_int(&XmP, 1) <= 0) { /* takes care of 0 and 1 */ + ret = MBEDTLS_ERR_ECP_INVALID_KEY; + goto cleanup; + } + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + if (grp_id == MBEDTLS_ECP_DP_CURVE25519) { + if (mbedtls_mpi_cmp_mpi(&XmP, &ecp_x25519_bad_point_1) == 0) { + ret = MBEDTLS_ERR_ECP_INVALID_KEY; + goto cleanup; + } + + if (mbedtls_mpi_cmp_mpi(&XmP, &ecp_x25519_bad_point_2) == 0) { + ret = MBEDTLS_ERR_ECP_INVALID_KEY; + goto cleanup; + } + } +#else + (void) grp_id; +#endif + + /* Final check: check if XmP + 1 is P (final because it changes XmP!) */ + MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&XmP, &XmP, 1)); + if (mbedtls_mpi_cmp_mpi(&XmP, P) == 0) { + ret = MBEDTLS_ERR_ECP_INVALID_KEY; + goto cleanup; + } + + ret = 0; + +cleanup: + mbedtls_mpi_free(&XmP); + + return ret; +} + +/* + * Check validity of a public key for Montgomery curves with x-only schemes + */ +static int ecp_check_pubkey_mx(const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt) +{ + /* [Curve25519 p. 5] Just check X is the correct number of bytes */ + /* Allow any public value, if it's too big then we'll just reduce it mod p + * (RFC 7748 sec. 5 para. 3). */ + if (mbedtls_mpi_size(&pt->X) > (grp->nbits + 7) / 8) { + return MBEDTLS_ERR_ECP_INVALID_KEY; + } + + /* Implicit in all standards (as they don't consider negative numbers): + * X must be non-negative. This is normally ensured by the way it's + * encoded for transmission, but let's be extra sure. */ + if (mbedtls_mpi_cmp_int(&pt->X, 0) < 0) { + return MBEDTLS_ERR_ECP_INVALID_KEY; + } + + return ecp_check_bad_points_mx(&pt->X, &grp->P, grp->id); +} +#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ +#endif /* MBEDTLS_ECP_VERIFY_ALT */ + +#if !defined(MBEDTLS_ECP_VERIFY_ALT) +/* + * Check that a point is valid as a public key + */ +#if defined(MBEDTLS_ECP_VERIFY_ALT_SOFT_FALLBACK) +int mbedtls_ecp_check_pubkey_soft(const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *pt) +#else +int mbedtls_ecp_check_pubkey(const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *pt) +#endif /* MBEDTLS_ECP_VERIFY_ALT_SOFT_FALLBACK */ +{ + /* Must use affine coordinates */ + if (mbedtls_mpi_cmp_int(&pt->Z, 1) != 0) { + return MBEDTLS_ERR_ECP_INVALID_KEY; + } + +#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) + if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { + return ecp_check_pubkey_mx(grp, pt); + } +#endif +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) + if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { + return ecp_check_pubkey_sw(grp, pt); + } +#endif + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; +} + +#endif /* MBEDTLS_ECP_VERIFY_ALT */ + +/* + * Check that an mbedtls_mpi is valid as a private key + */ +int mbedtls_ecp_check_privkey(const mbedtls_ecp_group *grp, + const mbedtls_mpi *d) +{ +#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) + if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { + /* see RFC 7748 sec. 5 para. 5 */ + if (mbedtls_mpi_get_bit(d, 0) != 0 || + mbedtls_mpi_get_bit(d, 1) != 0 || + mbedtls_mpi_bitlen(d) != grp->nbits + 1) { /* mbedtls_mpi_bitlen is one-based! */ + return MBEDTLS_ERR_ECP_INVALID_KEY; + } + + /* see [Curve25519] page 5 */ + if (grp->nbits == 254 && mbedtls_mpi_get_bit(d, 2) != 0) { + return MBEDTLS_ERR_ECP_INVALID_KEY; + } + + return 0; + } +#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) + if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { + /* see SEC1 3.2 */ + if (mbedtls_mpi_cmp_int(d, 1) < 0 || + mbedtls_mpi_cmp_mpi(d, &grp->N) >= 0) { + return MBEDTLS_ERR_ECP_INVALID_KEY; + } else { + return 0; + } + } +#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ + + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; +} + +#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_gen_privkey_mx(size_t high_bit, + mbedtls_mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + size_t n_random_bytes = high_bit / 8 + 1; + + /* [Curve25519] page 5 */ + /* Generate a (high_bit+1)-bit random number by generating just enough + * random bytes, then shifting out extra bits from the top (necessary + * when (high_bit+1) is not a multiple of 8). */ + MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(d, n_random_bytes, + f_rng, p_rng)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(d, 8 * n_random_bytes - high_bit - 1)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(d, high_bit, 1)); + + /* Make sure the last two bits are unset for Curve448, three bits for + Curve25519 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(d, 0, 0)); + MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(d, 1, 0)); + if (high_bit == 254) { + MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(d, 2, 0)); + } + +cleanup: + return ret; +} +#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ + +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) +static int mbedtls_ecp_gen_privkey_sw( + const mbedtls_mpi *N, mbedtls_mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) +{ + int ret = mbedtls_mpi_random(d, 1, N, f_rng, p_rng); + switch (ret) { + case MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: + return MBEDTLS_ERR_ECP_RANDOM_FAILED; + default: + return ret; + } +} +#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ + +/* + * Generate a private key + */ +int mbedtls_ecp_gen_privkey(const mbedtls_ecp_group *grp, + mbedtls_mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ +#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) + if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { + return mbedtls_ecp_gen_privkey_mx(grp->nbits, d, f_rng, p_rng); + } +#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ + +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) + if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { + return mbedtls_ecp_gen_privkey_sw(&grp->N, d, f_rng, p_rng); + } +#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ + + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; +} + +#if defined(MBEDTLS_ECP_C) +/* + * Generate a keypair with configurable base point + */ +int mbedtls_ecp_gen_keypair_base(mbedtls_ecp_group *grp, + const mbedtls_ecp_point *G, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + MBEDTLS_MPI_CHK(mbedtls_ecp_gen_privkey(grp, d, f_rng, p_rng)); + MBEDTLS_MPI_CHK(mbedtls_ecp_mul(grp, Q, d, G, f_rng, p_rng)); + +cleanup: + return ret; +} + +/* + * Generate key pair, wrapper for conventional base point + */ +int mbedtls_ecp_gen_keypair(mbedtls_ecp_group *grp, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + return mbedtls_ecp_gen_keypair_base(grp, &grp->G, d, Q, f_rng, p_rng); +} + +/* + * Generate a keypair, prettier wrapper + */ +int mbedtls_ecp_gen_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + if ((ret = mbedtls_ecp_group_load(&key->grp, grp_id)) != 0) { + return ret; + } + + return mbedtls_ecp_gen_keypair(&key->grp, &key->d, &key->Q, f_rng, p_rng); +} +#endif /* MBEDTLS_ECP_C */ + +int mbedtls_ecp_set_public_key(mbedtls_ecp_group_id grp_id, + mbedtls_ecp_keypair *key, + const mbedtls_ecp_point *Q) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if (key->grp.id == MBEDTLS_ECP_DP_NONE) { + /* Group not set yet */ + if ((ret = mbedtls_ecp_group_load(&key->grp, grp_id)) != 0) { + return ret; + } + } else if (key->grp.id != grp_id) { + /* Group mismatch */ + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + return mbedtls_ecp_copy(&key->Q, Q); +} + + +#define ECP_CURVE25519_KEY_SIZE 32 +#define ECP_CURVE448_KEY_SIZE 56 +/* + * Read a private key. + */ +int mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, + const unsigned char *buf, size_t buflen) +{ + int ret = 0; + + if ((ret = mbedtls_ecp_group_load(&key->grp, grp_id)) != 0) { + return ret; + } + + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + +#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) + if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { + /* + * Mask the key as mandated by RFC7748 for Curve25519 and Curve448. + */ + if (grp_id == MBEDTLS_ECP_DP_CURVE25519) { + if (buflen != ECP_CURVE25519_KEY_SIZE) { + return MBEDTLS_ERR_ECP_INVALID_KEY; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary_le(&key->d, buf, buflen)); + + /* Set the three least significant bits to 0 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 0, 0)); + MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 1, 0)); + MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 2, 0)); + + /* Set the most significant bit to 0 */ + MBEDTLS_MPI_CHK( + mbedtls_mpi_set_bit(&key->d, + ECP_CURVE25519_KEY_SIZE * 8 - 1, 0) + ); + + /* Set the second most significant bit to 1 */ + MBEDTLS_MPI_CHK( + mbedtls_mpi_set_bit(&key->d, + ECP_CURVE25519_KEY_SIZE * 8 - 2, 1) + ); + } else if (grp_id == MBEDTLS_ECP_DP_CURVE448) { + if (buflen != ECP_CURVE448_KEY_SIZE) { + return MBEDTLS_ERR_ECP_INVALID_KEY; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary_le(&key->d, buf, buflen)); + + /* Set the two least significant bits to 0 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 0, 0)); + MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 1, 0)); + + /* Set the most significant bit to 1 */ + MBEDTLS_MPI_CHK( + mbedtls_mpi_set_bit(&key->d, + ECP_CURVE448_KEY_SIZE * 8 - 1, 1) + ); + } + } +#endif +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) + if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&key->d, buf, buflen)); + } +#endif + + if (ret == 0) { + MBEDTLS_MPI_CHK(mbedtls_ecp_check_privkey(&key->grp, &key->d)); + } + +cleanup: + + if (ret != 0) { + mbedtls_mpi_free(&key->d); + } + + return ret; +} + +int mbedtls_ecp_write_key_ext(const mbedtls_ecp_keypair *key, + size_t *olen, unsigned char *buf, size_t buflen) +{ + size_t len = (key->grp.nbits + 7) / 8; + if (len > buflen) { + /* For robustness, ensure *olen <= buflen even on error. */ + *olen = 0; + return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + } + *olen = len; + + /* Private key not set */ + if (key->d.n == 0) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + +#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) + if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { + return mbedtls_mpi_write_binary_le(&key->d, buf, len); + } +#endif + +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) + if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { + return mbedtls_mpi_write_binary(&key->d, buf, len); + } +#endif + + /* Private key set but no recognized curve type? This shouldn't happen. */ + return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; +} + +/* + * Write a public key. + */ +int mbedtls_ecp_write_public_key(const mbedtls_ecp_keypair *key, + int format, size_t *olen, + unsigned char *buf, size_t buflen) +{ + return mbedtls_ecp_point_write_binary(&key->grp, &key->Q, + format, olen, buf, buflen); +} + + +#if defined(MBEDTLS_ECP_C) +/* + * Check a public-private key pair + */ +int mbedtls_ecp_check_pub_priv( + const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_point Q; + mbedtls_ecp_group grp; + if (pub->grp.id == MBEDTLS_ECP_DP_NONE || + pub->grp.id != prv->grp.id || + mbedtls_mpi_cmp_mpi(&pub->Q.X, &prv->Q.X) || + mbedtls_mpi_cmp_mpi(&pub->Q.Y, &prv->Q.Y) || + mbedtls_mpi_cmp_mpi(&pub->Q.Z, &prv->Q.Z)) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + mbedtls_ecp_point_init(&Q); + mbedtls_ecp_group_init(&grp); + + /* mbedtls_ecp_mul() needs a non-const group... */ + mbedtls_ecp_group_copy(&grp, &prv->grp); + + /* Also checks d is valid */ + MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&grp, &Q, &prv->d, &prv->grp.G, f_rng, p_rng)); + + if (mbedtls_mpi_cmp_mpi(&Q.X, &prv->Q.X) || + mbedtls_mpi_cmp_mpi(&Q.Y, &prv->Q.Y) || + mbedtls_mpi_cmp_mpi(&Q.Z, &prv->Q.Z)) { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + +cleanup: + mbedtls_ecp_point_free(&Q); + mbedtls_ecp_group_free(&grp); + + return ret; +} + +int mbedtls_ecp_keypair_calc_public(mbedtls_ecp_keypair *key, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G, + f_rng, p_rng); +} +#endif /* MBEDTLS_ECP_C */ + +mbedtls_ecp_group_id mbedtls_ecp_keypair_get_group_id( + const mbedtls_ecp_keypair *key) +{ + return key->grp.id; +} + +/* + * Export generic key-pair parameters. + */ +int mbedtls_ecp_export(const mbedtls_ecp_keypair *key, mbedtls_ecp_group *grp, + mbedtls_mpi *d, mbedtls_ecp_point *Q) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if (grp != NULL && (ret = mbedtls_ecp_group_copy(grp, &key->grp)) != 0) { + return ret; + } + + if (d != NULL && (ret = mbedtls_mpi_copy(d, &key->d)) != 0) { + return ret; + } + + if (Q != NULL && (ret = mbedtls_ecp_copy(Q, &key->Q)) != 0) { + return ret; + } + + return 0; +} + +#if defined(MBEDTLS_SELF_TEST) + +#if defined(MBEDTLS_ECP_C) +/* + * PRNG for test - !!!INSECURE NEVER USE IN PRODUCTION!!! + * + * This is the linear congruential generator from numerical recipes, + * except we only use the low byte as the output. See + * https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use + */ +static int self_test_rng(void *ctx, unsigned char *out, size_t len) +{ + static uint32_t state = 42; + + (void) ctx; + + for (size_t i = 0; i < len; i++) { + state = state * 1664525u + 1013904223u; + out[i] = (unsigned char) state; + } + + return 0; +} + +/* Adjust the exponent to be a valid private point for the specified curve. + * This is sometimes necessary because we use a single set of exponents + * for all curves but the validity of values depends on the curve. */ +static int self_test_adjust_exponent(const mbedtls_ecp_group *grp, + mbedtls_mpi *m) +{ + int ret = 0; + switch (grp->id) { + /* If Curve25519 is available, then that's what we use for the + * Montgomery test, so we don't need the adjustment code. */ +#if !defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + case MBEDTLS_ECP_DP_CURVE448: + /* Move highest bit from 254 to N-1. Setting bit N-1 is + * necessary to enforce the highest-bit-set constraint. */ + MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(m, 254, 0)); + MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(m, grp->nbits, 1)); + /* Copy second-highest bit from 253 to N-2. This is not + * necessary but improves the test variety a bit. */ + MBEDTLS_MPI_CHK( + mbedtls_mpi_set_bit(m, grp->nbits - 1, + mbedtls_mpi_get_bit(m, 253))); + break; +#endif +#endif /* ! defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) */ + default: + /* Non-Montgomery curves and Curve25519 need no adjustment. */ + (void) grp; + (void) m; + goto cleanup; + } +cleanup: + return ret; +} + +/* Calculate R = m.P for each m in exponents. Check that the number of + * basic operations doesn't depend on the value of m. */ +static int self_test_point(int verbose, + mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, + mbedtls_mpi *m, + const mbedtls_ecp_point *P, + const char *const *exponents, + size_t n_exponents) +{ + int ret = 0; + size_t i = 0; + unsigned long add_c_prev, dbl_c_prev, mul_c_prev; + add_count = 0; + dbl_count = 0; + mul_count = 0; + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(m, 16, exponents[0])); + MBEDTLS_MPI_CHK(self_test_adjust_exponent(grp, m)); + MBEDTLS_MPI_CHK(mbedtls_ecp_mul(grp, R, m, P, self_test_rng, NULL)); + + for (i = 1; i < n_exponents; i++) { + add_c_prev = add_count; + dbl_c_prev = dbl_count; + mul_c_prev = mul_count; + add_count = 0; + dbl_count = 0; + mul_count = 0; + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(m, 16, exponents[i])); + MBEDTLS_MPI_CHK(self_test_adjust_exponent(grp, m)); + MBEDTLS_MPI_CHK(mbedtls_ecp_mul(grp, R, m, P, self_test_rng, NULL)); + + if (add_count != add_c_prev || + dbl_count != dbl_c_prev || + mul_count != mul_c_prev) { + ret = 1; + break; + } + } + +cleanup: + if (verbose != 0) { + if (ret != 0) { + mbedtls_printf("failed (%u)\n", (unsigned int) i); + } else { + mbedtls_printf("passed\n"); + } + } + return ret; +} +#endif /* MBEDTLS_ECP_C */ + +/* + * Checkup routine + */ +int mbedtls_ecp_self_test(int verbose) +{ +#if defined(MBEDTLS_ECP_C) + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_group grp; + mbedtls_ecp_point R, P; + mbedtls_mpi m; + +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) + const char *sw_exponents[] = + { + "000000000000000000000000000000000000000000000001", /* one */ + "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8C", /* n - 1 */ + "5EA6F389A38B8BC81E767753B15AA5569E1782E30ABE7D25", /* random */ + "400000000000000000000000000000000000000000000000", /* one and zeros */ + "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", /* all ones */ + "555555555555555555555555555555555555555555555555", /* 101010... */ + }; +#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ +#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) + const char *m_exponents[] = + { + /* Valid private values for Curve25519. In a build with Curve448 + * but not Curve25519, they will be adjusted in + * self_test_adjust_exponent(). */ + "4000000000000000000000000000000000000000000000000000000000000000", + "5C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C30", + "5715ECCE24583F7A7023C24164390586842E816D7280A49EF6DF4EAE6B280BF8", + "41A2B017516F6D254E1F002BCCBADD54BE30F8CEC737A0E912B4963B6BA74460", + "5555555555555555555555555555555555555555555555555555555555555550", + "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8", + }; +#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ + + mbedtls_ecp_group_init(&grp); + mbedtls_ecp_point_init(&R); + mbedtls_ecp_point_init(&P); + mbedtls_mpi_init(&m); + +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) + /* Use secp256r1 if available, or any available curve */ +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1)); +#else + MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&grp, mbedtls_ecp_curve_list()->grp_id)); +#endif + + if (verbose != 0) { + mbedtls_printf(" ECP SW test #1 (constant op_count, base point G): "); + } + /* Do a dummy multiplication first to trigger precomputation */ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&m, 2)); + MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&grp, &P, &m, &grp.G, self_test_rng, NULL)); + ret = self_test_point(verbose, + &grp, &R, &m, &grp.G, + sw_exponents, + sizeof(sw_exponents) / sizeof(sw_exponents[0])); + if (ret != 0) { + goto cleanup; + } + + if (verbose != 0) { + mbedtls_printf(" ECP SW test #2 (constant op_count, other point): "); + } + /* We computed P = 2G last time, use it */ + ret = self_test_point(verbose, + &grp, &R, &m, &P, + sw_exponents, + sizeof(sw_exponents) / sizeof(sw_exponents[0])); + if (ret != 0) { + goto cleanup; + } + + mbedtls_ecp_group_free(&grp); + mbedtls_ecp_point_free(&R); +#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ + +#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) + if (verbose != 0) { + mbedtls_printf(" ECP Montgomery test (constant op_count): "); + } +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_CURVE25519)); +#elif defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_CURVE448)); +#else +#error "MBEDTLS_ECP_MONTGOMERY_ENABLED is defined, but no curve is supported for self-test" +#endif + ret = self_test_point(verbose, + &grp, &R, &m, &grp.G, + m_exponents, + sizeof(m_exponents) / sizeof(m_exponents[0])); + if (ret != 0) { + goto cleanup; + } +#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ + +cleanup: + + if (ret < 0 && verbose != 0) { + mbedtls_printf("Unexpected error, return code = %08X\n", (unsigned int) ret); + } + + mbedtls_ecp_group_free(&grp); + mbedtls_ecp_point_free(&R); + mbedtls_ecp_point_free(&P); + mbedtls_mpi_free(&m); + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + return ret; +#else /* MBEDTLS_ECP_C */ + (void) verbose; + return 0; +#endif /* MBEDTLS_ECP_C */ +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ECP_LIGHT */ diff --git a/tf-psa-crypto/drivers/builtin/src/ecp_curves.c b/tf-psa-crypto/drivers/builtin/src/ecp_curves.c new file mode 100644 index 0000000000..85a442fd33 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/ecp_curves.c @@ -0,0 +1,4355 @@ +/* + * Elliptic curves over GF(p): curve-specific data and functions + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if !defined(MBEDTLS_ECP_WITH_MPI_UINT) + +#if defined(MBEDTLS_ECP_LIGHT) + +#include "mbedtls/private/ecp.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#include "bn_mul.h" +#include "bignum_core.h" +#include "ecp_invasive.h" + +#include + +#define ECP_MPI_INIT(_p, _n) { .p = (mbedtls_mpi_uint *) (_p), .s = 1, .n = (_n) } + +#define ECP_MPI_INIT_ARRAY(x) \ + ECP_MPI_INIT(x, sizeof(x) / sizeof(mbedtls_mpi_uint)) + +#define ECP_POINT_INIT_XY_Z0(x, y) { \ + ECP_MPI_INIT_ARRAY(x), ECP_MPI_INIT_ARRAY(y), ECP_MPI_INIT(NULL, 0) } +#define ECP_POINT_INIT_XY_Z1(x, y) { \ + ECP_MPI_INIT_ARRAY(x), ECP_MPI_INIT_ARRAY(y), ECP_MPI_INIT(mpi_one, 1) } + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +/* For these curves, we build the group parameters dynamically. */ +#define ECP_LOAD_GROUP +static const mbedtls_mpi_uint mpi_one[] = { 1 }; +#endif + +/* + * Note: the constants are in little-endian order + * to be directly usable in MPIs + */ + +/* + * Domain parameters for secp256r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +static const mbedtls_mpi_uint secp256r1_p[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF), +}; +static const mbedtls_mpi_uint secp256r1_b[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x4B, 0x60, 0xD2, 0x27, 0x3E, 0x3C, 0xCE, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0xB0, 0x53, 0xCC, 0xB0, 0x06, 0x1D, 0x65), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0x86, 0x98, 0x76, 0x55, 0xBD, 0xEB, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xE7, 0x93, 0x3A, 0xAA, 0xD8, 0x35, 0xC6, 0x5A), +}; +static const mbedtls_mpi_uint secp256r1_gx[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B), +}; +static const mbedtls_mpi_uint secp256r1_gy[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F), +}; +static const mbedtls_mpi_uint secp256r1_n[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3), + MBEDTLS_BYTES_TO_T_UINT_8(0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF), +}; +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 +static const mbedtls_mpi_uint secp256r1_T_0_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B), +}; +static const mbedtls_mpi_uint secp256r1_T_0_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F), +}; +static const mbedtls_mpi_uint secp256r1_T_1_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0xC8, 0xBA, 0x04, 0xB7, 0x4B, 0xD2, 0xF7), + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0xC6, 0x23, 0x3A, 0xA0, 0x09, 0x3A, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x9D, 0x4C, 0xF9, 0x58, 0x23, 0xCC, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x02, 0xED, 0x7B, 0x29, 0x87, 0x0F, 0xFA, 0x3C), +}; +static const mbedtls_mpi_uint secp256r1_T_1_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0x69, 0xF2, 0x40, 0x0B, 0xA3, 0x98, 0xCE), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0xA8, 0x48, 0x02, 0x0D, 0x1C, 0x12, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0xAF, 0x09, 0x83, 0x80, 0xAA, 0x58, 0xA7), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0x12, 0xBE, 0x70, 0x94, 0x76, 0xE3, 0xE4), +}; +static const mbedtls_mpi_uint secp256r1_T_2_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x7D, 0x7D, 0xEF, 0x86, 0xFF, 0xE3, 0x37, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x86, 0x8B, 0x08, 0x27, 0x7C, 0xD7, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0x54, 0x4C, 0x25, 0x4F, 0x9A, 0xFE, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0xFD, 0xF0, 0x6D, 0x37, 0x03, 0x69, 0xD6), +}; +static const mbedtls_mpi_uint secp256r1_T_2_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0xD5, 0xDA, 0xAD, 0x92, 0x49, 0xF0, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0xF9, 0x73, 0x43, 0x9E, 0xAF, 0xA7, 0xD1, 0xF3), + MBEDTLS_BYTES_TO_T_UINT_8(0x67, 0x41, 0x07, 0xDF, 0x78, 0x95, 0x3E, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0x22, 0x3D, 0xD1, 0xE6, 0x3C, 0xA5, 0xE2, 0x20), +}; +static const mbedtls_mpi_uint secp256r1_T_3_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBF, 0x6A, 0x5D, 0x52, 0x35, 0xD7, 0xBF, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0xA2, 0xBE, 0x96, 0xF4, 0xF8, 0x02, 0xC3), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0x20, 0x49, 0x54, 0xEA, 0xB3, 0x82, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0x2E, 0xDB, 0xEA, 0x02, 0xD1, 0x75, 0x1C, 0x62), +}; +static const mbedtls_mpi_uint secp256r1_T_3_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0x85, 0xF4, 0x9E, 0x4C, 0xDC, 0x39, 0x89), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0x6D, 0xC4, 0x57, 0xD8, 0x03, 0x5D, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0x7F, 0x2D, 0x52, 0x6F, 0xC9, 0xDA, 0x4F), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0x64, 0xFA, 0xB4, 0xFE, 0xA4, 0xC4, 0xD7), +}; +static const mbedtls_mpi_uint secp256r1_T_4_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0x37, 0xB9, 0xC0, 0xAA, 0x59, 0xC6, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0x58, 0xD9, 0xED, 0x58, 0x99, 0x65, 0xF7), + MBEDTLS_BYTES_TO_T_UINT_8(0x88, 0x7D, 0x26, 0x8C, 0x4A, 0xF9, 0x05, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0x73, 0x9A, 0xC9, 0xE7, 0x46, 0xDC, 0x00), +}; +static const mbedtls_mpi_uint secp256r1_T_4_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0xD0, 0x55, 0xDF, 0x00, 0x0A, 0xF5, 0x4A), + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0xBF, 0x56, 0x81, 0x2D, 0x20, 0xEB, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0xC1, 0x28, 0x52, 0xAB, 0xE3, 0xD1, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x24, 0x34, 0x79, 0x45, 0x57, 0xA5, 0x12, 0x03), +}; +static const mbedtls_mpi_uint secp256r1_T_5_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEE, 0xCF, 0xB8, 0x7E, 0xF7, 0x92, 0x96, 0x8D), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0x01, 0x8C, 0x0D, 0x23, 0xF2, 0xE3, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0x2E, 0xE3, 0x84, 0x52, 0x7A, 0x34, 0x76), + MBEDTLS_BYTES_TO_T_UINT_8(0xE5, 0xA1, 0xB0, 0x15, 0x90, 0xE2, 0x53, 0x3C), +}; +static const mbedtls_mpi_uint secp256r1_T_5_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0x98, 0xE7, 0xFA, 0xA5, 0x7D, 0x8B, 0x53), + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0x35, 0xD2, 0x00, 0xD1, 0x1B, 0x9F, 0x1B), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0x69, 0x08, 0x9A, 0x72, 0xF0, 0xA9, 0x11), + MBEDTLS_BYTES_TO_T_UINT_8(0xB3, 0xFE, 0x0E, 0x14, 0xDA, 0x7C, 0x0E, 0xD3), +}; +static const mbedtls_mpi_uint secp256r1_T_6_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0xF6, 0xE8, 0xF8, 0x87, 0xF7, 0xFC, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0x90, 0xBE, 0x7F, 0x3F, 0x7A, 0x2B, 0xD7, 0x13), + MBEDTLS_BYTES_TO_T_UINT_8(0xCF, 0x32, 0xF2, 0x2D, 0x94, 0x6D, 0x42, 0xFD), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0x9A, 0xE3, 0x5F, 0x42, 0xBB, 0x84, 0xED), +}; +static const mbedtls_mpi_uint secp256r1_T_6_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x95, 0x29, 0x73, 0xA1, 0x67, 0x3E, 0x02), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x30, 0x54, 0x35, 0x8E, 0x0A, 0xDD, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0x03, 0xD7, 0xA1, 0x97, 0x61, 0x3B, 0xF8, 0x0C), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0x33, 0x3C, 0x58, 0x55, 0x34, 0x23, 0xA3), +}; +static const mbedtls_mpi_uint secp256r1_T_7_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0x5D, 0x16, 0x5F, 0x7B, 0xBC, 0xBB, 0xCE), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0xEE, 0x4E, 0x8A, 0xC1, 0x51, 0xCC, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x0D, 0x4D, 0x1B, 0x53, 0x23, 0x1D, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x2A, 0x38, 0x66, 0x52, 0x84, 0xE1, 0x95), +}; +static const mbedtls_mpi_uint secp256r1_T_7_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0x9B, 0x83, 0x0A, 0x81, 0x4F, 0xAD, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0x0F, 0xFF, 0x42, 0x41, 0x6E, 0xA9, 0xA2, 0xA0), + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0xA1, 0x4F, 0x1F, 0x89, 0x82, 0xAA, 0x3E), + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0xB8, 0x0F, 0x6B, 0x8F, 0x8C, 0xD6, 0x68), +}; +static const mbedtls_mpi_uint secp256r1_T_8_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0xB3, 0xBB, 0x51, 0x69, 0xA2, 0x11, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x4F, 0x0F, 0x8D, 0xBD, 0x26, 0x0F, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0xCB, 0xEC, 0x6B, 0x34, 0xC3, 0x3D, 0x9D), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0x5D, 0x1E, 0x10, 0xD5, 0x44, 0xE2, 0x54), +}; +static const mbedtls_mpi_uint secp256r1_T_8_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x9E, 0xB1, 0xF1, 0x6E, 0x4C, 0xAD, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0xE3, 0xC2, 0x58, 0xC0, 0xFB, 0x34, 0x43), + MBEDTLS_BYTES_TO_T_UINT_8(0x25, 0x9C, 0xDF, 0x35, 0x07, 0x41, 0xBD, 0x19), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x6E, 0x10, 0xEC, 0x0E, 0xEC, 0xBB, 0xD6), +}; +static const mbedtls_mpi_uint secp256r1_T_9_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0xCF, 0xEF, 0x3F, 0x83, 0x1A, 0x88, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0x29, 0xB5, 0xB9, 0xE0, 0xC9, 0xA3, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x88, 0x46, 0x1E, 0x77, 0xCD, 0x7E, 0xB3, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x21, 0xD0, 0xD4, 0xA3, 0x16, 0x08, 0xEE), +}; +static const mbedtls_mpi_uint secp256r1_T_9_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA1, 0xCA, 0xA8, 0xB3, 0xBF, 0x29, 0x99, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0xD1, 0xF2, 0x05, 0xC1, 0xCF, 0x5D, 0x91, 0x48), + MBEDTLS_BYTES_TO_T_UINT_8(0x9F, 0x01, 0x49, 0xDB, 0x82, 0xDF, 0x5F, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0xE1, 0x06, 0x90, 0xAD, 0xE3, 0x38, 0xA4, 0xC4), +}; +static const mbedtls_mpi_uint secp256r1_T_10_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0xD2, 0x3A, 0xE8, 0x03, 0xC5, 0x6D, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0x35, 0xD0, 0xAE, 0x1D, 0x7A, 0x9F, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0x33, 0x1E, 0xD2, 0xCB, 0xAC, 0x88, 0x27, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0xB9, 0x9C, 0xE0, 0x31, 0xDD, 0x99, 0x86), +}; +static const mbedtls_mpi_uint secp256r1_T_10_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0xF9, 0x9B, 0x32, 0x96, 0x41, 0x58, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0xF9, 0x5A, 0x2A, 0xB8, 0x96, 0x0E, 0xB2, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0x78, 0x2C, 0xC7, 0x08, 0x99, 0x19, 0x24), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0x59, 0x28, 0xE9, 0x84, 0x54, 0xE6, 0x16), +}; +static const mbedtls_mpi_uint secp256r1_T_11_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x38, 0x30, 0xDB, 0x70, 0x2C, 0x0A, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x5C, 0x9D, 0xE9, 0xD5, 0x46, 0x0B, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x0B, 0x60, 0x4B, 0x37, 0x7D, 0xB9, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0x24, 0xF3, 0x3D, 0x79, 0x7F, 0x6C, 0x18), +}; +static const mbedtls_mpi_uint secp256r1_T_11_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x7F, 0xE5, 0x1C, 0x4F, 0x60, 0x24, 0xF7, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0xD8, 0xE2, 0x91, 0x7F, 0x89, 0x49, 0x92), + MBEDTLS_BYTES_TO_T_UINT_8(0x97, 0xA7, 0x2E, 0x8D, 0x6A, 0xB3, 0x39, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0x13, 0x89, 0xB5, 0x9A, 0xB8, 0x8D, 0x42, 0x9C), +}; +static const mbedtls_mpi_uint secp256r1_T_12_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0x45, 0xE6, 0x4B, 0x3F, 0x4F, 0x1E, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0x65, 0x5E, 0x59, 0x22, 0xCC, 0x72, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x93, 0x1A, 0x27, 0x1E, 0x34, 0xC5, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0xF2, 0xA5, 0x58, 0x5C, 0x15, 0x2E, 0xC6), +}; +static const mbedtls_mpi_uint secp256r1_T_12_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF4, 0x7F, 0xBA, 0x58, 0x5A, 0x84, 0x6F, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0xA6, 0x36, 0x7E, 0xDC, 0xF7, 0xE1, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x4D, 0xAA, 0xEE, 0x57, 0x76, 0x3A, 0xD3), + MBEDTLS_BYTES_TO_T_UINT_8(0x4E, 0x7E, 0x26, 0x18, 0x22, 0x23, 0x9F, 0xFF), +}; +static const mbedtls_mpi_uint secp256r1_T_13_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x4C, 0x64, 0xC7, 0x55, 0x02, 0x3F, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0x02, 0x90, 0xBB, 0xC3, 0xEC, 0x30, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x9F, 0x6F, 0x64, 0xF4, 0x16, 0x69, 0x48, 0xA4), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x44, 0x9C, 0x95, 0x0C, 0x7D, 0x67, 0x5E), +}; +static const mbedtls_mpi_uint secp256r1_T_13_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x44, 0x91, 0x8B, 0xD8, 0xD0, 0xD7, 0xE7, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0xF9, 0x48, 0x62, 0x6F, 0xA8, 0x93, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0x3A, 0x99, 0x02, 0xD5, 0x0B, 0x3D, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xD3, 0x00, 0x31, 0xE6, 0x0C, 0x9F, 0x44), +}; +static const mbedtls_mpi_uint secp256r1_T_14_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x56, 0xB2, 0xAA, 0xFD, 0x88, 0x15, 0xDF, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0x4C, 0x35, 0x27, 0x31, 0x44, 0xCD, 0xC0, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0x53, 0xF8, 0x91, 0xA5, 0x71, 0x94, 0x84, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0xCB, 0xD0, 0x93, 0xE9, 0x88, 0xDA, 0xE4), +}; +static const mbedtls_mpi_uint secp256r1_T_14_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x24, 0xC6, 0x39, 0x16, 0x5D, 0xA3, 0x1E, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x07, 0x37, 0x26, 0x36, 0x2A, 0xFE, 0x60), + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0xBC, 0xF3, 0xD0, 0xDE, 0x50, 0xFC, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0x80, 0x2E, 0x06, 0x10, 0x15, 0x4D, 0xFA, 0xF7), +}; +static const mbedtls_mpi_uint secp256r1_T_15_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0x65, 0x69, 0x5B, 0x66, 0xA2, 0x75, 0x2E), + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0x16, 0x00, 0x5A, 0xB0, 0x30, 0x25, 0x1A), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0xFB, 0x86, 0x42, 0x80, 0xC1, 0xC4, 0x76), + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0x1D, 0x83, 0x8E, 0x94, 0x01, 0x5F, 0x82), +}; +static const mbedtls_mpi_uint secp256r1_T_15_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x39, 0x37, 0x70, 0xEF, 0x1F, 0xA1, 0xF0, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0x10, 0x5B, 0xCE, 0xC4, 0x9B, 0x6F, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x11, 0x11, 0x24, 0x4F, 0x4C, 0x79, 0x61), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0x3A, 0x72, 0xBC, 0xFE, 0x72, 0x58, 0x43), +}; +static const mbedtls_ecp_point secp256r1_T[16] = { + ECP_POINT_INIT_XY_Z1(secp256r1_T_0_X, secp256r1_T_0_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_1_X, secp256r1_T_1_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_2_X, secp256r1_T_2_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_3_X, secp256r1_T_3_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_4_X, secp256r1_T_4_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_5_X, secp256r1_T_5_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_6_X, secp256r1_T_6_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_7_X, secp256r1_T_7_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_8_X, secp256r1_T_8_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_9_X, secp256r1_T_9_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_10_X, secp256r1_T_10_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_11_X, secp256r1_T_11_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_12_X, secp256r1_T_12_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_13_X, secp256r1_T_13_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_14_X, secp256r1_T_14_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_15_X, secp256r1_T_15_Y), +}; +#else +#define secp256r1_T NULL +#endif + +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +/* + * Domain parameters for secp384r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +static const mbedtls_mpi_uint secp384r1_p[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), +}; +static const mbedtls_mpi_uint secp384r1_b[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0x2A, 0xEC, 0xD3, 0xED, 0xC8, 0x85, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0xD1, 0x2E, 0x8A, 0x8D, 0x39, 0x56, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x87, 0x13, 0x50, 0x8F, 0x08, 0x14, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0x12, 0x41, 0x81, 0xFE, 0x6E, 0x9C, 0x1D, 0x18), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x2D, 0xF8, 0xE3, 0x6B, 0x05, 0x8E, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0xE7, 0x3E, 0xE2, 0xA7, 0x2F, 0x31, 0xB3), +}; +static const mbedtls_mpi_uint secp384r1_gx[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0x0A, 0x76, 0x72, 0x38, 0x5E, 0x54, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x29, 0x55, 0xBF, 0x5D, 0xF2, 0x02, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0x2A, 0x54, 0x82, 0xE0, 0x41, 0xF7, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x9B, 0xA7, 0x8B, 0x62, 0x3B, 0x1D, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0xAD, 0x20, 0xF3, 0x1E, 0xC7, 0xB1, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x05, 0x8B, 0xBE, 0x22, 0xCA, 0x87, 0xAA), +}; +static const mbedtls_mpi_uint secp384r1_gy[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x0E, 0xEA, 0x90, 0x7C, 0x1D, 0x43, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0x81, 0x7E, 0x1D, 0xCE, 0xB1, 0x60, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0xB8, 0xF0, 0xB5, 0x13, 0x31, 0xDA, 0xE9), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x14, 0x9A, 0x28, 0xBD, 0x1D, 0xF4, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0xDC, 0x92, 0x92, 0xBF, 0x98, 0x9E, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x6F, 0x2C, 0x26, 0x96, 0x4A, 0xDE, 0x17, 0x36), +}; +static const mbedtls_mpi_uint secp384r1_n[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x73, 0x29, 0xC5, 0xCC, 0x6A, 0x19, 0xEC, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0x7A, 0xA7, 0xB0, 0x48, 0xB2, 0x0D, 0x1A, 0x58), + MBEDTLS_BYTES_TO_T_UINT_8(0xDF, 0x2D, 0x37, 0xF4, 0x81, 0x4D, 0x63, 0xC7), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), +}; +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 +static const mbedtls_mpi_uint secp384r1_T_0_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0x0A, 0x76, 0x72, 0x38, 0x5E, 0x54, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x29, 0x55, 0xBF, 0x5D, 0xF2, 0x02, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0x2A, 0x54, 0x82, 0xE0, 0x41, 0xF7, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x9B, 0xA7, 0x8B, 0x62, 0x3B, 0x1D, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0xAD, 0x20, 0xF3, 0x1E, 0xC7, 0xB1, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x05, 0x8B, 0xBE, 0x22, 0xCA, 0x87, 0xAA), +}; +static const mbedtls_mpi_uint secp384r1_T_0_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x0E, 0xEA, 0x90, 0x7C, 0x1D, 0x43, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0x81, 0x7E, 0x1D, 0xCE, 0xB1, 0x60, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0xB8, 0xF0, 0xB5, 0x13, 0x31, 0xDA, 0xE9), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x14, 0x9A, 0x28, 0xBD, 0x1D, 0xF4, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0xDC, 0x92, 0x92, 0xBF, 0x98, 0x9E, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x6F, 0x2C, 0x26, 0x96, 0x4A, 0xDE, 0x17, 0x36), +}; +static const mbedtls_mpi_uint secp384r1_T_1_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0x92, 0x00, 0x2C, 0x78, 0xDB, 0x1F, 0x37), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0xF3, 0xEB, 0xB7, 0x06, 0xF7, 0xB6, 0xBC), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0xBC, 0x2C, 0xCF, 0xD8, 0xED, 0x53, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0x75, 0x7B, 0xA3, 0xAB, 0xC3, 0x2C, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0xE5, 0x9D, 0x78, 0x41, 0xF6, 0x76, 0x84, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0x54, 0x56, 0xE8, 0x52, 0xB3, 0xCB, 0xA8, 0xBD), +}; +static const mbedtls_mpi_uint secp384r1_T_1_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0xF2, 0xAE, 0xA4, 0xB6, 0x89, 0x1B, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0x0F, 0xCE, 0x1C, 0x7C, 0xF6, 0x50, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0x4C, 0xEB, 0x90, 0xE6, 0x4D, 0xC7, 0xD4, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0xD1, 0x49, 0x2D, 0x8A, 0x01, 0x99, 0x60, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x80, 0x9B, 0x9B, 0x6A, 0xB0, 0x07, 0xD9), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0xA2, 0xEE, 0x59, 0xBE, 0x95, 0xBC, 0x23), +}; +static const mbedtls_mpi_uint secp384r1_T_2_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0x9D, 0x56, 0xAE, 0x59, 0xFB, 0x1F, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0xCF, 0xAC, 0x91, 0x80, 0x87, 0xA8, 0x6E, 0x58), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0x08, 0xA7, 0x08, 0x94, 0x32, 0xFC, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0x9F, 0x29, 0x9E, 0x84, 0xF4, 0xE5, 0x6E, 0x7E), + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0x21, 0xB9, 0x50, 0x24, 0xF8, 0x9C, 0xC7), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0x04, 0x01, 0xC2, 0xFB, 0x77, 0x3E, 0xDE), +}; +static const mbedtls_mpi_uint secp384r1_T_2_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x38, 0xEE, 0xE3, 0xC7, 0x9D, 0xEC, 0xA6), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x88, 0xCF, 0x43, 0xFA, 0x92, 0x5E, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0xCA, 0x43, 0xF8, 0x3B, 0x49, 0x7E, 0x75), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0xE7, 0xEB, 0x17, 0x45, 0x86, 0xC2, 0xE1), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x69, 0x57, 0x32, 0xE0, 0x9C, 0xD1, 0x00), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x10, 0xB8, 0x4D, 0xB8, 0xF4, 0x0D, 0xE3), +}; +static const mbedtls_mpi_uint secp384r1_T_3_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x60, 0xDC, 0x9A, 0xB2, 0x79, 0x39, 0x27, 0x16), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0x71, 0xE4, 0x3B, 0x4D, 0x60, 0x0C, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0xBD, 0x19, 0x40, 0xFA, 0x19, 0x2A, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0x4D, 0xF8, 0x1E, 0x43, 0xA1, 0x50, 0x8D, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0xA3, 0x18, 0x7C, 0x41, 0xFA, 0x7C, 0x1B, 0x58), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x59, 0x24, 0xC4, 0xE9, 0xB7, 0xD3, 0xAD), +}; +static const mbedtls_mpi_uint secp384r1_T_3_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0x01, 0x3D, 0x63, 0x54, 0x45, 0x6F, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0xB2, 0x19, 0xA3, 0x86, 0x1D, 0x42, 0x34), + MBEDTLS_BYTES_TO_T_UINT_8(0x84, 0x02, 0x87, 0x18, 0x92, 0x52, 0x1A, 0x71), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x18, 0xB1, 0x5D, 0x18, 0x1B, 0x37, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0xF4, 0x74, 0x61, 0xBA, 0x18, 0xAF, 0x40, 0x30), + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x7D, 0x3C, 0x52, 0x0F, 0x07, 0xB0, 0x6F), +}; +static const mbedtls_mpi_uint secp384r1_T_4_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0x39, 0x13, 0xAA, 0x60, 0x15, 0x99, 0x30), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0x00, 0xCB, 0xC6, 0xB1, 0xDB, 0x97, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0xFA, 0x60, 0xB8, 0x24, 0xE4, 0x7D, 0xD3), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x75, 0xB3, 0x70, 0xB2, 0x83, 0xB1, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0xA3, 0xE3, 0x6C, 0xCD, 0x33, 0x62, 0x7A, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0x88, 0x30, 0xDC, 0x0F, 0x9F, 0xBB, 0xB8, 0xAA), +}; +static const mbedtls_mpi_uint secp384r1_T_4_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA6, 0xD5, 0x0A, 0x60, 0x81, 0xB9, 0xC5, 0x16), + MBEDTLS_BYTES_TO_T_UINT_8(0x44, 0xAA, 0x2F, 0xD6, 0xF2, 0x73, 0xDF, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0x7B, 0x74, 0xC9, 0xB3, 0x5B, 0x95, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x04, 0xEB, 0x15, 0xC8, 0x5F, 0x00, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0xB5, 0x50, 0x20, 0x28, 0xD1, 0x01, 0xAF, 0xF0), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x6D, 0x4F, 0x31, 0x81, 0x2F, 0x94, 0x48), +}; +static const mbedtls_mpi_uint secp384r1_T_5_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0x2F, 0xD8, 0xB6, 0x63, 0x7C, 0xE9, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x8C, 0xB9, 0x14, 0xD9, 0x37, 0x63, 0xDE), + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0x02, 0xB8, 0x46, 0xAD, 0xCE, 0x7B, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0x82, 0x47, 0x2D, 0x66, 0xA7, 0xE9, 0x33, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0xF9, 0x93, 0x94, 0xA8, 0x48, 0xB3, 0x4F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0x4A, 0xAC, 0x51, 0x08, 0x72, 0x2F, 0x1A), +}; +static const mbedtls_mpi_uint secp384r1_T_5_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0xAD, 0xA0, 0xF9, 0x81, 0xE1, 0x78, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0x9A, 0x63, 0xD8, 0xBA, 0x79, 0x1A, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0x31, 0x7B, 0x7A, 0x5A, 0x5D, 0x7D, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x96, 0x12, 0x4B, 0x19, 0x09, 0xE0, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0x8A, 0x57, 0xEE, 0x4E, 0x6E, 0x7E, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0x9D, 0x69, 0xDC, 0xB3, 0xDA, 0xD8, 0x08), +}; +static const mbedtls_mpi_uint secp384r1_T_6_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x49, 0x03, 0x03, 0x33, 0x6F, 0x28, 0x4A), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0xDB, 0xA7, 0x05, 0x8C, 0xF3, 0x4D, 0xFB), + MBEDTLS_BYTES_TO_T_UINT_8(0x8E, 0x92, 0xB1, 0xA8, 0xEC, 0x0D, 0x64, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0x4E, 0xFC, 0xFD, 0xD0, 0x4B, 0x88, 0x1B, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x9C, 0x51, 0x69, 0xCE, 0x71, 0x73, 0xF5), + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0x5A, 0x14, 0x23, 0x1A, 0x46, 0x63, 0x5F), +}; +static const mbedtls_mpi_uint secp384r1_T_6_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0x4C, 0x70, 0x44, 0x18, 0xCD, 0xEF, 0xED), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x49, 0xDD, 0x64, 0x7E, 0x7E, 0x4D, 0x92), + MBEDTLS_BYTES_TO_T_UINT_8(0xA2, 0x32, 0x7C, 0x09, 0xD0, 0x3F, 0xD6, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0xE0, 0x4F, 0x65, 0x0C, 0x7A, 0x54, 0x3E), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0xFA, 0xFB, 0x4A, 0xB4, 0x79, 0x5A, 0x8C), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x5D, 0x1B, 0x2B, 0xDA, 0xBC, 0x9A, 0x74), +}; +static const mbedtls_mpi_uint secp384r1_T_7_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0xAC, 0x56, 0xF7, 0x5F, 0x51, 0x68, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0xE0, 0x1D, 0xBC, 0x13, 0x4E, 0xAC, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0xF5, 0xC5, 0xE6, 0xD2, 0x88, 0xBA, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x0E, 0x28, 0x23, 0x58, 0x67, 0xFA, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0x9E, 0x80, 0x4B, 0xD8, 0xC4, 0xDF, 0x15, 0xE4), + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x0E, 0x58, 0xE6, 0x2C, 0x59, 0xC2, 0x03), +}; +static const mbedtls_mpi_uint secp384r1_T_7_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x26, 0x27, 0x99, 0x16, 0x2B, 0x22, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0xF3, 0x8F, 0xC3, 0x2A, 0x9B, 0xFC, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x2E, 0x83, 0x3D, 0xFE, 0x9E, 0x3C, 0x1B), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0x57, 0xCD, 0x2D, 0xC1, 0x49, 0x38, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0x42, 0x8B, 0x33, 0x89, 0x1F, 0xEA, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0xAA, 0x1D, 0x13, 0xD7, 0x50, 0xBB, 0x3E, 0xEB), +}; +static const mbedtls_mpi_uint secp384r1_T_8_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD2, 0x9A, 0x52, 0xD2, 0x54, 0x7C, 0x97, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0xE0, 0x33, 0x6E, 0xED, 0xD9, 0x87, 0x50, 0xC5), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x35, 0x7E, 0x16, 0x40, 0x15, 0x83, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0x33, 0x2B, 0xA4, 0xAB, 0x03, 0x91, 0xEA, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0x47, 0x39, 0xEF, 0x05, 0x59, 0xD0, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0xBF, 0x24, 0x0D, 0x76, 0x11, 0x53, 0x08, 0xAF), +}; +static const mbedtls_mpi_uint secp384r1_T_8_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x2F, 0xDD, 0xBD, 0x50, 0x48, 0xB1, 0xE5), + MBEDTLS_BYTES_TO_T_UINT_8(0x80, 0x1C, 0x84, 0x55, 0x78, 0x14, 0xEB, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x5E, 0x3E, 0xA6, 0xAF, 0xF6, 0xC7, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0xE7, 0x11, 0xE2, 0x65, 0xCA, 0x41, 0x95, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0x83, 0xD8, 0xE6, 0x4D, 0x22, 0x06, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x7F, 0x25, 0x2A, 0xAA, 0x28, 0x46, 0x97), +}; +static const mbedtls_mpi_uint secp384r1_T_9_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x79, 0xDB, 0x15, 0x56, 0x84, 0xCB, 0xC0, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0x56, 0xDB, 0x0E, 0x08, 0xC9, 0xF5, 0xD4, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0x62, 0xD0, 0x1A, 0x7C, 0x13, 0xD5, 0x07), + MBEDTLS_BYTES_TO_T_UINT_8(0x7D, 0xAD, 0x53, 0xE0, 0x32, 0x21, 0xA0, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0x38, 0x81, 0x21, 0x23, 0x0E, 0xD2, 0xBB), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x51, 0x05, 0xD0, 0x1E, 0x82, 0xA9, 0x71), +}; +static const mbedtls_mpi_uint secp384r1_T_9_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0xC3, 0x27, 0xBF, 0xC6, 0xAA, 0xB7, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x65, 0x45, 0xDF, 0xB9, 0x46, 0x17, 0x46), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0x38, 0x3F, 0xB2, 0xB1, 0x5D, 0xCA, 0x1C), + MBEDTLS_BYTES_TO_T_UINT_8(0x88, 0x29, 0x6C, 0x63, 0xE9, 0xD7, 0x48, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0xF1, 0xD7, 0x99, 0x8C, 0xC2, 0x05, 0x99), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0xE6, 0x5E, 0x82, 0x6D, 0xE5, 0x7E, 0xD5), +}; +static const mbedtls_mpi_uint secp384r1_T_10_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0x61, 0xFA, 0x7D, 0x01, 0xDB, 0xB6, 0x63), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0xC6, 0x58, 0x39, 0xF4, 0xC6, 0x82, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0x5A, 0x7A, 0x80, 0x08, 0xCD, 0xAA, 0xD8), + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x8C, 0xC6, 0x3F, 0x3C, 0xA5, 0x68, 0xF4), + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0xF5, 0xD5, 0x17, 0xAE, 0x36, 0xD8, 0x8A), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0xAD, 0x92, 0xC5, 0x57, 0x6C, 0xDA, 0x91), +}; +static const mbedtls_mpi_uint secp384r1_T_10_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x67, 0x17, 0xC0, 0x40, 0x78, 0x8C, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0x9F, 0xF4, 0xAA, 0xDA, 0x5C, 0x7E, 0xB2), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0xDB, 0x42, 0x3E, 0x72, 0x64, 0xA0, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0xF9, 0x41, 0x17, 0x43, 0xE3, 0xE8, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0xDD, 0xCC, 0x43, 0x7E, 0x16, 0x05, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0x4B, 0xCF, 0x48, 0x8F, 0x41, 0x90, 0xE5), +}; +static const mbedtls_mpi_uint secp384r1_T_11_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x0C, 0x6B, 0x9D, 0x22, 0x04, 0xBC, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0x63, 0x79, 0x2F, 0x6A, 0x0E, 0x8A, 0xDE), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0x67, 0x3F, 0x02, 0xB8, 0x91, 0x7F, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x14, 0x64, 0xA0, 0x33, 0xF4, 0x6B, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x44, 0x71, 0x87, 0xB8, 0x88, 0x3F, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0x1B, 0x2B, 0x85, 0x05, 0xC5, 0x44, 0x53, 0x15), +}; +static const mbedtls_mpi_uint secp384r1_T_11_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0x2B, 0xFE, 0xD1, 0x1C, 0x73, 0xE3, 0x2E), + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0x33, 0xA1, 0xD3, 0x69, 0x1C, 0x9D, 0xD2), + MBEDTLS_BYTES_TO_T_UINT_8(0xE0, 0x5A, 0xBA, 0xB6, 0xAE, 0x1B, 0x94, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0x74, 0x90, 0x5C, 0x57, 0xB0, 0x3A, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x2F, 0x93, 0x20, 0x24, 0x54, 0x1D, 0x8D), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x78, 0x9D, 0x71, 0x67, 0x5D, 0x49, 0x98), +}; +static const mbedtls_mpi_uint secp384r1_T_12_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x12, 0xC8, 0x0E, 0x11, 0x8D, 0xE0, 0x8F, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0x7F, 0x79, 0x6C, 0x5F, 0xB7, 0xBC, 0xB1), + MBEDTLS_BYTES_TO_T_UINT_8(0x88, 0xE1, 0x83, 0x3C, 0x12, 0xBB, 0xEE, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0xC2, 0xC4, 0x1B, 0x41, 0x71, 0xB9, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0xEE, 0xBB, 0x1D, 0x89, 0x50, 0x88, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x1C, 0x55, 0x74, 0xEB, 0xDE, 0x92, 0x3F), +}; +static const mbedtls_mpi_uint secp384r1_T_12_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0x38, 0x92, 0x06, 0x19, 0xD0, 0xB3, 0xB2), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0x99, 0x26, 0xA3, 0x5F, 0xE2, 0xC1, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0x75, 0xFC, 0xFD, 0xC3, 0xB6, 0x26, 0x24, 0x8F), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0xAD, 0xE7, 0x49, 0xB7, 0x64, 0x4B, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x4E, 0x95, 0xAD, 0x07, 0xFE, 0xB6, 0x30), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0x15, 0xE7, 0x2D, 0x19, 0xA9, 0x08, 0x10), +}; +static const mbedtls_mpi_uint secp384r1_T_13_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0xBD, 0xAC, 0x0A, 0x3F, 0x6B, 0xFF, 0xFA), + MBEDTLS_BYTES_TO_T_UINT_8(0xE0, 0xE4, 0x74, 0x14, 0xD9, 0x70, 0x1D, 0x71), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0xB0, 0x71, 0xBB, 0xD8, 0x18, 0x96, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0xB8, 0x19, 0x90, 0x80, 0xB5, 0xEE, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0x21, 0x20, 0xA6, 0x17, 0x48, 0x03, 0x6F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x1D, 0xBB, 0x6D, 0x94, 0x20, 0x34, 0xF1), +}; +static const mbedtls_mpi_uint secp384r1_T_13_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0x82, 0x67, 0x4B, 0x8E, 0x4E, 0xBE, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0xDA, 0x77, 0xF8, 0x23, 0x55, 0x2B, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0x02, 0xDE, 0x25, 0x35, 0x2D, 0x74, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0xD0, 0x0C, 0xB8, 0x0B, 0x39, 0xBA, 0xAD, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0xA6, 0x0E, 0x28, 0x4D, 0xE1, 0x3D, 0xE4, 0x1B), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0xEC, 0x0A, 0xD4, 0xB8, 0xC4, 0x8D, 0xB0), +}; +static const mbedtls_mpi_uint secp384r1_T_14_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0x68, 0xCE, 0xC2, 0x55, 0x4D, 0x0C, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x20, 0x93, 0x32, 0x90, 0xD6, 0xAE, 0x47), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x78, 0xAB, 0x43, 0x9E, 0xEB, 0x73, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0x97, 0xC3, 0x83, 0xA6, 0x3C, 0xF1, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0x0F, 0x25, 0x25, 0x66, 0x08, 0x26, 0xFA, 0x4B), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0xFB, 0x44, 0x5D, 0x82, 0xEC, 0x3B, 0xAC), +}; +static const mbedtls_mpi_uint secp384r1_T_14_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0x90, 0xEA, 0xB5, 0x04, 0x99, 0xD0, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0x4A, 0xF2, 0x22, 0xA0, 0xEB, 0xFD, 0x45, 0x87), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0xA4, 0x81, 0x32, 0xFC, 0xFA, 0xEE, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0xBB, 0xA4, 0x6A, 0x77, 0x41, 0x5C, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0xA1, 0x1E, 0xAA, 0x4F, 0xF0, 0x10, 0xB3, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0x74, 0x13, 0x14, 0x9E, 0x90, 0xD7, 0xE6), +}; +static const mbedtls_mpi_uint secp384r1_T_15_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0xBD, 0x70, 0x4F, 0xA8, 0xD1, 0x06, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x4E, 0x2E, 0x68, 0xFC, 0x35, 0xFA, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x60, 0x53, 0x75, 0xED, 0xF2, 0x5F, 0xC2, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0x39, 0x87, 0x6B, 0x9F, 0x05, 0xE2, 0x22, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0x1A, 0xA8, 0xB7, 0x03, 0x9E, 0x6D, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0xD0, 0x69, 0x88, 0xA8, 0x39, 0x9E, 0x3A), +}; +static const mbedtls_mpi_uint secp384r1_T_15_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0xEF, 0x68, 0xFE, 0xEC, 0x24, 0x08, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0xA1, 0x06, 0x4B, 0x92, 0x0D, 0xB7, 0x34, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0xF4, 0xDD, 0x1A, 0xA0, 0x4A, 0xE4, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0xC3, 0x63, 0x4F, 0x4F, 0xCE, 0xBB, 0xD6, 0xD3), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0xEE, 0x8D, 0xDF, 0x3F, 0x73, 0xB7, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0xDF, 0x06, 0xB6, 0x80, 0x4D, 0x81, 0xD9, 0x53), +}; +static const mbedtls_mpi_uint secp384r1_T_16_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0xF5, 0x13, 0xDF, 0x13, 0x19, 0x97, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0xF9, 0xB3, 0x33, 0x66, 0x82, 0x21, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xFC, 0x39, 0x16, 0x23, 0x43, 0x76, 0x0E), + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0x48, 0x25, 0xA1, 0x64, 0x95, 0x1C, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x43, 0xAC, 0x15, 0x57, 0xD9, 0xDE, 0xA0, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0x5F, 0xB8, 0x3D, 0x48, 0x91, 0x24, 0xCC), +}; +static const mbedtls_mpi_uint secp384r1_T_16_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0xF2, 0xC8, 0x54, 0xD1, 0x32, 0xBD, 0xC4), + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0x3B, 0xF0, 0xAA, 0x9D, 0xD8, 0xF4, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0xC3, 0xBB, 0x6C, 0x66, 0xAC, 0x25, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x6F, 0x25, 0x10, 0xB2, 0xE1, 0x41, 0xDE, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0xE8, 0x30, 0xB8, 0x37, 0xBC, 0x2A, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x57, 0x01, 0x4A, 0x1E, 0x78, 0x9F, 0x85), +}; +static const mbedtls_mpi_uint secp384r1_T_17_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBD, 0x19, 0xCD, 0x12, 0x0B, 0x51, 0x4F, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0x4B, 0x3D, 0x24, 0xA4, 0x16, 0x59, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xEB, 0xD3, 0x59, 0x2E, 0x75, 0x7C, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0xB9, 0xB4, 0xA5, 0xD9, 0x2E, 0x29, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0x16, 0x05, 0x75, 0x02, 0xB3, 0x06, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0x7C, 0x9F, 0x79, 0x91, 0xF1, 0x4F, 0x23), +}; +static const mbedtls_mpi_uint secp384r1_T_17_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x98, 0x7C, 0x84, 0xE1, 0xFF, 0x30, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0xE2, 0xC2, 0x5F, 0x55, 0x40, 0xBD, 0xCD), + MBEDTLS_BYTES_TO_T_UINT_8(0x69, 0x65, 0x87, 0x3F, 0xC4, 0xC2, 0x24, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0x30, 0x0A, 0x60, 0x15, 0xD1, 0x24, 0x48), + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0x99, 0xD9, 0xB6, 0xAE, 0xB1, 0xAF, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x80, 0xEE, 0xA2, 0x0F, 0x74, 0xB9, 0xF3), +}; +static const mbedtls_mpi_uint secp384r1_T_18_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x03, 0xE6, 0x0F, 0x37, 0xC1, 0x10, 0x99, 0x1E), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0xAD, 0x9D, 0x5D, 0x80, 0x01, 0xA6, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x0F, 0x10, 0x2A, 0x9D, 0x20, 0x38, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x60, 0xCB, 0xCE, 0x5A, 0xA0, 0xA7, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0xCF, 0x14, 0xDF, 0xBF, 0xE5, 0x74, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0xB5, 0x12, 0x1A, 0xDD, 0x59, 0x02, 0x5D, 0xC6), +}; +static const mbedtls_mpi_uint secp384r1_T_18_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0xC9, 0xF8, 0xF5, 0xB6, 0x13, 0x4D, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0x45, 0xB1, 0x93, 0xB3, 0xA2, 0x79, 0xDC), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0xF6, 0xCF, 0xF7, 0xE6, 0x29, 0x9C, 0xCC), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0x50, 0x65, 0x80, 0xBC, 0x59, 0x0A, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0xF0, 0x24, 0x35, 0xA2, 0x46, 0xF0, 0x0C), + MBEDTLS_BYTES_TO_T_UINT_8(0xBD, 0x26, 0xC0, 0x9D, 0x61, 0x56, 0x62, 0x67), +}; +static const mbedtls_mpi_uint secp384r1_T_19_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0xBB, 0xC2, 0x24, 0x43, 0x2E, 0x37, 0x54), + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0xF7, 0xCE, 0x35, 0xFC, 0x77, 0xF3, 0x3F), + MBEDTLS_BYTES_TO_T_UINT_8(0x75, 0x34, 0x96, 0xD5, 0x4A, 0x76, 0x9D, 0x6B), + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0x3B, 0x0F, 0xEA, 0xA8, 0x12, 0x0B, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0x3F, 0x5D, 0x2D, 0x1C, 0xD4, 0x9E, 0xFB), + MBEDTLS_BYTES_TO_T_UINT_8(0x7D, 0x2E, 0xDD, 0xC7, 0x6E, 0xAB, 0xAF, 0xDC), +}; +static const mbedtls_mpi_uint secp384r1_T_19_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0xB2, 0x7B, 0x0C, 0x9A, 0x83, 0x8E, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0x51, 0x90, 0x92, 0x79, 0x32, 0x19, 0xC3), + MBEDTLS_BYTES_TO_T_UINT_8(0xEE, 0x89, 0xF9, 0xD0, 0xCF, 0x2C, 0xA5, 0x8F), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0x50, 0x21, 0xDE, 0x50, 0x41, 0x9D, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0xE0, 0x7D, 0x2B, 0x9E, 0x9D, 0x95, 0xA8, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0xA5, 0x20, 0x87, 0x88, 0x97, 0x5F, 0xAA), +}; +static const mbedtls_mpi_uint secp384r1_T_20_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x59, 0xB4, 0x66, 0x7E, 0xE8, 0x5A, 0x60), + MBEDTLS_BYTES_TO_T_UINT_8(0xA5, 0x5C, 0x7E, 0xB2, 0xAD, 0xD9, 0xC9, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0x82, 0x97, 0x49, 0xA3, 0x13, 0x83, 0x07, 0x2E), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x26, 0xC7, 0x13, 0x35, 0x0D, 0xB0, 0x6B), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0x60, 0xAB, 0xFA, 0x4B, 0x93, 0x18, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x54, 0x2D, 0x1C, 0x31, 0x4C, 0xE4, 0x61, 0xAE), +}; +static const mbedtls_mpi_uint secp384r1_T_20_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xDE, 0x4D, 0x1E, 0x51, 0x59, 0x6E, 0x91, 0xC5), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0x54, 0x4D, 0x51, 0xED, 0x36, 0xCC, 0x60), + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0xA8, 0x56, 0xC7, 0x78, 0x27, 0x33, 0xC5), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0xB7, 0x95, 0xC9, 0x8B, 0xC8, 0x6A, 0xBC), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0xE9, 0x13, 0x96, 0xB3, 0xE1, 0xF9, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0x46, 0xB0, 0x5E, 0xC3, 0x94, 0x03, 0x05), +}; +static const mbedtls_mpi_uint secp384r1_T_21_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x5B, 0x29, 0x30, 0x41, 0x1A, 0x9E, 0xB6), + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0xCA, 0x83, 0x31, 0x5B, 0xA7, 0xCB, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0x41, 0x50, 0x44, 0x4D, 0x64, 0x31, 0x89), + MBEDTLS_BYTES_TO_T_UINT_8(0xCF, 0x84, 0xC2, 0x5D, 0x97, 0xA5, 0x3C, 0x18), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0x0F, 0xA5, 0xFD, 0x8E, 0x5A, 0x47, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x58, 0x02, 0x2D, 0x40, 0xB1, 0x0B, 0xBA), +}; +static const mbedtls_mpi_uint secp384r1_T_21_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x33, 0x8C, 0x67, 0xCE, 0x23, 0x43, 0x99), + MBEDTLS_BYTES_TO_T_UINT_8(0x84, 0x53, 0x47, 0x72, 0x44, 0x1F, 0x5B, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0xC1, 0xD9, 0xA4, 0x50, 0x88, 0x63, 0x18), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0xF2, 0x75, 0x69, 0x73, 0x00, 0xC4, 0x31), + MBEDTLS_BYTES_TO_T_UINT_8(0x4B, 0x90, 0x1D, 0xDF, 0x1A, 0x00, 0xD8, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0x05, 0xB1, 0x89, 0x48, 0xA8, 0x70, 0x62, 0xEF), +}; +static const mbedtls_mpi_uint secp384r1_T_22_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0x8A, 0x55, 0x50, 0x7B, 0xEF, 0x8A, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0xFE, 0x1B, 0x23, 0x48, 0x23, 0x63, 0x91, 0xB6), + MBEDTLS_BYTES_TO_T_UINT_8(0x0D, 0x04, 0x54, 0x3C, 0x24, 0x9B, 0xC7, 0x9A), + MBEDTLS_BYTES_TO_T_UINT_8(0x25, 0x38, 0xC3, 0x84, 0xFB, 0xFF, 0x9F, 0x49), + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0x2A, 0xE0, 0x6D, 0x68, 0x8A, 0x5C, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0xC4, 0x93, 0x53, 0x85, 0xA1, 0x0D, 0xAF, 0x63), +}; +static const mbedtls_mpi_uint secp384r1_T_22_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1B, 0x88, 0x95, 0x4C, 0x0B, 0xD0, 0x06, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0xAF, 0x8D, 0x49, 0xA2, 0xC8, 0xB4, 0xE0), + MBEDTLS_BYTES_TO_T_UINT_8(0x75, 0x76, 0x53, 0x09, 0x88, 0x43, 0x87, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0x90, 0xA4, 0x77, 0x3F, 0x5E, 0x21, 0xB4, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0x35, 0x9E, 0x86, 0x64, 0xCC, 0x91, 0xC1, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0x17, 0x56, 0xCB, 0xC3, 0x7D, 0x5B, 0xB1), +}; +static const mbedtls_mpi_uint secp384r1_T_23_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x74, 0x9F, 0xB5, 0x91, 0x21, 0xB1, 0x1C), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xED, 0xE1, 0x11, 0xEF, 0x45, 0xAF, 0xC1), + MBEDTLS_BYTES_TO_T_UINT_8(0xE0, 0x31, 0xBE, 0xB2, 0xBC, 0x72, 0x65, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0xB1, 0x4B, 0x8C, 0x77, 0xCE, 0x1E, 0x42, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xC9, 0xAA, 0xB9, 0xD9, 0x86, 0x99, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x23, 0x80, 0xC6, 0x4E, 0x35, 0x0B, 0x6D), +}; +static const mbedtls_mpi_uint secp384r1_T_23_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0xD8, 0xA2, 0x0A, 0x39, 0x32, 0x1D, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0xC8, 0x86, 0xF1, 0x12, 0x9A, 0x4A, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xF1, 0x7C, 0xAA, 0x70, 0x8E, 0xBC, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0x62, 0x01, 0x47, 0x8F, 0xDD, 0x8B, 0xA5, 0xC8), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x08, 0x21, 0xF4, 0xAB, 0xC7, 0xF5, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0x0A, 0x76, 0xA5, 0x95, 0xC4, 0x0F, 0x88, 0x1D), +}; +static const mbedtls_mpi_uint secp384r1_T_24_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0x42, 0x2A, 0x52, 0xCD, 0x75, 0x51, 0x49), + MBEDTLS_BYTES_TO_T_UINT_8(0x90, 0x36, 0xE5, 0x04, 0x2B, 0x44, 0xC6, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0xEE, 0x16, 0x13, 0x07, 0x83, 0xB5, 0x30), + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0x59, 0xC6, 0xA2, 0x19, 0x05, 0xD3, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x8B, 0xA8, 0x16, 0x09, 0xB7, 0xEA, 0xD6), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0xEE, 0x14, 0xAF, 0xB5, 0xFD, 0xD0, 0xEF), +}; +static const mbedtls_mpi_uint secp384r1_T_24_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0x7C, 0xCA, 0x71, 0x3E, 0x6E, 0x66, 0x75), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0x31, 0x0E, 0x3F, 0xE5, 0x91, 0xC4, 0x7F), + MBEDTLS_BYTES_TO_T_UINT_8(0x8E, 0x3D, 0xC2, 0x3E, 0x95, 0x37, 0x58, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0x1F, 0x02, 0x03, 0xF3, 0xEF, 0xEE, 0x66), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x5B, 0x1A, 0xFC, 0x38, 0xCD, 0xE8, 0x24), + MBEDTLS_BYTES_TO_T_UINT_8(0x12, 0x57, 0x42, 0x85, 0xC6, 0x21, 0x68, 0x71), +}; +static const mbedtls_mpi_uint secp384r1_T_25_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xA2, 0x4A, 0x66, 0xB1, 0x0A, 0xE6, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0x0C, 0x94, 0x9D, 0x5E, 0x99, 0xB2, 0xCE), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0x03, 0x40, 0xCA, 0xB2, 0xB3, 0x30, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0x78, 0x48, 0x27, 0x34, 0x1E, 0xE2, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0x72, 0x5B, 0xAC, 0xC1, 0x6D, 0xE3, 0x82), + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0xAB, 0x46, 0xCB, 0xEA, 0x5E, 0x4B, 0x0B), +}; +static const mbedtls_mpi_uint secp384r1_T_25_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x08, 0xAD, 0x4E, 0x51, 0x9F, 0x2A, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x5C, 0x7D, 0x4C, 0xD6, 0xCF, 0xDD, 0x02), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0x76, 0x26, 0xE0, 0x8B, 0x10, 0xD9, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0xA7, 0x23, 0x4E, 0x5F, 0xD2, 0x42, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0xD1, 0xE5, 0xA4, 0xEC, 0x77, 0x21, 0x34, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0x14, 0x65, 0xEA, 0x4A, 0x85, 0xC3, 0x2F), +}; +static const mbedtls_mpi_uint secp384r1_T_26_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0xD8, 0x40, 0x27, 0x73, 0x15, 0x7E, 0x65), + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0xBB, 0x53, 0x7E, 0x0F, 0x40, 0xC8, 0xD4), + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0x37, 0x19, 0x73, 0xEF, 0x5A, 0x5E, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0x73, 0x2B, 0x49, 0x7E, 0xAC, 0x97, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0xB2, 0xC3, 0x1E, 0x0E, 0xE7, 0xD2, 0x21), + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0x08, 0xD6, 0xDD, 0xAC, 0x21, 0xD6, 0x3E), +}; +static const mbedtls_mpi_uint secp384r1_T_26_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA9, 0x26, 0xBE, 0x6D, 0x6D, 0xF2, 0x38, 0x3F), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0x6C, 0x31, 0xA7, 0x49, 0x50, 0x3A, 0x89), + MBEDTLS_BYTES_TO_T_UINT_8(0xC3, 0x99, 0xC6, 0xF5, 0xD2, 0xC2, 0x30, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0xE4, 0xF6, 0x8B, 0x8B, 0x97, 0xE9, 0xB2), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x21, 0xB7, 0x0D, 0xFC, 0x15, 0x54, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x83, 0x1C, 0xA4, 0xCD, 0x6B, 0x9D, 0xF2), +}; +static const mbedtls_mpi_uint secp384r1_T_27_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0xE8, 0x4C, 0x48, 0xE4, 0xAA, 0x69, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0x7A, 0x27, 0xFC, 0x37, 0x96, 0x1A, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0x6F, 0xE7, 0x30, 0xA5, 0xCF, 0x13, 0x46, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0xD8, 0xAF, 0x74, 0x23, 0x4D, 0x56, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0x32, 0x3D, 0x44, 0x14, 0x1B, 0x97, 0x83, 0xF0), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x47, 0xD7, 0x5F, 0xFD, 0x98, 0x38, 0xF7), +}; +static const mbedtls_mpi_uint secp384r1_T_27_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA3, 0x73, 0x64, 0x36, 0xFD, 0x7B, 0xC1, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0x5D, 0x32, 0xD2, 0x47, 0x94, 0x89, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0xE9, 0x30, 0xAC, 0x06, 0xC8, 0x65, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x6C, 0xB9, 0x1B, 0xF7, 0x61, 0x49, 0x53), + MBEDTLS_BYTES_TO_T_UINT_8(0xD7, 0xFF, 0x32, 0x43, 0x80, 0xDA, 0xA6, 0xB1), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xF8, 0x04, 0x01, 0x95, 0x35, 0xCE, 0x21), +}; +static const mbedtls_mpi_uint secp384r1_T_28_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x06, 0x46, 0x0D, 0x51, 0xE2, 0xD8, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0x14, 0x57, 0x1D, 0x6F, 0x79, 0xA0, 0xCD, 0xA6), + MBEDTLS_BYTES_TO_T_UINT_8(0xDF, 0xFB, 0x36, 0xCA, 0xAD, 0xF5, 0x9E, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0x6F, 0x7A, 0x1D, 0x9E, 0x1D, 0x95, 0x48, 0xDC), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0x26, 0xA5, 0xB7, 0x15, 0x2C, 0xC2, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0x42, 0x72, 0xAA, 0x11, 0xDC, 0xC9, 0xB6), +}; +static const mbedtls_mpi_uint secp384r1_T_28_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0x6C, 0x64, 0xA7, 0x62, 0x3C, 0xAB, 0xD4), + MBEDTLS_BYTES_TO_T_UINT_8(0x48, 0x6A, 0x44, 0xD8, 0x60, 0xC0, 0xA8, 0x80), + MBEDTLS_BYTES_TO_T_UINT_8(0x82, 0x76, 0x58, 0x12, 0x57, 0x3C, 0x89, 0x46), + MBEDTLS_BYTES_TO_T_UINT_8(0x82, 0x4F, 0x83, 0xCE, 0xCB, 0xB8, 0xD0, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x9A, 0x84, 0x04, 0xB0, 0xAD, 0xEB, 0xFA, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0xA4, 0xC3, 0x41, 0x44, 0x4E, 0x65, 0x3E), +}; +static const mbedtls_mpi_uint secp384r1_T_29_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x16, 0xA9, 0x1C, 0xE7, 0x65, 0x20, 0xC1), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0x53, 0x32, 0xF8, 0xC0, 0xA6, 0xBD, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0xF0, 0xE6, 0x57, 0x31, 0xCC, 0x26, 0x6F), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0xE3, 0x54, 0x1C, 0x34, 0xD3, 0x17, 0xBC), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xAE, 0xED, 0xFB, 0xCD, 0xE7, 0x1E, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x16, 0x1C, 0x34, 0x40, 0x00, 0x1F, 0xB6), +}; +static const mbedtls_mpi_uint secp384r1_T_29_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0x32, 0x00, 0xC2, 0xD4, 0x3B, 0x1A, 0x09), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0xE0, 0x99, 0x8F, 0x0C, 0x4A, 0x16, 0x44), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x73, 0x18, 0x1B, 0xD4, 0x94, 0x29, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0xA4, 0x2D, 0xB1, 0x9D, 0x74, 0x32, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0xBF, 0xF4, 0xB1, 0x0C, 0x37, 0x62, 0x8B, 0x66), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0xFF, 0xDA, 0xE2, 0x35, 0xA3, 0xB6, 0x42), +}; +static const mbedtls_mpi_uint secp384r1_T_30_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0x49, 0x99, 0x65, 0xC5, 0xED, 0x16, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0x79, 0x42, 0x9A, 0xF3, 0xA7, 0x4E, 0x6F, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0x0A, 0x7E, 0xC0, 0xD7, 0x4E, 0x07, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0x7A, 0x31, 0x69, 0xA6, 0xB9, 0x15, 0x34), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0xE0, 0x72, 0xA4, 0x3F, 0xB9, 0xF8, 0x0C), + MBEDTLS_BYTES_TO_T_UINT_8(0x2B, 0x75, 0x32, 0x85, 0xA2, 0xDE, 0x37, 0x12), +}; +static const mbedtls_mpi_uint secp384r1_T_30_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0xC0, 0x0D, 0xCF, 0x25, 0x41, 0xA4, 0xF4), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0xFC, 0xB2, 0x48, 0xC3, 0x85, 0x83, 0x4B), + MBEDTLS_BYTES_TO_T_UINT_8(0x2B, 0xBE, 0x0B, 0x58, 0x2D, 0x7A, 0x9A, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0xF3, 0x81, 0x18, 0x1B, 0x74, 0x4F, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0xE2, 0x43, 0xA3, 0x0A, 0x16, 0x8B, 0xA3, 0x1E), + MBEDTLS_BYTES_TO_T_UINT_8(0x4A, 0x18, 0x81, 0x7B, 0x8D, 0xA2, 0x35, 0x77), +}; +static const mbedtls_mpi_uint secp384r1_T_31_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0xC4, 0x3F, 0x2C, 0xE7, 0x5F, 0x99, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0x2B, 0xB7, 0xB6, 0xAD, 0x5A, 0x56, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x00, 0xA4, 0x48, 0xC8, 0xE8, 0xBA, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0xA1, 0xB5, 0x13, 0x5A, 0xCD, 0x99, 0x9C), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x95, 0xAD, 0xFC, 0xE2, 0x7E, 0xE7, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0x6B, 0xD1, 0x34, 0x99, 0x53, 0x63, 0x0B), +}; +static const mbedtls_mpi_uint secp384r1_T_31_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x8A, 0x77, 0x5D, 0x2B, 0xAB, 0x01, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x4E, 0x85, 0xD0, 0xD5, 0x49, 0x83, 0x4D, 0x60), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0xC6, 0x91, 0x30, 0x3B, 0x00, 0xAF, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0xAE, 0x61, 0x07, 0xE1, 0xB6, 0xE2, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0x43, 0x41, 0xFE, 0x9B, 0xB6, 0xF0, 0xA5), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x97, 0xAE, 0xAD, 0x89, 0x88, 0x9E, 0x41), +}; +static const mbedtls_ecp_point secp384r1_T[32] = { + ECP_POINT_INIT_XY_Z1(secp384r1_T_0_X, secp384r1_T_0_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_1_X, secp384r1_T_1_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_2_X, secp384r1_T_2_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_3_X, secp384r1_T_3_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_4_X, secp384r1_T_4_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_5_X, secp384r1_T_5_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_6_X, secp384r1_T_6_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_7_X, secp384r1_T_7_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_8_X, secp384r1_T_8_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_9_X, secp384r1_T_9_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_10_X, secp384r1_T_10_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_11_X, secp384r1_T_11_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_12_X, secp384r1_T_12_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_13_X, secp384r1_T_13_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_14_X, secp384r1_T_14_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_15_X, secp384r1_T_15_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_16_X, secp384r1_T_16_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_17_X, secp384r1_T_17_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_18_X, secp384r1_T_18_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_19_X, secp384r1_T_19_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_20_X, secp384r1_T_20_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_21_X, secp384r1_T_21_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_22_X, secp384r1_T_22_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_23_X, secp384r1_T_23_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_24_X, secp384r1_T_24_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_25_X, secp384r1_T_25_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_26_X, secp384r1_T_26_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_27_X, secp384r1_T_27_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_28_X, secp384r1_T_28_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_29_X, secp384r1_T_29_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_30_X, secp384r1_T_30_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_31_X, secp384r1_T_31_Y), +}; +#else +#define secp384r1_T NULL +#endif + +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +/* + * Domain parameters for secp521r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +static const mbedtls_mpi_uint secp521r1_p[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_2(0xFF, 0x01), +}; +static const mbedtls_mpi_uint secp521r1_b[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x3F, 0x50, 0x6B, 0xD4, 0x1F, 0x45, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x34, 0x2C, 0x3D, 0x88, 0xDF, 0x73, 0x35), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0xBF, 0xB1, 0x3B, 0xBD, 0xC0, 0x52, 0x16), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0x93, 0x7E, 0xEC, 0x51, 0x39, 0x19, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0xE1, 0x09, 0xF1, 0x8E, 0x91, 0x89, 0xB4, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0x15, 0xB3, 0x99, 0x5B, 0x72, 0xDA, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0xEE, 0x40, 0x85, 0xB6, 0xA0, 0x21, 0x9A, 0x92), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x9A, 0x1C, 0x8E, 0x61, 0xB9, 0x3E, 0x95), + MBEDTLS_BYTES_TO_T_UINT_2(0x51, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_gx[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0xBD, 0xE5, 0xC2, 0x31, 0x7E, 0x7E, 0xF9), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x42, 0x6A, 0x85, 0xC1, 0xB3, 0x48, 0x33), + MBEDTLS_BYTES_TO_T_UINT_8(0xDE, 0xA8, 0xFF, 0xA2, 0x27, 0xC1, 0x1D, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x59, 0xE7, 0xEF, 0x77, 0x5E, 0x4B, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x3D, 0x4D, 0x6B, 0x60, 0xAF, 0x28, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0xB5, 0x3F, 0x05, 0x39, 0x81, 0x64, 0x9C), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0xB4, 0x95, 0x23, 0x66, 0xCB, 0x3E, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0xE9, 0x04, 0x04, 0xB7, 0x06, 0x8E, 0x85), + MBEDTLS_BYTES_TO_T_UINT_2(0xC6, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_gy[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x66, 0xD1, 0x9F, 0x76, 0x94, 0xBE, 0x88), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0xC2, 0x72, 0xA2, 0x86, 0x70, 0x3C, 0x35), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0x07, 0xAD, 0x3F, 0x01, 0xB9, 0x50, 0xC5), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0x26, 0xF4, 0x5E, 0x99, 0x72, 0xEE, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0x2C, 0x66, 0x3E, 0x27, 0x17, 0xBD, 0xAF, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x44, 0x9B, 0x57, 0x49, 0x44, 0xF5, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x1B, 0x7D, 0x2C, 0xB4, 0x5F, 0x8A, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0xC0, 0x3B, 0x9A, 0x78, 0x6A, 0x29, 0x39), + MBEDTLS_BYTES_TO_T_UINT_2(0x18, 0x01), +}; +static const mbedtls_mpi_uint secp521r1_n[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0x64, 0x38, 0x91, 0x1E, 0xB7, 0x6F, 0xBB), + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0x47, 0x9C, 0x89, 0xB8, 0xC9, 0xB5, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0xD0, 0xA5, 0x09, 0xF7, 0x48, 0x01, 0xCC, 0x7F), + MBEDTLS_BYTES_TO_T_UINT_8(0x6B, 0x96, 0x2F, 0xBF, 0x83, 0x87, 0x86, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_2(0xFF, 0x01), +}; +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 +static const mbedtls_mpi_uint secp521r1_T_0_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0xBD, 0xE5, 0xC2, 0x31, 0x7E, 0x7E, 0xF9), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x42, 0x6A, 0x85, 0xC1, 0xB3, 0x48, 0x33), + MBEDTLS_BYTES_TO_T_UINT_8(0xDE, 0xA8, 0xFF, 0xA2, 0x27, 0xC1, 0x1D, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x59, 0xE7, 0xEF, 0x77, 0x5E, 0x4B, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x3D, 0x4D, 0x6B, 0x60, 0xAF, 0x28, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0xB5, 0x3F, 0x05, 0x39, 0x81, 0x64, 0x9C), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0xB4, 0x95, 0x23, 0x66, 0xCB, 0x3E, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0xE9, 0x04, 0x04, 0xB7, 0x06, 0x8E, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_0_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x66, 0xD1, 0x9F, 0x76, 0x94, 0xBE, 0x88), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0xC2, 0x72, 0xA2, 0x86, 0x70, 0x3C, 0x35), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0x07, 0xAD, 0x3F, 0x01, 0xB9, 0x50, 0xC5), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0x26, 0xF4, 0x5E, 0x99, 0x72, 0xEE, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0x2C, 0x66, 0x3E, 0x27, 0x17, 0xBD, 0xAF, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x44, 0x9B, 0x57, 0x49, 0x44, 0xF5, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x1B, 0x7D, 0x2C, 0xB4, 0x5F, 0x8A, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0xC0, 0x3B, 0x9A, 0x78, 0x6A, 0x29, 0x39), + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_1_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0xB1, 0x2D, 0xEB, 0x27, 0x2F, 0xE8, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x4B, 0x44, 0x25, 0xDB, 0x5C, 0x5F, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0x13, 0x85, 0x28, 0x78, 0x2E, 0x75, 0x34, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0x69, 0x57, 0x0F, 0x73, 0x78, 0x7A, 0xE3, 0x53), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xD8, 0xEC, 0xDC, 0xDA, 0x04, 0xAD, 0xAB), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0x8A, 0x09, 0xF3, 0x58, 0x79, 0xD8, 0x29), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0x03, 0xCB, 0x50, 0x1A, 0x7F, 0x56, 0x00), + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0xA6, 0x78, 0x38, 0x85, 0x67, 0x0B, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_1_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0xD5, 0xD2, 0x22, 0xC4, 0x00, 0x3B, 0xBA), + MBEDTLS_BYTES_TO_T_UINT_8(0xD5, 0x93, 0x0E, 0x7B, 0x85, 0x51, 0xC3, 0x06), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0xA6, 0x5F, 0x54, 0x49, 0x02, 0x81, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0x22, 0xE9, 0x6B, 0x3A, 0x92, 0xE7, 0x72, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0x6F, 0x5F, 0x28, 0x9E, 0x91, 0x27, 0x88, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0x28, 0x31, 0xB3, 0x84, 0xCA, 0x12, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0xF9, 0xAC, 0x22, 0x10, 0x0A, 0x64, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0xC6, 0x33, 0x1F, 0x69, 0x19, 0x18, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_2_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x48, 0xB8, 0xC7, 0x37, 0x5A, 0x00, 0x36), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0xCC, 0x32, 0xE0, 0xEE, 0x03, 0xC2, 0xBA), + MBEDTLS_BYTES_TO_T_UINT_8(0xC4, 0x29, 0xC2, 0xE4, 0x6E, 0x24, 0x20, 0x8D), + MBEDTLS_BYTES_TO_T_UINT_8(0x06, 0x6B, 0x7F, 0x7B, 0xF9, 0xB0, 0xB8, 0x13), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x7B, 0x3C, 0xE1, 0x19, 0xA1, 0x23, 0x02), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0xE3, 0xC2, 0x53, 0xC0, 0x07, 0x13, 0xA9), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0xFE, 0x36, 0x35, 0x9F, 0x5E, 0x59, 0xCE), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x55, 0x89, 0x84, 0xBC, 0xEF, 0xA2, 0xC2), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_2_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0x1A, 0x08, 0x67, 0xB4, 0xE7, 0x22, 0xED), + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0x26, 0xDF, 0x81, 0x3C, 0x5F, 0x1C, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0xE0, 0x4D, 0xD0, 0x0A, 0x48, 0x06, 0xF4, 0x48), + MBEDTLS_BYTES_TO_T_UINT_8(0x73, 0x18, 0x39, 0xF7, 0xD1, 0x20, 0x77, 0x8D), + MBEDTLS_BYTES_TO_T_UINT_8(0x78, 0x8F, 0x44, 0x13, 0xCB, 0x78, 0x11, 0x11), + MBEDTLS_BYTES_TO_T_UINT_8(0x33, 0xE2, 0x49, 0xEA, 0x43, 0x79, 0x08, 0x39), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0xD1, 0xD8, 0x73, 0x2C, 0x71, 0x2F, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0xE5, 0xE7, 0xF4, 0x46, 0xAB, 0x20, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_3_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0x0B, 0xB9, 0x71, 0x1A, 0x27, 0xB7, 0xA7), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0xA2, 0x2C, 0xD1, 0xDA, 0xBC, 0xC1, 0xBD), + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0xA3, 0x10, 0x1F, 0x90, 0xF2, 0xA5, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0xFB, 0x20, 0xF4, 0xC0, 0x70, 0xC0, 0xF5), + MBEDTLS_BYTES_TO_T_UINT_8(0x8F, 0xA7, 0x99, 0xF0, 0xA5, 0xD3, 0x09, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0xE8, 0x14, 0x39, 0xBE, 0xCB, 0x60, 0xAF), + MBEDTLS_BYTES_TO_T_UINT_8(0x9F, 0xD6, 0x14, 0xA9, 0xC9, 0x20, 0xC3, 0xEA), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0xA8, 0x5B, 0xFD, 0x2D, 0x96, 0xBC, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_3_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0x04, 0x45, 0xBE, 0xCE, 0x75, 0x95, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0xCC, 0xDA, 0x58, 0x49, 0x35, 0x09, 0x8D, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0xF0, 0xC0, 0x36, 0xF2, 0xA6, 0x2D, 0x14), + MBEDTLS_BYTES_TO_T_UINT_8(0xE7, 0xFC, 0x3D, 0xA8, 0xFB, 0x3C, 0xD2, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0x4D, 0x71, 0x09, 0x18, 0x42, 0xF0, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xC1, 0xCE, 0x9E, 0x6A, 0x49, 0x60, 0x12), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0xB1, 0x00, 0xF7, 0xA1, 0x7A, 0x31, 0xB4), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0xC3, 0x86, 0xCD, 0x20, 0x4A, 0x17, 0x86), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_4_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0xAB, 0x8B, 0x47, 0x8D, 0xAA, 0xA6, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0xC4, 0x97, 0xF0, 0xBC, 0x2D, 0xDC, 0x9D, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0x86, 0xB0, 0x74, 0xB2, 0xF4, 0xF6, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xBD, 0xAC, 0xE3, 0x8F, 0x43, 0x5C, 0xB1), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0xC3, 0xE2, 0x6E, 0x25, 0x49, 0xCD, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x5E, 0x08, 0xB3, 0xB9, 0xAC, 0x5F, 0xD1), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0xB7, 0xD1, 0xF4, 0xDC, 0x19, 0xE9, 0xC8), + MBEDTLS_BYTES_TO_T_UINT_8(0x49, 0xE4, 0xFA, 0xE1, 0x36, 0x3E, 0xED, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_4_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x67, 0x92, 0x84, 0x6E, 0x48, 0x03, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0x9E, 0x95, 0xEF, 0x8F, 0xB2, 0x82, 0x6B, 0x1C), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xFA, 0xB9, 0x55, 0x23, 0xFE, 0x09, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0x79, 0x85, 0x4B, 0x0E, 0xD4, 0x35, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0x9A, 0x27, 0x45, 0x81, 0xE0, 0x88, 0x52, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0x63, 0xA2, 0x4B, 0xBC, 0x5D, 0xB1, 0x92), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x8C, 0x83, 0xD9, 0x3E, 0xD3, 0x42, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0x03, 0x3A, 0x31, 0xBA, 0xE9, 0x3A, 0xD1), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_5_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x35, 0x10, 0xCD, 0x2D, 0x00, 0xFE, 0x32, 0xA7), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0x6E, 0x1F, 0xDA, 0xF8, 0x6F, 0x4D, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0x79, 0x7D, 0x09, 0xE5, 0xD3, 0x03, 0x21), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0xC3, 0xBE, 0xDF, 0x07, 0x65, 0x49, 0xCC), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0x57, 0x33, 0xEF, 0xAE, 0x4F, 0x04, 0x27), + MBEDTLS_BYTES_TO_T_UINT_8(0x9A, 0xE9, 0x9B, 0xFE, 0xBF, 0xE6, 0x85, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0xBD, 0xBA, 0xAA, 0x06, 0xC4, 0xC6, 0xB8, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0x83, 0x01, 0xA9, 0xF6, 0x51, 0xE7, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0x1B, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_5_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0xA6, 0x15, 0x8E, 0xAB, 0x1F, 0x10, 0x87), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0x08, 0x27, 0x1A, 0xA1, 0x21, 0xAD, 0xF5), + MBEDTLS_BYTES_TO_T_UINT_8(0x02, 0x09, 0x90, 0x6E, 0x50, 0x90, 0x9A, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0x9A, 0xFE, 0xD7, 0xA1, 0xF5, 0xA2, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x7D, 0xE3, 0xDC, 0x21, 0xFB, 0xA4, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0xBF, 0x07, 0xFF, 0x45, 0xDF, 0x51, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0x5C, 0x34, 0x02, 0x62, 0x9B, 0x08, 0x12), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0xCE, 0x9A, 0x6A, 0xEC, 0x75, 0xF6, 0x46), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_6_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0x59, 0xF4, 0x78, 0x3C, 0x60, 0xB1, 0x4A), + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0x37, 0x84, 0x6A, 0xDC, 0xF2, 0x9A, 0x7D), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0x9A, 0x9A, 0x15, 0x36, 0xE0, 0x2B, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0xEC, 0x38, 0x9C, 0x50, 0x3D, 0x1E, 0x37, 0x82), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0x79, 0xF0, 0x92, 0xF2, 0x8B, 0x18, 0x82), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0xE0, 0x82, 0x1E, 0x80, 0x82, 0x4B, 0xD7), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0xBB, 0x59, 0x6B, 0x8A, 0x77, 0x41, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0xF9, 0xD4, 0xB8, 0x4A, 0x82, 0xCF, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_6_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0x8C, 0xC8, 0x9B, 0x72, 0x9E, 0xF7, 0xF9), + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0xCE, 0xE9, 0x77, 0x0A, 0x19, 0x59, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0xA1, 0x41, 0x6A, 0x72, 0x4B, 0xB4, 0xDC), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0x35, 0x43, 0xE2, 0x8C, 0xBE, 0x0D, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0xEB, 0xAD, 0xF3, 0xA9, 0xA6, 0x68, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0x2F, 0xE2, 0x48, 0x0C, 0xDB, 0x1F, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xD1, 0x1E, 0x60, 0x9B, 0x2A, 0xD2, 0xC1, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0x64, 0xB5, 0xD2, 0xF6, 0xF6, 0x6E, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_7_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0x3D, 0x30, 0x78, 0x10, 0x18, 0x41, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0x1D, 0x1C, 0xE0, 0x6D, 0x83, 0xD1, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0x03, 0x0B, 0xF5, 0x2F, 0x6C, 0x04, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x3E, 0xD5, 0xFC, 0x31, 0x5B, 0x3A, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x82, 0x2F, 0xFB, 0xFE, 0xF8, 0x76, 0x39), + MBEDTLS_BYTES_TO_T_UINT_8(0x85, 0x26, 0xDA, 0x9C, 0x36, 0xF5, 0x93, 0xD1), + MBEDTLS_BYTES_TO_T_UINT_8(0x4C, 0xE7, 0x6E, 0xD2, 0x7D, 0x81, 0x09, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0xD3, 0x03, 0xF9, 0x58, 0x48, 0x24, 0xA2, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_7_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1B, 0x79, 0x0C, 0x8E, 0x6B, 0x95, 0xF3, 0xC4), + MBEDTLS_BYTES_TO_T_UINT_8(0xF4, 0x10, 0x5C, 0x87, 0x03, 0x39, 0xCF, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0xF0, 0xF7, 0xC1, 0x07, 0xA4, 0xF4, 0x3F), + MBEDTLS_BYTES_TO_T_UINT_8(0x32, 0xE8, 0x02, 0x89, 0x65, 0xC4, 0x72, 0x36), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x88, 0xEA, 0x96, 0x67, 0x0B, 0x5D, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0x75, 0x60, 0xA8, 0xBD, 0x74, 0xDF, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0x6E, 0xE5, 0x71, 0x50, 0x67, 0xD0, 0xD2, 0xE6), + MBEDTLS_BYTES_TO_T_UINT_8(0xD5, 0xFC, 0xE5, 0xC7, 0x77, 0xB0, 0x7F, 0x8C), + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_8_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x97, 0x86, 0x69, 0xCD, 0x0D, 0x9A, 0xBD, 0x66), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0x17, 0xBC, 0xBB, 0x59, 0x85, 0x7D, 0x0E), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xA8, 0x76, 0xAC, 0x80, 0xA9, 0x72, 0xE0), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0x78, 0xC1, 0xE2, 0x4D, 0xAF, 0xF9, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0x97, 0x8E, 0x74, 0xC4, 0x4B, 0xB2, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0xD8, 0xF6, 0xF3, 0xAF, 0x2F, 0x52, 0xE5), + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0x57, 0xF4, 0xCE, 0xEE, 0x43, 0xED, 0x60), + MBEDTLS_BYTES_TO_T_UINT_8(0x7D, 0x46, 0x38, 0xDE, 0x20, 0xFD, 0x59, 0x18), + MBEDTLS_BYTES_TO_T_UINT_8(0xD7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_8_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x18, 0xE8, 0x58, 0xB9, 0x76, 0x2C, 0xE6), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0x54, 0xE4, 0xFE, 0xC7, 0xBC, 0x31, 0x37), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xF8, 0x89, 0xEE, 0x70, 0xB5, 0xB0, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x22, 0x26, 0x9A, 0x53, 0xB9, 0x38, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0xA7, 0x19, 0x8C, 0x74, 0x7E, 0x88, 0x46), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0xDA, 0x0A, 0xE8, 0xDA, 0xA5, 0xBE, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0x90, 0x5C, 0xF7, 0xB1, 0x0C, 0x72, 0xFB, 0x09), + MBEDTLS_BYTES_TO_T_UINT_8(0x78, 0xE2, 0x23, 0xE7, 0x46, 0xB7, 0xE0, 0x91), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_9_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0x36, 0xBC, 0xBD, 0x48, 0x11, 0x8E, 0x72), + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0xBB, 0xA1, 0xF7, 0x0B, 0x9E, 0xBF, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x28, 0xE1, 0xA2, 0x8F, 0xFC, 0xFC, 0xD6), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0xFE, 0x19, 0x0A, 0xE5, 0xE7, 0x69, 0x39), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0xCD, 0x12, 0xF5, 0xBE, 0xD3, 0x04, 0xF1), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xA8, 0x0D, 0x81, 0x59, 0xC4, 0x79, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0xA3, 0xF3, 0x4B, 0x92, 0x65, 0xC3, 0x31, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0x75, 0xB5, 0x4F, 0x4D, 0x91, 0xD4, 0xE2, 0xB2), + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_9_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0x09, 0x41, 0x79, 0x1D, 0x4D, 0x0D, 0x33), + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0x31, 0x18, 0xBA, 0xA0, 0xF2, 0x6E, 0x7E), + MBEDTLS_BYTES_TO_T_UINT_8(0x93, 0x5B, 0x4D, 0x4F, 0xAF, 0xC9, 0x8C, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0x48, 0x99, 0x9C, 0x06, 0x68, 0xDE, 0xD8, 0x29), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x04, 0xE1, 0xB5, 0x9D, 0x00, 0xBC, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0x95, 0x92, 0x8D, 0x72, 0xD3, 0x37, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0x4B, 0x27, 0xA2, 0xE8, 0xA4, 0x26, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0x45, 0x9C, 0xA9, 0xCB, 0x9F, 0xBA, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_10_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0x7E, 0x1B, 0x64, 0xF4, 0xE8, 0xA5, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0xF7, 0x20, 0xA9, 0xCA, 0xF3, 0x89, 0xE5, 0xE1), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0xED, 0xFC, 0xAB, 0xD9, 0x0A, 0xB9, 0x07), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0x6F, 0x46, 0x7C, 0xCD, 0x78, 0xFF, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0x69, 0xAB, 0x71, 0x5A, 0x94, 0xAB, 0x20, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x2E, 0xEE, 0x87, 0x57, 0x1F, 0xAD, 0xD3), + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0x4C, 0x3D, 0xFB, 0x7E, 0xA1, 0x8B, 0x07), + MBEDTLS_BYTES_TO_T_UINT_8(0x69, 0xCF, 0x07, 0x86, 0xBA, 0x53, 0x37, 0xCF), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_10_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x26, 0xB2, 0xB9, 0xE2, 0x91, 0xE3, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0x79, 0xC9, 0x54, 0x84, 0x08, 0x3D, 0x0B, 0xD2), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0xA8, 0x77, 0x2F, 0x64, 0x45, 0x99, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0x96, 0x16, 0x1F, 0xDB, 0x96, 0x28, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x2B, 0x8D, 0xFF, 0xA2, 0x4F, 0x55, 0xD3), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0xE6, 0x48, 0xBD, 0x99, 0x3D, 0x12, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0x84, 0x59, 0xDA, 0xB9, 0xB6, 0x66, 0x12), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x78, 0x41, 0x92, 0xDF, 0xF4, 0x3F, 0x63), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_11_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0x86, 0x6F, 0x4F, 0xBF, 0x67, 0xDF, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0x2B, 0x1E, 0x5F, 0x00, 0xEA, 0xF6, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0x90, 0xB9, 0x6A, 0x89, 0xD8, 0xC0, 0xD7, 0xA7), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x9A, 0x32, 0x23, 0xA0, 0x02, 0x91, 0x58), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0x7F, 0x6A, 0x15, 0x64, 0x6A, 0x8B, 0xBB), + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0x57, 0x82, 0x58, 0xA9, 0x56, 0xB5, 0xFB), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x50, 0x92, 0x60, 0xCC, 0x81, 0x24, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0x3D, 0xAD, 0xDA, 0xD9, 0x51, 0x3E, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_11_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEC, 0xFE, 0x8F, 0xB0, 0x0B, 0xDE, 0x2E, 0x7E), + MBEDTLS_BYTES_TO_T_UINT_8(0x79, 0xD2, 0xBE, 0xEF, 0xAC, 0x76, 0x71, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0xE8, 0x72, 0x0B, 0xAC, 0xFE, 0xCA, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0x5B, 0xC7, 0xFC, 0xE3, 0x3C, 0x7C, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0xA1, 0x04, 0xA7, 0xB9, 0x9B, 0x93, 0xC0, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0x48, 0x4B, 0x8E, 0x32, 0xC5, 0xF0, 0x6B), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x42, 0x07, 0xC1, 0xF2, 0xF1, 0x72, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0x37, 0x54, 0x9C, 0x88, 0xD2, 0x62, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_12_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x19, 0x8A, 0x89, 0x58, 0xA2, 0x0F, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0xCC, 0x4C, 0x97, 0x30, 0x66, 0x34, 0x26), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x6A, 0x1E, 0x1F, 0xDB, 0xC9, 0x5E, 0x13), + MBEDTLS_BYTES_TO_T_UINT_8(0x1B, 0x4D, 0x49, 0xFF, 0x9B, 0x9C, 0xAC, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0xD7, 0xE4, 0x4B, 0xF2, 0xD4, 0x1A, 0xD2, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0xDA, 0xE8, 0x61, 0x9F, 0xC8, 0x49, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0xCB, 0xF2, 0x2D, 0x85, 0xF6, 0x8D, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0xC5, 0xCD, 0x2C, 0x79, 0xC6, 0x0E, 0x4F), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_12_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x73, 0x1D, 0x55, 0x0F, 0xF8, 0x22, 0x9F, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0x56, 0xBA, 0xE7, 0x57, 0x32, 0xEC, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x9A, 0xC6, 0x4C, 0x09, 0xC4, 0x52, 0x3F), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x1E, 0x6F, 0xF4, 0x7D, 0x27, 0xDD, 0xAF), + MBEDTLS_BYTES_TO_T_UINT_8(0x94, 0x11, 0x16, 0xEC, 0x79, 0x83, 0xAD, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0x4E, 0x92, 0x1F, 0x19, 0x7D, 0x65, 0xDC), + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0xFF, 0x78, 0x15, 0x45, 0x63, 0x32, 0xE4), + MBEDTLS_BYTES_TO_T_UINT_8(0xBF, 0x91, 0xD0, 0x78, 0x58, 0xDA, 0x50, 0x47), + MBEDTLS_BYTES_TO_T_UINT_8(0x73, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_13_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x23, 0xDE, 0x40, 0xF6, 0x41, 0xB4, 0x3B, 0x95), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0x8D, 0xE0, 0xE1, 0xA9, 0xF0, 0x35, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0xD4, 0xBA, 0x7B, 0xCC, 0x1B, 0x3A, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0xD0, 0x5A, 0x2E, 0x74, 0x47, 0x14, 0xC3, 0x4D), + MBEDTLS_BYTES_TO_T_UINT_8(0x7D, 0xF0, 0x8B, 0x06, 0x15, 0x8E, 0x0E, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0xB5, 0xD2, 0xEB, 0x97, 0x50, 0x7D, 0x31, 0xFC), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0x93, 0x4C, 0xDB, 0x97, 0x79, 0x44, 0xF5), + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0xA2, 0xA0, 0x0B, 0xC8, 0x3A, 0x8A, 0xF9), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_13_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x79, 0x50, 0x92, 0x9E, 0x24, 0x1F, 0xCB, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0xD3, 0x16, 0xC9, 0xC5, 0x3D, 0x5A, 0xAF, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0xE3, 0x97, 0xE4, 0xA8, 0x50, 0xF6, 0x7E), + MBEDTLS_BYTES_TO_T_UINT_8(0x45, 0x57, 0x97, 0x42, 0x78, 0x92, 0x49, 0x0D), + MBEDTLS_BYTES_TO_T_UINT_8(0xA5, 0xEB, 0x62, 0x24, 0xFB, 0x8F, 0x32, 0xCF), + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0x0C, 0x36, 0x6E, 0x8F, 0xE8, 0xE8, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0xD3, 0x7C, 0xC7, 0x8D, 0x3F, 0x5C, 0xE1), + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0x64, 0x6A, 0x73, 0x10, 0x79, 0xB8, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_14_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0xF9, 0xEF, 0xA5, 0x20, 0x4A, 0x5C, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0xF3, 0xF4, 0x49, 0x5B, 0x73, 0xAA, 0x1B), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0xF2, 0xEA, 0x0F, 0x00, 0xAD, 0x53, 0xAB), + MBEDTLS_BYTES_TO_T_UINT_8(0x03, 0xB8, 0x66, 0xED, 0xC4, 0x2B, 0x4C, 0x35), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0x2F, 0xC1, 0x9A, 0x37, 0xD2, 0x7F, 0x58), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0xA7, 0x81, 0x38, 0x64, 0xC9, 0x37, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0x3B, 0x6C, 0x9F, 0x5B, 0xD9, 0x8B, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x14, 0xD9, 0x08, 0xD8, 0xD2, 0x7E, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_14_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x71, 0xE6, 0x3D, 0xD1, 0xB0, 0xE7, 0xCD), + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0x81, 0x23, 0xEC, 0x2D, 0x42, 0x45, 0xE6), + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0x5B, 0x44, 0x6B, 0x89, 0x03, 0x67, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x84, 0x27, 0xAE, 0x80, 0x5A, 0x33, 0xBE, 0x11), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0xB6, 0x64, 0x1A, 0xDF, 0xD3, 0x85, 0x91), + MBEDTLS_BYTES_TO_T_UINT_8(0x67, 0x8C, 0x22, 0xBA, 0xD0, 0xBD, 0xCC, 0xA0), + MBEDTLS_BYTES_TO_T_UINT_8(0xF7, 0x3C, 0x01, 0x3A, 0xFF, 0x9D, 0xC7, 0x6B), + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0xC7, 0x64, 0xB4, 0x59, 0x4E, 0x9F, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0x85, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_15_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA1, 0x34, 0x0A, 0x41, 0x94, 0xA8, 0xF2, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0xD4, 0xE4, 0xF0, 0x97, 0x45, 0x6D, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0x8F, 0x1F, 0x4D, 0x6D, 0xFE, 0xA0, 0xC4, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x28, 0x5C, 0x40, 0xBB, 0x65, 0xD4, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0xA8, 0x87, 0x35, 0x20, 0x3A, 0x89, 0x44), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0xFD, 0x4F, 0xAB, 0x2D, 0xD1, 0xD0, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0xE8, 0x00, 0xFC, 0x69, 0x52, 0xF8, 0xD5), + MBEDTLS_BYTES_TO_T_UINT_8(0xE1, 0x9A, 0x99, 0xE1, 0xDC, 0x9C, 0x3F, 0xD9), + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_15_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x12, 0x08, 0x98, 0xD9, 0xCA, 0x73, 0xD5, 0xA9), + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0x2C, 0xE0, 0xA7, 0x3E, 0x91, 0xD7, 0x87), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x04, 0xB0, 0x54, 0x09, 0xF4, 0x72, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0xEE, 0x28, 0xCC, 0xE8, 0x50, 0x78, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0x0D, 0x91, 0x03, 0x76, 0xDB, 0x68, 0x24, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0x7A, 0xE0, 0x56, 0xB2, 0x5D, 0x12, 0xD3, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0x0D, 0x42, 0x59, 0x8B, 0xDF, 0x67, 0xB5, 0xBE), + MBEDTLS_BYTES_TO_T_UINT_8(0xD1, 0xCC, 0xE5, 0x31, 0x53, 0x7A, 0x46, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_16_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xCC, 0x8D, 0x59, 0xB5, 0x1B, 0x0F, 0xF4, 0xAF), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x2F, 0xD1, 0x2C, 0xE0, 0xD8, 0x04, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xF4, 0xD7, 0xBA, 0xB0, 0xA3, 0x7E, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0x08, 0x51, 0x56, 0xA6, 0x76, 0x67, 0x33), + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0x17, 0x63, 0xFE, 0x56, 0xD0, 0xD9, 0x71), + MBEDTLS_BYTES_TO_T_UINT_8(0xAA, 0xF6, 0xC3, 0x14, 0x47, 0xC5, 0xA7, 0x31), + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0x4C, 0x80, 0xF6, 0xA2, 0x57, 0xA7, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0xB3, 0x7B, 0xF8, 0x2F, 0xE1, 0x3E, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_16_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0xF4, 0xF9, 0x6B, 0x7B, 0x90, 0xDF, 0x30), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x82, 0xEF, 0x62, 0xA1, 0x4C, 0x53, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0x99, 0x76, 0x01, 0xBA, 0x8D, 0x0F, 0x54), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0xF4, 0x58, 0x73, 0x56, 0xFE, 0xDD, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0xCE, 0xF9, 0xE8, 0xA1, 0x34, 0xC3, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0x5F, 0xDC, 0x6A, 0x3D, 0xD8, 0x7F, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0xF4, 0x51, 0xB8, 0xB8, 0xC1, 0xD7, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0x7D, 0x58, 0xD1, 0xD4, 0x1B, 0x4D, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0xD3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_17_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0x95, 0xDF, 0x00, 0xD8, 0x21, 0xDE, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0xF7, 0x47, 0x3C, 0xC3, 0xB2, 0x01, 0x53, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0x17, 0x43, 0x23, 0xBD, 0xCA, 0x71, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0xBA, 0x0F, 0x4F, 0xDC, 0x41, 0x54, 0xBE), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0x39, 0x26, 0x70, 0x53, 0x32, 0x18, 0x11), + MBEDTLS_BYTES_TO_T_UINT_8(0x32, 0x46, 0x07, 0x97, 0x3A, 0x57, 0xE0, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0x92, 0x4F, 0xCE, 0xDF, 0x25, 0x80, 0x26), + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0x6F, 0x9A, 0x03, 0x05, 0x4B, 0xD1, 0x47), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_17_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x25, 0x01, 0x72, 0x30, 0x90, 0x17, 0x51, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0xFB, 0x41, 0x65, 0x5C, 0xB4, 0x2D, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0xCD, 0xCD, 0xAA, 0x41, 0xCC, 0xBB, 0x07), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0xCE, 0x08, 0x0A, 0x63, 0xE9, 0xA2, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0xA8, 0x21, 0x7F, 0x7A, 0x5B, 0x9B, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0x6B, 0x89, 0x44, 0x0A, 0x7F, 0x85, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0x7D, 0xDE, 0x7C, 0x19, 0x5C, 0x65, 0x26, 0x61), + MBEDTLS_BYTES_TO_T_UINT_8(0xD7, 0xAC, 0x62, 0x29, 0x4A, 0xF1, 0xD0, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_18_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x32, 0x00, 0x40, 0x87, 0xEB, 0xA9, 0x58, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0x51, 0x0B, 0xFF, 0x56, 0x35, 0x51, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0xAC, 0x08, 0x94, 0x71, 0xDA, 0xEC, 0x99), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x4D, 0xC5, 0x7B, 0x31, 0x8B, 0x8D, 0x5E), + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x05, 0xF1, 0x3E, 0x9E, 0x8F, 0x17, 0x8F), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0x9C, 0x4B, 0x62, 0x94, 0xAD, 0x49, 0xFC), + MBEDTLS_BYTES_TO_T_UINT_8(0x0F, 0xC9, 0xC6, 0x8F, 0xFD, 0x33, 0x44, 0x34), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x96, 0x17, 0x7F, 0x42, 0xBE, 0xF7, 0x0D), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_18_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFB, 0x29, 0x39, 0x13, 0x08, 0x8D, 0x91, 0x47), + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0x79, 0xF9, 0x2F, 0xA9, 0x0A, 0xCF, 0xD6), + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0x87, 0x7A, 0xA3, 0x19, 0xAB, 0x55, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x0B, 0x01, 0xC5, 0x56, 0x19, 0x9D, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0xDE, 0x82, 0x3B, 0xEA, 0xD3, 0x0B, 0x8C), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x6B, 0xC7, 0xF3, 0x0F, 0x82, 0x87, 0x6C), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0x2E, 0x23, 0xF2, 0x39, 0x9D, 0x49, 0x70), + MBEDTLS_BYTES_TO_T_UINT_8(0x31, 0xDE, 0xAF, 0x7A, 0xEE, 0xB0, 0xDA, 0x70), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_19_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0x4E, 0x2A, 0x50, 0xFD, 0x8E, 0xC0, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0x0F, 0x7C, 0x76, 0x63, 0xD8, 0x89, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0xEC, 0x2D, 0xB9, 0x4E, 0xF4, 0xEE, 0x85, 0xCF), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0x95, 0x5C, 0x96, 0x5D, 0xAA, 0x59, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0xDB, 0xD2, 0x68, 0x8E, 0x5A, 0x94, 0x60), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x02, 0xBF, 0x77, 0x9F, 0xB9, 0x4C, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0xDC, 0xC0, 0xCF, 0x81, 0x1E, 0xC4, 0x6C), + MBEDTLS_BYTES_TO_T_UINT_8(0x2B, 0xCC, 0x37, 0x86, 0xDC, 0xE2, 0x64, 0x72), + MBEDTLS_BYTES_TO_T_UINT_8(0xD5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_19_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2C, 0x30, 0xB1, 0x59, 0x20, 0x9D, 0x98, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x77, 0x0C, 0x9D, 0xF8, 0x20, 0xDC, 0x90, 0xBA), + MBEDTLS_BYTES_TO_T_UINT_8(0xB1, 0xA0, 0xF4, 0xE7, 0x3E, 0x9C, 0x9E, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0xB5, 0x25, 0xA2, 0xB0, 0x54, 0xCD, 0x2E, 0x33), + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0xD9, 0x42, 0xB0, 0x80, 0xB0, 0xA3, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0x9F, 0xFE, 0x9D, 0x8D, 0x40, 0xFF, 0x27, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0x9D, 0xA6, 0x88, 0x3A, 0x8B, 0x6F, 0x14), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x39, 0xEE, 0x1F, 0x3F, 0xB1, 0x4F, 0x63), + MBEDTLS_BYTES_TO_T_UINT_8(0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_20_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0xD7, 0x9E, 0xFF, 0xD2, 0x35, 0x67, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0x4F, 0x15, 0x5D, 0xE3, 0xE8, 0x53, 0x86), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0xF7, 0x24, 0x98, 0xA2, 0xCB, 0x11, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0x06, 0x2E, 0x25, 0xE1, 0x94, 0xC5, 0xA3, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0xE0, 0x82, 0x6E, 0xBA, 0xE7, 0x43, 0x25, 0xB0), + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0x65, 0xB4, 0x49, 0x73, 0x18, 0x35, 0x54), + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0x5B, 0xBC, 0x62, 0x86, 0x4C, 0xC1, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0xF2, 0x95, 0xA2, 0xBB, 0xA2, 0x35, 0x65), + MBEDTLS_BYTES_TO_T_UINT_8(0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_20_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0x59, 0x62, 0xB0, 0x4B, 0x1E, 0xB4, 0xD8), + MBEDTLS_BYTES_TO_T_UINT_8(0x0D, 0x55, 0xCE, 0xB0, 0x69, 0xBA, 0x63, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0x6E, 0x69, 0x86, 0xDB, 0x34, 0x7D, 0x68, 0x64), + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x06, 0xCA, 0x55, 0x44, 0x36, 0x2B, 0xBA), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0xD4, 0xC4, 0x3D, 0xCD, 0x9E, 0x69, 0xA4), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0x44, 0xE4, 0xBF, 0x31, 0xE6, 0x40, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0x4F, 0xFA, 0x75, 0xE3, 0xFB, 0x97, 0x0E), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0xC0, 0xBD, 0x1C, 0x48, 0xB0, 0x26, 0xD0), + MBEDTLS_BYTES_TO_T_UINT_8(0xD2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_21_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x7B, 0x32, 0xFA, 0xF2, 0x6D, 0x84, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x21, 0x03, 0x1D, 0x0D, 0x22, 0x55, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0xF9, 0x42, 0x03, 0x9C, 0xC2, 0xCB, 0xBA), + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0xA1, 0x96, 0xD9, 0x9D, 0x11, 0x6F, 0xBE), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0x40, 0x57, 0xEB, 0x40, 0x2D, 0xC0, 0x11), + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0x96, 0xBB, 0x4F, 0x2F, 0x23, 0xA8, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0x29, 0x85, 0x21, 0xA5, 0x50, 0x62, 0x06), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x7D, 0x92, 0xCF, 0x87, 0x0C, 0x22, 0xF9), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_21_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x0E, 0xA5, 0x32, 0x5B, 0xDF, 0x9C, 0xD5), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0x96, 0x37, 0x2C, 0x88, 0x35, 0x30, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0xB4, 0x69, 0xFF, 0xEB, 0xC6, 0x94, 0x08), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x55, 0x60, 0xAD, 0xAA, 0x58, 0x14, 0x88), + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0xFF, 0xF2, 0xB2, 0xD5, 0xA7, 0xD9, 0x27), + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0xAE, 0x54, 0xD2, 0x60, 0x31, 0xF3, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0x92, 0x83, 0xE3, 0xF1, 0x42, 0x83, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0x49, 0xD2, 0xC8, 0xB7, 0x76, 0x45, 0x7F, 0x7D), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_22_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x4A, 0x11, 0xA4, 0xFB, 0x7A, 0x01, 0xBC, 0xC8), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0x27, 0x73, 0x8D, 0x02, 0x91, 0x27, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0x62, 0xF6, 0xDD, 0x6B, 0xFA, 0x5B, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0xCA, 0xA2, 0x44, 0x2C, 0xF0, 0x28, 0xD8), + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0xF1, 0x7A, 0xA2, 0x42, 0x4C, 0x50, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0x83, 0x3E, 0x50, 0xAB, 0x9C, 0xF7, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0xED, 0x78, 0xCB, 0x76, 0x69, 0xDA, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x01, 0x1E, 0x43, 0x27, 0x47, 0x6E, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_22_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD3, 0x4F, 0x54, 0xB9, 0x3E, 0xBD, 0xD5, 0x44), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x35, 0x40, 0x69, 0x7F, 0x74, 0x9D, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x06, 0x6F, 0x67, 0x68, 0x2B, 0x4D, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0x65, 0x41, 0xFC, 0x7C, 0x1E, 0xE8, 0xC8), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0x79, 0x37, 0xAF, 0xFD, 0xD2, 0xDA, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0x33, 0xA8, 0x69, 0x56, 0x62, 0xA4, 0xE4, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0x71, 0x73, 0x21, 0x8A, 0x17, 0x81, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0x14, 0x55, 0x8F, 0x7B, 0xB8, 0xAF, 0xF7, 0x86), + MBEDTLS_BYTES_TO_T_UINT_8(0xAA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_23_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x4B, 0xD1, 0xBD, 0xBE, 0x8C, 0xBC, 0x60, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0x62, 0xA6, 0x57, 0x8C, 0xAE, 0x5C, 0x19, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0x7A, 0x43, 0xE4, 0xD9, 0xD8, 0x7B, 0xE7, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0xB9, 0xE4, 0x85, 0x7C, 0x2E, 0xFC, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0x02, 0x2E, 0x01, 0x2A, 0x6D, 0x56, 0xBE, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0x0C, 0x25, 0x9B, 0xAE, 0x86, 0x37, 0x43), + MBEDTLS_BYTES_TO_T_UINT_8(0x4A, 0x22, 0xB3, 0xCB, 0x99, 0x66, 0xB7, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0x56, 0xF7, 0x90, 0xF0, 0x1B, 0x09, 0x27, 0xF7), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_23_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x16, 0x08, 0xEF, 0x39, 0x64, 0x49, 0x31), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0xA0, 0xE3, 0x97, 0xA9, 0x07, 0x54, 0x26), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0xFF, 0xE2, 0x00, 0x07, 0x21, 0x88, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0xFD, 0x59, 0x53, 0x05, 0x6C, 0x42, 0x27), + MBEDTLS_BYTES_TO_T_UINT_8(0x8F, 0xF7, 0x39, 0x5C, 0x82, 0x36, 0xE8, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0x2E, 0x83, 0xA8, 0xE2, 0xA8, 0x43, 0x07, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0xAF, 0x2B, 0x79, 0xED, 0xD8, 0x39, 0x87), + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x20, 0x91, 0x7A, 0xC4, 0x07, 0xEF, 0x6C), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_24_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0x10, 0x2F, 0xAA, 0x0C, 0x94, 0x0E, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0x81, 0x87, 0x41, 0x23, 0xEB, 0x55, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0x53, 0xCC, 0x79, 0xB6, 0xEB, 0x6C, 0xCC), + MBEDTLS_BYTES_TO_T_UINT_8(0xF4, 0x77, 0x73, 0x9D, 0xFC, 0x64, 0x6F, 0x7F), + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0x40, 0xE3, 0x6D, 0x1C, 0x16, 0x71, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0xF4, 0x1B, 0xFF, 0x1C, 0x2F, 0xA5, 0xD7), + MBEDTLS_BYTES_TO_T_UINT_8(0x06, 0x0E, 0x0B, 0x11, 0xF4, 0x8D, 0x93, 0xAF), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0xC5, 0x64, 0x6F, 0x24, 0x19, 0xF2, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_24_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0xB3, 0xAF, 0xA5, 0x0E, 0x4F, 0x5E, 0xE1), + MBEDTLS_BYTES_TO_T_UINT_8(0x0F, 0x77, 0xCA, 0xF2, 0x6D, 0xC5, 0xF6, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0x90, 0x18, 0x8E, 0x33, 0x68, 0x6C, 0xE8, 0xE0), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x8B, 0x80, 0x90, 0x19, 0x7F, 0x90, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0x80, 0x6B, 0x68, 0xE2, 0x7D, 0xD4, 0xD0), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0xC1, 0x67, 0xB3, 0x72, 0xCB, 0xBF, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0xD5, 0xD3, 0x1D, 0x14, 0x58, 0x0A, 0x80), + MBEDTLS_BYTES_TO_T_UINT_8(0x79, 0x7A, 0x65, 0x98, 0xB3, 0x07, 0x4B, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_25_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0x87, 0x0F, 0x5F, 0xCF, 0xA2, 0x01, 0x08), + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0xC9, 0xC8, 0x6E, 0x35, 0x87, 0xA5, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0x94, 0x3E, 0x91, 0xA0, 0xAB, 0x24, 0x1E, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0xBC, 0x02, 0x35, 0x70, 0xC1, 0x5F, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x59, 0xA0, 0x50, 0x04, 0x80, 0x52, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0x56, 0x6E, 0x42, 0x8F, 0x8C, 0x91, 0x65), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xA2, 0xCB, 0xA5, 0xDE, 0x14, 0x24, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0xCB, 0x74, 0x28, 0xE6, 0xA7, 0xE7, 0xC3), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_25_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x35, 0x73, 0xA8, 0x8F, 0x9E, 0x0E, 0x63, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0x1B, 0x77, 0xC7, 0xC1, 0x38, 0xF9, 0xDC), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0x3C, 0xCF, 0xA8, 0x7A, 0xD7, 0xF3, 0xC4), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x5F, 0x9A, 0xC9, 0xAD, 0xE9, 0x1A, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0xCF, 0x2B, 0x5E, 0xD5, 0x81, 0x95, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x88, 0x75, 0x29, 0x1F, 0xC7, 0xC7, 0xD0), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0xA9, 0x5A, 0x4D, 0x63, 0x95, 0xF9, 0x4E), + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0xCD, 0x04, 0x8F, 0xCD, 0x91, 0xDE, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_26_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x88, 0xD4, 0xFD, 0x25, 0x11, 0x99, 0x6E, 0xEA), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x83, 0x01, 0x3D, 0xFB, 0x56, 0xA5, 0x4E), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x3A, 0xDC, 0x74, 0xC2, 0xD7, 0xCF, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0x8F, 0xBD, 0xF1, 0xDD, 0xA3, 0x07, 0x03, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0xBE, 0xE9, 0x2E, 0x58, 0x84, 0x66, 0xFC), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x20, 0x78, 0x37, 0x79, 0x0B, 0xA6, 0x64), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0xF2, 0xAC, 0x65, 0xC8, 0xC9, 0x2F, 0x61), + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x93, 0xE5, 0x0D, 0x0C, 0xC6, 0xB8, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_26_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x69, 0xAD, 0x5C, 0x19, 0x12, 0x61, 0x0E, 0x25), + MBEDTLS_BYTES_TO_T_UINT_8(0x39, 0x4F, 0x0B, 0x1F, 0x49, 0x7E, 0xCD, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0x2E, 0x30, 0x61, 0xDB, 0x08, 0x68, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0x78, 0xAF, 0xB3, 0x08, 0xC1, 0x69, 0xE5), + MBEDTLS_BYTES_TO_T_UINT_8(0xC4, 0x5F, 0x5D, 0xC1, 0x57, 0x6F, 0xD8, 0x34), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0xD3, 0x6A, 0xF7, 0xFD, 0x86, 0xE5, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0x63, 0xBD, 0x70, 0x7B, 0x47, 0xE8, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0x62, 0xC8, 0x7E, 0x9D, 0x11, 0x2B, 0xA5), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_27_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xE2, 0x84, 0xFD, 0xD5, 0x9A, 0x56, 0x7F, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0xBB, 0xA4, 0x6F, 0x12, 0x6E, 0x4D, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x08, 0xA1, 0x82, 0x9C, 0x62, 0x74, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0x9E, 0x58, 0x22, 0x05, 0x1D, 0x15, 0x35, 0x79), + MBEDTLS_BYTES_TO_T_UINT_8(0x9A, 0x88, 0xCF, 0x5C, 0x05, 0x78, 0xFB, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x6B, 0x2F, 0x79, 0x09, 0x73, 0x67, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0xA0, 0x80, 0xD8, 0xE8, 0xEC, 0xFB, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xE7, 0x0B, 0xB7, 0x81, 0x48, 0x7B, 0xD9), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_27_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x53, 0xA9, 0xED, 0x61, 0x92, 0xD7, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x49, 0xD9, 0x5D, 0x9B, 0x4E, 0x89, 0x35), + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0x12, 0xEB, 0x9A, 0xC9, 0xCB, 0xC1, 0x95), + MBEDTLS_BYTES_TO_T_UINT_8(0x35, 0xDC, 0x95, 0x16, 0xFE, 0x29, 0x70, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x33, 0xB1, 0xD6, 0x78, 0xB9, 0xE2, 0x36), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0xCE, 0x88, 0xC3, 0xFD, 0x7A, 0x6B, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0x1E, 0x50, 0x1E, 0xAF, 0xB1, 0x25, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0xE7, 0xD7, 0xD5, 0xBD, 0x7A, 0x12, 0xF9), + MBEDTLS_BYTES_TO_T_UINT_8(0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_28_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x22, 0xAA, 0xA2, 0x80, 0x5D, 0x8F, 0xCD, 0xC8), + MBEDTLS_BYTES_TO_T_UINT_8(0x48, 0x39, 0x79, 0x64, 0xA1, 0x67, 0x3C, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0xC7, 0x49, 0xFF, 0x7F, 0xAC, 0xAB, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0x54, 0x3E, 0x83, 0xF0, 0x3D, 0xBC, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0x92, 0x4A, 0x38, 0x42, 0x8A, 0xAB, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0xE7, 0x0B, 0x4F, 0xEE, 0x9E, 0x92, 0xA5, 0xBE), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0xDD, 0x19, 0x96, 0xF2, 0xF0, 0x6B, 0x2E), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0xFC, 0xDD, 0xB2, 0x8A, 0xE5, 0x4C, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_28_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0x06, 0x49, 0xAC, 0x99, 0x7E, 0xF8, 0x12), + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0xC8, 0x01, 0x51, 0xEA, 0xF6, 0x52, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0x43, 0x89, 0x66, 0x2B, 0x1F, 0x9B, 0x2A, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0xDF, 0x0F, 0x95, 0x07, 0x2B, 0x6C, 0x6E, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0x24, 0xC3, 0xB4, 0xBB, 0x91, 0x1F, 0xA3, 0x72), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x6E, 0x54, 0x28, 0x7B, 0x9C, 0x79, 0x2E), + MBEDTLS_BYTES_TO_T_UINT_8(0x03, 0x45, 0xFF, 0xA6, 0xDA, 0xA2, 0x83, 0x71), + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0xDE, 0x8F, 0x17, 0x37, 0x82, 0xCB, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_29_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0x94, 0x3F, 0x26, 0xC9, 0x1D, 0xD9, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0x97, 0x28, 0x20, 0xCD, 0xC1, 0xF3, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0xC9, 0xB5, 0x60, 0x9B, 0x1E, 0xDC, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0xB9, 0x5B, 0x7D, 0xA0, 0xB2, 0x8C, 0xF0), + MBEDTLS_BYTES_TO_T_UINT_8(0x33, 0xD1, 0x42, 0xE6, 0x39, 0x33, 0x6D, 0xBB), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0xC0, 0xFC, 0xD2, 0x14, 0x5D, 0x3E, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0x78, 0x4A, 0x3E, 0x40, 0x16, 0x93, 0x15, 0xCF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x24, 0xC1, 0x27, 0x27, 0xE5, 0x4B, 0xD8), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_29_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x50, 0xD8, 0xBC, 0xC1, 0x46, 0x22, 0xBB), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0x0E, 0x60, 0xA1, 0xB3, 0x50, 0xD4, 0x86), + MBEDTLS_BYTES_TO_T_UINT_8(0x80, 0xB1, 0x26, 0xB6, 0x6D, 0x47, 0x5A, 0x6F), + MBEDTLS_BYTES_TO_T_UINT_8(0x45, 0xAC, 0x11, 0x35, 0x3E, 0xB9, 0xF4, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0x97, 0xFA, 0xBB, 0x6B, 0x39, 0x13, 0xD8), + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x7B, 0x34, 0x12, 0x75, 0x8E, 0x9B, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0x2C, 0x9E, 0xCD, 0x29, 0xB6, 0xEF, 0x8D, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0xAC, 0xE9, 0x25, 0x27, 0xBB, 0x78, 0x47), + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_30_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0x7A, 0xA8, 0xD3, 0xE3, 0x66, 0xE5, 0x66), + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0x4C, 0xC4, 0x2C, 0x76, 0x81, 0x50, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0xEE, 0x71, 0x08, 0xB8, 0x52, 0x7C, 0xAF, 0xDC), + MBEDTLS_BYTES_TO_T_UINT_8(0x45, 0x59, 0x24, 0xDD, 0xFB, 0x2F, 0xD0, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0xCD, 0x56, 0xE9, 0xAC, 0x91, 0xE6, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0xE5, 0x64, 0x20, 0xC6, 0x9F, 0xE4, 0xEF, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x2C, 0x8F, 0x8C, 0x97, 0xF6, 0x22, 0xC3), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xF4, 0x88, 0xAA, 0xA8, 0xD7, 0xA5, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_30_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0x6C, 0xAE, 0x83, 0xB1, 0x55, 0x55, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x67, 0x84, 0x47, 0x7C, 0x83, 0x5C, 0x89), + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0x10, 0x4D, 0xDD, 0x30, 0x60, 0xB0, 0xE6), + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0xA7, 0x36, 0x76, 0x24, 0x32, 0x9F, 0x9D), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x42, 0x81, 0xFB, 0xA4, 0x2E, 0x13, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0x94, 0x91, 0xFF, 0x99, 0xA0, 0x09, 0x61), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0x83, 0xA1, 0x76, 0xAF, 0x37, 0x5C, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xA8, 0x04, 0x86, 0xC4, 0xA9, 0x79, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_31_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x8C, 0xC2, 0x34, 0xFB, 0x83, 0x28, 0x27), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0x03, 0x7D, 0x5E, 0x9E, 0x0E, 0xB0, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0xA2, 0x02, 0x46, 0x7F, 0xB9, 0xAC, 0xBB, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0x06, 0xED, 0x48, 0xC2, 0x96, 0x4D, 0x56, 0x27), + MBEDTLS_BYTES_TO_T_UINT_8(0x44, 0xB5, 0xC5, 0xD1, 0xE6, 0x1C, 0x7E, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x2E, 0x18, 0x71, 0x2D, 0x7B, 0xD7, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0x46, 0x9D, 0xDE, 0xAA, 0x78, 0x8E, 0xB1), + MBEDTLS_BYTES_TO_T_UINT_8(0x4D, 0xD7, 0x69, 0x2E, 0xE1, 0xD9, 0x48, 0xDE), + MBEDTLS_BYTES_TO_T_UINT_8(0xFB, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_31_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0xFF, 0x9E, 0x09, 0x22, 0x22, 0xE6, 0x8D), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x14, 0x28, 0x13, 0x1B, 0x62, 0x12, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0xCC, 0x7F, 0x67, 0x03, 0xB0, 0xC0, 0xF3, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0xC3, 0x0F, 0xFB, 0x25, 0x48, 0x3E, 0xF4), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0x6E, 0x53, 0x98, 0x36, 0xB3, 0xD3, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0x81, 0x54, 0x22, 0xA4, 0xCC, 0xC1, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xBA, 0xFC, 0xA9, 0xDF, 0x68, 0x86, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x92, 0x0E, 0xC3, 0xF2, 0x58, 0xE8, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_ecp_point secp521r1_T[32] = { + ECP_POINT_INIT_XY_Z1(secp521r1_T_0_X, secp521r1_T_0_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_1_X, secp521r1_T_1_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_2_X, secp521r1_T_2_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_3_X, secp521r1_T_3_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_4_X, secp521r1_T_4_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_5_X, secp521r1_T_5_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_6_X, secp521r1_T_6_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_7_X, secp521r1_T_7_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_8_X, secp521r1_T_8_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_9_X, secp521r1_T_9_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_10_X, secp521r1_T_10_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_11_X, secp521r1_T_11_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_12_X, secp521r1_T_12_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_13_X, secp521r1_T_13_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_14_X, secp521r1_T_14_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_15_X, secp521r1_T_15_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_16_X, secp521r1_T_16_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_17_X, secp521r1_T_17_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_18_X, secp521r1_T_18_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_19_X, secp521r1_T_19_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_20_X, secp521r1_T_20_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_21_X, secp521r1_T_21_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_22_X, secp521r1_T_22_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_23_X, secp521r1_T_23_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_24_X, secp521r1_T_24_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_25_X, secp521r1_T_25_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_26_X, secp521r1_T_26_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_27_X, secp521r1_T_27_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_28_X, secp521r1_T_28_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_29_X, secp521r1_T_29_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_30_X, secp521r1_T_30_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_31_X, secp521r1_T_31_Y), +}; +#else +#define secp521r1_T NULL +#endif +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +static const mbedtls_mpi_uint secp256k1_p[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), +}; +static const mbedtls_mpi_uint secp256k1_a[] = { + MBEDTLS_BYTES_TO_T_UINT_2(0x00, 0x00), +}; +static const mbedtls_mpi_uint secp256k1_b[] = { + MBEDTLS_BYTES_TO_T_UINT_2(0x07, 0x00), +}; +static const mbedtls_mpi_uint secp256k1_gx[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x17, 0xF8, 0x16, 0x5B, 0x81, 0xF2, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x28, 0xCE, 0x2D, 0xDB, 0xFC, 0x9B, 0x02), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0x0B, 0x87, 0xCE, 0x95, 0x62, 0xA0, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xBB, 0xDC, 0xF9, 0x7E, 0x66, 0xBE, 0x79), +}; +static const mbedtls_mpi_uint secp256k1_gy[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0xD4, 0x10, 0xFB, 0x8F, 0xD0, 0x47, 0x9C), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x54, 0x85, 0xA6, 0x48, 0xB4, 0x17, 0xFD), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0x08, 0x11, 0x0E, 0xFC, 0xFB, 0xA4, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0xC4, 0xA3, 0x26, 0x77, 0xDA, 0x3A, 0x48), +}; +static const mbedtls_mpi_uint secp256k1_n[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA), + MBEDTLS_BYTES_TO_T_UINT_8(0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), +}; + +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 +static const mbedtls_mpi_uint secp256k1_T_0_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x17, 0xF8, 0x16, 0x5B, 0x81, 0xF2, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x28, 0xCE, 0x2D, 0xDB, 0xFC, 0x9B, 0x02), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0x0B, 0x87, 0xCE, 0x95, 0x62, 0xA0, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xBB, 0xDC, 0xF9, 0x7E, 0x66, 0xBE, 0x79), +}; +static const mbedtls_mpi_uint secp256k1_T_0_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0xD4, 0x10, 0xFB, 0x8F, 0xD0, 0x47, 0x9C), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x54, 0x85, 0xA6, 0x48, 0xB4, 0x17, 0xFD), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0x08, 0x11, 0x0E, 0xFC, 0xFB, 0xA4, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0xC4, 0xA3, 0x26, 0x77, 0xDA, 0x3A, 0x48), +}; +static const mbedtls_mpi_uint secp256k1_T_1_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xE7, 0xEE, 0xD7, 0x1E, 0x67, 0x86, 0x32, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0x23, 0x73, 0xB1, 0xA9, 0xD5, 0xCC, 0x27, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x0E, 0x11, 0x01, 0x71, 0xFE, 0x92, 0x73), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0x28, 0x63, 0x6D, 0x72, 0x09, 0xA6, 0xC0), +}; +static const mbedtls_mpi_uint secp256k1_T_1_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xCE, 0xE1, 0x69, 0xDC, 0x3E, 0x2C, 0x75, 0xC3), + MBEDTLS_BYTES_TO_T_UINT_8(0xE5, 0xB7, 0x3F, 0x30, 0x26, 0x3C, 0xDF, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0xBE, 0xB9, 0x5D, 0x0E, 0xE8, 0x5E, 0x14), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0xC3, 0x05, 0xD6, 0xB7, 0xD5, 0x24, 0xFC), +}; +static const mbedtls_mpi_uint secp256k1_T_2_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x13, 0xCF, 0x7B, 0xDC, 0xCD, 0xC3, 0x39, 0x9D), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0xDA, 0xB9, 0xE5, 0x64, 0xA7, 0x47, 0x91), + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0x46, 0xA8, 0x61, 0xF6, 0x23, 0xEB, 0x58), + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0xC1, 0xFF, 0xE4, 0x55, 0xD5, 0xC2, 0xBF), +}; +static const mbedtls_mpi_uint secp256k1_T_2_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0xBE, 0xB9, 0x59, 0x24, 0x13, 0x4A, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x45, 0x12, 0xDE, 0xBA, 0x4F, 0xEF, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0x08, 0xBF, 0xC1, 0x66, 0xAA, 0x0A, 0xBC), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0xFE, 0x30, 0x55, 0x31, 0x86, 0xA7, 0xB4), +}; +static const mbedtls_mpi_uint secp256k1_T_3_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0xBF, 0x18, 0x81, 0x67, 0x27, 0x42, 0xBD), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0x05, 0x83, 0xA4, 0xDD, 0x57, 0xD3, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x20, 0x63, 0xAB, 0xE4, 0x90, 0x70, 0xD0, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x5D, 0xFD, 0xA0, 0xEF, 0xCF, 0x1C, 0x54), +}; +static const mbedtls_mpi_uint secp256k1_T_3_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x13, 0x80, 0xE4, 0xF6, 0x09, 0xBC, 0x57, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0x9F, 0x6E, 0x88, 0x54, 0x6E, 0x51, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0x5F, 0x85, 0xFB, 0x84, 0x3E, 0x4A, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0x19, 0xF5, 0x55, 0xC9, 0x07, 0xD8, 0xCE), +}; +static const mbedtls_mpi_uint secp256k1_T_4_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1A, 0xB4, 0xC3, 0xD9, 0x5C, 0xA0, 0xD4, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0x0D, 0x30, 0xAF, 0x59, 0x9B, 0xF8, 0x04, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0x4D, 0xA6, 0xFD, 0x66, 0x7B, 0xC3, 0x39, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0xE0, 0xBF, 0xF0, 0xC2, 0xE9, 0x71, 0xA4, 0x9E), +}; +static const mbedtls_mpi_uint secp256k1_T_4_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x14, 0x2D, 0xB9, 0x88, 0x28, 0xF1, 0xBE, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0x14, 0xF3, 0x1A, 0x0E, 0xB9, 0x01, 0x66, 0x34), + MBEDTLS_BYTES_TO_T_UINT_8(0x77, 0xA7, 0xA4, 0xF4, 0x05, 0xD0, 0xAA, 0x53), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x39, 0x1E, 0x47, 0xE5, 0x68, 0xC8, 0xC0), +}; +static const mbedtls_mpi_uint secp256k1_T_5_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0xB9, 0xFC, 0xE0, 0x33, 0x8A, 0x7D, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0x93, 0xA5, 0x53, 0x55, 0x16, 0xB4, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0x5F, 0xEA, 0x9B, 0x29, 0x52, 0x71, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0xB2, 0xF0, 0x24, 0xB8, 0x7D, 0xB7, 0xA0, 0x9B), +}; +static const mbedtls_mpi_uint secp256k1_T_5_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x00, 0x27, 0xB2, 0xDF, 0x73, 0xA2, 0xE0), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x2E, 0x4D, 0x7C, 0xDE, 0x7A, 0x23, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x65, 0x60, 0xC7, 0x97, 0x1E, 0xA4, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0x13, 0x5B, 0x77, 0x59, 0xCB, 0x36, 0xE1), +}; +static const mbedtls_mpi_uint secp256k1_T_6_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0xBC, 0x9F, 0x9E, 0x2D, 0x53, 0x2A, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0x5F, 0x64, 0x9F, 0x1A, 0x19, 0xE6, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0x9E, 0x7B, 0x39, 0xD2, 0xDB, 0x85, 0x84, 0xD5), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0xC7, 0x0D, 0x58, 0x6E, 0x3F, 0x52, 0x15), +}; +static const mbedtls_mpi_uint secp256k1_T_6_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0x68, 0x19, 0x0B, 0x68, 0xC9, 0x1E, 0xFB), + MBEDTLS_BYTES_TO_T_UINT_8(0xD2, 0x4E, 0x21, 0x49, 0x3D, 0x55, 0xCC, 0x25), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xF9, 0x25, 0x45, 0x54, 0x45, 0xB1, 0x0F), + MBEDTLS_BYTES_TO_T_UINT_8(0xA9, 0xB3, 0xF7, 0xCD, 0x80, 0xA4, 0x04, 0x05), +}; +static const mbedtls_mpi_uint secp256k1_T_7_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0x1E, 0x88, 0xC4, 0xAA, 0x18, 0x7E, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0x4B, 0xAC, 0xD9, 0xB2, 0xA1, 0xC0, 0x71, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0xA9, 0xA2, 0xF1, 0x15, 0xA6, 0x5F, 0x6C, 0x86), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0x5B, 0x05, 0xBC, 0xB7, 0xC6, 0x4E, 0x72), +}; +static const mbedtls_mpi_uint secp256k1_T_7_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x80, 0xF8, 0x5C, 0x20, 0x2A, 0xE1, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x48, 0x2E, 0x68, 0x82, 0x7F, 0xEB, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0xA2, 0x3B, 0x25, 0xDB, 0x32, 0x4D, 0x88, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xEE, 0x6E, 0xA6, 0xB6, 0x6D, 0x62, 0x78, 0x22), +}; +static const mbedtls_mpi_uint secp256k1_T_8_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x4D, 0x3E, 0x86, 0x58, 0xC3, 0xEB, 0xBA), + MBEDTLS_BYTES_TO_T_UINT_8(0x1A, 0x89, 0x33, 0x18, 0x21, 0x1D, 0x9B, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0x9D, 0xFF, 0xC3, 0x79, 0xC1, 0x88, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0xD4, 0x48, 0x53, 0xE8, 0xAD, 0x21, 0x16), +}; +static const mbedtls_mpi_uint secp256k1_T_8_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0x7B, 0xDE, 0xCB, 0xD8, 0x39, 0x17, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0xD3, 0xF3, 0x03, 0xF2, 0x5C, 0xBC, 0xC8, 0x8A), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0xAE, 0x4C, 0xB0, 0x16, 0xA4, 0x93, 0x86), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x8B, 0x6B, 0xDC, 0xD7, 0x9A, 0x3E, 0x7E), +}; +static const mbedtls_mpi_uint secp256k1_T_9_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0x2D, 0x7A, 0xD2, 0x59, 0x05, 0xA2, 0x82), + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0x56, 0x09, 0x32, 0xF1, 0xE8, 0xE3, 0x72), + MBEDTLS_BYTES_TO_T_UINT_8(0x03, 0xCA, 0xE5, 0x2E, 0xF0, 0xFB, 0x18, 0x19), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x85, 0xA9, 0x23, 0x15, 0x31, 0x1F, 0x0E), +}; +static const mbedtls_mpi_uint secp256k1_T_9_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0xE5, 0xB1, 0x86, 0xB9, 0x6E, 0x8D, 0xD3), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x77, 0xFC, 0xC9, 0xA3, 0x3F, 0x89, 0xD2), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x6A, 0xDC, 0x25, 0xB0, 0xC7, 0x41, 0x54), + MBEDTLS_BYTES_TO_T_UINT_8(0x02, 0x11, 0x6B, 0xA6, 0x11, 0x62, 0xD4, 0x2D), +}; +static const mbedtls_mpi_uint secp256k1_T_10_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x7D, 0x34, 0xB3, 0x20, 0x7F, 0x37, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0xBD, 0xD4, 0x45, 0xE8, 0xC2, 0xE9, 0xC5, 0xEA), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x32, 0x3B, 0x25, 0x7E, 0x79, 0xAF, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0xE4, 0x54, 0x71, 0xBE, 0x35, 0x4E, 0xD0), +}; +static const mbedtls_mpi_uint secp256k1_T_10_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x94, 0xDD, 0x8F, 0xB5, 0xC2, 0xDD, 0x75), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0x49, 0xE9, 0x1C, 0x2F, 0x08, 0x49, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0x77, 0xB6, 0x03, 0x88, 0x6F, 0xB8, 0x15, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0xD3, 0x1C, 0xF3, 0xA5, 0xEB, 0x79, 0x01), +}; +static const mbedtls_mpi_uint secp256k1_T_11_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x25, 0xF9, 0x43, 0x88, 0x89, 0x0D, 0x06, 0xEA), + MBEDTLS_BYTES_TO_T_UINT_8(0x02, 0x2D, 0xF5, 0x98, 0x32, 0xF6, 0xB1, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0x23, 0x73, 0x8F, 0x2B, 0x50, 0x27, 0x0A, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0xE3, 0xBD, 0x16, 0x05, 0xC8, 0x93, 0x12), +}; +static const mbedtls_mpi_uint secp256k1_T_11_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x0A, 0x6A, 0xF7, 0xE3, 0x3D, 0xDE, 0x5F, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0xA3, 0x9C, 0x22, 0x3C, 0x33, 0x36, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x20, 0x24, 0x4C, 0x69, 0x45, 0x78, 0x14, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0xF8, 0xD4, 0xBF, 0xB8, 0xC0, 0xA1, 0x25), +}; +static const mbedtls_mpi_uint secp256k1_T_12_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0x88, 0xE1, 0x91, 0x03, 0xEB, 0xB3, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0x11, 0xA1, 0xEF, 0x14, 0x0D, 0xC4, 0x7D), + MBEDTLS_BYTES_TO_T_UINT_8(0xFE, 0xD4, 0x0D, 0x1D, 0x96, 0x33, 0x5C, 0x19), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0x45, 0x2A, 0x1A, 0xE6, 0x57, 0x04, 0x9B), +}; +static const mbedtls_mpi_uint secp256k1_T_12_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0xB5, 0xA7, 0x80, 0xE9, 0x93, 0x97, 0x8D), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0xB9, 0x7C, 0xA0, 0xC9, 0x57, 0x26, 0x43), + MBEDTLS_BYTES_TO_T_UINT_8(0x9E, 0xEF, 0x56, 0xDA, 0x66, 0xF6, 0x1B, 0x9A), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x89, 0x6B, 0x91, 0xE0, 0xA9, 0x65, 0x2B), +}; +static const mbedtls_mpi_uint secp256k1_T_13_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0x98, 0x96, 0x9B, 0x06, 0x7D, 0x5E, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0x0A, 0xFA, 0xC1, 0x5F, 0x19, 0x37, 0x94, 0x9D), + MBEDTLS_BYTES_TO_T_UINT_8(0xCF, 0xBE, 0x6B, 0x1A, 0x05, 0xE4, 0xBF, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0x84, 0xCD, 0x5D, 0x35, 0xB4, 0x51, 0xF7, 0x64), +}; +static const mbedtls_mpi_uint secp256k1_T_13_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0xEF, 0x96, 0xDB, 0xF2, 0x61, 0x63, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x04, 0x88, 0xC9, 0x9F, 0x1B, 0x94, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x30, 0x79, 0x7E, 0x24, 0xE7, 0x5F, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0xB8, 0x90, 0xB7, 0x94, 0x25, 0xBB, 0x0F), +}; +static const mbedtls_mpi_uint secp256k1_T_14_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x62, 0x79, 0xEA, 0xAD, 0xC0, 0x6D, 0x18, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0xA4, 0x58, 0x2A, 0x8D, 0x95, 0xB3, 0xE6), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0xC4, 0xC2, 0x12, 0x0D, 0x79, 0xE2, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0x02, 0x6F, 0xBE, 0x97, 0x4D, 0xA4, 0x20, 0x07), +}; +static const mbedtls_mpi_uint secp256k1_T_14_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0x31, 0x71, 0xC6, 0xA6, 0x91, 0xEB, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x9B, 0xA8, 0x4A, 0xE7, 0x77, 0xE1, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0xA9, 0x06, 0xD3, 0x3D, 0x94, 0x30, 0xEF, 0x8C), + MBEDTLS_BYTES_TO_T_UINT_8(0xE7, 0xDF, 0xCA, 0xFA, 0xF5, 0x28, 0xF8, 0xC9), +}; +static const mbedtls_mpi_uint secp256k1_T_15_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xCC, 0xE1, 0x32, 0xFD, 0x3E, 0x81, 0xF8, 0x11), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0xF2, 0x4B, 0x1D, 0x19, 0xC9, 0x0F, 0xCC), + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0xB1, 0x8A, 0x22, 0x8B, 0x05, 0x6B, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0x35, 0x21, 0xEF, 0x30, 0xEC, 0x09, 0x2A, 0x89), +}; +static const mbedtls_mpi_uint secp256k1_T_15_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x84, 0x4A, 0x46, 0x07, 0x6C, 0x3C, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x18, 0x3A, 0xF4, 0xCC, 0xF5, 0xB2, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0x8F, 0xCD, 0x0A, 0x9C, 0xF4, 0xBD, 0x95), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x89, 0x7F, 0x8A, 0xB1, 0x52, 0x3A, 0xAB), +}; +static const mbedtls_ecp_point secp256k1_T[16] = { + ECP_POINT_INIT_XY_Z1(secp256k1_T_0_X, secp256k1_T_0_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_1_X, secp256k1_T_1_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_2_X, secp256k1_T_2_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_3_X, secp256k1_T_3_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_4_X, secp256k1_T_4_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_5_X, secp256k1_T_5_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_6_X, secp256k1_T_6_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_7_X, secp256k1_T_7_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_8_X, secp256k1_T_8_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_9_X, secp256k1_T_9_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_10_X, secp256k1_T_10_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_11_X, secp256k1_T_11_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_12_X, secp256k1_T_12_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_13_X, secp256k1_T_13_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_14_X, secp256k1_T_14_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_15_X, secp256k1_T_15_Y), +}; +#else +#define secp256k1_T NULL +#endif +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +/* + * Domain parameters for brainpoolP256r1 (RFC 5639 3.4) + */ +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP256r1_p[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x77, 0x53, 0x6E, 0x1F, 0x1D, 0x48, 0x13, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x20, 0x26, 0xD5, 0x23, 0xF6, 0x3B, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9), +}; +static const mbedtls_mpi_uint brainpoolP256r1_a[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0xB5, 0x30, 0xF3, 0x44, 0x4B, 0x4A, 0xE9), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x5C, 0xDC, 0x26, 0xC1, 0x55, 0x80, 0xFB), + MBEDTLS_BYTES_TO_T_UINT_8(0xE7, 0xFF, 0x7A, 0x41, 0x30, 0x75, 0xF6, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0x30, 0x2C, 0xFC, 0x75, 0x09, 0x5A, 0x7D), +}; +static const mbedtls_mpi_uint brainpoolP256r1_b[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x07, 0x8C, 0xFF, 0x18, 0xDC, 0xCC, 0x6B), + MBEDTLS_BYTES_TO_T_UINT_8(0xCE, 0xE1, 0xF7, 0x5C, 0x29, 0x16, 0x84, 0x95), + MBEDTLS_BYTES_TO_T_UINT_8(0xBF, 0x7C, 0xD7, 0xBB, 0xD9, 0xB5, 0x30, 0xF3), + MBEDTLS_BYTES_TO_T_UINT_8(0x44, 0x4B, 0x4A, 0xE9, 0x6C, 0x5C, 0xDC, 0x26), +}; +static const mbedtls_mpi_uint brainpoolP256r1_gx[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x62, 0x32, 0xCE, 0x9A, 0xBD, 0x53, 0x44, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x23, 0xBD, 0xE3, 0xE1, 0x27, 0xDE, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0xB7, 0x81, 0xFC, 0x2F, 0x48, 0x4B, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x57, 0x7E, 0xCB, 0xB9, 0xAE, 0xD2, 0x8B), +}; +static const mbedtls_mpi_uint brainpoolP256r1_gy[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x97, 0x69, 0x04, 0x2F, 0xC7, 0x54, 0x1D, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x54, 0x8E, 0xED, 0x2D, 0x13, 0x45, 0x77, 0xC2), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x1D, 0x61, 0x14, 0x1A, 0x46, 0xF8, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0xC4, 0xDA, 0xC3, 0x35, 0xF8, 0x7E, 0x54), +}; +static const mbedtls_mpi_uint brainpoolP256r1_n[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0x56, 0x48, 0x97, 0x82, 0x0E, 0x1E, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0xF7, 0xA6, 0x61, 0xB5, 0xA3, 0x7A, 0x39, 0x8C), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9), +}; + +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 +static const mbedtls_mpi_uint brainpoolP256r1_T_0_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x62, 0x32, 0xCE, 0x9A, 0xBD, 0x53, 0x44, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x23, 0xBD, 0xE3, 0xE1, 0x27, 0xDE, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0xB7, 0x81, 0xFC, 0x2F, 0x48, 0x4B, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x57, 0x7E, 0xCB, 0xB9, 0xAE, 0xD2, 0x8B), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_0_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x97, 0x69, 0x04, 0x2F, 0xC7, 0x54, 0x1D, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x54, 0x8E, 0xED, 0x2D, 0x13, 0x45, 0x77, 0xC2), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x1D, 0x61, 0x14, 0x1A, 0x46, 0xF8, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0xC4, 0xDA, 0xC3, 0x35, 0xF8, 0x7E, 0x54), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_1_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0xA2, 0xED, 0x52, 0xC9, 0x8C, 0xE3, 0xA5), + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0xC9, 0xC4, 0x87, 0x3F, 0x93, 0x7A, 0xD1), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0x12, 0x53, 0x61, 0x3E, 0x76, 0x08, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0x8C, 0x74, 0xF4, 0x08, 0xC3, 0x76, 0x80), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_1_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x05, 0xDD, 0x09, 0xA6, 0xED, 0xEE, 0xC4, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0xD9, 0xBE, 0x4B, 0xA5, 0xB7, 0x2B, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0x20, 0x12, 0xCA, 0x0A, 0x38, 0x24, 0xAB), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x72, 0x71, 0x90, 0x7A, 0x2E, 0xB7, 0x23), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_2_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2C, 0x66, 0xA1, 0x93, 0x10, 0x2A, 0x51, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0x88, 0x10, 0x11, 0x12, 0xBC, 0xB0, 0xB6, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0x58, 0xD7, 0x0A, 0x84, 0x05, 0xA3, 0x9C), + MBEDTLS_BYTES_TO_T_UINT_8(0xF7, 0x8E, 0x95, 0x61, 0xD3, 0x0B, 0xDF, 0x36), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_2_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF9, 0x92, 0x12, 0x0F, 0x5E, 0x87, 0x70, 0x1B), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0xE9, 0x9B, 0xEB, 0x3A, 0xFB, 0xCF, 0xC4), + MBEDTLS_BYTES_TO_T_UINT_8(0xDC, 0x92, 0xB9, 0xF7, 0x45, 0xD3, 0x06, 0xB6), + MBEDTLS_BYTES_TO_T_UINT_8(0x82, 0x28, 0x65, 0xE1, 0xC5, 0x6C, 0x57, 0x18), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_3_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x0E, 0x77, 0x01, 0x81, 0x9E, 0x38, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0xF0, 0xD5, 0xA5, 0x91, 0x2B, 0xDF, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0xEE, 0xB6, 0x25, 0xD6, 0x98, 0xDE, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0xA1, 0x55, 0x63, 0x39, 0xEB, 0xB5, 0x47), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_3_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0xD6, 0xB8, 0xE3, 0x13, 0xED, 0x7F, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0xE8, 0xAE, 0x36, 0xB8, 0xCD, 0x19, 0x02), + MBEDTLS_BYTES_TO_T_UINT_8(0xF9, 0x82, 0x83, 0x7A, 0x7B, 0x46, 0x56, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0x4E, 0x60, 0x46, 0x15, 0x5A, 0xAC, 0x99, 0x30), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_4_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBF, 0x61, 0x50, 0xC6, 0xFF, 0x10, 0x7D, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x51, 0xDF, 0xA9, 0x7D, 0x78, 0x26, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0x56, 0x15, 0x9A, 0xF7, 0x01, 0xC1, 0xBB, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x0F, 0xE6, 0x2A, 0xBD, 0x4A, 0x9E, 0x87), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_4_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0xF8, 0xD1, 0x77, 0xD2, 0x49, 0xB3, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0x86, 0xFB, 0x9E, 0x1F, 0x5A, 0x60, 0x47), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0xC4, 0x8D, 0xCD, 0x86, 0x61, 0x2F, 0xF9), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0xF6, 0xB9, 0xAC, 0x37, 0x9D, 0xE9, 0x28), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_5_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x77, 0xAA, 0x97, 0x9C, 0x0B, 0x04, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0x80, 0xA6, 0x60, 0x81, 0xCE, 0x25, 0x13, 0x3E), + MBEDTLS_BYTES_TO_T_UINT_8(0x24, 0x00, 0xF3, 0xBB, 0x82, 0x99, 0x95, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0x5A, 0xCE, 0x90, 0x71, 0x38, 0x2F, 0x10), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_5_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0x1A, 0xC0, 0x84, 0x27, 0xD6, 0x9D, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0x37, 0x52, 0x16, 0x13, 0x0E, 0xCE, 0x92), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xBF, 0x5A, 0xDB, 0xDB, 0x6E, 0x1E, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0xB7, 0x5E, 0xF9, 0x86, 0xDD, 0x8A, 0x5C), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_6_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0xAB, 0x5C, 0x8D, 0x1D, 0xF2, 0x2D, 0x1E), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0xC5, 0xF8, 0xF7, 0x1D, 0x96, 0x0B, 0x4D), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x4C, 0xA7, 0x45, 0x20, 0x6A, 0x1E, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0x5D, 0xEF, 0xDE, 0xEE, 0x39, 0x44, 0x19), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_6_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x4B, 0x2F, 0x6D, 0x52, 0xC9, 0x58, 0x60, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0xC3, 0xC9, 0x62, 0xCB, 0x38, 0x3C, 0x55, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xA5, 0x09, 0x10, 0x88, 0xDB, 0xE3, 0xBD), + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0xE0, 0x3C, 0xCE, 0x06, 0x0B, 0x4B, 0x5D), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_7_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB1, 0x1D, 0xB4, 0x10, 0x76, 0x8F, 0xBA, 0x09), + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0x70, 0x5A, 0x07, 0xF5, 0x1A, 0x74, 0xC7), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0xE9, 0x94, 0xA8, 0xC0, 0xD5, 0x4A, 0x4A), + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0x6D, 0xD4, 0xE8, 0x9B, 0xE9, 0x6D, 0x0E), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_7_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x00, 0x32, 0x41, 0x57, 0x84, 0x89, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0xEE, 0xC7, 0x14, 0xEC, 0xE9, 0x27, 0xFF, 0xF3), + MBEDTLS_BYTES_TO_T_UINT_8(0x9A, 0x67, 0x9E, 0xFB, 0xB6, 0xB8, 0x96, 0xF3), + MBEDTLS_BYTES_TO_T_UINT_8(0xE5, 0x4A, 0xE3, 0x97, 0x4B, 0x58, 0xDE, 0x30), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_8_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA6, 0x1E, 0x5C, 0xF5, 0x7F, 0xD5, 0xD4, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0x08, 0x7A, 0xF1, 0xBD, 0x89, 0xC7, 0x1E), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0xF9, 0x11, 0x1B, 0xF5, 0x3C, 0x6D, 0x8C), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x50, 0xE5, 0x69, 0x1D, 0x59, 0xFC, 0x0C), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_8_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x2F, 0xF8, 0x3F, 0xEC, 0x55, 0x99, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0xA7, 0x29, 0x90, 0x43, 0x81, 0x31, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0xC3, 0x18, 0x44, 0x50, 0x5D, 0x76, 0xCB, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0xC5, 0x5B, 0x9A, 0x03, 0xE6, 0x17, 0x39), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_9_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0x89, 0xFC, 0x55, 0x94, 0x91, 0x6A, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0x46, 0x35, 0xF2, 0x3A, 0x42, 0x08, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0xD3, 0xD2, 0x76, 0x49, 0x42, 0x87, 0xD3, 0x7F), + MBEDTLS_BYTES_TO_T_UINT_8(0x90, 0xEA, 0xA0, 0x52, 0xF1, 0x6A, 0x30, 0x57), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_9_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0xB2, 0x57, 0xA3, 0x8A, 0x4D, 0x1B, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0xA3, 0x99, 0x94, 0xB5, 0x3D, 0x64, 0x09), + MBEDTLS_BYTES_TO_T_UINT_8(0x35, 0xC3, 0xD7, 0x53, 0xF6, 0x49, 0x1C, 0x60), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0x23, 0x41, 0x4D, 0xFB, 0x7A, 0x5C, 0x53), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_10_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0xB8, 0x15, 0x65, 0x5C, 0x85, 0x94, 0xD7), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x37, 0xC7, 0xF8, 0x7E, 0xAE, 0x6C, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0x53, 0xD8, 0x11, 0x54, 0x98, 0x44, 0xE3, 0xF1), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0x4D, 0xA6, 0x4B, 0x28, 0xF2, 0x57, 0x9E), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_10_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0xD0, 0xEB, 0x1E, 0xAA, 0x30, 0xD3, 0x6A), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0x9B, 0x4D, 0xA7, 0x73, 0x6E, 0xB6, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0x47, 0xF6, 0xED, 0x37, 0xEF, 0x71, 0x4D), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0xB5, 0x49, 0x61, 0x5E, 0x45, 0xF6, 0x4A), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_11_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0x0E, 0xB3, 0x84, 0x3A, 0x63, 0x72, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x53, 0x5C, 0xA7, 0xC6, 0x2E, 0xAB, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0x0F, 0x8F, 0x87, 0x50, 0x28, 0xB4, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0x98, 0x4A, 0x98, 0x31, 0x86, 0xCA, 0x51), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_11_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0xC9, 0xE2, 0xFD, 0x5D, 0x1F, 0xE8, 0xC2), + MBEDTLS_BYTES_TO_T_UINT_8(0xD5, 0x90, 0x91, 0xC4, 0x84, 0xF0, 0xBA, 0xC5), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x5A, 0xB3, 0x4E, 0xFB, 0xE0, 0x57, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0x6B, 0x0B, 0x90, 0xA6, 0xFD, 0x9D, 0x8E, 0x02), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_12_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0x41, 0x8F, 0x31, 0xFA, 0x5A, 0xF6, 0x33), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xE9, 0xE3, 0xF6, 0xE0, 0x4A, 0xE7, 0xD2), + MBEDTLS_BYTES_TO_T_UINT_8(0x84, 0x4E, 0xCD, 0xA2, 0x22, 0x14, 0xD4, 0x12), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0xED, 0x21, 0xB7, 0x0F, 0x53, 0x10, 0x17), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_12_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x05, 0x06, 0x24, 0x2C, 0x4E, 0xD1, 0x1E, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0xD7, 0x3F, 0xC1, 0x9F, 0xAB, 0xF0, 0x37, 0x95), + MBEDTLS_BYTES_TO_T_UINT_8(0x03, 0x5E, 0x12, 0xCE, 0x83, 0x1B, 0x2A, 0x18), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0x65, 0xCF, 0xE8, 0x5C, 0xA5, 0xA2, 0x70), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_13_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0x86, 0x76, 0x3A, 0x94, 0xF6, 0x1D, 0xC1), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0xDA, 0xC9, 0xA6, 0x29, 0x93, 0x15, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x61, 0x6A, 0x7D, 0xC7, 0xA9, 0xF3, 0x76), + MBEDTLS_BYTES_TO_T_UINT_8(0x4A, 0x03, 0x71, 0xA2, 0x15, 0xCE, 0x50, 0x72), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_13_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0xD0, 0xA8, 0x1E, 0x91, 0xC4, 0x4F, 0x24), + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0x4B, 0x7E, 0xD7, 0x71, 0x58, 0x7E, 0x1E), + MBEDTLS_BYTES_TO_T_UINT_8(0x93, 0x45, 0xAF, 0x2A, 0x18, 0x93, 0x95, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0x1B, 0x8F, 0xC7, 0xFA, 0x4C, 0x7A, 0x86, 0x54), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_14_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x97, 0xAF, 0x68, 0x3A, 0x23, 0xC1, 0x2E, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0x89, 0x50, 0x11, 0x67, 0x39, 0xB9, 0xAF, 0x48), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x86, 0xAA, 0x1E, 0x88, 0x21, 0x29, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0x28, 0xA4, 0x9D, 0x89, 0xA9, 0x9A, 0x10), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_14_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0xBA, 0x04, 0x67, 0xB7, 0x01, 0x40, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0xE9, 0x09, 0xA3, 0xCA, 0xA6, 0x37, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x97, 0xA8, 0xB6, 0x3C, 0xEE, 0x90, 0x3D), + MBEDTLS_BYTES_TO_T_UINT_8(0xDC, 0xED, 0xC4, 0xF7, 0xC3, 0x95, 0xEC, 0x85), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_15_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0x84, 0xBD, 0xEB, 0xD5, 0x64, 0xBB, 0x9D), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x9B, 0xE2, 0x28, 0x50, 0xC2, 0x72, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x39, 0xF2, 0x74, 0xD1, 0x26, 0xBF, 0x32, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0xCB, 0xAF, 0x72, 0xDB, 0x6D, 0x30, 0x98), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_15_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB3, 0x50, 0x85, 0xF4, 0x2B, 0x48, 0xC1, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0x28, 0xBB, 0x11, 0xBA, 0x5B, 0x22, 0x6C), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0xA1, 0xE5, 0x5C, 0xC9, 0x1D, 0x44, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0xE8, 0xE6, 0x6F, 0xBB, 0xC1, 0x81, 0x7F), +}; +static const mbedtls_ecp_point brainpoolP256r1_T[16] = { + ECP_POINT_INIT_XY_Z1(brainpoolP256r1_T_0_X, brainpoolP256r1_T_0_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_1_X, brainpoolP256r1_T_1_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_2_X, brainpoolP256r1_T_2_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_3_X, brainpoolP256r1_T_3_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_4_X, brainpoolP256r1_T_4_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_5_X, brainpoolP256r1_T_5_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_6_X, brainpoolP256r1_T_6_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_7_X, brainpoolP256r1_T_7_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_8_X, brainpoolP256r1_T_8_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_9_X, brainpoolP256r1_T_9_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_10_X, brainpoolP256r1_T_10_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_11_X, brainpoolP256r1_T_11_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_12_X, brainpoolP256r1_T_12_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_13_X, brainpoolP256r1_T_13_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_14_X, brainpoolP256r1_T_14_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_15_X, brainpoolP256r1_T_15_Y), +}; +#else +#define brainpoolP256r1_T NULL +#endif + +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ + +/* + * Domain parameters for brainpoolP384r1 (RFC 5639 3.6) + */ +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP384r1_p[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x53, 0xEC, 0x07, 0x31, 0x13, 0x00, 0x47, 0x87), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x1A, 0x1D, 0x90, 0x29, 0xA7, 0xD3, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0x23, 0x11, 0xB7, 0x7F, 0x19, 0xDA, 0xB1, 0x12), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C), +}; +static const mbedtls_mpi_uint brainpoolP384r1_a[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0xD4, 0x3A, 0x50, 0x4A, 0x81, 0xA5, 0x8A), + MBEDTLS_BYTES_TO_T_UINT_8(0x0F, 0xF9, 0x91, 0xBA, 0xEF, 0x65, 0x91, 0x13), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0x27, 0xB2, 0x4F, 0x8E, 0xA2, 0xBE, 0xC2), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0xAF, 0x05, 0xCE, 0x0A, 0x08, 0x72, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0x15, 0x8C, 0x3D, 0xC6, 0x82, 0xC3, 0x7B), +}; +static const mbedtls_mpi_uint brainpoolP384r1_b[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0x4C, 0x50, 0xFA, 0x96, 0x86, 0xB7, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0x94, 0xC9, 0xDB, 0x95, 0x02, 0x39, 0xB4, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0xD5, 0x62, 0xEB, 0x3E, 0xA5, 0x0E, 0x88, 0x2E), + MBEDTLS_BYTES_TO_T_UINT_8(0xA6, 0xD2, 0xDC, 0x07, 0xE1, 0x7D, 0xB7, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x44, 0xF0, 0x16, 0x54, 0xB5, 0x39, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04), +}; +static const mbedtls_mpi_uint brainpoolP384r1_gx[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xAF, 0xD4, 0x47, 0xE2, 0xB2, 0x87, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0xAA, 0x46, 0xD6, 0x36, 0x34, 0xE0, 0x26, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x10, 0xBD, 0x0C, 0xFE, 0xCA, 0x7F, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x4F, 0xF1, 0x7E, 0xE7, 0xA3, 0x47, 0x88), + MBEDTLS_BYTES_TO_T_UINT_8(0x6B, 0x3F, 0xC1, 0xB7, 0x81, 0x3A, 0xA6, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0x45, 0xCF, 0x68, 0xF0, 0x64, 0x1C, 0x1D), +}; +static const mbedtls_mpi_uint brainpoolP384r1_gy[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x53, 0x3C, 0x26, 0x41, 0x03, 0x82, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0x81, 0x91, 0x77, 0x21, 0x46, 0x46, 0x0E), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x29, 0x91, 0xF9, 0x4F, 0x05, 0x9C, 0xE1), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x58, 0xEC, 0xFE, 0x29, 0x0B, 0xB7, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0xD5, 0xCF, 0x95, 0x8E, 0xEB, 0xB1, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0xC2, 0xF9, 0x20, 0x75, 0x1D, 0xBE, 0x8A), +}; +static const mbedtls_mpi_uint brainpoolP384r1_n[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x65, 0x04, 0xE9, 0x02, 0x32, 0x88, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0xC3, 0x7F, 0x6B, 0xAF, 0xB6, 0x3A, 0xCF), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0x25, 0x04, 0xAC, 0x6C, 0x6E, 0x16, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0xB3, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C), +}; + +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 +static const mbedtls_mpi_uint brainpoolP384r1_T_0_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xAF, 0xD4, 0x47, 0xE2, 0xB2, 0x87, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0xAA, 0x46, 0xD6, 0x36, 0x34, 0xE0, 0x26, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x10, 0xBD, 0x0C, 0xFE, 0xCA, 0x7F, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x4F, 0xF1, 0x7E, 0xE7, 0xA3, 0x47, 0x88), + MBEDTLS_BYTES_TO_T_UINT_8(0x6B, 0x3F, 0xC1, 0xB7, 0x81, 0x3A, 0xA6, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0x45, 0xCF, 0x68, 0xF0, 0x64, 0x1C, 0x1D), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_0_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x53, 0x3C, 0x26, 0x41, 0x03, 0x82, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0x81, 0x91, 0x77, 0x21, 0x46, 0x46, 0x0E), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x29, 0x91, 0xF9, 0x4F, 0x05, 0x9C, 0xE1), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x58, 0xEC, 0xFE, 0x29, 0x0B, 0xB7, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0xD5, 0xCF, 0x95, 0x8E, 0xEB, 0xB1, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0xC2, 0xF9, 0x20, 0x75, 0x1D, 0xBE, 0x8A), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_1_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x93, 0xD8, 0x8A, 0x54, 0x41, 0xD6, 0x6B, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0xE2, 0x3B, 0xF1, 0x22, 0xFD, 0x2D, 0x4B, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0x55, 0xE3, 0x33, 0xF0, 0x73, 0x52, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0x3F, 0x30, 0x26, 0xCA, 0x7F, 0x52, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0xD3, 0x6E, 0x17, 0x9B, 0xD5, 0x2A, 0x4A, 0x31), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0xDA, 0x6B, 0xE5, 0x03, 0x07, 0x1D, 0x2E), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_1_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0x7A, 0xAF, 0x98, 0xE3, 0xA4, 0xF6, 0x19), + MBEDTLS_BYTES_TO_T_UINT_8(0xEC, 0x7D, 0xFE, 0x51, 0x40, 0x3B, 0x47, 0xD2), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x88, 0xEC, 0xC4, 0xE2, 0x8F, 0xCB, 0xA4), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0xE2, 0x88, 0x2D, 0x4E, 0x50, 0xEB, 0x9A), + MBEDTLS_BYTES_TO_T_UINT_8(0x13, 0x54, 0x94, 0x5E, 0xF4, 0x7F, 0x3A, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0x07, 0x1C, 0xE1, 0xBD, 0x0F, 0xF8, 0x63), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_2_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x94, 0x92, 0x28, 0x2E, 0x32, 0x04, 0xB1, 0x4D), + MBEDTLS_BYTES_TO_T_UINT_8(0x25, 0x82, 0x44, 0x43, 0x76, 0x0D, 0x55, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0xE3, 0xFF, 0x89, 0x46, 0xDE, 0x4E, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0x22, 0xBB, 0x67, 0x1A, 0x81, 0xEE, 0x27), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0x54, 0xE2, 0x7A, 0xAE, 0xDA, 0x2C, 0xD0), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0x9A, 0x90, 0xAA, 0x6E, 0x8B, 0xCC, 0x5F), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_2_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0x40, 0xAC, 0xED, 0x7D, 0x37, 0x87, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0xF8, 0xB1, 0x80, 0x4C, 0x8C, 0x04, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x98, 0x2C, 0xAD, 0x30, 0x69, 0x35, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0x32, 0x2E, 0x00, 0x2F, 0x44, 0x8C, 0xF0, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0x58, 0x07, 0xD7, 0xCD, 0x60, 0xA1, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0xFB, 0x7B, 0x03, 0x05, 0x5E, 0x79, 0x73), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_3_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0x17, 0xCE, 0x38, 0x4B, 0x5E, 0x5B, 0xC8), + MBEDTLS_BYTES_TO_T_UINT_8(0x60, 0x0E, 0x0A, 0x61, 0x9D, 0x7C, 0x62, 0x08), + MBEDTLS_BYTES_TO_T_UINT_8(0x25, 0xF0, 0x98, 0x71, 0x7F, 0x17, 0x26, 0xD7), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0xD3, 0xFA, 0x3C, 0xF0, 0x70, 0x07, 0x82), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0x47, 0x5C, 0x09, 0x43, 0xB7, 0x65, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0xA9, 0xA7, 0x3E, 0xFA, 0xF3, 0xEC, 0x22), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_3_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x78, 0x22, 0x2B, 0x58, 0x71, 0xFA, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x30, 0xCE, 0x6A, 0xB3, 0xB0, 0x4F, 0x83), + MBEDTLS_BYTES_TO_T_UINT_8(0xCF, 0x95, 0x20, 0xA9, 0x23, 0xC2, 0x65, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0xCF, 0x03, 0x5B, 0x8A, 0x80, 0x44, 0xBB), + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0xF8, 0x91, 0xF7, 0xD5, 0xED, 0xEA, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0x5B, 0x16, 0x10, 0x25, 0xAC, 0x2A, 0x17), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_4_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0xEC, 0xDC, 0xC4, 0x7B, 0x8C, 0x6B, 0xE9), + MBEDTLS_BYTES_TO_T_UINT_8(0x2B, 0xBB, 0x1C, 0xD3, 0x5A, 0xEE, 0xD9, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x5D, 0x30, 0x5E, 0xF7, 0xB2, 0x41, 0x9D), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0xCE, 0x0F, 0x1A, 0xC6, 0x41, 0x64, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0x18, 0xE1, 0xE3, 0x82, 0x15, 0x66, 0x4B), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0xE2, 0x24, 0x04, 0x72, 0x39, 0xA0, 0x7C), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_4_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2B, 0x51, 0xA2, 0x58, 0x88, 0x62, 0xE1, 0x02), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0xD2, 0x65, 0x14, 0xE9, 0x4C, 0x82, 0x30), + MBEDTLS_BYTES_TO_T_UINT_8(0xDC, 0xE1, 0xAC, 0x87, 0xAE, 0x31, 0x1A, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0x85, 0x4F, 0x96, 0x1E, 0x85, 0x7A, 0xC3, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0x86, 0xBB, 0xF0, 0xC0, 0x9D, 0x08, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0xBD, 0x53, 0x03, 0x09, 0x80, 0x91, 0xEF, 0x68), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_5_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0xD7, 0xAF, 0x6F, 0x69, 0x7B, 0x88, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0x13, 0xE4, 0x30, 0xA2, 0x47, 0xB5, 0xC1), + MBEDTLS_BYTES_TO_T_UINT_8(0x0F, 0xD2, 0xC0, 0xDD, 0x8A, 0x1C, 0x3C, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0xF9, 0x8C, 0xB3, 0x4C, 0xBA, 0x8B, 0x6D, 0xCF), + MBEDTLS_BYTES_TO_T_UINT_8(0x6B, 0xC7, 0xA1, 0xA8, 0x6E, 0x3C, 0x4F, 0xF1), + MBEDTLS_BYTES_TO_T_UINT_8(0x94, 0x4A, 0x97, 0xC8, 0x03, 0x6F, 0x01, 0x82), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_5_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0x18, 0x12, 0xA9, 0x39, 0xD5, 0x22, 0x26), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0xA7, 0xC0, 0xBD, 0x9D, 0x8D, 0x78, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0xA9, 0xB3, 0xD0, 0x7F, 0xDF, 0xD0, 0x30, 0xDE), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x25, 0x73, 0x96, 0xEC, 0xA8, 0x1D, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0xD1, 0x65, 0x66, 0xDC, 0xD9, 0xCF, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0xED, 0x7B, 0x37, 0xAD, 0xE2, 0xBE, 0x2D), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_6_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x79, 0x42, 0x6A, 0x07, 0x66, 0xB1, 0xBD), + MBEDTLS_BYTES_TO_T_UINT_8(0x45, 0x53, 0x62, 0x65, 0x92, 0x09, 0x4C, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0x06, 0xAF, 0xC3, 0x03, 0xF6, 0xF4, 0x2D, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0xCA, 0x41, 0xD9, 0xA2, 0x69, 0x9B, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0x4B, 0xB2, 0xA6, 0x8D, 0xE1, 0xAA, 0x61, 0x76), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0xBA, 0x4D, 0x12, 0xB6, 0xBE, 0xF3, 0x7E), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_6_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0xD9, 0x92, 0x22, 0x07, 0xCE, 0xC9, 0x26), + MBEDTLS_BYTES_TO_T_UINT_8(0x62, 0xA1, 0x7C, 0x91, 0xDB, 0x32, 0xF7, 0xE5), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x49, 0x4B, 0x6D, 0xFB, 0xD9, 0x70, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0xFB, 0x4E, 0x4C, 0x5E, 0x66, 0x81, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0xA5, 0xB3, 0xE1, 0x00, 0xB7, 0xD9, 0xCC, 0x58), + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0x36, 0x8B, 0xC4, 0x39, 0x20, 0xFD, 0x30), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_7_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x94, 0x1F, 0x60, 0x03, 0xBB, 0xD7, 0x60, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0x3C, 0x62, 0xDD, 0x71, 0x95, 0xE9, 0x61), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x5B, 0x7A, 0x5F, 0x68, 0x81, 0xC5, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xAF, 0xB5, 0xB9, 0x98, 0x42, 0x28, 0xA5), + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0x29, 0x8E, 0x11, 0x49, 0xB4, 0xD7, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x3E, 0xD2, 0x30, 0xA1, 0xBA, 0xCA, 0x03), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_7_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0x37, 0x64, 0x44, 0x2F, 0x03, 0xE5, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0x4A, 0x42, 0xBC, 0xFF, 0xA2, 0x1A, 0x5F, 0x06), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x04, 0xAB, 0x04, 0xE0, 0x24, 0xAD, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0x45, 0x17, 0x67, 0x1F, 0x3E, 0x53, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0x0F, 0xB3, 0x1B, 0x57, 0x54, 0xC2, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0xD3, 0xF8, 0xC4, 0x1B, 0x9B, 0xFA, 0x30), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_8_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x90, 0xFD, 0xFB, 0xCA, 0x49, 0x38, 0x4E), + MBEDTLS_BYTES_TO_T_UINT_8(0xC3, 0xCF, 0xC6, 0xDD, 0xF0, 0xFF, 0x8C, 0x11), + MBEDTLS_BYTES_TO_T_UINT_8(0xD7, 0x69, 0x9D, 0xBD, 0x5F, 0x33, 0xE9, 0xB4), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0x19, 0x82, 0x3D, 0xAC, 0x1C, 0x40, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0xC7, 0x02, 0x46, 0x14, 0x77, 0x00, 0xBE), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x05, 0xF2, 0x77, 0x3A, 0x66, 0x5C, 0x39), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_8_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xE6, 0x17, 0xDE, 0xB2, 0xA1, 0xE5, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0x71, 0xEC, 0x9D, 0xD8, 0xF5, 0xD4, 0x66), + MBEDTLS_BYTES_TO_T_UINT_8(0xAA, 0xC6, 0x42, 0x5E, 0xE7, 0x18, 0xBA, 0xD0), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0x21, 0x68, 0x5A, 0x26, 0xFB, 0xD7, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x00, 0x5C, 0xBA, 0x8A, 0x34, 0xEC, 0x75), + MBEDTLS_BYTES_TO_T_UINT_8(0xC3, 0x9C, 0x3C, 0xAF, 0x53, 0xE8, 0x65, 0x35), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_9_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0xEF, 0x28, 0xDC, 0x67, 0x05, 0xC8, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0x78, 0xC3, 0x85, 0x49, 0xA0, 0xBC, 0x0F), + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0x3E, 0x2D, 0xA0, 0xCF, 0xD4, 0x7A, 0xF5), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0x93, 0xFE, 0x60, 0xB3, 0x6E, 0x99, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0x62, 0xAD, 0x04, 0xE7, 0x49, 0xAF, 0x5E, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0x54, 0x7A, 0xED, 0xA6, 0x9E, 0x18, 0x09, 0x31), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_9_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x05, 0x94, 0x44, 0xDC, 0xB8, 0x85, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0x14, 0xB7, 0x37, 0xC2, 0x50, 0x75, 0x15, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0xC6, 0x0F, 0xB2, 0xA9, 0x91, 0x3E, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0x81, 0xAD, 0x25, 0xA1, 0x26, 0x73, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0xF1, 0xD1, 0x61, 0x7C, 0x76, 0x8F, 0x13), + MBEDTLS_BYTES_TO_T_UINT_8(0x06, 0xDB, 0x4A, 0xFF, 0x14, 0xA7, 0x48, 0x0B), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_10_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0x73, 0xC6, 0xC2, 0xCC, 0xF1, 0x57, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0xED, 0x73, 0x27, 0x70, 0x82, 0xB6, 0x5E), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0xBA, 0xAC, 0x3A, 0xCF, 0xF4, 0xEA, 0xA6), + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0xD6, 0xB1, 0x8F, 0x0E, 0x08, 0x2C, 0x5E), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0xE3, 0x8F, 0x2F, 0x0E, 0xA1, 0xF3, 0x07), + MBEDTLS_BYTES_TO_T_UINT_8(0x1A, 0xF5, 0x7C, 0x9B, 0x29, 0x0A, 0xF6, 0x28), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_10_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBD, 0xEE, 0x17, 0x47, 0x34, 0x15, 0xA3, 0xAF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFB, 0xBE, 0x88, 0x48, 0xE7, 0xA2, 0xBB, 0xDE), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0xAD, 0xDC, 0x65, 0x61, 0x37, 0x0F, 0xC1), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x67, 0xAD, 0xA2, 0x3A, 0x1C, 0x91, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0x07, 0x0C, 0x3A, 0x41, 0x6E, 0x13, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x73, 0xBD, 0x7E, 0xED, 0xAA, 0x14, 0xDD, 0x61), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_11_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC3, 0xDC, 0x20, 0x01, 0x72, 0x11, 0x48, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xC4, 0x7B, 0xF8, 0x62, 0x3D, 0xF0, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0xC2, 0x3D, 0x2E, 0x52, 0xA3, 0x4A, 0x89), + MBEDTLS_BYTES_TO_T_UINT_8(0xCE, 0xE2, 0x53, 0x46, 0x5E, 0x21, 0xF8, 0xCE), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0xC7, 0x8F, 0xA9, 0x26, 0x42, 0x32, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0xFB, 0xA6, 0xA0, 0x8D, 0x4B, 0x9A, 0x19, 0x03), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_11_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0xAB, 0x6D, 0x1E, 0xFB, 0xEE, 0x60, 0x0C), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x56, 0x3C, 0xC5, 0x5D, 0x10, 0x79, 0x1C), + MBEDTLS_BYTES_TO_T_UINT_8(0x25, 0xBC, 0x41, 0x9F, 0x71, 0xEF, 0x02, 0xF9), + MBEDTLS_BYTES_TO_T_UINT_8(0xA2, 0x36, 0xC4, 0xD0, 0x88, 0x9B, 0x32, 0xFC), + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0xD4, 0x5D, 0x17, 0x39, 0xE6, 0x22, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0x26, 0x01, 0xCE, 0xBE, 0x4A, 0x9C, 0x27), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_12_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0x6D, 0x11, 0xCA, 0x6C, 0x5A, 0x93, 0x0C), + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0x96, 0x26, 0xAF, 0x2F, 0xE4, 0x30, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0x35, 0xC1, 0x4C, 0xC6, 0x30, 0x1F, 0x5C, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0xB3, 0xE8, 0xFC, 0x35, 0xEB, 0x63, 0x6C), + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0x1D, 0xCA, 0xFC, 0x50, 0x36, 0x4B, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0x0E, 0x23, 0x5B, 0xAF, 0xEB, 0x2D, 0x31), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_12_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0x88, 0xB6, 0xD7, 0x74, 0x4A, 0x23, 0xB6), + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0x66, 0xE2, 0xBB, 0x29, 0xA6, 0x4F, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0x6F, 0x7E, 0x68, 0x6E, 0xA0, 0x14, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0x3B, 0x73, 0xD4, 0xE8, 0xAB, 0x5B, 0xF6, 0x0D), + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0xE0, 0x3C, 0x24, 0x00, 0x95, 0xE9, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x0D, 0x4F, 0x81, 0xD0, 0xF2, 0x3F, 0x00), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_13_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0x1D, 0xCD, 0x78, 0x39, 0xC4, 0x6B, 0xD9), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0x45, 0xC7, 0xB8, 0x2F, 0xAA, 0x5D, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0x33, 0x8C, 0x6E, 0xA3, 0x24, 0xB2, 0xDB, 0x4B), + MBEDTLS_BYTES_TO_T_UINT_8(0x69, 0x2D, 0xD9, 0xF1, 0xC7, 0x9B, 0x8A, 0xAF), + MBEDTLS_BYTES_TO_T_UINT_8(0x67, 0xE1, 0x2C, 0xB9, 0x40, 0x37, 0x91, 0x75), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0x2C, 0xB5, 0x23, 0x03, 0x2B, 0xAF, 0x2F), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_13_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0x9D, 0x5A, 0x20, 0x10, 0xA9, 0x84, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0x30, 0x89, 0x20, 0x13, 0xE9, 0xB2, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x6E, 0x52, 0xEB, 0x03, 0x18, 0x1F, 0xA6), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x9E, 0x1C, 0x35, 0x87, 0x92, 0x69, 0xC7), + MBEDTLS_BYTES_TO_T_UINT_8(0xA1, 0xC9, 0x88, 0xAF, 0xC6, 0x6C, 0x83, 0x72), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0xD5, 0x7A, 0x54, 0x34, 0x99, 0xB6, 0x6F), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_14_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xDF, 0xAD, 0x45, 0x9B, 0x4B, 0x41, 0x4D, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x1B, 0x5D, 0xAB, 0x7F, 0x35, 0x34, 0xE9, 0x29), + MBEDTLS_BYTES_TO_T_UINT_8(0x73, 0xBE, 0x78, 0x34, 0x44, 0xF3, 0x4A, 0x87), + MBEDTLS_BYTES_TO_T_UINT_8(0xFB, 0xDE, 0xE3, 0xC4, 0xEE, 0x0B, 0xF9, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0x86, 0x16, 0x48, 0x32, 0xB8, 0x74, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0xEE, 0x7C, 0xBA, 0xBD, 0x81, 0xE3, 0x55), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_14_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0x6A, 0xFA, 0x84, 0xDA, 0xB8, 0xD5, 0x14), + MBEDTLS_BYTES_TO_T_UINT_8(0xB2, 0x9F, 0x8A, 0xD5, 0x1B, 0x2E, 0x1A, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x0C, 0x61, 0xE2, 0xFF, 0x5B, 0xE6, 0xD5), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0x62, 0xC1, 0x87, 0x53, 0x1B, 0x92, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0x54, 0x90, 0x00, 0xD1, 0x6A, 0x0C, 0x0E, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x8B, 0x2E, 0xB5, 0x3B, 0x44, 0xB5, 0xA0, 0x78), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_15_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0x5D, 0x02, 0x58, 0xB5, 0xBE, 0x45, 0x14), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0xEF, 0x8E, 0x90, 0x4D, 0x2A, 0x32, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0x48, 0x99, 0x75, 0x5C, 0x0A, 0x33, 0x8F, 0x36), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0x6C, 0x95, 0xD4, 0x1F, 0xF3, 0xEB, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0xE4, 0x4C, 0x91, 0x20, 0xF3, 0x25, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x95, 0xEB, 0x29, 0x6F, 0x20, 0x34, 0x81), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_15_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0x15, 0xE5, 0x13, 0x7E, 0x64, 0x8B, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0xBC, 0x0D, 0x18, 0x7E, 0x37, 0x9E, 0xFA), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x82, 0x20, 0xF7, 0x2D, 0x7A, 0x77, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x29, 0xA2, 0xDB, 0x7A, 0xE6, 0x6F, 0xA5), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0xC6, 0x50, 0x5C, 0xBC, 0xE6, 0x4F, 0xBD), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0x9F, 0xD5, 0xE8, 0xC5, 0x3D, 0xB7, 0x30), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_16_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x45, 0x03, 0x55, 0x10, 0xDB, 0xA6, 0x8B, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0x4E, 0x17, 0xAE, 0x78, 0xC9, 0x1D, 0x43, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0x4E, 0x35, 0x49, 0xD4, 0x47, 0x84, 0x8D, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0x95, 0x2F, 0xEA, 0xBC, 0xB4, 0x18, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0x48, 0xAE, 0x89, 0xF5, 0x65, 0x3D, 0x89), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0xF2, 0x2B, 0x20, 0xD1, 0x75, 0x50, 0x63), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_16_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0xE6, 0x5C, 0x2C, 0xE0, 0x7D, 0xDF, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0x07, 0x3E, 0xCE, 0x9F, 0x18, 0xB6, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0x9A, 0xF8, 0xF0, 0xD5, 0xFA, 0x42, 0x1D, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0x6C, 0x1D, 0x03, 0xC9, 0x0E, 0x2B, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x43, 0x18, 0x52, 0xA5, 0xB4, 0x63, 0xE1, 0x06), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0x0A, 0xD9, 0xC4, 0xFD, 0x16, 0x60, 0x54), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_17_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x43, 0x7D, 0xDE, 0xDF, 0x4B, 0x4A, 0xB0, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x4E, 0x8C, 0x94, 0xC1, 0xE2, 0x85, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0xF0, 0xEA, 0xB5, 0x9B, 0x70, 0xEF, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0x56, 0xC2, 0x39, 0x5D, 0xF3, 0x2C, 0xD9, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x0D, 0x1C, 0x2E, 0xCC, 0x2F, 0x54, 0x87, 0x80), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x72, 0xC7, 0xB5, 0x50, 0xA3, 0x84, 0x77), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_17_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0xD1, 0xAF, 0xA9, 0xB4, 0x8B, 0x5D, 0xFA), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0xF6, 0x52, 0x8A, 0xC3, 0x56, 0xA5, 0x5E), + MBEDTLS_BYTES_TO_T_UINT_8(0x3B, 0x52, 0xFF, 0xEA, 0x05, 0x42, 0x77, 0x83), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0x08, 0x90, 0x72, 0x86, 0xC4, 0xC3, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0x4D, 0x15, 0xF8, 0xF1, 0x16, 0x67, 0xC6, 0xD5), + MBEDTLS_BYTES_TO_T_UINT_8(0x75, 0x87, 0xAC, 0x8F, 0x71, 0xEC, 0x83, 0x81), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_18_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0xE1, 0xE6, 0x2D, 0x0E, 0x11, 0xA1, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0xE2, 0xA8, 0x32, 0xE6, 0xE3, 0x83, 0xD1), + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x56, 0xE5, 0xCD, 0xB7, 0x2B, 0x67, 0x6F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE5, 0xED, 0xC9, 0x65, 0x6D, 0x87, 0xE1, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x8E, 0xFD, 0x9A, 0x53, 0x0E, 0xFA, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0x49, 0x4C, 0x4A, 0xE2, 0x23, 0x84, 0xFA, 0x01), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_18_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0xFE, 0x49, 0x81, 0xD1, 0x3E, 0xF4, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0x45, 0x72, 0xE0, 0xEF, 0x0D, 0xB8, 0x3E, 0x6F), + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0x00, 0x0F, 0x5F, 0xCE, 0x60, 0x72, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0xCC, 0xD8, 0x03, 0x07, 0x6E, 0x5A, 0xCD), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0x3A, 0x35, 0x50, 0x4E, 0x1F, 0xCA, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0xEA, 0x88, 0x55, 0xBD, 0x6E, 0x05, 0x7F), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_19_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB1, 0x6D, 0xF1, 0x97, 0xA6, 0x69, 0x39, 0x24), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0x41, 0x99, 0xFF, 0x3B, 0xA1, 0x26, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0x2F, 0x95, 0x80, 0x12, 0x4A, 0x1B, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0xBF, 0x51, 0xAA, 0xAE, 0x2D, 0xDA, 0xCF), + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0x1C, 0xB3, 0x52, 0x36, 0x49, 0xD4, 0x86), + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0xC1, 0x1F, 0x3A, 0xD3, 0x3E, 0x5C, 0x1A), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_19_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x73, 0x51, 0xF7, 0x2B, 0xC8, 0xA9, 0xA7, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0x12, 0x4E, 0x7F, 0x98, 0x41, 0x66, 0xB0, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0x1D, 0xC0, 0x42, 0xCD, 0xF8, 0xC3, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0xCC, 0x41, 0x91, 0x7D, 0xCC, 0x8B, 0xCC, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0xAE, 0x76, 0xED, 0x56, 0x18, 0xC5, 0xAB), + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0x6A, 0x06, 0xA3, 0x7F, 0x65, 0x10, 0x1F), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_20_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0xEC, 0x3C, 0x05, 0x05, 0xCA, 0xF6, 0xED), + MBEDTLS_BYTES_TO_T_UINT_8(0x48, 0xCD, 0x02, 0x51, 0x12, 0x16, 0x3C, 0x63), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0xEB, 0xB3, 0x43, 0x7B, 0xDD, 0xB2, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x59, 0x90, 0x41, 0xDB, 0xE4, 0xF5, 0x91), + MBEDTLS_BYTES_TO_T_UINT_8(0xD0, 0x0E, 0x18, 0x2A, 0x5A, 0x83, 0x7C, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE1, 0x37, 0xA1, 0x0D, 0xF1, 0x2F, 0x63, 0x79), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_20_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0xC0, 0xFA, 0x6F, 0x1F, 0x67, 0xCF, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x34, 0x45, 0xBB, 0xF4, 0xF9, 0x9B, 0x89), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0x69, 0xFE, 0x67, 0x1D, 0x64, 0x8F, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x39, 0xBF, 0xD8, 0xB3, 0xC7, 0xAD, 0x8A), + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0x93, 0xFF, 0xF3, 0x28, 0xFA, 0x39, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0xF9, 0xC3, 0x85, 0x26, 0x7A, 0x88, 0x89), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_21_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x4D, 0xD5, 0x79, 0xD8, 0x11, 0xDE, 0xEB, 0x4E), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x46, 0xA4, 0x6A, 0xDA, 0x74, 0x34, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xBD, 0xD3, 0xF5, 0x14, 0xEE, 0xFE, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x4C, 0xA3, 0x71, 0x43, 0x65, 0xF8, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0x6C, 0x35, 0xFA, 0x90, 0x25, 0xD8, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0x34, 0x84, 0x96, 0xA1, 0x43, 0x03, 0x4D), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_21_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x3B, 0x3B, 0x2F, 0xCA, 0x59, 0xF2, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0x48, 0x24, 0x74, 0xD8, 0x72, 0x90, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x42, 0x74, 0x8C, 0x6F, 0x52, 0x19, 0x3D), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0x9E, 0x41, 0x63, 0x68, 0x78, 0x4C, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x53, 0x94, 0xB6, 0x6B, 0x38, 0x52, 0xA8, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0x30, 0x25, 0x93, 0xA1, 0x6F, 0x6E, 0x68), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_22_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x2F, 0x4B, 0x64, 0x79, 0x50, 0xFF, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0x36, 0xED, 0x57, 0x39, 0x3B, 0xE7, 0xF3), + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x85, 0xEA, 0x35, 0xD6, 0xC0, 0xA0, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x89, 0x3A, 0xCC, 0x22, 0x1C, 0x46, 0x02), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x7A, 0xB0, 0xA1, 0x1B, 0x69, 0x62, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0xB8, 0x8A, 0x6C, 0x18, 0x85, 0x0D, 0x88), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_22_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0xB6, 0x50, 0xE9, 0x4E, 0x7F, 0xE8, 0x07), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x5B, 0x5C, 0xD1, 0x4B, 0x11, 0x9A, 0xD8), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0x25, 0x56, 0x74, 0x51, 0x9C, 0xEC, 0x9C), + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0x7F, 0xB6, 0x8A, 0xCB, 0x3A, 0x10, 0x6A), + MBEDTLS_BYTES_TO_T_UINT_8(0x60, 0x33, 0x07, 0x01, 0xE9, 0x49, 0x59, 0xE6), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0xA5, 0x2E, 0xF2, 0xBA, 0x32, 0x63, 0x44), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_23_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0x06, 0x0B, 0xA5, 0x44, 0x27, 0x7F, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0x74, 0xAC, 0x0F, 0xCC, 0x4F, 0x13, 0x61), + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0xB1, 0xBF, 0x97, 0x49, 0xA5, 0x1C, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0x64, 0x68, 0x7B, 0x0F, 0xCC, 0x77, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0x39, 0xF9, 0x4E, 0x84, 0x9C, 0xF6, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0xCF, 0x6D, 0xE2, 0xA1, 0x2D, 0xF9, 0x2B), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_23_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0xC4, 0x90, 0x57, 0x31, 0x01, 0x05, 0x5E), + MBEDTLS_BYTES_TO_T_UINT_8(0xCC, 0x1E, 0xBB, 0xBF, 0x98, 0xA4, 0x7C, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0x89, 0xE3, 0xA0, 0xB2, 0xCD, 0x39, 0x9A, 0x3F), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x34, 0x60, 0x7A, 0x89, 0x98, 0xB5, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0x20, 0x3D, 0x3A, 0x04, 0x8F, 0x5A, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0xA3, 0x26, 0xB6, 0x49, 0x09, 0x9C, 0x0F, 0x59), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_24_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0x66, 0xD2, 0x38, 0x2A, 0x62, 0x81, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0xC8, 0x20, 0x5E, 0x28, 0xA3, 0x81, 0xA7), + MBEDTLS_BYTES_TO_T_UINT_8(0x20, 0x31, 0xA4, 0xF1, 0xEA, 0x7D, 0x87, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0x8F, 0x2C, 0x99, 0x09, 0x6F, 0x63, 0xEB, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x73, 0x76, 0xDA, 0x1A, 0x06, 0xBE, 0xDE, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0x09, 0x2E, 0x75, 0x39, 0x30, 0x2D, 0x42), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_24_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0x9B, 0xC1, 0x5A, 0x17, 0xC3, 0x8C, 0x31), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0x8D, 0x94, 0x4D, 0x3D, 0xAB, 0x60, 0xD4), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFD, 0x1E, 0x0F, 0x43, 0xAE, 0x9D, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x8E, 0xF2, 0xF3, 0x20, 0x1B, 0xAA, 0xB7, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0x5B, 0xA4, 0xF4, 0x90, 0x3B, 0xE3, 0x71), + MBEDTLS_BYTES_TO_T_UINT_8(0xF7, 0x78, 0x72, 0xBD, 0x65, 0x09, 0x0B, 0x01), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_25_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0x37, 0x2A, 0x6C, 0x16, 0x4F, 0x64, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0xCE, 0xA3, 0x90, 0xB4, 0x9A, 0xBC, 0xF7), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0x38, 0x55, 0x63, 0x1D, 0x3A, 0x6E, 0x18), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0xB4, 0xAA, 0x99, 0x22, 0x45, 0x89, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0x7C, 0x8C, 0xA6, 0x3D, 0xA7, 0x3E, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0x06, 0x42, 0xDC, 0xA6, 0xE3, 0xC6, 0x12), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_25_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0x8C, 0x3D, 0x5D, 0x47, 0x31, 0x7C, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0x85, 0xEE, 0x46, 0x7E, 0x13, 0x04, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0x9E, 0x3C, 0x8B, 0x43, 0x2E, 0x74, 0xF5, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x88, 0x8E, 0x07, 0x29, 0x08, 0x03, 0x26), + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0x9B, 0x89, 0xEB, 0x08, 0xE8, 0x43, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0x07, 0x67, 0xFD, 0xD9, 0x73, 0x6F, 0x18), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_26_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0xEB, 0x21, 0x8D, 0x98, 0x43, 0x74, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0x88, 0xCC, 0x14, 0xD8, 0x08, 0xBB, 0xA6, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0xC4, 0x98, 0xF2, 0x6A, 0x18, 0xC3, 0xDD, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0x38, 0x91, 0xA0, 0x03, 0xF2, 0x04, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x7A, 0xAF, 0xE8, 0xFD, 0xFB, 0x13, 0x70, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0xD0, 0x93, 0x87, 0x98, 0x4A, 0xE0, 0x00, 0x12), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_26_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x97, 0x2E, 0x69, 0x9C, 0xA2, 0x2D, 0x03, 0x3F), + MBEDTLS_BYTES_TO_T_UINT_8(0x79, 0xFE, 0xF3, 0xB9, 0xC1, 0x85, 0x2A, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0xCE, 0xFD, 0x86, 0xB1, 0xCD, 0xBF, 0x41, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0xD8, 0x9A, 0x21, 0xF3, 0xFE, 0xCB, 0xF1), + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0x78, 0x04, 0x60, 0xB7, 0xA9, 0xA2, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x1E, 0x66, 0x2A, 0x54, 0x51, 0xBD, 0x8B), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_27_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8E, 0x16, 0x36, 0xEF, 0x61, 0x2D, 0xEE, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0x45, 0x5F, 0x88, 0xA0, 0x13, 0x12, 0xF7, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0xA9, 0xC6, 0xAD, 0x4A, 0x4A, 0x07, 0x01, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0x74, 0xB1, 0x4F, 0xEB, 0xBD, 0xD5, 0x6B), + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0xF9, 0x71, 0xA2, 0x06, 0x4F, 0xD7, 0xBC), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0x8B, 0x4D, 0x48, 0xE0, 0x98, 0xFB, 0x6A), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_27_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC4, 0xBA, 0x10, 0xA3, 0x0D, 0x52, 0xAC, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0xD0, 0xE0, 0x36, 0xE6, 0x07, 0x3A, 0x30), + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0x80, 0xF0, 0xAA, 0x49, 0x22, 0x4B, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xC7, 0xAB, 0x1C, 0x89, 0xCD, 0x24, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x82, 0x2A, 0xFC, 0xB3, 0x6D, 0x45, 0x96, 0x49), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0xE4, 0xDB, 0x52, 0x3F, 0xC4, 0xB4, 0x19), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_28_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0xCC, 0xC8, 0x7F, 0xBB, 0x6B, 0x87, 0x47), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0x21, 0x3C, 0x69, 0x7D, 0x38, 0x57, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0x4C, 0x18, 0x3C, 0x53, 0xA5, 0x48, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0xC3, 0x64, 0x45, 0xDB, 0xC4, 0x6D, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0x49, 0xCC, 0xD1, 0xBB, 0x17, 0xB8, 0x34, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x69, 0x71, 0xFA, 0xA0, 0x28, 0x4A, 0x3D), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_28_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0xE8, 0x9E, 0x39, 0xEA, 0x8D, 0x38, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0xCC, 0x9C, 0xBB, 0xCD, 0x80, 0x1A, 0xEE, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0xA0, 0x45, 0xBF, 0xD9, 0x22, 0x11, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x7C, 0x5C, 0xD9, 0xC0, 0x9F, 0x69, 0xF5), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0x8A, 0xA6, 0x79, 0x4E, 0x35, 0xB9, 0xD5), + MBEDTLS_BYTES_TO_T_UINT_8(0xCC, 0x8B, 0x9A, 0x3E, 0xA1, 0xB8, 0x28, 0x10), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_29_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0x2F, 0xEF, 0xBB, 0xA9, 0x72, 0x7F, 0xEA), + MBEDTLS_BYTES_TO_T_UINT_8(0xB5, 0x34, 0xB7, 0x12, 0xB9, 0xE7, 0xC3, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0x1D, 0xD9, 0x42, 0x77, 0x0C, 0x71, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0xEC, 0x01, 0x59, 0xA7, 0x56, 0x03, 0x91, 0x8D), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x91, 0x99, 0x33, 0x30, 0x3E, 0xEF, 0x13), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0xC9, 0x5A, 0x9A, 0x54, 0x66, 0xF1, 0x70), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_29_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x2C, 0xB7, 0x6E, 0x71, 0x7D, 0x35, 0x30), + MBEDTLS_BYTES_TO_T_UINT_8(0x1A, 0x0D, 0xEF, 0xD1, 0x2D, 0x99, 0x63, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0x31, 0xAF, 0x2D, 0xC9, 0xC6, 0xC2, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0xC0, 0xDF, 0x80, 0x54, 0xC4, 0xAC, 0xF3), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x6B, 0xA0, 0x84, 0x96, 0xF7, 0x31, 0xC8), + MBEDTLS_BYTES_TO_T_UINT_8(0x93, 0xE2, 0x7C, 0x7A, 0x41, 0x45, 0x75, 0x6A), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_30_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0xEE, 0x58, 0x31, 0xE8, 0x68, 0xD6, 0x76), + MBEDTLS_BYTES_TO_T_UINT_8(0xD2, 0x2E, 0x48, 0xB7, 0x09, 0x9F, 0xD4, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0xA9, 0x5C, 0xE7, 0x64, 0x43, 0x5D, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0x9E, 0x58, 0x9F, 0x50, 0xAB, 0x68, 0xFF, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0x88, 0x2D, 0xBA, 0x12, 0xBF, 0x8D, 0x7D), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0xDF, 0x6F, 0xB3, 0x75, 0xA4, 0x55, 0x73), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_30_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x17, 0x92, 0x39, 0xB7, 0x13, 0x37, 0x6F), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0x43, 0x71, 0xA7, 0xCA, 0x17, 0x1B, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0xE7, 0xB9, 0xB0, 0x78, 0xEF, 0xA0, 0xDA, 0x83), + MBEDTLS_BYTES_TO_T_UINT_8(0x9A, 0x84, 0xF2, 0x0F, 0x85, 0xA2, 0xB6, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0x65, 0x2E, 0x6E, 0x45, 0xB9, 0x4C, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0xFE, 0x6A, 0x8C, 0x2B, 0x77, 0x96, 0x36, 0x22), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_31_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x7A, 0x13, 0x4A, 0x97, 0x63, 0x02, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0x1E, 0x06, 0x03, 0x8F, 0xB9, 0xEE, 0x64), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0xEE, 0x8B, 0x89, 0xA9, 0x70, 0xDB, 0xCE), + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x7B, 0x81, 0xC9, 0x70, 0x8D, 0x62, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0x75, 0xDA, 0x46, 0xF8, 0xF9, 0x3A, 0xBE, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x9F, 0x9C, 0x7A, 0x97, 0x62, 0xEB, 0xFA, 0x0F), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_31_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB2, 0x03, 0x3D, 0x3C, 0x46, 0x27, 0x9E, 0x65), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0x08, 0x1C, 0xD5, 0x25, 0xAF, 0xE9, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0xFE, 0x69, 0xDC, 0x59, 0xF4, 0x8A, 0x7C, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x9A, 0x7A, 0x99, 0x21, 0x0C, 0x4E, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xCE, 0x85, 0x5F, 0xAC, 0xAA, 0x82, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x57, 0x69, 0x90, 0x76, 0xF3, 0x53, 0x3F), +}; +static const mbedtls_ecp_point brainpoolP384r1_T[32] = { + ECP_POINT_INIT_XY_Z1(brainpoolP384r1_T_0_X, brainpoolP384r1_T_0_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_1_X, brainpoolP384r1_T_1_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_2_X, brainpoolP384r1_T_2_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_3_X, brainpoolP384r1_T_3_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_4_X, brainpoolP384r1_T_4_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_5_X, brainpoolP384r1_T_5_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_6_X, brainpoolP384r1_T_6_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_7_X, brainpoolP384r1_T_7_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_8_X, brainpoolP384r1_T_8_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_9_X, brainpoolP384r1_T_9_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_10_X, brainpoolP384r1_T_10_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_11_X, brainpoolP384r1_T_11_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_12_X, brainpoolP384r1_T_12_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_13_X, brainpoolP384r1_T_13_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_14_X, brainpoolP384r1_T_14_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_15_X, brainpoolP384r1_T_15_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_16_X, brainpoolP384r1_T_16_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_17_X, brainpoolP384r1_T_17_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_18_X, brainpoolP384r1_T_18_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_19_X, brainpoolP384r1_T_19_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_20_X, brainpoolP384r1_T_20_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_21_X, brainpoolP384r1_T_21_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_22_X, brainpoolP384r1_T_22_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_23_X, brainpoolP384r1_T_23_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_24_X, brainpoolP384r1_T_24_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_25_X, brainpoolP384r1_T_25_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_26_X, brainpoolP384r1_T_26_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_27_X, brainpoolP384r1_T_27_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_28_X, brainpoolP384r1_T_28_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_29_X, brainpoolP384r1_T_29_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_30_X, brainpoolP384r1_T_30_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_31_X, brainpoolP384r1_T_31_Y), +}; +#else +#define brainpoolP384r1_T NULL +#endif + +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ + +/* + * Domain parameters for brainpoolP512r1 (RFC 5639 3.7) + */ +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP512r1_p[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0x48, 0x3A, 0x58, 0x56, 0x60, 0xAA, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x85, 0xC6, 0x82, 0x2D, 0x2F, 0xFF, 0x81, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0x80, 0xA3, 0xE6, 0x2A, 0xA1, 0xCD, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0x68, 0xC6, 0x9B, 0x00, 0x9B, 0x4D, 0x7D), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F), + MBEDTLS_BYTES_TO_T_UINT_8(0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA), +}; +static const mbedtls_mpi_uint brainpoolP512r1_a[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0x94, 0xFC, 0x77, 0x4D, 0xAC, 0xC1, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0xC7, 0xF2, 0x2B, 0xA7, 0x17, 0x11, 0x7F), + MBEDTLS_BYTES_TO_T_UINT_8(0xB5, 0xC8, 0x9A, 0x8B, 0xC9, 0xF1, 0x2E, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0xA1, 0x3A, 0x25, 0xA8, 0x5A, 0x5D, 0xED, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0x63, 0x98, 0xEA, 0xCA, 0x41, 0x34, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0x16, 0xF9, 0x3D, 0x8D, 0xDD, 0xCB, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0x4C, 0x23, 0xAC, 0x45, 0x71, 0x32, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0x89, 0x3B, 0x60, 0x8B, 0x31, 0xA3, 0x30, 0x78), +}; +static const mbedtls_mpi_uint brainpoolP512r1_b[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x23, 0xF7, 0x16, 0x80, 0x63, 0xBD, 0x09, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0xE5, 0xBA, 0x5E, 0xB7, 0x50, 0x40, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0x67, 0x3E, 0x08, 0xDC, 0xCA, 0x94, 0xFC, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0x4D, 0xAC, 0xC1, 0xE7, 0xB9, 0xC7, 0xF2, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0x17, 0x11, 0x7F, 0xB5, 0xC8, 0x9A, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0xF1, 0x2E, 0x0A, 0xA1, 0x3A, 0x25, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x5D, 0xED, 0x2D, 0xBC, 0x63, 0x98, 0xEA), + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0x41, 0x34, 0xA8, 0x10, 0x16, 0xF9, 0x3D), +}; +static const mbedtls_mpi_uint brainpoolP512r1_gx[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x22, 0xF8, 0xB9, 0xBC, 0x09, 0x22, 0x35, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x5E, 0x6A, 0x40, 0x47, 0x50, 0x6D, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x7D, 0xB9, 0x93, 0x7B, 0x68, 0xD1, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xD4, 0xD0, 0xE2, 0x78, 0x1F, 0x3B, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0x8E, 0x09, 0xD0, 0xF4, 0xEE, 0x62, 0x3B, 0xB4), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0x16, 0xD9, 0xB5, 0x70, 0x9F, 0xED, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0x93, 0x6A, 0x4C, 0x9C, 0x2E, 0x32, 0x21, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0xD9, 0x2E, 0xD8, 0xBD, 0xE4, 0xAE, 0x81), +}; +static const mbedtls_mpi_uint brainpoolP512r1_gy[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x08, 0xD8, 0x3A, 0x0F, 0x1E, 0xCD, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0x06, 0x54, 0xF0, 0xA8, 0x2F, 0x2B, 0xCA, 0xD1), + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0x63, 0x27, 0x8A, 0xD8, 0x4B, 0xCA, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0x48, 0x5F, 0x4A, 0x49, 0xDE, 0xDC, 0xB2), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0x81, 0x1F, 0x88, 0x5B, 0xC5, 0x00, 0xA0), + MBEDTLS_BYTES_TO_T_UINT_8(0x1A, 0x7B, 0xA5, 0x24, 0x00, 0xF7, 0x09, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0x22, 0x78, 0xCF, 0xA9, 0xBF, 0xEA, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0xEC, 0x32, 0x63, 0x56, 0x5D, 0x38, 0xDE, 0x7D), +}; +static const mbedtls_mpi_uint brainpoolP512r1_n[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x69, 0x00, 0xA9, 0x9C, 0x82, 0x96, 0x87, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0xDA, 0x5D, 0x08, 0x81, 0xD3, 0xB1, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0x10, 0xAC, 0x7F, 0x19, 0x61, 0x86, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x26, 0xA9, 0x4C, 0x41, 0x5C, 0x3E, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F), + MBEDTLS_BYTES_TO_T_UINT_8(0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA), +}; + +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 +static const mbedtls_mpi_uint brainpoolP512r1_T_0_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x22, 0xF8, 0xB9, 0xBC, 0x09, 0x22, 0x35, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x5E, 0x6A, 0x40, 0x47, 0x50, 0x6D, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x7D, 0xB9, 0x93, 0x7B, 0x68, 0xD1, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xD4, 0xD0, 0xE2, 0x78, 0x1F, 0x3B, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0x8E, 0x09, 0xD0, 0xF4, 0xEE, 0x62, 0x3B, 0xB4), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0x16, 0xD9, 0xB5, 0x70, 0x9F, 0xED, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0x93, 0x6A, 0x4C, 0x9C, 0x2E, 0x32, 0x21, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0xD9, 0x2E, 0xD8, 0xBD, 0xE4, 0xAE, 0x81), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_0_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x08, 0xD8, 0x3A, 0x0F, 0x1E, 0xCD, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0x06, 0x54, 0xF0, 0xA8, 0x2F, 0x2B, 0xCA, 0xD1), + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0x63, 0x27, 0x8A, 0xD8, 0x4B, 0xCA, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0x48, 0x5F, 0x4A, 0x49, 0xDE, 0xDC, 0xB2), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0x81, 0x1F, 0x88, 0x5B, 0xC5, 0x00, 0xA0), + MBEDTLS_BYTES_TO_T_UINT_8(0x1A, 0x7B, 0xA5, 0x24, 0x00, 0xF7, 0x09, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0x22, 0x78, 0xCF, 0xA9, 0xBF, 0xEA, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0xEC, 0x32, 0x63, 0x56, 0x5D, 0x38, 0xDE, 0x7D), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_1_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0xE9, 0x6B, 0x8C, 0x6F, 0x9D, 0x88, 0x43), + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0x4F, 0x86, 0x96, 0xA7, 0x56, 0xD1, 0x37), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0xAB, 0xFA, 0xEE, 0xA7, 0xF5, 0x0E, 0xA6), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x40, 0xEF, 0x9E, 0x6D, 0xD6, 0x32, 0x33), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0xED, 0x56, 0x14, 0x57, 0x1A, 0x8D, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0xED, 0x4D, 0x3A, 0xFA, 0x71, 0x75, 0x6B), + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0xC5, 0x76, 0x1C, 0x14, 0xBE, 0xB5, 0xCD), + MBEDTLS_BYTES_TO_T_UINT_8(0xE1, 0x5A, 0xCB, 0xE7, 0x36, 0x1D, 0x52, 0x1C), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_1_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6B, 0x8D, 0x7A, 0xEB, 0xA3, 0x8B, 0xD5, 0xB0), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0xA3, 0x41, 0xF8, 0xAC, 0x9E, 0xAB, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0x12, 0xE3, 0x65, 0x0D, 0x1C, 0xFE, 0x09, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0xCA, 0x13, 0x3F, 0xC5, 0xF9, 0x7E, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0x2C, 0x5D, 0x63, 0x28, 0xA6, 0x89, 0xD3, 0x91), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x95, 0x3F, 0x7A, 0x82, 0xD4, 0x77, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0xBB, 0x92, 0x32, 0x00, 0xF4, 0x66, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x58, 0x31, 0xD1, 0x17, 0x9F, 0x2A, 0x22), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_2_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0x36, 0xA9, 0xCD, 0x80, 0xA5, 0x2D, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0x44, 0xAB, 0xCE, 0x71, 0xFF, 0x0C, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0x24, 0x58, 0x35, 0x5A, 0x21, 0x32, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0x1B, 0xA6, 0x28, 0xF8, 0x7A, 0x97, 0xAE, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0x84, 0xE7, 0x08, 0xFA, 0x47, 0xC9, 0x55, 0x09), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xAC, 0x2E, 0x84, 0xA4, 0xF5, 0x52, 0xC4), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x58, 0x05, 0x9D, 0xA7, 0xC8, 0x71, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0xB3, 0x92, 0xB4, 0x92, 0xC1, 0x92, 0xEC, 0x6B), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_2_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x4A, 0x48, 0x2D, 0x79, 0x5E, 0x58, 0xE5, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x85, 0x26, 0xEC, 0xE9, 0x6E, 0xD4, 0x06), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x68, 0x26, 0x87, 0x38, 0xA2, 0xD2, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0xF7, 0x17, 0x60, 0xCE, 0x75, 0xF8, 0xA5, 0x6F), + MBEDTLS_BYTES_TO_T_UINT_8(0x20, 0x51, 0xDB, 0xA9, 0xAE, 0x87, 0xF1, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x49, 0x92, 0x3B, 0x19, 0x96, 0xF5, 0xB0), + MBEDTLS_BYTES_TO_T_UINT_8(0xC4, 0xD5, 0x52, 0x52, 0x8C, 0xCE, 0xFD, 0xFA), + MBEDTLS_BYTES_TO_T_UINT_8(0x24, 0x18, 0x0A, 0xE6, 0xF6, 0xAE, 0x08, 0x41), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_3_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0x2B, 0xD8, 0x54, 0xCE, 0xB0, 0x57, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0xB0, 0xF8, 0x9E, 0x03, 0x03, 0x3C, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x93, 0x0E, 0x29, 0x29, 0x00, 0xF3, 0x70, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0x54, 0x33, 0x99, 0x0E, 0x00, 0x5D, 0xFE, 0x4B), + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0x2D, 0xF2, 0x59, 0x32, 0xCF, 0x03, 0xF4), + MBEDTLS_BYTES_TO_T_UINT_8(0x3B, 0xC9, 0x72, 0xAE, 0x0C, 0xEF, 0xD1, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x5A, 0x27, 0xBF, 0x2F, 0x45, 0xF9, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0xBE, 0xE5, 0x2C, 0xFF, 0x5B, 0x1E, 0x88), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_3_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xAA, 0xAC, 0xBB, 0xD8, 0x83, 0xC2, 0x46, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0xCF, 0xDC, 0xCE, 0x15, 0xB4, 0xEF, 0xCF, 0x46), + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0xDB, 0x5E, 0x94, 0x31, 0x0B, 0xB2, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0xB9, 0xE3, 0xE3, 0x11, 0x71, 0x41, 0x1E), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0xE3, 0x01, 0xB7, 0x7D, 0xBC, 0x65, 0xBE), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x07, 0x65, 0x87, 0xA7, 0xE8, 0x48, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0x48, 0x8F, 0xD4, 0x30, 0x8E, 0xB4, 0x6C), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0xE0, 0x73, 0xBE, 0x1E, 0xBF, 0x56, 0x36), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_4_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFE, 0x0E, 0x5E, 0x87, 0xC5, 0xAB, 0x0E, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0xF9, 0x5F, 0x80, 0x24, 0x4C, 0x2A, 0xF1), + MBEDTLS_BYTES_TO_T_UINT_8(0xDE, 0x15, 0x21, 0x54, 0x92, 0x84, 0x8D, 0x6A), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0x8A, 0x47, 0x74, 0xDC, 0x42, 0xB1, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0xF7, 0x30, 0xFD, 0xC1, 0x9B, 0x0C, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x4E, 0x6C, 0xCC, 0xDF, 0xC5, 0xE3, 0xA9, 0xD5), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0x67, 0x59, 0x10, 0x5C, 0x51, 0x54, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x37, 0xFB, 0x6E, 0xB0, 0x78, 0x63, 0x8E), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_4_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA5, 0xEF, 0xC4, 0x39, 0x20, 0xF1, 0x46, 0x66), + MBEDTLS_BYTES_TO_T_UINT_8(0xE2, 0x62, 0xAE, 0xFF, 0x10, 0xE4, 0xE2, 0xE9), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0x5C, 0xF5, 0x2E, 0x22, 0x89, 0xE5, 0x82), + MBEDTLS_BYTES_TO_T_UINT_8(0x89, 0x0C, 0x29, 0xA8, 0x62, 0xAE, 0xDB, 0x65), + MBEDTLS_BYTES_TO_T_UINT_8(0xD7, 0x9E, 0x0F, 0xCA, 0x87, 0x2A, 0x6F, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0xCE, 0xDC, 0x9B, 0x9F, 0x65, 0xD4, 0xAD, 0x27), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0xC3, 0x08, 0x0F, 0xCF, 0x67, 0xE9, 0xF4), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x5C, 0xD7, 0xFF, 0x41, 0x9C, 0xCB, 0x26), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_5_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x25, 0x05, 0x12, 0xAD, 0x73, 0x63, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0x99, 0x07, 0x86, 0x57, 0xE7, 0x94, 0xB1), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x4B, 0xA5, 0xBF, 0x18, 0xA9, 0xEF, 0x6A), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x4C, 0xC4, 0x09, 0xF2, 0x2F, 0x0C, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0x3A, 0x04, 0xEA, 0x89, 0x6C, 0x91, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0x7D, 0x6C, 0x3A, 0xE7, 0xA3, 0xEC, 0x24, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0xA1, 0x26, 0x21, 0x04, 0xE3, 0xB9, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x53, 0x71, 0x4B, 0x7B, 0xC2, 0x89, 0xCD, 0xA2), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_5_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0xB9, 0xA8, 0x9D, 0xFD, 0x00, 0x3A, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0x41, 0x6C, 0xBB, 0x5A, 0xCA, 0x1F, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0xD7, 0xE2, 0x6C, 0x6B, 0xA7, 0x48, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0x19, 0xAD, 0xA7, 0xC1, 0x7E, 0x4F, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0xD1, 0xF7, 0x19, 0x3C, 0x06, 0x74, 0x2C, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0x23, 0x4F, 0x0C, 0x09, 0xB0, 0x80, 0x4A), + MBEDTLS_BYTES_TO_T_UINT_8(0x4E, 0x74, 0x34, 0x08, 0x44, 0x7E, 0xA3, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0xFB, 0xCC, 0x8D, 0x12, 0x6E, 0xE1, 0x3D, 0x0B), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_6_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0x18, 0xB1, 0x71, 0x02, 0x93, 0xC2, 0xA4), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x89, 0x40, 0xE2, 0x1F, 0xE7, 0x5E, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x8E, 0xAE, 0x89, 0x01, 0xD4, 0x0C, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0xDA, 0x58, 0x70, 0x24, 0xF2, 0xE4, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0x6F, 0xC7, 0x1D, 0xD6, 0x4A, 0x6F, 0x66, 0x4F), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x1D, 0x7E, 0x4A, 0x2C, 0xCA, 0xEC, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0xA1, 0x06, 0x7F, 0xA8, 0x99, 0xE4, 0xD3, 0x4E), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0x1D, 0x5A, 0xDF, 0x5E, 0x58, 0x36, 0x49), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_6_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0xB9, 0x32, 0x69, 0x1F, 0x72, 0x2A, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x73, 0xE2, 0x03, 0x39, 0x35, 0xAA, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0x5E, 0x5D, 0x48, 0xEF, 0xAE, 0x30, 0xF5), + MBEDTLS_BYTES_TO_T_UINT_8(0x77, 0x7F, 0x60, 0x19, 0xAF, 0xEC, 0x9D, 0xFC), + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0xD9, 0x19, 0xE4, 0x1B, 0x56, 0x15, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0xD7, 0x33, 0x59, 0x1F, 0x43, 0x59, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0xCE, 0xEE, 0xCA, 0xA4, 0x7F, 0x63, 0xD4), + MBEDTLS_BYTES_TO_T_UINT_8(0xBD, 0x40, 0xC0, 0xF6, 0x19, 0x89, 0x43, 0x20), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_7_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0x92, 0xEA, 0x07, 0x65, 0x79, 0x86, 0xD3), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xB7, 0x13, 0x75, 0xD3, 0xC5, 0x0A, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x9E, 0xFA, 0xE1, 0x1F, 0x0C, 0xF9, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x8C, 0xED, 0x5C, 0x21, 0xE9, 0x09, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0xF4, 0x4D, 0xD8, 0x18, 0xC4, 0xF6, 0x36, 0x39), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0xC9, 0xAC, 0x5C, 0xFA, 0x69, 0xA4, 0xA0), + MBEDTLS_BYTES_TO_T_UINT_8(0x6B, 0x8C, 0x94, 0x1C, 0x7B, 0x71, 0x36, 0x58), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0xBD, 0x46, 0xCE, 0xB7, 0x1D, 0x9C, 0x5E), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_7_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0xD6, 0x96, 0x4B, 0xA6, 0x47, 0xEB, 0xE5), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0xF1, 0x5F, 0x15, 0xDE, 0x99, 0x6F, 0x66), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0xBD, 0xE5, 0x04, 0xB8, 0xE6, 0xC0, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0x49, 0xD3, 0xF0, 0x04, 0x00, 0xE4, 0x05, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0xF3, 0x06, 0xA3, 0x1A, 0xFF, 0xEA, 0x73), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0x32, 0xAA, 0x99, 0x33, 0x09, 0xB6, 0x34), + MBEDTLS_BYTES_TO_T_UINT_8(0x6E, 0xEF, 0xFC, 0x61, 0x10, 0x42, 0x31, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0xF1, 0xF4, 0x33, 0xCF, 0x28, 0x90, 0x9C), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_8_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0xDE, 0xF9, 0x88, 0x87, 0x7B, 0xEB, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0xB8, 0xDA, 0xFA, 0xDA, 0x3D, 0xA6, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0xF0, 0x62, 0x82, 0x53, 0x32, 0x55, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0xA5, 0x32, 0x4A, 0x19, 0x11, 0x9C, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0xB3, 0x27, 0xE9, 0x75, 0x90, 0x05, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0x1C, 0x90, 0x48, 0x77, 0x01, 0x85, 0x1B), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0xD6, 0x9B, 0x84, 0xA8, 0xD7, 0xC5, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0xE1, 0x7A, 0xCB, 0xB3, 0x11, 0x46, 0xD7, 0x99), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_8_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8B, 0x23, 0xBF, 0x75, 0x75, 0xA1, 0x95, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0x4B, 0x66, 0x5D, 0x34, 0x13, 0xA9, 0x03, 0xBE), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0x80, 0x9D, 0x5F, 0xD2, 0x44, 0xE1, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0x5D, 0xBD, 0xA8, 0xBF, 0xB4, 0x25, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0x99, 0x1F, 0x53, 0xF1, 0x57, 0xDB, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0x7C, 0xE5, 0xC5, 0x51, 0x0B, 0x4C, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0x6B, 0xB0, 0x1A, 0x9C, 0x16, 0xB0, 0x32, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0xF4, 0xE3, 0xCF, 0xDD, 0x48, 0xB4, 0x7B, 0x33), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_9_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0xDD, 0x9E, 0x3C, 0x98, 0x0E, 0x77, 0x65), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0xAB, 0x01, 0xD3, 0x87, 0x74, 0x25, 0x4A), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0xA3, 0xE3, 0x76, 0x43, 0x87, 0x12, 0xBD), + MBEDTLS_BYTES_TO_T_UINT_8(0x54, 0xB1, 0x3B, 0x60, 0x66, 0xEB, 0x98, 0x54), + MBEDTLS_BYTES_TO_T_UINT_8(0xD2, 0x78, 0xC8, 0xD7, 0x4E, 0x75, 0xCA, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0xDF, 0x71, 0x19, 0xE7, 0x07, 0x36, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0xC9, 0xA8, 0x5F, 0x91, 0xBF, 0x47, 0xB2), + MBEDTLS_BYTES_TO_T_UINT_8(0x80, 0x96, 0x58, 0x96, 0x18, 0xB6, 0xFA, 0x01), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_9_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD0, 0x2D, 0xA9, 0x9B, 0x86, 0xDB, 0x0C, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0x0B, 0x2D, 0x56, 0x4A, 0xD3, 0x93, 0x8A), + MBEDTLS_BYTES_TO_T_UINT_8(0xB5, 0x15, 0xE2, 0x65, 0x12, 0x86, 0x0E, 0xB2), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x41, 0x4D, 0xC1, 0xCB, 0xE4, 0xC3, 0xD7), + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0x53, 0x10, 0xCA, 0xA3, 0xAC, 0x83, 0x26), + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0x01, 0x22, 0x96, 0x10, 0xAD, 0x69, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0x46, 0x4E, 0xD8, 0xEA, 0xD6, 0x9D, 0xF3), + MBEDTLS_BYTES_TO_T_UINT_8(0x43, 0x2F, 0x7F, 0x62, 0x62, 0x80, 0xD0, 0x14), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_10_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB2, 0xDA, 0x00, 0x63, 0x09, 0xBD, 0x6A, 0x83), + MBEDTLS_BYTES_TO_T_UINT_8(0x0F, 0xD4, 0x6E, 0x48, 0x05, 0xB7, 0xF7, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0x14, 0x4D, 0xD7, 0x00, 0x4A, 0x15, 0x27, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0x15, 0xAA, 0x37, 0x27, 0x34, 0x18, 0x24), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0x20, 0x2C, 0x84, 0x1B, 0x88, 0xBA, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x09, 0xD6, 0x04, 0xA2, 0x60, 0x84, 0x72), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0x04, 0x94, 0x08, 0xD4, 0xED, 0x47, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0x8B, 0xF3, 0xE4, 0x3E, 0xB9, 0x5B, 0x35, 0x42), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_10_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0xD8, 0xB6, 0x80, 0xD6, 0xF1, 0x30, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0x14, 0xA6, 0x85, 0xEE, 0xA7, 0xD8, 0x61), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0x49, 0x2A, 0x1E, 0x7C, 0xE9, 0x2D, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0x87, 0x56, 0x91, 0x03, 0x77, 0x4D, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0x52, 0xD4, 0xAA, 0xF7, 0xFA, 0xB0, 0xC5), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x5D, 0x11, 0x39, 0xB1, 0xE7, 0x76, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0x13, 0xBC, 0x37, 0x5D, 0x74, 0xCD, 0xC2), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x48, 0x14, 0x23, 0x30, 0xF8, 0x46, 0x37), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_11_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x27, 0xB0, 0xD9, 0xB2, 0x74, 0xB4, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0xA6, 0xB9, 0x6F, 0x9F, 0x64, 0x36, 0x92), + MBEDTLS_BYTES_TO_T_UINT_8(0x2E, 0x2B, 0x78, 0x40, 0x05, 0x2B, 0x7B, 0xA9), + MBEDTLS_BYTES_TO_T_UINT_8(0xB3, 0x68, 0x3A, 0xB6, 0x4A, 0xE2, 0xDB, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0x33, 0xD7, 0x34, 0x8B, 0x25, 0x45, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0x89, 0xCE, 0xA8, 0xC9, 0x01, 0xFB, 0x0E, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0xE2, 0xF9, 0x51, 0x4C, 0x12, 0x9F, 0x60, 0xE4), + MBEDTLS_BYTES_TO_T_UINT_8(0x67, 0x85, 0xBD, 0x30, 0x37, 0x84, 0x39, 0x44), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_11_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x33, 0xAF, 0x2E, 0xB8, 0x2E, 0xCC, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0xB1, 0x73, 0x59, 0x4E, 0x0C, 0x09, 0x4A), + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0x24, 0x89, 0x81, 0x12, 0xFF, 0xBB, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x37, 0x1A, 0x66, 0xEE, 0xED, 0xB6, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0xBD, 0x04, 0x20, 0x5D, 0xFB, 0xBF, 0x95), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0xF8, 0x34, 0xA3, 0xFF, 0x45, 0xDE, 0x92), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x18, 0x73, 0xF1, 0x32, 0x25, 0x58, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0xC1, 0x14, 0xE3, 0x9E, 0x40, 0x0F, 0x12), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_12_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0x07, 0x9D, 0x9C, 0x00, 0xF7, 0x56, 0x19), + MBEDTLS_BYTES_TO_T_UINT_8(0xFB, 0xBA, 0x87, 0xF9, 0x15, 0x0C, 0x66, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0x1F, 0xC1, 0x28, 0xB0, 0x47, 0x0D, 0xF5), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0xCA, 0x27, 0xEE, 0x4B, 0x23, 0x2B, 0x89), + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0xB5, 0x68, 0xC8, 0x17, 0x5D, 0xC3, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0x02, 0x08, 0xEE, 0x20, 0x9D, 0xEA, 0x64), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0x14, 0x50, 0xD4, 0x7D, 0x5F, 0xCF, 0xA0), + MBEDTLS_BYTES_TO_T_UINT_8(0xD5, 0xFA, 0xF8, 0xA7, 0xC6, 0xDC, 0x14, 0x8C), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_12_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0xBD, 0x0A, 0x1A, 0x18, 0x98, 0xDC, 0xB0), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0x63, 0x02, 0xB7, 0xD5, 0x5B, 0x5A, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0xB1, 0xD7, 0x4B, 0x15, 0x39, 0x61, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0x32, 0xE1, 0x9E, 0x70, 0x1B, 0xCE, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0xD8, 0x18, 0x83, 0x52, 0x9B, 0x6D, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0x55, 0x56, 0x19, 0x34, 0xA4, 0xEA, 0xFC), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0xA9, 0x55, 0x80, 0xE3, 0x15, 0x36, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0x06, 0xC8, 0x1D, 0x17, 0x0D, 0xAD, 0x16), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_13_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x20, 0xD6, 0xF0, 0xCC, 0xF3, 0x63, 0x53, 0xD2), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0x5A, 0xDC, 0x46, 0xBD, 0x0D, 0xAD, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0x2F, 0x11, 0x60, 0x15, 0x51, 0x4A, 0xEA), + MBEDTLS_BYTES_TO_T_UINT_8(0x33, 0xE3, 0x93, 0x38, 0xD5, 0x83, 0xAA, 0x0D), + MBEDTLS_BYTES_TO_T_UINT_8(0x90, 0xA6, 0xCC, 0xB1, 0xFD, 0xBB, 0x1A, 0x0F), + MBEDTLS_BYTES_TO_T_UINT_8(0x3B, 0x54, 0xC8, 0x54, 0x6F, 0x79, 0x1A, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0x4A, 0xDA, 0x28, 0x92, 0x97, 0x9D, 0x7F), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0x4B, 0xDB, 0xC7, 0x52, 0xC5, 0x66, 0x34), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_13_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x05, 0x7E, 0x92, 0x53, 0x30, 0x93, 0xFD, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x16, 0x6A, 0xB1, 0x91, 0x0A, 0xB4, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x9D, 0x40, 0x3F, 0xE3, 0xF1, 0x01, 0x46), + MBEDTLS_BYTES_TO_T_UINT_8(0x13, 0x0E, 0xD8, 0xED, 0x11, 0x8E, 0x4C, 0xED), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0x4A, 0x1B, 0x88, 0xDF, 0x8D, 0x29, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0x97, 0x23, 0x21, 0x11, 0xAB, 0x77, 0x81, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0xAF, 0x11, 0xFA, 0xBA, 0x40, 0x63, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0x2B, 0x6F, 0x8D, 0x80, 0xDF, 0x67, 0xF5, 0x44), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_14_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB2, 0x8B, 0xB7, 0x08, 0xF4, 0xD7, 0x2D, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0x2B, 0x30, 0x02, 0x45, 0x71, 0x08, 0x49), + MBEDTLS_BYTES_TO_T_UINT_8(0x97, 0x3A, 0xCA, 0x50, 0xF6, 0xC2, 0x19, 0x8C), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0xB9, 0x9B, 0x3E, 0x73, 0x95, 0x1D, 0x49), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x60, 0x59, 0x48, 0xCB, 0xD8, 0xD6, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0xB9, 0x6C, 0x89, 0xAB, 0x99, 0xA8, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0xA1, 0x8B, 0x4E, 0x06, 0x19, 0xEC, 0x99), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0x95, 0x04, 0xCF, 0xD5, 0x94, 0xB3, 0x02), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_14_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0x35, 0x93, 0x7C, 0xB3, 0xB8, 0x9E, 0x1B), + MBEDTLS_BYTES_TO_T_UINT_8(0xC4, 0x45, 0x5C, 0x7E, 0xBF, 0x75, 0x81, 0x0F), + MBEDTLS_BYTES_TO_T_UINT_8(0xDC, 0xE8, 0x24, 0xDF, 0xEC, 0x2F, 0x7D, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0x8B, 0xD5, 0x6A, 0x9B, 0xA0, 0xE0, 0x4F), + MBEDTLS_BYTES_TO_T_UINT_8(0x32, 0xE3, 0x27, 0x82, 0xDE, 0xDD, 0xCA, 0x4B), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0x57, 0x56, 0x46, 0x05, 0x06, 0x01, 0x2E), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0x35, 0xA7, 0x47, 0xE2, 0x6B, 0x2C, 0x4F), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0x9D, 0x4C, 0xEC, 0x1F, 0x11, 0x75, 0x2B), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_15_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xAA, 0x41, 0xC1, 0xE9, 0x0E, 0xE9, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0x0A, 0xCF, 0x9C, 0x4B, 0xE8, 0xED, 0x0A, 0x49), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0x73, 0xCA, 0x0C, 0x46, 0x0A, 0x9C, 0xE4), + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0xE1, 0x9E, 0xBC, 0xFE, 0x44, 0x63, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0x31, 0x43, 0x71, 0xEE, 0xF8, 0xC1, 0x8C, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0x4B, 0xF0, 0x69, 0x25, 0xBD, 0x71, 0x1A), + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0x9A, 0xFE, 0x82, 0xE7, 0xC1, 0xC1, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x5A, 0x6E, 0x5E, 0x97, 0x6A, 0x35, 0x8D), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_15_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA2, 0x18, 0x6C, 0x7E, 0xB8, 0x9E, 0x57, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0x35, 0xB9, 0xC1, 0xD0, 0xFE, 0x78, 0xFB, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x08, 0xAE, 0x46, 0x34, 0xEA, 0x7A, 0x7F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x1C, 0x56, 0xA9, 0x18, 0x37, 0xD4, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x63, 0xE9, 0x0A, 0xB6, 0x38, 0x3C, 0xC1), + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0x4F, 0xA4, 0x6E, 0x85, 0x31, 0x23, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0x0D, 0xAD, 0xC4, 0xC3, 0xB1, 0x4B, 0x1C, 0x82), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0x56, 0x4A, 0x38, 0xB3, 0x6B, 0x6F, 0x2C), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_16_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x67, 0xC7, 0x19, 0xDE, 0x21, 0xED, 0x89, 0xD0), + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0xBE, 0xA6, 0xAE, 0xEB, 0x9D, 0xA7, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x0E, 0x13, 0x1E, 0x86, 0x57, 0xC3, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x4B, 0x30, 0x46, 0x52, 0xC1, 0xEC, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0x6E, 0xD5, 0x44, 0x31, 0x96, 0x3B, 0x26, 0x27), + MBEDTLS_BYTES_TO_T_UINT_8(0x77, 0x68, 0xA8, 0x67, 0x78, 0x39, 0xE8, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0x8E, 0x78, 0xB7, 0xDD, 0xF2, 0x58, 0xB6, 0x3D), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0x3C, 0xB3, 0x26, 0xC4, 0x2C, 0x8C, 0xA5), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_16_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0x24, 0xE5, 0x73, 0xEE, 0x9A, 0x02, 0xA9), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x6A, 0x65, 0x60, 0xF3, 0x62, 0xE3, 0xE9), + MBEDTLS_BYTES_TO_T_UINT_8(0xFB, 0x07, 0x84, 0xE6, 0x3B, 0x46, 0x65, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE1, 0x8F, 0x0C, 0xB0, 0xE1, 0x04, 0x82, 0x9D), + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0x13, 0xBF, 0x3D, 0xA0, 0x48, 0xA2, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0x26, 0x76, 0x74, 0xAB, 0x0B, 0x29, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0x6E, 0x5F, 0x03, 0x34, 0x7C, 0x38, 0xCE), + MBEDTLS_BYTES_TO_T_UINT_8(0x4D, 0x72, 0xF9, 0x3B, 0x3C, 0xA4, 0xBC, 0x7C), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_17_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0xCE, 0x18, 0x80, 0xB8, 0x24, 0x45, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x09, 0x03, 0xB8, 0x06, 0x64, 0xF7, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x26, 0xB1, 0x10, 0x6D, 0x71, 0x12, 0x2E), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0x12, 0xC6, 0x6E, 0x1E, 0x6A, 0xC3, 0x80), + MBEDTLS_BYTES_TO_T_UINT_8(0xE5, 0xD3, 0x0A, 0xDE, 0xD8, 0x6B, 0x04, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0x87, 0x5B, 0xAE, 0xDB, 0x3C, 0xC0, 0xC5), + MBEDTLS_BYTES_TO_T_UINT_8(0x8E, 0xF5, 0xF9, 0xC1, 0x9A, 0x89, 0xBB, 0x7E), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0x69, 0x72, 0x8B, 0xAE, 0x32, 0x13, 0x11), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_17_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF9, 0x16, 0x07, 0x50, 0xFA, 0x4C, 0xCF, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0x50, 0x21, 0xE9, 0xDE, 0xEC, 0x7E, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x2F, 0xE8, 0x83, 0x30, 0x0B, 0x65, 0x0E), + MBEDTLS_BYTES_TO_T_UINT_8(0xA5, 0x0B, 0x99, 0xAC, 0xC9, 0xBA, 0x6C, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0x59, 0x5A, 0x0D, 0x7B, 0x9E, 0x08, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0x91, 0xB2, 0xDC, 0x90, 0xCE, 0x67, 0xED), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x93, 0x60, 0x0C, 0xD7, 0x1F, 0x2F, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x7F, 0x9D, 0x40, 0xF8, 0x78, 0x7A, 0x54), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_18_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x13, 0x22, 0x95, 0xE8, 0xEF, 0x31, 0x57, 0x35), + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0x88, 0x53, 0xFE, 0xAF, 0x7C, 0x47, 0x14), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0xCE, 0xCC, 0x79, 0xE8, 0x9F, 0x8C, 0xC4), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x16, 0xDD, 0x77, 0x6E, 0x8A, 0x73, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0x07, 0x97, 0x21, 0x3B, 0xF8, 0x5F, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0xB5, 0xD2, 0x81, 0x84, 0xF0, 0xE7, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x8F, 0x75, 0x09, 0x6A, 0x0E, 0x53, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0x4F, 0x70, 0x97, 0xC7, 0xAC, 0x7D, 0x3F), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_18_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF9, 0x3C, 0x6A, 0xB4, 0x10, 0xA9, 0xC8, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0xEE, 0xC5, 0xD6, 0x69, 0x16, 0xB8, 0xAC, 0x25), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x44, 0xDC, 0xEB, 0x48, 0x54, 0x5D, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0x6F, 0x48, 0x9B, 0xD7, 0x72, 0x69, 0xA4, 0x8A), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x0D, 0x36, 0x9A, 0x66, 0x0B, 0xEC, 0x24), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0xC6, 0xD4, 0xB6, 0x60, 0xE5, 0xC3, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x29, 0x42, 0xE0, 0x9D, 0xFD, 0x7C, 0x3E), + MBEDTLS_BYTES_TO_T_UINT_8(0x43, 0x10, 0xBA, 0x55, 0xBC, 0x3B, 0x38, 0x5D), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_19_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x25, 0x66, 0xFA, 0x05, 0x73, 0x03, 0x1B, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0xA4, 0x66, 0x12, 0x96, 0x7B, 0x02, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0x44, 0xB5, 0xDE, 0x6D, 0x98, 0xD1, 0xD5, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0xE2, 0xF5, 0x44, 0xB8, 0x8E, 0xF6, 0x8C, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x15, 0x2B, 0x72, 0xBC, 0x49, 0xE5, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x44, 0xD7, 0xDF, 0x8F, 0xEB, 0x8D, 0x80), + MBEDTLS_BYTES_TO_T_UINT_8(0x05, 0x64, 0x88, 0xAA, 0xB7, 0xE4, 0x70, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0x14, 0xBB, 0xE9, 0x9B, 0xB9, 0x65, 0x5D), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_19_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0x8E, 0x88, 0xF5, 0xF1, 0xC1, 0x89, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0x30, 0x53, 0xE6, 0xFB, 0x2D, 0x82, 0xB4), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0xE4, 0xFF, 0xBA, 0x31, 0x79, 0xAB, 0xC2), + MBEDTLS_BYTES_TO_T_UINT_8(0x45, 0x09, 0xF7, 0xB7, 0x09, 0x78, 0x4C, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0xAE, 0xC2, 0x44, 0xDC, 0x17, 0x78, 0x47), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0xD4, 0x17, 0x43, 0x19, 0x74, 0x9E, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x64, 0x3B, 0x73, 0xA2, 0x99, 0x27, 0x76), + MBEDTLS_BYTES_TO_T_UINT_8(0x05, 0x74, 0x36, 0x5F, 0xD3, 0x14, 0xB1, 0x31), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_20_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x07, 0xAB, 0xFD, 0x9B, 0x03, 0xC5, 0xD5), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0xBE, 0xB0, 0x1D, 0xF2, 0x0C, 0x73, 0x73), + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0xE7, 0x7B, 0x87, 0xD3, 0x34, 0xFD, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0x9A, 0x25, 0x3D, 0xC7, 0x36, 0x83, 0x53, 0xDC), + MBEDTLS_BYTES_TO_T_UINT_8(0x22, 0x7C, 0xCF, 0x63, 0x55, 0x12, 0x11, 0xB0), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0x34, 0x4D, 0x27, 0x92, 0xAC, 0x18, 0x16), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x42, 0x61, 0x9D, 0x2E, 0xFF, 0x13, 0x16), + MBEDTLS_BYTES_TO_T_UINT_8(0xF4, 0xDE, 0x92, 0x65, 0x57, 0x0D, 0xBC, 0x0A), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_20_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0x7B, 0x6E, 0xC6, 0x2A, 0x21, 0x74, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0xA7, 0x53, 0x4D, 0x29, 0x36, 0xEF, 0xE5), + MBEDTLS_BYTES_TO_T_UINT_8(0xE1, 0xD6, 0x41, 0xC7, 0x99, 0xAD, 0x50, 0x53), + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0xAC, 0x41, 0x9F, 0xFB, 0x4C, 0x86, 0xF1), + MBEDTLS_BYTES_TO_T_UINT_8(0x8B, 0xBB, 0xE6, 0x25, 0x28, 0xAA, 0xEB, 0x1E), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x04, 0xA2, 0xC3, 0xAA, 0x08, 0x8A, 0xCC), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x2B, 0x5B, 0xE2, 0x8D, 0x76, 0xEA, 0x34), + MBEDTLS_BYTES_TO_T_UINT_8(0xB3, 0x33, 0xD2, 0x21, 0x4D, 0x62, 0xE3, 0x8E), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_21_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0x06, 0x8B, 0x2B, 0xC2, 0xC4, 0xB1, 0xD2), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0xF5, 0xA1, 0xC0, 0x03, 0x6A, 0x29, 0x12), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xA9, 0xEF, 0x55, 0xB6, 0x1A, 0x9F, 0x6B), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x54, 0x32, 0xBE, 0x06, 0x43, 0xB5, 0xFD), + MBEDTLS_BYTES_TO_T_UINT_8(0xF7, 0xD6, 0xD9, 0x20, 0x89, 0xBE, 0xD4, 0x1B), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x26, 0x95, 0x10, 0xCE, 0xB4, 0x88, 0x79), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0xA6, 0x27, 0xAC, 0x32, 0xBA, 0xBD, 0xC7), + MBEDTLS_BYTES_TO_T_UINT_8(0xA3, 0xA6, 0xAE, 0x9C, 0x7B, 0xBE, 0xA1, 0x63), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_21_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8B, 0xCD, 0x4D, 0x3D, 0xDF, 0x96, 0xBB, 0x7D), + MBEDTLS_BYTES_TO_T_UINT_8(0x77, 0xA7, 0x11, 0x06, 0xCC, 0x0E, 0x31, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0x20, 0xE4, 0xF4, 0xAD, 0x7B, 0x5F, 0xF1, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0x54, 0xBE, 0xF4, 0x8A, 0x03, 0x47, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x53, 0x00, 0x7F, 0xB0, 0x8A, 0x68, 0xA6), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x16, 0xB1, 0x73, 0x6F, 0x5B, 0x0E, 0xC3), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0x32, 0xE3, 0x43, 0x64, 0x75, 0xFB, 0xFB), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x18, 0x55, 0x8A, 0x4E, 0x6E, 0x35, 0x54), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_22_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x80, 0x97, 0x15, 0x1E, 0xCB, 0xF2, 0x9C, 0xA5), + MBEDTLS_BYTES_TO_T_UINT_8(0x2B, 0xD1, 0xBB, 0xF3, 0x70, 0xAD, 0x13, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0x96, 0xA4, 0xC5, 0x5E, 0xDA, 0xD5, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0x81, 0xE9, 0x65, 0x66, 0x76, 0x47, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x35, 0x87, 0x06, 0x73, 0xCF, 0x34, 0xD2), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x81, 0x15, 0x42, 0xA2, 0x79, 0x5B, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0xA2, 0x7D, 0x09, 0x14, 0x64, 0xC6, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0x6D, 0xC4, 0xED, 0xF1, 0xD6, 0xE9, 0x24), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_22_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0xD5, 0xBB, 0x25, 0xA3, 0xDD, 0xA3, 0x88), + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0xF2, 0x68, 0x67, 0x39, 0x8F, 0x73, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0x76, 0x28, 0x89, 0xAD, 0x32, 0xE0, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0x90, 0xCC, 0x57, 0x58, 0xAA, 0xC9, 0x75), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0xD7, 0x43, 0xD2, 0xCE, 0x5E, 0xA0, 0x08), + MBEDTLS_BYTES_TO_T_UINT_8(0x33, 0xB0, 0xB8, 0xA4, 0x9E, 0x96, 0x26, 0x86), + MBEDTLS_BYTES_TO_T_UINT_8(0x94, 0x61, 0x1D, 0xF3, 0x65, 0x5E, 0x60, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0x1E, 0x65, 0xED, 0xCF, 0x07, 0x60, 0x20), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_23_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0x30, 0x17, 0x8A, 0x91, 0x88, 0x0A, 0xA4), + MBEDTLS_BYTES_TO_T_UINT_8(0x05, 0x7D, 0x18, 0xA4, 0xAC, 0x59, 0xFC, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0x31, 0x8B, 0x25, 0x65, 0x39, 0x9A, 0xDC), + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x16, 0x4B, 0x68, 0xBA, 0x59, 0x13, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xFD, 0xD3, 0xC5, 0x56, 0xC9, 0x8C, 0x5E), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0xC6, 0x9F, 0xF4, 0xE6, 0xF7, 0xB4, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0x7C, 0x03, 0x00, 0x26, 0x9F, 0xD8, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0x24, 0x1D, 0x6E, 0x00, 0xB9, 0x00, 0x6E, 0x93), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_23_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x75, 0x63, 0xDA, 0x03, 0x2B, 0xD5, 0x0B, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0xFC, 0xE2, 0xC8, 0x47, 0xF0, 0xAE, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0x4C, 0xF7, 0x50, 0x0C, 0x48, 0x06, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0xDF, 0x2B, 0x32, 0x98, 0x0E, 0x7E, 0x61, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0x02, 0x27, 0xFE, 0x75, 0x86, 0xDF, 0x24), + MBEDTLS_BYTES_TO_T_UINT_8(0x2B, 0x30, 0xB1, 0x22, 0x32, 0x1B, 0xFE, 0x24), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x27, 0xF7, 0x78, 0x6F, 0xD7, 0xFD, 0xE4), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x78, 0xCC, 0xEA, 0xC0, 0x50, 0x24, 0x44), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_24_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x2B, 0x4F, 0x7F, 0x58, 0xE6, 0xC2, 0x70), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x43, 0xD5, 0xA7, 0x35, 0x3C, 0x80, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0x1A, 0x6D, 0x4B, 0x12, 0x00, 0x7B, 0xE6, 0xA6), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x15, 0xBD, 0xD0, 0x9B, 0xCA, 0xAA, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0xCF, 0xCE, 0x9C, 0xE3, 0x8B, 0x60, 0x7A, 0x53), + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0xDA, 0x4B, 0x03, 0xA7, 0x8D, 0x43, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0xAF, 0x00, 0x2B, 0x32, 0xF0, 0x22, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0xDC, 0xD9, 0x99, 0x99, 0xBE, 0x43, 0x99, 0x3E), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_24_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x71, 0x41, 0xF4, 0xB5, 0xFD, 0xDD, 0x36), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0xE2, 0x20, 0x4C, 0xD1, 0x2E, 0x1F, 0x06), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0x43, 0x48, 0x76, 0x8A, 0x49, 0xAC, 0x87), + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0x1A, 0x55, 0xA8, 0xA3, 0xD4, 0x57, 0x75), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0xA6, 0x84, 0x39, 0xC9, 0x13, 0xBB, 0x60), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0xFA, 0xA9, 0x70, 0xDE, 0x83, 0xDD, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0xEC, 0xC9, 0xD9, 0x3E, 0x44, 0x91, 0x68, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x9F, 0x85, 0x6D, 0xF7, 0x54, 0x36, 0x82), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_25_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x6B, 0xA6, 0xA3, 0xE5, 0xD4, 0x46, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0x23, 0x3E, 0xDC, 0x84, 0x7C, 0x7B, 0x24, 0x34), + MBEDTLS_BYTES_TO_T_UINT_8(0x14, 0xED, 0x7F, 0x86, 0x07, 0x6C, 0x57, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0x06, 0xFE, 0x52, 0x12, 0x79, 0x69, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0x84, 0xD1, 0x44, 0x5F, 0x21, 0x3A, 0xC3, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0xD9, 0x4A, 0xC0, 0x75, 0xAB, 0x17, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0x81, 0x94, 0xB6, 0x80, 0x6B, 0x6F, 0xC3), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0xBE, 0x8E, 0xA5, 0xAA, 0xBC, 0x1E, 0x3E), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_25_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x89, 0xC7, 0x85, 0xA6, 0x59, 0x9B, 0xB1, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0xCE, 0x40, 0xD1, 0xFB, 0xDF, 0x94, 0xF7), + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0xB8, 0x5E, 0xBF, 0x45, 0xA8, 0x2D, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x9C, 0x06, 0x1B, 0xA9, 0x57, 0xB9, 0x79), + MBEDTLS_BYTES_TO_T_UINT_8(0x53, 0xE9, 0xCE, 0xA2, 0xD3, 0x74, 0xA1, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0xAA, 0x5F, 0x34, 0x78, 0xDB, 0xAE, 0x3A, 0x14), + MBEDTLS_BYTES_TO_T_UINT_8(0x7D, 0x32, 0x84, 0x3E, 0x68, 0x6A, 0x43, 0x0F), + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0xBC, 0x39, 0x36, 0xA4, 0xC5, 0xBB, 0x11), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_26_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0x07, 0xA2, 0xB5, 0xC9, 0x0F, 0x4D, 0x0F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x1D, 0x67, 0xE6, 0xF1, 0x46, 0xEB, 0x71), + MBEDTLS_BYTES_TO_T_UINT_8(0xD7, 0x41, 0x23, 0x95, 0xE7, 0xE0, 0x10, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0x69, 0xFE, 0x68, 0x8C, 0xC6, 0x5F, 0xB6), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0xB9, 0x2B, 0x3D, 0xD2, 0x4F, 0xD8, 0x1A), + MBEDTLS_BYTES_TO_T_UINT_8(0xA3, 0x09, 0xF5, 0x5F, 0xCF, 0xF6, 0x91, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x15, 0x42, 0x6B, 0x6D, 0xB5, 0xF3, 0xB6), + MBEDTLS_BYTES_TO_T_UINT_8(0xBF, 0x56, 0x9D, 0xC5, 0xFF, 0xCA, 0x13, 0x9B), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_26_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x4D, 0x38, 0xE6, 0x23, 0x63, 0x48, 0x3C, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0xD2, 0x68, 0x3C, 0xD1, 0x3B, 0xE9, 0x3B, 0x82), + MBEDTLS_BYTES_TO_T_UINT_8(0xB5, 0x08, 0x54, 0x49, 0xD1, 0x46, 0x45, 0x13), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0x70, 0x52, 0x6E, 0x79, 0xC4, 0x5E, 0x95), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0xDF, 0xE8, 0x5A, 0x32, 0x81, 0xDA, 0xD3), + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0x2D, 0x94, 0x5B, 0xB5, 0x35, 0x9F, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0x12, 0x8D, 0xC3, 0x36, 0x36, 0xB2, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0x39, 0x2F, 0x22, 0x38, 0x5B, 0x18, 0x4C, 0x35), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_27_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0xC1, 0x22, 0x0E, 0xF0, 0x73, 0x11, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0xB2, 0xAE, 0xA4, 0x56, 0x18, 0x61, 0x66, 0x12), + MBEDTLS_BYTES_TO_T_UINT_8(0x79, 0xFB, 0x72, 0x08, 0x84, 0x38, 0x51, 0xB0), + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x86, 0xA8, 0xB9, 0x31, 0x99, 0x29, 0xC3), + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0xFB, 0xC3, 0x42, 0xB3, 0xC7, 0x6F, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0xF8, 0xE1, 0x09, 0xBE, 0x75, 0xB0, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x7D, 0xFF, 0xF4, 0x99, 0xFC, 0x13, 0xAB), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0x1B, 0x84, 0x81, 0x42, 0x22, 0xC6, 0x3D), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_27_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0xE0, 0x37, 0xA4, 0xA0, 0x2F, 0x38, 0x7F), + MBEDTLS_BYTES_TO_T_UINT_8(0xD0, 0x3D, 0xB7, 0x40, 0x2F, 0x39, 0x3C, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0x7A, 0x3B, 0x8A, 0x51, 0xAE, 0x40, 0x49, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0x20, 0x9F, 0xDD, 0xA9, 0xD0, 0x77, 0xC7), + MBEDTLS_BYTES_TO_T_UINT_8(0x78, 0x1D, 0x64, 0xDA, 0xA0, 0x53, 0xC7, 0x7D), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x7B, 0x66, 0x55, 0x94, 0xD1, 0x51, 0x44), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0xA9, 0xB5, 0x5B, 0x38, 0x35, 0x40, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0xC9, 0x0F, 0xF0, 0x73, 0x79, 0x43, 0x61), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_28_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0x47, 0x45, 0x69, 0x80, 0x72, 0x72, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0x11, 0x99, 0x59, 0xDB, 0x48, 0x80, 0x39), + MBEDTLS_BYTES_TO_T_UINT_8(0x75, 0x6E, 0x3D, 0xFC, 0x37, 0x15, 0xF4, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0xBB, 0x5B, 0xA6, 0x35, 0x8D, 0x28, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0x1A, 0x3B, 0x2C, 0x8F, 0xD3, 0xAA, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0x1C, 0x1A, 0xF8, 0x02, 0xD9, 0x7B, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0x69, 0xAC, 0xF8, 0x54, 0x31, 0x14, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0x8A, 0xE6, 0xDE, 0x58, 0xB9, 0xC4, 0x7A), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_28_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0x83, 0x52, 0xFE, 0xF9, 0x7B, 0xE9, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0xA2, 0x55, 0x46, 0x15, 0x49, 0xC1, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0xBC, 0x5C, 0x91, 0xBD, 0xB9, 0x9C, 0xF4), + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0xFD, 0xB1, 0x4E, 0x5F, 0x74, 0xEE, 0x53), + MBEDTLS_BYTES_TO_T_UINT_8(0xB1, 0x8B, 0xD8, 0x8B, 0x17, 0x73, 0x1B, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0x22, 0x92, 0xD7, 0x67, 0x06, 0xAD, 0x25, 0xCD), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0x0F, 0x80, 0x24, 0xE2, 0x27, 0x5F, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0x1C, 0xCE, 0xD0, 0x67, 0xCA, 0xD4, 0x0B), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_29_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0xF1, 0xDD, 0x33, 0x66, 0xF9, 0x05, 0xD6), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0xE5, 0x6B, 0x79, 0xBD, 0x48, 0x42, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0xD1, 0x14, 0x52, 0xE3, 0x53, 0xB4, 0x50, 0xD4), + MBEDTLS_BYTES_TO_T_UINT_8(0x32, 0x84, 0x6C, 0xCF, 0xDA, 0xB2, 0x20, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0xD6, 0x1A, 0xE5, 0xE2, 0x29, 0x70, 0xCE), + MBEDTLS_BYTES_TO_T_UINT_8(0xD5, 0x61, 0xFE, 0xBB, 0x21, 0x82, 0xD1, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0x2C, 0xF0, 0x9C, 0x8B, 0x1A, 0x42, 0x30, 0x06), + MBEDTLS_BYTES_TO_T_UINT_8(0x43, 0xD6, 0x49, 0x81, 0x92, 0xF1, 0xD0, 0x90), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_29_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x91, 0x93, 0x6A, 0xA6, 0x22, 0xE9, 0xD6), + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0xDC, 0xC3, 0x69, 0x11, 0x95, 0x7D, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0xA3, 0x9D, 0x87, 0x5E, 0x64, 0x41, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0x87, 0x5A, 0x15, 0xBD, 0x6E, 0x3C, 0x8D), + MBEDTLS_BYTES_TO_T_UINT_8(0xD0, 0x8D, 0x50, 0xCC, 0xCF, 0xB7, 0x8F, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0x65, 0xCD, 0x31, 0x30, 0xF1, 0x68, 0x13), + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0x5C, 0x66, 0x67, 0x92, 0x30, 0x57, 0x95), + MBEDTLS_BYTES_TO_T_UINT_8(0x23, 0x9B, 0x01, 0x3D, 0x20, 0x8B, 0xD1, 0x0D), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_30_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0xC0, 0xE6, 0x4F, 0xDE, 0x62, 0xAB, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0x48, 0xB3, 0x1C, 0x0F, 0x16, 0x93, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0x77, 0x63, 0xBD, 0x1F, 0x16, 0x50, 0x56, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0x06, 0xBC, 0xE9, 0x27, 0x1C, 0x9A, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0xFE, 0x21, 0xC5, 0x39, 0x55, 0xE1, 0xFD), + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0xA8, 0xD0, 0x96, 0x0E, 0xB5, 0xB2, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0xE7, 0x4B, 0xF3, 0x11, 0x0C, 0xC9, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x43, 0x3A, 0xC4, 0x87, 0x71, 0xEE, 0xFA, 0x18), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_30_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0x77, 0xEE, 0x81, 0x5E, 0x96, 0xEA, 0x4B), + MBEDTLS_BYTES_TO_T_UINT_8(0xEE, 0xDF, 0xA9, 0xF4, 0x4F, 0x7C, 0xB2, 0x43), + MBEDTLS_BYTES_TO_T_UINT_8(0x9F, 0xD4, 0xDF, 0x35, 0x63, 0x47, 0x25, 0x8A), + MBEDTLS_BYTES_TO_T_UINT_8(0xA5, 0x3D, 0xFF, 0xA4, 0x02, 0xC3, 0x95, 0x11), + MBEDTLS_BYTES_TO_T_UINT_8(0xD5, 0x10, 0x78, 0xD1, 0x2B, 0xB7, 0xBE, 0x0E), + MBEDTLS_BYTES_TO_T_UINT_8(0x0A, 0xE9, 0x57, 0xF9, 0xE0, 0xD8, 0xFC, 0xBC), + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0xC4, 0x01, 0xD6, 0xB4, 0xE7, 0x78, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0x02, 0x6C, 0xB9, 0x13, 0xA4, 0xE8, 0x6D, 0x6F), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_31_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0xB0, 0xC9, 0xCD, 0xBF, 0xA2, 0x1E, 0x63), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x4F, 0x86, 0x22, 0x9B, 0xEA, 0xE8, 0xBB), + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x46, 0xDF, 0x43, 0xB9, 0x82, 0x2D, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0x32, 0xF1, 0x4E, 0x95, 0x41, 0xAE, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0x93, 0x26, 0xFC, 0xD3, 0x90, 0xDC, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x05, 0x45, 0xCA, 0xF9, 0x5A, 0x89, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0x82, 0x63, 0x4E, 0x55, 0x1D, 0x3A, 0x08), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x69, 0x52, 0x49, 0xE9, 0xED, 0x57, 0x34), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_31_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0x64, 0xE9, 0xAC, 0x4C, 0x4A, 0xEA, 0x25), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0xE9, 0x0B, 0x99, 0xE7, 0xF9, 0xA9, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x24, 0x0C, 0xC1, 0xF4, 0x8D, 0x07, 0xB6, 0xB1), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0x68, 0xFA, 0x35, 0xE4, 0x9E, 0xAE, 0xD9), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0x2D, 0x1A, 0x13, 0x8E, 0x02, 0xE2, 0x63), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0x38, 0x28, 0x86, 0x46, 0x7B, 0x3A, 0xE1), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0x4C, 0x64, 0x59, 0x0A, 0xF9, 0x02, 0xC4), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0x4F, 0x23, 0xA2, 0xC3, 0xD5, 0xEF, 0x42), +}; +static const mbedtls_ecp_point brainpoolP512r1_T[32] = { + ECP_POINT_INIT_XY_Z1(brainpoolP512r1_T_0_X, brainpoolP512r1_T_0_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_1_X, brainpoolP512r1_T_1_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_2_X, brainpoolP512r1_T_2_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_3_X, brainpoolP512r1_T_3_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_4_X, brainpoolP512r1_T_4_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_5_X, brainpoolP512r1_T_5_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_6_X, brainpoolP512r1_T_6_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_7_X, brainpoolP512r1_T_7_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_8_X, brainpoolP512r1_T_8_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_9_X, brainpoolP512r1_T_9_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_10_X, brainpoolP512r1_T_10_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_11_X, brainpoolP512r1_T_11_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_12_X, brainpoolP512r1_T_12_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_13_X, brainpoolP512r1_T_13_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_14_X, brainpoolP512r1_T_14_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_15_X, brainpoolP512r1_T_15_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_16_X, brainpoolP512r1_T_16_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_17_X, brainpoolP512r1_T_17_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_18_X, brainpoolP512r1_T_18_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_19_X, brainpoolP512r1_T_19_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_20_X, brainpoolP512r1_T_20_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_21_X, brainpoolP512r1_T_21_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_22_X, brainpoolP512r1_T_22_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_23_X, brainpoolP512r1_T_23_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_24_X, brainpoolP512r1_T_24_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_25_X, brainpoolP512r1_T_25_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_26_X, brainpoolP512r1_T_26_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_27_X, brainpoolP512r1_T_27_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_28_X, brainpoolP512r1_T_28_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_29_X, brainpoolP512r1_T_29_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_30_X, brainpoolP512r1_T_30_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_31_X, brainpoolP512r1_T_31_Y), +}; +#else +#define brainpoolP512r1_T NULL +#endif +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ + +#if defined(ECP_LOAD_GROUP) +/* + * Create an MPI from embedded constants + * (assumes len is an exact multiple of sizeof(mbedtls_mpi_uint)) + */ +static inline void ecp_mpi_load(mbedtls_mpi *X, const mbedtls_mpi_uint *p, size_t len) +{ + X->s = 1; + X->n = (unsigned short) (len / sizeof(mbedtls_mpi_uint)); + X->p = (mbedtls_mpi_uint *) p; +} + +/* + * Set an MPI to static value 1 + */ +static inline void ecp_mpi_set1(mbedtls_mpi *X) +{ + X->s = 1; + X->n = 1; + X->p = (mbedtls_mpi_uint *) mpi_one; /* X->p will not be modified so the cast is safe */ +} + +/* + * Make group available from embedded constants + */ +static int ecp_group_load(mbedtls_ecp_group *grp, + const mbedtls_mpi_uint *p, size_t plen, + const mbedtls_mpi_uint *a, size_t alen, + const mbedtls_mpi_uint *b, size_t blen, + const mbedtls_mpi_uint *gx, size_t gxlen, + const mbedtls_mpi_uint *gy, size_t gylen, + const mbedtls_mpi_uint *n, size_t nlen, + const mbedtls_ecp_point *T) +{ + ecp_mpi_load(&grp->P, p, plen); + if (a != NULL) { + ecp_mpi_load(&grp->A, a, alen); + } + ecp_mpi_load(&grp->B, b, blen); + ecp_mpi_load(&grp->N, n, nlen); + + ecp_mpi_load(&grp->G.X, gx, gxlen); + ecp_mpi_load(&grp->G.Y, gy, gylen); + ecp_mpi_set1(&grp->G.Z); + + grp->pbits = mbedtls_mpi_bitlen(&grp->P); + grp->nbits = mbedtls_mpi_bitlen(&grp->N); + + grp->h = 1; + + grp->T = (mbedtls_ecp_point *) T; + /* + * Set T_size to 0 to prevent T free by mbedtls_ecp_group_free. + */ + grp->T_size = 0; + + return 0; +} +#endif /* ECP_LOAD_GROUP */ + +#if defined(MBEDTLS_ECP_NIST_OPTIM) +/* Forward declarations */ +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +static int ecp_mod_p256(mbedtls_mpi *); +#endif +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +static int ecp_mod_p384(mbedtls_mpi *); +#endif +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +static int ecp_mod_p521(mbedtls_mpi *); +#endif + +#define NIST_MODP(P) grp->modp = ecp_mod_ ## P; +#else +#define NIST_MODP(P) +#endif /* MBEDTLS_ECP_NIST_OPTIM */ + +/* Additional forward declarations */ +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +static int ecp_mod_p255(mbedtls_mpi *); +#endif +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) +static int ecp_mod_p448(mbedtls_mpi *); +#endif +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +static int ecp_mod_p256k1(mbedtls_mpi *); +#endif + +#if defined(ECP_LOAD_GROUP) +#define LOAD_GROUP_A(G) ecp_group_load(grp, \ + G ## _p, sizeof(G ## _p), \ + G ## _a, sizeof(G ## _a), \ + G ## _b, sizeof(G ## _b), \ + G ## _gx, sizeof(G ## _gx), \ + G ## _gy, sizeof(G ## _gy), \ + G ## _n, sizeof(G ## _n), \ + G ## _T \ + ) + +#define LOAD_GROUP(G) ecp_group_load(grp, \ + G ## _p, sizeof(G ## _p), \ + NULL, 0, \ + G ## _b, sizeof(G ## _b), \ + G ## _gx, sizeof(G ## _gx), \ + G ## _gy, sizeof(G ## _gy), \ + G ## _n, sizeof(G ## _n), \ + G ## _T \ + ) +#endif /* ECP_LOAD_GROUP */ + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +/* Constants used by ecp_use_curve25519() */ +static const mbedtls_mpi_sint curve25519_a24 = 0x01DB42; +static const unsigned char curve25519_part_of_n[] = { + 0x14, 0xDE, 0xF9, 0xDE, 0xA2, 0xF7, 0x9C, 0xD6, + 0x58, 0x12, 0x63, 0x1A, 0x5C, 0xF5, 0xD3, 0xED, +}; + +/* + * Specialized function for creating the Curve25519 group + */ +static int ecp_use_curve25519(mbedtls_ecp_group *grp) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + /* Actually ( A + 2 ) / 4 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&grp->A, curve25519_a24)); + + /* P = 2^255 - 19 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&grp->P, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&grp->P, 255)); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&grp->P, &grp->P, 19)); + grp->pbits = mbedtls_mpi_bitlen(&grp->P); + + /* N = 2^252 + 27742317777372353535851937790883648493 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&grp->N, + curve25519_part_of_n, sizeof(curve25519_part_of_n))); + MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&grp->N, 252, 1)); + + /* Y intentionally not set, since we use x/z coordinates. + * This is used as a marker to identify Montgomery curves! */ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&grp->G.X, 9)); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&grp->G.Z, 1)); + mbedtls_mpi_free(&grp->G.Y); + + /* Actually, the required msb for private keys */ + grp->nbits = 254; + +cleanup: + if (ret != 0) { + mbedtls_ecp_group_free(grp); + } + + return ret; +} +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) +/* Constants used by ecp_use_curve448() */ +static const mbedtls_mpi_sint curve448_a24 = 0x98AA; +static const unsigned char curve448_part_of_n[] = { + 0x83, 0x35, 0xDC, 0x16, 0x3B, 0xB1, 0x24, + 0xB6, 0x51, 0x29, 0xC9, 0x6F, 0xDE, 0x93, + 0x3D, 0x8D, 0x72, 0x3A, 0x70, 0xAA, 0xDC, + 0x87, 0x3D, 0x6D, 0x54, 0xA7, 0xBB, 0x0D, +}; + +/* + * Specialized function for creating the Curve448 group + */ +static int ecp_use_curve448(mbedtls_ecp_group *grp) +{ + mbedtls_mpi Ns; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + mbedtls_mpi_init(&Ns); + + /* Actually ( A + 2 ) / 4 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&grp->A, curve448_a24)); + + /* P = 2^448 - 2^224 - 1 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&grp->P, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&grp->P, 224)); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&grp->P, &grp->P, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&grp->P, 224)); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&grp->P, &grp->P, 1)); + grp->pbits = mbedtls_mpi_bitlen(&grp->P); + + /* Y intentionally not set, since we use x/z coordinates. + * This is used as a marker to identify Montgomery curves! */ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&grp->G.X, 5)); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&grp->G.Z, 1)); + mbedtls_mpi_free(&grp->G.Y); + + /* N = 2^446 - 13818066809895115352007386748515426880336692474882178609894547503885 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&grp->N, 446, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&Ns, + curve448_part_of_n, sizeof(curve448_part_of_n))); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&grp->N, &grp->N, &Ns)); + + /* Actually, the required msb for private keys */ + grp->nbits = 447; + +cleanup: + mbedtls_mpi_free(&Ns); + if (ret != 0) { + mbedtls_ecp_group_free(grp); + } + + return ret; +} +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ + +/* + * Set a group using well-known domain parameters + */ +int mbedtls_ecp_group_load(mbedtls_ecp_group *grp, mbedtls_ecp_group_id id) +{ + mbedtls_ecp_group_free(grp); + + mbedtls_ecp_group_init(grp); + + grp->id = id; + + switch (id) { +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + case MBEDTLS_ECP_DP_SECP256R1: + NIST_MODP(p256); + return LOAD_GROUP(secp256r1); +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + case MBEDTLS_ECP_DP_SECP384R1: + NIST_MODP(p384); + return LOAD_GROUP(secp384r1); +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + case MBEDTLS_ECP_DP_SECP521R1: + NIST_MODP(p521); + return LOAD_GROUP(secp521r1); +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + case MBEDTLS_ECP_DP_SECP256K1: + grp->modp = ecp_mod_p256k1; + return LOAD_GROUP_A(secp256k1); +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + case MBEDTLS_ECP_DP_BP256R1: + return LOAD_GROUP_A(brainpoolP256r1); +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + case MBEDTLS_ECP_DP_BP384R1: + return LOAD_GROUP_A(brainpoolP384r1); +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + case MBEDTLS_ECP_DP_BP512R1: + return LOAD_GROUP_A(brainpoolP512r1); +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + case MBEDTLS_ECP_DP_CURVE25519: + grp->modp = ecp_mod_p255; + return ecp_use_curve25519(grp); +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + case MBEDTLS_ECP_DP_CURVE448: + grp->modp = ecp_mod_p448; + return ecp_use_curve448(grp); +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ + + default: + grp->id = MBEDTLS_ECP_DP_NONE; + return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + } +} + +#if defined(MBEDTLS_ECP_NIST_OPTIM) +/* + * Fast reduction modulo the primes used by the NIST curves. + * + * These functions are critical for speed, but not needed for correct + * operations. So, we make the choice to heavily rely on the internals of our + * bignum library, which creates a tight coupling between these functions and + * our MPI implementation. However, the coupling between the ECP module and + * MPI remains loose, since these functions can be deactivated at will. + */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +/* + * The reader is advised to first understand ecp_mod_p192() since the same + * general structure is used here, but with additional complications: + * (1) chunks of 32 bits, and (2) subtractions. + */ + +/* + * For these primes, we need to handle data in chunks of 32 bits. + * This makes it more complicated if we use 64 bits limbs in MPI, + * which prevents us from using a uniform access method as for p192. + * + * So, we define a mini abstraction layer to access 32 bit chunks, + * load them in 'cur' for work, and store them back from 'cur' when done. + * + * While at it, also define the size of N in terms of 32-bit chunks. + */ +#define LOAD32 cur = A(i); + +#if defined(MBEDTLS_HAVE_INT32) /* 32 bit */ + +#define MAX32 N->n +#define A(j) N->p[j] +#define STORE32 N->p[i] = cur; + +#else /* 64-bit */ + +#define MAX32 N->n * 2 +#define A(j) (j) % 2 ? (uint32_t) (N->p[(j)/2] >> 32) : \ + (uint32_t) (N->p[(j)/2]) +#define STORE32 \ + if (i % 2) { \ + N->p[i/2] &= 0x00000000FFFFFFFF; \ + N->p[i/2] |= ((mbedtls_mpi_uint) cur) << 32; \ + } else { \ + N->p[i/2] &= 0xFFFFFFFF00000000; \ + N->p[i/2] |= (mbedtls_mpi_uint) cur; \ + } + +#endif /* sizeof( mbedtls_mpi_uint ) */ + +/* + * Helpers for addition and subtraction of chunks, with signed carry. + */ +static inline void add32(uint32_t *dst, uint32_t src, signed char *carry) +{ + *dst += src; + *carry += (*dst < src); +} + +static inline void sub32(uint32_t *dst, uint32_t src, signed char *carry) +{ + *carry -= (*dst < src); + *dst -= src; +} + +#define ADD(j) add32(&cur, A(j), &c); +#define SUB(j) sub32(&cur, A(j), &c); + +/* + * Helpers for the main 'loop' + */ +#define INIT(b) \ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; \ + signed char c = 0, cc; \ + uint32_t cur; \ + size_t i = 0, bits = (b); \ + /* N is the size of the product of two b-bit numbers, plus one */ \ + /* limb for fix_negative */ \ + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(N, (b) * 2 / biL + 1)); \ + LOAD32; + +#define NEXT \ + STORE32; i++; LOAD32; \ + cc = c; c = 0; \ + if (cc < 0) \ + sub32(&cur, -cc, &c); \ + else \ + add32(&cur, cc, &c); \ + +#define LAST \ + STORE32; i++; \ + cur = c > 0 ? c : 0; STORE32; \ + cur = 0; while (++i < MAX32) { STORE32; } \ + if (c < 0) mbedtls_ecp_fix_negative(N, c, bits); + +/* + * If the result is negative, we get it in the form + * c * 2^bits + N, with c negative and N positive shorter than 'bits' + */ +static void mbedtls_ecp_fix_negative(mbedtls_mpi *N, signed char c, size_t bits) +{ + size_t i; + + /* Set N := 2^bits - 1 - N. We know that 0 <= N < 2^bits, so + * set the absolute value to 0xfff...fff - N. There is no carry + * since we're subtracting from all-bits-one. */ + for (i = 0; i <= bits / 8 / sizeof(mbedtls_mpi_uint); i++) { + N->p[i] = ~(mbedtls_mpi_uint) 0 - N->p[i]; + } + /* Add 1, taking care of the carry. */ + i = 0; + do { + ++N->p[i]; + } while (N->p[i++] == 0 && i <= bits / 8 / sizeof(mbedtls_mpi_uint)); + /* Invert the sign. + * Now N = N0 - 2^bits where N0 is the initial value of N. */ + N->s = -1; + + /* Add |c| * 2^bits to the absolute value. Since c and N are + * negative, this adds c * 2^bits. */ + mbedtls_mpi_uint msw = (mbedtls_mpi_uint) -c; +#if defined(MBEDTLS_HAVE_INT64) + if (bits == 224) { + msw <<= 32; + } +#endif + N->p[bits / 8 / sizeof(mbedtls_mpi_uint)] += msw; +} + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +/* + * Fast quasi-reduction modulo p256 (FIPS 186-3 D.2.3) + */ +static int ecp_mod_p256(mbedtls_mpi *N) +{ + INIT(256); + + ADD(8); ADD(9); + SUB(11); SUB(12); SUB(13); SUB(14); NEXT; // A0 + + ADD(9); ADD(10); + SUB(12); SUB(13); SUB(14); SUB(15); NEXT; // A1 + + ADD(10); ADD(11); + SUB(13); SUB(14); SUB(15); NEXT; // A2 + + ADD(11); ADD(11); ADD(12); ADD(12); ADD(13); + SUB(15); SUB(8); SUB(9); NEXT; // A3 + + ADD(12); ADD(12); ADD(13); ADD(13); ADD(14); + SUB(9); SUB(10); NEXT; // A4 + + ADD(13); ADD(13); ADD(14); ADD(14); ADD(15); + SUB(10); SUB(11); NEXT; // A5 + + ADD(14); ADD(14); ADD(15); ADD(15); ADD(14); ADD(13); + SUB(8); SUB(9); NEXT; // A6 + + ADD(15); ADD(15); ADD(15); ADD(8); + SUB(10); SUB(11); SUB(12); SUB(13); LAST; // A7 + +cleanup: + return ret; +} +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +/* + * Fast quasi-reduction modulo p384 (FIPS 186-3 D.2.4) + */ +static int ecp_mod_p384(mbedtls_mpi *N) +{ + INIT(384); + + ADD(12); ADD(21); ADD(20); + SUB(23); NEXT; // A0 + + ADD(13); ADD(22); ADD(23); + SUB(12); SUB(20); NEXT; // A2 + + ADD(14); ADD(23); + SUB(13); SUB(21); NEXT; // A2 + + ADD(15); ADD(12); ADD(20); ADD(21); + SUB(14); SUB(22); SUB(23); NEXT; // A3 + + ADD(21); ADD(21); ADD(16); ADD(13); ADD(12); ADD(20); ADD(22); + SUB(15); SUB(23); SUB(23); NEXT; // A4 + + ADD(22); ADD(22); ADD(17); ADD(14); ADD(13); ADD(21); ADD(23); + SUB(16); NEXT; // A5 + + ADD(23); ADD(23); ADD(18); ADD(15); ADD(14); ADD(22); + SUB(17); NEXT; // A6 + + ADD(19); ADD(16); ADD(15); ADD(23); + SUB(18); NEXT; // A7 + + ADD(20); ADD(17); ADD(16); + SUB(19); NEXT; // A8 + + ADD(21); ADD(18); ADD(17); + SUB(20); NEXT; // A9 + + ADD(22); ADD(19); ADD(18); + SUB(21); NEXT; // A10 + + ADD(23); ADD(20); ADD(19); + SUB(22); LAST; // A11 + +cleanup: + return ret; +} +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#undef A +#undef LOAD32 +#undef STORE32 +#undef MAX32 +#undef INIT +#undef NEXT +#undef LAST + +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED || + MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +/* + * Here we have an actual Mersenne prime, so things are more straightforward. + * However, chunks are aligned on a 'weird' boundary (521 bits). + */ + +/* Size of p521 in terms of mbedtls_mpi_uint */ +#define P521_WIDTH (521 / 8 / sizeof(mbedtls_mpi_uint) + 1) + +/* Bits to keep in the most significant mbedtls_mpi_uint */ +#define P521_MASK 0x01FF + +/* + * Fast quasi-reduction modulo p521 (FIPS 186-3 D.2.5) + * Write N as A1 + 2^521 A0, return A0 + A1 + */ +static int ecp_mod_p521(mbedtls_mpi *N) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t i; + mbedtls_mpi M; + mbedtls_mpi_uint Mp[P521_WIDTH + 1]; + /* Worst case for the size of M is when mbedtls_mpi_uint is 16 bits: + * we need to hold bits 513 to 1056, which is 34 limbs, that is + * P521_WIDTH + 1. Otherwise P521_WIDTH is enough. */ + + if (N->n < P521_WIDTH) { + return 0; + } + + /* M = A1 */ + M.s = 1; + M.n = N->n - (P521_WIDTH - 1); + if (M.n > P521_WIDTH + 1) { + M.n = P521_WIDTH + 1; + } + M.p = Mp; + memcpy(Mp, N->p + P521_WIDTH - 1, M.n * sizeof(mbedtls_mpi_uint)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&M, 521 % (8 * sizeof(mbedtls_mpi_uint)))); + + /* N = A0 */ + N->p[P521_WIDTH - 1] &= P521_MASK; + for (i = P521_WIDTH; i < N->n; i++) { + N->p[i] = 0; + } + + /* N = A0 + A1 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_add_abs(N, N, &M)); + +cleanup: + return ret; +} + +#undef P521_WIDTH +#undef P521_MASK +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#endif /* MBEDTLS_ECP_NIST_OPTIM */ + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + +/* Size of p255 in terms of mbedtls_mpi_uint */ +#define P255_WIDTH (255 / 8 / sizeof(mbedtls_mpi_uint) + 1) + +/* + * Fast quasi-reduction modulo p255 = 2^255 - 19 + * Write N as A0 + 2^256 A1, return A0 + 38 * A1 + */ +static int ecp_mod_p255(mbedtls_mpi *N) +{ + mbedtls_mpi_uint Mp[P255_WIDTH]; + + /* Helper references for top part of N */ + mbedtls_mpi_uint * const NT_p = N->p + P255_WIDTH; + const size_t NT_n = N->n - P255_WIDTH; + if (N->n <= P255_WIDTH) { + return 0; + } + if (NT_n > P255_WIDTH) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* Split N as N + 2^256 M */ + memcpy(Mp, NT_p, sizeof(mbedtls_mpi_uint) * NT_n); + memset(NT_p, 0, sizeof(mbedtls_mpi_uint) * NT_n); + + /* N = A0 + 38 * A1 */ + mbedtls_mpi_core_mla(N->p, P255_WIDTH + 1, + Mp, NT_n, + 38); + + return 0; +} +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + +/* Size of p448 in terms of mbedtls_mpi_uint */ +#define P448_WIDTH (448 / 8 / sizeof(mbedtls_mpi_uint)) + +/* Number of limbs fully occupied by 2^224 (max), and limbs used by it (min) */ +#define DIV_ROUND_UP(X, Y) (((X) + (Y) -1) / (Y)) +#define P224_SIZE (224 / 8) +#define P224_WIDTH_MIN (P224_SIZE / sizeof(mbedtls_mpi_uint)) +#define P224_WIDTH_MAX DIV_ROUND_UP(P224_SIZE, sizeof(mbedtls_mpi_uint)) +#define P224_UNUSED_BITS ((P224_WIDTH_MAX * sizeof(mbedtls_mpi_uint) * 8) - 224) + +/* + * Fast quasi-reduction modulo p448 = 2^448 - 2^224 - 1 + * Write N as A0 + 2^448 A1 and A1 as B0 + 2^224 B1, and return + * A0 + A1 + B1 + (B0 + B1) * 2^224. This is different to the reference + * implementation of Curve448, which uses its own special 56-bit limbs rather + * than a generic bignum library. We could squeeze some extra speed out on + * 32-bit machines by splitting N up into 32-bit limbs and doing the + * arithmetic using the limbs directly as we do for the NIST primes above, + * but for 64-bit targets it should use half the number of operations if we do + * the reduction with 224-bit limbs, since mpi_add_mpi will then use 64-bit adds. + */ +static int ecp_mod_p448(mbedtls_mpi *N) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t i; + mbedtls_mpi M, Q; + mbedtls_mpi_uint Mp[P448_WIDTH + 1], Qp[P448_WIDTH]; + + if (N->n <= P448_WIDTH) { + return 0; + } + + /* M = A1 */ + M.s = 1; + M.n = N->n - (P448_WIDTH); + if (M.n > P448_WIDTH) { + /* Shouldn't be called with N larger than 2^896! */ + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + M.p = Mp; + memset(Mp, 0, sizeof(Mp)); + memcpy(Mp, N->p + P448_WIDTH, M.n * sizeof(mbedtls_mpi_uint)); + + /* N = A0 */ + for (i = P448_WIDTH; i < N->n; i++) { + N->p[i] = 0; + } + + /* N += A1 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(N, N, &M)); + + /* Q = B1, N += B1 */ + Q = M; + Q.p = Qp; + memcpy(Qp, Mp, sizeof(Qp)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Q, 224)); + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(N, N, &Q)); + + /* M = (B0 + B1) * 2^224, N += M */ + if (sizeof(mbedtls_mpi_uint) > 4) { + Mp[P224_WIDTH_MIN] &= ((mbedtls_mpi_uint)-1) >> (P224_UNUSED_BITS); + } + for (i = P224_WIDTH_MAX; i < M.n; ++i) { + Mp[i] = 0; + } + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&M, &M, &Q)); + M.n = P448_WIDTH + 1; /* Make room for shifted carry bit from the addition */ + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&M, 224)); + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(N, N, &M)); + +cleanup: + return ret; +} +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +/* + * Fast quasi-reduction modulo P = 2^s - R, + * with R about 33 bits, used by the Koblitz curves. + * + * Write N as A0 + 2^224 A1, return A0 + R * A1. + * Actually do two passes, since R is big. + */ +#define P_KOBLITZ_MAX (256 / 8 / sizeof(mbedtls_mpi_uint)) // Max limbs in P +#define P_KOBLITZ_R (8 / sizeof(mbedtls_mpi_uint)) // Limbs in R +static inline int ecp_mod_koblitz(mbedtls_mpi *N, const mbedtls_mpi_uint *Rp, size_t p_limbs, + size_t adjust, size_t shift, mbedtls_mpi_uint mask) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t i; + mbedtls_mpi M, R; + mbedtls_mpi_uint Mp[P_KOBLITZ_MAX + P_KOBLITZ_R + 1]; + + if (N->n < p_limbs) { + return 0; + } + + /* Init R */ + R.s = 1; + R.p = (mbedtls_mpi_uint *) Rp; /* R.p will not be modified so the cast is safe */ + R.n = P_KOBLITZ_R; + + /* Common setup for M */ + M.s = 1; + M.p = Mp; + + /* M = A1 */ + M.n = (unsigned short) (N->n - (p_limbs - adjust)); + if (M.n > p_limbs + adjust) { + M.n = (unsigned short) (p_limbs + adjust); + } + memset(Mp, 0, sizeof(Mp)); + memcpy(Mp, N->p + p_limbs - adjust, M.n * sizeof(mbedtls_mpi_uint)); + if (shift != 0) { + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&M, shift)); + } + M.n += R.n; /* Make room for multiplication by R */ + + /* N = A0 */ + if (mask != 0) { + N->p[p_limbs - 1] &= mask; + } + for (i = p_limbs; i < N->n; i++) { + N->p[i] = 0; + } + + /* N = A0 + R * A1 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&M, &M, &R)); + MBEDTLS_MPI_CHK(mbedtls_mpi_add_abs(N, N, &M)); + + /* Second pass */ + + /* M = A1 */ + M.n = (unsigned short) (N->n - (p_limbs - adjust)); + if (M.n > p_limbs + adjust) { + M.n = (unsigned short) (p_limbs + adjust); + } + memset(Mp, 0, sizeof(Mp)); + memcpy(Mp, N->p + p_limbs - adjust, M.n * sizeof(mbedtls_mpi_uint)); + if (shift != 0) { + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&M, shift)); + } + M.n += R.n; /* Make room for multiplication by R */ + + /* N = A0 */ + if (mask != 0) { + N->p[p_limbs - 1] &= mask; + } + for (i = p_limbs; i < N->n; i++) { + N->p[i] = 0; + } + + /* N = A0 + R * A1 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&M, &M, &R)); + MBEDTLS_MPI_CHK(mbedtls_mpi_add_abs(N, N, &M)); + +cleanup: + return ret; +} +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED) */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +/* + * Fast quasi-reduction modulo p256k1 = 2^256 - R, + * with R = 2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1 = 0x01000003D1 + */ +static int ecp_mod_p256k1(mbedtls_mpi *N) +{ + static const mbedtls_mpi_uint Rp[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD1, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00) + }; + return ecp_mod_koblitz(N, Rp, 256 / 8 / sizeof(mbedtls_mpi_uint), 0, 0, + 0); +} +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +#if defined(MBEDTLS_TEST_HOOKS) + +MBEDTLS_STATIC_TESTABLE +mbedtls_ecp_variant mbedtls_ecp_get_variant(void) +{ + return MBEDTLS_ECP_VARIANT_WITH_MPI_STRUCT; +} + +#endif /* MBEDTLS_TEST_HOOKS */ + +#endif /* MBEDTLS_ECP_LIGHT */ +#endif /* MBEDTLS_ECP_WITH_MPI_UINT */ diff --git a/tf-psa-crypto/drivers/builtin/src/ecp_curves_new.c b/tf-psa-crypto/drivers/builtin/src/ecp_curves_new.c new file mode 100644 index 0000000000..87c46041e4 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/ecp_curves_new.c @@ -0,0 +1,4772 @@ +/* + * Elliptic curves over GF(p): curve-specific data and functions + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_ECP_WITH_MPI_UINT) + +#if defined(MBEDTLS_ECP_LIGHT) + +#include "mbedtls/private/ecp.h" +#include "mbedtls/platform.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#include "mbedtls/platform.h" + +#include "constant_time_internal.h" + +#include "bn_mul.h" +#include "bignum_core.h" +#include "ecp_invasive.h" + +#include + +#define ECP_MPI_INIT(_p, _n) { .p = (mbedtls_mpi_uint *) (_p), .s = 1, .n = (_n) } + +#define ECP_MPI_INIT_ARRAY(x) \ + ECP_MPI_INIT(x, sizeof(x) / sizeof(mbedtls_mpi_uint)) + +#define ECP_POINT_INIT_XY_Z0(x, y) { \ + ECP_MPI_INIT_ARRAY(x), ECP_MPI_INIT_ARRAY(y), ECP_MPI_INIT(NULL, 0) } +#define ECP_POINT_INIT_XY_Z1(x, y) { \ + ECP_MPI_INIT_ARRAY(x), ECP_MPI_INIT_ARRAY(y), ECP_MPI_INIT(mpi_one, 1) } + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +/* For these curves, we build the group parameters dynamically. */ +#define ECP_LOAD_GROUP +static mbedtls_mpi_uint mpi_one[] = { 1 }; +#endif + +/* + * Note: the constants are in little-endian order + * to be directly usable in MPIs + */ + +/* + * Domain parameters for secp256r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +static const mbedtls_mpi_uint secp256r1_p[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF), +}; +static const mbedtls_mpi_uint secp256r1_b[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x4B, 0x60, 0xD2, 0x27, 0x3E, 0x3C, 0xCE, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0xB0, 0x53, 0xCC, 0xB0, 0x06, 0x1D, 0x65), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0x86, 0x98, 0x76, 0x55, 0xBD, 0xEB, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xE7, 0x93, 0x3A, 0xAA, 0xD8, 0x35, 0xC6, 0x5A), +}; +static const mbedtls_mpi_uint secp256r1_gx[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B), +}; +static const mbedtls_mpi_uint secp256r1_gy[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F), +}; +static const mbedtls_mpi_uint secp256r1_n[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3), + MBEDTLS_BYTES_TO_T_UINT_8(0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF), +}; +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 +static const mbedtls_mpi_uint secp256r1_T_0_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B), +}; +static const mbedtls_mpi_uint secp256r1_T_0_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F), +}; +static const mbedtls_mpi_uint secp256r1_T_1_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0xC8, 0xBA, 0x04, 0xB7, 0x4B, 0xD2, 0xF7), + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0xC6, 0x23, 0x3A, 0xA0, 0x09, 0x3A, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x9D, 0x4C, 0xF9, 0x58, 0x23, 0xCC, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x02, 0xED, 0x7B, 0x29, 0x87, 0x0F, 0xFA, 0x3C), +}; +static const mbedtls_mpi_uint secp256r1_T_1_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0x69, 0xF2, 0x40, 0x0B, 0xA3, 0x98, 0xCE), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0xA8, 0x48, 0x02, 0x0D, 0x1C, 0x12, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0xAF, 0x09, 0x83, 0x80, 0xAA, 0x58, 0xA7), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0x12, 0xBE, 0x70, 0x94, 0x76, 0xE3, 0xE4), +}; +static const mbedtls_mpi_uint secp256r1_T_2_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x7D, 0x7D, 0xEF, 0x86, 0xFF, 0xE3, 0x37, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x86, 0x8B, 0x08, 0x27, 0x7C, 0xD7, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0x54, 0x4C, 0x25, 0x4F, 0x9A, 0xFE, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0xFD, 0xF0, 0x6D, 0x37, 0x03, 0x69, 0xD6), +}; +static const mbedtls_mpi_uint secp256r1_T_2_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0xD5, 0xDA, 0xAD, 0x92, 0x49, 0xF0, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0xF9, 0x73, 0x43, 0x9E, 0xAF, 0xA7, 0xD1, 0xF3), + MBEDTLS_BYTES_TO_T_UINT_8(0x67, 0x41, 0x07, 0xDF, 0x78, 0x95, 0x3E, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0x22, 0x3D, 0xD1, 0xE6, 0x3C, 0xA5, 0xE2, 0x20), +}; +static const mbedtls_mpi_uint secp256r1_T_3_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBF, 0x6A, 0x5D, 0x52, 0x35, 0xD7, 0xBF, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0xA2, 0xBE, 0x96, 0xF4, 0xF8, 0x02, 0xC3), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0x20, 0x49, 0x54, 0xEA, 0xB3, 0x82, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0x2E, 0xDB, 0xEA, 0x02, 0xD1, 0x75, 0x1C, 0x62), +}; +static const mbedtls_mpi_uint secp256r1_T_3_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0x85, 0xF4, 0x9E, 0x4C, 0xDC, 0x39, 0x89), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0x6D, 0xC4, 0x57, 0xD8, 0x03, 0x5D, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0x7F, 0x2D, 0x52, 0x6F, 0xC9, 0xDA, 0x4F), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0x64, 0xFA, 0xB4, 0xFE, 0xA4, 0xC4, 0xD7), +}; +static const mbedtls_mpi_uint secp256r1_T_4_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0x37, 0xB9, 0xC0, 0xAA, 0x59, 0xC6, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0x58, 0xD9, 0xED, 0x58, 0x99, 0x65, 0xF7), + MBEDTLS_BYTES_TO_T_UINT_8(0x88, 0x7D, 0x26, 0x8C, 0x4A, 0xF9, 0x05, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0x73, 0x9A, 0xC9, 0xE7, 0x46, 0xDC, 0x00), +}; +static const mbedtls_mpi_uint secp256r1_T_4_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0xD0, 0x55, 0xDF, 0x00, 0x0A, 0xF5, 0x4A), + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0xBF, 0x56, 0x81, 0x2D, 0x20, 0xEB, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0xC1, 0x28, 0x52, 0xAB, 0xE3, 0xD1, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x24, 0x34, 0x79, 0x45, 0x57, 0xA5, 0x12, 0x03), +}; +static const mbedtls_mpi_uint secp256r1_T_5_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEE, 0xCF, 0xB8, 0x7E, 0xF7, 0x92, 0x96, 0x8D), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0x01, 0x8C, 0x0D, 0x23, 0xF2, 0xE3, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0x2E, 0xE3, 0x84, 0x52, 0x7A, 0x34, 0x76), + MBEDTLS_BYTES_TO_T_UINT_8(0xE5, 0xA1, 0xB0, 0x15, 0x90, 0xE2, 0x53, 0x3C), +}; +static const mbedtls_mpi_uint secp256r1_T_5_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0x98, 0xE7, 0xFA, 0xA5, 0x7D, 0x8B, 0x53), + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0x35, 0xD2, 0x00, 0xD1, 0x1B, 0x9F, 0x1B), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0x69, 0x08, 0x9A, 0x72, 0xF0, 0xA9, 0x11), + MBEDTLS_BYTES_TO_T_UINT_8(0xB3, 0xFE, 0x0E, 0x14, 0xDA, 0x7C, 0x0E, 0xD3), +}; +static const mbedtls_mpi_uint secp256r1_T_6_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0xF6, 0xE8, 0xF8, 0x87, 0xF7, 0xFC, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0x90, 0xBE, 0x7F, 0x3F, 0x7A, 0x2B, 0xD7, 0x13), + MBEDTLS_BYTES_TO_T_UINT_8(0xCF, 0x32, 0xF2, 0x2D, 0x94, 0x6D, 0x42, 0xFD), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0x9A, 0xE3, 0x5F, 0x42, 0xBB, 0x84, 0xED), +}; +static const mbedtls_mpi_uint secp256r1_T_6_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x95, 0x29, 0x73, 0xA1, 0x67, 0x3E, 0x02), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x30, 0x54, 0x35, 0x8E, 0x0A, 0xDD, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0x03, 0xD7, 0xA1, 0x97, 0x61, 0x3B, 0xF8, 0x0C), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0x33, 0x3C, 0x58, 0x55, 0x34, 0x23, 0xA3), +}; +static const mbedtls_mpi_uint secp256r1_T_7_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0x5D, 0x16, 0x5F, 0x7B, 0xBC, 0xBB, 0xCE), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0xEE, 0x4E, 0x8A, 0xC1, 0x51, 0xCC, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x0D, 0x4D, 0x1B, 0x53, 0x23, 0x1D, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x2A, 0x38, 0x66, 0x52, 0x84, 0xE1, 0x95), +}; +static const mbedtls_mpi_uint secp256r1_T_7_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0x9B, 0x83, 0x0A, 0x81, 0x4F, 0xAD, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0x0F, 0xFF, 0x42, 0x41, 0x6E, 0xA9, 0xA2, 0xA0), + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0xA1, 0x4F, 0x1F, 0x89, 0x82, 0xAA, 0x3E), + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0xB8, 0x0F, 0x6B, 0x8F, 0x8C, 0xD6, 0x68), +}; +static const mbedtls_mpi_uint secp256r1_T_8_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0xB3, 0xBB, 0x51, 0x69, 0xA2, 0x11, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x4F, 0x0F, 0x8D, 0xBD, 0x26, 0x0F, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0xCB, 0xEC, 0x6B, 0x34, 0xC3, 0x3D, 0x9D), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0x5D, 0x1E, 0x10, 0xD5, 0x44, 0xE2, 0x54), +}; +static const mbedtls_mpi_uint secp256r1_T_8_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x9E, 0xB1, 0xF1, 0x6E, 0x4C, 0xAD, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0xE3, 0xC2, 0x58, 0xC0, 0xFB, 0x34, 0x43), + MBEDTLS_BYTES_TO_T_UINT_8(0x25, 0x9C, 0xDF, 0x35, 0x07, 0x41, 0xBD, 0x19), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x6E, 0x10, 0xEC, 0x0E, 0xEC, 0xBB, 0xD6), +}; +static const mbedtls_mpi_uint secp256r1_T_9_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0xCF, 0xEF, 0x3F, 0x83, 0x1A, 0x88, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0x29, 0xB5, 0xB9, 0xE0, 0xC9, 0xA3, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x88, 0x46, 0x1E, 0x77, 0xCD, 0x7E, 0xB3, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x21, 0xD0, 0xD4, 0xA3, 0x16, 0x08, 0xEE), +}; +static const mbedtls_mpi_uint secp256r1_T_9_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA1, 0xCA, 0xA8, 0xB3, 0xBF, 0x29, 0x99, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0xD1, 0xF2, 0x05, 0xC1, 0xCF, 0x5D, 0x91, 0x48), + MBEDTLS_BYTES_TO_T_UINT_8(0x9F, 0x01, 0x49, 0xDB, 0x82, 0xDF, 0x5F, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0xE1, 0x06, 0x90, 0xAD, 0xE3, 0x38, 0xA4, 0xC4), +}; +static const mbedtls_mpi_uint secp256r1_T_10_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0xD2, 0x3A, 0xE8, 0x03, 0xC5, 0x6D, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0x35, 0xD0, 0xAE, 0x1D, 0x7A, 0x9F, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0x33, 0x1E, 0xD2, 0xCB, 0xAC, 0x88, 0x27, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0xB9, 0x9C, 0xE0, 0x31, 0xDD, 0x99, 0x86), +}; +static const mbedtls_mpi_uint secp256r1_T_10_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0xF9, 0x9B, 0x32, 0x96, 0x41, 0x58, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0xF9, 0x5A, 0x2A, 0xB8, 0x96, 0x0E, 0xB2, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0x78, 0x2C, 0xC7, 0x08, 0x99, 0x19, 0x24), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0x59, 0x28, 0xE9, 0x84, 0x54, 0xE6, 0x16), +}; +static const mbedtls_mpi_uint secp256r1_T_11_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x38, 0x30, 0xDB, 0x70, 0x2C, 0x0A, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x5C, 0x9D, 0xE9, 0xD5, 0x46, 0x0B, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x0B, 0x60, 0x4B, 0x37, 0x7D, 0xB9, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0x24, 0xF3, 0x3D, 0x79, 0x7F, 0x6C, 0x18), +}; +static const mbedtls_mpi_uint secp256r1_T_11_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x7F, 0xE5, 0x1C, 0x4F, 0x60, 0x24, 0xF7, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0xD8, 0xE2, 0x91, 0x7F, 0x89, 0x49, 0x92), + MBEDTLS_BYTES_TO_T_UINT_8(0x97, 0xA7, 0x2E, 0x8D, 0x6A, 0xB3, 0x39, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0x13, 0x89, 0xB5, 0x9A, 0xB8, 0x8D, 0x42, 0x9C), +}; +static const mbedtls_mpi_uint secp256r1_T_12_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0x45, 0xE6, 0x4B, 0x3F, 0x4F, 0x1E, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0x65, 0x5E, 0x59, 0x22, 0xCC, 0x72, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x93, 0x1A, 0x27, 0x1E, 0x34, 0xC5, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0xF2, 0xA5, 0x58, 0x5C, 0x15, 0x2E, 0xC6), +}; +static const mbedtls_mpi_uint secp256r1_T_12_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF4, 0x7F, 0xBA, 0x58, 0x5A, 0x84, 0x6F, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0xA6, 0x36, 0x7E, 0xDC, 0xF7, 0xE1, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x4D, 0xAA, 0xEE, 0x57, 0x76, 0x3A, 0xD3), + MBEDTLS_BYTES_TO_T_UINT_8(0x4E, 0x7E, 0x26, 0x18, 0x22, 0x23, 0x9F, 0xFF), +}; +static const mbedtls_mpi_uint secp256r1_T_13_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x4C, 0x64, 0xC7, 0x55, 0x02, 0x3F, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0x02, 0x90, 0xBB, 0xC3, 0xEC, 0x30, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x9F, 0x6F, 0x64, 0xF4, 0x16, 0x69, 0x48, 0xA4), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x44, 0x9C, 0x95, 0x0C, 0x7D, 0x67, 0x5E), +}; +static const mbedtls_mpi_uint secp256r1_T_13_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x44, 0x91, 0x8B, 0xD8, 0xD0, 0xD7, 0xE7, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0xF9, 0x48, 0x62, 0x6F, 0xA8, 0x93, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0x3A, 0x99, 0x02, 0xD5, 0x0B, 0x3D, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xD3, 0x00, 0x31, 0xE6, 0x0C, 0x9F, 0x44), +}; +static const mbedtls_mpi_uint secp256r1_T_14_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x56, 0xB2, 0xAA, 0xFD, 0x88, 0x15, 0xDF, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0x4C, 0x35, 0x27, 0x31, 0x44, 0xCD, 0xC0, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0x53, 0xF8, 0x91, 0xA5, 0x71, 0x94, 0x84, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0xCB, 0xD0, 0x93, 0xE9, 0x88, 0xDA, 0xE4), +}; +static const mbedtls_mpi_uint secp256r1_T_14_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x24, 0xC6, 0x39, 0x16, 0x5D, 0xA3, 0x1E, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x07, 0x37, 0x26, 0x36, 0x2A, 0xFE, 0x60), + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0xBC, 0xF3, 0xD0, 0xDE, 0x50, 0xFC, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0x80, 0x2E, 0x06, 0x10, 0x15, 0x4D, 0xFA, 0xF7), +}; +static const mbedtls_mpi_uint secp256r1_T_15_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0x65, 0x69, 0x5B, 0x66, 0xA2, 0x75, 0x2E), + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0x16, 0x00, 0x5A, 0xB0, 0x30, 0x25, 0x1A), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0xFB, 0x86, 0x42, 0x80, 0xC1, 0xC4, 0x76), + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0x1D, 0x83, 0x8E, 0x94, 0x01, 0x5F, 0x82), +}; +static const mbedtls_mpi_uint secp256r1_T_15_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x39, 0x37, 0x70, 0xEF, 0x1F, 0xA1, 0xF0, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0x10, 0x5B, 0xCE, 0xC4, 0x9B, 0x6F, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x11, 0x11, 0x24, 0x4F, 0x4C, 0x79, 0x61), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0x3A, 0x72, 0xBC, 0xFE, 0x72, 0x58, 0x43), +}; +static const mbedtls_ecp_point secp256r1_T[16] = { + ECP_POINT_INIT_XY_Z1(secp256r1_T_0_X, secp256r1_T_0_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_1_X, secp256r1_T_1_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_2_X, secp256r1_T_2_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_3_X, secp256r1_T_3_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_4_X, secp256r1_T_4_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_5_X, secp256r1_T_5_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_6_X, secp256r1_T_6_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_7_X, secp256r1_T_7_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_8_X, secp256r1_T_8_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_9_X, secp256r1_T_9_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_10_X, secp256r1_T_10_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_11_X, secp256r1_T_11_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_12_X, secp256r1_T_12_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_13_X, secp256r1_T_13_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_14_X, secp256r1_T_14_Y), + ECP_POINT_INIT_XY_Z0(secp256r1_T_15_X, secp256r1_T_15_Y), +}; +#else +#define secp256r1_T NULL +#endif + +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +/* + * Domain parameters for secp384r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +static const mbedtls_mpi_uint secp384r1_p[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), +}; +static const mbedtls_mpi_uint secp384r1_b[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0x2A, 0xEC, 0xD3, 0xED, 0xC8, 0x85, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0xD1, 0x2E, 0x8A, 0x8D, 0x39, 0x56, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x87, 0x13, 0x50, 0x8F, 0x08, 0x14, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0x12, 0x41, 0x81, 0xFE, 0x6E, 0x9C, 0x1D, 0x18), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x2D, 0xF8, 0xE3, 0x6B, 0x05, 0x8E, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0xE7, 0x3E, 0xE2, 0xA7, 0x2F, 0x31, 0xB3), +}; +static const mbedtls_mpi_uint secp384r1_gx[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0x0A, 0x76, 0x72, 0x38, 0x5E, 0x54, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x29, 0x55, 0xBF, 0x5D, 0xF2, 0x02, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0x2A, 0x54, 0x82, 0xE0, 0x41, 0xF7, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x9B, 0xA7, 0x8B, 0x62, 0x3B, 0x1D, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0xAD, 0x20, 0xF3, 0x1E, 0xC7, 0xB1, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x05, 0x8B, 0xBE, 0x22, 0xCA, 0x87, 0xAA), +}; +static const mbedtls_mpi_uint secp384r1_gy[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x0E, 0xEA, 0x90, 0x7C, 0x1D, 0x43, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0x81, 0x7E, 0x1D, 0xCE, 0xB1, 0x60, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0xB8, 0xF0, 0xB5, 0x13, 0x31, 0xDA, 0xE9), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x14, 0x9A, 0x28, 0xBD, 0x1D, 0xF4, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0xDC, 0x92, 0x92, 0xBF, 0x98, 0x9E, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x6F, 0x2C, 0x26, 0x96, 0x4A, 0xDE, 0x17, 0x36), +}; +static const mbedtls_mpi_uint secp384r1_n[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x73, 0x29, 0xC5, 0xCC, 0x6A, 0x19, 0xEC, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0x7A, 0xA7, 0xB0, 0x48, 0xB2, 0x0D, 0x1A, 0x58), + MBEDTLS_BYTES_TO_T_UINT_8(0xDF, 0x2D, 0x37, 0xF4, 0x81, 0x4D, 0x63, 0xC7), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), +}; +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 +static const mbedtls_mpi_uint secp384r1_T_0_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0x0A, 0x76, 0x72, 0x38, 0x5E, 0x54, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x29, 0x55, 0xBF, 0x5D, 0xF2, 0x02, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0x2A, 0x54, 0x82, 0xE0, 0x41, 0xF7, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x9B, 0xA7, 0x8B, 0x62, 0x3B, 0x1D, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0xAD, 0x20, 0xF3, 0x1E, 0xC7, 0xB1, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x05, 0x8B, 0xBE, 0x22, 0xCA, 0x87, 0xAA), +}; +static const mbedtls_mpi_uint secp384r1_T_0_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x0E, 0xEA, 0x90, 0x7C, 0x1D, 0x43, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0x81, 0x7E, 0x1D, 0xCE, 0xB1, 0x60, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0xB8, 0xF0, 0xB5, 0x13, 0x31, 0xDA, 0xE9), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x14, 0x9A, 0x28, 0xBD, 0x1D, 0xF4, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0xDC, 0x92, 0x92, 0xBF, 0x98, 0x9E, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x6F, 0x2C, 0x26, 0x96, 0x4A, 0xDE, 0x17, 0x36), +}; +static const mbedtls_mpi_uint secp384r1_T_1_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0x92, 0x00, 0x2C, 0x78, 0xDB, 0x1F, 0x37), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0xF3, 0xEB, 0xB7, 0x06, 0xF7, 0xB6, 0xBC), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0xBC, 0x2C, 0xCF, 0xD8, 0xED, 0x53, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0x75, 0x7B, 0xA3, 0xAB, 0xC3, 0x2C, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0xE5, 0x9D, 0x78, 0x41, 0xF6, 0x76, 0x84, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0x54, 0x56, 0xE8, 0x52, 0xB3, 0xCB, 0xA8, 0xBD), +}; +static const mbedtls_mpi_uint secp384r1_T_1_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0xF2, 0xAE, 0xA4, 0xB6, 0x89, 0x1B, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0x0F, 0xCE, 0x1C, 0x7C, 0xF6, 0x50, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0x4C, 0xEB, 0x90, 0xE6, 0x4D, 0xC7, 0xD4, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0xD1, 0x49, 0x2D, 0x8A, 0x01, 0x99, 0x60, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x80, 0x9B, 0x9B, 0x6A, 0xB0, 0x07, 0xD9), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0xA2, 0xEE, 0x59, 0xBE, 0x95, 0xBC, 0x23), +}; +static const mbedtls_mpi_uint secp384r1_T_2_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0x9D, 0x56, 0xAE, 0x59, 0xFB, 0x1F, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0xCF, 0xAC, 0x91, 0x80, 0x87, 0xA8, 0x6E, 0x58), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0x08, 0xA7, 0x08, 0x94, 0x32, 0xFC, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0x9F, 0x29, 0x9E, 0x84, 0xF4, 0xE5, 0x6E, 0x7E), + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0x21, 0xB9, 0x50, 0x24, 0xF8, 0x9C, 0xC7), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0x04, 0x01, 0xC2, 0xFB, 0x77, 0x3E, 0xDE), +}; +static const mbedtls_mpi_uint secp384r1_T_2_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x38, 0xEE, 0xE3, 0xC7, 0x9D, 0xEC, 0xA6), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x88, 0xCF, 0x43, 0xFA, 0x92, 0x5E, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0xCA, 0x43, 0xF8, 0x3B, 0x49, 0x7E, 0x75), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0xE7, 0xEB, 0x17, 0x45, 0x86, 0xC2, 0xE1), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x69, 0x57, 0x32, 0xE0, 0x9C, 0xD1, 0x00), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x10, 0xB8, 0x4D, 0xB8, 0xF4, 0x0D, 0xE3), +}; +static const mbedtls_mpi_uint secp384r1_T_3_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x60, 0xDC, 0x9A, 0xB2, 0x79, 0x39, 0x27, 0x16), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0x71, 0xE4, 0x3B, 0x4D, 0x60, 0x0C, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0xBD, 0x19, 0x40, 0xFA, 0x19, 0x2A, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0x4D, 0xF8, 0x1E, 0x43, 0xA1, 0x50, 0x8D, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0xA3, 0x18, 0x7C, 0x41, 0xFA, 0x7C, 0x1B, 0x58), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x59, 0x24, 0xC4, 0xE9, 0xB7, 0xD3, 0xAD), +}; +static const mbedtls_mpi_uint secp384r1_T_3_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0x01, 0x3D, 0x63, 0x54, 0x45, 0x6F, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0xB2, 0x19, 0xA3, 0x86, 0x1D, 0x42, 0x34), + MBEDTLS_BYTES_TO_T_UINT_8(0x84, 0x02, 0x87, 0x18, 0x92, 0x52, 0x1A, 0x71), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x18, 0xB1, 0x5D, 0x18, 0x1B, 0x37, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0xF4, 0x74, 0x61, 0xBA, 0x18, 0xAF, 0x40, 0x30), + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x7D, 0x3C, 0x52, 0x0F, 0x07, 0xB0, 0x6F), +}; +static const mbedtls_mpi_uint secp384r1_T_4_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0x39, 0x13, 0xAA, 0x60, 0x15, 0x99, 0x30), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0x00, 0xCB, 0xC6, 0xB1, 0xDB, 0x97, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0xFA, 0x60, 0xB8, 0x24, 0xE4, 0x7D, 0xD3), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x75, 0xB3, 0x70, 0xB2, 0x83, 0xB1, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0xA3, 0xE3, 0x6C, 0xCD, 0x33, 0x62, 0x7A, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0x88, 0x30, 0xDC, 0x0F, 0x9F, 0xBB, 0xB8, 0xAA), +}; +static const mbedtls_mpi_uint secp384r1_T_4_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA6, 0xD5, 0x0A, 0x60, 0x81, 0xB9, 0xC5, 0x16), + MBEDTLS_BYTES_TO_T_UINT_8(0x44, 0xAA, 0x2F, 0xD6, 0xF2, 0x73, 0xDF, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0x7B, 0x74, 0xC9, 0xB3, 0x5B, 0x95, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x04, 0xEB, 0x15, 0xC8, 0x5F, 0x00, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0xB5, 0x50, 0x20, 0x28, 0xD1, 0x01, 0xAF, 0xF0), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x6D, 0x4F, 0x31, 0x81, 0x2F, 0x94, 0x48), +}; +static const mbedtls_mpi_uint secp384r1_T_5_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0x2F, 0xD8, 0xB6, 0x63, 0x7C, 0xE9, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x8C, 0xB9, 0x14, 0xD9, 0x37, 0x63, 0xDE), + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0x02, 0xB8, 0x46, 0xAD, 0xCE, 0x7B, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0x82, 0x47, 0x2D, 0x66, 0xA7, 0xE9, 0x33, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0xF9, 0x93, 0x94, 0xA8, 0x48, 0xB3, 0x4F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0x4A, 0xAC, 0x51, 0x08, 0x72, 0x2F, 0x1A), +}; +static const mbedtls_mpi_uint secp384r1_T_5_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0xAD, 0xA0, 0xF9, 0x81, 0xE1, 0x78, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0x9A, 0x63, 0xD8, 0xBA, 0x79, 0x1A, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0x31, 0x7B, 0x7A, 0x5A, 0x5D, 0x7D, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x96, 0x12, 0x4B, 0x19, 0x09, 0xE0, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0x8A, 0x57, 0xEE, 0x4E, 0x6E, 0x7E, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0x9D, 0x69, 0xDC, 0xB3, 0xDA, 0xD8, 0x08), +}; +static const mbedtls_mpi_uint secp384r1_T_6_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x49, 0x03, 0x03, 0x33, 0x6F, 0x28, 0x4A), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0xDB, 0xA7, 0x05, 0x8C, 0xF3, 0x4D, 0xFB), + MBEDTLS_BYTES_TO_T_UINT_8(0x8E, 0x92, 0xB1, 0xA8, 0xEC, 0x0D, 0x64, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0x4E, 0xFC, 0xFD, 0xD0, 0x4B, 0x88, 0x1B, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x9C, 0x51, 0x69, 0xCE, 0x71, 0x73, 0xF5), + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0x5A, 0x14, 0x23, 0x1A, 0x46, 0x63, 0x5F), +}; +static const mbedtls_mpi_uint secp384r1_T_6_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0x4C, 0x70, 0x44, 0x18, 0xCD, 0xEF, 0xED), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x49, 0xDD, 0x64, 0x7E, 0x7E, 0x4D, 0x92), + MBEDTLS_BYTES_TO_T_UINT_8(0xA2, 0x32, 0x7C, 0x09, 0xD0, 0x3F, 0xD6, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0xE0, 0x4F, 0x65, 0x0C, 0x7A, 0x54, 0x3E), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0xFA, 0xFB, 0x4A, 0xB4, 0x79, 0x5A, 0x8C), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x5D, 0x1B, 0x2B, 0xDA, 0xBC, 0x9A, 0x74), +}; +static const mbedtls_mpi_uint secp384r1_T_7_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0xAC, 0x56, 0xF7, 0x5F, 0x51, 0x68, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0xE0, 0x1D, 0xBC, 0x13, 0x4E, 0xAC, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0xF5, 0xC5, 0xE6, 0xD2, 0x88, 0xBA, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x0E, 0x28, 0x23, 0x58, 0x67, 0xFA, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0x9E, 0x80, 0x4B, 0xD8, 0xC4, 0xDF, 0x15, 0xE4), + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x0E, 0x58, 0xE6, 0x2C, 0x59, 0xC2, 0x03), +}; +static const mbedtls_mpi_uint secp384r1_T_7_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x26, 0x27, 0x99, 0x16, 0x2B, 0x22, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0xF3, 0x8F, 0xC3, 0x2A, 0x9B, 0xFC, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x2E, 0x83, 0x3D, 0xFE, 0x9E, 0x3C, 0x1B), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0x57, 0xCD, 0x2D, 0xC1, 0x49, 0x38, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0x42, 0x8B, 0x33, 0x89, 0x1F, 0xEA, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0xAA, 0x1D, 0x13, 0xD7, 0x50, 0xBB, 0x3E, 0xEB), +}; +static const mbedtls_mpi_uint secp384r1_T_8_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD2, 0x9A, 0x52, 0xD2, 0x54, 0x7C, 0x97, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0xE0, 0x33, 0x6E, 0xED, 0xD9, 0x87, 0x50, 0xC5), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x35, 0x7E, 0x16, 0x40, 0x15, 0x83, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0x33, 0x2B, 0xA4, 0xAB, 0x03, 0x91, 0xEA, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0x47, 0x39, 0xEF, 0x05, 0x59, 0xD0, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0xBF, 0x24, 0x0D, 0x76, 0x11, 0x53, 0x08, 0xAF), +}; +static const mbedtls_mpi_uint secp384r1_T_8_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x2F, 0xDD, 0xBD, 0x50, 0x48, 0xB1, 0xE5), + MBEDTLS_BYTES_TO_T_UINT_8(0x80, 0x1C, 0x84, 0x55, 0x78, 0x14, 0xEB, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x5E, 0x3E, 0xA6, 0xAF, 0xF6, 0xC7, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0xE7, 0x11, 0xE2, 0x65, 0xCA, 0x41, 0x95, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0x83, 0xD8, 0xE6, 0x4D, 0x22, 0x06, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x7F, 0x25, 0x2A, 0xAA, 0x28, 0x46, 0x97), +}; +static const mbedtls_mpi_uint secp384r1_T_9_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x79, 0xDB, 0x15, 0x56, 0x84, 0xCB, 0xC0, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0x56, 0xDB, 0x0E, 0x08, 0xC9, 0xF5, 0xD4, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0x62, 0xD0, 0x1A, 0x7C, 0x13, 0xD5, 0x07), + MBEDTLS_BYTES_TO_T_UINT_8(0x7D, 0xAD, 0x53, 0xE0, 0x32, 0x21, 0xA0, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0x38, 0x81, 0x21, 0x23, 0x0E, 0xD2, 0xBB), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x51, 0x05, 0xD0, 0x1E, 0x82, 0xA9, 0x71), +}; +static const mbedtls_mpi_uint secp384r1_T_9_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0xC3, 0x27, 0xBF, 0xC6, 0xAA, 0xB7, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x65, 0x45, 0xDF, 0xB9, 0x46, 0x17, 0x46), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0x38, 0x3F, 0xB2, 0xB1, 0x5D, 0xCA, 0x1C), + MBEDTLS_BYTES_TO_T_UINT_8(0x88, 0x29, 0x6C, 0x63, 0xE9, 0xD7, 0x48, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0xF1, 0xD7, 0x99, 0x8C, 0xC2, 0x05, 0x99), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0xE6, 0x5E, 0x82, 0x6D, 0xE5, 0x7E, 0xD5), +}; +static const mbedtls_mpi_uint secp384r1_T_10_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0x61, 0xFA, 0x7D, 0x01, 0xDB, 0xB6, 0x63), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0xC6, 0x58, 0x39, 0xF4, 0xC6, 0x82, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0x5A, 0x7A, 0x80, 0x08, 0xCD, 0xAA, 0xD8), + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x8C, 0xC6, 0x3F, 0x3C, 0xA5, 0x68, 0xF4), + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0xF5, 0xD5, 0x17, 0xAE, 0x36, 0xD8, 0x8A), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0xAD, 0x92, 0xC5, 0x57, 0x6C, 0xDA, 0x91), +}; +static const mbedtls_mpi_uint secp384r1_T_10_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x67, 0x17, 0xC0, 0x40, 0x78, 0x8C, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0x9F, 0xF4, 0xAA, 0xDA, 0x5C, 0x7E, 0xB2), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0xDB, 0x42, 0x3E, 0x72, 0x64, 0xA0, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0xF9, 0x41, 0x17, 0x43, 0xE3, 0xE8, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0xDD, 0xCC, 0x43, 0x7E, 0x16, 0x05, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0x4B, 0xCF, 0x48, 0x8F, 0x41, 0x90, 0xE5), +}; +static const mbedtls_mpi_uint secp384r1_T_11_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x0C, 0x6B, 0x9D, 0x22, 0x04, 0xBC, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0x63, 0x79, 0x2F, 0x6A, 0x0E, 0x8A, 0xDE), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0x67, 0x3F, 0x02, 0xB8, 0x91, 0x7F, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x14, 0x64, 0xA0, 0x33, 0xF4, 0x6B, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x44, 0x71, 0x87, 0xB8, 0x88, 0x3F, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0x1B, 0x2B, 0x85, 0x05, 0xC5, 0x44, 0x53, 0x15), +}; +static const mbedtls_mpi_uint secp384r1_T_11_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0x2B, 0xFE, 0xD1, 0x1C, 0x73, 0xE3, 0x2E), + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0x33, 0xA1, 0xD3, 0x69, 0x1C, 0x9D, 0xD2), + MBEDTLS_BYTES_TO_T_UINT_8(0xE0, 0x5A, 0xBA, 0xB6, 0xAE, 0x1B, 0x94, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0x74, 0x90, 0x5C, 0x57, 0xB0, 0x3A, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x2F, 0x93, 0x20, 0x24, 0x54, 0x1D, 0x8D), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x78, 0x9D, 0x71, 0x67, 0x5D, 0x49, 0x98), +}; +static const mbedtls_mpi_uint secp384r1_T_12_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x12, 0xC8, 0x0E, 0x11, 0x8D, 0xE0, 0x8F, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0x7F, 0x79, 0x6C, 0x5F, 0xB7, 0xBC, 0xB1), + MBEDTLS_BYTES_TO_T_UINT_8(0x88, 0xE1, 0x83, 0x3C, 0x12, 0xBB, 0xEE, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0xC2, 0xC4, 0x1B, 0x41, 0x71, 0xB9, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0xEE, 0xBB, 0x1D, 0x89, 0x50, 0x88, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x1C, 0x55, 0x74, 0xEB, 0xDE, 0x92, 0x3F), +}; +static const mbedtls_mpi_uint secp384r1_T_12_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0x38, 0x92, 0x06, 0x19, 0xD0, 0xB3, 0xB2), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0x99, 0x26, 0xA3, 0x5F, 0xE2, 0xC1, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0x75, 0xFC, 0xFD, 0xC3, 0xB6, 0x26, 0x24, 0x8F), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0xAD, 0xE7, 0x49, 0xB7, 0x64, 0x4B, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x4E, 0x95, 0xAD, 0x07, 0xFE, 0xB6, 0x30), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0x15, 0xE7, 0x2D, 0x19, 0xA9, 0x08, 0x10), +}; +static const mbedtls_mpi_uint secp384r1_T_13_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0xBD, 0xAC, 0x0A, 0x3F, 0x6B, 0xFF, 0xFA), + MBEDTLS_BYTES_TO_T_UINT_8(0xE0, 0xE4, 0x74, 0x14, 0xD9, 0x70, 0x1D, 0x71), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0xB0, 0x71, 0xBB, 0xD8, 0x18, 0x96, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0xB8, 0x19, 0x90, 0x80, 0xB5, 0xEE, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0x21, 0x20, 0xA6, 0x17, 0x48, 0x03, 0x6F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x1D, 0xBB, 0x6D, 0x94, 0x20, 0x34, 0xF1), +}; +static const mbedtls_mpi_uint secp384r1_T_13_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0x82, 0x67, 0x4B, 0x8E, 0x4E, 0xBE, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0xDA, 0x77, 0xF8, 0x23, 0x55, 0x2B, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0x02, 0xDE, 0x25, 0x35, 0x2D, 0x74, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0xD0, 0x0C, 0xB8, 0x0B, 0x39, 0xBA, 0xAD, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0xA6, 0x0E, 0x28, 0x4D, 0xE1, 0x3D, 0xE4, 0x1B), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0xEC, 0x0A, 0xD4, 0xB8, 0xC4, 0x8D, 0xB0), +}; +static const mbedtls_mpi_uint secp384r1_T_14_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0x68, 0xCE, 0xC2, 0x55, 0x4D, 0x0C, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x20, 0x93, 0x32, 0x90, 0xD6, 0xAE, 0x47), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x78, 0xAB, 0x43, 0x9E, 0xEB, 0x73, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0x97, 0xC3, 0x83, 0xA6, 0x3C, 0xF1, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0x0F, 0x25, 0x25, 0x66, 0x08, 0x26, 0xFA, 0x4B), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0xFB, 0x44, 0x5D, 0x82, 0xEC, 0x3B, 0xAC), +}; +static const mbedtls_mpi_uint secp384r1_T_14_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0x90, 0xEA, 0xB5, 0x04, 0x99, 0xD0, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0x4A, 0xF2, 0x22, 0xA0, 0xEB, 0xFD, 0x45, 0x87), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0xA4, 0x81, 0x32, 0xFC, 0xFA, 0xEE, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0xBB, 0xA4, 0x6A, 0x77, 0x41, 0x5C, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0xA1, 0x1E, 0xAA, 0x4F, 0xF0, 0x10, 0xB3, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0x74, 0x13, 0x14, 0x9E, 0x90, 0xD7, 0xE6), +}; +static const mbedtls_mpi_uint secp384r1_T_15_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0xBD, 0x70, 0x4F, 0xA8, 0xD1, 0x06, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x4E, 0x2E, 0x68, 0xFC, 0x35, 0xFA, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x60, 0x53, 0x75, 0xED, 0xF2, 0x5F, 0xC2, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0x39, 0x87, 0x6B, 0x9F, 0x05, 0xE2, 0x22, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0x1A, 0xA8, 0xB7, 0x03, 0x9E, 0x6D, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0xD0, 0x69, 0x88, 0xA8, 0x39, 0x9E, 0x3A), +}; +static const mbedtls_mpi_uint secp384r1_T_15_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0xEF, 0x68, 0xFE, 0xEC, 0x24, 0x08, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0xA1, 0x06, 0x4B, 0x92, 0x0D, 0xB7, 0x34, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0xF4, 0xDD, 0x1A, 0xA0, 0x4A, 0xE4, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0xC3, 0x63, 0x4F, 0x4F, 0xCE, 0xBB, 0xD6, 0xD3), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0xEE, 0x8D, 0xDF, 0x3F, 0x73, 0xB7, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0xDF, 0x06, 0xB6, 0x80, 0x4D, 0x81, 0xD9, 0x53), +}; +static const mbedtls_mpi_uint secp384r1_T_16_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0xF5, 0x13, 0xDF, 0x13, 0x19, 0x97, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0xF9, 0xB3, 0x33, 0x66, 0x82, 0x21, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xFC, 0x39, 0x16, 0x23, 0x43, 0x76, 0x0E), + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0x48, 0x25, 0xA1, 0x64, 0x95, 0x1C, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x43, 0xAC, 0x15, 0x57, 0xD9, 0xDE, 0xA0, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0x5F, 0xB8, 0x3D, 0x48, 0x91, 0x24, 0xCC), +}; +static const mbedtls_mpi_uint secp384r1_T_16_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0xF2, 0xC8, 0x54, 0xD1, 0x32, 0xBD, 0xC4), + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0x3B, 0xF0, 0xAA, 0x9D, 0xD8, 0xF4, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0xC3, 0xBB, 0x6C, 0x66, 0xAC, 0x25, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x6F, 0x25, 0x10, 0xB2, 0xE1, 0x41, 0xDE, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0xE8, 0x30, 0xB8, 0x37, 0xBC, 0x2A, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x57, 0x01, 0x4A, 0x1E, 0x78, 0x9F, 0x85), +}; +static const mbedtls_mpi_uint secp384r1_T_17_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBD, 0x19, 0xCD, 0x12, 0x0B, 0x51, 0x4F, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0x4B, 0x3D, 0x24, 0xA4, 0x16, 0x59, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xEB, 0xD3, 0x59, 0x2E, 0x75, 0x7C, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0xB9, 0xB4, 0xA5, 0xD9, 0x2E, 0x29, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0x16, 0x05, 0x75, 0x02, 0xB3, 0x06, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0x7C, 0x9F, 0x79, 0x91, 0xF1, 0x4F, 0x23), +}; +static const mbedtls_mpi_uint secp384r1_T_17_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x98, 0x7C, 0x84, 0xE1, 0xFF, 0x30, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0xE2, 0xC2, 0x5F, 0x55, 0x40, 0xBD, 0xCD), + MBEDTLS_BYTES_TO_T_UINT_8(0x69, 0x65, 0x87, 0x3F, 0xC4, 0xC2, 0x24, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0x30, 0x0A, 0x60, 0x15, 0xD1, 0x24, 0x48), + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0x99, 0xD9, 0xB6, 0xAE, 0xB1, 0xAF, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x80, 0xEE, 0xA2, 0x0F, 0x74, 0xB9, 0xF3), +}; +static const mbedtls_mpi_uint secp384r1_T_18_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x03, 0xE6, 0x0F, 0x37, 0xC1, 0x10, 0x99, 0x1E), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0xAD, 0x9D, 0x5D, 0x80, 0x01, 0xA6, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x0F, 0x10, 0x2A, 0x9D, 0x20, 0x38, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x60, 0xCB, 0xCE, 0x5A, 0xA0, 0xA7, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0xCF, 0x14, 0xDF, 0xBF, 0xE5, 0x74, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0xB5, 0x12, 0x1A, 0xDD, 0x59, 0x02, 0x5D, 0xC6), +}; +static const mbedtls_mpi_uint secp384r1_T_18_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0xC9, 0xF8, 0xF5, 0xB6, 0x13, 0x4D, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0x45, 0xB1, 0x93, 0xB3, 0xA2, 0x79, 0xDC), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0xF6, 0xCF, 0xF7, 0xE6, 0x29, 0x9C, 0xCC), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0x50, 0x65, 0x80, 0xBC, 0x59, 0x0A, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0xF0, 0x24, 0x35, 0xA2, 0x46, 0xF0, 0x0C), + MBEDTLS_BYTES_TO_T_UINT_8(0xBD, 0x26, 0xC0, 0x9D, 0x61, 0x56, 0x62, 0x67), +}; +static const mbedtls_mpi_uint secp384r1_T_19_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0xBB, 0xC2, 0x24, 0x43, 0x2E, 0x37, 0x54), + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0xF7, 0xCE, 0x35, 0xFC, 0x77, 0xF3, 0x3F), + MBEDTLS_BYTES_TO_T_UINT_8(0x75, 0x34, 0x96, 0xD5, 0x4A, 0x76, 0x9D, 0x6B), + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0x3B, 0x0F, 0xEA, 0xA8, 0x12, 0x0B, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0x3F, 0x5D, 0x2D, 0x1C, 0xD4, 0x9E, 0xFB), + MBEDTLS_BYTES_TO_T_UINT_8(0x7D, 0x2E, 0xDD, 0xC7, 0x6E, 0xAB, 0xAF, 0xDC), +}; +static const mbedtls_mpi_uint secp384r1_T_19_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0xB2, 0x7B, 0x0C, 0x9A, 0x83, 0x8E, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0x51, 0x90, 0x92, 0x79, 0x32, 0x19, 0xC3), + MBEDTLS_BYTES_TO_T_UINT_8(0xEE, 0x89, 0xF9, 0xD0, 0xCF, 0x2C, 0xA5, 0x8F), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0x50, 0x21, 0xDE, 0x50, 0x41, 0x9D, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0xE0, 0x7D, 0x2B, 0x9E, 0x9D, 0x95, 0xA8, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0xA5, 0x20, 0x87, 0x88, 0x97, 0x5F, 0xAA), +}; +static const mbedtls_mpi_uint secp384r1_T_20_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x59, 0xB4, 0x66, 0x7E, 0xE8, 0x5A, 0x60), + MBEDTLS_BYTES_TO_T_UINT_8(0xA5, 0x5C, 0x7E, 0xB2, 0xAD, 0xD9, 0xC9, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0x82, 0x97, 0x49, 0xA3, 0x13, 0x83, 0x07, 0x2E), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x26, 0xC7, 0x13, 0x35, 0x0D, 0xB0, 0x6B), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0x60, 0xAB, 0xFA, 0x4B, 0x93, 0x18, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x54, 0x2D, 0x1C, 0x31, 0x4C, 0xE4, 0x61, 0xAE), +}; +static const mbedtls_mpi_uint secp384r1_T_20_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xDE, 0x4D, 0x1E, 0x51, 0x59, 0x6E, 0x91, 0xC5), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0x54, 0x4D, 0x51, 0xED, 0x36, 0xCC, 0x60), + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0xA8, 0x56, 0xC7, 0x78, 0x27, 0x33, 0xC5), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0xB7, 0x95, 0xC9, 0x8B, 0xC8, 0x6A, 0xBC), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0xE9, 0x13, 0x96, 0xB3, 0xE1, 0xF9, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0x46, 0xB0, 0x5E, 0xC3, 0x94, 0x03, 0x05), +}; +static const mbedtls_mpi_uint secp384r1_T_21_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x5B, 0x29, 0x30, 0x41, 0x1A, 0x9E, 0xB6), + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0xCA, 0x83, 0x31, 0x5B, 0xA7, 0xCB, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0x41, 0x50, 0x44, 0x4D, 0x64, 0x31, 0x89), + MBEDTLS_BYTES_TO_T_UINT_8(0xCF, 0x84, 0xC2, 0x5D, 0x97, 0xA5, 0x3C, 0x18), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0x0F, 0xA5, 0xFD, 0x8E, 0x5A, 0x47, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x58, 0x02, 0x2D, 0x40, 0xB1, 0x0B, 0xBA), +}; +static const mbedtls_mpi_uint secp384r1_T_21_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x33, 0x8C, 0x67, 0xCE, 0x23, 0x43, 0x99), + MBEDTLS_BYTES_TO_T_UINT_8(0x84, 0x53, 0x47, 0x72, 0x44, 0x1F, 0x5B, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0xC1, 0xD9, 0xA4, 0x50, 0x88, 0x63, 0x18), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0xF2, 0x75, 0x69, 0x73, 0x00, 0xC4, 0x31), + MBEDTLS_BYTES_TO_T_UINT_8(0x4B, 0x90, 0x1D, 0xDF, 0x1A, 0x00, 0xD8, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0x05, 0xB1, 0x89, 0x48, 0xA8, 0x70, 0x62, 0xEF), +}; +static const mbedtls_mpi_uint secp384r1_T_22_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0x8A, 0x55, 0x50, 0x7B, 0xEF, 0x8A, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0xFE, 0x1B, 0x23, 0x48, 0x23, 0x63, 0x91, 0xB6), + MBEDTLS_BYTES_TO_T_UINT_8(0x0D, 0x04, 0x54, 0x3C, 0x24, 0x9B, 0xC7, 0x9A), + MBEDTLS_BYTES_TO_T_UINT_8(0x25, 0x38, 0xC3, 0x84, 0xFB, 0xFF, 0x9F, 0x49), + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0x2A, 0xE0, 0x6D, 0x68, 0x8A, 0x5C, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0xC4, 0x93, 0x53, 0x85, 0xA1, 0x0D, 0xAF, 0x63), +}; +static const mbedtls_mpi_uint secp384r1_T_22_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1B, 0x88, 0x95, 0x4C, 0x0B, 0xD0, 0x06, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0xAF, 0x8D, 0x49, 0xA2, 0xC8, 0xB4, 0xE0), + MBEDTLS_BYTES_TO_T_UINT_8(0x75, 0x76, 0x53, 0x09, 0x88, 0x43, 0x87, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0x90, 0xA4, 0x77, 0x3F, 0x5E, 0x21, 0xB4, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0x35, 0x9E, 0x86, 0x64, 0xCC, 0x91, 0xC1, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0x17, 0x56, 0xCB, 0xC3, 0x7D, 0x5B, 0xB1), +}; +static const mbedtls_mpi_uint secp384r1_T_23_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x74, 0x9F, 0xB5, 0x91, 0x21, 0xB1, 0x1C), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xED, 0xE1, 0x11, 0xEF, 0x45, 0xAF, 0xC1), + MBEDTLS_BYTES_TO_T_UINT_8(0xE0, 0x31, 0xBE, 0xB2, 0xBC, 0x72, 0x65, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0xB1, 0x4B, 0x8C, 0x77, 0xCE, 0x1E, 0x42, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xC9, 0xAA, 0xB9, 0xD9, 0x86, 0x99, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x23, 0x80, 0xC6, 0x4E, 0x35, 0x0B, 0x6D), +}; +static const mbedtls_mpi_uint secp384r1_T_23_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0xD8, 0xA2, 0x0A, 0x39, 0x32, 0x1D, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0xC8, 0x86, 0xF1, 0x12, 0x9A, 0x4A, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xF1, 0x7C, 0xAA, 0x70, 0x8E, 0xBC, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0x62, 0x01, 0x47, 0x8F, 0xDD, 0x8B, 0xA5, 0xC8), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x08, 0x21, 0xF4, 0xAB, 0xC7, 0xF5, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0x0A, 0x76, 0xA5, 0x95, 0xC4, 0x0F, 0x88, 0x1D), +}; +static const mbedtls_mpi_uint secp384r1_T_24_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0x42, 0x2A, 0x52, 0xCD, 0x75, 0x51, 0x49), + MBEDTLS_BYTES_TO_T_UINT_8(0x90, 0x36, 0xE5, 0x04, 0x2B, 0x44, 0xC6, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0xEE, 0x16, 0x13, 0x07, 0x83, 0xB5, 0x30), + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0x59, 0xC6, 0xA2, 0x19, 0x05, 0xD3, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x8B, 0xA8, 0x16, 0x09, 0xB7, 0xEA, 0xD6), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0xEE, 0x14, 0xAF, 0xB5, 0xFD, 0xD0, 0xEF), +}; +static const mbedtls_mpi_uint secp384r1_T_24_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0x7C, 0xCA, 0x71, 0x3E, 0x6E, 0x66, 0x75), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0x31, 0x0E, 0x3F, 0xE5, 0x91, 0xC4, 0x7F), + MBEDTLS_BYTES_TO_T_UINT_8(0x8E, 0x3D, 0xC2, 0x3E, 0x95, 0x37, 0x58, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0x1F, 0x02, 0x03, 0xF3, 0xEF, 0xEE, 0x66), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x5B, 0x1A, 0xFC, 0x38, 0xCD, 0xE8, 0x24), + MBEDTLS_BYTES_TO_T_UINT_8(0x12, 0x57, 0x42, 0x85, 0xC6, 0x21, 0x68, 0x71), +}; +static const mbedtls_mpi_uint secp384r1_T_25_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xA2, 0x4A, 0x66, 0xB1, 0x0A, 0xE6, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0x0C, 0x94, 0x9D, 0x5E, 0x99, 0xB2, 0xCE), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0x03, 0x40, 0xCA, 0xB2, 0xB3, 0x30, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0x78, 0x48, 0x27, 0x34, 0x1E, 0xE2, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0x72, 0x5B, 0xAC, 0xC1, 0x6D, 0xE3, 0x82), + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0xAB, 0x46, 0xCB, 0xEA, 0x5E, 0x4B, 0x0B), +}; +static const mbedtls_mpi_uint secp384r1_T_25_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x08, 0xAD, 0x4E, 0x51, 0x9F, 0x2A, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x5C, 0x7D, 0x4C, 0xD6, 0xCF, 0xDD, 0x02), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0x76, 0x26, 0xE0, 0x8B, 0x10, 0xD9, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0xA7, 0x23, 0x4E, 0x5F, 0xD2, 0x42, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0xD1, 0xE5, 0xA4, 0xEC, 0x77, 0x21, 0x34, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0x14, 0x65, 0xEA, 0x4A, 0x85, 0xC3, 0x2F), +}; +static const mbedtls_mpi_uint secp384r1_T_26_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0xD8, 0x40, 0x27, 0x73, 0x15, 0x7E, 0x65), + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0xBB, 0x53, 0x7E, 0x0F, 0x40, 0xC8, 0xD4), + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0x37, 0x19, 0x73, 0xEF, 0x5A, 0x5E, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0x73, 0x2B, 0x49, 0x7E, 0xAC, 0x97, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0xB2, 0xC3, 0x1E, 0x0E, 0xE7, 0xD2, 0x21), + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0x08, 0xD6, 0xDD, 0xAC, 0x21, 0xD6, 0x3E), +}; +static const mbedtls_mpi_uint secp384r1_T_26_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA9, 0x26, 0xBE, 0x6D, 0x6D, 0xF2, 0x38, 0x3F), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0x6C, 0x31, 0xA7, 0x49, 0x50, 0x3A, 0x89), + MBEDTLS_BYTES_TO_T_UINT_8(0xC3, 0x99, 0xC6, 0xF5, 0xD2, 0xC2, 0x30, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0xE4, 0xF6, 0x8B, 0x8B, 0x97, 0xE9, 0xB2), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x21, 0xB7, 0x0D, 0xFC, 0x15, 0x54, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x83, 0x1C, 0xA4, 0xCD, 0x6B, 0x9D, 0xF2), +}; +static const mbedtls_mpi_uint secp384r1_T_27_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0xE8, 0x4C, 0x48, 0xE4, 0xAA, 0x69, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0x7A, 0x27, 0xFC, 0x37, 0x96, 0x1A, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0x6F, 0xE7, 0x30, 0xA5, 0xCF, 0x13, 0x46, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0xD8, 0xAF, 0x74, 0x23, 0x4D, 0x56, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0x32, 0x3D, 0x44, 0x14, 0x1B, 0x97, 0x83, 0xF0), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x47, 0xD7, 0x5F, 0xFD, 0x98, 0x38, 0xF7), +}; +static const mbedtls_mpi_uint secp384r1_T_27_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA3, 0x73, 0x64, 0x36, 0xFD, 0x7B, 0xC1, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0x5D, 0x32, 0xD2, 0x47, 0x94, 0x89, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0xE9, 0x30, 0xAC, 0x06, 0xC8, 0x65, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x6C, 0xB9, 0x1B, 0xF7, 0x61, 0x49, 0x53), + MBEDTLS_BYTES_TO_T_UINT_8(0xD7, 0xFF, 0x32, 0x43, 0x80, 0xDA, 0xA6, 0xB1), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xF8, 0x04, 0x01, 0x95, 0x35, 0xCE, 0x21), +}; +static const mbedtls_mpi_uint secp384r1_T_28_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x06, 0x46, 0x0D, 0x51, 0xE2, 0xD8, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0x14, 0x57, 0x1D, 0x6F, 0x79, 0xA0, 0xCD, 0xA6), + MBEDTLS_BYTES_TO_T_UINT_8(0xDF, 0xFB, 0x36, 0xCA, 0xAD, 0xF5, 0x9E, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0x6F, 0x7A, 0x1D, 0x9E, 0x1D, 0x95, 0x48, 0xDC), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0x26, 0xA5, 0xB7, 0x15, 0x2C, 0xC2, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0x42, 0x72, 0xAA, 0x11, 0xDC, 0xC9, 0xB6), +}; +static const mbedtls_mpi_uint secp384r1_T_28_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0x6C, 0x64, 0xA7, 0x62, 0x3C, 0xAB, 0xD4), + MBEDTLS_BYTES_TO_T_UINT_8(0x48, 0x6A, 0x44, 0xD8, 0x60, 0xC0, 0xA8, 0x80), + MBEDTLS_BYTES_TO_T_UINT_8(0x82, 0x76, 0x58, 0x12, 0x57, 0x3C, 0x89, 0x46), + MBEDTLS_BYTES_TO_T_UINT_8(0x82, 0x4F, 0x83, 0xCE, 0xCB, 0xB8, 0xD0, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x9A, 0x84, 0x04, 0xB0, 0xAD, 0xEB, 0xFA, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0xA4, 0xC3, 0x41, 0x44, 0x4E, 0x65, 0x3E), +}; +static const mbedtls_mpi_uint secp384r1_T_29_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x16, 0xA9, 0x1C, 0xE7, 0x65, 0x20, 0xC1), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0x53, 0x32, 0xF8, 0xC0, 0xA6, 0xBD, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0xF0, 0xE6, 0x57, 0x31, 0xCC, 0x26, 0x6F), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0xE3, 0x54, 0x1C, 0x34, 0xD3, 0x17, 0xBC), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xAE, 0xED, 0xFB, 0xCD, 0xE7, 0x1E, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x16, 0x1C, 0x34, 0x40, 0x00, 0x1F, 0xB6), +}; +static const mbedtls_mpi_uint secp384r1_T_29_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0x32, 0x00, 0xC2, 0xD4, 0x3B, 0x1A, 0x09), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0xE0, 0x99, 0x8F, 0x0C, 0x4A, 0x16, 0x44), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x73, 0x18, 0x1B, 0xD4, 0x94, 0x29, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0xA4, 0x2D, 0xB1, 0x9D, 0x74, 0x32, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0xBF, 0xF4, 0xB1, 0x0C, 0x37, 0x62, 0x8B, 0x66), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0xFF, 0xDA, 0xE2, 0x35, 0xA3, 0xB6, 0x42), +}; +static const mbedtls_mpi_uint secp384r1_T_30_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0x49, 0x99, 0x65, 0xC5, 0xED, 0x16, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0x79, 0x42, 0x9A, 0xF3, 0xA7, 0x4E, 0x6F, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0x0A, 0x7E, 0xC0, 0xD7, 0x4E, 0x07, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0x7A, 0x31, 0x69, 0xA6, 0xB9, 0x15, 0x34), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0xE0, 0x72, 0xA4, 0x3F, 0xB9, 0xF8, 0x0C), + MBEDTLS_BYTES_TO_T_UINT_8(0x2B, 0x75, 0x32, 0x85, 0xA2, 0xDE, 0x37, 0x12), +}; +static const mbedtls_mpi_uint secp384r1_T_30_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0xC0, 0x0D, 0xCF, 0x25, 0x41, 0xA4, 0xF4), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0xFC, 0xB2, 0x48, 0xC3, 0x85, 0x83, 0x4B), + MBEDTLS_BYTES_TO_T_UINT_8(0x2B, 0xBE, 0x0B, 0x58, 0x2D, 0x7A, 0x9A, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0xF3, 0x81, 0x18, 0x1B, 0x74, 0x4F, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0xE2, 0x43, 0xA3, 0x0A, 0x16, 0x8B, 0xA3, 0x1E), + MBEDTLS_BYTES_TO_T_UINT_8(0x4A, 0x18, 0x81, 0x7B, 0x8D, 0xA2, 0x35, 0x77), +}; +static const mbedtls_mpi_uint secp384r1_T_31_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0xC4, 0x3F, 0x2C, 0xE7, 0x5F, 0x99, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0x2B, 0xB7, 0xB6, 0xAD, 0x5A, 0x56, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x00, 0xA4, 0x48, 0xC8, 0xE8, 0xBA, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0xA1, 0xB5, 0x13, 0x5A, 0xCD, 0x99, 0x9C), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x95, 0xAD, 0xFC, 0xE2, 0x7E, 0xE7, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0x6B, 0xD1, 0x34, 0x99, 0x53, 0x63, 0x0B), +}; +static const mbedtls_mpi_uint secp384r1_T_31_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x8A, 0x77, 0x5D, 0x2B, 0xAB, 0x01, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x4E, 0x85, 0xD0, 0xD5, 0x49, 0x83, 0x4D, 0x60), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0xC6, 0x91, 0x30, 0x3B, 0x00, 0xAF, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0xAE, 0x61, 0x07, 0xE1, 0xB6, 0xE2, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0x43, 0x41, 0xFE, 0x9B, 0xB6, 0xF0, 0xA5), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x97, 0xAE, 0xAD, 0x89, 0x88, 0x9E, 0x41), +}; +static const mbedtls_ecp_point secp384r1_T[32] = { + ECP_POINT_INIT_XY_Z1(secp384r1_T_0_X, secp384r1_T_0_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_1_X, secp384r1_T_1_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_2_X, secp384r1_T_2_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_3_X, secp384r1_T_3_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_4_X, secp384r1_T_4_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_5_X, secp384r1_T_5_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_6_X, secp384r1_T_6_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_7_X, secp384r1_T_7_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_8_X, secp384r1_T_8_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_9_X, secp384r1_T_9_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_10_X, secp384r1_T_10_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_11_X, secp384r1_T_11_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_12_X, secp384r1_T_12_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_13_X, secp384r1_T_13_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_14_X, secp384r1_T_14_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_15_X, secp384r1_T_15_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_16_X, secp384r1_T_16_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_17_X, secp384r1_T_17_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_18_X, secp384r1_T_18_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_19_X, secp384r1_T_19_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_20_X, secp384r1_T_20_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_21_X, secp384r1_T_21_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_22_X, secp384r1_T_22_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_23_X, secp384r1_T_23_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_24_X, secp384r1_T_24_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_25_X, secp384r1_T_25_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_26_X, secp384r1_T_26_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_27_X, secp384r1_T_27_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_28_X, secp384r1_T_28_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_29_X, secp384r1_T_29_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_30_X, secp384r1_T_30_Y), + ECP_POINT_INIT_XY_Z0(secp384r1_T_31_X, secp384r1_T_31_Y), +}; +#else +#define secp384r1_T NULL +#endif + +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +/* + * Domain parameters for secp521r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +static const mbedtls_mpi_uint secp521r1_p[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_2(0xFF, 0x01), +}; +static const mbedtls_mpi_uint secp521r1_b[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x3F, 0x50, 0x6B, 0xD4, 0x1F, 0x45, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x34, 0x2C, 0x3D, 0x88, 0xDF, 0x73, 0x35), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0xBF, 0xB1, 0x3B, 0xBD, 0xC0, 0x52, 0x16), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0x93, 0x7E, 0xEC, 0x51, 0x39, 0x19, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0xE1, 0x09, 0xF1, 0x8E, 0x91, 0x89, 0xB4, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0x15, 0xB3, 0x99, 0x5B, 0x72, 0xDA, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0xEE, 0x40, 0x85, 0xB6, 0xA0, 0x21, 0x9A, 0x92), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x9A, 0x1C, 0x8E, 0x61, 0xB9, 0x3E, 0x95), + MBEDTLS_BYTES_TO_T_UINT_2(0x51, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_gx[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0xBD, 0xE5, 0xC2, 0x31, 0x7E, 0x7E, 0xF9), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x42, 0x6A, 0x85, 0xC1, 0xB3, 0x48, 0x33), + MBEDTLS_BYTES_TO_T_UINT_8(0xDE, 0xA8, 0xFF, 0xA2, 0x27, 0xC1, 0x1D, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x59, 0xE7, 0xEF, 0x77, 0x5E, 0x4B, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x3D, 0x4D, 0x6B, 0x60, 0xAF, 0x28, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0xB5, 0x3F, 0x05, 0x39, 0x81, 0x64, 0x9C), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0xB4, 0x95, 0x23, 0x66, 0xCB, 0x3E, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0xE9, 0x04, 0x04, 0xB7, 0x06, 0x8E, 0x85), + MBEDTLS_BYTES_TO_T_UINT_2(0xC6, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_gy[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x66, 0xD1, 0x9F, 0x76, 0x94, 0xBE, 0x88), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0xC2, 0x72, 0xA2, 0x86, 0x70, 0x3C, 0x35), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0x07, 0xAD, 0x3F, 0x01, 0xB9, 0x50, 0xC5), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0x26, 0xF4, 0x5E, 0x99, 0x72, 0xEE, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0x2C, 0x66, 0x3E, 0x27, 0x17, 0xBD, 0xAF, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x44, 0x9B, 0x57, 0x49, 0x44, 0xF5, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x1B, 0x7D, 0x2C, 0xB4, 0x5F, 0x8A, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0xC0, 0x3B, 0x9A, 0x78, 0x6A, 0x29, 0x39), + MBEDTLS_BYTES_TO_T_UINT_2(0x18, 0x01), +}; +static const mbedtls_mpi_uint secp521r1_n[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0x64, 0x38, 0x91, 0x1E, 0xB7, 0x6F, 0xBB), + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0x47, 0x9C, 0x89, 0xB8, 0xC9, 0xB5, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0xD0, 0xA5, 0x09, 0xF7, 0x48, 0x01, 0xCC, 0x7F), + MBEDTLS_BYTES_TO_T_UINT_8(0x6B, 0x96, 0x2F, 0xBF, 0x83, 0x87, 0x86, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_2(0xFF, 0x01), +}; +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 +static const mbedtls_mpi_uint secp521r1_T_0_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0xBD, 0xE5, 0xC2, 0x31, 0x7E, 0x7E, 0xF9), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x42, 0x6A, 0x85, 0xC1, 0xB3, 0x48, 0x33), + MBEDTLS_BYTES_TO_T_UINT_8(0xDE, 0xA8, 0xFF, 0xA2, 0x27, 0xC1, 0x1D, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x59, 0xE7, 0xEF, 0x77, 0x5E, 0x4B, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x3D, 0x4D, 0x6B, 0x60, 0xAF, 0x28, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0xB5, 0x3F, 0x05, 0x39, 0x81, 0x64, 0x9C), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0xB4, 0x95, 0x23, 0x66, 0xCB, 0x3E, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0xE9, 0x04, 0x04, 0xB7, 0x06, 0x8E, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_0_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x66, 0xD1, 0x9F, 0x76, 0x94, 0xBE, 0x88), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0xC2, 0x72, 0xA2, 0x86, 0x70, 0x3C, 0x35), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0x07, 0xAD, 0x3F, 0x01, 0xB9, 0x50, 0xC5), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0x26, 0xF4, 0x5E, 0x99, 0x72, 0xEE, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0x2C, 0x66, 0x3E, 0x27, 0x17, 0xBD, 0xAF, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x44, 0x9B, 0x57, 0x49, 0x44, 0xF5, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x1B, 0x7D, 0x2C, 0xB4, 0x5F, 0x8A, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0xC0, 0x3B, 0x9A, 0x78, 0x6A, 0x29, 0x39), + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_1_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0xB1, 0x2D, 0xEB, 0x27, 0x2F, 0xE8, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x4B, 0x44, 0x25, 0xDB, 0x5C, 0x5F, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0x13, 0x85, 0x28, 0x78, 0x2E, 0x75, 0x34, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0x69, 0x57, 0x0F, 0x73, 0x78, 0x7A, 0xE3, 0x53), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xD8, 0xEC, 0xDC, 0xDA, 0x04, 0xAD, 0xAB), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0x8A, 0x09, 0xF3, 0x58, 0x79, 0xD8, 0x29), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0x03, 0xCB, 0x50, 0x1A, 0x7F, 0x56, 0x00), + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0xA6, 0x78, 0x38, 0x85, 0x67, 0x0B, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_1_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0xD5, 0xD2, 0x22, 0xC4, 0x00, 0x3B, 0xBA), + MBEDTLS_BYTES_TO_T_UINT_8(0xD5, 0x93, 0x0E, 0x7B, 0x85, 0x51, 0xC3, 0x06), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0xA6, 0x5F, 0x54, 0x49, 0x02, 0x81, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0x22, 0xE9, 0x6B, 0x3A, 0x92, 0xE7, 0x72, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0x6F, 0x5F, 0x28, 0x9E, 0x91, 0x27, 0x88, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0x28, 0x31, 0xB3, 0x84, 0xCA, 0x12, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0xF9, 0xAC, 0x22, 0x10, 0x0A, 0x64, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0xC6, 0x33, 0x1F, 0x69, 0x19, 0x18, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_2_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x48, 0xB8, 0xC7, 0x37, 0x5A, 0x00, 0x36), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0xCC, 0x32, 0xE0, 0xEE, 0x03, 0xC2, 0xBA), + MBEDTLS_BYTES_TO_T_UINT_8(0xC4, 0x29, 0xC2, 0xE4, 0x6E, 0x24, 0x20, 0x8D), + MBEDTLS_BYTES_TO_T_UINT_8(0x06, 0x6B, 0x7F, 0x7B, 0xF9, 0xB0, 0xB8, 0x13), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x7B, 0x3C, 0xE1, 0x19, 0xA1, 0x23, 0x02), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0xE3, 0xC2, 0x53, 0xC0, 0x07, 0x13, 0xA9), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0xFE, 0x36, 0x35, 0x9F, 0x5E, 0x59, 0xCE), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x55, 0x89, 0x84, 0xBC, 0xEF, 0xA2, 0xC2), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_2_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0x1A, 0x08, 0x67, 0xB4, 0xE7, 0x22, 0xED), + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0x26, 0xDF, 0x81, 0x3C, 0x5F, 0x1C, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0xE0, 0x4D, 0xD0, 0x0A, 0x48, 0x06, 0xF4, 0x48), + MBEDTLS_BYTES_TO_T_UINT_8(0x73, 0x18, 0x39, 0xF7, 0xD1, 0x20, 0x77, 0x8D), + MBEDTLS_BYTES_TO_T_UINT_8(0x78, 0x8F, 0x44, 0x13, 0xCB, 0x78, 0x11, 0x11), + MBEDTLS_BYTES_TO_T_UINT_8(0x33, 0xE2, 0x49, 0xEA, 0x43, 0x79, 0x08, 0x39), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0xD1, 0xD8, 0x73, 0x2C, 0x71, 0x2F, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0xE5, 0xE7, 0xF4, 0x46, 0xAB, 0x20, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_3_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0x0B, 0xB9, 0x71, 0x1A, 0x27, 0xB7, 0xA7), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0xA2, 0x2C, 0xD1, 0xDA, 0xBC, 0xC1, 0xBD), + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0xA3, 0x10, 0x1F, 0x90, 0xF2, 0xA5, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0xFB, 0x20, 0xF4, 0xC0, 0x70, 0xC0, 0xF5), + MBEDTLS_BYTES_TO_T_UINT_8(0x8F, 0xA7, 0x99, 0xF0, 0xA5, 0xD3, 0x09, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0xE8, 0x14, 0x39, 0xBE, 0xCB, 0x60, 0xAF), + MBEDTLS_BYTES_TO_T_UINT_8(0x9F, 0xD6, 0x14, 0xA9, 0xC9, 0x20, 0xC3, 0xEA), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0xA8, 0x5B, 0xFD, 0x2D, 0x96, 0xBC, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_3_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0x04, 0x45, 0xBE, 0xCE, 0x75, 0x95, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0xCC, 0xDA, 0x58, 0x49, 0x35, 0x09, 0x8D, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0xF0, 0xC0, 0x36, 0xF2, 0xA6, 0x2D, 0x14), + MBEDTLS_BYTES_TO_T_UINT_8(0xE7, 0xFC, 0x3D, 0xA8, 0xFB, 0x3C, 0xD2, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0x4D, 0x71, 0x09, 0x18, 0x42, 0xF0, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xC1, 0xCE, 0x9E, 0x6A, 0x49, 0x60, 0x12), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0xB1, 0x00, 0xF7, 0xA1, 0x7A, 0x31, 0xB4), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0xC3, 0x86, 0xCD, 0x20, 0x4A, 0x17, 0x86), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_4_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0xAB, 0x8B, 0x47, 0x8D, 0xAA, 0xA6, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0xC4, 0x97, 0xF0, 0xBC, 0x2D, 0xDC, 0x9D, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0x86, 0xB0, 0x74, 0xB2, 0xF4, 0xF6, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xBD, 0xAC, 0xE3, 0x8F, 0x43, 0x5C, 0xB1), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0xC3, 0xE2, 0x6E, 0x25, 0x49, 0xCD, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x5E, 0x08, 0xB3, 0xB9, 0xAC, 0x5F, 0xD1), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0xB7, 0xD1, 0xF4, 0xDC, 0x19, 0xE9, 0xC8), + MBEDTLS_BYTES_TO_T_UINT_8(0x49, 0xE4, 0xFA, 0xE1, 0x36, 0x3E, 0xED, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_4_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x67, 0x92, 0x84, 0x6E, 0x48, 0x03, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0x9E, 0x95, 0xEF, 0x8F, 0xB2, 0x82, 0x6B, 0x1C), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xFA, 0xB9, 0x55, 0x23, 0xFE, 0x09, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0x79, 0x85, 0x4B, 0x0E, 0xD4, 0x35, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0x9A, 0x27, 0x45, 0x81, 0xE0, 0x88, 0x52, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0x63, 0xA2, 0x4B, 0xBC, 0x5D, 0xB1, 0x92), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x8C, 0x83, 0xD9, 0x3E, 0xD3, 0x42, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0x03, 0x3A, 0x31, 0xBA, 0xE9, 0x3A, 0xD1), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_5_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x35, 0x10, 0xCD, 0x2D, 0x00, 0xFE, 0x32, 0xA7), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0x6E, 0x1F, 0xDA, 0xF8, 0x6F, 0x4D, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0x79, 0x7D, 0x09, 0xE5, 0xD3, 0x03, 0x21), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0xC3, 0xBE, 0xDF, 0x07, 0x65, 0x49, 0xCC), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0x57, 0x33, 0xEF, 0xAE, 0x4F, 0x04, 0x27), + MBEDTLS_BYTES_TO_T_UINT_8(0x9A, 0xE9, 0x9B, 0xFE, 0xBF, 0xE6, 0x85, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0xBD, 0xBA, 0xAA, 0x06, 0xC4, 0xC6, 0xB8, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0x83, 0x01, 0xA9, 0xF6, 0x51, 0xE7, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0x1B, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_5_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0xA6, 0x15, 0x8E, 0xAB, 0x1F, 0x10, 0x87), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0x08, 0x27, 0x1A, 0xA1, 0x21, 0xAD, 0xF5), + MBEDTLS_BYTES_TO_T_UINT_8(0x02, 0x09, 0x90, 0x6E, 0x50, 0x90, 0x9A, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0x9A, 0xFE, 0xD7, 0xA1, 0xF5, 0xA2, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x7D, 0xE3, 0xDC, 0x21, 0xFB, 0xA4, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0xBF, 0x07, 0xFF, 0x45, 0xDF, 0x51, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0x5C, 0x34, 0x02, 0x62, 0x9B, 0x08, 0x12), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0xCE, 0x9A, 0x6A, 0xEC, 0x75, 0xF6, 0x46), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_6_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0x59, 0xF4, 0x78, 0x3C, 0x60, 0xB1, 0x4A), + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0x37, 0x84, 0x6A, 0xDC, 0xF2, 0x9A, 0x7D), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0x9A, 0x9A, 0x15, 0x36, 0xE0, 0x2B, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0xEC, 0x38, 0x9C, 0x50, 0x3D, 0x1E, 0x37, 0x82), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0x79, 0xF0, 0x92, 0xF2, 0x8B, 0x18, 0x82), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0xE0, 0x82, 0x1E, 0x80, 0x82, 0x4B, 0xD7), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0xBB, 0x59, 0x6B, 0x8A, 0x77, 0x41, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0xF9, 0xD4, 0xB8, 0x4A, 0x82, 0xCF, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_6_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0x8C, 0xC8, 0x9B, 0x72, 0x9E, 0xF7, 0xF9), + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0xCE, 0xE9, 0x77, 0x0A, 0x19, 0x59, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0xA1, 0x41, 0x6A, 0x72, 0x4B, 0xB4, 0xDC), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0x35, 0x43, 0xE2, 0x8C, 0xBE, 0x0D, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0xEB, 0xAD, 0xF3, 0xA9, 0xA6, 0x68, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0x2F, 0xE2, 0x48, 0x0C, 0xDB, 0x1F, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xD1, 0x1E, 0x60, 0x9B, 0x2A, 0xD2, 0xC1, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0x64, 0xB5, 0xD2, 0xF6, 0xF6, 0x6E, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_7_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0x3D, 0x30, 0x78, 0x10, 0x18, 0x41, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0x1D, 0x1C, 0xE0, 0x6D, 0x83, 0xD1, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0x03, 0x0B, 0xF5, 0x2F, 0x6C, 0x04, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x3E, 0xD5, 0xFC, 0x31, 0x5B, 0x3A, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x82, 0x2F, 0xFB, 0xFE, 0xF8, 0x76, 0x39), + MBEDTLS_BYTES_TO_T_UINT_8(0x85, 0x26, 0xDA, 0x9C, 0x36, 0xF5, 0x93, 0xD1), + MBEDTLS_BYTES_TO_T_UINT_8(0x4C, 0xE7, 0x6E, 0xD2, 0x7D, 0x81, 0x09, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0xD3, 0x03, 0xF9, 0x58, 0x48, 0x24, 0xA2, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_7_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1B, 0x79, 0x0C, 0x8E, 0x6B, 0x95, 0xF3, 0xC4), + MBEDTLS_BYTES_TO_T_UINT_8(0xF4, 0x10, 0x5C, 0x87, 0x03, 0x39, 0xCF, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0xF0, 0xF7, 0xC1, 0x07, 0xA4, 0xF4, 0x3F), + MBEDTLS_BYTES_TO_T_UINT_8(0x32, 0xE8, 0x02, 0x89, 0x65, 0xC4, 0x72, 0x36), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x88, 0xEA, 0x96, 0x67, 0x0B, 0x5D, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0x75, 0x60, 0xA8, 0xBD, 0x74, 0xDF, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0x6E, 0xE5, 0x71, 0x50, 0x67, 0xD0, 0xD2, 0xE6), + MBEDTLS_BYTES_TO_T_UINT_8(0xD5, 0xFC, 0xE5, 0xC7, 0x77, 0xB0, 0x7F, 0x8C), + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_8_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x97, 0x86, 0x69, 0xCD, 0x0D, 0x9A, 0xBD, 0x66), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0x17, 0xBC, 0xBB, 0x59, 0x85, 0x7D, 0x0E), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xA8, 0x76, 0xAC, 0x80, 0xA9, 0x72, 0xE0), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0x78, 0xC1, 0xE2, 0x4D, 0xAF, 0xF9, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0x97, 0x8E, 0x74, 0xC4, 0x4B, 0xB2, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0xD8, 0xF6, 0xF3, 0xAF, 0x2F, 0x52, 0xE5), + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0x57, 0xF4, 0xCE, 0xEE, 0x43, 0xED, 0x60), + MBEDTLS_BYTES_TO_T_UINT_8(0x7D, 0x46, 0x38, 0xDE, 0x20, 0xFD, 0x59, 0x18), + MBEDTLS_BYTES_TO_T_UINT_8(0xD7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_8_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x18, 0xE8, 0x58, 0xB9, 0x76, 0x2C, 0xE6), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0x54, 0xE4, 0xFE, 0xC7, 0xBC, 0x31, 0x37), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xF8, 0x89, 0xEE, 0x70, 0xB5, 0xB0, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x22, 0x26, 0x9A, 0x53, 0xB9, 0x38, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0xA7, 0x19, 0x8C, 0x74, 0x7E, 0x88, 0x46), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0xDA, 0x0A, 0xE8, 0xDA, 0xA5, 0xBE, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0x90, 0x5C, 0xF7, 0xB1, 0x0C, 0x72, 0xFB, 0x09), + MBEDTLS_BYTES_TO_T_UINT_8(0x78, 0xE2, 0x23, 0xE7, 0x46, 0xB7, 0xE0, 0x91), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_9_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0x36, 0xBC, 0xBD, 0x48, 0x11, 0x8E, 0x72), + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0xBB, 0xA1, 0xF7, 0x0B, 0x9E, 0xBF, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x28, 0xE1, 0xA2, 0x8F, 0xFC, 0xFC, 0xD6), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0xFE, 0x19, 0x0A, 0xE5, 0xE7, 0x69, 0x39), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0xCD, 0x12, 0xF5, 0xBE, 0xD3, 0x04, 0xF1), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xA8, 0x0D, 0x81, 0x59, 0xC4, 0x79, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0xA3, 0xF3, 0x4B, 0x92, 0x65, 0xC3, 0x31, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0x75, 0xB5, 0x4F, 0x4D, 0x91, 0xD4, 0xE2, 0xB2), + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_9_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0x09, 0x41, 0x79, 0x1D, 0x4D, 0x0D, 0x33), + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0x31, 0x18, 0xBA, 0xA0, 0xF2, 0x6E, 0x7E), + MBEDTLS_BYTES_TO_T_UINT_8(0x93, 0x5B, 0x4D, 0x4F, 0xAF, 0xC9, 0x8C, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0x48, 0x99, 0x9C, 0x06, 0x68, 0xDE, 0xD8, 0x29), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x04, 0xE1, 0xB5, 0x9D, 0x00, 0xBC, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0x95, 0x92, 0x8D, 0x72, 0xD3, 0x37, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0x4B, 0x27, 0xA2, 0xE8, 0xA4, 0x26, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0x45, 0x9C, 0xA9, 0xCB, 0x9F, 0xBA, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_10_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0x7E, 0x1B, 0x64, 0xF4, 0xE8, 0xA5, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0xF7, 0x20, 0xA9, 0xCA, 0xF3, 0x89, 0xE5, 0xE1), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0xED, 0xFC, 0xAB, 0xD9, 0x0A, 0xB9, 0x07), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0x6F, 0x46, 0x7C, 0xCD, 0x78, 0xFF, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0x69, 0xAB, 0x71, 0x5A, 0x94, 0xAB, 0x20, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x2E, 0xEE, 0x87, 0x57, 0x1F, 0xAD, 0xD3), + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0x4C, 0x3D, 0xFB, 0x7E, 0xA1, 0x8B, 0x07), + MBEDTLS_BYTES_TO_T_UINT_8(0x69, 0xCF, 0x07, 0x86, 0xBA, 0x53, 0x37, 0xCF), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_10_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x26, 0xB2, 0xB9, 0xE2, 0x91, 0xE3, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0x79, 0xC9, 0x54, 0x84, 0x08, 0x3D, 0x0B, 0xD2), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0xA8, 0x77, 0x2F, 0x64, 0x45, 0x99, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0x96, 0x16, 0x1F, 0xDB, 0x96, 0x28, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x2B, 0x8D, 0xFF, 0xA2, 0x4F, 0x55, 0xD3), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0xE6, 0x48, 0xBD, 0x99, 0x3D, 0x12, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0x84, 0x59, 0xDA, 0xB9, 0xB6, 0x66, 0x12), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x78, 0x41, 0x92, 0xDF, 0xF4, 0x3F, 0x63), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_11_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0x86, 0x6F, 0x4F, 0xBF, 0x67, 0xDF, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0x2B, 0x1E, 0x5F, 0x00, 0xEA, 0xF6, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0x90, 0xB9, 0x6A, 0x89, 0xD8, 0xC0, 0xD7, 0xA7), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x9A, 0x32, 0x23, 0xA0, 0x02, 0x91, 0x58), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0x7F, 0x6A, 0x15, 0x64, 0x6A, 0x8B, 0xBB), + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0x57, 0x82, 0x58, 0xA9, 0x56, 0xB5, 0xFB), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x50, 0x92, 0x60, 0xCC, 0x81, 0x24, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0x3D, 0xAD, 0xDA, 0xD9, 0x51, 0x3E, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_11_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEC, 0xFE, 0x8F, 0xB0, 0x0B, 0xDE, 0x2E, 0x7E), + MBEDTLS_BYTES_TO_T_UINT_8(0x79, 0xD2, 0xBE, 0xEF, 0xAC, 0x76, 0x71, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0xE8, 0x72, 0x0B, 0xAC, 0xFE, 0xCA, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0x5B, 0xC7, 0xFC, 0xE3, 0x3C, 0x7C, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0xA1, 0x04, 0xA7, 0xB9, 0x9B, 0x93, 0xC0, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0x48, 0x4B, 0x8E, 0x32, 0xC5, 0xF0, 0x6B), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x42, 0x07, 0xC1, 0xF2, 0xF1, 0x72, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0x37, 0x54, 0x9C, 0x88, 0xD2, 0x62, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_12_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x19, 0x8A, 0x89, 0x58, 0xA2, 0x0F, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0xCC, 0x4C, 0x97, 0x30, 0x66, 0x34, 0x26), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x6A, 0x1E, 0x1F, 0xDB, 0xC9, 0x5E, 0x13), + MBEDTLS_BYTES_TO_T_UINT_8(0x1B, 0x4D, 0x49, 0xFF, 0x9B, 0x9C, 0xAC, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0xD7, 0xE4, 0x4B, 0xF2, 0xD4, 0x1A, 0xD2, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0xDA, 0xE8, 0x61, 0x9F, 0xC8, 0x49, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0xCB, 0xF2, 0x2D, 0x85, 0xF6, 0x8D, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0xC5, 0xCD, 0x2C, 0x79, 0xC6, 0x0E, 0x4F), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_12_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x73, 0x1D, 0x55, 0x0F, 0xF8, 0x22, 0x9F, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0x56, 0xBA, 0xE7, 0x57, 0x32, 0xEC, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x9A, 0xC6, 0x4C, 0x09, 0xC4, 0x52, 0x3F), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x1E, 0x6F, 0xF4, 0x7D, 0x27, 0xDD, 0xAF), + MBEDTLS_BYTES_TO_T_UINT_8(0x94, 0x11, 0x16, 0xEC, 0x79, 0x83, 0xAD, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0x4E, 0x92, 0x1F, 0x19, 0x7D, 0x65, 0xDC), + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0xFF, 0x78, 0x15, 0x45, 0x63, 0x32, 0xE4), + MBEDTLS_BYTES_TO_T_UINT_8(0xBF, 0x91, 0xD0, 0x78, 0x58, 0xDA, 0x50, 0x47), + MBEDTLS_BYTES_TO_T_UINT_8(0x73, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_13_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x23, 0xDE, 0x40, 0xF6, 0x41, 0xB4, 0x3B, 0x95), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0x8D, 0xE0, 0xE1, 0xA9, 0xF0, 0x35, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0xD4, 0xBA, 0x7B, 0xCC, 0x1B, 0x3A, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0xD0, 0x5A, 0x2E, 0x74, 0x47, 0x14, 0xC3, 0x4D), + MBEDTLS_BYTES_TO_T_UINT_8(0x7D, 0xF0, 0x8B, 0x06, 0x15, 0x8E, 0x0E, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0xB5, 0xD2, 0xEB, 0x97, 0x50, 0x7D, 0x31, 0xFC), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0x93, 0x4C, 0xDB, 0x97, 0x79, 0x44, 0xF5), + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0xA2, 0xA0, 0x0B, 0xC8, 0x3A, 0x8A, 0xF9), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_13_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x79, 0x50, 0x92, 0x9E, 0x24, 0x1F, 0xCB, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0xD3, 0x16, 0xC9, 0xC5, 0x3D, 0x5A, 0xAF, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0xE3, 0x97, 0xE4, 0xA8, 0x50, 0xF6, 0x7E), + MBEDTLS_BYTES_TO_T_UINT_8(0x45, 0x57, 0x97, 0x42, 0x78, 0x92, 0x49, 0x0D), + MBEDTLS_BYTES_TO_T_UINT_8(0xA5, 0xEB, 0x62, 0x24, 0xFB, 0x8F, 0x32, 0xCF), + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0x0C, 0x36, 0x6E, 0x8F, 0xE8, 0xE8, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0xD3, 0x7C, 0xC7, 0x8D, 0x3F, 0x5C, 0xE1), + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0x64, 0x6A, 0x73, 0x10, 0x79, 0xB8, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_14_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0xF9, 0xEF, 0xA5, 0x20, 0x4A, 0x5C, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0xF3, 0xF4, 0x49, 0x5B, 0x73, 0xAA, 0x1B), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0xF2, 0xEA, 0x0F, 0x00, 0xAD, 0x53, 0xAB), + MBEDTLS_BYTES_TO_T_UINT_8(0x03, 0xB8, 0x66, 0xED, 0xC4, 0x2B, 0x4C, 0x35), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0x2F, 0xC1, 0x9A, 0x37, 0xD2, 0x7F, 0x58), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0xA7, 0x81, 0x38, 0x64, 0xC9, 0x37, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0x3B, 0x6C, 0x9F, 0x5B, 0xD9, 0x8B, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x14, 0xD9, 0x08, 0xD8, 0xD2, 0x7E, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_14_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x71, 0xE6, 0x3D, 0xD1, 0xB0, 0xE7, 0xCD), + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0x81, 0x23, 0xEC, 0x2D, 0x42, 0x45, 0xE6), + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0x5B, 0x44, 0x6B, 0x89, 0x03, 0x67, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x84, 0x27, 0xAE, 0x80, 0x5A, 0x33, 0xBE, 0x11), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0xB6, 0x64, 0x1A, 0xDF, 0xD3, 0x85, 0x91), + MBEDTLS_BYTES_TO_T_UINT_8(0x67, 0x8C, 0x22, 0xBA, 0xD0, 0xBD, 0xCC, 0xA0), + MBEDTLS_BYTES_TO_T_UINT_8(0xF7, 0x3C, 0x01, 0x3A, 0xFF, 0x9D, 0xC7, 0x6B), + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0xC7, 0x64, 0xB4, 0x59, 0x4E, 0x9F, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0x85, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_15_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA1, 0x34, 0x0A, 0x41, 0x94, 0xA8, 0xF2, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0xD4, 0xE4, 0xF0, 0x97, 0x45, 0x6D, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0x8F, 0x1F, 0x4D, 0x6D, 0xFE, 0xA0, 0xC4, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x28, 0x5C, 0x40, 0xBB, 0x65, 0xD4, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0xA8, 0x87, 0x35, 0x20, 0x3A, 0x89, 0x44), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0xFD, 0x4F, 0xAB, 0x2D, 0xD1, 0xD0, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0xE8, 0x00, 0xFC, 0x69, 0x52, 0xF8, 0xD5), + MBEDTLS_BYTES_TO_T_UINT_8(0xE1, 0x9A, 0x99, 0xE1, 0xDC, 0x9C, 0x3F, 0xD9), + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_15_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x12, 0x08, 0x98, 0xD9, 0xCA, 0x73, 0xD5, 0xA9), + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0x2C, 0xE0, 0xA7, 0x3E, 0x91, 0xD7, 0x87), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x04, 0xB0, 0x54, 0x09, 0xF4, 0x72, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0xEE, 0x28, 0xCC, 0xE8, 0x50, 0x78, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0x0D, 0x91, 0x03, 0x76, 0xDB, 0x68, 0x24, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0x7A, 0xE0, 0x56, 0xB2, 0x5D, 0x12, 0xD3, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0x0D, 0x42, 0x59, 0x8B, 0xDF, 0x67, 0xB5, 0xBE), + MBEDTLS_BYTES_TO_T_UINT_8(0xD1, 0xCC, 0xE5, 0x31, 0x53, 0x7A, 0x46, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_16_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xCC, 0x8D, 0x59, 0xB5, 0x1B, 0x0F, 0xF4, 0xAF), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x2F, 0xD1, 0x2C, 0xE0, 0xD8, 0x04, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xF4, 0xD7, 0xBA, 0xB0, 0xA3, 0x7E, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0x08, 0x51, 0x56, 0xA6, 0x76, 0x67, 0x33), + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0x17, 0x63, 0xFE, 0x56, 0xD0, 0xD9, 0x71), + MBEDTLS_BYTES_TO_T_UINT_8(0xAA, 0xF6, 0xC3, 0x14, 0x47, 0xC5, 0xA7, 0x31), + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0x4C, 0x80, 0xF6, 0xA2, 0x57, 0xA7, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0xB3, 0x7B, 0xF8, 0x2F, 0xE1, 0x3E, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_16_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0xF4, 0xF9, 0x6B, 0x7B, 0x90, 0xDF, 0x30), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x82, 0xEF, 0x62, 0xA1, 0x4C, 0x53, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0x99, 0x76, 0x01, 0xBA, 0x8D, 0x0F, 0x54), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0xF4, 0x58, 0x73, 0x56, 0xFE, 0xDD, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0xCE, 0xF9, 0xE8, 0xA1, 0x34, 0xC3, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0x5F, 0xDC, 0x6A, 0x3D, 0xD8, 0x7F, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0xF4, 0x51, 0xB8, 0xB8, 0xC1, 0xD7, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0x7D, 0x58, 0xD1, 0xD4, 0x1B, 0x4D, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0xD3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_17_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0x95, 0xDF, 0x00, 0xD8, 0x21, 0xDE, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0xF7, 0x47, 0x3C, 0xC3, 0xB2, 0x01, 0x53, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0x17, 0x43, 0x23, 0xBD, 0xCA, 0x71, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0xBA, 0x0F, 0x4F, 0xDC, 0x41, 0x54, 0xBE), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0x39, 0x26, 0x70, 0x53, 0x32, 0x18, 0x11), + MBEDTLS_BYTES_TO_T_UINT_8(0x32, 0x46, 0x07, 0x97, 0x3A, 0x57, 0xE0, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0x92, 0x4F, 0xCE, 0xDF, 0x25, 0x80, 0x26), + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0x6F, 0x9A, 0x03, 0x05, 0x4B, 0xD1, 0x47), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_17_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x25, 0x01, 0x72, 0x30, 0x90, 0x17, 0x51, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0xFB, 0x41, 0x65, 0x5C, 0xB4, 0x2D, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0xCD, 0xCD, 0xAA, 0x41, 0xCC, 0xBB, 0x07), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0xCE, 0x08, 0x0A, 0x63, 0xE9, 0xA2, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0xA8, 0x21, 0x7F, 0x7A, 0x5B, 0x9B, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0x6B, 0x89, 0x44, 0x0A, 0x7F, 0x85, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0x7D, 0xDE, 0x7C, 0x19, 0x5C, 0x65, 0x26, 0x61), + MBEDTLS_BYTES_TO_T_UINT_8(0xD7, 0xAC, 0x62, 0x29, 0x4A, 0xF1, 0xD0, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_18_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x32, 0x00, 0x40, 0x87, 0xEB, 0xA9, 0x58, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0x51, 0x0B, 0xFF, 0x56, 0x35, 0x51, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0xAC, 0x08, 0x94, 0x71, 0xDA, 0xEC, 0x99), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x4D, 0xC5, 0x7B, 0x31, 0x8B, 0x8D, 0x5E), + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x05, 0xF1, 0x3E, 0x9E, 0x8F, 0x17, 0x8F), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0x9C, 0x4B, 0x62, 0x94, 0xAD, 0x49, 0xFC), + MBEDTLS_BYTES_TO_T_UINT_8(0x0F, 0xC9, 0xC6, 0x8F, 0xFD, 0x33, 0x44, 0x34), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x96, 0x17, 0x7F, 0x42, 0xBE, 0xF7, 0x0D), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_18_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFB, 0x29, 0x39, 0x13, 0x08, 0x8D, 0x91, 0x47), + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0x79, 0xF9, 0x2F, 0xA9, 0x0A, 0xCF, 0xD6), + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0x87, 0x7A, 0xA3, 0x19, 0xAB, 0x55, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x0B, 0x01, 0xC5, 0x56, 0x19, 0x9D, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0xDE, 0x82, 0x3B, 0xEA, 0xD3, 0x0B, 0x8C), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x6B, 0xC7, 0xF3, 0x0F, 0x82, 0x87, 0x6C), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0x2E, 0x23, 0xF2, 0x39, 0x9D, 0x49, 0x70), + MBEDTLS_BYTES_TO_T_UINT_8(0x31, 0xDE, 0xAF, 0x7A, 0xEE, 0xB0, 0xDA, 0x70), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_19_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0x4E, 0x2A, 0x50, 0xFD, 0x8E, 0xC0, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0x0F, 0x7C, 0x76, 0x63, 0xD8, 0x89, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0xEC, 0x2D, 0xB9, 0x4E, 0xF4, 0xEE, 0x85, 0xCF), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0x95, 0x5C, 0x96, 0x5D, 0xAA, 0x59, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0xDB, 0xD2, 0x68, 0x8E, 0x5A, 0x94, 0x60), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x02, 0xBF, 0x77, 0x9F, 0xB9, 0x4C, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0xDC, 0xC0, 0xCF, 0x81, 0x1E, 0xC4, 0x6C), + MBEDTLS_BYTES_TO_T_UINT_8(0x2B, 0xCC, 0x37, 0x86, 0xDC, 0xE2, 0x64, 0x72), + MBEDTLS_BYTES_TO_T_UINT_8(0xD5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_19_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2C, 0x30, 0xB1, 0x59, 0x20, 0x9D, 0x98, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x77, 0x0C, 0x9D, 0xF8, 0x20, 0xDC, 0x90, 0xBA), + MBEDTLS_BYTES_TO_T_UINT_8(0xB1, 0xA0, 0xF4, 0xE7, 0x3E, 0x9C, 0x9E, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0xB5, 0x25, 0xA2, 0xB0, 0x54, 0xCD, 0x2E, 0x33), + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0xD9, 0x42, 0xB0, 0x80, 0xB0, 0xA3, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0x9F, 0xFE, 0x9D, 0x8D, 0x40, 0xFF, 0x27, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0x9D, 0xA6, 0x88, 0x3A, 0x8B, 0x6F, 0x14), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x39, 0xEE, 0x1F, 0x3F, 0xB1, 0x4F, 0x63), + MBEDTLS_BYTES_TO_T_UINT_8(0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_20_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0xD7, 0x9E, 0xFF, 0xD2, 0x35, 0x67, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0x4F, 0x15, 0x5D, 0xE3, 0xE8, 0x53, 0x86), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0xF7, 0x24, 0x98, 0xA2, 0xCB, 0x11, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0x06, 0x2E, 0x25, 0xE1, 0x94, 0xC5, 0xA3, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0xE0, 0x82, 0x6E, 0xBA, 0xE7, 0x43, 0x25, 0xB0), + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0x65, 0xB4, 0x49, 0x73, 0x18, 0x35, 0x54), + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0x5B, 0xBC, 0x62, 0x86, 0x4C, 0xC1, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0xF2, 0x95, 0xA2, 0xBB, 0xA2, 0x35, 0x65), + MBEDTLS_BYTES_TO_T_UINT_8(0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_20_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0x59, 0x62, 0xB0, 0x4B, 0x1E, 0xB4, 0xD8), + MBEDTLS_BYTES_TO_T_UINT_8(0x0D, 0x55, 0xCE, 0xB0, 0x69, 0xBA, 0x63, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0x6E, 0x69, 0x86, 0xDB, 0x34, 0x7D, 0x68, 0x64), + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x06, 0xCA, 0x55, 0x44, 0x36, 0x2B, 0xBA), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0xD4, 0xC4, 0x3D, 0xCD, 0x9E, 0x69, 0xA4), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0x44, 0xE4, 0xBF, 0x31, 0xE6, 0x40, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0x4F, 0xFA, 0x75, 0xE3, 0xFB, 0x97, 0x0E), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0xC0, 0xBD, 0x1C, 0x48, 0xB0, 0x26, 0xD0), + MBEDTLS_BYTES_TO_T_UINT_8(0xD2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_21_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x7B, 0x32, 0xFA, 0xF2, 0x6D, 0x84, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x21, 0x03, 0x1D, 0x0D, 0x22, 0x55, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0xF9, 0x42, 0x03, 0x9C, 0xC2, 0xCB, 0xBA), + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0xA1, 0x96, 0xD9, 0x9D, 0x11, 0x6F, 0xBE), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0x40, 0x57, 0xEB, 0x40, 0x2D, 0xC0, 0x11), + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0x96, 0xBB, 0x4F, 0x2F, 0x23, 0xA8, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0x29, 0x85, 0x21, 0xA5, 0x50, 0x62, 0x06), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x7D, 0x92, 0xCF, 0x87, 0x0C, 0x22, 0xF9), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_21_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x0E, 0xA5, 0x32, 0x5B, 0xDF, 0x9C, 0xD5), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0x96, 0x37, 0x2C, 0x88, 0x35, 0x30, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0xB4, 0x69, 0xFF, 0xEB, 0xC6, 0x94, 0x08), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x55, 0x60, 0xAD, 0xAA, 0x58, 0x14, 0x88), + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0xFF, 0xF2, 0xB2, 0xD5, 0xA7, 0xD9, 0x27), + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0xAE, 0x54, 0xD2, 0x60, 0x31, 0xF3, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0x92, 0x83, 0xE3, 0xF1, 0x42, 0x83, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0x49, 0xD2, 0xC8, 0xB7, 0x76, 0x45, 0x7F, 0x7D), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_22_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x4A, 0x11, 0xA4, 0xFB, 0x7A, 0x01, 0xBC, 0xC8), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0x27, 0x73, 0x8D, 0x02, 0x91, 0x27, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0x62, 0xF6, 0xDD, 0x6B, 0xFA, 0x5B, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0xCA, 0xA2, 0x44, 0x2C, 0xF0, 0x28, 0xD8), + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0xF1, 0x7A, 0xA2, 0x42, 0x4C, 0x50, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0x83, 0x3E, 0x50, 0xAB, 0x9C, 0xF7, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0xED, 0x78, 0xCB, 0x76, 0x69, 0xDA, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x01, 0x1E, 0x43, 0x27, 0x47, 0x6E, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_22_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD3, 0x4F, 0x54, 0xB9, 0x3E, 0xBD, 0xD5, 0x44), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x35, 0x40, 0x69, 0x7F, 0x74, 0x9D, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x06, 0x6F, 0x67, 0x68, 0x2B, 0x4D, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0x65, 0x41, 0xFC, 0x7C, 0x1E, 0xE8, 0xC8), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0x79, 0x37, 0xAF, 0xFD, 0xD2, 0xDA, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0x33, 0xA8, 0x69, 0x56, 0x62, 0xA4, 0xE4, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0x71, 0x73, 0x21, 0x8A, 0x17, 0x81, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0x14, 0x55, 0x8F, 0x7B, 0xB8, 0xAF, 0xF7, 0x86), + MBEDTLS_BYTES_TO_T_UINT_8(0xAA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_23_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x4B, 0xD1, 0xBD, 0xBE, 0x8C, 0xBC, 0x60, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0x62, 0xA6, 0x57, 0x8C, 0xAE, 0x5C, 0x19, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0x7A, 0x43, 0xE4, 0xD9, 0xD8, 0x7B, 0xE7, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0xB9, 0xE4, 0x85, 0x7C, 0x2E, 0xFC, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0x02, 0x2E, 0x01, 0x2A, 0x6D, 0x56, 0xBE, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0x0C, 0x25, 0x9B, 0xAE, 0x86, 0x37, 0x43), + MBEDTLS_BYTES_TO_T_UINT_8(0x4A, 0x22, 0xB3, 0xCB, 0x99, 0x66, 0xB7, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0x56, 0xF7, 0x90, 0xF0, 0x1B, 0x09, 0x27, 0xF7), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_23_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x16, 0x08, 0xEF, 0x39, 0x64, 0x49, 0x31), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0xA0, 0xE3, 0x97, 0xA9, 0x07, 0x54, 0x26), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0xFF, 0xE2, 0x00, 0x07, 0x21, 0x88, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0xFD, 0x59, 0x53, 0x05, 0x6C, 0x42, 0x27), + MBEDTLS_BYTES_TO_T_UINT_8(0x8F, 0xF7, 0x39, 0x5C, 0x82, 0x36, 0xE8, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0x2E, 0x83, 0xA8, 0xE2, 0xA8, 0x43, 0x07, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0xAF, 0x2B, 0x79, 0xED, 0xD8, 0x39, 0x87), + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x20, 0x91, 0x7A, 0xC4, 0x07, 0xEF, 0x6C), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_24_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0x10, 0x2F, 0xAA, 0x0C, 0x94, 0x0E, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0x81, 0x87, 0x41, 0x23, 0xEB, 0x55, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0x53, 0xCC, 0x79, 0xB6, 0xEB, 0x6C, 0xCC), + MBEDTLS_BYTES_TO_T_UINT_8(0xF4, 0x77, 0x73, 0x9D, 0xFC, 0x64, 0x6F, 0x7F), + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0x40, 0xE3, 0x6D, 0x1C, 0x16, 0x71, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0xF4, 0x1B, 0xFF, 0x1C, 0x2F, 0xA5, 0xD7), + MBEDTLS_BYTES_TO_T_UINT_8(0x06, 0x0E, 0x0B, 0x11, 0xF4, 0x8D, 0x93, 0xAF), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0xC5, 0x64, 0x6F, 0x24, 0x19, 0xF2, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_24_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0xB3, 0xAF, 0xA5, 0x0E, 0x4F, 0x5E, 0xE1), + MBEDTLS_BYTES_TO_T_UINT_8(0x0F, 0x77, 0xCA, 0xF2, 0x6D, 0xC5, 0xF6, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0x90, 0x18, 0x8E, 0x33, 0x68, 0x6C, 0xE8, 0xE0), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x8B, 0x80, 0x90, 0x19, 0x7F, 0x90, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0x80, 0x6B, 0x68, 0xE2, 0x7D, 0xD4, 0xD0), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0xC1, 0x67, 0xB3, 0x72, 0xCB, 0xBF, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0xD5, 0xD3, 0x1D, 0x14, 0x58, 0x0A, 0x80), + MBEDTLS_BYTES_TO_T_UINT_8(0x79, 0x7A, 0x65, 0x98, 0xB3, 0x07, 0x4B, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_25_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0x87, 0x0F, 0x5F, 0xCF, 0xA2, 0x01, 0x08), + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0xC9, 0xC8, 0x6E, 0x35, 0x87, 0xA5, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0x94, 0x3E, 0x91, 0xA0, 0xAB, 0x24, 0x1E, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0xBC, 0x02, 0x35, 0x70, 0xC1, 0x5F, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x59, 0xA0, 0x50, 0x04, 0x80, 0x52, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0x56, 0x6E, 0x42, 0x8F, 0x8C, 0x91, 0x65), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xA2, 0xCB, 0xA5, 0xDE, 0x14, 0x24, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0xCB, 0x74, 0x28, 0xE6, 0xA7, 0xE7, 0xC3), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_25_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x35, 0x73, 0xA8, 0x8F, 0x9E, 0x0E, 0x63, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0x1B, 0x77, 0xC7, 0xC1, 0x38, 0xF9, 0xDC), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0x3C, 0xCF, 0xA8, 0x7A, 0xD7, 0xF3, 0xC4), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x5F, 0x9A, 0xC9, 0xAD, 0xE9, 0x1A, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0xCF, 0x2B, 0x5E, 0xD5, 0x81, 0x95, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x88, 0x75, 0x29, 0x1F, 0xC7, 0xC7, 0xD0), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0xA9, 0x5A, 0x4D, 0x63, 0x95, 0xF9, 0x4E), + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0xCD, 0x04, 0x8F, 0xCD, 0x91, 0xDE, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_26_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x88, 0xD4, 0xFD, 0x25, 0x11, 0x99, 0x6E, 0xEA), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x83, 0x01, 0x3D, 0xFB, 0x56, 0xA5, 0x4E), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x3A, 0xDC, 0x74, 0xC2, 0xD7, 0xCF, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0x8F, 0xBD, 0xF1, 0xDD, 0xA3, 0x07, 0x03, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0xBE, 0xE9, 0x2E, 0x58, 0x84, 0x66, 0xFC), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x20, 0x78, 0x37, 0x79, 0x0B, 0xA6, 0x64), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0xF2, 0xAC, 0x65, 0xC8, 0xC9, 0x2F, 0x61), + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x93, 0xE5, 0x0D, 0x0C, 0xC6, 0xB8, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_26_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x69, 0xAD, 0x5C, 0x19, 0x12, 0x61, 0x0E, 0x25), + MBEDTLS_BYTES_TO_T_UINT_8(0x39, 0x4F, 0x0B, 0x1F, 0x49, 0x7E, 0xCD, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0x2E, 0x30, 0x61, 0xDB, 0x08, 0x68, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0x78, 0xAF, 0xB3, 0x08, 0xC1, 0x69, 0xE5), + MBEDTLS_BYTES_TO_T_UINT_8(0xC4, 0x5F, 0x5D, 0xC1, 0x57, 0x6F, 0xD8, 0x34), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0xD3, 0x6A, 0xF7, 0xFD, 0x86, 0xE5, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0x63, 0xBD, 0x70, 0x7B, 0x47, 0xE8, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0x62, 0xC8, 0x7E, 0x9D, 0x11, 0x2B, 0xA5), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_27_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xE2, 0x84, 0xFD, 0xD5, 0x9A, 0x56, 0x7F, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0xBB, 0xA4, 0x6F, 0x12, 0x6E, 0x4D, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x08, 0xA1, 0x82, 0x9C, 0x62, 0x74, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0x9E, 0x58, 0x22, 0x05, 0x1D, 0x15, 0x35, 0x79), + MBEDTLS_BYTES_TO_T_UINT_8(0x9A, 0x88, 0xCF, 0x5C, 0x05, 0x78, 0xFB, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x6B, 0x2F, 0x79, 0x09, 0x73, 0x67, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0xA0, 0x80, 0xD8, 0xE8, 0xEC, 0xFB, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xE7, 0x0B, 0xB7, 0x81, 0x48, 0x7B, 0xD9), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_27_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x53, 0xA9, 0xED, 0x61, 0x92, 0xD7, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x49, 0xD9, 0x5D, 0x9B, 0x4E, 0x89, 0x35), + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0x12, 0xEB, 0x9A, 0xC9, 0xCB, 0xC1, 0x95), + MBEDTLS_BYTES_TO_T_UINT_8(0x35, 0xDC, 0x95, 0x16, 0xFE, 0x29, 0x70, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x33, 0xB1, 0xD6, 0x78, 0xB9, 0xE2, 0x36), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0xCE, 0x88, 0xC3, 0xFD, 0x7A, 0x6B, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0x1E, 0x50, 0x1E, 0xAF, 0xB1, 0x25, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0xE7, 0xD7, 0xD5, 0xBD, 0x7A, 0x12, 0xF9), + MBEDTLS_BYTES_TO_T_UINT_8(0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_28_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x22, 0xAA, 0xA2, 0x80, 0x5D, 0x8F, 0xCD, 0xC8), + MBEDTLS_BYTES_TO_T_UINT_8(0x48, 0x39, 0x79, 0x64, 0xA1, 0x67, 0x3C, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0xC7, 0x49, 0xFF, 0x7F, 0xAC, 0xAB, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0x54, 0x3E, 0x83, 0xF0, 0x3D, 0xBC, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0x92, 0x4A, 0x38, 0x42, 0x8A, 0xAB, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0xE7, 0x0B, 0x4F, 0xEE, 0x9E, 0x92, 0xA5, 0xBE), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0xDD, 0x19, 0x96, 0xF2, 0xF0, 0x6B, 0x2E), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0xFC, 0xDD, 0xB2, 0x8A, 0xE5, 0x4C, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_28_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0x06, 0x49, 0xAC, 0x99, 0x7E, 0xF8, 0x12), + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0xC8, 0x01, 0x51, 0xEA, 0xF6, 0x52, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0x43, 0x89, 0x66, 0x2B, 0x1F, 0x9B, 0x2A, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0xDF, 0x0F, 0x95, 0x07, 0x2B, 0x6C, 0x6E, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0x24, 0xC3, 0xB4, 0xBB, 0x91, 0x1F, 0xA3, 0x72), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x6E, 0x54, 0x28, 0x7B, 0x9C, 0x79, 0x2E), + MBEDTLS_BYTES_TO_T_UINT_8(0x03, 0x45, 0xFF, 0xA6, 0xDA, 0xA2, 0x83, 0x71), + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0xDE, 0x8F, 0x17, 0x37, 0x82, 0xCB, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_29_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0x94, 0x3F, 0x26, 0xC9, 0x1D, 0xD9, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0x97, 0x28, 0x20, 0xCD, 0xC1, 0xF3, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0xC9, 0xB5, 0x60, 0x9B, 0x1E, 0xDC, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0xB9, 0x5B, 0x7D, 0xA0, 0xB2, 0x8C, 0xF0), + MBEDTLS_BYTES_TO_T_UINT_8(0x33, 0xD1, 0x42, 0xE6, 0x39, 0x33, 0x6D, 0xBB), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0xC0, 0xFC, 0xD2, 0x14, 0x5D, 0x3E, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0x78, 0x4A, 0x3E, 0x40, 0x16, 0x93, 0x15, 0xCF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x24, 0xC1, 0x27, 0x27, 0xE5, 0x4B, 0xD8), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_29_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x50, 0xD8, 0xBC, 0xC1, 0x46, 0x22, 0xBB), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0x0E, 0x60, 0xA1, 0xB3, 0x50, 0xD4, 0x86), + MBEDTLS_BYTES_TO_T_UINT_8(0x80, 0xB1, 0x26, 0xB6, 0x6D, 0x47, 0x5A, 0x6F), + MBEDTLS_BYTES_TO_T_UINT_8(0x45, 0xAC, 0x11, 0x35, 0x3E, 0xB9, 0xF4, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0x97, 0xFA, 0xBB, 0x6B, 0x39, 0x13, 0xD8), + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x7B, 0x34, 0x12, 0x75, 0x8E, 0x9B, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0x2C, 0x9E, 0xCD, 0x29, 0xB6, 0xEF, 0x8D, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0xAC, 0xE9, 0x25, 0x27, 0xBB, 0x78, 0x47), + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_30_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0x7A, 0xA8, 0xD3, 0xE3, 0x66, 0xE5, 0x66), + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0x4C, 0xC4, 0x2C, 0x76, 0x81, 0x50, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0xEE, 0x71, 0x08, 0xB8, 0x52, 0x7C, 0xAF, 0xDC), + MBEDTLS_BYTES_TO_T_UINT_8(0x45, 0x59, 0x24, 0xDD, 0xFB, 0x2F, 0xD0, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0xCD, 0x56, 0xE9, 0xAC, 0x91, 0xE6, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0xE5, 0x64, 0x20, 0xC6, 0x9F, 0xE4, 0xEF, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x2C, 0x8F, 0x8C, 0x97, 0xF6, 0x22, 0xC3), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xF4, 0x88, 0xAA, 0xA8, 0xD7, 0xA5, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_30_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0x6C, 0xAE, 0x83, 0xB1, 0x55, 0x55, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x67, 0x84, 0x47, 0x7C, 0x83, 0x5C, 0x89), + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0x10, 0x4D, 0xDD, 0x30, 0x60, 0xB0, 0xE6), + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0xA7, 0x36, 0x76, 0x24, 0x32, 0x9F, 0x9D), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x42, 0x81, 0xFB, 0xA4, 0x2E, 0x13, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0x94, 0x91, 0xFF, 0x99, 0xA0, 0x09, 0x61), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0x83, 0xA1, 0x76, 0xAF, 0x37, 0x5C, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xA8, 0x04, 0x86, 0xC4, 0xA9, 0x79, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_31_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x8C, 0xC2, 0x34, 0xFB, 0x83, 0x28, 0x27), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0x03, 0x7D, 0x5E, 0x9E, 0x0E, 0xB0, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0xA2, 0x02, 0x46, 0x7F, 0xB9, 0xAC, 0xBB, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0x06, 0xED, 0x48, 0xC2, 0x96, 0x4D, 0x56, 0x27), + MBEDTLS_BYTES_TO_T_UINT_8(0x44, 0xB5, 0xC5, 0xD1, 0xE6, 0x1C, 0x7E, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x2E, 0x18, 0x71, 0x2D, 0x7B, 0xD7, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0x46, 0x9D, 0xDE, 0xAA, 0x78, 0x8E, 0xB1), + MBEDTLS_BYTES_TO_T_UINT_8(0x4D, 0xD7, 0x69, 0x2E, 0xE1, 0xD9, 0x48, 0xDE), + MBEDTLS_BYTES_TO_T_UINT_8(0xFB, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_mpi_uint secp521r1_T_31_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0xFF, 0x9E, 0x09, 0x22, 0x22, 0xE6, 0x8D), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x14, 0x28, 0x13, 0x1B, 0x62, 0x12, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0xCC, 0x7F, 0x67, 0x03, 0xB0, 0xC0, 0xF3, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0xC3, 0x0F, 0xFB, 0x25, 0x48, 0x3E, 0xF4), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0x6E, 0x53, 0x98, 0x36, 0xB3, 0xD3, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0x81, 0x54, 0x22, 0xA4, 0xCC, 0xC1, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xBA, 0xFC, 0xA9, 0xDF, 0x68, 0x86, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x92, 0x0E, 0xC3, 0xF2, 0x58, 0xE8, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), +}; +static const mbedtls_ecp_point secp521r1_T[32] = { + ECP_POINT_INIT_XY_Z1(secp521r1_T_0_X, secp521r1_T_0_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_1_X, secp521r1_T_1_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_2_X, secp521r1_T_2_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_3_X, secp521r1_T_3_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_4_X, secp521r1_T_4_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_5_X, secp521r1_T_5_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_6_X, secp521r1_T_6_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_7_X, secp521r1_T_7_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_8_X, secp521r1_T_8_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_9_X, secp521r1_T_9_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_10_X, secp521r1_T_10_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_11_X, secp521r1_T_11_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_12_X, secp521r1_T_12_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_13_X, secp521r1_T_13_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_14_X, secp521r1_T_14_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_15_X, secp521r1_T_15_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_16_X, secp521r1_T_16_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_17_X, secp521r1_T_17_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_18_X, secp521r1_T_18_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_19_X, secp521r1_T_19_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_20_X, secp521r1_T_20_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_21_X, secp521r1_T_21_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_22_X, secp521r1_T_22_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_23_X, secp521r1_T_23_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_24_X, secp521r1_T_24_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_25_X, secp521r1_T_25_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_26_X, secp521r1_T_26_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_27_X, secp521r1_T_27_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_28_X, secp521r1_T_28_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_29_X, secp521r1_T_29_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_30_X, secp521r1_T_30_Y), + ECP_POINT_INIT_XY_Z0(secp521r1_T_31_X, secp521r1_T_31_Y), +}; +#else +#define secp521r1_T NULL +#endif +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +static const mbedtls_mpi_uint secp256k1_p[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), +}; +static const mbedtls_mpi_uint secp256k1_a[] = { + MBEDTLS_BYTES_TO_T_UINT_2(0x00, 0x00), +}; +static const mbedtls_mpi_uint secp256k1_b[] = { + MBEDTLS_BYTES_TO_T_UINT_2(0x07, 0x00), +}; +static const mbedtls_mpi_uint secp256k1_gx[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x17, 0xF8, 0x16, 0x5B, 0x81, 0xF2, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x28, 0xCE, 0x2D, 0xDB, 0xFC, 0x9B, 0x02), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0x0B, 0x87, 0xCE, 0x95, 0x62, 0xA0, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xBB, 0xDC, 0xF9, 0x7E, 0x66, 0xBE, 0x79), +}; +static const mbedtls_mpi_uint secp256k1_gy[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0xD4, 0x10, 0xFB, 0x8F, 0xD0, 0x47, 0x9C), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x54, 0x85, 0xA6, 0x48, 0xB4, 0x17, 0xFD), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0x08, 0x11, 0x0E, 0xFC, 0xFB, 0xA4, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0xC4, 0xA3, 0x26, 0x77, 0xDA, 0x3A, 0x48), +}; +static const mbedtls_mpi_uint secp256k1_n[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA), + MBEDTLS_BYTES_TO_T_UINT_8(0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF), +}; + +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 +static const mbedtls_mpi_uint secp256k1_T_0_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x17, 0xF8, 0x16, 0x5B, 0x81, 0xF2, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x28, 0xCE, 0x2D, 0xDB, 0xFC, 0x9B, 0x02), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0x0B, 0x87, 0xCE, 0x95, 0x62, 0xA0, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xBB, 0xDC, 0xF9, 0x7E, 0x66, 0xBE, 0x79), +}; +static const mbedtls_mpi_uint secp256k1_T_0_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0xD4, 0x10, 0xFB, 0x8F, 0xD0, 0x47, 0x9C), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x54, 0x85, 0xA6, 0x48, 0xB4, 0x17, 0xFD), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0x08, 0x11, 0x0E, 0xFC, 0xFB, 0xA4, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0xC4, 0xA3, 0x26, 0x77, 0xDA, 0x3A, 0x48), +}; +static const mbedtls_mpi_uint secp256k1_T_1_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xE7, 0xEE, 0xD7, 0x1E, 0x67, 0x86, 0x32, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0x23, 0x73, 0xB1, 0xA9, 0xD5, 0xCC, 0x27, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x0E, 0x11, 0x01, 0x71, 0xFE, 0x92, 0x73), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0x28, 0x63, 0x6D, 0x72, 0x09, 0xA6, 0xC0), +}; +static const mbedtls_mpi_uint secp256k1_T_1_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xCE, 0xE1, 0x69, 0xDC, 0x3E, 0x2C, 0x75, 0xC3), + MBEDTLS_BYTES_TO_T_UINT_8(0xE5, 0xB7, 0x3F, 0x30, 0x26, 0x3C, 0xDF, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0xBE, 0xB9, 0x5D, 0x0E, 0xE8, 0x5E, 0x14), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0xC3, 0x05, 0xD6, 0xB7, 0xD5, 0x24, 0xFC), +}; +static const mbedtls_mpi_uint secp256k1_T_2_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x13, 0xCF, 0x7B, 0xDC, 0xCD, 0xC3, 0x39, 0x9D), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0xDA, 0xB9, 0xE5, 0x64, 0xA7, 0x47, 0x91), + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0x46, 0xA8, 0x61, 0xF6, 0x23, 0xEB, 0x58), + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0xC1, 0xFF, 0xE4, 0x55, 0xD5, 0xC2, 0xBF), +}; +static const mbedtls_mpi_uint secp256k1_T_2_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0xBE, 0xB9, 0x59, 0x24, 0x13, 0x4A, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x45, 0x12, 0xDE, 0xBA, 0x4F, 0xEF, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0x08, 0xBF, 0xC1, 0x66, 0xAA, 0x0A, 0xBC), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0xFE, 0x30, 0x55, 0x31, 0x86, 0xA7, 0xB4), +}; +static const mbedtls_mpi_uint secp256k1_T_3_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0xBF, 0x18, 0x81, 0x67, 0x27, 0x42, 0xBD), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0x05, 0x83, 0xA4, 0xDD, 0x57, 0xD3, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x20, 0x63, 0xAB, 0xE4, 0x90, 0x70, 0xD0, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x5D, 0xFD, 0xA0, 0xEF, 0xCF, 0x1C, 0x54), +}; +static const mbedtls_mpi_uint secp256k1_T_3_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x13, 0x80, 0xE4, 0xF6, 0x09, 0xBC, 0x57, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0x9F, 0x6E, 0x88, 0x54, 0x6E, 0x51, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0x5F, 0x85, 0xFB, 0x84, 0x3E, 0x4A, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0x19, 0xF5, 0x55, 0xC9, 0x07, 0xD8, 0xCE), +}; +static const mbedtls_mpi_uint secp256k1_T_4_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1A, 0xB4, 0xC3, 0xD9, 0x5C, 0xA0, 0xD4, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0x0D, 0x30, 0xAF, 0x59, 0x9B, 0xF8, 0x04, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0x4D, 0xA6, 0xFD, 0x66, 0x7B, 0xC3, 0x39, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0xE0, 0xBF, 0xF0, 0xC2, 0xE9, 0x71, 0xA4, 0x9E), +}; +static const mbedtls_mpi_uint secp256k1_T_4_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x14, 0x2D, 0xB9, 0x88, 0x28, 0xF1, 0xBE, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0x14, 0xF3, 0x1A, 0x0E, 0xB9, 0x01, 0x66, 0x34), + MBEDTLS_BYTES_TO_T_UINT_8(0x77, 0xA7, 0xA4, 0xF4, 0x05, 0xD0, 0xAA, 0x53), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x39, 0x1E, 0x47, 0xE5, 0x68, 0xC8, 0xC0), +}; +static const mbedtls_mpi_uint secp256k1_T_5_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0xB9, 0xFC, 0xE0, 0x33, 0x8A, 0x7D, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0x93, 0xA5, 0x53, 0x55, 0x16, 0xB4, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0x5F, 0xEA, 0x9B, 0x29, 0x52, 0x71, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0xB2, 0xF0, 0x24, 0xB8, 0x7D, 0xB7, 0xA0, 0x9B), +}; +static const mbedtls_mpi_uint secp256k1_T_5_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x00, 0x27, 0xB2, 0xDF, 0x73, 0xA2, 0xE0), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x2E, 0x4D, 0x7C, 0xDE, 0x7A, 0x23, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x65, 0x60, 0xC7, 0x97, 0x1E, 0xA4, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0x13, 0x5B, 0x77, 0x59, 0xCB, 0x36, 0xE1), +}; +static const mbedtls_mpi_uint secp256k1_T_6_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0xBC, 0x9F, 0x9E, 0x2D, 0x53, 0x2A, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0x5F, 0x64, 0x9F, 0x1A, 0x19, 0xE6, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0x9E, 0x7B, 0x39, 0xD2, 0xDB, 0x85, 0x84, 0xD5), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0xC7, 0x0D, 0x58, 0x6E, 0x3F, 0x52, 0x15), +}; +static const mbedtls_mpi_uint secp256k1_T_6_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0x68, 0x19, 0x0B, 0x68, 0xC9, 0x1E, 0xFB), + MBEDTLS_BYTES_TO_T_UINT_8(0xD2, 0x4E, 0x21, 0x49, 0x3D, 0x55, 0xCC, 0x25), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xF9, 0x25, 0x45, 0x54, 0x45, 0xB1, 0x0F), + MBEDTLS_BYTES_TO_T_UINT_8(0xA9, 0xB3, 0xF7, 0xCD, 0x80, 0xA4, 0x04, 0x05), +}; +static const mbedtls_mpi_uint secp256k1_T_7_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0x1E, 0x88, 0xC4, 0xAA, 0x18, 0x7E, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0x4B, 0xAC, 0xD9, 0xB2, 0xA1, 0xC0, 0x71, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0xA9, 0xA2, 0xF1, 0x15, 0xA6, 0x5F, 0x6C, 0x86), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0x5B, 0x05, 0xBC, 0xB7, 0xC6, 0x4E, 0x72), +}; +static const mbedtls_mpi_uint secp256k1_T_7_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x80, 0xF8, 0x5C, 0x20, 0x2A, 0xE1, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x48, 0x2E, 0x68, 0x82, 0x7F, 0xEB, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0xA2, 0x3B, 0x25, 0xDB, 0x32, 0x4D, 0x88, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xEE, 0x6E, 0xA6, 0xB6, 0x6D, 0x62, 0x78, 0x22), +}; +static const mbedtls_mpi_uint secp256k1_T_8_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x4D, 0x3E, 0x86, 0x58, 0xC3, 0xEB, 0xBA), + MBEDTLS_BYTES_TO_T_UINT_8(0x1A, 0x89, 0x33, 0x18, 0x21, 0x1D, 0x9B, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0x9D, 0xFF, 0xC3, 0x79, 0xC1, 0x88, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0xD4, 0x48, 0x53, 0xE8, 0xAD, 0x21, 0x16), +}; +static const mbedtls_mpi_uint secp256k1_T_8_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0x7B, 0xDE, 0xCB, 0xD8, 0x39, 0x17, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0xD3, 0xF3, 0x03, 0xF2, 0x5C, 0xBC, 0xC8, 0x8A), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0xAE, 0x4C, 0xB0, 0x16, 0xA4, 0x93, 0x86), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x8B, 0x6B, 0xDC, 0xD7, 0x9A, 0x3E, 0x7E), +}; +static const mbedtls_mpi_uint secp256k1_T_9_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0x2D, 0x7A, 0xD2, 0x59, 0x05, 0xA2, 0x82), + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0x56, 0x09, 0x32, 0xF1, 0xE8, 0xE3, 0x72), + MBEDTLS_BYTES_TO_T_UINT_8(0x03, 0xCA, 0xE5, 0x2E, 0xF0, 0xFB, 0x18, 0x19), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x85, 0xA9, 0x23, 0x15, 0x31, 0x1F, 0x0E), +}; +static const mbedtls_mpi_uint secp256k1_T_9_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0xE5, 0xB1, 0x86, 0xB9, 0x6E, 0x8D, 0xD3), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x77, 0xFC, 0xC9, 0xA3, 0x3F, 0x89, 0xD2), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x6A, 0xDC, 0x25, 0xB0, 0xC7, 0x41, 0x54), + MBEDTLS_BYTES_TO_T_UINT_8(0x02, 0x11, 0x6B, 0xA6, 0x11, 0x62, 0xD4, 0x2D), +}; +static const mbedtls_mpi_uint secp256k1_T_10_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x7D, 0x34, 0xB3, 0x20, 0x7F, 0x37, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0xBD, 0xD4, 0x45, 0xE8, 0xC2, 0xE9, 0xC5, 0xEA), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x32, 0x3B, 0x25, 0x7E, 0x79, 0xAF, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0xE4, 0x54, 0x71, 0xBE, 0x35, 0x4E, 0xD0), +}; +static const mbedtls_mpi_uint secp256k1_T_10_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x94, 0xDD, 0x8F, 0xB5, 0xC2, 0xDD, 0x75), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0x49, 0xE9, 0x1C, 0x2F, 0x08, 0x49, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0x77, 0xB6, 0x03, 0x88, 0x6F, 0xB8, 0x15, 0x67), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0xD3, 0x1C, 0xF3, 0xA5, 0xEB, 0x79, 0x01), +}; +static const mbedtls_mpi_uint secp256k1_T_11_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x25, 0xF9, 0x43, 0x88, 0x89, 0x0D, 0x06, 0xEA), + MBEDTLS_BYTES_TO_T_UINT_8(0x02, 0x2D, 0xF5, 0x98, 0x32, 0xF6, 0xB1, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0x23, 0x73, 0x8F, 0x2B, 0x50, 0x27, 0x0A, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0xE3, 0xBD, 0x16, 0x05, 0xC8, 0x93, 0x12), +}; +static const mbedtls_mpi_uint secp256k1_T_11_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x0A, 0x6A, 0xF7, 0xE3, 0x3D, 0xDE, 0x5F, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0xA3, 0x9C, 0x22, 0x3C, 0x33, 0x36, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x20, 0x24, 0x4C, 0x69, 0x45, 0x78, 0x14, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0xF8, 0xD4, 0xBF, 0xB8, 0xC0, 0xA1, 0x25), +}; +static const mbedtls_mpi_uint secp256k1_T_12_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0x88, 0xE1, 0x91, 0x03, 0xEB, 0xB3, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0x11, 0xA1, 0xEF, 0x14, 0x0D, 0xC4, 0x7D), + MBEDTLS_BYTES_TO_T_UINT_8(0xFE, 0xD4, 0x0D, 0x1D, 0x96, 0x33, 0x5C, 0x19), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0x45, 0x2A, 0x1A, 0xE6, 0x57, 0x04, 0x9B), +}; +static const mbedtls_mpi_uint secp256k1_T_12_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0xB5, 0xA7, 0x80, 0xE9, 0x93, 0x97, 0x8D), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0xB9, 0x7C, 0xA0, 0xC9, 0x57, 0x26, 0x43), + MBEDTLS_BYTES_TO_T_UINT_8(0x9E, 0xEF, 0x56, 0xDA, 0x66, 0xF6, 0x1B, 0x9A), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x89, 0x6B, 0x91, 0xE0, 0xA9, 0x65, 0x2B), +}; +static const mbedtls_mpi_uint secp256k1_T_13_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0x98, 0x96, 0x9B, 0x06, 0x7D, 0x5E, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0x0A, 0xFA, 0xC1, 0x5F, 0x19, 0x37, 0x94, 0x9D), + MBEDTLS_BYTES_TO_T_UINT_8(0xCF, 0xBE, 0x6B, 0x1A, 0x05, 0xE4, 0xBF, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0x84, 0xCD, 0x5D, 0x35, 0xB4, 0x51, 0xF7, 0x64), +}; +static const mbedtls_mpi_uint secp256k1_T_13_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0xEF, 0x96, 0xDB, 0xF2, 0x61, 0x63, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x04, 0x88, 0xC9, 0x9F, 0x1B, 0x94, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x30, 0x79, 0x7E, 0x24, 0xE7, 0x5F, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0xB8, 0x90, 0xB7, 0x94, 0x25, 0xBB, 0x0F), +}; +static const mbedtls_mpi_uint secp256k1_T_14_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x62, 0x79, 0xEA, 0xAD, 0xC0, 0x6D, 0x18, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0xA4, 0x58, 0x2A, 0x8D, 0x95, 0xB3, 0xE6), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0xC4, 0xC2, 0x12, 0x0D, 0x79, 0xE2, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0x02, 0x6F, 0xBE, 0x97, 0x4D, 0xA4, 0x20, 0x07), +}; +static const mbedtls_mpi_uint secp256k1_T_14_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0x31, 0x71, 0xC6, 0xA6, 0x91, 0xEB, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x9B, 0xA8, 0x4A, 0xE7, 0x77, 0xE1, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0xA9, 0x06, 0xD3, 0x3D, 0x94, 0x30, 0xEF, 0x8C), + MBEDTLS_BYTES_TO_T_UINT_8(0xE7, 0xDF, 0xCA, 0xFA, 0xF5, 0x28, 0xF8, 0xC9), +}; +static const mbedtls_mpi_uint secp256k1_T_15_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xCC, 0xE1, 0x32, 0xFD, 0x3E, 0x81, 0xF8, 0x11), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0xF2, 0x4B, 0x1D, 0x19, 0xC9, 0x0F, 0xCC), + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0xB1, 0x8A, 0x22, 0x8B, 0x05, 0x6B, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0x35, 0x21, 0xEF, 0x30, 0xEC, 0x09, 0x2A, 0x89), +}; +static const mbedtls_mpi_uint secp256k1_T_15_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x84, 0x4A, 0x46, 0x07, 0x6C, 0x3C, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x18, 0x3A, 0xF4, 0xCC, 0xF5, 0xB2, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0x8F, 0xCD, 0x0A, 0x9C, 0xF4, 0xBD, 0x95), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x89, 0x7F, 0x8A, 0xB1, 0x52, 0x3A, 0xAB), +}; +static const mbedtls_ecp_point secp256k1_T[16] = { + ECP_POINT_INIT_XY_Z1(secp256k1_T_0_X, secp256k1_T_0_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_1_X, secp256k1_T_1_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_2_X, secp256k1_T_2_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_3_X, secp256k1_T_3_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_4_X, secp256k1_T_4_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_5_X, secp256k1_T_5_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_6_X, secp256k1_T_6_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_7_X, secp256k1_T_7_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_8_X, secp256k1_T_8_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_9_X, secp256k1_T_9_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_10_X, secp256k1_T_10_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_11_X, secp256k1_T_11_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_12_X, secp256k1_T_12_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_13_X, secp256k1_T_13_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_14_X, secp256k1_T_14_Y), + ECP_POINT_INIT_XY_Z0(secp256k1_T_15_X, secp256k1_T_15_Y), +}; +#else +#define secp256k1_T NULL +#endif +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +/* + * Domain parameters for brainpoolP256r1 (RFC 5639 3.4) + */ +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP256r1_p[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x77, 0x53, 0x6E, 0x1F, 0x1D, 0x48, 0x13, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x20, 0x26, 0xD5, 0x23, 0xF6, 0x3B, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9), +}; +static const mbedtls_mpi_uint brainpoolP256r1_a[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0xB5, 0x30, 0xF3, 0x44, 0x4B, 0x4A, 0xE9), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x5C, 0xDC, 0x26, 0xC1, 0x55, 0x80, 0xFB), + MBEDTLS_BYTES_TO_T_UINT_8(0xE7, 0xFF, 0x7A, 0x41, 0x30, 0x75, 0xF6, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0x30, 0x2C, 0xFC, 0x75, 0x09, 0x5A, 0x7D), +}; +static const mbedtls_mpi_uint brainpoolP256r1_b[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x07, 0x8C, 0xFF, 0x18, 0xDC, 0xCC, 0x6B), + MBEDTLS_BYTES_TO_T_UINT_8(0xCE, 0xE1, 0xF7, 0x5C, 0x29, 0x16, 0x84, 0x95), + MBEDTLS_BYTES_TO_T_UINT_8(0xBF, 0x7C, 0xD7, 0xBB, 0xD9, 0xB5, 0x30, 0xF3), + MBEDTLS_BYTES_TO_T_UINT_8(0x44, 0x4B, 0x4A, 0xE9, 0x6C, 0x5C, 0xDC, 0x26), +}; +static const mbedtls_mpi_uint brainpoolP256r1_gx[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x62, 0x32, 0xCE, 0x9A, 0xBD, 0x53, 0x44, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x23, 0xBD, 0xE3, 0xE1, 0x27, 0xDE, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0xB7, 0x81, 0xFC, 0x2F, 0x48, 0x4B, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x57, 0x7E, 0xCB, 0xB9, 0xAE, 0xD2, 0x8B), +}; +static const mbedtls_mpi_uint brainpoolP256r1_gy[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x97, 0x69, 0x04, 0x2F, 0xC7, 0x54, 0x1D, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x54, 0x8E, 0xED, 0x2D, 0x13, 0x45, 0x77, 0xC2), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x1D, 0x61, 0x14, 0x1A, 0x46, 0xF8, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0xC4, 0xDA, 0xC3, 0x35, 0xF8, 0x7E, 0x54), +}; +static const mbedtls_mpi_uint brainpoolP256r1_n[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0x56, 0x48, 0x97, 0x82, 0x0E, 0x1E, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0xF7, 0xA6, 0x61, 0xB5, 0xA3, 0x7A, 0x39, 0x8C), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9), +}; + +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 +static const mbedtls_mpi_uint brainpoolP256r1_T_0_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x62, 0x32, 0xCE, 0x9A, 0xBD, 0x53, 0x44, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x23, 0xBD, 0xE3, 0xE1, 0x27, 0xDE, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0xB7, 0x81, 0xFC, 0x2F, 0x48, 0x4B, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x57, 0x7E, 0xCB, 0xB9, 0xAE, 0xD2, 0x8B), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_0_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x97, 0x69, 0x04, 0x2F, 0xC7, 0x54, 0x1D, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x54, 0x8E, 0xED, 0x2D, 0x13, 0x45, 0x77, 0xC2), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x1D, 0x61, 0x14, 0x1A, 0x46, 0xF8, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0xC4, 0xDA, 0xC3, 0x35, 0xF8, 0x7E, 0x54), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_1_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0xA2, 0xED, 0x52, 0xC9, 0x8C, 0xE3, 0xA5), + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0xC9, 0xC4, 0x87, 0x3F, 0x93, 0x7A, 0xD1), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0x12, 0x53, 0x61, 0x3E, 0x76, 0x08, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0x8C, 0x74, 0xF4, 0x08, 0xC3, 0x76, 0x80), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_1_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x05, 0xDD, 0x09, 0xA6, 0xED, 0xEE, 0xC4, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0xD9, 0xBE, 0x4B, 0xA5, 0xB7, 0x2B, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0x20, 0x12, 0xCA, 0x0A, 0x38, 0x24, 0xAB), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x72, 0x71, 0x90, 0x7A, 0x2E, 0xB7, 0x23), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_2_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2C, 0x66, 0xA1, 0x93, 0x10, 0x2A, 0x51, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0x88, 0x10, 0x11, 0x12, 0xBC, 0xB0, 0xB6, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0x58, 0xD7, 0x0A, 0x84, 0x05, 0xA3, 0x9C), + MBEDTLS_BYTES_TO_T_UINT_8(0xF7, 0x8E, 0x95, 0x61, 0xD3, 0x0B, 0xDF, 0x36), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_2_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF9, 0x92, 0x12, 0x0F, 0x5E, 0x87, 0x70, 0x1B), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0xE9, 0x9B, 0xEB, 0x3A, 0xFB, 0xCF, 0xC4), + MBEDTLS_BYTES_TO_T_UINT_8(0xDC, 0x92, 0xB9, 0xF7, 0x45, 0xD3, 0x06, 0xB6), + MBEDTLS_BYTES_TO_T_UINT_8(0x82, 0x28, 0x65, 0xE1, 0xC5, 0x6C, 0x57, 0x18), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_3_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x0E, 0x77, 0x01, 0x81, 0x9E, 0x38, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0xF0, 0xD5, 0xA5, 0x91, 0x2B, 0xDF, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0xEE, 0xB6, 0x25, 0xD6, 0x98, 0xDE, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0xA1, 0x55, 0x63, 0x39, 0xEB, 0xB5, 0x47), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_3_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0xD6, 0xB8, 0xE3, 0x13, 0xED, 0x7F, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0xE8, 0xAE, 0x36, 0xB8, 0xCD, 0x19, 0x02), + MBEDTLS_BYTES_TO_T_UINT_8(0xF9, 0x82, 0x83, 0x7A, 0x7B, 0x46, 0x56, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0x4E, 0x60, 0x46, 0x15, 0x5A, 0xAC, 0x99, 0x30), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_4_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBF, 0x61, 0x50, 0xC6, 0xFF, 0x10, 0x7D, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x51, 0xDF, 0xA9, 0x7D, 0x78, 0x26, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0x56, 0x15, 0x9A, 0xF7, 0x01, 0xC1, 0xBB, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x0F, 0xE6, 0x2A, 0xBD, 0x4A, 0x9E, 0x87), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_4_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0xF8, 0xD1, 0x77, 0xD2, 0x49, 0xB3, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0x86, 0xFB, 0x9E, 0x1F, 0x5A, 0x60, 0x47), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0xC4, 0x8D, 0xCD, 0x86, 0x61, 0x2F, 0xF9), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0xF6, 0xB9, 0xAC, 0x37, 0x9D, 0xE9, 0x28), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_5_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x77, 0xAA, 0x97, 0x9C, 0x0B, 0x04, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0x80, 0xA6, 0x60, 0x81, 0xCE, 0x25, 0x13, 0x3E), + MBEDTLS_BYTES_TO_T_UINT_8(0x24, 0x00, 0xF3, 0xBB, 0x82, 0x99, 0x95, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0x5A, 0xCE, 0x90, 0x71, 0x38, 0x2F, 0x10), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_5_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0x1A, 0xC0, 0x84, 0x27, 0xD6, 0x9D, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0x37, 0x52, 0x16, 0x13, 0x0E, 0xCE, 0x92), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xBF, 0x5A, 0xDB, 0xDB, 0x6E, 0x1E, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0xB7, 0x5E, 0xF9, 0x86, 0xDD, 0x8A, 0x5C), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_6_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0xAB, 0x5C, 0x8D, 0x1D, 0xF2, 0x2D, 0x1E), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0xC5, 0xF8, 0xF7, 0x1D, 0x96, 0x0B, 0x4D), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x4C, 0xA7, 0x45, 0x20, 0x6A, 0x1E, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0x5D, 0xEF, 0xDE, 0xEE, 0x39, 0x44, 0x19), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_6_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x4B, 0x2F, 0x6D, 0x52, 0xC9, 0x58, 0x60, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0xC3, 0xC9, 0x62, 0xCB, 0x38, 0x3C, 0x55, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xA5, 0x09, 0x10, 0x88, 0xDB, 0xE3, 0xBD), + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0xE0, 0x3C, 0xCE, 0x06, 0x0B, 0x4B, 0x5D), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_7_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB1, 0x1D, 0xB4, 0x10, 0x76, 0x8F, 0xBA, 0x09), + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0x70, 0x5A, 0x07, 0xF5, 0x1A, 0x74, 0xC7), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0xE9, 0x94, 0xA8, 0xC0, 0xD5, 0x4A, 0x4A), + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0x6D, 0xD4, 0xE8, 0x9B, 0xE9, 0x6D, 0x0E), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_7_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x00, 0x32, 0x41, 0x57, 0x84, 0x89, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0xEE, 0xC7, 0x14, 0xEC, 0xE9, 0x27, 0xFF, 0xF3), + MBEDTLS_BYTES_TO_T_UINT_8(0x9A, 0x67, 0x9E, 0xFB, 0xB6, 0xB8, 0x96, 0xF3), + MBEDTLS_BYTES_TO_T_UINT_8(0xE5, 0x4A, 0xE3, 0x97, 0x4B, 0x58, 0xDE, 0x30), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_8_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA6, 0x1E, 0x5C, 0xF5, 0x7F, 0xD5, 0xD4, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0x08, 0x7A, 0xF1, 0xBD, 0x89, 0xC7, 0x1E), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0xF9, 0x11, 0x1B, 0xF5, 0x3C, 0x6D, 0x8C), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x50, 0xE5, 0x69, 0x1D, 0x59, 0xFC, 0x0C), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_8_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x2F, 0xF8, 0x3F, 0xEC, 0x55, 0x99, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0xA7, 0x29, 0x90, 0x43, 0x81, 0x31, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0xC3, 0x18, 0x44, 0x50, 0x5D, 0x76, 0xCB, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0xC5, 0x5B, 0x9A, 0x03, 0xE6, 0x17, 0x39), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_9_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0x89, 0xFC, 0x55, 0x94, 0x91, 0x6A, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0x46, 0x35, 0xF2, 0x3A, 0x42, 0x08, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0xD3, 0xD2, 0x76, 0x49, 0x42, 0x87, 0xD3, 0x7F), + MBEDTLS_BYTES_TO_T_UINT_8(0x90, 0xEA, 0xA0, 0x52, 0xF1, 0x6A, 0x30, 0x57), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_9_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0xB2, 0x57, 0xA3, 0x8A, 0x4D, 0x1B, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0xA3, 0x99, 0x94, 0xB5, 0x3D, 0x64, 0x09), + MBEDTLS_BYTES_TO_T_UINT_8(0x35, 0xC3, 0xD7, 0x53, 0xF6, 0x49, 0x1C, 0x60), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0x23, 0x41, 0x4D, 0xFB, 0x7A, 0x5C, 0x53), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_10_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0xB8, 0x15, 0x65, 0x5C, 0x85, 0x94, 0xD7), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x37, 0xC7, 0xF8, 0x7E, 0xAE, 0x6C, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0x53, 0xD8, 0x11, 0x54, 0x98, 0x44, 0xE3, 0xF1), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0x4D, 0xA6, 0x4B, 0x28, 0xF2, 0x57, 0x9E), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_10_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0xD0, 0xEB, 0x1E, 0xAA, 0x30, 0xD3, 0x6A), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0x9B, 0x4D, 0xA7, 0x73, 0x6E, 0xB6, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0x47, 0xF6, 0xED, 0x37, 0xEF, 0x71, 0x4D), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0xB5, 0x49, 0x61, 0x5E, 0x45, 0xF6, 0x4A), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_11_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0x0E, 0xB3, 0x84, 0x3A, 0x63, 0x72, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x53, 0x5C, 0xA7, 0xC6, 0x2E, 0xAB, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0x0F, 0x8F, 0x87, 0x50, 0x28, 0xB4, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0x98, 0x4A, 0x98, 0x31, 0x86, 0xCA, 0x51), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_11_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0xC9, 0xE2, 0xFD, 0x5D, 0x1F, 0xE8, 0xC2), + MBEDTLS_BYTES_TO_T_UINT_8(0xD5, 0x90, 0x91, 0xC4, 0x84, 0xF0, 0xBA, 0xC5), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x5A, 0xB3, 0x4E, 0xFB, 0xE0, 0x57, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0x6B, 0x0B, 0x90, 0xA6, 0xFD, 0x9D, 0x8E, 0x02), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_12_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0x41, 0x8F, 0x31, 0xFA, 0x5A, 0xF6, 0x33), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xE9, 0xE3, 0xF6, 0xE0, 0x4A, 0xE7, 0xD2), + MBEDTLS_BYTES_TO_T_UINT_8(0x84, 0x4E, 0xCD, 0xA2, 0x22, 0x14, 0xD4, 0x12), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0xED, 0x21, 0xB7, 0x0F, 0x53, 0x10, 0x17), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_12_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x05, 0x06, 0x24, 0x2C, 0x4E, 0xD1, 0x1E, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0xD7, 0x3F, 0xC1, 0x9F, 0xAB, 0xF0, 0x37, 0x95), + MBEDTLS_BYTES_TO_T_UINT_8(0x03, 0x5E, 0x12, 0xCE, 0x83, 0x1B, 0x2A, 0x18), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0x65, 0xCF, 0xE8, 0x5C, 0xA5, 0xA2, 0x70), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_13_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0x86, 0x76, 0x3A, 0x94, 0xF6, 0x1D, 0xC1), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0xDA, 0xC9, 0xA6, 0x29, 0x93, 0x15, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x61, 0x6A, 0x7D, 0xC7, 0xA9, 0xF3, 0x76), + MBEDTLS_BYTES_TO_T_UINT_8(0x4A, 0x03, 0x71, 0xA2, 0x15, 0xCE, 0x50, 0x72), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_13_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0xD0, 0xA8, 0x1E, 0x91, 0xC4, 0x4F, 0x24), + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0x4B, 0x7E, 0xD7, 0x71, 0x58, 0x7E, 0x1E), + MBEDTLS_BYTES_TO_T_UINT_8(0x93, 0x45, 0xAF, 0x2A, 0x18, 0x93, 0x95, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0x1B, 0x8F, 0xC7, 0xFA, 0x4C, 0x7A, 0x86, 0x54), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_14_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x97, 0xAF, 0x68, 0x3A, 0x23, 0xC1, 0x2E, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0x89, 0x50, 0x11, 0x67, 0x39, 0xB9, 0xAF, 0x48), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x86, 0xAA, 0x1E, 0x88, 0x21, 0x29, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0x28, 0xA4, 0x9D, 0x89, 0xA9, 0x9A, 0x10), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_14_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0xBA, 0x04, 0x67, 0xB7, 0x01, 0x40, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0xE9, 0x09, 0xA3, 0xCA, 0xA6, 0x37, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x97, 0xA8, 0xB6, 0x3C, 0xEE, 0x90, 0x3D), + MBEDTLS_BYTES_TO_T_UINT_8(0xDC, 0xED, 0xC4, 0xF7, 0xC3, 0x95, 0xEC, 0x85), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_15_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0x84, 0xBD, 0xEB, 0xD5, 0x64, 0xBB, 0x9D), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x9B, 0xE2, 0x28, 0x50, 0xC2, 0x72, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x39, 0xF2, 0x74, 0xD1, 0x26, 0xBF, 0x32, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0xCB, 0xAF, 0x72, 0xDB, 0x6D, 0x30, 0x98), +}; +static const mbedtls_mpi_uint brainpoolP256r1_T_15_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB3, 0x50, 0x85, 0xF4, 0x2B, 0x48, 0xC1, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0x28, 0xBB, 0x11, 0xBA, 0x5B, 0x22, 0x6C), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0xA1, 0xE5, 0x5C, 0xC9, 0x1D, 0x44, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0xE8, 0xE6, 0x6F, 0xBB, 0xC1, 0x81, 0x7F), +}; +static const mbedtls_ecp_point brainpoolP256r1_T[16] = { + ECP_POINT_INIT_XY_Z1(brainpoolP256r1_T_0_X, brainpoolP256r1_T_0_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_1_X, brainpoolP256r1_T_1_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_2_X, brainpoolP256r1_T_2_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_3_X, brainpoolP256r1_T_3_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_4_X, brainpoolP256r1_T_4_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_5_X, brainpoolP256r1_T_5_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_6_X, brainpoolP256r1_T_6_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_7_X, brainpoolP256r1_T_7_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_8_X, brainpoolP256r1_T_8_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_9_X, brainpoolP256r1_T_9_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_10_X, brainpoolP256r1_T_10_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_11_X, brainpoolP256r1_T_11_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_12_X, brainpoolP256r1_T_12_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_13_X, brainpoolP256r1_T_13_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_14_X, brainpoolP256r1_T_14_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP256r1_T_15_X, brainpoolP256r1_T_15_Y), +}; +#else +#define brainpoolP256r1_T NULL +#endif + +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ + +/* + * Domain parameters for brainpoolP384r1 (RFC 5639 3.6) + */ +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP384r1_p[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x53, 0xEC, 0x07, 0x31, 0x13, 0x00, 0x47, 0x87), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x1A, 0x1D, 0x90, 0x29, 0xA7, 0xD3, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0x23, 0x11, 0xB7, 0x7F, 0x19, 0xDA, 0xB1, 0x12), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C), +}; +static const mbedtls_mpi_uint brainpoolP384r1_a[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0xD4, 0x3A, 0x50, 0x4A, 0x81, 0xA5, 0x8A), + MBEDTLS_BYTES_TO_T_UINT_8(0x0F, 0xF9, 0x91, 0xBA, 0xEF, 0x65, 0x91, 0x13), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0x27, 0xB2, 0x4F, 0x8E, 0xA2, 0xBE, 0xC2), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0xAF, 0x05, 0xCE, 0x0A, 0x08, 0x72, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0x15, 0x8C, 0x3D, 0xC6, 0x82, 0xC3, 0x7B), +}; +static const mbedtls_mpi_uint brainpoolP384r1_b[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0x4C, 0x50, 0xFA, 0x96, 0x86, 0xB7, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0x94, 0xC9, 0xDB, 0x95, 0x02, 0x39, 0xB4, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0xD5, 0x62, 0xEB, 0x3E, 0xA5, 0x0E, 0x88, 0x2E), + MBEDTLS_BYTES_TO_T_UINT_8(0xA6, 0xD2, 0xDC, 0x07, 0xE1, 0x7D, 0xB7, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x44, 0xF0, 0x16, 0x54, 0xB5, 0x39, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04), +}; +static const mbedtls_mpi_uint brainpoolP384r1_gx[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xAF, 0xD4, 0x47, 0xE2, 0xB2, 0x87, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0xAA, 0x46, 0xD6, 0x36, 0x34, 0xE0, 0x26, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x10, 0xBD, 0x0C, 0xFE, 0xCA, 0x7F, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x4F, 0xF1, 0x7E, 0xE7, 0xA3, 0x47, 0x88), + MBEDTLS_BYTES_TO_T_UINT_8(0x6B, 0x3F, 0xC1, 0xB7, 0x81, 0x3A, 0xA6, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0x45, 0xCF, 0x68, 0xF0, 0x64, 0x1C, 0x1D), +}; +static const mbedtls_mpi_uint brainpoolP384r1_gy[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x53, 0x3C, 0x26, 0x41, 0x03, 0x82, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0x81, 0x91, 0x77, 0x21, 0x46, 0x46, 0x0E), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x29, 0x91, 0xF9, 0x4F, 0x05, 0x9C, 0xE1), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x58, 0xEC, 0xFE, 0x29, 0x0B, 0xB7, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0xD5, 0xCF, 0x95, 0x8E, 0xEB, 0xB1, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0xC2, 0xF9, 0x20, 0x75, 0x1D, 0xBE, 0x8A), +}; +static const mbedtls_mpi_uint brainpoolP384r1_n[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x65, 0x04, 0xE9, 0x02, 0x32, 0x88, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0xC3, 0x7F, 0x6B, 0xAF, 0xB6, 0x3A, 0xCF), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0x25, 0x04, 0xAC, 0x6C, 0x6E, 0x16, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0xB3, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C), +}; + +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 +static const mbedtls_mpi_uint brainpoolP384r1_T_0_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xAF, 0xD4, 0x47, 0xE2, 0xB2, 0x87, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0xAA, 0x46, 0xD6, 0x36, 0x34, 0xE0, 0x26, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x10, 0xBD, 0x0C, 0xFE, 0xCA, 0x7F, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x4F, 0xF1, 0x7E, 0xE7, 0xA3, 0x47, 0x88), + MBEDTLS_BYTES_TO_T_UINT_8(0x6B, 0x3F, 0xC1, 0xB7, 0x81, 0x3A, 0xA6, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0x45, 0xCF, 0x68, 0xF0, 0x64, 0x1C, 0x1D), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_0_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x53, 0x3C, 0x26, 0x41, 0x03, 0x82, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0x81, 0x91, 0x77, 0x21, 0x46, 0x46, 0x0E), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x29, 0x91, 0xF9, 0x4F, 0x05, 0x9C, 0xE1), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x58, 0xEC, 0xFE, 0x29, 0x0B, 0xB7, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0xD5, 0xCF, 0x95, 0x8E, 0xEB, 0xB1, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0xC2, 0xF9, 0x20, 0x75, 0x1D, 0xBE, 0x8A), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_1_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x93, 0xD8, 0x8A, 0x54, 0x41, 0xD6, 0x6B, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0xE2, 0x3B, 0xF1, 0x22, 0xFD, 0x2D, 0x4B, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0x55, 0xE3, 0x33, 0xF0, 0x73, 0x52, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0x3F, 0x30, 0x26, 0xCA, 0x7F, 0x52, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0xD3, 0x6E, 0x17, 0x9B, 0xD5, 0x2A, 0x4A, 0x31), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0xDA, 0x6B, 0xE5, 0x03, 0x07, 0x1D, 0x2E), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_1_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0x7A, 0xAF, 0x98, 0xE3, 0xA4, 0xF6, 0x19), + MBEDTLS_BYTES_TO_T_UINT_8(0xEC, 0x7D, 0xFE, 0x51, 0x40, 0x3B, 0x47, 0xD2), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x88, 0xEC, 0xC4, 0xE2, 0x8F, 0xCB, 0xA4), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0xE2, 0x88, 0x2D, 0x4E, 0x50, 0xEB, 0x9A), + MBEDTLS_BYTES_TO_T_UINT_8(0x13, 0x54, 0x94, 0x5E, 0xF4, 0x7F, 0x3A, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0x07, 0x1C, 0xE1, 0xBD, 0x0F, 0xF8, 0x63), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_2_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x94, 0x92, 0x28, 0x2E, 0x32, 0x04, 0xB1, 0x4D), + MBEDTLS_BYTES_TO_T_UINT_8(0x25, 0x82, 0x44, 0x43, 0x76, 0x0D, 0x55, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0xE3, 0xFF, 0x89, 0x46, 0xDE, 0x4E, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0x22, 0xBB, 0x67, 0x1A, 0x81, 0xEE, 0x27), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0x54, 0xE2, 0x7A, 0xAE, 0xDA, 0x2C, 0xD0), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0x9A, 0x90, 0xAA, 0x6E, 0x8B, 0xCC, 0x5F), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_2_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0x40, 0xAC, 0xED, 0x7D, 0x37, 0x87, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0xF8, 0xB1, 0x80, 0x4C, 0x8C, 0x04, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x98, 0x2C, 0xAD, 0x30, 0x69, 0x35, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0x32, 0x2E, 0x00, 0x2F, 0x44, 0x8C, 0xF0, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0x58, 0x07, 0xD7, 0xCD, 0x60, 0xA1, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0xFB, 0x7B, 0x03, 0x05, 0x5E, 0x79, 0x73), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_3_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0x17, 0xCE, 0x38, 0x4B, 0x5E, 0x5B, 0xC8), + MBEDTLS_BYTES_TO_T_UINT_8(0x60, 0x0E, 0x0A, 0x61, 0x9D, 0x7C, 0x62, 0x08), + MBEDTLS_BYTES_TO_T_UINT_8(0x25, 0xF0, 0x98, 0x71, 0x7F, 0x17, 0x26, 0xD7), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0xD3, 0xFA, 0x3C, 0xF0, 0x70, 0x07, 0x82), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0x47, 0x5C, 0x09, 0x43, 0xB7, 0x65, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0xA9, 0xA7, 0x3E, 0xFA, 0xF3, 0xEC, 0x22), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_3_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x78, 0x22, 0x2B, 0x58, 0x71, 0xFA, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x30, 0xCE, 0x6A, 0xB3, 0xB0, 0x4F, 0x83), + MBEDTLS_BYTES_TO_T_UINT_8(0xCF, 0x95, 0x20, 0xA9, 0x23, 0xC2, 0x65, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0xCF, 0x03, 0x5B, 0x8A, 0x80, 0x44, 0xBB), + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0xF8, 0x91, 0xF7, 0xD5, 0xED, 0xEA, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0x5B, 0x16, 0x10, 0x25, 0xAC, 0x2A, 0x17), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_4_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0xEC, 0xDC, 0xC4, 0x7B, 0x8C, 0x6B, 0xE9), + MBEDTLS_BYTES_TO_T_UINT_8(0x2B, 0xBB, 0x1C, 0xD3, 0x5A, 0xEE, 0xD9, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x5D, 0x30, 0x5E, 0xF7, 0xB2, 0x41, 0x9D), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0xCE, 0x0F, 0x1A, 0xC6, 0x41, 0x64, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0x18, 0xE1, 0xE3, 0x82, 0x15, 0x66, 0x4B), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0xE2, 0x24, 0x04, 0x72, 0x39, 0xA0, 0x7C), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_4_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2B, 0x51, 0xA2, 0x58, 0x88, 0x62, 0xE1, 0x02), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0xD2, 0x65, 0x14, 0xE9, 0x4C, 0x82, 0x30), + MBEDTLS_BYTES_TO_T_UINT_8(0xDC, 0xE1, 0xAC, 0x87, 0xAE, 0x31, 0x1A, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0x85, 0x4F, 0x96, 0x1E, 0x85, 0x7A, 0xC3, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0x86, 0xBB, 0xF0, 0xC0, 0x9D, 0x08, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0xBD, 0x53, 0x03, 0x09, 0x80, 0x91, 0xEF, 0x68), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_5_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0xD7, 0xAF, 0x6F, 0x69, 0x7B, 0x88, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0x13, 0xE4, 0x30, 0xA2, 0x47, 0xB5, 0xC1), + MBEDTLS_BYTES_TO_T_UINT_8(0x0F, 0xD2, 0xC0, 0xDD, 0x8A, 0x1C, 0x3C, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0xF9, 0x8C, 0xB3, 0x4C, 0xBA, 0x8B, 0x6D, 0xCF), + MBEDTLS_BYTES_TO_T_UINT_8(0x6B, 0xC7, 0xA1, 0xA8, 0x6E, 0x3C, 0x4F, 0xF1), + MBEDTLS_BYTES_TO_T_UINT_8(0x94, 0x4A, 0x97, 0xC8, 0x03, 0x6F, 0x01, 0x82), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_5_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0x18, 0x12, 0xA9, 0x39, 0xD5, 0x22, 0x26), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0xA7, 0xC0, 0xBD, 0x9D, 0x8D, 0x78, 0x38), + MBEDTLS_BYTES_TO_T_UINT_8(0xA9, 0xB3, 0xD0, 0x7F, 0xDF, 0xD0, 0x30, 0xDE), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x25, 0x73, 0x96, 0xEC, 0xA8, 0x1D, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0xD1, 0x65, 0x66, 0xDC, 0xD9, 0xCF, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0xED, 0x7B, 0x37, 0xAD, 0xE2, 0xBE, 0x2D), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_6_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x79, 0x42, 0x6A, 0x07, 0x66, 0xB1, 0xBD), + MBEDTLS_BYTES_TO_T_UINT_8(0x45, 0x53, 0x62, 0x65, 0x92, 0x09, 0x4C, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0x06, 0xAF, 0xC3, 0x03, 0xF6, 0xF4, 0x2D, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0xCA, 0x41, 0xD9, 0xA2, 0x69, 0x9B, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0x4B, 0xB2, 0xA6, 0x8D, 0xE1, 0xAA, 0x61, 0x76), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0xBA, 0x4D, 0x12, 0xB6, 0xBE, 0xF3, 0x7E), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_6_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0xD9, 0x92, 0x22, 0x07, 0xCE, 0xC9, 0x26), + MBEDTLS_BYTES_TO_T_UINT_8(0x62, 0xA1, 0x7C, 0x91, 0xDB, 0x32, 0xF7, 0xE5), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x49, 0x4B, 0x6D, 0xFB, 0xD9, 0x70, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0xFB, 0x4E, 0x4C, 0x5E, 0x66, 0x81, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0xA5, 0xB3, 0xE1, 0x00, 0xB7, 0xD9, 0xCC, 0x58), + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0x36, 0x8B, 0xC4, 0x39, 0x20, 0xFD, 0x30), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_7_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x94, 0x1F, 0x60, 0x03, 0xBB, 0xD7, 0x60, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0x3C, 0x62, 0xDD, 0x71, 0x95, 0xE9, 0x61), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x5B, 0x7A, 0x5F, 0x68, 0x81, 0xC5, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xAF, 0xB5, 0xB9, 0x98, 0x42, 0x28, 0xA5), + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0x29, 0x8E, 0x11, 0x49, 0xB4, 0xD7, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x3E, 0xD2, 0x30, 0xA1, 0xBA, 0xCA, 0x03), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_7_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0x37, 0x64, 0x44, 0x2F, 0x03, 0xE5, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0x4A, 0x42, 0xBC, 0xFF, 0xA2, 0x1A, 0x5F, 0x06), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0x04, 0xAB, 0x04, 0xE0, 0x24, 0xAD, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0x45, 0x17, 0x67, 0x1F, 0x3E, 0x53, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0x0F, 0xB3, 0x1B, 0x57, 0x54, 0xC2, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0xD3, 0xF8, 0xC4, 0x1B, 0x9B, 0xFA, 0x30), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_8_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x90, 0xFD, 0xFB, 0xCA, 0x49, 0x38, 0x4E), + MBEDTLS_BYTES_TO_T_UINT_8(0xC3, 0xCF, 0xC6, 0xDD, 0xF0, 0xFF, 0x8C, 0x11), + MBEDTLS_BYTES_TO_T_UINT_8(0xD7, 0x69, 0x9D, 0xBD, 0x5F, 0x33, 0xE9, 0xB4), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0x19, 0x82, 0x3D, 0xAC, 0x1C, 0x40, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0xC7, 0x02, 0x46, 0x14, 0x77, 0x00, 0xBE), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x05, 0xF2, 0x77, 0x3A, 0x66, 0x5C, 0x39), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_8_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xE6, 0x17, 0xDE, 0xB2, 0xA1, 0xE5, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0x71, 0xEC, 0x9D, 0xD8, 0xF5, 0xD4, 0x66), + MBEDTLS_BYTES_TO_T_UINT_8(0xAA, 0xC6, 0x42, 0x5E, 0xE7, 0x18, 0xBA, 0xD0), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0x21, 0x68, 0x5A, 0x26, 0xFB, 0xD7, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x00, 0x5C, 0xBA, 0x8A, 0x34, 0xEC, 0x75), + MBEDTLS_BYTES_TO_T_UINT_8(0xC3, 0x9C, 0x3C, 0xAF, 0x53, 0xE8, 0x65, 0x35), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_9_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0xEF, 0x28, 0xDC, 0x67, 0x05, 0xC8, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0x78, 0xC3, 0x85, 0x49, 0xA0, 0xBC, 0x0F), + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0x3E, 0x2D, 0xA0, 0xCF, 0xD4, 0x7A, 0xF5), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0x93, 0xFE, 0x60, 0xB3, 0x6E, 0x99, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0x62, 0xAD, 0x04, 0xE7, 0x49, 0xAF, 0x5E, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0x54, 0x7A, 0xED, 0xA6, 0x9E, 0x18, 0x09, 0x31), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_9_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x05, 0x94, 0x44, 0xDC, 0xB8, 0x85, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0x14, 0xB7, 0x37, 0xC2, 0x50, 0x75, 0x15, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0xC6, 0x0F, 0xB2, 0xA9, 0x91, 0x3E, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0x81, 0xAD, 0x25, 0xA1, 0x26, 0x73, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0xF1, 0xD1, 0x61, 0x7C, 0x76, 0x8F, 0x13), + MBEDTLS_BYTES_TO_T_UINT_8(0x06, 0xDB, 0x4A, 0xFF, 0x14, 0xA7, 0x48, 0x0B), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_10_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0x73, 0xC6, 0xC2, 0xCC, 0xF1, 0x57, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0xED, 0x73, 0x27, 0x70, 0x82, 0xB6, 0x5E), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0xBA, 0xAC, 0x3A, 0xCF, 0xF4, 0xEA, 0xA6), + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0xD6, 0xB1, 0x8F, 0x0E, 0x08, 0x2C, 0x5E), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0xE3, 0x8F, 0x2F, 0x0E, 0xA1, 0xF3, 0x07), + MBEDTLS_BYTES_TO_T_UINT_8(0x1A, 0xF5, 0x7C, 0x9B, 0x29, 0x0A, 0xF6, 0x28), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_10_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xBD, 0xEE, 0x17, 0x47, 0x34, 0x15, 0xA3, 0xAF), + MBEDTLS_BYTES_TO_T_UINT_8(0xFB, 0xBE, 0x88, 0x48, 0xE7, 0xA2, 0xBB, 0xDE), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0xAD, 0xDC, 0x65, 0x61, 0x37, 0x0F, 0xC1), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x67, 0xAD, 0xA2, 0x3A, 0x1C, 0x91, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0x07, 0x0C, 0x3A, 0x41, 0x6E, 0x13, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x73, 0xBD, 0x7E, 0xED, 0xAA, 0x14, 0xDD, 0x61), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_11_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC3, 0xDC, 0x20, 0x01, 0x72, 0x11, 0x48, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xC4, 0x7B, 0xF8, 0x62, 0x3D, 0xF0, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0xC2, 0x3D, 0x2E, 0x52, 0xA3, 0x4A, 0x89), + MBEDTLS_BYTES_TO_T_UINT_8(0xCE, 0xE2, 0x53, 0x46, 0x5E, 0x21, 0xF8, 0xCE), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0xC7, 0x8F, 0xA9, 0x26, 0x42, 0x32, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0xFB, 0xA6, 0xA0, 0x8D, 0x4B, 0x9A, 0x19, 0x03), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_11_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0xAB, 0x6D, 0x1E, 0xFB, 0xEE, 0x60, 0x0C), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x56, 0x3C, 0xC5, 0x5D, 0x10, 0x79, 0x1C), + MBEDTLS_BYTES_TO_T_UINT_8(0x25, 0xBC, 0x41, 0x9F, 0x71, 0xEF, 0x02, 0xF9), + MBEDTLS_BYTES_TO_T_UINT_8(0xA2, 0x36, 0xC4, 0xD0, 0x88, 0x9B, 0x32, 0xFC), + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0xD4, 0x5D, 0x17, 0x39, 0xE6, 0x22, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x7B, 0x26, 0x01, 0xCE, 0xBE, 0x4A, 0x9C, 0x27), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_12_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0x6D, 0x11, 0xCA, 0x6C, 0x5A, 0x93, 0x0C), + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0x96, 0x26, 0xAF, 0x2F, 0xE4, 0x30, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0x35, 0xC1, 0x4C, 0xC6, 0x30, 0x1F, 0x5C, 0x04), + MBEDTLS_BYTES_TO_T_UINT_8(0x59, 0xB3, 0xE8, 0xFC, 0x35, 0xEB, 0x63, 0x6C), + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0x1D, 0xCA, 0xFC, 0x50, 0x36, 0x4B, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0x0E, 0x23, 0x5B, 0xAF, 0xEB, 0x2D, 0x31), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_12_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0x88, 0xB6, 0xD7, 0x74, 0x4A, 0x23, 0xB6), + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0x66, 0xE2, 0xBB, 0x29, 0xA6, 0x4F, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0x6F, 0x7E, 0x68, 0x6E, 0xA0, 0x14, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0x3B, 0x73, 0xD4, 0xE8, 0xAB, 0x5B, 0xF6, 0x0D), + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0xE0, 0x3C, 0x24, 0x00, 0x95, 0xE9, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x0D, 0x4F, 0x81, 0xD0, 0xF2, 0x3F, 0x00), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_13_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0x1D, 0xCD, 0x78, 0x39, 0xC4, 0x6B, 0xD9), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0x45, 0xC7, 0xB8, 0x2F, 0xAA, 0x5D, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0x33, 0x8C, 0x6E, 0xA3, 0x24, 0xB2, 0xDB, 0x4B), + MBEDTLS_BYTES_TO_T_UINT_8(0x69, 0x2D, 0xD9, 0xF1, 0xC7, 0x9B, 0x8A, 0xAF), + MBEDTLS_BYTES_TO_T_UINT_8(0x67, 0xE1, 0x2C, 0xB9, 0x40, 0x37, 0x91, 0x75), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0x2C, 0xB5, 0x23, 0x03, 0x2B, 0xAF, 0x2F), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_13_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0x9D, 0x5A, 0x20, 0x10, 0xA9, 0x84, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0x30, 0x89, 0x20, 0x13, 0xE9, 0xB2, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x6E, 0x52, 0xEB, 0x03, 0x18, 0x1F, 0xA6), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x9E, 0x1C, 0x35, 0x87, 0x92, 0x69, 0xC7), + MBEDTLS_BYTES_TO_T_UINT_8(0xA1, 0xC9, 0x88, 0xAF, 0xC6, 0x6C, 0x83, 0x72), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0xD5, 0x7A, 0x54, 0x34, 0x99, 0xB6, 0x6F), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_14_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xDF, 0xAD, 0x45, 0x9B, 0x4B, 0x41, 0x4D, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x1B, 0x5D, 0xAB, 0x7F, 0x35, 0x34, 0xE9, 0x29), + MBEDTLS_BYTES_TO_T_UINT_8(0x73, 0xBE, 0x78, 0x34, 0x44, 0xF3, 0x4A, 0x87), + MBEDTLS_BYTES_TO_T_UINT_8(0xFB, 0xDE, 0xE3, 0xC4, 0xEE, 0x0B, 0xF9, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0x86, 0x16, 0x48, 0x32, 0xB8, 0x74, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0xEE, 0x7C, 0xBA, 0xBD, 0x81, 0xE3, 0x55), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_14_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0x6A, 0xFA, 0x84, 0xDA, 0xB8, 0xD5, 0x14), + MBEDTLS_BYTES_TO_T_UINT_8(0xB2, 0x9F, 0x8A, 0xD5, 0x1B, 0x2E, 0x1A, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x0C, 0x61, 0xE2, 0xFF, 0x5B, 0xE6, 0xD5), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0x62, 0xC1, 0x87, 0x53, 0x1B, 0x92, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0x54, 0x90, 0x00, 0xD1, 0x6A, 0x0C, 0x0E, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x8B, 0x2E, 0xB5, 0x3B, 0x44, 0xB5, 0xA0, 0x78), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_15_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0x5D, 0x02, 0x58, 0xB5, 0xBE, 0x45, 0x14), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0xEF, 0x8E, 0x90, 0x4D, 0x2A, 0x32, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0x48, 0x99, 0x75, 0x5C, 0x0A, 0x33, 0x8F, 0x36), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0x6C, 0x95, 0xD4, 0x1F, 0xF3, 0xEB, 0xDA), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0xE4, 0x4C, 0x91, 0x20, 0xF3, 0x25, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x95, 0xEB, 0x29, 0x6F, 0x20, 0x34, 0x81), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_15_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0x15, 0xE5, 0x13, 0x7E, 0x64, 0x8B, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0xBC, 0x0D, 0x18, 0x7E, 0x37, 0x9E, 0xFA), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x82, 0x20, 0xF7, 0x2D, 0x7A, 0x77, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x29, 0xA2, 0xDB, 0x7A, 0xE6, 0x6F, 0xA5), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0xC6, 0x50, 0x5C, 0xBC, 0xE6, 0x4F, 0xBD), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0x9F, 0xD5, 0xE8, 0xC5, 0x3D, 0xB7, 0x30), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_16_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x45, 0x03, 0x55, 0x10, 0xDB, 0xA6, 0x8B, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0x4E, 0x17, 0xAE, 0x78, 0xC9, 0x1D, 0x43, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0x4E, 0x35, 0x49, 0xD4, 0x47, 0x84, 0x8D, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0x95, 0x2F, 0xEA, 0xBC, 0xB4, 0x18, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0x48, 0xAE, 0x89, 0xF5, 0x65, 0x3D, 0x89), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0xF2, 0x2B, 0x20, 0xD1, 0x75, 0x50, 0x63), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_16_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0xE6, 0x5C, 0x2C, 0xE0, 0x7D, 0xDF, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0x07, 0x3E, 0xCE, 0x9F, 0x18, 0xB6, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0x9A, 0xF8, 0xF0, 0xD5, 0xFA, 0x42, 0x1D, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0x6C, 0x1D, 0x03, 0xC9, 0x0E, 0x2B, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x43, 0x18, 0x52, 0xA5, 0xB4, 0x63, 0xE1, 0x06), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0x0A, 0xD9, 0xC4, 0xFD, 0x16, 0x60, 0x54), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_17_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x43, 0x7D, 0xDE, 0xDF, 0x4B, 0x4A, 0xB0, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x4E, 0x8C, 0x94, 0xC1, 0xE2, 0x85, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x4F, 0xF0, 0xEA, 0xB5, 0x9B, 0x70, 0xEF, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0x56, 0xC2, 0x39, 0x5D, 0xF3, 0x2C, 0xD9, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x0D, 0x1C, 0x2E, 0xCC, 0x2F, 0x54, 0x87, 0x80), + MBEDTLS_BYTES_TO_T_UINT_8(0xB0, 0x72, 0xC7, 0xB5, 0x50, 0xA3, 0x84, 0x77), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_17_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0xD1, 0xAF, 0xA9, 0xB4, 0x8B, 0x5D, 0xFA), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0xF6, 0x52, 0x8A, 0xC3, 0x56, 0xA5, 0x5E), + MBEDTLS_BYTES_TO_T_UINT_8(0x3B, 0x52, 0xFF, 0xEA, 0x05, 0x42, 0x77, 0x83), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0x08, 0x90, 0x72, 0x86, 0xC4, 0xC3, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0x4D, 0x15, 0xF8, 0xF1, 0x16, 0x67, 0xC6, 0xD5), + MBEDTLS_BYTES_TO_T_UINT_8(0x75, 0x87, 0xAC, 0x8F, 0x71, 0xEC, 0x83, 0x81), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_18_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0xE1, 0xE6, 0x2D, 0x0E, 0x11, 0xA1, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0xE2, 0xA8, 0x32, 0xE6, 0xE3, 0x83, 0xD1), + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x56, 0xE5, 0xCD, 0xB7, 0x2B, 0x67, 0x6F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE5, 0xED, 0xC9, 0x65, 0x6D, 0x87, 0xE1, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x8E, 0xFD, 0x9A, 0x53, 0x0E, 0xFA, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0x49, 0x4C, 0x4A, 0xE2, 0x23, 0x84, 0xFA, 0x01), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_18_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0xFE, 0x49, 0x81, 0xD1, 0x3E, 0xF4, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0x45, 0x72, 0xE0, 0xEF, 0x0D, 0xB8, 0x3E, 0x6F), + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0x00, 0x0F, 0x5F, 0xCE, 0x60, 0x72, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0xCC, 0xD8, 0x03, 0x07, 0x6E, 0x5A, 0xCD), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0x3A, 0x35, 0x50, 0x4E, 0x1F, 0xCA, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0xEA, 0x88, 0x55, 0xBD, 0x6E, 0x05, 0x7F), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_19_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB1, 0x6D, 0xF1, 0x97, 0xA6, 0x69, 0x39, 0x24), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0x41, 0x99, 0xFF, 0x3B, 0xA1, 0x26, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0x2F, 0x95, 0x80, 0x12, 0x4A, 0x1B, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0xBF, 0x51, 0xAA, 0xAE, 0x2D, 0xDA, 0xCF), + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0x1C, 0xB3, 0x52, 0x36, 0x49, 0xD4, 0x86), + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0xC1, 0x1F, 0x3A, 0xD3, 0x3E, 0x5C, 0x1A), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_19_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x73, 0x51, 0xF7, 0x2B, 0xC8, 0xA9, 0xA7, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0x12, 0x4E, 0x7F, 0x98, 0x41, 0x66, 0xB0, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0x1D, 0xC0, 0x42, 0xCD, 0xF8, 0xC3, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0xCC, 0x41, 0x91, 0x7D, 0xCC, 0x8B, 0xCC, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0xAE, 0x76, 0xED, 0x56, 0x18, 0xC5, 0xAB), + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0x6A, 0x06, 0xA3, 0x7F, 0x65, 0x10, 0x1F), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_20_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0xEC, 0x3C, 0x05, 0x05, 0xCA, 0xF6, 0xED), + MBEDTLS_BYTES_TO_T_UINT_8(0x48, 0xCD, 0x02, 0x51, 0x12, 0x16, 0x3C, 0x63), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0xEB, 0xB3, 0x43, 0x7B, 0xDD, 0xB2, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x59, 0x90, 0x41, 0xDB, 0xE4, 0xF5, 0x91), + MBEDTLS_BYTES_TO_T_UINT_8(0xD0, 0x0E, 0x18, 0x2A, 0x5A, 0x83, 0x7C, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE1, 0x37, 0xA1, 0x0D, 0xF1, 0x2F, 0x63, 0x79), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_20_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0xC0, 0xFA, 0x6F, 0x1F, 0x67, 0xCF, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x34, 0x45, 0xBB, 0xF4, 0xF9, 0x9B, 0x89), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0x69, 0xFE, 0x67, 0x1D, 0x64, 0x8F, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x39, 0xBF, 0xD8, 0xB3, 0xC7, 0xAD, 0x8A), + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0x93, 0xFF, 0xF3, 0x28, 0xFA, 0x39, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0xF9, 0xC3, 0x85, 0x26, 0x7A, 0x88, 0x89), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_21_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x4D, 0xD5, 0x79, 0xD8, 0x11, 0xDE, 0xEB, 0x4E), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x46, 0xA4, 0x6A, 0xDA, 0x74, 0x34, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0xBD, 0xD3, 0xF5, 0x14, 0xEE, 0xFE, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x4C, 0xA3, 0x71, 0x43, 0x65, 0xF8, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0x6C, 0x35, 0xFA, 0x90, 0x25, 0xD8, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0x34, 0x84, 0x96, 0xA1, 0x43, 0x03, 0x4D), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_21_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x3B, 0x3B, 0x2F, 0xCA, 0x59, 0xF2, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xCD, 0x48, 0x24, 0x74, 0xD8, 0x72, 0x90, 0xA3), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x42, 0x74, 0x8C, 0x6F, 0x52, 0x19, 0x3D), + MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0x9E, 0x41, 0x63, 0x68, 0x78, 0x4C, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x53, 0x94, 0xB6, 0x6B, 0x38, 0x52, 0xA8, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0x30, 0x25, 0x93, 0xA1, 0x6F, 0x6E, 0x68), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_22_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x2F, 0x4B, 0x64, 0x79, 0x50, 0xFF, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0x36, 0xED, 0x57, 0x39, 0x3B, 0xE7, 0xF3), + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x85, 0xEA, 0x35, 0xD6, 0xC0, 0xA0, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x89, 0x3A, 0xCC, 0x22, 0x1C, 0x46, 0x02), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x7A, 0xB0, 0xA1, 0x1B, 0x69, 0x62, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0xB8, 0x8A, 0x6C, 0x18, 0x85, 0x0D, 0x88), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_22_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0xB6, 0x50, 0xE9, 0x4E, 0x7F, 0xE8, 0x07), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x5B, 0x5C, 0xD1, 0x4B, 0x11, 0x9A, 0xD8), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0x25, 0x56, 0x74, 0x51, 0x9C, 0xEC, 0x9C), + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0x7F, 0xB6, 0x8A, 0xCB, 0x3A, 0x10, 0x6A), + MBEDTLS_BYTES_TO_T_UINT_8(0x60, 0x33, 0x07, 0x01, 0xE9, 0x49, 0x59, 0xE6), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0xA5, 0x2E, 0xF2, 0xBA, 0x32, 0x63, 0x44), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_23_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0x06, 0x0B, 0xA5, 0x44, 0x27, 0x7F, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0x74, 0xAC, 0x0F, 0xCC, 0x4F, 0x13, 0x61), + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0xB1, 0xBF, 0x97, 0x49, 0xA5, 0x1C, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0x64, 0x68, 0x7B, 0x0F, 0xCC, 0x77, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0x39, 0xF9, 0x4E, 0x84, 0x9C, 0xF6, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0xCF, 0x6D, 0xE2, 0xA1, 0x2D, 0xF9, 0x2B), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_23_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0xC4, 0x90, 0x57, 0x31, 0x01, 0x05, 0x5E), + MBEDTLS_BYTES_TO_T_UINT_8(0xCC, 0x1E, 0xBB, 0xBF, 0x98, 0xA4, 0x7C, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0x89, 0xE3, 0xA0, 0xB2, 0xCD, 0x39, 0x9A, 0x3F), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x34, 0x60, 0x7A, 0x89, 0x98, 0xB5, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0x20, 0x3D, 0x3A, 0x04, 0x8F, 0x5A, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0xA3, 0x26, 0xB6, 0x49, 0x09, 0x9C, 0x0F, 0x59), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_24_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0x66, 0xD2, 0x38, 0x2A, 0x62, 0x81, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0xC8, 0x20, 0x5E, 0x28, 0xA3, 0x81, 0xA7), + MBEDTLS_BYTES_TO_T_UINT_8(0x20, 0x31, 0xA4, 0xF1, 0xEA, 0x7D, 0x87, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0x8F, 0x2C, 0x99, 0x09, 0x6F, 0x63, 0xEB, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x73, 0x76, 0xDA, 0x1A, 0x06, 0xBE, 0xDE, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0x09, 0x2E, 0x75, 0x39, 0x30, 0x2D, 0x42), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_24_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0x9B, 0xC1, 0x5A, 0x17, 0xC3, 0x8C, 0x31), + MBEDTLS_BYTES_TO_T_UINT_8(0x58, 0x8D, 0x94, 0x4D, 0x3D, 0xAB, 0x60, 0xD4), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFD, 0x1E, 0x0F, 0x43, 0xAE, 0x9D, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x8E, 0xF2, 0xF3, 0x20, 0x1B, 0xAA, 0xB7, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0x5B, 0xA4, 0xF4, 0x90, 0x3B, 0xE3, 0x71), + MBEDTLS_BYTES_TO_T_UINT_8(0xF7, 0x78, 0x72, 0xBD, 0x65, 0x09, 0x0B, 0x01), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_25_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0x37, 0x2A, 0x6C, 0x16, 0x4F, 0x64, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0xCE, 0xA3, 0x90, 0xB4, 0x9A, 0xBC, 0xF7), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0x38, 0x55, 0x63, 0x1D, 0x3A, 0x6E, 0x18), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0xB4, 0xAA, 0x99, 0x22, 0x45, 0x89, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0x7C, 0x8C, 0xA6, 0x3D, 0xA7, 0x3E, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0x06, 0x42, 0xDC, 0xA6, 0xE3, 0xC6, 0x12), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_25_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0x8C, 0x3D, 0x5D, 0x47, 0x31, 0x7C, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0x85, 0xEE, 0x46, 0x7E, 0x13, 0x04, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0x9E, 0x3C, 0x8B, 0x43, 0x2E, 0x74, 0xF5, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x88, 0x8E, 0x07, 0x29, 0x08, 0x03, 0x26), + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0x9B, 0x89, 0xEB, 0x08, 0xE8, 0x43, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0x07, 0x67, 0xFD, 0xD9, 0x73, 0x6F, 0x18), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_26_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0xEB, 0x21, 0x8D, 0x98, 0x43, 0x74, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0x88, 0xCC, 0x14, 0xD8, 0x08, 0xBB, 0xA6, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0xC4, 0x98, 0xF2, 0x6A, 0x18, 0xC3, 0xDD, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0x38, 0x91, 0xA0, 0x03, 0xF2, 0x04, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x7A, 0xAF, 0xE8, 0xFD, 0xFB, 0x13, 0x70, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0xD0, 0x93, 0x87, 0x98, 0x4A, 0xE0, 0x00, 0x12), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_26_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x97, 0x2E, 0x69, 0x9C, 0xA2, 0x2D, 0x03, 0x3F), + MBEDTLS_BYTES_TO_T_UINT_8(0x79, 0xFE, 0xF3, 0xB9, 0xC1, 0x85, 0x2A, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0xCE, 0xFD, 0x86, 0xB1, 0xCD, 0xBF, 0x41, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0xD8, 0x9A, 0x21, 0xF3, 0xFE, 0xCB, 0xF1), + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0x78, 0x04, 0x60, 0xB7, 0xA9, 0xA2, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x1E, 0x66, 0x2A, 0x54, 0x51, 0xBD, 0x8B), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_27_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8E, 0x16, 0x36, 0xEF, 0x61, 0x2D, 0xEE, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0x45, 0x5F, 0x88, 0xA0, 0x13, 0x12, 0xF7, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0xA9, 0xC6, 0xAD, 0x4A, 0x4A, 0x07, 0x01, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0xB8, 0x74, 0xB1, 0x4F, 0xEB, 0xBD, 0xD5, 0x6B), + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0xF9, 0x71, 0xA2, 0x06, 0x4F, 0xD7, 0xBC), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0x8B, 0x4D, 0x48, 0xE0, 0x98, 0xFB, 0x6A), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_27_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC4, 0xBA, 0x10, 0xA3, 0x0D, 0x52, 0xAC, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0xD0, 0xE0, 0x36, 0xE6, 0x07, 0x3A, 0x30), + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0x80, 0xF0, 0xAA, 0x49, 0x22, 0x4B, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xC7, 0xAB, 0x1C, 0x89, 0xCD, 0x24, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x82, 0x2A, 0xFC, 0xB3, 0x6D, 0x45, 0x96, 0x49), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0xE4, 0xDB, 0x52, 0x3F, 0xC4, 0xB4, 0x19), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_28_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x5B, 0xCC, 0xC8, 0x7F, 0xBB, 0x6B, 0x87, 0x47), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0x21, 0x3C, 0x69, 0x7D, 0x38, 0x57, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0x4C, 0x18, 0x3C, 0x53, 0xA5, 0x48, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0xC3, 0x64, 0x45, 0xDB, 0xC4, 0x6D, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0x49, 0xCC, 0xD1, 0xBB, 0x17, 0xB8, 0x34, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x69, 0x71, 0xFA, 0xA0, 0x28, 0x4A, 0x3D), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_28_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0xE8, 0x9E, 0x39, 0xEA, 0x8D, 0x38, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0xCC, 0x9C, 0xBB, 0xCD, 0x80, 0x1A, 0xEE, 0xB7), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0xA0, 0x45, 0xBF, 0xD9, 0x22, 0x11, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x7C, 0x5C, 0xD9, 0xC0, 0x9F, 0x69, 0xF5), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0x8A, 0xA6, 0x79, 0x4E, 0x35, 0xB9, 0xD5), + MBEDTLS_BYTES_TO_T_UINT_8(0xCC, 0x8B, 0x9A, 0x3E, 0xA1, 0xB8, 0x28, 0x10), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_29_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0x2F, 0xEF, 0xBB, 0xA9, 0x72, 0x7F, 0xEA), + MBEDTLS_BYTES_TO_T_UINT_8(0xB5, 0x34, 0xB7, 0x12, 0xB9, 0xE7, 0xC3, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0x1D, 0xD9, 0x42, 0x77, 0x0C, 0x71, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0xEC, 0x01, 0x59, 0xA7, 0x56, 0x03, 0x91, 0x8D), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x91, 0x99, 0x33, 0x30, 0x3E, 0xEF, 0x13), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0xC9, 0x5A, 0x9A, 0x54, 0x66, 0xF1, 0x70), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_29_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0x2C, 0xB7, 0x6E, 0x71, 0x7D, 0x35, 0x30), + MBEDTLS_BYTES_TO_T_UINT_8(0x1A, 0x0D, 0xEF, 0xD1, 0x2D, 0x99, 0x63, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0x31, 0xAF, 0x2D, 0xC9, 0xC6, 0xC2, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0xC0, 0xDF, 0x80, 0x54, 0xC4, 0xAC, 0xF3), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x6B, 0xA0, 0x84, 0x96, 0xF7, 0x31, 0xC8), + MBEDTLS_BYTES_TO_T_UINT_8(0x93, 0xE2, 0x7C, 0x7A, 0x41, 0x45, 0x75, 0x6A), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_30_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0xEE, 0x58, 0x31, 0xE8, 0x68, 0xD6, 0x76), + MBEDTLS_BYTES_TO_T_UINT_8(0xD2, 0x2E, 0x48, 0xB7, 0x09, 0x9F, 0xD4, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0xA9, 0x5C, 0xE7, 0x64, 0x43, 0x5D, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0x9E, 0x58, 0x9F, 0x50, 0xAB, 0x68, 0xFF, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0x88, 0x2D, 0xBA, 0x12, 0xBF, 0x8D, 0x7D), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0xDF, 0x6F, 0xB3, 0x75, 0xA4, 0x55, 0x73), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_30_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x17, 0x92, 0x39, 0xB7, 0x13, 0x37, 0x6F), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0x43, 0x71, 0xA7, 0xCA, 0x17, 0x1B, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0xE7, 0xB9, 0xB0, 0x78, 0xEF, 0xA0, 0xDA, 0x83), + MBEDTLS_BYTES_TO_T_UINT_8(0x9A, 0x84, 0xF2, 0x0F, 0x85, 0xA2, 0xB6, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0x72, 0x65, 0x2E, 0x6E, 0x45, 0xB9, 0x4C, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0xFE, 0x6A, 0x8C, 0x2B, 0x77, 0x96, 0x36, 0x22), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_31_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x7A, 0x13, 0x4A, 0x97, 0x63, 0x02, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0x1E, 0x06, 0x03, 0x8F, 0xB9, 0xEE, 0x64), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0xEE, 0x8B, 0x89, 0xA9, 0x70, 0xDB, 0xCE), + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x7B, 0x81, 0xC9, 0x70, 0x8D, 0x62, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0x75, 0xDA, 0x46, 0xF8, 0xF9, 0x3A, 0xBE, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x9F, 0x9C, 0x7A, 0x97, 0x62, 0xEB, 0xFA, 0x0F), +}; +static const mbedtls_mpi_uint brainpoolP384r1_T_31_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB2, 0x03, 0x3D, 0x3C, 0x46, 0x27, 0x9E, 0x65), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0x08, 0x1C, 0xD5, 0x25, 0xAF, 0xE9, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0xFE, 0x69, 0xDC, 0x59, 0xF4, 0x8A, 0x7C, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x9A, 0x7A, 0x99, 0x21, 0x0C, 0x4E, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xCE, 0x85, 0x5F, 0xAC, 0xAA, 0x82, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0x83, 0x57, 0x69, 0x90, 0x76, 0xF3, 0x53, 0x3F), +}; +static const mbedtls_ecp_point brainpoolP384r1_T[32] = { + ECP_POINT_INIT_XY_Z1(brainpoolP384r1_T_0_X, brainpoolP384r1_T_0_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_1_X, brainpoolP384r1_T_1_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_2_X, brainpoolP384r1_T_2_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_3_X, brainpoolP384r1_T_3_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_4_X, brainpoolP384r1_T_4_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_5_X, brainpoolP384r1_T_5_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_6_X, brainpoolP384r1_T_6_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_7_X, brainpoolP384r1_T_7_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_8_X, brainpoolP384r1_T_8_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_9_X, brainpoolP384r1_T_9_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_10_X, brainpoolP384r1_T_10_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_11_X, brainpoolP384r1_T_11_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_12_X, brainpoolP384r1_T_12_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_13_X, brainpoolP384r1_T_13_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_14_X, brainpoolP384r1_T_14_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_15_X, brainpoolP384r1_T_15_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_16_X, brainpoolP384r1_T_16_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_17_X, brainpoolP384r1_T_17_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_18_X, brainpoolP384r1_T_18_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_19_X, brainpoolP384r1_T_19_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_20_X, brainpoolP384r1_T_20_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_21_X, brainpoolP384r1_T_21_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_22_X, brainpoolP384r1_T_22_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_23_X, brainpoolP384r1_T_23_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_24_X, brainpoolP384r1_T_24_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_25_X, brainpoolP384r1_T_25_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_26_X, brainpoolP384r1_T_26_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_27_X, brainpoolP384r1_T_27_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_28_X, brainpoolP384r1_T_28_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_29_X, brainpoolP384r1_T_29_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_30_X, brainpoolP384r1_T_30_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP384r1_T_31_X, brainpoolP384r1_T_31_Y), +}; +#else +#define brainpoolP384r1_T NULL +#endif + +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ + +/* + * Domain parameters for brainpoolP512r1 (RFC 5639 3.7) + */ +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP512r1_p[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0x48, 0x3A, 0x58, 0x56, 0x60, 0xAA, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0x85, 0xC6, 0x82, 0x2D, 0x2F, 0xFF, 0x81, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0x80, 0xA3, 0xE6, 0x2A, 0xA1, 0xCD, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0x68, 0xC6, 0x9B, 0x00, 0x9B, 0x4D, 0x7D), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F), + MBEDTLS_BYTES_TO_T_UINT_8(0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA), +}; +static const mbedtls_mpi_uint brainpoolP512r1_a[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0x94, 0xFC, 0x77, 0x4D, 0xAC, 0xC1, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0xC7, 0xF2, 0x2B, 0xA7, 0x17, 0x11, 0x7F), + MBEDTLS_BYTES_TO_T_UINT_8(0xB5, 0xC8, 0x9A, 0x8B, 0xC9, 0xF1, 0x2E, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0xA1, 0x3A, 0x25, 0xA8, 0x5A, 0x5D, 0xED, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0x63, 0x98, 0xEA, 0xCA, 0x41, 0x34, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0x16, 0xF9, 0x3D, 0x8D, 0xDD, 0xCB, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0x4C, 0x23, 0xAC, 0x45, 0x71, 0x32, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0x89, 0x3B, 0x60, 0x8B, 0x31, 0xA3, 0x30, 0x78), +}; +static const mbedtls_mpi_uint brainpoolP512r1_b[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x23, 0xF7, 0x16, 0x80, 0x63, 0xBD, 0x09, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0xE5, 0xBA, 0x5E, 0xB7, 0x50, 0x40, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0x67, 0x3E, 0x08, 0xDC, 0xCA, 0x94, 0xFC, 0x77), + MBEDTLS_BYTES_TO_T_UINT_8(0x4D, 0xAC, 0xC1, 0xE7, 0xB9, 0xC7, 0xF2, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0x17, 0x11, 0x7F, 0xB5, 0xC8, 0x9A, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0xF1, 0x2E, 0x0A, 0xA1, 0x3A, 0x25, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x5D, 0xED, 0x2D, 0xBC, 0x63, 0x98, 0xEA), + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0x41, 0x34, 0xA8, 0x10, 0x16, 0xF9, 0x3D), +}; +static const mbedtls_mpi_uint brainpoolP512r1_gx[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x22, 0xF8, 0xB9, 0xBC, 0x09, 0x22, 0x35, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x5E, 0x6A, 0x40, 0x47, 0x50, 0x6D, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x7D, 0xB9, 0x93, 0x7B, 0x68, 0xD1, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xD4, 0xD0, 0xE2, 0x78, 0x1F, 0x3B, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0x8E, 0x09, 0xD0, 0xF4, 0xEE, 0x62, 0x3B, 0xB4), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0x16, 0xD9, 0xB5, 0x70, 0x9F, 0xED, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0x93, 0x6A, 0x4C, 0x9C, 0x2E, 0x32, 0x21, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0xD9, 0x2E, 0xD8, 0xBD, 0xE4, 0xAE, 0x81), +}; +static const mbedtls_mpi_uint brainpoolP512r1_gy[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x08, 0xD8, 0x3A, 0x0F, 0x1E, 0xCD, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0x06, 0x54, 0xF0, 0xA8, 0x2F, 0x2B, 0xCA, 0xD1), + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0x63, 0x27, 0x8A, 0xD8, 0x4B, 0xCA, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0x48, 0x5F, 0x4A, 0x49, 0xDE, 0xDC, 0xB2), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0x81, 0x1F, 0x88, 0x5B, 0xC5, 0x00, 0xA0), + MBEDTLS_BYTES_TO_T_UINT_8(0x1A, 0x7B, 0xA5, 0x24, 0x00, 0xF7, 0x09, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0x22, 0x78, 0xCF, 0xA9, 0xBF, 0xEA, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0xEC, 0x32, 0x63, 0x56, 0x5D, 0x38, 0xDE, 0x7D), +}; +static const mbedtls_mpi_uint brainpoolP512r1_n[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x69, 0x00, 0xA9, 0x9C, 0x82, 0x96, 0x87, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0xDA, 0x5D, 0x08, 0x81, 0xD3, 0xB1, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0x47, 0x10, 0xAC, 0x7F, 0x19, 0x61, 0x86, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x26, 0xA9, 0x4C, 0x41, 0x5C, 0x3E, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F), + MBEDTLS_BYTES_TO_T_UINT_8(0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA), +}; + +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 +static const mbedtls_mpi_uint brainpoolP512r1_T_0_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x22, 0xF8, 0xB9, 0xBC, 0x09, 0x22, 0x35, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x5E, 0x6A, 0x40, 0x47, 0x50, 0x6D, 0x7C), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0x7D, 0xB9, 0x93, 0x7B, 0x68, 0xD1, 0x50), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xD4, 0xD0, 0xE2, 0x78, 0x1F, 0x3B, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0x8E, 0x09, 0xD0, 0xF4, 0xEE, 0x62, 0x3B, 0xB4), + MBEDTLS_BYTES_TO_T_UINT_8(0xC1, 0x16, 0xD9, 0xB5, 0x70, 0x9F, 0xED, 0x85), + MBEDTLS_BYTES_TO_T_UINT_8(0x93, 0x6A, 0x4C, 0x9C, 0x2E, 0x32, 0x21, 0x5A), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0xD9, 0x2E, 0xD8, 0xBD, 0xE4, 0xAE, 0x81), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_0_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x08, 0xD8, 0x3A, 0x0F, 0x1E, 0xCD, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0x06, 0x54, 0xF0, 0xA8, 0x2F, 0x2B, 0xCA, 0xD1), + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0x63, 0x27, 0x8A, 0xD8, 0x4B, 0xCA, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0x48, 0x5F, 0x4A, 0x49, 0xDE, 0xDC, 0xB2), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0x81, 0x1F, 0x88, 0x5B, 0xC5, 0x00, 0xA0), + MBEDTLS_BYTES_TO_T_UINT_8(0x1A, 0x7B, 0xA5, 0x24, 0x00, 0xF7, 0x09, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0x22, 0x78, 0xCF, 0xA9, 0xBF, 0xEA, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0xEC, 0x32, 0x63, 0x56, 0x5D, 0x38, 0xDE, 0x7D), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_1_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0xE9, 0x6B, 0x8C, 0x6F, 0x9D, 0x88, 0x43), + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0x4F, 0x86, 0x96, 0xA7, 0x56, 0xD1, 0x37), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0xAB, 0xFA, 0xEE, 0xA7, 0xF5, 0x0E, 0xA6), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x40, 0xEF, 0x9E, 0x6D, 0xD6, 0x32, 0x33), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0xED, 0x56, 0x14, 0x57, 0x1A, 0x8D, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0xED, 0x4D, 0x3A, 0xFA, 0x71, 0x75, 0x6B), + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0xC5, 0x76, 0x1C, 0x14, 0xBE, 0xB5, 0xCD), + MBEDTLS_BYTES_TO_T_UINT_8(0xE1, 0x5A, 0xCB, 0xE7, 0x36, 0x1D, 0x52, 0x1C), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_1_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x6B, 0x8D, 0x7A, 0xEB, 0xA3, 0x8B, 0xD5, 0xB0), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0xA3, 0x41, 0xF8, 0xAC, 0x9E, 0xAB, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0x12, 0xE3, 0x65, 0x0D, 0x1C, 0xFE, 0x09, 0x2B), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0xCA, 0x13, 0x3F, 0xC5, 0xF9, 0x7E, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0x2C, 0x5D, 0x63, 0x28, 0xA6, 0x89, 0xD3, 0x91), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x95, 0x3F, 0x7A, 0x82, 0xD4, 0x77, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0xBB, 0x92, 0x32, 0x00, 0xF4, 0x66, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x58, 0x31, 0xD1, 0x17, 0x9F, 0x2A, 0x22), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_2_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0x36, 0xA9, 0xCD, 0x80, 0xA5, 0x2D, 0x78), + MBEDTLS_BYTES_TO_T_UINT_8(0x91, 0x44, 0xAB, 0xCE, 0x71, 0xFF, 0x0C, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0x24, 0x58, 0x35, 0x5A, 0x21, 0x32, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0x1B, 0xA6, 0x28, 0xF8, 0x7A, 0x97, 0xAE, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0x84, 0xE7, 0x08, 0xFA, 0x47, 0xC9, 0x55, 0x09), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xAC, 0x2E, 0x84, 0xA4, 0xF5, 0x52, 0xC4), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x58, 0x05, 0x9D, 0xA7, 0xC8, 0x71, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0xB3, 0x92, 0xB4, 0x92, 0xC1, 0x92, 0xEC, 0x6B), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_2_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x4A, 0x48, 0x2D, 0x79, 0x5E, 0x58, 0xE5, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x85, 0x26, 0xEC, 0xE9, 0x6E, 0xD4, 0x06), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x68, 0x26, 0x87, 0x38, 0xA2, 0xD2, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0xF7, 0x17, 0x60, 0xCE, 0x75, 0xF8, 0xA5, 0x6F), + MBEDTLS_BYTES_TO_T_UINT_8(0x20, 0x51, 0xDB, 0xA9, 0xAE, 0x87, 0xF1, 0x15), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x49, 0x92, 0x3B, 0x19, 0x96, 0xF5, 0xB0), + MBEDTLS_BYTES_TO_T_UINT_8(0xC4, 0xD5, 0x52, 0x52, 0x8C, 0xCE, 0xFD, 0xFA), + MBEDTLS_BYTES_TO_T_UINT_8(0x24, 0x18, 0x0A, 0xE6, 0xF6, 0xAE, 0x08, 0x41), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_3_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0x2B, 0xD8, 0x54, 0xCE, 0xB0, 0x57, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0xB0, 0xF8, 0x9E, 0x03, 0x03, 0x3C, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x93, 0x0E, 0x29, 0x29, 0x00, 0xF3, 0x70, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0x54, 0x33, 0x99, 0x0E, 0x00, 0x5D, 0xFE, 0x4B), + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0x2D, 0xF2, 0x59, 0x32, 0xCF, 0x03, 0xF4), + MBEDTLS_BYTES_TO_T_UINT_8(0x3B, 0xC9, 0x72, 0xAE, 0x0C, 0xEF, 0xD1, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x5A, 0x27, 0xBF, 0x2F, 0x45, 0xF9, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0xD4, 0xBE, 0xE5, 0x2C, 0xFF, 0x5B, 0x1E, 0x88), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_3_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xAA, 0xAC, 0xBB, 0xD8, 0x83, 0xC2, 0x46, 0xF6), + MBEDTLS_BYTES_TO_T_UINT_8(0xCF, 0xDC, 0xCE, 0x15, 0xB4, 0xEF, 0xCF, 0x46), + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0xDB, 0x5E, 0x94, 0x31, 0x0B, 0xB2, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0xB9, 0xE3, 0xE3, 0x11, 0x71, 0x41, 0x1E), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0xE3, 0x01, 0xB7, 0x7D, 0xBC, 0x65, 0xBE), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x07, 0x65, 0x87, 0xA7, 0xE8, 0x48, 0xE3), + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0x48, 0x8F, 0xD4, 0x30, 0x8E, 0xB4, 0x6C), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0xE0, 0x73, 0xBE, 0x1E, 0xBF, 0x56, 0x36), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_4_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xFE, 0x0E, 0x5E, 0x87, 0xC5, 0xAB, 0x0E, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0xF9, 0x5F, 0x80, 0x24, 0x4C, 0x2A, 0xF1), + MBEDTLS_BYTES_TO_T_UINT_8(0xDE, 0x15, 0x21, 0x54, 0x92, 0x84, 0x8D, 0x6A), + MBEDTLS_BYTES_TO_T_UINT_8(0xA8, 0x8A, 0x47, 0x74, 0xDC, 0x42, 0xB1, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0xF7, 0x30, 0xFD, 0xC1, 0x9B, 0x0C, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x4E, 0x6C, 0xCC, 0xDF, 0xC5, 0xE3, 0xA9, 0xD5), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0x67, 0x59, 0x10, 0x5C, 0x51, 0x54, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x37, 0xFB, 0x6E, 0xB0, 0x78, 0x63, 0x8E), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_4_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA5, 0xEF, 0xC4, 0x39, 0x20, 0xF1, 0x46, 0x66), + MBEDTLS_BYTES_TO_T_UINT_8(0xE2, 0x62, 0xAE, 0xFF, 0x10, 0xE4, 0xE2, 0xE9), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0x5C, 0xF5, 0x2E, 0x22, 0x89, 0xE5, 0x82), + MBEDTLS_BYTES_TO_T_UINT_8(0x89, 0x0C, 0x29, 0xA8, 0x62, 0xAE, 0xDB, 0x65), + MBEDTLS_BYTES_TO_T_UINT_8(0xD7, 0x9E, 0x0F, 0xCA, 0x87, 0x2A, 0x6F, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0xCE, 0xDC, 0x9B, 0x9F, 0x65, 0xD4, 0xAD, 0x27), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0xC3, 0x08, 0x0F, 0xCF, 0x67, 0xE9, 0xF4), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x5C, 0xD7, 0xFF, 0x41, 0x9C, 0xCB, 0x26), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_5_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x25, 0x05, 0x12, 0xAD, 0x73, 0x63, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0x99, 0x07, 0x86, 0x57, 0xE7, 0x94, 0xB1), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x4B, 0xA5, 0xBF, 0x18, 0xA9, 0xEF, 0x6A), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0x4C, 0xC4, 0x09, 0xF2, 0x2F, 0x0C, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0x3A, 0x04, 0xEA, 0x89, 0x6C, 0x91, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0x7D, 0x6C, 0x3A, 0xE7, 0xA3, 0xEC, 0x24, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0xA1, 0x26, 0x21, 0x04, 0xE3, 0xB9, 0x40), + MBEDTLS_BYTES_TO_T_UINT_8(0x53, 0x71, 0x4B, 0x7B, 0xC2, 0x89, 0xCD, 0xA2), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_5_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB7, 0xB9, 0xA8, 0x9D, 0xFD, 0x00, 0x3A, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0x41, 0x6C, 0xBB, 0x5A, 0xCA, 0x1F, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0xD7, 0xE2, 0x6C, 0x6B, 0xA7, 0x48, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0x19, 0xAD, 0xA7, 0xC1, 0x7E, 0x4F, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0xD1, 0xF7, 0x19, 0x3C, 0x06, 0x74, 0x2C, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0x23, 0x4F, 0x0C, 0x09, 0xB0, 0x80, 0x4A), + MBEDTLS_BYTES_TO_T_UINT_8(0x4E, 0x74, 0x34, 0x08, 0x44, 0x7E, 0xA3, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0xFB, 0xCC, 0x8D, 0x12, 0x6E, 0xE1, 0x3D, 0x0B), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_6_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0x18, 0xB1, 0x71, 0x02, 0x93, 0xC2, 0xA4), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x89, 0x40, 0xE2, 0x1F, 0xE7, 0x5E, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x8E, 0xAE, 0x89, 0x01, 0xD4, 0x0C, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0xAE, 0xDA, 0x58, 0x70, 0x24, 0xF2, 0xE4, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0x6F, 0xC7, 0x1D, 0xD6, 0x4A, 0x6F, 0x66, 0x4F), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x1D, 0x7E, 0x4A, 0x2C, 0xCA, 0xEC, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0xA1, 0x06, 0x7F, 0xA8, 0x99, 0xE4, 0xD3, 0x4E), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0x1D, 0x5A, 0xDF, 0x5E, 0x58, 0x36, 0x49), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_6_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0xB9, 0x32, 0x69, 0x1F, 0x72, 0x2A, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0x73, 0xE2, 0x03, 0x39, 0x35, 0xAA, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0x5E, 0x5D, 0x48, 0xEF, 0xAE, 0x30, 0xF5), + MBEDTLS_BYTES_TO_T_UINT_8(0x77, 0x7F, 0x60, 0x19, 0xAF, 0xEC, 0x9D, 0xFC), + MBEDTLS_BYTES_TO_T_UINT_8(0xCA, 0xD9, 0x19, 0xE4, 0x1B, 0x56, 0x15, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0xD7, 0x33, 0x59, 0x1F, 0x43, 0x59, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0xCE, 0xEE, 0xCA, 0xA4, 0x7F, 0x63, 0xD4), + MBEDTLS_BYTES_TO_T_UINT_8(0xBD, 0x40, 0xC0, 0xF6, 0x19, 0x89, 0x43, 0x20), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_7_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0x92, 0xEA, 0x07, 0x65, 0x79, 0x86, 0xD3), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xB7, 0x13, 0x75, 0xD3, 0xC5, 0x0A, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x9E, 0xFA, 0xE1, 0x1F, 0x0C, 0xF9, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x8C, 0xED, 0x5C, 0x21, 0xE9, 0x09, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0xF4, 0x4D, 0xD8, 0x18, 0xC4, 0xF6, 0x36, 0x39), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0xC9, 0xAC, 0x5C, 0xFA, 0x69, 0xA4, 0xA0), + MBEDTLS_BYTES_TO_T_UINT_8(0x6B, 0x8C, 0x94, 0x1C, 0x7B, 0x71, 0x36, 0x58), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0xBD, 0x46, 0xCE, 0xB7, 0x1D, 0x9C, 0x5E), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_7_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0xD6, 0x96, 0x4B, 0xA6, 0x47, 0xEB, 0xE5), + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0xF1, 0x5F, 0x15, 0xDE, 0x99, 0x6F, 0x66), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0xBD, 0xE5, 0x04, 0xB8, 0xE6, 0xC0, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0x49, 0xD3, 0xF0, 0x04, 0x00, 0xE4, 0x05, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0xF3, 0x06, 0xA3, 0x1A, 0xFF, 0xEA, 0x73), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0x32, 0xAA, 0x99, 0x33, 0x09, 0xB6, 0x34), + MBEDTLS_BYTES_TO_T_UINT_8(0x6E, 0xEF, 0xFC, 0x61, 0x10, 0x42, 0x31, 0x94), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0xF1, 0xF4, 0x33, 0xCF, 0x28, 0x90, 0x9C), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_8_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0xDE, 0xF9, 0x88, 0x87, 0x7B, 0xEB, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0xB8, 0xDA, 0xFA, 0xDA, 0x3D, 0xA6, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0xF0, 0x62, 0x82, 0x53, 0x32, 0x55, 0x03), + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0xA5, 0x32, 0x4A, 0x19, 0x11, 0x9C, 0x10), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0xB3, 0x27, 0xE9, 0x75, 0x90, 0x05, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0x1C, 0x90, 0x48, 0x77, 0x01, 0x85, 0x1B), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0xD6, 0x9B, 0x84, 0xA8, 0xD7, 0xC5, 0x28), + MBEDTLS_BYTES_TO_T_UINT_8(0xE1, 0x7A, 0xCB, 0xB3, 0x11, 0x46, 0xD7, 0x99), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_8_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8B, 0x23, 0xBF, 0x75, 0x75, 0xA1, 0x95, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0x4B, 0x66, 0x5D, 0x34, 0x13, 0xA9, 0x03, 0xBE), + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0x80, 0x9D, 0x5F, 0xD2, 0x44, 0xE1, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0x5D, 0xBD, 0xA8, 0xBF, 0xB4, 0x25, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0x99, 0x1F, 0x53, 0xF1, 0x57, 0xDB, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0x7C, 0xE5, 0xC5, 0x51, 0x0B, 0x4C, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0x6B, 0xB0, 0x1A, 0x9C, 0x16, 0xB0, 0x32, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0xF4, 0xE3, 0xCF, 0xDD, 0x48, 0xB4, 0x7B, 0x33), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_9_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0xDD, 0x9E, 0x3C, 0x98, 0x0E, 0x77, 0x65), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0xAB, 0x01, 0xD3, 0x87, 0x74, 0x25, 0x4A), + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0xA3, 0xE3, 0x76, 0x43, 0x87, 0x12, 0xBD), + MBEDTLS_BYTES_TO_T_UINT_8(0x54, 0xB1, 0x3B, 0x60, 0x66, 0xEB, 0x98, 0x54), + MBEDTLS_BYTES_TO_T_UINT_8(0xD2, 0x78, 0xC8, 0xD7, 0x4E, 0x75, 0xCA, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0xDF, 0x71, 0x19, 0xE7, 0x07, 0x36, 0xB5), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0xC9, 0xA8, 0x5F, 0x91, 0xBF, 0x47, 0xB2), + MBEDTLS_BYTES_TO_T_UINT_8(0x80, 0x96, 0x58, 0x96, 0x18, 0xB6, 0xFA, 0x01), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_9_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD0, 0x2D, 0xA9, 0x9B, 0x86, 0xDB, 0x0C, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0x0B, 0x2D, 0x56, 0x4A, 0xD3, 0x93, 0x8A), + MBEDTLS_BYTES_TO_T_UINT_8(0xB5, 0x15, 0xE2, 0x65, 0x12, 0x86, 0x0E, 0xB2), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x41, 0x4D, 0xC1, 0xCB, 0xE4, 0xC3, 0xD7), + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0x53, 0x10, 0xCA, 0xA3, 0xAC, 0x83, 0x26), + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0x01, 0x22, 0x96, 0x10, 0xAD, 0x69, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0x42, 0x46, 0x4E, 0xD8, 0xEA, 0xD6, 0x9D, 0xF3), + MBEDTLS_BYTES_TO_T_UINT_8(0x43, 0x2F, 0x7F, 0x62, 0x62, 0x80, 0xD0, 0x14), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_10_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB2, 0xDA, 0x00, 0x63, 0x09, 0xBD, 0x6A, 0x83), + MBEDTLS_BYTES_TO_T_UINT_8(0x0F, 0xD4, 0x6E, 0x48, 0x05, 0xB7, 0xF7, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0x14, 0x4D, 0xD7, 0x00, 0x4A, 0x15, 0x27, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0x15, 0xAA, 0x37, 0x27, 0x34, 0x18, 0x24), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0x20, 0x2C, 0x84, 0x1B, 0x88, 0xBA, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x09, 0xD6, 0x04, 0xA2, 0x60, 0x84, 0x72), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0x04, 0x94, 0x08, 0xD4, 0xED, 0x47, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0x8B, 0xF3, 0xE4, 0x3E, 0xB9, 0x5B, 0x35, 0x42), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_10_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x5F, 0xD8, 0xB6, 0x80, 0xD6, 0xF1, 0x30, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0x14, 0xA6, 0x85, 0xEE, 0xA7, 0xD8, 0x61), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0x49, 0x2A, 0x1E, 0x7C, 0xE9, 0x2D, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0x3A, 0x87, 0x56, 0x91, 0x03, 0x77, 0x4D, 0x55), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0x52, 0xD4, 0xAA, 0xF7, 0xFA, 0xB0, 0xC5), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x5D, 0x11, 0x39, 0xB1, 0xE7, 0x76, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0x13, 0xBC, 0x37, 0x5D, 0x74, 0xCD, 0xC2), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x48, 0x14, 0x23, 0x30, 0xF8, 0x46, 0x37), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_11_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x27, 0xB0, 0xD9, 0xB2, 0x74, 0xB4, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0xEA, 0xA6, 0xB9, 0x6F, 0x9F, 0x64, 0x36, 0x92), + MBEDTLS_BYTES_TO_T_UINT_8(0x2E, 0x2B, 0x78, 0x40, 0x05, 0x2B, 0x7B, 0xA9), + MBEDTLS_BYTES_TO_T_UINT_8(0xB3, 0x68, 0x3A, 0xB6, 0x4A, 0xE2, 0xDB, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0x1E, 0x33, 0xD7, 0x34, 0x8B, 0x25, 0x45, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0x89, 0xCE, 0xA8, 0xC9, 0x01, 0xFB, 0x0E, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0xE2, 0xF9, 0x51, 0x4C, 0x12, 0x9F, 0x60, 0xE4), + MBEDTLS_BYTES_TO_T_UINT_8(0x67, 0x85, 0xBD, 0x30, 0x37, 0x84, 0x39, 0x44), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_11_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x26, 0x33, 0xAF, 0x2E, 0xB8, 0x2E, 0xCC, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0xB1, 0x73, 0x59, 0x4E, 0x0C, 0x09, 0x4A), + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0x24, 0x89, 0x81, 0x12, 0xFF, 0xBB, 0x6E), + MBEDTLS_BYTES_TO_T_UINT_8(0x71, 0x37, 0x1A, 0x66, 0xEE, 0xED, 0xB6, 0x9B), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0xBD, 0x04, 0x20, 0x5D, 0xFB, 0xBF, 0x95), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0xF8, 0x34, 0xA3, 0xFF, 0x45, 0xDE, 0x92), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x18, 0x73, 0xF1, 0x32, 0x25, 0x58, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0xC1, 0x14, 0xE3, 0x9E, 0x40, 0x0F, 0x12), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_12_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0x07, 0x9D, 0x9C, 0x00, 0xF7, 0x56, 0x19), + MBEDTLS_BYTES_TO_T_UINT_8(0xFB, 0xBA, 0x87, 0xF9, 0x15, 0x0C, 0x66, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0x1F, 0xC1, 0x28, 0xB0, 0x47, 0x0D, 0xF5), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0xCA, 0x27, 0xEE, 0x4B, 0x23, 0x2B, 0x89), + MBEDTLS_BYTES_TO_T_UINT_8(0x7E, 0xB5, 0x68, 0xC8, 0x17, 0x5D, 0xC3, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0x02, 0x08, 0xEE, 0x20, 0x9D, 0xEA, 0x64), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0x14, 0x50, 0xD4, 0x7D, 0x5F, 0xCF, 0xA0), + MBEDTLS_BYTES_TO_T_UINT_8(0xD5, 0xFA, 0xF8, 0xA7, 0xC6, 0xDC, 0x14, 0x8C), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_12_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x76, 0xBD, 0x0A, 0x1A, 0x18, 0x98, 0xDC, 0xB0), + MBEDTLS_BYTES_TO_T_UINT_8(0x63, 0x63, 0x02, 0xB7, 0xD5, 0x5B, 0x5A, 0xC6), + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0xB1, 0xD7, 0x4B, 0x15, 0x39, 0x61, 0x5D), + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0x32, 0xE1, 0x9E, 0x70, 0x1B, 0xCE, 0x51), + MBEDTLS_BYTES_TO_T_UINT_8(0x64, 0xD8, 0x18, 0x83, 0x52, 0x9B, 0x6D, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0x55, 0x56, 0x19, 0x34, 0xA4, 0xEA, 0xFC), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0xA9, 0x55, 0x80, 0xE3, 0x15, 0x36, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0x06, 0xC8, 0x1D, 0x17, 0x0D, 0xAD, 0x16), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_13_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x20, 0xD6, 0xF0, 0xCC, 0xF3, 0x63, 0x53, 0xD2), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0x5A, 0xDC, 0x46, 0xBD, 0x0D, 0xAD, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0x2F, 0x11, 0x60, 0x15, 0x51, 0x4A, 0xEA), + MBEDTLS_BYTES_TO_T_UINT_8(0x33, 0xE3, 0x93, 0x38, 0xD5, 0x83, 0xAA, 0x0D), + MBEDTLS_BYTES_TO_T_UINT_8(0x90, 0xA6, 0xCC, 0xB1, 0xFD, 0xBB, 0x1A, 0x0F), + MBEDTLS_BYTES_TO_T_UINT_8(0x3B, 0x54, 0xC8, 0x54, 0x6F, 0x79, 0x1A, 0x59), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0x4A, 0xDA, 0x28, 0x92, 0x97, 0x9D, 0x7F), + MBEDTLS_BYTES_TO_T_UINT_8(0xD6, 0x4B, 0xDB, 0xC7, 0x52, 0xC5, 0x66, 0x34), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_13_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x05, 0x7E, 0x92, 0x53, 0x30, 0x93, 0xFD, 0xFF), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x16, 0x6A, 0xB1, 0x91, 0x0A, 0xB4, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0x6D, 0x9D, 0x40, 0x3F, 0xE3, 0xF1, 0x01, 0x46), + MBEDTLS_BYTES_TO_T_UINT_8(0x13, 0x0E, 0xD8, 0xED, 0x11, 0x8E, 0x4C, 0xED), + MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0x4A, 0x1B, 0x88, 0xDF, 0x8D, 0x29, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0x97, 0x23, 0x21, 0x11, 0xAB, 0x77, 0x81, 0x62), + MBEDTLS_BYTES_TO_T_UINT_8(0x0B, 0xAF, 0x11, 0xFA, 0xBA, 0x40, 0x63, 0xE7), + MBEDTLS_BYTES_TO_T_UINT_8(0x2B, 0x6F, 0x8D, 0x80, 0xDF, 0x67, 0xF5, 0x44), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_14_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB2, 0x8B, 0xB7, 0x08, 0xF4, 0xD7, 0x2D, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0x2B, 0x30, 0x02, 0x45, 0x71, 0x08, 0x49), + MBEDTLS_BYTES_TO_T_UINT_8(0x97, 0x3A, 0xCA, 0x50, 0xF6, 0xC2, 0x19, 0x8C), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0xB9, 0x9B, 0x3E, 0x73, 0x95, 0x1D, 0x49), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x60, 0x59, 0x48, 0xCB, 0xD8, 0xD6, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0xB9, 0x6C, 0x89, 0xAB, 0x99, 0xA8, 0xF8), + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0xA1, 0x8B, 0x4E, 0x06, 0x19, 0xEC, 0x99), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0x95, 0x04, 0xCF, 0xD5, 0x94, 0xB3, 0x02), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_14_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x29, 0x35, 0x93, 0x7C, 0xB3, 0xB8, 0x9E, 0x1B), + MBEDTLS_BYTES_TO_T_UINT_8(0xC4, 0x45, 0x5C, 0x7E, 0xBF, 0x75, 0x81, 0x0F), + MBEDTLS_BYTES_TO_T_UINT_8(0xDC, 0xE8, 0x24, 0xDF, 0xEC, 0x2F, 0x7D, 0xB9), + MBEDTLS_BYTES_TO_T_UINT_8(0xF2, 0x8B, 0xD5, 0x6A, 0x9B, 0xA0, 0xE0, 0x4F), + MBEDTLS_BYTES_TO_T_UINT_8(0x32, 0xE3, 0x27, 0x82, 0xDE, 0xDD, 0xCA, 0x4B), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0x57, 0x56, 0x46, 0x05, 0x06, 0x01, 0x2E), + MBEDTLS_BYTES_TO_T_UINT_8(0x74, 0x35, 0xA7, 0x47, 0xE2, 0x6B, 0x2C, 0x4F), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0x9D, 0x4C, 0xEC, 0x1F, 0x11, 0x75, 0x2B), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_15_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0xAA, 0x41, 0xC1, 0xE9, 0x0E, 0xE9, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0x0A, 0xCF, 0x9C, 0x4B, 0xE8, 0xED, 0x0A, 0x49), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0x73, 0xCA, 0x0C, 0x46, 0x0A, 0x9C, 0xE4), + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0xE1, 0x9E, 0xBC, 0xFE, 0x44, 0x63, 0x6D), + MBEDTLS_BYTES_TO_T_UINT_8(0x31, 0x43, 0x71, 0xEE, 0xF8, 0xC1, 0x8C, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x6A, 0x4B, 0xF0, 0x69, 0x25, 0xBD, 0x71, 0x1A), + MBEDTLS_BYTES_TO_T_UINT_8(0xFD, 0x9A, 0xFE, 0x82, 0xE7, 0xC1, 0xC1, 0xEE), + MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0x5A, 0x6E, 0x5E, 0x97, 0x6A, 0x35, 0x8D), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_15_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA2, 0x18, 0x6C, 0x7E, 0xB8, 0x9E, 0x57, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0x35, 0xB9, 0xC1, 0xD0, 0xFE, 0x78, 0xFB, 0x32), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x08, 0xAE, 0x46, 0x34, 0xEA, 0x7A, 0x7F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x1C, 0x56, 0xA9, 0x18, 0x37, 0xD4, 0x9E), + MBEDTLS_BYTES_TO_T_UINT_8(0x28, 0x63, 0xE9, 0x0A, 0xB6, 0x38, 0x3C, 0xC1), + MBEDTLS_BYTES_TO_T_UINT_8(0x3E, 0x4F, 0xA4, 0x6E, 0x85, 0x31, 0x23, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0x0D, 0xAD, 0xC4, 0xC3, 0xB1, 0x4B, 0x1C, 0x82), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0x56, 0x4A, 0x38, 0xB3, 0x6B, 0x6F, 0x2C), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_16_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x67, 0xC7, 0x19, 0xDE, 0x21, 0xED, 0x89, 0xD0), + MBEDTLS_BYTES_TO_T_UINT_8(0x2F, 0xBE, 0xA6, 0xAE, 0xEB, 0x9D, 0xA7, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x0E, 0x13, 0x1E, 0x86, 0x57, 0xC3, 0x3B), + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x4B, 0x30, 0x46, 0x52, 0xC1, 0xEC, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0x6E, 0xD5, 0x44, 0x31, 0x96, 0x3B, 0x26, 0x27), + MBEDTLS_BYTES_TO_T_UINT_8(0x77, 0x68, 0xA8, 0x67, 0x78, 0x39, 0xE8, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0x8E, 0x78, 0xB7, 0xDD, 0xF2, 0x58, 0xB6, 0x3D), + MBEDTLS_BYTES_TO_T_UINT_8(0x81, 0x3C, 0xB3, 0x26, 0xC4, 0x2C, 0x8C, 0xA5), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_16_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB9, 0x24, 0xE5, 0x73, 0xEE, 0x9A, 0x02, 0xA9), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0x6A, 0x65, 0x60, 0xF3, 0x62, 0xE3, 0xE9), + MBEDTLS_BYTES_TO_T_UINT_8(0xFB, 0x07, 0x84, 0xE6, 0x3B, 0x46, 0x65, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE1, 0x8F, 0x0C, 0xB0, 0xE1, 0x04, 0x82, 0x9D), + MBEDTLS_BYTES_TO_T_UINT_8(0xEB, 0x13, 0xBF, 0x3D, 0xA0, 0x48, 0xA2, 0x74), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0x26, 0x76, 0x74, 0xAB, 0x0B, 0x29, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0x30, 0x6E, 0x5F, 0x03, 0x34, 0x7C, 0x38, 0xCE), + MBEDTLS_BYTES_TO_T_UINT_8(0x4D, 0x72, 0xF9, 0x3B, 0x3C, 0xA4, 0xBC, 0x7C), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_17_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x5C, 0xCE, 0x18, 0x80, 0xB8, 0x24, 0x45, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x09, 0x03, 0xB8, 0x06, 0x64, 0xF7, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0xF1, 0x26, 0xB1, 0x10, 0x6D, 0x71, 0x12, 0x2E), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0x12, 0xC6, 0x6E, 0x1E, 0x6A, 0xC3, 0x80), + MBEDTLS_BYTES_TO_T_UINT_8(0xE5, 0xD3, 0x0A, 0xDE, 0xD8, 0x6B, 0x04, 0x5C), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0x87, 0x5B, 0xAE, 0xDB, 0x3C, 0xC0, 0xC5), + MBEDTLS_BYTES_TO_T_UINT_8(0x8E, 0xF5, 0xF9, 0xC1, 0x9A, 0x89, 0xBB, 0x7E), + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0x69, 0x72, 0x8B, 0xAE, 0x32, 0x13, 0x11), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_17_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF9, 0x16, 0x07, 0x50, 0xFA, 0x4C, 0xCF, 0xE8), + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0x50, 0x21, 0xE9, 0xDE, 0xEC, 0x7E, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x2F, 0xE8, 0x83, 0x30, 0x0B, 0x65, 0x0E), + MBEDTLS_BYTES_TO_T_UINT_8(0xA5, 0x0B, 0x99, 0xAC, 0xC9, 0xBA, 0x6C, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0x59, 0x5A, 0x0D, 0x7B, 0x9E, 0x08, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0x91, 0xB2, 0xDC, 0x90, 0xCE, 0x67, 0xED), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x93, 0x60, 0x0C, 0xD7, 0x1F, 0x2F, 0x17), + MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x7F, 0x9D, 0x40, 0xF8, 0x78, 0x7A, 0x54), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_18_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x13, 0x22, 0x95, 0xE8, 0xEF, 0x31, 0x57, 0x35), + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0x88, 0x53, 0xFE, 0xAF, 0x7C, 0x47, 0x14), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0xCE, 0xCC, 0x79, 0xE8, 0x9F, 0x8C, 0xC4), + MBEDTLS_BYTES_TO_T_UINT_8(0xDB, 0x16, 0xDD, 0x77, 0x6E, 0x8A, 0x73, 0x97), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0x07, 0x97, 0x21, 0x3B, 0xF8, 0x5F, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0xC6, 0xB5, 0xD2, 0x81, 0x84, 0xF0, 0xE7, 0x9F), + MBEDTLS_BYTES_TO_T_UINT_8(0xCB, 0x8F, 0x75, 0x09, 0x6A, 0x0E, 0x53, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0x4F, 0x70, 0x97, 0xC7, 0xAC, 0x7D, 0x3F), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_18_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF9, 0x3C, 0x6A, 0xB4, 0x10, 0xA9, 0xC8, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0xEE, 0xC5, 0xD6, 0x69, 0x16, 0xB8, 0xAC, 0x25), + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x44, 0xDC, 0xEB, 0x48, 0x54, 0x5D, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0x6F, 0x48, 0x9B, 0xD7, 0x72, 0x69, 0xA4, 0x8A), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x0D, 0x36, 0x9A, 0x66, 0x0B, 0xEC, 0x24), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0xC6, 0xD4, 0xB6, 0x60, 0xE5, 0xC3, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0xBA, 0x29, 0x42, 0xE0, 0x9D, 0xFD, 0x7C, 0x3E), + MBEDTLS_BYTES_TO_T_UINT_8(0x43, 0x10, 0xBA, 0x55, 0xBC, 0x3B, 0x38, 0x5D), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_19_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x25, 0x66, 0xFA, 0x05, 0x73, 0x03, 0x1B, 0x69), + MBEDTLS_BYTES_TO_T_UINT_8(0x11, 0xA4, 0x66, 0x12, 0x96, 0x7B, 0x02, 0x4C), + MBEDTLS_BYTES_TO_T_UINT_8(0x44, 0xB5, 0xDE, 0x6D, 0x98, 0xD1, 0xD5, 0xA8), + MBEDTLS_BYTES_TO_T_UINT_8(0xE2, 0xF5, 0x44, 0xB8, 0x8E, 0xF6, 0x8C, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x15, 0x2B, 0x72, 0xBC, 0x49, 0xE5, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0x6C, 0x44, 0xD7, 0xDF, 0x8F, 0xEB, 0x8D, 0x80), + MBEDTLS_BYTES_TO_T_UINT_8(0x05, 0x64, 0x88, 0xAA, 0xB7, 0xE4, 0x70, 0x1D), + MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0x14, 0xBB, 0xE9, 0x9B, 0xB9, 0x65, 0x5D), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_19_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x66, 0x8E, 0x88, 0xF5, 0xF1, 0xC1, 0x89, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0x30, 0x53, 0xE6, 0xFB, 0x2D, 0x82, 0xB4), + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0xE4, 0xFF, 0xBA, 0x31, 0x79, 0xAB, 0xC2), + MBEDTLS_BYTES_TO_T_UINT_8(0x45, 0x09, 0xF7, 0xB7, 0x09, 0x78, 0x4C, 0x90), + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0xAE, 0xC2, 0x44, 0xDC, 0x17, 0x78, 0x47), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0xD4, 0x17, 0x43, 0x19, 0x74, 0x9E, 0x23), + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x64, 0x3B, 0x73, 0xA2, 0x99, 0x27, 0x76), + MBEDTLS_BYTES_TO_T_UINT_8(0x05, 0x74, 0x36, 0x5F, 0xD3, 0x14, 0xB1, 0x31), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_20_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xAC, 0x07, 0xAB, 0xFD, 0x9B, 0x03, 0xC5, 0xD5), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0xBE, 0xB0, 0x1D, 0xF2, 0x0C, 0x73, 0x73), + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0xE7, 0x7B, 0x87, 0xD3, 0x34, 0xFD, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0x9A, 0x25, 0x3D, 0xC7, 0x36, 0x83, 0x53, 0xDC), + MBEDTLS_BYTES_TO_T_UINT_8(0x22, 0x7C, 0xCF, 0x63, 0x55, 0x12, 0x11, 0xB0), + MBEDTLS_BYTES_TO_T_UINT_8(0xC0, 0x34, 0x4D, 0x27, 0x92, 0xAC, 0x18, 0x16), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x42, 0x61, 0x9D, 0x2E, 0xFF, 0x13, 0x16), + MBEDTLS_BYTES_TO_T_UINT_8(0xF4, 0xDE, 0x92, 0x65, 0x57, 0x0D, 0xBC, 0x0A), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_20_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xEF, 0x7B, 0x6E, 0xC6, 0x2A, 0x21, 0x74, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0xA7, 0x53, 0x4D, 0x29, 0x36, 0xEF, 0xE5), + MBEDTLS_BYTES_TO_T_UINT_8(0xE1, 0xD6, 0x41, 0xC7, 0x99, 0xAD, 0x50, 0x53), + MBEDTLS_BYTES_TO_T_UINT_8(0x99, 0xAC, 0x41, 0x9F, 0xFB, 0x4C, 0x86, 0xF1), + MBEDTLS_BYTES_TO_T_UINT_8(0x8B, 0xBB, 0xE6, 0x25, 0x28, 0xAA, 0xEB, 0x1E), + MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x04, 0xA2, 0xC3, 0xAA, 0x08, 0x8A, 0xCC), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x2B, 0x5B, 0xE2, 0x8D, 0x76, 0xEA, 0x34), + MBEDTLS_BYTES_TO_T_UINT_8(0xB3, 0x33, 0xD2, 0x21, 0x4D, 0x62, 0xE3, 0x8E), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_21_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0x06, 0x8B, 0x2B, 0xC2, 0xC4, 0xB1, 0xD2), + MBEDTLS_BYTES_TO_T_UINT_8(0xFA, 0xF5, 0xA1, 0xC0, 0x03, 0x6A, 0x29, 0x12), + MBEDTLS_BYTES_TO_T_UINT_8(0xF5, 0xA9, 0xEF, 0x55, 0xB6, 0x1A, 0x9F, 0x6B), + MBEDTLS_BYTES_TO_T_UINT_8(0x9B, 0x54, 0x32, 0xBE, 0x06, 0x43, 0xB5, 0xFD), + MBEDTLS_BYTES_TO_T_UINT_8(0xF7, 0xD6, 0xD9, 0x20, 0x89, 0xBE, 0xD4, 0x1B), + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0x26, 0x95, 0x10, 0xCE, 0xB4, 0x88, 0x79), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0xA6, 0x27, 0xAC, 0x32, 0xBA, 0xBD, 0xC7), + MBEDTLS_BYTES_TO_T_UINT_8(0xA3, 0xA6, 0xAE, 0x9C, 0x7B, 0xBE, 0xA1, 0x63), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_21_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8B, 0xCD, 0x4D, 0x3D, 0xDF, 0x96, 0xBB, 0x7D), + MBEDTLS_BYTES_TO_T_UINT_8(0x77, 0xA7, 0x11, 0x06, 0xCC, 0x0E, 0x31, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0x20, 0xE4, 0xF4, 0xAD, 0x7B, 0x5F, 0xF1, 0xEF), + MBEDTLS_BYTES_TO_T_UINT_8(0xE4, 0x54, 0xBE, 0xF4, 0x8A, 0x03, 0x47, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0x53, 0x00, 0x7F, 0xB0, 0x8A, 0x68, 0xA6), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x16, 0xB1, 0x73, 0x6F, 0x5B, 0x0E, 0xC3), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0x32, 0xE3, 0x43, 0x64, 0x75, 0xFB, 0xFB), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x18, 0x55, 0x8A, 0x4E, 0x6E, 0x35, 0x54), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_22_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x80, 0x97, 0x15, 0x1E, 0xCB, 0xF2, 0x9C, 0xA5), + MBEDTLS_BYTES_TO_T_UINT_8(0x2B, 0xD1, 0xBB, 0xF3, 0x70, 0xAD, 0x13, 0xAD), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0x96, 0xA4, 0xC5, 0x5E, 0xDA, 0xD5, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0x81, 0xE9, 0x65, 0x66, 0x76, 0x47, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x35, 0x87, 0x06, 0x73, 0xCF, 0x34, 0xD2), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x81, 0x15, 0x42, 0xA2, 0x79, 0x5B, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0x08, 0xA2, 0x7D, 0x09, 0x14, 0x64, 0xC6, 0xAE), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0x6D, 0xC4, 0xED, 0xF1, 0xD6, 0xE9, 0x24), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_22_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xB4, 0xD5, 0xBB, 0x25, 0xA3, 0xDD, 0xA3, 0x88), + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0xF2, 0x68, 0x67, 0x39, 0x8F, 0x73, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0x76, 0x28, 0x89, 0xAD, 0x32, 0xE0, 0xDF), + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0x90, 0xCC, 0x57, 0x58, 0xAA, 0xC9, 0x75), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0xD7, 0x43, 0xD2, 0xCE, 0x5E, 0xA0, 0x08), + MBEDTLS_BYTES_TO_T_UINT_8(0x33, 0xB0, 0xB8, 0xA4, 0x9E, 0x96, 0x26, 0x86), + MBEDTLS_BYTES_TO_T_UINT_8(0x94, 0x61, 0x1D, 0xF3, 0x65, 0x5E, 0x60, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0x1E, 0x65, 0xED, 0xCF, 0x07, 0x60, 0x20), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_23_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0x30, 0x17, 0x8A, 0x91, 0x88, 0x0A, 0xA4), + MBEDTLS_BYTES_TO_T_UINT_8(0x05, 0x7D, 0x18, 0xA4, 0xAC, 0x59, 0xFC, 0x5F), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0x31, 0x8B, 0x25, 0x65, 0x39, 0x9A, 0xDC), + MBEDTLS_BYTES_TO_T_UINT_8(0x15, 0x16, 0x4B, 0x68, 0xBA, 0x59, 0x13, 0x2F), + MBEDTLS_BYTES_TO_T_UINT_8(0x8D, 0xFD, 0xD3, 0xC5, 0x56, 0xC9, 0x8C, 0x5E), + MBEDTLS_BYTES_TO_T_UINT_8(0xBC, 0xC6, 0x9F, 0xF4, 0xE6, 0xF7, 0xB4, 0x01), + MBEDTLS_BYTES_TO_T_UINT_8(0x2D, 0x7C, 0x03, 0x00, 0x26, 0x9F, 0xD8, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0x24, 0x1D, 0x6E, 0x00, 0xB9, 0x00, 0x6E, 0x93), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_23_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x75, 0x63, 0xDA, 0x03, 0x2B, 0xD5, 0x0B, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0x46, 0xFC, 0xE2, 0xC8, 0x47, 0xF0, 0xAE, 0xF2), + MBEDTLS_BYTES_TO_T_UINT_8(0x51, 0x4C, 0xF7, 0x50, 0x0C, 0x48, 0x06, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0xDF, 0x2B, 0x32, 0x98, 0x0E, 0x7E, 0x61, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0x02, 0x27, 0xFE, 0x75, 0x86, 0xDF, 0x24), + MBEDTLS_BYTES_TO_T_UINT_8(0x2B, 0x30, 0xB1, 0x22, 0x32, 0x1B, 0xFE, 0x24), + MBEDTLS_BYTES_TO_T_UINT_8(0xC2, 0x27, 0xF7, 0x78, 0x6F, 0xD7, 0xFD, 0xE4), + MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0x78, 0xCC, 0xEA, 0xC0, 0x50, 0x24, 0x44), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_24_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x2B, 0x4F, 0x7F, 0x58, 0xE6, 0xC2, 0x70), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x43, 0xD5, 0xA7, 0x35, 0x3C, 0x80, 0xB8), + MBEDTLS_BYTES_TO_T_UINT_8(0x1A, 0x6D, 0x4B, 0x12, 0x00, 0x7B, 0xE6, 0xA6), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x15, 0xBD, 0xD0, 0x9B, 0xCA, 0xAA, 0x81), + MBEDTLS_BYTES_TO_T_UINT_8(0xCF, 0xCE, 0x9C, 0xE3, 0x8B, 0x60, 0x7A, 0x53), + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0xDA, 0x4B, 0x03, 0xA7, 0x8D, 0x43, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0xAF, 0x00, 0x2B, 0x32, 0xF0, 0x22, 0x68), + MBEDTLS_BYTES_TO_T_UINT_8(0xDC, 0xD9, 0x99, 0x99, 0xBE, 0x43, 0x99, 0x3E), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_24_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x1F, 0x71, 0x41, 0xF4, 0xB5, 0xFD, 0xDD, 0x36), + MBEDTLS_BYTES_TO_T_UINT_8(0x9D, 0xE2, 0x20, 0x4C, 0xD1, 0x2E, 0x1F, 0x06), + MBEDTLS_BYTES_TO_T_UINT_8(0x96, 0x43, 0x48, 0x76, 0x8A, 0x49, 0xAC, 0x87), + MBEDTLS_BYTES_TO_T_UINT_8(0x0C, 0x1A, 0x55, 0xA8, 0xA3, 0xD4, 0x57, 0x75), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0xA6, 0x84, 0x39, 0xC9, 0x13, 0xBB, 0x60), + MBEDTLS_BYTES_TO_T_UINT_8(0xD9, 0xFA, 0xA9, 0x70, 0xDE, 0x83, 0xDD, 0xC9), + MBEDTLS_BYTES_TO_T_UINT_8(0xEC, 0xC9, 0xD9, 0x3E, 0x44, 0x91, 0x68, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0xB6, 0x9F, 0x85, 0x6D, 0xF7, 0x54, 0x36, 0x82), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_25_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x68, 0x6B, 0xA6, 0xA3, 0xE5, 0xD4, 0x46, 0xDB), + MBEDTLS_BYTES_TO_T_UINT_8(0x23, 0x3E, 0xDC, 0x84, 0x7C, 0x7B, 0x24, 0x34), + MBEDTLS_BYTES_TO_T_UINT_8(0x14, 0xED, 0x7F, 0x86, 0x07, 0x6C, 0x57, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0x95, 0x06, 0xFE, 0x52, 0x12, 0x79, 0x69, 0x56), + MBEDTLS_BYTES_TO_T_UINT_8(0x84, 0xD1, 0x44, 0x5F, 0x21, 0x3A, 0xC3, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0x5E, 0xD9, 0x4A, 0xC0, 0x75, 0xAB, 0x17, 0xAC), + MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0x81, 0x94, 0xB6, 0x80, 0x6B, 0x6F, 0xC3), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0xBE, 0x8E, 0xA5, 0xAA, 0xBC, 0x1E, 0x3E), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_25_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x89, 0xC7, 0x85, 0xA6, 0x59, 0x9B, 0xB1, 0x52), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0xCE, 0x40, 0xD1, 0xFB, 0xDF, 0x94, 0xF7), + MBEDTLS_BYTES_TO_T_UINT_8(0x18, 0xB8, 0x5E, 0xBF, 0x45, 0xA8, 0x2D, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x98, 0x9C, 0x06, 0x1B, 0xA9, 0x57, 0xB9, 0x79), + MBEDTLS_BYTES_TO_T_UINT_8(0x53, 0xE9, 0xCE, 0xA2, 0xD3, 0x74, 0xA1, 0x3C), + MBEDTLS_BYTES_TO_T_UINT_8(0xAA, 0x5F, 0x34, 0x78, 0xDB, 0xAE, 0x3A, 0x14), + MBEDTLS_BYTES_TO_T_UINT_8(0x7D, 0x32, 0x84, 0x3E, 0x68, 0x6A, 0x43, 0x0F), + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0xBC, 0x39, 0x36, 0xA4, 0xC5, 0xBB, 0x11), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_26_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x8C, 0x07, 0xA2, 0xB5, 0xC9, 0x0F, 0x4D, 0x0F), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0x1D, 0x67, 0xE6, 0xF1, 0x46, 0xEB, 0x71), + MBEDTLS_BYTES_TO_T_UINT_8(0xD7, 0x41, 0x23, 0x95, 0xE7, 0xE0, 0x10, 0xDD), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0x69, 0xFE, 0x68, 0x8C, 0xC6, 0x5F, 0xB6), + MBEDTLS_BYTES_TO_T_UINT_8(0xE3, 0xB9, 0x2B, 0x3D, 0xD2, 0x4F, 0xD8, 0x1A), + MBEDTLS_BYTES_TO_T_UINT_8(0xA3, 0x09, 0xF5, 0x5F, 0xCF, 0xF6, 0x91, 0x57), + MBEDTLS_BYTES_TO_T_UINT_8(0x65, 0x15, 0x42, 0x6B, 0x6D, 0xB5, 0xF3, 0xB6), + MBEDTLS_BYTES_TO_T_UINT_8(0xBF, 0x56, 0x9D, 0xC5, 0xFF, 0xCA, 0x13, 0x9B), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_26_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x4D, 0x38, 0xE6, 0x23, 0x63, 0x48, 0x3C, 0xCA), + MBEDTLS_BYTES_TO_T_UINT_8(0xD2, 0x68, 0x3C, 0xD1, 0x3B, 0xE9, 0x3B, 0x82), + MBEDTLS_BYTES_TO_T_UINT_8(0xB5, 0x08, 0x54, 0x49, 0xD1, 0x46, 0x45, 0x13), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0x70, 0x52, 0x6E, 0x79, 0xC4, 0x5E, 0x95), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0xDF, 0xE8, 0x5A, 0x32, 0x81, 0xDA, 0xD3), + MBEDTLS_BYTES_TO_T_UINT_8(0x3C, 0x2D, 0x94, 0x5B, 0xB5, 0x35, 0x9F, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0x2A, 0x12, 0x8D, 0xC3, 0x36, 0x36, 0xB2, 0x2A), + MBEDTLS_BYTES_TO_T_UINT_8(0x39, 0x2F, 0x22, 0x38, 0x5B, 0x18, 0x4C, 0x35), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_27_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0xC1, 0x22, 0x0E, 0xF0, 0x73, 0x11, 0x05), + MBEDTLS_BYTES_TO_T_UINT_8(0xB2, 0xAE, 0xA4, 0x56, 0x18, 0x61, 0x66, 0x12), + MBEDTLS_BYTES_TO_T_UINT_8(0x79, 0xFB, 0x72, 0x08, 0x84, 0x38, 0x51, 0xB0), + MBEDTLS_BYTES_TO_T_UINT_8(0xDA, 0x86, 0xA8, 0xB9, 0x31, 0x99, 0x29, 0xC3), + MBEDTLS_BYTES_TO_T_UINT_8(0x8A, 0xFB, 0xC3, 0x42, 0xB3, 0xC7, 0x6F, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0xD8, 0xF8, 0xE1, 0x09, 0xBE, 0x75, 0xB0, 0x22), + MBEDTLS_BYTES_TO_T_UINT_8(0x5A, 0x7D, 0xFF, 0xF4, 0x99, 0xFC, 0x13, 0xAB), + MBEDTLS_BYTES_TO_T_UINT_8(0xE6, 0x1B, 0x84, 0x81, 0x42, 0x22, 0xC6, 0x3D), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_27_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x21, 0xE0, 0x37, 0xA4, 0xA0, 0x2F, 0x38, 0x7F), + MBEDTLS_BYTES_TO_T_UINT_8(0xD0, 0x3D, 0xB7, 0x40, 0x2F, 0x39, 0x3C, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0x7A, 0x3B, 0x8A, 0x51, 0xAE, 0x40, 0x49, 0x7A), + MBEDTLS_BYTES_TO_T_UINT_8(0x36, 0x20, 0x9F, 0xDD, 0xA9, 0xD0, 0x77, 0xC7), + MBEDTLS_BYTES_TO_T_UINT_8(0x78, 0x1D, 0x64, 0xDA, 0xA0, 0x53, 0xC7, 0x7D), + MBEDTLS_BYTES_TO_T_UINT_8(0x37, 0x7B, 0x66, 0x55, 0x94, 0xD1, 0x51, 0x44), + MBEDTLS_BYTES_TO_T_UINT_8(0x0E, 0xA9, 0xB5, 0x5B, 0x38, 0x35, 0x40, 0xC0), + MBEDTLS_BYTES_TO_T_UINT_8(0xC8, 0xC9, 0x0F, 0xF0, 0x73, 0x79, 0x43, 0x61), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_28_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0x47, 0x45, 0x69, 0x80, 0x72, 0x72, 0x42), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0x11, 0x99, 0x59, 0xDB, 0x48, 0x80, 0x39), + MBEDTLS_BYTES_TO_T_UINT_8(0x75, 0x6E, 0x3D, 0xFC, 0x37, 0x15, 0xF4, 0xBF), + MBEDTLS_BYTES_TO_T_UINT_8(0x17, 0xBB, 0x5B, 0xA6, 0x35, 0x8D, 0x28, 0x20), + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0x1A, 0x3B, 0x2C, 0x8F, 0xD3, 0xAA, 0x2D), + MBEDTLS_BYTES_TO_T_UINT_8(0x55, 0x1C, 0x1A, 0xF8, 0x02, 0xD9, 0x7B, 0x41), + MBEDTLS_BYTES_TO_T_UINT_8(0xAF, 0x69, 0xAC, 0xF8, 0x54, 0x31, 0x14, 0xA1), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0x8A, 0xE6, 0xDE, 0x58, 0xB9, 0xC4, 0x7A), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_28_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x57, 0x83, 0x52, 0xFE, 0xF9, 0x7B, 0xE9, 0x1F), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0xA2, 0x55, 0x46, 0x15, 0x49, 0xC1, 0x3A), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0xBC, 0x5C, 0x91, 0xBD, 0xB9, 0x9C, 0xF4), + MBEDTLS_BYTES_TO_T_UINT_8(0xBB, 0xFD, 0xB1, 0x4E, 0x5F, 0x74, 0xEE, 0x53), + MBEDTLS_BYTES_TO_T_UINT_8(0xB1, 0x8B, 0xD8, 0x8B, 0x17, 0x73, 0x1B, 0x96), + MBEDTLS_BYTES_TO_T_UINT_8(0x22, 0x92, 0xD7, 0x67, 0x06, 0xAD, 0x25, 0xCD), + MBEDTLS_BYTES_TO_T_UINT_8(0x01, 0x0F, 0x80, 0x24, 0xE2, 0x27, 0x5F, 0x8B), + MBEDTLS_BYTES_TO_T_UINT_8(0x61, 0x1C, 0xCE, 0xD0, 0x67, 0xCA, 0xD4, 0x0B), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_29_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x87, 0xF1, 0xDD, 0x33, 0x66, 0xF9, 0x05, 0xD6), + MBEDTLS_BYTES_TO_T_UINT_8(0x1D, 0xE5, 0x6B, 0x79, 0xBD, 0x48, 0x42, 0xAA), + MBEDTLS_BYTES_TO_T_UINT_8(0xD1, 0x14, 0x52, 0xE3, 0x53, 0xB4, 0x50, 0xD4), + MBEDTLS_BYTES_TO_T_UINT_8(0x32, 0x84, 0x6C, 0xCF, 0xDA, 0xB2, 0x20, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0xD6, 0x1A, 0xE5, 0xE2, 0x29, 0x70, 0xCE), + MBEDTLS_BYTES_TO_T_UINT_8(0xD5, 0x61, 0xFE, 0xBB, 0x21, 0x82, 0xD1, 0xFE), + MBEDTLS_BYTES_TO_T_UINT_8(0x2C, 0xF0, 0x9C, 0x8B, 0x1A, 0x42, 0x30, 0x06), + MBEDTLS_BYTES_TO_T_UINT_8(0x43, 0xD6, 0x49, 0x81, 0x92, 0xF1, 0xD0, 0x90), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_29_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xC9, 0x91, 0x93, 0x6A, 0xA6, 0x22, 0xE9, 0xD6), + MBEDTLS_BYTES_TO_T_UINT_8(0x09, 0xDC, 0xC3, 0x69, 0x11, 0x95, 0x7D, 0xEC), + MBEDTLS_BYTES_TO_T_UINT_8(0x1C, 0xA3, 0x9D, 0x87, 0x5E, 0x64, 0x41, 0xA2), + MBEDTLS_BYTES_TO_T_UINT_8(0xBE, 0x87, 0x5A, 0x15, 0xBD, 0x6E, 0x3C, 0x8D), + MBEDTLS_BYTES_TO_T_UINT_8(0xD0, 0x8D, 0x50, 0xCC, 0xCF, 0xB7, 0x8F, 0x0B), + MBEDTLS_BYTES_TO_T_UINT_8(0x38, 0x65, 0xCD, 0x31, 0x30, 0xF1, 0x68, 0x13), + MBEDTLS_BYTES_TO_T_UINT_8(0x10, 0x5C, 0x66, 0x67, 0x92, 0x30, 0x57, 0x95), + MBEDTLS_BYTES_TO_T_UINT_8(0x23, 0x9B, 0x01, 0x3D, 0x20, 0x8B, 0xD1, 0x0D), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_30_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xAB, 0xC0, 0xE6, 0x4F, 0xDE, 0x62, 0xAB, 0xB3), + MBEDTLS_BYTES_TO_T_UINT_8(0xA4, 0x48, 0xB3, 0x1C, 0x0F, 0x16, 0x93, 0x45), + MBEDTLS_BYTES_TO_T_UINT_8(0x77, 0x63, 0xBD, 0x1F, 0x16, 0x50, 0x56, 0x98), + MBEDTLS_BYTES_TO_T_UINT_8(0x5D, 0x06, 0xBC, 0xE9, 0x27, 0x1C, 0x9A, 0x7B), + MBEDTLS_BYTES_TO_T_UINT_8(0xF8, 0xFE, 0x21, 0xC5, 0x39, 0x55, 0xE1, 0xFD), + MBEDTLS_BYTES_TO_T_UINT_8(0xF6, 0xA8, 0xD0, 0x96, 0x0E, 0xB5, 0xB2, 0x84), + MBEDTLS_BYTES_TO_T_UINT_8(0x3D, 0xE7, 0x4B, 0xF3, 0x11, 0x0C, 0xC9, 0x5B), + MBEDTLS_BYTES_TO_T_UINT_8(0x43, 0x3A, 0xC4, 0x87, 0x71, 0xEE, 0xFA, 0x18), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_30_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0x77, 0xEE, 0x81, 0x5E, 0x96, 0xEA, 0x4B), + MBEDTLS_BYTES_TO_T_UINT_8(0xEE, 0xDF, 0xA9, 0xF4, 0x4F, 0x7C, 0xB2, 0x43), + MBEDTLS_BYTES_TO_T_UINT_8(0x9F, 0xD4, 0xDF, 0x35, 0x63, 0x47, 0x25, 0x8A), + MBEDTLS_BYTES_TO_T_UINT_8(0xA5, 0x3D, 0xFF, 0xA4, 0x02, 0xC3, 0x95, 0x11), + MBEDTLS_BYTES_TO_T_UINT_8(0xD5, 0x10, 0x78, 0xD1, 0x2B, 0xB7, 0xBE, 0x0E), + MBEDTLS_BYTES_TO_T_UINT_8(0x0A, 0xE9, 0x57, 0xF9, 0xE0, 0xD8, 0xFC, 0xBC), + MBEDTLS_BYTES_TO_T_UINT_8(0xF3, 0xC4, 0x01, 0xD6, 0xB4, 0xE7, 0x78, 0xE2), + MBEDTLS_BYTES_TO_T_UINT_8(0x02, 0x6C, 0xB9, 0x13, 0xA4, 0xE8, 0x6D, 0x6F), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_31_X[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xE8, 0xB0, 0xC9, 0xCD, 0xBF, 0xA2, 0x1E, 0x63), + MBEDTLS_BYTES_TO_T_UINT_8(0xDD, 0x4F, 0x86, 0x22, 0x9B, 0xEA, 0xE8, 0xBB), + MBEDTLS_BYTES_TO_T_UINT_8(0x50, 0x46, 0xDF, 0x43, 0xB9, 0x82, 0x2D, 0x0A), + MBEDTLS_BYTES_TO_T_UINT_8(0x07, 0x32, 0xF1, 0x4E, 0x95, 0x41, 0xAE, 0x8E), + MBEDTLS_BYTES_TO_T_UINT_8(0x52, 0x93, 0x26, 0xFC, 0xD3, 0x90, 0xDC, 0xEB), + MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x05, 0x45, 0xCA, 0xF9, 0x5A, 0x89, 0x93), + MBEDTLS_BYTES_TO_T_UINT_8(0xC5, 0x82, 0x63, 0x4E, 0x55, 0x1D, 0x3A, 0x08), + MBEDTLS_BYTES_TO_T_UINT_8(0x7C, 0x69, 0x52, 0x49, 0xE9, 0xED, 0x57, 0x34), +}; +static const mbedtls_mpi_uint brainpoolP512r1_T_31_Y[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0x70, 0x64, 0xE9, 0xAC, 0x4C, 0x4A, 0xEA, 0x25), + MBEDTLS_BYTES_TO_T_UINT_8(0xE9, 0xE9, 0x0B, 0x99, 0xE7, 0xF9, 0xA9, 0x2C), + MBEDTLS_BYTES_TO_T_UINT_8(0x24, 0x0C, 0xC1, 0xF4, 0x8D, 0x07, 0xB6, 0xB1), + MBEDTLS_BYTES_TO_T_UINT_8(0xAD, 0x68, 0xFA, 0x35, 0xE4, 0x9E, 0xAE, 0xD9), + MBEDTLS_BYTES_TO_T_UINT_8(0xF0, 0x2D, 0x1A, 0x13, 0x8E, 0x02, 0xE2, 0x63), + MBEDTLS_BYTES_TO_T_UINT_8(0x27, 0x38, 0x28, 0x86, 0x46, 0x7B, 0x3A, 0xE1), + MBEDTLS_BYTES_TO_T_UINT_8(0x3F, 0x4C, 0x64, 0x59, 0x0A, 0xF9, 0x02, 0xC4), + MBEDTLS_BYTES_TO_T_UINT_8(0x41, 0x4F, 0x23, 0xA2, 0xC3, 0xD5, 0xEF, 0x42), +}; +static const mbedtls_ecp_point brainpoolP512r1_T[32] = { + ECP_POINT_INIT_XY_Z1(brainpoolP512r1_T_0_X, brainpoolP512r1_T_0_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_1_X, brainpoolP512r1_T_1_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_2_X, brainpoolP512r1_T_2_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_3_X, brainpoolP512r1_T_3_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_4_X, brainpoolP512r1_T_4_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_5_X, brainpoolP512r1_T_5_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_6_X, brainpoolP512r1_T_6_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_7_X, brainpoolP512r1_T_7_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_8_X, brainpoolP512r1_T_8_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_9_X, brainpoolP512r1_T_9_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_10_X, brainpoolP512r1_T_10_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_11_X, brainpoolP512r1_T_11_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_12_X, brainpoolP512r1_T_12_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_13_X, brainpoolP512r1_T_13_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_14_X, brainpoolP512r1_T_14_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_15_X, brainpoolP512r1_T_15_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_16_X, brainpoolP512r1_T_16_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_17_X, brainpoolP512r1_T_17_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_18_X, brainpoolP512r1_T_18_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_19_X, brainpoolP512r1_T_19_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_20_X, brainpoolP512r1_T_20_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_21_X, brainpoolP512r1_T_21_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_22_X, brainpoolP512r1_T_22_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_23_X, brainpoolP512r1_T_23_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_24_X, brainpoolP512r1_T_24_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_25_X, brainpoolP512r1_T_25_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_26_X, brainpoolP512r1_T_26_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_27_X, brainpoolP512r1_T_27_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_28_X, brainpoolP512r1_T_28_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_29_X, brainpoolP512r1_T_29_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_30_X, brainpoolP512r1_T_30_Y), + ECP_POINT_INIT_XY_Z0(brainpoolP512r1_T_31_X, brainpoolP512r1_T_31_Y), +}; +#else +#define brainpoolP512r1_T NULL +#endif +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ + + +#if defined(ECP_LOAD_GROUP) || defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) || \ + defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) +/* + * Create an MPI from embedded constants + * (assumes len is an exact multiple of sizeof(mbedtls_mpi_uint) and + * len < 1048576) + */ +static inline void ecp_mpi_load(mbedtls_mpi *X, const mbedtls_mpi_uint *p, size_t len) +{ + X->s = 1; + X->n = (unsigned short) (len / sizeof(mbedtls_mpi_uint)); + X->p = (mbedtls_mpi_uint *) p; +} +#endif + +#if defined(ECP_LOAD_GROUP) +/* + * Set an MPI to static value 1 + */ +static inline void ecp_mpi_set1(mbedtls_mpi *X) +{ + X->s = 1; + X->n = 1; + X->p = mpi_one; +} + +/* + * Make group available from embedded constants + */ +static int ecp_group_load(mbedtls_ecp_group *grp, + const mbedtls_mpi_uint *p, size_t plen, + const mbedtls_mpi_uint *a, size_t alen, + const mbedtls_mpi_uint *b, size_t blen, + const mbedtls_mpi_uint *gx, size_t gxlen, + const mbedtls_mpi_uint *gy, size_t gylen, + const mbedtls_mpi_uint *n, size_t nlen, + const mbedtls_ecp_point *T) +{ + ecp_mpi_load(&grp->P, p, plen); + if (a != NULL) { + ecp_mpi_load(&grp->A, a, alen); + } + ecp_mpi_load(&grp->B, b, blen); + ecp_mpi_load(&grp->N, n, nlen); + + ecp_mpi_load(&grp->G.X, gx, gxlen); + ecp_mpi_load(&grp->G.Y, gy, gylen); + ecp_mpi_set1(&grp->G.Z); + + grp->pbits = mbedtls_mpi_bitlen(&grp->P); + grp->nbits = mbedtls_mpi_bitlen(&grp->N); + + grp->h = 1; + + grp->T = (mbedtls_ecp_point *) T; + /* + * Set T_size to 0 to prevent T free by mbedtls_ecp_group_free. + */ + grp->T_size = 0; + + return 0; +} +#endif /* ECP_LOAD_GROUP */ + +#if defined(MBEDTLS_ECP_NIST_OPTIM) +/* Forward declarations */ +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +static int ecp_mod_p256(mbedtls_mpi *); +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p256_raw(mbedtls_mpi_uint *X, size_t X_limbs); +#endif +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +static int ecp_mod_p384(mbedtls_mpi *); +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p384_raw(mbedtls_mpi_uint *X, size_t X_limbs); +#endif +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +static int ecp_mod_p521(mbedtls_mpi *); +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p521_raw(mbedtls_mpi_uint *N_p, size_t N_n); +#endif + +#define NIST_MODP(P) grp->modp = ecp_mod_ ## P; +#else +#define NIST_MODP(P) +#endif /* MBEDTLS_ECP_NIST_OPTIM */ + +/* Additional forward declarations */ +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +static int ecp_mod_p255(mbedtls_mpi *); +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p255_raw(mbedtls_mpi_uint *X, size_t X_limbs); +#endif +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) +static int ecp_mod_p448(mbedtls_mpi *); +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p448_raw(mbedtls_mpi_uint *, size_t); +#endif +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +static int ecp_mod_p256k1(mbedtls_mpi *); +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p256k1_raw(mbedtls_mpi_uint *X, size_t X_limbs); +#endif + +#if defined(ECP_LOAD_GROUP) +#define LOAD_GROUP_A(G) ecp_group_load(grp, \ + G ## _p, sizeof(G ## _p), \ + G ## _a, sizeof(G ## _a), \ + G ## _b, sizeof(G ## _b), \ + G ## _gx, sizeof(G ## _gx), \ + G ## _gy, sizeof(G ## _gy), \ + G ## _n, sizeof(G ## _n), \ + G ## _T \ + ) + +#define LOAD_GROUP(G) ecp_group_load(grp, \ + G ## _p, sizeof(G ## _p), \ + NULL, 0, \ + G ## _b, sizeof(G ## _b), \ + G ## _gx, sizeof(G ## _gx), \ + G ## _gy, sizeof(G ## _gy), \ + G ## _n, sizeof(G ## _n), \ + G ## _T \ + ) +#endif /* ECP_LOAD_GROUP */ + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +/* Constants used by ecp_use_curve25519() */ +static const mbedtls_mpi_sint curve25519_a24 = 0x01DB42; + +/* P = 2^255 - 19 */ +static const mbedtls_mpi_uint curve25519_p[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xED, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF), + MBEDTLS_BYTES_TO_T_UINT_8(0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF), + MBEDTLS_BYTES_TO_T_UINT_8(0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF), + MBEDTLS_BYTES_TO_T_UINT_8(0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X7F) +}; + +/* N = 2^252 + 27742317777372353535851937790883648493 */ +static const mbedtls_mpi_uint curve25519_n[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0XED, 0XD3, 0XF5, 0X5C, 0X1A, 0X63, 0X12, 0X58), + MBEDTLS_BYTES_TO_T_UINT_8(0XD6, 0X9C, 0XF7, 0XA2, 0XDE, 0XF9, 0XDE, 0X14), + MBEDTLS_BYTES_TO_T_UINT_8(0X00, 0X00, 0X00, 0X00, 0x00, 0x00, 0x00, 0x00), + MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10) +}; + +/* + * Specialized function for creating the Curve25519 group + */ +static int ecp_use_curve25519(mbedtls_ecp_group *grp) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + /* Actually ( A + 2 ) / 4 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&grp->A, curve25519_a24)); + + ecp_mpi_load(&grp->P, curve25519_p, sizeof(curve25519_p)); + + grp->pbits = mbedtls_mpi_bitlen(&grp->P); + + ecp_mpi_load(&grp->N, curve25519_n, sizeof(curve25519_n)); + + /* Y intentionally not set, since we use x/z coordinates. + * This is used as a marker to identify Montgomery curves! */ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&grp->G.X, 9)); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&grp->G.Z, 1)); + mbedtls_mpi_free(&grp->G.Y); + + /* Actually, the required msb for private keys */ + grp->nbits = 254; + +cleanup: + if (ret != 0) { + mbedtls_ecp_group_free(grp); + } + + return ret; +} +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) +/* Constants used by ecp_use_curve448() */ +static const mbedtls_mpi_sint curve448_a24 = 0x98AA; + +/* P = 2^448 - 2^224 - 1 */ +static const mbedtls_mpi_uint curve448_p[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF), + MBEDTLS_BYTES_TO_T_UINT_8(0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF), + MBEDTLS_BYTES_TO_T_UINT_8(0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF), + MBEDTLS_BYTES_TO_T_UINT_8(0XFF, 0XFF, 0XFF, 0XFF, 0XFE, 0XFF, 0XFF, 0XFF), + MBEDTLS_BYTES_TO_T_UINT_8(0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF), + MBEDTLS_BYTES_TO_T_UINT_8(0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF), + MBEDTLS_BYTES_TO_T_UINT_8(0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF), + MBEDTLS_BYTES_TO_T_UINT_8(0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00) +}; + +/* N = 2^446 - 13818066809895115352007386748515426880336692474882178609894547503885 */ +static const mbedtls_mpi_uint curve448_n[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0XF3, 0X44, 0X58, 0XAB, 0X92, 0XC2, 0X78, 0X23), + MBEDTLS_BYTES_TO_T_UINT_8(0X55, 0X8F, 0XC5, 0X8D, 0X72, 0XC2, 0X6C, 0X21), + MBEDTLS_BYTES_TO_T_UINT_8(0X90, 0X36, 0XD6, 0XAE, 0X49, 0XDB, 0X4E, 0XC4), + MBEDTLS_BYTES_TO_T_UINT_8(0XE9, 0X23, 0XCA, 0X7C, 0XFF, 0XFF, 0XFF, 0XFF), + MBEDTLS_BYTES_TO_T_UINT_8(0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF), + MBEDTLS_BYTES_TO_T_UINT_8(0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF), + MBEDTLS_BYTES_TO_T_UINT_8(0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0X3F), + MBEDTLS_BYTES_TO_T_UINT_8(0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00) +}; + +/* + * Specialized function for creating the Curve448 group + */ +static int ecp_use_curve448(mbedtls_ecp_group *grp) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + /* Actually ( A + 2 ) / 4 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&grp->A, curve448_a24)); + + ecp_mpi_load(&grp->P, curve448_p, sizeof(curve448_p)); + grp->pbits = mbedtls_mpi_bitlen(&grp->P); + + /* Y intentionally not set, since we use x/z coordinates. + * This is used as a marker to identify Montgomery curves! */ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&grp->G.X, 5)); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&grp->G.Z, 1)); + mbedtls_mpi_free(&grp->G.Y); + + ecp_mpi_load(&grp->N, curve448_n, sizeof(curve448_n)); + + /* Actually, the required msb for private keys */ + grp->nbits = 447; + +cleanup: + if (ret != 0) { + mbedtls_ecp_group_free(grp); + } + + return ret; +} +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ + +/* + * Set a group using well-known domain parameters + */ +int mbedtls_ecp_group_load(mbedtls_ecp_group *grp, mbedtls_ecp_group_id id) +{ + mbedtls_ecp_group_free(grp); + + mbedtls_ecp_group_init(grp); + + grp->id = id; + + switch (id) { +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + case MBEDTLS_ECP_DP_SECP256R1: + NIST_MODP(p256); + return LOAD_GROUP(secp256r1); +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + case MBEDTLS_ECP_DP_SECP384R1: + NIST_MODP(p384); + return LOAD_GROUP(secp384r1); +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + case MBEDTLS_ECP_DP_SECP521R1: + NIST_MODP(p521); + return LOAD_GROUP(secp521r1); +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + case MBEDTLS_ECP_DP_SECP256K1: + grp->modp = ecp_mod_p256k1; + return LOAD_GROUP_A(secp256k1); +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + case MBEDTLS_ECP_DP_BP256R1: + return LOAD_GROUP_A(brainpoolP256r1); +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + case MBEDTLS_ECP_DP_BP384R1: + return LOAD_GROUP_A(brainpoolP384r1); +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + case MBEDTLS_ECP_DP_BP512R1: + return LOAD_GROUP_A(brainpoolP512r1); +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + case MBEDTLS_ECP_DP_CURVE25519: + grp->modp = ecp_mod_p255; + return ecp_use_curve25519(grp); +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + case MBEDTLS_ECP_DP_CURVE448: + grp->modp = ecp_mod_p448; + return ecp_use_curve448(grp); +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ + + default: + grp->id = MBEDTLS_ECP_DP_NONE; + return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + } +} + +#if defined(MBEDTLS_ECP_NIST_OPTIM) +/* + * Fast reduction modulo the primes used by the NIST curves. + * + * These functions are critical for speed, but not needed for correct + * operations. So, we make the choice to heavily rely on the internals of our + * bignum library, which creates a tight coupling between these functions and + * our MPI implementation. However, the coupling between the ECP module and + * MPI remains loose, since these functions can be deactivated at will. + */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + +/* + * The reader is advised to first understand ecp_mod_p192() since the same + * general structure is used here, but with additional complications: + * (1) chunks of 32 bits, and (2) subtractions. + */ + +/* + * For these primes, we need to handle data in chunks of 32 bits. + * This makes it more complicated if we use 64 bits limbs in MPI, + * which prevents us from using a uniform access method as for p192. + * + * So, we define a mini abstraction layer to access 32 bit chunks, + * load them in 'cur' for work, and store them back from 'cur' when done. + * + * While at it, also define the size of N in terms of 32-bit chunks. + */ +#define LOAD32 cur = A(i); + +#if defined(MBEDTLS_HAVE_INT32) /* 32 bit */ + +#define MAX32 X_limbs +#define A(j) X[j] +#define STORE32 X[i] = (mbedtls_mpi_uint) cur; +#define STORE0 X[i] = 0; + +#else /* 64 bit */ + +#define MAX32 X_limbs * 2 +#define A(j) \ + (j) % 2 ? \ + (uint32_t) (X[(j) / 2] >> 32) : \ + (uint32_t) (X[(j) / 2]) +#define STORE32 \ + if (i % 2) { \ + X[i/2] &= 0x00000000FFFFFFFF; \ + X[i/2] |= (uint64_t) (cur) << 32; \ + } else { \ + X[i/2] &= 0xFFFFFFFF00000000; \ + X[i/2] |= (uint32_t) cur; \ + } + +#define STORE0 \ + if (i % 2) { \ + X[i/2] &= 0x00000000FFFFFFFF; \ + } else { \ + X[i/2] &= 0xFFFFFFFF00000000; \ + } + +#endif + +static inline int8_t extract_carry(int64_t cur) +{ + return (int8_t) (cur >> 32); +} + +#define ADD(j) cur += A(j) +#define SUB(j) cur -= A(j) + +#define ADD_CARRY(cc) cur += (cc) +#define SUB_CARRY(cc) cur -= (cc) + +#define ADD_LAST ADD_CARRY(last_c) +#define SUB_LAST SUB_CARRY(last_c) + +/* + * Helpers for the main 'loop' + */ +#define INIT(b) \ + int8_t c = 0, last_c; \ + int64_t cur; \ + size_t i = 0; \ + LOAD32; + +#define NEXT \ + c = extract_carry(cur); \ + STORE32; i++; LOAD32; \ + ADD_CARRY(c); + +#define RESET \ + c = extract_carry(cur); \ + last_c = c; \ + STORE32; i = 0; LOAD32; \ + c = 0; \ + +#define LAST \ + c = extract_carry(cur); \ + STORE32; i++; \ + if (c != 0) \ + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; \ + while (i < MAX32) { STORE0; i++; } + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + +/* + * Fast quasi-reduction modulo p256 (FIPS 186-3 D.2.3) + */ +static int ecp_mod_p256(mbedtls_mpi *N) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t expected_width = BITS_TO_LIMBS(256) * 2; + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(N, expected_width)); + ret = mbedtls_ecp_mod_p256_raw(N->p, expected_width); +cleanup: + return ret; +} + +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p256_raw(mbedtls_mpi_uint *X, size_t X_limbs) +{ + if (X_limbs != BITS_TO_LIMBS(256) * 2) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + INIT(256); + + ADD(8); ADD(9); + SUB(11); SUB(12); SUB(13); SUB(14); NEXT; // A0 + + ADD(9); ADD(10); + SUB(12); SUB(13); SUB(14); SUB(15); NEXT; // A1 + + ADD(10); ADD(11); + SUB(13); SUB(14); SUB(15); NEXT; // A2 + + ADD(11); ADD(11); ADD(12); ADD(12); ADD(13); + SUB(15); SUB(8); SUB(9); NEXT; // A3 + + ADD(12); ADD(12); ADD(13); ADD(13); ADD(14); + SUB(9); SUB(10); NEXT; // A4 + + ADD(13); ADD(13); ADD(14); ADD(14); ADD(15); + SUB(10); SUB(11); NEXT; // A5 + + ADD(14); ADD(14); ADD(15); ADD(15); ADD(14); ADD(13); + SUB(8); SUB(9); NEXT; // A6 + + ADD(15); ADD(15); ADD(15); ADD(8); + SUB(10); SUB(11); SUB(12); SUB(13); // A7 + + RESET; + + /* Use 2^224 * (2^32 - 1) + 2^192 + 2^96 - 1 + * to modulo reduce the final carry. */ + ADD_LAST; NEXT; // A0 + ; NEXT; // A1 + ; NEXT; // A2 + SUB_LAST; NEXT; // A3 + ; NEXT; // A4 + ; NEXT; // A5 + SUB_LAST; NEXT; // A6 + ADD_LAST; // A7 + + RESET; + + /* Use 2^224 * (2^32 - 1) + 2^192 + 2^96 - 1 + * to modulo reduce the carry generated by the previous reduction. */ + ADD_LAST; NEXT; // A0 + ; NEXT; // A1 + ; NEXT; // A2 + SUB_LAST; NEXT; // A3 + ; NEXT; // A4 + ; NEXT; // A5 + SUB_LAST; NEXT; // A6 + ADD_LAST; // A7 + + LAST; + + return 0; +} + +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +/* + * Fast quasi-reduction modulo p384 (FIPS 186-3 D.2.4) + */ +static int ecp_mod_p384(mbedtls_mpi *N) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t expected_width = BITS_TO_LIMBS(384) * 2; + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(N, expected_width)); + ret = mbedtls_ecp_mod_p384_raw(N->p, expected_width); +cleanup: + return ret; +} + +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p384_raw(mbedtls_mpi_uint *X, size_t X_limbs) +{ + if (X_limbs != BITS_TO_LIMBS(384) * 2) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + INIT(384); + + ADD(12); ADD(21); ADD(20); + SUB(23); NEXT; // A0 + + ADD(13); ADD(22); ADD(23); + SUB(12); SUB(20); NEXT; // A1 + + ADD(14); ADD(23); + SUB(13); SUB(21); NEXT; // A2 + + ADD(15); ADD(12); ADD(20); ADD(21); + SUB(14); SUB(22); SUB(23); NEXT; // A3 + + ADD(21); ADD(21); ADD(16); ADD(13); ADD(12); ADD(20); ADD(22); + SUB(15); SUB(23); SUB(23); NEXT; // A4 + + ADD(22); ADD(22); ADD(17); ADD(14); ADD(13); ADD(21); ADD(23); + SUB(16); NEXT; // A5 + + ADD(23); ADD(23); ADD(18); ADD(15); ADD(14); ADD(22); + SUB(17); NEXT; // A6 + + ADD(19); ADD(16); ADD(15); ADD(23); + SUB(18); NEXT; // A7 + + ADD(20); ADD(17); ADD(16); + SUB(19); NEXT; // A8 + + ADD(21); ADD(18); ADD(17); + SUB(20); NEXT; // A9 + + ADD(22); ADD(19); ADD(18); + SUB(21); NEXT; // A10 + + ADD(23); ADD(20); ADD(19); + SUB(22); // A11 + + RESET; + + /* Use 2^384 = P + 2^128 + 2^96 - 2^32 + 1 to modulo reduce the final carry */ + ADD_LAST; NEXT; // A0 + SUB_LAST; NEXT; // A1 + ; NEXT; // A2 + ADD_LAST; NEXT; // A3 + ADD_LAST; NEXT; // A4 + ; NEXT; // A5 + ; NEXT; // A6 + ; NEXT; // A7 + ; NEXT; // A8 + ; NEXT; // A9 + ; NEXT; // A10 + // A11 + + RESET; + + ADD_LAST; NEXT; // A0 + SUB_LAST; NEXT; // A1 + ; NEXT; // A2 + ADD_LAST; NEXT; // A3 + ADD_LAST; NEXT; // A4 + ; NEXT; // A5 + ; NEXT; // A6 + ; NEXT; // A7 + ; NEXT; // A8 + ; NEXT; // A9 + ; NEXT; // A10 + // A11 + + LAST; + + return 0; +} +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#undef LOAD32 +#undef MAX32 +#undef A +#undef STORE32 +#undef STORE0 +#undef ADD +#undef SUB +#undef ADD_CARRY +#undef SUB_CARRY +#undef ADD_LAST +#undef SUB_LAST +#undef INIT +#undef NEXT +#undef RESET +#undef LAST + +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED || + MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +/* Size of p521 in terms of mbedtls_mpi_uint */ +#define P521_WIDTH (521 / 8 / sizeof(mbedtls_mpi_uint) + 1) + +/* Bits to keep in the most significant mbedtls_mpi_uint */ +#define P521_MASK 0x01FF + +/* + * Fast quasi-reduction modulo p521 = 2^521 - 1 (FIPS 186-3 D.2.5) + */ +static int ecp_mod_p521(mbedtls_mpi *N) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t expected_width = BITS_TO_LIMBS(521) * 2; + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(N, expected_width)); + ret = mbedtls_ecp_mod_p521_raw(N->p, expected_width); +cleanup: + return ret; +} + +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p521_raw(mbedtls_mpi_uint *X, size_t X_limbs) +{ + mbedtls_mpi_uint carry = 0; + + if (X_limbs != BITS_TO_LIMBS(521) * 2) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* Step 1: Reduction to P521_WIDTH limbs */ + /* Helper references for bottom part of X */ + mbedtls_mpi_uint *X0 = X; + size_t X0_limbs = P521_WIDTH; + /* Helper references for top part of X */ + mbedtls_mpi_uint *X1 = X + X0_limbs; + size_t X1_limbs = X_limbs - X0_limbs; + /* Split X as X0 + 2^P521_WIDTH X1 and compute X0 + 2^(biL - 9) X1. + * (We are using that 2^P521_WIDTH = 2^(512 + biL) and that + * 2^(512 + biL) X1 = 2^(biL - 9) X1 mod P521.) + * The high order limb of the result will be held in carry and the rest + * in X0 (that is the result will be represented as + * 2^P521_WIDTH carry + X0). + * + * Also, note that the resulting carry is either 0 or 1: + * X0 < 2^P521_WIDTH = 2^(512 + biL) and X1 < 2^(P521_WIDTH-biL) = 2^512 + * therefore + * X0 + 2^(biL - 9) X1 < 2^(512 + biL) + 2^(512 + biL - 9) + * which in turn is less than 2 * 2^(512 + biL). + */ + mbedtls_mpi_uint shift = ((mbedtls_mpi_uint) 1u) << (biL - 9); + carry = mbedtls_mpi_core_mla(X0, X0_limbs, X1, X1_limbs, shift); + /* Set X to X0 (by clearing the top part). */ + memset(X1, 0, X1_limbs * sizeof(mbedtls_mpi_uint)); + + /* Step 2: Reduction modulo P521 + * + * At this point X is reduced to P521_WIDTH limbs. What remains is to add + * the carry (that is 2^P521_WIDTH carry) and to reduce mod P521. */ + + /* 2^P521_WIDTH carry = 2^(512 + biL) carry = 2^(biL - 9) carry mod P521. + * Also, recall that carry is either 0 or 1. */ + mbedtls_mpi_uint addend = carry << (biL - 9); + /* Keep the top 9 bits and reduce the rest, using 2^521 = 1 mod P521. */ + addend += (X[P521_WIDTH - 1] >> 9); + X[P521_WIDTH - 1] &= P521_MASK; + + /* Reuse the top part of X (already zeroed) as a helper array for + * carrying out the addition. */ + mbedtls_mpi_uint *addend_arr = X + P521_WIDTH; + addend_arr[0] = addend; + (void) mbedtls_mpi_core_add(X, X, addend_arr, P521_WIDTH); + /* Both addends were less than P521 therefore X < 2 * P521. (This also means + * that the result fit in P521_WIDTH limbs and there won't be any carry.) */ + + /* Clear the reused part of X. */ + addend_arr[0] = 0; + + return 0; +} + +#undef P521_WIDTH +#undef P521_MASK + +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#endif /* MBEDTLS_ECP_NIST_OPTIM */ + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + +/* Size of p255 in terms of mbedtls_mpi_uint */ +#define P255_WIDTH (255 / 8 / sizeof(mbedtls_mpi_uint) + 1) + +/* + * Fast quasi-reduction modulo p255 = 2^255 - 19 + * Write N as A0 + 2^256 A1, return A0 + 38 * A1 + */ +static int ecp_mod_p255(mbedtls_mpi *N) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t expected_width = BITS_TO_LIMBS(255) * 2; + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(N, expected_width)); + ret = mbedtls_ecp_mod_p255_raw(N->p, expected_width); +cleanup: + return ret; +} + +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p255_raw(mbedtls_mpi_uint *X, size_t X_Limbs) +{ + + if (X_Limbs != BITS_TO_LIMBS(255) * 2) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + mbedtls_mpi_uint *carry = mbedtls_calloc(P255_WIDTH, ciL); + if (carry == NULL) { + return MBEDTLS_ERR_ECP_ALLOC_FAILED; + } + + /* Step 1: Reduction to P255_WIDTH limbs */ + if (X_Limbs > P255_WIDTH) { + /* Helper references for top part of X */ + mbedtls_mpi_uint * const A1 = X + P255_WIDTH; + const size_t A1_limbs = X_Limbs - P255_WIDTH; + + /* X = A0 + 38 * A1, capture carry out */ + *carry = mbedtls_mpi_core_mla(X, P255_WIDTH, A1, A1_limbs, 38); + /* Clear top part */ + memset(A1, 0, sizeof(mbedtls_mpi_uint) * A1_limbs); + } + + /* Step 2: Reduce to <2p + * Split as A0 + 2^255*c, with c a scalar, and compute A0 + 19*c */ + *carry <<= 1; + *carry += (X[P255_WIDTH - 1] >> (biL - 1)); + *carry *= 19; + + /* Clear top bit */ + X[P255_WIDTH - 1] <<= 1; X[P255_WIDTH - 1] >>= 1; + /* Since the top bit for X has been cleared 0 + 0 + Carry + * will not overflow. + * + * Furthermore for 2p = 2^256-38. When a carry propagation on the highest + * limb occurs, X > 2^255 and all the remaining bits on the limb are zero. + * - If X < 2^255 ==> X < 2p + * - If X > 2^255 ==> X < 2^256 - 2^255 < 2p */ + (void) mbedtls_mpi_core_add(X, X, carry, P255_WIDTH); + + mbedtls_free(carry); + return 0; +} +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + +/* Size of p448 in terms of mbedtls_mpi_uint */ +#define P448_WIDTH (448 / 8 / sizeof(mbedtls_mpi_uint)) + +/* Number of limbs fully occupied by 2^224 (max), and limbs used by it (min) */ +#define DIV_ROUND_UP(X, Y) (((X) + (Y) -1) / (Y)) +#define P224_SIZE (224 / 8) +#define P224_WIDTH_MIN (P224_SIZE / sizeof(mbedtls_mpi_uint)) +#define P224_WIDTH_MAX DIV_ROUND_UP(P224_SIZE, sizeof(mbedtls_mpi_uint)) +#define P224_UNUSED_BITS ((P224_WIDTH_MAX * sizeof(mbedtls_mpi_uint) * 8) - 224) + +static int ecp_mod_p448(mbedtls_mpi *N) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t expected_width = BITS_TO_LIMBS(448) * 2; + + /* This is required as some tests and use cases do not pass in a Bignum of + * the correct size, and expect the growth to be done automatically, which + * will no longer happen. */ + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(N, expected_width)); + + ret = mbedtls_ecp_mod_p448_raw(N->p, N->n); + +cleanup: + return ret; +} + +/* + * Fast quasi-reduction modulo p448 = 2^448 - 2^224 - 1 + * Write X as A0 + 2^448 A1 and A1 as B0 + 2^224 B1, and return A0 + A1 + B1 + + * (B0 + B1) * 2^224. This is different to the reference implementation of + * Curve448, which uses its own special 56-bit limbs rather than a generic + * bignum library. We could squeeze some extra speed out on 32-bit machines by + * splitting N up into 32-bit limbs and doing the arithmetic using the limbs + * directly as we do for the NIST primes above, but for 64-bit targets it should + * use half the number of operations if we do the reduction with 224-bit limbs, + * since mpi_core_add will then use 64-bit adds. + */ +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p448_raw(mbedtls_mpi_uint *X, size_t X_limbs) +{ + size_t round; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if (X_limbs != BITS_TO_LIMBS(448) * 2) { + return 0; + } + + size_t M_limbs = X_limbs - (P448_WIDTH); + + if (M_limbs > P448_WIDTH) { + /* Shouldn't be called with X larger than 2^896! */ + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* Both M and Q require an extra limb to catch carries. */ + M_limbs++; + + const size_t Q_limbs = M_limbs; + mbedtls_mpi_uint *M = NULL; + mbedtls_mpi_uint *Q = NULL; + + M = mbedtls_calloc(M_limbs, ciL); + + if (M == NULL) { + return MBEDTLS_ERR_ECP_ALLOC_FAILED; + } + + Q = mbedtls_calloc(Q_limbs, ciL); + + if (Q == NULL) { + ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; + goto cleanup; + } + + /* M = A1 */ + memset(M, 0, (M_limbs * ciL)); + /* Do not copy into the overflow limb, as this would read past the end of + * X. */ + memcpy(M, X + P448_WIDTH, ((M_limbs - 1) * ciL)); + + /* X = A0 */ + memset(X + P448_WIDTH, 0, ((M_limbs - 1) * ciL)); + + /* X = X + M = A0 + A1 */ + /* Carry here fits in oversize X. Oversize M means it will get + * added in, not returned as carry. */ + (void) mbedtls_mpi_core_add(X, X, M, M_limbs); + + /* Q = B1 = M >> 224 */ + memcpy(Q, (char *) M + P224_SIZE, P224_SIZE); + memset((char *) Q + P224_SIZE, 0, P224_SIZE); + + /* X = X + Q = (A0 + A1) + B1 + * Oversize Q catches potential carry here when X is already max 448 bits. + */ + (void) mbedtls_mpi_core_add(X, X, Q, Q_limbs); + + /* M = B0 */ +#ifdef MBEDTLS_HAVE_INT64 + M[P224_WIDTH_MIN] &= ((mbedtls_mpi_uint)-1) >> (P224_UNUSED_BITS); + #endif + memset(M + P224_WIDTH_MAX, 0, ((M_limbs - P224_WIDTH_MAX) * ciL)); + + /* M = M + Q = B0 + B1 */ + (void) mbedtls_mpi_core_add(M, M, Q, Q_limbs); + + /* M = (B0 + B1) * 2^224 */ + /* Shifted carry bit from the addition fits in oversize M. */ + memmove((char *) M + P224_SIZE, M, P224_SIZE + ciL); + memset(M, 0, P224_SIZE); + + /* X = X + M = (A0 + A1 + B1) + (B0 + B1) * 2^224 */ + (void) mbedtls_mpi_core_add(X, X, M, M_limbs); + + /* In the second and third rounds A1 and B0 have at most 1 non-zero limb and + * B1=0. + * Using this we need to calculate: + * A0 + A1 + B1 + (B0 + B1) * 2^224 = A0 + A1 + B0 * 2^224. */ + for (round = 0; round < 2; ++round) { + + /* M = A1 */ + memset(M, 0, (M_limbs * ciL)); + memcpy(M, X + P448_WIDTH, ((M_limbs - 1) * ciL)); + + /* X = A0 */ + memset(X + P448_WIDTH, 0, ((M_limbs - 1) * ciL)); + + /* M = A1 + B0 * 2^224 + * We know that only one limb of A1 will be non-zero and that it will be + * limb 0. We also know that B0 is the bottom 224 bits of A1 (which is + * then shifted up 224 bits), so, given M is currently A1 this turns + * into: + * M = M + (M << 224) + * As the single non-zero limb in B0 will be A1 limb 0 shifted up by 224 + * bits, we can just move that into the right place, shifted up + * accordingly.*/ + M[P224_WIDTH_MIN] = M[0] << (224 & (biL - 1)); + + /* X = A0 + (A1 + B0 * 2^224) */ + (void) mbedtls_mpi_core_add(X, X, M, M_limbs); + } + + ret = 0; + +cleanup: + mbedtls_free(M); + mbedtls_free(Q); + + return ret; +} +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + +/* + * Fast quasi-reduction modulo P = 2^s - R, + * with R about 33 bits, used by the Koblitz curves. + * + * Write X as A0 + 2^224 A1, return A0 + R * A1. + */ +#define P_KOBLITZ_R (8 / sizeof(mbedtls_mpi_uint)) // Limbs in R + +static inline int ecp_mod_koblitz(mbedtls_mpi_uint *X, + size_t X_limbs, + mbedtls_mpi_uint *R, + size_t bits) +{ + int ret = 0; + + /* Determine if A1 is aligned to limb bitsize. If not then the used limbs + * of P, A0 and A1 must be set accordingly and there is a middle limb + * which is shared by A0 and A1 and need to handle accordingly. + */ + size_t shift = bits % biL; + size_t adjust = (shift + biL - 1) / biL; + size_t P_limbs = bits / biL + adjust; + + mbedtls_mpi_uint *A1 = mbedtls_calloc(P_limbs, ciL); + if (A1 == NULL) { + return MBEDTLS_ERR_ECP_ALLOC_FAILED; + } + + /* Create a buffer to store the value of `R * A1` */ + size_t R_limbs = P_KOBLITZ_R; + size_t M_limbs = P_limbs + R_limbs; + mbedtls_mpi_uint *M = mbedtls_calloc(M_limbs, ciL); + if (M == NULL) { + ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; + goto cleanup; + } + + mbedtls_mpi_uint mask = 0; + if (adjust != 0) { + mask = ((mbedtls_mpi_uint) 1 << shift) - 1; + } + + /* Two passes are needed to reduce the value of `A0 + R * A1` and then + * we need an additional one to reduce the possible overflow during + * the addition. + */ + for (size_t pass = 0; pass < 3; pass++) { + /* Copy A1 */ + memcpy(A1, X + P_limbs - adjust, P_limbs * ciL); + + /* Shift A1 to be aligned */ + if (shift != 0) { + mbedtls_mpi_core_shift_r(A1, P_limbs, shift); + } + + /* Zeroize the A1 part of the shared limb */ + if (mask != 0) { + X[P_limbs - 1] &= mask; + } + + /* X = A0 + * Zeroize the A1 part of X to keep only the A0 part. + */ + for (size_t i = P_limbs; i < X_limbs; i++) { + X[i] = 0; + } + + /* X = A0 + R * A1 */ + mbedtls_mpi_core_mul(M, A1, P_limbs, R, R_limbs); + (void) mbedtls_mpi_core_add(X, X, M, P_limbs + R_limbs); + + /* Carry can not be generated since R is a 33-bit value and stored in + * 64 bits. The result value of the multiplication is at most + * P length + 33 bits in length and the result value of the addition + * is at most P length + 34 bits in length. So the result of the + * addition always fits in P length + 64 bits. + */ + } + +cleanup: + mbedtls_free(M); + mbedtls_free(A1); + + return ret; +} + +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED) */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + +/* + * Fast quasi-reduction modulo p256k1 = 2^256 - R, + * with R = 2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1 = 0x01000003D1 + */ +static int ecp_mod_p256k1(mbedtls_mpi *N) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t expected_width = BITS_TO_LIMBS(256) * 2; + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(N, expected_width)); + ret = mbedtls_ecp_mod_p256k1_raw(N->p, expected_width); + +cleanup: + return ret; +} + +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p256k1_raw(mbedtls_mpi_uint *X, size_t X_limbs) +{ + static mbedtls_mpi_uint Rp[] = { + MBEDTLS_BYTES_TO_T_UINT_8(0xD1, 0x03, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00) + }; + + if (X_limbs != BITS_TO_LIMBS(256) * 2) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + return ecp_mod_koblitz(X, X_limbs, Rp, 256); +} + +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +#if defined(MBEDTLS_TEST_HOOKS) +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_modulus_setup(mbedtls_mpi_mod_modulus *N, + const mbedtls_ecp_group_id id, + const mbedtls_ecp_modulus_type ctype) +{ + mbedtls_mpi_modp_fn modp = NULL; + mbedtls_mpi_uint *p = NULL; + size_t p_limbs; + + if (!(ctype == (mbedtls_ecp_modulus_type) MBEDTLS_ECP_MOD_COORDINATE || \ + ctype == (mbedtls_ecp_modulus_type) MBEDTLS_ECP_MOD_SCALAR)) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + switch (id) { +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + case MBEDTLS_ECP_DP_SECP256R1: + if (ctype == (mbedtls_ecp_modulus_type) MBEDTLS_ECP_MOD_COORDINATE) { +#if defined(MBEDTLS_ECP_NIST_OPTIM) + modp = &mbedtls_ecp_mod_p256_raw; +#endif + p = (mbedtls_mpi_uint *) secp256r1_p; + p_limbs = CHARS_TO_LIMBS(sizeof(secp256r1_p)); + } else { + p = (mbedtls_mpi_uint *) secp256r1_n; + p_limbs = CHARS_TO_LIMBS(sizeof(secp256r1_n)); + } + break; +#endif + +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + case MBEDTLS_ECP_DP_SECP384R1: + if (ctype == (mbedtls_ecp_modulus_type) MBEDTLS_ECP_MOD_COORDINATE) { +#if defined(MBEDTLS_ECP_NIST_OPTIM) + modp = &mbedtls_ecp_mod_p384_raw; +#endif + p = (mbedtls_mpi_uint *) secp384r1_p; + p_limbs = CHARS_TO_LIMBS(sizeof(secp384r1_p)); + } else { + p = (mbedtls_mpi_uint *) secp384r1_n; + p_limbs = CHARS_TO_LIMBS(sizeof(secp384r1_n)); + } + break; +#endif + +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + case MBEDTLS_ECP_DP_SECP521R1: + if (ctype == (mbedtls_ecp_modulus_type) MBEDTLS_ECP_MOD_COORDINATE) { +#if defined(MBEDTLS_ECP_NIST_OPTIM) + modp = &mbedtls_ecp_mod_p521_raw; +#endif + p = (mbedtls_mpi_uint *) secp521r1_p; + p_limbs = CHARS_TO_LIMBS(sizeof(secp521r1_p)); + } else { + p = (mbedtls_mpi_uint *) secp521r1_n; + p_limbs = CHARS_TO_LIMBS(sizeof(secp521r1_n)); + } + break; +#endif + +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + case MBEDTLS_ECP_DP_BP256R1: + if (ctype == (mbedtls_ecp_modulus_type) MBEDTLS_ECP_MOD_COORDINATE) { + p = (mbedtls_mpi_uint *) brainpoolP256r1_p; + p_limbs = CHARS_TO_LIMBS(sizeof(brainpoolP256r1_p)); + } else { + p = (mbedtls_mpi_uint *) brainpoolP256r1_n; + p_limbs = CHARS_TO_LIMBS(sizeof(brainpoolP256r1_n)); + } + break; +#endif + +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + case MBEDTLS_ECP_DP_BP384R1: + if (ctype == (mbedtls_ecp_modulus_type) MBEDTLS_ECP_MOD_COORDINATE) { + p = (mbedtls_mpi_uint *) brainpoolP384r1_p; + p_limbs = CHARS_TO_LIMBS(sizeof(brainpoolP384r1_p)); + } else { + p = (mbedtls_mpi_uint *) brainpoolP384r1_n; + p_limbs = CHARS_TO_LIMBS(sizeof(brainpoolP384r1_n)); + } + break; +#endif + +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + case MBEDTLS_ECP_DP_BP512R1: + if (ctype == (mbedtls_ecp_modulus_type) MBEDTLS_ECP_MOD_COORDINATE) { + p = (mbedtls_mpi_uint *) brainpoolP512r1_p; + p_limbs = CHARS_TO_LIMBS(sizeof(brainpoolP512r1_p)); + } else { + p = (mbedtls_mpi_uint *) brainpoolP512r1_n; + p_limbs = CHARS_TO_LIMBS(sizeof(brainpoolP512r1_n)); + } + break; +#endif + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + case MBEDTLS_ECP_DP_CURVE25519: + if (ctype == (mbedtls_ecp_modulus_type) MBEDTLS_ECP_MOD_COORDINATE) { + modp = &mbedtls_ecp_mod_p255_raw; + p = (mbedtls_mpi_uint *) curve25519_p; + p_limbs = CHARS_TO_LIMBS(sizeof(curve25519_p)); + } else { + p = (mbedtls_mpi_uint *) curve25519_n; + p_limbs = CHARS_TO_LIMBS(sizeof(curve25519_n)); + } + break; +#endif + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + case MBEDTLS_ECP_DP_SECP256K1: + if (ctype == (mbedtls_ecp_modulus_type) MBEDTLS_ECP_MOD_COORDINATE) { + modp = &mbedtls_ecp_mod_p256k1_raw; + p = (mbedtls_mpi_uint *) secp256k1_p; + p_limbs = CHARS_TO_LIMBS(sizeof(secp256k1_p)); + } else { + p = (mbedtls_mpi_uint *) secp256k1_n; + p_limbs = CHARS_TO_LIMBS(sizeof(secp256k1_n)); + } + break; +#endif + +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + case MBEDTLS_ECP_DP_CURVE448: + if (ctype == (mbedtls_ecp_modulus_type) MBEDTLS_ECP_MOD_COORDINATE) { + modp = &mbedtls_ecp_mod_p448_raw; + p = (mbedtls_mpi_uint *) curve448_p; + p_limbs = CHARS_TO_LIMBS(sizeof(curve448_p)); + } else { + p = (mbedtls_mpi_uint *) curve448_n; + p_limbs = CHARS_TO_LIMBS(sizeof(curve448_n)); + } + break; +#endif + + default: + case MBEDTLS_ECP_DP_NONE: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + if (modp != NULL) { + if (mbedtls_mpi_mod_optred_modulus_setup(N, p, p_limbs, modp)) { + return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + } + } else { + if (mbedtls_mpi_mod_modulus_setup(N, p, p_limbs)) { + return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + } + } + return 0; +} +#endif /* MBEDTLS_TEST_HOOKS */ + +#if defined(MBEDTLS_TEST_HOOKS) + +MBEDTLS_STATIC_TESTABLE +mbedtls_ecp_variant mbedtls_ecp_get_variant(void) +{ + return MBEDTLS_ECP_VARIANT_WITH_MPI_UINT; +} + +#endif /* MBEDTLS_TEST_HOOKS */ + +#endif /* MBEDTLS_ECP_LIGHT */ +#endif /* MBEDTLS_ECP_WITH_MPI_UINT */ diff --git a/tf-psa-crypto/drivers/builtin/src/ecp_invasive.h b/tf-psa-crypto/drivers/builtin/src/ecp_invasive.h new file mode 100644 index 0000000000..29954ba94f --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/ecp_invasive.h @@ -0,0 +1,236 @@ +/** + * \file ecp_invasive.h + * + * \brief ECP module: interfaces for invasive testing only. + * + * The interfaces in this file are intended for testing purposes only. + * They SHOULD NOT be made available in library integrations except when + * building the library for testing. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_ECP_INVASIVE_H +#define TF_PSA_CRYPTO_ECP_INVASIVE_H + +#include "tf_psa_crypto_common.h" +#include "mbedtls/private/bignum.h" +#include "bignum_mod.h" +#include "mbedtls/private/ecp.h" + +/* + * Curve modulus types + */ +typedef enum { + MBEDTLS_ECP_MOD_NONE = 0, + MBEDTLS_ECP_MOD_COORDINATE, + MBEDTLS_ECP_MOD_SCALAR +} mbedtls_ecp_modulus_type; + +typedef enum { + MBEDTLS_ECP_VARIANT_NONE = 0, + MBEDTLS_ECP_VARIANT_WITH_MPI_STRUCT, + MBEDTLS_ECP_VARIANT_WITH_MPI_UINT +} mbedtls_ecp_variant; + +#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_ECP_LIGHT) + +/** Queries the ecp variant. + * + * \return The id of the ecp variant. + */ +MBEDTLS_STATIC_TESTABLE +mbedtls_ecp_variant mbedtls_ecp_get_variant(void); + +#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) +/** Generate a private key on a Montgomery curve (Curve25519 or Curve448). + * + * This function implements key generation for the set of secret keys + * specified in [Curve25519] p. 5 and in [Curve448]. The resulting value + * has the lower bits masked but is not necessarily canonical. + * + * \note - [Curve25519] http://cr.yp.to/ecdh/curve25519-20060209.pdf + * - [RFC7748] https://tools.ietf.org/html/rfc7748 + * + * \p high_bit The position of the high-order bit of the key to generate. + * This is the bit-size of the key minus 1: + * 254 for Curve25519 or 447 for Curve448. + * \param d The randomly generated key. This is a number of size + * exactly \p high_bit + 1 bits, with the least significant bits + * masked as specified in [Curve25519] and in [RFC7748] §5. + * \param f_rng The RNG function. + * \param p_rng The RNG context to be passed to \p f_rng. + * + * \return \c 0 on success. + * \return \c MBEDTLS_ERR_ECP_xxx or MBEDTLS_ERR_MPI_xxx on failure. + */ +int mbedtls_ecp_gen_privkey_mx(size_t high_bit, + mbedtls_mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + +/** Fast quasi-reduction modulo p256 (FIPS 186-3 D.2.3) + * + * \param[in,out] X The address of the MPI to be converted. + * Must have exact limb size that stores a 512-bit MPI + * (double the bitlength of the modulus). + * Upon return holds the reduced value which is + * in range `0 <= X < 2 * N` (where N is the modulus). + * The bitlength of the reduced value is the same as + * that of the modulus (256 bits). + * \param[in] X_limbs The length of \p X in limbs. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if \p X_limbs is not the + * limb size that sores a 512-bit MPI. + */ +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p256_raw(mbedtls_mpi_uint *X, size_t X_limbs); + +#endif + +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + +/** Fast quasi-reduction modulo p521 = 2^521 - 1 (FIPS 186-3 D.2.5) + * + * \param[in,out] X The address of the MPI to be converted. + * Must have twice as many limbs as the modulus + * (the modulus is 521 bits long). Upon return this + * holds the reduced value. The reduced value is + * in range `0 <= X < 2 * N` (where N is the modulus). + * and its the bitlength is one plus the bitlength + * of the modulus. + * \param[in] X_limbs The length of \p X in limbs. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if \p X_limbs does not have + * twice as many limbs as the modulus. + */ +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p521_raw(mbedtls_mpi_uint *X, size_t X_limbs); + +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + +/** Fast quasi-reduction modulo p384 (FIPS 186-3 D.2.4) + * + * \param[in,out] X The address of the MPI to be converted. + * Must have exact limb size that stores a 768-bit MPI + * (double the bitlength of the modulus). + * Upon return holds the reduced value which is + * in range `0 <= X < 2 * N` (where N is the modulus). + * The bitlength of the reduced value is the same as + * that of the modulus (384 bits). + * \param[in] X_limbs The length of \p N in limbs. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if \p N_n does not have + * twice as many limbs as the modulus. + */ +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p384_raw(mbedtls_mpi_uint *X, size_t X_limbs); + +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + +/** Fast quasi-reduction modulo p256k1 = 2^256 - R, + * with R = 2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1 = 0x01000003D1 + * + * \param[in,out] X The address of the MPI to be converted. + * Must have exact limb size that stores a 512-bit MPI + * (double the bitlength of the modulus). + * Upon return holds the reduced value which is + * in range `0 <= X < 2 * N` (where N is the modulus). + * The bitlength of the reduced value is the same as + * that of the modulus (256 bits). + * \param[in] X_limbs The length of \p X in limbs. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if \p X does not have + * twice as many limbs as the modulus. + * \return #MBEDTLS_ERR_ECP_ALLOC_FAILED if memory allocation failed. + */ +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p256k1_raw(mbedtls_mpi_uint *X, size_t X_limbs); + +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + +/** Fast quasi-reduction modulo p255 = 2^255 - 19 + * + * \param[in,out] X The address of the MPI to be converted. + * Must have exact limb size that stores a 510-bit MPI + * (double the bitlength of the modulus). + * Upon return holds the reduced value which is + * in range `0 <= X < 2 * N` (where N is the modulus). + * \param[in] X_limbs The length of \p X in limbs. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if \p X does not have + * twice as many limbs as the modulus. + * \return #MBEDTLS_ERR_ECP_ALLOC_FAILED if memory allocation failed. + */ +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p255_raw(mbedtls_mpi_uint *X, size_t X_limbs); + +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + +/** Fast quasi-reduction modulo p448 = 2^448 - 2^224 - 1 + * Write X as A0 + 2^448 A1 and A1 as B0 + 2^224 B1, and return A0 + A1 + B1 + + * (B0 + B1) * 2^224. + * + * \param[in,out] X The address of the MPI to be converted. + * Must have exact limb size that stores a 896-bit MPI + * (double the bitlength of the modulus). Upon return + * holds the reduced value which is in range `0 <= X < + * N` (where N is the modulus). The bitlength of the + * reduced value is the same as that of the modulus + * (448 bits). + * \param[in] X_limbs The length of \p X in limbs. + * + * \return \c 0 on Success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if \p X does not have + * twice as many limbs as the modulus. + * \return #MBEDTLS_ERR_ECP_ALLOC_FAILED if memory allocation + * failed. + */ +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_mod_p448_raw(mbedtls_mpi_uint *X, size_t X_limbs); + +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ + +/** Initialise a modulus with hard-coded const curve data. + * + * \note The caller is responsible for the \p N modulus' memory. + * mbedtls_mpi_mod_modulus_free(&N) should be invoked at the + * end of its lifecycle. + * + * \param[in,out] N The address of the modulus structure to populate. + * Must be initialized. + * \param[in] id The mbedtls_ecp_group_id for which to initialise the modulus. + * \param[in] ctype The mbedtls_ecp_modulus_type identifier for a coordinate modulus (P) + * or a scalar modulus (N). + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the given MPIs do not + * have the correct number of limbs. + * + */ +MBEDTLS_STATIC_TESTABLE +int mbedtls_ecp_modulus_setup(mbedtls_mpi_mod_modulus *N, + const mbedtls_ecp_group_id id, + const mbedtls_ecp_modulus_type ctype); + +#endif /* MBEDTLS_TEST_HOOKS && MBEDTLS_ECP_C */ + +#endif /* TF_PSA_CRYPTO_ECP_INVASIVE_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/entropy.c b/tf-psa-crypto/drivers/builtin/src/entropy.c new file mode 100644 index 0000000000..cc6d1d523f --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/entropy.c @@ -0,0 +1,677 @@ +/* + * Entropy accumulator implementation + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_ENTROPY_C) + +#include "mbedtls/private/entropy.h" +#include "entropy_poll.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#include "mbedtls/platform.h" + +#define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */ + +void mbedtls_entropy_init(mbedtls_entropy_context *ctx) +{ + ctx->source_count = 0; + memset(ctx->source, 0, sizeof(ctx->source)); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init(&ctx->mutex); +#endif + + ctx->accumulator_started = 0; + mbedtls_md_init(&ctx->accumulator); + + /* Note: the list of sources here must remain consistent with the + * definitions of MBEDTLS_ENTROPY_TRUE_SOURCES in + * "tf-psa-crypto/private/crypto_adjust_config_derived.h". */ + + /* In principle, we could support both a built-in source and a custom + * source. However, it isn't a common need. So for now the two + * callback functions have the same name and there can only be one. */ +#if defined(MBEDTLS_PSA_BUILTIN_GET_ENTROPY) || defined(MBEDTLS_PSA_DRIVER_GET_ENTROPY) + mbedtls_entropy_add_source(ctx, mbedtls_entropy_poll_platform, NULL, + MBEDTLS_ENTROPY_POLL_PLATFORM_MIN, + MBEDTLS_ENTROPY_SOURCE_STRONG); +#endif +#if defined(MBEDTLS_ENTROPY_NV_SEED) + mbedtls_entropy_add_source(ctx, mbedtls_nv_seed_poll, NULL, + MBEDTLS_ENTROPY_BLOCK_SIZE, + MBEDTLS_ENTROPY_SOURCE_STRONG); + ctx->initial_entropy_run = 0; +#endif +} + +void mbedtls_entropy_free(mbedtls_entropy_context *ctx) +{ + if (ctx == NULL) { + return; + } + + /* If the context was already free, don't call free() again. + * This is important for mutexes which don't allow double-free. */ + if (ctx->accumulator_started == -1) { + return; + } + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free(&ctx->mutex); +#endif + mbedtls_md_free(&ctx->accumulator); +#if defined(MBEDTLS_ENTROPY_NV_SEED) + ctx->initial_entropy_run = 0; +#endif + ctx->source_count = 0; + mbedtls_platform_zeroize(ctx->source, sizeof(ctx->source)); + ctx->accumulator_started = -1; +} + +int mbedtls_entropy_add_source(mbedtls_entropy_context *ctx, + mbedtls_entropy_f_source_ptr f_source, void *p_source, + size_t threshold, int strong) +{ + int idx, ret = 0; + +#if defined(MBEDTLS_THREADING_C) + if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) { + return ret; + } +#endif + + idx = ctx->source_count; + if (idx >= MBEDTLS_ENTROPY_MAX_SOURCES) { + ret = MBEDTLS_ERR_ENTROPY_MAX_SOURCES; + goto exit; + } + + ctx->source[idx].f_source = f_source; + ctx->source[idx].p_source = p_source; + ctx->source[idx].threshold = threshold; + ctx->source[idx].strong = strong; + + ctx->source_count++; + +exit: +#if defined(MBEDTLS_THREADING_C) + if (mbedtls_mutex_unlock(&ctx->mutex) != 0) { + return MBEDTLS_ERR_THREADING_MUTEX_ERROR; + } +#endif + + return ret; +} + +/* + * Entropy accumulator update + */ +static int entropy_update(mbedtls_entropy_context *ctx, unsigned char source_id, + const unsigned char *data, size_t len) +{ + unsigned char header[2]; + unsigned char tmp[MBEDTLS_ENTROPY_BLOCK_SIZE]; + size_t use_len = len; + const unsigned char *p = data; + int ret = 0; + + if (use_len > MBEDTLS_ENTROPY_BLOCK_SIZE) { + if ((ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD), + data, len, tmp)) != 0) { + goto cleanup; + } + p = tmp; + use_len = MBEDTLS_ENTROPY_BLOCK_SIZE; + } + + header[0] = source_id; + header[1] = use_len & 0xFF; + + /* + * Start the accumulator if this has not already happened. Note that + * it is sufficient to start the accumulator here only because all calls to + * gather entropy eventually execute this code. + */ + if (ctx->accumulator_started == 0) { + ret = mbedtls_md_setup(&ctx->accumulator, + mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD), 0); + if (ret != 0) { + goto cleanup; + } + ret = mbedtls_md_starts(&ctx->accumulator); + if (ret != 0) { + goto cleanup; + } + ctx->accumulator_started = 1; + } + if ((ret = mbedtls_md_update(&ctx->accumulator, header, 2)) != 0) { + goto cleanup; + } + ret = mbedtls_md_update(&ctx->accumulator, p, use_len); + +cleanup: + mbedtls_platform_zeroize(tmp, sizeof(tmp)); + + return ret; +} + +int mbedtls_entropy_update_manual(mbedtls_entropy_context *ctx, + const unsigned char *data, size_t len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + +#if defined(MBEDTLS_THREADING_C) + if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) { + return ret; + } +#endif + + ret = entropy_update(ctx, MBEDTLS_ENTROPY_SOURCE_MANUAL, data, len); + +#if defined(MBEDTLS_THREADING_C) + if (mbedtls_mutex_unlock(&ctx->mutex) != 0) { + return MBEDTLS_ERR_THREADING_MUTEX_ERROR; + } +#endif + + return ret; +} + +/* + * Run through the different sources to add entropy to our accumulator + */ +static int entropy_gather_internal(mbedtls_entropy_context *ctx) +{ + int ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; + int i; + int have_one_strong = 0; + unsigned char buf[MBEDTLS_ENTROPY_MAX_GATHER]; + size_t olen; + + if (ctx->source_count == 0) { + return MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED; + } + + /* + * Run through our entropy sources + */ + for (i = 0; i < ctx->source_count; i++) { + if (ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG) { + have_one_strong = 1; + } + + olen = 0; + if ((ret = ctx->source[i].f_source(ctx->source[i].p_source, + buf, MBEDTLS_ENTROPY_MAX_GATHER, &olen)) != 0) { + goto cleanup; + } + + /* + * Add if we actually gathered something + */ + if (olen > 0) { + if ((ret = entropy_update(ctx, (unsigned char) i, + buf, olen)) != 0) { + return ret; + } + ctx->source[i].size += olen; + } + } + + if (have_one_strong == 0) { + ret = MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE; + } + +cleanup: + mbedtls_platform_zeroize(buf, sizeof(buf)); + + return ret; +} + +/* + * Thread-safe wrapper for entropy_gather_internal() + */ +int mbedtls_entropy_gather(mbedtls_entropy_context *ctx) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + +#if defined(MBEDTLS_THREADING_C) + if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) { + return ret; + } +#endif + + ret = entropy_gather_internal(ctx); + +#if defined(MBEDTLS_THREADING_C) + if (mbedtls_mutex_unlock(&ctx->mutex) != 0) { + return MBEDTLS_ERR_THREADING_MUTEX_ERROR; + } +#endif + + return ret; +} + +int mbedtls_entropy_func(void *data, unsigned char *output, size_t len) +{ + int ret, count = 0, i, thresholds_reached; + size_t strong_size; + mbedtls_entropy_context *ctx = (mbedtls_entropy_context *) data; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + + if (len > MBEDTLS_ENTROPY_BLOCK_SIZE) { + return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; + } + +#if defined(MBEDTLS_ENTROPY_NV_SEED) + /* Update the NV entropy seed before generating any entropy for outside + * use. + */ + if (ctx->initial_entropy_run == 0) { + ctx->initial_entropy_run = 1; + if ((ret = mbedtls_entropy_update_nv_seed(ctx)) != 0) { + return ret; + } + } +#endif + +#if defined(MBEDTLS_THREADING_C) + if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) { + return ret; + } +#endif + + /* + * Always gather extra entropy before a call + */ + do { + if (count++ > ENTROPY_MAX_LOOP) { + ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; + goto exit; + } + + if ((ret = entropy_gather_internal(ctx)) != 0) { + goto exit; + } + + thresholds_reached = 1; + strong_size = 0; + for (i = 0; i < ctx->source_count; i++) { + if (ctx->source[i].size < ctx->source[i].threshold) { + thresholds_reached = 0; + } + if (ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG) { + strong_size += ctx->source[i].size; + } + } + } while (!thresholds_reached || strong_size < MBEDTLS_ENTROPY_BLOCK_SIZE); + + memset(buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE); + + /* + * Note that at this stage it is assumed that the accumulator was started + * in a previous call to entropy_update(). If this is not guaranteed, the + * code below will fail. + */ + if ((ret = mbedtls_md_finish(&ctx->accumulator, buf)) != 0) { + goto exit; + } + + /* + * Reset accumulator and counters and recycle existing entropy + */ + mbedtls_md_free(&ctx->accumulator); + mbedtls_md_init(&ctx->accumulator); + ret = mbedtls_md_setup(&ctx->accumulator, + mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD), 0); + if (ret != 0) { + goto exit; + } + ret = mbedtls_md_starts(&ctx->accumulator); + if (ret != 0) { + goto exit; + } + if ((ret = mbedtls_md_update(&ctx->accumulator, buf, + MBEDTLS_ENTROPY_BLOCK_SIZE)) != 0) { + goto exit; + } + + /* + * Perform second hashing on entropy + */ + if ((ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD), + buf, MBEDTLS_ENTROPY_BLOCK_SIZE, buf)) != 0) { + goto exit; + } + + for (i = 0; i < ctx->source_count; i++) { + ctx->source[i].size = 0; + } + + memcpy(output, buf, len); + + ret = 0; + +exit: + mbedtls_platform_zeroize(buf, sizeof(buf)); + +#if defined(MBEDTLS_THREADING_C) + if (mbedtls_mutex_unlock(&ctx->mutex) != 0) { + return MBEDTLS_ERR_THREADING_MUTEX_ERROR; + } +#endif + + return ret; +} + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +int mbedtls_entropy_update_nv_seed(mbedtls_entropy_context *ctx) +{ + int ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + + /* Read new seed and write it to NV */ + if ((ret = mbedtls_entropy_func(ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE)) != 0) { + return ret; + } + + if (mbedtls_nv_seed_write(buf, MBEDTLS_ENTROPY_BLOCK_SIZE) < 0) { + return MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + } + + /* Manually update the remaining stream with a separator value to diverge */ + memset(buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE); + ret = mbedtls_entropy_update_manual(ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE); + + return ret; +} +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#if defined(MBEDTLS_FS_IO) +int mbedtls_entropy_write_seed_file(mbedtls_entropy_context *ctx, const char *path) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + FILE *f = NULL; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + + if ((ret = mbedtls_entropy_func(ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE)) != 0) { + ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; + goto exit; + } + + if ((f = fopen(path, "wb")) == NULL) { + ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + goto exit; + } + + /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ + mbedtls_setbuf(f, NULL); + + if (fwrite(buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f) != MBEDTLS_ENTROPY_BLOCK_SIZE) { + ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + goto exit; + } + + ret = 0; + +exit: + mbedtls_platform_zeroize(buf, sizeof(buf)); + + if (f != NULL) { + fclose(f); + } + + return ret; +} + +int mbedtls_entropy_update_seed_file(mbedtls_entropy_context *ctx, const char *path) +{ + int ret = 0; + FILE *f; + size_t n; + unsigned char buf[MBEDTLS_ENTROPY_MAX_SEED_SIZE]; + + if ((f = fopen(path, "rb")) == NULL) { + return MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + } + + /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ + mbedtls_setbuf(f, NULL); + + fseek(f, 0, SEEK_END); + n = (size_t) ftell(f); + fseek(f, 0, SEEK_SET); + + if (n > MBEDTLS_ENTROPY_MAX_SEED_SIZE) { + n = MBEDTLS_ENTROPY_MAX_SEED_SIZE; + } + + if (fread(buf, 1, n, f) != n) { + ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + } else { + ret = mbedtls_entropy_update_manual(ctx, buf, n); + } + + fclose(f); + + mbedtls_platform_zeroize(buf, sizeof(buf)); + + if (ret != 0) { + return ret; + } + + return mbedtls_entropy_write_seed_file(ctx, path); +} +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * Dummy source function + */ +static int entropy_dummy_source(void *data, unsigned char *output, + size_t len, size_t *olen) +{ + ((void) data); + + memset(output, 0x2a, len); + *olen = len; + + return 0; +} + +#if defined(MBEDTLS_PSA_DRIVER_GET_ENTROPY) + +static int mbedtls_entropy_source_self_test_gather(unsigned char *buf, size_t buf_len) +{ + int ret = 0; + size_t entropy_len = 0; + size_t olen = 0; + size_t attempts = buf_len; + + while (attempts > 0 && entropy_len < buf_len) { + if ((ret = mbedtls_entropy_poll_platform(NULL, buf + entropy_len, + buf_len - entropy_len, &olen)) != 0) { + return ret; + } + + entropy_len += olen; + attempts--; + } + + if (entropy_len < buf_len) { + ret = 1; + } + + return ret; +} + + +static int mbedtls_entropy_source_self_test_check_bits(const unsigned char *buf, + size_t buf_len) +{ + unsigned char set = 0xFF; + unsigned char unset = 0x00; + size_t i; + + for (i = 0; i < buf_len; i++) { + set &= buf[i]; + unset |= buf[i]; + } + + return set == 0xFF || unset == 0x00; +} + +/* + * A test to ensure that the entropy sources are functioning correctly + * and there is no obvious failure. The test performs the following checks: + * - The entropy source is not providing only 0s (all bits unset) or 1s (all + * bits set). + * - The entropy source is not providing values in a pattern. Because the + * hardware could be providing data in an arbitrary length, this check polls + * the hardware entropy source twice and compares the result to ensure they + * are not equal. + * - The error code returned by the entropy source is not an error. + */ +int mbedtls_entropy_source_self_test(int verbose) +{ + int ret = 0; + unsigned char buf0[2 * sizeof(unsigned long long int)]; + unsigned char buf1[2 * sizeof(unsigned long long int)]; + + if (verbose != 0) { + mbedtls_printf(" ENTROPY_BIAS test: "); + } + + memset(buf0, 0x00, sizeof(buf0)); + memset(buf1, 0x00, sizeof(buf1)); + + if ((ret = mbedtls_entropy_source_self_test_gather(buf0, sizeof(buf0))) != 0) { + goto cleanup; + } + if ((ret = mbedtls_entropy_source_self_test_gather(buf1, sizeof(buf1))) != 0) { + goto cleanup; + } + + /* Make sure that the returned values are not all 0 or 1 */ + if ((ret = mbedtls_entropy_source_self_test_check_bits(buf0, sizeof(buf0))) != 0) { + goto cleanup; + } + if ((ret = mbedtls_entropy_source_self_test_check_bits(buf1, sizeof(buf1))) != 0) { + goto cleanup; + } + + /* Make sure that the entropy source is not returning values in a + * pattern */ + ret = memcmp(buf0, buf1, sizeof(buf0)) == 0; + +cleanup: + if (verbose != 0) { + if (ret != 0) { + mbedtls_printf("failed\n"); + } else { + mbedtls_printf("passed\n"); + } + + mbedtls_printf("\n"); + } + + return ret != 0; +} + +#endif /* MBEDTLS_PSA_DRIVER_GET_ENTROPY */ + +/* + * The actual entropy quality is hard to test, but we can at least + * test that the functions don't cause errors and write the correct + * amount of data to buffers. + */ +int mbedtls_entropy_self_test(int verbose) +{ + int ret = 1; + mbedtls_entropy_context ctx; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; + unsigned char acc[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; + size_t i, j; + + if (verbose != 0) { + mbedtls_printf(" ENTROPY test: "); + } + + mbedtls_entropy_init(&ctx); + + /* First do a gather to make sure we have default sources */ + if ((ret = mbedtls_entropy_gather(&ctx)) != 0) { + goto cleanup; + } + + ret = mbedtls_entropy_add_source(&ctx, entropy_dummy_source, NULL, 16, + MBEDTLS_ENTROPY_SOURCE_WEAK); + if (ret != 0) { + goto cleanup; + } + + if ((ret = mbedtls_entropy_update_manual(&ctx, buf, sizeof(buf))) != 0) { + goto cleanup; + } + + /* + * To test that mbedtls_entropy_func writes correct number of bytes: + * - use the whole buffer and rely on ASan to detect overruns + * - collect entropy 8 times and OR the result in an accumulator: + * any byte should then be 0 with probably 2^(-64), so requiring + * each of the 32 or 64 bytes to be non-zero has a false failure rate + * of at most 2^(-58) which is acceptable. + */ + for (i = 0; i < 8; i++) { + if ((ret = mbedtls_entropy_func(&ctx, buf, sizeof(buf))) != 0) { + goto cleanup; + } + + for (j = 0; j < sizeof(buf); j++) { + acc[j] |= buf[j]; + } + } + + for (j = 0; j < sizeof(buf); j++) { + if (acc[j] == 0) { + ret = 1; + goto cleanup; + } + } + +#if defined(MBEDTLS_PSA_DRIVER_GET_ENTROPY) + if ((ret = mbedtls_entropy_source_self_test(0)) != 0) { + goto cleanup; + } +#endif + +cleanup: + mbedtls_entropy_free(&ctx); + + if (verbose != 0) { + if (ret != 0) { + mbedtls_printf("failed\n"); + } else { + mbedtls_printf("passed\n"); + } + + mbedtls_printf("\n"); + } + + return ret != 0; +} +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ENTROPY_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/entropy_poll.c b/tf-psa-crypto/drivers/builtin/src/entropy_poll.c new file mode 100644 index 0000000000..df26c3e079 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/entropy_poll.c @@ -0,0 +1,89 @@ +/* + * Platform-specific and custom entropy polling functions + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#include + +#if defined(MBEDTLS_ENTROPY_C) + +#include "mbedtls/platform.h" +#include "mbedtls/private/entropy.h" +#include "entropy_poll.h" +#include "mbedtls/private/error_common.h" +#include "mbedtls/private/error_common.h" +#include + +/* In principle, we could support both a built-in source and a custom + * source. However, it isn't a common need. So for now the two + * callback functions have the same name and there can only be one. */ +#if defined(MBEDTLS_PSA_BUILTIN_GET_ENTROPY) || defined(MBEDTLS_PSA_DRIVER_GET_ENTROPY) + +/* We currently only support a single "true" entropy source (other than the + * "fake" source which is the NV seed). It can be either the built-in one + * or a user-provided callback. */ +#if defined(MBEDTLS_PSA_DRIVER_GET_ENTROPY) && defined(MBEDTLS_PSA_BUILTIN_GET_ENTROPY) +#error "MBEDTLS_PSA_DRIVER_GET_ENTROPY and MBEDTLS_PSA_BUILTIN_GET_ENTROPY " \ + "are currently incompatible." +#endif + +int mbedtls_entropy_poll_platform(void *data, unsigned char *output, size_t len, size_t *olen) +{ + int ret; + size_t estimate_bits = 0; + (void) data; + + /* Historically, in PolarSSL and Mbed TLS, the entropy callback provided + * full-entropy output, and reported how many bytes in the output buffer + * had useful data. Reporting the length was not very useful because + * we get the same amount of entropy by processing the whole output bufer, + * processing the whole buffer barely costs more CPU time since the buffer + * is small, and most entropy sources just fill the whole buffer anyway. + * So since TF-PSA-Crypto 1.0, we process the whole buffer. + */ + *olen = len; + + ret = mbedtls_platform_get_entropy(PSA_DRIVER_GET_ENTROPY_FLAGS_NONE, + &estimate_bits, output, len); + if (ret != 0) { + return ret; + } + + if (estimate_bits < (8 * len)) { + return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; + } + + return 0; +} +#endif /* MBEDTLS_PSA_BUILTIN_GET_ENTROPY || MBEDTLS_PSA_DRIVER_GET_ENTROPY */ + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +int mbedtls_nv_seed_poll(void *data, + unsigned char *output, size_t len, size_t *olen) +{ + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + size_t use_len = MBEDTLS_ENTROPY_BLOCK_SIZE; + ((void) data); + + memset(buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE); + + if (mbedtls_nv_seed_read(buf, MBEDTLS_ENTROPY_BLOCK_SIZE) < 0) { + return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; + } + + if (len < use_len) { + use_len = len; + } + + memcpy(output, buf, use_len); + *olen = use_len; + + return 0; +} +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#endif /* MBEDTLS_ENTROPY_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/entropy_poll.h b/tf-psa-crypto/drivers/builtin/src/entropy_poll.h new file mode 100644 index 0000000000..7462db6607 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/entropy_poll.h @@ -0,0 +1,44 @@ +/** + * \file entropy_poll.h + * + * \brief Platform-specific and custom entropy polling functions + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_ENTROPY_POLL_H +#define TF_PSA_CRYPTO_ENTROPY_POLL_H + +#include "tf-psa-crypto/build_info.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MBEDTLS_ENTROPY_POLL_PLATFORM_MIN 32 + +/** + * This function is either provided by the library + * (if #MBEDTLS_PSA_BUILTIN_GET_ENTROPY is enabled) + * or provided externally (if #MBEDTLS_PSA_DRIVER_GET_ENTROPY is enabled). + */ +int mbedtls_entropy_poll_platform(void *data, unsigned char *output, size_t len, size_t *olen); + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +/** + * \brief Entropy poll callback for a non-volatile seed file + * + * \note This must accept NULL as its first argument. + */ +int mbedtls_nv_seed_poll(void *data, + unsigned char *output, size_t len, size_t *olen); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_ENTROPY_POLL_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/gcm.c b/tf-psa-crypto/drivers/builtin/src/gcm.c new file mode 100644 index 0000000000..b9412a7b6d --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/gcm.c @@ -0,0 +1,1314 @@ +/* + * NIST SP800-38D compliant GCM implementation + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +/* + * http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf + * + * See also: + * [MGV] http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf + * + * We use the algorithm described as Shoup's method with 4-bit tables in + * [MGV] 4.1, pp. 12-13, to enhance speed without using too much memory. + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_GCM_C) + +#include "mbedtls/private/gcm.h" +#include "mbedtls/platform.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" +#include "mbedtls/constant_time.h" + +#if defined(MBEDTLS_BLOCK_CIPHER_C) +#include "block_cipher_internal.h" +#endif + +#include + +#if defined(MBEDTLS_AESNI_C) +#include "aesni.h" +#endif + +#if defined(MBEDTLS_AESCE_C) +#include "aesce.h" +#endif + +/* Used to select the acceleration mechanism */ +#define MBEDTLS_GCM_ACC_SMALLTABLE 0 +#define MBEDTLS_GCM_ACC_LARGETABLE 1 +#define MBEDTLS_GCM_ACC_AESNI 2 +#define MBEDTLS_GCM_ACC_AESCE 3 + +/* + * Initialize a context + */ +void mbedtls_gcm_init(mbedtls_gcm_context *ctx) +{ + memset(ctx, 0, sizeof(mbedtls_gcm_context)); +} + +static inline void gcm_set_acceleration(mbedtls_gcm_context *ctx) +{ +#if defined(MBEDTLS_GCM_LARGE_TABLE) + ctx->acceleration = MBEDTLS_GCM_ACC_LARGETABLE; +#else + ctx->acceleration = MBEDTLS_GCM_ACC_SMALLTABLE; +#endif + +#if defined(MBEDTLS_AESNI_HAVE_CODE) + /* With CLMUL support, we need only h, not the rest of the table */ + if (mbedtls_aesni_has_support(MBEDTLS_AESNI_CLMUL)) { + ctx->acceleration = MBEDTLS_GCM_ACC_AESNI; + } +#endif + +#if defined(MBEDTLS_AESCE_HAVE_CODE) + if (MBEDTLS_AESCE_HAS_SUPPORT()) { + ctx->acceleration = MBEDTLS_GCM_ACC_AESCE; + } +#endif +} + +static inline void gcm_gen_table_rightshift(uint64_t dst[2], const uint64_t src[2]) +{ + uint8_t *u8Dst = (uint8_t *) dst; + uint8_t *u8Src = (uint8_t *) src; + + MBEDTLS_PUT_UINT64_BE(MBEDTLS_GET_UINT64_BE(&src[1], 0) >> 1, &dst[1], 0); + u8Dst[8] |= (u8Src[7] & 0x01) << 7; + MBEDTLS_PUT_UINT64_BE(MBEDTLS_GET_UINT64_BE(&src[0], 0) >> 1, &dst[0], 0); + u8Dst[0] ^= (u8Src[15] & 0x01) ? 0xE1 : 0; +} + +/* + * Precompute small multiples of H, that is set + * HH[i] || HL[i] = H times i, + * where i is seen as a field element as in [MGV], ie high-order bits + * correspond to low powers of P. The result is stored in the same way, that + * is the high-order bit of HH corresponds to P^0 and the low-order bit of HL + * corresponds to P^127. + */ +static int gcm_gen_table(mbedtls_gcm_context *ctx) +{ + int ret, i, j; + uint64_t u64h[2] = { 0 }; + uint8_t *h = (uint8_t *) u64h; + +#if defined(MBEDTLS_BLOCK_CIPHER_C) + ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, h, h); +#else + size_t olen = 0; + ret = mbedtls_cipher_update(&ctx->cipher_ctx, h, 16, h, &olen); +#endif + if (ret != 0) { + return ret; + } + + gcm_set_acceleration(ctx); + + /* MBEDTLS_GCM_HTABLE_SIZE/2 = 1000 corresponds to 1 in GF(2^128) */ + ctx->H[MBEDTLS_GCM_HTABLE_SIZE/2][0] = u64h[0]; + ctx->H[MBEDTLS_GCM_HTABLE_SIZE/2][1] = u64h[1]; + + switch (ctx->acceleration) { +#if defined(MBEDTLS_AESNI_HAVE_CODE) + case MBEDTLS_GCM_ACC_AESNI: + return 0; +#endif + +#if defined(MBEDTLS_AESCE_HAVE_CODE) + case MBEDTLS_GCM_ACC_AESCE: + return 0; +#endif + + default: + /* 0 corresponds to 0 in GF(2^128) */ + ctx->H[0][0] = 0; + ctx->H[0][1] = 0; + + for (i = MBEDTLS_GCM_HTABLE_SIZE/4; i > 0; i >>= 1) { + gcm_gen_table_rightshift(ctx->H[i], ctx->H[i*2]); + } + +#if !defined(MBEDTLS_GCM_LARGE_TABLE) + /* pack elements of H as 64-bits ints, big-endian */ + for (i = MBEDTLS_GCM_HTABLE_SIZE/2; i > 0; i >>= 1) { + MBEDTLS_PUT_UINT64_BE(ctx->H[i][0], &ctx->H[i][0], 0); + MBEDTLS_PUT_UINT64_BE(ctx->H[i][1], &ctx->H[i][1], 0); + } +#endif + + for (i = 2; i < MBEDTLS_GCM_HTABLE_SIZE; i <<= 1) { + for (j = 1; j < i; j++) { + mbedtls_xor_no_simd((unsigned char *) ctx->H[i+j], + (unsigned char *) ctx->H[i], + (unsigned char *) ctx->H[j], + 16); + } + } + } + + return 0; +} + +int mbedtls_gcm_setkey(mbedtls_gcm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if (keybits != 128 && keybits != 192 && keybits != 256) { + return MBEDTLS_ERR_GCM_BAD_INPUT; + } + +#if defined(MBEDTLS_BLOCK_CIPHER_C) + mbedtls_block_cipher_free(&ctx->block_cipher_ctx); + + if ((ret = mbedtls_block_cipher_setup(&ctx->block_cipher_ctx, cipher)) != 0) { + return ret; + } + + if ((ret = mbedtls_block_cipher_setkey(&ctx->block_cipher_ctx, key, keybits)) != 0) { + return ret; + } +#else + const mbedtls_cipher_info_t *cipher_info; + + cipher_info = mbedtls_cipher_info_from_values(cipher, keybits, + MBEDTLS_MODE_ECB); + if (cipher_info == NULL) { + return MBEDTLS_ERR_GCM_BAD_INPUT; + } + + if (mbedtls_cipher_info_get_block_size(cipher_info) != 16) { + return MBEDTLS_ERR_GCM_BAD_INPUT; + } + + mbedtls_cipher_free(&ctx->cipher_ctx); + + if ((ret = mbedtls_cipher_setup(&ctx->cipher_ctx, cipher_info)) != 0) { + return ret; + } + + if ((ret = mbedtls_cipher_setkey(&ctx->cipher_ctx, key, keybits, + MBEDTLS_ENCRYPT)) != 0) { + return ret; + } +#endif + + if ((ret = gcm_gen_table(ctx)) != 0) { + return ret; + } + + return 0; +} + +#if defined(MBEDTLS_GCM_LARGE_TABLE) +static const uint16_t last8[256] = { + 0x0000, 0xc201, 0x8403, 0x4602, 0x0807, 0xca06, 0x8c04, 0x4e05, + 0x100e, 0xd20f, 0x940d, 0x560c, 0x1809, 0xda08, 0x9c0a, 0x5e0b, + 0x201c, 0xe21d, 0xa41f, 0x661e, 0x281b, 0xea1a, 0xac18, 0x6e19, + 0x3012, 0xf213, 0xb411, 0x7610, 0x3815, 0xfa14, 0xbc16, 0x7e17, + 0x4038, 0x8239, 0xc43b, 0x063a, 0x483f, 0x8a3e, 0xcc3c, 0x0e3d, + 0x5036, 0x9237, 0xd435, 0x1634, 0x5831, 0x9a30, 0xdc32, 0x1e33, + 0x6024, 0xa225, 0xe427, 0x2626, 0x6823, 0xaa22, 0xec20, 0x2e21, + 0x702a, 0xb22b, 0xf429, 0x3628, 0x782d, 0xba2c, 0xfc2e, 0x3e2f, + 0x8070, 0x4271, 0x0473, 0xc672, 0x8877, 0x4a76, 0x0c74, 0xce75, + 0x907e, 0x527f, 0x147d, 0xd67c, 0x9879, 0x5a78, 0x1c7a, 0xde7b, + 0xa06c, 0x626d, 0x246f, 0xe66e, 0xa86b, 0x6a6a, 0x2c68, 0xee69, + 0xb062, 0x7263, 0x3461, 0xf660, 0xb865, 0x7a64, 0x3c66, 0xfe67, + 0xc048, 0x0249, 0x444b, 0x864a, 0xc84f, 0x0a4e, 0x4c4c, 0x8e4d, + 0xd046, 0x1247, 0x5445, 0x9644, 0xd841, 0x1a40, 0x5c42, 0x9e43, + 0xe054, 0x2255, 0x6457, 0xa656, 0xe853, 0x2a52, 0x6c50, 0xae51, + 0xf05a, 0x325b, 0x7459, 0xb658, 0xf85d, 0x3a5c, 0x7c5e, 0xbe5f, + 0x00e1, 0xc2e0, 0x84e2, 0x46e3, 0x08e6, 0xcae7, 0x8ce5, 0x4ee4, + 0x10ef, 0xd2ee, 0x94ec, 0x56ed, 0x18e8, 0xdae9, 0x9ceb, 0x5eea, + 0x20fd, 0xe2fc, 0xa4fe, 0x66ff, 0x28fa, 0xeafb, 0xacf9, 0x6ef8, + 0x30f3, 0xf2f2, 0xb4f0, 0x76f1, 0x38f4, 0xfaf5, 0xbcf7, 0x7ef6, + 0x40d9, 0x82d8, 0xc4da, 0x06db, 0x48de, 0x8adf, 0xccdd, 0x0edc, + 0x50d7, 0x92d6, 0xd4d4, 0x16d5, 0x58d0, 0x9ad1, 0xdcd3, 0x1ed2, + 0x60c5, 0xa2c4, 0xe4c6, 0x26c7, 0x68c2, 0xaac3, 0xecc1, 0x2ec0, + 0x70cb, 0xb2ca, 0xf4c8, 0x36c9, 0x78cc, 0xbacd, 0xfccf, 0x3ece, + 0x8091, 0x4290, 0x0492, 0xc693, 0x8896, 0x4a97, 0x0c95, 0xce94, + 0x909f, 0x529e, 0x149c, 0xd69d, 0x9898, 0x5a99, 0x1c9b, 0xde9a, + 0xa08d, 0x628c, 0x248e, 0xe68f, 0xa88a, 0x6a8b, 0x2c89, 0xee88, + 0xb083, 0x7282, 0x3480, 0xf681, 0xb884, 0x7a85, 0x3c87, 0xfe86, + 0xc0a9, 0x02a8, 0x44aa, 0x86ab, 0xc8ae, 0x0aaf, 0x4cad, 0x8eac, + 0xd0a7, 0x12a6, 0x54a4, 0x96a5, 0xd8a0, 0x1aa1, 0x5ca3, 0x9ea2, + 0xe0b5, 0x22b4, 0x64b6, 0xa6b7, 0xe8b2, 0x2ab3, 0x6cb1, 0xaeb0, + 0xf0bb, 0x32ba, 0x74b8, 0xb6b9, 0xf8bc, 0x3abd, 0x7cbf, 0xbebe +}; + +static void gcm_mult_largetable(uint8_t *output, const uint8_t *x, uint64_t H[256][2]) +{ + int i; + uint64_t u64z[2]; + uint16_t *u16z = (uint16_t *) u64z; + uint8_t *u8z = (uint8_t *) u64z; + uint8_t rem; + + u64z[0] = 0; + u64z[1] = 0; + + if (MBEDTLS_IS_BIG_ENDIAN) { + for (i = 15; i > 0; i--) { + mbedtls_xor_no_simd(u8z, u8z, (uint8_t *) H[x[i]], 16); + rem = u8z[15]; + + u64z[1] >>= 8; + u8z[8] = u8z[7]; + u64z[0] >>= 8; + + u16z[0] ^= MBEDTLS_GET_UINT16_LE(&last8[rem], 0); + } + } else { + for (i = 15; i > 0; i--) { + mbedtls_xor_no_simd(u8z, u8z, (uint8_t *) H[x[i]], 16); + rem = u8z[15]; + + u64z[1] <<= 8; + u8z[8] = u8z[7]; + u64z[0] <<= 8; + + u16z[0] ^= last8[rem]; + } + } + + mbedtls_xor_no_simd(output, u8z, (uint8_t *) H[x[0]], 16); +} +#else +/* + * Shoup's method for multiplication use this table with + * last4[x] = x times P^128 + * where x and last4[x] are seen as elements of GF(2^128) as in [MGV] + */ +static const uint16_t last4[16] = +{ + 0x0000, 0x1c20, 0x3840, 0x2460, + 0x7080, 0x6ca0, 0x48c0, 0x54e0, + 0xe100, 0xfd20, 0xd940, 0xc560, + 0x9180, 0x8da0, 0xa9c0, 0xb5e0 +}; + +static void gcm_mult_smalltable(uint8_t *output, const uint8_t *x, uint64_t H[16][2]) +{ + int i = 0; + unsigned char lo, hi, rem; + uint64_t u64z[2]; + const uint64_t *pu64z = NULL; + uint8_t *u8z = (uint8_t *) u64z; + + lo = x[15] & 0xf; + hi = (x[15] >> 4) & 0xf; + + pu64z = H[lo]; + + rem = (unsigned char) pu64z[1] & 0xf; + u64z[1] = (pu64z[0] << 60) | (pu64z[1] >> 4); + u64z[0] = (pu64z[0] >> 4); + u64z[0] ^= (uint64_t) last4[rem] << 48; + mbedtls_xor_no_simd(u8z, u8z, (uint8_t *) H[hi], 16); + + for (i = 14; i >= 0; i--) { + lo = x[i] & 0xf; + hi = (x[i] >> 4) & 0xf; + + rem = (unsigned char) u64z[1] & 0xf; + u64z[1] = (u64z[0] << 60) | (u64z[1] >> 4); + u64z[0] = (u64z[0] >> 4); + u64z[0] ^= (uint64_t) last4[rem] << 48; + mbedtls_xor_no_simd(u8z, u8z, (uint8_t *) H[lo], 16); + + rem = (unsigned char) u64z[1] & 0xf; + u64z[1] = (u64z[0] << 60) | (u64z[1] >> 4); + u64z[0] = (u64z[0] >> 4); + u64z[0] ^= (uint64_t) last4[rem] << 48; + mbedtls_xor_no_simd(u8z, u8z, (uint8_t *) H[hi], 16); + } + + MBEDTLS_PUT_UINT64_BE(u64z[0], output, 0); + MBEDTLS_PUT_UINT64_BE(u64z[1], output, 8); +} +#endif + +/* + * Sets output to x times H using the precomputed tables. + * x and output are seen as elements of GF(2^128) as in [MGV]. + */ +static void gcm_mult(mbedtls_gcm_context *ctx, const unsigned char x[16], + unsigned char output[16]) +{ + switch (ctx->acceleration) { +#if defined(MBEDTLS_AESNI_HAVE_CODE) + case MBEDTLS_GCM_ACC_AESNI: + mbedtls_aesni_gcm_mult(output, x, (uint8_t *) ctx->H[MBEDTLS_GCM_HTABLE_SIZE/2]); + break; +#endif + +#if defined(MBEDTLS_AESCE_HAVE_CODE) + case MBEDTLS_GCM_ACC_AESCE: + mbedtls_aesce_gcm_mult(output, x, (uint8_t *) ctx->H[MBEDTLS_GCM_HTABLE_SIZE/2]); + break; +#endif + +#if defined(MBEDTLS_GCM_LARGE_TABLE) + case MBEDTLS_GCM_ACC_LARGETABLE: + gcm_mult_largetable(output, x, ctx->H); + break; +#else + case MBEDTLS_GCM_ACC_SMALLTABLE: + gcm_mult_smalltable(output, x, ctx->H); + break; +#endif + } + + return; +} + +int mbedtls_gcm_starts(mbedtls_gcm_context *ctx, + int mode, + const unsigned char *iv, size_t iv_len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char work_buf[16]; + const unsigned char *p; + size_t use_len; + uint64_t iv_bits; +#if !defined(MBEDTLS_BLOCK_CIPHER_C) + size_t olen = 0; +#endif + + /* IV is limited to 2^64 bits, so 2^61 bytes */ + /* IV is not allowed to be zero length */ + if (iv_len == 0 || (uint64_t) iv_len >> 61 != 0) { + return MBEDTLS_ERR_GCM_BAD_INPUT; + } + + memset(ctx->y, 0x00, sizeof(ctx->y)); + memset(ctx->buf, 0x00, sizeof(ctx->buf)); + + ctx->mode = mode; + ctx->len = 0; + ctx->add_len = 0; + + if (iv_len == 12) { + memcpy(ctx->y, iv, iv_len); + ctx->y[15] = 1; + } else { + memset(work_buf, 0x00, 16); + iv_bits = (uint64_t) iv_len * 8; + MBEDTLS_PUT_UINT64_BE(iv_bits, work_buf, 8); + + p = iv; + while (iv_len > 0) { + use_len = (iv_len < 16) ? iv_len : 16; + +#if defined(MBEDTLS_COMPILER_IS_GCC) && (MBEDTLS_GCC_VERSION >= 70110) +#pragma GCC diagnostic push +#pragma GCC diagnostic warning "-Wstringop-overflow=0" +#endif + + mbedtls_xor(ctx->y, ctx->y, p, use_len); + +#if defined(MBEDTLS_COMPILER_IS_GCC) && (MBEDTLS_GCC_VERSION >= 70110) +#pragma GCC diagnostic pop +#endif + + gcm_mult(ctx, ctx->y, ctx->y); + + iv_len -= use_len; + p += use_len; + } + + mbedtls_xor(ctx->y, ctx->y, work_buf, 16); + + gcm_mult(ctx, ctx->y, ctx->y); + } + + +#if defined(MBEDTLS_BLOCK_CIPHER_C) + ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->base_ectr); +#else + ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->base_ectr, &olen); +#endif + if (ret != 0) { + return ret; + } + + return 0; +} + +/** + * mbedtls_gcm_context::buf contains the partial state of the computation of + * the authentication tag. + * mbedtls_gcm_context::add_len and mbedtls_gcm_context::len indicate + * different stages of the computation: + * * len == 0 && add_len == 0: initial state + * * len == 0 && add_len % 16 != 0: the first `add_len % 16` bytes have + * a partial block of AD that has been + * xored in but not yet multiplied in. + * * len == 0 && add_len % 16 == 0: the authentication tag is correct if + * the data ends now. + * * len % 16 != 0: the first `len % 16` bytes have + * a partial block of ciphertext that has + * been xored in but not yet multiplied in. + * * len > 0 && len % 16 == 0: the authentication tag is correct if + * the data ends now. + */ +int mbedtls_gcm_update_ad(mbedtls_gcm_context *ctx, + const unsigned char *add, size_t add_len) +{ + const unsigned char *p; + size_t use_len, offset; + uint64_t new_add_len; + + /* AD is limited to 2^64 bits, ie 2^61 bytes + * Also check for possible overflow */ +#if SIZE_MAX > 0xFFFFFFFFFFFFFFFFULL + if (add_len > 0xFFFFFFFFFFFFFFFFULL) { + return MBEDTLS_ERR_GCM_BAD_INPUT; + } +#endif + new_add_len = ctx->add_len + (uint64_t) add_len; + if (new_add_len < ctx->add_len || new_add_len >> 61 != 0) { + return MBEDTLS_ERR_GCM_BAD_INPUT; + } + + offset = ctx->add_len % 16; + p = add; + + if (offset != 0) { + use_len = 16 - offset; + if (use_len > add_len) { + use_len = add_len; + } + + mbedtls_xor(ctx->buf + offset, ctx->buf + offset, p, use_len); + + if (offset + use_len == 16) { + gcm_mult(ctx, ctx->buf, ctx->buf); + } + + ctx->add_len += use_len; + add_len -= use_len; + p += use_len; + } + + ctx->add_len += add_len; + + while (add_len >= 16) { + mbedtls_xor(ctx->buf, ctx->buf, p, 16); + + gcm_mult(ctx, ctx->buf, ctx->buf); + + add_len -= 16; + p += 16; + } + + if (add_len > 0) { + mbedtls_xor(ctx->buf, ctx->buf, p, add_len); + } + + return 0; +} + +/* Increment the counter. */ +static void gcm_incr(unsigned char y[16]) +{ + uint32_t x = MBEDTLS_GET_UINT32_BE(y, 12); + x++; + MBEDTLS_PUT_UINT32_BE(x, y, 12); +} + +/* Calculate and apply the encryption mask. Process use_len bytes of data, + * starting at position offset in the mask block. */ +static int gcm_mask(mbedtls_gcm_context *ctx, + unsigned char ectr[16], + size_t offset, size_t use_len, + const unsigned char *input, + unsigned char *output) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + +#if defined(MBEDTLS_BLOCK_CIPHER_C) + ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ectr); +#else + size_t olen = 0; + ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ectr, &olen); +#endif + if (ret != 0) { + mbedtls_platform_zeroize(ectr, 16); + return ret; + } + + if (ctx->mode == MBEDTLS_GCM_DECRYPT) { + mbedtls_xor(ctx->buf + offset, ctx->buf + offset, input, use_len); + } + mbedtls_xor(output, ectr + offset, input, use_len); + if (ctx->mode == MBEDTLS_GCM_ENCRYPT) { + mbedtls_xor(ctx->buf + offset, ctx->buf + offset, output, use_len); + } + + return 0; +} + +int mbedtls_gcm_update(mbedtls_gcm_context *ctx, + const unsigned char *input, size_t input_length, + unsigned char *output, size_t output_size, + size_t *output_length) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + const unsigned char *p = input; + unsigned char *out_p = output; + size_t offset; + unsigned char ectr[16] = { 0 }; + + if (output_size < input_length) { + return MBEDTLS_ERR_GCM_BUFFER_TOO_SMALL; + } + *output_length = input_length; + + /* Exit early if input_length==0 so that we don't do any pointer arithmetic + * on a potentially null pointer. + * Returning early also means that the last partial block of AD remains + * untouched for mbedtls_gcm_finish */ + if (input_length == 0) { + return 0; + } + + if (output > input && (size_t) (output - input) < input_length) { + return MBEDTLS_ERR_GCM_BAD_INPUT; + } + + /* Total length is restricted to 2^39 - 256 bits, ie 2^36 - 2^5 bytes + * Also check for possible overflow */ + if (ctx->len + input_length < ctx->len || + (uint64_t) ctx->len + input_length > 0xFFFFFFFE0ull) { + return MBEDTLS_ERR_GCM_BAD_INPUT; + } + + if (ctx->len == 0 && ctx->add_len % 16 != 0) { + gcm_mult(ctx, ctx->buf, ctx->buf); + } + + offset = ctx->len % 16; + if (offset != 0) { + size_t use_len = 16 - offset; + if (use_len > input_length) { + use_len = input_length; + } + + if ((ret = gcm_mask(ctx, ectr, offset, use_len, p, out_p)) != 0) { + return ret; + } + + if (offset + use_len == 16) { + gcm_mult(ctx, ctx->buf, ctx->buf); + } + + ctx->len += use_len; + input_length -= use_len; + p += use_len; + out_p += use_len; + } + + ctx->len += input_length; + + while (input_length >= 16) { + gcm_incr(ctx->y); + if ((ret = gcm_mask(ctx, ectr, 0, 16, p, out_p)) != 0) { + return ret; + } + + gcm_mult(ctx, ctx->buf, ctx->buf); + + input_length -= 16; + p += 16; + out_p += 16; + } + + if (input_length > 0) { + gcm_incr(ctx->y); + if ((ret = gcm_mask(ctx, ectr, 0, input_length, p, out_p)) != 0) { + return ret; + } + } + + mbedtls_platform_zeroize(ectr, sizeof(ectr)); + return 0; +} + +int mbedtls_gcm_finish(mbedtls_gcm_context *ctx, + unsigned char *output, size_t output_size, + size_t *output_length, + unsigned char *tag, size_t tag_len) +{ + unsigned char work_buf[16]; + uint64_t orig_len; + uint64_t orig_add_len; + + /* We never pass any output in finish(). The output parameter exists only + * for the sake of alternative implementations. */ + (void) output; + (void) output_size; + *output_length = 0; + + /* Total length is restricted to 2^39 - 256 bits, ie 2^36 - 2^5 bytes + * and AD length is restricted to 2^64 bits, ie 2^61 bytes so neither of + * the two multiplications would overflow. */ + orig_len = ctx->len * 8; + orig_add_len = ctx->add_len * 8; + + if (ctx->len == 0 && ctx->add_len % 16 != 0) { + gcm_mult(ctx, ctx->buf, ctx->buf); + } + + if (tag_len > 16 || tag_len < 4) { + return MBEDTLS_ERR_GCM_BAD_INPUT; + } + + if (ctx->len % 16 != 0) { + gcm_mult(ctx, ctx->buf, ctx->buf); + } + + memcpy(tag, ctx->base_ectr, tag_len); + + if (orig_len || orig_add_len) { + memset(work_buf, 0x00, 16); + + MBEDTLS_PUT_UINT32_BE((orig_add_len >> 32), work_buf, 0); + MBEDTLS_PUT_UINT32_BE((orig_add_len), work_buf, 4); + MBEDTLS_PUT_UINT32_BE((orig_len >> 32), work_buf, 8); + MBEDTLS_PUT_UINT32_BE((orig_len), work_buf, 12); + + mbedtls_xor(ctx->buf, ctx->buf, work_buf, 16); + + gcm_mult(ctx, ctx->buf, ctx->buf); + + mbedtls_xor(tag, tag, ctx->buf, tag_len); + } + + return 0; +} + +int mbedtls_gcm_crypt_and_tag(mbedtls_gcm_context *ctx, + int mode, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *input, + unsigned char *output, + size_t tag_len, + unsigned char *tag) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t olen; + + if ((ret = mbedtls_gcm_starts(ctx, mode, iv, iv_len)) != 0) { + return ret; + } + + if ((ret = mbedtls_gcm_update_ad(ctx, add, add_len)) != 0) { + return ret; + } + + if ((ret = mbedtls_gcm_update(ctx, input, length, + output, length, &olen)) != 0) { + return ret; + } + + if ((ret = mbedtls_gcm_finish(ctx, NULL, 0, &olen, tag, tag_len)) != 0) { + return ret; + } + + return 0; +} + +int mbedtls_gcm_auth_decrypt(mbedtls_gcm_context *ctx, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *tag, + size_t tag_len, + const unsigned char *input, + unsigned char *output) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char check_tag[16]; + int diff; + + if ((ret = mbedtls_gcm_crypt_and_tag(ctx, MBEDTLS_GCM_DECRYPT, length, + iv, iv_len, add, add_len, + input, output, tag_len, check_tag)) != 0) { + return ret; + } + + /* Check tag in "constant-time" */ + diff = mbedtls_ct_memcmp(tag, check_tag, tag_len); + + if (diff != 0) { + mbedtls_platform_zeroize(output, length); + return MBEDTLS_ERR_GCM_AUTH_FAILED; + } + + return 0; +} + +void mbedtls_gcm_free(mbedtls_gcm_context *ctx) +{ + if (ctx == NULL) { + return; + } +#if defined(MBEDTLS_BLOCK_CIPHER_C) + mbedtls_block_cipher_free(&ctx->block_cipher_ctx); +#else + mbedtls_cipher_free(&ctx->cipher_ctx); +#endif + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_gcm_context)); +} + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_CCM_GCM_CAN_AES) +/* + * AES-GCM test vectors from: + * + * http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip + */ +#define MAX_TESTS 6 + +static const int key_index_test_data[MAX_TESTS] = +{ 0, 0, 1, 1, 1, 1 }; + +static const unsigned char key_test_data[][32] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }, +}; + +static const size_t iv_len_test_data[MAX_TESTS] = +{ 12, 12, 12, 12, 8, 60 }; + +static const int iv_index_test_data[MAX_TESTS] = +{ 0, 0, 1, 1, 1, 2 }; + +static const unsigned char iv_test_data[][64] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + { 0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5, + 0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52, 0x69, 0xaa, + 0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1, + 0xe4, 0xc3, 0x03, 0xd2, 0xa3, 0x18, 0xa7, 0x28, + 0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39, + 0xfc, 0xf0, 0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54, + 0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57, + 0xa6, 0x37, 0xb3, 0x9b }, +}; + +static const size_t add_len_test_data[MAX_TESTS] = +{ 0, 0, 0, 20, 20, 20 }; + +static const int add_index_test_data[MAX_TESTS] = +{ 0, 0, 0, 1, 1, 1 }; + +static const unsigned char additional_test_data[][64] = +{ + { 0x00 }, + { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xab, 0xad, 0xda, 0xd2 }, +}; + +static const size_t pt_len_test_data[MAX_TESTS] = +{ 0, 16, 64, 60, 60, 60 }; + +static const int pt_index_test_data[MAX_TESTS] = +{ 0, 0, 1, 1, 1, 1 }; + +static const unsigned char pt_test_data[][64] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 }, +}; + +static const unsigned char ct_test_data[][64] = +{ + { 0x00 }, + { 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, + 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78 }, + { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85 }, + { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91 }, + { 0x61, 0x35, 0x3b, 0x4c, 0x28, 0x06, 0x93, 0x4a, + 0x77, 0x7f, 0xf5, 0x1f, 0xa2, 0x2a, 0x47, 0x55, + 0x69, 0x9b, 0x2a, 0x71, 0x4f, 0xcd, 0xc6, 0xf8, + 0x37, 0x66, 0xe5, 0xf9, 0x7b, 0x6c, 0x74, 0x23, + 0x73, 0x80, 0x69, 0x00, 0xe4, 0x9f, 0x24, 0xb2, + 0x2b, 0x09, 0x75, 0x44, 0xd4, 0x89, 0x6b, 0x42, + 0x49, 0x89, 0xb5, 0xe1, 0xeb, 0xac, 0x0f, 0x07, + 0xc2, 0x3f, 0x45, 0x98 }, + { 0x8c, 0xe2, 0x49, 0x98, 0x62, 0x56, 0x15, 0xb6, + 0x03, 0xa0, 0x33, 0xac, 0xa1, 0x3f, 0xb8, 0x94, + 0xbe, 0x91, 0x12, 0xa5, 0xc3, 0xa2, 0x11, 0xa8, + 0xba, 0x26, 0x2a, 0x3c, 0xca, 0x7e, 0x2c, 0xa7, + 0x01, 0xe4, 0xa9, 0xa4, 0xfb, 0xa4, 0x3c, 0x90, + 0xcc, 0xdc, 0xb2, 0x81, 0xd4, 0x8c, 0x7c, 0x6f, + 0xd6, 0x28, 0x75, 0xd2, 0xac, 0xa4, 0x17, 0x03, + 0x4c, 0x34, 0xae, 0xe5 }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { 0x00 }, + { 0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41, + 0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00 }, + { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, + 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57, + 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, + 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c, + 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, + 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, + 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9, + 0xcc, 0xda, 0x27, 0x10, 0xac, 0xad, 0xe2, 0x56 }, + { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, + 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57, + 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, + 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c, + 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, + 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, + 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9, + 0xcc, 0xda, 0x27, 0x10 }, + { 0x0f, 0x10, 0xf5, 0x99, 0xae, 0x14, 0xa1, 0x54, + 0xed, 0x24, 0xb3, 0x6e, 0x25, 0x32, 0x4d, 0xb8, + 0xc5, 0x66, 0x63, 0x2e, 0xf2, 0xbb, 0xb3, 0x4f, + 0x83, 0x47, 0x28, 0x0f, 0xc4, 0x50, 0x70, 0x57, + 0xfd, 0xdc, 0x29, 0xdf, 0x9a, 0x47, 0x1f, 0x75, + 0xc6, 0x65, 0x41, 0xd4, 0xd4, 0xda, 0xd1, 0xc9, + 0xe9, 0x3a, 0x19, 0xa5, 0x8e, 0x8b, 0x47, 0x3f, + 0xa0, 0xf0, 0x62, 0xf7 }, + { 0xd2, 0x7e, 0x88, 0x68, 0x1c, 0xe3, 0x24, 0x3c, + 0x48, 0x30, 0x16, 0x5a, 0x8f, 0xdc, 0xf9, 0xff, + 0x1d, 0xe9, 0xa1, 0xd8, 0xe6, 0xb4, 0x47, 0xef, + 0x6e, 0xf7, 0xb7, 0x98, 0x28, 0x66, 0x6e, 0x45, + 0x81, 0xe7, 0x90, 0x12, 0xaf, 0x34, 0xdd, 0xd9, + 0xe2, 0xf0, 0x37, 0x58, 0x9b, 0x29, 0x2d, 0xb3, + 0xe6, 0x7c, 0x03, 0x67, 0x45, 0xfa, 0x22, 0xe7, + 0xe9, 0xb7, 0x37, 0x3b }, + { 0x00 }, + { 0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e, + 0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18 }, + { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, + 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, + 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, + 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, + 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, + 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, + 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, + 0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad }, + { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, + 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, + 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, + 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, + 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, + 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, + 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, + 0xbc, 0xc9, 0xf6, 0x62 }, + { 0xc3, 0x76, 0x2d, 0xf1, 0xca, 0x78, 0x7d, 0x32, + 0xae, 0x47, 0xc1, 0x3b, 0xf1, 0x98, 0x44, 0xcb, + 0xaf, 0x1a, 0xe1, 0x4d, 0x0b, 0x97, 0x6a, 0xfa, + 0xc5, 0x2f, 0xf7, 0xd7, 0x9b, 0xba, 0x9d, 0xe0, + 0xfe, 0xb5, 0x82, 0xd3, 0x39, 0x34, 0xa4, 0xf0, + 0x95, 0x4c, 0xc2, 0x36, 0x3b, 0xc7, 0x3f, 0x78, + 0x62, 0xac, 0x43, 0x0e, 0x64, 0xab, 0xe4, 0x99, + 0xf4, 0x7c, 0x9b, 0x1f }, + { 0x5a, 0x8d, 0xef, 0x2f, 0x0c, 0x9e, 0x53, 0xf1, + 0xf7, 0x5d, 0x78, 0x53, 0x65, 0x9e, 0x2a, 0x20, + 0xee, 0xb2, 0xb2, 0x2a, 0xaf, 0xde, 0x64, 0x19, + 0xa0, 0x58, 0xab, 0x4f, 0x6f, 0x74, 0x6b, 0xf4, + 0x0f, 0xc0, 0xc3, 0xb7, 0x80, 0xf2, 0x44, 0x45, + 0x2d, 0xa3, 0xeb, 0xf1, 0xc5, 0xd8, 0x2c, 0xde, + 0xa2, 0x41, 0x89, 0x97, 0x20, 0x0e, 0xf8, 0x2e, + 0x44, 0xae, 0x7e, 0x3f }, +#endif /* !MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH */ +}; + +static const unsigned char tag_test_data[][16] = +{ + { 0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61, + 0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a }, + { 0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd, + 0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf }, + { 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, + 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 }, + { 0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb, + 0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47 }, + { 0x36, 0x12, 0xd2, 0xe7, 0x9e, 0x3b, 0x07, 0x85, + 0x56, 0x1b, 0xe1, 0x4a, 0xac, 0xa2, 0xfc, 0xcb }, + { 0x61, 0x9c, 0xc5, 0xae, 0xff, 0xfe, 0x0b, 0xfa, + 0x46, 0x2a, 0xf4, 0x3c, 0x16, 0x99, 0xd0, 0x50 }, +#if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH) + { 0xcd, 0x33, 0xb2, 0x8a, 0xc7, 0x73, 0xf7, 0x4b, + 0xa0, 0x0e, 0xd1, 0xf3, 0x12, 0x57, 0x24, 0x35 }, + { 0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab, + 0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14, 0xf0, 0xfb }, + { 0x99, 0x24, 0xa7, 0xc8, 0x58, 0x73, 0x36, 0xbf, + 0xb1, 0x18, 0x02, 0x4d, 0xb8, 0x67, 0x4a, 0x14 }, + { 0x25, 0x19, 0x49, 0x8e, 0x80, 0xf1, 0x47, 0x8f, + 0x37, 0xba, 0x55, 0xbd, 0x6d, 0x27, 0x61, 0x8c }, + { 0x65, 0xdc, 0xc5, 0x7f, 0xcf, 0x62, 0x3a, 0x24, + 0x09, 0x4f, 0xcc, 0xa4, 0x0d, 0x35, 0x33, 0xf8 }, + { 0xdc, 0xf5, 0x66, 0xff, 0x29, 0x1c, 0x25, 0xbb, + 0xb8, 0x56, 0x8f, 0xc3, 0xd3, 0x76, 0xa6, 0xd9 }, + { 0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9, + 0xa9, 0x63, 0xb4, 0xf1, 0xc4, 0xcb, 0x73, 0x8b }, + { 0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0, + 0x26, 0x5b, 0x98, 0xb5, 0xd4, 0x8a, 0xb9, 0x19 }, + { 0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd, + 0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c }, + { 0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68, + 0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b }, + { 0x3a, 0x33, 0x7d, 0xbf, 0x46, 0xa7, 0x92, 0xc4, + 0x5e, 0x45, 0x49, 0x13, 0xfe, 0x2e, 0xa8, 0xf2 }, + { 0xa4, 0x4a, 0x82, 0x66, 0xee, 0x1c, 0x8e, 0xb0, + 0xc8, 0xb5, 0xd4, 0xcf, 0x5a, 0xe9, 0xf1, 0x9a }, +#endif /* !MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH */ +}; + +int mbedtls_gcm_self_test(int verbose) +{ + mbedtls_gcm_context ctx; + unsigned char buf[64]; + unsigned char tag_buf[16]; + int i, j, ret; + mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES; + size_t olen; + + if (verbose != 0) { +#if defined(MBEDTLS_AESNI_HAVE_CODE) + if (mbedtls_aesni_has_support(MBEDTLS_AESNI_CLMUL)) { + mbedtls_printf(" GCM note: using AESNI.\n"); + } else +#endif + +#if defined(MBEDTLS_AESCE_HAVE_CODE) + if (MBEDTLS_AESCE_HAS_SUPPORT()) { + mbedtls_printf(" GCM note: using AESCE.\n"); + } else +#endif + + mbedtls_printf(" GCM note: built-in implementation.\n"); + } + + static const int loop_limit = + (sizeof(ct_test_data) / sizeof(*ct_test_data)) / MAX_TESTS; + + for (j = 0; j < loop_limit; j++) { + int key_len = 128 + 64 * j; + + for (i = 0; i < MAX_TESTS; i++) { + if (verbose != 0) { + mbedtls_printf(" AES-GCM-%3d #%d (%s): ", + key_len, i, "enc"); + } + + mbedtls_gcm_init(&ctx); + + ret = mbedtls_gcm_setkey(&ctx, cipher, + key_test_data[key_index_test_data[i]], + key_len); + /* + * AES-192 is an optional feature that may be unavailable when + * there is an alternative underlying implementation such as a + * PSA driver. + */ + if (ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && key_len == 192) { + mbedtls_printf("skipped\n"); + break; + } else if (ret != 0) { + goto exit; + } + + ret = mbedtls_gcm_crypt_and_tag(&ctx, MBEDTLS_GCM_ENCRYPT, + pt_len_test_data[i], + iv_test_data[iv_index_test_data[i]], + iv_len_test_data[i], + additional_test_data[add_index_test_data[i]], + add_len_test_data[i], + pt_test_data[pt_index_test_data[i]], + buf, 16, tag_buf); + if (ret != 0) { + goto exit; + } + + if (memcmp(buf, ct_test_data[j * 6 + i], + pt_len_test_data[i]) != 0 || + memcmp(tag_buf, tag_test_data[j * 6 + i], 16) != 0) { + ret = 1; + goto exit; + } + + mbedtls_gcm_free(&ctx); + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + + mbedtls_gcm_init(&ctx); + + if (verbose != 0) { + mbedtls_printf(" AES-GCM-%3d #%d (%s): ", + key_len, i, "dec"); + } + + ret = mbedtls_gcm_setkey(&ctx, cipher, + key_test_data[key_index_test_data[i]], + key_len); + if (ret != 0) { + goto exit; + } + + ret = mbedtls_gcm_crypt_and_tag(&ctx, MBEDTLS_GCM_DECRYPT, + pt_len_test_data[i], + iv_test_data[iv_index_test_data[i]], + iv_len_test_data[i], + additional_test_data[add_index_test_data[i]], + add_len_test_data[i], + ct_test_data[j * 6 + i], buf, 16, tag_buf); + + if (ret != 0) { + goto exit; + } + + if (memcmp(buf, pt_test_data[pt_index_test_data[i]], + pt_len_test_data[i]) != 0 || + memcmp(tag_buf, tag_test_data[j * 6 + i], 16) != 0) { + ret = 1; + goto exit; + } + + mbedtls_gcm_free(&ctx); + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + + mbedtls_gcm_init(&ctx); + + if (verbose != 0) { + mbedtls_printf(" AES-GCM-%3d #%d split (%s): ", + key_len, i, "enc"); + } + + ret = mbedtls_gcm_setkey(&ctx, cipher, + key_test_data[key_index_test_data[i]], + key_len); + if (ret != 0) { + goto exit; + } + + ret = mbedtls_gcm_starts(&ctx, MBEDTLS_GCM_ENCRYPT, + iv_test_data[iv_index_test_data[i]], + iv_len_test_data[i]); + if (ret != 0) { + goto exit; + } + + ret = mbedtls_gcm_update_ad(&ctx, + additional_test_data[add_index_test_data[i]], + add_len_test_data[i]); + if (ret != 0) { + goto exit; + } + + if (pt_len_test_data[i] > 32) { + size_t rest_len = pt_len_test_data[i] - 32; + ret = mbedtls_gcm_update(&ctx, + pt_test_data[pt_index_test_data[i]], + 32, + buf, sizeof(buf), &olen); + if (ret != 0) { + goto exit; + } + if (olen != 32) { + goto exit; + } + + ret = mbedtls_gcm_update(&ctx, + pt_test_data[pt_index_test_data[i]] + 32, + rest_len, + buf + 32, sizeof(buf) - 32, &olen); + if (ret != 0) { + goto exit; + } + if (olen != rest_len) { + goto exit; + } + } else { + ret = mbedtls_gcm_update(&ctx, + pt_test_data[pt_index_test_data[i]], + pt_len_test_data[i], + buf, sizeof(buf), &olen); + if (ret != 0) { + goto exit; + } + if (olen != pt_len_test_data[i]) { + goto exit; + } + } + + ret = mbedtls_gcm_finish(&ctx, NULL, 0, &olen, tag_buf, 16); + if (ret != 0) { + goto exit; + } + + if (memcmp(buf, ct_test_data[j * 6 + i], + pt_len_test_data[i]) != 0 || + memcmp(tag_buf, tag_test_data[j * 6 + i], 16) != 0) { + ret = 1; + goto exit; + } + + mbedtls_gcm_free(&ctx); + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + + mbedtls_gcm_init(&ctx); + + if (verbose != 0) { + mbedtls_printf(" AES-GCM-%3d #%d split (%s): ", + key_len, i, "dec"); + } + + ret = mbedtls_gcm_setkey(&ctx, cipher, + key_test_data[key_index_test_data[i]], + key_len); + if (ret != 0) { + goto exit; + } + + ret = mbedtls_gcm_starts(&ctx, MBEDTLS_GCM_DECRYPT, + iv_test_data[iv_index_test_data[i]], + iv_len_test_data[i]); + if (ret != 0) { + goto exit; + } + ret = mbedtls_gcm_update_ad(&ctx, + additional_test_data[add_index_test_data[i]], + add_len_test_data[i]); + if (ret != 0) { + goto exit; + } + + if (pt_len_test_data[i] > 32) { + size_t rest_len = pt_len_test_data[i] - 32; + ret = mbedtls_gcm_update(&ctx, + ct_test_data[j * 6 + i], 32, + buf, sizeof(buf), &olen); + if (ret != 0) { + goto exit; + } + if (olen != 32) { + goto exit; + } + + ret = mbedtls_gcm_update(&ctx, + ct_test_data[j * 6 + i] + 32, + rest_len, + buf + 32, sizeof(buf) - 32, &olen); + if (ret != 0) { + goto exit; + } + if (olen != rest_len) { + goto exit; + } + } else { + ret = mbedtls_gcm_update(&ctx, + ct_test_data[j * 6 + i], + pt_len_test_data[i], + buf, sizeof(buf), &olen); + if (ret != 0) { + goto exit; + } + if (olen != pt_len_test_data[i]) { + goto exit; + } + } + + ret = mbedtls_gcm_finish(&ctx, NULL, 0, &olen, tag_buf, 16); + if (ret != 0) { + goto exit; + } + + if (memcmp(buf, pt_test_data[pt_index_test_data[i]], + pt_len_test_data[i]) != 0 || + memcmp(tag_buf, tag_test_data[j * 6 + i], 16) != 0) { + ret = 1; + goto exit; + } + + mbedtls_gcm_free(&ctx); + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + ret = 0; + +exit: + if (ret != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + mbedtls_gcm_free(&ctx); + } + + return ret; +} + +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#endif /* MBEDTLS_GCM_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/hmac_drbg.c b/tf-psa-crypto/drivers/builtin/src/hmac_drbg.c new file mode 100644 index 0000000000..01a62dac02 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/hmac_drbg.c @@ -0,0 +1,639 @@ +/* + * HMAC_DRBG implementation (NIST SP 800-90) + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +/* + * The NIST SP 800-90A DRBGs are described in the following publication. + * http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf + * References below are based on rev. 1 (January 2012). + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_HMAC_DRBG_C) + +#include "mbedtls/private/hmac_drbg.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#include "mbedtls/platform.h" + +/* + * HMAC_DRBG context initialization + */ +void mbedtls_hmac_drbg_init(mbedtls_hmac_drbg_context *ctx) +{ + memset(ctx, 0, sizeof(mbedtls_hmac_drbg_context)); + + ctx->reseed_interval = MBEDTLS_PSA_RNG_RESEED_INTERVAL; +} + +/* + * HMAC_DRBG update, using optional additional data (10.1.2.2) + */ +int mbedtls_hmac_drbg_update(mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, + size_t add_len) +{ + size_t md_len = mbedtls_md_get_size(ctx->md_ctx.md_info); + unsigned char rounds = (additional != NULL && add_len != 0) ? 2 : 1; + unsigned char sep[1]; + unsigned char K[MBEDTLS_MD_MAX_SIZE]; + int ret = MBEDTLS_ERR_MD_BAD_INPUT_DATA; + + for (sep[0] = 0; sep[0] < rounds; sep[0]++) { + /* Step 1 or 4 */ + if ((ret = mbedtls_md_hmac_reset(&ctx->md_ctx)) != 0) { + goto exit; + } + if ((ret = mbedtls_md_hmac_update(&ctx->md_ctx, + ctx->V, md_len)) != 0) { + goto exit; + } + if ((ret = mbedtls_md_hmac_update(&ctx->md_ctx, + sep, 1)) != 0) { + goto exit; + } + if (rounds == 2) { + if ((ret = mbedtls_md_hmac_update(&ctx->md_ctx, + additional, add_len)) != 0) { + goto exit; + } + } + if ((ret = mbedtls_md_hmac_finish(&ctx->md_ctx, K)) != 0) { + goto exit; + } + + /* Step 2 or 5 */ + if ((ret = mbedtls_md_hmac_starts(&ctx->md_ctx, K, md_len)) != 0) { + goto exit; + } + if ((ret = mbedtls_md_hmac_update(&ctx->md_ctx, + ctx->V, md_len)) != 0) { + goto exit; + } + if ((ret = mbedtls_md_hmac_finish(&ctx->md_ctx, ctx->V)) != 0) { + goto exit; + } + } + +exit: + mbedtls_platform_zeroize(K, sizeof(K)); + return ret; +} + +/* + * Simplified HMAC_DRBG initialisation (for use with deterministic ECDSA) + */ +int mbedtls_hmac_drbg_seed_buf(mbedtls_hmac_drbg_context *ctx, + const mbedtls_md_info_t *md_info, + const unsigned char *data, size_t data_len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if ((ret = mbedtls_md_setup(&ctx->md_ctx, md_info, 0)) != 0) { + return ret; + } + if ((ret = mbedtls_md_hmac_setup(&ctx->md_ctx, md_info)) != 0) { + return ret; + } + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init(&ctx->mutex); +#endif + + /* + * Set initial working state. + * Use the V memory location, which is currently all 0, to initialize the + * MD context with an all-zero key. Then set V to its initial value. + */ + if ((ret = mbedtls_md_hmac_starts(&ctx->md_ctx, ctx->V, + mbedtls_md_get_size(md_info))) != 0) { + return ret; + } + memset(ctx->V, 0x01, mbedtls_md_get_size(md_info)); + + if ((ret = mbedtls_hmac_drbg_update(ctx, data, data_len)) != 0) { + return ret; + } + + return 0; +} + +/* + * Internal function used both for seeding and reseeding the DRBG. + * Comments starting with arabic numbers refer to section 10.1.2.4 + * of SP800-90A, while roman numbers refer to section 9.2. + */ +static int hmac_drbg_reseed_core(mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t len, + int use_nonce) +{ + unsigned char seed[MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT]; + size_t seedlen = 0; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + { + size_t total_entropy_len; + + if (use_nonce == 0) { + total_entropy_len = ctx->entropy_len; + } else { + total_entropy_len = ctx->entropy_len * 3 / 2; + } + + /* III. Check input length */ + if (len > MBEDTLS_HMAC_DRBG_MAX_INPUT || + total_entropy_len + len > MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT) { + return MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG; + } + } + + memset(seed, 0, MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT); + + /* IV. Gather entropy_len bytes of entropy for the seed */ + if ((ret = ctx->f_entropy(ctx->p_entropy, + seed, ctx->entropy_len)) != 0) { + return MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED; + } + seedlen += ctx->entropy_len; + + /* For initial seeding, allow adding of nonce generated + * from the entropy source. See Sect 8.6.7 in SP800-90A. */ + if (use_nonce) { + /* Note: We don't merge the two calls to f_entropy() in order + * to avoid requesting too much entropy from f_entropy() + * at once. Specifically, if the underlying digest is not + * SHA-1, 3 / 2 * entropy_len is at least 36 Bytes, which + * is larger than the maximum of 32 Bytes that our own + * entropy source implementation can emit in a single + * call in configurations disabling SHA-512. */ + if ((ret = ctx->f_entropy(ctx->p_entropy, + seed + seedlen, + ctx->entropy_len / 2)) != 0) { + return MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED; + } + + seedlen += ctx->entropy_len / 2; + } + + + /* 1. Concatenate entropy and additional data if any */ + if (additional != NULL && len != 0) { + memcpy(seed + seedlen, additional, len); + seedlen += len; + } + + /* 2. Update state */ + if ((ret = mbedtls_hmac_drbg_update(ctx, seed, seedlen)) != 0) { + goto exit; + } + + /* 3. Reset reseed_counter */ + ctx->reseed_counter = 0; + +exit: + /* 4. Done */ + mbedtls_platform_zeroize(seed, seedlen); + return ret; +} + +/* + * HMAC_DRBG reseeding: 10.1.2.4 + 9.2 + */ +int mbedtls_hmac_drbg_reseed(mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t len) +{ + return hmac_drbg_reseed_core(ctx, additional, len, 0); +} + +/* + * HMAC_DRBG initialisation (10.1.2.3 + 9.1) + * + * The nonce is not passed as a separate parameter but extracted + * from the entropy source as suggested in 8.6.7. + */ +int mbedtls_hmac_drbg_seed(mbedtls_hmac_drbg_context *ctx, + const mbedtls_md_info_t *md_info, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t md_size; + + if ((ret = mbedtls_md_setup(&ctx->md_ctx, md_info, 0)) != 0) { + return ret; + } + if ((ret = mbedtls_md_hmac_setup(&ctx->md_ctx, md_info)) != 0) { + return ret; + } + + /* The mutex is initialized iff the md context is set up. */ +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init(&ctx->mutex); +#endif + + md_size = mbedtls_md_get_size(md_info); + + /* + * Set initial working state. + * Use the V memory location, which is currently all 0, to initialize the + * MD context with an all-zero key. Then set V to its initial value. + */ + if ((ret = mbedtls_md_hmac_starts(&ctx->md_ctx, ctx->V, md_size)) != 0) { + return ret; + } + memset(ctx->V, 0x01, md_size); + + ctx->f_entropy = f_entropy; + ctx->p_entropy = p_entropy; + + if (ctx->entropy_len == 0) { + /* + * See SP800-57 5.6.1 (p. 65-66) for the security strength provided by + * each hash function, then according to SP800-90A rev1 10.1 table 2, + * min_entropy_len (in bits) is security_strength. + * + * (This also matches the sizes used in the NIST test vectors.) + */ + ctx->entropy_len = md_size <= 20 ? 16 : /* 160-bits hash -> 128 bits */ + md_size <= 28 ? 24 : /* 224-bits hash -> 192 bits */ + 32; /* better (256+) -> 256 bits */ + } + + if ((ret = hmac_drbg_reseed_core(ctx, custom, len, + 1 /* add nonce */)) != 0) { + return ret; + } + + return 0; +} + +/* + * Set prediction resistance + */ +void mbedtls_hmac_drbg_set_prediction_resistance(mbedtls_hmac_drbg_context *ctx, + int resistance) +{ + ctx->prediction_resistance = resistance; +} + +/* + * Set entropy length grabbed for seeding + */ +void mbedtls_hmac_drbg_set_entropy_len(mbedtls_hmac_drbg_context *ctx, size_t len) +{ + ctx->entropy_len = len; +} + +/* + * Set reseed interval + */ +void mbedtls_hmac_drbg_set_reseed_interval(mbedtls_hmac_drbg_context *ctx, int interval) +{ + ctx->reseed_interval = interval; +} + +/* + * HMAC_DRBG random function with optional additional data: + * 10.1.2.5 (arabic) + 9.3 (Roman) + */ +int mbedtls_hmac_drbg_random_with_add(void *p_rng, + unsigned char *output, size_t out_len, + const unsigned char *additional, size_t add_len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_hmac_drbg_context *ctx = (mbedtls_hmac_drbg_context *) p_rng; + size_t md_len = mbedtls_md_get_size(ctx->md_ctx.md_info); + size_t left = out_len; + unsigned char *out = output; + + /* II. Check request length */ + if (out_len > MBEDTLS_HMAC_DRBG_MAX_REQUEST) { + return MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG; + } + + /* III. Check input length */ + if (add_len > MBEDTLS_HMAC_DRBG_MAX_INPUT) { + return MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG; + } + + /* 1. (aka VII and IX) Check reseed counter and PR */ + if (ctx->f_entropy != NULL && /* For no-reseeding instances */ + (ctx->prediction_resistance == MBEDTLS_HMAC_DRBG_PR_ON || + ctx->reseed_counter >= ctx->reseed_interval)) { + if ((ret = mbedtls_hmac_drbg_reseed(ctx, additional, add_len)) != 0) { + return ret; + } + + add_len = 0; /* VII.4 */ + } + + /* 2. Use additional data if any */ + if (additional != NULL && add_len != 0) { + if ((ret = mbedtls_hmac_drbg_update(ctx, + additional, add_len)) != 0) { + goto exit; + } + } + + /* 3, 4, 5. Generate bytes */ + while (left != 0) { + size_t use_len = left > md_len ? md_len : left; + + if ((ret = mbedtls_md_hmac_reset(&ctx->md_ctx)) != 0) { + goto exit; + } + if ((ret = mbedtls_md_hmac_update(&ctx->md_ctx, + ctx->V, md_len)) != 0) { + goto exit; + } + if ((ret = mbedtls_md_hmac_finish(&ctx->md_ctx, ctx->V)) != 0) { + goto exit; + } + + memcpy(out, ctx->V, use_len); + out += use_len; + left -= use_len; + } + + /* 6. Update */ + if ((ret = mbedtls_hmac_drbg_update(ctx, + additional, add_len)) != 0) { + goto exit; + } + + /* 7. Update reseed counter */ + ctx->reseed_counter++; + +exit: + /* 8. Done */ + return ret; +} + +/* + * HMAC_DRBG random function + */ +int mbedtls_hmac_drbg_random(void *p_rng, unsigned char *output, size_t out_len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_hmac_drbg_context *ctx = (mbedtls_hmac_drbg_context *) p_rng; + +#if defined(MBEDTLS_THREADING_C) + if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) { + return ret; + } +#endif + + ret = mbedtls_hmac_drbg_random_with_add(ctx, output, out_len, NULL, 0); + +#if defined(MBEDTLS_THREADING_C) + if (mbedtls_mutex_unlock(&ctx->mutex) != 0) { + return MBEDTLS_ERR_THREADING_MUTEX_ERROR; + } +#endif + + return ret; +} + +/* + * This function resets HMAC_DRBG context to the state immediately + * after initial call of mbedtls_hmac_drbg_init(). + */ +void mbedtls_hmac_drbg_free(mbedtls_hmac_drbg_context *ctx) +{ + if (ctx == NULL) { + return; + } + +#if defined(MBEDTLS_THREADING_C) + /* The mutex is initialized iff the md context is set up. */ + if (ctx->md_ctx.md_info != NULL) { + mbedtls_mutex_free(&ctx->mutex); + } +#endif + mbedtls_md_free(&ctx->md_ctx); + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_hmac_drbg_context)); + ctx->reseed_interval = MBEDTLS_PSA_RNG_RESEED_INTERVAL; +} + +#if defined(MBEDTLS_FS_IO) +int mbedtls_hmac_drbg_write_seed_file(mbedtls_hmac_drbg_context *ctx, const char *path) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + FILE *f; + unsigned char buf[MBEDTLS_HMAC_DRBG_MAX_INPUT]; + + if ((f = fopen(path, "wb")) == NULL) { + return MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR; + } + + /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ + mbedtls_setbuf(f, NULL); + + if ((ret = mbedtls_hmac_drbg_random(ctx, buf, sizeof(buf))) != 0) { + goto exit; + } + + if (fwrite(buf, 1, sizeof(buf), f) != sizeof(buf)) { + ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR; + goto exit; + } + + ret = 0; + +exit: + fclose(f); + mbedtls_platform_zeroize(buf, sizeof(buf)); + + return ret; +} + +int mbedtls_hmac_drbg_update_seed_file(mbedtls_hmac_drbg_context *ctx, const char *path) +{ + int ret = 0; + FILE *f = NULL; + size_t n; + unsigned char buf[MBEDTLS_HMAC_DRBG_MAX_INPUT]; + unsigned char c; + + if ((f = fopen(path, "rb")) == NULL) { + return MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR; + } + + /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ + mbedtls_setbuf(f, NULL); + + n = fread(buf, 1, sizeof(buf), f); + if (fread(&c, 1, 1, f) != 0) { + ret = MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG; + goto exit; + } + if (n == 0 || ferror(f)) { + ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR; + goto exit; + } + fclose(f); + f = NULL; + + ret = mbedtls_hmac_drbg_update(ctx, buf, n); + +exit: + mbedtls_platform_zeroize(buf, sizeof(buf)); + if (f != NULL) { + fclose(f); + } + if (ret != 0) { + return ret; + } + return mbedtls_hmac_drbg_write_seed_file(ctx, path); +} +#endif /* MBEDTLS_FS_IO */ + + +#if defined(MBEDTLS_SELF_TEST) + +#if !defined(PSA_WANT_ALG_SHA_1) +/* Dummy checkup routine */ +int mbedtls_hmac_drbg_self_test(int verbose) +{ + (void) verbose; + return 0; +} +#else + +#define OUTPUT_LEN 80 + +/* From a NIST PR=true test vector */ +static const unsigned char entropy_pr[] = { + 0xa0, 0xc9, 0xab, 0x58, 0xf1, 0xe2, 0xe5, 0xa4, 0xde, 0x3e, 0xbd, 0x4f, + 0xf7, 0x3e, 0x9c, 0x5b, 0x64, 0xef, 0xd8, 0xca, 0x02, 0x8c, 0xf8, 0x11, + 0x48, 0xa5, 0x84, 0xfe, 0x69, 0xab, 0x5a, 0xee, 0x42, 0xaa, 0x4d, 0x42, + 0x17, 0x60, 0x99, 0xd4, 0x5e, 0x13, 0x97, 0xdc, 0x40, 0x4d, 0x86, 0xa3, + 0x7b, 0xf5, 0x59, 0x54, 0x75, 0x69, 0x51, 0xe4 +}; +static const unsigned char result_pr[OUTPUT_LEN] = { + 0x9a, 0x00, 0xa2, 0xd0, 0x0e, 0xd5, 0x9b, 0xfe, 0x31, 0xec, 0xb1, 0x39, + 0x9b, 0x60, 0x81, 0x48, 0xd1, 0x96, 0x9d, 0x25, 0x0d, 0x3c, 0x1e, 0x94, + 0x10, 0x10, 0x98, 0x12, 0x93, 0x25, 0xca, 0xb8, 0xfc, 0xcc, 0x2d, 0x54, + 0x73, 0x19, 0x70, 0xc0, 0x10, 0x7a, 0xa4, 0x89, 0x25, 0x19, 0x95, 0x5e, + 0x4b, 0xc6, 0x00, 0x1d, 0x7f, 0x4e, 0x6a, 0x2b, 0xf8, 0xa3, 0x01, 0xab, + 0x46, 0x05, 0x5c, 0x09, 0xa6, 0x71, 0x88, 0xf1, 0xa7, 0x40, 0xee, 0xf3, + 0xe1, 0x5c, 0x02, 0x9b, 0x44, 0xaf, 0x03, 0x44 +}; + +/* From a NIST PR=false test vector */ +static const unsigned char entropy_nopr[] = { + 0x79, 0x34, 0x9b, 0xbf, 0x7c, 0xdd, 0xa5, 0x79, 0x95, 0x57, 0x86, 0x66, + 0x21, 0xc9, 0x13, 0x83, 0x11, 0x46, 0x73, 0x3a, 0xbf, 0x8c, 0x35, 0xc8, + 0xc7, 0x21, 0x5b, 0x5b, 0x96, 0xc4, 0x8e, 0x9b, 0x33, 0x8c, 0x74, 0xe3, + 0xe9, 0x9d, 0xfe, 0xdf +}; +static const unsigned char result_nopr[OUTPUT_LEN] = { + 0xc6, 0xa1, 0x6a, 0xb8, 0xd4, 0x20, 0x70, 0x6f, 0x0f, 0x34, 0xab, 0x7f, + 0xec, 0x5a, 0xdc, 0xa9, 0xd8, 0xca, 0x3a, 0x13, 0x3e, 0x15, 0x9c, 0xa6, + 0xac, 0x43, 0xc6, 0xf8, 0xa2, 0xbe, 0x22, 0x83, 0x4a, 0x4c, 0x0a, 0x0a, + 0xff, 0xb1, 0x0d, 0x71, 0x94, 0xf1, 0xc1, 0xa5, 0xcf, 0x73, 0x22, 0xec, + 0x1a, 0xe0, 0x96, 0x4e, 0xd4, 0xbf, 0x12, 0x27, 0x46, 0xe0, 0x87, 0xfd, + 0xb5, 0xb3, 0xe9, 0x1b, 0x34, 0x93, 0xd5, 0xbb, 0x98, 0xfa, 0xed, 0x49, + 0xe8, 0x5f, 0x13, 0x0f, 0xc8, 0xa4, 0x59, 0xb7 +}; + +/* "Entropy" from buffer */ +static size_t test_offset; +static int hmac_drbg_self_test_entropy(void *data, + unsigned char *buf, size_t len) +{ + const unsigned char *p = data; + memcpy(buf, p + test_offset, len); + test_offset += len; + return 0; +} + +#define CHK(c) if ((c) != 0) \ + { \ + if (verbose != 0) \ + mbedtls_printf("failed\n"); \ + return 1; \ + } + +/* + * Checkup routine for HMAC_DRBG with SHA-1 + */ +int mbedtls_hmac_drbg_self_test(int verbose) +{ + mbedtls_hmac_drbg_context ctx; + unsigned char buf[OUTPUT_LEN]; + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); + + mbedtls_hmac_drbg_init(&ctx); + + /* + * PR = True + */ + if (verbose != 0) { + mbedtls_printf(" HMAC_DRBG (PR = True) : "); + } + + test_offset = 0; + CHK(mbedtls_hmac_drbg_seed(&ctx, md_info, + hmac_drbg_self_test_entropy, (void *) entropy_pr, + NULL, 0)); + mbedtls_hmac_drbg_set_prediction_resistance(&ctx, MBEDTLS_HMAC_DRBG_PR_ON); + CHK(mbedtls_hmac_drbg_random(&ctx, buf, OUTPUT_LEN)); + CHK(mbedtls_hmac_drbg_random(&ctx, buf, OUTPUT_LEN)); + CHK(memcmp(buf, result_pr, OUTPUT_LEN)); + mbedtls_hmac_drbg_free(&ctx); + + mbedtls_hmac_drbg_free(&ctx); + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + + /* + * PR = False + */ + if (verbose != 0) { + mbedtls_printf(" HMAC_DRBG (PR = False) : "); + } + + mbedtls_hmac_drbg_init(&ctx); + + test_offset = 0; + CHK(mbedtls_hmac_drbg_seed(&ctx, md_info, + hmac_drbg_self_test_entropy, (void *) entropy_nopr, + NULL, 0)); + CHK(mbedtls_hmac_drbg_reseed(&ctx, NULL, 0)); + CHK(mbedtls_hmac_drbg_random(&ctx, buf, OUTPUT_LEN)); + CHK(mbedtls_hmac_drbg_random(&ctx, buf, OUTPUT_LEN)); + CHK(memcmp(buf, result_nopr, OUTPUT_LEN)); + mbedtls_hmac_drbg_free(&ctx); + + mbedtls_hmac_drbg_free(&ctx); + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + return 0; +} +#endif /* PSA_WANT_ALG_SHA_1 */ +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_HMAC_DRBG_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/md5.c b/tf-psa-crypto/drivers/builtin/src/md5.c new file mode 100644 index 0000000000..01397b70d2 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/md5.c @@ -0,0 +1,419 @@ +/* + * RFC 1321 compliant MD5 implementation + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +/* + * The MD5 algorithm was designed by Ron Rivest in 1991. + * + * http://www.ietf.org/rfc/rfc1321.txt + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_MD5_C) + +#include "mbedtls/private/md5.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#include + +#include "mbedtls/platform.h" + +void mbedtls_md5_init(mbedtls_md5_context *ctx) +{ + memset(ctx, 0, sizeof(mbedtls_md5_context)); +} + +void mbedtls_md5_free(mbedtls_md5_context *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_md5_context)); +} + +void mbedtls_md5_clone(mbedtls_md5_context *dst, + const mbedtls_md5_context *src) +{ + *dst = *src; +} + +/* + * MD5 context setup + */ +int mbedtls_md5_starts(mbedtls_md5_context *ctx) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + + return 0; +} + +static int mbedtls_internal_md5_process(mbedtls_md5_context *ctx, + const unsigned char data[64]) +{ + struct { + uint32_t X[16], A, B, C, D; + } local; + + local.X[0] = MBEDTLS_GET_UINT32_LE(data, 0); + local.X[1] = MBEDTLS_GET_UINT32_LE(data, 4); + local.X[2] = MBEDTLS_GET_UINT32_LE(data, 8); + local.X[3] = MBEDTLS_GET_UINT32_LE(data, 12); + local.X[4] = MBEDTLS_GET_UINT32_LE(data, 16); + local.X[5] = MBEDTLS_GET_UINT32_LE(data, 20); + local.X[6] = MBEDTLS_GET_UINT32_LE(data, 24); + local.X[7] = MBEDTLS_GET_UINT32_LE(data, 28); + local.X[8] = MBEDTLS_GET_UINT32_LE(data, 32); + local.X[9] = MBEDTLS_GET_UINT32_LE(data, 36); + local.X[10] = MBEDTLS_GET_UINT32_LE(data, 40); + local.X[11] = MBEDTLS_GET_UINT32_LE(data, 44); + local.X[12] = MBEDTLS_GET_UINT32_LE(data, 48); + local.X[13] = MBEDTLS_GET_UINT32_LE(data, 52); + local.X[14] = MBEDTLS_GET_UINT32_LE(data, 56); + local.X[15] = MBEDTLS_GET_UINT32_LE(data, 60); + +#define S(x, n) \ + (((x) << (n)) | (((x) & 0xFFFFFFFF) >> (32 - (n)))) + +#define P(a, b, c, d, k, s, t) \ + do \ + { \ + (a) += F((b), (c), (d)) + local.X[(k)] + (t); \ + (a) = S((a), (s)) + (b); \ + } while (0) + + local.A = ctx->state[0]; + local.B = ctx->state[1]; + local.C = ctx->state[2]; + local.D = ctx->state[3]; + +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) + + P(local.A, local.B, local.C, local.D, 0, 7, 0xD76AA478); + P(local.D, local.A, local.B, local.C, 1, 12, 0xE8C7B756); + P(local.C, local.D, local.A, local.B, 2, 17, 0x242070DB); + P(local.B, local.C, local.D, local.A, 3, 22, 0xC1BDCEEE); + P(local.A, local.B, local.C, local.D, 4, 7, 0xF57C0FAF); + P(local.D, local.A, local.B, local.C, 5, 12, 0x4787C62A); + P(local.C, local.D, local.A, local.B, 6, 17, 0xA8304613); + P(local.B, local.C, local.D, local.A, 7, 22, 0xFD469501); + P(local.A, local.B, local.C, local.D, 8, 7, 0x698098D8); + P(local.D, local.A, local.B, local.C, 9, 12, 0x8B44F7AF); + P(local.C, local.D, local.A, local.B, 10, 17, 0xFFFF5BB1); + P(local.B, local.C, local.D, local.A, 11, 22, 0x895CD7BE); + P(local.A, local.B, local.C, local.D, 12, 7, 0x6B901122); + P(local.D, local.A, local.B, local.C, 13, 12, 0xFD987193); + P(local.C, local.D, local.A, local.B, 14, 17, 0xA679438E); + P(local.B, local.C, local.D, local.A, 15, 22, 0x49B40821); + +#undef F + +#define F(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) + + P(local.A, local.B, local.C, local.D, 1, 5, 0xF61E2562); + P(local.D, local.A, local.B, local.C, 6, 9, 0xC040B340); + P(local.C, local.D, local.A, local.B, 11, 14, 0x265E5A51); + P(local.B, local.C, local.D, local.A, 0, 20, 0xE9B6C7AA); + P(local.A, local.B, local.C, local.D, 5, 5, 0xD62F105D); + P(local.D, local.A, local.B, local.C, 10, 9, 0x02441453); + P(local.C, local.D, local.A, local.B, 15, 14, 0xD8A1E681); + P(local.B, local.C, local.D, local.A, 4, 20, 0xE7D3FBC8); + P(local.A, local.B, local.C, local.D, 9, 5, 0x21E1CDE6); + P(local.D, local.A, local.B, local.C, 14, 9, 0xC33707D6); + P(local.C, local.D, local.A, local.B, 3, 14, 0xF4D50D87); + P(local.B, local.C, local.D, local.A, 8, 20, 0x455A14ED); + P(local.A, local.B, local.C, local.D, 13, 5, 0xA9E3E905); + P(local.D, local.A, local.B, local.C, 2, 9, 0xFCEFA3F8); + P(local.C, local.D, local.A, local.B, 7, 14, 0x676F02D9); + P(local.B, local.C, local.D, local.A, 12, 20, 0x8D2A4C8A); + +#undef F + +#define F(x, y, z) ((x) ^ (y) ^ (z)) + + P(local.A, local.B, local.C, local.D, 5, 4, 0xFFFA3942); + P(local.D, local.A, local.B, local.C, 8, 11, 0x8771F681); + P(local.C, local.D, local.A, local.B, 11, 16, 0x6D9D6122); + P(local.B, local.C, local.D, local.A, 14, 23, 0xFDE5380C); + P(local.A, local.B, local.C, local.D, 1, 4, 0xA4BEEA44); + P(local.D, local.A, local.B, local.C, 4, 11, 0x4BDECFA9); + P(local.C, local.D, local.A, local.B, 7, 16, 0xF6BB4B60); + P(local.B, local.C, local.D, local.A, 10, 23, 0xBEBFBC70); + P(local.A, local.B, local.C, local.D, 13, 4, 0x289B7EC6); + P(local.D, local.A, local.B, local.C, 0, 11, 0xEAA127FA); + P(local.C, local.D, local.A, local.B, 3, 16, 0xD4EF3085); + P(local.B, local.C, local.D, local.A, 6, 23, 0x04881D05); + P(local.A, local.B, local.C, local.D, 9, 4, 0xD9D4D039); + P(local.D, local.A, local.B, local.C, 12, 11, 0xE6DB99E5); + P(local.C, local.D, local.A, local.B, 15, 16, 0x1FA27CF8); + P(local.B, local.C, local.D, local.A, 2, 23, 0xC4AC5665); + +#undef F + +#define F(x, y, z) ((y) ^ ((x) | ~(z))) + + P(local.A, local.B, local.C, local.D, 0, 6, 0xF4292244); + P(local.D, local.A, local.B, local.C, 7, 10, 0x432AFF97); + P(local.C, local.D, local.A, local.B, 14, 15, 0xAB9423A7); + P(local.B, local.C, local.D, local.A, 5, 21, 0xFC93A039); + P(local.A, local.B, local.C, local.D, 12, 6, 0x655B59C3); + P(local.D, local.A, local.B, local.C, 3, 10, 0x8F0CCC92); + P(local.C, local.D, local.A, local.B, 10, 15, 0xFFEFF47D); + P(local.B, local.C, local.D, local.A, 1, 21, 0x85845DD1); + P(local.A, local.B, local.C, local.D, 8, 6, 0x6FA87E4F); + P(local.D, local.A, local.B, local.C, 15, 10, 0xFE2CE6E0); + P(local.C, local.D, local.A, local.B, 6, 15, 0xA3014314); + P(local.B, local.C, local.D, local.A, 13, 21, 0x4E0811A1); + P(local.A, local.B, local.C, local.D, 4, 6, 0xF7537E82); + P(local.D, local.A, local.B, local.C, 11, 10, 0xBD3AF235); + P(local.C, local.D, local.A, local.B, 2, 15, 0x2AD7D2BB); + P(local.B, local.C, local.D, local.A, 9, 21, 0xEB86D391); + +#undef F + + ctx->state[0] += local.A; + ctx->state[1] += local.B; + ctx->state[2] += local.C; + ctx->state[3] += local.D; + + /* Zeroise variables to clear sensitive data from memory. */ + mbedtls_platform_zeroize(&local, sizeof(local)); + + return 0; +} + +/* + * MD5 process buffer + */ +int mbedtls_md5_update(mbedtls_md5_context *ctx, + const unsigned char *input, + size_t ilen) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t fill; + uint32_t left; + + if (ilen == 0) { + return 0; + } + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if (ctx->total[0] < (uint32_t) ilen) { + ctx->total[1]++; + } + + if (left && ilen >= fill) { + memcpy((void *) (ctx->buffer + left), input, fill); + if ((ret = mbedtls_internal_md5_process(ctx, ctx->buffer)) != 0) { + return ret; + } + + input += fill; + ilen -= fill; + left = 0; + } + + while (ilen >= 64) { + if ((ret = mbedtls_internal_md5_process(ctx, input)) != 0) { + return ret; + } + + input += 64; + ilen -= 64; + } + + if (ilen > 0) { + memcpy((void *) (ctx->buffer + left), input, ilen); + } + + return 0; +} + +/* + * MD5 final digest + */ +int mbedtls_md5_finish(mbedtls_md5_context *ctx, + unsigned char output[16]) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + uint32_t used; + uint32_t high, low; + + /* + * Add padding: 0x80 then 0x00 until 8 bytes remain for the length + */ + used = ctx->total[0] & 0x3F; + + ctx->buffer[used++] = 0x80; + + if (used <= 56) { + /* Enough room for padding + length in current block */ + memset(ctx->buffer + used, 0, 56 - used); + } else { + /* We'll need an extra block */ + memset(ctx->buffer + used, 0, 64 - used); + + if ((ret = mbedtls_internal_md5_process(ctx, ctx->buffer)) != 0) { + goto exit; + } + + memset(ctx->buffer, 0, 56); + } + + /* + * Add message length + */ + high = (ctx->total[0] >> 29) + | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + MBEDTLS_PUT_UINT32_LE(low, ctx->buffer, 56); + MBEDTLS_PUT_UINT32_LE(high, ctx->buffer, 60); + + if ((ret = mbedtls_internal_md5_process(ctx, ctx->buffer)) != 0) { + goto exit; + } + + /* + * Output final state + */ + MBEDTLS_PUT_UINT32_LE(ctx->state[0], output, 0); + MBEDTLS_PUT_UINT32_LE(ctx->state[1], output, 4); + MBEDTLS_PUT_UINT32_LE(ctx->state[2], output, 8); + MBEDTLS_PUT_UINT32_LE(ctx->state[3], output, 12); + + ret = 0; + +exit: + mbedtls_md5_free(ctx); + return ret; +} + +/* + * output = MD5( input buffer ) + */ +int mbedtls_md5(const unsigned char *input, + size_t ilen, + unsigned char output[16]) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_md5_context ctx; + + mbedtls_md5_init(&ctx); + + if ((ret = mbedtls_md5_starts(&ctx)) != 0) { + goto exit; + } + + if ((ret = mbedtls_md5_update(&ctx, input, ilen)) != 0) { + goto exit; + } + + if ((ret = mbedtls_md5_finish(&ctx, output)) != 0) { + goto exit; + } + +exit: + mbedtls_md5_free(&ctx); + + return ret; +} + +#if defined(MBEDTLS_SELF_TEST) +/* + * RFC 1321 test vectors + */ +static const unsigned char md5_test_buf[7][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012345678901234567890" } +}; + +static const size_t md5_test_buflen[7] = +{ + 0, 1, 3, 14, 26, 62, 80 +}; + +static const unsigned char md5_test_sum[7][16] = +{ + { 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04, + 0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E }, + { 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8, + 0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 }, + { 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0, + 0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 }, + { 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D, + 0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 }, + { 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00, + 0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B }, + { 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5, + 0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F }, + { 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55, + 0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A } +}; + +/* + * Checkup routine + */ +int mbedtls_md5_self_test(int verbose) +{ + int i, ret = 0; + unsigned char md5sum[16]; + + for (i = 0; i < 7; i++) { + if (verbose != 0) { + mbedtls_printf(" MD5 test #%d: ", i + 1); + } + + ret = mbedtls_md5(md5_test_buf[i], md5_test_buflen[i], md5sum); + if (ret != 0) { + goto fail; + } + + if (memcmp(md5sum, md5_test_sum[i], 16) != 0) { + ret = 1; + goto fail; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + return 0; + +fail: + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + return ret; +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_MD5_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/md_psa.h b/tf-psa-crypto/drivers/builtin/src/md_psa.h new file mode 100644 index 0000000000..c93dd72972 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/md_psa.h @@ -0,0 +1,26 @@ +/** + * Translation between MD and PSA identifiers (algorithms, errors). + * + * Note: this internal module will go away when everything becomes based on + * PSA Crypto; it is a helper for the transition period. + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_MD_PSA_H +#define TF_PSA_CRYPTO_MD_PSA_H + +#include "tf_psa_crypto_common.h" + +#include "mbedtls/md.h" +#include "psa/crypto.h" + +/** Convert PSA status to MD error code. + * + * \param status PSA status. + * + * \return The corresponding MD error code, + */ +int mbedtls_md_error_from_psa(psa_status_t status); + +#endif /* TF_PSA_CRYPTO_MD_PSA_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/poly1305.c b/tf-psa-crypto/drivers/builtin/src/poly1305.c new file mode 100644 index 0000000000..ba5299844d --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/poly1305.c @@ -0,0 +1,488 @@ +/** + * \file poly1305.c + * + * \brief Poly1305 authentication algorithm. + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_POLY1305_C) + +#include "mbedtls/private/poly1305.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#include + +#include "mbedtls/platform.h" + +#define POLY1305_BLOCK_SIZE_BYTES (16U) + +/* + * Our implementation is tuned for 32-bit platforms with a 64-bit multiplier. + * However we provided an alternative for platforms without such a multiplier. + */ +#if defined(MBEDTLS_NO_64BIT_MULTIPLICATION) +static uint64_t mul64(uint32_t a, uint32_t b) +{ + /* a = al + 2**16 ah, b = bl + 2**16 bh */ + const uint16_t al = (uint16_t) a; + const uint16_t bl = (uint16_t) b; + const uint16_t ah = a >> 16; + const uint16_t bh = b >> 16; + + /* ab = al*bl + 2**16 (ah*bl + bl*bh) + 2**32 ah*bh */ + const uint32_t lo = (uint32_t) al * bl; + const uint64_t me = (uint64_t) ((uint32_t) ah * bl) + (uint32_t) al * bh; + const uint32_t hi = (uint32_t) ah * bh; + + return lo + (me << 16) + ((uint64_t) hi << 32); +} +#else +static inline uint64_t mul64(uint32_t a, uint32_t b) +{ + return (uint64_t) a * b; +} +#endif + + +/** + * \brief Process blocks with Poly1305. + * + * \param ctx The Poly1305 context. + * \param nblocks Number of blocks to process. Note that this + * function only processes full blocks. + * \param input Buffer containing the input block(s). + * \param needs_padding Set to 0 if the padding bit has already been + * applied to the input data before calling this + * function. Otherwise, set this parameter to 1. + */ +static void poly1305_process(mbedtls_poly1305_context *ctx, + size_t nblocks, + const unsigned char *input, + uint32_t needs_padding) +{ + uint64_t d0, d1, d2, d3; + uint32_t acc0, acc1, acc2, acc3, acc4; + uint32_t r0, r1, r2, r3; + uint32_t rs1, rs2, rs3; + size_t offset = 0U; + size_t i; + + r0 = ctx->r[0]; + r1 = ctx->r[1]; + r2 = ctx->r[2]; + r3 = ctx->r[3]; + + rs1 = r1 + (r1 >> 2U); + rs2 = r2 + (r2 >> 2U); + rs3 = r3 + (r3 >> 2U); + + acc0 = ctx->acc[0]; + acc1 = ctx->acc[1]; + acc2 = ctx->acc[2]; + acc3 = ctx->acc[3]; + acc4 = ctx->acc[4]; + + /* Process full blocks */ + for (i = 0U; i < nblocks; i++) { + /* The input block is treated as a 128-bit little-endian integer */ + d0 = MBEDTLS_GET_UINT32_LE(input, offset + 0); + d1 = MBEDTLS_GET_UINT32_LE(input, offset + 4); + d2 = MBEDTLS_GET_UINT32_LE(input, offset + 8); + d3 = MBEDTLS_GET_UINT32_LE(input, offset + 12); + + /* Compute: acc += (padded) block as a 130-bit integer */ + d0 += (uint64_t) acc0; + d1 += (uint64_t) acc1 + (d0 >> 32U); + d2 += (uint64_t) acc2 + (d1 >> 32U); + d3 += (uint64_t) acc3 + (d2 >> 32U); + acc0 = (uint32_t) d0; + acc1 = (uint32_t) d1; + acc2 = (uint32_t) d2; + acc3 = (uint32_t) d3; + acc4 += (uint32_t) (d3 >> 32U) + needs_padding; + + /* Compute: acc *= r */ + d0 = mul64(acc0, r0) + + mul64(acc1, rs3) + + mul64(acc2, rs2) + + mul64(acc3, rs1); + d1 = mul64(acc0, r1) + + mul64(acc1, r0) + + mul64(acc2, rs3) + + mul64(acc3, rs2) + + mul64(acc4, rs1); + d2 = mul64(acc0, r2) + + mul64(acc1, r1) + + mul64(acc2, r0) + + mul64(acc3, rs3) + + mul64(acc4, rs2); + d3 = mul64(acc0, r3) + + mul64(acc1, r2) + + mul64(acc2, r1) + + mul64(acc3, r0) + + mul64(acc4, rs3); + acc4 *= r0; + + /* Compute: acc %= (2^130 - 5) (partial remainder) */ + d1 += (d0 >> 32); + d2 += (d1 >> 32); + d3 += (d2 >> 32); + acc0 = (uint32_t) d0; + acc1 = (uint32_t) d1; + acc2 = (uint32_t) d2; + acc3 = (uint32_t) d3; + acc4 = (uint32_t) (d3 >> 32) + acc4; + + d0 = (uint64_t) acc0 + (acc4 >> 2) + (acc4 & 0xFFFFFFFCU); + acc4 &= 3U; + acc0 = (uint32_t) d0; + d0 = (uint64_t) acc1 + (d0 >> 32U); + acc1 = (uint32_t) d0; + d0 = (uint64_t) acc2 + (d0 >> 32U); + acc2 = (uint32_t) d0; + d0 = (uint64_t) acc3 + (d0 >> 32U); + acc3 = (uint32_t) d0; + d0 = (uint64_t) acc4 + (d0 >> 32U); + acc4 = (uint32_t) d0; + + offset += POLY1305_BLOCK_SIZE_BYTES; + } + + ctx->acc[0] = acc0; + ctx->acc[1] = acc1; + ctx->acc[2] = acc2; + ctx->acc[3] = acc3; + ctx->acc[4] = acc4; +} + +/** + * \brief Compute the Poly1305 MAC + * + * \param ctx The Poly1305 context. + * \param mac The buffer to where the MAC is written. Must be + * big enough to contain the 16-byte MAC. + */ +static void poly1305_compute_mac(const mbedtls_poly1305_context *ctx, + unsigned char mac[16]) +{ + uint64_t d; + uint32_t g0, g1, g2, g3, g4; + uint32_t acc0, acc1, acc2, acc3, acc4; + uint32_t mask; + uint32_t mask_inv; + + acc0 = ctx->acc[0]; + acc1 = ctx->acc[1]; + acc2 = ctx->acc[2]; + acc3 = ctx->acc[3]; + acc4 = ctx->acc[4]; + + /* Before adding 's' we ensure that the accumulator is mod 2^130 - 5. + * We do this by calculating acc - (2^130 - 5), then checking if + * the 131st bit is set. If it is, then reduce: acc -= (2^130 - 5) + */ + + /* Calculate acc + -(2^130 - 5) */ + d = ((uint64_t) acc0 + 5U); + g0 = (uint32_t) d; + d = ((uint64_t) acc1 + (d >> 32)); + g1 = (uint32_t) d; + d = ((uint64_t) acc2 + (d >> 32)); + g2 = (uint32_t) d; + d = ((uint64_t) acc3 + (d >> 32)); + g3 = (uint32_t) d; + g4 = acc4 + (uint32_t) (d >> 32U); + + /* mask == 0xFFFFFFFF if 131st bit is set, otherwise mask == 0 */ + mask = (uint32_t) 0U - (g4 >> 2U); + mask_inv = ~mask; + + /* If 131st bit is set then acc=g, otherwise, acc is unmodified */ + acc0 = (acc0 & mask_inv) | (g0 & mask); + acc1 = (acc1 & mask_inv) | (g1 & mask); + acc2 = (acc2 & mask_inv) | (g2 & mask); + acc3 = (acc3 & mask_inv) | (g3 & mask); + + /* Add 's' */ + d = (uint64_t) acc0 + ctx->s[0]; + acc0 = (uint32_t) d; + d = (uint64_t) acc1 + ctx->s[1] + (d >> 32U); + acc1 = (uint32_t) d; + d = (uint64_t) acc2 + ctx->s[2] + (d >> 32U); + acc2 = (uint32_t) d; + acc3 += ctx->s[3] + (uint32_t) (d >> 32U); + + /* Compute MAC (128 least significant bits of the accumulator) */ + MBEDTLS_PUT_UINT32_LE(acc0, mac, 0); + MBEDTLS_PUT_UINT32_LE(acc1, mac, 4); + MBEDTLS_PUT_UINT32_LE(acc2, mac, 8); + MBEDTLS_PUT_UINT32_LE(acc3, mac, 12); +} + +void mbedtls_poly1305_init(mbedtls_poly1305_context *ctx) +{ + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_poly1305_context)); +} + +void mbedtls_poly1305_free(mbedtls_poly1305_context *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_poly1305_context)); +} + +int mbedtls_poly1305_starts(mbedtls_poly1305_context *ctx, + const unsigned char key[32]) +{ + /* r &= 0x0ffffffc0ffffffc0ffffffc0fffffff */ + ctx->r[0] = MBEDTLS_GET_UINT32_LE(key, 0) & 0x0FFFFFFFU; + ctx->r[1] = MBEDTLS_GET_UINT32_LE(key, 4) & 0x0FFFFFFCU; + ctx->r[2] = MBEDTLS_GET_UINT32_LE(key, 8) & 0x0FFFFFFCU; + ctx->r[3] = MBEDTLS_GET_UINT32_LE(key, 12) & 0x0FFFFFFCU; + + ctx->s[0] = MBEDTLS_GET_UINT32_LE(key, 16); + ctx->s[1] = MBEDTLS_GET_UINT32_LE(key, 20); + ctx->s[2] = MBEDTLS_GET_UINT32_LE(key, 24); + ctx->s[3] = MBEDTLS_GET_UINT32_LE(key, 28); + + /* Initial accumulator state */ + ctx->acc[0] = 0U; + ctx->acc[1] = 0U; + ctx->acc[2] = 0U; + ctx->acc[3] = 0U; + ctx->acc[4] = 0U; + + /* Queue initially empty */ + mbedtls_platform_zeroize(ctx->queue, sizeof(ctx->queue)); + ctx->queue_len = 0U; + + return 0; +} + +int mbedtls_poly1305_update(mbedtls_poly1305_context *ctx, + const unsigned char *input, + size_t ilen) +{ + size_t offset = 0U; + size_t remaining = ilen; + size_t queue_free_len; + size_t nblocks; + + if ((remaining > 0U) && (ctx->queue_len > 0U)) { + queue_free_len = (POLY1305_BLOCK_SIZE_BYTES - ctx->queue_len); + + if (ilen < queue_free_len) { + /* Not enough data to complete the block. + * Store this data with the other leftovers. + */ + memcpy(&ctx->queue[ctx->queue_len], + input, + ilen); + + ctx->queue_len += ilen; + + remaining = 0U; + } else { + /* Enough data to produce a complete block */ + memcpy(&ctx->queue[ctx->queue_len], + input, + queue_free_len); + + ctx->queue_len = 0U; + + poly1305_process(ctx, 1U, ctx->queue, 1U); /* add padding bit */ + + offset += queue_free_len; + remaining -= queue_free_len; + } + } + + if (remaining >= POLY1305_BLOCK_SIZE_BYTES) { + nblocks = remaining / POLY1305_BLOCK_SIZE_BYTES; + + poly1305_process(ctx, nblocks, &input[offset], 1U); + + offset += nblocks * POLY1305_BLOCK_SIZE_BYTES; + remaining %= POLY1305_BLOCK_SIZE_BYTES; + } + + if (remaining > 0U) { + /* Store partial block */ + ctx->queue_len = remaining; + memcpy(ctx->queue, &input[offset], remaining); + } + + return 0; +} + +int mbedtls_poly1305_finish(mbedtls_poly1305_context *ctx, + unsigned char mac[16]) +{ + /* Process any leftover data */ + if (ctx->queue_len > 0U) { + /* Add padding bit */ + ctx->queue[ctx->queue_len] = 1U; + ctx->queue_len++; + + /* Pad with zeroes */ + memset(&ctx->queue[ctx->queue_len], + 0, + POLY1305_BLOCK_SIZE_BYTES - ctx->queue_len); + + poly1305_process(ctx, 1U, /* Process 1 block */ + ctx->queue, 0U); /* Already padded above */ + } + + poly1305_compute_mac(ctx, mac); + + return 0; +} + +int mbedtls_poly1305_mac(const unsigned char key[32], + const unsigned char *input, + size_t ilen, + unsigned char mac[16]) +{ + mbedtls_poly1305_context ctx; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + mbedtls_poly1305_init(&ctx); + + ret = mbedtls_poly1305_starts(&ctx, key); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_poly1305_update(&ctx, input, ilen); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_poly1305_finish(&ctx, mac); + +cleanup: + mbedtls_poly1305_free(&ctx); + return ret; +} + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char test_keys[2][32] = +{ + { + 0x85, 0xd6, 0xbe, 0x78, 0x57, 0x55, 0x6d, 0x33, + 0x7f, 0x44, 0x52, 0xfe, 0x42, 0xd5, 0x06, 0xa8, + 0x01, 0x03, 0x80, 0x8a, 0xfb, 0x0d, 0xb2, 0xfd, + 0x4a, 0xbf, 0xf6, 0xaf, 0x41, 0x49, 0xf5, 0x1b + }, + { + 0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a, + 0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0, + 0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09, + 0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0 + } +}; + +static const unsigned char test_data[2][127] = +{ + { + 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x69, 0x63, 0x20, 0x46, 0x6f, + 0x72, 0x75, 0x6d, 0x20, 0x52, 0x65, 0x73, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x20, 0x47, 0x72, 0x6f, + 0x75, 0x70 + }, + { + 0x27, 0x54, 0x77, 0x61, 0x73, 0x20, 0x62, 0x72, + 0x69, 0x6c, 0x6c, 0x69, 0x67, 0x2c, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x6c, 0x69, 0x74, 0x68, 0x79, 0x20, 0x74, 0x6f, + 0x76, 0x65, 0x73, 0x0a, 0x44, 0x69, 0x64, 0x20, + 0x67, 0x79, 0x72, 0x65, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x67, 0x69, 0x6d, 0x62, 0x6c, 0x65, 0x20, + 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x62, 0x65, 0x3a, 0x0a, 0x41, 0x6c, 0x6c, + 0x20, 0x6d, 0x69, 0x6d, 0x73, 0x79, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x6f, 0x72, 0x6f, 0x67, 0x6f, 0x76, 0x65, + 0x73, 0x2c, 0x0a, 0x41, 0x6e, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x6d, 0x65, 0x20, + 0x72, 0x61, 0x74, 0x68, 0x73, 0x20, 0x6f, 0x75, + 0x74, 0x67, 0x72, 0x61, 0x62, 0x65, 0x2e + } +}; + +static const size_t test_data_len[2] = +{ + 34U, + 127U +}; + +static const unsigned char test_mac[2][16] = +{ + { + 0xa8, 0x06, 0x1d, 0xc1, 0x30, 0x51, 0x36, 0xc6, + 0xc2, 0x2b, 0x8b, 0xaf, 0x0c, 0x01, 0x27, 0xa9 + }, + { + 0x45, 0x41, 0x66, 0x9a, 0x7e, 0xaa, 0xee, 0x61, + 0xe7, 0x08, 0xdc, 0x7c, 0xbc, 0xc5, 0xeb, 0x62 + } +}; + +/* Make sure no other definition is already present. */ +#undef ASSERT + +#define ASSERT(cond, args) \ + do \ + { \ + if (!(cond)) \ + { \ + if (verbose != 0) \ + mbedtls_printf args; \ + \ + return -1; \ + } \ + } \ + while (0) + +int mbedtls_poly1305_self_test(int verbose) +{ + unsigned char mac[16]; + unsigned i; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + for (i = 0U; i < 2U; i++) { + if (verbose != 0) { + mbedtls_printf(" Poly1305 test %u ", i); + } + + ret = mbedtls_poly1305_mac(test_keys[i], + test_data[i], + test_data_len[i], + mac); + ASSERT(0 == ret, ("error code: %i\n", ret)); + + ASSERT(0 == memcmp(mac, test_mac[i], 16U), ("failed (mac)\n")); + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + return 0; +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_POLY1305_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_aead.c b/tf-psa-crypto/drivers/builtin/src/psa_crypto_aead.c new file mode 100644 index 0000000000..ca1982647e --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_aead.c @@ -0,0 +1,648 @@ +/* + * PSA AEAD entry points + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_PSA_CRYPTO_C) + +#include "psa_crypto_aead.h" +#include "psa_crypto_core.h" +#include "psa_crypto_cipher.h" + +#include +#include "mbedtls/platform.h" + +#include "mbedtls/private/ccm.h" +#include "mbedtls/private/chachapoly.h" +#include "mbedtls/private/cipher.h" +#include "mbedtls/private/gcm.h" +#include "mbedtls/private/error_common.h" + +#if defined(MBEDTLS_PSA_BUILTIN_AEAD) +static psa_status_t psa_aead_setup( + mbedtls_psa_aead_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + mbedtls_cipher_id_t cipher_id; + mbedtls_cipher_mode_t mode; + (void) key_buffer_size; + + status = mbedtls_cipher_values_from_psa(alg, attributes->type, + &mode, &cipher_id); + if (status != PSA_SUCCESS) { + return status; + } + + switch (PSA_ALG_AEAD_WITH_SHORTENED_TAG(alg, 0)) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) + case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, 0): + operation->alg = PSA_ALG_CCM; + /* CCM allows the following tag lengths: 4, 6, 8, 10, 12, 14, 16. + * The call to mbedtls_ccm_encrypt_and_tag or + * mbedtls_ccm_auth_decrypt will validate the tag length. */ + if (PSA_BLOCK_CIPHER_BLOCK_LENGTH(attributes->type) != 16) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + mbedtls_ccm_init(&operation->ctx.ccm); + status = mbedtls_to_psa_error( + mbedtls_ccm_setkey(&operation->ctx.ccm, cipher_id, + key_buffer, (unsigned int) attributes->bits)); + if (status != PSA_SUCCESS) { + return status; + } + break; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) + case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, 0): + operation->alg = PSA_ALG_GCM; + /* GCM allows the following tag lengths: 4, 8, 12, 13, 14, 15, 16. + * The call to mbedtls_gcm_crypt_and_tag or + * mbedtls_gcm_auth_decrypt will validate the tag length. */ + if (PSA_BLOCK_CIPHER_BLOCK_LENGTH(attributes->type) != 16) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + mbedtls_gcm_init(&operation->ctx.gcm); + status = mbedtls_to_psa_error( + mbedtls_gcm_setkey(&operation->ctx.gcm, cipher_id, + key_buffer, (unsigned int) attributes->bits)); + if (status != PSA_SUCCESS) { + return status; + } + break; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) + case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CHACHA20_POLY1305, 0): + operation->alg = PSA_ALG_CHACHA20_POLY1305; + /* We only support the default tag length. */ + if (alg != PSA_ALG_CHACHA20_POLY1305) { + return PSA_ERROR_NOT_SUPPORTED; + } + + mbedtls_chachapoly_init(&operation->ctx.chachapoly); + status = mbedtls_to_psa_error( + mbedtls_chachapoly_setkey(&operation->ctx.chachapoly, + key_buffer)); + if (status != PSA_SUCCESS) { + return status; + } + break; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ + + default: + (void) status; + (void) key_buffer; + return PSA_ERROR_NOT_SUPPORTED; + } + + operation->key_type = psa_get_key_type(attributes); + + operation->tag_length = PSA_ALG_AEAD_GET_TAG_LENGTH(alg); + + return PSA_SUCCESS; +} + +psa_status_t mbedtls_psa_aead_encrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *nonce, size_t nonce_length, + const uint8_t *additional_data, size_t additional_data_length, + const uint8_t *plaintext, size_t plaintext_length, + uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + mbedtls_psa_aead_operation_t operation = MBEDTLS_PSA_AEAD_OPERATION_INIT; + uint8_t *tag; + + status = psa_aead_setup(&operation, attributes, key_buffer, + key_buffer_size, alg); + + if (status != PSA_SUCCESS) { + goto exit; + } + + /* For all currently supported modes, the tag is at the end of the + * ciphertext. */ + if (ciphertext_size < (plaintext_length + operation.tag_length)) { + status = PSA_ERROR_BUFFER_TOO_SMALL; + goto exit; + } + tag = ciphertext + plaintext_length; + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) + if (operation.alg == PSA_ALG_CCM) { + status = mbedtls_to_psa_error( + mbedtls_ccm_encrypt_and_tag(&operation.ctx.ccm, + plaintext_length, + nonce, nonce_length, + additional_data, + additional_data_length, + plaintext, ciphertext, + tag, operation.tag_length)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) + if (operation.alg == PSA_ALG_GCM) { + status = mbedtls_to_psa_error( + mbedtls_gcm_crypt_and_tag(&operation.ctx.gcm, + MBEDTLS_GCM_ENCRYPT, + plaintext_length, + nonce, nonce_length, + additional_data, additional_data_length, + plaintext, ciphertext, + operation.tag_length, tag)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) + if (operation.alg == PSA_ALG_CHACHA20_POLY1305) { + if (operation.tag_length != 16) { + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; + } + status = mbedtls_to_psa_error( + mbedtls_chachapoly_encrypt_and_tag(&operation.ctx.chachapoly, + plaintext_length, + nonce, + additional_data, + additional_data_length, + plaintext, + ciphertext, + tag)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ + { + (void) tag; + (void) nonce; + (void) nonce_length; + (void) additional_data; + (void) additional_data_length; + (void) plaintext; + return PSA_ERROR_NOT_SUPPORTED; + } + + if (status == PSA_SUCCESS) { + *ciphertext_length = plaintext_length + operation.tag_length; + } + +exit: + mbedtls_psa_aead_abort(&operation); + + return status; +} + +/* Locate the tag in a ciphertext buffer containing the encrypted data + * followed by the tag. Return the length of the part preceding the tag in + * *plaintext_length. This is the size of the plaintext in modes where + * the encrypted data has the same size as the plaintext, such as + * CCM and GCM. */ +static psa_status_t psa_aead_unpadded_locate_tag(size_t tag_length, + const uint8_t *ciphertext, + size_t ciphertext_length, + size_t plaintext_size, + const uint8_t **p_tag) +{ + size_t payload_length; + if (tag_length > ciphertext_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + payload_length = ciphertext_length - tag_length; + if (payload_length > plaintext_size) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + *p_tag = ciphertext + payload_length; + return PSA_SUCCESS; +} + +psa_status_t mbedtls_psa_aead_decrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *nonce, size_t nonce_length, + const uint8_t *additional_data, size_t additional_data_length, + const uint8_t *ciphertext, size_t ciphertext_length, + uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + mbedtls_psa_aead_operation_t operation = MBEDTLS_PSA_AEAD_OPERATION_INIT; + const uint8_t *tag = NULL; + + status = psa_aead_setup(&operation, attributes, key_buffer, + key_buffer_size, alg); + + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_aead_unpadded_locate_tag(operation.tag_length, + ciphertext, ciphertext_length, + plaintext_size, &tag); + if (status != PSA_SUCCESS) { + goto exit; + } + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) + if (operation.alg == PSA_ALG_CCM) { + status = mbedtls_to_psa_error( + mbedtls_ccm_auth_decrypt(&operation.ctx.ccm, + ciphertext_length - operation.tag_length, + nonce, nonce_length, + additional_data, + additional_data_length, + ciphertext, plaintext, + tag, operation.tag_length)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) + if (operation.alg == PSA_ALG_GCM) { + status = mbedtls_to_psa_error( + mbedtls_gcm_auth_decrypt(&operation.ctx.gcm, + ciphertext_length - operation.tag_length, + nonce, nonce_length, + additional_data, + additional_data_length, + tag, operation.tag_length, + ciphertext, plaintext)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) + if (operation.alg == PSA_ALG_CHACHA20_POLY1305) { + if (operation.tag_length != 16) { + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; + } + status = mbedtls_to_psa_error( + mbedtls_chachapoly_auth_decrypt(&operation.ctx.chachapoly, + ciphertext_length - operation.tag_length, + nonce, + additional_data, + additional_data_length, + tag, + ciphertext, + plaintext)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ + { + (void) nonce; + (void) nonce_length; + (void) additional_data; + (void) additional_data_length; + (void) plaintext; + return PSA_ERROR_NOT_SUPPORTED; + } + + if (status == PSA_SUCCESS) { + *plaintext_length = ciphertext_length - operation.tag_length; + } + +exit: + mbedtls_psa_aead_abort(&operation); + + return status; +} + +/* Set the key and algorithm for a multipart authenticated encryption + * operation. */ +psa_status_t mbedtls_psa_aead_encrypt_setup( + mbedtls_psa_aead_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + status = psa_aead_setup(operation, attributes, key_buffer, + key_buffer_size, alg); + + if (status == PSA_SUCCESS) { + operation->is_encrypt = 1; + } + + return status; +} + +/* Set the key and algorithm for a multipart authenticated decryption + * operation. */ +psa_status_t mbedtls_psa_aead_decrypt_setup( + mbedtls_psa_aead_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + status = psa_aead_setup(operation, attributes, key_buffer, + key_buffer_size, alg); + + if (status == PSA_SUCCESS) { + operation->is_encrypt = 0; + } + + return status; +} + +/* Set a nonce for the multipart AEAD operation*/ +psa_status_t mbedtls_psa_aead_set_nonce( + mbedtls_psa_aead_operation_t *operation, + const uint8_t *nonce, + size_t nonce_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) + if (operation->alg == PSA_ALG_GCM) { + status = mbedtls_to_psa_error( + mbedtls_gcm_starts(&operation->ctx.gcm, + operation->is_encrypt ? + MBEDTLS_GCM_ENCRYPT : MBEDTLS_GCM_DECRYPT, + nonce, + nonce_length)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) + if (operation->alg == PSA_ALG_CCM) { + status = mbedtls_to_psa_error( + mbedtls_ccm_starts(&operation->ctx.ccm, + operation->is_encrypt ? + MBEDTLS_CCM_ENCRYPT : MBEDTLS_CCM_DECRYPT, + nonce, + nonce_length)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) + if (operation->alg == PSA_ALG_CHACHA20_POLY1305) { + /* Note - ChaChaPoly allows an 8 byte nonce, but we would have to + * allocate a buffer in the operation, copy the nonce to it and pad + * it, so for now check the nonce is 12 bytes, as + * mbedtls_chachapoly_starts() assumes it can read 12 bytes from the + * passed in buffer. */ + if (nonce_length != 12) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + status = mbedtls_to_psa_error( + mbedtls_chachapoly_starts(&operation->ctx.chachapoly, + nonce, + operation->is_encrypt ? + MBEDTLS_CHACHAPOLY_ENCRYPT : + MBEDTLS_CHACHAPOLY_DECRYPT)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ + { + (void) operation; + (void) nonce; + (void) nonce_length; + + return PSA_ERROR_NOT_SUPPORTED; + } + + return status; +} + +/* Declare the lengths of the message and additional data for AEAD. */ +psa_status_t mbedtls_psa_aead_set_lengths( + mbedtls_psa_aead_operation_t *operation, + size_t ad_length, + size_t plaintext_length) +{ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) + if (operation->alg == PSA_ALG_CCM) { + return mbedtls_to_psa_error( + mbedtls_ccm_set_lengths(&operation->ctx.ccm, + ad_length, + plaintext_length, + operation->tag_length)); + + } +#else /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ + (void) operation; + (void) ad_length; + (void) plaintext_length; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ + + return PSA_SUCCESS; +} + +/* Pass additional data to an active multipart AEAD operation. */ +psa_status_t mbedtls_psa_aead_update_ad( + mbedtls_psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) + if (operation->alg == PSA_ALG_GCM) { + status = mbedtls_to_psa_error( + mbedtls_gcm_update_ad(&operation->ctx.gcm, input, input_length)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) + if (operation->alg == PSA_ALG_CCM) { + status = mbedtls_to_psa_error( + mbedtls_ccm_update_ad(&operation->ctx.ccm, input, input_length)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) + if (operation->alg == PSA_ALG_CHACHA20_POLY1305) { + status = mbedtls_to_psa_error( + mbedtls_chachapoly_update_aad(&operation->ctx.chachapoly, + input, + input_length)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ + { + (void) operation; + (void) input; + (void) input_length; + + return PSA_ERROR_NOT_SUPPORTED; + } + + return status; +} + +/* Encrypt or decrypt a message fragment in an active multipart AEAD + * operation.*/ +psa_status_t mbedtls_psa_aead_update( + mbedtls_psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + size_t update_output_length; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + update_output_length = input_length; + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) + if (operation->alg == PSA_ALG_GCM) { + status = mbedtls_to_psa_error( + mbedtls_gcm_update(&operation->ctx.gcm, + input, input_length, + output, output_size, + &update_output_length)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) + if (operation->alg == PSA_ALG_CCM) { + if (output_size < input_length) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + status = mbedtls_to_psa_error( + mbedtls_ccm_update(&operation->ctx.ccm, + input, input_length, + output, output_size, + &update_output_length)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) + if (operation->alg == PSA_ALG_CHACHA20_POLY1305) { + if (output_size < input_length) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + status = mbedtls_to_psa_error( + mbedtls_chachapoly_update(&operation->ctx.chachapoly, + input_length, + input, + output)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ + { + (void) operation; + (void) input; + (void) output; + (void) output_size; + + return PSA_ERROR_NOT_SUPPORTED; + } + + if (status == PSA_SUCCESS) { + *output_length = update_output_length; + } + + return status; +} + +/* Finish encrypting a message in a multipart AEAD operation. */ +psa_status_t mbedtls_psa_aead_finish( + mbedtls_psa_aead_operation_t *operation, + uint8_t *ciphertext, + size_t ciphertext_size, + size_t *ciphertext_length, + uint8_t *tag, + size_t tag_size, + size_t *tag_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + size_t finish_output_size = 0; + + if (tag_size < operation->tag_length) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) + if (operation->alg == PSA_ALG_GCM) { + status = mbedtls_to_psa_error( + mbedtls_gcm_finish(&operation->ctx.gcm, + ciphertext, ciphertext_size, ciphertext_length, + tag, operation->tag_length)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) + if (operation->alg == PSA_ALG_CCM) { + /* tag must be big enough to store a tag of size passed into set + * lengths. */ + if (tag_size < operation->tag_length) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + status = mbedtls_to_psa_error( + mbedtls_ccm_finish(&operation->ctx.ccm, + tag, operation->tag_length)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) + if (operation->alg == PSA_ALG_CHACHA20_POLY1305) { + /* Belt and braces. Although the above tag_size check should have + * already done this, if we later start supporting smaller tag sizes + * for chachapoly, then passing a tag buffer smaller than 16 into here + * could cause a buffer overflow, so better safe than sorry. */ + if (tag_size < 16) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + status = mbedtls_to_psa_error( + mbedtls_chachapoly_finish(&operation->ctx.chachapoly, + tag)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ + { + (void) ciphertext; + (void) ciphertext_size; + (void) ciphertext_length; + (void) tag; + (void) tag_size; + (void) tag_length; + + return PSA_ERROR_NOT_SUPPORTED; + } + + if (status == PSA_SUCCESS) { + /* This will be zero for all supported algorithms currently, but left + * here for future support. */ + *ciphertext_length = finish_output_size; + *tag_length = operation->tag_length; + } + + return status; +} + +/* Abort an AEAD operation */ +psa_status_t mbedtls_psa_aead_abort( + mbedtls_psa_aead_operation_t *operation) +{ + switch (operation->alg) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) + case PSA_ALG_CCM: + mbedtls_ccm_free(&operation->ctx.ccm); + break; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) + case PSA_ALG_GCM: + mbedtls_gcm_free(&operation->ctx.gcm); + break; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) + case PSA_ALG_CHACHA20_POLY1305: + mbedtls_chachapoly_free(&operation->ctx.chachapoly); + break; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ + } + + operation->is_encrypt = 0; + + return PSA_SUCCESS; +} + +#endif /* MBEDTLS_PSA_BUILTIN_AEAD */ + +#endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_aead.h b/tf-psa-crypto/drivers/builtin/src/psa_crypto_aead.h new file mode 100644 index 0000000000..f4d7f778c2 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_aead.h @@ -0,0 +1,499 @@ +/* + * PSA AEAD driver entry points + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_AEAD_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_AEAD_H + +#include + +/** + * \brief Process an authenticated encryption operation. + * + * \note The signature of this function is that of a PSA driver + * aead_encrypt entry point. This function behaves as an aead_encrypt + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key context. + * \param key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param alg The AEAD algorithm to compute. + * \param[in] nonce Nonce or IV to use. + * \param nonce_length Size of the nonce buffer in bytes. This must + * be appropriate for the selected algorithm. + * The default nonce size is + * PSA_AEAD_NONCE_LENGTH(key_type, alg) where + * key_type is the type of key. + * \param[in] additional_data Additional data that will be authenticated + * but not encrypted. + * \param additional_data_length Size of additional_data in bytes. + * \param[in] plaintext Data that will be authenticated and encrypted. + * \param plaintext_length Size of plaintext in bytes. + * \param[out] ciphertext Output buffer for the authenticated and + * encrypted data. The additional data is not + * part of this output. For algorithms where the + * encrypted data and the authentication tag are + * defined as separate outputs, the + * authentication tag is appended to the + * encrypted data. + * \param ciphertext_size Size of the ciphertext buffer in bytes. This + * must be appropriate for the selected algorithm + * and key: + * - A sufficient output size is + * PSA_AEAD_ENCRYPT_OUTPUT_SIZE(key_type, alg, + * plaintext_length) where key_type is the type + * of key. + * - PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE( + * plaintext_length) evaluates to the maximum + * ciphertext size of any supported AEAD + * encryption. + * \param[out] ciphertext_length On success, the size of the output in the + * ciphertext buffer. + * + * \retval #PSA_SUCCESS Success. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p alg is not supported. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * ciphertext_size is too small. + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_aead_encrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *nonce, size_t nonce_length, + const uint8_t *additional_data, size_t additional_data_length, + const uint8_t *plaintext, size_t plaintext_length, + uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_length); + +/** + * \brief Process an authenticated decryption operation. + * + * \note The signature of this function is that of a PSA driver + * aead_decrypt entry point. This function behaves as an aead_decrypt + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key context. + * \param key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param alg The AEAD algorithm to compute. + * \param[in] nonce Nonce or IV to use. + * \param nonce_length Size of the nonce buffer in bytes. This must + * be appropriate for the selected algorithm. + * The default nonce size is + * PSA_AEAD_NONCE_LENGTH(key_type, alg) where + * key_type is the type of key. + * \param[in] additional_data Additional data that has been authenticated + * but not encrypted. + * \param additional_data_length Size of additional_data in bytes. + * \param[in] ciphertext Data that has been authenticated and + * encrypted. For algorithms where the encrypted + * data and the authentication tag are defined + * as separate inputs, the buffer contains + * encrypted data followed by the authentication + * tag. + * \param ciphertext_length Size of ciphertext in bytes. + * \param[out] plaintext Output buffer for the decrypted data. + * \param plaintext_size Size of the plaintext buffer in bytes. This + * must be appropriate for the selected algorithm + * and key: + * - A sufficient output size is + * PSA_AEAD_DECRYPT_OUTPUT_SIZE(key_type, alg, + * ciphertext_length) where key_type is the + * type of key. + * - PSA_AEAD_DECRYPT_OUTPUT_MAX_SIZE( + * ciphertext_length) evaluates to the maximum + * plaintext size of any supported AEAD + * decryption. + * \param[out] plaintext_length On success, the size of the output in the + * plaintext buffer. + * + * \retval #PSA_SUCCESS Success. + * \retval #PSA_ERROR_INVALID_SIGNATURE + * The cipher is not authentic. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p alg is not supported. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * plaintext_size is too small. + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_aead_decrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *nonce, size_t nonce_length, + const uint8_t *additional_data, size_t additional_data_length, + const uint8_t *ciphertext, size_t ciphertext_length, + uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_length); + +/** Set the key for a multipart authenticated encryption operation. + * + * \note The signature of this function is that of a PSA driver + * aead_encrypt_setup entry point. This function behaves as an + * aead_encrypt_setup entry point as defined in the PSA driver interface + * specification for transparent drivers. + * + * If an error occurs at any step after a call to + * mbedtls_psa_aead_encrypt_setup(), the operation is reset by the PSA core by a + * call to mbedtls_psa_aead_abort(). The PSA core may call + * mbedtls_psa_aead_abort() at any time after the operation has been + * initialized, and is required to when the operation is no longer needed. + * + * \param[in,out] operation The operation object to set up. It must have + * been initialized as per the documentation for + * #mbedtls_psa_aead_operation_t and not yet in + * use. + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key context. + * \param key_buffer_size Size of the \p key_buffer buffer in bytes. + It must be consistent with the size in bits + recorded in \p attributes. + * \param alg The AEAD algorithm to compute + * (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_AEAD(\p alg) is true). + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * An invalid block length was supplied. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p alg is not supported. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * Failed to allocate memory for key material + */ +psa_status_t mbedtls_psa_aead_encrypt_setup( + mbedtls_psa_aead_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg); + +/** Set the key for a multipart authenticated decryption operation. + * + * \note The signature of this function is that of a PSA driver + * aead_decrypt_setup entry point. This function behaves as an + * aead_decrypt_setup entry point as defined in the PSA driver interface + * specification for transparent drivers. + * + * If an error occurs at any step after a call to + * mbedtls_psa_aead_decrypt_setup(), the PSA core resets the operation by a + * call to mbedtls_psa_aead_abort(). The PSA core may call + * mbedtls_psa_aead_abort() at any time after the operation has been + * initialized, and is required to when the operation is no longer needed. + * + * \param[in,out] operation The operation object to set up. It must have + * been initialized as per the documentation for + * #mbedtls_psa_aead_operation_t and not yet in + * use. + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key context. + * \param key_buffer_size Size of the \p key_buffer buffer in bytes. + It must be consistent with the size in bits + recorded in \p attributes. + * \param alg The AEAD algorithm to compute + * (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_AEAD(\p alg) is true). + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * An invalid block length was supplied. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p alg is not supported. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * Failed to allocate memory for key material + */ +psa_status_t mbedtls_psa_aead_decrypt_setup( + mbedtls_psa_aead_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg); + +/** Set the nonce for an authenticated encryption or decryption operation. + * + * \note The signature of this function is that of a PSA driver aead_set_nonce + * entry point. This function behaves as an aead_set_nonce entry point as + * defined in the PSA driver interface specification for transparent + * drivers. + * + * This function sets the nonce for the authenticated + * encryption or decryption operation. + * + * The PSA core calls mbedtls_psa_aead_encrypt_setup() or + * mbedtls_psa_aead_decrypt_setup() before calling this function. + * + * If this function returns an error status, the PSA core will call + * mbedtls_psa_aead_abort(). + * + * \param[in,out] operation Active AEAD operation. + * \param[in] nonce Buffer containing the nonce to use. + * \param nonce_length Size of the nonce in bytes. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The size of \p nonce is not acceptable for the chosen algorithm. + * \retval #PSA_ERROR_NOT_SUPPORTED + * Algorithm previously set is not supported in this configuration of + * the library. + */ +psa_status_t mbedtls_psa_aead_set_nonce( + mbedtls_psa_aead_operation_t *operation, + const uint8_t *nonce, + size_t nonce_length); + +/** Declare the lengths of the message and additional data for AEAD. + * + * \note The signature of this function is that of a PSA driver aead_set_lengths + * entry point. This function behaves as an aead_set_lengths entry point + * as defined in the PSA driver interface specification for transparent + * drivers. + * + * The PSA core calls this function before calling mbedtls_psa_aead_update_ad() + * or mbedtls_psa_aead_update() if the algorithm for the operation requires it. + * If the algorithm does not require it, calling this function is optional, but + * if this function is called then the implementation must enforce the lengths. + * + * The PSA core may call this function before or after setting the nonce with + * mbedtls_psa_aead_set_nonce(). + * + * - For #PSA_ALG_CCM, calling this function is required. + * - For the other AEAD algorithms defined in this specification, calling + * this function is not required. + * + * If this function returns an error status, the PSA core calls + * mbedtls_psa_aead_abort(). + * + * \param[in,out] operation Active AEAD operation. + * \param ad_length Size of the non-encrypted additional + * authenticated data in bytes. + * \param plaintext_length Size of the plaintext to encrypt in bytes. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * At least one of the lengths is not acceptable for the chosen + * algorithm. + * \retval #PSA_ERROR_NOT_SUPPORTED + * Algorithm previously set is not supported in this configuration of + * the library. + */ +psa_status_t mbedtls_psa_aead_set_lengths( + mbedtls_psa_aead_operation_t *operation, + size_t ad_length, + size_t plaintext_length); + +/** Pass additional data to an active AEAD operation. + * + * \note The signature of this function is that of a PSA driver + * aead_update_ad entry point. This function behaves as an aead_update_ad + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * Additional data is authenticated, but not encrypted. + * + * The PSA core can call this function multiple times to pass successive + * fragments of the additional data. It will not call this function after + * passing data to encrypt or decrypt with mbedtls_psa_aead_update(). + * + * Before calling this function, the PSA core will: + * 1. Call either mbedtls_psa_aead_encrypt_setup() or + * mbedtls_psa_aead_decrypt_setup(). + * 2. Set the nonce with mbedtls_psa_aead_set_nonce(). + * + * If this function returns an error status, the PSA core will call + * mbedtls_psa_aead_abort(). + * + * \param[in,out] operation Active AEAD operation. + * \param[in] input Buffer containing the fragment of + * additional data. + * \param input_length Size of the \p input buffer in bytes. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_NOT_SUPPORTED + * Algorithm previously set is not supported in this configuration of + * the library. + */ +psa_status_t mbedtls_psa_aead_update_ad( + mbedtls_psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length); + +/** Encrypt or decrypt a message fragment in an active AEAD operation. + * + * \note The signature of this function is that of a PSA driver + * aead_update entry point. This function behaves as an aead_update entry + * point as defined in the PSA driver interface specification for + * transparent drivers. + * + * Before calling this function, the PSA core will: + * 1. Call either mbedtls_psa_aead_encrypt_setup() or + * mbedtls_psa_aead_decrypt_setup(). The choice of setup function + * determines whether this function encrypts or decrypts its input. + * 2. Set the nonce with mbedtls_psa_aead_set_nonce(). + * 3. Call mbedtls_psa_aead_update_ad() to pass all the additional data. + * + * If this function returns an error status, the PSA core will call + * mbedtls_psa_aead_abort(). + * + * This function does not require the input to be aligned to any + * particular block boundary. If the implementation can only process + * a whole block at a time, it must consume all the input provided, but + * it may delay the end of the corresponding output until a subsequent + * call to mbedtls_psa_aead_update(), mbedtls_psa_aead_finish() provides + * sufficient input. The amount of data that can be delayed in this way is + * bounded by #PSA_AEAD_UPDATE_OUTPUT_SIZE. + * + * \param[in,out] operation Active AEAD operation. + * \param[in] input Buffer containing the message fragment to + * encrypt or decrypt. + * \param input_length Size of the \p input buffer in bytes. + * \param[out] output Buffer where the output is to be written. + * \param output_size Size of the \p output buffer in bytes. + * This must be appropriate for the selected + * algorithm and key: + * - A sufficient output size is + * #PSA_AEAD_UPDATE_OUTPUT_SIZE(\c key_type, + * \c alg, \p input_length) where + * \c key_type is the type of key and \c alg is + * the algorithm that were used to set up the + * operation. + * - #PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE(\p + * input_length) evaluates to the maximum + * output size of any supported AEAD + * algorithm. + * \param[out] output_length On success, the number of bytes + * that make up the returned output. + * + * \retval #PSA_SUCCESS + * Success. + * + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p output buffer is too small. + * #PSA_AEAD_UPDATE_OUTPUT_SIZE(\c key_type, \c alg, \p input_length) or + * #PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE(\p input_length) can be used to + * determine the required buffer size. + */ +psa_status_t mbedtls_psa_aead_update( + mbedtls_psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** Finish encrypting a message in an AEAD operation. + * + * \note The signature of this function is that of a PSA driver + * aead_finish entry point. This function behaves as an aead_finish entry + * point as defined in the PSA driver interface specification for + * transparent drivers. + * + * The operation must have been set up by the PSA core with + * mbedtls_psa_aead_encrypt_setup(). + * + * This function finishes the authentication of the additional data + * formed by concatenating the inputs passed to preceding calls to + * mbedtls_psa_aead_update_ad() with the plaintext formed by concatenating the + * inputs passed to preceding calls to mbedtls_psa_aead_update(). + * + * This function has two output buffers: + * - \p ciphertext contains trailing ciphertext that was buffered from + * preceding calls to mbedtls_psa_aead_update(). + * - \p tag contains the authentication tag. + * + * Whether or not this function returns successfully, the PSA core subsequently + * calls mbedtls_psa_aead_abort() to deactivate the operation. + * + * \param[in,out] operation Active AEAD operation. + * \param[out] ciphertext Buffer where the last part of the ciphertext + * is to be written. + * \param ciphertext_size Size of the \p ciphertext buffer in bytes. + * This must be appropriate for the selected + * algorithm and key: + * - A sufficient output size is + * #PSA_AEAD_FINISH_OUTPUT_SIZE(\c key_type, + * \c alg) where \c key_type is the type of key + * and \c alg is the algorithm that were used to + * set up the operation. + * - #PSA_AEAD_FINISH_OUTPUT_MAX_SIZE evaluates to + * the maximum output size of any supported AEAD + * algorithm. + * \param[out] ciphertext_length On success, the number of bytes of + * returned ciphertext. + * \param[out] tag Buffer where the authentication tag is + * to be written. + * \param tag_size Size of the \p tag buffer in bytes. + * This must be appropriate for the selected + * algorithm and key: + * - The exact tag size is #PSA_AEAD_TAG_LENGTH(\c + * key_type, \c key_bits, \c alg) where + * \c key_type and \c key_bits are the type and + * bit-size of the key, and \c alg are the + * algorithm that were used in the call to + * mbedtls_psa_aead_encrypt_setup(). + * - #PSA_AEAD_TAG_MAX_SIZE evaluates to the + * maximum tag size of any supported AEAD + * algorithm. + * \param[out] tag_length On success, the number of bytes + * that make up the returned tag. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p tag buffer is too small. + * #PSA_AEAD_TAG_LENGTH(\c key_type, key_bits, \c alg) or + * #PSA_AEAD_TAG_MAX_SIZE can be used to determine the required \p tag + * buffer size. + */ +psa_status_t mbedtls_psa_aead_finish( + mbedtls_psa_aead_operation_t *operation, + uint8_t *ciphertext, + size_t ciphertext_size, + size_t *ciphertext_length, + uint8_t *tag, + size_t tag_size, + size_t *tag_length); + +/** Abort an AEAD operation. + * + * \note The signature of this function is that of a PSA driver + * aead_abort entry point. This function behaves as an aead_abort entry + * point as defined in the PSA driver interface specification for + * transparent drivers. + * + * Aborting an operation frees all associated resources except for the + * \p operation structure itself. Once aborted, the operation object + * can be reused for another operation by the PSA core by it calling + * mbedtls_psa_aead_encrypt_setup() or mbedtls_psa_aead_decrypt_setup() again. + * + * The PSA core may call this function any time after the operation object has + * been initialized as described in #mbedtls_psa_aead_operation_t. + * + * In particular, calling mbedtls_psa_aead_abort() after the operation has been + * terminated by a call to mbedtls_psa_aead_abort() or + * mbedtls_psa_aead_finish() is safe and has no effect. + * + * \param[in,out] operation Initialized AEAD operation. + * + * \retval #PSA_SUCCESS + * Success. + */ +psa_status_t mbedtls_psa_aead_abort( + mbedtls_psa_aead_operation_t *operation); + +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_AEAD_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_cipher.c b/tf-psa-crypto/drivers/builtin/src/psa_crypto_cipher.c new file mode 100644 index 0000000000..700822df77 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_cipher.c @@ -0,0 +1,752 @@ +/* + * PSA cipher driver entry points + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_PSA_CRYPTO_C) + +#include "psa_crypto_cipher.h" +#include "psa_crypto_core.h" +#include "psa_crypto_random_impl.h" +#include "constant_time_internal.h" + +#include "mbedtls/private/cipher.h" +#include "mbedtls/private/error_common.h" + +#include + +#if defined(MBEDTLS_PSA_BUILTIN_CIPHER) || \ + defined(MBEDTLS_PSA_BUILTIN_AEAD) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_AES) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ARIA) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_CAMELLIA) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_CHACHA20) +/* mbedtls_cipher_values_from_psa() below only checks if the proper build symbols + * are enabled, but it does not provide any compatibility check between them + * (i.e. if the specified key works with the specified algorithm). This helper + * function is meant to provide this support. + * mbedtls_cipher_info_from_psa() might be used for the same purpose, but it + * requires CIPHER_C to be enabled. + */ +static psa_status_t mbedtls_cipher_validate_values( + psa_algorithm_t alg, + psa_key_type_t key_type) +{ + /* Reduce code size - hinting to the compiler about what it can assume allows the compiler to + eliminate bits of the logic below. */ +#if !defined(PSA_WANT_KEY_TYPE_AES) + MBEDTLS_ASSUME(key_type != PSA_KEY_TYPE_AES); +#endif +#if !defined(PSA_WANT_KEY_TYPE_ARIA) + MBEDTLS_ASSUME(key_type != PSA_KEY_TYPE_ARIA); +#endif +#if !defined(PSA_WANT_KEY_TYPE_CAMELLIA) + MBEDTLS_ASSUME(key_type != PSA_KEY_TYPE_CAMELLIA); +#endif +#if !defined(PSA_WANT_KEY_TYPE_CHACHA20) + MBEDTLS_ASSUME(key_type != PSA_KEY_TYPE_CHACHA20); +#endif +#if !defined(PSA_WANT_ALG_CCM) + MBEDTLS_ASSUME(alg != PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, 0)); +#endif +#if !defined(PSA_WANT_ALG_GCM) + MBEDTLS_ASSUME(alg != PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, 0)); +#endif +#if !defined(PSA_WANT_ALG_STREAM_CIPHER) + MBEDTLS_ASSUME(alg != PSA_ALG_STREAM_CIPHER); +#endif +#if !defined(PSA_WANT_ALG_CHACHA20_POLY1305) + MBEDTLS_ASSUME(alg != PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CHACHA20_POLY1305, 0)); +#endif +#if !defined(PSA_WANT_ALG_CCM_STAR_NO_TAG) + MBEDTLS_ASSUME(alg != PSA_ALG_CCM_STAR_NO_TAG); +#endif +#if !defined(PSA_WANT_ALG_CTR) + MBEDTLS_ASSUME(alg != PSA_ALG_CTR); +#endif +#if !defined(PSA_WANT_ALG_CFB) + MBEDTLS_ASSUME(alg != PSA_ALG_CFB); +#endif +#if !defined(PSA_WANT_ALG_OFB) + MBEDTLS_ASSUME(alg != PSA_ALG_OFB); +#endif +#if !defined(PSA_WANT_ALG_ECB_NO_PADDING) + MBEDTLS_ASSUME(alg != PSA_ALG_ECB_NO_PADDING); +#endif +#if !defined(PSA_WANT_ALG_CBC_NO_PADDING) + MBEDTLS_ASSUME(alg != PSA_ALG_CBC_NO_PADDING); +#endif +#if !defined(PSA_WANT_ALG_CBC_PKCS7) + MBEDTLS_ASSUME(alg != PSA_ALG_CBC_PKCS7); +#endif +#if !defined(PSA_WANT_ALG_CMAC) + MBEDTLS_ASSUME(alg != PSA_ALG_CMAC); +#endif + + if (alg == PSA_ALG_STREAM_CIPHER || + alg == PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CHACHA20_POLY1305, 0)) { + if (key_type == PSA_KEY_TYPE_CHACHA20) { + return PSA_SUCCESS; + } + } + + if (alg == PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, 0) || + alg == PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, 0) || + alg == PSA_ALG_CCM_STAR_NO_TAG) { + if (key_type == PSA_KEY_TYPE_AES || + key_type == PSA_KEY_TYPE_ARIA || + key_type == PSA_KEY_TYPE_CAMELLIA) { + return PSA_SUCCESS; + } + } + + if (alg == PSA_ALG_CTR || + alg == PSA_ALG_CFB || + alg == PSA_ALG_OFB || + alg == PSA_ALG_XTS || + alg == PSA_ALG_ECB_NO_PADDING || + alg == PSA_ALG_CBC_NO_PADDING || + alg == PSA_ALG_CBC_PKCS7 || + alg == PSA_ALG_CMAC) { + if (key_type == PSA_KEY_TYPE_AES || + key_type == PSA_KEY_TYPE_ARIA || + key_type == PSA_KEY_TYPE_CAMELLIA) { + return PSA_SUCCESS; + } + } + + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t mbedtls_cipher_values_from_psa( + psa_algorithm_t alg, + psa_key_type_t key_type, + mbedtls_cipher_mode_t *mode, + mbedtls_cipher_id_t *cipher_id) +{ + mbedtls_cipher_id_t cipher_id_tmp; + if (PSA_ALG_IS_AEAD(alg)) { + alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(alg, 0); + } + + if (PSA_ALG_IS_CIPHER(alg) || PSA_ALG_IS_AEAD(alg)) { + switch (alg) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_STREAM_CIPHER) + case PSA_ALG_STREAM_CIPHER: + *mode = MBEDTLS_MODE_STREAM; + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CTR) + case PSA_ALG_CTR: + *mode = MBEDTLS_MODE_CTR; + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CFB) + case PSA_ALG_CFB: + *mode = MBEDTLS_MODE_CFB; + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_OFB) + case PSA_ALG_OFB: + *mode = MBEDTLS_MODE_OFB; + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING) + case PSA_ALG_ECB_NO_PADDING: + *mode = MBEDTLS_MODE_ECB; + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_NO_PADDING) + case PSA_ALG_CBC_NO_PADDING: + *mode = MBEDTLS_MODE_CBC; + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_PKCS7) + case PSA_ALG_CBC_PKCS7: + *mode = MBEDTLS_MODE_CBC; + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM_STAR_NO_TAG) + case PSA_ALG_CCM_STAR_NO_TAG: + *mode = MBEDTLS_MODE_CCM_STAR_NO_TAG; + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) + case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, 0): + *mode = MBEDTLS_MODE_CCM; + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) + case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, 0): + *mode = MBEDTLS_MODE_GCM; + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) + case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CHACHA20_POLY1305, 0): + *mode = MBEDTLS_MODE_CHACHAPOLY; + break; +#endif + default: + return PSA_ERROR_NOT_SUPPORTED; + } + } else if (alg == PSA_ALG_CMAC) { + *mode = MBEDTLS_MODE_ECB; + } else { + return PSA_ERROR_NOT_SUPPORTED; + } + + switch (key_type) { +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_AES) + case PSA_KEY_TYPE_AES: + cipher_id_tmp = MBEDTLS_CIPHER_ID_AES; + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ARIA) + case PSA_KEY_TYPE_ARIA: + cipher_id_tmp = MBEDTLS_CIPHER_ID_ARIA; + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_CAMELLIA) + case PSA_KEY_TYPE_CAMELLIA: + cipher_id_tmp = MBEDTLS_CIPHER_ID_CAMELLIA; + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_CHACHA20) + case PSA_KEY_TYPE_CHACHA20: + cipher_id_tmp = MBEDTLS_CIPHER_ID_CHACHA20; + break; +#endif + default: + return PSA_ERROR_NOT_SUPPORTED; + } + if (cipher_id != NULL) { + *cipher_id = cipher_id_tmp; + } + + return mbedtls_cipher_validate_values(alg, key_type); +} +#else +/* When MBEDTLS_PSA_BUILTIN_CIPHER, MBEDTLS_PSA_BUILTIN_AEAD, + * MBEDTLS_PSA_BUILTIN_KEY_TYPE_AES, MBEDTLS_PSA_BUILTIN_KEY_TYPE_ARIA, + * MBEDTLS_PSA_BUILTIN_KEY_TYPE_CAMELLIA and MBEDTLS_PSA_BUILTIN_CIPHER are + * not defined, the function mbedtls_cipher_values_from_psa() can only ever + * return PSA_ERROR_NOT_SUPPORTED. In that configuration, the compiler may + * report an error such as: + * "code will never be executed [-Werror,-Wunreachable-code]" + * on the line: + * if (cipher_id != NULL) { + * + * Since under these conditions the function can only return + * PSA_ERROR_NOT_SUPPORTED and still pulls in a non-trivial amount of code, + * provide a reduced version that simply returns PSA_ERROR_NOT_SUPPORTED. + * + * Note that when all the conditions above are met, this function is used + * by mbedtls_cipher_info_from_psa(), if built-in CMAC is additionally enabled. + */ +psa_status_t mbedtls_cipher_values_from_psa( + psa_algorithm_t alg, + psa_key_type_t key_type, + mbedtls_cipher_mode_t *mode, + mbedtls_cipher_id_t *cipher_id) +{ + (void) alg; + (void) key_type; + (void) mode; + (void) cipher_id; + + return PSA_ERROR_NOT_SUPPORTED; +} +#endif /* MBEDTLS_PSA_BUILTIN_CIPHER) || + MBEDTLS_PSA_BUILTIN_AEAD || + MBEDTLS_PSA_BUILTIN_KEY_TYPE_AES || + MBEDTLS_PSA_BUILTIN_KEY_TYPE_ARIA || + MBEDTLS_PSA_BUILTIN_KEY_TYPE_CAMELLIA || + MBEDTLS_PSA_BUILTIN_KEY_TYPE_CHACHA20 */ + +#if defined(MBEDTLS_CIPHER_C) +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_psa( + psa_algorithm_t alg, + psa_key_type_t key_type, + size_t key_bits, + mbedtls_cipher_id_t *cipher_id) +{ + mbedtls_cipher_mode_t mode; + psa_status_t status; + mbedtls_cipher_id_t cipher_id_tmp = MBEDTLS_CIPHER_ID_NONE; + + status = mbedtls_cipher_values_from_psa(alg, key_type, &mode, &cipher_id_tmp); + if (status != PSA_SUCCESS) { + return NULL; + } + if (cipher_id != NULL) { + *cipher_id = cipher_id_tmp; + } + + return mbedtls_cipher_info_from_values(cipher_id_tmp, (int) key_bits, mode); +} +#endif /* MBEDTLS_CIPHER_C */ + +#if defined(MBEDTLS_PSA_BUILTIN_CIPHER) + +static psa_status_t psa_cipher_setup( + mbedtls_psa_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, + mbedtls_operation_t cipher_operation) +{ + int ret = 0; + size_t key_bits; + const mbedtls_cipher_info_t *cipher_info = NULL; + psa_key_type_t key_type = attributes->type; + + (void) key_buffer_size; + + mbedtls_cipher_init(&operation->ctx.cipher); + + operation->alg = alg; + key_bits = attributes->bits; + cipher_info = mbedtls_cipher_info_from_psa(alg, key_type, + key_bits, NULL); + if (cipher_info == NULL) { + return PSA_ERROR_NOT_SUPPORTED; + } + + ret = mbedtls_cipher_setup(&operation->ctx.cipher, cipher_info); + if (ret != 0) { + goto exit; + } + + { + ret = mbedtls_cipher_setkey(&operation->ctx.cipher, key_buffer, + (int) key_bits, cipher_operation); + } + if (ret != 0) { + goto exit; + } + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_NO_PADDING) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_PKCS7) + switch (alg) { + case PSA_ALG_CBC_NO_PADDING: + ret = mbedtls_cipher_set_padding_mode(&operation->ctx.cipher, + MBEDTLS_PADDING_NONE); + break; + case PSA_ALG_CBC_PKCS7: + ret = mbedtls_cipher_set_padding_mode(&operation->ctx.cipher, + MBEDTLS_PADDING_PKCS7); + break; + default: + /* The algorithm doesn't involve padding. */ + ret = 0; + break; + } + if (ret != 0) { + goto exit; + } +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CBC_NO_PADDING || + MBEDTLS_PSA_BUILTIN_ALG_CBC_PKCS7 */ + + operation->block_length = (PSA_ALG_IS_STREAM_CIPHER(alg) ? 1 : + PSA_BLOCK_CIPHER_BLOCK_LENGTH(key_type)); + operation->iv_length = PSA_CIPHER_IV_LENGTH(key_type, alg); + +exit: + return mbedtls_to_psa_error(ret); +} + +psa_status_t mbedtls_psa_cipher_encrypt_setup( + mbedtls_psa_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg) +{ + return psa_cipher_setup(operation, attributes, + key_buffer, key_buffer_size, + alg, MBEDTLS_ENCRYPT); +} + +psa_status_t mbedtls_psa_cipher_decrypt_setup( + mbedtls_psa_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg) +{ + return psa_cipher_setup(operation, attributes, + key_buffer, key_buffer_size, + alg, MBEDTLS_DECRYPT); +} + +psa_status_t mbedtls_psa_cipher_set_iv( + mbedtls_psa_cipher_operation_t *operation, + const uint8_t *iv, size_t iv_length) +{ + if (iv_length != operation->iv_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return mbedtls_to_psa_error( + mbedtls_cipher_set_iv(&operation->ctx.cipher, + iv, iv_length)); +} + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING) +/** Process input for which the algorithm is set to ECB mode. + * + * This requires manual processing, since the PSA API is defined as being + * able to process arbitrary-length calls to psa_cipher_update() with ECB mode, + * but the underlying mbedtls_cipher_update only takes full blocks. + * + * \param ctx The mbedtls cipher context to use. It must have been + * set up for ECB. + * \param[in] input The input plaintext or ciphertext to process. + * \param input_length The number of bytes to process from \p input. + * This does not need to be aligned to a block boundary. + * If there is a partial block at the end of the input, + * it is stored in \p ctx for future processing. + * \param output The buffer where the output is written. It must be + * at least `BS * floor((p + input_length) / BS)` bytes + * long, where `p` is the number of bytes in the + * unprocessed partial block in \p ctx (with + * `0 <= p <= BS - 1`) and `BS` is the block size. + * \param output_length On success, the number of bytes written to \p output. + * \c 0 on error. + * + * \return #PSA_SUCCESS or an error from a hardware accelerator + */ +static psa_status_t psa_cipher_update_ecb( + mbedtls_cipher_context_t *ctx, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t *output_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + size_t block_size = mbedtls_cipher_info_get_block_size(ctx->cipher_info); + size_t internal_output_length = 0; + *output_length = 0; + + if (input_length == 0) { + status = PSA_SUCCESS; + goto exit; + } + + if (ctx->unprocessed_len > 0) { + /* Fill up to block size, and run the block if there's a full one. */ + size_t bytes_to_copy = block_size - ctx->unprocessed_len; + + if (input_length < bytes_to_copy) { + bytes_to_copy = input_length; + } + + memcpy(&(ctx->unprocessed_data[ctx->unprocessed_len]), + input, bytes_to_copy); + input_length -= bytes_to_copy; + input += bytes_to_copy; + ctx->unprocessed_len += bytes_to_copy; + + if (ctx->unprocessed_len == block_size) { + status = mbedtls_to_psa_error( + mbedtls_cipher_update(ctx, + ctx->unprocessed_data, + block_size, + output, &internal_output_length)); + + if (status != PSA_SUCCESS) { + goto exit; + } + + output += internal_output_length; + *output_length += internal_output_length; + ctx->unprocessed_len = 0; + } + } + + while (input_length >= block_size) { + /* Run all full blocks we have, one by one */ + status = mbedtls_to_psa_error( + mbedtls_cipher_update(ctx, input, + block_size, + output, &internal_output_length)); + + if (status != PSA_SUCCESS) { + goto exit; + } + + input_length -= block_size; + input += block_size; + + output += internal_output_length; + *output_length += internal_output_length; + } + + if (input_length > 0) { + /* Save unprocessed bytes for later processing */ + memcpy(&(ctx->unprocessed_data[ctx->unprocessed_len]), + input, input_length); + ctx->unprocessed_len += input_length; + } + + status = PSA_SUCCESS; + +exit: + return status; +} +#endif /* MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING */ + +psa_status_t mbedtls_psa_cipher_update( + mbedtls_psa_cipher_operation_t *operation, + const uint8_t *input, size_t input_length, + uint8_t *output, size_t output_size, size_t *output_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + size_t expected_output_size; + + if (!PSA_ALG_IS_STREAM_CIPHER(operation->alg)) { + /* Take the unprocessed partial block left over from previous + * update calls, if any, plus the input to this call. Remove + * the last partial block, if any. You get the data that will be + * output in this call. */ + expected_output_size = + (operation->ctx.cipher.unprocessed_len + input_length) + / operation->block_length * operation->block_length; + } else { + expected_output_size = input_length; + } + + if (output_size < expected_output_size) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING) + if (operation->alg == PSA_ALG_ECB_NO_PADDING) { + /* mbedtls_cipher_update has an API inconsistency: it will only + * process a single block at a time in ECB mode. Abstract away that + * inconsistency here to match the PSA API behaviour. */ + status = psa_cipher_update_ecb(&operation->ctx.cipher, + input, + input_length, + output, + output_length); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING */ + if (input_length == 0) { + /* There is no input, nothing to be done */ + *output_length = 0; + status = PSA_SUCCESS; + } else { + status = mbedtls_to_psa_error( + mbedtls_cipher_update(&operation->ctx.cipher, input, + input_length, output, output_length)); + + if (*output_length > output_size) { + return PSA_ERROR_CORRUPTION_DETECTED; + } + } + + return status; +} + +psa_status_t mbedtls_psa_cipher_finish( + mbedtls_psa_cipher_operation_t *operation, + uint8_t *output, size_t output_size, size_t *output_length) +{ + psa_status_t status = PSA_ERROR_GENERIC_ERROR; + size_t invalid_padding = 0; + + /* We will copy output_size bytes from temp_output_buffer to the + * output buffer. We can't use *output_length to determine how + * much to copy because we must not leak that value through timing + * when doing decryption with unpadding. But the underlying function + * is not guaranteed to write beyond *output_length. To ensure we don't + * leak the former content of the stack to the caller, wipe that + * former content. */ + uint8_t temp_output_buffer[MBEDTLS_MAX_BLOCK_LENGTH] = { 0 }; + if (output_size > sizeof(temp_output_buffer)) { + output_size = sizeof(temp_output_buffer); + } + + if (operation->ctx.cipher.unprocessed_len != 0) { + if (operation->alg == PSA_ALG_ECB_NO_PADDING || + operation->alg == PSA_ALG_CBC_NO_PADDING) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + } + + status = mbedtls_to_psa_error( + mbedtls_cipher_finish_padded(&operation->ctx.cipher, + temp_output_buffer, + output_length, + &invalid_padding)); + if (status != PSA_SUCCESS) { + goto exit; + } + + if (output_size == 0) { + ; /* Nothing to copy. Note that output may be NULL in this case. */ + } else { + /* Do not use the value of *output_length to determine how much + * to copy. When decrypting a padded cipher, the output length is + * sensitive, and leaking it could allow a padding oracle attack. */ + memcpy(output, temp_output_buffer, output_size); + } + + status = mbedtls_ct_error_if_else_0(invalid_padding, + PSA_ERROR_INVALID_PADDING); + mbedtls_ct_condition_t buffer_too_small = + mbedtls_ct_uint_lt(output_size, *output_length); + status = mbedtls_ct_error_if(buffer_too_small, + PSA_ERROR_BUFFER_TOO_SMALL, + status); + +exit: + mbedtls_platform_zeroize(temp_output_buffer, + sizeof(temp_output_buffer)); + return status; +} + +psa_status_t mbedtls_psa_cipher_abort( + mbedtls_psa_cipher_operation_t *operation) +{ + /* Sanity check (shouldn't happen: operation->alg should + * always have been initialized to a valid value). */ + if (!PSA_ALG_IS_CIPHER(operation->alg)) { + return PSA_ERROR_BAD_STATE; + } + + mbedtls_cipher_free(&operation->ctx.cipher); + + return PSA_SUCCESS; +} + +psa_status_t mbedtls_psa_cipher_encrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *iv, + size_t iv_length, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + mbedtls_psa_cipher_operation_t operation = MBEDTLS_PSA_CIPHER_OPERATION_INIT; + size_t update_output_length, finish_output_length; + + status = mbedtls_psa_cipher_encrypt_setup(&operation, attributes, + key_buffer, key_buffer_size, + alg); + if (status != PSA_SUCCESS) { + goto exit; + } + + if (iv_length > 0) { + status = mbedtls_psa_cipher_set_iv(&operation, iv, iv_length); + if (status != PSA_SUCCESS) { + goto exit; + } + } + + status = mbedtls_psa_cipher_update(&operation, input, input_length, + output, output_size, + &update_output_length); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = mbedtls_psa_cipher_finish( + &operation, + mbedtls_buffer_offset(output, update_output_length), + output_size - update_output_length, &finish_output_length); + if (status != PSA_SUCCESS) { + goto exit; + } + + *output_length = update_output_length + finish_output_length; + +exit: + if (status == PSA_SUCCESS) { + status = mbedtls_psa_cipher_abort(&operation); + } else { + mbedtls_psa_cipher_abort(&operation); + } + + return status; +} + +psa_status_t mbedtls_psa_cipher_decrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + mbedtls_psa_cipher_operation_t operation = MBEDTLS_PSA_CIPHER_OPERATION_INIT; + size_t olength, accumulated_length; + + status = mbedtls_psa_cipher_decrypt_setup(&operation, attributes, + key_buffer, key_buffer_size, + alg); + if (status != PSA_SUCCESS) { + goto exit; + } + + if (operation.iv_length > 0) { + status = mbedtls_psa_cipher_set_iv(&operation, + input, operation.iv_length); + if (status != PSA_SUCCESS) { + goto exit; + } + } + + status = mbedtls_psa_cipher_update( + &operation, + mbedtls_buffer_offset_const(input, operation.iv_length), + input_length - operation.iv_length, + output, output_size, &olength); + if (status != PSA_SUCCESS) { + goto exit; + } + + accumulated_length = olength; + + status = mbedtls_psa_cipher_finish( + &operation, + mbedtls_buffer_offset(output, accumulated_length), + output_size - accumulated_length, &olength); + + *output_length = accumulated_length + olength; + +exit: + /* C99 doesn't allow a declaration to follow a label */; + psa_status_t abort_status = mbedtls_psa_cipher_abort(&operation); + /* Normally abort shouldn't fail unless the operation is in a bad + * state, in which case we'd expect finish to fail with the same error. + * So it doesn't matter much which call's error code we pick when both + * fail. However, in unauthenticated decryption specifically, the + * distinction between PSA_SUCCESS and PSA_ERROR_INVALID_PADDING is + * security-sensitive (risk of a padding oracle attack), so here we + * must not have a code path that depends on the value of status. */ + if (abort_status != PSA_SUCCESS) { + status = abort_status; + } + + return status; +} +#endif /* MBEDTLS_PSA_BUILTIN_CIPHER */ + +#endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_cipher.h b/tf-psa-crypto/drivers/builtin/src/psa_crypto_cipher.h new file mode 100644 index 0000000000..7a73e6d33d --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_cipher.h @@ -0,0 +1,314 @@ +/* + * PSA cipher driver entry points and associated auxiliary functions + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_CIPHER_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_CIPHER_H + +#include +#include + +/** Get Mbed TLS cipher information given the cipher algorithm PSA identifier + * as well as the PSA type and size of the key to be used with the cipher + * algorithm. + * + * \param[in] alg PSA cipher algorithm identifier + * \param[in] key_type PSA key type + * \param[out] mode Mbed TLS cipher mode + * \param[out] cipher_id Mbed TLS cipher algorithm identifier + * + * \return On success \c PSA_SUCCESS is returned and key_bits, mode and cipher_id + * are properly updated. + * \c PSA_ERROR_NOT_SUPPORTED is returned if the cipher algorithm is not + * supported. + */ + +psa_status_t mbedtls_cipher_values_from_psa(psa_algorithm_t alg, psa_key_type_t key_type, + mbedtls_cipher_mode_t *mode, + mbedtls_cipher_id_t *cipher_id); + +#if defined(MBEDTLS_CIPHER_C) +/** Get Mbed TLS cipher information given the cipher algorithm PSA identifier + * as well as the PSA type and size of the key to be used with the cipher + * algorithm. + * + * \param alg PSA cipher algorithm identifier + * \param key_type PSA key type + * \param key_bits Size of the key in bits + * \param[out] cipher_id Mbed TLS cipher algorithm identifier + * + * \return The Mbed TLS cipher information of the cipher algorithm. + * \c NULL if the PSA cipher algorithm is not supported. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_psa( + psa_algorithm_t alg, psa_key_type_t key_type, size_t key_bits, + mbedtls_cipher_id_t *cipher_id); +#endif /* MBEDTLS_CIPHER_C */ + +/** + * \brief Set the key for a multipart symmetric encryption operation. + * + * \note The signature of this function is that of a PSA driver + * cipher_encrypt_setup entry point. This function behaves as a + * cipher_encrypt_setup entry point as defined in the PSA driver + * interface specification for transparent drivers. + * + * \param[in,out] operation The operation object to set up. It has been + * initialized as per the documentation for + * #psa_cipher_operation_t and not yet in use. + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key context. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] alg The cipher algorithm to compute + * (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_CIPHER(\p alg) is true). + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_cipher_encrypt_setup( + mbedtls_psa_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg); + +/** + * \brief Set the key for a multipart symmetric decryption operation. + * + * \note The signature of this function is that of a PSA driver + * cipher_decrypt_setup entry point. This function behaves as a + * cipher_decrypt_setup entry point as defined in the PSA driver + * interface specification for transparent drivers. + * + * \param[in,out] operation The operation object to set up. It has been + * initialized as per the documentation for + * #psa_cipher_operation_t and not yet in use. + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key context. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] alg The cipher algorithm to compute + * (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_CIPHER(\p alg) is true). + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_cipher_decrypt_setup( + mbedtls_psa_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg); + +/** Set the IV for a symmetric encryption or decryption operation. + * + * This function sets the IV (initialization vector), nonce + * or initial counter value for the encryption or decryption operation. + * + * \note The signature of this function is that of a PSA driver + * cipher_set_iv entry point. This function behaves as a + * cipher_set_iv entry point as defined in the PSA driver + * interface specification for transparent drivers. + * + * \param[in,out] operation Active cipher operation. + * \param[in] iv Buffer containing the IV to use. + * \param[in] iv_length Size of the IV in bytes. It is guaranteed by + * the core to be less or equal to + * PSA_CIPHER_IV_MAX_SIZE. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The size of \p iv is not acceptable for the chosen algorithm, + * or the chosen algorithm does not use an IV. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + */ +psa_status_t mbedtls_psa_cipher_set_iv( + mbedtls_psa_cipher_operation_t *operation, + const uint8_t *iv, size_t iv_length); + +/** Encrypt or decrypt a message fragment in an active cipher operation. + * + * \note The signature of this function is that of a PSA driver + * cipher_update entry point. This function behaves as a + * cipher_update entry point as defined in the PSA driver + * interface specification for transparent drivers. + * + * \param[in,out] operation Active cipher operation. + * \param[in] input Buffer containing the message fragment to + * encrypt or decrypt. + * \param[in] input_length Size of the \p input buffer in bytes. + * \param[out] output Buffer where the output is to be written. + * \param[in] output_size Size of the \p output buffer in bytes. + * \param[out] output_length On success, the number of bytes + * that make up the returned output. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p output buffer is too small. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + */ +psa_status_t mbedtls_psa_cipher_update( + mbedtls_psa_cipher_operation_t *operation, + const uint8_t *input, size_t input_length, + uint8_t *output, size_t output_size, size_t *output_length); + +/** Finish encrypting or decrypting a message in a cipher operation. + * + * \note The signature of this function is that of a PSA driver + * cipher_finish entry point. This function behaves as a + * cipher_finish entry point as defined in the PSA driver + * interface specification for transparent drivers. + * + * \param[in,out] operation Active cipher operation. + * \param[out] output Buffer where the output is to be written. + * \param[in] output_size Size of the \p output buffer in bytes. + * \param[out] output_length On success, the number of bytes + * that make up the returned output. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The total input size passed to this operation is not valid for + * this particular algorithm. For example, the algorithm is a based + * on block cipher and requires a whole number of blocks, but the + * total input size is not a multiple of the block size. + * \retval #PSA_ERROR_INVALID_PADDING + * This is a decryption operation for an algorithm that includes + * padding, and the ciphertext does not contain valid padding. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p output buffer is too small. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + */ +psa_status_t mbedtls_psa_cipher_finish( + mbedtls_psa_cipher_operation_t *operation, + uint8_t *output, size_t output_size, size_t *output_length); + +/** Abort a cipher operation. + * + * Aborting an operation frees all associated resources except for the + * \p operation structure itself. Once aborted, the operation object + * can be reused for another operation. + * + * \note The signature of this function is that of a PSA driver + * cipher_abort entry point. This function behaves as a + * cipher_abort entry point as defined in the PSA driver + * interface specification for transparent drivers. + * + * \param[in,out] operation Initialized cipher operation. + * + * \retval #PSA_SUCCESS \emptydescription + */ +psa_status_t mbedtls_psa_cipher_abort(mbedtls_psa_cipher_operation_t *operation); + +/** Encrypt a message using a symmetric cipher. + * + * \note The signature of this function is that of a PSA driver + * cipher_encrypt entry point. This function behaves as a + * cipher_encrypt entry point as defined in the PSA driver + * interface specification for transparent drivers. + * + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key context. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] alg The cipher algorithm to compute + * (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_CIPHER(\p alg) is true). + * \param[in] iv Buffer containing the IV for encryption. The + * IV has been generated by the core. + * \param[in] iv_length Size of the \p iv in bytes. + * \param[in] input Buffer containing the message to encrypt. + * \param[in] input_length Size of the \p input buffer in bytes. + * \param[in,out] output Buffer where the output is to be written. + * \param[in] output_size Size of the \p output buffer in bytes. + * \param[out] output_length On success, the number of bytes that make up + * the returned output. Initialized to zero + * by the core. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p output buffer is too small. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The size \p iv_length is not acceptable for the chosen algorithm, + * or the chosen algorithm does not use an IV. + * The total input size passed to this operation is not valid for + * this particular algorithm. For example, the algorithm is a based + * on block cipher and requires a whole number of blocks, but the + * total input size is not a multiple of the block size. + * \retval #PSA_ERROR_INVALID_PADDING + * This is a decryption operation for an algorithm that includes + * padding, and the ciphertext does not contain valid padding. + */ +psa_status_t mbedtls_psa_cipher_encrypt(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *iv, + size_t iv_length, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** Decrypt a message using a symmetric cipher. + * + * \note The signature of this function is that of a PSA driver + * cipher_decrypt entry point. This function behaves as a + * cipher_decrypt entry point as defined in the PSA driver + * interface specification for transparent drivers. + * + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key context. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] alg The cipher algorithm to compute + * (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_CIPHER(\p alg) is true). + * \param[in] input Buffer containing the iv and the ciphertext. + * \param[in] input_length Size of the \p input buffer in bytes. + * \param[out] output Buffer where the output is to be written. + * \param[in] output_size Size of the \p output buffer in bytes. + * \param[out] output_length On success, the number of bytes that make up + * the returned output. Initialized to zero + * by the core. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p output buffer is too small. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The size of \p iv is not acceptable for the chosen algorithm, + * or the chosen algorithm does not use an IV. + * The total input size passed to this operation is not valid for + * this particular algorithm. For example, the algorithm is a based + * on block cipher and requires a whole number of blocks, but the + * total input size is not a multiple of the block size. + * \retval #PSA_ERROR_INVALID_PADDING + * This is a decryption operation for an algorithm that includes + * padding, and the ciphertext does not contain valid padding. + */ +psa_status_t mbedtls_psa_cipher_decrypt(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_CIPHER_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.c b/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.c new file mode 100644 index 0000000000..156519f5f8 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.c @@ -0,0 +1,911 @@ +/* + * PSA ECP layer on top of Mbed TLS crypto + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_PSA_CRYPTO_C) + +#include +#include "psa_crypto_core.h" +#include "psa_crypto_ecp.h" +#include "psa_crypto_random_impl.h" +#include "psa_util_internal.h" + +#include +#include +#include "mbedtls/platform.h" + +#include +#include +#include + +#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) +#include "tf-psa-crypto/private/everest/x25519.h" +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_BASIC) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) +/* Helper function to verify if the provided EC's family and key bit size are valid. + * + * Note: "bits" parameter is used both as input and output and it might be updated + * in case provided input value is not multiple of 8 ("sloppy" bits). + */ +static int check_ecc_parameters(psa_ecc_family_t family, size_t *bits) +{ + switch (family) { + case PSA_ECC_FAMILY_SECP_R1: + switch (*bits) { + case 192: + case 224: + case 256: + case 384: + case 521: + return PSA_SUCCESS; + case 528: + *bits = 521; + return PSA_SUCCESS; + } + break; + + case PSA_ECC_FAMILY_BRAINPOOL_P_R1: + switch (*bits) { + case 256: + case 384: + case 512: + return PSA_SUCCESS; + } + break; + + case PSA_ECC_FAMILY_MONTGOMERY: + switch (*bits) { + case 448: + case 255: + return PSA_SUCCESS; + case 256: + *bits = 255; + return PSA_SUCCESS; + } + break; + + case PSA_ECC_FAMILY_SECP_K1: + switch (*bits) { + case 192: + case 256: + return PSA_SUCCESS; + } + break; + } + + return PSA_ERROR_INVALID_ARGUMENT; +} + +psa_status_t mbedtls_psa_ecp_load_representation( + psa_key_type_t type, size_t curve_bits, + const uint8_t *data, size_t data_length, + mbedtls_ecp_keypair **p_ecp) +{ + mbedtls_ecp_group_id grp_id = MBEDTLS_ECP_DP_NONE; + psa_status_t status; + mbedtls_ecp_keypair *ecp = NULL; + size_t curve_bytes = data_length; + int explicit_bits = (curve_bits != 0); + + if (PSA_KEY_TYPE_IS_PUBLIC_KEY(type) && + PSA_KEY_TYPE_ECC_GET_FAMILY(type) != PSA_ECC_FAMILY_MONTGOMERY) { + /* A Weierstrass public key is represented as: + * - The byte 0x04; + * - `x_P` as a `ceiling(m/8)`-byte string, big-endian; + * - `y_P` as a `ceiling(m/8)`-byte string, big-endian. + * So its data length is 2m+1 where m is the curve size in bits. + */ + if ((data_length & 1) == 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + curve_bytes = data_length / 2; + + /* Montgomery public keys are represented in compressed format, meaning + * their curve_bytes is equal to the amount of input. */ + + /* Private keys are represented in uncompressed private random integer + * format, meaning their curve_bytes is equal to the amount of input. */ + } + + if (explicit_bits) { + /* With an explicit bit-size, the data must have the matching length. */ + if (curve_bytes != PSA_BITS_TO_BYTES(curve_bits)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + } else { + /* We need to infer the bit-size from the data. Since the only + * information we have is the length in bytes, the value of curve_bits + * at this stage is rounded up to the nearest multiple of 8. */ + curve_bits = PSA_BYTES_TO_BITS(curve_bytes); + } + + /* Allocate and initialize a key representation. */ + ecp = mbedtls_calloc(1, sizeof(mbedtls_ecp_keypair)); + if (ecp == NULL) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + mbedtls_ecp_keypair_init(ecp); + + status = check_ecc_parameters(PSA_KEY_TYPE_ECC_GET_FAMILY(type), &curve_bits); + if (status != PSA_SUCCESS) { + goto exit; + } + + /* Load the group. */ + grp_id = mbedtls_ecc_group_from_psa(PSA_KEY_TYPE_ECC_GET_FAMILY(type), + curve_bits); + if (grp_id == MBEDTLS_ECP_DP_NONE) { + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; + } + + status = mbedtls_to_psa_error( + mbedtls_ecp_group_load(&ecp->grp, grp_id)); + if (status != PSA_SUCCESS) { + goto exit; + } + + /* Load the key material. */ + if (PSA_KEY_TYPE_IS_PUBLIC_KEY(type)) { + /* Load the public value. */ + status = mbedtls_to_psa_error( + mbedtls_ecp_point_read_binary(&ecp->grp, &ecp->Q, + data, + data_length)); + if (status != PSA_SUCCESS) { + goto exit; + } + + /* Check that the point is on the curve. */ + status = mbedtls_to_psa_error( + mbedtls_ecp_check_pubkey(&ecp->grp, &ecp->Q)); + if (status != PSA_SUCCESS) { + goto exit; + } + } else { + /* Load and validate the secret value. */ + status = mbedtls_to_psa_error( + mbedtls_ecp_read_key(ecp->grp.id, + ecp, + data, + data_length)); + if (status != PSA_SUCCESS) { + goto exit; + } + } + + *p_ecp = ecp; +exit: + if (status != PSA_SUCCESS) { + mbedtls_ecp_keypair_free(ecp); + mbedtls_free(ecp); + } + + return status; +} +#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_BASIC) || + * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || + * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || + * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) */ + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) + +psa_status_t mbedtls_psa_ecp_import_key( + const psa_key_attributes_t *attributes, + const uint8_t *data, size_t data_length, + uint8_t *key_buffer, size_t key_buffer_size, + size_t *key_buffer_length, size_t *bits) +{ + psa_status_t status; + mbedtls_ecp_keypair *ecp = NULL; + + /* Parse input */ + status = mbedtls_psa_ecp_load_representation(attributes->type, + attributes->bits, + data, + data_length, + &ecp); + if (status != PSA_SUCCESS) { + goto exit; + } + + if (PSA_KEY_TYPE_ECC_GET_FAMILY(attributes->type) == + PSA_ECC_FAMILY_MONTGOMERY) { + *bits = ecp->grp.nbits + 1; + } else { + *bits = ecp->grp.nbits; + } + + /* Re-export the data to PSA export format. There is currently no support + * for other input formats then the export format, so this is a 1-1 + * copy operation. */ + status = mbedtls_psa_ecp_export_key(attributes->type, + ecp, + key_buffer, + key_buffer_size, + key_buffer_length); +exit: + /* Always free the PK object (will also free contained ECP context) */ + mbedtls_ecp_keypair_free(ecp); + mbedtls_free(ecp); + + return status; +} + +psa_status_t mbedtls_psa_ecp_export_key(psa_key_type_t type, + mbedtls_ecp_keypair *ecp, + uint8_t *data, + size_t data_size, + size_t *data_length) +{ + psa_status_t status; + + if (PSA_KEY_TYPE_IS_PUBLIC_KEY(type)) { + /* Check whether the public part is loaded */ + if (mbedtls_ecp_is_zero(&ecp->Q)) { + /* Calculate the public key */ + status = mbedtls_to_psa_error( + mbedtls_ecp_mul(&ecp->grp, &ecp->Q, &ecp->d, &ecp->grp.G, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE)); + if (status != PSA_SUCCESS) { + return status; + } + } + + status = mbedtls_to_psa_error( + mbedtls_ecp_point_write_binary(&ecp->grp, &ecp->Q, + MBEDTLS_ECP_PF_UNCOMPRESSED, + data_length, + data, + data_size)); + if (status != PSA_SUCCESS) { + memset(data, 0, data_size); + } + + return status; + } else { + status = mbedtls_to_psa_error( + mbedtls_ecp_write_key_ext(ecp, data_length, data, data_size)); + return status; + } +} + +psa_status_t mbedtls_psa_ecp_export_public_key( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + uint8_t *data, size_t data_size, size_t *data_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_keypair *ecp = NULL; + + status = mbedtls_psa_ecp_load_representation( + attributes->type, attributes->bits, + key_buffer, key_buffer_size, &ecp); + if (status != PSA_SUCCESS) { + return status; + } + + status = mbedtls_psa_ecp_export_key( + PSA_KEY_TYPE_ECC_PUBLIC_KEY( + PSA_KEY_TYPE_ECC_GET_FAMILY(attributes->type)), + ecp, data, data_size, data_length); + + mbedtls_ecp_keypair_free(ecp); + mbedtls_free(ecp); + + return status; +} +#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || + * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || + * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) */ + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE) +psa_status_t mbedtls_psa_ecp_generate_key( + const psa_key_attributes_t *attributes, + uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length) +{ + psa_ecc_family_t curve = PSA_KEY_TYPE_ECC_GET_FAMILY( + attributes->type); + mbedtls_ecp_group_id grp_id = + mbedtls_ecc_group_from_psa(curve, attributes->bits); + if (grp_id == MBEDTLS_ECP_DP_NONE) { + return PSA_ERROR_NOT_SUPPORTED; + } + + mbedtls_ecp_keypair ecp; + mbedtls_ecp_keypair_init(&ecp); + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + ret = mbedtls_ecp_group_load(&ecp.grp, grp_id); + if (ret != 0) { + goto exit; + } + + ret = mbedtls_ecp_gen_privkey(&ecp.grp, &ecp.d, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE); + if (ret != 0) { + goto exit; + } + + ret = mbedtls_ecp_write_key_ext(&ecp, key_buffer_length, + key_buffer, key_buffer_size); + +exit: + mbedtls_ecp_keypair_free(&ecp); + return mbedtls_to_psa_error(ret); +} +#endif /* MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE */ + +/****************************************************************/ +/* ECDSA sign/verify */ +/****************************************************************/ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) +psa_status_t mbedtls_psa_ecdsa_sign_hash( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *hash, size_t hash_length, + uint8_t *signature, size_t signature_size, size_t *signature_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_keypair *ecp = NULL; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t curve_bytes; + mbedtls_mpi r, s; + + status = mbedtls_psa_ecp_load_representation(attributes->type, + attributes->bits, + key_buffer, + key_buffer_size, + &ecp); + if (status != PSA_SUCCESS) { + return status; + } + + curve_bytes = PSA_BITS_TO_BYTES(ecp->grp.pbits); + mbedtls_mpi_init(&r); + mbedtls_mpi_init(&s); + + if (signature_size < 2 * curve_bytes) { + ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + goto cleanup; + } + + if (PSA_ALG_ECDSA_IS_DETERMINISTIC(alg)) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) + psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH(alg); + mbedtls_md_type_t md_alg = mbedtls_md_type_from_psa_alg(hash_alg); + MBEDTLS_MPI_CHK(mbedtls_ecdsa_sign_det_ext( + &ecp->grp, &r, &s, + &ecp->d, hash, + hash_length, md_alg, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE)); +#else + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + goto cleanup; +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) */ + } else { + (void) alg; + MBEDTLS_MPI_CHK(mbedtls_ecdsa_sign(&ecp->grp, &r, &s, &ecp->d, + hash, hash_length, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE)); + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&r, + signature, + curve_bytes)); + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&s, + signature + curve_bytes, + curve_bytes)); +cleanup: + mbedtls_mpi_free(&r); + mbedtls_mpi_free(&s); + if (ret == 0) { + *signature_length = 2 * curve_bytes; + } + + mbedtls_ecp_keypair_free(ecp); + mbedtls_free(ecp); + + return mbedtls_to_psa_error(ret); +} + +psa_status_t mbedtls_psa_ecp_load_public_part(mbedtls_ecp_keypair *ecp) +{ + int ret = 0; + + /* Check whether the public part is loaded. If not, load it. */ + if (mbedtls_ecp_is_zero(&ecp->Q)) { + ret = mbedtls_ecp_mul(&ecp->grp, &ecp->Q, + &ecp->d, &ecp->grp.G, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE); + } + + return mbedtls_to_psa_error(ret); +} + +psa_status_t mbedtls_psa_ecdsa_verify_hash( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *hash, size_t hash_length, + const uint8_t *signature, size_t signature_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_keypair *ecp = NULL; + size_t curve_bytes; + mbedtls_mpi r, s; + + (void) alg; + + status = mbedtls_psa_ecp_load_representation(attributes->type, + attributes->bits, + key_buffer, + key_buffer_size, + &ecp); + if (status != PSA_SUCCESS) { + return status; + } + + curve_bytes = PSA_BITS_TO_BYTES(ecp->grp.pbits); + mbedtls_mpi_init(&r); + mbedtls_mpi_init(&s); + + if (signature_length != 2 * curve_bytes) { + status = PSA_ERROR_INVALID_SIGNATURE; + goto cleanup; + } + + status = mbedtls_to_psa_error(mbedtls_mpi_read_binary(&r, + signature, + curve_bytes)); + if (status != PSA_SUCCESS) { + goto cleanup; + } + + status = mbedtls_to_psa_error(mbedtls_mpi_read_binary(&s, + signature + curve_bytes, + curve_bytes)); + if (status != PSA_SUCCESS) { + goto cleanup; + } + + status = mbedtls_psa_ecp_load_public_part(ecp); + if (status != PSA_SUCCESS) { + goto cleanup; + } + + status = mbedtls_to_psa_error(mbedtls_ecdsa_verify(&ecp->grp, hash, + hash_length, &ecp->Q, + &r, &s)); +cleanup: + mbedtls_mpi_free(&r); + mbedtls_mpi_free(&s); + mbedtls_ecp_keypair_free(ecp); + mbedtls_free(ecp); + + return status; +} + +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \ + * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) */ + +/****************************************************************/ +/* ECDH Key Agreement */ +/****************************************************************/ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) +static psa_status_t ecdh_write_secret(const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *secret, + uint8_t *shared_secret, size_t shared_secret_size, + size_t *shared_secret_length) +{ + *shared_secret_length = PSA_BITS_TO_BYTES(grp->pbits); + if (shared_secret_size < *shared_secret_length) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + return mbedtls_to_psa_error( + mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY ? + mbedtls_mpi_write_binary_le(&secret->X, shared_secret, *shared_secret_length) : + mbedtls_mpi_write_binary(&secret->X, shared_secret, *shared_secret_length)); +} + +#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) +static psa_status_t ecdh_everest_shared_secret( + const uint8_t *key_buffer, size_t key_buffer_size, + const uint8_t *peer_key, size_t peer_key_length, + uint8_t *shared_secret, size_t shared_secret_size, + size_t *shared_secret_length) +{ + /* This static function is only called when we know the curve is x25519, + * so we know key_buffer_size is correct unless the keystore is corrupted. + * However even in that case we don't want the consequence to be a memory + * error, so check anyway. This cannot be covered by tests though. */ + if (key_buffer_size != MBEDTLS_X25519_KEY_SIZE_BYTES) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* peer_key_length comes from the outside and could be incorrect */ + if (peer_key_length != MBEDTLS_X25519_KEY_SIZE_BYTES) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + *shared_secret_length = MBEDTLS_X25519_KEY_SIZE_BYTES; + if (shared_secret_size < *shared_secret_length) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + mbedtls_x25519_scalarmult(shared_secret, key_buffer, peer_key); + + return PSA_SUCCESS; +} +#endif /* MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED */ + +psa_status_t mbedtls_psa_key_agreement_ecdh( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *peer_key, size_t peer_key_length, + uint8_t *shared_secret, size_t shared_secret_size, + size_t *shared_secret_length) +{ + mbedtls_ecp_keypair *our_key = NULL; + mbedtls_ecp_keypair *their_key = NULL; + mbedtls_ecp_point secret; + mbedtls_ecp_point_init(&secret); + + psa_status_t status; + if (!PSA_KEY_TYPE_IS_ECC_KEY_PAIR(attributes->type) || + !PSA_ALG_IS_ECDH(alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + +#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) + if (attributes->type == PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY) && + attributes->bits == 255) { + return ecdh_everest_shared_secret(key_buffer, key_buffer_size, + peer_key, peer_key_length, + shared_secret, shared_secret_size, + shared_secret_length); + } +#endif /* MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED */ + + status = mbedtls_psa_ecp_load_representation( + attributes->type, + attributes->bits, + key_buffer, + key_buffer_size, + &our_key); + if (status != PSA_SUCCESS) { + return status; + } + + size_t bits = 0; + psa_ecc_family_t curve = mbedtls_ecc_group_to_psa(our_key->grp.id, &bits); + + status = mbedtls_psa_ecp_load_representation( + PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve), + bits, + peer_key, + peer_key_length, + &their_key); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = mbedtls_to_psa_error( + mbedtls_ecp_mul(&our_key->grp, &secret, &our_key->d, &their_key->Q, + mbedtls_psa_get_random, MBEDTLS_PSA_RANDOM_STATE)); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = ecdh_write_secret(&our_key->grp, &secret, + shared_secret, shared_secret_size, shared_secret_length); + +exit: + if (status != PSA_SUCCESS) { + mbedtls_platform_zeroize(shared_secret, shared_secret_size); + } + mbedtls_ecp_point_free(&secret); + mbedtls_ecp_keypair_free(their_key); + mbedtls_free(their_key); + mbedtls_ecp_keypair_free(our_key); + mbedtls_free(our_key); + return status; +} +#endif /* MBEDTLS_PSA_BUILTIN_ALG_ECDH */ + +/****************************************************************/ +/* Interruptible ECC Key Generation */ +/****************************************************************/ + +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE) + +uint32_t mbedtls_psa_generate_key_iop_get_num_ops( + mbedtls_psa_generate_key_iop_t *operation) +{ + return operation->num_ops; +} + +psa_status_t mbedtls_psa_ecp_generate_key_iop_setup( + mbedtls_psa_generate_key_iop_t *operation, + const psa_key_attributes_t *attributes) +{ + int status = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + mbedtls_ecp_keypair_init(&operation->ecp); + + psa_ecc_family_t curve = PSA_KEY_TYPE_ECC_GET_FAMILY( + psa_get_key_type(attributes)); + mbedtls_ecp_group_id grp_id = + mbedtls_ecc_group_from_psa(curve, psa_get_key_bits(attributes)); + if (grp_id == MBEDTLS_ECP_DP_NONE) { + return PSA_ERROR_NOT_SUPPORTED; + } + + status = mbedtls_ecp_group_load(&operation->ecp.grp, grp_id); + + return mbedtls_to_psa_error(status); +} + +psa_status_t mbedtls_psa_ecp_generate_key_iop_complete( + mbedtls_psa_generate_key_iop_t *operation, + uint8_t *key_output, + size_t key_output_size, + size_t *key_len) +{ + *key_len = 0; + int status = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + *key_len = PSA_BITS_TO_BYTES(operation->ecp.grp.nbits); + + if (*key_len > key_output_size) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + status = mbedtls_ecp_gen_privkey(&operation->ecp.grp, &operation->ecp.d, + mbedtls_psa_get_random, MBEDTLS_PSA_RANDOM_STATE); + + if (status != 0) { + return mbedtls_to_psa_error(status); + } + + /* Our implementation of key generation only generates the private key + which doesn't invlolve any ECC arithmetic operations so number of ops + is less than 1 but we round up to 1 to differentiate between num ops of + 0 which means no work has been done this facilitates testing. */ + operation->num_ops = 1; + + status = mbedtls_mpi_write_binary(&operation->ecp.d, key_output, key_output_size); + + return mbedtls_to_psa_error(status); +} + +psa_status_t mbedtls_psa_ecp_generate_key_iop_abort( + mbedtls_psa_generate_key_iop_t *operation) +{ + mbedtls_ecp_keypair_free(&operation->ecp); + operation->num_ops = 0; + return PSA_SUCCESS; +} + +#endif /* MBEDTLS_ECP_RESTARTABLE && MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE */ + +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + (defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY)) + +uint32_t mbedtls_psa_ecp_export_public_key_iop_get_num_ops( + mbedtls_psa_export_public_key_iop_t *operation) +{ + return operation->num_ops; +} + +psa_status_t mbedtls_psa_ecp_export_public_key_iop_setup( + mbedtls_psa_export_public_key_iop_t *operation, + uint8_t *key, + size_t key_len, + const psa_key_attributes_t *key_attributes) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + status = mbedtls_psa_ecp_load_representation( + psa_get_key_type(key_attributes), + psa_get_key_bits(key_attributes), + key, + key_len, + &operation->key); + if (status != PSA_SUCCESS) { + goto exit; + } + + mbedtls_ecp_restart_init(&operation->restart_ctx); + operation->num_ops = 0; + +exit: + return status; +} + +psa_status_t mbedtls_psa_ecp_export_public_key_iop_complete( + mbedtls_psa_export_public_key_iop_t *operation, + uint8_t *pub_key, + size_t pub_key_size, + size_t *pub_key_len) +{ + int ret = 0; + + if (mbedtls_ecp_is_zero(&operation->key->Q)) { + mbedtls_psa_interruptible_set_max_ops(psa_interruptible_get_max_ops()); + + ret = mbedtls_ecp_mul_restartable(&operation->key->grp, &operation->key->Q, + &operation->key->d, &operation->key->grp.G, + mbedtls_psa_get_random, MBEDTLS_PSA_RANDOM_STATE, + &operation->restart_ctx); + operation->num_ops += operation->restart_ctx.ops_done; + } + + if (ret == 0) { + ret = mbedtls_ecp_write_public_key(operation->key, + MBEDTLS_ECP_PF_UNCOMPRESSED, pub_key_len, + pub_key, pub_key_size); + } + + return mbedtls_to_psa_error(ret); +} + +psa_status_t mbedtls_psa_ecp_export_public_key_iop_abort( + mbedtls_psa_export_public_key_iop_t *operation) +{ + mbedtls_ecp_keypair_free(operation->key); + mbedtls_free(operation->key); + mbedtls_ecp_restart_free(&operation->restart_ctx); + operation->num_ops = 0; + return PSA_SUCCESS; +} + +#endif /* MBEDTLS_ECP_RESTARTABLE && \ + (MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT || + MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT || \ + MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) */ + +/****************************************************************/ +/* Interruptible ECC Key Agreement */ +/****************************************************************/ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) && defined(MBEDTLS_ECP_RESTARTABLE) + +uint32_t mbedtls_psa_key_agreement_iop_get_num_ops( + mbedtls_psa_key_agreement_interruptible_operation_t *operation) +{ + return operation->num_ops; +} + +psa_status_t mbedtls_psa_key_agreement_iop_setup( + mbedtls_psa_key_agreement_interruptible_operation_t *operation, + const psa_key_attributes_t *private_key_attributes, + const uint8_t *private_key_buffer, + size_t private_key_buffer_len, + const uint8_t *peer_key, + size_t peer_key_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + /* We need to clear number of ops here in case there was a previous + complete operation which doesn't reset it after finsishing. */ + operation->num_ops = 0; + + psa_key_type_t private_key_type = psa_get_key_type(private_key_attributes); + if (!PSA_KEY_TYPE_IS_ECC_KEY_PAIR(private_key_type)) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + status = mbedtls_psa_ecp_load_representation( + psa_get_key_type(private_key_attributes), + psa_get_key_bits(private_key_attributes), + private_key_buffer, + private_key_buffer_len, + &operation->our_key); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = mbedtls_psa_ecp_load_representation( + PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(private_key_type), + psa_get_key_bits(private_key_attributes), + peer_key, + peer_key_length, + &operation->their_key); + if (status != PSA_SUCCESS) { + goto exit; + } + + /* mbedtls_psa_ecp_load_representation() calls mbedtls_ecp_check_pubkey() which + takes MBEDTLS_ECP_OPS_CHK amount of ops. */ + operation->num_ops += MBEDTLS_ECP_OPS_CHK; + +exit: + return status; +} + +psa_status_t mbedtls_psa_key_agreement_iop_complete( + mbedtls_psa_key_agreement_interruptible_operation_t *operation, + uint8_t *shared_secret, + size_t shared_secret_size, + size_t *shared_secret_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_point secret; + + mbedtls_ecp_point_init(&secret); + + mbedtls_psa_interruptible_set_max_ops(psa_interruptible_get_max_ops()); + + status = mbedtls_to_psa_error( + mbedtls_ecp_mul_restartable(&operation->our_key->grp, + &secret, + &operation->our_key->d, + &operation->their_key->Q, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE, + &operation->rs)); + operation->num_ops += operation->rs.ops_done; + if (status != PSA_SUCCESS) { + goto exit; + } + + status = ecdh_write_secret(&operation->our_key->grp, &secret, + shared_secret, shared_secret_size, shared_secret_length); + +exit: + mbedtls_ecp_point_free(&secret); + + return status; +} + +psa_status_t mbedtls_psa_key_agreement_iop_abort( + mbedtls_psa_key_agreement_interruptible_operation_t *operation) +{ + mbedtls_ecp_keypair_free(operation->our_key); + mbedtls_free(operation->our_key); + operation->our_key = NULL; + + mbedtls_ecp_keypair_free(operation->their_key); + mbedtls_free(operation->their_key); + operation->their_key = NULL; + + mbedtls_ecp_restart_free(&operation->rs); + operation->num_ops = 0; + + return PSA_SUCCESS; +} + +#endif /* MBEDTLS_PSA_BUILTIN_ALG_ECDH */ + +#endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.h b/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.h new file mode 100644 index 0000000000..b6b1bc1074 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.h @@ -0,0 +1,516 @@ +/* + * PSA ECP layer on top of Mbed TLS crypto + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_ECP_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_ECP_H + +#include +#include + +/** Load the contents of a key buffer into an internal ECP representation + * + * \param[in] type The type of key contained in \p data. + * \param[in] curve_bits The nominal bit-size of the curve. + * It must be consistent with the representation + * passed in \p data. + * This can be 0, in which case the bit-size + * is inferred from \p data_length (which is possible + * for all key types and representation formats + * formats that are currently supported or will + * be in the foreseeable future). + * \param[in] data The buffer from which to load the representation. + * \param[in] data_length The size in bytes of \p data. + * \param[out] p_ecp Returns a pointer to an ECP context on success. + * The caller is responsible for freeing both the + * contents of the context and the context itself + * when done. + */ +psa_status_t mbedtls_psa_ecp_load_representation(psa_key_type_t type, + size_t curve_bits, + const uint8_t *data, + size_t data_length, + mbedtls_ecp_keypair **p_ecp); + +/** Load the public part of an internal ECP, if required. + * + * \param ecp The ECP context to load the public part for. + * + * \return PSA_SUCCESS on success, otherwise an MPI error. + */ + +psa_status_t mbedtls_psa_ecp_load_public_part(mbedtls_ecp_keypair *ecp); + +/** Import an ECP key in binary format. + * + * \note The signature of this function is that of a PSA driver + * import_key entry point. This function behaves as an import_key + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \param[in] attributes The attributes for the key to import. + * \param[in] data The buffer containing the key data in import + * format. + * \param[in] data_length Size of the \p data buffer in bytes. + * \param[out] key_buffer The buffer containing the key data in output + * format. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. This + * size is greater or equal to \p data_length. + * \param[out] key_buffer_length The length of the data written in \p + * key_buffer in bytes. + * \param[out] bits The key size in number of bits. + * + * \retval #PSA_SUCCESS The ECP key was imported successfully. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The key data is not correctly formatted. + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_ecp_import_key( + const psa_key_attributes_t *attributes, + const uint8_t *data, size_t data_length, + uint8_t *key_buffer, size_t key_buffer_size, + size_t *key_buffer_length, size_t *bits); + +/** Export an ECP key to export representation + * + * \param[in] type The type of key (public/private) to export + * \param[in] ecp The internal ECP representation from which to export + * \param[out] data The buffer to export to + * \param[in] data_size The length of the buffer to export to + * \param[out] data_length The amount of bytes written to \p data + */ +psa_status_t mbedtls_psa_ecp_export_key(psa_key_type_t type, + mbedtls_ecp_keypair *ecp, + uint8_t *data, + size_t data_size, + size_t *data_length); + +/** Export an ECP public key or the public part of an ECP key pair in binary + * format. + * + * \note The signature of this function is that of a PSA driver + * export_public_key entry point. This function behaves as an + * export_public_key entry point as defined in the PSA driver interface + * specification. + * + * \param[in] attributes The attributes for the key to export. + * \param[in] key_buffer Material or context of the key to export. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[out] data Buffer where the key data is to be written. + * \param[in] data_size Size of the \p data buffer in bytes. + * \param[out] data_length On success, the number of bytes written in + * \p data + * + * \retval #PSA_SUCCESS The ECP public key was exported successfully. + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription + * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + */ +psa_status_t mbedtls_psa_ecp_export_public_key( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + uint8_t *data, size_t data_size, size_t *data_length); + +/** + * \brief Get the total number of ops that an export public-key operation has taken + * Since it's start. + * + * \param[in] operation The \c mbedtls_psa_export_public_key_iop_t to use. + * + * \return Total number of operations. + */ +uint32_t mbedtls_psa_ecp_export_public_key_iop_get_num_ops( + mbedtls_psa_export_public_key_iop_t *operation); + +/** + * \brief Setup a new interruptible export public-key operation. + * + * \param[in] operation The \c mbedtls_psa_export_public_key_iop_t to use. + * This must be initialized first. + * \param[in] private_key pointer to private key. + * \param[in] private_key_len size of \p private_key in bytes. + * \param[in] private_key_attributes Key attributes of the private key. + * + * \retval #PSA_SUCCESS + * The operation started successfully - call \c mbedtls_psa_ecp_export_public_key_iop_complete() + * with the same operation to complete the operation. + * \retval #PSA_ERROR_NOT_SUPPORTED + * Either no internal interruptible operations are + * currently supported, or the key attributes are not unsupported. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * There was insufficient memory to load the key representation. + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * + */ +psa_status_t mbedtls_psa_ecp_export_public_key_iop_setup( + mbedtls_psa_export_public_key_iop_t *operation, + uint8_t *private_key, + size_t private_key_len, + const psa_key_attributes_t *private_key_attributes); + + +/** + * \brief Continue and eventually complete an export public-key operation. + * + * \param[in] operation The \c mbedtls_psa_export_public_key_iop_t to use. + * This must be initialized first and + * had \c mbedtls_psa_ecp_export_public_key_iop_setup() + * called successfully. + * \param[out] pub_key Buffer where the public key data is to be written. + * \param[in] pub_key_size Size of the \p pub_key buffer in bytes. + * \param[out] pub_key_len On success, the number of bytes that make up the public key data. + * + * \retval #PSA_SUCCESS + * The key was exported successfully. + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_BUFFER_TOO_SMALL \emptydescription + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * + */ +psa_status_t mbedtls_psa_ecp_export_public_key_iop_complete( + mbedtls_psa_export_public_key_iop_t *operation, + uint8_t *pub_key, + size_t pub_key_size, + size_t *pub_key_len); + +/** + * \brief Abort an interruptible export public-key operation. + * + * \param[in] operation The \c mbedtls_psa_export_public_key_iop_t to abort. + * + * \retval #PSA_SUCCESS + * The operation was aborted successfully. + */ +psa_status_t mbedtls_psa_ecp_export_public_key_iop_abort( + mbedtls_psa_export_public_key_iop_t *operation); + +/** + * \brief Generate an ECP key. + * + * \note The signature of the function is that of a PSA driver generate_key + * entry point. + * + * \param[in] attributes The attributes for the ECP key to generate. + * \param[out] key_buffer Buffer where the key data is to be written. + * \param[in] key_buffer_size Size of \p key_buffer in bytes. + * \param[out] key_buffer_length On success, the number of bytes written in + * \p key_buffer. + * + * \retval #PSA_SUCCESS + * The key was successfully generated. + * \retval #PSA_ERROR_NOT_SUPPORTED + * Key length or type not supported. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of \p key_buffer is too small. + */ +psa_status_t mbedtls_psa_ecp_generate_key( + const psa_key_attributes_t *attributes, + uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length); + +/** + * \brief Get the total number of ops that a key generation operation has taken + * Since it's start. + * + * \param[in] operation The \c mbedtls_psa_generate_key_iop_t to use. + * This must be initialized first. + * \return Total number of operations. + */ +uint32_t mbedtls_psa_generate_key_iop_get_num_ops( + mbedtls_psa_generate_key_iop_t *operation); + +/** + * \brief Setup a new interruptible key generation operation. + * + * \param[in] operation The \c mbedtls_psa_generate_key_iop_t to use. + * This must be initialized first. + * \param[in] attributes The desired attributes of the generated key. + * + * \retval #PSA_SUCCESS + * The operation started successfully - call \c mbedtls_psa_ecp_generate_key_iop_complete() + * with the same operation to complete the operation. + * * \retval #PSA_ERROR_NOT_SUPPORTED + * Either no internal interruptible operations are + * currently supported, or the key attributes are not unsupported. + * * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * There was insufficient memory to load the key representation. + * + */ +psa_status_t mbedtls_psa_ecp_generate_key_iop_setup( + mbedtls_psa_generate_key_iop_t *operation, + const psa_key_attributes_t *attributes); + +/** + * \brief Continue and eventually complete a key generation operation. + * + * \note The signature of this function is that of a PSA driver + * generate_key_complete entry point. This function behaves as a + * generate_key_complete entry point as defined in the PSA driver + * interface specification for transparent drivers. + * + * \param[in] operation The \c mbedtls_psa_generate_key_iop_t to use. + * This must be initialized first and + * had \c mbedtls_psa_ecp_generate_key_iop_setup() + * called successfully. + * \param[out] key_output The buffer to which the generated key + * is to be written. + * \param[out] key_len On success, the number of bytes that make + * up the returned key output. + * \retval #PSA_SUCCESS + * The key was generated successfully. + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * + */ +psa_status_t mbedtls_psa_ecp_generate_key_iop_complete( + mbedtls_psa_generate_key_iop_t *operation, + uint8_t *key_output, + size_t key_output_size, + size_t *key_len); + +/** + * \brief Abort a key generation operation. + * + * \param[in] operation The \c mbedtls_psa_generate_key_iop_t to abort. + * + * \retval #PSA_SUCCESS + * The operation was aborted successfully. + * + */ +psa_status_t mbedtls_psa_ecp_generate_key_iop_abort( + mbedtls_psa_generate_key_iop_t *operation); + +/** + * \brief Get the total number of ops that a key agreement operation has taken + * since its start. + * + * \note The signature of this function is that of a PSA driver + * key_agreement_get_num_ops entry point. This function behaves as an + * key_agreement_get_num_ops entry point as defined in the PSA driver + * interface specification for transparent drivers. + * + * \param[in] operation The \c mbedtls_psa_key_agreement_interruptible_operation_t to use. + * This must be initialized first. + * + * \return Total number of operations. + */ +uint32_t mbedtls_psa_key_agreement_iop_get_num_ops( + mbedtls_psa_key_agreement_interruptible_operation_t *operation); + +/** + * \brief Set up a new interruptible key agreement operation. + * + * \note The signature of this function is that of a PSA driver + * key_agreement_setup entry point. This function behaves as a + * key_agreement_setup entry point as defined in the PSA driver interface + * specification for transparent drivers. + * + * \param[in] operation The \c psa_key_agreement_iop_t to use. + * This must be initialized first. + * \param[in] private_key_attributes The attributes of the private key to use for the + * operation. + * \param[in] private_key_buffer The buffer containing the private key + * context. + * \param[in] private_key_buffer_len Size of the \p private_key_buffer buffer in + * bytes. + * \param[in] peer_key The buffer containing the key context + * of the peer's public key. + * \param[in] peer_key_length Size of the \p peer_key buffer in + * bytes. + * \retval #PSA_SUCCESS + * The operation started successfully - call \c psa_key_agreement_complete() + * with the same context to complete the operation + * \retval #PSA_ERROR_INVALID_ARGUMENT + * An unsupported, incorrectly formatted or incorrect type of key was + * used. + * \retval #PSA_ERROR_NOT_SUPPORTED Either no internal interruptible operations + * are currently supported, or the key type is currently unsupported. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * There was insufficient memory to load the key representation. + */ +psa_status_t mbedtls_psa_key_agreement_iop_setup( + mbedtls_psa_key_agreement_interruptible_operation_t *operation, + const psa_key_attributes_t *private_key_attributes, + const uint8_t *private_key_buffer, + size_t private_key_buffer_len, + const uint8_t *peer_key, + size_t peer_key_length); + +/** + * \brief Continue and eventually complete a key agreement operation. + * + * \note The signature of this function is that of a PSA driver + * key_agreement_complete entry point. This function behaves as a + * key_agreement_complete entry point as defined in the PSA driver + * interface specification for transparent drivers. + * + * \param[in] operation The \c mbedtls_psa_key_agreement_interruptible_operation_t to use. + * This must be initialized first. + * \param[out] shared_secret The buffer to which the shared secret + * is to be written. + * \param[in] shared_secret_size Size of the \p shared_secret buffer in + * bytes. + * \param[out] shared_secret_length On success, the number of bytes that make + * up the returned shared secret. + * \retval #PSA_SUCCESS + * The shared secret was calculated successfully. + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * Internal interruptible operations are currently not supported. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * \p shared_secret_size is too small + */ +psa_status_t mbedtls_psa_key_agreement_iop_complete( + mbedtls_psa_key_agreement_interruptible_operation_t *operation, + uint8_t *shared_secret, + size_t shared_secret_size, + size_t *shared_secret_length); + +/** + * \brief Abort a key agreement operation. + * + * \note The signature of this function is that of a PSA driver + * key_agreement_abort entry point. This function behaves as a + * key_agreement_abort entry point as defined in the PSA driver + * interface specification for transparent drivers. + * + * \param[in] operation The \c mbedtls_psa_key_agreement_interruptible_operation_t to abort. + * This must be initialized first. + * + * \retval #PSA_SUCCESS + * The operation was aborted successfully. + */ +psa_status_t mbedtls_psa_key_agreement_iop_abort( + mbedtls_psa_key_agreement_interruptible_operation_t *operation); + +/** Sign an already-calculated hash with ECDSA. + * + * \note The signature of this function is that of a PSA driver + * sign_hash entry point. This function behaves as a sign_hash + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \param[in] attributes The attributes of the ECC key to use for the + * operation. + * \param[in] key_buffer The buffer containing the ECC key context. + * format. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] alg Randomized or deterministic ECDSA algorithm. + * \param[in] hash The hash or message to sign. + * \param[in] hash_length Size of the \p hash buffer in bytes. + * \param[out] signature Buffer where the signature is to be written. + * \param[in] signature_size Size of the \p signature buffer in bytes. + * \param[out] signature_length On success, the number of bytes + * that make up the returned signature value. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p signature buffer is too small. You can + * determine a sufficient buffer size by calling + * #PSA_SIGN_OUTPUT_SIZE(\c PSA_KEY_TYPE_ECC_KEY_PAIR, \c key_bits, + * \p alg) where \c key_bits is the bit-size of the ECC key. + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY \emptydescription + */ +psa_status_t mbedtls_psa_ecdsa_sign_hash( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *hash, size_t hash_length, + uint8_t *signature, size_t signature_size, size_t *signature_length); + +/** + * \brief Verify an ECDSA hash or short message signature. + * + * \note The signature of this function is that of a PSA driver + * verify_hash entry point. This function behaves as a verify_hash + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \param[in] attributes The attributes of the ECC key to use for the + * operation. + * \param[in] key_buffer The buffer containing the ECC key context. + * format. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] alg Randomized or deterministic ECDSA algorithm. + * \param[in] hash The hash or message whose signature is to be + * verified. + * \param[in] hash_length Size of the \p hash buffer in bytes. + * \param[in] signature Buffer containing the signature to verify. + * \param[in] signature_length Size of the \p signature buffer in bytes. + * + * \retval #PSA_SUCCESS + * The signature is valid. + * \retval #PSA_ERROR_INVALID_SIGNATURE + * The calculation was performed successfully, but the passed + * signature is not a valid signature. + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + */ +psa_status_t mbedtls_psa_ecdsa_verify_hash( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *hash, size_t hash_length, + const uint8_t *signature, size_t signature_length); + + +/** Perform a key agreement and return the raw ECDH shared secret. + * + * \note The signature of this function is that of a PSA driver + * key_agreement entry point. This function behaves as a key_agreement + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the private key + * context. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in + * bytes. + * \param[in] alg A key agreement algorithm that is + * compatible with the type of the key. + * \param[in] peer_key The buffer containing the key context + * of the peer's public key. + * \param[in] peer_key_length Size of the \p peer_key buffer in + * bytes. + * \param[out] shared_secret The buffer to which the shared secret + * is to be written. + * \param[in] shared_secret_size Size of the \p shared_secret buffer in + * bytes. + * \param[out] shared_secret_length On success, the number of bytes that make + * up the returned shared secret. + * \retval #PSA_SUCCESS + * Success. Shared secret successfully calculated. + * \retval #PSA_ERROR_INVALID_HANDLE \emptydescription + * \retval #PSA_ERROR_NOT_PERMITTED \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \p alg is not a key agreement algorithm, or + * \p private_key is not compatible with \p alg, + * or \p peer_key is not valid for \p alg or not compatible with + * \p private_key. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * \p shared_secret_size is too small + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p alg is not a supported key agreement algorithm. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_key_agreement_ecdh( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *peer_key, size_t peer_key_length, + uint8_t *shared_secret, size_t shared_secret_size, + size_t *shared_secret_length); +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_ECP_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_ffdh.c b/tf-psa-crypto/drivers/builtin/src/psa_crypto_ffdh.c new file mode 100644 index 0000000000..8812080124 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_ffdh.c @@ -0,0 +1,781 @@ +/* + * PSA FFDH layer on top of Mbed TLS crypto + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_PSA_CRYPTO_C) + +#include +#include "psa_crypto_core.h" +#include "psa_crypto_ffdh.h" +#include "psa_crypto_random_impl.h" +#include "mbedtls/platform.h" +#include "mbedtls/private/error_common.h" + + +/** + * RFC 7919 standardizes a number of Diffie-Hellman groups, some of which are + * included here for use within the psa_crypto_ffdh module. + * + * The following lists the source of the above groups in the standards: + * - RFC 7919 section A.1: ffdhe2048 + * - RFC 7919 section A.2: ffdhe3072 + * - RFC 7919 section A.3: ffdhe4096 + * - RFC 7919 section A.4: ffdhe6144 + * - RFC 7919 section A.5: ffdhe8192 + * + * The constants with suffix "_p" denote the chosen prime moduli, while + * the constants with suffix "_g" denote the chosen generator + * of the associated prime field. + * + * The constants further suffixed with "_bin" are provided in binary format, + * while all other constants represent null-terminated strings holding the + * hexadecimal presentation of the respective numbers. + * + * The primes from RFC 7919 have been generating by the following trust-worthy + * procedure: + * - Fix N in { 2048, 3072, 4096, 6144, 8192 } and consider the N-bit number + * the first and last 64 bits are all 1, and the remaining N - 128 bits of + * which are 0x7ff...ff. + * - Add the smallest multiple of the first N - 129 bits of the binary expansion + * of e (for RFC 7919) to this intermediate bit-string such that the resulting + * integer is a safe-prime. + * - The result is the respective RFC 7919 prime, and the corresponding + * generator is always chosen to be 2 (which is a square for these prime, + * hence the corresponding subgroup has order (p-1)/2 and avoids leaking a + * bit in the private exponent). + */ + +/* + * Trustworthy DHM parameters in binary form + */ + + #define MBEDTLS_DHM_RFC7919_FFDHE2048_P_BIN { \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, \ + 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, \ + 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, \ + 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, \ + 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, \ + 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, \ + 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, \ + 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, \ + 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, \ + 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, \ + 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, \ + 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, \ + 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, \ + 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, \ + 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, \ + 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, \ + 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, \ + 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, \ + 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, \ + 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, \ + 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, \ + 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, \ + 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, \ + 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, \ + 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, \ + 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, \ + 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, \ + 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, \ + 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, \ + 0x88, 0x6B, 0x42, 0x38, 0x61, 0x28, 0x5C, 0x97, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, } + +#define MBEDTLS_DHM_RFC7919_FFDHE2048_G_BIN { 0x02 } + +#define MBEDTLS_DHM_RFC7919_FFDHE3072_P_BIN { \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, \ + 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, \ + 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, \ + 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, \ + 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, \ + 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, \ + 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, \ + 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, \ + 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, \ + 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, \ + 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, \ + 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, \ + 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, \ + 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, \ + 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, \ + 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, \ + 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, \ + 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, \ + 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, \ + 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, \ + 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, \ + 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, \ + 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, \ + 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, \ + 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, \ + 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, \ + 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, \ + 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, \ + 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, \ + 0x88, 0x6B, 0x42, 0x38, 0x61, 0x1F, 0xCF, 0xDC, \ + 0xDE, 0x35, 0x5B, 0x3B, 0x65, 0x19, 0x03, 0x5B, \ + 0xBC, 0x34, 0xF4, 0xDE, 0xF9, 0x9C, 0x02, 0x38, \ + 0x61, 0xB4, 0x6F, 0xC9, 0xD6, 0xE6, 0xC9, 0x07, \ + 0x7A, 0xD9, 0x1D, 0x26, 0x91, 0xF7, 0xF7, 0xEE, \ + 0x59, 0x8C, 0xB0, 0xFA, 0xC1, 0x86, 0xD9, 0x1C, \ + 0xAE, 0xFE, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, \ + 0xB4, 0x13, 0x0C, 0x93, 0xBC, 0x43, 0x79, 0x44, \ + 0xF4, 0xFD, 0x44, 0x52, 0xE2, 0xD7, 0x4D, 0xD3, \ + 0x64, 0xF2, 0xE2, 0x1E, 0x71, 0xF5, 0x4B, 0xFF, \ + 0x5C, 0xAE, 0x82, 0xAB, 0x9C, 0x9D, 0xF6, 0x9E, \ + 0xE8, 0x6D, 0x2B, 0xC5, 0x22, 0x36, 0x3A, 0x0D, \ + 0xAB, 0xC5, 0x21, 0x97, 0x9B, 0x0D, 0xEA, 0xDA, \ + 0x1D, 0xBF, 0x9A, 0x42, 0xD5, 0xC4, 0x48, 0x4E, \ + 0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF, \ + 0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C, \ + 0x25, 0xE4, 0x1D, 0x2B, 0x66, 0xC6, 0x2E, 0x37, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + +#define MBEDTLS_DHM_RFC7919_FFDHE3072_G_BIN { 0x02 } + +#define MBEDTLS_DHM_RFC7919_FFDHE4096_P_BIN { \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, \ + 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, \ + 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, \ + 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, \ + 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, \ + 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, \ + 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, \ + 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, \ + 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, \ + 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, \ + 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, \ + 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, \ + 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, \ + 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, \ + 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, \ + 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, \ + 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, \ + 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, \ + 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, \ + 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, \ + 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, \ + 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, \ + 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, \ + 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, \ + 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, \ + 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, \ + 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, \ + 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, \ + 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, \ + 0x88, 0x6B, 0x42, 0x38, 0x61, 0x1F, 0xCF, 0xDC, \ + 0xDE, 0x35, 0x5B, 0x3B, 0x65, 0x19, 0x03, 0x5B, \ + 0xBC, 0x34, 0xF4, 0xDE, 0xF9, 0x9C, 0x02, 0x38, \ + 0x61, 0xB4, 0x6F, 0xC9, 0xD6, 0xE6, 0xC9, 0x07, \ + 0x7A, 0xD9, 0x1D, 0x26, 0x91, 0xF7, 0xF7, 0xEE, \ + 0x59, 0x8C, 0xB0, 0xFA, 0xC1, 0x86, 0xD9, 0x1C, \ + 0xAE, 0xFE, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, \ + 0xB4, 0x13, 0x0C, 0x93, 0xBC, 0x43, 0x79, 0x44, \ + 0xF4, 0xFD, 0x44, 0x52, 0xE2, 0xD7, 0x4D, 0xD3, \ + 0x64, 0xF2, 0xE2, 0x1E, 0x71, 0xF5, 0x4B, 0xFF, \ + 0x5C, 0xAE, 0x82, 0xAB, 0x9C, 0x9D, 0xF6, 0x9E, \ + 0xE8, 0x6D, 0x2B, 0xC5, 0x22, 0x36, 0x3A, 0x0D, \ + 0xAB, 0xC5, 0x21, 0x97, 0x9B, 0x0D, 0xEA, 0xDA, \ + 0x1D, 0xBF, 0x9A, 0x42, 0xD5, 0xC4, 0x48, 0x4E, \ + 0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF, \ + 0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C, \ + 0x25, 0xE4, 0x1D, 0x2B, 0x66, 0x9E, 0x1E, 0xF1, \ + 0x6E, 0x6F, 0x52, 0xC3, 0x16, 0x4D, 0xF4, 0xFB, \ + 0x79, 0x30, 0xE9, 0xE4, 0xE5, 0x88, 0x57, 0xB6, \ + 0xAC, 0x7D, 0x5F, 0x42, 0xD6, 0x9F, 0x6D, 0x18, \ + 0x77, 0x63, 0xCF, 0x1D, 0x55, 0x03, 0x40, 0x04, \ + 0x87, 0xF5, 0x5B, 0xA5, 0x7E, 0x31, 0xCC, 0x7A, \ + 0x71, 0x35, 0xC8, 0x86, 0xEF, 0xB4, 0x31, 0x8A, \ + 0xED, 0x6A, 0x1E, 0x01, 0x2D, 0x9E, 0x68, 0x32, \ + 0xA9, 0x07, 0x60, 0x0A, 0x91, 0x81, 0x30, 0xC4, \ + 0x6D, 0xC7, 0x78, 0xF9, 0x71, 0xAD, 0x00, 0x38, \ + 0x09, 0x29, 0x99, 0xA3, 0x33, 0xCB, 0x8B, 0x7A, \ + 0x1A, 0x1D, 0xB9, 0x3D, 0x71, 0x40, 0x00, 0x3C, \ + 0x2A, 0x4E, 0xCE, 0xA9, 0xF9, 0x8D, 0x0A, 0xCC, \ + 0x0A, 0x82, 0x91, 0xCD, 0xCE, 0xC9, 0x7D, 0xCF, \ + 0x8E, 0xC9, 0xB5, 0x5A, 0x7F, 0x88, 0xA4, 0x6B, \ + 0x4D, 0xB5, 0xA8, 0x51, 0xF4, 0x41, 0x82, 0xE1, \ + 0xC6, 0x8A, 0x00, 0x7E, 0x5E, 0x65, 0x5F, 0x6A, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + +#define MBEDTLS_DHM_RFC7919_FFDHE4096_G_BIN { 0x02 } + +#define MBEDTLS_DHM_RFC7919_FFDHE6144_P_BIN { \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, \ + 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, \ + 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, \ + 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, \ + 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, \ + 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, \ + 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, \ + 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, \ + 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, \ + 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, \ + 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, \ + 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, \ + 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, \ + 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, \ + 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, \ + 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, \ + 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, \ + 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, \ + 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, \ + 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, \ + 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, \ + 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, \ + 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, \ + 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, \ + 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, \ + 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, \ + 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, \ + 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, \ + 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, \ + 0x88, 0x6B, 0x42, 0x38, 0x61, 0x1F, 0xCF, 0xDC, \ + 0xDE, 0x35, 0x5B, 0x3B, 0x65, 0x19, 0x03, 0x5B, \ + 0xBC, 0x34, 0xF4, 0xDE, 0xF9, 0x9C, 0x02, 0x38, \ + 0x61, 0xB4, 0x6F, 0xC9, 0xD6, 0xE6, 0xC9, 0x07, \ + 0x7A, 0xD9, 0x1D, 0x26, 0x91, 0xF7, 0xF7, 0xEE, \ + 0x59, 0x8C, 0xB0, 0xFA, 0xC1, 0x86, 0xD9, 0x1C, \ + 0xAE, 0xFE, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, \ + 0xB4, 0x13, 0x0C, 0x93, 0xBC, 0x43, 0x79, 0x44, \ + 0xF4, 0xFD, 0x44, 0x52, 0xE2, 0xD7, 0x4D, 0xD3, \ + 0x64, 0xF2, 0xE2, 0x1E, 0x71, 0xF5, 0x4B, 0xFF, \ + 0x5C, 0xAE, 0x82, 0xAB, 0x9C, 0x9D, 0xF6, 0x9E, \ + 0xE8, 0x6D, 0x2B, 0xC5, 0x22, 0x36, 0x3A, 0x0D, \ + 0xAB, 0xC5, 0x21, 0x97, 0x9B, 0x0D, 0xEA, 0xDA, \ + 0x1D, 0xBF, 0x9A, 0x42, 0xD5, 0xC4, 0x48, 0x4E, \ + 0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF, \ + 0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C, \ + 0x25, 0xE4, 0x1D, 0x2B, 0x66, 0x9E, 0x1E, 0xF1, \ + 0x6E, 0x6F, 0x52, 0xC3, 0x16, 0x4D, 0xF4, 0xFB, \ + 0x79, 0x30, 0xE9, 0xE4, 0xE5, 0x88, 0x57, 0xB6, \ + 0xAC, 0x7D, 0x5F, 0x42, 0xD6, 0x9F, 0x6D, 0x18, \ + 0x77, 0x63, 0xCF, 0x1D, 0x55, 0x03, 0x40, 0x04, \ + 0x87, 0xF5, 0x5B, 0xA5, 0x7E, 0x31, 0xCC, 0x7A, \ + 0x71, 0x35, 0xC8, 0x86, 0xEF, 0xB4, 0x31, 0x8A, \ + 0xED, 0x6A, 0x1E, 0x01, 0x2D, 0x9E, 0x68, 0x32, \ + 0xA9, 0x07, 0x60, 0x0A, 0x91, 0x81, 0x30, 0xC4, \ + 0x6D, 0xC7, 0x78, 0xF9, 0x71, 0xAD, 0x00, 0x38, \ + 0x09, 0x29, 0x99, 0xA3, 0x33, 0xCB, 0x8B, 0x7A, \ + 0x1A, 0x1D, 0xB9, 0x3D, 0x71, 0x40, 0x00, 0x3C, \ + 0x2A, 0x4E, 0xCE, 0xA9, 0xF9, 0x8D, 0x0A, 0xCC, \ + 0x0A, 0x82, 0x91, 0xCD, 0xCE, 0xC9, 0x7D, 0xCF, \ + 0x8E, 0xC9, 0xB5, 0x5A, 0x7F, 0x88, 0xA4, 0x6B, \ + 0x4D, 0xB5, 0xA8, 0x51, 0xF4, 0x41, 0x82, 0xE1, \ + 0xC6, 0x8A, 0x00, 0x7E, 0x5E, 0x0D, 0xD9, 0x02, \ + 0x0B, 0xFD, 0x64, 0xB6, 0x45, 0x03, 0x6C, 0x7A, \ + 0x4E, 0x67, 0x7D, 0x2C, 0x38, 0x53, 0x2A, 0x3A, \ + 0x23, 0xBA, 0x44, 0x42, 0xCA, 0xF5, 0x3E, 0xA6, \ + 0x3B, 0xB4, 0x54, 0x32, 0x9B, 0x76, 0x24, 0xC8, \ + 0x91, 0x7B, 0xDD, 0x64, 0xB1, 0xC0, 0xFD, 0x4C, \ + 0xB3, 0x8E, 0x8C, 0x33, 0x4C, 0x70, 0x1C, 0x3A, \ + 0xCD, 0xAD, 0x06, 0x57, 0xFC, 0xCF, 0xEC, 0x71, \ + 0x9B, 0x1F, 0x5C, 0x3E, 0x4E, 0x46, 0x04, 0x1F, \ + 0x38, 0x81, 0x47, 0xFB, 0x4C, 0xFD, 0xB4, 0x77, \ + 0xA5, 0x24, 0x71, 0xF7, 0xA9, 0xA9, 0x69, 0x10, \ + 0xB8, 0x55, 0x32, 0x2E, 0xDB, 0x63, 0x40, 0xD8, \ + 0xA0, 0x0E, 0xF0, 0x92, 0x35, 0x05, 0x11, 0xE3, \ + 0x0A, 0xBE, 0xC1, 0xFF, 0xF9, 0xE3, 0xA2, 0x6E, \ + 0x7F, 0xB2, 0x9F, 0x8C, 0x18, 0x30, 0x23, 0xC3, \ + 0x58, 0x7E, 0x38, 0xDA, 0x00, 0x77, 0xD9, 0xB4, \ + 0x76, 0x3E, 0x4E, 0x4B, 0x94, 0xB2, 0xBB, 0xC1, \ + 0x94, 0xC6, 0x65, 0x1E, 0x77, 0xCA, 0xF9, 0x92, \ + 0xEE, 0xAA, 0xC0, 0x23, 0x2A, 0x28, 0x1B, 0xF6, \ + 0xB3, 0xA7, 0x39, 0xC1, 0x22, 0x61, 0x16, 0x82, \ + 0x0A, 0xE8, 0xDB, 0x58, 0x47, 0xA6, 0x7C, 0xBE, \ + 0xF9, 0xC9, 0x09, 0x1B, 0x46, 0x2D, 0x53, 0x8C, \ + 0xD7, 0x2B, 0x03, 0x74, 0x6A, 0xE7, 0x7F, 0x5E, \ + 0x62, 0x29, 0x2C, 0x31, 0x15, 0x62, 0xA8, 0x46, \ + 0x50, 0x5D, 0xC8, 0x2D, 0xB8, 0x54, 0x33, 0x8A, \ + 0xE4, 0x9F, 0x52, 0x35, 0xC9, 0x5B, 0x91, 0x17, \ + 0x8C, 0xCF, 0x2D, 0xD5, 0xCA, 0xCE, 0xF4, 0x03, \ + 0xEC, 0x9D, 0x18, 0x10, 0xC6, 0x27, 0x2B, 0x04, \ + 0x5B, 0x3B, 0x71, 0xF9, 0xDC, 0x6B, 0x80, 0xD6, \ + 0x3F, 0xDD, 0x4A, 0x8E, 0x9A, 0xDB, 0x1E, 0x69, \ + 0x62, 0xA6, 0x95, 0x26, 0xD4, 0x31, 0x61, 0xC1, \ + 0xA4, 0x1D, 0x57, 0x0D, 0x79, 0x38, 0xDA, 0xD4, \ + 0xA4, 0x0E, 0x32, 0x9C, 0xD0, 0xE4, 0x0E, 0x65, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + +#define MBEDTLS_DHM_RFC7919_FFDHE6144_G_BIN { 0x02 } + +#define MBEDTLS_DHM_RFC7919_FFDHE8192_P_BIN { \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, \ + 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, \ + 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, \ + 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, \ + 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, \ + 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, \ + 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, \ + 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, \ + 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, \ + 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, \ + 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, \ + 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, \ + 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, \ + 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, \ + 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, \ + 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, \ + 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, \ + 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, \ + 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, \ + 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, \ + 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, \ + 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, \ + 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, \ + 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, \ + 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, \ + 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, \ + 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, \ + 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, \ + 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, \ + 0x88, 0x6B, 0x42, 0x38, 0x61, 0x1F, 0xCF, 0xDC, \ + 0xDE, 0x35, 0x5B, 0x3B, 0x65, 0x19, 0x03, 0x5B, \ + 0xBC, 0x34, 0xF4, 0xDE, 0xF9, 0x9C, 0x02, 0x38, \ + 0x61, 0xB4, 0x6F, 0xC9, 0xD6, 0xE6, 0xC9, 0x07, \ + 0x7A, 0xD9, 0x1D, 0x26, 0x91, 0xF7, 0xF7, 0xEE, \ + 0x59, 0x8C, 0xB0, 0xFA, 0xC1, 0x86, 0xD9, 0x1C, \ + 0xAE, 0xFE, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, \ + 0xB4, 0x13, 0x0C, 0x93, 0xBC, 0x43, 0x79, 0x44, \ + 0xF4, 0xFD, 0x44, 0x52, 0xE2, 0xD7, 0x4D, 0xD3, \ + 0x64, 0xF2, 0xE2, 0x1E, 0x71, 0xF5, 0x4B, 0xFF, \ + 0x5C, 0xAE, 0x82, 0xAB, 0x9C, 0x9D, 0xF6, 0x9E, \ + 0xE8, 0x6D, 0x2B, 0xC5, 0x22, 0x36, 0x3A, 0x0D, \ + 0xAB, 0xC5, 0x21, 0x97, 0x9B, 0x0D, 0xEA, 0xDA, \ + 0x1D, 0xBF, 0x9A, 0x42, 0xD5, 0xC4, 0x48, 0x4E, \ + 0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF, \ + 0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C, \ + 0x25, 0xE4, 0x1D, 0x2B, 0x66, 0x9E, 0x1E, 0xF1, \ + 0x6E, 0x6F, 0x52, 0xC3, 0x16, 0x4D, 0xF4, 0xFB, \ + 0x79, 0x30, 0xE9, 0xE4, 0xE5, 0x88, 0x57, 0xB6, \ + 0xAC, 0x7D, 0x5F, 0x42, 0xD6, 0x9F, 0x6D, 0x18, \ + 0x77, 0x63, 0xCF, 0x1D, 0x55, 0x03, 0x40, 0x04, \ + 0x87, 0xF5, 0x5B, 0xA5, 0x7E, 0x31, 0xCC, 0x7A, \ + 0x71, 0x35, 0xC8, 0x86, 0xEF, 0xB4, 0x31, 0x8A, \ + 0xED, 0x6A, 0x1E, 0x01, 0x2D, 0x9E, 0x68, 0x32, \ + 0xA9, 0x07, 0x60, 0x0A, 0x91, 0x81, 0x30, 0xC4, \ + 0x6D, 0xC7, 0x78, 0xF9, 0x71, 0xAD, 0x00, 0x38, \ + 0x09, 0x29, 0x99, 0xA3, 0x33, 0xCB, 0x8B, 0x7A, \ + 0x1A, 0x1D, 0xB9, 0x3D, 0x71, 0x40, 0x00, 0x3C, \ + 0x2A, 0x4E, 0xCE, 0xA9, 0xF9, 0x8D, 0x0A, 0xCC, \ + 0x0A, 0x82, 0x91, 0xCD, 0xCE, 0xC9, 0x7D, 0xCF, \ + 0x8E, 0xC9, 0xB5, 0x5A, 0x7F, 0x88, 0xA4, 0x6B, \ + 0x4D, 0xB5, 0xA8, 0x51, 0xF4, 0x41, 0x82, 0xE1, \ + 0xC6, 0x8A, 0x00, 0x7E, 0x5E, 0x0D, 0xD9, 0x02, \ + 0x0B, 0xFD, 0x64, 0xB6, 0x45, 0x03, 0x6C, 0x7A, \ + 0x4E, 0x67, 0x7D, 0x2C, 0x38, 0x53, 0x2A, 0x3A, \ + 0x23, 0xBA, 0x44, 0x42, 0xCA, 0xF5, 0x3E, 0xA6, \ + 0x3B, 0xB4, 0x54, 0x32, 0x9B, 0x76, 0x24, 0xC8, \ + 0x91, 0x7B, 0xDD, 0x64, 0xB1, 0xC0, 0xFD, 0x4C, \ + 0xB3, 0x8E, 0x8C, 0x33, 0x4C, 0x70, 0x1C, 0x3A, \ + 0xCD, 0xAD, 0x06, 0x57, 0xFC, 0xCF, 0xEC, 0x71, \ + 0x9B, 0x1F, 0x5C, 0x3E, 0x4E, 0x46, 0x04, 0x1F, \ + 0x38, 0x81, 0x47, 0xFB, 0x4C, 0xFD, 0xB4, 0x77, \ + 0xA5, 0x24, 0x71, 0xF7, 0xA9, 0xA9, 0x69, 0x10, \ + 0xB8, 0x55, 0x32, 0x2E, 0xDB, 0x63, 0x40, 0xD8, \ + 0xA0, 0x0E, 0xF0, 0x92, 0x35, 0x05, 0x11, 0xE3, \ + 0x0A, 0xBE, 0xC1, 0xFF, 0xF9, 0xE3, 0xA2, 0x6E, \ + 0x7F, 0xB2, 0x9F, 0x8C, 0x18, 0x30, 0x23, 0xC3, \ + 0x58, 0x7E, 0x38, 0xDA, 0x00, 0x77, 0xD9, 0xB4, \ + 0x76, 0x3E, 0x4E, 0x4B, 0x94, 0xB2, 0xBB, 0xC1, \ + 0x94, 0xC6, 0x65, 0x1E, 0x77, 0xCA, 0xF9, 0x92, \ + 0xEE, 0xAA, 0xC0, 0x23, 0x2A, 0x28, 0x1B, 0xF6, \ + 0xB3, 0xA7, 0x39, 0xC1, 0x22, 0x61, 0x16, 0x82, \ + 0x0A, 0xE8, 0xDB, 0x58, 0x47, 0xA6, 0x7C, 0xBE, \ + 0xF9, 0xC9, 0x09, 0x1B, 0x46, 0x2D, 0x53, 0x8C, \ + 0xD7, 0x2B, 0x03, 0x74, 0x6A, 0xE7, 0x7F, 0x5E, \ + 0x62, 0x29, 0x2C, 0x31, 0x15, 0x62, 0xA8, 0x46, \ + 0x50, 0x5D, 0xC8, 0x2D, 0xB8, 0x54, 0x33, 0x8A, \ + 0xE4, 0x9F, 0x52, 0x35, 0xC9, 0x5B, 0x91, 0x17, \ + 0x8C, 0xCF, 0x2D, 0xD5, 0xCA, 0xCE, 0xF4, 0x03, \ + 0xEC, 0x9D, 0x18, 0x10, 0xC6, 0x27, 0x2B, 0x04, \ + 0x5B, 0x3B, 0x71, 0xF9, 0xDC, 0x6B, 0x80, 0xD6, \ + 0x3F, 0xDD, 0x4A, 0x8E, 0x9A, 0xDB, 0x1E, 0x69, \ + 0x62, 0xA6, 0x95, 0x26, 0xD4, 0x31, 0x61, 0xC1, \ + 0xA4, 0x1D, 0x57, 0x0D, 0x79, 0x38, 0xDA, 0xD4, \ + 0xA4, 0x0E, 0x32, 0x9C, 0xCF, 0xF4, 0x6A, 0xAA, \ + 0x36, 0xAD, 0x00, 0x4C, 0xF6, 0x00, 0xC8, 0x38, \ + 0x1E, 0x42, 0x5A, 0x31, 0xD9, 0x51, 0xAE, 0x64, \ + 0xFD, 0xB2, 0x3F, 0xCE, 0xC9, 0x50, 0x9D, 0x43, \ + 0x68, 0x7F, 0xEB, 0x69, 0xED, 0xD1, 0xCC, 0x5E, \ + 0x0B, 0x8C, 0xC3, 0xBD, 0xF6, 0x4B, 0x10, 0xEF, \ + 0x86, 0xB6, 0x31, 0x42, 0xA3, 0xAB, 0x88, 0x29, \ + 0x55, 0x5B, 0x2F, 0x74, 0x7C, 0x93, 0x26, 0x65, \ + 0xCB, 0x2C, 0x0F, 0x1C, 0xC0, 0x1B, 0xD7, 0x02, \ + 0x29, 0x38, 0x88, 0x39, 0xD2, 0xAF, 0x05, 0xE4, \ + 0x54, 0x50, 0x4A, 0xC7, 0x8B, 0x75, 0x82, 0x82, \ + 0x28, 0x46, 0xC0, 0xBA, 0x35, 0xC3, 0x5F, 0x5C, \ + 0x59, 0x16, 0x0C, 0xC0, 0x46, 0xFD, 0x82, 0x51, \ + 0x54, 0x1F, 0xC6, 0x8C, 0x9C, 0x86, 0xB0, 0x22, \ + 0xBB, 0x70, 0x99, 0x87, 0x6A, 0x46, 0x0E, 0x74, \ + 0x51, 0xA8, 0xA9, 0x31, 0x09, 0x70, 0x3F, 0xEE, \ + 0x1C, 0x21, 0x7E, 0x6C, 0x38, 0x26, 0xE5, 0x2C, \ + 0x51, 0xAA, 0x69, 0x1E, 0x0E, 0x42, 0x3C, 0xFC, \ + 0x99, 0xE9, 0xE3, 0x16, 0x50, 0xC1, 0x21, 0x7B, \ + 0x62, 0x48, 0x16, 0xCD, 0xAD, 0x9A, 0x95, 0xF9, \ + 0xD5, 0xB8, 0x01, 0x94, 0x88, 0xD9, 0xC0, 0xA0, \ + 0xA1, 0xFE, 0x30, 0x75, 0xA5, 0x77, 0xE2, 0x31, \ + 0x83, 0xF8, 0x1D, 0x4A, 0x3F, 0x2F, 0xA4, 0x57, \ + 0x1E, 0xFC, 0x8C, 0xE0, 0xBA, 0x8A, 0x4F, 0xE8, \ + 0xB6, 0x85, 0x5D, 0xFE, 0x72, 0xB0, 0xA6, 0x6E, \ + 0xDE, 0xD2, 0xFB, 0xAB, 0xFB, 0xE5, 0x8A, 0x30, \ + 0xFA, 0xFA, 0xBE, 0x1C, 0x5D, 0x71, 0xA8, 0x7E, \ + 0x2F, 0x74, 0x1E, 0xF8, 0xC1, 0xFE, 0x86, 0xFE, \ + 0xA6, 0xBB, 0xFD, 0xE5, 0x30, 0x67, 0x7F, 0x0D, \ + 0x97, 0xD1, 0x1D, 0x49, 0xF7, 0xA8, 0x44, 0x3D, \ + 0x08, 0x22, 0xE5, 0x06, 0xA9, 0xF4, 0x61, 0x4E, \ + 0x01, 0x1E, 0x2A, 0x94, 0x83, 0x8F, 0xF8, 0x8C, \ + 0xD6, 0x8C, 0x8B, 0xB7, 0xC5, 0xC6, 0x42, 0x4C, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + +#define MBEDTLS_DHM_RFC7919_FFDHE8192_G_BIN { 0x02 } + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_GENERATE) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_PUBLIC_KEY) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_FFDH) +static psa_status_t mbedtls_psa_ffdh_set_prime_generator(size_t key_size, + mbedtls_mpi *P, + mbedtls_mpi *G) +{ + const unsigned char *dhm_P = NULL; + const unsigned char *dhm_G = NULL; + size_t dhm_size_P = 0; + size_t dhm_size_G = 0; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if (P == NULL && G == NULL) { + return PSA_ERROR_INVALID_ARGUMENT; + } + +#if defined(MBEDTLS_PSA_BUILTIN_DH_RFC7919_2048) + static const unsigned char dhm_P_2048[] = + MBEDTLS_DHM_RFC7919_FFDHE2048_P_BIN; + static const unsigned char dhm_G_2048[] = + MBEDTLS_DHM_RFC7919_FFDHE2048_G_BIN; +#endif /* MBEDTLS_PSA_BUILTIN_DH_RFC7919_2048 */ +#if defined(MBEDTLS_PSA_BUILTIN_DH_RFC7919_3072) + static const unsigned char dhm_P_3072[] = + MBEDTLS_DHM_RFC7919_FFDHE3072_P_BIN; + static const unsigned char dhm_G_3072[] = + MBEDTLS_DHM_RFC7919_FFDHE3072_G_BIN; +#endif /* MBEDTLS_PSA_BUILTIN_DH_RFC7919_3072 */ +#if defined(MBEDTLS_PSA_BUILTIN_DH_RFC7919_4096) + static const unsigned char dhm_P_4096[] = + MBEDTLS_DHM_RFC7919_FFDHE4096_P_BIN; + static const unsigned char dhm_G_4096[] = + MBEDTLS_DHM_RFC7919_FFDHE4096_G_BIN; +#endif /* MBEDTLS_PSA_BUILTIN_DH_RFC7919_4096 */ +#if defined(MBEDTLS_PSA_BUILTIN_DH_RFC7919_6144) + static const unsigned char dhm_P_6144[] = + MBEDTLS_DHM_RFC7919_FFDHE6144_P_BIN; + static const unsigned char dhm_G_6144[] = + MBEDTLS_DHM_RFC7919_FFDHE6144_G_BIN; +#endif /* MBEDTLS_PSA_BUILTIN_DH_RFC7919_6144 */ +#if defined(MBEDTLS_PSA_BUILTIN_DH_RFC7919_8192) + static const unsigned char dhm_P_8192[] = + MBEDTLS_DHM_RFC7919_FFDHE8192_P_BIN; + static const unsigned char dhm_G_8192[] = + MBEDTLS_DHM_RFC7919_FFDHE8192_G_BIN; +#endif /* MBEDTLS_PSA_BUILTIN_DH_RFC7919_8192 */ + + switch (key_size) { +#if defined(MBEDTLS_PSA_BUILTIN_DH_RFC7919_2048) + case sizeof(dhm_P_2048): + dhm_P = dhm_P_2048; + dhm_G = dhm_G_2048; + dhm_size_P = sizeof(dhm_P_2048); + dhm_size_G = sizeof(dhm_G_2048); + break; +#endif /* MBEDTLS_PSA_BUILTIN_DH_RFC7919_2048 */ +#if defined(MBEDTLS_PSA_BUILTIN_DH_RFC7919_3072) + case sizeof(dhm_P_3072): + dhm_P = dhm_P_3072; + dhm_G = dhm_G_3072; + dhm_size_P = sizeof(dhm_P_3072); + dhm_size_G = sizeof(dhm_G_3072); + break; +#endif /* MBEDTLS_PSA_BUILTIN_DH_RFC7919_3072 */ +#if defined(MBEDTLS_PSA_BUILTIN_DH_RFC7919_4096) + case sizeof(dhm_P_4096): + dhm_P = dhm_P_4096; + dhm_G = dhm_G_4096; + dhm_size_P = sizeof(dhm_P_4096); + dhm_size_G = sizeof(dhm_G_4096); + break; +#endif /* MBEDTLS_PSA_BUILTIN_DH_RFC7919_4096 */ +#if defined(MBEDTLS_PSA_BUILTIN_DH_RFC7919_6144) + case sizeof(dhm_P_6144): + dhm_P = dhm_P_6144; + dhm_G = dhm_G_6144; + dhm_size_P = sizeof(dhm_P_6144); + dhm_size_G = sizeof(dhm_G_6144); + break; +#endif /* MBEDTLS_PSA_BUILTIN_DH_RFC7919_6144 */ +#if defined(MBEDTLS_PSA_BUILTIN_DH_RFC7919_8192) + case sizeof(dhm_P_8192): + dhm_P = dhm_P_8192; + dhm_G = dhm_G_8192; + dhm_size_P = sizeof(dhm_P_8192); + dhm_size_G = sizeof(dhm_G_8192); + break; +#endif /* MBEDTLS_PSA_BUILTIN_DH_RFC7919_8192 */ + default: + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (P != NULL) { + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(P, dhm_P, + dhm_size_P)); + } + if (G != NULL) { + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(G, dhm_G, + dhm_size_G)); + } + +cleanup: + if (ret != 0) { + return mbedtls_to_psa_error(ret); + } + + return PSA_SUCCESS; +} +#endif /* MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_EXPORT || + MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_GENERATE || + MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_PUBLIC_KEY || + MBEDTLS_PSA_BUILTIN_ALG_FFDH */ + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_PUBLIC_KEY) +psa_status_t mbedtls_psa_ffdh_export_public_key( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *data, + size_t data_size, + size_t *data_length) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi GX, G, X, P; + psa_key_type_t type = attributes->type; + + if (PSA_KEY_TYPE_IS_PUBLIC_KEY(type)) { + if (key_buffer_size > data_size) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + memcpy(data, key_buffer, key_buffer_size); + memset(data + key_buffer_size, 0, + data_size - key_buffer_size); + *data_length = key_buffer_size; + return PSA_SUCCESS; + } + + mbedtls_mpi_init(&GX); mbedtls_mpi_init(&G); + mbedtls_mpi_init(&X); mbedtls_mpi_init(&P); + + size_t key_len = PSA_BITS_TO_BYTES(attributes->bits); + if (key_len > data_size) { + status = PSA_ERROR_BUFFER_TOO_SMALL; + goto cleanup; + } + + status = mbedtls_psa_ffdh_set_prime_generator(key_len, &P, &G); + + if (status != PSA_SUCCESS) { + goto cleanup; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&X, key_buffer, + key_buffer_size)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&GX, &G, &X, &P, NULL)); + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&GX, data, key_len)); + + *data_length = key_len; + + ret = 0; +cleanup: + mbedtls_mpi_free(&P); mbedtls_mpi_free(&G); + mbedtls_mpi_free(&X); mbedtls_mpi_free(&GX); + + if (status == PSA_SUCCESS && ret != 0) { + status = mbedtls_to_psa_error(ret); + } + + return status; +} +#endif /* MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_EXPORT || + MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_PUBLIC_KEY */ + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_GENERATE) +psa_status_t mbedtls_psa_ffdh_generate_key( + const psa_key_attributes_t *attributes, + uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length) +{ + mbedtls_mpi X, P; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi_init(&P); mbedtls_mpi_init(&X); + (void) attributes; + + status = mbedtls_psa_ffdh_set_prime_generator(key_buffer_size, &P, NULL); + + if (status != PSA_SUCCESS) { + goto cleanup; + } + + /* RFC7919: Traditional finite field Diffie-Hellman has each peer choose their + secret exponent from the range [2, P-2]. + Select random value in range [3, P-1] and decrease it by 1. */ + MBEDTLS_MPI_CHK(mbedtls_mpi_random(&X, 3, &P, mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE)); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&X, &X, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&X, key_buffer, key_buffer_size)); + *key_buffer_length = key_buffer_size; + +cleanup: + mbedtls_mpi_free(&P); mbedtls_mpi_free(&X); + if (status == PSA_SUCCESS && ret != 0) { + return mbedtls_to_psa_error(ret); + } + + return status; +} +#endif /* MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_GENERATE */ + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_IMPORT) +psa_status_t mbedtls_psa_ffdh_import_key( + const psa_key_attributes_t *attributes, + const uint8_t *data, size_t data_length, + uint8_t *key_buffer, size_t key_buffer_size, + size_t *key_buffer_length, size_t *bits) +{ + (void) attributes; + + if (key_buffer_size < data_length) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + memcpy(key_buffer, data, data_length); + *key_buffer_length = data_length; + *bits = PSA_BYTES_TO_BITS(data_length); + + return PSA_SUCCESS; +} +#endif /* MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_IMPORT */ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_FFDH) +psa_status_t mbedtls_psa_ffdh_key_agreement( + const psa_key_attributes_t *attributes, + const uint8_t *peer_key, + size_t peer_key_length, + const uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *shared_secret, + size_t shared_secret_size, + size_t *shared_secret_length) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi P, X, GY, K; + const size_t calculated_shared_secret_size = key_buffer_size; + + if (!PSA_KEY_TYPE_IS_DH_KEY_PAIR(psa_get_key_type(attributes))) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (peer_key_length != key_buffer_size) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* This has been checked by the core, but keep a local check too. */ + if (calculated_shared_secret_size > shared_secret_size) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + mbedtls_mpi_init(&P); + mbedtls_mpi_init(&X); mbedtls_mpi_init(&GY); + mbedtls_mpi_init(&K); + + status = mbedtls_psa_ffdh_set_prime_generator( + PSA_BITS_TO_BYTES(attributes->bits), &P, NULL); + + if (status != PSA_SUCCESS) { + goto cleanup; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&GY, peer_key, + peer_key_length)); + + /* RFC 7919 5.1: validate the peer's public key: 1 < GY < P-1 + * + * This check is sufficient to ensure GY is not of low order, because we're + * using a safe prime (that is, q = (p-1) / 2 is also prime), so the only + * group elements of low order are 1 and p-1. (Obviously we also want to + * exclude 0 that is not a group element, and values >= p as they are not + * residues mod p.) + * + * Note: we know we're using a safe prime because the only FFDH groups + * defined by the PSA spec are from RFC 7919 (since version 1.0) and RFC + * 3525 (since v1.4, not yet supported in tf-psa-crypto as of writing this + * comment), which both use safe primes. + * + * Note: NIST SP 800-56Ar3 5.7.1.1 (2) has the check on the shared secret, + * but checking before is equivalent (unless our secret key is exactly + * (p-1)/2, which has negligible probability and can't be influenced by the + * adversary). Checking before is cleaner in terms of side channel analysis, + * as we haven't loaded our secret yet, so no worries about branches. + * + * Use X as a temporary, since we haven't loaded it yet. + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&X, &P, 1)); // x = p - 1 + if (mbedtls_mpi_cmp_mpi(&GY, &X) >= 0) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto cleanup; + } + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&X, 1)); // x = 1 + if (mbedtls_mpi_cmp_mpi(&GY, &X) <= 0) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto cleanup; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&X, key_buffer, + key_buffer_size)); + + /* Calculate shared secret public key: K = G^(XY) mod P = GY^X mod P */ + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&K, &GY, &X, &P, NULL)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&K, shared_secret, + calculated_shared_secret_size)); + + *shared_secret_length = calculated_shared_secret_size; + + ret = 0; + +cleanup: + mbedtls_mpi_free(&P); + mbedtls_mpi_free(&X); mbedtls_mpi_free(&GY); + mbedtls_mpi_free(&K); + + if (status == PSA_SUCCESS && ret != 0) { + status = mbedtls_to_psa_error(ret); + } + + return status; +} +#endif /* MBEDTLS_PSA_BUILTIN_ALG_FFDH */ + +#endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_ffdh.h b/tf-psa-crypto/drivers/builtin/src/psa_crypto_ffdh.h new file mode 100644 index 0000000000..30cc945aea --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_ffdh.h @@ -0,0 +1,131 @@ +/* + * PSA FFDH layer on top of Mbed TLS crypto + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_FFDH_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_FFDH_H + +#include + +/** Perform a key agreement and return the FFDH shared secret. + * + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] peer_key The buffer containing the key context + * of the peer's public key. + * \param[in] peer_key_length Size of the \p peer_key buffer in + * bytes. + * \param[in] key_buffer The buffer containing the private key + * context. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in + * bytes. + * \param[out] shared_secret The buffer to which the shared secret + * is to be written. + * \param[in] shared_secret_size Size of the \p shared_secret buffer in + * bytes. + * \param[out] shared_secret_length On success, the number of bytes that make + * up the returned shared secret. + * \retval #PSA_SUCCESS + * Success. Shared secret successfully calculated. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \p key_buffer_size, \p peer_key_length, \p shared_secret_size + * do not match + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_ffdh_key_agreement( + const psa_key_attributes_t *attributes, + const uint8_t *peer_key, + size_t peer_key_length, + const uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *shared_secret, + size_t shared_secret_size, + size_t *shared_secret_length); + +/** Export a public key or the public part of a DH key pair in binary format. + * + * \param[in] attributes The attributes for the key to export. + * \param[in] key_buffer Material or context of the key to export. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[out] data Buffer where the key data is to be written. + * \param[in] data_size Size of the \p data buffer in bytes. + * \param[out] data_length On success, the number of bytes written in + * \p data + * + * \retval #PSA_SUCCESS The public key was exported successfully. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of \p key_buffer is too small. + * \retval #PSA_ERROR_NOT_PERMITTED \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_ffdh_export_public_key( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *data, + size_t data_size, + size_t *data_length); + +/** + * \brief Generate DH key. + * + * \note The signature of the function is that of a PSA driver generate_key + * entry point. + * + * \param[in] attributes The attributes for the key to generate. + * \param[out] key_buffer Buffer where the key data is to be written. + * \param[in] key_buffer_size Size of \p key_buffer in bytes. + * \param[out] key_buffer_length On success, the number of bytes written in + * \p key_buffer. + * + * \retval #PSA_SUCCESS + * The key was generated successfully. + * \retval #PSA_ERROR_NOT_SUPPORTED + * Key size in bits is invalid. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of \p key_buffer is too small. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_ffdh_generate_key( + const psa_key_attributes_t *attributes, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length); + +/** + * \brief Import DH key. + * + * \note The signature of the function is that of a PSA driver import_key + * entry point. + * + * \param[in] attributes The attributes for the key to import. + * \param[in] data The buffer containing the key data in import + * format. + * \param[in] data_length Size of the \p data buffer in bytes. + * \param[out] key_buffer The buffer containing the key data in output + * format. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. This + * size is greater or equal to \p data_length. + * \param[out] key_buffer_length The length of the data written in \p + * key_buffer in bytes. + * \param[out] bits The key size in number of bits. + * + * \retval #PSA_SUCCESS + * The key was generated successfully. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of \p key_buffer is too small. + */ +psa_status_t mbedtls_psa_ffdh_import_key( + const psa_key_attributes_t *attributes, + const uint8_t *data, size_t data_length, + uint8_t *key_buffer, size_t key_buffer_size, + size_t *key_buffer_length, size_t *bits); + +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_FFDH_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_hash.c b/tf-psa-crypto/drivers/builtin/src/psa_crypto_hash.c new file mode 100644 index 0000000000..bd1e3083f8 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_hash.c @@ -0,0 +1,458 @@ +/* + * PSA hashing layer on top of Mbed TLS software crypto + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_PSA_CRYPTO_C) + +#include +#include "psa_crypto_core.h" +#include "psa_crypto_hash.h" + +#include +#include + +#if defined(MBEDTLS_PSA_BUILTIN_HASH) +psa_status_t mbedtls_psa_hash_abort( + mbedtls_psa_hash_operation_t *operation) +{ + switch (operation->alg) { + case 0: + /* The object has (apparently) been initialized but it is not + * in use. It's ok to call abort on such an object, and there's + * nothing to do. */ + break; +#if defined(MBEDTLS_PSA_BUILTIN_ALG_MD5) + case PSA_ALG_MD5: + mbedtls_md5_free(&operation->ctx.md5); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RIPEMD160) + case PSA_ALG_RIPEMD160: + mbedtls_ripemd160_free(&operation->ctx.ripemd160); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_1) + case PSA_ALG_SHA_1: + mbedtls_sha1_free(&operation->ctx.sha1); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_224) + case PSA_ALG_SHA_224: + mbedtls_sha256_free(&operation->ctx.sha256); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_256) + case PSA_ALG_SHA_256: + mbedtls_sha256_free(&operation->ctx.sha256); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_384) + case PSA_ALG_SHA_384: + mbedtls_sha512_free(&operation->ctx.sha512); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_512) + case PSA_ALG_SHA_512: + mbedtls_sha512_free(&operation->ctx.sha512); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) + case PSA_ALG_SHA3_224: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) + case PSA_ALG_SHA3_256: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) + case PSA_ALG_SHA3_384: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512) + case PSA_ALG_SHA3_512: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_SOME_HASH) + mbedtls_sha3_free(&operation->ctx.sha3); + break; +#endif + default: + return PSA_ERROR_BAD_STATE; + } + operation->alg = 0; + return PSA_SUCCESS; +} + +psa_status_t mbedtls_psa_hash_setup( + mbedtls_psa_hash_operation_t *operation, + psa_algorithm_t alg) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + /* A context must be freshly initialized before it can be set up. */ + if (operation->alg != 0) { + return PSA_ERROR_BAD_STATE; + } + + switch (alg) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_MD5) + case PSA_ALG_MD5: + mbedtls_md5_init(&operation->ctx.md5); + ret = mbedtls_md5_starts(&operation->ctx.md5); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RIPEMD160) + case PSA_ALG_RIPEMD160: + mbedtls_ripemd160_init(&operation->ctx.ripemd160); + ret = mbedtls_ripemd160_starts(&operation->ctx.ripemd160); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_1) + case PSA_ALG_SHA_1: + mbedtls_sha1_init(&operation->ctx.sha1); + ret = mbedtls_sha1_starts(&operation->ctx.sha1); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_224) + case PSA_ALG_SHA_224: + mbedtls_sha256_init(&operation->ctx.sha256); + ret = mbedtls_sha256_starts(&operation->ctx.sha256, 1); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_256) + case PSA_ALG_SHA_256: + mbedtls_sha256_init(&operation->ctx.sha256); + ret = mbedtls_sha256_starts(&operation->ctx.sha256, 0); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_384) + case PSA_ALG_SHA_384: + mbedtls_sha512_init(&operation->ctx.sha512); + ret = mbedtls_sha512_starts(&operation->ctx.sha512, 1); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_512) + case PSA_ALG_SHA_512: + mbedtls_sha512_init(&operation->ctx.sha512); + ret = mbedtls_sha512_starts(&operation->ctx.sha512, 0); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) + case PSA_ALG_SHA3_224: + mbedtls_sha3_init(&operation->ctx.sha3); + ret = mbedtls_sha3_starts(&operation->ctx.sha3, MBEDTLS_SHA3_224); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) + case PSA_ALG_SHA3_256: + mbedtls_sha3_init(&operation->ctx.sha3); + ret = mbedtls_sha3_starts(&operation->ctx.sha3, MBEDTLS_SHA3_256); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) + case PSA_ALG_SHA3_384: + mbedtls_sha3_init(&operation->ctx.sha3); + ret = mbedtls_sha3_starts(&operation->ctx.sha3, MBEDTLS_SHA3_384); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512) + case PSA_ALG_SHA3_512: + mbedtls_sha3_init(&operation->ctx.sha3); + ret = mbedtls_sha3_starts(&operation->ctx.sha3, MBEDTLS_SHA3_512); + break; +#endif + default: + return PSA_ALG_IS_HASH(alg) ? + PSA_ERROR_NOT_SUPPORTED : + PSA_ERROR_INVALID_ARGUMENT; + } + if (ret == 0) { + operation->alg = alg; + } else { + mbedtls_psa_hash_abort(operation); + } + return mbedtls_to_psa_error(ret); +} + +psa_status_t mbedtls_psa_hash_clone( + const mbedtls_psa_hash_operation_t *source_operation, + mbedtls_psa_hash_operation_t *target_operation) +{ + switch (source_operation->alg) { + case 0: + return PSA_ERROR_BAD_STATE; +#if defined(MBEDTLS_PSA_BUILTIN_ALG_MD5) + case PSA_ALG_MD5: + mbedtls_md5_clone(&target_operation->ctx.md5, + &source_operation->ctx.md5); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RIPEMD160) + case PSA_ALG_RIPEMD160: + mbedtls_ripemd160_clone(&target_operation->ctx.ripemd160, + &source_operation->ctx.ripemd160); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_1) + case PSA_ALG_SHA_1: + mbedtls_sha1_clone(&target_operation->ctx.sha1, + &source_operation->ctx.sha1); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_224) + case PSA_ALG_SHA_224: + mbedtls_sha256_clone(&target_operation->ctx.sha256, + &source_operation->ctx.sha256); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_256) + case PSA_ALG_SHA_256: + mbedtls_sha256_clone(&target_operation->ctx.sha256, + &source_operation->ctx.sha256); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_384) + case PSA_ALG_SHA_384: + mbedtls_sha512_clone(&target_operation->ctx.sha512, + &source_operation->ctx.sha512); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_512) + case PSA_ALG_SHA_512: + mbedtls_sha512_clone(&target_operation->ctx.sha512, + &source_operation->ctx.sha512); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) + case PSA_ALG_SHA3_224: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) + case PSA_ALG_SHA3_256: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) + case PSA_ALG_SHA3_384: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512) + case PSA_ALG_SHA3_512: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_SOME_HASH) + mbedtls_sha3_clone(&target_operation->ctx.sha3, + &source_operation->ctx.sha3); + break; +#endif + default: + (void) source_operation; + (void) target_operation; + return PSA_ERROR_NOT_SUPPORTED; + } + + target_operation->alg = source_operation->alg; + return PSA_SUCCESS; +} + +psa_status_t mbedtls_psa_hash_update( + mbedtls_psa_hash_operation_t *operation, + const uint8_t *input, + size_t input_length) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + switch (operation->alg) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_MD5) + case PSA_ALG_MD5: + ret = mbedtls_md5_update(&operation->ctx.md5, + input, input_length); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RIPEMD160) + case PSA_ALG_RIPEMD160: + ret = mbedtls_ripemd160_update(&operation->ctx.ripemd160, + input, input_length); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_1) + case PSA_ALG_SHA_1: + ret = mbedtls_sha1_update(&operation->ctx.sha1, + input, input_length); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_224) + case PSA_ALG_SHA_224: + ret = mbedtls_sha256_update(&operation->ctx.sha256, + input, input_length); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_256) + case PSA_ALG_SHA_256: + ret = mbedtls_sha256_update(&operation->ctx.sha256, + input, input_length); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_384) + case PSA_ALG_SHA_384: + ret = mbedtls_sha512_update(&operation->ctx.sha512, + input, input_length); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_512) + case PSA_ALG_SHA_512: + ret = mbedtls_sha512_update(&operation->ctx.sha512, + input, input_length); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) + case PSA_ALG_SHA3_224: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) + case PSA_ALG_SHA3_256: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) + case PSA_ALG_SHA3_384: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512) + case PSA_ALG_SHA3_512: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_SOME_HASH) + ret = mbedtls_sha3_update(&operation->ctx.sha3, + input, input_length); + break; +#endif + default: + (void) input; + (void) input_length; + return PSA_ERROR_BAD_STATE; + } + + return mbedtls_to_psa_error(ret); +} + +psa_status_t mbedtls_psa_hash_finish( + mbedtls_psa_hash_operation_t *operation, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + psa_status_t status; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t actual_hash_length = PSA_HASH_LENGTH(operation->alg); + + /* Fill the output buffer with something that isn't a valid hash + * (barring an attack on the hash and deliberately-crafted input), + * in case the caller doesn't check the return status properly. */ + *hash_length = hash_size; + /* If hash_size is 0 then hash may be NULL and then the + * call to memset would have undefined behavior. */ + if (hash_size != 0) { + memset(hash, '!', hash_size); + } + + if (hash_size < actual_hash_length) { + status = PSA_ERROR_BUFFER_TOO_SMALL; + goto exit; + } + + switch (operation->alg) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_MD5) + case PSA_ALG_MD5: + ret = mbedtls_md5_finish(&operation->ctx.md5, hash); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RIPEMD160) + case PSA_ALG_RIPEMD160: + ret = mbedtls_ripemd160_finish(&operation->ctx.ripemd160, hash); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_1) + case PSA_ALG_SHA_1: + ret = mbedtls_sha1_finish(&operation->ctx.sha1, hash); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_224) + case PSA_ALG_SHA_224: + ret = mbedtls_sha256_finish(&operation->ctx.sha256, hash); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_256) + case PSA_ALG_SHA_256: + ret = mbedtls_sha256_finish(&operation->ctx.sha256, hash); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_384) + case PSA_ALG_SHA_384: + ret = mbedtls_sha512_finish(&operation->ctx.sha512, hash); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_512) + case PSA_ALG_SHA_512: + ret = mbedtls_sha512_finish(&operation->ctx.sha512, hash); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) + case PSA_ALG_SHA3_224: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) + case PSA_ALG_SHA3_256: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) + case PSA_ALG_SHA3_384: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512) + case PSA_ALG_SHA3_512: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_SOME_HASH) + ret = mbedtls_sha3_finish(&operation->ctx.sha3, hash, hash_size); + break; +#endif + default: + (void) hash; + return PSA_ERROR_BAD_STATE; + } + status = mbedtls_to_psa_error(ret); + +exit: + if (status == PSA_SUCCESS) { + *hash_length = actual_hash_length; + } + return status; +} + +psa_status_t mbedtls_psa_hash_compute( + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + mbedtls_psa_hash_operation_t operation = MBEDTLS_PSA_HASH_OPERATION_INIT; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_status_t abort_status = PSA_ERROR_CORRUPTION_DETECTED; + + *hash_length = hash_size; + status = mbedtls_psa_hash_setup(&operation, alg); + if (status != PSA_SUCCESS) { + goto exit; + } + status = mbedtls_psa_hash_update(&operation, input, input_length); + if (status != PSA_SUCCESS) { + goto exit; + } + status = mbedtls_psa_hash_finish(&operation, hash, hash_size, hash_length); + if (status != PSA_SUCCESS) { + goto exit; + } + +exit: + abort_status = mbedtls_psa_hash_abort(&operation); + if (status == PSA_SUCCESS) { + return abort_status; + } else { + return status; + } + +} +#endif /* MBEDTLS_PSA_BUILTIN_HASH */ + +#endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_hash.h b/tf-psa-crypto/drivers/builtin/src/psa_crypto_hash.h new file mode 100644 index 0000000000..032d05ce7e --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_hash.h @@ -0,0 +1,211 @@ +/* + * PSA hashing layer on top of Mbed TLS software crypto + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_HASH_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_HASH_H + +#include + +/** Calculate the hash (digest) of a message using Mbed TLS routines. + * + * \note The signature of this function is that of a PSA driver hash_compute + * entry point. This function behaves as a hash_compute entry point as + * defined in the PSA driver interface specification for transparent + * drivers. + * + * \param alg The hash algorithm to compute (\c PSA_ALG_XXX value + * such that #PSA_ALG_IS_HASH(\p alg) is true). + * \param[in] input Buffer containing the message to hash. + * \param input_length Size of the \p input buffer in bytes. + * \param[out] hash Buffer where the hash is to be written. + * \param hash_size Size of the \p hash buffer in bytes. + * \param[out] hash_length On success, the number of bytes + * that make up the hash value. This is always + * #PSA_HASH_LENGTH(\p alg). + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p alg is not supported + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * \p hash_size is too small + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_hash_compute( + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *hash, + size_t hash_size, + size_t *hash_length); + +/** Set up a multipart hash operation using Mbed TLS routines. + * + * \note The signature of this function is that of a PSA driver hash_setup + * entry point. This function behaves as a hash_setup entry point as + * defined in the PSA driver interface specification for transparent + * drivers. + * + * If an error occurs at any step after a call to mbedtls_psa_hash_setup(), the + * operation will need to be reset by a call to mbedtls_psa_hash_abort(). The + * core may call mbedtls_psa_hash_abort() at any time after the operation + * has been initialized. + * + * After a successful call to mbedtls_psa_hash_setup(), the core must + * eventually terminate the operation. The following events terminate an + * operation: + * - A successful call to mbedtls_psa_hash_finish() or mbedtls_psa_hash_verify(). + * - A call to mbedtls_psa_hash_abort(). + * + * \param[in,out] operation The operation object to set up. It must have + * been initialized to all-zero and not yet be in use. + * \param alg The hash algorithm to compute (\c PSA_ALG_XXX value + * such that #PSA_ALG_IS_HASH(\p alg) is true). + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p alg is not supported + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be inactive). + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_hash_setup( + mbedtls_psa_hash_operation_t *operation, + psa_algorithm_t alg); + +/** Clone an Mbed TLS hash operation. + * + * \note The signature of this function is that of a PSA driver hash_clone + * entry point. This function behaves as a hash_clone entry point as + * defined in the PSA driver interface specification for transparent + * drivers. + * + * This function copies the state of an ongoing hash operation to + * a new operation object. In other words, this function is equivalent + * to calling mbedtls_psa_hash_setup() on \p target_operation with the same + * algorithm that \p source_operation was set up for, then + * mbedtls_psa_hash_update() on \p target_operation with the same input that + * that was passed to \p source_operation. After this function returns, the + * two objects are independent, i.e. subsequent calls involving one of + * the objects do not affect the other object. + * + * \param[in] source_operation The active hash operation to clone. + * \param[in,out] target_operation The operation object to set up. + * It must be initialized but not active. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_BAD_STATE + * The \p source_operation state is not valid (it must be active). + * \retval #PSA_ERROR_BAD_STATE + * The \p target_operation state is not valid (it must be inactive). + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + */ +psa_status_t mbedtls_psa_hash_clone( + const mbedtls_psa_hash_operation_t *source_operation, + mbedtls_psa_hash_operation_t *target_operation); + +/** Add a message fragment to a multipart Mbed TLS hash operation. + * + * \note The signature of this function is that of a PSA driver hash_update + * entry point. This function behaves as a hash_update entry point as + * defined in the PSA driver interface specification for transparent + * drivers. + * + * The application must call mbedtls_psa_hash_setup() before calling this function. + * + * If this function returns an error status, the operation enters an error + * state and must be aborted by calling mbedtls_psa_hash_abort(). + * + * \param[in,out] operation Active hash operation. + * \param[in] input Buffer containing the message fragment to hash. + * \param input_length Size of the \p input buffer in bytes. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be active). + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_hash_update( + mbedtls_psa_hash_operation_t *operation, + const uint8_t *input, + size_t input_length); + +/** Finish the calculation of the Mbed TLS-calculated hash of a message. + * + * \note The signature of this function is that of a PSA driver hash_finish + * entry point. This function behaves as a hash_finish entry point as + * defined in the PSA driver interface specification for transparent + * drivers. + * + * The application must call mbedtls_psa_hash_setup() before calling this function. + * This function calculates the hash of the message formed by concatenating + * the inputs passed to preceding calls to mbedtls_psa_hash_update(). + * + * When this function returns successfully, the operation becomes inactive. + * If this function returns an error status, the operation enters an error + * state and must be aborted by calling mbedtls_psa_hash_abort(). + * + * \param[in,out] operation Active hash operation. + * \param[out] hash Buffer where the hash is to be written. + * \param hash_size Size of the \p hash buffer in bytes. + * \param[out] hash_length On success, the number of bytes + * that make up the hash value. This is always + * #PSA_HASH_LENGTH(\c alg) where \c alg is the + * hash algorithm that is calculated. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be active). + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p hash buffer is too small. You can determine a + * sufficient buffer size by calling #PSA_HASH_LENGTH(\c alg) + * where \c alg is the hash algorithm that is calculated. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_hash_finish( + mbedtls_psa_hash_operation_t *operation, + uint8_t *hash, + size_t hash_size, + size_t *hash_length); + +/** Abort an Mbed TLS hash operation. + * + * \note The signature of this function is that of a PSA driver hash_abort + * entry point. This function behaves as a hash_abort entry point as + * defined in the PSA driver interface specification for transparent + * drivers. + * + * Aborting an operation frees all associated resources except for the + * \p operation structure itself. Once aborted, the operation object + * can be reused for another operation by calling + * mbedtls_psa_hash_setup() again. + * + * You may call this function any time after the operation object has + * been initialized by one of the methods described in #psa_hash_operation_t. + * + * In particular, calling mbedtls_psa_hash_abort() after the operation has been + * terminated by a call to mbedtls_psa_hash_abort(), mbedtls_psa_hash_finish() or + * mbedtls_psa_hash_verify() is safe and has no effect. + * + * \param[in,out] operation Initialized hash operation. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_hash_abort( + mbedtls_psa_hash_operation_t *operation); + +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_HASH_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_mac.c b/tf-psa-crypto/drivers/builtin/src/psa_crypto_mac.c new file mode 100644 index 0000000000..82a3a79daa --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_mac.c @@ -0,0 +1,495 @@ +/* + * PSA MAC layer on top of Mbed TLS software crypto + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_PSA_CRYPTO_C) + +#include +#include "psa_crypto_core.h" +#include "psa_crypto_cipher.h" +#include "psa_crypto_mac.h" +#include + +#include +#include "mbedtls/constant_time.h" +#include + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC) +static psa_status_t psa_hmac_abort_internal( + mbedtls_psa_hmac_operation_t *hmac) +{ + mbedtls_platform_zeroize(hmac->opad, sizeof(hmac->opad)); + return psa_hash_abort(&hmac->hash_ctx); +} + +static psa_status_t psa_hmac_setup_internal( + mbedtls_psa_hmac_operation_t *hmac, + const uint8_t *key, + size_t key_length, + psa_algorithm_t hash_alg) +{ + uint8_t ipad[PSA_HMAC_MAX_HASH_BLOCK_SIZE]; + size_t i; + size_t hash_size = PSA_HASH_LENGTH(hash_alg); + size_t block_size = PSA_HASH_BLOCK_LENGTH(hash_alg); + psa_status_t status; + + hmac->alg = hash_alg; + + /* Sanity checks on block_size, to guarantee that there won't be a buffer + * overflow below. This should never trigger if the hash algorithm + * is implemented correctly. */ + /* The size checks against the ipad and opad buffers cannot be written + * `block_size > sizeof( ipad ) || block_size > sizeof( hmac->opad )` + * because that triggers -Wlogical-op on GCC 7.3. */ + if (block_size > sizeof(ipad)) { + return PSA_ERROR_NOT_SUPPORTED; + } + if (block_size > sizeof(hmac->opad)) { + return PSA_ERROR_NOT_SUPPORTED; + } + if (block_size < hash_size) { + return PSA_ERROR_NOT_SUPPORTED; + } + + if (key_length > block_size) { + status = psa_hash_compute(hash_alg, key, key_length, + ipad, sizeof(ipad), &key_length); + if (status != PSA_SUCCESS) { + goto cleanup; + } + } + /* A 0-length key is not commonly used in HMAC when used as a MAC, + * but it is permitted. It is common when HMAC is used in HKDF, for + * example. Don't call `memcpy` in the 0-length because `key` could be + * an invalid pointer which would make the behavior undefined. */ + else if (key_length != 0) { + memcpy(ipad, key, key_length); + } + + /* ipad contains the key followed by garbage. Xor and fill with 0x36 + * to create the ipad value. */ + for (i = 0; i < key_length; i++) { + ipad[i] ^= 0x36; + } + memset(ipad + key_length, 0x36, block_size - key_length); + + /* Copy the key material from ipad to opad, flipping the requisite bits, + * and filling the rest of opad with the requisite constant. */ + for (i = 0; i < key_length; i++) { + hmac->opad[i] = ipad[i] ^ 0x36 ^ 0x5C; + } + memset(hmac->opad + key_length, 0x5C, block_size - key_length); + + status = psa_hash_setup(&hmac->hash_ctx, hash_alg); + if (status != PSA_SUCCESS) { + goto cleanup; + } + + status = psa_hash_update(&hmac->hash_ctx, ipad, block_size); + +cleanup: + mbedtls_platform_zeroize(ipad, sizeof(ipad)); + + return status; +} + +static psa_status_t psa_hmac_update_internal( + mbedtls_psa_hmac_operation_t *hmac, + const uint8_t *data, + size_t data_length) +{ + return psa_hash_update(&hmac->hash_ctx, data, data_length); +} + +static psa_status_t psa_hmac_finish_internal( + mbedtls_psa_hmac_operation_t *hmac, + uint8_t *mac, + size_t mac_size) +{ + uint8_t tmp[PSA_HASH_MAX_SIZE]; + psa_algorithm_t hash_alg = hmac->alg; + size_t hash_size = 0; + size_t block_size = PSA_HASH_BLOCK_LENGTH(hash_alg); + psa_status_t status; + + status = psa_hash_finish(&hmac->hash_ctx, tmp, sizeof(tmp), &hash_size); + if (status != PSA_SUCCESS) { + return status; + } + /* From here on, tmp needs to be wiped. */ + + status = psa_hash_setup(&hmac->hash_ctx, hash_alg); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_hash_update(&hmac->hash_ctx, hmac->opad, block_size); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_hash_update(&hmac->hash_ctx, tmp, hash_size); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_hash_finish(&hmac->hash_ctx, tmp, sizeof(tmp), &hash_size); + if (status != PSA_SUCCESS) { + goto exit; + } + + memcpy(mac, tmp, mac_size); + +exit: + mbedtls_platform_zeroize(tmp, hash_size); + return status; +} +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC) +static psa_status_t cmac_setup(mbedtls_psa_mac_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + const mbedtls_cipher_info_t *cipher_info = + mbedtls_cipher_info_from_psa( + PSA_ALG_CMAC, + psa_get_key_type(attributes), + psa_get_key_bits(attributes), + NULL); + + if (cipher_info == NULL) { + return PSA_ERROR_NOT_SUPPORTED; + } + + ret = mbedtls_cipher_setup(&operation->ctx.cmac, cipher_info); + if (ret != 0) { + goto exit; + } + + ret = mbedtls_cipher_cmac_starts(&operation->ctx.cmac, + key_buffer, + psa_get_key_bits(attributes)); +exit: + return mbedtls_to_psa_error(ret); +} +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC) + +/* Initialize this driver's MAC operation structure. Once this function has been + * called, mbedtls_psa_mac_abort can run and will do the right thing. */ +static psa_status_t mac_init( + mbedtls_psa_mac_operation_t *operation, + psa_algorithm_t alg) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + operation->alg = alg; + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC) + if (PSA_ALG_FULL_LENGTH_MAC(operation->alg) == PSA_ALG_CMAC) { + mbedtls_cipher_init(&operation->ctx.cmac); + status = PSA_SUCCESS; + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC) + if (PSA_ALG_IS_HMAC(operation->alg)) { + /* We'll set up the hash operation later in psa_hmac_setup_internal. */ + operation->ctx.hmac.alg = 0; + status = PSA_SUCCESS; + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */ + { + (void) operation; + status = PSA_ERROR_NOT_SUPPORTED; + } + + if (status != PSA_SUCCESS) { + memset(operation, 0, sizeof(*operation)); + } + return status; +} + +psa_status_t mbedtls_psa_mac_abort(mbedtls_psa_mac_operation_t *operation) +{ + if (operation->alg == 0) { + /* The object has (apparently) been initialized but it is not + * in use. It's ok to call abort on such an object, and there's + * nothing to do. */ + return PSA_SUCCESS; + } else +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC) + if (PSA_ALG_FULL_LENGTH_MAC(operation->alg) == PSA_ALG_CMAC) { + mbedtls_cipher_free(&operation->ctx.cmac); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC) + if (PSA_ALG_IS_HMAC(operation->alg)) { + psa_hmac_abort_internal(&operation->ctx.hmac); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */ + { + /* Sanity check (shouldn't happen: operation->alg should + * always have been initialized to a valid value). */ + goto bad_state; + } + + operation->alg = 0; + + return PSA_SUCCESS; + +bad_state: + /* If abort is called on an uninitialized object, we can't trust + * anything. Wipe the object in case it contains confidential data. + * This may result in a memory leak if a pointer gets overwritten, + * but it's too late to do anything about this. */ + memset(operation, 0, sizeof(*operation)); + return PSA_ERROR_BAD_STATE; +} + +static psa_status_t psa_mac_setup(mbedtls_psa_mac_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + /* A context must be freshly initialized before it can be set up. */ + if (operation->alg != 0) { + return PSA_ERROR_BAD_STATE; + } + + status = mac_init(operation, alg); + if (status != PSA_SUCCESS) { + return status; + } + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC) + if (PSA_ALG_FULL_LENGTH_MAC(alg) == PSA_ALG_CMAC) { + /* Key buffer size for CMAC is dictated by the key bits set on the + * attributes, and previously validated by the core on key import. */ + (void) key_buffer_size; + status = cmac_setup(operation, attributes, key_buffer); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC) + if (PSA_ALG_IS_HMAC(alg)) { + status = psa_hmac_setup_internal(&operation->ctx.hmac, + key_buffer, + key_buffer_size, + PSA_ALG_HMAC_GET_HASH(alg)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */ + { + (void) attributes; + (void) key_buffer; + (void) key_buffer_size; + status = PSA_ERROR_NOT_SUPPORTED; + } + + if (status != PSA_SUCCESS) { + mbedtls_psa_mac_abort(operation); + } + + return status; +} + +psa_status_t mbedtls_psa_mac_sign_setup( + mbedtls_psa_mac_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg) +{ + return psa_mac_setup(operation, attributes, + key_buffer, key_buffer_size, alg); +} + +psa_status_t mbedtls_psa_mac_verify_setup( + mbedtls_psa_mac_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg) +{ + return psa_mac_setup(operation, attributes, + key_buffer, key_buffer_size, alg); +} + +psa_status_t mbedtls_psa_mac_update( + mbedtls_psa_mac_operation_t *operation, + const uint8_t *input, + size_t input_length) +{ + if (operation->alg == 0) { + return PSA_ERROR_BAD_STATE; + } + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC) + if (PSA_ALG_FULL_LENGTH_MAC(operation->alg) == PSA_ALG_CMAC) { + return mbedtls_to_psa_error( + mbedtls_cipher_cmac_update(&operation->ctx.cmac, + input, input_length)); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC) + if (PSA_ALG_IS_HMAC(operation->alg)) { + return psa_hmac_update_internal(&operation->ctx.hmac, + input, input_length); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */ + { + /* This shouldn't happen if `operation` was initialized by + * a setup function. */ + (void) input; + (void) input_length; + return PSA_ERROR_BAD_STATE; + } +} + +static psa_status_t psa_mac_finish_internal( + mbedtls_psa_mac_operation_t *operation, + uint8_t *mac, size_t mac_size) +{ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC) + if (PSA_ALG_FULL_LENGTH_MAC(operation->alg) == PSA_ALG_CMAC) { + uint8_t tmp[PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE]; + int ret = mbedtls_cipher_cmac_finish(&operation->ctx.cmac, tmp); + if (ret == 0) { + memcpy(mac, tmp, mac_size); + } + mbedtls_platform_zeroize(tmp, sizeof(tmp)); + return mbedtls_to_psa_error(ret); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC) + if (PSA_ALG_IS_HMAC(operation->alg)) { + return psa_hmac_finish_internal(&operation->ctx.hmac, + mac, mac_size); + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */ + { + /* This shouldn't happen if `operation` was initialized by + * a setup function. */ + (void) operation; + (void) mac; + (void) mac_size; + return PSA_ERROR_BAD_STATE; + } +} + +psa_status_t mbedtls_psa_mac_sign_finish( + mbedtls_psa_mac_operation_t *operation, + uint8_t *mac, + size_t mac_size, + size_t *mac_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (operation->alg == 0) { + return PSA_ERROR_BAD_STATE; + } + + status = psa_mac_finish_internal(operation, mac, mac_size); + if (status == PSA_SUCCESS) { + *mac_length = mac_size; + } + + return status; +} + +psa_status_t mbedtls_psa_mac_verify_finish( + mbedtls_psa_mac_operation_t *operation, + const uint8_t *mac, + size_t mac_length) +{ + uint8_t actual_mac[PSA_MAC_MAX_SIZE]; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (operation->alg == 0) { + return PSA_ERROR_BAD_STATE; + } + + /* Consistency check: requested MAC length fits our local buffer */ + if (mac_length > sizeof(actual_mac)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + status = psa_mac_finish_internal(operation, actual_mac, mac_length); + if (status != PSA_SUCCESS) { + goto cleanup; + } + + if (mbedtls_ct_memcmp(mac, actual_mac, mac_length) != 0) { + status = PSA_ERROR_INVALID_SIGNATURE; + } + +cleanup: + mbedtls_platform_zeroize(actual_mac, sizeof(actual_mac)); + + return status; +} + +psa_status_t mbedtls_psa_mac_compute( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *mac, + size_t mac_size, + size_t *mac_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + mbedtls_psa_mac_operation_t operation = MBEDTLS_PSA_MAC_OPERATION_INIT; + /* Make sure the whole operation is zeroed. + * PSA_MAC_OPERATION_INIT does not necessarily do it fully, + * since one field is a union and initializing a union does not + * necessarily initialize all of its members. + * In multipart operations, this is done in the API functions, + * before driver dispatch, since it needs to be done before calling + * the driver entry point. Here, we bypass the multipart API, + * so it's our job. */ + memset(&operation, 0, sizeof(operation)); + + status = psa_mac_setup(&operation, + attributes, key_buffer, key_buffer_size, + alg); + if (status != PSA_SUCCESS) { + goto exit; + } + + if (input_length > 0) { + status = mbedtls_psa_mac_update(&operation, input, input_length); + if (status != PSA_SUCCESS) { + goto exit; + } + } + + status = psa_mac_finish_internal(&operation, mac, mac_size); + if (status == PSA_SUCCESS) { + *mac_length = mac_size; + } + +exit: + mbedtls_psa_mac_abort(&operation); + + return status; +} + +#endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC || MBEDTLS_PSA_BUILTIN_ALG_CMAC */ + +#endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_mac.h b/tf-psa-crypto/drivers/builtin/src/psa_crypto_mac.h new file mode 100644 index 0000000000..73ecf57abc --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_mac.h @@ -0,0 +1,264 @@ +/* + * PSA MAC layer on top of Mbed TLS software crypto + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_MAC_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_MAC_H + +#include + +/** Calculate the MAC (message authentication code) of a message using Mbed TLS. + * + * \note The signature of this function is that of a PSA driver mac_compute + * entry point. This function behaves as a mac_compute entry point as + * defined in the PSA driver interface specification for transparent + * drivers. + * + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key to use for + * computing the MAC. This buffer contains the key + * in export representation as defined by + * psa_export_key() (i.e. the raw key bytes). + * \param key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param alg The MAC algorithm to use (\c PSA_ALG_XXX value + * such that #PSA_ALG_IS_MAC(\p alg) is true). + * \param[in] input Buffer containing the input message. + * \param input_length Size of the \p input buffer in bytes. + * \param[out] mac Buffer where the MAC value is to be written. + * \param mac_size Size of the \p mac buffer in bytes. + * \param[out] mac_length On success, the number of bytes + * that make up the MAC value. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p alg is not supported. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * \p mac_size is too small + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_mac_compute( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *mac, + size_t mac_size, + size_t *mac_length); + +/** Set up a multipart MAC calculation operation using Mbed TLS. + * + * \note The signature of this function is that of a PSA driver mac_sign_setup + * entry point. This function behaves as a mac_sign_setup entry point as + * defined in the PSA driver interface specification for transparent + * drivers. + * + * \param[in,out] operation The operation object to set up. It must have + * been initialized and not yet in use. + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key to use for + * computing the MAC. This buffer contains the key + * in export representation as defined by + * psa_export_key() (i.e. the raw key bytes). + * \param key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param alg The MAC algorithm to use (\c PSA_ALG_XXX value + * such that #PSA_ALG_IS_MAC(\p alg) is true). + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p alg is not supported. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be inactive). + */ +psa_status_t mbedtls_psa_mac_sign_setup( + mbedtls_psa_mac_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg); + +/** Set up a multipart MAC verification operation using Mbed TLS. + * + * \note The signature of this function is that of a PSA driver mac_verify_setup + * entry point. This function behaves as a mac_verify_setup entry point as + * defined in the PSA driver interface specification for transparent + * drivers. + * + * \param[in,out] operation The operation object to set up. It must have + * been initialized and not yet in use. + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the key to use for + * computing the MAC. This buffer contains the key + * in export representation as defined by + * psa_export_key() (i.e. the raw key bytes). + * \param key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param alg The MAC algorithm to use (\c PSA_ALG_XXX value + * such that #PSA_ALG_IS_MAC(\p alg) is true). + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p alg is not supported. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be inactive). + */ +psa_status_t mbedtls_psa_mac_verify_setup( + mbedtls_psa_mac_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg); + +/** Add a message fragment to a multipart MAC operation using Mbed TLS. + * + * \note The signature of this function is that of a PSA driver mac_update + * entry point. This function behaves as a mac_update entry point as + * defined in the PSA driver interface specification for transparent + * drivers. + * + * The PSA core calls mbedtls_psa_mac_sign_setup() or + * mbedtls_psa_mac_verify_setup() before calling this function. + * + * If this function returns an error status, the PSA core aborts the + * operation by calling mbedtls_psa_mac_abort(). + * + * \param[in,out] operation Active MAC operation. + * \param[in] input Buffer containing the message fragment to add to + * the MAC calculation. + * \param input_length Size of the \p input buffer in bytes. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be active). + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_mac_update( + mbedtls_psa_mac_operation_t *operation, + const uint8_t *input, + size_t input_length); + +/** Finish the calculation of the MAC of a message using Mbed TLS. + * + * \note The signature of this function is that of a PSA driver mac_sign_finish + * entry point. This function behaves as a mac_sign_finish entry point as + * defined in the PSA driver interface specification for transparent + * drivers. + * + * The PSA core calls mbedtls_psa_mac_sign_setup() before calling this function. + * This function calculates the MAC of the message formed by concatenating + * the inputs passed to preceding calls to mbedtls_psa_mac_update(). + * + * Whether this function returns successfully or not, the PSA core subsequently + * aborts the operation by calling mbedtls_psa_mac_abort(). + * + * \param[in,out] operation Active MAC operation. + * \param[out] mac Buffer where the MAC value is to be written. + * \param mac_size Output size requested for the MAC algorithm. The PSA + * core guarantees this is a valid MAC length for the + * algorithm and key combination passed to + * mbedtls_psa_mac_sign_setup(). It also guarantees the + * \p mac buffer is large enough to contain the + * requested output size. + * \param[out] mac_length On success, the number of bytes output to buffer + * \p mac, which will be equal to the requested length + * \p mac_size. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be an active mac sign + * operation). + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p mac buffer is too small. A sufficient buffer size + * can be determined by calling PSA_MAC_LENGTH(). + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_mac_sign_finish( + mbedtls_psa_mac_operation_t *operation, + uint8_t *mac, + size_t mac_size, + size_t *mac_length); + +/** Finish the calculation of the MAC of a message and compare it with + * an expected value using Mbed TLS. + * + * \note The signature of this function is that of a PSA driver + * mac_verify_finish entry point. This function behaves as a + * mac_verify_finish entry point as defined in the PSA driver interface + * specification for transparent drivers. + * + * The PSA core calls mbedtls_psa_mac_verify_setup() before calling this + * function. This function calculates the MAC of the message formed by + * concatenating the inputs passed to preceding calls to + * mbedtls_psa_mac_update(). It then compares the calculated MAC with the + * expected MAC passed as a parameter to this function. + * + * Whether this function returns successfully or not, the PSA core subsequently + * aborts the operation by calling mbedtls_psa_mac_abort(). + * + * \param[in,out] operation Active MAC operation. + * \param[in] mac Buffer containing the expected MAC value. + * \param mac_length Length in bytes of the expected MAC value. The PSA + * core guarantees that this length is a valid MAC + * length for the algorithm and key combination passed + * to mbedtls_psa_mac_verify_setup(). + * + * \retval #PSA_SUCCESS + * The expected MAC is identical to the actual MAC of the message. + * \retval #PSA_ERROR_INVALID_SIGNATURE + * The MAC of the message was calculated successfully, but it + * differs from the expected MAC. + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be an active mac verify + * operation). + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_mac_verify_finish( + mbedtls_psa_mac_operation_t *operation, + const uint8_t *mac, + size_t mac_length); + +/** Abort a MAC operation using Mbed TLS. + * + * Aborting an operation frees all associated resources except for the + * \p operation structure itself. Once aborted, the operation object + * can be reused for another operation by calling + * mbedtls_psa_mac_sign_setup() or mbedtls_psa_mac_verify_setup() again. + * + * The PSA core may call this function any time after the operation object has + * been initialized by one of the methods described in + * #mbedtls_psa_mac_operation_t. + * + * In particular, calling mbedtls_psa_mac_abort() after the operation has been + * terminated by a call to mbedtls_psa_mac_abort(), + * mbedtls_psa_mac_sign_finish() or mbedtls_psa_mac_verify_finish() is safe and + * has no effect. + * + * \param[in,out] operation Initialized MAC operation. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_mac_abort( + mbedtls_psa_mac_operation_t *operation); + +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_MAC_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_pake.c b/tf-psa-crypto/drivers/builtin/src/psa_crypto_pake.c new file mode 100644 index 0000000000..2e5c38c623 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_pake.c @@ -0,0 +1,568 @@ +/* + * PSA PAKE layer on top of Mbed TLS software crypto + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_PSA_CRYPTO_C) + +#include +#include "psa_crypto_core.h" +#include "psa_crypto_pake.h" +#include "psa_crypto_slot_management.h" + +#include +#include "psa_util_internal.h" + +#include +#include +#include + +/* + * State sequence: + * + * psa_pake_setup() + * | + * |-- In any order: + * | | psa_pake_set_user() + * | | psa_pake_set_peer() + * | | psa_pake_set_role() + * | + * |--- In any order: (First round input before or after first round output) + * | | + * | |------ In Order + * | | | psa_pake_output(PSA_PAKE_STEP_KEY_SHARE) + * | | | psa_pake_output(PSA_PAKE_STEP_ZK_PUBLIC) + * | | | psa_pake_output(PSA_PAKE_STEP_ZK_PROOF) + * | | | psa_pake_output(PSA_PAKE_STEP_KEY_SHARE) + * | | | psa_pake_output(PSA_PAKE_STEP_ZK_PUBLIC) + * | | | psa_pake_output(PSA_PAKE_STEP_ZK_PROOF) + * | | + * | |------ In Order: + * | | psa_pake_input(PSA_PAKE_STEP_KEY_SHARE) + * | | psa_pake_input(PSA_PAKE_STEP_ZK_PUBLIC) + * | | psa_pake_input(PSA_PAKE_STEP_ZK_PROOF) + * | | psa_pake_input(PSA_PAKE_STEP_KEY_SHARE) + * | | psa_pake_input(PSA_PAKE_STEP_ZK_PUBLIC) + * | | psa_pake_input(PSA_PAKE_STEP_ZK_PROOF) + * | + * |--- In any order: (Second round input before or after second round output) + * | | + * | |------ In Order + * | | | psa_pake_output(PSA_PAKE_STEP_KEY_SHARE) + * | | | psa_pake_output(PSA_PAKE_STEP_ZK_PUBLIC) + * | | | psa_pake_output(PSA_PAKE_STEP_ZK_PROOF) + * | | + * | |------ In Order: + * | | psa_pake_input(PSA_PAKE_STEP_KEY_SHARE) + * | | psa_pake_input(PSA_PAKE_STEP_ZK_PUBLIC) + * | | psa_pake_input(PSA_PAKE_STEP_ZK_PROOF) + * | + * psa_pake_get_shared_key() + * psa_pake_abort() + */ + +/* + * Possible sequence of calls to implementation: + * + * |--- In any order: + * | | + * | |------ In Order + * | | | mbedtls_psa_pake_output(PSA_JPAKE_X1_STEP_KEY_SHARE) + * | | | mbedtls_psa_pake_output(PSA_JPAKE_X1_STEP_ZK_PUBLIC) + * | | | mbedtls_psa_pake_output(PSA_JPAKE_X1_STEP_ZK_PROOF) + * | | | mbedtls_psa_pake_output(PSA_JPAKE_X2_STEP_KEY_SHARE) + * | | | mbedtls_psa_pake_output(PSA_JPAKE_X2_STEP_ZK_PUBLIC) + * | | | mbedtls_psa_pake_output(PSA_JPAKE_X2_STEP_ZK_PROOF) + * | | + * | |------ In Order: + * | | mbedtls_psa_pake_input(PSA_JPAKE_X1_STEP_KEY_SHARE) + * | | mbedtls_psa_pake_input(PSA_JPAKE_X1_STEP_ZK_PUBLIC) + * | | mbedtls_psa_pake_input(PSA_JPAKE_X1_STEP_ZK_PROOF) + * | | mbedtls_psa_pake_input(PSA_JPAKE_X2_STEP_KEY_SHARE) + * | | mbedtls_psa_pake_input(PSA_JPAKE_X2_STEP_ZK_PUBLIC) + * | | mbedtls_psa_pake_input(PSA_JPAKE_X2_STEP_ZK_PROOF) + * | + * |--- In any order: + * | | + * | |------ In Order + * | | | mbedtls_psa_pake_output(PSA_JPAKE_X2S_STEP_KEY_SHARE) + * | | | mbedtls_psa_pake_output(PSA_JPAKE_X2S_STEP_ZK_PUBLIC) + * | | | mbedtls_psa_pake_output(PSA_JPAKE_X2S_STEP_ZK_PROOF) + * | | + * | |------ In Order: + * | | mbedtls_psa_pake_input(PSA_JPAKE_X4S_STEP_KEY_SHARE) + * | | mbedtls_psa_pake_input(PSA_JPAKE_X4S_STEP_ZK_PUBLIC) + * | | mbedtls_psa_pake_input(PSA_JPAKE_X4S_STEP_ZK_PROOF) + */ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE) +static psa_status_t mbedtls_ecjpake_to_psa_error(int ret) +{ + /* Only legacy error codes need to be translated. + * Those are either a low-level error code (-127..-2) + * or a high-level error code (<= -0x1000). */ + if (ret > -0x1000 && ret <= -0x80) { + return (psa_status_t) ret; + } + switch (ret) { + case MBEDTLS_ERR_ECP_INVALID_KEY: + return PSA_ERROR_DATA_INVALID; + case MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE: + return PSA_ERROR_NOT_SUPPORTED; + default: + return PSA_ERROR_GENERIC_ERROR; + } +} +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_PAKE) +#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE) +static psa_status_t psa_pake_ecjpake_setup(mbedtls_psa_pake_operation_t *operation) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + mbedtls_ecjpake_init(&operation->ctx.jpake); + + ret = mbedtls_ecjpake_setup(&operation->ctx.jpake, + operation->role, + MBEDTLS_MD_SHA256, + MBEDTLS_ECP_DP_SECP256R1, + operation->password, + operation->password_len); + + mbedtls_platform_zeroize(operation->password, operation->password_len); + + if (ret != 0) { + return mbedtls_ecjpake_to_psa_error(ret); + } + + return PSA_SUCCESS; +} +#endif + +/* The only two JPAKE user/peer identifiers supported in built-in implementation. */ +static const uint8_t jpake_server_id[] = { 's', 'e', 'r', 'v', 'e', 'r' }; +static const uint8_t jpake_client_id[] = { 'c', 'l', 'i', 'e', 'n', 't' }; + +psa_status_t mbedtls_psa_pake_setup(mbedtls_psa_pake_operation_t *operation, + const psa_crypto_driver_pake_inputs_t *inputs) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + size_t user_len = 0, peer_len = 0, password_len = 0; + uint8_t *peer = NULL, *user = NULL; + size_t actual_user_len = 0, actual_peer_len = 0, actual_password_len = 0; + psa_pake_cipher_suite_t cipher_suite = psa_pake_cipher_suite_init(); + + status = psa_crypto_driver_pake_get_password_len(inputs, &password_len); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_crypto_driver_pake_get_user_len(inputs, &user_len); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_crypto_driver_pake_get_peer_len(inputs, &peer_len); + if (status != PSA_SUCCESS) { + return status; + } + + status = psa_crypto_driver_pake_get_cipher_suite(inputs, &cipher_suite); + if (status != PSA_SUCCESS) { + return status; + } + + operation->password = mbedtls_calloc(1, password_len); + if (operation->password == NULL) { + status = PSA_ERROR_INSUFFICIENT_MEMORY; + goto error; + } + + user = mbedtls_calloc(1, user_len); + if (user == NULL) { + status = PSA_ERROR_INSUFFICIENT_MEMORY; + goto error; + } + + peer = mbedtls_calloc(1, peer_len); + if (peer == NULL) { + status = PSA_ERROR_INSUFFICIENT_MEMORY; + goto error; + } + + status = psa_crypto_driver_pake_get_password(inputs, operation->password, + password_len, &actual_password_len); + if (status != PSA_SUCCESS) { + goto error; + } + + status = psa_crypto_driver_pake_get_user(inputs, user, + user_len, &actual_user_len); + if (status != PSA_SUCCESS) { + goto error; + } + + status = psa_crypto_driver_pake_get_peer(inputs, peer, + peer_len, &actual_peer_len); + if (status != PSA_SUCCESS) { + goto error; + } + + operation->password_len = actual_password_len; + operation->alg = cipher_suite.algorithm; + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE) + if (PSA_ALG_IS_JPAKE(cipher_suite.algorithm)) { + if (cipher_suite.type != PSA_PAKE_PRIMITIVE_TYPE_ECC || + cipher_suite.family != PSA_ECC_FAMILY_SECP_R1 || + cipher_suite.bits != 256 || + PSA_ALG_GET_HASH(cipher_suite.algorithm) != PSA_ALG_SHA_256) { + status = PSA_ERROR_NOT_SUPPORTED; + goto error; + } + + const size_t user_peer_len = sizeof(jpake_client_id); // client and server have the same length + if (actual_user_len != user_peer_len || + actual_peer_len != user_peer_len) { + status = PSA_ERROR_NOT_SUPPORTED; + goto error; + } + + if (memcmp(user, jpake_client_id, actual_user_len) == 0 && + memcmp(peer, jpake_server_id, actual_peer_len) == 0) { + operation->role = MBEDTLS_ECJPAKE_CLIENT; + } else + if (memcmp(user, jpake_server_id, actual_user_len) == 0 && + memcmp(peer, jpake_client_id, actual_peer_len) == 0) { + operation->role = MBEDTLS_ECJPAKE_SERVER; + } else { + status = PSA_ERROR_NOT_SUPPORTED; + goto error; + } + + operation->buffer_length = 0; + operation->buffer_offset = 0; + + status = psa_pake_ecjpake_setup(operation); + if (status != PSA_SUCCESS) { + goto error; + } + + /* Role has been set, release user/peer buffers. */ + mbedtls_free(user); mbedtls_free(peer); + + return PSA_SUCCESS; + } else +#else + (void) operation; + (void) inputs; +#endif + { status = PSA_ERROR_NOT_SUPPORTED; } + +error: + mbedtls_free(user); mbedtls_free(peer); + /* In case of failure of the setup of a multipart operation, the PSA driver interface + * specifies that the core does not call any other driver entry point thus does not + * call mbedtls_psa_pake_abort(). Therefore call it here to do the needed clean + * up like freeing the memory that may have been allocated to store the password. + */ + mbedtls_psa_pake_abort(operation); + return status; +} + +static psa_status_t mbedtls_psa_pake_output_internal( + mbedtls_psa_pake_operation_t *operation, + psa_crypto_driver_pake_step_t step, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t length; + (void) step; // Unused parameter + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE) + /* + * The PSA CRYPTO PAKE and Mbed TLS JPAKE API have a different + * handling of output sequencing. + * + * The Mbed TLS JPAKE API outputs the whole X1+X2 and X2S steps data + * at once, on the other side the PSA CRYPTO PAKE api requires + * the KEY_SHARE/ZP_PUBLIC/ZK_PROOF parts of X1, X2 & X2S to be + * retrieved in sequence. + * + * In order to achieve API compatibility, the whole X1+X2 or X2S steps + * data is stored in an intermediate buffer at first step output call, + * and data is sliced down by parsing the ECPoint records in order + * to return the right parts on each step. + */ + if (PSA_ALG_IS_JPAKE(operation->alg)) { + /* Initialize & write round on KEY_SHARE sequences */ + if (step == PSA_JPAKE_X1_STEP_KEY_SHARE) { + ret = mbedtls_ecjpake_write_round_one(&operation->ctx.jpake, + operation->buffer, + sizeof(operation->buffer), + &operation->buffer_length, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE); + if (ret != 0) { + return mbedtls_ecjpake_to_psa_error(ret); + } + + operation->buffer_offset = 0; + } else if (step == PSA_JPAKE_X2S_STEP_KEY_SHARE) { + ret = mbedtls_ecjpake_write_round_two(&operation->ctx.jpake, + operation->buffer, + sizeof(operation->buffer), + &operation->buffer_length, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE); + if (ret != 0) { + return mbedtls_ecjpake_to_psa_error(ret); + } + + operation->buffer_offset = 0; + } + + /* + * mbedtls_ecjpake_write_round_xxx() outputs thing in the format + * defined by draft-cragie-tls-ecjpake-01 section 7. The summary is + * that the data for each step is prepended with a length byte, and + * then they're concatenated. Additionally, the server's second round + * output is prepended with a 3-bytes ECParameters structure. + * + * In PSA, we output each step separately, and don't prepend the + * output with a length byte, even less a curve identifier, as that + * information is already available. + */ + if (step == PSA_JPAKE_X2S_STEP_KEY_SHARE && + operation->role == MBEDTLS_ECJPAKE_SERVER) { + /* Skip ECParameters, with is 3 bytes (RFC 8422) */ + operation->buffer_offset += 3; + } + + /* Read the length byte then move past it to the data */ + length = operation->buffer[operation->buffer_offset]; + operation->buffer_offset += 1; + + if (operation->buffer_offset + length > operation->buffer_length) { + return PSA_ERROR_DATA_CORRUPT; + } + + if (output_size < length) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + memcpy(output, + operation->buffer + operation->buffer_offset, + length); + *output_length = length; + + operation->buffer_offset += length; + + /* Reset buffer after ZK_PROOF sequence */ + if ((step == PSA_JPAKE_X2_STEP_ZK_PROOF) || + (step == PSA_JPAKE_X2S_STEP_ZK_PROOF)) { + mbedtls_platform_zeroize(operation->buffer, sizeof(operation->buffer)); + operation->buffer_length = 0; + operation->buffer_offset = 0; + } + + return PSA_SUCCESS; + } else +#else + (void) step; + (void) output; + (void) output_size; + (void) output_length; +#endif + { return PSA_ERROR_NOT_SUPPORTED; } +} + +psa_status_t mbedtls_psa_pake_output(mbedtls_psa_pake_operation_t *operation, + psa_crypto_driver_pake_step_t step, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + psa_status_t status = mbedtls_psa_pake_output_internal( + operation, step, output, output_size, output_length); + + return status; +} + +static psa_status_t mbedtls_psa_pake_input_internal( + mbedtls_psa_pake_operation_t *operation, + psa_crypto_driver_pake_step_t step, + const uint8_t *input, + size_t input_length) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + (void) step; // Unused parameter + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE) + /* + * The PSA CRYPTO PAKE and Mbed TLS JPAKE API have a different + * handling of input sequencing. + * + * The Mbed TLS JPAKE API takes the whole X1+X2 or X4S steps data + * at once as input, on the other side the PSA CRYPTO PAKE api requires + * the KEY_SHARE/ZP_PUBLIC/ZK_PROOF parts of X1, X2 & X4S to be + * given in sequence. + * + * In order to achieve API compatibility, each X1+X2 or X4S step data + * is stored sequentially in an intermediate buffer and given to the + * Mbed TLS JPAKE API on the last step. + * + * This causes any input error to be only detected on the last step. + */ + if (PSA_ALG_IS_JPAKE(operation->alg)) { + /* + * Copy input to local buffer and format it as the Mbed TLS API + * expects, i.e. as defined by draft-cragie-tls-ecjpake-01 section 7. + * The summary is that the data for each step is prepended with a + * length byte, and then they're concatenated. Additionally, the + * server's second round output is prepended with a 3-bytes + * ECParameters structure - which means we have to prepend that when + * we're a client. + */ + if (step == PSA_JPAKE_X4S_STEP_KEY_SHARE && + operation->role == MBEDTLS_ECJPAKE_CLIENT) { + /* We only support secp256r1. */ + /* This is the ECParameters structure defined by RFC 8422. */ + unsigned char ecparameters[3] = { + 3, /* named_curve */ + 0, 23 /* secp256r1 */ + }; + + if (operation->buffer_length + sizeof(ecparameters) > + sizeof(operation->buffer)) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + memcpy(operation->buffer + operation->buffer_length, + ecparameters, sizeof(ecparameters)); + operation->buffer_length += sizeof(ecparameters); + } + + /* + * The core checks that input_length is smaller than + * PSA_PAKE_INPUT_MAX_SIZE. + * Thus no risk of integer overflow here. + */ + if (operation->buffer_length + input_length + 1 > sizeof(operation->buffer)) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + /* Write the length byte */ + operation->buffer[operation->buffer_length] = (uint8_t) input_length; + operation->buffer_length += 1; + + /* Finally copy the data */ + memcpy(operation->buffer + operation->buffer_length, + input, input_length); + operation->buffer_length += input_length; + + /* Load buffer at each last round ZK_PROOF */ + if (step == PSA_JPAKE_X2_STEP_ZK_PROOF) { + ret = mbedtls_ecjpake_read_round_one(&operation->ctx.jpake, + operation->buffer, + operation->buffer_length); + + mbedtls_platform_zeroize(operation->buffer, sizeof(operation->buffer)); + operation->buffer_length = 0; + + if (ret != 0) { + return mbedtls_ecjpake_to_psa_error(ret); + } + } else if (step == PSA_JPAKE_X4S_STEP_ZK_PROOF) { + ret = mbedtls_ecjpake_read_round_two(&operation->ctx.jpake, + operation->buffer, + operation->buffer_length); + + mbedtls_platform_zeroize(operation->buffer, sizeof(operation->buffer)); + operation->buffer_length = 0; + + if (ret != 0) { + return mbedtls_ecjpake_to_psa_error(ret); + } + } + + return PSA_SUCCESS; + } else +#else + (void) step; + (void) input; + (void) input_length; +#endif + { return PSA_ERROR_NOT_SUPPORTED; } +} + +psa_status_t mbedtls_psa_pake_input(mbedtls_psa_pake_operation_t *operation, + psa_crypto_driver_pake_step_t step, + const uint8_t *input, + size_t input_length) +{ + psa_status_t status = mbedtls_psa_pake_input_internal( + operation, step, input, input_length); + + return status; +} + +psa_status_t mbedtls_psa_pake_get_implicit_key( + mbedtls_psa_pake_operation_t *operation, + uint8_t *output, size_t output_size, + size_t *output_length) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE) + if (PSA_ALG_IS_JPAKE(operation->alg)) { + ret = mbedtls_ecjpake_write_shared_key(&operation->ctx.jpake, + output, + output_size, + output_length, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE); + if (ret != 0) { + return mbedtls_ecjpake_to_psa_error(ret); + } + + return PSA_SUCCESS; + } else +#else + (void) output; +#endif + { return PSA_ERROR_NOT_SUPPORTED; } +} + +psa_status_t mbedtls_psa_pake_abort(mbedtls_psa_pake_operation_t *operation) +{ + mbedtls_zeroize_and_free(operation->password, operation->password_len); + operation->password = NULL; + operation->password_len = 0; + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE) + if (PSA_ALG_IS_JPAKE(operation->alg)) { + operation->role = MBEDTLS_ECJPAKE_NONE; + mbedtls_platform_zeroize(operation->buffer, sizeof(operation->buffer)); + operation->buffer_length = 0; + operation->buffer_offset = 0; + mbedtls_ecjpake_free(&operation->ctx.jpake); + } +#endif + + operation->alg = PSA_ALG_NONE; + + return PSA_SUCCESS; +} + +#endif /* MBEDTLS_PSA_BUILTIN_PAKE */ + +#endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_pake.h b/tf-psa-crypto/drivers/builtin/src/psa_crypto_pake.h new file mode 100644 index 0000000000..4fe43aa40d --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_pake.h @@ -0,0 +1,159 @@ +/* + * PSA PAKE layer on top of Mbed TLS software crypto + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_PAKE_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_PAKE_H + +#include + +/** Set the session information for a password-authenticated key exchange. + * + * \note The signature of this function is that of a PSA driver + * pake_setup entry point. This function behaves as a pake_setup + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \param[in,out] operation The operation object to set up. It must have + * been initialized but not set up yet. + * \param[in] inputs Inputs required for PAKE operation (role, password, + * key lifetime, cipher suite) + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_NOT_SUPPORTED + * The algorithm in \p cipher_suite is not a supported PAKE algorithm, + * or the PAKE primitive in \p cipher_suite is not supported or not + * compatible with the PAKE algorithm, or the hash algorithm in + * \p cipher_suite is not supported or not compatible with the PAKE + * algorithm and primitive. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_pake_setup(mbedtls_psa_pake_operation_t *operation, + const psa_crypto_driver_pake_inputs_t *inputs); + + +/** Get output for a step of a password-authenticated key exchange. + * + * \note The signature of this function is that of a PSA driver + * pake_output entry point. This function behaves as a pake_output + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \param[in,out] operation Active PAKE operation. + * \param step The step of the algorithm for which the output is + * requested. + * \param[out] output Buffer where the output is to be written in the + * format appropriate for this driver \p step. Refer to + * the documentation of psa_crypto_driver_pake_step_t for + * more information. + * \param output_size Size of the \p output buffer in bytes. This must + * be at least #PSA_PAKE_OUTPUT_SIZE(\p alg, \p + * primitive, \p step) where \p alg and + * \p primitive are the PAKE algorithm and primitive + * in the operation's cipher suite, and \p step is + * the output step. + * + * \param[out] output_length On success, the number of bytes of the returned + * output. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p output buffer is too small. + * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription + * \retval #PSA_ERROR_DATA_INVALID \emptydescription + */ +psa_status_t mbedtls_psa_pake_output(mbedtls_psa_pake_operation_t *operation, + psa_crypto_driver_pake_step_t step, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** Provide input for a step of a password-authenticated key exchange. + * + * \note The signature of this function is that of a PSA driver + * pake_input entry point. This function behaves as a pake_input + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \note The core checks that input_length is smaller than PSA_PAKE_INPUT_MAX_SIZE. + * + * \param[in,out] operation Active PAKE operation. + * \param step The driver step for which the input is provided. + * \param[in] input Buffer containing the input in the format + * appropriate for this \p step. Refer to the + * documentation of psa_crypto_driver_pake_step_t + * for more information. + * \param input_length Size of the \p input buffer in bytes. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_INVALID_SIGNATURE + * The verification fails for a zero-knowledge input step. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * the \p input is not valid for the \p operation's algorithm, cipher suite + * or \p step. + * \retval #PSA_ERROR_NOT_SUPPORTED + * the \p input is not supported for the \p operation's algorithm, cipher + * suite or \p step. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription + * \retval #PSA_ERROR_DATA_INVALID \emptydescription + */ +psa_status_t mbedtls_psa_pake_input(mbedtls_psa_pake_operation_t *operation, + psa_crypto_driver_pake_step_t step, + const uint8_t *input, + size_t input_length); + +/** Get implicitly confirmed shared secret from a PAKE. + * + * \note The signature of this function is that of a PSA driver + * pake_get_implicit_key entry point. This function behaves as a + * pake_get_implicit_key entry point as defined in the PSA driver + * interface specification for transparent drivers. + * + * \param[in,out] operation Active PAKE operation. + * \param[out] output Output buffer for implicit key. + * \param output_size Size of the output buffer in bytes. + * \param[out] output_length On success, the number of bytes of the implicit key. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_NOT_SUPPORTED + * Input from a PAKE is not supported by the algorithm in the \p output + * key derivation operation. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription + * \retval #PSA_ERROR_DATA_INVALID \emptydescription + */ +psa_status_t mbedtls_psa_pake_get_implicit_key( + mbedtls_psa_pake_operation_t *operation, + uint8_t *output, size_t output_size, + size_t *output_length); + +/** Abort a PAKE operation. + * + * \note The signature of this function is that of a PSA driver + * pake_abort entry point. This function behaves as a pake_abort + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \param[in,out] operation The operation to abort. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_pake_abort(mbedtls_psa_pake_operation_t *operation); + +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_PAKE_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_rsa.c b/tf-psa-crypto/drivers/builtin/src/psa_crypto_rsa.c new file mode 100644 index 0000000000..9f369a7c63 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_rsa.c @@ -0,0 +1,699 @@ +/* + * PSA RSA layer on top of Mbed TLS crypto + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_PSA_CRYPTO_C) + +#include +#include "psa/crypto_values.h" +#include "psa_crypto_core.h" +#include "psa_crypto_random_impl.h" +#include "psa_crypto_rsa.h" +#include "psa_crypto_hash.h" +#include "mbedtls/psa_util.h" + +#include +#include +#include +#include "mbedtls/platform.h" + +#include +#include +#include "rsa_internal.h" + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_IMPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) + +/* Mbed TLS doesn't support non-byte-aligned key sizes (i.e. key sizes + * that are not a multiple of 8) well. For example, there is only + * mbedtls_rsa_get_len(), which returns a number of bytes, and no + * way to return the exact bit size of a key. + * To keep things simple, reject non-byte-aligned key sizes. */ +static psa_status_t psa_check_rsa_key_byte_aligned( + const mbedtls_rsa_context *rsa) +{ + if (mbedtls_mpi_bitlen(&rsa->N) % 8 != 0) { + return PSA_ERROR_NOT_SUPPORTED; + } + + return PSA_SUCCESS; +} + +psa_status_t mbedtls_psa_rsa_load_representation( + psa_key_type_t type, const uint8_t *data, size_t data_length, + mbedtls_rsa_context **p_rsa) +{ + psa_status_t status; + size_t bits; + + *p_rsa = mbedtls_calloc(1, sizeof(mbedtls_rsa_context)); + if (*p_rsa == NULL) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } + mbedtls_rsa_init(*p_rsa); + + /* Parse the data. */ + if (PSA_KEY_TYPE_IS_KEY_PAIR(type)) { + status = mbedtls_to_psa_error(mbedtls_rsa_parse_key(*p_rsa, data, data_length)); + } else { + status = mbedtls_to_psa_error(mbedtls_rsa_parse_pubkey(*p_rsa, data, data_length)); + } + if (status != PSA_SUCCESS) { + goto exit; + } + + /* The size of an RSA key doesn't have to be a multiple of 8. Mbed TLS + * supports non-byte-aligned key sizes, but not well. For example, + * mbedtls_rsa_get_len() returns the key size in bytes, not in bits. */ + bits = PSA_BYTES_TO_BITS(mbedtls_rsa_get_len(*p_rsa)); + if (bits > PSA_VENDOR_RSA_MAX_KEY_BITS) { + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; + } + status = psa_check_rsa_key_byte_aligned(*p_rsa); + if (status != PSA_SUCCESS) { + goto exit; + } + +exit: + return status; +} +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS) || + * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_IMPORT) || + * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT) || + * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) */ + +#if (defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_IMPORT) && \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT)) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) +psa_status_t mbedtls_psa_rsa_import_key( + const psa_key_attributes_t *attributes, + const uint8_t *data, size_t data_length, + uint8_t *key_buffer, size_t key_buffer_size, + size_t *key_buffer_length, size_t *bits) +{ + psa_status_t status; + mbedtls_rsa_context *rsa = NULL; + + /* Parse input */ + status = mbedtls_psa_rsa_load_representation(attributes->type, + data, + data_length, + &rsa); + if (status != PSA_SUCCESS) { + goto exit; + } + + *bits = (psa_key_bits_t) PSA_BYTES_TO_BITS(mbedtls_rsa_get_len(rsa)); + + /* Re-export the data to PSA export format, such that we can store export + * representation in the key slot. Export representation in case of RSA is + * the smallest representation that's allowed as input, so a straight-up + * allocation of the same size as the input buffer will be large enough. */ + status = mbedtls_psa_rsa_export_key(attributes->type, + rsa, + key_buffer, + key_buffer_size, + key_buffer_length); +exit: + /* Always free the RSA object */ + mbedtls_rsa_free(rsa); + mbedtls_free(rsa); + + return status; +} +#endif /* (defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_IMPORT) && + * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT)) || + * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) */ + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT) || \ + defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) +psa_status_t mbedtls_psa_rsa_export_key(psa_key_type_t type, + mbedtls_rsa_context *rsa, + uint8_t *data, + size_t data_size, + size_t *data_length) +{ + int ret; + uint8_t *end = data + data_size; + + /* PSA Crypto API defines the format of an RSA key as a DER-encoded + * representation of the non-encrypted PKCS#1 RSAPrivateKey for a + * private key and of the RFC3279 RSAPublicKey for a public key. */ + if (PSA_KEY_TYPE_IS_KEY_PAIR(type)) { + ret = mbedtls_rsa_write_key(rsa, data, &end); + } else { + ret = mbedtls_rsa_write_pubkey(rsa, data, &end); + } + + if (ret < 0) { + /* Clean up in case pk_write failed halfway through. */ + memset(data, 0, data_size); + return mbedtls_to_psa_error(ret); + } + + /* The mbedtls_pk_xxx functions write to the end of the buffer. + * Move the data to the beginning and erase remaining data + * at the original location. */ + if (2 * (size_t) ret <= data_size) { + memcpy(data, data + data_size - ret, ret); + memset(data + data_size - ret, 0, ret); + } else if ((size_t) ret < data_size) { + memmove(data, data + data_size - ret, ret); + memset(data + ret, 0, data_size - ret); + } + + *data_length = ret; + return PSA_SUCCESS; +} + +psa_status_t mbedtls_psa_rsa_export_public_key( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + uint8_t *data, size_t data_size, size_t *data_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + mbedtls_rsa_context *rsa = NULL; + + status = mbedtls_psa_rsa_load_representation( + attributes->type, key_buffer, key_buffer_size, &rsa); + if (status == PSA_SUCCESS) { + status = mbedtls_psa_rsa_export_key(PSA_KEY_TYPE_RSA_PUBLIC_KEY, + rsa, + data, + data_size, + data_length); + } + mbedtls_rsa_free(rsa); + mbedtls_free(rsa); + + return status; +} +#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_EXPORT) || + * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) */ + +#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE) +static psa_status_t psa_rsa_read_exponent(const uint8_t *e_bytes, + size_t e_length, + int *exponent) +{ + size_t i; + uint32_t acc = 0; + + /* Mbed TLS encodes the public exponent as an int. For simplicity, only + * support values that fit in a 32-bit integer, which is larger than + * int on just about every platform anyway. */ + if (e_length > sizeof(acc)) { + return PSA_ERROR_NOT_SUPPORTED; + } + for (i = 0; i < e_length; i++) { + acc = (acc << 8) | e_bytes[i]; + } + if (acc > INT_MAX) { + return PSA_ERROR_NOT_SUPPORTED; + } + *exponent = acc; + return PSA_SUCCESS; +} + +psa_status_t mbedtls_psa_rsa_generate_key( + const psa_key_attributes_t *attributes, + const uint8_t *custom_data, size_t custom_data_length, + uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length) +{ + psa_status_t status; + mbedtls_rsa_context rsa; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + int exponent = 65537; + + if (custom_data_length != 0) { + status = psa_rsa_read_exponent(custom_data, custom_data_length, + &exponent); + if (status != PSA_SUCCESS) { + return status; + } + } + + mbedtls_rsa_init(&rsa); + ret = mbedtls_rsa_gen_key(&rsa, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE, + (unsigned int) attributes->bits, + exponent); + if (ret != 0) { + mbedtls_rsa_free(&rsa); + return mbedtls_to_psa_error(ret); + } + + status = mbedtls_psa_rsa_export_key(attributes->type, + &rsa, key_buffer, key_buffer_size, + key_buffer_length); + mbedtls_rsa_free(&rsa); + + return status; +} +#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR_GENERATE) */ + +/****************************************************************/ +/* Sign/verify hashes */ +/****************************************************************/ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS) + +/* Decode the hash algorithm from alg and store the mbedtls encoding in + * md_alg. Verify that the hash length is acceptable. */ +static psa_status_t psa_rsa_decode_md_type(psa_algorithm_t alg, + size_t hash_length, + mbedtls_md_type_t *md_alg) +{ + psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH(alg); + *md_alg = mbedtls_md_type_from_psa_alg(hash_alg); + + /* The Mbed TLS RSA module uses an unsigned int for hash length + * parameters. Validate that it fits so that we don't risk an + * overflow later. */ +#if SIZE_MAX > UINT_MAX + if (hash_length > UINT_MAX) { + return PSA_ERROR_INVALID_ARGUMENT; + } +#endif + + /* For signatures using a hash, the hash length must be correct. */ + if (alg != PSA_ALG_RSA_PKCS1V15_SIGN_RAW) { + if (*md_alg == MBEDTLS_MD_NONE) { + return PSA_ERROR_NOT_SUPPORTED; + } + if (mbedtls_md_get_size_from_type(*md_alg) != hash_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + } + + return PSA_SUCCESS; +} + +psa_status_t mbedtls_psa_rsa_sign_hash( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *hash, size_t hash_length, + uint8_t *signature, size_t signature_size, size_t *signature_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + mbedtls_rsa_context *rsa = NULL; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_md_type_t md_alg; + + status = mbedtls_psa_rsa_load_representation(attributes->type, + key_buffer, + key_buffer_size, + &rsa); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_rsa_decode_md_type(alg, hash_length, &md_alg); + if (status != PSA_SUCCESS) { + goto exit; + } + + if (signature_size < mbedtls_rsa_get_len(rsa)) { + status = PSA_ERROR_BUFFER_TOO_SMALL; + goto exit; + } + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) + if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg)) { + ret = mbedtls_rsa_set_padding(rsa, MBEDTLS_RSA_PKCS_V15, + MBEDTLS_MD_NONE); + if (ret == 0) { + ret = mbedtls_rsa_pkcs1_sign(rsa, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE, + md_alg, + (unsigned int) hash_length, + hash, + signature); + } + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS) + if (PSA_ALG_IS_RSA_PSS(alg)) { + ret = mbedtls_rsa_set_padding(rsa, MBEDTLS_RSA_PKCS_V21, md_alg); + + if (ret == 0) { + ret = mbedtls_rsa_rsassa_pss_sign_ext(rsa, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE, + MBEDTLS_MD_NONE, + (unsigned int) hash_length, + hash, + MBEDTLS_RSA_SALT_LEN_ANY, + signature); + } + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS */ + { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + if (ret == 0) { + *signature_length = mbedtls_rsa_get_len(rsa); + } + status = mbedtls_to_psa_error(ret); + +exit: + mbedtls_rsa_free(rsa); + mbedtls_free(rsa); + + return status; +} + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS) +static int rsa_pss_expected_salt_len(psa_algorithm_t alg, + const mbedtls_rsa_context *rsa, + size_t hash_length) +{ + if (PSA_ALG_IS_RSA_PSS_ANY_SALT(alg)) { + return MBEDTLS_RSA_SALT_LEN_ANY; + } + /* Otherwise: standard salt length, i.e. largest possible salt length + * up to the hash length. */ + int klen = (int) mbedtls_rsa_get_len(rsa); // known to fit + int hlen = (int) hash_length; // known to fit + int room = klen - 2 - hlen; + if (room < 0) { + return 0; // there is no valid signature in this case anyway + } else if (room > hlen) { + return hlen; + } else { + return room; + } +} +#endif /* MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS */ + +psa_status_t mbedtls_psa_rsa_verify_hash( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *hash, size_t hash_length, + const uint8_t *signature, size_t signature_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + mbedtls_rsa_context *rsa = NULL; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_md_type_t md_alg; + + status = mbedtls_psa_rsa_load_representation(attributes->type, + key_buffer, + key_buffer_size, + &rsa); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = psa_rsa_decode_md_type(alg, hash_length, &md_alg); + if (status != PSA_SUCCESS) { + goto exit; + } + + if (signature_length != mbedtls_rsa_get_len(rsa)) { + status = PSA_ERROR_INVALID_SIGNATURE; + goto exit; + } + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) + if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg)) { + ret = mbedtls_rsa_set_padding(rsa, MBEDTLS_RSA_PKCS_V15, + MBEDTLS_MD_NONE); + if (ret == 0) { + ret = mbedtls_rsa_pkcs1_verify(rsa, + md_alg, + (unsigned int) hash_length, + hash, + signature); + } + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS) + if (PSA_ALG_IS_RSA_PSS(alg)) { + ret = mbedtls_rsa_set_padding(rsa, MBEDTLS_RSA_PKCS_V21, md_alg); + if (ret == 0) { + int slen = rsa_pss_expected_salt_len(alg, rsa, hash_length); + ret = mbedtls_rsa_rsassa_pss_verify_ext(rsa, + md_alg, + (unsigned) hash_length, + hash, + md_alg, + slen, + signature); + } + } else +#endif /* MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS */ + { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + + /* Mbed TLS distinguishes "invalid padding" from "valid padding but + * the rest of the signature is invalid". This has little use in + * practice and PSA doesn't report this distinction. */ + status = (ret == MBEDTLS_ERR_RSA_INVALID_PADDING) ? + PSA_ERROR_INVALID_SIGNATURE : + mbedtls_to_psa_error(ret); + +exit: + mbedtls_rsa_free(rsa); + mbedtls_free(rsa); + + return status; +} + +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS) */ + +/****************************************************************/ +/* Asymmetric cryptography */ +/****************************************************************/ + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) +static int psa_rsa_oaep_set_padding_mode(psa_algorithm_t alg, + mbedtls_rsa_context *rsa) +{ + psa_algorithm_t hash_alg = PSA_ALG_RSA_OAEP_GET_HASH(alg); + mbedtls_md_type_t md_alg = mbedtls_md_type_from_psa_alg(hash_alg); + + /* Just to get the error status right, as rsa_set_padding() doesn't + * distinguish between "bad RSA algorithm" and "unknown hash". */ + if (mbedtls_md_info_from_type(md_alg) == NULL) { + return PSA_ERROR_NOT_SUPPORTED; + } + + return mbedtls_rsa_set_padding(rsa, MBEDTLS_RSA_PKCS_V21, md_alg); +} +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) */ + +psa_status_t mbedtls_psa_asymmetric_encrypt(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *salt, + size_t salt_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + (void) key_buffer; + (void) key_buffer_size; + (void) input; + (void) input_length; + (void) salt; + (void) salt_length; + (void) output; + (void) output_size; + (void) output_length; + + if (PSA_KEY_TYPE_IS_RSA(attributes->type)) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) + mbedtls_rsa_context *rsa = NULL; + status = mbedtls_psa_rsa_load_representation(attributes->type, + key_buffer, + key_buffer_size, + &rsa); + if (status != PSA_SUCCESS) { + goto rsa_exit; + } + + if (output_size < mbedtls_rsa_get_len(rsa)) { + status = PSA_ERROR_BUFFER_TOO_SMALL; + goto rsa_exit; + } +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) */ + if (alg == PSA_ALG_RSA_PKCS1V15_CRYPT) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) + status = mbedtls_to_psa_error( + mbedtls_rsa_pkcs1_encrypt(rsa, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE, + input_length, + input, + output)); +#else + status = PSA_ERROR_NOT_SUPPORTED; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT */ + } else + if (PSA_ALG_IS_RSA_OAEP(alg)) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) + status = mbedtls_to_psa_error( + psa_rsa_oaep_set_padding_mode(alg, rsa)); + if (status != PSA_SUCCESS) { + goto rsa_exit; + } + + status = mbedtls_to_psa_error( + mbedtls_rsa_rsaes_oaep_encrypt(rsa, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE, + salt, salt_length, + input_length, + input, + output)); +#else + status = PSA_ERROR_NOT_SUPPORTED; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP */ + } else { + status = PSA_ERROR_INVALID_ARGUMENT; + } +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) +rsa_exit: + if (status == PSA_SUCCESS) { + *output_length = mbedtls_rsa_get_len(rsa); + } + + mbedtls_rsa_free(rsa); + mbedtls_free(rsa); +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) */ + } else { + status = PSA_ERROR_NOT_SUPPORTED; + } + + return status; +} + +psa_status_t mbedtls_psa_asymmetric_decrypt(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *salt, + size_t salt_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + (void) key_buffer; + (void) key_buffer_size; + (void) input; + (void) input_length; + (void) salt; + (void) salt_length; + (void) output; + (void) output_size; + (void) output_length; + + *output_length = 0; + + if (attributes->type == PSA_KEY_TYPE_RSA_KEY_PAIR) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) + mbedtls_rsa_context *rsa = NULL; + status = mbedtls_psa_rsa_load_representation(attributes->type, + key_buffer, + key_buffer_size, + &rsa); + if (status != PSA_SUCCESS) { + goto rsa_exit; + } + + if (input_length != mbedtls_rsa_get_len(rsa)) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto rsa_exit; + } +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) */ + + if (alg == PSA_ALG_RSA_PKCS1V15_CRYPT) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) + status = mbedtls_to_psa_error( + mbedtls_rsa_pkcs1_decrypt(rsa, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE, + output_length, + input, + output, + output_size)); +#else + status = PSA_ERROR_NOT_SUPPORTED; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT */ + } else + if (PSA_ALG_IS_RSA_OAEP(alg)) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) + status = mbedtls_to_psa_error( + psa_rsa_oaep_set_padding_mode(alg, rsa)); + if (status != PSA_SUCCESS) { + goto rsa_exit; + } + + status = mbedtls_to_psa_error( + mbedtls_rsa_rsaes_oaep_decrypt(rsa, + mbedtls_psa_get_random, + MBEDTLS_PSA_RANDOM_STATE, + salt, salt_length, + output_length, + input, + output, + output_size)); +#else + status = PSA_ERROR_NOT_SUPPORTED; +#endif /* MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP */ + } else { + status = PSA_ERROR_INVALID_ARGUMENT; + } + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) +rsa_exit: + mbedtls_rsa_free(rsa); + mbedtls_free(rsa); +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) || + * defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) */ + } else { + status = PSA_ERROR_NOT_SUPPORTED; + } + + return status; +} + +#endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_rsa.h b/tf-psa-crypto/drivers/builtin/src/psa_crypto_rsa.h new file mode 100644 index 0000000000..adc2d7343d --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_rsa.h @@ -0,0 +1,321 @@ +/* + * PSA RSA layer on top of Mbed TLS crypto + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_RSA_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_RSA_H + +#include +#include + +/** Load the contents of a key buffer into an internal RSA representation + * + * \param[in] type The type of key contained in \p data. + * \param[in] data The buffer from which to load the representation. + * \param[in] data_length The size in bytes of \p data. + * \param[out] p_rsa Returns a pointer to an RSA context on success. + * The caller is responsible for freeing both the + * contents of the context and the context itself + * when done. + */ +psa_status_t mbedtls_psa_rsa_load_representation(psa_key_type_t type, + const uint8_t *data, + size_t data_length, + mbedtls_rsa_context **p_rsa); + +/** Import an RSA key in binary format. + * + * \note The signature of this function is that of a PSA driver + * import_key entry point. This function behaves as an import_key + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \param[in] attributes The attributes for the key to import. + * \param[in] data The buffer containing the key data in import + * format. + * \param[in] data_length Size of the \p data buffer in bytes. + * \param[out] key_buffer The buffer containing the key data in output + * format. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. This + * size is greater or equal to \p data_length. + * \param[out] key_buffer_length The length of the data written in \p + * key_buffer in bytes. + * \param[out] bits The key size in number of bits. + * + * \retval #PSA_SUCCESS The RSA key was imported successfully. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The key data is not correctly formatted. + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_rsa_import_key( + const psa_key_attributes_t *attributes, + const uint8_t *data, size_t data_length, + uint8_t *key_buffer, size_t key_buffer_size, + size_t *key_buffer_length, size_t *bits); + +/** Export an RSA key to export representation + * + * \param[in] type The type of key (public/private) to export + * \param[in] rsa The internal RSA representation from which to export + * \param[out] data The buffer to export to + * \param[in] data_size The length of the buffer to export to + * \param[out] data_length The amount of bytes written to \p data + */ +psa_status_t mbedtls_psa_rsa_export_key(psa_key_type_t type, + mbedtls_rsa_context *rsa, + uint8_t *data, + size_t data_size, + size_t *data_length); + +/** Export a public RSA key or the public part of an RSA key pair in binary + * format. + * + * \note The signature of this function is that of a PSA driver + * export_public_key entry point. This function behaves as an + * export_public_key entry point as defined in the PSA driver interface + * specification. + * + * \param[in] attributes The attributes for the key to export. + * \param[in] key_buffer Material or context of the key to export. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[out] data Buffer where the key data is to be written. + * \param[in] data_size Size of the \p data buffer in bytes. + * \param[out] data_length On success, the number of bytes written in + * \p data. + * + * \retval #PSA_SUCCESS The RSA public key was exported successfully. + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription + * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + */ +psa_status_t mbedtls_psa_rsa_export_public_key( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + uint8_t *data, size_t data_size, size_t *data_length); + +/** + * \brief Generate an RSA key. + * + * \param[in] attributes The attributes for the RSA key to generate. + * \param[in] custom_data The public exponent to use. + * This can be a null pointer if + * \c params_data_length is 0. + * \param custom_data_length Length of \p custom_data in bytes. + * This can be 0, in which case the + * public exponent will be 65537. + * \param[out] key_buffer Buffer where the key data is to be written. + * \param[in] key_buffer_size Size of \p key_buffer in bytes. + * \param[out] key_buffer_length On success, the number of bytes written in + * \p key_buffer. + * + * \retval #PSA_SUCCESS + * The key was successfully generated. + * \retval #PSA_ERROR_NOT_SUPPORTED + * Key length or type not supported. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of \p key_buffer is too small. + */ +psa_status_t mbedtls_psa_rsa_generate_key( + const psa_key_attributes_t *attributes, + const uint8_t *custom_data, size_t custom_data_length, + uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length); + +/** Sign an already-calculated hash with an RSA private key. + * + * \note The signature of this function is that of a PSA driver + * sign_hash entry point. This function behaves as a sign_hash + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \param[in] attributes The attributes of the RSA key to use for the + * operation. + * \param[in] key_buffer The buffer containing the RSA key context. + * format. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] alg A signature algorithm that is compatible with + * an RSA key. + * \param[in] hash The hash or message to sign. + * \param[in] hash_length Size of the \p hash buffer in bytes. + * \param[out] signature Buffer where the signature is to be written. + * \param[in] signature_size Size of the \p signature buffer in bytes. + * \param[out] signature_length On success, the number of bytes + * that make up the returned signature value. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p signature buffer is too small. You can + * determine a sufficient buffer size by calling + * #PSA_SIGN_OUTPUT_SIZE(\c PSA_KEY_TYPE_RSA_KEY_PAIR, \c key_bits, + * \p alg) where \c key_bits is the bit-size of the RSA key. + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY \emptydescription + */ +psa_status_t mbedtls_psa_rsa_sign_hash( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *hash, size_t hash_length, + uint8_t *signature, size_t signature_size, size_t *signature_length); + +/** + * \brief Verify the signature a hash or short message using a public RSA key. + * + * \note The signature of this function is that of a PSA driver + * verify_hash entry point. This function behaves as a verify_hash + * entry point as defined in the PSA driver interface specification for + * transparent drivers. + * + * \param[in] attributes The attributes of the RSA key to use for the + * operation. + * \param[in] key_buffer The buffer containing the RSA key context. + * format. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] alg A signature algorithm that is compatible with + * an RSA key. + * \param[in] hash The hash or message whose signature is to be + * verified. + * \param[in] hash_length Size of the \p hash buffer in bytes. + * \param[in] signature Buffer containing the signature to verify. + * \param[in] signature_length Size of the \p signature buffer in bytes. + * + * \retval #PSA_SUCCESS + * The signature is valid. + * \retval #PSA_ERROR_INVALID_SIGNATURE + * The calculation was performed successfully, but the passed + * signature is not a valid signature. + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + */ +psa_status_t mbedtls_psa_rsa_verify_hash( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, size_t key_buffer_size, + psa_algorithm_t alg, const uint8_t *hash, size_t hash_length, + const uint8_t *signature, size_t signature_length); + +/** + * \brief Encrypt a short message with a public key. + * + * \param attributes The attributes for the key to import. + * \param key_buffer Buffer where the key data is to be written. + * \param key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param input_length Size of the \p input buffer in bytes. + * \param[in] salt A salt or label, if supported by the + * encryption algorithm. + * If the algorithm does not support a + * salt, pass \c NULL. + * If the algorithm supports an optional + * salt and you do not want to pass a salt, + * pass \c NULL. + * + * - For #PSA_ALG_RSA_PKCS1V15_CRYPT, no salt is + * supported. + * \param salt_length Size of the \p salt buffer in bytes. + * If \p salt is \c NULL, pass 0. + * \param[out] output Buffer where the encrypted message is to + * be written. + * \param output_size Size of the \p output buffer in bytes. + * \param[out] output_length On success, the number of bytes + * that make up the returned output. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p output buffer is too small. You can + * determine a sufficient buffer size by calling + * #PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(\c key_type, \c key_bits, \p alg) + * where \c key_type and \c key_bits are the type and bit-size + * respectively of \p key. + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription + * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY \emptydescription + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t mbedtls_psa_asymmetric_encrypt(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *salt, + size_t salt_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * \brief Decrypt a short message with a private key. + * + * \param attributes The attributes for the key to import. + * \param key_buffer Buffer where the key data is to be written. + * \param key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] input The message to decrypt. + * \param input_length Size of the \p input buffer in bytes. + * \param[in] salt A salt or label, if supported by the + * encryption algorithm. + * If the algorithm does not support a + * salt, pass \c NULL. + * If the algorithm supports an optional + * salt and you do not want to pass a salt, + * pass \c NULL. + * + * - For #PSA_ALG_RSA_PKCS1V15_CRYPT, no salt is + * supported. + * \param salt_length Size of the \p salt buffer in bytes. + * If \p salt is \c NULL, pass 0. + * \param[out] output Buffer where the decrypted message is to + * be written. + * \param output_size Size of the \c output buffer in bytes. + * \param[out] output_length On success, the number of bytes + * that make up the returned output. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p output buffer is too small. You can + * determine a sufficient buffer size by calling + * #PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(\c key_type, \c key_bits, \p alg) + * where \c key_type and \c key_bits are the type and bit-size + * respectively of \p key. + * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription + * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription + * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY \emptydescription + * \retval #PSA_ERROR_INVALID_PADDING \emptydescription + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t mbedtls_psa_asymmetric_decrypt(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *salt, + size_t salt_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_RSA_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_xof.c b/tf-psa-crypto/drivers/builtin/src/psa_crypto_xof.c new file mode 100644 index 0000000000..3e2367f94b --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_xof.c @@ -0,0 +1,149 @@ +/* + * PSA XOF (extendable-output function) layer on top of software crypto + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_PSA_CRYPTO_C) + +#include +#include "psa_crypto_xof.h" + +#if defined(MBEDTLS_PSA_BUILTIN_XOF) + +#include + +#include "mbedtls/private/sha3.h" + +psa_status_t mbedtls_psa_xof_abort( + mbedtls_psa_xof_operation_t *operation) +{ + switch (operation->alg) { + case 0: + /* The object has (apparently) been initialized but it is not + * in use. It's ok to call abort on such an object, and there's + * nothing to do. */ + break; + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHAKE128) + case PSA_ALG_SHAKE128: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHAKE256) + case PSA_ALG_SHAKE256: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SOME_SHAKE) + mbedtls_sha3_free(&operation->ctx.shake); + break; +#endif + + default: + return PSA_ERROR_BAD_STATE; + } + operation->alg = 0; + return PSA_SUCCESS; +} + +psa_status_t mbedtls_psa_xof_setup( + mbedtls_psa_xof_operation_t *operation, + psa_algorithm_t alg) +{ + /* A context must be freshly initialized before it can be set up. */ + if (operation->alg != 0) { + return PSA_ERROR_BAD_STATE; + } + + switch (alg) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHAKE128) + case PSA_ALG_SHAKE128: + mbedtls_sha3_starts(&operation->ctx.shake, MBEDTLS_SHA3_SHAKE128); + break; +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHAKE256) + case PSA_ALG_SHAKE256: + mbedtls_sha3_starts(&operation->ctx.shake, MBEDTLS_SHA3_SHAKE256); + break; +#endif + + default: + return PSA_ALG_IS_XOF(alg) ? + PSA_ERROR_NOT_SUPPORTED : + PSA_ERROR_INVALID_ARGUMENT; + } + + operation->alg = alg; + return PSA_SUCCESS; +} + +psa_status_t mbedtls_psa_xof_set_context( + mbedtls_psa_xof_operation_t *operation, + const uint8_t *context, size_t context_length) +{ + switch (operation->alg) { + case 0: + return PSA_ERROR_BAD_STATE; + + default: + (void) context; + (void) context_length; + return PSA_ERROR_INVALID_ARGUMENT; + } +} + +psa_status_t mbedtls_psa_xof_update( + mbedtls_psa_xof_operation_t *operation, + const uint8_t *input, size_t input_length) +{ + switch (operation->alg) { + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHAKE128) + case PSA_ALG_SHAKE128: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHAKE256) + case PSA_ALG_SHAKE256: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SOME_SHAKE) + mbedtls_sha3_update(&operation->ctx.shake, input, input_length); + return PSA_SUCCESS; +#endif + + default: + (void) input; + (void) input_length; + return PSA_ERROR_BAD_STATE; + } +} + +psa_status_t mbedtls_psa_xof_output( + mbedtls_psa_xof_operation_t *operation, + uint8_t *output, size_t output_size) +{ + /* TODO: fill output with something "safe" in case of error. + * What would be safe here? */ + + switch (operation->alg) { + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHAKE128) + case PSA_ALG_SHAKE128: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHAKE256) + case PSA_ALG_SHAKE256: +#endif +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SOME_SHAKE) + mbedtls_sha3_finish(&operation->ctx.shake, output, output_size); + return PSA_SUCCESS; +#endif + + default: + (void) output; + (void) output_size; + return PSA_ERROR_BAD_STATE; + } +} + +#endif /* MBEDTLS_PSA_BUILTIN_XOF */ + +#endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_xof.h b/tf-psa-crypto/drivers/builtin/src/psa_crypto_xof.h new file mode 100644 index 0000000000..0abf22d30e --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_xof.h @@ -0,0 +1,155 @@ +/* + * PSA XOF (extendable-output function) layer on top of software crypto + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_XOF_H +#define TF_PSA_CRYPTO_PSA_CRYPTO_XOF_H + +#include + +/** Set up a multipart XOF operation using built-in code. + * + * If an error occurs at any step after a call to mbedtls_psa_xof_setup(), the + * operation will need to be reset by a call to mbedtls_psa_xof_abort(). The + * core may call mbedtls_psa_xof_abort() at any time after the operation + * has been initialized. + * + * After a successful call to mbedtls_psa_xof_setup(), the core must + * eventually terminate the operation by calling mbedtls_psa_xof_abort(). + * + * \warning The core must call the functions as directed. Otherwise, the + * behavior is undefined, although the driver will try to limit + * the damage to potentially data leakage and memory leaks but + * avoid memory corruption as long as the operation structure has + * been initialited. + * + * \param[in,out] operation The operation object to set up. It must have + * been initialized to all-zero and not yet be in use. + * \param alg The XOF algorithm to compute (\c PSA_ALG_XXX value + * such that #PSA_ALG_IS_XOF(\p alg) is true). + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p alg is not supported + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be inactive). + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_xof_setup( + mbedtls_psa_xof_operation_t *operation, + psa_algorithm_t alg); + +/** Set the context in a multipart XOF operation. + * + * The core must call mbedtls_psa_xof_setup() before calling this function. + * The core must call this function as directed in the description of + * the XOF algorithm, generally before calling mbedtls_psa_xof_update(). + * The core must not call this function if the XOF algorithm does not use + * a context. + * + * If this function returns an error status, the operation enters an error + * state and must be aborted by calling mbedtls_psa_xof_abort(). + * + * \param[in,out] operation Active XOF operation. + * \param[in] context Buffer containing the message fragment to add. + * \param context_length Size of the \p input buffer in bytes. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be active). + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_xof_set_context( + mbedtls_psa_xof_operation_t *operation, + const uint8_t *context, size_t context_length); + +/** Add an input fragment to a multipart XOF operation. + * + * The core must call mbedtls_psa_xof_setup() before calling this function. + * The core must not call this function after calling + * mbedtls_psa_xof_output() on the operation. + * + * This function can be called multiple times successively, to pass + * input incrementally. + * + * If the XOF algorithm requires a context, the core must call + * mbedtls_psa_xof_set_context() before this function. If the XOF + * algorithm can use an optional context, the core must call + * mbedtls_psa_xof_set_context() before this function, if at all. + * + * If this function returns an error status, the operation enters an error + * state and must be aborted by calling mbedtls_psa_xof_abort(). + * + * \param[in,out] operation Active XOF operation. + * \param[in] input Buffer containing the message fragment to add. + * \param input_length Size of the \p input buffer in bytes. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be active). + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_xof_update( + mbedtls_psa_xof_operation_t *operation, + const uint8_t *input, size_t input_length); + +/** Obtain some output from a XOF operation. + * + * The core must call mbedtls_psa_xof_setup() before calling this function. + * + * This function calculates the incremental XOF output of the message formed + * by concatenating the inputs passed to preceding calls to + * mbedtls_psa_xof_update(). + * + * This function can be called multiple times successively, to obtain + * output incrementally. + * + * \param[in,out] operation Active xof operation. + * \param[out] output Buffer where the XOF output is to be written. + * \param output_size Size of the \p output buffer in bytes. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be active). + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_xof_output( + mbedtls_psa_xof_operation_t *operation, + uint8_t *output, size_t output_size); + +/** Abort an Mbed TLS xof operation. + * + * \note The signature of this function is that of a PSA driver xof_abort + * entry point. This function behaves as a xof_abort entry point as + * defined in the PSA driver interface specification for transparent + * drivers. + * + * Aborting an operation frees all associated resources except for the + * \p operation structure itself. Once aborted, the operation object + * can be reused for another operation by calling + * mbedtls_psa_xof_setup() again. + * + * You may call this function any time after the operation object has + * been initialized by one of the methods described in #psa_xof_operation_t. + * + * \param[in,out] operation Initialized XOF operation. + * + * \retval #PSA_SUCCESS \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + */ +psa_status_t mbedtls_psa_xof_abort( + mbedtls_psa_xof_operation_t *operation); + +#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_XOF_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_util_internal.c b/tf-psa-crypto/drivers/builtin/src/psa_util_internal.c new file mode 100644 index 0000000000..c88d4dadf8 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_util_internal.c @@ -0,0 +1,282 @@ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "tf_psa_crypto_common.h" + +/* This is needed for MBEDTLS_ERR_XXX macros */ +#include + +#include "psa_util_internal.h" + +#if defined(MBEDTLS_PSA_CRYPTO_CLIENT) + +#include + +#if defined(MBEDTLS_MD_LIGHT) +#include +#endif +#if defined(MBEDTLS_LMS_C) +#include +#endif +#if defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY) || \ + defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC) +#include +#endif +#if defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) +#include +#endif +#if defined(MBEDTLS_PK_C) +#include +#if defined(MBEDTLS_PK_HAVE_PRIVATE_HEADER) +#include +#endif /* MBEDTLS_PK_HAVE_PRIVATE_HEADER */ +#endif +#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA) +#include +#endif + +/* PSA_SUCCESS is kept at the top of each error table since + * it's the most common status when everything functions properly. */ +#if defined(MBEDTLS_MD_LIGHT) +const mbedtls_error_pair_t psa_to_md_errors[] = +{ + { PSA_SUCCESS, 0 }, + { PSA_ERROR_NOT_SUPPORTED, MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE }, + { PSA_ERROR_INVALID_ARGUMENT, MBEDTLS_ERR_MD_BAD_INPUT_DATA }, + { PSA_ERROR_INSUFFICIENT_MEMORY, MBEDTLS_ERR_MD_ALLOC_FAILED } +}; +#endif + +#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA) +const mbedtls_error_pair_t psa_to_cipher_errors[] = +{ + { PSA_SUCCESS, 0 }, + { PSA_ERROR_NOT_SUPPORTED, MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE }, + { PSA_ERROR_INVALID_ARGUMENT, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA }, + { PSA_ERROR_INSUFFICIENT_MEMORY, MBEDTLS_ERR_CIPHER_ALLOC_FAILED } +}; +#endif + +#if defined(MBEDTLS_LMS_C) +const mbedtls_error_pair_t psa_to_lms_errors[] = +{ + { PSA_SUCCESS, 0 }, + { PSA_ERROR_BUFFER_TOO_SMALL, MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL }, + { PSA_ERROR_INVALID_ARGUMENT, MBEDTLS_ERR_LMS_BAD_INPUT_DATA } +}; +#endif + +#if defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY) || \ + defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC) +const mbedtls_error_pair_t psa_to_pk_rsa_errors[] = +{ + { PSA_SUCCESS, 0 }, + { PSA_ERROR_NOT_PERMITTED, MBEDTLS_ERR_RSA_BAD_INPUT_DATA }, + { PSA_ERROR_INVALID_ARGUMENT, MBEDTLS_ERR_RSA_BAD_INPUT_DATA }, + { PSA_ERROR_INVALID_HANDLE, MBEDTLS_ERR_RSA_BAD_INPUT_DATA }, + { PSA_ERROR_BUFFER_TOO_SMALL, MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE }, + { PSA_ERROR_INSUFFICIENT_ENTROPY, MBEDTLS_ERR_RSA_RNG_FAILED }, + { PSA_ERROR_INVALID_SIGNATURE, MBEDTLS_ERR_RSA_VERIFY_FAILED }, + { PSA_ERROR_INVALID_PADDING, MBEDTLS_ERR_RSA_INVALID_PADDING } +}; +#endif + +#if defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) +const mbedtls_error_pair_t psa_to_pk_ecdsa_errors[] = +{ + { PSA_SUCCESS, 0 }, + { PSA_ERROR_NOT_PERMITTED, MBEDTLS_ERR_ECP_BAD_INPUT_DATA }, + { PSA_ERROR_INVALID_ARGUMENT, MBEDTLS_ERR_ECP_BAD_INPUT_DATA }, + { PSA_ERROR_INVALID_HANDLE, MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE }, + { PSA_ERROR_BUFFER_TOO_SMALL, MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL }, + { PSA_ERROR_INSUFFICIENT_ENTROPY, MBEDTLS_ERR_ECP_RANDOM_FAILED }, + { PSA_ERROR_INVALID_SIGNATURE, MBEDTLS_ERR_ECP_VERIFY_FAILED } +}; +#endif + +int psa_generic_status_to_mbedtls(psa_status_t status) +{ + switch (status) { + case PSA_SUCCESS: + return 0; + case PSA_ERROR_NOT_SUPPORTED: + return MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED; + case PSA_ERROR_CORRUPTION_DETECTED: + return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + case PSA_ERROR_COMMUNICATION_FAILURE: + case PSA_ERROR_HARDWARE_FAILURE: + return MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED; + case PSA_ERROR_NOT_PERMITTED: + default: + return MBEDTLS_ERR_ERROR_GENERIC_ERROR; + } +} + +int psa_status_to_mbedtls(psa_status_t status, + const mbedtls_error_pair_t *local_translations, + size_t local_errors_num, + int (*fallback_f)(psa_status_t)) +{ + for (size_t i = 0; i < local_errors_num; i++) { + if (status == local_translations[i].psa_status) { + return local_translations[i].mbedtls_error; + } + } + return fallback_f(status); +} + +#if defined(MBEDTLS_PK_C) +int psa_pk_status_to_mbedtls(psa_status_t status) +{ + switch (status) { + case PSA_ERROR_INVALID_HANDLE: + return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT; + case PSA_ERROR_BUFFER_TOO_SMALL: + return MBEDTLS_ERR_PK_BUFFER_TOO_SMALL; + case PSA_ERROR_NOT_SUPPORTED: + return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE; + case PSA_ERROR_INVALID_ARGUMENT: + return MBEDTLS_ERR_PK_INVALID_ALG; + case PSA_ERROR_NOT_PERMITTED: + return MBEDTLS_ERR_PK_TYPE_MISMATCH; + case PSA_ERROR_INSUFFICIENT_MEMORY: + return MBEDTLS_ERR_PK_ALLOC_FAILED; + case PSA_ERROR_BAD_STATE: + return MBEDTLS_ERR_PK_BAD_INPUT_DATA; + case PSA_ERROR_DATA_CORRUPT: + case PSA_ERROR_DATA_INVALID: + case PSA_ERROR_STORAGE_FAILURE: + return MBEDTLS_ERR_PK_FILE_IO_ERROR; + default: + return psa_generic_status_to_mbedtls(status); + } +} +#endif /* MBEDTLS_PK_C */ + +/****************************************************************/ +/* Key management */ +/****************************************************************/ + +#if defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) +psa_ecc_family_t mbedtls_ecc_group_to_psa(mbedtls_ecp_group_id grpid, + size_t *bits) +{ + switch (grpid) { +#if defined(PSA_WANT_ECC_SECP_R1_256) + case MBEDTLS_ECP_DP_SECP256R1: + *bits = 256; + return PSA_ECC_FAMILY_SECP_R1; +#endif +#if defined(PSA_WANT_ECC_SECP_R1_384) + case MBEDTLS_ECP_DP_SECP384R1: + *bits = 384; + return PSA_ECC_FAMILY_SECP_R1; +#endif +#if defined(PSA_WANT_ECC_SECP_R1_521) + case MBEDTLS_ECP_DP_SECP521R1: + *bits = 521; + return PSA_ECC_FAMILY_SECP_R1; +#endif +#if defined(PSA_WANT_ECC_BRAINPOOL_P_R1_256) + case MBEDTLS_ECP_DP_BP256R1: + *bits = 256; + return PSA_ECC_FAMILY_BRAINPOOL_P_R1; +#endif +#if defined(PSA_WANT_ECC_BRAINPOOL_P_R1_384) + case MBEDTLS_ECP_DP_BP384R1: + *bits = 384; + return PSA_ECC_FAMILY_BRAINPOOL_P_R1; +#endif +#if defined(PSA_WANT_ECC_BRAINPOOL_P_R1_512) + case MBEDTLS_ECP_DP_BP512R1: + *bits = 512; + return PSA_ECC_FAMILY_BRAINPOOL_P_R1; +#endif +#if defined(PSA_WANT_ECC_MONTGOMERY_255) + case MBEDTLS_ECP_DP_CURVE25519: + *bits = 255; + return PSA_ECC_FAMILY_MONTGOMERY; +#endif +#if defined(PSA_WANT_ECC_SECP_K1_256) + case MBEDTLS_ECP_DP_SECP256K1: + *bits = 256; + return PSA_ECC_FAMILY_SECP_K1; +#endif +#if defined(PSA_WANT_ECC_MONTGOMERY_448) + case MBEDTLS_ECP_DP_CURVE448: + *bits = 448; + return PSA_ECC_FAMILY_MONTGOMERY; +#endif + default: + *bits = 0; + return 0; + } +} + +mbedtls_ecp_group_id mbedtls_ecc_group_from_psa(psa_ecc_family_t family, + size_t bits) +{ + switch (family) { + case PSA_ECC_FAMILY_SECP_R1: + switch (bits) { +#if defined(PSA_WANT_ECC_SECP_R1_256) + case 256: + return MBEDTLS_ECP_DP_SECP256R1; +#endif +#if defined(PSA_WANT_ECC_SECP_R1_384) + case 384: + return MBEDTLS_ECP_DP_SECP384R1; +#endif +#if defined(PSA_WANT_ECC_SECP_R1_521) + case 521: + return MBEDTLS_ECP_DP_SECP521R1; +#endif + } + break; + + case PSA_ECC_FAMILY_BRAINPOOL_P_R1: + switch (bits) { +#if defined(PSA_WANT_ECC_BRAINPOOL_P_R1_256) + case 256: + return MBEDTLS_ECP_DP_BP256R1; +#endif +#if defined(PSA_WANT_ECC_BRAINPOOL_P_R1_384) + case 384: + return MBEDTLS_ECP_DP_BP384R1; +#endif +#if defined(PSA_WANT_ECC_BRAINPOOL_P_R1_512) + case 512: + return MBEDTLS_ECP_DP_BP512R1; +#endif + } + break; + + case PSA_ECC_FAMILY_MONTGOMERY: + switch (bits) { +#if defined(PSA_WANT_ECC_MONTGOMERY_255) + case 255: + return MBEDTLS_ECP_DP_CURVE25519; +#endif +#if defined(PSA_WANT_ECC_MONTGOMERY_448) + case 448: + return MBEDTLS_ECP_DP_CURVE448; +#endif + } + break; + + case PSA_ECC_FAMILY_SECP_K1: + switch (bits) { +#if defined(PSA_WANT_ECC_SECP_K1_256) + case 256: + return MBEDTLS_ECP_DP_SECP256K1; +#endif + } + break; + } + + return MBEDTLS_ECP_DP_NONE; +} +#endif /* PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY */ +#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */ diff --git a/tf-psa-crypto/drivers/builtin/src/psa_util_internal.h b/tf-psa-crypto/drivers/builtin/src/psa_util_internal.h new file mode 100644 index 0000000000..95bdfc30be --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/psa_util_internal.h @@ -0,0 +1,132 @@ +/** + * \file psa_util_internal.h + * + * \brief Internal utility functions for use of PSA Crypto. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PSA_UTIL_INTERNAL_H +#define TF_PSA_CRYPTO_PSA_UTIL_INTERNAL_H + +/* Include the public header so that users only need one include. */ +#include "mbedtls/psa_util.h" + +#include "psa/crypto.h" + +#if defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) + +#include "mbedtls/private/ecp.h" + +#endif /* PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY */ + +#if defined(MBEDTLS_PSA_CRYPTO_CLIENT) + +/************************************************************************* + * FFDH + ************************************************************************/ + +#define MBEDTLS_PSA_MAX_FFDH_PUBKEY_LENGTH \ + PSA_KEY_EXPORT_FFDH_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_FFDH_MAX_KEY_BITS) + +/************************************************************************* + * ECC + ************************************************************************/ + +#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH \ + PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS) + +#define MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH \ + PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS) + +/************************************************************************* + * Error translation + ************************************************************************/ + +typedef struct { + /* Error codes used by PSA crypto are in -255..-128, fitting in 16 bits. */ + int16_t psa_status; + /* Error codes used by Mbed TLS are in one of the ranges + * -127..-1 (low-level) or -32767..-4096 (high-level with a low-level + * code optionally added), fitting in 16 bits. */ + int16_t mbedtls_error; +} mbedtls_error_pair_t; + +#if defined(MBEDTLS_MD_LIGHT) +extern const mbedtls_error_pair_t psa_to_md_errors[4]; +#endif + +#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA) +extern const mbedtls_error_pair_t psa_to_cipher_errors[4]; +#endif + +#if defined(MBEDTLS_LMS_C) +extern const mbedtls_error_pair_t psa_to_lms_errors[3]; +#endif + +#if defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY) || \ + defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC) +extern const mbedtls_error_pair_t psa_to_pk_rsa_errors[8]; +#endif + +#if defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) +extern const mbedtls_error_pair_t psa_to_pk_ecdsa_errors[7]; +#endif + +/* Generic fallback function for error translation, + * when the received state was not module-specific. */ +int psa_generic_status_to_mbedtls(psa_status_t status); + +/* This function iterates over provided local error translations, + * and if no match was found - calls the fallback error translation function. */ +int psa_status_to_mbedtls(psa_status_t status, + const mbedtls_error_pair_t *local_translations, + size_t local_errors_num, + int (*fallback_f)(psa_status_t)); + +/* The second out of three-stage error handling functions of the pk module, + * acts as a fallback after RSA / ECDSA error translation, and if no match + * is found, it itself calls psa_generic_status_to_mbedtls. */ +int psa_pk_status_to_mbedtls(psa_status_t status); + +/* Utility macro to shorten the defines of error translator in modules. */ +#define PSA_TO_MBEDTLS_ERR_LIST(status, error_list, fallback_f) \ + psa_status_to_mbedtls(status, error_list, \ + sizeof(error_list)/sizeof(error_list[0]), \ + fallback_f) + +#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */ +#if defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) +/** Convert an ECC curve identifier from the Mbed TLS encoding to PSA. + * + * \param grpid An Mbed TLS elliptic curve identifier + * (`MBEDTLS_ECP_DP_xxx`). + * \param[out] bits On success the bit size of the curve; 0 on failure. + * + * \return If the curve is supported in the PSA API, this function + * returns the proper PSA curve identifier + * (`PSA_ECC_FAMILY_xxx`). This holds even if the curve is + * not supported by the ECP module. + * \return \c 0 if the curve is not supported in the PSA API. + */ +psa_ecc_family_t mbedtls_ecc_group_to_psa(mbedtls_ecp_group_id grpid, + size_t *bits); + +/** Convert an ECC curve identifier from the PSA encoding to Mbed TLS. + * + * \param family A PSA elliptic curve family identifier + * (`PSA_ECC_FAMILY_xxx`). + * \param bits The bit-length of a private key on \p curve. + * + * \return If the curve is supported in the PSA API, this function + * returns the corresponding Mbed TLS elliptic curve + * identifier (`MBEDTLS_ECP_DP_xxx`). + * \return #MBEDTLS_ECP_DP_NONE if the combination of \c curve + * and \p bits is not supported. + */ +mbedtls_ecp_group_id mbedtls_ecc_group_from_psa(psa_ecc_family_t family, + size_t bits); +#endif /* PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY */ +#endif /* TF_PSA_CRYPTO_PSA_UTIL_INTERNAL_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/ripemd160.c b/tf-psa-crypto/drivers/builtin/src/ripemd160.c new file mode 100644 index 0000000000..b63e0859a5 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/ripemd160.c @@ -0,0 +1,482 @@ +/* + * RIPE MD-160 implementation + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +/* + * The RIPEMD-160 algorithm was designed by RIPE in 1996 + * http://homes.esat.kuleuven.be/~bosselae/mbedtls_ripemd160.html + * http://ehash.iaik.tugraz.at/wiki/RIPEMD-160 + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_RIPEMD160_C) + +#include "mbedtls/private/ripemd160.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#include + +#include "mbedtls/platform.h" + +void mbedtls_ripemd160_init(mbedtls_ripemd160_context *ctx) +{ + memset(ctx, 0, sizeof(mbedtls_ripemd160_context)); +} + +void mbedtls_ripemd160_free(mbedtls_ripemd160_context *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ripemd160_context)); +} + +void mbedtls_ripemd160_clone(mbedtls_ripemd160_context *dst, + const mbedtls_ripemd160_context *src) +{ + *dst = *src; +} + +/* + * RIPEMD-160 context setup + */ +int mbedtls_ripemd160_starts(mbedtls_ripemd160_context *ctx) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; + + return 0; +} +/* + * Process one block + */ +static int mbedtls_internal_ripemd160_process(mbedtls_ripemd160_context *ctx, + const unsigned char data[64]) +{ + struct { + uint32_t A, B, C, D, E, Ap, Bp, Cp, Dp, Ep, X[16]; + } local; + + local.X[0] = MBEDTLS_GET_UINT32_LE(data, 0); + local.X[1] = MBEDTLS_GET_UINT32_LE(data, 4); + local.X[2] = MBEDTLS_GET_UINT32_LE(data, 8); + local.X[3] = MBEDTLS_GET_UINT32_LE(data, 12); + local.X[4] = MBEDTLS_GET_UINT32_LE(data, 16); + local.X[5] = MBEDTLS_GET_UINT32_LE(data, 20); + local.X[6] = MBEDTLS_GET_UINT32_LE(data, 24); + local.X[7] = MBEDTLS_GET_UINT32_LE(data, 28); + local.X[8] = MBEDTLS_GET_UINT32_LE(data, 32); + local.X[9] = MBEDTLS_GET_UINT32_LE(data, 36); + local.X[10] = MBEDTLS_GET_UINT32_LE(data, 40); + local.X[11] = MBEDTLS_GET_UINT32_LE(data, 44); + local.X[12] = MBEDTLS_GET_UINT32_LE(data, 48); + local.X[13] = MBEDTLS_GET_UINT32_LE(data, 52); + local.X[14] = MBEDTLS_GET_UINT32_LE(data, 56); + local.X[15] = MBEDTLS_GET_UINT32_LE(data, 60); + + local.A = local.Ap = ctx->state[0]; + local.B = local.Bp = ctx->state[1]; + local.C = local.Cp = ctx->state[2]; + local.D = local.Dp = ctx->state[3]; + local.E = local.Ep = ctx->state[4]; + +#define F1(x, y, z) ((x) ^ (y) ^ (z)) +#define F2(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define F3(x, y, z) (((x) | ~(y)) ^ (z)) +#define F4(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define F5(x, y, z) ((x) ^ ((y) | ~(z))) + +#define S(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +#define P(a, b, c, d, e, r, s, f, k) \ + do \ + { \ + (a) += f((b), (c), (d)) + local.X[r] + (k); \ + (a) = S((a), (s)) + (e); \ + (c) = S((c), 10); \ + } while (0) + +#define P2(a, b, c, d, e, r, s, rp, sp) \ + do \ + { \ + P((a), (b), (c), (d), (e), (r), (s), F, K); \ + P(a ## p, b ## p, c ## p, d ## p, e ## p, \ + (rp), (sp), Fp, Kp); \ + } while (0) + +#define F F1 +#define K 0x00000000 +#define Fp F5 +#define Kp 0x50A28BE6 + P2(local.A, local.B, local.C, local.D, local.E, 0, 11, 5, 8); + P2(local.E, local.A, local.B, local.C, local.D, 1, 14, 14, 9); + P2(local.D, local.E, local.A, local.B, local.C, 2, 15, 7, 9); + P2(local.C, local.D, local.E, local.A, local.B, 3, 12, 0, 11); + P2(local.B, local.C, local.D, local.E, local.A, 4, 5, 9, 13); + P2(local.A, local.B, local.C, local.D, local.E, 5, 8, 2, 15); + P2(local.E, local.A, local.B, local.C, local.D, 6, 7, 11, 15); + P2(local.D, local.E, local.A, local.B, local.C, 7, 9, 4, 5); + P2(local.C, local.D, local.E, local.A, local.B, 8, 11, 13, 7); + P2(local.B, local.C, local.D, local.E, local.A, 9, 13, 6, 7); + P2(local.A, local.B, local.C, local.D, local.E, 10, 14, 15, 8); + P2(local.E, local.A, local.B, local.C, local.D, 11, 15, 8, 11); + P2(local.D, local.E, local.A, local.B, local.C, 12, 6, 1, 14); + P2(local.C, local.D, local.E, local.A, local.B, 13, 7, 10, 14); + P2(local.B, local.C, local.D, local.E, local.A, 14, 9, 3, 12); + P2(local.A, local.B, local.C, local.D, local.E, 15, 8, 12, 6); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F2 +#define K 0x5A827999 +#define Fp F4 +#define Kp 0x5C4DD124 + P2(local.E, local.A, local.B, local.C, local.D, 7, 7, 6, 9); + P2(local.D, local.E, local.A, local.B, local.C, 4, 6, 11, 13); + P2(local.C, local.D, local.E, local.A, local.B, 13, 8, 3, 15); + P2(local.B, local.C, local.D, local.E, local.A, 1, 13, 7, 7); + P2(local.A, local.B, local.C, local.D, local.E, 10, 11, 0, 12); + P2(local.E, local.A, local.B, local.C, local.D, 6, 9, 13, 8); + P2(local.D, local.E, local.A, local.B, local.C, 15, 7, 5, 9); + P2(local.C, local.D, local.E, local.A, local.B, 3, 15, 10, 11); + P2(local.B, local.C, local.D, local.E, local.A, 12, 7, 14, 7); + P2(local.A, local.B, local.C, local.D, local.E, 0, 12, 15, 7); + P2(local.E, local.A, local.B, local.C, local.D, 9, 15, 8, 12); + P2(local.D, local.E, local.A, local.B, local.C, 5, 9, 12, 7); + P2(local.C, local.D, local.E, local.A, local.B, 2, 11, 4, 6); + P2(local.B, local.C, local.D, local.E, local.A, 14, 7, 9, 15); + P2(local.A, local.B, local.C, local.D, local.E, 11, 13, 1, 13); + P2(local.E, local.A, local.B, local.C, local.D, 8, 12, 2, 11); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F3 +#define K 0x6ED9EBA1 +#define Fp F3 +#define Kp 0x6D703EF3 + P2(local.D, local.E, local.A, local.B, local.C, 3, 11, 15, 9); + P2(local.C, local.D, local.E, local.A, local.B, 10, 13, 5, 7); + P2(local.B, local.C, local.D, local.E, local.A, 14, 6, 1, 15); + P2(local.A, local.B, local.C, local.D, local.E, 4, 7, 3, 11); + P2(local.E, local.A, local.B, local.C, local.D, 9, 14, 7, 8); + P2(local.D, local.E, local.A, local.B, local.C, 15, 9, 14, 6); + P2(local.C, local.D, local.E, local.A, local.B, 8, 13, 6, 6); + P2(local.B, local.C, local.D, local.E, local.A, 1, 15, 9, 14); + P2(local.A, local.B, local.C, local.D, local.E, 2, 14, 11, 12); + P2(local.E, local.A, local.B, local.C, local.D, 7, 8, 8, 13); + P2(local.D, local.E, local.A, local.B, local.C, 0, 13, 12, 5); + P2(local.C, local.D, local.E, local.A, local.B, 6, 6, 2, 14); + P2(local.B, local.C, local.D, local.E, local.A, 13, 5, 10, 13); + P2(local.A, local.B, local.C, local.D, local.E, 11, 12, 0, 13); + P2(local.E, local.A, local.B, local.C, local.D, 5, 7, 4, 7); + P2(local.D, local.E, local.A, local.B, local.C, 12, 5, 13, 5); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F4 +#define K 0x8F1BBCDC +#define Fp F2 +#define Kp 0x7A6D76E9 + P2(local.C, local.D, local.E, local.A, local.B, 1, 11, 8, 15); + P2(local.B, local.C, local.D, local.E, local.A, 9, 12, 6, 5); + P2(local.A, local.B, local.C, local.D, local.E, 11, 14, 4, 8); + P2(local.E, local.A, local.B, local.C, local.D, 10, 15, 1, 11); + P2(local.D, local.E, local.A, local.B, local.C, 0, 14, 3, 14); + P2(local.C, local.D, local.E, local.A, local.B, 8, 15, 11, 14); + P2(local.B, local.C, local.D, local.E, local.A, 12, 9, 15, 6); + P2(local.A, local.B, local.C, local.D, local.E, 4, 8, 0, 14); + P2(local.E, local.A, local.B, local.C, local.D, 13, 9, 5, 6); + P2(local.D, local.E, local.A, local.B, local.C, 3, 14, 12, 9); + P2(local.C, local.D, local.E, local.A, local.B, 7, 5, 2, 12); + P2(local.B, local.C, local.D, local.E, local.A, 15, 6, 13, 9); + P2(local.A, local.B, local.C, local.D, local.E, 14, 8, 9, 12); + P2(local.E, local.A, local.B, local.C, local.D, 5, 6, 7, 5); + P2(local.D, local.E, local.A, local.B, local.C, 6, 5, 10, 15); + P2(local.C, local.D, local.E, local.A, local.B, 2, 12, 14, 8); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F5 +#define K 0xA953FD4E +#define Fp F1 +#define Kp 0x00000000 + P2(local.B, local.C, local.D, local.E, local.A, 4, 9, 12, 8); + P2(local.A, local.B, local.C, local.D, local.E, 0, 15, 15, 5); + P2(local.E, local.A, local.B, local.C, local.D, 5, 5, 10, 12); + P2(local.D, local.E, local.A, local.B, local.C, 9, 11, 4, 9); + P2(local.C, local.D, local.E, local.A, local.B, 7, 6, 1, 12); + P2(local.B, local.C, local.D, local.E, local.A, 12, 8, 5, 5); + P2(local.A, local.B, local.C, local.D, local.E, 2, 13, 8, 14); + P2(local.E, local.A, local.B, local.C, local.D, 10, 12, 7, 6); + P2(local.D, local.E, local.A, local.B, local.C, 14, 5, 6, 8); + P2(local.C, local.D, local.E, local.A, local.B, 1, 12, 2, 13); + P2(local.B, local.C, local.D, local.E, local.A, 3, 13, 13, 6); + P2(local.A, local.B, local.C, local.D, local.E, 8, 14, 14, 5); + P2(local.E, local.A, local.B, local.C, local.D, 11, 11, 0, 15); + P2(local.D, local.E, local.A, local.B, local.C, 6, 8, 3, 13); + P2(local.C, local.D, local.E, local.A, local.B, 15, 5, 9, 11); + P2(local.B, local.C, local.D, local.E, local.A, 13, 6, 11, 11); +#undef F +#undef K +#undef Fp +#undef Kp + + local.C = ctx->state[1] + local.C + local.Dp; + ctx->state[1] = ctx->state[2] + local.D + local.Ep; + ctx->state[2] = ctx->state[3] + local.E + local.Ap; + ctx->state[3] = ctx->state[4] + local.A + local.Bp; + ctx->state[4] = ctx->state[0] + local.B + local.Cp; + ctx->state[0] = local.C; + + /* Zeroise variables to clear sensitive data from memory. */ + mbedtls_platform_zeroize(&local, sizeof(local)); + + return 0; +} + +/* + * RIPEMD-160 process buffer + */ +int mbedtls_ripemd160_update(mbedtls_ripemd160_context *ctx, + const unsigned char *input, + size_t ilen) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t fill; + uint32_t left; + + if (ilen == 0) { + return 0; + } + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if (ctx->total[0] < (uint32_t) ilen) { + ctx->total[1]++; + } + + if (left && ilen >= fill) { + memcpy((void *) (ctx->buffer + left), input, fill); + + if ((ret = mbedtls_internal_ripemd160_process(ctx, ctx->buffer)) != 0) { + return ret; + } + + input += fill; + ilen -= fill; + left = 0; + } + + while (ilen >= 64) { + if ((ret = mbedtls_internal_ripemd160_process(ctx, input)) != 0) { + return ret; + } + + input += 64; + ilen -= 64; + } + + if (ilen > 0) { + memcpy((void *) (ctx->buffer + left), input, ilen); + } + + return 0; +} + +static const unsigned char ripemd160_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * RIPEMD-160 final digest + */ +int mbedtls_ripemd160_finish(mbedtls_ripemd160_context *ctx, + unsigned char output[20]) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = (ctx->total[0] >> 29) + | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + MBEDTLS_PUT_UINT32_LE(low, msglen, 0); + MBEDTLS_PUT_UINT32_LE(high, msglen, 4); + + last = ctx->total[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + ret = mbedtls_ripemd160_update(ctx, ripemd160_padding, padn); + if (ret != 0) { + goto exit; + } + + ret = mbedtls_ripemd160_update(ctx, msglen, 8); + if (ret != 0) { + goto exit; + } + + MBEDTLS_PUT_UINT32_LE(ctx->state[0], output, 0); + MBEDTLS_PUT_UINT32_LE(ctx->state[1], output, 4); + MBEDTLS_PUT_UINT32_LE(ctx->state[2], output, 8); + MBEDTLS_PUT_UINT32_LE(ctx->state[3], output, 12); + MBEDTLS_PUT_UINT32_LE(ctx->state[4], output, 16); + + ret = 0; + +exit: + mbedtls_ripemd160_free(ctx); + return ret; +} + +/* + * output = RIPEMD-160( input buffer ) + */ +int mbedtls_ripemd160(const unsigned char *input, + size_t ilen, + unsigned char output[20]) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_ripemd160_context ctx; + + mbedtls_ripemd160_init(&ctx); + + if ((ret = mbedtls_ripemd160_starts(&ctx)) != 0) { + goto exit; + } + + if ((ret = mbedtls_ripemd160_update(&ctx, input, ilen)) != 0) { + goto exit; + } + + if ((ret = mbedtls_ripemd160_finish(&ctx, output)) != 0) { + goto exit; + } + +exit: + mbedtls_ripemd160_free(&ctx); + + return ret; +} + +#if defined(MBEDTLS_SELF_TEST) +/* + * Test vectors from the RIPEMD-160 paper and + * http://homes.esat.kuleuven.be/~bosselae/mbedtls_ripemd160.html#HMAC + */ +#define TESTS 8 +static const unsigned char ripemd160_test_str[TESTS][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012345678901234567890" }, +}; + +static const size_t ripemd160_test_strlen[TESTS] = +{ + 0, 1, 3, 14, 26, 56, 62, 80 +}; + +static const unsigned char ripemd160_test_md[TESTS][20] = +{ + { 0x9c, 0x11, 0x85, 0xa5, 0xc5, 0xe9, 0xfc, 0x54, 0x61, 0x28, + 0x08, 0x97, 0x7e, 0xe8, 0xf5, 0x48, 0xb2, 0x25, 0x8d, 0x31 }, + { 0x0b, 0xdc, 0x9d, 0x2d, 0x25, 0x6b, 0x3e, 0xe9, 0xda, 0xae, + 0x34, 0x7b, 0xe6, 0xf4, 0xdc, 0x83, 0x5a, 0x46, 0x7f, 0xfe }, + { 0x8e, 0xb2, 0x08, 0xf7, 0xe0, 0x5d, 0x98, 0x7a, 0x9b, 0x04, + 0x4a, 0x8e, 0x98, 0xc6, 0xb0, 0x87, 0xf1, 0x5a, 0x0b, 0xfc }, + { 0x5d, 0x06, 0x89, 0xef, 0x49, 0xd2, 0xfa, 0xe5, 0x72, 0xb8, + 0x81, 0xb1, 0x23, 0xa8, 0x5f, 0xfa, 0x21, 0x59, 0x5f, 0x36 }, + { 0xf7, 0x1c, 0x27, 0x10, 0x9c, 0x69, 0x2c, 0x1b, 0x56, 0xbb, + 0xdc, 0xeb, 0x5b, 0x9d, 0x28, 0x65, 0xb3, 0x70, 0x8d, 0xbc }, + { 0x12, 0xa0, 0x53, 0x38, 0x4a, 0x9c, 0x0c, 0x88, 0xe4, 0x05, + 0xa0, 0x6c, 0x27, 0xdc, 0xf4, 0x9a, 0xda, 0x62, 0xeb, 0x2b }, + { 0xb0, 0xe2, 0x0b, 0x6e, 0x31, 0x16, 0x64, 0x02, 0x86, 0xed, + 0x3a, 0x87, 0xa5, 0x71, 0x30, 0x79, 0xb2, 0x1f, 0x51, 0x89 }, + { 0x9b, 0x75, 0x2e, 0x45, 0x57, 0x3d, 0x4b, 0x39, 0xf4, 0xdb, + 0xd3, 0x32, 0x3c, 0xab, 0x82, 0xbf, 0x63, 0x32, 0x6b, 0xfb }, +}; + +/* + * Checkup routine + */ +int mbedtls_ripemd160_self_test(int verbose) +{ + int i, ret = 0; + unsigned char output[20]; + + memset(output, 0, sizeof(output)); + + for (i = 0; i < TESTS; i++) { + if (verbose != 0) { + mbedtls_printf(" RIPEMD-160 test #%d: ", i + 1); + } + + ret = mbedtls_ripemd160(ripemd160_test_str[i], + ripemd160_test_strlen[i], output); + if (ret != 0) { + goto fail; + } + + if (memcmp(output, ripemd160_test_md[i], 20) != 0) { + ret = 1; + goto fail; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + return 0; + +fail: + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + return ret; +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_RIPEMD160_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/rsa.c b/tf-psa-crypto/drivers/builtin/src/rsa.c new file mode 100644 index 0000000000..914e7a3248 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/rsa.c @@ -0,0 +1,2716 @@ +/* + * The RSA public-key cryptosystem + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +/* + * The following sources were referenced in the design of this implementation + * of the RSA algorithm: + * + * [1] A method for obtaining digital signatures and public-key cryptosystems + * R Rivest, A Shamir, and L Adleman + * http://people.csail.mit.edu/rivest/pubs.html#RSA78 + * + * [2] Handbook of Applied Cryptography - 1997, Chapter 8 + * Menezes, van Oorschot and Vanstone + * + * [3] Malware Guard Extension: Using SGX to Conceal Cache Attacks + * Michael Schwarz, Samuel Weiser, Daniel Gruss, Clémentine Maurice and + * Stefan Mangard + * https://arxiv.org/abs/1702.08719v2 + * + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_RSA_C) + +#include "mbedtls/private/rsa.h" +#include "bignum_core.h" +#include "bignum_internal.h" +#include "rsa_alt_helpers.h" +#include "rsa_internal.h" +#include "crypto_oid.h" +#include "mbedtls/asn1write.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" +#include "constant_time_internal.h" +#include "mbedtls/constant_time.h" +#include "md_psa.h" + +#include + +#if defined(MBEDTLS_PKCS1_V15) && !defined(__OpenBSD__) && !defined(__NetBSD__) +#include +#endif + +#include "mbedtls/platform.h" + +/* + * Wrapper around mbedtls_asn1_get_mpi() that rejects zero. + * + * The value zero is never a valid value for an RSA parameter. + */ +static int asn1_get_nonzero_mpi(unsigned char **p, + const unsigned char *end, + mbedtls_mpi *X) +{ + int ret; + + ret = mbedtls_asn1_get_mpi(p, end, X); + if (ret != 0) { + return ret; + } + + if (mbedtls_mpi_cmp_int(X, 0) == 0) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + return 0; +} + +int mbedtls_rsa_parse_key(mbedtls_rsa_context *rsa, const unsigned char *key, size_t keylen) +{ + int ret, version; + size_t len, bits; + unsigned char *p, *end; + +#if defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi T; + mbedtls_mpi_init(&T); +#endif /* !MBEDTLS_RSA_NO_CRT */ + + p = (unsigned char *) key; + end = p + keylen; + + /* + * This function parses the RSAPrivateKey (PKCS#1) + * + * RSAPrivateKey ::= SEQUENCE { + * version Version, + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER, -- (inverse of q) mod p + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + */ + if ((ret = mbedtls_asn1_get_tag(&p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { + return ret; + } + + if (end != p + len) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + if ((ret = mbedtls_asn1_get_int(&p, end, &version)) != 0) { + return ret; + } + + if (version != 0) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + /* Import N */ + if ((ret = asn1_get_nonzero_mpi(&p, end, &rsa->N)) != 0) { + goto cleanup; + } + + rsa->len = mbedtls_mpi_size(&rsa->N); + + /* Import E */ + if ((ret = asn1_get_nonzero_mpi(&p, end, &rsa->E)) != 0) { + goto cleanup; + } + + /* Import D */ + if ((ret = asn1_get_nonzero_mpi(&p, end, &rsa->D)) != 0) { + goto cleanup; + } + + /* Import P */ + if ((ret = asn1_get_nonzero_mpi(&p, end, &rsa->P)) != 0) { + goto cleanup; + } + + /* Import Q */ + if ((ret = asn1_get_nonzero_mpi(&p, end, &rsa->Q)) != 0) { + goto cleanup; + } + +#if !defined(MBEDTLS_RSA_NO_CRT) + /* + * The RSA CRT parameters DP, DQ and QP are nominally redundant, in + * that they can be easily recomputed from D, P and Q. However by + * parsing them from the PKCS1 structure it is possible to avoid + * recalculating them which both reduces the overhead of loading + * RSA private keys into memory and also avoids side channels which + * can arise when computing those values, since all of D, P, and Q + * are secret. See https://eprint.iacr.org/2020/055 for a + * description of one such attack. + */ + + /* Import DP */ + if ((ret = asn1_get_nonzero_mpi(&p, end, &rsa->DP)) != 0) { + goto cleanup; + } + + /* Import DQ */ + if ((ret = asn1_get_nonzero_mpi(&p, end, &rsa->DQ)) != 0) { + goto cleanup; + } + + /* Import QP */ + if ((ret = asn1_get_nonzero_mpi(&p, end, &rsa->QP)) != 0) { + goto cleanup; + } + +#else + /* Verify existence of the CRT params */ + if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 || + (ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 || + (ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0) { + goto cleanup; + } +#endif + + /* This check here is a duplication of the one in "mbedtls_psa_rsa_load_representation" + * in "psa_crypto_rsa.c". The reason for which this is needed here is explained + * in issue tf-psa-crypto#562. */ + bits = PSA_BYTES_TO_BITS(mbedtls_rsa_get_len(rsa)); + if (bits > PSA_VENDOR_RSA_MAX_KEY_BITS) { + ret = PSA_ERROR_NOT_SUPPORTED; + goto cleanup; + } + + //if ((ret = mbedtls_rsa_check_privkey(rsa)) != 0) { + // goto cleanup; + //} + + if (p != end) { + ret = MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + } + +cleanup: +#if defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_free(&T); +#endif /* MBEDTLS_RSA_NO_CRT */ + + if (ret != 0) { + mbedtls_rsa_free(rsa); + } + + return ret; +} + +int mbedtls_rsa_parse_pubkey(mbedtls_rsa_context *rsa, const unsigned char *key, size_t keylen) +{ + unsigned char *p = (unsigned char *) key; + unsigned char *end = (unsigned char *) (key + keylen); + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t len; + + /* + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ + mbedtls_mpi_init(&rsa->N); + mbedtls_mpi_init(&rsa->E); + + if ((ret = mbedtls_asn1_get_tag(&p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { + goto exit; + } + + if (end != p + len) { + ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + goto exit; + } + + /* Import N */ + if ((ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER)) != 0) { + goto exit; + } + + if ((ret = mbedtls_mpi_read_binary(&rsa->N, p, len)) != 0) { + ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + goto exit; + } + + rsa->len = mbedtls_mpi_size(&rsa->N); + + p += len; + + /* Import E */ + if ((ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER)) != 0) { + goto exit; + } + + if ((ret = mbedtls_mpi_read_binary(&rsa->E, p, len)) != 0) { + ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + goto exit; + } + + p += len; + + if (mbedtls_rsa_check_pubkey(rsa) != 0) { + ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + goto exit; + } + + if (p != end) { + ret = MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + } + +exit: + if (ret != 0) { + mbedtls_mpi_free(&rsa->N); + mbedtls_mpi_free(&rsa->E); + } + + return ret; +} + +#define MBEDTLS_RSA_WRITE_MPI(m) \ + do { \ + if ((ret = mbedtls_asn1_write_mpi(p, start, m)) < 0) { \ + goto end_of_export; \ + } \ + len += ret; \ + } while (0) + +int mbedtls_rsa_write_key(const mbedtls_rsa_context *rsa, unsigned char *start, + unsigned char **p) +{ + size_t len = 0; + int ret; +#if defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi DP, DQ, QP; + + mbedtls_mpi_init(&DP); mbedtls_mpi_init(&DQ); mbedtls_mpi_init(&QP); +#endif /* MBEDTLS_RSA_NO_CRT */ + + /* + * Export the parameters one after another to avoid simultaneous copies. + */ + + /* Export QP, DQ, DP */ +#if !defined(MBEDTLS_RSA_NO_CRT) + MBEDTLS_RSA_WRITE_MPI(&rsa->QP); + MBEDTLS_RSA_WRITE_MPI(&rsa->DQ); + MBEDTLS_RSA_WRITE_MPI(&rsa->DP); +#else /* MBEDTLS_RSA_NO_CRT */ + if ((ret = mbedtls_rsa_deduce_crt(&rsa->P, &rsa->Q, &rsa->D, &DP, &DQ, &QP)) != 0) { + goto end_of_export; + } + MBEDTLS_RSA_WRITE_MPI(&QP); + MBEDTLS_RSA_WRITE_MPI(&DQ); + MBEDTLS_RSA_WRITE_MPI(&DP); +#endif /* MBEDTLS_RSA_NO_CRT */ + + /* Export Q, P, D, E, N */ + MBEDTLS_RSA_WRITE_MPI(&rsa->Q); + MBEDTLS_RSA_WRITE_MPI(&rsa->P); + MBEDTLS_RSA_WRITE_MPI(&rsa->D); + MBEDTLS_RSA_WRITE_MPI(&rsa->E); + MBEDTLS_RSA_WRITE_MPI(&rsa->N); + +end_of_export: + +#if defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_free(&DP); mbedtls_mpi_free(&DQ); mbedtls_mpi_free(&QP); +#endif /* MBEDTLS_RSA_NO_CRT */ + + if (ret < 0) { + return ret; + } + + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(p, start, 0)); + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len)); + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, + MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE)); + + return (int) len; +} + +/* + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ +int mbedtls_rsa_write_pubkey(const mbedtls_rsa_context *rsa, unsigned char *start, + unsigned char **p) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t len = 0; + + /* Export E, N */ + MBEDTLS_RSA_WRITE_MPI(&rsa->E); + MBEDTLS_RSA_WRITE_MPI(&rsa->N); + +end_of_export: + + if (ret < 0) { + return ret; + } + + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len)); + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE)); + + return (int) len; +} + +#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) + +/** This function performs the unpadding part of a PKCS#1 v1.5 decryption + * operation (EME-PKCS1-v1_5 decoding). + * + * \note The return value from this function is a sensitive value + * (this is unusual). #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE shouldn't happen + * in a well-written application, but 0 vs #MBEDTLS_ERR_RSA_INVALID_PADDING + * is often a situation that an attacker can provoke and leaking which + * one is the result is precisely the information the attacker wants. + * + * \param input The input buffer which is the payload inside PKCS#1v1.5 + * encryption padding, called the "encoded message EM" + * by the terminology. + * \param ilen The length of the payload in the \p input buffer. + * \param output The buffer for the payload, called "message M" by the + * PKCS#1 terminology. This must be a writable buffer of + * length \p output_max_len bytes. + * \param olen The address at which to store the length of + * the payload. This must not be \c NULL. + * \param output_max_len The length in bytes of the output buffer \p output. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE + * The output buffer is too small for the unpadded payload. + * \return #MBEDTLS_ERR_RSA_INVALID_PADDING + * The input doesn't contain properly formatted padding. + */ +static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, + size_t ilen, + unsigned char *output, + size_t output_max_len, + size_t *olen) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t i, plaintext_max_size; + + /* The following variables take sensitive values: their value must + * not leak into the observable behavior of the function other than + * the designated outputs (output, olen, return value). Otherwise + * this would open the execution of the function to + * side-channel-based variants of the Bleichenbacher padding oracle + * attack. Potential side channels include overall timing, memory + * access patterns (especially visible to an adversary who has access + * to a shared memory cache), and branches (especially visible to + * an adversary who has access to a shared code cache or to a shared + * branch predictor). */ + size_t pad_count = 0; + mbedtls_ct_condition_t bad; + mbedtls_ct_condition_t pad_done; + size_t plaintext_size = 0; + mbedtls_ct_condition_t output_too_large; + + plaintext_max_size = (output_max_len > ilen - 11) ? ilen - 11 + : output_max_len; + + /* Check and get padding length in constant time and constant + * memory trace. The first byte must be 0. */ + bad = mbedtls_ct_bool(input[0]); + + + /* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00 + * where PS must be at least 8 nonzero bytes. */ + bad = mbedtls_ct_bool_or(bad, mbedtls_ct_uint_ne(input[1], MBEDTLS_RSA_CRYPT)); + + /* Read the whole buffer. Set pad_done to nonzero if we find + * the 0x00 byte and remember the padding length in pad_count. */ + pad_done = MBEDTLS_CT_FALSE; + for (i = 2; i < ilen; i++) { + mbedtls_ct_condition_t found = mbedtls_ct_uint_eq(input[i], 0); + pad_done = mbedtls_ct_bool_or(pad_done, found); + pad_count += mbedtls_ct_uint_if_else_0(mbedtls_ct_bool_not(pad_done), 1); + } + + /* If pad_done is still zero, there's no data, only unfinished padding. */ + bad = mbedtls_ct_bool_or(bad, mbedtls_ct_bool_not(pad_done)); + + /* There must be at least 8 bytes of padding. */ + bad = mbedtls_ct_bool_or(bad, mbedtls_ct_uint_gt(8, pad_count)); + + /* If the padding is valid, set plaintext_size to the number of + * remaining bytes after stripping the padding. If the padding + * is invalid, avoid leaking this fact through the size of the + * output: use the maximum message size that fits in the output + * buffer. Do it without branches to avoid leaking the padding + * validity through timing. RSA keys are small enough that all the + * size_t values involved fit in unsigned int. */ + plaintext_size = mbedtls_ct_uint_if( + bad, (unsigned) plaintext_max_size, + (unsigned) (ilen - pad_count - 3)); + + /* Set output_too_large to 0 if the plaintext fits in the output + * buffer and to 1 otherwise. */ + output_too_large = mbedtls_ct_uint_gt(plaintext_size, + plaintext_max_size); + + /* Set ret without branches to avoid timing attacks. Return: + * - INVALID_PADDING if the padding is bad (bad != 0). + * - OUTPUT_TOO_LARGE if the padding is good but the decrypted + * plaintext does not fit in the output buffer. + * - 0 if the padding is correct. */ + ret = mbedtls_ct_error_if( + bad, + MBEDTLS_ERR_RSA_INVALID_PADDING, + mbedtls_ct_error_if_else_0(output_too_large, MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE) + ); + + /* If the padding is bad or the plaintext is too large, zero the + * data that we're about to copy to the output buffer. + * We need to copy the same amount of data + * from the same buffer whether the padding is good or not to + * avoid leaking the padding validity through overall timing or + * through memory or cache access patterns. */ + mbedtls_ct_zeroize_if(mbedtls_ct_bool_or(bad, output_too_large), input + 11, ilen - 11); + + /* If the plaintext is too large, truncate it to the buffer size. + * Copy anyway to avoid revealing the length through timing, because + * revealing the length is as bad as revealing the padding validity + * for a Bleichenbacher attack. */ + plaintext_size = mbedtls_ct_uint_if(output_too_large, + (unsigned) plaintext_max_size, + (unsigned) plaintext_size); + + /* Move the plaintext to the leftmost position where it can start in + * the working buffer, i.e. make it start plaintext_max_size from + * the end of the buffer. Do this with a memory access trace that + * does not depend on the plaintext size. After this move, the + * starting location of the plaintext is no longer sensitive + * information. */ + mbedtls_ct_memmove_left(input + ilen - plaintext_max_size, + plaintext_max_size, + plaintext_max_size - plaintext_size); + + /* Finally copy the decrypted plaintext plus trailing zeros into the output + * buffer. If output_max_len is 0, then output may be an invalid pointer + * and the result of memcpy() would be undefined; prevent undefined + * behavior making sure to depend only on output_max_len (the size of the + * user-provided output buffer), which is independent from plaintext + * length, validity of padding, success of the decryption, and other + * secrets. */ + if (output_max_len != 0) { + memcpy(output, input + ilen - plaintext_max_size, plaintext_max_size); + } + + /* Report the amount of data we copied to the output buffer. In case + * of errors (bad padding or output too large), the value of *olen + * when this function returns is not specified. Making it equivalent + * to the good case limits the risks of leaking the padding validity. */ + *olen = plaintext_size; + + return ret; +} + +#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C */ + +/* + * Checks whether the context fields are set in such a way + * that the RSA primitives will be able to execute without error. + * It does *not* make guarantees for consistency of the parameters. + */ +static int rsa_check_context(mbedtls_rsa_context const *ctx, int is_priv, + int blinding_needed) +{ +#if !defined(MBEDTLS_RSA_NO_CRT) + /* blinding_needed is only used for NO_CRT to decide whether + * P,Q need to be present or not. */ + ((void) blinding_needed); +#endif + + if (ctx->len != mbedtls_mpi_size(&ctx->N) || + ctx->len > MBEDTLS_MPI_MAX_SIZE) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + /* + * 1. Modular exponentiation needs positive, odd moduli. + */ + + /* Modular exponentiation wrt. N is always used for + * RSA public key operations. */ + if (mbedtls_mpi_cmp_int(&ctx->N, 0) <= 0 || + mbedtls_mpi_get_bit(&ctx->N, 0) == 0) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + +#if !defined(MBEDTLS_RSA_NO_CRT) + /* Modular exponentiation for P and Q is only + * used for private key operations and if CRT + * is used. */ + if (is_priv && + (mbedtls_mpi_cmp_int(&ctx->P, 0) <= 0 || + mbedtls_mpi_get_bit(&ctx->P, 0) == 0 || + mbedtls_mpi_cmp_int(&ctx->Q, 0) <= 0 || + mbedtls_mpi_get_bit(&ctx->Q, 0) == 0)) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } +#endif /* !MBEDTLS_RSA_NO_CRT */ + + /* + * 2. Exponents must be positive + */ + + /* Always need E for public key operations */ + if (mbedtls_mpi_cmp_int(&ctx->E, 0) <= 0) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + +#if defined(MBEDTLS_RSA_NO_CRT) + /* For private key operations, use D or DP & DQ + * as (unblinded) exponents. */ + if (is_priv && mbedtls_mpi_cmp_int(&ctx->D, 0) <= 0) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } +#else + if (is_priv && + (mbedtls_mpi_cmp_int(&ctx->DP, 0) <= 0 || + mbedtls_mpi_cmp_int(&ctx->DQ, 0) <= 0)) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } +#endif /* MBEDTLS_RSA_NO_CRT */ + + /* Blinding shouldn't make exponents negative either, + * so check that P, Q >= 1 if that hasn't yet been + * done as part of 1. */ +#if defined(MBEDTLS_RSA_NO_CRT) + if (is_priv && blinding_needed && + (mbedtls_mpi_cmp_int(&ctx->P, 0) <= 0 || + mbedtls_mpi_cmp_int(&ctx->Q, 0) <= 0)) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } +#endif + + /* It wouldn't lead to an error if it wasn't satisfied, + * but check for QP >= 1 nonetheless. */ +#if !defined(MBEDTLS_RSA_NO_CRT) + if (is_priv && + mbedtls_mpi_cmp_int(&ctx->QP, 0) <= 0) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } +#endif + + return 0; +} + +/* + * Initialize an RSA context + */ +void mbedtls_rsa_init(mbedtls_rsa_context *ctx) +{ + memset(ctx, 0, sizeof(mbedtls_rsa_context)); + + ctx->padding = MBEDTLS_RSA_PKCS_V15; + ctx->hash_id = MBEDTLS_MD_NONE; +} + +/* + * Set padding for an existing RSA context + */ +int mbedtls_rsa_set_padding(mbedtls_rsa_context *ctx, int padding, + mbedtls_md_type_t hash_id) +{ + switch (padding) { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + break; +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + break; +#endif + default: + return MBEDTLS_ERR_RSA_INVALID_PADDING; + } + +#if defined(MBEDTLS_PKCS1_V21) + if ((padding == MBEDTLS_RSA_PKCS_V21) && + (hash_id != MBEDTLS_MD_NONE)) { + /* Just make sure this hash is supported in this build. */ + if (mbedtls_md_info_from_type(hash_id) == NULL) { + return MBEDTLS_ERR_RSA_INVALID_PADDING; + } + } +#endif /* MBEDTLS_PKCS1_V21 */ + + ctx->padding = padding; + ctx->hash_id = hash_id; + + return 0; +} + +/* + * Get padding mode of initialized RSA context + */ +int mbedtls_rsa_get_padding_mode(const mbedtls_rsa_context *ctx) +{ + return ctx->padding; +} + +/* + * Get hash identifier of mbedtls_md_type_t type + */ +int mbedtls_rsa_get_md_alg(const mbedtls_rsa_context *ctx) +{ + return ctx->hash_id; +} + +/* + * Get length in bits of RSA modulus + */ +size_t mbedtls_rsa_get_bitlen(const mbedtls_rsa_context *ctx) +{ + return mbedtls_mpi_bitlen(&ctx->N); +} + +/* + * Get length in bytes of RSA modulus + */ +size_t mbedtls_rsa_get_len(const mbedtls_rsa_context *ctx) +{ + return ctx->len; +} + +#if defined(MBEDTLS_GENPRIME) + +/* + * Generate an RSA keypair + * + * This generation method follows the RSA key pair generation procedure of + * FIPS 186-4 if 2^16 < exponent < 2^256 and nbits = 2048 or nbits = 3072. + */ +int mbedtls_rsa_gen_key(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + unsigned int nbits, int exponent) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi H; + int prime_quality = 0; + + /* + * If the modulus is 1024 bit long or shorter, then the security strength of + * the RSA algorithm is less than or equal to 80 bits and therefore an error + * rate of 2^-80 is sufficient. + */ + if (nbits > 1024) { + prime_quality = MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR; + } + + mbedtls_mpi_init(&H); + + if (exponent < 3 || nbits % 2 != 0) { + ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + goto cleanup; + } + + if (nbits < MBEDTLS_RSA_GEN_KEY_MIN_BITS) { + ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + goto cleanup; + } + + /* + * find primes P and Q with Q < P so that: + * 1. |P-Q| > 2^( nbits / 2 - 100 ) + * 2. GCD( E, (P-1)*(Q-1) ) == 1 + * 3. E^-1 mod LCM(P-1, Q-1) > 2^( nbits / 2 ) + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&ctx->E, exponent)); + + do { + MBEDTLS_MPI_CHK(mbedtls_mpi_gen_prime(&ctx->P, nbits >> 1, + prime_quality, f_rng, p_rng)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_gen_prime(&ctx->Q, nbits >> 1, + prime_quality, f_rng, p_rng)); + + /* make sure the difference between p and q is not too small (FIPS 186-4 §B.3.3 step 5.4) */ + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&H, &ctx->P, &ctx->Q)); + if (mbedtls_mpi_bitlen(&H) <= ((nbits >= 200) ? ((nbits >> 1) - 99) : 0)) { + continue; + } + + /* not required by any standards, but some users rely on the fact that P > Q */ + if (H.s < 0) { + mbedtls_mpi_swap(&ctx->P, &ctx->Q); + } + + /* Compute D = E^-1 mod LCM(P-1, Q-1) (FIPS 186-4 §B.3.1 criterion 3(b)) + * if it exists (FIPS 186-4 §B.3.1 criterion 2(a)) */ + ret = mbedtls_rsa_deduce_private_exponent(&ctx->P, &ctx->Q, &ctx->E, &ctx->D); + if (ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) { + continue; + } + if (ret != 0) { + goto cleanup; + } + + /* (FIPS 186-4 §B.3.1 criterion 3(a)) */ + if (mbedtls_mpi_bitlen(&ctx->D) <= ((nbits + 1) / 2)) { + continue; + } + + break; + } while (1); + + + /* N = P * Q */ + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->N, &ctx->P, &ctx->Q)); + ctx->len = mbedtls_mpi_size(&ctx->N); + +#if !defined(MBEDTLS_RSA_NO_CRT) + /* + * DP = D mod (P - 1) + * DQ = D mod (Q - 1) + * QP = Q^-1 mod P + */ + MBEDTLS_MPI_CHK(mbedtls_rsa_deduce_crt(&ctx->P, &ctx->Q, &ctx->D, + &ctx->DP, &ctx->DQ, &ctx->QP)); +#endif /* MBEDTLS_RSA_NO_CRT */ + + /* Double-check */ + MBEDTLS_MPI_CHK(mbedtls_rsa_check_privkey(ctx)); + +cleanup: + + mbedtls_mpi_free(&H); + + if (ret != 0) { + mbedtls_rsa_free(ctx); + + if ((-ret & ~0x7f) == 0) { + ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_RSA_KEY_GEN_FAILED, ret); + } + return ret; + } + + return 0; +} + +#endif /* MBEDTLS_GENPRIME */ + +/* + * Check a public RSA key + */ +int mbedtls_rsa_check_pubkey(const mbedtls_rsa_context *ctx) +{ + if (rsa_check_context(ctx, 0 /* public */, 0 /* no blinding */) != 0) { + return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + } + + if (mbedtls_mpi_bitlen(&ctx->N) < 128) { + return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + } + + if (mbedtls_mpi_get_bit(&ctx->E, 0) == 0 || + mbedtls_mpi_bitlen(&ctx->E) < 2 || + mbedtls_mpi_cmp_mpi(&ctx->E, &ctx->N) >= 0) { + return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + } + + return 0; +} + +/* + * Check for the consistency of all fields in an RSA private key context + */ +int mbedtls_rsa_check_privkey(const mbedtls_rsa_context *ctx) +{ + if (mbedtls_rsa_check_pubkey(ctx) != 0 || + rsa_check_context(ctx, 1 /* private */, 1 /* blinding */) != 0) { + return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + } + + if (mbedtls_rsa_validate_params(&ctx->N, &ctx->P, &ctx->Q, + &ctx->D, &ctx->E, NULL, NULL) != 0) { + return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + } + +#if !defined(MBEDTLS_RSA_NO_CRT) + else if (mbedtls_rsa_validate_crt(&ctx->P, &ctx->Q, &ctx->D, + &ctx->DP, &ctx->DQ, &ctx->QP) != 0) { + return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + } +#endif + + return 0; +} + +/* + * Check if contexts holding a public and private key match + */ +int mbedtls_rsa_check_pub_priv(const mbedtls_rsa_context *pub, + const mbedtls_rsa_context *prv) +{ + if (mbedtls_rsa_check_pubkey(pub) != 0 || + mbedtls_rsa_check_privkey(prv) != 0) { + return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + } + + if (mbedtls_mpi_cmp_mpi(&pub->N, &prv->N) != 0 || + mbedtls_mpi_cmp_mpi(&pub->E, &prv->E) != 0) { + return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + } + + return 0; +} + +/* + * Do an RSA public key operation + */ +int mbedtls_rsa_public(mbedtls_rsa_context *ctx, + const unsigned char *input, + unsigned char *output) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t olen; + mbedtls_mpi T; + + if (rsa_check_context(ctx, 0 /* public */, 0 /* no blinding */)) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + mbedtls_mpi_init(&T); + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&T, input, ctx->len)); + + if (mbedtls_mpi_cmp_mpi(&T, &ctx->N) >= 0) { + ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + goto cleanup; + } + + olen = ctx->len; + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod_unsafe(&T, &T, &ctx->E, &ctx->N, &ctx->RN)); + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&T, output, olen)); + +cleanup: + + mbedtls_mpi_free(&T); + + if (ret != 0) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_RSA_PUBLIC_FAILED, ret); + } + + return 0; +} + +#if !defined(MBEDTLS_RSA_NO_CRT) +/* + * Compute T such that T = TP mod P and T = TQ mod Q. + * (This is the Chinese Remainder Theorem - CRT.) + */ +static int rsa_apply_crt(mbedtls_mpi *T, + const mbedtls_mpi *TP, + const mbedtls_mpi *TQ, + const mbedtls_rsa_context *ctx) +{ + int ret; + + /* + * Set T = ((TP - TQ) * (Q^-1 mod P) mod P) * Q + TQ + * + * That way we have both: + * mod P: T = (TP - TQ) * (Q^-1 * Q) + TQ = (TP - TQ) * 1 + TQ = TP + * mod Q: T = (...) * Q + TQ = TQ + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(T, TP, TQ)); // T = TP - TQ + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(T, T, &ctx->QP)); // T *= Q^-1 mod P + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(T, T, &ctx->P)); // T %= P + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(T, T, &ctx->Q)); // T *= Q + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(T, T, TQ)); // T += TQ + +cleanup: + return ret; +} +#endif + +/* Generate random A and B such that A^-1 = B mod N */ +static int rsa_gen_rand_with_inverse(const mbedtls_rsa_context *ctx, + mbedtls_mpi *A, + mbedtls_mpi *B, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ +#if defined(MBEDTLS_RSA_NO_CRT) + int ret; + mbedtls_mpi G; + + mbedtls_mpi_init(&G); + + MBEDTLS_MPI_CHK(mbedtls_mpi_random(A, 1, &ctx->N, f_rng, p_rng)); + MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&G, B, A, &ctx->N)); + + if (mbedtls_mpi_cmp_int(&G, 1) != 0) { + /* This happens if we're unlucky enough to draw a multiple of P or Q, + * or if (at least) one of them is not a prime, and we drew a multiple + * of one of its factors. */ + ret = MBEDTLS_ERR_RSA_RNG_FAILED; + goto cleanup; + } + +cleanup: + mbedtls_mpi_free(&G); + + return ret; +#else + int ret; + mbedtls_mpi Ap, Aq, Bp, Bq, G; + + mbedtls_mpi_init(&Ap); mbedtls_mpi_init(&Aq); + mbedtls_mpi_init(&Bp); mbedtls_mpi_init(&Bq); + mbedtls_mpi_init(&G); + + /* + * Instead of generating A, B = A^-1 (mod N) directly, generate one Ap, Bp + * pair (mod P) and one pair (mod Q) and use Chinese Remainder Theorem to + * construct an A and B from those. + * + * This works because the CRT correspondence is a ring isomorphism between + * Z/NZ (integers mod N) and Z/PZ x Z/QZ (pairs of integers mod P and Q): + * - it is a bijection (one-to-one correspondence); + * - doing a ring operation (modular +, -, *, ^-1 when possible) on one side is + * the same as doing it on the other side. + * So, drawing uniformly at random an invertible A mod N is the same as + * drawing uniformly at random pairs of invertible Ap mod P, Aq mod Q. + */ + + /* Generate Ap in [1, P) and compute Bp = Ap^-1 mod P */ + MBEDTLS_MPI_CHK(mbedtls_mpi_random(&Ap, 1, &ctx->P, f_rng, p_rng)); + MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&G, &Bp, &Ap, &ctx->P)); + if (mbedtls_mpi_cmp_int(&G, 1) != 0) { + /* This can only happen if P was not a prime. */ + ret = MBEDTLS_ERR_RSA_RNG_FAILED; + goto cleanup; + } + + /* Generate Aq in [1, Q) and compute Bq = Aq^-1 mod Q */ + MBEDTLS_MPI_CHK(mbedtls_mpi_random(&Aq, 1, &ctx->Q, f_rng, p_rng)); + MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&G, &Bq, &Aq, &ctx->Q)); + if (mbedtls_mpi_cmp_int(&G, 1) != 0) { + /* This can only happen if Q was not a prime. */ + ret = MBEDTLS_ERR_RSA_RNG_FAILED; + goto cleanup; + } + + /* Reconstruct A and B */ + MBEDTLS_MPI_CHK(rsa_apply_crt(A, &Ap, &Aq, ctx)); + MBEDTLS_MPI_CHK(rsa_apply_crt(B, &Bp, &Bq, ctx)); + +cleanup: + mbedtls_mpi_free(&Ap); mbedtls_mpi_free(&Aq); + mbedtls_mpi_free(&Bp); mbedtls_mpi_free(&Bq); + mbedtls_mpi_free(&G); + + return ret; +#endif +} + +/* + * Generate or update blinding values, see section 10 of: + * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA, + * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer + * Berlin Heidelberg, 1996. p. 104-113. + */ +static int rsa_prepare_blinding(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) +{ + int ret; + + if (ctx->Vf.p != NULL) { + /* We already have blinding values, just update them by squaring */ + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vi, &ctx->Vi, &ctx->Vi)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vi, &ctx->Vi, &ctx->N)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vf, &ctx->Vf, &ctx->Vf)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vf, &ctx->Vf, &ctx->N)); + goto cleanup; + } + + /* Unblinding value: Vf = random number, invertible mod N */ + MBEDTLS_MPI_CHK(rsa_gen_rand_with_inverse(ctx, &ctx->Vf, &ctx->Vi, f_rng, p_rng)); + + /* Blinding value: Vi = Vf^(-e) mod N + * (Vi already contains Vf^-1 at this point) */ + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&ctx->Vi, &ctx->Vi, &ctx->E, &ctx->N, &ctx->RN)); + +cleanup: + return ret; +} + +/* + * Unblind + * T = T * Vf mod N + */ +static int rsa_unblind(mbedtls_mpi *T, mbedtls_mpi *Vf, const mbedtls_mpi *N) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + const mbedtls_mpi_uint mm = mbedtls_mpi_core_montmul_init(N->p); + const size_t nlimbs = N->n; + const size_t tlimbs = mbedtls_mpi_core_montmul_working_limbs(nlimbs); + mbedtls_mpi RR, M_T; + + mbedtls_mpi_init(&RR); + mbedtls_mpi_init(&M_T); + + MBEDTLS_MPI_CHK(mbedtls_mpi_core_get_mont_r2_unsafe(&RR, N)); + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&M_T, tlimbs)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(T, nlimbs)); + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Vf, nlimbs)); + + /* T = T * Vf mod N + * Reminder: montmul(A, B, N) = A * B * R^-1 mod N + * Usually both operands are multiplied by R mod N beforehand (by calling + * `to_mont_rep()` on them), yielding a result that's also * R mod N (aka + * "in the Montgomery domain"). Here we only multiply one operand by R mod + * N, so the result is directly what we want - no need to call + * `from_mont_rep()` on it. */ + mbedtls_mpi_core_to_mont_rep(T->p, T->p, N->p, nlimbs, mm, RR.p, M_T.p); + mbedtls_mpi_core_montmul(T->p, T->p, Vf->p, nlimbs, N->p, nlimbs, mm, M_T.p); + +cleanup: + + mbedtls_mpi_free(&RR); + mbedtls_mpi_free(&M_T); + + return ret; +} + +/* + * Exponent blinding supposed to prevent side-channel attacks using multiple + * traces of measurements to recover the RSA key. The more collisions are there, + * the more bits of the key can be recovered. See [3]. + * + * Collecting n collisions with m bit long blinding value requires 2^(m-m/n) + * observations on average. + * + * For example with 28 byte blinding to achieve 2 collisions the adversary has + * to make 2^112 observations on average. + * + * (With the currently (as of 2017 April) known best algorithms breaking 2048 + * bit RSA requires approximately as much time as trying out 2^112 random keys. + * Thus in this sense with 28 byte blinding the security is not reduced by + * side-channel attacks like the one in [3]) + * + * This countermeasure does not help if the key recovery is possible with a + * single trace. + */ +#define RSA_EXPONENT_BLINDING 28 + +/* + * Do an RSA private key operation + */ +int mbedtls_rsa_private(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *input, + unsigned char *output) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t olen; + + /* Temporary holding the result */ + mbedtls_mpi T; + + /* Temporaries holding P-1, Q-1 and the + * exponent blinding factor, respectively. */ + mbedtls_mpi P1, Q1, R; + +#if !defined(MBEDTLS_RSA_NO_CRT) + /* Temporaries holding the results mod p resp. mod q. */ + mbedtls_mpi TP, TQ; + + /* Temporaries holding the blinded exponents for + * the mod p resp. mod q computation (if used). */ + mbedtls_mpi DP_blind, DQ_blind; +#else + /* Temporary holding the blinded exponent (if used). */ + mbedtls_mpi D_blind; +#endif /* MBEDTLS_RSA_NO_CRT */ + + /* Temporaries holding the initial input and the double + * checked result; should be the same in the end. */ + mbedtls_mpi input_blinded, check_result_blinded; + + if (f_rng == NULL) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + if (rsa_check_context(ctx, 1 /* private key checks */, + 1 /* blinding on */) != 0) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + /* MPI Initialization */ + mbedtls_mpi_init(&T); + + mbedtls_mpi_init(&P1); + mbedtls_mpi_init(&Q1); + mbedtls_mpi_init(&R); + +#if defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_init(&D_blind); +#else + mbedtls_mpi_init(&DP_blind); + mbedtls_mpi_init(&DQ_blind); +#endif + +#if !defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_init(&TP); mbedtls_mpi_init(&TQ); +#endif + + mbedtls_mpi_init(&input_blinded); + mbedtls_mpi_init(&check_result_blinded); + + /* End of MPI initialization */ + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&T, input, ctx->len)); + if (mbedtls_mpi_cmp_mpi(&T, &ctx->N) >= 0) { + ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + goto cleanup; + } + + /* + * Blinding + * T = T * Vi mod N + */ + MBEDTLS_MPI_CHK(rsa_prepare_blinding(ctx, f_rng, p_rng)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&T, &T, &ctx->Vi)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&T, &T, &ctx->N)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&input_blinded, &T)); + + /* + * Exponent blinding + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&P1, &ctx->P, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&Q1, &ctx->Q, 1)); + +#if defined(MBEDTLS_RSA_NO_CRT) + /* + * D_blind = ( P - 1 ) * ( Q - 1 ) * R + D + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&R, RSA_EXPONENT_BLINDING, + f_rng, p_rng)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&D_blind, &P1, &Q1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&D_blind, &D_blind, &R)); + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&D_blind, &D_blind, &ctx->D)); +#else + /* + * DP_blind = ( P - 1 ) * R + DP + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&R, RSA_EXPONENT_BLINDING, + f_rng, p_rng)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&DP_blind, &P1, &R)); + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&DP_blind, &DP_blind, + &ctx->DP)); + + /* + * DQ_blind = ( Q - 1 ) * R + DQ + */ + MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&R, RSA_EXPONENT_BLINDING, + f_rng, p_rng)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&DQ_blind, &Q1, &R)); + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&DQ_blind, &DQ_blind, + &ctx->DQ)); +#endif /* MBEDTLS_RSA_NO_CRT */ + +#if defined(MBEDTLS_RSA_NO_CRT) + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&T, &T, &D_blind, &ctx->N, &ctx->RN)); +#else + /* + * Faster decryption using the CRT + * + * TP = input ^ dP mod P + * TQ = input ^ dQ mod Q + */ + + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&TP, &T, &DP_blind, &ctx->P, &ctx->RP)); + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&TQ, &T, &DQ_blind, &ctx->Q, &ctx->RQ)); + MBEDTLS_MPI_CHK(rsa_apply_crt(&T, &TP, &TQ, ctx)); +#endif /* MBEDTLS_RSA_NO_CRT */ + + /* Verify the result to prevent glitching attacks. */ + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&check_result_blinded, &T, &ctx->E, + &ctx->N, &ctx->RN)); + if (mbedtls_mpi_cmp_mpi(&check_result_blinded, &input_blinded) != 0) { + ret = MBEDTLS_ERR_RSA_VERIFY_FAILED; + goto cleanup; + } + + /* + * Unblind + * T = T * Vf mod N + */ + MBEDTLS_MPI_CHK(rsa_unblind(&T, &ctx->Vf, &ctx->N)); + + olen = ctx->len; + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&T, output, olen)); + +cleanup: + + mbedtls_mpi_free(&P1); + mbedtls_mpi_free(&Q1); + mbedtls_mpi_free(&R); + +#if defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_free(&D_blind); +#else + mbedtls_mpi_free(&DP_blind); + mbedtls_mpi_free(&DQ_blind); +#endif + + mbedtls_mpi_free(&T); + +#if !defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_free(&TP); mbedtls_mpi_free(&TQ); +#endif + + mbedtls_mpi_free(&check_result_blinded); + mbedtls_mpi_free(&input_blinded); + + if (ret != 0 && ret >= -0x007f) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_RSA_PRIVATE_FAILED, ret); + } + + return ret; +} + +#if defined(MBEDTLS_PKCS1_V21) +/** + * Generate and apply the MGF1 operation (from PKCS#1 v2.1) to a buffer. + * + * \param dst buffer to mask + * \param dlen length of destination buffer + * \param src source of the mask generation + * \param slen length of the source buffer + * \param md_alg message digest to use + */ +static int mgf_mask(unsigned char *dst, size_t dlen, unsigned char *src, + size_t slen, mbedtls_md_type_t md_alg) +{ + unsigned char counter[4]; + unsigned char *p; + unsigned int hlen; + size_t i, use_len; + unsigned char mask[MBEDTLS_MD_MAX_SIZE]; + int ret = 0; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + mbedtls_md_init(&md_ctx); + md_info = mbedtls_md_info_from_type(md_alg); + if (md_info == NULL) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + mbedtls_md_init(&md_ctx); + if ((ret = mbedtls_md_setup(&md_ctx, md_info, 0)) != 0) { + goto exit; + } + + hlen = mbedtls_md_get_size(md_info); + + memset(mask, 0, sizeof(mask)); + memset(counter, 0, 4); + + /* Generate and apply dbMask */ + p = dst; + + while (dlen > 0) { + use_len = hlen; + if (dlen < hlen) { + use_len = dlen; + } + + if ((ret = mbedtls_md_starts(&md_ctx)) != 0) { + goto exit; + } + if ((ret = mbedtls_md_update(&md_ctx, src, slen)) != 0) { + goto exit; + } + if ((ret = mbedtls_md_update(&md_ctx, counter, 4)) != 0) { + goto exit; + } + if ((ret = mbedtls_md_finish(&md_ctx, mask)) != 0) { + goto exit; + } + + for (i = 0; i < use_len; ++i) { + *p++ ^= mask[i]; + } + + counter[3]++; + + dlen -= use_len; + } + +exit: + mbedtls_platform_zeroize(mask, sizeof(mask)); + mbedtls_md_free(&md_ctx); + + return ret; +} + +/** + * Generate Hash(M') as in RFC 8017 page 43 points 5 and 6. + * + * \param hash the input hash + * \param hlen length of the input hash + * \param salt the input salt + * \param slen length of the input salt + * \param out the output buffer - must be large enough for \p md_alg + * \param md_alg message digest to use + */ +static int hash_mprime(const unsigned char *hash, size_t hlen, + const unsigned char *salt, size_t slen, + unsigned char *out, mbedtls_md_type_t md_alg) +{ + const unsigned char zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + mbedtls_md_context_t md_ctx; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_alg); + if (md_info == NULL) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + mbedtls_md_init(&md_ctx); + if ((ret = mbedtls_md_setup(&md_ctx, md_info, 0)) != 0) { + goto exit; + } + if ((ret = mbedtls_md_starts(&md_ctx)) != 0) { + goto exit; + } + if ((ret = mbedtls_md_update(&md_ctx, zeros, sizeof(zeros))) != 0) { + goto exit; + } + if ((ret = mbedtls_md_update(&md_ctx, hash, hlen)) != 0) { + goto exit; + } + if ((ret = mbedtls_md_update(&md_ctx, salt, slen)) != 0) { + goto exit; + } + if ((ret = mbedtls_md_finish(&md_ctx, out)) != 0) { + goto exit; + } + +exit: + mbedtls_md_free(&md_ctx); + + return ret; +} + +/** + * Compute a hash. + * + * \param md_alg algorithm to use + * \param input input message to hash + * \param ilen input length + * \param output the output buffer - must be large enough for \p md_alg + */ +static int compute_hash(mbedtls_md_type_t md_alg, + const unsigned char *input, size_t ilen, + unsigned char *output) +{ + const mbedtls_md_info_t *md_info; + + md_info = mbedtls_md_info_from_type(md_alg); + if (md_info == NULL) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + return mbedtls_md(md_info, input, ilen, output); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSAES-OAEP-ENCRYPT function + */ +int mbedtls_rsa_rsaes_oaep_encrypt(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *label, size_t label_len, + size_t ilen, + const unsigned char *input, + unsigned char *output) +{ + size_t olen; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char *p = output; + unsigned int hlen; + + if (f_rng == NULL) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + hlen = mbedtls_md_get_size_from_type((mbedtls_md_type_t) ctx->hash_id); + if (hlen == 0) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + olen = ctx->len; + + /* first comparison checks for overflow */ + if (ilen + 2 * hlen + 2 < ilen || olen < ilen + 2 * hlen + 2) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + memset(output, 0, olen); + + *p++ = 0; + + /* Generate a random octet string seed */ + if ((ret = f_rng(p_rng, p, hlen)) != 0) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_RSA_RNG_FAILED, ret); + } + + p += hlen; + + /* Construct DB */ + ret = compute_hash((mbedtls_md_type_t) ctx->hash_id, label, label_len, p); + if (ret != 0) { + return ret; + } + p += hlen; + p += olen - 2 * hlen - 2 - ilen; + *p++ = 1; + if (ilen != 0) { + memcpy(p, input, ilen); + } + + /* maskedDB: Apply dbMask to DB */ + if ((ret = mgf_mask(output + hlen + 1, olen - hlen - 1, output + 1, hlen, + (mbedtls_md_type_t) ctx->hash_id)) != 0) { + return ret; + } + + /* maskedSeed: Apply seedMask to seed */ + if ((ret = mgf_mask(output + 1, hlen, output + hlen + 1, olen - hlen - 1, + (mbedtls_md_type_t) ctx->hash_id)) != 0) { + return ret; + } + + return mbedtls_rsa_public(ctx, output, output); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-ENCRYPT function + */ +int mbedtls_rsa_rsaes_pkcs1_v15_encrypt(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, size_t ilen, + const unsigned char *input, + unsigned char *output) +{ + size_t nb_pad, olen; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char *p = output; + + olen = ctx->len; + + /* first comparison checks for overflow */ + if (ilen + 11 < ilen || olen < ilen + 11) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + nb_pad = olen - 3 - ilen; + + *p++ = 0; + + if (f_rng == NULL) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + *p++ = MBEDTLS_RSA_CRYPT; + + while (nb_pad-- > 0) { + int rng_dl = 100; + + do { + ret = f_rng(p_rng, p, 1); + } while (*p == 0 && --rng_dl && ret == 0); + + /* Check if RNG failed to generate data */ + if (rng_dl == 0 || ret != 0) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_RSA_RNG_FAILED, ret); + } + + p++; + } + + *p++ = 0; + if (ilen != 0) { + memcpy(p, input, ilen); + } + + return mbedtls_rsa_public(ctx, output, output); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Add the message padding, then do an RSA operation + */ +int mbedtls_rsa_pkcs1_encrypt(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + size_t ilen, + const unsigned char *input, + unsigned char *output) +{ + switch (ctx->padding) { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsaes_pkcs1_v15_encrypt(ctx, f_rng, p_rng, + ilen, input, output); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsaes_oaep_encrypt(ctx, f_rng, p_rng, NULL, 0, + ilen, input, output); +#endif + + default: + return MBEDTLS_ERR_RSA_INVALID_PADDING; + } +} + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSAES-OAEP-DECRYPT function + */ +int mbedtls_rsa_rsaes_oaep_decrypt(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *label, size_t label_len, + size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t ilen, i, pad_len; + unsigned char *p; + mbedtls_ct_condition_t bad, in_padding; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + unsigned char lhash[MBEDTLS_MD_MAX_SIZE]; + unsigned int hlen; + + /* + * Parameters sanity checks + */ + if (ctx->padding != MBEDTLS_RSA_PKCS_V21) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + ilen = ctx->len; + + if (ilen < 16 || ilen > sizeof(buf)) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + hlen = mbedtls_md_get_size_from_type((mbedtls_md_type_t) ctx->hash_id); + if (hlen == 0) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + // checking for integer underflow + if (2 * hlen + 2 > ilen) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + /* + * RSA operation + */ + ret = mbedtls_rsa_private(ctx, f_rng, p_rng, input, buf); + + if (ret != 0) { + goto cleanup; + } + + /* + * Unmask data and generate lHash + */ + /* seed: Apply seedMask to maskedSeed */ + if ((ret = mgf_mask(buf + 1, hlen, buf + hlen + 1, ilen - hlen - 1, + (mbedtls_md_type_t) ctx->hash_id)) != 0 || + /* DB: Apply dbMask to maskedDB */ + (ret = mgf_mask(buf + hlen + 1, ilen - hlen - 1, buf + 1, hlen, + (mbedtls_md_type_t) ctx->hash_id)) != 0) { + goto cleanup; + } + + /* Generate lHash */ + ret = compute_hash((mbedtls_md_type_t) ctx->hash_id, + label, label_len, lhash); + if (ret != 0) { + goto cleanup; + } + + /* + * Check contents, in "constant-time" + */ + p = buf; + + bad = mbedtls_ct_bool(*p++); /* First byte must be 0 */ + + p += hlen; /* Skip seed */ + + /* Check lHash */ + bad = mbedtls_ct_bool_or(bad, mbedtls_ct_bool(mbedtls_ct_memcmp(lhash, p, hlen))); + p += hlen; + + /* Get zero-padding len, but always read till end of buffer + * (minus one, for the 01 byte) */ + pad_len = 0; + in_padding = MBEDTLS_CT_TRUE; + for (i = 0; i < ilen - 2 * hlen - 2; i++) { + in_padding = mbedtls_ct_bool_and(in_padding, mbedtls_ct_uint_eq(p[i], 0)); + pad_len += mbedtls_ct_uint_if_else_0(in_padding, 1); + } + + p += pad_len; + bad = mbedtls_ct_bool_or(bad, mbedtls_ct_uint_ne(*p++, 0x01)); + + /* + * The only information "leaked" is whether the padding was correct or not + * (eg, no data is copied if it was not correct). This meets the + * recommendations in PKCS#1 v2.2: an opponent cannot distinguish between + * the different error conditions. + */ + if (bad != MBEDTLS_CT_FALSE) { + ret = MBEDTLS_ERR_RSA_INVALID_PADDING; + goto cleanup; + } + + if (ilen - ((size_t) (p - buf)) > output_max_len) { + ret = MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE; + goto cleanup; + } + + *olen = ilen - ((size_t) (p - buf)); + if (*olen != 0) { + memcpy(output, p, *olen); + } + ret = 0; + +cleanup: + mbedtls_platform_zeroize(buf, sizeof(buf)); + mbedtls_platform_zeroize(lhash, sizeof(lhash)); + + return ret; +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function + */ +int mbedtls_rsa_rsaes_pkcs1_v15_decrypt(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t ilen; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + + ilen = ctx->len; + + if (ctx->padding != MBEDTLS_RSA_PKCS_V15) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + if (ilen < 16 || ilen > sizeof(buf)) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + ret = mbedtls_rsa_private(ctx, f_rng, p_rng, input, buf); + + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_ct_rsaes_pkcs1_v15_unpadding(buf, ilen, + output, output_max_len, olen); + +cleanup: + mbedtls_platform_zeroize(buf, sizeof(buf)); + + return ret; +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Do an RSA operation, then remove the message padding + */ +int mbedtls_rsa_pkcs1_decrypt(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len) +{ + switch (ctx->padding) { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsaes_pkcs1_v15_decrypt(ctx, f_rng, p_rng, olen, + input, output, output_max_len); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsaes_oaep_decrypt(ctx, f_rng, p_rng, NULL, 0, + olen, input, output, + output_max_len); +#endif + + default: + return MBEDTLS_ERR_RSA_INVALID_PADDING; + } +} + +#if defined(MBEDTLS_PKCS1_V21) +static int rsa_rsassa_pss_sign_no_mode_check(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + int saltlen, + unsigned char *sig) +{ + size_t olen; + unsigned char *p = sig; + unsigned char *salt = NULL; + size_t slen, min_slen, hlen, offset = 0; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t msb; + mbedtls_md_type_t hash_id; + + if ((md_alg != MBEDTLS_MD_NONE || hashlen != 0) && hash == NULL) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + if (f_rng == NULL) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + olen = ctx->len; + + if (md_alg != MBEDTLS_MD_NONE) { + /* Gather length of hash to sign */ + size_t exp_hashlen = mbedtls_md_get_size_from_type(md_alg); + if (exp_hashlen == 0) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + if (hashlen != exp_hashlen) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + } + + hash_id = (mbedtls_md_type_t) ctx->hash_id; + if (hash_id == MBEDTLS_MD_NONE) { + hash_id = md_alg; + } + hlen = mbedtls_md_get_size_from_type(hash_id); + if (hlen == 0) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + if (saltlen == MBEDTLS_RSA_SALT_LEN_ANY) { + /* Calculate the largest possible salt length, up to the hash size. + * Normally this is the hash length, which is the maximum salt length + * according to FIPS 185-4 §5.5 (e) and common practice. If there is not + * enough room, use the maximum salt length that fits. The constraint is + * that the hash length plus the salt length plus 2 bytes must be at most + * the key length. This complies with FIPS 186-4 §5.5 (e) and RFC 8017 + * (PKCS#1 v2.2) §9.1.1 step 3. */ + min_slen = hlen - 2; + if (olen < hlen + min_slen + 2) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } else if (olen >= hlen + hlen + 2) { + slen = hlen; + } else { + slen = olen - hlen - 2; + } + } else if ((saltlen < 0) || (saltlen + hlen + 2 > olen)) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } else { + slen = (size_t) saltlen; + } + + memset(sig, 0, olen); + + /* Note: EMSA-PSS encoding is over the length of N - 1 bits */ + msb = mbedtls_mpi_bitlen(&ctx->N) - 1; + p += olen - hlen - slen - 2; + *p++ = 0x01; + + /* Generate salt of length slen in place in the encoded message */ + salt = p; + if ((ret = f_rng(p_rng, salt, slen)) != 0) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_RSA_RNG_FAILED, ret); + } + + p += slen; + + /* Generate H = Hash( M' ) */ + ret = hash_mprime(hash, hashlen, salt, slen, p, hash_id); + if (ret != 0) { + return ret; + } + + /* Compensate for boundary condition when applying mask */ + if (msb % 8 == 0) { + offset = 1; + } + + /* maskedDB: Apply dbMask to DB */ + ret = mgf_mask(sig + offset, olen - hlen - 1 - offset, p, hlen, hash_id); + if (ret != 0) { + return ret; + } + + msb = mbedtls_mpi_bitlen(&ctx->N) - 1; + sig[0] &= 0xFF >> (olen * 8 - msb); + + p += hlen; + *p++ = 0xBC; + + return mbedtls_rsa_private(ctx, f_rng, p_rng, sig, sig); +} + +static int rsa_rsassa_pss_sign(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + int saltlen, + unsigned char *sig) +{ + if (ctx->padding != MBEDTLS_RSA_PKCS_V21) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + if ((ctx->hash_id == MBEDTLS_MD_NONE) && (md_alg == MBEDTLS_MD_NONE)) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + return rsa_rsassa_pss_sign_no_mode_check(ctx, f_rng, p_rng, md_alg, hashlen, hash, saltlen, + sig); +} + +int mbedtls_rsa_rsassa_pss_sign_no_mode_check(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig) +{ + return rsa_rsassa_pss_sign_no_mode_check(ctx, f_rng, p_rng, md_alg, + hashlen, hash, MBEDTLS_RSA_SALT_LEN_ANY, sig); +} + +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PSS-SIGN function with + * the option to pass in the salt length. + */ +int mbedtls_rsa_rsassa_pss_sign_ext(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + int saltlen, + unsigned char *sig) +{ + return rsa_rsassa_pss_sign(ctx, f_rng, p_rng, md_alg, + hashlen, hash, saltlen, sig); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-V1_5-SIGN function + */ + +/* Construct a PKCS v1.5 encoding of a hashed message + * + * This is used both for signature generation and verification. + * + * Parameters: + * - md_alg: Identifies the hash algorithm used to generate the given hash; + * MBEDTLS_MD_NONE if raw data is signed. + * - hashlen: Length of hash. Must match md_alg if that's not NONE. + * - hash: Buffer containing the hashed message or the raw data. + * - dst_len: Length of the encoded message. + * - dst: Buffer to hold the encoded message. + * + * Assumptions: + * - hash has size hashlen. + * - dst points to a buffer of size at least dst_len. + * + */ +static int rsa_rsassa_pkcs1_v15_encode(mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + size_t dst_len, + unsigned char *dst) +{ + size_t oid_size = 0; + size_t nb_pad = dst_len; + unsigned char *p = dst; + const char *oid = NULL; + + /* Are we signing hashed or raw data? */ + if (md_alg != MBEDTLS_MD_NONE) { + unsigned char md_size = mbedtls_md_get_size_from_type(md_alg); + if (md_size == 0) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + if (mbedtls_oid_get_oid_by_md(md_alg, &oid, &oid_size) != 0) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + if (hashlen != md_size) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + /* Double-check that 8 + hashlen + oid_size can be used as a + * 1-byte ASN.1 length encoding and that there's no overflow. */ + if (8 + hashlen + oid_size >= 0x80 || + 10 + hashlen < hashlen || + 10 + hashlen + oid_size < 10 + hashlen) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + /* + * Static bounds check: + * - Need 10 bytes for five tag-length pairs. + * (Insist on 1-byte length encodings to protect against variants of + * Bleichenbacher's forgery attack against lax PKCS#1v1.5 verification) + * - Need hashlen bytes for hash + * - Need oid_size bytes for hash alg OID. + */ + if (nb_pad < 10 + hashlen + oid_size) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + nb_pad -= 10 + hashlen + oid_size; + } else { + if (nb_pad < hashlen) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + nb_pad -= hashlen; + } + + /* Need space for signature header and padding delimiter (3 bytes), + * and 8 bytes for the minimal padding */ + if (nb_pad < 3 + 8) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + nb_pad -= 3; + + /* Now nb_pad is the amount of memory to be filled + * with padding, and at least 8 bytes long. */ + + /* Write signature header and padding */ + *p++ = 0; + *p++ = MBEDTLS_RSA_SIGN; + memset(p, 0xFF, nb_pad); + p += nb_pad; + *p++ = 0; + + /* Are we signing raw data? */ + if (md_alg == MBEDTLS_MD_NONE) { + memcpy(p, hash, hashlen); + return 0; + } + + /* Signing hashed data, add corresponding ASN.1 structure + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest } + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * Digest ::= OCTET STRING + * + * Schematic: + * TAG-SEQ + LEN [ TAG-SEQ + LEN [ TAG-OID + LEN [ OID ] + * TAG-NULL + LEN [ NULL ] ] + * TAG-OCTET + LEN [ HASH ] ] + */ + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char) (0x08 + oid_size + hashlen); + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char) (0x04 + oid_size); + *p++ = MBEDTLS_ASN1_OID; + *p++ = (unsigned char) oid_size; + memcpy(p, oid, oid_size); + p += oid_size; + *p++ = MBEDTLS_ASN1_NULL; + *p++ = 0x00; + *p++ = MBEDTLS_ASN1_OCTET_STRING; + *p++ = (unsigned char) hashlen; + memcpy(p, hash, hashlen); + p += hashlen; + + /* Just a sanity-check, should be automatic + * after the initial bounds check. */ + if (p != dst + dst_len) { + mbedtls_platform_zeroize(dst, dst_len); + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + return 0; +} + +/* + * Do an RSA operation to sign the message digest + */ +int mbedtls_rsa_rsassa_pkcs1_v15_sign(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned char *sig_try = NULL, *verif = NULL; + + if ((md_alg != MBEDTLS_MD_NONE || hashlen != 0) && hash == NULL) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + if (ctx->padding != MBEDTLS_RSA_PKCS_V15) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + /* + * Prepare PKCS1-v1.5 encoding (padding and hash identifier) + */ + + if ((ret = rsa_rsassa_pkcs1_v15_encode(md_alg, hashlen, hash, + ctx->len, sig)) != 0) { + return ret; + } + + /* Private key operation + * + * In order to prevent Lenstra's attack, make the signature in a + * temporary buffer and check it before returning it. + */ + + sig_try = mbedtls_calloc(1, ctx->len); + if (sig_try == NULL) { + return MBEDTLS_ERR_MPI_ALLOC_FAILED; + } + + verif = mbedtls_calloc(1, ctx->len); + if (verif == NULL) { + mbedtls_free(sig_try); + return MBEDTLS_ERR_MPI_ALLOC_FAILED; + } + + MBEDTLS_MPI_CHK(mbedtls_rsa_private(ctx, f_rng, p_rng, sig, sig_try)); + MBEDTLS_MPI_CHK(mbedtls_rsa_public(ctx, sig_try, verif)); + + if (mbedtls_ct_memcmp(verif, sig, ctx->len) != 0) { + ret = MBEDTLS_ERR_RSA_PRIVATE_FAILED; + goto cleanup; + } + + memcpy(sig, sig_try, ctx->len); + +cleanup: + mbedtls_zeroize_and_free(sig_try, ctx->len); + mbedtls_zeroize_and_free(verif, ctx->len); + + if (ret != 0) { + memset(sig, '!', ctx->len); + } + return ret; +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Do an RSA operation to sign the message digest + */ +int mbedtls_rsa_pkcs1_sign(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig) +{ + if ((md_alg != MBEDTLS_MD_NONE || hashlen != 0) && hash == NULL) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + switch (ctx->padding) { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsassa_pkcs1_v15_sign(ctx, f_rng, p_rng, + md_alg, hashlen, hash, sig); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsassa_pss_sign_ext(ctx, f_rng, p_rng, md_alg, + hashlen, hash, MBEDTLS_RSA_SALT_LEN_ANY, sig); +#endif + + default: + return MBEDTLS_ERR_RSA_INVALID_PADDING; + } +} + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PSS-VERIFY function + */ +int mbedtls_rsa_rsassa_pss_verify_ext(mbedtls_rsa_context *ctx, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + mbedtls_md_type_t mgf1_hash_id, + int expected_salt_len, + const unsigned char *sig) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t siglen; + unsigned char *p; + unsigned char *hash_start; + unsigned char result[MBEDTLS_MD_MAX_SIZE]; + unsigned int hlen; + size_t observed_salt_len, msb; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE] = { 0 }; + + if ((md_alg != MBEDTLS_MD_NONE || hashlen != 0) && hash == NULL) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + siglen = ctx->len; + + if (siglen < 16 || siglen > sizeof(buf)) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + ret = mbedtls_rsa_public(ctx, sig, buf); + + if (ret != 0) { + return ret; + } + + p = buf; + + if (buf[siglen - 1] != 0xBC) { + return MBEDTLS_ERR_RSA_INVALID_PADDING; + } + + if (md_alg != MBEDTLS_MD_NONE) { + /* Gather length of hash to sign */ + size_t exp_hashlen = mbedtls_md_get_size_from_type(md_alg); + if (exp_hashlen == 0) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + if (hashlen != exp_hashlen) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + } + + hlen = mbedtls_md_get_size_from_type(mgf1_hash_id); + if (hlen == 0) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + /* + * Note: EMSA-PSS verification is over the length of N - 1 bits + */ + msb = mbedtls_mpi_bitlen(&ctx->N) - 1; + + if (buf[0] >> (8 - siglen * 8 + msb)) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + /* Compensate for boundary condition when applying mask */ + if (msb % 8 == 0) { + p++; + siglen -= 1; + } + + if (siglen < hlen + 2) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + hash_start = p + siglen - hlen - 1; + + ret = mgf_mask(p, siglen - hlen - 1, hash_start, hlen, mgf1_hash_id); + if (ret != 0) { + return ret; + } + + buf[0] &= 0xFF >> (siglen * 8 - msb); + + while (p < hash_start - 1 && *p == 0) { + p++; + } + + if (*p++ != 0x01) { + return MBEDTLS_ERR_RSA_INVALID_PADDING; + } + + observed_salt_len = (size_t) (hash_start - p); + + if (expected_salt_len != MBEDTLS_RSA_SALT_LEN_ANY && + observed_salt_len != (size_t) expected_salt_len) { + return MBEDTLS_ERR_RSA_INVALID_PADDING; + } + + /* + * Generate H = Hash( M' ) + */ + ret = hash_mprime(hash, hashlen, p, observed_salt_len, + result, mgf1_hash_id); + if (ret != 0) { + return ret; + } + + if (memcmp(hash_start, result, hlen) != 0) { + return MBEDTLS_ERR_RSA_VERIFY_FAILED; + } + + return 0; +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-v1_5-VERIFY function + */ +int mbedtls_rsa_rsassa_pkcs1_v15_verify(mbedtls_rsa_context *ctx, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig) +{ + int ret = 0; + size_t sig_len; + unsigned char *encoded = NULL, *encoded_expected = NULL; + + if ((md_alg != MBEDTLS_MD_NONE || hashlen != 0) && hash == NULL) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + + sig_len = ctx->len; + + /* + * Prepare expected PKCS1 v1.5 encoding of hash. + */ + + if ((encoded = mbedtls_calloc(1, sig_len)) == NULL || + (encoded_expected = mbedtls_calloc(1, sig_len)) == NULL) { + ret = MBEDTLS_ERR_MPI_ALLOC_FAILED; + goto cleanup; + } + + if ((ret = rsa_rsassa_pkcs1_v15_encode(md_alg, hashlen, hash, sig_len, + encoded_expected)) != 0) { + goto cleanup; + } + + /* + * Apply RSA primitive to get what should be PKCS1 encoded hash. + */ + + ret = mbedtls_rsa_public(ctx, sig, encoded); + if (ret != 0) { + goto cleanup; + } + + /* + * Compare + */ + + if ((ret = mbedtls_ct_memcmp(encoded, encoded_expected, + sig_len)) != 0) { + ret = MBEDTLS_ERR_RSA_VERIFY_FAILED; + goto cleanup; + } + +cleanup: + + if (encoded != NULL) { + mbedtls_zeroize_and_free(encoded, sig_len); + } + + if (encoded_expected != NULL) { + mbedtls_zeroize_and_free(encoded_expected, sig_len); + } + + return ret; +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Do an RSA operation and check the message digest + */ +int mbedtls_rsa_pkcs1_verify(mbedtls_rsa_context *ctx, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig) +{ + if ((md_alg != MBEDTLS_MD_NONE || hashlen != 0) && hash == NULL) { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } + +#if defined(MBEDTLS_PKCS1_V21) + mbedtls_md_type_t mgf1_hash_id; +#endif + + switch (ctx->padding) { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsassa_pkcs1_v15_verify(ctx, md_alg, + hashlen, hash, sig); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + mgf1_hash_id = (ctx->hash_id != MBEDTLS_MD_NONE) + ? (mbedtls_md_type_t) ctx->hash_id + : md_alg; + return mbedtls_rsa_rsassa_pss_verify_ext(ctx, md_alg, + hashlen, hash, mgf1_hash_id, + MBEDTLS_RSA_SALT_LEN_ANY, + sig); +#endif + + default: + return MBEDTLS_ERR_RSA_INVALID_PADDING; + } +} + +/* + * Copy the components of an RSA key + */ +int mbedtls_rsa_copy(mbedtls_rsa_context *dst, const mbedtls_rsa_context *src) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + dst->len = src->len; + + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->N, &src->N)); + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->E, &src->E)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->D, &src->D)); + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->P, &src->P)); + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->Q, &src->Q)); + +#if !defined(MBEDTLS_RSA_NO_CRT) + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->DP, &src->DP)); + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->DQ, &src->DQ)); + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->QP, &src->QP)); + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->RP, &src->RP)); + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->RQ, &src->RQ)); +#endif + + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->RN, &src->RN)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->Vi, &src->Vi)); + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->Vf, &src->Vf)); + + dst->padding = src->padding; + dst->hash_id = src->hash_id; + +cleanup: + if (ret != 0) { + mbedtls_rsa_free(dst); + } + + return ret; +} + +/* + * Free the components of an RSA key + */ +void mbedtls_rsa_free(mbedtls_rsa_context *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_mpi_free(&ctx->Vi); + mbedtls_mpi_free(&ctx->Vf); + mbedtls_mpi_free(&ctx->RN); + mbedtls_mpi_free(&ctx->D); + mbedtls_mpi_free(&ctx->Q); + mbedtls_mpi_free(&ctx->P); + mbedtls_mpi_free(&ctx->E); + mbedtls_mpi_free(&ctx->N); + +#if !defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_free(&ctx->RQ); + mbedtls_mpi_free(&ctx->RP); + mbedtls_mpi_free(&ctx->QP); + mbedtls_mpi_free(&ctx->DQ); + mbedtls_mpi_free(&ctx->DP); +#endif /* MBEDTLS_RSA_NO_CRT */ +} + +#if defined(MBEDTLS_SELF_TEST) + + +/* + * Example RSA-1024 keypair, for test purposes + */ +#define KEY_LEN 128 + +#define RSA_N "9292758453063D803DD603D5E777D788" \ + "8ED1D5BF35786190FA2F23EBC0848AEA" \ + "DDA92CA6C3D80B32C4D109BE0F36D6AE" \ + "7130B9CED7ACDF54CFC7555AC14EEBAB" \ + "93A89813FBF3C4F8066D2D800F7C38A8" \ + "1AE31942917403FF4946B0A83D3D3E05" \ + "EE57C6F5F5606FB5D4BC6CD34EE0801A" \ + "5E94BB77B07507233A0BC7BAC8F90F79" + +#define RSA_E "10001" + +#define RSA_D "24BF6185468786FDD303083D25E64EFC" \ + "66CA472BC44D253102F8B4A9D3BFA750" \ + "91386C0077937FE33FA3252D28855837" \ + "AE1B484A8A9A45F7EE8C0C634F99E8CD" \ + "DF79C5CE07EE72C7F123142198164234" \ + "CABB724CF78B8173B9F880FC86322407" \ + "AF1FEDFDDE2BEB674CA15F3E81A1521E" \ + "071513A1E85B5DFA031F21ECAE91A34D" + +#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \ + "2C01CAD19EA484A87EA4377637E75500" \ + "FCB2005C5C7DD6EC4AC023CDA285D796" \ + "C3D9E75E1EFC42488BB4F1D13AC30A57" + +#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \ + "E211C2B9E5DB1ED0BF61D0D9899620F4" \ + "910E4168387E3C30AA1E00C339A79508" \ + "8452DD96A9A5EA5D9DCA68DA636032AF" + +#define PT_LEN 24 +#define RSA_PT "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \ + "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD" + +#if defined(MBEDTLS_PKCS1_V15) +static int myrand(void *rng_state, unsigned char *output, size_t len) +{ +#if !defined(__OpenBSD__) && !defined(__NetBSD__) + size_t i; + + if (rng_state != NULL) { + rng_state = NULL; + } + + for (i = 0; i < len; ++i) { + output[i] = rand(); + } +#else + if (rng_state != NULL) { + rng_state = NULL; + } + + arc4random_buf(output, len); +#endif /* !OpenBSD && !NetBSD */ + + return 0; +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Checkup routine + */ +int mbedtls_rsa_self_test(int verbose) +{ + int ret = 0; +#if defined(MBEDTLS_PKCS1_V15) + size_t len; + mbedtls_rsa_context rsa; + unsigned char rsa_plaintext[PT_LEN]; + unsigned char rsa_decrypted[PT_LEN]; + unsigned char rsa_ciphertext[KEY_LEN]; +#if defined(PSA_WANT_ALG_SHA_1) + unsigned char sha1sum[20]; +#endif + + mbedtls_mpi K; + + mbedtls_mpi_init(&K); + mbedtls_rsa_init(&rsa); + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&rsa.N, 16, RSA_N)); + MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&rsa.P, 16, RSA_P)); + MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&rsa.Q, 16, RSA_Q)); + MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&rsa.D, 16, RSA_D)); + MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&rsa.E, 16, RSA_E)); + rsa.len = mbedtls_mpi_size(&rsa.N); + +#if !defined(MBEDTLS_RSA_NO_CRT) + MBEDTLS_MPI_CHK(mbedtls_rsa_deduce_crt(&rsa.P, &rsa.Q, &rsa.D, &rsa.DP, &rsa.DQ, &rsa.QP)); +#endif /* !MBEDTLS_RSA_NO_CRT */ + + if (verbose != 0) { + mbedtls_printf(" RSA key validation: "); + } + + if (mbedtls_rsa_check_pubkey(&rsa) != 0 || + mbedtls_rsa_check_privkey(&rsa) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + ret = 1; + goto cleanup; + } + + if (verbose != 0) { + mbedtls_printf("passed\n PKCS#1 encryption : "); + } + + memcpy(rsa_plaintext, RSA_PT, PT_LEN); + + if (mbedtls_rsa_pkcs1_encrypt(&rsa, myrand, NULL, + PT_LEN, rsa_plaintext, + rsa_ciphertext) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + ret = 1; + goto cleanup; + } + + if (verbose != 0) { + mbedtls_printf("passed\n PKCS#1 decryption : "); + } + + if (mbedtls_rsa_pkcs1_decrypt(&rsa, myrand, NULL, + &len, rsa_ciphertext, rsa_decrypted, + sizeof(rsa_decrypted)) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + ret = 1; + goto cleanup; + } + + if (memcmp(rsa_decrypted, rsa_plaintext, len) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + ret = 1; + goto cleanup; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + +#if defined(PSA_WANT_ALG_SHA_1) + if (verbose != 0) { + mbedtls_printf(" PKCS#1 data sign : "); + } + + if (mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), + rsa_plaintext, PT_LEN, sha1sum) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + return 1; + } + + if (mbedtls_rsa_pkcs1_sign(&rsa, myrand, NULL, + MBEDTLS_MD_SHA1, 20, + sha1sum, rsa_ciphertext) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + ret = 1; + goto cleanup; + } + + if (verbose != 0) { + mbedtls_printf("passed\n PKCS#1 sig. verify: "); + } + + if (mbedtls_rsa_pkcs1_verify(&rsa, MBEDTLS_MD_SHA1, 20, + sha1sum, rsa_ciphertext) != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + + ret = 1; + goto cleanup; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } +#endif /* PSA_WANT_ALG_SHA_1 */ + + if (verbose != 0) { + mbedtls_printf("\n"); + } + +cleanup: + mbedtls_mpi_free(&K); + mbedtls_rsa_free(&rsa); +#else /* MBEDTLS_PKCS1_V15 */ + ((void) verbose); +#endif /* MBEDTLS_PKCS1_V15 */ + return ret; +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_RSA_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/rsa_alt_helpers.c b/tf-psa-crypto/drivers/builtin/src/rsa_alt_helpers.c new file mode 100644 index 0000000000..d2b68d13ed --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/rsa_alt_helpers.c @@ -0,0 +1,294 @@ +/* + * Helper functions for the RSA module + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + * + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_RSA_C) + +#include "mbedtls/private/rsa.h" +#include "mbedtls/private/bignum.h" +#include "bignum_internal.h" +#include "rsa_alt_helpers.h" + +/* + * Given P, Q and the public exponent E, deduce D. + * This is essentially a modular inversion. + */ +int mbedtls_rsa_deduce_private_exponent(mbedtls_mpi const *P, + mbedtls_mpi const *Q, + mbedtls_mpi const *E, + mbedtls_mpi *D) +{ + int ret = 0; + mbedtls_mpi K, L; + + if (D == NULL) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + if (mbedtls_mpi_cmp_int(P, 1) <= 0 || + mbedtls_mpi_cmp_int(Q, 1) <= 0 || + mbedtls_mpi_cmp_int(E, 0) == 0) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + if (mbedtls_mpi_get_bit(E, 0) != 1) { + return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + } + + mbedtls_mpi_init(&K); + mbedtls_mpi_init(&L); + + /* Temporarily put K := P-1 and L := Q-1 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&K, P, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&L, Q, 1)); + + /* Temporarily put D := gcd(P-1, Q-1) */ + MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(D, &K, &L)); + + /* K := LCM(P-1, Q-1) */ + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&K, &K, &L)); + MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(&K, NULL, &K, D)); + + /* Compute modular inverse of E mod LCM(P-1, Q-1) + * This is FIPS 186-4 §B.3.1 criterion 3(b). + * This will return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if E is not coprime to + * (P-1)(Q-1), also validating FIPS 186-4 §B.3.1 criterion 2(a). */ + MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod_even_in_range(D, E, &K)); + +cleanup: + + mbedtls_mpi_free(&K); + mbedtls_mpi_free(&L); + + return ret; +} + +int mbedtls_rsa_deduce_crt(const mbedtls_mpi *P, const mbedtls_mpi *Q, + const mbedtls_mpi *D, mbedtls_mpi *DP, + mbedtls_mpi *DQ, mbedtls_mpi *QP) +{ + int ret = 0; + mbedtls_mpi K; + mbedtls_mpi_init(&K); + + /* DP = D mod P-1 */ + if (DP != NULL) { + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&K, P, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(DP, D, &K)); + } + + /* DQ = D mod Q-1 */ + if (DQ != NULL) { + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&K, Q, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(DQ, D, &K)); + } + + /* QP = Q^{-1} mod P */ + if (QP != NULL) { + MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod_odd(QP, Q, P)); + } + +cleanup: + mbedtls_mpi_free(&K); + + return ret; +} + +/* + * Check that core RSA parameters are sane. + */ +int mbedtls_rsa_validate_params(const mbedtls_mpi *N, const mbedtls_mpi *P, + const mbedtls_mpi *Q, const mbedtls_mpi *D, + const mbedtls_mpi *E, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng) +{ + int ret = 0; + mbedtls_mpi K, L; + + mbedtls_mpi_init(&K); + mbedtls_mpi_init(&L); + + /* + * Step 1: If PRNG provided, check that P and Q are prime + */ + +#if defined(MBEDTLS_GENPRIME) + /* + * When generating keys, the strongest security we support aims for an error + * rate of at most 2^-100 and we are aiming for the same certainty here as + * well. + */ + if (f_rng != NULL && P != NULL && + (ret = mbedtls_mpi_is_prime_ext(P, 50, f_rng, p_rng)) != 0) { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + + if (f_rng != NULL && Q != NULL && + (ret = mbedtls_mpi_is_prime_ext(Q, 50, f_rng, p_rng)) != 0) { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } +#else + ((void) f_rng); + ((void) p_rng); +#endif /* MBEDTLS_GENPRIME */ + + /* + * Step 2: Check that 1 < N = P * Q + */ + + if (P != NULL && Q != NULL && N != NULL) { + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&K, P, Q)); + if (mbedtls_mpi_cmp_int(N, 1) <= 0 || + mbedtls_mpi_cmp_mpi(&K, N) != 0) { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + + /* + * Step 3: Check and 1 < D, E < N if present. + */ + + if (N != NULL && D != NULL && E != NULL) { + if (mbedtls_mpi_cmp_int(D, 1) <= 0 || + mbedtls_mpi_cmp_int(E, 1) <= 0 || + mbedtls_mpi_cmp_mpi(D, N) >= 0 || + mbedtls_mpi_cmp_mpi(E, N) >= 0) { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + + /* + * Step 4: Check that D, E are inverse modulo P-1 and Q-1 + */ + + if (P != NULL && Q != NULL && D != NULL && E != NULL) { + if (mbedtls_mpi_cmp_int(P, 1) <= 0 || + mbedtls_mpi_cmp_int(Q, 1) <= 0) { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + + /* Compute DE-1 mod P-1 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&K, D, E)); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&K, &K, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&L, P, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&K, &K, &L)); + if (mbedtls_mpi_cmp_int(&K, 0) != 0) { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + + /* Compute DE-1 mod Q-1 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&K, D, E)); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&K, &K, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&L, Q, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&K, &K, &L)); + if (mbedtls_mpi_cmp_int(&K, 0) != 0) { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + +cleanup: + + mbedtls_mpi_free(&K); + mbedtls_mpi_free(&L); + + /* Wrap MPI error codes by RSA check failure error code */ + if (ret != 0 && ret != MBEDTLS_ERR_RSA_KEY_CHECK_FAILED) { + ret += MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + } + + return ret; +} + +/* + * Check that RSA CRT parameters are in accordance with core parameters. + */ +int mbedtls_rsa_validate_crt(const mbedtls_mpi *P, const mbedtls_mpi *Q, + const mbedtls_mpi *D, const mbedtls_mpi *DP, + const mbedtls_mpi *DQ, const mbedtls_mpi *QP) +{ + int ret = 0; + + mbedtls_mpi K, L; + mbedtls_mpi_init(&K); + mbedtls_mpi_init(&L); + + /* Check that DP - D == 0 mod P - 1 */ + if (DP != NULL) { + if (P == NULL) { + ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&K, P, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&L, DP, D)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&L, &L, &K)); + + if (mbedtls_mpi_cmp_int(&L, 0) != 0) { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + + /* Check that DQ - D == 0 mod Q - 1 */ + if (DQ != NULL) { + if (Q == NULL) { + ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&K, Q, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&L, DQ, D)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&L, &L, &K)); + + if (mbedtls_mpi_cmp_int(&L, 0) != 0) { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + + /* Check that QP * Q - 1 == 0 mod P */ + if (QP != NULL) { + if (P == NULL || Q == NULL) { + ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&K, QP, Q)); + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&K, &K, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&K, &K, P)); + if (mbedtls_mpi_cmp_int(&K, 0) != 0) { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + +cleanup: + + /* Wrap MPI error codes by RSA check failure error code */ + if (ret != 0 && + ret != MBEDTLS_ERR_RSA_KEY_CHECK_FAILED && + ret != MBEDTLS_ERR_RSA_BAD_INPUT_DATA) { + ret += MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + } + + mbedtls_mpi_free(&K); + mbedtls_mpi_free(&L); + + return ret; +} + +#endif /* MBEDTLS_RSA_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/rsa_alt_helpers.h b/tf-psa-crypto/drivers/builtin/src/rsa_alt_helpers.h new file mode 100644 index 0000000000..8366d343ac --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/rsa_alt_helpers.h @@ -0,0 +1,185 @@ +/** + * \file rsa_alt_helpers.h + * + * \brief Context-independent RSA helper functions + * + * Please note: The below explanation is historical and is no longer relevant + * due to there being no compelling reason to keep these functions separate + * since the RSA alt interface was removed. A future refactoring will address + * this which is tracked by the following issue: + * https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/105. + * + * This module declares some RSA-related helper functions useful when + * implementing the RSA interface. These functions are provided in a separate + * compilation unit in order to make it easy for designers of alternative RSA + * implementations to use them in their own code, as it is conceived that the + * functionality they provide will be necessary for most complete + * implementations. + * + * End-users of Mbed TLS who are not providing their own alternative RSA + * implementations should not use these functions directly, and should instead + * use only the functions declared in rsa.h. + * + * The interface provided by this module will be maintained through LTS (Long + * Term Support) branches of Mbed TLS, but may otherwise be subject to change, + * and must be considered an internal interface of the library. + * + * There are two classes of helper functions: + * + * (1) Parameter-generating helpers. These are: + * - mbedtls_rsa_deduce_private_exponent + * - mbedtls_rsa_deduce_crt + * Each of these functions takes a set of core RSA parameters and + * generates some other, or CRT related parameters. + * + * (2) Parameter-checking helpers. These are: + * - mbedtls_rsa_validate_params + * - mbedtls_rsa_validate_crt + * They take a set of core or CRT related RSA parameters and check their + * validity. + * + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_RSA_ALT_HELPERS_H +#define TF_PSA_CRYPTO_RSA_ALT_HELPERS_H + +#include "tf-psa-crypto/build_info.h" + +#include "mbedtls/private/bignum.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Compute RSA private exponent from + * prime moduli and public key. + * + * \note This is a 'static' helper function not operating on + * an RSA context. Alternative implementations need not + * overwrite it. + * + * \param P First prime factor of RSA modulus + * \param Q Second prime factor of RSA modulus + * \param E RSA public exponent + * \param D Pointer to MPI holding the private exponent on success, + * i.e. the modular inverse of E modulo LCM(P-1,Q-1). + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if E is not coprime to P-1 + * and Q-1, that is, if GCD( E, (P-1)*(Q-1) ) != 1. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if inputs are otherwise + * invalid. + * + * \note This function does not check whether P and Q are primes. + * + */ +int mbedtls_rsa_deduce_private_exponent(mbedtls_mpi const *P, + mbedtls_mpi const *Q, + mbedtls_mpi const *E, + mbedtls_mpi *D); + + +/** + * \brief Generate RSA-CRT parameters + * + * \note This is a 'static' helper function not operating on + * an RSA context. Alternative implementations need not + * overwrite it. + * + * \param P First prime factor of N + * \param Q Second prime factor of N + * \param D RSA private exponent + * \param DP Output variable for D modulo P-1 + * \param DQ Output variable for D modulo Q-1 + * \param QP Output variable for the modular inverse of Q modulo P. + * + * \return 0 on success, non-zero error code otherwise. + * + * \note This function does not check whether P, Q are + * prime and whether D is a valid private exponent. + * + */ +int mbedtls_rsa_deduce_crt(const mbedtls_mpi *P, const mbedtls_mpi *Q, + const mbedtls_mpi *D, mbedtls_mpi *DP, + mbedtls_mpi *DQ, mbedtls_mpi *QP); + + +/** + * \brief Check validity of core RSA parameters + * + * \note This is a 'static' helper function not operating on + * an RSA context. Alternative implementations need not + * overwrite it. + * + * \param N RSA modulus N = PQ + * \param P First prime factor of N + * \param Q Second prime factor of N + * \param D RSA private exponent + * \param E RSA public exponent + * \param f_rng PRNG to be used for primality check, or NULL + * \param p_rng PRNG context for f_rng, or NULL + * + * \return + * - 0 if the following conditions are satisfied + * if all relevant parameters are provided: + * - P prime if f_rng != NULL (%) + * - Q prime if f_rng != NULL (%) + * - 1 < N = P * Q + * - 1 < D, E < N + * - D and E are modular inverses modulo P-1 and Q-1 + * (%) This is only done if MBEDTLS_GENPRIME is defined. + * - A non-zero error code otherwise. + * + * \note The function can be used with a restricted set of arguments + * to perform specific checks only. E.g., calling it with + * (-,P,-,-,-) and a PRNG amounts to a primality check for P. + */ +int mbedtls_rsa_validate_params(const mbedtls_mpi *N, const mbedtls_mpi *P, + const mbedtls_mpi *Q, const mbedtls_mpi *D, + const mbedtls_mpi *E, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng); + +/** + * \brief Check validity of RSA CRT parameters + * + * \note This is a 'static' helper function not operating on + * an RSA context. Alternative implementations need not + * overwrite it. + * + * \param P First prime factor of RSA modulus + * \param Q Second prime factor of RSA modulus + * \param D RSA private exponent + * \param DP MPI to check for D modulo P-1 + * \param DQ MPI to check for D modulo P-1 + * \param QP MPI to check for the modular inverse of Q modulo P. + * + * \return + * - 0 if the following conditions are satisfied: + * - D = DP mod P-1 if P, D, DP != NULL + * - Q = DQ mod P-1 if P, D, DQ != NULL + * - QP = Q^-1 mod P if P, Q, QP != NULL + * - \c MBEDTLS_ERR_RSA_KEY_CHECK_FAILED if check failed, + * potentially including \c MBEDTLS_ERR_MPI_XXX if some + * MPI calculations failed. + * - \c MBEDTLS_ERR_RSA_BAD_INPUT_DATA if insufficient + * data was provided to check DP, DQ or QP. + * + * \note The function can be used with a restricted set of arguments + * to perform specific checks only. E.g., calling it with the + * parameters (P, -, D, DP, -, -) will check DP = D mod P-1. + */ +int mbedtls_rsa_validate_crt(const mbedtls_mpi *P, const mbedtls_mpi *Q, + const mbedtls_mpi *D, const mbedtls_mpi *DP, + const mbedtls_mpi *DQ, const mbedtls_mpi *QP); + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_RSA_ALT_HELPERS_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/rsa_internal.h b/tf-psa-crypto/drivers/builtin/src/rsa_internal.h new file mode 100644 index 0000000000..174b1150df --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/rsa_internal.h @@ -0,0 +1,119 @@ +/** + * \file rsa_internal.h + * + * \brief Internal-only RSA public-key cryptosystem API. + * + * This file declares RSA-related functions that are to be used + * only from within the Mbed TLS library itself. + * + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_RSA_INTERNAL_H +#define TF_PSA_CRYPTO_RSA_INTERNAL_H + +#include "mbedtls/private/rsa.h" +#include "mbedtls/asn1.h" + +/** + * \brief Parse a PKCS#1 (ASN.1) encoded private RSA key. + * + * \param rsa The RSA context where parsed data will be stored. + * \param key The buffer that contains the key. + * \param keylen The length of the key buffer in bytes. + * + * \return 0 on success. + * \return MBEDTLS_ERR_ASN1_xxx in case of ASN.1 parsing errors. + * \return MBEDTLS_ERR_RSA_xxx in case of RSA internal failures while + * parsing data. + * \return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED if validity checks on the + * provided key fail. + */ +int mbedtls_rsa_parse_key(mbedtls_rsa_context *rsa, const unsigned char *key, size_t keylen); + +/** + * \brief Parse a PKCS#1 (ASN.1) encoded public RSA key. + * + * \param rsa The RSA context where parsed data will be stored. + * \param key The buffer that contains the key. + * \param keylen The length of the key buffer in bytes. + * + * \return 0 on success. + * \return MBEDTLS_ERR_ASN1_xxx in case of ASN.1 parsing errors. + * \return MBEDTLS_ERR_RSA_xxx in case of RSA internal failures while + * parsing data. + * \return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED if validity checks on the + * provided key fail. + */ +int mbedtls_rsa_parse_pubkey(mbedtls_rsa_context *rsa, const unsigned char *key, size_t keylen); + +/** + * \brief Write a PKCS#1 (ASN.1) encoded private RSA key. + * + * \param rsa The RSA context which contains the data to be written. + * \param start Beginning of the buffer that will be filled with the + * private key. + * \param p End of the buffer that will be filled with the private key. + * On successful return, the referenced pointer will be + * updated in order to point to the beginning of written data. + * + * \return On success, the number of bytes written to the output buffer + * (i.e. a value > 0). + * \return MBEDTLS_ERR_ASN1_xxx in case of failure while writing to the + * output buffer. + * + * \note The output buffer is filled backward, i.e. starting from its + * end and moving toward its start. + */ +int mbedtls_rsa_write_key(const mbedtls_rsa_context *rsa, unsigned char *start, + unsigned char **p); + +/** + * \brief Parse a PKCS#1 (ASN.1) encoded public RSA key. + * + * \param rsa The RSA context which contains the data to be written. + * \param start Beginning of the buffer that will be filled with the + * private key. + * \param p End of the buffer that will be filled with the private key. + * On successful return, the referenced pointer will be + * updated in order to point to the beginning of written data. + * + * \return On success, the number of bytes written to the output buffer + * (i.e. a value > 0). + * \return MBEDTLS_ERR_RSA_BAD_INPUT_DATA if the RSA context does not + * contain a valid public key. + * \return MBEDTLS_ERR_ASN1_xxx in case of failure while writing to the + * output buffer. + * + * \note The output buffer is filled backward, i.e. starting from its + * end and moving toward its start. + */ +int mbedtls_rsa_write_pubkey(const mbedtls_rsa_context *rsa, unsigned char *start, + unsigned char **p); + +#if defined(MBEDTLS_PKCS1_V21) +/** + * \brief This function is analogue to \c mbedtls_rsa_rsassa_pss_sign_ext(). + * The only difference between them is that this function is more flexible + * on the parameters of \p ctx that are set with \c mbedtls_rsa_set_padding(). + * + * \note Compared to its counterpart, this function: + * - does not check the padding setting of \p ctx. + * - allows the hash_id of \p ctx to be MBEDTLS_MD_NONE, + * in which case it uses \p md_alg as the hash_id. + * + * \note Refer to \c mbedtls_rsa_rsassa_pss_sign_ext() for a description + * of the functioning and parameters of this function. + */ +int mbedtls_rsa_rsassa_pss_sign_no_mode_check(mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig); +#endif /* MBEDTLS_PKCS1_V21 */ + +#endif /* TF_PSA_CRYPTO_RSA_INTERNAL_H */ diff --git a/tf-psa-crypto/drivers/builtin/src/sha1.c b/tf-psa-crypto/drivers/builtin/src/sha1.c new file mode 100644 index 0000000000..643206af7f --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/sha1.c @@ -0,0 +1,473 @@ +/* + * FIPS-180-1 compliant SHA-1 implementation + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +/* + * The SHA-1 standard was published by NIST in 1993. + * + * http://www.itl.nist.gov/fipspubs/fip180-1.htm + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_SHA1_C) + +#include "mbedtls/private/sha1.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#include + +#include "mbedtls/platform.h" + +void mbedtls_sha1_init(mbedtls_sha1_context *ctx) +{ + memset(ctx, 0, sizeof(mbedtls_sha1_context)); +} + +void mbedtls_sha1_free(mbedtls_sha1_context *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_sha1_context)); +} + +void mbedtls_sha1_clone(mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src) +{ + *dst = *src; +} + +/* + * SHA-1 context setup + */ +int mbedtls_sha1_starts(mbedtls_sha1_context *ctx) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; + + return 0; +} + +static int mbedtls_internal_sha1_process(mbedtls_sha1_context *ctx, + const unsigned char data[64]) +{ + struct { + uint32_t temp, W[16], A, B, C, D, E; + } local; + + local.W[0] = MBEDTLS_GET_UINT32_BE(data, 0); + local.W[1] = MBEDTLS_GET_UINT32_BE(data, 4); + local.W[2] = MBEDTLS_GET_UINT32_BE(data, 8); + local.W[3] = MBEDTLS_GET_UINT32_BE(data, 12); + local.W[4] = MBEDTLS_GET_UINT32_BE(data, 16); + local.W[5] = MBEDTLS_GET_UINT32_BE(data, 20); + local.W[6] = MBEDTLS_GET_UINT32_BE(data, 24); + local.W[7] = MBEDTLS_GET_UINT32_BE(data, 28); + local.W[8] = MBEDTLS_GET_UINT32_BE(data, 32); + local.W[9] = MBEDTLS_GET_UINT32_BE(data, 36); + local.W[10] = MBEDTLS_GET_UINT32_BE(data, 40); + local.W[11] = MBEDTLS_GET_UINT32_BE(data, 44); + local.W[12] = MBEDTLS_GET_UINT32_BE(data, 48); + local.W[13] = MBEDTLS_GET_UINT32_BE(data, 52); + local.W[14] = MBEDTLS_GET_UINT32_BE(data, 56); + local.W[15] = MBEDTLS_GET_UINT32_BE(data, 60); + +#define S(x, n) (((x) << (n)) | (((x) & 0xFFFFFFFF) >> (32 - (n)))) + +#define R(t) \ + ( \ + local.temp = local.W[((t) - 3) & 0x0F] ^ \ + local.W[((t) - 8) & 0x0F] ^ \ + local.W[((t) - 14) & 0x0F] ^ \ + local.W[(t) & 0x0F], \ + (local.W[(t) & 0x0F] = S(local.temp, 1)) \ + ) + +#define P(a, b, c, d, e, x) \ + do \ + { \ + (e) += S((a), 5) + F((b), (c), (d)) + K + (x); \ + (b) = S((b), 30); \ + } while (0) + + local.A = ctx->state[0]; + local.B = ctx->state[1]; + local.C = ctx->state[2]; + local.D = ctx->state[3]; + local.E = ctx->state[4]; + +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define K 0x5A827999 + + P(local.A, local.B, local.C, local.D, local.E, local.W[0]); + P(local.E, local.A, local.B, local.C, local.D, local.W[1]); + P(local.D, local.E, local.A, local.B, local.C, local.W[2]); + P(local.C, local.D, local.E, local.A, local.B, local.W[3]); + P(local.B, local.C, local.D, local.E, local.A, local.W[4]); + P(local.A, local.B, local.C, local.D, local.E, local.W[5]); + P(local.E, local.A, local.B, local.C, local.D, local.W[6]); + P(local.D, local.E, local.A, local.B, local.C, local.W[7]); + P(local.C, local.D, local.E, local.A, local.B, local.W[8]); + P(local.B, local.C, local.D, local.E, local.A, local.W[9]); + P(local.A, local.B, local.C, local.D, local.E, local.W[10]); + P(local.E, local.A, local.B, local.C, local.D, local.W[11]); + P(local.D, local.E, local.A, local.B, local.C, local.W[12]); + P(local.C, local.D, local.E, local.A, local.B, local.W[13]); + P(local.B, local.C, local.D, local.E, local.A, local.W[14]); + P(local.A, local.B, local.C, local.D, local.E, local.W[15]); + P(local.E, local.A, local.B, local.C, local.D, R(16)); + P(local.D, local.E, local.A, local.B, local.C, R(17)); + P(local.C, local.D, local.E, local.A, local.B, R(18)); + P(local.B, local.C, local.D, local.E, local.A, R(19)); + +#undef K +#undef F + +#define F(x, y, z) ((x) ^ (y) ^ (z)) +#define K 0x6ED9EBA1 + + P(local.A, local.B, local.C, local.D, local.E, R(20)); + P(local.E, local.A, local.B, local.C, local.D, R(21)); + P(local.D, local.E, local.A, local.B, local.C, R(22)); + P(local.C, local.D, local.E, local.A, local.B, R(23)); + P(local.B, local.C, local.D, local.E, local.A, R(24)); + P(local.A, local.B, local.C, local.D, local.E, R(25)); + P(local.E, local.A, local.B, local.C, local.D, R(26)); + P(local.D, local.E, local.A, local.B, local.C, R(27)); + P(local.C, local.D, local.E, local.A, local.B, R(28)); + P(local.B, local.C, local.D, local.E, local.A, R(29)); + P(local.A, local.B, local.C, local.D, local.E, R(30)); + P(local.E, local.A, local.B, local.C, local.D, R(31)); + P(local.D, local.E, local.A, local.B, local.C, R(32)); + P(local.C, local.D, local.E, local.A, local.B, R(33)); + P(local.B, local.C, local.D, local.E, local.A, R(34)); + P(local.A, local.B, local.C, local.D, local.E, R(35)); + P(local.E, local.A, local.B, local.C, local.D, R(36)); + P(local.D, local.E, local.A, local.B, local.C, R(37)); + P(local.C, local.D, local.E, local.A, local.B, R(38)); + P(local.B, local.C, local.D, local.E, local.A, R(39)); + +#undef K +#undef F + +#define F(x, y, z) (((x) & (y)) | ((z) & ((x) | (y)))) +#define K 0x8F1BBCDC + + P(local.A, local.B, local.C, local.D, local.E, R(40)); + P(local.E, local.A, local.B, local.C, local.D, R(41)); + P(local.D, local.E, local.A, local.B, local.C, R(42)); + P(local.C, local.D, local.E, local.A, local.B, R(43)); + P(local.B, local.C, local.D, local.E, local.A, R(44)); + P(local.A, local.B, local.C, local.D, local.E, R(45)); + P(local.E, local.A, local.B, local.C, local.D, R(46)); + P(local.D, local.E, local.A, local.B, local.C, R(47)); + P(local.C, local.D, local.E, local.A, local.B, R(48)); + P(local.B, local.C, local.D, local.E, local.A, R(49)); + P(local.A, local.B, local.C, local.D, local.E, R(50)); + P(local.E, local.A, local.B, local.C, local.D, R(51)); + P(local.D, local.E, local.A, local.B, local.C, R(52)); + P(local.C, local.D, local.E, local.A, local.B, R(53)); + P(local.B, local.C, local.D, local.E, local.A, R(54)); + P(local.A, local.B, local.C, local.D, local.E, R(55)); + P(local.E, local.A, local.B, local.C, local.D, R(56)); + P(local.D, local.E, local.A, local.B, local.C, R(57)); + P(local.C, local.D, local.E, local.A, local.B, R(58)); + P(local.B, local.C, local.D, local.E, local.A, R(59)); + +#undef K +#undef F + +#define F(x, y, z) ((x) ^ (y) ^ (z)) +#define K 0xCA62C1D6 + + P(local.A, local.B, local.C, local.D, local.E, R(60)); + P(local.E, local.A, local.B, local.C, local.D, R(61)); + P(local.D, local.E, local.A, local.B, local.C, R(62)); + P(local.C, local.D, local.E, local.A, local.B, R(63)); + P(local.B, local.C, local.D, local.E, local.A, R(64)); + P(local.A, local.B, local.C, local.D, local.E, R(65)); + P(local.E, local.A, local.B, local.C, local.D, R(66)); + P(local.D, local.E, local.A, local.B, local.C, R(67)); + P(local.C, local.D, local.E, local.A, local.B, R(68)); + P(local.B, local.C, local.D, local.E, local.A, R(69)); + P(local.A, local.B, local.C, local.D, local.E, R(70)); + P(local.E, local.A, local.B, local.C, local.D, R(71)); + P(local.D, local.E, local.A, local.B, local.C, R(72)); + P(local.C, local.D, local.E, local.A, local.B, R(73)); + P(local.B, local.C, local.D, local.E, local.A, R(74)); + P(local.A, local.B, local.C, local.D, local.E, R(75)); + P(local.E, local.A, local.B, local.C, local.D, R(76)); + P(local.D, local.E, local.A, local.B, local.C, R(77)); + P(local.C, local.D, local.E, local.A, local.B, R(78)); + P(local.B, local.C, local.D, local.E, local.A, R(79)); + +#undef K +#undef F + + ctx->state[0] += local.A; + ctx->state[1] += local.B; + ctx->state[2] += local.C; + ctx->state[3] += local.D; + ctx->state[4] += local.E; + + /* Zeroise buffers and variables to clear sensitive data from memory. */ + mbedtls_platform_zeroize(&local, sizeof(local)); + + return 0; +} + +/* + * SHA-1 process buffer + */ +int mbedtls_sha1_update(mbedtls_sha1_context *ctx, + const unsigned char *input, + size_t ilen) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t fill; + uint32_t left; + + if (ilen == 0) { + return 0; + } + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if (ctx->total[0] < (uint32_t) ilen) { + ctx->total[1]++; + } + + if (left && ilen >= fill) { + memcpy((void *) (ctx->buffer + left), input, fill); + + if ((ret = mbedtls_internal_sha1_process(ctx, ctx->buffer)) != 0) { + return ret; + } + + input += fill; + ilen -= fill; + left = 0; + } + + while (ilen >= 64) { + if ((ret = mbedtls_internal_sha1_process(ctx, input)) != 0) { + return ret; + } + + input += 64; + ilen -= 64; + } + + if (ilen > 0) { + memcpy((void *) (ctx->buffer + left), input, ilen); + } + + return 0; +} + +/* + * SHA-1 final digest + */ +int mbedtls_sha1_finish(mbedtls_sha1_context *ctx, + unsigned char output[20]) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + uint32_t used; + uint32_t high, low; + + /* + * Add padding: 0x80 then 0x00 until 8 bytes remain for the length + */ + used = ctx->total[0] & 0x3F; + + ctx->buffer[used++] = 0x80; + + if (used <= 56) { + /* Enough room for padding + length in current block */ + memset(ctx->buffer + used, 0, 56 - used); + } else { + /* We'll need an extra block */ + memset(ctx->buffer + used, 0, 64 - used); + + if ((ret = mbedtls_internal_sha1_process(ctx, ctx->buffer)) != 0) { + goto exit; + } + + memset(ctx->buffer, 0, 56); + } + + /* + * Add message length + */ + high = (ctx->total[0] >> 29) + | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + MBEDTLS_PUT_UINT32_BE(high, ctx->buffer, 56); + MBEDTLS_PUT_UINT32_BE(low, ctx->buffer, 60); + + if ((ret = mbedtls_internal_sha1_process(ctx, ctx->buffer)) != 0) { + goto exit; + } + + /* + * Output final state + */ + MBEDTLS_PUT_UINT32_BE(ctx->state[0], output, 0); + MBEDTLS_PUT_UINT32_BE(ctx->state[1], output, 4); + MBEDTLS_PUT_UINT32_BE(ctx->state[2], output, 8); + MBEDTLS_PUT_UINT32_BE(ctx->state[3], output, 12); + MBEDTLS_PUT_UINT32_BE(ctx->state[4], output, 16); + + ret = 0; + +exit: + mbedtls_sha1_free(ctx); + return ret; +} + +/* + * output = SHA-1( input buffer ) + */ +int mbedtls_sha1(const unsigned char *input, + size_t ilen, + unsigned char output[20]) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_sha1_context ctx; + + mbedtls_sha1_init(&ctx); + + if ((ret = mbedtls_sha1_starts(&ctx)) != 0) { + goto exit; + } + + if ((ret = mbedtls_sha1_update(&ctx, input, ilen)) != 0) { + goto exit; + } + + if ((ret = mbedtls_sha1_finish(&ctx, output)) != 0) { + goto exit; + } + +exit: + mbedtls_sha1_free(&ctx); + return ret; +} + +#if defined(MBEDTLS_SELF_TEST) +/* + * FIPS-180-1 test vectors + */ +static const unsigned char sha1_test_buf[3][57] = +{ + { "abc" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "" } +}; + +static const size_t sha1_test_buflen[3] = +{ + 3, 56, 1000 +}; + +static const unsigned char sha1_test_sum[3][20] = +{ + { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E, + 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D }, + { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE, + 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 }, + { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E, + 0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F } +}; + +/* + * Checkup routine + */ +int mbedtls_sha1_self_test(int verbose) +{ + int i, j, buflen, ret = 0; + unsigned char buf[1024]; + unsigned char sha1sum[20]; + mbedtls_sha1_context ctx; + + mbedtls_sha1_init(&ctx); + + /* + * SHA-1 + */ + for (i = 0; i < 3; i++) { + if (verbose != 0) { + mbedtls_printf(" SHA-1 test #%d: ", i + 1); + } + + if ((ret = mbedtls_sha1_starts(&ctx)) != 0) { + goto fail; + } + + if (i == 2) { + memset(buf, 'a', buflen = 1000); + + for (j = 0; j < 1000; j++) { + ret = mbedtls_sha1_update(&ctx, buf, buflen); + if (ret != 0) { + goto fail; + } + } + } else { + ret = mbedtls_sha1_update(&ctx, sha1_test_buf[i], + sha1_test_buflen[i]); + if (ret != 0) { + goto fail; + } + } + + if ((ret = mbedtls_sha1_finish(&ctx, sha1sum)) != 0) { + goto fail; + } + + if (memcmp(sha1sum, sha1_test_sum[i], 20) != 0) { + ret = 1; + goto fail; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + goto exit; + +fail: + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + +exit: + mbedtls_sha1_free(&ctx); + + return ret; +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA1_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/sha256.c b/tf-psa-crypto/drivers/builtin/src/sha256.c new file mode 100644 index 0000000000..3eb38dd1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/sha256.c @@ -0,0 +1,956 @@ +/* + * FIPS-180-2 compliant SHA-256 implementation + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +/* + * The SHA-256 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +/* Ensure that SIG_SETMASK is defined when -std=c99 is used. */ +#if !defined(_GNU_SOURCE) +#define _GNU_SOURCE +#endif + +#if defined(__clang__) && (__clang_major__ >= 4) + +/* Ideally, we would simply use MBEDTLS_ARCH_IS_ARMV8_A in the following #if, + * but that is defined by build_info.h, and we need this block to happen first. */ +#if defined(__ARM_ARCH) && (__ARM_ARCH_PROFILE == 'A') +#if __ARM_ARCH >= 8 +#define MBEDTLS_SHA256_ARCH_IS_ARMV8_A +#endif +#endif + +#if defined(MBEDTLS_SHA256_ARCH_IS_ARMV8_A) && !defined(__ARM_FEATURE_CRYPTO) +/* + * The intrinsic declaration are guarded by predefined ACLE macros in clang: + * these are normally only enabled by the -march option on the command line. + * By defining the macros ourselves we gain access to those declarations without + * requiring -march on the command line. + * + * `arm_neon.h` is included by tf_psa_crypto_common.h, so we put these defines + * at the top of this file, before any includes but after the intrinsic + * declaration. This is necessary with + * Clang <=15.x. With Clang 16.0 and above, these macro definitions are + * no longer required, but they're harmless. See + * https://reviews.llvm.org/D131064 + */ +#define __ARM_FEATURE_CRYPTO 1 +/* See: https://arm-software.github.io/acle/main/acle.html#cryptographic-extensions + * + * `__ARM_FEATURE_CRYPTO` is deprecated, but we need to continue to specify it + * for older compilers. + */ +#define __ARM_FEATURE_SHA2 1 +#define MBEDTLS_ENABLE_ARM_CRYPTO_EXTENSIONS_COMPILER_FLAG +#endif + +#endif /* defined(__clang__) && (__clang_major__ >= 4) */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_SHA256_C) || defined(MBEDTLS_SHA224_C) + +#include "mbedtls/private/sha256.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#include + +#include "mbedtls/platform.h" + +#if defined(MBEDTLS_ARCH_IS_ARMV8_A) + +# if defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT) || \ + defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY) +# if !defined(MBEDTLS_HAVE_NEON_INTRINSICS) +# if defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT) +# warning "Target does not support NEON instructions" +# undef MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT +# else +# error "Target does not support NEON instructions" +# endif +# endif +# endif + +# if defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT) || \ + defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY) +/* *INDENT-OFF* */ + +# if !defined(__ARM_FEATURE_CRYPTO) || defined(MBEDTLS_ENABLE_ARM_CRYPTO_EXTENSIONS_COMPILER_FLAG) +# if defined(__ARMCOMPILER_VERSION) +# if __ARMCOMPILER_VERSION <= 6090000 +# error "Must use minimum -march=armv8-a+crypto for MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_*" +# endif +# pragma clang attribute push (__attribute__((target("sha2"))), apply_to=function) +# define MBEDTLS_POP_TARGET_PRAGMA +# elif defined(__clang__) +# if __clang_major__ < 4 +# error "A more recent Clang is required for MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_*" +# endif +# pragma clang attribute push (__attribute__((target("crypto"))), apply_to=function) +# define MBEDTLS_POP_TARGET_PRAGMA +# elif defined(__GNUC__) + /* FIXME: GCC 5 claims to support Armv8 Crypto Extensions, but some + * intrinsics are missing. Missing intrinsics could be worked around. + */ +# if __GNUC__ < 6 +# error "A more recent GCC is required for MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_*" +# else +# pragma GCC push_options +# pragma GCC target ("arch=armv8-a+crypto") +# define MBEDTLS_POP_TARGET_PRAGMA +# endif +# else +# error "Only GCC and Clang supported for MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_*" +# endif +# endif +/* *INDENT-ON* */ + +# endif +# if defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT) +# if defined(__unix__) +# if defined(__linux__) +/* Our preferred method of detection is getauxval() */ +# include +/* These are not always defined via sys/auxv.h */ +# if !defined(HWCAP_SHA2) +# define HWCAP_SHA2 (1 << 6) +# endif +# if !defined(HWCAP2_SHA2) +# define HWCAP2_SHA2 (1 << 3) +# endif +# endif +/* Use SIGILL on Unix, and fall back to it on Linux */ +# include +# endif +# endif +#elif !defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64) +# undef MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY +# undef MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT +#endif + +#if defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT) +/* + * Capability detection code comes early, so we can disable + * MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT if no detection mechanism found + */ +#if defined(MBEDTLS_ARCH_IS_ARM64) && defined(HWCAP_SHA2) +static int mbedtls_a64_crypto_sha256_determine_support(void) +{ + return (getauxval(AT_HWCAP) & HWCAP_SHA2) ? 1 : 0; +} +#elif defined(MBEDTLS_ARCH_IS_ARM32) && defined(HWCAP2_SHA2) +static int mbedtls_a64_crypto_sha256_determine_support(void) +{ + return (getauxval(AT_HWCAP2) & HWCAP2_SHA2) ? 1 : 0; +} +#elif defined(__APPLE__) +static int mbedtls_a64_crypto_sha256_determine_support(void) +{ + return 1; +} +#elif defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +static int mbedtls_a64_crypto_sha256_determine_support(void) +{ + return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) ? + 1 : 0; +} +#elif defined(__unix__) && defined(SIG_SETMASK) +/* Detection with SIGILL, setjmp() and longjmp() */ +#include +#include + +static jmp_buf return_from_sigill; + +/* + * Armv8-A SHA256 support detection via SIGILL + */ +static void sigill_handler(int signal) +{ + (void) signal; + longjmp(return_from_sigill, 1); +} + +static int mbedtls_a64_crypto_sha256_determine_support(void) +{ + struct sigaction old_action, new_action; + + sigset_t old_mask; + if (sigprocmask(0, NULL, &old_mask)) { + return 0; + } + + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = 0; + new_action.sa_handler = sigill_handler; + + sigaction(SIGILL, &new_action, &old_action); + + static int ret = 0; + + if (setjmp(return_from_sigill) == 0) { /* First return only */ + /* If this traps, we will return a second time from setjmp() with 1 */ +#if defined(MBEDTLS_ARCH_IS_ARM64) + asm volatile ("sha256h q0, q0, v0.4s" : : : "v0"); +#else + asm volatile ("sha256h.32 q0, q0, q0" : : : "q0"); +#endif + ret = 1; + } + + sigaction(SIGILL, &old_action, NULL); + sigprocmask(SIG_SETMASK, &old_mask, NULL); + + return ret; +} +#else +#warning "No mechanism to detect ARMV8_CRYPTO found, using C code only" +#undef MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT +#endif /* HWCAP_SHA2, __APPLE__, __unix__ && SIG_SETMASK */ + +#endif /* MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT */ + +#define SHA256_BLOCK_SIZE 64 + +void mbedtls_sha256_init(mbedtls_sha256_context *ctx) +{ + memset(ctx, 0, sizeof(mbedtls_sha256_context)); +} + +void mbedtls_sha256_free(mbedtls_sha256_context *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_sha256_context)); +} + +void mbedtls_sha256_clone(mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src) +{ + *dst = *src; +} + +/* + * SHA-256 context setup + */ +int mbedtls_sha256_starts(mbedtls_sha256_context *ctx, int is224) +{ +#if defined(MBEDTLS_SHA224_C) && defined(MBEDTLS_SHA256_C) + if (is224 != 0 && is224 != 1) { + return MBEDTLS_ERR_SHA256_BAD_INPUT_DATA; + } +#elif defined(MBEDTLS_SHA256_C) + if (is224 != 0) { + return MBEDTLS_ERR_SHA256_BAD_INPUT_DATA; + } +#else /* defined MBEDTLS_SHA224_C only */ + if (is224 == 0) { + return MBEDTLS_ERR_SHA256_BAD_INPUT_DATA; + } +#endif + + ctx->total[0] = 0; + ctx->total[1] = 0; + + if (is224 == 0) { +#if defined(MBEDTLS_SHA256_C) + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; +#endif + } else { +#if defined(MBEDTLS_SHA224_C) + ctx->state[0] = 0xC1059ED8; + ctx->state[1] = 0x367CD507; + ctx->state[2] = 0x3070DD17; + ctx->state[3] = 0xF70E5939; + ctx->state[4] = 0xFFC00B31; + ctx->state[5] = 0x68581511; + ctx->state[6] = 0x64F98FA7; + ctx->state[7] = 0xBEFA4FA4; +#endif + } + +#if defined(MBEDTLS_SHA224_C) + ctx->is224 = is224; +#endif + + return 0; +} + +static const uint32_t K[] = +{ + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, +}; + +#if defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT) || \ + defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY) + +#if defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY) +# define mbedtls_internal_sha256_process_many_a64_crypto mbedtls_internal_sha256_process_many +# define mbedtls_internal_sha256_process_a64_crypto mbedtls_internal_sha256_process +#endif + +static size_t mbedtls_internal_sha256_process_many_a64_crypto( + mbedtls_sha256_context *ctx, const uint8_t *msg, size_t len) +{ + uint32x4_t abcd = vld1q_u32(&ctx->state[0]); + uint32x4_t efgh = vld1q_u32(&ctx->state[4]); + + size_t processed = 0; + + for (; + len >= SHA256_BLOCK_SIZE; + processed += SHA256_BLOCK_SIZE, + msg += SHA256_BLOCK_SIZE, + len -= SHA256_BLOCK_SIZE) { + uint32x4_t tmp, abcd_prev; + + uint32x4_t abcd_orig = abcd; + uint32x4_t efgh_orig = efgh; + + uint32x4_t sched0 = vreinterpretq_u32_u8(vld1q_u8(msg + 16 * 0)); + uint32x4_t sched1 = vreinterpretq_u32_u8(vld1q_u8(msg + 16 * 1)); + uint32x4_t sched2 = vreinterpretq_u32_u8(vld1q_u8(msg + 16 * 2)); + uint32x4_t sched3 = vreinterpretq_u32_u8(vld1q_u8(msg + 16 * 3)); + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ /* Will be true if not defined */ + /* Untested on BE */ + sched0 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(sched0))); + sched1 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(sched1))); + sched2 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(sched2))); + sched3 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(sched3))); +#endif + + /* Rounds 0 to 3 */ + tmp = vaddq_u32(sched0, vld1q_u32(&K[0])); + abcd_prev = abcd; + abcd = vsha256hq_u32(abcd_prev, efgh, tmp); + efgh = vsha256h2q_u32(efgh, abcd_prev, tmp); + + /* Rounds 4 to 7 */ + tmp = vaddq_u32(sched1, vld1q_u32(&K[4])); + abcd_prev = abcd; + abcd = vsha256hq_u32(abcd_prev, efgh, tmp); + efgh = vsha256h2q_u32(efgh, abcd_prev, tmp); + + /* Rounds 8 to 11 */ + tmp = vaddq_u32(sched2, vld1q_u32(&K[8])); + abcd_prev = abcd; + abcd = vsha256hq_u32(abcd_prev, efgh, tmp); + efgh = vsha256h2q_u32(efgh, abcd_prev, tmp); + + /* Rounds 12 to 15 */ + tmp = vaddq_u32(sched3, vld1q_u32(&K[12])); + abcd_prev = abcd; + abcd = vsha256hq_u32(abcd_prev, efgh, tmp); + efgh = vsha256h2q_u32(efgh, abcd_prev, tmp); + + for (int t = 16; t < 64; t += 16) { + /* Rounds t to t + 3 */ + sched0 = vsha256su1q_u32(vsha256su0q_u32(sched0, sched1), sched2, sched3); + tmp = vaddq_u32(sched0, vld1q_u32(&K[t])); + abcd_prev = abcd; + abcd = vsha256hq_u32(abcd_prev, efgh, tmp); + efgh = vsha256h2q_u32(efgh, abcd_prev, tmp); + + /* Rounds t + 4 to t + 7 */ + sched1 = vsha256su1q_u32(vsha256su0q_u32(sched1, sched2), sched3, sched0); + tmp = vaddq_u32(sched1, vld1q_u32(&K[t + 4])); + abcd_prev = abcd; + abcd = vsha256hq_u32(abcd_prev, efgh, tmp); + efgh = vsha256h2q_u32(efgh, abcd_prev, tmp); + + /* Rounds t + 8 to t + 11 */ + sched2 = vsha256su1q_u32(vsha256su0q_u32(sched2, sched3), sched0, sched1); + tmp = vaddq_u32(sched2, vld1q_u32(&K[t + 8])); + abcd_prev = abcd; + abcd = vsha256hq_u32(abcd_prev, efgh, tmp); + efgh = vsha256h2q_u32(efgh, abcd_prev, tmp); + + /* Rounds t + 12 to t + 15 */ + sched3 = vsha256su1q_u32(vsha256su0q_u32(sched3, sched0), sched1, sched2); + tmp = vaddq_u32(sched3, vld1q_u32(&K[t + 12])); + abcd_prev = abcd; + abcd = vsha256hq_u32(abcd_prev, efgh, tmp); + efgh = vsha256h2q_u32(efgh, abcd_prev, tmp); + } + + abcd = vaddq_u32(abcd, abcd_orig); + efgh = vaddq_u32(efgh, efgh_orig); + } + + vst1q_u32(&ctx->state[0], abcd); + vst1q_u32(&ctx->state[4], efgh); + + return processed; +} + +static int mbedtls_internal_sha256_process_a64_crypto(mbedtls_sha256_context *ctx, + const unsigned char data[SHA256_BLOCK_SIZE]) +{ + return (mbedtls_internal_sha256_process_many_a64_crypto(ctx, data, + SHA256_BLOCK_SIZE) == + SHA256_BLOCK_SIZE) ? 0 : -1; +} + +#endif /* MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT || MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY */ + +#if defined(MBEDTLS_POP_TARGET_PRAGMA) +#if defined(__clang__) +#pragma clang attribute pop +#elif defined(__GNUC__) +#pragma GCC pop_options +#endif +#undef MBEDTLS_POP_TARGET_PRAGMA +#endif + +#if !defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT) +#define mbedtls_internal_sha256_process_many_c mbedtls_internal_sha256_process_many +#define mbedtls_internal_sha256_process_c mbedtls_internal_sha256_process +#endif + + +#if !defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY) + +#define SHR(x, n) (((x) & 0xFFFFFFFF) >> (n)) +#define ROTR(x, n) (SHR(x, n) | ((x) << (32 - (n)))) + +#define S0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) +#define S1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) + +#define S2(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S3(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) + +#define F0(x, y, z) (((x) & (y)) | ((z) & ((x) | (y)))) +#define F1(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) + +#define R(t) \ + ( \ + local.W[t] = S1(local.W[(t) - 2]) + local.W[(t) - 7] + \ + S0(local.W[(t) - 15]) + local.W[(t) - 16] \ + ) + +#define P(a, b, c, d, e, f, g, h, x, K) \ + do \ + { \ + local.temp1 = (h) + S3(e) + F1((e), (f), (g)) + (K) + (x); \ + local.temp2 = S2(a) + F0((a), (b), (c)); \ + (d) += local.temp1; (h) = local.temp1 + local.temp2; \ + } while (0) + +static int mbedtls_internal_sha256_process_c(mbedtls_sha256_context *ctx, + const unsigned char data[SHA256_BLOCK_SIZE]) +{ + struct { + uint32_t temp1, temp2, W[64]; + uint32_t A[8]; + } local; + + unsigned int i; + + for (i = 0; i < 8; i++) { + local.A[i] = ctx->state[i]; + } + +#if defined(MBEDTLS_SHA256_SMALLER) + for (i = 0; i < 64; i++) { + if (i < 16) { + local.W[i] = MBEDTLS_GET_UINT32_BE(data, 4 * i); + } else { + R(i); + } + + P(local.A[0], local.A[1], local.A[2], local.A[3], local.A[4], + local.A[5], local.A[6], local.A[7], local.W[i], K[i]); + + local.temp1 = local.A[7]; local.A[7] = local.A[6]; + local.A[6] = local.A[5]; local.A[5] = local.A[4]; + local.A[4] = local.A[3]; local.A[3] = local.A[2]; + local.A[2] = local.A[1]; local.A[1] = local.A[0]; + local.A[0] = local.temp1; + } +#else /* MBEDTLS_SHA256_SMALLER */ + for (i = 0; i < 16; i++) { + local.W[i] = MBEDTLS_GET_UINT32_BE(data, 4 * i); + } + + for (i = 0; i < 16; i += 8) { + P(local.A[0], local.A[1], local.A[2], local.A[3], local.A[4], + local.A[5], local.A[6], local.A[7], local.W[i+0], K[i+0]); + P(local.A[7], local.A[0], local.A[1], local.A[2], local.A[3], + local.A[4], local.A[5], local.A[6], local.W[i+1], K[i+1]); + P(local.A[6], local.A[7], local.A[0], local.A[1], local.A[2], + local.A[3], local.A[4], local.A[5], local.W[i+2], K[i+2]); + P(local.A[5], local.A[6], local.A[7], local.A[0], local.A[1], + local.A[2], local.A[3], local.A[4], local.W[i+3], K[i+3]); + P(local.A[4], local.A[5], local.A[6], local.A[7], local.A[0], + local.A[1], local.A[2], local.A[3], local.W[i+4], K[i+4]); + P(local.A[3], local.A[4], local.A[5], local.A[6], local.A[7], + local.A[0], local.A[1], local.A[2], local.W[i+5], K[i+5]); + P(local.A[2], local.A[3], local.A[4], local.A[5], local.A[6], + local.A[7], local.A[0], local.A[1], local.W[i+6], K[i+6]); + P(local.A[1], local.A[2], local.A[3], local.A[4], local.A[5], + local.A[6], local.A[7], local.A[0], local.W[i+7], K[i+7]); + } + + for (i = 16; i < 64; i += 8) { + P(local.A[0], local.A[1], local.A[2], local.A[3], local.A[4], + local.A[5], local.A[6], local.A[7], R(i+0), K[i+0]); + P(local.A[7], local.A[0], local.A[1], local.A[2], local.A[3], + local.A[4], local.A[5], local.A[6], R(i+1), K[i+1]); + P(local.A[6], local.A[7], local.A[0], local.A[1], local.A[2], + local.A[3], local.A[4], local.A[5], R(i+2), K[i+2]); + P(local.A[5], local.A[6], local.A[7], local.A[0], local.A[1], + local.A[2], local.A[3], local.A[4], R(i+3), K[i+3]); + P(local.A[4], local.A[5], local.A[6], local.A[7], local.A[0], + local.A[1], local.A[2], local.A[3], R(i+4), K[i+4]); + P(local.A[3], local.A[4], local.A[5], local.A[6], local.A[7], + local.A[0], local.A[1], local.A[2], R(i+5), K[i+5]); + P(local.A[2], local.A[3], local.A[4], local.A[5], local.A[6], + local.A[7], local.A[0], local.A[1], R(i+6), K[i+6]); + P(local.A[1], local.A[2], local.A[3], local.A[4], local.A[5], + local.A[6], local.A[7], local.A[0], R(i+7), K[i+7]); + } +#endif /* MBEDTLS_SHA256_SMALLER */ + + for (i = 0; i < 8; i++) { + ctx->state[i] += local.A[i]; + } + + /* Zeroise buffers and variables to clear sensitive data from memory. */ + mbedtls_platform_zeroize(&local, sizeof(local)); + + return 0; +} + +static size_t mbedtls_internal_sha256_process_many_c( + mbedtls_sha256_context *ctx, const uint8_t *data, size_t len) +{ + size_t processed = 0; + + while (len >= SHA256_BLOCK_SIZE) { + if (mbedtls_internal_sha256_process_c(ctx, data) != 0) { + return 0; + } + + data += SHA256_BLOCK_SIZE; + len -= SHA256_BLOCK_SIZE; + + processed += SHA256_BLOCK_SIZE; + } + + return processed; +} + +#endif /* !MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY */ + + +#if defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT) + +static int mbedtls_a64_crypto_sha256_has_support(void) +{ + static int done = 0; + static int supported = 0; + + if (!done) { + supported = mbedtls_a64_crypto_sha256_determine_support(); + done = 1; + } + + return supported; +} + +static size_t mbedtls_internal_sha256_process_many(mbedtls_sha256_context *ctx, + const uint8_t *msg, size_t len) +{ + if (mbedtls_a64_crypto_sha256_has_support()) { + return mbedtls_internal_sha256_process_many_a64_crypto(ctx, msg, len); + } else { + return mbedtls_internal_sha256_process_many_c(ctx, msg, len); + } +} + +static int mbedtls_internal_sha256_process(mbedtls_sha256_context *ctx, + const unsigned char data[SHA256_BLOCK_SIZE]) +{ + if (mbedtls_a64_crypto_sha256_has_support()) { + return mbedtls_internal_sha256_process_a64_crypto(ctx, data); + } else { + return mbedtls_internal_sha256_process_c(ctx, data); + } +} + +#endif /* MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT */ + + +/* + * SHA-256 process buffer + */ +int mbedtls_sha256_update(mbedtls_sha256_context *ctx, + const unsigned char *input, + size_t ilen) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t fill; + uint32_t left; + + if (ilen == 0) { + return 0; + } + + left = ctx->total[0] & 0x3F; + fill = SHA256_BLOCK_SIZE - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if (ctx->total[0] < (uint32_t) ilen) { + ctx->total[1]++; + } + + if (left && ilen >= fill) { + memcpy((void *) (ctx->buffer + left), input, fill); + + if ((ret = mbedtls_internal_sha256_process(ctx, ctx->buffer)) != 0) { + return ret; + } + + input += fill; + ilen -= fill; + left = 0; + } + + while (ilen >= SHA256_BLOCK_SIZE) { + size_t processed = + mbedtls_internal_sha256_process_many(ctx, input, ilen); + if (processed < SHA256_BLOCK_SIZE) { + return MBEDTLS_ERR_ERROR_GENERIC_ERROR; + } + + input += processed; + ilen -= processed; + } + + if (ilen > 0) { + memcpy((void *) (ctx->buffer + left), input, ilen); + } + + return 0; +} + +/* + * SHA-256 final digest + */ +int mbedtls_sha256_finish(mbedtls_sha256_context *ctx, + unsigned char *output) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + uint32_t used; + uint32_t high, low; + int truncated = 0; + + /* + * Add padding: 0x80 then 0x00 until 8 bytes remain for the length + */ + used = ctx->total[0] & 0x3F; + + ctx->buffer[used++] = 0x80; + + if (used <= 56) { + /* Enough room for padding + length in current block */ + memset(ctx->buffer + used, 0, 56 - used); + } else { + /* We'll need an extra block */ + memset(ctx->buffer + used, 0, SHA256_BLOCK_SIZE - used); + + if ((ret = mbedtls_internal_sha256_process(ctx, ctx->buffer)) != 0) { + goto exit; + } + + memset(ctx->buffer, 0, 56); + } + + /* + * Add message length + */ + high = (ctx->total[0] >> 29) + | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + MBEDTLS_PUT_UINT32_BE(high, ctx->buffer, 56); + MBEDTLS_PUT_UINT32_BE(low, ctx->buffer, 60); + + if ((ret = mbedtls_internal_sha256_process(ctx, ctx->buffer)) != 0) { + goto exit; + } + + /* + * Output final state + */ + MBEDTLS_PUT_UINT32_BE(ctx->state[0], output, 0); + MBEDTLS_PUT_UINT32_BE(ctx->state[1], output, 4); + MBEDTLS_PUT_UINT32_BE(ctx->state[2], output, 8); + MBEDTLS_PUT_UINT32_BE(ctx->state[3], output, 12); + MBEDTLS_PUT_UINT32_BE(ctx->state[4], output, 16); + MBEDTLS_PUT_UINT32_BE(ctx->state[5], output, 20); + MBEDTLS_PUT_UINT32_BE(ctx->state[6], output, 24); + +#if defined(MBEDTLS_SHA224_C) + truncated = ctx->is224; +#endif + if (!truncated) { + MBEDTLS_PUT_UINT32_BE(ctx->state[7], output, 28); + } + + ret = 0; + +exit: + mbedtls_sha256_free(ctx); + return ret; +} + +/* + * output = SHA-256( input buffer ) + */ +int mbedtls_sha256(const unsigned char *input, + size_t ilen, + unsigned char *output, + int is224) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_sha256_context ctx; + +#if defined(MBEDTLS_SHA224_C) && defined(MBEDTLS_SHA256_C) + if (is224 != 0 && is224 != 1) { + return MBEDTLS_ERR_SHA256_BAD_INPUT_DATA; + } +#elif defined(MBEDTLS_SHA256_C) + if (is224 != 0) { + return MBEDTLS_ERR_SHA256_BAD_INPUT_DATA; + } +#else /* defined MBEDTLS_SHA224_C only */ + if (is224 == 0) { + return MBEDTLS_ERR_SHA256_BAD_INPUT_DATA; + } +#endif + + mbedtls_sha256_init(&ctx); + + if ((ret = mbedtls_sha256_starts(&ctx, is224)) != 0) { + goto exit; + } + + if ((ret = mbedtls_sha256_update(&ctx, input, ilen)) != 0) { + goto exit; + } + + if ((ret = mbedtls_sha256_finish(&ctx, output)) != 0) { + goto exit; + } + +exit: + mbedtls_sha256_free(&ctx); + + return ret; +} + +#if defined(MBEDTLS_SELF_TEST) +/* + * FIPS-180-2 test vectors + */ +static const unsigned char sha_test_buf[3][57] = +{ + { "abc" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "" } +}; + +static const size_t sha_test_buflen[3] = +{ + 3, 56, 1000 +}; + +typedef const unsigned char (sha_test_sum_t)[32]; + +/* + * SHA-224 test vectors + */ +#if defined(MBEDTLS_SHA224_C) +static sha_test_sum_t sha224_test_sum[] = +{ + { 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22, + 0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3, + 0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7, + 0xE3, 0x6C, 0x9D, 0xA7 }, + { 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC, + 0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50, + 0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19, + 0x52, 0x52, 0x25, 0x25 }, + { 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8, + 0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B, + 0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE, + 0x4E, 0xE7, 0xAD, 0x67 } +}; +#endif + +/* + * SHA-256 test vectors + */ +#if defined(MBEDTLS_SHA256_C) +static sha_test_sum_t sha256_test_sum[] = +{ + { 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA, + 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23, + 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C, + 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD }, + { 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8, + 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39, + 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67, + 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 }, + { 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92, + 0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67, + 0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E, + 0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 } +}; +#endif + +/* + * Checkup routine + */ +static int mbedtls_sha256_common_self_test(int verbose, int is224) +{ + int i, buflen, ret = 0; + unsigned char *buf; + unsigned char sha256sum[32]; + mbedtls_sha256_context ctx; + +#if defined(MBEDTLS_SHA224_C) && defined(MBEDTLS_SHA256_C) + sha_test_sum_t *sha_test_sum = (is224) ? sha224_test_sum : sha256_test_sum; +#elif defined(MBEDTLS_SHA256_C) + sha_test_sum_t *sha_test_sum = sha256_test_sum; +#else + sha_test_sum_t *sha_test_sum = sha224_test_sum; +#endif + + buf = mbedtls_calloc(1024, sizeof(unsigned char)); + if (NULL == buf) { + if (verbose != 0) { + mbedtls_printf("Buffer allocation failed\n"); + } + + return 1; + } + + mbedtls_sha256_init(&ctx); + + for (i = 0; i < 3; i++) { + if (verbose != 0) { + mbedtls_printf(" SHA-%d test #%d: ", 256 - is224 * 32, i + 1); + } + + if ((ret = mbedtls_sha256_starts(&ctx, is224)) != 0) { + goto fail; + } + + if (i == 2) { + memset(buf, 'a', buflen = 1000); + + for (int j = 0; j < 1000; j++) { + ret = mbedtls_sha256_update(&ctx, buf, buflen); + if (ret != 0) { + goto fail; + } + } + + } else { + ret = mbedtls_sha256_update(&ctx, sha_test_buf[i], + sha_test_buflen[i]); + if (ret != 0) { + goto fail; + } + } + + if ((ret = mbedtls_sha256_finish(&ctx, sha256sum)) != 0) { + goto fail; + } + + + if (memcmp(sha256sum, sha_test_sum[i], 32 - is224 * 4) != 0) { + ret = 1; + goto fail; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + goto exit; + +fail: + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + +exit: + mbedtls_sha256_free(&ctx); + mbedtls_free(buf); + + return ret; +} + +#if defined(MBEDTLS_SHA256_C) +int mbedtls_sha256_self_test(int verbose) +{ + return mbedtls_sha256_common_self_test(verbose, 0); +} +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA224_C) +int mbedtls_sha224_self_test(int verbose) +{ + return mbedtls_sha256_common_self_test(verbose, 1); +} +#endif /* MBEDTLS_SHA224_C */ + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA256_C || MBEDTLS_SHA224_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/sha3.c b/tf-psa-crypto/drivers/builtin/src/sha3.c new file mode 100644 index 0000000000..2bac57eaee --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/sha3.c @@ -0,0 +1,951 @@ +/* + * FIPS-202 compliant SHA3 implementation + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +/* + * The SHA-3 Secure Hash Standard was published by NIST in 2015. + * + * https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf + */ + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_SHA3_C) + +/* + * These macros select manually unrolled implementations of parts of the main permutation function. + * + * Unrolling has a major impact on both performance and code size. gcc performance benefits a lot + * from manually unrolling at higher optimisation levels. + * + * Depending on your size/perf priorities, compiler and target, it may be beneficial to adjust + * these; the defaults here should give sensible trade-offs for gcc and clang on aarch64 and + * x86-64. + */ +#if !defined(MBEDTLS_SHA3_THETA_UNROLL) + #define MBEDTLS_SHA3_THETA_UNROLL 0 //no-check-names +#endif +#if !defined(MBEDTLS_SHA3_CHI_UNROLL) + #if defined(__OPTIMIZE_SIZE__) + #define MBEDTLS_SHA3_CHI_UNROLL 0 //no-check-names + #else + #define MBEDTLS_SHA3_CHI_UNROLL 1 //no-check-names + #endif +#endif +#if !defined(MBEDTLS_SHA3_PI_UNROLL) + #define MBEDTLS_SHA3_PI_UNROLL 1 //no-check-names +#endif +#if !defined(MBEDTLS_SHA3_RHO_UNROLL) + #define MBEDTLS_SHA3_RHO_UNROLL 1 //no-check-names +#endif + +#include "mbedtls/private/sha3.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#include "mbedtls/platform.h" +#endif /* MBEDTLS_SELF_TEST */ + +#define SHA3_XOR_BYTE 0x06 +#define SHAKE_XOR_BYTE 0x1F + +/* Precomputed masks for the iota transform. + * + * Each round uses a 64-bit mask value. In each mask values, only + * bits whose position is of the form 2^k-1 can be set, thus only + * 7 of 64 bits of the mask need to be known for each mask value. + * + * We use a compressed encoding of the mask where bits 63, 31 and 15 + * are moved to bits 4-6. This allows us to make each mask value + * 1 byte rather than 8 bytes, saving 7*24 = 168 bytes of data (with + * perhaps a little variation due to alignment). Decompressing this + * requires a little code, but much less than the savings on the table. + * + * The impact on performance depends on the platform and compiler. + * There's a bit more computation, but less memory bandwidth. A quick + * benchmark on x86_64 shows a 7% speed improvement with GCC and a + * 5% speed penalty with Clang, compared to the naive uint64_t[24] table. + * YMMV. + */ +/* Helper macro to set the values of the higher bits in unused low positions */ +#define H(b63, b31, b15) (b63 << 6 | b31 << 5 | b15 << 4) +static const uint8_t iota_r_packed[24] = { + H(0, 0, 0) | 0x01, H(0, 0, 1) | 0x82, H(1, 0, 1) | 0x8a, H(1, 1, 1) | 0x00, + H(0, 0, 1) | 0x8b, H(0, 1, 0) | 0x01, H(1, 1, 1) | 0x81, H(1, 0, 1) | 0x09, + H(0, 0, 0) | 0x8a, H(0, 0, 0) | 0x88, H(0, 1, 1) | 0x09, H(0, 1, 0) | 0x0a, + H(0, 1, 1) | 0x8b, H(1, 0, 0) | 0x8b, H(1, 0, 1) | 0x89, H(1, 0, 1) | 0x03, + H(1, 0, 1) | 0x02, H(1, 0, 0) | 0x80, H(0, 0, 1) | 0x0a, H(1, 1, 0) | 0x0a, + H(1, 1, 1) | 0x81, H(1, 0, 1) | 0x80, H(0, 1, 0) | 0x01, H(1, 1, 1) | 0x08, +}; +#undef H + +static const uint32_t rho[6] = { + 0x3f022425, 0x1c143a09, 0x2c3d3615, 0x27191713, 0x312b382e, 0x3e030832 +}; + +static const uint32_t pi[6] = { + 0x110b070a, 0x10050312, 0x04181508, 0x0d13170f, 0x0e14020c, 0x01060916 +}; + +#define ROTR64(x, y) (((x) << (64U - (y))) | ((x) >> (y))) // 64-bit rotate right +#define ABSORB(ctx, idx, v) do { ctx->state[(idx) >> 3] ^= ((uint64_t) (v)) << (((idx) & 0x7) << 3); \ +} while (0) +#define SQUEEZE(ctx, idx) ((uint8_t) (ctx->state[(idx) >> 3] >> (((idx) & 0x7) << 3))) +#define SWAP(x, y) do { uint64_t tmp = (x); (x) = (y); (y) = tmp; } while (0) + +/* The permutation function. */ +static void keccak_f1600(mbedtls_sha3_context *ctx) +{ + uint64_t lane[5]; + uint64_t *s = ctx->state; + int i; + + for (int round = 0; round < 24; round++) { + uint64_t t; + + /* Theta */ +#if MBEDTLS_SHA3_THETA_UNROLL == 0 //no-check-names + for (i = 0; i < 5; i++) { + lane[i] = s[i] ^ s[i + 5] ^ s[i + 10] ^ s[i + 15] ^ s[i + 20]; + } + for (i = 0; i < 5; i++) { + t = lane[(i + 4) % 5] ^ ROTR64(lane[(i + 1) % 5], 63); + s[i] ^= t; s[i + 5] ^= t; s[i + 10] ^= t; s[i + 15] ^= t; s[i + 20] ^= t; + } +#else + lane[0] = s[0] ^ s[5] ^ s[10] ^ s[15] ^ s[20]; + lane[1] = s[1] ^ s[6] ^ s[11] ^ s[16] ^ s[21]; + lane[2] = s[2] ^ s[7] ^ s[12] ^ s[17] ^ s[22]; + lane[3] = s[3] ^ s[8] ^ s[13] ^ s[18] ^ s[23]; + lane[4] = s[4] ^ s[9] ^ s[14] ^ s[19] ^ s[24]; + + t = lane[4] ^ ROTR64(lane[1], 63); + s[0] ^= t; s[5] ^= t; s[10] ^= t; s[15] ^= t; s[20] ^= t; + + t = lane[0] ^ ROTR64(lane[2], 63); + s[1] ^= t; s[6] ^= t; s[11] ^= t; s[16] ^= t; s[21] ^= t; + + t = lane[1] ^ ROTR64(lane[3], 63); + s[2] ^= t; s[7] ^= t; s[12] ^= t; s[17] ^= t; s[22] ^= t; + + t = lane[2] ^ ROTR64(lane[4], 63); + s[3] ^= t; s[8] ^= t; s[13] ^= t; s[18] ^= t; s[23] ^= t; + + t = lane[3] ^ ROTR64(lane[0], 63); + s[4] ^= t; s[9] ^= t; s[14] ^= t; s[19] ^= t; s[24] ^= t; +#endif + + /* Rho */ + for (i = 1; i < 25; i += 4) { + uint32_t r = rho[(i - 1) >> 2]; +#if MBEDTLS_SHA3_RHO_UNROLL == 0 + for (int j = i; j < i + 4; j++) { + uint8_t r8 = (uint8_t) (r >> 24); + r <<= 8; + s[j] = ROTR64(s[j], r8); + } +#else + s[i + 0] = ROTR64(s[i + 0], MBEDTLS_BYTE_3(r)); + s[i + 1] = ROTR64(s[i + 1], MBEDTLS_BYTE_2(r)); + s[i + 2] = ROTR64(s[i + 2], MBEDTLS_BYTE_1(r)); + s[i + 3] = ROTR64(s[i + 3], MBEDTLS_BYTE_0(r)); +#endif + } + + /* Pi */ + t = s[1]; +#if MBEDTLS_SHA3_PI_UNROLL == 0 + for (i = 0; i < 24; i += 4) { + uint32_t p = pi[i >> 2]; + for (unsigned j = 0; j < 4; j++) { + SWAP(s[p & 0xff], t); + p >>= 8; + } + } +#else + uint32_t p = pi[0]; + SWAP(s[MBEDTLS_BYTE_0(p)], t); SWAP(s[MBEDTLS_BYTE_1(p)], t); + SWAP(s[MBEDTLS_BYTE_2(p)], t); SWAP(s[MBEDTLS_BYTE_3(p)], t); + p = pi[1]; + SWAP(s[MBEDTLS_BYTE_0(p)], t); SWAP(s[MBEDTLS_BYTE_1(p)], t); + SWAP(s[MBEDTLS_BYTE_2(p)], t); SWAP(s[MBEDTLS_BYTE_3(p)], t); + p = pi[2]; + SWAP(s[MBEDTLS_BYTE_0(p)], t); SWAP(s[MBEDTLS_BYTE_1(p)], t); + SWAP(s[MBEDTLS_BYTE_2(p)], t); SWAP(s[MBEDTLS_BYTE_3(p)], t); + p = pi[3]; + SWAP(s[MBEDTLS_BYTE_0(p)], t); SWAP(s[MBEDTLS_BYTE_1(p)], t); + SWAP(s[MBEDTLS_BYTE_2(p)], t); SWAP(s[MBEDTLS_BYTE_3(p)], t); + p = pi[4]; + SWAP(s[MBEDTLS_BYTE_0(p)], t); SWAP(s[MBEDTLS_BYTE_1(p)], t); + SWAP(s[MBEDTLS_BYTE_2(p)], t); SWAP(s[MBEDTLS_BYTE_3(p)], t); + p = pi[5]; + SWAP(s[MBEDTLS_BYTE_0(p)], t); SWAP(s[MBEDTLS_BYTE_1(p)], t); + SWAP(s[MBEDTLS_BYTE_2(p)], t); SWAP(s[MBEDTLS_BYTE_3(p)], t); +#endif + + /* Chi */ +#if MBEDTLS_SHA3_CHI_UNROLL == 0 //no-check-names + for (i = 0; i <= 20; i += 5) { + lane[0] = s[i]; lane[1] = s[i + 1]; lane[2] = s[i + 2]; + lane[3] = s[i + 3]; lane[4] = s[i + 4]; + s[i + 0] ^= (~lane[1]) & lane[2]; + s[i + 1] ^= (~lane[2]) & lane[3]; + s[i + 2] ^= (~lane[3]) & lane[4]; + s[i + 3] ^= (~lane[4]) & lane[0]; + s[i + 4] ^= (~lane[0]) & lane[1]; + } +#else + lane[0] = s[0]; lane[1] = s[1]; lane[2] = s[2]; lane[3] = s[3]; lane[4] = s[4]; + s[0] ^= (~lane[1]) & lane[2]; + s[1] ^= (~lane[2]) & lane[3]; + s[2] ^= (~lane[3]) & lane[4]; + s[3] ^= (~lane[4]) & lane[0]; + s[4] ^= (~lane[0]) & lane[1]; + + lane[0] = s[5]; lane[1] = s[6]; lane[2] = s[7]; lane[3] = s[8]; lane[4] = s[9]; + s[5] ^= (~lane[1]) & lane[2]; + s[6] ^= (~lane[2]) & lane[3]; + s[7] ^= (~lane[3]) & lane[4]; + s[8] ^= (~lane[4]) & lane[0]; + s[9] ^= (~lane[0]) & lane[1]; + + lane[0] = s[10]; lane[1] = s[11]; lane[2] = s[12]; lane[3] = s[13]; lane[4] = s[14]; + s[10] ^= (~lane[1]) & lane[2]; + s[11] ^= (~lane[2]) & lane[3]; + s[12] ^= (~lane[3]) & lane[4]; + s[13] ^= (~lane[4]) & lane[0]; + s[14] ^= (~lane[0]) & lane[1]; + + lane[0] = s[15]; lane[1] = s[16]; lane[2] = s[17]; lane[3] = s[18]; lane[4] = s[19]; + s[15] ^= (~lane[1]) & lane[2]; + s[16] ^= (~lane[2]) & lane[3]; + s[17] ^= (~lane[3]) & lane[4]; + s[18] ^= (~lane[4]) & lane[0]; + s[19] ^= (~lane[0]) & lane[1]; + + lane[0] = s[20]; lane[1] = s[21]; lane[2] = s[22]; lane[3] = s[23]; lane[4] = s[24]; + s[20] ^= (~lane[1]) & lane[2]; + s[21] ^= (~lane[2]) & lane[3]; + s[22] ^= (~lane[3]) & lane[4]; + s[23] ^= (~lane[4]) & lane[0]; + s[24] ^= (~lane[0]) & lane[1]; +#endif + + /* Iota */ + /* Decompress the round masks (see definition of rc) */ + s[0] ^= ((iota_r_packed[round] & 0x40ull) << 57 | + (iota_r_packed[round] & 0x20ull) << 26 | + (iota_r_packed[round] & 0x10ull) << 11 | + (iota_r_packed[round] & 0x8f)); + } +} + +void mbedtls_sha3_init(mbedtls_sha3_context *ctx) +{ + memset(ctx, 0, sizeof(mbedtls_sha3_context)); +} + +void mbedtls_sha3_free(mbedtls_sha3_context *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_sha3_context)); +} + +void mbedtls_sha3_clone(mbedtls_sha3_context *dst, + const mbedtls_sha3_context *src) +{ + *dst = *src; +} + +/* + * SHA-3 context setup + */ +int mbedtls_sha3_starts(mbedtls_sha3_context *ctx, mbedtls_sha3_id id) +{ + /* Clean up in case the context is being reused */ + memset(ctx, 0, sizeof(*ctx)); + + switch (id) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) + case MBEDTLS_SHA3_224: + ctx->olen = 224 / 8; + ctx->max_block_size = 1152 / 8; + break; +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) + case MBEDTLS_SHA3_256: + ctx->olen = 256 / 8; + ctx->max_block_size = 1088 / 8; + break; +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) + case MBEDTLS_SHA3_384: + ctx->olen = 384 / 8; + ctx->max_block_size = 832 / 8; + break; +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512) + case MBEDTLS_SHA3_512: + ctx->olen = 512 / 8; + ctx->max_block_size = 576 / 8; + break; +#endif + +#if defined(MBEDTLS_SHA3_WANT_SHAKE128) + case MBEDTLS_SHA3_SHAKE128: + ctx->max_block_size = 1344 / 8; + break; +#endif + +#if defined(MBEDTLS_SHA3_WANT_SHAKE256) + case MBEDTLS_SHA3_SHAKE256: + ctx->max_block_size = 1088 / 8; + break; +#endif + + default: + return MBEDTLS_ERR_SHA3_BAD_INPUT_DATA; + } + + return 0; +} + +/* + * SHA-3 process buffer + */ +int mbedtls_sha3_update(mbedtls_sha3_context *ctx, + const uint8_t *input, + size_t ilen) +{ + if (ilen >= 8) { + // 8-byte align index + int align_bytes = 8 - (ctx->index % 8); + if (align_bytes) { + for (; align_bytes > 0; align_bytes--) { + ABSORB(ctx, ctx->index, *input++); + ilen--; + ctx->index++; + } + if ((ctx->index = ctx->index % ctx->max_block_size) == 0) { + keccak_f1600(ctx); + } + } + + // process input in 8-byte chunks + while (ilen >= 8) { + ABSORB(ctx, ctx->index, MBEDTLS_GET_UINT64_LE(input, 0)); + input += 8; + ilen -= 8; + if ((ctx->index = (ctx->index + 8) % ctx->max_block_size) == 0) { + keccak_f1600(ctx); + } + } + } + + // handle remaining bytes + while (ilen-- > 0) { + ABSORB(ctx, ctx->index, *input++); + if ((ctx->index = (ctx->index + 1) % ctx->max_block_size) == 0) { + keccak_f1600(ctx); + } + } + + return 0; +} + +int mbedtls_sha3_finish(mbedtls_sha3_context *ctx, + uint8_t *output, size_t olen) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + uint8_t xor_byte; + + /* Catch SHA-3 families, with fixed output length */ + if (ctx->olen > 0) { + if (ctx->olen > olen) { + ret = MBEDTLS_ERR_SHA3_BAD_INPUT_DATA; + goto exit; + } + olen = ctx->olen; + xor_byte = SHA3_XOR_BYTE; + } else { + xor_byte = SHAKE_XOR_BYTE; + } + + if (ctx->finished == 0) { + ABSORB(ctx, ctx->index, xor_byte); + ABSORB(ctx, ctx->max_block_size - 1, 0x80); + keccak_f1600(ctx); + ctx->index = 0; + ctx->finished = 1; + } + + while (olen-- > 0) { + *output++ = SQUEEZE(ctx, ctx->index); + + if ((ctx->index = (ctx->index + 1) % ctx->max_block_size) == 0) { + keccak_f1600(ctx); + } + } + + /* If there is a fixed output length (SHA3), we only accept a single call + * to finish(), and have it clean up the context. If the output length is + * variable (SHAKE), leave the context ready for further finish() calls. */ + if (ctx->olen > 0) { + ret = 0; + goto exit; + } + + return 0; + +exit: + mbedtls_sha3_free(ctx); + return ret; +} + +/* + * output = SHA-3( input buffer ) + */ +int mbedtls_sha3(mbedtls_sha3_id id, const uint8_t *input, + size_t ilen, uint8_t *output, size_t olen) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_sha3_context ctx; + + mbedtls_sha3_init(&ctx); + + /* Sanity checks are performed in every mbedtls_sha3_xxx() */ + if ((ret = mbedtls_sha3_starts(&ctx, id)) != 0) { + goto exit; + } + + if ((ret = mbedtls_sha3_update(&ctx, input, ilen)) != 0) { + goto exit; + } + + if ((ret = mbedtls_sha3_finish(&ctx, output, olen)) != 0) { + goto exit; + } + +exit: + mbedtls_sha3_free(&ctx); + + return ret; +} + +/**************** Self-tests ****************/ + +#if defined(MBEDTLS_SELF_TEST) + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_SOME_HASH) + +static const unsigned char test_data[2][4] = +{ + "", + "abc", +}; + +static const size_t test_data_len[2] = +{ + 0, /* "" */ + 3 /* "abc" */ +}; + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) +static const unsigned char test_hash_sha3_224[2][28] = +{ + { /* "" */ + 0x6B, 0x4E, 0x03, 0x42, 0x36, 0x67, 0xDB, 0xB7, + 0x3B, 0x6E, 0x15, 0x45, 0x4F, 0x0E, 0xB1, 0xAB, + 0xD4, 0x59, 0x7F, 0x9A, 0x1B, 0x07, 0x8E, 0x3F, + 0x5B, 0x5A, 0x6B, 0xC7 + }, + { /* "abc" */ + 0xE6, 0x42, 0x82, 0x4C, 0x3F, 0x8C, 0xF2, 0x4A, + 0xD0, 0x92, 0x34, 0xEE, 0x7D, 0x3C, 0x76, 0x6F, + 0xC9, 0xA3, 0xA5, 0x16, 0x8D, 0x0C, 0x94, 0xAD, + 0x73, 0xB4, 0x6F, 0xDF + } +}; +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) +static const unsigned char test_hash_sha3_256[2][32] = +{ + { /* "" */ + 0xA7, 0xFF, 0xC6, 0xF8, 0xBF, 0x1E, 0xD7, 0x66, + 0x51, 0xC1, 0x47, 0x56, 0xA0, 0x61, 0xD6, 0x62, + 0xF5, 0x80, 0xFF, 0x4D, 0xE4, 0x3B, 0x49, 0xFA, + 0x82, 0xD8, 0x0A, 0x4B, 0x80, 0xF8, 0x43, 0x4A + }, + { /* "abc" */ + 0x3A, 0x98, 0x5D, 0xA7, 0x4F, 0xE2, 0x25, 0xB2, + 0x04, 0x5C, 0x17, 0x2D, 0x6B, 0xD3, 0x90, 0xBD, + 0x85, 0x5F, 0x08, 0x6E, 0x3E, 0x9D, 0x52, 0x5B, + 0x46, 0xBF, 0xE2, 0x45, 0x11, 0x43, 0x15, 0x32 + } +}; +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) +static const unsigned char test_hash_sha3_384[2][48] = +{ + { /* "" */ + 0x0C, 0x63, 0xA7, 0x5B, 0x84, 0x5E, 0x4F, 0x7D, + 0x01, 0x10, 0x7D, 0x85, 0x2E, 0x4C, 0x24, 0x85, + 0xC5, 0x1A, 0x50, 0xAA, 0xAA, 0x94, 0xFC, 0x61, + 0x99, 0x5E, 0x71, 0xBB, 0xEE, 0x98, 0x3A, 0x2A, + 0xC3, 0x71, 0x38, 0x31, 0x26, 0x4A, 0xDB, 0x47, + 0xFB, 0x6B, 0xD1, 0xE0, 0x58, 0xD5, 0xF0, 0x04 + }, + { /* "abc" */ + 0xEC, 0x01, 0x49, 0x82, 0x88, 0x51, 0x6F, 0xC9, + 0x26, 0x45, 0x9F, 0x58, 0xE2, 0xC6, 0xAD, 0x8D, + 0xF9, 0xB4, 0x73, 0xCB, 0x0F, 0xC0, 0x8C, 0x25, + 0x96, 0xDA, 0x7C, 0xF0, 0xE4, 0x9B, 0xE4, 0xB2, + 0x98, 0xD8, 0x8C, 0xEA, 0x92, 0x7A, 0xC7, 0xF5, + 0x39, 0xF1, 0xED, 0xF2, 0x28, 0x37, 0x6D, 0x25 + } +}; +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512) +static const unsigned char test_hash_sha3_512[2][64] = +{ + { /* "" */ + 0xA6, 0x9F, 0x73, 0xCC, 0xA2, 0x3A, 0x9A, 0xC5, + 0xC8, 0xB5, 0x67, 0xDC, 0x18, 0x5A, 0x75, 0x6E, + 0x97, 0xC9, 0x82, 0x16, 0x4F, 0xE2, 0x58, 0x59, + 0xE0, 0xD1, 0xDC, 0xC1, 0x47, 0x5C, 0x80, 0xA6, + 0x15, 0xB2, 0x12, 0x3A, 0xF1, 0xF5, 0xF9, 0x4C, + 0x11, 0xE3, 0xE9, 0x40, 0x2C, 0x3A, 0xC5, 0x58, + 0xF5, 0x00, 0x19, 0x9D, 0x95, 0xB6, 0xD3, 0xE3, + 0x01, 0x75, 0x85, 0x86, 0x28, 0x1D, 0xCD, 0x26 + }, + { /* "abc" */ + 0xB7, 0x51, 0x85, 0x0B, 0x1A, 0x57, 0x16, 0x8A, + 0x56, 0x93, 0xCD, 0x92, 0x4B, 0x6B, 0x09, 0x6E, + 0x08, 0xF6, 0x21, 0x82, 0x74, 0x44, 0xF7, 0x0D, + 0x88, 0x4F, 0x5D, 0x02, 0x40, 0xD2, 0x71, 0x2E, + 0x10, 0xE1, 0x16, 0xE9, 0x19, 0x2A, 0xF3, 0xC9, + 0x1A, 0x7E, 0xC5, 0x76, 0x47, 0xE3, 0x93, 0x40, + 0x57, 0x34, 0x0B, 0x4C, 0xF4, 0x08, 0xD5, 0xA5, + 0x65, 0x92, 0xF8, 0x27, 0x4E, 0xEC, 0x53, 0xF0 + } +}; +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) +static const unsigned char long_kat_hash_sha3_224[28] = +{ + 0xD6, 0x93, 0x35, 0xB9, 0x33, 0x25, 0x19, 0x2E, + 0x51, 0x6A, 0x91, 0x2E, 0x6D, 0x19, 0xA1, 0x5C, + 0xB5, 0x1C, 0x6E, 0xD5, 0xC1, 0x52, 0x43, 0xE7, + 0xA7, 0xFD, 0x65, 0x3C +}; +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) +static const unsigned char long_kat_hash_sha3_256[32] = +{ + 0x5C, 0x88, 0x75, 0xAE, 0x47, 0x4A, 0x36, 0x34, + 0xBA, 0x4F, 0xD5, 0x5E, 0xC8, 0x5B, 0xFF, 0xD6, + 0x61, 0xF3, 0x2A, 0xCA, 0x75, 0xC6, 0xD6, 0x99, + 0xD0, 0xCD, 0xCB, 0x6C, 0x11, 0x58, 0x91, 0xC1 +}; +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) +static const unsigned char long_kat_hash_sha3_384[48] = +{ + 0xEE, 0xE9, 0xE2, 0x4D, 0x78, 0xC1, 0x85, 0x53, + 0x37, 0x98, 0x34, 0x51, 0xDF, 0x97, 0xC8, 0xAD, + 0x9E, 0xED, 0xF2, 0x56, 0xC6, 0x33, 0x4F, 0x8E, + 0x94, 0x8D, 0x25, 0x2D, 0x5E, 0x0E, 0x76, 0x84, + 0x7A, 0xA0, 0x77, 0x4D, 0xDB, 0x90, 0xA8, 0x42, + 0x19, 0x0D, 0x2C, 0x55, 0x8B, 0x4B, 0x83, 0x40 +}; +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512) +static const unsigned char long_kat_hash_sha3_512[64] = +{ + 0x3C, 0x3A, 0x87, 0x6D, 0xA1, 0x40, 0x34, 0xAB, + 0x60, 0x62, 0x7C, 0x07, 0x7B, 0xB9, 0x8F, 0x7E, + 0x12, 0x0A, 0x2A, 0x53, 0x70, 0x21, 0x2D, 0xFF, + 0xB3, 0x38, 0x5A, 0x18, 0xD4, 0xF3, 0x88, 0x59, + 0xED, 0x31, 0x1D, 0x0A, 0x9D, 0x51, 0x41, 0xCE, + 0x9C, 0xC5, 0xC6, 0x6E, 0xE6, 0x89, 0xB2, 0x66, + 0xA8, 0xAA, 0x18, 0xAC, 0xE8, 0x28, 0x2A, 0x0E, + 0x0D, 0xB5, 0x96, 0xC9, 0x0B, 0x0A, 0x7B, 0x87 +}; +#endif + +static int mbedtls_sha3_kat_test(int verbose, + const char *type_name, + mbedtls_sha3_id id, + int test_num) +{ + uint8_t hash[64]; + int result; + + result = mbedtls_sha3(id, + test_data[test_num], test_data_len[test_num], + hash, sizeof(hash)); + if (result != 0) { + if (verbose != 0) { + mbedtls_printf(" %s test %d error code: %d\n", + type_name, test_num, result); + } + + return result; + } + + switch (id) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) + case MBEDTLS_SHA3_224: + result = memcmp(hash, test_hash_sha3_224[test_num], 28); + break; +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) + case MBEDTLS_SHA3_256: + result = memcmp(hash, test_hash_sha3_256[test_num], 32); + break; +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) + case MBEDTLS_SHA3_384: + result = memcmp(hash, test_hash_sha3_384[test_num], 48); + break; +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512) + case MBEDTLS_SHA3_512: + result = memcmp(hash, test_hash_sha3_512[test_num], 64); + break; +#endif + default: + break; + } + + if (0 != result) { + if (verbose != 0) { + mbedtls_printf(" %s test %d failed\n", type_name, test_num); + } + + return -1; + } + + if (verbose != 0) { + mbedtls_printf(" %s test %d passed\n", type_name, test_num); + } + + return 0; +} + +static int mbedtls_sha3_long_kat_test(int verbose, + const char *type_name, + mbedtls_sha3_id id) +{ + mbedtls_sha3_context ctx; + unsigned char buffer[1000]; + unsigned char hash[64]; + int result = 0; + + memset(buffer, 'a', 1000); + + if (verbose != 0) { + mbedtls_printf(" %s long KAT test ", type_name); + } + + mbedtls_sha3_init(&ctx); + + result = mbedtls_sha3_starts(&ctx, id); + if (result != 0) { + if (verbose != 0) { + mbedtls_printf("setup failed\n "); + } + } + + /* Process 1,000,000 (one million) 'a' characters */ + for (int i = 0; i < 1000; i++) { + result = mbedtls_sha3_update(&ctx, buffer, 1000); + if (result != 0) { + if (verbose != 0) { + mbedtls_printf("update error code: %i\n", result); + } + + goto cleanup; + } + } + + result = mbedtls_sha3_finish(&ctx, hash, sizeof(hash)); + if (result != 0) { + if (verbose != 0) { + mbedtls_printf("finish error code: %d\n", result); + } + + goto cleanup; + } + + switch (id) { +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) + case MBEDTLS_SHA3_224: + result = memcmp(hash, long_kat_hash_sha3_224, 28); + break; +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) + case MBEDTLS_SHA3_256: + result = memcmp(hash, long_kat_hash_sha3_256, 32); + break; +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) + case MBEDTLS_SHA3_384: + result = memcmp(hash, long_kat_hash_sha3_384, 48); + break; +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512) + case MBEDTLS_SHA3_512: + result = memcmp(hash, long_kat_hash_sha3_512, 64); + break; +#endif + default: + break; + } + + if (result != 0) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + +cleanup: + mbedtls_sha3_free(&ctx); + return result; +} + +#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_SOME_HASH) */ + +#if defined(MBEDTLS_SHA3_WANT_SHAKE128) +static const unsigned char shake128_test_input[2][16] = +{ + { + 0xD4, 0xD6, 0x7B, 0x00, 0xCA, 0x51, 0x39, 0x77, + 0x91, 0xB8, 0x12, 0x05, 0xD5, 0x58, 0x2C, 0x0A + }, + { + 0xCC, 0x0A, 0x93, 0x9D, 0x40, 0xFE, 0xFD, 0xC6, + 0xC9, 0x9A, 0xCF, 0xA3, 0x7D, 0xE1, 0x0D, 0xF6 + } +}; + +static const unsigned char shake128_test_output[2][16] = +{ + { + 0xD0, 0xAC, 0xFB, 0x2A, 0x14, 0x92, 0x8C, 0xAF, + 0x8C, 0x16, 0x8A, 0xE5, 0x14, 0x92, 0x5E, 0x4E + }, + { + 0xB7, 0x0B, 0x72, 0x4A, 0x91, 0xBA, 0x86, 0x5E, + 0xF4, 0x34, 0xF8, 0x50, 0x48, 0x50, 0x48, 0x91 + } +}; +#endif + +#if defined(MBEDTLS_SHA3_WANT_SHAKE256) +static const unsigned char shake256_test_input[2][32] = +{ + { + 0xEF, 0x89, 0x6C, 0xDC, 0xB3, 0x63, 0xA6, 0x15, + 0x91, 0x78, 0xA1, 0xBB, 0x1C, 0x99, 0x39, 0x46, + 0xC5, 0x04, 0x02, 0x09, 0x5C, 0xDA, 0xEA, 0x4F, + 0xD4, 0xD4, 0x19, 0xAA, 0x47, 0x32, 0x1C, 0x88 + }, + { + 0x76, 0x89, 0x1A, 0x7B, 0xCC, 0x6C, 0x04, 0x49, + 0x00, 0x35, 0xB7, 0x43, 0x15, 0x2F, 0x64, 0xA8, + 0xDD, 0x2E, 0xA1, 0x8A, 0xB4, 0x72, 0xB8, 0xD3, + 0x6E, 0xCF, 0x45, 0x85, 0x8D, 0x0B, 0x00, 0x46 + } +}; + +static const unsigned char shake256_test_output[2][32] = +{ + { + 0x7A, 0xBB, 0xA4, 0xE8, 0xB8, 0xDD, 0x76, 0x6B, + 0xBA, 0xBE, 0x98, 0xF8, 0xF1, 0x69, 0xCB, 0x62, + 0x08, 0x67, 0x4D, 0xE1, 0x9A, 0x51, 0xD7, 0x3C, + 0x92, 0xB7, 0xDC, 0x04, 0xA4, 0xB5, 0xEE, 0x3D + }, + { + 0xE8, 0x44, 0x7D, 0xF8, 0x7D, 0x01, 0xBE, 0xEB, + 0x72, 0x4C, 0x9A, 0x2A, 0x38, 0xAB, 0x00, 0xFC, + 0xC2, 0x4E, 0x9B, 0xD1, 0x78, 0x60, 0xE6, 0x73, + 0xB0, 0x21, 0x22, 0x2D, 0x62, 0x1A, 0x78, 0x10 + } +}; +#endif + +#if defined(MBEDTLS_SHA3_WANT_SHAKE128) || defined(MBEDTLS_SHA3_WANT_SHAKE256) +static int mbedtls_shake_self_test(int verbose) +{ + uint8_t output[32]; + int i; + int result; + + for (i = 0; i < 2; i++) { +#if defined(MBEDTLS_SHA3_WANT_SHAKE128) + if (verbose != 0) { + mbedtls_printf(" SHAKE128 test %d ", i); + } + result = mbedtls_sha3(MBEDTLS_SHA3_SHAKE128, + shake128_test_input[i], 16, + output, 16); + if (result != 0) { + if (verbose != 0) { + mbedtls_printf("error code: %d\n", result); + } + return -1; + } + if (0 != memcmp(shake128_test_output[i], output, 16)) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + return -1; + } + if (verbose != 0) { + mbedtls_printf("passed\n"); + } +#endif + +#if defined(MBEDTLS_SHA3_WANT_SHAKE256) + if (verbose != 0) { + mbedtls_printf(" SHAKE256 test %d ", i); + } + result = mbedtls_sha3(MBEDTLS_SHA3_SHAKE256, + shake256_test_input[i], 32, + output, 32); + if (result != 0) { + if (verbose != 0) { + mbedtls_printf("error code: %d\n", result); + } + return -1; + } + if (0 != memcmp(shake256_test_output[i], output, 32)) { + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + return -1; + } + if (verbose != 0) { + mbedtls_printf("passed\n"); + } +#endif + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + return 0; +} +#endif + +int mbedtls_sha3_self_test(int verbose) +{ + int i; + + /* SHA-3 Known Answer Tests (KAT) */ + for (i = 0; i < 2; i++) { + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) + if (0 != mbedtls_sha3_kat_test(verbose, + "SHA3-224", MBEDTLS_SHA3_224, i)) { + return 1; + } +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) + if (0 != mbedtls_sha3_kat_test(verbose, + "SHA3-256", MBEDTLS_SHA3_256, i)) { + return 1; + } +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) + if (0 != mbedtls_sha3_kat_test(verbose, + "SHA3-384", MBEDTLS_SHA3_384, i)) { + return 1; + } +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512) + if (0 != mbedtls_sha3_kat_test(verbose, + "SHA3-512", MBEDTLS_SHA3_512, i)) { + return 1; + } +#endif + } + + /* SHA-3 long KAT tests */ +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) + if (0 != mbedtls_sha3_long_kat_test(verbose, + "SHA3-224", MBEDTLS_SHA3_224)) { + return 1; + } +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) + if (0 != mbedtls_sha3_long_kat_test(verbose, + "SHA3-256", MBEDTLS_SHA3_256)) { + return 1; + } +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) + if (0 != mbedtls_sha3_long_kat_test(verbose, + "SHA3-384", MBEDTLS_SHA3_384)) { + return 1; + } +#endif + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512) + if (0 != mbedtls_sha3_long_kat_test(verbose, + "SHA3-512", MBEDTLS_SHA3_512)) { + return 1; + } +#endif + if (verbose != 0) { + mbedtls_printf("\n"); + } + +#if defined(MBEDTLS_SHA3_WANT_SHAKE128) || defined(MBEDTLS_SHA3_WANT_SHAKE256) + /* SHAKE tests */ + if (0 != mbedtls_shake_self_test(verbose)) { + return 1; + } +#endif + + return 0; +} +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA3_C */ diff --git a/tf-psa-crypto/drivers/builtin/src/sha512.c b/tf-psa-crypto/drivers/builtin/src/sha512.c new file mode 100644 index 0000000000..36f99bfc47 --- /dev/null +++ b/tf-psa-crypto/drivers/builtin/src/sha512.c @@ -0,0 +1,1089 @@ +/* + * FIPS-180-2 compliant SHA-384/512 implementation + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +/* + * The SHA-512 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#if defined(__aarch64__) && !defined(__ARM_FEATURE_SHA512) && \ + defined(__clang__) && __clang_major__ >= 7 +/* + * The intrinsic declaration are guarded by predefined ACLE macros in clang: + * these are normally only enabled by the -march option on the command line. + * By defining the macros ourselves we gain access to those declarations without + * requiring -march on the command line. + * + * `arm_neon.h` is included by tf_psa_crypto_common.h, so we put these defines + * at the top of this file, before any includes but after the intrinsic + * declaration. This is necessary with + * Clang <=15.x. With Clang 16.0 and above, these macro definitions are + * no longer required, but they're harmless. See + * https://reviews.llvm.org/D131064 + */ +#define __ARM_FEATURE_SHA512 1 +#define MBEDTLS_ENABLE_ARM_SHA3_EXTENSIONS_COMPILER_FLAG +#endif + +#include "tf_psa_crypto_common.h" + +#if defined(MBEDTLS_SHA512_C) || defined(MBEDTLS_SHA384_C) + +#include "mbedtls/private/sha512.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/private/error_common.h" + +#if defined(_MSC_VER) || defined(__WATCOMC__) + #define UL64(x) x##ui64 +#else + #define UL64(x) x##ULL +#endif + +#include + +#include "mbedtls/platform.h" + +#if defined(__aarch64__) +# if defined(MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT) || \ + defined(MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY) +/* *INDENT-OFF* */ +# if !defined(MBEDTLS_HAVE_NEON_INTRINSICS) +# error "Target does not support NEON instructions" +# endif +/* + * Best performance comes from most recent compilers, with intrinsics and -O3. + * Must compile with -march=armv8.2-a+sha3, but we can't detect armv8.2-a, and + * can't always detect __ARM_FEATURE_SHA512 (notably clang 7-12). + * + * GCC < 8 won't work at all (lacks the sha512 instructions) + * GCC >= 8 uses intrinsics, sets __ARM_FEATURE_SHA512 + * + * Clang < 7 won't work at all (lacks the sha512 instructions) + * Clang 7-12 don't have intrinsics (but we work around that with inline + * assembler) or __ARM_FEATURE_SHA512 + * Clang == 13.0.0 same as clang 12 (only seen on macOS) + * Clang >= 13.0.1 has __ARM_FEATURE_SHA512 and intrinsics + */ +# if !defined(__ARM_FEATURE_SHA512) || defined(MBEDTLS_ENABLE_ARM_SHA3_EXTENSIONS_COMPILER_FLAG) + /* Test Clang first, as it defines __GNUC__ */ +# if defined(__ARMCOMPILER_VERSION) +# if __ARMCOMPILER_VERSION < 6090000 +# error "A more recent armclang is required for MBEDTLS_SHA512_USE_A64_CRYPTO_*" +# elif __ARMCOMPILER_VERSION == 6090000 +# error "Must use minimum -march=armv8.2-a+sha3 for MBEDTLS_SHA512_USE_A64_CRYPTO_*" +# else +# pragma clang attribute push (__attribute__((target("sha3"))), apply_to=function) +# define MBEDTLS_POP_TARGET_PRAGMA +# endif +# elif defined(__clang__) +# if __clang_major__ < 7 +# error "A more recent Clang is required for MBEDTLS_SHA512_USE_A64_CRYPTO_*" +# else +# pragma clang attribute push (__attribute__((target("sha3"))), apply_to=function) +# define MBEDTLS_POP_TARGET_PRAGMA +# endif +# elif defined(__GNUC__) +# if __GNUC__ < 8 +# error "A more recent GCC is required for MBEDTLS_SHA512_USE_A64_CRYPTO_*" +# else +# pragma GCC push_options +# pragma GCC target ("arch=armv8.2-a+sha3") +# define MBEDTLS_POP_TARGET_PRAGMA +# endif +# else +# error "Only GCC and Clang supported for MBEDTLS_SHA512_USE_A64_CRYPTO_*" +# endif +# endif +/* *INDENT-ON* */ +# endif +# if defined(MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT) +# if defined(__unix__) +# if defined(__linux__) +/* Our preferred method of detection is getauxval() */ +# include +# if !defined(HWCAP_SHA512) +/* The same header that declares getauxval() should provide the HWCAP_xxx + * constants to analyze its return value. However, the libc may be too + * old to have the constant that we need. So if it's missing, assume that + * the value is the same one used by the Linux kernel ABI. + */ +# define HWCAP_SHA512 (1 << 21) +# endif +# endif +/* Use SIGILL on Unix, and fall back to it on Linux */ +# include +# endif +# endif +#elif !defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64) +# undef MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY +# undef MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT +#endif + +#if defined(MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT) +/* + * Capability detection code comes early, so we can disable + * MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT if no detection mechanism found + */ +#if defined(HWCAP_SHA512) +static int mbedtls_a64_crypto_sha512_determine_support(void) +{ + return (getauxval(AT_HWCAP) & HWCAP_SHA512) ? 1 : 0; +} +#elif defined(__APPLE__) +#include +#include + +static int mbedtls_a64_crypto_sha512_determine_support(void) +{ + int value = 0; + size_t value_len = sizeof(value); + + int ret = sysctlbyname("hw.optional.armv8_2_sha512", &value, &value_len, + NULL, 0); + return ret == 0 && value != 0; +} +#elif defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64) +/* + * As of March 2022, there don't appear to be any PF_ARM_V8_* flags + * available to pass to IsProcessorFeaturePresent() to check for + * SHA-512 support. So we fall back to the C code only. + */ +#if defined(_MSC_VER) +#pragma message "No mechanism to detect A64_CRYPTO found, using C code only" +#else +#warning "No mechanism to detect A64_CRYPTO found, using C code only" +#endif +#elif defined(__unix__) && defined(SIG_SETMASK) +/* Detection with SIGILL, setjmp() and longjmp() */ +#include +#include + +static jmp_buf return_from_sigill; + +/* + * A64 SHA512 support detection via SIGILL + */ +static void sigill_handler(int signal) +{ + (void) signal; + longjmp(return_from_sigill, 1); +} + +static int mbedtls_a64_crypto_sha512_determine_support(void) +{ + struct sigaction old_action, new_action; + + sigset_t old_mask; + if (sigprocmask(0, NULL, &old_mask)) { + return 0; + } + + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = 0; + new_action.sa_handler = sigill_handler; + + sigaction(SIGILL, &new_action, &old_action); + + static int ret = 0; + + if (setjmp(return_from_sigill) == 0) { /* First return only */ + /* If this traps, we will return a second time from setjmp() with 1 */ + asm ("sha512h q0, q0, v0.2d" : : : "v0"); + ret = 1; + } + + sigaction(SIGILL, &old_action, NULL); + sigprocmask(SIG_SETMASK, &old_mask, NULL); + + return ret; +} +#else +#warning "No mechanism to detect A64_CRYPTO found, using C code only" +#undef MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT +#endif /* HWCAP_SHA512, __APPLE__, __unix__ && SIG_SETMASK */ + +#endif /* MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT */ + +#define SHA512_BLOCK_SIZE 128 + +#if defined(MBEDTLS_SHA512_SMALLER) +static void sha512_put_uint64_be(uint64_t n, unsigned char *b, uint8_t i) +{ + MBEDTLS_PUT_UINT64_BE(n, b, i); +} +#else +#define sha512_put_uint64_be MBEDTLS_PUT_UINT64_BE +#endif /* MBEDTLS_SHA512_SMALLER */ + +void mbedtls_sha512_init(mbedtls_sha512_context *ctx) +{ + memset(ctx, 0, sizeof(mbedtls_sha512_context)); +} + +void mbedtls_sha512_free(mbedtls_sha512_context *ctx) +{ + if (ctx == NULL) { + return; + } + + mbedtls_platform_zeroize(ctx, sizeof(mbedtls_sha512_context)); +} + +void mbedtls_sha512_clone(mbedtls_sha512_context *dst, + const mbedtls_sha512_context *src) +{ + *dst = *src; +} + +/* + * SHA-512 context setup + */ +int mbedtls_sha512_starts(mbedtls_sha512_context *ctx, int is384) +{ +#if defined(MBEDTLS_SHA384_C) && defined(MBEDTLS_SHA512_C) + if (is384 != 0 && is384 != 1) { + return MBEDTLS_ERR_SHA512_BAD_INPUT_DATA; + } +#elif defined(MBEDTLS_SHA512_C) + if (is384 != 0) { + return MBEDTLS_ERR_SHA512_BAD_INPUT_DATA; + } +#else /* defined MBEDTLS_SHA384_C only */ + if (is384 == 0) { + return MBEDTLS_ERR_SHA512_BAD_INPUT_DATA; + } +#endif + + ctx->total[0] = 0; + ctx->total[1] = 0; + + if (is384 == 0) { +#if defined(MBEDTLS_SHA512_C) + ctx->state[0] = UL64(0x6A09E667F3BCC908); + ctx->state[1] = UL64(0xBB67AE8584CAA73B); + ctx->state[2] = UL64(0x3C6EF372FE94F82B); + ctx->state[3] = UL64(0xA54FF53A5F1D36F1); + ctx->state[4] = UL64(0x510E527FADE682D1); + ctx->state[5] = UL64(0x9B05688C2B3E6C1F); + ctx->state[6] = UL64(0x1F83D9ABFB41BD6B); + ctx->state[7] = UL64(0x5BE0CD19137E2179); +#endif /* MBEDTLS_SHA512_C */ + } else { +#if defined(MBEDTLS_SHA384_C) + ctx->state[0] = UL64(0xCBBB9D5DC1059ED8); + ctx->state[1] = UL64(0x629A292A367CD507); + ctx->state[2] = UL64(0x9159015A3070DD17); + ctx->state[3] = UL64(0x152FECD8F70E5939); + ctx->state[4] = UL64(0x67332667FFC00B31); + ctx->state[5] = UL64(0x8EB44A8768581511); + ctx->state[6] = UL64(0xDB0C2E0D64F98FA7); + ctx->state[7] = UL64(0x47B5481DBEFA4FA4); +#endif /* MBEDTLS_SHA384_C */ + } + +#if defined(MBEDTLS_SHA384_C) + ctx->is384 = is384; +#endif + + return 0; +} + +/* + * Round constants + */ +static const uint64_t K[80] = +{ + UL64(0x428A2F98D728AE22), UL64(0x7137449123EF65CD), + UL64(0xB5C0FBCFEC4D3B2F), UL64(0xE9B5DBA58189DBBC), + UL64(0x3956C25BF348B538), UL64(0x59F111F1B605D019), + UL64(0x923F82A4AF194F9B), UL64(0xAB1C5ED5DA6D8118), + UL64(0xD807AA98A3030242), UL64(0x12835B0145706FBE), + UL64(0x243185BE4EE4B28C), UL64(0x550C7DC3D5FFB4E2), + UL64(0x72BE5D74F27B896F), UL64(0x80DEB1FE3B1696B1), + UL64(0x9BDC06A725C71235), UL64(0xC19BF174CF692694), + UL64(0xE49B69C19EF14AD2), UL64(0xEFBE4786384F25E3), + UL64(0x0FC19DC68B8CD5B5), UL64(0x240CA1CC77AC9C65), + UL64(0x2DE92C6F592B0275), UL64(0x4A7484AA6EA6E483), + UL64(0x5CB0A9DCBD41FBD4), UL64(0x76F988DA831153B5), + UL64(0x983E5152EE66DFAB), UL64(0xA831C66D2DB43210), + UL64(0xB00327C898FB213F), UL64(0xBF597FC7BEEF0EE4), + UL64(0xC6E00BF33DA88FC2), UL64(0xD5A79147930AA725), + UL64(0x06CA6351E003826F), UL64(0x142929670A0E6E70), + UL64(0x27B70A8546D22FFC), UL64(0x2E1B21385C26C926), + UL64(0x4D2C6DFC5AC42AED), UL64(0x53380D139D95B3DF), + UL64(0x650A73548BAF63DE), UL64(0x766A0ABB3C77B2A8), + UL64(0x81C2C92E47EDAEE6), UL64(0x92722C851482353B), + UL64(0xA2BFE8A14CF10364), UL64(0xA81A664BBC423001), + UL64(0xC24B8B70D0F89791), UL64(0xC76C51A30654BE30), + UL64(0xD192E819D6EF5218), UL64(0xD69906245565A910), + UL64(0xF40E35855771202A), UL64(0x106AA07032BBD1B8), + UL64(0x19A4C116B8D2D0C8), UL64(0x1E376C085141AB53), + UL64(0x2748774CDF8EEB99), UL64(0x34B0BCB5E19B48A8), + UL64(0x391C0CB3C5C95A63), UL64(0x4ED8AA4AE3418ACB), + UL64(0x5B9CCA4F7763E373), UL64(0x682E6FF3D6B2B8A3), + UL64(0x748F82EE5DEFB2FC), UL64(0x78A5636F43172F60), + UL64(0x84C87814A1F0AB72), UL64(0x8CC702081A6439EC), + UL64(0x90BEFFFA23631E28), UL64(0xA4506CEBDE82BDE9), + UL64(0xBEF9A3F7B2C67915), UL64(0xC67178F2E372532B), + UL64(0xCA273ECEEA26619C), UL64(0xD186B8C721C0C207), + UL64(0xEADA7DD6CDE0EB1E), UL64(0xF57D4F7FEE6ED178), + UL64(0x06F067AA72176FBA), UL64(0x0A637DC5A2C898A6), + UL64(0x113F9804BEF90DAE), UL64(0x1B710B35131C471B), + UL64(0x28DB77F523047D84), UL64(0x32CAAB7B40C72493), + UL64(0x3C9EBE0A15C9BEBC), UL64(0x431D67C49C100D4C), + UL64(0x4CC5D4BECB3E42B6), UL64(0x597F299CFC657E2A), + UL64(0x5FCB6FAB3AD6FAEC), UL64(0x6C44198C4A475817) +}; + +#if defined(MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT) || \ + defined(MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY) + +#if defined(MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY) +# define mbedtls_internal_sha512_process_many_a64_crypto mbedtls_internal_sha512_process_many +# define mbedtls_internal_sha512_process_a64_crypto mbedtls_internal_sha512_process +#endif + +/* Accelerated SHA-512 implementation originally written by Simon Tatham for PuTTY, + * under the MIT licence; dual-licensed as Apache 2 with his kind permission. + */ + +#if defined(__clang__) && \ + (__clang_major__ < 13 || \ + (__clang_major__ == 13 && __clang_minor__ == 0 && __clang_patchlevel__ == 0)) +static inline uint64x2_t vsha512su0q_u64(uint64x2_t x, uint64x2_t y) +{ + asm ("sha512su0 %0.2D,%1.2D" : "+w" (x) : "w" (y)); + return x; +} +static inline uint64x2_t vsha512su1q_u64(uint64x2_t x, uint64x2_t y, uint64x2_t z) +{ + asm ("sha512su1 %0.2D,%1.2D,%2.2D" : "+w" (x) : "w" (y), "w" (z)); + return x; +} +static inline uint64x2_t vsha512hq_u64(uint64x2_t x, uint64x2_t y, uint64x2_t z) +{ + asm ("sha512h %0,%1,%2.2D" : "+w" (x) : "w" (y), "w" (z)); + return x; +} +static inline uint64x2_t vsha512h2q_u64(uint64x2_t x, uint64x2_t y, uint64x2_t z) +{ + asm ("sha512h2 %0,%1,%2.2D" : "+w" (x) : "w" (y), "w" (z)); + return x; +} +#endif /* __clang__ etc */ + +static size_t mbedtls_internal_sha512_process_many_a64_crypto( + mbedtls_sha512_context *ctx, const uint8_t *msg, size_t len) +{ + uint64x2_t ab = vld1q_u64(&ctx->state[0]); + uint64x2_t cd = vld1q_u64(&ctx->state[2]); + uint64x2_t ef = vld1q_u64(&ctx->state[4]); + uint64x2_t gh = vld1q_u64(&ctx->state[6]); + + size_t processed = 0; + + for (; + len >= SHA512_BLOCK_SIZE; + processed += SHA512_BLOCK_SIZE, + msg += SHA512_BLOCK_SIZE, + len -= SHA512_BLOCK_SIZE) { + uint64x2_t initial_sum, sum, intermed; + + uint64x2_t ab_orig = ab; + uint64x2_t cd_orig = cd; + uint64x2_t ef_orig = ef; + uint64x2_t gh_orig = gh; + + uint64x2_t s0 = (uint64x2_t) vld1q_u8(msg + 16 * 0); + uint64x2_t s1 = (uint64x2_t) vld1q_u8(msg + 16 * 1); + uint64x2_t s2 = (uint64x2_t) vld1q_u8(msg + 16 * 2); + uint64x2_t s3 = (uint64x2_t) vld1q_u8(msg + 16 * 3); + uint64x2_t s4 = (uint64x2_t) vld1q_u8(msg + 16 * 4); + uint64x2_t s5 = (uint64x2_t) vld1q_u8(msg + 16 * 5); + uint64x2_t s6 = (uint64x2_t) vld1q_u8(msg + 16 * 6); + uint64x2_t s7 = (uint64x2_t) vld1q_u8(msg + 16 * 7); + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ /* assume LE if these not defined; untested on BE */ + s0 = vreinterpretq_u64_u8(vrev64q_u8(vreinterpretq_u8_u64(s0))); + s1 = vreinterpretq_u64_u8(vrev64q_u8(vreinterpretq_u8_u64(s1))); + s2 = vreinterpretq_u64_u8(vrev64q_u8(vreinterpretq_u8_u64(s2))); + s3 = vreinterpretq_u64_u8(vrev64q_u8(vreinterpretq_u8_u64(s3))); + s4 = vreinterpretq_u64_u8(vrev64q_u8(vreinterpretq_u8_u64(s4))); + s5 = vreinterpretq_u64_u8(vrev64q_u8(vreinterpretq_u8_u64(s5))); + s6 = vreinterpretq_u64_u8(vrev64q_u8(vreinterpretq_u8_u64(s6))); + s7 = vreinterpretq_u64_u8(vrev64q_u8(vreinterpretq_u8_u64(s7))); +#endif + + /* Rounds 0 and 1 */ + initial_sum = vaddq_u64(s0, vld1q_u64(&K[0])); + sum = vaddq_u64(vextq_u64(initial_sum, initial_sum, 1), gh); + intermed = vsha512hq_u64(sum, vextq_u64(ef, gh, 1), vextq_u64(cd, ef, 1)); + gh = vsha512h2q_u64(intermed, cd, ab); + cd = vaddq_u64(cd, intermed); + + /* Rounds 2 and 3 */ + initial_sum = vaddq_u64(s1, vld1q_u64(&K[2])); + sum = vaddq_u64(vextq_u64(initial_sum, initial_sum, 1), ef); + intermed = vsha512hq_u64(sum, vextq_u64(cd, ef, 1), vextq_u64(ab, cd, 1)); + ef = vsha512h2q_u64(intermed, ab, gh); + ab = vaddq_u64(ab, intermed); + + /* Rounds 4 and 5 */ + initial_sum = vaddq_u64(s2, vld1q_u64(&K[4])); + sum = vaddq_u64(vextq_u64(initial_sum, initial_sum, 1), cd); + intermed = vsha512hq_u64(sum, vextq_u64(ab, cd, 1), vextq_u64(gh, ab, 1)); + cd = vsha512h2q_u64(intermed, gh, ef); + gh = vaddq_u64(gh, intermed); + + /* Rounds 6 and 7 */ + initial_sum = vaddq_u64(s3, vld1q_u64(&K[6])); + sum = vaddq_u64(vextq_u64(initial_sum, initial_sum, 1), ab); + intermed = vsha512hq_u64(sum, vextq_u64(gh, ab, 1), vextq_u64(ef, gh, 1)); + ab = vsha512h2q_u64(intermed, ef, cd); + ef = vaddq_u64(ef, intermed); + + /* Rounds 8 and 9 */ + initial_sum = vaddq_u64(s4, vld1q_u64(&K[8])); + sum = vaddq_u64(vextq_u64(initial_sum, initial_sum, 1), gh); + intermed = vsha512hq_u64(sum, vextq_u64(ef, gh, 1), vextq_u64(cd, ef, 1)); + gh = vsha512h2q_u64(intermed, cd, ab); + cd = vaddq_u64(cd, intermed); + + /* Rounds 10 and 11 */ + initial_sum = vaddq_u64(s5, vld1q_u64(&K[10])); + sum = vaddq_u64(vextq_u64(initial_sum, initial_sum, 1), ef); + intermed = vsha512hq_u64(sum, vextq_u64(cd, ef, 1), vextq_u64(ab, cd, 1)); + ef = vsha512h2q_u64(intermed, ab, gh); + ab = vaddq_u64(ab, intermed); + + /* Rounds 12 and 13 */ + initial_sum = vaddq_u64(s6, vld1q_u64(&K[12])); + sum = vaddq_u64(vextq_u64(initial_sum, initial_sum, 1), cd); + intermed = vsha512hq_u64(sum, vextq_u64(ab, cd, 1), vextq_u64(gh, ab, 1)); + cd = vsha512h2q_u64(intermed, gh, ef); + gh = vaddq_u64(gh, intermed); + + /* Rounds 14 and 15 */ + initial_sum = vaddq_u64(s7, vld1q_u64(&K[14])); + sum = vaddq_u64(vextq_u64(initial_sum, initial_sum, 1), ab); + intermed = vsha512hq_u64(sum, vextq_u64(gh, ab, 1), vextq_u64(ef, gh, 1)); + ab = vsha512h2q_u64(intermed, ef, cd); + ef = vaddq_u64(ef, intermed); + + for (unsigned int t = 16; t < 80; t += 16) { + /* Rounds t and t + 1 */ + s0 = vsha512su1q_u64(vsha512su0q_u64(s0, s1), s7, vextq_u64(s4, s5, 1)); + initial_sum = vaddq_u64(s0, vld1q_u64(&K[t])); + sum = vaddq_u64(vextq_u64(initial_sum, initial_sum, 1), gh); + intermed = vsha512hq_u64(sum, vextq_u64(ef, gh, 1), vextq_u64(cd, ef, 1)); + gh = vsha512h2q_u64(intermed, cd, ab); + cd = vaddq_u64(cd, intermed); + + /* Rounds t + 2 and t + 3 */ + s1 = vsha512su1q_u64(vsha512su0q_u64(s1, s2), s0, vextq_u64(s5, s6, 1)); + initial_sum = vaddq_u64(s1, vld1q_u64(&K[t + 2])); + sum = vaddq_u64(vextq_u64(initial_sum, initial_sum, 1), ef); + intermed = vsha512hq_u64(sum, vextq_u64(cd, ef, 1), vextq_u64(ab, cd, 1)); + ef = vsha512h2q_u64(intermed, ab, gh); + ab = vaddq_u64(ab, intermed); + + /* Rounds t + 4 and t + 5 */ + s2 = vsha512su1q_u64(vsha512su0q_u64(s2, s3), s1, vextq_u64(s6, s7, 1)); + initial_sum = vaddq_u64(s2, vld1q_u64(&K[t + 4])); + sum = vaddq_u64(vextq_u64(initial_sum, initial_sum, 1), cd); + intermed = vsha512hq_u64(sum, vextq_u64(ab, cd, 1), vextq_u64(gh, ab, 1)); + cd = vsha512h2q_u64(intermed, gh, ef); + gh = vaddq_u64(gh, intermed); + + /* Rounds t + 6 and t + 7 */ + s3 = vsha512su1q_u64(vsha512su0q_u64(s3, s4), s2, vextq_u64(s7, s0, 1)); + initial_sum = vaddq_u64(s3, vld1q_u64(&K[t + 6])); + sum = vaddq_u64(vextq_u64(initial_sum, initial_sum, 1), ab); + intermed = vsha512hq_u64(sum, vextq_u64(gh, ab, 1), vextq_u64(ef, gh, 1)); + ab = vsha512h2q_u64(intermed, ef, cd); + ef = vaddq_u64(ef, intermed); + + /* Rounds t + 8 and t + 9 */ + s4 = vsha512su1q_u64(vsha512su0q_u64(s4, s5), s3, vextq_u64(s0, s1, 1)); + initial_sum = vaddq_u64(s4, vld1q_u64(&K[t + 8])); + sum = vaddq_u64(vextq_u64(initial_sum, initial_sum, 1), gh); + intermed = vsha512hq_u64(sum, vextq_u64(ef, gh, 1), vextq_u64(cd, ef, 1)); + gh = vsha512h2q_u64(intermed, cd, ab); + cd = vaddq_u64(cd, intermed); + + /* Rounds t + 10 and t + 11 */ + s5 = vsha512su1q_u64(vsha512su0q_u64(s5, s6), s4, vextq_u64(s1, s2, 1)); + initial_sum = vaddq_u64(s5, vld1q_u64(&K[t + 10])); + sum = vaddq_u64(vextq_u64(initial_sum, initial_sum, 1), ef); + intermed = vsha512hq_u64(sum, vextq_u64(cd, ef, 1), vextq_u64(ab, cd, 1)); + ef = vsha512h2q_u64(intermed, ab, gh); + ab = vaddq_u64(ab, intermed); + + /* Rounds t + 12 and t + 13 */ + s6 = vsha512su1q_u64(vsha512su0q_u64(s6, s7), s5, vextq_u64(s2, s3, 1)); + initial_sum = vaddq_u64(s6, vld1q_u64(&K[t + 12])); + sum = vaddq_u64(vextq_u64(initial_sum, initial_sum, 1), cd); + intermed = vsha512hq_u64(sum, vextq_u64(ab, cd, 1), vextq_u64(gh, ab, 1)); + cd = vsha512h2q_u64(intermed, gh, ef); + gh = vaddq_u64(gh, intermed); + + /* Rounds t + 14 and t + 15 */ + s7 = vsha512su1q_u64(vsha512su0q_u64(s7, s0), s6, vextq_u64(s3, s4, 1)); + initial_sum = vaddq_u64(s7, vld1q_u64(&K[t + 14])); + sum = vaddq_u64(vextq_u64(initial_sum, initial_sum, 1), ab); + intermed = vsha512hq_u64(sum, vextq_u64(gh, ab, 1), vextq_u64(ef, gh, 1)); + ab = vsha512h2q_u64(intermed, ef, cd); + ef = vaddq_u64(ef, intermed); + } + + ab = vaddq_u64(ab, ab_orig); + cd = vaddq_u64(cd, cd_orig); + ef = vaddq_u64(ef, ef_orig); + gh = vaddq_u64(gh, gh_orig); + } + + vst1q_u64(&ctx->state[0], ab); + vst1q_u64(&ctx->state[2], cd); + vst1q_u64(&ctx->state[4], ef); + vst1q_u64(&ctx->state[6], gh); + + return processed; +} + +static int mbedtls_internal_sha512_process_a64_crypto(mbedtls_sha512_context *ctx, + const unsigned char data[SHA512_BLOCK_SIZE]) +{ + return (mbedtls_internal_sha512_process_many_a64_crypto(ctx, data, + SHA512_BLOCK_SIZE) == + SHA512_BLOCK_SIZE) ? 0 : -1; +} + +#endif /* MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT || MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY */ + +#if defined(MBEDTLS_POP_TARGET_PRAGMA) +#if defined(__clang__) +#pragma clang attribute pop +#elif defined(__GNUC__) +#pragma GCC pop_options +#endif +#undef MBEDTLS_POP_TARGET_PRAGMA +#endif + + +#if !defined(MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT) +#define mbedtls_internal_sha512_process_many_c mbedtls_internal_sha512_process_many +#define mbedtls_internal_sha512_process_c mbedtls_internal_sha512_process +#endif + + +#if !defined(MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY) + +static int mbedtls_internal_sha512_process_c(mbedtls_sha512_context *ctx, + const unsigned char data[SHA512_BLOCK_SIZE]) +{ + int i; + struct { + uint64_t temp1, temp2, W[80]; + uint64_t A[8]; + } local; + +#define SHR(x, n) ((x) >> (n)) +#define ROTR(x, n) (SHR((x), (n)) | ((x) << (64 - (n)))) + +#define S0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7)) +#define S1(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHR(x, 6)) + +#define S2(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39)) +#define S3(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41)) + +#define F0(x, y, z) (((x) & (y)) | ((z) & ((x) | (y)))) +#define F1(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) + +#define P(a, b, c, d, e, f, g, h, x, K) \ + do \ + { \ + local.temp1 = (h) + S3(e) + F1((e), (f), (g)) + (K) + (x); \ + local.temp2 = S2(a) + F0((a), (b), (c)); \ + (d) += local.temp1; (h) = local.temp1 + local.temp2; \ + } while (0) + + for (i = 0; i < 8; i++) { + local.A[i] = ctx->state[i]; + } + +#if defined(MBEDTLS_SHA512_SMALLER) + for (i = 0; i < 80; i++) { + if (i < 16) { + local.W[i] = MBEDTLS_GET_UINT64_BE(data, i << 3); + } else { + local.W[i] = S1(local.W[i - 2]) + local.W[i - 7] + + S0(local.W[i - 15]) + local.W[i - 16]; + } + + P(local.A[0], local.A[1], local.A[2], local.A[3], local.A[4], + local.A[5], local.A[6], local.A[7], local.W[i], K[i]); + + local.temp1 = local.A[7]; local.A[7] = local.A[6]; + local.A[6] = local.A[5]; local.A[5] = local.A[4]; + local.A[4] = local.A[3]; local.A[3] = local.A[2]; + local.A[2] = local.A[1]; local.A[1] = local.A[0]; + local.A[0] = local.temp1; + } +#else /* MBEDTLS_SHA512_SMALLER */ + for (i = 0; i < 16; i++) { + local.W[i] = MBEDTLS_GET_UINT64_BE(data, i << 3); + } + + for (; i < 80; i++) { + local.W[i] = S1(local.W[i - 2]) + local.W[i - 7] + + S0(local.W[i - 15]) + local.W[i - 16]; + } + + i = 0; + do { + P(local.A[0], local.A[1], local.A[2], local.A[3], local.A[4], + local.A[5], local.A[6], local.A[7], local.W[i], K[i]); i++; + P(local.A[7], local.A[0], local.A[1], local.A[2], local.A[3], + local.A[4], local.A[5], local.A[6], local.W[i], K[i]); i++; + P(local.A[6], local.A[7], local.A[0], local.A[1], local.A[2], + local.A[3], local.A[4], local.A[5], local.W[i], K[i]); i++; + P(local.A[5], local.A[6], local.A[7], local.A[0], local.A[1], + local.A[2], local.A[3], local.A[4], local.W[i], K[i]); i++; + P(local.A[4], local.A[5], local.A[6], local.A[7], local.A[0], + local.A[1], local.A[2], local.A[3], local.W[i], K[i]); i++; + P(local.A[3], local.A[4], local.A[5], local.A[6], local.A[7], + local.A[0], local.A[1], local.A[2], local.W[i], K[i]); i++; + P(local.A[2], local.A[3], local.A[4], local.A[5], local.A[6], + local.A[7], local.A[0], local.A[1], local.W[i], K[i]); i++; + P(local.A[1], local.A[2], local.A[3], local.A[4], local.A[5], + local.A[6], local.A[7], local.A[0], local.W[i], K[i]); i++; + } while (i < 80); +#endif /* MBEDTLS_SHA512_SMALLER */ + + for (i = 0; i < 8; i++) { + ctx->state[i] += local.A[i]; + } + + /* Zeroise buffers and variables to clear sensitive data from memory. */ + mbedtls_platform_zeroize(&local, sizeof(local)); + + return 0; +} + +static size_t mbedtls_internal_sha512_process_many_c( + mbedtls_sha512_context *ctx, const uint8_t *data, size_t len) +{ + size_t processed = 0; + + while (len >= SHA512_BLOCK_SIZE) { + if (mbedtls_internal_sha512_process_c(ctx, data) != 0) { + return 0; + } + + data += SHA512_BLOCK_SIZE; + len -= SHA512_BLOCK_SIZE; + + processed += SHA512_BLOCK_SIZE; + } + + return processed; +} + +#endif /* !MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY */ + + +#if defined(MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT) + +static int mbedtls_a64_crypto_sha512_has_support(void) +{ + static int done = 0; + static int supported = 0; + + if (!done) { + supported = mbedtls_a64_crypto_sha512_determine_support(); + done = 1; + } + + return supported; +} + +static size_t mbedtls_internal_sha512_process_many(mbedtls_sha512_context *ctx, + const uint8_t *msg, size_t len) +{ + if (mbedtls_a64_crypto_sha512_has_support()) { + return mbedtls_internal_sha512_process_many_a64_crypto(ctx, msg, len); + } else { + return mbedtls_internal_sha512_process_many_c(ctx, msg, len); + } +} + +static int mbedtls_internal_sha512_process(mbedtls_sha512_context *ctx, + const unsigned char data[SHA512_BLOCK_SIZE]) +{ + if (mbedtls_a64_crypto_sha512_has_support()) { + return mbedtls_internal_sha512_process_a64_crypto(ctx, data); + } else { + return mbedtls_internal_sha512_process_c(ctx, data); + } +} + +#endif /* MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT */ + +/* + * SHA-512 process buffer + */ +int mbedtls_sha512_update(mbedtls_sha512_context *ctx, + const unsigned char *input, + size_t ilen) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t fill; + unsigned int left; + + if (ilen == 0) { + return 0; + } + + left = (unsigned int) (ctx->total[0] & 0x7F); + fill = SHA512_BLOCK_SIZE - left; + + ctx->total[0] += (uint64_t) ilen; + + if (ctx->total[0] < (uint64_t) ilen) { + ctx->total[1]++; + } + + if (left && ilen >= fill) { + memcpy((void *) (ctx->buffer + left), input, fill); + + if ((ret = mbedtls_internal_sha512_process(ctx, ctx->buffer)) != 0) { + return ret; + } + + input += fill; + ilen -= fill; + left = 0; + } + + while (ilen >= SHA512_BLOCK_SIZE) { + size_t processed = + mbedtls_internal_sha512_process_many(ctx, input, ilen); + if (processed < SHA512_BLOCK_SIZE) { + return MBEDTLS_ERR_ERROR_GENERIC_ERROR; + } + + input += processed; + ilen -= processed; + } + + if (ilen > 0) { + memcpy((void *) (ctx->buffer + left), input, ilen); + } + + return 0; +} + +/* + * SHA-512 final digest + */ +int mbedtls_sha512_finish(mbedtls_sha512_context *ctx, + unsigned char *output) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + unsigned used; + uint64_t high, low; + int truncated = 0; + + /* + * Add padding: 0x80 then 0x00 until 16 bytes remain for the length + */ + used = ctx->total[0] & 0x7F; + + ctx->buffer[used++] = 0x80; + + if (used <= 112) { + /* Enough room for padding + length in current block */ + memset(ctx->buffer + used, 0, 112 - used); + } else { + /* We'll need an extra block */ + memset(ctx->buffer + used, 0, SHA512_BLOCK_SIZE - used); + + if ((ret = mbedtls_internal_sha512_process(ctx, ctx->buffer)) != 0) { + goto exit; + } + + memset(ctx->buffer, 0, 112); + } + + /* + * Add message length + */ + high = (ctx->total[0] >> 61) + | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + sha512_put_uint64_be(high, ctx->buffer, 112); + sha512_put_uint64_be(low, ctx->buffer, 120); + + if ((ret = mbedtls_internal_sha512_process(ctx, ctx->buffer)) != 0) { + goto exit; + } + + /* + * Output final state + */ + sha512_put_uint64_be(ctx->state[0], output, 0); + sha512_put_uint64_be(ctx->state[1], output, 8); + sha512_put_uint64_be(ctx->state[2], output, 16); + sha512_put_uint64_be(ctx->state[3], output, 24); + sha512_put_uint64_be(ctx->state[4], output, 32); + sha512_put_uint64_be(ctx->state[5], output, 40); + +#if defined(MBEDTLS_SHA384_C) + truncated = ctx->is384; +#endif + if (!truncated) { + sha512_put_uint64_be(ctx->state[6], output, 48); + sha512_put_uint64_be(ctx->state[7], output, 56); + } + + ret = 0; + +exit: + mbedtls_sha512_free(ctx); + return ret; +} + +/* + * output = SHA-512( input buffer ) + */ +int mbedtls_sha512(const unsigned char *input, + size_t ilen, + unsigned char *output, + int is384) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_sha512_context ctx; + +#if defined(MBEDTLS_SHA384_C) && defined(MBEDTLS_SHA512_C) + if (is384 != 0 && is384 != 1) { + return MBEDTLS_ERR_SHA512_BAD_INPUT_DATA; + } +#elif defined(MBEDTLS_SHA512_C) + if (is384 != 0) { + return MBEDTLS_ERR_SHA512_BAD_INPUT_DATA; + } +#else /* defined MBEDTLS_SHA384_C only */ + if (is384 == 0) { + return MBEDTLS_ERR_SHA512_BAD_INPUT_DATA; + } +#endif + + mbedtls_sha512_init(&ctx); + + if ((ret = mbedtls_sha512_starts(&ctx, is384)) != 0) { + goto exit; + } + + if ((ret = mbedtls_sha512_update(&ctx, input, ilen)) != 0) { + goto exit; + } + + if ((ret = mbedtls_sha512_finish(&ctx, output)) != 0) { + goto exit; + } + +exit: + mbedtls_sha512_free(&ctx); + + return ret; +} + +#if defined(MBEDTLS_SELF_TEST) + +/* + * FIPS-180-2 test vectors + */ +static const unsigned char sha_test_buf[3][113] = +{ + { "abc" }, + { + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" + }, + { "" } +}; + +static const size_t sha_test_buflen[3] = +{ + 3, 112, 1000 +}; + +typedef const unsigned char (sha_test_sum_t)[64]; + +/* + * SHA-384 test vectors + */ +#if defined(MBEDTLS_SHA384_C) +static sha_test_sum_t sha384_test_sum[] = +{ + { 0xCB, 0x00, 0x75, 0x3F, 0x45, 0xA3, 0x5E, 0x8B, + 0xB5, 0xA0, 0x3D, 0x69, 0x9A, 0xC6, 0x50, 0x07, + 0x27, 0x2C, 0x32, 0xAB, 0x0E, 0xDE, 0xD1, 0x63, + 0x1A, 0x8B, 0x60, 0x5A, 0x43, 0xFF, 0x5B, 0xED, + 0x80, 0x86, 0x07, 0x2B, 0xA1, 0xE7, 0xCC, 0x23, + 0x58, 0xBA, 0xEC, 0xA1, 0x34, 0xC8, 0x25, 0xA7 }, + { 0x09, 0x33, 0x0C, 0x33, 0xF7, 0x11, 0x47, 0xE8, + 0x3D, 0x19, 0x2F, 0xC7, 0x82, 0xCD, 0x1B, 0x47, + 0x53, 0x11, 0x1B, 0x17, 0x3B, 0x3B, 0x05, 0xD2, + 0x2F, 0xA0, 0x80, 0x86, 0xE3, 0xB0, 0xF7, 0x12, + 0xFC, 0xC7, 0xC7, 0x1A, 0x55, 0x7E, 0x2D, 0xB9, + 0x66, 0xC3, 0xE9, 0xFA, 0x91, 0x74, 0x60, 0x39 }, + { 0x9D, 0x0E, 0x18, 0x09, 0x71, 0x64, 0x74, 0xCB, + 0x08, 0x6E, 0x83, 0x4E, 0x31, 0x0A, 0x4A, 0x1C, + 0xED, 0x14, 0x9E, 0x9C, 0x00, 0xF2, 0x48, 0x52, + 0x79, 0x72, 0xCE, 0xC5, 0x70, 0x4C, 0x2A, 0x5B, + 0x07, 0xB8, 0xB3, 0xDC, 0x38, 0xEC, 0xC4, 0xEB, + 0xAE, 0x97, 0xDD, 0xD8, 0x7F, 0x3D, 0x89, 0x85 } +}; +#endif /* MBEDTLS_SHA384_C */ + +/* + * SHA-512 test vectors + */ +#if defined(MBEDTLS_SHA512_C) +static sha_test_sum_t sha512_test_sum[] = +{ + { 0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA, + 0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20, 0x41, 0x31, + 0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2, + 0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A, + 0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8, + 0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD, + 0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E, + 0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F }, + { 0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA, + 0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F, + 0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1, + 0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18, + 0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4, + 0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A, + 0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54, + 0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09 }, + { 0xE7, 0x18, 0x48, 0x3D, 0x0C, 0xE7, 0x69, 0x64, + 0x4E, 0x2E, 0x42, 0xC7, 0xBC, 0x15, 0xB4, 0x63, + 0x8E, 0x1F, 0x98, 0xB1, 0x3B, 0x20, 0x44, 0x28, + 0x56, 0x32, 0xA8, 0x03, 0xAF, 0xA9, 0x73, 0xEB, + 0xDE, 0x0F, 0xF2, 0x44, 0x87, 0x7E, 0xA6, 0x0A, + 0x4C, 0xB0, 0x43, 0x2C, 0xE5, 0x77, 0xC3, 0x1B, + 0xEB, 0x00, 0x9C, 0x5C, 0x2C, 0x49, 0xAA, 0x2E, + 0x4E, 0xAD, 0xB2, 0x17, 0xAD, 0x8C, 0xC0, 0x9B } +}; +#endif /* MBEDTLS_SHA512_C */ + +static int mbedtls_sha512_common_self_test(int verbose, int is384) +{ + int i, buflen, ret = 0; + unsigned char *buf; + unsigned char sha512sum[64]; + mbedtls_sha512_context ctx; + +#if defined(MBEDTLS_SHA384_C) && defined(MBEDTLS_SHA512_C) + sha_test_sum_t *sha_test_sum = (is384) ? sha384_test_sum : sha512_test_sum; +#elif defined(MBEDTLS_SHA512_C) + sha_test_sum_t *sha_test_sum = sha512_test_sum; +#else + sha_test_sum_t *sha_test_sum = sha384_test_sum; +#endif + + buf = mbedtls_calloc(1024, sizeof(unsigned char)); + if (NULL == buf) { + if (verbose != 0) { + mbedtls_printf("Buffer allocation failed\n"); + } + + return 1; + } + + mbedtls_sha512_init(&ctx); + + for (i = 0; i < 3; i++) { + if (verbose != 0) { + mbedtls_printf(" SHA-%d test #%d: ", 512 - is384 * 128, i + 1); + } + + if ((ret = mbedtls_sha512_starts(&ctx, is384)) != 0) { + goto fail; + } + + if (i == 2) { + memset(buf, 'a', buflen = 1000); + + for (int j = 0; j < 1000; j++) { + ret = mbedtls_sha512_update(&ctx, buf, buflen); + if (ret != 0) { + goto fail; + } + } + } else { + ret = mbedtls_sha512_update(&ctx, sha_test_buf[i], + sha_test_buflen[i]); + if (ret != 0) { + goto fail; + } + } + + if ((ret = mbedtls_sha512_finish(&ctx, sha512sum)) != 0) { + goto fail; + } + + if (memcmp(sha512sum, sha_test_sum[i], 64 - is384 * 16) != 0) { + ret = 1; + goto fail; + } + + if (verbose != 0) { + mbedtls_printf("passed\n"); + } + } + + if (verbose != 0) { + mbedtls_printf("\n"); + } + + goto exit; + +fail: + if (verbose != 0) { + mbedtls_printf("failed\n"); + } + +exit: + mbedtls_sha512_free(&ctx); + mbedtls_free(buf); + + return ret; +} + +#if defined(MBEDTLS_SHA512_C) +int mbedtls_sha512_self_test(int verbose) +{ + return mbedtls_sha512_common_self_test(verbose, 0); +} +#endif /* MBEDTLS_SHA512_C */ + +#if defined(MBEDTLS_SHA384_C) +int mbedtls_sha384_self_test(int verbose) +{ + return mbedtls_sha512_common_self_test(verbose, 1); +} +#endif /* MBEDTLS_SHA384_C */ + +#undef ARRAY_LENGTH + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA512_C || MBEDTLS_SHA384_C */ diff --git a/tf-psa-crypto/drivers/driver.cmake b/tf-psa-crypto/drivers/driver.cmake new file mode 100644 index 0000000000..6b1e782fec --- /dev/null +++ b/tf-psa-crypto/drivers/driver.cmake @@ -0,0 +1,54 @@ +# CMake module for building drivers. +# This file is meant to be included from the `CMakeLists.txt` of drivers, e.g. +# in `builtin/CMakeLists.txt`. +# +# We do not use it for everest and p256-m for the time being, but it is one +# of the goals of https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/579 to fix +# that. +# +# The driver public headers should be located in the `drivers/*/include` +# directory. +# +# The following variables must be defined by the caller before including this +# module: +# - tf_psa_crypto_driver: the driver name (e.g. "builtin", "libtestdriver1") +# - ${tf_psa_crypto_driver}_src_files: the list of source files for the driver + +set(${tf_psa_crypto_driver}_target ${TF_PSA_CRYPTO_TARGET_PREFIX}${tf_psa_crypto_driver}) +if (USE_STATIC_TF_PSA_CRYPTO_LIBRARY) + set(${tf_psa_crypto_driver}_static_target ${${tf_psa_crypto_driver}_target}) +endif() +set(target_libraries ${${tf_psa_crypto_driver}_target}) +if(USE_STATIC_TF_PSA_CRYPTO_LIBRARY AND USE_SHARED_TF_PSA_CRYPTO_LIBRARY) + string(APPEND ${tf_psa_crypto_driver}_static_target "_static") + list(APPEND target_libraries ${${tf_psa_crypto_driver}_static_target}) +endif() + +foreach (target IN LISTS target_libraries) + add_library(${target} STATIC ${${tf_psa_crypto_driver}_src_files}) + tf_psa_crypto_set_base_compile_options(${target}) + tf_psa_crypto_set_extra_compile_options(${target}) + + target_include_directories(${target} + PUBLIC include + PRIVATE # Add the build-tree include directory before the source-tree one + # so that generated headers in the build tree take precedence. + ${PROJECT_BINARY_DIR}/include + ${PROJECT_SOURCE_DIR}/include + ${TF_PSA_CRYPTO_PRIVATE_INCLUDE_DIRS} + ${TF_PSA_CRYPTO_DRIVERS_INCLUDE_DIRS}) + tf_psa_crypto_set_config_files_compile_definitions(${target}) + if(TF_PSA_CRYPTO_TEST_DRIVER) + add_dependencies(${target} ${TF_PSA_CRYPTO_TEST_DRIVER_GENERATION_TARGETS}) + endif() +endforeach(target) + +if(USE_SHARED_TF_PSA_CRYPTO_LIBRARY) + set_property(TARGET ${${tf_psa_crypto_driver}_target} PROPERTY POSITION_INDEPENDENT_CODE ON) +endif(USE_SHARED_TF_PSA_CRYPTO_LIBRARY) + +if(INSTALL_TF_PSA_CRYPTO_HEADERS) + install(DIRECTORY "include/" + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING PATTERN "*.h") +endif(INSTALL_TF_PSA_CRYPTO_HEADERS) diff --git a/tf-psa-crypto/drivers/everest/.gitignore b/tf-psa-crypto/drivers/everest/.gitignore new file mode 100644 index 0000000000..f3c7a7c5da --- /dev/null +++ b/tf-psa-crypto/drivers/everest/.gitignore @@ -0,0 +1 @@ +Makefile diff --git a/tf-psa-crypto/drivers/everest/CMakeLists.txt b/tf-psa-crypto/drivers/everest/CMakeLists.txt new file mode 100644 index 0000000000..29afacf23d --- /dev/null +++ b/tf-psa-crypto/drivers/everest/CMakeLists.txt @@ -0,0 +1,45 @@ +set(everest_target "${TF_PSA_CRYPTO_TARGET_PREFIX}everest") +if (USE_STATIC_TF_PSA_CRYPTO_LIBRARY) + set(everest_static_target ${everest_target}) +endif() +set(target_libraries ${everest_target}) +if(USE_STATIC_TF_PSA_CRYPTO_LIBRARY AND USE_SHARED_TF_PSA_CRYPTO_LIBRARY) + string(APPEND everest_static_target "_static") + list(APPEND target_libraries ${everest_static_target}) +endif() + +foreach (target IN LISTS target_libraries) + add_library(${target} STATIC + library/x25519.c + library/Hacl_Curve25519_joined.c) + + tf_psa_crypto_set_base_compile_options(${target}) + target_include_directories(${target} + PUBLIC include + PRIVATE # Add the build-tree include directory before the source-tree one + # so that generated headers in the build tree take precedence. + ${PROJECT_BINARY_DIR}/include + ${PROJECT_SOURCE_DIR}/include + ${TF_PSA_CRYPTO_DRIVERS_INCLUDE_DIRS} + include/tf-psa-crypto/private/everest + include/tf-psa-crypto/private/everest/kremlib + ${PROJECT_SOURCE_DIR}/core) + tf_psa_crypto_set_config_files_compile_definitions(${target}) + if(TF_PSA_CRYPTO_TEST_DRIVER) + add_dependencies(${target} ${TF_PSA_CRYPTO_TEST_DRIVER_GENERATION_TARGETS}) + endif() +endforeach(target) + +if(USE_SHARED_TF_PSA_CRYPTO_LIBRARY) + set_property(TARGET ${everest_target} PROPERTY POSITION_INDEPENDENT_CODE ON) +endif(USE_SHARED_TF_PSA_CRYPTO_LIBRARY) + +if(INSTALL_TF_PSA_CRYPTO_HEADERS) + + install(DIRECTORY "include/" + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING + PATTERN "*.h" + ) + +endif(INSTALL_TF_PSA_CRYPTO_HEADERS) diff --git a/tf-psa-crypto/drivers/everest/Makefile.inc b/tf-psa-crypto/drivers/everest/Makefile.inc new file mode 100644 index 0000000000..050b3da91b --- /dev/null +++ b/tf-psa-crypto/drivers/everest/Makefile.inc @@ -0,0 +1,5 @@ +THIRDPARTY_INCLUDES+=-I$(THIRDPARTY_DIR)/everest/include -I$(THIRDPARTY_DIR)/everest/include/tf-psa-crypto/private/everest -I$(THIRDPARTY_DIR)/everest/include/tf-psa-crypto/private/everest/kremlib + +THIRDPARTY_CRYPTO_OBJECTS+= \ + $(THIRDPARTY_DIR)/everest/library/x25519.o \ + $(THIRDPARTY_DIR)/everest/library/Hacl_Curve25519_joined.o diff --git a/tf-psa-crypto/drivers/everest/README.md b/tf-psa-crypto/drivers/everest/README.md new file mode 100644 index 0000000000..bcf12c0c05 --- /dev/null +++ b/tf-psa-crypto/drivers/everest/README.md @@ -0,0 +1,5 @@ +The files in this directory stem from [Project Everest](https://project-everest.github.io/) and are distributed under the Apache 2.0 license. + +This is a formally verified implementation of Curve25519-based handshakes. The C code is automatically derived from the (verified) [original implementation](https://github.com/project-everest/hacl-star/tree/master/code/curve25519) in the [F* language](https://github.com/fstarlang/fstar) by [KreMLin](https://github.com/fstarlang/kremlin). In addition to the improved safety and security of the implementation, it is also significantly faster than the default implementation of Curve25519 in mbedTLS. + +The caveat is that not all platforms are supported, although the version in `everest/library/legacy` should work on most systems. The main issue is that some platforms do not provide a 128-bit integer type and KreMLin therefore has to use additional (also verified) code to simulate them, resulting in less of a performance gain overall. Explicitly supported platforms are currently `x86` and `x86_64` using gcc or clang, and Visual C (2010 and later). diff --git a/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/Hacl_Curve25519.h b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/Hacl_Curve25519.h new file mode 100644 index 0000000000..4178f74dd4 --- /dev/null +++ b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/Hacl_Curve25519.h @@ -0,0 +1,25 @@ +/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. + Licensed under the Apache 2.0 License. */ + +/* This file was generated by KreMLin + * KreMLin invocation: /mnt/e/everest/verify/kremlin/krml -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrcLh -minimal -fbuiltin-uint128 -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrcLh -minimal -I /mnt/e/everest/verify/hacl-star/code/lib/kremlin -I /mnt/e/everest/verify/kremlin/kremlib/compat -I /mnt/e/everest/verify/hacl-star/specs -I /mnt/e/everest/verify/hacl-star/specs/old -I . -ccopt -march=native -verbose -ldopt -flto -tmpdir x25519-c -I ../bignum -bundle Hacl.Curve25519=* -minimal -add-include "kremlib.h" -skip-compilation x25519-c/out.krml -o x25519-c/Hacl_Curve25519.c + * F* version: 059db0c8 + * KreMLin version: 916c37ac + */ + + + +#ifndef TF_PSA_CRYPTO_HACL_CURVE25519_H +#define TF_PSA_CRYPTO_HACL_CURVE25519_H + + +#include "kremlib.h" + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) + +void Hacl_Curve25519_crypto_scalarmult(uint8_t *mypublic, uint8_t *secret, uint8_t *basepoint); + +#endif /* TF_PSA_CRYPTO_HACL_CURVE25519_H */ + +#define __Hacl_Curve25519_H_DEFINED +#endif diff --git a/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlib.h b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlib.h new file mode 100644 index 0000000000..99a005d38f --- /dev/null +++ b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlib.h @@ -0,0 +1,29 @@ +/* + * Copyright 2016-2018 INRIA and Microsoft Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) and + * originated from Project Everest (https://project-everest.github.io/) + */ + +#ifndef TF_PSA_CRYPTO_KREMLIB_H +#define TF_PSA_CRYPTO_KREMLIB_H + +#include "kremlin/internal/target.h" +#include "kremlin/internal/types.h" +#include "kremlin/c_endianness.h" + +#endif /* TF_PSA_CRYPTO_KREMLIB_H */ diff --git a/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlib/FStar_UInt128.h b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlib/FStar_UInt128.h new file mode 100644 index 0000000000..d71c8820bc --- /dev/null +++ b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlib/FStar_UInt128.h @@ -0,0 +1,124 @@ +/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. + Licensed under the Apache 2.0 License. */ + +/* This file was generated by KreMLin + * KreMLin invocation: ../krml -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrB9w -minimal -fparentheses -fcurly-braces -fno-shadow -header copyright-header.txt -minimal -tmpdir dist/uint128 -skip-compilation -extract-uints -add-include -add-include -add-include "kremlin/internal/types.h" -bundle FStar.UInt128=* extracted/prims.krml extracted/FStar_Pervasives_Native.krml extracted/FStar_Pervasives.krml extracted/FStar_Mul.krml extracted/FStar_Squash.krml extracted/FStar_Classical.krml extracted/FStar_StrongExcludedMiddle.krml extracted/FStar_FunctionalExtensionality.krml extracted/FStar_List_Tot_Base.krml extracted/FStar_List_Tot_Properties.krml extracted/FStar_List_Tot.krml extracted/FStar_Seq_Base.krml extracted/FStar_Seq_Properties.krml extracted/FStar_Seq.krml extracted/FStar_Math_Lib.krml extracted/FStar_Math_Lemmas.krml extracted/FStar_BitVector.krml extracted/FStar_UInt.krml extracted/FStar_UInt32.krml extracted/FStar_Int.krml extracted/FStar_Int16.krml extracted/FStar_Preorder.krml extracted/FStar_Ghost.krml extracted/FStar_ErasedLogic.krml extracted/FStar_UInt64.krml extracted/FStar_Set.krml extracted/FStar_PropositionalExtensionality.krml extracted/FStar_PredicateExtensionality.krml extracted/FStar_TSet.krml extracted/FStar_Monotonic_Heap.krml extracted/FStar_Heap.krml extracted/FStar_Map.krml extracted/FStar_Monotonic_HyperHeap.krml extracted/FStar_Monotonic_HyperStack.krml extracted/FStar_HyperStack.krml extracted/FStar_Monotonic_Witnessed.krml extracted/FStar_HyperStack_ST.krml extracted/FStar_HyperStack_All.krml extracted/FStar_Date.krml extracted/FStar_Universe.krml extracted/FStar_GSet.krml extracted/FStar_ModifiesGen.krml extracted/LowStar_Monotonic_Buffer.krml extracted/LowStar_Buffer.krml extracted/Spec_Loops.krml extracted/LowStar_BufferOps.krml extracted/C_Loops.krml extracted/FStar_UInt8.krml extracted/FStar_Kremlin_Endianness.krml extracted/FStar_UInt63.krml extracted/FStar_Exn.krml extracted/FStar_ST.krml extracted/FStar_All.krml extracted/FStar_Dyn.krml extracted/FStar_Int63.krml extracted/FStar_Int64.krml extracted/FStar_Int32.krml extracted/FStar_Int8.krml extracted/FStar_UInt16.krml extracted/FStar_Int_Cast.krml extracted/FStar_UInt128.krml extracted/C_Endianness.krml extracted/FStar_List.krml extracted/FStar_Float.krml extracted/FStar_IO.krml extracted/C.krml extracted/FStar_Char.krml extracted/FStar_String.krml extracted/LowStar_Modifies.krml extracted/C_String.krml extracted/FStar_Bytes.krml extracted/FStar_HyperStack_IO.krml extracted/C_Failure.krml extracted/TestLib.krml extracted/FStar_Int_Cast_Full.krml + * F* version: 059db0c8 + * KreMLin version: 916c37ac + */ + + + +#ifndef __FStar_UInt128_H +#define __FStar_UInt128_H + + +#include +#include +#include "kremlin/internal/types.h" + +uint64_t FStar_UInt128___proj__Mkuint128__item__low(FStar_UInt128_uint128 projectee); + +uint64_t FStar_UInt128___proj__Mkuint128__item__high(FStar_UInt128_uint128 projectee); + +typedef FStar_UInt128_uint128 FStar_UInt128_t; + +FStar_UInt128_uint128 FStar_UInt128_add(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); + +FStar_UInt128_uint128 +FStar_UInt128_add_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); + +FStar_UInt128_uint128 FStar_UInt128_add_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); + +FStar_UInt128_uint128 FStar_UInt128_sub(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); + +FStar_UInt128_uint128 +FStar_UInt128_sub_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); + +FStar_UInt128_uint128 FStar_UInt128_sub_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); + +FStar_UInt128_uint128 FStar_UInt128_logand(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); + +FStar_UInt128_uint128 FStar_UInt128_logxor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); + +FStar_UInt128_uint128 FStar_UInt128_logor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); + +FStar_UInt128_uint128 FStar_UInt128_lognot(FStar_UInt128_uint128 a); + +FStar_UInt128_uint128 FStar_UInt128_shift_left(FStar_UInt128_uint128 a, uint32_t s); + +FStar_UInt128_uint128 FStar_UInt128_shift_right(FStar_UInt128_uint128 a, uint32_t s); + +bool FStar_UInt128_eq(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); + +bool FStar_UInt128_gt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); + +bool FStar_UInt128_lt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); + +bool FStar_UInt128_gte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); + +bool FStar_UInt128_lte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); + +FStar_UInt128_uint128 FStar_UInt128_eq_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); + +FStar_UInt128_uint128 FStar_UInt128_gte_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); + +FStar_UInt128_uint128 FStar_UInt128_uint64_to_uint128(uint64_t a); + +uint64_t FStar_UInt128_uint128_to_uint64(FStar_UInt128_uint128 a); + +extern FStar_UInt128_uint128 +(*FStar_UInt128_op_Plus_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1); + +extern FStar_UInt128_uint128 +(*FStar_UInt128_op_Plus_Question_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1); + +extern FStar_UInt128_uint128 +(*FStar_UInt128_op_Plus_Percent_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1); + +extern FStar_UInt128_uint128 +(*FStar_UInt128_op_Subtraction_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1); + +extern FStar_UInt128_uint128 +(*FStar_UInt128_op_Subtraction_Question_Hat)( + FStar_UInt128_uint128 x0, + FStar_UInt128_uint128 x1 +); + +extern FStar_UInt128_uint128 +(*FStar_UInt128_op_Subtraction_Percent_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1); + +extern FStar_UInt128_uint128 +(*FStar_UInt128_op_Amp_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1); + +extern FStar_UInt128_uint128 +(*FStar_UInt128_op_Hat_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1); + +extern FStar_UInt128_uint128 +(*FStar_UInt128_op_Bar_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1); + +extern FStar_UInt128_uint128 +(*FStar_UInt128_op_Less_Less_Hat)(FStar_UInt128_uint128 x0, uint32_t x1); + +extern FStar_UInt128_uint128 +(*FStar_UInt128_op_Greater_Greater_Hat)(FStar_UInt128_uint128 x0, uint32_t x1); + +extern bool (*FStar_UInt128_op_Equals_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1); + +extern bool +(*FStar_UInt128_op_Greater_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1); + +extern bool (*FStar_UInt128_op_Less_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1); + +extern bool +(*FStar_UInt128_op_Greater_Equals_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1); + +extern bool +(*FStar_UInt128_op_Less_Equals_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1); + +FStar_UInt128_uint128 FStar_UInt128_mul32(uint64_t x, uint32_t y); + +FStar_UInt128_uint128 FStar_UInt128_mul_wide(uint64_t x, uint64_t y); + +#define __FStar_UInt128_H_DEFINED +#endif diff --git a/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlib/FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8.h b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlib/FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8.h new file mode 100644 index 0000000000..21560c4a5d --- /dev/null +++ b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlib/FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8.h @@ -0,0 +1,280 @@ +/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. + Licensed under the Apache 2.0 License. */ + +/* This file was generated by KreMLin + * KreMLin invocation: ../krml -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrB9w -minimal -fparentheses -fcurly-braces -fno-shadow -header copyright-header.txt -minimal -tmpdir dist/minimal -skip-compilation -extract-uints -add-include -add-include -add-include "kremlin/internal/compat.h" -add-include "kremlin/internal/types.h" -bundle FStar.UInt64+FStar.UInt32+FStar.UInt16+FStar.UInt8=* extracted/prims.krml extracted/FStar_Pervasives_Native.krml extracted/FStar_Pervasives.krml extracted/FStar_Mul.krml extracted/FStar_Squash.krml extracted/FStar_Classical.krml extracted/FStar_StrongExcludedMiddle.krml extracted/FStar_FunctionalExtensionality.krml extracted/FStar_List_Tot_Base.krml extracted/FStar_List_Tot_Properties.krml extracted/FStar_List_Tot.krml extracted/FStar_Seq_Base.krml extracted/FStar_Seq_Properties.krml extracted/FStar_Seq.krml extracted/FStar_Math_Lib.krml extracted/FStar_Math_Lemmas.krml extracted/FStar_BitVector.krml extracted/FStar_UInt.krml extracted/FStar_UInt32.krml extracted/FStar_Int.krml extracted/FStar_Int16.krml extracted/FStar_Preorder.krml extracted/FStar_Ghost.krml extracted/FStar_ErasedLogic.krml extracted/FStar_UInt64.krml extracted/FStar_Set.krml extracted/FStar_PropositionalExtensionality.krml extracted/FStar_PredicateExtensionality.krml extracted/FStar_TSet.krml extracted/FStar_Monotonic_Heap.krml extracted/FStar_Heap.krml extracted/FStar_Map.krml extracted/FStar_Monotonic_HyperHeap.krml extracted/FStar_Monotonic_HyperStack.krml extracted/FStar_HyperStack.krml extracted/FStar_Monotonic_Witnessed.krml extracted/FStar_HyperStack_ST.krml extracted/FStar_HyperStack_All.krml extracted/FStar_Date.krml extracted/FStar_Universe.krml extracted/FStar_GSet.krml extracted/FStar_ModifiesGen.krml extracted/LowStar_Monotonic_Buffer.krml extracted/LowStar_Buffer.krml extracted/Spec_Loops.krml extracted/LowStar_BufferOps.krml extracted/C_Loops.krml extracted/FStar_UInt8.krml extracted/FStar_Kremlin_Endianness.krml extracted/FStar_UInt63.krml extracted/FStar_Exn.krml extracted/FStar_ST.krml extracted/FStar_All.krml extracted/FStar_Dyn.krml extracted/FStar_Int63.krml extracted/FStar_Int64.krml extracted/FStar_Int32.krml extracted/FStar_Int8.krml extracted/FStar_UInt16.krml extracted/FStar_Int_Cast.krml extracted/FStar_UInt128.krml extracted/C_Endianness.krml extracted/FStar_List.krml extracted/FStar_Float.krml extracted/FStar_IO.krml extracted/C.krml extracted/FStar_Char.krml extracted/FStar_String.krml extracted/LowStar_Modifies.krml extracted/C_String.krml extracted/FStar_Bytes.krml extracted/FStar_HyperStack_IO.krml extracted/C_Failure.krml extracted/TestLib.krml extracted/FStar_Int_Cast_Full.krml + * F* version: 059db0c8 + * KreMLin version: 916c37ac + */ + + + +#ifndef __FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8_H +#define __FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8_H + + +#include +#include +#include "kremlin/internal/compat.h" +#include "kremlin/internal/types.h" + +extern Prims_int FStar_UInt64_n; + +extern Prims_int FStar_UInt64_v(uint64_t x0); + +extern uint64_t FStar_UInt64_uint_to_t(Prims_int x0); + +extern uint64_t FStar_UInt64_add(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_add_underspec(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_add_mod(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_sub(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_sub_underspec(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_sub_mod(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_mul(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_mul_underspec(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_mul_mod(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_mul_div(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_div(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_rem(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_logand(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_logxor(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_logor(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_lognot(uint64_t x0); + +extern uint64_t FStar_UInt64_shift_right(uint64_t x0, uint32_t x1); + +extern uint64_t FStar_UInt64_shift_left(uint64_t x0, uint32_t x1); + +extern bool FStar_UInt64_eq(uint64_t x0, uint64_t x1); + +extern bool FStar_UInt64_gt(uint64_t x0, uint64_t x1); + +extern bool FStar_UInt64_gte(uint64_t x0, uint64_t x1); + +extern bool FStar_UInt64_lt(uint64_t x0, uint64_t x1); + +extern bool FStar_UInt64_lte(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_minus(uint64_t x0); + +extern uint32_t FStar_UInt64_n_minus_one; + +uint64_t FStar_UInt64_eq_mask(uint64_t a, uint64_t b); + +uint64_t FStar_UInt64_gte_mask(uint64_t a, uint64_t b); + +extern Prims_string FStar_UInt64_to_string(uint64_t x0); + +extern uint64_t FStar_UInt64_of_string(Prims_string x0); + +extern Prims_int FStar_UInt32_n; + +extern Prims_int FStar_UInt32_v(uint32_t x0); + +extern uint32_t FStar_UInt32_uint_to_t(Prims_int x0); + +extern uint32_t FStar_UInt32_add(uint32_t x0, uint32_t x1); + +extern uint32_t FStar_UInt32_add_underspec(uint32_t x0, uint32_t x1); + +extern uint32_t FStar_UInt32_add_mod(uint32_t x0, uint32_t x1); + +extern uint32_t FStar_UInt32_sub(uint32_t x0, uint32_t x1); + +extern uint32_t FStar_UInt32_sub_underspec(uint32_t x0, uint32_t x1); + +extern uint32_t FStar_UInt32_sub_mod(uint32_t x0, uint32_t x1); + +extern uint32_t FStar_UInt32_mul(uint32_t x0, uint32_t x1); + +extern uint32_t FStar_UInt32_mul_underspec(uint32_t x0, uint32_t x1); + +extern uint32_t FStar_UInt32_mul_mod(uint32_t x0, uint32_t x1); + +extern uint32_t FStar_UInt32_mul_div(uint32_t x0, uint32_t x1); + +extern uint32_t FStar_UInt32_div(uint32_t x0, uint32_t x1); + +extern uint32_t FStar_UInt32_rem(uint32_t x0, uint32_t x1); + +extern uint32_t FStar_UInt32_logand(uint32_t x0, uint32_t x1); + +extern uint32_t FStar_UInt32_logxor(uint32_t x0, uint32_t x1); + +extern uint32_t FStar_UInt32_logor(uint32_t x0, uint32_t x1); + +extern uint32_t FStar_UInt32_lognot(uint32_t x0); + +extern uint32_t FStar_UInt32_shift_right(uint32_t x0, uint32_t x1); + +extern uint32_t FStar_UInt32_shift_left(uint32_t x0, uint32_t x1); + +extern bool FStar_UInt32_eq(uint32_t x0, uint32_t x1); + +extern bool FStar_UInt32_gt(uint32_t x0, uint32_t x1); + +extern bool FStar_UInt32_gte(uint32_t x0, uint32_t x1); + +extern bool FStar_UInt32_lt(uint32_t x0, uint32_t x1); + +extern bool FStar_UInt32_lte(uint32_t x0, uint32_t x1); + +extern uint32_t FStar_UInt32_minus(uint32_t x0); + +extern uint32_t FStar_UInt32_n_minus_one; + +uint32_t FStar_UInt32_eq_mask(uint32_t a, uint32_t b); + +uint32_t FStar_UInt32_gte_mask(uint32_t a, uint32_t b); + +extern Prims_string FStar_UInt32_to_string(uint32_t x0); + +extern uint32_t FStar_UInt32_of_string(Prims_string x0); + +extern Prims_int FStar_UInt16_n; + +extern Prims_int FStar_UInt16_v(uint16_t x0); + +extern uint16_t FStar_UInt16_uint_to_t(Prims_int x0); + +extern uint16_t FStar_UInt16_add(uint16_t x0, uint16_t x1); + +extern uint16_t FStar_UInt16_add_underspec(uint16_t x0, uint16_t x1); + +extern uint16_t FStar_UInt16_add_mod(uint16_t x0, uint16_t x1); + +extern uint16_t FStar_UInt16_sub(uint16_t x0, uint16_t x1); + +extern uint16_t FStar_UInt16_sub_underspec(uint16_t x0, uint16_t x1); + +extern uint16_t FStar_UInt16_sub_mod(uint16_t x0, uint16_t x1); + +extern uint16_t FStar_UInt16_mul(uint16_t x0, uint16_t x1); + +extern uint16_t FStar_UInt16_mul_underspec(uint16_t x0, uint16_t x1); + +extern uint16_t FStar_UInt16_mul_mod(uint16_t x0, uint16_t x1); + +extern uint16_t FStar_UInt16_mul_div(uint16_t x0, uint16_t x1); + +extern uint16_t FStar_UInt16_div(uint16_t x0, uint16_t x1); + +extern uint16_t FStar_UInt16_rem(uint16_t x0, uint16_t x1); + +extern uint16_t FStar_UInt16_logand(uint16_t x0, uint16_t x1); + +extern uint16_t FStar_UInt16_logxor(uint16_t x0, uint16_t x1); + +extern uint16_t FStar_UInt16_logor(uint16_t x0, uint16_t x1); + +extern uint16_t FStar_UInt16_lognot(uint16_t x0); + +extern uint16_t FStar_UInt16_shift_right(uint16_t x0, uint32_t x1); + +extern uint16_t FStar_UInt16_shift_left(uint16_t x0, uint32_t x1); + +extern bool FStar_UInt16_eq(uint16_t x0, uint16_t x1); + +extern bool FStar_UInt16_gt(uint16_t x0, uint16_t x1); + +extern bool FStar_UInt16_gte(uint16_t x0, uint16_t x1); + +extern bool FStar_UInt16_lt(uint16_t x0, uint16_t x1); + +extern bool FStar_UInt16_lte(uint16_t x0, uint16_t x1); + +extern uint16_t FStar_UInt16_minus(uint16_t x0); + +extern uint32_t FStar_UInt16_n_minus_one; + +uint16_t FStar_UInt16_eq_mask(uint16_t a, uint16_t b); + +uint16_t FStar_UInt16_gte_mask(uint16_t a, uint16_t b); + +extern Prims_string FStar_UInt16_to_string(uint16_t x0); + +extern uint16_t FStar_UInt16_of_string(Prims_string x0); + +extern Prims_int FStar_UInt8_n; + +extern Prims_int FStar_UInt8_v(uint8_t x0); + +extern uint8_t FStar_UInt8_uint_to_t(Prims_int x0); + +extern uint8_t FStar_UInt8_add(uint8_t x0, uint8_t x1); + +extern uint8_t FStar_UInt8_add_underspec(uint8_t x0, uint8_t x1); + +extern uint8_t FStar_UInt8_add_mod(uint8_t x0, uint8_t x1); + +extern uint8_t FStar_UInt8_sub(uint8_t x0, uint8_t x1); + +extern uint8_t FStar_UInt8_sub_underspec(uint8_t x0, uint8_t x1); + +extern uint8_t FStar_UInt8_sub_mod(uint8_t x0, uint8_t x1); + +extern uint8_t FStar_UInt8_mul(uint8_t x0, uint8_t x1); + +extern uint8_t FStar_UInt8_mul_underspec(uint8_t x0, uint8_t x1); + +extern uint8_t FStar_UInt8_mul_mod(uint8_t x0, uint8_t x1); + +extern uint8_t FStar_UInt8_mul_div(uint8_t x0, uint8_t x1); + +extern uint8_t FStar_UInt8_div(uint8_t x0, uint8_t x1); + +extern uint8_t FStar_UInt8_rem(uint8_t x0, uint8_t x1); + +extern uint8_t FStar_UInt8_logand(uint8_t x0, uint8_t x1); + +extern uint8_t FStar_UInt8_logxor(uint8_t x0, uint8_t x1); + +extern uint8_t FStar_UInt8_logor(uint8_t x0, uint8_t x1); + +extern uint8_t FStar_UInt8_lognot(uint8_t x0); + +extern uint8_t FStar_UInt8_shift_right(uint8_t x0, uint32_t x1); + +extern uint8_t FStar_UInt8_shift_left(uint8_t x0, uint32_t x1); + +extern bool FStar_UInt8_eq(uint8_t x0, uint8_t x1); + +extern bool FStar_UInt8_gt(uint8_t x0, uint8_t x1); + +extern bool FStar_UInt8_gte(uint8_t x0, uint8_t x1); + +extern bool FStar_UInt8_lt(uint8_t x0, uint8_t x1); + +extern bool FStar_UInt8_lte(uint8_t x0, uint8_t x1); + +extern uint8_t FStar_UInt8_minus(uint8_t x0); + +extern uint32_t FStar_UInt8_n_minus_one; + +uint8_t FStar_UInt8_eq_mask(uint8_t a, uint8_t b); + +uint8_t FStar_UInt8_gte_mask(uint8_t a, uint8_t b); + +extern Prims_string FStar_UInt8_to_string(uint8_t x0); + +extern uint8_t FStar_UInt8_of_string(Prims_string x0); + +typedef uint8_t FStar_UInt8_byte; + +#define __FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8_H_DEFINED +#endif diff --git a/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/c_endianness.h b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/c_endianness.h new file mode 100644 index 0000000000..1b0d0eb05b --- /dev/null +++ b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/c_endianness.h @@ -0,0 +1,206 @@ +/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. + Licensed under the Apache 2.0 License. */ + +#ifndef __KREMLIN_ENDIAN_H +#define __KREMLIN_ENDIAN_H + +#include +#include + +#include "kremlin/internal/callconv.h" + +/******************************************************************************/ +/* Implementing C.fst (part 2: endian-ness macros) */ +/******************************************************************************/ + +/* ... for Linux */ +#if defined(__linux__) || defined(__CYGWIN__) +# include + +/* ... for OSX */ +#elif defined(__APPLE__) +# include +# define htole64(x) OSSwapHostToLittleInt64(x) +# define le64toh(x) OSSwapLittleToHostInt64(x) +# define htobe64(x) OSSwapHostToBigInt64(x) +# define be64toh(x) OSSwapBigToHostInt64(x) + +# define htole16(x) OSSwapHostToLittleInt16(x) +# define le16toh(x) OSSwapLittleToHostInt16(x) +# define htobe16(x) OSSwapHostToBigInt16(x) +# define be16toh(x) OSSwapBigToHostInt16(x) + +# define htole32(x) OSSwapHostToLittleInt32(x) +# define le32toh(x) OSSwapLittleToHostInt32(x) +# define htobe32(x) OSSwapHostToBigInt32(x) +# define be32toh(x) OSSwapBigToHostInt32(x) + +/* ... for Solaris */ +#elif defined(__sun__) +# include +# define htole64(x) LE_64(x) +# define le64toh(x) LE_64(x) +# define htobe64(x) BE_64(x) +# define be64toh(x) BE_64(x) + +# define htole16(x) LE_16(x) +# define le16toh(x) LE_16(x) +# define htobe16(x) BE_16(x) +# define be16toh(x) BE_16(x) + +# define htole32(x) LE_32(x) +# define le32toh(x) LE_32(x) +# define htobe32(x) BE_32(x) +# define be32toh(x) BE_32(x) + +/* ... for the BSDs */ +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) +# include +#elif defined(__OpenBSD__) +# include + +/* ... for Windows (MSVC)... not targeting XBOX 360! */ +#elif defined(_MSC_VER) + +# include +# define htobe16(x) _byteswap_ushort(x) +# define htole16(x) (x) +# define be16toh(x) _byteswap_ushort(x) +# define le16toh(x) (x) + +# define htobe32(x) _byteswap_ulong(x) +# define htole32(x) (x) +# define be32toh(x) _byteswap_ulong(x) +# define le32toh(x) (x) + +# define htobe64(x) _byteswap_uint64(x) +# define htole64(x) (x) +# define be64toh(x) _byteswap_uint64(x) +# define le64toh(x) (x) + +/* ... for Windows (GCC-like, e.g. mingw or clang) */ +#elif (defined(_WIN32) || defined(_WIN64)) && \ + (defined(__GNUC__) || defined(__clang__)) + +# define htobe16(x) __builtin_bswap16(x) +# define htole16(x) (x) +# define be16toh(x) __builtin_bswap16(x) +# define le16toh(x) (x) + +# define htobe32(x) __builtin_bswap32(x) +# define htole32(x) (x) +# define be32toh(x) __builtin_bswap32(x) +# define le32toh(x) (x) + +# define htobe64(x) __builtin_bswap64(x) +# define htole64(x) (x) +# define be64toh(x) __builtin_bswap64(x) +# define le64toh(x) (x) + +/* ... generic big-endian fallback code */ +#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + +/* byte swapping code inspired by: + * https://github.com/rweather/arduinolibs/blob/master/libraries/Crypto/utility/EndianUtil.h + * */ + +# define htobe32(x) (x) +# define be32toh(x) (x) +# define htole32(x) \ + (__extension__({ \ + uint32_t _temp = (x); \ + ((_temp >> 24) & 0x000000FF) | ((_temp >> 8) & 0x0000FF00) | \ + ((_temp << 8) & 0x00FF0000) | ((_temp << 24) & 0xFF000000); \ + })) +# define le32toh(x) (htole32((x))) + +# define htobe64(x) (x) +# define be64toh(x) (x) +# define htole64(x) \ + (__extension__({ \ + uint64_t __temp = (x); \ + uint32_t __low = htobe32((uint32_t)__temp); \ + uint32_t __high = htobe32((uint32_t)(__temp >> 32)); \ + (((uint64_t)__low) << 32) | __high; \ + })) +# define le64toh(x) (htole64((x))) + +/* ... generic little-endian fallback code */ +#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + +# define htole32(x) (x) +# define le32toh(x) (x) +# define htobe32(x) \ + (__extension__({ \ + uint32_t _temp = (x); \ + ((_temp >> 24) & 0x000000FF) | ((_temp >> 8) & 0x0000FF00) | \ + ((_temp << 8) & 0x00FF0000) | ((_temp << 24) & 0xFF000000); \ + })) +# define be32toh(x) (htobe32((x))) + +# define htole64(x) (x) +# define le64toh(x) (x) +# define htobe64(x) \ + (__extension__({ \ + uint64_t __temp = (x); \ + uint32_t __low = htobe32((uint32_t)__temp); \ + uint32_t __high = htobe32((uint32_t)(__temp >> 32)); \ + (((uint64_t)__low) << 32) | __high; \ + })) +# define be64toh(x) (htobe64((x))) + +/* ... couldn't determine endian-ness of the target platform */ +#else +# error "Please define __BYTE_ORDER__!" + +#endif /* defined(__linux__) || ... */ + +/* Loads and stores. These avoid undefined behavior due to unaligned memory + * accesses, via memcpy. */ + +inline static uint16_t load16(uint8_t *b) { + uint16_t x; + memcpy(&x, b, 2); + return x; +} + +inline static uint32_t load32(uint8_t *b) { + uint32_t x; + memcpy(&x, b, 4); + return x; +} + +inline static uint64_t load64(uint8_t *b) { + uint64_t x; + memcpy(&x, b, 8); + return x; +} + +inline static void store16(uint8_t *b, uint16_t i) { + memcpy(b, &i, 2); +} + +inline static void store32(uint8_t *b, uint32_t i) { + memcpy(b, &i, 4); +} + +inline static void store64(uint8_t *b, uint64_t i) { + memcpy(b, &i, 8); +} + +#define load16_le(b) (le16toh(load16(b))) +#define store16_le(b, i) (store16(b, htole16(i))) +#define load16_be(b) (be16toh(load16(b))) +#define store16_be(b, i) (store16(b, htobe16(i))) + +#define load32_le(b) (le32toh(load32(b))) +#define store32_le(b, i) (store32(b, htole32(i))) +#define load32_be(b) (be32toh(load32(b))) +#define store32_be(b, i) (store32(b, htobe32(i))) + +#define load64_le(b) (le64toh(load64(b))) +#define store64_le(b, i) (store64(b, htole64(i))) +#define load64_be(b) (be64toh(load64(b))) +#define store64_be(b, i) (store64(b, htobe64(i))) + +#endif diff --git a/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/builtin.h b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/builtin.h new file mode 100644 index 0000000000..219b266862 --- /dev/null +++ b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/builtin.h @@ -0,0 +1,16 @@ +/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. + Licensed under the Apache 2.0 License. */ + +#ifndef __KREMLIN_BUILTIN_H +#define __KREMLIN_BUILTIN_H + +/* For alloca, when using KreMLin's -falloca */ +#if (defined(_WIN32) || defined(_WIN64)) +# include +#endif + +/* If some globals need to be initialized before the main, then kremlin will + * generate and try to link last a function with this type: */ +void kremlinit_globals(void); + +#endif diff --git a/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/callconv.h b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/callconv.h new file mode 100644 index 0000000000..8ff8ca5ae9 --- /dev/null +++ b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/callconv.h @@ -0,0 +1,48 @@ +/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. + Licensed under the Apache 2.0 License. */ + +#ifndef __KREMLIN_CALLCONV_H +#define __KREMLIN_CALLCONV_H + +/******************************************************************************/ +/* Some macros to ease compatibility */ +/******************************************************************************/ + +/* We want to generate __cdecl safely without worrying about it being undefined. + * When using MSVC, these are always defined. When using MinGW, these are + * defined too. They have no meaning for other platforms, so we define them to + * be empty macros in other situations. */ +#ifndef _MSC_VER +#ifndef __cdecl +#define __cdecl +#endif +#ifndef __stdcall +#define __stdcall +#endif +#ifndef __fastcall +#define __fastcall +#endif +#endif + +/* Since KreMLin emits the inline keyword unconditionally, we follow the + * guidelines at https://gcc.gnu.org/onlinedocs/gcc/Inline.html and make this + * __inline__ to ensure the code compiles with -std=c90 and earlier. */ +#if defined(__GNUC__) +# define inline __inline__ +#elif defined(_MSC_VER) +# define inline __inline +#endif + +/* GCC-specific attribute syntax; everyone else gets the standard C inline + * attribute. */ +#ifdef __GNU_C__ +# ifndef __clang__ +# define force_inline inline __attribute__((always_inline)) +# else +# define force_inline inline +# endif +#else +# define force_inline inline +#endif + +#endif diff --git a/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/compat.h b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/compat.h new file mode 100644 index 0000000000..a5b8889da8 --- /dev/null +++ b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/compat.h @@ -0,0 +1,34 @@ +/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. + Licensed under the Apache 2.0 License. */ + +#ifndef KRML_COMPAT_H +#define KRML_COMPAT_H + +#include + +/* A series of macros that define C implementations of types that are not Low*, + * to facilitate porting programs to Low*. */ + +typedef const char *Prims_string; + +typedef struct { + uint32_t length; + const char *data; +} FStar_Bytes_bytes; + +typedef int32_t Prims_pos, Prims_nat, Prims_nonzero, Prims_int, + krml_checked_int_t; + +#define RETURN_OR(x) \ + do { \ + int64_t __ret = x; \ + if (__ret < INT32_MIN || INT32_MAX < __ret) { \ + KRML_HOST_PRINTF( \ + "Prims.{int,nat,pos} integer overflow at %s:%d\n", __FILE__, \ + __LINE__); \ + KRML_HOST_EXIT(252); \ + } \ + return (int32_t)__ret; \ + } while (0) + +#endif diff --git a/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/debug.h b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/debug.h new file mode 100644 index 0000000000..44ac22cd62 --- /dev/null +++ b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/debug.h @@ -0,0 +1,57 @@ +/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. + Licensed under the Apache 2.0 License. */ + +#ifndef __KREMLIN_DEBUG_H +#define __KREMLIN_DEBUG_H + +#include + +#include "kremlin/internal/target.h" + +/******************************************************************************/ +/* Debugging helpers - intended only for KreMLin developers */ +/******************************************************************************/ + +/* In support of "-wasm -d force-c": we might need this function to be + * forward-declared, because the dependency on WasmSupport appears very late, + * after SimplifyWasm, and sadly, after the topological order has been done. */ +void WasmSupport_check_buffer_size(uint32_t s); + +/* A series of GCC atrocities to trace function calls (kremlin's [-d c-calls] + * option). Useful when trying to debug, say, Wasm, to compare traces. */ +/* clang-format off */ +#ifdef __GNUC__ +#define KRML_FORMAT(X) _Generic((X), \ + uint8_t : "0x%08" PRIx8, \ + uint16_t: "0x%08" PRIx16, \ + uint32_t: "0x%08" PRIx32, \ + uint64_t: "0x%08" PRIx64, \ + int8_t : "0x%08" PRIx8, \ + int16_t : "0x%08" PRIx16, \ + int32_t : "0x%08" PRIx32, \ + int64_t : "0x%08" PRIx64, \ + default : "%s") + +#define KRML_FORMAT_ARG(X) _Generic((X), \ + uint8_t : X, \ + uint16_t: X, \ + uint32_t: X, \ + uint64_t: X, \ + int8_t : X, \ + int16_t : X, \ + int32_t : X, \ + int64_t : X, \ + default : "unknown") +/* clang-format on */ + +# define KRML_DEBUG_RETURN(X) \ + ({ \ + __auto_type _ret = (X); \ + KRML_HOST_PRINTF("returning: "); \ + KRML_HOST_PRINTF(KRML_FORMAT(_ret), KRML_FORMAT_ARG(_ret)); \ + KRML_HOST_PRINTF(" \n"); \ + _ret; \ + }) +#endif + +#endif diff --git a/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/target.h b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/target.h new file mode 100644 index 0000000000..b552f52b06 --- /dev/null +++ b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/target.h @@ -0,0 +1,102 @@ +/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. + Licensed under the Apache 2.0 License. */ + +#ifndef __KREMLIN_TARGET_H +#define __KREMLIN_TARGET_H + +#include +#include +#include +#include +#include + +#include "kremlin/internal/callconv.h" + +/******************************************************************************/ +/* Macros that KreMLin will generate. */ +/******************************************************************************/ + +/* For "bare" targets that do not have a C stdlib, the user might want to use + * [-add-early-include '"mydefinitions.h"'] and override these. */ +#ifndef KRML_HOST_PRINTF +# define KRML_HOST_PRINTF printf +#endif + +#if ( \ + (defined __STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + (!(defined KRML_HOST_EPRINTF))) +# define KRML_HOST_EPRINTF(...) fprintf(stderr, __VA_ARGS__) +#endif + +#ifndef KRML_HOST_EXIT +# define KRML_HOST_EXIT exit +#endif + +#ifndef KRML_HOST_MALLOC +# define KRML_HOST_MALLOC malloc +#endif + +#ifndef KRML_HOST_CALLOC +# define KRML_HOST_CALLOC calloc +#endif + +#ifndef KRML_HOST_FREE +# define KRML_HOST_FREE free +#endif + +#ifndef KRML_HOST_TIME + +# include + +/* Prims_nat not yet in scope */ +inline static int32_t krml_time() { + return (int32_t)time(NULL); +} + +# define KRML_HOST_TIME krml_time +#endif + +/* In statement position, exiting is easy. */ +#define KRML_EXIT \ + do { \ + KRML_HOST_PRINTF("Unimplemented function at %s:%d\n", __FILE__, __LINE__); \ + KRML_HOST_EXIT(254); \ + } while (0) + +/* In expression position, use the comma-operator and a malloc to return an + * expression of the right size. KreMLin passes t as the parameter to the macro. + */ +#define KRML_EABORT(t, msg) \ + (KRML_HOST_PRINTF("KreMLin abort at %s:%d\n%s\n", __FILE__, __LINE__, msg), \ + KRML_HOST_EXIT(255), *((t *)KRML_HOST_MALLOC(sizeof(t)))) + +/* In FStar.Buffer.fst, the size of arrays is uint32_t, but it's a number of + * *elements*. Do an ugly, run-time check (some of which KreMLin can eliminate). + */ + +#ifdef __GNUC__ +# define _KRML_CHECK_SIZE_PRAGMA \ + _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") +#else +# define _KRML_CHECK_SIZE_PRAGMA +#endif + +#define KRML_CHECK_SIZE(size_elt, sz) \ + do { \ + _KRML_CHECK_SIZE_PRAGMA \ + if (((size_t)(sz)) > ((size_t)(SIZE_MAX / (size_elt)))) { \ + KRML_HOST_PRINTF( \ + "Maximum allocatable size exceeded, aborting before overflow at " \ + "%s:%d\n", \ + __FILE__, __LINE__); \ + KRML_HOST_EXIT(253); \ + } \ + } while (0) + +#if defined(_MSC_VER) && _MSC_VER < 1900 +# define KRML_HOST_SNPRINTF(buf, sz, fmt, arg) _snprintf_s(buf, sz, _TRUNCATE, fmt, arg) +#else +# define KRML_HOST_SNPRINTF(buf, sz, fmt, arg) snprintf(buf, sz, fmt, arg) +#endif + +#endif diff --git a/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/types.h b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/types.h new file mode 100644 index 0000000000..b936f00db5 --- /dev/null +++ b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/types.h @@ -0,0 +1,61 @@ +/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. + Licensed under the Apache 2.0 License. */ + +#ifndef KRML_TYPES_H +#define KRML_TYPES_H + +#include +#include +#include + +/* Types which are either abstract, meaning that have to be implemented in C, or + * which are models, meaning that they are swapped out at compile-time for + * hand-written C types (in which case they're marked as noextract). */ + +typedef uint64_t FStar_UInt64_t, FStar_UInt64_t_; +typedef int64_t FStar_Int64_t, FStar_Int64_t_; +typedef uint32_t FStar_UInt32_t, FStar_UInt32_t_; +typedef int32_t FStar_Int32_t, FStar_Int32_t_; +typedef uint16_t FStar_UInt16_t, FStar_UInt16_t_; +typedef int16_t FStar_Int16_t, FStar_Int16_t_; +typedef uint8_t FStar_UInt8_t, FStar_UInt8_t_; +typedef int8_t FStar_Int8_t, FStar_Int8_t_; + +/* Only useful when building Kremlib, because it's in the dependency graph of + * FStar.Int.Cast. */ +typedef uint64_t FStar_UInt63_t, FStar_UInt63_t_; +typedef int64_t FStar_Int63_t, FStar_Int63_t_; + +typedef double FStar_Float_float; +typedef uint32_t FStar_Char_char; +typedef FILE *FStar_IO_fd_read, *FStar_IO_fd_write; + +typedef void *FStar_Dyn_dyn; + +typedef const char *C_String_t, *C_String_t_; + +typedef int exit_code; +typedef FILE *channel; + +typedef unsigned long long TestLib_cycles; + +typedef uint64_t FStar_Date_dateTime, FStar_Date_timeSpan; + +/* The uint128 type is a special case since we offer several implementations of + * it, depending on the compiler and whether the user wants the verified + * implementation or not. */ +#if !defined(KRML_VERIFIED_UINT128) && defined(_MSC_VER) && defined(_M_X64) +# include +typedef __m128i FStar_UInt128_uint128; +#elif !defined(KRML_VERIFIED_UINT128) && !defined(_MSC_VER) +typedef unsigned __int128 FStar_UInt128_uint128; +#else +typedef struct FStar_UInt128_uint128_s { + uint64_t low; + uint64_t high; +} FStar_UInt128_uint128; +#endif + +typedef FStar_UInt128_uint128 FStar_UInt128_t, FStar_UInt128_t_, uint128_t; + +#endif diff --git a/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/wasmsupport.h b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/wasmsupport.h new file mode 100644 index 0000000000..b44fa3f75d --- /dev/null +++ b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/kremlin/internal/wasmsupport.h @@ -0,0 +1,5 @@ +/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. + Licensed under the Apache 2.0 License. */ + +/* This file is automatically included when compiling with -wasm -d force-c */ +#define WasmSupport_check_buffer_size(X) diff --git a/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/vs2013/Hacl_Curve25519.h b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/vs2013/Hacl_Curve25519.h new file mode 100644 index 0000000000..27ebe07947 --- /dev/null +++ b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/vs2013/Hacl_Curve25519.h @@ -0,0 +1,21 @@ +/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. + Licensed under the Apache 2.0 License. */ + +/* This file was generated by KreMLin + * KreMLin invocation: /mnt/e/everest/verify/kremlin/krml -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrcLh -minimal -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrcLh -minimal -I /mnt/e/everest/verify/hacl-star/code/lib/kremlin -I /mnt/e/everest/verify/kremlin/kremlib/compat -I /mnt/e/everest/verify/hacl-star/specs -I /mnt/e/everest/verify/hacl-star/specs/old -I . -ccopt -march=native -verbose -ldopt -flto -tmpdir x25519-c -I ../bignum -bundle Hacl.Curve25519=* -minimal -add-include "kremlib.h" -skip-compilation x25519-c/out.krml -o x25519-c/Hacl_Curve25519.c + * F* version: 059db0c8 + * KreMLin version: 916c37ac + */ + + + +#ifndef __Hacl_Curve25519_H +#define __Hacl_Curve25519_H + + +#include "kremlib.h" + +void Hacl_Curve25519_crypto_scalarmult(uint8_t *mypublic, uint8_t *secret, uint8_t *basepoint); + +#define __Hacl_Curve25519_H_DEFINED +#endif diff --git a/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/x25519.h b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/x25519.h new file mode 100644 index 0000000000..68a5649d57 --- /dev/null +++ b/tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/everest/x25519.h @@ -0,0 +1,48 @@ +/* + * ECDH with curve-optimized implementation multiplexing + * + * Copyright 2016-2018 INRIA and Microsoft Corporation + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef TF_PSA_CRYPTO_X25519_H +#define TF_PSA_CRYPTO_X25519_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS) + +#define MBEDTLS_X25519_KEY_SIZE_BYTES 32 + +/* + * Scalar multiplication: out = scalar * point + * + * All buffer must of at least the expected size. + */ +void mbedtls_x25519_scalarmult(uint8_t out[MBEDTLS_X25519_KEY_SIZE_BYTES], + const uint8_t scalar[MBEDTLS_X25519_KEY_SIZE_BYTES], + const uint8_t point[MBEDTLS_X25519_KEY_SIZE_BYTES]); + +#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_X25519_H */ diff --git a/tf-psa-crypto/drivers/everest/library/Hacl_Curve25519.c b/tf-psa-crypto/drivers/everest/library/Hacl_Curve25519.c new file mode 100644 index 0000000000..450b9f8ddf --- /dev/null +++ b/tf-psa-crypto/drivers/everest/library/Hacl_Curve25519.c @@ -0,0 +1,760 @@ +/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. + Licensed under the Apache 2.0 License. */ + +/* This file was generated by KreMLin + * KreMLin invocation: /mnt/e/everest/verify/kremlin/krml -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrcLh -minimal -fbuiltin-uint128 -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrcLh -minimal -I /mnt/e/everest/verify/hacl-star/code/lib/kremlin -I /mnt/e/everest/verify/kremlin/kremlib/compat -I /mnt/e/everest/verify/hacl-star/specs -I /mnt/e/everest/verify/hacl-star/specs/old -I . -ccopt -march=native -verbose -ldopt -flto -tmpdir x25519-c -I ../bignum -bundle Hacl.Curve25519=* -minimal -add-include "kremlib.h" -skip-compilation x25519-c/out.krml -o x25519-c/Hacl_Curve25519.c + * F* version: 059db0c8 + * KreMLin version: 916c37ac + */ + + +#include "Hacl_Curve25519.h" + +extern uint64_t FStar_UInt64_eq_mask(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_gte_mask(uint64_t x0, uint64_t x1); + +extern uint128_t FStar_UInt128_add(uint128_t x0, uint128_t x1); + +extern uint128_t FStar_UInt128_add_mod(uint128_t x0, uint128_t x1); + +extern uint128_t FStar_UInt128_logand(uint128_t x0, uint128_t x1); + +extern uint128_t FStar_UInt128_shift_right(uint128_t x0, uint32_t x1); + +extern uint128_t FStar_UInt128_uint64_to_uint128(uint64_t x0); + +extern uint64_t FStar_UInt128_uint128_to_uint64(uint128_t x0); + +extern uint128_t FStar_UInt128_mul_wide(uint64_t x0, uint64_t x1); + +static void Hacl_Bignum_Modulo_carry_top(uint64_t *b) +{ + uint64_t b4 = b[4U]; + uint64_t b0 = b[0U]; + uint64_t b4_ = b4 & (uint64_t)0x7ffffffffffffU; + uint64_t b0_ = b0 + (uint64_t)19U * (b4 >> (uint32_t)51U); + b[4U] = b4_; + b[0U] = b0_; +} + +inline static void Hacl_Bignum_Fproduct_copy_from_wide_(uint64_t *output, uint128_t *input) +{ + uint32_t i; + for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U) + { + uint128_t xi = input[i]; + output[i] = (uint64_t)xi; + } +} + +inline static void +Hacl_Bignum_Fproduct_sum_scalar_multiplication_(uint128_t *output, uint64_t *input, uint64_t s) +{ + uint32_t i; + for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U) + { + uint128_t xi = output[i]; + uint64_t yi = input[i]; + output[i] = xi + (uint128_t)yi * s; + } +} + +inline static void Hacl_Bignum_Fproduct_carry_wide_(uint128_t *tmp) +{ + uint32_t i; + for (i = (uint32_t)0U; i < (uint32_t)4U; i = i + (uint32_t)1U) + { + uint32_t ctr = i; + uint128_t tctr = tmp[ctr]; + uint128_t tctrp1 = tmp[ctr + (uint32_t)1U]; + uint64_t r0 = (uint64_t)tctr & (uint64_t)0x7ffffffffffffU; + uint128_t c = tctr >> (uint32_t)51U; + tmp[ctr] = (uint128_t)r0; + tmp[ctr + (uint32_t)1U] = tctrp1 + c; + } +} + +inline static void Hacl_Bignum_Fmul_shift_reduce(uint64_t *output) +{ + uint64_t tmp = output[4U]; + uint64_t b0; + { + uint32_t i; + for (i = (uint32_t)0U; i < (uint32_t)4U; i = i + (uint32_t)1U) + { + uint32_t ctr = (uint32_t)5U - i - (uint32_t)1U; + uint64_t z = output[ctr - (uint32_t)1U]; + output[ctr] = z; + } + } + output[0U] = tmp; + b0 = output[0U]; + output[0U] = (uint64_t)19U * b0; +} + +static void +Hacl_Bignum_Fmul_mul_shift_reduce_(uint128_t *output, uint64_t *input, uint64_t *input2) +{ + uint32_t i; + uint64_t input2i; + { + uint32_t i0; + for (i0 = (uint32_t)0U; i0 < (uint32_t)4U; i0 = i0 + (uint32_t)1U) + { + uint64_t input2i0 = input2[i0]; + Hacl_Bignum_Fproduct_sum_scalar_multiplication_(output, input, input2i0); + Hacl_Bignum_Fmul_shift_reduce(input); + } + } + i = (uint32_t)4U; + input2i = input2[i]; + Hacl_Bignum_Fproduct_sum_scalar_multiplication_(output, input, input2i); +} + +inline static void Hacl_Bignum_Fmul_fmul(uint64_t *output, uint64_t *input, uint64_t *input2) +{ + uint64_t tmp[5U] = { 0U }; + memcpy(tmp, input, (uint32_t)5U * sizeof input[0U]); + KRML_CHECK_SIZE(sizeof (uint128_t), (uint32_t)5U); + { + uint128_t t[5U]; + { + uint32_t _i; + for (_i = 0U; _i < (uint32_t)5U; ++_i) + t[_i] = (uint128_t)(uint64_t)0U; + } + { + uint128_t b4; + uint128_t b0; + uint128_t b4_; + uint128_t b0_; + uint64_t i0; + uint64_t i1; + uint64_t i0_; + uint64_t i1_; + Hacl_Bignum_Fmul_mul_shift_reduce_(t, tmp, input2); + Hacl_Bignum_Fproduct_carry_wide_(t); + b4 = t[4U]; + b0 = t[0U]; + b4_ = b4 & (uint128_t)(uint64_t)0x7ffffffffffffU; + b0_ = b0 + (uint128_t)(uint64_t)19U * (uint64_t)(b4 >> (uint32_t)51U); + t[4U] = b4_; + t[0U] = b0_; + Hacl_Bignum_Fproduct_copy_from_wide_(output, t); + i0 = output[0U]; + i1 = output[1U]; + i0_ = i0 & (uint64_t)0x7ffffffffffffU; + i1_ = i1 + (i0 >> (uint32_t)51U); + output[0U] = i0_; + output[1U] = i1_; + } + } +} + +inline static void Hacl_Bignum_Fsquare_fsquare__(uint128_t *tmp, uint64_t *output) +{ + uint64_t r0 = output[0U]; + uint64_t r1 = output[1U]; + uint64_t r2 = output[2U]; + uint64_t r3 = output[3U]; + uint64_t r4 = output[4U]; + uint64_t d0 = r0 * (uint64_t)2U; + uint64_t d1 = r1 * (uint64_t)2U; + uint64_t d2 = r2 * (uint64_t)2U * (uint64_t)19U; + uint64_t d419 = r4 * (uint64_t)19U; + uint64_t d4 = d419 * (uint64_t)2U; + uint128_t s0 = (uint128_t)r0 * r0 + (uint128_t)d4 * r1 + (uint128_t)d2 * r3; + uint128_t s1 = (uint128_t)d0 * r1 + (uint128_t)d4 * r2 + (uint128_t)(r3 * (uint64_t)19U) * r3; + uint128_t s2 = (uint128_t)d0 * r2 + (uint128_t)r1 * r1 + (uint128_t)d4 * r3; + uint128_t s3 = (uint128_t)d0 * r3 + (uint128_t)d1 * r2 + (uint128_t)r4 * d419; + uint128_t s4 = (uint128_t)d0 * r4 + (uint128_t)d1 * r3 + (uint128_t)r2 * r2; + tmp[0U] = s0; + tmp[1U] = s1; + tmp[2U] = s2; + tmp[3U] = s3; + tmp[4U] = s4; +} + +inline static void Hacl_Bignum_Fsquare_fsquare_(uint128_t *tmp, uint64_t *output) +{ + uint128_t b4; + uint128_t b0; + uint128_t b4_; + uint128_t b0_; + uint64_t i0; + uint64_t i1; + uint64_t i0_; + uint64_t i1_; + Hacl_Bignum_Fsquare_fsquare__(tmp, output); + Hacl_Bignum_Fproduct_carry_wide_(tmp); + b4 = tmp[4U]; + b0 = tmp[0U]; + b4_ = b4 & (uint128_t)(uint64_t)0x7ffffffffffffU; + b0_ = b0 + (uint128_t)(uint64_t)19U * (uint64_t)(b4 >> (uint32_t)51U); + tmp[4U] = b4_; + tmp[0U] = b0_; + Hacl_Bignum_Fproduct_copy_from_wide_(output, tmp); + i0 = output[0U]; + i1 = output[1U]; + i0_ = i0 & (uint64_t)0x7ffffffffffffU; + i1_ = i1 + (i0 >> (uint32_t)51U); + output[0U] = i0_; + output[1U] = i1_; +} + +static void +Hacl_Bignum_Fsquare_fsquare_times_(uint64_t *input, uint128_t *tmp, uint32_t count1) +{ + uint32_t i; + Hacl_Bignum_Fsquare_fsquare_(tmp, input); + for (i = (uint32_t)1U; i < count1; i = i + (uint32_t)1U) + Hacl_Bignum_Fsquare_fsquare_(tmp, input); +} + +inline static void +Hacl_Bignum_Fsquare_fsquare_times(uint64_t *output, uint64_t *input, uint32_t count1) +{ + KRML_CHECK_SIZE(sizeof (uint128_t), (uint32_t)5U); + { + uint128_t t[5U]; + { + uint32_t _i; + for (_i = 0U; _i < (uint32_t)5U; ++_i) + t[_i] = (uint128_t)(uint64_t)0U; + } + memcpy(output, input, (uint32_t)5U * sizeof input[0U]); + Hacl_Bignum_Fsquare_fsquare_times_(output, t, count1); + } +} + +inline static void Hacl_Bignum_Fsquare_fsquare_times_inplace(uint64_t *output, uint32_t count1) +{ + KRML_CHECK_SIZE(sizeof (uint128_t), (uint32_t)5U); + { + uint128_t t[5U]; + { + uint32_t _i; + for (_i = 0U; _i < (uint32_t)5U; ++_i) + t[_i] = (uint128_t)(uint64_t)0U; + } + Hacl_Bignum_Fsquare_fsquare_times_(output, t, count1); + } +} + +inline static void Hacl_Bignum_Crecip_crecip(uint64_t *out, uint64_t *z) +{ + uint64_t buf[20U] = { 0U }; + uint64_t *a0 = buf; + uint64_t *t00 = buf + (uint32_t)5U; + uint64_t *b0 = buf + (uint32_t)10U; + uint64_t *t01; + uint64_t *b1; + uint64_t *c0; + uint64_t *a; + uint64_t *t0; + uint64_t *b; + uint64_t *c; + Hacl_Bignum_Fsquare_fsquare_times(a0, z, (uint32_t)1U); + Hacl_Bignum_Fsquare_fsquare_times(t00, a0, (uint32_t)2U); + Hacl_Bignum_Fmul_fmul(b0, t00, z); + Hacl_Bignum_Fmul_fmul(a0, b0, a0); + Hacl_Bignum_Fsquare_fsquare_times(t00, a0, (uint32_t)1U); + Hacl_Bignum_Fmul_fmul(b0, t00, b0); + Hacl_Bignum_Fsquare_fsquare_times(t00, b0, (uint32_t)5U); + t01 = buf + (uint32_t)5U; + b1 = buf + (uint32_t)10U; + c0 = buf + (uint32_t)15U; + Hacl_Bignum_Fmul_fmul(b1, t01, b1); + Hacl_Bignum_Fsquare_fsquare_times(t01, b1, (uint32_t)10U); + Hacl_Bignum_Fmul_fmul(c0, t01, b1); + Hacl_Bignum_Fsquare_fsquare_times(t01, c0, (uint32_t)20U); + Hacl_Bignum_Fmul_fmul(t01, t01, c0); + Hacl_Bignum_Fsquare_fsquare_times_inplace(t01, (uint32_t)10U); + Hacl_Bignum_Fmul_fmul(b1, t01, b1); + Hacl_Bignum_Fsquare_fsquare_times(t01, b1, (uint32_t)50U); + a = buf; + t0 = buf + (uint32_t)5U; + b = buf + (uint32_t)10U; + c = buf + (uint32_t)15U; + Hacl_Bignum_Fmul_fmul(c, t0, b); + Hacl_Bignum_Fsquare_fsquare_times(t0, c, (uint32_t)100U); + Hacl_Bignum_Fmul_fmul(t0, t0, c); + Hacl_Bignum_Fsquare_fsquare_times_inplace(t0, (uint32_t)50U); + Hacl_Bignum_Fmul_fmul(t0, t0, b); + Hacl_Bignum_Fsquare_fsquare_times_inplace(t0, (uint32_t)5U); + Hacl_Bignum_Fmul_fmul(out, t0, a); +} + +inline static void Hacl_Bignum_fsum(uint64_t *a, uint64_t *b) +{ + uint32_t i; + for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U) + { + uint64_t xi = a[i]; + uint64_t yi = b[i]; + a[i] = xi + yi; + } +} + +inline static void Hacl_Bignum_fdifference(uint64_t *a, uint64_t *b) +{ + uint64_t tmp[5U] = { 0U }; + uint64_t b0; + uint64_t b1; + uint64_t b2; + uint64_t b3; + uint64_t b4; + memcpy(tmp, b, (uint32_t)5U * sizeof b[0U]); + b0 = tmp[0U]; + b1 = tmp[1U]; + b2 = tmp[2U]; + b3 = tmp[3U]; + b4 = tmp[4U]; + tmp[0U] = b0 + (uint64_t)0x3fffffffffff68U; + tmp[1U] = b1 + (uint64_t)0x3ffffffffffff8U; + tmp[2U] = b2 + (uint64_t)0x3ffffffffffff8U; + tmp[3U] = b3 + (uint64_t)0x3ffffffffffff8U; + tmp[4U] = b4 + (uint64_t)0x3ffffffffffff8U; + { + uint32_t i; + for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U) + { + uint64_t xi = a[i]; + uint64_t yi = tmp[i]; + a[i] = yi - xi; + } + } +} + +inline static void Hacl_Bignum_fscalar(uint64_t *output, uint64_t *b, uint64_t s) +{ + KRML_CHECK_SIZE(sizeof (uint128_t), (uint32_t)5U); + { + uint128_t tmp[5U]; + { + uint32_t _i; + for (_i = 0U; _i < (uint32_t)5U; ++_i) + tmp[_i] = (uint128_t)(uint64_t)0U; + } + { + uint128_t b4; + uint128_t b0; + uint128_t b4_; + uint128_t b0_; + { + uint32_t i; + for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U) + { + uint64_t xi = b[i]; + tmp[i] = (uint128_t)xi * s; + } + } + Hacl_Bignum_Fproduct_carry_wide_(tmp); + b4 = tmp[4U]; + b0 = tmp[0U]; + b4_ = b4 & (uint128_t)(uint64_t)0x7ffffffffffffU; + b0_ = b0 + (uint128_t)(uint64_t)19U * (uint64_t)(b4 >> (uint32_t)51U); + tmp[4U] = b4_; + tmp[0U] = b0_; + Hacl_Bignum_Fproduct_copy_from_wide_(output, tmp); + } + } +} + +inline static void Hacl_Bignum_fmul(uint64_t *output, uint64_t *a, uint64_t *b) +{ + Hacl_Bignum_Fmul_fmul(output, a, b); +} + +inline static void Hacl_Bignum_crecip(uint64_t *output, uint64_t *input) +{ + Hacl_Bignum_Crecip_crecip(output, input); +} + +static void +Hacl_EC_Point_swap_conditional_step(uint64_t *a, uint64_t *b, uint64_t swap1, uint32_t ctr) +{ + uint32_t i = ctr - (uint32_t)1U; + uint64_t ai = a[i]; + uint64_t bi = b[i]; + uint64_t x = swap1 & (ai ^ bi); + uint64_t ai1 = ai ^ x; + uint64_t bi1 = bi ^ x; + a[i] = ai1; + b[i] = bi1; +} + +static void +Hacl_EC_Point_swap_conditional_(uint64_t *a, uint64_t *b, uint64_t swap1, uint32_t ctr) +{ + if (!(ctr == (uint32_t)0U)) + { + uint32_t i; + Hacl_EC_Point_swap_conditional_step(a, b, swap1, ctr); + i = ctr - (uint32_t)1U; + Hacl_EC_Point_swap_conditional_(a, b, swap1, i); + } +} + +static void Hacl_EC_Point_swap_conditional(uint64_t *a, uint64_t *b, uint64_t iswap) +{ + uint64_t swap1 = (uint64_t)0U - iswap; + Hacl_EC_Point_swap_conditional_(a, b, swap1, (uint32_t)5U); + Hacl_EC_Point_swap_conditional_(a + (uint32_t)5U, b + (uint32_t)5U, swap1, (uint32_t)5U); +} + +static void Hacl_EC_Point_copy(uint64_t *output, uint64_t *input) +{ + memcpy(output, input, (uint32_t)5U * sizeof input[0U]); + memcpy(output + (uint32_t)5U, + input + (uint32_t)5U, + (uint32_t)5U * sizeof (input + (uint32_t)5U)[0U]); +} + +static void Hacl_EC_Format_fexpand(uint64_t *output, uint8_t *input) +{ + uint64_t i0 = load64_le(input); + uint8_t *x00 = input + (uint32_t)6U; + uint64_t i1 = load64_le(x00); + uint8_t *x01 = input + (uint32_t)12U; + uint64_t i2 = load64_le(x01); + uint8_t *x02 = input + (uint32_t)19U; + uint64_t i3 = load64_le(x02); + uint8_t *x0 = input + (uint32_t)24U; + uint64_t i4 = load64_le(x0); + uint64_t output0 = i0 & (uint64_t)0x7ffffffffffffU; + uint64_t output1 = i1 >> (uint32_t)3U & (uint64_t)0x7ffffffffffffU; + uint64_t output2 = i2 >> (uint32_t)6U & (uint64_t)0x7ffffffffffffU; + uint64_t output3 = i3 >> (uint32_t)1U & (uint64_t)0x7ffffffffffffU; + uint64_t output4 = i4 >> (uint32_t)12U & (uint64_t)0x7ffffffffffffU; + output[0U] = output0; + output[1U] = output1; + output[2U] = output2; + output[3U] = output3; + output[4U] = output4; +} + +static void Hacl_EC_Format_fcontract_first_carry_pass(uint64_t *input) +{ + uint64_t t0 = input[0U]; + uint64_t t1 = input[1U]; + uint64_t t2 = input[2U]; + uint64_t t3 = input[3U]; + uint64_t t4 = input[4U]; + uint64_t t1_ = t1 + (t0 >> (uint32_t)51U); + uint64_t t0_ = t0 & (uint64_t)0x7ffffffffffffU; + uint64_t t2_ = t2 + (t1_ >> (uint32_t)51U); + uint64_t t1__ = t1_ & (uint64_t)0x7ffffffffffffU; + uint64_t t3_ = t3 + (t2_ >> (uint32_t)51U); + uint64_t t2__ = t2_ & (uint64_t)0x7ffffffffffffU; + uint64_t t4_ = t4 + (t3_ >> (uint32_t)51U); + uint64_t t3__ = t3_ & (uint64_t)0x7ffffffffffffU; + input[0U] = t0_; + input[1U] = t1__; + input[2U] = t2__; + input[3U] = t3__; + input[4U] = t4_; +} + +static void Hacl_EC_Format_fcontract_first_carry_full(uint64_t *input) +{ + Hacl_EC_Format_fcontract_first_carry_pass(input); + Hacl_Bignum_Modulo_carry_top(input); +} + +static void Hacl_EC_Format_fcontract_second_carry_pass(uint64_t *input) +{ + uint64_t t0 = input[0U]; + uint64_t t1 = input[1U]; + uint64_t t2 = input[2U]; + uint64_t t3 = input[3U]; + uint64_t t4 = input[4U]; + uint64_t t1_ = t1 + (t0 >> (uint32_t)51U); + uint64_t t0_ = t0 & (uint64_t)0x7ffffffffffffU; + uint64_t t2_ = t2 + (t1_ >> (uint32_t)51U); + uint64_t t1__ = t1_ & (uint64_t)0x7ffffffffffffU; + uint64_t t3_ = t3 + (t2_ >> (uint32_t)51U); + uint64_t t2__ = t2_ & (uint64_t)0x7ffffffffffffU; + uint64_t t4_ = t4 + (t3_ >> (uint32_t)51U); + uint64_t t3__ = t3_ & (uint64_t)0x7ffffffffffffU; + input[0U] = t0_; + input[1U] = t1__; + input[2U] = t2__; + input[3U] = t3__; + input[4U] = t4_; +} + +static void Hacl_EC_Format_fcontract_second_carry_full(uint64_t *input) +{ + uint64_t i0; + uint64_t i1; + uint64_t i0_; + uint64_t i1_; + Hacl_EC_Format_fcontract_second_carry_pass(input); + Hacl_Bignum_Modulo_carry_top(input); + i0 = input[0U]; + i1 = input[1U]; + i0_ = i0 & (uint64_t)0x7ffffffffffffU; + i1_ = i1 + (i0 >> (uint32_t)51U); + input[0U] = i0_; + input[1U] = i1_; +} + +static void Hacl_EC_Format_fcontract_trim(uint64_t *input) +{ + uint64_t a0 = input[0U]; + uint64_t a1 = input[1U]; + uint64_t a2 = input[2U]; + uint64_t a3 = input[3U]; + uint64_t a4 = input[4U]; + uint64_t mask0 = FStar_UInt64_gte_mask(a0, (uint64_t)0x7ffffffffffedU); + uint64_t mask1 = FStar_UInt64_eq_mask(a1, (uint64_t)0x7ffffffffffffU); + uint64_t mask2 = FStar_UInt64_eq_mask(a2, (uint64_t)0x7ffffffffffffU); + uint64_t mask3 = FStar_UInt64_eq_mask(a3, (uint64_t)0x7ffffffffffffU); + uint64_t mask4 = FStar_UInt64_eq_mask(a4, (uint64_t)0x7ffffffffffffU); + uint64_t mask = (((mask0 & mask1) & mask2) & mask3) & mask4; + uint64_t a0_ = a0 - ((uint64_t)0x7ffffffffffedU & mask); + uint64_t a1_ = a1 - ((uint64_t)0x7ffffffffffffU & mask); + uint64_t a2_ = a2 - ((uint64_t)0x7ffffffffffffU & mask); + uint64_t a3_ = a3 - ((uint64_t)0x7ffffffffffffU & mask); + uint64_t a4_ = a4 - ((uint64_t)0x7ffffffffffffU & mask); + input[0U] = a0_; + input[1U] = a1_; + input[2U] = a2_; + input[3U] = a3_; + input[4U] = a4_; +} + +static void Hacl_EC_Format_fcontract_store(uint8_t *output, uint64_t *input) +{ + uint64_t t0 = input[0U]; + uint64_t t1 = input[1U]; + uint64_t t2 = input[2U]; + uint64_t t3 = input[3U]; + uint64_t t4 = input[4U]; + uint64_t o0 = t1 << (uint32_t)51U | t0; + uint64_t o1 = t2 << (uint32_t)38U | t1 >> (uint32_t)13U; + uint64_t o2 = t3 << (uint32_t)25U | t2 >> (uint32_t)26U; + uint64_t o3 = t4 << (uint32_t)12U | t3 >> (uint32_t)39U; + uint8_t *b0 = output; + uint8_t *b1 = output + (uint32_t)8U; + uint8_t *b2 = output + (uint32_t)16U; + uint8_t *b3 = output + (uint32_t)24U; + store64_le(b0, o0); + store64_le(b1, o1); + store64_le(b2, o2); + store64_le(b3, o3); +} + +static void Hacl_EC_Format_fcontract(uint8_t *output, uint64_t *input) +{ + Hacl_EC_Format_fcontract_first_carry_full(input); + Hacl_EC_Format_fcontract_second_carry_full(input); + Hacl_EC_Format_fcontract_trim(input); + Hacl_EC_Format_fcontract_store(output, input); +} + +static void Hacl_EC_Format_scalar_of_point(uint8_t *scalar, uint64_t *point) +{ + uint64_t *x = point; + uint64_t *z = point + (uint32_t)5U; + uint64_t buf[10U] = { 0U }; + uint64_t *zmone = buf; + uint64_t *sc = buf + (uint32_t)5U; + Hacl_Bignum_crecip(zmone, z); + Hacl_Bignum_fmul(sc, x, zmone); + Hacl_EC_Format_fcontract(scalar, sc); +} + +static void +Hacl_EC_AddAndDouble_fmonty( + uint64_t *pp, + uint64_t *ppq, + uint64_t *p, + uint64_t *pq, + uint64_t *qmqp +) +{ + uint64_t *qx = qmqp; + uint64_t *x2 = pp; + uint64_t *z2 = pp + (uint32_t)5U; + uint64_t *x3 = ppq; + uint64_t *z3 = ppq + (uint32_t)5U; + uint64_t *x = p; + uint64_t *z = p + (uint32_t)5U; + uint64_t *xprime = pq; + uint64_t *zprime = pq + (uint32_t)5U; + uint64_t buf[40U] = { 0U }; + uint64_t *origx = buf; + uint64_t *origxprime0 = buf + (uint32_t)5U; + uint64_t *xxprime0 = buf + (uint32_t)25U; + uint64_t *zzprime0 = buf + (uint32_t)30U; + uint64_t *origxprime; + uint64_t *xx0; + uint64_t *zz0; + uint64_t *xxprime; + uint64_t *zzprime; + uint64_t *zzzprime; + uint64_t *zzz; + uint64_t *xx; + uint64_t *zz; + uint64_t scalar; + memcpy(origx, x, (uint32_t)5U * sizeof x[0U]); + Hacl_Bignum_fsum(x, z); + Hacl_Bignum_fdifference(z, origx); + memcpy(origxprime0, xprime, (uint32_t)5U * sizeof xprime[0U]); + Hacl_Bignum_fsum(xprime, zprime); + Hacl_Bignum_fdifference(zprime, origxprime0); + Hacl_Bignum_fmul(xxprime0, xprime, z); + Hacl_Bignum_fmul(zzprime0, x, zprime); + origxprime = buf + (uint32_t)5U; + xx0 = buf + (uint32_t)15U; + zz0 = buf + (uint32_t)20U; + xxprime = buf + (uint32_t)25U; + zzprime = buf + (uint32_t)30U; + zzzprime = buf + (uint32_t)35U; + memcpy(origxprime, xxprime, (uint32_t)5U * sizeof xxprime[0U]); + Hacl_Bignum_fsum(xxprime, zzprime); + Hacl_Bignum_fdifference(zzprime, origxprime); + Hacl_Bignum_Fsquare_fsquare_times(x3, xxprime, (uint32_t)1U); + Hacl_Bignum_Fsquare_fsquare_times(zzzprime, zzprime, (uint32_t)1U); + Hacl_Bignum_fmul(z3, zzzprime, qx); + Hacl_Bignum_Fsquare_fsquare_times(xx0, x, (uint32_t)1U); + Hacl_Bignum_Fsquare_fsquare_times(zz0, z, (uint32_t)1U); + zzz = buf + (uint32_t)10U; + xx = buf + (uint32_t)15U; + zz = buf + (uint32_t)20U; + Hacl_Bignum_fmul(x2, xx, zz); + Hacl_Bignum_fdifference(zz, xx); + scalar = (uint64_t)121665U; + Hacl_Bignum_fscalar(zzz, zz, scalar); + Hacl_Bignum_fsum(zzz, xx); + Hacl_Bignum_fmul(z2, zzz, zz); +} + +static void +Hacl_EC_Ladder_SmallLoop_cmult_small_loop_step( + uint64_t *nq, + uint64_t *nqpq, + uint64_t *nq2, + uint64_t *nqpq2, + uint64_t *q, + uint8_t byt +) +{ + uint64_t bit0 = (uint64_t)(byt >> (uint32_t)7U); + uint64_t bit; + Hacl_EC_Point_swap_conditional(nq, nqpq, bit0); + Hacl_EC_AddAndDouble_fmonty(nq2, nqpq2, nq, nqpq, q); + bit = (uint64_t)(byt >> (uint32_t)7U); + Hacl_EC_Point_swap_conditional(nq2, nqpq2, bit); +} + +static void +Hacl_EC_Ladder_SmallLoop_cmult_small_loop_double_step( + uint64_t *nq, + uint64_t *nqpq, + uint64_t *nq2, + uint64_t *nqpq2, + uint64_t *q, + uint8_t byt +) +{ + uint8_t byt1; + Hacl_EC_Ladder_SmallLoop_cmult_small_loop_step(nq, nqpq, nq2, nqpq2, q, byt); + byt1 = byt << (uint32_t)1U; + Hacl_EC_Ladder_SmallLoop_cmult_small_loop_step(nq2, nqpq2, nq, nqpq, q, byt1); +} + +static void +Hacl_EC_Ladder_SmallLoop_cmult_small_loop( + uint64_t *nq, + uint64_t *nqpq, + uint64_t *nq2, + uint64_t *nqpq2, + uint64_t *q, + uint8_t byt, + uint32_t i +) +{ + if (!(i == (uint32_t)0U)) + { + uint32_t i_ = i - (uint32_t)1U; + uint8_t byt_; + Hacl_EC_Ladder_SmallLoop_cmult_small_loop_double_step(nq, nqpq, nq2, nqpq2, q, byt); + byt_ = byt << (uint32_t)2U; + Hacl_EC_Ladder_SmallLoop_cmult_small_loop(nq, nqpq, nq2, nqpq2, q, byt_, i_); + } +} + +static void +Hacl_EC_Ladder_BigLoop_cmult_big_loop( + uint8_t *n1, + uint64_t *nq, + uint64_t *nqpq, + uint64_t *nq2, + uint64_t *nqpq2, + uint64_t *q, + uint32_t i +) +{ + if (!(i == (uint32_t)0U)) + { + uint32_t i1 = i - (uint32_t)1U; + uint8_t byte = n1[i1]; + Hacl_EC_Ladder_SmallLoop_cmult_small_loop(nq, nqpq, nq2, nqpq2, q, byte, (uint32_t)4U); + Hacl_EC_Ladder_BigLoop_cmult_big_loop(n1, nq, nqpq, nq2, nqpq2, q, i1); + } +} + +static void Hacl_EC_Ladder_cmult(uint64_t *result, uint8_t *n1, uint64_t *q) +{ + uint64_t point_buf[40U] = { 0U }; + uint64_t *nq = point_buf; + uint64_t *nqpq = point_buf + (uint32_t)10U; + uint64_t *nq2 = point_buf + (uint32_t)20U; + uint64_t *nqpq2 = point_buf + (uint32_t)30U; + Hacl_EC_Point_copy(nqpq, q); + nq[0U] = (uint64_t)1U; + Hacl_EC_Ladder_BigLoop_cmult_big_loop(n1, nq, nqpq, nq2, nqpq2, q, (uint32_t)32U); + Hacl_EC_Point_copy(result, nq); +} + +void Hacl_Curve25519_crypto_scalarmult(uint8_t *mypublic, uint8_t *secret, uint8_t *basepoint) +{ + uint64_t buf0[10U] = { 0U }; + uint64_t *x0 = buf0; + uint64_t *z = buf0 + (uint32_t)5U; + uint64_t *q; + Hacl_EC_Format_fexpand(x0, basepoint); + z[0U] = (uint64_t)1U; + q = buf0; + { + uint8_t e[32U] = { 0U }; + uint8_t e0; + uint8_t e31; + uint8_t e01; + uint8_t e311; + uint8_t e312; + uint8_t *scalar; + memcpy(e, secret, (uint32_t)32U * sizeof secret[0U]); + e0 = e[0U]; + e31 = e[31U]; + e01 = e0 & (uint8_t)248U; + e311 = e31 & (uint8_t)127U; + e312 = e311 | (uint8_t)64U; + e[0U] = e01; + e[31U] = e312; + scalar = e; + { + uint64_t buf[15U] = { 0U }; + uint64_t *nq = buf; + uint64_t *x = nq; + x[0U] = (uint64_t)1U; + Hacl_EC_Ladder_cmult(nq, scalar, q); + Hacl_EC_Format_scalar_of_point(mypublic, nq); + } + } +} + diff --git a/tf-psa-crypto/drivers/everest/library/Hacl_Curve25519_joined.c b/tf-psa-crypto/drivers/everest/library/Hacl_Curve25519_joined.c new file mode 100644 index 0000000000..17869e4d44 --- /dev/null +++ b/tf-psa-crypto/drivers/everest/library/Hacl_Curve25519_joined.c @@ -0,0 +1,50 @@ +/* + * Interface to code from Project Everest + * + * Copyright 2016-2018 INRIA and Microsoft Corporation + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ +#ifndef _BSD_SOURCE +/* Required to get htole64() from gcc/glibc's endian.h (older systems) + * when we compile with -std=c99 */ +#define _BSD_SOURCE +#endif +#ifndef _DEFAULT_SOURCE +/* (modern version of _BSD_SOURCE) */ +#define _DEFAULT_SOURCE +#endif + +#include "tf_psa_crypto_common.h" +#include "mbedtls/private_access.h" + +#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) + +#if defined(__SIZEOF_INT128__) && (__SIZEOF_INT128__ == 16) +#define MBEDTLS_HAVE_INT128 +#endif + +#if defined(MBEDTLS_HAVE_INT128) +#include "Hacl_Curve25519.c" +#else +#define KRML_VERIFIED_UINT128 +#include "kremlib/FStar_UInt128_extracted.c" +#include "legacy/Hacl_Curve25519.c" +#endif + +#include "kremlib/FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8.c" + +#endif /* defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) */ diff --git a/tf-psa-crypto/drivers/everest/library/kremlib/FStar_UInt128_extracted.c b/tf-psa-crypto/drivers/everest/library/kremlib/FStar_UInt128_extracted.c new file mode 100644 index 0000000000..1060515d92 --- /dev/null +++ b/tf-psa-crypto/drivers/everest/library/kremlib/FStar_UInt128_extracted.c @@ -0,0 +1,413 @@ +/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. + Licensed under the Apache 2.0 License. */ + +/* This file was generated by KreMLin + * KreMLin invocation: ../krml -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrB9w -minimal -fparentheses -fcurly-braces -fno-shadow -header copyright-header.txt -minimal -tmpdir extracted -warn-error +9+11 -skip-compilation -extract-uints -add-include -add-include "kremlib.h" -add-include "kremlin/internal/compat.h" extracted/prims.krml extracted/FStar_Pervasives_Native.krml extracted/FStar_Pervasives.krml extracted/FStar_Mul.krml extracted/FStar_Squash.krml extracted/FStar_Classical.krml extracted/FStar_StrongExcludedMiddle.krml extracted/FStar_FunctionalExtensionality.krml extracted/FStar_List_Tot_Base.krml extracted/FStar_List_Tot_Properties.krml extracted/FStar_List_Tot.krml extracted/FStar_Seq_Base.krml extracted/FStar_Seq_Properties.krml extracted/FStar_Seq.krml extracted/FStar_Math_Lib.krml extracted/FStar_Math_Lemmas.krml extracted/FStar_BitVector.krml extracted/FStar_UInt.krml extracted/FStar_UInt32.krml extracted/FStar_Int.krml extracted/FStar_Int16.krml extracted/FStar_Preorder.krml extracted/FStar_Ghost.krml extracted/FStar_ErasedLogic.krml extracted/FStar_UInt64.krml extracted/FStar_Set.krml extracted/FStar_PropositionalExtensionality.krml extracted/FStar_PredicateExtensionality.krml extracted/FStar_TSet.krml extracted/FStar_Monotonic_Heap.krml extracted/FStar_Heap.krml extracted/FStar_Map.krml extracted/FStar_Monotonic_HyperHeap.krml extracted/FStar_Monotonic_HyperStack.krml extracted/FStar_HyperStack.krml extracted/FStar_Monotonic_Witnessed.krml extracted/FStar_HyperStack_ST.krml extracted/FStar_HyperStack_All.krml extracted/FStar_Date.krml extracted/FStar_Universe.krml extracted/FStar_GSet.krml extracted/FStar_ModifiesGen.krml extracted/LowStar_Monotonic_Buffer.krml extracted/LowStar_Buffer.krml extracted/Spec_Loops.krml extracted/LowStar_BufferOps.krml extracted/C_Loops.krml extracted/FStar_UInt8.krml extracted/FStar_Kremlin_Endianness.krml extracted/FStar_UInt63.krml extracted/FStar_Exn.krml extracted/FStar_ST.krml extracted/FStar_All.krml extracted/FStar_Dyn.krml extracted/FStar_Int63.krml extracted/FStar_Int64.krml extracted/FStar_Int32.krml extracted/FStar_Int8.krml extracted/FStar_UInt16.krml extracted/FStar_Int_Cast.krml extracted/FStar_UInt128.krml extracted/C_Endianness.krml extracted/FStar_List.krml extracted/FStar_Float.krml extracted/FStar_IO.krml extracted/C.krml extracted/FStar_Char.krml extracted/FStar_String.krml extracted/LowStar_Modifies.krml extracted/C_String.krml extracted/FStar_Bytes.krml extracted/FStar_HyperStack_IO.krml extracted/C_Failure.krml extracted/TestLib.krml extracted/FStar_Int_Cast_Full.krml + * F* version: 059db0c8 + * KreMLin version: 916c37ac + */ + + +#include "FStar_UInt128.h" +#include "kremlin/c_endianness.h" +#include "FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8.h" + +uint64_t FStar_UInt128___proj__Mkuint128__item__low(FStar_UInt128_uint128 projectee) +{ + return projectee.low; +} + +uint64_t FStar_UInt128___proj__Mkuint128__item__high(FStar_UInt128_uint128 projectee) +{ + return projectee.high; +} + +static uint64_t FStar_UInt128_constant_time_carry(uint64_t a, uint64_t b) +{ + return (a ^ ((a ^ b) | ((a - b) ^ b))) >> (uint32_t)63U; +} + +static uint64_t FStar_UInt128_carry(uint64_t a, uint64_t b) +{ + return FStar_UInt128_constant_time_carry(a, b); +} + +FStar_UInt128_uint128 FStar_UInt128_add(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) +{ + FStar_UInt128_uint128 + flat = { a.low + b.low, a.high + b.high + FStar_UInt128_carry(a.low + b.low, b.low) }; + return flat; +} + +FStar_UInt128_uint128 +FStar_UInt128_add_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) +{ + FStar_UInt128_uint128 + flat = { a.low + b.low, a.high + b.high + FStar_UInt128_carry(a.low + b.low, b.low) }; + return flat; +} + +FStar_UInt128_uint128 FStar_UInt128_add_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) +{ + FStar_UInt128_uint128 + flat = { a.low + b.low, a.high + b.high + FStar_UInt128_carry(a.low + b.low, b.low) }; + return flat; +} + +FStar_UInt128_uint128 FStar_UInt128_sub(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) +{ + FStar_UInt128_uint128 + flat = { a.low - b.low, a.high - b.high - FStar_UInt128_carry(a.low, a.low - b.low) }; + return flat; +} + +FStar_UInt128_uint128 +FStar_UInt128_sub_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) +{ + FStar_UInt128_uint128 + flat = { a.low - b.low, a.high - b.high - FStar_UInt128_carry(a.low, a.low - b.low) }; + return flat; +} + +static FStar_UInt128_uint128 +FStar_UInt128_sub_mod_impl(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) +{ + FStar_UInt128_uint128 + flat = { a.low - b.low, a.high - b.high - FStar_UInt128_carry(a.low, a.low - b.low) }; + return flat; +} + +FStar_UInt128_uint128 FStar_UInt128_sub_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) +{ + return FStar_UInt128_sub_mod_impl(a, b); +} + +FStar_UInt128_uint128 FStar_UInt128_logand(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) +{ + FStar_UInt128_uint128 flat = { a.low & b.low, a.high & b.high }; + return flat; +} + +FStar_UInt128_uint128 FStar_UInt128_logxor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) +{ + FStar_UInt128_uint128 flat = { a.low ^ b.low, a.high ^ b.high }; + return flat; +} + +FStar_UInt128_uint128 FStar_UInt128_logor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) +{ + FStar_UInt128_uint128 flat = { a.low | b.low, a.high | b.high }; + return flat; +} + +FStar_UInt128_uint128 FStar_UInt128_lognot(FStar_UInt128_uint128 a) +{ + FStar_UInt128_uint128 flat = { ~a.low, ~a.high }; + return flat; +} + +static uint32_t FStar_UInt128_u32_64 = (uint32_t)64U; + +static uint64_t FStar_UInt128_add_u64_shift_left(uint64_t hi, uint64_t lo, uint32_t s) +{ + return (hi << s) + (lo >> (FStar_UInt128_u32_64 - s)); +} + +static uint64_t FStar_UInt128_add_u64_shift_left_respec(uint64_t hi, uint64_t lo, uint32_t s) +{ + return FStar_UInt128_add_u64_shift_left(hi, lo, s); +} + +static FStar_UInt128_uint128 +FStar_UInt128_shift_left_small(FStar_UInt128_uint128 a, uint32_t s) +{ + if (s == (uint32_t)0U) + { + return a; + } + else + { + FStar_UInt128_uint128 + flat = { a.low << s, FStar_UInt128_add_u64_shift_left_respec(a.high, a.low, s) }; + return flat; + } +} + +static FStar_UInt128_uint128 +FStar_UInt128_shift_left_large(FStar_UInt128_uint128 a, uint32_t s) +{ + FStar_UInt128_uint128 flat = { (uint64_t)0U, a.low << (s - FStar_UInt128_u32_64) }; + return flat; +} + +FStar_UInt128_uint128 FStar_UInt128_shift_left(FStar_UInt128_uint128 a, uint32_t s) +{ + if (s < FStar_UInt128_u32_64) + { + return FStar_UInt128_shift_left_small(a, s); + } + else + { + return FStar_UInt128_shift_left_large(a, s); + } +} + +static uint64_t FStar_UInt128_add_u64_shift_right(uint64_t hi, uint64_t lo, uint32_t s) +{ + return (lo >> s) + (hi << (FStar_UInt128_u32_64 - s)); +} + +static uint64_t FStar_UInt128_add_u64_shift_right_respec(uint64_t hi, uint64_t lo, uint32_t s) +{ + return FStar_UInt128_add_u64_shift_right(hi, lo, s); +} + +static FStar_UInt128_uint128 +FStar_UInt128_shift_right_small(FStar_UInt128_uint128 a, uint32_t s) +{ + if (s == (uint32_t)0U) + { + return a; + } + else + { + FStar_UInt128_uint128 + flat = { FStar_UInt128_add_u64_shift_right_respec(a.high, a.low, s), a.high >> s }; + return flat; + } +} + +static FStar_UInt128_uint128 +FStar_UInt128_shift_right_large(FStar_UInt128_uint128 a, uint32_t s) +{ + FStar_UInt128_uint128 flat = { a.high >> (s - FStar_UInt128_u32_64), (uint64_t)0U }; + return flat; +} + +FStar_UInt128_uint128 FStar_UInt128_shift_right(FStar_UInt128_uint128 a, uint32_t s) +{ + if (s < FStar_UInt128_u32_64) + { + return FStar_UInt128_shift_right_small(a, s); + } + else + { + return FStar_UInt128_shift_right_large(a, s); + } +} + +bool FStar_UInt128_eq(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) +{ + return a.low == b.low && a.high == b.high; +} + +bool FStar_UInt128_gt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) +{ + return a.high > b.high || (a.high == b.high && a.low > b.low); +} + +bool FStar_UInt128_lt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) +{ + return a.high < b.high || (a.high == b.high && a.low < b.low); +} + +bool FStar_UInt128_gte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) +{ + return a.high > b.high || (a.high == b.high && a.low >= b.low); +} + +bool FStar_UInt128_lte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) +{ + return a.high < b.high || (a.high == b.high && a.low <= b.low); +} + +FStar_UInt128_uint128 FStar_UInt128_eq_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) +{ + FStar_UInt128_uint128 + flat = + { + FStar_UInt64_eq_mask(a.low, + b.low) + & FStar_UInt64_eq_mask(a.high, b.high), + FStar_UInt64_eq_mask(a.low, + b.low) + & FStar_UInt64_eq_mask(a.high, b.high) + }; + return flat; +} + +FStar_UInt128_uint128 FStar_UInt128_gte_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) +{ + FStar_UInt128_uint128 + flat = + { + (FStar_UInt64_gte_mask(a.high, b.high) & ~FStar_UInt64_eq_mask(a.high, b.high)) + | (FStar_UInt64_eq_mask(a.high, b.high) & FStar_UInt64_gte_mask(a.low, b.low)), + (FStar_UInt64_gte_mask(a.high, b.high) & ~FStar_UInt64_eq_mask(a.high, b.high)) + | (FStar_UInt64_eq_mask(a.high, b.high) & FStar_UInt64_gte_mask(a.low, b.low)) + }; + return flat; +} + +FStar_UInt128_uint128 FStar_UInt128_uint64_to_uint128(uint64_t a) +{ + FStar_UInt128_uint128 flat = { a, (uint64_t)0U }; + return flat; +} + +uint64_t FStar_UInt128_uint128_to_uint64(FStar_UInt128_uint128 a) +{ + return a.low; +} + +FStar_UInt128_uint128 +(*FStar_UInt128_op_Plus_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) = + FStar_UInt128_add; + +FStar_UInt128_uint128 +(*FStar_UInt128_op_Plus_Question_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) = + FStar_UInt128_add_underspec; + +FStar_UInt128_uint128 +(*FStar_UInt128_op_Plus_Percent_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) = + FStar_UInt128_add_mod; + +FStar_UInt128_uint128 +(*FStar_UInt128_op_Subtraction_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) = + FStar_UInt128_sub; + +FStar_UInt128_uint128 +(*FStar_UInt128_op_Subtraction_Question_Hat)( + FStar_UInt128_uint128 x0, + FStar_UInt128_uint128 x1 +) = FStar_UInt128_sub_underspec; + +FStar_UInt128_uint128 +(*FStar_UInt128_op_Subtraction_Percent_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) = + FStar_UInt128_sub_mod; + +FStar_UInt128_uint128 +(*FStar_UInt128_op_Amp_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) = + FStar_UInt128_logand; + +FStar_UInt128_uint128 +(*FStar_UInt128_op_Hat_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) = + FStar_UInt128_logxor; + +FStar_UInt128_uint128 +(*FStar_UInt128_op_Bar_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) = + FStar_UInt128_logor; + +FStar_UInt128_uint128 +(*FStar_UInt128_op_Less_Less_Hat)(FStar_UInt128_uint128 x0, uint32_t x1) = + FStar_UInt128_shift_left; + +FStar_UInt128_uint128 +(*FStar_UInt128_op_Greater_Greater_Hat)(FStar_UInt128_uint128 x0, uint32_t x1) = + FStar_UInt128_shift_right; + +bool +(*FStar_UInt128_op_Equals_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) = + FStar_UInt128_eq; + +bool +(*FStar_UInt128_op_Greater_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) = + FStar_UInt128_gt; + +bool +(*FStar_UInt128_op_Less_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) = + FStar_UInt128_lt; + +bool +(*FStar_UInt128_op_Greater_Equals_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) = + FStar_UInt128_gte; + +bool +(*FStar_UInt128_op_Less_Equals_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) = + FStar_UInt128_lte; + +static uint64_t FStar_UInt128_u64_mod_32(uint64_t a) +{ + return a & (uint64_t)0xffffffffU; +} + +static uint32_t FStar_UInt128_u32_32 = (uint32_t)32U; + +static uint64_t FStar_UInt128_u32_combine(uint64_t hi, uint64_t lo) +{ + return lo + (hi << FStar_UInt128_u32_32); +} + +FStar_UInt128_uint128 FStar_UInt128_mul32(uint64_t x, uint32_t y) +{ + FStar_UInt128_uint128 + flat = + { + FStar_UInt128_u32_combine((x >> FStar_UInt128_u32_32) + * (uint64_t)y + + (FStar_UInt128_u64_mod_32(x) * (uint64_t)y >> FStar_UInt128_u32_32), + FStar_UInt128_u64_mod_32(FStar_UInt128_u64_mod_32(x) * (uint64_t)y)), + ((x >> FStar_UInt128_u32_32) + * (uint64_t)y + + (FStar_UInt128_u64_mod_32(x) * (uint64_t)y >> FStar_UInt128_u32_32)) + >> FStar_UInt128_u32_32 + }; + return flat; +} + +typedef struct K___uint64_t_uint64_t_uint64_t_uint64_t_s +{ + uint64_t fst; + uint64_t snd; + uint64_t thd; + uint64_t f3; +} +K___uint64_t_uint64_t_uint64_t_uint64_t; + +static K___uint64_t_uint64_t_uint64_t_uint64_t +FStar_UInt128_mul_wide_impl_t_(uint64_t x, uint64_t y) +{ + K___uint64_t_uint64_t_uint64_t_uint64_t + flat = + { + FStar_UInt128_u64_mod_32(x), + FStar_UInt128_u64_mod_32(FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y)), + x + >> FStar_UInt128_u32_32, + (x >> FStar_UInt128_u32_32) + * FStar_UInt128_u64_mod_32(y) + + (FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y) >> FStar_UInt128_u32_32) + }; + return flat; +} + +static uint64_t FStar_UInt128_u32_combine_(uint64_t hi, uint64_t lo) +{ + return lo + (hi << FStar_UInt128_u32_32); +} + +static FStar_UInt128_uint128 FStar_UInt128_mul_wide_impl(uint64_t x, uint64_t y) +{ + K___uint64_t_uint64_t_uint64_t_uint64_t scrut = FStar_UInt128_mul_wide_impl_t_(x, y); + uint64_t u1 = scrut.fst; + uint64_t w3 = scrut.snd; + uint64_t x_ = scrut.thd; + uint64_t t_ = scrut.f3; + FStar_UInt128_uint128 + flat = + { + FStar_UInt128_u32_combine_(u1 * (y >> FStar_UInt128_u32_32) + FStar_UInt128_u64_mod_32(t_), + w3), + x_ + * (y >> FStar_UInt128_u32_32) + + (t_ >> FStar_UInt128_u32_32) + + ((u1 * (y >> FStar_UInt128_u32_32) + FStar_UInt128_u64_mod_32(t_)) >> FStar_UInt128_u32_32) + }; + return flat; +} + +FStar_UInt128_uint128 FStar_UInt128_mul_wide(uint64_t x, uint64_t y) +{ + return FStar_UInt128_mul_wide_impl(x, y); +} + diff --git a/tf-psa-crypto/drivers/everest/library/kremlib/FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8.c b/tf-psa-crypto/drivers/everest/library/kremlib/FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8.c new file mode 100644 index 0000000000..08265248f2 --- /dev/null +++ b/tf-psa-crypto/drivers/everest/library/kremlib/FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8.c @@ -0,0 +1,100 @@ +/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. + Licensed under the Apache 2.0 License. */ + +/* This file was generated by KreMLin + * KreMLin invocation: ../krml -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrB9w -minimal -fparentheses -fcurly-braces -fno-shadow -header copyright-header.txt -minimal -tmpdir dist/minimal -skip-compilation -extract-uints -add-include -add-include -add-include "kremlin/internal/compat.h" -add-include "kremlin/internal/types.h" -bundle FStar.UInt64+FStar.UInt32+FStar.UInt16+FStar.UInt8=* extracted/prims.krml extracted/FStar_Pervasives_Native.krml extracted/FStar_Pervasives.krml extracted/FStar_Mul.krml extracted/FStar_Squash.krml extracted/FStar_Classical.krml extracted/FStar_StrongExcludedMiddle.krml extracted/FStar_FunctionalExtensionality.krml extracted/FStar_List_Tot_Base.krml extracted/FStar_List_Tot_Properties.krml extracted/FStar_List_Tot.krml extracted/FStar_Seq_Base.krml extracted/FStar_Seq_Properties.krml extracted/FStar_Seq.krml extracted/FStar_Math_Lib.krml extracted/FStar_Math_Lemmas.krml extracted/FStar_BitVector.krml extracted/FStar_UInt.krml extracted/FStar_UInt32.krml extracted/FStar_Int.krml extracted/FStar_Int16.krml extracted/FStar_Preorder.krml extracted/FStar_Ghost.krml extracted/FStar_ErasedLogic.krml extracted/FStar_UInt64.krml extracted/FStar_Set.krml extracted/FStar_PropositionalExtensionality.krml extracted/FStar_PredicateExtensionality.krml extracted/FStar_TSet.krml extracted/FStar_Monotonic_Heap.krml extracted/FStar_Heap.krml extracted/FStar_Map.krml extracted/FStar_Monotonic_HyperHeap.krml extracted/FStar_Monotonic_HyperStack.krml extracted/FStar_HyperStack.krml extracted/FStar_Monotonic_Witnessed.krml extracted/FStar_HyperStack_ST.krml extracted/FStar_HyperStack_All.krml extracted/FStar_Date.krml extracted/FStar_Universe.krml extracted/FStar_GSet.krml extracted/FStar_ModifiesGen.krml extracted/LowStar_Monotonic_Buffer.krml extracted/LowStar_Buffer.krml extracted/Spec_Loops.krml extracted/LowStar_BufferOps.krml extracted/C_Loops.krml extracted/FStar_UInt8.krml extracted/FStar_Kremlin_Endianness.krml extracted/FStar_UInt63.krml extracted/FStar_Exn.krml extracted/FStar_ST.krml extracted/FStar_All.krml extracted/FStar_Dyn.krml extracted/FStar_Int63.krml extracted/FStar_Int64.krml extracted/FStar_Int32.krml extracted/FStar_Int8.krml extracted/FStar_UInt16.krml extracted/FStar_Int_Cast.krml extracted/FStar_UInt128.krml extracted/C_Endianness.krml extracted/FStar_List.krml extracted/FStar_Float.krml extracted/FStar_IO.krml extracted/C.krml extracted/FStar_Char.krml extracted/FStar_String.krml extracted/LowStar_Modifies.krml extracted/C_String.krml extracted/FStar_Bytes.krml extracted/FStar_HyperStack_IO.krml extracted/C_Failure.krml extracted/TestLib.krml extracted/FStar_Int_Cast_Full.krml + * F* version: 059db0c8 + * KreMLin version: 916c37ac + */ + + +#include "FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8.h" + +uint64_t FStar_UInt64_eq_mask(uint64_t a, uint64_t b) +{ + uint64_t x = a ^ b; + uint64_t minus_x = ~x + (uint64_t)1U; + uint64_t x_or_minus_x = x | minus_x; + uint64_t xnx = x_or_minus_x >> (uint32_t)63U; + return xnx - (uint64_t)1U; +} + +uint64_t FStar_UInt64_gte_mask(uint64_t a, uint64_t b) +{ + uint64_t x = a; + uint64_t y = b; + uint64_t x_xor_y = x ^ y; + uint64_t x_sub_y = x - y; + uint64_t x_sub_y_xor_y = x_sub_y ^ y; + uint64_t q = x_xor_y | x_sub_y_xor_y; + uint64_t x_xor_q = x ^ q; + uint64_t x_xor_q_ = x_xor_q >> (uint32_t)63U; + return x_xor_q_ - (uint64_t)1U; +} + +uint32_t FStar_UInt32_eq_mask(uint32_t a, uint32_t b) +{ + uint32_t x = a ^ b; + uint32_t minus_x = ~x + (uint32_t)1U; + uint32_t x_or_minus_x = x | minus_x; + uint32_t xnx = x_or_minus_x >> (uint32_t)31U; + return xnx - (uint32_t)1U; +} + +uint32_t FStar_UInt32_gte_mask(uint32_t a, uint32_t b) +{ + uint32_t x = a; + uint32_t y = b; + uint32_t x_xor_y = x ^ y; + uint32_t x_sub_y = x - y; + uint32_t x_sub_y_xor_y = x_sub_y ^ y; + uint32_t q = x_xor_y | x_sub_y_xor_y; + uint32_t x_xor_q = x ^ q; + uint32_t x_xor_q_ = x_xor_q >> (uint32_t)31U; + return x_xor_q_ - (uint32_t)1U; +} + +uint16_t FStar_UInt16_eq_mask(uint16_t a, uint16_t b) +{ + uint16_t x = a ^ b; + uint16_t minus_x = ~x + (uint16_t)1U; + uint16_t x_or_minus_x = x | minus_x; + uint16_t xnx = x_or_minus_x >> (uint32_t)15U; + return xnx - (uint16_t)1U; +} + +uint16_t FStar_UInt16_gte_mask(uint16_t a, uint16_t b) +{ + uint16_t x = a; + uint16_t y = b; + uint16_t x_xor_y = x ^ y; + uint16_t x_sub_y = x - y; + uint16_t x_sub_y_xor_y = x_sub_y ^ y; + uint16_t q = x_xor_y | x_sub_y_xor_y; + uint16_t x_xor_q = x ^ q; + uint16_t x_xor_q_ = x_xor_q >> (uint32_t)15U; + return x_xor_q_ - (uint16_t)1U; +} + +uint8_t FStar_UInt8_eq_mask(uint8_t a, uint8_t b) +{ + uint8_t x = a ^ b; + uint8_t minus_x = ~x + (uint8_t)1U; + uint8_t x_or_minus_x = x | minus_x; + uint8_t xnx = x_or_minus_x >> (uint32_t)7U; + return xnx - (uint8_t)1U; +} + +uint8_t FStar_UInt8_gte_mask(uint8_t a, uint8_t b) +{ + uint8_t x = a; + uint8_t y = b; + uint8_t x_xor_y = x ^ y; + uint8_t x_sub_y = x - y; + uint8_t x_sub_y_xor_y = x_sub_y ^ y; + uint8_t q = x_xor_y | x_sub_y_xor_y; + uint8_t x_xor_q = x ^ q; + uint8_t x_xor_q_ = x_xor_q >> (uint32_t)7U; + return x_xor_q_ - (uint8_t)1U; +} + diff --git a/tf-psa-crypto/drivers/everest/library/legacy/Hacl_Curve25519.c b/tf-psa-crypto/drivers/everest/library/legacy/Hacl_Curve25519.c new file mode 100644 index 0000000000..babebe4f11 --- /dev/null +++ b/tf-psa-crypto/drivers/everest/library/legacy/Hacl_Curve25519.c @@ -0,0 +1,805 @@ +/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. + Licensed under the Apache 2.0 License. */ + +/* This file was generated by KreMLin + * KreMLin invocation: /mnt/e/everest/verify/kremlin/krml -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrcLh -minimal -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrcLh -minimal -I /mnt/e/everest/verify/hacl-star/code/lib/kremlin -I /mnt/e/everest/verify/kremlin/kremlib/compat -I /mnt/e/everest/verify/hacl-star/specs -I /mnt/e/everest/verify/hacl-star/specs/old -I . -ccopt -march=native -verbose -ldopt -flto -tmpdir x25519-c -I ../bignum -bundle Hacl.Curve25519=* -minimal -add-include "kremlib.h" -skip-compilation x25519-c/out.krml -o x25519-c/Hacl_Curve25519.c + * F* version: 059db0c8 + * KreMLin version: 916c37ac + */ + + +#include "Hacl_Curve25519.h" + +extern uint64_t FStar_UInt64_eq_mask(uint64_t x0, uint64_t x1); + +extern uint64_t FStar_UInt64_gte_mask(uint64_t x0, uint64_t x1); + +extern FStar_UInt128_uint128 +FStar_UInt128_add(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1); + +extern FStar_UInt128_uint128 +FStar_UInt128_add_mod(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1); + +extern FStar_UInt128_uint128 +FStar_UInt128_logand(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1); + +extern FStar_UInt128_uint128 FStar_UInt128_shift_right(FStar_UInt128_uint128 x0, uint32_t x1); + +extern FStar_UInt128_uint128 FStar_UInt128_uint64_to_uint128(uint64_t x0); + +extern uint64_t FStar_UInt128_uint128_to_uint64(FStar_UInt128_uint128 x0); + +extern FStar_UInt128_uint128 FStar_UInt128_mul_wide(uint64_t x0, uint64_t x1); + +static void Hacl_Bignum_Modulo_carry_top(uint64_t *b) +{ + uint64_t b4 = b[4U]; + uint64_t b0 = b[0U]; + uint64_t b4_ = b4 & (uint64_t)0x7ffffffffffffU; + uint64_t b0_ = b0 + (uint64_t)19U * (b4 >> (uint32_t)51U); + b[4U] = b4_; + b[0U] = b0_; +} + +inline static void +Hacl_Bignum_Fproduct_copy_from_wide_(uint64_t *output, FStar_UInt128_uint128 *input) +{ + uint32_t i; + for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U) + { + FStar_UInt128_uint128 xi = input[i]; + output[i] = FStar_UInt128_uint128_to_uint64(xi); + } +} + +inline static void +Hacl_Bignum_Fproduct_sum_scalar_multiplication_( + FStar_UInt128_uint128 *output, + uint64_t *input, + uint64_t s +) +{ + uint32_t i; + for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U) + { + FStar_UInt128_uint128 xi = output[i]; + uint64_t yi = input[i]; + output[i] = FStar_UInt128_add_mod(xi, FStar_UInt128_mul_wide(yi, s)); + } +} + +inline static void Hacl_Bignum_Fproduct_carry_wide_(FStar_UInt128_uint128 *tmp) +{ + uint32_t i; + for (i = (uint32_t)0U; i < (uint32_t)4U; i = i + (uint32_t)1U) + { + uint32_t ctr = i; + FStar_UInt128_uint128 tctr = tmp[ctr]; + FStar_UInt128_uint128 tctrp1 = tmp[ctr + (uint32_t)1U]; + uint64_t r0 = FStar_UInt128_uint128_to_uint64(tctr) & (uint64_t)0x7ffffffffffffU; + FStar_UInt128_uint128 c = FStar_UInt128_shift_right(tctr, (uint32_t)51U); + tmp[ctr] = FStar_UInt128_uint64_to_uint128(r0); + tmp[ctr + (uint32_t)1U] = FStar_UInt128_add(tctrp1, c); + } +} + +inline static void Hacl_Bignum_Fmul_shift_reduce(uint64_t *output) +{ + uint64_t tmp = output[4U]; + uint64_t b0; + { + uint32_t i; + for (i = (uint32_t)0U; i < (uint32_t)4U; i = i + (uint32_t)1U) + { + uint32_t ctr = (uint32_t)5U - i - (uint32_t)1U; + uint64_t z = output[ctr - (uint32_t)1U]; + output[ctr] = z; + } + } + output[0U] = tmp; + b0 = output[0U]; + output[0U] = (uint64_t)19U * b0; +} + +static void +Hacl_Bignum_Fmul_mul_shift_reduce_( + FStar_UInt128_uint128 *output, + uint64_t *input, + uint64_t *input2 +) +{ + uint32_t i; + uint64_t input2i; + { + uint32_t i0; + for (i0 = (uint32_t)0U; i0 < (uint32_t)4U; i0 = i0 + (uint32_t)1U) + { + uint64_t input2i0 = input2[i0]; + Hacl_Bignum_Fproduct_sum_scalar_multiplication_(output, input, input2i0); + Hacl_Bignum_Fmul_shift_reduce(input); + } + } + i = (uint32_t)4U; + input2i = input2[i]; + Hacl_Bignum_Fproduct_sum_scalar_multiplication_(output, input, input2i); +} + +inline static void Hacl_Bignum_Fmul_fmul(uint64_t *output, uint64_t *input, uint64_t *input2) +{ + uint64_t tmp[5U] = { 0U }; + memcpy(tmp, input, (uint32_t)5U * sizeof input[0U]); + KRML_CHECK_SIZE(sizeof (FStar_UInt128_uint128), (uint32_t)5U); + { + FStar_UInt128_uint128 t[5U]; + { + uint32_t _i; + for (_i = 0U; _i < (uint32_t)5U; ++_i) + t[_i] = FStar_UInt128_uint64_to_uint128((uint64_t)0U); + } + { + FStar_UInt128_uint128 b4; + FStar_UInt128_uint128 b0; + FStar_UInt128_uint128 b4_; + FStar_UInt128_uint128 b0_; + uint64_t i0; + uint64_t i1; + uint64_t i0_; + uint64_t i1_; + Hacl_Bignum_Fmul_mul_shift_reduce_(t, tmp, input2); + Hacl_Bignum_Fproduct_carry_wide_(t); + b4 = t[4U]; + b0 = t[0U]; + b4_ = FStar_UInt128_logand(b4, FStar_UInt128_uint64_to_uint128((uint64_t)0x7ffffffffffffU)); + b0_ = + FStar_UInt128_add(b0, + FStar_UInt128_mul_wide((uint64_t)19U, + FStar_UInt128_uint128_to_uint64(FStar_UInt128_shift_right(b4, (uint32_t)51U)))); + t[4U] = b4_; + t[0U] = b0_; + Hacl_Bignum_Fproduct_copy_from_wide_(output, t); + i0 = output[0U]; + i1 = output[1U]; + i0_ = i0 & (uint64_t)0x7ffffffffffffU; + i1_ = i1 + (i0 >> (uint32_t)51U); + output[0U] = i0_; + output[1U] = i1_; + } + } +} + +inline static void Hacl_Bignum_Fsquare_fsquare__(FStar_UInt128_uint128 *tmp, uint64_t *output) +{ + uint64_t r0 = output[0U]; + uint64_t r1 = output[1U]; + uint64_t r2 = output[2U]; + uint64_t r3 = output[3U]; + uint64_t r4 = output[4U]; + uint64_t d0 = r0 * (uint64_t)2U; + uint64_t d1 = r1 * (uint64_t)2U; + uint64_t d2 = r2 * (uint64_t)2U * (uint64_t)19U; + uint64_t d419 = r4 * (uint64_t)19U; + uint64_t d4 = d419 * (uint64_t)2U; + FStar_UInt128_uint128 + s0 = + FStar_UInt128_add(FStar_UInt128_add(FStar_UInt128_mul_wide(r0, r0), + FStar_UInt128_mul_wide(d4, r1)), + FStar_UInt128_mul_wide(d2, r3)); + FStar_UInt128_uint128 + s1 = + FStar_UInt128_add(FStar_UInt128_add(FStar_UInt128_mul_wide(d0, r1), + FStar_UInt128_mul_wide(d4, r2)), + FStar_UInt128_mul_wide(r3 * (uint64_t)19U, r3)); + FStar_UInt128_uint128 + s2 = + FStar_UInt128_add(FStar_UInt128_add(FStar_UInt128_mul_wide(d0, r2), + FStar_UInt128_mul_wide(r1, r1)), + FStar_UInt128_mul_wide(d4, r3)); + FStar_UInt128_uint128 + s3 = + FStar_UInt128_add(FStar_UInt128_add(FStar_UInt128_mul_wide(d0, r3), + FStar_UInt128_mul_wide(d1, r2)), + FStar_UInt128_mul_wide(r4, d419)); + FStar_UInt128_uint128 + s4 = + FStar_UInt128_add(FStar_UInt128_add(FStar_UInt128_mul_wide(d0, r4), + FStar_UInt128_mul_wide(d1, r3)), + FStar_UInt128_mul_wide(r2, r2)); + tmp[0U] = s0; + tmp[1U] = s1; + tmp[2U] = s2; + tmp[3U] = s3; + tmp[4U] = s4; +} + +inline static void Hacl_Bignum_Fsquare_fsquare_(FStar_UInt128_uint128 *tmp, uint64_t *output) +{ + FStar_UInt128_uint128 b4; + FStar_UInt128_uint128 b0; + FStar_UInt128_uint128 b4_; + FStar_UInt128_uint128 b0_; + uint64_t i0; + uint64_t i1; + uint64_t i0_; + uint64_t i1_; + Hacl_Bignum_Fsquare_fsquare__(tmp, output); + Hacl_Bignum_Fproduct_carry_wide_(tmp); + b4 = tmp[4U]; + b0 = tmp[0U]; + b4_ = FStar_UInt128_logand(b4, FStar_UInt128_uint64_to_uint128((uint64_t)0x7ffffffffffffU)); + b0_ = + FStar_UInt128_add(b0, + FStar_UInt128_mul_wide((uint64_t)19U, + FStar_UInt128_uint128_to_uint64(FStar_UInt128_shift_right(b4, (uint32_t)51U)))); + tmp[4U] = b4_; + tmp[0U] = b0_; + Hacl_Bignum_Fproduct_copy_from_wide_(output, tmp); + i0 = output[0U]; + i1 = output[1U]; + i0_ = i0 & (uint64_t)0x7ffffffffffffU; + i1_ = i1 + (i0 >> (uint32_t)51U); + output[0U] = i0_; + output[1U] = i1_; +} + +static void +Hacl_Bignum_Fsquare_fsquare_times_( + uint64_t *input, + FStar_UInt128_uint128 *tmp, + uint32_t count1 +) +{ + uint32_t i; + Hacl_Bignum_Fsquare_fsquare_(tmp, input); + for (i = (uint32_t)1U; i < count1; i = i + (uint32_t)1U) + Hacl_Bignum_Fsquare_fsquare_(tmp, input); +} + +inline static void +Hacl_Bignum_Fsquare_fsquare_times(uint64_t *output, uint64_t *input, uint32_t count1) +{ + KRML_CHECK_SIZE(sizeof (FStar_UInt128_uint128), (uint32_t)5U); + { + FStar_UInt128_uint128 t[5U]; + { + uint32_t _i; + for (_i = 0U; _i < (uint32_t)5U; ++_i) + t[_i] = FStar_UInt128_uint64_to_uint128((uint64_t)0U); + } + memcpy(output, input, (uint32_t)5U * sizeof input[0U]); + Hacl_Bignum_Fsquare_fsquare_times_(output, t, count1); + } +} + +inline static void Hacl_Bignum_Fsquare_fsquare_times_inplace(uint64_t *output, uint32_t count1) +{ + KRML_CHECK_SIZE(sizeof (FStar_UInt128_uint128), (uint32_t)5U); + { + FStar_UInt128_uint128 t[5U]; + { + uint32_t _i; + for (_i = 0U; _i < (uint32_t)5U; ++_i) + t[_i] = FStar_UInt128_uint64_to_uint128((uint64_t)0U); + } + Hacl_Bignum_Fsquare_fsquare_times_(output, t, count1); + } +} + +inline static void Hacl_Bignum_Crecip_crecip(uint64_t *out, uint64_t *z) +{ + uint64_t buf[20U] = { 0U }; + uint64_t *a0 = buf; + uint64_t *t00 = buf + (uint32_t)5U; + uint64_t *b0 = buf + (uint32_t)10U; + uint64_t *t01; + uint64_t *b1; + uint64_t *c0; + uint64_t *a; + uint64_t *t0; + uint64_t *b; + uint64_t *c; + Hacl_Bignum_Fsquare_fsquare_times(a0, z, (uint32_t)1U); + Hacl_Bignum_Fsquare_fsquare_times(t00, a0, (uint32_t)2U); + Hacl_Bignum_Fmul_fmul(b0, t00, z); + Hacl_Bignum_Fmul_fmul(a0, b0, a0); + Hacl_Bignum_Fsquare_fsquare_times(t00, a0, (uint32_t)1U); + Hacl_Bignum_Fmul_fmul(b0, t00, b0); + Hacl_Bignum_Fsquare_fsquare_times(t00, b0, (uint32_t)5U); + t01 = buf + (uint32_t)5U; + b1 = buf + (uint32_t)10U; + c0 = buf + (uint32_t)15U; + Hacl_Bignum_Fmul_fmul(b1, t01, b1); + Hacl_Bignum_Fsquare_fsquare_times(t01, b1, (uint32_t)10U); + Hacl_Bignum_Fmul_fmul(c0, t01, b1); + Hacl_Bignum_Fsquare_fsquare_times(t01, c0, (uint32_t)20U); + Hacl_Bignum_Fmul_fmul(t01, t01, c0); + Hacl_Bignum_Fsquare_fsquare_times_inplace(t01, (uint32_t)10U); + Hacl_Bignum_Fmul_fmul(b1, t01, b1); + Hacl_Bignum_Fsquare_fsquare_times(t01, b1, (uint32_t)50U); + a = buf; + t0 = buf + (uint32_t)5U; + b = buf + (uint32_t)10U; + c = buf + (uint32_t)15U; + Hacl_Bignum_Fmul_fmul(c, t0, b); + Hacl_Bignum_Fsquare_fsquare_times(t0, c, (uint32_t)100U); + Hacl_Bignum_Fmul_fmul(t0, t0, c); + Hacl_Bignum_Fsquare_fsquare_times_inplace(t0, (uint32_t)50U); + Hacl_Bignum_Fmul_fmul(t0, t0, b); + Hacl_Bignum_Fsquare_fsquare_times_inplace(t0, (uint32_t)5U); + Hacl_Bignum_Fmul_fmul(out, t0, a); +} + +inline static void Hacl_Bignum_fsum(uint64_t *a, uint64_t *b) +{ + uint32_t i; + for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U) + { + uint64_t xi = a[i]; + uint64_t yi = b[i]; + a[i] = xi + yi; + } +} + +inline static void Hacl_Bignum_fdifference(uint64_t *a, uint64_t *b) +{ + uint64_t tmp[5U] = { 0U }; + uint64_t b0; + uint64_t b1; + uint64_t b2; + uint64_t b3; + uint64_t b4; + memcpy(tmp, b, (uint32_t)5U * sizeof b[0U]); + b0 = tmp[0U]; + b1 = tmp[1U]; + b2 = tmp[2U]; + b3 = tmp[3U]; + b4 = tmp[4U]; + tmp[0U] = b0 + (uint64_t)0x3fffffffffff68U; + tmp[1U] = b1 + (uint64_t)0x3ffffffffffff8U; + tmp[2U] = b2 + (uint64_t)0x3ffffffffffff8U; + tmp[3U] = b3 + (uint64_t)0x3ffffffffffff8U; + tmp[4U] = b4 + (uint64_t)0x3ffffffffffff8U; + { + uint32_t i; + for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U) + { + uint64_t xi = a[i]; + uint64_t yi = tmp[i]; + a[i] = yi - xi; + } + } +} + +inline static void Hacl_Bignum_fscalar(uint64_t *output, uint64_t *b, uint64_t s) +{ + KRML_CHECK_SIZE(sizeof (FStar_UInt128_uint128), (uint32_t)5U); + { + FStar_UInt128_uint128 tmp[5U]; + { + uint32_t _i; + for (_i = 0U; _i < (uint32_t)5U; ++_i) + tmp[_i] = FStar_UInt128_uint64_to_uint128((uint64_t)0U); + } + { + FStar_UInt128_uint128 b4; + FStar_UInt128_uint128 b0; + FStar_UInt128_uint128 b4_; + FStar_UInt128_uint128 b0_; + { + uint32_t i; + for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U) + { + uint64_t xi = b[i]; + tmp[i] = FStar_UInt128_mul_wide(xi, s); + } + } + Hacl_Bignum_Fproduct_carry_wide_(tmp); + b4 = tmp[4U]; + b0 = tmp[0U]; + b4_ = FStar_UInt128_logand(b4, FStar_UInt128_uint64_to_uint128((uint64_t)0x7ffffffffffffU)); + b0_ = + FStar_UInt128_add(b0, + FStar_UInt128_mul_wide((uint64_t)19U, + FStar_UInt128_uint128_to_uint64(FStar_UInt128_shift_right(b4, (uint32_t)51U)))); + tmp[4U] = b4_; + tmp[0U] = b0_; + Hacl_Bignum_Fproduct_copy_from_wide_(output, tmp); + } + } +} + +inline static void Hacl_Bignum_fmul(uint64_t *output, uint64_t *a, uint64_t *b) +{ + Hacl_Bignum_Fmul_fmul(output, a, b); +} + +inline static void Hacl_Bignum_crecip(uint64_t *output, uint64_t *input) +{ + Hacl_Bignum_Crecip_crecip(output, input); +} + +static void +Hacl_EC_Point_swap_conditional_step(uint64_t *a, uint64_t *b, uint64_t swap1, uint32_t ctr) +{ + uint32_t i = ctr - (uint32_t)1U; + uint64_t ai = a[i]; + uint64_t bi = b[i]; + uint64_t x = swap1 & (ai ^ bi); + uint64_t ai1 = ai ^ x; + uint64_t bi1 = bi ^ x; + a[i] = ai1; + b[i] = bi1; +} + +static void +Hacl_EC_Point_swap_conditional_(uint64_t *a, uint64_t *b, uint64_t swap1, uint32_t ctr) +{ + if (!(ctr == (uint32_t)0U)) + { + uint32_t i; + Hacl_EC_Point_swap_conditional_step(a, b, swap1, ctr); + i = ctr - (uint32_t)1U; + Hacl_EC_Point_swap_conditional_(a, b, swap1, i); + } +} + +static void Hacl_EC_Point_swap_conditional(uint64_t *a, uint64_t *b, uint64_t iswap) +{ + uint64_t swap1 = (uint64_t)0U - iswap; + Hacl_EC_Point_swap_conditional_(a, b, swap1, (uint32_t)5U); + Hacl_EC_Point_swap_conditional_(a + (uint32_t)5U, b + (uint32_t)5U, swap1, (uint32_t)5U); +} + +static void Hacl_EC_Point_copy(uint64_t *output, uint64_t *input) +{ + memcpy(output, input, (uint32_t)5U * sizeof input[0U]); + memcpy(output + (uint32_t)5U, + input + (uint32_t)5U, + (uint32_t)5U * sizeof (input + (uint32_t)5U)[0U]); +} + +static void Hacl_EC_Format_fexpand(uint64_t *output, uint8_t *input) +{ + uint64_t i0 = load64_le(input); + uint8_t *x00 = input + (uint32_t)6U; + uint64_t i1 = load64_le(x00); + uint8_t *x01 = input + (uint32_t)12U; + uint64_t i2 = load64_le(x01); + uint8_t *x02 = input + (uint32_t)19U; + uint64_t i3 = load64_le(x02); + uint8_t *x0 = input + (uint32_t)24U; + uint64_t i4 = load64_le(x0); + uint64_t output0 = i0 & (uint64_t)0x7ffffffffffffU; + uint64_t output1 = i1 >> (uint32_t)3U & (uint64_t)0x7ffffffffffffU; + uint64_t output2 = i2 >> (uint32_t)6U & (uint64_t)0x7ffffffffffffU; + uint64_t output3 = i3 >> (uint32_t)1U & (uint64_t)0x7ffffffffffffU; + uint64_t output4 = i4 >> (uint32_t)12U & (uint64_t)0x7ffffffffffffU; + output[0U] = output0; + output[1U] = output1; + output[2U] = output2; + output[3U] = output3; + output[4U] = output4; +} + +static void Hacl_EC_Format_fcontract_first_carry_pass(uint64_t *input) +{ + uint64_t t0 = input[0U]; + uint64_t t1 = input[1U]; + uint64_t t2 = input[2U]; + uint64_t t3 = input[3U]; + uint64_t t4 = input[4U]; + uint64_t t1_ = t1 + (t0 >> (uint32_t)51U); + uint64_t t0_ = t0 & (uint64_t)0x7ffffffffffffU; + uint64_t t2_ = t2 + (t1_ >> (uint32_t)51U); + uint64_t t1__ = t1_ & (uint64_t)0x7ffffffffffffU; + uint64_t t3_ = t3 + (t2_ >> (uint32_t)51U); + uint64_t t2__ = t2_ & (uint64_t)0x7ffffffffffffU; + uint64_t t4_ = t4 + (t3_ >> (uint32_t)51U); + uint64_t t3__ = t3_ & (uint64_t)0x7ffffffffffffU; + input[0U] = t0_; + input[1U] = t1__; + input[2U] = t2__; + input[3U] = t3__; + input[4U] = t4_; +} + +static void Hacl_EC_Format_fcontract_first_carry_full(uint64_t *input) +{ + Hacl_EC_Format_fcontract_first_carry_pass(input); + Hacl_Bignum_Modulo_carry_top(input); +} + +static void Hacl_EC_Format_fcontract_second_carry_pass(uint64_t *input) +{ + uint64_t t0 = input[0U]; + uint64_t t1 = input[1U]; + uint64_t t2 = input[2U]; + uint64_t t3 = input[3U]; + uint64_t t4 = input[4U]; + uint64_t t1_ = t1 + (t0 >> (uint32_t)51U); + uint64_t t0_ = t0 & (uint64_t)0x7ffffffffffffU; + uint64_t t2_ = t2 + (t1_ >> (uint32_t)51U); + uint64_t t1__ = t1_ & (uint64_t)0x7ffffffffffffU; + uint64_t t3_ = t3 + (t2_ >> (uint32_t)51U); + uint64_t t2__ = t2_ & (uint64_t)0x7ffffffffffffU; + uint64_t t4_ = t4 + (t3_ >> (uint32_t)51U); + uint64_t t3__ = t3_ & (uint64_t)0x7ffffffffffffU; + input[0U] = t0_; + input[1U] = t1__; + input[2U] = t2__; + input[3U] = t3__; + input[4U] = t4_; +} + +static void Hacl_EC_Format_fcontract_second_carry_full(uint64_t *input) +{ + uint64_t i0; + uint64_t i1; + uint64_t i0_; + uint64_t i1_; + Hacl_EC_Format_fcontract_second_carry_pass(input); + Hacl_Bignum_Modulo_carry_top(input); + i0 = input[0U]; + i1 = input[1U]; + i0_ = i0 & (uint64_t)0x7ffffffffffffU; + i1_ = i1 + (i0 >> (uint32_t)51U); + input[0U] = i0_; + input[1U] = i1_; +} + +static void Hacl_EC_Format_fcontract_trim(uint64_t *input) +{ + uint64_t a0 = input[0U]; + uint64_t a1 = input[1U]; + uint64_t a2 = input[2U]; + uint64_t a3 = input[3U]; + uint64_t a4 = input[4U]; + uint64_t mask0 = FStar_UInt64_gte_mask(a0, (uint64_t)0x7ffffffffffedU); + uint64_t mask1 = FStar_UInt64_eq_mask(a1, (uint64_t)0x7ffffffffffffU); + uint64_t mask2 = FStar_UInt64_eq_mask(a2, (uint64_t)0x7ffffffffffffU); + uint64_t mask3 = FStar_UInt64_eq_mask(a3, (uint64_t)0x7ffffffffffffU); + uint64_t mask4 = FStar_UInt64_eq_mask(a4, (uint64_t)0x7ffffffffffffU); + uint64_t mask = (((mask0 & mask1) & mask2) & mask3) & mask4; + uint64_t a0_ = a0 - ((uint64_t)0x7ffffffffffedU & mask); + uint64_t a1_ = a1 - ((uint64_t)0x7ffffffffffffU & mask); + uint64_t a2_ = a2 - ((uint64_t)0x7ffffffffffffU & mask); + uint64_t a3_ = a3 - ((uint64_t)0x7ffffffffffffU & mask); + uint64_t a4_ = a4 - ((uint64_t)0x7ffffffffffffU & mask); + input[0U] = a0_; + input[1U] = a1_; + input[2U] = a2_; + input[3U] = a3_; + input[4U] = a4_; +} + +static void Hacl_EC_Format_fcontract_store(uint8_t *output, uint64_t *input) +{ + uint64_t t0 = input[0U]; + uint64_t t1 = input[1U]; + uint64_t t2 = input[2U]; + uint64_t t3 = input[3U]; + uint64_t t4 = input[4U]; + uint64_t o0 = t1 << (uint32_t)51U | t0; + uint64_t o1 = t2 << (uint32_t)38U | t1 >> (uint32_t)13U; + uint64_t o2 = t3 << (uint32_t)25U | t2 >> (uint32_t)26U; + uint64_t o3 = t4 << (uint32_t)12U | t3 >> (uint32_t)39U; + uint8_t *b0 = output; + uint8_t *b1 = output + (uint32_t)8U; + uint8_t *b2 = output + (uint32_t)16U; + uint8_t *b3 = output + (uint32_t)24U; + store64_le(b0, o0); + store64_le(b1, o1); + store64_le(b2, o2); + store64_le(b3, o3); +} + +static void Hacl_EC_Format_fcontract(uint8_t *output, uint64_t *input) +{ + Hacl_EC_Format_fcontract_first_carry_full(input); + Hacl_EC_Format_fcontract_second_carry_full(input); + Hacl_EC_Format_fcontract_trim(input); + Hacl_EC_Format_fcontract_store(output, input); +} + +static void Hacl_EC_Format_scalar_of_point(uint8_t *scalar, uint64_t *point) +{ + uint64_t *x = point; + uint64_t *z = point + (uint32_t)5U; + uint64_t buf[10U] = { 0U }; + uint64_t *zmone = buf; + uint64_t *sc = buf + (uint32_t)5U; + Hacl_Bignum_crecip(zmone, z); + Hacl_Bignum_fmul(sc, x, zmone); + Hacl_EC_Format_fcontract(scalar, sc); +} + +static void +Hacl_EC_AddAndDouble_fmonty( + uint64_t *pp, + uint64_t *ppq, + uint64_t *p, + uint64_t *pq, + uint64_t *qmqp +) +{ + uint64_t *qx = qmqp; + uint64_t *x2 = pp; + uint64_t *z2 = pp + (uint32_t)5U; + uint64_t *x3 = ppq; + uint64_t *z3 = ppq + (uint32_t)5U; + uint64_t *x = p; + uint64_t *z = p + (uint32_t)5U; + uint64_t *xprime = pq; + uint64_t *zprime = pq + (uint32_t)5U; + uint64_t buf[40U] = { 0U }; + uint64_t *origx = buf; + uint64_t *origxprime0 = buf + (uint32_t)5U; + uint64_t *xxprime0 = buf + (uint32_t)25U; + uint64_t *zzprime0 = buf + (uint32_t)30U; + uint64_t *origxprime; + uint64_t *xx0; + uint64_t *zz0; + uint64_t *xxprime; + uint64_t *zzprime; + uint64_t *zzzprime; + uint64_t *zzz; + uint64_t *xx; + uint64_t *zz; + uint64_t scalar; + memcpy(origx, x, (uint32_t)5U * sizeof x[0U]); + Hacl_Bignum_fsum(x, z); + Hacl_Bignum_fdifference(z, origx); + memcpy(origxprime0, xprime, (uint32_t)5U * sizeof xprime[0U]); + Hacl_Bignum_fsum(xprime, zprime); + Hacl_Bignum_fdifference(zprime, origxprime0); + Hacl_Bignum_fmul(xxprime0, xprime, z); + Hacl_Bignum_fmul(zzprime0, x, zprime); + origxprime = buf + (uint32_t)5U; + xx0 = buf + (uint32_t)15U; + zz0 = buf + (uint32_t)20U; + xxprime = buf + (uint32_t)25U; + zzprime = buf + (uint32_t)30U; + zzzprime = buf + (uint32_t)35U; + memcpy(origxprime, xxprime, (uint32_t)5U * sizeof xxprime[0U]); + Hacl_Bignum_fsum(xxprime, zzprime); + Hacl_Bignum_fdifference(zzprime, origxprime); + Hacl_Bignum_Fsquare_fsquare_times(x3, xxprime, (uint32_t)1U); + Hacl_Bignum_Fsquare_fsquare_times(zzzprime, zzprime, (uint32_t)1U); + Hacl_Bignum_fmul(z3, zzzprime, qx); + Hacl_Bignum_Fsquare_fsquare_times(xx0, x, (uint32_t)1U); + Hacl_Bignum_Fsquare_fsquare_times(zz0, z, (uint32_t)1U); + zzz = buf + (uint32_t)10U; + xx = buf + (uint32_t)15U; + zz = buf + (uint32_t)20U; + Hacl_Bignum_fmul(x2, xx, zz); + Hacl_Bignum_fdifference(zz, xx); + scalar = (uint64_t)121665U; + Hacl_Bignum_fscalar(zzz, zz, scalar); + Hacl_Bignum_fsum(zzz, xx); + Hacl_Bignum_fmul(z2, zzz, zz); +} + +static void +Hacl_EC_Ladder_SmallLoop_cmult_small_loop_step( + uint64_t *nq, + uint64_t *nqpq, + uint64_t *nq2, + uint64_t *nqpq2, + uint64_t *q, + uint8_t byt +) +{ + uint64_t bit0 = (uint64_t)(byt >> (uint32_t)7U); + uint64_t bit; + Hacl_EC_Point_swap_conditional(nq, nqpq, bit0); + Hacl_EC_AddAndDouble_fmonty(nq2, nqpq2, nq, nqpq, q); + bit = (uint64_t)(byt >> (uint32_t)7U); + Hacl_EC_Point_swap_conditional(nq2, nqpq2, bit); +} + +static void +Hacl_EC_Ladder_SmallLoop_cmult_small_loop_double_step( + uint64_t *nq, + uint64_t *nqpq, + uint64_t *nq2, + uint64_t *nqpq2, + uint64_t *q, + uint8_t byt +) +{ + uint8_t byt1; + Hacl_EC_Ladder_SmallLoop_cmult_small_loop_step(nq, nqpq, nq2, nqpq2, q, byt); + byt1 = byt << (uint32_t)1U; + Hacl_EC_Ladder_SmallLoop_cmult_small_loop_step(nq2, nqpq2, nq, nqpq, q, byt1); +} + +static void +Hacl_EC_Ladder_SmallLoop_cmult_small_loop( + uint64_t *nq, + uint64_t *nqpq, + uint64_t *nq2, + uint64_t *nqpq2, + uint64_t *q, + uint8_t byt, + uint32_t i +) +{ + if (!(i == (uint32_t)0U)) + { + uint32_t i_ = i - (uint32_t)1U; + uint8_t byt_; + Hacl_EC_Ladder_SmallLoop_cmult_small_loop_double_step(nq, nqpq, nq2, nqpq2, q, byt); + byt_ = byt << (uint32_t)2U; + Hacl_EC_Ladder_SmallLoop_cmult_small_loop(nq, nqpq, nq2, nqpq2, q, byt_, i_); + } +} + +static void +Hacl_EC_Ladder_BigLoop_cmult_big_loop( + uint8_t *n1, + uint64_t *nq, + uint64_t *nqpq, + uint64_t *nq2, + uint64_t *nqpq2, + uint64_t *q, + uint32_t i +) +{ + if (!(i == (uint32_t)0U)) + { + uint32_t i1 = i - (uint32_t)1U; + uint8_t byte = n1[i1]; + Hacl_EC_Ladder_SmallLoop_cmult_small_loop(nq, nqpq, nq2, nqpq2, q, byte, (uint32_t)4U); + Hacl_EC_Ladder_BigLoop_cmult_big_loop(n1, nq, nqpq, nq2, nqpq2, q, i1); + } +} + +static void Hacl_EC_Ladder_cmult(uint64_t *result, uint8_t *n1, uint64_t *q) +{ + uint64_t point_buf[40U] = { 0U }; + uint64_t *nq = point_buf; + uint64_t *nqpq = point_buf + (uint32_t)10U; + uint64_t *nq2 = point_buf + (uint32_t)20U; + uint64_t *nqpq2 = point_buf + (uint32_t)30U; + Hacl_EC_Point_copy(nqpq, q); + nq[0U] = (uint64_t)1U; + Hacl_EC_Ladder_BigLoop_cmult_big_loop(n1, nq, nqpq, nq2, nqpq2, q, (uint32_t)32U); + Hacl_EC_Point_copy(result, nq); +} + +void Hacl_Curve25519_crypto_scalarmult(uint8_t *mypublic, uint8_t *secret, uint8_t *basepoint) +{ + uint64_t buf0[10U] = { 0U }; + uint64_t *x0 = buf0; + uint64_t *z = buf0 + (uint32_t)5U; + uint64_t *q; + Hacl_EC_Format_fexpand(x0, basepoint); + z[0U] = (uint64_t)1U; + q = buf0; + { + uint8_t e[32U] = { 0U }; + uint8_t e0; + uint8_t e31; + uint8_t e01; + uint8_t e311; + uint8_t e312; + uint8_t *scalar; + memcpy(e, secret, (uint32_t)32U * sizeof secret[0U]); + e0 = e[0U]; + e31 = e[31U]; + e01 = e0 & (uint8_t)248U; + e311 = e31 & (uint8_t)127U; + e312 = e311 | (uint8_t)64U; + e[0U] = e01; + e[31U] = e312; + scalar = e; + { + uint64_t buf[15U] = { 0U }; + uint64_t *nq = buf; + uint64_t *x = nq; + x[0U] = (uint64_t)1U; + Hacl_EC_Ladder_cmult(nq, scalar, q); + Hacl_EC_Format_scalar_of_point(mypublic, nq); + } + } +} + diff --git a/tf-psa-crypto/drivers/everest/library/x25519.c b/tf-psa-crypto/drivers/everest/library/x25519.c new file mode 100644 index 0000000000..3a843c333d --- /dev/null +++ b/tf-psa-crypto/drivers/everest/library/x25519.c @@ -0,0 +1,52 @@ +/* + * ECDH with curve-optimized implementation multiplexing + * + * Copyright 2016-2018 INRIA and Microsoft Corporation + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "tf_psa_crypto_common.h" +#include "mbedtls/private_access.h" + +#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) && defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) + +#if !(defined(__SIZEOF_INT128__) && (__SIZEOF_INT128__ == 16)) +#define KRML_VERIFIED_UINT128 +#endif + +#include +#include + +#include "x25519.h" + +void mbedtls_x25519_scalarmult(uint8_t out[MBEDTLS_X25519_KEY_SIZE_BYTES], + const uint8_t scalar[MBEDTLS_X25519_KEY_SIZE_BYTES], + const uint8_t point[MBEDTLS_X25519_KEY_SIZE_BYTES]) +{ + uint8_t cp_scalar[MBEDTLS_X25519_KEY_SIZE_BYTES]; + uint8_t cp_point[MBEDTLS_X25519_KEY_SIZE_BYTES]; + + memcpy(cp_scalar, scalar, sizeof(cp_scalar)); + memcpy(cp_point, point, sizeof(cp_point)); + + Hacl_Curve25519_crypto_scalarmult(out, cp_scalar, cp_point); + + mbedtls_platform_zeroize(cp_scalar, sizeof(cp_scalar)); + mbedtls_platform_zeroize(cp_point, sizeof(cp_point)); +} + +#endif /* MBEDTLS_PSA_BUILTIN_ALG_ECDH && MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED */ diff --git a/tf-psa-crypto/drivers/p256-m/.gitignore b/tf-psa-crypto/drivers/p256-m/.gitignore new file mode 100644 index 0000000000..f3c7a7c5da --- /dev/null +++ b/tf-psa-crypto/drivers/p256-m/.gitignore @@ -0,0 +1 @@ +Makefile diff --git a/tf-psa-crypto/drivers/p256-m/CMakeLists.txt b/tf-psa-crypto/drivers/p256-m/CMakeLists.txt new file mode 100644 index 0000000000..c4a86dd054 --- /dev/null +++ b/tf-psa-crypto/drivers/p256-m/CMakeLists.txt @@ -0,0 +1,36 @@ +set(p256-m_target "${TF_PSA_CRYPTO_TARGET_PREFIX}p256-m") +if (USE_STATIC_TF_PSA_CRYPTO_LIBRARY) + set(p256-m_static_target ${p256-m_target}) +endif() +set(target_libraries ${p256-m_target}) +if(USE_STATIC_TF_PSA_CRYPTO_LIBRARY AND USE_SHARED_TF_PSA_CRYPTO_LIBRARY) + string(APPEND p256-m_static_target "_static") + list(APPEND target_libraries ${p256-m_static_target}) +endif() + +foreach (target IN LISTS target_libraries) + add_library(${target} STATIC + p256-m_driver_entrypoints.c + p256-m/p256-m.c) + + tf_psa_crypto_set_base_compile_options(${target}) + + target_include_directories(${target} + PUBLIC p256-m + # Add the build-tree include directory before the source-tree one + # so that generated headers in the build tree take precedence. + PRIVATE ${PROJECT_BINARY_DIR}/include + ${PROJECT_SOURCE_DIR}/include + ${PROJECT_SOURCE_DIR}/core + ${PROJECT_SOURCE_DIR}/dispatch + ${TF_PSA_CRYPTO_DRIVERS_INCLUDE_DIRS} + ) + tf_psa_crypto_set_config_files_compile_definitions(${target}) + if(TF_PSA_CRYPTO_TEST_DRIVER) + add_dependencies(${target} ${TF_PSA_CRYPTO_TEST_DRIVER_GENERATION_TARGETS}) + endif() +endforeach(target) + +if(USE_SHARED_TF_PSA_CRYPTO_LIBRARY) + set_property(TARGET ${p256-m_target} PROPERTY POSITION_INDEPENDENT_CODE ON) +endif(USE_SHARED_TF_PSA_CRYPTO_LIBRARY) diff --git a/tf-psa-crypto/drivers/p256-m/Makefile.inc b/tf-psa-crypto/drivers/p256-m/Makefile.inc new file mode 100644 index 0000000000..53bb55b547 --- /dev/null +++ b/tf-psa-crypto/drivers/p256-m/Makefile.inc @@ -0,0 +1,5 @@ +THIRDPARTY_INCLUDES+=-I$(THIRDPARTY_DIR)/p256-m/p256-m/include -I$(THIRDPARTY_DIR)/p256-m/p256-m/include/p256-m -I$(THIRDPARTY_DIR)/p256-m/p256-m_driver_interface + +THIRDPARTY_CRYPTO_OBJECTS+= \ + $(THIRDPARTY_DIR)/p256-m//p256-m_driver_entrypoints.o \ + $(THIRDPARTY_DIR)/p256-m//p256-m/p256-m.o diff --git a/tf-psa-crypto/drivers/p256-m/README.md b/tf-psa-crypto/drivers/p256-m/README.md new file mode 100644 index 0000000000..ec90f34462 --- /dev/null +++ b/tf-psa-crypto/drivers/p256-m/README.md @@ -0,0 +1,4 @@ +The files within the `p256-m/` subdirectory originate from the [p256-m GitHub repository](https://github.com/mpg/p256-m). They are distributed here under a dual Apache-2.0 OR GPL-2.0-or-later license. They are authored by Manuel Pégourié-Gonnard. p256-m is a minimalistic implementation of ECDH and ECDSA on NIST P-256, especially suited to constrained 32-bit environments. Mbed TLS documentation for integrating drivers uses p256-m as an example of a software accelerator, and describes how it can be integrated alongside Mbed TLS. It should be noted that p256-m files in the Mbed TLS repo will not be updated regularly, so they may not have fixes and improvements present in the upstream project. + +The files `p256-m.c`, `p256-m.h` and `README.md` have been taken from the `p256-m` repository. +It should be noted that p256-m deliberately does not supply its own cryptographically secure RNG function. As a result, the PSA RNG is used, with `p256_generate_random()` wrapping `psa_generate_random()`. diff --git a/tf-psa-crypto/drivers/p256-m/p256-m/README.md b/tf-psa-crypto/drivers/p256-m/p256-m/README.md new file mode 100644 index 0000000000..5e88f719db --- /dev/null +++ b/tf-psa-crypto/drivers/p256-m/p256-m/README.md @@ -0,0 +1,544 @@ +*This is the original README for the p256-m repository. Please note that as +only a subset of p256-m's files are present in Mbed TLS, this README may refer +to files that are not present/relevant here.* + +p256-m is a minimalistic implementation of ECDH and ECDSA on NIST P-256, +especially suited to constrained 32-bit environments. It's written in standard +C, with optional bits of assembly for Arm Cortex-M and Cortex-A CPUs. + +Its design is guided by the following goals in this order: + +1. correctness & security; +2. low code size & RAM usage; +3. runtime performance. + +Most cryptographic implementations care more about speed than footprint, and +some might even risk weakening security for more speed. p256-m was written +because I wanted to see what happened when reversing the usual emphasis. + +The result is a full implementation of ECDH and ECDSA in **less than 3KiB of +code**, using **less than 768 bytes of RAM**, with comparable performance +to existing implementations (see below) - in less than 700 LOC. + +_Contents of this Readme:_ + +- [Correctness](#correctness) +- [Security](#security) +- [Code size](#code-size) +- [RAM usage](#ram-usage) +- [Runtime performance](#runtime-performance) +- [Comparison with other implementations](#comparison-with-other-implementations) +- [Design overview](#design-overview) +- [Notes about other curves](#notes-about-other-curves) +- [Notes about other platforms](#notes-about-other-platforms) + +## Correctness + +**API design:** + +- The API is minimal: only 4 public functions. +- Each public function fully validates its inputs and returns specific errors. +- The API uses arrays of octets for all input and output. + +**Testing:** + +- p256-m is validated against multiple test vectors from various RFCs and + NIST. +- In addition, crafted inputs are used for negative testing and to reach + corner cases. +- Two test suites are provided: one for closed-box testing (using only the + public API), one for open-box testing (for unit-testing internal functions, +and reaching more error cases by exploiting knowledge of how the RNG is used). +- The resulting branch coverage is maximal: closed-box testing reaches all + branches except four; three of them are reached by open-box testing using a +rigged RNG; the last branch could only be reached by computing a discrete log +on P-256... See `coverage.sh`. +- Testing also uses dynamic analysis: valgrind, ASan, MemSan, UBSan. + +**Code quality:** + +- The code is standard C99; it builds without warnings with `clang + -Weverything` and `gcc -Wall -Wextra -pedantic`. +- The code is small and well documented, including internal APIs: with the + header file, it's less than 700 lines of code, and more lines of comments +than of code. +- However it _has not been reviewed_ independently so far, as this is a + personal project. + +**Short Weierstrass pitfalls:** + +Its has been [pointed out](https://safecurves.cr.yp.to/) that the NIST curves, +and indeed all Short Weierstrass curves, have a number of pitfalls including +risk for the implementation to: + +- "produce incorrect results for some rare curve points" - this is avoided by + carefully checking the validity domain of formulas used throughout the code; +- "leak secret data when the input isn't a curve point" - this is avoided by + validating that points lie on the curve every time a point is deserialized. + +## Security + +In addition to the above correctness claims, p256-m has the following +properties: + +- it has no branch depending (even indirectly) on secret data; +- it has no memory access depending (even indirectly) on secret data. + +These properties are checked using valgrind and MemSan with the ideas +behind [ctgrind](https://github.com/agl/ctgrind), see `consttime.sh`. + +In addition to avoiding branches and memory accesses depending on secret data, +p256-m also avoid instructions (or library functions) whose execution time +depends on the value of operands on cores of interest. Namely, it never uses +integer division, and for multiplication by default it only uses 16x16->32 bit +unsigned multiplication. On cores which have a constant-time 32x32->64 bit +unsigned multiplication instruction, the symbol `MUL64_IS_CONSTANT_TIME` can +be defined by the user at compile-time to take advantage of it in order to +improve performance and code size. (On Cortex-M and Cortex-A cores wtih GCC or +Clang this is not necessary, since inline assembly is used instead.) + +As a result, p256-m should be secure against the following classes of attackers: + +1. attackers who can only manipulate the input and observe the output; +2. attackers who can also measure the total computation time of the operation; +3. attackers who can also observe and manipulate micro-architectural features + such as the cache or branch predictor with arbitrary precision. + +However, p256-m makes no attempt to protect against: + +4. passive physical attackers who can record traces of physical emissions + (power, EM, sound) of the CPU while it manipulates secrets; +5. active physical attackers who can also inject faults in the computation. + +(Note: p256-m should actually be secure against SPA, by virtue of being fully +constant-flow, but is not expected to resist any other physical attack.) + +**Warning:** p256-m requires an externally-provided RNG function. If that +function is not cryptographically secure, then neither is p256-m's key +generation or ECDSA signature generation. + +_Note:_ p256-m also follows best practices such as securely erasing secret +data on the stack before returning. + +## Code size + +Compiled with +[ARM-GCC 9](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads), +with `-mthumb -Os`, here are samples of code sizes reached on selected cores: + +- Cortex-M0: 2988 bytes +- Cortex-M4: 2900 bytes +- Cortex-A7: 2924 bytes + +Clang was also tried but tends to generate larger code (by about 10%). For +details, see `sizes.sh`. + +**What's included:** + +- Full input validation and (de)serialisation of input/outputs to/from bytes. +- Cleaning up secret values from the stack before returning from a function. +- The code has no dependency on libc functions or the toolchain's runtime + library (such as helpers for long multiply); this can be checked for the +Arm-GCC toolchain with the `deps.sh` script. + +**What's excluded:** + +- A secure RNG function needs to be provided externally, see + `p256_generate_random()` in `p256-m.h`. + +## RAM usage + +p256-m doesn't use any dynamic memory (on the heap), only the stack. Here's +how much stack is used by each of its 4 public functions on selected cores: + +| Function | Cortex-M0 | Cortex-M4 | Cortex-A7 | +| ------------------------- | --------: | --------: | --------: | +| `p256_gen_keypair` | 608 | 564 | 564 | +| `p256_ecdh_shared_secret` | 640 | 596 | 596 | +| `p256_ecdsa_sign` | 664 | 604 | 604 | +| `p256_ecdsa_verify` | 752 | 700 | 700 | + +For details, see `stack.sh`, `wcs.py` and `libc.msu` (the above figures assume +that the externally-provided RNG function uses at most 384 bytes of stack). + +## Runtime performance + +Here are the timings of each public function in milliseconds measured on +platforms based on a selection of cores: + +- Cortex-M0 at 48 MHz: STM32F091 board running Mbed OS 6 +- Cortex-M4 at 100 MHz: STM32F411 board running Mbed OS 6 +- Cortex-A7 at 900 MHz: Raspberry Pi 2B running Raspbian Buster + +| Function | Cortex-M0 | Cortex-M4 | Cortex-A7 | +| ------------------------- | --------: | --------: | --------: | +| `p256_gen_keypair` | 921 | 145 | 11 | +| `p256_ecdh_shared_secret` | 922 | 144 | 11 | +| `p256_ecdsa_sign` | 990 | 155 | 12 | +| `p256_ecdsa_verify` | 1976 | 309 | 24 | +| Sum of the above | 4809 | 753 | 59 | + +The sum of these operations corresponds to a TLS handshake using ECDHE-ECDSA +with mutual authentication based on raw public keys or directly-trusted +certificates (otherwise, add one 'verify' for each link in the peer's +certificate chain). + +_Note_: the above figures where obtained by compiling with GCC, which is able +to use inline assembly. Without that inline assembly (22 lines for Cortex-M0, +1 line for Cortex-M4), the code would be roughly 2 times slower on those +platforms. (The effect is much less important on the Cortex-A7 core.) + +For details, see `bench.sh`, `benchmark.c` and `on-target-benchmark/`. + +## Comparison with other implementations + +The most relevant/convenient implementation for comparisons is +[TinyCrypt](https://github.com/intel/tinycrypt), as it's also a standalone +implementation of ECDH and ECDSA on P-256 only, that also targets constrained +devices. Other implementations tend to implement many curves and build on a +shared bignum/MPI module (possibly also supporting RSA), which makes fair +comparisons less convenient. + +The scripts used for TinyCrypt measurements are available in [this +branch](https://github.com/mpg/tinycrypt/tree/measurements), based on version +0.2.8. + +**Code size** + +| Core | p256-m | TinyCrypt | +| --------- | -----: | --------: | +| Cortex-M0 | 2988 | 6134 | +| Cortex-M4 | 2900 | 5934 | +| Cortex-A7 | 2924 | 5934 | + +**RAM usage** + +TinyCrypto also uses no heap, only the stack. Here's the RAM used by each +operation on a Cortex-M0 core: + +| operation | p256-m | TinyCrypt | +| ------------------ | -----: | --------: | +| key generation | 608 | 824 | +| ECDH shared secret | 640 | 728 | +| ECDSA sign | 664 | 880 | +| ECDSA verify | 752 | 824 | + +On a Cortex-M4 or Cortex-A7 core (identical numbers): + +| operation | p256-m | TinyCrypt | +| ------------------ | -----: | --------: | +| key generation | 564 | 796 | +| ECDH shared secret | 596 | 700 | +| ECDSA sign | 604 | 844 | +| ECDSA verify | 700 | 808 | + +**Runtime performance** + +Here are the timings of each operation in milliseconds measured on +platforms based on a selection of cores: + +_Cortex-M0_ at 48 MHz: STM32F091 board running Mbed OS 6 + +| Operation | p256-m | TinyCrypt | +| ------------------ | -----: | --------: | +| Key generation | 921 | 979 | +| ECDH shared secret | 922 | 975 | +| ECDSA sign | 990 | 1009 | +| ECDSA verify | 1976 | 1130 | +| Sum of those 4 | 4809 | 4093 | + +_Cortex-M4_ at 100 MHz: STM32F411 board running Mbed OS 6 + +| Operation | p256-m | TinyCrypt | +| ------------------ | -----: | --------: | +| Key generation | 145 | 178 | +| ECDH shared secret | 144 | 177 | +| ECDSA sign | 155 | 188 | +| ECDSA verify | 309 | 210 | +| Sum of those 4 | 753 | 753 | + +_Cortex-A7_ at 900 MHz: Raspberry Pi 2B running Raspbian Buster + +| Operation | p256-m | TinyCrypt | +| ------------------ | -----: | --------: | +| Key generation | 11 | 13 | +| ECDH shared secret | 11 | 13 | +| ECDSA sign | 12 | 14 | +| ECDSA verify | 24 | 15 | +| Sum of those 4 | 59 | 55 | + +_64-bit Intel_ (i7-6500U at 2.50GHz) laptop running Ubuntu 20.04 + +Note: results in microseconds (previous benchmarks in milliseconds) + +| Operation | p256-m | TinyCrypt | +| ------------------ | -----: | --------: | +| Key generation | 1060 | 1627 | +| ECDH shared secret | 1060 | 1611 | +| ECDSA sign | 1136 | 1712 | +| ECDSA verify | 2279 | 1888 | +| Sum of those 4 | 5535 | 6838 | + +**Other differences** + +- While p256-m fully validates all inputs, Tinycrypt's ECDH shared secret + function doesn't include validation of the peer's public key, which should be +done separately by the user for static ECDH (there are attacks [when users +forget](https://link.springer.com/chapter/10.1007/978-3-319-24174-6_21)). +- The two implementations have slightly different security characteristics: + p256-m is fully constant-time from the ground up so should be more robust +than TinyCrypt against powerful local attackers (such as an untrusted OS +attacking a secure enclave); on the other hand TinyCrypt includes coordinate +randomisation which protects against some passive physical attacks (such as +DPA, see Table 3, column C9 of [this +paper](https://www.esat.kuleuven.be/cosic/publications/article-2293.pdf#page=12)), +which p256-m completely ignores. +- TinyCrypt's code looks like it could easily be expanded to support other + curves, while p256-m has much more hard-coded to minimize code size (see +"Notes about other curves" below). +- TinyCrypt uses a specialised routine for reduction modulo the curve prime, + exploiting its structure as a Solinas prime, which should be faster than the +generic Montgomery reduction used by p256-m, but other factors appear to +compensate for that. +- TinyCrypt uses Co-Z Jacobian formulas for point operation, which should be + faster (though a bit larger) than the mixed affine-Jacobian formulas +used by p256-m, but again other factors appear to compensate for that. +- p256-m uses bits of inline assembly for 64-bit multiplication on the + platforms used for benchmarking, while TinyCrypt uses only C (and the +compiler's runtime library). +- TinyCrypt uses a specialised routine based on Shamir's trick for + ECDSA verification, which gives much better performance than the generic +code that p256-m uses in order to minimize code size. + +## Design overview + +The implementation is contained in a single file to keep most functions static +and allow for more optimisations. It is organized in multiple layers: + +- Fixed-width multi-precision arithmetic +- Fixed-width modular arithmetic +- Operations on curve points +- Operations with scalars +- The public API + +**Multi-precision arithmetic.** + +Large integers are represented as arrays of `uint32_t` limbs. When carries may +occur, casts to `uint64_t` are used to nudge the compiler towards using the +CPU's carry flag. When overflow may occur, functions return a carry flag. + +This layer contains optional assembly for Cortex-M and Cortex-A cores, for the +internal `u32_muladd64()` function, as well as two pure C versions of this +function, depending on whether `MUL64_IS_CONSTANT_TIME`. + +This layer's API consists of: + +- addition, subtraction; +- multiply-and-add, shift by one limb (for Montgomery multiplication); +- conditional assignment, assignment of a small value; +- comparison of two values for equality, comparison to 0 for equality; +- (de)serialization as big-endian arrays of bytes. + +**Modular arithmetic.** + +All modular operations are done in the Montgomery domain, that is x is +represented by `x * 2^256 mod m`; integers need to be converted to that domain +before computations, and back from it afterwards. Montgomery constants +associated to the curve's p and n are pre-computed and stored in static +structures. + +Modular inversion is computed using Fermat's little theorem to get +constant-time behaviour with respect to the value being inverted. + +This layer's API consists of: + +- the curve's constants p and n (and associated Montgomery constants); +- modular addition, subtraction, multiplication, and inversion; +- assignment of a small value; +- conversion to/from Montgomery domain; +- (de)serialization to/from bytes with integrated range checking and + Montgomery domain conversion. + +**Operations on curve points.** + +Curve points are represented using either affine or Jacobian coordinates; +affine coordinates are extended to represent 0 as (0,0). Individual +coordinates are always in the Montgomery domain. + +Not all formulas associated with affine or Jacobian coordinates are complete; +great care is taken to document and satisfy each function's pre-conditions. + +This layer's API consists of: + +- curve constants: b from the equation, the base point's coordinates; +- point validity check (on the curve and not 0); +- Jacobian to affine coordinate conversion; +- point doubling in Jacobian coordinates (complete formulas); +- point addition in mixed affine-Jacobian coordinates (P not in {0, Q, -Q}); +- point addition-or-doubling in affine coordinates (leaky version, only used + for ECDSA verify where all data is public); +- (de)serialization to/from bytes with integrated validity checking + +**Scalar operations.** + +The crucial function here is scalar multiplication. It uses a signed binary +ladder, which is a variant of the good old double-and-add algorithm where an +addition/subtraction is performed at each step. Again, care is taken to make +sure the pre-conditions for the addition formulas are always satisfied. The +signed binary ladder only works if the scalar is odd; this is ensured by +negating both the scalar (mod n) and the input point if necessary. + +This layer's API consists of: + +- scalar multiplication +- de-serialization from bytes with integrated range checking +- generation of a scalar and its associated public key + +**Public API.** + +This layer builds on the others, but unlike them, all inputs and outputs are +byte arrays. Key generation and ECDH shared secret computation are thin +wrappers around internal functions, just taking care of format conversions and +errors. The ECDSA functions have more non-trivial logic. + +This layer's API consists of: + +- key-pair generation +- ECDH shared secret computation +- ECDSA signature creation +- ECDSA signature verification + +**Testing.** + +A self-contained, straightforward, pure-Python implementation was first +produced as a warm-up and to help check intermediate values. Test vectors from +various sources are embedded and used to validate the implementation. + +This implementation, `p256.py`, is used by a second Python script, +`gen-test-data.py`, to generate additional data for both positive and negative +testing, available from a C header file, that is then used by the closed-box +and open-box test programs. + +p256-m can be compiled with extra instrumentation to mark secret data and +allow either valgrind or MemSan to check that no branch or memory access +depends on it (even indirectly). Macros are defined for this purpose near the +top of the file. + +**Tested platforms.** + +There are 4 versions of the internal function `u32_muladd64`: two assembly +versions, for Cortex-M/A cores with or without the DSP extension, and two +pure-C versions, depending on whether `MUL64_IS_CONSTANT_TIME`. + +Tests are run on the following platforms: + +- `make` on x64 tests the pure-C version without `MUL64_IS_CONSTANT_TIME` + (with Clang). +- `./consttime.sh` on x64 tests both pure-C versions (with Clang). +- `make` on Arm v7-A (Raspberry Pi 2) tests the Arm-DSP assembly version (with + Clang). +- `on-target-*box` on boards based on Cortex-M0 and M4 cores test both + assembly versions (with GCC). + +In addition: + +- `sizes.sh` builds the code for three Arm cores with GCC and Clang. +- `deps.sh` checks for external dependencies with GCC. + +## Notes about other curves + +It should be clear that minimal code size can only be reached by specializing +the implementation to the curve at hand. Here's a list of things in the +implementation that are specific to the NIST P-256 curve, and how the +implementation could be changed to expand to other curves, layer by layer (see +"Design Overview" above). + +**Fixed-width multi-precision arithmetic:** + +- The number of limbs is hard-coded to 8. For other 256-bit curves, nothing to + change. For a curve of another size, hard-code to another value. For multiple +curves of various sizes, add a parameter to each function specifying the +number of limbs; when declaring arrays, always use the maximum number of +limbs. + +**Fixed-width modular arithmetic:** + +- The values of the curve's constant p and n, and their associated Montgomery + constants, are hard-coded. For another curve, just hard-code the new constants. +For multiple other curves, define all the constants, and from this layer's API +only keep the functions that already accept a `mod` parameter (that is, remove +convenience functions `m256_xxx_p()`). +- The number of limbs is again hard-coded to 8. See above, but it order to + support multiple sizes there is no need to add a new parameter to functions +in this layer: the existing `mod` parameter can include the number of limbs as +well. + +**Operations on curve points:** + +- The values of the curve's constants b (constant term from the equation) and + gx, gy (coordinates of the base point) are hard-coded. For another curve, + hard-code the other values. For multiple curves, define each curve's value and +add a "curve id" parameter to all functions in this layer. +- The value of the curve's constant a is implicitly hard-coded to `-3` by using + a standard optimisation to save one multiplication in the first step of +`point_double()`. For curves that don't have a == -3, replace that with the +normal computation. +- The fact that b != 0 in the curve equation is used indirectly, to ensure + that (0, 0) is not a point on the curve and re-use that value to represent +the point 0. As far as I know, all Short Weierstrass curves standardized so +far have b != 0. +- The shape of the curve is assumed to be Short Weierstrass. For other curve + shapes (Montgomery, (twisted) Edwards), this layer would probably look very +different (both implementation and API). + +**Scalar operations:** + +- If multiple curves are to be supported, all function in this layer need to + gain a new "curve id" parameter. +- This layer assumes that the bit size of the curve's order n is the same as + that of the modulus p. This is true of most curves standardized so far, the +only exception being secp224k1. If that curve were to be supported, the +representation of `n` and scalars would need adapting to allow for an extra +limb. +- The bit size of the curve's order is hard-coded in `scalar_mult()`. For + multiple curves, this should be deduced from the "curve id" parameter. +- The `scalar_mult()` function exploits the fact that the second least + significant bit of the curve's order n is set in order to avoid a special +case. For curve orders that don't meet this criterion, we can just handle that +special case (multiplication by +-2) separately (always compute that and +conditionally assign it to the result). +- The shape of the curve is again assumed to be Short Weierstrass. For other curve + shapes (Montgomery, (twisted) Edwards), this layer would probably have a +very different implementation. + +**Public API:** + +- For multiple curves, all functions in this layer would need to gain a "curve + id" parameter and handle variable-sized input/output. +- The shape of the curve is again assumed to be Short Weierstrass. For other curve + shapes (Montgomery, (twisted) Edwards), the ECDH API would probably look +quite similar (with differences in the size of public keys), but the ECDSA API +wouldn't apply and an EdDSA API would look pretty different. + +## Notes about other platforms + +While p256-m is standard C99, it is written with constrained 32-bit platforms +in mind and makes a few assumptions about the platform: + +- The types `uint8_t`, `uint16_t`, `uint32_t` and `uint64_t` exist. +- 32-bit unsigned addition and subtraction with carry are constant time. +- 16x16->32-bit unsigned multiplication is available and constant time. + +Also, on platforms on which 64-bit addition and subtraction with carry, or +even 64x64->128-bit multiplication, are available, p256-m makes no use of +them, though they could significantly improve performance. + +This could be improved by replacing uses of arrays of `uint32_t` with a +defined type throughout the internal APIs, and then on 64-bit platforms define +that type to be an array of `uint64_t` instead, and making the obvious +adaptations in the multi-precision arithmetic layer. + +Finally, the optional assembly code (which boosts performance by a factor 2 on +tested Cortex-M CPUs, while slightly reducing code size and stack usage) is +currently only available with compilers that support GCC's extended asm +syntax (which includes GCC and Clang). diff --git a/tf-psa-crypto/drivers/p256-m/p256-m/p256-m.c b/tf-psa-crypto/drivers/p256-m/p256-m/p256-m.c new file mode 100644 index 0000000000..42c35b5bf5 --- /dev/null +++ b/tf-psa-crypto/drivers/p256-m/p256-m/p256-m.c @@ -0,0 +1,1514 @@ +/* + * Implementation of curve P-256 (ECDH and ECDSA) + * + * Copyright The Mbed TLS Contributors + * Author: Manuel Pégourié-Gonnard. + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "p256-m.h" +#include "mbedtls/platform_util.h" +#include "psa/crypto.h" +#include +#include +#include + +#if defined (MBEDTLS_PSA_P256M_DRIVER_ENABLED) + +/* + * Zeroize memory - this should not be optimized away + */ +#define zeroize mbedtls_platform_zeroize + +/* + * Helpers to test constant-time behaviour with valgrind or MemSan. + * + * CT_POISON() is used for secret data. It marks the memory area as + * uninitialised, so that any branch or pointer dereference that depends on it + * (even indirectly) triggers a warning. + * CT_UNPOISON() is used for public data; it marks the area as initialised. + * + * These are macros in order to avoid interfering with origin tracking. + */ +#if defined(CT_MEMSAN) + +#include +#define CT_POISON __msan_allocated_memory +// void __msan_allocated_memory(const volatile void* data, size_t size); +#define CT_UNPOISON __msan_unpoison +// void __msan_unpoison(const volatile void *a, size_t size); + +#elif defined(CT_VALGRIND) + +#include +#define CT_POISON VALGRIND_MAKE_MEM_UNDEFINED +// VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr,_qzz_len) +#define CT_UNPOISON VALGRIND_MAKE_MEM_DEFINED +// VALGRIND_MAKE_MEM_DEFINED(_qzz_addr,_qzz_len) + +#else +#define CT_POISON(p, sz) +#define CT_UNPOISON(p, sz) +#endif + +/********************************************************************** + * + * Operations on fixed-width unsigned integers + * + * Represented using 32-bit limbs, least significant limb first. + * That is: x = x[0] + 2^32 x[1] + ... + 2^224 x[7] for 256-bit. + * + **********************************************************************/ + +/* + * 256-bit set to 32-bit value + * + * in: x in [0, 2^32) + * out: z = x + */ +static void u256_set32(uint32_t z[8], uint32_t x) +{ + z[0] = x; + for (unsigned i = 1; i < 8; i++) { + z[i] = 0; + } +} + +/* + * 256-bit addition + * + * in: x, y in [0, 2^256) + * out: z = (x + y) mod 2^256 + * c = (x + y) div 2^256 + * That is, z + c * 2^256 = x + y + * + * Note: as a memory area, z must be either equal to x or y, or not overlap. + */ +static uint32_t u256_add(uint32_t z[8], + const uint32_t x[8], const uint32_t y[8]) +{ + uint32_t carry = 0; + + for (unsigned i = 0; i < 8; i++) { + uint64_t sum = (uint64_t) carry + x[i] + y[i]; + z[i] = (uint32_t) sum; + carry = (uint32_t) (sum >> 32); + } + + return carry; +} + +/* + * 256-bit subtraction + * + * in: x, y in [0, 2^256) + * out: z = (x - y) mod 2^256 + * c = 0 if x >=y, 1 otherwise + * That is, z = c * 2^256 + x - y + * + * Note: as a memory area, z must be either equal to x or y, or not overlap. + */ +static uint32_t u256_sub(uint32_t z[8], + const uint32_t x[8], const uint32_t y[8]) +{ + uint32_t carry = 0; + + for (unsigned i = 0; i < 8; i++) { + uint64_t diff = (uint64_t) x[i] - y[i] - carry; + z[i] = (uint32_t) diff; + carry = -(uint32_t) (diff >> 32); + } + + return carry; +} + +/* + * 256-bit conditional assignment + * + * in: x in [0, 2^256) + * c in [0, 1] + * out: z = x if c == 1, z unchanged otherwise + * + * Note: as a memory area, z must be either equal to x, or not overlap. + */ +static void u256_cmov(uint32_t z[8], const uint32_t x[8], uint32_t c) +{ + const uint32_t x_mask = -c; + for (unsigned i = 0; i < 8; i++) { + z[i] = (z[i] & ~x_mask) | (x[i] & x_mask); + } +} + +/* + * 256-bit compare for equality + * + * in: x in [0, 2^256) + * y in [0, 2^256) + * out: 0 if x == y, unspecified non-zero otherwise + */ +static uint32_t u256_diff(const uint32_t x[8], const uint32_t y[8]) +{ + uint32_t diff = 0; + for (unsigned i = 0; i < 8; i++) { + diff |= x[i] ^ y[i]; + } + return diff; +} + +/* + * 256-bit compare to zero + * + * in: x in [0, 2^256) + * out: 0 if x == 0, unspecified non-zero otherwise + */ +static uint32_t u256_diff0(const uint32_t x[8]) +{ + uint32_t diff = 0; + for (unsigned i = 0; i < 8; i++) { + diff |= x[i]; + } + return diff; +} + +/* + * 32 x 32 -> 64-bit multiply-and-accumulate + * + * in: x, y, z, t in [0, 2^32) + * out: x * y + z + t in [0, 2^64) + * + * Note: this computation cannot overflow. + * + * Note: this function has two pure-C implementations (depending on whether + * MUL64_IS_CONSTANT_TIME), and possibly optimised asm implementations. + * Start with the potential asm definitions, and use the C definition only if + * we no have no asm for the current toolchain & CPU. + */ +static uint64_t u32_muladd64(uint32_t x, uint32_t y, uint32_t z, uint32_t t); + +/* This macro is used to mark whether an asm implentation is found */ +#undef MULADD64_ASM +/* This macro is used to mark whether the implementation has a small + * code size (ie, it can be inlined even in an unrolled loop) */ +#undef MULADD64_SMALL + +/* + * Currently assembly optimisations are only supported with GCC/Clang for + * Arm's Cortex-A and Cortex-M lines of CPUs, which start with the v6-M and + * v7-M architectures. __ARM_ARCH_PROFILE is not defined for v6 and earlier. + * Thumb and 32-bit assembly is supported; aarch64 is not supported. + */ +#if defined(__GNUC__) &&\ + defined(__ARM_ARCH) && __ARM_ARCH >= 6 && defined(__ARM_ARCH_PROFILE) && \ + ( __ARM_ARCH_PROFILE == 77 || __ARM_ARCH_PROFILE == 65 ) /* 'M' or 'A' */ && \ + !defined(__aarch64__) + +/* + * This set of CPUs is conveniently partitioned as follows: + * + * 1. Cores that have the DSP extension, which includes a 1-cycle UMAAL + * instruction: M4, M7, M33, all A-class cores. + * 2. Cores that don't have the DSP extension, and also lack a constant-time + * 64-bit multiplication instruction: + * - M0, M0+, M23: 32-bit multiplication only; + * - M3: 64-bit multiplication is not constant-time. + */ +#if defined(__ARM_FEATURE_DSP) + +static uint64_t u32_muladd64(uint32_t x, uint32_t y, uint32_t z, uint32_t t) +{ + __asm__( + /* UMAAL , , , */ + "umaal %[z], %[t], %[x], %[y]" + : [z] "+l" (z), [t] "+l" (t) + : [x] "l" (x), [y] "l" (y) + ); + return ((uint64_t) t << 32) | z; +} +#define MULADD64_ASM +#define MULADD64_SMALL + +#else /* __ARM_FEATURE_DSP */ + +/* + * This implementation only uses 16x16->32 bit multiplication. + * + * It decomposes the multiplicands as: + * x = xh:xl = 2^16 * xh + xl + * y = yh:yl = 2^16 * yh + yl + * and computes their product as: + * x*y = xl*yl + 2**16 (xh*yl + yl*yh) + 2**32 xh*yh + * then adds z and t to the result. + */ +static uint64_t u32_muladd64(uint32_t x, uint32_t y, uint32_t z, uint32_t t) +{ + /* First compute x*y, using 3 temporary registers */ + uint32_t tmp1, tmp2, tmp3; + __asm__( + ".syntax unified\n\t" + /* start by splitting the inputs into halves */ + "lsrs %[u], %[x], #16\n\t" + "lsrs %[v], %[y], #16\n\t" + "uxth %[x], %[x]\n\t" + "uxth %[y], %[y]\n\t" + /* now we have %[x], %[y], %[u], %[v] = xl, yl, xh, yh */ + /* let's compute the 4 products we can form with those */ + "movs %[w], %[v]\n\t" + "muls %[w], %[u]\n\t" + "muls %[v], %[x]\n\t" + "muls %[x], %[y]\n\t" + "muls %[y], %[u]\n\t" + /* now we have %[x], %[y], %[v], %[w] = xl*yl, xh*yl, xl*yh, xh*yh */ + /* let's split and add the first middle product */ + "lsls %[u], %[y], #16\n\t" + "lsrs %[y], %[y], #16\n\t" + "adds %[x], %[u]\n\t" + "adcs %[y], %[w]\n\t" + /* let's finish with the second middle product */ + "lsls %[u], %[v], #16\n\t" + "lsrs %[v], %[v], #16\n\t" + "adds %[x], %[u]\n\t" + "adcs %[y], %[v]\n\t" + : [x] "+l" (x), [y] "+l" (y), + [u] "=&l" (tmp1), [v] "=&l" (tmp2), [w] "=&l" (tmp3) + : /* no read-only inputs */ + : "cc" + ); + (void) tmp1; + (void) tmp2; + (void) tmp3; + + /* Add z and t, using one temporary register */ + __asm__( + ".syntax unified\n\t" + "movs %[u], #0\n\t" + "adds %[x], %[z]\n\t" + "adcs %[y], %[u]\n\t" + "adds %[x], %[t]\n\t" + "adcs %[y], %[u]\n\t" + : [x] "+l" (x), [y] "+l" (y), [u] "=&l" (tmp1) + : [z] "l" (z), [t] "l" (t) + : "cc" + ); + (void) tmp1; + + return ((uint64_t) y << 32) | x; +} +#define MULADD64_ASM + +#endif /* __ARM_FEATURE_DSP */ + +#endif /* GCC/Clang with Cortex-M/A CPU */ + +#if !defined(MULADD64_ASM) +#if defined(MUL64_IS_CONSTANT_TIME) +static uint64_t u32_muladd64(uint32_t x, uint32_t y, uint32_t z, uint32_t t) +{ + return (uint64_t) x * y + z + t; +} +#define MULADD64_SMALL +#else +static uint64_t u32_muladd64(uint32_t x, uint32_t y, uint32_t z, uint32_t t) +{ + /* x = xl + 2**16 xh, y = yl + 2**16 yh */ + const uint16_t xl = (uint16_t) x; + const uint16_t yl = (uint16_t) y; + const uint16_t xh = x >> 16; + const uint16_t yh = y >> 16; + + /* x*y = xl*yl + 2**16 (xh*yl + yl*yh) + 2**32 xh*yh + * = lo + 2**16 (m1 + m2 ) + 2**32 hi */ + const uint32_t lo = (uint32_t) xl * yl; + const uint32_t m1 = (uint32_t) xh * yl; + const uint32_t m2 = (uint32_t) xl * yh; + const uint32_t hi = (uint32_t) xh * yh; + + uint64_t acc = lo + ((uint64_t) (hi + (m1 >> 16) + (m2 >> 16)) << 32); + acc += m1 << 16; + acc += m2 << 16; + acc += z; + acc += t; + + return acc; +} +#endif /* MUL64_IS_CONSTANT_TIME */ +#endif /* MULADD64_ASM */ + +/* + * 288 + 32 x 256 -> 288-bit multiply and add + * + * in: x in [0, 2^32) + * y in [0, 2^256) + * z in [0, 2^288) + * out: z_out = z_in + x * y mod 2^288 + * c = z_in + x * y div 2^288 + * That is, z_out + c * 2^288 = z_in + x * y + * + * Note: as a memory area, z must be either equal to y, or not overlap. + * + * This is a helper for Montgomery multiplication. + */ +static uint32_t u288_muladd(uint32_t z[9], uint32_t x, const uint32_t y[8]) +{ + uint32_t carry = 0; + +#define U288_MULADD_STEP(i) \ + do { \ + uint64_t prod = u32_muladd64(x, y[i], z[i], carry); \ + z[i] = (uint32_t) prod; \ + carry = (uint32_t) (prod >> 32); \ + } while( 0 ) + +#if defined(MULADD64_SMALL) + U288_MULADD_STEP(0); + U288_MULADD_STEP(1); + U288_MULADD_STEP(2); + U288_MULADD_STEP(3); + U288_MULADD_STEP(4); + U288_MULADD_STEP(5); + U288_MULADD_STEP(6); + U288_MULADD_STEP(7); +#else + for (unsigned i = 0; i < 8; i++) { + U288_MULADD_STEP(i); + } +#endif + + uint64_t sum = (uint64_t) z[8] + carry; + z[8] = (uint32_t) sum; + carry = (uint32_t) (sum >> 32); + + return carry; +} + +/* + * 288-bit in-place right shift by 32 bits + * + * in: z in [0, 2^288) + * c in [0, 2^32) + * out: z_out = z_in div 2^32 + c * 2^256 + * = (z_in + c * 2^288) div 2^32 + * + * This is a helper for Montgomery multiplication. + */ +static void u288_rshift32(uint32_t z[9], uint32_t c) +{ + for (unsigned i = 0; i < 8; i++) { + z[i] = z[i + 1]; + } + z[8] = c; +} + +/* + * 256-bit import from big-endian bytes + * + * in: p = p0, ..., p31 + * out: z = p0 * 2^248 + p1 * 2^240 + ... + p30 * 2^8 + p31 + */ +static void u256_from_bytes(uint32_t z[8], const uint8_t p[32]) +{ + for (unsigned i = 0; i < 8; i++) { + unsigned j = 4 * (7 - i); + z[i] = ((uint32_t) p[j + 0] << 24) | + ((uint32_t) p[j + 1] << 16) | + ((uint32_t) p[j + 2] << 8) | + ((uint32_t) p[j + 3] << 0); + } +} + +/* + * 256-bit export to big-endian bytes + * + * in: z in [0, 2^256) + * out: p = p0, ..., p31 such that + * z = p0 * 2^248 + p1 * 2^240 + ... + p30 * 2^8 + p31 + */ +static void u256_to_bytes(uint8_t p[32], const uint32_t z[8]) +{ + for (unsigned i = 0; i < 8; i++) { + unsigned j = 4 * (7 - i); + p[j + 0] = (uint8_t) (z[i] >> 24); + p[j + 1] = (uint8_t) (z[i] >> 16); + p[j + 2] = (uint8_t) (z[i] >> 8); + p[j + 3] = (uint8_t) (z[i] >> 0); + } +} + +/********************************************************************** + * + * Operations modulo a 256-bit prime m + * + * These are done in the Montgomery domain, that is x is represented by + * x * 2^256 mod m + * Numbers need to be converted to that domain before computations, + * and back from it afterwards. + * + * Inversion is computed using Fermat's little theorem. + * + * Assumptions on m: + * - Montgomery operations require that m is odd. + * - Fermat's little theorem require it to be a prime. + * - m256_inv() further requires that m % 2^32 >= 2. + * - m256_inv() also assumes that the value of m is not a secret. + * + * In practice operations are done modulo the curve's p and n, + * both of which satisfy those assumptions. + * + **********************************************************************/ + +/* + * Data associated to a modulus for Montgomery operations. + * + * m in [0, 2^256) - the modulus itself, must be odd + * R2 = 2^512 mod m + * ni = -m^-1 mod 2^32 + */ +typedef struct { + uint32_t m[8]; + uint32_t R2[8]; + uint32_t ni; +} +m256_mod; + +/* + * Data for Montgomery operations modulo the curve's p + */ +static const m256_mod p256_p = { + { /* the curve's p */ + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF, + }, + { /* 2^512 mod p */ + 0x00000003, 0x00000000, 0xffffffff, 0xfffffffb, + 0xfffffffe, 0xffffffff, 0xfffffffd, 0x00000004, + }, + 0x00000001, /* -p^-1 mod 2^32 */ +}; + +/* + * Data for Montgomery operations modulo the curve's n + */ +static const m256_mod p256_n = { + { /* the curve's n */ + 0xFC632551, 0xF3B9CAC2, 0xA7179E84, 0xBCE6FAAD, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + }, + { /* 2^512 mod n */ + 0xbe79eea2, 0x83244c95, 0x49bd6fa6, 0x4699799c, + 0x2b6bec59, 0x2845b239, 0xf3d95620, 0x66e12d94, + }, + 0xee00bc4f, /* -n^-1 mod 2^32 */ +}; + +/* + * Modular addition + * + * in: x, y in [0, m) + * mod must point to a valid m256_mod structure + * out: z = (x + y) mod m, in [0, m) + * + * Note: as a memory area, z must be either equal to x or y, or not overlap. + */ +static void m256_add(uint32_t z[8], + const uint32_t x[8], const uint32_t y[8], + const m256_mod *mod) +{ + uint32_t r[8]; + uint32_t carry_add = u256_add(z, x, y); + uint32_t carry_sub = u256_sub(r, z, mod->m); + /* Need to subract m if: + * x+y >= 2^256 > m (that is, carry_add == 1) + * OR z >= m (that is, carry_sub == 0) */ + uint32_t use_sub = carry_add | (1 - carry_sub); + u256_cmov(z, r, use_sub); +} + +/* + * Modular addition mod p + * + * in: x, y in [0, p) + * out: z = (x + y) mod p, in [0, p) + * + * Note: as a memory area, z must be either equal to x or y, or not overlap. + */ +static void m256_add_p(uint32_t z[8], + const uint32_t x[8], const uint32_t y[8]) +{ + m256_add(z, x, y, &p256_p); +} + +/* + * Modular subtraction + * + * in: x, y in [0, m) + * mod must point to a valid m256_mod structure + * out: z = (x - y) mod m, in [0, m) + * + * Note: as a memory area, z must be either equal to x or y, or not overlap. + */ +static void m256_sub(uint32_t z[8], + const uint32_t x[8], const uint32_t y[8], + const m256_mod *mod) +{ + uint32_t r[8]; + uint32_t carry = u256_sub(z, x, y); + (void) u256_add(r, z, mod->m); + /* Need to add m if and only if x < y, that is carry == 1. + * In that case z is in [2^256 - m + 1, 2^256 - 1], so the + * addition will have a carry as well, which cancels out. */ + u256_cmov(z, r, carry); +} + +/* + * Modular subtraction mod p + * + * in: x, y in [0, p) + * out: z = (x + y) mod p, in [0, p) + * + * Note: as a memory area, z must be either equal to x or y, or not overlap. + */ +static void m256_sub_p(uint32_t z[8], + const uint32_t x[8], const uint32_t y[8]) +{ + m256_sub(z, x, y, &p256_p); +} + +/* + * Montgomery modular multiplication + * + * in: x, y in [0, m) + * mod must point to a valid m256_mod structure + * out: z = (x * y) / 2^256 mod m, in [0, m) + * + * Note: as a memory area, z may overlap with x or y. + */ +static void m256_mul(uint32_t z[8], + const uint32_t x[8], const uint32_t y[8], + const m256_mod *mod) +{ + /* + * Algorithm 14.36 in Handbook of Applied Cryptography with: + * b = 2^32, n = 8, R = 2^256 + */ + uint32_t m_prime = mod->ni; + uint32_t a[9]; + + for (unsigned i = 0; i < 9; i++) { + a[i] = 0; + } + + for (unsigned i = 0; i < 8; i++) { + /* the "mod 2^32" is implicit from the type */ + uint32_t u = (a[0] + x[i] * y[0]) * m_prime; + + /* a = (a + x[i] * y + u * m) div b */ + uint32_t c = u288_muladd(a, x[i], y); + c += u288_muladd(a, u, mod->m); + u288_rshift32(a, c); + } + + /* a = a > m ? a - m : a */ + uint32_t carry_add = a[8]; // 0 or 1 since a < 2m, see HAC Note 14.37 + uint32_t carry_sub = u256_sub(z, a, mod->m); + uint32_t use_sub = carry_add | (1 - carry_sub); // see m256_add() + u256_cmov(z, a, 1 - use_sub); +} + +/* + * Montgomery modular multiplication modulo p. + * + * in: x, y in [0, p) + * out: z = (x * y) / 2^256 mod p, in [0, p) + * + * Note: as a memory area, z may overlap with x or y. + */ +static void m256_mul_p(uint32_t z[8], + const uint32_t x[8], const uint32_t y[8]) +{ + m256_mul(z, x, y, &p256_p); +} + +/* + * In-place conversion to Montgomery form + * + * in: z in [0, m) + * mod must point to a valid m256_mod structure + * out: z_out = z_in * 2^256 mod m, in [0, m) + */ +static void m256_prep(uint32_t z[8], const m256_mod *mod) +{ + m256_mul(z, z, mod->R2, mod); +} + +/* + * In-place conversion from Montgomery form + * + * in: z in [0, m) + * mod must point to a valid m256_mod structure + * out: z_out = z_in / 2^256 mod m, in [0, m) + * That is, z_in was z_actual * 2^256 mod m, and z_out is z_actual + */ +static void m256_done(uint32_t z[8], const m256_mod *mod) +{ + uint32_t one[8]; + u256_set32(one, 1); + m256_mul(z, z, one, mod); +} + +/* + * Set to 32-bit value + * + * in: x in [0, 2^32) + * mod must point to a valid m256_mod structure + * out: z = x * 2^256 mod m, in [0, m) + * That is, z is set to the image of x in the Montgomery domain. + */ +static void m256_set32(uint32_t z[8], uint32_t x, const m256_mod *mod) +{ + u256_set32(z, x); + m256_prep(z, mod); +} + +/* + * Modular inversion in Montgomery form + * + * in: x in [0, m) + * mod must point to a valid m256_mod structure + * such that mod->m % 2^32 >= 2, assumed to be public. + * out: z = x^-1 * 2^512 mod m if x != 0, + * z = 0 if x == 0 + * That is, if x = x_actual * 2^256 mod m, then + * z = x_actual^-1 * 2^256 mod m + * + * Note: as a memory area, z may overlap with x. + */ +static void m256_inv(uint32_t z[8], const uint32_t x[8], + const m256_mod *mod) +{ + /* + * Use Fermat's little theorem to compute x^-1 as x^(m-2). + * + * Take advantage of the fact that both p's and n's least significant limb + * is at least 2 to perform the subtraction on the flight (no carry). + * + * Use plain right-to-left binary exponentiation; + * branches are OK as the exponent is not a secret. + */ + uint32_t bitval[8]; + u256_cmov(bitval, x, 1); /* copy x before writing to z */ + + m256_set32(z, 1, mod); + + unsigned i = 0; + uint32_t limb = mod->m[i] - 2; + while (1) { + for (unsigned j = 0; j < 32; j++) { + if ((limb & 1) != 0) { + m256_mul(z, z, bitval, mod); + } + m256_mul(bitval, bitval, bitval, mod); + limb >>= 1; + } + + if (i == 7) + break; + + i++; + limb = mod->m[i]; + } +} + +/* + * Import modular integer from bytes to Montgomery domain + * + * in: p = p0, ..., p32 + * mod must point to a valid m256_mod structure + * out: z = (p0 * 2^248 + ... + p31) * 2^256 mod m, in [0, m) + * return 0 if the number was already in [0, m), or -1. + * z may be incorrect and must be discared when -1 is returned. + */ +static int m256_from_bytes(uint32_t z[8], + const uint8_t p[32], const m256_mod *mod) +{ + u256_from_bytes(z, p); + + uint32_t t[8]; + uint32_t lt_m = u256_sub(t, z, mod->m); + if (lt_m != 1) + return -1; + + m256_prep(z, mod); + return 0; +} + +/* + * Export modular integer from Montgomery domain to bytes + * + * in: z in [0, 2^256) + * mod must point to a valid m256_mod structure + * out: p = p0, ..., p31 such that + * z = (p0 * 2^248 + ... + p31) * 2^256 mod m + */ +static void m256_to_bytes(uint8_t p[32], + const uint32_t z[8], const m256_mod *mod) +{ + uint32_t zi[8]; + u256_cmov(zi, z, 1); + m256_done(zi, mod); + + u256_to_bytes(p, zi); +} + +/********************************************************************** + * + * Operations on curve points + * + * Points are represented in two coordinates system: + * - affine (x, y) - extended to represent 0 (see below) + * - jacobian (x:y:z) + * In either case, coordinates are integers modulo p256_p and + * are always represented in the Montgomery domain. + * + * For background on jacobian coordinates, see for example [GECC] 3.2.2: + * - conversions go (x, y) -> (x:y:1) and (x:y:z) -> (x/z^2, y/z^3) + * - the curve equation becomes y^2 = x^3 - 3 x z^4 + b z^6 + * - 0 (aka the origin aka point at infinity) is (x:y:0) with y^2 = x^3. + * - point negation goes -(x:y:z) = (x:-y:z) + * + * Normally 0 (the point at infinity) can't be represented in affine + * coordinates. However we extend affine coordinates with the convention that + * (0, 0) (which is normally not a point on the curve) is interpreted as 0. + * + * References: + * - [GECC]: Guide to Elliptic Curve Cryptography; Hankerson, Menezes, + * Vanstone; Springer, 2004. + * - [CMO98]: Efficient Elliptic Curve Exponentiation Using Mixed Coordinates; + * Cohen, Miyaji, Ono; Springer, ASIACRYPT 1998. + * https://link.springer.com/content/pdf/10.1007/3-540-49649-1_6.pdf + * - [RCB15]: Complete addition formulas for prime order elliptic curves; + * Renes, Costello, Batina; IACR e-print 2015-1060. + * https://eprint.iacr.org/2015/1060.pdf + * + **********************************************************************/ + +/* + * The curve's b parameter in the Short Weierstrass equation + * y^2 = x^3 - 3*x + b + * Compared to the standard, this is converted to the Montgomery domain. + */ +static const uint32_t p256_b[8] = { /* b * 2^256 mod p */ + 0x29c4bddf, 0xd89cdf62, 0x78843090, 0xacf005cd, + 0xf7212ed6, 0xe5a220ab, 0x04874834, 0xdc30061d, +}; + +/* + * The curve's conventional base point G. + * Compared to the standard, coordinates converted to the Montgomery domain. + */ +static const uint32_t p256_gx[8] = { /* G_x * 2^256 mod p */ + 0x18a9143c, 0x79e730d4, 0x5fedb601, 0x75ba95fc, + 0x77622510, 0x79fb732b, 0xa53755c6, 0x18905f76, +}; +static const uint32_t p256_gy[8] = { /* G_y * 2^256 mod p */ + 0xce95560a, 0xddf25357, 0xba19e45c, 0x8b4ab8e4, + 0xdd21f325, 0xd2e88688, 0x25885d85, 0x8571ff18, +}; + +/* + * Point-on-curve check - do the coordinates satisfy the curve's equation? + * + * in: x, y in [0, p) (Montgomery domain) + * out: 0 if the point lies on the curve and is not 0, + * unspecified non-zero otherwise + */ +static uint32_t point_check(const uint32_t x[8], const uint32_t y[8]) +{ + uint32_t lhs[8], rhs[8]; + + /* lhs = y^2 */ + m256_mul_p(lhs, y, y); + + /* rhs = x^3 - 3x + b */ + m256_mul_p(rhs, x, x); /* x^2 */ + m256_mul_p(rhs, rhs, x); /* x^3 */ + for (unsigned i = 0; i < 3; i++) + m256_sub_p(rhs, rhs, x); /* x^3 - 3x */ + m256_add_p(rhs, rhs, p256_b); /* x^3 - 3x + b */ + + return u256_diff(lhs, rhs); +} + +/* + * In-place jacobian to affine coordinate conversion + * + * in: (x:y:z) must be on the curve (coordinates in Montegomery domain) + * out: x_out = x_in / z_in^2 (Montgomery domain) + * y_out = y_in / z_in^3 (Montgomery domain) + * z_out unspecified, must be disregarded + * + * Note: if z is 0 (that is, the input point is 0), x_out = y_out = 0. + */ +static void point_to_affine(uint32_t x[8], uint32_t y[8], uint32_t z[8]) +{ + uint32_t t[8]; + + m256_inv(z, z, &p256_p); /* z = z^-1 */ + + m256_mul_p(t, z, z); /* t = z^-2 */ + m256_mul_p(x, x, t); /* x = x * z^-2 */ + + m256_mul_p(t, t, z); /* t = z^-3 */ + m256_mul_p(y, y, t); /* y = y * z^-3 */ +} + +/* + * In-place point doubling in jacobian coordinates (Montgomery domain) + * + * in: P_in = (x:y:z), must be on the curve + * out: (x:y:z) = P_out = 2 * P_in + */ +static void point_double(uint32_t x[8], uint32_t y[8], uint32_t z[8]) +{ + /* + * This is formula 6 from [CMO98], cited as complete in [RCB15] (table 1). + * Notations as in the paper, except u added and t ommited (it's x3). + */ + uint32_t m[8], s[8], u[8]; + + /* m = 3 * x^2 + a * z^4 = 3 * (x + z^2) * (x - z^2) */ + m256_mul_p(s, z, z); + m256_add_p(m, x, s); + m256_sub_p(u, x, s); + m256_mul_p(s, m, u); + m256_add_p(m, s, s); + m256_add_p(m, m, s); + + /* s = 4 * x * y^2 */ + m256_mul_p(u, y, y); + m256_add_p(u, u, u); /* u = 2 * y^2 (used below) */ + m256_mul_p(s, x, u); + m256_add_p(s, s, s); + + /* u = 8 * y^4 (not named in the paper, first term of y3) */ + m256_mul_p(u, u, u); + m256_add_p(u, u, u); + + /* x3 = t = m^2 - 2 * s */ + m256_mul_p(x, m, m); + m256_sub_p(x, x, s); + m256_sub_p(x, x, s); + + /* z3 = 2 * y * z */ + m256_mul_p(z, y, z); + m256_add_p(z, z, z); + + /* y3 = -u + m * (s - t) */ + m256_sub_p(y, s, x); + m256_mul_p(y, y, m); + m256_sub_p(y, y, u); +} + +/* + * In-place point addition in jacobian-affine coordinates (Montgomery domain) + * + * in: P_in = (x1:y1:z1), must be on the curve and not 0 + * Q = (x2, y2), must be on the curve and not P_in or -P_in or 0 + * out: P_out = (x1:y1:z1) = P_in + Q + */ +static void point_add(uint32_t x1[8], uint32_t y1[8], uint32_t z1[8], + const uint32_t x2[8], const uint32_t y2[8]) +{ + /* + * This is formula 5 from [CMO98], with z2 == 1 substituted. We use + * intermediates with neutral names, and names from the paper in comments. + */ + uint32_t t1[8], t2[8], t3[8]; + + /* u1 = x1 and s1 = y1 (no computations) */ + + /* t1 = u2 = x2 z1^2 */ + m256_mul_p(t1, z1, z1); + m256_mul_p(t2, t1, z1); + m256_mul_p(t1, t1, x2); + + /* t2 = s2 = y2 z1^3 */ + m256_mul_p(t2, t2, y2); + + /* t1 = h = u2 - u1 */ + m256_sub_p(t1, t1, x1); /* t1 = x2 * z1^2 - x1 */ + + /* t2 = r = s2 - s1 */ + m256_sub_p(t2, t2, y1); + + /* z3 = z1 * h */ + m256_mul_p(z1, z1, t1); + + /* t1 = h^3 */ + m256_mul_p(t3, t1, t1); + m256_mul_p(t1, t3, t1); + + /* t3 = x1 * h^2 */ + m256_mul_p(t3, t3, x1); + + /* x3 = r^2 - 2 * x1 * h^2 - h^3 */ + m256_mul_p(x1, t2, t2); + m256_sub_p(x1, x1, t3); + m256_sub_p(x1, x1, t3); + m256_sub_p(x1, x1, t1); + + /* y3 = r * (x1 * h^2 - x3) - y1 h^3 */ + m256_sub_p(t3, t3, x1); + m256_mul_p(t3, t3, t2); + m256_mul_p(t1, t1, y1); + m256_sub_p(y1, t3, t1); +} + +/* + * Point addition or doubling (affine to jacobian, Montgomery domain) + * + * in: P = (x1, y1) - must be on the curve and not 0 + * Q = (x2, y2) - must be on the curve and not 0 + * out: (x3, y3) = R = P + Q + * + * Note: unlike point_add(), this function works if P = +- Q; + * however it leaks information on its input through timing, + * branches taken and memory access patterns (if observable). + */ +static void point_add_or_double_leaky( + uint32_t x3[8], uint32_t y3[8], + const uint32_t x1[8], const uint32_t y1[8], + const uint32_t x2[8], const uint32_t y2[8]) +{ + + uint32_t z3[8]; + u256_cmov(x3, x1, 1); + u256_cmov(y3, y1, 1); + m256_set32(z3, 1, &p256_p); + + if (u256_diff(x1, x2) != 0) { + // P != +- Q -> generic addition + point_add(x3, y3, z3, x2, y2); + point_to_affine(x3, y3, z3); + } + else if (u256_diff(y1, y2) == 0) { + // P == Q -> double + point_double(x3, y3, z3); + point_to_affine(x3, y3, z3); + } else { + // P == -Q -> zero + m256_set32(x3, 0, &p256_p); + m256_set32(y3, 0, &p256_p); + } +} + +/* + * Import curve point from bytes + * + * in: p = (x, y) concatenated, fixed-width 256-bit big-endian integers + * out: x, y in Mongomery domain + * return 0 if x and y are both in [0, p) + * and (x, y) is on the curve and not 0 + * unspecified non-zero otherwise. + * x and y are unspecified and must be discarded if returning non-zero. + */ +static int point_from_bytes(uint32_t x[8], uint32_t y[8], const uint8_t p[64]) +{ + int ret; + + ret = m256_from_bytes(x, p, &p256_p); + if (ret != 0) + return ret; + + ret = m256_from_bytes(y, p + 32, &p256_p); + if (ret != 0) + return ret; + + return (int) point_check(x, y); +} + +/* + * Export curve point to bytes + * + * in: x, y affine coordinates of a point (Montgomery domain) + * must be on the curve and not 0 + * out: p = (x, y) concatenated, fixed-width 256-bit big-endian integers + */ +static void point_to_bytes(uint8_t p[64], + const uint32_t x[8], const uint32_t y[8]) +{ + m256_to_bytes(p, x, &p256_p); + m256_to_bytes(p + 32, y, &p256_p); +} + +/********************************************************************** + * + * Scalar multiplication and other scalar-related operations + * + **********************************************************************/ + +/* + * Scalar multiplication + * + * in: P = (px, py), affine (Montgomery), must be on the curve and not 0 + * s in [1, n-1] + * out: R = s * P = (rx, ry), affine coordinates (Montgomery). + * + * Note: as memory areas, none of the parameters may overlap. + */ +static void scalar_mult(uint32_t rx[8], uint32_t ry[8], + const uint32_t px[8], const uint32_t py[8], + const uint32_t s[8]) +{ + /* + * We use a signed binary ladder, see for example slides 10-14 of + * http://ecc2015.math.u-bordeaux1.fr/documents/hamburg.pdf but with + * implicit recoding, and a different loop initialisation to avoid feeding + * 0 to our addition formulas, as they don't support it. + */ + uint32_t s_odd[8], py_neg[8], py_use[8], rz[8]; + + /* + * Make s odd by replacing it with n - s if necessary. + * + * If s was odd, we'll have s_odd = s, and define P' = P. + * Otherwise, we'll have s_odd = n - s and define P' = -P. + * + * Either way, we can compute s * P as s_odd * P'. + */ + u256_sub(s_odd, p256_n.m, s); /* no carry, result still in [1, n-1] */ + uint32_t negate = ~s[0] & 1; + u256_cmov(s_odd, s, 1 - negate); + + /* Compute py_neg = - py mod p (that's the y coordinate of -P) */ + u256_set32(py_use, 0); + m256_sub_p(py_neg, py_use, py); + + /* Initialize R = P' = (x:(-1)^negate * y:1) */ + u256_cmov(rx, px, 1); + u256_cmov(ry, py, 1); + m256_set32(rz, 1, &p256_p); + u256_cmov(ry, py_neg, negate); + + /* + * For any odd number s_odd = b255 ... b1 1, we have + * s_odd = 2^255 + 2^254 sbit(b255) + ... + 2 sbit(b2) + sbit(b1) + * writing + * sbit(b) = 2 * b - 1 = b ? 1 : -1 + * + * Use that to compute s_odd * P' by repeating R = 2 * R +- P': + * s_odd * P' = 2 * ( ... (2 * P' + sbit(b255) P') ... ) + sbit(b1) P' + * + * The loop invariant is that when beginning an iteration we have + * R = s_i P' + * with + * s_i = 2^(255-i) + 2^(254-i) sbit(b_255) + ... + * where the sum has 256 - i terms. + * + * When updating R we need to make sure the input to point_add() is + * neither 0 not +-P'. Since that input is 2 s_i P', it is sufficient to + * see that 1 < 2 s_i < n-1. The lower bound is obvious since s_i is a + * positive integer, and for the upper bound we distinguish three cases. + * + * If i > 1, then s_i < 2^254, so 2 s_i < 2^255 < n-1. + * Otherwise, i == 1 and we have 2 s_i = s_odd - sbit(b1). + * If s_odd <= n-4, then 2 s_1 <= n-3. + * Otherwise, s_odd = n-2, and for this curve's value of n, + * we have b1 == 1, so sbit(b1) = 1 and 2 s_1 <= n-3. + */ + for (unsigned i = 255; i > 0; i--) { + uint32_t bit = (s_odd[i / 32] >> i % 32) & 1; + + /* set (px, py_use) = sbit(bit) P' = sbit(bit) * (-1)^negate P */ + u256_cmov(py_use, py, bit ^ negate); + u256_cmov(py_use, py_neg, (1 - bit) ^ negate); + + /* Update R = 2 * R +- P' */ + point_double(rx, ry, rz); + point_add(rx, ry, rz, px, py_use); + } + + point_to_affine(rx, ry, rz); +} + +/* + * Scalar import from big-endian bytes + * + * in: p = p0, ..., p31 + * out: s = p0 * 2^248 + p1 * 2^240 + ... + p30 * 2^8 + p31 + * return 0 if s in [1, n-1], + * -1 otherwise. + */ +static int scalar_from_bytes(uint32_t s[8], const uint8_t p[32]) +{ + u256_from_bytes(s, p); + + uint32_t r[8]; + uint32_t lt_n = u256_sub(r, s, p256_n.m); + + u256_set32(r, 1); + uint32_t lt_1 = u256_sub(r, s, r); + + if (lt_n && !lt_1) + return 0; + + return -1; +} + +/* Using RNG functions from Mbed TLS as p256-m does not come with a + * cryptographically secure RNG function. + */ +int p256_generate_random(uint8_t *output, unsigned output_size) +{ + int ret; + ret = psa_generate_random(output, output_size); + + if (ret != 0){ + return P256_RANDOM_FAILED; + } + return P256_SUCCESS; +} + +/* + * Scalar generation, with public key + * + * out: sbytes the big-endian bytes representation of the scalar + * s its u256 representation + * x, y the affine coordinates of s * G (Montgomery domain) + * return 0 if OK, -1 on failure + * sbytes, s, x, y must be discarded when returning non-zero. + */ +static int scalar_gen_with_pub(uint8_t sbytes[32], uint32_t s[8], + uint32_t x[8], uint32_t y[8]) +{ + /* generate a random valid scalar */ + int ret; + unsigned nb_tried = 0; + do { + if (nb_tried++ >= 4) + return -1; + + ret = p256_generate_random(sbytes, 32); + CT_POISON(sbytes, 32); + if (ret != 0) + return -1; + + ret = scalar_from_bytes(s, sbytes); + CT_UNPOISON(&ret, sizeof ret); + } + while (ret != 0); + + /* compute and ouput the associated public key */ + scalar_mult(x, y, p256_gx, p256_gy, s); + + /* the associated public key is not a secret */ + CT_UNPOISON(x, 32); + CT_UNPOISON(y, 32); + + return 0; +} + +/* + * ECDH/ECDSA generate pair + */ +int p256_gen_keypair(uint8_t priv[32], uint8_t pub[64]) +{ + uint32_t s[8], x[8], y[8]; + int ret = scalar_gen_with_pub(priv, s, x, y); + zeroize(s, sizeof s); + if (ret != 0) + return P256_RANDOM_FAILED; + + point_to_bytes(pub, x, y); + return 0; +} + +/********************************************************************** + * + * ECDH + * + **********************************************************************/ + +/* + * ECDH compute shared secret + */ +int p256_ecdh_shared_secret(uint8_t secret[32], + const uint8_t priv[32], const uint8_t peer[64]) +{ + CT_POISON(priv, 32); + + uint32_t s[8], px[8], py[8], x[8], y[8]; + int ret; + + ret = scalar_from_bytes(s, priv); + CT_UNPOISON(&ret, sizeof ret); + if (ret != 0) { + ret = P256_INVALID_PRIVKEY; + goto cleanup; + } + + ret = point_from_bytes(px, py, peer); + if (ret != 0) { + ret = P256_INVALID_PUBKEY; + goto cleanup; + } + + scalar_mult(x, y, px, py, s); + + m256_to_bytes(secret, x, &p256_p); + CT_UNPOISON(secret, 32); + +cleanup: + zeroize(s, sizeof s); + return ret; +} + +/********************************************************************** + * + * ECDSA + * + * Reference: + * [SEC1] SEC 1: Elliptic Curve Cryptography, Certicom research, 2009. + * http://www.secg.org/sec1-v2.pdf + **********************************************************************/ + +/* + * Reduction mod n of a small number + * + * in: x in [0, 2^256) + * out: x_out = x_in mod n in [0, n) + */ +static void ecdsa_m256_mod_n(uint32_t x[8]) +{ + uint32_t t[8]; + uint32_t c = u256_sub(t, x, p256_n.m); + u256_cmov(x, t, 1 - c); +} + +/* + * Import integer mod n (Montgomery domain) from hash + * + * in: h = h0, ..., h_hlen + * hlen the length of h in bytes + * out: z = (h0 * 2^l-8 + ... + h_l) * 2^256 mod n + * with l = min(32, hlen) + * + * Note: in [SEC1] this is step 5 of 4.1.3 (sign) or step 3 or 4.1.4 (verify), + * with obvious simplications since n's bit-length is a multiple of 8. + */ +static void ecdsa_m256_from_hash(uint32_t z[8], + const uint8_t *h, size_t hlen) +{ + /* convert from h (big-endian) */ + /* hlen is public data so it's OK to branch on it */ + if (hlen < 32) { + uint8_t p[32]; + for (unsigned i = 0; i < 32; i++) + p[i] = 0; + for (unsigned i = 0; i < hlen; i++) + p[32 - hlen + i] = h[i]; + u256_from_bytes(z, p); + } else { + u256_from_bytes(z, h); + } + + /* ensure the result is in [0, n) */ + ecdsa_m256_mod_n(z); + + /* map to Montgomery domain */ + m256_prep(z, &p256_n); +} + +/* + * ECDSA sign + */ +int p256_ecdsa_sign(uint8_t sig[64], const uint8_t priv[32], + const uint8_t *hash, size_t hlen) +{ + CT_POISON(priv, 32); + + /* + * Steps and notations from [SEC1] 4.1.3 + * + * Instead of retrying on r == 0 or s == 0, just abort, + * as those events have negligible probability. + */ + int ret; + + /* Temporary buffers - the first two are mostly stable, so have names */ + uint32_t xr[8], k[8], t3[8], t4[8]; + + /* 1. Set ephemeral keypair */ + uint8_t *kb = (uint8_t *) t4; + /* kb will be erased by re-using t4 for dU - if we exit before that, we + * haven't read the private key yet so we kb isn't sensitive yet */ + ret = scalar_gen_with_pub(kb, k, xr, t3); /* xr = x_coord(k * G) */ + if (ret != 0) + return P256_RANDOM_FAILED; + m256_prep(k, &p256_n); + + /* 2. Convert xr to an integer */ + m256_done(xr, &p256_p); + + /* 3. Reduce xr mod n (extra: output it while at it) */ + ecdsa_m256_mod_n(xr); /* xr = int(xr) mod n */ + + /* xr is public data so it's OK to use a branch */ + if (u256_diff0(xr) == 0) + return P256_RANDOM_FAILED; + + u256_to_bytes(sig, xr); + + m256_prep(xr, &p256_n); + + /* 4. Skipped - we take the hash as an input, not the message */ + + /* 5. Derive an integer from the hash */ + ecdsa_m256_from_hash(t3, hash, hlen); /* t3 = e */ + + /* 6. Compute s = k^-1 * (e + r * dU) */ + + /* Note: dU will be erased by re-using t4 for the value of s (public) */ + ret = scalar_from_bytes(t4, priv); /* t4 = dU (integer domain) */ + CT_UNPOISON(&ret, sizeof ret); /* Result of input validation */ + if (ret != 0) + return P256_INVALID_PRIVKEY; + m256_prep(t4, &p256_n); /* t4 = dU (Montgomery domain) */ + + m256_inv(k, k, &p256_n); /* k^-1 */ + m256_mul(t4, xr, t4, &p256_n); /* t4 = r * dU */ + m256_add(t4, t3, t4, &p256_n); /* t4 = e + r * dU */ + m256_mul(t4, k, t4, &p256_n); /* t4 = s = k^-1 * (e + r * dU) */ + zeroize(k, sizeof k); + + /* 7. Output s (r already outputed at step 3) */ + CT_UNPOISON(t4, 32); + if (u256_diff0(t4) == 0) { + /* undo early output of r */ + u256_to_bytes(sig, t4); + return P256_RANDOM_FAILED; + } + m256_to_bytes(sig + 32, t4, &p256_n); + + return P256_SUCCESS; +} + +/* + * ECDSA verify + */ +int p256_ecdsa_verify(const uint8_t sig[64], const uint8_t pub[64], + const uint8_t *hash, size_t hlen) +{ + /* + * Steps and notations from [SEC1] 4.1.3 + * + * Note: we're using public data only, so branches are OK + */ + int ret; + + /* 1. Validate range of r and s : [1, n-1] */ + uint32_t r[8], s[8]; + ret = scalar_from_bytes(r, sig); + if (ret != 0) + return P256_INVALID_SIGNATURE; + ret = scalar_from_bytes(s, sig + 32); + if (ret != 0) + return P256_INVALID_SIGNATURE; + + /* 2. Skipped - we take the hash as an input, not the message */ + + /* 3. Derive an integer from the hash */ + uint32_t e[8]; + ecdsa_m256_from_hash(e, hash, hlen); + + /* 4. Compute u1 = e * s^-1 and u2 = r * s^-1 */ + uint32_t u1[8], u2[8]; + m256_prep(s, &p256_n); /* s in Montgomery domain */ + m256_inv(s, s, &p256_n); /* s = s^-1 mod n */ + m256_mul(u1, e, s, &p256_n); /* u1 = e * s^-1 mod n */ + m256_done(u1, &p256_n); /* u1 out of Montgomery domain */ + + u256_cmov(u2, r, 1); + m256_prep(u2, &p256_n); /* r in Montgomery domain */ + m256_mul(u2, u2, s, &p256_n); /* u2 = r * s^-1 mod n */ + m256_done(u2, &p256_n); /* u2 out of Montgomery domain */ + + /* 5. Compute R (and re-use (u1, u2) to store its coordinates */ + uint32_t px[8], py[8]; + ret = point_from_bytes(px, py, pub); + if (ret != 0) + return P256_INVALID_PUBKEY; + + scalar_mult(e, s, px, py, u2); /* (e, s) = R2 = u2 * Qu */ + + if (u256_diff0(u1) == 0) { + /* u1 out of range for scalar_mult() - just skip it */ + u256_cmov(u1, e, 1); + /* we don't care about the y coordinate */ + } else { + scalar_mult(px, py, p256_gx, p256_gy, u1); /* (px, py) = R1 = u1 * G */ + + /* (u1, u2) = R = R1 + R2 */ + point_add_or_double_leaky(u1, u2, px, py, e, s); + /* No need to check if R == 0 here: if that's the case, it will be + * caught when comparating rx (which will be 0) to r (which isn't). */ + } + + /* 6. Convert xR to an integer */ + m256_done(u1, &p256_p); + + /* 7. Reduce xR mod n */ + ecdsa_m256_mod_n(u1); + + /* 8. Compare xR mod n to r */ + uint32_t diff = u256_diff(u1, r); + if (diff == 0) + return P256_SUCCESS; + + return P256_INVALID_SIGNATURE; +} + +/********************************************************************** + * + * Key management utilities + * + **********************************************************************/ + +int p256_validate_pubkey(const uint8_t pub[64]) +{ + uint32_t x[8], y[8]; + int ret = point_from_bytes(x, y, pub); + + return ret == 0 ? P256_SUCCESS : P256_INVALID_PUBKEY; +} + +int p256_validate_privkey(const uint8_t priv[32]) +{ + uint32_t s[8]; + int ret = scalar_from_bytes(s, priv); + zeroize(s, sizeof(s)); + + return ret == 0 ? P256_SUCCESS : P256_INVALID_PRIVKEY; +} + +int p256_public_from_private(uint8_t pub[64], const uint8_t priv[32]) +{ + int ret; + uint32_t s[8]; + + ret = scalar_from_bytes(s, priv); + if (ret != 0) + return P256_INVALID_PRIVKEY; + + /* compute and ouput the associated public key */ + uint32_t x[8], y[8]; + scalar_mult(x, y, p256_gx, p256_gy, s); + + /* the associated public key is not a secret, the scalar was */ + CT_UNPOISON(x, 32); + CT_UNPOISON(y, 32); + zeroize(s, sizeof(s)); + + point_to_bytes(pub, x, y); + return P256_SUCCESS; +} + +#endif diff --git a/tf-psa-crypto/drivers/p256-m/p256-m/p256-m.h b/tf-psa-crypto/drivers/p256-m/p256-m/p256-m.h new file mode 100644 index 0000000000..c2c11e5210 --- /dev/null +++ b/tf-psa-crypto/drivers/p256-m/p256-m/p256-m.h @@ -0,0 +1,135 @@ +/* + * Interface of curve P-256 (ECDH and ECDSA) + * + * Copyright The Mbed TLS Contributors + * Author: Manuel Pégourié-Gonnard. + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef TF_PSA_CRYPTO_P256_M_P256_M_H +#define TF_PSA_CRYPTO_P256_M_P256_M_H + +#include +#include + +/* Status codes */ +#define P256_SUCCESS 0 +#define P256_RANDOM_FAILED -1 +#define P256_INVALID_PUBKEY -2 +#define P256_INVALID_PRIVKEY -3 +#define P256_INVALID_SIGNATURE -4 + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * RNG function - must be provided externally and be cryptographically secure. + * + * in: output - must point to a writable buffer of at least output_size bytes. + * output_size - the number of random bytes to write to output. + * out: output is filled with output_size random bytes. + * return 0 on success, non-zero on errors. + */ +extern int p256_generate_random(uint8_t * output, unsigned output_size); + +/* + * ECDH/ECDSA generate key pair + * + * [in] draws from p256_generate_random() + * [out] priv: on success, holds the private key, as a big-endian integer + * [out] pub: on success, holds the public key, as two big-endian integers + * + * return: P256_SUCCESS on success + * P256_RANDOM_FAILED on failure + */ +int p256_gen_keypair(uint8_t priv[32], uint8_t pub[64]); + +/* + * ECDH compute shared secret + * + * [out] secret: on success, holds the shared secret, as a big-endian integer + * [in] priv: our private key as a big-endian integer + * [in] pub: the peer's public key, as two big-endian integers + * + * return: P256_SUCCESS on success + * P256_INVALID_PRIVKEY if priv is invalid + * P256_INVALID_PUBKEY if pub is invalid + */ +int p256_ecdh_shared_secret(uint8_t secret[32], + const uint8_t priv[32], const uint8_t pub[64]); + +/* + * ECDSA sign + * + * [in] draws from p256_generate_random() + * [out] sig: on success, holds the signature, as two big-endian integers + * [in] priv: our private key as a big-endian integer + * [in] hash: the hash of the message to be signed + * [in] hlen: the size of hash in bytes + * + * return: P256_SUCCESS on success + * P256_RANDOM_FAILED on failure + * P256_INVALID_PRIVKEY if priv is invalid + */ +int p256_ecdsa_sign(uint8_t sig[64], const uint8_t priv[32], + const uint8_t *hash, size_t hlen); + +/* + * ECDSA verify + * + * [in] sig: the signature to be verified, as two big-endian integers + * [in] pub: the associated public key, as two big-endian integers + * [in] hash: the hash of the message that was signed + * [in] hlen: the size of hash in bytes + * + * return: P256_SUCCESS on success - the signature was verified as valid + * P256_INVALID_PUBKEY if pub is invalid + * P256_INVALID_SIGNATURE if the signature was found to be invalid + */ +int p256_ecdsa_verify(const uint8_t sig[64], const uint8_t pub[64], + const uint8_t *hash, size_t hlen); + +/* + * Public key validation + * + * Note: you never need to call this function, as all other functions always + * validate their input; however it's availabe if you want to validate the key + * without performing an operation. + * + * [in] pub: the public key, as two big-endian integers + * + * return: P256_SUCCESS if the key is valid + * P256_INVALID_PUBKEY if pub is invalid + */ +int p256_validate_pubkey(const uint8_t pub[64]); + +/* + * Private key validation + * + * Note: you never need to call this function, as all other functions always + * validate their input; however it's availabe if you want to validate the key + * without performing an operation. + * + * [in] priv: the private key, as a big-endian integer + * + * return: P256_SUCCESS if the key is valid + * P256_INVALID_PRIVKEY if priv is invalid + */ +int p256_validate_privkey(const uint8_t priv[32]); + +/* + * Compute public key from private key + * + * [out] pub: the associated public key, as two big-endian integers + * [in] priv: the private key, as a big-endian integer + * + * return: P256_SUCCESS on success + * P256_INVALID_PRIVKEY if priv is invalid + */ +int p256_public_from_private(uint8_t pub[64], const uint8_t priv[32]); + +#ifdef __cplusplus +} +#endif + +#endif /* TF_PSA_CRYPTO_P256_M_P256_M_H */ diff --git a/tf-psa-crypto/drivers/p256-m/p256-m_driver_entrypoints.c b/tf-psa-crypto/drivers/p256-m/p256-m_driver_entrypoints.c new file mode 100644 index 0000000000..d272dcbb1e --- /dev/null +++ b/tf-psa-crypto/drivers/p256-m/p256-m_driver_entrypoints.c @@ -0,0 +1,312 @@ +/* + * Driver entry points for p256-m + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include "mbedtls/platform.h" +#include "p256-m_driver_entrypoints.h" +#include "p256-m/p256-m.h" +#include "psa/crypto.h" +#include +#include +#include "psa_crypto_driver_wrappers_no_static.h" + +#if defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED) + +/* INFORMATION ON PSA KEY EXPORT FORMATS: + * + * PSA exports SECP256R1 keys in two formats: + * 1. Keypair format: 32 byte string which is just the private key (public key + * can be calculated from the private key) + * 2. Public Key format: A leading byte 0x04 (indicating uncompressed format), + * followed by the 64 byte public key. This results in a + * total of 65 bytes. + * + * p256-m's internal format for private keys matches PSA. Its format for public + * keys is only 64 bytes: the same as PSA but without the leading byte (0x04). + * Hence, when passing public keys from PSA to p256-m, the leading byte is + * removed. + * + * Shared secret and signature have the same format between PSA and p256-m. + */ +#define PSA_PUBKEY_SIZE 65 +#define PSA_PUBKEY_HEADER_BYTE 0x04 +#define P256_PUBKEY_SIZE 64 +#define PRIVKEY_SIZE 32 +#define SHARED_SECRET_SIZE 32 +#define SIGNATURE_SIZE 64 + +#define CURVE_BITS 256 + +/* Convert between p256-m and PSA error codes */ +static psa_status_t p256_to_psa_error(int ret) +{ + switch (ret) { + case P256_SUCCESS: + return PSA_SUCCESS; + case P256_INVALID_PUBKEY: + case P256_INVALID_PRIVKEY: + return PSA_ERROR_INVALID_ARGUMENT; + case P256_INVALID_SIGNATURE: + return PSA_ERROR_INVALID_SIGNATURE; + case P256_RANDOM_FAILED: + default: + return PSA_ERROR_GENERIC_ERROR; + } +} + +psa_status_t p256_transparent_import_key(const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length, + size_t *bits) +{ + /* Check the key size */ + if (*bits != 0 && *bits != CURVE_BITS) { + return PSA_ERROR_NOT_SUPPORTED; + } + + /* Validate the key (and its type and size) */ + psa_key_type_t type = psa_get_key_type(attributes); + if (type == PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)) { + if (data_length != PSA_PUBKEY_SIZE) { + return *bits == 0 ? PSA_ERROR_NOT_SUPPORTED : PSA_ERROR_INVALID_ARGUMENT; + } + /* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */ + if (p256_validate_pubkey(data + 1) != P256_SUCCESS) { + return PSA_ERROR_INVALID_ARGUMENT; + } + } else if (type == PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)) { + if (data_length != PRIVKEY_SIZE) { + return *bits == 0 ? PSA_ERROR_NOT_SUPPORTED : PSA_ERROR_INVALID_ARGUMENT; + } + if (p256_validate_privkey(data) != P256_SUCCESS) { + return PSA_ERROR_INVALID_ARGUMENT; + } + } else { + return PSA_ERROR_NOT_SUPPORTED; + } + *bits = CURVE_BITS; + + /* We only support the export format for input, so just copy. */ + if (key_buffer_size < data_length) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + memcpy(key_buffer, data, data_length); + *key_buffer_length = data_length; + + return PSA_SUCCESS; +} + +psa_status_t p256_transparent_export_public_key(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *data, + size_t data_size, + size_t *data_length) +{ + /* Is this the right curve? */ + size_t bits = psa_get_key_bits(attributes); + psa_key_type_t type = psa_get_key_type(attributes); + if (bits != CURVE_BITS || type != PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)) { + return PSA_ERROR_NOT_SUPPORTED; + } + + /* Validate sizes, as p256-m expects fixed-size buffers */ + if (key_buffer_size != PRIVKEY_SIZE) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (data_size < PSA_PUBKEY_SIZE) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + /* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */ + data[0] = PSA_PUBKEY_HEADER_BYTE; + int ret = p256_public_from_private(data + 1, key_buffer); + if (ret == P256_SUCCESS) { + *data_length = PSA_PUBKEY_SIZE; + } + + return p256_to_psa_error(ret); +} + +psa_status_t p256_transparent_generate_key( + const psa_key_attributes_t *attributes, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length) +{ + /* We don't use this argument, but the specification mandates the signature + * of driver entry-points. (void) used to avoid compiler warning. */ + (void) attributes; + + /* Validate sizes, as p256-m expects fixed-size buffers */ + if (key_buffer_size != PRIVKEY_SIZE) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + /* + * p256-m's keypair generation function outputs both public and private + * keys. Allocate a buffer to which the public key will be written. The + * private key will be written to key_buffer, which is passed to this + * function as an argument. */ + uint8_t public_key_buffer[P256_PUBKEY_SIZE]; + + int ret = p256_gen_keypair(key_buffer, public_key_buffer); + if (ret == P256_SUCCESS) { + *key_buffer_length = PRIVKEY_SIZE; + } + + return p256_to_psa_error(ret); +} + +psa_status_t p256_transparent_key_agreement( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *peer_key, + size_t peer_key_length, + uint8_t *shared_secret, + size_t shared_secret_size, + size_t *shared_secret_length) +{ + /* We don't use these arguments, but the specification mandates the + * sginature of driver entry-points. (void) used to avoid compiler + * warning. */ + (void) attributes; + (void) alg; + + /* Validate sizes, as p256-m expects fixed-size buffers */ + if (key_buffer_size != PRIVKEY_SIZE || peer_key_length != PSA_PUBKEY_SIZE) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (shared_secret_size < SHARED_SECRET_SIZE) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + /* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */ + const uint8_t *peer_key_p256m = peer_key + 1; + int ret = p256_ecdh_shared_secret(shared_secret, key_buffer, peer_key_p256m); + if (ret == P256_SUCCESS) { + *shared_secret_length = SHARED_SECRET_SIZE; + } + + return p256_to_psa_error(ret); +} + +psa_status_t p256_transparent_sign_hash( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *hash, + size_t hash_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length) +{ + /* We don't use these arguments, but the specification mandates the + * sginature of driver entry-points. (void) used to avoid compiler + * warning. */ + (void) attributes; + (void) alg; + + /* Validate sizes, as p256-m expects fixed-size buffers */ + if (key_buffer_size != PRIVKEY_SIZE) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (signature_size < SIGNATURE_SIZE) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + int ret = p256_ecdsa_sign(signature, key_buffer, hash, hash_length); + if (ret == P256_SUCCESS) { + *signature_length = SIGNATURE_SIZE; + } + + return p256_to_psa_error(ret); +} + +/* This function expects the key buffer to contain a PSA public key, + * as exported by psa_export_public_key() */ +static psa_status_t p256_verify_hash_with_public_key( + const uint8_t *key_buffer, + size_t key_buffer_size, + const uint8_t *hash, + size_t hash_length, + const uint8_t *signature, + size_t signature_length) +{ + /* Validate sizes, as p256-m expects fixed-size buffers */ + if (key_buffer_size != PSA_PUBKEY_SIZE || *key_buffer != PSA_PUBKEY_HEADER_BYTE) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (signature_length != SIGNATURE_SIZE) { + return PSA_ERROR_INVALID_SIGNATURE; + } + + /* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */ + const uint8_t *public_key_p256m = key_buffer + 1; + int ret = p256_ecdsa_verify(signature, public_key_p256m, hash, hash_length); + + return p256_to_psa_error(ret); +} + +psa_status_t p256_transparent_verify_hash( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *hash, + size_t hash_length, + const uint8_t *signature, + size_t signature_length) +{ + /* We don't use this argument, but the specification mandates the signature + * of driver entry-points. (void) used to avoid compiler warning. */ + (void) alg; + + psa_status_t status; + uint8_t public_key_buffer[PSA_PUBKEY_SIZE]; + size_t public_key_buffer_size = PSA_PUBKEY_SIZE; + + size_t public_key_length = PSA_PUBKEY_SIZE; + /* As p256-m doesn't require dynamic allocation, we want to avoid it in + * the entrypoint functions as well. psa_driver_wrapper_export_public_key() + * requires size_t*, so we use a pointer to a stack variable. */ + size_t *public_key_length_ptr = &public_key_length; + + /* The contents of key_buffer may either be the 32 byte private key + * (keypair format), or 0x04 followed by the 64 byte public key (public + * key format). To ensure the key is in the latter format, the public key + * is exported. */ + status = psa_driver_wrapper_export_public_key( + attributes, + key_buffer, + key_buffer_size, + public_key_buffer, + public_key_buffer_size, + public_key_length_ptr); + if (status != PSA_SUCCESS) { + goto exit; + } + + status = p256_verify_hash_with_public_key( + public_key_buffer, + public_key_buffer_size, + hash, + hash_length, + signature, + signature_length); + +exit: + return status; +} + +#endif /* MBEDTLS_PSA_P256M_DRIVER_ENABLED */ diff --git a/tf-psa-crypto/drivers/p256-m/p256-m_driver_entrypoints.h b/tf-psa-crypto/drivers/p256-m/p256-m_driver_entrypoints.h new file mode 100644 index 0000000000..5f345988fd --- /dev/null +++ b/tf-psa-crypto/drivers/p256-m/p256-m_driver_entrypoints.h @@ -0,0 +1,219 @@ +/* + * Driver entry points for p256-m + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_P256_M_DRIVER_ENTRYPOINTS_H +#define TF_PSA_CRYPTO_P256_M_DRIVER_ENTRYPOINTS_H + +#if defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED) +#ifndef PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT +#define PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT +#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */ +#endif /* MBEDTLS_PSA_P256M_DRIVER_ENABLED */ + +#include "psa/crypto_types.h" + +/** Import SECP256R1 key. + * + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] data The raw key material. For private keys + * this must be a big-endian integer of 32 + * bytes; for public key this must be an + * uncompressed ECPoint (65 bytes). + * \param[in] data_length The size of the raw key material. + * \param[out] key_buffer The buffer to contain the key data in + * output format upon successful return. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[out] key_buffer_length The length of the data written in \p + * key_buffer in bytes. + * \param[out] bits The bitsize of the key. + * + * \retval #PSA_SUCCESS + * Success. Keypair generated and stored in buffer. + * \retval #PSA_ERROR_NOT_SUPPORTED + * The input is not supported by this driver (not SECP256R1). + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The input is invalid. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * \p key_buffer_size is too small. + */ +psa_status_t p256_transparent_import_key(const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length, + size_t *bits); + +/** Export SECP256R1 public key, from the private key. + * + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The private key in the export format. + * \param[in] key_buffer_size The size of the private key in bytes. + * \param[out] data The buffer to contain the public key in + * the export format upon successful return. + * \param[in] data_size The size of the \p data buffer in bytes. + * \param[out] data_length The length written to \p data in bytes. + * + * \retval #PSA_SUCCESS + * Success. Keypair generated and stored in buffer. + * \retval #PSA_ERROR_NOT_SUPPORTED + * The input is not supported by this driver (not SECP256R1). + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The input is invalid. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * \p key_buffer_size is too small. + */ +psa_status_t p256_transparent_export_public_key(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *data, + size_t data_size, + size_t *data_length); + +/** Generate SECP256R1 ECC Key Pair. + * Interface function which calls the p256-m key generation function and + * places it in the key buffer provided by the caller (Mbed TLS) in the + * correct format. For a SECP256R1 curve this is the 32 bit private key. + * + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[out] key_buffer The buffer to contain the key data in + * output format upon successful return. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[out] key_buffer_length The length of the data written in \p + * key_buffer in bytes. + * + * \retval #PSA_SUCCESS + * Success. Keypair generated and stored in buffer. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * \p key_buffer_size is too small. + * \retval #PSA_ERROR_GENERIC_ERROR + * The internal RNG failed. + */ +psa_status_t p256_transparent_generate_key( + const psa_key_attributes_t *attributes, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length); + +/** Perform raw key agreement using p256-m's ECDH implementation + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the private key + * in the format specified by PSA. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] alg A key agreement algorithm that is + * compatible with the type of the key. + * \param[in] peer_key The buffer containing the peer's public + * key in format specified by PSA. + * \param[in] peer_key_length Size of the \p peer_key buffer in + * bytes. + * \param[out] shared_secret The buffer to which the shared secret + * is to be written. + * \param[in] shared_secret_size Size of the \p shared_secret buffer in + * bytes. + * \param[out] shared_secret_length On success, the number of bytes that + * make up the returned shared secret. + * \retval #PSA_SUCCESS + * Success. Shared secret successfully calculated. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The input is invalid. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * \p shared_secret_size is too small. + */ +psa_status_t p256_transparent_key_agreement( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *peer_key, + size_t peer_key_length, + uint8_t *shared_secret, + size_t shared_secret_size, + size_t *shared_secret_length); + +/** Sign an already-calculated hash with a private key using p256-m's ECDSA + * implementation + * \param[in] attributes The attributes of the key to use for the + * operation. + * \param[in] key_buffer The buffer containing the private key + * in the format specified by PSA. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] alg A signature algorithm that is compatible + * with the type of the key. + * \param[in] hash The hash to sign. + * \param[in] hash_length Size of the \p hash buffer in bytes. + * \param[out] signature Buffer where signature is to be written. + * \param[in] signature_size Size of the \p signature buffer in bytes. + * \param[out] signature_length On success, the number of bytes + * that make up the returned signature value. + * + * \retval #PSA_SUCCESS + * Success. Hash was signed successfully. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The input is invalid. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * \p signature_size is too small. + * \retval #PSA_ERROR_GENERIC_ERROR + * The internal RNG failed. + */ +psa_status_t p256_transparent_sign_hash( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *hash, + size_t hash_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length); + +/** Verify the signature of a hash using a SECP256R1 public key using p256-m's + * ECDSA implementation. + * + * \note p256-m expects a 64 byte public key, but the contents of the key + buffer may be the 32 byte keypair representation or the 65 byte + public key representation. As a result, this function calls + psa_driver_wrapper_export_public_key() to ensure the public key + can be passed to p256-m. + * + * \param[in] attributes The attributes of the key to use for the + * operation. + * + * \param[in] key_buffer The buffer containing the key + * in the format specified by PSA. + * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. + * \param[in] alg A signature algorithm that is compatible with + * the type of the key. + * \param[in] hash The hash whose signature is to be + * verified. + * \param[in] hash_length Size of the \p hash buffer in bytes. + * \param[in] signature Buffer containing the signature to verify. + * \param[in] signature_length Size of the \p signature buffer in bytes. + * + * \retval #PSA_SUCCESS + * The signature is valid. + * \retval #PSA_ERROR_INVALID_SIGNATURE + * The calculation was performed successfully, but the passed + * signature is not a valid signature. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The input is invalid. + */ +psa_status_t p256_transparent_verify_hash( + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + psa_algorithm_t alg, + const uint8_t *hash, + size_t hash_length, + const uint8_t *signature, + size_t signature_length); + +#endif /* TF_PSA_CRYPTO_P256_M_DRIVER_ENTRYPOINTS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/CMakeLists.txt b/tf-psa-crypto/drivers/pqcp/CMakeLists.txt new file mode 100644 index 0000000000..ab531a942b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/CMakeLists.txt @@ -0,0 +1,14 @@ +set(tf_psa_crypto_driver "pqcp") + +# Point the C compiler only to files under include and src, written by us. +# The actual code from mldsa-native is included through #include directives. +file(GLOB pqcp_src_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} src/*.c) + +include(${PROJECT_SOURCE_DIR}/drivers/driver.cmake) + +foreach (target IN LISTS target_libraries) + target_include_directories(${target} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + PRIVATE mldsa-native/mldsa + ) +endforeach(target) diff --git a/tf-psa-crypto/drivers/pqcp/Makefile.inc b/tf-psa-crypto/drivers/pqcp/Makefile.inc new file mode 100644 index 0000000000..e7a5b2017e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/Makefile.inc @@ -0,0 +1,6 @@ +THIRDPARTY_INCLUDES += -I$(THIRDPARTY_DIR)/pqcp/include +THIRDPARTY_PRIVATE_INCLUDES += -I$(THIRDPARTY_DIR)/pqcp/src +THIRDPARTY_PRIVATE_INCLUDES += -I$(THIRDPARTY_DIR)/pqcp/mldsa-native/mldsa + +THIRDPARTY_CRYPTO_OBJECTS += $(patsubst %.c,%.o,$(wildcard $(THIRDPARTY_DIR)/pqcp/src/*.c)) + diff --git a/tf-psa-crypto/drivers/pqcp/include/tf-psa-crypto/private/crypto_struct_pqcp.h b/tf-psa-crypto/drivers/pqcp/include/tf-psa-crypto/private/crypto_struct_pqcp.h new file mode 100644 index 0000000000..ddd9666d5e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/include/tf-psa-crypto/private/crypto_struct_pqcp.h @@ -0,0 +1,25 @@ +/** + * \file crypto_struct_pqcp.h + * + * \brief Context structure declarations of the PSA driver that wraps around + * mldsa-native. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef TF_PSA_CRYPTO_PRIVATE_CRYPTO_STRUCT_PQCP_H +#define TF_PSA_CRYPTO_PRIVATE_CRYPTO_STRUCT_PQCP_H + +#include "mbedtls/private_access.h" + +#include + +#if defined(TF_PSA_CRYPTO_PQCP_MLDSA_ENABLED) + +/* No context structures yet. */ + +#endif /* TF_PSA_CRYPTO_PQCP_MLDSA_ENABLED */ + +#endif /* TF_PSA_CRYPTO_PRIVATE_CRYPTO_STRUCT_PQCP_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.clang-format b/tf-psa-crypto/drivers/pqcp/mldsa-native/.clang-format new file mode 100644 index 0000000000..6ebaa3b5a2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.clang-format @@ -0,0 +1,29 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +# +# clang-format style file for mldsa-native +# +BasedOnStyle: Google +MaxEmptyLinesToKeep: 3 +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +DerivePointerAlignment: false +PointerAlignment: Right +# TODO(davidben): The default for Google style is now Regroup, but the default +# IncludeCategories does not recognize . We should +# reconfigure IncludeCategories to match. For now, keep it at Preserve. +IncludeBlocks: Preserve + +# Designate CBMC contracts/macros that appear in .h files +# as "attributes" so they don't get increasingly indented line after line +BreakBeforeBraces: Allman +InsertBraces: true +IndentExternBlock: NoIndent +WhitespaceSensitiveMacros: ['__contract__', '__loop__' ] +Macros: + # Make this artifically long to avoid function bodies after short contracts + - __contract__(x)={ void a; void b; void c; void d; void e; void f; } void abcdefghijklmnopqrstuvw() + - __loop__(x)={} do + # Make this artifically long to force line break + - MLD_INTERNAL_API=void abcdefghijklmnopqrstuvwabcdefghijklmnopqrstuvwabcdefg(); diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.envrc b/tf-psa-crypto/drivers/pqcp/mldsa-native/.envrc new file mode 100644 index 0000000000..1b6e22afcd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.envrc @@ -0,0 +1,8 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +if ! has nix_direnv_version || ! nix_direnv_version 3.0.3; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.3/direnvrc" "sha256-0EVQVNSRQWsln+rgPW3mXVmnF5sfcmKEYOmOSfLYxHg=" +fi + +use flake diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/ISSUE_TEMPLATE/config.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..bc1fdc85ef --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,14 @@ +blank_issues_enabled: false +contact_links: + - name: Mbed TLS & TF-PSA-Crypto security team + url: mailto:mbed-tls-security@lists.trustedfirmware.org + about: Report a security vulnerability in TF-PSA-Crypto. + - name: PQ Code Package security contact + url: https://github.com/pq-code-package/mldsa-native/security + about: Report a security vulnerability in the upstream mldsa-native. + - name: TF-PSA-Crypto issue tracker + url: https://github.com/Mbed-TLS/TF-PSA-Crypto/issues + about: Bugs and feature requests in TF-PSA-Crypto + - name: PSA Crypto mailing list + url: https://lists.trustedfirmware.org/mailman3/lists/psa-crypto.lists.trustedfirmware.org/ + about: PSA Crypto community support and general discussion. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/bench/action.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/bench/action.yml new file mode 100644 index 0000000000..aea4980542 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/bench/action.yml @@ -0,0 +1,114 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Bench mldsa-native +description: Run benchmarking script + +inputs: + name: + description: Name for the benchmarking run + required: true + perf: + description: Method of obtaining PMU metrics + required: true + default: "PERF" + cflags: + description: CFLAGS to pass to compilation + default: "" + archflags: + description: ARCHFLAGS to pass to compilation + default: "" + ldflags: + description: LDFLAGS to pass to compilation + default: "" + opt: + description: opt flag to set for tests script + default: "true" + bench_extra_args: + description: Further arguments to be appended to command line for `bench` script + default: "" + store_results: + description: Whether to push results to GH pages + default: "false" + gh_token: + description: GitHub access token + required: true + nix-shell: + description: Run in the specified Nix environment if exists + default: "ci-bench" + nix-cache: + description: Determine whether to enable nix cache + default: 'false' + nix-verbose: + description: Determine wether to suppress nix log or not + default: 'false' + custom_shell: + description: The shell to use. Only relevant if no nix-shell specified + default: "bash" + cross_prefix: + description: "Binary prefix for cross-compilation builds" + default: "" + alert_threshold: + description: "Set alert threshold in percentage for benchmark result" + default: "103%" +runs: + using: composite + steps: + - uses: ./.github/actions/setup-shell + with: + nix-shell: ${{ inputs.nix-shell }} + nix-cache: ${{ inputs.nix-cache }} + nix-verbose: ${{ inputs.nix-verbose }} + gh_token: ${{ inputs.gh_token }} + custom_shell: ${{ inputs.custom_shell }} + script: | + ARCH=$(uname -m) + cat >> $GITHUB_STEP_SUMMARY <<-EOF + ## Setup + Architecture: $ARCH + - $(uname -a) + - $(nix --version) + - $(${{ matrix.target.cross_prefix }}gcc --version | grep -m1 "") + - $(bash --version | grep -m1 "") + + ## CPU Info + $(cat /proc/cpuinfo) + EOF + - name: Run benchmark + shell: ${{ env.SHELL }} + run: | + ./scripts/tests bench -c ${{ inputs.perf }} --cross-prefix="${{ inputs.cross_prefix }}" \ + --cflags="${{ inputs.cflags }} ${{ inputs.archflags }}" \ + --ldflags="${{ inputs.ldflags }}" \ + --opt=$([[ ${{ inputs.opt }} == "false" ]] && echo "no_opt" || echo "opt") \ + -v --output=output.json ${{ inputs.bench_extra_args }} + + ./scripts/tests bench --components -c ${{ inputs.perf }} --cross-prefix="${{ inputs.cross_prefix }}" \ + --cflags="${{ inputs.cflags }} ${{ inputs.archflags }}" \ + --ldflags="${{ inputs.ldflags }}" \ + --opt=$([[ ${{ inputs.opt }} == "false" ]] && echo "no_opt" || echo "opt") \ + -v ${{ inputs.bench_extra_args }} + - name: Check namespace + shell: ${{ env.SHELL }} + run: | + check-namespace + - name: Store benchmark result + uses: benchmark-action/github-action-benchmark@d48d326b4ca9ba73ca0cd0d59f108f9e02a381c7 # v1.20.4 + with: + name: ${{ inputs.name }} + tool: "customSmallerIsBetter" + output-file-path: output.json + github-token: ${{ inputs.gh_token }} + auto-push: ${{ inputs.store_results == 'true' }} + comment-on-alert: true + summary-always: true + alert-threshold: ${{ inputs.alert_threshold }} + comment-always: true + - name: Reset gh-pages if result is not pushed to gh-pages + shell: ${{ env.SHELL }} + if: ${{ inputs.store_results != 'true' }} + run: | + git -c advice.detachedHead=false switch gh-pages + git reset --hard HEAD~1 + git checkout - diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/cbmc/action.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/cbmc/action.yml new file mode 100644 index 0000000000..e75feda2f5 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/cbmc/action.yml @@ -0,0 +1,68 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: CBMC +description: Run CBMC proofs for mldsa-native + +inputs: + nix-shell: + description: Run in the specified Nix environment if exists + default: "ci-cbmc" + nix-cache: + description: Determine whether to enable nix cache + default: 'true' + nix-verbose: + description: Determine wether to suppress nix log or not + default: 'false' + custom_shell: + description: The shell to use. Only relevant if use-nix is 'false' + default: "bash" + mldsa_parameter_set: + description: "Security level for ML-DSA (2,3,5)" + default: "2" + gh_token: + description: Github access token to use + required: true +runs: + using: composite + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: ./.github/actions/setup-shell + with: + nix-shell: ${{ inputs.nix-shell }} + nix-cache: ${{ inputs.nix-cache }} + nix-verbose: ${{ inputs.nix-verbose }} + gh_token: ${{ inputs.gh_token }} + custom_shell: ${{ inputs.custom_shell }} + script: | + + if [[ ${{ inputs.nix-shell }} != '' ]]; then + nix-collect-garbage + fi + + cat >> $GITHUB_STEP_SUMMARY << EOF + ## Setup + Architecture: $(uname -m) + - $(nix --version) + - $(cbmc --version) + - litani Version $(litani --version) + - Cadical Version $(cadical --version) + - $(bash --version | grep -m1 "") + EOF + - name: Run CBMC proofs (MLD_CONFIG_PARAMETER_SET=${{ inputs.mldsa_parameter_set }}) + shell: ${{ env.SHELL }} + env: + GH_TOKEN: ${{ inputs.gh_token }} + run: | + echo "::group::cbmc_${{ inputs.mldsa_parameter_set }}" + tests cbmc --mldsa-parameter-set ${{ inputs.mldsa_parameter_set }} --per-proof-timeout 1800 --output-result-json ${{ github.workspace }}/cbmc_result_${{ inputs.mldsa_parameter_set }}.json || cbmc_failed=true + echo "::endgroup::" + python3 ${{ github.action_path }}/report.py \ + --results-json "${{ github.workspace }}/cbmc_result_${{ inputs.mldsa_parameter_set }}.json" \ + --mldsa-parameter-set "${{ inputs.mldsa_parameter_set }}" \ + --min-runtime 20 \ + --regression-threshold 1.5 \ + --gh-pages-branch gh-pages \ + --data-dir dev/cbmc + if [ "$cbmc_failed" = "true" ]; then exit 1; fi diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/cbmc/report.py b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/cbmc/report.py new file mode 100644 index 0000000000..d8204c4736 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/cbmc/report.py @@ -0,0 +1,297 @@ +#!/usr/bin/env python3 +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +"""CBMC proof results reporter for GitHub Actions.""" + +import argparse +import base64 +import json +import os +import subprocess +import tempfile +from collections import namedtuple + +# GitHub context +GITHUB_REPOSITORY = os.environ.get("GITHUB_REPOSITORY", "") +GITHUB_REF = os.environ.get("GITHUB_REF", "") +GITHUB_SHA = os.environ.get("GITHUB_SHA", "")[:7] + +COMMENT_TAG = "cbmc-report" + +# Status symbols +OK = "✅" +WARN = "⚠️" +FAIL = "❌" + +ProofResult = namedtuple( + "ProofResult", ["name", "status", "current", "previous", "change"] +) + + +def get_args(): + parser = argparse.ArgumentParser(description="CBMC proof results reporter") + parser.add_argument("--results-json", required=True) + parser.add_argument( + "--mldsa-parameter-set", required=True, choices=["44", "65", "87"] + ) + parser.add_argument("--min-runtime", type=int, default=20) + parser.add_argument("--regression-threshold", type=float, default=1.5) + parser.add_argument("--gh-pages-branch", default="gh-pages") + parser.add_argument("--data-dir", default="dev/cbmc") + return parser.parse_args() + + +def get_pr_number(): + """Get PR number from GitHub event.""" + event_path = os.environ.get("GITHUB_EVENT_PATH") + if not event_path or not os.path.exists(event_path): + return None + with open(event_path) as f: + event = json.load(f) + return event.get("pull_request", {}).get("number") + + +def fetch_baseline(cfg): + """Fetch baseline data from gh-pages branch.""" + baseline_file = f"{cfg.data_dir}/mldsa-{cfg.param_set}.json" + subprocess.run( + ["git", "fetch", "origin", cfg.gh_pages_branch, "--depth=1"], + capture_output=True, + ) + result = subprocess.run( + ["git", "show", f"origin/{cfg.gh_pages_branch}:{baseline_file}"], + capture_output=True, + text=True, + ) + if result.returncode == 0 and result.stdout.strip(): + return json.loads(result.stdout) + return None + + +def render_table(rows): + """Render a markdown table from ProofResult rows.""" + lines = [ + "| Proof | Status | Current | Previous | Change |", + "|-------|--------|---------|----------|--------|", + ] + lines.extend( + f"| `{r.name}` | {r.status} | {r.current} | {r.previous} | {r.change} |" + for r in rows + ) + return lines + + +def classify_proof(r, baseline_runtimes, cfg): + """Classify a single proof result, returning (ProofResult, is_alert).""" + name = r["name"] + base = baseline_runtimes.get(name, {}) + base_val, base_failed = base.get("value"), base.get("status") == "failed" + + if r.get("status") == "failed": + prev = "failed" if base_failed else (f"{base_val}s" if base_val else "-") + return ProofResult(name, FAIL, "-", prev, "-"), True + + cur_val = r["value"] + if base_failed: + return ProofResult(name, OK, f"{cur_val}s", "failed", "fixed"), False + if base_val is None: + return ProofResult(name, OK, f"{cur_val}s", "-", "new"), False + + ratio = cur_val / base_val if base_val > 0 else 1 + change = f"{(ratio - 1) * 100:+.0f}%" if base_val > 0 else "-" + is_regression = cur_val >= cfg.min_runtime and ratio >= cfg.regression_threshold + status = WARN if is_regression else OK + return ( + ProofResult(name, status, f"{cur_val}s", f"{base_val}s", change), + is_regression, + ) + + +def compute_total_runtime(data): + """Compute total runtime from proof results.""" + if not data: + return None + return sum( + r["value"] for r in data.get("runtimes", []) if r.get("status") != "failed" + ) + + +def build_comment(current, baseline, cfg): + """Build the PR comment markdown.""" + baseline_runtimes = {r["name"]: r for r in (baseline or {}).get("runtimes", [])} + alerts, all_rows = [], [] + + for r in current.get("runtimes", []): + result, is_alert = classify_proof(r, baseline_runtimes, cfg) + all_rows.append(result) + if is_alert: + alerts.append(result) + + def sort_key(r): + return -1 if r.current == "-" else -int(r.current.rstrip("s")) + + all_rows.sort(key=sort_key) + + # Compute total runtimes and add as first row + cur_total = compute_total_runtime(current) + base_total = compute_total_runtime(baseline) + if base_total and base_total > 0: + total_ratio = cur_total / base_total + total_change = f"{(total_ratio - 1) * 100:+.1f}%" + total_status = WARN if total_ratio >= 1.25 else OK + else: + total_change = "-" + total_status = OK + total_row = ProofResult( + "**TOTAL**", + total_status, + f"{cur_total}s", + f"{base_total}s" if base_total else "-", + total_change, + ) + all_rows.insert(0, total_row) + if total_status == WARN: + alerts.insert(0, total_row) + + lines = [ + f"", + f"## CBMC Results (ML-DSA-{cfg.param_set})", + "", + ] + + if alerts: + lines += [f"{WARN} **Attention Required**", ""] + render_table(alerts) + [""] + + total = current.get("summary", {}).get("total", len(all_rows)) + lines += ( + [ + "
", + f"Full Results ({total} proofs)", + "", + ] + + render_table(all_rows) + + [ + "", + "
", + "", + f"", + ] + ) + return "\n".join(lines) + + +def post_or_update_comment(pr_number, body, cfg): + """Post or update PR comment.""" + tag = f"" + result = subprocess.run( + [ + "gh", + "api", + f"repos/{GITHUB_REPOSITORY}/issues/{pr_number}/comments", + "--jq", + f'.[] | select(.body | startswith("{tag}")) | .id', + ], + capture_output=True, + text=True, + ) + existing_id = ( + result.stdout.strip().split("\n")[0] + if result.returncode == 0 and result.stdout.strip() + else None + ) + + with tempfile.NamedTemporaryFile(mode="w", suffix=".md", delete=False) as f: + f.write(body) + tmp_path = f.name + + try: + if existing_id: + subprocess.run( + [ + "gh", + "api", + f"repos/{GITHUB_REPOSITORY}/issues/comments/{existing_id}", + "-X", + "PATCH", + "-F", + f"body=@{tmp_path}", + ], + check=True, + ) + print(f"Updated existing comment {existing_id}") + else: + subprocess.run( + [ + "gh", + "api", + f"repos/{GITHUB_REPOSITORY}/issues/{pr_number}/comments", + "-X", + "POST", + "-F", + f"body=@{tmp_path}", + ], + check=True, + ) + print("Created new comment") + finally: + os.unlink(tmp_path) + + +def push_to_gh_pages(current, cfg): + """Push results to gh-pages branch using GitHub Contents API.""" + file_path = f"{cfg.data_dir}/mldsa-{cfg.param_set}.json" + content_b64 = base64.b64encode(json.dumps(current, indent=2).encode()).decode() + + result = subprocess.run( + [ + "gh", + "api", + f"repos/{GITHUB_REPOSITORY}/contents/{file_path}?ref={cfg.gh_pages_branch}", + "--jq", + ".sha", + ], + capture_output=True, + text=True, + ) + sha = result.stdout.strip() if result.returncode == 0 else "" + + cmd = [ + "gh", + "api", + f"repos/{GITHUB_REPOSITORY}/contents/{file_path}", + "-X", + "PUT", + "-F", + f"message=Update CBMC results for ML-DSA-{cfg.param_set} ({GITHUB_SHA})", + "-F", + f"content={content_b64}", + "-F", + f"branch={cfg.gh_pages_branch}", + ] + if sha: + cmd.extend(["-F", f"sha={sha}"]) + + subprocess.run(cmd, check=True) + print(f"Pushed results to {cfg.gh_pages_branch}") + + +def main(): + args = get_args() + args.param_set = args.mldsa_parameter_set + + with open(args.results_json) as f: + current = json.load(f) + baseline = fetch_baseline(args) + + pr_number = get_pr_number() + if pr_number: + post_or_update_comment(pr_number, build_comment(current, baseline, args), args) + elif GITHUB_REF in ("refs/heads/main", "refs/heads/master"): + push_to_gh_pages(current, args) + else: + print(f"Not a PR and not main branch ({GITHUB_REF}), skipping") + + +if __name__ == "__main__": + main() diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/config-variations/action.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/config-variations/action.yml new file mode 100644 index 0000000000..7d4c2f0f02 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/config-variations/action.yml @@ -0,0 +1,304 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: 'Custom config tests' +description: 'Build and test mldsa-native with various custom configs' +inputs: + gh_token: + description: 'GitHub token' + required: true + tests: + description: 'List of tests to run (space-separated IDs) or "all" for all tests. Available IDs: pct-enabled, pct-enabled-broken, reduce-ram, reduce-ram-pct, custom-alloc-heap, custom-zeroize, native-cap-ON, native-cap-OFF, native-cap-ID_AA64PFR1_EL1, native-cap-CPUID_AVX2, no-asm, serial-fips202, custom-randombytes, custom-memcpy, custom-memset, custom-stdlib, nblocks-1, nblocks-4, nblocks-6' + required: false + default: 'all' + opt: + description: 'Optimization level to pass to multi-functest' + required: false + default: 'all' +runs: + using: 'composite' + steps: + - name: "PCT enabled" + if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'pct-enabled') }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-DMLD_CONFIG_KEYGEN_PCT -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + opt: ${{ inputs.opt }} + examples: true + extra_args: "--exclude-example basic_deterministic" + - name: "REDUCE_RAM" + if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'reduce-ram') }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-DMLD_CONFIG_REDUCE_RAM -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + alloc: true + opt: ${{ inputs.opt }} + examples: true + - name: "REDUCE_RAM + PCT" + if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'reduce-ram-pct') }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-DMLD_CONFIG_REDUCE_RAM -DMLD_CONFIG_KEYGEN_PCT -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + alloc: true + opt: ${{ inputs.opt }} + examples: true + extra_args: "--exclude-example basic_deterministic" + - name: "PCT enabled + broken" + if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'pct-enabled-broken') }} + shell: bash + run: | + make clean + CFLAGS='-Itest -DMLD_CONFIG_FILE=\"configs/break_pct_config.h\"' make func -j4 + # PCT breakage is done at runtime via MLD_BREAK_PCT + make run_func # Should be OK + MLD_BREAK_PCT=0 make run_func # Should be OK + if (MLD_BREAK_PCT=1 make run_func 2>&1 >/dev/null); then + echo "PCT failure expected" + exit 1 + else + echo "PCT failed as expected" + fi + - name: "Custom allocation (heap based)" + if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'custom-alloc-heap') }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-std=c11 -D_GNU_SOURCE -Itest -DMLD_CONFIG_FILE=\\\\\\\"configs/custom_heap_alloc_config.h\\\\\\\" -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + opt: ${{ inputs.opt }} + extra_env: 'ASAN_OPTIONS=detect_leaks=1' + examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config + rng_fail: false # Requires custom config + - name: "Custom zeroization (explicit_bzero)" + if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'custom-zeroize') }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-std=c11 -D_GNU_SOURCE -Itest -DMLD_CONFIG_FILE=\\\\\\\"configs/custom_zeroize_config.h\\\\\\\" -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + opt: ${{ inputs.opt }} + examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config + rng_fail: false # Requires custom config + - name: "Custom native capability functions (static ON)" + if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'native-cap-ON') }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-std=c11 -D_GNU_SOURCE -Itest -DMLD_CONFIG_FILE=\\\\\\\"configs/custom_native_capability_config_1.h\\\\\\\" -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + opt: ${{ inputs.opt }} + examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config + rng_fail: false # Requires custom config + - name: "Custom native capability functions (static OFF)" + if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'native-cap-OFF') }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-std=c11 -D_GNU_SOURCE -Itest -DMLD_CONFIG_FILE=\\\\\\\"configs/custom_native_capability_config_0.h\\\\\\\" -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + opt: ${{ inputs.opt }} + examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config + rng_fail: false # Requires custom config + - name: "Custom native capability functions (ID_AA64PFR1_EL1 detection)" + if: ${{ (inputs.tests == 'all' || contains(inputs.tests, 'native-cap-ID_AA64PFR1_EL1')) && runner.os == 'Linux' && runner.arch == 'ARM64' }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-std=c11 -march=armv8.4-a+sha3 -D_GNU_SOURCE -Itest -DMLD_CONFIG_FILE=\\\\\\\"configs/custom_native_capability_config_ID_AA64PFR1_EL1.h\\\\\\\" -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + opt: ${{ inputs.opt }} + examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config + rng_fail: false # Requires custom config + - name: "Custom native capability functions (CPUID AVX2 detection)" + if: ${{ (inputs.tests == 'all' || contains(inputs.tests, 'native-cap-CPUID_AVX2')) && runner.os == 'Linux' && runner.arch == 'X64' }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-std=c11 -mavx2 -mbmi2 -mpopcnt -D_GNU_SOURCE -Itest -DMLD_CONFIG_FILE=\\\\\\\"configs/custom_native_capability_config_CPUID_AVX2.h\\\\\\\" -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + opt: ${{ inputs.opt }} + examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config + rng_fail: false # Requires custom config + - name: "No ASM" + if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'no-asm') }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-std=c11 -D_GNU_SOURCE -Itest -DMLD_CONFIG_FILE=\\\\\\\"configs/no_asm_config.h\\\\\\\" -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + opt: ${{ inputs.opt }} + examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config + rng_fail: false # Requires custom config + - name: "Serial FIPS202 (no batched Keccak)" + if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'serial-fips202') }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-std=c11 -D_GNU_SOURCE -Itest -DMLD_CONFIG_FILE=\\\\\\\"configs/serial_fips202_config.h\\\\\\\" -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + opt: ${{ inputs.opt }} + examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config + rng_fail: false # Requires custom config + - name: "Custom randombytes" + if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'custom-randombytes') }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-std=c11 -D_GNU_SOURCE -Itest -DMLD_CONFIG_FILE=\\\\\\\"configs/custom_randombytes_config.h\\\\\\\" -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + opt: ${{ inputs.opt }} + examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config + rng_fail: false # Requires custom config + - name: "Custom memcpy" + if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'custom-memcpy') }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-std=c11 -D_GNU_SOURCE -Itest -DMLD_CONFIG_FILE=\\\\\\\"configs/custom_memcpy_config.h\\\\\\\" -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + opt: ${{ inputs.opt }} + examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config + rng_fail: false # Requires custom config + - name: "Custom memset" + if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'custom-memset') }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-std=c11 -D_GNU_SOURCE -Itest -DMLD_CONFIG_FILE=\\\\\\\"configs/custom_memset_config.h\\\\\\\" -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + opt: ${{ inputs.opt }} + examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config + rng_fail: false # Requires custom config + - name: "Custom stdlib (memcpy + memset)" + if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'custom-stdlib') }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-std=c11 -D_GNU_SOURCE -Itest -DMLD_CONFIG_FILE=\\\\\\\"configs/custom_stdlib_config.h\\\\\\\" -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + opt: ${{ inputs.opt }} + examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config + rng_fail: false # Requires custom config + - name: "MLD_POLY_UNIFORM_NBLOCKS=1" + if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'nblocks-1') }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -DMLD_POLY_UNIFORM_NBLOCKS=1" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + opt: ${{ inputs.opt }} + examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config + rng_fail: false # Requires custom config + - name: "MLD_POLY_UNIFORM_NBLOCKS=4" + if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'nblocks-4') }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -DMLD_POLY_UNIFORM_NBLOCKS=4" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + opt: ${{ inputs.opt }} + examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config + rng_fail: false # Requires custom config + - name: "MLD_POLY_UNIFORM_NBLOCKS=6" + if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'nblocks-6') }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ inputs.gh_token }} + compile_mode: native + cflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -DMLD_POLY_UNIFORM_NBLOCKS=6" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + func: true + kat: true + acvp: true + opt: ${{ inputs.opt }} + examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config + rng_fail: false # Requires custom config diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/ct-test/action.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/ct-test/action.yml new file mode 100644 index 0000000000..7ba812406e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/ct-test/action.yml @@ -0,0 +1,50 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: CT Test +description: Builds the library with given flags and runs Valgrind-based constant-time tests + +inputs: + cflags: + description: CFLAGS to pass to compilation + default: "" + valgrind_flags: + description: Extra flags to pass to valgrind + default: "" + +runs: + using: composite + steps: + - name: System info + shell: ${{ env.SHELL }} + run: | + ARCH=$(uname -m) + echo <<-EOF + ## Setup + Architecture: $ARCH + - $(uname -a) + - $(nix --version || echo 'nix not present') + - $(bash --version | grep -m1 "") + - $(python3 --version) + - $(${{ inputs.cross_prefix }}${CC} --version | grep -m1 "") + EOF + cat >> $GITHUB_STEP_SUMMARY <<-EOF + ## Setup + Architecture: $ARCH + - $(uname -a) + - $(nix --version || echo 'nix not present') + - $(bash --version | grep -m1 "") + - $(python3 --version) + - $(${{ inputs.cross_prefix }}${CC} --version | grep -m1 "") + EOF + - shell: ${{ env.SHELL }} + run: | + make clean + # --vex-guest-max-insns=55 (default is 60) is a workaround for + # "VEX temporary storage exhausted" errors in the x86 backend (poly_chknorm) + # It may increase run-time of the valgrind tests. + # TODO: Check with future versions of valgrind if this is still needed (both 3.24 and 3.25 fail without) + # TODO: Check if this is still needed once the poly_chknorm intrinsics implementation is replaced by assembly + # Disable the AArch64 SHA3 extension as it's not yet supported by valgrind + MK_COMPILER_SUPPORTS_SHA3=0 tests func --exec-wrapper="valgrind --vex-guest-max-insns=55 --error-exitcode=1 ${{ inputs.valgrind_flags }}" --cflags="-DMLD_CONFIG_CT_TESTING_ENABLED -DNTESTS=5 ${{ inputs.cflags }}" diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/functest/action.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/functest/action.yml new file mode 100644 index 0000000000..65013abba2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/functest/action.yml @@ -0,0 +1,127 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Functional tests +description: Run functional tests + +inputs: + nix-shell: + description: Run in the specified Nix environment if exists + default: "ci" + nix-cache: + description: Determine whether to enable nix cache + default: 'false' + nix-verbose: + description: Determine wether to suppress nix log or not + default: 'false' + custom_shell: + description: The shell to use. Only relevant if no nix-shell specified + default: "bash" + gh_token: + description: Github access token to use + required: true + cflags: + description: CFLAGS to pass to compilation + default: "" + ldflags: + description: LDFLAGS to pass to linking + default: "" + cross_prefix: + description: Binary prefix for cross compilation + default: "" + exec_wrapper: + description: Binary wrapper for execution (e.g. QEMU) + default: "" + opt: + description: Whether to build opt/non-opt binaries or all (all | opt | no_opt) + default: "all" + func: + description: Determine whether to run functional test or not + default: "true" + kat: + description: Determine whether to run kat test or not + default: "true" + acvp: + description: Determine whether to run acvp test or not + default: "true" + examples: + description: Determine whether to run examples or not + default: "true" + unit: + description: Determine whether to run unit tests or not + default: "true" + check_namespace: + description: Determine whether to check namespacing or not + default: "true" + stack: + description: Determine whether to run stack analysis or not + default: "false" + alloc: + description: Determine whether to run alloc tests or not + default: "true" + rng_fail: + description: Determine whether to run rng fail tests or not + default: "true" + extra_args: + description: Additional arguments to pass to the tests script + default: "" + extra_env: + description: Additional environment variables to set when calling the tests script + default: "" +runs: + using: composite + steps: + - name: Preprocess + shell: bash + run: | + arch=$(uname -m) + echo MODE="${{ inputs.cross_prefix == '' && 'native' || 'cross' }}" >> $GITHUB_ENV + echo FUNC="${{ inputs.func == 'true' && 'func' || 'no-func' }}" >> $GITHUB_ENV + echo KAT="${{ inputs.kat == 'true' && 'kat' || 'no-kat' }}" >> $GITHUB_ENV + echo UNIT="${{ inputs.unit == 'true' && 'unit' || 'no-unit' }}" >> $GITHUB_ENV + echo ACVP="${{ inputs.acvp == 'true' && 'acvp' || 'no-acvp' }}" >> $GITHUB_ENV + echo EXAMPLES="${{ inputs.examples == 'true' && 'examples' || 'no-examples' }}" >> $GITHUB_ENV + echo STACK="${{ inputs.stack == 'true' && 'stack' || 'no-stack' }}" >> $GITHUB_ENV + echo ALLOC="${{ inputs.alloc == 'true' && 'alloc' || 'no-alloc' }}" >> $GITHUB_ENV + echo RNGFAIL="${{ inputs.rng_fail == 'true' && 'rng-fail' || 'no-rng-fail' }}" >> $GITHUB_ENV + - name: Setup nix + uses: ./.github/actions/setup-shell + with: + nix-shell: ${{ inputs.nix-shell }} + nix-cache: ${{ inputs.nix-cache }} + nix-verbose: ${{ inputs.nix-verbose }} + gh_token: ${{ inputs.gh_token }} + custom_shell: ${{ inputs.custom_shell }} + - name: System info + shell: ${{ env.SHELL }} + run: | + ARCH=$(uname -m) + echo <<-EOF + ## Setup + Architecture: $ARCH + - $(uname -a) + - $(nix --version || echo 'nix not present') + - $(bash --version | grep -m1 "") + - $(python3 --version) + - $(${{ inputs.cross_prefix }}${CC} --version | grep -m1 "") + EOF + cat >> $GITHUB_STEP_SUMMARY <<-EOF + ## Setup + Architecture: $ARCH + - $(uname -a) + - $(nix --version || echo 'nix not present') + - $(bash --version | grep -m1 "") + - $(python3 --version) + - $(${{ inputs.cross_prefix }}${CC} --version | grep -m1 "") + EOF + - name: ${{ env.MODE }} ${{ inputs.opt }} tests (${{ env.FUNC }}, ${{ env.KAT }}, ${{ env.EXAMPLES }}, ${{ env.STACK }}, ${{ env.UNIT }}, ${{ env.ALLOC }}, ${{ env.RNGFAIL }}) + shell: ${{ env.SHELL }} + run: | + make clean + ${{ inputs.extra_env }} ./scripts/tests all ${{ inputs.check_namespace == 'true' && '--check-namespace' || ''}} --exec-wrapper="${{ inputs.exec_wrapper }}" --cross-prefix="${{ inputs.cross_prefix }}" --cflags="${{ inputs.cflags }}" --ldflags="${{ inputs.ldflags }}" --opt=${{ inputs.opt }} --${{ env.FUNC }} --${{ env.KAT }} --${{ env.ACVP }} --${{ env.EXAMPLES }} --${{ env.STACK }} --${{ env.UNIT }} --${{ env.ALLOC }} --${{ env.RNGFAIL }} -v ${{ inputs.extra_args }} + - name: Post ${{ env.MODE }} Tests + shell: ${{ env.SHELL }} + if: success() || failure() + run: | + make clean diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/lint/action.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/lint/action.yml new file mode 100644 index 0000000000..13b4f7406f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/lint/action.yml @@ -0,0 +1,51 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Lint +description: Lint + +inputs: + nix-shell: + description: Run in the specified Nix environment if exists + default: "ci-linter" + nix-cache: + description: Determine whether to enable nix cache + default: "false" + nix-verbose: + description: Determine wether to suppress nix log or not + default: 'false' + custom_shell: + description: The shell to use. Only relevant if no nix-shell specified + default: "bash" + cross-prefix: + description: Binary prefix for cross compilation + default: "" + gh_token: + description: Github access token to use + required: true +runs: + using: composite + steps: + - uses: ./.github/actions/setup-shell + with: + nix-shell: ${{ inputs.nix-shell }} + custom_shell: ${{ inputs.custom_shell }} + nix-cache: ${{ inputs.nix-cache }} + nix-verbose: ${{ inputs.nix-verbose }} + gh_token: ${{ inputs.gh_token }} + script: | + cat >> $GITHUB_STEP_SUMMARY << EOF + ## Setup + Architecture: $(uname -m) + - $(uname -a) + - $(nix --version) + - $(clang-format --version) + - $(${{ matrix.target.cross-prefix }}gcc --version | grep -m1 "") + - $(bash --version | grep -m1 "") + EOF + - name: Run linter + shell: ${{ env.SHELL }} + run: | + echo "## Lint & Checks" >> $GITHUB_STEP_SUMMARY + lint diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/multi-functest/action.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/multi-functest/action.yml new file mode 100644 index 0000000000..509c96e306 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/multi-functest/action.yml @@ -0,0 +1,317 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Multiple Functional tests +description: Run functional tests + +inputs: + nix-shell: + description: Run in the specified Nix environment if exists + default: "ci" + custom_shell: + description: The shell to use. Only relevant if no nix-shell specified + default: "bash" + nix-cache: + description: Determine whether to enable nix cache + default: 'false' + nix-verbose: + description: Determine wether to suppress nix log or not + default: 'false' + gh_token: + description: Github access token to use + required: true + cflags: + description: CFLAGS to pass to compilation + default: "" + ldflags: + description: LDFLAGS to pass to linking + default: "" + compile_mode: + description: all | native | cross-x86_64 | cross-aarch64 | cross-riscv64 | cross-riscv32 + default: "native" + opt: + description: all | opt | no_opt + default: "all" + func: + description: Determine whether to run functional test or not + default: "true" + kat: + description: Determine whether to run kat test or not + default: "true" + acvp: + description: Determine whether to run acvp test or not + default: "true" + examples: + description: Determine whether to run examples or not + default: "true" + unit: + description: Determine whether to run unit tests or not + default: "true" + check_namespace: + description: Determine whether to check namespacing or not + default: "true" + stack: + description: Determine whether to run stack analysis or not + default: "false" + alloc: + description: Determine whether to run alloc tests or not + default: "true" + rng_fail: + description: Determine whether to run rng fail tests or not + default: "true" + extra_args: + description: Additional arguments to pass to the tests script + default: "" + extra_env: + description: Additional environment variables to set when calling the tests script + default: "" +runs: + using: composite + steps: + - name: Native Tests + if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'native') }} + uses: ./.github/actions/functest + with: + nix-shell: ${{ inputs.nix-shell }} + nix-cache: ${{ inputs.nix-cache }} + nix-verbose: ${{ inputs.nix-verbose }} + gh_token: ${{ inputs.gh_token }} + custom_shell: ${{ inputs.custom_shell }} + cflags: ${{ inputs.cflags }} + ldflags: ${{ inputs.ldflags }} + opt: ${{ inputs.opt }} + func: ${{ inputs.func }} + kat: ${{ inputs.kat }} + unit: ${{ inputs.unit }} + acvp: ${{ inputs.acvp }} + examples: ${{ inputs.examples }} + check_namespace: ${{ inputs.check_namespace }} + stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} + rng_fail: ${{ inputs.rng_fail }} + extra_args: ${{ inputs.extra_args }} + extra_env: ${{ inputs.extra_env }} + - name: Cross x86_64 Tests + if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-x86_64') && (success() || failure()) }} + uses: ./.github/actions/functest + with: + nix-shell: ${{ inputs.nix-shell }} + nix-cache: ${{ inputs.nix-cache }} + nix-verbose: ${{ inputs.nix-verbose }} + gh_token: ${{ inputs.gh_token }} + custom_shell: ${{ inputs.custom_shell }} + cflags: "${{ inputs.cflags }} -DMLD_FORCE_X86_64" + ldflags: ${{ inputs.ldflags }} + cross_prefix: x86_64-unknown-linux-gnu- + exec_wrapper: qemu-x86_64 + opt: ${{ inputs.opt }} + func: ${{ inputs.func }} + kat: ${{ inputs.kat }} + unit: ${{ inputs.unit }} + acvp: ${{ inputs.acvp }} + examples: ${{ inputs.examples }} + check_namespace: ${{ inputs.check_namespace }} + stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} + rng_fail: ${{ inputs.rng_fail }} + extra_args: ${{ inputs.extra_args }} + extra_env: ${{ inputs.extra_env }} + - name: Cross aarch64 Tests + if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-aarch64') && (success() || failure()) }} + uses: ./.github/actions/functest + with: + nix-shell: ${{ inputs.nix-shell }} + nix-cache: ${{ inputs.nix-cache }} + nix-verbose: ${{ inputs.nix-verbose }} + gh_token: ${{ inputs.gh_token }} + custom_shell: ${{ inputs.custom_shell }} + cflags: "${{ inputs.cflags }} -DMLD_FORCE_AARCH64" + ldflags: ${{ inputs.ldflags }} + cross_prefix: aarch64-unknown-linux-gnu- + exec_wrapper: qemu-aarch64 + opt: ${{ inputs.opt }} + func: ${{ inputs.func }} + kat: ${{ inputs.kat }} + unit: ${{ inputs.unit }} + acvp: ${{ inputs.acvp }} + examples: ${{ inputs.examples }} + check_namespace: ${{ inputs.check_namespace }} + stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} + rng_fail: ${{ inputs.rng_fail }} + extra_args: ${{ inputs.extra_args }} + extra_env: ${{ inputs.extra_env }} + - name: Cross ppc64le Tests + if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-ppc64le') && (success() || failure()) }} + uses: ./.github/actions/functest + with: + nix-shell: ${{ inputs.nix-shell }} + nix-cache: ${{ inputs.nix-cache }} + nix-verbose: ${{ inputs.nix-verbose }} + gh_token: ${{ inputs.gh_token }} + custom_shell: ${{ inputs.custom_shell }} + cflags: "${{ inputs.cflags }} -DMLD_FORCE_PPC64LE" + ldflags: ${{ inputs.ldflags }} + cross_prefix: powerpc64le-unknown-linux-gnu- + exec_wrapper: qemu-ppc64le + opt: ${{ inputs.opt }} + func: ${{ inputs.func }} + kat: ${{ inputs.kat }} + unit: ${{ inputs.unit }} + acvp: ${{ inputs.acvp }} + examples: ${{ inputs.examples }} + check_namespace: ${{ inputs.check_namespace }} + stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} + rng_fail: ${{ inputs.rng_fail }} + extra_args: ${{ inputs.extra_args }} + extra_env: ${{ inputs.extra_env }} + - name: Cross aarch64_be Tests + if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-aarch64_be') && (success() || failure()) }} + uses: ./.github/actions/functest + with: + nix-shell: ${{ inputs.nix-shell }} + nix-cache: ${{ inputs.nix-cache }} + nix-verbose: ${{ inputs.nix-verbose }} + gh_token: ${{ inputs.gh_token }} + custom_shell: ${{ inputs.custom_shell }} + cflags: "${{ inputs.cflags }} -DMLD_FORCE_AARCH64_EB" + ldflags: "${{ inputs.ldflags }} -static" + cross_prefix: aarch64_be-none-linux-gnu- + exec_wrapper: qemu-aarch64_be + opt: ${{ inputs.opt }} + func: ${{ inputs.func }} + kat: ${{ inputs.kat }} + unit: ${{ inputs.unit }} + acvp: ${{ inputs.acvp }} + examples: ${{ inputs.examples }} + check_namespace: ${{ inputs.check_namespace }} + stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} + rng_fail: ${{ inputs.rng_fail }} + extra_args: ${{ inputs.extra_args }} + extra_env: ${{ inputs.extra_env }} + - name: Cross riscv64 Tests (RVV, VLEN=128) + if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-riscv64') && (success() || failure()) }} + uses: ./.github/actions/functest + with: + nix-shell: ${{ inputs.nix-shell }} + nix-cache: ${{ inputs.nix-cache }} + nix-verbose: ${{ inputs.nix-verbose }} + gh_token: ${{ inputs.gh_token }} + custom_shell: ${{ inputs.custom_shell }} + cflags: "${{ inputs.cflags }} -DMLD_FORCE_RISCV64" + ldflags: ${{ inputs.ldflags }} + cross_prefix: riscv64-unknown-linux-gnu- + exec_wrapper: "qemu-riscv64 -cpu rv64,v=true,vlen=128" + opt: ${{ inputs.opt }} + func: ${{ inputs.func }} + kat: ${{ inputs.kat }} + unit: ${{ inputs.unit }} + acvp: ${{ inputs.acvp }} + examples: ${{ inputs.examples }} + check_namespace: ${{ inputs.check_namespace }} + stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} + rng_fail: ${{ inputs.rng_fail }} + extra_args: ${{ inputs.extra_args }} + extra_env: ${{ inputs.extra_env }} + - name: Cross riscv64 Tests (RVV, VLEN=256) + if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-riscv64') && (success() || failure()) }} + uses: ./.github/actions/functest + with: + nix-shell: ${{ inputs.nix-shell }} + nix-cache: ${{ inputs.nix-cache }} + nix-verbose: ${{ inputs.nix-verbose }} + gh_token: ${{ inputs.gh_token }} + custom_shell: ${{ inputs.custom_shell }} + cflags: "${{ inputs.cflags }} -DMLD_FORCE_RISCV64" + cross_prefix: riscv64-unknown-linux-gnu- + exec_wrapper: "qemu-riscv64 -cpu rv64,v=true,vlen=256" + opt: ${{ inputs.opt }} + func: ${{ inputs.func }} + kat: ${{ inputs.kat }} + unit: ${{ inputs.unit }} + acvp: ${{ inputs.acvp }} + examples: ${{ inputs.examples }} + check_namespace: ${{ inputs.check_namespace }} + stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} + rng_fail: ${{ inputs.rng_fail }} + extra_args: ${{ inputs.extra_args }} + extra_env: ${{ inputs.extra_env }} + - name: Cross riscv64 Tests (RVV, VLEN=512) + if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-riscv64') && (success() || failure()) }} + uses: ./.github/actions/functest + with: + nix-shell: ${{ inputs.nix-shell }} + nix-cache: ${{ inputs.nix-cache }} + nix-verbose: ${{ inputs.nix-verbose }} + gh_token: ${{ inputs.gh_token }} + custom_shell: ${{ inputs.custom_shell }} + cflags: "${{ inputs.cflags }} -DMLD_FORCE_RISCV64" + cross_prefix: riscv64-unknown-linux-gnu- + exec_wrapper: "qemu-riscv64 -cpu rv64,v=true,vlen=512" + opt: ${{ inputs.opt }} + func: ${{ inputs.func }} + kat: ${{ inputs.kat }} + unit: ${{ inputs.unit }} + acvp: ${{ inputs.acvp }} + examples: ${{ inputs.examples }} + check_namespace: ${{ inputs.check_namespace }} + stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} + rng_fail: ${{ inputs.rng_fail }} + extra_args: ${{ inputs.extra_args }} + extra_env: ${{ inputs.extra_env }} + - name: Cross riscv64 Tests (RVV, VLEN=1024) + if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-riscv64') && (success() || failure()) }} + uses: ./.github/actions/functest + with: + nix-shell: ${{ inputs.nix-shell }} + nix-cache: ${{ inputs.nix-cache }} + nix-verbose: ${{ inputs.nix-verbose }} + gh_token: ${{ inputs.gh_token }} + custom_shell: ${{ inputs.custom_shell }} + cflags: "${{ inputs.cflags }} -DMLD_FORCE_RISCV64" + cross_prefix: riscv64-unknown-linux-gnu- + exec_wrapper: "qemu-riscv64 -cpu rv64,v=true,vlen=1024" + opt: ${{ inputs.opt }} + func: ${{ inputs.func }} + kat: ${{ inputs.kat }} + unit: ${{ inputs.unit }} + acvp: ${{ inputs.acvp }} + examples: ${{ inputs.examples }} + check_namespace: ${{ inputs.check_namespace }} + stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} + rng_fail: ${{ inputs.rng_fail }} + extra_args: ${{ inputs.extra_args }} + extra_env: ${{ inputs.extra_env }} + - name: Cross riscv32 Tests + if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-riscv32') && (success() || failure()) }} + uses: ./.github/actions/functest + with: + nix-shell: ${{ inputs.nix-shell }} + nix-cache: ${{ inputs.nix-cache }} + nix-verbose: ${{ inputs.nix-verbose }} + gh_token: ${{ inputs.gh_token }} + custom_shell: ${{ inputs.custom_shell }} + cflags: "${{ inputs.cflags }} -DMLD_FORCE_RISCV32" + ldflags: ${{ inputs.ldflags }} + cross_prefix: riscv32-unknown-linux-gnu- + exec_wrapper: qemu-riscv32 + opt: ${{ inputs.opt }} + func: ${{ inputs.func }} + kat: ${{ inputs.kat }} + unit: ${{ inputs.unit }} + acvp: ${{ inputs.acvp }} + examples: ${{ inputs.examples }} + check_namespace: ${{ inputs.check_namespace }} + stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} + rng_fail: ${{ inputs.rng_fail }} + extra_args: ${{ inputs.extra_args }} + extra_env: ${{ inputs.extra_env }} + diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-apt/action.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-apt/action.yml new file mode 100644 index 0000000000..572f608c24 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-apt/action.yml @@ -0,0 +1,32 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Dependencies (apt) +description: Install dependencies via apt + +inputs: + packages: + description: Space-separated list of additional packages to install + required: false + default: '' + sudo: + required: false + default: 'sudo' + +runs: + using: composite + steps: + - name: Update package repository + shell: bash + run: | + ${{ inputs.sudo }} apt-get update + - name: Install base packages + shell: bash + run: | + ${{ inputs.sudo }} apt-get install make gcc python3 -y + - name: Install additional packages + if: ${{ inputs.packages != ''}} + shell: bash + run: | + ${{ inputs.sudo }} apt-get install ${{ inputs.packages }} -y diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-brew/action.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-brew/action.yml new file mode 100644 index 0000000000..24c43f28d7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-brew/action.yml @@ -0,0 +1,32 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Dependencies (apt) +description: Install dependencies via brew + +inputs: + packages: + description: Space-separated list of additional packages to install + required: false + default: '' + sudo: + required: false + default: 'sudo' + +runs: + using: composite + steps: + - name: Update package repository + shell: bash + run: | + brew update + - name: Install base packages + shell: bash + run: | + brew install make + - name: Install additional packages + if: ${{ inputs.packages != ''}} + shell: bash + run: | + brew install ${{ inputs.packages }} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-nix/action.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-nix/action.yml new file mode 100644 index 0000000000..9b69ba2aa8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-nix/action.yml @@ -0,0 +1,137 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Setup nix +description: Setup nix + +inputs: + script: + description: The script to be run in the nix shell + required: false + devShell: + description: The name of the devShell + required: true + cache: + description: Determine whether to enable nix cache + default: 'false' + verbose: + description: Determine wether to suppress nix log or not + default: 'false' + cache_prefix: + description: Fixed prefix of ID of Github cache entries that should be removed. + required: false + save_cache: + description: Determine whether to save cache with primary key or not + required: false + default: 'false' + gh_token: + description: Github access token to use + required: true + install: + required: false + description: Determine how to install nix ('installer' | 'apt') + default: 'installer' + +runs: + using: composite + steps: + - name: Pre-check nix + id: nix-pre-check + if: ${{ env.NIX_SHELL == '' }} + shell: bash -lo pipefail {0} + run: | + suppress() { + local exit_code="$?" + local line_no="$1" + echo "Nix check failed at $line_no: $exit_code" + echo "installed=false" >> $GITHUB_OUTPUT + exit 0 + } + + trap 'suppress $LINENO' ERR + + if [[ $USER == 'root' ]]; then + mkdir -p /root + echo "HOME=/root" >> $GITHUB_ENV + fi + + nix --version + - name: Install nix via apt + if: ${{ steps.nix-pre-check.outputs.installed == 'false' && inputs.install == 'apt' }} + shell: bash + run: | + if [[ -f /.dockerenv ]]; then + apt install nix -y + else + sudo apt install nix -y + fi + mkdir -p ~/.config/nix + cat >> ~/.config/nix/nix.conf << EOF + experimental-features = nix-command flakes + EOF + + if [[ ! -z $GH_TOKEN ]]; then + echo "access-tokens = github.com=$GH_TOKEN" >> ~/.config/nix/nix.conf + fi + - uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 + if: ${{ steps.nix-pre-check.outputs.installed == 'false' }} + with: + github_access_token: ${{ inputs.gh_token }} + - name: Post-check nix + id: nix-post-check + continue-on-error: true + shell: bash -lo pipefail {0} + run: | + echo "::group::nix config" + if [[ -z "${{ inputs.cache_prefix }}" ]]; then + cache_prefix="${{ runner.os }}-${{ runner.arch }}" + else + cache_prefix="${{ inputs.cache_prefix }}" + fi + + echo "cache_prefix=$cache_prefix" >> $GITHUB_OUTPUT + + if [[ "${{ steps.nix-pre-check.outputs.installed }}" == 'false' ]]; then + sudo chown -R $USER:nixbld /nix + fi + + nix profile install nixpkgs/nixos-24.11#sqlite + nix config show + echo "::endgroup::" + - uses: nix-community/cache-nix-action@dab0514428ae3988852b7787a6d86a6fc571cc9d #v6.0.0 + id: cache + if: ${{ env.NIX_CACHE_ENABLED != 1 && inputs.cache == 'true' }} + continue-on-error: true + with: + primary-key: ${{ steps.nix-post-check.outputs.cache_prefix }} + gc-max-store-size-linux: 3221225472 + purge: ${{ inputs.save_cache == 'true' }} + save: ${{ inputs.save_cache == 'true' }} + purge-prefixes: cache-${{ steps.nix-post-check.outputs.cache_prefix }} + purge-created: 0 + purge-primary-key: ${{ inputs.save_cache == 'true' && 'always' || 'never' }} + token: ${{ inputs.gh_token }} + - name: Set Shell + shell: bash -lo pipefail {0} + run: | + echo "::group::set nix shell" + if [[ "${{ steps.cache.outputs.hit-primary-key }}" == "true" ]]; then + echo NIX_CACHE_ENABLED=1 >> $GITHUB_ENV + fi + + echo NIX_SHELL="${{ inputs.devShell }}" >> $GITHUB_ENV + nix_extra_flags="${{ inputs.verbose == 'false' && '--quiet' || '' }}" + if [[ ${{ inputs.install }} == 'apt' && ! -f /.dockerenv ]]; then + echo SHELL="sudo $(which nix) develop $nix_extra_flags .#${{ inputs.devShell }} -c bash -e {0}" >> $GITHUB_ENV + else + echo SHELL="$(which nix) develop $nix_extra_flags .#${{ inputs.devShell }} -c bash -e {0}" >> $GITHUB_ENV + fi + echo "::endgroup::" + - name: Prepare nix dev shell + shell: ${{ env.SHELL }} + run: | + - name: Dependency check + shell: ${{ env.SHELL }} + if: inputs.script != '' + run: eval ${{ inputs.script }} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-oqs/action.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-oqs/action.yml new file mode 100644 index 0000000000..c00701a9a2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-oqs/action.yml @@ -0,0 +1,35 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Setup libOQS +description: Setup libOQS + +inputs: + dir: + description: Directory to fetch libOQS into + default: 'libOQS' + repository: + description: Repository to fetch from + default: 'open-quantum-safe/libOQS' + commit: + description: Commit to fetch + default: 'HEAD' + gh_token: + description: Github access token to use + required: true + +runs: + using: composite + steps: + - name: Fetch libOQS + shell: bash + run: | + mkdir ${{ inputs.dir }} && cd ${{ inputs.dir }} + git config --global --add safe.directory $GITHUB_WORKSPACE/${{ inputs.dir }} + git init + git remote add origin $GITHUB_SERVER_URL/${{ inputs.repository }} + git fetch origin --depth 1 ${{ inputs.commit }} + git checkout FETCH_HEAD + + # Remember libOQS directory + echo LIBOQS_DIR="$GITHUB_WORKSPACE/${{ inputs.dir }}" >> $GITHUB_ENV diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-os/action.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-os/action.yml new file mode 100644 index 0000000000..97dfc20388 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-os/action.yml @@ -0,0 +1,47 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Setup OS +description: Setup OS + +inputs: + packages: + description: Space-separated list of additional packages to install + required: false + default: '' + sudo: + required: false + default: 'sudo' + +runs: + using: composite + steps: + - name: Detect OS + shell: bash + run: | + if (which yum > /dev/null); then + echo PKG="yum" >> $GITHUB_ENV + elif (which brew > /dev/null); then + echo PKG="brew" >> $GITHUB_ENV + elif (which apt > /dev/null); then + echo PKG="apt" >> $GITHUB_ENV + fi + - name: Setup via yum + if: ${{ env.PKG == 'yum' }} + uses: ./.github/actions/setup-yum + with: + packages: ${{ inputs.packages }} + sudo: ${{ inputs.sudo }} + - name: Setup via apt + if: ${{ env.PKG == 'apt' }} + uses: ./.github/actions/setup-apt + with: + packages: ${{ inputs.packages }} + sudo: ${{ inputs.sudo }} + - name: Setup via brew + if: ${{ env.PKG == 'brew' }} + uses: ./.github/actions/setup-brew + with: + packages: ${{ inputs.packages }} + sudo: ${{ inputs.sudo }} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-shell/action.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-shell/action.yml new file mode 100644 index 0000000000..1e40a65540 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-shell/action.yml @@ -0,0 +1,52 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Set Shell +description: Setup nix or custom shell for workflows + +inputs: + nix-shell: + description: Run in the specified Nix environment if exists. If empty, custom shell will be used instead of nix. + default: 'ci' + nix-cache: + description: Determine whether to enable nix cache + default: 'false' + nix-cache-prefix: + description: Fixed prefix of ID of Github cache entries that should be removed. + required: false + nix-verbose: + description: Determine wether to suppress nix log or not + default: 'false' + custom_shell: + description: The shell to use. Only relevant if no nix-shell specified + default: 'bash' + script: + description: The script to be run in the nix shell + required: false + gh_token: + description: Github access token to use + required: true + +runs: + using: composite + steps: + - name: Setup nix + uses: ./.github/actions/setup-nix + if: ${{ inputs.nix-shell != '' }} + with: + devShell: ${{ inputs.nix-shell }} + gh_token: ${{ inputs.gh_token }} + verbose: ${{ inputs.nix-verbose }} + cache: ${{ inputs.nix-cache }} + script: ${{ inputs.script }} + cache_prefix: ${{ inputs.nix-cache-prefix }} + - name: Set custom shell + shell: bash + if: ${{ inputs.nix-shell == '' }} + run: | + echo SHELL="${{ inputs.custom_shell }}" >> $GITHUB_ENV + + if [[ "${{ inputs.script }}" != '' ]]; then + eval ${{ inputs.script }} + fi diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-yum/action.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-yum/action.yml new file mode 100644 index 0000000000..f5a793c890 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/actions/setup-yum/action.yml @@ -0,0 +1,28 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Dependencies (yum) +description: Install dependencies via yum + +inputs: + packages: + description: Space-separated list of additional packages to install + required: false + default: '' + sudo: + required: false + default: 'sudo' + +runs: + using: composite + steps: + - name: Install base packages + shell: bash + run: | + ${{ inputs.sudo }} yum install make gcc python3 git -y + - name: Install additional packages + if: ${{ inputs.packages != ''}} + shell: bash + run: | + ${{ inputs.sudo }} yum install ${{ inputs.packages }} -y diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/dependabot.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/dependabot.yml new file mode 100644 index 0000000000..7b667de234 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/dependabot.yml @@ -0,0 +1,9 @@ +# Copyright (c) The mldsa-native project authors + +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly + diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/pull_request_template.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/pull_request_template.md new file mode 100644 index 0000000000..2a68852e00 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/pull_request_template.md @@ -0,0 +1,8 @@ +## Description + + + +## PR checklist + +- [ ] This pull request is must be on the Mbed-TLS fork, not upstream, because: +- [ ] **TF-PSA-Crypto PR** provided https://github.com/Mbed-TLS/TF-PSA-Crypto/pull/ | not required diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/all.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/all.yml new file mode 100644 index 0000000000..df0dd88952 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/all.yml @@ -0,0 +1,85 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: CI +permissions: + contents: read +on: + workflow_dispatch: + push: + branches: ["main"] + pull_request: + branches: ["main"] + types: [ "opened", "synchronize" ] + +jobs: + base: + name: Base + permissions: + contents: 'read' + id-token: 'write' + uses: ./.github/workflows/base.yml + secrets: inherit + lint-markdown: + name: Lint Markdown + permissions: + contents: 'read' + id-token: 'write' + uses: ./.github/workflows/lint_markdown.yml + nix: + name: Nix + permissions: + actions: 'write' + contents: 'read' + id-token: 'write' + uses: ./.github/workflows/nix.yml + secrets: inherit + ci: + name: Extended + permissions: + contents: 'read' + id-token: 'write' + needs: [ base, nix ] + uses: ./.github/workflows/ci.yml + secrets: inherit + cbmc: + name: CBMC + permissions: + contents: 'read' + id-token: 'write' + pull-requests: 'write' + needs: [ base, nix ] + uses: ./.github/workflows/cbmc.yml + secrets: inherit + oqs_integration: + name: libOQS + permissions: + contents: 'read' + id-token: 'write' + needs: [ base ] + uses: ./.github/workflows/integration-liboqs.yml + secrets: inherit + ct-test: + name: Constant-time + permissions: + contents: 'read' + id-token: 'write' + needs: [ base, nix ] + uses: ./.github/workflows/ct-tests.yml + secrets: inherit + slothy: + name: SLOTHY + permissions: + contents: 'read' + id-token: 'write' + needs: [ base, nix ] + uses: ./.github/workflows/slothy.yml + secrets: inherit + baremetal: + name: Baremetal + permissions: + contents: 'read' + id-token: 'write' + needs: [ base ] + uses: ./.github/workflows/baremetal.yml + secrets: inherit diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/baremetal.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/baremetal.yml new file mode 100644 index 0000000000..cb7fb8613b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/baremetal.yml @@ -0,0 +1,39 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Baremetal +permissions: + contents: read +on: + workflow_call: + workflow_dispatch: + +jobs: + baremetal_tests: + name: Baremetal tests (${{ matrix.target.name }}) + strategy: + fail-fast: false + matrix: + target: + - runner: ubuntu-latest + name: 'M55-AN547' + makefile: test/baremetal/platform/m55-an547/platform.mk + nix-shell: arm-embedded + runs-on: ${{ matrix.target.runner }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: baremetal build + test + uses: ./.github/actions/functest + env: + EXTRA_MAKEFILE: ${{ matrix.target.makefile }} + with: + nix-shell: ${{ matrix.target.nix-shell }} + gh_token: ${{ secrets.GITHUB_TOKEN }} + opt: no_opt + func: true + kat: true + acvp: true + examples: false + stack: false + alloc: true + rng_fail: false diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/base.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/base.yml new file mode 100644 index 0000000000..d040235414 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/base.yml @@ -0,0 +1,285 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Base +permissions: + contents: read +on: + workflow_call: + workflow_dispatch: + +jobs: + lint: + strategy: + fail-fast: false + matrix: + system: [ubuntu-latest, ubuntu-24.04-arm] + name: Linting + runs-on: ${{ matrix.system }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: ./.github/actions/lint + with: + nix-shell: ci-linter + gh_token: ${{ secrets.GITHUB_TOKEN }} + cross-prefix: "aarch64-unknown-linux-gnu-" + quickcheck: + strategy: + fail-fast: false + matrix: + external: + - ${{ github.repository_owner != 'pq-code-package' }} + target: + - runner: ubuntu-24.04-arm + name: 'aarch64' + - runner: ubuntu-latest + name: 'x86_64' + - runner: macos-latest + name: 'macos (aarch64)' + - runner: macos-15-intel + name: 'macos (x86_64)' + exclude: + - {external: true, + target: { + runner: ubuntu-24.04-arm, + name: 'aarch64' + }} + name: Quickcheck (${{ matrix.target.name }}) + runs-on: ${{ matrix.target.runner }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: make quickcheck + run: | + OPT=0 make quickcheck + make clean >/dev/null + OPT=1 make quickcheck + - uses: ./.github/actions/setup-os + - name: tests func + run: | + ./scripts/tests func --check-namespace + quickcheck-acvp: + strategy: + fail-fast: false + matrix: + external: + - ${{ github.repository_owner != 'pq-code-package' }} + target: + - runner: ubuntu-24.04-arm + name: 'aarch64' + - runner: ubuntu-latest + name: 'x86_64' + acvp-version: [v1.1.0.39, v1.1.0.40, v1.1.0.41] + exclude: + - {external: true, + target: { + runner: ubuntu-24.04-arm, + name: 'aarch64' + }} + name: Quickcheck ACVP (${{ matrix.target.name }}, ${{ matrix.acvp-version }}) + runs-on: ${{ matrix.target.runner }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: Run ACVP test + run: | + ./scripts/tests acvp --version ${{ matrix.acvp-version }} + quickcheck_bench: + strategy: + fail-fast: false + matrix: + external: + - ${{ github.repository_owner != 'pq-code-package' }} + target: + - runner: ubuntu-24.04-arm + name: 'aarch64' + - runner: ubuntu-24.04-arm + name: 'aarch64' + - runner: ubuntu-latest + name: 'x86_64' + - runner: macos-latest + name: 'macos (aarch64)' + - runner: macos-15-intel + name: 'macos (x86_64)' + exclude: + - {external: true, + target: { + runner: ubuntu-24.04-arm, + name: 'aarch64' + }} + name: Quickcheck bench (${{ matrix.target.name }}) + runs-on: ${{ matrix.target.runner }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: "tests bench (cycles: NO)" + run: | + ./scripts/tests bench -c NO + - name: "tests bench (build only, cycles: PMU)" + if: ${{ matrix.target.name != 'macos (aarch64)' && matrix.target.name != 'macos (x86_64)' }} + run: | + make clean + ./scripts/tests bench -c PMU --no-run + - name: "tests bench (build only, cycles: PERF)" + if: ${{ matrix.target.name != 'macos (aarch64)' && matrix.target.name != 'macos (x86_64)' }} + run: | + make clean + ./scripts/tests bench -c PERF --no-run + - name: "tests bench (build only, cycles: MAC)" + if: ${{ matrix.target.name == 'macos (aarch64)' || matrix.target.name == 'macos (x86_64)' }} + run: | + make clean + ./scripts/tests bench -c MAC --no-run + - name: tests bench components + run: | + make clean + ./scripts/tests bench --components -c NO + quickcheck-c90: + strategy: + fail-fast: false + matrix: + external: + - ${{ github.repository_owner != 'pq-code-package' }} + target: + - runner: ubuntu-24.04-arm + name: 'aarch64' + - runner: ubuntu-latest + name: 'x86_64' + exclude: + - {external: true, + target: { + runner: ubuntu-24.04-arm, + name: 'aarch64' + }} + name: Quickcheck C90 (${{ matrix.target.name }}) + runs-on: ${{ matrix.target.runner }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: make quickcheck + run: | + OPT=0 CFLAGS=-std=c90 make quickcheck + make clean >/dev/null + OPT=1 CFLAGS=-std=c90 make quickcheck + - uses: ./.github/actions/setup-apt + - name: tests func + run: | + ./scripts/tests func --cflags="-std=c90" --check-namespace + - name: tests bench + run: | + ./scripts/tests bench -c NO --cflags="-std=c90" + - name: tests bench components + run: | + ./scripts/tests bench --components -c NO --cflags="-std=c90" + quickcheck-windows: + strategy: + fail-fast: false + matrix: + system: [windows-2025, windows-2022] + name: Quickcheck ${{ matrix.system }} + runs-on: ${{ matrix.system }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 + - name: Build test + shell: powershell + run: | + # print compiler version + cl + nmake /f ./Makefile.Microsoft_nmake quickcheck + quickcheck-windows-mingw-w64: + strategy: + fail-fast: false + matrix: + # TODO: re-enable 5.4.0 or other old version + mingw-version: [11.2.0, 12.2.0, 13.2.0, 14.2.0, 15.2.0] + name: Quickcheck (Mingw-w64 ${{ matrix.mingw-version }}) + runs-on: windows-latest + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: Install MinGW-w64 + run: choco install mingw --version=${{ matrix.mingw-version }} -y + shell: cmd + - name: make quickcheck + shell: bash + run: | + CC=gcc OPT=0 make quickcheck + CC=gcc make clean >/dev/null + CC=gcc OPT=1 make quickcheck + quickcheck-lib: + name: Quickcheck lib + strategy: + matrix: + system: [macos-latest, macos-15-intel, ubuntu-latest, ubuntu-24.04-arm] + runs-on: ${{ matrix.system }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: make lib + run: | + make lib + simpasm: + strategy: + fail-fast: false + matrix: + backend: + - arg: '--aarch64-clean' + name: Clean + - arg: '' + name: Optimized + simplify: + - arg: '' + name: Simplified + - arg: '--no-simplify' + name: Unmodified + runs-on: ubuntu-24.04-arm + name: AArch64 dev backend (${{ matrix.simplify.name }}) + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: Reinstate and test backend + uses: ./.github/actions/setup-shell + with: + nix-shell: 'ci' + gh_token: ${{ secrets.GITHUB_TOKEN }} + script: | + ./scripts/autogen ${{ matrix.simplify.arg }} + make clean + OPT=1 make quickcheck + x86_64_intel_syntax: + name: x86_64 Intel syntax + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: Generate with Intel syntax and test + uses: ./.github/actions/setup-shell + with: + nix-shell: 'ci' + gh_token: ${{ secrets.GITHUB_TOKEN }} + script: | + ./scripts/autogen --x86-64-syntax intel + make clean + ./scripts/tests all + scan-build: + strategy: + fail-fast: false + matrix: + external: + - ${{ github.repository_owner != 'pq-code-package' }} + target: + - runner: ubuntu-24.04-arm + name: 'aarch64' + - runner: ubuntu-latest + name: 'x86_64' + name: scan-build (${{ matrix.target.name }}) + runs-on: ${{ matrix.target.runner }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: ./.github/actions/setup-apt + with: + packages: clang-tools clang + - name: make quickcheck + run: | + scan-build --status-bugs make quickcheck OPT=0 + make clean >/dev/null + scan-build --status-bugs make quickcheck OPT=1 + symlink-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: donatj/symlink-check-action@b3c737d0fd4e52752f0b8c71a03f3f775fa015cb diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/bench.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/bench.yml new file mode 100644 index 0000000000..0bf34ae035 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/bench.yml @@ -0,0 +1,181 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Bench +on: + workflow_dispatch: + push: + branches: ["main"] + pull_request: + branches: ["main"] + types: [ "labeled" ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + pull-requests: read + +jobs: + bench: + permissions: + contents: write + pull-requests: write + name: ${{ matrix.target.name }} + strategy: + fail-fast: true + matrix: + target: + - system: rpi4 + name: Arm Cortex-A72 (Raspberry Pi 4) benchmarks + bench_pmu: PMU + archflags: -mcpu=cortex-a72 -DMLD_SYS_AARCH64_SLOW_BARREL_SHIFTER + cflags: "-flto -DMLD_FORCE_AARCH64" + ldflags: "-flto" + bench_extra_args: "" + nix_shell: ci-bench + only_no_opt: false + - system: rpi5 + name: Arm Cortex-A76 (Raspberry Pi 5) benchmarks + bench_pmu: PERF + archflags: "-mcpu=cortex-a76 -march=armv8.2-a" + cflags: "-flto -DMLD_FORCE_AARCH64" + ldflags: "-flto" + bench_extra_args: "" + nix_shell: ci-bench + only_no_opt: false + - system: a55 + name: Arm Cortex-A55 (Snapdragon 888) benchmarks + bench_pmu: PERF + archflags: "-mcpu=cortex-a55 -march=armv8.2-a" + cflags: "-flto -DMLD_FORCE_AARCH64" + ldflags: "-flto -static" + bench_extra_args: -w exec-on-a55 + nix_shell: ci-bench + only_no_opt: false + - system: bpi + name: SpacemiT K1 8 (Banana Pi F3) benchmarks + bench_pmu: PERF + archflags: "-march=rv64imafdcv_zicsr_zifencei" + cflags: "" + ldflags: "-static" + bench_extra_args: -w exec-on-bpi + cross_prefix: riscv64-unknown-linux-gnu- + nix_shell: ci-cross-riscv64 + only_no_opt: true + - system: m1-mac-mini + name: Mac Mini (M1, 2020) benchmarks + bench_pmu: MAC + archflags: "-mcpu=apple-m1 -march=armv8.4-a+sha3" + cflags: "-flto" + ldflags: "-flto" + bench_extra_args: "-r" + nix_shell: ci-bench + only_no_opt: false + if: github.repository_owner == 'pq-code-package' && (github.event.label.name == 'benchmark' || github.ref == 'refs/heads/main') + runs-on: self-hosted-${{ matrix.target.system }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: ./.github/actions/bench + if: ${{ !matrix.target.only_no_opt }} + with: + name: ${{ matrix.target.name }} (opt) + cflags: ${{ matrix.target.cflags }} + archflags: ${{ matrix.target.archflags }} + ldflags: ${{ matrix.target.ldflags }} + perf: ${{ matrix.target.bench_pmu }} + store_results: ${{ github.repository_owner == 'pq-code-package' && github.ref == 'refs/heads/main' }} + bench_extra_args: ${{ matrix.target.bench_extra_args }} + gh_token: ${{ secrets.GITHUB_TOKEN }} + nix-shell: ${{ matrix.target.nix_shell }} + cross_prefix: ${{ matrix.target.cross_prefix }} + opt: true + - uses: ./.github/actions/bench + with: + name: ${{ matrix.target.name }} (no-opt) + cflags: ${{ matrix.target.cflags }} + archflags: ${{ matrix.target.archflags }} + ldflags: ${{ matrix.target.ldflags }} + perf: ${{ matrix.target.bench_pmu }} + store_results: ${{ github.repository_owner == 'pq-code-package' && github.ref == 'refs/heads/main' }} + bench_extra_args: ${{ matrix.target.bench_extra_args }} + gh_token: ${{ secrets.GITHUB_TOKEN }} + nix-shell: ${{ matrix.target.nix_shell }} + cross_prefix: ${{ matrix.target.cross_prefix }} + opt: false + + ec2_all: + name: ${{ matrix.target.name }} ${{ matrix.opt.name }} + permissions: + contents: write + pull-requests: write + id-token: write + strategy: + fail-fast: false + matrix: + target: + - name: Graviton2 + ec2_instance_type: t4g.small + ec2_ami: ubuntu-latest (aarch64) + archflags: -mcpu=cortex-a76 -march=armv8.2-a + cflags: "-flto -DMLD_FORCE_AARCH64" + ldflags: "-flto" + perf: PERF + - name: Graviton3 + ec2_instance_type: c7g.medium + ec2_ami: ubuntu-latest (aarch64) + archflags: -march=armv8.4-a+sha3 + cflags: "-flto -DMLD_FORCE_AARCH64" + ldflags: "-flto" + perf: PERF + - name: Graviton4 + ec2_instance_type: c8g.medium + ec2_ami: ubuntu-latest (aarch64) + archflags: -march=armv9-a+sha3 + cflags: "-flto -DMLD_FORCE_AARCH64" + ldflags: "-flto" + perf: PERF + - name: AMD EPYC 4th gen (c7a) + ec2_instance_type: c7a.medium + ec2_ami: ubuntu-latest (x86_64) + archflags: -mavx2 -mbmi2 -mpopcnt -maes -march=znver4 + cflags: "-flto -DMLD_FORCE_X86_64" + ldflags: "-flto" + perf: PMU + - name: Intel Xeon 4th gen (c7i) + ec2_instance_type: c7i.metal-24xl + ec2_ami: ubuntu-latest (x86_64) + archflags: -mavx2 -mbmi2 -mpopcnt -maes -march=sapphirerapids + cflags: "-flto -DMLD_FORCE_X86_64" + ldflags: "-flto" + perf: PMU + - name: AMD EPYC 3rd gen (c6a) + ec2_instance_type: c6a.large + ec2_ami: ubuntu-latest (x86_64) + archflags: -mavx2 -mbmi2 -mpopcnt -maes -march=znver3 + cflags: "-flto -DMLD_FORCE_X86_64" + ldflags: "-flto" + perf: PMU + - name: Intel Xeon 3rd gen (c6i) + ec2_instance_type: c6i.large + ec2_ami: ubuntu-latest (x86_64) + archflags: -mavx2 -mbmi2 -mpopcnt -maes -march=icelake-server + cflags: "-flto -DMLD_FORCE_X86_64" + ldflags: "-flto" + perf: PMU + uses: ./.github/workflows/bench_ec2_reusable.yml + if: github.repository_owner == 'pq-code-package' && (github.event.label.name == 'benchmark' || github.ref == 'refs/heads/main') + with: + ec2_instance_type: ${{ matrix.target.ec2_instance_type }} + ec2_ami: ${{ matrix.target.ec2_ami }} + archflags: ${{ matrix.target.archflags }} + cflags: ${{ matrix.target.cflags }} + ldflags: ${{ matrix.target.ldflags }} + opt: "all" + store_results: ${{ github.repository_owner == 'pq-code-package' && github.ref == 'refs/heads/main' }} # Only store optimized results + name: ${{ matrix.target.name }} + perf: ${{ matrix.target.perf }} + secrets: inherit diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/bench_ec2_any.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/bench_ec2_any.yml new file mode 100644 index 0000000000..3985df2ab2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/bench_ec2_any.yml @@ -0,0 +1,70 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: bench-ec2-any +permissions: + contents: read +on: + workflow_dispatch: + inputs: + name: + description: Alternative name of instance + default: Graviton2 + ec2_instance_type: + description: Type if EC2 instance to benchmark on + default: t4g.small + ec2_ami: + description: AMI ID + type: choice + options: + - ubuntu-latest (x86_64) + - ubuntu-latest (aarch64) + - ubuntu-latest (custom AMI) + default: ubuntu-latest (aarch64) + ec2_ami_id: + description: AMI ID + required: false + default: ami-0c4e709339fa8521a + cflags: + description: Custom CFLAGS for compilation + default: + archflags: + description: Custom ARCH flags for compilation + default: '' + ldflags: + description: Custom LDFLAGS for linking + default: '' + opt: + description: Benchmark optimized, non-optimized, or both + type: choice + options: + - all + - opt + - no_opt + bench_extra_args: + description: Additional command line to be appended to `tests bench` script + default: '' + compiler: + description: Compiler to use. When unset, default nix shell is used. + default: '' +jobs: + bench-ec2-any: + name: Ad-hoc benchmark on $${{ inputs.ec2_instance_type }} + permissions: + contents: 'read' + id-token: 'write' + uses: ./.github/workflows/bench_ec2_reusable.yml + with: + ec2_instance_type: ${{ inputs.ec2_instance_type }} + ec2_ami: ${{ inputs.ec2_ami }} + ec2_ami_id: ${{ inputs.ec2_ami_id }} + cflags: ${{ inputs.cflags }} + archflags: ${{ inputs.archflags }} + ldflags: ${{ inputs.ldflags }} + opt: ${{ inputs.opt }} + name: ${{ inputs.name }} + store_results: false + bench_extra_args: ${{ inputs.bench_extra_args }} + compiler: ${{ inputs.compiler }} + secrets: inherit diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/bench_ec2_reusable.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/bench_ec2_reusable.yml new file mode 100644 index 0000000000..7c68c4b82a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/bench_ec2_reusable.yml @@ -0,0 +1,232 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: bench-ec2-reusable +on: + workflow_call: + inputs: + name: + type: string + description: Alternative name of instance + default: Graviton2 + ec2_instance_type: + type: string + description: Type if EC2 instance to benchmark on + default: t4g.small + ec2_ami: + type: string + description: Textual description of AMI + default: ubuntu-latest (aarch64) + ec2_ami_id: + type: string + description: AMI ID + default: ami-0c4e709339fa8521a + cflags: + type: string + description: Custom CFLAGS for compilation + default: "" + archflags: + type: string + description: Custom ARCH flags for compilation + default: -mcpu=neoverse-n1 -march=armv8.2-a + ldflags: + type: string + description: Custom LDFLAGS for linking + default: "" + opt: + type: string + description: Runs with optimized code if enabled (opt, no_opt, all) + default: "opt" + perf: + type: string + description: Method by which clock cycles should be measured (PMU | PERF) + default: PERF + store_results: + type: boolean + description: Indicates if results should be pushed to github pages + default: false + verbose: + description: Determine for the log verbosity + type: boolean + default: false + bench_extra_args: + type: string + description: Additional command line to be appended to `bench` script + default: '' + compiler: + type: string + description: Compiler to use. When unset, default nix shell is used. + default: '' + additional_packages: + type: string + description: Additional packages to install when custom compiler is used. + default: '' + aws_region: + type: string + default: "us-east-1" + alert_threshold: + type: string + description: "Set alert threshold in percentage for benchmark result" + default: "103%" +env: + AWS_ROLE: arn:aws:iam::904233116199:role/mldsa-native-ci + AMI_UBUNTU_LATEST_X86_64: ami-084568db4383264d4 + AMI_UBUNTU_LATEST_AARCH64: ami-0c4e709339fa8521a + +permissions: + contents: read + pull-requests: read + +jobs: + start-ec2-runner: + name: Start ${{ inputs.name }} (${{ inputs.ec2_instance_type }}) + permissions: + contents: 'read' + id-token: 'write' + runs-on: ubuntu-latest + if: ${{ always() }} # The point is to make this step non-cancellable, + # avoiding race conditions where an instance is started, + # but isn't yet done registering as a runner and reporting back. + outputs: + label: ${{ steps.start-ec2-runner.outputs.label }} + ec2-instance-id: ${{ steps.start-ec2-runner.outputs.ec2-instance-id }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: Determine AMI ID + id: det_ami_id + run: | + if [[ "${{ inputs.ec2_ami }}" == "ubuntu-latest (x86_64)" ]]; then + AMI_ID=${{ env.AMI_UBUNTU_LATEST_X86_64 }} + elif [[ "${{ inputs.ec2_ami }}" == "ubuntu-latest (aarch64)" ]]; then + AMI_ID=${{ env.AMI_UBUNTU_LATEST_AARCH64 }} + elif [[ "${{ inputs.ec2_ami }}" == "ubuntu-latest (custom AMI)" ]]; then + AMI_ID=${{ inputs.ec2_ami_id }} + fi + echo "Using AMI ID: $AMI_ID" + echo "AMI_ID=$AMI_ID" >> $GITHUB_OUTPUT + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@00943011d9042930efac3dcd3a170e4273319bc8 # v5.1.0 + with: + role-to-assume: ${{ env.AWS_ROLE }} + aws-region: ${{ inputs.aws_region }} + - name: Start EC2 runner + id: start-ec2-runner + uses: machulav/ec2-github-runner@a6dbcefcf8a31a861f5e078bb153ed332130c512 # v2.4.3 + with: + mode: start + github-token: ${{ secrets.AWS_GITHUB_TOKEN }} + ec2-image-id: ${{ steps.det_ami_id.outputs.AMI_ID }} + ec2-instance-type: ${{ inputs.ec2_instance_type }} + subnet-id: subnet-094d73eb42eb6bf5b + security-group-id: sg-0282706dbc92a1579 + bench_nix: + name: Bench (nix) + permissions: + contents: write + pull-requests: write + runs-on: ${{ needs.start-ec2-runner.outputs.label }} + needs: start-ec2-runner # required to start the main job when the runner is ready + if: ${{ inputs.compiler == '' }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: ./.github/actions/bench + if: ${{ inputs.opt == 'all' || inputs.opt == 'opt' }} + with: + nix-verbose: ${{ inputs.verbose }} + name: ${{ inputs.name }} + cflags: ${{ inputs.cflags }} + archflags: ${{ inputs.archflags }} + ldflags: ${{ inputs.ldflags }} + opt: true + perf: ${{ inputs.perf }} + store_results: ${{ inputs.store_results }} + bench_extra_args: ${{ inputs.bench_extra_args }} + gh_token: ${{ secrets.AWS_GITHUB_TOKEN }} + - uses: ./.github/actions/bench + if: ${{ inputs.opt == 'all' || inputs.opt == 'no_opt' }} + with: + nix-verbose: ${{ inputs.verbose }} + name: ${{ inputs.name }} (no-opt) + cflags: ${{ inputs.cflags }} + archflags: ${{ inputs.archflags }} + ldflags: ${{ inputs.ldflags }} + opt: false + perf: ${{ inputs.perf }} + store_results: ${{ inputs.store_results }} + bench_extra_args: ${{ inputs.bench_extra_args }} + gh_token: ${{ secrets.AWS_GITHUB_TOKEN }} + alert_threshold: ${{ inputs.alert_threshold }} + bench_custom: + name: Bench (custom compiler) + permissions: + contents: write + pull-requests: write + runs-on: ${{ needs.start-ec2-runner.outputs.label }} + needs: start-ec2-runner # required to start the main job when the runner is ready + if: ${{ inputs.compiler != '' }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: ./.github/actions/setup-apt + with: + packages: ${{ inputs.additional_packages }} + - name: Set compiler + run: | + echo "CC=${{ inputs.compiler }}" >> "$GITHUB_ENV" + - uses: ./.github/actions/bench + if: ${{ inputs.opt == 'all' || inputs.opt == 'opt' }} + with: + nix-shell: 'ci-bench' + custom-shell: 'bash' + nix-cache: false + nix-verbose: ${{ inputs.verbose }} + name: ${{ inputs.name }} (${{ inputs.compiler }}) + cflags: ${{ inputs.cflags }} + archflags: ${{ inputs.archflags }} + ldflags: ${{ inputs.ldflags }} + opt: true + perf: ${{ inputs.perf }} + store_results: ${{ inputs.store_results }} + bench_extra_args: ${{ inputs.bench_extra_args }} + gh_token: ${{ secrets.AWS_GITHUB_TOKEN }} + - uses: ./.github/actions/bench + if: ${{ inputs.opt == 'all' || inputs.opt == 'no_opt' }} + with: + nix-shell: 'ci-bench' + custom-shell: 'bash' + nix-cache: false + nix-verbose: ${{ inputs.verbose }} + name: ${{ inputs.name }} (${{ inputs.compiler }}) (no-opt) + cflags: ${{ inputs.cflags }} + archflags: ${{ inputs.archflags }} + ldflags: ${{ inputs.ldflags }} + opt: false + perf: ${{ inputs.perf }} + store_results: ${{ inputs.store_results }} + bench_extra_args: ${{ inputs.bench_extra_args }} + gh_token: ${{ secrets.AWS_GITHUB_TOKEN }} + alert_threshold: ${{ inputs.alert_threshold }} + stop-ec2-runner: + name: Stop ${{ inputs.name }} (${{ inputs.ec2_instance_type }}) + permissions: + contents: 'read' + id-token: 'write' + needs: + - start-ec2-runner + - bench_nix # required to wait when the main job is done + - bench_custom # required to wait when the main job is done + runs-on: ubuntu-latest + if: ${{ always() }} # required to stop the runner even if the error happened in the previous jobs + steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@00943011d9042930efac3dcd3a170e4273319bc8 # v5.1.0 + with: + role-to-assume: ${{ env.AWS_ROLE }} + aws-region: ${{ inputs.aws_region }} + - name: Stop EC2 runner + uses: machulav/ec2-github-runner@a6dbcefcf8a31a861f5e078bb153ed332130c512 # v2.4.3 + with: + mode: stop + github-token: ${{ secrets.AWS_GITHUB_TOKEN }} + label: ${{ needs.start-ec2-runner.outputs.label }} + ec2-instance-id: ${{ needs.start-ec2-runner.outputs.ec2-instance-id }} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/cbmc.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/cbmc.yml new file mode 100644 index 0000000000..fca5202222 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/cbmc.yml @@ -0,0 +1,80 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: CBMC +permissions: + contents: read +on: + workflow_call: + workflow_dispatch: + +jobs: + cbmc_44: + name: CBMC (ML-DSA-44) + if: ${{ github.repository_owner == 'pq-code-package' && !github.event.pull_request.head.repo.fork }} + permissions: + contents: 'read' + id-token: 'write' + pull-requests: 'write' + uses: ./.github/workflows/ci_ec2_reusable.yml + with: + name: CBMC (ML-DSA-44) + ec2_instance_type: c7g.4xlarge + ec2_ami: ubuntu-latest (aarch64) + ec2_volume_size: 20 + compile_mode: native + opt: no_opt + lint: false + verbose: true + functest: true + kattest: false + acvptest: false + cbmc: true + cbmc_mldsa_parameter_set: 44 + secrets: inherit + cbmc_65: + name: CBMC (ML-DSA-65) + if: ${{ github.repository_owner == 'pq-code-package' && !github.event.pull_request.head.repo.fork }} + permissions: + contents: 'read' + id-token: 'write' + pull-requests: 'write' + uses: ./.github/workflows/ci_ec2_reusable.yml + with: + name: CBMC (ML-DSA-65) + ec2_instance_type: c7g.4xlarge + ec2_ami: ubuntu-latest (aarch64) + ec2_volume_size: 20 + compile_mode: native + opt: no_opt + lint: false + verbose: true + functest: true + kattest: false + acvptest: false + cbmc: true + cbmc_mldsa_parameter_set: 65 + secrets: inherit + cbmc_87: + name: CBMC (ML-DSA-87) + if: ${{ github.repository_owner == 'pq-code-package' && !github.event.pull_request.head.repo.fork }} + permissions: + contents: 'read' + id-token: 'write' + pull-requests: 'write' + uses: ./.github/workflows/ci_ec2_reusable.yml + with: + name: CBMC (ML-DSA-87) + ec2_instance_type: c7g.4xlarge + ec2_ami: ubuntu-latest (aarch64) + ec2_volume_size: 20 + compile_mode: native + opt: no_opt + lint: false + verbose: true + functest: true + kattest: false + acvptest: false + cbmc: true + cbmc_mldsa_parameter_set: 87 + secrets: inherit diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/ci.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/ci.yml new file mode 100644 index 0000000000..4048ae5180 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/ci.yml @@ -0,0 +1,787 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Extended +permissions: + contents: read +on: + workflow_call: + workflow_dispatch: + +jobs: + build_kat: + strategy: + fail-fast: false + matrix: + external: + - ${{ github.repository_owner != 'pq-code-package' }} + target: + - runner: macos-latest + name: 'MacOS (aarch64)' + arch: mac + mode: native + nix_shell: ci + - runner: macos-15-intel + name: 'MacOS (x86_64)' + arch: mac + mode: native + nix_shell: ci + - runner: ubuntu-24.04-arm + name: 'ubuntu-latest (aarch64)' + arch: aarch64 + mode: native + nix_shell: ci + - runner: ubuntu-24.04-arm + name: 'ubuntu-latest (aarch64)' + arch: x86_64 + mode: cross-x86_64 + nix_shell: ci-cross-x86_64 + - runner: ubuntu-24.04-arm + name: 'ubuntu-latest (aarch64)' + arch: riscv64 + mode: cross-riscv64 + nix_shell: ci-cross-riscv64 + - runner: ubuntu-24.04-arm + name: 'ubuntu-latest (aarch64)' + arch: riscv32 + mode: cross-riscv32 + nix_shell: ci-cross-riscv32 + - runner: ubuntu-24.04-arm + name: 'ubuntu-latest (ppc64le)' + arch: ppc64le + mode: cross-ppc64le + nix_shell: ci-cross-ppc64le + - runner: ubuntu-latest + name: 'ubuntu-latest (x86_64)' + arch: x86_64 + mode: native + nix_shell: ci + - runner: ubuntu-latest + name: 'ubuntu-latest (x86_64)' + arch: aarch64 + mode: cross-aarch64 + nix_shell: ci-cross-aarch64 + - runner: ubuntu-latest + name: 'ubuntu-latest (x86_64)' + arch: aarch64_be + mode: cross-aarch64_be + nix_shell: ci-cross-aarch64_be + exclude: + - {external: true, + target: { + runner: ubuntu-24.04-arm, + name: 'ubuntu-latest (aarch64)', + arch: aarch64, + mode: native, + nix_shell: ci + }} + - {external: true, + target: { + runner: ubuntu-24.04-arm, + name: 'ubuntu-latest (aarch64)', + arch: x86_64, + mode: cross-x86_64, + nix_shell: ci-cross-x86_64 + }} + - {external: true, + target: { + runner: ubuntu-24.04-arm, + name: 'ubuntu-latest (aarch64)', + arch: riscv64, + mode: cross-riscv64, + nix_shell: ci-cross-riscv64 + }} + - {external: true, + target: { + runner: ubuntu-24.04-arm, + name: 'ubuntu-latest (aarch64)', + arch: riscv32, + mode: cross-riscv32, + nix_shell: ci-cross-riscv32 + }} + - {external: true, + target: { + runner: ubuntu-24.04-arm, + name: 'ubuntu-latest (ppc64le)', + arch: ppc64le, + mode: cross-ppc64le, + nix_shell: ci-cross-ppc64le + }} + - {external: true, + target: { + runner: ubuntu-latest, + name: 'ubuntu-latest (x86_64)', + arch: x86_64, + mode: native, + nix_shell: ci + }} + - {external: true, + target: { + runner: ubuntu-latest, + name: 'ubuntu-latest (x86_64)', + arch: aarch64, + mode: cross-aarch64, + nix_shell: ci-cross-aarch64 + }} + - {external: true, + target: { + runner: ubuntu-latest, + name: 'ubuntu-latest (x86_64)', + arch: aarch64_be, + mode: cross-aarch64_be, + nix_shell: ci-cross-aarch64_be + }} + name: Functional tests (${{ matrix.target.arch }}${{ matrix.target.mode != 'native' && ', cross' || ''}}) + runs-on: ${{ matrix.target.runner }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: build + test (no-opt) + uses: ./.github/actions/multi-functest + with: + nix-shell: ${{ matrix.target.nix_shell }} + nix-cache: ${{ matrix.target.mode == 'native' && 'false' || 'true' }} + gh_token: ${{ secrets.GITHUB_TOKEN }} + compile_mode: ${{ matrix.target.mode }} + opt: 'no_opt' + - name: build + test (+debug+memsan+ubsan, native) + uses: ./.github/actions/multi-functest + if: ${{ matrix.target.mode == 'native' }} + with: + gh_token: ${{ secrets.GITHUB_TOKEN }} + compile_mode: native + cflags: "-DMLDSA_DEBUG -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + check_namespace: 'false' + - name: build + test (cross, opt) + uses: ./.github/actions/multi-functest + # There is no native code yet on PPC64LE, riscv32 or AArch64_be, so no point running opt tests + if: ${{ matrix.target.mode != 'native' && (matrix.target.arch != 'ppc64le' && matrix.target.arch != 'riscv32' && matrix.target.arch != 'aarch64_be') }} + with: + nix-shell: ${{ matrix.target.nix_shell }} + nix-cache: ${{ matrix.target.mode == 'native' && 'false' || 'true' }} + gh_token: ${{ secrets.GITHUB_TOKEN }} + compile_mode: ${{ matrix.target.mode }} + opt: 'opt' + - name: build + test (cross, opt, +debug) + uses: ./.github/actions/multi-functest + # There is no native code yet on PPC64LE, riscv32 or AArch64_be, so no point running opt tests + if: ${{ matrix.target.mode != 'native' && (matrix.target.arch != 'ppc64le' && matrix.target.arch != 'riscv32' && matrix.target.arch != 'aarch64_be') }} + with: + nix-shell: ${{ matrix.target.nix_shell }} + nix-cache: ${{ matrix.target.mode == 'native' && 'false' || 'true' }} + gh_token: ${{ secrets.GITHUB_TOKEN }} + compile_mode: ${{ matrix.target.mode }} + cflags: "-DMLDSA_DEBUG" + opt: 'opt' + backend_tests: + name: AArch64 FIPS202 backends (${{ matrix.backend }}) + strategy: + fail-fast: false + matrix: + backend: [x1_scalar, x1_v84a, x2_v84a, x4_v8a_scalar, x4_v8a_v84a_scalar] + runs-on: macos-latest + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: build + test + uses: ./.github/actions/multi-functest + with: + nix-shell: 'ci' + nix-cache: 'false' + gh_token: ${{ secrets.GITHUB_TOKEN }} + compile_mode: 'native' + opt: 'opt' + examples: 'false' + cflags: "-DMLDSA_DEBUG -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + ldflags: "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all" + check_namespace: 'false' + extra_args: "--fips202-aarch64-backend ${{ matrix.backend }}" + compiler_tests: + name: Compiler tests (${{ matrix.compiler.name }}, ${{ matrix.target.name }}, ${{ matrix.cflags }}) + strategy: + fail-fast: false + matrix: + cflags: [ "-O0", "-Os", "-O3" ] + target: + - runner: ubuntu-24.04-arm + name: 'aarch64' + - runner: ubuntu-latest + name: 'x86_64' + - runner: macos-latest + name: 'macos' + compiler: + - name: gcc-4.8 + shell: ci_gcc48 + darwin: False + c17: False + c23: False + opt: all + examples: true + - name: gcc-4.9 + shell: ci_gcc49 + darwin: False + c17: False + c23: False + opt: all + examples: true + - name: gcc-7 + shell: ci_gcc7 + darwin: False + c17: False + c23: False + opt: all + examples: true + - name: gcc-11 + shell: ci_gcc11 + darwin: True + c17: True + c23: False + opt: all + examples: true + - name: gcc-13 + shell: ci_gcc13 + darwin: True + c17: True + c23: False + opt: all + examples: true + - name: gcc-14 + shell: ci_gcc14 + darwin: True + c17: True + c23: True + opt: all + examples: true + - name: gcc-15 + shell: ci_gcc15 + darwin: True + c17: True + c23: True + opt: all + examples: true + - name: clang-18 + shell: ci_clang18 + darwin: True + c17: True + c23: True + opt: all + examples: true + - name: clang-19 + shell: ci_clang19 + darwin: True + c17: True + c23: True + opt: all + examples: true + - name: clang-20 + shell: ci_clang20 + darwin: True + c17: True + c23: True + opt: all + examples: true + - name: clang-21 + shell: ci_clang21 + darwin: True + c17: True + c23: True + opt: all + examples: true + # CPU flags are not correctly passed to the zig assembler + # https://github.com/ziglang/zig/issues/23576 + # We therefore only test the C backend + # + # We omit all examples since there is currently no way to run + # only those examples not involving native code. + - name: zig-0.12 + shell: ci_zig0_12 + darwin: True + c17: True + c23: False + examples: False + opt: no_opt + - name: zig-0.13 + shell: ci_zig0_13 + darwin: True + c17: True + c23: False + examples: False + opt: no_opt + - name: zig-0.14 + shell: ci_zig0_14 + darwin: True + c17: True + c23: True + examples: False + opt: no_opt + - name: zig-0.15 + shell: ci_zig0_15 + darwin: True + c17: True + c23: True + examples: False + opt: no_opt + runs-on: ${{ matrix.target.runner }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: native build+functest (default) + if: ${{ matrix.compiler.darwin || matrix.target.runner != 'macos-latest' }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ secrets.GITHUB_TOKEN }} + compile_mode: native + func: true + kat: false + acvp: false + examples: ${{ matrix.compiler.examples }} + opt: ${{ matrix.compiler.opt }} + nix-shell: ${{ matrix.compiler.shell }} + cflags: "${{ matrix.cflags }}" + - name: native build+functest (C90) + if: ${{ matrix.compiler.darwin || matrix.target.runner != 'macos-latest' }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ secrets.GITHUB_TOKEN }} + compile_mode: native + func: true + kat: false + acvp: false + examples: ${{ matrix.compiler.examples }} + opt: ${{ matrix.compiler.opt }} + nix-shell: ${{ matrix.compiler.shell }} + cflags: "-std=c90 ${{ matrix.cflags }}" + - name: native build+functest (C99) + if: ${{ matrix.compiler.darwin || matrix.target.runner != 'macos-latest' }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ secrets.GITHUB_TOKEN }} + compile_mode: native + func: true + kat: false + acvp: false + examples: ${{ matrix.compiler.examples }} + opt: ${{ matrix.compiler.opt }} + nix-shell: ${{ matrix.compiler.shell }} + cflags: "-std=c99 ${{ matrix.cflags }}" + - name: native build+functest (C11) + if: ${{ matrix.compiler.darwin || matrix.target.runner != 'macos-latest' }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ secrets.GITHUB_TOKEN }} + compile_mode: native + func: true + kat: false + acvp: false + examples: ${{ matrix.compiler.examples }} + opt: ${{ matrix.compiler.opt }} + nix-shell: ${{ matrix.compiler.shell }} + cflags: "-std=c11 ${{ matrix.cflags }}" + - name: native build+functest (C17) + if: ${{ (matrix.compiler.darwin || matrix.target.runner != 'macos-latest') && + matrix.compiler.c17 }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ secrets.GITHUB_TOKEN }} + compile_mode: native + func: true + kat: false + acvp: false + examples: ${{ matrix.compiler.examples }} + opt: ${{ matrix.compiler.opt }} + nix-shell: ${{ matrix.compiler.shell }} + cflags: "-std=c17 ${{ matrix.cflags }}" + - name: native build+functest (C23) + if: ${{ (matrix.compiler.darwin || matrix.target.runner != 'macos-latest') && + matrix.compiler.c23 }} + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ secrets.GITHUB_TOKEN }} + compile_mode: native + func: true + kat: false + acvp: false + examples: ${{ matrix.compiler.examples }} + opt: ${{ matrix.compiler.opt }} + nix-shell: ${{ matrix.compiler.shell }} + cflags: "-std=c23 ${{ matrix.cflags }}" + stack_analysis: + name: Stack analysis (${{ matrix.target.name }}, ${{ matrix.cflags }}) + strategy: + fail-fast: false + matrix: + external: + - ${{ github.repository_owner != 'pq-code-package' }} + target: + - runner: ubuntu-latest + name: x86_64 + - runner: ubuntu-24.04-arm + name: aarch64 + cflags: + - '-O3' + - '-Os' + - '-O3 -DMLD_CONFIG_REDUCE_RAM' + - '-Os -DMLD_CONFIG_REDUCE_RAM' + exclude: + - external: true + runs-on: ${{ matrix.target.runner }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: Stack analysis + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ secrets.GITHUB_TOKEN }} + compile_mode: native + nix-shell: ci_valgrind-varlat_gcc15 + nix-cache: false + opt: all + cflags: "${{ matrix.cflags }}" + func: false + kat: false + acvp: false + examples: false + stack: true + check_namespace: false + config_variations: + name: Non-standard configurations + strategy: + fail-fast: false + matrix: + external: + - ${{ github.repository_owner != 'pq-code-package' }} + target: + - runner: ubuntu-24.04-arm + name: 'ubuntu-latest (aarch64)' + - runner: ubuntu-latest + name: 'ubuntu-latest (x86_64)' + exclude: + - {external: true, + target: { + runner: ubuntu-24.04-arm, + name: 'ubuntu-latest (aarch64)', + }} + - {external: true, + target: { + runner: ubuntu-latest, + name: 'ubuntu-latest (x86_64)', + }} + runs-on: ${{ matrix.target.runner }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: "Config Variations" + uses: ./.github/actions/config-variations + with: + gh_token: ${{ secrets.GITHUB_TOKEN }} + check-cf-protections: + name: Test control-flow protections (${{ matrix.compiler.name }}, x86_64) + strategy: + fail-fast: false + matrix: + compiler: + - name: gcc-14 + shell: ci_gcc14 + - name: gcc-15 + shell: ci_gcc15 + - name: clang-19 + shell: ci_clang19 + # On AArch64 -fcf-protection is not supported anyway + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: Test control-flow protections + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ secrets.GITHUB_TOKEN }} + compile_mode: native + cflags: "-Wl,-z,cet-report=error -fcf-protection=full" + func: true + kat: true + acvp: true + nix-shell: ${{ matrix.compiler.shell }} + # ensure that sign.h and mldsa_native.h; api.h and native backends are compatible + check-apis: + strategy: + fail-fast: false + matrix: + external: + - ${{ github.repository_owner != 'pq-code-package' }} + target: + - runner: ubuntu-24.04-arm + name: 'aarch64' + - runner: ubuntu-latest + name: 'x86_64' + exclude: + - {external: true, + target: { + runner: ubuntu-24.04-arm, + name: 'aarch64' + }} + name: Check API consistency + runs-on: ${{ matrix.target.runner }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: make quickcheck + run: | + OPT=0 CFLAGS="-Imldsa -DMLD_CHECK_APIS -Wno-redundant-decls" make quickcheck + make clean >/dev/null + OPT=1 CFLAGS="-Imldsa -DMLD_CHECK_APIS -Wno-redundant-decls" make quickcheck + - uses: ./.github/actions/setup-apt + - name: tests func + run: | + ./scripts/tests func --cflags="-Imldsa -DMLD_CHECK_APIS -Wno-redundant-decls" + ec2_functests: + strategy: + fail-fast: false + matrix: + target: + - name: AMD EPYC 4th gen (t3a) + ec2_instance_type: t3a.small + ec2_ami: ubuntu-latest (x86_64) + ec2_volume_size: 20 + compile_mode: native + opt: all + config_variations: 'native-cap-CPUID_AVX2' + - name: Intel Xeon 4th gen (t3) + ec2_instance_type: t3.small + ec2_ami: ubuntu-latest (x86_64) + ec2_volume_size: 20 + compile_mode: native + opt: all + config_variations: 'native-cap-CPUID_AVX2' + - name: Graviton2 (c6g.medium) + ec2_instance_type: c6g.medium + ec2_ami: ubuntu-latest (aarch64) + ec2_volume_size: 20 + compile_mode: native + opt: all + config_variations: 'native-cap-ON native-cap-OFF native-cap-ID_AA64PFR1_EL1' + - name: Graviton3 (c7g.medium) + ec2_instance_type: c7g.medium + ec2_ami: ubuntu-latest (aarch64) + ec2_volume_size: 20 + compile_mode: native + opt: all + config_variations: 'native-cap-ID_AA64PFR1_EL1' + name: Platform tests (${{ matrix.target.name }}) + permissions: + contents: 'read' + id-token: 'write' + if: github.repository_owner == 'pq-code-package' && !github.event.pull_request.head.repo.fork + uses: ./.github/workflows/ci_ec2_reusable.yml + with: + name: ${{ matrix.target.name }} + ec2_instance_type: ${{ matrix.target.ec2_instance_type }} + ec2_ami: ${{ matrix.target.ec2_ami }} + ec2_ami_id: ${{ matrix.target.ec2_ami_id }} + compile_mode: ${{ matrix.target.compile_mode }} + opt: ${{ matrix.target.opt }} + config_variations: ${{ matrix.target.config_variations || '' }} + functest: true + kattest: true + acvptest: true + lint: false + verbose: true + secrets: inherit + compatibility_tests: + strategy: + max-parallel: 4 + fail-fast: false + matrix: + container: + - id: debian:bullseye + - id: debian:bookworm + - id: nixos/nix:latest + nix_shell: 'nix-shell -p python3 gcc gnumake perl' + name: Compatibility tests (${{ matrix.container.id }}) + runs-on: ubuntu-latest + container: + ${{ matrix.container.id }} + steps: + # We're not using the checkout action here because on it's not supported + # on all containers we want to test. Resort to a manual checkout. + + # We can't hoist this into an action since calling an action can only + # be done after checkout. + - name: Manual checkout + shell: bash + run: | + if (which yum > /dev/null); then + yum install git -y + elif (which apt > /dev/null); then + apt update + apt install git -y + fi + + git config --global --add safe.directory $GITHUB_WORKSPACE + git init + git remote add origin $GITHUB_SERVER_URL/$GITHUB_REPOSITORY + git fetch origin --depth 1 $GITHUB_SHA + git checkout FETCH_HEAD + - uses: ./.github/actions/setup-os + with: + sudo: "" + - name: make quickcheck + shell: bash + run: | + if [ -n "${{ matrix.container.nix_shell }}" ]; then + ${{ matrix.container.nix_shell }} --run "CC=gcc OPT=0 make quickcheck && make clean >/dev/null && CC=gcc OPT=1 make quickcheck" + else + CC=gcc OPT=0 make quickcheck + make clean >/dev/null + CC=gcc OPT=1 make quickcheck + fi + - name: Functional Tests + uses: ./.github/actions/multi-functest + with: + nix-shell: "" + custom_shell: ${{ matrix.container.nix_shell && format('{0} --run \"bash -e {{0}}\"', matrix.container.nix_shell) || 'bash' }} + gh_token: ${{ secrets.GITHUB_TOKEN }} + ec2_compatibilitytests: + strategy: + max-parallel: 8 + fail-fast: false + matrix: + container: + - id: amazonlinux-2-aarch:base + # TODO: Python 3.7 on Amazon Linux 2 lacks `sha512_224` in hashlib; set to false to skip acvp. + quickcheck: false + acvptest: false + - id: amazonlinux-2-aarch:gcc-7x + # TODO: Python 3.7 on Amazon Linux 2 lacks `sha512_224` in hashlib; set to false to skip acvp. + quickcheck: false + acvptest: false + - id: amazonlinux-2-aarch:clang-7x + # TODO: Python 3.7 on Amazon Linux 2 lacks `sha512_224` in hashlib; set to false to skip acvp. + quickcheck: false + acvptest: false + - id: amazonlinux-2023-aarch:base + quickcheck: true + acvptest: true + - id: amazonlinux-2023-aarch:gcc-11x + quickcheck: true + acvptest: true + - id: amazonlinux-2023-aarch:clang-15x + quickcheck: true + acvptest: true + - id: amazonlinux-2023-aarch:clang-15x-sanitizer + quickcheck: true + acvptest: true + # - id: amazonlinux-2023-aarch:cryptofuzz Not yet supported + - id: ubuntu-22.04-aarch:gcc-12x + quickcheck: true + acvptest: true + - id: ubuntu-22.04-aarch:gcc-11x + quickcheck: true + acvptest: true + - id: ubuntu-20.04-aarch:gcc-8x + quickcheck: true + acvptest: true + - id: ubuntu-20.04-aarch:gcc-7x + quickcheck: true + acvptest: true + - id: ubuntu-20.04-aarch:clang-9x + quickcheck: true + acvptest: true + - id: ubuntu-20.04-aarch:clang-8x + quickcheck: true + acvptest: true + - id: ubuntu-20.04-aarch:clang-7x-bm-framework + quickcheck: true + acvptest: true + - id: ubuntu-20.04-aarch:clang-7x + quickcheck: true + acvptest: true + - id: ubuntu-20.04-aarch:clang-10x + quickcheck: true + acvptest: true + - id: ubuntu-22.04-aarch:base + quickcheck: true + acvptest: true + - id: ubuntu-20.04-aarch:base + quickcheck: true + acvptest: true + name: Compatibility tests (${{ matrix.container.id }}) + permissions: + contents: 'read' + id-token: 'write' + uses: ./.github/workflows/ci_ec2_container.yml + if: github.repository_owner == 'pq-code-package' && !github.event.pull_request.head.repo.fork + with: + container: ${{ matrix.container.id }} + name: ${{ matrix.container.id }} + ec2_instance_type: t4g.small + ec2_ami: ubuntu-latest (custom AMI) + ec2_ami_id: ami-0c9bc1901ef0d1066 # Has docker images preinstalled + compile_mode: native + opt: all + functest: true + kattest: true + acvptest: ${{ matrix.container.acvptest }} + quickcheck: ${{ matrix.container.quickcheck }} + lint: false + verbose: true + cflags: "-O0" + secrets: inherit + check_autogenerated_files: + strategy: + fail-fast: false + matrix: + target: + - system: macos-latest + nix_shell: 'ci-cross-x86_64' + nix_cache: 'true' + extra_args: '--force-cross' + # TODO: This does not yet work (#1304) <- MLKEM ISSUE, Port when fixed + # - system: macos-15-intel + # nix_cache: 'false' + # nix_shell: 'ci' + - system: ubuntu-latest + nix_shell: 'ci-cross-aarch64' + nix_cache: 'true' + extra_args: '--force-cross' + - system: ubuntu-24.04-arm + nix_shell: 'ci-cross-x86_64' + nix_cache: 'true' + extra_args: '--force-cross' + runs-on: ${{ matrix.target.system }} + name: Check autogenerated files + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: ./.github/actions/setup-shell + with: + nix-shell: ${{ matrix.target.nix_shell }} + nix-cache: ${{ matrix.target.nix_cache }} + gh_token: ${{ secrets.GITHUB_TOKEN }} + script: | + python3 ./scripts/autogen --dry-run ${{ matrix.target.extra_args }} + check_hol_light_object_code: + strategy: + fail-fast: false + matrix: + target: + - system: macos-latest + nix_cache: 'true' + nix_shell: 'hol_light-cross-x86_64' + extra_args: '--force-cross' + # TODO: autogen does not yet work on macos15-intel (#1304) + # - system: macos-15-intel + # nix_cache: 'false' + # nix_shell: 'ci' + - system: ubuntu-latest + nix_shell: 'hol_light-cross-aarch64' + nix_cache: 'true' + extra_args: '--force-cross' + - system: ubuntu-24.04-arm + nix_shell: 'hol_light-cross-x86_64' + nix_cache: 'true' + extra_args: '--force-cross' + runs-on: ${{ matrix.target.system }} + name: Check object code in HOL-Light proofs + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: ./.github/actions/setup-shell + with: + nix-shell: ${{ matrix.target.nix_shell }} + nix-cache: ${{ matrix.target.nix_cache }} + gh_token: ${{ secrets.GITHUB_TOKEN }} + script: | + python3 ./scripts/autogen --dry-run --update-hol-light-bytecode ${{ matrix.target.extra_args }} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/ci_ec2_container.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/ci_ec2_container.yml new file mode 100644 index 0000000000..ce1c7b8d5f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/ci_ec2_container.yml @@ -0,0 +1,213 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: ci-ec2-reusable +permissions: + contents: read +on: + workflow_call: + inputs: + name: + type: string + description: Alternative name of instance + default: Graviton2 + ec2_instance_type: + type: string + description: Type if EC2 instance to benchmark on + default: t4g.small + ec2_ami: + type: string + description: Textual description of AMI + default: ubuntu-latest (aarch64) + ec2_ami_id: + type: string + description: AMI ID + default: ami-0e8c824f386e1de06 + cflags: + type: string + description: Custom CFLAGS for compilation + default: "" + verbose: + description: Determine for the log verbosity + type: boolean + default: false + compile_mode: + type: string + description: either all, native, cross or none + default: all + opt: + type: string + description: either all, opt or no_opt + default: all + functest: + type: boolean + default: true + kattest: + type: boolean + default: true + acvptest: + type: boolean + default: true + quickcheck: + type: boolean + default: true + lint: + type: boolean + default: true + cbmc: + type: boolean + default: false + cbmc_mldsa_parameter_set: + type: string + default: 44 + container: + type: string + default: '' +env: + AWS_ROLE: arn:aws:iam::904233116199:role/mldsa-native-ci + AWS_REGION: us-east-1 + AMI_UBUNTU_LATEST_X86_64: ami-0e86e20dae9224db8 + AMI_UBUNTU_LATEST_AARCH64: ami-096ea6a12ea24a797 +jobs: + start-ec2-runner: + name: Start instance (${{ inputs.ec2_instance_type }}) + permissions: + contents: 'read' + id-token: 'write' + runs-on: ubuntu-latest + if: ${{ always() }} # The point is to make this step non-cancellable, + # avoiding race conditions where an instance is started, + # but isn't yet done registering as a runner and reporting back. + outputs: + label: ${{ steps.remember-runner.outputs.label }} + ec2-instance-id: ${{ steps.remember-runner.outputs.ec2-instance-id }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: Determine AMI ID + id: det_ami_id + run: | + if [[ "${{ inputs.ec2_ami }}" == "ubuntu-latest (x86_64)" ]]; then + AMI_ID=${{ env.AMI_UBUNTU_LATEST_X86_64 }} + elif [[ "${{ inputs.ec2_ami }}" == "ubuntu-latest (aarch64)" ]]; then + AMI_ID=${{ env.AMI_UBUNTU_LATEST_AARCH64 }} + elif [[ "${{ inputs.ec2_ami }}" == "ubuntu-latest (custom AMI)" ]]; then + AMI_ID=${{ inputs.ec2_ami_id }} + fi + echo "Using AMI ID: $AMI_ID" + echo "AMI_ID=$AMI_ID" >> $GITHUB_OUTPUT + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@00943011d9042930efac3dcd3a170e4273319bc8 # v5.1.0 + with: + role-to-assume: ${{ env.AWS_ROLE }} + aws-region: ${{ env.AWS_REGION }} + - name: Start EC2 runner + id: start-ec2-runner-first + continue-on-error: true + uses: machulav/ec2-github-runner@a6dbcefcf8a31a861f5e078bb153ed332130c512 # v2.4.3 + with: + mode: start + github-token: ${{ secrets.AWS_GITHUB_TOKEN }} + ec2-image-id: ${{ steps.det_ami_id.outputs.AMI_ID }} + ec2-instance-type: ${{ inputs.ec2_instance_type }} + subnet-id: subnet-094d73eb42eb6bf5b + security-group-id: sg-0282706dbc92a1579 + - name: Start EC2 runner (wait before retry) + if: steps.start-ec2-runner-first.outcome == 'failure' + shell: bash + run: | + sleep 30 # Wait 30s before retrying + sleep $((1 + RANDOM % 30)) + - name: Start EC2 runner (retry) + id: start-ec2-runner-second + if: steps.start-ec2-runner-first.outcome == 'failure' + uses: machulav/ec2-github-runner@a6dbcefcf8a31a861f5e078bb153ed332130c512 # v2.4.3 + with: + mode: start + github-token: ${{ secrets.AWS_GITHUB_TOKEN }} + ec2-image-id: ${{ steps.det_ami_id.outputs.AMI_ID }} + ec2-instance-type: ${{ inputs.ec2_instance_type }} + subnet-id: subnet-094d73eb42eb6bf5b + security-group-id: sg-0282706dbc92a1579 + - name: Remember runner + id: remember-runner + shell: bash + run: | + if [[ "${{ steps.start-ec2-runner-first.outcome }}" == "failure" ]]; then + echo "label=${{ steps.start-ec2-runner-second.outputs.label }}" >> "$GITHUB_OUTPUT" + echo "ec2-instance-id=${{ steps.start-ec2-runner-second.outputs.ec2-instance-id }}" >> "$GITHUB_OUTPUT" + else + echo "label=${{ steps.start-ec2-runner-first.outputs.label }}" >> "$GITHUB_OUTPUT" + echo "ec2-instance-id=${{ steps.start-ec2-runner-first.outputs.ec2-instance-id }}" >> "$GITHUB_OUTPUT" + fi + + tests: + name: Run tests + needs: start-ec2-runner + if: ${{ inputs.container != '' }} + runs-on: ${{ needs.start-ec2-runner.outputs.label }} + container: + localhost:5000/${{ inputs.container }} + steps: + # We're not using the checkout action here because on it's not supported + # on all containers we want to test. Resort to a manual checkout. + # + # We can't hoist this into an action since calling an action can only + # be done after checkout. + - name: Manual checkout + shell: bash + run: | + if /usr/bin/which yum; then + yum install git -y + elif /usr/bin/which apt; then + apt update + apt install git -y + fi + + git init + git remote add origin $GITHUB_SERVER_URL/$GITHUB_REPOSITORY + git fetch origin --depth 1 $GITHUB_SHA + git checkout FETCH_HEAD + - uses: ./.github/actions/setup-os + with: + sudo: "" + - name: make quickcheck + if: ${{ inputs.quickcheck }} + run: | + OPT=0 make quickcheck + make clean >/dev/null + OPT=1 make quickcheck + - name: Functional Tests + uses: ./.github/actions/multi-functest + with: + nix-shell: "" + gh_token: ${{ secrets.AWS_GITHUB_TOKEN }} + cflags: ${{ inputs.cflags }} + compile_mode: ${{ inputs.compile_mode }} + opt: ${{ inputs.opt }} + func: ${{ inputs.functest }} + kat: ${{ inputs.kattest }} + acvp: ${{ inputs.acvptest }} + stop-ec2-runner: + name: Stop instance (${{ inputs.ec2_instance_type }}) + permissions: + contents: 'read' + id-token: 'write' + needs: + - start-ec2-runner + - tests + runs-on: ubuntu-latest + if: ${{ always() }} # required to stop the runner even if the error happened in the previous jobs + steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@00943011d9042930efac3dcd3a170e4273319bc8 # v5.1.0 + with: + role-to-assume: ${{ env.AWS_ROLE }} + aws-region: ${{ env.AWS_REGION }} + - name: Stop EC2 runner + uses: machulav/ec2-github-runner@a6dbcefcf8a31a861f5e078bb153ed332130c512 # v2.4.3 + with: + mode: stop + github-token: ${{ secrets.AWS_GITHUB_TOKEN }} + label: ${{ needs.start-ec2-runner.outputs.label }} + ec2-instance-id: ${{ needs.start-ec2-runner.outputs.ec2-instance-id }} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/ci_ec2_reusable.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/ci_ec2_reusable.yml new file mode 100644 index 0000000000..5fbaf0b335 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/ci_ec2_reusable.yml @@ -0,0 +1,235 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: ci-ec2-reusable +permissions: + contents: read +on: + workflow_call: + inputs: + name: + type: string + description: Alternative name of instance + default: Graviton2 + ec2_instance_type: + type: string + description: Type if EC2 instance to benchmark on + default: t4g.small + ec2_ami: + type: string + description: Textual description of AMI + default: ubuntu-latest (aarch64) + ec2_ami_id: + type: string + description: AMI ID + default: ami-0e8c824f386e1de06 + ec2_volume_size: + type: string + default: "" + cflags: + type: string + description: Custom CFLAGS for compilation + default: "" + verbose: + description: Determine for the log verbosity + type: boolean + default: false + compile_mode: + type: string + description: either all, native, cross or none + default: all + opt: + type: string + description: either all, opt or no_opt + default: all + functest: + type: boolean + default: true + kattest: + type: boolean + default: true + acvptest: + type: boolean + default: true + lint: + type: boolean + default: true + test: + type: boolean + default: true + config_variations: + type: string + description: List of configuration variation tests to run (space-separated IDs) or empty for no tests + default: '' + cbmc: + type: boolean + default: false + slothy: + type: boolean + default: false + cbmc_mldsa_parameter_set: + type: string + default: 44 +env: + AWS_ROLE: arn:aws:iam::904233116199:role/mldsa-native-ci + AWS_REGION: us-east-1 + AMI_UBUNTU_LATEST_X86_64: ami-084568db4383264d4 + AMI_UBUNTU_LATEST_AARCH64: ami-0c4e709339fa8521a +jobs: + start-ec2-runner: + name: Start instance (${{ inputs.ec2_instance_type }}) + permissions: + contents: 'read' + id-token: 'write' + runs-on: ubuntu-latest + if: ${{ always() }} # The point is to make this step non-cancellable, + # avoiding race conditions where an instance is started, + # but isn't yet done registering as a runner and reporting back. + outputs: + label: ${{ steps.remember-runner.outputs.label }} + ec2-instance-id: ${{ steps.remember-runner.outputs.ec2-instance-id }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: Determine AMI ID + id: det_ami_id + run: | + if [[ "${{ inputs.ec2_ami }}" == "ubuntu-latest (x86_64)" ]]; then + AMI_ID=${{ env.AMI_UBUNTU_LATEST_X86_64 }} + elif [[ "${{ inputs.ec2_ami }}" == "ubuntu-latest (aarch64)" ]]; then + AMI_ID=${{ env.AMI_UBUNTU_LATEST_AARCH64 }} + elif [[ "${{ inputs.ec2_ami }}" == "ubuntu-latest (custom AMI)" ]]; then + AMI_ID=${{ inputs.ec2_ami_id }} + fi + echo "Using AMI ID: $AMI_ID" + echo "AMI_ID=$AMI_ID" >> $GITHUB_OUTPUT + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@00943011d9042930efac3dcd3a170e4273319bc8 # v5.1.0 + with: + role-to-assume: ${{ env.AWS_ROLE }} + aws-region: ${{ env.AWS_REGION }} + - name: Start EC2 runner + id: start-ec2-runner-first + continue-on-error: true + uses: machulav/ec2-github-runner@a6dbcefcf8a31a861f5e078bb153ed332130c512 # v2.4.3 + with: + mode: start + github-token: ${{ secrets.AWS_GITHUB_TOKEN }} + ec2-image-id: ${{ steps.det_ami_id.outputs.AMI_ID }} + ec2-volume-size: ${{ inputs.ec2_volume_size }} + ec2-instance-type: ${{ inputs.ec2_instance_type }} + subnet-id: subnet-094d73eb42eb6bf5b + security-group-id: sg-0282706dbc92a1579 + - name: Start EC2c runner (wait before retry) + if: steps.start-ec2-runner-first.outcome == 'failure' + shell: bash + run: | + sleep 30 # Wait 30s before retrying + sleep $((1 + RANDOM % 30)) + - name: Start EC2 runner (retry) + id: start-ec2-runner-second + if: steps.start-ec2-runner-first.outcome == 'failure' + uses: machulav/ec2-github-runner@a6dbcefcf8a31a861f5e078bb153ed332130c512 # v2.4.3 + with: + mode: start + github-token: ${{ secrets.AWS_GITHUB_TOKEN }} + ec2-image-id: ${{ steps.det_ami_id.outputs.AMI_ID }} + ec2-volume-size: ${{ inputs.ec2_volume_size }} + ec2-instance-type: ${{ inputs.ec2_instance_type }} + subnet-id: subnet-094d73eb42eb6bf5b + security-group-id: sg-0282706dbc92a1579 + - name: Remember runner + id: remember-runner + shell: bash + run: | + if [[ "${{ steps.start-ec2-runner-first.outcome }}" == "failure" ]]; then + echo "label=${{ steps.start-ec2-runner-second.outputs.label }}" >> "$GITHUB_OUTPUT" + echo "ec2-instance-id=${{ steps.start-ec2-runner-second.outputs.ec2-instance-id }}" >> "$GITHUB_OUTPUT" + else + echo "label=${{ steps.start-ec2-runner-first.outputs.label }}" >> "$GITHUB_OUTPUT" + echo "ec2-instance-id=${{ steps.start-ec2-runner-first.outputs.ec2-instance-id }}" >> "$GITHUB_OUTPUT" + fi + + tests: + name: Run tests + needs: start-ec2-runner + runs-on: ${{ needs.start-ec2-runner.outputs.label }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: Linting + if: ${{ inputs.lint }} + uses: ./.github/actions/lint + with: + nix-shell: ci-linter + gh_token: ${{ secrets.AWS_GITHUB_TOKEN }} + nix-verbose: ${{ inputs.verbose }} + - name: Functional Tests + if: ${{ inputs.test }} + uses: ./.github/actions/multi-functest + with: + nix-shell: ${{ (inputs.compile_mode == 'cross' || inputs.compile_mode == 'all') && 'ci-cross' || 'ci' }} + nix-cache: ${{ inputs.cbmc || inputs.compile_mode == 'cross' || inputs.compile_mode == 'all' }} + nix-verbose: ${{ inputs.verbose }} + gh_token: ${{ secrets.AWS_GITHUB_TOKEN }} + cflags: ${{ inputs.cflags }} + compile_mode: ${{ inputs.compile_mode }} + opt: ${{ inputs.opt }} + func: ${{ inputs.functest }} + kat: ${{ inputs.kattest }} + acvp: ${{ inputs.acvptest }} + - name: Config Variations + if: ${{ inputs.config_variations != '' && (success() || failure()) }} + uses: ./.github/actions/config-variations + with: + gh_token: ${{ secrets.AWS_GITHUB_TOKEN }} + tests: ${{ inputs.config_variations }} + opt: opt + - name: CBMC + if: ${{ inputs.cbmc && (success() || failure()) }} + uses: ./.github/actions/cbmc + with: + nix-shell: ci-cbmc + nix-verbose: ${{ inputs.verbose }} + mldsa_parameter_set: ${{ inputs.cbmc_mldsa_parameter_set }} + gh_token: ${{ secrets.AWS_GITHUB_TOKEN }} + - name: SLOTHY + if: ${{ inputs.slothy }} + uses: ./.github/actions/setup-shell + with: + gh_token: ${{ secrets.AWS_GITHUB_TOKEN }} + nix-cache: true + nix-shell: ci-slothy + script: | + autogen --slothy + tests all --opt opt + # Force testing of SLOTHY-optimized Keccak variants + # We can't run the examples here because some of them also specify the backend + make clean + tests all --no-examples --opt opt --cflags="-DMLD_CONFIG_FIPS202_BACKEND_FILE=\\\"fips202/native/aarch64/x1_scalar.h\\\"" + make clean + tests all --no-examples --opt opt --cflags="-DMLD_CONFIG_FIPS202_BACKEND_FILE=\\\"fips202/native/aarch64/x4_v8a_scalar.h\\\"" + make clean + tests all --no-examples --opt opt --cflags="-march=armv8.4-a+sha3 -DMLD_CONFIG_FIPS202_BACKEND_FILE=\\\"fips202/native/aarch64/x4_v8a_v84a_scalar.h\\\"" + stop-ec2-runner: + name: Stop instance (${{ inputs.ec2_instance_type }}) + permissions: + contents: 'read' + id-token: 'write' + needs: + - start-ec2-runner + - tests + runs-on: ubuntu-latest + if: ${{ always() }} # required to stop the runner even if the error happened in the previous jobs + steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@00943011d9042930efac3dcd3a170e4273319bc8 # v5.1.0 + with: + role-to-assume: ${{ env.AWS_ROLE }} + aws-region: ${{ env.AWS_REGION }} + - name: Stop EC2 runner + uses: machulav/ec2-github-runner@a6dbcefcf8a31a861f5e078bb153ed332130c512 # v2.4.3 + with: + mode: stop + github-token: ${{ secrets.AWS_GITHUB_TOKEN }} + label: ${{ needs.start-ec2-runner.outputs.label }} + ec2-instance-id: ${{ needs.start-ec2-runner.outputs.ec2-instance-id }} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/ct-tests.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/ct-tests.yml new file mode 100644 index 0000000000..2163e4dc84 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/ct-tests.yml @@ -0,0 +1,92 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Constant-time tests +permissions: + contents: read +on: + workflow_call: + workflow_dispatch: + +jobs: + check-ct-varlat: + # Using the patched Valgrind from the KyberSlash paper to detect divisions + # In case the patch no longer applies after an update, we may want to switch back + # to stock valgrind added in https://github.com/pq-code-package/mlkem-native/pull/687 + name: CT test ${{ matrix.nix-shell }} ${{ matrix.system }} + strategy: + fail-fast: false + max-parallel: 10 + matrix: + system: [ubuntu-latest, ubuntu-24.04-arm] + nix-shell: + - ci_valgrind-varlat_clang14 + - ci_valgrind-varlat_clang15 + - ci_valgrind-varlat_clang16 + - ci_valgrind-varlat_clang17 + - ci_valgrind-varlat_clang18 + - ci_valgrind-varlat_clang19 + - ci_valgrind-varlat_clang20 + - ci_valgrind-varlat_clang21 + - ci_valgrind-varlat_gcc48 + - ci_valgrind-varlat_gcc49 + - ci_valgrind-varlat_gcc7 + - ci_valgrind-varlat_gcc11 + - ci_valgrind-varlat_gcc12 + - ci_valgrind-varlat_gcc13 + - ci_valgrind-varlat_gcc14 + - ci_valgrind-varlat_gcc15 + runs-on: ${{ matrix.system }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: Setup nix + uses: ./.github/actions/setup-shell + with: + gh_token: ${{ secrets.GITHUB_TOKEN }} + nix-shell: ${{ matrix.nix-shell }} + nix-cache: true + - name: Build and run test (-Oz) + # -Oz got introduced in gcc12 + if: ${{ matrix.nix-shell != 'ci_valgrind-varlat_gcc48' && matrix.nix-shell != 'ci_valgrind-varlat_gcc49' && matrix.nix-shell != 'ci_valgrind-varlat_gcc7' && matrix.nix-shell != 'ci_valgrind-varlat_gcc11'}} + uses: ./.github/actions/ct-test + with: + cflags: -Oz -DMLD_CONFIG_KEYGEN_PCT + valgrind_flags: --variable-latency-errors=yes + - name: Build and run test (-Os) + uses: ./.github/actions/ct-test + with: + cflags: -Os -DMLD_CONFIG_KEYGEN_PCT + valgrind_flags: --variable-latency-errors=yes + - name: Build and run test (-O3) + uses: ./.github/actions/ct-test + with: + cflags: -O3 -DMLD_CONFIG_KEYGEN_PCT + valgrind_flags: --variable-latency-errors=yes + - name: Build and run test (-Ofast) + # -Ofast got deprecated in clang19; -O3 -ffast-math should be used instead + if: ${{ matrix.nix-shell != 'ci_valgrind-varlat_clang19' && matrix.nix-shell != 'ci_valgrind-varlat_clang20' && matrix.nix-shell != 'ci_valgrind-varlat_clang21'}} + uses: ./.github/actions/ct-test + with: + cflags: -Ofast -DMLD_CONFIG_KEYGEN_PCT + valgrind_flags: --variable-latency-errors=yes + - name: Build and run test (-O3 -ffast-math) + uses: ./.github/actions/ct-test + with: + cflags: -O3 -ffast-math -DMLD_CONFIG_KEYGEN_PCT + valgrind_flags: --variable-latency-errors=yes + - name: Build and run test (-O2) + uses: ./.github/actions/ct-test + with: + cflags: -O2 -DMLD_CONFIG_KEYGEN_PCT + valgrind_flags: --variable-latency-errors=yes + - name: Build and run test (-O1) + uses: ./.github/actions/ct-test + with: + cflags: -O1 -DMLD_CONFIG_KEYGEN_PCT + valgrind_flags: --variable-latency-errors=yes + - name: Build and run test (-O0) + uses: ./.github/actions/ct-test + with: + cflags: -O0 -DMLD_CONFIG_KEYGEN_PCT + valgrind_flags: --variable-latency-errors=yes diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/hol_light.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/hol_light.yml new file mode 100644 index 0000000000..3a91bac55a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/hol_light.yml @@ -0,0 +1,115 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: HOL-Light +permissions: + contents: read +on: + push: + branches: ["main"] + paths: + - '.github/workflows/hol_light.yml' + - 'proofs/hol_light/x86_64/Makefile' + - 'proofs/hol_light/x86_64/**/*.S' + - 'proofs/hol_light/x86_64/**/*.ml' + - 'nix/hol_light/*' + - 'nix/s2n_bignum/*' + pull_request: + branches: ["main"] + paths: + - '.github/workflows/hol_light.yml' + - 'proofs/hol_light/x86_64/Makefile' + - 'proofs/hol_light/x86_64/**/*.S' + - 'proofs/hol_light/x86_64/**/*.ml' + - 'nix/hol_light/*' + - 'nix/s2n_bignum/*' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + # The proofs also check that the byte code is up to date, + # but we use this as a fast path to not even start the proofs + # if the byte code needs updating. + hol_light_bytecode: + name: HOL-Light bytecode check + runs-on: pqcp-x64 + if: github.repository_owner == 'pq-code-package' && !github.event.pull_request.head.repo.fork + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + fetch-depth: 0 + - uses: ./.github/actions/setup-shell + with: + gh_token: ${{ secrets.GITHUB_TOKEN }} + nix-shell: 'hol_light' + script: | + autogen --update-hol-light-bytecode --dry-run + hol_light_interactive: + name: HOL-Light interactive shell test + runs-on: pqcp-x64 + needs: [ hol_light_bytecode ] + if: github.repository_owner == 'pq-code-package' && !github.event.pull_request.head.repo.fork + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + fetch-depth: 0 + - uses: ./.github/actions/setup-shell + with: + gh_token: ${{ secrets.GITHUB_TOKEN }} + nix-shell: 'hol_light' + script: | + # Load base infrastructure and specs to validate HOL-Light environment + # When we have smaller/faster proofs, we can run them here instead: + # make -C proofs/hol_light/x86_64 mldsa/mldsa_ntt.o + # echo 'needs "proofs/mldsa_ntt.ml";;' | hol.sh + echo 'needs "x86/proofs/base.ml";; needs "proofs/mldsa_specs.ml";; #quit;;' | hol.sh + hol_light_proofs: + needs: [ hol_light_bytecode ] + strategy: + fail-fast: false + matrix: + proof: + # Dependencies on {name}.{S,ml} are implicit + - name: mldsa_ntt + needs: ["mldsa_specs.ml", "mldsa_utils.ml", "mldsa_zetas.ml"] + name: HOL Light proof for ${{ matrix.proof.name }}.S + runs-on: pqcp-x64 + if: github.repository_owner == 'pq-code-package' && !github.event.pull_request.head.repo.fork + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + fetch-depth: 0 + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 + - name: Check if dependencies changed + id: check_run + shell: bash + run: | + run_needed=0 + changed_files="${{ steps.changed-files.outputs.all_changed_files }}" + dependencies="${{ join(matrix.proof.needs, ' ') }} ${{ format('{0}.S {0}.ml', matrix.proof.name) }}" + for changed in $changed_files; do + for needs in $dependencies; do + if [[ "$changed" == *"$needs" ]]; then + run_needed=1 + fi + done + done + + # Always re-run upon change to nix files for HOL-Light + if [[ "$changed_files" == *"nix/"* ]] || [[ "$changed_files" == *"hol_light.yml"* ]] || [[ "$changed_files" == *"flake"* ]] || [[ "$changed_files" == *"proofs/hol_light/x86_64/Makefile"* ]]; then + run_needed=1 + fi + + echo "run_needed=${run_needed}" >> $GITHUB_OUTPUT + - uses: ./.github/actions/setup-shell + if: | + steps.check_run.outputs.run_needed == '1' + with: + gh_token: ${{ secrets.GITHUB_TOKEN }} + nix-shell: 'hol_light' + script: | + tests hol_light -p ${{ matrix.proof.name }} --verbose diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/integration-liboqs.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/integration-liboqs.yml new file mode 100644 index 0000000000..a4c4a6b427 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/integration-liboqs.yml @@ -0,0 +1,84 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Test liboqs integration +permissions: + contents: read +on: + workflow_call: + workflow_dispatch: + +jobs: + oqs_basic_build: + strategy: + fail-fast: false + matrix: + include: + # x86 + - system: ubuntu-latest + name: Haswell + # ubuntu-latest has AVX512 instructions that are not supported by valgrind + # We need to explicitly compile for an older uarch to workaround the valgrind failures + # TODO: switch this back to auto once valgrind supports AVX512 well + flags: -DOQS_DIST_BUILD=OFF -DOQS_OPT_TARGET=haswell -DCMAKE_BUILD_TYPE=Debug -DOQS_ENABLE_TEST_CONSTANT_TIME=ON + - system: ubuntu-latest + name: C + flags: -DOQS_DIST_BUILD=OFF -DOQS_OPT_TARGET=generic -DCMAKE_BUILD_TYPE=Debug -DOQS_ENABLE_TEST_CONSTANT_TIME=ON + # AArch64 + - system: ubuntu-24.04-arm + name: Auto + flags: -DOQS_DIST_BUILD=OFF -DOQS_OPT_TARGET=auto -DCMAKE_BUILD_TYPE=Debug -DOQS_ENABLE_TEST_CONSTANT_TIME=ON + - system: ubuntu-24.04-arm + name: C + flags: -DOQS_DIST_BUILD=OFF -DOQS_OPT_TARGET=generic -DCMAKE_BUILD_TYPE=Debug -DOQS_ENABLE_TEST_CONSTANT_TIME=ON + name: Build (${{ matrix.name }}, ${{ matrix.system }}) + runs-on: ${{ matrix.system }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: ./.github/actions/setup-os + with: + packages: 'cmake python3-jinja2 python3-tabulate python3-git python3-pytest valgrind' + - uses: ./.github/actions/setup-oqs + with: + # TODO: change to upstream once mldsa-native got merged + commit: 'e66470560d396ce32ec8ab0f2c953a7624fd70a8' + repository: 'mkannwischer/liboqs' + - name: Apply patch + run: | + cd $LIBOQS_DIR + # Adjust commit in importer script + sed -i "/name: mldsa-native/,/preserve_folder_structure/s%git_url: .*%git_url: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY%" scripts/copy_from_upstream/copy_from_upstream.yml + sed -i "/name: mldsa-native/,/preserve_folder_structure/s/git_branch: .*/git_branch: $GITHUB_SHA/" scripts/copy_from_upstream/copy_from_upstream.yml + sed -i "/name: mldsa-native/,/preserve_folder_structure/s/git_commit: .*/git_commit: $GITHUB_SHA/" scripts/copy_from_upstream/copy_from_upstream.yml + + # TODO: Remove one it has been removed upstream + # Remove CT test suppressions + echo "" > tests/constant_time/sig/passes/ml_dsa + echo "" > tests/constant_time/sig/passes/ml_dsa-avx2 + + # Temporarily remove oldpqclean because of build failures in its SHA3 assembly + yq e -i 'del(.kems[] | select(.name == "kyber"))' scripts/copy_from_upstream/copy_from_upstream.yml + yq e -i 'del(.sigs[] | select(.name == "dilithium"))' scripts/copy_from_upstream/copy_from_upstream.yml + git diff >> $GITHUB_STEP_SUMMARY; + - name: Configure + run: | + cd $LIBOQS_DIR + git config --global user.name "pqcp_ci" + git config --global user.email "ci@pqcp.org" + git config --global --add safe.directory "$LIBOQS_DIR" + - name: Import mldsa-native + run: | + cd $LIBOQS_DIR/scripts/copy_from_upstream + ./copy_from_upstream.py copy + - name: Build libOQS + run: | + cd $LIBOQS_DIR + mkdir build + cd build + cmake ${{ matrix.flags }} .. + make -j$(nproc) + - name: Run ML-DSA test + run: | + cd $LIBOQS_DIR + python3 -m pytest -k ML-DSA diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/lint_markdown.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/lint_markdown.yml new file mode 100644 index 0000000000..b158d8731c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/lint_markdown.yml @@ -0,0 +1,19 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Lint-Markdown +permissions: + contents: read +on: + workflow_call: + workflow_dispatch: + +jobs: + lint-markdown-link: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: Check markdown links + run: | + npm install -g markdown-link-check@3.14.2 + find . -name '*.md' -print0 | xargs -0 -P16 -n1 markdown-link-check -q diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/nix.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/nix.yml new file mode 100644 index 0000000000..82b53c3e3b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/nix.yml @@ -0,0 +1,144 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Nix +permissions: + contents: read +on: + workflow_call: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + check_modified_files: + runs-on: ubuntu-latest + outputs: + run_needed: ${{ steps.check_run.outputs.run_needed }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + if: github.event_name != 'workflow_dispatch' + with: + fetch-depth: 0 + - name: Get changed files + if: github.event_name != 'workflow_dispatch' + id: changed-files + uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 + - name: Check if dependencies changed + id: check_run + shell: bash + run: | + if [[ ${{ (github.event_name == 'workflow_dispatch' && '1') || '0' }} == "1" ]]; then + run_needed=1 + else + run_needed=0 + changed_files="${{ steps.changed-files.outputs.all_changed_files }}" + dependencies="flake.lock flake.nix nix/" + for changed in $changed_files; do + for needs in $dependencies; do + if [[ "$changed" == "$needs"* ]]; then + run_needed=1 + fi + done + done + fi + echo "run_needed=${run_needed}" >> $GITHUB_OUTPUT + + build_nix_cache: + needs: [ check_modified_files ] + if: ${{ needs.check_modified_files.outputs.run_needed == '1' && github.ref == 'refs/heads/main' }} + permissions: + actions: 'write' + contents: 'read' + strategy: + fail-fast: false + matrix: + runner: [ ubuntu-24.04, ubuntu-24.04-arm, macos-latest ] + name: build nix cache (${{ matrix.runner }}) + runs-on: ${{ matrix.runner }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: ./.github/actions/setup-nix + with: + cache: true + verbose: true + save_cache: true + devShell: ci + gh_token: ${{ secrets.GITHUB_TOKEN }} + script: | + # We only run cross-compilation checks for x86 on macos-latest, + # so restrict caching to the corresponding cross shell. + if [[ ${{ runner.os }} == 'macOS' ]]; then + nix develop .#ci-cross-x86_64 --profile tmp-cross + else + nix develop .#ci-cross --profile tmp-cross + # GH ubuntu-24.04 image tend to run outof space + if [[ ${{ matrix.runner }} == 'ubuntu-24.04' ]]; then + nix-collect-garbage + fi + fi + nix develop --profile tmp + nix-collect-garbage + develop_environment: + needs: [ check_modified_files ] + if: ${{ needs.check_modified_files.outputs.run_needed == '1' }} + strategy: + fail-fast: false + matrix: + target: + # nixpkgs requires 2.18 since August 2025, see + # https://github.com/NixOS/nixpkgs/pull/428076 + # TODO: Re-enable tests on Ubuntu 22 once nix has been updated to >= 2.18 + # - runner: ubuntu-22.04 + # container: + # install: 'apt' + - runner: ubuntu-latest + container: nixos/nix:2.18.0 + install: 'native' + - runner: ubuntu-24.04 + container: + install: 'apt' + - runner: macos-latest + container: + install: 'installer' + - runner: ubuntu-22.04 + container: + install: 'installer' + - runner: ubuntu-24.04 + container: + install: 'installer' + name: nix setup test (${{ matrix.target.container != '' && matrix.target.container || matrix.target.runner }}, nix via ${{ matrix.target.install }}) + runs-on: ${{ matrix.target.runner }} + container: + ${{ matrix.target.container }} + steps: + - name: Install git + shell: bash + run: | + if ! which git 2>&1 >/dev/null; then + ${{ matrix.target.container == '' && 'sudo' || '' }} apt update + ${{ matrix.target.container == '' && 'sudo' || '' }} apt install git -y + fi + - name: Manual checkout + shell: bash + run: | + git init + git config --global --add safe.directory $GITHUB_WORKSPACE + git remote add origin $GITHUB_SERVER_URL/$GITHUB_REPOSITORY + git fetch origin --depth 1 $GITHUB_SHA + git checkout FETCH_HEAD + - uses: ./.github/actions/setup-nix + if: ${{ matrix.target.container == '' }} + with: + gh_token: ${{ secrets.GITHUB_TOKEN }} + devShell: default + verbose: true + cache: true + install: ${{ matrix.target.install }} + - name: nix develop (in container) + if: ${{ matrix.target.container != '' }} + run: | + nix develop --experimental-features "nix-command flakes" --access-tokens "github.com=${{ secrets.GITHUB_TOKEN }}" diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/scorecard.yaml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/scorecard.yaml new file mode 100644 index 0000000000..5938ff3ad0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/scorecard.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: OSSF Scorecard analysis +on: + # Only the default branch is supported. + branch_protection_rule: + schedule: + # Weekly on Saturdays. + - cron: '30 1 * * 6' + push: + branches: [ main ] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Needed if using Code scanning alerts + security-events: write + # Needed for GitHub OIDC token if publish_results is true + id-token: write + + steps: + - name: "Checkout code" + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 + with: + results_file: results.sarif + results_format: sarif + # (Optional) fine-grained personal access token. Uncomment the `repo_token` line below if: + # - you want to enable the Branch-Protection check on a *public* repository, or + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-fine-grained-pat-optional. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + + # Publish the results for public repositories to enable scorecard badges. For more details, see + # https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories, `publish_results` will automatically be set to `false`, regardless + # of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # required for Code scanning alerts + - name: "Upload SARIF results to code scanning" + uses: github/codeql-action/upload-sarif@592977e6ae857384aa79bb31e7a1d62d63449ec5 # v2.16.3 + with: + sarif_file: results.sarif diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/slothy.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/slothy.yml new file mode 100644 index 0000000000..191061ff59 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.github/workflows/slothy.yml @@ -0,0 +1,29 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: SLOTHY re-optimization tests +permissions: + contents: read +on: + workflow_call: + workflow_dispatch: + +jobs: + slothy: + name: SLOTHY + if: ${{ github.repository_owner == 'pq-code-package' && !github.event.pull_request.head.repo.fork }} + permissions: + contents: 'read' + id-token: 'write' + uses: ./.github/workflows/ci_ec2_reusable.yml + with: + name: SLOTHY + ec2_instance_type: c8g.8xlarge + ec2_ami: ubuntu-latest (aarch64) + ec2_volume_size: 20 + lint: false + test: false + cbmc: false + slothy: true + secrets: inherit diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/.gitignore b/tf-psa-crypto/drivers/pqcp/mldsa-native/.gitignore new file mode 100644 index 0000000000..f661f70f41 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/.gitignore @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +test/build +.direnv +# Downloaded ACVP test data +test/acvp/.acvp-data/ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/BIBLIOGRAPHY.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/BIBLIOGRAPHY.md new file mode 100644 index 0000000000..515c7fc5cc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/BIBLIOGRAPHY.md @@ -0,0 +1,371 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) +[//]: # (This file is auto-generated from BIBLIOGRAPHY.yml) +[//]: # (Do not modify it directly) + +# Bibliography + +This file lists the citations made throughout the mldsa-native +source code and documentation. + +### `ACVP` + +* Automated Cryptographic Validation Protocol (ACVP) Server +* Author(s): + - National Institute of Standards and Technology +* URL: https://github.com/usnistgov/ACVP-Server +* Referenced from: + - [README.md](README.md) + +### `FIPS140_3_IG` + +* Implementation Guidance for FIPS 140-3 and the Cryptographic Module Validation Program +* Author(s): + - National Institute of Standards and Technology +* URL: https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements +* Referenced from: + - [examples/basic_deterministic/mldsa_native/mldsa_native_config.h](examples/basic_deterministic/mldsa_native/mldsa_native_config.h) + - [examples/basic_lowram/mldsa_native/mldsa_native_config.h](examples/basic_lowram/mldsa_native/mldsa_native_config.h) + - [examples/bring_your_own_fips202/mldsa_native/mldsa_native_config.h](examples/bring_your_own_fips202/mldsa_native/mldsa_native_config.h) + - [examples/bring_your_own_fips202_static/mldsa_native/mldsa_native_config.h](examples/bring_your_own_fips202_static/mldsa_native/mldsa_native_config.h) + - [examples/custom_backend/mldsa_native/mldsa_native_config.h](examples/custom_backend/mldsa_native/mldsa_native_config.h) + - [examples/monolithic_build/mldsa_native/mldsa_native_config.h](examples/monolithic_build/mldsa_native/mldsa_native_config.h) + - [examples/monolithic_build_multilevel/mldsa_native/mldsa_native_config.h](examples/monolithic_build_multilevel/mldsa_native/mldsa_native_config.h) + - [examples/monolithic_build_multilevel_native/mldsa_native/mldsa_native_config.h](examples/monolithic_build_multilevel_native/mldsa_native/mldsa_native_config.h) + - [examples/monolithic_build_native/mldsa_native/mldsa_native_config.h](examples/monolithic_build_native/mldsa_native/mldsa_native_config.h) + - [examples/multilevel_build/mldsa_native/mldsa_native_config.h](examples/multilevel_build/mldsa_native/mldsa_native_config.h) + - [examples/multilevel_build_native/mldsa_native/mldsa_native_config.h](examples/multilevel_build_native/mldsa_native/mldsa_native_config.h) + - [integration/liboqs/config_aarch64.h](integration/liboqs/config_aarch64.h) + - [integration/liboqs/config_c.h](integration/liboqs/config_c.h) + - [integration/liboqs/config_x86_64.h](integration/liboqs/config_x86_64.h) + - [mldsa/mldsa_native_config.h](mldsa/mldsa_native_config.h) + - [mldsa/src/sign.c](mldsa/src/sign.c) + - [test/configs/break_pct_config.h](test/configs/break_pct_config.h) + - [test/configs/custom_heap_alloc_config.h](test/configs/custom_heap_alloc_config.h) + - [test/configs/custom_memcpy_config.h](test/configs/custom_memcpy_config.h) + - [test/configs/custom_memset_config.h](test/configs/custom_memset_config.h) + - [test/configs/custom_native_capability_config_0.h](test/configs/custom_native_capability_config_0.h) + - [test/configs/custom_native_capability_config_1.h](test/configs/custom_native_capability_config_1.h) + - [test/configs/custom_native_capability_config_CPUID_AVX2.h](test/configs/custom_native_capability_config_CPUID_AVX2.h) + - [test/configs/custom_native_capability_config_ID_AA64PFR1_EL1.h](test/configs/custom_native_capability_config_ID_AA64PFR1_EL1.h) + - [test/configs/custom_randombytes_config.h](test/configs/custom_randombytes_config.h) + - [test/configs/custom_stdlib_config.h](test/configs/custom_stdlib_config.h) + - [test/configs/custom_zeroize_config.h](test/configs/custom_zeroize_config.h) + - [test/configs/no_asm_config.h](test/configs/no_asm_config.h) + - [test/configs/serial_fips202_config.h](test/configs/serial_fips202_config.h) + - [test/configs/test_alloc_config.h](test/configs/test_alloc_config.h) + +### `FIPS202` + +* FIPS202 SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions +* Author(s): + - National Institute of Standards and Technology +* URL: https://csrc.nist.gov/pubs/fips/202/final +* Referenced from: + - [FIPS202.md](FIPS202.md) + - [README.md](README.md) + +### `FIPS204` + +* FIPS 204 Module-Lattice-Based Digital Signature Standard +* Author(s): + - National Institute of Standards and Technology +* URL: https://csrc.nist.gov/pubs/fips/204/final +* Referenced from: + - [README.md](README.md) + - [examples/basic_deterministic/mldsa_native/mldsa_native_config.h](examples/basic_deterministic/mldsa_native/mldsa_native_config.h) + - [examples/basic_lowram/mldsa_native/mldsa_native_config.h](examples/basic_lowram/mldsa_native/mldsa_native_config.h) + - [examples/bring_your_own_fips202/mldsa_native/mldsa_native_config.h](examples/bring_your_own_fips202/mldsa_native/mldsa_native_config.h) + - [examples/bring_your_own_fips202_static/mldsa_native/mldsa_native_config.h](examples/bring_your_own_fips202_static/mldsa_native/mldsa_native_config.h) + - [examples/custom_backend/mldsa_native/mldsa_native_config.h](examples/custom_backend/mldsa_native/mldsa_native_config.h) + - [examples/monolithic_build/mldsa_native/mldsa_native_config.h](examples/monolithic_build/mldsa_native/mldsa_native_config.h) + - [examples/monolithic_build_multilevel/mldsa_native/mldsa_native_config.h](examples/monolithic_build_multilevel/mldsa_native/mldsa_native_config.h) + - [examples/monolithic_build_multilevel_native/mldsa_native/mldsa_native_config.h](examples/monolithic_build_multilevel_native/mldsa_native/mldsa_native_config.h) + - [examples/monolithic_build_native/mldsa_native/mldsa_native_config.h](examples/monolithic_build_native/mldsa_native/mldsa_native_config.h) + - [examples/multilevel_build/mldsa_native/mldsa_native_config.h](examples/multilevel_build/mldsa_native/mldsa_native_config.h) + - [examples/multilevel_build_native/mldsa_native/mldsa_native_config.h](examples/multilevel_build_native/mldsa_native/mldsa_native_config.h) + - [mldsa/mldsa_native.h](mldsa/mldsa_native.h) + - [mldsa/mldsa_native_config.h](mldsa/mldsa_native_config.h) + - [mldsa/src/ct.h](mldsa/src/ct.h) + - [mldsa/src/fips202/fips202.c](mldsa/src/fips202/fips202.c) + - [mldsa/src/fips202/fips202x4.c](mldsa/src/fips202/fips202x4.c) + - [mldsa/src/poly.c](mldsa/src/poly.c) + - [mldsa/src/poly_kl.c](mldsa/src/poly_kl.c) + - [mldsa/src/polyvec.c](mldsa/src/polyvec.c) + - [mldsa/src/rounding.h](mldsa/src/rounding.h) + - [mldsa/src/sign.c](mldsa/src/sign.c) + - [mldsa/src/sign.h](mldsa/src/sign.h) + - [test/configs/break_pct_config.h](test/configs/break_pct_config.h) + - [test/configs/custom_memcpy_config.h](test/configs/custom_memcpy_config.h) + - [test/configs/custom_memset_config.h](test/configs/custom_memset_config.h) + - [test/configs/custom_native_capability_config_0.h](test/configs/custom_native_capability_config_0.h) + - [test/configs/custom_native_capability_config_1.h](test/configs/custom_native_capability_config_1.h) + - [test/configs/custom_native_capability_config_CPUID_AVX2.h](test/configs/custom_native_capability_config_CPUID_AVX2.h) + - [test/configs/custom_native_capability_config_ID_AA64PFR1_EL1.h](test/configs/custom_native_capability_config_ID_AA64PFR1_EL1.h) + - [test/configs/custom_randombytes_config.h](test/configs/custom_randombytes_config.h) + - [test/configs/custom_stdlib_config.h](test/configs/custom_stdlib_config.h) + - [test/configs/custom_zeroize_config.h](test/configs/custom_zeroize_config.h) + - [test/configs/no_asm_config.h](test/configs/no_asm_config.h) + - [test/configs/serial_fips202_config.h](test/configs/serial_fips202_config.h) + - [test/configs/test_alloc_config.h](test/configs/test_alloc_config.h) + +### `HYBRID` + +* Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64 +* Author(s): + - Hanno Becker + - Matthias J. Kannwischer +* URL: https://eprint.iacr.org/2022/1243 +* Referenced from: + - [dev/fips202/aarch64/auto.h](dev/fips202/aarch64/auto.h) + - [dev/fips202/aarch64/src/keccak_f1600_x1_v84a_asm.S](dev/fips202/aarch64/src/keccak_f1600_x1_v84a_asm.S) + - [dev/fips202/aarch64/src/keccak_f1600_x2_v84a_asm.S](dev/fips202/aarch64/src/keccak_f1600_x2_v84a_asm.S) + - [mldsa/src/fips202/native/aarch64/auto.h](mldsa/src/fips202/native/aarch64/auto.h) + - [mldsa/src/fips202/native/aarch64/src/keccak_f1600_x1_v84a_asm.S](mldsa/src/fips202/native/aarch64/src/keccak_f1600_x1_v84a_asm.S) + - [mldsa/src/fips202/native/aarch64/src/keccak_f1600_x2_v84a_asm.S](mldsa/src/fips202/native/aarch64/src/keccak_f1600_x2_v84a_asm.S) + +### `KyberSlash` + +* KyberSlash: Exploiting secret-dependent division timings in Kyber implementations +* Author(s): + - Daniel J. Bernstein + - Karthikeyan Bhargavan + - Shivam Bhasin + - Anupam Chattopadhyay + - Tee Kiah Chia + - Matthias J. Kannwischer + - Franziskus Kiefer + - Thales Paiva + - Prasanna Ravi + - Goutam Tamvada +* URL: https://kyberslash.cr.yp.to/papers.html +* Referenced from: + - [nix/valgrind/README.md](nix/valgrind/README.md) + +### `NIST_FAQ` + +* Post-Quantum Cryptography FAQs +* Author(s): + - National Institute of Standards and Technology +* URL: https://csrc.nist.gov/Projects/post-quantum-cryptography/faqs#Rdc7 +* Referenced from: + - [README.md](README.md) + +### `NIST_FIPS204_SEC6` + +* FIPS 204 Section 6 Guidance +* Author(s): + - National Institute of Standards and Technology +* URL: https://csrc.nist.gov/csrc/media/Projects/post-quantum-cryptography/documents/faq/fips204-sec6-03192025.pdf +* Referenced from: + - [README.md](README.md) + +### `NeonNTT` + +* Neon NTT: Faster Dilithium, Kyber, and Saber on Cortex-A72 and Apple M1 +* Author(s): + - Hanno Becker + - Vincent Hwang + - Matthias J. Kannwischer + - Bo-Yin Yang + - Shang-Yi Yang +* URL: https://eprint.iacr.org/2021/986 +* Referenced from: + - [dev/aarch64_clean/src/intt.S](dev/aarch64_clean/src/intt.S) + - [dev/aarch64_clean/src/ntt.S](dev/aarch64_clean/src/ntt.S) + - [dev/aarch64_opt/README.md](dev/aarch64_opt/README.md) + - [dev/aarch64_opt/src/intt.S](dev/aarch64_opt/src/intt.S) + - [dev/aarch64_opt/src/ntt.S](dev/aarch64_opt/src/ntt.S) + - [mldsa/src/native/aarch64/src/intt.S](mldsa/src/native/aarch64/src/intt.S) + - [mldsa/src/native/aarch64/src/ntt.S](mldsa/src/native/aarch64/src/ntt.S) + +### `REF` + +* CRYSTALS-Dilithium reference implementation +* Author(s): + - Shi Bai + - Léo Ducas + - Eike Kiltz + - Tancrède Lepoint + - Vadim Lyubashevsky + - Peter Schwabe + - Gregor Seiler + - Damien Stehlé +* URL: https://github.com/pq-crystals/dilithium/tree/master/ref +* Referenced from: + - [README.md](README.md) + - [mldsa/src/poly.c](mldsa/src/poly.c) + - [mldsa/src/poly_kl.c](mldsa/src/poly_kl.c) + +### `REF_AVX2` + +* CRYSTALS-Dilithium optimized AVX2 implementation +* Author(s): + - Shi Bai + - Léo Ducas + - Eike Kiltz + - Tancrède Lepoint + - Vadim Lyubashevsky + - Peter Schwabe + - Gregor Seiler + - Damien Stehlé +* URL: https://github.com/pq-crystals/dilithium/tree/master/avx2 +* Referenced from: + - [dev/x86_64/src/intt.S](dev/x86_64/src/intt.S) + - [dev/x86_64/src/ntt.S](dev/x86_64/src/ntt.S) + - [dev/x86_64/src/nttunpack.S](dev/x86_64/src/nttunpack.S) + - [dev/x86_64/src/pointwise.S](dev/x86_64/src/pointwise.S) + - [dev/x86_64/src/pointwise_acc_l4.S](dev/x86_64/src/pointwise_acc_l4.S) + - [dev/x86_64/src/pointwise_acc_l5.S](dev/x86_64/src/pointwise_acc_l5.S) + - [dev/x86_64/src/pointwise_acc_l7.S](dev/x86_64/src/pointwise_acc_l7.S) + - [dev/x86_64/src/poly_caddq_avx2.c](dev/x86_64/src/poly_caddq_avx2.c) + - [dev/x86_64/src/poly_chknorm_avx2.c](dev/x86_64/src/poly_chknorm_avx2.c) + - [dev/x86_64/src/poly_decompose_32_avx2.c](dev/x86_64/src/poly_decompose_32_avx2.c) + - [dev/x86_64/src/poly_decompose_88_avx2.c](dev/x86_64/src/poly_decompose_88_avx2.c) + - [dev/x86_64/src/poly_use_hint_32_avx2.c](dev/x86_64/src/poly_use_hint_32_avx2.c) + - [dev/x86_64/src/poly_use_hint_88_avx2.c](dev/x86_64/src/poly_use_hint_88_avx2.c) + - [dev/x86_64/src/polyz_unpack_17_avx2.c](dev/x86_64/src/polyz_unpack_17_avx2.c) + - [dev/x86_64/src/polyz_unpack_19_avx2.c](dev/x86_64/src/polyz_unpack_19_avx2.c) + - [dev/x86_64/src/rej_uniform_avx2.c](dev/x86_64/src/rej_uniform_avx2.c) + - [dev/x86_64/src/rej_uniform_eta2_avx2.c](dev/x86_64/src/rej_uniform_eta2_avx2.c) + - [dev/x86_64/src/rej_uniform_eta4_avx2.c](dev/x86_64/src/rej_uniform_eta4_avx2.c) + - [mldsa/src/native/x86_64/src/intt.S](mldsa/src/native/x86_64/src/intt.S) + - [mldsa/src/native/x86_64/src/ntt.S](mldsa/src/native/x86_64/src/ntt.S) + - [mldsa/src/native/x86_64/src/nttunpack.S](mldsa/src/native/x86_64/src/nttunpack.S) + - [mldsa/src/native/x86_64/src/pointwise.S](mldsa/src/native/x86_64/src/pointwise.S) + - [mldsa/src/native/x86_64/src/pointwise_acc_l4.S](mldsa/src/native/x86_64/src/pointwise_acc_l4.S) + - [mldsa/src/native/x86_64/src/pointwise_acc_l5.S](mldsa/src/native/x86_64/src/pointwise_acc_l5.S) + - [mldsa/src/native/x86_64/src/pointwise_acc_l7.S](mldsa/src/native/x86_64/src/pointwise_acc_l7.S) + - [mldsa/src/native/x86_64/src/poly_caddq_avx2.c](mldsa/src/native/x86_64/src/poly_caddq_avx2.c) + - [mldsa/src/native/x86_64/src/poly_chknorm_avx2.c](mldsa/src/native/x86_64/src/poly_chknorm_avx2.c) + - [mldsa/src/native/x86_64/src/poly_decompose_32_avx2.c](mldsa/src/native/x86_64/src/poly_decompose_32_avx2.c) + - [mldsa/src/native/x86_64/src/poly_decompose_88_avx2.c](mldsa/src/native/x86_64/src/poly_decompose_88_avx2.c) + - [mldsa/src/native/x86_64/src/poly_use_hint_32_avx2.c](mldsa/src/native/x86_64/src/poly_use_hint_32_avx2.c) + - [mldsa/src/native/x86_64/src/poly_use_hint_88_avx2.c](mldsa/src/native/x86_64/src/poly_use_hint_88_avx2.c) + - [mldsa/src/native/x86_64/src/polyz_unpack_17_avx2.c](mldsa/src/native/x86_64/src/polyz_unpack_17_avx2.c) + - [mldsa/src/native/x86_64/src/polyz_unpack_19_avx2.c](mldsa/src/native/x86_64/src/polyz_unpack_19_avx2.c) + - [mldsa/src/native/x86_64/src/rej_uniform_avx2.c](mldsa/src/native/x86_64/src/rej_uniform_avx2.c) + - [mldsa/src/native/x86_64/src/rej_uniform_eta2_avx2.c](mldsa/src/native/x86_64/src/rej_uniform_eta2_avx2.c) + - [mldsa/src/native/x86_64/src/rej_uniform_eta4_avx2.c](mldsa/src/native/x86_64/src/rej_uniform_eta4_avx2.c) + - [proofs/hol_light/x86_64/mldsa/mldsa_ntt.S](proofs/hol_light/x86_64/mldsa/mldsa_ntt.S) + +### `Round3_Spec` + +* CRYSTALS-Dilithium Algorithm Specifications and Supporting Documentation (Version 3.1) +* Author(s): + - Shi Bai + - Léo Ducas + - Eike Kiltz + - Tancrède Lepoint + - Vadim Lyubashevsky + - Peter Schwabe + - Gregor Seiler + - Damien Stehlé +* URL: https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf +* Referenced from: + - [mldsa/src/sign.c](mldsa/src/sign.c) + +### `SLOTHY_Paper` + +* Fast and Clean: Auditable high-performance assembly via constraint solving +* Author(s): + - Amin Abdulrahman + - Hanno Becker + - Matthias J. Kannwischer + - Fabien Klein +* URL: https://eprint.iacr.org/2022/1303 +* Referenced from: + - [dev/aarch64_clean/src/intt.S](dev/aarch64_clean/src/intt.S) + - [dev/aarch64_clean/src/ntt.S](dev/aarch64_clean/src/ntt.S) + - [dev/aarch64_opt/README.md](dev/aarch64_opt/README.md) + - [dev/aarch64_opt/src/intt.S](dev/aarch64_opt/src/intt.S) + - [dev/aarch64_opt/src/ntt.S](dev/aarch64_opt/src/ntt.S) + - [mldsa/src/native/aarch64/src/intt.S](mldsa/src/native/aarch64/src/intt.S) + - [mldsa/src/native/aarch64/src/ntt.S](mldsa/src/native/aarch64/src/ntt.S) + +### `libmceliece` + +* libmceliece implementation of Classic McEliece +* Author(s): + - Daniel J. Bernstein + - Tung Chou +* URL: https://lib.mceliece.org/ +* Referenced from: + - [mldsa/src/ct.h](mldsa/src/ct.h) + +### `m1cycles` + +* Cycle counting on Apple M1 +* Author(s): + - Dougall Johnson +* URL: https://gist.github.com/dougallj/5bafb113492047c865c0c8cfbc930155#file-m1_robsize-c-L390 +* Referenced from: + - [test/hal/hal.c](test/hal/hal.c) + +### `mupq` + +* Common files for pqm4, pqm3, pqriscv +* Author(s): + - Matthias J. Kannwischer + - Richard Petri + - Joost Rijneveld + - Peter Schwabe + - Ko Stoffelen +* URL: https://github.com/mupq/mupq +* Referenced from: + - [mldsa/src/fips202/fips202.c](mldsa/src/fips202/fips202.c) + - [mldsa/src/fips202/keccakf1600.c](mldsa/src/fips202/keccakf1600.c) + +### `optblocker` + +* PQC forum post on opt-blockers using volatile globals +* Author(s): + - Daniel J. Bernstein +* URL: https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ +* Referenced from: + - [mldsa/src/ct.h](mldsa/src/ct.h) + +### `supercop` + +* SUPERCOP benchmarking framework +* Author(s): + - Daniel J. Bernstein +* URL: http://bench.cr.yp.to/supercop.html +* Referenced from: + - [mldsa/src/fips202/fips202.c](mldsa/src/fips202/fips202.c) + - [mldsa/src/fips202/keccakf1600.c](mldsa/src/fips202/keccakf1600.c) + +### `surf` + +* SURF: Simple Unpredictable Random Function +* Author(s): + - Daniel J. Bernstein +* URL: https://cr.yp.to/papers.html#surf +* Referenced from: + - [test/notrandombytes/notrandombytes.c](test/notrandombytes/notrandombytes.c) + - [test/notrandombytes/notrandombytes.h](test/notrandombytes/notrandombytes.h) + +### `tiny_sha3` + +* tiny_sha3 +* Author(s): + - Markku-Juhani O. Saarinen +* URL: https://github.com/mjosaarinen/tiny_sha3 +* Referenced from: + - [FIPS202.md](FIPS202.md) + - [README.md](README.md) + - [examples/bring_your_own_fips202/README.md](examples/bring_your_own_fips202/README.md) + - [examples/bring_your_own_fips202_static/README.md](examples/bring_your_own_fips202_static/README.md) + - [examples/bring_your_own_fips202_static/custom_fips202/README.md](examples/bring_your_own_fips202_static/custom_fips202/README.md) + - [examples/custom_backend/README.md](examples/custom_backend/README.md) + +### `tweetfips` + +* 'tweetfips202' FIPS202 implementation +* Author(s): + - Gilles Van Assche + - Daniel J. Bernstein + - Peter Schwabe +* URL: https://keccak.team/2015/tweetfips202.html +* Referenced from: + - [mldsa/src/fips202/fips202.c](mldsa/src/fips202/fips202.c) + - [mldsa/src/fips202/keccakf1600.c](mldsa/src/fips202/keccakf1600.c) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/BIBLIOGRAPHY.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/BIBLIOGRAPHY.yml new file mode 100644 index 0000000000..53a33b0f51 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/BIBLIOGRAPHY.yml @@ -0,0 +1,167 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +- id: ACVP + name: Automated Cryptographic Validation Protocol (ACVP) Server + author: National Institute of Standards and Technology + url: https://github.com/usnistgov/ACVP-Server + +- id: FIPS204 + short: FIPS 204 + name: "FIPS 204 Module-Lattice-Based Digital Signature Standard" + author: National Institute of Standards and Technology + url: https://csrc.nist.gov/pubs/fips/204/final + +- id: FIPS202 + short: FIPS 202 + name: "FIPS202 SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions" + author: National Institute of Standards and Technology + url: https://csrc.nist.gov/pubs/fips/202/final + +- id: NIST_FAQ + name: "Post-Quantum Cryptography FAQs" + author: National Institute of Standards and Technology + url: https://csrc.nist.gov/Projects/post-quantum-cryptography/faqs#Rdc7 + +- id: NIST_FIPS204_SEC6 + name: "FIPS 204 Section 6 Guidance" + author: National Institute of Standards and Technology + url: https://csrc.nist.gov/csrc/media/Projects/post-quantum-cryptography/documents/faq/fips204-sec6-03192025.pdf + +- id: REF + name: "CRYSTALS-Dilithium reference implementation" + author: + - Bai, Shi + - Ducas, Léo + - Kiltz, Eike + - Lepoint, Tancrède + - Lyubashevsky, Vadim + - Schwabe, Peter + - Seiler, Gregor + - Stehlé, Damien + url: https://github.com/pq-crystals/dilithium/tree/master/ref + +- id: REF_AVX2 + name: "CRYSTALS-Dilithium optimized AVX2 implementation" + author: + - Bai, Shi + - Ducas, Léo + - Kiltz, Eike + - Lepoint, Tancrède + - Lyubashevsky, Vadim + - Schwabe, Peter + - Seiler, Gregor + - Stehlé, Damien + url: https://github.com/pq-crystals/dilithium/tree/master/avx2 + +- id: KyberSlash + short: KyberSlash + name: "KyberSlash: Exploiting secret-dependent division timings in Kyber implementations" + author: + - Bernstein, Daniel J. + - Bhargavan, Karthikeyan + - Bhasin, Shivam + - Chattopadhyay, Anupam + - Chia, Tee Kiah + - Kannwischer, Matthias J. + - Kiefer, Franziskus + - Paiva, Thales + - Ravi, Prasanna + - Tamvada, Goutam + url: https://kyberslash.cr.yp.to/papers.html + +- id: FIPS140_3_IG + short: FIPS 140-3 IG + name: "Implementation Guidance for FIPS 140-3 and the Cryptographic Module Validation Program" + author: National Institute of Standards and Technology + url: https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + +- id: Round3_Spec + name: "CRYSTALS-Dilithium Algorithm Specifications and Supporting Documentation (Version 3.1)" + author: + - Bai, Shi + - Ducas, Léo + - Kiltz, Eike + - Lepoint, Tancrède + - Lyubashevsky, Vadim + - Schwabe, Peter + - Seiler, Gregor + - Stehlé, Damien + url: https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf + +- id: SLOTHY_Paper + name: "Fast and Clean: Auditable high-performance assembly via constraint solving" + short: SLOTHY paper + author: + - Abdulrahman, Amin + - Becker, Hanno + - Kannwischer, Matthias J. + - Klein, Fabien + url: https://eprint.iacr.org/2022/1303 + +- id: NeonNTT + name: "Neon NTT: Faster Dilithium, Kyber, and Saber on Cortex-A72 and Apple M1" + year: 2022 + url: https://eprint.iacr.org/2021/986 + author: + - Becker, Hanno + - Hwang, Vincent + - Kannwischer, Matthias J. + - Yang, Bo-Yin + - Yang, Shang-Yi +- id: mupq + name: Common files for pqm4, pqm3, pqriscv + author: + - Kannwischer, Matthias J. + - Petri, Richard + - Rijneveld, Joost + - Schwabe, Peter + - Stoffelen, Ko + url: https://github.com/mupq/mupq + +- id: supercop + name: SUPERCOP benchmarking framework + author: Bernstein, Daniel J. + url: http://bench.cr.yp.to/supercop.html + +- id: tweetfips + name: "'tweetfips202' FIPS202 implementation" + author: + - Van Assche, Gilles + - Bernstein, Daniel J. + - Schwabe, Peter + url: https://keccak.team/2015/tweetfips202.html + +- id: tiny_sha3 + name: tiny_sha3 + author: Saarinen, Markku-Juhani O. + url: https://github.com/mjosaarinen/tiny_sha3 + +- id: libmceliece + name: libmceliece implementation of Classic McEliece + author: + - Bernstein, Daniel J. + - Chou, Tung + url: https://lib.mceliece.org/ + +- id: optblocker + name: PQC forum post on opt-blockers using volatile globals + author: Bernstein, Daniel J. + url: https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ + +- id: HYBRID + name: "Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64" + author: + - Becker, Hanno + - Kannwischer, Matthias J. + url: https://eprint.iacr.org/2022/1243 + +- id: surf + name: "SURF: Simple Unpredictable Random Function" + author: Bernstein, Daniel J. + url: https://cr.yp.to/papers.html#surf + +- id: m1cycles + name: Cycle counting on Apple M1 + author: Johnson, Dougall + url: https://gist.github.com/dougallj/5bafb113492047c865c0c8cfbc930155#file-m1_robsize-c-L390 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/BUILDING.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/BUILDING.md new file mode 100644 index 0000000000..47d5454d17 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/BUILDING.md @@ -0,0 +1,105 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Building mldsa-native + +### Prerequisites + +To build **mldsa-native**, you need `make` and a C90 compiler. To use the test scripts, you need Python3 (>= 3.7). + +### By hand + +See [mldsa](mldsa). + +### Using `make` + +You can build and test **mldsa-native** as follows: + +```bash +make test # With native code backend (if available) +make OPT=0 test # With C backend +``` + +To merely build test components, use the following `make` targets: + +```bash +make func +make kat +make acvp +``` + +To run them, add `run_`: + +```bash +make run_func +make run_kat +make run_acvp +``` + +The resulting binaries can be found in `test/build` (their full path is printed by `make`). + +For benchmarking, specify the cycle counting method. Currently, **mldsa-native** is supporting NO, PERF, PMU, and MAC: +* `NO` means that no cycle counting will be used; this can be used to confirm that benchmarks compile fine. +* `PERF` uses the `perf` kernel module for cycle counting. Does not work on Apple platforms. +* `PMU` uses direct PMU access if available. On AArch64, this may require you to load a kernel module first, see [here](https://github.com/mupq/pqax?tab=readme-ov-file#enable-access-to-performance-counters). Does not work on Apple platforms. +* `MAC` is `perf`-based and works on some Apple platforms, at least Apple M1. + +``` +# CYCLES has to be one of PERF, PMU, MAC, NO +sudo make run_bench CYCLES=PERF +sudo make run_bench_components CYCLES=PERF +``` + +### Using `tests` script + +For convenience, you can also use the [`./scripts/tests`](scripts/tests) script as a wrapper around `make`. For +example, + +```bash +./scripts/tests func +``` + +will compile and run functionality tests. Similarly, + +```bash +./scripts/tests bench -c PERF -r +``` + +will compile and run benchmarks, using PERF for cycle counting (`-c PERF`) and running as root (`-r`). + +For detailed information on how to use the script, please refer to +`./scripts/tests --help`. + +### Windows + +You can also build **mldsa-native** on Windows using `nmake` and an MSVC compiler. + +To build and run the tests (only support functional testing for non-opt implementation for now), use the following `nmake` targets: +```powershell +nmke /f .\Makefile.Microsoft_nmake quickcheck +``` + +# Checking the proofs + +## CBMC + +### Prerequisites + +To run the CBMC proofs, you need specific versions of CBMC and the underlying solvers, e.g. as specified in our `nix` environment; see [nix/cbmc](nix/cbmc/). +See [CONTRIBUTING.md](CONTRIBUTING.md) for instructions on how to setup and use `nix`. + +### Running the CBMC proofs + +Once you are in the `nix` shell or have all tools setup by hand, use `./scripts/tests cbmc` (or just `tests cbmc` in the `nix` shell) to re-check the CBMC proofs. +See `tests cbmc --help` for details on the command line options, and [proofs/cbmc](proofs/cbmc) for more details on the CBMC proofs in general. + +## HOL-Light + +### Prerequisites + +To run the HOL-Light proofs, you need recent versions of HOL-Light and s2n-bignum, e.g. as specified in our `nix` environment; see [nix/s2n_bignum](nix/s2n_bignum) and [nix/hol_light](nix/hol_light). +See [CONTRIBUTING.md](CONTRIBUTING.md) for instructions on how to setup and use `nix`. + +### Running the HOL-Light proofs + +Once you are in the `nix` shell or have all tools setup by hand, use `./scripts/tests hol_light` (or just `tests hol_light` in the `nix` shell) to re-check the HOL-Light proofs. Note that depending on the function, they will take a long time. See `tests hol_light --help` for details on the command line options, and [proofs/hol_light](proofs/hol_light) for more details on the HOL-Light proofs in general. + diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/CODEOWNERS b/tf-psa-crypto/drivers/pqcp/mldsa-native/CODEOWNERS new file mode 100644 index 0000000000..610b3a1387 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/CODEOWNERS @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +# Last matching pattern has precedence + +* @pq-code-package/pqcp-mldsa-native-admin diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/CONTRIBUTING.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/CONTRIBUTING.md new file mode 100644 index 0000000000..8e8462bd94 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/CONTRIBUTING.md @@ -0,0 +1,8 @@ +# Contributing to mldsa-native + +We aim to minimize the differences between the [upstream mldsa-native](https://github.com/pq-code-package/mldsa-native) and our fork. If you wish to contribute to mldsa-native, please [contribute upstream](https://github.com/pq-code-package/mldsa-native/blob/main/CONTRIBUTING.md). If you think that the TF-PSA-Crypto integration requires a patch, please discuss it in an [issue on our fork](https://github.com/Mbed-TLS/mldsa-native/issues) first. + +Contributions to the Mbed-TLS mldsa-native fork have the same license as upstream. See the [LICENSE](LICENSE) file. + +When contributing code to us, the committer and all authors are required to make the submission under the terms of the [Developer Certificate of Origin](dco.txt), confirming that the code submitted can (legally) become part of the project, and is submitted under the [LICENSE](LICENSE). +This is done by including the standard Git `Signed-off-by:` line in every commit message. If more than one person contributed to the commit, they should also add their own `Signed-off-by:` line. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/FIPS202.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/FIPS202.md new file mode 100644 index 0000000000..44eaee682e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/FIPS202.md @@ -0,0 +1,41 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Replacing FIPS-202 + +If your library has a FIPS-202[^FIPS202] implementation, you can use it instead of the one shipped with mldsa-native. + +1. Replace `mldsa/src/fips202/*` by your own FIPS-202 implementation. +2. Provide replacements for the headers [`mldsa/src/fips202/fips202.h`](mldsa/src/fips202/fips202.h) and [`mldsa/src/fips202/fips202x4.h`](mldsa/src/fips202/fips202x4.h) and the +functionalities specified therein: + * Structure definitions for `mld_shake128ctx`, `mld_shake256ctx`, `mld_shake128x4ctx`, and `mld_shake256x4ctx` + * `mld_shake128_init()`: Initialize a SHAKE-128 context + * `mld_shake128_absorb()`: Absorb data into a SHAKE-128 context (can be called multiple times) + * `mld_shake128_finalize()`: Finalize the absorb phase of a SHAKE-128 context + * `mld_shake128_squeeze()`: Squeeze data from a SHAKE-128 context (can be called multiple times) + * `mld_shake128_release()`: Release and securely zero a SHAKE-128 context after use + * `mld_shake256_init()`: Initialize a SHAKE-256 context + * `mld_shake256_absorb()`: Absorb data into a SHAKE-256 context (can be called multiple times) + * `mld_shake256_finalize()`: Finalize the absorb phase of a SHAKE-256 context + * `mld_shake256_squeeze()`: Squeeze data from a SHAKE-256 context (can be called multiple times) + * `mld_shake256_release()`: Release and securely zero a SHAKE-256 context after use + * `mld_shake256()`: One-shot SHAKE-256 operation + * `mld_shake128x4_init()`: Initialize a 4x-batched SHAKE-128 context + * `mld_shake128x4_absorb_once()`: Initialize and absorb into a 4x-batched SHAKE-128 context in one step + * `mld_shake128x4_squeezeblocks()`: Squeeze blocks from a 4x-batched SHAKE-128 context + * `mld_shake128x4_release()`: Release a 4x-batched SHAKE-128 context after use + * `mld_shake256x4_init()`: Initialize a 4x-batched SHAKE-256 context + * `mld_shake256x4_absorb_once()`: Initialize and absorb into a 4x-batched SHAKE-256 context in one step + * `mld_shake256x4_squeezeblocks()`: Squeeze blocks from a 4x-batched SHAKE-256 context + * `mld_shake256x4_release()`: Release a 4x-batched SHAKE-256 context after use + +See [`mldsa/src/fips202/fips202.h`](mldsa/src/fips202/fips202.h) and [`mldsa/src/fips202/fips202x4.h`](mldsa/src/fips202/fips202x4.h) for more details. Note that the structure +definitions may differ from those shipped with mldsa-native. + +## Example + +See [`examples/bring_your_own_fips202/`](examples/bring_your_own_fips202/) for an example how to use a custom FIPS-202 +implementation with tiny_sha3[^tiny_sha3]. + + +[^FIPS202]: National Institute of Standards and Technology: FIPS202 SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions, [https://csrc.nist.gov/pubs/fips/202/final](https://csrc.nist.gov/pubs/fips/202/final) +[^tiny_sha3]: Markku-Juhani O. Saarinen: tiny_sha3, [https://github.com/mjosaarinen/tiny_sha3](https://github.com/mjosaarinen/tiny_sha3) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/LICENSE b/tf-psa-crypto/drivers/pqcp/mldsa-native/LICENSE new file mode 100644 index 0000000000..5fd3c1b135 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/LICENSE @@ -0,0 +1,286 @@ +mldsa-native is a fork of the public domain Dilithium reference implementation, +available on https://github.com/pq-crystals/dilithium. + +All new files and all files derived from the Dilithium reference +implementation are made available under the Apache-2.0 license OR +the ISC license OR the MIT license. These licenses are +reproduced at the bottom of this file. + +The code in test/notrandombytes/* is derived from +https://cr.yp.to/papers.html#surf and licensed under +LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT. +It is only used for testing purposes. + +The benchmarking code in test/hal/hal.c carries the +MIT license. It is only used for testing purposes. + +``` +Copyright (c) The mldsa-native project authors +Copyright (c) The mlkem-native project authors +Copyright (c) 2020 Dougall Johnson +Copyright (c) 2022 Arm Limited +SPDX-License-Identifier: MIT + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +``` + +ISC license for mldsa-native content +------------------------------------ + +Copyright (c) The mldsa-native project authors + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. + + +MIT license for mldsa-native content +------------------------------------ + +Copyright (c) The mldsa-native project authors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the “Software”), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Apache-2.0 license for mldsa-native content +------------------------------------------- + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) The mldsa-native project authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/MAINTAINERS.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/MAINTAINERS.md new file mode 100644 index 0000000000..00d9e5538c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/MAINTAINERS.md @@ -0,0 +1,11 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Maintainers + +## Active Maintainers + +| Name | GitHub | Affliation +|-------------------------|-------------------------------------------------|---------------------- +| Hanno Becker | [hanno-becker](https://github.com/hanno-becker) | AWS | +| Matthias J. Kannwischer | [mkannwischer](https://github.com/mkannwischer) | Chelpis Quantum Corp | +| Jake Massimo | [jakemas](https://github.com/jakemas) | AWS | diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/META.sh b/tf-psa-crypto/drivers/pqcp/mldsa-native/META.sh new file mode 100755 index 0000000000..21edbff227 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/META.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# Helper script to query META.yml +# +# Arguments +# - Scheme to query: ML-DSA-44, ML-DSA-65, ML-DSA-87 +# - Field to query, e.g. "kat-sha256" +# +# Optional: +# - Value to compare against + +META=META.yml + +# Manual extraction of metadata with basic cmd line tools +VAL=$(cat $META | + grep "name\|$2" | + grep $1 -A 1 | + grep $2 | + cut -d ":" -f 2 | tr -d ' ') + +# More robust extraction using yq +if (which yq 2>&1 >/dev/null); then + QUERY=".implementations | .[] | select(.name==\"$1\") | .\"$2\"" + echo "cat $META | yq "$QUERY" -r" + VAL_JQ=$(cat $META | yq "$QUERY" -r) + + if [[ $VAL_JQ != $VAL ]]; then + echo "ERROR parsing metadata file $META" + exit 1 + fi +fi + +INPUT=$3 +if [[ $INPUT != "" ]]; then + if [[ $INPUT != "$VAL" ]]; then + echo "$META $1 $2: FAIL ($VAL != $INPUT)" + exit 1 + else + echo "$META $1 $2: OK" + exit 0 + fi +else + echo $VAL +fi diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/META.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/META.yml new file mode 100644 index 0000000000..62358f2825 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/META.yml @@ -0,0 +1,24 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: ML-DSA +type: signature +implementations: + - name: ML-DSA-44 + claimed-nist-level: 2 + length-public-key: 1312 + length-secret-key: 2560 + length-signature: 2420 + kat-sha256: 33e7eb7e3b4965fc8b8274ebf8a222c519008ec242b3f753d1bc240f1ee3cb1f + - name: ML-DSA-65 + claimed-nist-level: 3 + length-public-key: 1952 + length-secret-key: 4032 + length-signature: 3309 + kat-sha256: 2ff0ddcd0dc08b746aa04853d6f84c82c6c8ac38783c9061aed78e29c1698ae5 + - name: ML-DSA-87 + claimed-nist-level: 5 + length-public-key: 2592 + length-secret-key: 4896 + length-signature: 4627 + kat-sha256: 1bfb25b29f6f2bc89057e3bddee055a8f7df563b0e747004b2968159f7739afa diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/Makefile new file mode 100644 index 0000000000..cb88f9b794 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/Makefile @@ -0,0 +1,293 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +.PHONY: func kat acvp stack unit alloc rng_fail \ + func_44 kat_44 acvp_44 stack_44 unit_44 alloc_44 rng_fail_44 \ + func_65 kat_65 acvp_65 stack_65 unit_65 alloc_65 rng_fail_65 \ + func_87 kat_87 acvp_87 stack_87 unit_87 alloc_87 rng_fail_87 \ + run_func run_kat run_acvp run_stack run_unit run_alloc run_rng_fail \ + run_func_44 run_kat_44 run_stack_44 run_unit_44 run_alloc_44 run_rng_fail_44 \ + run_func_65 run_kat_65 run_stack_65 run_unit_65 run_alloc_65 run_rng_fail_65 \ + run_func_87 run_kat_87 run_stack_87 run_unit_87 run_alloc_87 run_rng_fail_87 \ + bench_44 bench_65 bench_87 bench \ + run_bench_44 run_bench_65 run_bench_87 run_bench \ + bench_components_44 bench_components_65 bench_components_87 bench_components \ + run_bench_components_44 run_bench_components_65 run_bench_components_87 run_bench_components \ + build test all \ + clean quickcheck check-defined-CYCLES \ + size_44 size_65 size_87 size \ + run_size_44 run_size_65 run_size_87 run_size \ + host_info + +SHELL := /usr/bin/env bash +.DEFAULT_GOAL := build + +all: build + +# Extra Makefile to include, e.g., for baremetal targets +ifneq ($(EXTRA_MAKEFILE),) +include $(EXTRA_MAKEFILE) +endif + +W := $(EXEC_WRAPPER) + +BUILD_DIR ?= test/build + +# Skip includes for clean target +ifneq ($(MAKECMDGOALS),clean) +include test/mk/config.mk +include test/mk/auto.mk +include test/mk/components.mk +include test/mk/rules.mk +endif + +quickcheck: test + +build: func kat acvp + $(Q)echo " Everything builds fine!" + +test: run_kat run_func run_acvp run_unit run_alloc run_rng_fail + $(Q)echo " Everything checks fine!" + +# Detect available SHA256 command +SHA256SUM := $(shell command -v shasum >/dev/null 2>&1 && echo "shasum -a 256" || (command -v sha256sum >/dev/null 2>&1 && echo "sha256sum" || echo "")) +ifeq ($(SHA256SUM),) +$(error Neither 'shasum' nor 'sha256sum' found. Please install one of these tools.) +endif + +run_kat_44: kat_44 + set -o pipefail; $(W) $(MLDSA44_DIR)/bin/gen_KAT44 | $(SHA256SUM) | cut -d " " -f 1 | xargs ./META.sh ML-DSA-44 kat-sha256 +run_kat_65: kat_65 + set -o pipefail; $(W) $(MLDSA65_DIR)/bin/gen_KAT65 | $(SHA256SUM) | cut -d " " -f 1 | xargs ./META.sh ML-DSA-65 kat-sha256 +run_kat_87: kat_87 + set -o pipefail; $(W) $(MLDSA87_DIR)/bin/gen_KAT87 | $(SHA256SUM) | cut -d " " -f 1 | xargs ./META.sh ML-DSA-87 kat-sha256 +run_kat: run_kat_44 run_kat_65 run_kat_87 + +run_func_44: func_44 + $(W) $(MLDSA44_DIR)/bin/test_mldsa44 +run_func_65: func_65 + $(W) $(MLDSA65_DIR)/bin/test_mldsa65 +run_func_87: func_87 + $(W) $(MLDSA87_DIR)/bin/test_mldsa87 +run_func: run_func_44 run_func_65 run_func_87 + +run_unit_44: unit_44 + $(W) $(MLDSA44_DIR)/bin/test_unit44 +run_unit_65: unit_65 + $(W) $(MLDSA65_DIR)/bin/test_unit65 +run_unit_87: unit_87 + $(W) $(MLDSA87_DIR)/bin/test_unit87 +run_unit: run_unit_44 run_unit_65 run_unit_87 + +run_acvp: acvp + EXEC_WRAPPER="$(EXEC_WRAPPER)" python3 ./test/acvp/acvp_client.py $(if $(ACVP_VERSION),--version $(ACVP_VERSION)) + +func_44: $(MLDSA44_DIR)/bin/test_mldsa44 + $(Q)echo " FUNC ML-DSA-44: $^" +func_65: $(MLDSA65_DIR)/bin/test_mldsa65 + $(Q)echo " FUNC ML-DSA-65: $^" +func_87: $(MLDSA87_DIR)/bin/test_mldsa87 + $(Q)echo " FUNC ML-DSA-87: $^" +func: func_44 func_65 func_87 + +unit_44: $(MLDSA44_DIR)/bin/test_unit44 + $(Q)echo " UNIT ML-DSA-44: $^" +unit_65: $(MLDSA65_DIR)/bin/test_unit65 + $(Q)echo " UNIT ML-DSA-65: $^" +unit_87: $(MLDSA87_DIR)/bin/test_unit87 + $(Q)echo " UNIT ML-DSA-87: $^" +unit: unit_44 unit_65 unit_87 + +kat_44: $(MLDSA44_DIR)/bin/gen_KAT44 + $(Q)echo " KAT ML-DSA-44: $^" +kat_65: $(MLDSA65_DIR)/bin/gen_KAT65 + $(Q)echo " KAT ML-DSA-65: $^" +kat_87: $(MLDSA87_DIR)/bin/gen_KAT87 + $(Q)echo " KAT ML-DSA-87: $^" +kat: kat_44 kat_65 kat_87 + +acvp_44: $(MLDSA44_DIR)/bin/acvp_mldsa44 + $(Q)echo " ACVP ML-DSA-44: $^" +acvp_65: $(MLDSA65_DIR)/bin/acvp_mldsa65 + $(Q)echo " ACVP ML-DSA-65: $^" +acvp_87: $(MLDSA87_DIR)/bin/acvp_mldsa87 + $(Q)echo " ACVP ML-DSA-87: $^" +acvp: acvp_44 acvp_65 acvp_87 + +ifeq ($(HOST_PLATFORM),Linux-aarch64) +# valgrind does not work with the AArch64 SHA3 extension +# Use armv8-a as the target architecture, overwriting a +# potential earlier addition of armv8.4-a+sha3. +$(MLDSA44_DIR)/bin/test_stack44: CFLAGS += -march=armv8-a +$(MLDSA65_DIR)/bin/test_stack65: CFLAGS += -march=armv8-a +$(MLDSA87_DIR)/bin/test_stack87: CFLAGS += -march=armv8-a +endif + +stack_44: $(MLDSA44_DIR)/bin/test_stack44 + $(Q)echo " STACK ML-DSA-44: $^" +stack_65: $(MLDSA65_DIR)/bin/test_stack65 + $(Q)echo " STACK ML-DSA-65: $^" +stack_87: $(MLDSA87_DIR)/bin/test_stack87 + $(Q)echo " STACK ML-DSA-87: $^" +stack: stack_44 stack_65 stack_87 + +run_stack_44: stack_44 + $(Q)python3 scripts/stack $(MLDSA44_DIR)/bin/test_stack44 --build-dir $(MLDSA44_DIR) $(STACK_ANALYSIS_FLAGS) +run_stack_65: stack_65 + $(Q)python3 scripts/stack $(MLDSA65_DIR)/bin/test_stack65 --build-dir $(MLDSA65_DIR) $(STACK_ANALYSIS_FLAGS) +run_stack_87: stack_87 + $(Q)python3 scripts/stack $(MLDSA87_DIR)/bin/test_stack87 --build-dir $(MLDSA87_DIR) $(STACK_ANALYSIS_FLAGS) +run_stack: run_stack_44 run_stack_65 run_stack_87 + +alloc_44: $(MLDSA44_DIR)/bin/test_alloc44 + $(Q)echo " ALLOC ML-DSA-44: $^" +alloc_65: $(MLDSA65_DIR)/bin/test_alloc65 + $(Q)echo " ALLOC ML-DSA-65: $^" +alloc_87: $(MLDSA87_DIR)/bin/test_alloc87 + $(Q)echo " ALLOC ML-DSA-87: $^" +alloc: alloc_44 alloc_65 alloc_87 + +run_alloc_44: alloc_44 + $(W) $(MLDSA44_DIR)/bin/test_alloc44 +run_alloc_65: alloc_65 + $(W) $(MLDSA65_DIR)/bin/test_alloc65 +run_alloc_87: alloc_87 + $(W) $(MLDSA87_DIR)/bin/test_alloc87 +run_alloc: run_alloc_44 run_alloc_65 run_alloc_87 + +rng_fail_44: $(MLDSA44_DIR)/bin/test_rng_fail44 + $(Q)echo " RNG_FAIL ML-DSA-44: $^" +rng_fail_65: $(MLDSA65_DIR)/bin/test_rng_fail65 + $(Q)echo " RNG_FAIL ML-DSA-65: $^" +rng_fail_87: $(MLDSA87_DIR)/bin/test_rng_fail87 + $(Q)echo " RNG_FAIL ML-DSA-87: $^" +rng_fail: rng_fail_44 rng_fail_65 rng_fail_87 + +run_rng_fail_44: rng_fail_44 + $(W) $(MLDSA44_DIR)/bin/test_rng_fail44 +run_rng_fail_65: rng_fail_65 + $(W) $(MLDSA65_DIR)/bin/test_rng_fail65 +run_rng_fail_87: rng_fail_87 + $(W) $(MLDSA87_DIR)/bin/test_rng_fail87 +run_rng_fail: run_rng_fail_44 run_rng_fail_65 run_rng_fail_87 + +lib: $(BUILD_DIR)/libmldsa.a $(BUILD_DIR)/libmldsa44.a $(BUILD_DIR)/libmldsa65.a $(BUILD_DIR)/libmldsa87.a + +# Enforce setting CYCLES make variable when +# building benchmarking binaries +check_defined = $(if $(value $1),, $(error $2)) +check-defined-CYCLES: + @:$(call check_defined,CYCLES,CYCLES undefined. Benchmarking requires setting one of NO PMU PERF MAC) + +bench_44: check-defined-CYCLES \ + $(MLDSA44_DIR)/bin/bench_mldsa44 +bench_65: check-defined-CYCLES \ + $(MLDSA65_DIR)/bin/bench_mldsa65 +bench_87: check-defined-CYCLES \ + $(MLDSA87_DIR)/bin/bench_mldsa87 +bench: bench_44 bench_65 bench_87 + +run_bench_44: bench_44 + $(W) $(MLDSA44_DIR)/bin/bench_mldsa44 +run_bench_65: bench_65 + $(W) $(MLDSA65_DIR)/bin/bench_mldsa65 +run_bench_87: bench_87 + $(W) $(MLDSA87_DIR)/bin/bench_mldsa87 +run_bench: bench + $(W) $(MLDSA44_DIR)/bin/bench_mldsa44 + $(W) $(MLDSA65_DIR)/bin/bench_mldsa65 + $(W) $(MLDSA87_DIR)/bin/bench_mldsa87 + +bench_components_44: check-defined-CYCLES \ + $(MLDSA44_DIR)/bin/bench_components_mldsa44 +bench_components_65: check-defined-CYCLES \ + $(MLDSA65_DIR)/bin/bench_components_mldsa65 +bench_components_87: check-defined-CYCLES \ + $(MLDSA87_DIR)/bin/bench_components_mldsa87 +bench_components: bench_components_44 bench_components_65 bench_components_87 + +run_bench_components_44: bench_components_44 + $(W) $(MLDSA44_DIR)/bin/bench_components_mldsa44 +run_bench_components_65: bench_components_65 + $(W) $(MLDSA65_DIR)/bin/bench_components_mldsa65 +run_bench_components_87: bench_components_87 + $(W) $(MLDSA87_DIR)/bin/bench_components_mldsa87 +run_bench_components: bench_components + $(W) $(MLDSA44_DIR)/bin/bench_components_mldsa44 + $(W) $(MLDSA65_DIR)/bin/bench_components_mldsa65 + $(W) $(MLDSA87_DIR)/bin/bench_components_mldsa87 + + +size_44: $(BUILD_DIR)/libmldsa44.a +size_65: $(BUILD_DIR)/libmldsa65.a +size_87: $(BUILD_DIR)/libmldsa87.a +size: size_44 size_65 size_87 + +run_size_44: size_44 + $(Q)echo "size $(BUILD_DIR)/libmldsa44.a" + $(Q)$(SIZE) $(BUILD_DIR)/libmldsa44.a | (read header; echo "$$header"; awk '$$5 != 0' | sort -k5 -n -r) + +run_size_65: size_65 + $(Q)echo "size $(BUILD_DIR)/libmldsa65.a" + $(Q)$(SIZE) $(BUILD_DIR)/libmldsa65.a | (read header; echo "$$header"; awk '$$5 != 0' | sort -k5 -n -r) + +run_size_87: size_87 + $(Q)echo "size $(BUILD_DIR)/libmldsa87.a" + $(Q)$(SIZE) $(BUILD_DIR)/libmldsa87.a | (read header; echo "$$header"; awk '$$5 != 0' | sort -k5 -n -r) + + +run_size: \ + run_size_44 \ + run_size_65 \ + run_size_87 + +# Display host and compiler feature detection information +# Shows which architectural features are supported by both the compiler and host CPU +# Usage: make host_info [AUTO=0|1] [CROSS_PREFIX=...] +host_info: + @echo "=== Host and Compiler Feature Detection ===" + @echo "Host Platform: $(HOST_PLATFORM)" + @echo "Target Architecture: $(ARCH)" + @echo "Compiler: $(CC)" + @echo "Cross Prefix: $(if $(CROSS_PREFIX),$(CROSS_PREFIX),)" + @echo "AUTO: $(AUTO)" + @echo "" +ifeq ($(ARCH),x86_64) + @echo "=== x86_64 Feature Support ===" + @echo "AVX2: Host $(if $(filter 1,$(MK_HOST_SUPPORTS_AVX2)),✅,❌) Compiler $(if $(filter 1,$(MK_COMPILER_SUPPORTS_AVX2)),✅,❌)" + @echo "SSE2: Host $(if $(filter 1,$(MK_HOST_SUPPORTS_SSE2)),✅,❌) Compiler $(if $(filter 1,$(MK_COMPILER_SUPPORTS_SSE2)),✅,❌)" + @echo "BMI2: Host $(if $(filter 1,$(MK_HOST_SUPPORTS_BMI2)),✅,❌) Compiler $(if $(filter 1,$(MK_COMPILER_SUPPORTS_BMI2)),✅,❌)" +else ifeq ($(ARCH),aarch64) + @echo "=== AArch64 Feature Support ===" + @echo "SHA3: Host $(if $(filter 1,$(MK_HOST_SUPPORTS_SHA3)),✅,❌) Compiler $(if $(filter 1,$(MK_COMPILER_SUPPORTS_SHA3)),✅,❌)" +else + @echo "=== Architecture Not Supported ===" + @echo "No specific feature detection available for $(ARCH)" +endif + +EXAMPLE_DIRS := \ + examples/bring_your_own_fips202 \ + examples/bring_your_own_fips202_static \ + examples/custom_backend \ + examples/basic \ + examples/basic_deterministic \ + examples/basic_lowram \ + examples/monolithic_build \ + examples/monolithic_build_native \ + examples/monolithic_build_multilevel \ + examples/monolithic_build_multilevel_native \ + examples/multilevel_build \ + examples/multilevel_build_native + +EXAMPLE_CLEAN_TARGETS := $(EXAMPLE_DIRS:%=clean-%) + +.PHONY: $(EXAMPLE_CLEAN_TARGETS) + +$(EXAMPLE_CLEAN_TARGETS): clean-%: + @echo " CLEAN $*" + -@$(MAKE) clean -C $* >/dev/null + +clean: $(EXAMPLE_CLEAN_TARGETS) + @echo " RM $(BUILD_DIR)" + -@$(RM) -rf $(BUILD_DIR) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/Makefile.Microsoft_nmake b/tf-psa-crypto/drivers/pqcp/mldsa-native/Makefile.Microsoft_nmake new file mode 100644 index 0000000000..e96893adf2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/Makefile.Microsoft_nmake @@ -0,0 +1,92 @@ +# Copyright (c) The mldsa-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +CFLAGS = /nologo /O2 /Imldsa /Imldsa/src/ /Imlmdsa/src/fips202 /Imldsa/src/fips202/native /Imldsa/src/native + +OBJ_FILES = .\mldsa\*.obj \ + .\mldsa\fips202\*.obj + +BUILD_DIR = test\build +MLDSA44_BUILD_DIR = $(BUILD_DIR)\mldsa44 +MLDSA65_BUILD_DIR = $(BUILD_DIR)\mldsa65 +MLDSA87_BUILD_DIR = $(BUILD_DIR)\mldsa87 + +OBJ_FILES_44 = $(MLDSA44_BUILD_DIR)\mldsa\*.obj \ + $(MLDSA44_BUILD_DIR)\mldsa\fips202\*.obj +OBJ_FILES_65 = $(MLDSA65_BUILD_DIR)\mldsa\*.obj \ + $(MLDSA65_BUILD_DIR)\mldsa\fips202\*.obj +OBJ_FILES_87 = $(MLDSA87_BUILD_DIR)\mldsa\*.obj \ + $(MLDSA87_BUILD_DIR)\mldsa\fips202\*.obj + +# NOTE: We currently only build code for non-opt code, as we haven't yet made the assembly compatible on Windows +!IFNDEF OPT +OPT = 0 +!ENDIF + +{test/notrandombytes}.c{$(BUILD_DIR)\randombytes}.obj:: + @if NOT EXIST $(BUILD_DIR)\randombytes mkdir $(BUILD_DIR)\randombytes + $(CC) $(CFLAGS) /c /Fo$(BUILD_DIR)\randombytes\ $< + +# compilation for mldsa44 +{mldsa\src}.c{$(MLDSA44_BUILD_DIR)\mldsa}.obj:: + @if NOT EXIST $(MLDSA44_BUILD_DIR)\mldsa mkdir $(MLDSA44_BUILD_DIR)\mldsa + $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=44 /c /Fo$(MLDSA44_BUILD_DIR)\mldsa\ $< + +{mldsa\src\fips202}.c{$(MLDSA44_BUILD_DIR)\mldsa\fips202}.obj:: + @if NOT EXIST $(MLDSA44_BUILD_DIR)\mldsa\fips202 mkdir $(MLDSA44_BUILD_DIR)\mldsa\fips202 + $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=44 /c /Fo$(MLDSA44_BUILD_DIR)\mldsa\fips202\ $< + +{test\src}.c{$(MLDSA44_BUILD_DIR)\test}.obj:: + @if NOT EXIST $(MLDSA44_BUILD_DIR)\test mkdir $(MLDSA44_BUILD_DIR)\test + $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=44 /c /Fo$(MLDSA44_BUILD_DIR)\test\ $< + +# compilation for mldsa65 +{mldsa\src}.c{$(MLDSA65_BUILD_DIR)\mldsa}.obj:: + @if NOT EXIST $(MLDSA65_BUILD_DIR)\mldsa mkdir $(MLDSA65_BUILD_DIR)\mldsa + $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=65 /c /Fo$(MLDSA65_BUILD_DIR)\mldsa\ $< + +{mldsa\src\fips202}.c{$(MLDSA65_BUILD_DIR)\mldsa\fips202}.obj:: + @if NOT EXIST $(MLDSA65_BUILD_DIR)\mldsa\fips202 mkdir $(MLDSA65_BUILD_DIR)\mldsa\fips202 + $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=65 /c /Fo$(MLDSA65_BUILD_DIR)\mldsa\fips202\ $< + +{test\src}.c{$(MLDSA65_BUILD_DIR)\test}.obj:: + @if NOT EXIST $(MLDSA65_BUILD_DIR)\test mkdir $(MLDSA65_BUILD_DIR)\test + $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=65 /c /Fo$(MLDSA65_BUILD_DIR)\test\ $< + +# compilation for mldsa87 +{mldsa\src}.c{$(MLDSA87_BUILD_DIR)\mldsa}.obj:: + @if NOT EXIST $(MLDSA87_BUILD_DIR)\mldsa mkdir $(MLDSA87_BUILD_DIR)\mldsa + $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=87 /c /Fo$(MLDSA87_BUILD_DIR)\mldsa\ $< + +{mldsa\src\fips202}.c{$(MLDSA87_BUILD_DIR)\mldsa\fips202}.obj:: + @if NOT EXIST $(MLDSA87_BUILD_DIR)\mldsa\fips202 mkdir $(MLDSA87_BUILD_DIR)\mldsa\fips202 + $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=87 /c /Fo$(MLDSA87_BUILD_DIR)\mldsa\fips202\ $< + +{test\src}.c{$(MLDSA87_BUILD_DIR)\test}.obj:: + @if NOT EXIST $(MLDSA87_BUILD_DIR)\test mkdir $(MLDSA87_BUILD_DIR)\test + $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=87 /c /Fo$(MLDSA87_BUILD_DIR)\test\ $< + + +# compile functional test for mldsa44 +test_mldsa44: $(OBJ_FILES_44) $(MLDSA44_BUILD_DIR)\test\test_mldsa.obj $(BUILD_DIR)\randombytes\notrandombytes.obj + @if NOT EXIST $(MLDSA44_BUILD_DIR)\bin mkdir $(MLDSA44_BUILD_DIR)\bin + $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=44 /Fe$(MLDSA44_BUILD_DIR)\bin\test_mldsa44 $** /link + +# compile functional test for mldsa65 +test_mldsa65: $(OBJ_FILES_65) $(MLDSA65_BUILD_DIR)\test\test_mldsa.obj $(BUILD_DIR)\randombytes\notrandombytes.obj + @if NOT EXIST $(MLDSA65_BUILD_DIR)\bin mkdir $(MLDSA65_BUILD_DIR)\bin + $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=65 /Fe$(MLDSA65_BUILD_DIR)\bin\test_mldsa65 $** /link + +# compile functional test for mldsa87 +test_mldsa87: $(OBJ_FILES_87) $(MLDSA87_BUILD_DIR)\test\test_mldsa.obj $(BUILD_DIR)\randombytes\notrandombytes.obj + @if NOT EXIST $(MLDSA87_BUILD_DIR)\bin mkdir $(MLDSA87_BUILD_DIR)\bin + $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=87 /Fe$(MLDSA87_BUILD_DIR)\bin\test_mldsa87 $** /link + +quickcheck: test_mldsa44 test_mldsa65 test_mldsa87 + $(MLDSA44_BUILD_DIR)\bin\test_mldsa44.exe + $(MLDSA65_BUILD_DIR)\bin\test_mldsa65.exe + $(MLDSA87_BUILD_DIR)\bin\test_mldsa87.exe + +clean: + -DEL $(BUILD_DIR) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/README.md new file mode 100644 index 0000000000..2a0f1d859a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/README.md @@ -0,0 +1,8 @@ +# mldsa-native fork + +This repository is a fork of [mldsa-native](https://github.com/pq-code-package/mldsa-native) from the [PQ Code Package](https://github.com/pq-code-package), which is integrated in [TF-PSA-Crypto](https://github.com/Mbed-TLS/TF-PSA-Crypto). Unless you are a maintainer of TF-PSA-Crypto, you probably want: + +* The [upstream mldsa-native repository](https://github.com/pq-code-package/mldsa-native), if you aren't using TF-PSA-Crypto. +* The [TF-PSA-Crypto repository](https://github.com/Mbed-TLS/TF-PSA-Crypto), if you are using TF-PSA-Crypto. + +We aim to keep this fork up to date with all applicable upstream security fixes and major bug fixes. Other improvements will be synchronized at a pace that remains to be defined. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/RELICENSE.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/RELICENSE.md new file mode 100644 index 0000000000..3205884779 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/RELICENSE.md @@ -0,0 +1,20 @@ +# Relicensing mldsa-native + +This document gathers consent by mldsa-native contributors to relicense +mldsa-native from `Apache-2.0` to `Apache-2.0 OR ISC OR MIT`. + +The relicensing itself is intended to be carried out once all contributors +have given consent to the relicensing. + +## Contributors agreeing to relicensing + +By adding my name to the list below, I agree to relicense all my contributions +in the mldsa-native project under `Apache-2.0 OR ISC OR MIT`. + +- Hanno Becker +- Matthias Kannwischer +- Rod Chapman +- Jake Massimo +- Pravek Sharma +- Mila Anastasova +- Thing Han, Lim potsrevenmil@gmail.com diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/SECURITY.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/SECURITY.md new file mode 100644 index 0000000000..785359c3e5 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/SECURITY.md @@ -0,0 +1,5 @@ +# Security Policy + +## Reporting security bugs + +If you think you have found a security bug in the mldsa-native in TF-PSA-Crypto, please [report it as a vulnerability in TF-PSA-Crypto](https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/SECURITY.md). diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/STDLIB.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/STDLIB.md new file mode 100644 index 0000000000..4a7830f38f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/STDLIB.md @@ -0,0 +1,27 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Standard Library Dependencies + +mldsa-native has minimal dependencies on the C standard library. This document lists all stdlib functions used and configuration options for custom replacements. + +## Dependencies + +### Memory Functions +- **memcpy**: Used extensively for copying data structures, keys, and intermediate values (40+ occurrences) +- **memset**: Used for zeroing state structures and buffers (3 occurrences). **Note**: This is NOT used for security-critical zeroing - that is handled by `mld_zeroize` which has its own custom replacement mechanism + +### Debug Functions (MLDSA_DEBUG builds only) +- **fprintf**: Used in debug.c for error reporting to stderr +- **exit**: Used in debug.c to terminate on assertion failures + +## Custom Replacements + +Custom replacements can be provided for memory functions using the configuration options in `mldsa/src/config.h`: + +### MLD_CONFIG_CUSTOM_MEMCPY +Replaces all `memcpy` calls with a custom implementation. When enabled, you must define a `mld_memcpy` function with the same signature as the standard `memcpy`. + +### MLD_CONFIG_CUSTOM_MEMSET +Replaces all `memset` calls with a custom implementation. When enabled, you must define a `mld_memset` function with the same signature as the standard `memset`. + +See the configuration examples in `mldsa/src/config.h` and test configurations in `test/custom_*_config.h` for usage examples and implementation requirements. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dco.txt b/tf-psa-crypto/drivers/pqcp/mldsa-native/dco.txt new file mode 100644 index 0000000000..8201f99215 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dco.txt @@ -0,0 +1,37 @@ +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +1 Letterman Drive +Suite D4700 +San Francisco, CA, 94129 + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/meta.h new file mode 100644 index 0000000000..c6f6ad47b0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/meta.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_META_H +#define MLD_NATIVE_AARCH64_META_H + +/* Set of primitives that this backend replaces */ +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_AARCH64 + + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/arith_native_aarch64.h" + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + mld_ntt_asm(data, mld_aarch64_ntt_zetas_layer123456, + mld_aarch64_ntt_zetas_layer78); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + mld_intt_asm(data, mld_aarch64_intt_zetas_layer78, + mld_aarch64_intt_zetas_layer123456); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + if (len != MLDSA_N || + buflen % 24 != 0) /* NEON support is mandatory for AArch64 */ + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N, hence, this cast is safe. */ + return (int)mld_rej_uniform_asm(r, buf, buflen, mld_rej_uniform_table); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_32_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_88_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + mld_poly_caddq_asm(a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_32_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_88_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + return mld_poly_chknorm_asm(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_17_asm(r, buf, mld_polyz_unpack_17_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_19_asm(r, buf, mld_polyz_unpack_19_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t out[MLDSA_N], const int32_t in0[MLDSA_N], + const int32_t in1[MLDSA_N]) +{ + mld_poly_pointwise_montgomery_asm(out, in0, in1); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l4_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l5_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l7_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ +#endif /* !MLD_NATIVE_AARCH64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/src/aarch64_zetas.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/src/aarch64_zetas.c new file mode 100644 index 0000000000..9ab7b9a68c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/src/aarch64_zetas.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Table of zeta values used in the AArch64 forward NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer123456[] = { + -3572223, -915382907, 3765607, 964937599, 3761513, 963888510, + -3201494, -820383522, -2883726, -738955404, -3145678, -806080660, + -3201430, -820367122, 0, 0, -601683, -154181397, + -3370349, -863652652, -4063053, -1041158200, 3602218, 923069133, + 3182878, 815613168, 2740543, 702264730, -3586446, -919027554, + 0, 0, 3542485, 907762539, 2663378, 682491182, + -1674615, -429120452, -3110818, -797147778, 2101410, 538486762, + 3704823, 949361686, 1159875, 297218217, 0, 0, + 2682288, 687336873, -3524442, -903139016, -434125, -111244624, + 394148, 101000509, 928749, 237992130, 1095468, 280713909, + -3506380, -898510625, 0, 0, 2129892, 545785280, + 676590, 173376332, -1335936, -342333886, 2071829, 530906624, + -4018989, -1029866791, 3241972, 830756018, 2156050, 552488273, + 0, 0, 3764867, 964747974, -3227876, -827143915, + 1714295, 439288460, 3415069, 875112161, 1759347, 450833045, + -817536, -209493775, -3574466, -915957677, 0, 0, + -1005239, -257592709, 2453983, 628833668, 1460718, 374309300, + 3756790, 962678241, -1935799, -496048908, -1716988, -439978542, + -3950053, -1012201926, 0, 0, 557458, 142848732, + -642628, -164673562, -3585098, -918682129, -2897314, -742437332, + 3192354, 818041395, 556856, 142694469, 3870317, 991769559, + 0, 0, -1221177, -312926867, 2815639, 721508096, + 2283733, 585207070, 2917338, 747568486, 1853806, 475038184, + 3345963, 857403734, 1858416, 476219497, 0, 0, +}; + +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer78[] = { + 3073009, 1277625, -2635473, 3852015, 787459213, + 327391679, -675340520, 987079667, 1753, -2659525, + 2660408, -59148, 449207, -681503850, 681730119, + -15156688, -1935420, -1455890, -1780227, 2772600, + -495951789, -373072124, -456183549, 710479343, 4183372, + -3222807, -3121440, -274060, 1071989969, -825844983, + -799869667, -70227934, 1182243, 636927, -3956745, + -3284915, 302950022, 163212680, -1013916752, -841760171, + 87208, -3965306, -2296397, -3716946, 22347069, + -1016110510, -588452222, -952468207, 2508980, 2028118, + 1937570, -3815725, 642926661, 519705671, 496502727, + -977780347, -27812, 1009365, -1979497, -3956944, + -7126831, 258649997, -507246529, -1013967746, 822541, + -2454145, 1596822, -3759465, 210776307, -628875181, + 409185979, -963363710, 2811291, -2983781, -1109516, + 4158088, 720393920, -764594519, -284313712, 1065510939, + -1685153, 2678278, -3551006, -250446, -431820817, + 686309310, -909946047, -64176841, -3410568, -3768948, + 635956, -2455377, -873958779, -965793731, 162963861, + -629190881, 1528066, 482649, 1148858, -2962264, + 391567239, 123678909, 294395108, -759080783, -4146264, + 2192938, 2387513, -268456, -1062481036, 561940831, + 611800717, -68791907, -1772588, -1727088, -3611750, + -3180456, -454226054, -442566669, -925511710, -814992530, + -565603, 169688, 2462444, -3334383, -144935890, + 43482586, 631001801, -854436357, 3747250, 1239911, + 3195676, 1254190, 960233614, 317727459, 818892658, + 321386456, 2296099, -3838479, 2642980, -12417, + 588375860, -983611064, 677264190, -3181859, -4166425, + -3488383, 1987814, -3197248, -1067647297, -893898890, + 509377762, -819295484, 2998219, -89301, -1354892, + -1310261, 768294260, -22883400, -347191365, -335754661, + 141835, 2513018, 613238, -2218467, 36345249, + 643961400, 157142369, -568482643, 1736313, 235407, + -3250154, 3258457, 444930577, 60323094, -832852657, + 834980303, -458740, 4040196, 2039144, -818761, + -117552223, 1035301089, 522531086, -209807681, -1921994, + -3472069, -1879878, -2178965, -492511373, -889718424, + -481719139, -558360247, -2579253, 1787943, -2391089, + -2254727, -660934133, 458160776, -612717067, -577774276, + -1623354, -2374402, 586241, 527981, -415984810, + -608441020, 150224382, 135295244, 2105286, -2033807, + -1179613, -2743411, 539479988, -521163479, -302276083, + -702999655, 3482206, -4182915, -1300016, -2362063, + 892316032, -1071872863, -333129378, -605279149, -1476985, + 2491325, 507927, -724804, -378477722, 638402564, + 130156402, -185731180, 1994046, -1393159, -1187885, + -1834526, 510974714, -356997292, -304395785, -470097680, + -1317678, 2461387, 3035980, 621164, -337655269, + 630730945, 777970524, 159173408, -3033742, 2647994, + -2612853, 749577, -777397036, 678549029, -669544140, + 192079267, -338420, 3009748, 4148469, -4022750, + -86720197, 771248568, 1063046068, -1030830548, 3901472, + -1226661, 2925816, 3374250, 999753034, -314332144, + 749740976, 864652284, 3980599, -1615530, 1665318, + 1163598, 1020029345, -413979908, 426738094, 298172236, + 2569011, 1723229, 2028038, -3369273, 658309618, + 441577800, 519685171, -863376927, 1356448, -2775755, + 2683270, -2778788, 347590090, -711287812, 687588511, + -712065019, 3994671, -1370517, 3363542, 545376, + 1023635298, -351195274, 861908357, 139752717, -11879, + 3020393, 214880, -770441, -3043996, 773976352, + 55063046, -197425671, -3467665, 2312838, -653275, + -459163, -888589898, 592665232, -167401858, -117660617, + 3105558, 508145, 860144, 140244, 795799901, + 130212265, 220412084, 35937555, -1103344, -553718, + 3430436, -1514152, -282732136, -141890356, 879049958, + -388001774, 348812, -327848, 1011223, -2354215, + 89383150, -84011120, 259126110, -603268097, -2185084, + 2358373, -3014420, 2926054, -559928242, 604333585, + -772445769, 749801963, 3123762, -2193087, -1716814, + -392707, 800464680, -561979013, -439933955, -100631253, + -3818627, -1922253, -2236726, 1744507, -978523985, + -492577742, -573161516, 447030292, -303005, -3974485, + 1900052, 1054478, -77645096, -1018462631, 486888731, + 270210213, 3531229, -3773731, -781875, -731434, + 904878186, -967019376, -200355636, -187430119, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer78[] = { + -1744507, 2236726, 1922253, 3818627, -447030292, 573161516, + 492577742, 978523985, 731434, 781875, 3773731, -3531229, + 187430119, 200355636, 967019376, -904878186, -1054478, -1900052, + 3974485, 303005, -270210213, -486888731, 1018462631, 77645096, + 2354215, -1011223, 327848, -348812, 603268097, -259126110, + 84011120, -89383150, 392707, 1716814, 2193087, -3123762, + 100631253, 439933955, 561979013, -800464680, -2926054, 3014420, + -2358373, 2185084, -749801963, 772445769, -604333585, 559928242, + 459163, 653275, -2312838, 3467665, 117660617, 167401858, + -592665232, 888589898, 1514152, -3430436, 553718, 1103344, + 388001774, -879049958, 141890356, 282732136, -140244, -860144, + -508145, -3105558, -35937555, -220412084, -130212265, -795799901, + 2778788, -2683270, 2775755, -1356448, 712065019, -687588511, + 711287812, -347590090, 770441, -214880, -3020393, 11879, + 197425671, -55063046, -773976352, 3043996, -545376, -3363542, + 1370517, -3994671, -139752717, -861908357, 351195274, -1023635298, + -3374250, -2925816, 1226661, -3901472, -864652284, -749740976, + 314332144, -999753034, 3369273, -2028038, -1723229, -2569011, + 863376927, -519685171, -441577800, -658309618, -1163598, -1665318, + 1615530, -3980599, -298172236, -426738094, 413979908, -1020029345, + -621164, -3035980, -2461387, 1317678, -159173408, -777970524, + -630730945, 337655269, 4022750, -4148469, -3009748, 338420, + 1030830548, -1063046068, -771248568, 86720197, -749577, 2612853, + -2647994, 3033742, -192079267, 669544140, -678549029, 777397036, + 2362063, 1300016, 4182915, -3482206, 605279149, 333129378, + 1071872863, -892316032, 1834526, 1187885, 1393159, -1994046, + 470097680, 304395785, 356997292, -510974714, 724804, -507927, + -2491325, 1476985, 185731180, -130156402, -638402564, 378477722, + 2254727, 2391089, -1787943, 2579253, 577774276, 612717067, + -458160776, 660934133, 2743411, 1179613, 2033807, -2105286, + 702999655, 302276083, 521163479, -539479988, -527981, -586241, + 2374402, 1623354, -135295244, -150224382, 608441020, 415984810, + -3258457, 3250154, -235407, -1736313, -834980303, 832852657, + -60323094, -444930577, 2178965, 1879878, 3472069, 1921994, + 558360247, 481719139, 889718424, 492511373, 818761, -2039144, + -4040196, 458740, 209807681, -522531086, -1035301089, 117552223, + 3197248, -1987814, 3488383, 4166425, 819295484, -509377762, + 893898890, 1067647297, 2218467, -613238, -2513018, -141835, + 568482643, -157142369, -643961400, -36345249, 1310261, 1354892, + 89301, -2998219, 335754661, 347191365, 22883400, -768294260, + 3334383, -2462444, -169688, 565603, 854436357, -631001801, + -43482586, 144935890, 12417, -2642980, 3838479, -2296099, + 3181859, -677264190, 983611064, -588375860, -1254190, -3195676, + -1239911, -3747250, -321386456, -818892658, -317727459, -960233614, + 2962264, -1148858, -482649, -1528066, 759080783, -294395108, + -123678909, -391567239, 3180456, 3611750, 1727088, 1772588, + 814992530, 925511710, 442566669, 454226054, 268456, -2387513, + -2192938, 4146264, 68791907, -611800717, -561940831, 1062481036, + -4158088, 1109516, 2983781, -2811291, -1065510939, 284313712, + 764594519, -720393920, 2455377, -635956, 3768948, 3410568, + 629190881, -162963861, 965793731, 873958779, 250446, 3551006, + -2678278, 1685153, 64176841, 909946047, -686309310, 431820817, + 3815725, -1937570, -2028118, -2508980, 977780347, -496502727, + -519705671, -642926661, 3759465, -1596822, 2454145, -822541, + 963363710, -409185979, 628875181, -210776307, 3956944, 1979497, + -1009365, 27812, 1013967746, 507246529, -258649997, 7126831, + 274060, 3121440, 3222807, -4183372, 70227934, 799869667, + 825844983, -1071989969, 3716946, 2296397, 3965306, -87208, + 952468207, 588452222, 1016110510, -22347069, 3284915, 3956745, + -636927, -1182243, 841760171, 1013916752, -163212680, -302950022, + -3852015, 2635473, -1277625, -3073009, -987079667, 675340520, + -327391679, -787459213, -2772600, 1780227, 1455890, 1935420, + -710479343, 456183549, 373072124, 495951789, 59148, -2660408, + 2659525, -1753, 15156688, -681730119, 681503850, -449207, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer123456[] = { + -2283733, -585207070, 0, 0, -1858416, -476219497, + -3345963, -857403734, -2815639, -721508096, 0, 0, + -1853806, -475038184, -2917338, -747568486, 3585098, 918682129, + 0, 0, -3870317, -991769559, -556856, -142694469, + 642628, 164673562, 0, 0, -3192354, -818041395, + 2897314, 742437332, -1460718, -374309300, 0, 0, + 3950053, 1012201926, 1716988, 439978542, -2453983, -628833668, + 0, 0, 1935799, 496048908, -3756790, -962678241, + -1714295, -439288460, 0, 0, 3574466, 915957677, + 817536, 209493775, 3227876, 827143915, 0, 0, + -1759347, -450833045, -3415069, -875112161, 1335936, 342333886, + 0, 0, -2156050, -552488273, -3241972, -830756018, + -676590, -173376332, 0, 0, 4018989, 1029866791, + -2071829, -530906624, 434125, 111244624, 0, 0, + 3506380, 898510625, -1095468, -280713909, 3524442, 903139016, + 0, 0, -928749, -237992130, -394148, -101000509, + 1674615, 429120452, 0, 0, -1159875, -297218217, + -3704823, -949361686, -2663378, -682491182, 0, 0, + -2101410, -538486762, 3110818, 797147778, 4063053, 1041158200, + 0, 0, 3586446, 919027554, -2740543, -702264730, + 3370349, 863652652, 0, 0, -3182878, -815613168, + -3602218, -923069133, -294725, -75523344, -3761513, -963888510, + -3765607, -964937599, 3201430, 820367122, 3145678, 806080660, + 2883726, 738955404, 3201494, 820383522, 1221177, 312926867, + -557458, -142848732, 1005239, 257592709, -3764867, -964747974, + -2129892, -545785280, -2682288, -687336873, -3542485, -907762539, + 601683, 154181397, 0, 0, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_zetas) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/src/arith_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/src/arith_native_aarch64.h new file mode 100644 index 0000000000..e77f55014c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/src/arith_native_aarch64.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#define MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H + +#include +#include "../../../common.h" + +#define mld_aarch64_ntt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_ntt_zetas_layer123456) +#define mld_aarch64_ntt_zetas_layer78 MLD_NAMESPACE(aarch64_ntt_zetas_layer78) + +#define mld_aarch64_intt_zetas_layer78 MLD_NAMESPACE(aarch64_intt_zetas_layer78) +#define mld_aarch64_intt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_intt_zetas_layer123456) + +extern const int32_t mld_aarch64_ntt_zetas_layer123456[]; +extern const int32_t mld_aarch64_ntt_zetas_layer78[]; + +extern const int32_t mld_aarch64_intt_zetas_layer78[]; +extern const int32_t mld_aarch64_intt_zetas_layer123456[]; + +#define mld_rej_uniform_table MLD_NAMESPACE(rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[]; +#define mld_rej_uniform_eta_table MLD_NAMESPACE(rej_uniform_eta_table) +extern const uint8_t mld_rej_uniform_eta_table[]; + +#define mld_polyz_unpack_17_indices MLD_NAMESPACE(polyz_unpack_17_indices) +extern const uint8_t mld_polyz_unpack_17_indices[]; +#define mld_polyz_unpack_19_indices MLD_NAMESPACE(polyz_unpack_19_indices) +extern const uint8_t mld_polyz_unpack_19_indices[]; + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_ntt_asm MLD_NAMESPACE(ntt_asm) +void mld_ntt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_intt_asm MLD_NAMESPACE(intt_asm) +void mld_intt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_rej_uniform_asm MLD_NAMESPACE(rej_uniform_asm) +uint64_t mld_rej_uniform_asm(int32_t *r, const uint8_t *buf, unsigned buflen, + const uint8_t *table); + +#define mld_rej_uniform_eta2_asm MLD_NAMESPACE(rej_uniform_eta2_asm) +uint64_t mld_rej_uniform_eta2_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_rej_uniform_eta4_asm MLD_NAMESPACE(rej_uniform_eta4_asm) +uint64_t mld_rej_uniform_eta4_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_poly_decompose_32_asm MLD_NAMESPACE(poly_decompose_32_asm) +void mld_poly_decompose_32_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_asm MLD_NAMESPACE(poly_decompose_88_asm) +void mld_poly_decompose_88_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_asm MLD_NAMESPACE(poly_caddq_asm) +void mld_poly_caddq_asm(int32_t *a); + +#define mld_poly_use_hint_32_asm MLD_NAMESPACE(poly_use_hint_32_asm) +void mld_poly_use_hint_32_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_asm MLD_NAMESPACE(poly_use_hint_88_asm) +void mld_poly_use_hint_88_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_asm MLD_NAMESPACE(poly_chknorm_asm) +int mld_poly_chknorm_asm(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_asm MLD_NAMESPACE(polyz_unpack_17_asm) +void mld_polyz_unpack_17_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_polyz_unpack_19_asm MLD_NAMESPACE(polyz_unpack_19_asm) +void mld_polyz_unpack_19_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_poly_pointwise_montgomery_asm \ + MLD_NAMESPACE(poly_pointwise_montgomery_asm) +void mld_poly_pointwise_montgomery_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l4_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l4_asm) +void mld_polyvecl_pointwise_acc_montgomery_l4_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l5_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l5_asm) +void mld_polyvecl_pointwise_acc_montgomery_l5_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l7_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l7_asm) +void mld_polyvecl_pointwise_acc_montgomery_l7_asm(int32_t *, const int32_t *, + const int32_t *); + +#endif /* !MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/src/polyz_unpack_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/src/polyz_unpack_table.c new file mode 100644 index 0000000000..7ef915b587 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/src/polyz_unpack_table.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* Table of indices used for tbl instructions in polyz_unpack_{17,19}. */ + +MLD_ALIGN const uint8_t mld_polyz_unpack_17_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, + 9, 10, 11, 255, 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, + 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, 8, 9, 10, 255, + 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, 17, 18, 19, 255, +}; + +MLD_ALIGN const uint8_t mld_polyz_unpack_19_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 5, 6, 7, 255, 7, 8, 9, 255, + 10, 11, 12, 255, 12, 13, 14, 255, 15, 16, 17, 255, 17, 18, 19, 255, + 4, 5, 6, 255, 6, 7, 8, 255, 9, 10, 11, 255, 11, 12, 13, 255, + 14, 15, 16, 255, 16, 17, 18, 255, 19, 20, 21, 255, 21, 22, 23, 255, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_polyz_unpack_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/src/rej_uniform_eta_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/src/rej_uniform_eta_table.c new file mode 100644 index 0000000000..cf21509cbf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/src/rej_uniform_eta_table.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by 16-bit rejection sampling (rej_eta). + * Adapted from ML-KEM for ML-DSA eta rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_eta_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 2, 3, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 4, 5, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 2, 3, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 7 */, + 6, 7, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 2, 3, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 11 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 13 */, + 2, 3, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 15 */, + 8, 9, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 16 */, + 0, 1, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 17 */, + 2, 3, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 18 */, + 0, 1, 2, 3, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 19 */, + 4, 5, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 20 */, + 0, 1, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 21 */, + 2, 3, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 22 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 23 */, + 6, 7, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 24 */, + 0, 1, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 25 */, + 2, 3, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 26 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 27 */, + 4, 5, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 28 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 29 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 30 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 255, 255, 255, 255, 255, 255 /* 31 */, + 10, 11, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 32 */, + 0, 1, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 33 */, + 2, 3, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 34 */, + 0, 1, 2, 3, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 35 */, + 4, 5, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 36 */, + 0, 1, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 37 */, + 2, 3, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 38 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 39 */, + 6, 7, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 40 */, + 0, 1, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 41 */, + 2, 3, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 42 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 43 */, + 4, 5, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 44 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 45 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 46 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 255, 255, 255, 255, 255, 255 /* 47 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 48 */, + 0, 1, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 49 */, + 2, 3, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 50 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 51 */, + 4, 5, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 52 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 53 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 54 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 55 */, + 6, 7, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 56 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 57 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 58 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 59 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 60 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 61 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 62 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 63 */, + 12, 13, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 64 */, + 0, 1, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 65 */, + 2, 3, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 66 */, + 0, 1, 2, 3, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 67 */, + 4, 5, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 68 */, + 0, 1, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 69 */, + 2, 3, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 70 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 71 */, + 6, 7, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 72 */, + 0, 1, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 73 */, + 2, 3, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 74 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 75 */, + 4, 5, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 76 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 77 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 78 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 255, 255, 255, 255, 255, 255 /* 79 */, + 8, 9, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 80 */, + 0, 1, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 81 */, + 2, 3, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 82 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 83 */, + 4, 5, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 84 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 85 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 86 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 87 */, + 6, 7, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 88 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 89 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 90 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 91 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 92 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 93 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 94 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 255, 255, 255, 255 /* 95 */, + 10, 11, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 96 */, + 0, 1, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 97 */, + 2, 3, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 98 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 99 */, + 4, 5, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 100 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 101 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 102 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 103 */, + 6, 7, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 104 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 105 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 106 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 107 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 108 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 109 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 110 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 255, 255, 255, 255 /* 111 */, + 8, 9, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 112 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 113 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 114 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 115 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 116 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 117 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 118 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 119 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 120 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 121 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 122 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 123 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 124 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 125 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 126 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 255, 255 /* 127 */, + 14, 15, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 128 */, + 0, 1, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 129 */, + 2, 3, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 130 */, + 0, 1, 2, 3, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 131 */, + 4, 5, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 132 */, + 0, 1, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 133 */, + 2, 3, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 134 */, + 0, 1, 2, 3, 4, 5, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 135 */, + 6, 7, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 136 */, + 0, 1, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 137 */, + 2, 3, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 138 */, + 0, 1, 2, 3, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 139 */, + 4, 5, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 140 */, + 0, 1, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 141 */, + 2, 3, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 142 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 14, 15, 255, 255, 255, 255, 255, 255 /* 143 */, + 8, 9, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 144 */, + 0, 1, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 145 */, + 2, 3, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 146 */, + 0, 1, 2, 3, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 147 */, + 4, 5, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 148 */, + 0, 1, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 149 */, + 2, 3, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 150 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 151 */, + 6, 7, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 152 */, + 0, 1, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 153 */, + 2, 3, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 154 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 155 */, + 4, 5, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 156 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 157 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 158 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 14, 15, 255, 255, 255, 255 /* 159 */, + 10, 11, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 160 */, + 0, 1, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 161 */, + 2, 3, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 162 */, + 0, 1, 2, 3, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 163 */, + 4, 5, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 164 */, + 0, 1, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 165 */, + 2, 3, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 166 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 167 */, + 6, 7, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 168 */, + 0, 1, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 169 */, + 2, 3, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 170 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 171 */, + 4, 5, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 172 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 173 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 174 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 14, 15, 255, 255, 255, 255 /* 175 */, + 8, 9, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 176 */, + 0, 1, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 177 */, + 2, 3, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 178 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 179 */, + 4, 5, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 180 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 181 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 182 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 183 */, + 6, 7, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 184 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 185 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 186 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 187 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 188 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 189 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 190 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 14, 15, 255, 255 /* 191 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 192 */, + 0, 1, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 193 */, + 2, 3, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 194 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 195 */, + 4, 5, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 196 */, + 0, 1, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 197 */, + 2, 3, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 198 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 199 */, + 6, 7, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 200 */, + 0, 1, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 201 */, + 2, 3, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 202 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 203 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 204 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 205 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 206 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 207 */, + 8, 9, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 208 */, + 0, 1, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 209 */, + 2, 3, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 210 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 211 */, + 4, 5, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 212 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 213 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 214 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 215 */, + 6, 7, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 216 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 217 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 218 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 219 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 220 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 221 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 222 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 14, 15, 255, 255 /* 223 */, + 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 224 */, + 0, 1, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 225 */, + 2, 3, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 226 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 227 */, + 4, 5, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 228 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 229 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 230 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 231 */, + 6, 7, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 232 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 233 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 234 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 235 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 236 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 237 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 238 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 14, 15, 255, 255 /* 239 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 240 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 241 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 242 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 243 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 244 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 245 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 246 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 247 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 248 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 249 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 250 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 251 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 252 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 253 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 254 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 255 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_eta_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/src/rej_uniform_table.c new file mode 100644 index 0000000000..65bc3b78d3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_clean/src/rej_uniform_table.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by rejection sampling of the public matrix. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 7 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 11 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 13 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 15 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/README.md new file mode 100644 index 0000000000..b6e2910d9a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/README.md @@ -0,0 +1,15 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# AArch64 backend (little endian) + +This directory contains a native backend for little endian AArch64 systems. It is derived from [^NeonNTT] [^SLOTHY_Paper]. + +## Variants + +This backend comes in two versions: "clean" and optimized. The "clean" backend is handwritten and meant to be easy to read and modify; for example, it heavily leverages register aliases and assembly macros. This directory contains the optimized version, which is automatically generated from the clean one via [SLOTHY](https://github.com/slothy-optimizer/slothy). Currently, the target architecture is Neoverse N1, but you can easily re-optimize the code for a different microarchitecture supported by SLOTHY, by adjusting the parameters in the [Makefile](src/Makefile). + +Performance on in-order CPUs such as the Arm Cortex-A55 can be significantly improved by re-optimizing for the specific CPU which may, however, degrade performance on other CPUs. + + +[^NeonNTT]: Becker, Hwang, Kannwischer, Yang, Yang: Neon NTT: Faster Dilithium, Kyber, and Saber on Cortex-A72 and Apple M1, [https://eprint.iacr.org/2021/986](https://eprint.iacr.org/2021/986) +[^SLOTHY_Paper]: Abdulrahman, Becker, Kannwischer, Klein: Fast and Clean: Auditable high-performance assembly via constraint solving, [https://eprint.iacr.org/2022/1303](https://eprint.iacr.org/2022/1303) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/meta.h new file mode 100644 index 0000000000..c6f6ad47b0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/meta.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_META_H +#define MLD_NATIVE_AARCH64_META_H + +/* Set of primitives that this backend replaces */ +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_AARCH64 + + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/arith_native_aarch64.h" + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + mld_ntt_asm(data, mld_aarch64_ntt_zetas_layer123456, + mld_aarch64_ntt_zetas_layer78); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + mld_intt_asm(data, mld_aarch64_intt_zetas_layer78, + mld_aarch64_intt_zetas_layer123456); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + if (len != MLDSA_N || + buflen % 24 != 0) /* NEON support is mandatory for AArch64 */ + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N, hence, this cast is safe. */ + return (int)mld_rej_uniform_asm(r, buf, buflen, mld_rej_uniform_table); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_32_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_88_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + mld_poly_caddq_asm(a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_32_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_88_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + return mld_poly_chknorm_asm(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_17_asm(r, buf, mld_polyz_unpack_17_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_19_asm(r, buf, mld_polyz_unpack_19_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t out[MLDSA_N], const int32_t in0[MLDSA_N], + const int32_t in1[MLDSA_N]) +{ + mld_poly_pointwise_montgomery_asm(out, in0, in1); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l4_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l5_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l7_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ +#endif /* !MLD_NATIVE_AARCH64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/Makefile new file mode 100644 index 0000000000..4f280d4b27 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/Makefile @@ -0,0 +1,125 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +###### +# To run, see the README.md file +###### +.PHONY: all clean + +# ISA to optimize for +TARGET_ISA=Arm_AArch64 + +# MicroArch target to optimize for +# Changing this to Arm_Cortex_A55 results in significantly better performance +# on the Cortex-A55, but may result in worse performance on other CPUs. +TARGET_MICROARCH=Arm_Neoverse_N1_experimental + +SLOTHY_EXTRA_FLAGS ?= + +SLOTHY_FLAGS=-c sw_pipelining.enabled=true \ + -c inputs_are_outputs \ + -c sw_pipelining.minimize_overlapping=False \ + -c sw_pipelining.allow_post \ + -c variable_size \ + -c constraints.stalls_first_attempt=64 \ + $(SLOTHY_EXTRA_FLAGS) + +SLOTHY_FLAGS_SPLIT= -c inputs_are_outputs \ + -c variable_size \ + -c constraints.stalls_first_attempt=64 \ + -c split_heuristic=true \ + -c split_heuristic_repeat=2 \ + -c sw_pipelining.enabled=true \ + -c sw_pipelining.halving_heuristic=True \ + $(SLOTHY_EXTRA_FLAGS) + +# For kernels which stash callee-saved v8-v15 but don't stash callee-saved GPRs x19-x30. +# Allow SLOTHY to use all V-registers, but only caller-saved GPRs. +RESERVE_X_ONLY_FLAG=-c reserved_regs="[x18--x30,sp]" + +# Used for kernels which don't stash callee-saved registers. +# Restrict SLOTHY to caller-saved registers. +RESERVE_ALL_FLAG=-c reserved_regs="[x18--x30,sp,v8--v15]" + +all: ntt.S \ + intt.S \ + mld_polyvecl_pointwise_acc_montgomery_l4.S \ + mld_polyvecl_pointwise_acc_montgomery_l5.S \ + mld_polyvecl_pointwise_acc_montgomery_l7.S \ + pointwise_montgomery.S \ + poly_caddq_asm.S \ + poly_chknorm_asm.S \ + poly_decompose_32_asm.S \ + poly_decompose_88_asm.S \ + poly_use_hint_32_asm.S \ + poly_use_hint_88_asm.S \ + polyz_unpack_17_asm.S \ + polyz_unpack_19_asm.S \ + rej_uniform_asm.S \ + rej_uniform_eta2_asm.S \ + rej_uniform_eta4_asm.S + +# These units explicitly save and restore registers v8-v15, so SLOTHY can freely use +# those registers. +ntt.S: ../../aarch64_clean/src/ntt.S + # optimize first loop in one go and write to temp file + $(eval TMPFILE := $(shell mktemp)) + slothy-cli $(TARGET_ISA) $(TARGET_MICROARCH) $< -o $(TMPFILE) -l ntt_layer123_start $(SLOTHY_FLAGS) $(RESERVE_X_ONLY_FLAG) + # optimize second loop using split heuristic + slothy-cli $(TARGET_ISA) $(TARGET_MICROARCH) $(TMPFILE) -o $@ -l ntt_layer45678_start $(SLOTHY_FLAGS_SPLIT) -c split_heuristic_factor=1.5 $(RESERVE_X_ONLY_FLAG) + +# Copy remaining files without optimization for now +intt.S: ../../aarch64_clean/src/intt.S + # optimize first loop in one go and write to temp file + $(eval TMPFILE := $(shell mktemp)) + slothy-cli $(TARGET_ISA) $(TARGET_MICROARCH) $< -o $(TMPFILE) -l intt_layer5678_start $(SLOTHY_FLAGS) -c reserved_regs="[x0,x18--x30,sp]" + # optimize second loop using split heuristic + slothy-cli $(TARGET_ISA) $(TARGET_MICROARCH) $(TMPFILE) -o $@ -l intt_layer1234_start $(SLOTHY_FLAGS_SPLIT) -c split_heuristic_factor=2.5 $(RESERVE_X_ONLY_FLAG) + +mld_polyvecl_pointwise_acc_montgomery_l4.S: ../../aarch64_clean/src/mld_polyvecl_pointwise_acc_montgomery_l4.S + cp $< $@ + +mld_polyvecl_pointwise_acc_montgomery_l5.S: ../../aarch64_clean/src/mld_polyvecl_pointwise_acc_montgomery_l5.S + cp $< $@ + +mld_polyvecl_pointwise_acc_montgomery_l7.S: ../../aarch64_clean/src/mld_polyvecl_pointwise_acc_montgomery_l7.S + cp $< $@ + +pointwise_montgomery.S: ../../aarch64_clean/src/pointwise_montgomery.S + cp $< $@ + +poly_caddq_asm.S: ../../aarch64_clean/src/poly_caddq_asm.S + cp $< $@ + +poly_chknorm_asm.S: ../../aarch64_clean/src/poly_chknorm_asm.S + cp $< $@ + +poly_decompose_32_asm.S: ../../aarch64_clean/src/poly_decompose_32_asm.S + cp $< $@ + +poly_decompose_88_asm.S: ../../aarch64_clean/src/poly_decompose_88_asm.S + cp $< $@ + +poly_use_hint_32_asm.S: ../../aarch64_clean/src/poly_use_hint_32_asm.S + cp $< $@ + +poly_use_hint_88_asm.S: ../../aarch64_clean/src/poly_use_hint_88_asm.S + cp $< $@ + +polyz_unpack_17_asm.S: ../../aarch64_clean/src/polyz_unpack_17_asm.S + cp $< $@ + +polyz_unpack_19_asm.S: ../../aarch64_clean/src/polyz_unpack_19_asm.S + cp $< $@ + +rej_uniform_asm.S: ../../aarch64_clean/src/rej_uniform_asm.S + cp $< $@ + +rej_uniform_eta2_asm.S: ../../aarch64_clean/src/rej_uniform_eta2_asm.S + cp $< $@ + +rej_uniform_eta4_asm.S: ../../aarch64_clean/src/rej_uniform_eta4_asm.S + cp $< $@ + +clean: + -$(RM) -rf *.S diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/README.md new file mode 100644 index 0000000000..94deeaf1f4 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/README.md @@ -0,0 +1,15 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# mldsa-native AArch64 backend SLOTHY-optimized code + +This directory contains the AArch64 backend after it has been optimized by [SLOTHY](https://github.com/slothy-optimizer/slothy/). + +## Re-running SLOTHY + +If the "clean" sources [`../../aarch64_clean/src/*.S`](../../aarch64_clean/src/) change, take the following steps to re-optimize and install them into the main source tree: + +1. Run `make` to re-generate the optimized sources using SLOTHY. This assumes a working SLOTHY setup, as established e.g. by the default nix shell for mldsa-native. See also the [SLOTHY README](https://github.com/slothy-optimizer/slothy/). + +2. Run `autogen` to transfer the newly optimized files into the main source tree [mldsa/src/native](../../../mldsa/src/native). + +3. Run `./scripts/tests all --opt=OPT` to check that the new assembly is still functional. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/aarch64_zetas.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/aarch64_zetas.c new file mode 100644 index 0000000000..9ab7b9a68c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/aarch64_zetas.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Table of zeta values used in the AArch64 forward NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer123456[] = { + -3572223, -915382907, 3765607, 964937599, 3761513, 963888510, + -3201494, -820383522, -2883726, -738955404, -3145678, -806080660, + -3201430, -820367122, 0, 0, -601683, -154181397, + -3370349, -863652652, -4063053, -1041158200, 3602218, 923069133, + 3182878, 815613168, 2740543, 702264730, -3586446, -919027554, + 0, 0, 3542485, 907762539, 2663378, 682491182, + -1674615, -429120452, -3110818, -797147778, 2101410, 538486762, + 3704823, 949361686, 1159875, 297218217, 0, 0, + 2682288, 687336873, -3524442, -903139016, -434125, -111244624, + 394148, 101000509, 928749, 237992130, 1095468, 280713909, + -3506380, -898510625, 0, 0, 2129892, 545785280, + 676590, 173376332, -1335936, -342333886, 2071829, 530906624, + -4018989, -1029866791, 3241972, 830756018, 2156050, 552488273, + 0, 0, 3764867, 964747974, -3227876, -827143915, + 1714295, 439288460, 3415069, 875112161, 1759347, 450833045, + -817536, -209493775, -3574466, -915957677, 0, 0, + -1005239, -257592709, 2453983, 628833668, 1460718, 374309300, + 3756790, 962678241, -1935799, -496048908, -1716988, -439978542, + -3950053, -1012201926, 0, 0, 557458, 142848732, + -642628, -164673562, -3585098, -918682129, -2897314, -742437332, + 3192354, 818041395, 556856, 142694469, 3870317, 991769559, + 0, 0, -1221177, -312926867, 2815639, 721508096, + 2283733, 585207070, 2917338, 747568486, 1853806, 475038184, + 3345963, 857403734, 1858416, 476219497, 0, 0, +}; + +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer78[] = { + 3073009, 1277625, -2635473, 3852015, 787459213, + 327391679, -675340520, 987079667, 1753, -2659525, + 2660408, -59148, 449207, -681503850, 681730119, + -15156688, -1935420, -1455890, -1780227, 2772600, + -495951789, -373072124, -456183549, 710479343, 4183372, + -3222807, -3121440, -274060, 1071989969, -825844983, + -799869667, -70227934, 1182243, 636927, -3956745, + -3284915, 302950022, 163212680, -1013916752, -841760171, + 87208, -3965306, -2296397, -3716946, 22347069, + -1016110510, -588452222, -952468207, 2508980, 2028118, + 1937570, -3815725, 642926661, 519705671, 496502727, + -977780347, -27812, 1009365, -1979497, -3956944, + -7126831, 258649997, -507246529, -1013967746, 822541, + -2454145, 1596822, -3759465, 210776307, -628875181, + 409185979, -963363710, 2811291, -2983781, -1109516, + 4158088, 720393920, -764594519, -284313712, 1065510939, + -1685153, 2678278, -3551006, -250446, -431820817, + 686309310, -909946047, -64176841, -3410568, -3768948, + 635956, -2455377, -873958779, -965793731, 162963861, + -629190881, 1528066, 482649, 1148858, -2962264, + 391567239, 123678909, 294395108, -759080783, -4146264, + 2192938, 2387513, -268456, -1062481036, 561940831, + 611800717, -68791907, -1772588, -1727088, -3611750, + -3180456, -454226054, -442566669, -925511710, -814992530, + -565603, 169688, 2462444, -3334383, -144935890, + 43482586, 631001801, -854436357, 3747250, 1239911, + 3195676, 1254190, 960233614, 317727459, 818892658, + 321386456, 2296099, -3838479, 2642980, -12417, + 588375860, -983611064, 677264190, -3181859, -4166425, + -3488383, 1987814, -3197248, -1067647297, -893898890, + 509377762, -819295484, 2998219, -89301, -1354892, + -1310261, 768294260, -22883400, -347191365, -335754661, + 141835, 2513018, 613238, -2218467, 36345249, + 643961400, 157142369, -568482643, 1736313, 235407, + -3250154, 3258457, 444930577, 60323094, -832852657, + 834980303, -458740, 4040196, 2039144, -818761, + -117552223, 1035301089, 522531086, -209807681, -1921994, + -3472069, -1879878, -2178965, -492511373, -889718424, + -481719139, -558360247, -2579253, 1787943, -2391089, + -2254727, -660934133, 458160776, -612717067, -577774276, + -1623354, -2374402, 586241, 527981, -415984810, + -608441020, 150224382, 135295244, 2105286, -2033807, + -1179613, -2743411, 539479988, -521163479, -302276083, + -702999655, 3482206, -4182915, -1300016, -2362063, + 892316032, -1071872863, -333129378, -605279149, -1476985, + 2491325, 507927, -724804, -378477722, 638402564, + 130156402, -185731180, 1994046, -1393159, -1187885, + -1834526, 510974714, -356997292, -304395785, -470097680, + -1317678, 2461387, 3035980, 621164, -337655269, + 630730945, 777970524, 159173408, -3033742, 2647994, + -2612853, 749577, -777397036, 678549029, -669544140, + 192079267, -338420, 3009748, 4148469, -4022750, + -86720197, 771248568, 1063046068, -1030830548, 3901472, + -1226661, 2925816, 3374250, 999753034, -314332144, + 749740976, 864652284, 3980599, -1615530, 1665318, + 1163598, 1020029345, -413979908, 426738094, 298172236, + 2569011, 1723229, 2028038, -3369273, 658309618, + 441577800, 519685171, -863376927, 1356448, -2775755, + 2683270, -2778788, 347590090, -711287812, 687588511, + -712065019, 3994671, -1370517, 3363542, 545376, + 1023635298, -351195274, 861908357, 139752717, -11879, + 3020393, 214880, -770441, -3043996, 773976352, + 55063046, -197425671, -3467665, 2312838, -653275, + -459163, -888589898, 592665232, -167401858, -117660617, + 3105558, 508145, 860144, 140244, 795799901, + 130212265, 220412084, 35937555, -1103344, -553718, + 3430436, -1514152, -282732136, -141890356, 879049958, + -388001774, 348812, -327848, 1011223, -2354215, + 89383150, -84011120, 259126110, -603268097, -2185084, + 2358373, -3014420, 2926054, -559928242, 604333585, + -772445769, 749801963, 3123762, -2193087, -1716814, + -392707, 800464680, -561979013, -439933955, -100631253, + -3818627, -1922253, -2236726, 1744507, -978523985, + -492577742, -573161516, 447030292, -303005, -3974485, + 1900052, 1054478, -77645096, -1018462631, 486888731, + 270210213, 3531229, -3773731, -781875, -731434, + 904878186, -967019376, -200355636, -187430119, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer78[] = { + -1744507, 2236726, 1922253, 3818627, -447030292, 573161516, + 492577742, 978523985, 731434, 781875, 3773731, -3531229, + 187430119, 200355636, 967019376, -904878186, -1054478, -1900052, + 3974485, 303005, -270210213, -486888731, 1018462631, 77645096, + 2354215, -1011223, 327848, -348812, 603268097, -259126110, + 84011120, -89383150, 392707, 1716814, 2193087, -3123762, + 100631253, 439933955, 561979013, -800464680, -2926054, 3014420, + -2358373, 2185084, -749801963, 772445769, -604333585, 559928242, + 459163, 653275, -2312838, 3467665, 117660617, 167401858, + -592665232, 888589898, 1514152, -3430436, 553718, 1103344, + 388001774, -879049958, 141890356, 282732136, -140244, -860144, + -508145, -3105558, -35937555, -220412084, -130212265, -795799901, + 2778788, -2683270, 2775755, -1356448, 712065019, -687588511, + 711287812, -347590090, 770441, -214880, -3020393, 11879, + 197425671, -55063046, -773976352, 3043996, -545376, -3363542, + 1370517, -3994671, -139752717, -861908357, 351195274, -1023635298, + -3374250, -2925816, 1226661, -3901472, -864652284, -749740976, + 314332144, -999753034, 3369273, -2028038, -1723229, -2569011, + 863376927, -519685171, -441577800, -658309618, -1163598, -1665318, + 1615530, -3980599, -298172236, -426738094, 413979908, -1020029345, + -621164, -3035980, -2461387, 1317678, -159173408, -777970524, + -630730945, 337655269, 4022750, -4148469, -3009748, 338420, + 1030830548, -1063046068, -771248568, 86720197, -749577, 2612853, + -2647994, 3033742, -192079267, 669544140, -678549029, 777397036, + 2362063, 1300016, 4182915, -3482206, 605279149, 333129378, + 1071872863, -892316032, 1834526, 1187885, 1393159, -1994046, + 470097680, 304395785, 356997292, -510974714, 724804, -507927, + -2491325, 1476985, 185731180, -130156402, -638402564, 378477722, + 2254727, 2391089, -1787943, 2579253, 577774276, 612717067, + -458160776, 660934133, 2743411, 1179613, 2033807, -2105286, + 702999655, 302276083, 521163479, -539479988, -527981, -586241, + 2374402, 1623354, -135295244, -150224382, 608441020, 415984810, + -3258457, 3250154, -235407, -1736313, -834980303, 832852657, + -60323094, -444930577, 2178965, 1879878, 3472069, 1921994, + 558360247, 481719139, 889718424, 492511373, 818761, -2039144, + -4040196, 458740, 209807681, -522531086, -1035301089, 117552223, + 3197248, -1987814, 3488383, 4166425, 819295484, -509377762, + 893898890, 1067647297, 2218467, -613238, -2513018, -141835, + 568482643, -157142369, -643961400, -36345249, 1310261, 1354892, + 89301, -2998219, 335754661, 347191365, 22883400, -768294260, + 3334383, -2462444, -169688, 565603, 854436357, -631001801, + -43482586, 144935890, 12417, -2642980, 3838479, -2296099, + 3181859, -677264190, 983611064, -588375860, -1254190, -3195676, + -1239911, -3747250, -321386456, -818892658, -317727459, -960233614, + 2962264, -1148858, -482649, -1528066, 759080783, -294395108, + -123678909, -391567239, 3180456, 3611750, 1727088, 1772588, + 814992530, 925511710, 442566669, 454226054, 268456, -2387513, + -2192938, 4146264, 68791907, -611800717, -561940831, 1062481036, + -4158088, 1109516, 2983781, -2811291, -1065510939, 284313712, + 764594519, -720393920, 2455377, -635956, 3768948, 3410568, + 629190881, -162963861, 965793731, 873958779, 250446, 3551006, + -2678278, 1685153, 64176841, 909946047, -686309310, 431820817, + 3815725, -1937570, -2028118, -2508980, 977780347, -496502727, + -519705671, -642926661, 3759465, -1596822, 2454145, -822541, + 963363710, -409185979, 628875181, -210776307, 3956944, 1979497, + -1009365, 27812, 1013967746, 507246529, -258649997, 7126831, + 274060, 3121440, 3222807, -4183372, 70227934, 799869667, + 825844983, -1071989969, 3716946, 2296397, 3965306, -87208, + 952468207, 588452222, 1016110510, -22347069, 3284915, 3956745, + -636927, -1182243, 841760171, 1013916752, -163212680, -302950022, + -3852015, 2635473, -1277625, -3073009, -987079667, 675340520, + -327391679, -787459213, -2772600, 1780227, 1455890, 1935420, + -710479343, 456183549, 373072124, 495951789, 59148, -2660408, + 2659525, -1753, 15156688, -681730119, 681503850, -449207, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer123456[] = { + -2283733, -585207070, 0, 0, -1858416, -476219497, + -3345963, -857403734, -2815639, -721508096, 0, 0, + -1853806, -475038184, -2917338, -747568486, 3585098, 918682129, + 0, 0, -3870317, -991769559, -556856, -142694469, + 642628, 164673562, 0, 0, -3192354, -818041395, + 2897314, 742437332, -1460718, -374309300, 0, 0, + 3950053, 1012201926, 1716988, 439978542, -2453983, -628833668, + 0, 0, 1935799, 496048908, -3756790, -962678241, + -1714295, -439288460, 0, 0, 3574466, 915957677, + 817536, 209493775, 3227876, 827143915, 0, 0, + -1759347, -450833045, -3415069, -875112161, 1335936, 342333886, + 0, 0, -2156050, -552488273, -3241972, -830756018, + -676590, -173376332, 0, 0, 4018989, 1029866791, + -2071829, -530906624, 434125, 111244624, 0, 0, + 3506380, 898510625, -1095468, -280713909, 3524442, 903139016, + 0, 0, -928749, -237992130, -394148, -101000509, + 1674615, 429120452, 0, 0, -1159875, -297218217, + -3704823, -949361686, -2663378, -682491182, 0, 0, + -2101410, -538486762, 3110818, 797147778, 4063053, 1041158200, + 0, 0, 3586446, 919027554, -2740543, -702264730, + 3370349, 863652652, 0, 0, -3182878, -815613168, + -3602218, -923069133, -294725, -75523344, -3761513, -963888510, + -3765607, -964937599, 3201430, 820367122, 3145678, 806080660, + 2883726, 738955404, 3201494, 820383522, 1221177, 312926867, + -557458, -142848732, 1005239, 257592709, -3764867, -964747974, + -2129892, -545785280, -2682288, -687336873, -3542485, -907762539, + 601683, 154181397, 0, 0, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_zetas) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/arith_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/arith_native_aarch64.h new file mode 100644 index 0000000000..e77f55014c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/arith_native_aarch64.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#define MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H + +#include +#include "../../../common.h" + +#define mld_aarch64_ntt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_ntt_zetas_layer123456) +#define mld_aarch64_ntt_zetas_layer78 MLD_NAMESPACE(aarch64_ntt_zetas_layer78) + +#define mld_aarch64_intt_zetas_layer78 MLD_NAMESPACE(aarch64_intt_zetas_layer78) +#define mld_aarch64_intt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_intt_zetas_layer123456) + +extern const int32_t mld_aarch64_ntt_zetas_layer123456[]; +extern const int32_t mld_aarch64_ntt_zetas_layer78[]; + +extern const int32_t mld_aarch64_intt_zetas_layer78[]; +extern const int32_t mld_aarch64_intt_zetas_layer123456[]; + +#define mld_rej_uniform_table MLD_NAMESPACE(rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[]; +#define mld_rej_uniform_eta_table MLD_NAMESPACE(rej_uniform_eta_table) +extern const uint8_t mld_rej_uniform_eta_table[]; + +#define mld_polyz_unpack_17_indices MLD_NAMESPACE(polyz_unpack_17_indices) +extern const uint8_t mld_polyz_unpack_17_indices[]; +#define mld_polyz_unpack_19_indices MLD_NAMESPACE(polyz_unpack_19_indices) +extern const uint8_t mld_polyz_unpack_19_indices[]; + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_ntt_asm MLD_NAMESPACE(ntt_asm) +void mld_ntt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_intt_asm MLD_NAMESPACE(intt_asm) +void mld_intt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_rej_uniform_asm MLD_NAMESPACE(rej_uniform_asm) +uint64_t mld_rej_uniform_asm(int32_t *r, const uint8_t *buf, unsigned buflen, + const uint8_t *table); + +#define mld_rej_uniform_eta2_asm MLD_NAMESPACE(rej_uniform_eta2_asm) +uint64_t mld_rej_uniform_eta2_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_rej_uniform_eta4_asm MLD_NAMESPACE(rej_uniform_eta4_asm) +uint64_t mld_rej_uniform_eta4_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_poly_decompose_32_asm MLD_NAMESPACE(poly_decompose_32_asm) +void mld_poly_decompose_32_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_asm MLD_NAMESPACE(poly_decompose_88_asm) +void mld_poly_decompose_88_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_asm MLD_NAMESPACE(poly_caddq_asm) +void mld_poly_caddq_asm(int32_t *a); + +#define mld_poly_use_hint_32_asm MLD_NAMESPACE(poly_use_hint_32_asm) +void mld_poly_use_hint_32_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_asm MLD_NAMESPACE(poly_use_hint_88_asm) +void mld_poly_use_hint_88_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_asm MLD_NAMESPACE(poly_chknorm_asm) +int mld_poly_chknorm_asm(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_asm MLD_NAMESPACE(polyz_unpack_17_asm) +void mld_polyz_unpack_17_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_polyz_unpack_19_asm MLD_NAMESPACE(polyz_unpack_19_asm) +void mld_polyz_unpack_19_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_poly_pointwise_montgomery_asm \ + MLD_NAMESPACE(poly_pointwise_montgomery_asm) +void mld_poly_pointwise_montgomery_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l4_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l4_asm) +void mld_polyvecl_pointwise_acc_montgomery_l4_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l5_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l5_asm) +void mld_polyvecl_pointwise_acc_montgomery_l5_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l7_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l7_asm) +void mld_polyvecl_pointwise_acc_montgomery_l7_asm(int32_t *, const int32_t *, + const int32_t *); + +#endif /* !MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/polyz_unpack_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/polyz_unpack_table.c new file mode 100644 index 0000000000..7ef915b587 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/polyz_unpack_table.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* Table of indices used for tbl instructions in polyz_unpack_{17,19}. */ + +MLD_ALIGN const uint8_t mld_polyz_unpack_17_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, + 9, 10, 11, 255, 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, + 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, 8, 9, 10, 255, + 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, 17, 18, 19, 255, +}; + +MLD_ALIGN const uint8_t mld_polyz_unpack_19_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 5, 6, 7, 255, 7, 8, 9, 255, + 10, 11, 12, 255, 12, 13, 14, 255, 15, 16, 17, 255, 17, 18, 19, 255, + 4, 5, 6, 255, 6, 7, 8, 255, 9, 10, 11, 255, 11, 12, 13, 255, + 14, 15, 16, 255, 16, 17, 18, 255, 19, 20, 21, 255, 21, 22, 23, 255, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_polyz_unpack_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/rej_uniform_eta_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/rej_uniform_eta_table.c new file mode 100644 index 0000000000..cf21509cbf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/rej_uniform_eta_table.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by 16-bit rejection sampling (rej_eta). + * Adapted from ML-KEM for ML-DSA eta rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_eta_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 2, 3, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 4, 5, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 2, 3, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 7 */, + 6, 7, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 2, 3, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 11 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 13 */, + 2, 3, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 15 */, + 8, 9, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 16 */, + 0, 1, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 17 */, + 2, 3, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 18 */, + 0, 1, 2, 3, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 19 */, + 4, 5, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 20 */, + 0, 1, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 21 */, + 2, 3, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 22 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 23 */, + 6, 7, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 24 */, + 0, 1, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 25 */, + 2, 3, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 26 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 27 */, + 4, 5, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 28 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 29 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 30 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 255, 255, 255, 255, 255, 255 /* 31 */, + 10, 11, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 32 */, + 0, 1, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 33 */, + 2, 3, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 34 */, + 0, 1, 2, 3, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 35 */, + 4, 5, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 36 */, + 0, 1, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 37 */, + 2, 3, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 38 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 39 */, + 6, 7, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 40 */, + 0, 1, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 41 */, + 2, 3, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 42 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 43 */, + 4, 5, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 44 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 45 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 46 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 255, 255, 255, 255, 255, 255 /* 47 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 48 */, + 0, 1, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 49 */, + 2, 3, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 50 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 51 */, + 4, 5, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 52 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 53 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 54 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 55 */, + 6, 7, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 56 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 57 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 58 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 59 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 60 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 61 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 62 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 63 */, + 12, 13, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 64 */, + 0, 1, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 65 */, + 2, 3, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 66 */, + 0, 1, 2, 3, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 67 */, + 4, 5, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 68 */, + 0, 1, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 69 */, + 2, 3, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 70 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 71 */, + 6, 7, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 72 */, + 0, 1, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 73 */, + 2, 3, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 74 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 75 */, + 4, 5, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 76 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 77 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 78 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 255, 255, 255, 255, 255, 255 /* 79 */, + 8, 9, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 80 */, + 0, 1, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 81 */, + 2, 3, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 82 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 83 */, + 4, 5, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 84 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 85 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 86 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 87 */, + 6, 7, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 88 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 89 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 90 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 91 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 92 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 93 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 94 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 255, 255, 255, 255 /* 95 */, + 10, 11, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 96 */, + 0, 1, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 97 */, + 2, 3, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 98 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 99 */, + 4, 5, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 100 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 101 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 102 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 103 */, + 6, 7, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 104 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 105 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 106 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 107 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 108 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 109 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 110 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 255, 255, 255, 255 /* 111 */, + 8, 9, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 112 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 113 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 114 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 115 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 116 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 117 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 118 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 119 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 120 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 121 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 122 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 123 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 124 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 125 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 126 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 255, 255 /* 127 */, + 14, 15, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 128 */, + 0, 1, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 129 */, + 2, 3, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 130 */, + 0, 1, 2, 3, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 131 */, + 4, 5, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 132 */, + 0, 1, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 133 */, + 2, 3, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 134 */, + 0, 1, 2, 3, 4, 5, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 135 */, + 6, 7, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 136 */, + 0, 1, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 137 */, + 2, 3, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 138 */, + 0, 1, 2, 3, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 139 */, + 4, 5, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 140 */, + 0, 1, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 141 */, + 2, 3, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 142 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 14, 15, 255, 255, 255, 255, 255, 255 /* 143 */, + 8, 9, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 144 */, + 0, 1, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 145 */, + 2, 3, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 146 */, + 0, 1, 2, 3, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 147 */, + 4, 5, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 148 */, + 0, 1, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 149 */, + 2, 3, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 150 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 151 */, + 6, 7, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 152 */, + 0, 1, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 153 */, + 2, 3, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 154 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 155 */, + 4, 5, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 156 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 157 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 158 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 14, 15, 255, 255, 255, 255 /* 159 */, + 10, 11, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 160 */, + 0, 1, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 161 */, + 2, 3, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 162 */, + 0, 1, 2, 3, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 163 */, + 4, 5, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 164 */, + 0, 1, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 165 */, + 2, 3, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 166 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 167 */, + 6, 7, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 168 */, + 0, 1, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 169 */, + 2, 3, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 170 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 171 */, + 4, 5, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 172 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 173 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 174 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 14, 15, 255, 255, 255, 255 /* 175 */, + 8, 9, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 176 */, + 0, 1, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 177 */, + 2, 3, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 178 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 179 */, + 4, 5, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 180 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 181 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 182 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 183 */, + 6, 7, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 184 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 185 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 186 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 187 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 188 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 189 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 190 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 14, 15, 255, 255 /* 191 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 192 */, + 0, 1, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 193 */, + 2, 3, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 194 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 195 */, + 4, 5, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 196 */, + 0, 1, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 197 */, + 2, 3, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 198 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 199 */, + 6, 7, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 200 */, + 0, 1, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 201 */, + 2, 3, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 202 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 203 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 204 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 205 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 206 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 207 */, + 8, 9, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 208 */, + 0, 1, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 209 */, + 2, 3, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 210 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 211 */, + 4, 5, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 212 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 213 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 214 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 215 */, + 6, 7, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 216 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 217 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 218 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 219 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 220 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 221 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 222 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 14, 15, 255, 255 /* 223 */, + 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 224 */, + 0, 1, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 225 */, + 2, 3, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 226 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 227 */, + 4, 5, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 228 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 229 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 230 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 231 */, + 6, 7, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 232 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 233 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 234 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 235 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 236 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 237 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 238 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 14, 15, 255, 255 /* 239 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 240 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 241 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 242 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 243 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 244 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 245 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 246 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 247 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 248 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 249 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 250 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 251 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 252 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 253 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 254 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 255 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_eta_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/rej_uniform_table.c new file mode 100644 index 0000000000..65bc3b78d3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/aarch64_opt/src/rej_uniform_table.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by rejection sampling of the public matrix. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 7 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 11 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 13 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 15 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/auto.h new file mode 100644 index 0000000000..4375cc1976 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/auto.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [HYBRID] + * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64 + * Becker, Kannwischer + * https://eprint.iacr.org/2022/1243 + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +#define MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* Default FIPS202 assembly profile for AArch64 systems */ + +/* + * Default logic to decide which implementation to use. + * + */ + +/* + * Keccak-f1600 + * + * - On Arm-based Apple CPUs, we pick a pure Neon implementation. + * - Otherwise, unless MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, + * we use lazy-rotation scalar assembly from @[HYBRID]. + * - Otherwise, if MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, we + * fall back to the standard C implementation. + */ +#if defined(__ARM_FEATURE_SHA3) && defined(__APPLE__) +#include "x1_v84a.h" +#elif !defined(MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER) +#include "x1_scalar.h" +#endif + +/* + * Keccak-f1600x2/x4 + * + * The optimal implementation is highly CPU-specific; see @[HYBRID]. + * + * For now, if v8.4-A is not implemented, we fall back to Keccak-f1600. + * If v8.4-A is implemented and we are on an Apple CPU, we use a plain + * Neon-based implementation. + * If v8.4-A is implemented and we are not on an Apple CPU, we use a + * scalar/Neon/Neon hybrid. + * The reason for this distinction is that Apple CPUs appear to implement + * the SHA3 instructions on all SIMD units, while Arm CPUs prior to Cortex-X4 + * don't, and ordinary Neon instructions are still needed. + */ +#if defined(__ARM_FEATURE_SHA3) +/* + * For Apple-M cores, we use a plain implementation leveraging SHA3 + * instructions only. + */ +#if defined(__APPLE__) +#include "x2_v84a.h" +#else +#include "x4_v8a_v84a_scalar.h" +#endif + +#else /* __ARM_FEATURE_SHA3 */ + +#include "x4_v8a_scalar.h" + +#endif /* !__ARM_FEATURE_SHA3 */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/src/fips202_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/src/fips202_native_aarch64.h new file mode 100644 index 0000000000..20f6168038 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/src/fips202_native_aarch64.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#define MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H + +#include +#include "../../../../cbmc.h" +#include "../../../../common.h" + + +#define mld_keccakf1600_round_constants \ + MLD_NAMESPACE(keccakf1600_round_constants) +extern const uint64_t mld_keccakf1600_round_constants[]; + +#define mld_keccak_f1600_x1_scalar_asm MLD_NAMESPACE(keccak_f1600_x1_scalar_asm) +void mld_keccak_f1600_x1_scalar_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x1_v84a_asm MLD_NAMESPACE(keccak_f1600_x1_v84a_asm) +void mld_keccak_f1600_x1_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x2_v84a_asm MLD_NAMESPACE(keccak_f1600_x2_v84a_asm) +void mld_keccak_f1600_x2_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 2)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 2)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/src/keccakf1600_round_constants.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/src/keccakf1600_round_constants.c new file mode 100644 index 0000000000..05e9cbfeec --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/src/keccakf1600_round_constants.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../../common.h" + +#if (defined(MLD_FIPS202_AARCH64_NEED_X1_SCALAR) || \ + defined(MLD_FIPS202_AARCH64_NEED_X1_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X2_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID)) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "fips202_native_aarch64.h" + +MLD_ALIGN const uint64_t mld_keccakf1600_round_constants[] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, +}; + +#else /* (MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_aarch64_round_constants) + +#endif /* !((MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/x1_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/x1_scalar.h new file mode 100644 index 0000000000..681b991371 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/x1_scalar.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_SCALAR + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + mld_keccak_f1600_x1_scalar_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/x1_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/x1_v84a.h new file mode 100644 index 0000000000..d15c8c26f3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/x1_v84a.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x1_v84a_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/x2_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/x2_v84a.h new file mode 100644 index 0000000000..16c22fa1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/x2_v84a.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X2_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" + + +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x2_v84a_asm(state + 0 * 25, mld_keccakf1600_round_constants); + mld_keccak_f1600_x2_v84a_asm(state + 2 * 25, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/x4_v8a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/x4_v8a_scalar.h new file mode 100644 index 0000000000..0f7f8fe499 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/x4_v8a_scalar.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(state, + mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/x4_v8a_v84a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/x4_v8a_v84a_scalar.h new file mode 100644 index 0000000000..3da883b762 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/fips202/aarch64/x4_v8a_v84a_scalar.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm( + state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/README.md new file mode 100644 index 0000000000..ba4d0273eb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/README.md @@ -0,0 +1,4 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +This directory contains the native x86_64 arithmetic backend for ML-DSA provided by the official [AVX2 +implementation](https://github.com/pq-crystals/dilithium/blob/master/avx2) of the Dilithium team. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/meta.h new file mode 100644 index 0000000000..393374c06f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/meta.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_X86_64_META_H +#define MLD_NATIVE_X86_64_META_H + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_X86_64_DEFAULT + +#define MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +#if !defined(__ASSEMBLER__) +#include +#include "../../common.h" +#include "../api.h" +#include "src/arith_native_x86_64.h" + +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t data[MLDSA_N]) +{ + if (mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + mld_nttunpack_avx2(data); + } +} + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_ntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_invntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)mld_rej_uniform_avx2(r, buf); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_32_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_88_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_caddq_avx2(a); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_32_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_88_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + return mld_poly_chknorm_avx2(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_17_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_19_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_avx2(c, a, b, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l4_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l5_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l7_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_NATIVE_X86_64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/arith_native_x86_64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/arith_native_x86_64.h new file mode 100644 index 0000000000..08d5abf74a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/arith_native_x86_64.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#define MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#include "../../../common.h" + +#include +#include "consts.h" + +#define MLD_AVX2_REJ_UNIFORM_BUFLEN \ + (5 * 168) /* REJ_UNIFORM_NBLOCKS * SHAKE128_RATE */ + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) + +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_rej_uniform_table MLD_NAMESPACE(mld_rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[256][8]; + +#define mld_ntt_avx2 MLD_NAMESPACE(ntt_avx2) +void mld_ntt_avx2(int32_t *r, const int32_t *qdata) +/* This must be kept in sync with the HOL-Light specification + * in proofs/hol_light/x86_64/proofs/mldsa_ntt.ml */ +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, MLDSA_N, 8380417)) + requires(qdata == mld_qdata) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + /* check-magic: off */ + ensures(array_abs_bound(r, 0, MLDSA_N, 42035262)) + /* check-magic: on */ +); + +#define mld_invntt_avx2 MLD_NAMESPACE(invntt_avx2) +void mld_invntt_avx2(int32_t *r, const int32_t *mld_qdata); + +#define mld_nttunpack_avx2 MLD_NAMESPACE(nttunpack_avx2) +void mld_nttunpack_avx2(int32_t *r); + +#define mld_rej_uniform_avx2 MLD_NAMESPACE(mld_rej_uniform_avx2) +unsigned mld_rej_uniform_avx2(int32_t *r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]); + +#define mld_rej_uniform_eta2_avx2 MLD_NAMESPACE(mld_rej_uniform_eta2_avx2) +unsigned mld_rej_uniform_eta2_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]); + +#define mld_rej_uniform_eta4_avx2 MLD_NAMESPACE(mld_rej_uniform_eta4_avx2) +unsigned mld_rej_uniform_eta4_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]); + +#define mld_poly_decompose_32_avx2 MLD_NAMESPACE(mld_poly_decompose_32_avx2) +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_avx2 MLD_NAMESPACE(mld_poly_decompose_88_avx2) +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_avx2 MLD_NAMESPACE(poly_caddq_avx2) +void mld_poly_caddq_avx2(int32_t *r); + +#define mld_poly_use_hint_32_avx2 MLD_NAMESPACE(mld_poly_use_hint_32_avx2) +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_avx2 MLD_NAMESPACE(mld_poly_use_hint_88_avx2) +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_avx2 MLD_NAMESPACE(mld_poly_chknorm_avx2) +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_avx2 MLD_NAMESPACE(mld_polyz_unpack_17_avx2) +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a); + +#define mld_polyz_unpack_19_avx2 MLD_NAMESPACE(mld_polyz_unpack_19_avx2) +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a); + +#define mld_pointwise_avx2 MLD_NAMESPACE(pointwise_avx2) +void mld_pointwise_avx2(int32_t *c, const int32_t *a, const int32_t *b, + const int32_t *qdata); + +#define mld_pointwise_acc_l4_avx2 MLD_NAMESPACE(pointwise_acc_l4_avx2) +void mld_pointwise_acc_l4_avx2(int32_t c[MLDSA_N], const int32_t a[4][MLDSA_N], + const int32_t b[4][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l5_avx2 MLD_NAMESPACE(pointwise_acc_l5_avx2) +void mld_pointwise_acc_l5_avx2(int32_t c[MLDSA_N], const int32_t a[5][MLDSA_N], + const int32_t b[5][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l7_avx2 MLD_NAMESPACE(pointwise_acc_l7_avx2) +void mld_pointwise_acc_l7_avx2(int32_t c[MLDSA_N], const int32_t a[7][MLDSA_N], + const int32_t b[7][MLDSA_N], + const int32_t *qdata); + +#endif /* !MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/consts.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/consts.c new file mode 100644 index 0000000000..aaca3535ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/consts.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include "consts.h" + +/* + * Table of zeta values used in the AVX2 forward and inverse NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_qdata[624] = { + 8380417, 8380417, 8380417, 8380417, 8380417, + 8380417, 8380417, 8380417, 58728449, 58728449, + 58728449, 58728449, 58728449, 58728449, 58728449, + 58728449, -8395782, -8395782, -8395782, -8395782, + -8395782, -8395782, -8395782, -8395782, 41978, + 41978, 41978, 41978, 41978, 41978, + 41978, 41978, -151046689, 1830765815, -1929875198, + -1927777021, 1640767044, 1477910808, 1612161320, 1640734244, + 308362795, 308362795, 308362795, 308362795, -1815525077, + -1815525077, -1815525077, -1815525077, -1374673747, -1374673747, + -1374673747, -1374673747, -1091570561, -1091570561, -1091570561, + -1091570561, -1929495947, -1929495947, -1929495947, -1929495947, + 515185417, 515185417, 515185417, 515185417, -285697463, + -285697463, -285697463, -285697463, 625853735, 625853735, + 625853735, 625853735, 1727305304, 1727305304, 2082316400, + 2082316400, -1364982364, -1364982364, 858240904, 858240904, + 1806278032, 1806278032, 222489248, 222489248, -346752664, + -346752664, 684667771, 684667771, 1654287830, 1654287830, + -878576921, -878576921, -1257667337, -1257667337, -748618600, + -748618600, 329347125, 329347125, 1837364258, 1837364258, + -1443016191, -1443016191, -1170414139, -1170414139, -1846138265, + -1631226336, -1404529459, 1838055109, 1594295555, -1076973524, + -1898723372, -594436433, -202001019, -475984260, -561427818, + 1797021249, -1061813248, 2059733581, -1661512036, -1104976547, + -1750224323, -901666090, 418987550, 1831915353, -1925356481, + 992097815, 879957084, 2024403852, 1484874664, -1636082790, + -285388938, -1983539117, -1495136972, -950076368, -1714807468, + -952438995, -1574918427, 1350681039, -2143979939, 1599739335, + -1285853323, -993005454, -1440787840, 568627424, -783134478, + -588790216, 289871779, -1262003603, 2135294594, -1018755525, + -889861155, 1665705315, 1321868265, 1225434135, -1784632064, + 666258756, 675310538, -1555941048, -1999506068, -1499481951, + -695180180, -1375177022, 1777179795, 334803717, -178766299, + -518252220, 1957047970, 1146323031, -654783359, -1974159335, + 1651689966, 140455867, -1039411342, 1955560694, 1529189038, + -2131021878, -247357819, 1518161567, -86965173, 1708872713, + 1787797779, 1638590967, -120646188, -1669960606, -916321552, + 1155548552, 2143745726, 1210558298, -1261461890, -318346816, + 628664287, -1729304568, 1422575624, 1424130038, -1185330464, + 235321234, 168022240, 1206536194, 985155484, -894060583, + -898413, -1363460238, -605900043, 2027833504, 14253662, + 1014493059, 863641633, 1819892093, 2124962073, -1223601433, + -1920467227, -1637785316, -1536588520, 694382729, 235104446, + -1045062172, 831969619, -300448763, 756955444, -260312805, + 1554794072, 1339088280, -2040058690, -853476187, -2047270596, + -1723816713, -1591599803, -440824168, 1119856484, 1544891539, + 155290192, -973777462, 991903578, 912367099, -44694137, + 1176904444, -421552614, -818371958, 1747917558, -325927722, + 908452108, 1851023419, -1176751719, -1354528380, -72690498, + -314284737, 985022747, 963438279, -1078959975, 604552167, + -1021949428, 608791570, 173440395, -2126092136, -1316619236, + -1039370342, 6087993, -110126092, 565464272, -1758099917, + -1600929361, 879867909, -1809756372, 400711272, 1363007700, + 30313375, -326425360, 1683520342, -517299994, 2027935492, + -1372618620, 128353682, -1123881663, 137583815, -635454918, + -642772911, 45766801, 671509323, -2070602178, 419615363, + 1216882040, -270590488, -1276805128, 371462360, -1357098057, + -384158533, 827959816, -596344473, 702390549, -279505433, + -260424530, -71875110, -1208667171, -1499603926, 2036925262, + -540420426, 746144248, -1420958686, 2032221021, 1904936414, + 1257750362, 1926727420, 1931587462, 1258381762, 885133339, + 1629985060, 1967222129, 6363718, -1287922800, 1136965286, + 1779436847, 1116720494, 1042326957, 1405999311, 713994583, + 940195359, -1542497137, 2061661095, -883155599, 1726753853, + -1547952704, 394851342, 283780712, 776003547, 1123958025, + 201262505, 1934038751, 374860238, -3975713, 25847, + -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 1826347, 1826347, 1826347, + 2353451, 2353451, 2353451, 2353451, -359251, + -359251, -359251, -359251, -2091905, -2091905, + -2091905, -2091905, 3119733, 3119733, 3119733, + 3119733, -2884855, -2884855, -2884855, -2884855, + 3111497, 3111497, 3111497, 3111497, 2680103, + 2680103, 2680103, 2680103, 2725464, 2725464, + 1024112, 1024112, -1079900, -1079900, 3585928, + 3585928, -549488, -549488, -1119584, -1119584, + 2619752, 2619752, -2108549, -2108549, -2118186, + -2118186, -3859737, -3859737, -1399561, -1399561, + -3277672, -3277672, 1757237, 1757237, -19422, + -19422, 4010497, 4010497, 280005, 280005, + 2706023, 95776, 3077325, 3530437, -1661693, + -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, + -539299, -1699267, -1643818, 3505694, -3821735, + 3507263, -2140649, -1600420, 3699596, 811944, + 531354, 954230, 3881043, 3900724, -2556880, + 2071892, -2797779, -3930395, -3677745, -1452451, + 2176455, -1257611, -4083598, -3190144, -3632928, + 3412210, 2147896, -2967645, -411027, -671102, + -22981, -381987, 1852771, -3343383, 508951, + 44288, 904516, -3724342, 1653064, 2389356, + 759969, 189548, 3159746, -2409325, 1315589, + 1285669, -812732, -3019102, -3628969, -1528703, + -3041255, 3475950, -1585221, 1939314, -1000202, + -3157330, 126922, -983419, 2715295, -3693493, + -2477047, -1228525, -1308169, 1349076, -1430430, + 264944, 3097992, -1100098, 3958618, -8578, + -3249728, -210977, -1316856, -3553272, -1851402, + -177440, 1341330, -1584928, -1439742, -3881060, + 3839961, 2091667, -3342478, 266997, -3520352, + 900702, 495491, -655327, -3556995, 342297, + 3437287, 2842341, 4055324, -3767016, -2994039, + -1333058, -451100, -1279661, 1500165, -542412, + -2584293, -2013608, 1957272, -3183426, 810149, + -3038916, 2213111, -426683, -1667432, -2939036, + 183443, -554416, 3937738, 3407706, 2244091, + 2434439, -3759364, 1859098, -1613174, -3122442, + -525098, 286988, -3342277, 2691481, 1247620, + 1250494, 1869119, 1237275, 1312455, 1917081, + 777191, -2831860, -3724270, 2432395, 3369112, + 162844, 1652634, 3523897, -975884, 1723600, + -1104333, -2235985, -976891, 3919660, 1400424, + 2316500, -2446433, -1235728, -1197226, 909542, + -43260, 2031748, -768622, -2437823, 1735879, + -2590150, 2486353, 2635921, 1903435, -3318210, + 3306115, -2546312, 2235880, -1671176, 594136, + 2454455, 185531, 1616392, -3694233, 3866901, + 1717735, -1803090, -260646, -420899, 1612842, + -48306, -846154, 3817976, -3562462, 3513181, + -3193378, 819034, -522500, 3207046, -3595838, + 4108315, 203044, 1265009, 1595974, -3548272, + -1050970, -1430225, -1962642, -1374803, 3406031, + -1846953, -3776993, -164721, -1207385, 3014001, + -1799107, 269760, 472078, 1910376, -3833893, + -2286327, -3545687, -1362209, 1976782, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_consts) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/consts.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/consts.h new file mode 100644 index 0000000000..7fe08f454b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/consts.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#ifndef MLD_NATIVE_X86_64_SRC_CONSTS_H +#define MLD_NATIVE_X86_64_SRC_CONSTS_H +#include "../../../common.h" +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQ 0 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV 8 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV 16 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV 24 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV 32 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS 328 + +#ifndef __ASSEMBLER__ +#define mld_qdata MLD_NAMESPACE(qdata) +extern const int32_t mld_qdata[624]; +#endif + +#endif /* !MLD_NATIVE_X86_64_SRC_CONSTS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_caddq_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_caddq_avx2.c new file mode 100644 index 0000000000..05d86d14fc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_caddq_avx2.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/************************************************* + * Name: mld_poly_caddq_avx2 + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *r: pointer to input/output polynomial + **************************************************/ +void mld_poly_caddq_avx2(int32_t *r) +{ + unsigned int i; + __m256i f, g; + const __m256i q = _mm256_set1_epi32(MLDSA_Q); + const __m256i zero = _mm256_setzero_si256(); + __m256i *rr = (__m256i *)r; + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256(&rr[i]); + g = _mm256_cmpgt_epi32(zero, f); + g = _mm256_and_si256(g, q); + f = _mm256_add_epi32(f, g); + _mm256_store_si256(&rr[i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_reduce) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_chknorm_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_chknorm_avx2.c new file mode 100644 index 0000000000..50e2c7fa9b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_chknorm_avx2.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B) +{ + unsigned int i; + __m256i f, t; + const __m256i bound = _mm256_set1_epi32(B - 1); + + t = _mm256_setzero_si256(); + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + f = _mm256_abs_epi32(f); + f = _mm256_cmpgt_epi32(f, bound); + t = _mm256_or_si256(t, f); + } + + return 1 - _mm256_testz_si256(t, t); +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_chknorm) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_decompose_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_decompose_32_avx2.c new file mode 100644 index 0000000000..76846bf1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_decompose_32_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(31 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 4092 == intdiv(2 * intdiv(MLDSA_Q - 1, 32), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 4092. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 32*GAMMA2 = 16*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 16B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + * + * round(f1' * 1025 / 2^22) is in turn computed in 2 steps as + * round(floor(f1' * 1025 / 2^16) / 2^6). The mulhi computes f1'' = + * floor(f1' * 1025 / 2^16). As for the next step f1 = round(f1'' / 2^6), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^9) = round(f1'' * 2^9 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 1025 / 2^16) = 1025 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(16B / B) = 16 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 16, i.e. f > 31*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 31*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 15, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_decompose_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_decompose_88_avx2.c new file mode 100644 index 0000000000..463506b962 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_decompose_88_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ + +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 1488 == intdiv(2 * intdiv(MLDSA_Q - 1, 88), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 1488. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 88*GAMMA2 = 44*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 44B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + * + * round(f1' * 11275 / 2^24) is in turn computed in 2 steps as + * round(floor(f1' * 11275 / 2^16) / 2^8). The mulhi computes f1'' = + * floor(f1' * 11275 / 2^16). As for the next step f1 = round(f1'' / 2^8), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^7) = round(f1'' * 2^7 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 11275 / 2^16) = 11275 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(44B / B) = 44 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 44, i.e. f > 87*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 87*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 43, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_use_hint_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_use_hint_32_avx2.c new file mode 100644 index 0000000000..0094bc93a9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_use_hint_32_avx2.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + const __m256i mask = _mm256_set1_epi32(15); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_32_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 16 */ + f1 = _mm256_add_epi32(f1, h); + f1 = _mm256_and_si256(f1, mask); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_use_hint_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_use_hint_88_avx2.c new file mode 100644 index 0000000000..b109ab6351 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/poly_use_hint_88_avx2.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + const __m256i max = _mm256_set1_epi32(43); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_88_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 44 */ + f1 = _mm256_add_epi32(f1, h); + f1 = MLD_MM256_BLENDV_EPI32(f1, max, f1); + f = _mm256_cmpgt_epi32(f1, max); + f1 = MLD_MM256_BLENDV_EPI32(f1, zero, f); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/polyz_unpack_17_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/polyz_unpack_17_avx2.c new file mode 100644 index 0000000000..f6c08a832f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/polyz_unpack_17_avx2.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 27, 26, 25, -1, 25, 24, 23, -1, 8, 7, + 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0); + const __m256i srlvdidx = _mm256_set_epi32(6, 4, 2, 0, 6, 4, 2, 0); + const __m256i mask = _mm256_set1_epi32(0x3FFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 17)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[18 * i]); + /* Load bytes 2..17 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[18 * i + 2]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-8 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 8, 7, 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte8, byte7, byte6, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,27, 26, 25, -1,25, 24, 23] │ + * │ Result: [0, byte17, byte16, byte15, ..., 0, byte11, byte10, byte9] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 18 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 32..55 48..71 + * 72..95 88..111 104..127 120..143 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 18..39 36..55 54..71 + * 72..95 90..111 108..127 126..143 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..17 18..35 36..53 54..71 + * 72..89 90..107 108..125 126..143 */ + + /* Map [0, 1, ..., 2^18-1] to [2^17, 2^17-1, ..., -2^17+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_17) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/polyz_unpack_19_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/polyz_unpack_19_avx2.c new file mode 100644 index 0000000000..4a5ce48f38 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/polyz_unpack_19_avx2.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 26, 25, 24, -1, 24, 23, 22, -1, 9, 8, + 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0); + /* Equivalent to _mm256_set_epi32(4, 0, 4, 0, 4, 0, 4, 0) */ + const __m256i srlvdidx = _mm256_set1_epi64x((uint64_t)4 << 32); + const __m256i mask = _mm256_set1_epi32(0xFFFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 19)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[20 * i]); + /* Load bytes 4..19 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[20 * i + 4]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-9 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 9, 8, 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte9, byte8, byte7, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,26, 25, 24, -1,24, 23, 22] │ + * │ Result: [0, byte19, byte18, byte17, ..., 0, byte12, byte11, byte10] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 20 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 40..63 56..79 + * 80..103 96..119 120..143 136..159 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 20..39 40..63 60..79 + * 80..103 100..119 120..143 140..159 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..19 20..39 40..59 60..79 + * 80..99 100..119 120..139 140..159 */ + + /* Map [0, 1, ..., 2^20-1] to [2^19, 2^19-1, ..., -2^19+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_19) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/rej_uniform_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/rej_uniform_avx2.c new file mode 100644 index 0000000000..07a5df9706 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/rej_uniform_avx2.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The pqcrystals implementation assumes a buffer that is 8 bytes + *. larger as the first loop overreads by 8 bytes that are then + * discarded. We instead do not pad the buffer and do not overread. + * The performance impact is negligible and it does not force the + * frontend to perform the unintuitive padding. + */ + +unsigned int mld_rej_uniform_avx2( + int32_t *MLD_RESTRICT r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i d, tmp; + const __m256i bound = _mm256_set1_epi32(MLDSA_Q); + const __m256i mask = _mm256_set1_epi32(0x7FFFFF); + const __m256i idx8 = + _mm256_set_epi8(-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4, + -1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 32) + { + d = _mm256_loadu_si256((__m256i *)&buf[pos]); + + /* Permute 64-bit lanes + * 0x94 = 10010100b rearranges 64-bit lanes as: [3,2,1,0] -> [2,1,1,0] + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Original Layout ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ bytes 16..23 │ bytes 24..31 │ + * └─────────────────┴─────────────────┴─────────────────┴─────────────────┘ + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Layout after permute ║ + * ║ Byte indices in high half shifted down by 8 positions ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌───────────────┬─────────────────┐ ┌─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ │ bytes 8..15 │ bytes 16..23 │ + * └───────────────┴─────────────────┘ └─────────────────┴─────────────────┘ + * Lower 128-bit lane (bytes 0-15) Upper 128-bit lane (bytes 16-31) + */ + d = _mm256_permute4x64_epi64(d, 0x94); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-11 into low 128-bit half of permuted vector────────────────┐ + * │ Shuffle: [-1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0] │ + * │ Result: [0, byte11, byte10, byte9, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 4-15 into high 128-bit half of permuted vector ──────────────┐ + * │ Shuffle: [-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4] │ + * │ Result: [0, byte23, byte22, byte21, ..., 0, byte14, byte13, byte12 │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + d = _mm256_shuffle_epi8(d, idx8); + d = _mm256_and_si256(d, mask); + pos += 24; + + tmp = _mm256_sub_epi32(d, bound); + good = (uint32_t)_mm256_movemask_ps((__m256)tmp); + tmp = _mm256_cvtepu8_epi32( + _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good])); + d = _mm256_permutevar8x32_epi32(d, tmp); + + _mm256_storeu_si256((__m256i *)&r[ctr], d); + ctr += (unsigned)_mm_popcnt_u32(good); + } + + while (ctr < MLDSA_N && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 3) + { + uint32_t t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + /* Safe because t < MLDSA_Q. */ + r[ctr++] = (int32_t)t; + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/rej_uniform_eta2_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/rej_uniform_eta2_avx2.c new file mode 100644 index 0000000000..70c5c42c70 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/rej_uniform_eta2_avx2.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA2 2 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ +unsigned int mld_rej_uniform_eta2_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1, f2; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA2); + const __m256i bound = mask; + /* check-magic: -6560 == 32*round(-2**10 / 5) */ + const __m256i v = _mm256_set1_epi32(-6560); + const __m256i p = _mm256_set1_epi32(5); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 15) + { + t0 = t0 - (205 * t0 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t0); + } + if (t1 < 15 && ctr < MLDSA_N) + { + t1 = t1 - (205 * t1 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta2) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA2 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/rej_uniform_eta4_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/rej_uniform_eta4_avx2.c new file mode 100644 index 0000000000..ba00e91252 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/rej_uniform_eta4_avx2.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA4 4 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ + +unsigned int mld_rej_uniform_eta4_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA4); + const __m256i bound = _mm256_set1_epi8(9); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 9) + { + r[ctr++] = (int32_t)(4 - t0); + } + if (t1 < 9 && ctr < MLDSA_N) + { + r[ctr++] = (int32_t)(4 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta4) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA4 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/rej_uniform_table.c new file mode 100644 index 0000000000..6c537b4542 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/dev/x86_64/src/rej_uniform_table.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" + +/* + * Lookup table used by rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[256][8] = { + {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, + {2, 0, 0, 0, 0, 0, 0, 0}, {0, 2, 0, 0, 0, 0, 0, 0}, + {1, 2, 0, 0, 0, 0, 0, 0}, {0, 1, 2, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 0, 0}, {0, 3, 0, 0, 0, 0, 0, 0}, + {1, 3, 0, 0, 0, 0, 0, 0}, {0, 1, 3, 0, 0, 0, 0, 0}, + {2, 3, 0, 0, 0, 0, 0, 0}, {0, 2, 3, 0, 0, 0, 0, 0}, + {1, 2, 3, 0, 0, 0, 0, 0}, {0, 1, 2, 3, 0, 0, 0, 0}, + {4, 0, 0, 0, 0, 0, 0, 0}, {0, 4, 0, 0, 0, 0, 0, 0}, + {1, 4, 0, 0, 0, 0, 0, 0}, {0, 1, 4, 0, 0, 0, 0, 0}, + {2, 4, 0, 0, 0, 0, 0, 0}, {0, 2, 4, 0, 0, 0, 0, 0}, + {1, 2, 4, 0, 0, 0, 0, 0}, {0, 1, 2, 4, 0, 0, 0, 0}, + {3, 4, 0, 0, 0, 0, 0, 0}, {0, 3, 4, 0, 0, 0, 0, 0}, + {1, 3, 4, 0, 0, 0, 0, 0}, {0, 1, 3, 4, 0, 0, 0, 0}, + {2, 3, 4, 0, 0, 0, 0, 0}, {0, 2, 3, 4, 0, 0, 0, 0}, + {1, 2, 3, 4, 0, 0, 0, 0}, {0, 1, 2, 3, 4, 0, 0, 0}, + {5, 0, 0, 0, 0, 0, 0, 0}, {0, 5, 0, 0, 0, 0, 0, 0}, + {1, 5, 0, 0, 0, 0, 0, 0}, {0, 1, 5, 0, 0, 0, 0, 0}, + {2, 5, 0, 0, 0, 0, 0, 0}, {0, 2, 5, 0, 0, 0, 0, 0}, + {1, 2, 5, 0, 0, 0, 0, 0}, {0, 1, 2, 5, 0, 0, 0, 0}, + {3, 5, 0, 0, 0, 0, 0, 0}, {0, 3, 5, 0, 0, 0, 0, 0}, + {1, 3, 5, 0, 0, 0, 0, 0}, {0, 1, 3, 5, 0, 0, 0, 0}, + {2, 3, 5, 0, 0, 0, 0, 0}, {0, 2, 3, 5, 0, 0, 0, 0}, + {1, 2, 3, 5, 0, 0, 0, 0}, {0, 1, 2, 3, 5, 0, 0, 0}, + {4, 5, 0, 0, 0, 0, 0, 0}, {0, 4, 5, 0, 0, 0, 0, 0}, + {1, 4, 5, 0, 0, 0, 0, 0}, {0, 1, 4, 5, 0, 0, 0, 0}, + {2, 4, 5, 0, 0, 0, 0, 0}, {0, 2, 4, 5, 0, 0, 0, 0}, + {1, 2, 4, 5, 0, 0, 0, 0}, {0, 1, 2, 4, 5, 0, 0, 0}, + {3, 4, 5, 0, 0, 0, 0, 0}, {0, 3, 4, 5, 0, 0, 0, 0}, + {1, 3, 4, 5, 0, 0, 0, 0}, {0, 1, 3, 4, 5, 0, 0, 0}, + {2, 3, 4, 5, 0, 0, 0, 0}, {0, 2, 3, 4, 5, 0, 0, 0}, + {1, 2, 3, 4, 5, 0, 0, 0}, {0, 1, 2, 3, 4, 5, 0, 0}, + {6, 0, 0, 0, 0, 0, 0, 0}, {0, 6, 0, 0, 0, 0, 0, 0}, + {1, 6, 0, 0, 0, 0, 0, 0}, {0, 1, 6, 0, 0, 0, 0, 0}, + {2, 6, 0, 0, 0, 0, 0, 0}, {0, 2, 6, 0, 0, 0, 0, 0}, + {1, 2, 6, 0, 0, 0, 0, 0}, {0, 1, 2, 6, 0, 0, 0, 0}, + {3, 6, 0, 0, 0, 0, 0, 0}, {0, 3, 6, 0, 0, 0, 0, 0}, + {1, 3, 6, 0, 0, 0, 0, 0}, {0, 1, 3, 6, 0, 0, 0, 0}, + {2, 3, 6, 0, 0, 0, 0, 0}, {0, 2, 3, 6, 0, 0, 0, 0}, + {1, 2, 3, 6, 0, 0, 0, 0}, {0, 1, 2, 3, 6, 0, 0, 0}, + {4, 6, 0, 0, 0, 0, 0, 0}, {0, 4, 6, 0, 0, 0, 0, 0}, + {1, 4, 6, 0, 0, 0, 0, 0}, {0, 1, 4, 6, 0, 0, 0, 0}, + {2, 4, 6, 0, 0, 0, 0, 0}, {0, 2, 4, 6, 0, 0, 0, 0}, + {1, 2, 4, 6, 0, 0, 0, 0}, {0, 1, 2, 4, 6, 0, 0, 0}, + {3, 4, 6, 0, 0, 0, 0, 0}, {0, 3, 4, 6, 0, 0, 0, 0}, + {1, 3, 4, 6, 0, 0, 0, 0}, {0, 1, 3, 4, 6, 0, 0, 0}, + {2, 3, 4, 6, 0, 0, 0, 0}, {0, 2, 3, 4, 6, 0, 0, 0}, + {1, 2, 3, 4, 6, 0, 0, 0}, {0, 1, 2, 3, 4, 6, 0, 0}, + {5, 6, 0, 0, 0, 0, 0, 0}, {0, 5, 6, 0, 0, 0, 0, 0}, + {1, 5, 6, 0, 0, 0, 0, 0}, {0, 1, 5, 6, 0, 0, 0, 0}, + {2, 5, 6, 0, 0, 0, 0, 0}, {0, 2, 5, 6, 0, 0, 0, 0}, + {1, 2, 5, 6, 0, 0, 0, 0}, {0, 1, 2, 5, 6, 0, 0, 0}, + {3, 5, 6, 0, 0, 0, 0, 0}, {0, 3, 5, 6, 0, 0, 0, 0}, + {1, 3, 5, 6, 0, 0, 0, 0}, {0, 1, 3, 5, 6, 0, 0, 0}, + {2, 3, 5, 6, 0, 0, 0, 0}, {0, 2, 3, 5, 6, 0, 0, 0}, + {1, 2, 3, 5, 6, 0, 0, 0}, {0, 1, 2, 3, 5, 6, 0, 0}, + {4, 5, 6, 0, 0, 0, 0, 0}, {0, 4, 5, 6, 0, 0, 0, 0}, + {1, 4, 5, 6, 0, 0, 0, 0}, {0, 1, 4, 5, 6, 0, 0, 0}, + {2, 4, 5, 6, 0, 0, 0, 0}, {0, 2, 4, 5, 6, 0, 0, 0}, + {1, 2, 4, 5, 6, 0, 0, 0}, {0, 1, 2, 4, 5, 6, 0, 0}, + {3, 4, 5, 6, 0, 0, 0, 0}, {0, 3, 4, 5, 6, 0, 0, 0}, + {1, 3, 4, 5, 6, 0, 0, 0}, {0, 1, 3, 4, 5, 6, 0, 0}, + {2, 3, 4, 5, 6, 0, 0, 0}, {0, 2, 3, 4, 5, 6, 0, 0}, + {1, 2, 3, 4, 5, 6, 0, 0}, {0, 1, 2, 3, 4, 5, 6, 0}, + {7, 0, 0, 0, 0, 0, 0, 0}, {0, 7, 0, 0, 0, 0, 0, 0}, + {1, 7, 0, 0, 0, 0, 0, 0}, {0, 1, 7, 0, 0, 0, 0, 0}, + {2, 7, 0, 0, 0, 0, 0, 0}, {0, 2, 7, 0, 0, 0, 0, 0}, + {1, 2, 7, 0, 0, 0, 0, 0}, {0, 1, 2, 7, 0, 0, 0, 0}, + {3, 7, 0, 0, 0, 0, 0, 0}, {0, 3, 7, 0, 0, 0, 0, 0}, + {1, 3, 7, 0, 0, 0, 0, 0}, {0, 1, 3, 7, 0, 0, 0, 0}, + {2, 3, 7, 0, 0, 0, 0, 0}, {0, 2, 3, 7, 0, 0, 0, 0}, + {1, 2, 3, 7, 0, 0, 0, 0}, {0, 1, 2, 3, 7, 0, 0, 0}, + {4, 7, 0, 0, 0, 0, 0, 0}, {0, 4, 7, 0, 0, 0, 0, 0}, + {1, 4, 7, 0, 0, 0, 0, 0}, {0, 1, 4, 7, 0, 0, 0, 0}, + {2, 4, 7, 0, 0, 0, 0, 0}, {0, 2, 4, 7, 0, 0, 0, 0}, + {1, 2, 4, 7, 0, 0, 0, 0}, {0, 1, 2, 4, 7, 0, 0, 0}, + {3, 4, 7, 0, 0, 0, 0, 0}, {0, 3, 4, 7, 0, 0, 0, 0}, + {1, 3, 4, 7, 0, 0, 0, 0}, {0, 1, 3, 4, 7, 0, 0, 0}, + {2, 3, 4, 7, 0, 0, 0, 0}, {0, 2, 3, 4, 7, 0, 0, 0}, + {1, 2, 3, 4, 7, 0, 0, 0}, {0, 1, 2, 3, 4, 7, 0, 0}, + {5, 7, 0, 0, 0, 0, 0, 0}, {0, 5, 7, 0, 0, 0, 0, 0}, + {1, 5, 7, 0, 0, 0, 0, 0}, {0, 1, 5, 7, 0, 0, 0, 0}, + {2, 5, 7, 0, 0, 0, 0, 0}, {0, 2, 5, 7, 0, 0, 0, 0}, + {1, 2, 5, 7, 0, 0, 0, 0}, {0, 1, 2, 5, 7, 0, 0, 0}, + {3, 5, 7, 0, 0, 0, 0, 0}, {0, 3, 5, 7, 0, 0, 0, 0}, + {1, 3, 5, 7, 0, 0, 0, 0}, {0, 1, 3, 5, 7, 0, 0, 0}, + {2, 3, 5, 7, 0, 0, 0, 0}, {0, 2, 3, 5, 7, 0, 0, 0}, + {1, 2, 3, 5, 7, 0, 0, 0}, {0, 1, 2, 3, 5, 7, 0, 0}, + {4, 5, 7, 0, 0, 0, 0, 0}, {0, 4, 5, 7, 0, 0, 0, 0}, + {1, 4, 5, 7, 0, 0, 0, 0}, {0, 1, 4, 5, 7, 0, 0, 0}, + {2, 4, 5, 7, 0, 0, 0, 0}, {0, 2, 4, 5, 7, 0, 0, 0}, + {1, 2, 4, 5, 7, 0, 0, 0}, {0, 1, 2, 4, 5, 7, 0, 0}, + {3, 4, 5, 7, 0, 0, 0, 0}, {0, 3, 4, 5, 7, 0, 0, 0}, + {1, 3, 4, 5, 7, 0, 0, 0}, {0, 1, 3, 4, 5, 7, 0, 0}, + {2, 3, 4, 5, 7, 0, 0, 0}, {0, 2, 3, 4, 5, 7, 0, 0}, + {1, 2, 3, 4, 5, 7, 0, 0}, {0, 1, 2, 3, 4, 5, 7, 0}, + {6, 7, 0, 0, 0, 0, 0, 0}, {0, 6, 7, 0, 0, 0, 0, 0}, + {1, 6, 7, 0, 0, 0, 0, 0}, {0, 1, 6, 7, 0, 0, 0, 0}, + {2, 6, 7, 0, 0, 0, 0, 0}, {0, 2, 6, 7, 0, 0, 0, 0}, + {1, 2, 6, 7, 0, 0, 0, 0}, {0, 1, 2, 6, 7, 0, 0, 0}, + {3, 6, 7, 0, 0, 0, 0, 0}, {0, 3, 6, 7, 0, 0, 0, 0}, + {1, 3, 6, 7, 0, 0, 0, 0}, {0, 1, 3, 6, 7, 0, 0, 0}, + {2, 3, 6, 7, 0, 0, 0, 0}, {0, 2, 3, 6, 7, 0, 0, 0}, + {1, 2, 3, 6, 7, 0, 0, 0}, {0, 1, 2, 3, 6, 7, 0, 0}, + {4, 6, 7, 0, 0, 0, 0, 0}, {0, 4, 6, 7, 0, 0, 0, 0}, + {1, 4, 6, 7, 0, 0, 0, 0}, {0, 1, 4, 6, 7, 0, 0, 0}, + {2, 4, 6, 7, 0, 0, 0, 0}, {0, 2, 4, 6, 7, 0, 0, 0}, + {1, 2, 4, 6, 7, 0, 0, 0}, {0, 1, 2, 4, 6, 7, 0, 0}, + {3, 4, 6, 7, 0, 0, 0, 0}, {0, 3, 4, 6, 7, 0, 0, 0}, + {1, 3, 4, 6, 7, 0, 0, 0}, {0, 1, 3, 4, 6, 7, 0, 0}, + {2, 3, 4, 6, 7, 0, 0, 0}, {0, 2, 3, 4, 6, 7, 0, 0}, + {1, 2, 3, 4, 6, 7, 0, 0}, {0, 1, 2, 3, 4, 6, 7, 0}, + {5, 6, 7, 0, 0, 0, 0, 0}, {0, 5, 6, 7, 0, 0, 0, 0}, + {1, 5, 6, 7, 0, 0, 0, 0}, {0, 1, 5, 6, 7, 0, 0, 0}, + {2, 5, 6, 7, 0, 0, 0, 0}, {0, 2, 5, 6, 7, 0, 0, 0}, + {1, 2, 5, 6, 7, 0, 0, 0}, {0, 1, 2, 5, 6, 7, 0, 0}, + {3, 5, 6, 7, 0, 0, 0, 0}, {0, 3, 5, 6, 7, 0, 0, 0}, + {1, 3, 5, 6, 7, 0, 0, 0}, {0, 1, 3, 5, 6, 7, 0, 0}, + {2, 3, 5, 6, 7, 0, 0, 0}, {0, 2, 3, 5, 6, 7, 0, 0}, + {1, 2, 3, 5, 6, 7, 0, 0}, {0, 1, 2, 3, 5, 6, 7, 0}, + {4, 5, 6, 7, 0, 0, 0, 0}, {0, 4, 5, 6, 7, 0, 0, 0}, + {1, 4, 5, 6, 7, 0, 0, 0}, {0, 1, 4, 5, 6, 7, 0, 0}, + {2, 4, 5, 6, 7, 0, 0, 0}, {0, 2, 4, 5, 6, 7, 0, 0}, + {1, 2, 4, 5, 6, 7, 0, 0}, {0, 1, 2, 4, 5, 6, 7, 0}, + {3, 4, 5, 6, 7, 0, 0, 0}, {0, 3, 4, 5, 6, 7, 0, 0}, + {1, 3, 4, 5, 6, 7, 0, 0}, {0, 1, 3, 4, 5, 6, 7, 0}, + {2, 3, 4, 5, 6, 7, 0, 0}, {0, 2, 3, 4, 5, 6, 7, 0}, + {1, 2, 3, 4, 5, 6, 7, 0}, {0, 1, 2, 3, 4, 5, 6, 7}, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/README.md new file mode 100644 index 0000000000..61fac11199 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/README.md @@ -0,0 +1,59 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Usage examples + +This directory contains minimal examples demonstrating how you can use mldsa-native. + +## Basic + +See [basic](basic) for a basic example of how to build a single instance of mldsa-native. + +## Basic_deterministic + +See [basic_deterministic](basic_deterministic) for a basic example of how to build a single instance of mldsa-native without `randombytes()` implementation. This allows users to build mldsa-native using only the deterministic API when randomized functions are not required. + +## Basic_lowram + +See [basic_lowram](basic_lowram) for a basic example of how to build a single instance of mldsa-native with reduced RAM usage (`MLD_CONFIG_REDUCE_RAM`). This is useful for embedded systems with tight RAM constraints. + +## Multi-level build (C only) + +See [multilevel_build](multilevel_build) for an example of how to build one instance of mldsa-native per security level, +in such a way that level-independent code is shared. + +## Multi-level build (with native code) + +See [multilevel_build_native](multilevel_build_native) for an example of how to build one instance of mldsa-native per +security level, in such a way that level-independent code is shared, and leveraging the native backends. + +## Custom FIPS202 implementation + +See [bring_your_own_fips202](bring_your_own_fips202) for an example of how to use mldsa-native with your own FIPS-202 +implementation. + +## Custom FIPS202 implementation (static state variant) + +See [bring_your_own_fips202_static](bring_your_own_fips202_static) for an example of how to use mldsa-native with a +custom FIPS-202 implementation using a static state. This variant demonstrates the serial-only FIPS-202 configuration +(`MLD_CONFIG_SERIAL_FIPS202_ONLY`). + +## Custom config + custom FIPS-202 backend + +See [custom_backend](custom_backend) for an example of how to use mldsa-native with a custom configuration file and a +custom FIPS-202 backend. + +## Monobuild (C only) + +See [monolithic_build](monolithic_build) for an example of how to build mldsa-native (with C backend) from a single +auto-generated compilation unit. + +## Multi-level monobuild (C only) + +See [monolithic_build_multilevel](monolithic_build_multilevel) for an example of how to build all security levels of +mldsa-native (with C backend) inside a single compilation unit, sharing the level-independent code. + +## Multi-level monobuild (with native code) + +See [monolithic_build_multilevel_native](monolithic_build_multilevel_native) for an example of how to build all security +levels of mldsa-native inside a single compilation unit, sharing the level-independent code, while also linking in assembly +from the native backends. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/.gitignore b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/.gitignore new file mode 100644 index 0000000000..eb98a94f12 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +build diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/Makefile new file mode 100644 index 0000000000..274ad8ed39 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/Makefile @@ -0,0 +1,119 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +.PHONY: build run clean +.DEFAULT_GOAL := all + +CC ?= gcc + +# Adjust CFLAGS if needed +CFLAGS := \ + -Wall \ + -Wextra \ + -Werror=unused-result \ + -Wpedantic \ + -Werror \ + -Wmissing-prototypes \ + -Wshadow \ + -Wpointer-arith \ + -Wredundant-decls \ + -Wconversion \ + -Wsign-conversion \ + -Wno-long-long \ + -Wno-unknown-pragmas \ + -Wno-unused-command-line-argument \ + -O3 \ + -fomit-frame-pointer \ + -std=c99 \ + -pedantic \ + -MMD \ + $(CFLAGS) + +# If you want to use the native backends, the compiler needs to know about +# the target architecture. Here, we import the default host detection from +# mldsa-native's tests, but you can write your own or specialize accordingly. +AUTO ?= 1 +include auto.mk + +# The following only concerns the cross-compilation tests. +# You can likely ignore the following for your application. +# +# Append cross-prefix for cross compilation +# When called from the root Makefile, CROSS_PREFIX has already been added here +ifeq (,$(findstring $(CROSS_PREFIX),$(CC))) +CC := $(CROSS_PREFIX)$(CC) +endif + +# Part A: +# +# mldsa-native source and header files +# +# If you are not concerned about minimizing for a specific backend, +# you can just include _all_ source files into your build. +# +# In this example, we compile the individual mldsa-native source files directly. +# Alternatively, you can compile the 'monobuild' source file mldsa_native.c. +# See examples/monolithic_build for that. +MLD_SOURCE=$(wildcard \ + mldsa_native/src/*.c \ + mldsa_native/src/**/*.c \ + mldsa_native/src/**/**/*.c \ + mldsa_native/src/**/**/**/*.c) + +INC=-Imldsa_native + +# Part B: +# +# Random number generator +# +# !!! WARNING !!! +# +# The randombytes() implementation used here is for TESTING ONLY. +# You MUST NOT use this implementation outside of testing. +# +# !!! WARNING !!! +RNG_SOURCE=$(wildcard test_only_rng/*.c) + +# Part C: +# +# Your application source code +APP_SOURCE=$(wildcard *.c) + +ALL_SOURCE=$(MLD_SOURCE) $(RNG_SOURCE) $(APP_SOURCE) + +BUILD_DIR=build +BIN=test_binary + +# +# Configuration adjustments +# + +# Pick prefix +CFLAGS += -DMLD_CONFIG_NAMESPACE_PREFIX=mldsa + +BINARY_NAME_FULL_44=$(BUILD_DIR)/$(BIN)44 +BINARY_NAME_FULL_65=$(BUILD_DIR)/$(BIN)65 +BINARY_NAME_FULL_87=$(BUILD_DIR)/$(BIN)87 +BINARIES_FULL=$(BINARY_NAME_FULL_44) $(BINARY_NAME_FULL_65) $(BINARY_NAME_FULL_87) + +$(BINARY_NAME_FULL_44): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=44 +$(BINARY_NAME_FULL_65): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=65 +$(BINARY_NAME_FULL_87): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=87 + +$(BINARIES_FULL): $(ALL_SOURCE) + echo "$@" + mkdir -p $(BUILD_DIR) + $(CC) $(CFLAGS) $(INC) $^ -o $@ + +all: build + +build: $(BINARIES_FULL) + +run: $(BINARIES_FULL) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_44) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_65) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_87) + +clean: + rm -rf $(BUILD_DIR) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/README.md new file mode 100644 index 0000000000..46e831070b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/README.md @@ -0,0 +1,38 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Basic build + +This directory contains a minimal example for how to build mldsa-native for a single security level. + +## Use Case + +Use this approach when: +- You need only one ML-DSA parameter set (44, 65, or 87) +- You want to build the mldsa-native C files separately, not as a single compilation unit. +- You're using C only, no native backends. + +## Components + +1. mldsa-native source tree: [`mldsa/src/`](../../mldsa/src) and [`mldsa/src/fips202/`](../../mldsa/src/fips202) +2. A secure random number generator implementing [`randombytes.h`](../../mldsa/src/randombytes.h) +3. Your application source code + +## Configuration + +The configuration file [mldsa_native_config.h](mldsa_native/mldsa_native_config.h) sets: +- `MLD_CONFIG_PARAMETER_SET`: Security level (44, 65, or 87). Default is 65. +- `MLD_CONFIG_NAMESPACE_PREFIX`: Symbol prefix for the API. Set to `mldsa` in this example. + +To change the security level, modify `MLD_CONFIG_PARAMETER_SET` in the config file or pass it via CFLAGS. + +## Usage + +```bash +make build # Build the example +make run # Run the example +``` + +## Warning + +The `randombytes()` implementation in `test_only_rng/` is for TESTING ONLY. +You MUST provide a cryptographically secure RNG for production use. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/auto.mk b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/auto.mk new file mode 100644 index 0000000000..5f71942085 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/auto.mk @@ -0,0 +1,178 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# Automatically detect system architecture and set preprocessor flags accordingly +# This file detects host CPU capabilities and combines them with compiler support +# to enable optimal compilation flags. +# +# Compiler feature detection can be overridden by setting the corresponding variable +# on the command line: +# make MK_COMPILER_SUPPORTS_SHA3=0 # Disable SHA3 detection +# make MK_COMPILER_SUPPORTS_AVX2=0 # Disable AVX2 detection +# make MK_COMPILER_SUPPORTS_BMI2=0 # Disable BMI2 detection +# make MK_COMPILER_SUPPORTS_SSE2=0 # Disable SSE2 detection + +ifndef _AUTO_MK +_AUTO_MK := + +# Override ARCH for cross-compilation based on CROSS_PREFIX +ifeq ($(CROSS_PREFIX),) +ARCH := $(shell uname -m) +# Normalize architecture names +ifeq ($(ARCH),arm64) +ARCH := aarch64 +endif +else # CROSS_PREFIX +ifneq ($(findstring x86_64, $(CROSS_PREFIX)),) +ARCH := x86_64 +else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),) +ARCH := aarch64_be +else ifneq ($(findstring aarch64, $(CROSS_PREFIX)),) +ARCH := aarch64 +else ifneq ($(findstring riscv64, $(CROSS_PREFIX)),) +ARCH := riscv64 +else ifneq ($(findstring riscv32, $(CROSS_PREFIX)),) +ARCH := riscv32 +else ifneq ($(findstring powerpc64le, $(CROSS_PREFIX)),) +ARCH := powerpc64le +else ifneq ($(findstring arm-none-eabi-, $(CROSS_PREFIX)),) +ARCH := arm +else +ifeq ($(AUTO),1) +$(warning Unknown cross-compilation prefix $(CROSS_PREFIX), no automatic detection of CFLAGS.) +ARCH := unknown +endif +endif +endif # CROSS_PREFIX + +# x86_64 compiler feature detection +ifeq ($(ARCH),x86_64) + +# Test AVX2 support using C with inline assembly +MK_COMPILER_SUPPORTS_AVX2 ?= $(shell echo 'int main() { __asm__("vpxor %%ymm0, %%ymm1, %%ymm2" ::: "ymm0", "ymm1", "ymm2"); return 0; }' | $(CC) -mavx2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test SSE2 support using C with inline assembly +MK_COMPILER_SUPPORTS_SSE2 ?= $(shell echo 'int main() { __asm__("pxor %%xmm0, %%xmm1" ::: "xmm0", "xmm1"); return 0; }' | $(CC) -msse2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test BMI2 support using C with inline assembly +MK_COMPILER_SUPPORTS_BMI2 ?= $(shell echo 'int main() { __asm__("pdep %%eax, %%ebx, %%ecx" ::: "eax", "ebx", "ecx"); return 0; }' | $(CC) -mbmi2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # x86_64 compiler detection + +# AArch64 compiler feature detection +ifeq ($(ARCH),aarch64) + +# Test SHA3 support (Armv8.4-a+SHA3) using C with inline assembly +MK_COMPILER_SUPPORTS_SHA3 ?= $(shell echo 'int main() { __asm__("eor3 v0.16b, v1.16b, v2.16b, v3.16b" ::: "v0", "v1", "v2", "v3"); return 0; }' | $(CC) -march=armv8.4-a+sha3 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # aarch64 compiler detection + +# Define HOST_PLATFORM if not already defined +HOST_PLATFORM ?= $(shell uname -s)-$(shell uname -m) + +# Helper function to check if host CPU supports a feature +# Usage: $(call check_host_feature,feature_pattern,source_command) +define check_host_feature +$(shell $(2) 2>/dev/null | grep -q "$(1)" && echo 1 || echo 0) +endef + +# x86_64 architecture detection +ifeq ($(ARCH),x86_64) + +# Host CPU feature detection for x86_64 +ifeq ($(HOST_PLATFORM),Linux-x86_64) +# Linux: Use /proc/cpuinfo +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,avx2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,sse2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,bmi2,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-x86_64) +# macOS: Use sysctl +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,AVX2,sysctl -n machdep.cpu.leaf7_features) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,SSE2,sysctl -n machdep.cpu.features) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,BMI2,sysctl -n machdep.cpu.leaf7_features) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_AVX2 := 1 +MK_HOST_SUPPORTS_SSE2 := 1 +MK_HOST_SUPPORTS_BMI2 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_AVX2 := 0 +MK_HOST_SUPPORTS_SSE2 := 0 +MK_HOST_SUPPORTS_BMI2 := 0 +endif # HOST_PLATFORM x86_64 + +endif # x86_64 + +# AArch64 architecture detection +ifeq ($(ARCH),aarch64) + +# Host CPU feature detection for AArch64 +ifeq ($(HOST_PLATFORM),Linux-aarch64) +# Linux: Use /proc/cpuinfo (look for sha3 in Features line) +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,sha3,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-arm64) +# macOS: Use sysctl to check for SHA3 support +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,1,sysctl -n hw.optional.armv8_2_sha3) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_SHA3 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_SHA3 := 0 +endif # HOST_PLATFORM aarch64 + +endif # aarch64 + +# Only apply CFLAGS modifications if AUTO=1 +ifeq ($(AUTO),1) + +# x86_64 CFLAGS configuration +ifeq ($(ARCH),x86_64) +CFLAGS += -DMLD_FORCE_X86_64 + +# Add flags only if both compiler and host support the feature +ifeq ($(MK_COMPILER_SUPPORTS_AVX2)$(MK_HOST_SUPPORTS_AVX2),11) +CFLAGS += -mavx2 +endif + +ifeq ($(MK_COMPILER_SUPPORTS_BMI2)$(MK_HOST_SUPPORTS_BMI2),11) +CFLAGS += -mbmi2 +endif +endif # x86_64 + +# AArch64 CFLAGS configuration +ifeq ($(ARCH),aarch64) +CFLAGS += -DMLD_FORCE_AARCH64 + +# Add SHA3 flags only if both compiler and host support it +ifeq ($(MK_COMPILER_SUPPORTS_SHA3)$(MK_HOST_SUPPORTS_SHA3),11) +CFLAGS += -march=armv8.4-a+sha3 +endif +endif # aarch64 + +# AArch64 Big Endian CFLAGS configuration +ifeq ($(ARCH),aarch64_be) +CFLAGS += -DMLD_FORCE_AARCH64_EB +endif # aarch64_be + +# RISC-V 64-bit CFLAGS configuration +ifeq ($(ARCH),riscv64) +CFLAGS += -DMLD_FORCE_RISCV64 +CFLAGS += -march=rv64gcv +endif # riscv64 + +# RISC-V 32-bit CFLAGS configuration +ifeq ($(ARCH),riscv32) +CFLAGS += -DMLD_FORCE_RISCV32 +endif # riscv32 + +# PowerPC 64-bit Little Endian CFLAGS configuration +ifeq ($(ARCH),powerpc64le) +CFLAGS += -DMLD_FORCE_PPC64LE +endif # powerpc64le + +endif # AUTO=1 + +endif # _AUTO_MK diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/expected_signatures.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/expected_signatures.h new file mode 100644 index 0000000000..d52fbe8d5e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/expected_signatures.h @@ -0,0 +1,890 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef EXPECTED_SIGNATURES_H +#define EXPECTED_SIGNATURES_H + +#include + +/* Expected deterministic signatures for each parameter set + * These are generated using the same test message, context, and deterministic + * RNG as used in the basic example. + * + * The PCT modifies the PRNG state, so the KAT tests don't work. + * We run KAT tests only for disabled PCT. */ +#if !defined(MLD_CONFIG_KEYGEN_PCT) +#if MLD_CONFIG_PARAMETER_SET == 44 +const uint8_t expected_signature[] = { + 0x27, 0x5e, 0xbe, 0x2d, 0x23, 0x1a, 0x76, 0xc5, 0xd9, 0x77, 0xcb, 0x62, + 0x25, 0x04, 0xdb, 0x23, 0x31, 0xa9, 0xa8, 0xcd, 0xbc, 0xde, 0xf2, 0x20, + 0xfd, 0xa7, 0xb5, 0xf5, 0x59, 0xae, 0xe6, 0xdd, 0x62, 0xfa, 0x34, 0x96, + 0x4f, 0x1d, 0xcd, 0x84, 0x82, 0xee, 0xc1, 0x74, 0x96, 0x3d, 0x98, 0xd9, + 0x42, 0x9d, 0xd0, 0x77, 0x9c, 0xf9, 0x9e, 0x0e, 0xa7, 0xcb, 0x70, 0xeb, + 0xe7, 0xcd, 0xce, 0x8c, 0xdc, 0x37, 0x15, 0x95, 0x0e, 0x24, 0x70, 0x4f, + 0x33, 0x6e, 0x4f, 0xad, 0xed, 0x4d, 0xf3, 0xe5, 0x38, 0xc1, 0xcd, 0xbb, + 0xde, 0xf1, 0xd2, 0x0d, 0xd6, 0x6b, 0xa3, 0x68, 0x92, 0x4c, 0x4b, 0x4f, + 0x89, 0xa0, 0xa8, 0xc8, 0x36, 0x93, 0x91, 0x17, 0xe7, 0x16, 0xed, 0xcb, + 0xdc, 0xf6, 0x28, 0x13, 0x32, 0x60, 0x14, 0xe0, 0x28, 0x7a, 0x69, 0x05, + 0x1d, 0xf7, 0x3b, 0xdf, 0x18, 0x0c, 0xaf, 0xba, 0x46, 0xf1, 0x5e, 0xd4, + 0xd3, 0xd0, 0x8e, 0x9a, 0xe2, 0xac, 0xdd, 0x0e, 0x5f, 0xb1, 0x69, 0xe2, + 0x74, 0x77, 0x2e, 0x52, 0xf9, 0x11, 0x3d, 0xd8, 0xe5, 0x36, 0x6f, 0x7d, + 0x7d, 0xde, 0x7c, 0xa7, 0x1d, 0x37, 0xdf, 0x6d, 0x5e, 0xea, 0xc8, 0xc0, + 0x72, 0x3f, 0x79, 0xbd, 0x0b, 0x6d, 0x7f, 0x9a, 0x15, 0x90, 0xda, 0xc1, + 0xae, 0xce, 0xf3, 0x44, 0x35, 0x5e, 0x83, 0x86, 0x7e, 0x89, 0x18, 0xa7, + 0x97, 0x8e, 0x87, 0x7c, 0x15, 0xd2, 0xd2, 0x7e, 0xf2, 0xc8, 0x29, 0x4f, + 0x70, 0x0f, 0xa6, 0xd4, 0x76, 0xe8, 0xdd, 0x7d, 0x7a, 0x2d, 0xfe, 0x0a, + 0x0c, 0x5c, 0xb1, 0xef, 0xec, 0x1a, 0x32, 0xca, 0x87, 0xff, 0x6b, 0xb1, + 0xa0, 0xe1, 0x2e, 0x01, 0x52, 0xb2, 0xb8, 0x74, 0x34, 0xb3, 0xfb, 0x15, + 0x0f, 0x17, 0xca, 0x74, 0xc1, 0xc1, 0x61, 0x86, 0x40, 0x38, 0x58, 0xba, + 0x82, 0x26, 0x66, 0x33, 0xa4, 0x52, 0xf3, 0xb5, 0x36, 0x60, 0xd8, 0x5a, + 0x8d, 0x9d, 0x28, 0x18, 0x3a, 0x68, 0x34, 0x2a, 0xa2, 0xe2, 0xb5, 0x39, + 0xed, 0x7d, 0xe5, 0xbe, 0x46, 0xb9, 0x04, 0x0c, 0xf3, 0xef, 0x88, 0x6e, + 0x9d, 0x6f, 0x23, 0xe2, 0x44, 0xe5, 0x2e, 0x3a, 0x7a, 0x1d, 0x49, 0x0f, + 0xdd, 0xcd, 0xd6, 0x4e, 0x0d, 0x0b, 0xc3, 0x35, 0xf2, 0xd1, 0x5d, 0x73, + 0x5d, 0x07, 0xca, 0x5c, 0xbd, 0x14, 0xec, 0x57, 0xb3, 0xbd, 0x37, 0xe7, + 0xdf, 0x06, 0x7d, 0xe0, 0x58, 0x4a, 0xcf, 0x7a, 0xc5, 0xa7, 0x24, 0x62, + 0x6f, 0x09, 0x75, 0x69, 0x74, 0x7f, 0xdf, 0xc8, 0x69, 0x5c, 0x20, 0x10, + 0x3a, 0xe8, 0x01, 0x12, 0xa3, 0xfb, 0xda, 0x4c, 0x3a, 0x0d, 0x3c, 0x3e, + 0x26, 0xe0, 0xa6, 0x7f, 0xb2, 0x6b, 0x0b, 0x68, 0x0a, 0x68, 0x86, 0xb1, + 0xfa, 0x61, 0x3a, 0xe8, 0x77, 0xdc, 0x42, 0xf7, 0xf4, 0x39, 0x9a, 0x40, + 0x58, 0x71, 0xc7, 0x0f, 0xf4, 0x0e, 0xc5, 0x1e, 0xe0, 0x28, 0x45, 0x7d, + 0xba, 0x84, 0xe4, 0x34, 0x69, 0xf9, 0xa5, 0x8a, 0x80, 0x43, 0xc0, 0x8d, + 0x04, 0x33, 0x43, 0xb8, 0xd7, 0x5d, 0x93, 0xed, 0x0f, 0x31, 0x6a, 0x4d, + 0xbf, 0xb7, 0x44, 0x41, 0x1b, 0xd4, 0xac, 0x9d, 0x83, 0x66, 0x08, 0x92, + 0xad, 0x3c, 0x0e, 0x1a, 0xe8, 0xd4, 0xe1, 0x5c, 0x63, 0xcf, 0x27, 0x48, + 0x5a, 0x8f, 0xc5, 0x6f, 0x83, 0x6b, 0x6f, 0xe8, 0xda, 0x1f, 0xba, 0xe9, + 0x7e, 0x11, 0xab, 0x8b, 0x4e, 0xc1, 0x9e, 0x23, 0x69, 0x1f, 0x42, 0x40, + 0xad, 0xbb, 0xfb, 0x4f, 0xe2, 0x50, 0xc9, 0x46, 0xe7, 0x15, 0x15, 0xf8, + 0x61, 0x09, 0x2a, 0x0b, 0x37, 0x43, 0xd4, 0x98, 0x5f, 0xc8, 0x4d, 0x06, + 0xe7, 0x0c, 0x3f, 0x83, 0x59, 0xd5, 0xcd, 0x2d, 0xde, 0x1e, 0x3a, 0x87, + 0x4e, 0xf7, 0x0a, 0x3c, 0x84, 0x72, 0x47, 0x11, 0x02, 0x6c, 0xe8, 0x93, + 0xcd, 0x24, 0xe9, 0x23, 0x86, 0x78, 0x53, 0xe0, 0xc6, 0x2f, 0xba, 0xa7, + 0xed, 0xaf, 0xba, 0x42, 0x80, 0x0d, 0xe6, 0xae, 0xda, 0xed, 0xbc, 0x65, + 0x21, 0x6d, 0x13, 0x90, 0x61, 0xb4, 0x05, 0x7b, 0x07, 0x86, 0xd7, 0x89, + 0x30, 0x9c, 0xc1, 0x9a, 0x41, 0x4d, 0xe8, 0x2b, 0x35, 0x21, 0x3a, 0x8a, + 0x60, 0x83, 0x1a, 0x97, 0x10, 0x98, 0xb6, 0xe1, 0x6b, 0xb5, 0xb1, 0xa1, + 0x36, 0x34, 0x60, 0x1b, 0x96, 0x5d, 0x1f, 0x2a, 0xd8, 0xf2, 0x94, 0xdd, + 0x58, 0x3d, 0x0f, 0xbe, 0x9d, 0xfc, 0xf5, 0x24, 0xb1, 0xd2, 0xc3, 0x36, + 0xef, 0xdb, 0x8e, 0x97, 0x3c, 0x9a, 0x4f, 0x48, 0xe3, 0x84, 0x91, 0xd8, + 0x39, 0x91, 0xf6, 0x55, 0xeb, 0x62, 0x51, 0x3d, 0x8f, 0x55, 0x60, 0x5e, + 0x00, 0xe0, 0xd2, 0xc7, 0x66, 0x51, 0xf1, 0xe2, 0xb7, 0x43, 0xc3, 0xe6, + 0x12, 0x9a, 0xe5, 0x84, 0xe0, 0x10, 0x76, 0xc7, 0x75, 0x6e, 0xa6, 0xee, + 0x11, 0xe4, 0xaf, 0xbd, 0x8a, 0x4f, 0x1d, 0x05, 0x29, 0x4f, 0xce, 0xa5, + 0x73, 0x92, 0x57, 0x7e, 0x0d, 0x11, 0xbc, 0xf8, 0x74, 0x4d, 0xf7, 0xb9, + 0x40, 0x0d, 0x5a, 0xa1, 0x19, 0x76, 0x4a, 0xae, 0x21, 0x16, 0xd4, 0x3f, + 0x76, 0xbf, 0x27, 0xbd, 0x2f, 0xe4, 0x25, 0x21, 0x00, 0x4e, 0xcc, 0x7c, + 0xc6, 0x57, 0xa4, 0xbf, 0xf1, 0x56, 0x90, 0xe0, 0xa4, 0xa3, 0xee, 0xcf, + 0x43, 0x4f, 0xda, 0x77, 0x47, 0x51, 0x79, 0x6a, 0x29, 0xb4, 0x2c, 0xdf, + 0xca, 0x47, 0xcb, 0xb8, 0x82, 0x7e, 0x44, 0x62, 0x9b, 0x8f, 0x61, 0x7b, + 0x3a, 0x93, 0x82, 0x1f, 0x69, 0xb7, 0xb1, 0xa6, 0x2c, 0xe1, 0xb2, 0x65, + 0xa0, 0x6d, 0x6f, 0xe4, 0x79, 0xd8, 0x30, 0xe0, 0xee, 0xd8, 0x83, 0x01, + 0xb2, 0x1f, 0x5c, 0x90, 0x44, 0x86, 0x48, 0x11, 0xf9, 0x11, 0xff, 0xea, + 0x45, 0x43, 0xae, 0x8a, 0x6b, 0x99, 0xf2, 0x1f, 0x02, 0x51, 0x4a, 0x35, + 0x02, 0x34, 0xd3, 0xe8, 0xda, 0xb1, 0x4b, 0xe3, 0xa5, 0x60, 0xce, 0x67, + 0xe3, 0x62, 0x59, 0xfc, 0x00, 0x0a, 0xe2, 0xfe, 0x7b, 0x1e, 0xe6, 0xf5, + 0x75, 0x19, 0x9b, 0x5e, 0xcb, 0xe6, 0xf5, 0x80, 0x9e, 0x3c, 0xb8, 0x54, + 0xd6, 0x0b, 0xfd, 0x48, 0xe0, 0xfa, 0x82, 0x2b, 0x5b, 0x26, 0xf9, 0x49, + 0xaf, 0xbe, 0x9c, 0x78, 0x73, 0xce, 0xc5, 0x65, 0xe2, 0x94, 0x2b, 0xd9, + 0xd0, 0x27, 0x3a, 0x66, 0x3e, 0xe2, 0xe0, 0x10, 0x79, 0x3d, 0xde, 0xc8, + 0x47, 0xdb, 0x1e, 0xc3, 0xe7, 0x51, 0xae, 0x59, 0xeb, 0x38, 0x66, 0x63, + 0x40, 0x8f, 0xbe, 0x1e, 0xb2, 0x2b, 0xeb, 0x64, 0x5f, 0xdd, 0x24, 0xc4, + 0x5a, 0x25, 0x59, 0xa2, 0xda, 0x4f, 0xdf, 0xf8, 0xb0, 0xb0, 0xf7, 0xcd, + 0x1f, 0x14, 0xcd, 0x09, 0x48, 0x70, 0x27, 0x1b, 0xde, 0xc4, 0xf0, 0xf3, + 0x56, 0x97, 0x8a, 0xb7, 0xf4, 0x19, 0x76, 0xe3, 0x9a, 0x33, 0x55, 0xfe, + 0x93, 0x68, 0xca, 0x1f, 0x3d, 0x44, 0x86, 0x39, 0x5d, 0x84, 0x58, 0x50, + 0xf2, 0xf1, 0xea, 0x4a, 0x5c, 0x1c, 0x74, 0xf0, 0x4b, 0xa5, 0x9c, 0x30, + 0xa0, 0x14, 0x1a, 0x80, 0xe0, 0xde, 0x3e, 0xae, 0x7f, 0x10, 0x18, 0x4a, + 0x1e, 0x9e, 0x6b, 0x75, 0x1a, 0xca, 0x08, 0x4e, 0x61, 0x72, 0x43, 0x9b, + 0x18, 0x4d, 0x2c, 0xd8, 0xb4, 0xc9, 0xea, 0x00, 0xb0, 0xdf, 0x1b, 0xcb, + 0x03, 0xc3, 0x7a, 0x27, 0xff, 0x41, 0x9d, 0xf9, 0xfd, 0xb3, 0x0c, 0xc0, + 0x48, 0x5d, 0x7c, 0xae, 0x5a, 0x72, 0x69, 0x93, 0x68, 0xe1, 0x9e, 0x9f, + 0x1f, 0x5c, 0x0a, 0x60, 0x90, 0x1a, 0x8e, 0x5a, 0x30, 0xd4, 0x2c, 0xbd, + 0xe1, 0x20, 0x51, 0xbc, 0x1c, 0x50, 0xb5, 0xf7, 0x42, 0x23, 0x35, 0x0f, + 0x92, 0xe2, 0xbb, 0x2a, 0x04, 0xa7, 0xde, 0x2e, 0x25, 0xfa, 0xed, 0x20, + 0x83, 0x9c, 0xd4, 0x56, 0xe0, 0x4d, 0x8d, 0x79, 0xa5, 0xa0, 0x6f, 0x49, + 0x62, 0x82, 0x9a, 0xa7, 0x4e, 0x54, 0x95, 0x0a, 0xc6, 0x5e, 0x27, 0x65, + 0x6d, 0x11, 0x2b, 0x35, 0x72, 0x34, 0x48, 0xd2, 0xe4, 0x9e, 0x07, 0x7d, + 0x03, 0x27, 0x15, 0x93, 0x55, 0x5c, 0x32, 0x43, 0xdb, 0x34, 0x8d, 0xbd, + 0x8d, 0x88, 0xa5, 0x24, 0x07, 0x93, 0x89, 0x37, 0xb9, 0x17, 0x15, 0xad, + 0xc7, 0x68, 0x86, 0x63, 0x0f, 0x10, 0x53, 0x8f, 0x40, 0xd3, 0x7b, 0x22, + 0x2b, 0x1a, 0x4c, 0xcb, 0x4f, 0x51, 0xf1, 0x3b, 0x19, 0xb8, 0x42, 0x53, + 0xaf, 0xf6, 0xb9, 0x57, 0x7f, 0xba, 0x8d, 0xb8, 0xb7, 0x3b, 0xe3, 0xc5, + 0xab, 0x4a, 0x26, 0x21, 0x6e, 0xce, 0x27, 0xb8, 0xc3, 0x99, 0x56, 0x14, + 0xdd, 0x5b, 0x61, 0x82, 0xbf, 0xd3, 0xc8, 0x76, 0xee, 0x22, 0xaf, 0x21, + 0x21, 0x1d, 0x4e, 0x33, 0xb5, 0x43, 0x3a, 0xfb, 0x91, 0xa0, 0xaa, 0xe3, + 0x10, 0x4a, 0x50, 0x42, 0xd4, 0x5f, 0x92, 0x0e, 0x71, 0x60, 0x4f, 0xaa, + 0xef, 0x66, 0x45, 0xfe, 0xf7, 0xc8, 0xb0, 0x73, 0x75, 0x91, 0x0b, 0x86, + 0x40, 0xa5, 0x02, 0x28, 0xf7, 0xe0, 0x1f, 0x5d, 0xe6, 0xe3, 0xa4, 0x57, + 0xbd, 0x29, 0xaa, 0x53, 0xae, 0x35, 0x30, 0x78, 0x73, 0xd6, 0xb7, 0x01, + 0x9d, 0x13, 0x50, 0xf6, 0x39, 0xa2, 0x3e, 0x03, 0x04, 0xaa, 0x6d, 0xcf, + 0x6b, 0xff, 0x9a, 0xbe, 0x3e, 0x0a, 0xd4, 0x20, 0xce, 0x42, 0x1f, 0xca, + 0x2f, 0xd3, 0x2c, 0xd1, 0xf4, 0xd2, 0x50, 0xd3, 0xa2, 0xc1, 0x1e, 0x87, + 0xbf, 0xeb, 0xb8, 0xa8, 0xd4, 0x1c, 0x96, 0xb8, 0x8e, 0xbe, 0x35, 0x5f, + 0x08, 0x28, 0x20, 0x2b, 0xdc, 0xa4, 0xf5, 0xf6, 0xde, 0xca, 0x1e, 0xcb, + 0x93, 0x3b, 0x64, 0x79, 0x00, 0x3c, 0x8d, 0xbb, 0x5c, 0x7a, 0x40, 0x14, + 0x58, 0x12, 0xa4, 0xf7, 0x6e, 0x51, 0xfb, 0xe7, 0x6f, 0x49, 0x5b, 0xc2, + 0xc9, 0x05, 0x38, 0x9c, 0x08, 0x78, 0x71, 0x27, 0x2b, 0xf5, 0xbf, 0xd6, + 0x38, 0xaa, 0x45, 0xe1, 0xe1, 0x4c, 0xfb, 0xfd, 0xb7, 0xe6, 0xcf, 0xad, + 0x9e, 0x56, 0xaf, 0x12, 0x12, 0x98, 0xe6, 0x38, 0xaa, 0xee, 0xdb, 0x9e, + 0xca, 0xe1, 0x79, 0x6d, 0x44, 0xfb, 0x19, 0x50, 0x92, 0x00, 0x06, 0x2c, + 0x24, 0x71, 0x6c, 0x34, 0x45, 0xac, 0xf9, 0x82, 0x66, 0xa8, 0x63, 0x80, + 0xa8, 0x5b, 0x21, 0x3c, 0x36, 0x71, 0x93, 0x40, 0x7b, 0xff, 0xa2, 0xd0, + 0x72, 0xb4, 0x66, 0xfa, 0xfc, 0xa0, 0xee, 0xca, 0x15, 0x73, 0x52, 0xe7, + 0x9d, 0x11, 0xd3, 0xbc, 0xab, 0x37, 0x31, 0x0e, 0xaf, 0xdc, 0x05, 0x30, + 0x79, 0x8c, 0x25, 0x75, 0x5c, 0x60, 0xc7, 0x9a, 0xfc, 0x88, 0xea, 0xe6, + 0x09, 0x9f, 0xd1, 0x4f, 0x13, 0xf4, 0x41, 0x54, 0x5b, 0x7a, 0xe4, 0x49, + 0x3c, 0x0f, 0x15, 0xe9, 0xa4, 0x85, 0xb2, 0x92, 0x07, 0xea, 0xea, 0x7c, + 0xc1, 0x6d, 0xa9, 0x03, 0xb3, 0x31, 0xce, 0x1e, 0x82, 0xca, 0x9e, 0x3c, + 0x88, 0x88, 0xc1, 0x04, 0x5f, 0xbe, 0xd5, 0x94, 0x0d, 0x67, 0x98, 0x27, + 0xd0, 0x0f, 0x43, 0xf3, 0xb3, 0xfc, 0xff, 0x24, 0xa2, 0x1e, 0x17, 0x06, + 0xb0, 0x52, 0x16, 0x7c, 0xd8, 0x49, 0x74, 0x51, 0xcf, 0x2d, 0x36, 0x16, + 0xb0, 0x88, 0xb2, 0x2b, 0x1d, 0x72, 0x70, 0xab, 0xe2, 0xf6, 0x5f, 0xa5, + 0x2d, 0x4e, 0xd1, 0x42, 0x3c, 0x83, 0x84, 0xb2, 0x56, 0xeb, 0x8d, 0xce, + 0x33, 0x46, 0xdb, 0x3d, 0x4f, 0x97, 0xea, 0x37, 0x5e, 0x0d, 0xd7, 0x4c, + 0x9a, 0x7e, 0xc9, 0x0e, 0x69, 0x4d, 0x97, 0x15, 0x1e, 0x09, 0xbe, 0x7e, + 0xff, 0xe8, 0xf5, 0xab, 0xe9, 0xe7, 0xed, 0x4b, 0x41, 0xa5, 0xf2, 0x2a, + 0x24, 0x48, 0x8b, 0x72, 0x4b, 0x9d, 0xcf, 0x45, 0xdb, 0xc0, 0xaf, 0xa8, + 0x0f, 0x0f, 0x67, 0x37, 0xd3, 0x8b, 0xe1, 0x67, 0x90, 0xd8, 0x1c, 0x58, + 0x36, 0x46, 0x51, 0x52, 0xea, 0xb4, 0x75, 0xb1, 0xcd, 0xc5, 0x39, 0x16, + 0xe0, 0xec, 0x16, 0xf7, 0xf8, 0x0f, 0x5d, 0x13, 0x84, 0x62, 0x34, 0x86, + 0x42, 0x05, 0xa8, 0x08, 0x84, 0xa9, 0x77, 0x12, 0xc1, 0x56, 0xdd, 0x28, + 0xde, 0x39, 0x33, 0x21, 0x3d, 0xbd, 0x94, 0xce, 0xe4, 0xb3, 0x17, 0x9b, + 0x09, 0x20, 0xf0, 0x25, 0xce, 0x00, 0x34, 0x8e, 0x12, 0x94, 0x74, 0x0b, + 0x16, 0xa1, 0x60, 0x76, 0x24, 0xf0, 0xbf, 0xe3, 0x3a, 0x83, 0x8f, 0x40, + 0x47, 0x2e, 0x1c, 0xd5, 0x35, 0x25, 0x87, 0xb3, 0x11, 0xdc, 0x98, 0xb0, + 0xa6, 0x5f, 0x6a, 0x05, 0x1d, 0x06, 0x8d, 0xe8, 0xb0, 0x98, 0xf0, 0x43, + 0x29, 0x84, 0xe4, 0xef, 0x34, 0x67, 0x74, 0x64, 0xe8, 0xb8, 0xf0, 0xd4, + 0x9e, 0xc1, 0x3f, 0x5f, 0xeb, 0xe0, 0x9b, 0x37, 0xf8, 0x75, 0x46, 0x47, + 0xa5, 0x3e, 0x42, 0x20, 0x50, 0xc4, 0x5d, 0xf3, 0xdf, 0x4e, 0xf8, 0x0e, + 0x1e, 0x15, 0x10, 0x3e, 0xf1, 0x68, 0xad, 0x87, 0xad, 0xe5, 0x45, 0x5e, + 0x22, 0xba, 0x2e, 0x51, 0xa0, 0xbf, 0xdc, 0x87, 0xca, 0xe4, 0x1f, 0x2f, + 0x2c, 0xae, 0xa9, 0x14, 0xd7, 0xdd, 0x01, 0xa8, 0x4f, 0x43, 0xcb, 0x84, + 0x92, 0xbf, 0xf9, 0x3d, 0xf0, 0x6b, 0x19, 0x43, 0xb0, 0xdf, 0xff, 0x94, + 0x76, 0xe2, 0x84, 0xf9, 0x31, 0x88, 0x7e, 0xc6, 0x87, 0x58, 0xbe, 0x5d, + 0x8b, 0xf8, 0xb5, 0xdc, 0x95, 0x16, 0x5f, 0xa1, 0x2c, 0xe8, 0x53, 0x36, + 0x64, 0xf5, 0x5d, 0xa0, 0x74, 0x12, 0x78, 0x59, 0x73, 0x69, 0x5a, 0x2b, + 0x36, 0x4a, 0xff, 0x5b, 0xef, 0x49, 0x2c, 0xb2, 0x9e, 0x59, 0xf0, 0x39, + 0x56, 0xe1, 0xd0, 0x1a, 0x05, 0xb2, 0x7c, 0xd1, 0x40, 0x09, 0xdf, 0x00, + 0xc9, 0x15, 0x53, 0xa2, 0xda, 0x84, 0xb5, 0x85, 0x05, 0x76, 0xa6, 0x1b, + 0xcb, 0x06, 0xb2, 0xc8, 0xa0, 0xc5, 0x23, 0x8f, 0xb0, 0xe8, 0xf5, 0xd9, + 0xd0, 0x19, 0x29, 0xfe, 0x2d, 0x9a, 0x57, 0x76, 0x5f, 0xf2, 0xef, 0x71, + 0x16, 0xee, 0x28, 0x7b, 0xe4, 0x48, 0xeb, 0xda, 0xe0, 0xd5, 0xbc, 0x0e, + 0x46, 0x6b, 0x06, 0x5d, 0xe5, 0x91, 0x2d, 0xcb, 0xc4, 0x53, 0xa6, 0x16, + 0xd5, 0xe7, 0xd8, 0xf1, 0xdd, 0x4f, 0xbb, 0xcc, 0x55, 0x67, 0x19, 0x98, + 0x94, 0x95, 0x5e, 0xd6, 0xf5, 0xf7, 0xe8, 0x6a, 0xf7, 0x20, 0x86, 0x3a, + 0x43, 0xbf, 0xe9, 0xec, 0x6b, 0x33, 0x49, 0x19, 0x43, 0xfb, 0xeb, 0x3f, + 0xf4, 0x9d, 0x29, 0x66, 0xb9, 0x6e, 0xb5, 0x15, 0x4b, 0x8d, 0x3c, 0x3c, + 0xfa, 0xf2, 0x87, 0xba, 0x61, 0x11, 0x40, 0xe6, 0xb4, 0x6f, 0xf5, 0xe1, + 0x24, 0x32, 0x69, 0x3e, 0xff, 0xf7, 0xbc, 0xee, 0x82, 0xf2, 0x9e, 0x6d, + 0x3f, 0x6c, 0xcc, 0x0f, 0x4f, 0xc3, 0xf1, 0xdb, 0x1e, 0x81, 0xd7, 0x9b, + 0x22, 0xa8, 0xa7, 0x36, 0x6d, 0xa9, 0x6f, 0x46, 0x1a, 0xa7, 0xff, 0x00, + 0x4b, 0xd8, 0xab, 0xe7, 0x50, 0x3b, 0xe9, 0xc0, 0x57, 0xec, 0x8d, 0x0c, + 0xa0, 0xee, 0x8c, 0x2a, 0x74, 0xf2, 0x94, 0xf9, 0x0c, 0x20, 0x14, 0xd9, + 0xad, 0x0d, 0x4e, 0xac, 0x35, 0x44, 0x59, 0x28, 0x24, 0x31, 0x32, 0xaa, + 0x6d, 0xc2, 0x13, 0xb9, 0xee, 0x75, 0x0c, 0x5f, 0x39, 0xef, 0x31, 0xca, + 0x28, 0x48, 0x56, 0x59, 0xfb, 0xa8, 0xd8, 0x2b, 0x70, 0x61, 0x22, 0x43, + 0x43, 0xb9, 0x60, 0x44, 0xeb, 0xf8, 0x98, 0x87, 0x25, 0x84, 0xa2, 0xaa, + 0x37, 0xd4, 0xb8, 0xd6, 0x3d, 0xa3, 0xa1, 0x4a, 0x81, 0xc2, 0xa9, 0xea, + 0xa2, 0xd6, 0x63, 0x76, 0x50, 0xeb, 0xcd, 0x19, 0x40, 0xb1, 0x7c, 0xf6, + 0xc1, 0x44, 0x01, 0x25, 0xe0, 0xdd, 0xb8, 0x39, 0xef, 0x46, 0x3d, 0x50, + 0x33, 0xed, 0xb1, 0x63, 0x65, 0xd7, 0x50, 0xe7, 0x95, 0xba, 0xab, 0xa7, + 0x14, 0xe5, 0x60, 0xcb, 0x81, 0x6e, 0x88, 0x3c, 0x06, 0x6e, 0x7d, 0x8e, + 0xe7, 0xbb, 0xa5, 0xc2, 0xbd, 0xae, 0x46, 0x8f, 0x43, 0x04, 0x29, 0xe6, + 0x17, 0x38, 0x05, 0x2d, 0x97, 0x93, 0x5b, 0xf9, 0xef, 0x4d, 0x2e, 0x75, + 0x6c, 0x69, 0xba, 0x08, 0xf2, 0x21, 0x1e, 0x21, 0xe6, 0x8a, 0x5b, 0x8c, + 0xd4, 0x8e, 0xde, 0x64, 0x9b, 0x9d, 0x54, 0x58, 0x65, 0x3e, 0xdd, 0x8a, + 0x1e, 0x81, 0x4e, 0x45, 0xe8, 0xfb, 0x20, 0xc3, 0x3a, 0xf0, 0x50, 0x1e, + 0x8a, 0x18, 0xea, 0x2b, 0xf5, 0xe1, 0xa6, 0xb6, 0xc8, 0xa0, 0x02, 0x3d, + 0x6e, 0xfa, 0x0b, 0x51, 0x95, 0x4e, 0x4c, 0x11, 0xb0, 0xc4, 0x62, 0x58, + 0xa6, 0x9c, 0x13, 0x4e, 0xbe, 0xc9, 0x29, 0x93, 0x29, 0x15, 0x5f, 0xaf, + 0x0e, 0xc3, 0xb3, 0x26, 0x3f, 0xdc, 0x4c, 0x33, 0xb8, 0x4b, 0x11, 0xae, + 0x1f, 0xd7, 0x05, 0x39, 0xcf, 0xfe, 0xc3, 0x6d, 0xf0, 0xc0, 0x77, 0x02, + 0xb8, 0x9b, 0x3d, 0x1b, 0x3d, 0x72, 0xfe, 0x7e, 0x18, 0x60, 0x9b, 0xc4, + 0x8b, 0xac, 0x25, 0x6d, 0x3b, 0x80, 0x34, 0xbc, 0x51, 0xaf, 0xf6, 0xff, + 0x66, 0x98, 0x86, 0x6e, 0x9e, 0x9a, 0xfe, 0x6d, 0x21, 0x4d, 0xf1, 0x58, + 0x3e, 0x3e, 0x43, 0xe3, 0x7e, 0x40, 0xb0, 0xb3, 0xd8, 0x12, 0xa5, 0xce, + 0x09, 0x41, 0x8c, 0x1d, 0x73, 0xcd, 0xfc, 0x63, 0xed, 0xeb, 0x08, 0x1e, + 0x34, 0xfb, 0xed, 0x75, 0xb7, 0x86, 0x84, 0x7c, 0x80, 0xe9, 0xe4, 0xa3, + 0x1c, 0x4a, 0x0d, 0x11, 0x16, 0x24, 0xb2, 0xb1, 0x99, 0xe5, 0xe3, 0x2e, + 0x2f, 0x70, 0xcd, 0x1e, 0x35, 0x14, 0x79, 0xba, 0xa2, 0x51, 0x7a, 0x29, + 0x5c, 0x75, 0x8f, 0xdd, 0x22, 0xdf, 0xb2, 0x64, 0xd9, 0x95, 0x11, 0x33, + 0x97, 0xee, 0x69, 0x42, 0x01, 0x96, 0x98, 0x1b, 0x43, 0xc2, 0xec, 0xf9, + 0xb0, 0xdb, 0x69, 0x34, 0xab, 0x98, 0x1b, 0xb2, 0x04, 0x05, 0x14, 0x1d, + 0x25, 0x2f, 0x32, 0x41, 0x50, 0x51, 0x55, 0x62, 0x6d, 0x78, 0x7f, 0x8b, + 0xbb, 0xc2, 0xcd, 0xcf, 0xe4, 0xed, 0x04, 0x1f, 0x25, 0x30, 0x43, 0x64, + 0x69, 0x7c, 0x87, 0xa3, 0xa9, 0xb1, 0xc1, 0xd1, 0xdc, 0x01, 0x10, 0x1d, + 0x27, 0x3f, 0x5c, 0x5d, 0x75, 0x82, 0x9b, 0xaa, 0xb3, 0xe8, 0x0c, 0x11, + 0x1f, 0x24, 0x38, 0x41, 0x45, 0x54, 0x5f, 0x69, 0x85, 0x8d, 0x93, 0x9e, + 0xc5, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x25, 0x32, 0x42}; +#elif MLD_CONFIG_PARAMETER_SET == 65 +const uint8_t expected_signature[] = { + 0x8b, 0x6f, 0x79, 0x00, 0xcc, 0x79, 0x57, 0xee, 0x16, 0x86, 0x87, 0xd5, + 0xcf, 0xb6, 0x90, 0x2c, 0xc6, 0x30, 0xeb, 0x8d, 0x39, 0xae, 0x9b, 0xf1, + 0x66, 0xe0, 0xd6, 0x93, 0xa5, 0x4e, 0x26, 0x9b, 0x96, 0x8f, 0xd1, 0x46, + 0x97, 0xbe, 0x71, 0x1c, 0xf3, 0xa5, 0xe5, 0xae, 0x8d, 0x4b, 0xf2, 0xe6, + 0x48, 0x8f, 0xe9, 0x5e, 0x07, 0xef, 0xe4, 0xbb, 0x39, 0xc1, 0xc9, 0x3c, + 0xc3, 0x0b, 0xfb, 0x2a, 0x29, 0x06, 0xfe, 0x01, 0xcb, 0x63, 0x83, 0x10, + 0xa8, 0xc8, 0xa0, 0x29, 0xa5, 0x80, 0xeb, 0xbd, 0xa9, 0xd9, 0x0b, 0x61, + 0xbc, 0xce, 0x11, 0x55, 0x66, 0x12, 0xc7, 0x5b, 0xd2, 0x7a, 0x5a, 0xc8, + 0xab, 0xab, 0xbf, 0x3a, 0x1f, 0x96, 0x1a, 0x70, 0xcb, 0x41, 0x5f, 0xc8, + 0xb7, 0x09, 0x22, 0x98, 0x9b, 0xb8, 0xf7, 0x2d, 0x49, 0x65, 0x1d, 0x09, + 0x8b, 0x70, 0xb5, 0x42, 0xc9, 0x89, 0x5b, 0x74, 0xb4, 0x28, 0x82, 0x01, + 0x53, 0x12, 0x3e, 0x23, 0xf6, 0x54, 0xf8, 0x51, 0x12, 0x4b, 0x02, 0x3a, + 0x7e, 0xb6, 0x1f, 0xac, 0xa0, 0xe6, 0x6f, 0xf8, 0x61, 0x82, 0xe4, 0xfb, + 0x96, 0x2a, 0xd2, 0xaf, 0x3c, 0xea, 0x6e, 0xdc, 0x18, 0x8a, 0x5d, 0x90, + 0xda, 0xa2, 0x5d, 0xa7, 0x8f, 0x5b, 0x50, 0x46, 0xaf, 0x8c, 0x17, 0x6a, + 0x4c, 0x39, 0xfc, 0x31, 0x4c, 0x4b, 0xc2, 0x57, 0x66, 0x61, 0x98, 0xbf, + 0xe6, 0xfb, 0x54, 0x96, 0xd3, 0x70, 0xb8, 0xaf, 0xcd, 0x8b, 0xcc, 0x00, + 0x07, 0x92, 0x15, 0xc2, 0xbb, 0x48, 0xbb, 0xc6, 0xb7, 0xb5, 0x58, 0x8c, + 0xfc, 0xf0, 0xda, 0x6a, 0x0d, 0xf7, 0x1d, 0x7d, 0xc6, 0x27, 0x26, 0x1a, + 0x99, 0xc5, 0x2f, 0xf8, 0x97, 0x65, 0x43, 0x86, 0xd6, 0x25, 0x23, 0x2b, + 0x06, 0x8f, 0x12, 0xa1, 0xae, 0xbb, 0x58, 0x34, 0x25, 0xec, 0x5b, 0x68, + 0xa4, 0xe1, 0x03, 0xfc, 0x26, 0xa2, 0xd6, 0x2b, 0x61, 0x10, 0x47, 0xbd, + 0x16, 0xe5, 0xca, 0x4a, 0xce, 0xed, 0x89, 0x09, 0x1a, 0xed, 0x22, 0xc1, + 0xca, 0x44, 0xe3, 0xef, 0x72, 0x34, 0xab, 0xab, 0x61, 0x5c, 0x9f, 0x5f, + 0xb5, 0xf5, 0xe8, 0x2d, 0x89, 0xea, 0x4b, 0x40, 0x65, 0x57, 0x8b, 0xa2, + 0x95, 0x40, 0x9c, 0x72, 0xc0, 0x46, 0x69, 0x45, 0x06, 0xf6, 0x07, 0x5b, + 0x2d, 0xa5, 0x46, 0xca, 0x5d, 0xfb, 0x40, 0xb7, 0x48, 0x59, 0x5b, 0xe2, + 0x1b, 0x38, 0xb2, 0x15, 0x75, 0x66, 0x67, 0x58, 0x00, 0x3f, 0xde, 0x8a, + 0x63, 0x13, 0x34, 0x6a, 0x30, 0xca, 0xb4, 0xd5, 0x3e, 0xe0, 0x6d, 0x14, + 0xb8, 0x9a, 0x48, 0xef, 0xfd, 0xbd, 0x6d, 0x20, 0x11, 0x4d, 0x25, 0xe5, + 0xab, 0x15, 0x8d, 0xe5, 0x91, 0xbc, 0xc6, 0x69, 0x8a, 0xf8, 0xab, 0x3a, + 0x82, 0xae, 0xc5, 0x03, 0x2c, 0xcf, 0x54, 0xdc, 0xcd, 0xe8, 0x49, 0x53, + 0xb5, 0xd8, 0xc2, 0x24, 0xf8, 0x8c, 0x38, 0x8f, 0xe3, 0xfe, 0x3a, 0x18, + 0x15, 0xa8, 0xda, 0x77, 0xc8, 0x81, 0x72, 0xc6, 0xc1, 0x60, 0xa3, 0x73, + 0x65, 0x68, 0x5c, 0xf3, 0x1d, 0x8d, 0x61, 0x21, 0x65, 0xfb, 0x45, 0xc4, + 0x4c, 0x31, 0x88, 0x25, 0x0d, 0x52, 0x75, 0x3b, 0xec, 0x54, 0xe0, 0xb1, + 0x9c, 0x7c, 0xdf, 0xe3, 0x3b, 0x77, 0x31, 0x33, 0xd7, 0x25, 0x99, 0xff, + 0xc5, 0x40, 0x1e, 0x85, 0x09, 0xfd, 0x2d, 0x24, 0x4a, 0x92, 0xe7, 0x77, + 0x48, 0xa5, 0x46, 0xf4, 0x8e, 0xa3, 0x6b, 0x24, 0xe4, 0x6b, 0x31, 0xf6, + 0xe0, 0x16, 0x49, 0x9b, 0x9f, 0xa3, 0x1a, 0x5c, 0x05, 0x5e, 0x81, 0x62, + 0xc8, 0x14, 0x52, 0xb4, 0x21, 0xfd, 0x76, 0x6d, 0x88, 0xe9, 0x3b, 0x0b, + 0x75, 0x27, 0x92, 0x47, 0x5a, 0x58, 0x08, 0x26, 0xa7, 0xa2, 0x48, 0x1c, + 0x14, 0x3e, 0x5e, 0xdf, 0x81, 0x83, 0x83, 0x3e, 0xc6, 0x72, 0x27, 0xc4, + 0x6a, 0x46, 0x2b, 0xf2, 0x8d, 0x42, 0x11, 0xb9, 0x15, 0xd7, 0xf0, 0x20, + 0x29, 0x53, 0xba, 0xf0, 0x6e, 0x41, 0x3d, 0xee, 0x19, 0xf2, 0x43, 0xf3, + 0x6d, 0x00, 0xe2, 0x43, 0x77, 0xb9, 0xa9, 0x78, 0x34, 0x48, 0x3c, 0x1a, + 0x8b, 0xbd, 0xa1, 0xe5, 0x90, 0x59, 0x5b, 0xd6, 0x1e, 0x22, 0xdf, 0xb2, + 0xa7, 0x96, 0x7d, 0x55, 0x86, 0x66, 0x95, 0xb7, 0x06, 0xe7, 0x60, 0x2a, + 0x01, 0x48, 0x3f, 0xd4, 0xa7, 0xd4, 0xc2, 0x38, 0xa4, 0x10, 0x8e, 0x4f, + 0x97, 0xad, 0xa3, 0xb9, 0xe2, 0xaa, 0x13, 0xb1, 0x16, 0x89, 0x3d, 0x74, + 0x60, 0x94, 0x8c, 0xc3, 0xe6, 0x5f, 0xcf, 0xdc, 0x58, 0x17, 0x98, 0x27, + 0x86, 0xae, 0x2a, 0x0d, 0xe8, 0x33, 0x79, 0xc8, 0xc8, 0x5b, 0x59, 0xb0, + 0xba, 0xac, 0xd3, 0x6e, 0x2d, 0x7b, 0x0b, 0x9a, 0xb5, 0xfd, 0x58, 0x42, + 0xeb, 0x80, 0xf4, 0x6b, 0x9a, 0x2f, 0x19, 0x43, 0x75, 0xb4, 0xcb, 0xc9, + 0xd5, 0x28, 0xf5, 0xb9, 0x67, 0x82, 0xb4, 0xed, 0x8c, 0x3f, 0x3d, 0x6b, + 0x6d, 0x1b, 0x80, 0x13, 0x5c, 0x7b, 0x2e, 0xfa, 0xa0, 0x32, 0xba, 0xb5, + 0x46, 0xd6, 0xe7, 0x90, 0xe9, 0xd1, 0x91, 0xa0, 0xaa, 0x26, 0x35, 0xa2, + 0x0d, 0x98, 0x44, 0x11, 0xae, 0xf9, 0xc5, 0x12, 0x4d, 0x1a, 0x7c, 0x53, + 0xea, 0xf6, 0x05, 0x8d, 0x3a, 0x74, 0x92, 0xc9, 0x65, 0xeb, 0x6f, 0xb5, + 0xb4, 0xd2, 0xcd, 0x5c, 0xec, 0xaf, 0x95, 0xcb, 0xb4, 0x3c, 0x22, 0xca, + 0x1c, 0x06, 0x85, 0x16, 0x96, 0x24, 0x8c, 0x6c, 0x80, 0xf8, 0xb3, 0xa7, + 0x87, 0x77, 0xeb, 0x09, 0x71, 0xc8, 0x95, 0xfb, 0x5e, 0xe5, 0x6f, 0x78, + 0xf9, 0x60, 0xf9, 0x9e, 0x58, 0x7b, 0xbd, 0x47, 0xdd, 0x48, 0x2e, 0x56, + 0xcd, 0x63, 0x72, 0xc9, 0x4b, 0x65, 0x2d, 0x41, 0xe8, 0x81, 0x19, 0x33, + 0x4b, 0xf6, 0x02, 0xc6, 0xcb, 0x2e, 0xdf, 0x3d, 0xc8, 0xdd, 0x2f, 0x0f, + 0x09, 0x67, 0xf0, 0xaa, 0x3c, 0x51, 0xdc, 0x8d, 0xc6, 0xc3, 0xb2, 0x3b, + 0x15, 0x85, 0xcb, 0xeb, 0x62, 0xef, 0xa3, 0xf9, 0x94, 0xf4, 0x35, 0x9c, + 0x59, 0xcc, 0xc2, 0x68, 0xb4, 0xde, 0x02, 0x75, 0x8e, 0xf5, 0x33, 0xca, + 0xd5, 0xc5, 0x24, 0xae, 0xf6, 0xde, 0x2b, 0x01, 0xf4, 0x56, 0xb9, 0xa5, + 0xa7, 0xe0, 0x64, 0x2e, 0xba, 0x1d, 0x53, 0x54, 0x46, 0xcf, 0x64, 0x16, + 0x12, 0xe2, 0xa6, 0xcc, 0x18, 0xb4, 0x77, 0x8b, 0x19, 0x50, 0x43, 0x96, + 0xc8, 0x5d, 0xc3, 0x58, 0xf0, 0xfd, 0x5e, 0x13, 0xa9, 0x10, 0x67, 0xdf, + 0x25, 0xdb, 0xaf, 0x38, 0x5f, 0xbd, 0x35, 0xc1, 0x49, 0x44, 0xe8, 0x1f, + 0x12, 0xa4, 0x7c, 0x28, 0xa3, 0xd6, 0x0d, 0x6f, 0x44, 0xa9, 0x5f, 0xfc, + 0x9f, 0xfa, 0x11, 0x62, 0x87, 0x5b, 0x0e, 0x91, 0xd4, 0xb6, 0xd3, 0x71, + 0xc2, 0x77, 0x19, 0xf6, 0x7c, 0x11, 0x30, 0x5e, 0x5c, 0xd3, 0x1e, 0x90, + 0x05, 0x31, 0x63, 0xbb, 0xef, 0x85, 0xe0, 0x27, 0x94, 0x80, 0xcb, 0x33, + 0xbc, 0x5e, 0x45, 0x87, 0x62, 0xdf, 0xd4, 0x12, 0x2f, 0xf5, 0x41, 0x15, + 0x03, 0x0c, 0x80, 0xe8, 0xe2, 0x06, 0xde, 0x4b, 0x46, 0x70, 0x94, 0xd2, + 0x0d, 0x85, 0x72, 0x27, 0xe5, 0x6c, 0xeb, 0xd2, 0x78, 0x0b, 0x38, 0x40, + 0xe8, 0xdb, 0x47, 0x5c, 0xba, 0xd0, 0x21, 0x33, 0x8f, 0xb8, 0xc0, 0x66, + 0x1e, 0xd1, 0xb0, 0x94, 0xa3, 0x39, 0xc7, 0x87, 0xaf, 0x97, 0x98, 0xce, + 0x6d, 0x03, 0x1a, 0xdb, 0x52, 0x96, 0x0b, 0x9d, 0x5b, 0xf8, 0xa3, 0xf4, + 0x41, 0x95, 0x72, 0xad, 0x0e, 0x98, 0x61, 0x7f, 0xf3, 0x8f, 0x23, 0xeb, + 0xc0, 0xdf, 0xd7, 0x70, 0x26, 0x8c, 0xb3, 0xb3, 0xf0, 0xa2, 0x8a, 0x39, + 0xdd, 0x61, 0xb4, 0x53, 0xe0, 0x2a, 0x6f, 0x91, 0x34, 0x9c, 0x76, 0xf6, + 0x52, 0x93, 0xe6, 0x39, 0xb7, 0x54, 0x07, 0x46, 0x82, 0x2d, 0x05, 0x6d, + 0x9a, 0x00, 0x53, 0x65, 0x68, 0x93, 0x91, 0x00, 0xda, 0xe0, 0x93, 0x34, + 0x60, 0xb1, 0x93, 0x0b, 0x64, 0xa8, 0x12, 0xd2, 0x51, 0x3c, 0xdb, 0xb0, + 0x4c, 0x39, 0x4e, 0xce, 0xbd, 0xf0, 0x65, 0x12, 0x8a, 0xd4, 0x80, 0x7d, + 0x82, 0x85, 0xe4, 0x92, 0xc2, 0x77, 0x1e, 0xcf, 0xd9, 0xab, 0x0f, 0x9b, + 0x32, 0x2e, 0x3f, 0xe1, 0x0e, 0x87, 0x1c, 0x87, 0x34, 0xe7, 0x93, 0x16, + 0x95, 0x09, 0x7d, 0x24, 0xa8, 0xb5, 0xe0, 0x9f, 0x23, 0x87, 0x5c, 0x0b, + 0x31, 0x4a, 0x2f, 0xe2, 0x5c, 0x82, 0x49, 0x51, 0xe4, 0x93, 0xcb, 0x05, + 0x23, 0x4f, 0x8a, 0x83, 0x88, 0xfb, 0x89, 0xb0, 0x08, 0xd6, 0x64, 0xad, + 0x51, 0x84, 0x40, 0x29, 0xb1, 0xca, 0x74, 0x26, 0x29, 0x5a, 0x61, 0x01, + 0x2e, 0xa0, 0xeb, 0xeb, 0x02, 0xb5, 0xff, 0xd8, 0x20, 0x6a, 0x5e, 0x8d, + 0x17, 0x1e, 0xa3, 0xd7, 0x2f, 0x20, 0x0b, 0x93, 0x17, 0x24, 0xf7, 0x90, + 0x7b, 0xc6, 0xba, 0xd8, 0xf9, 0xe9, 0x0a, 0x2a, 0x7a, 0x81, 0x23, 0x81, + 0x03, 0x6f, 0x1e, 0x0d, 0x87, 0x83, 0xd1, 0xcf, 0x92, 0x2f, 0x19, 0x82, + 0x4e, 0x6c, 0x0a, 0x02, 0xb6, 0x70, 0xbc, 0xe1, 0x58, 0xe7, 0x16, 0xdb, + 0x2f, 0x74, 0x9f, 0xe1, 0xc2, 0x1e, 0x64, 0xc6, 0x48, 0x08, 0xee, 0xea, + 0x52, 0x9a, 0xce, 0x2c, 0xc5, 0x0c, 0x7a, 0x63, 0xf1, 0x6a, 0xbd, 0x2c, + 0x8b, 0xd5, 0x4a, 0xfa, 0x1e, 0xab, 0x9a, 0x5b, 0x25, 0xb8, 0xfa, 0x0a, + 0xe9, 0x68, 0x80, 0x6f, 0x80, 0x57, 0x10, 0x54, 0xb8, 0xa2, 0x16, 0xbd, + 0xfe, 0xf7, 0xea, 0x01, 0xc7, 0x94, 0x5a, 0x95, 0xe3, 0x61, 0xa5, 0x49, + 0x84, 0xf5, 0x79, 0x78, 0xb5, 0x0a, 0x96, 0xca, 0x01, 0x1b, 0xd0, 0x0b, + 0x51, 0x30, 0xd3, 0x48, 0xfc, 0x4d, 0x50, 0x71, 0x09, 0x73, 0xea, 0x37, + 0xcd, 0x9d, 0x3d, 0xde, 0x30, 0x56, 0x21, 0xf0, 0xef, 0x84, 0xad, 0x27, + 0xe1, 0x83, 0xdb, 0xfb, 0xcd, 0x11, 0xb2, 0xbd, 0x30, 0x67, 0x8a, 0x88, + 0x09, 0x0e, 0x9d, 0x96, 0x09, 0xba, 0xda, 0x9d, 0xf0, 0xe9, 0xb4, 0xa6, + 0x7a, 0x04, 0xf9, 0x4b, 0xb8, 0x51, 0xa9, 0x99, 0xf3, 0xbb, 0x77, 0x95, + 0x0a, 0xa1, 0xa6, 0xa1, 0x24, 0xfc, 0xcc, 0x45, 0xe8, 0x83, 0xc8, 0x6f, + 0x48, 0xad, 0x9a, 0x73, 0xd0, 0xe0, 0x57, 0x7d, 0xe4, 0x78, 0x65, 0xef, + 0xae, 0xc2, 0xfe, 0x7a, 0x56, 0xaf, 0x03, 0x71, 0x2b, 0xe6, 0xa1, 0x7e, + 0xe5, 0x12, 0xf8, 0xc3, 0x75, 0xc7, 0x22, 0x5f, 0x1b, 0x52, 0x90, 0xe5, + 0xdf, 0xba, 0x9d, 0xe2, 0x68, 0xe0, 0xb3, 0x7a, 0x9e, 0x14, 0xff, 0xb5, + 0x0a, 0x80, 0x20, 0x49, 0x88, 0xe9, 0x9c, 0xe4, 0xb5, 0xaf, 0x7e, 0x51, + 0xec, 0xe7, 0xfc, 0x64, 0x65, 0x21, 0x10, 0xc6, 0x1f, 0x7f, 0x93, 0x7d, + 0xd8, 0xf5, 0xd0, 0x98, 0x94, 0x44, 0xf8, 0x49, 0x6a, 0x51, 0x0a, 0x54, + 0xf4, 0x9f, 0xee, 0x3c, 0x56, 0xbf, 0x4c, 0xe4, 0xde, 0x1c, 0x9b, 0x11, + 0x7e, 0x9a, 0x71, 0x11, 0x80, 0x33, 0xd5, 0xb0, 0x9b, 0xef, 0x67, 0x29, + 0xa4, 0x7d, 0x70, 0x31, 0x3f, 0x8b, 0x2e, 0x4a, 0x0f, 0x2c, 0x91, 0x3d, + 0x3e, 0x3d, 0x8c, 0x0a, 0x2b, 0xf1, 0xdd, 0xbf, 0x61, 0xe6, 0xa3, 0xef, + 0x6d, 0x82, 0xc8, 0xb7, 0x5e, 0x2b, 0x83, 0xc9, 0x4e, 0xa0, 0x85, 0x7f, + 0x01, 0x5a, 0xca, 0x6e, 0x90, 0xfa, 0x7e, 0x82, 0x4d, 0x35, 0x7e, 0xe0, + 0x26, 0x40, 0xf4, 0xa6, 0xae, 0xc3, 0x89, 0xf3, 0xca, 0x55, 0x2c, 0xb5, + 0x29, 0x05, 0x94, 0x45, 0xa7, 0x45, 0xf3, 0x3d, 0xbb, 0x53, 0x5e, 0xca, + 0x7c, 0x84, 0x8f, 0x72, 0x98, 0x93, 0x90, 0x1f, 0x56, 0x72, 0xdb, 0xbd, + 0xa9, 0xeb, 0xf9, 0xe9, 0xce, 0xb1, 0x41, 0xc3, 0xaa, 0xa0, 0xc4, 0x74, + 0x23, 0xc1, 0xeb, 0x7d, 0x41, 0xcd, 0xa4, 0x62, 0xec, 0xfc, 0x9a, 0xa4, + 0x16, 0xec, 0x67, 0x41, 0x89, 0xf0, 0x0e, 0xf3, 0xd1, 0xa2, 0x2f, 0xba, + 0x5d, 0x93, 0x36, 0x46, 0xf5, 0x52, 0x64, 0x91, 0xe7, 0x40, 0x91, 0x20, + 0xa1, 0xc9, 0xaa, 0x4c, 0x79, 0xc4, 0xbb, 0x67, 0x79, 0xad, 0x43, 0xab, + 0xba, 0xde, 0xfc, 0xf1, 0x74, 0x81, 0x33, 0xc0, 0x3f, 0x39, 0xd1, 0xd1, + 0xdf, 0xc0, 0x53, 0x33, 0xb2, 0x92, 0x37, 0xe6, 0x86, 0x2a, 0xe4, 0xe1, + 0x7c, 0x98, 0xf7, 0xdb, 0x5c, 0xa9, 0xff, 0x8d, 0x9c, 0xab, 0xe2, 0xf2, + 0xd5, 0xb1, 0x42, 0xa9, 0xf4, 0x97, 0x80, 0xcd, 0xde, 0x25, 0x2e, 0x87, + 0x92, 0xdd, 0xcf, 0xed, 0x67, 0x93, 0x8c, 0x5a, 0x1d, 0xee, 0xcf, 0x9d, + 0x50, 0x8f, 0xa7, 0xe3, 0x5c, 0xa3, 0x68, 0x78, 0x24, 0xeb, 0x60, 0xa3, + 0x8b, 0x36, 0xbb, 0xcb, 0x46, 0xee, 0x77, 0xfb, 0xf8, 0x69, 0x24, 0xd1, + 0xfa, 0xad, 0x76, 0x76, 0x5e, 0x54, 0xe5, 0xb6, 0x36, 0xc6, 0xdd, 0xa9, + 0x6c, 0x44, 0x15, 0xf7, 0x0a, 0xf8, 0xbb, 0xba, 0xec, 0x35, 0xff, 0xc9, + 0xd6, 0x5d, 0xf5, 0x73, 0x4a, 0x15, 0x8f, 0x7b, 0x6e, 0xf4, 0xa0, 0x6d, + 0x10, 0xbb, 0x67, 0x0c, 0xb4, 0x69, 0xad, 0xb6, 0x40, 0xf7, 0x5f, 0x37, + 0x28, 0xc4, 0x08, 0x49, 0xd0, 0x16, 0x70, 0x80, 0xea, 0x55, 0x66, 0x07, + 0xc8, 0x03, 0x1b, 0xf6, 0xd3, 0x03, 0x04, 0x74, 0xe0, 0x50, 0x3f, 0xd2, + 0x53, 0x92, 0xa0, 0x9d, 0x59, 0xc9, 0x74, 0xf2, 0x7e, 0x3b, 0x33, 0x02, + 0x10, 0x0b, 0x39, 0xf7, 0x4f, 0x6b, 0x58, 0xb2, 0x1a, 0xda, 0x65, 0x44, + 0xd1, 0x7c, 0x3f, 0xd7, 0xe3, 0xac, 0xe2, 0x1f, 0x38, 0xc1, 0x6a, 0xb0, + 0xdc, 0xc3, 0x9c, 0x7b, 0x11, 0x3c, 0x05, 0x21, 0x96, 0x76, 0x98, 0x76, + 0x82, 0xc1, 0x54, 0xdf, 0xdc, 0x8f, 0x4c, 0xd2, 0x63, 0x04, 0x06, 0x77, + 0x36, 0xe6, 0x2e, 0xd1, 0x00, 0x28, 0x42, 0x7c, 0x4a, 0x27, 0x90, 0x46, + 0xc9, 0xce, 0x33, 0x1c, 0xae, 0xda, 0x79, 0x64, 0x7f, 0x52, 0x3f, 0x58, + 0x11, 0x76, 0x4a, 0xb6, 0x72, 0xd8, 0x76, 0xae, 0xfd, 0x5c, 0x57, 0x69, + 0x76, 0x91, 0x84, 0x21, 0xc4, 0x9b, 0xd8, 0xa2, 0xff, 0x93, 0x02, 0x77, + 0x61, 0x57, 0x96, 0x7b, 0x8e, 0xfc, 0xf2, 0x6c, 0x11, 0x2b, 0x5e, 0x88, + 0x5c, 0x17, 0x1d, 0x12, 0x79, 0x3a, 0x78, 0xb6, 0x9d, 0x70, 0xfa, 0xd4, + 0xc1, 0x5c, 0x90, 0x0e, 0x0a, 0xd1, 0x3c, 0x7d, 0xcf, 0xee, 0x8a, 0xb2, + 0xb2, 0x4d, 0xce, 0x89, 0x32, 0xa9, 0x6c, 0x56, 0x57, 0x85, 0xb1, 0xbf, + 0x18, 0x1d, 0xc6, 0xe1, 0x17, 0xc5, 0x92, 0x42, 0x99, 0xf9, 0x9f, 0x04, + 0xec, 0x38, 0xf8, 0xa0, 0xd2, 0xab, 0xe6, 0x13, 0x4d, 0x9c, 0x18, 0x86, + 0x3e, 0x18, 0x73, 0x2c, 0xac, 0xe0, 0xb9, 0xf9, 0x87, 0x74, 0xb8, 0xd7, + 0x47, 0x6e, 0x42, 0xfc, 0x29, 0xa0, 0x1f, 0x56, 0x68, 0xb6, 0x23, 0x96, + 0xa2, 0x8d, 0x54, 0x81, 0x0f, 0x60, 0xb9, 0xde, 0x93, 0xfc, 0xfd, 0xde, + 0xbe, 0xb3, 0xb5, 0x87, 0xec, 0x9f, 0x17, 0xc2, 0x77, 0x6e, 0xa0, 0x62, + 0xdb, 0x66, 0xba, 0xc5, 0x05, 0x12, 0x46, 0x5d, 0x3c, 0x23, 0x29, 0x68, + 0xe5, 0x31, 0xe3, 0x15, 0xec, 0xac, 0x15, 0x9a, 0xbf, 0x42, 0x65, 0x80, + 0x45, 0x9c, 0x1d, 0xc2, 0x0e, 0x18, 0x47, 0x40, 0x44, 0xc1, 0x55, 0x24, + 0x5a, 0x35, 0xad, 0x59, 0xd2, 0xc6, 0xc3, 0x68, 0x58, 0xbd, 0x6f, 0xcf, + 0x5d, 0xb1, 0x9b, 0x0c, 0x92, 0x39, 0x22, 0x49, 0x66, 0x2e, 0x03, 0x7b, + 0x75, 0x5c, 0x6c, 0xde, 0x37, 0x54, 0xa9, 0x07, 0x2f, 0x7e, 0xc1, 0x3e, + 0x3b, 0xab, 0xd2, 0xa9, 0xfa, 0xc7, 0x6b, 0xd5, 0x14, 0x08, 0x35, 0x89, + 0x0b, 0x31, 0x18, 0x54, 0x7d, 0x6b, 0x53, 0x80, 0x6e, 0x32, 0x9b, 0xff, + 0x61, 0x7f, 0x36, 0xe5, 0x28, 0x40, 0xbc, 0xc7, 0x19, 0xb3, 0xae, 0xfa, + 0x95, 0xa8, 0xae, 0xd2, 0x97, 0x72, 0xc6, 0x91, 0x36, 0x3a, 0xa6, 0xec, + 0x4a, 0x41, 0x63, 0x6b, 0x28, 0xef, 0x5a, 0xa1, 0xdb, 0xf2, 0xd9, 0xfd, + 0x61, 0x72, 0xa4, 0xd2, 0x9e, 0xf7, 0x47, 0xf4, 0x4e, 0xea, 0x2a, 0xa5, + 0x35, 0xe1, 0x77, 0x3a, 0x53, 0x28, 0xa6, 0x55, 0x48, 0x0c, 0x1e, 0x44, + 0xfc, 0xc1, 0x31, 0x5a, 0x00, 0xcd, 0x29, 0xc1, 0x5c, 0xca, 0x2a, 0x07, + 0x01, 0x63, 0xac, 0xb3, 0xfb, 0xf6, 0x0b, 0xac, 0xfd, 0xe8, 0x7b, 0xed, + 0xf9, 0x3d, 0x9a, 0xbc, 0x67, 0x28, 0x1c, 0xd9, 0x3f, 0x97, 0x28, 0x4a, + 0xe7, 0xd0, 0x08, 0xe9, 0x3e, 0xa0, 0xcb, 0x0f, 0xe0, 0x3f, 0x1b, 0x80, + 0x43, 0x74, 0xd9, 0x9d, 0x0b, 0x22, 0x81, 0xf7, 0xec, 0x71, 0x2a, 0x29, + 0x9e, 0x5d, 0x1e, 0x8d, 0xf4, 0x22, 0x95, 0x78, 0x86, 0xcb, 0xf0, 0x9d, + 0xe7, 0x6a, 0x66, 0x7e, 0x28, 0xb5, 0x47, 0xb6, 0xdc, 0x0d, 0x03, 0x3c, + 0x09, 0x58, 0x76, 0x93, 0x39, 0xb2, 0xd3, 0x75, 0xb4, 0x51, 0x55, 0x84, + 0x30, 0x24, 0x0a, 0x76, 0xf4, 0x97, 0xe7, 0x0f, 0x5a, 0x67, 0xee, 0xf4, + 0xc7, 0x69, 0x8d, 0xf2, 0x32, 0x29, 0x5c, 0x33, 0x82, 0x5f, 0x6c, 0x47, + 0xd0, 0xe2, 0xbd, 0x62, 0xd6, 0x4c, 0x6d, 0x0d, 0xba, 0x87, 0xd3, 0x43, + 0x7e, 0x2d, 0xa6, 0x14, 0x09, 0x4f, 0x3b, 0xc3, 0x04, 0x14, 0xe5, 0x65, + 0xe9, 0x3b, 0x6a, 0xca, 0xb5, 0x96, 0x84, 0x3f, 0x53, 0x49, 0x22, 0x45, + 0x91, 0xff, 0xf9, 0x26, 0x75, 0x0d, 0x9c, 0xa7, 0x00, 0xf4, 0x65, 0xc4, + 0x60, 0x72, 0xab, 0xeb, 0xf8, 0xa8, 0x72, 0xfe, 0xd8, 0xde, 0x93, 0x67, + 0xcb, 0x09, 0xcc, 0xa0, 0xce, 0x9f, 0x67, 0x63, 0x26, 0xfa, 0x7f, 0x89, + 0xaa, 0x3e, 0x6d, 0xb2, 0x90, 0xd7, 0xef, 0x3e, 0x2a, 0x66, 0x26, 0x33, + 0xe6, 0x26, 0xc1, 0x58, 0xf8, 0x91, 0xea, 0x2f, 0xd0, 0x84, 0x21, 0x41, + 0x93, 0xa6, 0x36, 0x40, 0xb5, 0x4c, 0xac, 0x21, 0x88, 0x37, 0x47, 0x8a, + 0xb8, 0xf3, 0x33, 0x73, 0x12, 0xd7, 0x5a, 0x55, 0xf9, 0xd1, 0x1e, 0x75, + 0xa4, 0x66, 0x68, 0x3f, 0xf7, 0xb2, 0xc4, 0x5d, 0x1b, 0xb1, 0x61, 0x0f, + 0xaf, 0x4b, 0x9b, 0x20, 0x2b, 0x05, 0x68, 0x1c, 0x6c, 0x97, 0x8d, 0xb8, + 0x7b, 0x96, 0xda, 0xe0, 0x67, 0x15, 0x4c, 0x51, 0x71, 0x0d, 0xd3, 0x7b, + 0xde, 0xaa, 0xd3, 0x58, 0xf5, 0xc9, 0x62, 0x0a, 0xc2, 0x33, 0x1f, 0xf3, + 0xc3, 0x30, 0xb5, 0x64, 0xd1, 0x59, 0x41, 0x0e, 0xae, 0xaa, 0x0d, 0xdf, + 0x9f, 0x5d, 0x3f, 0x15, 0x0d, 0x46, 0x7a, 0x6d, 0x2e, 0x29, 0x1b, 0xc0, + 0xd3, 0x11, 0x10, 0x5d, 0xdc, 0x6a, 0x35, 0x8c, 0x43, 0xc8, 0x9f, 0x05, + 0x80, 0xdc, 0x25, 0x24, 0x37, 0x70, 0x7e, 0x1c, 0xe9, 0x85, 0x5a, 0xef, + 0x83, 0x3a, 0x55, 0x68, 0x83, 0x17, 0xf4, 0xc7, 0xae, 0xe4, 0x84, 0xc9, + 0x64, 0x5d, 0x2f, 0xb6, 0xca, 0x10, 0x95, 0xb8, 0xd6, 0x80, 0xfd, 0x05, + 0xa5, 0x06, 0x32, 0x34, 0x91, 0x01, 0xd2, 0x02, 0x90, 0xe1, 0xf7, 0x89, + 0x8a, 0xee, 0x18, 0x04, 0x93, 0xd9, 0xb4, 0x63, 0x4b, 0xf7, 0x7a, 0x9c, + 0x1b, 0x4b, 0xf9, 0x31, 0x32, 0xd9, 0xf2, 0x55, 0x4e, 0xc1, 0x02, 0xce, + 0x77, 0x38, 0x36, 0x29, 0xb8, 0x54, 0x8c, 0xc2, 0x27, 0x5f, 0xd9, 0xae, + 0x3e, 0x1e, 0xcd, 0xe9, 0x07, 0x90, 0x4c, 0xe0, 0xda, 0x16, 0x6e, 0xdf, + 0xde, 0x3a, 0x61, 0x89, 0x9f, 0x79, 0xd0, 0xd4, 0x66, 0x95, 0xad, 0xe4, + 0x11, 0x7d, 0xa1, 0xae, 0xec, 0x3e, 0x6e, 0x20, 0x5a, 0xd0, 0x28, 0x0e, + 0x55, 0xec, 0xcf, 0x34, 0xec, 0xb7, 0xfc, 0xa4, 0xb3, 0x8f, 0x56, 0x13, + 0x50, 0xcc, 0x15, 0x10, 0x74, 0x40, 0x72, 0x42, 0x20, 0x22, 0xb3, 0xaf, + 0xf3, 0x68, 0xba, 0x95, 0x45, 0xcb, 0xef, 0x92, 0xd5, 0x14, 0x4c, 0x1f, + 0xe3, 0xc1, 0xa6, 0x03, 0x4e, 0x05, 0xd2, 0x1a, 0xee, 0xd2, 0x48, 0x44, + 0x2e, 0x50, 0x3b, 0x86, 0xc8, 0x6a, 0xc8, 0x4c, 0xca, 0x2a, 0xb6, 0xf7, + 0x3c, 0xaf, 0xdc, 0x62, 0xb1, 0x49, 0x13, 0xfe, 0xe7, 0x32, 0xea, 0x78, + 0xfa, 0xba, 0xcf, 0x15, 0x47, 0x58, 0xdc, 0x19, 0x73, 0x1d, 0xff, 0xbd, + 0xcc, 0x27, 0xf6, 0xfc, 0x66, 0x68, 0xa7, 0x29, 0xaf, 0x2b, 0x25, 0x0c, + 0x15, 0x47, 0xff, 0xc1, 0x00, 0x9d, 0xfa, 0x58, 0x9c, 0xaa, 0xf9, 0xcc, + 0x4c, 0x51, 0x1d, 0xda, 0xf3, 0x3c, 0x10, 0xd0, 0x3b, 0x59, 0x30, 0x02, + 0x68, 0x29, 0x1c, 0xa7, 0x22, 0xea, 0x81, 0xd3, 0x29, 0x71, 0x39, 0xe8, + 0x72, 0x7f, 0x7d, 0x94, 0x0a, 0x64, 0x2c, 0xe6, 0x55, 0xfb, 0x90, 0x78, + 0x7e, 0x6c, 0x3e, 0xfe, 0x57, 0x14, 0x61, 0xef, 0xe2, 0x63, 0x57, 0x6c, + 0x13, 0x97, 0x27, 0x2b, 0x38, 0x44, 0xab, 0x74, 0x76, 0x11, 0xa6, 0x60, + 0xad, 0x8e, 0xad, 0xe5, 0xa5, 0xa1, 0x66, 0xc5, 0xe1, 0x4d, 0x27, 0xa0, + 0x79, 0x7a, 0x09, 0xe6, 0xf0, 0x28, 0x3f, 0xcb, 0xc6, 0xf8, 0x94, 0xc0, + 0xf1, 0x13, 0xbe, 0x62, 0x6a, 0x52, 0x75, 0x52, 0xd3, 0x82, 0x31, 0xbd, + 0x15, 0xf2, 0xe8, 0x2e, 0xb1, 0x62, 0x03, 0x1e, 0xe2, 0xb3, 0xec, 0xbc, + 0x3c, 0x12, 0xca, 0x62, 0x4e, 0xc2, 0x3a, 0x51, 0x1c, 0xdf, 0xa2, 0x84, + 0x88, 0xe5, 0x7e, 0xd7, 0x5d, 0xd7, 0xbf, 0xf2, 0x7d, 0xbd, 0x9a, 0x90, + 0x63, 0xfd, 0x8a, 0x84, 0x2b, 0x9d, 0x89, 0x27, 0x63, 0x4c, 0x0a, 0xe3, + 0x70, 0x94, 0x7b, 0xe6, 0xb3, 0xd7, 0xcb, 0xcb, 0x8a, 0xeb, 0x6b, 0x53, + 0x34, 0x2f, 0x62, 0x44, 0x2d, 0x73, 0x63, 0x8a, 0xf4, 0xa2, 0x01, 0xd7, + 0x12, 0xb6, 0x8d, 0x8c, 0x4b, 0x73, 0x2b, 0x44, 0x50, 0x49, 0x6f, 0x01, + 0xac, 0xc5, 0x15, 0x37, 0x6c, 0xde, 0xd4, 0x02, 0xb1, 0x12, 0x80, 0x73, + 0xb2, 0x52, 0x0e, 0xe0, 0xb5, 0x75, 0xc9, 0x48, 0xcf, 0x18, 0x5c, 0xcc, + 0xaf, 0x58, 0xa2, 0x3e, 0x28, 0xe4, 0xab, 0xde, 0xea, 0x2a, 0xcf, 0x58, + 0x22, 0xc4, 0x68, 0xea, 0x9b, 0x7b, 0x90, 0xc5, 0xdc, 0x1c, 0x37, 0xd1, + 0x8a, 0x4f, 0xe7, 0x24, 0x23, 0x39, 0xb9, 0x62, 0xb8, 0x41, 0x13, 0x7b, + 0xe2, 0x1e, 0x0d, 0x4e, 0x38, 0x11, 0xa3, 0xb9, 0x10, 0xbb, 0x10, 0x6f, + 0x40, 0x9f, 0x50, 0x05, 0xc7, 0x0e, 0xb9, 0x9e, 0xab, 0x7c, 0x3c, 0x78, + 0xce, 0x54, 0xbf, 0xbf, 0x40, 0x36, 0x76, 0xbc, 0x4b, 0x64, 0x32, 0xca, + 0x0e, 0x2d, 0x91, 0x87, 0xd5, 0x00, 0x19, 0xbf, 0x12, 0xd0, 0x35, 0x7c, + 0xa1, 0xe5, 0xcf, 0x7a, 0x2d, 0x08, 0x62, 0xed, 0x34, 0x61, 0xe3, 0xda, + 0x2c, 0xcc, 0x1b, 0xf8, 0x12, 0xfe, 0xfd, 0x19, 0xa2, 0xc3, 0x70, 0xfd, + 0x4f, 0x5b, 0x5d, 0x20, 0xd2, 0xe1, 0xc5, 0xac, 0xe7, 0xa1, 0x84, 0x00, + 0xbd, 0x46, 0x81, 0xfd, 0x54, 0x69, 0xed, 0x1a, 0x7a, 0x32, 0xbb, 0x75, + 0x22, 0x76, 0x6d, 0x34, 0x24, 0xcc, 0xe6, 0xbe, 0x78, 0x5a, 0x75, 0x6c, + 0xbc, 0x62, 0xb8, 0x14, 0xf7, 0x13, 0x73, 0xc2, 0xdc, 0xb6, 0xfa, 0xfb, + 0x97, 0xfe, 0x27, 0x7b, 0x33, 0xb8, 0xeb, 0x20, 0xd2, 0x0f, 0x4f, 0xed, + 0xd1, 0xd0, 0x63, 0xf7, 0xc5, 0x8e, 0xec, 0xcc, 0xd2, 0x31, 0x38, 0x35, + 0x65, 0x33, 0x5c, 0x63, 0x85, 0xf7, 0x3d, 0xc3, 0x62, 0x26, 0x52, 0x0a, + 0x67, 0xda, 0x87, 0x1f, 0x9e, 0x47, 0xec, 0x6b, 0xf5, 0x74, 0x1a, 0xc5, + 0xa7, 0xa0, 0x0f, 0xdd, 0xc5, 0x42, 0xf4, 0xda, 0x41, 0x1a, 0x48, 0xa9, + 0xbe, 0x4f, 0xb6, 0x28, 0x17, 0xe9, 0xf5, 0xd7, 0x00, 0xb3, 0xfe, 0x05, + 0x4e, 0xa7, 0xdf, 0x65, 0x7a, 0xb8, 0x4f, 0xe0, 0xfe, 0x58, 0x9e, 0xba, + 0x45, 0x11, 0xba, 0xc2, 0xdb, 0x97, 0x97, 0xa4, 0xbc, 0x18, 0x21, 0x1b, + 0xad, 0x82, 0xef, 0xb1, 0x5f, 0x2f, 0x25, 0x9d, 0xca, 0x52, 0xa5, 0x6d, + 0x8c, 0xab, 0x07, 0x2b, 0x7b, 0x6a, 0x77, 0x9d, 0xdf, 0xfb, 0xae, 0x6e, + 0x49, 0x18, 0x25, 0x4a, 0xf2, 0x7d, 0xa0, 0x32, 0xc8, 0x53, 0x10, 0xc3, + 0xf2, 0xef, 0xf3, 0xe7, 0x79, 0xd7, 0x6a, 0x0e, 0x61, 0xff, 0x89, 0xc9, + 0x42, 0xe8, 0x6e, 0x4f, 0x78, 0xe1, 0x5f, 0xcd, 0x7a, 0xf6, 0x27, 0x72, + 0x67, 0xea, 0x0b, 0xa6, 0xcc, 0x34, 0xb7, 0x8f, 0x92, 0x3c, 0x95, 0xb9, + 0x0a, 0x5d, 0x49, 0x2e, 0xb7, 0x7d, 0x31, 0x9c, 0x79, 0x61, 0x95, 0x9c, + 0x60, 0x56, 0x8d, 0x35, 0x00, 0xc5, 0x8b, 0xe6, 0x02, 0x0f, 0x26, 0x39, + 0x7b, 0x93, 0x94, 0xb1, 0xcd, 0xde, 0xed, 0xfa, 0x2a, 0x4b, 0x63, 0xa8, + 0x1b, 0x31, 0x43, 0x5e, 0x69, 0x7c, 0xd6, 0x15, 0x35, 0x9c, 0xa2, 0xd7, + 0xdf, 0x0e, 0x1a, 0x20, 0x50, 0xf5, 0x02, 0x21, 0x30, 0x35, 0x3c, 0x60, + 0x71, 0xad, 0xd0, 0xe3, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x10, 0x17, 0x1d, 0x22, 0x2d}; +#elif MLD_CONFIG_PARAMETER_SET == 87 +const uint8_t expected_signature[] = { + 0xdf, 0xe6, 0xe1, 0xa5, 0x20, 0xc1, 0xac, 0x98, 0x55, 0x2c, 0xf2, 0x13, + 0x65, 0x42, 0xe2, 0xb0, 0x77, 0x5f, 0x15, 0x00, 0x8f, 0x14, 0x48, 0xa1, + 0xe3, 0xee, 0x81, 0x35, 0x15, 0x34, 0xad, 0x6e, 0x60, 0x85, 0x00, 0xf8, + 0x18, 0x53, 0x0d, 0xa0, 0xc5, 0x41, 0xc4, 0x48, 0x09, 0x1b, 0x34, 0x0c, + 0x0e, 0xcf, 0xc6, 0x3d, 0x38, 0x78, 0x8b, 0x69, 0xe5, 0x6f, 0x4d, 0x43, + 0xfa, 0xa6, 0x75, 0x26, 0x8a, 0x75, 0x97, 0x10, 0x6a, 0x1f, 0x3c, 0xa6, + 0x94, 0xa9, 0x93, 0x8f, 0xe5, 0x62, 0xbf, 0x94, 0xe4, 0xd0, 0x0d, 0x11, + 0x4d, 0x03, 0xe2, 0xd8, 0xdf, 0x68, 0xb7, 0x87, 0x62, 0xc9, 0xdc, 0xc9, + 0x36, 0x4f, 0xcc, 0xd1, 0xa4, 0xae, 0x7e, 0xa4, 0xb9, 0xaf, 0xaf, 0xf0, + 0x8a, 0xe6, 0xff, 0x83, 0xe7, 0x54, 0x22, 0x6e, 0x3f, 0x2e, 0xa0, 0x4f, + 0xa8, 0x31, 0x53, 0xf3, 0x62, 0xeb, 0x04, 0xfa, 0xd1, 0x57, 0x39, 0x43, + 0xf9, 0xe0, 0x31, 0x12, 0x45, 0x09, 0x8b, 0x9e, 0x1e, 0x7a, 0x2b, 0x85, + 0xee, 0xdd, 0xe8, 0x1e, 0xd7, 0xc0, 0x17, 0xb4, 0xd2, 0xdc, 0x36, 0xa9, + 0xe4, 0x49, 0x88, 0xbf, 0x71, 0x43, 0x9d, 0x3e, 0xd2, 0x10, 0xe7, 0x82, + 0xb5, 0xfe, 0xdd, 0x42, 0xc8, 0x1b, 0x11, 0xf6, 0x52, 0x23, 0x98, 0x83, + 0x48, 0xec, 0xec, 0x70, 0x8b, 0xe7, 0x49, 0x9a, 0xd7, 0xd9, 0x7b, 0x47, + 0x4e, 0xe2, 0x5e, 0x17, 0x1a, 0xa0, 0x0e, 0x60, 0x85, 0x3a, 0x30, 0x8c, + 0x1c, 0x26, 0xb4, 0xe1, 0xb5, 0x2b, 0x48, 0xf4, 0xb8, 0x93, 0x2f, 0x79, + 0x3a, 0x1e, 0xb6, 0x3b, 0x07, 0x3b, 0x1e, 0x15, 0xd7, 0x85, 0x5e, 0xd4, + 0x06, 0x0e, 0xcd, 0x6a, 0x93, 0x3a, 0x93, 0x29, 0x6a, 0xbe, 0x68, 0x8a, + 0xb6, 0xb8, 0xfa, 0xc5, 0x63, 0x48, 0x98, 0x10, 0x6d, 0xd9, 0xd3, 0x5b, + 0x29, 0x5f, 0x93, 0x90, 0x08, 0x1c, 0x1a, 0x15, 0x7b, 0x0a, 0x59, 0x9d, + 0x64, 0x24, 0x45, 0xb6, 0xd3, 0x7b, 0xc1, 0x5d, 0x74, 0x1f, 0x0b, 0x8e, + 0x18, 0xf2, 0x92, 0x8e, 0xd4, 0x7f, 0x72, 0x5c, 0x98, 0x1f, 0x8b, 0xa5, + 0xb8, 0xf4, 0x7e, 0x12, 0x6a, 0x93, 0xb9, 0xb5, 0xf1, 0xda, 0x97, 0x75, + 0x4f, 0x56, 0x80, 0x88, 0x64, 0x2b, 0xe0, 0x59, 0xcd, 0x5e, 0x91, 0x64, + 0x9c, 0x0c, 0xa8, 0xdd, 0xac, 0xcb, 0xf3, 0x48, 0x3b, 0x5c, 0xc4, 0xc5, + 0xb9, 0x9a, 0x0b, 0x8e, 0x5d, 0x9a, 0xd5, 0xb7, 0xf0, 0xd4, 0x07, 0x48, + 0xb9, 0x63, 0x02, 0x87, 0x8d, 0xae, 0x7e, 0x03, 0x33, 0x4f, 0x86, 0x15, + 0x1b, 0x3b, 0xdf, 0xda, 0xce, 0xd3, 0x1e, 0xc0, 0x76, 0xb5, 0x1c, 0xdd, + 0xb8, 0x32, 0x87, 0x7d, 0x59, 0x18, 0x72, 0x0c, 0xde, 0x8f, 0x63, 0x2d, + 0x38, 0xf2, 0xe9, 0xc2, 0x81, 0xed, 0xfa, 0x2d, 0x61, 0xef, 0x48, 0xdb, + 0xa2, 0xeb, 0xfe, 0x52, 0x31, 0x1e, 0x21, 0x0a, 0x08, 0xf6, 0x02, 0xd3, + 0xc0, 0x32, 0x3b, 0x6b, 0x2f, 0x64, 0xc4, 0xb3, 0x4b, 0xfe, 0x69, 0x78, + 0xbf, 0x20, 0x62, 0x07, 0x77, 0xdf, 0x2c, 0x18, 0x53, 0x61, 0x8e, 0x05, + 0x01, 0x86, 0xab, 0xab, 0xec, 0x18, 0x8c, 0x15, 0x63, 0x1f, 0xe9, 0x99, + 0xb2, 0x35, 0x77, 0xe1, 0x58, 0xf1, 0xa9, 0x4d, 0x1a, 0xb9, 0x8c, 0x30, + 0x63, 0x6f, 0x9e, 0x7d, 0x4e, 0xcf, 0xb5, 0x6c, 0xf3, 0xe4, 0xdc, 0xab, + 0xf9, 0xae, 0x58, 0xf8, 0x1d, 0x08, 0x7b, 0x73, 0x82, 0x58, 0xc8, 0x67, + 0x48, 0x1a, 0x5e, 0x3d, 0xdb, 0xac, 0x1b, 0x1b, 0xef, 0xeb, 0xa4, 0xe5, + 0x67, 0x48, 0x76, 0xd1, 0x96, 0x4f, 0x6c, 0x7d, 0x06, 0x8c, 0x02, 0x86, + 0x95, 0x83, 0xb6, 0x9b, 0x5e, 0x9a, 0xb5, 0x85, 0xc0, 0x4f, 0x13, 0x1c, + 0x32, 0xf8, 0x29, 0xdf, 0x47, 0x85, 0xdb, 0xe4, 0x37, 0xdc, 0xd8, 0x04, + 0x18, 0xdd, 0xca, 0x97, 0xdd, 0x67, 0x13, 0xbe, 0x74, 0x95, 0xdc, 0xd0, + 0xcc, 0xe6, 0xb5, 0xa5, 0x12, 0x9b, 0x23, 0x4f, 0x41, 0x8c, 0xcc, 0x95, + 0xf4, 0xb0, 0x5f, 0x2a, 0xc4, 0xbf, 0x88, 0xda, 0x55, 0xcb, 0x13, 0x93, + 0x22, 0x60, 0x51, 0x43, 0xc7, 0x9a, 0x2c, 0xfa, 0xb2, 0x59, 0xc1, 0xe6, + 0x8a, 0xa4, 0xb8, 0xfb, 0xd3, 0x31, 0x1d, 0xc7, 0x88, 0xdc, 0xbc, 0xe9, + 0xba, 0xe7, 0xdc, 0xe3, 0xdd, 0x90, 0x96, 0xb4, 0xb4, 0x0a, 0xc1, 0x07, + 0x31, 0x3f, 0xdb, 0xc5, 0x4d, 0x73, 0x58, 0x86, 0x15, 0x37, 0x07, 0x86, + 0x03, 0x17, 0x16, 0x18, 0x15, 0xb9, 0x26, 0x35, 0x8a, 0x43, 0x22, 0xae, + 0x21, 0x52, 0x05, 0x4e, 0x5c, 0x3f, 0x3e, 0xb9, 0x2a, 0x19, 0x13, 0xfd, + 0x31, 0x47, 0x6a, 0x74, 0xaa, 0xb9, 0xc6, 0x2c, 0x13, 0x8c, 0x21, 0xc4, + 0x8d, 0x00, 0xf4, 0x24, 0xf2, 0xb7, 0xd3, 0x13, 0xad, 0x29, 0x5e, 0x50, + 0x0b, 0x0e, 0x9f, 0x9a, 0xb7, 0xf6, 0x9e, 0xba, 0x12, 0x23, 0x84, 0x8c, + 0xbe, 0x2c, 0x14, 0x1e, 0xe6, 0x79, 0x15, 0x20, 0x2d, 0x32, 0x08, 0xd8, + 0x1c, 0x87, 0x1b, 0xa8, 0xc0, 0xbb, 0x85, 0xa9, 0x71, 0x30, 0x5e, 0x39, + 0x48, 0x87, 0xdc, 0x3d, 0x03, 0x29, 0x19, 0xd1, 0xd4, 0x21, 0x3a, 0x53, + 0x2d, 0x5e, 0x78, 0xff, 0x94, 0x4b, 0x91, 0xa6, 0xb5, 0xe5, 0x42, 0x56, + 0x67, 0x6a, 0x0e, 0xf3, 0x2d, 0x6a, 0x4e, 0xd7, 0x3a, 0x81, 0xb1, 0x4d, + 0x0b, 0x66, 0x5f, 0x43, 0x28, 0x7c, 0x75, 0x8b, 0x2b, 0x99, 0x24, 0xc2, + 0x5e, 0x8c, 0x22, 0xf0, 0xd5, 0xb3, 0xfc, 0x86, 0x62, 0xf3, 0xd2, 0x6c, + 0xa7, 0x48, 0x04, 0x44, 0x5d, 0x93, 0x74, 0x37, 0x16, 0x2c, 0x19, 0x12, + 0x57, 0x49, 0xef, 0xd5, 0xd6, 0x92, 0xdc, 0x51, 0xf8, 0x55, 0x3a, 0xc0, + 0x0b, 0xdf, 0x41, 0xb5, 0x01, 0x59, 0x7e, 0x85, 0x65, 0xdb, 0x44, 0xbd, + 0x04, 0x96, 0x1a, 0xd4, 0x6e, 0x22, 0x54, 0x92, 0xdb, 0xc7, 0xc5, 0x3a, + 0xdf, 0x0c, 0xf4, 0x1b, 0xdc, 0x14, 0xf6, 0x91, 0x9c, 0xbe, 0xf8, 0x8e, + 0x70, 0xd1, 0x3a, 0x0e, 0x58, 0xe6, 0xb9, 0xd3, 0xaa, 0xa2, 0x70, 0xba, + 0xdd, 0x16, 0x13, 0x19, 0xd1, 0x96, 0x78, 0x04, 0x2f, 0xd7, 0x38, 0x8c, + 0x35, 0x1f, 0xfc, 0x58, 0xa4, 0x4c, 0xa9, 0x9a, 0xae, 0x13, 0x3b, 0xc1, + 0x20, 0x4b, 0x66, 0x0f, 0x72, 0x42, 0x0a, 0x53, 0x84, 0x54, 0x71, 0x06, + 0xdb, 0x85, 0x8f, 0x40, 0xa6, 0x09, 0xf7, 0x24, 0xc4, 0x35, 0xf7, 0x1d, + 0xd4, 0x3d, 0x54, 0x75, 0xaf, 0xc4, 0x78, 0x0f, 0xce, 0xe0, 0x0c, 0x90, + 0x0f, 0xd5, 0x2e, 0x61, 0xf7, 0x58, 0xaa, 0xf0, 0xc7, 0x37, 0x5a, 0x59, + 0x1f, 0x8a, 0x03, 0x98, 0x43, 0xb7, 0x27, 0x78, 0x4e, 0x44, 0x5a, 0xb5, + 0x29, 0xf5, 0xab, 0x9e, 0xb7, 0x2a, 0xc4, 0xa3, 0x03, 0x00, 0xe3, 0x28, + 0x57, 0xc9, 0x2a, 0x98, 0xb8, 0xa1, 0x45, 0x1d, 0xfa, 0x6e, 0xb3, 0x0d, + 0x42, 0x5a, 0xb6, 0xb1, 0x0e, 0x5c, 0xbe, 0x82, 0xe2, 0x36, 0x40, 0x4b, + 0x05, 0x28, 0xd9, 0xbc, 0x27, 0xd6, 0x77, 0x00, 0xc9, 0x29, 0x6a, 0xd6, + 0x19, 0x8f, 0x8d, 0xda, 0xe1, 0xc3, 0x8b, 0x69, 0x71, 0xd0, 0xf7, 0xc8, + 0x33, 0xef, 0xe6, 0x23, 0x6b, 0xcb, 0x00, 0x56, 0x0a, 0x9b, 0x9d, 0x60, + 0x3a, 0xd3, 0xad, 0xd9, 0x5c, 0x6a, 0x7d, 0xab, 0x35, 0x71, 0x93, 0xc5, + 0xf2, 0x6a, 0x38, 0x0e, 0xfb, 0xd9, 0x9b, 0xa5, 0xda, 0x52, 0x45, 0xef, + 0x93, 0x94, 0x5b, 0x08, 0x8c, 0x07, 0xab, 0x2e, 0x99, 0x88, 0x77, 0xb5, + 0x15, 0x66, 0x7f, 0x0e, 0xfa, 0xb0, 0x29, 0xe4, 0x88, 0xd9, 0xdd, 0x22, + 0xaf, 0x7a, 0x4e, 0xb5, 0xd0, 0x62, 0x85, 0x27, 0x33, 0xf1, 0xb7, 0x34, + 0xb1, 0xe6, 0xda, 0x9f, 0x3c, 0xfe, 0xf5, 0xd4, 0xef, 0x56, 0x48, 0x93, + 0x7a, 0x54, 0xa2, 0x7f, 0x07, 0xea, 0x31, 0xb8, 0x8b, 0xca, 0xb9, 0xdb, + 0x1e, 0x2b, 0xb5, 0x16, 0xe6, 0x0e, 0xd9, 0x3f, 0x7c, 0xf0, 0xc2, 0x3e, + 0x57, 0x64, 0x60, 0x97, 0xfb, 0xdf, 0x8c, 0x3e, 0x56, 0x22, 0x92, 0x2a, + 0xb2, 0x21, 0x00, 0x0a, 0x75, 0x89, 0x68, 0xe7, 0x51, 0xa3, 0x63, 0x05, + 0xe1, 0x6f, 0x1e, 0x1e, 0x80, 0xa2, 0x4b, 0x5d, 0xb7, 0xf4, 0xb7, 0x45, + 0x85, 0x00, 0x84, 0x6e, 0xbe, 0x0b, 0x67, 0xbf, 0x21, 0x06, 0x5a, 0x56, + 0x79, 0xe9, 0x6b, 0x0e, 0x72, 0x19, 0x2d, 0x09, 0x78, 0xd5, 0x5e, 0xc2, + 0x32, 0xee, 0x29, 0xd4, 0x7a, 0x65, 0xc7, 0xfe, 0x16, 0x86, 0xd2, 0x29, + 0x71, 0xe5, 0x91, 0x0e, 0x3e, 0x86, 0xd5, 0x00, 0xc4, 0xfc, 0xd9, 0xae, + 0xd3, 0x7c, 0x13, 0xfd, 0x62, 0xce, 0x0c, 0xb2, 0xe5, 0x1f, 0x6d, 0xed, + 0x55, 0x6f, 0xc1, 0xaa, 0xa1, 0x74, 0x59, 0x46, 0x83, 0xd5, 0x5d, 0x71, + 0x17, 0x13, 0x1d, 0x0b, 0x25, 0xfb, 0x0a, 0xcd, 0x67, 0xfe, 0x57, 0x93, + 0xc2, 0x71, 0x55, 0x6c, 0x68, 0xfa, 0x40, 0xdb, 0xdd, 0xce, 0xd5, 0x5c, + 0xce, 0x0a, 0x1d, 0xfa, 0x19, 0x30, 0xe2, 0x2b, 0x63, 0x98, 0x16, 0x2c, + 0x67, 0x69, 0x55, 0xe5, 0xc1, 0x6c, 0x6e, 0xb7, 0x92, 0x6a, 0xbb, 0x10, + 0xd3, 0x13, 0x2e, 0x73, 0x91, 0x74, 0xcb, 0x9f, 0x5c, 0x7f, 0x5c, 0x48, + 0x58, 0x36, 0x13, 0x47, 0xf7, 0x49, 0xae, 0x90, 0x15, 0x53, 0xb5, 0xe6, + 0x37, 0xfb, 0x81, 0x47, 0xb4, 0x69, 0x84, 0xca, 0x95, 0xab, 0x19, 0x2a, + 0x28, 0xc2, 0x8a, 0xf1, 0xcd, 0xf9, 0x3e, 0xd3, 0xaf, 0xe1, 0x75, 0xf7, + 0x94, 0x74, 0x1c, 0xf5, 0x32, 0xcf, 0x70, 0xbd, 0x69, 0xcc, 0xa8, 0x3c, + 0xca, 0x59, 0x53, 0xfa, 0xcb, 0xe7, 0xb6, 0x36, 0x70, 0xea, 0xe2, 0x84, + 0xfa, 0x5e, 0xbd, 0xd7, 0x59, 0x3d, 0x21, 0xc6, 0x9f, 0x5c, 0x1f, 0xa6, + 0xa9, 0xf1, 0xd3, 0x26, 0x9e, 0xff, 0xbc, 0x81, 0xfe, 0xbe, 0xee, 0x64, + 0xd9, 0x63, 0x94, 0x4b, 0x15, 0xd8, 0x95, 0xaa, 0xec, 0x10, 0xc9, 0xe2, + 0xe1, 0x05, 0x37, 0x64, 0xc4, 0xb0, 0x2e, 0xa5, 0x0e, 0x4c, 0x2d, 0x03, + 0x53, 0xf1, 0x93, 0x77, 0x9d, 0x46, 0x14, 0x67, 0x48, 0x5f, 0xad, 0x1b, + 0xdc, 0xb9, 0x74, 0xa2, 0x6c, 0xfc, 0xd2, 0xa0, 0x1f, 0x43, 0x89, 0x15, + 0xc5, 0x0c, 0xb0, 0x9e, 0x1e, 0xc2, 0xd6, 0x44, 0xd9, 0x6e, 0xfc, 0xb4, + 0x9c, 0x95, 0x90, 0xcd, 0xc3, 0x17, 0x1c, 0x6a, 0xce, 0x03, 0x56, 0x9f, + 0xe7, 0xcd, 0x7e, 0xe7, 0xa2, 0x0c, 0x2b, 0x0d, 0x59, 0xb0, 0xc9, 0x4c, + 0x6e, 0x33, 0x6d, 0x43, 0xc4, 0x3a, 0x10, 0x24, 0x03, 0x3e, 0x09, 0xb6, + 0x86, 0x13, 0xba, 0x18, 0x19, 0xd3, 0xff, 0xeb, 0xa5, 0x25, 0x8f, 0x6f, + 0xc8, 0xe6, 0x96, 0xa4, 0xd2, 0x66, 0x40, 0x81, 0x79, 0xe8, 0x39, 0x18, + 0x41, 0x02, 0x66, 0x5c, 0x30, 0x5f, 0x58, 0x9d, 0x35, 0x16, 0xc6, 0x96, + 0xa8, 0x68, 0xbc, 0x09, 0x83, 0x17, 0x2c, 0x5f, 0x5e, 0xd0, 0x1d, 0xb0, + 0x48, 0x5e, 0xcf, 0x91, 0x16, 0x4d, 0xa0, 0xba, 0xbc, 0x61, 0xa8, 0x3f, + 0x30, 0x09, 0xbb, 0xa3, 0x12, 0xcd, 0xdc, 0x29, 0xf7, 0xb0, 0xad, 0x05, + 0x17, 0xd6, 0xd3, 0x16, 0xfb, 0xe5, 0x99, 0xf4, 0x71, 0x62, 0xa3, 0x45, + 0x45, 0xc7, 0x9b, 0xaa, 0x45, 0xd3, 0x35, 0xfe, 0xfb, 0x63, 0xaf, 0xe7, + 0x85, 0x31, 0xc9, 0x66, 0x26, 0xa9, 0xda, 0x8c, 0xc6, 0xf6, 0xd5, 0xdf, + 0xb1, 0xa9, 0xf1, 0xb6, 0x3d, 0x92, 0xae, 0x4d, 0xbc, 0x74, 0x7d, 0x76, + 0x5a, 0x59, 0x8c, 0x87, 0xff, 0x95, 0x2f, 0x67, 0x37, 0x30, 0x1a, 0xc1, + 0x23, 0x2e, 0x0c, 0xaa, 0x80, 0x1c, 0xf3, 0xa3, 0x74, 0x94, 0xb2, 0xda, + 0x1a, 0xb8, 0x46, 0xec, 0x30, 0x76, 0xf4, 0xdf, 0xfb, 0x00, 0xb3, 0x6f, + 0x86, 0xc1, 0xc5, 0x3a, 0x5d, 0x11, 0x14, 0x87, 0xeb, 0x30, 0xd8, 0x33, + 0x18, 0x00, 0x01, 0x76, 0x43, 0x82, 0xcd, 0x1c, 0x36, 0x54, 0xd2, 0x64, + 0x5b, 0xfb, 0x93, 0xca, 0x20, 0x1d, 0xa3, 0x20, 0x99, 0xc3, 0x8e, 0x5c, + 0x82, 0xfc, 0x56, 0x07, 0x41, 0x4b, 0x4f, 0x54, 0xc7, 0xb5, 0xe8, 0x6d, + 0x7e, 0xd8, 0x8a, 0x56, 0xb4, 0x76, 0x1e, 0xd3, 0x82, 0x97, 0xdd, 0x2b, + 0xd9, 0x80, 0xb7, 0xb6, 0xeb, 0x3d, 0xe5, 0xe0, 0x20, 0x27, 0x8c, 0xf0, + 0xd6, 0x14, 0xc7, 0xcd, 0x79, 0xbc, 0xa0, 0x21, 0x85, 0xc3, 0x02, 0xae, + 0x73, 0xc4, 0x0a, 0x39, 0x1a, 0x98, 0x61, 0xc3, 0x86, 0xd8, 0x97, 0x67, + 0x87, 0xe9, 0x56, 0x0b, 0x61, 0xa6, 0x7e, 0x07, 0xfb, 0x0a, 0x8b, 0xd1, + 0x90, 0xbd, 0x39, 0x22, 0xdb, 0xc2, 0x7f, 0xaa, 0x79, 0xb7, 0x39, 0x09, + 0xc1, 0x69, 0xdb, 0xe2, 0x7f, 0xec, 0xde, 0x80, 0x7a, 0x6c, 0xde, 0x76, + 0xa4, 0xe8, 0xe0, 0x8d, 0x71, 0xfa, 0x62, 0xf0, 0x2e, 0x7b, 0xf4, 0xce, + 0x65, 0x18, 0x42, 0xde, 0x92, 0x1b, 0xdc, 0xc9, 0xa7, 0x8d, 0xa5, 0x91, + 0x0f, 0xa5, 0x1b, 0x89, 0xcf, 0x29, 0x10, 0x1d, 0x94, 0x78, 0x1b, 0xea, + 0x79, 0x35, 0x62, 0xd4, 0x29, 0xe6, 0x59, 0x8c, 0xc1, 0xd2, 0xf3, 0x32, + 0x71, 0x09, 0xce, 0x51, 0xd7, 0x14, 0x29, 0x92, 0xbf, 0xdf, 0x9a, 0x69, + 0xda, 0x61, 0x03, 0x0f, 0xa2, 0x0a, 0xab, 0x57, 0x1c, 0xca, 0xab, 0x42, + 0x63, 0x63, 0x1e, 0x35, 0x5d, 0x8d, 0xba, 0x6f, 0x4b, 0x6b, 0x5e, 0x7c, + 0xc0, 0x1e, 0xb7, 0xf4, 0x65, 0xbd, 0x13, 0x1c, 0xf2, 0xa9, 0x73, 0x38, + 0xc3, 0x47, 0xc9, 0x32, 0xf0, 0x30, 0x57, 0x05, 0x42, 0x52, 0xac, 0x72, + 0xee, 0x9f, 0x4e, 0x21, 0xbf, 0x38, 0x19, 0x6d, 0x48, 0xec, 0x97, 0xcb, + 0x70, 0x9e, 0xee, 0xb3, 0xa1, 0xaa, 0xa6, 0x7e, 0xe9, 0x16, 0xdf, 0xcd, + 0x1c, 0x56, 0xcf, 0xf0, 0x9f, 0x4d, 0xd1, 0x8c, 0x14, 0x50, 0x5d, 0x23, + 0x96, 0xe0, 0x1f, 0x61, 0x79, 0xbf, 0x44, 0xfd, 0xa2, 0x31, 0xf7, 0x4c, + 0x0c, 0x8d, 0x8c, 0x1b, 0xbf, 0x8d, 0x45, 0xbf, 0x0b, 0xd8, 0xfb, 0x6f, + 0xff, 0x15, 0xc0, 0x44, 0x7c, 0xb9, 0xb8, 0xf9, 0xef, 0x0d, 0x79, 0x11, + 0x3b, 0x79, 0xd2, 0x52, 0x89, 0x5a, 0xcd, 0x0f, 0x10, 0x92, 0x42, 0xfe, + 0xcf, 0x0a, 0x11, 0x8a, 0x8a, 0xda, 0xee, 0xc8, 0x6b, 0xd9, 0xab, 0xec, + 0xb4, 0x25, 0x6f, 0x8d, 0x68, 0x26, 0xe8, 0xdd, 0xf5, 0xa4, 0xe8, 0x65, + 0x37, 0x03, 0xb0, 0xad, 0x73, 0x3b, 0x4d, 0x74, 0x57, 0x7f, 0x0f, 0x6c, + 0xb0, 0x5d, 0x59, 0x80, 0x13, 0xa1, 0x6c, 0xb0, 0xed, 0x26, 0xec, 0x79, + 0x50, 0x5f, 0x5c, 0xb7, 0xa6, 0xae, 0xe8, 0x0a, 0x6d, 0x55, 0x9a, 0x7f, + 0x59, 0x23, 0xa3, 0x7e, 0x84, 0x7b, 0x3b, 0xfc, 0xde, 0xe1, 0xd9, 0x7c, + 0xd6, 0x87, 0xb3, 0x0e, 0xdb, 0xc1, 0x8c, 0x5e, 0x77, 0xb7, 0x23, 0xd7, + 0x14, 0xd4, 0x23, 0xb4, 0xac, 0x45, 0xbf, 0xfe, 0x40, 0x20, 0x4d, 0x91, + 0x20, 0x94, 0xbd, 0x58, 0xb1, 0x99, 0x69, 0xaf, 0x31, 0x68, 0xbd, 0x61, + 0x5e, 0x87, 0x81, 0x54, 0x4e, 0x2d, 0x03, 0xc2, 0xe2, 0xcd, 0xdc, 0x59, + 0xe5, 0x35, 0xcf, 0xb8, 0xfc, 0x65, 0xed, 0x46, 0xb3, 0x92, 0xe7, 0xf8, + 0x3a, 0x32, 0xaa, 0x0e, 0x5a, 0x82, 0x58, 0x4e, 0x77, 0xd8, 0x33, 0xc9, + 0xb0, 0x3e, 0xad, 0xa5, 0x92, 0xe9, 0xa9, 0x8c, 0x00, 0x72, 0x8f, 0xdc, + 0x77, 0x9d, 0x5c, 0x97, 0xd6, 0x58, 0x20, 0x1e, 0xf4, 0x55, 0x2d, 0xc0, + 0x30, 0xf0, 0x66, 0xda, 0x2d, 0x11, 0xac, 0xd4, 0x2d, 0xd5, 0x25, 0x42, + 0x1d, 0xce, 0x49, 0xb5, 0x95, 0x79, 0x9b, 0x6c, 0x65, 0xe0, 0x8a, 0xc5, + 0x9f, 0x75, 0xe3, 0xe6, 0xf8, 0xa6, 0x88, 0xd6, 0x93, 0x70, 0x4f, 0x89, + 0x94, 0x74, 0xbd, 0xef, 0xc2, 0x1a, 0x55, 0x74, 0x37, 0x44, 0x85, 0x1e, + 0xa9, 0xbb, 0x3f, 0x15, 0xc7, 0x84, 0x80, 0xa5, 0xab, 0xc3, 0x91, 0x8e, + 0xd6, 0x32, 0x46, 0x0d, 0xfa, 0xd1, 0x19, 0xd1, 0xfc, 0x02, 0xe2, 0x20, + 0xa6, 0xa9, 0xf7, 0xf4, 0xcc, 0x5b, 0x54, 0x4f, 0x4a, 0x73, 0x35, 0xda, + 0xf0, 0x31, 0x81, 0x1a, 0x82, 0xe7, 0xd4, 0xc8, 0xb4, 0x1d, 0x70, 0xa9, + 0x5d, 0x67, 0xb9, 0x7d, 0x4b, 0xcd, 0xa4, 0x81, 0xf9, 0xb2, 0x38, 0x07, + 0x16, 0xd5, 0x28, 0x82, 0xb9, 0x76, 0x5b, 0xa1, 0x09, 0x7a, 0xe7, 0x2a, + 0xcf, 0xc0, 0x3d, 0x2a, 0x42, 0x9a, 0xf3, 0xc8, 0x64, 0x15, 0x7c, 0x94, + 0xd0, 0x97, 0xee, 0x34, 0xb6, 0xf0, 0xb2, 0xba, 0x7e, 0xb2, 0xbb, 0x4e, + 0xbf, 0x88, 0xd0, 0x6b, 0xc5, 0x9c, 0xb9, 0xf2, 0x7d, 0xbf, 0x5d, 0x87, + 0xbc, 0x36, 0x4a, 0xd1, 0x1b, 0x6f, 0x40, 0x09, 0xba, 0x26, 0x51, 0xd6, + 0xc0, 0xaf, 0x27, 0xce, 0x27, 0x8d, 0x93, 0xa8, 0x6c, 0x91, 0xe7, 0x91, + 0x42, 0xc0, 0x68, 0x36, 0x5b, 0xd5, 0x56, 0x4c, 0xe2, 0x77, 0xc3, 0xac, + 0x56, 0xe3, 0x1c, 0xc2, 0xf9, 0x78, 0x02, 0x39, 0x7d, 0xed, 0x18, 0x2a, + 0x01, 0x48, 0xe6, 0xf6, 0x7e, 0x34, 0x50, 0xf4, 0x57, 0x56, 0x93, 0xdb, + 0x85, 0x1b, 0x1e, 0x1a, 0x6f, 0x3e, 0x07, 0x3c, 0xad, 0x3f, 0x8d, 0x75, + 0x53, 0xc3, 0x20, 0x72, 0x93, 0x28, 0xd2, 0x86, 0xc8, 0xa5, 0x90, 0xf2, + 0x5f, 0x13, 0xd5, 0xa5, 0xbe, 0x88, 0x9e, 0x9a, 0x57, 0x2c, 0x53, 0x3f, + 0x11, 0x25, 0x00, 0x00, 0x4a, 0x16, 0x8d, 0xd3, 0x3f, 0x2d, 0x3d, 0x88, + 0xbb, 0x4c, 0x4f, 0x9a, 0xb9, 0x97, 0x5f, 0xed, 0x71, 0xa9, 0x68, 0xd9, + 0x4a, 0x14, 0x24, 0xc7, 0xbe, 0xff, 0x85, 0x57, 0xa3, 0x21, 0xe3, 0x21, + 0x79, 0x1f, 0xd0, 0xbb, 0xb7, 0x73, 0xde, 0x60, 0x02, 0x4b, 0x8f, 0x7d, + 0xb3, 0xb3, 0x8a, 0xda, 0x4c, 0xf4, 0xb8, 0xf1, 0x31, 0xff, 0x32, 0x7b, + 0xd8, 0xfa, 0xb1, 0xcb, 0xb4, 0x58, 0xf5, 0xc8, 0x64, 0xdf, 0xfe, 0x3d, + 0x89, 0x52, 0x5c, 0x52, 0x95, 0xf3, 0xba, 0x0d, 0x1d, 0x2c, 0xc4, 0xf7, + 0x3c, 0x3b, 0x6f, 0x8e, 0xc7, 0xab, 0xad, 0x3d, 0x3d, 0x95, 0x9b, 0xc7, + 0x71, 0x36, 0xae, 0x08, 0xc3, 0x08, 0x79, 0xfa, 0x24, 0xee, 0xd9, 0xf9, + 0x63, 0xc7, 0xd9, 0x16, 0x19, 0x8e, 0x0d, 0xaf, 0x52, 0x87, 0x86, 0x7d, + 0xec, 0xe5, 0xea, 0x5a, 0xda, 0x86, 0x9d, 0x0e, 0x50, 0x53, 0x8c, 0x24, + 0xa8, 0x69, 0xc4, 0xf3, 0x85, 0x7b, 0x34, 0x67, 0x19, 0x35, 0xec, 0xd4, + 0xd4, 0x50, 0xe0, 0xe6, 0xe9, 0x29, 0x5b, 0x92, 0xee, 0xba, 0xa9, 0xef, + 0xf6, 0x35, 0x23, 0x8b, 0xdb, 0x48, 0x32, 0x25, 0x41, 0xf3, 0x55, 0x12, + 0x33, 0xc3, 0x6c, 0xed, 0x32, 0xe1, 0x64, 0x7a, 0x8d, 0xa2, 0x19, 0x5a, + 0x26, 0xf2, 0x83, 0xf1, 0xe4, 0x27, 0xdb, 0x67, 0xc3, 0x89, 0x37, 0xea, + 0x78, 0x19, 0xc6, 0xa3, 0x82, 0x84, 0x1c, 0xf3, 0x2b, 0xbe, 0xde, 0xba, + 0xe7, 0x60, 0x2e, 0xf5, 0x4e, 0xb6, 0x73, 0x29, 0xac, 0xc7, 0x55, 0xab, + 0x21, 0xe9, 0x95, 0x78, 0xd5, 0x8e, 0x27, 0xdc, 0x92, 0x5f, 0xc0, 0xcb, + 0xee, 0x66, 0x09, 0x0a, 0xfc, 0x94, 0x43, 0x44, 0x50, 0x35, 0x57, 0xf8, + 0x08, 0xf9, 0x97, 0xa2, 0x0e, 0xde, 0x81, 0xe1, 0xd1, 0xa0, 0x41, 0xfe, + 0xe6, 0x08, 0x6c, 0x98, 0x8c, 0x81, 0x46, 0x0e, 0xf9, 0x9a, 0x54, 0xfe, + 0xc3, 0x91, 0xe3, 0xd4, 0x46, 0xca, 0x52, 0xa2, 0x73, 0x9e, 0x4d, 0xa7, + 0xfd, 0xa1, 0x8e, 0x43, 0x28, 0xf5, 0xa3, 0xa2, 0x62, 0x20, 0x53, 0x62, + 0x05, 0x49, 0xba, 0x06, 0xe2, 0xeb, 0xba, 0xfb, 0x8e, 0xa0, 0x22, 0xc7, + 0xf9, 0xcc, 0x7f, 0x8b, 0xa8, 0x5d, 0x55, 0xd2, 0x24, 0xff, 0xdd, 0x2c, + 0xc1, 0xd0, 0x3d, 0xe4, 0x79, 0xea, 0xba, 0x62, 0xe5, 0xa2, 0x62, 0xf4, + 0x1f, 0xec, 0xb0, 0x07, 0xf2, 0x0d, 0x32, 0x84, 0x86, 0x81, 0x3d, 0x95, + 0xc1, 0x64, 0xfe, 0x9a, 0x3d, 0x8f, 0x4b, 0x6d, 0xfb, 0x0d, 0x42, 0xcf, + 0xbf, 0xdb, 0x51, 0xb2, 0x16, 0xa2, 0x35, 0xaa, 0xe7, 0x31, 0x54, 0xc2, + 0x87, 0xc6, 0xa5, 0x30, 0x71, 0x64, 0x65, 0xff, 0x41, 0x20, 0xb0, 0x83, + 0xdb, 0xb7, 0x95, 0xce, 0xd7, 0xcc, 0x7a, 0x77, 0xad, 0xb8, 0xb7, 0x4c, + 0xfc, 0x11, 0x05, 0x2b, 0xc4, 0xd4, 0xb6, 0x8b, 0xae, 0x13, 0xa5, 0x40, + 0x18, 0x6e, 0x0d, 0xe3, 0xc6, 0xb0, 0x81, 0x46, 0x46, 0x7e, 0x52, 0x0b, + 0x85, 0x4d, 0x98, 0xd9, 0x42, 0xdf, 0xde, 0x45, 0xc1, 0x5a, 0x33, 0x12, + 0x46, 0x26, 0xb3, 0x6f, 0xf2, 0x8b, 0x37, 0x6b, 0xfd, 0x08, 0xf4, 0x46, + 0x86, 0x89, 0x63, 0x63, 0x21, 0xe5, 0xa9, 0xb7, 0xd0, 0x09, 0x17, 0x52, + 0xee, 0xea, 0xdf, 0x97, 0xb7, 0x73, 0x2e, 0x54, 0x2c, 0x7b, 0x70, 0xd3, + 0xda, 0x26, 0x57, 0x1f, 0xb0, 0x19, 0xd9, 0x91, 0x18, 0x69, 0x75, 0x42, + 0x63, 0xcf, 0x6c, 0x8c, 0x98, 0x5e, 0x17, 0x99, 0x7e, 0x1d, 0xdc, 0x67, + 0x6d, 0x99, 0xd9, 0x02, 0x6e, 0x73, 0x90, 0x5a, 0x4f, 0x0a, 0xb4, 0x48, + 0xfb, 0xc5, 0xbd, 0xd2, 0x10, 0x05, 0xa6, 0x12, 0x68, 0x36, 0x28, 0x51, + 0x60, 0x1c, 0xa1, 0xe9, 0x90, 0x54, 0xa5, 0x53, 0xc3, 0x48, 0x9e, 0xd8, + 0x42, 0x52, 0x85, 0x0e, 0xff, 0xfe, 0xbf, 0xad, 0x3a, 0xa4, 0x57, 0x09, + 0x13, 0x38, 0x64, 0x15, 0x7c, 0xfd, 0xed, 0x91, 0x76, 0x44, 0x20, 0x84, + 0xd9, 0x90, 0xab, 0xfe, 0xfd, 0xd6, 0xab, 0xf1, 0xb3, 0x25, 0x21, 0x3d, + 0x97, 0x72, 0xb2, 0x95, 0xc5, 0x22, 0x80, 0xd9, 0x4a, 0x49, 0x9d, 0x99, + 0xc2, 0x4a, 0x9a, 0x59, 0xb3, 0x71, 0x75, 0x5b, 0xf9, 0x89, 0x7a, 0xdd, + 0xa9, 0xb3, 0xc3, 0xeb, 0x42, 0x91, 0xe2, 0x97, 0x30, 0x40, 0x48, 0x68, + 0x19, 0x3b, 0xf5, 0x7b, 0x4e, 0x33, 0x4b, 0x0c, 0xf3, 0xed, 0xda, 0x76, + 0x3f, 0xb0, 0x4b, 0x53, 0x85, 0x04, 0x33, 0x07, 0x53, 0xd8, 0x55, 0xa2, + 0xfb, 0x30, 0x2c, 0x66, 0xbd, 0x21, 0xf8, 0xfa, 0x20, 0x14, 0x9a, 0x0d, + 0x7f, 0xc9, 0x2f, 0x5b, 0x34, 0x29, 0x09, 0x16, 0xb5, 0x0a, 0x8d, 0xdf, + 0xa2, 0x84, 0x9a, 0xae, 0xe6, 0xa0, 0x50, 0x80, 0x31, 0x04, 0xd3, 0x0c, + 0x8f, 0xd1, 0x8a, 0xfd, 0xb4, 0xa5, 0xae, 0xf5, 0x3c, 0x62, 0xae, 0x45, + 0x70, 0xbb, 0x54, 0x62, 0xc8, 0x50, 0x71, 0x42, 0x85, 0xf6, 0x6f, 0xa0, + 0xf0, 0x10, 0x8a, 0x09, 0xbd, 0x71, 0x78, 0xa6, 0x5e, 0xe4, 0x03, 0x8f, + 0x3b, 0xd0, 0x5c, 0x37, 0x55, 0x1a, 0xc8, 0x57, 0x26, 0x62, 0x6c, 0xc4, + 0x67, 0x71, 0x9d, 0x97, 0xc0, 0xea, 0x35, 0x3e, 0x12, 0xd0, 0x2b, 0xc2, + 0x8f, 0x9e, 0xa6, 0x41, 0x48, 0x33, 0x83, 0x38, 0x37, 0x7e, 0xd4, 0xe3, + 0xee, 0x94, 0x8b, 0x81, 0xa4, 0x60, 0xdd, 0xdd, 0xc1, 0x8a, 0x7b, 0xda, + 0xa8, 0x46, 0xb8, 0x42, 0x3a, 0x25, 0xd6, 0x81, 0x89, 0x29, 0x21, 0xc2, + 0x0c, 0x5b, 0xfd, 0x3e, 0x8c, 0x65, 0x91, 0x52, 0xb3, 0x74, 0x1f, 0xd1, + 0x49, 0x7e, 0x1d, 0x59, 0x58, 0x96, 0xb5, 0xee, 0x32, 0xa4, 0xa8, 0x07, + 0x7c, 0xd1, 0x5b, 0x4b, 0xf8, 0x43, 0x5a, 0xa5, 0xcc, 0x60, 0xcc, 0x08, + 0x6a, 0x3c, 0x41, 0x66, 0x99, 0xe3, 0xa8, 0xe0, 0xb8, 0x87, 0xfc, 0x92, + 0xc0, 0x79, 0xc5, 0x3f, 0xd6, 0xc6, 0x8c, 0x01, 0xf4, 0xa5, 0x05, 0xad, + 0x51, 0xed, 0x04, 0xd7, 0x55, 0xc0, 0x73, 0x05, 0x0e, 0x73, 0xe5, 0x39, + 0x45, 0x5b, 0x95, 0x4a, 0x34, 0x07, 0x99, 0xdf, 0x4c, 0x35, 0xf5, 0x0c, + 0x27, 0x6d, 0xd1, 0x45, 0xf1, 0xfd, 0x24, 0xb7, 0xfe, 0xea, 0x11, 0x5d, + 0xa2, 0xc5, 0xa6, 0x81, 0x37, 0x1d, 0xc2, 0x31, 0x31, 0xfc, 0xe0, 0xf4, + 0xd7, 0xe9, 0x98, 0x8b, 0xe3, 0x70, 0x51, 0x62, 0xc8, 0x61, 0x6d, 0xec, + 0x75, 0x56, 0x71, 0xae, 0x88, 0xe0, 0x80, 0xf5, 0xb7, 0x85, 0x10, 0xb7, + 0x3d, 0x16, 0x78, 0x5f, 0x72, 0xab, 0x8f, 0x63, 0xc6, 0xd5, 0xa8, 0xc9, + 0x9c, 0xef, 0x8d, 0x9a, 0xc5, 0x4f, 0x63, 0xad, 0xc0, 0xf3, 0x1f, 0x69, + 0x0e, 0xce, 0x29, 0x92, 0xc1, 0x3b, 0xb0, 0xc5, 0xed, 0x0a, 0x7b, 0x92, + 0xd0, 0x4c, 0x9c, 0x82, 0xb0, 0x51, 0xf6, 0x33, 0x61, 0x3b, 0x76, 0x48, + 0x38, 0xf4, 0x7c, 0xaa, 0x52, 0x87, 0x15, 0x1a, 0xbe, 0xb8, 0xdc, 0x9b, + 0x16, 0xd2, 0x07, 0xf7, 0xf9, 0x74, 0xe0, 0xaf, 0x0e, 0x29, 0x05, 0xec, + 0x6c, 0x0e, 0x3b, 0xa7, 0xe7, 0xa4, 0xfc, 0xa4, 0xef, 0x57, 0x16, 0x7f, + 0x13, 0xbd, 0x8c, 0x42, 0x02, 0x55, 0x70, 0x56, 0xa5, 0xa9, 0x01, 0x29, + 0x12, 0x7d, 0x80, 0x46, 0x18, 0x8e, 0x39, 0x3f, 0x44, 0x55, 0xec, 0xef, + 0x60, 0x58, 0x7d, 0xce, 0x64, 0x8e, 0x9c, 0xea, 0xe4, 0x73, 0xd1, 0x48, + 0x9c, 0x3f, 0x92, 0xa0, 0x9a, 0x76, 0xa5, 0x5a, 0x13, 0x1f, 0x10, 0xb9, + 0xb7, 0xb1, 0xde, 0x49, 0x22, 0x58, 0xf4, 0x43, 0x5f, 0x03, 0x43, 0xc3, + 0x6c, 0xbf, 0x82, 0xaf, 0x88, 0x39, 0xfd, 0xb2, 0x28, 0x9b, 0x47, 0x3f, + 0x83, 0x3d, 0xd9, 0x7c, 0xf0, 0xc9, 0xc5, 0xa2, 0xb4, 0xd6, 0x0d, 0x59, + 0x51, 0x27, 0x60, 0x10, 0x5e, 0xbb, 0x18, 0xa6, 0x42, 0x4a, 0x9d, 0xc4, + 0x16, 0x0e, 0xb6, 0x57, 0x23, 0x03, 0x24, 0x27, 0xdc, 0x20, 0x56, 0x30, + 0x8b, 0x0f, 0xb6, 0xb7, 0x73, 0xf5, 0x36, 0x3e, 0xf6, 0x7a, 0x71, 0xa5, + 0x57, 0xcc, 0x6d, 0xc6, 0xf3, 0xdc, 0x35, 0xfb, 0x95, 0xf7, 0xa7, 0xd7, + 0x56, 0x38, 0xd4, 0x15, 0xe2, 0xd5, 0x6f, 0x70, 0x30, 0xc8, 0x7d, 0x8a, + 0x87, 0xe6, 0xd1, 0xe0, 0x50, 0x62, 0xde, 0xfa, 0x29, 0x40, 0x97, 0xa0, + 0x54, 0x63, 0x31, 0xd3, 0x08, 0x87, 0x0a, 0xdc, 0x6e, 0x5e, 0xab, 0x8d, + 0x16, 0xaf, 0x6e, 0x8b, 0x1a, 0x77, 0xf6, 0xd4, 0xe0, 0xbf, 0x59, 0xab, + 0xc7, 0xb0, 0x45, 0x18, 0xaa, 0xe6, 0x65, 0x6f, 0x7d, 0x13, 0xb2, 0xbf, + 0xb3, 0x66, 0x72, 0xfa, 0xfd, 0xee, 0xad, 0x07, 0x56, 0x51, 0x6a, 0xe2, + 0xff, 0xb2, 0xaf, 0x4d, 0xd1, 0xf2, 0x77, 0x35, 0x5e, 0x90, 0xcd, 0xe7, + 0xa8, 0x32, 0x4d, 0x9f, 0xbd, 0xa8, 0xce, 0xab, 0xf1, 0x49, 0x98, 0xb5, + 0x23, 0x5c, 0x62, 0x2d, 0x43, 0x31, 0x80, 0x87, 0xc2, 0xa8, 0xf5, 0xb9, + 0xb6, 0xae, 0x7f, 0x37, 0x13, 0xb8, 0x6b, 0x73, 0xf3, 0x56, 0x38, 0xa7, + 0x9b, 0x97, 0x69, 0x37, 0x00, 0xdc, 0xff, 0xfe, 0x58, 0xc9, 0x12, 0x47, + 0x75, 0x98, 0x1f, 0xad, 0xd8, 0xb5, 0xc8, 0x47, 0x4f, 0xd0, 0x72, 0x63, + 0x54, 0x25, 0x6c, 0x88, 0xc9, 0x9f, 0x3c, 0x82, 0xe0, 0xdd, 0x4c, 0xff, + 0x8e, 0xaf, 0x8f, 0x8e, 0xea, 0x84, 0x3f, 0x73, 0xdd, 0x9e, 0x18, 0x73, + 0x47, 0x70, 0xc7, 0xc7, 0x99, 0x65, 0xcf, 0xf3, 0xb6, 0x24, 0xed, 0x97, + 0x8f, 0xcd, 0x93, 0x1e, 0xff, 0x6e, 0x9c, 0xf1, 0x30, 0x14, 0x1a, 0x27, + 0x59, 0x6a, 0x0e, 0xf3, 0xe4, 0xfa, 0x1d, 0x65, 0xb5, 0x53, 0xe4, 0xab, + 0xb1, 0x3e, 0xe1, 0x91, 0xf4, 0x6d, 0x99, 0xca, 0x7d, 0x03, 0x08, 0x50, + 0xea, 0xa9, 0x39, 0x7f, 0x6d, 0xe7, 0x43, 0xfb, 0x64, 0xcc, 0x4b, 0x9e, + 0xa0, 0x26, 0xe4, 0x0e, 0xff, 0xb7, 0x11, 0x0a, 0x29, 0x50, 0x90, 0xd7, + 0x4d, 0x62, 0x9a, 0x4a, 0x23, 0xb7, 0xd3, 0x53, 0xde, 0x3a, 0xd1, 0xba, + 0xd3, 0x10, 0x59, 0xc6, 0xc5, 0x5e, 0xac, 0xf9, 0x61, 0x74, 0x54, 0xf4, + 0x27, 0x9f, 0x9a, 0x61, 0x13, 0xdc, 0xe5, 0x96, 0xe3, 0x95, 0x0d, 0xcc, + 0xbd, 0x81, 0x74, 0x79, 0x73, 0xef, 0x2e, 0x0b, 0x0f, 0x91, 0x65, 0x3c, + 0x26, 0x7c, 0x47, 0x10, 0x31, 0x0b, 0xfb, 0x41, 0x0c, 0xc2, 0xa8, 0xc4, + 0x0e, 0xbd, 0x0a, 0x8c, 0xa4, 0x80, 0x45, 0x57, 0x62, 0x0b, 0x4d, 0x44, + 0x5e, 0x59, 0x77, 0xfd, 0x3d, 0xf3, 0xd7, 0x92, 0x49, 0xc1, 0xcb, 0x8a, + 0x54, 0x56, 0x3b, 0xde, 0xcf, 0x16, 0x9a, 0x65, 0xbe, 0xac, 0x64, 0xe1, + 0xd4, 0xd4, 0x1e, 0xac, 0x6b, 0x4a, 0xad, 0xc4, 0x33, 0xac, 0xcb, 0x83, + 0xf4, 0x4d, 0xe8, 0xb6, 0xd7, 0x23, 0xd7, 0x71, 0x25, 0xa2, 0x25, 0x3d, + 0x7e, 0xf0, 0x3b, 0x7f, 0x61, 0x11, 0x56, 0xd4, 0x83, 0xc8, 0xc0, 0x29, + 0x38, 0x10, 0x73, 0xad, 0x6a, 0xb7, 0xb9, 0xd2, 0x2e, 0x9f, 0xae, 0x16, + 0x5e, 0xa6, 0x13, 0x1c, 0xc2, 0x17, 0x73, 0x43, 0x03, 0xdd, 0xa6, 0xaf, + 0x9a, 0x17, 0x31, 0xb8, 0x86, 0x97, 0xc2, 0xd6, 0xe6, 0xed, 0xd4, 0xe1, + 0x7d, 0xb9, 0xa6, 0x96, 0xc1, 0x4b, 0xcb, 0x11, 0x1e, 0xe1, 0xe0, 0xd2, + 0x28, 0x69, 0x68, 0x3b, 0x21, 0x17, 0x63, 0x0c, 0xc0, 0x49, 0x30, 0x22, + 0x3a, 0x59, 0x72, 0xe6, 0x47, 0xb4, 0xdc, 0xa8, 0x29, 0x1c, 0x89, 0xa6, + 0x3a, 0x77, 0x99, 0xea, 0x46, 0xce, 0x38, 0xda, 0x31, 0x88, 0xad, 0xe7, + 0x26, 0xce, 0xc6, 0x56, 0x04, 0x30, 0xfa, 0x01, 0xac, 0xbb, 0xe2, 0xb8, + 0x23, 0xe4, 0x9d, 0x4f, 0x77, 0x02, 0x00, 0x28, 0xf1, 0xe0, 0x19, 0x3f, + 0x22, 0x4f, 0x22, 0x69, 0x87, 0xc0, 0x4e, 0x26, 0x33, 0xfe, 0x6c, 0x70, + 0x56, 0x3b, 0x60, 0x5f, 0xfb, 0xf8, 0x43, 0xcf, 0x3f, 0xb9, 0xcb, 0x80, + 0x22, 0xbb, 0x0a, 0xa8, 0x1c, 0x3e, 0x7e, 0x4d, 0x42, 0x60, 0x5c, 0x8e, + 0xfa, 0x42, 0xb3, 0x95, 0xe7, 0x92, 0x6b, 0xec, 0x7a, 0x95, 0x88, 0x98, + 0xe3, 0xf9, 0x0d, 0xe5, 0x08, 0xf1, 0x26, 0x96, 0x2a, 0x81, 0x2b, 0x7c, + 0x0d, 0x12, 0xa0, 0x7f, 0x7b, 0x39, 0xf6, 0xcc, 0x1b, 0x2d, 0x2c, 0xe9, + 0x5b, 0x02, 0x9b, 0x5c, 0x94, 0x51, 0x13, 0xe8, 0xa0, 0x19, 0xce, 0xde, + 0x07, 0x1b, 0xda, 0x39, 0x14, 0xb5, 0x8b, 0xcf, 0x79, 0x3e, 0x2b, 0xb8, + 0x75, 0xab, 0x81, 0xee, 0x5e, 0x08, 0x33, 0xc3, 0x49, 0x5b, 0x4a, 0x9c, + 0x74, 0x34, 0xde, 0x08, 0x61, 0x03, 0x38, 0xe3, 0xd8, 0xff, 0xc5, 0xc0, + 0xb5, 0x40, 0xd5, 0x26, 0x57, 0x85, 0xf1, 0xb7, 0x77, 0xb6, 0x36, 0xe0, + 0x8d, 0x43, 0x3a, 0xef, 0xfe, 0x0f, 0xf7, 0xee, 0x67, 0x6c, 0x7b, 0xd1, + 0x83, 0xf6, 0x10, 0xda, 0x67, 0x04, 0x3a, 0x27, 0xd8, 0x3a, 0xcb, 0x9d, + 0x4c, 0xa6, 0x9a, 0xc7, 0xea, 0x07, 0xc6, 0x76, 0x79, 0x1b, 0x23, 0x4a, + 0x68, 0x2f, 0x14, 0x84, 0x42, 0x79, 0xe8, 0x1f, 0xf2, 0xe6, 0xac, 0x72, + 0xb0, 0xb0, 0xb6, 0x39, 0x95, 0x40, 0xa4, 0x6e, 0x54, 0x2e, 0xb7, 0xb5, + 0x13, 0x70, 0x48, 0x0d, 0x27, 0xed, 0x2c, 0xa2, 0x64, 0x53, 0xb4, 0x04, + 0x84, 0xab, 0xd8, 0xea, 0x2a, 0x8c, 0xac, 0x5b, 0x1d, 0xb8, 0xb2, 0xbe, + 0x55, 0x2b, 0x4a, 0x47, 0xfc, 0xe0, 0x15, 0x78, 0xb6, 0xd6, 0xff, 0x20, + 0xa8, 0x8a, 0xec, 0x8b, 0x30, 0xef, 0xc5, 0xc6, 0xec, 0xa0, 0xdf, 0xd3, + 0xc4, 0x2b, 0x4a, 0xdf, 0xef, 0x5c, 0x46, 0xb3, 0x31, 0xc7, 0x5f, 0x8f, + 0x1e, 0x99, 0x76, 0x81, 0x71, 0x61, 0xdb, 0xc3, 0xc4, 0x0f, 0x66, 0x7b, + 0xd7, 0x44, 0xc7, 0x8d, 0x12, 0x38, 0x71, 0x7c, 0xd8, 0x41, 0xf6, 0x8a, + 0xb9, 0xba, 0xd2, 0x1f, 0xa1, 0x27, 0x64, 0x67, 0x51, 0xb2, 0xaf, 0xea, + 0x02, 0x95, 0x79, 0x20, 0x0a, 0xc8, 0xaa, 0x03, 0x11, 0xb6, 0x8b, 0x7d, + 0x86, 0xb7, 0xef, 0x5e, 0x3f, 0x0b, 0x91, 0x47, 0xf0, 0x43, 0xb4, 0x54, + 0x1d, 0x16, 0x66, 0xe9, 0x63, 0x1a, 0x55, 0xaf, 0x34, 0xad, 0x11, 0x68, + 0x4d, 0x36, 0xb7, 0x0c, 0x6d, 0x4d, 0xed, 0xba, 0x14, 0xe8, 0xf6, 0xe2, + 0x15, 0x64, 0xb6, 0x15, 0x28, 0xbf, 0xd2, 0x4d, 0xb6, 0x6f, 0xca, 0x5f, + 0x81, 0x1b, 0xf0, 0x31, 0xf5, 0xd3, 0xe0, 0x06, 0xc7, 0xf3, 0x0c, 0x18, + 0x91, 0x45, 0x22, 0xa2, 0x30, 0x48, 0x82, 0xeb, 0x42, 0xfc, 0x8f, 0x2a, + 0xa3, 0x1a, 0x8d, 0x84, 0x28, 0x20, 0x16, 0x95, 0xd9, 0x66, 0x67, 0x2b, + 0xef, 0xc6, 0x6e, 0x56, 0x1c, 0x62, 0x74, 0x16, 0x5c, 0x3e, 0x17, 0xd0, + 0xb7, 0xdd, 0x70, 0xb6, 0x0e, 0x79, 0x46, 0xc5, 0x4e, 0x72, 0x46, 0x69, + 0xf5, 0xa1, 0x1c, 0x7b, 0xd5, 0x67, 0x5c, 0xb3, 0x46, 0x4d, 0x18, 0x31, + 0x47, 0x42, 0x20, 0xe6, 0x12, 0x84, 0x4e, 0x16, 0x0f, 0x4a, 0xd0, 0xc4, + 0x91, 0xa3, 0xbd, 0x91, 0xcd, 0x86, 0x4c, 0xcd, 0x4b, 0x2e, 0x62, 0x84, + 0xea, 0x19, 0x2d, 0x21, 0x1a, 0x64, 0xc4, 0xd2, 0x24, 0x92, 0x96, 0x04, + 0x66, 0xb5, 0x4a, 0xe4, 0xa9, 0xd6, 0xaf, 0x12, 0x9b, 0xb5, 0x59, 0xe0, + 0x5c, 0x84, 0x84, 0x7c, 0x68, 0x99, 0xd8, 0x23, 0xa2, 0x15, 0xa7, 0x82, + 0xa5, 0x66, 0x95, 0x8f, 0xfe, 0x57, 0xc1, 0x12, 0x6c, 0x89, 0xe5, 0x5b, + 0x5d, 0x64, 0xdb, 0x81, 0x4f, 0x77, 0x3c, 0xc8, 0x52, 0x4e, 0x2a, 0xd6, + 0x74, 0x3c, 0x4b, 0x11, 0xfc, 0xc1, 0x7c, 0x01, 0xba, 0x0f, 0x0f, 0x57, + 0x8a, 0xbe, 0x5b, 0x16, 0x88, 0x96, 0xe6, 0xe9, 0x60, 0xcf, 0x66, 0xe9, + 0xe6, 0x07, 0xb0, 0x0b, 0xa3, 0xa0, 0xad, 0xdf, 0x70, 0xd4, 0xcb, 0x2e, + 0x33, 0x2f, 0xe5, 0xf2, 0x1e, 0x0d, 0x74, 0x7a, 0xf9, 0x4a, 0x0f, 0x32, + 0xb4, 0xa1, 0xc9, 0xf5, 0x3f, 0x0a, 0x06, 0xf9, 0x67, 0x45, 0x9c, 0xd9, + 0x58, 0xd4, 0x0e, 0x72, 0x55, 0x47, 0x49, 0x9b, 0xab, 0x9c, 0x66, 0xe7, + 0x4d, 0x9a, 0x02, 0x1b, 0x41, 0xad, 0xe5, 0x8c, 0x7f, 0xa1, 0xdc, 0xad, + 0xcd, 0x74, 0xda, 0x9f, 0xfa, 0x87, 0x32, 0xc1, 0x07, 0x8e, 0x9b, 0xef, + 0x28, 0x2f, 0x17, 0x6d, 0xdb, 0x84, 0x4b, 0xa8, 0x7d, 0x31, 0xa8, 0x32, + 0xe4, 0x9a, 0x1e, 0x0e, 0xef, 0x68, 0xf4, 0xac, 0x03, 0x6c, 0x68, 0xcc, + 0x28, 0xbb, 0xfb, 0x21, 0xb8, 0x11, 0xd7, 0xf9, 0xe8, 0x24, 0x37, 0xdf, + 0xe0, 0xb2, 0xef, 0xd6, 0xec, 0xdf, 0xcf, 0xf5, 0x50, 0x19, 0xa3, 0xa9, + 0x1b, 0x01, 0x2e, 0x94, 0x42, 0xb0, 0x14, 0x5d, 0x0e, 0x37, 0x46, 0x4a, + 0x52, 0x53, 0x60, 0x6b, 0x89, 0xc9, 0xca, 0xed, 0x0a, 0x0c, 0x18, 0x33, + 0x3c, 0x40, 0x42, 0x76, 0x7a, 0x7d, 0xb6, 0x10, 0x29, 0x3e, 0x42, 0x75, + 0xa6, 0xbf, 0xcb, 0xd3, 0xdc, 0xe1, 0x00, 0x05, 0x08, 0x25, 0x67, 0x6c, + 0x72, 0xde, 0x26, 0x72, 0x88, 0xbe, 0xfa, 0x05, 0x57, 0x77, 0x78, 0x83, + 0xce, 0xd5, 0x44, 0x49, 0x8b, 0xab, 0xbc, 0xca, 0xd3, 0x1c, 0x34, 0x4a, + 0xaa, 0xc7, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x17, 0x22, 0x2a, 0x2f, 0x36, 0x3d, 0x43}; +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_KEYGEN_PCT */ +#endif /* !EXPECTED_SIGNATURES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/main.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/main.c new file mode 100644 index 0000000000..401e62c128 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/main.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include +#include +#include +#include + +/* Import public mldsa-native API + * + * This requires specifying the parameter set and namespace prefix + * used for the build. + */ +#include +#include "expected_signatures.h" +#include "test_only_rng/notrandombytes.h" + +#define CHECK(x) \ + do \ + { \ + int rc; \ + rc = (x); \ + if (!rc) \ + { \ + fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \ + return 1; \ + } \ + } while (0) + +#define TEST_MSG \ + "This is a test message for ML-DSA digital signature algorithm!" +#define TEST_MSG_LEN (sizeof(TEST_MSG) - 1) + +#define TEST_CTX "test_context_123" +#define TEST_CTX_LEN (sizeof(TEST_CTX) - 1) + +int main(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t sig[CRYPTO_BYTES]; + uint8_t sm[TEST_MSG_LEN + CRYPTO_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + CRYPTO_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-%d Basic Example\n", MLD_CONFIG_PARAMETER_SET); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(crypto_sign_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(crypto_sign_signature(sig, &siglen, (const uint8_t *)test_msg, + TEST_MSG_LEN, (const uint8_t *)test_ctx, + TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(crypto_sign_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(crypto_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(crypto_sign_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", CRYPTO_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", CRYPTO_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", CRYPTO_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature)); + CHECK(memcmp(sig, expected_signature, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/mldsa_native.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/mldsa_native.h new file mode 100644 index 0000000000..fd150a9df1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/mldsa_native.h @@ -0,0 +1,975 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_H +#define MLD_H + +/* + * Public API for mldsa-native + * + * This header defines the public API of a single build of mldsa-native. + * + * Make sure the configuration file is in the include path + * (this is "mldsa_native_config.h" by default, or MLD_CONFIG_FILE if defined). + * + * # Multi-level builds + * + * This header specifies a build of mldsa-native for a fixed security level. + * If you need multiple security levels, leave the security level unspecified + * in the configuration file and include this header multiple times, setting + * MLD_CONFIG_PARAMETER_SET accordingly for each, and #undef'ing the MLD_H + * guard to allow multiple inclusions. + * + * # Legacy configuration (deprecated) + * + * Instead of providing the config file used for the build, you can + * alternatively set the following configuration options prior to + * including this header. + * + * This method of configuration is deprecated. + * It will be removed in mldsa-native-v2. + * + * - MLD_CONFIG_API_PARAMETER_SET [required] + * + * The parameter set used for the build; 44, 65, or 87. + * + * - MLD_CONFIG_API_NAMESPACE_PREFIX [required] + * + * The namespace prefix used for the build. + * + * NOTE: + * For a multi-level build, you must include the 44/65/87 suffixes + * in MLD_CONFIG_API_NAMESPACE_PREFIX. + * + * - MLD_CONFIG_API_NO_SUPERCOP [optional] + * + * By default, this header will also expose the mldsa-native API in the + * SUPERCOP naming convention crypto_sign_xxx. If you don't want/need this, + * set MLD_CONFIG_API_NO_SUPERCOP. You must set this for a multi-level build. + * + * - MLD_CONFIG_API_CONSTANTS_ONLY [optional] + * + * If you don't want this header to expose any function declarations, + * but only constants for the sizes of key material, set + * MLD_CONFIG_API_CONSTANTS_ONLY. In this case, you don't need to set + * MLD_CONFIG_API_PARAMETER_SET or MLD_CONFIG_API_NAMESPACE_PREFIX, + * nor include a configuration. + * + * - MLD_CONFIG_API_QUALIFIER [optional] + * + * Qualifier to apply to external API. + * + ******************************************************************************/ + +/******************************* Key sizes ************************************/ + +/* Sizes of cryptographic material, per parameter set */ +/* See mldsa/src/params.h for the arithmetic expressions giving rise to these */ +/* check-magic: off */ +#define MLDSA44_SECRETKEYBYTES 2560 +#define MLDSA44_PUBLICKEYBYTES 1312 +#define MLDSA44_BYTES 2420 + +#define MLDSA65_SECRETKEYBYTES 4032 +#define MLDSA65_PUBLICKEYBYTES 1952 +#define MLDSA65_BYTES 3309 + +#define MLDSA87_SECRETKEYBYTES 4896 +#define MLDSA87_PUBLICKEYBYTES 2592 +#define MLDSA87_BYTES 4627 +/* check-magic: on */ + +/* Size of seed and randomness in bytes (level-independent) */ +#define MLDSA_SEEDBYTES 32 +#define MLDSA44_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA65_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA87_SEEDBYTES MLDSA_SEEDBYTES + +/* Size of CRH output in bytes (level-independent) */ +#define MLDSA_CRHBYTES 64 +#define MLDSA44_CRHBYTES MLDSA_CRHBYTES +#define MLDSA65_CRHBYTES MLDSA_CRHBYTES +#define MLDSA87_CRHBYTES MLDSA_CRHBYTES + +/* Size of TR output in bytes (level-independent) */ +#define MLDSA_TRBYTES 64 +#define MLDSA44_TRBYTES MLDSA_TRBYTES +#define MLDSA65_TRBYTES MLDSA_TRBYTES +#define MLDSA87_TRBYTES MLDSA_TRBYTES + +/* Size of randomness for signing in bytes (level-independent) */ +#define MLDSA_RNDBYTES 32 +#define MLDSA44_RNDBYTES MLDSA_RNDBYTES +#define MLDSA65_RNDBYTES MLDSA_RNDBYTES +#define MLDSA87_RNDBYTES MLDSA_RNDBYTES + +/* Sizes of cryptographic material, as a function of LVL=44,65,87 */ +#define MLDSA_SECRETKEYBYTES_(LVL) MLDSA##LVL##_SECRETKEYBYTES +#define MLDSA_PUBLICKEYBYTES_(LVL) MLDSA##LVL##_PUBLICKEYBYTES +#define MLDSA_BYTES_(LVL) MLDSA##LVL##_BYTES +#define MLDSA_SECRETKEYBYTES(LVL) MLDSA_SECRETKEYBYTES_(LVL) +#define MLDSA_PUBLICKEYBYTES(LVL) MLDSA_PUBLICKEYBYTES_(LVL) +#define MLDSA_BYTES(LVL) MLDSA_BYTES_(LVL) + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + +/****************************** Function API **********************************/ + +#define MLD_API_CONCAT_(x, y) x##y +#define MLD_API_CONCAT(x, y) MLD_API_CONCAT_(x, y) +#define MLD_API_CONCAT_UNDERSCORE(x, y) MLD_API_CONCAT(MLD_API_CONCAT(x, _), y) + +#if !defined(MLD_CONFIG_API_PARAMETER_SET) +/* Recommended configuration via same config file as used for the build. */ + +/* For now, we derive the legacy API configuration MLD_CONFIG_API_XXX from + * the config file. In mldsa-native-v2, this will be removed and we will + * exclusively work with MLD_CONFIG_XXX. */ + +/* You need to make sure the config file is in the include path. */ +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#define MLD_CONFIG_API_PARAMETER_SET MLD_CONFIG_PARAMETER_SET + +#if defined(MLD_CONFIG_MULTILEVEL_BUILD) +#define MLD_CONFIG_API_NAMESPACE_PREFIX \ + MLD_API_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_CONFIG_API_NAMESPACE_PREFIX MLD_CONFIG_NAMESPACE_PREFIX +#endif + +#if defined(MLD_CONFIG_NO_SUPERCOP) +#define MLD_CONFIG_API_NO_SUPERCOP +#endif + +#if defined(MLD_CONFIG_CONSTANTS_ONLY) +#define MLD_CONFIG_API_CONSTANTS_ONLY +#endif + +#if defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_CONFIG_API_QUALIFIER MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#else /* !MLD_CONFIG_API_PARAMETER_SET */ +#define MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_PARAMETER_SET */ + +#define MLD_API_NAMESPACE(sym) \ + MLD_API_CONCAT_UNDERSCORE(MLD_CONFIG_API_NAMESPACE_PREFIX, sym) + +#if defined(__GNUC__) || defined(clang) +#define MLD_API_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_API_MUST_CHECK_RETURN_VALUE +#endif + +#if defined(MLD_CONFIG_API_QUALIFIER) +#define MLD_API_QUALIFIER MLD_CONFIG_API_QUALIFIER +#else +#define MLD_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_API_CONSTANTS_ONLY) + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************************* + * Name: crypto_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: + * input random seed + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair_internal)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t seed[MLDSA_SEEDBYTES] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: If MLD_CONFIG_KEYGEN_PCT is enabled and the + * PCT check failed. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return -1 in that case. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_extmu + * + * Description: Computes signature. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_extmu)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t *sm: pointer to output signed message (allocated array + * with MLDSA{44,65,87}_BYTES + mlen bytes), can be + * equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(sign)( + uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_extmu)( + const uint8_t *sig, size_t siglen, const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_open + * + * Description: Verify signed message. + * + * Arguments: + * - uint8_t *m: pointer to output message (allocated array with + * smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(open)( + uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: crypto_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *ph, size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_shake256)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_shake256)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/* Maximum formatted domain separation message length */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +size_t MLD_API_NAMESPACE(prepare_domain_separation_prefix)( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg); + +/************************************************* + * Name: crypto_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[CRYPTO_SECRETKEYBYTES]: input secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(pk_from_sk)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +#ifdef __cplusplus +} +#endif + +/****************************** SUPERCOP API *********************************/ + +#if !defined(MLD_CONFIG_API_NO_SUPERCOP) +/* Export API in SUPERCOP naming scheme CRYPTO_xxx / crypto_sign_xxx */ +#define CRYPTO_SECRETKEYBYTES MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_PUBLICKEYBYTES MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_BYTES MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET) + +#define crypto_sign_keypair MLD_API_NAMESPACE(keypair) +#define crypto_sign_signature MLD_API_NAMESPACE(signature) +#define crypto_sign MLD_API_NAMESPACE(sign) +#define crypto_sign_verify MLD_API_NAMESPACE(verify) +#define crypto_sign_open MLD_API_NAMESPACE(open) + +#else /* !MLD_CONFIG_API_NO_SUPERCOP */ + +/* If the SUPERCOP API is not needed, we can undefine the various helper macros + * above. Otherwise, they are needed for lazy evaluation of crypto_sign_xxx. */ +#if !defined(MLD_API_LEGACY_CONFIG) +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_QUALIFIER +#endif /* !MLD_API_LEGACY_CONFIG */ + +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_NAMESPACE +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_QUALIFIER +#undef MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_NO_SUPERCOP */ +#endif /* !MLD_CONFIG_API_CONSTANTS_ONLY */ + + +/***************************** Memory Usage **********************************/ + +/* + * By default mldsa-native performs all memory allocations on the stack. + * Alternatively, mldsa-native supports custom allocation of large structures + * through the `MLD_CONFIG_CUSTOM_ALLOC_FREE` configuration option. + * See mldsa_native_config.h for details. + * + * `MLD_TOTAL_ALLOC_{44,65,87}_{KEYPAIR,SIGN,VERIFY}` indicates the maximum + * (accumulative) allocation via MLD_ALLOC for each parameter set and operation. + * Note that some stack allocation remains even + * when using custom allocators, so these values are lower than total stack + * usage with the default stack-only allocation. + * + * These constants may be used to implement custom allocations using a + * fixed-sized buffer and a simple allocator (e.g., bump allocator). + */ +/* check-magic: off */ +#if defined(MLD_API_LEGACY_CONFIG) || !defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 45248 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 56640 +#define MLD_TOTAL_ALLOC_44_SIGN 52896 +#define MLD_TOTAL_ALLOC_44_VERIFY 38816 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 71872 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 85856 +#define MLD_TOTAL_ALLOC_65_SIGN 80576 +#define MLD_TOTAL_ALLOC_65_VERIFY 62432 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 112832 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 130816 +#define MLD_TOTAL_ALLOC_87_SIGN 123584 +#define MLD_TOTAL_ALLOC_87_VERIFY 99552 +#else /* MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM */ +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 32992 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 36192 +#define MLD_TOTAL_ALLOC_44_SIGN 32448 +#define MLD_TOTAL_ALLOC_44_VERIFY 22464 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 46304 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 50048 +#define MLD_TOTAL_ALLOC_65_SIGN 44768 +#define MLD_TOTAL_ALLOC_65_VERIFY 30720 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 62688 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 66336 +#define MLD_TOTAL_ALLOC_87_SIGN 59104 +#define MLD_TOTAL_ALLOC_87_VERIFY 41216 +#endif /* !(MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM) */ +/* check-magic: on */ + +/* + * MLD_TOTAL_ALLOC_*_KEYPAIR adapts based on MLD_CONFIG_KEYGEN_PCT. + * For legacy config, we don't know which options are used, so assume + * the worst case (PCT enabled). + */ +#if defined(MLD_API_LEGACY_CONFIG) || defined(MLD_CONFIG_KEYGEN_PCT) +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#else +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#endif + +#define MLD_MAX3_(a, b, c) \ + ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c))) + +/* + * `MLD_TOTAL_ALLOC_{44,65,87}` is the maximum across all operations for each + * parameter set. + */ +#define MLD_TOTAL_ALLOC_44 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_44_KEYPAIR, MLD_TOTAL_ALLOC_44_SIGN, \ + MLD_TOTAL_ALLOC_44_VERIFY) +#define MLD_TOTAL_ALLOC_65 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_65_KEYPAIR, MLD_TOTAL_ALLOC_65_SIGN, \ + MLD_TOTAL_ALLOC_65_VERIFY) +#define MLD_TOTAL_ALLOC_87 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_87_KEYPAIR, MLD_TOTAL_ALLOC_87_SIGN, \ + MLD_TOTAL_ALLOC_87_VERIFY) + +#endif /* !MLD_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/mldsa_native_config.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/mldsa_native_config.h new file mode 100644 index 0000000000..25dc887718 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/mldsa_native_config.h @@ -0,0 +1,723 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_CONFIG_H +#define MLD_CONFIG_H + +/****************************************************************************** + * Name: MLD_CONFIG_PARAMETER_SET + * + * Description: Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * If you want to support multiple parameter sets, build the + * library multiple times and set MLD_CONFIG_MULTILEVEL_BUILD. + * See MLD_CONFIG_MULTILEVEL_BUILD for how to do this while + * minimizing code duplication. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of the default configuration file mldsa/mldsa_native_config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * then configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + * + *****************************************************************************/ +/* #define MLD_CONFIG_FILE "mldsa_native_config.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_NAMESPACE_PREFIX + * + * Description: The prefix to use to namespace global symbols from mldsa/. + * + * In a multi-level build, level-dependent symbols will + * additionally be prefixed with the parameter set (44/65/87). + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_NAMESPACE_PREFIX) +#define MLD_CONFIG_NAMESPACE_PREFIX MLD_DEFAULT_NAMESPACE_PREFIX +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_BUILD + * + * Description: Set this if the build is part of a multi-level build supporting + * multiple parameter sets. + * + * If you need only a single parameter set, keep this unset. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them. + * + * See examples/multilevel_build for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_BUILD */ + +/****************************************************************************** + * Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_EXTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_RANDOMIZED_API + * + * Description: If this option is set, mldsa-native will be built without the + * randomized API functions (crypto_sign_keypair, + * crypto_sign, crypto_sign_signature, and + * crypto_sign_signature_extmu). + * This allows users to build mldsa-native without providing a + * randombytes() implementation if they only need the + * internal deterministic API + * (crypto_sign_keypair_internal, crypto_sign_signature_internal). + * + * NOTE: This option is incompatible with MLD_CONFIG_KEYGEN_PCT + * as the current PCT implementation requires + * crypto_sign_signature(). + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_RANDOMIZED_API */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_SUPERCOP + * + * Description: By default, mldsa_native.h exposes the mldsa-native API in the + * SUPERCOP naming convention (crypto_sign_xxx). If you don't need + * this, set MLD_CONFIG_NO_SUPERCOP. + * + * NOTE: You must set this for a multi-level build as the SUPERCOP + * naming does not disambiguate between the parameter sets. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_SUPERCOP */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONSTANTS_ONLY + * + * Description: If you only need the size constants (MLDSA_PUBLICKEYBYTES, etc.) + * but no function declarations, set MLD_CONFIG_CONSTANTS_ONLY. + * + * This only affects the public header mldsa_native.h, not + * the implementation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONSTANTS_ONLY */ + +/****************************************************************************** + * + * Build-only configuration options + * + * The remaining configurations are build-options only. + * They do not affect the API described in mldsa_native.h. + * + *****************************************************************************/ + +#if defined(MLD_BUILD_INTERNAL) +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_WITH_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, all MLD_CONFIG_PARAMETER_SET-independent + * code will be included in the build, including code needed only + * for other parameter sets. + * + * Example: TODO: add example + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_WITH_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_NO_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, no MLD_CONFIG_PARAMETER_SET-independent code + * will be included in the build. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * + * Description: This is only relevant for single compilation unit (SCU) + * builds of mldsa-native. In this case, it determines whether + * directives defined in parameter-set-independent headers should + * be #undef'ined or not at the of the SCU file. This is needed + * in multilevel builds. + * + * See examples/multilevel_build_native for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * + * Description: Determines whether an native arithmetic backend should be used. + * + * The arithmetic backend covers performance critical functions + * such as the number-theoretic transform (NTT). + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the arithmetic backend to be use is + * determined by MLD_CONFIG_ARITH_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_ARITH_BACKEND_FILE + * + * Description: The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * + * Description: Determines whether an native FIPS202 backend should be used. + * + * The FIPS202 backend covers 1x/2x/4x-fold Keccak-f1600, which is + * the performance bottleneck of SHA3 and SHAKE. + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the FIPS202 backend to be use is + * determined by MLD_CONFIG_FIPS202_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_BACKEND_FILE + * + * Description: The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202X4_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202-X4 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202x4.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ZEROIZE + * + * Description: In compliance with @[FIPS204, Section 3.6.3], mldsa-native, + * zeroizes intermediate stack buffers before returning from + * function calls. + * + * Set this option and define `mld_zeroize` if you want to + * use a custom method to zeroize intermediate stack buffers. + * The default implementation uses SecureZeroMemory on Windows + * and a memset + compiler barrier otherwise. If neither of those + * is available on the target platform, compilation will fail, + * and you will need to use MLD_CONFIG_CUSTOM_ZEROIZE to provide + * a custom implementation of `mld_zeroize()`. + * + * WARNING: + * The explicit stack zeroization conducted by mldsa-native + * reduces the likelihood of data leaking on the stack, but + * does not eliminate it! The C standard makes no guarantee about + * where a compiler allocates structures and whether/where it makes + * copies of them. Also, in addition to entire structures, there + * may also be potentially exploitable leakage of individual values + * on the stack. + * + * If you need bullet-proof zeroization of the stack, you need to + * consider additional measures instead of what this feature + * provides. In this case, you can set mld_zeroize to a + * no-op. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void mld_zeroize(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * Description: mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to provided by the + * consumer. + * + * If this option is not set, mldsa-native expects a function + * int randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mld_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_RANDOMBYTES + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) + { + ... your implementation ... + return 0; + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + * + * Description: mldsa-native backends may rely on specific hardware features. + * Those backends will only be included in an mldsa-native build + * if support for the respective features is enabled at + * compile-time. However, when building for a heteroneous set + * of CPUs to run the resulting binary/library on, feature + * detection at _runtime_ is needed to decided whether a backend + * can be used or not. + * + * Set this option and define `mld_sys_check_capability` if you + * want to use a custom method to dispatch between implementations. + * + * Return value 1 indicates that a capability is supported. + * Return value 0 indicates that a capability is not supported. + * + * If this option is not set, mldsa-native uses compile-time + * feature detection only to decide which backend to use. + * + * If you compile mldsa-native on a system with different + * capabilities than the system that the resulting binary/library + * will be run on, you must use this option. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) + { + ... your implementation ... + } +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ALLOC_FREE [EXPERIMENTAL] + * + * Description: Set this option and define `MLD_CUSTOM_ALLOC` and + * `MLD_CUSTOM_FREE` if you want to use custom allocation for + * large local structures or buffers. + * + * By default, all buffers/structures are allocated on the stack. + * If this option is set, most of them will be allocated via + * MLD_CUSTOM_ALLOC. + * + * Parameters to MLD_CUSTOM_ALLOC: + * - T* v: Target pointer to declare. + * - T: Type of structure to be allocated + * - N: Number of elements to be allocated. + * + * Parameters to MLD_CUSTOM_FREE: + * - T* v: Target pointer to free. May be NULL. + * - T: Type of structure to be freed. + * - N: Number of elements to be freed. + * + * WARNING: This option is experimental! + * Its scope, configuration and function/macro signatures may + * change at any time. We expect a stable API for v2. + * + * NOTE: Even if this option is set, some allocations further down + * the call stack will still be made from the stack. Those will + * likely be added to the scope of this option in the future. + * + * NOTE: MLD_CUSTOM_ALLOC need not guarantee a successful + * allocation nor include error handling. Upon failure, the + * target pointer should simply be set to NULL. The calling + * code will handle this case and invoke MLD_CUSTOM_FREE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ALLOC_FREE + #if !defined(__ASSEMBLER__) + #include + #define MLD_CUSTOM_ALLOC(v, T, N) \ + T* (v) = (T *)aligned_alloc(MLD_DEFAULT_ALIGN, \ + MLD_ALIGN_UP(sizeof(T) * (N))) + #define MLD_CUSTOM_FREE(v, T, N) free(v) + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMCPY + * + * Description: Set this option and define `mld_memcpy` if you want to + * use a custom method to copy memory instead of the standard + * library memcpy function. + * + * The custom implementation must have the same signature and + * behavior as the standard memcpy function: + * void *mld_memcpy(void *dest, const void *src, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMCPY + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMSET + * + * Description: Set this option and define `mld_memset` if you want to + * use a custom method to set memory instead of the standard + * library memset function. + * + * The custom implementation must have the same signature and + * behavior as the standard memset function: + * void *mld_memset(void *s, int c, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMSET + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memset(void *s, int c, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_INTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of internal API. + * + * The primary use case for this option are single-CU builds, + * in which case this option can be set to `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_INTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CT_TESTING_ENABLED + * + * Description: If set, mldsa-native annotates data as secret / public using + * valgrind's annotations VALGRIND_MAKE_MEM_UNDEFINED and + * VALGRIND_MAKE_MEM_DEFINED, enabling various checks for secret- + * dependent control flow of variable time execution (depending + * on the exact version of valgrind installed). + * + *****************************************************************************/ +/* #define MLD_CONFIG_CT_TESTING_ENABLED */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * and MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT + * + * Description: Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, crypto_sign_keypair_internal and + * crypto_sign_keypair will return a non-zero error code if the + * PCT failed. + * + * NOTE: This feature will drastically lower the performance of + * key generation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * Description: If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "src/src.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Description: Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * NOTE: Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + * + *****************************************************************************/ +/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER + * + * Description: Set this to add a context parameter that is provided to public + * API functions and is then available in custom callbacks. + * + * The type of the context parameter is configured via + * MLD_CONFIG_CONTEXT_PARAMETER_TYPE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER_TYPE + * + * Description: Set this to define the type for the context parameter used by + * MLD_CONFIG_CONTEXT_PARAMETER. + * + * This is only relevant if MLD_CONFIG_CONTEXT_PARAMETER is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER_TYPE void* */ + +/****************************************************************************** + * Name: MLD_CONFIG_REDUCE_RAM [EXPERIMENTAL] + * + * Description: Set this to reduce RAM usage. + * This trades memory for performance. + * + * For expected memory usage, see the MLD_TOTAL_ALLOC_* constants + * defined in mldsa_native.h. + * + * This option is useful for embedded systems with tight RAM + * constraints but relaxed performance requirements. + * + * WARNING: This option is experimental! + * CBMC proofs do not currently cover this configuration option. + * Its scope and configuration may change at any time. + * + *****************************************************************************/ +/* #define MLD_CONFIG_REDUCE_RAM */ + +/************************* Config internals ********************************/ + +#endif /* MLD_BUILD_INTERNAL */ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace is + * + * PQCP_MLDSA_NATIVE_MLDSA_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_ + */ + +#if MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65 +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87 +#endif + +#endif /* !MLD_CONFIG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/cbmc.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/cbmc.h new file mode 100644 index 0000000000..8ed1ecb06b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/cbmc.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_CBMC_H +#define MLD_CBMC_H +/*************************************************** + * Basic replacements for __CPROVER_XXX contracts + ***************************************************/ +#ifndef CBMC + +#define __contract__(x) +#define __loop__(x) +#define cassert(x) + +#else /* !CBMC */ + +#include + +#define __contract__(x) x +#define __loop__(x) x + +/* https://diffblue.github.io/cbmc/contracts-assigns.html */ +#define assigns(...) __CPROVER_assigns(__VA_ARGS__) + +/* https://diffblue.github.io/cbmc/contracts-requires-ensures.html */ +#define requires(...) __CPROVER_requires(__VA_ARGS__) +#define ensures(...) __CPROVER_ensures(__VA_ARGS__) +/* https://diffblue.github.io/cbmc/contracts-loops.html */ +#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__) +#define decreases(...) __CPROVER_decreases(__VA_ARGS__) +/* cassert to avoid confusion with in-built assert */ +#define cassert(x) __CPROVER_assert(x, "cbmc assertion failed") +#define assume(...) __CPROVER_assume(__VA_ARGS__) + +/*************************************************** + * Macros for "expression" forms that may appear + * _inside_ top-level contracts. + ***************************************************/ + +/* + * function return value - useful inside ensures + * https://diffblue.github.io/cbmc/contracts-functions.html + */ +#define return_value (__CPROVER_return_value) + +/* + * assigns l-value targets + * https://diffblue.github.io/cbmc/contracts-assigns.html + */ +#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__) +#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__) +#define same_object(...) __CPROVER_same_object(__VA_ARGS__) + +/* + * Pointer-related predicates + * https://diffblue.github.io/cbmc/contracts-memory-predicates.html + */ +#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__) +#define readable(...) __CPROVER_r_ok(__VA_ARGS__) +#define writeable(...) __CPROVER_w_ok(__VA_ARGS__) + +/* Maximum supported buffer size + * + * Larger buffers may be supported, but due to internal modeling constraints + * in CBMC, the proofs of memory- and type-safety won't be able to run. + * + * If you find yourself in need for a buffer size larger than this, + * please contact the maintainers, so we can prioritize work to relax + * this somewhat artificial bound. + */ +#define MLD_MAX_BUFFER_SIZE (SIZE_MAX >> 12) + + +/* + * History variables + * https://diffblue.github.io/cbmc/contracts-history-variables.html + */ +#define old(...) __CPROVER_old(__VA_ARGS__) +#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__) + +/* + * Quantifiers + * Note that the range on qvar is _exclusive_ between qvar_lb .. qvar_ub + * https://diffblue.github.io/cbmc/contracts-quantifiers.html + */ + +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define forall(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> (predicate) \ + } + +#define exists(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_exists \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) && (predicate) \ + } +/* clang-format on */ + +/*************************************************** + * Convenience macros for common contract patterns + ***************************************************/ +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define CBMC_CONCAT_(left, right) left##right +#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right) + +#define array_bound_core(qvar, qvar_lb, qvar_ub, array_var, \ + value_lb, value_ub) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + (((int)(value_lb) <= ((array_var)[(qvar)])) && \ + (((array_var)[(qvar)]) < (int)(value_ub))) \ + } + +#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \ + array_bound_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (qvar_lb), \ + (qvar_ub), (array_var), (value_lb), (value_ub)) + +#define array_unchanged_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (int32_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged(array_var, N) \ + array_unchanged_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) + +#define array_unchanged_u64_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (uint64_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged_u64(array_var, N) \ + array_unchanged_u64_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) +/* clang-format on */ + +/* Wrapper around array_bound operating on absolute values. + * + * The absolute value bound `k` is exclusive. + * + * Note that since the lower bound in array_bound is inclusive, we have to + * raise it by 1 here. + */ +#define array_abs_bound(arr, lb, ub, k) \ + array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k)) + +#endif /* CBMC */ + +#endif /* !MLD_CBMC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/common.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/common.h new file mode 100644 index 0000000000..4a5bc8109d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/common.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_COMMON_H +#define MLD_COMMON_H + +#define MLD_BUILD_INTERNAL + +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#include "params.h" +#include "sys.h" + +/* Internal and public API have external linkage by default, but + * this can be overwritten by the user, e.g. for single-CU builds. */ +#if !defined(MLD_CONFIG_INTERNAL_API_QUALIFIER) +#define MLD_INTERNAL_API +#else +#define MLD_INTERNAL_API MLD_CONFIG_INTERNAL_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_EXTERNAL_API +#else +#define MLD_EXTERNAL_API MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#if defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) || \ + defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) +#define MLD_MULTILEVEL_BUILD +#endif + +#define MLD_CONCAT_(x1, x2) x1##x2 +#define MLD_CONCAT(x1, x2) MLD_CONCAT_(x1, x2) + +#if defined(MLD_MULTILEVEL_BUILD) +#define MLD_ADD_PARAM_SET(s) MLD_CONCAT(s, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_ADD_PARAM_SET(s) s +#endif + +#define MLD_NAMESPACE_PREFIX MLD_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, _) +#define MLD_NAMESPACE_PREFIX_KL \ + MLD_CONCAT(MLD_ADD_PARAM_SET(MLD_CONFIG_NAMESPACE_PREFIX), _) + +/* Functions are prefixed by MLD_CONFIG_NAMESPACE_PREFIX. + * + * If multiple parameter sets are used, functions depending on the parameter + * set are additionally prefixed with 44/65/87. See mldsa_native_config.h. + * + * Example: If MLD_CONFIG_NAMESPACE_PREFIX is PQCP_MLDSA_NATIVE, then + * MLD_NAMESPACE_KL(keypair) becomes PQCP_MLDSA_NATIVE44_keypair/ + * PQCP_MLDSA_NATIVE65_keypair/PQCP_MLDSA_NATIVE87_keypair. + */ +#define MLD_NAMESPACE(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX, s) +#define MLD_NAMESPACE_KL(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX_KL, s) + +/* On Apple platforms, we need to emit leading underscore + * in front of assembly symbols. We thus introducee a separate + * namespace wrapper for ASM symbols. */ +#if !defined(__APPLE__) +#define MLD_ASM_NAMESPACE(sym) MLD_NAMESPACE(sym) +#else +#define MLD_ASM_NAMESPACE(sym) MLD_CONCAT(_, MLD_NAMESPACE(sym)) +#endif + +/* + * On X86_64 if control-flow protections (CET) are enabled (through + * -fcf-protection=), we add an endbr64 instruction at every global function + * label. See sys.h for more details + */ +#if defined(MLD_SYS_X86_64) +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : MLD_CET_ENDBR +#else +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : +#endif + +/* We aim to simplify the user's life by supporting builds where + * all source files are included, even those that are not needed. + * Those files are appropriately guarded and will be empty when unneeded. + * The following is to avoid compilers complaining about this. */ +#define MLD_EMPTY_CU(s) extern int MLD_NAMESPACE_KL(empty_cu_##s); + +/* MLD_CONFIG_NO_ASM takes precedence over MLD_USE_NATIVE_XXX */ +#if defined(MLD_CONFIG_NO_ASM) +#undef MLD_CONFIG_USE_NATIVE_BACKEND_ARITH +#undef MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, but MLD_CONFIG_ARITH_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, but MLD_CONFIG_FIPS202_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_NO_RANDOMIZED_API) && defined(MLD_CONFIG_KEYGEN_PCT) +#error Bad configuration: MLD_CONFIG_NO_RANDOMIZED_API is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires crypto_sign_signature() +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#include MLD_CONFIG_ARITH_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#include MLD_CONFIG_FIPS202_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "fips202/native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#define MLD_FIPS202_HEADER_FILE "fips202/fips202.h" +#else +#define MLD_FIPS202_HEADER_FILE MLD_CONFIG_FIPS202_CUSTOM_HEADER +#endif + +#if !defined(MLD_CONFIG_FIPS202X4_CUSTOM_HEADER) +#define MLD_FIPS202X4_HEADER_FILE "fips202/fips202x4.h" +#else +#define MLD_FIPS202X4_HEADER_FILE MLD_CONFIG_FIPS202X4_CUSTOM_HEADER +#endif + +/* Standard library function replacements */ +#if !defined(__ASSEMBLER__) +#if !defined(MLD_CONFIG_CUSTOM_MEMCPY) +#include +#define mld_memcpy memcpy +#endif + +#if !defined(MLD_CONFIG_CUSTOM_MEMSET) +#include +#define mld_memset memset +#endif + +/* Allocation macros for large local structures + * + * MLD_ALLOC(v, T, N) declares T *v and attempts to point it to an T[N] + * MLD_FREE(v, T, N) zeroizes and frees the allocation + * + * Default implementation uses stack allocation. + * Can be overridden by setting the config option MLD_CONFIG_CUSTOM_ALLOC_FREE + * and defining MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE. + */ +#if defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) != \ + (defined(MLD_CUSTOM_ALLOC) && defined(MLD_CUSTOM_FREE)) +#error Bad configuration: MLD_CONFIG_CUSTOM_ALLOC_FREE must be set together with MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE +#endif + +/* + * If the integration wants to provide a context parameter for use in + * platform-specific hooks, then it should define this parameter. + * + * The MLD_CONTEXT_PARAMETERS_n macros are intended to be used with macros + * defining the function names and expand to either pass or discard the context + * argument as required by the current build. If there is no context parameter + * requested then these are removed from the prototypes and from all calls. + */ +#ifdef MLD_CONFIG_CONTEXT_PARAMETER +#define MLD_CONTEXT_PARAMETERS_0(context) (context) +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0, context) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1, context) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) \ + (arg0, arg1, arg2, context) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3, context) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4, context) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, context) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, context) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, context) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, context) +#else /* MLD_CONFIG_CONTEXT_PARAMETER */ +#define MLD_CONTEXT_PARAMETERS_0(context) () +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) (arg0, arg1, arg2) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) +#endif /* !MLD_CONFIG_CONTEXT_PARAMETER */ + +#if defined(MLD_CONFIG_CONTEXT_PARAMETER_TYPE) != \ + defined(MLD_CONFIG_CONTEXT_PARAMETER) +#error MLD_CONFIG_CONTEXT_PARAMETER_TYPE must be defined if and only if MLD_CONFIG_CONTEXT_PARAMETER is defined +#endif + +#if !defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) +/* Default: stack allocation */ + +#define MLD_ALLOC(v, T, N, context) \ + MLD_ALIGN T mld_alloc_##v[N]; \ + T *v = mld_alloc_##v + +/* TODO: This leads to a circular dependency between common and ct.h + * It just works out before we're at the end of the file, but it's still + * prone to issues in the future. */ +#include "ct.h" +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + mld_zeroize(mld_alloc_##v, sizeof(mld_alloc_##v)); \ + (v) = NULL; \ + } while (0) + +#else /* !MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* Custom allocation */ + +/* + * The indirection here is necessary to use MLD_CONTEXT_PARAMETERS_3 here. + */ +#define MLD_APPLY(f, args) f args + +#define MLD_ALLOC(v, T, N, context) \ + MLD_APPLY(MLD_CUSTOM_ALLOC, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)) + +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + if (v != NULL) \ + { \ + mld_zeroize(v, sizeof(T) * (N)); \ + MLD_APPLY(MLD_CUSTOM_FREE, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)); \ + v = NULL; \ + } \ + } while (0) + +#endif /* MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* + * We are facing severe CBMC performance issues when using unions. + * As a temporary workaround, we use unions only when MLD_CONFIG_REDUCE_RAM is + * set. + * TODO: Remove the workaround once + * https://github.com/diffblue/cbmc/issues/8813 + * is resolved + */ +#if defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_UNION_OR_STRUCT union +#else +#define MLD_UNION_OR_STRUCT struct +#endif + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_COMMON_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/ct.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/ct.c new file mode 100644 index 0000000000..010b1a52a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/ct.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include "ct.h" + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +/* + * Masking value used in constant-time functions from + * ct.h to block the compiler's range analysis and + * thereby reduce the risk of compiler-introduced branches. + */ +volatile uint64_t mld_ct_opt_blocker_u64 = 0; + +#else /* !MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(ct) + +#endif /* !(!MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/ct.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/ct.h new file mode 100644 index 0000000000..c307456468 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/ct.h @@ -0,0 +1,366 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [libmceliece] + * libmceliece implementation of Classic McEliece + * Bernstein, Chou + * https://lib.mceliece.org/ + * + * - [optblocker] + * PQC forum post on opt-blockers using volatile globals + * Daniel J. Bernstein + * https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ + */ + +#ifndef MLD_CT_H +#define MLD_CT_H + +#include +#include "cbmc.h" +#include "common.h" + +/* Constant-time comparisons and conditional operations + + We reduce the risk for compilation into variable-time code + through the use of 'value barriers'. + + Functionally, a value barrier is a no-op. To the compiler, however, + it constitutes an arbitrary modification of its input, and therefore + harden's value propagation and range analysis. + + We consider two approaches to implement a value barrier: + - An empty inline asm block which marks the target value as clobbered. + - XOR'ing with the value of a volatile global that's set to 0; + see @[optblocker] for a discussion of this idea, and + @[libmceliece, inttypes/crypto_intN.h] for an implementation. + + The first approach is cheap because it only prevents the compiler + from reasoning about the value of the variable past the barrier, + but does not directly generate additional instructions. + + The second approach generates redundant loads and XOR operations + and therefore comes at a higher runtime cost. However, it appears + more robust towards optimization, as compilers should never drop + a volatile load. + + We use the empty-ASM value barrier for GCC and clang, and fall + back to the global volatile barrier otherwise. + + The global value barrier can be forced by setting + MLD_CONFIG_NO_ASM_VALUE_BARRIER. + +*/ + +#if defined(MLD_HAVE_INLINE_ASM) && !defined(MLD_CONFIG_NO_ASM_VALUE_BARRIER) +#define MLD_USE_ASM_VALUE_BARRIER +#endif + + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) +/* + * Declaration of global volatile that the global value barrier + * is loading from and masking with. + */ +#define mld_ct_opt_blocker_u64 MLD_NAMESPACE(ct_opt_blocker_u64) +extern volatile uint64_t mld_ct_opt_blocker_u64; + + +/* Helper functions for obtaining global masks of various sizes */ + +/* This contract is not proved but treated as an axiom. + * + * Its validity relies on the assumption that the global opt-blocker + * constant mld_ct_opt_blocker_u64 is not modified. + */ +static MLD_INLINE uint64_t mld_ct_get_optblocker_u64(void) +__contract__(ensures(return_value == 0)) { return mld_ct_opt_blocker_u64; } + +static MLD_INLINE int64_t mld_ct_get_optblocker_i64(void) +__contract__(ensures(return_value == 0)) { return (int64_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint32_t mld_ct_get_optblocker_u32(void) +__contract__(ensures(return_value == 0)) { return (uint32_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint8_t mld_ct_get_optblocker_u8(void) +__contract__(ensures(return_value == 0)) { return (uint8_t)mld_ct_get_optblocker_u64(); } + +/* Opt-blocker based implementation of value barriers */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_i64()); } + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u32()); } + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u8()); } + + +#else /* !MLD_USE_ASM_VALUE_BARRIER */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} +#endif /* MLD_USE_ASM_VALUE_BARRIER */ + +#ifdef CBMC +#pragma CPROVER check push +#pragma CPROVER check disable "conversion" +#endif + +/************************************************* + * Name: mld_cast_uint32_to_int32 + * + * Description: Cast uint32 value to int32 + * + * Returns: For uint32_t x, the unique y in int32_t + * so that x == y mod 2^32. + * + * Concretely: + * - x < 2^31: returns x + * - x >= 2^31: returns x - 2^31 + * + **************************************************/ +static MLD_ALWAYS_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x) +{ + /* + * PORTABILITY: This relies on uint32_t -> int32_t + * being implemented as the inverse of int32_t -> uint32_t, + * which is implementation-defined (C99 6.3.1.3 (3)) + * CBMC (correctly) fails to prove this conversion is OK, + * so we have to suppress that check here + */ + return (int32_t)x; +} + +#ifdef CBMC +#pragma CPROVER check pop +#endif + + +/************************************************* + * Name: mld_cast_int64_to_uint32 + * + * Description: Cast int64 value to uint32 as per C standard. + * + * Returns: For int64_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int64_to_uint32(int64_t x) +{ + return (uint32_t)(x & (int64_t)UINT32_MAX); +} + +/************************************************* + * Name: mld_cast_int32_to_uint32 + * + * Description: Cast int32 value to uint32 as per C standard. + * + * Returns: For int32_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int32_to_uint32(int32_t x) +{ + return mld_cast_int64_to_uint32((int64_t)x); +} + +/************************************************* + * Name: mld_ct_sel_int32 + * + * Description: Functionally equivalent to cond ? a : b, + * but implemented with guards against + * compiler-introduced branches. + * + * Arguments: int32_t a: First alternative + * int32_t b: Second alternative + * uint32_t cond: Condition variable. + * + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_sel_int32(int32_t a, int32_t b, uint32_t cond) +__contract__( + requires(cond == 0x0 || cond == 0xFFFFFFFF) + ensures(return_value == (cond ? a : b)) +) +{ + uint32_t au = mld_cast_int32_to_uint32(a); + uint32_t bu = mld_cast_int32_to_uint32(b); + uint32_t res = bu ^ (mld_value_barrier_u32(cond) & (au ^ bu)); + return mld_cast_uint32_to_int32(res); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u32 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_nonzero_u32(uint32_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFFFFFFFF))) +{ + int64_t tmp = mld_value_barrier_i64(-((int64_t)x)); + tmp >>= 32; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u8 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint8_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint8_t mld_ct_cmask_nonzero_u8(uint8_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFF))) +{ + uint32_t mask = mld_ct_cmask_nonzero_u32((uint32_t)x); + return (uint8_t)(mask & 0xFF); +} + +/************************************************* + * Name: mld_ct_cmask_neg_i32 + * + * Description: Return 0 if input is non-negative, and -1 otherwise. + * + * Arguments: int32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_neg_i32(int32_t x) +__contract__( + ensures(return_value == ((x < 0) ? 0xFFFFFFFF : 0)) +) +{ + int64_t tmp = mld_value_barrier_i64((int64_t)x); + tmp >>= 31; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_abs_i32 + * + * Description: Return -x if x<0, x otherwise + * + * Arguments: int32_t x: Input value + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_abs_i32(int32_t x) +__contract__( + requires(x >= -INT32_MAX) + ensures(return_value == ((x < 0) ? -x : x)) +) +{ + return mld_ct_sel_int32(-x, x, mld_ct_cmask_neg_i32(x)); +} + +/************************************************* + * Name: mld_ct_memcmp + * + * Description: Compare two arrays for equality in constant time. + * + * Arguments: const uint8_t *a: pointer to first byte array + * const uint8_t *b: pointer to second byte array + * size_t len: length of the byte arrays, upper-bounded + * to UINT16_MAX to control proof complexity + * only. + * + * Returns 0 if the byte arrays are equal, 0xFF otherwise. + **************************************************/ +static MLD_INLINE uint8_t mld_ct_memcmp(const uint8_t *a, const uint8_t *b, + const size_t len) +__contract__( + requires(len <= UINT16_MAX) + requires(memory_no_alias(a, len)) + requires(memory_no_alias(b, len)) + ensures((return_value == 0) || (return_value == 0xFF)) + ensures((return_value == 0) == forall(i, 0, len, (a[i] == b[i])))) +{ + uint8_t r = 0, s = 0; + unsigned i; + + for (i = 0; i < len; i++) + __loop__( + invariant(i <= len) + invariant((r == 0) == (forall(k, 0, i, (a[k] == b[k]))))) + { + r |= a[i] ^ b[i]; + /* s is useless, but prevents the loop from being aborted once r=0xff. */ + s ^= a[i] ^ b[i]; + } + + /* + * - Convert r into a mask; this may not be necessary, but is an additional + * safeguard + * towards leaking information about a and b. + * - XOR twice with s, separated by a value barrier, to prevent the compile + * from dropping the s computation in the loop. + */ + return (mld_value_barrier_u8(mld_ct_cmask_nonzero_u8(r) ^ s) ^ s); +} + +/************************************************* + * Name: mld_zeroize + * + * Description: Force-zeroize a buffer. + * @[FIPS204, Section 3.6.3] Destruction of intermediate + * values. + * + * Arguments: void *ptr: pointer to buffer to be zeroed + * size_t len: Amount of bytes to be zeroed + **************************************************/ +#if !defined(MLD_CONFIG_CUSTOM_ZEROIZE) +#if defined(MLD_SYS_WINDOWS) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) { SecureZeroMemory(ptr, len); } +#elif defined(MLD_HAVE_INLINE_ASM) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) +{ + memset(ptr, 0, len); + /* This follows OpenSSL and seems sufficient to prevent the compiler + * from optimizing away the memset. + * + * If there was a reliable way to detect availability of memset_s(), + * that would be preferred. */ + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +} +#else /* !MLD_SYS_WINDOWS && MLD_HAVE_INLINE_ASM */ +#error No plausibly-secure implementation of mld_zeroize available. Please provide your own using MLD_CONFIG_CUSTOM_ZEROIZE. +#endif /* !MLD_SYS_WINDOWS && !MLD_HAVE_INLINE_ASM */ +#endif /* !MLD_CONFIG_CUSTOM_ZEROIZE */ + +#endif /* !MLD_CT_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/debug.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/debug.c new file mode 100644 index 0000000000..a55d51e8b1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/debug.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* NOTE: You can remove this file unless you compile with MLDSA_DEBUG. */ + +#include "common.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#if defined(MLDSA_DEBUG) + +#include +#include +#include +#include "debug.h" + +#define MLD_DEBUG_ERROR_HEADER "[ERROR:%s:%04d] " + +void mld_debug_check_assert(const char *file, int line, const int val) +{ + if (val == 0) + { + fprintf(stderr, MLD_DEBUG_ERROR_HEADER "Assertion failed (value %d)\n", + file, line, val); + exit(1); + } +} + +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive) +{ + int err = 0; + unsigned i; + for (i = 0; i < len; i++) + { + int32_t val = ptr[i]; + if (!(val > lower_bound_exclusive && val < upper_bound_exclusive)) + { + fprintf(stderr, + MLD_DEBUG_ERROR_HEADER + "Bounds assertion failed: Index %u, value %d out of bounds " + "(%" PRId64 ",%" PRId64 ")\n", + file, line, i, (int)val, lower_bound_exclusive, + upper_bound_exclusive); + err = 1; + } + } + + if (err == 1) + { + exit(1); + } +} + +#else /* MLDSA_DEBUG */ + +MLD_EMPTY_CU(debug) + +#endif /* !MLDSA_DEBUG */ + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(debug) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_DEBUG_ERROR_HEADER diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/debug.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/debug.h new file mode 100644 index 0000000000..af187bb9de --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/debug.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_DEBUG_H +#define MLD_DEBUG_H +#include "common.h" + +#if defined(MLDSA_DEBUG) +#include + +/************************************************* + * Name: mld_assert + * + * Description: Check debug assertion + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - val: Value asserted to be non-zero + **************************************************/ +#define mld_debug_check_assert MLD_NAMESPACE(mldsa_debug_assert) +void mld_debug_check_assert(const char *file, int line, const int val); + +/************************************************* + * Name: mld_debug_check_bounds + * + * Description: Check whether values in an array of int32_t + * are within specified bounds. + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - ptr: Base of array to be checked + * - len: Number of int32_t in ptr + * - lower_bound_exclusive: Exclusive lower bound + * - upper_bound_exclusive: Exclusive upper bound + **************************************************/ +#define mld_debug_check_bounds MLD_NAMESPACE(mldsa_debug_check_bounds) +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive); + +/* Check assertion, calling exit() upon failure + * + * val: Value that's asserted to be non-zero + */ +#define mld_assert(val) mld_debug_check_assert(__FILE__, __LINE__, (val)) + +/* Check bounds in array of int32_t's + * ptr: Base of int32_t array; will be explicitly cast to int32_t*, + * so you may pass a byte-compatible type such as mld_poly or mld_polyvec. + * len: Number of int32_t in array + * value_lb: Inclusive lower value bound + * value_ub: Exclusive upper value bound */ +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + mld_debug_check_bounds(__FILE__, __LINE__, (const int32_t *)(ptr), (len), \ + ((int64_t)(value_lb)) - 1, (value_ub)) + +/* Check absolute bounds in array of int32_t's + * ptr: Base of array, expression of type int32_t* + * len: Number of int32_t in array + * value_abs_bd: Exclusive absolute upper bound */ +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + mld_assert_bound((ptr), (len), (-((int64_t)(value_abs_bd)) + 1), \ + (value_abs_bd)) + +/* Version of bounds assertions for 2-dimensional arrays */ +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + mld_assert_bound((ptr), ((len0) * (len1)), (value_lb), (value_ub)) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + mld_assert_abs_bound((ptr), ((len0) * (len1)), (value_abs_bd)) + +/* When running CBMC, convert debug assertions into proof obligations */ +#elif defined(CBMC) +#include "cbmc.h" + +#define mld_assert(val) cassert(val) + +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + cassert(array_bound(((int32_t *)(ptr)), 0, (len), (value_lb), (value_ub))) + +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + cassert(array_abs_bound(((int32_t *)(ptr)), 0, (len), (value_abs_bd))) + +/* Because of https://github.com/diffblue/cbmc/issues/8570, we can't + * just use a single flattened array_bound(...) here. */ +#define mld_assert_bound_2d(ptr, M, N, value_lb, value_ub) \ + cassert(forall(kN, 0, (M), \ + array_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_lb), (value_ub)))) + +#define mld_assert_abs_bound_2d(ptr, M, N, value_abs_bd) \ + cassert(forall(kN, 0, (M), \ + array_abs_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_abs_bd)))) + +#else /* !MLDSA_DEBUG && CBMC */ + +#define mld_assert(val) \ + do \ + { \ + } while (0) +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + do \ + { \ + } while (0) +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + do \ + { \ + } while (0) + +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + do \ + { \ + } while (0) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + do \ + { \ + } while (0) + + +#endif /* !MLDSA_DEBUG && !CBMC */ +#endif /* !MLD_DEBUG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/fips202.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/fips202.c new file mode 100644 index 0000000000..1112de061c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/fips202.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "../common.h" +#include "../ct.h" +#include "fips202.h" +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +/************************************************* + * Name: keccak_init + * + * Description: Initializes the Keccak state. + * + * Arguments: - uint64_t *s: pointer to Keccak state + **************************************************/ +static void keccak_init(uint64_t s[MLD_KECCAK_LANES]) +__contract__( + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + mld_memset(s, 0, sizeof(uint64_t) * MLD_KECCAK_LANES); +} + +/************************************************* + * Name: keccak_absorb + * + * Description: Absorb step of Keccak; incremental. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_absorb(uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r, + const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(pos <= r) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(in, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + ensures(return_value < r)) +{ + while (inlen >= r - pos) + __loop__( + assigns(pos, in, inlen, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + invariant(inlen <= loop_entry(inlen)) + invariant(pos <= r) + invariant(in == loop_entry(in) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600_xor_bytes(s, in, pos, r - pos); + inlen -= r - pos; + in += r - pos; + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: At this point, inlen < r, so the truncation to unsigned is safe. */ + mld_keccakf1600_xor_bytes(s, in, pos, (unsigned)inlen); + + /* Safety: At this point, inlen < r and pos <= r so the truncation to unsigned + * is safe. */ + return (unsigned)(pos + inlen); +} + +/************************************************* + * Name: keccak_finalize + * + * Description: Finalize absorb step. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - uint8_t p: domain separation byte + **************************************************/ +static void keccak_finalize(uint64_t s[MLD_KECCAK_LANES], unsigned int pos, + unsigned int r, uint8_t p) +__contract__( + requires(pos <= r && r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires((r / 8) >= 1) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + uint8_t b = 0x80; + mld_keccakf1600_xor_bytes(s, &p, pos, 1); + mld_keccakf1600_xor_bytes(s, &b, r - 1, 1); +} + +/************************************************* + * Name: keccak_squeeze + * + * Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes. + * Modifies the state. Can be called multiple times to keep + * squeezing, i.e., is incremental. + * + * Arguments: - uint8_t *out: pointer to output data + * - size_t outlen: number of bytes to be squeezed (written to out) + * - uint64_t *s: pointer to input/output Keccak state + * - unsigned int pos: number of bytes in current block already + *squeezed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_squeeze(uint8_t *out, size_t outlen, + uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r) +__contract__( + requires((r == SHAKE128_RATE && pos <= SHAKE128_RATE) || + (r == SHAKE256_RATE && pos <= SHAKE256_RATE) || + (r == SHA3_512_RATE && pos <= SHA3_512_RATE)) + requires(outlen <= 8 * r /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(out, outlen)) + ensures(return_value <= r)) +{ + unsigned int i; + size_t out_offset = 0; + + /* Reference: This code is re-factored from the reference implementation + * to facilitate proof with CBMC and to improve readability. + * + * Take a mutable copy of outlen to count down the number of bytes + * still to squeeze. The initial value of outlen is needed for the CBMC + * assigns() clauses. */ + size_t bytes_to_go = outlen; + + while (bytes_to_go > 0) + __loop__( + assigns(i, bytes_to_go, pos, out_offset, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES), memory_slice(out, outlen)) + invariant(bytes_to_go <= outlen) + invariant(out_offset == outlen - bytes_to_go) + invariant(pos <= r) + ) + { + if (pos == r) + { + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: If bytes_to_go < r - pos, truncation to unsigned is safe. */ + i = bytes_to_go < r - pos ? (unsigned)bytes_to_go : r - pos; + mld_keccakf1600_extract_bytes(s, out + out_offset, pos, i); + bytes_to_go -= i; + pos += i; + out_offset += i; + } + + return pos; +} + +void mld_shake128_init(mld_shake128ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE128_RATE, in, inlen); +} + +void mld_shake128_finalize(mld_shake128ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE128_RATE, 0x1F); + state->pos = SHAKE128_RATE; +} + +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE128_RATE); +} + +void mld_shake128_release(mld_shake128ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128ctx)); +} + +void mld_shake256_init(mld_shake256ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); +} + +void mld_shake256_finalize(mld_shake256ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); + state->pos = SHAKE256_RATE; +} + +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); +} + +void mld_shake256_release(mld_shake256ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256ctx)); +} + +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +{ + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, in, inlen); + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/fips202.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/fips202.h new file mode 100644 index 0000000000..9f0253cb88 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/fips202.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202_H +#define MLD_FIPS202_FIPS202_H + +#include +#include +#include "../cbmc.h" +#include "../common.h" + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 +#define SHA3_256_RATE 136 +#define SHA3_512_RATE 72 +#define MLD_KECCAK_LANES 25 +#define SHA3_256_HASHBYTES 32 +#define SHA3_512_HASHBYTES 64 + + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake128ctx; + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake256ctx; + +#define mld_shake128_init MLD_NAMESPACE(shake128_init) +/************************************************* + * Name: mld_shake128_init + * + * Description: Initializes state for use as SHAKE128 XOF + * + * Arguments: - mld_shake128ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake128_init(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos == 0) +); + +#define mld_shake128_absorb MLD_NAMESPACE(shake128_absorb) +/************************************************* + * Name: mld_shake128_absorb + * + * Description: Absorb step of the SHAKE128 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake128ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_finalize MLD_NAMESPACE(shake128_finalize) +/************************************************* + * Name: mld_shake128_finalize + * + * Description: Concludes the absorb phase of the SHAKE128 XOF. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_finalize(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_squeeze MLD_NAMESPACE(shake128_squeeze) +/************************************************* + * Name: mld_shake128_squeeze + * + * Description: Squeeze step of SHAKE128 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake128ctx *s: pointer to input/output state + **************************************************/ +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE128_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_release MLD_NAMESPACE(shake128_release) +/************************************************* + * Name: mld_shake128_release + * + * Description: Release and securely zero the SHAKE128 state. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_release(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) +); + +#define mld_shake256_init MLD_NAMESPACE(shake256_init) +/************************************************* + * Name: mld_shake256_init + * + * Description: Initializes state for use as SHAKE256 XOF + * + * Arguments: - mld_shake256ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake256_init(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos == 0) +); + +#define mld_shake256_absorb MLD_NAMESPACE(shake256_absorb) +/************************************************* + * Name: mld_shake256_absorb + * + * Description: Absorb step of the SHAKE256 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake256ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_finalize MLD_NAMESPACE(shake256_finalize) +/************************************************* + * Name: mld_shake256_finalize + * + * Description: Concludes the absorb phase of the SHAKE256 XOF. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_finalize(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_squeeze MLD_NAMESPACE(shake256_squeeze) +/************************************************* + * Name: mld_shake256_squeeze + * + * Description: Squeeze step of SHAKE256 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake256ctx *s: pointer to input/output state + **************************************************/ +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_release MLD_NAMESPACE(shake256_release) +/************************************************* + * Name: mld_shake256_release + * + * Description: Release and securely zero the SHAKE256 state. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_release(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) +); + +#define mld_shake256 MLD_NAMESPACE(shake256) +/************************************************* + * Name: mld_shake256 + * + * Description: SHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +); + +#endif /* !MLD_FIPS202_FIPS202_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/fips202x4.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/fips202x4.c new file mode 100644 index 0000000000..0fb5cd57c7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/fips202x4.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include "../common.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "../ct.h" +#include "fips202.h" +#include "fips202x4.h" +#include "keccakf1600.h" + +static void mld_keccak_absorb_once_x4(uint64_t *s, uint32_t r, + const uint8_t *in0, const uint8_t *in1, + const uint8_t *in2, const uint8_t *in3, + size_t inlen, uint8_t p) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))) +{ + while (inlen >= r) + __loop__( + assigns(inlen, in0, in1, in2, in3, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + invariant(inlen <= loop_entry(inlen)) + invariant(in0 == loop_entry(in0) + (loop_entry(inlen) - inlen)) + invariant(in1 == loop_entry(in1) + (loop_entry(inlen) - inlen)) + invariant(in2 == loop_entry(in2) + (loop_entry(inlen) - inlen)) + invariant(in3 == loop_entry(in3) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, r); + mld_keccakf1600x4_permute(s); + + in0 += r; + in1 += r; + in2 += r; + in3 += r; + inlen -= r; + } + + /* Safety: At this point, inlen < r, so the truncations to unsigned are safe + * below. */ + if (inlen > 0) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, (unsigned)inlen); + } + + if (inlen == r - 1) + { + p |= 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + } + else + { + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + p = 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, r - 1, 1); + } +} + +static void mld_keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1, + uint8_t *out2, uint8_t *out3, + size_t nblocks, uint64_t *s, uint32_t r) +__contract__( + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(out0, nblocks * r)) + requires(memory_no_alias(out1, nblocks * r)) + requires(memory_no_alias(out2, nblocks * r)) + requires(memory_no_alias(out3, nblocks * r)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(out0, nblocks * r)) + assigns(memory_slice(out1, nblocks * r)) + assigns(memory_slice(out2, nblocks * r)) + assigns(memory_slice(out3, nblocks * r))) +{ + while (nblocks > 0) + __loop__( + assigns(out0, out1, out2, out3, nblocks, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY), + memory_slice(out0, nblocks * r), + memory_slice(out1, nblocks * r), + memory_slice(out2, nblocks * r), + memory_slice(out3, nblocks * r)) + invariant(nblocks <= loop_entry(nblocks) && + out0 == loop_entry(out0) + r * (loop_entry(nblocks) - nblocks) && + out1 == loop_entry(out1) + r * (loop_entry(nblocks) - nblocks) && + out2 == loop_entry(out2) + r * (loop_entry(nblocks) - nblocks) && + out3 == loop_entry(out3) + r * (loop_entry(nblocks) - nblocks))) + { + mld_keccakf1600x4_permute(s); + mld_keccakf1600x4_extract_bytes(s, out0, out1, out2, out3, 0, r); + + out0 += r; + out1 += r; + out2 += r; + out3 += r; + nblocks--; + } +} + +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake128x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE128_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE128_RATE); +} + +void mld_shake128x4_init(mld_shake128x4ctx *state) { (void)state; } +void mld_shake128x4_release(mld_shake128x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128x4ctx)); +} + + +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake256x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE256_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE256_RATE); +} + +void mld_shake256x4_init(mld_shake256x4ctx *state) { (void)state; } +void mld_shake256x4_release(mld_shake256x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256x4ctx)); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/fips202x4.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/fips202x4.h new file mode 100644 index 0000000000..e7987207a6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/fips202x4.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202X4_H +#define MLD_FIPS202_FIPS202X4_H + +#include +#include + +#include "../cbmc.h" +#include "../common.h" + +#include "fips202.h" +#include "keccakf1600.h" + +/* Context for non-incremental API */ +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake128x4ctx; + +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake256x4ctx; + +#define mld_shake128x4_absorb_once MLD_NAMESPACE(shake128x4_absorb_once) +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_squeezeblocks MLD_NAMESPACE(shake128x4_squeezeblocks) +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE128_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE128_RATE), + memory_slice(out1, nblocks * SHAKE128_RATE), + memory_slice(out2, nblocks * SHAKE128_RATE), + memory_slice(out3, nblocks * SHAKE128_RATE), + memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_init MLD_NAMESPACE(shake128x4_init) +void mld_shake128x4_init(mld_shake128x4ctx *state); + +#define mld_shake128x4_release MLD_NAMESPACE(shake128x4_release) +void mld_shake128x4_release(mld_shake128x4ctx *state); + + +#define mld_shake256x4_absorb_once MLD_NAMESPACE(shake256x4_absorb_once) +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_squeezeblocks MLD_NAMESPACE(shake256x4_squeezeblocks) +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE256_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE256_RATE), + memory_slice(out1, nblocks * SHAKE256_RATE), + memory_slice(out2, nblocks * SHAKE256_RATE), + memory_slice(out3, nblocks * SHAKE256_RATE), + memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_init MLD_NAMESPACE(shake256x4_init) +void mld_shake256x4_init(mld_shake256x4ctx *state); + +#define mld_shake256x4_release MLD_NAMESPACE(shake256x4_release) +void mld_shake256x4_release(mld_shake256x4ctx *state); + + +#endif /* !MLD_FIPS202_FIPS202X4_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/keccakf1600.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/keccakf1600.c new file mode 100644 index 0000000000..e59120c07c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/keccakf1600.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#define MLD_KECCAK_NROUNDS 24 +#define MLD_KECCAK_ROL(a, offset) ((a << offset) ^ (a >> (64 - offset))) + +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = state_ptr[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = (state[(offset + i) >> 3] >> (8 * ((offset + i) & 0x07))) & 0xFF; + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state_ptr[i] ^= data[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state[(offset + i) >> 3] ^= (uint64_t)data[i] + << (8 * ((offset + i) & 0x07)); + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X4_NATIVE) + if (mld_keccak_f1600_x4_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 0); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 1); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 2); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 3); +} + +static const uint64_t mld_KeccakF_RoundConstants[MLD_KECCAK_NROUNDS] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +static void mld_keccakf1600_permute_c(uint64_t *state) +{ + unsigned round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + uint64_t BCa, BCe, BCi, BCo, BCu; + uint64_t Da, De, Di, Do, Du; + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + /* copyFromState(A, state) */ + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < MLD_KECCAK_NROUNDS; round += 2) + __loop__(invariant(round <= MLD_KECCAK_NROUNDS && round % 2 == 0)) + { + /* prepareTheta */ + BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; + BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + /* thetaRhoPiChiIotaPrepareTheta(round, A, E) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = MLD_KECCAK_ROL(Age, 44); + Aki ^= Di; + BCi = MLD_KECCAK_ROL(Aki, 43); + Amo ^= Do; + BCo = MLD_KECCAK_ROL(Amo, 21); + Asu ^= Du; + BCu = MLD_KECCAK_ROL(Asu, 14); + Eba = BCa ^ ((~BCe) & BCi); + Eba ^= (uint64_t)mld_KeccakF_RoundConstants[round]; + Ebe = BCe ^ ((~BCi) & BCo); + Ebi = BCi ^ ((~BCo) & BCu); + Ebo = BCo ^ ((~BCu) & BCa); + Ebu = BCu ^ ((~BCa) & BCe); + + Abo ^= Do; + BCa = MLD_KECCAK_ROL(Abo, 28); + Agu ^= Du; + BCe = MLD_KECCAK_ROL(Agu, 20); + Aka ^= Da; + BCi = MLD_KECCAK_ROL(Aka, 3); + Ame ^= De; + BCo = MLD_KECCAK_ROL(Ame, 45); + Asi ^= Di; + BCu = MLD_KECCAK_ROL(Asi, 61); + Ega = BCa ^ ((~BCe) & BCi); + Ege = BCe ^ ((~BCi) & BCo); + Egi = BCi ^ ((~BCo) & BCu); + Ego = BCo ^ ((~BCu) & BCa); + Egu = BCu ^ ((~BCa) & BCe); + + Abe ^= De; + BCa = MLD_KECCAK_ROL(Abe, 1); + Agi ^= Di; + BCe = MLD_KECCAK_ROL(Agi, 6); + Ako ^= Do; + BCi = MLD_KECCAK_ROL(Ako, 25); + Amu ^= Du; + BCo = MLD_KECCAK_ROL(Amu, 8); + Asa ^= Da; + BCu = MLD_KECCAK_ROL(Asa, 18); + Eka = BCa ^ ((~BCe) & BCi); + Eke = BCe ^ ((~BCi) & BCo); + Eki = BCi ^ ((~BCo) & BCu); + Eko = BCo ^ ((~BCu) & BCa); + Eku = BCu ^ ((~BCa) & BCe); + + Abu ^= Du; + BCa = MLD_KECCAK_ROL(Abu, 27); + Aga ^= Da; + BCe = MLD_KECCAK_ROL(Aga, 36); + Ake ^= De; + BCi = MLD_KECCAK_ROL(Ake, 10); + Ami ^= Di; + BCo = MLD_KECCAK_ROL(Ami, 15); + Aso ^= Do; + BCu = MLD_KECCAK_ROL(Aso, 56); + Ema = BCa ^ ((~BCe) & BCi); + Eme = BCe ^ ((~BCi) & BCo); + Emi = BCi ^ ((~BCo) & BCu); + Emo = BCo ^ ((~BCu) & BCa); + Emu = BCu ^ ((~BCa) & BCe); + + Abi ^= Di; + BCa = MLD_KECCAK_ROL(Abi, 62); + Ago ^= Do; + BCe = MLD_KECCAK_ROL(Ago, 55); + Aku ^= Du; + BCi = MLD_KECCAK_ROL(Aku, 39); + Ama ^= Da; + BCo = MLD_KECCAK_ROL(Ama, 41); + Ase ^= De; + BCu = MLD_KECCAK_ROL(Ase, 2); + Esa = BCa ^ ((~BCe) & BCi); + Ese = BCe ^ ((~BCi) & BCo); + Esi = BCi ^ ((~BCo) & BCu); + Eso = BCo ^ ((~BCu) & BCa); + Esu = BCu ^ ((~BCa) & BCe); + + /* prepareTheta */ + BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + /* thetaRhoPiChiIotaPrepareTheta(round+1, E, A) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = MLD_KECCAK_ROL(Ege, 44); + Eki ^= Di; + BCi = MLD_KECCAK_ROL(Eki, 43); + Emo ^= Do; + BCo = MLD_KECCAK_ROL(Emo, 21); + Esu ^= Du; + BCu = MLD_KECCAK_ROL(Esu, 14); + Aba = BCa ^ ((~BCe) & BCi); + Aba ^= (uint64_t)mld_KeccakF_RoundConstants[round + 1]; + Abe = BCe ^ ((~BCi) & BCo); + Abi = BCi ^ ((~BCo) & BCu); + Abo = BCo ^ ((~BCu) & BCa); + Abu = BCu ^ ((~BCa) & BCe); + + Ebo ^= Do; + BCa = MLD_KECCAK_ROL(Ebo, 28); + Egu ^= Du; + BCe = MLD_KECCAK_ROL(Egu, 20); + Eka ^= Da; + BCi = MLD_KECCAK_ROL(Eka, 3); + Eme ^= De; + BCo = MLD_KECCAK_ROL(Eme, 45); + Esi ^= Di; + BCu = MLD_KECCAK_ROL(Esi, 61); + Aga = BCa ^ ((~BCe) & BCi); + Age = BCe ^ ((~BCi) & BCo); + Agi = BCi ^ ((~BCo) & BCu); + Ago = BCo ^ ((~BCu) & BCa); + Agu = BCu ^ ((~BCa) & BCe); + + Ebe ^= De; + BCa = MLD_KECCAK_ROL(Ebe, 1); + Egi ^= Di; + BCe = MLD_KECCAK_ROL(Egi, 6); + Eko ^= Do; + BCi = MLD_KECCAK_ROL(Eko, 25); + Emu ^= Du; + BCo = MLD_KECCAK_ROL(Emu, 8); + Esa ^= Da; + BCu = MLD_KECCAK_ROL(Esa, 18); + Aka = BCa ^ ((~BCe) & BCi); + Ake = BCe ^ ((~BCi) & BCo); + Aki = BCi ^ ((~BCo) & BCu); + Ako = BCo ^ ((~BCu) & BCa); + Aku = BCu ^ ((~BCa) & BCe); + + Ebu ^= Du; + BCa = MLD_KECCAK_ROL(Ebu, 27); + Ega ^= Da; + BCe = MLD_KECCAK_ROL(Ega, 36); + Eke ^= De; + BCi = MLD_KECCAK_ROL(Eke, 10); + Emi ^= Di; + BCo = MLD_KECCAK_ROL(Emi, 15); + Eso ^= Do; + BCu = MLD_KECCAK_ROL(Eso, 56); + Ama = BCa ^ ((~BCe) & BCi); + Ame = BCe ^ ((~BCi) & BCo); + Ami = BCi ^ ((~BCo) & BCu); + Amo = BCo ^ ((~BCu) & BCa); + Amu = BCu ^ ((~BCa) & BCe); + + Ebi ^= Di; + BCa = MLD_KECCAK_ROL(Ebi, 62); + Ego ^= Do; + BCe = MLD_KECCAK_ROL(Ego, 55); + Eku ^= Du; + BCi = MLD_KECCAK_ROL(Eku, 39); + Ema ^= Da; + BCo = MLD_KECCAK_ROL(Ema, 41); + Ese ^= De; + BCu = MLD_KECCAK_ROL(Ese, 2); + Asa = BCa ^ ((~BCe) & BCi); + Ase = BCe ^ ((~BCi) & BCo); + Asi = BCi ^ ((~BCo) & BCu); + Aso = BCo ^ ((~BCu) & BCa); + Asu = BCu ^ ((~BCa) & BCe); + } + + /* copyToState(state, A) */ + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} + +void mld_keccakf1600_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X1_NATIVE) + if (mld_keccak_f1600_x1_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X1_NATIVE */ + mld_keccakf1600_permute_c(state); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(keccakf1600) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_KECCAK_NROUNDS +#undef MLD_KECCAK_ROL diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/keccakf1600.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/keccakf1600.h new file mode 100644 index 0000000000..e56adc1561 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/keccakf1600.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_KECCAKF1600_H +#define MLD_FIPS202_KECCAKF1600_H +#include +#include "../cbmc.h" +#include "../common.h" +#include "fips202.h" + +#define MLD_KECCAK_LANES 25 +#define MLD_KECCAK_WAY 4 + +/* + * WARNING: + * The contents of this structure, including the placement + * and interleaving of Keccak lanes, are IMPLEMENTATION-DEFINED. + * The struct is only exposed here to allow its construction on the stack. + */ + +#define mld_keccakf1600_extract_bytes MLD_NAMESPACE(keccakf1600_extract_bytes) +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(data, length)) +); + +#define mld_keccakf1600_xor_bytes MLD_NAMESPACE(keccakf1600_xor_bytes) +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#define mld_keccakf1600x4_extract_bytes \ + MLD_NAMESPACE(keccakf1600x4_extract_bytes) +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + requires(memory_no_alias(data1, length)) + requires(memory_no_alias(data2, length)) + requires(memory_no_alias(data3, length)) + assigns(memory_slice(data0, length)) + assigns(memory_slice(data1, length)) + assigns(memory_slice(data2, length)) + assigns(memory_slice(data3, length)) +); + +#define mld_keccakf1600x4_xor_bytes MLD_NAMESPACE(keccakf1600x4_xor_bytes) +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + /* Case 1: all input buffers are distinct; Case 2: All input buffers are the same */ + requires((data0 == data1 && + data0 == data2 && + data0 == data3) || + (memory_no_alias(data1, length) && + memory_no_alias(data2, length) && + memory_no_alias(data3, length))) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600x4_permute MLD_NAMESPACE(keccakf1600x4_permute) +void mld_keccakf1600x4_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600_permute MLD_NAMESPACE(keccakf1600_permute) +void mld_keccakf1600_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#endif /* !MLD_FIPS202_KECCAKF1600_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/auto.h new file mode 100644 index 0000000000..4375cc1976 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/auto.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [HYBRID] + * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64 + * Becker, Kannwischer + * https://eprint.iacr.org/2022/1243 + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +#define MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* Default FIPS202 assembly profile for AArch64 systems */ + +/* + * Default logic to decide which implementation to use. + * + */ + +/* + * Keccak-f1600 + * + * - On Arm-based Apple CPUs, we pick a pure Neon implementation. + * - Otherwise, unless MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, + * we use lazy-rotation scalar assembly from @[HYBRID]. + * - Otherwise, if MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, we + * fall back to the standard C implementation. + */ +#if defined(__ARM_FEATURE_SHA3) && defined(__APPLE__) +#include "x1_v84a.h" +#elif !defined(MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER) +#include "x1_scalar.h" +#endif + +/* + * Keccak-f1600x2/x4 + * + * The optimal implementation is highly CPU-specific; see @[HYBRID]. + * + * For now, if v8.4-A is not implemented, we fall back to Keccak-f1600. + * If v8.4-A is implemented and we are on an Apple CPU, we use a plain + * Neon-based implementation. + * If v8.4-A is implemented and we are not on an Apple CPU, we use a + * scalar/Neon/Neon hybrid. + * The reason for this distinction is that Apple CPUs appear to implement + * the SHA3 instructions on all SIMD units, while Arm CPUs prior to Cortex-X4 + * don't, and ordinary Neon instructions are still needed. + */ +#if defined(__ARM_FEATURE_SHA3) +/* + * For Apple-M cores, we use a plain implementation leveraging SHA3 + * instructions only. + */ +#if defined(__APPLE__) +#include "x2_v84a.h" +#else +#include "x4_v8a_v84a_scalar.h" +#endif + +#else /* __ARM_FEATURE_SHA3 */ + +#include "x4_v8a_scalar.h" + +#endif /* !__ARM_FEATURE_SHA3 */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h new file mode 100644 index 0000000000..20f6168038 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#define MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H + +#include +#include "../../../../cbmc.h" +#include "../../../../common.h" + + +#define mld_keccakf1600_round_constants \ + MLD_NAMESPACE(keccakf1600_round_constants) +extern const uint64_t mld_keccakf1600_round_constants[]; + +#define mld_keccak_f1600_x1_scalar_asm MLD_NAMESPACE(keccak_f1600_x1_scalar_asm) +void mld_keccak_f1600_x1_scalar_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x1_v84a_asm MLD_NAMESPACE(keccak_f1600_x1_v84a_asm) +void mld_keccak_f1600_x1_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x2_v84a_asm MLD_NAMESPACE(keccak_f1600_x2_v84a_asm) +void mld_keccak_f1600_x2_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 2)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 2)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c new file mode 100644 index 0000000000..05e9cbfeec --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../../common.h" + +#if (defined(MLD_FIPS202_AARCH64_NEED_X1_SCALAR) || \ + defined(MLD_FIPS202_AARCH64_NEED_X1_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X2_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID)) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "fips202_native_aarch64.h" + +MLD_ALIGN const uint64_t mld_keccakf1600_round_constants[] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, +}; + +#else /* (MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_aarch64_round_constants) + +#endif /* !((MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/x1_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/x1_scalar.h new file mode 100644 index 0000000000..681b991371 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/x1_scalar.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_SCALAR + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + mld_keccak_f1600_x1_scalar_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/x1_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/x1_v84a.h new file mode 100644 index 0000000000..d15c8c26f3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/x1_v84a.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x1_v84a_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/x2_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/x2_v84a.h new file mode 100644 index 0000000000..16c22fa1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/x2_v84a.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X2_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" + + +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x2_v84a_asm(state + 0 * 25, mld_keccakf1600_round_constants); + mld_keccak_f1600_x2_v84a_asm(state + 2 * 25, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h new file mode 100644 index 0000000000..0f7f8fe499 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(state, + mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h new file mode 100644 index 0000000000..3da883b762 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm( + state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/api.h new file mode 100644 index 0000000000..4625c9a1ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/api.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_API_H +#define MLD_FIPS202_NATIVE_API_H +/* + * FIPS-202 native interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + */ + +#include +#include "../../cbmc.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* + * This is the C<->native interface allowing for the drop-in + * of custom Keccak-F1600 implementations. + * + * A _backend_ is a specific implementation of parts of this interface. + * + * You can replace 1-fold or 4-fold batched Keccak-F1600. + * To enable, set MLD_USE_FIPS202_X1_NATIVE or MLD_USE_FIPS202_X4_NATIVE + * in your backend, and define the inline wrappers mld_keccak_f1600_x1_native() + * and/or mld_keccak_f1600_x4_native(), respectively, to forward to your + * implementation. + */ + +#if defined(MLD_USE_FIPS202_X1_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 1)) +); +#endif /* MLD_USE_FIPS202_X1_NATIVE */ +#if defined(MLD_USE_FIPS202_X4_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 4)) +); +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + +#endif /* !MLD_FIPS202_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/auto.h new file mode 100644 index 0000000000..0a09c733c8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/auto.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AUTO_H +#define MLD_FIPS202_NATIVE_AUTO_H + +/* + * Default FIPS202 backend + */ +#include "../../sys.h" + +#if defined(MLD_SYS_AARCH64) +#include "aarch64/auto.h" +#endif + +#if defined(MLD_SYS_X86_64) && defined(MLD_SYS_X86_64_AVX2) +#include "x86_64/xkcp.h" +#endif + +#endif /* !MLD_FIPS202_NATIVE_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c new file mode 100644 index 0000000000..4eaad2fd66 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* +Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, +Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby +denoted as "the implementer". + +For more information, feedback or questions, please refer to our websites: +http://keccak.noekeon.org/ +http://keyak.noekeon.org/ +http://ketje.noekeon.org/ + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +/* + * Changes for mlkem-native/mldsa-native: + * - copyFromState and copyToState operate on uninterleaved + * Keccak states in memory. + */ + +#include "../../../../common.h" +#if defined(MLD_FIPS202_X86_64_XKCP) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include + +#include "KeccakP_1600_times4_SIMD256.h" + +#ifndef MLD_SYS_LITTLE_ENDIAN +#error Expecting a little-endian platform +#endif + +#define ANDnu256(a, b) _mm256_andnot_si256(a, b) +#define CONST256(a) _mm256_load_si256((const __m256i *)&(a)) +#define CONST256_64(a) (__m256i) _mm256_broadcast_sd((const double *)(&a)) +#define ROL64in256(d, a, o) \ + d = _mm256_or_si256(_mm256_slli_epi64(a, o), _mm256_srli_epi64(a, 64 - (o))) +#define ROL64in256_8(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho8)) +#define ROL64in256_56(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho56)) +static const uint64_t rho8[4] = {0x0605040302010007, 0x0E0D0C0B0A09080F, + 0x1615141312111017, 0x1E1D1C1B1A19181F}; +static const uint64_t rho56[4] = {0x0007060504030201, 0x080F0E0D0C0B0A09, + 0x1017161514131211, 0x181F1E1D1C1B1A19}; +#define STORE256(a, b) _mm256_store_si256((__m256i *)&(a), b) +#define XOR256(a, b) _mm256_xor_si256(a, b) +#define XOReq256(a, b) a = _mm256_xor_si256(a, b) + +#define SnP_laneLengthInBytes 8 + +#define declareABCDE \ + __m256i Aba, Abe, Abi, Abo, Abu; \ + __m256i Aga, Age, Agi, Ago, Agu; \ + __m256i Aka, Ake, Aki, Ako, Aku; \ + __m256i Ama, Ame, Ami, Amo, Amu; \ + __m256i Asa, Ase, Asi, Aso, Asu; \ + __m256i Bba, Bbe, Bbi, Bbo, Bbu; \ + __m256i Bga, Bge, Bgi, Bgo, Bgu; \ + __m256i Bka, Bke, Bki, Bko, Bku; \ + __m256i Bma, Bme, Bmi, Bmo, Bmu; \ + __m256i Bsa, Bse, Bsi, Bso, Bsu; \ + __m256i Ca, Ce, Ci, Co, Cu; \ + __m256i Ca1, Ce1, Ci1, Co1, Cu1; \ + __m256i Da, De, Di, Do, Du; \ + __m256i Eba, Ebe, Ebi, Ebo, Ebu; \ + __m256i Ega, Ege, Egi, Ego, Egu; \ + __m256i Eka, Eke, Eki, Eko, Eku; \ + __m256i Ema, Eme, Emi, Emo, Emu; \ + __m256i Esa, Ese, Esi, Eso, Esu; + +#define prepareTheta \ + Ca = XOR256(Aba, XOR256(Aga, XOR256(Aka, XOR256(Ama, Asa)))); \ + Ce = XOR256(Abe, XOR256(Age, XOR256(Ake, XOR256(Ame, Ase)))); \ + Ci = XOR256(Abi, XOR256(Agi, XOR256(Aki, XOR256(Ami, Asi)))); \ + Co = XOR256(Abo, XOR256(Ago, XOR256(Ako, XOR256(Amo, Aso)))); \ + Cu = XOR256(Abu, XOR256(Agu, XOR256(Aku, XOR256(Amu, Asu)))); + +/* + * --- Theta Rho Pi Chi Iota Prepare-theta + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + Ca = E##ba; \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + Ce = E##be; \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + Ci = E##bi; \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + Co = E##bo; \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + Cu = E##bu; \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(Ca, E##ga); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(Ce, E##ge); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + XOReq256(Ci, E##gi); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + XOReq256(Co, E##go); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + XOReq256(Cu, E##gu); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(Ca, E##ka); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(Ce, E##ke); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + XOReq256(Ci, E##ki); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + XOReq256(Co, E##ko); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + XOReq256(Cu, E##ku); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(Ca, E##ma); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(Ce, E##me); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + XOReq256(Ci, E##mi); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + XOReq256(Co, E##mo); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + XOReq256(Cu, E##mu); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(Ca, E##sa); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(Ce, E##se); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + XOReq256(Ci, E##si); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + XOReq256(Co, E##so); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); \ + XOReq256(Cu, E##su); + + +/* + * --- Theta Rho Pi Chi Iota + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIota(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); + + +static MLD_ALIGN const uint64_t keccakf1600RoundConstants[24] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +#include + +#define copyFromState(X, state) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m256i _idx = \ + _mm256_set_epi64x((long long)&state64[75], (long long)&state64[50], \ + (long long)&state64[25], (long long)&state64[0]); \ + X##ba = _mm256_i64gather_epi64((long long *)(0 * 8), _idx, 1); \ + X##be = _mm256_i64gather_epi64((long long *)(1 * 8), _idx, 1); \ + X##bi = _mm256_i64gather_epi64((long long *)(2 * 8), _idx, 1); \ + X##bo = _mm256_i64gather_epi64((long long *)(3 * 8), _idx, 1); \ + X##bu = _mm256_i64gather_epi64((long long *)(4 * 8), _idx, 1); \ + X##ga = _mm256_i64gather_epi64((long long *)(5 * 8), _idx, 1); \ + X##ge = _mm256_i64gather_epi64((long long *)(6 * 8), _idx, 1); \ + X##gi = _mm256_i64gather_epi64((long long *)(7 * 8), _idx, 1); \ + X##go = _mm256_i64gather_epi64((long long *)(8 * 8), _idx, 1); \ + X##gu = _mm256_i64gather_epi64((long long *)(9 * 8), _idx, 1); \ + X##ka = _mm256_i64gather_epi64((long long *)(10 * 8), _idx, 1); \ + X##ke = _mm256_i64gather_epi64((long long *)(11 * 8), _idx, 1); \ + X##ki = _mm256_i64gather_epi64((long long *)(12 * 8), _idx, 1); \ + X##ko = _mm256_i64gather_epi64((long long *)(13 * 8), _idx, 1); \ + X##ku = _mm256_i64gather_epi64((long long *)(14 * 8), _idx, 1); \ + X##ma = _mm256_i64gather_epi64((long long *)(15 * 8), _idx, 1); \ + X##me = _mm256_i64gather_epi64((long long *)(16 * 8), _idx, 1); \ + X##mi = _mm256_i64gather_epi64((long long *)(17 * 8), _idx, 1); \ + X##mo = _mm256_i64gather_epi64((long long *)(18 * 8), _idx, 1); \ + X##mu = _mm256_i64gather_epi64((long long *)(19 * 8), _idx, 1); \ + X##sa = _mm256_i64gather_epi64((long long *)(20 * 8), _idx, 1); \ + X##se = _mm256_i64gather_epi64((long long *)(21 * 8), _idx, 1); \ + X##si = _mm256_i64gather_epi64((long long *)(22 * 8), _idx, 1); \ + X##so = _mm256_i64gather_epi64((long long *)(23 * 8), _idx, 1); \ + X##su = _mm256_i64gather_epi64((long long *)(24 * 8), _idx, 1); \ + } while (0); + +#define SCATTER_STORE256(state, idx, v) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m128d t = _mm_castsi128_pd(_mm256_castsi256_si128((v))); \ + _mm_storel_pd((double *)&state64[0 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[25 + (idx)], t); \ + t = _mm_castsi128_pd(_mm256_extracti128_si256((v), 1)); \ + _mm_storel_pd((double *)&state64[50 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[75 + (idx)], t); \ + } while (0) + +#define copyToState(state, X) \ + SCATTER_STORE256(state, 0, X##ba); \ + SCATTER_STORE256(state, 1, X##be); \ + SCATTER_STORE256(state, 2, X##bi); \ + SCATTER_STORE256(state, 3, X##bo); \ + SCATTER_STORE256(state, 4, X##bu); \ + SCATTER_STORE256(state, 5, X##ga); \ + SCATTER_STORE256(state, 6, X##ge); \ + SCATTER_STORE256(state, 7, X##gi); \ + SCATTER_STORE256(state, 8, X##go); \ + SCATTER_STORE256(state, 9, X##gu); \ + SCATTER_STORE256(state, 10, X##ka); \ + SCATTER_STORE256(state, 11, X##ke); \ + SCATTER_STORE256(state, 12, X##ki); \ + SCATTER_STORE256(state, 13, X##ko); \ + SCATTER_STORE256(state, 14, X##ku); \ + SCATTER_STORE256(state, 15, X##ma); \ + SCATTER_STORE256(state, 16, X##me); \ + SCATTER_STORE256(state, 17, X##mi); \ + SCATTER_STORE256(state, 18, X##mo); \ + SCATTER_STORE256(state, 19, X##mu); \ + SCATTER_STORE256(state, 20, X##sa); \ + SCATTER_STORE256(state, 21, X##se); \ + SCATTER_STORE256(state, 22, X##si); \ + SCATTER_STORE256(state, 23, X##so); \ + SCATTER_STORE256(state, 24, X##su); + +#define copyStateVariables(X, Y) \ + X##ba = Y##ba; \ + X##be = Y##be; \ + X##bi = Y##bi; \ + X##bo = Y##bo; \ + X##bu = Y##bu; \ + X##ga = Y##ga; \ + X##ge = Y##ge; \ + X##gi = Y##gi; \ + X##go = Y##go; \ + X##gu = Y##gu; \ + X##ka = Y##ka; \ + X##ke = Y##ke; \ + X##ki = Y##ki; \ + X##ko = Y##ko; \ + X##ku = Y##ku; \ + X##ma = Y##ma; \ + X##me = Y##me; \ + X##mi = Y##mi; \ + X##mo = Y##mo; \ + X##mu = Y##mu; \ + X##sa = Y##sa; \ + X##se = Y##se; \ + X##si = Y##si; \ + X##so = Y##so; \ + X##su = Y##su; + +/* clang-format off */ +#define rounds24 \ + prepareTheta \ + thetaRhoPiChiIotaPrepareTheta( 0, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 1, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 2, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 3, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 4, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 5, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 6, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 7, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 8, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 9, E, A) \ + thetaRhoPiChiIotaPrepareTheta(10, A, E) \ + thetaRhoPiChiIotaPrepareTheta(11, E, A) \ + thetaRhoPiChiIotaPrepareTheta(12, A, E) \ + thetaRhoPiChiIotaPrepareTheta(13, E, A) \ + thetaRhoPiChiIotaPrepareTheta(14, A, E) \ + thetaRhoPiChiIotaPrepareTheta(15, E, A) \ + thetaRhoPiChiIotaPrepareTheta(16, A, E) \ + thetaRhoPiChiIotaPrepareTheta(17, E, A) \ + thetaRhoPiChiIotaPrepareTheta(18, A, E) \ + thetaRhoPiChiIotaPrepareTheta(19, E, A) \ + thetaRhoPiChiIotaPrepareTheta(20, A, E) \ + thetaRhoPiChiIotaPrepareTheta(21, E, A) \ + thetaRhoPiChiIotaPrepareTheta(22, A, E) \ + thetaRhoPiChiIota(23, E, A) +/* clang-format on */ + +void mld_keccakf1600x4_permute24(void *states) +{ + __m256i *statesAsLanes = (__m256i *)states; + declareABCDE copyFromState(A, statesAsLanes) + rounds24 copyToState(statesAsLanes, A) +} + +#else /* MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_avx2_keccakx4) + +#endif /* !(MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef ANDnu256 +#undef CONST256 +#undef CONST256_64 +#undef ROL64in256 +#undef ROL64in256_8 +#undef ROL64in256_56 +#undef STORE256 +#undef XOR256 +#undef XOReq256 +#undef SnP_laneLengthInBytes +#undef declareABCDE +#undef prepareTheta +#undef thetaRhoPiChiIotaPrepareTheta +#undef thetaRhoPiChiIota +#undef copyFromState +#undef SCATTER_STORE256 +#undef copyToState +#undef copyStateVariables +#undef rounds24 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h new file mode 100644 index 0000000000..3499d38e2c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H +#define MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H + +#include "../../../../common.h" + +#define mld_keccakf1600x4_permute24 \ + MLD_NAMESPACE(KeccakP1600times4_PermuteAll_24rounds) +void mld_keccakf1600x4_permute24(void *states); + +#endif /* !MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/x86_64/xkcp.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/x86_64/xkcp.h new file mode 100644 index 0000000000..c03642d7e0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/fips202/native/x86_64/xkcp.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_XKCP_H +#define MLD_FIPS202_NATIVE_X86_64_XKCP_H + +#include "../../../common.h" + +#define MLD_FIPS202_X86_64_XKCP + +#if !defined(__ASSEMBLER__) +#include +#include "../api.h" +#include "src/KeccakP_1600_times4_SIMD256.h" + +#define MLD_USE_FIPS202_X4_NATIVE +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_keccakf1600x4_permute24(state); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_X86_64_XKCP_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/meta.h new file mode 100644 index 0000000000..c6f6ad47b0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/meta.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_META_H +#define MLD_NATIVE_AARCH64_META_H + +/* Set of primitives that this backend replaces */ +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_AARCH64 + + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/arith_native_aarch64.h" + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + mld_ntt_asm(data, mld_aarch64_ntt_zetas_layer123456, + mld_aarch64_ntt_zetas_layer78); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + mld_intt_asm(data, mld_aarch64_intt_zetas_layer78, + mld_aarch64_intt_zetas_layer123456); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + if (len != MLDSA_N || + buflen % 24 != 0) /* NEON support is mandatory for AArch64 */ + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N, hence, this cast is safe. */ + return (int)mld_rej_uniform_asm(r, buf, buflen, mld_rej_uniform_table); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_32_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_88_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + mld_poly_caddq_asm(a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_32_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_88_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + return mld_poly_chknorm_asm(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_17_asm(r, buf, mld_polyz_unpack_17_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_19_asm(r, buf, mld_polyz_unpack_19_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t out[MLDSA_N], const int32_t in0[MLDSA_N], + const int32_t in1[MLDSA_N]) +{ + mld_poly_pointwise_montgomery_asm(out, in0, in1); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l4_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l5_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l7_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ +#endif /* !MLD_NATIVE_AARCH64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/src/aarch64_zetas.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/src/aarch64_zetas.c new file mode 100644 index 0000000000..9ab7b9a68c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/src/aarch64_zetas.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Table of zeta values used in the AArch64 forward NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer123456[] = { + -3572223, -915382907, 3765607, 964937599, 3761513, 963888510, + -3201494, -820383522, -2883726, -738955404, -3145678, -806080660, + -3201430, -820367122, 0, 0, -601683, -154181397, + -3370349, -863652652, -4063053, -1041158200, 3602218, 923069133, + 3182878, 815613168, 2740543, 702264730, -3586446, -919027554, + 0, 0, 3542485, 907762539, 2663378, 682491182, + -1674615, -429120452, -3110818, -797147778, 2101410, 538486762, + 3704823, 949361686, 1159875, 297218217, 0, 0, + 2682288, 687336873, -3524442, -903139016, -434125, -111244624, + 394148, 101000509, 928749, 237992130, 1095468, 280713909, + -3506380, -898510625, 0, 0, 2129892, 545785280, + 676590, 173376332, -1335936, -342333886, 2071829, 530906624, + -4018989, -1029866791, 3241972, 830756018, 2156050, 552488273, + 0, 0, 3764867, 964747974, -3227876, -827143915, + 1714295, 439288460, 3415069, 875112161, 1759347, 450833045, + -817536, -209493775, -3574466, -915957677, 0, 0, + -1005239, -257592709, 2453983, 628833668, 1460718, 374309300, + 3756790, 962678241, -1935799, -496048908, -1716988, -439978542, + -3950053, -1012201926, 0, 0, 557458, 142848732, + -642628, -164673562, -3585098, -918682129, -2897314, -742437332, + 3192354, 818041395, 556856, 142694469, 3870317, 991769559, + 0, 0, -1221177, -312926867, 2815639, 721508096, + 2283733, 585207070, 2917338, 747568486, 1853806, 475038184, + 3345963, 857403734, 1858416, 476219497, 0, 0, +}; + +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer78[] = { + 3073009, 1277625, -2635473, 3852015, 787459213, + 327391679, -675340520, 987079667, 1753, -2659525, + 2660408, -59148, 449207, -681503850, 681730119, + -15156688, -1935420, -1455890, -1780227, 2772600, + -495951789, -373072124, -456183549, 710479343, 4183372, + -3222807, -3121440, -274060, 1071989969, -825844983, + -799869667, -70227934, 1182243, 636927, -3956745, + -3284915, 302950022, 163212680, -1013916752, -841760171, + 87208, -3965306, -2296397, -3716946, 22347069, + -1016110510, -588452222, -952468207, 2508980, 2028118, + 1937570, -3815725, 642926661, 519705671, 496502727, + -977780347, -27812, 1009365, -1979497, -3956944, + -7126831, 258649997, -507246529, -1013967746, 822541, + -2454145, 1596822, -3759465, 210776307, -628875181, + 409185979, -963363710, 2811291, -2983781, -1109516, + 4158088, 720393920, -764594519, -284313712, 1065510939, + -1685153, 2678278, -3551006, -250446, -431820817, + 686309310, -909946047, -64176841, -3410568, -3768948, + 635956, -2455377, -873958779, -965793731, 162963861, + -629190881, 1528066, 482649, 1148858, -2962264, + 391567239, 123678909, 294395108, -759080783, -4146264, + 2192938, 2387513, -268456, -1062481036, 561940831, + 611800717, -68791907, -1772588, -1727088, -3611750, + -3180456, -454226054, -442566669, -925511710, -814992530, + -565603, 169688, 2462444, -3334383, -144935890, + 43482586, 631001801, -854436357, 3747250, 1239911, + 3195676, 1254190, 960233614, 317727459, 818892658, + 321386456, 2296099, -3838479, 2642980, -12417, + 588375860, -983611064, 677264190, -3181859, -4166425, + -3488383, 1987814, -3197248, -1067647297, -893898890, + 509377762, -819295484, 2998219, -89301, -1354892, + -1310261, 768294260, -22883400, -347191365, -335754661, + 141835, 2513018, 613238, -2218467, 36345249, + 643961400, 157142369, -568482643, 1736313, 235407, + -3250154, 3258457, 444930577, 60323094, -832852657, + 834980303, -458740, 4040196, 2039144, -818761, + -117552223, 1035301089, 522531086, -209807681, -1921994, + -3472069, -1879878, -2178965, -492511373, -889718424, + -481719139, -558360247, -2579253, 1787943, -2391089, + -2254727, -660934133, 458160776, -612717067, -577774276, + -1623354, -2374402, 586241, 527981, -415984810, + -608441020, 150224382, 135295244, 2105286, -2033807, + -1179613, -2743411, 539479988, -521163479, -302276083, + -702999655, 3482206, -4182915, -1300016, -2362063, + 892316032, -1071872863, -333129378, -605279149, -1476985, + 2491325, 507927, -724804, -378477722, 638402564, + 130156402, -185731180, 1994046, -1393159, -1187885, + -1834526, 510974714, -356997292, -304395785, -470097680, + -1317678, 2461387, 3035980, 621164, -337655269, + 630730945, 777970524, 159173408, -3033742, 2647994, + -2612853, 749577, -777397036, 678549029, -669544140, + 192079267, -338420, 3009748, 4148469, -4022750, + -86720197, 771248568, 1063046068, -1030830548, 3901472, + -1226661, 2925816, 3374250, 999753034, -314332144, + 749740976, 864652284, 3980599, -1615530, 1665318, + 1163598, 1020029345, -413979908, 426738094, 298172236, + 2569011, 1723229, 2028038, -3369273, 658309618, + 441577800, 519685171, -863376927, 1356448, -2775755, + 2683270, -2778788, 347590090, -711287812, 687588511, + -712065019, 3994671, -1370517, 3363542, 545376, + 1023635298, -351195274, 861908357, 139752717, -11879, + 3020393, 214880, -770441, -3043996, 773976352, + 55063046, -197425671, -3467665, 2312838, -653275, + -459163, -888589898, 592665232, -167401858, -117660617, + 3105558, 508145, 860144, 140244, 795799901, + 130212265, 220412084, 35937555, -1103344, -553718, + 3430436, -1514152, -282732136, -141890356, 879049958, + -388001774, 348812, -327848, 1011223, -2354215, + 89383150, -84011120, 259126110, -603268097, -2185084, + 2358373, -3014420, 2926054, -559928242, 604333585, + -772445769, 749801963, 3123762, -2193087, -1716814, + -392707, 800464680, -561979013, -439933955, -100631253, + -3818627, -1922253, -2236726, 1744507, -978523985, + -492577742, -573161516, 447030292, -303005, -3974485, + 1900052, 1054478, -77645096, -1018462631, 486888731, + 270210213, 3531229, -3773731, -781875, -731434, + 904878186, -967019376, -200355636, -187430119, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer78[] = { + -1744507, 2236726, 1922253, 3818627, -447030292, 573161516, + 492577742, 978523985, 731434, 781875, 3773731, -3531229, + 187430119, 200355636, 967019376, -904878186, -1054478, -1900052, + 3974485, 303005, -270210213, -486888731, 1018462631, 77645096, + 2354215, -1011223, 327848, -348812, 603268097, -259126110, + 84011120, -89383150, 392707, 1716814, 2193087, -3123762, + 100631253, 439933955, 561979013, -800464680, -2926054, 3014420, + -2358373, 2185084, -749801963, 772445769, -604333585, 559928242, + 459163, 653275, -2312838, 3467665, 117660617, 167401858, + -592665232, 888589898, 1514152, -3430436, 553718, 1103344, + 388001774, -879049958, 141890356, 282732136, -140244, -860144, + -508145, -3105558, -35937555, -220412084, -130212265, -795799901, + 2778788, -2683270, 2775755, -1356448, 712065019, -687588511, + 711287812, -347590090, 770441, -214880, -3020393, 11879, + 197425671, -55063046, -773976352, 3043996, -545376, -3363542, + 1370517, -3994671, -139752717, -861908357, 351195274, -1023635298, + -3374250, -2925816, 1226661, -3901472, -864652284, -749740976, + 314332144, -999753034, 3369273, -2028038, -1723229, -2569011, + 863376927, -519685171, -441577800, -658309618, -1163598, -1665318, + 1615530, -3980599, -298172236, -426738094, 413979908, -1020029345, + -621164, -3035980, -2461387, 1317678, -159173408, -777970524, + -630730945, 337655269, 4022750, -4148469, -3009748, 338420, + 1030830548, -1063046068, -771248568, 86720197, -749577, 2612853, + -2647994, 3033742, -192079267, 669544140, -678549029, 777397036, + 2362063, 1300016, 4182915, -3482206, 605279149, 333129378, + 1071872863, -892316032, 1834526, 1187885, 1393159, -1994046, + 470097680, 304395785, 356997292, -510974714, 724804, -507927, + -2491325, 1476985, 185731180, -130156402, -638402564, 378477722, + 2254727, 2391089, -1787943, 2579253, 577774276, 612717067, + -458160776, 660934133, 2743411, 1179613, 2033807, -2105286, + 702999655, 302276083, 521163479, -539479988, -527981, -586241, + 2374402, 1623354, -135295244, -150224382, 608441020, 415984810, + -3258457, 3250154, -235407, -1736313, -834980303, 832852657, + -60323094, -444930577, 2178965, 1879878, 3472069, 1921994, + 558360247, 481719139, 889718424, 492511373, 818761, -2039144, + -4040196, 458740, 209807681, -522531086, -1035301089, 117552223, + 3197248, -1987814, 3488383, 4166425, 819295484, -509377762, + 893898890, 1067647297, 2218467, -613238, -2513018, -141835, + 568482643, -157142369, -643961400, -36345249, 1310261, 1354892, + 89301, -2998219, 335754661, 347191365, 22883400, -768294260, + 3334383, -2462444, -169688, 565603, 854436357, -631001801, + -43482586, 144935890, 12417, -2642980, 3838479, -2296099, + 3181859, -677264190, 983611064, -588375860, -1254190, -3195676, + -1239911, -3747250, -321386456, -818892658, -317727459, -960233614, + 2962264, -1148858, -482649, -1528066, 759080783, -294395108, + -123678909, -391567239, 3180456, 3611750, 1727088, 1772588, + 814992530, 925511710, 442566669, 454226054, 268456, -2387513, + -2192938, 4146264, 68791907, -611800717, -561940831, 1062481036, + -4158088, 1109516, 2983781, -2811291, -1065510939, 284313712, + 764594519, -720393920, 2455377, -635956, 3768948, 3410568, + 629190881, -162963861, 965793731, 873958779, 250446, 3551006, + -2678278, 1685153, 64176841, 909946047, -686309310, 431820817, + 3815725, -1937570, -2028118, -2508980, 977780347, -496502727, + -519705671, -642926661, 3759465, -1596822, 2454145, -822541, + 963363710, -409185979, 628875181, -210776307, 3956944, 1979497, + -1009365, 27812, 1013967746, 507246529, -258649997, 7126831, + 274060, 3121440, 3222807, -4183372, 70227934, 799869667, + 825844983, -1071989969, 3716946, 2296397, 3965306, -87208, + 952468207, 588452222, 1016110510, -22347069, 3284915, 3956745, + -636927, -1182243, 841760171, 1013916752, -163212680, -302950022, + -3852015, 2635473, -1277625, -3073009, -987079667, 675340520, + -327391679, -787459213, -2772600, 1780227, 1455890, 1935420, + -710479343, 456183549, 373072124, 495951789, 59148, -2660408, + 2659525, -1753, 15156688, -681730119, 681503850, -449207, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer123456[] = { + -2283733, -585207070, 0, 0, -1858416, -476219497, + -3345963, -857403734, -2815639, -721508096, 0, 0, + -1853806, -475038184, -2917338, -747568486, 3585098, 918682129, + 0, 0, -3870317, -991769559, -556856, -142694469, + 642628, 164673562, 0, 0, -3192354, -818041395, + 2897314, 742437332, -1460718, -374309300, 0, 0, + 3950053, 1012201926, 1716988, 439978542, -2453983, -628833668, + 0, 0, 1935799, 496048908, -3756790, -962678241, + -1714295, -439288460, 0, 0, 3574466, 915957677, + 817536, 209493775, 3227876, 827143915, 0, 0, + -1759347, -450833045, -3415069, -875112161, 1335936, 342333886, + 0, 0, -2156050, -552488273, -3241972, -830756018, + -676590, -173376332, 0, 0, 4018989, 1029866791, + -2071829, -530906624, 434125, 111244624, 0, 0, + 3506380, 898510625, -1095468, -280713909, 3524442, 903139016, + 0, 0, -928749, -237992130, -394148, -101000509, + 1674615, 429120452, 0, 0, -1159875, -297218217, + -3704823, -949361686, -2663378, -682491182, 0, 0, + -2101410, -538486762, 3110818, 797147778, 4063053, 1041158200, + 0, 0, 3586446, 919027554, -2740543, -702264730, + 3370349, 863652652, 0, 0, -3182878, -815613168, + -3602218, -923069133, -294725, -75523344, -3761513, -963888510, + -3765607, -964937599, 3201430, 820367122, 3145678, 806080660, + 2883726, 738955404, 3201494, 820383522, 1221177, 312926867, + -557458, -142848732, 1005239, 257592709, -3764867, -964747974, + -2129892, -545785280, -2682288, -687336873, -3542485, -907762539, + 601683, 154181397, 0, 0, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_zetas) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h new file mode 100644 index 0000000000..e77f55014c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#define MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H + +#include +#include "../../../common.h" + +#define mld_aarch64_ntt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_ntt_zetas_layer123456) +#define mld_aarch64_ntt_zetas_layer78 MLD_NAMESPACE(aarch64_ntt_zetas_layer78) + +#define mld_aarch64_intt_zetas_layer78 MLD_NAMESPACE(aarch64_intt_zetas_layer78) +#define mld_aarch64_intt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_intt_zetas_layer123456) + +extern const int32_t mld_aarch64_ntt_zetas_layer123456[]; +extern const int32_t mld_aarch64_ntt_zetas_layer78[]; + +extern const int32_t mld_aarch64_intt_zetas_layer78[]; +extern const int32_t mld_aarch64_intt_zetas_layer123456[]; + +#define mld_rej_uniform_table MLD_NAMESPACE(rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[]; +#define mld_rej_uniform_eta_table MLD_NAMESPACE(rej_uniform_eta_table) +extern const uint8_t mld_rej_uniform_eta_table[]; + +#define mld_polyz_unpack_17_indices MLD_NAMESPACE(polyz_unpack_17_indices) +extern const uint8_t mld_polyz_unpack_17_indices[]; +#define mld_polyz_unpack_19_indices MLD_NAMESPACE(polyz_unpack_19_indices) +extern const uint8_t mld_polyz_unpack_19_indices[]; + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_ntt_asm MLD_NAMESPACE(ntt_asm) +void mld_ntt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_intt_asm MLD_NAMESPACE(intt_asm) +void mld_intt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_rej_uniform_asm MLD_NAMESPACE(rej_uniform_asm) +uint64_t mld_rej_uniform_asm(int32_t *r, const uint8_t *buf, unsigned buflen, + const uint8_t *table); + +#define mld_rej_uniform_eta2_asm MLD_NAMESPACE(rej_uniform_eta2_asm) +uint64_t mld_rej_uniform_eta2_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_rej_uniform_eta4_asm MLD_NAMESPACE(rej_uniform_eta4_asm) +uint64_t mld_rej_uniform_eta4_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_poly_decompose_32_asm MLD_NAMESPACE(poly_decompose_32_asm) +void mld_poly_decompose_32_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_asm MLD_NAMESPACE(poly_decompose_88_asm) +void mld_poly_decompose_88_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_asm MLD_NAMESPACE(poly_caddq_asm) +void mld_poly_caddq_asm(int32_t *a); + +#define mld_poly_use_hint_32_asm MLD_NAMESPACE(poly_use_hint_32_asm) +void mld_poly_use_hint_32_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_asm MLD_NAMESPACE(poly_use_hint_88_asm) +void mld_poly_use_hint_88_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_asm MLD_NAMESPACE(poly_chknorm_asm) +int mld_poly_chknorm_asm(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_asm MLD_NAMESPACE(polyz_unpack_17_asm) +void mld_polyz_unpack_17_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_polyz_unpack_19_asm MLD_NAMESPACE(polyz_unpack_19_asm) +void mld_polyz_unpack_19_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_poly_pointwise_montgomery_asm \ + MLD_NAMESPACE(poly_pointwise_montgomery_asm) +void mld_poly_pointwise_montgomery_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l4_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l4_asm) +void mld_polyvecl_pointwise_acc_montgomery_l4_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l5_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l5_asm) +void mld_polyvecl_pointwise_acc_montgomery_l5_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l7_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l7_asm) +void mld_polyvecl_pointwise_acc_montgomery_l7_asm(int32_t *, const int32_t *, + const int32_t *); + +#endif /* !MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c new file mode 100644 index 0000000000..7ef915b587 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* Table of indices used for tbl instructions in polyz_unpack_{17,19}. */ + +MLD_ALIGN const uint8_t mld_polyz_unpack_17_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, + 9, 10, 11, 255, 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, + 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, 8, 9, 10, 255, + 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, 17, 18, 19, 255, +}; + +MLD_ALIGN const uint8_t mld_polyz_unpack_19_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 5, 6, 7, 255, 7, 8, 9, 255, + 10, 11, 12, 255, 12, 13, 14, 255, 15, 16, 17, 255, 17, 18, 19, 255, + 4, 5, 6, 255, 6, 7, 8, 255, 9, 10, 11, 255, 11, 12, 13, 255, + 14, 15, 16, 255, 16, 17, 18, 255, 19, 20, 21, 255, 21, 22, 23, 255, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_polyz_unpack_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c new file mode 100644 index 0000000000..cf21509cbf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by 16-bit rejection sampling (rej_eta). + * Adapted from ML-KEM for ML-DSA eta rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_eta_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 2, 3, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 4, 5, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 2, 3, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 7 */, + 6, 7, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 2, 3, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 11 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 13 */, + 2, 3, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 15 */, + 8, 9, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 16 */, + 0, 1, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 17 */, + 2, 3, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 18 */, + 0, 1, 2, 3, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 19 */, + 4, 5, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 20 */, + 0, 1, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 21 */, + 2, 3, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 22 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 23 */, + 6, 7, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 24 */, + 0, 1, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 25 */, + 2, 3, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 26 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 27 */, + 4, 5, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 28 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 29 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 30 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 255, 255, 255, 255, 255, 255 /* 31 */, + 10, 11, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 32 */, + 0, 1, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 33 */, + 2, 3, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 34 */, + 0, 1, 2, 3, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 35 */, + 4, 5, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 36 */, + 0, 1, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 37 */, + 2, 3, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 38 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 39 */, + 6, 7, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 40 */, + 0, 1, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 41 */, + 2, 3, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 42 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 43 */, + 4, 5, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 44 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 45 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 46 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 255, 255, 255, 255, 255, 255 /* 47 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 48 */, + 0, 1, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 49 */, + 2, 3, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 50 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 51 */, + 4, 5, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 52 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 53 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 54 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 55 */, + 6, 7, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 56 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 57 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 58 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 59 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 60 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 61 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 62 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 63 */, + 12, 13, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 64 */, + 0, 1, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 65 */, + 2, 3, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 66 */, + 0, 1, 2, 3, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 67 */, + 4, 5, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 68 */, + 0, 1, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 69 */, + 2, 3, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 70 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 71 */, + 6, 7, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 72 */, + 0, 1, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 73 */, + 2, 3, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 74 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 75 */, + 4, 5, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 76 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 77 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 78 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 255, 255, 255, 255, 255, 255 /* 79 */, + 8, 9, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 80 */, + 0, 1, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 81 */, + 2, 3, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 82 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 83 */, + 4, 5, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 84 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 85 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 86 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 87 */, + 6, 7, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 88 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 89 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 90 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 91 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 92 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 93 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 94 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 255, 255, 255, 255 /* 95 */, + 10, 11, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 96 */, + 0, 1, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 97 */, + 2, 3, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 98 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 99 */, + 4, 5, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 100 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 101 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 102 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 103 */, + 6, 7, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 104 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 105 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 106 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 107 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 108 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 109 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 110 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 255, 255, 255, 255 /* 111 */, + 8, 9, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 112 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 113 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 114 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 115 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 116 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 117 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 118 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 119 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 120 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 121 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 122 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 123 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 124 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 125 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 126 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 255, 255 /* 127 */, + 14, 15, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 128 */, + 0, 1, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 129 */, + 2, 3, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 130 */, + 0, 1, 2, 3, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 131 */, + 4, 5, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 132 */, + 0, 1, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 133 */, + 2, 3, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 134 */, + 0, 1, 2, 3, 4, 5, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 135 */, + 6, 7, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 136 */, + 0, 1, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 137 */, + 2, 3, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 138 */, + 0, 1, 2, 3, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 139 */, + 4, 5, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 140 */, + 0, 1, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 141 */, + 2, 3, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 142 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 14, 15, 255, 255, 255, 255, 255, 255 /* 143 */, + 8, 9, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 144 */, + 0, 1, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 145 */, + 2, 3, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 146 */, + 0, 1, 2, 3, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 147 */, + 4, 5, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 148 */, + 0, 1, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 149 */, + 2, 3, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 150 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 151 */, + 6, 7, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 152 */, + 0, 1, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 153 */, + 2, 3, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 154 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 155 */, + 4, 5, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 156 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 157 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 158 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 14, 15, 255, 255, 255, 255 /* 159 */, + 10, 11, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 160 */, + 0, 1, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 161 */, + 2, 3, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 162 */, + 0, 1, 2, 3, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 163 */, + 4, 5, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 164 */, + 0, 1, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 165 */, + 2, 3, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 166 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 167 */, + 6, 7, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 168 */, + 0, 1, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 169 */, + 2, 3, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 170 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 171 */, + 4, 5, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 172 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 173 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 174 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 14, 15, 255, 255, 255, 255 /* 175 */, + 8, 9, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 176 */, + 0, 1, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 177 */, + 2, 3, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 178 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 179 */, + 4, 5, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 180 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 181 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 182 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 183 */, + 6, 7, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 184 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 185 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 186 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 187 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 188 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 189 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 190 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 14, 15, 255, 255 /* 191 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 192 */, + 0, 1, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 193 */, + 2, 3, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 194 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 195 */, + 4, 5, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 196 */, + 0, 1, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 197 */, + 2, 3, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 198 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 199 */, + 6, 7, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 200 */, + 0, 1, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 201 */, + 2, 3, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 202 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 203 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 204 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 205 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 206 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 207 */, + 8, 9, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 208 */, + 0, 1, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 209 */, + 2, 3, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 210 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 211 */, + 4, 5, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 212 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 213 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 214 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 215 */, + 6, 7, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 216 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 217 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 218 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 219 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 220 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 221 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 222 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 14, 15, 255, 255 /* 223 */, + 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 224 */, + 0, 1, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 225 */, + 2, 3, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 226 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 227 */, + 4, 5, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 228 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 229 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 230 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 231 */, + 6, 7, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 232 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 233 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 234 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 235 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 236 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 237 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 238 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 14, 15, 255, 255 /* 239 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 240 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 241 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 242 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 243 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 244 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 245 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 246 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 247 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 248 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 249 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 250 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 251 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 252 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 253 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 254 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 255 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_eta_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/src/rej_uniform_table.c new file mode 100644 index 0000000000..65bc3b78d3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/aarch64/src/rej_uniform_table.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by rejection sampling of the public matrix. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 7 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 11 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 13 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 15 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/api.h new file mode 100644 index 0000000000..0f1fdeb168 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/api.h @@ -0,0 +1,594 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_API_H +#define MLD_NATIVE_API_H +/* + * Native arithmetic interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + * + * To ensure consistency with backends, the header will be + * included automatically after inclusion of the active + * backend, to ensure consistency of function signatures, + * and run sanity checks. + */ + +#include +#include "../cbmc.h" +#include "../common.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* Bound on absolute value of coefficients after NTT. + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) + +/* Absolute exclusive upper bound for the output of the inverse NTT + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_INTT_BOUND MLDSA_Q + +/* Absolute bound for range of mld_reduce32() + * + * NOTE: This is the same bound as in reduce.h and has to be kept + * in sync. */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define REDUCE32_RANGE_MAX 6283009 +/* + * This is the C<->native interface allowing for the drop-in of + * native code for performance critical arithmetic components of ML-DSA. + * + * A _backend_ is a specific implementation of (part of) this interface. + * + * To add a function to a backend, define MLD_USE_NATIVE_XXX and + * implement `static inline xxx(...)` in the profile header. + */ + +/* + * Those functions are meant to be trivial wrappers around the chosen native + * implementation. The are static inline to avoid unnecessary calls. + * The macro before each declaration controls whether a native + * implementation is present. + */ + +#if defined(MLD_USE_NATIVE_NTT) +/************************************************* + * Name: mld_ntt_native + * + * Description: Computes negacyclic number-theoretic transform (NTT) of + * a polynomial in place. + * + * The input polynomial is assumed to be in normal order. + * The output polynomial is in bitreversed order. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_ntt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_NTT */ + + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) +/* + * This must only be set if NTT and INTT have native implementations + * that are adapted to the custom order. + */ +#if !defined(MLD_USE_NATIVE_NTT) || !defined(MLD_USE_NATIVE_INTT) +#error \ + "Invalid native profile: MLD_USE_NATIVE_NTT_CUSTOM_ORDER can only be \ +set if there are native implementations for NTT and INTT." +#endif + +/************************************************* + * Name: mlD_poly_permute_bitrev_to_custom + * + * Description: When MLD_USE_NATIVE_NTT_CUSTOM_ORDER is defined, + * convert a polynomial in NTT domain from bitreversed + * order to the custom order output by the native NTT. + * + * This must only be defined if there is native code for + * both the NTT and INTT. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + * + **************************************************/ +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t p[MLDSA_N]) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q))); +#endif /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + + +#if defined(MLD_USE_NATIVE_INTT) +/************************************************* + * Name: mld_intt_native + * + * Description: Computes inverse of negacyclic number-theoretic transform + *(NTT) of a polynomial in place. + * + * The input polynomial is in bitreversed order. + * The output polynomial is assumed to be in normal order. + * + * Arguments: - uint32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_intt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_INTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_INTT */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) +/************************************************* + * Name: mld_rej_uniform_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [0, MLDSA_Q-1] + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform mod q). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + * lengths. Otherwise, returns non-negative number of sampled 32-bit integers + * (at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= ( 5 * 168) && buflen % 3 == 0) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(r, 0, (unsigned) return_value, 0, MLDSA_Q)) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) +/************************************************* + * Name: mld_rej_uniform_eta2_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-2,+2]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-2, +2]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA2 */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) +/************************************************* + * Name: mld_rej_uniform_eta4_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-4,+4]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-4, +4]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) +/************************************************* + * Name: mld_poly_decompose_32_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/32. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: input/output polynomial. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_32 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) +/************************************************* + * Name: mld_poly_decompose_88_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/88. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: output polynomial with coefficients c0. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CADDQ) +/************************************************* + * Name: mld_poly_caddq_native + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *a: pointer to input/output polynomial + **************************************************/ +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_32) +/************************************************* + * Name: mld_poly_use_hint_32_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/32. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_32 */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) +/************************************************* + * Name: mld_poly_use_hint_88_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/88. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) +/************************************************* + * Name: mld_poly_chknorm_native + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const int32_t *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if the infinity norm is strictly smaller than B, and 1 + * otherwise. B must not be larger than MLDSA_Q - MLD_REDUCE32_RANGE_MAX. + **************************************************/ +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(0 <= B && B <= MLDSA_Q - REDUCE32_RANGE_MAX) + requires(array_bound(a, 0, MLDSA_N, -REDUCE32_RANGE_MAX, REDUCE32_RANGE_MAX)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == 0) == array_abs_bound(a, 0, MLDSA_N, B)) +); +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) +/************************************************* + * Name: mld_polyz_unpack_17_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^17. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_17 */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) +/************************************************* + * Name: mld_polyz_unpack_19_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^19. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_19 */ + +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) +/************************************************* + * Name: mld_poly_pointwise_montgomery_native + * + * Description: Pointwise multiplication of polynomials in NTT domain + * with Montgomery reduction. + * + * Computes c[i] = a[i] * b[i] * R^(-1) mod q for all i, + * where R = 2^32. + * + * Arguments: - int32_t c[MLDSA_N]: output polynomial + * - const int32_t a[MLDSA_N]: first input polynomial + * - const int32_t b[MLDSA_N]: second input polynomial + **************************************************/ +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(c, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(c, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(c, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l4_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 4. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 4 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 4 * MLDSA_N)) + requires(forall(l0, 0, 4, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 4, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l5_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 5. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 5 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 5 * MLDSA_N)) + requires(forall(l0, 0, 5, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 5, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l7_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 7. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 7 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 7 * MLDSA_N)) + requires(forall(l0, 0, 7, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 7, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 */ + +#endif /* !MLD_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/meta.h new file mode 100644 index 0000000000..0b46dd5791 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/meta.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_META_H +#define MLD_NATIVE_META_H + +/* + * Default arithmetic backend + */ +#include "../sys.h" + +#ifdef MLD_SYS_AARCH64 +#include "aarch64/meta.h" +#endif + +#ifdef MLD_SYS_X86_64_AVX2 +#include "x86_64/meta.h" +#endif + +#endif /* !MLD_NATIVE_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/meta.h new file mode 100644 index 0000000000..393374c06f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/meta.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_X86_64_META_H +#define MLD_NATIVE_X86_64_META_H + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_X86_64_DEFAULT + +#define MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +#if !defined(__ASSEMBLER__) +#include +#include "../../common.h" +#include "../api.h" +#include "src/arith_native_x86_64.h" + +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t data[MLDSA_N]) +{ + if (mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + mld_nttunpack_avx2(data); + } +} + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_ntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_invntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)mld_rej_uniform_avx2(r, buf); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_32_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_88_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_caddq_avx2(a); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_32_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_88_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + return mld_poly_chknorm_avx2(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_17_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_19_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_avx2(c, a, b, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l4_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l5_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l7_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_NATIVE_X86_64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h new file mode 100644 index 0000000000..08d5abf74a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#define MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#include "../../../common.h" + +#include +#include "consts.h" + +#define MLD_AVX2_REJ_UNIFORM_BUFLEN \ + (5 * 168) /* REJ_UNIFORM_NBLOCKS * SHAKE128_RATE */ + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) + +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_rej_uniform_table MLD_NAMESPACE(mld_rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[256][8]; + +#define mld_ntt_avx2 MLD_NAMESPACE(ntt_avx2) +void mld_ntt_avx2(int32_t *r, const int32_t *qdata) +/* This must be kept in sync with the HOL-Light specification + * in proofs/hol_light/x86_64/proofs/mldsa_ntt.ml */ +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, MLDSA_N, 8380417)) + requires(qdata == mld_qdata) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + /* check-magic: off */ + ensures(array_abs_bound(r, 0, MLDSA_N, 42035262)) + /* check-magic: on */ +); + +#define mld_invntt_avx2 MLD_NAMESPACE(invntt_avx2) +void mld_invntt_avx2(int32_t *r, const int32_t *mld_qdata); + +#define mld_nttunpack_avx2 MLD_NAMESPACE(nttunpack_avx2) +void mld_nttunpack_avx2(int32_t *r); + +#define mld_rej_uniform_avx2 MLD_NAMESPACE(mld_rej_uniform_avx2) +unsigned mld_rej_uniform_avx2(int32_t *r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]); + +#define mld_rej_uniform_eta2_avx2 MLD_NAMESPACE(mld_rej_uniform_eta2_avx2) +unsigned mld_rej_uniform_eta2_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]); + +#define mld_rej_uniform_eta4_avx2 MLD_NAMESPACE(mld_rej_uniform_eta4_avx2) +unsigned mld_rej_uniform_eta4_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]); + +#define mld_poly_decompose_32_avx2 MLD_NAMESPACE(mld_poly_decompose_32_avx2) +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_avx2 MLD_NAMESPACE(mld_poly_decompose_88_avx2) +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_avx2 MLD_NAMESPACE(poly_caddq_avx2) +void mld_poly_caddq_avx2(int32_t *r); + +#define mld_poly_use_hint_32_avx2 MLD_NAMESPACE(mld_poly_use_hint_32_avx2) +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_avx2 MLD_NAMESPACE(mld_poly_use_hint_88_avx2) +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_avx2 MLD_NAMESPACE(mld_poly_chknorm_avx2) +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_avx2 MLD_NAMESPACE(mld_polyz_unpack_17_avx2) +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a); + +#define mld_polyz_unpack_19_avx2 MLD_NAMESPACE(mld_polyz_unpack_19_avx2) +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a); + +#define mld_pointwise_avx2 MLD_NAMESPACE(pointwise_avx2) +void mld_pointwise_avx2(int32_t *c, const int32_t *a, const int32_t *b, + const int32_t *qdata); + +#define mld_pointwise_acc_l4_avx2 MLD_NAMESPACE(pointwise_acc_l4_avx2) +void mld_pointwise_acc_l4_avx2(int32_t c[MLDSA_N], const int32_t a[4][MLDSA_N], + const int32_t b[4][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l5_avx2 MLD_NAMESPACE(pointwise_acc_l5_avx2) +void mld_pointwise_acc_l5_avx2(int32_t c[MLDSA_N], const int32_t a[5][MLDSA_N], + const int32_t b[5][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l7_avx2 MLD_NAMESPACE(pointwise_acc_l7_avx2) +void mld_pointwise_acc_l7_avx2(int32_t c[MLDSA_N], const int32_t a[7][MLDSA_N], + const int32_t b[7][MLDSA_N], + const int32_t *qdata); + +#endif /* !MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/consts.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/consts.c new file mode 100644 index 0000000000..aaca3535ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/consts.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include "consts.h" + +/* + * Table of zeta values used in the AVX2 forward and inverse NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_qdata[624] = { + 8380417, 8380417, 8380417, 8380417, 8380417, + 8380417, 8380417, 8380417, 58728449, 58728449, + 58728449, 58728449, 58728449, 58728449, 58728449, + 58728449, -8395782, -8395782, -8395782, -8395782, + -8395782, -8395782, -8395782, -8395782, 41978, + 41978, 41978, 41978, 41978, 41978, + 41978, 41978, -151046689, 1830765815, -1929875198, + -1927777021, 1640767044, 1477910808, 1612161320, 1640734244, + 308362795, 308362795, 308362795, 308362795, -1815525077, + -1815525077, -1815525077, -1815525077, -1374673747, -1374673747, + -1374673747, -1374673747, -1091570561, -1091570561, -1091570561, + -1091570561, -1929495947, -1929495947, -1929495947, -1929495947, + 515185417, 515185417, 515185417, 515185417, -285697463, + -285697463, -285697463, -285697463, 625853735, 625853735, + 625853735, 625853735, 1727305304, 1727305304, 2082316400, + 2082316400, -1364982364, -1364982364, 858240904, 858240904, + 1806278032, 1806278032, 222489248, 222489248, -346752664, + -346752664, 684667771, 684667771, 1654287830, 1654287830, + -878576921, -878576921, -1257667337, -1257667337, -748618600, + -748618600, 329347125, 329347125, 1837364258, 1837364258, + -1443016191, -1443016191, -1170414139, -1170414139, -1846138265, + -1631226336, -1404529459, 1838055109, 1594295555, -1076973524, + -1898723372, -594436433, -202001019, -475984260, -561427818, + 1797021249, -1061813248, 2059733581, -1661512036, -1104976547, + -1750224323, -901666090, 418987550, 1831915353, -1925356481, + 992097815, 879957084, 2024403852, 1484874664, -1636082790, + -285388938, -1983539117, -1495136972, -950076368, -1714807468, + -952438995, -1574918427, 1350681039, -2143979939, 1599739335, + -1285853323, -993005454, -1440787840, 568627424, -783134478, + -588790216, 289871779, -1262003603, 2135294594, -1018755525, + -889861155, 1665705315, 1321868265, 1225434135, -1784632064, + 666258756, 675310538, -1555941048, -1999506068, -1499481951, + -695180180, -1375177022, 1777179795, 334803717, -178766299, + -518252220, 1957047970, 1146323031, -654783359, -1974159335, + 1651689966, 140455867, -1039411342, 1955560694, 1529189038, + -2131021878, -247357819, 1518161567, -86965173, 1708872713, + 1787797779, 1638590967, -120646188, -1669960606, -916321552, + 1155548552, 2143745726, 1210558298, -1261461890, -318346816, + 628664287, -1729304568, 1422575624, 1424130038, -1185330464, + 235321234, 168022240, 1206536194, 985155484, -894060583, + -898413, -1363460238, -605900043, 2027833504, 14253662, + 1014493059, 863641633, 1819892093, 2124962073, -1223601433, + -1920467227, -1637785316, -1536588520, 694382729, 235104446, + -1045062172, 831969619, -300448763, 756955444, -260312805, + 1554794072, 1339088280, -2040058690, -853476187, -2047270596, + -1723816713, -1591599803, -440824168, 1119856484, 1544891539, + 155290192, -973777462, 991903578, 912367099, -44694137, + 1176904444, -421552614, -818371958, 1747917558, -325927722, + 908452108, 1851023419, -1176751719, -1354528380, -72690498, + -314284737, 985022747, 963438279, -1078959975, 604552167, + -1021949428, 608791570, 173440395, -2126092136, -1316619236, + -1039370342, 6087993, -110126092, 565464272, -1758099917, + -1600929361, 879867909, -1809756372, 400711272, 1363007700, + 30313375, -326425360, 1683520342, -517299994, 2027935492, + -1372618620, 128353682, -1123881663, 137583815, -635454918, + -642772911, 45766801, 671509323, -2070602178, 419615363, + 1216882040, -270590488, -1276805128, 371462360, -1357098057, + -384158533, 827959816, -596344473, 702390549, -279505433, + -260424530, -71875110, -1208667171, -1499603926, 2036925262, + -540420426, 746144248, -1420958686, 2032221021, 1904936414, + 1257750362, 1926727420, 1931587462, 1258381762, 885133339, + 1629985060, 1967222129, 6363718, -1287922800, 1136965286, + 1779436847, 1116720494, 1042326957, 1405999311, 713994583, + 940195359, -1542497137, 2061661095, -883155599, 1726753853, + -1547952704, 394851342, 283780712, 776003547, 1123958025, + 201262505, 1934038751, 374860238, -3975713, 25847, + -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 1826347, 1826347, 1826347, + 2353451, 2353451, 2353451, 2353451, -359251, + -359251, -359251, -359251, -2091905, -2091905, + -2091905, -2091905, 3119733, 3119733, 3119733, + 3119733, -2884855, -2884855, -2884855, -2884855, + 3111497, 3111497, 3111497, 3111497, 2680103, + 2680103, 2680103, 2680103, 2725464, 2725464, + 1024112, 1024112, -1079900, -1079900, 3585928, + 3585928, -549488, -549488, -1119584, -1119584, + 2619752, 2619752, -2108549, -2108549, -2118186, + -2118186, -3859737, -3859737, -1399561, -1399561, + -3277672, -3277672, 1757237, 1757237, -19422, + -19422, 4010497, 4010497, 280005, 280005, + 2706023, 95776, 3077325, 3530437, -1661693, + -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, + -539299, -1699267, -1643818, 3505694, -3821735, + 3507263, -2140649, -1600420, 3699596, 811944, + 531354, 954230, 3881043, 3900724, -2556880, + 2071892, -2797779, -3930395, -3677745, -1452451, + 2176455, -1257611, -4083598, -3190144, -3632928, + 3412210, 2147896, -2967645, -411027, -671102, + -22981, -381987, 1852771, -3343383, 508951, + 44288, 904516, -3724342, 1653064, 2389356, + 759969, 189548, 3159746, -2409325, 1315589, + 1285669, -812732, -3019102, -3628969, -1528703, + -3041255, 3475950, -1585221, 1939314, -1000202, + -3157330, 126922, -983419, 2715295, -3693493, + -2477047, -1228525, -1308169, 1349076, -1430430, + 264944, 3097992, -1100098, 3958618, -8578, + -3249728, -210977, -1316856, -3553272, -1851402, + -177440, 1341330, -1584928, -1439742, -3881060, + 3839961, 2091667, -3342478, 266997, -3520352, + 900702, 495491, -655327, -3556995, 342297, + 3437287, 2842341, 4055324, -3767016, -2994039, + -1333058, -451100, -1279661, 1500165, -542412, + -2584293, -2013608, 1957272, -3183426, 810149, + -3038916, 2213111, -426683, -1667432, -2939036, + 183443, -554416, 3937738, 3407706, 2244091, + 2434439, -3759364, 1859098, -1613174, -3122442, + -525098, 286988, -3342277, 2691481, 1247620, + 1250494, 1869119, 1237275, 1312455, 1917081, + 777191, -2831860, -3724270, 2432395, 3369112, + 162844, 1652634, 3523897, -975884, 1723600, + -1104333, -2235985, -976891, 3919660, 1400424, + 2316500, -2446433, -1235728, -1197226, 909542, + -43260, 2031748, -768622, -2437823, 1735879, + -2590150, 2486353, 2635921, 1903435, -3318210, + 3306115, -2546312, 2235880, -1671176, 594136, + 2454455, 185531, 1616392, -3694233, 3866901, + 1717735, -1803090, -260646, -420899, 1612842, + -48306, -846154, 3817976, -3562462, 3513181, + -3193378, 819034, -522500, 3207046, -3595838, + 4108315, 203044, 1265009, 1595974, -3548272, + -1050970, -1430225, -1962642, -1374803, 3406031, + -1846953, -3776993, -164721, -1207385, 3014001, + -1799107, 269760, 472078, 1910376, -3833893, + -2286327, -3545687, -1362209, 1976782, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_consts) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/consts.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/consts.h new file mode 100644 index 0000000000..7fe08f454b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/consts.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#ifndef MLD_NATIVE_X86_64_SRC_CONSTS_H +#define MLD_NATIVE_X86_64_SRC_CONSTS_H +#include "../../../common.h" +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQ 0 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV 8 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV 16 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV 24 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV 32 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS 328 + +#ifndef __ASSEMBLER__ +#define mld_qdata MLD_NAMESPACE(qdata) +extern const int32_t mld_qdata[624]; +#endif + +#endif /* !MLD_NATIVE_X86_64_SRC_CONSTS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c new file mode 100644 index 0000000000..05d86d14fc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/************************************************* + * Name: mld_poly_caddq_avx2 + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *r: pointer to input/output polynomial + **************************************************/ +void mld_poly_caddq_avx2(int32_t *r) +{ + unsigned int i; + __m256i f, g; + const __m256i q = _mm256_set1_epi32(MLDSA_Q); + const __m256i zero = _mm256_setzero_si256(); + __m256i *rr = (__m256i *)r; + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256(&rr[i]); + g = _mm256_cmpgt_epi32(zero, f); + g = _mm256_and_si256(g, q); + f = _mm256_add_epi32(f, g); + _mm256_store_si256(&rr[i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_reduce) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c new file mode 100644 index 0000000000..50e2c7fa9b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B) +{ + unsigned int i; + __m256i f, t; + const __m256i bound = _mm256_set1_epi32(B - 1); + + t = _mm256_setzero_si256(); + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + f = _mm256_abs_epi32(f); + f = _mm256_cmpgt_epi32(f, bound); + t = _mm256_or_si256(t, f); + } + + return 1 - _mm256_testz_si256(t, t); +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_chknorm) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c new file mode 100644 index 0000000000..76846bf1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(31 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 4092 == intdiv(2 * intdiv(MLDSA_Q - 1, 32), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 4092. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 32*GAMMA2 = 16*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 16B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + * + * round(f1' * 1025 / 2^22) is in turn computed in 2 steps as + * round(floor(f1' * 1025 / 2^16) / 2^6). The mulhi computes f1'' = + * floor(f1' * 1025 / 2^16). As for the next step f1 = round(f1'' / 2^6), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^9) = round(f1'' * 2^9 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 1025 / 2^16) = 1025 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(16B / B) = 16 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 16, i.e. f > 31*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 31*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 15, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c new file mode 100644 index 0000000000..463506b962 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ + +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 1488 == intdiv(2 * intdiv(MLDSA_Q - 1, 88), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 1488. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 88*GAMMA2 = 44*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 44B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + * + * round(f1' * 11275 / 2^24) is in turn computed in 2 steps as + * round(floor(f1' * 11275 / 2^16) / 2^8). The mulhi computes f1'' = + * floor(f1' * 11275 / 2^16). As for the next step f1 = round(f1'' / 2^8), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^7) = round(f1'' * 2^7 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 11275 / 2^16) = 11275 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(44B / B) = 44 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 44, i.e. f > 87*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 87*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 43, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c new file mode 100644 index 0000000000..0094bc93a9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + const __m256i mask = _mm256_set1_epi32(15); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_32_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 16 */ + f1 = _mm256_add_epi32(f1, h); + f1 = _mm256_and_si256(f1, mask); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c new file mode 100644 index 0000000000..b109ab6351 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + const __m256i max = _mm256_set1_epi32(43); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_88_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 44 */ + f1 = _mm256_add_epi32(f1, h); + f1 = MLD_MM256_BLENDV_EPI32(f1, max, f1); + f = _mm256_cmpgt_epi32(f1, max); + f1 = MLD_MM256_BLENDV_EPI32(f1, zero, f); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c new file mode 100644 index 0000000000..f6c08a832f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 27, 26, 25, -1, 25, 24, 23, -1, 8, 7, + 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0); + const __m256i srlvdidx = _mm256_set_epi32(6, 4, 2, 0, 6, 4, 2, 0); + const __m256i mask = _mm256_set1_epi32(0x3FFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 17)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[18 * i]); + /* Load bytes 2..17 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[18 * i + 2]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-8 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 8, 7, 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte8, byte7, byte6, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,27, 26, 25, -1,25, 24, 23] │ + * │ Result: [0, byte17, byte16, byte15, ..., 0, byte11, byte10, byte9] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 18 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 32..55 48..71 + * 72..95 88..111 104..127 120..143 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 18..39 36..55 54..71 + * 72..95 90..111 108..127 126..143 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..17 18..35 36..53 54..71 + * 72..89 90..107 108..125 126..143 */ + + /* Map [0, 1, ..., 2^18-1] to [2^17, 2^17-1, ..., -2^17+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_17) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c new file mode 100644 index 0000000000..4a5ce48f38 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 26, 25, 24, -1, 24, 23, 22, -1, 9, 8, + 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0); + /* Equivalent to _mm256_set_epi32(4, 0, 4, 0, 4, 0, 4, 0) */ + const __m256i srlvdidx = _mm256_set1_epi64x((uint64_t)4 << 32); + const __m256i mask = _mm256_set1_epi32(0xFFFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 19)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[20 * i]); + /* Load bytes 4..19 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[20 * i + 4]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-9 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 9, 8, 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte9, byte8, byte7, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,26, 25, 24, -1,24, 23, 22] │ + * │ Result: [0, byte19, byte18, byte17, ..., 0, byte12, byte11, byte10] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 20 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 40..63 56..79 + * 80..103 96..119 120..143 136..159 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 20..39 40..63 60..79 + * 80..103 100..119 120..143 140..159 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..19 20..39 40..59 60..79 + * 80..99 100..119 120..139 140..159 */ + + /* Map [0, 1, ..., 2^20-1] to [2^19, 2^19-1, ..., -2^19+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_19) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c new file mode 100644 index 0000000000..07a5df9706 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The pqcrystals implementation assumes a buffer that is 8 bytes + *. larger as the first loop overreads by 8 bytes that are then + * discarded. We instead do not pad the buffer and do not overread. + * The performance impact is negligible and it does not force the + * frontend to perform the unintuitive padding. + */ + +unsigned int mld_rej_uniform_avx2( + int32_t *MLD_RESTRICT r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i d, tmp; + const __m256i bound = _mm256_set1_epi32(MLDSA_Q); + const __m256i mask = _mm256_set1_epi32(0x7FFFFF); + const __m256i idx8 = + _mm256_set_epi8(-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4, + -1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 32) + { + d = _mm256_loadu_si256((__m256i *)&buf[pos]); + + /* Permute 64-bit lanes + * 0x94 = 10010100b rearranges 64-bit lanes as: [3,2,1,0] -> [2,1,1,0] + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Original Layout ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ bytes 16..23 │ bytes 24..31 │ + * └─────────────────┴─────────────────┴─────────────────┴─────────────────┘ + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Layout after permute ║ + * ║ Byte indices in high half shifted down by 8 positions ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌───────────────┬─────────────────┐ ┌─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ │ bytes 8..15 │ bytes 16..23 │ + * └───────────────┴─────────────────┘ └─────────────────┴─────────────────┘ + * Lower 128-bit lane (bytes 0-15) Upper 128-bit lane (bytes 16-31) + */ + d = _mm256_permute4x64_epi64(d, 0x94); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-11 into low 128-bit half of permuted vector────────────────┐ + * │ Shuffle: [-1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0] │ + * │ Result: [0, byte11, byte10, byte9, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 4-15 into high 128-bit half of permuted vector ──────────────┐ + * │ Shuffle: [-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4] │ + * │ Result: [0, byte23, byte22, byte21, ..., 0, byte14, byte13, byte12 │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + d = _mm256_shuffle_epi8(d, idx8); + d = _mm256_and_si256(d, mask); + pos += 24; + + tmp = _mm256_sub_epi32(d, bound); + good = (uint32_t)_mm256_movemask_ps((__m256)tmp); + tmp = _mm256_cvtepu8_epi32( + _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good])); + d = _mm256_permutevar8x32_epi32(d, tmp); + + _mm256_storeu_si256((__m256i *)&r[ctr], d); + ctr += (unsigned)_mm_popcnt_u32(good); + } + + while (ctr < MLDSA_N && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 3) + { + uint32_t t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + /* Safe because t < MLDSA_Q. */ + r[ctr++] = (int32_t)t; + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c new file mode 100644 index 0000000000..70c5c42c70 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA2 2 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ +unsigned int mld_rej_uniform_eta2_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1, f2; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA2); + const __m256i bound = mask; + /* check-magic: -6560 == 32*round(-2**10 / 5) */ + const __m256i v = _mm256_set1_epi32(-6560); + const __m256i p = _mm256_set1_epi32(5); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 15) + { + t0 = t0 - (205 * t0 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t0); + } + if (t1 < 15 && ctr < MLDSA_N) + { + t1 = t1 - (205 * t1 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta2) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA2 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c new file mode 100644 index 0000000000..ba00e91252 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA4 4 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ + +unsigned int mld_rej_uniform_eta4_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA4); + const __m256i bound = _mm256_set1_epi8(9); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 9) + { + r[ctr++] = (int32_t)(4 - t0); + } + if (t1 < 9 && ctr < MLDSA_N) + { + r[ctr++] = (int32_t)(4 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta4) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA4 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/rej_uniform_table.c new file mode 100644 index 0000000000..6c537b4542 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/native/x86_64/src/rej_uniform_table.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" + +/* + * Lookup table used by rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[256][8] = { + {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, + {2, 0, 0, 0, 0, 0, 0, 0}, {0, 2, 0, 0, 0, 0, 0, 0}, + {1, 2, 0, 0, 0, 0, 0, 0}, {0, 1, 2, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 0, 0}, {0, 3, 0, 0, 0, 0, 0, 0}, + {1, 3, 0, 0, 0, 0, 0, 0}, {0, 1, 3, 0, 0, 0, 0, 0}, + {2, 3, 0, 0, 0, 0, 0, 0}, {0, 2, 3, 0, 0, 0, 0, 0}, + {1, 2, 3, 0, 0, 0, 0, 0}, {0, 1, 2, 3, 0, 0, 0, 0}, + {4, 0, 0, 0, 0, 0, 0, 0}, {0, 4, 0, 0, 0, 0, 0, 0}, + {1, 4, 0, 0, 0, 0, 0, 0}, {0, 1, 4, 0, 0, 0, 0, 0}, + {2, 4, 0, 0, 0, 0, 0, 0}, {0, 2, 4, 0, 0, 0, 0, 0}, + {1, 2, 4, 0, 0, 0, 0, 0}, {0, 1, 2, 4, 0, 0, 0, 0}, + {3, 4, 0, 0, 0, 0, 0, 0}, {0, 3, 4, 0, 0, 0, 0, 0}, + {1, 3, 4, 0, 0, 0, 0, 0}, {0, 1, 3, 4, 0, 0, 0, 0}, + {2, 3, 4, 0, 0, 0, 0, 0}, {0, 2, 3, 4, 0, 0, 0, 0}, + {1, 2, 3, 4, 0, 0, 0, 0}, {0, 1, 2, 3, 4, 0, 0, 0}, + {5, 0, 0, 0, 0, 0, 0, 0}, {0, 5, 0, 0, 0, 0, 0, 0}, + {1, 5, 0, 0, 0, 0, 0, 0}, {0, 1, 5, 0, 0, 0, 0, 0}, + {2, 5, 0, 0, 0, 0, 0, 0}, {0, 2, 5, 0, 0, 0, 0, 0}, + {1, 2, 5, 0, 0, 0, 0, 0}, {0, 1, 2, 5, 0, 0, 0, 0}, + {3, 5, 0, 0, 0, 0, 0, 0}, {0, 3, 5, 0, 0, 0, 0, 0}, + {1, 3, 5, 0, 0, 0, 0, 0}, {0, 1, 3, 5, 0, 0, 0, 0}, + {2, 3, 5, 0, 0, 0, 0, 0}, {0, 2, 3, 5, 0, 0, 0, 0}, + {1, 2, 3, 5, 0, 0, 0, 0}, {0, 1, 2, 3, 5, 0, 0, 0}, + {4, 5, 0, 0, 0, 0, 0, 0}, {0, 4, 5, 0, 0, 0, 0, 0}, + {1, 4, 5, 0, 0, 0, 0, 0}, {0, 1, 4, 5, 0, 0, 0, 0}, + {2, 4, 5, 0, 0, 0, 0, 0}, {0, 2, 4, 5, 0, 0, 0, 0}, + {1, 2, 4, 5, 0, 0, 0, 0}, {0, 1, 2, 4, 5, 0, 0, 0}, + {3, 4, 5, 0, 0, 0, 0, 0}, {0, 3, 4, 5, 0, 0, 0, 0}, + {1, 3, 4, 5, 0, 0, 0, 0}, {0, 1, 3, 4, 5, 0, 0, 0}, + {2, 3, 4, 5, 0, 0, 0, 0}, {0, 2, 3, 4, 5, 0, 0, 0}, + {1, 2, 3, 4, 5, 0, 0, 0}, {0, 1, 2, 3, 4, 5, 0, 0}, + {6, 0, 0, 0, 0, 0, 0, 0}, {0, 6, 0, 0, 0, 0, 0, 0}, + {1, 6, 0, 0, 0, 0, 0, 0}, {0, 1, 6, 0, 0, 0, 0, 0}, + {2, 6, 0, 0, 0, 0, 0, 0}, {0, 2, 6, 0, 0, 0, 0, 0}, + {1, 2, 6, 0, 0, 0, 0, 0}, {0, 1, 2, 6, 0, 0, 0, 0}, + {3, 6, 0, 0, 0, 0, 0, 0}, {0, 3, 6, 0, 0, 0, 0, 0}, + {1, 3, 6, 0, 0, 0, 0, 0}, {0, 1, 3, 6, 0, 0, 0, 0}, + {2, 3, 6, 0, 0, 0, 0, 0}, {0, 2, 3, 6, 0, 0, 0, 0}, + {1, 2, 3, 6, 0, 0, 0, 0}, {0, 1, 2, 3, 6, 0, 0, 0}, + {4, 6, 0, 0, 0, 0, 0, 0}, {0, 4, 6, 0, 0, 0, 0, 0}, + {1, 4, 6, 0, 0, 0, 0, 0}, {0, 1, 4, 6, 0, 0, 0, 0}, + {2, 4, 6, 0, 0, 0, 0, 0}, {0, 2, 4, 6, 0, 0, 0, 0}, + {1, 2, 4, 6, 0, 0, 0, 0}, {0, 1, 2, 4, 6, 0, 0, 0}, + {3, 4, 6, 0, 0, 0, 0, 0}, {0, 3, 4, 6, 0, 0, 0, 0}, + {1, 3, 4, 6, 0, 0, 0, 0}, {0, 1, 3, 4, 6, 0, 0, 0}, + {2, 3, 4, 6, 0, 0, 0, 0}, {0, 2, 3, 4, 6, 0, 0, 0}, + {1, 2, 3, 4, 6, 0, 0, 0}, {0, 1, 2, 3, 4, 6, 0, 0}, + {5, 6, 0, 0, 0, 0, 0, 0}, {0, 5, 6, 0, 0, 0, 0, 0}, + {1, 5, 6, 0, 0, 0, 0, 0}, {0, 1, 5, 6, 0, 0, 0, 0}, + {2, 5, 6, 0, 0, 0, 0, 0}, {0, 2, 5, 6, 0, 0, 0, 0}, + {1, 2, 5, 6, 0, 0, 0, 0}, {0, 1, 2, 5, 6, 0, 0, 0}, + {3, 5, 6, 0, 0, 0, 0, 0}, {0, 3, 5, 6, 0, 0, 0, 0}, + {1, 3, 5, 6, 0, 0, 0, 0}, {0, 1, 3, 5, 6, 0, 0, 0}, + {2, 3, 5, 6, 0, 0, 0, 0}, {0, 2, 3, 5, 6, 0, 0, 0}, + {1, 2, 3, 5, 6, 0, 0, 0}, {0, 1, 2, 3, 5, 6, 0, 0}, + {4, 5, 6, 0, 0, 0, 0, 0}, {0, 4, 5, 6, 0, 0, 0, 0}, + {1, 4, 5, 6, 0, 0, 0, 0}, {0, 1, 4, 5, 6, 0, 0, 0}, + {2, 4, 5, 6, 0, 0, 0, 0}, {0, 2, 4, 5, 6, 0, 0, 0}, + {1, 2, 4, 5, 6, 0, 0, 0}, {0, 1, 2, 4, 5, 6, 0, 0}, + {3, 4, 5, 6, 0, 0, 0, 0}, {0, 3, 4, 5, 6, 0, 0, 0}, + {1, 3, 4, 5, 6, 0, 0, 0}, {0, 1, 3, 4, 5, 6, 0, 0}, + {2, 3, 4, 5, 6, 0, 0, 0}, {0, 2, 3, 4, 5, 6, 0, 0}, + {1, 2, 3, 4, 5, 6, 0, 0}, {0, 1, 2, 3, 4, 5, 6, 0}, + {7, 0, 0, 0, 0, 0, 0, 0}, {0, 7, 0, 0, 0, 0, 0, 0}, + {1, 7, 0, 0, 0, 0, 0, 0}, {0, 1, 7, 0, 0, 0, 0, 0}, + {2, 7, 0, 0, 0, 0, 0, 0}, {0, 2, 7, 0, 0, 0, 0, 0}, + {1, 2, 7, 0, 0, 0, 0, 0}, {0, 1, 2, 7, 0, 0, 0, 0}, + {3, 7, 0, 0, 0, 0, 0, 0}, {0, 3, 7, 0, 0, 0, 0, 0}, + {1, 3, 7, 0, 0, 0, 0, 0}, {0, 1, 3, 7, 0, 0, 0, 0}, + {2, 3, 7, 0, 0, 0, 0, 0}, {0, 2, 3, 7, 0, 0, 0, 0}, + {1, 2, 3, 7, 0, 0, 0, 0}, {0, 1, 2, 3, 7, 0, 0, 0}, + {4, 7, 0, 0, 0, 0, 0, 0}, {0, 4, 7, 0, 0, 0, 0, 0}, + {1, 4, 7, 0, 0, 0, 0, 0}, {0, 1, 4, 7, 0, 0, 0, 0}, + {2, 4, 7, 0, 0, 0, 0, 0}, {0, 2, 4, 7, 0, 0, 0, 0}, + {1, 2, 4, 7, 0, 0, 0, 0}, {0, 1, 2, 4, 7, 0, 0, 0}, + {3, 4, 7, 0, 0, 0, 0, 0}, {0, 3, 4, 7, 0, 0, 0, 0}, + {1, 3, 4, 7, 0, 0, 0, 0}, {0, 1, 3, 4, 7, 0, 0, 0}, + {2, 3, 4, 7, 0, 0, 0, 0}, {0, 2, 3, 4, 7, 0, 0, 0}, + {1, 2, 3, 4, 7, 0, 0, 0}, {0, 1, 2, 3, 4, 7, 0, 0}, + {5, 7, 0, 0, 0, 0, 0, 0}, {0, 5, 7, 0, 0, 0, 0, 0}, + {1, 5, 7, 0, 0, 0, 0, 0}, {0, 1, 5, 7, 0, 0, 0, 0}, + {2, 5, 7, 0, 0, 0, 0, 0}, {0, 2, 5, 7, 0, 0, 0, 0}, + {1, 2, 5, 7, 0, 0, 0, 0}, {0, 1, 2, 5, 7, 0, 0, 0}, + {3, 5, 7, 0, 0, 0, 0, 0}, {0, 3, 5, 7, 0, 0, 0, 0}, + {1, 3, 5, 7, 0, 0, 0, 0}, {0, 1, 3, 5, 7, 0, 0, 0}, + {2, 3, 5, 7, 0, 0, 0, 0}, {0, 2, 3, 5, 7, 0, 0, 0}, + {1, 2, 3, 5, 7, 0, 0, 0}, {0, 1, 2, 3, 5, 7, 0, 0}, + {4, 5, 7, 0, 0, 0, 0, 0}, {0, 4, 5, 7, 0, 0, 0, 0}, + {1, 4, 5, 7, 0, 0, 0, 0}, {0, 1, 4, 5, 7, 0, 0, 0}, + {2, 4, 5, 7, 0, 0, 0, 0}, {0, 2, 4, 5, 7, 0, 0, 0}, + {1, 2, 4, 5, 7, 0, 0, 0}, {0, 1, 2, 4, 5, 7, 0, 0}, + {3, 4, 5, 7, 0, 0, 0, 0}, {0, 3, 4, 5, 7, 0, 0, 0}, + {1, 3, 4, 5, 7, 0, 0, 0}, {0, 1, 3, 4, 5, 7, 0, 0}, + {2, 3, 4, 5, 7, 0, 0, 0}, {0, 2, 3, 4, 5, 7, 0, 0}, + {1, 2, 3, 4, 5, 7, 0, 0}, {0, 1, 2, 3, 4, 5, 7, 0}, + {6, 7, 0, 0, 0, 0, 0, 0}, {0, 6, 7, 0, 0, 0, 0, 0}, + {1, 6, 7, 0, 0, 0, 0, 0}, {0, 1, 6, 7, 0, 0, 0, 0}, + {2, 6, 7, 0, 0, 0, 0, 0}, {0, 2, 6, 7, 0, 0, 0, 0}, + {1, 2, 6, 7, 0, 0, 0, 0}, {0, 1, 2, 6, 7, 0, 0, 0}, + {3, 6, 7, 0, 0, 0, 0, 0}, {0, 3, 6, 7, 0, 0, 0, 0}, + {1, 3, 6, 7, 0, 0, 0, 0}, {0, 1, 3, 6, 7, 0, 0, 0}, + {2, 3, 6, 7, 0, 0, 0, 0}, {0, 2, 3, 6, 7, 0, 0, 0}, + {1, 2, 3, 6, 7, 0, 0, 0}, {0, 1, 2, 3, 6, 7, 0, 0}, + {4, 6, 7, 0, 0, 0, 0, 0}, {0, 4, 6, 7, 0, 0, 0, 0}, + {1, 4, 6, 7, 0, 0, 0, 0}, {0, 1, 4, 6, 7, 0, 0, 0}, + {2, 4, 6, 7, 0, 0, 0, 0}, {0, 2, 4, 6, 7, 0, 0, 0}, + {1, 2, 4, 6, 7, 0, 0, 0}, {0, 1, 2, 4, 6, 7, 0, 0}, + {3, 4, 6, 7, 0, 0, 0, 0}, {0, 3, 4, 6, 7, 0, 0, 0}, + {1, 3, 4, 6, 7, 0, 0, 0}, {0, 1, 3, 4, 6, 7, 0, 0}, + {2, 3, 4, 6, 7, 0, 0, 0}, {0, 2, 3, 4, 6, 7, 0, 0}, + {1, 2, 3, 4, 6, 7, 0, 0}, {0, 1, 2, 3, 4, 6, 7, 0}, + {5, 6, 7, 0, 0, 0, 0, 0}, {0, 5, 6, 7, 0, 0, 0, 0}, + {1, 5, 6, 7, 0, 0, 0, 0}, {0, 1, 5, 6, 7, 0, 0, 0}, + {2, 5, 6, 7, 0, 0, 0, 0}, {0, 2, 5, 6, 7, 0, 0, 0}, + {1, 2, 5, 6, 7, 0, 0, 0}, {0, 1, 2, 5, 6, 7, 0, 0}, + {3, 5, 6, 7, 0, 0, 0, 0}, {0, 3, 5, 6, 7, 0, 0, 0}, + {1, 3, 5, 6, 7, 0, 0, 0}, {0, 1, 3, 5, 6, 7, 0, 0}, + {2, 3, 5, 6, 7, 0, 0, 0}, {0, 2, 3, 5, 6, 7, 0, 0}, + {1, 2, 3, 5, 6, 7, 0, 0}, {0, 1, 2, 3, 5, 6, 7, 0}, + {4, 5, 6, 7, 0, 0, 0, 0}, {0, 4, 5, 6, 7, 0, 0, 0}, + {1, 4, 5, 6, 7, 0, 0, 0}, {0, 1, 4, 5, 6, 7, 0, 0}, + {2, 4, 5, 6, 7, 0, 0, 0}, {0, 2, 4, 5, 6, 7, 0, 0}, + {1, 2, 4, 5, 6, 7, 0, 0}, {0, 1, 2, 4, 5, 6, 7, 0}, + {3, 4, 5, 6, 7, 0, 0, 0}, {0, 3, 4, 5, 6, 7, 0, 0}, + {1, 3, 4, 5, 6, 7, 0, 0}, {0, 1, 3, 4, 5, 6, 7, 0}, + {2, 3, 4, 5, 6, 7, 0, 0}, {0, 2, 3, 4, 5, 6, 7, 0}, + {1, 2, 3, 4, 5, 6, 7, 0}, {0, 1, 2, 3, 4, 5, 6, 7}, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/packing.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/packing.c new file mode 100644 index 0000000000..26da273856 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/packing.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include + +#include "common.h" +#include "packing.h" +#include "poly.h" +#include "polyvec.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_unpack_hints MLD_ADD_PARAM_SET(mld_unpack_hints) +/* End of parameter set namespacing */ + +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +{ + unsigned int i; + + mld_memcpy(pk, rho, MLDSA_SEEDBYTES); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt1_pack(pk + MLDSA_SEEDBYTES + i * MLDSA_POLYT1_PACKEDBYTES, + &t1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +{ + unsigned int i; + + mld_memcpy(rho, pk, MLDSA_SEEDBYTES); + pk += MLDSA_SEEDBYTES; + + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt1_unpack(&t1->vec[i], pk + i * MLDSA_POLYT1_PACKEDBYTES); + } +} + +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +{ + mld_memcpy(sk, rho, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, key, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, tr, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_pack_eta(sk, s1); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_eta(sk, s2); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_t0(sk, t0); +} + +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +{ + mld_memcpy(rho, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(key, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(tr, sk, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_unpack_eta(s1, sk); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_eta(s2, sk); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_t0(t0, sk); +} + +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +{ + unsigned int i, j, k; + + mld_memcpy(sig, c, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + /* skip z component - packed via mld_pack_sig_z */ + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + /* Encode hints h */ + + /* The final section of sig[] is MLDSA_POLYVECH_PACKEDBYTES long, where + * MLDSA_POLYVECH_PACKEDBYTES = MLDSA_OMEGA + MLDSA_K + * + * The first OMEGA bytes record the index numbers of the coefficients + * that are not equal to 0 + * + * The final K bytes record a running tally of the number of hints + * coming from each of the K polynomials in h. + * + * The pre-condition tells us that number_of_hints <= OMEGA, so some + * bytes may not be written, so we initialize all of them to zero + * to start. + */ + mld_memset(sig, 0, MLDSA_POLYVECH_PACKEDBYTES); + + k = 0; + /* For each polynomial in h... */ + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* For each coefficient in that polynomial, record it as as hint */ + /* if its value is not zero */ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + assigns(j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(j <= MLDSA_N) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* The reference implementation implicitly relies on the total */ + /* number of hints being less than OMEGA, assuming h is valid. */ + /* In mldsa-native, we check this explicitly to ease proof of */ + /* type safety. */ + if (h->vec[i].coeffs[j] != 0 && k < number_of_hints) + { + /* The enclosing if condition AND the loop invariant infer */ + /* that k < MLDSA_OMEGA, so writing to sig[k] is safe and k */ + /* can be incremented. */ + sig[k++] = (uint8_t)j; + } + } + /* Having recorded all the hints for this polynomial, also */ + /* record the running tally into the correct "slot" for that */ + /* coefficient in the final K bytes */ + sig[MLDSA_OMEGA + i] = (uint8_t)k; + } +} + +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +{ + sig += MLDSA_CTILDEBYTES; + sig += i * MLDSA_POLYZ_PACKEDBYTES; + mld_polyz_pack(sig, zi); +} + +/************************************************* + * Name: mld_unpack_hints + * + * Description: Unpack raw hint bytes into a polyveck + * struct + * + * Arguments: - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]: + * raw hint bytes + * + * Returns 1 in case of malformed hints; otherwise 0. + **************************************************/ +static int mld_unpack_hints( + mld_polyveck *h, const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(packed_hints, MLDSA_POLYVECH_PACKEDBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + /* All returned coefficients are either 0 or 1 */ + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +) +{ + unsigned int i, j; + unsigned int old_hint_count; + + /* Set all coefficients of all polynomials to 0. */ + /* Only those that are actually non-zero hints will */ + /* be overwritten below. */ + mld_memset(h, 0, sizeof(mld_polyveck)); + + old_hint_count = 0; + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + /* Grab the hint count for the i'th polynomial */ + const unsigned int new_hint_count = packed_hints[MLDSA_OMEGA + i]; + + /* new_hint_count must increase or stay the same, but also remain */ + /* less than or equal to MLDSA_OMEGA */ + if (new_hint_count < old_hint_count || new_hint_count > MLDSA_OMEGA) + { + /* Error - new_hint_count is invalid */ + return 1; + } + + /* If new_hint_count == old_hint_count, then this polynomial has */ + /* zero hints, so this loop executes zero times and we move */ + /* straight on to the next polynomial. */ + for (j = old_hint_count; j < new_hint_count; ++j) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + const uint8_t this_hint_index = packed_hints[j]; + + /* Coefficients must be ordered for strong unforgeability */ + if (j > old_hint_count && this_hint_index <= packed_hints[j - 1]) + { + return 1; + } + h->vec[i].coeffs[this_hint_index] = 1; + } + + old_hint_count = new_hint_count; + } + + /* Extra indices must be zero for strong unforgeability */ + for (j = old_hint_count; j < MLDSA_OMEGA; ++j) + __loop__( + invariant(j <= MLDSA_OMEGA) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + if (packed_hints[j] != 0) + { + return 1; + } + } + + return 0; +} + +MLD_INTERNAL_API +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +{ + mld_memcpy(c, sig, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + mld_polyvecl_unpack_z(z, sig); + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + return mld_unpack_hints(h, sig); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_unpack_hints diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/packing.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/packing.h new file mode 100644 index 0000000000..19095d08cd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/packing.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PACKING_H +#define MLD_PACKING_H + +#include +#include "polyvec.h" + +#define mld_pack_pk MLD_NAMESPACE_KL(pack_pk) +/************************************************* + * Name: mld_pack_pk + * + * Description: Bit-pack public key pk = (rho, t1). + * + * Arguments: - uint8_t pk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const mld_polyveck *t1: pointer to vector t1 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) +); + + +#define mld_pack_sk MLD_NAMESPACE_KL(pack_sk) +/************************************************* + * Name: mld_pack_sk + * + * Description: Bit-pack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - uint8_t sk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const uint8_t tr[]: byte array containing tr + * - const uint8_t key[]: byte array containing key + * - const mld_polyveck *t0: pointer to vector t0 + * - const mld_polyvecl *s1: pointer to vector s1 + * - const mld_polyveck *s2: pointer to vector s2 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +__contract__( + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + requires(forall(k2, 0, MLDSA_K, + array_abs_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) +); + + +#define mld_pack_sig_c_h MLD_NAMESPACE_KL(pack_sig_c_h) +/************************************************* + * Name: mld_pack_sig_c_h + * + * Description: Bit-pack c and h component of sig = (c, z, h). + * The z component is packed separately using mld_pack_sig_z. + * + * Arguments: - uint8_t sig[]: output byte array + * - const uint8_t *c: pointer to challenge hash length + * MLDSA_SEEDBYTES + * - const mld_polyveck *h: pointer to hint vector h + * - const unsigned int number_of_hints: total + * hints in *h + * + * Note that the number_of_hints argument is not present + * in the reference implementation. It is added here to ease + * proof of type safety. + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + requires(number_of_hints <= MLDSA_OMEGA) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_pack_sig_z MLD_NAMESPACE_KL(pack_sig_z) +/************************************************* + * Name: mld_pack_sig_z + * + * Description: Bit-pack single polynomial of z component of sig = (c, z, h). + * The c and h components are packed separately using + * mld_pack_sig_c_h. + * + * Arguments: - uint8_t sig[]: output byte array + * - const mld_poly *zi: pointer to a single polynomial in z + * - const unsigned int i: index of zi in vector z + * + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(zi, sizeof(mld_poly))) + requires(i < MLDSA_L) + requires(array_bound(zi->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_unpack_pk MLD_NAMESPACE_KL(unpack_pk) +/************************************************* + * Name: mld_unpack_pk + * + * Description: Unpack public key pk = (rho, t1). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const mld_polyveck *t1: pointer to output vector t1 + * - uint8_t pk[]: byte array containing bit-packed pk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) +); + + +#define mld_unpack_sk MLD_NAMESPACE_KL(unpack_sk) +/************************************************* + * Name: mld_unpack_sk + * + * Description: Unpack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const uint8_t tr[]: output byte array for tr + * - const uint8_t key[]: output byte array for key + * - const mld_polyveck *t0: pointer to output vector t0 + * - const mld_polyvecl *s1: pointer to output vector s1 + * - const mld_polyveck *s2: pointer to output vector s2 + * - uint8_t sk[]: byte array containing bit-packed sk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +__contract__( + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(key, MLDSA_SEEDBYTES)) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(s1, sizeof(mld_polyvecl))) + assigns(memory_slice(s2, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_unpack_sig MLD_NAMESPACE_KL(unpack_sig) +/************************************************* + * Name: mld_unpack_sig + * + * Description: Unpack signature sig = (c, z, h). + * + * Arguments: - uint8_t *c: pointer to output challenge hash + * - mld_polyvecl *z: pointer to output vector z + * - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t sig[]: byte array containing + * bit-packed signature + * + * Returns 1 in case of malformed signature; otherwise 0. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(c, MLDSA_CTILDEBYTES)) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(z->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +); +#endif /* !MLD_PACKING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/params.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/params.h new file mode 100644 index 0000000000..c67d2a33fb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/params.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PARAMS_H +#define MLD_PARAMS_H + +#define MLDSA_SEEDBYTES 32 +#define MLDSA_CRHBYTES 64 +#define MLDSA_TRBYTES 64 +#define MLDSA_RNDBYTES 32 +#define MLDSA_N 256 +#define MLDSA_Q 8380417 +#define MLDSA_Q_HALF ((MLDSA_Q + 1) / 2) +#define MLDSA_D 13 + +#if MLD_CONFIG_PARAMETER_SET == 44 + +#define MLDSA_K 4 +#define MLDSA_L 4 +#define MLDSA_ETA 2 +#define MLDSA_TAU 39 +#define MLDSA_BETA 78 +#define MLDSA_GAMMA1 (1 << 17) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 88) +#define MLDSA_OMEGA 80 +#define MLDSA_CTILDEBYTES 32 +#define MLDSA_POLYZ_PACKEDBYTES 576 +#define MLDSA_POLYW1_PACKEDBYTES 192 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#elif MLD_CONFIG_PARAMETER_SET == 65 + +#define MLDSA_K 6 +#define MLDSA_L 5 +#define MLDSA_ETA 4 +#define MLDSA_TAU 49 +#define MLDSA_BETA 196 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 55 +#define MLDSA_CTILDEBYTES 48 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 128 + +#elif MLD_CONFIG_PARAMETER_SET == 87 + +#define MLDSA_K 8 +#define MLDSA_L 7 +#define MLDSA_ETA 2 +#define MLDSA_TAU 60 +#define MLDSA_BETA 120 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 75 +#define MLDSA_CTILDEBYTES 64 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ + +#define MLDSA_POLYT1_PACKEDBYTES 320 +#define MLDSA_POLYT0_PACKEDBYTES 416 +#define MLDSA_POLYVECH_PACKEDBYTES (MLDSA_OMEGA + MLDSA_K) + +#define MLDSA_CRYPTO_PUBLICKEYBYTES \ + (MLDSA_SEEDBYTES + MLDSA_K * MLDSA_POLYT1_PACKEDBYTES) +#define MLDSA_CRYPTO_SECRETKEYBYTES \ + (2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + MLDSA_L * MLDSA_POLYETA_PACKEDBYTES + \ + MLDSA_K * MLDSA_POLYETA_PACKEDBYTES + MLDSA_K * MLDSA_POLYT0_PACKEDBYTES) +#define MLDSA_CRYPTO_BYTES \ + (MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES + \ + MLDSA_POLYVECH_PACKEDBYTES) + +#endif /* !MLD_PARAMS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/poly.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/poly.c new file mode 100644 index 0000000000..e40534e773 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/poly.c @@ -0,0 +1,973 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "common.h" +#include "ct.h" +#include "debug.h" +#include "poly.h" +#include "reduce.h" +#include "rounding.h" +#include "symmetric.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +#include "zetas.inc" + +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + { + a->coeffs[i] = mld_reduce32(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_STATIC_TESTABLE void mld_poly_caddq_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + ) + { + a->coeffs[i] = mld_caddq(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_POLY_CADDQ) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_poly_caddq_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + mld_poly_caddq_c(a); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1])) + invariant(forall(k2, 0, i, r->coeffs[k2] < MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k2, 0, i, r->coeffs[k2] >= INT32_MIN)) + ) + { + r->coeffs[i] = r->coeffs[i] + b->coeffs[i]; + } +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(r->coeffs, 0, i, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + ) + { + r->coeffs[i] = r->coeffs[i] - b->coeffs[i]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N; i++) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))) + { + /* Reference: uses a left shift by MLDSA_D which is undefined behaviour in + * C90/C99 + */ + a->coeffs[i] *= (1 << MLDSA_D); + } + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + + +static MLD_INLINE int32_t mld_fqmul(int32_t a, int32_t b) +__contract__( + requires(b > -MLDSA_Q_HALF && b < MLDSA_Q_HALF) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* Bounds: We argue in mld_montgomery_reduce() that the reult + * of Montgomery reduction is < MLDSA_Q if the input is smaller + * than 2^31 * MLDSA_Q in absolute value. Indeed, we have: + * + * |a * b| = |a| * |b| + * < 2^31 * MLDSA_Q_HALF + * < 2^31 * MLDSA_Q + */ + return mld_montgomery_reduce((int64_t)a * (int64_t)b); +} + +/* mld_ntt_butterfly_block() + * + * Computes a block CT butterflies with a fixed twiddle factor, + * using Montgomery multiplication. + * + * Parameters: + * - r: Pointer to base of polynomial (_not_ the base of butterfly block) + * - zeta: Twiddle factor to use for the butterfly. This must be in + * Montgomery form and signed canonical. + * - start: Offset to the beginning of the butterfly block + * - len: Index difference between coefficients subject to a butterfly + * - bound: Ghost variable describing coefficient bound: Prior to `start`, + * coefficients must be bound by `bound + MLDSA_Q`. Post `start`, + * they must be bound by `bound`. + * When this function returns, output coefficients in the index range + * [start, start+2*len) have bound bumped to `bound + MLDSA_Q`. + * Example: + * - start=8, len=4 + * This would compute the following four butterflies + * 8 -- 12 + * 9 -- 13 + * 10 -- 14 + * 11 -- 15 + * - start=4, len=2 + * This would compute the following two butterflies + * 4 -- 6 + * 5 -- 7 + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_butterfly_block(int32_t r[MLDSA_N], + const int32_t zeta, + const unsigned start, + const unsigned len, + const unsigned bound) +__contract__( + requires(start < MLDSA_N) + requires(1 <= len && len <= MLDSA_N / 2 && start + 2 * len <= MLDSA_N) + requires(0 <= bound && bound < INT32_MAX - MLDSA_Q) + requires(-MLDSA_Q_HALF < zeta && zeta < MLDSA_Q_HALF) + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, start, bound + MLDSA_Q)) + requires(array_abs_bound(r, start, MLDSA_N, bound)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, start + 2*len, bound + MLDSA_Q)) + ensures(array_abs_bound(r, start + 2 * len, MLDSA_N, bound))) +{ + /* `bound` is a ghost variable only needed in the CBMC specification */ + unsigned j; + ((void)bound); + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + /* + * Coefficients are updated in strided pairs, so the bounds for the + * intermediate states alternate twice between the old and new bound + */ + invariant(array_abs_bound(r, 0, j, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, bound)) + invariant(array_abs_bound(r, start + len, j + len, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j + len, MLDSA_N, bound))) + { + int32_t t; + t = mld_fqmul(r[j + len], zeta); + r[j + len] = r[j] - t; + r[j] = r[j] + t; + } +} + +/* mld_ntt_layer() + * + * Compute one layer of forward NTT + * + * Parameters: + * - r: Pointer to base of polynomial + * - layer: Indicates which layer is being applied. + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_layer(int32_t r[MLDSA_N], const unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (layer + 1) * MLDSA_Q))) +{ + unsigned start, k, len; + /* Twiddle factors for layer n are at indices 2^(n-1)..2^n-1. */ + k = 1u << (layer - 1); + len = (unsigned)MLDSA_N >> layer; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start < MLDSA_N + 2 * len) + invariant(k <= MLDSA_N) + invariant(2 * len * k == start + MLDSA_N) + invariant(array_abs_bound(r, 0, start, layer * MLDSA_Q + MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, layer * MLDSA_Q))) + { + int32_t zeta = mld_zetas[k++]; + mld_ntt_butterfly_block(r, zeta, start, len, layer * MLDSA_Q); + } +} + +MLD_STATIC_TESTABLE void mld_poly_ntt_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +) +{ + unsigned int layer; + int32_t *r; + + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + r = a->coeffs; + + for (layer = 1; layer < 9; layer++) + __loop__( + invariant(1 <= layer && layer <= 9) + invariant(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + ) + { + mld_ntt_layer(r, layer); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_NTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_ntt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_NTT */ + mld_poly_ntt_c(a); +} + +/************************************************* + * Name: mld_fqscale + * + * Description: Scales a field element by mont/256 , i.e., performs Montgomery + * multiplication by mont^2/256. + * Input is expected to have absolute value smaller than + * 256 * MLDSA_Q. + * Output has absolute value smaller than MLD_INTT_BOUND. + * + * Arguments: - int32_t a: Field element to be scaled. + **************************************************/ +static MLD_INLINE int32_t mld_fqscale(int32_t a) +__contract__( + requires(a > -256*MLDSA_Q && a < 256*MLDSA_Q) + ensures(return_value > -MLD_INTT_BOUND && return_value < MLD_INTT_BOUND) +) +{ + /* check-magic: 41978 == pow(2,64-8,MLDSA_Q) */ + const int32_t f = 41978; + /* Bounds: MLD_INTT_BOUND is MLDSA_Q, so the bounds reasoning is just + * a special case of that in mld_fqmul(). */ + return mld_montgomery_reduce((int64_t)a * f); +} + +/* Reference: Embedded into `invntt_tomont()` in the reference implementation + * @[REF] */ +static MLD_INLINE void mld_invntt_layer(int32_t r[MLDSA_N], unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> (layer - 1)) * MLDSA_Q))) +{ + unsigned start, k, len; + len = (unsigned)MLDSA_N >> layer; + k = (1u << layer) - 1; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start <= MLDSA_N && k <= 255) + invariant(2 * len * k + start == 2 * MLDSA_N - 2 * len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + unsigned j; + int32_t zeta = -mld_zetas[k--]; + + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, j, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, (MLDSA_N >> layer) * MLDSA_Q)) + invariant(array_abs_bound(r, start + len, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + int32_t t = r[j]; + r[j] = t + r[j + len]; + r[j + len] = t - r[j + len]; + r[j + len] = mld_fqmul(r[j + len], zeta); + } + } +} + +MLD_STATIC_TESTABLE void mld_poly_invntt_tomont_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +) +{ + unsigned int layer, j; + int32_t *r; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + r = a->coeffs; + for (layer = 8; layer >= 1; layer--) + __loop__( + invariant(layer <= 8) + /* Absolute bounds increase from 1Q before layer 8 */ + /* up to 256Q after layer 1 */ + invariant(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + mld_invntt_layer(r, layer); + } + + /* Coefficient bounds are now at 256Q. We now scale by mont / 256, + * i.e., compute the Montgomery multiplication by mont^2 / 256. + * mont corrects the mont^-1 factor introduced in the basemul. + * 1/256 performs that scaling of the inverse NTT. + * The reduced value is bounded by MLD_INTT_BOUND in absolute + * value.*/ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + invariant(j <= MLDSA_N) + invariant(array_abs_bound(r, 0, j, MLD_INTT_BOUND)) + invariant(array_abs_bound(r, j, MLDSA_N, MLDSA_N * MLDSA_Q)) + ) + { + r[j] = mld_fqscale(r[j]); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); +} + + +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_INTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_intt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_INTT */ + mld_poly_invntt_tomont_c(a); +} + +MLD_STATIC_TESTABLE void mld_poly_pointwise_montgomery_c(mld_poly *c, + const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_abs_bound(c->coeffs, 0, i, MLDSA_Q)) + ) + { + c->coeffs[i] = mld_montgomery_reduce((int64_t)a->coeffs[i] * b->coeffs[i]); + } + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +{ +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + ret = mld_poly_pointwise_montgomery_native(c->coeffs, a->coeffs, b->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + mld_poly_pointwise_montgomery_c(c, a, b); +} + +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, 0, i, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + invariant(array_bound(a1->coeffs, 0, i, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) + ) + { + mld_power2round(&a0->coeffs[i], &a1->coeffs[i], a->coeffs[i]); + } + + mld_assert_bound(a0->coeffs, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +#ifndef MLD_POLY_UNIFORM_NBLOCKS +#define MLD_POLY_UNIFORM_NBLOCKS \ + ((768 + MLD_STREAM128_BLOCKBYTES - 1) / MLD_STREAM128_BLOCKBYTES) +#endif +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +MLD_STATIC_TESTABLE unsigned int mld_rej_uniform_c(int32_t *a, + unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ + unsigned int ctr, pos; + uint32_t t; + mld_assert_bound(a, offset, 0, MLDSA_Q); + + ctr = offset; + pos = 0; + /* pos + 3 cannot overflow due to the assumption + buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) */ + while (ctr < target && pos + 3 <= buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_bound(a, 0, ctr, 0, MLDSA_Q))) + { + t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + a[ctr++] = (int32_t)t; + } + } + + mld_assert_bound(a, ctr, 0, MLDSA_Q); + + return ctr; +} +/************************************************* + * Name: mld_rej_uniform + * + * Description: Sample uniformly random coefficients in [0, MLDSA_Q-1] by + * performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes (must be + * multiple of 3) + * + * Returns number of sampled coefficients. Can be smaller than len if not enough + * random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +static unsigned int mld_rej_uniform(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) + int ret; + mld_assert_bound(a, offset, 0, MLDSA_Q); + if (offset == 0) + { + ret = mld_rej_uniform_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_bound(a, res, 0, MLDSA_Q); + return res; + } + } +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + + return mld_rej_uniform_c(a, target, offset, buf, buflen); +} + +/* Reference: poly_uniform() in the reference implementation @[REF]. + * - Simplified from reference by removing buffer tail handling + * since buflen % 3 = 0 always holds true (MLD_STREAM128_BLOCKBYTES + * = 168). + * - Modified rej_uniform interface to track offset directly. + * - Pass nonce packed in the extended seed array instead of a third + * argument. + * */ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +{ + unsigned int ctr; + unsigned int buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + MLD_ALIGN uint8_t buf[MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES]; + mld_xof128_ctx state; + + mld_xof128_init(&state); + mld_xof128_absorb_once(&state, seed, MLDSA_SEEDBYTES + 2); + mld_xof128_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, 0, buf, buflen); + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(a, sizeof(mld_poly)), object_whole(buf)) + invariant(ctr <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, ctr, 0, MLDSA_Q)) + invariant(state.pos <= SHAKE128_RATE) + ) + { + mld_xof128_squeezeblocks(buf, 1, &state); + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, ctr, buf, buflen); + } + mld_xof128_release(&state); + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof128_x4_ctx state; + unsigned buflen; + + mld_xof128_x4_init(&state); + mld_xof128_x4_absorb(&state, seed, MLDSA_SEEDBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_NBLOCKS. + * This should generate the matrix entries with high probability. + */ + + mld_xof128_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all matrix entries have been generated, squeeze + * one more block a time until we're done. + */ + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, object_whole(buf), + memory_slice(vec0, sizeof(mld_poly)), memory_slice(vec1, sizeof(mld_poly)), + memory_slice(vec2, sizeof(mld_poly)), memory_slice(vec3, sizeof(mld_poly))) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_bound(vec0->coeffs, 0, ctr[0], 0, MLDSA_Q)) + invariant(array_bound(vec1->coeffs, 0, ctr[1], 0, MLDSA_Q)) + invariant(array_bound(vec2->coeffs, 0, ctr[2], 0, MLDSA_Q)) + invariant(array_bound(vec3->coeffs, 0, ctr[3], 0, MLDSA_Q))) + { + mld_xof128_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + mld_xof128_x4_release(&state); + + mld_assert_bound(vec0->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec1->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec2->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec3->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0) & 0xFF); + r[5 * i + 1] = + (uint8_t)(((a->coeffs[4 * i + 0] >> 8) | (a->coeffs[4 * i + 1] << 2)) & + 0xFF); + r[5 * i + 2] = + (uint8_t)(((a->coeffs[4 * i + 1] >> 6) | (a->coeffs[4 * i + 2] << 4)) & + 0xFF); + r[5 * i + 3] = + (uint8_t)(((a->coeffs[4 * i + 2] >> 4) | (a->coeffs[4 * i + 3] << 6)) & + 0xFF); + r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, 0, 1 << 10))) + { + r->coeffs[4 * i + 0] = + ((a[5 * i + 0] >> 0) | ((int32_t)a[5 * i + 1] << 8)) & 0x3FF; + r->coeffs[4 * i + 1] = + ((a[5 * i + 1] >> 2) | ((int32_t)a[5 * i + 2] << 6)) & 0x3FF; + r->coeffs[4 * i + 2] = + ((a[5 * i + 2] >> 4) | ((int32_t)a[5 * i + 3] << 4)) & 0x3FF; + r->coeffs[4 * i + 3] = + ((a[5 * i + 3] >> 6) | ((int32_t)a[5 * i + 4] << 2)) & 0x3FF; + } + + mld_assert_bound(r->coeffs, MLDSA_N, 0, 1 << 10); +} + +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[8]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* Safety: a->coeffs[i] <= (1 << (MLDSA_D - 1) as they are output of + * power2round, hence, these casts are safe. */ + t[0] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 0]); + t[1] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 1]); + t[2] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 2]); + t[3] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 3]); + t[4] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 4]); + t[5] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 5]); + t[6] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 6]); + t[7] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 7]); + + r[13 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[13 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[13 * i + 1] |= (uint8_t)((t[1] << 5) & 0xFF); + r[13 * i + 2] = (uint8_t)((t[1] >> 3) & 0xFF); + r[13 * i + 3] = (uint8_t)((t[1] >> 11) & 0xFF); + r[13 * i + 3] |= (uint8_t)((t[2] << 2) & 0xFF); + r[13 * i + 4] = (uint8_t)((t[2] >> 6) & 0xFF); + r[13 * i + 4] |= (uint8_t)((t[3] << 7) & 0xFF); + r[13 * i + 5] = (uint8_t)((t[3] >> 1) & 0xFF); + r[13 * i + 6] = (uint8_t)((t[3] >> 9) & 0xFF); + r[13 * i + 6] |= (uint8_t)((t[4] << 4) & 0xFF); + r[13 * i + 7] = (uint8_t)((t[4] >> 4) & 0xFF); + r[13 * i + 8] = (uint8_t)((t[4] >> 12) & 0xFF); + r[13 * i + 8] |= (uint8_t)((t[5] << 1) & 0xFF); + r[13 * i + 9] = (uint8_t)((t[5] >> 7) & 0xFF); + r[13 * i + 9] |= (uint8_t)((t[6] << 6) & 0xFF); + r[13 * i + 10] = (uint8_t)((t[6] >> 2) & 0xFF); + r[13 * i + 11] = (uint8_t)((t[6] >> 10) & 0xFF); + r[13 * i + 11] |= (uint8_t)((t[7] << 3) & 0xFF); + r[13 * i + 12] = (uint8_t)((t[7] >> 5) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + { + r->coeffs[8 * i + 0] = a[13 * i + 0]; + r->coeffs[8 * i + 0] |= (int32_t)a[13 * i + 1] << 8; + r->coeffs[8 * i + 0] &= 0x1FFF; + + r->coeffs[8 * i + 1] = a[13 * i + 1] >> 5; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 2] << 3; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 3] << 11; + r->coeffs[8 * i + 1] &= 0x1FFF; + + r->coeffs[8 * i + 2] = a[13 * i + 3] >> 2; + r->coeffs[8 * i + 2] |= (int32_t)a[13 * i + 4] << 6; + r->coeffs[8 * i + 2] &= 0x1FFF; + + r->coeffs[8 * i + 3] = a[13 * i + 4] >> 7; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 5] << 1; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 6] << 9; + r->coeffs[8 * i + 3] &= 0x1FFF; + + r->coeffs[8 * i + 4] = a[13 * i + 6] >> 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 7] << 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 8] << 12; + r->coeffs[8 * i + 4] &= 0x1FFF; + + r->coeffs[8 * i + 5] = a[13 * i + 8] >> 1; + r->coeffs[8 * i + 5] |= (int32_t)a[13 * i + 9] << 7; + r->coeffs[8 * i + 5] &= 0x1FFF; + + r->coeffs[8 * i + 6] = a[13 * i + 9] >> 6; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 10] << 2; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 11] << 10; + r->coeffs[8 * i + 6] &= 0x1FFF; + + r->coeffs[8 * i + 7] = a[13 * i + 11] >> 3; + r->coeffs[8 * i + 7] |= (int32_t)a[13 * i + 12] << 5; + r->coeffs[8 * i + 7] &= 0x1FFF; + + r->coeffs[8 * i + 0] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 7]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +MLD_STATIC_TESTABLE uint32_t mld_poly_chknorm_c(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == array_abs_bound(a->coeffs, 0, i, B)) + ) + { + /* + * Since we know that -MLD_REDUCE32_RANGE_MAX <= a < MLD_REDUCE32_RANGE_MAX, + * and B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX, to check if + * -B < (a mod± MLDSA_Q) < B, it suffices to check if -B < a < B. + * + * We prove this to be true using the following CBMC assertions. + * a ==> b expressed as !a || b to also allow run-time assertion. + */ + mld_assert(a->coeffs[i] < B || a->coeffs[i] - MLDSA_Q <= -B); + mld_assert(a->coeffs[i] > -B || a->coeffs[i] + MLDSA_Q >= B); + + /* Reference: Leaks which coefficient violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + + /* if (abs(a[i]) >= B) */ + t |= mld_ct_cmask_neg_i32(B - 1 - mld_ct_abs_i32(a->coeffs[i])); + } + + return t; +} + +/* Reference: explicitly checks the bound B to be <= (MLDSA_Q - 1) / 8). + * This is unnecessary as it's always a compile-time constant. + * We instead model it as a precondition. + * Checking the bound is performed using a conditional arguing + * that it is okay to leak which coefficient violates the bound (while the + * coefficient itself must remain secret). + * We instead perform everything in constant-time. + * Also it is sufficient to check that it is smaller than + * MLDSA_Q - MLD_REDUCE32_RANGE_MAX > (MLDSA_Q - 1) / 8). + */ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +{ +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) + int ret; + int success; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + /* The native backend returns 0 if all coefficients are within the bound, + * 1 if at least one coefficient exceeds the bound, and + * -1 (MLD_NATIVE_FUNC_FALLBACK) if the platform does not have the + * required capabilities to run the native function. + */ + ret = mld_poly_chknorm_native(a->coeffs, B); + + success = (ret != MLD_NATIVE_FUNC_FALLBACK); + /* Constant-time: It would be fine to leak the return value of chknorm + * entirely (as it is fine to leak if any coefficient exceeded the bound or + * not). However, it is cleaner to perform declassification in sign.c. + * Hence, here we only declassify if the native function returned + * MLD_NATIVE_FUNC_FALLBACK or not (which solely depends on system + * capabilities). + */ + MLD_CT_TESTING_DECLASSIFY(&success, sizeof(int)); + if (success) + { + /* Convert 0 / 1 to 0 / 0xFFFFFFFF here */ + return 0U - (uint32_t)ret; + } +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + return mld_poly_chknorm_c(a, B); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ +MLD_EMPTY_CU(mld_poly) +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_POLY_UNIFORM_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/poly.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/poly.h new file mode 100644 index 0000000000..ff7710438e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/poly.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_H +#define MLD_POLY_H + +#include +#include "cbmc.h" +#include "common.h" +#include "reduce.h" +#include "rounding.h" + +/* Absolute exclusive upper bound for the output of the forward NTT */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) +/* Absolute exclusive upper bound for the output of the inverse NTT*/ +#define MLD_INTT_BOUND MLDSA_Q + +typedef struct +{ + int32_t coeffs[MLDSA_N]; +} MLD_ALIGN mld_poly; + +#define mld_poly_reduce MLD_NAMESPACE(poly_reduce) +/************************************************* + * Name: mld_poly_reduce + * + * Description: Inplace reduction of all coefficients of polynomial to + * representative in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) +); + +#define mld_poly_caddq MLD_NAMESPACE(poly_caddq) +/************************************************* + * Name: mld_poly_caddq + * + * Description: For all coefficients of in/out polynomial add MLDSA_Q if + * coefficient is negative. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_add MLD_NAMESPACE(poly_add) +/************************************************* + * Name: mld_poly_add + * + * Description: Add polynomials. No modular reduction is performed. + * + * Arguments: - r: Pointer to input-output polynomial to be added to. + * - b: Pointer to input polynomial that should be added + * to r. Must be disjoint from r. + **************************************************/ + +/* + * NOTE: The reference implementation uses a 3-argument poly_add. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(forall(k0, 0, MLDSA_N, (int64_t) r->coeffs[k0] + b->coeffs[k0] < MLD_REDUCE32_DOMAIN_MAX)) + requires(forall(k1, 0, MLDSA_N, (int64_t) r->coeffs[k1] + b->coeffs[k1] >= INT32_MIN)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(forall(k2, 0, MLDSA_N, r->coeffs[k2] == old(*r).coeffs[k2] + b->coeffs[k2])) + ensures(forall(k3, 0, MLDSA_N, r->coeffs[k3] < MLD_REDUCE32_DOMAIN_MAX)) + ensures(forall(k4, 0, MLDSA_N, r->coeffs[k4] >= INT32_MIN)) +); + +#define mld_poly_sub MLD_NAMESPACE(poly_sub) +/************************************************* + * Name: mld_poly_sub + * + * Description: Subtract polynomials. No modular reduction is + * performed. + * + * Arguments: - mld_poly *r: Pointer to input-output polynomial. + * - const mld_poly *b: Pointer to input polynomial that should be + * subtracted from r. Must be disjoint from r. + **************************************************/ +/* + * NOTE: The reference implementation uses a 3-argument poly_sub. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_Q)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) +); + +#define mld_poly_shiftl MLD_NAMESPACE(poly_shiftl) +/************************************************* + * Name: mld_poly_shiftl + * + * Description: Multiply polynomial by 2^MLDSA_D without modular reduction. + *Assumes input coefficients to be less than 2^{31-MLDSA_D} in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_ntt MLD_NAMESPACE(poly_ntt) +/************************************************* + * Name: mld_poly_ntt + * + * Description: Inplace forward NTT. Coefficients can grow by + * 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +); + + +#define mld_poly_invntt_tomont MLD_NAMESPACE(poly_invntt_tomont) +/************************************************* + * Name: mld_poly_invntt_tomont + * + * Description: Inplace inverse NTT and multiplication by 2^{32}. + * Input coefficients need to be less than MLDSA_Q in absolute + * value and output coefficients are bounded by + * MLD_INTT_BOUND. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +); + +#define mld_poly_pointwise_montgomery MLD_NAMESPACE(poly_pointwise_montgomery) +/************************************************* + * Name: mld_poly_pointwise_montgomery + * + * Description: Pointwise multiplication of polynomials in NTT domain + * representation and multiplication of resulting polynomial + * by 2^{-32}. + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const mld_poly *a: pointer to first input polynomial + * - const mld_poly *b: pointer to second input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + +#define mld_poly_power2round MLD_NAMESPACE(poly_power2round) +/************************************************* + * Name: mld_poly_power2round + * + * Description: For all coefficients c of the input polynomial, + * compute c0, c1 such that c mod MLDSA_Q = c1*2^MLDSA_D + c0 + * with -2^{MLDSA_D-1} < c0 <= 2^{MLDSA_D-1}. Assumes coefficients + *to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + *c1 + * - mld_poly *a0: pointer to output polynomial with coefficients + *c0 + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +__contract__( + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a0->coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) +); + +#define mld_poly_uniform MLD_NAMESPACE(poly_uniform) +/************************************************* + * Name: mld_poly_uniform + * + * Description: Sample polynomial with uniformly random coefficients + * in [0,MLDSA_Q-1] by performing rejection sampling on the + * output stream of SHAKE128(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_SEEDBYTES and the packed 2-byte nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES + 2)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +#define mld_poly_uniform_4x MLD_NAMESPACE(poly_uniform_4x) +/************************************************* + * Name: mld_poly_uniform_x4 + * + * Description: Generate four polynomials using rejection sampling + * on (pseudo-)uniformly random bytes sampled from a seed. + * + * Arguments: - mld_poly *vec0, *vec1, *vec2, *vec3: + * Pointers to 4 polynomials to be sampled. + * - uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]: + * Pointer consecutive array of seed buffers of size + * MLDSA_SEEDBYTES + 2 each, plus padding for alignment. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +__contract__( + requires(memory_no_alias(vec0, sizeof(mld_poly))) + requires(memory_no_alias(vec1, sizeof(mld_poly))) + requires(memory_no_alias(vec2, sizeof(mld_poly))) + requires(memory_no_alias(vec3, sizeof(mld_poly))) + requires(memory_no_alias(seed, 4 * MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2))) + assigns(memory_slice(vec0, sizeof(mld_poly))) + assigns(memory_slice(vec1, sizeof(mld_poly))) + assigns(memory_slice(vec2, sizeof(mld_poly))) + assigns(memory_slice(vec3, sizeof(mld_poly))) + ensures(array_bound(vec0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec1->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec2->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec3->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +#define mld_polyt1_pack MLD_NAMESPACE(polyt1_pack) +/************************************************* + * Name: mld_polyt1_pack + * + * Description: Bit-pack polynomial t1 with coefficients fitting in 10 bits. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(r, MLDSA_POLYT1_PACKEDBYTES)) +); + +#define mld_polyt1_unpack MLD_NAMESPACE(polyt1_unpack) +/************************************************* + * Name: mld_polyt1_unpack + * + * Description: Unpack polynomial t1 with 10-bit coefficients. + * Output coefficients are standard representatives. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT1_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, 0, 1 << 10)) +); + +#define mld_polyt0_pack MLD_NAMESPACE(polyt0_pack) +/************************************************* + * Name: mld_polyt0_pack + * + * Description: Bit-pack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + * 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) + assigns(memory_slice(r, MLDSA_POLYT0_PACKEDBYTES)) +); + + +#define mld_polyt0_unpack MLD_NAMESPACE(polyt0_unpack) +/************************************************* + * Name: mld_polyt0_unpack + * + * Description: Unpack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + *2^{MLDSA_D-1}]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT0_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) +); + +#define mld_poly_chknorm MLD_NAMESPACE(poly_chknorm) +/************************************************* + * Name: mld_poly_chknorm + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const mld_poly *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if norm is strictly smaller than + * B <= (MLDSA_Q - MLD_REDUCE32_RANGE_MAX) and 0xFFFFFFFF otherwise. + * + * Specification: The definition of this FIPS-204 requires signed canonical + * reduction prior to applying the bounds check. + * However, `-B < (a mod± MLDSA_Q) < B` is equivalent to + * `-B < a < B` under the assumption that + * `B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX` (cf. the assertion in + * the code). Hence, the present spec and implementation are + * correct without reduction. + * + **************************************************/ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +); + +#endif /* !MLD_POLY_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/poly_kl.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/poly_kl.c new file mode 100644 index 0000000000..7a319ca515 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/poly_kl.c @@ -0,0 +1,931 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "ct.h" +#include "debug.h" +#include "poly_kl.h" +#include "rounding.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_rej_eta MLD_ADD_PARAM_SET(mld_rej_eta) +#define mld_rej_eta_c MLD_ADD_PARAM_SET(mld_rej_eta_c) +#define mld_poly_decompose_c MLD_ADD_PARAM_SET(mld_poly_decompose_c) +#define mld_poly_use_hint_c MLD_ADD_PARAM_SET(mld_poly_use_hint_c) +#define mld_polyz_unpack_c MLD_ADD_PARAM_SET(mld_polyz_unpack_c) +/* End of parameter set namespacing */ + + +MLD_STATIC_TESTABLE +void mld_poly_decompose_c(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +) +{ + unsigned int i; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, i, MLDSA_N, 0, MLDSA_Q)) + invariant(array_bound(a1->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + invariant(array_abs_bound(a0->coeffs, 0, i, MLDSA_GAMMA2+1)) + ) + { + mld_decompose(&a0->coeffs[i], &a1->coeffs[i], a0->coeffs[i]); + } + + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +{ +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_88_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_32_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_DECOMPOSE_88 && MLD_CONFIG_PARAMETER_SET == \ + 44) && MLD_USE_NATIVE_POLY_DECOMPOSE_32 && (MLD_CONFIG_PARAMETER_SET \ + == 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_decompose_c(a1, a0); +} + +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(s <= i) + invariant(array_bound(h->coeffs, 0, i, 0, 2)) + ) + { + const unsigned int hint_bit = mld_make_hint(a0->coeffs[i], a1->coeffs[i]); + h->coeffs[i] = (int32_t)hint_bit; + s += hint_bit; + } + + mld_assert(s <= MLDSA_N); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + return s; +} + +MLD_STATIC_TESTABLE void mld_poly_use_hint_c(mld_poly *b, const mld_poly *a, + const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(b->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ) + { + b->coeffs[i] = mld_use_hint(a->coeffs[i], h->coeffs[i]); + } + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +{ +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_88_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_USE_HINT_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_32_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_USE_HINT_88 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLY_USE_HINT_32 && (MLD_CONFIG_PARAMETER_SET == \ + 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_use_hint_c(b, a, h); +} + +/************************************************* + * Name: mld_rej_eta + * + * Description: Sample uniformly random coefficients in [-MLDSA_ETA, MLDSA_ETA] + *by performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes + * + * Returns number of sampled coefficients. Can be smaller than target if not + *enough random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_eta()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +#if MLDSA_ETA == 2 +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 1 +#elif MLDSA_ETA == 4 +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 2 +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + +MLD_STATIC_TESTABLE unsigned int mld_rej_eta_c(int32_t *a, unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ + unsigned int ctr, pos; + int t_valid; + uint32_t t0, t1; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + ctr = offset; + pos = 0; + while (ctr < target && pos < buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_abs_bound(a, 0, ctr, MLDSA_ETA + 1)) + ) + { + t0 = buf[pos] & 0x0F; + t1 = buf[pos++] >> 4; + + /* Constant time: The inputs and outputs to the rejection sampling are + * secret. However, it is fine to leak which coefficients have been + * rejected. For constant-time testing, we declassify the result of + * the comparison. + */ +#if MLDSA_ETA == 2 + t_valid = t0 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 15 */ + { + t0 = t0 - (205 * t0 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t0; + } + t_valid = t1 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) /* t1 < 15 */ + { + t1 = t1 - (205 * t1 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t1; + } +#elif MLDSA_ETA == 4 + t_valid = t0 < 9; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 9 */ + { + a[ctr++] = 4 - (int32_t)t0; + } + t_valid = t1 < 9; /* t1 < 9 */ + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) + { + a[ctr++] = 4 - (int32_t)t1; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + } + + mld_assert_abs_bound(a, ctr, MLDSA_ETA + 1); + + return ctr; +} + +static unsigned int mld_rej_eta(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ +#if MLDSA_ETA == 2 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta2_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#elif MLDSA_ETA == 4 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta4_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#endif /* !(MLDSA_ETA == 2 && MLD_USE_NATIVE_REJ_UNIFORM_ETA2) && MLDSA_ETA == \ + 4 && MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + + return mld_rej_eta_c(a, target, offset, buf, buflen); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_ETA_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof256_x4_ctx state; + unsigned buflen; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = nonce0; + extseed[1][MLDSA_CRHBYTES] = nonce1; + extseed[2][MLDSA_CRHBYTES] = nonce2; + extseed[3][MLDSA_CRHBYTES] = nonce3; + extseed[0][MLDSA_CRHBYTES + 1] = 0; + extseed[1][MLDSA_CRHBYTES + 1] = 0; + extseed[2][MLDSA_CRHBYTES + 1] = 0; + extseed[3][MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(r0, sizeof(mld_poly)), + memory_slice(r1, sizeof(mld_poly)), memory_slice(r2, sizeof(mld_poly)), + memory_slice(r3, sizeof(mld_poly)), object_whole(buf[0]), + object_whole(buf[1]), object_whole(buf[2]), + object_whole(buf[3])) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_abs_bound(r0->coeffs, 0, ctr[0], MLDSA_ETA + 1)) + invariant(array_abs_bound(r1->coeffs, 0, ctr[1], MLDSA_ETA + 1)) + invariant(array_abs_bound(r2->coeffs, 0, ctr[2], MLDSA_ETA + 1)) + invariant(array_abs_bound(r3->coeffs, 0, ctr[3], MLDSA_ETA + 1))) + { + mld_xof256_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + + mld_xof256_x4_release(&state); + + mld_assert_abs_bound(r0->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r1->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r2->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r3->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +{ + /* Temporary buffer for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr; + mld_xof256_ctx state; + unsigned buflen; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = nonce; + extseed[MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr = mld_rej_eta(r->coeffs, MLDSA_N, 0, buf, buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, object_whole(&state), + object_whole(buf), memory_slice(r, sizeof(mld_poly))) + invariant(ctr <= MLDSA_N) + invariant(state.pos <= SHAKE256_RATE) + invariant(array_abs_bound(r->coeffs, 0, ctr, MLDSA_ETA + 1))) + { + mld_xof256_squeezeblocks(buf, 1, &state); + ctr = mld_rej_eta(r->coeffs, MLDSA_N, ctr, buf, buflen); + } + + mld_xof256_release(&state); + + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define MLD_POLY_UNIFORM_GAMMA1_NBLOCKS \ + ((MLDSA_POLYZ_PACKEDBYTES + MLD_STREAM256_BLOCKBYTES - 1) / \ + MLD_STREAM256_BLOCKBYTES) + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + mld_xof256_ctx state; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = (uint8_t)(nonce & 0xFF); + extseed[MLDSA_CRHBYTES + 1] = (uint8_t)(nonce >> 8); + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + mld_polyz_unpack(a, buf); + + mld_xof256_release(&state); + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + mld_xof256_x4_ctx state; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = (uint8_t)(nonce0 & 0xFF); + extseed[1][MLDSA_CRHBYTES] = (uint8_t)(nonce1 & 0xFF); + extseed[2][MLDSA_CRHBYTES] = (uint8_t)(nonce2 & 0xFF); + extseed[3][MLDSA_CRHBYTES] = (uint8_t)(nonce3 & 0xFF); + extseed[0][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce0 >> 8); + extseed[1][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce1 >> 8); + extseed[2][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce2 >> 8); + extseed[3][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce3 >> 8); + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + + mld_polyz_unpack(r0, buf[0]); + mld_polyz_unpack(r1, buf[1]); + mld_polyz_unpack(r2, buf[2]); + mld_polyz_unpack(r3, buf[3]); + mld_xof256_x4_release(&state); + + mld_assert_bound(r0->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r1->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r2->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r3->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +{ + unsigned int i, j, pos; + uint64_t signs; + uint64_t offset; + MLD_ALIGN uint8_t buf[SHAKE256_RATE]; + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, seed, MLDSA_CTILDEBYTES); + mld_shake256_finalize(&state); + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + + /* Convert the first 8 bytes of buf[] into an unsigned 64-bit value. */ + /* Each bit of that dictates the sign of the resulting challenge value */ + signs = 0; + for (i = 0; i < 8; ++i) + __loop__( + assigns(i, signs) + invariant(i <= 8) + ) + { + signs |= (uint64_t)buf[i] << 8 * i; + } + pos = 8; + + mld_memset(c, 0, sizeof(mld_poly)); + + for (i = MLDSA_N - MLDSA_TAU; i < MLDSA_N; ++i) + __loop__( + assigns(i, j, object_whole(buf), state, pos, memory_slice(c, sizeof(mld_poly)), signs) + invariant(i >= MLDSA_N - MLDSA_TAU) + invariant(i <= MLDSA_N) + invariant(pos >= 1) + invariant(pos <= SHAKE256_RATE) + invariant(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) + invariant(state.pos <= SHAKE256_RATE) + ) + { + do + __loop__( + assigns(j, object_whole(buf), state, pos) + invariant(state.pos <= SHAKE256_RATE) + ) + { + if (pos >= SHAKE256_RATE) + { + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + pos = 0; + } + j = buf[pos++]; + } while (j > i); + + c->coeffs[i] = c->coeffs[j]; + + /* Reference: Compute coefficent value here in two steps to */ + /* mixinf unsigned and signed arithmetic with implicit */ + /* conversions, and so that CBMC can keep track of ranges */ + /* to complete type-safety proof here. */ + + /* The least-significant bit of signs tells us if we want -1 or +1 */ + offset = 2 * (signs & 1); + + /* offset has value 0 or 2 here, so (1 - (int32_t) offset) has + * value -1 or +1 */ + c->coeffs[j] = 1 - (int32_t)offset; + + /* Move to the next bit of signs for next time */ + signs >>= 1; + } + + mld_assert_bound(c->coeffs, MLDSA_N, -1, 2); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(&signs, sizeof(signs)); +} + +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint8_t t[8]; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_ETA + 1); + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 1]); + t[2] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 2]); + t[3] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 3]); + t[4] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 4]); + t[5] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 5]); + t[6] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 6]); + t[7] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 7]); + + r[3 * i + 0] = (uint8_t)(((t[0] >> 0) | (t[1] << 3) | (t[2] << 6)) & 0xFF); + r[3 * i + 1] = + (uint8_t)(((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)) & + 0xFF); + r[3 * i + 2] = (uint8_t)(((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)) & 0xFF); + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 1]); + r[i] = (uint8_t)(t[0] | (t[1] << 4)); + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ +} + +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -5, MLDSA_ETA + 1))) + { + r->coeffs[8 * i + 0] = (a[3 * i + 0] >> 0) & 7; + r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 7; + r->coeffs[8 * i + 2] = ((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 7; + r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 7; + r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 7; + r->coeffs[8 * i + 5] = ((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 7; + r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 7; + r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5) & 7; + + r->coeffs[8 * i + 0] = MLDSA_ETA - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = MLDSA_ETA - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = MLDSA_ETA - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = MLDSA_ETA - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = MLDSA_ETA - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = MLDSA_ETA - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = MLDSA_ETA - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = MLDSA_ETA - r->coeffs[8 * i + 7]; + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -11, MLDSA_ETA + 1))) + { + r->coeffs[2 * i + 0] = a[i] & 0x0F; + r->coeffs[2 * i + 1] = a[i] >> 4; + r->coeffs[2 * i + 0] = MLDSA_ETA - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_ETA - r->coeffs[2 * i + 1]; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + + mld_assert_bound(r->coeffs, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + + +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[4]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 1]); + t[2] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 2]); + t[3] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 3]); + + r[9 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[9 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[9 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[9 * i + 2] |= (uint8_t)((t[1] << 2) & 0xFF); + r[9 * i + 3] = (uint8_t)((t[1] >> 6) & 0xFF); + r[9 * i + 4] = (uint8_t)((t[1] >> 14) & 0xFF); + r[9 * i + 4] |= (uint8_t)((t[2] << 4) & 0xFF); + r[9 * i + 5] = (uint8_t)((t[2] >> 4) & 0xFF); + r[9 * i + 6] = (uint8_t)((t[2] >> 12) & 0xFF); + r[9 * i + 6] |= (uint8_t)((t[3] << 6) & 0xFF); + r[9 * i + 7] = (uint8_t)((t[3] >> 2) & 0xFF); + r[9 * i + 8] = (uint8_t)((t[3] >> 10) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 1]); + + r[5 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[5 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[5 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[5 * i + 2] |= (uint8_t)((t[1] << 4) & 0xFF); + r[5 * i + 3] = (uint8_t)((t[1] >> 4) & 0xFF); + r[5 * i + 4] = (uint8_t)((t[1] >> 12) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +MLD_STATIC_TESTABLE void mld_polyz_unpack_c( + mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +) +{ + unsigned int i; +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[4 * i + 0] = a[9 * i + 0]; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 2] << 16; + r->coeffs[4 * i + 0] &= 0x3FFFF; + + r->coeffs[4 * i + 1] = a[9 * i + 2] >> 2; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 3] << 6; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 4] << 14; + r->coeffs[4 * i + 1] &= 0x3FFFF; + + r->coeffs[4 * i + 2] = a[9 * i + 4] >> 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 5] << 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 6] << 12; + r->coeffs[4 * i + 2] &= 0x3FFFF; + + r->coeffs[4 * i + 3] = a[9 * i + 6] >> 6; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 7] << 2; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10; + r->coeffs[4 * i + 3] &= 0x3FFFF; + + r->coeffs[4 * i + 0] = MLDSA_GAMMA1 - r->coeffs[4 * i + 0]; + r->coeffs[4 * i + 1] = MLDSA_GAMMA1 - r->coeffs[4 * i + 1]; + r->coeffs[4 * i + 2] = MLDSA_GAMMA1 - r->coeffs[4 * i + 2]; + r->coeffs[4 * i + 3] = MLDSA_GAMMA1 - r->coeffs[4 * i + 3]; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[2 * i + 0] = a[5 * i + 0]; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 2] << 16; + r->coeffs[2 * i + 0] &= 0xFFFFF; + + r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 3] << 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12; + /* r->coeffs[2*i+1] &= 0xFFFFF; */ /* No effect, since we're anyway at 20 + bits */ + + r->coeffs[2 * i + 0] = MLDSA_GAMMA1 - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_GAMMA1 - r->coeffs[2 * i + 1]; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +{ +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + ret = mld_polyz_unpack_17_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#elif defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + ret = mld_polyz_unpack_19_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYZ_UNPACK_17 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLYZ_UNPACK_19 && (MLD_CONFIG_PARAMETER_SET == 65 \ + || MLD_CONFIG_PARAMETER_SET == 87) */ + + mld_polyz_unpack_c(r, a); +} + +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + + mld_assert_bound(a->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[3 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0]) & 0xFF); + r[3 * i + 0] |= (uint8_t)((a->coeffs[4 * i + 1] << 6) & 0xFF); + r[3 * i + 1] = (uint8_t)((a->coeffs[4 * i + 1] >> 2) & 0xFF); + r[3 * i + 1] |= (uint8_t)((a->coeffs[4 * i + 2] << 4) & 0xFF); + r[3 * i + 2] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) & 0xFF); + r[3 * i + 2] |= (uint8_t)((a->coeffs[4 * i + 3] << 2) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + r[i] = + (uint8_t)((a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_rej_eta +#undef mld_rej_eta_c +#undef mld_poly_decompose_c +#undef mld_poly_use_hint_c +#undef mld_polyz_unpack_c +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_GAMMA1_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/poly_kl.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/poly_kl.h new file mode 100644 index 0000000000..c6aa498358 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/poly_kl.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_KL_H +#define MLD_POLY_KL_H + +#include "cbmc.h" +#include "common.h" +#include "poly.h" + +#define mld_poly_decompose MLD_NAMESPACE_KL(poly_decompose) +/************************************************* + * Name: mld_poly_decompose + * + * Description: For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such c mod MLDSA_Q = c1*ALPHA + + * c0 with -ALPHA/2 < c0 <= ALPHA/2 except + * c1 = (MLDSA_Q-1)/ALPHA where we set + * c1 = 0 and -ALPHA/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + * c1 + * - mld_poly *a0: pointer to input/output polynomial. Output + * polynomial has coefficients c0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +); + + +#define mld_poly_make_hint MLD_NAMESPACE_KL(poly_make_hint) +/************************************************* + * Name: mld_poly_make_hint + * + * Description: Compute hint polynomial. The coefficients of which indicate + * whether the low bits of the corresponding coefficient of + * the input polynomial overflow into the high bits. + * + * Arguments: - mld_poly *h: pointer to output hint polynomial + * - const mld_poly *a0: pointer to low part of input polynomial + * - const mld_poly *a1: pointer to high part of input polynomial + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + assigns(memory_slice(h, sizeof(mld_poly))) + ensures(return_value <= MLDSA_N) + ensures(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) +); + +#define mld_poly_use_hint MLD_NAMESPACE_KL(poly_use_hint) +/************************************************* + * Name: mld_poly_use_hint + * + * Description: Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - mld_poly *b: pointer to output polynomial with corrected high + *bits + * - const mld_poly *a: pointer to input polynomial + * - const mld_poly *h: pointer to input hint polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta_4x MLD_NAMESPACE_KL(poly_uniform_eta_4x) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample four polynomials with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce_i) + * + * Arguments: - mld_poly *r0: pointer to first output polynomial + * - mld_poly *r1: pointer to second output polynomial + * - mld_poly *r2: pointer to third output polynomial + * - mld_poly *r3: pointer to fourth output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce0: first nonce + * - uint8_t nonce1: second nonce + * - uint8_t nonce2: third nonce + * - uint8_t nonce3: fourth nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_abs_bound(r0->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r1->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r2->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r3->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta MLD_NAMESPACE_KL(poly_uniform_eta) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample polynomial with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce: nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1 MLD_NAMESPACE_KL(poly_uniform_gamma1) +/************************************************* + * Name: mld_poly_uniform_gamma1 + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1_4x MLD_NAMESPACE_KL(poly_uniform_gamma1_4x) +/************************************************* + * Name: mld_poly_uniform_gamma1_4x + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_bound(r0->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r1->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r2->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r3->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define mld_poly_challenge MLD_NAMESPACE_KL(poly_challenge) +/************************************************* + * Name: mld_poly_challenge + * + * Description: Implementation of H. Samples polynomial with MLDSA_TAU nonzero + * coefficients in {-1,1} using the output stream of + * SHAKE256(seed). + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const uint8_t mu[]: byte array containing seed of length + * MLDSA_CTILDEBYTES + **************************************************/ +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +__contract__( + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CTILDEBYTES)) + assigns(memory_slice(c, sizeof(mld_poly))) + /* All coefficients of c are -1, 0 or +1 */ + ensures(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) +); + +#define mld_polyeta_pack MLD_NAMESPACE_KL(polyeta_pack) +/************************************************* + * Name: mld_polyeta_pack + * + * Description: Bit-pack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYETA_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + assigns(memory_slice(r, MLDSA_POLYETA_PACKEDBYTES)) +); + +/* + * polyeta_unpack produces coefficients in [-MLDSA_ETA,MLDSA_ETA] for + * well-formed inputs (i.e., those produced by polyeta_pack). + * However, when passed an arbitrary byte array, it may produce smaller values, + * i.e, values in [MLD_POLYETA_UNPACK_LOWER_BOUND,MLDSA_ETA] + * Even though this should never happen, we use use the bound for arbitrary + * inputs in the CBMC proofs. + */ +#if MLDSA_ETA == 2 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-5) +#elif MLDSA_ETA == 4 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-11) +#else +#error "Invalid value of MLDSA_ETA" +#endif + +#define mld_polyeta_unpack MLD_NAMESPACE_KL(polyeta_unpack) +/************************************************* + * Name: mld_polyeta_unpack + * + * Description: Unpack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYETA_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)) +); + +#define mld_polyz_pack MLD_NAMESPACE_KL(polyz_pack) +/************************************************* + * Name: mld_polyz_pack + * + * Description: Bit-pack polynomial with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYZ_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(r, MLDSA_POLYZ_PACKEDBYTES)) +); + + +#define mld_polyz_unpack MLD_NAMESPACE_KL(polyz_unpack) +/************************************************* + * Name: mld_polyz_unpack + * + * Description: Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); + +#define mld_polyw1_pack MLD_NAMESPACE_KL(polyw1_pack) +/************************************************* + * Name: mld_polyw1_pack + * + * Description: Bit-pack polynomial w1 with coefficients in [0,15] or [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES)) +); + +#endif /* !MLD_POLY_KL_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/polyvec.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/polyvec.c new file mode 100644 index 0000000000..5c3a08ab32 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/polyvec.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include +#include + +#include "common.h" +#include "debug.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" + +/* This namespacing is not done at the top to avoid a naming conflict + * with native backends, which are currently not yet namespaced. */ +#define mld_polymat_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polymat_permute_bitrev_to_custom) +#define mld_polyvecl_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polyvecl_permute_bitrev_to_custom) +#define mld_polyvecl_pointwise_acc_montgomery_c \ + MLD_ADD_PARAM_SET(mld_polyvecl_pointwise_acc_montgomery_c) + +#if !defined(MLD_CONFIG_REDUCE_RAM) +/* Helper function to ensure that the polynomial entries in the output + * of mld_polyvec_matrix_expand use the standard (bitreversed) ordering + * of coefficients. + * No-op unless a native backend with a custom ordering is used. + */ + +static void mld_polyvecl_permute_bitrev_to_custom(mld_polyvecl *v) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +{ +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + unsigned i; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_permute_bitrev_to_custom(v->vec[i].coeffs); + } +#else /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + /* Nothing to do */ + (void)v; +#endif /* !MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ +} + +static void mld_polymat_permute_bitrev_to_custom(mld_polymat *mat) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; i++) + __loop__( + assigns(i, memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))) + { + mld_polyvecl_permute_bitrev_to_custom(&mat->vec[i]); + } +} +#endif /* !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + unsigned int i; + MLD_ALIGN uint8_t seed_ext[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + mld_memcpy(seed_ext, mat->rho, MLDSA_SEEDBYTES); + + /* Generate row on-demand */ + for (i = 0; i < MLDSA_L; i++) + { + uint8_t x = (uint8_t)row; + uint8_t y = (uint8_t)i; + + seed_ext[MLDSA_SEEDBYTES + 0] = y; + seed_ext[MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(&mat->row_buffer.vec[i], seed_ext); + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + mld_poly_permute_bitrev_to_custom(mat->row_buffer.vec[i].coeffs); +#endif + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); + + return &mat->row_buffer; +#else /* MLD_CONFIG_REDUCE_RAM */ + return &mat->vec[row]; +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + /* In REDUCE_RAM mode, just copy the seed for later on-demand generation */ + mld_memcpy(mat->rho, rho, MLDSA_SEEDBYTES); +#else + unsigned int i, j; + /* + * We generate four separate seed arrays rather than a single one to work + * around limitations in CBMC function contracts dealing with disjoint slices + * of the same parent object. + */ + + MLD_ALIGN uint8_t seed_ext[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + mld_memcpy(seed_ext[j], rho, MLDSA_SEEDBYTES); + } + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + /* Sample 4 matrix entries a time. */ + for (i = 0; i < (MLDSA_K * MLDSA_L / 4) * 4; i += 4) + __loop__( + assigns(i, j, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= (MLDSA_K * MLDSA_L / 4) * 4 && i % 4 == 0) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + uint8_t x = (uint8_t)((i + j) / MLDSA_L); + uint8_t y = (uint8_t)((i + j) % MLDSA_L); + + seed_ext[j][MLDSA_SEEDBYTES + 0] = y; + seed_ext[j][MLDSA_SEEDBYTES + 1] = x; + } + + mld_poly_uniform_4x(&mat->vec[i / MLDSA_L].vec[i % MLDSA_L], + &mat->vec[(i + 1) / MLDSA_L].vec[(i + 1) % MLDSA_L], + &mat->vec[(i + 2) / MLDSA_L].vec[(i + 2) % MLDSA_L], + &mat->vec[(i + 3) / MLDSA_L].vec[(i + 3) % MLDSA_L], + seed_ext); + } +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + i = 0; +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + /* Entries omitted by the batch-sampling are sampled individually. */ + while (i < MLDSA_K * MLDSA_L) + __loop__( + assigns(i, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K * MLDSA_L) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + uint8_t x = (uint8_t)(i / MLDSA_L); + uint8_t y = (uint8_t)(i % MLDSA_L); + mld_poly *this_poly = &mat->vec[i / MLDSA_L].vec[i % MLDSA_L]; + + seed_ext[0][MLDSA_SEEDBYTES + 0] = y; + seed_ext[0][MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(this_poly, seed_ext[0]); + i++; + } + + mld_polymat_permute_bitrev_to_custom(mat); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(t, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + const mld_polyvecl *row = mld_polymat_get_row(mat, i); + mld_polyvecl_pointwise_acc_montgomery(&t->vec[i], row, v); + } + + mld_assert_abs_bound_2d(t->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_L **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; +#endif + + /* Safety: nonce is at most ((UINT16_MAX - MLDSA_L) / MLDSA_L), and, hence, + * this cast is safe. See MLD_NONCE_UB comment in sign.c. */ + nonce = (uint16_t)(MLDSA_L * nonce); + /* Now, nonce <= UINT16_MAX - (MLDSA_L - 1), so the casts below are safe. */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_gamma1(&v->vec[i], seed, (uint16_t)(nonce + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLDSA_L == 4 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); +#elif MLDSA_L == 5 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); + mld_poly_uniform_gamma1(&v->vec[4], seed, (uint16_t)(nonce + 4)); +#elif MLDSA_L == 7 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], + &v->vec[3 /* irrelevant */], seed, nonce, + (uint16_t)(nonce + 1), (uint16_t)(nonce + 2), + 0xFF /* irrelevant */); + mld_poly_uniform_gamma1_4x(&v->vec[3], &v->vec[4], &v->vec[5], &v->vec[6], + seed, (uint16_t)(nonce + 3), (uint16_t)(nonce + 4), + (uint16_t)(nonce + 5), (uint16_t)(nonce + 6)); +#endif /* MLDSA_L == 7 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(k0, i, MLDSA_L, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_STATIC_TESTABLE void mld_polyvecl_pointwise_acc_montgomery_c( + mld_poly *w, const mld_polyvecl *u, const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i, j; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + for (i = 0; i < MLDSA_N; i++) + __loop__( + assigns(i, j, memory_slice(w, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_abs_bound(w->coeffs, 0, i, MLDSA_Q)) + ) + { + int64_t t = 0; + int32_t r; + for (j = 0; j < MLDSA_L; j++) + __loop__( + assigns(j, t) + invariant(j <= MLDSA_L) + invariant(t >= -(int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + invariant(t <= (int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + ) + { + t += (int64_t)u->vec[j].coeffs[i] * v->vec[j].coeffs[i]; + } + + r = mld_montgomery_reduce(t); + w->coeffs[i] = r; + } + + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +{ +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) && \ + MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l4_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) && \ + MLD_CONFIG_PARAMETER_SET == 65 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l5_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) && \ + MLD_CONFIG_PARAMETER_SET == 87 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l7_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 && \ + MLD_CONFIG_PARAMETER_SET == 44) && \ + !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 && \ + MLD_CONFIG_PARAMETER_SET == 65) && \ + MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 && \ + MLD_CONFIG_PARAMETER_SET == 87 */ + /* The first input is bounded by [0, Q-1] inclusive + * The second input is bounded by [-9Q+1, 9Q-1] inclusive . Hence, we can + * safely accumulate in 64-bits without intermediate reductions as + * MLDSA_L * (MLD_NTT_BOUND-1) * (Q-1) < INT64_MAX + * + * The worst case is ML-DSA-87: 7 * (9Q-1) * (Q-1) < 2**52 + * (and likewise for negative values) + */ + mld_polyvecl_pointwise_acc_montgomery_c(w, u, v); +} + +MLD_INTERNAL_API +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + invariant(i <= MLDSA_L) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + return t; +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_K **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k2, 0, i, + array_bound(v->vec[k2].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ) + { + mld_poly_reduce(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_caddq(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, + forall(k1, 0, MLDSA_N, u->vec[k0].coeffs[k1] == loop_entry(*u).vec[k0].coeffs[k1]))) + invariant(forall(k6, 0, i, array_bound(u->vec[k6].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + ) + { + mld_poly_add(&u->vec[i], &v->vec[i]); + } + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(u->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, u->vec[k1].coeffs[n1] == loop_entry(*u).vec[k1].coeffs[n1])))) + { + mld_poly_sub(&u->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, v->vec[k1].coeffs[n1] == loop_entry(*v).vec[k1].coeffs[n1]))) + ) + { + mld_poly_shiftl(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))) + { + mld_poly_invntt_tomont(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_INTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, array_abs_bound(r->vec[k2].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + mld_poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]); + } + mld_assert_abs_bound_2d(r->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + + return t; +} + +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + invariant(forall(k2, 0, i, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) + ) + { + mld_poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +{ + unsigned int i; + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + invariant(forall(k2, 0, i, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) + invariant(forall(k3, i, MLDSA_K, + array_bound(v0->vec[k3].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + ) + { + mld_poly_decompose(&v1->vec[i], &v0->vec[i]); + } + + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + mld_assert_abs_bound_2d(v0->vec, MLDSA_K, MLDSA_N, MLDSA_GAMMA2 + 1); +} + +MLD_INTERNAL_API +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, s, memory_slice(h, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(s <= i * MLDSA_N) + invariant(forall(k1, 0, i, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + s += mld_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]); + } + + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + return s; +} + +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *u, + const mld_polyveck *h) +{ + unsigned int i; + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(w, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)))) + ) + { + mld_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]); + } + + mld_assert_bound_2d(w->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +{ + unsigned int i; + mld_assert_bound_2d(w1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyw1_pack(&r[i * MLDSA_POLYW1_PACKEDBYTES], &w1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt0_pack(&r[i * MLDSA_POLYT0_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyz_unpack(&z->vec[i], r + i * MLDSA_POLYZ_PACKEDBYTES); + } + + mld_assert_bound_2d(z->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt0_unpack(&p->vec[i], r + i * MLDSA_POLYT0_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_polymat_permute_bitrev_to_custom +#undef mld_polyvecl_permute_bitrev_to_custom +#undef mld_polyvecl_pointwise_acc_montgomery_c diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/polyvec.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/polyvec.h new file mode 100644 index 0000000000..d21abc02ff --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/polyvec.h @@ -0,0 +1,725 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLYVEC_H +#define MLD_POLYVEC_H + +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "poly_kl.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_polyvecl MLD_ADD_PARAM_SET(mld_polyvecl) +#define mld_polyveck MLD_ADD_PARAM_SET(mld_polyveck) +#define mld_polymat MLD_ADD_PARAM_SET(mld_polymat) +/* End of parameter set namespacing */ + +/* Vectors of polynomials of length MLDSA_L */ +typedef struct +{ + mld_poly vec[MLDSA_L]; +} mld_polyvecl; + + +#define mld_polyvecl_uniform_gamma1 MLD_NAMESPACE_KL(polyvecl_uniform_gamma1) +/************************************************* + * Name: mld_polyvecl_uniform_gamma1 + * + * Description: Sample vector of polynomials with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_polyvecl *v: pointer to output vector + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + *************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + requires(nonce <= (UINT16_MAX - MLDSA_L) / MLDSA_L) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyvecl_ntt MLD_NAMESPACE_KL(polyvecl_ntt) +/************************************************* + * Name: mld_polyvecl_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_L. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyvecl *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k0, 0, MLDSA_L, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyvecl_pointwise_acc_montgomery \ + MLD_NAMESPACE_KL(polyvecl_pointwise_acc_montgomery) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery + * + * Description: Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * The first input "u" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * + * Arguments: - mld_poly *w: output polynomial + * - const mld_polyvecl *u: pointer to first input vector + * - const mld_polyvecl *v: pointer to second input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + + +#define mld_polyvecl_chknorm MLD_NAMESPACE_KL(polyvecl_chknorm) +/************************************************* + * Name: mld_polyvecl_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_L. + * Assumes input mld_polyvecl to be reduced by polyvecl_reduce(). + * + * Arguments: - const mld_polyvecl *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials is strictly smaller than B <= + * (MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +/* Vectors of polynomials of length MLDSA_K */ +typedef struct +{ + mld_poly vec[MLDSA_K]; +} mld_polyveck; + +/* Matrix of polynomials (K x L) */ +typedef struct +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + mld_polyvecl row_buffer; + uint8_t rho[MLDSA_SEEDBYTES]; +#else + mld_polyvecl vec[MLDSA_K]; +#endif +} mld_polymat; + +#define mld_polyveck_reduce MLD_NAMESPACE_KL(polyveck_reduce) +/************************************************* + * Name: polyveck_reduce + * + * Description: Reduce coefficients of polynomials in vector of length MLDSA_K + * to representatives in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) +); + +#define mld_polyveck_caddq MLD_NAMESPACE_KL(polyveck_caddq) +/************************************************* + * Name: mld_polyveck_caddq + * + * Description: For all coefficients of polynomials in vector of length MLDSA_K + * add MLDSA_Q if coefficient is negative. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_add MLD_NAMESPACE_KL(polyveck_add) +/************************************************* + * Name: mld_polyveck_add + * + * Description: Add vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to input-output vector of polynomials + * to be added to + * - const mld_polyveck *v: pointer to second input vector of + * polynomials + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(p0, 0, MLDSA_K, array_abs_bound(u->vec[p0].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) + requires(forall(p1, 0, MLDSA_K, + array_bound(v->vec[p1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(q2, 0, MLDSA_K, + array_bound(u->vec[q2].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_sub MLD_NAMESPACE_KL(polyveck_sub) +/************************************************* + * Name: mld_polyveck_sub + * + * Description: Subtract vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to first input vector + * - const mld_polyveck *v: pointer to second input vector to be + * subtracted from first input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(u->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_shiftl MLD_NAMESPACE_KL(polyveck_shiftl) +/************************************************* + * Name: mld_polyveck_shiftl + * + * Description: Multiply vector of polynomials of Length MLDSA_K by 2^MLDSA_D + *without modular reduction. Assumes input coefficients to be less than + *2^{31-MLDSA_D}. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_ntt MLD_NAMESPACE_KL(polyveck_ntt) +/************************************************* + * Name: mld_polyveck_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_K. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyveck_invntt_tomont MLD_NAMESPACE_KL(polyveck_invntt_tomont) +/************************************************* + * Name: mld_polyveck_invntt_tomont + * + * Description: Inverse NTT and multiplication by 2^{32} of polynomials + * in vector of length MLDSA_K. + * Input coefficients need to be less than MLDSA_Q, and + * Output coefficients are bounded by MLD_INTT_BOUND. + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) +); + +#define mld_polyveck_pointwise_poly_montgomery \ + MLD_NAMESPACE_KL(polyveck_pointwise_poly_montgomery) +/************************************************* + * Name: mld_polyveck_pointwise_poly_montgomery + * + * Description: Pointwise multiplication of a polynomial vector of length + * MLDSA_K by a single polynomial in NTT domain and multiplication + * of the resulting polynomial vector by 2^{-32}. + * + * Arguments: - mld_polyveck *r: pointer to output vector + * - mld_poly *a: pointer to input polynomial + * - mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(r, sizeof(mld_polyveck))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(r, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(r->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#define mld_polyveck_chknorm MLD_NAMESPACE_KL(polyveck_chknorm) +/************************************************* + * Name: mld_polyveck_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_K. + * Assumes input mld_polyveck to be reduced by polyveck_reduce(). + * + * Arguments: - const mld_polyveck *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials are strictly smaller than B <= + *(MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, + -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +#define mld_polyveck_power2round MLD_NAMESPACE_KL(polyveck_power2round) +/************************************************* + * Name: mld_polyveck_power2round + * + * Description: For all coefficients a of polynomials in vector of length + *MLDSA_K, compute a0, a1 such that a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with + *-2^{MLDSA_D-1} < a0 <= 2^{MLDSA_D-1}. Assumes coefficients to be standard + *representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to output vector of polynomials with + * coefficients a0 + * - const mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) +); + +#define mld_polyveck_decompose MLD_NAMESPACE_KL(polyveck_decompose) +/************************************************* + * Name: mld_polyveck_decompose + * + * Description: For all coefficients a of polynomials in vector of length + * MLDSA_K, compute high and low bits a0, a1 such a mod^+ MLDSA_Q = a1*ALPHA + * + a0 with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (MLDSA_Q-1)/ALPHA where we set + * a1 = 0 and -ALPHA/2 <= a0 = a mod MLDSA_Q - MLDSA_Q < 0. Assumes coefficients + * to be standard representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to input/output vector of + * polynomials with. Output polynomial has + * coefficients a0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v0->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + ensures(forall(k2, 0, MLDSA_K, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) +); + +#define mld_polyveck_make_hint MLD_NAMESPACE_KL(polyveck_make_hint) +/************************************************* + * Name: mld_polyveck_make_hint + * + * Description: Compute hint vector. + * + * Arguments: - mld_polyveck *h: pointer to output vector + * - const mld_polyveck *v0: pointer to low part of input vector + * - const mld_polyveck *v1: pointer to high part of input vector + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(return_value <= MLDSA_N * MLDSA_K) + ensures(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) +); + +#define mld_polyveck_use_hint MLD_NAMESPACE_KL(polyveck_use_hint) +/************************************************* + * Name: mld_polyveck_use_hint + * + * Description: Use hint vector to correct the high bits of input vector. + * + * Arguments: - mld_polyveck *w: pointer to output vector of polynomials with + * corrected high bits + * - const mld_polyveck *u: pointer to input vector + * - const mld_polyveck *h: pointer to input hint vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *v, + const mld_polyveck *h) +__contract__( + requires(memory_no_alias(w, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + assigns(memory_slice(w, sizeof(mld_polyveck))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) +); + +#define mld_polyveck_pack_w1 MLD_NAMESPACE_KL(polyveck_pack_w1) +/************************************************* + * Name: mld_polyveck_pack_w1 + * + * Description: Bit-pack polynomial vector w1 with coefficients in [0,15] or + * [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_K* MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_polyveck *a: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(w1, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(w1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) +); + +#define mld_polyveck_pack_eta MLD_NAMESPACE_KL(polyveck_pack_eta) +/************************************************* + * Name: mld_polyveck_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients + * in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyvecl_pack_eta MLD_NAMESPACE_KL(polyvecl_pack_eta) +/************************************************* + * Name: mld_polyvecl_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_L * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyveck_pack_t0 MLD_NAMESPACE_KL(polyveck_pack_t0) +/************************************************* + * Name: mld_polyveck_pack_t0 + * + * Description: Bit-pack polynomial vector to with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(p->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) +); + +#define mld_polyvecl_unpack_eta MLD_NAMESPACE_KL(polyvecl_unpack_eta) +/************************************************* + * Name: mld_polyvecl_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyvecl *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + assigns(memory_slice(p, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyvecl_unpack_z MLD_NAMESPACE_KL(polyvecl_unpack_z) +/************************************************* + * Name: mld_polyvecl_unpack_z + * + * Description: Unpack polynomial vector with coefficients in + * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_polyvecl *z: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(z->vec[k1].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyveck_unpack_eta MLD_NAMESPACE_KL(polyveck_unpack_eta) +/************************************************* + * Name: mld_polyveck_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyveck_unpack_t0 MLD_NAMESPACE_KL(polyveck_unpack_t0) +/************************************************* + * Name: mld_polyveck_unpack_t0 + * + * Description: Unpack polynomial vector with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) +); + +#define mld_polymat_get_row MLD_NAMESPACE_KL(polymat_get_row) +/************************************************* + * Name: mld_polymat_get_row + * + * Description: Retrieve a pointer to a specific row of the matrix. + * In MLD_CONFIG_REDUCE_RAM mode, generates the row on-demand. + * + * Arguments: - mld_polymat *mat: pointer to matrix + * - unsigned int row: row index (must be < MLDSA_K) + * + * Returns pointer to the row (mld_polyvecl) + **************************************************/ +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row); + +#define mld_polyvec_matrix_expand MLD_NAMESPACE_KL(polyvec_matrix_expand) +/************************************************* + * Name: mld_polyvec_matrix_expand + * + * Description: Implementation of ExpandA. Generates matrix A with uniformly + * random coefficients a_{i,j} by performing rejection + * sampling on the output stream of SHAKE128(rho|j|i) + * + * Arguments: - mld_polymat *mat: pointer to output matrix + * - const uint8_t rho[]: byte array containing seed rho + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +__contract__( + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +); + + + +#define mld_polyvec_matrix_pointwise_montgomery \ + MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery) +/************************************************* + * Name: mld_polyvec_matrix_pointwise_montgomery + * + * Description: Compute matrix-vector multiplication in NTT domain with + * pointwise multiplication and multiplication by 2^{-32}. + * Input matrix and vector must be in NTT domain representation. + * + * The first input "mat" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * Note: In MLD_CONFIG_REDUCE_RAM mode, mat cannot be const + * as rows are generated on-demand. + * + * Arguments: - mld_polyveck *t: pointer to output vector t + * - mld_polymat *mat: pointer to input matrix + * - const mld_polyvecl *v: pointer to input vector v + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(t, sizeof(mld_polyveck))) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(t, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#endif /* !MLD_POLYVEC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/randombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/randombytes.h new file mode 100644 index 0000000000..da55772419 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/randombytes.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_RANDOMBYTES_H +#define MLD_RANDOMBYTES_H + +#include +#include + +#include "cbmc.h" +#include "common.h" + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +#if !defined(MLD_CONFIG_CUSTOM_RANDOMBYTES) +MLD_MUST_CHECK_RETURN_VALUE +int randombytes(uint8_t *out, size_t outlen); +static MLD_INLINE int mld_randombytes(uint8_t *out, size_t outlen) +__contract__( + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) { return randombytes(out, outlen); } +#endif /* !MLD_CONFIG_CUSTOM_RANDOMBYTES */ +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ +#endif /* !MLD_RANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/reduce.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/reduce.h new file mode 100644 index 0000000000..413cf1829e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/reduce.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_REDUCE_H +#define MLD_REDUCE_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* check-magic: -4186625 == pow(2,32,MLDSA_Q) */ +#define MLD_MONT -4186625 + +/* Upper bound for domain of mld_reduce32() */ +#define MLD_REDUCE32_DOMAIN_MAX (INT32_MAX - (1 << 22)) + +/* Absolute bound for range of mld_reduce32() */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define MLD_REDUCE32_RANGE_MAX 6283009 + +/************************************************* + * Name: mld_montgomery_reduce + * + * Description: Generic Montgomery reduction; given a 64-bit integer a, computes + * 32-bit integer congruent to a * R^-1 mod q, where R=2^32 + * + * Arguments: - int64_t a: input integer to be reduced, of absolute value + * smaller or equal to INT64_MAX - 2^31 * MLDSA_Q. + * + * Returns: Integer congruent to a * R^-1 modulo q, with absolute value + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * In particular, if |a| < 2^31 * MLDSA_Q, the absolute value + * of the return value is < MLDSA_Q. + **************************************************/ +static MLD_INLINE int32_t mld_montgomery_reduce(int64_t a) +__contract__( + /* We don't attempt to express an input-dependent output bound + * as the post-condition here, as all call-sites satisfy the + * absolute input bound 2^31 * MLDSA_Q and higher-level + * reasoning can be conducted using |return_value| < MLDSA_Q. */ + requires(a > -(((int64_t)1 << 31) * MLDSA_Q) && + a < (((int64_t)1 << 31) * MLDSA_Q)) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* check-magic: 58728449 == unsigned_mod(pow(MLDSA_Q, -1, 2^32), 2^32) */ + const uint64_t QINV = 58728449; + + /* Compute a*q^{-1} mod 2^32 in unsigned representatives */ + const uint32_t a_reduced = mld_cast_int64_to_uint32(a); + const uint32_t a_inverted = (a_reduced * QINV) & UINT32_MAX; + + /* Lift to signed canonical representative mod 2^32. */ + const int32_t t = mld_cast_uint32_to_int32(a_inverted); + + int64_t r; + + mld_assert(a < +(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)) && + a > -(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q))); + + r = a - (int64_t)t * MLDSA_Q; + + /* + * PORTABILITY: Right-shift on a signed integer is, strictly-speaking, + * implementation-defined for negative left argument. Here, + * we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5)) + */ + r = r >> 32; + + /* Bounds: + * + * By construction of the Montgomery multiplication, by the time we + * compute r >> 32, r is divisible by 2^32, and hence + * + * |r >> 32| = |r| / 2^32 + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * (In general, we would only have |x >> n| <= ceil(|x| / 2^n)). + * + * In particular, if |a| < 2^31 * MLDSA_Q, then |return_value| < MLDSA_Q. + */ + return (int32_t)r; +} + +/************************************************* + * Name: mld_reduce32 + * + * Description: For finite field element a with a <= 2^{31} - 2^{22} - 1, + * compute r \equiv a (mod MLDSA_Q) such that + * -MLD_REDUCE32_RANGE_MAX <= r < MLD_REDUCE32_RANGE_MAX. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_reduce32(int32_t a) +__contract__( + requires(a <= MLD_REDUCE32_DOMAIN_MAX) + ensures(return_value >= -MLD_REDUCE32_RANGE_MAX) + ensures(return_value < MLD_REDUCE32_RANGE_MAX) +) +{ + int32_t t; + + t = (a + (1 << 22)) >> 23; + t = a - t * MLDSA_Q; + mld_assert((t - a) % MLDSA_Q == 0); + return t; +} + +/************************************************* + * Name: mld_caddq + * + * Description: Add MLDSA_Q if input coefficient is negative. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_caddq(int32_t a) +__contract__( + requires(a > -MLDSA_Q) + requires(a < MLDSA_Q) + ensures(return_value >= 0) + ensures(return_value < MLDSA_Q) + ensures(return_value == (a >= 0) ? a : (a + MLDSA_Q)) +) +{ + return mld_ct_sel_int32(a + MLDSA_Q, a, mld_ct_cmask_neg_i32(a)); +} + + +#endif /* !MLD_REDUCE_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/rounding.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/rounding.h new file mode 100644 index 0000000000..a83562b0f1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/rounding.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_ROUNDING_H +#define MLD_ROUNDING_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_power2round MLD_ADD_PARAM_SET(mld_power2round) +#define mld_decompose MLD_ADD_PARAM_SET(mld_decompose) +#define mld_make_hint MLD_ADD_PARAM_SET(mld_make_hint) +#define mld_use_hint MLD_ADD_PARAM_SET(mld_use_hint) +/* End of parameter set namespacing */ + +#define MLD_2_POW_D (1 << MLDSA_D) + +/************************************************* + * Name: mld_power2round + * + * Description: For finite field element a, compute a0, a1 such that + * a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with -2^{MLDSA_D-1} < a0 <= + * 2^{MLDSA_D-1}. Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: In the reference implementation, a1 is passed as a + * return value instead. + **************************************************/ +static MLD_INLINE void mld_power2round(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + ensures(*a0 > -(MLD_2_POW_D/2) && *a0 <= (MLD_2_POW_D/2)) + ensures(*a1 >= 0 && *a1 <= (MLDSA_Q - 1) / MLD_2_POW_D) + ensures((*a1 * MLD_2_POW_D + *a0 - a) % MLDSA_Q == 0) +) +{ + *a1 = (a + (1 << (MLDSA_D - 1)) - 1) >> MLDSA_D; + *a0 = a - (*a1 << MLDSA_D); +} + +/************************************************* + * Name: mld_decompose + * + * Description: For finite field element a, compute high and low bits a0, a1 + * such that a mod^+ MLDSA_Q = a1* 2 * MLDSA_GAMMA2 + a0 with + * -MLDSA_GAMMA2 < a0 <= MLDSA_GAMMA2 except + * if a1 = (MLDSA_Q-1)/(MLDSA_GAMMA2*2) where we set a1 = 0 and + * -MLDSA_GAMMA2 <= a0 = a mod^+ MLDSA_Q - MLDSA_Q < 0. + * Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: a1 is passed as a return value instead + **************************************************/ +static MLD_INLINE void mld_decompose(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + /* a0 = -MLDSA_GAMMA2 can only occur when (q-1) = a - (a mod MLDSA_GAMMA2), + * then a1=1; and a0 = a - (a mod MLDSA_GAMMA2) - 1 (@[FIPS204, Algorithm 36 (Decompose)]) */ + ensures(*a0 >= -MLDSA_GAMMA2 && *a0 <= MLDSA_GAMMA2) + ensures(*a1 >= 0 && *a1 < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) + ensures((*a1 * 2 * MLDSA_GAMMA2 + *a0 - a) % MLDSA_Q == 0) +) +{ + /* + * The goal is to compute f1 = round-(f / (2*GAMMA2)), which can be computed + * alternatively as round-(f / (128B)) = round-(ceil(f / 128) / B) where + * B = 2*GAMMA2 / 128. Here round-() denotes "round half down". + * + * The equality round-(f / (128B)) = round-(ceil(f / 128) / B) can deduced + * as follows. Since changing f to align-up(f, 128) can move f onto but not + * across a rounding boundary for division by 128*B (note that we need B to be + * even for this to work), and round- rounds down on the boundary, we have + * + * round-(f / (128B)) = round-(align-up(f, 128) / (128B)) + * = round-((align-up(f, 128) / 128) / B) + * = round-(ceil(f / 128) / B). + */ + *a1 = (a + 127) >> 7; + /* We know a >= 0 and a < MLDSA_Q, so... */ + /* check-magic: 65472 == round((MLDSA_Q-1)/128) */ + mld_assert(*a1 >= 0 && *a1 <= 65472); + +#if MLD_CONFIG_PARAMETER_SET == 44 + /* check-magic: 1488 == 2 * intdiv(intdiv(MLDSA_Q - 1, 88), 128) */ + /* check-magic: 11275 == floor(2**24 / 1488) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + */ + *a1 = (*a1 * 11275 + (1 << 23)) >> 24; + mld_assert(*a1 >= 0 && *a1 <= 44); + + *a1 = mld_ct_sel_int32(0, *a1, mld_ct_cmask_neg_i32(43 - *a1)); + mld_assert(*a1 >= 0 && *a1 <= 43); +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + /* check-magic: 4092 == 2 * intdiv(intdiv(MLDSA_Q - 1, 32), 128) */ + /* check-magic: 1025 == floor(2**22 / 4092) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + */ + *a1 = (*a1 * 1025 + (1 << 21)) >> 22; + mld_assert(*a1 >= 0 && *a1 <= 16); + + *a1 &= 15; + mld_assert(*a1 >= 0 && *a1 <= 15); + +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + + *a0 = a - *a1 * 2 * MLDSA_GAMMA2; + *a0 = mld_ct_sel_int32(*a0 - MLDSA_Q, *a0, + mld_ct_cmask_neg_i32((MLDSA_Q - 1) / 2 - *a0)); +} + +/************************************************* + * Name: mld_make_hint + * + * Description: Compute hint bit indicating whether the low bits of the + * input element overflow into the high bits. + * + * Arguments: - int32_t a0: low bits of input element + * - int32_t a1: high bits of input element + * + * Returns 1 if overflow, 0 otherwise + **************************************************/ +static MLD_INLINE unsigned int mld_make_hint(int32_t a0, int32_t a1) +__contract__( + ensures(return_value >= 0 && return_value <= 1) +) +{ + if (a0 > MLDSA_GAMMA2 || a0 < -MLDSA_GAMMA2 || + (a0 == -MLDSA_GAMMA2 && a1 != 0)) + { + return 1; + } + + return 0; +} + +/************************************************* + * Name: mld_use_hint + * + * Description: Correct high bits according to hint. + * + * Arguments: - int32_t a: input element + * - int32_t hint: hint bit + * + * Returns corrected high bits. + **************************************************/ +static MLD_INLINE int32_t mld_use_hint(int32_t a, int32_t hint) +__contract__( + requires(hint >= 0 && hint <= 1) + requires(a >= 0 && a < MLDSA_Q) + ensures(return_value >= 0 && return_value < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) +) +{ + int32_t a0, a1; + + mld_decompose(&a0, &a1, a); + if (hint == 0) + { + return a1; + } + +#if MLD_CONFIG_PARAMETER_SET == 44 + if (a0 > 0) + { + return (a1 == 43) ? 0 : a1 + 1; + } + else + { + return (a1 == 0) ? 43 : a1 - 1; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + if (a0 > 0) + { + return (a1 + 1) & 15; + } + else + { + return (a1 - 1) & 15; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + + +#endif /* !MLD_ROUNDING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/sign.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/sign.c new file mode 100644 index 0000000000..32bba52d65 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/sign.c @@ -0,0 +1,1508 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [Round3_Spec] + * CRYSTALS-Dilithium Algorithm Specifications and Supporting Documentation + * (Version 3.1) + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf + */ + +#include +#include + +#include "cbmc.h" +#include "ct.h" +#include "debug.h" +#include "packing.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" +#include "randombytes.h" +#include "sign.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_check_pct MLD_ADD_PARAM_SET(mld_check_pct) MLD_CONTEXT_PARAMETERS_2 +#define mld_sample_s1_s2 MLD_ADD_PARAM_SET(mld_sample_s1_s2) +#define mld_validate_hash_length MLD_ADD_PARAM_SET(mld_validate_hash_length) +#define mld_get_hash_oid MLD_ADD_PARAM_SET(mld_get_hash_oid) +#define mld_H MLD_ADD_PARAM_SET(mld_H) +#define mld_compute_pack_z MLD_ADD_PARAM_SET(mld_compute_pack_z) +#define mld_attempt_signature_generation \ + MLD_ADD_PARAM_SET(mld_attempt_signature_generation) MLD_CONTEXT_PARAMETERS_8 +#define mld_compute_t0_t1_tr_from_sk_components \ + MLD_ADD_PARAM_SET(mld_compute_t0_t1_tr_from_sk_components) \ + MLD_CONTEXT_PARAMETERS_7 +/* End of parameter set namespacing */ + + +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + ensures(return_value == 0 + || return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL) +); + +#if defined(MLD_CONFIG_KEYGEN_PCT) +/************************************************* + * @[FIPS140_3_IG] + * (https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf) + * + * TE10.35.02: Pair-wise Consistency Test (PCT) for DSA keypairs + * + * Purpose: Validates that a generated public/private key pair can correctly + * sign and verify data. Test performs signature generation using the private + * key (sk), followed by signature verification using the public key (pk). + * Returns 0 if the signature was successfully verified, non-zero if it cannot. + * + * Note: @[FIPS204] requires that public/private key pairs are to be used only + * for the calculation and/of verification of digital signatures. + **************************************************/ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t message[1] = {0}; + size_t siglen; + int ret; + MLD_ALLOC(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + MLD_ALLOC(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + + if (signature == NULL || pk_test == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Copy public key for testing */ + mld_memcpy(pk_test, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* Sign a test message using the original secret key */ + ret = mld_sign_signature(signature, &siglen, message, sizeof(message), NULL, + 0, sk, context); + if (ret != 0) + { + goto cleanup; + } + +#if defined(MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST) + /* Deliberately break public key for testing purposes */ + if (mld_break_pct()) + { + pk_test[0] = ~pk_test[0]; + } +#endif /* MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST */ + + /* Verify the signature using the (potentially corrupted) public key */ + ret = mld_sign_verify(signature, siglen, message, sizeof(message), NULL, 0, + pk_test, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + MLD_FREE(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + + return ret; +} +#else /* MLD_CONFIG_KEYGEN_PCT */ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + /* Skip PCT */ + ((void)pk); + ((void)sk); +#if defined(MLD_CONFIG_CONTEXT_PARAMETER) + ((void)context); +#endif + return 0; +} +#endif /* !MLD_CONFIG_KEYGEN_PCT */ + +static void mld_sample_s1_s2(mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t seed[MLDSA_CRHBYTES]) +__contract__( + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(object_whole(s1), object_whole(s2)) + ensures(forall(l0, 0, MLDSA_L, array_abs_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + ensures(forall(k0, 0, MLDSA_K, array_abs_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) +) +{ +/* Sample short vectors s1 and s2 */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; + uint16_t nonce = 0; + /* Safety: The nonces are at most 14 (MLDSA_L + MLDSA_K - 1), and, hence, the + * casts are safe. */ + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_eta(&s1->vec[i], seed, (uint8_t)(nonce + i)); + } + for (i = 0; i < MLDSA_K; i++) + { + mld_poly_uniform_eta(&s2->vec[i], seed, (uint8_t)(nonce + MLDSA_L + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLD_CONFIG_PARAMETER_SET == 44 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 4, 5, 6, 7); +#elif MLD_CONFIG_PARAMETER_SET == 65 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s2->vec[0], &s2->vec[1], + &s2->vec[2] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[2], &s2->vec[3], &s2->vec[4], &s2->vec[5], + seed, 7, 8, 9, 10); +#elif MLD_CONFIG_PARAMETER_SET == 87 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s1->vec[5], &s1->vec[6], + &s2->vec[0] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 7, 8, 9, 10); + mld_poly_uniform_eta_4x(&s2->vec[4], &s2->vec[5], &s2->vec[6], &s2->vec[7], + seed, 11, 12, 13, 14); +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ +} + +/************************************************* + * Name: mld_compute_t0_t1_tr_from_sk_components + * + * Description: Computes t0, t1, tr, and pk from secret key components + * rho, s1, s2. This is the shared computation used by + * both keygen and generating the public key from the + * secret key. + * + * Arguments: - mld_polyveck *t0: output t0 + * - mld_polyveck *t1: output t1 + * - uint8_t tr[MLDSA_TRBYTES]: output tr + * - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t rho[MLDSA_SEEDBYTES]: input rho + * - const mld_polyvecl *s1: input s1 + * - const mld_polyveck *s2: input s2 + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_t0_t1_tr_from_sk_components( + mld_polyveck *t0, mld_polyveck *t1, uint8_t tr[MLDSA_TRBYTES], + uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], const uint8_t rho[MLDSA_SEEDBYTES], + const mld_polyvecl *s1, const mld_polyveck *s2, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(l0, 0, MLDSA_L, array_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + requires(forall(k0, 0, MLDSA_K, array_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(forall(k1, 0, MLDSA_K, array_bound(t0->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(t1->vec[k2].coeffs, 0, MLDSA_N, 0, 1 << 10))) + ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY)) +{ + int ret; + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1hat, mld_polyvecl, 1, context); + MLD_ALLOC(t, mld_polyveck, 1, context); + + if (mat == NULL || s1hat == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Expand matrix */ + mld_polyvec_matrix_expand(mat, rho); + + /* Matrix-vector multiplication */ + *s1hat = *s1; + mld_polyvecl_ntt(s1hat); + mld_polyvec_matrix_pointwise_montgomery(t, mat, s1hat); + mld_polyveck_invntt_tomont(t); + + /* Add error vector s2 */ + mld_polyveck_add(t, s2); + + /* Reference: The following reduction is not present in the reference + * implementation. Omitting this reduction requires the output of + * the invntt to be small enough such that the addition of s2 does + * not result in absolute values >= MLDSA_Q. While our C, x86_64, + * and AArch64 invntt implementations produce small enough + * values for this to work out, it complicates the bounds + * reasoning. We instead add an additional reduction, and can + * consequently, relax the bounds requirements for the invntt. + */ + mld_polyveck_reduce(t); + + /* Decompose to get t1, t0 */ + mld_polyveck_caddq(t); + mld_polyveck_power2round(t1, t0, t); + + /* Pack public key and compute tr */ + mld_pack_pk(pk, rho, t1); + mld_shake256(tr, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + ret = 0; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_polyveck, 1, context); + MLD_FREE(s1hat, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + const uint8_t *rho, *rhoprime, *key; + MLD_ALLOC(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + MLD_ALLOC(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + + if (seedbuf == NULL || inbuf == NULL || tr == NULL || s1 == NULL || + s2 == NULL || t1 == NULL || t0 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Get randomness for rho, rhoprime and key */ + mld_memcpy(inbuf, seed, MLDSA_SEEDBYTES); + inbuf[MLDSA_SEEDBYTES + 0] = MLDSA_K; + inbuf[MLDSA_SEEDBYTES + 1] = MLDSA_L; + mld_shake256(seedbuf, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, inbuf, + MLDSA_SEEDBYTES + 2); + rho = seedbuf; + rhoprime = rho + MLDSA_SEEDBYTES; + key = rhoprime + MLDSA_CRHBYTES; + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + + /* Sample s1 and s2 */ + mld_sample_s1_s2(s1, s2, rhoprime); + + /* Compute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0, t1, tr, pk, rho, s1, s2, + context); + if (ret != 0) + { + goto cleanup; + } + + /* Pack secret key */ + mld_pack_sk(sk, rho, tr, key, t0, s1, s2); + + /* Constant time: pk is the public key, inherently public data */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_FREE(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + + if (ret != 0) + { + return ret; + } + + /* Pairwise Consistency Test (PCT) @[FIPS140_3_IG, p.87] */ + /* Do this after freeing all temporaries. */ + return mld_check_pct(pk, sk, context); +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t seed[MLDSA_SEEDBYTES]; + int ret; + if (mld_randombytes(seed, MLDSA_SEEDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(seed, sizeof(seed)); + ret = mld_sign_keypair_internal(pk, sk, seed, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed, sizeof(seed)); + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +/************************************************* + * Name: mld_H + * + * Description: Abstracts application of SHAKE256 to + * one, two or three blocks of data, + * yielding a user-requested size of + * output. + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in1: pointer to input block 1 + * Must NOT be NULL + * - size_t in1len: length of input in1 bytes + * - const uint8_t *in2: pointer to input block 2 + * May be NULL if in2len=0, in which case + * this block is ignored + * - size_t in2len: length of input in2 bytes + * - const uint8_t *in3: pointer to input block 3 + * May be NULL if in3len=0, in which case + * this block is ignored + * - size_t in3len: length of input in3 bytes + **************************************************/ +static void mld_H(uint8_t *out, size_t outlen, const uint8_t *in1, + size_t in1len, const uint8_t *in2, size_t in2len, + const uint8_t *in3, size_t in3len) +__contract__( + requires(in1len <= MLD_MAX_BUFFER_SIZE) + requires(in2len <= MLD_MAX_BUFFER_SIZE) + requires(in3len <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in1, in1len)) + requires(in2len == 0 || memory_no_alias(in2, in2len)) + requires(in3len == 0 || memory_no_alias(in3, in3len)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) +{ + mld_shake256ctx state; + mld_shake256_init(&state); + mld_shake256_absorb(&state, in1, in1len); + if (in2len != 0) + { + mld_shake256_absorb(&state, in2, in2len); + } + if (in3len != 0) + { + mld_shake256_absorb(&state, in3, in3len); + } + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(&state, sizeof(state)); +} + +/************************************************* + * Name: mld_compute_pack_z + * + * Description: Computes z = y + s1*c, checks that z has coefficients smaller + * than MLDSA_GAMMA1 - MLDSA_BETA, and packs z into the + * signature buffer. + * + * Arguments: - uint8_t *sig: output signature + * - const mld_poly *cp: challenge polynomial + * - const polyvecl *s1: secret vector s1 + * - const polyvecl *y: masking vector y + * + * Returns: - 0: Success (z has coefficients smaller than + * MLDSA_GAMMA1 - MLDSA_BETA,) + * - MLD_ERR_FAIL: z rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This function is inlined into mld_sign_signature in the + * reference implementation. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_pack_z(uint8_t sig[MLDSA_CRYPTO_BYTES], + const mld_poly *cp, const mld_polyvecl *s1, + const mld_polyvecl *y, mld_poly *z) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(cp, sizeof(mld_poly))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(y, sizeof(mld_polyvecl))) + requires(memory_no_alias(z, sizeof(mld_poly))) + requires(array_abs_bound(cp->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_L, + array_bound(y->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + requires(forall(k1, 0, MLDSA_L, array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(memory_slice(z, sizeof(mld_poly))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int i; + uint32_t z_invalid; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(z, sizeof(mld_poly)), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_poly_pointwise_montgomery(z, cp, &s1->vec[i]); + mld_poly_invntt_tomont(z); + mld_poly_add(z, &y->vec[i]); + mld_poly_reduce(z); + + z_invalid = mld_poly_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA); + /* Constant time: It is fine (and prohibitively expensive to avoid) + * to leak the result of the norm check and which polynomial in z caused a + * rejection. It would even be okay to leak which coefficient led to + * rejection as the candidate signature will be discarded anyway. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(&z_invalid, sizeof(uint32_t)); + if (z_invalid) + { + return MLD_ERR_FAIL; /* reject */ + } + /* If z is valid, then its coefficients are bounded by + * MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below + * to prove the pre-condition of pack_sig_z() */ + mld_assert_abs_bound(z, MLDSA_N, (MLDSA_GAMMA1 - MLDSA_BETA)); + + /* After the norm check, the distribution of each coefficient of z is + * independent of the secret key and it can, hence, be considered + * public. It is, hence, okay to immediately pack it into the user-provided + * signature buffer. */ + mld_pack_sig_z(sig, z, i); + } + return 0; +} + +/* Reference: The reference implementation does not explicitly check the + * maximum nonce value, but instead loops indefinitely (even when the nonce + * would overflow). Internally, sampling of y uses + * (nonceL), (nonceL+1), ... (nonce*L+L-1). + * Hence, there are no overflows if nonce < (UINT16_MAX - L)/L. + * Explicitly checking for this explicitly allows us to prove type-safety. + * Note that FIPS204 explicitly allows an upper-bound this loop of + * 814 (< (UINT16_MAX - L)/L) - see @[FIPS204, Appendix C]. */ +#define MLD_NONCE_UB ((UINT16_MAX - MLDSA_L) / MLDSA_L) + +/************************************************* + * Name: attempt_signature_generation + * + * Description: Attempts to generate a single signature. + * + * Arguments: - uint8_t *sig: pointer to output signature + * - const uint8_t *mu: pointer to message or hash + * of exactly MLDSA_CRHBYTES bytes + * - const uint8_t *rhoprime: pointer to randomness seed + * - uint16_t nonce: current nonce value + * - const mld_polymat *mat: expanded matrix + * - const polyvecl *s1: secret vector s1 + * - const polyveck *s2: secret vector s2 + * - const polyveck *t0: vector t0 + * + * Returns: - 0: Signature generation succeeded + * - MLD_ERR_FAIL: Signature rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This code differs from the reference implementation + * in that it factors out the core signature generation + * step into a distinct function here in order to improve + * efficiency of CBMC proof. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_attempt_signature_generation( + uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *mu, + const uint8_t rhoprime[MLDSA_CRHBYTES], uint16_t nonce, mld_polymat *mat, + const mld_polyvecl *s1, const mld_polyveck *s2, const mld_polyveck *t0, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(rhoprime, MLDSA_CRHBYTES)) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(nonce <= MLD_NONCE_UB) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int n; + uint32_t w0_invalid, h_invalid; + int ret; + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyvecl y; + mld_polyveck h; + } + yh_u; + mld_polyvecl *y; + mld_polyveck *h; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck w1; + mld_polyvecl tmp; + } + w1tmp_u; + mld_polyveck *w1; + mld_polyvecl *tmp; + + MLD_ALLOC(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(yh, yh_u, 1, context); + MLD_ALLOC(z, mld_poly, 1, context); + MLD_ALLOC(w1tmp, w1tmp_u, 1, context); + MLD_ALLOC(w0, mld_polyveck, 1, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(t, mld_poly, 1, context); + + if (challenge_bytes == NULL || yh == NULL || z == NULL || w1tmp == NULL || + w0 == NULL || cp == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + y = &yh->y; + h = &yh->h; + w1 = &w1tmp->w1; + tmp = &w1tmp->tmp; + + /* Sample intermediate vector y */ + mld_polyvecl_uniform_gamma1(y, rhoprime, nonce); + + /* Matrix-vector multiplication */ + *tmp = *y; + mld_polyvecl_ntt(tmp); + mld_polyvec_matrix_pointwise_montgomery(w0, mat, tmp); + mld_polyveck_invntt_tomont(w0); + + /* Decompose w and call the random oracle */ + mld_polyveck_caddq(w0); + mld_polyveck_decompose(w1, w0); + mld_polyveck_pack_w1(sig, w1); + + mld_H(challenge_bytes, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, sig, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + /* Constant time: Leaking challenge_bytes does not reveal any information + * about the secret key as H() is modelled as random oracle. + * This also applies to challenges for rejected signatures. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(challenge_bytes, MLDSA_CTILDEBYTES); + mld_poly_challenge(cp, challenge_bytes); + mld_poly_ntt(cp); + + /* Compute z, reject if it reveals secret */ + ret = mld_compute_pack_z(sig, cp, s1, y, t); + if (ret) + { + goto cleanup; + } + + /* Check that subtracting cs2 does not change high bits of w and low bits + * do not reveal secret information */ + mld_polyveck_pointwise_poly_montgomery(h, cp, s2); + mld_polyveck_invntt_tomont(h); + mld_polyveck_sub(w0, h); + mld_polyveck_reduce(w0); + + w0_invalid = mld_polyveck_chknorm(w0, MLDSA_GAMMA2 - MLDSA_BETA); + /* Constant time: w0_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&w0_invalid, sizeof(uint32_t)); + if (w0_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* Compute hints for w1 */ + mld_polyveck_pointwise_poly_montgomery(h, cp, t0); + mld_polyveck_invntt_tomont(h); + mld_polyveck_reduce(h); + + h_invalid = mld_polyveck_chknorm(h, MLDSA_GAMMA2); + /* Constant time: h_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&h_invalid, sizeof(uint32_t)); + if (h_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + mld_polyveck_add(w0, h); + + /* Constant time: At this point all norm checks have passed and we, hence, + * know that the signature does not leak any secret information. + * Consequently, any value that can be computed from the signature and public + * key is considered public. + * w0 and w1 are public as they can be computed from Az - ct = \alpha w1 + w0. + * h=c*t0 is public as both c and t0 are public. + * For a more detailed discussion, refer to https://eprint.iacr.org/2022/1406. + */ + MLD_CT_TESTING_DECLASSIFY(w0, sizeof(*w0)); + MLD_CT_TESTING_DECLASSIFY(w1, sizeof(*w1)); + n = mld_polyveck_make_hint(h, w0, w1); + if (n > MLDSA_OMEGA) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* All is well - write signature */ + mld_pack_sig_c_h(sig, challenge_bytes, h, n); + /* Constant time: At this point it is clear that the signature is valid - it + * can, hence, be considered public. */ + MLD_CT_TESTING_DECLASSIFY(sig, MLDSA_CRYPTO_BYTES); + ret = 0; /* success */ + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_poly, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(w0, mld_polyveck, 1, context); + MLD_FREE(w1tmp, w1tmp_u, 1, context); + MLD_FREE(z, mld_poly, 1, context); + MLD_FREE(yh, yh_u, 1, context); + MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + + return ret; +} +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + uint8_t *rho, *tr, *key, *mu, *rhoprime; + uint16_t nonce = 0; + MLD_ALLOC(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + + if (seedbuf == NULL || mat == NULL || s1 == NULL || t0 == NULL || s2 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + rho = seedbuf; + tr = rho + MLDSA_SEEDBYTES; + key = tr + MLDSA_TRBYTES; + mu = key + MLDSA_SEEDBYTES; + rhoprime = mu + MLDSA_CRHBYTES; + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + if (!externalmu) + { + /* Compute mu = CRH(tr, pre, msg) */ + mld_H(mu, MLDSA_CRHBYTES, tr, MLDSA_TRBYTES, pre, prelen, m, mlen); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Compute rhoprime = CRH(key, rnd, mu) */ + mld_H(rhoprime, MLDSA_CRHBYTES, key, MLDSA_SEEDBYTES, rnd, MLDSA_RNDBYTES, mu, + MLDSA_CRHBYTES); + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + /* Expand matrix and transform vectors */ + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(s1); + mld_polyveck_ntt(s2); + mld_polyveck_ntt(t0); + + /* By default, return failure. Flip to success and write output + * once signature generation succeeds. */ + ret = MLD_ERR_FAIL; + + /* Reference: This code is re-structured using a while(1), */ + /* with explicit "continue" statements (rather than "goto") */ + /* to implement rejection of invalid signatures. */ + while (1) + __loop__( + assigns(nonce, ret, object_whole(siglen), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(nonce <= MLD_NONCE_UB) + + /* t0, s1, s2, and mat are initialized above and are NOT changed by this */ + /* loop. We can therefore re-assert their bounds here as part of the */ + /* loop invariant. This makes proof noticeably faster with CBMC */ + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + invariant(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(ret == MLD_ERR_FAIL) + ) + { + /* Reference: this code explicitly checks for exhaustion of nonce */ + /* values to provide predictable termination and results in that case */ + /* Checking here also means that incrementing nonce below can also */ + /* be proven to be type-safe. */ + if (nonce == MLD_NONCE_UB) + { + /* Note that ret == MLD_ERR_FAIL by default, so we + * don't need to set it here. */ + break; + } + + ret = mld_attempt_signature_generation(sig, mu, rhoprime, nonce, mat, s1, + s2, t0, context); + nonce++; + if (ret == 0) + { + *siglen = MLDSA_CRYPTO_BYTES; + break; + } + else if (ret != MLD_ERR_FAIL) + { + /* For failures such as out-of-memory, propagate and exit immediately. */ + break; + } + + /* Otherwise, try again. */ + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the signature buffer. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + return ret; +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + size_t pre_len; + int ret; + MLD_ALLOC(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + MLD_ALLOC(rnd, uint8_t, MLDSA_RNDBYTES, context); + + if (pre == NULL || rnd == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Prepare domain separation prefix for pure ML-DSA */ + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, m, mlen, pre, pre_len, rnd, sk, + 0, context); + +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(rnd, uint8_t, MLDSA_RNDBYTES, context); + MLD_FREE(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t rnd[MLDSA_RNDBYTES]; + int ret; + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + *siglen = 0; + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, + rnd, sk, 1, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(rnd, sizeof(rnd)); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + for (i = 0; i < mlen; ++i) + __loop__( + assigns(i, object_whole(sm)) + invariant(i <= mlen) + ) + { + sm[MLDSA_CRYPTO_BYTES + mlen - 1 - i] = m[mlen - 1 - i]; + } + ret = mld_sign_signature(sm, smlen, sm + MLDSA_CRYPTO_BYTES, mlen, ctx, + ctxlen, sk, context); + *smlen += mlen; + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret, cmp; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck t1; + mld_polyveck w1; + } + t1w1_u; + mld_polyveck *t1; + mld_polyveck *w1; + + MLD_ALLOC(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_ALLOC(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(z, mld_polyvecl, 1, context); + MLD_ALLOC(t1w1, t1w1_u, 1, context); + MLD_ALLOC(tmp, mld_polyveck, 1, context); + MLD_ALLOC(h, mld_polyveck, 1, context); + + if (buf == NULL || rho == NULL || mu == NULL || c == NULL || c2 == NULL || + cp == NULL || mat == NULL || z == NULL || t1w1 == NULL || tmp == NULL || + h == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + t1 = &t1w1->t1; + w1 = &t1w1->w1; + + if (siglen != MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + mld_unpack_pk(rho, t1, pk); + + /* mld_unpack_sig and mld_polyvecl_chknorm signal failure through a + * single non-zero error code that's not yet aligned with MLD_ERR_XXX. + * Map it to MLD_ERR_FAIL explicitly. */ + if (mld_unpack_sig(c, z, h, sig)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + if (mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + if (!externalmu) + { + /* Compute CRH(H(rho, t1), pre, msg) */ + MLD_ALIGN uint8_t hpk[MLDSA_CRHBYTES]; + mld_H(hpk, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES, NULL, 0, NULL, + 0); + mld_H(mu, MLDSA_CRHBYTES, hpk, MLDSA_TRBYTES, pre, prelen, m, mlen); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(hpk, sizeof(hpk)); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Matrix-vector multiplication; compute Az - c2^dt1 */ + mld_poly_challenge(cp, c); + mld_poly_ntt(cp); + mld_polyveck_shiftl(t1); + mld_polyveck_ntt(t1); + mld_polyveck_pointwise_poly_montgomery(tmp, cp, t1); + + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(z); + mld_polyvec_matrix_pointwise_montgomery(w1, mat, z); + mld_polyveck_sub(w1, tmp); + mld_polyveck_reduce(w1); + mld_polyveck_invntt_tomont(w1); + + /* Reconstruct w1 */ + mld_polyveck_caddq(w1); + mld_polyveck_use_hint(tmp, w1, h); + mld_polyveck_pack_w1(buf, tmp); + /* Call random oracle and verify challenge */ + mld_H(c2, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, buf, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + + cmp = mld_ct_memcmp(c, c2, MLDSA_CTILDEBYTES); + + /* Declassify the result of the verification. */ + MLD_CT_TESTING_DECLASSIFY(&cmp, sizeof(cmp)); + + ret = cmp == 0 ? 0 : MLD_ERR_FAIL; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(h, mld_polyveck, 1, context); + MLD_FREE(tmp, mld_polyveck, 1, context); + MLD_FREE(t1w1, t1w1_u, 1, context); + MLD_FREE(z, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, m, mlen, pre, pre_len, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + return mld_sign_verify_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, pk, + 1, context); +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + if (smlen < MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + *mlen = smlen - MLDSA_CRYPTO_BYTES; + ret = mld_sign_verify(sm, MLDSA_CRYPTO_BYTES, sm + MLDSA_CRYPTO_BYTES, *mlen, + ctx, ctxlen, pk, context); + if (ret == 0) + { + /* All good, copy msg, return 0 */ + for (i = 0; i < *mlen; ++i) + __loop__( + assigns(i, memory_slice(m, *mlen)) + invariant(i <= *mlen) + ) + { + m[i] = sm[MLDSA_CRYPTO_BYTES + i]; + } + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the message buffer. */ + *mlen = 0; + mld_memset(m, 0, smlen); + } + + return ret; +} + + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_signature_internal(sig, siglen, pre, pre_len, NULL, 0, rnd, sk, + 0, context); +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, pre, pre_len, NULL, 0, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_signature_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, rnd, sk, + MLD_PREHASH_SHAKE_256, context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_verify_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, pk, MLD_PREHASH_SHAKE_256, + context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + + +#define MLD_PRE_HASH_OID_LEN 11 + +/************************************************* + * Name: mld_get_hash_oid + * + * Description: Returns the OID of a given SHA-2/SHA-3 hash function. + * + * Arguments: - uint8_t oid[11]: pointer to output oid + * - int hashalg: hash algorithm constant (MLD_PREHASH_*) + * + ***************************************************/ +static void mld_get_hash_oid(uint8_t oid[MLD_PRE_HASH_OID_LEN], int hashalg) +{ + unsigned int i; + static const struct + { + int alg; + uint8_t oid[MLD_PRE_HASH_OID_LEN]; + } oid_map[] = { + {MLD_PREHASH_SHA2_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}}, + {MLD_PREHASH_SHA2_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}}, + {MLD_PREHASH_SHA2_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}}, + {MLD_PREHASH_SHA2_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}}, + {MLD_PREHASH_SHA2_512_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05}}, + {MLD_PREHASH_SHA2_512_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06}}, + {MLD_PREHASH_SHA3_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07}}, + {MLD_PREHASH_SHA3_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08}}, + {MLD_PREHASH_SHA3_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09}}, + {MLD_PREHASH_SHA3_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A}}, + {MLD_PREHASH_SHAKE_128, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B}}, + {MLD_PREHASH_SHAKE_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C}}}; + + for (i = 0; i < sizeof(oid_map) / sizeof(oid_map[0]); i++) + __loop__( + invariant(i <= sizeof(oid_map) / sizeof(oid_map[0])) + ) + { + if (oid_map[i].alg == hashalg) + { + mld_memcpy(oid, oid_map[i].oid, MLD_PRE_HASH_OID_LEN); + return; + } + } +} + +static int mld_validate_hash_length(int hashalg, size_t len) +{ + switch (hashalg) + { + case MLD_PREHASH_SHA2_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_128: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_256: + return (len == 512 / 8) ? 0 : -1; + } + return -1; +} + +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +{ + if (ctxlen > 255) + { + return 0; + } + + if (hashalg != MLD_PREHASH_NONE) + { + if (ph == NULL || mld_validate_hash_length(hashalg, phlen) != 0) + { + return 0; + } + } + + /* Common prefix: 0x00/0x01 || ctxlen || ctx */ + prefix[0] = (hashalg == MLD_PREHASH_NONE) ? 0 : 1; + prefix[1] = (uint8_t)ctxlen; + if (ctxlen > 0) + { + mld_memcpy(prefix + 2, ctx, ctxlen); + } + + if (hashalg == MLD_PREHASH_NONE) + { + return 2 + ctxlen; + } + + /* HashML-DSA: append oid || ph */ + mld_get_hash_oid(prefix + 2 + ctxlen, hashalg); + mld_memcpy(prefix + 2 + ctxlen + MLD_PRE_HASH_OID_LEN, ph, phlen); + return 2 + ctxlen + MLD_PRE_HASH_OID_LEN + phlen; +} + +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + uint8_t check, cmp0, cmp1, chk1, chk2; + int ret; + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(t0_computed, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + + if (rho == NULL || tr == NULL || tr_computed == NULL || key == NULL || + s1 == NULL || s2 == NULL || t0 == NULL || t0_computed == NULL || + t1 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Unpack secret key */ + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + /* Validate s1 and s2 coefficients are within [-MLDSA_ETA, MLDSA_ETA] */ + chk1 = mld_polyvecl_chknorm(s1, MLDSA_ETA + 1) & 0xFF; + chk2 = mld_polyveck_chknorm(s2, MLDSA_ETA + 1) & 0xFF; + + /* Recompute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0_computed, t1, tr_computed, + pk, rho, s1, s2, context); + if (ret != 0) + { + goto cleanup; + } + + /* Validate t0 and tr using constant-time comparisons */ + cmp0 = mld_ct_memcmp((const uint8_t *)t0, (const uint8_t *)t0_computed, + sizeof(mld_polyveck)); + cmp1 = mld_ct_memcmp((const uint8_t *)tr, (const uint8_t *)tr_computed, + MLDSA_TRBYTES); + check = mld_value_barrier_u8(cmp0 | cmp1 | chk1 | chk2); + + /* Declassify the final result of the validity check. */ + MLD_CT_TESTING_DECLASSIFY(&check, sizeof(check)); + ret = (check != 0) ? MLD_ERR_FAIL : 0; + +cleanup: + + if (ret != 0) + { + mld_zeroize(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + } + + /* Constant time: pk is either the valid public key or zeroed on error */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(t0_computed, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + + return ret; +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_check_pct +#undef mld_sample_s1_s2 +#undef mld_validate_hash_length +#undef mld_get_hash_oid +#undef mld_H +#undef mld_compute_pack_z +#undef mld_attempt_signature_generation +#undef mld_compute_t0_t1_tr_from_sk_components +#undef MLD_NONCE_UB +#undef MLD_PRE_HASH_OID_LEN diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/sign.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/sign.h new file mode 100644 index 0000000000..2e0bac32ea --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/sign.h @@ -0,0 +1,807 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_SIGN_H +#define MLD_SIGN_H + +#include +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "polyvec.h" +#include "sys.h" + +#if defined(MLD_CHECK_APIS) +/* Include to ensure consistency between internal sign.h + * and external mldsa_native.h. */ +#include "mldsa_native.h" + +#if MLDSA_CRYPTO_SECRETKEYBYTES != \ + MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for SECRETKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_PUBLICKEYBYTES != \ + MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for PUBLICKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_BYTES != MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for CRYPTO_BYTES between sign.h and mldsa_native.h +#endif + +#endif /* MLD_CHECK_APIS */ + +#define mld_sign_keypair_internal \ + MLD_NAMESPACE_KL(keypair_internal) MLD_CONTEXT_PARAMETERS_3 +#define mld_sign_keypair MLD_NAMESPACE_KL(keypair) MLD_CONTEXT_PARAMETERS_2 +#define mld_sign_signature_internal \ + MLD_NAMESPACE_KL(signature_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_signature MLD_NAMESPACE_KL(signature) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_extmu \ + MLD_NAMESPACE_KL(signature_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign MLD_NAMESPACE_KL(sign) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_internal \ + MLD_NAMESPACE_KL(verify_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify MLD_NAMESPACE_KL(verify) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_extmu \ + MLD_NAMESPACE_KL(verify_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign_open MLD_NAMESPACE_KL(open) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_pre_hash_internal \ + MLD_NAMESPACE_KL(signature_pre_hash_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_verify_pre_hash_internal \ + MLD_NAMESPACE_KL(verify_pre_hash_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_signature_pre_hash_shake256 \ + MLD_NAMESPACE_KL(signature_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify_pre_hash_shake256 \ + MLD_NAMESPACE_KL(verify_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_7 +#define mld_prepare_domain_separation_prefix \ + MLD_NAMESPACE_KL(prepare_domain_separation_prefix) +#define mld_sign_pk_from_sk \ + MLD_NAMESPACE_KL(pk_from_sk) MLD_CONTEXT_PARAMETERS_2 + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: mld_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: input random seed + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int externalmu: indicates input message m is + * processed as mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return MLD_ERR_FAIL in that case. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires((externalmu == 0 && (prelen == 0 || memory_no_alias(pre, prelen))) || + (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) + ensures(return_value == 0 ==> *siglen == MLDSA_CRYPTO_BYTES) + ensures(return_value != 0 ==> *siglen == 0) +); + +/************************************************* + * Name: mld_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_signature_extmu + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign + * + * Description: Compute signed message. + * + * Arguments: - uint8_t *sm: pointer to output signed message + * (allocated array with MLDSA_CRYPTO_BYTES + + *mlen bytes), can be equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sm, MLDSA_CRYPTO_BYTES + mlen)) + requires(memory_no_alias(smlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sm, MLDSA_CRYPTO_BYTES + mlen)) + assigns(object_whole(smlen)) + ensures((return_value == 0 && *smlen == MLDSA_CRYPTO_BYTES + mlen) || + (return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL)) +); + +/************************************************* + * Name: mld_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as + * mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(externalmu == 0 || (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + requires(externalmu == 1 || prelen == 0 || memory_no_alias(pre, prelen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_open + * + * Description: Verify signed message. + * + * Arguments: - uint8_t *m: pointer to output message (allocated array + * with smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context tring + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(smlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(m, smlen)) + requires(memory_no_alias(mlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(sm, smlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + assigns(memory_slice(m, smlen)) + assigns(memory_slice(mlen, sizeof(size_t))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and + * verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/* Maximum formatted domain separation message length: + * - Pure ML-DSA: 0x00 || ctxlen || ctx (max 255) + * - HashML-DSA: 0x01 || ctxlen || ctx (max 255) || oid (11) || ph (max 64) */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +__contract__( + requires(ctxlen <= 255) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(hashalg == MLD_PREHASH_NONE || memory_no_alias(ph, phlen)) + requires(memory_no_alias(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + assigns(memory_slice(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + ensures(return_value <= MLD_DOMAIN_SEPARATION_MAX_BYTES) +); + +/************************************************* + * Name: mld_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: input secret + * key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); +#endif /* !MLD_SIGN_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/symmetric.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/symmetric.h new file mode 100644 index 0000000000..bb70f05552 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/symmetric.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_SYMMETRIC_H +#define MLD_SYMMETRIC_H + +#include +#include "cbmc.h" +#include "common.h" + +#include MLD_FIPS202_HEADER_FILE +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#include MLD_FIPS202X4_HEADER_FILE +#endif + +#define MLD_STREAM128_BLOCKBYTES SHAKE128_RATE +#define MLD_STREAM256_BLOCKBYTES SHAKE256_RATE + +#define mld_xof256_ctx mld_shake256ctx +#define mld_xof256_init(CTX) mld_shake256_init(CTX) + +#define mld_xof256_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake256_absorb(CTX, IN, INBYTES); \ + mld_shake256_finalize(CTX); \ + } while (0) + + +#define mld_xof256_release(CTX) mld_shake256_release(CTX) +#define mld_xof256_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake256_squeeze(OUT, (OUTBLOCKS) * SHAKE256_RATE, STATE) + +#define mld_xof128_ctx mld_shake128ctx +#define mld_xof128_init(CTX) mld_shake128_init(CTX) + +#define mld_xof128_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake128_absorb(CTX, IN, INBYTES); \ + mld_shake128_finalize(CTX); \ + } while (0) + +#define mld_xof128_release(CTX) mld_shake128_release(CTX) +#define mld_xof128_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake128_squeeze(OUT, (OUTBLOCKS) * SHAKE128_RATE, STATE) + +#define mld_xof256_x4_ctx mld_shake256x4ctx +#define mld_xof256_x4_init(CTX) mld_shake256x4_init((CTX)) +#define mld_xof256_x4_absorb(CTX, IN, INBYTES) \ + mld_shake256x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof256_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake256x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof256_x4_release(CTX) mld_shake256x4_release((CTX)) + +#define mld_xof128_x4_ctx mld_shake128x4ctx +#define mld_xof128_x4_init(CTX) mld_shake128x4_init((CTX)) +#define mld_xof128_x4_absorb(CTX, IN, INBYTES) \ + mld_shake128x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof128_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake128x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof128_x4_release(CTX) mld_shake128x4_release((CTX)) + +#endif /* !MLD_SYMMETRIC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/sys.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/sys.h new file mode 100644 index 0000000000..1226526420 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/sys.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_SYS_H +#define MLD_SYS_H + +#if !defined(MLD_CONFIG_NO_ASM) && (defined(__GNUC__) || defined(__clang__)) +#define MLD_HAVE_INLINE_ASM +#endif + +/* Try to find endianness, if not forced through CFLAGS already */ +#if !defined(MLD_SYS_LITTLE_ENDIAN) && !defined(MLD_SYS_BIG_ENDIAN) +#if defined(__BYTE_ORDER__) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define MLD_SYS_LITTLE_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define MLD_SYS_BIG_ENDIAN +#else +#error "__BYTE_ORDER__ defined, but don't recognize value." +#endif +#endif /* __BYTE_ORDER__ */ + +/* MSVC does not define __BYTE_ORDER__. However, MSVC only supports + * little endian x86, x86_64, and AArch64. It is, hence, safe to assume + * little endian. */ +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_IX86) || defined(_M_ARM64)) +#define MLD_SYS_LITTLE_ENDIAN +#endif + +#endif /* !MLD_SYS_LITTLE_ENDIAN && !MLD_SYS_BIG_ENDIAN */ + +/* Check if we're running on an AArch64 little endian system. _M_ARM64 is set by + * MSVC. */ +#if defined(__AARCH64EL__) || defined(_M_ARM64) +#define MLD_SYS_AARCH64 +#endif + +/* Check if we're running on an AArch64 big endian system. */ +#if defined(__AARCH64EB__) +#define MLD_SYS_AARCH64_EB +#endif + +#if defined(__x86_64__) +#define MLD_SYS_X86_64 +#if defined(__AVX2__) +#define MLD_SYS_X86_64_AVX2 +#endif +#endif /* __x86_64__ */ + +#if defined(MLD_SYS_LITTLE_ENDIAN) && defined(__powerpc64__) +#define MLD_SYS_PPC64LE +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 +#define MLD_SYS_RISCV64 +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32 +#define MLD_SYS_RISCV32 +#endif + +#if defined(_WIN64) || defined(_WIN32) +#define MLD_SYS_WINDOWS +#endif + +#if defined(__linux__) +#define MLD_SYS_LINUX +#endif + +#if defined(__APPLE__) +#define MLD_SYS_APPLE +#endif + +/* If MLD_FORCE_AARCH64 is set, assert that we're indeed on an AArch64 system. + */ +#if defined(MLD_FORCE_AARCH64) && !defined(MLD_SYS_AARCH64) +#error "MLD_FORCE_AARCH64 is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_AARCH64_EB is set, assert that we're indeed on a big endian + * AArch64 system. */ +#if defined(MLD_FORCE_AARCH64_EB) && !defined(MLD_SYS_AARCH64_EB) +#error \ + "MLD_FORCE_AARCH64_EB is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_X86_64 is set, assert that we're indeed on an X86_64 system. */ +#if defined(MLD_FORCE_X86_64) && !defined(MLD_SYS_X86_64) +#error "MLD_FORCE_X86_64 is set, but we don't seem to be on an X86_64 system." +#endif + +#if defined(MLD_FORCE_PPC64LE) && !defined(MLD_SYS_PPC64LE) +#error "MLD_FORCE_PPC64LE is set, but we don't seem to be on a PPC64LE system." +#endif + +#if defined(MLD_FORCE_RISCV64) && !defined(MLD_SYS_RISCV64) +#error "MLD_FORCE_RISCV64 is set, but we don't seem to be on a RISCV64 system." +#endif + +#if defined(MLD_FORCE_RISCV32) && !defined(MLD_SYS_RISCV32) +#error "MLD_FORCE_RISCV32 is set, but we don't seem to be on a RISCV32 system." +#endif + +/* + * MLD_INLINE: Hint for inlining. + * - MSVC: __inline + * - C99+: inline + * - GCC/Clang C90: __attribute__((unused)) to silence warnings + * - Other C90: empty + */ +#if !defined(MLD_INLINE) +#if defined(_MSC_VER) +#define MLD_INLINE __inline +#elif defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +#define MLD_INLINE inline +#elif defined(__GNUC__) || defined(__clang__) +#define MLD_INLINE __attribute__((unused)) +#else +#define MLD_INLINE +#endif +#endif /* !MLD_INLINE */ + +/* + * MLD_ALWAYS_INLINE: Force inlining. + * - MSVC: __forceinline + * - GCC/Clang C99+: MLD_INLINE __attribute__((always_inline)) + * - Other: MLD_INLINE (no forced inlining) + */ +#if !defined(MLD_ALWAYS_INLINE) +#if defined(_MSC_VER) +#define MLD_ALWAYS_INLINE __forceinline +#elif (defined(__GNUC__) || defined(__clang__)) && \ + (defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)) +#define MLD_ALWAYS_INLINE MLD_INLINE __attribute__((always_inline)) +#else +#define MLD_ALWAYS_INLINE MLD_INLINE +#endif +#endif /* !MLD_ALWAYS_INLINE */ + +#ifndef MLD_STATIC_TESTABLE +#define MLD_STATIC_TESTABLE static +#endif + +/* + * C90 does not have the restrict compiler directive yet. + * We don't use it in C90 builds. + */ +#if !defined(restrict) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define MLD_RESTRICT restrict +#else +#define MLD_RESTRICT +#endif + +#else /* !restrict */ + +#define MLD_RESTRICT restrict +#endif /* restrict */ + +#define MLD_DEFAULT_ALIGN 32 +#define MLD_ALIGN_UP(N) \ + ((((N) + (MLD_DEFAULT_ALIGN - 1)) / MLD_DEFAULT_ALIGN) * MLD_DEFAULT_ALIGN) +#if defined(__GNUC__) +#define MLD_ALIGN __attribute__((aligned(MLD_DEFAULT_ALIGN))) +#elif defined(_MSC_VER) +#define MLD_ALIGN __declspec(align(MLD_DEFAULT_ALIGN)) +#else +#define MLD_ALIGN /* No known support for alignment constraints */ +#endif + + +/* New X86_64 CPUs support Conflow-flow protection using the CET instructions. + * When enabled (through -fcf-protection=), all compilation units (including + * empty ones) need to support CET for this to work. + * For assembly, this means that source files need to signal support for + * CET by setting the appropriate note.gnu.property section. + * This can be achieved by including the header in all assembly file. + * This file also provides the _CET_ENDBR macro which needs to be placed at + * every potential target of an indirect branch. + * If CET is enabled _CET_ENDBR maps to the endbr64 instruction, otherwise + * it is empty. + * In case the compiler does not support CET (e.g., +#define MLD_CET_ENDBR _CET_ENDBR +#else +#define MLD_CET_ENDBR +#endif +#endif /* MLD_SYS_X86_64 */ + +#if defined(MLD_CONFIG_CT_TESTING_ENABLED) && !defined(__ASSEMBLER__) +#include +#define MLD_CT_TESTING_SECRET(ptr, len) \ + VALGRIND_MAKE_MEM_UNDEFINED((ptr), (len)) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) +#else /* MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__ */ +#define MLD_CT_TESTING_SECRET(ptr, len) \ + do \ + { \ + } while (0) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + do \ + { \ + } while (0) +#endif /* !(MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__) */ + +#if defined(__GNUC__) || defined(__clang__) +#define MLD_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_MUST_CHECK_RETURN_VALUE +#endif + + +#if !defined(__ASSEMBLER__) +/* System capability enumeration */ +typedef enum +{ + /* x86_64 */ + MLD_SYS_CAP_AVX2, + /* AArch64 */ + MLD_SYS_CAP_SHA3 +} mld_sys_cap; + +#if !defined(MLD_CONFIG_CUSTOM_CAPABILITY_FUNC) +#include "cbmc.h" + +static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) +__contract__( + ensures(return_value == 0 || return_value == 1) +) +{ + /* By default, we rely on compile-time feature detection/specification: + * If a feature is enabled at compile-time, we assume it is supported by + * the host that the resulting library/binary will be built on. + * If this assumption is not true, you MUST overwrite this function. + * See the documentation of MLD_CONFIG_CUSTOM_CAPABILITY_FUNC in + * mldsa_native_config.h for more information. */ + (void)cap; + return 1; +} +#endif /* !MLD_CONFIG_CUSTOM_CAPABILITY_FUNC */ +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_SYS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/zetas.inc b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/zetas.inc new file mode 100644 index 0000000000..dc3cf15dd3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/mldsa_native/src/zetas.inc @@ -0,0 +1,56 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include + +/* + * Table of zeta values used in the reference NTT and inverse NTT. + * See autogen for details. + */ +static const int32_t mld_zetas[MLDSA_N] = { + 0, 25847, -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 2353451, -359251, -2091905, 3119733, -2884855, + 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488, + -1119584, 2619752, -2108549, -2118186, -3859737, -1399561, -3277672, + 1757237, -19422, 4010497, 280005, 2706023, 95776, 3077325, + 3530437, -1661693, -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267, + -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596, + 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, + -2797779, -3930395, -1528703, -3677745, -3041255, -1452451, 3475950, + 2176455, -1585221, -1257611, 1939314, -4083598, -1000202, -3190144, + -3157330, -3632928, 126922, 3412210, -983419, 2147896, 2715295, + -2967645, -3693493, -411027, -2477047, -671102, -1228525, -22981, + -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944, + 508951, 3097992, 44288, -1100098, 904516, 3958618, -3724342, + -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856, + 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, + 1341330, 1285669, -1584928, -812732, -1439742, -3019102, -3881060, + -3628969, 3839961, 2091667, 3407706, 2316500, 3817976, -3342478, + 2244091, -2446433, -3562462, 266997, 2434439, -1235728, 3513181, + -3520352, -3759364, -1197226, -3193378, 900702, 1859098, 909542, + 819034, 495491, -1613174, -43260, -522500, -655327, -3122442, + 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297, + 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, + 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, + 1595974, -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, + 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100, + 1312455, 3306115, -1962642, -1279661, 1917081, -2546312, -1374803, + 1500165, 777191, 2235880, 3406031, -542412, -2831860, -1671176, + -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395, + 2454455, -164721, 1957272, 3369112, 185531, -1207385, -3183426, + 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, + -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, + 472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333, + -260646, -3833893, -2939036, -2235985, -420899, -2286327, 183443, + -976891, 1612842, -3545687, -554416, 3919660, -48306, -1362209, + 3937738, 1400424, -846154, 1976782, +}; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/test_only_rng/notrandombytes.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/test_only_rng/notrandombytes.c new file mode 100644 index 0000000000..ef5a423a9e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/test_only_rng/notrandombytes.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* * Based on @[surf]*/ + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +#include +#include + +#include "notrandombytes.h" + +#ifdef ENABLE_CT_TESTING +#include +#endif + +static uint32_t seed[32] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, + 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5}; +static uint32_t in[12]; +static uint32_t out[8]; +static int32_t outleft = 0; + +void randombytes_reset(void) +{ + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + outleft = 0; +} + +#define ROTATE(x, b) (((x) << (b)) | ((x) >> (32 - (b)))) +#define MUSH(i, b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x, b)); + +static void surf(void) +{ + uint32_t t[12]; + uint32_t x; + uint32_t sum = 0; + int32_t r; + int32_t i; + int32_t loop; + + for (i = 0; i < 12; ++i) + { + t[i] = in[i] ^ seed[12 + i]; + } + for (i = 0; i < 8; ++i) + { + out[i] = seed[24 + i]; + } + x = t[11]; + for (loop = 0; loop < 2; ++loop) + { + for (r = 0; r < 16; ++r) + { + sum += 0x9e3779b9; + MUSH(0, 5) + MUSH(1, 7) + MUSH(2, 9) + MUSH(3, 13) + MUSH(4, 5) + MUSH(5, 7) + MUSH(6, 9) + MUSH(7, 13) + MUSH(8, 5) + MUSH(9, 7) + MUSH(10, 9) + MUSH(11, 13) + } + for (i = 0; i < 8; ++i) + { + out[i] ^= t[i + 4]; + } + } +} + +int randombytes(uint8_t *buf, size_t n) +{ +#ifdef ENABLE_CT_TESTING + uint8_t *buf_orig = buf; + size_t n_orig = n; +#endif + + while (n > 0) + { + if (!outleft) + { + if (!++in[0]) + { + if (!++in[1]) + { + if (!++in[2]) + { + ++in[3]; + } + } + } + surf(); + outleft = 8; + } + *buf = (uint8_t)out[--outleft]; + ++buf; + --n; + } + +#ifdef ENABLE_CT_TESTING + /* + * Mark all randombytes output as secret (undefined). + * Valgrind will propagate this to everything derived from it. + */ + VALGRIND_MAKE_MEM_UNDEFINED(buf_orig, n_orig); +#endif /* ENABLE_CT_TESTING */ + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/test_only_rng/notrandombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/test_only_rng/notrandombytes.h new file mode 100644 index 0000000000..bdf9787920 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic/test_only_rng/notrandombytes.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* Based on @[surf]. */ + +#ifndef NOTRANDOMBYTES_H +#define NOTRANDOMBYTES_H + +#include +#include + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +void randombytes_reset(void); +int randombytes(uint8_t *buf, size_t n); + +#endif /* !NOTRANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/.gitignore b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/.gitignore new file mode 100644 index 0000000000..eb98a94f12 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +build diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/Makefile new file mode 100644 index 0000000000..ad4576e9e9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/Makefile @@ -0,0 +1,100 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +.PHONY: build run clean +.DEFAULT_GOAL := all + +CC ?= gcc + +# Adjust CFLAGS if needed +CFLAGS := \ + -Wall \ + -Wextra \ + -Werror=unused-result \ + -Wpedantic \ + -Werror \ + -Wmissing-prototypes \ + -Wshadow \ + -Wpointer-arith \ + -Wredundant-decls \ + -Wconversion \ + -Wsign-conversion \ + -Wno-long-long \ + -Wno-unknown-pragmas \ + -Wno-unused-command-line-argument \ + -O3 \ + -fomit-frame-pointer \ + -std=c99 \ + -pedantic \ + -MMD \ + $(CFLAGS) + +# If you want to use the native backends, the compiler needs to know about +# the target architecture. Here, we import the default host detection from +# mldsa-native's tests, but you can write your own or specialize accordingly. +AUTO ?= 1 +include auto.mk + +# The following only concerns the cross-compilation tests. +# You can likely ignore the following for your application. +# +# Append cross-prefix for cross compilation +# When called from the root Makefile, CROSS_PREFIX has already been added here +ifeq (,$(findstring $(CROSS_PREFIX),$(CC))) +CC := $(CROSS_PREFIX)$(CC) +endif + +# Part A: +# +# mldsa-native source and header files +# +# If you are not concerned about minimizing for a specific backend, +# you can just include _all_ source files into your build. +# +# In this example, we compile the individual mldsa-native source files directly. +# Alternatively, you can compile the 'monobuild' source file mldsa_native.c. +# See examples/monolithic_build for that. +MLD_SOURCE=$(wildcard \ + mldsa_native/src/*.c \ + mldsa_native/src/**/*.c \ + mldsa_native/src/**/**/*.c \ + mldsa_native/src/**/**/**/*.c) + +INC=-Imldsa_native + +# Part B: +# +# Your application source code +APP_SOURCE=$(wildcard *.c) + +ALL_SOURCE=$(MLD_SOURCE) $(APP_SOURCE) + +BUILD_DIR=build +BIN=test_binary + +BINARY_NAME_FULL_44=$(BUILD_DIR)/$(BIN)44 +BINARY_NAME_FULL_65=$(BUILD_DIR)/$(BIN)65 +BINARY_NAME_FULL_87=$(BUILD_DIR)/$(BIN)87 +BINARIES_FULL=$(BINARY_NAME_FULL_44) $(BINARY_NAME_FULL_65) $(BINARY_NAME_FULL_87) + +$(BINARY_NAME_FULL_44): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=44 +$(BINARY_NAME_FULL_65): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=65 +$(BINARY_NAME_FULL_87): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=87 + +$(BINARIES_FULL): $(ALL_SOURCE) + echo "$@" + mkdir -p $(BUILD_DIR) + $(CC) $(CFLAGS) $(INC) $^ -o $@ + +all: build + +build: $(BINARIES_FULL) + +run: $(BINARIES_FULL) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_44) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_65) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_87) + +clean: + rm -rf $(BUILD_DIR) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/README.md new file mode 100644 index 0000000000..e5ac1135e9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/README.md @@ -0,0 +1,36 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + + +This directory contains a minimal example for building mldsa-native using only the deterministic API, +without requiring a `randombytes()` implementation. + +## Use Case + +Use this approach when: +- Your application manages its own entropy/randomness externally +- You only need `crypto_sign_keypair_internal` and `crypto_sign_signature_internal` (deterministic variants) + +## Components + +1. mldsa-native source tree: [`mldsa/src/`](../../mldsa/src) and [`mldsa/src/fips202/`](../../mldsa/src/fips202) +2. Your application source code + +No `randombytes()` implementation is required. + +## Configuration + +The configuration file [mldsa_native_config.h](mldsa_native/mldsa_native_config.h) sets: +- `MLD_CONFIG_NO_RANDOMIZED_API`: Disables `crypto_sign_keypair`, `crypto_sign_signature`, etc. +- `MLD_CONFIG_PARAMETER_SET`: Security level (default 65) +- `MLD_CONFIG_NAMESPACE_PREFIX`: Symbol prefix (set to `mldsa`) + +## Notes + +- This is incompatible with `MLD_CONFIG_KEYGEN_PCT` (pairwise consistency test) + +## Usage + +```bash +make build # Build the example +make run # Run the example +``` diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/auto.mk b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/auto.mk new file mode 100644 index 0000000000..5f71942085 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/auto.mk @@ -0,0 +1,178 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# Automatically detect system architecture and set preprocessor flags accordingly +# This file detects host CPU capabilities and combines them with compiler support +# to enable optimal compilation flags. +# +# Compiler feature detection can be overridden by setting the corresponding variable +# on the command line: +# make MK_COMPILER_SUPPORTS_SHA3=0 # Disable SHA3 detection +# make MK_COMPILER_SUPPORTS_AVX2=0 # Disable AVX2 detection +# make MK_COMPILER_SUPPORTS_BMI2=0 # Disable BMI2 detection +# make MK_COMPILER_SUPPORTS_SSE2=0 # Disable SSE2 detection + +ifndef _AUTO_MK +_AUTO_MK := + +# Override ARCH for cross-compilation based on CROSS_PREFIX +ifeq ($(CROSS_PREFIX),) +ARCH := $(shell uname -m) +# Normalize architecture names +ifeq ($(ARCH),arm64) +ARCH := aarch64 +endif +else # CROSS_PREFIX +ifneq ($(findstring x86_64, $(CROSS_PREFIX)),) +ARCH := x86_64 +else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),) +ARCH := aarch64_be +else ifneq ($(findstring aarch64, $(CROSS_PREFIX)),) +ARCH := aarch64 +else ifneq ($(findstring riscv64, $(CROSS_PREFIX)),) +ARCH := riscv64 +else ifneq ($(findstring riscv32, $(CROSS_PREFIX)),) +ARCH := riscv32 +else ifneq ($(findstring powerpc64le, $(CROSS_PREFIX)),) +ARCH := powerpc64le +else ifneq ($(findstring arm-none-eabi-, $(CROSS_PREFIX)),) +ARCH := arm +else +ifeq ($(AUTO),1) +$(warning Unknown cross-compilation prefix $(CROSS_PREFIX), no automatic detection of CFLAGS.) +ARCH := unknown +endif +endif +endif # CROSS_PREFIX + +# x86_64 compiler feature detection +ifeq ($(ARCH),x86_64) + +# Test AVX2 support using C with inline assembly +MK_COMPILER_SUPPORTS_AVX2 ?= $(shell echo 'int main() { __asm__("vpxor %%ymm0, %%ymm1, %%ymm2" ::: "ymm0", "ymm1", "ymm2"); return 0; }' | $(CC) -mavx2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test SSE2 support using C with inline assembly +MK_COMPILER_SUPPORTS_SSE2 ?= $(shell echo 'int main() { __asm__("pxor %%xmm0, %%xmm1" ::: "xmm0", "xmm1"); return 0; }' | $(CC) -msse2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test BMI2 support using C with inline assembly +MK_COMPILER_SUPPORTS_BMI2 ?= $(shell echo 'int main() { __asm__("pdep %%eax, %%ebx, %%ecx" ::: "eax", "ebx", "ecx"); return 0; }' | $(CC) -mbmi2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # x86_64 compiler detection + +# AArch64 compiler feature detection +ifeq ($(ARCH),aarch64) + +# Test SHA3 support (Armv8.4-a+SHA3) using C with inline assembly +MK_COMPILER_SUPPORTS_SHA3 ?= $(shell echo 'int main() { __asm__("eor3 v0.16b, v1.16b, v2.16b, v3.16b" ::: "v0", "v1", "v2", "v3"); return 0; }' | $(CC) -march=armv8.4-a+sha3 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # aarch64 compiler detection + +# Define HOST_PLATFORM if not already defined +HOST_PLATFORM ?= $(shell uname -s)-$(shell uname -m) + +# Helper function to check if host CPU supports a feature +# Usage: $(call check_host_feature,feature_pattern,source_command) +define check_host_feature +$(shell $(2) 2>/dev/null | grep -q "$(1)" && echo 1 || echo 0) +endef + +# x86_64 architecture detection +ifeq ($(ARCH),x86_64) + +# Host CPU feature detection for x86_64 +ifeq ($(HOST_PLATFORM),Linux-x86_64) +# Linux: Use /proc/cpuinfo +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,avx2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,sse2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,bmi2,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-x86_64) +# macOS: Use sysctl +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,AVX2,sysctl -n machdep.cpu.leaf7_features) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,SSE2,sysctl -n machdep.cpu.features) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,BMI2,sysctl -n machdep.cpu.leaf7_features) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_AVX2 := 1 +MK_HOST_SUPPORTS_SSE2 := 1 +MK_HOST_SUPPORTS_BMI2 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_AVX2 := 0 +MK_HOST_SUPPORTS_SSE2 := 0 +MK_HOST_SUPPORTS_BMI2 := 0 +endif # HOST_PLATFORM x86_64 + +endif # x86_64 + +# AArch64 architecture detection +ifeq ($(ARCH),aarch64) + +# Host CPU feature detection for AArch64 +ifeq ($(HOST_PLATFORM),Linux-aarch64) +# Linux: Use /proc/cpuinfo (look for sha3 in Features line) +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,sha3,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-arm64) +# macOS: Use sysctl to check for SHA3 support +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,1,sysctl -n hw.optional.armv8_2_sha3) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_SHA3 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_SHA3 := 0 +endif # HOST_PLATFORM aarch64 + +endif # aarch64 + +# Only apply CFLAGS modifications if AUTO=1 +ifeq ($(AUTO),1) + +# x86_64 CFLAGS configuration +ifeq ($(ARCH),x86_64) +CFLAGS += -DMLD_FORCE_X86_64 + +# Add flags only if both compiler and host support the feature +ifeq ($(MK_COMPILER_SUPPORTS_AVX2)$(MK_HOST_SUPPORTS_AVX2),11) +CFLAGS += -mavx2 +endif + +ifeq ($(MK_COMPILER_SUPPORTS_BMI2)$(MK_HOST_SUPPORTS_BMI2),11) +CFLAGS += -mbmi2 +endif +endif # x86_64 + +# AArch64 CFLAGS configuration +ifeq ($(ARCH),aarch64) +CFLAGS += -DMLD_FORCE_AARCH64 + +# Add SHA3 flags only if both compiler and host support it +ifeq ($(MK_COMPILER_SUPPORTS_SHA3)$(MK_HOST_SUPPORTS_SHA3),11) +CFLAGS += -march=armv8.4-a+sha3 +endif +endif # aarch64 + +# AArch64 Big Endian CFLAGS configuration +ifeq ($(ARCH),aarch64_be) +CFLAGS += -DMLD_FORCE_AARCH64_EB +endif # aarch64_be + +# RISC-V 64-bit CFLAGS configuration +ifeq ($(ARCH),riscv64) +CFLAGS += -DMLD_FORCE_RISCV64 +CFLAGS += -march=rv64gcv +endif # riscv64 + +# RISC-V 32-bit CFLAGS configuration +ifeq ($(ARCH),riscv32) +CFLAGS += -DMLD_FORCE_RISCV32 +endif # riscv32 + +# PowerPC 64-bit Little Endian CFLAGS configuration +ifeq ($(ARCH),powerpc64le) +CFLAGS += -DMLD_FORCE_PPC64LE +endif # powerpc64le + +endif # AUTO=1 + +endif # _AUTO_MK diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/expected_signatures.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/expected_signatures.h new file mode 100644 index 0000000000..d52fbe8d5e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/expected_signatures.h @@ -0,0 +1,890 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef EXPECTED_SIGNATURES_H +#define EXPECTED_SIGNATURES_H + +#include + +/* Expected deterministic signatures for each parameter set + * These are generated using the same test message, context, and deterministic + * RNG as used in the basic example. + * + * The PCT modifies the PRNG state, so the KAT tests don't work. + * We run KAT tests only for disabled PCT. */ +#if !defined(MLD_CONFIG_KEYGEN_PCT) +#if MLD_CONFIG_PARAMETER_SET == 44 +const uint8_t expected_signature[] = { + 0x27, 0x5e, 0xbe, 0x2d, 0x23, 0x1a, 0x76, 0xc5, 0xd9, 0x77, 0xcb, 0x62, + 0x25, 0x04, 0xdb, 0x23, 0x31, 0xa9, 0xa8, 0xcd, 0xbc, 0xde, 0xf2, 0x20, + 0xfd, 0xa7, 0xb5, 0xf5, 0x59, 0xae, 0xe6, 0xdd, 0x62, 0xfa, 0x34, 0x96, + 0x4f, 0x1d, 0xcd, 0x84, 0x82, 0xee, 0xc1, 0x74, 0x96, 0x3d, 0x98, 0xd9, + 0x42, 0x9d, 0xd0, 0x77, 0x9c, 0xf9, 0x9e, 0x0e, 0xa7, 0xcb, 0x70, 0xeb, + 0xe7, 0xcd, 0xce, 0x8c, 0xdc, 0x37, 0x15, 0x95, 0x0e, 0x24, 0x70, 0x4f, + 0x33, 0x6e, 0x4f, 0xad, 0xed, 0x4d, 0xf3, 0xe5, 0x38, 0xc1, 0xcd, 0xbb, + 0xde, 0xf1, 0xd2, 0x0d, 0xd6, 0x6b, 0xa3, 0x68, 0x92, 0x4c, 0x4b, 0x4f, + 0x89, 0xa0, 0xa8, 0xc8, 0x36, 0x93, 0x91, 0x17, 0xe7, 0x16, 0xed, 0xcb, + 0xdc, 0xf6, 0x28, 0x13, 0x32, 0x60, 0x14, 0xe0, 0x28, 0x7a, 0x69, 0x05, + 0x1d, 0xf7, 0x3b, 0xdf, 0x18, 0x0c, 0xaf, 0xba, 0x46, 0xf1, 0x5e, 0xd4, + 0xd3, 0xd0, 0x8e, 0x9a, 0xe2, 0xac, 0xdd, 0x0e, 0x5f, 0xb1, 0x69, 0xe2, + 0x74, 0x77, 0x2e, 0x52, 0xf9, 0x11, 0x3d, 0xd8, 0xe5, 0x36, 0x6f, 0x7d, + 0x7d, 0xde, 0x7c, 0xa7, 0x1d, 0x37, 0xdf, 0x6d, 0x5e, 0xea, 0xc8, 0xc0, + 0x72, 0x3f, 0x79, 0xbd, 0x0b, 0x6d, 0x7f, 0x9a, 0x15, 0x90, 0xda, 0xc1, + 0xae, 0xce, 0xf3, 0x44, 0x35, 0x5e, 0x83, 0x86, 0x7e, 0x89, 0x18, 0xa7, + 0x97, 0x8e, 0x87, 0x7c, 0x15, 0xd2, 0xd2, 0x7e, 0xf2, 0xc8, 0x29, 0x4f, + 0x70, 0x0f, 0xa6, 0xd4, 0x76, 0xe8, 0xdd, 0x7d, 0x7a, 0x2d, 0xfe, 0x0a, + 0x0c, 0x5c, 0xb1, 0xef, 0xec, 0x1a, 0x32, 0xca, 0x87, 0xff, 0x6b, 0xb1, + 0xa0, 0xe1, 0x2e, 0x01, 0x52, 0xb2, 0xb8, 0x74, 0x34, 0xb3, 0xfb, 0x15, + 0x0f, 0x17, 0xca, 0x74, 0xc1, 0xc1, 0x61, 0x86, 0x40, 0x38, 0x58, 0xba, + 0x82, 0x26, 0x66, 0x33, 0xa4, 0x52, 0xf3, 0xb5, 0x36, 0x60, 0xd8, 0x5a, + 0x8d, 0x9d, 0x28, 0x18, 0x3a, 0x68, 0x34, 0x2a, 0xa2, 0xe2, 0xb5, 0x39, + 0xed, 0x7d, 0xe5, 0xbe, 0x46, 0xb9, 0x04, 0x0c, 0xf3, 0xef, 0x88, 0x6e, + 0x9d, 0x6f, 0x23, 0xe2, 0x44, 0xe5, 0x2e, 0x3a, 0x7a, 0x1d, 0x49, 0x0f, + 0xdd, 0xcd, 0xd6, 0x4e, 0x0d, 0x0b, 0xc3, 0x35, 0xf2, 0xd1, 0x5d, 0x73, + 0x5d, 0x07, 0xca, 0x5c, 0xbd, 0x14, 0xec, 0x57, 0xb3, 0xbd, 0x37, 0xe7, + 0xdf, 0x06, 0x7d, 0xe0, 0x58, 0x4a, 0xcf, 0x7a, 0xc5, 0xa7, 0x24, 0x62, + 0x6f, 0x09, 0x75, 0x69, 0x74, 0x7f, 0xdf, 0xc8, 0x69, 0x5c, 0x20, 0x10, + 0x3a, 0xe8, 0x01, 0x12, 0xa3, 0xfb, 0xda, 0x4c, 0x3a, 0x0d, 0x3c, 0x3e, + 0x26, 0xe0, 0xa6, 0x7f, 0xb2, 0x6b, 0x0b, 0x68, 0x0a, 0x68, 0x86, 0xb1, + 0xfa, 0x61, 0x3a, 0xe8, 0x77, 0xdc, 0x42, 0xf7, 0xf4, 0x39, 0x9a, 0x40, + 0x58, 0x71, 0xc7, 0x0f, 0xf4, 0x0e, 0xc5, 0x1e, 0xe0, 0x28, 0x45, 0x7d, + 0xba, 0x84, 0xe4, 0x34, 0x69, 0xf9, 0xa5, 0x8a, 0x80, 0x43, 0xc0, 0x8d, + 0x04, 0x33, 0x43, 0xb8, 0xd7, 0x5d, 0x93, 0xed, 0x0f, 0x31, 0x6a, 0x4d, + 0xbf, 0xb7, 0x44, 0x41, 0x1b, 0xd4, 0xac, 0x9d, 0x83, 0x66, 0x08, 0x92, + 0xad, 0x3c, 0x0e, 0x1a, 0xe8, 0xd4, 0xe1, 0x5c, 0x63, 0xcf, 0x27, 0x48, + 0x5a, 0x8f, 0xc5, 0x6f, 0x83, 0x6b, 0x6f, 0xe8, 0xda, 0x1f, 0xba, 0xe9, + 0x7e, 0x11, 0xab, 0x8b, 0x4e, 0xc1, 0x9e, 0x23, 0x69, 0x1f, 0x42, 0x40, + 0xad, 0xbb, 0xfb, 0x4f, 0xe2, 0x50, 0xc9, 0x46, 0xe7, 0x15, 0x15, 0xf8, + 0x61, 0x09, 0x2a, 0x0b, 0x37, 0x43, 0xd4, 0x98, 0x5f, 0xc8, 0x4d, 0x06, + 0xe7, 0x0c, 0x3f, 0x83, 0x59, 0xd5, 0xcd, 0x2d, 0xde, 0x1e, 0x3a, 0x87, + 0x4e, 0xf7, 0x0a, 0x3c, 0x84, 0x72, 0x47, 0x11, 0x02, 0x6c, 0xe8, 0x93, + 0xcd, 0x24, 0xe9, 0x23, 0x86, 0x78, 0x53, 0xe0, 0xc6, 0x2f, 0xba, 0xa7, + 0xed, 0xaf, 0xba, 0x42, 0x80, 0x0d, 0xe6, 0xae, 0xda, 0xed, 0xbc, 0x65, + 0x21, 0x6d, 0x13, 0x90, 0x61, 0xb4, 0x05, 0x7b, 0x07, 0x86, 0xd7, 0x89, + 0x30, 0x9c, 0xc1, 0x9a, 0x41, 0x4d, 0xe8, 0x2b, 0x35, 0x21, 0x3a, 0x8a, + 0x60, 0x83, 0x1a, 0x97, 0x10, 0x98, 0xb6, 0xe1, 0x6b, 0xb5, 0xb1, 0xa1, + 0x36, 0x34, 0x60, 0x1b, 0x96, 0x5d, 0x1f, 0x2a, 0xd8, 0xf2, 0x94, 0xdd, + 0x58, 0x3d, 0x0f, 0xbe, 0x9d, 0xfc, 0xf5, 0x24, 0xb1, 0xd2, 0xc3, 0x36, + 0xef, 0xdb, 0x8e, 0x97, 0x3c, 0x9a, 0x4f, 0x48, 0xe3, 0x84, 0x91, 0xd8, + 0x39, 0x91, 0xf6, 0x55, 0xeb, 0x62, 0x51, 0x3d, 0x8f, 0x55, 0x60, 0x5e, + 0x00, 0xe0, 0xd2, 0xc7, 0x66, 0x51, 0xf1, 0xe2, 0xb7, 0x43, 0xc3, 0xe6, + 0x12, 0x9a, 0xe5, 0x84, 0xe0, 0x10, 0x76, 0xc7, 0x75, 0x6e, 0xa6, 0xee, + 0x11, 0xe4, 0xaf, 0xbd, 0x8a, 0x4f, 0x1d, 0x05, 0x29, 0x4f, 0xce, 0xa5, + 0x73, 0x92, 0x57, 0x7e, 0x0d, 0x11, 0xbc, 0xf8, 0x74, 0x4d, 0xf7, 0xb9, + 0x40, 0x0d, 0x5a, 0xa1, 0x19, 0x76, 0x4a, 0xae, 0x21, 0x16, 0xd4, 0x3f, + 0x76, 0xbf, 0x27, 0xbd, 0x2f, 0xe4, 0x25, 0x21, 0x00, 0x4e, 0xcc, 0x7c, + 0xc6, 0x57, 0xa4, 0xbf, 0xf1, 0x56, 0x90, 0xe0, 0xa4, 0xa3, 0xee, 0xcf, + 0x43, 0x4f, 0xda, 0x77, 0x47, 0x51, 0x79, 0x6a, 0x29, 0xb4, 0x2c, 0xdf, + 0xca, 0x47, 0xcb, 0xb8, 0x82, 0x7e, 0x44, 0x62, 0x9b, 0x8f, 0x61, 0x7b, + 0x3a, 0x93, 0x82, 0x1f, 0x69, 0xb7, 0xb1, 0xa6, 0x2c, 0xe1, 0xb2, 0x65, + 0xa0, 0x6d, 0x6f, 0xe4, 0x79, 0xd8, 0x30, 0xe0, 0xee, 0xd8, 0x83, 0x01, + 0xb2, 0x1f, 0x5c, 0x90, 0x44, 0x86, 0x48, 0x11, 0xf9, 0x11, 0xff, 0xea, + 0x45, 0x43, 0xae, 0x8a, 0x6b, 0x99, 0xf2, 0x1f, 0x02, 0x51, 0x4a, 0x35, + 0x02, 0x34, 0xd3, 0xe8, 0xda, 0xb1, 0x4b, 0xe3, 0xa5, 0x60, 0xce, 0x67, + 0xe3, 0x62, 0x59, 0xfc, 0x00, 0x0a, 0xe2, 0xfe, 0x7b, 0x1e, 0xe6, 0xf5, + 0x75, 0x19, 0x9b, 0x5e, 0xcb, 0xe6, 0xf5, 0x80, 0x9e, 0x3c, 0xb8, 0x54, + 0xd6, 0x0b, 0xfd, 0x48, 0xe0, 0xfa, 0x82, 0x2b, 0x5b, 0x26, 0xf9, 0x49, + 0xaf, 0xbe, 0x9c, 0x78, 0x73, 0xce, 0xc5, 0x65, 0xe2, 0x94, 0x2b, 0xd9, + 0xd0, 0x27, 0x3a, 0x66, 0x3e, 0xe2, 0xe0, 0x10, 0x79, 0x3d, 0xde, 0xc8, + 0x47, 0xdb, 0x1e, 0xc3, 0xe7, 0x51, 0xae, 0x59, 0xeb, 0x38, 0x66, 0x63, + 0x40, 0x8f, 0xbe, 0x1e, 0xb2, 0x2b, 0xeb, 0x64, 0x5f, 0xdd, 0x24, 0xc4, + 0x5a, 0x25, 0x59, 0xa2, 0xda, 0x4f, 0xdf, 0xf8, 0xb0, 0xb0, 0xf7, 0xcd, + 0x1f, 0x14, 0xcd, 0x09, 0x48, 0x70, 0x27, 0x1b, 0xde, 0xc4, 0xf0, 0xf3, + 0x56, 0x97, 0x8a, 0xb7, 0xf4, 0x19, 0x76, 0xe3, 0x9a, 0x33, 0x55, 0xfe, + 0x93, 0x68, 0xca, 0x1f, 0x3d, 0x44, 0x86, 0x39, 0x5d, 0x84, 0x58, 0x50, + 0xf2, 0xf1, 0xea, 0x4a, 0x5c, 0x1c, 0x74, 0xf0, 0x4b, 0xa5, 0x9c, 0x30, + 0xa0, 0x14, 0x1a, 0x80, 0xe0, 0xde, 0x3e, 0xae, 0x7f, 0x10, 0x18, 0x4a, + 0x1e, 0x9e, 0x6b, 0x75, 0x1a, 0xca, 0x08, 0x4e, 0x61, 0x72, 0x43, 0x9b, + 0x18, 0x4d, 0x2c, 0xd8, 0xb4, 0xc9, 0xea, 0x00, 0xb0, 0xdf, 0x1b, 0xcb, + 0x03, 0xc3, 0x7a, 0x27, 0xff, 0x41, 0x9d, 0xf9, 0xfd, 0xb3, 0x0c, 0xc0, + 0x48, 0x5d, 0x7c, 0xae, 0x5a, 0x72, 0x69, 0x93, 0x68, 0xe1, 0x9e, 0x9f, + 0x1f, 0x5c, 0x0a, 0x60, 0x90, 0x1a, 0x8e, 0x5a, 0x30, 0xd4, 0x2c, 0xbd, + 0xe1, 0x20, 0x51, 0xbc, 0x1c, 0x50, 0xb5, 0xf7, 0x42, 0x23, 0x35, 0x0f, + 0x92, 0xe2, 0xbb, 0x2a, 0x04, 0xa7, 0xde, 0x2e, 0x25, 0xfa, 0xed, 0x20, + 0x83, 0x9c, 0xd4, 0x56, 0xe0, 0x4d, 0x8d, 0x79, 0xa5, 0xa0, 0x6f, 0x49, + 0x62, 0x82, 0x9a, 0xa7, 0x4e, 0x54, 0x95, 0x0a, 0xc6, 0x5e, 0x27, 0x65, + 0x6d, 0x11, 0x2b, 0x35, 0x72, 0x34, 0x48, 0xd2, 0xe4, 0x9e, 0x07, 0x7d, + 0x03, 0x27, 0x15, 0x93, 0x55, 0x5c, 0x32, 0x43, 0xdb, 0x34, 0x8d, 0xbd, + 0x8d, 0x88, 0xa5, 0x24, 0x07, 0x93, 0x89, 0x37, 0xb9, 0x17, 0x15, 0xad, + 0xc7, 0x68, 0x86, 0x63, 0x0f, 0x10, 0x53, 0x8f, 0x40, 0xd3, 0x7b, 0x22, + 0x2b, 0x1a, 0x4c, 0xcb, 0x4f, 0x51, 0xf1, 0x3b, 0x19, 0xb8, 0x42, 0x53, + 0xaf, 0xf6, 0xb9, 0x57, 0x7f, 0xba, 0x8d, 0xb8, 0xb7, 0x3b, 0xe3, 0xc5, + 0xab, 0x4a, 0x26, 0x21, 0x6e, 0xce, 0x27, 0xb8, 0xc3, 0x99, 0x56, 0x14, + 0xdd, 0x5b, 0x61, 0x82, 0xbf, 0xd3, 0xc8, 0x76, 0xee, 0x22, 0xaf, 0x21, + 0x21, 0x1d, 0x4e, 0x33, 0xb5, 0x43, 0x3a, 0xfb, 0x91, 0xa0, 0xaa, 0xe3, + 0x10, 0x4a, 0x50, 0x42, 0xd4, 0x5f, 0x92, 0x0e, 0x71, 0x60, 0x4f, 0xaa, + 0xef, 0x66, 0x45, 0xfe, 0xf7, 0xc8, 0xb0, 0x73, 0x75, 0x91, 0x0b, 0x86, + 0x40, 0xa5, 0x02, 0x28, 0xf7, 0xe0, 0x1f, 0x5d, 0xe6, 0xe3, 0xa4, 0x57, + 0xbd, 0x29, 0xaa, 0x53, 0xae, 0x35, 0x30, 0x78, 0x73, 0xd6, 0xb7, 0x01, + 0x9d, 0x13, 0x50, 0xf6, 0x39, 0xa2, 0x3e, 0x03, 0x04, 0xaa, 0x6d, 0xcf, + 0x6b, 0xff, 0x9a, 0xbe, 0x3e, 0x0a, 0xd4, 0x20, 0xce, 0x42, 0x1f, 0xca, + 0x2f, 0xd3, 0x2c, 0xd1, 0xf4, 0xd2, 0x50, 0xd3, 0xa2, 0xc1, 0x1e, 0x87, + 0xbf, 0xeb, 0xb8, 0xa8, 0xd4, 0x1c, 0x96, 0xb8, 0x8e, 0xbe, 0x35, 0x5f, + 0x08, 0x28, 0x20, 0x2b, 0xdc, 0xa4, 0xf5, 0xf6, 0xde, 0xca, 0x1e, 0xcb, + 0x93, 0x3b, 0x64, 0x79, 0x00, 0x3c, 0x8d, 0xbb, 0x5c, 0x7a, 0x40, 0x14, + 0x58, 0x12, 0xa4, 0xf7, 0x6e, 0x51, 0xfb, 0xe7, 0x6f, 0x49, 0x5b, 0xc2, + 0xc9, 0x05, 0x38, 0x9c, 0x08, 0x78, 0x71, 0x27, 0x2b, 0xf5, 0xbf, 0xd6, + 0x38, 0xaa, 0x45, 0xe1, 0xe1, 0x4c, 0xfb, 0xfd, 0xb7, 0xe6, 0xcf, 0xad, + 0x9e, 0x56, 0xaf, 0x12, 0x12, 0x98, 0xe6, 0x38, 0xaa, 0xee, 0xdb, 0x9e, + 0xca, 0xe1, 0x79, 0x6d, 0x44, 0xfb, 0x19, 0x50, 0x92, 0x00, 0x06, 0x2c, + 0x24, 0x71, 0x6c, 0x34, 0x45, 0xac, 0xf9, 0x82, 0x66, 0xa8, 0x63, 0x80, + 0xa8, 0x5b, 0x21, 0x3c, 0x36, 0x71, 0x93, 0x40, 0x7b, 0xff, 0xa2, 0xd0, + 0x72, 0xb4, 0x66, 0xfa, 0xfc, 0xa0, 0xee, 0xca, 0x15, 0x73, 0x52, 0xe7, + 0x9d, 0x11, 0xd3, 0xbc, 0xab, 0x37, 0x31, 0x0e, 0xaf, 0xdc, 0x05, 0x30, + 0x79, 0x8c, 0x25, 0x75, 0x5c, 0x60, 0xc7, 0x9a, 0xfc, 0x88, 0xea, 0xe6, + 0x09, 0x9f, 0xd1, 0x4f, 0x13, 0xf4, 0x41, 0x54, 0x5b, 0x7a, 0xe4, 0x49, + 0x3c, 0x0f, 0x15, 0xe9, 0xa4, 0x85, 0xb2, 0x92, 0x07, 0xea, 0xea, 0x7c, + 0xc1, 0x6d, 0xa9, 0x03, 0xb3, 0x31, 0xce, 0x1e, 0x82, 0xca, 0x9e, 0x3c, + 0x88, 0x88, 0xc1, 0x04, 0x5f, 0xbe, 0xd5, 0x94, 0x0d, 0x67, 0x98, 0x27, + 0xd0, 0x0f, 0x43, 0xf3, 0xb3, 0xfc, 0xff, 0x24, 0xa2, 0x1e, 0x17, 0x06, + 0xb0, 0x52, 0x16, 0x7c, 0xd8, 0x49, 0x74, 0x51, 0xcf, 0x2d, 0x36, 0x16, + 0xb0, 0x88, 0xb2, 0x2b, 0x1d, 0x72, 0x70, 0xab, 0xe2, 0xf6, 0x5f, 0xa5, + 0x2d, 0x4e, 0xd1, 0x42, 0x3c, 0x83, 0x84, 0xb2, 0x56, 0xeb, 0x8d, 0xce, + 0x33, 0x46, 0xdb, 0x3d, 0x4f, 0x97, 0xea, 0x37, 0x5e, 0x0d, 0xd7, 0x4c, + 0x9a, 0x7e, 0xc9, 0x0e, 0x69, 0x4d, 0x97, 0x15, 0x1e, 0x09, 0xbe, 0x7e, + 0xff, 0xe8, 0xf5, 0xab, 0xe9, 0xe7, 0xed, 0x4b, 0x41, 0xa5, 0xf2, 0x2a, + 0x24, 0x48, 0x8b, 0x72, 0x4b, 0x9d, 0xcf, 0x45, 0xdb, 0xc0, 0xaf, 0xa8, + 0x0f, 0x0f, 0x67, 0x37, 0xd3, 0x8b, 0xe1, 0x67, 0x90, 0xd8, 0x1c, 0x58, + 0x36, 0x46, 0x51, 0x52, 0xea, 0xb4, 0x75, 0xb1, 0xcd, 0xc5, 0x39, 0x16, + 0xe0, 0xec, 0x16, 0xf7, 0xf8, 0x0f, 0x5d, 0x13, 0x84, 0x62, 0x34, 0x86, + 0x42, 0x05, 0xa8, 0x08, 0x84, 0xa9, 0x77, 0x12, 0xc1, 0x56, 0xdd, 0x28, + 0xde, 0x39, 0x33, 0x21, 0x3d, 0xbd, 0x94, 0xce, 0xe4, 0xb3, 0x17, 0x9b, + 0x09, 0x20, 0xf0, 0x25, 0xce, 0x00, 0x34, 0x8e, 0x12, 0x94, 0x74, 0x0b, + 0x16, 0xa1, 0x60, 0x76, 0x24, 0xf0, 0xbf, 0xe3, 0x3a, 0x83, 0x8f, 0x40, + 0x47, 0x2e, 0x1c, 0xd5, 0x35, 0x25, 0x87, 0xb3, 0x11, 0xdc, 0x98, 0xb0, + 0xa6, 0x5f, 0x6a, 0x05, 0x1d, 0x06, 0x8d, 0xe8, 0xb0, 0x98, 0xf0, 0x43, + 0x29, 0x84, 0xe4, 0xef, 0x34, 0x67, 0x74, 0x64, 0xe8, 0xb8, 0xf0, 0xd4, + 0x9e, 0xc1, 0x3f, 0x5f, 0xeb, 0xe0, 0x9b, 0x37, 0xf8, 0x75, 0x46, 0x47, + 0xa5, 0x3e, 0x42, 0x20, 0x50, 0xc4, 0x5d, 0xf3, 0xdf, 0x4e, 0xf8, 0x0e, + 0x1e, 0x15, 0x10, 0x3e, 0xf1, 0x68, 0xad, 0x87, 0xad, 0xe5, 0x45, 0x5e, + 0x22, 0xba, 0x2e, 0x51, 0xa0, 0xbf, 0xdc, 0x87, 0xca, 0xe4, 0x1f, 0x2f, + 0x2c, 0xae, 0xa9, 0x14, 0xd7, 0xdd, 0x01, 0xa8, 0x4f, 0x43, 0xcb, 0x84, + 0x92, 0xbf, 0xf9, 0x3d, 0xf0, 0x6b, 0x19, 0x43, 0xb0, 0xdf, 0xff, 0x94, + 0x76, 0xe2, 0x84, 0xf9, 0x31, 0x88, 0x7e, 0xc6, 0x87, 0x58, 0xbe, 0x5d, + 0x8b, 0xf8, 0xb5, 0xdc, 0x95, 0x16, 0x5f, 0xa1, 0x2c, 0xe8, 0x53, 0x36, + 0x64, 0xf5, 0x5d, 0xa0, 0x74, 0x12, 0x78, 0x59, 0x73, 0x69, 0x5a, 0x2b, + 0x36, 0x4a, 0xff, 0x5b, 0xef, 0x49, 0x2c, 0xb2, 0x9e, 0x59, 0xf0, 0x39, + 0x56, 0xe1, 0xd0, 0x1a, 0x05, 0xb2, 0x7c, 0xd1, 0x40, 0x09, 0xdf, 0x00, + 0xc9, 0x15, 0x53, 0xa2, 0xda, 0x84, 0xb5, 0x85, 0x05, 0x76, 0xa6, 0x1b, + 0xcb, 0x06, 0xb2, 0xc8, 0xa0, 0xc5, 0x23, 0x8f, 0xb0, 0xe8, 0xf5, 0xd9, + 0xd0, 0x19, 0x29, 0xfe, 0x2d, 0x9a, 0x57, 0x76, 0x5f, 0xf2, 0xef, 0x71, + 0x16, 0xee, 0x28, 0x7b, 0xe4, 0x48, 0xeb, 0xda, 0xe0, 0xd5, 0xbc, 0x0e, + 0x46, 0x6b, 0x06, 0x5d, 0xe5, 0x91, 0x2d, 0xcb, 0xc4, 0x53, 0xa6, 0x16, + 0xd5, 0xe7, 0xd8, 0xf1, 0xdd, 0x4f, 0xbb, 0xcc, 0x55, 0x67, 0x19, 0x98, + 0x94, 0x95, 0x5e, 0xd6, 0xf5, 0xf7, 0xe8, 0x6a, 0xf7, 0x20, 0x86, 0x3a, + 0x43, 0xbf, 0xe9, 0xec, 0x6b, 0x33, 0x49, 0x19, 0x43, 0xfb, 0xeb, 0x3f, + 0xf4, 0x9d, 0x29, 0x66, 0xb9, 0x6e, 0xb5, 0x15, 0x4b, 0x8d, 0x3c, 0x3c, + 0xfa, 0xf2, 0x87, 0xba, 0x61, 0x11, 0x40, 0xe6, 0xb4, 0x6f, 0xf5, 0xe1, + 0x24, 0x32, 0x69, 0x3e, 0xff, 0xf7, 0xbc, 0xee, 0x82, 0xf2, 0x9e, 0x6d, + 0x3f, 0x6c, 0xcc, 0x0f, 0x4f, 0xc3, 0xf1, 0xdb, 0x1e, 0x81, 0xd7, 0x9b, + 0x22, 0xa8, 0xa7, 0x36, 0x6d, 0xa9, 0x6f, 0x46, 0x1a, 0xa7, 0xff, 0x00, + 0x4b, 0xd8, 0xab, 0xe7, 0x50, 0x3b, 0xe9, 0xc0, 0x57, 0xec, 0x8d, 0x0c, + 0xa0, 0xee, 0x8c, 0x2a, 0x74, 0xf2, 0x94, 0xf9, 0x0c, 0x20, 0x14, 0xd9, + 0xad, 0x0d, 0x4e, 0xac, 0x35, 0x44, 0x59, 0x28, 0x24, 0x31, 0x32, 0xaa, + 0x6d, 0xc2, 0x13, 0xb9, 0xee, 0x75, 0x0c, 0x5f, 0x39, 0xef, 0x31, 0xca, + 0x28, 0x48, 0x56, 0x59, 0xfb, 0xa8, 0xd8, 0x2b, 0x70, 0x61, 0x22, 0x43, + 0x43, 0xb9, 0x60, 0x44, 0xeb, 0xf8, 0x98, 0x87, 0x25, 0x84, 0xa2, 0xaa, + 0x37, 0xd4, 0xb8, 0xd6, 0x3d, 0xa3, 0xa1, 0x4a, 0x81, 0xc2, 0xa9, 0xea, + 0xa2, 0xd6, 0x63, 0x76, 0x50, 0xeb, 0xcd, 0x19, 0x40, 0xb1, 0x7c, 0xf6, + 0xc1, 0x44, 0x01, 0x25, 0xe0, 0xdd, 0xb8, 0x39, 0xef, 0x46, 0x3d, 0x50, + 0x33, 0xed, 0xb1, 0x63, 0x65, 0xd7, 0x50, 0xe7, 0x95, 0xba, 0xab, 0xa7, + 0x14, 0xe5, 0x60, 0xcb, 0x81, 0x6e, 0x88, 0x3c, 0x06, 0x6e, 0x7d, 0x8e, + 0xe7, 0xbb, 0xa5, 0xc2, 0xbd, 0xae, 0x46, 0x8f, 0x43, 0x04, 0x29, 0xe6, + 0x17, 0x38, 0x05, 0x2d, 0x97, 0x93, 0x5b, 0xf9, 0xef, 0x4d, 0x2e, 0x75, + 0x6c, 0x69, 0xba, 0x08, 0xf2, 0x21, 0x1e, 0x21, 0xe6, 0x8a, 0x5b, 0x8c, + 0xd4, 0x8e, 0xde, 0x64, 0x9b, 0x9d, 0x54, 0x58, 0x65, 0x3e, 0xdd, 0x8a, + 0x1e, 0x81, 0x4e, 0x45, 0xe8, 0xfb, 0x20, 0xc3, 0x3a, 0xf0, 0x50, 0x1e, + 0x8a, 0x18, 0xea, 0x2b, 0xf5, 0xe1, 0xa6, 0xb6, 0xc8, 0xa0, 0x02, 0x3d, + 0x6e, 0xfa, 0x0b, 0x51, 0x95, 0x4e, 0x4c, 0x11, 0xb0, 0xc4, 0x62, 0x58, + 0xa6, 0x9c, 0x13, 0x4e, 0xbe, 0xc9, 0x29, 0x93, 0x29, 0x15, 0x5f, 0xaf, + 0x0e, 0xc3, 0xb3, 0x26, 0x3f, 0xdc, 0x4c, 0x33, 0xb8, 0x4b, 0x11, 0xae, + 0x1f, 0xd7, 0x05, 0x39, 0xcf, 0xfe, 0xc3, 0x6d, 0xf0, 0xc0, 0x77, 0x02, + 0xb8, 0x9b, 0x3d, 0x1b, 0x3d, 0x72, 0xfe, 0x7e, 0x18, 0x60, 0x9b, 0xc4, + 0x8b, 0xac, 0x25, 0x6d, 0x3b, 0x80, 0x34, 0xbc, 0x51, 0xaf, 0xf6, 0xff, + 0x66, 0x98, 0x86, 0x6e, 0x9e, 0x9a, 0xfe, 0x6d, 0x21, 0x4d, 0xf1, 0x58, + 0x3e, 0x3e, 0x43, 0xe3, 0x7e, 0x40, 0xb0, 0xb3, 0xd8, 0x12, 0xa5, 0xce, + 0x09, 0x41, 0x8c, 0x1d, 0x73, 0xcd, 0xfc, 0x63, 0xed, 0xeb, 0x08, 0x1e, + 0x34, 0xfb, 0xed, 0x75, 0xb7, 0x86, 0x84, 0x7c, 0x80, 0xe9, 0xe4, 0xa3, + 0x1c, 0x4a, 0x0d, 0x11, 0x16, 0x24, 0xb2, 0xb1, 0x99, 0xe5, 0xe3, 0x2e, + 0x2f, 0x70, 0xcd, 0x1e, 0x35, 0x14, 0x79, 0xba, 0xa2, 0x51, 0x7a, 0x29, + 0x5c, 0x75, 0x8f, 0xdd, 0x22, 0xdf, 0xb2, 0x64, 0xd9, 0x95, 0x11, 0x33, + 0x97, 0xee, 0x69, 0x42, 0x01, 0x96, 0x98, 0x1b, 0x43, 0xc2, 0xec, 0xf9, + 0xb0, 0xdb, 0x69, 0x34, 0xab, 0x98, 0x1b, 0xb2, 0x04, 0x05, 0x14, 0x1d, + 0x25, 0x2f, 0x32, 0x41, 0x50, 0x51, 0x55, 0x62, 0x6d, 0x78, 0x7f, 0x8b, + 0xbb, 0xc2, 0xcd, 0xcf, 0xe4, 0xed, 0x04, 0x1f, 0x25, 0x30, 0x43, 0x64, + 0x69, 0x7c, 0x87, 0xa3, 0xa9, 0xb1, 0xc1, 0xd1, 0xdc, 0x01, 0x10, 0x1d, + 0x27, 0x3f, 0x5c, 0x5d, 0x75, 0x82, 0x9b, 0xaa, 0xb3, 0xe8, 0x0c, 0x11, + 0x1f, 0x24, 0x38, 0x41, 0x45, 0x54, 0x5f, 0x69, 0x85, 0x8d, 0x93, 0x9e, + 0xc5, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x25, 0x32, 0x42}; +#elif MLD_CONFIG_PARAMETER_SET == 65 +const uint8_t expected_signature[] = { + 0x8b, 0x6f, 0x79, 0x00, 0xcc, 0x79, 0x57, 0xee, 0x16, 0x86, 0x87, 0xd5, + 0xcf, 0xb6, 0x90, 0x2c, 0xc6, 0x30, 0xeb, 0x8d, 0x39, 0xae, 0x9b, 0xf1, + 0x66, 0xe0, 0xd6, 0x93, 0xa5, 0x4e, 0x26, 0x9b, 0x96, 0x8f, 0xd1, 0x46, + 0x97, 0xbe, 0x71, 0x1c, 0xf3, 0xa5, 0xe5, 0xae, 0x8d, 0x4b, 0xf2, 0xe6, + 0x48, 0x8f, 0xe9, 0x5e, 0x07, 0xef, 0xe4, 0xbb, 0x39, 0xc1, 0xc9, 0x3c, + 0xc3, 0x0b, 0xfb, 0x2a, 0x29, 0x06, 0xfe, 0x01, 0xcb, 0x63, 0x83, 0x10, + 0xa8, 0xc8, 0xa0, 0x29, 0xa5, 0x80, 0xeb, 0xbd, 0xa9, 0xd9, 0x0b, 0x61, + 0xbc, 0xce, 0x11, 0x55, 0x66, 0x12, 0xc7, 0x5b, 0xd2, 0x7a, 0x5a, 0xc8, + 0xab, 0xab, 0xbf, 0x3a, 0x1f, 0x96, 0x1a, 0x70, 0xcb, 0x41, 0x5f, 0xc8, + 0xb7, 0x09, 0x22, 0x98, 0x9b, 0xb8, 0xf7, 0x2d, 0x49, 0x65, 0x1d, 0x09, + 0x8b, 0x70, 0xb5, 0x42, 0xc9, 0x89, 0x5b, 0x74, 0xb4, 0x28, 0x82, 0x01, + 0x53, 0x12, 0x3e, 0x23, 0xf6, 0x54, 0xf8, 0x51, 0x12, 0x4b, 0x02, 0x3a, + 0x7e, 0xb6, 0x1f, 0xac, 0xa0, 0xe6, 0x6f, 0xf8, 0x61, 0x82, 0xe4, 0xfb, + 0x96, 0x2a, 0xd2, 0xaf, 0x3c, 0xea, 0x6e, 0xdc, 0x18, 0x8a, 0x5d, 0x90, + 0xda, 0xa2, 0x5d, 0xa7, 0x8f, 0x5b, 0x50, 0x46, 0xaf, 0x8c, 0x17, 0x6a, + 0x4c, 0x39, 0xfc, 0x31, 0x4c, 0x4b, 0xc2, 0x57, 0x66, 0x61, 0x98, 0xbf, + 0xe6, 0xfb, 0x54, 0x96, 0xd3, 0x70, 0xb8, 0xaf, 0xcd, 0x8b, 0xcc, 0x00, + 0x07, 0x92, 0x15, 0xc2, 0xbb, 0x48, 0xbb, 0xc6, 0xb7, 0xb5, 0x58, 0x8c, + 0xfc, 0xf0, 0xda, 0x6a, 0x0d, 0xf7, 0x1d, 0x7d, 0xc6, 0x27, 0x26, 0x1a, + 0x99, 0xc5, 0x2f, 0xf8, 0x97, 0x65, 0x43, 0x86, 0xd6, 0x25, 0x23, 0x2b, + 0x06, 0x8f, 0x12, 0xa1, 0xae, 0xbb, 0x58, 0x34, 0x25, 0xec, 0x5b, 0x68, + 0xa4, 0xe1, 0x03, 0xfc, 0x26, 0xa2, 0xd6, 0x2b, 0x61, 0x10, 0x47, 0xbd, + 0x16, 0xe5, 0xca, 0x4a, 0xce, 0xed, 0x89, 0x09, 0x1a, 0xed, 0x22, 0xc1, + 0xca, 0x44, 0xe3, 0xef, 0x72, 0x34, 0xab, 0xab, 0x61, 0x5c, 0x9f, 0x5f, + 0xb5, 0xf5, 0xe8, 0x2d, 0x89, 0xea, 0x4b, 0x40, 0x65, 0x57, 0x8b, 0xa2, + 0x95, 0x40, 0x9c, 0x72, 0xc0, 0x46, 0x69, 0x45, 0x06, 0xf6, 0x07, 0x5b, + 0x2d, 0xa5, 0x46, 0xca, 0x5d, 0xfb, 0x40, 0xb7, 0x48, 0x59, 0x5b, 0xe2, + 0x1b, 0x38, 0xb2, 0x15, 0x75, 0x66, 0x67, 0x58, 0x00, 0x3f, 0xde, 0x8a, + 0x63, 0x13, 0x34, 0x6a, 0x30, 0xca, 0xb4, 0xd5, 0x3e, 0xe0, 0x6d, 0x14, + 0xb8, 0x9a, 0x48, 0xef, 0xfd, 0xbd, 0x6d, 0x20, 0x11, 0x4d, 0x25, 0xe5, + 0xab, 0x15, 0x8d, 0xe5, 0x91, 0xbc, 0xc6, 0x69, 0x8a, 0xf8, 0xab, 0x3a, + 0x82, 0xae, 0xc5, 0x03, 0x2c, 0xcf, 0x54, 0xdc, 0xcd, 0xe8, 0x49, 0x53, + 0xb5, 0xd8, 0xc2, 0x24, 0xf8, 0x8c, 0x38, 0x8f, 0xe3, 0xfe, 0x3a, 0x18, + 0x15, 0xa8, 0xda, 0x77, 0xc8, 0x81, 0x72, 0xc6, 0xc1, 0x60, 0xa3, 0x73, + 0x65, 0x68, 0x5c, 0xf3, 0x1d, 0x8d, 0x61, 0x21, 0x65, 0xfb, 0x45, 0xc4, + 0x4c, 0x31, 0x88, 0x25, 0x0d, 0x52, 0x75, 0x3b, 0xec, 0x54, 0xe0, 0xb1, + 0x9c, 0x7c, 0xdf, 0xe3, 0x3b, 0x77, 0x31, 0x33, 0xd7, 0x25, 0x99, 0xff, + 0xc5, 0x40, 0x1e, 0x85, 0x09, 0xfd, 0x2d, 0x24, 0x4a, 0x92, 0xe7, 0x77, + 0x48, 0xa5, 0x46, 0xf4, 0x8e, 0xa3, 0x6b, 0x24, 0xe4, 0x6b, 0x31, 0xf6, + 0xe0, 0x16, 0x49, 0x9b, 0x9f, 0xa3, 0x1a, 0x5c, 0x05, 0x5e, 0x81, 0x62, + 0xc8, 0x14, 0x52, 0xb4, 0x21, 0xfd, 0x76, 0x6d, 0x88, 0xe9, 0x3b, 0x0b, + 0x75, 0x27, 0x92, 0x47, 0x5a, 0x58, 0x08, 0x26, 0xa7, 0xa2, 0x48, 0x1c, + 0x14, 0x3e, 0x5e, 0xdf, 0x81, 0x83, 0x83, 0x3e, 0xc6, 0x72, 0x27, 0xc4, + 0x6a, 0x46, 0x2b, 0xf2, 0x8d, 0x42, 0x11, 0xb9, 0x15, 0xd7, 0xf0, 0x20, + 0x29, 0x53, 0xba, 0xf0, 0x6e, 0x41, 0x3d, 0xee, 0x19, 0xf2, 0x43, 0xf3, + 0x6d, 0x00, 0xe2, 0x43, 0x77, 0xb9, 0xa9, 0x78, 0x34, 0x48, 0x3c, 0x1a, + 0x8b, 0xbd, 0xa1, 0xe5, 0x90, 0x59, 0x5b, 0xd6, 0x1e, 0x22, 0xdf, 0xb2, + 0xa7, 0x96, 0x7d, 0x55, 0x86, 0x66, 0x95, 0xb7, 0x06, 0xe7, 0x60, 0x2a, + 0x01, 0x48, 0x3f, 0xd4, 0xa7, 0xd4, 0xc2, 0x38, 0xa4, 0x10, 0x8e, 0x4f, + 0x97, 0xad, 0xa3, 0xb9, 0xe2, 0xaa, 0x13, 0xb1, 0x16, 0x89, 0x3d, 0x74, + 0x60, 0x94, 0x8c, 0xc3, 0xe6, 0x5f, 0xcf, 0xdc, 0x58, 0x17, 0x98, 0x27, + 0x86, 0xae, 0x2a, 0x0d, 0xe8, 0x33, 0x79, 0xc8, 0xc8, 0x5b, 0x59, 0xb0, + 0xba, 0xac, 0xd3, 0x6e, 0x2d, 0x7b, 0x0b, 0x9a, 0xb5, 0xfd, 0x58, 0x42, + 0xeb, 0x80, 0xf4, 0x6b, 0x9a, 0x2f, 0x19, 0x43, 0x75, 0xb4, 0xcb, 0xc9, + 0xd5, 0x28, 0xf5, 0xb9, 0x67, 0x82, 0xb4, 0xed, 0x8c, 0x3f, 0x3d, 0x6b, + 0x6d, 0x1b, 0x80, 0x13, 0x5c, 0x7b, 0x2e, 0xfa, 0xa0, 0x32, 0xba, 0xb5, + 0x46, 0xd6, 0xe7, 0x90, 0xe9, 0xd1, 0x91, 0xa0, 0xaa, 0x26, 0x35, 0xa2, + 0x0d, 0x98, 0x44, 0x11, 0xae, 0xf9, 0xc5, 0x12, 0x4d, 0x1a, 0x7c, 0x53, + 0xea, 0xf6, 0x05, 0x8d, 0x3a, 0x74, 0x92, 0xc9, 0x65, 0xeb, 0x6f, 0xb5, + 0xb4, 0xd2, 0xcd, 0x5c, 0xec, 0xaf, 0x95, 0xcb, 0xb4, 0x3c, 0x22, 0xca, + 0x1c, 0x06, 0x85, 0x16, 0x96, 0x24, 0x8c, 0x6c, 0x80, 0xf8, 0xb3, 0xa7, + 0x87, 0x77, 0xeb, 0x09, 0x71, 0xc8, 0x95, 0xfb, 0x5e, 0xe5, 0x6f, 0x78, + 0xf9, 0x60, 0xf9, 0x9e, 0x58, 0x7b, 0xbd, 0x47, 0xdd, 0x48, 0x2e, 0x56, + 0xcd, 0x63, 0x72, 0xc9, 0x4b, 0x65, 0x2d, 0x41, 0xe8, 0x81, 0x19, 0x33, + 0x4b, 0xf6, 0x02, 0xc6, 0xcb, 0x2e, 0xdf, 0x3d, 0xc8, 0xdd, 0x2f, 0x0f, + 0x09, 0x67, 0xf0, 0xaa, 0x3c, 0x51, 0xdc, 0x8d, 0xc6, 0xc3, 0xb2, 0x3b, + 0x15, 0x85, 0xcb, 0xeb, 0x62, 0xef, 0xa3, 0xf9, 0x94, 0xf4, 0x35, 0x9c, + 0x59, 0xcc, 0xc2, 0x68, 0xb4, 0xde, 0x02, 0x75, 0x8e, 0xf5, 0x33, 0xca, + 0xd5, 0xc5, 0x24, 0xae, 0xf6, 0xde, 0x2b, 0x01, 0xf4, 0x56, 0xb9, 0xa5, + 0xa7, 0xe0, 0x64, 0x2e, 0xba, 0x1d, 0x53, 0x54, 0x46, 0xcf, 0x64, 0x16, + 0x12, 0xe2, 0xa6, 0xcc, 0x18, 0xb4, 0x77, 0x8b, 0x19, 0x50, 0x43, 0x96, + 0xc8, 0x5d, 0xc3, 0x58, 0xf0, 0xfd, 0x5e, 0x13, 0xa9, 0x10, 0x67, 0xdf, + 0x25, 0xdb, 0xaf, 0x38, 0x5f, 0xbd, 0x35, 0xc1, 0x49, 0x44, 0xe8, 0x1f, + 0x12, 0xa4, 0x7c, 0x28, 0xa3, 0xd6, 0x0d, 0x6f, 0x44, 0xa9, 0x5f, 0xfc, + 0x9f, 0xfa, 0x11, 0x62, 0x87, 0x5b, 0x0e, 0x91, 0xd4, 0xb6, 0xd3, 0x71, + 0xc2, 0x77, 0x19, 0xf6, 0x7c, 0x11, 0x30, 0x5e, 0x5c, 0xd3, 0x1e, 0x90, + 0x05, 0x31, 0x63, 0xbb, 0xef, 0x85, 0xe0, 0x27, 0x94, 0x80, 0xcb, 0x33, + 0xbc, 0x5e, 0x45, 0x87, 0x62, 0xdf, 0xd4, 0x12, 0x2f, 0xf5, 0x41, 0x15, + 0x03, 0x0c, 0x80, 0xe8, 0xe2, 0x06, 0xde, 0x4b, 0x46, 0x70, 0x94, 0xd2, + 0x0d, 0x85, 0x72, 0x27, 0xe5, 0x6c, 0xeb, 0xd2, 0x78, 0x0b, 0x38, 0x40, + 0xe8, 0xdb, 0x47, 0x5c, 0xba, 0xd0, 0x21, 0x33, 0x8f, 0xb8, 0xc0, 0x66, + 0x1e, 0xd1, 0xb0, 0x94, 0xa3, 0x39, 0xc7, 0x87, 0xaf, 0x97, 0x98, 0xce, + 0x6d, 0x03, 0x1a, 0xdb, 0x52, 0x96, 0x0b, 0x9d, 0x5b, 0xf8, 0xa3, 0xf4, + 0x41, 0x95, 0x72, 0xad, 0x0e, 0x98, 0x61, 0x7f, 0xf3, 0x8f, 0x23, 0xeb, + 0xc0, 0xdf, 0xd7, 0x70, 0x26, 0x8c, 0xb3, 0xb3, 0xf0, 0xa2, 0x8a, 0x39, + 0xdd, 0x61, 0xb4, 0x53, 0xe0, 0x2a, 0x6f, 0x91, 0x34, 0x9c, 0x76, 0xf6, + 0x52, 0x93, 0xe6, 0x39, 0xb7, 0x54, 0x07, 0x46, 0x82, 0x2d, 0x05, 0x6d, + 0x9a, 0x00, 0x53, 0x65, 0x68, 0x93, 0x91, 0x00, 0xda, 0xe0, 0x93, 0x34, + 0x60, 0xb1, 0x93, 0x0b, 0x64, 0xa8, 0x12, 0xd2, 0x51, 0x3c, 0xdb, 0xb0, + 0x4c, 0x39, 0x4e, 0xce, 0xbd, 0xf0, 0x65, 0x12, 0x8a, 0xd4, 0x80, 0x7d, + 0x82, 0x85, 0xe4, 0x92, 0xc2, 0x77, 0x1e, 0xcf, 0xd9, 0xab, 0x0f, 0x9b, + 0x32, 0x2e, 0x3f, 0xe1, 0x0e, 0x87, 0x1c, 0x87, 0x34, 0xe7, 0x93, 0x16, + 0x95, 0x09, 0x7d, 0x24, 0xa8, 0xb5, 0xe0, 0x9f, 0x23, 0x87, 0x5c, 0x0b, + 0x31, 0x4a, 0x2f, 0xe2, 0x5c, 0x82, 0x49, 0x51, 0xe4, 0x93, 0xcb, 0x05, + 0x23, 0x4f, 0x8a, 0x83, 0x88, 0xfb, 0x89, 0xb0, 0x08, 0xd6, 0x64, 0xad, + 0x51, 0x84, 0x40, 0x29, 0xb1, 0xca, 0x74, 0x26, 0x29, 0x5a, 0x61, 0x01, + 0x2e, 0xa0, 0xeb, 0xeb, 0x02, 0xb5, 0xff, 0xd8, 0x20, 0x6a, 0x5e, 0x8d, + 0x17, 0x1e, 0xa3, 0xd7, 0x2f, 0x20, 0x0b, 0x93, 0x17, 0x24, 0xf7, 0x90, + 0x7b, 0xc6, 0xba, 0xd8, 0xf9, 0xe9, 0x0a, 0x2a, 0x7a, 0x81, 0x23, 0x81, + 0x03, 0x6f, 0x1e, 0x0d, 0x87, 0x83, 0xd1, 0xcf, 0x92, 0x2f, 0x19, 0x82, + 0x4e, 0x6c, 0x0a, 0x02, 0xb6, 0x70, 0xbc, 0xe1, 0x58, 0xe7, 0x16, 0xdb, + 0x2f, 0x74, 0x9f, 0xe1, 0xc2, 0x1e, 0x64, 0xc6, 0x48, 0x08, 0xee, 0xea, + 0x52, 0x9a, 0xce, 0x2c, 0xc5, 0x0c, 0x7a, 0x63, 0xf1, 0x6a, 0xbd, 0x2c, + 0x8b, 0xd5, 0x4a, 0xfa, 0x1e, 0xab, 0x9a, 0x5b, 0x25, 0xb8, 0xfa, 0x0a, + 0xe9, 0x68, 0x80, 0x6f, 0x80, 0x57, 0x10, 0x54, 0xb8, 0xa2, 0x16, 0xbd, + 0xfe, 0xf7, 0xea, 0x01, 0xc7, 0x94, 0x5a, 0x95, 0xe3, 0x61, 0xa5, 0x49, + 0x84, 0xf5, 0x79, 0x78, 0xb5, 0x0a, 0x96, 0xca, 0x01, 0x1b, 0xd0, 0x0b, + 0x51, 0x30, 0xd3, 0x48, 0xfc, 0x4d, 0x50, 0x71, 0x09, 0x73, 0xea, 0x37, + 0xcd, 0x9d, 0x3d, 0xde, 0x30, 0x56, 0x21, 0xf0, 0xef, 0x84, 0xad, 0x27, + 0xe1, 0x83, 0xdb, 0xfb, 0xcd, 0x11, 0xb2, 0xbd, 0x30, 0x67, 0x8a, 0x88, + 0x09, 0x0e, 0x9d, 0x96, 0x09, 0xba, 0xda, 0x9d, 0xf0, 0xe9, 0xb4, 0xa6, + 0x7a, 0x04, 0xf9, 0x4b, 0xb8, 0x51, 0xa9, 0x99, 0xf3, 0xbb, 0x77, 0x95, + 0x0a, 0xa1, 0xa6, 0xa1, 0x24, 0xfc, 0xcc, 0x45, 0xe8, 0x83, 0xc8, 0x6f, + 0x48, 0xad, 0x9a, 0x73, 0xd0, 0xe0, 0x57, 0x7d, 0xe4, 0x78, 0x65, 0xef, + 0xae, 0xc2, 0xfe, 0x7a, 0x56, 0xaf, 0x03, 0x71, 0x2b, 0xe6, 0xa1, 0x7e, + 0xe5, 0x12, 0xf8, 0xc3, 0x75, 0xc7, 0x22, 0x5f, 0x1b, 0x52, 0x90, 0xe5, + 0xdf, 0xba, 0x9d, 0xe2, 0x68, 0xe0, 0xb3, 0x7a, 0x9e, 0x14, 0xff, 0xb5, + 0x0a, 0x80, 0x20, 0x49, 0x88, 0xe9, 0x9c, 0xe4, 0xb5, 0xaf, 0x7e, 0x51, + 0xec, 0xe7, 0xfc, 0x64, 0x65, 0x21, 0x10, 0xc6, 0x1f, 0x7f, 0x93, 0x7d, + 0xd8, 0xf5, 0xd0, 0x98, 0x94, 0x44, 0xf8, 0x49, 0x6a, 0x51, 0x0a, 0x54, + 0xf4, 0x9f, 0xee, 0x3c, 0x56, 0xbf, 0x4c, 0xe4, 0xde, 0x1c, 0x9b, 0x11, + 0x7e, 0x9a, 0x71, 0x11, 0x80, 0x33, 0xd5, 0xb0, 0x9b, 0xef, 0x67, 0x29, + 0xa4, 0x7d, 0x70, 0x31, 0x3f, 0x8b, 0x2e, 0x4a, 0x0f, 0x2c, 0x91, 0x3d, + 0x3e, 0x3d, 0x8c, 0x0a, 0x2b, 0xf1, 0xdd, 0xbf, 0x61, 0xe6, 0xa3, 0xef, + 0x6d, 0x82, 0xc8, 0xb7, 0x5e, 0x2b, 0x83, 0xc9, 0x4e, 0xa0, 0x85, 0x7f, + 0x01, 0x5a, 0xca, 0x6e, 0x90, 0xfa, 0x7e, 0x82, 0x4d, 0x35, 0x7e, 0xe0, + 0x26, 0x40, 0xf4, 0xa6, 0xae, 0xc3, 0x89, 0xf3, 0xca, 0x55, 0x2c, 0xb5, + 0x29, 0x05, 0x94, 0x45, 0xa7, 0x45, 0xf3, 0x3d, 0xbb, 0x53, 0x5e, 0xca, + 0x7c, 0x84, 0x8f, 0x72, 0x98, 0x93, 0x90, 0x1f, 0x56, 0x72, 0xdb, 0xbd, + 0xa9, 0xeb, 0xf9, 0xe9, 0xce, 0xb1, 0x41, 0xc3, 0xaa, 0xa0, 0xc4, 0x74, + 0x23, 0xc1, 0xeb, 0x7d, 0x41, 0xcd, 0xa4, 0x62, 0xec, 0xfc, 0x9a, 0xa4, + 0x16, 0xec, 0x67, 0x41, 0x89, 0xf0, 0x0e, 0xf3, 0xd1, 0xa2, 0x2f, 0xba, + 0x5d, 0x93, 0x36, 0x46, 0xf5, 0x52, 0x64, 0x91, 0xe7, 0x40, 0x91, 0x20, + 0xa1, 0xc9, 0xaa, 0x4c, 0x79, 0xc4, 0xbb, 0x67, 0x79, 0xad, 0x43, 0xab, + 0xba, 0xde, 0xfc, 0xf1, 0x74, 0x81, 0x33, 0xc0, 0x3f, 0x39, 0xd1, 0xd1, + 0xdf, 0xc0, 0x53, 0x33, 0xb2, 0x92, 0x37, 0xe6, 0x86, 0x2a, 0xe4, 0xe1, + 0x7c, 0x98, 0xf7, 0xdb, 0x5c, 0xa9, 0xff, 0x8d, 0x9c, 0xab, 0xe2, 0xf2, + 0xd5, 0xb1, 0x42, 0xa9, 0xf4, 0x97, 0x80, 0xcd, 0xde, 0x25, 0x2e, 0x87, + 0x92, 0xdd, 0xcf, 0xed, 0x67, 0x93, 0x8c, 0x5a, 0x1d, 0xee, 0xcf, 0x9d, + 0x50, 0x8f, 0xa7, 0xe3, 0x5c, 0xa3, 0x68, 0x78, 0x24, 0xeb, 0x60, 0xa3, + 0x8b, 0x36, 0xbb, 0xcb, 0x46, 0xee, 0x77, 0xfb, 0xf8, 0x69, 0x24, 0xd1, + 0xfa, 0xad, 0x76, 0x76, 0x5e, 0x54, 0xe5, 0xb6, 0x36, 0xc6, 0xdd, 0xa9, + 0x6c, 0x44, 0x15, 0xf7, 0x0a, 0xf8, 0xbb, 0xba, 0xec, 0x35, 0xff, 0xc9, + 0xd6, 0x5d, 0xf5, 0x73, 0x4a, 0x15, 0x8f, 0x7b, 0x6e, 0xf4, 0xa0, 0x6d, + 0x10, 0xbb, 0x67, 0x0c, 0xb4, 0x69, 0xad, 0xb6, 0x40, 0xf7, 0x5f, 0x37, + 0x28, 0xc4, 0x08, 0x49, 0xd0, 0x16, 0x70, 0x80, 0xea, 0x55, 0x66, 0x07, + 0xc8, 0x03, 0x1b, 0xf6, 0xd3, 0x03, 0x04, 0x74, 0xe0, 0x50, 0x3f, 0xd2, + 0x53, 0x92, 0xa0, 0x9d, 0x59, 0xc9, 0x74, 0xf2, 0x7e, 0x3b, 0x33, 0x02, + 0x10, 0x0b, 0x39, 0xf7, 0x4f, 0x6b, 0x58, 0xb2, 0x1a, 0xda, 0x65, 0x44, + 0xd1, 0x7c, 0x3f, 0xd7, 0xe3, 0xac, 0xe2, 0x1f, 0x38, 0xc1, 0x6a, 0xb0, + 0xdc, 0xc3, 0x9c, 0x7b, 0x11, 0x3c, 0x05, 0x21, 0x96, 0x76, 0x98, 0x76, + 0x82, 0xc1, 0x54, 0xdf, 0xdc, 0x8f, 0x4c, 0xd2, 0x63, 0x04, 0x06, 0x77, + 0x36, 0xe6, 0x2e, 0xd1, 0x00, 0x28, 0x42, 0x7c, 0x4a, 0x27, 0x90, 0x46, + 0xc9, 0xce, 0x33, 0x1c, 0xae, 0xda, 0x79, 0x64, 0x7f, 0x52, 0x3f, 0x58, + 0x11, 0x76, 0x4a, 0xb6, 0x72, 0xd8, 0x76, 0xae, 0xfd, 0x5c, 0x57, 0x69, + 0x76, 0x91, 0x84, 0x21, 0xc4, 0x9b, 0xd8, 0xa2, 0xff, 0x93, 0x02, 0x77, + 0x61, 0x57, 0x96, 0x7b, 0x8e, 0xfc, 0xf2, 0x6c, 0x11, 0x2b, 0x5e, 0x88, + 0x5c, 0x17, 0x1d, 0x12, 0x79, 0x3a, 0x78, 0xb6, 0x9d, 0x70, 0xfa, 0xd4, + 0xc1, 0x5c, 0x90, 0x0e, 0x0a, 0xd1, 0x3c, 0x7d, 0xcf, 0xee, 0x8a, 0xb2, + 0xb2, 0x4d, 0xce, 0x89, 0x32, 0xa9, 0x6c, 0x56, 0x57, 0x85, 0xb1, 0xbf, + 0x18, 0x1d, 0xc6, 0xe1, 0x17, 0xc5, 0x92, 0x42, 0x99, 0xf9, 0x9f, 0x04, + 0xec, 0x38, 0xf8, 0xa0, 0xd2, 0xab, 0xe6, 0x13, 0x4d, 0x9c, 0x18, 0x86, + 0x3e, 0x18, 0x73, 0x2c, 0xac, 0xe0, 0xb9, 0xf9, 0x87, 0x74, 0xb8, 0xd7, + 0x47, 0x6e, 0x42, 0xfc, 0x29, 0xa0, 0x1f, 0x56, 0x68, 0xb6, 0x23, 0x96, + 0xa2, 0x8d, 0x54, 0x81, 0x0f, 0x60, 0xb9, 0xde, 0x93, 0xfc, 0xfd, 0xde, + 0xbe, 0xb3, 0xb5, 0x87, 0xec, 0x9f, 0x17, 0xc2, 0x77, 0x6e, 0xa0, 0x62, + 0xdb, 0x66, 0xba, 0xc5, 0x05, 0x12, 0x46, 0x5d, 0x3c, 0x23, 0x29, 0x68, + 0xe5, 0x31, 0xe3, 0x15, 0xec, 0xac, 0x15, 0x9a, 0xbf, 0x42, 0x65, 0x80, + 0x45, 0x9c, 0x1d, 0xc2, 0x0e, 0x18, 0x47, 0x40, 0x44, 0xc1, 0x55, 0x24, + 0x5a, 0x35, 0xad, 0x59, 0xd2, 0xc6, 0xc3, 0x68, 0x58, 0xbd, 0x6f, 0xcf, + 0x5d, 0xb1, 0x9b, 0x0c, 0x92, 0x39, 0x22, 0x49, 0x66, 0x2e, 0x03, 0x7b, + 0x75, 0x5c, 0x6c, 0xde, 0x37, 0x54, 0xa9, 0x07, 0x2f, 0x7e, 0xc1, 0x3e, + 0x3b, 0xab, 0xd2, 0xa9, 0xfa, 0xc7, 0x6b, 0xd5, 0x14, 0x08, 0x35, 0x89, + 0x0b, 0x31, 0x18, 0x54, 0x7d, 0x6b, 0x53, 0x80, 0x6e, 0x32, 0x9b, 0xff, + 0x61, 0x7f, 0x36, 0xe5, 0x28, 0x40, 0xbc, 0xc7, 0x19, 0xb3, 0xae, 0xfa, + 0x95, 0xa8, 0xae, 0xd2, 0x97, 0x72, 0xc6, 0x91, 0x36, 0x3a, 0xa6, 0xec, + 0x4a, 0x41, 0x63, 0x6b, 0x28, 0xef, 0x5a, 0xa1, 0xdb, 0xf2, 0xd9, 0xfd, + 0x61, 0x72, 0xa4, 0xd2, 0x9e, 0xf7, 0x47, 0xf4, 0x4e, 0xea, 0x2a, 0xa5, + 0x35, 0xe1, 0x77, 0x3a, 0x53, 0x28, 0xa6, 0x55, 0x48, 0x0c, 0x1e, 0x44, + 0xfc, 0xc1, 0x31, 0x5a, 0x00, 0xcd, 0x29, 0xc1, 0x5c, 0xca, 0x2a, 0x07, + 0x01, 0x63, 0xac, 0xb3, 0xfb, 0xf6, 0x0b, 0xac, 0xfd, 0xe8, 0x7b, 0xed, + 0xf9, 0x3d, 0x9a, 0xbc, 0x67, 0x28, 0x1c, 0xd9, 0x3f, 0x97, 0x28, 0x4a, + 0xe7, 0xd0, 0x08, 0xe9, 0x3e, 0xa0, 0xcb, 0x0f, 0xe0, 0x3f, 0x1b, 0x80, + 0x43, 0x74, 0xd9, 0x9d, 0x0b, 0x22, 0x81, 0xf7, 0xec, 0x71, 0x2a, 0x29, + 0x9e, 0x5d, 0x1e, 0x8d, 0xf4, 0x22, 0x95, 0x78, 0x86, 0xcb, 0xf0, 0x9d, + 0xe7, 0x6a, 0x66, 0x7e, 0x28, 0xb5, 0x47, 0xb6, 0xdc, 0x0d, 0x03, 0x3c, + 0x09, 0x58, 0x76, 0x93, 0x39, 0xb2, 0xd3, 0x75, 0xb4, 0x51, 0x55, 0x84, + 0x30, 0x24, 0x0a, 0x76, 0xf4, 0x97, 0xe7, 0x0f, 0x5a, 0x67, 0xee, 0xf4, + 0xc7, 0x69, 0x8d, 0xf2, 0x32, 0x29, 0x5c, 0x33, 0x82, 0x5f, 0x6c, 0x47, + 0xd0, 0xe2, 0xbd, 0x62, 0xd6, 0x4c, 0x6d, 0x0d, 0xba, 0x87, 0xd3, 0x43, + 0x7e, 0x2d, 0xa6, 0x14, 0x09, 0x4f, 0x3b, 0xc3, 0x04, 0x14, 0xe5, 0x65, + 0xe9, 0x3b, 0x6a, 0xca, 0xb5, 0x96, 0x84, 0x3f, 0x53, 0x49, 0x22, 0x45, + 0x91, 0xff, 0xf9, 0x26, 0x75, 0x0d, 0x9c, 0xa7, 0x00, 0xf4, 0x65, 0xc4, + 0x60, 0x72, 0xab, 0xeb, 0xf8, 0xa8, 0x72, 0xfe, 0xd8, 0xde, 0x93, 0x67, + 0xcb, 0x09, 0xcc, 0xa0, 0xce, 0x9f, 0x67, 0x63, 0x26, 0xfa, 0x7f, 0x89, + 0xaa, 0x3e, 0x6d, 0xb2, 0x90, 0xd7, 0xef, 0x3e, 0x2a, 0x66, 0x26, 0x33, + 0xe6, 0x26, 0xc1, 0x58, 0xf8, 0x91, 0xea, 0x2f, 0xd0, 0x84, 0x21, 0x41, + 0x93, 0xa6, 0x36, 0x40, 0xb5, 0x4c, 0xac, 0x21, 0x88, 0x37, 0x47, 0x8a, + 0xb8, 0xf3, 0x33, 0x73, 0x12, 0xd7, 0x5a, 0x55, 0xf9, 0xd1, 0x1e, 0x75, + 0xa4, 0x66, 0x68, 0x3f, 0xf7, 0xb2, 0xc4, 0x5d, 0x1b, 0xb1, 0x61, 0x0f, + 0xaf, 0x4b, 0x9b, 0x20, 0x2b, 0x05, 0x68, 0x1c, 0x6c, 0x97, 0x8d, 0xb8, + 0x7b, 0x96, 0xda, 0xe0, 0x67, 0x15, 0x4c, 0x51, 0x71, 0x0d, 0xd3, 0x7b, + 0xde, 0xaa, 0xd3, 0x58, 0xf5, 0xc9, 0x62, 0x0a, 0xc2, 0x33, 0x1f, 0xf3, + 0xc3, 0x30, 0xb5, 0x64, 0xd1, 0x59, 0x41, 0x0e, 0xae, 0xaa, 0x0d, 0xdf, + 0x9f, 0x5d, 0x3f, 0x15, 0x0d, 0x46, 0x7a, 0x6d, 0x2e, 0x29, 0x1b, 0xc0, + 0xd3, 0x11, 0x10, 0x5d, 0xdc, 0x6a, 0x35, 0x8c, 0x43, 0xc8, 0x9f, 0x05, + 0x80, 0xdc, 0x25, 0x24, 0x37, 0x70, 0x7e, 0x1c, 0xe9, 0x85, 0x5a, 0xef, + 0x83, 0x3a, 0x55, 0x68, 0x83, 0x17, 0xf4, 0xc7, 0xae, 0xe4, 0x84, 0xc9, + 0x64, 0x5d, 0x2f, 0xb6, 0xca, 0x10, 0x95, 0xb8, 0xd6, 0x80, 0xfd, 0x05, + 0xa5, 0x06, 0x32, 0x34, 0x91, 0x01, 0xd2, 0x02, 0x90, 0xe1, 0xf7, 0x89, + 0x8a, 0xee, 0x18, 0x04, 0x93, 0xd9, 0xb4, 0x63, 0x4b, 0xf7, 0x7a, 0x9c, + 0x1b, 0x4b, 0xf9, 0x31, 0x32, 0xd9, 0xf2, 0x55, 0x4e, 0xc1, 0x02, 0xce, + 0x77, 0x38, 0x36, 0x29, 0xb8, 0x54, 0x8c, 0xc2, 0x27, 0x5f, 0xd9, 0xae, + 0x3e, 0x1e, 0xcd, 0xe9, 0x07, 0x90, 0x4c, 0xe0, 0xda, 0x16, 0x6e, 0xdf, + 0xde, 0x3a, 0x61, 0x89, 0x9f, 0x79, 0xd0, 0xd4, 0x66, 0x95, 0xad, 0xe4, + 0x11, 0x7d, 0xa1, 0xae, 0xec, 0x3e, 0x6e, 0x20, 0x5a, 0xd0, 0x28, 0x0e, + 0x55, 0xec, 0xcf, 0x34, 0xec, 0xb7, 0xfc, 0xa4, 0xb3, 0x8f, 0x56, 0x13, + 0x50, 0xcc, 0x15, 0x10, 0x74, 0x40, 0x72, 0x42, 0x20, 0x22, 0xb3, 0xaf, + 0xf3, 0x68, 0xba, 0x95, 0x45, 0xcb, 0xef, 0x92, 0xd5, 0x14, 0x4c, 0x1f, + 0xe3, 0xc1, 0xa6, 0x03, 0x4e, 0x05, 0xd2, 0x1a, 0xee, 0xd2, 0x48, 0x44, + 0x2e, 0x50, 0x3b, 0x86, 0xc8, 0x6a, 0xc8, 0x4c, 0xca, 0x2a, 0xb6, 0xf7, + 0x3c, 0xaf, 0xdc, 0x62, 0xb1, 0x49, 0x13, 0xfe, 0xe7, 0x32, 0xea, 0x78, + 0xfa, 0xba, 0xcf, 0x15, 0x47, 0x58, 0xdc, 0x19, 0x73, 0x1d, 0xff, 0xbd, + 0xcc, 0x27, 0xf6, 0xfc, 0x66, 0x68, 0xa7, 0x29, 0xaf, 0x2b, 0x25, 0x0c, + 0x15, 0x47, 0xff, 0xc1, 0x00, 0x9d, 0xfa, 0x58, 0x9c, 0xaa, 0xf9, 0xcc, + 0x4c, 0x51, 0x1d, 0xda, 0xf3, 0x3c, 0x10, 0xd0, 0x3b, 0x59, 0x30, 0x02, + 0x68, 0x29, 0x1c, 0xa7, 0x22, 0xea, 0x81, 0xd3, 0x29, 0x71, 0x39, 0xe8, + 0x72, 0x7f, 0x7d, 0x94, 0x0a, 0x64, 0x2c, 0xe6, 0x55, 0xfb, 0x90, 0x78, + 0x7e, 0x6c, 0x3e, 0xfe, 0x57, 0x14, 0x61, 0xef, 0xe2, 0x63, 0x57, 0x6c, + 0x13, 0x97, 0x27, 0x2b, 0x38, 0x44, 0xab, 0x74, 0x76, 0x11, 0xa6, 0x60, + 0xad, 0x8e, 0xad, 0xe5, 0xa5, 0xa1, 0x66, 0xc5, 0xe1, 0x4d, 0x27, 0xa0, + 0x79, 0x7a, 0x09, 0xe6, 0xf0, 0x28, 0x3f, 0xcb, 0xc6, 0xf8, 0x94, 0xc0, + 0xf1, 0x13, 0xbe, 0x62, 0x6a, 0x52, 0x75, 0x52, 0xd3, 0x82, 0x31, 0xbd, + 0x15, 0xf2, 0xe8, 0x2e, 0xb1, 0x62, 0x03, 0x1e, 0xe2, 0xb3, 0xec, 0xbc, + 0x3c, 0x12, 0xca, 0x62, 0x4e, 0xc2, 0x3a, 0x51, 0x1c, 0xdf, 0xa2, 0x84, + 0x88, 0xe5, 0x7e, 0xd7, 0x5d, 0xd7, 0xbf, 0xf2, 0x7d, 0xbd, 0x9a, 0x90, + 0x63, 0xfd, 0x8a, 0x84, 0x2b, 0x9d, 0x89, 0x27, 0x63, 0x4c, 0x0a, 0xe3, + 0x70, 0x94, 0x7b, 0xe6, 0xb3, 0xd7, 0xcb, 0xcb, 0x8a, 0xeb, 0x6b, 0x53, + 0x34, 0x2f, 0x62, 0x44, 0x2d, 0x73, 0x63, 0x8a, 0xf4, 0xa2, 0x01, 0xd7, + 0x12, 0xb6, 0x8d, 0x8c, 0x4b, 0x73, 0x2b, 0x44, 0x50, 0x49, 0x6f, 0x01, + 0xac, 0xc5, 0x15, 0x37, 0x6c, 0xde, 0xd4, 0x02, 0xb1, 0x12, 0x80, 0x73, + 0xb2, 0x52, 0x0e, 0xe0, 0xb5, 0x75, 0xc9, 0x48, 0xcf, 0x18, 0x5c, 0xcc, + 0xaf, 0x58, 0xa2, 0x3e, 0x28, 0xe4, 0xab, 0xde, 0xea, 0x2a, 0xcf, 0x58, + 0x22, 0xc4, 0x68, 0xea, 0x9b, 0x7b, 0x90, 0xc5, 0xdc, 0x1c, 0x37, 0xd1, + 0x8a, 0x4f, 0xe7, 0x24, 0x23, 0x39, 0xb9, 0x62, 0xb8, 0x41, 0x13, 0x7b, + 0xe2, 0x1e, 0x0d, 0x4e, 0x38, 0x11, 0xa3, 0xb9, 0x10, 0xbb, 0x10, 0x6f, + 0x40, 0x9f, 0x50, 0x05, 0xc7, 0x0e, 0xb9, 0x9e, 0xab, 0x7c, 0x3c, 0x78, + 0xce, 0x54, 0xbf, 0xbf, 0x40, 0x36, 0x76, 0xbc, 0x4b, 0x64, 0x32, 0xca, + 0x0e, 0x2d, 0x91, 0x87, 0xd5, 0x00, 0x19, 0xbf, 0x12, 0xd0, 0x35, 0x7c, + 0xa1, 0xe5, 0xcf, 0x7a, 0x2d, 0x08, 0x62, 0xed, 0x34, 0x61, 0xe3, 0xda, + 0x2c, 0xcc, 0x1b, 0xf8, 0x12, 0xfe, 0xfd, 0x19, 0xa2, 0xc3, 0x70, 0xfd, + 0x4f, 0x5b, 0x5d, 0x20, 0xd2, 0xe1, 0xc5, 0xac, 0xe7, 0xa1, 0x84, 0x00, + 0xbd, 0x46, 0x81, 0xfd, 0x54, 0x69, 0xed, 0x1a, 0x7a, 0x32, 0xbb, 0x75, + 0x22, 0x76, 0x6d, 0x34, 0x24, 0xcc, 0xe6, 0xbe, 0x78, 0x5a, 0x75, 0x6c, + 0xbc, 0x62, 0xb8, 0x14, 0xf7, 0x13, 0x73, 0xc2, 0xdc, 0xb6, 0xfa, 0xfb, + 0x97, 0xfe, 0x27, 0x7b, 0x33, 0xb8, 0xeb, 0x20, 0xd2, 0x0f, 0x4f, 0xed, + 0xd1, 0xd0, 0x63, 0xf7, 0xc5, 0x8e, 0xec, 0xcc, 0xd2, 0x31, 0x38, 0x35, + 0x65, 0x33, 0x5c, 0x63, 0x85, 0xf7, 0x3d, 0xc3, 0x62, 0x26, 0x52, 0x0a, + 0x67, 0xda, 0x87, 0x1f, 0x9e, 0x47, 0xec, 0x6b, 0xf5, 0x74, 0x1a, 0xc5, + 0xa7, 0xa0, 0x0f, 0xdd, 0xc5, 0x42, 0xf4, 0xda, 0x41, 0x1a, 0x48, 0xa9, + 0xbe, 0x4f, 0xb6, 0x28, 0x17, 0xe9, 0xf5, 0xd7, 0x00, 0xb3, 0xfe, 0x05, + 0x4e, 0xa7, 0xdf, 0x65, 0x7a, 0xb8, 0x4f, 0xe0, 0xfe, 0x58, 0x9e, 0xba, + 0x45, 0x11, 0xba, 0xc2, 0xdb, 0x97, 0x97, 0xa4, 0xbc, 0x18, 0x21, 0x1b, + 0xad, 0x82, 0xef, 0xb1, 0x5f, 0x2f, 0x25, 0x9d, 0xca, 0x52, 0xa5, 0x6d, + 0x8c, 0xab, 0x07, 0x2b, 0x7b, 0x6a, 0x77, 0x9d, 0xdf, 0xfb, 0xae, 0x6e, + 0x49, 0x18, 0x25, 0x4a, 0xf2, 0x7d, 0xa0, 0x32, 0xc8, 0x53, 0x10, 0xc3, + 0xf2, 0xef, 0xf3, 0xe7, 0x79, 0xd7, 0x6a, 0x0e, 0x61, 0xff, 0x89, 0xc9, + 0x42, 0xe8, 0x6e, 0x4f, 0x78, 0xe1, 0x5f, 0xcd, 0x7a, 0xf6, 0x27, 0x72, + 0x67, 0xea, 0x0b, 0xa6, 0xcc, 0x34, 0xb7, 0x8f, 0x92, 0x3c, 0x95, 0xb9, + 0x0a, 0x5d, 0x49, 0x2e, 0xb7, 0x7d, 0x31, 0x9c, 0x79, 0x61, 0x95, 0x9c, + 0x60, 0x56, 0x8d, 0x35, 0x00, 0xc5, 0x8b, 0xe6, 0x02, 0x0f, 0x26, 0x39, + 0x7b, 0x93, 0x94, 0xb1, 0xcd, 0xde, 0xed, 0xfa, 0x2a, 0x4b, 0x63, 0xa8, + 0x1b, 0x31, 0x43, 0x5e, 0x69, 0x7c, 0xd6, 0x15, 0x35, 0x9c, 0xa2, 0xd7, + 0xdf, 0x0e, 0x1a, 0x20, 0x50, 0xf5, 0x02, 0x21, 0x30, 0x35, 0x3c, 0x60, + 0x71, 0xad, 0xd0, 0xe3, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x10, 0x17, 0x1d, 0x22, 0x2d}; +#elif MLD_CONFIG_PARAMETER_SET == 87 +const uint8_t expected_signature[] = { + 0xdf, 0xe6, 0xe1, 0xa5, 0x20, 0xc1, 0xac, 0x98, 0x55, 0x2c, 0xf2, 0x13, + 0x65, 0x42, 0xe2, 0xb0, 0x77, 0x5f, 0x15, 0x00, 0x8f, 0x14, 0x48, 0xa1, + 0xe3, 0xee, 0x81, 0x35, 0x15, 0x34, 0xad, 0x6e, 0x60, 0x85, 0x00, 0xf8, + 0x18, 0x53, 0x0d, 0xa0, 0xc5, 0x41, 0xc4, 0x48, 0x09, 0x1b, 0x34, 0x0c, + 0x0e, 0xcf, 0xc6, 0x3d, 0x38, 0x78, 0x8b, 0x69, 0xe5, 0x6f, 0x4d, 0x43, + 0xfa, 0xa6, 0x75, 0x26, 0x8a, 0x75, 0x97, 0x10, 0x6a, 0x1f, 0x3c, 0xa6, + 0x94, 0xa9, 0x93, 0x8f, 0xe5, 0x62, 0xbf, 0x94, 0xe4, 0xd0, 0x0d, 0x11, + 0x4d, 0x03, 0xe2, 0xd8, 0xdf, 0x68, 0xb7, 0x87, 0x62, 0xc9, 0xdc, 0xc9, + 0x36, 0x4f, 0xcc, 0xd1, 0xa4, 0xae, 0x7e, 0xa4, 0xb9, 0xaf, 0xaf, 0xf0, + 0x8a, 0xe6, 0xff, 0x83, 0xe7, 0x54, 0x22, 0x6e, 0x3f, 0x2e, 0xa0, 0x4f, + 0xa8, 0x31, 0x53, 0xf3, 0x62, 0xeb, 0x04, 0xfa, 0xd1, 0x57, 0x39, 0x43, + 0xf9, 0xe0, 0x31, 0x12, 0x45, 0x09, 0x8b, 0x9e, 0x1e, 0x7a, 0x2b, 0x85, + 0xee, 0xdd, 0xe8, 0x1e, 0xd7, 0xc0, 0x17, 0xb4, 0xd2, 0xdc, 0x36, 0xa9, + 0xe4, 0x49, 0x88, 0xbf, 0x71, 0x43, 0x9d, 0x3e, 0xd2, 0x10, 0xe7, 0x82, + 0xb5, 0xfe, 0xdd, 0x42, 0xc8, 0x1b, 0x11, 0xf6, 0x52, 0x23, 0x98, 0x83, + 0x48, 0xec, 0xec, 0x70, 0x8b, 0xe7, 0x49, 0x9a, 0xd7, 0xd9, 0x7b, 0x47, + 0x4e, 0xe2, 0x5e, 0x17, 0x1a, 0xa0, 0x0e, 0x60, 0x85, 0x3a, 0x30, 0x8c, + 0x1c, 0x26, 0xb4, 0xe1, 0xb5, 0x2b, 0x48, 0xf4, 0xb8, 0x93, 0x2f, 0x79, + 0x3a, 0x1e, 0xb6, 0x3b, 0x07, 0x3b, 0x1e, 0x15, 0xd7, 0x85, 0x5e, 0xd4, + 0x06, 0x0e, 0xcd, 0x6a, 0x93, 0x3a, 0x93, 0x29, 0x6a, 0xbe, 0x68, 0x8a, + 0xb6, 0xb8, 0xfa, 0xc5, 0x63, 0x48, 0x98, 0x10, 0x6d, 0xd9, 0xd3, 0x5b, + 0x29, 0x5f, 0x93, 0x90, 0x08, 0x1c, 0x1a, 0x15, 0x7b, 0x0a, 0x59, 0x9d, + 0x64, 0x24, 0x45, 0xb6, 0xd3, 0x7b, 0xc1, 0x5d, 0x74, 0x1f, 0x0b, 0x8e, + 0x18, 0xf2, 0x92, 0x8e, 0xd4, 0x7f, 0x72, 0x5c, 0x98, 0x1f, 0x8b, 0xa5, + 0xb8, 0xf4, 0x7e, 0x12, 0x6a, 0x93, 0xb9, 0xb5, 0xf1, 0xda, 0x97, 0x75, + 0x4f, 0x56, 0x80, 0x88, 0x64, 0x2b, 0xe0, 0x59, 0xcd, 0x5e, 0x91, 0x64, + 0x9c, 0x0c, 0xa8, 0xdd, 0xac, 0xcb, 0xf3, 0x48, 0x3b, 0x5c, 0xc4, 0xc5, + 0xb9, 0x9a, 0x0b, 0x8e, 0x5d, 0x9a, 0xd5, 0xb7, 0xf0, 0xd4, 0x07, 0x48, + 0xb9, 0x63, 0x02, 0x87, 0x8d, 0xae, 0x7e, 0x03, 0x33, 0x4f, 0x86, 0x15, + 0x1b, 0x3b, 0xdf, 0xda, 0xce, 0xd3, 0x1e, 0xc0, 0x76, 0xb5, 0x1c, 0xdd, + 0xb8, 0x32, 0x87, 0x7d, 0x59, 0x18, 0x72, 0x0c, 0xde, 0x8f, 0x63, 0x2d, + 0x38, 0xf2, 0xe9, 0xc2, 0x81, 0xed, 0xfa, 0x2d, 0x61, 0xef, 0x48, 0xdb, + 0xa2, 0xeb, 0xfe, 0x52, 0x31, 0x1e, 0x21, 0x0a, 0x08, 0xf6, 0x02, 0xd3, + 0xc0, 0x32, 0x3b, 0x6b, 0x2f, 0x64, 0xc4, 0xb3, 0x4b, 0xfe, 0x69, 0x78, + 0xbf, 0x20, 0x62, 0x07, 0x77, 0xdf, 0x2c, 0x18, 0x53, 0x61, 0x8e, 0x05, + 0x01, 0x86, 0xab, 0xab, 0xec, 0x18, 0x8c, 0x15, 0x63, 0x1f, 0xe9, 0x99, + 0xb2, 0x35, 0x77, 0xe1, 0x58, 0xf1, 0xa9, 0x4d, 0x1a, 0xb9, 0x8c, 0x30, + 0x63, 0x6f, 0x9e, 0x7d, 0x4e, 0xcf, 0xb5, 0x6c, 0xf3, 0xe4, 0xdc, 0xab, + 0xf9, 0xae, 0x58, 0xf8, 0x1d, 0x08, 0x7b, 0x73, 0x82, 0x58, 0xc8, 0x67, + 0x48, 0x1a, 0x5e, 0x3d, 0xdb, 0xac, 0x1b, 0x1b, 0xef, 0xeb, 0xa4, 0xe5, + 0x67, 0x48, 0x76, 0xd1, 0x96, 0x4f, 0x6c, 0x7d, 0x06, 0x8c, 0x02, 0x86, + 0x95, 0x83, 0xb6, 0x9b, 0x5e, 0x9a, 0xb5, 0x85, 0xc0, 0x4f, 0x13, 0x1c, + 0x32, 0xf8, 0x29, 0xdf, 0x47, 0x85, 0xdb, 0xe4, 0x37, 0xdc, 0xd8, 0x04, + 0x18, 0xdd, 0xca, 0x97, 0xdd, 0x67, 0x13, 0xbe, 0x74, 0x95, 0xdc, 0xd0, + 0xcc, 0xe6, 0xb5, 0xa5, 0x12, 0x9b, 0x23, 0x4f, 0x41, 0x8c, 0xcc, 0x95, + 0xf4, 0xb0, 0x5f, 0x2a, 0xc4, 0xbf, 0x88, 0xda, 0x55, 0xcb, 0x13, 0x93, + 0x22, 0x60, 0x51, 0x43, 0xc7, 0x9a, 0x2c, 0xfa, 0xb2, 0x59, 0xc1, 0xe6, + 0x8a, 0xa4, 0xb8, 0xfb, 0xd3, 0x31, 0x1d, 0xc7, 0x88, 0xdc, 0xbc, 0xe9, + 0xba, 0xe7, 0xdc, 0xe3, 0xdd, 0x90, 0x96, 0xb4, 0xb4, 0x0a, 0xc1, 0x07, + 0x31, 0x3f, 0xdb, 0xc5, 0x4d, 0x73, 0x58, 0x86, 0x15, 0x37, 0x07, 0x86, + 0x03, 0x17, 0x16, 0x18, 0x15, 0xb9, 0x26, 0x35, 0x8a, 0x43, 0x22, 0xae, + 0x21, 0x52, 0x05, 0x4e, 0x5c, 0x3f, 0x3e, 0xb9, 0x2a, 0x19, 0x13, 0xfd, + 0x31, 0x47, 0x6a, 0x74, 0xaa, 0xb9, 0xc6, 0x2c, 0x13, 0x8c, 0x21, 0xc4, + 0x8d, 0x00, 0xf4, 0x24, 0xf2, 0xb7, 0xd3, 0x13, 0xad, 0x29, 0x5e, 0x50, + 0x0b, 0x0e, 0x9f, 0x9a, 0xb7, 0xf6, 0x9e, 0xba, 0x12, 0x23, 0x84, 0x8c, + 0xbe, 0x2c, 0x14, 0x1e, 0xe6, 0x79, 0x15, 0x20, 0x2d, 0x32, 0x08, 0xd8, + 0x1c, 0x87, 0x1b, 0xa8, 0xc0, 0xbb, 0x85, 0xa9, 0x71, 0x30, 0x5e, 0x39, + 0x48, 0x87, 0xdc, 0x3d, 0x03, 0x29, 0x19, 0xd1, 0xd4, 0x21, 0x3a, 0x53, + 0x2d, 0x5e, 0x78, 0xff, 0x94, 0x4b, 0x91, 0xa6, 0xb5, 0xe5, 0x42, 0x56, + 0x67, 0x6a, 0x0e, 0xf3, 0x2d, 0x6a, 0x4e, 0xd7, 0x3a, 0x81, 0xb1, 0x4d, + 0x0b, 0x66, 0x5f, 0x43, 0x28, 0x7c, 0x75, 0x8b, 0x2b, 0x99, 0x24, 0xc2, + 0x5e, 0x8c, 0x22, 0xf0, 0xd5, 0xb3, 0xfc, 0x86, 0x62, 0xf3, 0xd2, 0x6c, + 0xa7, 0x48, 0x04, 0x44, 0x5d, 0x93, 0x74, 0x37, 0x16, 0x2c, 0x19, 0x12, + 0x57, 0x49, 0xef, 0xd5, 0xd6, 0x92, 0xdc, 0x51, 0xf8, 0x55, 0x3a, 0xc0, + 0x0b, 0xdf, 0x41, 0xb5, 0x01, 0x59, 0x7e, 0x85, 0x65, 0xdb, 0x44, 0xbd, + 0x04, 0x96, 0x1a, 0xd4, 0x6e, 0x22, 0x54, 0x92, 0xdb, 0xc7, 0xc5, 0x3a, + 0xdf, 0x0c, 0xf4, 0x1b, 0xdc, 0x14, 0xf6, 0x91, 0x9c, 0xbe, 0xf8, 0x8e, + 0x70, 0xd1, 0x3a, 0x0e, 0x58, 0xe6, 0xb9, 0xd3, 0xaa, 0xa2, 0x70, 0xba, + 0xdd, 0x16, 0x13, 0x19, 0xd1, 0x96, 0x78, 0x04, 0x2f, 0xd7, 0x38, 0x8c, + 0x35, 0x1f, 0xfc, 0x58, 0xa4, 0x4c, 0xa9, 0x9a, 0xae, 0x13, 0x3b, 0xc1, + 0x20, 0x4b, 0x66, 0x0f, 0x72, 0x42, 0x0a, 0x53, 0x84, 0x54, 0x71, 0x06, + 0xdb, 0x85, 0x8f, 0x40, 0xa6, 0x09, 0xf7, 0x24, 0xc4, 0x35, 0xf7, 0x1d, + 0xd4, 0x3d, 0x54, 0x75, 0xaf, 0xc4, 0x78, 0x0f, 0xce, 0xe0, 0x0c, 0x90, + 0x0f, 0xd5, 0x2e, 0x61, 0xf7, 0x58, 0xaa, 0xf0, 0xc7, 0x37, 0x5a, 0x59, + 0x1f, 0x8a, 0x03, 0x98, 0x43, 0xb7, 0x27, 0x78, 0x4e, 0x44, 0x5a, 0xb5, + 0x29, 0xf5, 0xab, 0x9e, 0xb7, 0x2a, 0xc4, 0xa3, 0x03, 0x00, 0xe3, 0x28, + 0x57, 0xc9, 0x2a, 0x98, 0xb8, 0xa1, 0x45, 0x1d, 0xfa, 0x6e, 0xb3, 0x0d, + 0x42, 0x5a, 0xb6, 0xb1, 0x0e, 0x5c, 0xbe, 0x82, 0xe2, 0x36, 0x40, 0x4b, + 0x05, 0x28, 0xd9, 0xbc, 0x27, 0xd6, 0x77, 0x00, 0xc9, 0x29, 0x6a, 0xd6, + 0x19, 0x8f, 0x8d, 0xda, 0xe1, 0xc3, 0x8b, 0x69, 0x71, 0xd0, 0xf7, 0xc8, + 0x33, 0xef, 0xe6, 0x23, 0x6b, 0xcb, 0x00, 0x56, 0x0a, 0x9b, 0x9d, 0x60, + 0x3a, 0xd3, 0xad, 0xd9, 0x5c, 0x6a, 0x7d, 0xab, 0x35, 0x71, 0x93, 0xc5, + 0xf2, 0x6a, 0x38, 0x0e, 0xfb, 0xd9, 0x9b, 0xa5, 0xda, 0x52, 0x45, 0xef, + 0x93, 0x94, 0x5b, 0x08, 0x8c, 0x07, 0xab, 0x2e, 0x99, 0x88, 0x77, 0xb5, + 0x15, 0x66, 0x7f, 0x0e, 0xfa, 0xb0, 0x29, 0xe4, 0x88, 0xd9, 0xdd, 0x22, + 0xaf, 0x7a, 0x4e, 0xb5, 0xd0, 0x62, 0x85, 0x27, 0x33, 0xf1, 0xb7, 0x34, + 0xb1, 0xe6, 0xda, 0x9f, 0x3c, 0xfe, 0xf5, 0xd4, 0xef, 0x56, 0x48, 0x93, + 0x7a, 0x54, 0xa2, 0x7f, 0x07, 0xea, 0x31, 0xb8, 0x8b, 0xca, 0xb9, 0xdb, + 0x1e, 0x2b, 0xb5, 0x16, 0xe6, 0x0e, 0xd9, 0x3f, 0x7c, 0xf0, 0xc2, 0x3e, + 0x57, 0x64, 0x60, 0x97, 0xfb, 0xdf, 0x8c, 0x3e, 0x56, 0x22, 0x92, 0x2a, + 0xb2, 0x21, 0x00, 0x0a, 0x75, 0x89, 0x68, 0xe7, 0x51, 0xa3, 0x63, 0x05, + 0xe1, 0x6f, 0x1e, 0x1e, 0x80, 0xa2, 0x4b, 0x5d, 0xb7, 0xf4, 0xb7, 0x45, + 0x85, 0x00, 0x84, 0x6e, 0xbe, 0x0b, 0x67, 0xbf, 0x21, 0x06, 0x5a, 0x56, + 0x79, 0xe9, 0x6b, 0x0e, 0x72, 0x19, 0x2d, 0x09, 0x78, 0xd5, 0x5e, 0xc2, + 0x32, 0xee, 0x29, 0xd4, 0x7a, 0x65, 0xc7, 0xfe, 0x16, 0x86, 0xd2, 0x29, + 0x71, 0xe5, 0x91, 0x0e, 0x3e, 0x86, 0xd5, 0x00, 0xc4, 0xfc, 0xd9, 0xae, + 0xd3, 0x7c, 0x13, 0xfd, 0x62, 0xce, 0x0c, 0xb2, 0xe5, 0x1f, 0x6d, 0xed, + 0x55, 0x6f, 0xc1, 0xaa, 0xa1, 0x74, 0x59, 0x46, 0x83, 0xd5, 0x5d, 0x71, + 0x17, 0x13, 0x1d, 0x0b, 0x25, 0xfb, 0x0a, 0xcd, 0x67, 0xfe, 0x57, 0x93, + 0xc2, 0x71, 0x55, 0x6c, 0x68, 0xfa, 0x40, 0xdb, 0xdd, 0xce, 0xd5, 0x5c, + 0xce, 0x0a, 0x1d, 0xfa, 0x19, 0x30, 0xe2, 0x2b, 0x63, 0x98, 0x16, 0x2c, + 0x67, 0x69, 0x55, 0xe5, 0xc1, 0x6c, 0x6e, 0xb7, 0x92, 0x6a, 0xbb, 0x10, + 0xd3, 0x13, 0x2e, 0x73, 0x91, 0x74, 0xcb, 0x9f, 0x5c, 0x7f, 0x5c, 0x48, + 0x58, 0x36, 0x13, 0x47, 0xf7, 0x49, 0xae, 0x90, 0x15, 0x53, 0xb5, 0xe6, + 0x37, 0xfb, 0x81, 0x47, 0xb4, 0x69, 0x84, 0xca, 0x95, 0xab, 0x19, 0x2a, + 0x28, 0xc2, 0x8a, 0xf1, 0xcd, 0xf9, 0x3e, 0xd3, 0xaf, 0xe1, 0x75, 0xf7, + 0x94, 0x74, 0x1c, 0xf5, 0x32, 0xcf, 0x70, 0xbd, 0x69, 0xcc, 0xa8, 0x3c, + 0xca, 0x59, 0x53, 0xfa, 0xcb, 0xe7, 0xb6, 0x36, 0x70, 0xea, 0xe2, 0x84, + 0xfa, 0x5e, 0xbd, 0xd7, 0x59, 0x3d, 0x21, 0xc6, 0x9f, 0x5c, 0x1f, 0xa6, + 0xa9, 0xf1, 0xd3, 0x26, 0x9e, 0xff, 0xbc, 0x81, 0xfe, 0xbe, 0xee, 0x64, + 0xd9, 0x63, 0x94, 0x4b, 0x15, 0xd8, 0x95, 0xaa, 0xec, 0x10, 0xc9, 0xe2, + 0xe1, 0x05, 0x37, 0x64, 0xc4, 0xb0, 0x2e, 0xa5, 0x0e, 0x4c, 0x2d, 0x03, + 0x53, 0xf1, 0x93, 0x77, 0x9d, 0x46, 0x14, 0x67, 0x48, 0x5f, 0xad, 0x1b, + 0xdc, 0xb9, 0x74, 0xa2, 0x6c, 0xfc, 0xd2, 0xa0, 0x1f, 0x43, 0x89, 0x15, + 0xc5, 0x0c, 0xb0, 0x9e, 0x1e, 0xc2, 0xd6, 0x44, 0xd9, 0x6e, 0xfc, 0xb4, + 0x9c, 0x95, 0x90, 0xcd, 0xc3, 0x17, 0x1c, 0x6a, 0xce, 0x03, 0x56, 0x9f, + 0xe7, 0xcd, 0x7e, 0xe7, 0xa2, 0x0c, 0x2b, 0x0d, 0x59, 0xb0, 0xc9, 0x4c, + 0x6e, 0x33, 0x6d, 0x43, 0xc4, 0x3a, 0x10, 0x24, 0x03, 0x3e, 0x09, 0xb6, + 0x86, 0x13, 0xba, 0x18, 0x19, 0xd3, 0xff, 0xeb, 0xa5, 0x25, 0x8f, 0x6f, + 0xc8, 0xe6, 0x96, 0xa4, 0xd2, 0x66, 0x40, 0x81, 0x79, 0xe8, 0x39, 0x18, + 0x41, 0x02, 0x66, 0x5c, 0x30, 0x5f, 0x58, 0x9d, 0x35, 0x16, 0xc6, 0x96, + 0xa8, 0x68, 0xbc, 0x09, 0x83, 0x17, 0x2c, 0x5f, 0x5e, 0xd0, 0x1d, 0xb0, + 0x48, 0x5e, 0xcf, 0x91, 0x16, 0x4d, 0xa0, 0xba, 0xbc, 0x61, 0xa8, 0x3f, + 0x30, 0x09, 0xbb, 0xa3, 0x12, 0xcd, 0xdc, 0x29, 0xf7, 0xb0, 0xad, 0x05, + 0x17, 0xd6, 0xd3, 0x16, 0xfb, 0xe5, 0x99, 0xf4, 0x71, 0x62, 0xa3, 0x45, + 0x45, 0xc7, 0x9b, 0xaa, 0x45, 0xd3, 0x35, 0xfe, 0xfb, 0x63, 0xaf, 0xe7, + 0x85, 0x31, 0xc9, 0x66, 0x26, 0xa9, 0xda, 0x8c, 0xc6, 0xf6, 0xd5, 0xdf, + 0xb1, 0xa9, 0xf1, 0xb6, 0x3d, 0x92, 0xae, 0x4d, 0xbc, 0x74, 0x7d, 0x76, + 0x5a, 0x59, 0x8c, 0x87, 0xff, 0x95, 0x2f, 0x67, 0x37, 0x30, 0x1a, 0xc1, + 0x23, 0x2e, 0x0c, 0xaa, 0x80, 0x1c, 0xf3, 0xa3, 0x74, 0x94, 0xb2, 0xda, + 0x1a, 0xb8, 0x46, 0xec, 0x30, 0x76, 0xf4, 0xdf, 0xfb, 0x00, 0xb3, 0x6f, + 0x86, 0xc1, 0xc5, 0x3a, 0x5d, 0x11, 0x14, 0x87, 0xeb, 0x30, 0xd8, 0x33, + 0x18, 0x00, 0x01, 0x76, 0x43, 0x82, 0xcd, 0x1c, 0x36, 0x54, 0xd2, 0x64, + 0x5b, 0xfb, 0x93, 0xca, 0x20, 0x1d, 0xa3, 0x20, 0x99, 0xc3, 0x8e, 0x5c, + 0x82, 0xfc, 0x56, 0x07, 0x41, 0x4b, 0x4f, 0x54, 0xc7, 0xb5, 0xe8, 0x6d, + 0x7e, 0xd8, 0x8a, 0x56, 0xb4, 0x76, 0x1e, 0xd3, 0x82, 0x97, 0xdd, 0x2b, + 0xd9, 0x80, 0xb7, 0xb6, 0xeb, 0x3d, 0xe5, 0xe0, 0x20, 0x27, 0x8c, 0xf0, + 0xd6, 0x14, 0xc7, 0xcd, 0x79, 0xbc, 0xa0, 0x21, 0x85, 0xc3, 0x02, 0xae, + 0x73, 0xc4, 0x0a, 0x39, 0x1a, 0x98, 0x61, 0xc3, 0x86, 0xd8, 0x97, 0x67, + 0x87, 0xe9, 0x56, 0x0b, 0x61, 0xa6, 0x7e, 0x07, 0xfb, 0x0a, 0x8b, 0xd1, + 0x90, 0xbd, 0x39, 0x22, 0xdb, 0xc2, 0x7f, 0xaa, 0x79, 0xb7, 0x39, 0x09, + 0xc1, 0x69, 0xdb, 0xe2, 0x7f, 0xec, 0xde, 0x80, 0x7a, 0x6c, 0xde, 0x76, + 0xa4, 0xe8, 0xe0, 0x8d, 0x71, 0xfa, 0x62, 0xf0, 0x2e, 0x7b, 0xf4, 0xce, + 0x65, 0x18, 0x42, 0xde, 0x92, 0x1b, 0xdc, 0xc9, 0xa7, 0x8d, 0xa5, 0x91, + 0x0f, 0xa5, 0x1b, 0x89, 0xcf, 0x29, 0x10, 0x1d, 0x94, 0x78, 0x1b, 0xea, + 0x79, 0x35, 0x62, 0xd4, 0x29, 0xe6, 0x59, 0x8c, 0xc1, 0xd2, 0xf3, 0x32, + 0x71, 0x09, 0xce, 0x51, 0xd7, 0x14, 0x29, 0x92, 0xbf, 0xdf, 0x9a, 0x69, + 0xda, 0x61, 0x03, 0x0f, 0xa2, 0x0a, 0xab, 0x57, 0x1c, 0xca, 0xab, 0x42, + 0x63, 0x63, 0x1e, 0x35, 0x5d, 0x8d, 0xba, 0x6f, 0x4b, 0x6b, 0x5e, 0x7c, + 0xc0, 0x1e, 0xb7, 0xf4, 0x65, 0xbd, 0x13, 0x1c, 0xf2, 0xa9, 0x73, 0x38, + 0xc3, 0x47, 0xc9, 0x32, 0xf0, 0x30, 0x57, 0x05, 0x42, 0x52, 0xac, 0x72, + 0xee, 0x9f, 0x4e, 0x21, 0xbf, 0x38, 0x19, 0x6d, 0x48, 0xec, 0x97, 0xcb, + 0x70, 0x9e, 0xee, 0xb3, 0xa1, 0xaa, 0xa6, 0x7e, 0xe9, 0x16, 0xdf, 0xcd, + 0x1c, 0x56, 0xcf, 0xf0, 0x9f, 0x4d, 0xd1, 0x8c, 0x14, 0x50, 0x5d, 0x23, + 0x96, 0xe0, 0x1f, 0x61, 0x79, 0xbf, 0x44, 0xfd, 0xa2, 0x31, 0xf7, 0x4c, + 0x0c, 0x8d, 0x8c, 0x1b, 0xbf, 0x8d, 0x45, 0xbf, 0x0b, 0xd8, 0xfb, 0x6f, + 0xff, 0x15, 0xc0, 0x44, 0x7c, 0xb9, 0xb8, 0xf9, 0xef, 0x0d, 0x79, 0x11, + 0x3b, 0x79, 0xd2, 0x52, 0x89, 0x5a, 0xcd, 0x0f, 0x10, 0x92, 0x42, 0xfe, + 0xcf, 0x0a, 0x11, 0x8a, 0x8a, 0xda, 0xee, 0xc8, 0x6b, 0xd9, 0xab, 0xec, + 0xb4, 0x25, 0x6f, 0x8d, 0x68, 0x26, 0xe8, 0xdd, 0xf5, 0xa4, 0xe8, 0x65, + 0x37, 0x03, 0xb0, 0xad, 0x73, 0x3b, 0x4d, 0x74, 0x57, 0x7f, 0x0f, 0x6c, + 0xb0, 0x5d, 0x59, 0x80, 0x13, 0xa1, 0x6c, 0xb0, 0xed, 0x26, 0xec, 0x79, + 0x50, 0x5f, 0x5c, 0xb7, 0xa6, 0xae, 0xe8, 0x0a, 0x6d, 0x55, 0x9a, 0x7f, + 0x59, 0x23, 0xa3, 0x7e, 0x84, 0x7b, 0x3b, 0xfc, 0xde, 0xe1, 0xd9, 0x7c, + 0xd6, 0x87, 0xb3, 0x0e, 0xdb, 0xc1, 0x8c, 0x5e, 0x77, 0xb7, 0x23, 0xd7, + 0x14, 0xd4, 0x23, 0xb4, 0xac, 0x45, 0xbf, 0xfe, 0x40, 0x20, 0x4d, 0x91, + 0x20, 0x94, 0xbd, 0x58, 0xb1, 0x99, 0x69, 0xaf, 0x31, 0x68, 0xbd, 0x61, + 0x5e, 0x87, 0x81, 0x54, 0x4e, 0x2d, 0x03, 0xc2, 0xe2, 0xcd, 0xdc, 0x59, + 0xe5, 0x35, 0xcf, 0xb8, 0xfc, 0x65, 0xed, 0x46, 0xb3, 0x92, 0xe7, 0xf8, + 0x3a, 0x32, 0xaa, 0x0e, 0x5a, 0x82, 0x58, 0x4e, 0x77, 0xd8, 0x33, 0xc9, + 0xb0, 0x3e, 0xad, 0xa5, 0x92, 0xe9, 0xa9, 0x8c, 0x00, 0x72, 0x8f, 0xdc, + 0x77, 0x9d, 0x5c, 0x97, 0xd6, 0x58, 0x20, 0x1e, 0xf4, 0x55, 0x2d, 0xc0, + 0x30, 0xf0, 0x66, 0xda, 0x2d, 0x11, 0xac, 0xd4, 0x2d, 0xd5, 0x25, 0x42, + 0x1d, 0xce, 0x49, 0xb5, 0x95, 0x79, 0x9b, 0x6c, 0x65, 0xe0, 0x8a, 0xc5, + 0x9f, 0x75, 0xe3, 0xe6, 0xf8, 0xa6, 0x88, 0xd6, 0x93, 0x70, 0x4f, 0x89, + 0x94, 0x74, 0xbd, 0xef, 0xc2, 0x1a, 0x55, 0x74, 0x37, 0x44, 0x85, 0x1e, + 0xa9, 0xbb, 0x3f, 0x15, 0xc7, 0x84, 0x80, 0xa5, 0xab, 0xc3, 0x91, 0x8e, + 0xd6, 0x32, 0x46, 0x0d, 0xfa, 0xd1, 0x19, 0xd1, 0xfc, 0x02, 0xe2, 0x20, + 0xa6, 0xa9, 0xf7, 0xf4, 0xcc, 0x5b, 0x54, 0x4f, 0x4a, 0x73, 0x35, 0xda, + 0xf0, 0x31, 0x81, 0x1a, 0x82, 0xe7, 0xd4, 0xc8, 0xb4, 0x1d, 0x70, 0xa9, + 0x5d, 0x67, 0xb9, 0x7d, 0x4b, 0xcd, 0xa4, 0x81, 0xf9, 0xb2, 0x38, 0x07, + 0x16, 0xd5, 0x28, 0x82, 0xb9, 0x76, 0x5b, 0xa1, 0x09, 0x7a, 0xe7, 0x2a, + 0xcf, 0xc0, 0x3d, 0x2a, 0x42, 0x9a, 0xf3, 0xc8, 0x64, 0x15, 0x7c, 0x94, + 0xd0, 0x97, 0xee, 0x34, 0xb6, 0xf0, 0xb2, 0xba, 0x7e, 0xb2, 0xbb, 0x4e, + 0xbf, 0x88, 0xd0, 0x6b, 0xc5, 0x9c, 0xb9, 0xf2, 0x7d, 0xbf, 0x5d, 0x87, + 0xbc, 0x36, 0x4a, 0xd1, 0x1b, 0x6f, 0x40, 0x09, 0xba, 0x26, 0x51, 0xd6, + 0xc0, 0xaf, 0x27, 0xce, 0x27, 0x8d, 0x93, 0xa8, 0x6c, 0x91, 0xe7, 0x91, + 0x42, 0xc0, 0x68, 0x36, 0x5b, 0xd5, 0x56, 0x4c, 0xe2, 0x77, 0xc3, 0xac, + 0x56, 0xe3, 0x1c, 0xc2, 0xf9, 0x78, 0x02, 0x39, 0x7d, 0xed, 0x18, 0x2a, + 0x01, 0x48, 0xe6, 0xf6, 0x7e, 0x34, 0x50, 0xf4, 0x57, 0x56, 0x93, 0xdb, + 0x85, 0x1b, 0x1e, 0x1a, 0x6f, 0x3e, 0x07, 0x3c, 0xad, 0x3f, 0x8d, 0x75, + 0x53, 0xc3, 0x20, 0x72, 0x93, 0x28, 0xd2, 0x86, 0xc8, 0xa5, 0x90, 0xf2, + 0x5f, 0x13, 0xd5, 0xa5, 0xbe, 0x88, 0x9e, 0x9a, 0x57, 0x2c, 0x53, 0x3f, + 0x11, 0x25, 0x00, 0x00, 0x4a, 0x16, 0x8d, 0xd3, 0x3f, 0x2d, 0x3d, 0x88, + 0xbb, 0x4c, 0x4f, 0x9a, 0xb9, 0x97, 0x5f, 0xed, 0x71, 0xa9, 0x68, 0xd9, + 0x4a, 0x14, 0x24, 0xc7, 0xbe, 0xff, 0x85, 0x57, 0xa3, 0x21, 0xe3, 0x21, + 0x79, 0x1f, 0xd0, 0xbb, 0xb7, 0x73, 0xde, 0x60, 0x02, 0x4b, 0x8f, 0x7d, + 0xb3, 0xb3, 0x8a, 0xda, 0x4c, 0xf4, 0xb8, 0xf1, 0x31, 0xff, 0x32, 0x7b, + 0xd8, 0xfa, 0xb1, 0xcb, 0xb4, 0x58, 0xf5, 0xc8, 0x64, 0xdf, 0xfe, 0x3d, + 0x89, 0x52, 0x5c, 0x52, 0x95, 0xf3, 0xba, 0x0d, 0x1d, 0x2c, 0xc4, 0xf7, + 0x3c, 0x3b, 0x6f, 0x8e, 0xc7, 0xab, 0xad, 0x3d, 0x3d, 0x95, 0x9b, 0xc7, + 0x71, 0x36, 0xae, 0x08, 0xc3, 0x08, 0x79, 0xfa, 0x24, 0xee, 0xd9, 0xf9, + 0x63, 0xc7, 0xd9, 0x16, 0x19, 0x8e, 0x0d, 0xaf, 0x52, 0x87, 0x86, 0x7d, + 0xec, 0xe5, 0xea, 0x5a, 0xda, 0x86, 0x9d, 0x0e, 0x50, 0x53, 0x8c, 0x24, + 0xa8, 0x69, 0xc4, 0xf3, 0x85, 0x7b, 0x34, 0x67, 0x19, 0x35, 0xec, 0xd4, + 0xd4, 0x50, 0xe0, 0xe6, 0xe9, 0x29, 0x5b, 0x92, 0xee, 0xba, 0xa9, 0xef, + 0xf6, 0x35, 0x23, 0x8b, 0xdb, 0x48, 0x32, 0x25, 0x41, 0xf3, 0x55, 0x12, + 0x33, 0xc3, 0x6c, 0xed, 0x32, 0xe1, 0x64, 0x7a, 0x8d, 0xa2, 0x19, 0x5a, + 0x26, 0xf2, 0x83, 0xf1, 0xe4, 0x27, 0xdb, 0x67, 0xc3, 0x89, 0x37, 0xea, + 0x78, 0x19, 0xc6, 0xa3, 0x82, 0x84, 0x1c, 0xf3, 0x2b, 0xbe, 0xde, 0xba, + 0xe7, 0x60, 0x2e, 0xf5, 0x4e, 0xb6, 0x73, 0x29, 0xac, 0xc7, 0x55, 0xab, + 0x21, 0xe9, 0x95, 0x78, 0xd5, 0x8e, 0x27, 0xdc, 0x92, 0x5f, 0xc0, 0xcb, + 0xee, 0x66, 0x09, 0x0a, 0xfc, 0x94, 0x43, 0x44, 0x50, 0x35, 0x57, 0xf8, + 0x08, 0xf9, 0x97, 0xa2, 0x0e, 0xde, 0x81, 0xe1, 0xd1, 0xa0, 0x41, 0xfe, + 0xe6, 0x08, 0x6c, 0x98, 0x8c, 0x81, 0x46, 0x0e, 0xf9, 0x9a, 0x54, 0xfe, + 0xc3, 0x91, 0xe3, 0xd4, 0x46, 0xca, 0x52, 0xa2, 0x73, 0x9e, 0x4d, 0xa7, + 0xfd, 0xa1, 0x8e, 0x43, 0x28, 0xf5, 0xa3, 0xa2, 0x62, 0x20, 0x53, 0x62, + 0x05, 0x49, 0xba, 0x06, 0xe2, 0xeb, 0xba, 0xfb, 0x8e, 0xa0, 0x22, 0xc7, + 0xf9, 0xcc, 0x7f, 0x8b, 0xa8, 0x5d, 0x55, 0xd2, 0x24, 0xff, 0xdd, 0x2c, + 0xc1, 0xd0, 0x3d, 0xe4, 0x79, 0xea, 0xba, 0x62, 0xe5, 0xa2, 0x62, 0xf4, + 0x1f, 0xec, 0xb0, 0x07, 0xf2, 0x0d, 0x32, 0x84, 0x86, 0x81, 0x3d, 0x95, + 0xc1, 0x64, 0xfe, 0x9a, 0x3d, 0x8f, 0x4b, 0x6d, 0xfb, 0x0d, 0x42, 0xcf, + 0xbf, 0xdb, 0x51, 0xb2, 0x16, 0xa2, 0x35, 0xaa, 0xe7, 0x31, 0x54, 0xc2, + 0x87, 0xc6, 0xa5, 0x30, 0x71, 0x64, 0x65, 0xff, 0x41, 0x20, 0xb0, 0x83, + 0xdb, 0xb7, 0x95, 0xce, 0xd7, 0xcc, 0x7a, 0x77, 0xad, 0xb8, 0xb7, 0x4c, + 0xfc, 0x11, 0x05, 0x2b, 0xc4, 0xd4, 0xb6, 0x8b, 0xae, 0x13, 0xa5, 0x40, + 0x18, 0x6e, 0x0d, 0xe3, 0xc6, 0xb0, 0x81, 0x46, 0x46, 0x7e, 0x52, 0x0b, + 0x85, 0x4d, 0x98, 0xd9, 0x42, 0xdf, 0xde, 0x45, 0xc1, 0x5a, 0x33, 0x12, + 0x46, 0x26, 0xb3, 0x6f, 0xf2, 0x8b, 0x37, 0x6b, 0xfd, 0x08, 0xf4, 0x46, + 0x86, 0x89, 0x63, 0x63, 0x21, 0xe5, 0xa9, 0xb7, 0xd0, 0x09, 0x17, 0x52, + 0xee, 0xea, 0xdf, 0x97, 0xb7, 0x73, 0x2e, 0x54, 0x2c, 0x7b, 0x70, 0xd3, + 0xda, 0x26, 0x57, 0x1f, 0xb0, 0x19, 0xd9, 0x91, 0x18, 0x69, 0x75, 0x42, + 0x63, 0xcf, 0x6c, 0x8c, 0x98, 0x5e, 0x17, 0x99, 0x7e, 0x1d, 0xdc, 0x67, + 0x6d, 0x99, 0xd9, 0x02, 0x6e, 0x73, 0x90, 0x5a, 0x4f, 0x0a, 0xb4, 0x48, + 0xfb, 0xc5, 0xbd, 0xd2, 0x10, 0x05, 0xa6, 0x12, 0x68, 0x36, 0x28, 0x51, + 0x60, 0x1c, 0xa1, 0xe9, 0x90, 0x54, 0xa5, 0x53, 0xc3, 0x48, 0x9e, 0xd8, + 0x42, 0x52, 0x85, 0x0e, 0xff, 0xfe, 0xbf, 0xad, 0x3a, 0xa4, 0x57, 0x09, + 0x13, 0x38, 0x64, 0x15, 0x7c, 0xfd, 0xed, 0x91, 0x76, 0x44, 0x20, 0x84, + 0xd9, 0x90, 0xab, 0xfe, 0xfd, 0xd6, 0xab, 0xf1, 0xb3, 0x25, 0x21, 0x3d, + 0x97, 0x72, 0xb2, 0x95, 0xc5, 0x22, 0x80, 0xd9, 0x4a, 0x49, 0x9d, 0x99, + 0xc2, 0x4a, 0x9a, 0x59, 0xb3, 0x71, 0x75, 0x5b, 0xf9, 0x89, 0x7a, 0xdd, + 0xa9, 0xb3, 0xc3, 0xeb, 0x42, 0x91, 0xe2, 0x97, 0x30, 0x40, 0x48, 0x68, + 0x19, 0x3b, 0xf5, 0x7b, 0x4e, 0x33, 0x4b, 0x0c, 0xf3, 0xed, 0xda, 0x76, + 0x3f, 0xb0, 0x4b, 0x53, 0x85, 0x04, 0x33, 0x07, 0x53, 0xd8, 0x55, 0xa2, + 0xfb, 0x30, 0x2c, 0x66, 0xbd, 0x21, 0xf8, 0xfa, 0x20, 0x14, 0x9a, 0x0d, + 0x7f, 0xc9, 0x2f, 0x5b, 0x34, 0x29, 0x09, 0x16, 0xb5, 0x0a, 0x8d, 0xdf, + 0xa2, 0x84, 0x9a, 0xae, 0xe6, 0xa0, 0x50, 0x80, 0x31, 0x04, 0xd3, 0x0c, + 0x8f, 0xd1, 0x8a, 0xfd, 0xb4, 0xa5, 0xae, 0xf5, 0x3c, 0x62, 0xae, 0x45, + 0x70, 0xbb, 0x54, 0x62, 0xc8, 0x50, 0x71, 0x42, 0x85, 0xf6, 0x6f, 0xa0, + 0xf0, 0x10, 0x8a, 0x09, 0xbd, 0x71, 0x78, 0xa6, 0x5e, 0xe4, 0x03, 0x8f, + 0x3b, 0xd0, 0x5c, 0x37, 0x55, 0x1a, 0xc8, 0x57, 0x26, 0x62, 0x6c, 0xc4, + 0x67, 0x71, 0x9d, 0x97, 0xc0, 0xea, 0x35, 0x3e, 0x12, 0xd0, 0x2b, 0xc2, + 0x8f, 0x9e, 0xa6, 0x41, 0x48, 0x33, 0x83, 0x38, 0x37, 0x7e, 0xd4, 0xe3, + 0xee, 0x94, 0x8b, 0x81, 0xa4, 0x60, 0xdd, 0xdd, 0xc1, 0x8a, 0x7b, 0xda, + 0xa8, 0x46, 0xb8, 0x42, 0x3a, 0x25, 0xd6, 0x81, 0x89, 0x29, 0x21, 0xc2, + 0x0c, 0x5b, 0xfd, 0x3e, 0x8c, 0x65, 0x91, 0x52, 0xb3, 0x74, 0x1f, 0xd1, + 0x49, 0x7e, 0x1d, 0x59, 0x58, 0x96, 0xb5, 0xee, 0x32, 0xa4, 0xa8, 0x07, + 0x7c, 0xd1, 0x5b, 0x4b, 0xf8, 0x43, 0x5a, 0xa5, 0xcc, 0x60, 0xcc, 0x08, + 0x6a, 0x3c, 0x41, 0x66, 0x99, 0xe3, 0xa8, 0xe0, 0xb8, 0x87, 0xfc, 0x92, + 0xc0, 0x79, 0xc5, 0x3f, 0xd6, 0xc6, 0x8c, 0x01, 0xf4, 0xa5, 0x05, 0xad, + 0x51, 0xed, 0x04, 0xd7, 0x55, 0xc0, 0x73, 0x05, 0x0e, 0x73, 0xe5, 0x39, + 0x45, 0x5b, 0x95, 0x4a, 0x34, 0x07, 0x99, 0xdf, 0x4c, 0x35, 0xf5, 0x0c, + 0x27, 0x6d, 0xd1, 0x45, 0xf1, 0xfd, 0x24, 0xb7, 0xfe, 0xea, 0x11, 0x5d, + 0xa2, 0xc5, 0xa6, 0x81, 0x37, 0x1d, 0xc2, 0x31, 0x31, 0xfc, 0xe0, 0xf4, + 0xd7, 0xe9, 0x98, 0x8b, 0xe3, 0x70, 0x51, 0x62, 0xc8, 0x61, 0x6d, 0xec, + 0x75, 0x56, 0x71, 0xae, 0x88, 0xe0, 0x80, 0xf5, 0xb7, 0x85, 0x10, 0xb7, + 0x3d, 0x16, 0x78, 0x5f, 0x72, 0xab, 0x8f, 0x63, 0xc6, 0xd5, 0xa8, 0xc9, + 0x9c, 0xef, 0x8d, 0x9a, 0xc5, 0x4f, 0x63, 0xad, 0xc0, 0xf3, 0x1f, 0x69, + 0x0e, 0xce, 0x29, 0x92, 0xc1, 0x3b, 0xb0, 0xc5, 0xed, 0x0a, 0x7b, 0x92, + 0xd0, 0x4c, 0x9c, 0x82, 0xb0, 0x51, 0xf6, 0x33, 0x61, 0x3b, 0x76, 0x48, + 0x38, 0xf4, 0x7c, 0xaa, 0x52, 0x87, 0x15, 0x1a, 0xbe, 0xb8, 0xdc, 0x9b, + 0x16, 0xd2, 0x07, 0xf7, 0xf9, 0x74, 0xe0, 0xaf, 0x0e, 0x29, 0x05, 0xec, + 0x6c, 0x0e, 0x3b, 0xa7, 0xe7, 0xa4, 0xfc, 0xa4, 0xef, 0x57, 0x16, 0x7f, + 0x13, 0xbd, 0x8c, 0x42, 0x02, 0x55, 0x70, 0x56, 0xa5, 0xa9, 0x01, 0x29, + 0x12, 0x7d, 0x80, 0x46, 0x18, 0x8e, 0x39, 0x3f, 0x44, 0x55, 0xec, 0xef, + 0x60, 0x58, 0x7d, 0xce, 0x64, 0x8e, 0x9c, 0xea, 0xe4, 0x73, 0xd1, 0x48, + 0x9c, 0x3f, 0x92, 0xa0, 0x9a, 0x76, 0xa5, 0x5a, 0x13, 0x1f, 0x10, 0xb9, + 0xb7, 0xb1, 0xde, 0x49, 0x22, 0x58, 0xf4, 0x43, 0x5f, 0x03, 0x43, 0xc3, + 0x6c, 0xbf, 0x82, 0xaf, 0x88, 0x39, 0xfd, 0xb2, 0x28, 0x9b, 0x47, 0x3f, + 0x83, 0x3d, 0xd9, 0x7c, 0xf0, 0xc9, 0xc5, 0xa2, 0xb4, 0xd6, 0x0d, 0x59, + 0x51, 0x27, 0x60, 0x10, 0x5e, 0xbb, 0x18, 0xa6, 0x42, 0x4a, 0x9d, 0xc4, + 0x16, 0x0e, 0xb6, 0x57, 0x23, 0x03, 0x24, 0x27, 0xdc, 0x20, 0x56, 0x30, + 0x8b, 0x0f, 0xb6, 0xb7, 0x73, 0xf5, 0x36, 0x3e, 0xf6, 0x7a, 0x71, 0xa5, + 0x57, 0xcc, 0x6d, 0xc6, 0xf3, 0xdc, 0x35, 0xfb, 0x95, 0xf7, 0xa7, 0xd7, + 0x56, 0x38, 0xd4, 0x15, 0xe2, 0xd5, 0x6f, 0x70, 0x30, 0xc8, 0x7d, 0x8a, + 0x87, 0xe6, 0xd1, 0xe0, 0x50, 0x62, 0xde, 0xfa, 0x29, 0x40, 0x97, 0xa0, + 0x54, 0x63, 0x31, 0xd3, 0x08, 0x87, 0x0a, 0xdc, 0x6e, 0x5e, 0xab, 0x8d, + 0x16, 0xaf, 0x6e, 0x8b, 0x1a, 0x77, 0xf6, 0xd4, 0xe0, 0xbf, 0x59, 0xab, + 0xc7, 0xb0, 0x45, 0x18, 0xaa, 0xe6, 0x65, 0x6f, 0x7d, 0x13, 0xb2, 0xbf, + 0xb3, 0x66, 0x72, 0xfa, 0xfd, 0xee, 0xad, 0x07, 0x56, 0x51, 0x6a, 0xe2, + 0xff, 0xb2, 0xaf, 0x4d, 0xd1, 0xf2, 0x77, 0x35, 0x5e, 0x90, 0xcd, 0xe7, + 0xa8, 0x32, 0x4d, 0x9f, 0xbd, 0xa8, 0xce, 0xab, 0xf1, 0x49, 0x98, 0xb5, + 0x23, 0x5c, 0x62, 0x2d, 0x43, 0x31, 0x80, 0x87, 0xc2, 0xa8, 0xf5, 0xb9, + 0xb6, 0xae, 0x7f, 0x37, 0x13, 0xb8, 0x6b, 0x73, 0xf3, 0x56, 0x38, 0xa7, + 0x9b, 0x97, 0x69, 0x37, 0x00, 0xdc, 0xff, 0xfe, 0x58, 0xc9, 0x12, 0x47, + 0x75, 0x98, 0x1f, 0xad, 0xd8, 0xb5, 0xc8, 0x47, 0x4f, 0xd0, 0x72, 0x63, + 0x54, 0x25, 0x6c, 0x88, 0xc9, 0x9f, 0x3c, 0x82, 0xe0, 0xdd, 0x4c, 0xff, + 0x8e, 0xaf, 0x8f, 0x8e, 0xea, 0x84, 0x3f, 0x73, 0xdd, 0x9e, 0x18, 0x73, + 0x47, 0x70, 0xc7, 0xc7, 0x99, 0x65, 0xcf, 0xf3, 0xb6, 0x24, 0xed, 0x97, + 0x8f, 0xcd, 0x93, 0x1e, 0xff, 0x6e, 0x9c, 0xf1, 0x30, 0x14, 0x1a, 0x27, + 0x59, 0x6a, 0x0e, 0xf3, 0xe4, 0xfa, 0x1d, 0x65, 0xb5, 0x53, 0xe4, 0xab, + 0xb1, 0x3e, 0xe1, 0x91, 0xf4, 0x6d, 0x99, 0xca, 0x7d, 0x03, 0x08, 0x50, + 0xea, 0xa9, 0x39, 0x7f, 0x6d, 0xe7, 0x43, 0xfb, 0x64, 0xcc, 0x4b, 0x9e, + 0xa0, 0x26, 0xe4, 0x0e, 0xff, 0xb7, 0x11, 0x0a, 0x29, 0x50, 0x90, 0xd7, + 0x4d, 0x62, 0x9a, 0x4a, 0x23, 0xb7, 0xd3, 0x53, 0xde, 0x3a, 0xd1, 0xba, + 0xd3, 0x10, 0x59, 0xc6, 0xc5, 0x5e, 0xac, 0xf9, 0x61, 0x74, 0x54, 0xf4, + 0x27, 0x9f, 0x9a, 0x61, 0x13, 0xdc, 0xe5, 0x96, 0xe3, 0x95, 0x0d, 0xcc, + 0xbd, 0x81, 0x74, 0x79, 0x73, 0xef, 0x2e, 0x0b, 0x0f, 0x91, 0x65, 0x3c, + 0x26, 0x7c, 0x47, 0x10, 0x31, 0x0b, 0xfb, 0x41, 0x0c, 0xc2, 0xa8, 0xc4, + 0x0e, 0xbd, 0x0a, 0x8c, 0xa4, 0x80, 0x45, 0x57, 0x62, 0x0b, 0x4d, 0x44, + 0x5e, 0x59, 0x77, 0xfd, 0x3d, 0xf3, 0xd7, 0x92, 0x49, 0xc1, 0xcb, 0x8a, + 0x54, 0x56, 0x3b, 0xde, 0xcf, 0x16, 0x9a, 0x65, 0xbe, 0xac, 0x64, 0xe1, + 0xd4, 0xd4, 0x1e, 0xac, 0x6b, 0x4a, 0xad, 0xc4, 0x33, 0xac, 0xcb, 0x83, + 0xf4, 0x4d, 0xe8, 0xb6, 0xd7, 0x23, 0xd7, 0x71, 0x25, 0xa2, 0x25, 0x3d, + 0x7e, 0xf0, 0x3b, 0x7f, 0x61, 0x11, 0x56, 0xd4, 0x83, 0xc8, 0xc0, 0x29, + 0x38, 0x10, 0x73, 0xad, 0x6a, 0xb7, 0xb9, 0xd2, 0x2e, 0x9f, 0xae, 0x16, + 0x5e, 0xa6, 0x13, 0x1c, 0xc2, 0x17, 0x73, 0x43, 0x03, 0xdd, 0xa6, 0xaf, + 0x9a, 0x17, 0x31, 0xb8, 0x86, 0x97, 0xc2, 0xd6, 0xe6, 0xed, 0xd4, 0xe1, + 0x7d, 0xb9, 0xa6, 0x96, 0xc1, 0x4b, 0xcb, 0x11, 0x1e, 0xe1, 0xe0, 0xd2, + 0x28, 0x69, 0x68, 0x3b, 0x21, 0x17, 0x63, 0x0c, 0xc0, 0x49, 0x30, 0x22, + 0x3a, 0x59, 0x72, 0xe6, 0x47, 0xb4, 0xdc, 0xa8, 0x29, 0x1c, 0x89, 0xa6, + 0x3a, 0x77, 0x99, 0xea, 0x46, 0xce, 0x38, 0xda, 0x31, 0x88, 0xad, 0xe7, + 0x26, 0xce, 0xc6, 0x56, 0x04, 0x30, 0xfa, 0x01, 0xac, 0xbb, 0xe2, 0xb8, + 0x23, 0xe4, 0x9d, 0x4f, 0x77, 0x02, 0x00, 0x28, 0xf1, 0xe0, 0x19, 0x3f, + 0x22, 0x4f, 0x22, 0x69, 0x87, 0xc0, 0x4e, 0x26, 0x33, 0xfe, 0x6c, 0x70, + 0x56, 0x3b, 0x60, 0x5f, 0xfb, 0xf8, 0x43, 0xcf, 0x3f, 0xb9, 0xcb, 0x80, + 0x22, 0xbb, 0x0a, 0xa8, 0x1c, 0x3e, 0x7e, 0x4d, 0x42, 0x60, 0x5c, 0x8e, + 0xfa, 0x42, 0xb3, 0x95, 0xe7, 0x92, 0x6b, 0xec, 0x7a, 0x95, 0x88, 0x98, + 0xe3, 0xf9, 0x0d, 0xe5, 0x08, 0xf1, 0x26, 0x96, 0x2a, 0x81, 0x2b, 0x7c, + 0x0d, 0x12, 0xa0, 0x7f, 0x7b, 0x39, 0xf6, 0xcc, 0x1b, 0x2d, 0x2c, 0xe9, + 0x5b, 0x02, 0x9b, 0x5c, 0x94, 0x51, 0x13, 0xe8, 0xa0, 0x19, 0xce, 0xde, + 0x07, 0x1b, 0xda, 0x39, 0x14, 0xb5, 0x8b, 0xcf, 0x79, 0x3e, 0x2b, 0xb8, + 0x75, 0xab, 0x81, 0xee, 0x5e, 0x08, 0x33, 0xc3, 0x49, 0x5b, 0x4a, 0x9c, + 0x74, 0x34, 0xde, 0x08, 0x61, 0x03, 0x38, 0xe3, 0xd8, 0xff, 0xc5, 0xc0, + 0xb5, 0x40, 0xd5, 0x26, 0x57, 0x85, 0xf1, 0xb7, 0x77, 0xb6, 0x36, 0xe0, + 0x8d, 0x43, 0x3a, 0xef, 0xfe, 0x0f, 0xf7, 0xee, 0x67, 0x6c, 0x7b, 0xd1, + 0x83, 0xf6, 0x10, 0xda, 0x67, 0x04, 0x3a, 0x27, 0xd8, 0x3a, 0xcb, 0x9d, + 0x4c, 0xa6, 0x9a, 0xc7, 0xea, 0x07, 0xc6, 0x76, 0x79, 0x1b, 0x23, 0x4a, + 0x68, 0x2f, 0x14, 0x84, 0x42, 0x79, 0xe8, 0x1f, 0xf2, 0xe6, 0xac, 0x72, + 0xb0, 0xb0, 0xb6, 0x39, 0x95, 0x40, 0xa4, 0x6e, 0x54, 0x2e, 0xb7, 0xb5, + 0x13, 0x70, 0x48, 0x0d, 0x27, 0xed, 0x2c, 0xa2, 0x64, 0x53, 0xb4, 0x04, + 0x84, 0xab, 0xd8, 0xea, 0x2a, 0x8c, 0xac, 0x5b, 0x1d, 0xb8, 0xb2, 0xbe, + 0x55, 0x2b, 0x4a, 0x47, 0xfc, 0xe0, 0x15, 0x78, 0xb6, 0xd6, 0xff, 0x20, + 0xa8, 0x8a, 0xec, 0x8b, 0x30, 0xef, 0xc5, 0xc6, 0xec, 0xa0, 0xdf, 0xd3, + 0xc4, 0x2b, 0x4a, 0xdf, 0xef, 0x5c, 0x46, 0xb3, 0x31, 0xc7, 0x5f, 0x8f, + 0x1e, 0x99, 0x76, 0x81, 0x71, 0x61, 0xdb, 0xc3, 0xc4, 0x0f, 0x66, 0x7b, + 0xd7, 0x44, 0xc7, 0x8d, 0x12, 0x38, 0x71, 0x7c, 0xd8, 0x41, 0xf6, 0x8a, + 0xb9, 0xba, 0xd2, 0x1f, 0xa1, 0x27, 0x64, 0x67, 0x51, 0xb2, 0xaf, 0xea, + 0x02, 0x95, 0x79, 0x20, 0x0a, 0xc8, 0xaa, 0x03, 0x11, 0xb6, 0x8b, 0x7d, + 0x86, 0xb7, 0xef, 0x5e, 0x3f, 0x0b, 0x91, 0x47, 0xf0, 0x43, 0xb4, 0x54, + 0x1d, 0x16, 0x66, 0xe9, 0x63, 0x1a, 0x55, 0xaf, 0x34, 0xad, 0x11, 0x68, + 0x4d, 0x36, 0xb7, 0x0c, 0x6d, 0x4d, 0xed, 0xba, 0x14, 0xe8, 0xf6, 0xe2, + 0x15, 0x64, 0xb6, 0x15, 0x28, 0xbf, 0xd2, 0x4d, 0xb6, 0x6f, 0xca, 0x5f, + 0x81, 0x1b, 0xf0, 0x31, 0xf5, 0xd3, 0xe0, 0x06, 0xc7, 0xf3, 0x0c, 0x18, + 0x91, 0x45, 0x22, 0xa2, 0x30, 0x48, 0x82, 0xeb, 0x42, 0xfc, 0x8f, 0x2a, + 0xa3, 0x1a, 0x8d, 0x84, 0x28, 0x20, 0x16, 0x95, 0xd9, 0x66, 0x67, 0x2b, + 0xef, 0xc6, 0x6e, 0x56, 0x1c, 0x62, 0x74, 0x16, 0x5c, 0x3e, 0x17, 0xd0, + 0xb7, 0xdd, 0x70, 0xb6, 0x0e, 0x79, 0x46, 0xc5, 0x4e, 0x72, 0x46, 0x69, + 0xf5, 0xa1, 0x1c, 0x7b, 0xd5, 0x67, 0x5c, 0xb3, 0x46, 0x4d, 0x18, 0x31, + 0x47, 0x42, 0x20, 0xe6, 0x12, 0x84, 0x4e, 0x16, 0x0f, 0x4a, 0xd0, 0xc4, + 0x91, 0xa3, 0xbd, 0x91, 0xcd, 0x86, 0x4c, 0xcd, 0x4b, 0x2e, 0x62, 0x84, + 0xea, 0x19, 0x2d, 0x21, 0x1a, 0x64, 0xc4, 0xd2, 0x24, 0x92, 0x96, 0x04, + 0x66, 0xb5, 0x4a, 0xe4, 0xa9, 0xd6, 0xaf, 0x12, 0x9b, 0xb5, 0x59, 0xe0, + 0x5c, 0x84, 0x84, 0x7c, 0x68, 0x99, 0xd8, 0x23, 0xa2, 0x15, 0xa7, 0x82, + 0xa5, 0x66, 0x95, 0x8f, 0xfe, 0x57, 0xc1, 0x12, 0x6c, 0x89, 0xe5, 0x5b, + 0x5d, 0x64, 0xdb, 0x81, 0x4f, 0x77, 0x3c, 0xc8, 0x52, 0x4e, 0x2a, 0xd6, + 0x74, 0x3c, 0x4b, 0x11, 0xfc, 0xc1, 0x7c, 0x01, 0xba, 0x0f, 0x0f, 0x57, + 0x8a, 0xbe, 0x5b, 0x16, 0x88, 0x96, 0xe6, 0xe9, 0x60, 0xcf, 0x66, 0xe9, + 0xe6, 0x07, 0xb0, 0x0b, 0xa3, 0xa0, 0xad, 0xdf, 0x70, 0xd4, 0xcb, 0x2e, + 0x33, 0x2f, 0xe5, 0xf2, 0x1e, 0x0d, 0x74, 0x7a, 0xf9, 0x4a, 0x0f, 0x32, + 0xb4, 0xa1, 0xc9, 0xf5, 0x3f, 0x0a, 0x06, 0xf9, 0x67, 0x45, 0x9c, 0xd9, + 0x58, 0xd4, 0x0e, 0x72, 0x55, 0x47, 0x49, 0x9b, 0xab, 0x9c, 0x66, 0xe7, + 0x4d, 0x9a, 0x02, 0x1b, 0x41, 0xad, 0xe5, 0x8c, 0x7f, 0xa1, 0xdc, 0xad, + 0xcd, 0x74, 0xda, 0x9f, 0xfa, 0x87, 0x32, 0xc1, 0x07, 0x8e, 0x9b, 0xef, + 0x28, 0x2f, 0x17, 0x6d, 0xdb, 0x84, 0x4b, 0xa8, 0x7d, 0x31, 0xa8, 0x32, + 0xe4, 0x9a, 0x1e, 0x0e, 0xef, 0x68, 0xf4, 0xac, 0x03, 0x6c, 0x68, 0xcc, + 0x28, 0xbb, 0xfb, 0x21, 0xb8, 0x11, 0xd7, 0xf9, 0xe8, 0x24, 0x37, 0xdf, + 0xe0, 0xb2, 0xef, 0xd6, 0xec, 0xdf, 0xcf, 0xf5, 0x50, 0x19, 0xa3, 0xa9, + 0x1b, 0x01, 0x2e, 0x94, 0x42, 0xb0, 0x14, 0x5d, 0x0e, 0x37, 0x46, 0x4a, + 0x52, 0x53, 0x60, 0x6b, 0x89, 0xc9, 0xca, 0xed, 0x0a, 0x0c, 0x18, 0x33, + 0x3c, 0x40, 0x42, 0x76, 0x7a, 0x7d, 0xb6, 0x10, 0x29, 0x3e, 0x42, 0x75, + 0xa6, 0xbf, 0xcb, 0xd3, 0xdc, 0xe1, 0x00, 0x05, 0x08, 0x25, 0x67, 0x6c, + 0x72, 0xde, 0x26, 0x72, 0x88, 0xbe, 0xfa, 0x05, 0x57, 0x77, 0x78, 0x83, + 0xce, 0xd5, 0x44, 0x49, 0x8b, 0xab, 0xbc, 0xca, 0xd3, 0x1c, 0x34, 0x4a, + 0xaa, 0xc7, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x17, 0x22, 0x2a, 0x2f, 0x36, 0x3d, 0x43}; +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_KEYGEN_PCT */ +#endif /* !EXPECTED_SIGNATURES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/main.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/main.c new file mode 100644 index 0000000000..42e805a8a4 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/main.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include +#include +#include +#include + +/* Import public mldsa-native API + * + * This requires specifying the parameter set and namespace prefix + * used for the build. + */ +#include +#include "expected_signatures.h" + +#define CHECK(x) \ + do \ + { \ + int rc; \ + rc = (x); \ + if (!rc) \ + { \ + fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \ + return 1; \ + } \ + } while (0) + +#define TEST_MSG \ + "This is a test message for ML-DSA digital signature algorithm!" +#define TEST_MSG_LEN (sizeof(TEST_MSG) - 1) + +#define TEST_CTX "test_context_123" +#define TEST_CTX_LEN (sizeof(TEST_CTX) - 1) + +int main(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t sig[CRYPTO_BYTES]; + /* For testing, we use the same randomness that would be generated by our + * deterministic test rng such that we can produce the same keys and + * signatures as in the basic example. + */ + /* # !!! WARNING !!! + * This is for TESTING ONLY. + * For key generation, you MUST USE cryptographic randomness outside of + * testing. + * For signing, you SHOULD provide cryptographic randomness. If you require + * deterministic signing, set sign_rnd to all zeros. + */ + + uint8_t keypair_rnd[MLDSA_SEEDBYTES] = { + 0x93, 0x4d, 0x60, 0xb3, 0x56, 0x24, 0xd7, 0x40, 0xb3, 0x0a, 0x7f, + 0x22, 0x7a, 0xf2, 0xae, 0x7c, 0x67, 0x8e, 0x4e, 0x04, 0xe1, 0x3c, + 0x5f, 0x50, 0x9e, 0xad, 0xe2, 0xb7, 0x9a, 0xea, 0x77, 0xe2}; + + uint8_t sign_rnd[MLDSA_RNDBYTES] = { + 0x3e, 0x2a, 0x2e, 0xa6, 0xc9, 0xc4, 0x76, 0xfc, 0x49, 0x37, 0xb0, + 0x13, 0xc9, 0x93, 0xa7, 0x93, 0xd6, 0xc0, 0xab, 0x99, 0x60, 0x69, + 0x5b, 0xa8, 0x38, 0xf6, 0x49, 0xda, 0x53, 0x9c, 0xa3, 0xd0}; + uint8_t + pre[TEST_CTX_LEN + 2]; /* prefix string (0, ctxlen, ctx) for signing */ + size_t siglen; + + printf("ML-DSA-%d Deterministic Example\n", MLD_CONFIG_PARAMETER_SET); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(mldsa_keypair_internal(pk, sk, keypair_rnd) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Prepare pre = (0, ctxlen, ctx) */ + pre[0] = 0; + pre[1] = TEST_CTX_LEN; + memcpy(pre + 2, test_ctx, TEST_CTX_LEN); + + + /* Alice signs the message */ + CHECK(mldsa_signature_internal(sig, &siglen, (const uint8_t *)test_msg, + TEST_MSG_LEN, pre, sizeof(pre), sign_rnd, sk, + 0) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(mldsa_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", CRYPTO_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", CRYPTO_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", CRYPTO_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature)); + CHECK(memcmp(sig, expected_signature, siglen) == 0); + } + printf("DONE\n"); + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/mldsa_native.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/mldsa_native.h new file mode 100644 index 0000000000..fd150a9df1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/mldsa_native.h @@ -0,0 +1,975 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_H +#define MLD_H + +/* + * Public API for mldsa-native + * + * This header defines the public API of a single build of mldsa-native. + * + * Make sure the configuration file is in the include path + * (this is "mldsa_native_config.h" by default, or MLD_CONFIG_FILE if defined). + * + * # Multi-level builds + * + * This header specifies a build of mldsa-native for a fixed security level. + * If you need multiple security levels, leave the security level unspecified + * in the configuration file and include this header multiple times, setting + * MLD_CONFIG_PARAMETER_SET accordingly for each, and #undef'ing the MLD_H + * guard to allow multiple inclusions. + * + * # Legacy configuration (deprecated) + * + * Instead of providing the config file used for the build, you can + * alternatively set the following configuration options prior to + * including this header. + * + * This method of configuration is deprecated. + * It will be removed in mldsa-native-v2. + * + * - MLD_CONFIG_API_PARAMETER_SET [required] + * + * The parameter set used for the build; 44, 65, or 87. + * + * - MLD_CONFIG_API_NAMESPACE_PREFIX [required] + * + * The namespace prefix used for the build. + * + * NOTE: + * For a multi-level build, you must include the 44/65/87 suffixes + * in MLD_CONFIG_API_NAMESPACE_PREFIX. + * + * - MLD_CONFIG_API_NO_SUPERCOP [optional] + * + * By default, this header will also expose the mldsa-native API in the + * SUPERCOP naming convention crypto_sign_xxx. If you don't want/need this, + * set MLD_CONFIG_API_NO_SUPERCOP. You must set this for a multi-level build. + * + * - MLD_CONFIG_API_CONSTANTS_ONLY [optional] + * + * If you don't want this header to expose any function declarations, + * but only constants for the sizes of key material, set + * MLD_CONFIG_API_CONSTANTS_ONLY. In this case, you don't need to set + * MLD_CONFIG_API_PARAMETER_SET or MLD_CONFIG_API_NAMESPACE_PREFIX, + * nor include a configuration. + * + * - MLD_CONFIG_API_QUALIFIER [optional] + * + * Qualifier to apply to external API. + * + ******************************************************************************/ + +/******************************* Key sizes ************************************/ + +/* Sizes of cryptographic material, per parameter set */ +/* See mldsa/src/params.h for the arithmetic expressions giving rise to these */ +/* check-magic: off */ +#define MLDSA44_SECRETKEYBYTES 2560 +#define MLDSA44_PUBLICKEYBYTES 1312 +#define MLDSA44_BYTES 2420 + +#define MLDSA65_SECRETKEYBYTES 4032 +#define MLDSA65_PUBLICKEYBYTES 1952 +#define MLDSA65_BYTES 3309 + +#define MLDSA87_SECRETKEYBYTES 4896 +#define MLDSA87_PUBLICKEYBYTES 2592 +#define MLDSA87_BYTES 4627 +/* check-magic: on */ + +/* Size of seed and randomness in bytes (level-independent) */ +#define MLDSA_SEEDBYTES 32 +#define MLDSA44_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA65_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA87_SEEDBYTES MLDSA_SEEDBYTES + +/* Size of CRH output in bytes (level-independent) */ +#define MLDSA_CRHBYTES 64 +#define MLDSA44_CRHBYTES MLDSA_CRHBYTES +#define MLDSA65_CRHBYTES MLDSA_CRHBYTES +#define MLDSA87_CRHBYTES MLDSA_CRHBYTES + +/* Size of TR output in bytes (level-independent) */ +#define MLDSA_TRBYTES 64 +#define MLDSA44_TRBYTES MLDSA_TRBYTES +#define MLDSA65_TRBYTES MLDSA_TRBYTES +#define MLDSA87_TRBYTES MLDSA_TRBYTES + +/* Size of randomness for signing in bytes (level-independent) */ +#define MLDSA_RNDBYTES 32 +#define MLDSA44_RNDBYTES MLDSA_RNDBYTES +#define MLDSA65_RNDBYTES MLDSA_RNDBYTES +#define MLDSA87_RNDBYTES MLDSA_RNDBYTES + +/* Sizes of cryptographic material, as a function of LVL=44,65,87 */ +#define MLDSA_SECRETKEYBYTES_(LVL) MLDSA##LVL##_SECRETKEYBYTES +#define MLDSA_PUBLICKEYBYTES_(LVL) MLDSA##LVL##_PUBLICKEYBYTES +#define MLDSA_BYTES_(LVL) MLDSA##LVL##_BYTES +#define MLDSA_SECRETKEYBYTES(LVL) MLDSA_SECRETKEYBYTES_(LVL) +#define MLDSA_PUBLICKEYBYTES(LVL) MLDSA_PUBLICKEYBYTES_(LVL) +#define MLDSA_BYTES(LVL) MLDSA_BYTES_(LVL) + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + +/****************************** Function API **********************************/ + +#define MLD_API_CONCAT_(x, y) x##y +#define MLD_API_CONCAT(x, y) MLD_API_CONCAT_(x, y) +#define MLD_API_CONCAT_UNDERSCORE(x, y) MLD_API_CONCAT(MLD_API_CONCAT(x, _), y) + +#if !defined(MLD_CONFIG_API_PARAMETER_SET) +/* Recommended configuration via same config file as used for the build. */ + +/* For now, we derive the legacy API configuration MLD_CONFIG_API_XXX from + * the config file. In mldsa-native-v2, this will be removed and we will + * exclusively work with MLD_CONFIG_XXX. */ + +/* You need to make sure the config file is in the include path. */ +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#define MLD_CONFIG_API_PARAMETER_SET MLD_CONFIG_PARAMETER_SET + +#if defined(MLD_CONFIG_MULTILEVEL_BUILD) +#define MLD_CONFIG_API_NAMESPACE_PREFIX \ + MLD_API_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_CONFIG_API_NAMESPACE_PREFIX MLD_CONFIG_NAMESPACE_PREFIX +#endif + +#if defined(MLD_CONFIG_NO_SUPERCOP) +#define MLD_CONFIG_API_NO_SUPERCOP +#endif + +#if defined(MLD_CONFIG_CONSTANTS_ONLY) +#define MLD_CONFIG_API_CONSTANTS_ONLY +#endif + +#if defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_CONFIG_API_QUALIFIER MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#else /* !MLD_CONFIG_API_PARAMETER_SET */ +#define MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_PARAMETER_SET */ + +#define MLD_API_NAMESPACE(sym) \ + MLD_API_CONCAT_UNDERSCORE(MLD_CONFIG_API_NAMESPACE_PREFIX, sym) + +#if defined(__GNUC__) || defined(clang) +#define MLD_API_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_API_MUST_CHECK_RETURN_VALUE +#endif + +#if defined(MLD_CONFIG_API_QUALIFIER) +#define MLD_API_QUALIFIER MLD_CONFIG_API_QUALIFIER +#else +#define MLD_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_API_CONSTANTS_ONLY) + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************************* + * Name: crypto_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: + * input random seed + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair_internal)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t seed[MLDSA_SEEDBYTES] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: If MLD_CONFIG_KEYGEN_PCT is enabled and the + * PCT check failed. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return -1 in that case. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_extmu + * + * Description: Computes signature. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_extmu)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t *sm: pointer to output signed message (allocated array + * with MLDSA{44,65,87}_BYTES + mlen bytes), can be + * equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(sign)( + uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_extmu)( + const uint8_t *sig, size_t siglen, const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_open + * + * Description: Verify signed message. + * + * Arguments: + * - uint8_t *m: pointer to output message (allocated array with + * smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(open)( + uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: crypto_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *ph, size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_shake256)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_shake256)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/* Maximum formatted domain separation message length */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +size_t MLD_API_NAMESPACE(prepare_domain_separation_prefix)( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg); + +/************************************************* + * Name: crypto_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[CRYPTO_SECRETKEYBYTES]: input secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(pk_from_sk)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +#ifdef __cplusplus +} +#endif + +/****************************** SUPERCOP API *********************************/ + +#if !defined(MLD_CONFIG_API_NO_SUPERCOP) +/* Export API in SUPERCOP naming scheme CRYPTO_xxx / crypto_sign_xxx */ +#define CRYPTO_SECRETKEYBYTES MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_PUBLICKEYBYTES MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_BYTES MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET) + +#define crypto_sign_keypair MLD_API_NAMESPACE(keypair) +#define crypto_sign_signature MLD_API_NAMESPACE(signature) +#define crypto_sign MLD_API_NAMESPACE(sign) +#define crypto_sign_verify MLD_API_NAMESPACE(verify) +#define crypto_sign_open MLD_API_NAMESPACE(open) + +#else /* !MLD_CONFIG_API_NO_SUPERCOP */ + +/* If the SUPERCOP API is not needed, we can undefine the various helper macros + * above. Otherwise, they are needed for lazy evaluation of crypto_sign_xxx. */ +#if !defined(MLD_API_LEGACY_CONFIG) +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_QUALIFIER +#endif /* !MLD_API_LEGACY_CONFIG */ + +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_NAMESPACE +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_QUALIFIER +#undef MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_NO_SUPERCOP */ +#endif /* !MLD_CONFIG_API_CONSTANTS_ONLY */ + + +/***************************** Memory Usage **********************************/ + +/* + * By default mldsa-native performs all memory allocations on the stack. + * Alternatively, mldsa-native supports custom allocation of large structures + * through the `MLD_CONFIG_CUSTOM_ALLOC_FREE` configuration option. + * See mldsa_native_config.h for details. + * + * `MLD_TOTAL_ALLOC_{44,65,87}_{KEYPAIR,SIGN,VERIFY}` indicates the maximum + * (accumulative) allocation via MLD_ALLOC for each parameter set and operation. + * Note that some stack allocation remains even + * when using custom allocators, so these values are lower than total stack + * usage with the default stack-only allocation. + * + * These constants may be used to implement custom allocations using a + * fixed-sized buffer and a simple allocator (e.g., bump allocator). + */ +/* check-magic: off */ +#if defined(MLD_API_LEGACY_CONFIG) || !defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 45248 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 56640 +#define MLD_TOTAL_ALLOC_44_SIGN 52896 +#define MLD_TOTAL_ALLOC_44_VERIFY 38816 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 71872 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 85856 +#define MLD_TOTAL_ALLOC_65_SIGN 80576 +#define MLD_TOTAL_ALLOC_65_VERIFY 62432 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 112832 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 130816 +#define MLD_TOTAL_ALLOC_87_SIGN 123584 +#define MLD_TOTAL_ALLOC_87_VERIFY 99552 +#else /* MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM */ +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 32992 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 36192 +#define MLD_TOTAL_ALLOC_44_SIGN 32448 +#define MLD_TOTAL_ALLOC_44_VERIFY 22464 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 46304 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 50048 +#define MLD_TOTAL_ALLOC_65_SIGN 44768 +#define MLD_TOTAL_ALLOC_65_VERIFY 30720 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 62688 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 66336 +#define MLD_TOTAL_ALLOC_87_SIGN 59104 +#define MLD_TOTAL_ALLOC_87_VERIFY 41216 +#endif /* !(MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM) */ +/* check-magic: on */ + +/* + * MLD_TOTAL_ALLOC_*_KEYPAIR adapts based on MLD_CONFIG_KEYGEN_PCT. + * For legacy config, we don't know which options are used, so assume + * the worst case (PCT enabled). + */ +#if defined(MLD_API_LEGACY_CONFIG) || defined(MLD_CONFIG_KEYGEN_PCT) +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#else +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#endif + +#define MLD_MAX3_(a, b, c) \ + ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c))) + +/* + * `MLD_TOTAL_ALLOC_{44,65,87}` is the maximum across all operations for each + * parameter set. + */ +#define MLD_TOTAL_ALLOC_44 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_44_KEYPAIR, MLD_TOTAL_ALLOC_44_SIGN, \ + MLD_TOTAL_ALLOC_44_VERIFY) +#define MLD_TOTAL_ALLOC_65 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_65_KEYPAIR, MLD_TOTAL_ALLOC_65_SIGN, \ + MLD_TOTAL_ALLOC_65_VERIFY) +#define MLD_TOTAL_ALLOC_87 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_87_KEYPAIR, MLD_TOTAL_ALLOC_87_SIGN, \ + MLD_TOTAL_ALLOC_87_VERIFY) + +#endif /* !MLD_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/mldsa_native_config.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/mldsa_native_config.h new file mode 100644 index 0000000000..a17df9b479 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/mldsa_native_config.h @@ -0,0 +1,739 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/* + * Test configuration: Configuration for deterministic-only build of + * mldsa-native + * + * This configuration differs from the default mldsa/mldsa_native_config.h in + * the following places: + * - MLD_CONFIG_NAMESPACE_PREFIX + * - MLD_CONFIG_NO_RANDOMIZED_API + */ + + +#ifndef MLD_CONFIG_H +#define MLD_CONFIG_H + +/****************************************************************************** + * Name: MLD_CONFIG_PARAMETER_SET + * + * Description: Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * If you want to support multiple parameter sets, build the + * library multiple times and set MLD_CONFIG_MULTILEVEL_BUILD. + * See MLD_CONFIG_MULTILEVEL_BUILD for how to do this while + * minimizing code duplication. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of the default configuration file mldsa/mldsa_native_config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * then configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + * + *****************************************************************************/ +/* No need to set this -- we _are_ already in a custom config */ +/* #define MLD_CONFIG_FILE "mldsa_native_config.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_NAMESPACE_PREFIX + * + * Description: The prefix to use to namespace global symbols from mldsa/. + * + * In a multi-level build, level-dependent symbols will + * additionally be prefixed with the parameter set (44/65/87). + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_NAMESPACE_PREFIX mldsa + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_BUILD + * + * Description: Set this if the build is part of a multi-level build supporting + * multiple parameter sets. + * + * If you need only a single parameter set, keep this unset. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them. + * + * See examples/multilevel_build for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_BUILD */ + +/****************************************************************************** + * Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_EXTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_RANDOMIZED_API + * + * Description: If this option is set, mldsa-native will be built without the + * randomized API functions (crypto_sign_keypair, + * crypto_sign, crypto_sign_signature, and + * crypto_sign_signature_extmu). + * This allows users to build mldsa-native without providing a + * randombytes() implementation if they only need the + * internal deterministic API + * (crypto_sign_keypair_internal, crypto_sign_signature_internal). + * + * NOTE: This option is incompatible with MLD_CONFIG_KEYGEN_PCT + * as the current PCT implementation requires + * crypto_sign_signature(). + * + *****************************************************************************/ +#define MLD_CONFIG_NO_RANDOMIZED_API + +/****************************************************************************** + * Name: MLD_CONFIG_NO_SUPERCOP + * + * Description: By default, mldsa_native.h exposes the mldsa-native API in the + * SUPERCOP naming convention (crypto_sign_xxx). If you don't need + * this, set MLD_CONFIG_NO_SUPERCOP. + * + * NOTE: You must set this for a multi-level build as the SUPERCOP + * naming does not disambiguate between the parameter sets. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_SUPERCOP */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONSTANTS_ONLY + * + * Description: If you only need the size constants (MLDSA_PUBLICKEYBYTES, etc.) + * but no function declarations, set MLD_CONFIG_CONSTANTS_ONLY. + * + * This only affects the public header mldsa_native.h, not + * the implementation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONSTANTS_ONLY */ + +/****************************************************************************** + * + * Build-only configuration options + * + * The remaining configurations are build-options only. + * They do not affect the API described in mldsa_native.h. + * + *****************************************************************************/ + +#if defined(MLD_BUILD_INTERNAL) +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_WITH_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, all MLD_CONFIG_PARAMETER_SET-independent + * code will be included in the build, including code needed only + * for other parameter sets. + * + * Example: TODO: add example + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_WITH_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_NO_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, no MLD_CONFIG_PARAMETER_SET-independent code + * will be included in the build. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * + * Description: This is only relevant for single compilation unit (SCU) + * builds of mldsa-native. In this case, it determines whether + * directives defined in parameter-set-independent headers should + * be #undef'ined or not at the of the SCU file. This is needed + * in multilevel builds. + * + * See examples/multilevel_build_native for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * + * Description: Determines whether an native arithmetic backend should be used. + * + * The arithmetic backend covers performance critical functions + * such as the number-theoretic transform (NTT). + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the arithmetic backend to be use is + * determined by MLD_CONFIG_ARITH_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_ARITH_BACKEND_FILE + * + * Description: The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * + * Description: Determines whether an native FIPS202 backend should be used. + * + * The FIPS202 backend covers 1x/2x/4x-fold Keccak-f1600, which is + * the performance bottleneck of SHA3 and SHAKE. + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the FIPS202 backend to be use is + * determined by MLD_CONFIG_FIPS202_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_BACKEND_FILE + * + * Description: The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202X4_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202-X4 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202x4.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ZEROIZE + * + * Description: In compliance with @[FIPS204, Section 3.6.3], mldsa-native, + * zeroizes intermediate stack buffers before returning from + * function calls. + * + * Set this option and define `mld_zeroize` if you want to + * use a custom method to zeroize intermediate stack buffers. + * The default implementation uses SecureZeroMemory on Windows + * and a memset + compiler barrier otherwise. If neither of those + * is available on the target platform, compilation will fail, + * and you will need to use MLD_CONFIG_CUSTOM_ZEROIZE to provide + * a custom implementation of `mld_zeroize()`. + * + * WARNING: + * The explicit stack zeroization conducted by mldsa-native + * reduces the likelihood of data leaking on the stack, but + * does not eliminate it! The C standard makes no guarantee about + * where a compiler allocates structures and whether/where it makes + * copies of them. Also, in addition to entire structures, there + * may also be potentially exploitable leakage of individual values + * on the stack. + * + * If you need bullet-proof zeroization of the stack, you need to + * consider additional measures instead of what this feature + * provides. In this case, you can set mld_zeroize to a + * no-op. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void mld_zeroize(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * Description: mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to provided by the + * consumer. + * + * If this option is not set, mldsa-native expects a function + * int randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mld_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_RANDOMBYTES + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) + { + ... your implementation ... + return 0; + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + * + * Description: mldsa-native backends may rely on specific hardware features. + * Those backends will only be included in an mldsa-native build + * if support for the respective features is enabled at + * compile-time. However, when building for a heteroneous set + * of CPUs to run the resulting binary/library on, feature + * detection at _runtime_ is needed to decided whether a backend + * can be used or not. + * + * Set this option and define `mld_sys_check_capability` if you + * want to use a custom method to dispatch between implementations. + * + * Return value 1 indicates that a capability is supported. + * Return value 0 indicates that a capability is not supported. + * + * If this option is not set, mldsa-native uses compile-time + * feature detection only to decide which backend to use. + * + * If you compile mldsa-native on a system with different + * capabilities than the system that the resulting binary/library + * will be run on, you must use this option. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) + { + ... your implementation ... + } +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ALLOC_FREE [EXPERIMENTAL] + * + * Description: Set this option and define `MLD_CUSTOM_ALLOC` and + * `MLD_CUSTOM_FREE` if you want to use custom allocation for + * large local structures or buffers. + * + * By default, all buffers/structures are allocated on the stack. + * If this option is set, most of them will be allocated via + * MLD_CUSTOM_ALLOC. + * + * Parameters to MLD_CUSTOM_ALLOC: + * - T* v: Target pointer to declare. + * - T: Type of structure to be allocated + * - N: Number of elements to be allocated. + * + * Parameters to MLD_CUSTOM_FREE: + * - T* v: Target pointer to free. May be NULL. + * - T: Type of structure to be freed. + * - N: Number of elements to be freed. + * + * WARNING: This option is experimental! + * Its scope, configuration and function/macro signatures may + * change at any time. We expect a stable API for v2. + * + * NOTE: Even if this option is set, some allocations further down + * the call stack will still be made from the stack. Those will + * likely be added to the scope of this option in the future. + * + * NOTE: MLD_CUSTOM_ALLOC need not guarantee a successful + * allocation nor include error handling. Upon failure, the + * target pointer should simply be set to NULL. The calling + * code will handle this case and invoke MLD_CUSTOM_FREE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ALLOC_FREE + #if !defined(__ASSEMBLER__) + #include + #define MLD_CUSTOM_ALLOC(v, T, N) \ + T* (v) = (T *)aligned_alloc(MLD_DEFAULT_ALIGN, \ + MLD_ALIGN_UP(sizeof(T) * (N))) + #define MLD_CUSTOM_FREE(v, T, N) free(v) + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMCPY + * + * Description: Set this option and define `mld_memcpy` if you want to + * use a custom method to copy memory instead of the standard + * library memcpy function. + * + * The custom implementation must have the same signature and + * behavior as the standard memcpy function: + * void *mld_memcpy(void *dest, const void *src, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMCPY + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMSET + * + * Description: Set this option and define `mld_memset` if you want to + * use a custom method to set memory instead of the standard + * library memset function. + * + * The custom implementation must have the same signature and + * behavior as the standard memset function: + * void *mld_memset(void *s, int c, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMSET + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memset(void *s, int c, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_INTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of internal API. + * + * The primary use case for this option are single-CU builds, + * in which case this option can be set to `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_INTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CT_TESTING_ENABLED + * + * Description: If set, mldsa-native annotates data as secret / public using + * valgrind's annotations VALGRIND_MAKE_MEM_UNDEFINED and + * VALGRIND_MAKE_MEM_DEFINED, enabling various checks for secret- + * dependent control flow of variable time execution (depending + * on the exact version of valgrind installed). + * + *****************************************************************************/ +/* #define MLD_CONFIG_CT_TESTING_ENABLED */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * and MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT + * + * Description: Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, crypto_sign_keypair_internal and + * crypto_sign_keypair will return a non-zero error code if the + * PCT failed. + * + * NOTE: This feature will drastically lower the performance of + * key generation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * Description: If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "src/src.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Description: Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * NOTE: Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + * + *****************************************************************************/ +/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER + * + * Description: Set this to add a context parameter that is provided to public + * API functions and is then available in custom callbacks. + * + * The type of the context parameter is configured via + * MLD_CONFIG_CONTEXT_PARAMETER_TYPE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER_TYPE + * + * Description: Set this to define the type for the context parameter used by + * MLD_CONFIG_CONTEXT_PARAMETER. + * + * This is only relevant if MLD_CONFIG_CONTEXT_PARAMETER is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER_TYPE void* */ + +/****************************************************************************** + * Name: MLD_CONFIG_REDUCE_RAM [EXPERIMENTAL] + * + * Description: Set this to reduce RAM usage. + * This trades memory for performance. + * + * For expected memory usage, see the MLD_TOTAL_ALLOC_* constants + * defined in mldsa_native.h. + * + * This option is useful for embedded systems with tight RAM + * constraints but relaxed performance requirements. + * + * WARNING: This option is experimental! + * CBMC proofs do not currently cover this configuration option. + * Its scope and configuration may change at any time. + * + *****************************************************************************/ +/* #define MLD_CONFIG_REDUCE_RAM */ + +/************************* Config internals ********************************/ + +#endif /* MLD_BUILD_INTERNAL */ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace is + * + * PQCP_MLDSA_NATIVE_MLDSA_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_ + */ + +#if MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65 +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87 +#endif + +#endif /* !MLD_CONFIG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/cbmc.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/cbmc.h new file mode 100644 index 0000000000..8ed1ecb06b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/cbmc.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_CBMC_H +#define MLD_CBMC_H +/*************************************************** + * Basic replacements for __CPROVER_XXX contracts + ***************************************************/ +#ifndef CBMC + +#define __contract__(x) +#define __loop__(x) +#define cassert(x) + +#else /* !CBMC */ + +#include + +#define __contract__(x) x +#define __loop__(x) x + +/* https://diffblue.github.io/cbmc/contracts-assigns.html */ +#define assigns(...) __CPROVER_assigns(__VA_ARGS__) + +/* https://diffblue.github.io/cbmc/contracts-requires-ensures.html */ +#define requires(...) __CPROVER_requires(__VA_ARGS__) +#define ensures(...) __CPROVER_ensures(__VA_ARGS__) +/* https://diffblue.github.io/cbmc/contracts-loops.html */ +#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__) +#define decreases(...) __CPROVER_decreases(__VA_ARGS__) +/* cassert to avoid confusion with in-built assert */ +#define cassert(x) __CPROVER_assert(x, "cbmc assertion failed") +#define assume(...) __CPROVER_assume(__VA_ARGS__) + +/*************************************************** + * Macros for "expression" forms that may appear + * _inside_ top-level contracts. + ***************************************************/ + +/* + * function return value - useful inside ensures + * https://diffblue.github.io/cbmc/contracts-functions.html + */ +#define return_value (__CPROVER_return_value) + +/* + * assigns l-value targets + * https://diffblue.github.io/cbmc/contracts-assigns.html + */ +#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__) +#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__) +#define same_object(...) __CPROVER_same_object(__VA_ARGS__) + +/* + * Pointer-related predicates + * https://diffblue.github.io/cbmc/contracts-memory-predicates.html + */ +#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__) +#define readable(...) __CPROVER_r_ok(__VA_ARGS__) +#define writeable(...) __CPROVER_w_ok(__VA_ARGS__) + +/* Maximum supported buffer size + * + * Larger buffers may be supported, but due to internal modeling constraints + * in CBMC, the proofs of memory- and type-safety won't be able to run. + * + * If you find yourself in need for a buffer size larger than this, + * please contact the maintainers, so we can prioritize work to relax + * this somewhat artificial bound. + */ +#define MLD_MAX_BUFFER_SIZE (SIZE_MAX >> 12) + + +/* + * History variables + * https://diffblue.github.io/cbmc/contracts-history-variables.html + */ +#define old(...) __CPROVER_old(__VA_ARGS__) +#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__) + +/* + * Quantifiers + * Note that the range on qvar is _exclusive_ between qvar_lb .. qvar_ub + * https://diffblue.github.io/cbmc/contracts-quantifiers.html + */ + +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define forall(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> (predicate) \ + } + +#define exists(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_exists \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) && (predicate) \ + } +/* clang-format on */ + +/*************************************************** + * Convenience macros for common contract patterns + ***************************************************/ +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define CBMC_CONCAT_(left, right) left##right +#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right) + +#define array_bound_core(qvar, qvar_lb, qvar_ub, array_var, \ + value_lb, value_ub) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + (((int)(value_lb) <= ((array_var)[(qvar)])) && \ + (((array_var)[(qvar)]) < (int)(value_ub))) \ + } + +#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \ + array_bound_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (qvar_lb), \ + (qvar_ub), (array_var), (value_lb), (value_ub)) + +#define array_unchanged_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (int32_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged(array_var, N) \ + array_unchanged_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) + +#define array_unchanged_u64_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (uint64_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged_u64(array_var, N) \ + array_unchanged_u64_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) +/* clang-format on */ + +/* Wrapper around array_bound operating on absolute values. + * + * The absolute value bound `k` is exclusive. + * + * Note that since the lower bound in array_bound is inclusive, we have to + * raise it by 1 here. + */ +#define array_abs_bound(arr, lb, ub, k) \ + array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k)) + +#endif /* CBMC */ + +#endif /* !MLD_CBMC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/common.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/common.h new file mode 100644 index 0000000000..4a5bc8109d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/common.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_COMMON_H +#define MLD_COMMON_H + +#define MLD_BUILD_INTERNAL + +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#include "params.h" +#include "sys.h" + +/* Internal and public API have external linkage by default, but + * this can be overwritten by the user, e.g. for single-CU builds. */ +#if !defined(MLD_CONFIG_INTERNAL_API_QUALIFIER) +#define MLD_INTERNAL_API +#else +#define MLD_INTERNAL_API MLD_CONFIG_INTERNAL_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_EXTERNAL_API +#else +#define MLD_EXTERNAL_API MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#if defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) || \ + defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) +#define MLD_MULTILEVEL_BUILD +#endif + +#define MLD_CONCAT_(x1, x2) x1##x2 +#define MLD_CONCAT(x1, x2) MLD_CONCAT_(x1, x2) + +#if defined(MLD_MULTILEVEL_BUILD) +#define MLD_ADD_PARAM_SET(s) MLD_CONCAT(s, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_ADD_PARAM_SET(s) s +#endif + +#define MLD_NAMESPACE_PREFIX MLD_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, _) +#define MLD_NAMESPACE_PREFIX_KL \ + MLD_CONCAT(MLD_ADD_PARAM_SET(MLD_CONFIG_NAMESPACE_PREFIX), _) + +/* Functions are prefixed by MLD_CONFIG_NAMESPACE_PREFIX. + * + * If multiple parameter sets are used, functions depending on the parameter + * set are additionally prefixed with 44/65/87. See mldsa_native_config.h. + * + * Example: If MLD_CONFIG_NAMESPACE_PREFIX is PQCP_MLDSA_NATIVE, then + * MLD_NAMESPACE_KL(keypair) becomes PQCP_MLDSA_NATIVE44_keypair/ + * PQCP_MLDSA_NATIVE65_keypair/PQCP_MLDSA_NATIVE87_keypair. + */ +#define MLD_NAMESPACE(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX, s) +#define MLD_NAMESPACE_KL(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX_KL, s) + +/* On Apple platforms, we need to emit leading underscore + * in front of assembly symbols. We thus introducee a separate + * namespace wrapper for ASM symbols. */ +#if !defined(__APPLE__) +#define MLD_ASM_NAMESPACE(sym) MLD_NAMESPACE(sym) +#else +#define MLD_ASM_NAMESPACE(sym) MLD_CONCAT(_, MLD_NAMESPACE(sym)) +#endif + +/* + * On X86_64 if control-flow protections (CET) are enabled (through + * -fcf-protection=), we add an endbr64 instruction at every global function + * label. See sys.h for more details + */ +#if defined(MLD_SYS_X86_64) +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : MLD_CET_ENDBR +#else +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : +#endif + +/* We aim to simplify the user's life by supporting builds where + * all source files are included, even those that are not needed. + * Those files are appropriately guarded and will be empty when unneeded. + * The following is to avoid compilers complaining about this. */ +#define MLD_EMPTY_CU(s) extern int MLD_NAMESPACE_KL(empty_cu_##s); + +/* MLD_CONFIG_NO_ASM takes precedence over MLD_USE_NATIVE_XXX */ +#if defined(MLD_CONFIG_NO_ASM) +#undef MLD_CONFIG_USE_NATIVE_BACKEND_ARITH +#undef MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, but MLD_CONFIG_ARITH_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, but MLD_CONFIG_FIPS202_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_NO_RANDOMIZED_API) && defined(MLD_CONFIG_KEYGEN_PCT) +#error Bad configuration: MLD_CONFIG_NO_RANDOMIZED_API is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires crypto_sign_signature() +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#include MLD_CONFIG_ARITH_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#include MLD_CONFIG_FIPS202_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "fips202/native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#define MLD_FIPS202_HEADER_FILE "fips202/fips202.h" +#else +#define MLD_FIPS202_HEADER_FILE MLD_CONFIG_FIPS202_CUSTOM_HEADER +#endif + +#if !defined(MLD_CONFIG_FIPS202X4_CUSTOM_HEADER) +#define MLD_FIPS202X4_HEADER_FILE "fips202/fips202x4.h" +#else +#define MLD_FIPS202X4_HEADER_FILE MLD_CONFIG_FIPS202X4_CUSTOM_HEADER +#endif + +/* Standard library function replacements */ +#if !defined(__ASSEMBLER__) +#if !defined(MLD_CONFIG_CUSTOM_MEMCPY) +#include +#define mld_memcpy memcpy +#endif + +#if !defined(MLD_CONFIG_CUSTOM_MEMSET) +#include +#define mld_memset memset +#endif + +/* Allocation macros for large local structures + * + * MLD_ALLOC(v, T, N) declares T *v and attempts to point it to an T[N] + * MLD_FREE(v, T, N) zeroizes and frees the allocation + * + * Default implementation uses stack allocation. + * Can be overridden by setting the config option MLD_CONFIG_CUSTOM_ALLOC_FREE + * and defining MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE. + */ +#if defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) != \ + (defined(MLD_CUSTOM_ALLOC) && defined(MLD_CUSTOM_FREE)) +#error Bad configuration: MLD_CONFIG_CUSTOM_ALLOC_FREE must be set together with MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE +#endif + +/* + * If the integration wants to provide a context parameter for use in + * platform-specific hooks, then it should define this parameter. + * + * The MLD_CONTEXT_PARAMETERS_n macros are intended to be used with macros + * defining the function names and expand to either pass or discard the context + * argument as required by the current build. If there is no context parameter + * requested then these are removed from the prototypes and from all calls. + */ +#ifdef MLD_CONFIG_CONTEXT_PARAMETER +#define MLD_CONTEXT_PARAMETERS_0(context) (context) +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0, context) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1, context) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) \ + (arg0, arg1, arg2, context) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3, context) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4, context) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, context) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, context) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, context) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, context) +#else /* MLD_CONFIG_CONTEXT_PARAMETER */ +#define MLD_CONTEXT_PARAMETERS_0(context) () +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) (arg0, arg1, arg2) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) +#endif /* !MLD_CONFIG_CONTEXT_PARAMETER */ + +#if defined(MLD_CONFIG_CONTEXT_PARAMETER_TYPE) != \ + defined(MLD_CONFIG_CONTEXT_PARAMETER) +#error MLD_CONFIG_CONTEXT_PARAMETER_TYPE must be defined if and only if MLD_CONFIG_CONTEXT_PARAMETER is defined +#endif + +#if !defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) +/* Default: stack allocation */ + +#define MLD_ALLOC(v, T, N, context) \ + MLD_ALIGN T mld_alloc_##v[N]; \ + T *v = mld_alloc_##v + +/* TODO: This leads to a circular dependency between common and ct.h + * It just works out before we're at the end of the file, but it's still + * prone to issues in the future. */ +#include "ct.h" +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + mld_zeroize(mld_alloc_##v, sizeof(mld_alloc_##v)); \ + (v) = NULL; \ + } while (0) + +#else /* !MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* Custom allocation */ + +/* + * The indirection here is necessary to use MLD_CONTEXT_PARAMETERS_3 here. + */ +#define MLD_APPLY(f, args) f args + +#define MLD_ALLOC(v, T, N, context) \ + MLD_APPLY(MLD_CUSTOM_ALLOC, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)) + +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + if (v != NULL) \ + { \ + mld_zeroize(v, sizeof(T) * (N)); \ + MLD_APPLY(MLD_CUSTOM_FREE, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)); \ + v = NULL; \ + } \ + } while (0) + +#endif /* MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* + * We are facing severe CBMC performance issues when using unions. + * As a temporary workaround, we use unions only when MLD_CONFIG_REDUCE_RAM is + * set. + * TODO: Remove the workaround once + * https://github.com/diffblue/cbmc/issues/8813 + * is resolved + */ +#if defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_UNION_OR_STRUCT union +#else +#define MLD_UNION_OR_STRUCT struct +#endif + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_COMMON_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/ct.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/ct.c new file mode 100644 index 0000000000..010b1a52a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/ct.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include "ct.h" + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +/* + * Masking value used in constant-time functions from + * ct.h to block the compiler's range analysis and + * thereby reduce the risk of compiler-introduced branches. + */ +volatile uint64_t mld_ct_opt_blocker_u64 = 0; + +#else /* !MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(ct) + +#endif /* !(!MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/ct.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/ct.h new file mode 100644 index 0000000000..c307456468 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/ct.h @@ -0,0 +1,366 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [libmceliece] + * libmceliece implementation of Classic McEliece + * Bernstein, Chou + * https://lib.mceliece.org/ + * + * - [optblocker] + * PQC forum post on opt-blockers using volatile globals + * Daniel J. Bernstein + * https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ + */ + +#ifndef MLD_CT_H +#define MLD_CT_H + +#include +#include "cbmc.h" +#include "common.h" + +/* Constant-time comparisons and conditional operations + + We reduce the risk for compilation into variable-time code + through the use of 'value barriers'. + + Functionally, a value barrier is a no-op. To the compiler, however, + it constitutes an arbitrary modification of its input, and therefore + harden's value propagation and range analysis. + + We consider two approaches to implement a value barrier: + - An empty inline asm block which marks the target value as clobbered. + - XOR'ing with the value of a volatile global that's set to 0; + see @[optblocker] for a discussion of this idea, and + @[libmceliece, inttypes/crypto_intN.h] for an implementation. + + The first approach is cheap because it only prevents the compiler + from reasoning about the value of the variable past the barrier, + but does not directly generate additional instructions. + + The second approach generates redundant loads and XOR operations + and therefore comes at a higher runtime cost. However, it appears + more robust towards optimization, as compilers should never drop + a volatile load. + + We use the empty-ASM value barrier for GCC and clang, and fall + back to the global volatile barrier otherwise. + + The global value barrier can be forced by setting + MLD_CONFIG_NO_ASM_VALUE_BARRIER. + +*/ + +#if defined(MLD_HAVE_INLINE_ASM) && !defined(MLD_CONFIG_NO_ASM_VALUE_BARRIER) +#define MLD_USE_ASM_VALUE_BARRIER +#endif + + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) +/* + * Declaration of global volatile that the global value barrier + * is loading from and masking with. + */ +#define mld_ct_opt_blocker_u64 MLD_NAMESPACE(ct_opt_blocker_u64) +extern volatile uint64_t mld_ct_opt_blocker_u64; + + +/* Helper functions for obtaining global masks of various sizes */ + +/* This contract is not proved but treated as an axiom. + * + * Its validity relies on the assumption that the global opt-blocker + * constant mld_ct_opt_blocker_u64 is not modified. + */ +static MLD_INLINE uint64_t mld_ct_get_optblocker_u64(void) +__contract__(ensures(return_value == 0)) { return mld_ct_opt_blocker_u64; } + +static MLD_INLINE int64_t mld_ct_get_optblocker_i64(void) +__contract__(ensures(return_value == 0)) { return (int64_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint32_t mld_ct_get_optblocker_u32(void) +__contract__(ensures(return_value == 0)) { return (uint32_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint8_t mld_ct_get_optblocker_u8(void) +__contract__(ensures(return_value == 0)) { return (uint8_t)mld_ct_get_optblocker_u64(); } + +/* Opt-blocker based implementation of value barriers */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_i64()); } + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u32()); } + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u8()); } + + +#else /* !MLD_USE_ASM_VALUE_BARRIER */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} +#endif /* MLD_USE_ASM_VALUE_BARRIER */ + +#ifdef CBMC +#pragma CPROVER check push +#pragma CPROVER check disable "conversion" +#endif + +/************************************************* + * Name: mld_cast_uint32_to_int32 + * + * Description: Cast uint32 value to int32 + * + * Returns: For uint32_t x, the unique y in int32_t + * so that x == y mod 2^32. + * + * Concretely: + * - x < 2^31: returns x + * - x >= 2^31: returns x - 2^31 + * + **************************************************/ +static MLD_ALWAYS_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x) +{ + /* + * PORTABILITY: This relies on uint32_t -> int32_t + * being implemented as the inverse of int32_t -> uint32_t, + * which is implementation-defined (C99 6.3.1.3 (3)) + * CBMC (correctly) fails to prove this conversion is OK, + * so we have to suppress that check here + */ + return (int32_t)x; +} + +#ifdef CBMC +#pragma CPROVER check pop +#endif + + +/************************************************* + * Name: mld_cast_int64_to_uint32 + * + * Description: Cast int64 value to uint32 as per C standard. + * + * Returns: For int64_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int64_to_uint32(int64_t x) +{ + return (uint32_t)(x & (int64_t)UINT32_MAX); +} + +/************************************************* + * Name: mld_cast_int32_to_uint32 + * + * Description: Cast int32 value to uint32 as per C standard. + * + * Returns: For int32_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int32_to_uint32(int32_t x) +{ + return mld_cast_int64_to_uint32((int64_t)x); +} + +/************************************************* + * Name: mld_ct_sel_int32 + * + * Description: Functionally equivalent to cond ? a : b, + * but implemented with guards against + * compiler-introduced branches. + * + * Arguments: int32_t a: First alternative + * int32_t b: Second alternative + * uint32_t cond: Condition variable. + * + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_sel_int32(int32_t a, int32_t b, uint32_t cond) +__contract__( + requires(cond == 0x0 || cond == 0xFFFFFFFF) + ensures(return_value == (cond ? a : b)) +) +{ + uint32_t au = mld_cast_int32_to_uint32(a); + uint32_t bu = mld_cast_int32_to_uint32(b); + uint32_t res = bu ^ (mld_value_barrier_u32(cond) & (au ^ bu)); + return mld_cast_uint32_to_int32(res); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u32 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_nonzero_u32(uint32_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFFFFFFFF))) +{ + int64_t tmp = mld_value_barrier_i64(-((int64_t)x)); + tmp >>= 32; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u8 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint8_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint8_t mld_ct_cmask_nonzero_u8(uint8_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFF))) +{ + uint32_t mask = mld_ct_cmask_nonzero_u32((uint32_t)x); + return (uint8_t)(mask & 0xFF); +} + +/************************************************* + * Name: mld_ct_cmask_neg_i32 + * + * Description: Return 0 if input is non-negative, and -1 otherwise. + * + * Arguments: int32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_neg_i32(int32_t x) +__contract__( + ensures(return_value == ((x < 0) ? 0xFFFFFFFF : 0)) +) +{ + int64_t tmp = mld_value_barrier_i64((int64_t)x); + tmp >>= 31; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_abs_i32 + * + * Description: Return -x if x<0, x otherwise + * + * Arguments: int32_t x: Input value + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_abs_i32(int32_t x) +__contract__( + requires(x >= -INT32_MAX) + ensures(return_value == ((x < 0) ? -x : x)) +) +{ + return mld_ct_sel_int32(-x, x, mld_ct_cmask_neg_i32(x)); +} + +/************************************************* + * Name: mld_ct_memcmp + * + * Description: Compare two arrays for equality in constant time. + * + * Arguments: const uint8_t *a: pointer to first byte array + * const uint8_t *b: pointer to second byte array + * size_t len: length of the byte arrays, upper-bounded + * to UINT16_MAX to control proof complexity + * only. + * + * Returns 0 if the byte arrays are equal, 0xFF otherwise. + **************************************************/ +static MLD_INLINE uint8_t mld_ct_memcmp(const uint8_t *a, const uint8_t *b, + const size_t len) +__contract__( + requires(len <= UINT16_MAX) + requires(memory_no_alias(a, len)) + requires(memory_no_alias(b, len)) + ensures((return_value == 0) || (return_value == 0xFF)) + ensures((return_value == 0) == forall(i, 0, len, (a[i] == b[i])))) +{ + uint8_t r = 0, s = 0; + unsigned i; + + for (i = 0; i < len; i++) + __loop__( + invariant(i <= len) + invariant((r == 0) == (forall(k, 0, i, (a[k] == b[k]))))) + { + r |= a[i] ^ b[i]; + /* s is useless, but prevents the loop from being aborted once r=0xff. */ + s ^= a[i] ^ b[i]; + } + + /* + * - Convert r into a mask; this may not be necessary, but is an additional + * safeguard + * towards leaking information about a and b. + * - XOR twice with s, separated by a value barrier, to prevent the compile + * from dropping the s computation in the loop. + */ + return (mld_value_barrier_u8(mld_ct_cmask_nonzero_u8(r) ^ s) ^ s); +} + +/************************************************* + * Name: mld_zeroize + * + * Description: Force-zeroize a buffer. + * @[FIPS204, Section 3.6.3] Destruction of intermediate + * values. + * + * Arguments: void *ptr: pointer to buffer to be zeroed + * size_t len: Amount of bytes to be zeroed + **************************************************/ +#if !defined(MLD_CONFIG_CUSTOM_ZEROIZE) +#if defined(MLD_SYS_WINDOWS) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) { SecureZeroMemory(ptr, len); } +#elif defined(MLD_HAVE_INLINE_ASM) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) +{ + memset(ptr, 0, len); + /* This follows OpenSSL and seems sufficient to prevent the compiler + * from optimizing away the memset. + * + * If there was a reliable way to detect availability of memset_s(), + * that would be preferred. */ + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +} +#else /* !MLD_SYS_WINDOWS && MLD_HAVE_INLINE_ASM */ +#error No plausibly-secure implementation of mld_zeroize available. Please provide your own using MLD_CONFIG_CUSTOM_ZEROIZE. +#endif /* !MLD_SYS_WINDOWS && !MLD_HAVE_INLINE_ASM */ +#endif /* !MLD_CONFIG_CUSTOM_ZEROIZE */ + +#endif /* !MLD_CT_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/debug.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/debug.c new file mode 100644 index 0000000000..a55d51e8b1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/debug.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* NOTE: You can remove this file unless you compile with MLDSA_DEBUG. */ + +#include "common.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#if defined(MLDSA_DEBUG) + +#include +#include +#include +#include "debug.h" + +#define MLD_DEBUG_ERROR_HEADER "[ERROR:%s:%04d] " + +void mld_debug_check_assert(const char *file, int line, const int val) +{ + if (val == 0) + { + fprintf(stderr, MLD_DEBUG_ERROR_HEADER "Assertion failed (value %d)\n", + file, line, val); + exit(1); + } +} + +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive) +{ + int err = 0; + unsigned i; + for (i = 0; i < len; i++) + { + int32_t val = ptr[i]; + if (!(val > lower_bound_exclusive && val < upper_bound_exclusive)) + { + fprintf(stderr, + MLD_DEBUG_ERROR_HEADER + "Bounds assertion failed: Index %u, value %d out of bounds " + "(%" PRId64 ",%" PRId64 ")\n", + file, line, i, (int)val, lower_bound_exclusive, + upper_bound_exclusive); + err = 1; + } + } + + if (err == 1) + { + exit(1); + } +} + +#else /* MLDSA_DEBUG */ + +MLD_EMPTY_CU(debug) + +#endif /* !MLDSA_DEBUG */ + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(debug) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_DEBUG_ERROR_HEADER diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/debug.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/debug.h new file mode 100644 index 0000000000..af187bb9de --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/debug.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_DEBUG_H +#define MLD_DEBUG_H +#include "common.h" + +#if defined(MLDSA_DEBUG) +#include + +/************************************************* + * Name: mld_assert + * + * Description: Check debug assertion + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - val: Value asserted to be non-zero + **************************************************/ +#define mld_debug_check_assert MLD_NAMESPACE(mldsa_debug_assert) +void mld_debug_check_assert(const char *file, int line, const int val); + +/************************************************* + * Name: mld_debug_check_bounds + * + * Description: Check whether values in an array of int32_t + * are within specified bounds. + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - ptr: Base of array to be checked + * - len: Number of int32_t in ptr + * - lower_bound_exclusive: Exclusive lower bound + * - upper_bound_exclusive: Exclusive upper bound + **************************************************/ +#define mld_debug_check_bounds MLD_NAMESPACE(mldsa_debug_check_bounds) +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive); + +/* Check assertion, calling exit() upon failure + * + * val: Value that's asserted to be non-zero + */ +#define mld_assert(val) mld_debug_check_assert(__FILE__, __LINE__, (val)) + +/* Check bounds in array of int32_t's + * ptr: Base of int32_t array; will be explicitly cast to int32_t*, + * so you may pass a byte-compatible type such as mld_poly or mld_polyvec. + * len: Number of int32_t in array + * value_lb: Inclusive lower value bound + * value_ub: Exclusive upper value bound */ +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + mld_debug_check_bounds(__FILE__, __LINE__, (const int32_t *)(ptr), (len), \ + ((int64_t)(value_lb)) - 1, (value_ub)) + +/* Check absolute bounds in array of int32_t's + * ptr: Base of array, expression of type int32_t* + * len: Number of int32_t in array + * value_abs_bd: Exclusive absolute upper bound */ +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + mld_assert_bound((ptr), (len), (-((int64_t)(value_abs_bd)) + 1), \ + (value_abs_bd)) + +/* Version of bounds assertions for 2-dimensional arrays */ +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + mld_assert_bound((ptr), ((len0) * (len1)), (value_lb), (value_ub)) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + mld_assert_abs_bound((ptr), ((len0) * (len1)), (value_abs_bd)) + +/* When running CBMC, convert debug assertions into proof obligations */ +#elif defined(CBMC) +#include "cbmc.h" + +#define mld_assert(val) cassert(val) + +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + cassert(array_bound(((int32_t *)(ptr)), 0, (len), (value_lb), (value_ub))) + +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + cassert(array_abs_bound(((int32_t *)(ptr)), 0, (len), (value_abs_bd))) + +/* Because of https://github.com/diffblue/cbmc/issues/8570, we can't + * just use a single flattened array_bound(...) here. */ +#define mld_assert_bound_2d(ptr, M, N, value_lb, value_ub) \ + cassert(forall(kN, 0, (M), \ + array_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_lb), (value_ub)))) + +#define mld_assert_abs_bound_2d(ptr, M, N, value_abs_bd) \ + cassert(forall(kN, 0, (M), \ + array_abs_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_abs_bd)))) + +#else /* !MLDSA_DEBUG && CBMC */ + +#define mld_assert(val) \ + do \ + { \ + } while (0) +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + do \ + { \ + } while (0) +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + do \ + { \ + } while (0) + +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + do \ + { \ + } while (0) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + do \ + { \ + } while (0) + + +#endif /* !MLDSA_DEBUG && !CBMC */ +#endif /* !MLD_DEBUG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/fips202.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/fips202.c new file mode 100644 index 0000000000..1112de061c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/fips202.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "../common.h" +#include "../ct.h" +#include "fips202.h" +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +/************************************************* + * Name: keccak_init + * + * Description: Initializes the Keccak state. + * + * Arguments: - uint64_t *s: pointer to Keccak state + **************************************************/ +static void keccak_init(uint64_t s[MLD_KECCAK_LANES]) +__contract__( + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + mld_memset(s, 0, sizeof(uint64_t) * MLD_KECCAK_LANES); +} + +/************************************************* + * Name: keccak_absorb + * + * Description: Absorb step of Keccak; incremental. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_absorb(uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r, + const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(pos <= r) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(in, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + ensures(return_value < r)) +{ + while (inlen >= r - pos) + __loop__( + assigns(pos, in, inlen, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + invariant(inlen <= loop_entry(inlen)) + invariant(pos <= r) + invariant(in == loop_entry(in) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600_xor_bytes(s, in, pos, r - pos); + inlen -= r - pos; + in += r - pos; + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: At this point, inlen < r, so the truncation to unsigned is safe. */ + mld_keccakf1600_xor_bytes(s, in, pos, (unsigned)inlen); + + /* Safety: At this point, inlen < r and pos <= r so the truncation to unsigned + * is safe. */ + return (unsigned)(pos + inlen); +} + +/************************************************* + * Name: keccak_finalize + * + * Description: Finalize absorb step. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - uint8_t p: domain separation byte + **************************************************/ +static void keccak_finalize(uint64_t s[MLD_KECCAK_LANES], unsigned int pos, + unsigned int r, uint8_t p) +__contract__( + requires(pos <= r && r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires((r / 8) >= 1) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + uint8_t b = 0x80; + mld_keccakf1600_xor_bytes(s, &p, pos, 1); + mld_keccakf1600_xor_bytes(s, &b, r - 1, 1); +} + +/************************************************* + * Name: keccak_squeeze + * + * Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes. + * Modifies the state. Can be called multiple times to keep + * squeezing, i.e., is incremental. + * + * Arguments: - uint8_t *out: pointer to output data + * - size_t outlen: number of bytes to be squeezed (written to out) + * - uint64_t *s: pointer to input/output Keccak state + * - unsigned int pos: number of bytes in current block already + *squeezed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_squeeze(uint8_t *out, size_t outlen, + uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r) +__contract__( + requires((r == SHAKE128_RATE && pos <= SHAKE128_RATE) || + (r == SHAKE256_RATE && pos <= SHAKE256_RATE) || + (r == SHA3_512_RATE && pos <= SHA3_512_RATE)) + requires(outlen <= 8 * r /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(out, outlen)) + ensures(return_value <= r)) +{ + unsigned int i; + size_t out_offset = 0; + + /* Reference: This code is re-factored from the reference implementation + * to facilitate proof with CBMC and to improve readability. + * + * Take a mutable copy of outlen to count down the number of bytes + * still to squeeze. The initial value of outlen is needed for the CBMC + * assigns() clauses. */ + size_t bytes_to_go = outlen; + + while (bytes_to_go > 0) + __loop__( + assigns(i, bytes_to_go, pos, out_offset, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES), memory_slice(out, outlen)) + invariant(bytes_to_go <= outlen) + invariant(out_offset == outlen - bytes_to_go) + invariant(pos <= r) + ) + { + if (pos == r) + { + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: If bytes_to_go < r - pos, truncation to unsigned is safe. */ + i = bytes_to_go < r - pos ? (unsigned)bytes_to_go : r - pos; + mld_keccakf1600_extract_bytes(s, out + out_offset, pos, i); + bytes_to_go -= i; + pos += i; + out_offset += i; + } + + return pos; +} + +void mld_shake128_init(mld_shake128ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE128_RATE, in, inlen); +} + +void mld_shake128_finalize(mld_shake128ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE128_RATE, 0x1F); + state->pos = SHAKE128_RATE; +} + +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE128_RATE); +} + +void mld_shake128_release(mld_shake128ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128ctx)); +} + +void mld_shake256_init(mld_shake256ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); +} + +void mld_shake256_finalize(mld_shake256ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); + state->pos = SHAKE256_RATE; +} + +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); +} + +void mld_shake256_release(mld_shake256ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256ctx)); +} + +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +{ + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, in, inlen); + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/fips202.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/fips202.h new file mode 100644 index 0000000000..9f0253cb88 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/fips202.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202_H +#define MLD_FIPS202_FIPS202_H + +#include +#include +#include "../cbmc.h" +#include "../common.h" + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 +#define SHA3_256_RATE 136 +#define SHA3_512_RATE 72 +#define MLD_KECCAK_LANES 25 +#define SHA3_256_HASHBYTES 32 +#define SHA3_512_HASHBYTES 64 + + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake128ctx; + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake256ctx; + +#define mld_shake128_init MLD_NAMESPACE(shake128_init) +/************************************************* + * Name: mld_shake128_init + * + * Description: Initializes state for use as SHAKE128 XOF + * + * Arguments: - mld_shake128ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake128_init(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos == 0) +); + +#define mld_shake128_absorb MLD_NAMESPACE(shake128_absorb) +/************************************************* + * Name: mld_shake128_absorb + * + * Description: Absorb step of the SHAKE128 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake128ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_finalize MLD_NAMESPACE(shake128_finalize) +/************************************************* + * Name: mld_shake128_finalize + * + * Description: Concludes the absorb phase of the SHAKE128 XOF. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_finalize(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_squeeze MLD_NAMESPACE(shake128_squeeze) +/************************************************* + * Name: mld_shake128_squeeze + * + * Description: Squeeze step of SHAKE128 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake128ctx *s: pointer to input/output state + **************************************************/ +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE128_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_release MLD_NAMESPACE(shake128_release) +/************************************************* + * Name: mld_shake128_release + * + * Description: Release and securely zero the SHAKE128 state. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_release(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) +); + +#define mld_shake256_init MLD_NAMESPACE(shake256_init) +/************************************************* + * Name: mld_shake256_init + * + * Description: Initializes state for use as SHAKE256 XOF + * + * Arguments: - mld_shake256ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake256_init(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos == 0) +); + +#define mld_shake256_absorb MLD_NAMESPACE(shake256_absorb) +/************************************************* + * Name: mld_shake256_absorb + * + * Description: Absorb step of the SHAKE256 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake256ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_finalize MLD_NAMESPACE(shake256_finalize) +/************************************************* + * Name: mld_shake256_finalize + * + * Description: Concludes the absorb phase of the SHAKE256 XOF. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_finalize(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_squeeze MLD_NAMESPACE(shake256_squeeze) +/************************************************* + * Name: mld_shake256_squeeze + * + * Description: Squeeze step of SHAKE256 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake256ctx *s: pointer to input/output state + **************************************************/ +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_release MLD_NAMESPACE(shake256_release) +/************************************************* + * Name: mld_shake256_release + * + * Description: Release and securely zero the SHAKE256 state. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_release(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) +); + +#define mld_shake256 MLD_NAMESPACE(shake256) +/************************************************* + * Name: mld_shake256 + * + * Description: SHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +); + +#endif /* !MLD_FIPS202_FIPS202_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/fips202x4.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/fips202x4.c new file mode 100644 index 0000000000..0fb5cd57c7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/fips202x4.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include "../common.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "../ct.h" +#include "fips202.h" +#include "fips202x4.h" +#include "keccakf1600.h" + +static void mld_keccak_absorb_once_x4(uint64_t *s, uint32_t r, + const uint8_t *in0, const uint8_t *in1, + const uint8_t *in2, const uint8_t *in3, + size_t inlen, uint8_t p) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))) +{ + while (inlen >= r) + __loop__( + assigns(inlen, in0, in1, in2, in3, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + invariant(inlen <= loop_entry(inlen)) + invariant(in0 == loop_entry(in0) + (loop_entry(inlen) - inlen)) + invariant(in1 == loop_entry(in1) + (loop_entry(inlen) - inlen)) + invariant(in2 == loop_entry(in2) + (loop_entry(inlen) - inlen)) + invariant(in3 == loop_entry(in3) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, r); + mld_keccakf1600x4_permute(s); + + in0 += r; + in1 += r; + in2 += r; + in3 += r; + inlen -= r; + } + + /* Safety: At this point, inlen < r, so the truncations to unsigned are safe + * below. */ + if (inlen > 0) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, (unsigned)inlen); + } + + if (inlen == r - 1) + { + p |= 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + } + else + { + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + p = 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, r - 1, 1); + } +} + +static void mld_keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1, + uint8_t *out2, uint8_t *out3, + size_t nblocks, uint64_t *s, uint32_t r) +__contract__( + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(out0, nblocks * r)) + requires(memory_no_alias(out1, nblocks * r)) + requires(memory_no_alias(out2, nblocks * r)) + requires(memory_no_alias(out3, nblocks * r)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(out0, nblocks * r)) + assigns(memory_slice(out1, nblocks * r)) + assigns(memory_slice(out2, nblocks * r)) + assigns(memory_slice(out3, nblocks * r))) +{ + while (nblocks > 0) + __loop__( + assigns(out0, out1, out2, out3, nblocks, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY), + memory_slice(out0, nblocks * r), + memory_slice(out1, nblocks * r), + memory_slice(out2, nblocks * r), + memory_slice(out3, nblocks * r)) + invariant(nblocks <= loop_entry(nblocks) && + out0 == loop_entry(out0) + r * (loop_entry(nblocks) - nblocks) && + out1 == loop_entry(out1) + r * (loop_entry(nblocks) - nblocks) && + out2 == loop_entry(out2) + r * (loop_entry(nblocks) - nblocks) && + out3 == loop_entry(out3) + r * (loop_entry(nblocks) - nblocks))) + { + mld_keccakf1600x4_permute(s); + mld_keccakf1600x4_extract_bytes(s, out0, out1, out2, out3, 0, r); + + out0 += r; + out1 += r; + out2 += r; + out3 += r; + nblocks--; + } +} + +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake128x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE128_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE128_RATE); +} + +void mld_shake128x4_init(mld_shake128x4ctx *state) { (void)state; } +void mld_shake128x4_release(mld_shake128x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128x4ctx)); +} + + +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake256x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE256_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE256_RATE); +} + +void mld_shake256x4_init(mld_shake256x4ctx *state) { (void)state; } +void mld_shake256x4_release(mld_shake256x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256x4ctx)); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/fips202x4.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/fips202x4.h new file mode 100644 index 0000000000..e7987207a6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/fips202x4.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202X4_H +#define MLD_FIPS202_FIPS202X4_H + +#include +#include + +#include "../cbmc.h" +#include "../common.h" + +#include "fips202.h" +#include "keccakf1600.h" + +/* Context for non-incremental API */ +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake128x4ctx; + +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake256x4ctx; + +#define mld_shake128x4_absorb_once MLD_NAMESPACE(shake128x4_absorb_once) +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_squeezeblocks MLD_NAMESPACE(shake128x4_squeezeblocks) +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE128_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE128_RATE), + memory_slice(out1, nblocks * SHAKE128_RATE), + memory_slice(out2, nblocks * SHAKE128_RATE), + memory_slice(out3, nblocks * SHAKE128_RATE), + memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_init MLD_NAMESPACE(shake128x4_init) +void mld_shake128x4_init(mld_shake128x4ctx *state); + +#define mld_shake128x4_release MLD_NAMESPACE(shake128x4_release) +void mld_shake128x4_release(mld_shake128x4ctx *state); + + +#define mld_shake256x4_absorb_once MLD_NAMESPACE(shake256x4_absorb_once) +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_squeezeblocks MLD_NAMESPACE(shake256x4_squeezeblocks) +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE256_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE256_RATE), + memory_slice(out1, nblocks * SHAKE256_RATE), + memory_slice(out2, nblocks * SHAKE256_RATE), + memory_slice(out3, nblocks * SHAKE256_RATE), + memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_init MLD_NAMESPACE(shake256x4_init) +void mld_shake256x4_init(mld_shake256x4ctx *state); + +#define mld_shake256x4_release MLD_NAMESPACE(shake256x4_release) +void mld_shake256x4_release(mld_shake256x4ctx *state); + + +#endif /* !MLD_FIPS202_FIPS202X4_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/keccakf1600.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/keccakf1600.c new file mode 100644 index 0000000000..e59120c07c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/keccakf1600.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#define MLD_KECCAK_NROUNDS 24 +#define MLD_KECCAK_ROL(a, offset) ((a << offset) ^ (a >> (64 - offset))) + +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = state_ptr[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = (state[(offset + i) >> 3] >> (8 * ((offset + i) & 0x07))) & 0xFF; + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state_ptr[i] ^= data[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state[(offset + i) >> 3] ^= (uint64_t)data[i] + << (8 * ((offset + i) & 0x07)); + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X4_NATIVE) + if (mld_keccak_f1600_x4_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 0); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 1); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 2); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 3); +} + +static const uint64_t mld_KeccakF_RoundConstants[MLD_KECCAK_NROUNDS] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +static void mld_keccakf1600_permute_c(uint64_t *state) +{ + unsigned round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + uint64_t BCa, BCe, BCi, BCo, BCu; + uint64_t Da, De, Di, Do, Du; + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + /* copyFromState(A, state) */ + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < MLD_KECCAK_NROUNDS; round += 2) + __loop__(invariant(round <= MLD_KECCAK_NROUNDS && round % 2 == 0)) + { + /* prepareTheta */ + BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; + BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + /* thetaRhoPiChiIotaPrepareTheta(round, A, E) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = MLD_KECCAK_ROL(Age, 44); + Aki ^= Di; + BCi = MLD_KECCAK_ROL(Aki, 43); + Amo ^= Do; + BCo = MLD_KECCAK_ROL(Amo, 21); + Asu ^= Du; + BCu = MLD_KECCAK_ROL(Asu, 14); + Eba = BCa ^ ((~BCe) & BCi); + Eba ^= (uint64_t)mld_KeccakF_RoundConstants[round]; + Ebe = BCe ^ ((~BCi) & BCo); + Ebi = BCi ^ ((~BCo) & BCu); + Ebo = BCo ^ ((~BCu) & BCa); + Ebu = BCu ^ ((~BCa) & BCe); + + Abo ^= Do; + BCa = MLD_KECCAK_ROL(Abo, 28); + Agu ^= Du; + BCe = MLD_KECCAK_ROL(Agu, 20); + Aka ^= Da; + BCi = MLD_KECCAK_ROL(Aka, 3); + Ame ^= De; + BCo = MLD_KECCAK_ROL(Ame, 45); + Asi ^= Di; + BCu = MLD_KECCAK_ROL(Asi, 61); + Ega = BCa ^ ((~BCe) & BCi); + Ege = BCe ^ ((~BCi) & BCo); + Egi = BCi ^ ((~BCo) & BCu); + Ego = BCo ^ ((~BCu) & BCa); + Egu = BCu ^ ((~BCa) & BCe); + + Abe ^= De; + BCa = MLD_KECCAK_ROL(Abe, 1); + Agi ^= Di; + BCe = MLD_KECCAK_ROL(Agi, 6); + Ako ^= Do; + BCi = MLD_KECCAK_ROL(Ako, 25); + Amu ^= Du; + BCo = MLD_KECCAK_ROL(Amu, 8); + Asa ^= Da; + BCu = MLD_KECCAK_ROL(Asa, 18); + Eka = BCa ^ ((~BCe) & BCi); + Eke = BCe ^ ((~BCi) & BCo); + Eki = BCi ^ ((~BCo) & BCu); + Eko = BCo ^ ((~BCu) & BCa); + Eku = BCu ^ ((~BCa) & BCe); + + Abu ^= Du; + BCa = MLD_KECCAK_ROL(Abu, 27); + Aga ^= Da; + BCe = MLD_KECCAK_ROL(Aga, 36); + Ake ^= De; + BCi = MLD_KECCAK_ROL(Ake, 10); + Ami ^= Di; + BCo = MLD_KECCAK_ROL(Ami, 15); + Aso ^= Do; + BCu = MLD_KECCAK_ROL(Aso, 56); + Ema = BCa ^ ((~BCe) & BCi); + Eme = BCe ^ ((~BCi) & BCo); + Emi = BCi ^ ((~BCo) & BCu); + Emo = BCo ^ ((~BCu) & BCa); + Emu = BCu ^ ((~BCa) & BCe); + + Abi ^= Di; + BCa = MLD_KECCAK_ROL(Abi, 62); + Ago ^= Do; + BCe = MLD_KECCAK_ROL(Ago, 55); + Aku ^= Du; + BCi = MLD_KECCAK_ROL(Aku, 39); + Ama ^= Da; + BCo = MLD_KECCAK_ROL(Ama, 41); + Ase ^= De; + BCu = MLD_KECCAK_ROL(Ase, 2); + Esa = BCa ^ ((~BCe) & BCi); + Ese = BCe ^ ((~BCi) & BCo); + Esi = BCi ^ ((~BCo) & BCu); + Eso = BCo ^ ((~BCu) & BCa); + Esu = BCu ^ ((~BCa) & BCe); + + /* prepareTheta */ + BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + /* thetaRhoPiChiIotaPrepareTheta(round+1, E, A) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = MLD_KECCAK_ROL(Ege, 44); + Eki ^= Di; + BCi = MLD_KECCAK_ROL(Eki, 43); + Emo ^= Do; + BCo = MLD_KECCAK_ROL(Emo, 21); + Esu ^= Du; + BCu = MLD_KECCAK_ROL(Esu, 14); + Aba = BCa ^ ((~BCe) & BCi); + Aba ^= (uint64_t)mld_KeccakF_RoundConstants[round + 1]; + Abe = BCe ^ ((~BCi) & BCo); + Abi = BCi ^ ((~BCo) & BCu); + Abo = BCo ^ ((~BCu) & BCa); + Abu = BCu ^ ((~BCa) & BCe); + + Ebo ^= Do; + BCa = MLD_KECCAK_ROL(Ebo, 28); + Egu ^= Du; + BCe = MLD_KECCAK_ROL(Egu, 20); + Eka ^= Da; + BCi = MLD_KECCAK_ROL(Eka, 3); + Eme ^= De; + BCo = MLD_KECCAK_ROL(Eme, 45); + Esi ^= Di; + BCu = MLD_KECCAK_ROL(Esi, 61); + Aga = BCa ^ ((~BCe) & BCi); + Age = BCe ^ ((~BCi) & BCo); + Agi = BCi ^ ((~BCo) & BCu); + Ago = BCo ^ ((~BCu) & BCa); + Agu = BCu ^ ((~BCa) & BCe); + + Ebe ^= De; + BCa = MLD_KECCAK_ROL(Ebe, 1); + Egi ^= Di; + BCe = MLD_KECCAK_ROL(Egi, 6); + Eko ^= Do; + BCi = MLD_KECCAK_ROL(Eko, 25); + Emu ^= Du; + BCo = MLD_KECCAK_ROL(Emu, 8); + Esa ^= Da; + BCu = MLD_KECCAK_ROL(Esa, 18); + Aka = BCa ^ ((~BCe) & BCi); + Ake = BCe ^ ((~BCi) & BCo); + Aki = BCi ^ ((~BCo) & BCu); + Ako = BCo ^ ((~BCu) & BCa); + Aku = BCu ^ ((~BCa) & BCe); + + Ebu ^= Du; + BCa = MLD_KECCAK_ROL(Ebu, 27); + Ega ^= Da; + BCe = MLD_KECCAK_ROL(Ega, 36); + Eke ^= De; + BCi = MLD_KECCAK_ROL(Eke, 10); + Emi ^= Di; + BCo = MLD_KECCAK_ROL(Emi, 15); + Eso ^= Do; + BCu = MLD_KECCAK_ROL(Eso, 56); + Ama = BCa ^ ((~BCe) & BCi); + Ame = BCe ^ ((~BCi) & BCo); + Ami = BCi ^ ((~BCo) & BCu); + Amo = BCo ^ ((~BCu) & BCa); + Amu = BCu ^ ((~BCa) & BCe); + + Ebi ^= Di; + BCa = MLD_KECCAK_ROL(Ebi, 62); + Ego ^= Do; + BCe = MLD_KECCAK_ROL(Ego, 55); + Eku ^= Du; + BCi = MLD_KECCAK_ROL(Eku, 39); + Ema ^= Da; + BCo = MLD_KECCAK_ROL(Ema, 41); + Ese ^= De; + BCu = MLD_KECCAK_ROL(Ese, 2); + Asa = BCa ^ ((~BCe) & BCi); + Ase = BCe ^ ((~BCi) & BCo); + Asi = BCi ^ ((~BCo) & BCu); + Aso = BCo ^ ((~BCu) & BCa); + Asu = BCu ^ ((~BCa) & BCe); + } + + /* copyToState(state, A) */ + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} + +void mld_keccakf1600_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X1_NATIVE) + if (mld_keccak_f1600_x1_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X1_NATIVE */ + mld_keccakf1600_permute_c(state); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(keccakf1600) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_KECCAK_NROUNDS +#undef MLD_KECCAK_ROL diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/keccakf1600.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/keccakf1600.h new file mode 100644 index 0000000000..e56adc1561 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/keccakf1600.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_KECCAKF1600_H +#define MLD_FIPS202_KECCAKF1600_H +#include +#include "../cbmc.h" +#include "../common.h" +#include "fips202.h" + +#define MLD_KECCAK_LANES 25 +#define MLD_KECCAK_WAY 4 + +/* + * WARNING: + * The contents of this structure, including the placement + * and interleaving of Keccak lanes, are IMPLEMENTATION-DEFINED. + * The struct is only exposed here to allow its construction on the stack. + */ + +#define mld_keccakf1600_extract_bytes MLD_NAMESPACE(keccakf1600_extract_bytes) +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(data, length)) +); + +#define mld_keccakf1600_xor_bytes MLD_NAMESPACE(keccakf1600_xor_bytes) +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#define mld_keccakf1600x4_extract_bytes \ + MLD_NAMESPACE(keccakf1600x4_extract_bytes) +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + requires(memory_no_alias(data1, length)) + requires(memory_no_alias(data2, length)) + requires(memory_no_alias(data3, length)) + assigns(memory_slice(data0, length)) + assigns(memory_slice(data1, length)) + assigns(memory_slice(data2, length)) + assigns(memory_slice(data3, length)) +); + +#define mld_keccakf1600x4_xor_bytes MLD_NAMESPACE(keccakf1600x4_xor_bytes) +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + /* Case 1: all input buffers are distinct; Case 2: All input buffers are the same */ + requires((data0 == data1 && + data0 == data2 && + data0 == data3) || + (memory_no_alias(data1, length) && + memory_no_alias(data2, length) && + memory_no_alias(data3, length))) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600x4_permute MLD_NAMESPACE(keccakf1600x4_permute) +void mld_keccakf1600x4_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600_permute MLD_NAMESPACE(keccakf1600_permute) +void mld_keccakf1600_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#endif /* !MLD_FIPS202_KECCAKF1600_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/auto.h new file mode 100644 index 0000000000..4375cc1976 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/auto.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [HYBRID] + * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64 + * Becker, Kannwischer + * https://eprint.iacr.org/2022/1243 + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +#define MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* Default FIPS202 assembly profile for AArch64 systems */ + +/* + * Default logic to decide which implementation to use. + * + */ + +/* + * Keccak-f1600 + * + * - On Arm-based Apple CPUs, we pick a pure Neon implementation. + * - Otherwise, unless MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, + * we use lazy-rotation scalar assembly from @[HYBRID]. + * - Otherwise, if MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, we + * fall back to the standard C implementation. + */ +#if defined(__ARM_FEATURE_SHA3) && defined(__APPLE__) +#include "x1_v84a.h" +#elif !defined(MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER) +#include "x1_scalar.h" +#endif + +/* + * Keccak-f1600x2/x4 + * + * The optimal implementation is highly CPU-specific; see @[HYBRID]. + * + * For now, if v8.4-A is not implemented, we fall back to Keccak-f1600. + * If v8.4-A is implemented and we are on an Apple CPU, we use a plain + * Neon-based implementation. + * If v8.4-A is implemented and we are not on an Apple CPU, we use a + * scalar/Neon/Neon hybrid. + * The reason for this distinction is that Apple CPUs appear to implement + * the SHA3 instructions on all SIMD units, while Arm CPUs prior to Cortex-X4 + * don't, and ordinary Neon instructions are still needed. + */ +#if defined(__ARM_FEATURE_SHA3) +/* + * For Apple-M cores, we use a plain implementation leveraging SHA3 + * instructions only. + */ +#if defined(__APPLE__) +#include "x2_v84a.h" +#else +#include "x4_v8a_v84a_scalar.h" +#endif + +#else /* __ARM_FEATURE_SHA3 */ + +#include "x4_v8a_scalar.h" + +#endif /* !__ARM_FEATURE_SHA3 */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h new file mode 100644 index 0000000000..20f6168038 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#define MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H + +#include +#include "../../../../cbmc.h" +#include "../../../../common.h" + + +#define mld_keccakf1600_round_constants \ + MLD_NAMESPACE(keccakf1600_round_constants) +extern const uint64_t mld_keccakf1600_round_constants[]; + +#define mld_keccak_f1600_x1_scalar_asm MLD_NAMESPACE(keccak_f1600_x1_scalar_asm) +void mld_keccak_f1600_x1_scalar_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x1_v84a_asm MLD_NAMESPACE(keccak_f1600_x1_v84a_asm) +void mld_keccak_f1600_x1_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x2_v84a_asm MLD_NAMESPACE(keccak_f1600_x2_v84a_asm) +void mld_keccak_f1600_x2_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 2)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 2)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c new file mode 100644 index 0000000000..05e9cbfeec --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../../common.h" + +#if (defined(MLD_FIPS202_AARCH64_NEED_X1_SCALAR) || \ + defined(MLD_FIPS202_AARCH64_NEED_X1_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X2_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID)) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "fips202_native_aarch64.h" + +MLD_ALIGN const uint64_t mld_keccakf1600_round_constants[] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, +}; + +#else /* (MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_aarch64_round_constants) + +#endif /* !((MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/x1_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/x1_scalar.h new file mode 100644 index 0000000000..681b991371 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/x1_scalar.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_SCALAR + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + mld_keccak_f1600_x1_scalar_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/x1_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/x1_v84a.h new file mode 100644 index 0000000000..d15c8c26f3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/x1_v84a.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x1_v84a_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/x2_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/x2_v84a.h new file mode 100644 index 0000000000..16c22fa1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/x2_v84a.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X2_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" + + +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x2_v84a_asm(state + 0 * 25, mld_keccakf1600_round_constants); + mld_keccak_f1600_x2_v84a_asm(state + 2 * 25, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h new file mode 100644 index 0000000000..0f7f8fe499 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(state, + mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h new file mode 100644 index 0000000000..3da883b762 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm( + state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/api.h new file mode 100644 index 0000000000..4625c9a1ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/api.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_API_H +#define MLD_FIPS202_NATIVE_API_H +/* + * FIPS-202 native interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + */ + +#include +#include "../../cbmc.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* + * This is the C<->native interface allowing for the drop-in + * of custom Keccak-F1600 implementations. + * + * A _backend_ is a specific implementation of parts of this interface. + * + * You can replace 1-fold or 4-fold batched Keccak-F1600. + * To enable, set MLD_USE_FIPS202_X1_NATIVE or MLD_USE_FIPS202_X4_NATIVE + * in your backend, and define the inline wrappers mld_keccak_f1600_x1_native() + * and/or mld_keccak_f1600_x4_native(), respectively, to forward to your + * implementation. + */ + +#if defined(MLD_USE_FIPS202_X1_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 1)) +); +#endif /* MLD_USE_FIPS202_X1_NATIVE */ +#if defined(MLD_USE_FIPS202_X4_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 4)) +); +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + +#endif /* !MLD_FIPS202_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/auto.h new file mode 100644 index 0000000000..0a09c733c8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/auto.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AUTO_H +#define MLD_FIPS202_NATIVE_AUTO_H + +/* + * Default FIPS202 backend + */ +#include "../../sys.h" + +#if defined(MLD_SYS_AARCH64) +#include "aarch64/auto.h" +#endif + +#if defined(MLD_SYS_X86_64) && defined(MLD_SYS_X86_64_AVX2) +#include "x86_64/xkcp.h" +#endif + +#endif /* !MLD_FIPS202_NATIVE_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c new file mode 100644 index 0000000000..4eaad2fd66 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* +Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, +Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby +denoted as "the implementer". + +For more information, feedback or questions, please refer to our websites: +http://keccak.noekeon.org/ +http://keyak.noekeon.org/ +http://ketje.noekeon.org/ + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +/* + * Changes for mlkem-native/mldsa-native: + * - copyFromState and copyToState operate on uninterleaved + * Keccak states in memory. + */ + +#include "../../../../common.h" +#if defined(MLD_FIPS202_X86_64_XKCP) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include + +#include "KeccakP_1600_times4_SIMD256.h" + +#ifndef MLD_SYS_LITTLE_ENDIAN +#error Expecting a little-endian platform +#endif + +#define ANDnu256(a, b) _mm256_andnot_si256(a, b) +#define CONST256(a) _mm256_load_si256((const __m256i *)&(a)) +#define CONST256_64(a) (__m256i) _mm256_broadcast_sd((const double *)(&a)) +#define ROL64in256(d, a, o) \ + d = _mm256_or_si256(_mm256_slli_epi64(a, o), _mm256_srli_epi64(a, 64 - (o))) +#define ROL64in256_8(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho8)) +#define ROL64in256_56(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho56)) +static const uint64_t rho8[4] = {0x0605040302010007, 0x0E0D0C0B0A09080F, + 0x1615141312111017, 0x1E1D1C1B1A19181F}; +static const uint64_t rho56[4] = {0x0007060504030201, 0x080F0E0D0C0B0A09, + 0x1017161514131211, 0x181F1E1D1C1B1A19}; +#define STORE256(a, b) _mm256_store_si256((__m256i *)&(a), b) +#define XOR256(a, b) _mm256_xor_si256(a, b) +#define XOReq256(a, b) a = _mm256_xor_si256(a, b) + +#define SnP_laneLengthInBytes 8 + +#define declareABCDE \ + __m256i Aba, Abe, Abi, Abo, Abu; \ + __m256i Aga, Age, Agi, Ago, Agu; \ + __m256i Aka, Ake, Aki, Ako, Aku; \ + __m256i Ama, Ame, Ami, Amo, Amu; \ + __m256i Asa, Ase, Asi, Aso, Asu; \ + __m256i Bba, Bbe, Bbi, Bbo, Bbu; \ + __m256i Bga, Bge, Bgi, Bgo, Bgu; \ + __m256i Bka, Bke, Bki, Bko, Bku; \ + __m256i Bma, Bme, Bmi, Bmo, Bmu; \ + __m256i Bsa, Bse, Bsi, Bso, Bsu; \ + __m256i Ca, Ce, Ci, Co, Cu; \ + __m256i Ca1, Ce1, Ci1, Co1, Cu1; \ + __m256i Da, De, Di, Do, Du; \ + __m256i Eba, Ebe, Ebi, Ebo, Ebu; \ + __m256i Ega, Ege, Egi, Ego, Egu; \ + __m256i Eka, Eke, Eki, Eko, Eku; \ + __m256i Ema, Eme, Emi, Emo, Emu; \ + __m256i Esa, Ese, Esi, Eso, Esu; + +#define prepareTheta \ + Ca = XOR256(Aba, XOR256(Aga, XOR256(Aka, XOR256(Ama, Asa)))); \ + Ce = XOR256(Abe, XOR256(Age, XOR256(Ake, XOR256(Ame, Ase)))); \ + Ci = XOR256(Abi, XOR256(Agi, XOR256(Aki, XOR256(Ami, Asi)))); \ + Co = XOR256(Abo, XOR256(Ago, XOR256(Ako, XOR256(Amo, Aso)))); \ + Cu = XOR256(Abu, XOR256(Agu, XOR256(Aku, XOR256(Amu, Asu)))); + +/* + * --- Theta Rho Pi Chi Iota Prepare-theta + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + Ca = E##ba; \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + Ce = E##be; \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + Ci = E##bi; \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + Co = E##bo; \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + Cu = E##bu; \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(Ca, E##ga); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(Ce, E##ge); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + XOReq256(Ci, E##gi); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + XOReq256(Co, E##go); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + XOReq256(Cu, E##gu); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(Ca, E##ka); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(Ce, E##ke); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + XOReq256(Ci, E##ki); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + XOReq256(Co, E##ko); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + XOReq256(Cu, E##ku); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(Ca, E##ma); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(Ce, E##me); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + XOReq256(Ci, E##mi); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + XOReq256(Co, E##mo); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + XOReq256(Cu, E##mu); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(Ca, E##sa); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(Ce, E##se); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + XOReq256(Ci, E##si); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + XOReq256(Co, E##so); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); \ + XOReq256(Cu, E##su); + + +/* + * --- Theta Rho Pi Chi Iota + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIota(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); + + +static MLD_ALIGN const uint64_t keccakf1600RoundConstants[24] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +#include + +#define copyFromState(X, state) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m256i _idx = \ + _mm256_set_epi64x((long long)&state64[75], (long long)&state64[50], \ + (long long)&state64[25], (long long)&state64[0]); \ + X##ba = _mm256_i64gather_epi64((long long *)(0 * 8), _idx, 1); \ + X##be = _mm256_i64gather_epi64((long long *)(1 * 8), _idx, 1); \ + X##bi = _mm256_i64gather_epi64((long long *)(2 * 8), _idx, 1); \ + X##bo = _mm256_i64gather_epi64((long long *)(3 * 8), _idx, 1); \ + X##bu = _mm256_i64gather_epi64((long long *)(4 * 8), _idx, 1); \ + X##ga = _mm256_i64gather_epi64((long long *)(5 * 8), _idx, 1); \ + X##ge = _mm256_i64gather_epi64((long long *)(6 * 8), _idx, 1); \ + X##gi = _mm256_i64gather_epi64((long long *)(7 * 8), _idx, 1); \ + X##go = _mm256_i64gather_epi64((long long *)(8 * 8), _idx, 1); \ + X##gu = _mm256_i64gather_epi64((long long *)(9 * 8), _idx, 1); \ + X##ka = _mm256_i64gather_epi64((long long *)(10 * 8), _idx, 1); \ + X##ke = _mm256_i64gather_epi64((long long *)(11 * 8), _idx, 1); \ + X##ki = _mm256_i64gather_epi64((long long *)(12 * 8), _idx, 1); \ + X##ko = _mm256_i64gather_epi64((long long *)(13 * 8), _idx, 1); \ + X##ku = _mm256_i64gather_epi64((long long *)(14 * 8), _idx, 1); \ + X##ma = _mm256_i64gather_epi64((long long *)(15 * 8), _idx, 1); \ + X##me = _mm256_i64gather_epi64((long long *)(16 * 8), _idx, 1); \ + X##mi = _mm256_i64gather_epi64((long long *)(17 * 8), _idx, 1); \ + X##mo = _mm256_i64gather_epi64((long long *)(18 * 8), _idx, 1); \ + X##mu = _mm256_i64gather_epi64((long long *)(19 * 8), _idx, 1); \ + X##sa = _mm256_i64gather_epi64((long long *)(20 * 8), _idx, 1); \ + X##se = _mm256_i64gather_epi64((long long *)(21 * 8), _idx, 1); \ + X##si = _mm256_i64gather_epi64((long long *)(22 * 8), _idx, 1); \ + X##so = _mm256_i64gather_epi64((long long *)(23 * 8), _idx, 1); \ + X##su = _mm256_i64gather_epi64((long long *)(24 * 8), _idx, 1); \ + } while (0); + +#define SCATTER_STORE256(state, idx, v) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m128d t = _mm_castsi128_pd(_mm256_castsi256_si128((v))); \ + _mm_storel_pd((double *)&state64[0 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[25 + (idx)], t); \ + t = _mm_castsi128_pd(_mm256_extracti128_si256((v), 1)); \ + _mm_storel_pd((double *)&state64[50 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[75 + (idx)], t); \ + } while (0) + +#define copyToState(state, X) \ + SCATTER_STORE256(state, 0, X##ba); \ + SCATTER_STORE256(state, 1, X##be); \ + SCATTER_STORE256(state, 2, X##bi); \ + SCATTER_STORE256(state, 3, X##bo); \ + SCATTER_STORE256(state, 4, X##bu); \ + SCATTER_STORE256(state, 5, X##ga); \ + SCATTER_STORE256(state, 6, X##ge); \ + SCATTER_STORE256(state, 7, X##gi); \ + SCATTER_STORE256(state, 8, X##go); \ + SCATTER_STORE256(state, 9, X##gu); \ + SCATTER_STORE256(state, 10, X##ka); \ + SCATTER_STORE256(state, 11, X##ke); \ + SCATTER_STORE256(state, 12, X##ki); \ + SCATTER_STORE256(state, 13, X##ko); \ + SCATTER_STORE256(state, 14, X##ku); \ + SCATTER_STORE256(state, 15, X##ma); \ + SCATTER_STORE256(state, 16, X##me); \ + SCATTER_STORE256(state, 17, X##mi); \ + SCATTER_STORE256(state, 18, X##mo); \ + SCATTER_STORE256(state, 19, X##mu); \ + SCATTER_STORE256(state, 20, X##sa); \ + SCATTER_STORE256(state, 21, X##se); \ + SCATTER_STORE256(state, 22, X##si); \ + SCATTER_STORE256(state, 23, X##so); \ + SCATTER_STORE256(state, 24, X##su); + +#define copyStateVariables(X, Y) \ + X##ba = Y##ba; \ + X##be = Y##be; \ + X##bi = Y##bi; \ + X##bo = Y##bo; \ + X##bu = Y##bu; \ + X##ga = Y##ga; \ + X##ge = Y##ge; \ + X##gi = Y##gi; \ + X##go = Y##go; \ + X##gu = Y##gu; \ + X##ka = Y##ka; \ + X##ke = Y##ke; \ + X##ki = Y##ki; \ + X##ko = Y##ko; \ + X##ku = Y##ku; \ + X##ma = Y##ma; \ + X##me = Y##me; \ + X##mi = Y##mi; \ + X##mo = Y##mo; \ + X##mu = Y##mu; \ + X##sa = Y##sa; \ + X##se = Y##se; \ + X##si = Y##si; \ + X##so = Y##so; \ + X##su = Y##su; + +/* clang-format off */ +#define rounds24 \ + prepareTheta \ + thetaRhoPiChiIotaPrepareTheta( 0, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 1, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 2, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 3, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 4, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 5, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 6, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 7, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 8, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 9, E, A) \ + thetaRhoPiChiIotaPrepareTheta(10, A, E) \ + thetaRhoPiChiIotaPrepareTheta(11, E, A) \ + thetaRhoPiChiIotaPrepareTheta(12, A, E) \ + thetaRhoPiChiIotaPrepareTheta(13, E, A) \ + thetaRhoPiChiIotaPrepareTheta(14, A, E) \ + thetaRhoPiChiIotaPrepareTheta(15, E, A) \ + thetaRhoPiChiIotaPrepareTheta(16, A, E) \ + thetaRhoPiChiIotaPrepareTheta(17, E, A) \ + thetaRhoPiChiIotaPrepareTheta(18, A, E) \ + thetaRhoPiChiIotaPrepareTheta(19, E, A) \ + thetaRhoPiChiIotaPrepareTheta(20, A, E) \ + thetaRhoPiChiIotaPrepareTheta(21, E, A) \ + thetaRhoPiChiIotaPrepareTheta(22, A, E) \ + thetaRhoPiChiIota(23, E, A) +/* clang-format on */ + +void mld_keccakf1600x4_permute24(void *states) +{ + __m256i *statesAsLanes = (__m256i *)states; + declareABCDE copyFromState(A, statesAsLanes) + rounds24 copyToState(statesAsLanes, A) +} + +#else /* MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_avx2_keccakx4) + +#endif /* !(MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef ANDnu256 +#undef CONST256 +#undef CONST256_64 +#undef ROL64in256 +#undef ROL64in256_8 +#undef ROL64in256_56 +#undef STORE256 +#undef XOR256 +#undef XOReq256 +#undef SnP_laneLengthInBytes +#undef declareABCDE +#undef prepareTheta +#undef thetaRhoPiChiIotaPrepareTheta +#undef thetaRhoPiChiIota +#undef copyFromState +#undef SCATTER_STORE256 +#undef copyToState +#undef copyStateVariables +#undef rounds24 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h new file mode 100644 index 0000000000..3499d38e2c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H +#define MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H + +#include "../../../../common.h" + +#define mld_keccakf1600x4_permute24 \ + MLD_NAMESPACE(KeccakP1600times4_PermuteAll_24rounds) +void mld_keccakf1600x4_permute24(void *states); + +#endif /* !MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/x86_64/xkcp.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/x86_64/xkcp.h new file mode 100644 index 0000000000..c03642d7e0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/fips202/native/x86_64/xkcp.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_XKCP_H +#define MLD_FIPS202_NATIVE_X86_64_XKCP_H + +#include "../../../common.h" + +#define MLD_FIPS202_X86_64_XKCP + +#if !defined(__ASSEMBLER__) +#include +#include "../api.h" +#include "src/KeccakP_1600_times4_SIMD256.h" + +#define MLD_USE_FIPS202_X4_NATIVE +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_keccakf1600x4_permute24(state); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_X86_64_XKCP_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/meta.h new file mode 100644 index 0000000000..c6f6ad47b0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/meta.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_META_H +#define MLD_NATIVE_AARCH64_META_H + +/* Set of primitives that this backend replaces */ +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_AARCH64 + + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/arith_native_aarch64.h" + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + mld_ntt_asm(data, mld_aarch64_ntt_zetas_layer123456, + mld_aarch64_ntt_zetas_layer78); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + mld_intt_asm(data, mld_aarch64_intt_zetas_layer78, + mld_aarch64_intt_zetas_layer123456); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + if (len != MLDSA_N || + buflen % 24 != 0) /* NEON support is mandatory for AArch64 */ + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N, hence, this cast is safe. */ + return (int)mld_rej_uniform_asm(r, buf, buflen, mld_rej_uniform_table); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_32_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_88_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + mld_poly_caddq_asm(a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_32_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_88_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + return mld_poly_chknorm_asm(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_17_asm(r, buf, mld_polyz_unpack_17_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_19_asm(r, buf, mld_polyz_unpack_19_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t out[MLDSA_N], const int32_t in0[MLDSA_N], + const int32_t in1[MLDSA_N]) +{ + mld_poly_pointwise_montgomery_asm(out, in0, in1); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l4_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l5_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l7_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ +#endif /* !MLD_NATIVE_AARCH64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/src/aarch64_zetas.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/src/aarch64_zetas.c new file mode 100644 index 0000000000..9ab7b9a68c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/src/aarch64_zetas.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Table of zeta values used in the AArch64 forward NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer123456[] = { + -3572223, -915382907, 3765607, 964937599, 3761513, 963888510, + -3201494, -820383522, -2883726, -738955404, -3145678, -806080660, + -3201430, -820367122, 0, 0, -601683, -154181397, + -3370349, -863652652, -4063053, -1041158200, 3602218, 923069133, + 3182878, 815613168, 2740543, 702264730, -3586446, -919027554, + 0, 0, 3542485, 907762539, 2663378, 682491182, + -1674615, -429120452, -3110818, -797147778, 2101410, 538486762, + 3704823, 949361686, 1159875, 297218217, 0, 0, + 2682288, 687336873, -3524442, -903139016, -434125, -111244624, + 394148, 101000509, 928749, 237992130, 1095468, 280713909, + -3506380, -898510625, 0, 0, 2129892, 545785280, + 676590, 173376332, -1335936, -342333886, 2071829, 530906624, + -4018989, -1029866791, 3241972, 830756018, 2156050, 552488273, + 0, 0, 3764867, 964747974, -3227876, -827143915, + 1714295, 439288460, 3415069, 875112161, 1759347, 450833045, + -817536, -209493775, -3574466, -915957677, 0, 0, + -1005239, -257592709, 2453983, 628833668, 1460718, 374309300, + 3756790, 962678241, -1935799, -496048908, -1716988, -439978542, + -3950053, -1012201926, 0, 0, 557458, 142848732, + -642628, -164673562, -3585098, -918682129, -2897314, -742437332, + 3192354, 818041395, 556856, 142694469, 3870317, 991769559, + 0, 0, -1221177, -312926867, 2815639, 721508096, + 2283733, 585207070, 2917338, 747568486, 1853806, 475038184, + 3345963, 857403734, 1858416, 476219497, 0, 0, +}; + +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer78[] = { + 3073009, 1277625, -2635473, 3852015, 787459213, + 327391679, -675340520, 987079667, 1753, -2659525, + 2660408, -59148, 449207, -681503850, 681730119, + -15156688, -1935420, -1455890, -1780227, 2772600, + -495951789, -373072124, -456183549, 710479343, 4183372, + -3222807, -3121440, -274060, 1071989969, -825844983, + -799869667, -70227934, 1182243, 636927, -3956745, + -3284915, 302950022, 163212680, -1013916752, -841760171, + 87208, -3965306, -2296397, -3716946, 22347069, + -1016110510, -588452222, -952468207, 2508980, 2028118, + 1937570, -3815725, 642926661, 519705671, 496502727, + -977780347, -27812, 1009365, -1979497, -3956944, + -7126831, 258649997, -507246529, -1013967746, 822541, + -2454145, 1596822, -3759465, 210776307, -628875181, + 409185979, -963363710, 2811291, -2983781, -1109516, + 4158088, 720393920, -764594519, -284313712, 1065510939, + -1685153, 2678278, -3551006, -250446, -431820817, + 686309310, -909946047, -64176841, -3410568, -3768948, + 635956, -2455377, -873958779, -965793731, 162963861, + -629190881, 1528066, 482649, 1148858, -2962264, + 391567239, 123678909, 294395108, -759080783, -4146264, + 2192938, 2387513, -268456, -1062481036, 561940831, + 611800717, -68791907, -1772588, -1727088, -3611750, + -3180456, -454226054, -442566669, -925511710, -814992530, + -565603, 169688, 2462444, -3334383, -144935890, + 43482586, 631001801, -854436357, 3747250, 1239911, + 3195676, 1254190, 960233614, 317727459, 818892658, + 321386456, 2296099, -3838479, 2642980, -12417, + 588375860, -983611064, 677264190, -3181859, -4166425, + -3488383, 1987814, -3197248, -1067647297, -893898890, + 509377762, -819295484, 2998219, -89301, -1354892, + -1310261, 768294260, -22883400, -347191365, -335754661, + 141835, 2513018, 613238, -2218467, 36345249, + 643961400, 157142369, -568482643, 1736313, 235407, + -3250154, 3258457, 444930577, 60323094, -832852657, + 834980303, -458740, 4040196, 2039144, -818761, + -117552223, 1035301089, 522531086, -209807681, -1921994, + -3472069, -1879878, -2178965, -492511373, -889718424, + -481719139, -558360247, -2579253, 1787943, -2391089, + -2254727, -660934133, 458160776, -612717067, -577774276, + -1623354, -2374402, 586241, 527981, -415984810, + -608441020, 150224382, 135295244, 2105286, -2033807, + -1179613, -2743411, 539479988, -521163479, -302276083, + -702999655, 3482206, -4182915, -1300016, -2362063, + 892316032, -1071872863, -333129378, -605279149, -1476985, + 2491325, 507927, -724804, -378477722, 638402564, + 130156402, -185731180, 1994046, -1393159, -1187885, + -1834526, 510974714, -356997292, -304395785, -470097680, + -1317678, 2461387, 3035980, 621164, -337655269, + 630730945, 777970524, 159173408, -3033742, 2647994, + -2612853, 749577, -777397036, 678549029, -669544140, + 192079267, -338420, 3009748, 4148469, -4022750, + -86720197, 771248568, 1063046068, -1030830548, 3901472, + -1226661, 2925816, 3374250, 999753034, -314332144, + 749740976, 864652284, 3980599, -1615530, 1665318, + 1163598, 1020029345, -413979908, 426738094, 298172236, + 2569011, 1723229, 2028038, -3369273, 658309618, + 441577800, 519685171, -863376927, 1356448, -2775755, + 2683270, -2778788, 347590090, -711287812, 687588511, + -712065019, 3994671, -1370517, 3363542, 545376, + 1023635298, -351195274, 861908357, 139752717, -11879, + 3020393, 214880, -770441, -3043996, 773976352, + 55063046, -197425671, -3467665, 2312838, -653275, + -459163, -888589898, 592665232, -167401858, -117660617, + 3105558, 508145, 860144, 140244, 795799901, + 130212265, 220412084, 35937555, -1103344, -553718, + 3430436, -1514152, -282732136, -141890356, 879049958, + -388001774, 348812, -327848, 1011223, -2354215, + 89383150, -84011120, 259126110, -603268097, -2185084, + 2358373, -3014420, 2926054, -559928242, 604333585, + -772445769, 749801963, 3123762, -2193087, -1716814, + -392707, 800464680, -561979013, -439933955, -100631253, + -3818627, -1922253, -2236726, 1744507, -978523985, + -492577742, -573161516, 447030292, -303005, -3974485, + 1900052, 1054478, -77645096, -1018462631, 486888731, + 270210213, 3531229, -3773731, -781875, -731434, + 904878186, -967019376, -200355636, -187430119, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer78[] = { + -1744507, 2236726, 1922253, 3818627, -447030292, 573161516, + 492577742, 978523985, 731434, 781875, 3773731, -3531229, + 187430119, 200355636, 967019376, -904878186, -1054478, -1900052, + 3974485, 303005, -270210213, -486888731, 1018462631, 77645096, + 2354215, -1011223, 327848, -348812, 603268097, -259126110, + 84011120, -89383150, 392707, 1716814, 2193087, -3123762, + 100631253, 439933955, 561979013, -800464680, -2926054, 3014420, + -2358373, 2185084, -749801963, 772445769, -604333585, 559928242, + 459163, 653275, -2312838, 3467665, 117660617, 167401858, + -592665232, 888589898, 1514152, -3430436, 553718, 1103344, + 388001774, -879049958, 141890356, 282732136, -140244, -860144, + -508145, -3105558, -35937555, -220412084, -130212265, -795799901, + 2778788, -2683270, 2775755, -1356448, 712065019, -687588511, + 711287812, -347590090, 770441, -214880, -3020393, 11879, + 197425671, -55063046, -773976352, 3043996, -545376, -3363542, + 1370517, -3994671, -139752717, -861908357, 351195274, -1023635298, + -3374250, -2925816, 1226661, -3901472, -864652284, -749740976, + 314332144, -999753034, 3369273, -2028038, -1723229, -2569011, + 863376927, -519685171, -441577800, -658309618, -1163598, -1665318, + 1615530, -3980599, -298172236, -426738094, 413979908, -1020029345, + -621164, -3035980, -2461387, 1317678, -159173408, -777970524, + -630730945, 337655269, 4022750, -4148469, -3009748, 338420, + 1030830548, -1063046068, -771248568, 86720197, -749577, 2612853, + -2647994, 3033742, -192079267, 669544140, -678549029, 777397036, + 2362063, 1300016, 4182915, -3482206, 605279149, 333129378, + 1071872863, -892316032, 1834526, 1187885, 1393159, -1994046, + 470097680, 304395785, 356997292, -510974714, 724804, -507927, + -2491325, 1476985, 185731180, -130156402, -638402564, 378477722, + 2254727, 2391089, -1787943, 2579253, 577774276, 612717067, + -458160776, 660934133, 2743411, 1179613, 2033807, -2105286, + 702999655, 302276083, 521163479, -539479988, -527981, -586241, + 2374402, 1623354, -135295244, -150224382, 608441020, 415984810, + -3258457, 3250154, -235407, -1736313, -834980303, 832852657, + -60323094, -444930577, 2178965, 1879878, 3472069, 1921994, + 558360247, 481719139, 889718424, 492511373, 818761, -2039144, + -4040196, 458740, 209807681, -522531086, -1035301089, 117552223, + 3197248, -1987814, 3488383, 4166425, 819295484, -509377762, + 893898890, 1067647297, 2218467, -613238, -2513018, -141835, + 568482643, -157142369, -643961400, -36345249, 1310261, 1354892, + 89301, -2998219, 335754661, 347191365, 22883400, -768294260, + 3334383, -2462444, -169688, 565603, 854436357, -631001801, + -43482586, 144935890, 12417, -2642980, 3838479, -2296099, + 3181859, -677264190, 983611064, -588375860, -1254190, -3195676, + -1239911, -3747250, -321386456, -818892658, -317727459, -960233614, + 2962264, -1148858, -482649, -1528066, 759080783, -294395108, + -123678909, -391567239, 3180456, 3611750, 1727088, 1772588, + 814992530, 925511710, 442566669, 454226054, 268456, -2387513, + -2192938, 4146264, 68791907, -611800717, -561940831, 1062481036, + -4158088, 1109516, 2983781, -2811291, -1065510939, 284313712, + 764594519, -720393920, 2455377, -635956, 3768948, 3410568, + 629190881, -162963861, 965793731, 873958779, 250446, 3551006, + -2678278, 1685153, 64176841, 909946047, -686309310, 431820817, + 3815725, -1937570, -2028118, -2508980, 977780347, -496502727, + -519705671, -642926661, 3759465, -1596822, 2454145, -822541, + 963363710, -409185979, 628875181, -210776307, 3956944, 1979497, + -1009365, 27812, 1013967746, 507246529, -258649997, 7126831, + 274060, 3121440, 3222807, -4183372, 70227934, 799869667, + 825844983, -1071989969, 3716946, 2296397, 3965306, -87208, + 952468207, 588452222, 1016110510, -22347069, 3284915, 3956745, + -636927, -1182243, 841760171, 1013916752, -163212680, -302950022, + -3852015, 2635473, -1277625, -3073009, -987079667, 675340520, + -327391679, -787459213, -2772600, 1780227, 1455890, 1935420, + -710479343, 456183549, 373072124, 495951789, 59148, -2660408, + 2659525, -1753, 15156688, -681730119, 681503850, -449207, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer123456[] = { + -2283733, -585207070, 0, 0, -1858416, -476219497, + -3345963, -857403734, -2815639, -721508096, 0, 0, + -1853806, -475038184, -2917338, -747568486, 3585098, 918682129, + 0, 0, -3870317, -991769559, -556856, -142694469, + 642628, 164673562, 0, 0, -3192354, -818041395, + 2897314, 742437332, -1460718, -374309300, 0, 0, + 3950053, 1012201926, 1716988, 439978542, -2453983, -628833668, + 0, 0, 1935799, 496048908, -3756790, -962678241, + -1714295, -439288460, 0, 0, 3574466, 915957677, + 817536, 209493775, 3227876, 827143915, 0, 0, + -1759347, -450833045, -3415069, -875112161, 1335936, 342333886, + 0, 0, -2156050, -552488273, -3241972, -830756018, + -676590, -173376332, 0, 0, 4018989, 1029866791, + -2071829, -530906624, 434125, 111244624, 0, 0, + 3506380, 898510625, -1095468, -280713909, 3524442, 903139016, + 0, 0, -928749, -237992130, -394148, -101000509, + 1674615, 429120452, 0, 0, -1159875, -297218217, + -3704823, -949361686, -2663378, -682491182, 0, 0, + -2101410, -538486762, 3110818, 797147778, 4063053, 1041158200, + 0, 0, 3586446, 919027554, -2740543, -702264730, + 3370349, 863652652, 0, 0, -3182878, -815613168, + -3602218, -923069133, -294725, -75523344, -3761513, -963888510, + -3765607, -964937599, 3201430, 820367122, 3145678, 806080660, + 2883726, 738955404, 3201494, 820383522, 1221177, 312926867, + -557458, -142848732, 1005239, 257592709, -3764867, -964747974, + -2129892, -545785280, -2682288, -687336873, -3542485, -907762539, + 601683, 154181397, 0, 0, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_zetas) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h new file mode 100644 index 0000000000..e77f55014c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#define MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H + +#include +#include "../../../common.h" + +#define mld_aarch64_ntt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_ntt_zetas_layer123456) +#define mld_aarch64_ntt_zetas_layer78 MLD_NAMESPACE(aarch64_ntt_zetas_layer78) + +#define mld_aarch64_intt_zetas_layer78 MLD_NAMESPACE(aarch64_intt_zetas_layer78) +#define mld_aarch64_intt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_intt_zetas_layer123456) + +extern const int32_t mld_aarch64_ntt_zetas_layer123456[]; +extern const int32_t mld_aarch64_ntt_zetas_layer78[]; + +extern const int32_t mld_aarch64_intt_zetas_layer78[]; +extern const int32_t mld_aarch64_intt_zetas_layer123456[]; + +#define mld_rej_uniform_table MLD_NAMESPACE(rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[]; +#define mld_rej_uniform_eta_table MLD_NAMESPACE(rej_uniform_eta_table) +extern const uint8_t mld_rej_uniform_eta_table[]; + +#define mld_polyz_unpack_17_indices MLD_NAMESPACE(polyz_unpack_17_indices) +extern const uint8_t mld_polyz_unpack_17_indices[]; +#define mld_polyz_unpack_19_indices MLD_NAMESPACE(polyz_unpack_19_indices) +extern const uint8_t mld_polyz_unpack_19_indices[]; + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_ntt_asm MLD_NAMESPACE(ntt_asm) +void mld_ntt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_intt_asm MLD_NAMESPACE(intt_asm) +void mld_intt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_rej_uniform_asm MLD_NAMESPACE(rej_uniform_asm) +uint64_t mld_rej_uniform_asm(int32_t *r, const uint8_t *buf, unsigned buflen, + const uint8_t *table); + +#define mld_rej_uniform_eta2_asm MLD_NAMESPACE(rej_uniform_eta2_asm) +uint64_t mld_rej_uniform_eta2_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_rej_uniform_eta4_asm MLD_NAMESPACE(rej_uniform_eta4_asm) +uint64_t mld_rej_uniform_eta4_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_poly_decompose_32_asm MLD_NAMESPACE(poly_decompose_32_asm) +void mld_poly_decompose_32_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_asm MLD_NAMESPACE(poly_decompose_88_asm) +void mld_poly_decompose_88_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_asm MLD_NAMESPACE(poly_caddq_asm) +void mld_poly_caddq_asm(int32_t *a); + +#define mld_poly_use_hint_32_asm MLD_NAMESPACE(poly_use_hint_32_asm) +void mld_poly_use_hint_32_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_asm MLD_NAMESPACE(poly_use_hint_88_asm) +void mld_poly_use_hint_88_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_asm MLD_NAMESPACE(poly_chknorm_asm) +int mld_poly_chknorm_asm(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_asm MLD_NAMESPACE(polyz_unpack_17_asm) +void mld_polyz_unpack_17_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_polyz_unpack_19_asm MLD_NAMESPACE(polyz_unpack_19_asm) +void mld_polyz_unpack_19_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_poly_pointwise_montgomery_asm \ + MLD_NAMESPACE(poly_pointwise_montgomery_asm) +void mld_poly_pointwise_montgomery_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l4_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l4_asm) +void mld_polyvecl_pointwise_acc_montgomery_l4_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l5_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l5_asm) +void mld_polyvecl_pointwise_acc_montgomery_l5_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l7_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l7_asm) +void mld_polyvecl_pointwise_acc_montgomery_l7_asm(int32_t *, const int32_t *, + const int32_t *); + +#endif /* !MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c new file mode 100644 index 0000000000..7ef915b587 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* Table of indices used for tbl instructions in polyz_unpack_{17,19}. */ + +MLD_ALIGN const uint8_t mld_polyz_unpack_17_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, + 9, 10, 11, 255, 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, + 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, 8, 9, 10, 255, + 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, 17, 18, 19, 255, +}; + +MLD_ALIGN const uint8_t mld_polyz_unpack_19_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 5, 6, 7, 255, 7, 8, 9, 255, + 10, 11, 12, 255, 12, 13, 14, 255, 15, 16, 17, 255, 17, 18, 19, 255, + 4, 5, 6, 255, 6, 7, 8, 255, 9, 10, 11, 255, 11, 12, 13, 255, + 14, 15, 16, 255, 16, 17, 18, 255, 19, 20, 21, 255, 21, 22, 23, 255, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_polyz_unpack_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c new file mode 100644 index 0000000000..cf21509cbf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by 16-bit rejection sampling (rej_eta). + * Adapted from ML-KEM for ML-DSA eta rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_eta_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 2, 3, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 4, 5, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 2, 3, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 7 */, + 6, 7, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 2, 3, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 11 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 13 */, + 2, 3, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 15 */, + 8, 9, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 16 */, + 0, 1, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 17 */, + 2, 3, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 18 */, + 0, 1, 2, 3, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 19 */, + 4, 5, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 20 */, + 0, 1, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 21 */, + 2, 3, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 22 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 23 */, + 6, 7, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 24 */, + 0, 1, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 25 */, + 2, 3, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 26 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 27 */, + 4, 5, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 28 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 29 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 30 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 255, 255, 255, 255, 255, 255 /* 31 */, + 10, 11, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 32 */, + 0, 1, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 33 */, + 2, 3, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 34 */, + 0, 1, 2, 3, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 35 */, + 4, 5, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 36 */, + 0, 1, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 37 */, + 2, 3, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 38 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 39 */, + 6, 7, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 40 */, + 0, 1, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 41 */, + 2, 3, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 42 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 43 */, + 4, 5, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 44 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 45 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 46 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 255, 255, 255, 255, 255, 255 /* 47 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 48 */, + 0, 1, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 49 */, + 2, 3, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 50 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 51 */, + 4, 5, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 52 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 53 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 54 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 55 */, + 6, 7, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 56 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 57 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 58 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 59 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 60 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 61 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 62 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 63 */, + 12, 13, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 64 */, + 0, 1, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 65 */, + 2, 3, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 66 */, + 0, 1, 2, 3, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 67 */, + 4, 5, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 68 */, + 0, 1, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 69 */, + 2, 3, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 70 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 71 */, + 6, 7, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 72 */, + 0, 1, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 73 */, + 2, 3, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 74 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 75 */, + 4, 5, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 76 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 77 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 78 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 255, 255, 255, 255, 255, 255 /* 79 */, + 8, 9, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 80 */, + 0, 1, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 81 */, + 2, 3, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 82 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 83 */, + 4, 5, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 84 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 85 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 86 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 87 */, + 6, 7, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 88 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 89 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 90 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 91 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 92 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 93 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 94 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 255, 255, 255, 255 /* 95 */, + 10, 11, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 96 */, + 0, 1, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 97 */, + 2, 3, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 98 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 99 */, + 4, 5, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 100 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 101 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 102 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 103 */, + 6, 7, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 104 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 105 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 106 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 107 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 108 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 109 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 110 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 255, 255, 255, 255 /* 111 */, + 8, 9, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 112 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 113 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 114 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 115 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 116 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 117 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 118 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 119 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 120 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 121 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 122 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 123 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 124 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 125 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 126 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 255, 255 /* 127 */, + 14, 15, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 128 */, + 0, 1, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 129 */, + 2, 3, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 130 */, + 0, 1, 2, 3, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 131 */, + 4, 5, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 132 */, + 0, 1, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 133 */, + 2, 3, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 134 */, + 0, 1, 2, 3, 4, 5, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 135 */, + 6, 7, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 136 */, + 0, 1, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 137 */, + 2, 3, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 138 */, + 0, 1, 2, 3, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 139 */, + 4, 5, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 140 */, + 0, 1, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 141 */, + 2, 3, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 142 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 14, 15, 255, 255, 255, 255, 255, 255 /* 143 */, + 8, 9, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 144 */, + 0, 1, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 145 */, + 2, 3, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 146 */, + 0, 1, 2, 3, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 147 */, + 4, 5, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 148 */, + 0, 1, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 149 */, + 2, 3, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 150 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 151 */, + 6, 7, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 152 */, + 0, 1, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 153 */, + 2, 3, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 154 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 155 */, + 4, 5, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 156 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 157 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 158 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 14, 15, 255, 255, 255, 255 /* 159 */, + 10, 11, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 160 */, + 0, 1, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 161 */, + 2, 3, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 162 */, + 0, 1, 2, 3, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 163 */, + 4, 5, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 164 */, + 0, 1, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 165 */, + 2, 3, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 166 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 167 */, + 6, 7, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 168 */, + 0, 1, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 169 */, + 2, 3, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 170 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 171 */, + 4, 5, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 172 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 173 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 174 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 14, 15, 255, 255, 255, 255 /* 175 */, + 8, 9, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 176 */, + 0, 1, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 177 */, + 2, 3, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 178 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 179 */, + 4, 5, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 180 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 181 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 182 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 183 */, + 6, 7, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 184 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 185 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 186 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 187 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 188 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 189 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 190 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 14, 15, 255, 255 /* 191 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 192 */, + 0, 1, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 193 */, + 2, 3, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 194 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 195 */, + 4, 5, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 196 */, + 0, 1, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 197 */, + 2, 3, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 198 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 199 */, + 6, 7, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 200 */, + 0, 1, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 201 */, + 2, 3, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 202 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 203 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 204 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 205 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 206 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 207 */, + 8, 9, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 208 */, + 0, 1, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 209 */, + 2, 3, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 210 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 211 */, + 4, 5, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 212 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 213 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 214 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 215 */, + 6, 7, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 216 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 217 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 218 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 219 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 220 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 221 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 222 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 14, 15, 255, 255 /* 223 */, + 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 224 */, + 0, 1, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 225 */, + 2, 3, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 226 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 227 */, + 4, 5, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 228 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 229 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 230 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 231 */, + 6, 7, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 232 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 233 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 234 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 235 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 236 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 237 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 238 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 14, 15, 255, 255 /* 239 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 240 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 241 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 242 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 243 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 244 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 245 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 246 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 247 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 248 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 249 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 250 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 251 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 252 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 253 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 254 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 255 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_eta_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/src/rej_uniform_table.c new file mode 100644 index 0000000000..65bc3b78d3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/aarch64/src/rej_uniform_table.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by rejection sampling of the public matrix. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 7 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 11 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 13 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 15 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/api.h new file mode 100644 index 0000000000..0f1fdeb168 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/api.h @@ -0,0 +1,594 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_API_H +#define MLD_NATIVE_API_H +/* + * Native arithmetic interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + * + * To ensure consistency with backends, the header will be + * included automatically after inclusion of the active + * backend, to ensure consistency of function signatures, + * and run sanity checks. + */ + +#include +#include "../cbmc.h" +#include "../common.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* Bound on absolute value of coefficients after NTT. + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) + +/* Absolute exclusive upper bound for the output of the inverse NTT + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_INTT_BOUND MLDSA_Q + +/* Absolute bound for range of mld_reduce32() + * + * NOTE: This is the same bound as in reduce.h and has to be kept + * in sync. */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define REDUCE32_RANGE_MAX 6283009 +/* + * This is the C<->native interface allowing for the drop-in of + * native code for performance critical arithmetic components of ML-DSA. + * + * A _backend_ is a specific implementation of (part of) this interface. + * + * To add a function to a backend, define MLD_USE_NATIVE_XXX and + * implement `static inline xxx(...)` in the profile header. + */ + +/* + * Those functions are meant to be trivial wrappers around the chosen native + * implementation. The are static inline to avoid unnecessary calls. + * The macro before each declaration controls whether a native + * implementation is present. + */ + +#if defined(MLD_USE_NATIVE_NTT) +/************************************************* + * Name: mld_ntt_native + * + * Description: Computes negacyclic number-theoretic transform (NTT) of + * a polynomial in place. + * + * The input polynomial is assumed to be in normal order. + * The output polynomial is in bitreversed order. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_ntt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_NTT */ + + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) +/* + * This must only be set if NTT and INTT have native implementations + * that are adapted to the custom order. + */ +#if !defined(MLD_USE_NATIVE_NTT) || !defined(MLD_USE_NATIVE_INTT) +#error \ + "Invalid native profile: MLD_USE_NATIVE_NTT_CUSTOM_ORDER can only be \ +set if there are native implementations for NTT and INTT." +#endif + +/************************************************* + * Name: mlD_poly_permute_bitrev_to_custom + * + * Description: When MLD_USE_NATIVE_NTT_CUSTOM_ORDER is defined, + * convert a polynomial in NTT domain from bitreversed + * order to the custom order output by the native NTT. + * + * This must only be defined if there is native code for + * both the NTT and INTT. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + * + **************************************************/ +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t p[MLDSA_N]) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q))); +#endif /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + + +#if defined(MLD_USE_NATIVE_INTT) +/************************************************* + * Name: mld_intt_native + * + * Description: Computes inverse of negacyclic number-theoretic transform + *(NTT) of a polynomial in place. + * + * The input polynomial is in bitreversed order. + * The output polynomial is assumed to be in normal order. + * + * Arguments: - uint32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_intt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_INTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_INTT */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) +/************************************************* + * Name: mld_rej_uniform_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [0, MLDSA_Q-1] + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform mod q). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + * lengths. Otherwise, returns non-negative number of sampled 32-bit integers + * (at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= ( 5 * 168) && buflen % 3 == 0) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(r, 0, (unsigned) return_value, 0, MLDSA_Q)) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) +/************************************************* + * Name: mld_rej_uniform_eta2_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-2,+2]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-2, +2]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA2 */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) +/************************************************* + * Name: mld_rej_uniform_eta4_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-4,+4]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-4, +4]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) +/************************************************* + * Name: mld_poly_decompose_32_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/32. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: input/output polynomial. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_32 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) +/************************************************* + * Name: mld_poly_decompose_88_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/88. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: output polynomial with coefficients c0. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CADDQ) +/************************************************* + * Name: mld_poly_caddq_native + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *a: pointer to input/output polynomial + **************************************************/ +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_32) +/************************************************* + * Name: mld_poly_use_hint_32_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/32. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_32 */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) +/************************************************* + * Name: mld_poly_use_hint_88_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/88. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) +/************************************************* + * Name: mld_poly_chknorm_native + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const int32_t *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if the infinity norm is strictly smaller than B, and 1 + * otherwise. B must not be larger than MLDSA_Q - MLD_REDUCE32_RANGE_MAX. + **************************************************/ +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(0 <= B && B <= MLDSA_Q - REDUCE32_RANGE_MAX) + requires(array_bound(a, 0, MLDSA_N, -REDUCE32_RANGE_MAX, REDUCE32_RANGE_MAX)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == 0) == array_abs_bound(a, 0, MLDSA_N, B)) +); +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) +/************************************************* + * Name: mld_polyz_unpack_17_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^17. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_17 */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) +/************************************************* + * Name: mld_polyz_unpack_19_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^19. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_19 */ + +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) +/************************************************* + * Name: mld_poly_pointwise_montgomery_native + * + * Description: Pointwise multiplication of polynomials in NTT domain + * with Montgomery reduction. + * + * Computes c[i] = a[i] * b[i] * R^(-1) mod q for all i, + * where R = 2^32. + * + * Arguments: - int32_t c[MLDSA_N]: output polynomial + * - const int32_t a[MLDSA_N]: first input polynomial + * - const int32_t b[MLDSA_N]: second input polynomial + **************************************************/ +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(c, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(c, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(c, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l4_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 4. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 4 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 4 * MLDSA_N)) + requires(forall(l0, 0, 4, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 4, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l5_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 5. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 5 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 5 * MLDSA_N)) + requires(forall(l0, 0, 5, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 5, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l7_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 7. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 7 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 7 * MLDSA_N)) + requires(forall(l0, 0, 7, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 7, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 */ + +#endif /* !MLD_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/meta.h new file mode 100644 index 0000000000..0b46dd5791 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/meta.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_META_H +#define MLD_NATIVE_META_H + +/* + * Default arithmetic backend + */ +#include "../sys.h" + +#ifdef MLD_SYS_AARCH64 +#include "aarch64/meta.h" +#endif + +#ifdef MLD_SYS_X86_64_AVX2 +#include "x86_64/meta.h" +#endif + +#endif /* !MLD_NATIVE_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/meta.h new file mode 100644 index 0000000000..393374c06f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/meta.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_X86_64_META_H +#define MLD_NATIVE_X86_64_META_H + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_X86_64_DEFAULT + +#define MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +#if !defined(__ASSEMBLER__) +#include +#include "../../common.h" +#include "../api.h" +#include "src/arith_native_x86_64.h" + +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t data[MLDSA_N]) +{ + if (mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + mld_nttunpack_avx2(data); + } +} + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_ntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_invntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)mld_rej_uniform_avx2(r, buf); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_32_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_88_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_caddq_avx2(a); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_32_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_88_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + return mld_poly_chknorm_avx2(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_17_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_19_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_avx2(c, a, b, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l4_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l5_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l7_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_NATIVE_X86_64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h new file mode 100644 index 0000000000..08d5abf74a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#define MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#include "../../../common.h" + +#include +#include "consts.h" + +#define MLD_AVX2_REJ_UNIFORM_BUFLEN \ + (5 * 168) /* REJ_UNIFORM_NBLOCKS * SHAKE128_RATE */ + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) + +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_rej_uniform_table MLD_NAMESPACE(mld_rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[256][8]; + +#define mld_ntt_avx2 MLD_NAMESPACE(ntt_avx2) +void mld_ntt_avx2(int32_t *r, const int32_t *qdata) +/* This must be kept in sync with the HOL-Light specification + * in proofs/hol_light/x86_64/proofs/mldsa_ntt.ml */ +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, MLDSA_N, 8380417)) + requires(qdata == mld_qdata) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + /* check-magic: off */ + ensures(array_abs_bound(r, 0, MLDSA_N, 42035262)) + /* check-magic: on */ +); + +#define mld_invntt_avx2 MLD_NAMESPACE(invntt_avx2) +void mld_invntt_avx2(int32_t *r, const int32_t *mld_qdata); + +#define mld_nttunpack_avx2 MLD_NAMESPACE(nttunpack_avx2) +void mld_nttunpack_avx2(int32_t *r); + +#define mld_rej_uniform_avx2 MLD_NAMESPACE(mld_rej_uniform_avx2) +unsigned mld_rej_uniform_avx2(int32_t *r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]); + +#define mld_rej_uniform_eta2_avx2 MLD_NAMESPACE(mld_rej_uniform_eta2_avx2) +unsigned mld_rej_uniform_eta2_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]); + +#define mld_rej_uniform_eta4_avx2 MLD_NAMESPACE(mld_rej_uniform_eta4_avx2) +unsigned mld_rej_uniform_eta4_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]); + +#define mld_poly_decompose_32_avx2 MLD_NAMESPACE(mld_poly_decompose_32_avx2) +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_avx2 MLD_NAMESPACE(mld_poly_decompose_88_avx2) +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_avx2 MLD_NAMESPACE(poly_caddq_avx2) +void mld_poly_caddq_avx2(int32_t *r); + +#define mld_poly_use_hint_32_avx2 MLD_NAMESPACE(mld_poly_use_hint_32_avx2) +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_avx2 MLD_NAMESPACE(mld_poly_use_hint_88_avx2) +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_avx2 MLD_NAMESPACE(mld_poly_chknorm_avx2) +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_avx2 MLD_NAMESPACE(mld_polyz_unpack_17_avx2) +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a); + +#define mld_polyz_unpack_19_avx2 MLD_NAMESPACE(mld_polyz_unpack_19_avx2) +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a); + +#define mld_pointwise_avx2 MLD_NAMESPACE(pointwise_avx2) +void mld_pointwise_avx2(int32_t *c, const int32_t *a, const int32_t *b, + const int32_t *qdata); + +#define mld_pointwise_acc_l4_avx2 MLD_NAMESPACE(pointwise_acc_l4_avx2) +void mld_pointwise_acc_l4_avx2(int32_t c[MLDSA_N], const int32_t a[4][MLDSA_N], + const int32_t b[4][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l5_avx2 MLD_NAMESPACE(pointwise_acc_l5_avx2) +void mld_pointwise_acc_l5_avx2(int32_t c[MLDSA_N], const int32_t a[5][MLDSA_N], + const int32_t b[5][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l7_avx2 MLD_NAMESPACE(pointwise_acc_l7_avx2) +void mld_pointwise_acc_l7_avx2(int32_t c[MLDSA_N], const int32_t a[7][MLDSA_N], + const int32_t b[7][MLDSA_N], + const int32_t *qdata); + +#endif /* !MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/consts.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/consts.c new file mode 100644 index 0000000000..aaca3535ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/consts.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include "consts.h" + +/* + * Table of zeta values used in the AVX2 forward and inverse NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_qdata[624] = { + 8380417, 8380417, 8380417, 8380417, 8380417, + 8380417, 8380417, 8380417, 58728449, 58728449, + 58728449, 58728449, 58728449, 58728449, 58728449, + 58728449, -8395782, -8395782, -8395782, -8395782, + -8395782, -8395782, -8395782, -8395782, 41978, + 41978, 41978, 41978, 41978, 41978, + 41978, 41978, -151046689, 1830765815, -1929875198, + -1927777021, 1640767044, 1477910808, 1612161320, 1640734244, + 308362795, 308362795, 308362795, 308362795, -1815525077, + -1815525077, -1815525077, -1815525077, -1374673747, -1374673747, + -1374673747, -1374673747, -1091570561, -1091570561, -1091570561, + -1091570561, -1929495947, -1929495947, -1929495947, -1929495947, + 515185417, 515185417, 515185417, 515185417, -285697463, + -285697463, -285697463, -285697463, 625853735, 625853735, + 625853735, 625853735, 1727305304, 1727305304, 2082316400, + 2082316400, -1364982364, -1364982364, 858240904, 858240904, + 1806278032, 1806278032, 222489248, 222489248, -346752664, + -346752664, 684667771, 684667771, 1654287830, 1654287830, + -878576921, -878576921, -1257667337, -1257667337, -748618600, + -748618600, 329347125, 329347125, 1837364258, 1837364258, + -1443016191, -1443016191, -1170414139, -1170414139, -1846138265, + -1631226336, -1404529459, 1838055109, 1594295555, -1076973524, + -1898723372, -594436433, -202001019, -475984260, -561427818, + 1797021249, -1061813248, 2059733581, -1661512036, -1104976547, + -1750224323, -901666090, 418987550, 1831915353, -1925356481, + 992097815, 879957084, 2024403852, 1484874664, -1636082790, + -285388938, -1983539117, -1495136972, -950076368, -1714807468, + -952438995, -1574918427, 1350681039, -2143979939, 1599739335, + -1285853323, -993005454, -1440787840, 568627424, -783134478, + -588790216, 289871779, -1262003603, 2135294594, -1018755525, + -889861155, 1665705315, 1321868265, 1225434135, -1784632064, + 666258756, 675310538, -1555941048, -1999506068, -1499481951, + -695180180, -1375177022, 1777179795, 334803717, -178766299, + -518252220, 1957047970, 1146323031, -654783359, -1974159335, + 1651689966, 140455867, -1039411342, 1955560694, 1529189038, + -2131021878, -247357819, 1518161567, -86965173, 1708872713, + 1787797779, 1638590967, -120646188, -1669960606, -916321552, + 1155548552, 2143745726, 1210558298, -1261461890, -318346816, + 628664287, -1729304568, 1422575624, 1424130038, -1185330464, + 235321234, 168022240, 1206536194, 985155484, -894060583, + -898413, -1363460238, -605900043, 2027833504, 14253662, + 1014493059, 863641633, 1819892093, 2124962073, -1223601433, + -1920467227, -1637785316, -1536588520, 694382729, 235104446, + -1045062172, 831969619, -300448763, 756955444, -260312805, + 1554794072, 1339088280, -2040058690, -853476187, -2047270596, + -1723816713, -1591599803, -440824168, 1119856484, 1544891539, + 155290192, -973777462, 991903578, 912367099, -44694137, + 1176904444, -421552614, -818371958, 1747917558, -325927722, + 908452108, 1851023419, -1176751719, -1354528380, -72690498, + -314284737, 985022747, 963438279, -1078959975, 604552167, + -1021949428, 608791570, 173440395, -2126092136, -1316619236, + -1039370342, 6087993, -110126092, 565464272, -1758099917, + -1600929361, 879867909, -1809756372, 400711272, 1363007700, + 30313375, -326425360, 1683520342, -517299994, 2027935492, + -1372618620, 128353682, -1123881663, 137583815, -635454918, + -642772911, 45766801, 671509323, -2070602178, 419615363, + 1216882040, -270590488, -1276805128, 371462360, -1357098057, + -384158533, 827959816, -596344473, 702390549, -279505433, + -260424530, -71875110, -1208667171, -1499603926, 2036925262, + -540420426, 746144248, -1420958686, 2032221021, 1904936414, + 1257750362, 1926727420, 1931587462, 1258381762, 885133339, + 1629985060, 1967222129, 6363718, -1287922800, 1136965286, + 1779436847, 1116720494, 1042326957, 1405999311, 713994583, + 940195359, -1542497137, 2061661095, -883155599, 1726753853, + -1547952704, 394851342, 283780712, 776003547, 1123958025, + 201262505, 1934038751, 374860238, -3975713, 25847, + -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 1826347, 1826347, 1826347, + 2353451, 2353451, 2353451, 2353451, -359251, + -359251, -359251, -359251, -2091905, -2091905, + -2091905, -2091905, 3119733, 3119733, 3119733, + 3119733, -2884855, -2884855, -2884855, -2884855, + 3111497, 3111497, 3111497, 3111497, 2680103, + 2680103, 2680103, 2680103, 2725464, 2725464, + 1024112, 1024112, -1079900, -1079900, 3585928, + 3585928, -549488, -549488, -1119584, -1119584, + 2619752, 2619752, -2108549, -2108549, -2118186, + -2118186, -3859737, -3859737, -1399561, -1399561, + -3277672, -3277672, 1757237, 1757237, -19422, + -19422, 4010497, 4010497, 280005, 280005, + 2706023, 95776, 3077325, 3530437, -1661693, + -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, + -539299, -1699267, -1643818, 3505694, -3821735, + 3507263, -2140649, -1600420, 3699596, 811944, + 531354, 954230, 3881043, 3900724, -2556880, + 2071892, -2797779, -3930395, -3677745, -1452451, + 2176455, -1257611, -4083598, -3190144, -3632928, + 3412210, 2147896, -2967645, -411027, -671102, + -22981, -381987, 1852771, -3343383, 508951, + 44288, 904516, -3724342, 1653064, 2389356, + 759969, 189548, 3159746, -2409325, 1315589, + 1285669, -812732, -3019102, -3628969, -1528703, + -3041255, 3475950, -1585221, 1939314, -1000202, + -3157330, 126922, -983419, 2715295, -3693493, + -2477047, -1228525, -1308169, 1349076, -1430430, + 264944, 3097992, -1100098, 3958618, -8578, + -3249728, -210977, -1316856, -3553272, -1851402, + -177440, 1341330, -1584928, -1439742, -3881060, + 3839961, 2091667, -3342478, 266997, -3520352, + 900702, 495491, -655327, -3556995, 342297, + 3437287, 2842341, 4055324, -3767016, -2994039, + -1333058, -451100, -1279661, 1500165, -542412, + -2584293, -2013608, 1957272, -3183426, 810149, + -3038916, 2213111, -426683, -1667432, -2939036, + 183443, -554416, 3937738, 3407706, 2244091, + 2434439, -3759364, 1859098, -1613174, -3122442, + -525098, 286988, -3342277, 2691481, 1247620, + 1250494, 1869119, 1237275, 1312455, 1917081, + 777191, -2831860, -3724270, 2432395, 3369112, + 162844, 1652634, 3523897, -975884, 1723600, + -1104333, -2235985, -976891, 3919660, 1400424, + 2316500, -2446433, -1235728, -1197226, 909542, + -43260, 2031748, -768622, -2437823, 1735879, + -2590150, 2486353, 2635921, 1903435, -3318210, + 3306115, -2546312, 2235880, -1671176, 594136, + 2454455, 185531, 1616392, -3694233, 3866901, + 1717735, -1803090, -260646, -420899, 1612842, + -48306, -846154, 3817976, -3562462, 3513181, + -3193378, 819034, -522500, 3207046, -3595838, + 4108315, 203044, 1265009, 1595974, -3548272, + -1050970, -1430225, -1962642, -1374803, 3406031, + -1846953, -3776993, -164721, -1207385, 3014001, + -1799107, 269760, 472078, 1910376, -3833893, + -2286327, -3545687, -1362209, 1976782, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_consts) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/consts.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/consts.h new file mode 100644 index 0000000000..7fe08f454b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/consts.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#ifndef MLD_NATIVE_X86_64_SRC_CONSTS_H +#define MLD_NATIVE_X86_64_SRC_CONSTS_H +#include "../../../common.h" +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQ 0 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV 8 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV 16 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV 24 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV 32 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS 328 + +#ifndef __ASSEMBLER__ +#define mld_qdata MLD_NAMESPACE(qdata) +extern const int32_t mld_qdata[624]; +#endif + +#endif /* !MLD_NATIVE_X86_64_SRC_CONSTS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c new file mode 100644 index 0000000000..05d86d14fc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/************************************************* + * Name: mld_poly_caddq_avx2 + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *r: pointer to input/output polynomial + **************************************************/ +void mld_poly_caddq_avx2(int32_t *r) +{ + unsigned int i; + __m256i f, g; + const __m256i q = _mm256_set1_epi32(MLDSA_Q); + const __m256i zero = _mm256_setzero_si256(); + __m256i *rr = (__m256i *)r; + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256(&rr[i]); + g = _mm256_cmpgt_epi32(zero, f); + g = _mm256_and_si256(g, q); + f = _mm256_add_epi32(f, g); + _mm256_store_si256(&rr[i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_reduce) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c new file mode 100644 index 0000000000..50e2c7fa9b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B) +{ + unsigned int i; + __m256i f, t; + const __m256i bound = _mm256_set1_epi32(B - 1); + + t = _mm256_setzero_si256(); + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + f = _mm256_abs_epi32(f); + f = _mm256_cmpgt_epi32(f, bound); + t = _mm256_or_si256(t, f); + } + + return 1 - _mm256_testz_si256(t, t); +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_chknorm) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c new file mode 100644 index 0000000000..76846bf1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(31 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 4092 == intdiv(2 * intdiv(MLDSA_Q - 1, 32), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 4092. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 32*GAMMA2 = 16*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 16B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + * + * round(f1' * 1025 / 2^22) is in turn computed in 2 steps as + * round(floor(f1' * 1025 / 2^16) / 2^6). The mulhi computes f1'' = + * floor(f1' * 1025 / 2^16). As for the next step f1 = round(f1'' / 2^6), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^9) = round(f1'' * 2^9 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 1025 / 2^16) = 1025 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(16B / B) = 16 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 16, i.e. f > 31*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 31*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 15, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c new file mode 100644 index 0000000000..463506b962 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ + +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 1488 == intdiv(2 * intdiv(MLDSA_Q - 1, 88), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 1488. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 88*GAMMA2 = 44*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 44B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + * + * round(f1' * 11275 / 2^24) is in turn computed in 2 steps as + * round(floor(f1' * 11275 / 2^16) / 2^8). The mulhi computes f1'' = + * floor(f1' * 11275 / 2^16). As for the next step f1 = round(f1'' / 2^8), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^7) = round(f1'' * 2^7 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 11275 / 2^16) = 11275 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(44B / B) = 44 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 44, i.e. f > 87*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 87*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 43, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c new file mode 100644 index 0000000000..0094bc93a9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + const __m256i mask = _mm256_set1_epi32(15); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_32_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 16 */ + f1 = _mm256_add_epi32(f1, h); + f1 = _mm256_and_si256(f1, mask); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c new file mode 100644 index 0000000000..b109ab6351 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + const __m256i max = _mm256_set1_epi32(43); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_88_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 44 */ + f1 = _mm256_add_epi32(f1, h); + f1 = MLD_MM256_BLENDV_EPI32(f1, max, f1); + f = _mm256_cmpgt_epi32(f1, max); + f1 = MLD_MM256_BLENDV_EPI32(f1, zero, f); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c new file mode 100644 index 0000000000..f6c08a832f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 27, 26, 25, -1, 25, 24, 23, -1, 8, 7, + 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0); + const __m256i srlvdidx = _mm256_set_epi32(6, 4, 2, 0, 6, 4, 2, 0); + const __m256i mask = _mm256_set1_epi32(0x3FFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 17)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[18 * i]); + /* Load bytes 2..17 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[18 * i + 2]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-8 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 8, 7, 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte8, byte7, byte6, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,27, 26, 25, -1,25, 24, 23] │ + * │ Result: [0, byte17, byte16, byte15, ..., 0, byte11, byte10, byte9] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 18 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 32..55 48..71 + * 72..95 88..111 104..127 120..143 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 18..39 36..55 54..71 + * 72..95 90..111 108..127 126..143 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..17 18..35 36..53 54..71 + * 72..89 90..107 108..125 126..143 */ + + /* Map [0, 1, ..., 2^18-1] to [2^17, 2^17-1, ..., -2^17+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_17) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c new file mode 100644 index 0000000000..4a5ce48f38 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 26, 25, 24, -1, 24, 23, 22, -1, 9, 8, + 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0); + /* Equivalent to _mm256_set_epi32(4, 0, 4, 0, 4, 0, 4, 0) */ + const __m256i srlvdidx = _mm256_set1_epi64x((uint64_t)4 << 32); + const __m256i mask = _mm256_set1_epi32(0xFFFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 19)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[20 * i]); + /* Load bytes 4..19 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[20 * i + 4]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-9 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 9, 8, 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte9, byte8, byte7, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,26, 25, 24, -1,24, 23, 22] │ + * │ Result: [0, byte19, byte18, byte17, ..., 0, byte12, byte11, byte10] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 20 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 40..63 56..79 + * 80..103 96..119 120..143 136..159 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 20..39 40..63 60..79 + * 80..103 100..119 120..143 140..159 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..19 20..39 40..59 60..79 + * 80..99 100..119 120..139 140..159 */ + + /* Map [0, 1, ..., 2^20-1] to [2^19, 2^19-1, ..., -2^19+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_19) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c new file mode 100644 index 0000000000..07a5df9706 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The pqcrystals implementation assumes a buffer that is 8 bytes + *. larger as the first loop overreads by 8 bytes that are then + * discarded. We instead do not pad the buffer and do not overread. + * The performance impact is negligible and it does not force the + * frontend to perform the unintuitive padding. + */ + +unsigned int mld_rej_uniform_avx2( + int32_t *MLD_RESTRICT r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i d, tmp; + const __m256i bound = _mm256_set1_epi32(MLDSA_Q); + const __m256i mask = _mm256_set1_epi32(0x7FFFFF); + const __m256i idx8 = + _mm256_set_epi8(-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4, + -1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 32) + { + d = _mm256_loadu_si256((__m256i *)&buf[pos]); + + /* Permute 64-bit lanes + * 0x94 = 10010100b rearranges 64-bit lanes as: [3,2,1,0] -> [2,1,1,0] + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Original Layout ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ bytes 16..23 │ bytes 24..31 │ + * └─────────────────┴─────────────────┴─────────────────┴─────────────────┘ + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Layout after permute ║ + * ║ Byte indices in high half shifted down by 8 positions ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌───────────────┬─────────────────┐ ┌─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ │ bytes 8..15 │ bytes 16..23 │ + * └───────────────┴─────────────────┘ └─────────────────┴─────────────────┘ + * Lower 128-bit lane (bytes 0-15) Upper 128-bit lane (bytes 16-31) + */ + d = _mm256_permute4x64_epi64(d, 0x94); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-11 into low 128-bit half of permuted vector────────────────┐ + * │ Shuffle: [-1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0] │ + * │ Result: [0, byte11, byte10, byte9, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 4-15 into high 128-bit half of permuted vector ──────────────┐ + * │ Shuffle: [-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4] │ + * │ Result: [0, byte23, byte22, byte21, ..., 0, byte14, byte13, byte12 │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + d = _mm256_shuffle_epi8(d, idx8); + d = _mm256_and_si256(d, mask); + pos += 24; + + tmp = _mm256_sub_epi32(d, bound); + good = (uint32_t)_mm256_movemask_ps((__m256)tmp); + tmp = _mm256_cvtepu8_epi32( + _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good])); + d = _mm256_permutevar8x32_epi32(d, tmp); + + _mm256_storeu_si256((__m256i *)&r[ctr], d); + ctr += (unsigned)_mm_popcnt_u32(good); + } + + while (ctr < MLDSA_N && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 3) + { + uint32_t t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + /* Safe because t < MLDSA_Q. */ + r[ctr++] = (int32_t)t; + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c new file mode 100644 index 0000000000..70c5c42c70 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA2 2 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ +unsigned int mld_rej_uniform_eta2_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1, f2; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA2); + const __m256i bound = mask; + /* check-magic: -6560 == 32*round(-2**10 / 5) */ + const __m256i v = _mm256_set1_epi32(-6560); + const __m256i p = _mm256_set1_epi32(5); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 15) + { + t0 = t0 - (205 * t0 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t0); + } + if (t1 < 15 && ctr < MLDSA_N) + { + t1 = t1 - (205 * t1 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta2) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA2 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c new file mode 100644 index 0000000000..ba00e91252 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA4 4 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ + +unsigned int mld_rej_uniform_eta4_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA4); + const __m256i bound = _mm256_set1_epi8(9); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 9) + { + r[ctr++] = (int32_t)(4 - t0); + } + if (t1 < 9 && ctr < MLDSA_N) + { + r[ctr++] = (int32_t)(4 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta4) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA4 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/rej_uniform_table.c new file mode 100644 index 0000000000..6c537b4542 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/native/x86_64/src/rej_uniform_table.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" + +/* + * Lookup table used by rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[256][8] = { + {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, + {2, 0, 0, 0, 0, 0, 0, 0}, {0, 2, 0, 0, 0, 0, 0, 0}, + {1, 2, 0, 0, 0, 0, 0, 0}, {0, 1, 2, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 0, 0}, {0, 3, 0, 0, 0, 0, 0, 0}, + {1, 3, 0, 0, 0, 0, 0, 0}, {0, 1, 3, 0, 0, 0, 0, 0}, + {2, 3, 0, 0, 0, 0, 0, 0}, {0, 2, 3, 0, 0, 0, 0, 0}, + {1, 2, 3, 0, 0, 0, 0, 0}, {0, 1, 2, 3, 0, 0, 0, 0}, + {4, 0, 0, 0, 0, 0, 0, 0}, {0, 4, 0, 0, 0, 0, 0, 0}, + {1, 4, 0, 0, 0, 0, 0, 0}, {0, 1, 4, 0, 0, 0, 0, 0}, + {2, 4, 0, 0, 0, 0, 0, 0}, {0, 2, 4, 0, 0, 0, 0, 0}, + {1, 2, 4, 0, 0, 0, 0, 0}, {0, 1, 2, 4, 0, 0, 0, 0}, + {3, 4, 0, 0, 0, 0, 0, 0}, {0, 3, 4, 0, 0, 0, 0, 0}, + {1, 3, 4, 0, 0, 0, 0, 0}, {0, 1, 3, 4, 0, 0, 0, 0}, + {2, 3, 4, 0, 0, 0, 0, 0}, {0, 2, 3, 4, 0, 0, 0, 0}, + {1, 2, 3, 4, 0, 0, 0, 0}, {0, 1, 2, 3, 4, 0, 0, 0}, + {5, 0, 0, 0, 0, 0, 0, 0}, {0, 5, 0, 0, 0, 0, 0, 0}, + {1, 5, 0, 0, 0, 0, 0, 0}, {0, 1, 5, 0, 0, 0, 0, 0}, + {2, 5, 0, 0, 0, 0, 0, 0}, {0, 2, 5, 0, 0, 0, 0, 0}, + {1, 2, 5, 0, 0, 0, 0, 0}, {0, 1, 2, 5, 0, 0, 0, 0}, + {3, 5, 0, 0, 0, 0, 0, 0}, {0, 3, 5, 0, 0, 0, 0, 0}, + {1, 3, 5, 0, 0, 0, 0, 0}, {0, 1, 3, 5, 0, 0, 0, 0}, + {2, 3, 5, 0, 0, 0, 0, 0}, {0, 2, 3, 5, 0, 0, 0, 0}, + {1, 2, 3, 5, 0, 0, 0, 0}, {0, 1, 2, 3, 5, 0, 0, 0}, + {4, 5, 0, 0, 0, 0, 0, 0}, {0, 4, 5, 0, 0, 0, 0, 0}, + {1, 4, 5, 0, 0, 0, 0, 0}, {0, 1, 4, 5, 0, 0, 0, 0}, + {2, 4, 5, 0, 0, 0, 0, 0}, {0, 2, 4, 5, 0, 0, 0, 0}, + {1, 2, 4, 5, 0, 0, 0, 0}, {0, 1, 2, 4, 5, 0, 0, 0}, + {3, 4, 5, 0, 0, 0, 0, 0}, {0, 3, 4, 5, 0, 0, 0, 0}, + {1, 3, 4, 5, 0, 0, 0, 0}, {0, 1, 3, 4, 5, 0, 0, 0}, + {2, 3, 4, 5, 0, 0, 0, 0}, {0, 2, 3, 4, 5, 0, 0, 0}, + {1, 2, 3, 4, 5, 0, 0, 0}, {0, 1, 2, 3, 4, 5, 0, 0}, + {6, 0, 0, 0, 0, 0, 0, 0}, {0, 6, 0, 0, 0, 0, 0, 0}, + {1, 6, 0, 0, 0, 0, 0, 0}, {0, 1, 6, 0, 0, 0, 0, 0}, + {2, 6, 0, 0, 0, 0, 0, 0}, {0, 2, 6, 0, 0, 0, 0, 0}, + {1, 2, 6, 0, 0, 0, 0, 0}, {0, 1, 2, 6, 0, 0, 0, 0}, + {3, 6, 0, 0, 0, 0, 0, 0}, {0, 3, 6, 0, 0, 0, 0, 0}, + {1, 3, 6, 0, 0, 0, 0, 0}, {0, 1, 3, 6, 0, 0, 0, 0}, + {2, 3, 6, 0, 0, 0, 0, 0}, {0, 2, 3, 6, 0, 0, 0, 0}, + {1, 2, 3, 6, 0, 0, 0, 0}, {0, 1, 2, 3, 6, 0, 0, 0}, + {4, 6, 0, 0, 0, 0, 0, 0}, {0, 4, 6, 0, 0, 0, 0, 0}, + {1, 4, 6, 0, 0, 0, 0, 0}, {0, 1, 4, 6, 0, 0, 0, 0}, + {2, 4, 6, 0, 0, 0, 0, 0}, {0, 2, 4, 6, 0, 0, 0, 0}, + {1, 2, 4, 6, 0, 0, 0, 0}, {0, 1, 2, 4, 6, 0, 0, 0}, + {3, 4, 6, 0, 0, 0, 0, 0}, {0, 3, 4, 6, 0, 0, 0, 0}, + {1, 3, 4, 6, 0, 0, 0, 0}, {0, 1, 3, 4, 6, 0, 0, 0}, + {2, 3, 4, 6, 0, 0, 0, 0}, {0, 2, 3, 4, 6, 0, 0, 0}, + {1, 2, 3, 4, 6, 0, 0, 0}, {0, 1, 2, 3, 4, 6, 0, 0}, + {5, 6, 0, 0, 0, 0, 0, 0}, {0, 5, 6, 0, 0, 0, 0, 0}, + {1, 5, 6, 0, 0, 0, 0, 0}, {0, 1, 5, 6, 0, 0, 0, 0}, + {2, 5, 6, 0, 0, 0, 0, 0}, {0, 2, 5, 6, 0, 0, 0, 0}, + {1, 2, 5, 6, 0, 0, 0, 0}, {0, 1, 2, 5, 6, 0, 0, 0}, + {3, 5, 6, 0, 0, 0, 0, 0}, {0, 3, 5, 6, 0, 0, 0, 0}, + {1, 3, 5, 6, 0, 0, 0, 0}, {0, 1, 3, 5, 6, 0, 0, 0}, + {2, 3, 5, 6, 0, 0, 0, 0}, {0, 2, 3, 5, 6, 0, 0, 0}, + {1, 2, 3, 5, 6, 0, 0, 0}, {0, 1, 2, 3, 5, 6, 0, 0}, + {4, 5, 6, 0, 0, 0, 0, 0}, {0, 4, 5, 6, 0, 0, 0, 0}, + {1, 4, 5, 6, 0, 0, 0, 0}, {0, 1, 4, 5, 6, 0, 0, 0}, + {2, 4, 5, 6, 0, 0, 0, 0}, {0, 2, 4, 5, 6, 0, 0, 0}, + {1, 2, 4, 5, 6, 0, 0, 0}, {0, 1, 2, 4, 5, 6, 0, 0}, + {3, 4, 5, 6, 0, 0, 0, 0}, {0, 3, 4, 5, 6, 0, 0, 0}, + {1, 3, 4, 5, 6, 0, 0, 0}, {0, 1, 3, 4, 5, 6, 0, 0}, + {2, 3, 4, 5, 6, 0, 0, 0}, {0, 2, 3, 4, 5, 6, 0, 0}, + {1, 2, 3, 4, 5, 6, 0, 0}, {0, 1, 2, 3, 4, 5, 6, 0}, + {7, 0, 0, 0, 0, 0, 0, 0}, {0, 7, 0, 0, 0, 0, 0, 0}, + {1, 7, 0, 0, 0, 0, 0, 0}, {0, 1, 7, 0, 0, 0, 0, 0}, + {2, 7, 0, 0, 0, 0, 0, 0}, {0, 2, 7, 0, 0, 0, 0, 0}, + {1, 2, 7, 0, 0, 0, 0, 0}, {0, 1, 2, 7, 0, 0, 0, 0}, + {3, 7, 0, 0, 0, 0, 0, 0}, {0, 3, 7, 0, 0, 0, 0, 0}, + {1, 3, 7, 0, 0, 0, 0, 0}, {0, 1, 3, 7, 0, 0, 0, 0}, + {2, 3, 7, 0, 0, 0, 0, 0}, {0, 2, 3, 7, 0, 0, 0, 0}, + {1, 2, 3, 7, 0, 0, 0, 0}, {0, 1, 2, 3, 7, 0, 0, 0}, + {4, 7, 0, 0, 0, 0, 0, 0}, {0, 4, 7, 0, 0, 0, 0, 0}, + {1, 4, 7, 0, 0, 0, 0, 0}, {0, 1, 4, 7, 0, 0, 0, 0}, + {2, 4, 7, 0, 0, 0, 0, 0}, {0, 2, 4, 7, 0, 0, 0, 0}, + {1, 2, 4, 7, 0, 0, 0, 0}, {0, 1, 2, 4, 7, 0, 0, 0}, + {3, 4, 7, 0, 0, 0, 0, 0}, {0, 3, 4, 7, 0, 0, 0, 0}, + {1, 3, 4, 7, 0, 0, 0, 0}, {0, 1, 3, 4, 7, 0, 0, 0}, + {2, 3, 4, 7, 0, 0, 0, 0}, {0, 2, 3, 4, 7, 0, 0, 0}, + {1, 2, 3, 4, 7, 0, 0, 0}, {0, 1, 2, 3, 4, 7, 0, 0}, + {5, 7, 0, 0, 0, 0, 0, 0}, {0, 5, 7, 0, 0, 0, 0, 0}, + {1, 5, 7, 0, 0, 0, 0, 0}, {0, 1, 5, 7, 0, 0, 0, 0}, + {2, 5, 7, 0, 0, 0, 0, 0}, {0, 2, 5, 7, 0, 0, 0, 0}, + {1, 2, 5, 7, 0, 0, 0, 0}, {0, 1, 2, 5, 7, 0, 0, 0}, + {3, 5, 7, 0, 0, 0, 0, 0}, {0, 3, 5, 7, 0, 0, 0, 0}, + {1, 3, 5, 7, 0, 0, 0, 0}, {0, 1, 3, 5, 7, 0, 0, 0}, + {2, 3, 5, 7, 0, 0, 0, 0}, {0, 2, 3, 5, 7, 0, 0, 0}, + {1, 2, 3, 5, 7, 0, 0, 0}, {0, 1, 2, 3, 5, 7, 0, 0}, + {4, 5, 7, 0, 0, 0, 0, 0}, {0, 4, 5, 7, 0, 0, 0, 0}, + {1, 4, 5, 7, 0, 0, 0, 0}, {0, 1, 4, 5, 7, 0, 0, 0}, + {2, 4, 5, 7, 0, 0, 0, 0}, {0, 2, 4, 5, 7, 0, 0, 0}, + {1, 2, 4, 5, 7, 0, 0, 0}, {0, 1, 2, 4, 5, 7, 0, 0}, + {3, 4, 5, 7, 0, 0, 0, 0}, {0, 3, 4, 5, 7, 0, 0, 0}, + {1, 3, 4, 5, 7, 0, 0, 0}, {0, 1, 3, 4, 5, 7, 0, 0}, + {2, 3, 4, 5, 7, 0, 0, 0}, {0, 2, 3, 4, 5, 7, 0, 0}, + {1, 2, 3, 4, 5, 7, 0, 0}, {0, 1, 2, 3, 4, 5, 7, 0}, + {6, 7, 0, 0, 0, 0, 0, 0}, {0, 6, 7, 0, 0, 0, 0, 0}, + {1, 6, 7, 0, 0, 0, 0, 0}, {0, 1, 6, 7, 0, 0, 0, 0}, + {2, 6, 7, 0, 0, 0, 0, 0}, {0, 2, 6, 7, 0, 0, 0, 0}, + {1, 2, 6, 7, 0, 0, 0, 0}, {0, 1, 2, 6, 7, 0, 0, 0}, + {3, 6, 7, 0, 0, 0, 0, 0}, {0, 3, 6, 7, 0, 0, 0, 0}, + {1, 3, 6, 7, 0, 0, 0, 0}, {0, 1, 3, 6, 7, 0, 0, 0}, + {2, 3, 6, 7, 0, 0, 0, 0}, {0, 2, 3, 6, 7, 0, 0, 0}, + {1, 2, 3, 6, 7, 0, 0, 0}, {0, 1, 2, 3, 6, 7, 0, 0}, + {4, 6, 7, 0, 0, 0, 0, 0}, {0, 4, 6, 7, 0, 0, 0, 0}, + {1, 4, 6, 7, 0, 0, 0, 0}, {0, 1, 4, 6, 7, 0, 0, 0}, + {2, 4, 6, 7, 0, 0, 0, 0}, {0, 2, 4, 6, 7, 0, 0, 0}, + {1, 2, 4, 6, 7, 0, 0, 0}, {0, 1, 2, 4, 6, 7, 0, 0}, + {3, 4, 6, 7, 0, 0, 0, 0}, {0, 3, 4, 6, 7, 0, 0, 0}, + {1, 3, 4, 6, 7, 0, 0, 0}, {0, 1, 3, 4, 6, 7, 0, 0}, + {2, 3, 4, 6, 7, 0, 0, 0}, {0, 2, 3, 4, 6, 7, 0, 0}, + {1, 2, 3, 4, 6, 7, 0, 0}, {0, 1, 2, 3, 4, 6, 7, 0}, + {5, 6, 7, 0, 0, 0, 0, 0}, {0, 5, 6, 7, 0, 0, 0, 0}, + {1, 5, 6, 7, 0, 0, 0, 0}, {0, 1, 5, 6, 7, 0, 0, 0}, + {2, 5, 6, 7, 0, 0, 0, 0}, {0, 2, 5, 6, 7, 0, 0, 0}, + {1, 2, 5, 6, 7, 0, 0, 0}, {0, 1, 2, 5, 6, 7, 0, 0}, + {3, 5, 6, 7, 0, 0, 0, 0}, {0, 3, 5, 6, 7, 0, 0, 0}, + {1, 3, 5, 6, 7, 0, 0, 0}, {0, 1, 3, 5, 6, 7, 0, 0}, + {2, 3, 5, 6, 7, 0, 0, 0}, {0, 2, 3, 5, 6, 7, 0, 0}, + {1, 2, 3, 5, 6, 7, 0, 0}, {0, 1, 2, 3, 5, 6, 7, 0}, + {4, 5, 6, 7, 0, 0, 0, 0}, {0, 4, 5, 6, 7, 0, 0, 0}, + {1, 4, 5, 6, 7, 0, 0, 0}, {0, 1, 4, 5, 6, 7, 0, 0}, + {2, 4, 5, 6, 7, 0, 0, 0}, {0, 2, 4, 5, 6, 7, 0, 0}, + {1, 2, 4, 5, 6, 7, 0, 0}, {0, 1, 2, 4, 5, 6, 7, 0}, + {3, 4, 5, 6, 7, 0, 0, 0}, {0, 3, 4, 5, 6, 7, 0, 0}, + {1, 3, 4, 5, 6, 7, 0, 0}, {0, 1, 3, 4, 5, 6, 7, 0}, + {2, 3, 4, 5, 6, 7, 0, 0}, {0, 2, 3, 4, 5, 6, 7, 0}, + {1, 2, 3, 4, 5, 6, 7, 0}, {0, 1, 2, 3, 4, 5, 6, 7}, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/packing.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/packing.c new file mode 100644 index 0000000000..26da273856 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/packing.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include + +#include "common.h" +#include "packing.h" +#include "poly.h" +#include "polyvec.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_unpack_hints MLD_ADD_PARAM_SET(mld_unpack_hints) +/* End of parameter set namespacing */ + +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +{ + unsigned int i; + + mld_memcpy(pk, rho, MLDSA_SEEDBYTES); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt1_pack(pk + MLDSA_SEEDBYTES + i * MLDSA_POLYT1_PACKEDBYTES, + &t1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +{ + unsigned int i; + + mld_memcpy(rho, pk, MLDSA_SEEDBYTES); + pk += MLDSA_SEEDBYTES; + + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt1_unpack(&t1->vec[i], pk + i * MLDSA_POLYT1_PACKEDBYTES); + } +} + +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +{ + mld_memcpy(sk, rho, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, key, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, tr, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_pack_eta(sk, s1); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_eta(sk, s2); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_t0(sk, t0); +} + +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +{ + mld_memcpy(rho, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(key, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(tr, sk, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_unpack_eta(s1, sk); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_eta(s2, sk); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_t0(t0, sk); +} + +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +{ + unsigned int i, j, k; + + mld_memcpy(sig, c, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + /* skip z component - packed via mld_pack_sig_z */ + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + /* Encode hints h */ + + /* The final section of sig[] is MLDSA_POLYVECH_PACKEDBYTES long, where + * MLDSA_POLYVECH_PACKEDBYTES = MLDSA_OMEGA + MLDSA_K + * + * The first OMEGA bytes record the index numbers of the coefficients + * that are not equal to 0 + * + * The final K bytes record a running tally of the number of hints + * coming from each of the K polynomials in h. + * + * The pre-condition tells us that number_of_hints <= OMEGA, so some + * bytes may not be written, so we initialize all of them to zero + * to start. + */ + mld_memset(sig, 0, MLDSA_POLYVECH_PACKEDBYTES); + + k = 0; + /* For each polynomial in h... */ + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* For each coefficient in that polynomial, record it as as hint */ + /* if its value is not zero */ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + assigns(j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(j <= MLDSA_N) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* The reference implementation implicitly relies on the total */ + /* number of hints being less than OMEGA, assuming h is valid. */ + /* In mldsa-native, we check this explicitly to ease proof of */ + /* type safety. */ + if (h->vec[i].coeffs[j] != 0 && k < number_of_hints) + { + /* The enclosing if condition AND the loop invariant infer */ + /* that k < MLDSA_OMEGA, so writing to sig[k] is safe and k */ + /* can be incremented. */ + sig[k++] = (uint8_t)j; + } + } + /* Having recorded all the hints for this polynomial, also */ + /* record the running tally into the correct "slot" for that */ + /* coefficient in the final K bytes */ + sig[MLDSA_OMEGA + i] = (uint8_t)k; + } +} + +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +{ + sig += MLDSA_CTILDEBYTES; + sig += i * MLDSA_POLYZ_PACKEDBYTES; + mld_polyz_pack(sig, zi); +} + +/************************************************* + * Name: mld_unpack_hints + * + * Description: Unpack raw hint bytes into a polyveck + * struct + * + * Arguments: - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]: + * raw hint bytes + * + * Returns 1 in case of malformed hints; otherwise 0. + **************************************************/ +static int mld_unpack_hints( + mld_polyveck *h, const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(packed_hints, MLDSA_POLYVECH_PACKEDBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + /* All returned coefficients are either 0 or 1 */ + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +) +{ + unsigned int i, j; + unsigned int old_hint_count; + + /* Set all coefficients of all polynomials to 0. */ + /* Only those that are actually non-zero hints will */ + /* be overwritten below. */ + mld_memset(h, 0, sizeof(mld_polyveck)); + + old_hint_count = 0; + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + /* Grab the hint count for the i'th polynomial */ + const unsigned int new_hint_count = packed_hints[MLDSA_OMEGA + i]; + + /* new_hint_count must increase or stay the same, but also remain */ + /* less than or equal to MLDSA_OMEGA */ + if (new_hint_count < old_hint_count || new_hint_count > MLDSA_OMEGA) + { + /* Error - new_hint_count is invalid */ + return 1; + } + + /* If new_hint_count == old_hint_count, then this polynomial has */ + /* zero hints, so this loop executes zero times and we move */ + /* straight on to the next polynomial. */ + for (j = old_hint_count; j < new_hint_count; ++j) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + const uint8_t this_hint_index = packed_hints[j]; + + /* Coefficients must be ordered for strong unforgeability */ + if (j > old_hint_count && this_hint_index <= packed_hints[j - 1]) + { + return 1; + } + h->vec[i].coeffs[this_hint_index] = 1; + } + + old_hint_count = new_hint_count; + } + + /* Extra indices must be zero for strong unforgeability */ + for (j = old_hint_count; j < MLDSA_OMEGA; ++j) + __loop__( + invariant(j <= MLDSA_OMEGA) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + if (packed_hints[j] != 0) + { + return 1; + } + } + + return 0; +} + +MLD_INTERNAL_API +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +{ + mld_memcpy(c, sig, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + mld_polyvecl_unpack_z(z, sig); + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + return mld_unpack_hints(h, sig); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_unpack_hints diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/packing.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/packing.h new file mode 100644 index 0000000000..19095d08cd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/packing.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PACKING_H +#define MLD_PACKING_H + +#include +#include "polyvec.h" + +#define mld_pack_pk MLD_NAMESPACE_KL(pack_pk) +/************************************************* + * Name: mld_pack_pk + * + * Description: Bit-pack public key pk = (rho, t1). + * + * Arguments: - uint8_t pk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const mld_polyveck *t1: pointer to vector t1 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) +); + + +#define mld_pack_sk MLD_NAMESPACE_KL(pack_sk) +/************************************************* + * Name: mld_pack_sk + * + * Description: Bit-pack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - uint8_t sk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const uint8_t tr[]: byte array containing tr + * - const uint8_t key[]: byte array containing key + * - const mld_polyveck *t0: pointer to vector t0 + * - const mld_polyvecl *s1: pointer to vector s1 + * - const mld_polyveck *s2: pointer to vector s2 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +__contract__( + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + requires(forall(k2, 0, MLDSA_K, + array_abs_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) +); + + +#define mld_pack_sig_c_h MLD_NAMESPACE_KL(pack_sig_c_h) +/************************************************* + * Name: mld_pack_sig_c_h + * + * Description: Bit-pack c and h component of sig = (c, z, h). + * The z component is packed separately using mld_pack_sig_z. + * + * Arguments: - uint8_t sig[]: output byte array + * - const uint8_t *c: pointer to challenge hash length + * MLDSA_SEEDBYTES + * - const mld_polyveck *h: pointer to hint vector h + * - const unsigned int number_of_hints: total + * hints in *h + * + * Note that the number_of_hints argument is not present + * in the reference implementation. It is added here to ease + * proof of type safety. + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + requires(number_of_hints <= MLDSA_OMEGA) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_pack_sig_z MLD_NAMESPACE_KL(pack_sig_z) +/************************************************* + * Name: mld_pack_sig_z + * + * Description: Bit-pack single polynomial of z component of sig = (c, z, h). + * The c and h components are packed separately using + * mld_pack_sig_c_h. + * + * Arguments: - uint8_t sig[]: output byte array + * - const mld_poly *zi: pointer to a single polynomial in z + * - const unsigned int i: index of zi in vector z + * + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(zi, sizeof(mld_poly))) + requires(i < MLDSA_L) + requires(array_bound(zi->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_unpack_pk MLD_NAMESPACE_KL(unpack_pk) +/************************************************* + * Name: mld_unpack_pk + * + * Description: Unpack public key pk = (rho, t1). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const mld_polyveck *t1: pointer to output vector t1 + * - uint8_t pk[]: byte array containing bit-packed pk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) +); + + +#define mld_unpack_sk MLD_NAMESPACE_KL(unpack_sk) +/************************************************* + * Name: mld_unpack_sk + * + * Description: Unpack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const uint8_t tr[]: output byte array for tr + * - const uint8_t key[]: output byte array for key + * - const mld_polyveck *t0: pointer to output vector t0 + * - const mld_polyvecl *s1: pointer to output vector s1 + * - const mld_polyveck *s2: pointer to output vector s2 + * - uint8_t sk[]: byte array containing bit-packed sk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +__contract__( + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(key, MLDSA_SEEDBYTES)) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(s1, sizeof(mld_polyvecl))) + assigns(memory_slice(s2, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_unpack_sig MLD_NAMESPACE_KL(unpack_sig) +/************************************************* + * Name: mld_unpack_sig + * + * Description: Unpack signature sig = (c, z, h). + * + * Arguments: - uint8_t *c: pointer to output challenge hash + * - mld_polyvecl *z: pointer to output vector z + * - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t sig[]: byte array containing + * bit-packed signature + * + * Returns 1 in case of malformed signature; otherwise 0. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(c, MLDSA_CTILDEBYTES)) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(z->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +); +#endif /* !MLD_PACKING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/params.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/params.h new file mode 100644 index 0000000000..c67d2a33fb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/params.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PARAMS_H +#define MLD_PARAMS_H + +#define MLDSA_SEEDBYTES 32 +#define MLDSA_CRHBYTES 64 +#define MLDSA_TRBYTES 64 +#define MLDSA_RNDBYTES 32 +#define MLDSA_N 256 +#define MLDSA_Q 8380417 +#define MLDSA_Q_HALF ((MLDSA_Q + 1) / 2) +#define MLDSA_D 13 + +#if MLD_CONFIG_PARAMETER_SET == 44 + +#define MLDSA_K 4 +#define MLDSA_L 4 +#define MLDSA_ETA 2 +#define MLDSA_TAU 39 +#define MLDSA_BETA 78 +#define MLDSA_GAMMA1 (1 << 17) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 88) +#define MLDSA_OMEGA 80 +#define MLDSA_CTILDEBYTES 32 +#define MLDSA_POLYZ_PACKEDBYTES 576 +#define MLDSA_POLYW1_PACKEDBYTES 192 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#elif MLD_CONFIG_PARAMETER_SET == 65 + +#define MLDSA_K 6 +#define MLDSA_L 5 +#define MLDSA_ETA 4 +#define MLDSA_TAU 49 +#define MLDSA_BETA 196 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 55 +#define MLDSA_CTILDEBYTES 48 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 128 + +#elif MLD_CONFIG_PARAMETER_SET == 87 + +#define MLDSA_K 8 +#define MLDSA_L 7 +#define MLDSA_ETA 2 +#define MLDSA_TAU 60 +#define MLDSA_BETA 120 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 75 +#define MLDSA_CTILDEBYTES 64 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ + +#define MLDSA_POLYT1_PACKEDBYTES 320 +#define MLDSA_POLYT0_PACKEDBYTES 416 +#define MLDSA_POLYVECH_PACKEDBYTES (MLDSA_OMEGA + MLDSA_K) + +#define MLDSA_CRYPTO_PUBLICKEYBYTES \ + (MLDSA_SEEDBYTES + MLDSA_K * MLDSA_POLYT1_PACKEDBYTES) +#define MLDSA_CRYPTO_SECRETKEYBYTES \ + (2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + MLDSA_L * MLDSA_POLYETA_PACKEDBYTES + \ + MLDSA_K * MLDSA_POLYETA_PACKEDBYTES + MLDSA_K * MLDSA_POLYT0_PACKEDBYTES) +#define MLDSA_CRYPTO_BYTES \ + (MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES + \ + MLDSA_POLYVECH_PACKEDBYTES) + +#endif /* !MLD_PARAMS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/poly.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/poly.c new file mode 100644 index 0000000000..e40534e773 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/poly.c @@ -0,0 +1,973 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "common.h" +#include "ct.h" +#include "debug.h" +#include "poly.h" +#include "reduce.h" +#include "rounding.h" +#include "symmetric.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +#include "zetas.inc" + +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + { + a->coeffs[i] = mld_reduce32(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_STATIC_TESTABLE void mld_poly_caddq_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + ) + { + a->coeffs[i] = mld_caddq(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_POLY_CADDQ) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_poly_caddq_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + mld_poly_caddq_c(a); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1])) + invariant(forall(k2, 0, i, r->coeffs[k2] < MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k2, 0, i, r->coeffs[k2] >= INT32_MIN)) + ) + { + r->coeffs[i] = r->coeffs[i] + b->coeffs[i]; + } +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(r->coeffs, 0, i, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + ) + { + r->coeffs[i] = r->coeffs[i] - b->coeffs[i]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N; i++) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))) + { + /* Reference: uses a left shift by MLDSA_D which is undefined behaviour in + * C90/C99 + */ + a->coeffs[i] *= (1 << MLDSA_D); + } + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + + +static MLD_INLINE int32_t mld_fqmul(int32_t a, int32_t b) +__contract__( + requires(b > -MLDSA_Q_HALF && b < MLDSA_Q_HALF) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* Bounds: We argue in mld_montgomery_reduce() that the reult + * of Montgomery reduction is < MLDSA_Q if the input is smaller + * than 2^31 * MLDSA_Q in absolute value. Indeed, we have: + * + * |a * b| = |a| * |b| + * < 2^31 * MLDSA_Q_HALF + * < 2^31 * MLDSA_Q + */ + return mld_montgomery_reduce((int64_t)a * (int64_t)b); +} + +/* mld_ntt_butterfly_block() + * + * Computes a block CT butterflies with a fixed twiddle factor, + * using Montgomery multiplication. + * + * Parameters: + * - r: Pointer to base of polynomial (_not_ the base of butterfly block) + * - zeta: Twiddle factor to use for the butterfly. This must be in + * Montgomery form and signed canonical. + * - start: Offset to the beginning of the butterfly block + * - len: Index difference between coefficients subject to a butterfly + * - bound: Ghost variable describing coefficient bound: Prior to `start`, + * coefficients must be bound by `bound + MLDSA_Q`. Post `start`, + * they must be bound by `bound`. + * When this function returns, output coefficients in the index range + * [start, start+2*len) have bound bumped to `bound + MLDSA_Q`. + * Example: + * - start=8, len=4 + * This would compute the following four butterflies + * 8 -- 12 + * 9 -- 13 + * 10 -- 14 + * 11 -- 15 + * - start=4, len=2 + * This would compute the following two butterflies + * 4 -- 6 + * 5 -- 7 + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_butterfly_block(int32_t r[MLDSA_N], + const int32_t zeta, + const unsigned start, + const unsigned len, + const unsigned bound) +__contract__( + requires(start < MLDSA_N) + requires(1 <= len && len <= MLDSA_N / 2 && start + 2 * len <= MLDSA_N) + requires(0 <= bound && bound < INT32_MAX - MLDSA_Q) + requires(-MLDSA_Q_HALF < zeta && zeta < MLDSA_Q_HALF) + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, start, bound + MLDSA_Q)) + requires(array_abs_bound(r, start, MLDSA_N, bound)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, start + 2*len, bound + MLDSA_Q)) + ensures(array_abs_bound(r, start + 2 * len, MLDSA_N, bound))) +{ + /* `bound` is a ghost variable only needed in the CBMC specification */ + unsigned j; + ((void)bound); + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + /* + * Coefficients are updated in strided pairs, so the bounds for the + * intermediate states alternate twice between the old and new bound + */ + invariant(array_abs_bound(r, 0, j, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, bound)) + invariant(array_abs_bound(r, start + len, j + len, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j + len, MLDSA_N, bound))) + { + int32_t t; + t = mld_fqmul(r[j + len], zeta); + r[j + len] = r[j] - t; + r[j] = r[j] + t; + } +} + +/* mld_ntt_layer() + * + * Compute one layer of forward NTT + * + * Parameters: + * - r: Pointer to base of polynomial + * - layer: Indicates which layer is being applied. + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_layer(int32_t r[MLDSA_N], const unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (layer + 1) * MLDSA_Q))) +{ + unsigned start, k, len; + /* Twiddle factors for layer n are at indices 2^(n-1)..2^n-1. */ + k = 1u << (layer - 1); + len = (unsigned)MLDSA_N >> layer; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start < MLDSA_N + 2 * len) + invariant(k <= MLDSA_N) + invariant(2 * len * k == start + MLDSA_N) + invariant(array_abs_bound(r, 0, start, layer * MLDSA_Q + MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, layer * MLDSA_Q))) + { + int32_t zeta = mld_zetas[k++]; + mld_ntt_butterfly_block(r, zeta, start, len, layer * MLDSA_Q); + } +} + +MLD_STATIC_TESTABLE void mld_poly_ntt_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +) +{ + unsigned int layer; + int32_t *r; + + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + r = a->coeffs; + + for (layer = 1; layer < 9; layer++) + __loop__( + invariant(1 <= layer && layer <= 9) + invariant(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + ) + { + mld_ntt_layer(r, layer); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_NTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_ntt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_NTT */ + mld_poly_ntt_c(a); +} + +/************************************************* + * Name: mld_fqscale + * + * Description: Scales a field element by mont/256 , i.e., performs Montgomery + * multiplication by mont^2/256. + * Input is expected to have absolute value smaller than + * 256 * MLDSA_Q. + * Output has absolute value smaller than MLD_INTT_BOUND. + * + * Arguments: - int32_t a: Field element to be scaled. + **************************************************/ +static MLD_INLINE int32_t mld_fqscale(int32_t a) +__contract__( + requires(a > -256*MLDSA_Q && a < 256*MLDSA_Q) + ensures(return_value > -MLD_INTT_BOUND && return_value < MLD_INTT_BOUND) +) +{ + /* check-magic: 41978 == pow(2,64-8,MLDSA_Q) */ + const int32_t f = 41978; + /* Bounds: MLD_INTT_BOUND is MLDSA_Q, so the bounds reasoning is just + * a special case of that in mld_fqmul(). */ + return mld_montgomery_reduce((int64_t)a * f); +} + +/* Reference: Embedded into `invntt_tomont()` in the reference implementation + * @[REF] */ +static MLD_INLINE void mld_invntt_layer(int32_t r[MLDSA_N], unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> (layer - 1)) * MLDSA_Q))) +{ + unsigned start, k, len; + len = (unsigned)MLDSA_N >> layer; + k = (1u << layer) - 1; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start <= MLDSA_N && k <= 255) + invariant(2 * len * k + start == 2 * MLDSA_N - 2 * len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + unsigned j; + int32_t zeta = -mld_zetas[k--]; + + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, j, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, (MLDSA_N >> layer) * MLDSA_Q)) + invariant(array_abs_bound(r, start + len, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + int32_t t = r[j]; + r[j] = t + r[j + len]; + r[j + len] = t - r[j + len]; + r[j + len] = mld_fqmul(r[j + len], zeta); + } + } +} + +MLD_STATIC_TESTABLE void mld_poly_invntt_tomont_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +) +{ + unsigned int layer, j; + int32_t *r; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + r = a->coeffs; + for (layer = 8; layer >= 1; layer--) + __loop__( + invariant(layer <= 8) + /* Absolute bounds increase from 1Q before layer 8 */ + /* up to 256Q after layer 1 */ + invariant(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + mld_invntt_layer(r, layer); + } + + /* Coefficient bounds are now at 256Q. We now scale by mont / 256, + * i.e., compute the Montgomery multiplication by mont^2 / 256. + * mont corrects the mont^-1 factor introduced in the basemul. + * 1/256 performs that scaling of the inverse NTT. + * The reduced value is bounded by MLD_INTT_BOUND in absolute + * value.*/ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + invariant(j <= MLDSA_N) + invariant(array_abs_bound(r, 0, j, MLD_INTT_BOUND)) + invariant(array_abs_bound(r, j, MLDSA_N, MLDSA_N * MLDSA_Q)) + ) + { + r[j] = mld_fqscale(r[j]); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); +} + + +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_INTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_intt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_INTT */ + mld_poly_invntt_tomont_c(a); +} + +MLD_STATIC_TESTABLE void mld_poly_pointwise_montgomery_c(mld_poly *c, + const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_abs_bound(c->coeffs, 0, i, MLDSA_Q)) + ) + { + c->coeffs[i] = mld_montgomery_reduce((int64_t)a->coeffs[i] * b->coeffs[i]); + } + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +{ +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + ret = mld_poly_pointwise_montgomery_native(c->coeffs, a->coeffs, b->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + mld_poly_pointwise_montgomery_c(c, a, b); +} + +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, 0, i, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + invariant(array_bound(a1->coeffs, 0, i, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) + ) + { + mld_power2round(&a0->coeffs[i], &a1->coeffs[i], a->coeffs[i]); + } + + mld_assert_bound(a0->coeffs, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +#ifndef MLD_POLY_UNIFORM_NBLOCKS +#define MLD_POLY_UNIFORM_NBLOCKS \ + ((768 + MLD_STREAM128_BLOCKBYTES - 1) / MLD_STREAM128_BLOCKBYTES) +#endif +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +MLD_STATIC_TESTABLE unsigned int mld_rej_uniform_c(int32_t *a, + unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ + unsigned int ctr, pos; + uint32_t t; + mld_assert_bound(a, offset, 0, MLDSA_Q); + + ctr = offset; + pos = 0; + /* pos + 3 cannot overflow due to the assumption + buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) */ + while (ctr < target && pos + 3 <= buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_bound(a, 0, ctr, 0, MLDSA_Q))) + { + t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + a[ctr++] = (int32_t)t; + } + } + + mld_assert_bound(a, ctr, 0, MLDSA_Q); + + return ctr; +} +/************************************************* + * Name: mld_rej_uniform + * + * Description: Sample uniformly random coefficients in [0, MLDSA_Q-1] by + * performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes (must be + * multiple of 3) + * + * Returns number of sampled coefficients. Can be smaller than len if not enough + * random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +static unsigned int mld_rej_uniform(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) + int ret; + mld_assert_bound(a, offset, 0, MLDSA_Q); + if (offset == 0) + { + ret = mld_rej_uniform_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_bound(a, res, 0, MLDSA_Q); + return res; + } + } +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + + return mld_rej_uniform_c(a, target, offset, buf, buflen); +} + +/* Reference: poly_uniform() in the reference implementation @[REF]. + * - Simplified from reference by removing buffer tail handling + * since buflen % 3 = 0 always holds true (MLD_STREAM128_BLOCKBYTES + * = 168). + * - Modified rej_uniform interface to track offset directly. + * - Pass nonce packed in the extended seed array instead of a third + * argument. + * */ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +{ + unsigned int ctr; + unsigned int buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + MLD_ALIGN uint8_t buf[MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES]; + mld_xof128_ctx state; + + mld_xof128_init(&state); + mld_xof128_absorb_once(&state, seed, MLDSA_SEEDBYTES + 2); + mld_xof128_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, 0, buf, buflen); + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(a, sizeof(mld_poly)), object_whole(buf)) + invariant(ctr <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, ctr, 0, MLDSA_Q)) + invariant(state.pos <= SHAKE128_RATE) + ) + { + mld_xof128_squeezeblocks(buf, 1, &state); + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, ctr, buf, buflen); + } + mld_xof128_release(&state); + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof128_x4_ctx state; + unsigned buflen; + + mld_xof128_x4_init(&state); + mld_xof128_x4_absorb(&state, seed, MLDSA_SEEDBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_NBLOCKS. + * This should generate the matrix entries with high probability. + */ + + mld_xof128_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all matrix entries have been generated, squeeze + * one more block a time until we're done. + */ + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, object_whole(buf), + memory_slice(vec0, sizeof(mld_poly)), memory_slice(vec1, sizeof(mld_poly)), + memory_slice(vec2, sizeof(mld_poly)), memory_slice(vec3, sizeof(mld_poly))) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_bound(vec0->coeffs, 0, ctr[0], 0, MLDSA_Q)) + invariant(array_bound(vec1->coeffs, 0, ctr[1], 0, MLDSA_Q)) + invariant(array_bound(vec2->coeffs, 0, ctr[2], 0, MLDSA_Q)) + invariant(array_bound(vec3->coeffs, 0, ctr[3], 0, MLDSA_Q))) + { + mld_xof128_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + mld_xof128_x4_release(&state); + + mld_assert_bound(vec0->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec1->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec2->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec3->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0) & 0xFF); + r[5 * i + 1] = + (uint8_t)(((a->coeffs[4 * i + 0] >> 8) | (a->coeffs[4 * i + 1] << 2)) & + 0xFF); + r[5 * i + 2] = + (uint8_t)(((a->coeffs[4 * i + 1] >> 6) | (a->coeffs[4 * i + 2] << 4)) & + 0xFF); + r[5 * i + 3] = + (uint8_t)(((a->coeffs[4 * i + 2] >> 4) | (a->coeffs[4 * i + 3] << 6)) & + 0xFF); + r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, 0, 1 << 10))) + { + r->coeffs[4 * i + 0] = + ((a[5 * i + 0] >> 0) | ((int32_t)a[5 * i + 1] << 8)) & 0x3FF; + r->coeffs[4 * i + 1] = + ((a[5 * i + 1] >> 2) | ((int32_t)a[5 * i + 2] << 6)) & 0x3FF; + r->coeffs[4 * i + 2] = + ((a[5 * i + 2] >> 4) | ((int32_t)a[5 * i + 3] << 4)) & 0x3FF; + r->coeffs[4 * i + 3] = + ((a[5 * i + 3] >> 6) | ((int32_t)a[5 * i + 4] << 2)) & 0x3FF; + } + + mld_assert_bound(r->coeffs, MLDSA_N, 0, 1 << 10); +} + +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[8]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* Safety: a->coeffs[i] <= (1 << (MLDSA_D - 1) as they are output of + * power2round, hence, these casts are safe. */ + t[0] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 0]); + t[1] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 1]); + t[2] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 2]); + t[3] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 3]); + t[4] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 4]); + t[5] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 5]); + t[6] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 6]); + t[7] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 7]); + + r[13 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[13 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[13 * i + 1] |= (uint8_t)((t[1] << 5) & 0xFF); + r[13 * i + 2] = (uint8_t)((t[1] >> 3) & 0xFF); + r[13 * i + 3] = (uint8_t)((t[1] >> 11) & 0xFF); + r[13 * i + 3] |= (uint8_t)((t[2] << 2) & 0xFF); + r[13 * i + 4] = (uint8_t)((t[2] >> 6) & 0xFF); + r[13 * i + 4] |= (uint8_t)((t[3] << 7) & 0xFF); + r[13 * i + 5] = (uint8_t)((t[3] >> 1) & 0xFF); + r[13 * i + 6] = (uint8_t)((t[3] >> 9) & 0xFF); + r[13 * i + 6] |= (uint8_t)((t[4] << 4) & 0xFF); + r[13 * i + 7] = (uint8_t)((t[4] >> 4) & 0xFF); + r[13 * i + 8] = (uint8_t)((t[4] >> 12) & 0xFF); + r[13 * i + 8] |= (uint8_t)((t[5] << 1) & 0xFF); + r[13 * i + 9] = (uint8_t)((t[5] >> 7) & 0xFF); + r[13 * i + 9] |= (uint8_t)((t[6] << 6) & 0xFF); + r[13 * i + 10] = (uint8_t)((t[6] >> 2) & 0xFF); + r[13 * i + 11] = (uint8_t)((t[6] >> 10) & 0xFF); + r[13 * i + 11] |= (uint8_t)((t[7] << 3) & 0xFF); + r[13 * i + 12] = (uint8_t)((t[7] >> 5) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + { + r->coeffs[8 * i + 0] = a[13 * i + 0]; + r->coeffs[8 * i + 0] |= (int32_t)a[13 * i + 1] << 8; + r->coeffs[8 * i + 0] &= 0x1FFF; + + r->coeffs[8 * i + 1] = a[13 * i + 1] >> 5; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 2] << 3; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 3] << 11; + r->coeffs[8 * i + 1] &= 0x1FFF; + + r->coeffs[8 * i + 2] = a[13 * i + 3] >> 2; + r->coeffs[8 * i + 2] |= (int32_t)a[13 * i + 4] << 6; + r->coeffs[8 * i + 2] &= 0x1FFF; + + r->coeffs[8 * i + 3] = a[13 * i + 4] >> 7; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 5] << 1; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 6] << 9; + r->coeffs[8 * i + 3] &= 0x1FFF; + + r->coeffs[8 * i + 4] = a[13 * i + 6] >> 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 7] << 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 8] << 12; + r->coeffs[8 * i + 4] &= 0x1FFF; + + r->coeffs[8 * i + 5] = a[13 * i + 8] >> 1; + r->coeffs[8 * i + 5] |= (int32_t)a[13 * i + 9] << 7; + r->coeffs[8 * i + 5] &= 0x1FFF; + + r->coeffs[8 * i + 6] = a[13 * i + 9] >> 6; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 10] << 2; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 11] << 10; + r->coeffs[8 * i + 6] &= 0x1FFF; + + r->coeffs[8 * i + 7] = a[13 * i + 11] >> 3; + r->coeffs[8 * i + 7] |= (int32_t)a[13 * i + 12] << 5; + r->coeffs[8 * i + 7] &= 0x1FFF; + + r->coeffs[8 * i + 0] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 7]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +MLD_STATIC_TESTABLE uint32_t mld_poly_chknorm_c(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == array_abs_bound(a->coeffs, 0, i, B)) + ) + { + /* + * Since we know that -MLD_REDUCE32_RANGE_MAX <= a < MLD_REDUCE32_RANGE_MAX, + * and B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX, to check if + * -B < (a mod± MLDSA_Q) < B, it suffices to check if -B < a < B. + * + * We prove this to be true using the following CBMC assertions. + * a ==> b expressed as !a || b to also allow run-time assertion. + */ + mld_assert(a->coeffs[i] < B || a->coeffs[i] - MLDSA_Q <= -B); + mld_assert(a->coeffs[i] > -B || a->coeffs[i] + MLDSA_Q >= B); + + /* Reference: Leaks which coefficient violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + + /* if (abs(a[i]) >= B) */ + t |= mld_ct_cmask_neg_i32(B - 1 - mld_ct_abs_i32(a->coeffs[i])); + } + + return t; +} + +/* Reference: explicitly checks the bound B to be <= (MLDSA_Q - 1) / 8). + * This is unnecessary as it's always a compile-time constant. + * We instead model it as a precondition. + * Checking the bound is performed using a conditional arguing + * that it is okay to leak which coefficient violates the bound (while the + * coefficient itself must remain secret). + * We instead perform everything in constant-time. + * Also it is sufficient to check that it is smaller than + * MLDSA_Q - MLD_REDUCE32_RANGE_MAX > (MLDSA_Q - 1) / 8). + */ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +{ +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) + int ret; + int success; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + /* The native backend returns 0 if all coefficients are within the bound, + * 1 if at least one coefficient exceeds the bound, and + * -1 (MLD_NATIVE_FUNC_FALLBACK) if the platform does not have the + * required capabilities to run the native function. + */ + ret = mld_poly_chknorm_native(a->coeffs, B); + + success = (ret != MLD_NATIVE_FUNC_FALLBACK); + /* Constant-time: It would be fine to leak the return value of chknorm + * entirely (as it is fine to leak if any coefficient exceeded the bound or + * not). However, it is cleaner to perform declassification in sign.c. + * Hence, here we only declassify if the native function returned + * MLD_NATIVE_FUNC_FALLBACK or not (which solely depends on system + * capabilities). + */ + MLD_CT_TESTING_DECLASSIFY(&success, sizeof(int)); + if (success) + { + /* Convert 0 / 1 to 0 / 0xFFFFFFFF here */ + return 0U - (uint32_t)ret; + } +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + return mld_poly_chknorm_c(a, B); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ +MLD_EMPTY_CU(mld_poly) +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_POLY_UNIFORM_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/poly.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/poly.h new file mode 100644 index 0000000000..ff7710438e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/poly.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_H +#define MLD_POLY_H + +#include +#include "cbmc.h" +#include "common.h" +#include "reduce.h" +#include "rounding.h" + +/* Absolute exclusive upper bound for the output of the forward NTT */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) +/* Absolute exclusive upper bound for the output of the inverse NTT*/ +#define MLD_INTT_BOUND MLDSA_Q + +typedef struct +{ + int32_t coeffs[MLDSA_N]; +} MLD_ALIGN mld_poly; + +#define mld_poly_reduce MLD_NAMESPACE(poly_reduce) +/************************************************* + * Name: mld_poly_reduce + * + * Description: Inplace reduction of all coefficients of polynomial to + * representative in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) +); + +#define mld_poly_caddq MLD_NAMESPACE(poly_caddq) +/************************************************* + * Name: mld_poly_caddq + * + * Description: For all coefficients of in/out polynomial add MLDSA_Q if + * coefficient is negative. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_add MLD_NAMESPACE(poly_add) +/************************************************* + * Name: mld_poly_add + * + * Description: Add polynomials. No modular reduction is performed. + * + * Arguments: - r: Pointer to input-output polynomial to be added to. + * - b: Pointer to input polynomial that should be added + * to r. Must be disjoint from r. + **************************************************/ + +/* + * NOTE: The reference implementation uses a 3-argument poly_add. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(forall(k0, 0, MLDSA_N, (int64_t) r->coeffs[k0] + b->coeffs[k0] < MLD_REDUCE32_DOMAIN_MAX)) + requires(forall(k1, 0, MLDSA_N, (int64_t) r->coeffs[k1] + b->coeffs[k1] >= INT32_MIN)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(forall(k2, 0, MLDSA_N, r->coeffs[k2] == old(*r).coeffs[k2] + b->coeffs[k2])) + ensures(forall(k3, 0, MLDSA_N, r->coeffs[k3] < MLD_REDUCE32_DOMAIN_MAX)) + ensures(forall(k4, 0, MLDSA_N, r->coeffs[k4] >= INT32_MIN)) +); + +#define mld_poly_sub MLD_NAMESPACE(poly_sub) +/************************************************* + * Name: mld_poly_sub + * + * Description: Subtract polynomials. No modular reduction is + * performed. + * + * Arguments: - mld_poly *r: Pointer to input-output polynomial. + * - const mld_poly *b: Pointer to input polynomial that should be + * subtracted from r. Must be disjoint from r. + **************************************************/ +/* + * NOTE: The reference implementation uses a 3-argument poly_sub. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_Q)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) +); + +#define mld_poly_shiftl MLD_NAMESPACE(poly_shiftl) +/************************************************* + * Name: mld_poly_shiftl + * + * Description: Multiply polynomial by 2^MLDSA_D without modular reduction. + *Assumes input coefficients to be less than 2^{31-MLDSA_D} in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_ntt MLD_NAMESPACE(poly_ntt) +/************************************************* + * Name: mld_poly_ntt + * + * Description: Inplace forward NTT. Coefficients can grow by + * 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +); + + +#define mld_poly_invntt_tomont MLD_NAMESPACE(poly_invntt_tomont) +/************************************************* + * Name: mld_poly_invntt_tomont + * + * Description: Inplace inverse NTT and multiplication by 2^{32}. + * Input coefficients need to be less than MLDSA_Q in absolute + * value and output coefficients are bounded by + * MLD_INTT_BOUND. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +); + +#define mld_poly_pointwise_montgomery MLD_NAMESPACE(poly_pointwise_montgomery) +/************************************************* + * Name: mld_poly_pointwise_montgomery + * + * Description: Pointwise multiplication of polynomials in NTT domain + * representation and multiplication of resulting polynomial + * by 2^{-32}. + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const mld_poly *a: pointer to first input polynomial + * - const mld_poly *b: pointer to second input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + +#define mld_poly_power2round MLD_NAMESPACE(poly_power2round) +/************************************************* + * Name: mld_poly_power2round + * + * Description: For all coefficients c of the input polynomial, + * compute c0, c1 such that c mod MLDSA_Q = c1*2^MLDSA_D + c0 + * with -2^{MLDSA_D-1} < c0 <= 2^{MLDSA_D-1}. Assumes coefficients + *to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + *c1 + * - mld_poly *a0: pointer to output polynomial with coefficients + *c0 + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +__contract__( + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a0->coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) +); + +#define mld_poly_uniform MLD_NAMESPACE(poly_uniform) +/************************************************* + * Name: mld_poly_uniform + * + * Description: Sample polynomial with uniformly random coefficients + * in [0,MLDSA_Q-1] by performing rejection sampling on the + * output stream of SHAKE128(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_SEEDBYTES and the packed 2-byte nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES + 2)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +#define mld_poly_uniform_4x MLD_NAMESPACE(poly_uniform_4x) +/************************************************* + * Name: mld_poly_uniform_x4 + * + * Description: Generate four polynomials using rejection sampling + * on (pseudo-)uniformly random bytes sampled from a seed. + * + * Arguments: - mld_poly *vec0, *vec1, *vec2, *vec3: + * Pointers to 4 polynomials to be sampled. + * - uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]: + * Pointer consecutive array of seed buffers of size + * MLDSA_SEEDBYTES + 2 each, plus padding for alignment. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +__contract__( + requires(memory_no_alias(vec0, sizeof(mld_poly))) + requires(memory_no_alias(vec1, sizeof(mld_poly))) + requires(memory_no_alias(vec2, sizeof(mld_poly))) + requires(memory_no_alias(vec3, sizeof(mld_poly))) + requires(memory_no_alias(seed, 4 * MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2))) + assigns(memory_slice(vec0, sizeof(mld_poly))) + assigns(memory_slice(vec1, sizeof(mld_poly))) + assigns(memory_slice(vec2, sizeof(mld_poly))) + assigns(memory_slice(vec3, sizeof(mld_poly))) + ensures(array_bound(vec0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec1->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec2->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec3->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +#define mld_polyt1_pack MLD_NAMESPACE(polyt1_pack) +/************************************************* + * Name: mld_polyt1_pack + * + * Description: Bit-pack polynomial t1 with coefficients fitting in 10 bits. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(r, MLDSA_POLYT1_PACKEDBYTES)) +); + +#define mld_polyt1_unpack MLD_NAMESPACE(polyt1_unpack) +/************************************************* + * Name: mld_polyt1_unpack + * + * Description: Unpack polynomial t1 with 10-bit coefficients. + * Output coefficients are standard representatives. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT1_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, 0, 1 << 10)) +); + +#define mld_polyt0_pack MLD_NAMESPACE(polyt0_pack) +/************************************************* + * Name: mld_polyt0_pack + * + * Description: Bit-pack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + * 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) + assigns(memory_slice(r, MLDSA_POLYT0_PACKEDBYTES)) +); + + +#define mld_polyt0_unpack MLD_NAMESPACE(polyt0_unpack) +/************************************************* + * Name: mld_polyt0_unpack + * + * Description: Unpack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + *2^{MLDSA_D-1}]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT0_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) +); + +#define mld_poly_chknorm MLD_NAMESPACE(poly_chknorm) +/************************************************* + * Name: mld_poly_chknorm + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const mld_poly *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if norm is strictly smaller than + * B <= (MLDSA_Q - MLD_REDUCE32_RANGE_MAX) and 0xFFFFFFFF otherwise. + * + * Specification: The definition of this FIPS-204 requires signed canonical + * reduction prior to applying the bounds check. + * However, `-B < (a mod± MLDSA_Q) < B` is equivalent to + * `-B < a < B` under the assumption that + * `B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX` (cf. the assertion in + * the code). Hence, the present spec and implementation are + * correct without reduction. + * + **************************************************/ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +); + +#endif /* !MLD_POLY_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/poly_kl.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/poly_kl.c new file mode 100644 index 0000000000..7a319ca515 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/poly_kl.c @@ -0,0 +1,931 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "ct.h" +#include "debug.h" +#include "poly_kl.h" +#include "rounding.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_rej_eta MLD_ADD_PARAM_SET(mld_rej_eta) +#define mld_rej_eta_c MLD_ADD_PARAM_SET(mld_rej_eta_c) +#define mld_poly_decompose_c MLD_ADD_PARAM_SET(mld_poly_decompose_c) +#define mld_poly_use_hint_c MLD_ADD_PARAM_SET(mld_poly_use_hint_c) +#define mld_polyz_unpack_c MLD_ADD_PARAM_SET(mld_polyz_unpack_c) +/* End of parameter set namespacing */ + + +MLD_STATIC_TESTABLE +void mld_poly_decompose_c(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +) +{ + unsigned int i; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, i, MLDSA_N, 0, MLDSA_Q)) + invariant(array_bound(a1->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + invariant(array_abs_bound(a0->coeffs, 0, i, MLDSA_GAMMA2+1)) + ) + { + mld_decompose(&a0->coeffs[i], &a1->coeffs[i], a0->coeffs[i]); + } + + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +{ +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_88_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_32_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_DECOMPOSE_88 && MLD_CONFIG_PARAMETER_SET == \ + 44) && MLD_USE_NATIVE_POLY_DECOMPOSE_32 && (MLD_CONFIG_PARAMETER_SET \ + == 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_decompose_c(a1, a0); +} + +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(s <= i) + invariant(array_bound(h->coeffs, 0, i, 0, 2)) + ) + { + const unsigned int hint_bit = mld_make_hint(a0->coeffs[i], a1->coeffs[i]); + h->coeffs[i] = (int32_t)hint_bit; + s += hint_bit; + } + + mld_assert(s <= MLDSA_N); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + return s; +} + +MLD_STATIC_TESTABLE void mld_poly_use_hint_c(mld_poly *b, const mld_poly *a, + const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(b->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ) + { + b->coeffs[i] = mld_use_hint(a->coeffs[i], h->coeffs[i]); + } + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +{ +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_88_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_USE_HINT_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_32_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_USE_HINT_88 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLY_USE_HINT_32 && (MLD_CONFIG_PARAMETER_SET == \ + 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_use_hint_c(b, a, h); +} + +/************************************************* + * Name: mld_rej_eta + * + * Description: Sample uniformly random coefficients in [-MLDSA_ETA, MLDSA_ETA] + *by performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes + * + * Returns number of sampled coefficients. Can be smaller than target if not + *enough random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_eta()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +#if MLDSA_ETA == 2 +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 1 +#elif MLDSA_ETA == 4 +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 2 +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + +MLD_STATIC_TESTABLE unsigned int mld_rej_eta_c(int32_t *a, unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ + unsigned int ctr, pos; + int t_valid; + uint32_t t0, t1; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + ctr = offset; + pos = 0; + while (ctr < target && pos < buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_abs_bound(a, 0, ctr, MLDSA_ETA + 1)) + ) + { + t0 = buf[pos] & 0x0F; + t1 = buf[pos++] >> 4; + + /* Constant time: The inputs and outputs to the rejection sampling are + * secret. However, it is fine to leak which coefficients have been + * rejected. For constant-time testing, we declassify the result of + * the comparison. + */ +#if MLDSA_ETA == 2 + t_valid = t0 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 15 */ + { + t0 = t0 - (205 * t0 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t0; + } + t_valid = t1 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) /* t1 < 15 */ + { + t1 = t1 - (205 * t1 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t1; + } +#elif MLDSA_ETA == 4 + t_valid = t0 < 9; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 9 */ + { + a[ctr++] = 4 - (int32_t)t0; + } + t_valid = t1 < 9; /* t1 < 9 */ + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) + { + a[ctr++] = 4 - (int32_t)t1; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + } + + mld_assert_abs_bound(a, ctr, MLDSA_ETA + 1); + + return ctr; +} + +static unsigned int mld_rej_eta(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ +#if MLDSA_ETA == 2 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta2_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#elif MLDSA_ETA == 4 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta4_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#endif /* !(MLDSA_ETA == 2 && MLD_USE_NATIVE_REJ_UNIFORM_ETA2) && MLDSA_ETA == \ + 4 && MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + + return mld_rej_eta_c(a, target, offset, buf, buflen); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_ETA_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof256_x4_ctx state; + unsigned buflen; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = nonce0; + extseed[1][MLDSA_CRHBYTES] = nonce1; + extseed[2][MLDSA_CRHBYTES] = nonce2; + extseed[3][MLDSA_CRHBYTES] = nonce3; + extseed[0][MLDSA_CRHBYTES + 1] = 0; + extseed[1][MLDSA_CRHBYTES + 1] = 0; + extseed[2][MLDSA_CRHBYTES + 1] = 0; + extseed[3][MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(r0, sizeof(mld_poly)), + memory_slice(r1, sizeof(mld_poly)), memory_slice(r2, sizeof(mld_poly)), + memory_slice(r3, sizeof(mld_poly)), object_whole(buf[0]), + object_whole(buf[1]), object_whole(buf[2]), + object_whole(buf[3])) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_abs_bound(r0->coeffs, 0, ctr[0], MLDSA_ETA + 1)) + invariant(array_abs_bound(r1->coeffs, 0, ctr[1], MLDSA_ETA + 1)) + invariant(array_abs_bound(r2->coeffs, 0, ctr[2], MLDSA_ETA + 1)) + invariant(array_abs_bound(r3->coeffs, 0, ctr[3], MLDSA_ETA + 1))) + { + mld_xof256_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + + mld_xof256_x4_release(&state); + + mld_assert_abs_bound(r0->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r1->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r2->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r3->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +{ + /* Temporary buffer for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr; + mld_xof256_ctx state; + unsigned buflen; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = nonce; + extseed[MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr = mld_rej_eta(r->coeffs, MLDSA_N, 0, buf, buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, object_whole(&state), + object_whole(buf), memory_slice(r, sizeof(mld_poly))) + invariant(ctr <= MLDSA_N) + invariant(state.pos <= SHAKE256_RATE) + invariant(array_abs_bound(r->coeffs, 0, ctr, MLDSA_ETA + 1))) + { + mld_xof256_squeezeblocks(buf, 1, &state); + ctr = mld_rej_eta(r->coeffs, MLDSA_N, ctr, buf, buflen); + } + + mld_xof256_release(&state); + + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define MLD_POLY_UNIFORM_GAMMA1_NBLOCKS \ + ((MLDSA_POLYZ_PACKEDBYTES + MLD_STREAM256_BLOCKBYTES - 1) / \ + MLD_STREAM256_BLOCKBYTES) + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + mld_xof256_ctx state; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = (uint8_t)(nonce & 0xFF); + extseed[MLDSA_CRHBYTES + 1] = (uint8_t)(nonce >> 8); + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + mld_polyz_unpack(a, buf); + + mld_xof256_release(&state); + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + mld_xof256_x4_ctx state; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = (uint8_t)(nonce0 & 0xFF); + extseed[1][MLDSA_CRHBYTES] = (uint8_t)(nonce1 & 0xFF); + extseed[2][MLDSA_CRHBYTES] = (uint8_t)(nonce2 & 0xFF); + extseed[3][MLDSA_CRHBYTES] = (uint8_t)(nonce3 & 0xFF); + extseed[0][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce0 >> 8); + extseed[1][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce1 >> 8); + extseed[2][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce2 >> 8); + extseed[3][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce3 >> 8); + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + + mld_polyz_unpack(r0, buf[0]); + mld_polyz_unpack(r1, buf[1]); + mld_polyz_unpack(r2, buf[2]); + mld_polyz_unpack(r3, buf[3]); + mld_xof256_x4_release(&state); + + mld_assert_bound(r0->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r1->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r2->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r3->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +{ + unsigned int i, j, pos; + uint64_t signs; + uint64_t offset; + MLD_ALIGN uint8_t buf[SHAKE256_RATE]; + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, seed, MLDSA_CTILDEBYTES); + mld_shake256_finalize(&state); + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + + /* Convert the first 8 bytes of buf[] into an unsigned 64-bit value. */ + /* Each bit of that dictates the sign of the resulting challenge value */ + signs = 0; + for (i = 0; i < 8; ++i) + __loop__( + assigns(i, signs) + invariant(i <= 8) + ) + { + signs |= (uint64_t)buf[i] << 8 * i; + } + pos = 8; + + mld_memset(c, 0, sizeof(mld_poly)); + + for (i = MLDSA_N - MLDSA_TAU; i < MLDSA_N; ++i) + __loop__( + assigns(i, j, object_whole(buf), state, pos, memory_slice(c, sizeof(mld_poly)), signs) + invariant(i >= MLDSA_N - MLDSA_TAU) + invariant(i <= MLDSA_N) + invariant(pos >= 1) + invariant(pos <= SHAKE256_RATE) + invariant(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) + invariant(state.pos <= SHAKE256_RATE) + ) + { + do + __loop__( + assigns(j, object_whole(buf), state, pos) + invariant(state.pos <= SHAKE256_RATE) + ) + { + if (pos >= SHAKE256_RATE) + { + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + pos = 0; + } + j = buf[pos++]; + } while (j > i); + + c->coeffs[i] = c->coeffs[j]; + + /* Reference: Compute coefficent value here in two steps to */ + /* mixinf unsigned and signed arithmetic with implicit */ + /* conversions, and so that CBMC can keep track of ranges */ + /* to complete type-safety proof here. */ + + /* The least-significant bit of signs tells us if we want -1 or +1 */ + offset = 2 * (signs & 1); + + /* offset has value 0 or 2 here, so (1 - (int32_t) offset) has + * value -1 or +1 */ + c->coeffs[j] = 1 - (int32_t)offset; + + /* Move to the next bit of signs for next time */ + signs >>= 1; + } + + mld_assert_bound(c->coeffs, MLDSA_N, -1, 2); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(&signs, sizeof(signs)); +} + +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint8_t t[8]; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_ETA + 1); + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 1]); + t[2] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 2]); + t[3] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 3]); + t[4] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 4]); + t[5] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 5]); + t[6] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 6]); + t[7] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 7]); + + r[3 * i + 0] = (uint8_t)(((t[0] >> 0) | (t[1] << 3) | (t[2] << 6)) & 0xFF); + r[3 * i + 1] = + (uint8_t)(((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)) & + 0xFF); + r[3 * i + 2] = (uint8_t)(((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)) & 0xFF); + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 1]); + r[i] = (uint8_t)(t[0] | (t[1] << 4)); + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ +} + +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -5, MLDSA_ETA + 1))) + { + r->coeffs[8 * i + 0] = (a[3 * i + 0] >> 0) & 7; + r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 7; + r->coeffs[8 * i + 2] = ((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 7; + r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 7; + r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 7; + r->coeffs[8 * i + 5] = ((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 7; + r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 7; + r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5) & 7; + + r->coeffs[8 * i + 0] = MLDSA_ETA - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = MLDSA_ETA - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = MLDSA_ETA - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = MLDSA_ETA - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = MLDSA_ETA - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = MLDSA_ETA - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = MLDSA_ETA - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = MLDSA_ETA - r->coeffs[8 * i + 7]; + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -11, MLDSA_ETA + 1))) + { + r->coeffs[2 * i + 0] = a[i] & 0x0F; + r->coeffs[2 * i + 1] = a[i] >> 4; + r->coeffs[2 * i + 0] = MLDSA_ETA - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_ETA - r->coeffs[2 * i + 1]; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + + mld_assert_bound(r->coeffs, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + + +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[4]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 1]); + t[2] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 2]); + t[3] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 3]); + + r[9 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[9 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[9 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[9 * i + 2] |= (uint8_t)((t[1] << 2) & 0xFF); + r[9 * i + 3] = (uint8_t)((t[1] >> 6) & 0xFF); + r[9 * i + 4] = (uint8_t)((t[1] >> 14) & 0xFF); + r[9 * i + 4] |= (uint8_t)((t[2] << 4) & 0xFF); + r[9 * i + 5] = (uint8_t)((t[2] >> 4) & 0xFF); + r[9 * i + 6] = (uint8_t)((t[2] >> 12) & 0xFF); + r[9 * i + 6] |= (uint8_t)((t[3] << 6) & 0xFF); + r[9 * i + 7] = (uint8_t)((t[3] >> 2) & 0xFF); + r[9 * i + 8] = (uint8_t)((t[3] >> 10) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 1]); + + r[5 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[5 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[5 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[5 * i + 2] |= (uint8_t)((t[1] << 4) & 0xFF); + r[5 * i + 3] = (uint8_t)((t[1] >> 4) & 0xFF); + r[5 * i + 4] = (uint8_t)((t[1] >> 12) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +MLD_STATIC_TESTABLE void mld_polyz_unpack_c( + mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +) +{ + unsigned int i; +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[4 * i + 0] = a[9 * i + 0]; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 2] << 16; + r->coeffs[4 * i + 0] &= 0x3FFFF; + + r->coeffs[4 * i + 1] = a[9 * i + 2] >> 2; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 3] << 6; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 4] << 14; + r->coeffs[4 * i + 1] &= 0x3FFFF; + + r->coeffs[4 * i + 2] = a[9 * i + 4] >> 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 5] << 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 6] << 12; + r->coeffs[4 * i + 2] &= 0x3FFFF; + + r->coeffs[4 * i + 3] = a[9 * i + 6] >> 6; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 7] << 2; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10; + r->coeffs[4 * i + 3] &= 0x3FFFF; + + r->coeffs[4 * i + 0] = MLDSA_GAMMA1 - r->coeffs[4 * i + 0]; + r->coeffs[4 * i + 1] = MLDSA_GAMMA1 - r->coeffs[4 * i + 1]; + r->coeffs[4 * i + 2] = MLDSA_GAMMA1 - r->coeffs[4 * i + 2]; + r->coeffs[4 * i + 3] = MLDSA_GAMMA1 - r->coeffs[4 * i + 3]; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[2 * i + 0] = a[5 * i + 0]; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 2] << 16; + r->coeffs[2 * i + 0] &= 0xFFFFF; + + r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 3] << 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12; + /* r->coeffs[2*i+1] &= 0xFFFFF; */ /* No effect, since we're anyway at 20 + bits */ + + r->coeffs[2 * i + 0] = MLDSA_GAMMA1 - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_GAMMA1 - r->coeffs[2 * i + 1]; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +{ +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + ret = mld_polyz_unpack_17_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#elif defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + ret = mld_polyz_unpack_19_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYZ_UNPACK_17 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLYZ_UNPACK_19 && (MLD_CONFIG_PARAMETER_SET == 65 \ + || MLD_CONFIG_PARAMETER_SET == 87) */ + + mld_polyz_unpack_c(r, a); +} + +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + + mld_assert_bound(a->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[3 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0]) & 0xFF); + r[3 * i + 0] |= (uint8_t)((a->coeffs[4 * i + 1] << 6) & 0xFF); + r[3 * i + 1] = (uint8_t)((a->coeffs[4 * i + 1] >> 2) & 0xFF); + r[3 * i + 1] |= (uint8_t)((a->coeffs[4 * i + 2] << 4) & 0xFF); + r[3 * i + 2] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) & 0xFF); + r[3 * i + 2] |= (uint8_t)((a->coeffs[4 * i + 3] << 2) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + r[i] = + (uint8_t)((a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_rej_eta +#undef mld_rej_eta_c +#undef mld_poly_decompose_c +#undef mld_poly_use_hint_c +#undef mld_polyz_unpack_c +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_GAMMA1_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/poly_kl.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/poly_kl.h new file mode 100644 index 0000000000..c6aa498358 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/poly_kl.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_KL_H +#define MLD_POLY_KL_H + +#include "cbmc.h" +#include "common.h" +#include "poly.h" + +#define mld_poly_decompose MLD_NAMESPACE_KL(poly_decompose) +/************************************************* + * Name: mld_poly_decompose + * + * Description: For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such c mod MLDSA_Q = c1*ALPHA + + * c0 with -ALPHA/2 < c0 <= ALPHA/2 except + * c1 = (MLDSA_Q-1)/ALPHA where we set + * c1 = 0 and -ALPHA/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + * c1 + * - mld_poly *a0: pointer to input/output polynomial. Output + * polynomial has coefficients c0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +); + + +#define mld_poly_make_hint MLD_NAMESPACE_KL(poly_make_hint) +/************************************************* + * Name: mld_poly_make_hint + * + * Description: Compute hint polynomial. The coefficients of which indicate + * whether the low bits of the corresponding coefficient of + * the input polynomial overflow into the high bits. + * + * Arguments: - mld_poly *h: pointer to output hint polynomial + * - const mld_poly *a0: pointer to low part of input polynomial + * - const mld_poly *a1: pointer to high part of input polynomial + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + assigns(memory_slice(h, sizeof(mld_poly))) + ensures(return_value <= MLDSA_N) + ensures(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) +); + +#define mld_poly_use_hint MLD_NAMESPACE_KL(poly_use_hint) +/************************************************* + * Name: mld_poly_use_hint + * + * Description: Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - mld_poly *b: pointer to output polynomial with corrected high + *bits + * - const mld_poly *a: pointer to input polynomial + * - const mld_poly *h: pointer to input hint polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta_4x MLD_NAMESPACE_KL(poly_uniform_eta_4x) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample four polynomials with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce_i) + * + * Arguments: - mld_poly *r0: pointer to first output polynomial + * - mld_poly *r1: pointer to second output polynomial + * - mld_poly *r2: pointer to third output polynomial + * - mld_poly *r3: pointer to fourth output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce0: first nonce + * - uint8_t nonce1: second nonce + * - uint8_t nonce2: third nonce + * - uint8_t nonce3: fourth nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_abs_bound(r0->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r1->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r2->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r3->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta MLD_NAMESPACE_KL(poly_uniform_eta) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample polynomial with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce: nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1 MLD_NAMESPACE_KL(poly_uniform_gamma1) +/************************************************* + * Name: mld_poly_uniform_gamma1 + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1_4x MLD_NAMESPACE_KL(poly_uniform_gamma1_4x) +/************************************************* + * Name: mld_poly_uniform_gamma1_4x + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_bound(r0->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r1->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r2->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r3->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define mld_poly_challenge MLD_NAMESPACE_KL(poly_challenge) +/************************************************* + * Name: mld_poly_challenge + * + * Description: Implementation of H. Samples polynomial with MLDSA_TAU nonzero + * coefficients in {-1,1} using the output stream of + * SHAKE256(seed). + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const uint8_t mu[]: byte array containing seed of length + * MLDSA_CTILDEBYTES + **************************************************/ +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +__contract__( + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CTILDEBYTES)) + assigns(memory_slice(c, sizeof(mld_poly))) + /* All coefficients of c are -1, 0 or +1 */ + ensures(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) +); + +#define mld_polyeta_pack MLD_NAMESPACE_KL(polyeta_pack) +/************************************************* + * Name: mld_polyeta_pack + * + * Description: Bit-pack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYETA_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + assigns(memory_slice(r, MLDSA_POLYETA_PACKEDBYTES)) +); + +/* + * polyeta_unpack produces coefficients in [-MLDSA_ETA,MLDSA_ETA] for + * well-formed inputs (i.e., those produced by polyeta_pack). + * However, when passed an arbitrary byte array, it may produce smaller values, + * i.e, values in [MLD_POLYETA_UNPACK_LOWER_BOUND,MLDSA_ETA] + * Even though this should never happen, we use use the bound for arbitrary + * inputs in the CBMC proofs. + */ +#if MLDSA_ETA == 2 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-5) +#elif MLDSA_ETA == 4 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-11) +#else +#error "Invalid value of MLDSA_ETA" +#endif + +#define mld_polyeta_unpack MLD_NAMESPACE_KL(polyeta_unpack) +/************************************************* + * Name: mld_polyeta_unpack + * + * Description: Unpack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYETA_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)) +); + +#define mld_polyz_pack MLD_NAMESPACE_KL(polyz_pack) +/************************************************* + * Name: mld_polyz_pack + * + * Description: Bit-pack polynomial with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYZ_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(r, MLDSA_POLYZ_PACKEDBYTES)) +); + + +#define mld_polyz_unpack MLD_NAMESPACE_KL(polyz_unpack) +/************************************************* + * Name: mld_polyz_unpack + * + * Description: Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); + +#define mld_polyw1_pack MLD_NAMESPACE_KL(polyw1_pack) +/************************************************* + * Name: mld_polyw1_pack + * + * Description: Bit-pack polynomial w1 with coefficients in [0,15] or [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES)) +); + +#endif /* !MLD_POLY_KL_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/polyvec.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/polyvec.c new file mode 100644 index 0000000000..5c3a08ab32 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/polyvec.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include +#include + +#include "common.h" +#include "debug.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" + +/* This namespacing is not done at the top to avoid a naming conflict + * with native backends, which are currently not yet namespaced. */ +#define mld_polymat_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polymat_permute_bitrev_to_custom) +#define mld_polyvecl_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polyvecl_permute_bitrev_to_custom) +#define mld_polyvecl_pointwise_acc_montgomery_c \ + MLD_ADD_PARAM_SET(mld_polyvecl_pointwise_acc_montgomery_c) + +#if !defined(MLD_CONFIG_REDUCE_RAM) +/* Helper function to ensure that the polynomial entries in the output + * of mld_polyvec_matrix_expand use the standard (bitreversed) ordering + * of coefficients. + * No-op unless a native backend with a custom ordering is used. + */ + +static void mld_polyvecl_permute_bitrev_to_custom(mld_polyvecl *v) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +{ +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + unsigned i; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_permute_bitrev_to_custom(v->vec[i].coeffs); + } +#else /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + /* Nothing to do */ + (void)v; +#endif /* !MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ +} + +static void mld_polymat_permute_bitrev_to_custom(mld_polymat *mat) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; i++) + __loop__( + assigns(i, memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))) + { + mld_polyvecl_permute_bitrev_to_custom(&mat->vec[i]); + } +} +#endif /* !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + unsigned int i; + MLD_ALIGN uint8_t seed_ext[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + mld_memcpy(seed_ext, mat->rho, MLDSA_SEEDBYTES); + + /* Generate row on-demand */ + for (i = 0; i < MLDSA_L; i++) + { + uint8_t x = (uint8_t)row; + uint8_t y = (uint8_t)i; + + seed_ext[MLDSA_SEEDBYTES + 0] = y; + seed_ext[MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(&mat->row_buffer.vec[i], seed_ext); + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + mld_poly_permute_bitrev_to_custom(mat->row_buffer.vec[i].coeffs); +#endif + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); + + return &mat->row_buffer; +#else /* MLD_CONFIG_REDUCE_RAM */ + return &mat->vec[row]; +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + /* In REDUCE_RAM mode, just copy the seed for later on-demand generation */ + mld_memcpy(mat->rho, rho, MLDSA_SEEDBYTES); +#else + unsigned int i, j; + /* + * We generate four separate seed arrays rather than a single one to work + * around limitations in CBMC function contracts dealing with disjoint slices + * of the same parent object. + */ + + MLD_ALIGN uint8_t seed_ext[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + mld_memcpy(seed_ext[j], rho, MLDSA_SEEDBYTES); + } + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + /* Sample 4 matrix entries a time. */ + for (i = 0; i < (MLDSA_K * MLDSA_L / 4) * 4; i += 4) + __loop__( + assigns(i, j, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= (MLDSA_K * MLDSA_L / 4) * 4 && i % 4 == 0) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + uint8_t x = (uint8_t)((i + j) / MLDSA_L); + uint8_t y = (uint8_t)((i + j) % MLDSA_L); + + seed_ext[j][MLDSA_SEEDBYTES + 0] = y; + seed_ext[j][MLDSA_SEEDBYTES + 1] = x; + } + + mld_poly_uniform_4x(&mat->vec[i / MLDSA_L].vec[i % MLDSA_L], + &mat->vec[(i + 1) / MLDSA_L].vec[(i + 1) % MLDSA_L], + &mat->vec[(i + 2) / MLDSA_L].vec[(i + 2) % MLDSA_L], + &mat->vec[(i + 3) / MLDSA_L].vec[(i + 3) % MLDSA_L], + seed_ext); + } +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + i = 0; +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + /* Entries omitted by the batch-sampling are sampled individually. */ + while (i < MLDSA_K * MLDSA_L) + __loop__( + assigns(i, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K * MLDSA_L) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + uint8_t x = (uint8_t)(i / MLDSA_L); + uint8_t y = (uint8_t)(i % MLDSA_L); + mld_poly *this_poly = &mat->vec[i / MLDSA_L].vec[i % MLDSA_L]; + + seed_ext[0][MLDSA_SEEDBYTES + 0] = y; + seed_ext[0][MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(this_poly, seed_ext[0]); + i++; + } + + mld_polymat_permute_bitrev_to_custom(mat); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(t, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + const mld_polyvecl *row = mld_polymat_get_row(mat, i); + mld_polyvecl_pointwise_acc_montgomery(&t->vec[i], row, v); + } + + mld_assert_abs_bound_2d(t->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_L **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; +#endif + + /* Safety: nonce is at most ((UINT16_MAX - MLDSA_L) / MLDSA_L), and, hence, + * this cast is safe. See MLD_NONCE_UB comment in sign.c. */ + nonce = (uint16_t)(MLDSA_L * nonce); + /* Now, nonce <= UINT16_MAX - (MLDSA_L - 1), so the casts below are safe. */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_gamma1(&v->vec[i], seed, (uint16_t)(nonce + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLDSA_L == 4 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); +#elif MLDSA_L == 5 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); + mld_poly_uniform_gamma1(&v->vec[4], seed, (uint16_t)(nonce + 4)); +#elif MLDSA_L == 7 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], + &v->vec[3 /* irrelevant */], seed, nonce, + (uint16_t)(nonce + 1), (uint16_t)(nonce + 2), + 0xFF /* irrelevant */); + mld_poly_uniform_gamma1_4x(&v->vec[3], &v->vec[4], &v->vec[5], &v->vec[6], + seed, (uint16_t)(nonce + 3), (uint16_t)(nonce + 4), + (uint16_t)(nonce + 5), (uint16_t)(nonce + 6)); +#endif /* MLDSA_L == 7 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(k0, i, MLDSA_L, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_STATIC_TESTABLE void mld_polyvecl_pointwise_acc_montgomery_c( + mld_poly *w, const mld_polyvecl *u, const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i, j; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + for (i = 0; i < MLDSA_N; i++) + __loop__( + assigns(i, j, memory_slice(w, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_abs_bound(w->coeffs, 0, i, MLDSA_Q)) + ) + { + int64_t t = 0; + int32_t r; + for (j = 0; j < MLDSA_L; j++) + __loop__( + assigns(j, t) + invariant(j <= MLDSA_L) + invariant(t >= -(int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + invariant(t <= (int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + ) + { + t += (int64_t)u->vec[j].coeffs[i] * v->vec[j].coeffs[i]; + } + + r = mld_montgomery_reduce(t); + w->coeffs[i] = r; + } + + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +{ +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) && \ + MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l4_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) && \ + MLD_CONFIG_PARAMETER_SET == 65 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l5_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) && \ + MLD_CONFIG_PARAMETER_SET == 87 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l7_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 && \ + MLD_CONFIG_PARAMETER_SET == 44) && \ + !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 && \ + MLD_CONFIG_PARAMETER_SET == 65) && \ + MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 && \ + MLD_CONFIG_PARAMETER_SET == 87 */ + /* The first input is bounded by [0, Q-1] inclusive + * The second input is bounded by [-9Q+1, 9Q-1] inclusive . Hence, we can + * safely accumulate in 64-bits without intermediate reductions as + * MLDSA_L * (MLD_NTT_BOUND-1) * (Q-1) < INT64_MAX + * + * The worst case is ML-DSA-87: 7 * (9Q-1) * (Q-1) < 2**52 + * (and likewise for negative values) + */ + mld_polyvecl_pointwise_acc_montgomery_c(w, u, v); +} + +MLD_INTERNAL_API +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + invariant(i <= MLDSA_L) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + return t; +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_K **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k2, 0, i, + array_bound(v->vec[k2].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ) + { + mld_poly_reduce(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_caddq(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, + forall(k1, 0, MLDSA_N, u->vec[k0].coeffs[k1] == loop_entry(*u).vec[k0].coeffs[k1]))) + invariant(forall(k6, 0, i, array_bound(u->vec[k6].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + ) + { + mld_poly_add(&u->vec[i], &v->vec[i]); + } + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(u->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, u->vec[k1].coeffs[n1] == loop_entry(*u).vec[k1].coeffs[n1])))) + { + mld_poly_sub(&u->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, v->vec[k1].coeffs[n1] == loop_entry(*v).vec[k1].coeffs[n1]))) + ) + { + mld_poly_shiftl(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))) + { + mld_poly_invntt_tomont(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_INTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, array_abs_bound(r->vec[k2].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + mld_poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]); + } + mld_assert_abs_bound_2d(r->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + + return t; +} + +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + invariant(forall(k2, 0, i, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) + ) + { + mld_poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +{ + unsigned int i; + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + invariant(forall(k2, 0, i, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) + invariant(forall(k3, i, MLDSA_K, + array_bound(v0->vec[k3].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + ) + { + mld_poly_decompose(&v1->vec[i], &v0->vec[i]); + } + + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + mld_assert_abs_bound_2d(v0->vec, MLDSA_K, MLDSA_N, MLDSA_GAMMA2 + 1); +} + +MLD_INTERNAL_API +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, s, memory_slice(h, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(s <= i * MLDSA_N) + invariant(forall(k1, 0, i, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + s += mld_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]); + } + + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + return s; +} + +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *u, + const mld_polyveck *h) +{ + unsigned int i; + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(w, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)))) + ) + { + mld_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]); + } + + mld_assert_bound_2d(w->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +{ + unsigned int i; + mld_assert_bound_2d(w1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyw1_pack(&r[i * MLDSA_POLYW1_PACKEDBYTES], &w1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt0_pack(&r[i * MLDSA_POLYT0_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyz_unpack(&z->vec[i], r + i * MLDSA_POLYZ_PACKEDBYTES); + } + + mld_assert_bound_2d(z->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt0_unpack(&p->vec[i], r + i * MLDSA_POLYT0_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_polymat_permute_bitrev_to_custom +#undef mld_polyvecl_permute_bitrev_to_custom +#undef mld_polyvecl_pointwise_acc_montgomery_c diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/polyvec.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/polyvec.h new file mode 100644 index 0000000000..d21abc02ff --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/polyvec.h @@ -0,0 +1,725 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLYVEC_H +#define MLD_POLYVEC_H + +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "poly_kl.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_polyvecl MLD_ADD_PARAM_SET(mld_polyvecl) +#define mld_polyveck MLD_ADD_PARAM_SET(mld_polyveck) +#define mld_polymat MLD_ADD_PARAM_SET(mld_polymat) +/* End of parameter set namespacing */ + +/* Vectors of polynomials of length MLDSA_L */ +typedef struct +{ + mld_poly vec[MLDSA_L]; +} mld_polyvecl; + + +#define mld_polyvecl_uniform_gamma1 MLD_NAMESPACE_KL(polyvecl_uniform_gamma1) +/************************************************* + * Name: mld_polyvecl_uniform_gamma1 + * + * Description: Sample vector of polynomials with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_polyvecl *v: pointer to output vector + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + *************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + requires(nonce <= (UINT16_MAX - MLDSA_L) / MLDSA_L) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyvecl_ntt MLD_NAMESPACE_KL(polyvecl_ntt) +/************************************************* + * Name: mld_polyvecl_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_L. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyvecl *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k0, 0, MLDSA_L, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyvecl_pointwise_acc_montgomery \ + MLD_NAMESPACE_KL(polyvecl_pointwise_acc_montgomery) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery + * + * Description: Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * The first input "u" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * + * Arguments: - mld_poly *w: output polynomial + * - const mld_polyvecl *u: pointer to first input vector + * - const mld_polyvecl *v: pointer to second input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + + +#define mld_polyvecl_chknorm MLD_NAMESPACE_KL(polyvecl_chknorm) +/************************************************* + * Name: mld_polyvecl_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_L. + * Assumes input mld_polyvecl to be reduced by polyvecl_reduce(). + * + * Arguments: - const mld_polyvecl *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials is strictly smaller than B <= + * (MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +/* Vectors of polynomials of length MLDSA_K */ +typedef struct +{ + mld_poly vec[MLDSA_K]; +} mld_polyveck; + +/* Matrix of polynomials (K x L) */ +typedef struct +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + mld_polyvecl row_buffer; + uint8_t rho[MLDSA_SEEDBYTES]; +#else + mld_polyvecl vec[MLDSA_K]; +#endif +} mld_polymat; + +#define mld_polyveck_reduce MLD_NAMESPACE_KL(polyveck_reduce) +/************************************************* + * Name: polyveck_reduce + * + * Description: Reduce coefficients of polynomials in vector of length MLDSA_K + * to representatives in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) +); + +#define mld_polyveck_caddq MLD_NAMESPACE_KL(polyveck_caddq) +/************************************************* + * Name: mld_polyveck_caddq + * + * Description: For all coefficients of polynomials in vector of length MLDSA_K + * add MLDSA_Q if coefficient is negative. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_add MLD_NAMESPACE_KL(polyveck_add) +/************************************************* + * Name: mld_polyveck_add + * + * Description: Add vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to input-output vector of polynomials + * to be added to + * - const mld_polyveck *v: pointer to second input vector of + * polynomials + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(p0, 0, MLDSA_K, array_abs_bound(u->vec[p0].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) + requires(forall(p1, 0, MLDSA_K, + array_bound(v->vec[p1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(q2, 0, MLDSA_K, + array_bound(u->vec[q2].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_sub MLD_NAMESPACE_KL(polyveck_sub) +/************************************************* + * Name: mld_polyveck_sub + * + * Description: Subtract vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to first input vector + * - const mld_polyveck *v: pointer to second input vector to be + * subtracted from first input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(u->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_shiftl MLD_NAMESPACE_KL(polyveck_shiftl) +/************************************************* + * Name: mld_polyveck_shiftl + * + * Description: Multiply vector of polynomials of Length MLDSA_K by 2^MLDSA_D + *without modular reduction. Assumes input coefficients to be less than + *2^{31-MLDSA_D}. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_ntt MLD_NAMESPACE_KL(polyveck_ntt) +/************************************************* + * Name: mld_polyveck_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_K. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyveck_invntt_tomont MLD_NAMESPACE_KL(polyveck_invntt_tomont) +/************************************************* + * Name: mld_polyveck_invntt_tomont + * + * Description: Inverse NTT and multiplication by 2^{32} of polynomials + * in vector of length MLDSA_K. + * Input coefficients need to be less than MLDSA_Q, and + * Output coefficients are bounded by MLD_INTT_BOUND. + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) +); + +#define mld_polyveck_pointwise_poly_montgomery \ + MLD_NAMESPACE_KL(polyveck_pointwise_poly_montgomery) +/************************************************* + * Name: mld_polyveck_pointwise_poly_montgomery + * + * Description: Pointwise multiplication of a polynomial vector of length + * MLDSA_K by a single polynomial in NTT domain and multiplication + * of the resulting polynomial vector by 2^{-32}. + * + * Arguments: - mld_polyveck *r: pointer to output vector + * - mld_poly *a: pointer to input polynomial + * - mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(r, sizeof(mld_polyveck))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(r, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(r->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#define mld_polyveck_chknorm MLD_NAMESPACE_KL(polyveck_chknorm) +/************************************************* + * Name: mld_polyveck_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_K. + * Assumes input mld_polyveck to be reduced by polyveck_reduce(). + * + * Arguments: - const mld_polyveck *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials are strictly smaller than B <= + *(MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, + -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +#define mld_polyveck_power2round MLD_NAMESPACE_KL(polyveck_power2round) +/************************************************* + * Name: mld_polyveck_power2round + * + * Description: For all coefficients a of polynomials in vector of length + *MLDSA_K, compute a0, a1 such that a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with + *-2^{MLDSA_D-1} < a0 <= 2^{MLDSA_D-1}. Assumes coefficients to be standard + *representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to output vector of polynomials with + * coefficients a0 + * - const mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) +); + +#define mld_polyveck_decompose MLD_NAMESPACE_KL(polyveck_decompose) +/************************************************* + * Name: mld_polyveck_decompose + * + * Description: For all coefficients a of polynomials in vector of length + * MLDSA_K, compute high and low bits a0, a1 such a mod^+ MLDSA_Q = a1*ALPHA + * + a0 with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (MLDSA_Q-1)/ALPHA where we set + * a1 = 0 and -ALPHA/2 <= a0 = a mod MLDSA_Q - MLDSA_Q < 0. Assumes coefficients + * to be standard representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to input/output vector of + * polynomials with. Output polynomial has + * coefficients a0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v0->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + ensures(forall(k2, 0, MLDSA_K, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) +); + +#define mld_polyveck_make_hint MLD_NAMESPACE_KL(polyveck_make_hint) +/************************************************* + * Name: mld_polyveck_make_hint + * + * Description: Compute hint vector. + * + * Arguments: - mld_polyveck *h: pointer to output vector + * - const mld_polyveck *v0: pointer to low part of input vector + * - const mld_polyveck *v1: pointer to high part of input vector + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(return_value <= MLDSA_N * MLDSA_K) + ensures(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) +); + +#define mld_polyveck_use_hint MLD_NAMESPACE_KL(polyveck_use_hint) +/************************************************* + * Name: mld_polyveck_use_hint + * + * Description: Use hint vector to correct the high bits of input vector. + * + * Arguments: - mld_polyveck *w: pointer to output vector of polynomials with + * corrected high bits + * - const mld_polyveck *u: pointer to input vector + * - const mld_polyveck *h: pointer to input hint vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *v, + const mld_polyveck *h) +__contract__( + requires(memory_no_alias(w, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + assigns(memory_slice(w, sizeof(mld_polyveck))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) +); + +#define mld_polyveck_pack_w1 MLD_NAMESPACE_KL(polyveck_pack_w1) +/************************************************* + * Name: mld_polyveck_pack_w1 + * + * Description: Bit-pack polynomial vector w1 with coefficients in [0,15] or + * [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_K* MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_polyveck *a: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(w1, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(w1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) +); + +#define mld_polyveck_pack_eta MLD_NAMESPACE_KL(polyveck_pack_eta) +/************************************************* + * Name: mld_polyveck_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients + * in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyvecl_pack_eta MLD_NAMESPACE_KL(polyvecl_pack_eta) +/************************************************* + * Name: mld_polyvecl_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_L * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyveck_pack_t0 MLD_NAMESPACE_KL(polyveck_pack_t0) +/************************************************* + * Name: mld_polyveck_pack_t0 + * + * Description: Bit-pack polynomial vector to with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(p->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) +); + +#define mld_polyvecl_unpack_eta MLD_NAMESPACE_KL(polyvecl_unpack_eta) +/************************************************* + * Name: mld_polyvecl_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyvecl *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + assigns(memory_slice(p, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyvecl_unpack_z MLD_NAMESPACE_KL(polyvecl_unpack_z) +/************************************************* + * Name: mld_polyvecl_unpack_z + * + * Description: Unpack polynomial vector with coefficients in + * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_polyvecl *z: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(z->vec[k1].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyveck_unpack_eta MLD_NAMESPACE_KL(polyveck_unpack_eta) +/************************************************* + * Name: mld_polyveck_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyveck_unpack_t0 MLD_NAMESPACE_KL(polyveck_unpack_t0) +/************************************************* + * Name: mld_polyveck_unpack_t0 + * + * Description: Unpack polynomial vector with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) +); + +#define mld_polymat_get_row MLD_NAMESPACE_KL(polymat_get_row) +/************************************************* + * Name: mld_polymat_get_row + * + * Description: Retrieve a pointer to a specific row of the matrix. + * In MLD_CONFIG_REDUCE_RAM mode, generates the row on-demand. + * + * Arguments: - mld_polymat *mat: pointer to matrix + * - unsigned int row: row index (must be < MLDSA_K) + * + * Returns pointer to the row (mld_polyvecl) + **************************************************/ +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row); + +#define mld_polyvec_matrix_expand MLD_NAMESPACE_KL(polyvec_matrix_expand) +/************************************************* + * Name: mld_polyvec_matrix_expand + * + * Description: Implementation of ExpandA. Generates matrix A with uniformly + * random coefficients a_{i,j} by performing rejection + * sampling on the output stream of SHAKE128(rho|j|i) + * + * Arguments: - mld_polymat *mat: pointer to output matrix + * - const uint8_t rho[]: byte array containing seed rho + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +__contract__( + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +); + + + +#define mld_polyvec_matrix_pointwise_montgomery \ + MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery) +/************************************************* + * Name: mld_polyvec_matrix_pointwise_montgomery + * + * Description: Compute matrix-vector multiplication in NTT domain with + * pointwise multiplication and multiplication by 2^{-32}. + * Input matrix and vector must be in NTT domain representation. + * + * The first input "mat" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * Note: In MLD_CONFIG_REDUCE_RAM mode, mat cannot be const + * as rows are generated on-demand. + * + * Arguments: - mld_polyveck *t: pointer to output vector t + * - mld_polymat *mat: pointer to input matrix + * - const mld_polyvecl *v: pointer to input vector v + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(t, sizeof(mld_polyveck))) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(t, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#endif /* !MLD_POLYVEC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/randombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/randombytes.h new file mode 100644 index 0000000000..da55772419 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/randombytes.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_RANDOMBYTES_H +#define MLD_RANDOMBYTES_H + +#include +#include + +#include "cbmc.h" +#include "common.h" + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +#if !defined(MLD_CONFIG_CUSTOM_RANDOMBYTES) +MLD_MUST_CHECK_RETURN_VALUE +int randombytes(uint8_t *out, size_t outlen); +static MLD_INLINE int mld_randombytes(uint8_t *out, size_t outlen) +__contract__( + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) { return randombytes(out, outlen); } +#endif /* !MLD_CONFIG_CUSTOM_RANDOMBYTES */ +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ +#endif /* !MLD_RANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/reduce.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/reduce.h new file mode 100644 index 0000000000..413cf1829e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/reduce.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_REDUCE_H +#define MLD_REDUCE_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* check-magic: -4186625 == pow(2,32,MLDSA_Q) */ +#define MLD_MONT -4186625 + +/* Upper bound for domain of mld_reduce32() */ +#define MLD_REDUCE32_DOMAIN_MAX (INT32_MAX - (1 << 22)) + +/* Absolute bound for range of mld_reduce32() */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define MLD_REDUCE32_RANGE_MAX 6283009 + +/************************************************* + * Name: mld_montgomery_reduce + * + * Description: Generic Montgomery reduction; given a 64-bit integer a, computes + * 32-bit integer congruent to a * R^-1 mod q, where R=2^32 + * + * Arguments: - int64_t a: input integer to be reduced, of absolute value + * smaller or equal to INT64_MAX - 2^31 * MLDSA_Q. + * + * Returns: Integer congruent to a * R^-1 modulo q, with absolute value + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * In particular, if |a| < 2^31 * MLDSA_Q, the absolute value + * of the return value is < MLDSA_Q. + **************************************************/ +static MLD_INLINE int32_t mld_montgomery_reduce(int64_t a) +__contract__( + /* We don't attempt to express an input-dependent output bound + * as the post-condition here, as all call-sites satisfy the + * absolute input bound 2^31 * MLDSA_Q and higher-level + * reasoning can be conducted using |return_value| < MLDSA_Q. */ + requires(a > -(((int64_t)1 << 31) * MLDSA_Q) && + a < (((int64_t)1 << 31) * MLDSA_Q)) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* check-magic: 58728449 == unsigned_mod(pow(MLDSA_Q, -1, 2^32), 2^32) */ + const uint64_t QINV = 58728449; + + /* Compute a*q^{-1} mod 2^32 in unsigned representatives */ + const uint32_t a_reduced = mld_cast_int64_to_uint32(a); + const uint32_t a_inverted = (a_reduced * QINV) & UINT32_MAX; + + /* Lift to signed canonical representative mod 2^32. */ + const int32_t t = mld_cast_uint32_to_int32(a_inverted); + + int64_t r; + + mld_assert(a < +(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)) && + a > -(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q))); + + r = a - (int64_t)t * MLDSA_Q; + + /* + * PORTABILITY: Right-shift on a signed integer is, strictly-speaking, + * implementation-defined for negative left argument. Here, + * we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5)) + */ + r = r >> 32; + + /* Bounds: + * + * By construction of the Montgomery multiplication, by the time we + * compute r >> 32, r is divisible by 2^32, and hence + * + * |r >> 32| = |r| / 2^32 + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * (In general, we would only have |x >> n| <= ceil(|x| / 2^n)). + * + * In particular, if |a| < 2^31 * MLDSA_Q, then |return_value| < MLDSA_Q. + */ + return (int32_t)r; +} + +/************************************************* + * Name: mld_reduce32 + * + * Description: For finite field element a with a <= 2^{31} - 2^{22} - 1, + * compute r \equiv a (mod MLDSA_Q) such that + * -MLD_REDUCE32_RANGE_MAX <= r < MLD_REDUCE32_RANGE_MAX. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_reduce32(int32_t a) +__contract__( + requires(a <= MLD_REDUCE32_DOMAIN_MAX) + ensures(return_value >= -MLD_REDUCE32_RANGE_MAX) + ensures(return_value < MLD_REDUCE32_RANGE_MAX) +) +{ + int32_t t; + + t = (a + (1 << 22)) >> 23; + t = a - t * MLDSA_Q; + mld_assert((t - a) % MLDSA_Q == 0); + return t; +} + +/************************************************* + * Name: mld_caddq + * + * Description: Add MLDSA_Q if input coefficient is negative. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_caddq(int32_t a) +__contract__( + requires(a > -MLDSA_Q) + requires(a < MLDSA_Q) + ensures(return_value >= 0) + ensures(return_value < MLDSA_Q) + ensures(return_value == (a >= 0) ? a : (a + MLDSA_Q)) +) +{ + return mld_ct_sel_int32(a + MLDSA_Q, a, mld_ct_cmask_neg_i32(a)); +} + + +#endif /* !MLD_REDUCE_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/rounding.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/rounding.h new file mode 100644 index 0000000000..a83562b0f1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/rounding.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_ROUNDING_H +#define MLD_ROUNDING_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_power2round MLD_ADD_PARAM_SET(mld_power2round) +#define mld_decompose MLD_ADD_PARAM_SET(mld_decompose) +#define mld_make_hint MLD_ADD_PARAM_SET(mld_make_hint) +#define mld_use_hint MLD_ADD_PARAM_SET(mld_use_hint) +/* End of parameter set namespacing */ + +#define MLD_2_POW_D (1 << MLDSA_D) + +/************************************************* + * Name: mld_power2round + * + * Description: For finite field element a, compute a0, a1 such that + * a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with -2^{MLDSA_D-1} < a0 <= + * 2^{MLDSA_D-1}. Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: In the reference implementation, a1 is passed as a + * return value instead. + **************************************************/ +static MLD_INLINE void mld_power2round(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + ensures(*a0 > -(MLD_2_POW_D/2) && *a0 <= (MLD_2_POW_D/2)) + ensures(*a1 >= 0 && *a1 <= (MLDSA_Q - 1) / MLD_2_POW_D) + ensures((*a1 * MLD_2_POW_D + *a0 - a) % MLDSA_Q == 0) +) +{ + *a1 = (a + (1 << (MLDSA_D - 1)) - 1) >> MLDSA_D; + *a0 = a - (*a1 << MLDSA_D); +} + +/************************************************* + * Name: mld_decompose + * + * Description: For finite field element a, compute high and low bits a0, a1 + * such that a mod^+ MLDSA_Q = a1* 2 * MLDSA_GAMMA2 + a0 with + * -MLDSA_GAMMA2 < a0 <= MLDSA_GAMMA2 except + * if a1 = (MLDSA_Q-1)/(MLDSA_GAMMA2*2) where we set a1 = 0 and + * -MLDSA_GAMMA2 <= a0 = a mod^+ MLDSA_Q - MLDSA_Q < 0. + * Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: a1 is passed as a return value instead + **************************************************/ +static MLD_INLINE void mld_decompose(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + /* a0 = -MLDSA_GAMMA2 can only occur when (q-1) = a - (a mod MLDSA_GAMMA2), + * then a1=1; and a0 = a - (a mod MLDSA_GAMMA2) - 1 (@[FIPS204, Algorithm 36 (Decompose)]) */ + ensures(*a0 >= -MLDSA_GAMMA2 && *a0 <= MLDSA_GAMMA2) + ensures(*a1 >= 0 && *a1 < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) + ensures((*a1 * 2 * MLDSA_GAMMA2 + *a0 - a) % MLDSA_Q == 0) +) +{ + /* + * The goal is to compute f1 = round-(f / (2*GAMMA2)), which can be computed + * alternatively as round-(f / (128B)) = round-(ceil(f / 128) / B) where + * B = 2*GAMMA2 / 128. Here round-() denotes "round half down". + * + * The equality round-(f / (128B)) = round-(ceil(f / 128) / B) can deduced + * as follows. Since changing f to align-up(f, 128) can move f onto but not + * across a rounding boundary for division by 128*B (note that we need B to be + * even for this to work), and round- rounds down on the boundary, we have + * + * round-(f / (128B)) = round-(align-up(f, 128) / (128B)) + * = round-((align-up(f, 128) / 128) / B) + * = round-(ceil(f / 128) / B). + */ + *a1 = (a + 127) >> 7; + /* We know a >= 0 and a < MLDSA_Q, so... */ + /* check-magic: 65472 == round((MLDSA_Q-1)/128) */ + mld_assert(*a1 >= 0 && *a1 <= 65472); + +#if MLD_CONFIG_PARAMETER_SET == 44 + /* check-magic: 1488 == 2 * intdiv(intdiv(MLDSA_Q - 1, 88), 128) */ + /* check-magic: 11275 == floor(2**24 / 1488) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + */ + *a1 = (*a1 * 11275 + (1 << 23)) >> 24; + mld_assert(*a1 >= 0 && *a1 <= 44); + + *a1 = mld_ct_sel_int32(0, *a1, mld_ct_cmask_neg_i32(43 - *a1)); + mld_assert(*a1 >= 0 && *a1 <= 43); +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + /* check-magic: 4092 == 2 * intdiv(intdiv(MLDSA_Q - 1, 32), 128) */ + /* check-magic: 1025 == floor(2**22 / 4092) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + */ + *a1 = (*a1 * 1025 + (1 << 21)) >> 22; + mld_assert(*a1 >= 0 && *a1 <= 16); + + *a1 &= 15; + mld_assert(*a1 >= 0 && *a1 <= 15); + +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + + *a0 = a - *a1 * 2 * MLDSA_GAMMA2; + *a0 = mld_ct_sel_int32(*a0 - MLDSA_Q, *a0, + mld_ct_cmask_neg_i32((MLDSA_Q - 1) / 2 - *a0)); +} + +/************************************************* + * Name: mld_make_hint + * + * Description: Compute hint bit indicating whether the low bits of the + * input element overflow into the high bits. + * + * Arguments: - int32_t a0: low bits of input element + * - int32_t a1: high bits of input element + * + * Returns 1 if overflow, 0 otherwise + **************************************************/ +static MLD_INLINE unsigned int mld_make_hint(int32_t a0, int32_t a1) +__contract__( + ensures(return_value >= 0 && return_value <= 1) +) +{ + if (a0 > MLDSA_GAMMA2 || a0 < -MLDSA_GAMMA2 || + (a0 == -MLDSA_GAMMA2 && a1 != 0)) + { + return 1; + } + + return 0; +} + +/************************************************* + * Name: mld_use_hint + * + * Description: Correct high bits according to hint. + * + * Arguments: - int32_t a: input element + * - int32_t hint: hint bit + * + * Returns corrected high bits. + **************************************************/ +static MLD_INLINE int32_t mld_use_hint(int32_t a, int32_t hint) +__contract__( + requires(hint >= 0 && hint <= 1) + requires(a >= 0 && a < MLDSA_Q) + ensures(return_value >= 0 && return_value < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) +) +{ + int32_t a0, a1; + + mld_decompose(&a0, &a1, a); + if (hint == 0) + { + return a1; + } + +#if MLD_CONFIG_PARAMETER_SET == 44 + if (a0 > 0) + { + return (a1 == 43) ? 0 : a1 + 1; + } + else + { + return (a1 == 0) ? 43 : a1 - 1; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + if (a0 > 0) + { + return (a1 + 1) & 15; + } + else + { + return (a1 - 1) & 15; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + + +#endif /* !MLD_ROUNDING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/sign.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/sign.c new file mode 100644 index 0000000000..32bba52d65 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/sign.c @@ -0,0 +1,1508 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [Round3_Spec] + * CRYSTALS-Dilithium Algorithm Specifications and Supporting Documentation + * (Version 3.1) + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf + */ + +#include +#include + +#include "cbmc.h" +#include "ct.h" +#include "debug.h" +#include "packing.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" +#include "randombytes.h" +#include "sign.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_check_pct MLD_ADD_PARAM_SET(mld_check_pct) MLD_CONTEXT_PARAMETERS_2 +#define mld_sample_s1_s2 MLD_ADD_PARAM_SET(mld_sample_s1_s2) +#define mld_validate_hash_length MLD_ADD_PARAM_SET(mld_validate_hash_length) +#define mld_get_hash_oid MLD_ADD_PARAM_SET(mld_get_hash_oid) +#define mld_H MLD_ADD_PARAM_SET(mld_H) +#define mld_compute_pack_z MLD_ADD_PARAM_SET(mld_compute_pack_z) +#define mld_attempt_signature_generation \ + MLD_ADD_PARAM_SET(mld_attempt_signature_generation) MLD_CONTEXT_PARAMETERS_8 +#define mld_compute_t0_t1_tr_from_sk_components \ + MLD_ADD_PARAM_SET(mld_compute_t0_t1_tr_from_sk_components) \ + MLD_CONTEXT_PARAMETERS_7 +/* End of parameter set namespacing */ + + +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + ensures(return_value == 0 + || return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL) +); + +#if defined(MLD_CONFIG_KEYGEN_PCT) +/************************************************* + * @[FIPS140_3_IG] + * (https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf) + * + * TE10.35.02: Pair-wise Consistency Test (PCT) for DSA keypairs + * + * Purpose: Validates that a generated public/private key pair can correctly + * sign and verify data. Test performs signature generation using the private + * key (sk), followed by signature verification using the public key (pk). + * Returns 0 if the signature was successfully verified, non-zero if it cannot. + * + * Note: @[FIPS204] requires that public/private key pairs are to be used only + * for the calculation and/of verification of digital signatures. + **************************************************/ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t message[1] = {0}; + size_t siglen; + int ret; + MLD_ALLOC(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + MLD_ALLOC(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + + if (signature == NULL || pk_test == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Copy public key for testing */ + mld_memcpy(pk_test, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* Sign a test message using the original secret key */ + ret = mld_sign_signature(signature, &siglen, message, sizeof(message), NULL, + 0, sk, context); + if (ret != 0) + { + goto cleanup; + } + +#if defined(MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST) + /* Deliberately break public key for testing purposes */ + if (mld_break_pct()) + { + pk_test[0] = ~pk_test[0]; + } +#endif /* MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST */ + + /* Verify the signature using the (potentially corrupted) public key */ + ret = mld_sign_verify(signature, siglen, message, sizeof(message), NULL, 0, + pk_test, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + MLD_FREE(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + + return ret; +} +#else /* MLD_CONFIG_KEYGEN_PCT */ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + /* Skip PCT */ + ((void)pk); + ((void)sk); +#if defined(MLD_CONFIG_CONTEXT_PARAMETER) + ((void)context); +#endif + return 0; +} +#endif /* !MLD_CONFIG_KEYGEN_PCT */ + +static void mld_sample_s1_s2(mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t seed[MLDSA_CRHBYTES]) +__contract__( + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(object_whole(s1), object_whole(s2)) + ensures(forall(l0, 0, MLDSA_L, array_abs_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + ensures(forall(k0, 0, MLDSA_K, array_abs_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) +) +{ +/* Sample short vectors s1 and s2 */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; + uint16_t nonce = 0; + /* Safety: The nonces are at most 14 (MLDSA_L + MLDSA_K - 1), and, hence, the + * casts are safe. */ + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_eta(&s1->vec[i], seed, (uint8_t)(nonce + i)); + } + for (i = 0; i < MLDSA_K; i++) + { + mld_poly_uniform_eta(&s2->vec[i], seed, (uint8_t)(nonce + MLDSA_L + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLD_CONFIG_PARAMETER_SET == 44 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 4, 5, 6, 7); +#elif MLD_CONFIG_PARAMETER_SET == 65 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s2->vec[0], &s2->vec[1], + &s2->vec[2] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[2], &s2->vec[3], &s2->vec[4], &s2->vec[5], + seed, 7, 8, 9, 10); +#elif MLD_CONFIG_PARAMETER_SET == 87 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s1->vec[5], &s1->vec[6], + &s2->vec[0] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 7, 8, 9, 10); + mld_poly_uniform_eta_4x(&s2->vec[4], &s2->vec[5], &s2->vec[6], &s2->vec[7], + seed, 11, 12, 13, 14); +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ +} + +/************************************************* + * Name: mld_compute_t0_t1_tr_from_sk_components + * + * Description: Computes t0, t1, tr, and pk from secret key components + * rho, s1, s2. This is the shared computation used by + * both keygen and generating the public key from the + * secret key. + * + * Arguments: - mld_polyveck *t0: output t0 + * - mld_polyveck *t1: output t1 + * - uint8_t tr[MLDSA_TRBYTES]: output tr + * - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t rho[MLDSA_SEEDBYTES]: input rho + * - const mld_polyvecl *s1: input s1 + * - const mld_polyveck *s2: input s2 + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_t0_t1_tr_from_sk_components( + mld_polyveck *t0, mld_polyveck *t1, uint8_t tr[MLDSA_TRBYTES], + uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], const uint8_t rho[MLDSA_SEEDBYTES], + const mld_polyvecl *s1, const mld_polyveck *s2, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(l0, 0, MLDSA_L, array_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + requires(forall(k0, 0, MLDSA_K, array_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(forall(k1, 0, MLDSA_K, array_bound(t0->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(t1->vec[k2].coeffs, 0, MLDSA_N, 0, 1 << 10))) + ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY)) +{ + int ret; + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1hat, mld_polyvecl, 1, context); + MLD_ALLOC(t, mld_polyveck, 1, context); + + if (mat == NULL || s1hat == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Expand matrix */ + mld_polyvec_matrix_expand(mat, rho); + + /* Matrix-vector multiplication */ + *s1hat = *s1; + mld_polyvecl_ntt(s1hat); + mld_polyvec_matrix_pointwise_montgomery(t, mat, s1hat); + mld_polyveck_invntt_tomont(t); + + /* Add error vector s2 */ + mld_polyveck_add(t, s2); + + /* Reference: The following reduction is not present in the reference + * implementation. Omitting this reduction requires the output of + * the invntt to be small enough such that the addition of s2 does + * not result in absolute values >= MLDSA_Q. While our C, x86_64, + * and AArch64 invntt implementations produce small enough + * values for this to work out, it complicates the bounds + * reasoning. We instead add an additional reduction, and can + * consequently, relax the bounds requirements for the invntt. + */ + mld_polyveck_reduce(t); + + /* Decompose to get t1, t0 */ + mld_polyveck_caddq(t); + mld_polyveck_power2round(t1, t0, t); + + /* Pack public key and compute tr */ + mld_pack_pk(pk, rho, t1); + mld_shake256(tr, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + ret = 0; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_polyveck, 1, context); + MLD_FREE(s1hat, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + const uint8_t *rho, *rhoprime, *key; + MLD_ALLOC(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + MLD_ALLOC(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + + if (seedbuf == NULL || inbuf == NULL || tr == NULL || s1 == NULL || + s2 == NULL || t1 == NULL || t0 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Get randomness for rho, rhoprime and key */ + mld_memcpy(inbuf, seed, MLDSA_SEEDBYTES); + inbuf[MLDSA_SEEDBYTES + 0] = MLDSA_K; + inbuf[MLDSA_SEEDBYTES + 1] = MLDSA_L; + mld_shake256(seedbuf, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, inbuf, + MLDSA_SEEDBYTES + 2); + rho = seedbuf; + rhoprime = rho + MLDSA_SEEDBYTES; + key = rhoprime + MLDSA_CRHBYTES; + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + + /* Sample s1 and s2 */ + mld_sample_s1_s2(s1, s2, rhoprime); + + /* Compute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0, t1, tr, pk, rho, s1, s2, + context); + if (ret != 0) + { + goto cleanup; + } + + /* Pack secret key */ + mld_pack_sk(sk, rho, tr, key, t0, s1, s2); + + /* Constant time: pk is the public key, inherently public data */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_FREE(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + + if (ret != 0) + { + return ret; + } + + /* Pairwise Consistency Test (PCT) @[FIPS140_3_IG, p.87] */ + /* Do this after freeing all temporaries. */ + return mld_check_pct(pk, sk, context); +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t seed[MLDSA_SEEDBYTES]; + int ret; + if (mld_randombytes(seed, MLDSA_SEEDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(seed, sizeof(seed)); + ret = mld_sign_keypair_internal(pk, sk, seed, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed, sizeof(seed)); + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +/************************************************* + * Name: mld_H + * + * Description: Abstracts application of SHAKE256 to + * one, two or three blocks of data, + * yielding a user-requested size of + * output. + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in1: pointer to input block 1 + * Must NOT be NULL + * - size_t in1len: length of input in1 bytes + * - const uint8_t *in2: pointer to input block 2 + * May be NULL if in2len=0, in which case + * this block is ignored + * - size_t in2len: length of input in2 bytes + * - const uint8_t *in3: pointer to input block 3 + * May be NULL if in3len=0, in which case + * this block is ignored + * - size_t in3len: length of input in3 bytes + **************************************************/ +static void mld_H(uint8_t *out, size_t outlen, const uint8_t *in1, + size_t in1len, const uint8_t *in2, size_t in2len, + const uint8_t *in3, size_t in3len) +__contract__( + requires(in1len <= MLD_MAX_BUFFER_SIZE) + requires(in2len <= MLD_MAX_BUFFER_SIZE) + requires(in3len <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in1, in1len)) + requires(in2len == 0 || memory_no_alias(in2, in2len)) + requires(in3len == 0 || memory_no_alias(in3, in3len)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) +{ + mld_shake256ctx state; + mld_shake256_init(&state); + mld_shake256_absorb(&state, in1, in1len); + if (in2len != 0) + { + mld_shake256_absorb(&state, in2, in2len); + } + if (in3len != 0) + { + mld_shake256_absorb(&state, in3, in3len); + } + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(&state, sizeof(state)); +} + +/************************************************* + * Name: mld_compute_pack_z + * + * Description: Computes z = y + s1*c, checks that z has coefficients smaller + * than MLDSA_GAMMA1 - MLDSA_BETA, and packs z into the + * signature buffer. + * + * Arguments: - uint8_t *sig: output signature + * - const mld_poly *cp: challenge polynomial + * - const polyvecl *s1: secret vector s1 + * - const polyvecl *y: masking vector y + * + * Returns: - 0: Success (z has coefficients smaller than + * MLDSA_GAMMA1 - MLDSA_BETA,) + * - MLD_ERR_FAIL: z rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This function is inlined into mld_sign_signature in the + * reference implementation. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_pack_z(uint8_t sig[MLDSA_CRYPTO_BYTES], + const mld_poly *cp, const mld_polyvecl *s1, + const mld_polyvecl *y, mld_poly *z) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(cp, sizeof(mld_poly))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(y, sizeof(mld_polyvecl))) + requires(memory_no_alias(z, sizeof(mld_poly))) + requires(array_abs_bound(cp->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_L, + array_bound(y->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + requires(forall(k1, 0, MLDSA_L, array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(memory_slice(z, sizeof(mld_poly))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int i; + uint32_t z_invalid; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(z, sizeof(mld_poly)), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_poly_pointwise_montgomery(z, cp, &s1->vec[i]); + mld_poly_invntt_tomont(z); + mld_poly_add(z, &y->vec[i]); + mld_poly_reduce(z); + + z_invalid = mld_poly_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA); + /* Constant time: It is fine (and prohibitively expensive to avoid) + * to leak the result of the norm check and which polynomial in z caused a + * rejection. It would even be okay to leak which coefficient led to + * rejection as the candidate signature will be discarded anyway. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(&z_invalid, sizeof(uint32_t)); + if (z_invalid) + { + return MLD_ERR_FAIL; /* reject */ + } + /* If z is valid, then its coefficients are bounded by + * MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below + * to prove the pre-condition of pack_sig_z() */ + mld_assert_abs_bound(z, MLDSA_N, (MLDSA_GAMMA1 - MLDSA_BETA)); + + /* After the norm check, the distribution of each coefficient of z is + * independent of the secret key and it can, hence, be considered + * public. It is, hence, okay to immediately pack it into the user-provided + * signature buffer. */ + mld_pack_sig_z(sig, z, i); + } + return 0; +} + +/* Reference: The reference implementation does not explicitly check the + * maximum nonce value, but instead loops indefinitely (even when the nonce + * would overflow). Internally, sampling of y uses + * (nonceL), (nonceL+1), ... (nonce*L+L-1). + * Hence, there are no overflows if nonce < (UINT16_MAX - L)/L. + * Explicitly checking for this explicitly allows us to prove type-safety. + * Note that FIPS204 explicitly allows an upper-bound this loop of + * 814 (< (UINT16_MAX - L)/L) - see @[FIPS204, Appendix C]. */ +#define MLD_NONCE_UB ((UINT16_MAX - MLDSA_L) / MLDSA_L) + +/************************************************* + * Name: attempt_signature_generation + * + * Description: Attempts to generate a single signature. + * + * Arguments: - uint8_t *sig: pointer to output signature + * - const uint8_t *mu: pointer to message or hash + * of exactly MLDSA_CRHBYTES bytes + * - const uint8_t *rhoprime: pointer to randomness seed + * - uint16_t nonce: current nonce value + * - const mld_polymat *mat: expanded matrix + * - const polyvecl *s1: secret vector s1 + * - const polyveck *s2: secret vector s2 + * - const polyveck *t0: vector t0 + * + * Returns: - 0: Signature generation succeeded + * - MLD_ERR_FAIL: Signature rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This code differs from the reference implementation + * in that it factors out the core signature generation + * step into a distinct function here in order to improve + * efficiency of CBMC proof. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_attempt_signature_generation( + uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *mu, + const uint8_t rhoprime[MLDSA_CRHBYTES], uint16_t nonce, mld_polymat *mat, + const mld_polyvecl *s1, const mld_polyveck *s2, const mld_polyveck *t0, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(rhoprime, MLDSA_CRHBYTES)) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(nonce <= MLD_NONCE_UB) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int n; + uint32_t w0_invalid, h_invalid; + int ret; + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyvecl y; + mld_polyveck h; + } + yh_u; + mld_polyvecl *y; + mld_polyveck *h; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck w1; + mld_polyvecl tmp; + } + w1tmp_u; + mld_polyveck *w1; + mld_polyvecl *tmp; + + MLD_ALLOC(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(yh, yh_u, 1, context); + MLD_ALLOC(z, mld_poly, 1, context); + MLD_ALLOC(w1tmp, w1tmp_u, 1, context); + MLD_ALLOC(w0, mld_polyveck, 1, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(t, mld_poly, 1, context); + + if (challenge_bytes == NULL || yh == NULL || z == NULL || w1tmp == NULL || + w0 == NULL || cp == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + y = &yh->y; + h = &yh->h; + w1 = &w1tmp->w1; + tmp = &w1tmp->tmp; + + /* Sample intermediate vector y */ + mld_polyvecl_uniform_gamma1(y, rhoprime, nonce); + + /* Matrix-vector multiplication */ + *tmp = *y; + mld_polyvecl_ntt(tmp); + mld_polyvec_matrix_pointwise_montgomery(w0, mat, tmp); + mld_polyveck_invntt_tomont(w0); + + /* Decompose w and call the random oracle */ + mld_polyveck_caddq(w0); + mld_polyveck_decompose(w1, w0); + mld_polyveck_pack_w1(sig, w1); + + mld_H(challenge_bytes, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, sig, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + /* Constant time: Leaking challenge_bytes does not reveal any information + * about the secret key as H() is modelled as random oracle. + * This also applies to challenges for rejected signatures. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(challenge_bytes, MLDSA_CTILDEBYTES); + mld_poly_challenge(cp, challenge_bytes); + mld_poly_ntt(cp); + + /* Compute z, reject if it reveals secret */ + ret = mld_compute_pack_z(sig, cp, s1, y, t); + if (ret) + { + goto cleanup; + } + + /* Check that subtracting cs2 does not change high bits of w and low bits + * do not reveal secret information */ + mld_polyveck_pointwise_poly_montgomery(h, cp, s2); + mld_polyveck_invntt_tomont(h); + mld_polyveck_sub(w0, h); + mld_polyveck_reduce(w0); + + w0_invalid = mld_polyveck_chknorm(w0, MLDSA_GAMMA2 - MLDSA_BETA); + /* Constant time: w0_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&w0_invalid, sizeof(uint32_t)); + if (w0_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* Compute hints for w1 */ + mld_polyveck_pointwise_poly_montgomery(h, cp, t0); + mld_polyveck_invntt_tomont(h); + mld_polyveck_reduce(h); + + h_invalid = mld_polyveck_chknorm(h, MLDSA_GAMMA2); + /* Constant time: h_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&h_invalid, sizeof(uint32_t)); + if (h_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + mld_polyveck_add(w0, h); + + /* Constant time: At this point all norm checks have passed and we, hence, + * know that the signature does not leak any secret information. + * Consequently, any value that can be computed from the signature and public + * key is considered public. + * w0 and w1 are public as they can be computed from Az - ct = \alpha w1 + w0. + * h=c*t0 is public as both c and t0 are public. + * For a more detailed discussion, refer to https://eprint.iacr.org/2022/1406. + */ + MLD_CT_TESTING_DECLASSIFY(w0, sizeof(*w0)); + MLD_CT_TESTING_DECLASSIFY(w1, sizeof(*w1)); + n = mld_polyveck_make_hint(h, w0, w1); + if (n > MLDSA_OMEGA) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* All is well - write signature */ + mld_pack_sig_c_h(sig, challenge_bytes, h, n); + /* Constant time: At this point it is clear that the signature is valid - it + * can, hence, be considered public. */ + MLD_CT_TESTING_DECLASSIFY(sig, MLDSA_CRYPTO_BYTES); + ret = 0; /* success */ + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_poly, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(w0, mld_polyveck, 1, context); + MLD_FREE(w1tmp, w1tmp_u, 1, context); + MLD_FREE(z, mld_poly, 1, context); + MLD_FREE(yh, yh_u, 1, context); + MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + + return ret; +} +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + uint8_t *rho, *tr, *key, *mu, *rhoprime; + uint16_t nonce = 0; + MLD_ALLOC(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + + if (seedbuf == NULL || mat == NULL || s1 == NULL || t0 == NULL || s2 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + rho = seedbuf; + tr = rho + MLDSA_SEEDBYTES; + key = tr + MLDSA_TRBYTES; + mu = key + MLDSA_SEEDBYTES; + rhoprime = mu + MLDSA_CRHBYTES; + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + if (!externalmu) + { + /* Compute mu = CRH(tr, pre, msg) */ + mld_H(mu, MLDSA_CRHBYTES, tr, MLDSA_TRBYTES, pre, prelen, m, mlen); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Compute rhoprime = CRH(key, rnd, mu) */ + mld_H(rhoprime, MLDSA_CRHBYTES, key, MLDSA_SEEDBYTES, rnd, MLDSA_RNDBYTES, mu, + MLDSA_CRHBYTES); + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + /* Expand matrix and transform vectors */ + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(s1); + mld_polyveck_ntt(s2); + mld_polyveck_ntt(t0); + + /* By default, return failure. Flip to success and write output + * once signature generation succeeds. */ + ret = MLD_ERR_FAIL; + + /* Reference: This code is re-structured using a while(1), */ + /* with explicit "continue" statements (rather than "goto") */ + /* to implement rejection of invalid signatures. */ + while (1) + __loop__( + assigns(nonce, ret, object_whole(siglen), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(nonce <= MLD_NONCE_UB) + + /* t0, s1, s2, and mat are initialized above and are NOT changed by this */ + /* loop. We can therefore re-assert their bounds here as part of the */ + /* loop invariant. This makes proof noticeably faster with CBMC */ + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + invariant(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(ret == MLD_ERR_FAIL) + ) + { + /* Reference: this code explicitly checks for exhaustion of nonce */ + /* values to provide predictable termination and results in that case */ + /* Checking here also means that incrementing nonce below can also */ + /* be proven to be type-safe. */ + if (nonce == MLD_NONCE_UB) + { + /* Note that ret == MLD_ERR_FAIL by default, so we + * don't need to set it here. */ + break; + } + + ret = mld_attempt_signature_generation(sig, mu, rhoprime, nonce, mat, s1, + s2, t0, context); + nonce++; + if (ret == 0) + { + *siglen = MLDSA_CRYPTO_BYTES; + break; + } + else if (ret != MLD_ERR_FAIL) + { + /* For failures such as out-of-memory, propagate and exit immediately. */ + break; + } + + /* Otherwise, try again. */ + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the signature buffer. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + return ret; +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + size_t pre_len; + int ret; + MLD_ALLOC(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + MLD_ALLOC(rnd, uint8_t, MLDSA_RNDBYTES, context); + + if (pre == NULL || rnd == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Prepare domain separation prefix for pure ML-DSA */ + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, m, mlen, pre, pre_len, rnd, sk, + 0, context); + +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(rnd, uint8_t, MLDSA_RNDBYTES, context); + MLD_FREE(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t rnd[MLDSA_RNDBYTES]; + int ret; + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + *siglen = 0; + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, + rnd, sk, 1, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(rnd, sizeof(rnd)); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + for (i = 0; i < mlen; ++i) + __loop__( + assigns(i, object_whole(sm)) + invariant(i <= mlen) + ) + { + sm[MLDSA_CRYPTO_BYTES + mlen - 1 - i] = m[mlen - 1 - i]; + } + ret = mld_sign_signature(sm, smlen, sm + MLDSA_CRYPTO_BYTES, mlen, ctx, + ctxlen, sk, context); + *smlen += mlen; + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret, cmp; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck t1; + mld_polyveck w1; + } + t1w1_u; + mld_polyveck *t1; + mld_polyveck *w1; + + MLD_ALLOC(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_ALLOC(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(z, mld_polyvecl, 1, context); + MLD_ALLOC(t1w1, t1w1_u, 1, context); + MLD_ALLOC(tmp, mld_polyveck, 1, context); + MLD_ALLOC(h, mld_polyveck, 1, context); + + if (buf == NULL || rho == NULL || mu == NULL || c == NULL || c2 == NULL || + cp == NULL || mat == NULL || z == NULL || t1w1 == NULL || tmp == NULL || + h == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + t1 = &t1w1->t1; + w1 = &t1w1->w1; + + if (siglen != MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + mld_unpack_pk(rho, t1, pk); + + /* mld_unpack_sig and mld_polyvecl_chknorm signal failure through a + * single non-zero error code that's not yet aligned with MLD_ERR_XXX. + * Map it to MLD_ERR_FAIL explicitly. */ + if (mld_unpack_sig(c, z, h, sig)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + if (mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + if (!externalmu) + { + /* Compute CRH(H(rho, t1), pre, msg) */ + MLD_ALIGN uint8_t hpk[MLDSA_CRHBYTES]; + mld_H(hpk, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES, NULL, 0, NULL, + 0); + mld_H(mu, MLDSA_CRHBYTES, hpk, MLDSA_TRBYTES, pre, prelen, m, mlen); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(hpk, sizeof(hpk)); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Matrix-vector multiplication; compute Az - c2^dt1 */ + mld_poly_challenge(cp, c); + mld_poly_ntt(cp); + mld_polyveck_shiftl(t1); + mld_polyveck_ntt(t1); + mld_polyveck_pointwise_poly_montgomery(tmp, cp, t1); + + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(z); + mld_polyvec_matrix_pointwise_montgomery(w1, mat, z); + mld_polyveck_sub(w1, tmp); + mld_polyveck_reduce(w1); + mld_polyveck_invntt_tomont(w1); + + /* Reconstruct w1 */ + mld_polyveck_caddq(w1); + mld_polyveck_use_hint(tmp, w1, h); + mld_polyveck_pack_w1(buf, tmp); + /* Call random oracle and verify challenge */ + mld_H(c2, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, buf, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + + cmp = mld_ct_memcmp(c, c2, MLDSA_CTILDEBYTES); + + /* Declassify the result of the verification. */ + MLD_CT_TESTING_DECLASSIFY(&cmp, sizeof(cmp)); + + ret = cmp == 0 ? 0 : MLD_ERR_FAIL; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(h, mld_polyveck, 1, context); + MLD_FREE(tmp, mld_polyveck, 1, context); + MLD_FREE(t1w1, t1w1_u, 1, context); + MLD_FREE(z, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, m, mlen, pre, pre_len, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + return mld_sign_verify_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, pk, + 1, context); +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + if (smlen < MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + *mlen = smlen - MLDSA_CRYPTO_BYTES; + ret = mld_sign_verify(sm, MLDSA_CRYPTO_BYTES, sm + MLDSA_CRYPTO_BYTES, *mlen, + ctx, ctxlen, pk, context); + if (ret == 0) + { + /* All good, copy msg, return 0 */ + for (i = 0; i < *mlen; ++i) + __loop__( + assigns(i, memory_slice(m, *mlen)) + invariant(i <= *mlen) + ) + { + m[i] = sm[MLDSA_CRYPTO_BYTES + i]; + } + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the message buffer. */ + *mlen = 0; + mld_memset(m, 0, smlen); + } + + return ret; +} + + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_signature_internal(sig, siglen, pre, pre_len, NULL, 0, rnd, sk, + 0, context); +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, pre, pre_len, NULL, 0, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_signature_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, rnd, sk, + MLD_PREHASH_SHAKE_256, context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_verify_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, pk, MLD_PREHASH_SHAKE_256, + context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + + +#define MLD_PRE_HASH_OID_LEN 11 + +/************************************************* + * Name: mld_get_hash_oid + * + * Description: Returns the OID of a given SHA-2/SHA-3 hash function. + * + * Arguments: - uint8_t oid[11]: pointer to output oid + * - int hashalg: hash algorithm constant (MLD_PREHASH_*) + * + ***************************************************/ +static void mld_get_hash_oid(uint8_t oid[MLD_PRE_HASH_OID_LEN], int hashalg) +{ + unsigned int i; + static const struct + { + int alg; + uint8_t oid[MLD_PRE_HASH_OID_LEN]; + } oid_map[] = { + {MLD_PREHASH_SHA2_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}}, + {MLD_PREHASH_SHA2_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}}, + {MLD_PREHASH_SHA2_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}}, + {MLD_PREHASH_SHA2_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}}, + {MLD_PREHASH_SHA2_512_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05}}, + {MLD_PREHASH_SHA2_512_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06}}, + {MLD_PREHASH_SHA3_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07}}, + {MLD_PREHASH_SHA3_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08}}, + {MLD_PREHASH_SHA3_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09}}, + {MLD_PREHASH_SHA3_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A}}, + {MLD_PREHASH_SHAKE_128, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B}}, + {MLD_PREHASH_SHAKE_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C}}}; + + for (i = 0; i < sizeof(oid_map) / sizeof(oid_map[0]); i++) + __loop__( + invariant(i <= sizeof(oid_map) / sizeof(oid_map[0])) + ) + { + if (oid_map[i].alg == hashalg) + { + mld_memcpy(oid, oid_map[i].oid, MLD_PRE_HASH_OID_LEN); + return; + } + } +} + +static int mld_validate_hash_length(int hashalg, size_t len) +{ + switch (hashalg) + { + case MLD_PREHASH_SHA2_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_128: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_256: + return (len == 512 / 8) ? 0 : -1; + } + return -1; +} + +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +{ + if (ctxlen > 255) + { + return 0; + } + + if (hashalg != MLD_PREHASH_NONE) + { + if (ph == NULL || mld_validate_hash_length(hashalg, phlen) != 0) + { + return 0; + } + } + + /* Common prefix: 0x00/0x01 || ctxlen || ctx */ + prefix[0] = (hashalg == MLD_PREHASH_NONE) ? 0 : 1; + prefix[1] = (uint8_t)ctxlen; + if (ctxlen > 0) + { + mld_memcpy(prefix + 2, ctx, ctxlen); + } + + if (hashalg == MLD_PREHASH_NONE) + { + return 2 + ctxlen; + } + + /* HashML-DSA: append oid || ph */ + mld_get_hash_oid(prefix + 2 + ctxlen, hashalg); + mld_memcpy(prefix + 2 + ctxlen + MLD_PRE_HASH_OID_LEN, ph, phlen); + return 2 + ctxlen + MLD_PRE_HASH_OID_LEN + phlen; +} + +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + uint8_t check, cmp0, cmp1, chk1, chk2; + int ret; + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(t0_computed, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + + if (rho == NULL || tr == NULL || tr_computed == NULL || key == NULL || + s1 == NULL || s2 == NULL || t0 == NULL || t0_computed == NULL || + t1 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Unpack secret key */ + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + /* Validate s1 and s2 coefficients are within [-MLDSA_ETA, MLDSA_ETA] */ + chk1 = mld_polyvecl_chknorm(s1, MLDSA_ETA + 1) & 0xFF; + chk2 = mld_polyveck_chknorm(s2, MLDSA_ETA + 1) & 0xFF; + + /* Recompute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0_computed, t1, tr_computed, + pk, rho, s1, s2, context); + if (ret != 0) + { + goto cleanup; + } + + /* Validate t0 and tr using constant-time comparisons */ + cmp0 = mld_ct_memcmp((const uint8_t *)t0, (const uint8_t *)t0_computed, + sizeof(mld_polyveck)); + cmp1 = mld_ct_memcmp((const uint8_t *)tr, (const uint8_t *)tr_computed, + MLDSA_TRBYTES); + check = mld_value_barrier_u8(cmp0 | cmp1 | chk1 | chk2); + + /* Declassify the final result of the validity check. */ + MLD_CT_TESTING_DECLASSIFY(&check, sizeof(check)); + ret = (check != 0) ? MLD_ERR_FAIL : 0; + +cleanup: + + if (ret != 0) + { + mld_zeroize(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + } + + /* Constant time: pk is either the valid public key or zeroed on error */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(t0_computed, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + + return ret; +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_check_pct +#undef mld_sample_s1_s2 +#undef mld_validate_hash_length +#undef mld_get_hash_oid +#undef mld_H +#undef mld_compute_pack_z +#undef mld_attempt_signature_generation +#undef mld_compute_t0_t1_tr_from_sk_components +#undef MLD_NONCE_UB +#undef MLD_PRE_HASH_OID_LEN diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/sign.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/sign.h new file mode 100644 index 0000000000..2e0bac32ea --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/sign.h @@ -0,0 +1,807 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_SIGN_H +#define MLD_SIGN_H + +#include +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "polyvec.h" +#include "sys.h" + +#if defined(MLD_CHECK_APIS) +/* Include to ensure consistency between internal sign.h + * and external mldsa_native.h. */ +#include "mldsa_native.h" + +#if MLDSA_CRYPTO_SECRETKEYBYTES != \ + MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for SECRETKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_PUBLICKEYBYTES != \ + MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for PUBLICKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_BYTES != MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for CRYPTO_BYTES between sign.h and mldsa_native.h +#endif + +#endif /* MLD_CHECK_APIS */ + +#define mld_sign_keypair_internal \ + MLD_NAMESPACE_KL(keypair_internal) MLD_CONTEXT_PARAMETERS_3 +#define mld_sign_keypair MLD_NAMESPACE_KL(keypair) MLD_CONTEXT_PARAMETERS_2 +#define mld_sign_signature_internal \ + MLD_NAMESPACE_KL(signature_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_signature MLD_NAMESPACE_KL(signature) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_extmu \ + MLD_NAMESPACE_KL(signature_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign MLD_NAMESPACE_KL(sign) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_internal \ + MLD_NAMESPACE_KL(verify_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify MLD_NAMESPACE_KL(verify) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_extmu \ + MLD_NAMESPACE_KL(verify_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign_open MLD_NAMESPACE_KL(open) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_pre_hash_internal \ + MLD_NAMESPACE_KL(signature_pre_hash_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_verify_pre_hash_internal \ + MLD_NAMESPACE_KL(verify_pre_hash_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_signature_pre_hash_shake256 \ + MLD_NAMESPACE_KL(signature_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify_pre_hash_shake256 \ + MLD_NAMESPACE_KL(verify_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_7 +#define mld_prepare_domain_separation_prefix \ + MLD_NAMESPACE_KL(prepare_domain_separation_prefix) +#define mld_sign_pk_from_sk \ + MLD_NAMESPACE_KL(pk_from_sk) MLD_CONTEXT_PARAMETERS_2 + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: mld_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: input random seed + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int externalmu: indicates input message m is + * processed as mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return MLD_ERR_FAIL in that case. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires((externalmu == 0 && (prelen == 0 || memory_no_alias(pre, prelen))) || + (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) + ensures(return_value == 0 ==> *siglen == MLDSA_CRYPTO_BYTES) + ensures(return_value != 0 ==> *siglen == 0) +); + +/************************************************* + * Name: mld_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_signature_extmu + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign + * + * Description: Compute signed message. + * + * Arguments: - uint8_t *sm: pointer to output signed message + * (allocated array with MLDSA_CRYPTO_BYTES + + *mlen bytes), can be equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sm, MLDSA_CRYPTO_BYTES + mlen)) + requires(memory_no_alias(smlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sm, MLDSA_CRYPTO_BYTES + mlen)) + assigns(object_whole(smlen)) + ensures((return_value == 0 && *smlen == MLDSA_CRYPTO_BYTES + mlen) || + (return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL)) +); + +/************************************************* + * Name: mld_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as + * mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(externalmu == 0 || (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + requires(externalmu == 1 || prelen == 0 || memory_no_alias(pre, prelen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_open + * + * Description: Verify signed message. + * + * Arguments: - uint8_t *m: pointer to output message (allocated array + * with smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context tring + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(smlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(m, smlen)) + requires(memory_no_alias(mlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(sm, smlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + assigns(memory_slice(m, smlen)) + assigns(memory_slice(mlen, sizeof(size_t))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and + * verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/* Maximum formatted domain separation message length: + * - Pure ML-DSA: 0x00 || ctxlen || ctx (max 255) + * - HashML-DSA: 0x01 || ctxlen || ctx (max 255) || oid (11) || ph (max 64) */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +__contract__( + requires(ctxlen <= 255) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(hashalg == MLD_PREHASH_NONE || memory_no_alias(ph, phlen)) + requires(memory_no_alias(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + assigns(memory_slice(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + ensures(return_value <= MLD_DOMAIN_SEPARATION_MAX_BYTES) +); + +/************************************************* + * Name: mld_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: input secret + * key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); +#endif /* !MLD_SIGN_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/symmetric.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/symmetric.h new file mode 100644 index 0000000000..bb70f05552 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/symmetric.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_SYMMETRIC_H +#define MLD_SYMMETRIC_H + +#include +#include "cbmc.h" +#include "common.h" + +#include MLD_FIPS202_HEADER_FILE +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#include MLD_FIPS202X4_HEADER_FILE +#endif + +#define MLD_STREAM128_BLOCKBYTES SHAKE128_RATE +#define MLD_STREAM256_BLOCKBYTES SHAKE256_RATE + +#define mld_xof256_ctx mld_shake256ctx +#define mld_xof256_init(CTX) mld_shake256_init(CTX) + +#define mld_xof256_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake256_absorb(CTX, IN, INBYTES); \ + mld_shake256_finalize(CTX); \ + } while (0) + + +#define mld_xof256_release(CTX) mld_shake256_release(CTX) +#define mld_xof256_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake256_squeeze(OUT, (OUTBLOCKS) * SHAKE256_RATE, STATE) + +#define mld_xof128_ctx mld_shake128ctx +#define mld_xof128_init(CTX) mld_shake128_init(CTX) + +#define mld_xof128_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake128_absorb(CTX, IN, INBYTES); \ + mld_shake128_finalize(CTX); \ + } while (0) + +#define mld_xof128_release(CTX) mld_shake128_release(CTX) +#define mld_xof128_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake128_squeeze(OUT, (OUTBLOCKS) * SHAKE128_RATE, STATE) + +#define mld_xof256_x4_ctx mld_shake256x4ctx +#define mld_xof256_x4_init(CTX) mld_shake256x4_init((CTX)) +#define mld_xof256_x4_absorb(CTX, IN, INBYTES) \ + mld_shake256x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof256_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake256x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof256_x4_release(CTX) mld_shake256x4_release((CTX)) + +#define mld_xof128_x4_ctx mld_shake128x4ctx +#define mld_xof128_x4_init(CTX) mld_shake128x4_init((CTX)) +#define mld_xof128_x4_absorb(CTX, IN, INBYTES) \ + mld_shake128x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof128_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake128x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof128_x4_release(CTX) mld_shake128x4_release((CTX)) + +#endif /* !MLD_SYMMETRIC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/sys.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/sys.h new file mode 100644 index 0000000000..1226526420 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/sys.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_SYS_H +#define MLD_SYS_H + +#if !defined(MLD_CONFIG_NO_ASM) && (defined(__GNUC__) || defined(__clang__)) +#define MLD_HAVE_INLINE_ASM +#endif + +/* Try to find endianness, if not forced through CFLAGS already */ +#if !defined(MLD_SYS_LITTLE_ENDIAN) && !defined(MLD_SYS_BIG_ENDIAN) +#if defined(__BYTE_ORDER__) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define MLD_SYS_LITTLE_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define MLD_SYS_BIG_ENDIAN +#else +#error "__BYTE_ORDER__ defined, but don't recognize value." +#endif +#endif /* __BYTE_ORDER__ */ + +/* MSVC does not define __BYTE_ORDER__. However, MSVC only supports + * little endian x86, x86_64, and AArch64. It is, hence, safe to assume + * little endian. */ +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_IX86) || defined(_M_ARM64)) +#define MLD_SYS_LITTLE_ENDIAN +#endif + +#endif /* !MLD_SYS_LITTLE_ENDIAN && !MLD_SYS_BIG_ENDIAN */ + +/* Check if we're running on an AArch64 little endian system. _M_ARM64 is set by + * MSVC. */ +#if defined(__AARCH64EL__) || defined(_M_ARM64) +#define MLD_SYS_AARCH64 +#endif + +/* Check if we're running on an AArch64 big endian system. */ +#if defined(__AARCH64EB__) +#define MLD_SYS_AARCH64_EB +#endif + +#if defined(__x86_64__) +#define MLD_SYS_X86_64 +#if defined(__AVX2__) +#define MLD_SYS_X86_64_AVX2 +#endif +#endif /* __x86_64__ */ + +#if defined(MLD_SYS_LITTLE_ENDIAN) && defined(__powerpc64__) +#define MLD_SYS_PPC64LE +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 +#define MLD_SYS_RISCV64 +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32 +#define MLD_SYS_RISCV32 +#endif + +#if defined(_WIN64) || defined(_WIN32) +#define MLD_SYS_WINDOWS +#endif + +#if defined(__linux__) +#define MLD_SYS_LINUX +#endif + +#if defined(__APPLE__) +#define MLD_SYS_APPLE +#endif + +/* If MLD_FORCE_AARCH64 is set, assert that we're indeed on an AArch64 system. + */ +#if defined(MLD_FORCE_AARCH64) && !defined(MLD_SYS_AARCH64) +#error "MLD_FORCE_AARCH64 is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_AARCH64_EB is set, assert that we're indeed on a big endian + * AArch64 system. */ +#if defined(MLD_FORCE_AARCH64_EB) && !defined(MLD_SYS_AARCH64_EB) +#error \ + "MLD_FORCE_AARCH64_EB is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_X86_64 is set, assert that we're indeed on an X86_64 system. */ +#if defined(MLD_FORCE_X86_64) && !defined(MLD_SYS_X86_64) +#error "MLD_FORCE_X86_64 is set, but we don't seem to be on an X86_64 system." +#endif + +#if defined(MLD_FORCE_PPC64LE) && !defined(MLD_SYS_PPC64LE) +#error "MLD_FORCE_PPC64LE is set, but we don't seem to be on a PPC64LE system." +#endif + +#if defined(MLD_FORCE_RISCV64) && !defined(MLD_SYS_RISCV64) +#error "MLD_FORCE_RISCV64 is set, but we don't seem to be on a RISCV64 system." +#endif + +#if defined(MLD_FORCE_RISCV32) && !defined(MLD_SYS_RISCV32) +#error "MLD_FORCE_RISCV32 is set, but we don't seem to be on a RISCV32 system." +#endif + +/* + * MLD_INLINE: Hint for inlining. + * - MSVC: __inline + * - C99+: inline + * - GCC/Clang C90: __attribute__((unused)) to silence warnings + * - Other C90: empty + */ +#if !defined(MLD_INLINE) +#if defined(_MSC_VER) +#define MLD_INLINE __inline +#elif defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +#define MLD_INLINE inline +#elif defined(__GNUC__) || defined(__clang__) +#define MLD_INLINE __attribute__((unused)) +#else +#define MLD_INLINE +#endif +#endif /* !MLD_INLINE */ + +/* + * MLD_ALWAYS_INLINE: Force inlining. + * - MSVC: __forceinline + * - GCC/Clang C99+: MLD_INLINE __attribute__((always_inline)) + * - Other: MLD_INLINE (no forced inlining) + */ +#if !defined(MLD_ALWAYS_INLINE) +#if defined(_MSC_VER) +#define MLD_ALWAYS_INLINE __forceinline +#elif (defined(__GNUC__) || defined(__clang__)) && \ + (defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)) +#define MLD_ALWAYS_INLINE MLD_INLINE __attribute__((always_inline)) +#else +#define MLD_ALWAYS_INLINE MLD_INLINE +#endif +#endif /* !MLD_ALWAYS_INLINE */ + +#ifndef MLD_STATIC_TESTABLE +#define MLD_STATIC_TESTABLE static +#endif + +/* + * C90 does not have the restrict compiler directive yet. + * We don't use it in C90 builds. + */ +#if !defined(restrict) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define MLD_RESTRICT restrict +#else +#define MLD_RESTRICT +#endif + +#else /* !restrict */ + +#define MLD_RESTRICT restrict +#endif /* restrict */ + +#define MLD_DEFAULT_ALIGN 32 +#define MLD_ALIGN_UP(N) \ + ((((N) + (MLD_DEFAULT_ALIGN - 1)) / MLD_DEFAULT_ALIGN) * MLD_DEFAULT_ALIGN) +#if defined(__GNUC__) +#define MLD_ALIGN __attribute__((aligned(MLD_DEFAULT_ALIGN))) +#elif defined(_MSC_VER) +#define MLD_ALIGN __declspec(align(MLD_DEFAULT_ALIGN)) +#else +#define MLD_ALIGN /* No known support for alignment constraints */ +#endif + + +/* New X86_64 CPUs support Conflow-flow protection using the CET instructions. + * When enabled (through -fcf-protection=), all compilation units (including + * empty ones) need to support CET for this to work. + * For assembly, this means that source files need to signal support for + * CET by setting the appropriate note.gnu.property section. + * This can be achieved by including the header in all assembly file. + * This file also provides the _CET_ENDBR macro which needs to be placed at + * every potential target of an indirect branch. + * If CET is enabled _CET_ENDBR maps to the endbr64 instruction, otherwise + * it is empty. + * In case the compiler does not support CET (e.g., +#define MLD_CET_ENDBR _CET_ENDBR +#else +#define MLD_CET_ENDBR +#endif +#endif /* MLD_SYS_X86_64 */ + +#if defined(MLD_CONFIG_CT_TESTING_ENABLED) && !defined(__ASSEMBLER__) +#include +#define MLD_CT_TESTING_SECRET(ptr, len) \ + VALGRIND_MAKE_MEM_UNDEFINED((ptr), (len)) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) +#else /* MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__ */ +#define MLD_CT_TESTING_SECRET(ptr, len) \ + do \ + { \ + } while (0) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + do \ + { \ + } while (0) +#endif /* !(MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__) */ + +#if defined(__GNUC__) || defined(__clang__) +#define MLD_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_MUST_CHECK_RETURN_VALUE +#endif + + +#if !defined(__ASSEMBLER__) +/* System capability enumeration */ +typedef enum +{ + /* x86_64 */ + MLD_SYS_CAP_AVX2, + /* AArch64 */ + MLD_SYS_CAP_SHA3 +} mld_sys_cap; + +#if !defined(MLD_CONFIG_CUSTOM_CAPABILITY_FUNC) +#include "cbmc.h" + +static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) +__contract__( + ensures(return_value == 0 || return_value == 1) +) +{ + /* By default, we rely on compile-time feature detection/specification: + * If a feature is enabled at compile-time, we assume it is supported by + * the host that the resulting library/binary will be built on. + * If this assumption is not true, you MUST overwrite this function. + * See the documentation of MLD_CONFIG_CUSTOM_CAPABILITY_FUNC in + * mldsa_native_config.h for more information. */ + (void)cap; + return 1; +} +#endif /* !MLD_CONFIG_CUSTOM_CAPABILITY_FUNC */ +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_SYS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/zetas.inc b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/zetas.inc new file mode 100644 index 0000000000..dc3cf15dd3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_deterministic/mldsa_native/src/zetas.inc @@ -0,0 +1,56 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include + +/* + * Table of zeta values used in the reference NTT and inverse NTT. + * See autogen for details. + */ +static const int32_t mld_zetas[MLDSA_N] = { + 0, 25847, -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 2353451, -359251, -2091905, 3119733, -2884855, + 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488, + -1119584, 2619752, -2108549, -2118186, -3859737, -1399561, -3277672, + 1757237, -19422, 4010497, 280005, 2706023, 95776, 3077325, + 3530437, -1661693, -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267, + -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596, + 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, + -2797779, -3930395, -1528703, -3677745, -3041255, -1452451, 3475950, + 2176455, -1585221, -1257611, 1939314, -4083598, -1000202, -3190144, + -3157330, -3632928, 126922, 3412210, -983419, 2147896, 2715295, + -2967645, -3693493, -411027, -2477047, -671102, -1228525, -22981, + -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944, + 508951, 3097992, 44288, -1100098, 904516, 3958618, -3724342, + -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856, + 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, + 1341330, 1285669, -1584928, -812732, -1439742, -3019102, -3881060, + -3628969, 3839961, 2091667, 3407706, 2316500, 3817976, -3342478, + 2244091, -2446433, -3562462, 266997, 2434439, -1235728, 3513181, + -3520352, -3759364, -1197226, -3193378, 900702, 1859098, 909542, + 819034, 495491, -1613174, -43260, -522500, -655327, -3122442, + 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297, + 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, + 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, + 1595974, -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, + 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100, + 1312455, 3306115, -1962642, -1279661, 1917081, -2546312, -1374803, + 1500165, 777191, 2235880, 3406031, -542412, -2831860, -1671176, + -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395, + 2454455, -164721, 1957272, 3369112, 185531, -1207385, -3183426, + 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, + -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, + 472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333, + -260646, -3833893, -2939036, -2235985, -420899, -2286327, 183443, + -976891, 1612842, -3545687, -554416, 3919660, -48306, -1362209, + 3937738, 1400424, -846154, 1976782, +}; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/.gitignore b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/.gitignore new file mode 100644 index 0000000000..14b55464cd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +build/ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/Makefile new file mode 100644 index 0000000000..274ad8ed39 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/Makefile @@ -0,0 +1,119 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +.PHONY: build run clean +.DEFAULT_GOAL := all + +CC ?= gcc + +# Adjust CFLAGS if needed +CFLAGS := \ + -Wall \ + -Wextra \ + -Werror=unused-result \ + -Wpedantic \ + -Werror \ + -Wmissing-prototypes \ + -Wshadow \ + -Wpointer-arith \ + -Wredundant-decls \ + -Wconversion \ + -Wsign-conversion \ + -Wno-long-long \ + -Wno-unknown-pragmas \ + -Wno-unused-command-line-argument \ + -O3 \ + -fomit-frame-pointer \ + -std=c99 \ + -pedantic \ + -MMD \ + $(CFLAGS) + +# If you want to use the native backends, the compiler needs to know about +# the target architecture. Here, we import the default host detection from +# mldsa-native's tests, but you can write your own or specialize accordingly. +AUTO ?= 1 +include auto.mk + +# The following only concerns the cross-compilation tests. +# You can likely ignore the following for your application. +# +# Append cross-prefix for cross compilation +# When called from the root Makefile, CROSS_PREFIX has already been added here +ifeq (,$(findstring $(CROSS_PREFIX),$(CC))) +CC := $(CROSS_PREFIX)$(CC) +endif + +# Part A: +# +# mldsa-native source and header files +# +# If you are not concerned about minimizing for a specific backend, +# you can just include _all_ source files into your build. +# +# In this example, we compile the individual mldsa-native source files directly. +# Alternatively, you can compile the 'monobuild' source file mldsa_native.c. +# See examples/monolithic_build for that. +MLD_SOURCE=$(wildcard \ + mldsa_native/src/*.c \ + mldsa_native/src/**/*.c \ + mldsa_native/src/**/**/*.c \ + mldsa_native/src/**/**/**/*.c) + +INC=-Imldsa_native + +# Part B: +# +# Random number generator +# +# !!! WARNING !!! +# +# The randombytes() implementation used here is for TESTING ONLY. +# You MUST NOT use this implementation outside of testing. +# +# !!! WARNING !!! +RNG_SOURCE=$(wildcard test_only_rng/*.c) + +# Part C: +# +# Your application source code +APP_SOURCE=$(wildcard *.c) + +ALL_SOURCE=$(MLD_SOURCE) $(RNG_SOURCE) $(APP_SOURCE) + +BUILD_DIR=build +BIN=test_binary + +# +# Configuration adjustments +# + +# Pick prefix +CFLAGS += -DMLD_CONFIG_NAMESPACE_PREFIX=mldsa + +BINARY_NAME_FULL_44=$(BUILD_DIR)/$(BIN)44 +BINARY_NAME_FULL_65=$(BUILD_DIR)/$(BIN)65 +BINARY_NAME_FULL_87=$(BUILD_DIR)/$(BIN)87 +BINARIES_FULL=$(BINARY_NAME_FULL_44) $(BINARY_NAME_FULL_65) $(BINARY_NAME_FULL_87) + +$(BINARY_NAME_FULL_44): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=44 +$(BINARY_NAME_FULL_65): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=65 +$(BINARY_NAME_FULL_87): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=87 + +$(BINARIES_FULL): $(ALL_SOURCE) + echo "$@" + mkdir -p $(BUILD_DIR) + $(CC) $(CFLAGS) $(INC) $^ -o $@ + +all: build + +build: $(BINARIES_FULL) + +run: $(BINARIES_FULL) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_44) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_65) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_87) + +clean: + rm -rf $(BUILD_DIR) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/README.md new file mode 100644 index 0000000000..eef6c3817b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/README.md @@ -0,0 +1,45 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Low RAM build + +This directory contains a minimal example for how to build mldsa-native with reduced RAM usage. + +## Use Case + +Use this approach when: +- You are building for an embedded system with tight RAM constraints +- You need to minimize stack usage +- Performance is less critical than memory footprint + +## Configuration + +The `MLD_CONFIG_REDUCE_RAM` option enables optimizations that reduce RAM usage: +- Uses unions for major allocations to reduce stack usage +- Trades some performance for lower memory footprint + +## Components + +1. mldsa-native source tree: [`mldsa/src/`](../../mldsa/src) and [`mldsa/src/fips202/`](../../mldsa/src/fips202) +2. A secure random number generator implementing [`randombytes.h`](../../mldsa/src/randombytes.h) +3. Your application source code + +## Configuration + +The configuration file [mldsa_native_config.h](mldsa_native/mldsa_native_config.h) sets: +- `MLD_CONFIG_PARAMETER_SET`: Security level (44, 65, or 87). Default is 65. +- `MLD_CONFIG_NAMESPACE_PREFIX`: Symbol prefix for the API. Set to `mldsa` in this example. +- `MLD_CONFIG_REDUCE_RAM`: Enables reduced RAM usage optimizations. + +To change the security level, modify `MLD_CONFIG_PARAMETER_SET` in the config file or pass it via CFLAGS. + +## Usage + +```bash +make build # Build the example +make run # Run the example +``` + +## Warning + +The `randombytes()` implementation in `test_only_rng/` is for TESTING ONLY. +You MUST provide a cryptographically secure RNG for production use. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/auto.mk b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/auto.mk new file mode 100644 index 0000000000..5f71942085 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/auto.mk @@ -0,0 +1,178 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# Automatically detect system architecture and set preprocessor flags accordingly +# This file detects host CPU capabilities and combines them with compiler support +# to enable optimal compilation flags. +# +# Compiler feature detection can be overridden by setting the corresponding variable +# on the command line: +# make MK_COMPILER_SUPPORTS_SHA3=0 # Disable SHA3 detection +# make MK_COMPILER_SUPPORTS_AVX2=0 # Disable AVX2 detection +# make MK_COMPILER_SUPPORTS_BMI2=0 # Disable BMI2 detection +# make MK_COMPILER_SUPPORTS_SSE2=0 # Disable SSE2 detection + +ifndef _AUTO_MK +_AUTO_MK := + +# Override ARCH for cross-compilation based on CROSS_PREFIX +ifeq ($(CROSS_PREFIX),) +ARCH := $(shell uname -m) +# Normalize architecture names +ifeq ($(ARCH),arm64) +ARCH := aarch64 +endif +else # CROSS_PREFIX +ifneq ($(findstring x86_64, $(CROSS_PREFIX)),) +ARCH := x86_64 +else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),) +ARCH := aarch64_be +else ifneq ($(findstring aarch64, $(CROSS_PREFIX)),) +ARCH := aarch64 +else ifneq ($(findstring riscv64, $(CROSS_PREFIX)),) +ARCH := riscv64 +else ifneq ($(findstring riscv32, $(CROSS_PREFIX)),) +ARCH := riscv32 +else ifneq ($(findstring powerpc64le, $(CROSS_PREFIX)),) +ARCH := powerpc64le +else ifneq ($(findstring arm-none-eabi-, $(CROSS_PREFIX)),) +ARCH := arm +else +ifeq ($(AUTO),1) +$(warning Unknown cross-compilation prefix $(CROSS_PREFIX), no automatic detection of CFLAGS.) +ARCH := unknown +endif +endif +endif # CROSS_PREFIX + +# x86_64 compiler feature detection +ifeq ($(ARCH),x86_64) + +# Test AVX2 support using C with inline assembly +MK_COMPILER_SUPPORTS_AVX2 ?= $(shell echo 'int main() { __asm__("vpxor %%ymm0, %%ymm1, %%ymm2" ::: "ymm0", "ymm1", "ymm2"); return 0; }' | $(CC) -mavx2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test SSE2 support using C with inline assembly +MK_COMPILER_SUPPORTS_SSE2 ?= $(shell echo 'int main() { __asm__("pxor %%xmm0, %%xmm1" ::: "xmm0", "xmm1"); return 0; }' | $(CC) -msse2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test BMI2 support using C with inline assembly +MK_COMPILER_SUPPORTS_BMI2 ?= $(shell echo 'int main() { __asm__("pdep %%eax, %%ebx, %%ecx" ::: "eax", "ebx", "ecx"); return 0; }' | $(CC) -mbmi2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # x86_64 compiler detection + +# AArch64 compiler feature detection +ifeq ($(ARCH),aarch64) + +# Test SHA3 support (Armv8.4-a+SHA3) using C with inline assembly +MK_COMPILER_SUPPORTS_SHA3 ?= $(shell echo 'int main() { __asm__("eor3 v0.16b, v1.16b, v2.16b, v3.16b" ::: "v0", "v1", "v2", "v3"); return 0; }' | $(CC) -march=armv8.4-a+sha3 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # aarch64 compiler detection + +# Define HOST_PLATFORM if not already defined +HOST_PLATFORM ?= $(shell uname -s)-$(shell uname -m) + +# Helper function to check if host CPU supports a feature +# Usage: $(call check_host_feature,feature_pattern,source_command) +define check_host_feature +$(shell $(2) 2>/dev/null | grep -q "$(1)" && echo 1 || echo 0) +endef + +# x86_64 architecture detection +ifeq ($(ARCH),x86_64) + +# Host CPU feature detection for x86_64 +ifeq ($(HOST_PLATFORM),Linux-x86_64) +# Linux: Use /proc/cpuinfo +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,avx2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,sse2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,bmi2,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-x86_64) +# macOS: Use sysctl +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,AVX2,sysctl -n machdep.cpu.leaf7_features) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,SSE2,sysctl -n machdep.cpu.features) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,BMI2,sysctl -n machdep.cpu.leaf7_features) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_AVX2 := 1 +MK_HOST_SUPPORTS_SSE2 := 1 +MK_HOST_SUPPORTS_BMI2 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_AVX2 := 0 +MK_HOST_SUPPORTS_SSE2 := 0 +MK_HOST_SUPPORTS_BMI2 := 0 +endif # HOST_PLATFORM x86_64 + +endif # x86_64 + +# AArch64 architecture detection +ifeq ($(ARCH),aarch64) + +# Host CPU feature detection for AArch64 +ifeq ($(HOST_PLATFORM),Linux-aarch64) +# Linux: Use /proc/cpuinfo (look for sha3 in Features line) +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,sha3,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-arm64) +# macOS: Use sysctl to check for SHA3 support +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,1,sysctl -n hw.optional.armv8_2_sha3) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_SHA3 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_SHA3 := 0 +endif # HOST_PLATFORM aarch64 + +endif # aarch64 + +# Only apply CFLAGS modifications if AUTO=1 +ifeq ($(AUTO),1) + +# x86_64 CFLAGS configuration +ifeq ($(ARCH),x86_64) +CFLAGS += -DMLD_FORCE_X86_64 + +# Add flags only if both compiler and host support the feature +ifeq ($(MK_COMPILER_SUPPORTS_AVX2)$(MK_HOST_SUPPORTS_AVX2),11) +CFLAGS += -mavx2 +endif + +ifeq ($(MK_COMPILER_SUPPORTS_BMI2)$(MK_HOST_SUPPORTS_BMI2),11) +CFLAGS += -mbmi2 +endif +endif # x86_64 + +# AArch64 CFLAGS configuration +ifeq ($(ARCH),aarch64) +CFLAGS += -DMLD_FORCE_AARCH64 + +# Add SHA3 flags only if both compiler and host support it +ifeq ($(MK_COMPILER_SUPPORTS_SHA3)$(MK_HOST_SUPPORTS_SHA3),11) +CFLAGS += -march=armv8.4-a+sha3 +endif +endif # aarch64 + +# AArch64 Big Endian CFLAGS configuration +ifeq ($(ARCH),aarch64_be) +CFLAGS += -DMLD_FORCE_AARCH64_EB +endif # aarch64_be + +# RISC-V 64-bit CFLAGS configuration +ifeq ($(ARCH),riscv64) +CFLAGS += -DMLD_FORCE_RISCV64 +CFLAGS += -march=rv64gcv +endif # riscv64 + +# RISC-V 32-bit CFLAGS configuration +ifeq ($(ARCH),riscv32) +CFLAGS += -DMLD_FORCE_RISCV32 +endif # riscv32 + +# PowerPC 64-bit Little Endian CFLAGS configuration +ifeq ($(ARCH),powerpc64le) +CFLAGS += -DMLD_FORCE_PPC64LE +endif # powerpc64le + +endif # AUTO=1 + +endif # _AUTO_MK diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/expected_signatures.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/expected_signatures.h new file mode 100644 index 0000000000..d52fbe8d5e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/expected_signatures.h @@ -0,0 +1,890 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef EXPECTED_SIGNATURES_H +#define EXPECTED_SIGNATURES_H + +#include + +/* Expected deterministic signatures for each parameter set + * These are generated using the same test message, context, and deterministic + * RNG as used in the basic example. + * + * The PCT modifies the PRNG state, so the KAT tests don't work. + * We run KAT tests only for disabled PCT. */ +#if !defined(MLD_CONFIG_KEYGEN_PCT) +#if MLD_CONFIG_PARAMETER_SET == 44 +const uint8_t expected_signature[] = { + 0x27, 0x5e, 0xbe, 0x2d, 0x23, 0x1a, 0x76, 0xc5, 0xd9, 0x77, 0xcb, 0x62, + 0x25, 0x04, 0xdb, 0x23, 0x31, 0xa9, 0xa8, 0xcd, 0xbc, 0xde, 0xf2, 0x20, + 0xfd, 0xa7, 0xb5, 0xf5, 0x59, 0xae, 0xe6, 0xdd, 0x62, 0xfa, 0x34, 0x96, + 0x4f, 0x1d, 0xcd, 0x84, 0x82, 0xee, 0xc1, 0x74, 0x96, 0x3d, 0x98, 0xd9, + 0x42, 0x9d, 0xd0, 0x77, 0x9c, 0xf9, 0x9e, 0x0e, 0xa7, 0xcb, 0x70, 0xeb, + 0xe7, 0xcd, 0xce, 0x8c, 0xdc, 0x37, 0x15, 0x95, 0x0e, 0x24, 0x70, 0x4f, + 0x33, 0x6e, 0x4f, 0xad, 0xed, 0x4d, 0xf3, 0xe5, 0x38, 0xc1, 0xcd, 0xbb, + 0xde, 0xf1, 0xd2, 0x0d, 0xd6, 0x6b, 0xa3, 0x68, 0x92, 0x4c, 0x4b, 0x4f, + 0x89, 0xa0, 0xa8, 0xc8, 0x36, 0x93, 0x91, 0x17, 0xe7, 0x16, 0xed, 0xcb, + 0xdc, 0xf6, 0x28, 0x13, 0x32, 0x60, 0x14, 0xe0, 0x28, 0x7a, 0x69, 0x05, + 0x1d, 0xf7, 0x3b, 0xdf, 0x18, 0x0c, 0xaf, 0xba, 0x46, 0xf1, 0x5e, 0xd4, + 0xd3, 0xd0, 0x8e, 0x9a, 0xe2, 0xac, 0xdd, 0x0e, 0x5f, 0xb1, 0x69, 0xe2, + 0x74, 0x77, 0x2e, 0x52, 0xf9, 0x11, 0x3d, 0xd8, 0xe5, 0x36, 0x6f, 0x7d, + 0x7d, 0xde, 0x7c, 0xa7, 0x1d, 0x37, 0xdf, 0x6d, 0x5e, 0xea, 0xc8, 0xc0, + 0x72, 0x3f, 0x79, 0xbd, 0x0b, 0x6d, 0x7f, 0x9a, 0x15, 0x90, 0xda, 0xc1, + 0xae, 0xce, 0xf3, 0x44, 0x35, 0x5e, 0x83, 0x86, 0x7e, 0x89, 0x18, 0xa7, + 0x97, 0x8e, 0x87, 0x7c, 0x15, 0xd2, 0xd2, 0x7e, 0xf2, 0xc8, 0x29, 0x4f, + 0x70, 0x0f, 0xa6, 0xd4, 0x76, 0xe8, 0xdd, 0x7d, 0x7a, 0x2d, 0xfe, 0x0a, + 0x0c, 0x5c, 0xb1, 0xef, 0xec, 0x1a, 0x32, 0xca, 0x87, 0xff, 0x6b, 0xb1, + 0xa0, 0xe1, 0x2e, 0x01, 0x52, 0xb2, 0xb8, 0x74, 0x34, 0xb3, 0xfb, 0x15, + 0x0f, 0x17, 0xca, 0x74, 0xc1, 0xc1, 0x61, 0x86, 0x40, 0x38, 0x58, 0xba, + 0x82, 0x26, 0x66, 0x33, 0xa4, 0x52, 0xf3, 0xb5, 0x36, 0x60, 0xd8, 0x5a, + 0x8d, 0x9d, 0x28, 0x18, 0x3a, 0x68, 0x34, 0x2a, 0xa2, 0xe2, 0xb5, 0x39, + 0xed, 0x7d, 0xe5, 0xbe, 0x46, 0xb9, 0x04, 0x0c, 0xf3, 0xef, 0x88, 0x6e, + 0x9d, 0x6f, 0x23, 0xe2, 0x44, 0xe5, 0x2e, 0x3a, 0x7a, 0x1d, 0x49, 0x0f, + 0xdd, 0xcd, 0xd6, 0x4e, 0x0d, 0x0b, 0xc3, 0x35, 0xf2, 0xd1, 0x5d, 0x73, + 0x5d, 0x07, 0xca, 0x5c, 0xbd, 0x14, 0xec, 0x57, 0xb3, 0xbd, 0x37, 0xe7, + 0xdf, 0x06, 0x7d, 0xe0, 0x58, 0x4a, 0xcf, 0x7a, 0xc5, 0xa7, 0x24, 0x62, + 0x6f, 0x09, 0x75, 0x69, 0x74, 0x7f, 0xdf, 0xc8, 0x69, 0x5c, 0x20, 0x10, + 0x3a, 0xe8, 0x01, 0x12, 0xa3, 0xfb, 0xda, 0x4c, 0x3a, 0x0d, 0x3c, 0x3e, + 0x26, 0xe0, 0xa6, 0x7f, 0xb2, 0x6b, 0x0b, 0x68, 0x0a, 0x68, 0x86, 0xb1, + 0xfa, 0x61, 0x3a, 0xe8, 0x77, 0xdc, 0x42, 0xf7, 0xf4, 0x39, 0x9a, 0x40, + 0x58, 0x71, 0xc7, 0x0f, 0xf4, 0x0e, 0xc5, 0x1e, 0xe0, 0x28, 0x45, 0x7d, + 0xba, 0x84, 0xe4, 0x34, 0x69, 0xf9, 0xa5, 0x8a, 0x80, 0x43, 0xc0, 0x8d, + 0x04, 0x33, 0x43, 0xb8, 0xd7, 0x5d, 0x93, 0xed, 0x0f, 0x31, 0x6a, 0x4d, + 0xbf, 0xb7, 0x44, 0x41, 0x1b, 0xd4, 0xac, 0x9d, 0x83, 0x66, 0x08, 0x92, + 0xad, 0x3c, 0x0e, 0x1a, 0xe8, 0xd4, 0xe1, 0x5c, 0x63, 0xcf, 0x27, 0x48, + 0x5a, 0x8f, 0xc5, 0x6f, 0x83, 0x6b, 0x6f, 0xe8, 0xda, 0x1f, 0xba, 0xe9, + 0x7e, 0x11, 0xab, 0x8b, 0x4e, 0xc1, 0x9e, 0x23, 0x69, 0x1f, 0x42, 0x40, + 0xad, 0xbb, 0xfb, 0x4f, 0xe2, 0x50, 0xc9, 0x46, 0xe7, 0x15, 0x15, 0xf8, + 0x61, 0x09, 0x2a, 0x0b, 0x37, 0x43, 0xd4, 0x98, 0x5f, 0xc8, 0x4d, 0x06, + 0xe7, 0x0c, 0x3f, 0x83, 0x59, 0xd5, 0xcd, 0x2d, 0xde, 0x1e, 0x3a, 0x87, + 0x4e, 0xf7, 0x0a, 0x3c, 0x84, 0x72, 0x47, 0x11, 0x02, 0x6c, 0xe8, 0x93, + 0xcd, 0x24, 0xe9, 0x23, 0x86, 0x78, 0x53, 0xe0, 0xc6, 0x2f, 0xba, 0xa7, + 0xed, 0xaf, 0xba, 0x42, 0x80, 0x0d, 0xe6, 0xae, 0xda, 0xed, 0xbc, 0x65, + 0x21, 0x6d, 0x13, 0x90, 0x61, 0xb4, 0x05, 0x7b, 0x07, 0x86, 0xd7, 0x89, + 0x30, 0x9c, 0xc1, 0x9a, 0x41, 0x4d, 0xe8, 0x2b, 0x35, 0x21, 0x3a, 0x8a, + 0x60, 0x83, 0x1a, 0x97, 0x10, 0x98, 0xb6, 0xe1, 0x6b, 0xb5, 0xb1, 0xa1, + 0x36, 0x34, 0x60, 0x1b, 0x96, 0x5d, 0x1f, 0x2a, 0xd8, 0xf2, 0x94, 0xdd, + 0x58, 0x3d, 0x0f, 0xbe, 0x9d, 0xfc, 0xf5, 0x24, 0xb1, 0xd2, 0xc3, 0x36, + 0xef, 0xdb, 0x8e, 0x97, 0x3c, 0x9a, 0x4f, 0x48, 0xe3, 0x84, 0x91, 0xd8, + 0x39, 0x91, 0xf6, 0x55, 0xeb, 0x62, 0x51, 0x3d, 0x8f, 0x55, 0x60, 0x5e, + 0x00, 0xe0, 0xd2, 0xc7, 0x66, 0x51, 0xf1, 0xe2, 0xb7, 0x43, 0xc3, 0xe6, + 0x12, 0x9a, 0xe5, 0x84, 0xe0, 0x10, 0x76, 0xc7, 0x75, 0x6e, 0xa6, 0xee, + 0x11, 0xe4, 0xaf, 0xbd, 0x8a, 0x4f, 0x1d, 0x05, 0x29, 0x4f, 0xce, 0xa5, + 0x73, 0x92, 0x57, 0x7e, 0x0d, 0x11, 0xbc, 0xf8, 0x74, 0x4d, 0xf7, 0xb9, + 0x40, 0x0d, 0x5a, 0xa1, 0x19, 0x76, 0x4a, 0xae, 0x21, 0x16, 0xd4, 0x3f, + 0x76, 0xbf, 0x27, 0xbd, 0x2f, 0xe4, 0x25, 0x21, 0x00, 0x4e, 0xcc, 0x7c, + 0xc6, 0x57, 0xa4, 0xbf, 0xf1, 0x56, 0x90, 0xe0, 0xa4, 0xa3, 0xee, 0xcf, + 0x43, 0x4f, 0xda, 0x77, 0x47, 0x51, 0x79, 0x6a, 0x29, 0xb4, 0x2c, 0xdf, + 0xca, 0x47, 0xcb, 0xb8, 0x82, 0x7e, 0x44, 0x62, 0x9b, 0x8f, 0x61, 0x7b, + 0x3a, 0x93, 0x82, 0x1f, 0x69, 0xb7, 0xb1, 0xa6, 0x2c, 0xe1, 0xb2, 0x65, + 0xa0, 0x6d, 0x6f, 0xe4, 0x79, 0xd8, 0x30, 0xe0, 0xee, 0xd8, 0x83, 0x01, + 0xb2, 0x1f, 0x5c, 0x90, 0x44, 0x86, 0x48, 0x11, 0xf9, 0x11, 0xff, 0xea, + 0x45, 0x43, 0xae, 0x8a, 0x6b, 0x99, 0xf2, 0x1f, 0x02, 0x51, 0x4a, 0x35, + 0x02, 0x34, 0xd3, 0xe8, 0xda, 0xb1, 0x4b, 0xe3, 0xa5, 0x60, 0xce, 0x67, + 0xe3, 0x62, 0x59, 0xfc, 0x00, 0x0a, 0xe2, 0xfe, 0x7b, 0x1e, 0xe6, 0xf5, + 0x75, 0x19, 0x9b, 0x5e, 0xcb, 0xe6, 0xf5, 0x80, 0x9e, 0x3c, 0xb8, 0x54, + 0xd6, 0x0b, 0xfd, 0x48, 0xe0, 0xfa, 0x82, 0x2b, 0x5b, 0x26, 0xf9, 0x49, + 0xaf, 0xbe, 0x9c, 0x78, 0x73, 0xce, 0xc5, 0x65, 0xe2, 0x94, 0x2b, 0xd9, + 0xd0, 0x27, 0x3a, 0x66, 0x3e, 0xe2, 0xe0, 0x10, 0x79, 0x3d, 0xde, 0xc8, + 0x47, 0xdb, 0x1e, 0xc3, 0xe7, 0x51, 0xae, 0x59, 0xeb, 0x38, 0x66, 0x63, + 0x40, 0x8f, 0xbe, 0x1e, 0xb2, 0x2b, 0xeb, 0x64, 0x5f, 0xdd, 0x24, 0xc4, + 0x5a, 0x25, 0x59, 0xa2, 0xda, 0x4f, 0xdf, 0xf8, 0xb0, 0xb0, 0xf7, 0xcd, + 0x1f, 0x14, 0xcd, 0x09, 0x48, 0x70, 0x27, 0x1b, 0xde, 0xc4, 0xf0, 0xf3, + 0x56, 0x97, 0x8a, 0xb7, 0xf4, 0x19, 0x76, 0xe3, 0x9a, 0x33, 0x55, 0xfe, + 0x93, 0x68, 0xca, 0x1f, 0x3d, 0x44, 0x86, 0x39, 0x5d, 0x84, 0x58, 0x50, + 0xf2, 0xf1, 0xea, 0x4a, 0x5c, 0x1c, 0x74, 0xf0, 0x4b, 0xa5, 0x9c, 0x30, + 0xa0, 0x14, 0x1a, 0x80, 0xe0, 0xde, 0x3e, 0xae, 0x7f, 0x10, 0x18, 0x4a, + 0x1e, 0x9e, 0x6b, 0x75, 0x1a, 0xca, 0x08, 0x4e, 0x61, 0x72, 0x43, 0x9b, + 0x18, 0x4d, 0x2c, 0xd8, 0xb4, 0xc9, 0xea, 0x00, 0xb0, 0xdf, 0x1b, 0xcb, + 0x03, 0xc3, 0x7a, 0x27, 0xff, 0x41, 0x9d, 0xf9, 0xfd, 0xb3, 0x0c, 0xc0, + 0x48, 0x5d, 0x7c, 0xae, 0x5a, 0x72, 0x69, 0x93, 0x68, 0xe1, 0x9e, 0x9f, + 0x1f, 0x5c, 0x0a, 0x60, 0x90, 0x1a, 0x8e, 0x5a, 0x30, 0xd4, 0x2c, 0xbd, + 0xe1, 0x20, 0x51, 0xbc, 0x1c, 0x50, 0xb5, 0xf7, 0x42, 0x23, 0x35, 0x0f, + 0x92, 0xe2, 0xbb, 0x2a, 0x04, 0xa7, 0xde, 0x2e, 0x25, 0xfa, 0xed, 0x20, + 0x83, 0x9c, 0xd4, 0x56, 0xe0, 0x4d, 0x8d, 0x79, 0xa5, 0xa0, 0x6f, 0x49, + 0x62, 0x82, 0x9a, 0xa7, 0x4e, 0x54, 0x95, 0x0a, 0xc6, 0x5e, 0x27, 0x65, + 0x6d, 0x11, 0x2b, 0x35, 0x72, 0x34, 0x48, 0xd2, 0xe4, 0x9e, 0x07, 0x7d, + 0x03, 0x27, 0x15, 0x93, 0x55, 0x5c, 0x32, 0x43, 0xdb, 0x34, 0x8d, 0xbd, + 0x8d, 0x88, 0xa5, 0x24, 0x07, 0x93, 0x89, 0x37, 0xb9, 0x17, 0x15, 0xad, + 0xc7, 0x68, 0x86, 0x63, 0x0f, 0x10, 0x53, 0x8f, 0x40, 0xd3, 0x7b, 0x22, + 0x2b, 0x1a, 0x4c, 0xcb, 0x4f, 0x51, 0xf1, 0x3b, 0x19, 0xb8, 0x42, 0x53, + 0xaf, 0xf6, 0xb9, 0x57, 0x7f, 0xba, 0x8d, 0xb8, 0xb7, 0x3b, 0xe3, 0xc5, + 0xab, 0x4a, 0x26, 0x21, 0x6e, 0xce, 0x27, 0xb8, 0xc3, 0x99, 0x56, 0x14, + 0xdd, 0x5b, 0x61, 0x82, 0xbf, 0xd3, 0xc8, 0x76, 0xee, 0x22, 0xaf, 0x21, + 0x21, 0x1d, 0x4e, 0x33, 0xb5, 0x43, 0x3a, 0xfb, 0x91, 0xa0, 0xaa, 0xe3, + 0x10, 0x4a, 0x50, 0x42, 0xd4, 0x5f, 0x92, 0x0e, 0x71, 0x60, 0x4f, 0xaa, + 0xef, 0x66, 0x45, 0xfe, 0xf7, 0xc8, 0xb0, 0x73, 0x75, 0x91, 0x0b, 0x86, + 0x40, 0xa5, 0x02, 0x28, 0xf7, 0xe0, 0x1f, 0x5d, 0xe6, 0xe3, 0xa4, 0x57, + 0xbd, 0x29, 0xaa, 0x53, 0xae, 0x35, 0x30, 0x78, 0x73, 0xd6, 0xb7, 0x01, + 0x9d, 0x13, 0x50, 0xf6, 0x39, 0xa2, 0x3e, 0x03, 0x04, 0xaa, 0x6d, 0xcf, + 0x6b, 0xff, 0x9a, 0xbe, 0x3e, 0x0a, 0xd4, 0x20, 0xce, 0x42, 0x1f, 0xca, + 0x2f, 0xd3, 0x2c, 0xd1, 0xf4, 0xd2, 0x50, 0xd3, 0xa2, 0xc1, 0x1e, 0x87, + 0xbf, 0xeb, 0xb8, 0xa8, 0xd4, 0x1c, 0x96, 0xb8, 0x8e, 0xbe, 0x35, 0x5f, + 0x08, 0x28, 0x20, 0x2b, 0xdc, 0xa4, 0xf5, 0xf6, 0xde, 0xca, 0x1e, 0xcb, + 0x93, 0x3b, 0x64, 0x79, 0x00, 0x3c, 0x8d, 0xbb, 0x5c, 0x7a, 0x40, 0x14, + 0x58, 0x12, 0xa4, 0xf7, 0x6e, 0x51, 0xfb, 0xe7, 0x6f, 0x49, 0x5b, 0xc2, + 0xc9, 0x05, 0x38, 0x9c, 0x08, 0x78, 0x71, 0x27, 0x2b, 0xf5, 0xbf, 0xd6, + 0x38, 0xaa, 0x45, 0xe1, 0xe1, 0x4c, 0xfb, 0xfd, 0xb7, 0xe6, 0xcf, 0xad, + 0x9e, 0x56, 0xaf, 0x12, 0x12, 0x98, 0xe6, 0x38, 0xaa, 0xee, 0xdb, 0x9e, + 0xca, 0xe1, 0x79, 0x6d, 0x44, 0xfb, 0x19, 0x50, 0x92, 0x00, 0x06, 0x2c, + 0x24, 0x71, 0x6c, 0x34, 0x45, 0xac, 0xf9, 0x82, 0x66, 0xa8, 0x63, 0x80, + 0xa8, 0x5b, 0x21, 0x3c, 0x36, 0x71, 0x93, 0x40, 0x7b, 0xff, 0xa2, 0xd0, + 0x72, 0xb4, 0x66, 0xfa, 0xfc, 0xa0, 0xee, 0xca, 0x15, 0x73, 0x52, 0xe7, + 0x9d, 0x11, 0xd3, 0xbc, 0xab, 0x37, 0x31, 0x0e, 0xaf, 0xdc, 0x05, 0x30, + 0x79, 0x8c, 0x25, 0x75, 0x5c, 0x60, 0xc7, 0x9a, 0xfc, 0x88, 0xea, 0xe6, + 0x09, 0x9f, 0xd1, 0x4f, 0x13, 0xf4, 0x41, 0x54, 0x5b, 0x7a, 0xe4, 0x49, + 0x3c, 0x0f, 0x15, 0xe9, 0xa4, 0x85, 0xb2, 0x92, 0x07, 0xea, 0xea, 0x7c, + 0xc1, 0x6d, 0xa9, 0x03, 0xb3, 0x31, 0xce, 0x1e, 0x82, 0xca, 0x9e, 0x3c, + 0x88, 0x88, 0xc1, 0x04, 0x5f, 0xbe, 0xd5, 0x94, 0x0d, 0x67, 0x98, 0x27, + 0xd0, 0x0f, 0x43, 0xf3, 0xb3, 0xfc, 0xff, 0x24, 0xa2, 0x1e, 0x17, 0x06, + 0xb0, 0x52, 0x16, 0x7c, 0xd8, 0x49, 0x74, 0x51, 0xcf, 0x2d, 0x36, 0x16, + 0xb0, 0x88, 0xb2, 0x2b, 0x1d, 0x72, 0x70, 0xab, 0xe2, 0xf6, 0x5f, 0xa5, + 0x2d, 0x4e, 0xd1, 0x42, 0x3c, 0x83, 0x84, 0xb2, 0x56, 0xeb, 0x8d, 0xce, + 0x33, 0x46, 0xdb, 0x3d, 0x4f, 0x97, 0xea, 0x37, 0x5e, 0x0d, 0xd7, 0x4c, + 0x9a, 0x7e, 0xc9, 0x0e, 0x69, 0x4d, 0x97, 0x15, 0x1e, 0x09, 0xbe, 0x7e, + 0xff, 0xe8, 0xf5, 0xab, 0xe9, 0xe7, 0xed, 0x4b, 0x41, 0xa5, 0xf2, 0x2a, + 0x24, 0x48, 0x8b, 0x72, 0x4b, 0x9d, 0xcf, 0x45, 0xdb, 0xc0, 0xaf, 0xa8, + 0x0f, 0x0f, 0x67, 0x37, 0xd3, 0x8b, 0xe1, 0x67, 0x90, 0xd8, 0x1c, 0x58, + 0x36, 0x46, 0x51, 0x52, 0xea, 0xb4, 0x75, 0xb1, 0xcd, 0xc5, 0x39, 0x16, + 0xe0, 0xec, 0x16, 0xf7, 0xf8, 0x0f, 0x5d, 0x13, 0x84, 0x62, 0x34, 0x86, + 0x42, 0x05, 0xa8, 0x08, 0x84, 0xa9, 0x77, 0x12, 0xc1, 0x56, 0xdd, 0x28, + 0xde, 0x39, 0x33, 0x21, 0x3d, 0xbd, 0x94, 0xce, 0xe4, 0xb3, 0x17, 0x9b, + 0x09, 0x20, 0xf0, 0x25, 0xce, 0x00, 0x34, 0x8e, 0x12, 0x94, 0x74, 0x0b, + 0x16, 0xa1, 0x60, 0x76, 0x24, 0xf0, 0xbf, 0xe3, 0x3a, 0x83, 0x8f, 0x40, + 0x47, 0x2e, 0x1c, 0xd5, 0x35, 0x25, 0x87, 0xb3, 0x11, 0xdc, 0x98, 0xb0, + 0xa6, 0x5f, 0x6a, 0x05, 0x1d, 0x06, 0x8d, 0xe8, 0xb0, 0x98, 0xf0, 0x43, + 0x29, 0x84, 0xe4, 0xef, 0x34, 0x67, 0x74, 0x64, 0xe8, 0xb8, 0xf0, 0xd4, + 0x9e, 0xc1, 0x3f, 0x5f, 0xeb, 0xe0, 0x9b, 0x37, 0xf8, 0x75, 0x46, 0x47, + 0xa5, 0x3e, 0x42, 0x20, 0x50, 0xc4, 0x5d, 0xf3, 0xdf, 0x4e, 0xf8, 0x0e, + 0x1e, 0x15, 0x10, 0x3e, 0xf1, 0x68, 0xad, 0x87, 0xad, 0xe5, 0x45, 0x5e, + 0x22, 0xba, 0x2e, 0x51, 0xa0, 0xbf, 0xdc, 0x87, 0xca, 0xe4, 0x1f, 0x2f, + 0x2c, 0xae, 0xa9, 0x14, 0xd7, 0xdd, 0x01, 0xa8, 0x4f, 0x43, 0xcb, 0x84, + 0x92, 0xbf, 0xf9, 0x3d, 0xf0, 0x6b, 0x19, 0x43, 0xb0, 0xdf, 0xff, 0x94, + 0x76, 0xe2, 0x84, 0xf9, 0x31, 0x88, 0x7e, 0xc6, 0x87, 0x58, 0xbe, 0x5d, + 0x8b, 0xf8, 0xb5, 0xdc, 0x95, 0x16, 0x5f, 0xa1, 0x2c, 0xe8, 0x53, 0x36, + 0x64, 0xf5, 0x5d, 0xa0, 0x74, 0x12, 0x78, 0x59, 0x73, 0x69, 0x5a, 0x2b, + 0x36, 0x4a, 0xff, 0x5b, 0xef, 0x49, 0x2c, 0xb2, 0x9e, 0x59, 0xf0, 0x39, + 0x56, 0xe1, 0xd0, 0x1a, 0x05, 0xb2, 0x7c, 0xd1, 0x40, 0x09, 0xdf, 0x00, + 0xc9, 0x15, 0x53, 0xa2, 0xda, 0x84, 0xb5, 0x85, 0x05, 0x76, 0xa6, 0x1b, + 0xcb, 0x06, 0xb2, 0xc8, 0xa0, 0xc5, 0x23, 0x8f, 0xb0, 0xe8, 0xf5, 0xd9, + 0xd0, 0x19, 0x29, 0xfe, 0x2d, 0x9a, 0x57, 0x76, 0x5f, 0xf2, 0xef, 0x71, + 0x16, 0xee, 0x28, 0x7b, 0xe4, 0x48, 0xeb, 0xda, 0xe0, 0xd5, 0xbc, 0x0e, + 0x46, 0x6b, 0x06, 0x5d, 0xe5, 0x91, 0x2d, 0xcb, 0xc4, 0x53, 0xa6, 0x16, + 0xd5, 0xe7, 0xd8, 0xf1, 0xdd, 0x4f, 0xbb, 0xcc, 0x55, 0x67, 0x19, 0x98, + 0x94, 0x95, 0x5e, 0xd6, 0xf5, 0xf7, 0xe8, 0x6a, 0xf7, 0x20, 0x86, 0x3a, + 0x43, 0xbf, 0xe9, 0xec, 0x6b, 0x33, 0x49, 0x19, 0x43, 0xfb, 0xeb, 0x3f, + 0xf4, 0x9d, 0x29, 0x66, 0xb9, 0x6e, 0xb5, 0x15, 0x4b, 0x8d, 0x3c, 0x3c, + 0xfa, 0xf2, 0x87, 0xba, 0x61, 0x11, 0x40, 0xe6, 0xb4, 0x6f, 0xf5, 0xe1, + 0x24, 0x32, 0x69, 0x3e, 0xff, 0xf7, 0xbc, 0xee, 0x82, 0xf2, 0x9e, 0x6d, + 0x3f, 0x6c, 0xcc, 0x0f, 0x4f, 0xc3, 0xf1, 0xdb, 0x1e, 0x81, 0xd7, 0x9b, + 0x22, 0xa8, 0xa7, 0x36, 0x6d, 0xa9, 0x6f, 0x46, 0x1a, 0xa7, 0xff, 0x00, + 0x4b, 0xd8, 0xab, 0xe7, 0x50, 0x3b, 0xe9, 0xc0, 0x57, 0xec, 0x8d, 0x0c, + 0xa0, 0xee, 0x8c, 0x2a, 0x74, 0xf2, 0x94, 0xf9, 0x0c, 0x20, 0x14, 0xd9, + 0xad, 0x0d, 0x4e, 0xac, 0x35, 0x44, 0x59, 0x28, 0x24, 0x31, 0x32, 0xaa, + 0x6d, 0xc2, 0x13, 0xb9, 0xee, 0x75, 0x0c, 0x5f, 0x39, 0xef, 0x31, 0xca, + 0x28, 0x48, 0x56, 0x59, 0xfb, 0xa8, 0xd8, 0x2b, 0x70, 0x61, 0x22, 0x43, + 0x43, 0xb9, 0x60, 0x44, 0xeb, 0xf8, 0x98, 0x87, 0x25, 0x84, 0xa2, 0xaa, + 0x37, 0xd4, 0xb8, 0xd6, 0x3d, 0xa3, 0xa1, 0x4a, 0x81, 0xc2, 0xa9, 0xea, + 0xa2, 0xd6, 0x63, 0x76, 0x50, 0xeb, 0xcd, 0x19, 0x40, 0xb1, 0x7c, 0xf6, + 0xc1, 0x44, 0x01, 0x25, 0xe0, 0xdd, 0xb8, 0x39, 0xef, 0x46, 0x3d, 0x50, + 0x33, 0xed, 0xb1, 0x63, 0x65, 0xd7, 0x50, 0xe7, 0x95, 0xba, 0xab, 0xa7, + 0x14, 0xe5, 0x60, 0xcb, 0x81, 0x6e, 0x88, 0x3c, 0x06, 0x6e, 0x7d, 0x8e, + 0xe7, 0xbb, 0xa5, 0xc2, 0xbd, 0xae, 0x46, 0x8f, 0x43, 0x04, 0x29, 0xe6, + 0x17, 0x38, 0x05, 0x2d, 0x97, 0x93, 0x5b, 0xf9, 0xef, 0x4d, 0x2e, 0x75, + 0x6c, 0x69, 0xba, 0x08, 0xf2, 0x21, 0x1e, 0x21, 0xe6, 0x8a, 0x5b, 0x8c, + 0xd4, 0x8e, 0xde, 0x64, 0x9b, 0x9d, 0x54, 0x58, 0x65, 0x3e, 0xdd, 0x8a, + 0x1e, 0x81, 0x4e, 0x45, 0xe8, 0xfb, 0x20, 0xc3, 0x3a, 0xf0, 0x50, 0x1e, + 0x8a, 0x18, 0xea, 0x2b, 0xf5, 0xe1, 0xa6, 0xb6, 0xc8, 0xa0, 0x02, 0x3d, + 0x6e, 0xfa, 0x0b, 0x51, 0x95, 0x4e, 0x4c, 0x11, 0xb0, 0xc4, 0x62, 0x58, + 0xa6, 0x9c, 0x13, 0x4e, 0xbe, 0xc9, 0x29, 0x93, 0x29, 0x15, 0x5f, 0xaf, + 0x0e, 0xc3, 0xb3, 0x26, 0x3f, 0xdc, 0x4c, 0x33, 0xb8, 0x4b, 0x11, 0xae, + 0x1f, 0xd7, 0x05, 0x39, 0xcf, 0xfe, 0xc3, 0x6d, 0xf0, 0xc0, 0x77, 0x02, + 0xb8, 0x9b, 0x3d, 0x1b, 0x3d, 0x72, 0xfe, 0x7e, 0x18, 0x60, 0x9b, 0xc4, + 0x8b, 0xac, 0x25, 0x6d, 0x3b, 0x80, 0x34, 0xbc, 0x51, 0xaf, 0xf6, 0xff, + 0x66, 0x98, 0x86, 0x6e, 0x9e, 0x9a, 0xfe, 0x6d, 0x21, 0x4d, 0xf1, 0x58, + 0x3e, 0x3e, 0x43, 0xe3, 0x7e, 0x40, 0xb0, 0xb3, 0xd8, 0x12, 0xa5, 0xce, + 0x09, 0x41, 0x8c, 0x1d, 0x73, 0xcd, 0xfc, 0x63, 0xed, 0xeb, 0x08, 0x1e, + 0x34, 0xfb, 0xed, 0x75, 0xb7, 0x86, 0x84, 0x7c, 0x80, 0xe9, 0xe4, 0xa3, + 0x1c, 0x4a, 0x0d, 0x11, 0x16, 0x24, 0xb2, 0xb1, 0x99, 0xe5, 0xe3, 0x2e, + 0x2f, 0x70, 0xcd, 0x1e, 0x35, 0x14, 0x79, 0xba, 0xa2, 0x51, 0x7a, 0x29, + 0x5c, 0x75, 0x8f, 0xdd, 0x22, 0xdf, 0xb2, 0x64, 0xd9, 0x95, 0x11, 0x33, + 0x97, 0xee, 0x69, 0x42, 0x01, 0x96, 0x98, 0x1b, 0x43, 0xc2, 0xec, 0xf9, + 0xb0, 0xdb, 0x69, 0x34, 0xab, 0x98, 0x1b, 0xb2, 0x04, 0x05, 0x14, 0x1d, + 0x25, 0x2f, 0x32, 0x41, 0x50, 0x51, 0x55, 0x62, 0x6d, 0x78, 0x7f, 0x8b, + 0xbb, 0xc2, 0xcd, 0xcf, 0xe4, 0xed, 0x04, 0x1f, 0x25, 0x30, 0x43, 0x64, + 0x69, 0x7c, 0x87, 0xa3, 0xa9, 0xb1, 0xc1, 0xd1, 0xdc, 0x01, 0x10, 0x1d, + 0x27, 0x3f, 0x5c, 0x5d, 0x75, 0x82, 0x9b, 0xaa, 0xb3, 0xe8, 0x0c, 0x11, + 0x1f, 0x24, 0x38, 0x41, 0x45, 0x54, 0x5f, 0x69, 0x85, 0x8d, 0x93, 0x9e, + 0xc5, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x25, 0x32, 0x42}; +#elif MLD_CONFIG_PARAMETER_SET == 65 +const uint8_t expected_signature[] = { + 0x8b, 0x6f, 0x79, 0x00, 0xcc, 0x79, 0x57, 0xee, 0x16, 0x86, 0x87, 0xd5, + 0xcf, 0xb6, 0x90, 0x2c, 0xc6, 0x30, 0xeb, 0x8d, 0x39, 0xae, 0x9b, 0xf1, + 0x66, 0xe0, 0xd6, 0x93, 0xa5, 0x4e, 0x26, 0x9b, 0x96, 0x8f, 0xd1, 0x46, + 0x97, 0xbe, 0x71, 0x1c, 0xf3, 0xa5, 0xe5, 0xae, 0x8d, 0x4b, 0xf2, 0xe6, + 0x48, 0x8f, 0xe9, 0x5e, 0x07, 0xef, 0xe4, 0xbb, 0x39, 0xc1, 0xc9, 0x3c, + 0xc3, 0x0b, 0xfb, 0x2a, 0x29, 0x06, 0xfe, 0x01, 0xcb, 0x63, 0x83, 0x10, + 0xa8, 0xc8, 0xa0, 0x29, 0xa5, 0x80, 0xeb, 0xbd, 0xa9, 0xd9, 0x0b, 0x61, + 0xbc, 0xce, 0x11, 0x55, 0x66, 0x12, 0xc7, 0x5b, 0xd2, 0x7a, 0x5a, 0xc8, + 0xab, 0xab, 0xbf, 0x3a, 0x1f, 0x96, 0x1a, 0x70, 0xcb, 0x41, 0x5f, 0xc8, + 0xb7, 0x09, 0x22, 0x98, 0x9b, 0xb8, 0xf7, 0x2d, 0x49, 0x65, 0x1d, 0x09, + 0x8b, 0x70, 0xb5, 0x42, 0xc9, 0x89, 0x5b, 0x74, 0xb4, 0x28, 0x82, 0x01, + 0x53, 0x12, 0x3e, 0x23, 0xf6, 0x54, 0xf8, 0x51, 0x12, 0x4b, 0x02, 0x3a, + 0x7e, 0xb6, 0x1f, 0xac, 0xa0, 0xe6, 0x6f, 0xf8, 0x61, 0x82, 0xe4, 0xfb, + 0x96, 0x2a, 0xd2, 0xaf, 0x3c, 0xea, 0x6e, 0xdc, 0x18, 0x8a, 0x5d, 0x90, + 0xda, 0xa2, 0x5d, 0xa7, 0x8f, 0x5b, 0x50, 0x46, 0xaf, 0x8c, 0x17, 0x6a, + 0x4c, 0x39, 0xfc, 0x31, 0x4c, 0x4b, 0xc2, 0x57, 0x66, 0x61, 0x98, 0xbf, + 0xe6, 0xfb, 0x54, 0x96, 0xd3, 0x70, 0xb8, 0xaf, 0xcd, 0x8b, 0xcc, 0x00, + 0x07, 0x92, 0x15, 0xc2, 0xbb, 0x48, 0xbb, 0xc6, 0xb7, 0xb5, 0x58, 0x8c, + 0xfc, 0xf0, 0xda, 0x6a, 0x0d, 0xf7, 0x1d, 0x7d, 0xc6, 0x27, 0x26, 0x1a, + 0x99, 0xc5, 0x2f, 0xf8, 0x97, 0x65, 0x43, 0x86, 0xd6, 0x25, 0x23, 0x2b, + 0x06, 0x8f, 0x12, 0xa1, 0xae, 0xbb, 0x58, 0x34, 0x25, 0xec, 0x5b, 0x68, + 0xa4, 0xe1, 0x03, 0xfc, 0x26, 0xa2, 0xd6, 0x2b, 0x61, 0x10, 0x47, 0xbd, + 0x16, 0xe5, 0xca, 0x4a, 0xce, 0xed, 0x89, 0x09, 0x1a, 0xed, 0x22, 0xc1, + 0xca, 0x44, 0xe3, 0xef, 0x72, 0x34, 0xab, 0xab, 0x61, 0x5c, 0x9f, 0x5f, + 0xb5, 0xf5, 0xe8, 0x2d, 0x89, 0xea, 0x4b, 0x40, 0x65, 0x57, 0x8b, 0xa2, + 0x95, 0x40, 0x9c, 0x72, 0xc0, 0x46, 0x69, 0x45, 0x06, 0xf6, 0x07, 0x5b, + 0x2d, 0xa5, 0x46, 0xca, 0x5d, 0xfb, 0x40, 0xb7, 0x48, 0x59, 0x5b, 0xe2, + 0x1b, 0x38, 0xb2, 0x15, 0x75, 0x66, 0x67, 0x58, 0x00, 0x3f, 0xde, 0x8a, + 0x63, 0x13, 0x34, 0x6a, 0x30, 0xca, 0xb4, 0xd5, 0x3e, 0xe0, 0x6d, 0x14, + 0xb8, 0x9a, 0x48, 0xef, 0xfd, 0xbd, 0x6d, 0x20, 0x11, 0x4d, 0x25, 0xe5, + 0xab, 0x15, 0x8d, 0xe5, 0x91, 0xbc, 0xc6, 0x69, 0x8a, 0xf8, 0xab, 0x3a, + 0x82, 0xae, 0xc5, 0x03, 0x2c, 0xcf, 0x54, 0xdc, 0xcd, 0xe8, 0x49, 0x53, + 0xb5, 0xd8, 0xc2, 0x24, 0xf8, 0x8c, 0x38, 0x8f, 0xe3, 0xfe, 0x3a, 0x18, + 0x15, 0xa8, 0xda, 0x77, 0xc8, 0x81, 0x72, 0xc6, 0xc1, 0x60, 0xa3, 0x73, + 0x65, 0x68, 0x5c, 0xf3, 0x1d, 0x8d, 0x61, 0x21, 0x65, 0xfb, 0x45, 0xc4, + 0x4c, 0x31, 0x88, 0x25, 0x0d, 0x52, 0x75, 0x3b, 0xec, 0x54, 0xe0, 0xb1, + 0x9c, 0x7c, 0xdf, 0xe3, 0x3b, 0x77, 0x31, 0x33, 0xd7, 0x25, 0x99, 0xff, + 0xc5, 0x40, 0x1e, 0x85, 0x09, 0xfd, 0x2d, 0x24, 0x4a, 0x92, 0xe7, 0x77, + 0x48, 0xa5, 0x46, 0xf4, 0x8e, 0xa3, 0x6b, 0x24, 0xe4, 0x6b, 0x31, 0xf6, + 0xe0, 0x16, 0x49, 0x9b, 0x9f, 0xa3, 0x1a, 0x5c, 0x05, 0x5e, 0x81, 0x62, + 0xc8, 0x14, 0x52, 0xb4, 0x21, 0xfd, 0x76, 0x6d, 0x88, 0xe9, 0x3b, 0x0b, + 0x75, 0x27, 0x92, 0x47, 0x5a, 0x58, 0x08, 0x26, 0xa7, 0xa2, 0x48, 0x1c, + 0x14, 0x3e, 0x5e, 0xdf, 0x81, 0x83, 0x83, 0x3e, 0xc6, 0x72, 0x27, 0xc4, + 0x6a, 0x46, 0x2b, 0xf2, 0x8d, 0x42, 0x11, 0xb9, 0x15, 0xd7, 0xf0, 0x20, + 0x29, 0x53, 0xba, 0xf0, 0x6e, 0x41, 0x3d, 0xee, 0x19, 0xf2, 0x43, 0xf3, + 0x6d, 0x00, 0xe2, 0x43, 0x77, 0xb9, 0xa9, 0x78, 0x34, 0x48, 0x3c, 0x1a, + 0x8b, 0xbd, 0xa1, 0xe5, 0x90, 0x59, 0x5b, 0xd6, 0x1e, 0x22, 0xdf, 0xb2, + 0xa7, 0x96, 0x7d, 0x55, 0x86, 0x66, 0x95, 0xb7, 0x06, 0xe7, 0x60, 0x2a, + 0x01, 0x48, 0x3f, 0xd4, 0xa7, 0xd4, 0xc2, 0x38, 0xa4, 0x10, 0x8e, 0x4f, + 0x97, 0xad, 0xa3, 0xb9, 0xe2, 0xaa, 0x13, 0xb1, 0x16, 0x89, 0x3d, 0x74, + 0x60, 0x94, 0x8c, 0xc3, 0xe6, 0x5f, 0xcf, 0xdc, 0x58, 0x17, 0x98, 0x27, + 0x86, 0xae, 0x2a, 0x0d, 0xe8, 0x33, 0x79, 0xc8, 0xc8, 0x5b, 0x59, 0xb0, + 0xba, 0xac, 0xd3, 0x6e, 0x2d, 0x7b, 0x0b, 0x9a, 0xb5, 0xfd, 0x58, 0x42, + 0xeb, 0x80, 0xf4, 0x6b, 0x9a, 0x2f, 0x19, 0x43, 0x75, 0xb4, 0xcb, 0xc9, + 0xd5, 0x28, 0xf5, 0xb9, 0x67, 0x82, 0xb4, 0xed, 0x8c, 0x3f, 0x3d, 0x6b, + 0x6d, 0x1b, 0x80, 0x13, 0x5c, 0x7b, 0x2e, 0xfa, 0xa0, 0x32, 0xba, 0xb5, + 0x46, 0xd6, 0xe7, 0x90, 0xe9, 0xd1, 0x91, 0xa0, 0xaa, 0x26, 0x35, 0xa2, + 0x0d, 0x98, 0x44, 0x11, 0xae, 0xf9, 0xc5, 0x12, 0x4d, 0x1a, 0x7c, 0x53, + 0xea, 0xf6, 0x05, 0x8d, 0x3a, 0x74, 0x92, 0xc9, 0x65, 0xeb, 0x6f, 0xb5, + 0xb4, 0xd2, 0xcd, 0x5c, 0xec, 0xaf, 0x95, 0xcb, 0xb4, 0x3c, 0x22, 0xca, + 0x1c, 0x06, 0x85, 0x16, 0x96, 0x24, 0x8c, 0x6c, 0x80, 0xf8, 0xb3, 0xa7, + 0x87, 0x77, 0xeb, 0x09, 0x71, 0xc8, 0x95, 0xfb, 0x5e, 0xe5, 0x6f, 0x78, + 0xf9, 0x60, 0xf9, 0x9e, 0x58, 0x7b, 0xbd, 0x47, 0xdd, 0x48, 0x2e, 0x56, + 0xcd, 0x63, 0x72, 0xc9, 0x4b, 0x65, 0x2d, 0x41, 0xe8, 0x81, 0x19, 0x33, + 0x4b, 0xf6, 0x02, 0xc6, 0xcb, 0x2e, 0xdf, 0x3d, 0xc8, 0xdd, 0x2f, 0x0f, + 0x09, 0x67, 0xf0, 0xaa, 0x3c, 0x51, 0xdc, 0x8d, 0xc6, 0xc3, 0xb2, 0x3b, + 0x15, 0x85, 0xcb, 0xeb, 0x62, 0xef, 0xa3, 0xf9, 0x94, 0xf4, 0x35, 0x9c, + 0x59, 0xcc, 0xc2, 0x68, 0xb4, 0xde, 0x02, 0x75, 0x8e, 0xf5, 0x33, 0xca, + 0xd5, 0xc5, 0x24, 0xae, 0xf6, 0xde, 0x2b, 0x01, 0xf4, 0x56, 0xb9, 0xa5, + 0xa7, 0xe0, 0x64, 0x2e, 0xba, 0x1d, 0x53, 0x54, 0x46, 0xcf, 0x64, 0x16, + 0x12, 0xe2, 0xa6, 0xcc, 0x18, 0xb4, 0x77, 0x8b, 0x19, 0x50, 0x43, 0x96, + 0xc8, 0x5d, 0xc3, 0x58, 0xf0, 0xfd, 0x5e, 0x13, 0xa9, 0x10, 0x67, 0xdf, + 0x25, 0xdb, 0xaf, 0x38, 0x5f, 0xbd, 0x35, 0xc1, 0x49, 0x44, 0xe8, 0x1f, + 0x12, 0xa4, 0x7c, 0x28, 0xa3, 0xd6, 0x0d, 0x6f, 0x44, 0xa9, 0x5f, 0xfc, + 0x9f, 0xfa, 0x11, 0x62, 0x87, 0x5b, 0x0e, 0x91, 0xd4, 0xb6, 0xd3, 0x71, + 0xc2, 0x77, 0x19, 0xf6, 0x7c, 0x11, 0x30, 0x5e, 0x5c, 0xd3, 0x1e, 0x90, + 0x05, 0x31, 0x63, 0xbb, 0xef, 0x85, 0xe0, 0x27, 0x94, 0x80, 0xcb, 0x33, + 0xbc, 0x5e, 0x45, 0x87, 0x62, 0xdf, 0xd4, 0x12, 0x2f, 0xf5, 0x41, 0x15, + 0x03, 0x0c, 0x80, 0xe8, 0xe2, 0x06, 0xde, 0x4b, 0x46, 0x70, 0x94, 0xd2, + 0x0d, 0x85, 0x72, 0x27, 0xe5, 0x6c, 0xeb, 0xd2, 0x78, 0x0b, 0x38, 0x40, + 0xe8, 0xdb, 0x47, 0x5c, 0xba, 0xd0, 0x21, 0x33, 0x8f, 0xb8, 0xc0, 0x66, + 0x1e, 0xd1, 0xb0, 0x94, 0xa3, 0x39, 0xc7, 0x87, 0xaf, 0x97, 0x98, 0xce, + 0x6d, 0x03, 0x1a, 0xdb, 0x52, 0x96, 0x0b, 0x9d, 0x5b, 0xf8, 0xa3, 0xf4, + 0x41, 0x95, 0x72, 0xad, 0x0e, 0x98, 0x61, 0x7f, 0xf3, 0x8f, 0x23, 0xeb, + 0xc0, 0xdf, 0xd7, 0x70, 0x26, 0x8c, 0xb3, 0xb3, 0xf0, 0xa2, 0x8a, 0x39, + 0xdd, 0x61, 0xb4, 0x53, 0xe0, 0x2a, 0x6f, 0x91, 0x34, 0x9c, 0x76, 0xf6, + 0x52, 0x93, 0xe6, 0x39, 0xb7, 0x54, 0x07, 0x46, 0x82, 0x2d, 0x05, 0x6d, + 0x9a, 0x00, 0x53, 0x65, 0x68, 0x93, 0x91, 0x00, 0xda, 0xe0, 0x93, 0x34, + 0x60, 0xb1, 0x93, 0x0b, 0x64, 0xa8, 0x12, 0xd2, 0x51, 0x3c, 0xdb, 0xb0, + 0x4c, 0x39, 0x4e, 0xce, 0xbd, 0xf0, 0x65, 0x12, 0x8a, 0xd4, 0x80, 0x7d, + 0x82, 0x85, 0xe4, 0x92, 0xc2, 0x77, 0x1e, 0xcf, 0xd9, 0xab, 0x0f, 0x9b, + 0x32, 0x2e, 0x3f, 0xe1, 0x0e, 0x87, 0x1c, 0x87, 0x34, 0xe7, 0x93, 0x16, + 0x95, 0x09, 0x7d, 0x24, 0xa8, 0xb5, 0xe0, 0x9f, 0x23, 0x87, 0x5c, 0x0b, + 0x31, 0x4a, 0x2f, 0xe2, 0x5c, 0x82, 0x49, 0x51, 0xe4, 0x93, 0xcb, 0x05, + 0x23, 0x4f, 0x8a, 0x83, 0x88, 0xfb, 0x89, 0xb0, 0x08, 0xd6, 0x64, 0xad, + 0x51, 0x84, 0x40, 0x29, 0xb1, 0xca, 0x74, 0x26, 0x29, 0x5a, 0x61, 0x01, + 0x2e, 0xa0, 0xeb, 0xeb, 0x02, 0xb5, 0xff, 0xd8, 0x20, 0x6a, 0x5e, 0x8d, + 0x17, 0x1e, 0xa3, 0xd7, 0x2f, 0x20, 0x0b, 0x93, 0x17, 0x24, 0xf7, 0x90, + 0x7b, 0xc6, 0xba, 0xd8, 0xf9, 0xe9, 0x0a, 0x2a, 0x7a, 0x81, 0x23, 0x81, + 0x03, 0x6f, 0x1e, 0x0d, 0x87, 0x83, 0xd1, 0xcf, 0x92, 0x2f, 0x19, 0x82, + 0x4e, 0x6c, 0x0a, 0x02, 0xb6, 0x70, 0xbc, 0xe1, 0x58, 0xe7, 0x16, 0xdb, + 0x2f, 0x74, 0x9f, 0xe1, 0xc2, 0x1e, 0x64, 0xc6, 0x48, 0x08, 0xee, 0xea, + 0x52, 0x9a, 0xce, 0x2c, 0xc5, 0x0c, 0x7a, 0x63, 0xf1, 0x6a, 0xbd, 0x2c, + 0x8b, 0xd5, 0x4a, 0xfa, 0x1e, 0xab, 0x9a, 0x5b, 0x25, 0xb8, 0xfa, 0x0a, + 0xe9, 0x68, 0x80, 0x6f, 0x80, 0x57, 0x10, 0x54, 0xb8, 0xa2, 0x16, 0xbd, + 0xfe, 0xf7, 0xea, 0x01, 0xc7, 0x94, 0x5a, 0x95, 0xe3, 0x61, 0xa5, 0x49, + 0x84, 0xf5, 0x79, 0x78, 0xb5, 0x0a, 0x96, 0xca, 0x01, 0x1b, 0xd0, 0x0b, + 0x51, 0x30, 0xd3, 0x48, 0xfc, 0x4d, 0x50, 0x71, 0x09, 0x73, 0xea, 0x37, + 0xcd, 0x9d, 0x3d, 0xde, 0x30, 0x56, 0x21, 0xf0, 0xef, 0x84, 0xad, 0x27, + 0xe1, 0x83, 0xdb, 0xfb, 0xcd, 0x11, 0xb2, 0xbd, 0x30, 0x67, 0x8a, 0x88, + 0x09, 0x0e, 0x9d, 0x96, 0x09, 0xba, 0xda, 0x9d, 0xf0, 0xe9, 0xb4, 0xa6, + 0x7a, 0x04, 0xf9, 0x4b, 0xb8, 0x51, 0xa9, 0x99, 0xf3, 0xbb, 0x77, 0x95, + 0x0a, 0xa1, 0xa6, 0xa1, 0x24, 0xfc, 0xcc, 0x45, 0xe8, 0x83, 0xc8, 0x6f, + 0x48, 0xad, 0x9a, 0x73, 0xd0, 0xe0, 0x57, 0x7d, 0xe4, 0x78, 0x65, 0xef, + 0xae, 0xc2, 0xfe, 0x7a, 0x56, 0xaf, 0x03, 0x71, 0x2b, 0xe6, 0xa1, 0x7e, + 0xe5, 0x12, 0xf8, 0xc3, 0x75, 0xc7, 0x22, 0x5f, 0x1b, 0x52, 0x90, 0xe5, + 0xdf, 0xba, 0x9d, 0xe2, 0x68, 0xe0, 0xb3, 0x7a, 0x9e, 0x14, 0xff, 0xb5, + 0x0a, 0x80, 0x20, 0x49, 0x88, 0xe9, 0x9c, 0xe4, 0xb5, 0xaf, 0x7e, 0x51, + 0xec, 0xe7, 0xfc, 0x64, 0x65, 0x21, 0x10, 0xc6, 0x1f, 0x7f, 0x93, 0x7d, + 0xd8, 0xf5, 0xd0, 0x98, 0x94, 0x44, 0xf8, 0x49, 0x6a, 0x51, 0x0a, 0x54, + 0xf4, 0x9f, 0xee, 0x3c, 0x56, 0xbf, 0x4c, 0xe4, 0xde, 0x1c, 0x9b, 0x11, + 0x7e, 0x9a, 0x71, 0x11, 0x80, 0x33, 0xd5, 0xb0, 0x9b, 0xef, 0x67, 0x29, + 0xa4, 0x7d, 0x70, 0x31, 0x3f, 0x8b, 0x2e, 0x4a, 0x0f, 0x2c, 0x91, 0x3d, + 0x3e, 0x3d, 0x8c, 0x0a, 0x2b, 0xf1, 0xdd, 0xbf, 0x61, 0xe6, 0xa3, 0xef, + 0x6d, 0x82, 0xc8, 0xb7, 0x5e, 0x2b, 0x83, 0xc9, 0x4e, 0xa0, 0x85, 0x7f, + 0x01, 0x5a, 0xca, 0x6e, 0x90, 0xfa, 0x7e, 0x82, 0x4d, 0x35, 0x7e, 0xe0, + 0x26, 0x40, 0xf4, 0xa6, 0xae, 0xc3, 0x89, 0xf3, 0xca, 0x55, 0x2c, 0xb5, + 0x29, 0x05, 0x94, 0x45, 0xa7, 0x45, 0xf3, 0x3d, 0xbb, 0x53, 0x5e, 0xca, + 0x7c, 0x84, 0x8f, 0x72, 0x98, 0x93, 0x90, 0x1f, 0x56, 0x72, 0xdb, 0xbd, + 0xa9, 0xeb, 0xf9, 0xe9, 0xce, 0xb1, 0x41, 0xc3, 0xaa, 0xa0, 0xc4, 0x74, + 0x23, 0xc1, 0xeb, 0x7d, 0x41, 0xcd, 0xa4, 0x62, 0xec, 0xfc, 0x9a, 0xa4, + 0x16, 0xec, 0x67, 0x41, 0x89, 0xf0, 0x0e, 0xf3, 0xd1, 0xa2, 0x2f, 0xba, + 0x5d, 0x93, 0x36, 0x46, 0xf5, 0x52, 0x64, 0x91, 0xe7, 0x40, 0x91, 0x20, + 0xa1, 0xc9, 0xaa, 0x4c, 0x79, 0xc4, 0xbb, 0x67, 0x79, 0xad, 0x43, 0xab, + 0xba, 0xde, 0xfc, 0xf1, 0x74, 0x81, 0x33, 0xc0, 0x3f, 0x39, 0xd1, 0xd1, + 0xdf, 0xc0, 0x53, 0x33, 0xb2, 0x92, 0x37, 0xe6, 0x86, 0x2a, 0xe4, 0xe1, + 0x7c, 0x98, 0xf7, 0xdb, 0x5c, 0xa9, 0xff, 0x8d, 0x9c, 0xab, 0xe2, 0xf2, + 0xd5, 0xb1, 0x42, 0xa9, 0xf4, 0x97, 0x80, 0xcd, 0xde, 0x25, 0x2e, 0x87, + 0x92, 0xdd, 0xcf, 0xed, 0x67, 0x93, 0x8c, 0x5a, 0x1d, 0xee, 0xcf, 0x9d, + 0x50, 0x8f, 0xa7, 0xe3, 0x5c, 0xa3, 0x68, 0x78, 0x24, 0xeb, 0x60, 0xa3, + 0x8b, 0x36, 0xbb, 0xcb, 0x46, 0xee, 0x77, 0xfb, 0xf8, 0x69, 0x24, 0xd1, + 0xfa, 0xad, 0x76, 0x76, 0x5e, 0x54, 0xe5, 0xb6, 0x36, 0xc6, 0xdd, 0xa9, + 0x6c, 0x44, 0x15, 0xf7, 0x0a, 0xf8, 0xbb, 0xba, 0xec, 0x35, 0xff, 0xc9, + 0xd6, 0x5d, 0xf5, 0x73, 0x4a, 0x15, 0x8f, 0x7b, 0x6e, 0xf4, 0xa0, 0x6d, + 0x10, 0xbb, 0x67, 0x0c, 0xb4, 0x69, 0xad, 0xb6, 0x40, 0xf7, 0x5f, 0x37, + 0x28, 0xc4, 0x08, 0x49, 0xd0, 0x16, 0x70, 0x80, 0xea, 0x55, 0x66, 0x07, + 0xc8, 0x03, 0x1b, 0xf6, 0xd3, 0x03, 0x04, 0x74, 0xe0, 0x50, 0x3f, 0xd2, + 0x53, 0x92, 0xa0, 0x9d, 0x59, 0xc9, 0x74, 0xf2, 0x7e, 0x3b, 0x33, 0x02, + 0x10, 0x0b, 0x39, 0xf7, 0x4f, 0x6b, 0x58, 0xb2, 0x1a, 0xda, 0x65, 0x44, + 0xd1, 0x7c, 0x3f, 0xd7, 0xe3, 0xac, 0xe2, 0x1f, 0x38, 0xc1, 0x6a, 0xb0, + 0xdc, 0xc3, 0x9c, 0x7b, 0x11, 0x3c, 0x05, 0x21, 0x96, 0x76, 0x98, 0x76, + 0x82, 0xc1, 0x54, 0xdf, 0xdc, 0x8f, 0x4c, 0xd2, 0x63, 0x04, 0x06, 0x77, + 0x36, 0xe6, 0x2e, 0xd1, 0x00, 0x28, 0x42, 0x7c, 0x4a, 0x27, 0x90, 0x46, + 0xc9, 0xce, 0x33, 0x1c, 0xae, 0xda, 0x79, 0x64, 0x7f, 0x52, 0x3f, 0x58, + 0x11, 0x76, 0x4a, 0xb6, 0x72, 0xd8, 0x76, 0xae, 0xfd, 0x5c, 0x57, 0x69, + 0x76, 0x91, 0x84, 0x21, 0xc4, 0x9b, 0xd8, 0xa2, 0xff, 0x93, 0x02, 0x77, + 0x61, 0x57, 0x96, 0x7b, 0x8e, 0xfc, 0xf2, 0x6c, 0x11, 0x2b, 0x5e, 0x88, + 0x5c, 0x17, 0x1d, 0x12, 0x79, 0x3a, 0x78, 0xb6, 0x9d, 0x70, 0xfa, 0xd4, + 0xc1, 0x5c, 0x90, 0x0e, 0x0a, 0xd1, 0x3c, 0x7d, 0xcf, 0xee, 0x8a, 0xb2, + 0xb2, 0x4d, 0xce, 0x89, 0x32, 0xa9, 0x6c, 0x56, 0x57, 0x85, 0xb1, 0xbf, + 0x18, 0x1d, 0xc6, 0xe1, 0x17, 0xc5, 0x92, 0x42, 0x99, 0xf9, 0x9f, 0x04, + 0xec, 0x38, 0xf8, 0xa0, 0xd2, 0xab, 0xe6, 0x13, 0x4d, 0x9c, 0x18, 0x86, + 0x3e, 0x18, 0x73, 0x2c, 0xac, 0xe0, 0xb9, 0xf9, 0x87, 0x74, 0xb8, 0xd7, + 0x47, 0x6e, 0x42, 0xfc, 0x29, 0xa0, 0x1f, 0x56, 0x68, 0xb6, 0x23, 0x96, + 0xa2, 0x8d, 0x54, 0x81, 0x0f, 0x60, 0xb9, 0xde, 0x93, 0xfc, 0xfd, 0xde, + 0xbe, 0xb3, 0xb5, 0x87, 0xec, 0x9f, 0x17, 0xc2, 0x77, 0x6e, 0xa0, 0x62, + 0xdb, 0x66, 0xba, 0xc5, 0x05, 0x12, 0x46, 0x5d, 0x3c, 0x23, 0x29, 0x68, + 0xe5, 0x31, 0xe3, 0x15, 0xec, 0xac, 0x15, 0x9a, 0xbf, 0x42, 0x65, 0x80, + 0x45, 0x9c, 0x1d, 0xc2, 0x0e, 0x18, 0x47, 0x40, 0x44, 0xc1, 0x55, 0x24, + 0x5a, 0x35, 0xad, 0x59, 0xd2, 0xc6, 0xc3, 0x68, 0x58, 0xbd, 0x6f, 0xcf, + 0x5d, 0xb1, 0x9b, 0x0c, 0x92, 0x39, 0x22, 0x49, 0x66, 0x2e, 0x03, 0x7b, + 0x75, 0x5c, 0x6c, 0xde, 0x37, 0x54, 0xa9, 0x07, 0x2f, 0x7e, 0xc1, 0x3e, + 0x3b, 0xab, 0xd2, 0xa9, 0xfa, 0xc7, 0x6b, 0xd5, 0x14, 0x08, 0x35, 0x89, + 0x0b, 0x31, 0x18, 0x54, 0x7d, 0x6b, 0x53, 0x80, 0x6e, 0x32, 0x9b, 0xff, + 0x61, 0x7f, 0x36, 0xe5, 0x28, 0x40, 0xbc, 0xc7, 0x19, 0xb3, 0xae, 0xfa, + 0x95, 0xa8, 0xae, 0xd2, 0x97, 0x72, 0xc6, 0x91, 0x36, 0x3a, 0xa6, 0xec, + 0x4a, 0x41, 0x63, 0x6b, 0x28, 0xef, 0x5a, 0xa1, 0xdb, 0xf2, 0xd9, 0xfd, + 0x61, 0x72, 0xa4, 0xd2, 0x9e, 0xf7, 0x47, 0xf4, 0x4e, 0xea, 0x2a, 0xa5, + 0x35, 0xe1, 0x77, 0x3a, 0x53, 0x28, 0xa6, 0x55, 0x48, 0x0c, 0x1e, 0x44, + 0xfc, 0xc1, 0x31, 0x5a, 0x00, 0xcd, 0x29, 0xc1, 0x5c, 0xca, 0x2a, 0x07, + 0x01, 0x63, 0xac, 0xb3, 0xfb, 0xf6, 0x0b, 0xac, 0xfd, 0xe8, 0x7b, 0xed, + 0xf9, 0x3d, 0x9a, 0xbc, 0x67, 0x28, 0x1c, 0xd9, 0x3f, 0x97, 0x28, 0x4a, + 0xe7, 0xd0, 0x08, 0xe9, 0x3e, 0xa0, 0xcb, 0x0f, 0xe0, 0x3f, 0x1b, 0x80, + 0x43, 0x74, 0xd9, 0x9d, 0x0b, 0x22, 0x81, 0xf7, 0xec, 0x71, 0x2a, 0x29, + 0x9e, 0x5d, 0x1e, 0x8d, 0xf4, 0x22, 0x95, 0x78, 0x86, 0xcb, 0xf0, 0x9d, + 0xe7, 0x6a, 0x66, 0x7e, 0x28, 0xb5, 0x47, 0xb6, 0xdc, 0x0d, 0x03, 0x3c, + 0x09, 0x58, 0x76, 0x93, 0x39, 0xb2, 0xd3, 0x75, 0xb4, 0x51, 0x55, 0x84, + 0x30, 0x24, 0x0a, 0x76, 0xf4, 0x97, 0xe7, 0x0f, 0x5a, 0x67, 0xee, 0xf4, + 0xc7, 0x69, 0x8d, 0xf2, 0x32, 0x29, 0x5c, 0x33, 0x82, 0x5f, 0x6c, 0x47, + 0xd0, 0xe2, 0xbd, 0x62, 0xd6, 0x4c, 0x6d, 0x0d, 0xba, 0x87, 0xd3, 0x43, + 0x7e, 0x2d, 0xa6, 0x14, 0x09, 0x4f, 0x3b, 0xc3, 0x04, 0x14, 0xe5, 0x65, + 0xe9, 0x3b, 0x6a, 0xca, 0xb5, 0x96, 0x84, 0x3f, 0x53, 0x49, 0x22, 0x45, + 0x91, 0xff, 0xf9, 0x26, 0x75, 0x0d, 0x9c, 0xa7, 0x00, 0xf4, 0x65, 0xc4, + 0x60, 0x72, 0xab, 0xeb, 0xf8, 0xa8, 0x72, 0xfe, 0xd8, 0xde, 0x93, 0x67, + 0xcb, 0x09, 0xcc, 0xa0, 0xce, 0x9f, 0x67, 0x63, 0x26, 0xfa, 0x7f, 0x89, + 0xaa, 0x3e, 0x6d, 0xb2, 0x90, 0xd7, 0xef, 0x3e, 0x2a, 0x66, 0x26, 0x33, + 0xe6, 0x26, 0xc1, 0x58, 0xf8, 0x91, 0xea, 0x2f, 0xd0, 0x84, 0x21, 0x41, + 0x93, 0xa6, 0x36, 0x40, 0xb5, 0x4c, 0xac, 0x21, 0x88, 0x37, 0x47, 0x8a, + 0xb8, 0xf3, 0x33, 0x73, 0x12, 0xd7, 0x5a, 0x55, 0xf9, 0xd1, 0x1e, 0x75, + 0xa4, 0x66, 0x68, 0x3f, 0xf7, 0xb2, 0xc4, 0x5d, 0x1b, 0xb1, 0x61, 0x0f, + 0xaf, 0x4b, 0x9b, 0x20, 0x2b, 0x05, 0x68, 0x1c, 0x6c, 0x97, 0x8d, 0xb8, + 0x7b, 0x96, 0xda, 0xe0, 0x67, 0x15, 0x4c, 0x51, 0x71, 0x0d, 0xd3, 0x7b, + 0xde, 0xaa, 0xd3, 0x58, 0xf5, 0xc9, 0x62, 0x0a, 0xc2, 0x33, 0x1f, 0xf3, + 0xc3, 0x30, 0xb5, 0x64, 0xd1, 0x59, 0x41, 0x0e, 0xae, 0xaa, 0x0d, 0xdf, + 0x9f, 0x5d, 0x3f, 0x15, 0x0d, 0x46, 0x7a, 0x6d, 0x2e, 0x29, 0x1b, 0xc0, + 0xd3, 0x11, 0x10, 0x5d, 0xdc, 0x6a, 0x35, 0x8c, 0x43, 0xc8, 0x9f, 0x05, + 0x80, 0xdc, 0x25, 0x24, 0x37, 0x70, 0x7e, 0x1c, 0xe9, 0x85, 0x5a, 0xef, + 0x83, 0x3a, 0x55, 0x68, 0x83, 0x17, 0xf4, 0xc7, 0xae, 0xe4, 0x84, 0xc9, + 0x64, 0x5d, 0x2f, 0xb6, 0xca, 0x10, 0x95, 0xb8, 0xd6, 0x80, 0xfd, 0x05, + 0xa5, 0x06, 0x32, 0x34, 0x91, 0x01, 0xd2, 0x02, 0x90, 0xe1, 0xf7, 0x89, + 0x8a, 0xee, 0x18, 0x04, 0x93, 0xd9, 0xb4, 0x63, 0x4b, 0xf7, 0x7a, 0x9c, + 0x1b, 0x4b, 0xf9, 0x31, 0x32, 0xd9, 0xf2, 0x55, 0x4e, 0xc1, 0x02, 0xce, + 0x77, 0x38, 0x36, 0x29, 0xb8, 0x54, 0x8c, 0xc2, 0x27, 0x5f, 0xd9, 0xae, + 0x3e, 0x1e, 0xcd, 0xe9, 0x07, 0x90, 0x4c, 0xe0, 0xda, 0x16, 0x6e, 0xdf, + 0xde, 0x3a, 0x61, 0x89, 0x9f, 0x79, 0xd0, 0xd4, 0x66, 0x95, 0xad, 0xe4, + 0x11, 0x7d, 0xa1, 0xae, 0xec, 0x3e, 0x6e, 0x20, 0x5a, 0xd0, 0x28, 0x0e, + 0x55, 0xec, 0xcf, 0x34, 0xec, 0xb7, 0xfc, 0xa4, 0xb3, 0x8f, 0x56, 0x13, + 0x50, 0xcc, 0x15, 0x10, 0x74, 0x40, 0x72, 0x42, 0x20, 0x22, 0xb3, 0xaf, + 0xf3, 0x68, 0xba, 0x95, 0x45, 0xcb, 0xef, 0x92, 0xd5, 0x14, 0x4c, 0x1f, + 0xe3, 0xc1, 0xa6, 0x03, 0x4e, 0x05, 0xd2, 0x1a, 0xee, 0xd2, 0x48, 0x44, + 0x2e, 0x50, 0x3b, 0x86, 0xc8, 0x6a, 0xc8, 0x4c, 0xca, 0x2a, 0xb6, 0xf7, + 0x3c, 0xaf, 0xdc, 0x62, 0xb1, 0x49, 0x13, 0xfe, 0xe7, 0x32, 0xea, 0x78, + 0xfa, 0xba, 0xcf, 0x15, 0x47, 0x58, 0xdc, 0x19, 0x73, 0x1d, 0xff, 0xbd, + 0xcc, 0x27, 0xf6, 0xfc, 0x66, 0x68, 0xa7, 0x29, 0xaf, 0x2b, 0x25, 0x0c, + 0x15, 0x47, 0xff, 0xc1, 0x00, 0x9d, 0xfa, 0x58, 0x9c, 0xaa, 0xf9, 0xcc, + 0x4c, 0x51, 0x1d, 0xda, 0xf3, 0x3c, 0x10, 0xd0, 0x3b, 0x59, 0x30, 0x02, + 0x68, 0x29, 0x1c, 0xa7, 0x22, 0xea, 0x81, 0xd3, 0x29, 0x71, 0x39, 0xe8, + 0x72, 0x7f, 0x7d, 0x94, 0x0a, 0x64, 0x2c, 0xe6, 0x55, 0xfb, 0x90, 0x78, + 0x7e, 0x6c, 0x3e, 0xfe, 0x57, 0x14, 0x61, 0xef, 0xe2, 0x63, 0x57, 0x6c, + 0x13, 0x97, 0x27, 0x2b, 0x38, 0x44, 0xab, 0x74, 0x76, 0x11, 0xa6, 0x60, + 0xad, 0x8e, 0xad, 0xe5, 0xa5, 0xa1, 0x66, 0xc5, 0xe1, 0x4d, 0x27, 0xa0, + 0x79, 0x7a, 0x09, 0xe6, 0xf0, 0x28, 0x3f, 0xcb, 0xc6, 0xf8, 0x94, 0xc0, + 0xf1, 0x13, 0xbe, 0x62, 0x6a, 0x52, 0x75, 0x52, 0xd3, 0x82, 0x31, 0xbd, + 0x15, 0xf2, 0xe8, 0x2e, 0xb1, 0x62, 0x03, 0x1e, 0xe2, 0xb3, 0xec, 0xbc, + 0x3c, 0x12, 0xca, 0x62, 0x4e, 0xc2, 0x3a, 0x51, 0x1c, 0xdf, 0xa2, 0x84, + 0x88, 0xe5, 0x7e, 0xd7, 0x5d, 0xd7, 0xbf, 0xf2, 0x7d, 0xbd, 0x9a, 0x90, + 0x63, 0xfd, 0x8a, 0x84, 0x2b, 0x9d, 0x89, 0x27, 0x63, 0x4c, 0x0a, 0xe3, + 0x70, 0x94, 0x7b, 0xe6, 0xb3, 0xd7, 0xcb, 0xcb, 0x8a, 0xeb, 0x6b, 0x53, + 0x34, 0x2f, 0x62, 0x44, 0x2d, 0x73, 0x63, 0x8a, 0xf4, 0xa2, 0x01, 0xd7, + 0x12, 0xb6, 0x8d, 0x8c, 0x4b, 0x73, 0x2b, 0x44, 0x50, 0x49, 0x6f, 0x01, + 0xac, 0xc5, 0x15, 0x37, 0x6c, 0xde, 0xd4, 0x02, 0xb1, 0x12, 0x80, 0x73, + 0xb2, 0x52, 0x0e, 0xe0, 0xb5, 0x75, 0xc9, 0x48, 0xcf, 0x18, 0x5c, 0xcc, + 0xaf, 0x58, 0xa2, 0x3e, 0x28, 0xe4, 0xab, 0xde, 0xea, 0x2a, 0xcf, 0x58, + 0x22, 0xc4, 0x68, 0xea, 0x9b, 0x7b, 0x90, 0xc5, 0xdc, 0x1c, 0x37, 0xd1, + 0x8a, 0x4f, 0xe7, 0x24, 0x23, 0x39, 0xb9, 0x62, 0xb8, 0x41, 0x13, 0x7b, + 0xe2, 0x1e, 0x0d, 0x4e, 0x38, 0x11, 0xa3, 0xb9, 0x10, 0xbb, 0x10, 0x6f, + 0x40, 0x9f, 0x50, 0x05, 0xc7, 0x0e, 0xb9, 0x9e, 0xab, 0x7c, 0x3c, 0x78, + 0xce, 0x54, 0xbf, 0xbf, 0x40, 0x36, 0x76, 0xbc, 0x4b, 0x64, 0x32, 0xca, + 0x0e, 0x2d, 0x91, 0x87, 0xd5, 0x00, 0x19, 0xbf, 0x12, 0xd0, 0x35, 0x7c, + 0xa1, 0xe5, 0xcf, 0x7a, 0x2d, 0x08, 0x62, 0xed, 0x34, 0x61, 0xe3, 0xda, + 0x2c, 0xcc, 0x1b, 0xf8, 0x12, 0xfe, 0xfd, 0x19, 0xa2, 0xc3, 0x70, 0xfd, + 0x4f, 0x5b, 0x5d, 0x20, 0xd2, 0xe1, 0xc5, 0xac, 0xe7, 0xa1, 0x84, 0x00, + 0xbd, 0x46, 0x81, 0xfd, 0x54, 0x69, 0xed, 0x1a, 0x7a, 0x32, 0xbb, 0x75, + 0x22, 0x76, 0x6d, 0x34, 0x24, 0xcc, 0xe6, 0xbe, 0x78, 0x5a, 0x75, 0x6c, + 0xbc, 0x62, 0xb8, 0x14, 0xf7, 0x13, 0x73, 0xc2, 0xdc, 0xb6, 0xfa, 0xfb, + 0x97, 0xfe, 0x27, 0x7b, 0x33, 0xb8, 0xeb, 0x20, 0xd2, 0x0f, 0x4f, 0xed, + 0xd1, 0xd0, 0x63, 0xf7, 0xc5, 0x8e, 0xec, 0xcc, 0xd2, 0x31, 0x38, 0x35, + 0x65, 0x33, 0x5c, 0x63, 0x85, 0xf7, 0x3d, 0xc3, 0x62, 0x26, 0x52, 0x0a, + 0x67, 0xda, 0x87, 0x1f, 0x9e, 0x47, 0xec, 0x6b, 0xf5, 0x74, 0x1a, 0xc5, + 0xa7, 0xa0, 0x0f, 0xdd, 0xc5, 0x42, 0xf4, 0xda, 0x41, 0x1a, 0x48, 0xa9, + 0xbe, 0x4f, 0xb6, 0x28, 0x17, 0xe9, 0xf5, 0xd7, 0x00, 0xb3, 0xfe, 0x05, + 0x4e, 0xa7, 0xdf, 0x65, 0x7a, 0xb8, 0x4f, 0xe0, 0xfe, 0x58, 0x9e, 0xba, + 0x45, 0x11, 0xba, 0xc2, 0xdb, 0x97, 0x97, 0xa4, 0xbc, 0x18, 0x21, 0x1b, + 0xad, 0x82, 0xef, 0xb1, 0x5f, 0x2f, 0x25, 0x9d, 0xca, 0x52, 0xa5, 0x6d, + 0x8c, 0xab, 0x07, 0x2b, 0x7b, 0x6a, 0x77, 0x9d, 0xdf, 0xfb, 0xae, 0x6e, + 0x49, 0x18, 0x25, 0x4a, 0xf2, 0x7d, 0xa0, 0x32, 0xc8, 0x53, 0x10, 0xc3, + 0xf2, 0xef, 0xf3, 0xe7, 0x79, 0xd7, 0x6a, 0x0e, 0x61, 0xff, 0x89, 0xc9, + 0x42, 0xe8, 0x6e, 0x4f, 0x78, 0xe1, 0x5f, 0xcd, 0x7a, 0xf6, 0x27, 0x72, + 0x67, 0xea, 0x0b, 0xa6, 0xcc, 0x34, 0xb7, 0x8f, 0x92, 0x3c, 0x95, 0xb9, + 0x0a, 0x5d, 0x49, 0x2e, 0xb7, 0x7d, 0x31, 0x9c, 0x79, 0x61, 0x95, 0x9c, + 0x60, 0x56, 0x8d, 0x35, 0x00, 0xc5, 0x8b, 0xe6, 0x02, 0x0f, 0x26, 0x39, + 0x7b, 0x93, 0x94, 0xb1, 0xcd, 0xde, 0xed, 0xfa, 0x2a, 0x4b, 0x63, 0xa8, + 0x1b, 0x31, 0x43, 0x5e, 0x69, 0x7c, 0xd6, 0x15, 0x35, 0x9c, 0xa2, 0xd7, + 0xdf, 0x0e, 0x1a, 0x20, 0x50, 0xf5, 0x02, 0x21, 0x30, 0x35, 0x3c, 0x60, + 0x71, 0xad, 0xd0, 0xe3, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x10, 0x17, 0x1d, 0x22, 0x2d}; +#elif MLD_CONFIG_PARAMETER_SET == 87 +const uint8_t expected_signature[] = { + 0xdf, 0xe6, 0xe1, 0xa5, 0x20, 0xc1, 0xac, 0x98, 0x55, 0x2c, 0xf2, 0x13, + 0x65, 0x42, 0xe2, 0xb0, 0x77, 0x5f, 0x15, 0x00, 0x8f, 0x14, 0x48, 0xa1, + 0xe3, 0xee, 0x81, 0x35, 0x15, 0x34, 0xad, 0x6e, 0x60, 0x85, 0x00, 0xf8, + 0x18, 0x53, 0x0d, 0xa0, 0xc5, 0x41, 0xc4, 0x48, 0x09, 0x1b, 0x34, 0x0c, + 0x0e, 0xcf, 0xc6, 0x3d, 0x38, 0x78, 0x8b, 0x69, 0xe5, 0x6f, 0x4d, 0x43, + 0xfa, 0xa6, 0x75, 0x26, 0x8a, 0x75, 0x97, 0x10, 0x6a, 0x1f, 0x3c, 0xa6, + 0x94, 0xa9, 0x93, 0x8f, 0xe5, 0x62, 0xbf, 0x94, 0xe4, 0xd0, 0x0d, 0x11, + 0x4d, 0x03, 0xe2, 0xd8, 0xdf, 0x68, 0xb7, 0x87, 0x62, 0xc9, 0xdc, 0xc9, + 0x36, 0x4f, 0xcc, 0xd1, 0xa4, 0xae, 0x7e, 0xa4, 0xb9, 0xaf, 0xaf, 0xf0, + 0x8a, 0xe6, 0xff, 0x83, 0xe7, 0x54, 0x22, 0x6e, 0x3f, 0x2e, 0xa0, 0x4f, + 0xa8, 0x31, 0x53, 0xf3, 0x62, 0xeb, 0x04, 0xfa, 0xd1, 0x57, 0x39, 0x43, + 0xf9, 0xe0, 0x31, 0x12, 0x45, 0x09, 0x8b, 0x9e, 0x1e, 0x7a, 0x2b, 0x85, + 0xee, 0xdd, 0xe8, 0x1e, 0xd7, 0xc0, 0x17, 0xb4, 0xd2, 0xdc, 0x36, 0xa9, + 0xe4, 0x49, 0x88, 0xbf, 0x71, 0x43, 0x9d, 0x3e, 0xd2, 0x10, 0xe7, 0x82, + 0xb5, 0xfe, 0xdd, 0x42, 0xc8, 0x1b, 0x11, 0xf6, 0x52, 0x23, 0x98, 0x83, + 0x48, 0xec, 0xec, 0x70, 0x8b, 0xe7, 0x49, 0x9a, 0xd7, 0xd9, 0x7b, 0x47, + 0x4e, 0xe2, 0x5e, 0x17, 0x1a, 0xa0, 0x0e, 0x60, 0x85, 0x3a, 0x30, 0x8c, + 0x1c, 0x26, 0xb4, 0xe1, 0xb5, 0x2b, 0x48, 0xf4, 0xb8, 0x93, 0x2f, 0x79, + 0x3a, 0x1e, 0xb6, 0x3b, 0x07, 0x3b, 0x1e, 0x15, 0xd7, 0x85, 0x5e, 0xd4, + 0x06, 0x0e, 0xcd, 0x6a, 0x93, 0x3a, 0x93, 0x29, 0x6a, 0xbe, 0x68, 0x8a, + 0xb6, 0xb8, 0xfa, 0xc5, 0x63, 0x48, 0x98, 0x10, 0x6d, 0xd9, 0xd3, 0x5b, + 0x29, 0x5f, 0x93, 0x90, 0x08, 0x1c, 0x1a, 0x15, 0x7b, 0x0a, 0x59, 0x9d, + 0x64, 0x24, 0x45, 0xb6, 0xd3, 0x7b, 0xc1, 0x5d, 0x74, 0x1f, 0x0b, 0x8e, + 0x18, 0xf2, 0x92, 0x8e, 0xd4, 0x7f, 0x72, 0x5c, 0x98, 0x1f, 0x8b, 0xa5, + 0xb8, 0xf4, 0x7e, 0x12, 0x6a, 0x93, 0xb9, 0xb5, 0xf1, 0xda, 0x97, 0x75, + 0x4f, 0x56, 0x80, 0x88, 0x64, 0x2b, 0xe0, 0x59, 0xcd, 0x5e, 0x91, 0x64, + 0x9c, 0x0c, 0xa8, 0xdd, 0xac, 0xcb, 0xf3, 0x48, 0x3b, 0x5c, 0xc4, 0xc5, + 0xb9, 0x9a, 0x0b, 0x8e, 0x5d, 0x9a, 0xd5, 0xb7, 0xf0, 0xd4, 0x07, 0x48, + 0xb9, 0x63, 0x02, 0x87, 0x8d, 0xae, 0x7e, 0x03, 0x33, 0x4f, 0x86, 0x15, + 0x1b, 0x3b, 0xdf, 0xda, 0xce, 0xd3, 0x1e, 0xc0, 0x76, 0xb5, 0x1c, 0xdd, + 0xb8, 0x32, 0x87, 0x7d, 0x59, 0x18, 0x72, 0x0c, 0xde, 0x8f, 0x63, 0x2d, + 0x38, 0xf2, 0xe9, 0xc2, 0x81, 0xed, 0xfa, 0x2d, 0x61, 0xef, 0x48, 0xdb, + 0xa2, 0xeb, 0xfe, 0x52, 0x31, 0x1e, 0x21, 0x0a, 0x08, 0xf6, 0x02, 0xd3, + 0xc0, 0x32, 0x3b, 0x6b, 0x2f, 0x64, 0xc4, 0xb3, 0x4b, 0xfe, 0x69, 0x78, + 0xbf, 0x20, 0x62, 0x07, 0x77, 0xdf, 0x2c, 0x18, 0x53, 0x61, 0x8e, 0x05, + 0x01, 0x86, 0xab, 0xab, 0xec, 0x18, 0x8c, 0x15, 0x63, 0x1f, 0xe9, 0x99, + 0xb2, 0x35, 0x77, 0xe1, 0x58, 0xf1, 0xa9, 0x4d, 0x1a, 0xb9, 0x8c, 0x30, + 0x63, 0x6f, 0x9e, 0x7d, 0x4e, 0xcf, 0xb5, 0x6c, 0xf3, 0xe4, 0xdc, 0xab, + 0xf9, 0xae, 0x58, 0xf8, 0x1d, 0x08, 0x7b, 0x73, 0x82, 0x58, 0xc8, 0x67, + 0x48, 0x1a, 0x5e, 0x3d, 0xdb, 0xac, 0x1b, 0x1b, 0xef, 0xeb, 0xa4, 0xe5, + 0x67, 0x48, 0x76, 0xd1, 0x96, 0x4f, 0x6c, 0x7d, 0x06, 0x8c, 0x02, 0x86, + 0x95, 0x83, 0xb6, 0x9b, 0x5e, 0x9a, 0xb5, 0x85, 0xc0, 0x4f, 0x13, 0x1c, + 0x32, 0xf8, 0x29, 0xdf, 0x47, 0x85, 0xdb, 0xe4, 0x37, 0xdc, 0xd8, 0x04, + 0x18, 0xdd, 0xca, 0x97, 0xdd, 0x67, 0x13, 0xbe, 0x74, 0x95, 0xdc, 0xd0, + 0xcc, 0xe6, 0xb5, 0xa5, 0x12, 0x9b, 0x23, 0x4f, 0x41, 0x8c, 0xcc, 0x95, + 0xf4, 0xb0, 0x5f, 0x2a, 0xc4, 0xbf, 0x88, 0xda, 0x55, 0xcb, 0x13, 0x93, + 0x22, 0x60, 0x51, 0x43, 0xc7, 0x9a, 0x2c, 0xfa, 0xb2, 0x59, 0xc1, 0xe6, + 0x8a, 0xa4, 0xb8, 0xfb, 0xd3, 0x31, 0x1d, 0xc7, 0x88, 0xdc, 0xbc, 0xe9, + 0xba, 0xe7, 0xdc, 0xe3, 0xdd, 0x90, 0x96, 0xb4, 0xb4, 0x0a, 0xc1, 0x07, + 0x31, 0x3f, 0xdb, 0xc5, 0x4d, 0x73, 0x58, 0x86, 0x15, 0x37, 0x07, 0x86, + 0x03, 0x17, 0x16, 0x18, 0x15, 0xb9, 0x26, 0x35, 0x8a, 0x43, 0x22, 0xae, + 0x21, 0x52, 0x05, 0x4e, 0x5c, 0x3f, 0x3e, 0xb9, 0x2a, 0x19, 0x13, 0xfd, + 0x31, 0x47, 0x6a, 0x74, 0xaa, 0xb9, 0xc6, 0x2c, 0x13, 0x8c, 0x21, 0xc4, + 0x8d, 0x00, 0xf4, 0x24, 0xf2, 0xb7, 0xd3, 0x13, 0xad, 0x29, 0x5e, 0x50, + 0x0b, 0x0e, 0x9f, 0x9a, 0xb7, 0xf6, 0x9e, 0xba, 0x12, 0x23, 0x84, 0x8c, + 0xbe, 0x2c, 0x14, 0x1e, 0xe6, 0x79, 0x15, 0x20, 0x2d, 0x32, 0x08, 0xd8, + 0x1c, 0x87, 0x1b, 0xa8, 0xc0, 0xbb, 0x85, 0xa9, 0x71, 0x30, 0x5e, 0x39, + 0x48, 0x87, 0xdc, 0x3d, 0x03, 0x29, 0x19, 0xd1, 0xd4, 0x21, 0x3a, 0x53, + 0x2d, 0x5e, 0x78, 0xff, 0x94, 0x4b, 0x91, 0xa6, 0xb5, 0xe5, 0x42, 0x56, + 0x67, 0x6a, 0x0e, 0xf3, 0x2d, 0x6a, 0x4e, 0xd7, 0x3a, 0x81, 0xb1, 0x4d, + 0x0b, 0x66, 0x5f, 0x43, 0x28, 0x7c, 0x75, 0x8b, 0x2b, 0x99, 0x24, 0xc2, + 0x5e, 0x8c, 0x22, 0xf0, 0xd5, 0xb3, 0xfc, 0x86, 0x62, 0xf3, 0xd2, 0x6c, + 0xa7, 0x48, 0x04, 0x44, 0x5d, 0x93, 0x74, 0x37, 0x16, 0x2c, 0x19, 0x12, + 0x57, 0x49, 0xef, 0xd5, 0xd6, 0x92, 0xdc, 0x51, 0xf8, 0x55, 0x3a, 0xc0, + 0x0b, 0xdf, 0x41, 0xb5, 0x01, 0x59, 0x7e, 0x85, 0x65, 0xdb, 0x44, 0xbd, + 0x04, 0x96, 0x1a, 0xd4, 0x6e, 0x22, 0x54, 0x92, 0xdb, 0xc7, 0xc5, 0x3a, + 0xdf, 0x0c, 0xf4, 0x1b, 0xdc, 0x14, 0xf6, 0x91, 0x9c, 0xbe, 0xf8, 0x8e, + 0x70, 0xd1, 0x3a, 0x0e, 0x58, 0xe6, 0xb9, 0xd3, 0xaa, 0xa2, 0x70, 0xba, + 0xdd, 0x16, 0x13, 0x19, 0xd1, 0x96, 0x78, 0x04, 0x2f, 0xd7, 0x38, 0x8c, + 0x35, 0x1f, 0xfc, 0x58, 0xa4, 0x4c, 0xa9, 0x9a, 0xae, 0x13, 0x3b, 0xc1, + 0x20, 0x4b, 0x66, 0x0f, 0x72, 0x42, 0x0a, 0x53, 0x84, 0x54, 0x71, 0x06, + 0xdb, 0x85, 0x8f, 0x40, 0xa6, 0x09, 0xf7, 0x24, 0xc4, 0x35, 0xf7, 0x1d, + 0xd4, 0x3d, 0x54, 0x75, 0xaf, 0xc4, 0x78, 0x0f, 0xce, 0xe0, 0x0c, 0x90, + 0x0f, 0xd5, 0x2e, 0x61, 0xf7, 0x58, 0xaa, 0xf0, 0xc7, 0x37, 0x5a, 0x59, + 0x1f, 0x8a, 0x03, 0x98, 0x43, 0xb7, 0x27, 0x78, 0x4e, 0x44, 0x5a, 0xb5, + 0x29, 0xf5, 0xab, 0x9e, 0xb7, 0x2a, 0xc4, 0xa3, 0x03, 0x00, 0xe3, 0x28, + 0x57, 0xc9, 0x2a, 0x98, 0xb8, 0xa1, 0x45, 0x1d, 0xfa, 0x6e, 0xb3, 0x0d, + 0x42, 0x5a, 0xb6, 0xb1, 0x0e, 0x5c, 0xbe, 0x82, 0xe2, 0x36, 0x40, 0x4b, + 0x05, 0x28, 0xd9, 0xbc, 0x27, 0xd6, 0x77, 0x00, 0xc9, 0x29, 0x6a, 0xd6, + 0x19, 0x8f, 0x8d, 0xda, 0xe1, 0xc3, 0x8b, 0x69, 0x71, 0xd0, 0xf7, 0xc8, + 0x33, 0xef, 0xe6, 0x23, 0x6b, 0xcb, 0x00, 0x56, 0x0a, 0x9b, 0x9d, 0x60, + 0x3a, 0xd3, 0xad, 0xd9, 0x5c, 0x6a, 0x7d, 0xab, 0x35, 0x71, 0x93, 0xc5, + 0xf2, 0x6a, 0x38, 0x0e, 0xfb, 0xd9, 0x9b, 0xa5, 0xda, 0x52, 0x45, 0xef, + 0x93, 0x94, 0x5b, 0x08, 0x8c, 0x07, 0xab, 0x2e, 0x99, 0x88, 0x77, 0xb5, + 0x15, 0x66, 0x7f, 0x0e, 0xfa, 0xb0, 0x29, 0xe4, 0x88, 0xd9, 0xdd, 0x22, + 0xaf, 0x7a, 0x4e, 0xb5, 0xd0, 0x62, 0x85, 0x27, 0x33, 0xf1, 0xb7, 0x34, + 0xb1, 0xe6, 0xda, 0x9f, 0x3c, 0xfe, 0xf5, 0xd4, 0xef, 0x56, 0x48, 0x93, + 0x7a, 0x54, 0xa2, 0x7f, 0x07, 0xea, 0x31, 0xb8, 0x8b, 0xca, 0xb9, 0xdb, + 0x1e, 0x2b, 0xb5, 0x16, 0xe6, 0x0e, 0xd9, 0x3f, 0x7c, 0xf0, 0xc2, 0x3e, + 0x57, 0x64, 0x60, 0x97, 0xfb, 0xdf, 0x8c, 0x3e, 0x56, 0x22, 0x92, 0x2a, + 0xb2, 0x21, 0x00, 0x0a, 0x75, 0x89, 0x68, 0xe7, 0x51, 0xa3, 0x63, 0x05, + 0xe1, 0x6f, 0x1e, 0x1e, 0x80, 0xa2, 0x4b, 0x5d, 0xb7, 0xf4, 0xb7, 0x45, + 0x85, 0x00, 0x84, 0x6e, 0xbe, 0x0b, 0x67, 0xbf, 0x21, 0x06, 0x5a, 0x56, + 0x79, 0xe9, 0x6b, 0x0e, 0x72, 0x19, 0x2d, 0x09, 0x78, 0xd5, 0x5e, 0xc2, + 0x32, 0xee, 0x29, 0xd4, 0x7a, 0x65, 0xc7, 0xfe, 0x16, 0x86, 0xd2, 0x29, + 0x71, 0xe5, 0x91, 0x0e, 0x3e, 0x86, 0xd5, 0x00, 0xc4, 0xfc, 0xd9, 0xae, + 0xd3, 0x7c, 0x13, 0xfd, 0x62, 0xce, 0x0c, 0xb2, 0xe5, 0x1f, 0x6d, 0xed, + 0x55, 0x6f, 0xc1, 0xaa, 0xa1, 0x74, 0x59, 0x46, 0x83, 0xd5, 0x5d, 0x71, + 0x17, 0x13, 0x1d, 0x0b, 0x25, 0xfb, 0x0a, 0xcd, 0x67, 0xfe, 0x57, 0x93, + 0xc2, 0x71, 0x55, 0x6c, 0x68, 0xfa, 0x40, 0xdb, 0xdd, 0xce, 0xd5, 0x5c, + 0xce, 0x0a, 0x1d, 0xfa, 0x19, 0x30, 0xe2, 0x2b, 0x63, 0x98, 0x16, 0x2c, + 0x67, 0x69, 0x55, 0xe5, 0xc1, 0x6c, 0x6e, 0xb7, 0x92, 0x6a, 0xbb, 0x10, + 0xd3, 0x13, 0x2e, 0x73, 0x91, 0x74, 0xcb, 0x9f, 0x5c, 0x7f, 0x5c, 0x48, + 0x58, 0x36, 0x13, 0x47, 0xf7, 0x49, 0xae, 0x90, 0x15, 0x53, 0xb5, 0xe6, + 0x37, 0xfb, 0x81, 0x47, 0xb4, 0x69, 0x84, 0xca, 0x95, 0xab, 0x19, 0x2a, + 0x28, 0xc2, 0x8a, 0xf1, 0xcd, 0xf9, 0x3e, 0xd3, 0xaf, 0xe1, 0x75, 0xf7, + 0x94, 0x74, 0x1c, 0xf5, 0x32, 0xcf, 0x70, 0xbd, 0x69, 0xcc, 0xa8, 0x3c, + 0xca, 0x59, 0x53, 0xfa, 0xcb, 0xe7, 0xb6, 0x36, 0x70, 0xea, 0xe2, 0x84, + 0xfa, 0x5e, 0xbd, 0xd7, 0x59, 0x3d, 0x21, 0xc6, 0x9f, 0x5c, 0x1f, 0xa6, + 0xa9, 0xf1, 0xd3, 0x26, 0x9e, 0xff, 0xbc, 0x81, 0xfe, 0xbe, 0xee, 0x64, + 0xd9, 0x63, 0x94, 0x4b, 0x15, 0xd8, 0x95, 0xaa, 0xec, 0x10, 0xc9, 0xe2, + 0xe1, 0x05, 0x37, 0x64, 0xc4, 0xb0, 0x2e, 0xa5, 0x0e, 0x4c, 0x2d, 0x03, + 0x53, 0xf1, 0x93, 0x77, 0x9d, 0x46, 0x14, 0x67, 0x48, 0x5f, 0xad, 0x1b, + 0xdc, 0xb9, 0x74, 0xa2, 0x6c, 0xfc, 0xd2, 0xa0, 0x1f, 0x43, 0x89, 0x15, + 0xc5, 0x0c, 0xb0, 0x9e, 0x1e, 0xc2, 0xd6, 0x44, 0xd9, 0x6e, 0xfc, 0xb4, + 0x9c, 0x95, 0x90, 0xcd, 0xc3, 0x17, 0x1c, 0x6a, 0xce, 0x03, 0x56, 0x9f, + 0xe7, 0xcd, 0x7e, 0xe7, 0xa2, 0x0c, 0x2b, 0x0d, 0x59, 0xb0, 0xc9, 0x4c, + 0x6e, 0x33, 0x6d, 0x43, 0xc4, 0x3a, 0x10, 0x24, 0x03, 0x3e, 0x09, 0xb6, + 0x86, 0x13, 0xba, 0x18, 0x19, 0xd3, 0xff, 0xeb, 0xa5, 0x25, 0x8f, 0x6f, + 0xc8, 0xe6, 0x96, 0xa4, 0xd2, 0x66, 0x40, 0x81, 0x79, 0xe8, 0x39, 0x18, + 0x41, 0x02, 0x66, 0x5c, 0x30, 0x5f, 0x58, 0x9d, 0x35, 0x16, 0xc6, 0x96, + 0xa8, 0x68, 0xbc, 0x09, 0x83, 0x17, 0x2c, 0x5f, 0x5e, 0xd0, 0x1d, 0xb0, + 0x48, 0x5e, 0xcf, 0x91, 0x16, 0x4d, 0xa0, 0xba, 0xbc, 0x61, 0xa8, 0x3f, + 0x30, 0x09, 0xbb, 0xa3, 0x12, 0xcd, 0xdc, 0x29, 0xf7, 0xb0, 0xad, 0x05, + 0x17, 0xd6, 0xd3, 0x16, 0xfb, 0xe5, 0x99, 0xf4, 0x71, 0x62, 0xa3, 0x45, + 0x45, 0xc7, 0x9b, 0xaa, 0x45, 0xd3, 0x35, 0xfe, 0xfb, 0x63, 0xaf, 0xe7, + 0x85, 0x31, 0xc9, 0x66, 0x26, 0xa9, 0xda, 0x8c, 0xc6, 0xf6, 0xd5, 0xdf, + 0xb1, 0xa9, 0xf1, 0xb6, 0x3d, 0x92, 0xae, 0x4d, 0xbc, 0x74, 0x7d, 0x76, + 0x5a, 0x59, 0x8c, 0x87, 0xff, 0x95, 0x2f, 0x67, 0x37, 0x30, 0x1a, 0xc1, + 0x23, 0x2e, 0x0c, 0xaa, 0x80, 0x1c, 0xf3, 0xa3, 0x74, 0x94, 0xb2, 0xda, + 0x1a, 0xb8, 0x46, 0xec, 0x30, 0x76, 0xf4, 0xdf, 0xfb, 0x00, 0xb3, 0x6f, + 0x86, 0xc1, 0xc5, 0x3a, 0x5d, 0x11, 0x14, 0x87, 0xeb, 0x30, 0xd8, 0x33, + 0x18, 0x00, 0x01, 0x76, 0x43, 0x82, 0xcd, 0x1c, 0x36, 0x54, 0xd2, 0x64, + 0x5b, 0xfb, 0x93, 0xca, 0x20, 0x1d, 0xa3, 0x20, 0x99, 0xc3, 0x8e, 0x5c, + 0x82, 0xfc, 0x56, 0x07, 0x41, 0x4b, 0x4f, 0x54, 0xc7, 0xb5, 0xe8, 0x6d, + 0x7e, 0xd8, 0x8a, 0x56, 0xb4, 0x76, 0x1e, 0xd3, 0x82, 0x97, 0xdd, 0x2b, + 0xd9, 0x80, 0xb7, 0xb6, 0xeb, 0x3d, 0xe5, 0xe0, 0x20, 0x27, 0x8c, 0xf0, + 0xd6, 0x14, 0xc7, 0xcd, 0x79, 0xbc, 0xa0, 0x21, 0x85, 0xc3, 0x02, 0xae, + 0x73, 0xc4, 0x0a, 0x39, 0x1a, 0x98, 0x61, 0xc3, 0x86, 0xd8, 0x97, 0x67, + 0x87, 0xe9, 0x56, 0x0b, 0x61, 0xa6, 0x7e, 0x07, 0xfb, 0x0a, 0x8b, 0xd1, + 0x90, 0xbd, 0x39, 0x22, 0xdb, 0xc2, 0x7f, 0xaa, 0x79, 0xb7, 0x39, 0x09, + 0xc1, 0x69, 0xdb, 0xe2, 0x7f, 0xec, 0xde, 0x80, 0x7a, 0x6c, 0xde, 0x76, + 0xa4, 0xe8, 0xe0, 0x8d, 0x71, 0xfa, 0x62, 0xf0, 0x2e, 0x7b, 0xf4, 0xce, + 0x65, 0x18, 0x42, 0xde, 0x92, 0x1b, 0xdc, 0xc9, 0xa7, 0x8d, 0xa5, 0x91, + 0x0f, 0xa5, 0x1b, 0x89, 0xcf, 0x29, 0x10, 0x1d, 0x94, 0x78, 0x1b, 0xea, + 0x79, 0x35, 0x62, 0xd4, 0x29, 0xe6, 0x59, 0x8c, 0xc1, 0xd2, 0xf3, 0x32, + 0x71, 0x09, 0xce, 0x51, 0xd7, 0x14, 0x29, 0x92, 0xbf, 0xdf, 0x9a, 0x69, + 0xda, 0x61, 0x03, 0x0f, 0xa2, 0x0a, 0xab, 0x57, 0x1c, 0xca, 0xab, 0x42, + 0x63, 0x63, 0x1e, 0x35, 0x5d, 0x8d, 0xba, 0x6f, 0x4b, 0x6b, 0x5e, 0x7c, + 0xc0, 0x1e, 0xb7, 0xf4, 0x65, 0xbd, 0x13, 0x1c, 0xf2, 0xa9, 0x73, 0x38, + 0xc3, 0x47, 0xc9, 0x32, 0xf0, 0x30, 0x57, 0x05, 0x42, 0x52, 0xac, 0x72, + 0xee, 0x9f, 0x4e, 0x21, 0xbf, 0x38, 0x19, 0x6d, 0x48, 0xec, 0x97, 0xcb, + 0x70, 0x9e, 0xee, 0xb3, 0xa1, 0xaa, 0xa6, 0x7e, 0xe9, 0x16, 0xdf, 0xcd, + 0x1c, 0x56, 0xcf, 0xf0, 0x9f, 0x4d, 0xd1, 0x8c, 0x14, 0x50, 0x5d, 0x23, + 0x96, 0xe0, 0x1f, 0x61, 0x79, 0xbf, 0x44, 0xfd, 0xa2, 0x31, 0xf7, 0x4c, + 0x0c, 0x8d, 0x8c, 0x1b, 0xbf, 0x8d, 0x45, 0xbf, 0x0b, 0xd8, 0xfb, 0x6f, + 0xff, 0x15, 0xc0, 0x44, 0x7c, 0xb9, 0xb8, 0xf9, 0xef, 0x0d, 0x79, 0x11, + 0x3b, 0x79, 0xd2, 0x52, 0x89, 0x5a, 0xcd, 0x0f, 0x10, 0x92, 0x42, 0xfe, + 0xcf, 0x0a, 0x11, 0x8a, 0x8a, 0xda, 0xee, 0xc8, 0x6b, 0xd9, 0xab, 0xec, + 0xb4, 0x25, 0x6f, 0x8d, 0x68, 0x26, 0xe8, 0xdd, 0xf5, 0xa4, 0xe8, 0x65, + 0x37, 0x03, 0xb0, 0xad, 0x73, 0x3b, 0x4d, 0x74, 0x57, 0x7f, 0x0f, 0x6c, + 0xb0, 0x5d, 0x59, 0x80, 0x13, 0xa1, 0x6c, 0xb0, 0xed, 0x26, 0xec, 0x79, + 0x50, 0x5f, 0x5c, 0xb7, 0xa6, 0xae, 0xe8, 0x0a, 0x6d, 0x55, 0x9a, 0x7f, + 0x59, 0x23, 0xa3, 0x7e, 0x84, 0x7b, 0x3b, 0xfc, 0xde, 0xe1, 0xd9, 0x7c, + 0xd6, 0x87, 0xb3, 0x0e, 0xdb, 0xc1, 0x8c, 0x5e, 0x77, 0xb7, 0x23, 0xd7, + 0x14, 0xd4, 0x23, 0xb4, 0xac, 0x45, 0xbf, 0xfe, 0x40, 0x20, 0x4d, 0x91, + 0x20, 0x94, 0xbd, 0x58, 0xb1, 0x99, 0x69, 0xaf, 0x31, 0x68, 0xbd, 0x61, + 0x5e, 0x87, 0x81, 0x54, 0x4e, 0x2d, 0x03, 0xc2, 0xe2, 0xcd, 0xdc, 0x59, + 0xe5, 0x35, 0xcf, 0xb8, 0xfc, 0x65, 0xed, 0x46, 0xb3, 0x92, 0xe7, 0xf8, + 0x3a, 0x32, 0xaa, 0x0e, 0x5a, 0x82, 0x58, 0x4e, 0x77, 0xd8, 0x33, 0xc9, + 0xb0, 0x3e, 0xad, 0xa5, 0x92, 0xe9, 0xa9, 0x8c, 0x00, 0x72, 0x8f, 0xdc, + 0x77, 0x9d, 0x5c, 0x97, 0xd6, 0x58, 0x20, 0x1e, 0xf4, 0x55, 0x2d, 0xc0, + 0x30, 0xf0, 0x66, 0xda, 0x2d, 0x11, 0xac, 0xd4, 0x2d, 0xd5, 0x25, 0x42, + 0x1d, 0xce, 0x49, 0xb5, 0x95, 0x79, 0x9b, 0x6c, 0x65, 0xe0, 0x8a, 0xc5, + 0x9f, 0x75, 0xe3, 0xe6, 0xf8, 0xa6, 0x88, 0xd6, 0x93, 0x70, 0x4f, 0x89, + 0x94, 0x74, 0xbd, 0xef, 0xc2, 0x1a, 0x55, 0x74, 0x37, 0x44, 0x85, 0x1e, + 0xa9, 0xbb, 0x3f, 0x15, 0xc7, 0x84, 0x80, 0xa5, 0xab, 0xc3, 0x91, 0x8e, + 0xd6, 0x32, 0x46, 0x0d, 0xfa, 0xd1, 0x19, 0xd1, 0xfc, 0x02, 0xe2, 0x20, + 0xa6, 0xa9, 0xf7, 0xf4, 0xcc, 0x5b, 0x54, 0x4f, 0x4a, 0x73, 0x35, 0xda, + 0xf0, 0x31, 0x81, 0x1a, 0x82, 0xe7, 0xd4, 0xc8, 0xb4, 0x1d, 0x70, 0xa9, + 0x5d, 0x67, 0xb9, 0x7d, 0x4b, 0xcd, 0xa4, 0x81, 0xf9, 0xb2, 0x38, 0x07, + 0x16, 0xd5, 0x28, 0x82, 0xb9, 0x76, 0x5b, 0xa1, 0x09, 0x7a, 0xe7, 0x2a, + 0xcf, 0xc0, 0x3d, 0x2a, 0x42, 0x9a, 0xf3, 0xc8, 0x64, 0x15, 0x7c, 0x94, + 0xd0, 0x97, 0xee, 0x34, 0xb6, 0xf0, 0xb2, 0xba, 0x7e, 0xb2, 0xbb, 0x4e, + 0xbf, 0x88, 0xd0, 0x6b, 0xc5, 0x9c, 0xb9, 0xf2, 0x7d, 0xbf, 0x5d, 0x87, + 0xbc, 0x36, 0x4a, 0xd1, 0x1b, 0x6f, 0x40, 0x09, 0xba, 0x26, 0x51, 0xd6, + 0xc0, 0xaf, 0x27, 0xce, 0x27, 0x8d, 0x93, 0xa8, 0x6c, 0x91, 0xe7, 0x91, + 0x42, 0xc0, 0x68, 0x36, 0x5b, 0xd5, 0x56, 0x4c, 0xe2, 0x77, 0xc3, 0xac, + 0x56, 0xe3, 0x1c, 0xc2, 0xf9, 0x78, 0x02, 0x39, 0x7d, 0xed, 0x18, 0x2a, + 0x01, 0x48, 0xe6, 0xf6, 0x7e, 0x34, 0x50, 0xf4, 0x57, 0x56, 0x93, 0xdb, + 0x85, 0x1b, 0x1e, 0x1a, 0x6f, 0x3e, 0x07, 0x3c, 0xad, 0x3f, 0x8d, 0x75, + 0x53, 0xc3, 0x20, 0x72, 0x93, 0x28, 0xd2, 0x86, 0xc8, 0xa5, 0x90, 0xf2, + 0x5f, 0x13, 0xd5, 0xa5, 0xbe, 0x88, 0x9e, 0x9a, 0x57, 0x2c, 0x53, 0x3f, + 0x11, 0x25, 0x00, 0x00, 0x4a, 0x16, 0x8d, 0xd3, 0x3f, 0x2d, 0x3d, 0x88, + 0xbb, 0x4c, 0x4f, 0x9a, 0xb9, 0x97, 0x5f, 0xed, 0x71, 0xa9, 0x68, 0xd9, + 0x4a, 0x14, 0x24, 0xc7, 0xbe, 0xff, 0x85, 0x57, 0xa3, 0x21, 0xe3, 0x21, + 0x79, 0x1f, 0xd0, 0xbb, 0xb7, 0x73, 0xde, 0x60, 0x02, 0x4b, 0x8f, 0x7d, + 0xb3, 0xb3, 0x8a, 0xda, 0x4c, 0xf4, 0xb8, 0xf1, 0x31, 0xff, 0x32, 0x7b, + 0xd8, 0xfa, 0xb1, 0xcb, 0xb4, 0x58, 0xf5, 0xc8, 0x64, 0xdf, 0xfe, 0x3d, + 0x89, 0x52, 0x5c, 0x52, 0x95, 0xf3, 0xba, 0x0d, 0x1d, 0x2c, 0xc4, 0xf7, + 0x3c, 0x3b, 0x6f, 0x8e, 0xc7, 0xab, 0xad, 0x3d, 0x3d, 0x95, 0x9b, 0xc7, + 0x71, 0x36, 0xae, 0x08, 0xc3, 0x08, 0x79, 0xfa, 0x24, 0xee, 0xd9, 0xf9, + 0x63, 0xc7, 0xd9, 0x16, 0x19, 0x8e, 0x0d, 0xaf, 0x52, 0x87, 0x86, 0x7d, + 0xec, 0xe5, 0xea, 0x5a, 0xda, 0x86, 0x9d, 0x0e, 0x50, 0x53, 0x8c, 0x24, + 0xa8, 0x69, 0xc4, 0xf3, 0x85, 0x7b, 0x34, 0x67, 0x19, 0x35, 0xec, 0xd4, + 0xd4, 0x50, 0xe0, 0xe6, 0xe9, 0x29, 0x5b, 0x92, 0xee, 0xba, 0xa9, 0xef, + 0xf6, 0x35, 0x23, 0x8b, 0xdb, 0x48, 0x32, 0x25, 0x41, 0xf3, 0x55, 0x12, + 0x33, 0xc3, 0x6c, 0xed, 0x32, 0xe1, 0x64, 0x7a, 0x8d, 0xa2, 0x19, 0x5a, + 0x26, 0xf2, 0x83, 0xf1, 0xe4, 0x27, 0xdb, 0x67, 0xc3, 0x89, 0x37, 0xea, + 0x78, 0x19, 0xc6, 0xa3, 0x82, 0x84, 0x1c, 0xf3, 0x2b, 0xbe, 0xde, 0xba, + 0xe7, 0x60, 0x2e, 0xf5, 0x4e, 0xb6, 0x73, 0x29, 0xac, 0xc7, 0x55, 0xab, + 0x21, 0xe9, 0x95, 0x78, 0xd5, 0x8e, 0x27, 0xdc, 0x92, 0x5f, 0xc0, 0xcb, + 0xee, 0x66, 0x09, 0x0a, 0xfc, 0x94, 0x43, 0x44, 0x50, 0x35, 0x57, 0xf8, + 0x08, 0xf9, 0x97, 0xa2, 0x0e, 0xde, 0x81, 0xe1, 0xd1, 0xa0, 0x41, 0xfe, + 0xe6, 0x08, 0x6c, 0x98, 0x8c, 0x81, 0x46, 0x0e, 0xf9, 0x9a, 0x54, 0xfe, + 0xc3, 0x91, 0xe3, 0xd4, 0x46, 0xca, 0x52, 0xa2, 0x73, 0x9e, 0x4d, 0xa7, + 0xfd, 0xa1, 0x8e, 0x43, 0x28, 0xf5, 0xa3, 0xa2, 0x62, 0x20, 0x53, 0x62, + 0x05, 0x49, 0xba, 0x06, 0xe2, 0xeb, 0xba, 0xfb, 0x8e, 0xa0, 0x22, 0xc7, + 0xf9, 0xcc, 0x7f, 0x8b, 0xa8, 0x5d, 0x55, 0xd2, 0x24, 0xff, 0xdd, 0x2c, + 0xc1, 0xd0, 0x3d, 0xe4, 0x79, 0xea, 0xba, 0x62, 0xe5, 0xa2, 0x62, 0xf4, + 0x1f, 0xec, 0xb0, 0x07, 0xf2, 0x0d, 0x32, 0x84, 0x86, 0x81, 0x3d, 0x95, + 0xc1, 0x64, 0xfe, 0x9a, 0x3d, 0x8f, 0x4b, 0x6d, 0xfb, 0x0d, 0x42, 0xcf, + 0xbf, 0xdb, 0x51, 0xb2, 0x16, 0xa2, 0x35, 0xaa, 0xe7, 0x31, 0x54, 0xc2, + 0x87, 0xc6, 0xa5, 0x30, 0x71, 0x64, 0x65, 0xff, 0x41, 0x20, 0xb0, 0x83, + 0xdb, 0xb7, 0x95, 0xce, 0xd7, 0xcc, 0x7a, 0x77, 0xad, 0xb8, 0xb7, 0x4c, + 0xfc, 0x11, 0x05, 0x2b, 0xc4, 0xd4, 0xb6, 0x8b, 0xae, 0x13, 0xa5, 0x40, + 0x18, 0x6e, 0x0d, 0xe3, 0xc6, 0xb0, 0x81, 0x46, 0x46, 0x7e, 0x52, 0x0b, + 0x85, 0x4d, 0x98, 0xd9, 0x42, 0xdf, 0xde, 0x45, 0xc1, 0x5a, 0x33, 0x12, + 0x46, 0x26, 0xb3, 0x6f, 0xf2, 0x8b, 0x37, 0x6b, 0xfd, 0x08, 0xf4, 0x46, + 0x86, 0x89, 0x63, 0x63, 0x21, 0xe5, 0xa9, 0xb7, 0xd0, 0x09, 0x17, 0x52, + 0xee, 0xea, 0xdf, 0x97, 0xb7, 0x73, 0x2e, 0x54, 0x2c, 0x7b, 0x70, 0xd3, + 0xda, 0x26, 0x57, 0x1f, 0xb0, 0x19, 0xd9, 0x91, 0x18, 0x69, 0x75, 0x42, + 0x63, 0xcf, 0x6c, 0x8c, 0x98, 0x5e, 0x17, 0x99, 0x7e, 0x1d, 0xdc, 0x67, + 0x6d, 0x99, 0xd9, 0x02, 0x6e, 0x73, 0x90, 0x5a, 0x4f, 0x0a, 0xb4, 0x48, + 0xfb, 0xc5, 0xbd, 0xd2, 0x10, 0x05, 0xa6, 0x12, 0x68, 0x36, 0x28, 0x51, + 0x60, 0x1c, 0xa1, 0xe9, 0x90, 0x54, 0xa5, 0x53, 0xc3, 0x48, 0x9e, 0xd8, + 0x42, 0x52, 0x85, 0x0e, 0xff, 0xfe, 0xbf, 0xad, 0x3a, 0xa4, 0x57, 0x09, + 0x13, 0x38, 0x64, 0x15, 0x7c, 0xfd, 0xed, 0x91, 0x76, 0x44, 0x20, 0x84, + 0xd9, 0x90, 0xab, 0xfe, 0xfd, 0xd6, 0xab, 0xf1, 0xb3, 0x25, 0x21, 0x3d, + 0x97, 0x72, 0xb2, 0x95, 0xc5, 0x22, 0x80, 0xd9, 0x4a, 0x49, 0x9d, 0x99, + 0xc2, 0x4a, 0x9a, 0x59, 0xb3, 0x71, 0x75, 0x5b, 0xf9, 0x89, 0x7a, 0xdd, + 0xa9, 0xb3, 0xc3, 0xeb, 0x42, 0x91, 0xe2, 0x97, 0x30, 0x40, 0x48, 0x68, + 0x19, 0x3b, 0xf5, 0x7b, 0x4e, 0x33, 0x4b, 0x0c, 0xf3, 0xed, 0xda, 0x76, + 0x3f, 0xb0, 0x4b, 0x53, 0x85, 0x04, 0x33, 0x07, 0x53, 0xd8, 0x55, 0xa2, + 0xfb, 0x30, 0x2c, 0x66, 0xbd, 0x21, 0xf8, 0xfa, 0x20, 0x14, 0x9a, 0x0d, + 0x7f, 0xc9, 0x2f, 0x5b, 0x34, 0x29, 0x09, 0x16, 0xb5, 0x0a, 0x8d, 0xdf, + 0xa2, 0x84, 0x9a, 0xae, 0xe6, 0xa0, 0x50, 0x80, 0x31, 0x04, 0xd3, 0x0c, + 0x8f, 0xd1, 0x8a, 0xfd, 0xb4, 0xa5, 0xae, 0xf5, 0x3c, 0x62, 0xae, 0x45, + 0x70, 0xbb, 0x54, 0x62, 0xc8, 0x50, 0x71, 0x42, 0x85, 0xf6, 0x6f, 0xa0, + 0xf0, 0x10, 0x8a, 0x09, 0xbd, 0x71, 0x78, 0xa6, 0x5e, 0xe4, 0x03, 0x8f, + 0x3b, 0xd0, 0x5c, 0x37, 0x55, 0x1a, 0xc8, 0x57, 0x26, 0x62, 0x6c, 0xc4, + 0x67, 0x71, 0x9d, 0x97, 0xc0, 0xea, 0x35, 0x3e, 0x12, 0xd0, 0x2b, 0xc2, + 0x8f, 0x9e, 0xa6, 0x41, 0x48, 0x33, 0x83, 0x38, 0x37, 0x7e, 0xd4, 0xe3, + 0xee, 0x94, 0x8b, 0x81, 0xa4, 0x60, 0xdd, 0xdd, 0xc1, 0x8a, 0x7b, 0xda, + 0xa8, 0x46, 0xb8, 0x42, 0x3a, 0x25, 0xd6, 0x81, 0x89, 0x29, 0x21, 0xc2, + 0x0c, 0x5b, 0xfd, 0x3e, 0x8c, 0x65, 0x91, 0x52, 0xb3, 0x74, 0x1f, 0xd1, + 0x49, 0x7e, 0x1d, 0x59, 0x58, 0x96, 0xb5, 0xee, 0x32, 0xa4, 0xa8, 0x07, + 0x7c, 0xd1, 0x5b, 0x4b, 0xf8, 0x43, 0x5a, 0xa5, 0xcc, 0x60, 0xcc, 0x08, + 0x6a, 0x3c, 0x41, 0x66, 0x99, 0xe3, 0xa8, 0xe0, 0xb8, 0x87, 0xfc, 0x92, + 0xc0, 0x79, 0xc5, 0x3f, 0xd6, 0xc6, 0x8c, 0x01, 0xf4, 0xa5, 0x05, 0xad, + 0x51, 0xed, 0x04, 0xd7, 0x55, 0xc0, 0x73, 0x05, 0x0e, 0x73, 0xe5, 0x39, + 0x45, 0x5b, 0x95, 0x4a, 0x34, 0x07, 0x99, 0xdf, 0x4c, 0x35, 0xf5, 0x0c, + 0x27, 0x6d, 0xd1, 0x45, 0xf1, 0xfd, 0x24, 0xb7, 0xfe, 0xea, 0x11, 0x5d, + 0xa2, 0xc5, 0xa6, 0x81, 0x37, 0x1d, 0xc2, 0x31, 0x31, 0xfc, 0xe0, 0xf4, + 0xd7, 0xe9, 0x98, 0x8b, 0xe3, 0x70, 0x51, 0x62, 0xc8, 0x61, 0x6d, 0xec, + 0x75, 0x56, 0x71, 0xae, 0x88, 0xe0, 0x80, 0xf5, 0xb7, 0x85, 0x10, 0xb7, + 0x3d, 0x16, 0x78, 0x5f, 0x72, 0xab, 0x8f, 0x63, 0xc6, 0xd5, 0xa8, 0xc9, + 0x9c, 0xef, 0x8d, 0x9a, 0xc5, 0x4f, 0x63, 0xad, 0xc0, 0xf3, 0x1f, 0x69, + 0x0e, 0xce, 0x29, 0x92, 0xc1, 0x3b, 0xb0, 0xc5, 0xed, 0x0a, 0x7b, 0x92, + 0xd0, 0x4c, 0x9c, 0x82, 0xb0, 0x51, 0xf6, 0x33, 0x61, 0x3b, 0x76, 0x48, + 0x38, 0xf4, 0x7c, 0xaa, 0x52, 0x87, 0x15, 0x1a, 0xbe, 0xb8, 0xdc, 0x9b, + 0x16, 0xd2, 0x07, 0xf7, 0xf9, 0x74, 0xe0, 0xaf, 0x0e, 0x29, 0x05, 0xec, + 0x6c, 0x0e, 0x3b, 0xa7, 0xe7, 0xa4, 0xfc, 0xa4, 0xef, 0x57, 0x16, 0x7f, + 0x13, 0xbd, 0x8c, 0x42, 0x02, 0x55, 0x70, 0x56, 0xa5, 0xa9, 0x01, 0x29, + 0x12, 0x7d, 0x80, 0x46, 0x18, 0x8e, 0x39, 0x3f, 0x44, 0x55, 0xec, 0xef, + 0x60, 0x58, 0x7d, 0xce, 0x64, 0x8e, 0x9c, 0xea, 0xe4, 0x73, 0xd1, 0x48, + 0x9c, 0x3f, 0x92, 0xa0, 0x9a, 0x76, 0xa5, 0x5a, 0x13, 0x1f, 0x10, 0xb9, + 0xb7, 0xb1, 0xde, 0x49, 0x22, 0x58, 0xf4, 0x43, 0x5f, 0x03, 0x43, 0xc3, + 0x6c, 0xbf, 0x82, 0xaf, 0x88, 0x39, 0xfd, 0xb2, 0x28, 0x9b, 0x47, 0x3f, + 0x83, 0x3d, 0xd9, 0x7c, 0xf0, 0xc9, 0xc5, 0xa2, 0xb4, 0xd6, 0x0d, 0x59, + 0x51, 0x27, 0x60, 0x10, 0x5e, 0xbb, 0x18, 0xa6, 0x42, 0x4a, 0x9d, 0xc4, + 0x16, 0x0e, 0xb6, 0x57, 0x23, 0x03, 0x24, 0x27, 0xdc, 0x20, 0x56, 0x30, + 0x8b, 0x0f, 0xb6, 0xb7, 0x73, 0xf5, 0x36, 0x3e, 0xf6, 0x7a, 0x71, 0xa5, + 0x57, 0xcc, 0x6d, 0xc6, 0xf3, 0xdc, 0x35, 0xfb, 0x95, 0xf7, 0xa7, 0xd7, + 0x56, 0x38, 0xd4, 0x15, 0xe2, 0xd5, 0x6f, 0x70, 0x30, 0xc8, 0x7d, 0x8a, + 0x87, 0xe6, 0xd1, 0xe0, 0x50, 0x62, 0xde, 0xfa, 0x29, 0x40, 0x97, 0xa0, + 0x54, 0x63, 0x31, 0xd3, 0x08, 0x87, 0x0a, 0xdc, 0x6e, 0x5e, 0xab, 0x8d, + 0x16, 0xaf, 0x6e, 0x8b, 0x1a, 0x77, 0xf6, 0xd4, 0xe0, 0xbf, 0x59, 0xab, + 0xc7, 0xb0, 0x45, 0x18, 0xaa, 0xe6, 0x65, 0x6f, 0x7d, 0x13, 0xb2, 0xbf, + 0xb3, 0x66, 0x72, 0xfa, 0xfd, 0xee, 0xad, 0x07, 0x56, 0x51, 0x6a, 0xe2, + 0xff, 0xb2, 0xaf, 0x4d, 0xd1, 0xf2, 0x77, 0x35, 0x5e, 0x90, 0xcd, 0xe7, + 0xa8, 0x32, 0x4d, 0x9f, 0xbd, 0xa8, 0xce, 0xab, 0xf1, 0x49, 0x98, 0xb5, + 0x23, 0x5c, 0x62, 0x2d, 0x43, 0x31, 0x80, 0x87, 0xc2, 0xa8, 0xf5, 0xb9, + 0xb6, 0xae, 0x7f, 0x37, 0x13, 0xb8, 0x6b, 0x73, 0xf3, 0x56, 0x38, 0xa7, + 0x9b, 0x97, 0x69, 0x37, 0x00, 0xdc, 0xff, 0xfe, 0x58, 0xc9, 0x12, 0x47, + 0x75, 0x98, 0x1f, 0xad, 0xd8, 0xb5, 0xc8, 0x47, 0x4f, 0xd0, 0x72, 0x63, + 0x54, 0x25, 0x6c, 0x88, 0xc9, 0x9f, 0x3c, 0x82, 0xe0, 0xdd, 0x4c, 0xff, + 0x8e, 0xaf, 0x8f, 0x8e, 0xea, 0x84, 0x3f, 0x73, 0xdd, 0x9e, 0x18, 0x73, + 0x47, 0x70, 0xc7, 0xc7, 0x99, 0x65, 0xcf, 0xf3, 0xb6, 0x24, 0xed, 0x97, + 0x8f, 0xcd, 0x93, 0x1e, 0xff, 0x6e, 0x9c, 0xf1, 0x30, 0x14, 0x1a, 0x27, + 0x59, 0x6a, 0x0e, 0xf3, 0xe4, 0xfa, 0x1d, 0x65, 0xb5, 0x53, 0xe4, 0xab, + 0xb1, 0x3e, 0xe1, 0x91, 0xf4, 0x6d, 0x99, 0xca, 0x7d, 0x03, 0x08, 0x50, + 0xea, 0xa9, 0x39, 0x7f, 0x6d, 0xe7, 0x43, 0xfb, 0x64, 0xcc, 0x4b, 0x9e, + 0xa0, 0x26, 0xe4, 0x0e, 0xff, 0xb7, 0x11, 0x0a, 0x29, 0x50, 0x90, 0xd7, + 0x4d, 0x62, 0x9a, 0x4a, 0x23, 0xb7, 0xd3, 0x53, 0xde, 0x3a, 0xd1, 0xba, + 0xd3, 0x10, 0x59, 0xc6, 0xc5, 0x5e, 0xac, 0xf9, 0x61, 0x74, 0x54, 0xf4, + 0x27, 0x9f, 0x9a, 0x61, 0x13, 0xdc, 0xe5, 0x96, 0xe3, 0x95, 0x0d, 0xcc, + 0xbd, 0x81, 0x74, 0x79, 0x73, 0xef, 0x2e, 0x0b, 0x0f, 0x91, 0x65, 0x3c, + 0x26, 0x7c, 0x47, 0x10, 0x31, 0x0b, 0xfb, 0x41, 0x0c, 0xc2, 0xa8, 0xc4, + 0x0e, 0xbd, 0x0a, 0x8c, 0xa4, 0x80, 0x45, 0x57, 0x62, 0x0b, 0x4d, 0x44, + 0x5e, 0x59, 0x77, 0xfd, 0x3d, 0xf3, 0xd7, 0x92, 0x49, 0xc1, 0xcb, 0x8a, + 0x54, 0x56, 0x3b, 0xde, 0xcf, 0x16, 0x9a, 0x65, 0xbe, 0xac, 0x64, 0xe1, + 0xd4, 0xd4, 0x1e, 0xac, 0x6b, 0x4a, 0xad, 0xc4, 0x33, 0xac, 0xcb, 0x83, + 0xf4, 0x4d, 0xe8, 0xb6, 0xd7, 0x23, 0xd7, 0x71, 0x25, 0xa2, 0x25, 0x3d, + 0x7e, 0xf0, 0x3b, 0x7f, 0x61, 0x11, 0x56, 0xd4, 0x83, 0xc8, 0xc0, 0x29, + 0x38, 0x10, 0x73, 0xad, 0x6a, 0xb7, 0xb9, 0xd2, 0x2e, 0x9f, 0xae, 0x16, + 0x5e, 0xa6, 0x13, 0x1c, 0xc2, 0x17, 0x73, 0x43, 0x03, 0xdd, 0xa6, 0xaf, + 0x9a, 0x17, 0x31, 0xb8, 0x86, 0x97, 0xc2, 0xd6, 0xe6, 0xed, 0xd4, 0xe1, + 0x7d, 0xb9, 0xa6, 0x96, 0xc1, 0x4b, 0xcb, 0x11, 0x1e, 0xe1, 0xe0, 0xd2, + 0x28, 0x69, 0x68, 0x3b, 0x21, 0x17, 0x63, 0x0c, 0xc0, 0x49, 0x30, 0x22, + 0x3a, 0x59, 0x72, 0xe6, 0x47, 0xb4, 0xdc, 0xa8, 0x29, 0x1c, 0x89, 0xa6, + 0x3a, 0x77, 0x99, 0xea, 0x46, 0xce, 0x38, 0xda, 0x31, 0x88, 0xad, 0xe7, + 0x26, 0xce, 0xc6, 0x56, 0x04, 0x30, 0xfa, 0x01, 0xac, 0xbb, 0xe2, 0xb8, + 0x23, 0xe4, 0x9d, 0x4f, 0x77, 0x02, 0x00, 0x28, 0xf1, 0xe0, 0x19, 0x3f, + 0x22, 0x4f, 0x22, 0x69, 0x87, 0xc0, 0x4e, 0x26, 0x33, 0xfe, 0x6c, 0x70, + 0x56, 0x3b, 0x60, 0x5f, 0xfb, 0xf8, 0x43, 0xcf, 0x3f, 0xb9, 0xcb, 0x80, + 0x22, 0xbb, 0x0a, 0xa8, 0x1c, 0x3e, 0x7e, 0x4d, 0x42, 0x60, 0x5c, 0x8e, + 0xfa, 0x42, 0xb3, 0x95, 0xe7, 0x92, 0x6b, 0xec, 0x7a, 0x95, 0x88, 0x98, + 0xe3, 0xf9, 0x0d, 0xe5, 0x08, 0xf1, 0x26, 0x96, 0x2a, 0x81, 0x2b, 0x7c, + 0x0d, 0x12, 0xa0, 0x7f, 0x7b, 0x39, 0xf6, 0xcc, 0x1b, 0x2d, 0x2c, 0xe9, + 0x5b, 0x02, 0x9b, 0x5c, 0x94, 0x51, 0x13, 0xe8, 0xa0, 0x19, 0xce, 0xde, + 0x07, 0x1b, 0xda, 0x39, 0x14, 0xb5, 0x8b, 0xcf, 0x79, 0x3e, 0x2b, 0xb8, + 0x75, 0xab, 0x81, 0xee, 0x5e, 0x08, 0x33, 0xc3, 0x49, 0x5b, 0x4a, 0x9c, + 0x74, 0x34, 0xde, 0x08, 0x61, 0x03, 0x38, 0xe3, 0xd8, 0xff, 0xc5, 0xc0, + 0xb5, 0x40, 0xd5, 0x26, 0x57, 0x85, 0xf1, 0xb7, 0x77, 0xb6, 0x36, 0xe0, + 0x8d, 0x43, 0x3a, 0xef, 0xfe, 0x0f, 0xf7, 0xee, 0x67, 0x6c, 0x7b, 0xd1, + 0x83, 0xf6, 0x10, 0xda, 0x67, 0x04, 0x3a, 0x27, 0xd8, 0x3a, 0xcb, 0x9d, + 0x4c, 0xa6, 0x9a, 0xc7, 0xea, 0x07, 0xc6, 0x76, 0x79, 0x1b, 0x23, 0x4a, + 0x68, 0x2f, 0x14, 0x84, 0x42, 0x79, 0xe8, 0x1f, 0xf2, 0xe6, 0xac, 0x72, + 0xb0, 0xb0, 0xb6, 0x39, 0x95, 0x40, 0xa4, 0x6e, 0x54, 0x2e, 0xb7, 0xb5, + 0x13, 0x70, 0x48, 0x0d, 0x27, 0xed, 0x2c, 0xa2, 0x64, 0x53, 0xb4, 0x04, + 0x84, 0xab, 0xd8, 0xea, 0x2a, 0x8c, 0xac, 0x5b, 0x1d, 0xb8, 0xb2, 0xbe, + 0x55, 0x2b, 0x4a, 0x47, 0xfc, 0xe0, 0x15, 0x78, 0xb6, 0xd6, 0xff, 0x20, + 0xa8, 0x8a, 0xec, 0x8b, 0x30, 0xef, 0xc5, 0xc6, 0xec, 0xa0, 0xdf, 0xd3, + 0xc4, 0x2b, 0x4a, 0xdf, 0xef, 0x5c, 0x46, 0xb3, 0x31, 0xc7, 0x5f, 0x8f, + 0x1e, 0x99, 0x76, 0x81, 0x71, 0x61, 0xdb, 0xc3, 0xc4, 0x0f, 0x66, 0x7b, + 0xd7, 0x44, 0xc7, 0x8d, 0x12, 0x38, 0x71, 0x7c, 0xd8, 0x41, 0xf6, 0x8a, + 0xb9, 0xba, 0xd2, 0x1f, 0xa1, 0x27, 0x64, 0x67, 0x51, 0xb2, 0xaf, 0xea, + 0x02, 0x95, 0x79, 0x20, 0x0a, 0xc8, 0xaa, 0x03, 0x11, 0xb6, 0x8b, 0x7d, + 0x86, 0xb7, 0xef, 0x5e, 0x3f, 0x0b, 0x91, 0x47, 0xf0, 0x43, 0xb4, 0x54, + 0x1d, 0x16, 0x66, 0xe9, 0x63, 0x1a, 0x55, 0xaf, 0x34, 0xad, 0x11, 0x68, + 0x4d, 0x36, 0xb7, 0x0c, 0x6d, 0x4d, 0xed, 0xba, 0x14, 0xe8, 0xf6, 0xe2, + 0x15, 0x64, 0xb6, 0x15, 0x28, 0xbf, 0xd2, 0x4d, 0xb6, 0x6f, 0xca, 0x5f, + 0x81, 0x1b, 0xf0, 0x31, 0xf5, 0xd3, 0xe0, 0x06, 0xc7, 0xf3, 0x0c, 0x18, + 0x91, 0x45, 0x22, 0xa2, 0x30, 0x48, 0x82, 0xeb, 0x42, 0xfc, 0x8f, 0x2a, + 0xa3, 0x1a, 0x8d, 0x84, 0x28, 0x20, 0x16, 0x95, 0xd9, 0x66, 0x67, 0x2b, + 0xef, 0xc6, 0x6e, 0x56, 0x1c, 0x62, 0x74, 0x16, 0x5c, 0x3e, 0x17, 0xd0, + 0xb7, 0xdd, 0x70, 0xb6, 0x0e, 0x79, 0x46, 0xc5, 0x4e, 0x72, 0x46, 0x69, + 0xf5, 0xa1, 0x1c, 0x7b, 0xd5, 0x67, 0x5c, 0xb3, 0x46, 0x4d, 0x18, 0x31, + 0x47, 0x42, 0x20, 0xe6, 0x12, 0x84, 0x4e, 0x16, 0x0f, 0x4a, 0xd0, 0xc4, + 0x91, 0xa3, 0xbd, 0x91, 0xcd, 0x86, 0x4c, 0xcd, 0x4b, 0x2e, 0x62, 0x84, + 0xea, 0x19, 0x2d, 0x21, 0x1a, 0x64, 0xc4, 0xd2, 0x24, 0x92, 0x96, 0x04, + 0x66, 0xb5, 0x4a, 0xe4, 0xa9, 0xd6, 0xaf, 0x12, 0x9b, 0xb5, 0x59, 0xe0, + 0x5c, 0x84, 0x84, 0x7c, 0x68, 0x99, 0xd8, 0x23, 0xa2, 0x15, 0xa7, 0x82, + 0xa5, 0x66, 0x95, 0x8f, 0xfe, 0x57, 0xc1, 0x12, 0x6c, 0x89, 0xe5, 0x5b, + 0x5d, 0x64, 0xdb, 0x81, 0x4f, 0x77, 0x3c, 0xc8, 0x52, 0x4e, 0x2a, 0xd6, + 0x74, 0x3c, 0x4b, 0x11, 0xfc, 0xc1, 0x7c, 0x01, 0xba, 0x0f, 0x0f, 0x57, + 0x8a, 0xbe, 0x5b, 0x16, 0x88, 0x96, 0xe6, 0xe9, 0x60, 0xcf, 0x66, 0xe9, + 0xe6, 0x07, 0xb0, 0x0b, 0xa3, 0xa0, 0xad, 0xdf, 0x70, 0xd4, 0xcb, 0x2e, + 0x33, 0x2f, 0xe5, 0xf2, 0x1e, 0x0d, 0x74, 0x7a, 0xf9, 0x4a, 0x0f, 0x32, + 0xb4, 0xa1, 0xc9, 0xf5, 0x3f, 0x0a, 0x06, 0xf9, 0x67, 0x45, 0x9c, 0xd9, + 0x58, 0xd4, 0x0e, 0x72, 0x55, 0x47, 0x49, 0x9b, 0xab, 0x9c, 0x66, 0xe7, + 0x4d, 0x9a, 0x02, 0x1b, 0x41, 0xad, 0xe5, 0x8c, 0x7f, 0xa1, 0xdc, 0xad, + 0xcd, 0x74, 0xda, 0x9f, 0xfa, 0x87, 0x32, 0xc1, 0x07, 0x8e, 0x9b, 0xef, + 0x28, 0x2f, 0x17, 0x6d, 0xdb, 0x84, 0x4b, 0xa8, 0x7d, 0x31, 0xa8, 0x32, + 0xe4, 0x9a, 0x1e, 0x0e, 0xef, 0x68, 0xf4, 0xac, 0x03, 0x6c, 0x68, 0xcc, + 0x28, 0xbb, 0xfb, 0x21, 0xb8, 0x11, 0xd7, 0xf9, 0xe8, 0x24, 0x37, 0xdf, + 0xe0, 0xb2, 0xef, 0xd6, 0xec, 0xdf, 0xcf, 0xf5, 0x50, 0x19, 0xa3, 0xa9, + 0x1b, 0x01, 0x2e, 0x94, 0x42, 0xb0, 0x14, 0x5d, 0x0e, 0x37, 0x46, 0x4a, + 0x52, 0x53, 0x60, 0x6b, 0x89, 0xc9, 0xca, 0xed, 0x0a, 0x0c, 0x18, 0x33, + 0x3c, 0x40, 0x42, 0x76, 0x7a, 0x7d, 0xb6, 0x10, 0x29, 0x3e, 0x42, 0x75, + 0xa6, 0xbf, 0xcb, 0xd3, 0xdc, 0xe1, 0x00, 0x05, 0x08, 0x25, 0x67, 0x6c, + 0x72, 0xde, 0x26, 0x72, 0x88, 0xbe, 0xfa, 0x05, 0x57, 0x77, 0x78, 0x83, + 0xce, 0xd5, 0x44, 0x49, 0x8b, 0xab, 0xbc, 0xca, 0xd3, 0x1c, 0x34, 0x4a, + 0xaa, 0xc7, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x17, 0x22, 0x2a, 0x2f, 0x36, 0x3d, 0x43}; +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_KEYGEN_PCT */ +#endif /* !EXPECTED_SIGNATURES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/main.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/main.c new file mode 100644 index 0000000000..727869036b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/main.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include +#include +#include +#include + +/* Import public mldsa-native API + * + * This requires specifying the parameter set and namespace prefix + * used for the build. + */ +#include +#include "expected_signatures.h" +#include "test_only_rng/notrandombytes.h" + +#define CHECK(x) \ + do \ + { \ + int rc; \ + rc = (x); \ + if (!rc) \ + { \ + fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \ + return 1; \ + } \ + } while (0) + +#define TEST_MSG \ + "This is a test message for ML-DSA digital signature algorithm!" +#define TEST_MSG_LEN (sizeof(TEST_MSG) - 1) + +#define TEST_CTX "test_context_123" +#define TEST_CTX_LEN (sizeof(TEST_CTX) - 1) + +int main(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t sig[CRYPTO_BYTES]; + uint8_t sm[TEST_MSG_LEN + CRYPTO_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + CRYPTO_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-%d Low RAM Example\n", MLD_CONFIG_PARAMETER_SET); + printf("========================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(crypto_sign_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(crypto_sign_signature(sig, &siglen, (const uint8_t *)test_msg, + TEST_MSG_LEN, (const uint8_t *)test_ctx, + TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(crypto_sign_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(crypto_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(crypto_sign_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", CRYPTO_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", CRYPTO_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", CRYPTO_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature)); + CHECK(memcmp(sig, expected_signature, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/mldsa_native.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/mldsa_native.h new file mode 100644 index 0000000000..fd150a9df1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/mldsa_native.h @@ -0,0 +1,975 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_H +#define MLD_H + +/* + * Public API for mldsa-native + * + * This header defines the public API of a single build of mldsa-native. + * + * Make sure the configuration file is in the include path + * (this is "mldsa_native_config.h" by default, or MLD_CONFIG_FILE if defined). + * + * # Multi-level builds + * + * This header specifies a build of mldsa-native for a fixed security level. + * If you need multiple security levels, leave the security level unspecified + * in the configuration file and include this header multiple times, setting + * MLD_CONFIG_PARAMETER_SET accordingly for each, and #undef'ing the MLD_H + * guard to allow multiple inclusions. + * + * # Legacy configuration (deprecated) + * + * Instead of providing the config file used for the build, you can + * alternatively set the following configuration options prior to + * including this header. + * + * This method of configuration is deprecated. + * It will be removed in mldsa-native-v2. + * + * - MLD_CONFIG_API_PARAMETER_SET [required] + * + * The parameter set used for the build; 44, 65, or 87. + * + * - MLD_CONFIG_API_NAMESPACE_PREFIX [required] + * + * The namespace prefix used for the build. + * + * NOTE: + * For a multi-level build, you must include the 44/65/87 suffixes + * in MLD_CONFIG_API_NAMESPACE_PREFIX. + * + * - MLD_CONFIG_API_NO_SUPERCOP [optional] + * + * By default, this header will also expose the mldsa-native API in the + * SUPERCOP naming convention crypto_sign_xxx. If you don't want/need this, + * set MLD_CONFIG_API_NO_SUPERCOP. You must set this for a multi-level build. + * + * - MLD_CONFIG_API_CONSTANTS_ONLY [optional] + * + * If you don't want this header to expose any function declarations, + * but only constants for the sizes of key material, set + * MLD_CONFIG_API_CONSTANTS_ONLY. In this case, you don't need to set + * MLD_CONFIG_API_PARAMETER_SET or MLD_CONFIG_API_NAMESPACE_PREFIX, + * nor include a configuration. + * + * - MLD_CONFIG_API_QUALIFIER [optional] + * + * Qualifier to apply to external API. + * + ******************************************************************************/ + +/******************************* Key sizes ************************************/ + +/* Sizes of cryptographic material, per parameter set */ +/* See mldsa/src/params.h for the arithmetic expressions giving rise to these */ +/* check-magic: off */ +#define MLDSA44_SECRETKEYBYTES 2560 +#define MLDSA44_PUBLICKEYBYTES 1312 +#define MLDSA44_BYTES 2420 + +#define MLDSA65_SECRETKEYBYTES 4032 +#define MLDSA65_PUBLICKEYBYTES 1952 +#define MLDSA65_BYTES 3309 + +#define MLDSA87_SECRETKEYBYTES 4896 +#define MLDSA87_PUBLICKEYBYTES 2592 +#define MLDSA87_BYTES 4627 +/* check-magic: on */ + +/* Size of seed and randomness in bytes (level-independent) */ +#define MLDSA_SEEDBYTES 32 +#define MLDSA44_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA65_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA87_SEEDBYTES MLDSA_SEEDBYTES + +/* Size of CRH output in bytes (level-independent) */ +#define MLDSA_CRHBYTES 64 +#define MLDSA44_CRHBYTES MLDSA_CRHBYTES +#define MLDSA65_CRHBYTES MLDSA_CRHBYTES +#define MLDSA87_CRHBYTES MLDSA_CRHBYTES + +/* Size of TR output in bytes (level-independent) */ +#define MLDSA_TRBYTES 64 +#define MLDSA44_TRBYTES MLDSA_TRBYTES +#define MLDSA65_TRBYTES MLDSA_TRBYTES +#define MLDSA87_TRBYTES MLDSA_TRBYTES + +/* Size of randomness for signing in bytes (level-independent) */ +#define MLDSA_RNDBYTES 32 +#define MLDSA44_RNDBYTES MLDSA_RNDBYTES +#define MLDSA65_RNDBYTES MLDSA_RNDBYTES +#define MLDSA87_RNDBYTES MLDSA_RNDBYTES + +/* Sizes of cryptographic material, as a function of LVL=44,65,87 */ +#define MLDSA_SECRETKEYBYTES_(LVL) MLDSA##LVL##_SECRETKEYBYTES +#define MLDSA_PUBLICKEYBYTES_(LVL) MLDSA##LVL##_PUBLICKEYBYTES +#define MLDSA_BYTES_(LVL) MLDSA##LVL##_BYTES +#define MLDSA_SECRETKEYBYTES(LVL) MLDSA_SECRETKEYBYTES_(LVL) +#define MLDSA_PUBLICKEYBYTES(LVL) MLDSA_PUBLICKEYBYTES_(LVL) +#define MLDSA_BYTES(LVL) MLDSA_BYTES_(LVL) + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + +/****************************** Function API **********************************/ + +#define MLD_API_CONCAT_(x, y) x##y +#define MLD_API_CONCAT(x, y) MLD_API_CONCAT_(x, y) +#define MLD_API_CONCAT_UNDERSCORE(x, y) MLD_API_CONCAT(MLD_API_CONCAT(x, _), y) + +#if !defined(MLD_CONFIG_API_PARAMETER_SET) +/* Recommended configuration via same config file as used for the build. */ + +/* For now, we derive the legacy API configuration MLD_CONFIG_API_XXX from + * the config file. In mldsa-native-v2, this will be removed and we will + * exclusively work with MLD_CONFIG_XXX. */ + +/* You need to make sure the config file is in the include path. */ +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#define MLD_CONFIG_API_PARAMETER_SET MLD_CONFIG_PARAMETER_SET + +#if defined(MLD_CONFIG_MULTILEVEL_BUILD) +#define MLD_CONFIG_API_NAMESPACE_PREFIX \ + MLD_API_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_CONFIG_API_NAMESPACE_PREFIX MLD_CONFIG_NAMESPACE_PREFIX +#endif + +#if defined(MLD_CONFIG_NO_SUPERCOP) +#define MLD_CONFIG_API_NO_SUPERCOP +#endif + +#if defined(MLD_CONFIG_CONSTANTS_ONLY) +#define MLD_CONFIG_API_CONSTANTS_ONLY +#endif + +#if defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_CONFIG_API_QUALIFIER MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#else /* !MLD_CONFIG_API_PARAMETER_SET */ +#define MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_PARAMETER_SET */ + +#define MLD_API_NAMESPACE(sym) \ + MLD_API_CONCAT_UNDERSCORE(MLD_CONFIG_API_NAMESPACE_PREFIX, sym) + +#if defined(__GNUC__) || defined(clang) +#define MLD_API_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_API_MUST_CHECK_RETURN_VALUE +#endif + +#if defined(MLD_CONFIG_API_QUALIFIER) +#define MLD_API_QUALIFIER MLD_CONFIG_API_QUALIFIER +#else +#define MLD_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_API_CONSTANTS_ONLY) + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************************* + * Name: crypto_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: + * input random seed + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair_internal)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t seed[MLDSA_SEEDBYTES] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: If MLD_CONFIG_KEYGEN_PCT is enabled and the + * PCT check failed. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return -1 in that case. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_extmu + * + * Description: Computes signature. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_extmu)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t *sm: pointer to output signed message (allocated array + * with MLDSA{44,65,87}_BYTES + mlen bytes), can be + * equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(sign)( + uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_extmu)( + const uint8_t *sig, size_t siglen, const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_open + * + * Description: Verify signed message. + * + * Arguments: + * - uint8_t *m: pointer to output message (allocated array with + * smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(open)( + uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: crypto_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *ph, size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_shake256)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_shake256)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/* Maximum formatted domain separation message length */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +size_t MLD_API_NAMESPACE(prepare_domain_separation_prefix)( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg); + +/************************************************* + * Name: crypto_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[CRYPTO_SECRETKEYBYTES]: input secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(pk_from_sk)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +#ifdef __cplusplus +} +#endif + +/****************************** SUPERCOP API *********************************/ + +#if !defined(MLD_CONFIG_API_NO_SUPERCOP) +/* Export API in SUPERCOP naming scheme CRYPTO_xxx / crypto_sign_xxx */ +#define CRYPTO_SECRETKEYBYTES MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_PUBLICKEYBYTES MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_BYTES MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET) + +#define crypto_sign_keypair MLD_API_NAMESPACE(keypair) +#define crypto_sign_signature MLD_API_NAMESPACE(signature) +#define crypto_sign MLD_API_NAMESPACE(sign) +#define crypto_sign_verify MLD_API_NAMESPACE(verify) +#define crypto_sign_open MLD_API_NAMESPACE(open) + +#else /* !MLD_CONFIG_API_NO_SUPERCOP */ + +/* If the SUPERCOP API is not needed, we can undefine the various helper macros + * above. Otherwise, they are needed for lazy evaluation of crypto_sign_xxx. */ +#if !defined(MLD_API_LEGACY_CONFIG) +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_QUALIFIER +#endif /* !MLD_API_LEGACY_CONFIG */ + +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_NAMESPACE +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_QUALIFIER +#undef MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_NO_SUPERCOP */ +#endif /* !MLD_CONFIG_API_CONSTANTS_ONLY */ + + +/***************************** Memory Usage **********************************/ + +/* + * By default mldsa-native performs all memory allocations on the stack. + * Alternatively, mldsa-native supports custom allocation of large structures + * through the `MLD_CONFIG_CUSTOM_ALLOC_FREE` configuration option. + * See mldsa_native_config.h for details. + * + * `MLD_TOTAL_ALLOC_{44,65,87}_{KEYPAIR,SIGN,VERIFY}` indicates the maximum + * (accumulative) allocation via MLD_ALLOC for each parameter set and operation. + * Note that some stack allocation remains even + * when using custom allocators, so these values are lower than total stack + * usage with the default stack-only allocation. + * + * These constants may be used to implement custom allocations using a + * fixed-sized buffer and a simple allocator (e.g., bump allocator). + */ +/* check-magic: off */ +#if defined(MLD_API_LEGACY_CONFIG) || !defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 45248 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 56640 +#define MLD_TOTAL_ALLOC_44_SIGN 52896 +#define MLD_TOTAL_ALLOC_44_VERIFY 38816 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 71872 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 85856 +#define MLD_TOTAL_ALLOC_65_SIGN 80576 +#define MLD_TOTAL_ALLOC_65_VERIFY 62432 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 112832 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 130816 +#define MLD_TOTAL_ALLOC_87_SIGN 123584 +#define MLD_TOTAL_ALLOC_87_VERIFY 99552 +#else /* MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM */ +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 32992 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 36192 +#define MLD_TOTAL_ALLOC_44_SIGN 32448 +#define MLD_TOTAL_ALLOC_44_VERIFY 22464 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 46304 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 50048 +#define MLD_TOTAL_ALLOC_65_SIGN 44768 +#define MLD_TOTAL_ALLOC_65_VERIFY 30720 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 62688 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 66336 +#define MLD_TOTAL_ALLOC_87_SIGN 59104 +#define MLD_TOTAL_ALLOC_87_VERIFY 41216 +#endif /* !(MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM) */ +/* check-magic: on */ + +/* + * MLD_TOTAL_ALLOC_*_KEYPAIR adapts based on MLD_CONFIG_KEYGEN_PCT. + * For legacy config, we don't know which options are used, so assume + * the worst case (PCT enabled). + */ +#if defined(MLD_API_LEGACY_CONFIG) || defined(MLD_CONFIG_KEYGEN_PCT) +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#else +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#endif + +#define MLD_MAX3_(a, b, c) \ + ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c))) + +/* + * `MLD_TOTAL_ALLOC_{44,65,87}` is the maximum across all operations for each + * parameter set. + */ +#define MLD_TOTAL_ALLOC_44 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_44_KEYPAIR, MLD_TOTAL_ALLOC_44_SIGN, \ + MLD_TOTAL_ALLOC_44_VERIFY) +#define MLD_TOTAL_ALLOC_65 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_65_KEYPAIR, MLD_TOTAL_ALLOC_65_SIGN, \ + MLD_TOTAL_ALLOC_65_VERIFY) +#define MLD_TOTAL_ALLOC_87 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_87_KEYPAIR, MLD_TOTAL_ALLOC_87_SIGN, \ + MLD_TOTAL_ALLOC_87_VERIFY) + +#endif /* !MLD_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/mldsa_native_config.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/mldsa_native_config.h new file mode 100644 index 0000000000..c2993903f6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/mldsa_native_config.h @@ -0,0 +1,741 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/* + * Test configuration: Configuration for low RAM build of mldsa-native + * + * This configuration differs from the default mldsa/mldsa_native_config.h in + * the following places: + * - MLD_CONFIG_NAMESPACE_PREFIX + * - MLD_CONFIG_REDUCE_RAM + */ + + +#ifndef MLD_CONFIG_H +#define MLD_CONFIG_H + +/****************************************************************************** + * Name: MLD_CONFIG_PARAMETER_SET + * + * Description: Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * If you want to support multiple parameter sets, build the + * library multiple times and set MLD_CONFIG_MULTILEVEL_BUILD. + * See MLD_CONFIG_MULTILEVEL_BUILD for how to do this while + * minimizing code duplication. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of the default configuration file mldsa/mldsa_native_config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * then configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + * + *****************************************************************************/ +/* No need to set this -- we _are_ already in a custom config */ +/* #define MLD_CONFIG_FILE "mldsa_native_config.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_NAMESPACE_PREFIX + * + * Description: The prefix to use to namespace global symbols from mldsa/. + * + * In a multi-level build, level-dependent symbols will + * additionally be prefixed with the parameter set (44/65/87). + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_NAMESPACE_PREFIX mldsa + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_BUILD + * + * Description: Set this if the build is part of a multi-level build supporting + * multiple parameter sets. + * + * If you need only a single parameter set, keep this unset. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them. + * + * See examples/multilevel_build for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_BUILD */ + +/****************************************************************************** + * Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_EXTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_RANDOMIZED_API + * + * Description: If this option is set, mldsa-native will be built without the + * randomized API functions (crypto_sign_keypair, + * crypto_sign, crypto_sign_signature, and + * crypto_sign_signature_extmu). + * This allows users to build mldsa-native without providing a + * randombytes() implementation if they only need the + * internal deterministic API + * (crypto_sign_keypair_internal, crypto_sign_signature_internal). + * + * NOTE: This option is incompatible with MLD_CONFIG_KEYGEN_PCT + * as the current PCT implementation requires + * crypto_sign_signature(). + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_RANDOMIZED_API */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_SUPERCOP + * + * Description: By default, mldsa_native.h exposes the mldsa-native API in the + * SUPERCOP naming convention (crypto_sign_xxx). If you don't need + * this, set MLD_CONFIG_NO_SUPERCOP. + * + * NOTE: You must set this for a multi-level build as the SUPERCOP + * naming does not disambiguate between the parameter sets. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_SUPERCOP */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONSTANTS_ONLY + * + * Description: If you only need the size constants (MLDSA_PUBLICKEYBYTES, etc.) + * but no function declarations, set MLD_CONFIG_CONSTANTS_ONLY. + * + * This only affects the public header mldsa_native.h, not + * the implementation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONSTANTS_ONLY */ + +/****************************************************************************** + * + * Build-only configuration options + * + * The remaining configurations are build-options only. + * They do not affect the API described in mldsa_native.h. + * + *****************************************************************************/ + +#if defined(MLD_BUILD_INTERNAL) +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_WITH_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, all MLD_CONFIG_PARAMETER_SET-independent + * code will be included in the build, including code needed only + * for other parameter sets. + * + * Example: TODO: add example + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_WITH_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_NO_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, no MLD_CONFIG_PARAMETER_SET-independent code + * will be included in the build. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * + * Description: This is only relevant for single compilation unit (SCU) + * builds of mldsa-native. In this case, it determines whether + * directives defined in parameter-set-independent headers should + * be #undef'ined or not at the of the SCU file. This is needed + * in multilevel builds. + * + * See examples/multilevel_build_native for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * + * Description: Determines whether an native arithmetic backend should be used. + * + * The arithmetic backend covers performance critical functions + * such as the number-theoretic transform (NTT). + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the arithmetic backend to be use is + * determined by MLD_CONFIG_ARITH_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_ARITH_BACKEND_FILE + * + * Description: The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * + * Description: Determines whether an native FIPS202 backend should be used. + * + * The FIPS202 backend covers 1x/2x/4x-fold Keccak-f1600, which is + * the performance bottleneck of SHA3 and SHAKE. + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the FIPS202 backend to be use is + * determined by MLD_CONFIG_FIPS202_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_BACKEND_FILE + * + * Description: The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202X4_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202-X4 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202x4.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ZEROIZE + * + * Description: In compliance with @[FIPS204, Section 3.6.3], mldsa-native, + * zeroizes intermediate stack buffers before returning from + * function calls. + * + * Set this option and define `mld_zeroize` if you want to + * use a custom method to zeroize intermediate stack buffers. + * The default implementation uses SecureZeroMemory on Windows + * and a memset + compiler barrier otherwise. If neither of those + * is available on the target platform, compilation will fail, + * and you will need to use MLD_CONFIG_CUSTOM_ZEROIZE to provide + * a custom implementation of `mld_zeroize()`. + * + * WARNING: + * The explicit stack zeroization conducted by mldsa-native + * reduces the likelihood of data leaking on the stack, but + * does not eliminate it! The C standard makes no guarantee about + * where a compiler allocates structures and whether/where it makes + * copies of them. Also, in addition to entire structures, there + * may also be potentially exploitable leakage of individual values + * on the stack. + * + * If you need bullet-proof zeroization of the stack, you need to + * consider additional measures instead of what this feature + * provides. In this case, you can set mld_zeroize to a + * no-op. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void mld_zeroize(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * Description: mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to provided by the + * consumer. + * + * If this option is not set, mldsa-native expects a function + * int randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mld_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_RANDOMBYTES + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) + { + ... your implementation ... + return 0; + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + * + * Description: mldsa-native backends may rely on specific hardware features. + * Those backends will only be included in an mldsa-native build + * if support for the respective features is enabled at + * compile-time. However, when building for a heteroneous set + * of CPUs to run the resulting binary/library on, feature + * detection at _runtime_ is needed to decided whether a backend + * can be used or not. + * + * Set this option and define `mld_sys_check_capability` if you + * want to use a custom method to dispatch between implementations. + * + * Return value 1 indicates that a capability is supported. + * Return value 0 indicates that a capability is not supported. + * + * If this option is not set, mldsa-native uses compile-time + * feature detection only to decide which backend to use. + * + * If you compile mldsa-native on a system with different + * capabilities than the system that the resulting binary/library + * will be run on, you must use this option. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) + { + ... your implementation ... + } +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ALLOC_FREE [EXPERIMENTAL] + * + * Description: Set this option and define `MLD_CUSTOM_ALLOC` and + * `MLD_CUSTOM_FREE` if you want to use custom allocation for + * large local structures or buffers. + * + * By default, all buffers/structures are allocated on the stack. + * If this option is set, most of them will be allocated via + * MLD_CUSTOM_ALLOC. + * + * Parameters to MLD_CUSTOM_ALLOC: + * - T* v: Target pointer to declare. + * - T: Type of structure to be allocated + * - N: Number of elements to be allocated. + * + * Parameters to MLD_CUSTOM_FREE: + * - T* v: Target pointer to free. May be NULL. + * - T: Type of structure to be freed. + * - N: Number of elements to be freed. + * + * WARNING: This option is experimental! + * Its scope, configuration and function/macro signatures may + * change at any time. We expect a stable API for v2. + * + * NOTE: Even if this option is set, some allocations further down + * the call stack will still be made from the stack. Those will + * likely be added to the scope of this option in the future. + * + * NOTE: MLD_CUSTOM_ALLOC need not guarantee a successful + * allocation nor include error handling. Upon failure, the + * target pointer should simply be set to NULL. The calling + * code will handle this case and invoke MLD_CUSTOM_FREE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ALLOC_FREE + #if !defined(__ASSEMBLER__) + #include + #define MLD_CUSTOM_ALLOC(v, T, N) \ + T* (v) = (T *)aligned_alloc(MLD_DEFAULT_ALIGN, \ + MLD_ALIGN_UP(sizeof(T) * (N))) + #define MLD_CUSTOM_FREE(v, T, N) free(v) + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMCPY + * + * Description: Set this option and define `mld_memcpy` if you want to + * use a custom method to copy memory instead of the standard + * library memcpy function. + * + * The custom implementation must have the same signature and + * behavior as the standard memcpy function: + * void *mld_memcpy(void *dest, const void *src, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMCPY + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMSET + * + * Description: Set this option and define `mld_memset` if you want to + * use a custom method to set memory instead of the standard + * library memset function. + * + * The custom implementation must have the same signature and + * behavior as the standard memset function: + * void *mld_memset(void *s, int c, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMSET + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memset(void *s, int c, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_INTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of internal API. + * + * The primary use case for this option are single-CU builds, + * in which case this option can be set to `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_INTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CT_TESTING_ENABLED + * + * Description: If set, mldsa-native annotates data as secret / public using + * valgrind's annotations VALGRIND_MAKE_MEM_UNDEFINED and + * VALGRIND_MAKE_MEM_DEFINED, enabling various checks for secret- + * dependent control flow of variable time execution (depending + * on the exact version of valgrind installed). + * + *****************************************************************************/ +/* #define MLD_CONFIG_CT_TESTING_ENABLED */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * and MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT + * + * Description: Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, crypto_sign_keypair_internal and + * crypto_sign_keypair will return a non-zero error code if the + * PCT failed. + * + * NOTE: This feature will drastically lower the performance of + * key generation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * Description: If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "src/src.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Description: Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * NOTE: Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + * + *****************************************************************************/ +/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER + * + * Description: Set this to add a context parameter that is provided to public + * API functions and is then available in custom callbacks. + * + * The type of the context parameter is configured via + * MLD_CONFIG_CONTEXT_PARAMETER_TYPE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER_TYPE + * + * Description: Set this to define the type for the context parameter used by + * MLD_CONFIG_CONTEXT_PARAMETER. + * + * This is only relevant if MLD_CONFIG_CONTEXT_PARAMETER is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER_TYPE void* */ + +/****************************************************************************** + * Name: MLD_CONFIG_REDUCE_RAM [EXPERIMENTAL] + * + * Description: Set this to reduce RAM usage. + * This trades memory for performance. + * + * For expected memory usage, see the MLD_TOTAL_ALLOC_* constants + * defined in mldsa_native.h. + * + * This option is useful for embedded systems with tight RAM + * constraints but relaxed performance requirements. + * + * WARNING: This option is experimental! + * CBMC proofs do not currently cover this configuration option. + * Its scope and configuration may change at any time. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_CONFIG_REDUCE_RAM +#endif + + +/************************* Config internals ********************************/ + +#endif /* MLD_BUILD_INTERNAL */ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace is + * + * PQCP_MLDSA_NATIVE_MLDSA_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_ + */ + +#if MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65 +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87 +#endif + +#endif /* !MLD_CONFIG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/cbmc.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/cbmc.h new file mode 100644 index 0000000000..8ed1ecb06b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/cbmc.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_CBMC_H +#define MLD_CBMC_H +/*************************************************** + * Basic replacements for __CPROVER_XXX contracts + ***************************************************/ +#ifndef CBMC + +#define __contract__(x) +#define __loop__(x) +#define cassert(x) + +#else /* !CBMC */ + +#include + +#define __contract__(x) x +#define __loop__(x) x + +/* https://diffblue.github.io/cbmc/contracts-assigns.html */ +#define assigns(...) __CPROVER_assigns(__VA_ARGS__) + +/* https://diffblue.github.io/cbmc/contracts-requires-ensures.html */ +#define requires(...) __CPROVER_requires(__VA_ARGS__) +#define ensures(...) __CPROVER_ensures(__VA_ARGS__) +/* https://diffblue.github.io/cbmc/contracts-loops.html */ +#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__) +#define decreases(...) __CPROVER_decreases(__VA_ARGS__) +/* cassert to avoid confusion with in-built assert */ +#define cassert(x) __CPROVER_assert(x, "cbmc assertion failed") +#define assume(...) __CPROVER_assume(__VA_ARGS__) + +/*************************************************** + * Macros for "expression" forms that may appear + * _inside_ top-level contracts. + ***************************************************/ + +/* + * function return value - useful inside ensures + * https://diffblue.github.io/cbmc/contracts-functions.html + */ +#define return_value (__CPROVER_return_value) + +/* + * assigns l-value targets + * https://diffblue.github.io/cbmc/contracts-assigns.html + */ +#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__) +#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__) +#define same_object(...) __CPROVER_same_object(__VA_ARGS__) + +/* + * Pointer-related predicates + * https://diffblue.github.io/cbmc/contracts-memory-predicates.html + */ +#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__) +#define readable(...) __CPROVER_r_ok(__VA_ARGS__) +#define writeable(...) __CPROVER_w_ok(__VA_ARGS__) + +/* Maximum supported buffer size + * + * Larger buffers may be supported, but due to internal modeling constraints + * in CBMC, the proofs of memory- and type-safety won't be able to run. + * + * If you find yourself in need for a buffer size larger than this, + * please contact the maintainers, so we can prioritize work to relax + * this somewhat artificial bound. + */ +#define MLD_MAX_BUFFER_SIZE (SIZE_MAX >> 12) + + +/* + * History variables + * https://diffblue.github.io/cbmc/contracts-history-variables.html + */ +#define old(...) __CPROVER_old(__VA_ARGS__) +#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__) + +/* + * Quantifiers + * Note that the range on qvar is _exclusive_ between qvar_lb .. qvar_ub + * https://diffblue.github.io/cbmc/contracts-quantifiers.html + */ + +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define forall(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> (predicate) \ + } + +#define exists(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_exists \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) && (predicate) \ + } +/* clang-format on */ + +/*************************************************** + * Convenience macros for common contract patterns + ***************************************************/ +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define CBMC_CONCAT_(left, right) left##right +#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right) + +#define array_bound_core(qvar, qvar_lb, qvar_ub, array_var, \ + value_lb, value_ub) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + (((int)(value_lb) <= ((array_var)[(qvar)])) && \ + (((array_var)[(qvar)]) < (int)(value_ub))) \ + } + +#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \ + array_bound_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (qvar_lb), \ + (qvar_ub), (array_var), (value_lb), (value_ub)) + +#define array_unchanged_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (int32_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged(array_var, N) \ + array_unchanged_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) + +#define array_unchanged_u64_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (uint64_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged_u64(array_var, N) \ + array_unchanged_u64_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) +/* clang-format on */ + +/* Wrapper around array_bound operating on absolute values. + * + * The absolute value bound `k` is exclusive. + * + * Note that since the lower bound in array_bound is inclusive, we have to + * raise it by 1 here. + */ +#define array_abs_bound(arr, lb, ub, k) \ + array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k)) + +#endif /* CBMC */ + +#endif /* !MLD_CBMC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/common.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/common.h new file mode 100644 index 0000000000..4a5bc8109d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/common.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_COMMON_H +#define MLD_COMMON_H + +#define MLD_BUILD_INTERNAL + +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#include "params.h" +#include "sys.h" + +/* Internal and public API have external linkage by default, but + * this can be overwritten by the user, e.g. for single-CU builds. */ +#if !defined(MLD_CONFIG_INTERNAL_API_QUALIFIER) +#define MLD_INTERNAL_API +#else +#define MLD_INTERNAL_API MLD_CONFIG_INTERNAL_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_EXTERNAL_API +#else +#define MLD_EXTERNAL_API MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#if defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) || \ + defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) +#define MLD_MULTILEVEL_BUILD +#endif + +#define MLD_CONCAT_(x1, x2) x1##x2 +#define MLD_CONCAT(x1, x2) MLD_CONCAT_(x1, x2) + +#if defined(MLD_MULTILEVEL_BUILD) +#define MLD_ADD_PARAM_SET(s) MLD_CONCAT(s, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_ADD_PARAM_SET(s) s +#endif + +#define MLD_NAMESPACE_PREFIX MLD_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, _) +#define MLD_NAMESPACE_PREFIX_KL \ + MLD_CONCAT(MLD_ADD_PARAM_SET(MLD_CONFIG_NAMESPACE_PREFIX), _) + +/* Functions are prefixed by MLD_CONFIG_NAMESPACE_PREFIX. + * + * If multiple parameter sets are used, functions depending on the parameter + * set are additionally prefixed with 44/65/87. See mldsa_native_config.h. + * + * Example: If MLD_CONFIG_NAMESPACE_PREFIX is PQCP_MLDSA_NATIVE, then + * MLD_NAMESPACE_KL(keypair) becomes PQCP_MLDSA_NATIVE44_keypair/ + * PQCP_MLDSA_NATIVE65_keypair/PQCP_MLDSA_NATIVE87_keypair. + */ +#define MLD_NAMESPACE(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX, s) +#define MLD_NAMESPACE_KL(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX_KL, s) + +/* On Apple platforms, we need to emit leading underscore + * in front of assembly symbols. We thus introducee a separate + * namespace wrapper for ASM symbols. */ +#if !defined(__APPLE__) +#define MLD_ASM_NAMESPACE(sym) MLD_NAMESPACE(sym) +#else +#define MLD_ASM_NAMESPACE(sym) MLD_CONCAT(_, MLD_NAMESPACE(sym)) +#endif + +/* + * On X86_64 if control-flow protections (CET) are enabled (through + * -fcf-protection=), we add an endbr64 instruction at every global function + * label. See sys.h for more details + */ +#if defined(MLD_SYS_X86_64) +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : MLD_CET_ENDBR +#else +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : +#endif + +/* We aim to simplify the user's life by supporting builds where + * all source files are included, even those that are not needed. + * Those files are appropriately guarded and will be empty when unneeded. + * The following is to avoid compilers complaining about this. */ +#define MLD_EMPTY_CU(s) extern int MLD_NAMESPACE_KL(empty_cu_##s); + +/* MLD_CONFIG_NO_ASM takes precedence over MLD_USE_NATIVE_XXX */ +#if defined(MLD_CONFIG_NO_ASM) +#undef MLD_CONFIG_USE_NATIVE_BACKEND_ARITH +#undef MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, but MLD_CONFIG_ARITH_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, but MLD_CONFIG_FIPS202_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_NO_RANDOMIZED_API) && defined(MLD_CONFIG_KEYGEN_PCT) +#error Bad configuration: MLD_CONFIG_NO_RANDOMIZED_API is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires crypto_sign_signature() +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#include MLD_CONFIG_ARITH_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#include MLD_CONFIG_FIPS202_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "fips202/native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#define MLD_FIPS202_HEADER_FILE "fips202/fips202.h" +#else +#define MLD_FIPS202_HEADER_FILE MLD_CONFIG_FIPS202_CUSTOM_HEADER +#endif + +#if !defined(MLD_CONFIG_FIPS202X4_CUSTOM_HEADER) +#define MLD_FIPS202X4_HEADER_FILE "fips202/fips202x4.h" +#else +#define MLD_FIPS202X4_HEADER_FILE MLD_CONFIG_FIPS202X4_CUSTOM_HEADER +#endif + +/* Standard library function replacements */ +#if !defined(__ASSEMBLER__) +#if !defined(MLD_CONFIG_CUSTOM_MEMCPY) +#include +#define mld_memcpy memcpy +#endif + +#if !defined(MLD_CONFIG_CUSTOM_MEMSET) +#include +#define mld_memset memset +#endif + +/* Allocation macros for large local structures + * + * MLD_ALLOC(v, T, N) declares T *v and attempts to point it to an T[N] + * MLD_FREE(v, T, N) zeroizes and frees the allocation + * + * Default implementation uses stack allocation. + * Can be overridden by setting the config option MLD_CONFIG_CUSTOM_ALLOC_FREE + * and defining MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE. + */ +#if defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) != \ + (defined(MLD_CUSTOM_ALLOC) && defined(MLD_CUSTOM_FREE)) +#error Bad configuration: MLD_CONFIG_CUSTOM_ALLOC_FREE must be set together with MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE +#endif + +/* + * If the integration wants to provide a context parameter for use in + * platform-specific hooks, then it should define this parameter. + * + * The MLD_CONTEXT_PARAMETERS_n macros are intended to be used with macros + * defining the function names and expand to either pass or discard the context + * argument as required by the current build. If there is no context parameter + * requested then these are removed from the prototypes and from all calls. + */ +#ifdef MLD_CONFIG_CONTEXT_PARAMETER +#define MLD_CONTEXT_PARAMETERS_0(context) (context) +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0, context) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1, context) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) \ + (arg0, arg1, arg2, context) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3, context) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4, context) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, context) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, context) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, context) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, context) +#else /* MLD_CONFIG_CONTEXT_PARAMETER */ +#define MLD_CONTEXT_PARAMETERS_0(context) () +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) (arg0, arg1, arg2) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) +#endif /* !MLD_CONFIG_CONTEXT_PARAMETER */ + +#if defined(MLD_CONFIG_CONTEXT_PARAMETER_TYPE) != \ + defined(MLD_CONFIG_CONTEXT_PARAMETER) +#error MLD_CONFIG_CONTEXT_PARAMETER_TYPE must be defined if and only if MLD_CONFIG_CONTEXT_PARAMETER is defined +#endif + +#if !defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) +/* Default: stack allocation */ + +#define MLD_ALLOC(v, T, N, context) \ + MLD_ALIGN T mld_alloc_##v[N]; \ + T *v = mld_alloc_##v + +/* TODO: This leads to a circular dependency between common and ct.h + * It just works out before we're at the end of the file, but it's still + * prone to issues in the future. */ +#include "ct.h" +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + mld_zeroize(mld_alloc_##v, sizeof(mld_alloc_##v)); \ + (v) = NULL; \ + } while (0) + +#else /* !MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* Custom allocation */ + +/* + * The indirection here is necessary to use MLD_CONTEXT_PARAMETERS_3 here. + */ +#define MLD_APPLY(f, args) f args + +#define MLD_ALLOC(v, T, N, context) \ + MLD_APPLY(MLD_CUSTOM_ALLOC, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)) + +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + if (v != NULL) \ + { \ + mld_zeroize(v, sizeof(T) * (N)); \ + MLD_APPLY(MLD_CUSTOM_FREE, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)); \ + v = NULL; \ + } \ + } while (0) + +#endif /* MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* + * We are facing severe CBMC performance issues when using unions. + * As a temporary workaround, we use unions only when MLD_CONFIG_REDUCE_RAM is + * set. + * TODO: Remove the workaround once + * https://github.com/diffblue/cbmc/issues/8813 + * is resolved + */ +#if defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_UNION_OR_STRUCT union +#else +#define MLD_UNION_OR_STRUCT struct +#endif + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_COMMON_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/ct.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/ct.c new file mode 100644 index 0000000000..010b1a52a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/ct.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include "ct.h" + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +/* + * Masking value used in constant-time functions from + * ct.h to block the compiler's range analysis and + * thereby reduce the risk of compiler-introduced branches. + */ +volatile uint64_t mld_ct_opt_blocker_u64 = 0; + +#else /* !MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(ct) + +#endif /* !(!MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/ct.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/ct.h new file mode 100644 index 0000000000..c307456468 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/ct.h @@ -0,0 +1,366 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [libmceliece] + * libmceliece implementation of Classic McEliece + * Bernstein, Chou + * https://lib.mceliece.org/ + * + * - [optblocker] + * PQC forum post on opt-blockers using volatile globals + * Daniel J. Bernstein + * https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ + */ + +#ifndef MLD_CT_H +#define MLD_CT_H + +#include +#include "cbmc.h" +#include "common.h" + +/* Constant-time comparisons and conditional operations + + We reduce the risk for compilation into variable-time code + through the use of 'value barriers'. + + Functionally, a value barrier is a no-op. To the compiler, however, + it constitutes an arbitrary modification of its input, and therefore + harden's value propagation and range analysis. + + We consider two approaches to implement a value barrier: + - An empty inline asm block which marks the target value as clobbered. + - XOR'ing with the value of a volatile global that's set to 0; + see @[optblocker] for a discussion of this idea, and + @[libmceliece, inttypes/crypto_intN.h] for an implementation. + + The first approach is cheap because it only prevents the compiler + from reasoning about the value of the variable past the barrier, + but does not directly generate additional instructions. + + The second approach generates redundant loads and XOR operations + and therefore comes at a higher runtime cost. However, it appears + more robust towards optimization, as compilers should never drop + a volatile load. + + We use the empty-ASM value barrier for GCC and clang, and fall + back to the global volatile barrier otherwise. + + The global value barrier can be forced by setting + MLD_CONFIG_NO_ASM_VALUE_BARRIER. + +*/ + +#if defined(MLD_HAVE_INLINE_ASM) && !defined(MLD_CONFIG_NO_ASM_VALUE_BARRIER) +#define MLD_USE_ASM_VALUE_BARRIER +#endif + + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) +/* + * Declaration of global volatile that the global value barrier + * is loading from and masking with. + */ +#define mld_ct_opt_blocker_u64 MLD_NAMESPACE(ct_opt_blocker_u64) +extern volatile uint64_t mld_ct_opt_blocker_u64; + + +/* Helper functions for obtaining global masks of various sizes */ + +/* This contract is not proved but treated as an axiom. + * + * Its validity relies on the assumption that the global opt-blocker + * constant mld_ct_opt_blocker_u64 is not modified. + */ +static MLD_INLINE uint64_t mld_ct_get_optblocker_u64(void) +__contract__(ensures(return_value == 0)) { return mld_ct_opt_blocker_u64; } + +static MLD_INLINE int64_t mld_ct_get_optblocker_i64(void) +__contract__(ensures(return_value == 0)) { return (int64_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint32_t mld_ct_get_optblocker_u32(void) +__contract__(ensures(return_value == 0)) { return (uint32_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint8_t mld_ct_get_optblocker_u8(void) +__contract__(ensures(return_value == 0)) { return (uint8_t)mld_ct_get_optblocker_u64(); } + +/* Opt-blocker based implementation of value barriers */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_i64()); } + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u32()); } + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u8()); } + + +#else /* !MLD_USE_ASM_VALUE_BARRIER */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} +#endif /* MLD_USE_ASM_VALUE_BARRIER */ + +#ifdef CBMC +#pragma CPROVER check push +#pragma CPROVER check disable "conversion" +#endif + +/************************************************* + * Name: mld_cast_uint32_to_int32 + * + * Description: Cast uint32 value to int32 + * + * Returns: For uint32_t x, the unique y in int32_t + * so that x == y mod 2^32. + * + * Concretely: + * - x < 2^31: returns x + * - x >= 2^31: returns x - 2^31 + * + **************************************************/ +static MLD_ALWAYS_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x) +{ + /* + * PORTABILITY: This relies on uint32_t -> int32_t + * being implemented as the inverse of int32_t -> uint32_t, + * which is implementation-defined (C99 6.3.1.3 (3)) + * CBMC (correctly) fails to prove this conversion is OK, + * so we have to suppress that check here + */ + return (int32_t)x; +} + +#ifdef CBMC +#pragma CPROVER check pop +#endif + + +/************************************************* + * Name: mld_cast_int64_to_uint32 + * + * Description: Cast int64 value to uint32 as per C standard. + * + * Returns: For int64_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int64_to_uint32(int64_t x) +{ + return (uint32_t)(x & (int64_t)UINT32_MAX); +} + +/************************************************* + * Name: mld_cast_int32_to_uint32 + * + * Description: Cast int32 value to uint32 as per C standard. + * + * Returns: For int32_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int32_to_uint32(int32_t x) +{ + return mld_cast_int64_to_uint32((int64_t)x); +} + +/************************************************* + * Name: mld_ct_sel_int32 + * + * Description: Functionally equivalent to cond ? a : b, + * but implemented with guards against + * compiler-introduced branches. + * + * Arguments: int32_t a: First alternative + * int32_t b: Second alternative + * uint32_t cond: Condition variable. + * + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_sel_int32(int32_t a, int32_t b, uint32_t cond) +__contract__( + requires(cond == 0x0 || cond == 0xFFFFFFFF) + ensures(return_value == (cond ? a : b)) +) +{ + uint32_t au = mld_cast_int32_to_uint32(a); + uint32_t bu = mld_cast_int32_to_uint32(b); + uint32_t res = bu ^ (mld_value_barrier_u32(cond) & (au ^ bu)); + return mld_cast_uint32_to_int32(res); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u32 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_nonzero_u32(uint32_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFFFFFFFF))) +{ + int64_t tmp = mld_value_barrier_i64(-((int64_t)x)); + tmp >>= 32; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u8 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint8_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint8_t mld_ct_cmask_nonzero_u8(uint8_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFF))) +{ + uint32_t mask = mld_ct_cmask_nonzero_u32((uint32_t)x); + return (uint8_t)(mask & 0xFF); +} + +/************************************************* + * Name: mld_ct_cmask_neg_i32 + * + * Description: Return 0 if input is non-negative, and -1 otherwise. + * + * Arguments: int32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_neg_i32(int32_t x) +__contract__( + ensures(return_value == ((x < 0) ? 0xFFFFFFFF : 0)) +) +{ + int64_t tmp = mld_value_barrier_i64((int64_t)x); + tmp >>= 31; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_abs_i32 + * + * Description: Return -x if x<0, x otherwise + * + * Arguments: int32_t x: Input value + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_abs_i32(int32_t x) +__contract__( + requires(x >= -INT32_MAX) + ensures(return_value == ((x < 0) ? -x : x)) +) +{ + return mld_ct_sel_int32(-x, x, mld_ct_cmask_neg_i32(x)); +} + +/************************************************* + * Name: mld_ct_memcmp + * + * Description: Compare two arrays for equality in constant time. + * + * Arguments: const uint8_t *a: pointer to first byte array + * const uint8_t *b: pointer to second byte array + * size_t len: length of the byte arrays, upper-bounded + * to UINT16_MAX to control proof complexity + * only. + * + * Returns 0 if the byte arrays are equal, 0xFF otherwise. + **************************************************/ +static MLD_INLINE uint8_t mld_ct_memcmp(const uint8_t *a, const uint8_t *b, + const size_t len) +__contract__( + requires(len <= UINT16_MAX) + requires(memory_no_alias(a, len)) + requires(memory_no_alias(b, len)) + ensures((return_value == 0) || (return_value == 0xFF)) + ensures((return_value == 0) == forall(i, 0, len, (a[i] == b[i])))) +{ + uint8_t r = 0, s = 0; + unsigned i; + + for (i = 0; i < len; i++) + __loop__( + invariant(i <= len) + invariant((r == 0) == (forall(k, 0, i, (a[k] == b[k]))))) + { + r |= a[i] ^ b[i]; + /* s is useless, but prevents the loop from being aborted once r=0xff. */ + s ^= a[i] ^ b[i]; + } + + /* + * - Convert r into a mask; this may not be necessary, but is an additional + * safeguard + * towards leaking information about a and b. + * - XOR twice with s, separated by a value barrier, to prevent the compile + * from dropping the s computation in the loop. + */ + return (mld_value_barrier_u8(mld_ct_cmask_nonzero_u8(r) ^ s) ^ s); +} + +/************************************************* + * Name: mld_zeroize + * + * Description: Force-zeroize a buffer. + * @[FIPS204, Section 3.6.3] Destruction of intermediate + * values. + * + * Arguments: void *ptr: pointer to buffer to be zeroed + * size_t len: Amount of bytes to be zeroed + **************************************************/ +#if !defined(MLD_CONFIG_CUSTOM_ZEROIZE) +#if defined(MLD_SYS_WINDOWS) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) { SecureZeroMemory(ptr, len); } +#elif defined(MLD_HAVE_INLINE_ASM) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) +{ + memset(ptr, 0, len); + /* This follows OpenSSL and seems sufficient to prevent the compiler + * from optimizing away the memset. + * + * If there was a reliable way to detect availability of memset_s(), + * that would be preferred. */ + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +} +#else /* !MLD_SYS_WINDOWS && MLD_HAVE_INLINE_ASM */ +#error No plausibly-secure implementation of mld_zeroize available. Please provide your own using MLD_CONFIG_CUSTOM_ZEROIZE. +#endif /* !MLD_SYS_WINDOWS && !MLD_HAVE_INLINE_ASM */ +#endif /* !MLD_CONFIG_CUSTOM_ZEROIZE */ + +#endif /* !MLD_CT_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/debug.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/debug.c new file mode 100644 index 0000000000..a55d51e8b1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/debug.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* NOTE: You can remove this file unless you compile with MLDSA_DEBUG. */ + +#include "common.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#if defined(MLDSA_DEBUG) + +#include +#include +#include +#include "debug.h" + +#define MLD_DEBUG_ERROR_HEADER "[ERROR:%s:%04d] " + +void mld_debug_check_assert(const char *file, int line, const int val) +{ + if (val == 0) + { + fprintf(stderr, MLD_DEBUG_ERROR_HEADER "Assertion failed (value %d)\n", + file, line, val); + exit(1); + } +} + +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive) +{ + int err = 0; + unsigned i; + for (i = 0; i < len; i++) + { + int32_t val = ptr[i]; + if (!(val > lower_bound_exclusive && val < upper_bound_exclusive)) + { + fprintf(stderr, + MLD_DEBUG_ERROR_HEADER + "Bounds assertion failed: Index %u, value %d out of bounds " + "(%" PRId64 ",%" PRId64 ")\n", + file, line, i, (int)val, lower_bound_exclusive, + upper_bound_exclusive); + err = 1; + } + } + + if (err == 1) + { + exit(1); + } +} + +#else /* MLDSA_DEBUG */ + +MLD_EMPTY_CU(debug) + +#endif /* !MLDSA_DEBUG */ + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(debug) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_DEBUG_ERROR_HEADER diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/debug.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/debug.h new file mode 100644 index 0000000000..af187bb9de --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/debug.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_DEBUG_H +#define MLD_DEBUG_H +#include "common.h" + +#if defined(MLDSA_DEBUG) +#include + +/************************************************* + * Name: mld_assert + * + * Description: Check debug assertion + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - val: Value asserted to be non-zero + **************************************************/ +#define mld_debug_check_assert MLD_NAMESPACE(mldsa_debug_assert) +void mld_debug_check_assert(const char *file, int line, const int val); + +/************************************************* + * Name: mld_debug_check_bounds + * + * Description: Check whether values in an array of int32_t + * are within specified bounds. + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - ptr: Base of array to be checked + * - len: Number of int32_t in ptr + * - lower_bound_exclusive: Exclusive lower bound + * - upper_bound_exclusive: Exclusive upper bound + **************************************************/ +#define mld_debug_check_bounds MLD_NAMESPACE(mldsa_debug_check_bounds) +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive); + +/* Check assertion, calling exit() upon failure + * + * val: Value that's asserted to be non-zero + */ +#define mld_assert(val) mld_debug_check_assert(__FILE__, __LINE__, (val)) + +/* Check bounds in array of int32_t's + * ptr: Base of int32_t array; will be explicitly cast to int32_t*, + * so you may pass a byte-compatible type such as mld_poly or mld_polyvec. + * len: Number of int32_t in array + * value_lb: Inclusive lower value bound + * value_ub: Exclusive upper value bound */ +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + mld_debug_check_bounds(__FILE__, __LINE__, (const int32_t *)(ptr), (len), \ + ((int64_t)(value_lb)) - 1, (value_ub)) + +/* Check absolute bounds in array of int32_t's + * ptr: Base of array, expression of type int32_t* + * len: Number of int32_t in array + * value_abs_bd: Exclusive absolute upper bound */ +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + mld_assert_bound((ptr), (len), (-((int64_t)(value_abs_bd)) + 1), \ + (value_abs_bd)) + +/* Version of bounds assertions for 2-dimensional arrays */ +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + mld_assert_bound((ptr), ((len0) * (len1)), (value_lb), (value_ub)) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + mld_assert_abs_bound((ptr), ((len0) * (len1)), (value_abs_bd)) + +/* When running CBMC, convert debug assertions into proof obligations */ +#elif defined(CBMC) +#include "cbmc.h" + +#define mld_assert(val) cassert(val) + +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + cassert(array_bound(((int32_t *)(ptr)), 0, (len), (value_lb), (value_ub))) + +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + cassert(array_abs_bound(((int32_t *)(ptr)), 0, (len), (value_abs_bd))) + +/* Because of https://github.com/diffblue/cbmc/issues/8570, we can't + * just use a single flattened array_bound(...) here. */ +#define mld_assert_bound_2d(ptr, M, N, value_lb, value_ub) \ + cassert(forall(kN, 0, (M), \ + array_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_lb), (value_ub)))) + +#define mld_assert_abs_bound_2d(ptr, M, N, value_abs_bd) \ + cassert(forall(kN, 0, (M), \ + array_abs_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_abs_bd)))) + +#else /* !MLDSA_DEBUG && CBMC */ + +#define mld_assert(val) \ + do \ + { \ + } while (0) +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + do \ + { \ + } while (0) +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + do \ + { \ + } while (0) + +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + do \ + { \ + } while (0) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + do \ + { \ + } while (0) + + +#endif /* !MLDSA_DEBUG && !CBMC */ +#endif /* !MLD_DEBUG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/fips202.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/fips202.c new file mode 100644 index 0000000000..1112de061c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/fips202.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "../common.h" +#include "../ct.h" +#include "fips202.h" +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +/************************************************* + * Name: keccak_init + * + * Description: Initializes the Keccak state. + * + * Arguments: - uint64_t *s: pointer to Keccak state + **************************************************/ +static void keccak_init(uint64_t s[MLD_KECCAK_LANES]) +__contract__( + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + mld_memset(s, 0, sizeof(uint64_t) * MLD_KECCAK_LANES); +} + +/************************************************* + * Name: keccak_absorb + * + * Description: Absorb step of Keccak; incremental. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_absorb(uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r, + const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(pos <= r) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(in, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + ensures(return_value < r)) +{ + while (inlen >= r - pos) + __loop__( + assigns(pos, in, inlen, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + invariant(inlen <= loop_entry(inlen)) + invariant(pos <= r) + invariant(in == loop_entry(in) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600_xor_bytes(s, in, pos, r - pos); + inlen -= r - pos; + in += r - pos; + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: At this point, inlen < r, so the truncation to unsigned is safe. */ + mld_keccakf1600_xor_bytes(s, in, pos, (unsigned)inlen); + + /* Safety: At this point, inlen < r and pos <= r so the truncation to unsigned + * is safe. */ + return (unsigned)(pos + inlen); +} + +/************************************************* + * Name: keccak_finalize + * + * Description: Finalize absorb step. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - uint8_t p: domain separation byte + **************************************************/ +static void keccak_finalize(uint64_t s[MLD_KECCAK_LANES], unsigned int pos, + unsigned int r, uint8_t p) +__contract__( + requires(pos <= r && r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires((r / 8) >= 1) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + uint8_t b = 0x80; + mld_keccakf1600_xor_bytes(s, &p, pos, 1); + mld_keccakf1600_xor_bytes(s, &b, r - 1, 1); +} + +/************************************************* + * Name: keccak_squeeze + * + * Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes. + * Modifies the state. Can be called multiple times to keep + * squeezing, i.e., is incremental. + * + * Arguments: - uint8_t *out: pointer to output data + * - size_t outlen: number of bytes to be squeezed (written to out) + * - uint64_t *s: pointer to input/output Keccak state + * - unsigned int pos: number of bytes in current block already + *squeezed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_squeeze(uint8_t *out, size_t outlen, + uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r) +__contract__( + requires((r == SHAKE128_RATE && pos <= SHAKE128_RATE) || + (r == SHAKE256_RATE && pos <= SHAKE256_RATE) || + (r == SHA3_512_RATE && pos <= SHA3_512_RATE)) + requires(outlen <= 8 * r /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(out, outlen)) + ensures(return_value <= r)) +{ + unsigned int i; + size_t out_offset = 0; + + /* Reference: This code is re-factored from the reference implementation + * to facilitate proof with CBMC and to improve readability. + * + * Take a mutable copy of outlen to count down the number of bytes + * still to squeeze. The initial value of outlen is needed for the CBMC + * assigns() clauses. */ + size_t bytes_to_go = outlen; + + while (bytes_to_go > 0) + __loop__( + assigns(i, bytes_to_go, pos, out_offset, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES), memory_slice(out, outlen)) + invariant(bytes_to_go <= outlen) + invariant(out_offset == outlen - bytes_to_go) + invariant(pos <= r) + ) + { + if (pos == r) + { + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: If bytes_to_go < r - pos, truncation to unsigned is safe. */ + i = bytes_to_go < r - pos ? (unsigned)bytes_to_go : r - pos; + mld_keccakf1600_extract_bytes(s, out + out_offset, pos, i); + bytes_to_go -= i; + pos += i; + out_offset += i; + } + + return pos; +} + +void mld_shake128_init(mld_shake128ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE128_RATE, in, inlen); +} + +void mld_shake128_finalize(mld_shake128ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE128_RATE, 0x1F); + state->pos = SHAKE128_RATE; +} + +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE128_RATE); +} + +void mld_shake128_release(mld_shake128ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128ctx)); +} + +void mld_shake256_init(mld_shake256ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); +} + +void mld_shake256_finalize(mld_shake256ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); + state->pos = SHAKE256_RATE; +} + +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); +} + +void mld_shake256_release(mld_shake256ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256ctx)); +} + +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +{ + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, in, inlen); + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/fips202.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/fips202.h new file mode 100644 index 0000000000..9f0253cb88 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/fips202.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202_H +#define MLD_FIPS202_FIPS202_H + +#include +#include +#include "../cbmc.h" +#include "../common.h" + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 +#define SHA3_256_RATE 136 +#define SHA3_512_RATE 72 +#define MLD_KECCAK_LANES 25 +#define SHA3_256_HASHBYTES 32 +#define SHA3_512_HASHBYTES 64 + + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake128ctx; + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake256ctx; + +#define mld_shake128_init MLD_NAMESPACE(shake128_init) +/************************************************* + * Name: mld_shake128_init + * + * Description: Initializes state for use as SHAKE128 XOF + * + * Arguments: - mld_shake128ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake128_init(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos == 0) +); + +#define mld_shake128_absorb MLD_NAMESPACE(shake128_absorb) +/************************************************* + * Name: mld_shake128_absorb + * + * Description: Absorb step of the SHAKE128 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake128ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_finalize MLD_NAMESPACE(shake128_finalize) +/************************************************* + * Name: mld_shake128_finalize + * + * Description: Concludes the absorb phase of the SHAKE128 XOF. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_finalize(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_squeeze MLD_NAMESPACE(shake128_squeeze) +/************************************************* + * Name: mld_shake128_squeeze + * + * Description: Squeeze step of SHAKE128 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake128ctx *s: pointer to input/output state + **************************************************/ +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE128_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_release MLD_NAMESPACE(shake128_release) +/************************************************* + * Name: mld_shake128_release + * + * Description: Release and securely zero the SHAKE128 state. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_release(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) +); + +#define mld_shake256_init MLD_NAMESPACE(shake256_init) +/************************************************* + * Name: mld_shake256_init + * + * Description: Initializes state for use as SHAKE256 XOF + * + * Arguments: - mld_shake256ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake256_init(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos == 0) +); + +#define mld_shake256_absorb MLD_NAMESPACE(shake256_absorb) +/************************************************* + * Name: mld_shake256_absorb + * + * Description: Absorb step of the SHAKE256 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake256ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_finalize MLD_NAMESPACE(shake256_finalize) +/************************************************* + * Name: mld_shake256_finalize + * + * Description: Concludes the absorb phase of the SHAKE256 XOF. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_finalize(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_squeeze MLD_NAMESPACE(shake256_squeeze) +/************************************************* + * Name: mld_shake256_squeeze + * + * Description: Squeeze step of SHAKE256 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake256ctx *s: pointer to input/output state + **************************************************/ +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_release MLD_NAMESPACE(shake256_release) +/************************************************* + * Name: mld_shake256_release + * + * Description: Release and securely zero the SHAKE256 state. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_release(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) +); + +#define mld_shake256 MLD_NAMESPACE(shake256) +/************************************************* + * Name: mld_shake256 + * + * Description: SHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +); + +#endif /* !MLD_FIPS202_FIPS202_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/fips202x4.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/fips202x4.c new file mode 100644 index 0000000000..0fb5cd57c7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/fips202x4.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include "../common.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "../ct.h" +#include "fips202.h" +#include "fips202x4.h" +#include "keccakf1600.h" + +static void mld_keccak_absorb_once_x4(uint64_t *s, uint32_t r, + const uint8_t *in0, const uint8_t *in1, + const uint8_t *in2, const uint8_t *in3, + size_t inlen, uint8_t p) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))) +{ + while (inlen >= r) + __loop__( + assigns(inlen, in0, in1, in2, in3, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + invariant(inlen <= loop_entry(inlen)) + invariant(in0 == loop_entry(in0) + (loop_entry(inlen) - inlen)) + invariant(in1 == loop_entry(in1) + (loop_entry(inlen) - inlen)) + invariant(in2 == loop_entry(in2) + (loop_entry(inlen) - inlen)) + invariant(in3 == loop_entry(in3) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, r); + mld_keccakf1600x4_permute(s); + + in0 += r; + in1 += r; + in2 += r; + in3 += r; + inlen -= r; + } + + /* Safety: At this point, inlen < r, so the truncations to unsigned are safe + * below. */ + if (inlen > 0) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, (unsigned)inlen); + } + + if (inlen == r - 1) + { + p |= 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + } + else + { + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + p = 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, r - 1, 1); + } +} + +static void mld_keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1, + uint8_t *out2, uint8_t *out3, + size_t nblocks, uint64_t *s, uint32_t r) +__contract__( + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(out0, nblocks * r)) + requires(memory_no_alias(out1, nblocks * r)) + requires(memory_no_alias(out2, nblocks * r)) + requires(memory_no_alias(out3, nblocks * r)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(out0, nblocks * r)) + assigns(memory_slice(out1, nblocks * r)) + assigns(memory_slice(out2, nblocks * r)) + assigns(memory_slice(out3, nblocks * r))) +{ + while (nblocks > 0) + __loop__( + assigns(out0, out1, out2, out3, nblocks, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY), + memory_slice(out0, nblocks * r), + memory_slice(out1, nblocks * r), + memory_slice(out2, nblocks * r), + memory_slice(out3, nblocks * r)) + invariant(nblocks <= loop_entry(nblocks) && + out0 == loop_entry(out0) + r * (loop_entry(nblocks) - nblocks) && + out1 == loop_entry(out1) + r * (loop_entry(nblocks) - nblocks) && + out2 == loop_entry(out2) + r * (loop_entry(nblocks) - nblocks) && + out3 == loop_entry(out3) + r * (loop_entry(nblocks) - nblocks))) + { + mld_keccakf1600x4_permute(s); + mld_keccakf1600x4_extract_bytes(s, out0, out1, out2, out3, 0, r); + + out0 += r; + out1 += r; + out2 += r; + out3 += r; + nblocks--; + } +} + +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake128x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE128_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE128_RATE); +} + +void mld_shake128x4_init(mld_shake128x4ctx *state) { (void)state; } +void mld_shake128x4_release(mld_shake128x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128x4ctx)); +} + + +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake256x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE256_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE256_RATE); +} + +void mld_shake256x4_init(mld_shake256x4ctx *state) { (void)state; } +void mld_shake256x4_release(mld_shake256x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256x4ctx)); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/fips202x4.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/fips202x4.h new file mode 100644 index 0000000000..e7987207a6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/fips202x4.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202X4_H +#define MLD_FIPS202_FIPS202X4_H + +#include +#include + +#include "../cbmc.h" +#include "../common.h" + +#include "fips202.h" +#include "keccakf1600.h" + +/* Context for non-incremental API */ +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake128x4ctx; + +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake256x4ctx; + +#define mld_shake128x4_absorb_once MLD_NAMESPACE(shake128x4_absorb_once) +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_squeezeblocks MLD_NAMESPACE(shake128x4_squeezeblocks) +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE128_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE128_RATE), + memory_slice(out1, nblocks * SHAKE128_RATE), + memory_slice(out2, nblocks * SHAKE128_RATE), + memory_slice(out3, nblocks * SHAKE128_RATE), + memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_init MLD_NAMESPACE(shake128x4_init) +void mld_shake128x4_init(mld_shake128x4ctx *state); + +#define mld_shake128x4_release MLD_NAMESPACE(shake128x4_release) +void mld_shake128x4_release(mld_shake128x4ctx *state); + + +#define mld_shake256x4_absorb_once MLD_NAMESPACE(shake256x4_absorb_once) +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_squeezeblocks MLD_NAMESPACE(shake256x4_squeezeblocks) +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE256_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE256_RATE), + memory_slice(out1, nblocks * SHAKE256_RATE), + memory_slice(out2, nblocks * SHAKE256_RATE), + memory_slice(out3, nblocks * SHAKE256_RATE), + memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_init MLD_NAMESPACE(shake256x4_init) +void mld_shake256x4_init(mld_shake256x4ctx *state); + +#define mld_shake256x4_release MLD_NAMESPACE(shake256x4_release) +void mld_shake256x4_release(mld_shake256x4ctx *state); + + +#endif /* !MLD_FIPS202_FIPS202X4_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/keccakf1600.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/keccakf1600.c new file mode 100644 index 0000000000..e59120c07c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/keccakf1600.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#define MLD_KECCAK_NROUNDS 24 +#define MLD_KECCAK_ROL(a, offset) ((a << offset) ^ (a >> (64 - offset))) + +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = state_ptr[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = (state[(offset + i) >> 3] >> (8 * ((offset + i) & 0x07))) & 0xFF; + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state_ptr[i] ^= data[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state[(offset + i) >> 3] ^= (uint64_t)data[i] + << (8 * ((offset + i) & 0x07)); + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X4_NATIVE) + if (mld_keccak_f1600_x4_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 0); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 1); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 2); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 3); +} + +static const uint64_t mld_KeccakF_RoundConstants[MLD_KECCAK_NROUNDS] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +static void mld_keccakf1600_permute_c(uint64_t *state) +{ + unsigned round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + uint64_t BCa, BCe, BCi, BCo, BCu; + uint64_t Da, De, Di, Do, Du; + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + /* copyFromState(A, state) */ + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < MLD_KECCAK_NROUNDS; round += 2) + __loop__(invariant(round <= MLD_KECCAK_NROUNDS && round % 2 == 0)) + { + /* prepareTheta */ + BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; + BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + /* thetaRhoPiChiIotaPrepareTheta(round, A, E) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = MLD_KECCAK_ROL(Age, 44); + Aki ^= Di; + BCi = MLD_KECCAK_ROL(Aki, 43); + Amo ^= Do; + BCo = MLD_KECCAK_ROL(Amo, 21); + Asu ^= Du; + BCu = MLD_KECCAK_ROL(Asu, 14); + Eba = BCa ^ ((~BCe) & BCi); + Eba ^= (uint64_t)mld_KeccakF_RoundConstants[round]; + Ebe = BCe ^ ((~BCi) & BCo); + Ebi = BCi ^ ((~BCo) & BCu); + Ebo = BCo ^ ((~BCu) & BCa); + Ebu = BCu ^ ((~BCa) & BCe); + + Abo ^= Do; + BCa = MLD_KECCAK_ROL(Abo, 28); + Agu ^= Du; + BCe = MLD_KECCAK_ROL(Agu, 20); + Aka ^= Da; + BCi = MLD_KECCAK_ROL(Aka, 3); + Ame ^= De; + BCo = MLD_KECCAK_ROL(Ame, 45); + Asi ^= Di; + BCu = MLD_KECCAK_ROL(Asi, 61); + Ega = BCa ^ ((~BCe) & BCi); + Ege = BCe ^ ((~BCi) & BCo); + Egi = BCi ^ ((~BCo) & BCu); + Ego = BCo ^ ((~BCu) & BCa); + Egu = BCu ^ ((~BCa) & BCe); + + Abe ^= De; + BCa = MLD_KECCAK_ROL(Abe, 1); + Agi ^= Di; + BCe = MLD_KECCAK_ROL(Agi, 6); + Ako ^= Do; + BCi = MLD_KECCAK_ROL(Ako, 25); + Amu ^= Du; + BCo = MLD_KECCAK_ROL(Amu, 8); + Asa ^= Da; + BCu = MLD_KECCAK_ROL(Asa, 18); + Eka = BCa ^ ((~BCe) & BCi); + Eke = BCe ^ ((~BCi) & BCo); + Eki = BCi ^ ((~BCo) & BCu); + Eko = BCo ^ ((~BCu) & BCa); + Eku = BCu ^ ((~BCa) & BCe); + + Abu ^= Du; + BCa = MLD_KECCAK_ROL(Abu, 27); + Aga ^= Da; + BCe = MLD_KECCAK_ROL(Aga, 36); + Ake ^= De; + BCi = MLD_KECCAK_ROL(Ake, 10); + Ami ^= Di; + BCo = MLD_KECCAK_ROL(Ami, 15); + Aso ^= Do; + BCu = MLD_KECCAK_ROL(Aso, 56); + Ema = BCa ^ ((~BCe) & BCi); + Eme = BCe ^ ((~BCi) & BCo); + Emi = BCi ^ ((~BCo) & BCu); + Emo = BCo ^ ((~BCu) & BCa); + Emu = BCu ^ ((~BCa) & BCe); + + Abi ^= Di; + BCa = MLD_KECCAK_ROL(Abi, 62); + Ago ^= Do; + BCe = MLD_KECCAK_ROL(Ago, 55); + Aku ^= Du; + BCi = MLD_KECCAK_ROL(Aku, 39); + Ama ^= Da; + BCo = MLD_KECCAK_ROL(Ama, 41); + Ase ^= De; + BCu = MLD_KECCAK_ROL(Ase, 2); + Esa = BCa ^ ((~BCe) & BCi); + Ese = BCe ^ ((~BCi) & BCo); + Esi = BCi ^ ((~BCo) & BCu); + Eso = BCo ^ ((~BCu) & BCa); + Esu = BCu ^ ((~BCa) & BCe); + + /* prepareTheta */ + BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + /* thetaRhoPiChiIotaPrepareTheta(round+1, E, A) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = MLD_KECCAK_ROL(Ege, 44); + Eki ^= Di; + BCi = MLD_KECCAK_ROL(Eki, 43); + Emo ^= Do; + BCo = MLD_KECCAK_ROL(Emo, 21); + Esu ^= Du; + BCu = MLD_KECCAK_ROL(Esu, 14); + Aba = BCa ^ ((~BCe) & BCi); + Aba ^= (uint64_t)mld_KeccakF_RoundConstants[round + 1]; + Abe = BCe ^ ((~BCi) & BCo); + Abi = BCi ^ ((~BCo) & BCu); + Abo = BCo ^ ((~BCu) & BCa); + Abu = BCu ^ ((~BCa) & BCe); + + Ebo ^= Do; + BCa = MLD_KECCAK_ROL(Ebo, 28); + Egu ^= Du; + BCe = MLD_KECCAK_ROL(Egu, 20); + Eka ^= Da; + BCi = MLD_KECCAK_ROL(Eka, 3); + Eme ^= De; + BCo = MLD_KECCAK_ROL(Eme, 45); + Esi ^= Di; + BCu = MLD_KECCAK_ROL(Esi, 61); + Aga = BCa ^ ((~BCe) & BCi); + Age = BCe ^ ((~BCi) & BCo); + Agi = BCi ^ ((~BCo) & BCu); + Ago = BCo ^ ((~BCu) & BCa); + Agu = BCu ^ ((~BCa) & BCe); + + Ebe ^= De; + BCa = MLD_KECCAK_ROL(Ebe, 1); + Egi ^= Di; + BCe = MLD_KECCAK_ROL(Egi, 6); + Eko ^= Do; + BCi = MLD_KECCAK_ROL(Eko, 25); + Emu ^= Du; + BCo = MLD_KECCAK_ROL(Emu, 8); + Esa ^= Da; + BCu = MLD_KECCAK_ROL(Esa, 18); + Aka = BCa ^ ((~BCe) & BCi); + Ake = BCe ^ ((~BCi) & BCo); + Aki = BCi ^ ((~BCo) & BCu); + Ako = BCo ^ ((~BCu) & BCa); + Aku = BCu ^ ((~BCa) & BCe); + + Ebu ^= Du; + BCa = MLD_KECCAK_ROL(Ebu, 27); + Ega ^= Da; + BCe = MLD_KECCAK_ROL(Ega, 36); + Eke ^= De; + BCi = MLD_KECCAK_ROL(Eke, 10); + Emi ^= Di; + BCo = MLD_KECCAK_ROL(Emi, 15); + Eso ^= Do; + BCu = MLD_KECCAK_ROL(Eso, 56); + Ama = BCa ^ ((~BCe) & BCi); + Ame = BCe ^ ((~BCi) & BCo); + Ami = BCi ^ ((~BCo) & BCu); + Amo = BCo ^ ((~BCu) & BCa); + Amu = BCu ^ ((~BCa) & BCe); + + Ebi ^= Di; + BCa = MLD_KECCAK_ROL(Ebi, 62); + Ego ^= Do; + BCe = MLD_KECCAK_ROL(Ego, 55); + Eku ^= Du; + BCi = MLD_KECCAK_ROL(Eku, 39); + Ema ^= Da; + BCo = MLD_KECCAK_ROL(Ema, 41); + Ese ^= De; + BCu = MLD_KECCAK_ROL(Ese, 2); + Asa = BCa ^ ((~BCe) & BCi); + Ase = BCe ^ ((~BCi) & BCo); + Asi = BCi ^ ((~BCo) & BCu); + Aso = BCo ^ ((~BCu) & BCa); + Asu = BCu ^ ((~BCa) & BCe); + } + + /* copyToState(state, A) */ + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} + +void mld_keccakf1600_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X1_NATIVE) + if (mld_keccak_f1600_x1_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X1_NATIVE */ + mld_keccakf1600_permute_c(state); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(keccakf1600) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_KECCAK_NROUNDS +#undef MLD_KECCAK_ROL diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/keccakf1600.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/keccakf1600.h new file mode 100644 index 0000000000..e56adc1561 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/keccakf1600.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_KECCAKF1600_H +#define MLD_FIPS202_KECCAKF1600_H +#include +#include "../cbmc.h" +#include "../common.h" +#include "fips202.h" + +#define MLD_KECCAK_LANES 25 +#define MLD_KECCAK_WAY 4 + +/* + * WARNING: + * The contents of this structure, including the placement + * and interleaving of Keccak lanes, are IMPLEMENTATION-DEFINED. + * The struct is only exposed here to allow its construction on the stack. + */ + +#define mld_keccakf1600_extract_bytes MLD_NAMESPACE(keccakf1600_extract_bytes) +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(data, length)) +); + +#define mld_keccakf1600_xor_bytes MLD_NAMESPACE(keccakf1600_xor_bytes) +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#define mld_keccakf1600x4_extract_bytes \ + MLD_NAMESPACE(keccakf1600x4_extract_bytes) +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + requires(memory_no_alias(data1, length)) + requires(memory_no_alias(data2, length)) + requires(memory_no_alias(data3, length)) + assigns(memory_slice(data0, length)) + assigns(memory_slice(data1, length)) + assigns(memory_slice(data2, length)) + assigns(memory_slice(data3, length)) +); + +#define mld_keccakf1600x4_xor_bytes MLD_NAMESPACE(keccakf1600x4_xor_bytes) +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + /* Case 1: all input buffers are distinct; Case 2: All input buffers are the same */ + requires((data0 == data1 && + data0 == data2 && + data0 == data3) || + (memory_no_alias(data1, length) && + memory_no_alias(data2, length) && + memory_no_alias(data3, length))) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600x4_permute MLD_NAMESPACE(keccakf1600x4_permute) +void mld_keccakf1600x4_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600_permute MLD_NAMESPACE(keccakf1600_permute) +void mld_keccakf1600_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#endif /* !MLD_FIPS202_KECCAKF1600_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/auto.h new file mode 100644 index 0000000000..4375cc1976 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/auto.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [HYBRID] + * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64 + * Becker, Kannwischer + * https://eprint.iacr.org/2022/1243 + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +#define MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* Default FIPS202 assembly profile for AArch64 systems */ + +/* + * Default logic to decide which implementation to use. + * + */ + +/* + * Keccak-f1600 + * + * - On Arm-based Apple CPUs, we pick a pure Neon implementation. + * - Otherwise, unless MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, + * we use lazy-rotation scalar assembly from @[HYBRID]. + * - Otherwise, if MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, we + * fall back to the standard C implementation. + */ +#if defined(__ARM_FEATURE_SHA3) && defined(__APPLE__) +#include "x1_v84a.h" +#elif !defined(MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER) +#include "x1_scalar.h" +#endif + +/* + * Keccak-f1600x2/x4 + * + * The optimal implementation is highly CPU-specific; see @[HYBRID]. + * + * For now, if v8.4-A is not implemented, we fall back to Keccak-f1600. + * If v8.4-A is implemented and we are on an Apple CPU, we use a plain + * Neon-based implementation. + * If v8.4-A is implemented and we are not on an Apple CPU, we use a + * scalar/Neon/Neon hybrid. + * The reason for this distinction is that Apple CPUs appear to implement + * the SHA3 instructions on all SIMD units, while Arm CPUs prior to Cortex-X4 + * don't, and ordinary Neon instructions are still needed. + */ +#if defined(__ARM_FEATURE_SHA3) +/* + * For Apple-M cores, we use a plain implementation leveraging SHA3 + * instructions only. + */ +#if defined(__APPLE__) +#include "x2_v84a.h" +#else +#include "x4_v8a_v84a_scalar.h" +#endif + +#else /* __ARM_FEATURE_SHA3 */ + +#include "x4_v8a_scalar.h" + +#endif /* !__ARM_FEATURE_SHA3 */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h new file mode 100644 index 0000000000..20f6168038 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#define MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H + +#include +#include "../../../../cbmc.h" +#include "../../../../common.h" + + +#define mld_keccakf1600_round_constants \ + MLD_NAMESPACE(keccakf1600_round_constants) +extern const uint64_t mld_keccakf1600_round_constants[]; + +#define mld_keccak_f1600_x1_scalar_asm MLD_NAMESPACE(keccak_f1600_x1_scalar_asm) +void mld_keccak_f1600_x1_scalar_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x1_v84a_asm MLD_NAMESPACE(keccak_f1600_x1_v84a_asm) +void mld_keccak_f1600_x1_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x2_v84a_asm MLD_NAMESPACE(keccak_f1600_x2_v84a_asm) +void mld_keccak_f1600_x2_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 2)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 2)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c new file mode 100644 index 0000000000..05e9cbfeec --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../../common.h" + +#if (defined(MLD_FIPS202_AARCH64_NEED_X1_SCALAR) || \ + defined(MLD_FIPS202_AARCH64_NEED_X1_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X2_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID)) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "fips202_native_aarch64.h" + +MLD_ALIGN const uint64_t mld_keccakf1600_round_constants[] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, +}; + +#else /* (MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_aarch64_round_constants) + +#endif /* !((MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/x1_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/x1_scalar.h new file mode 100644 index 0000000000..681b991371 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/x1_scalar.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_SCALAR + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + mld_keccak_f1600_x1_scalar_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/x1_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/x1_v84a.h new file mode 100644 index 0000000000..d15c8c26f3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/x1_v84a.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x1_v84a_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/x2_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/x2_v84a.h new file mode 100644 index 0000000000..16c22fa1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/x2_v84a.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X2_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" + + +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x2_v84a_asm(state + 0 * 25, mld_keccakf1600_round_constants); + mld_keccak_f1600_x2_v84a_asm(state + 2 * 25, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h new file mode 100644 index 0000000000..0f7f8fe499 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(state, + mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h new file mode 100644 index 0000000000..3da883b762 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm( + state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/api.h new file mode 100644 index 0000000000..4625c9a1ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/api.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_API_H +#define MLD_FIPS202_NATIVE_API_H +/* + * FIPS-202 native interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + */ + +#include +#include "../../cbmc.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* + * This is the C<->native interface allowing for the drop-in + * of custom Keccak-F1600 implementations. + * + * A _backend_ is a specific implementation of parts of this interface. + * + * You can replace 1-fold or 4-fold batched Keccak-F1600. + * To enable, set MLD_USE_FIPS202_X1_NATIVE or MLD_USE_FIPS202_X4_NATIVE + * in your backend, and define the inline wrappers mld_keccak_f1600_x1_native() + * and/or mld_keccak_f1600_x4_native(), respectively, to forward to your + * implementation. + */ + +#if defined(MLD_USE_FIPS202_X1_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 1)) +); +#endif /* MLD_USE_FIPS202_X1_NATIVE */ +#if defined(MLD_USE_FIPS202_X4_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 4)) +); +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + +#endif /* !MLD_FIPS202_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/auto.h new file mode 100644 index 0000000000..0a09c733c8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/auto.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AUTO_H +#define MLD_FIPS202_NATIVE_AUTO_H + +/* + * Default FIPS202 backend + */ +#include "../../sys.h" + +#if defined(MLD_SYS_AARCH64) +#include "aarch64/auto.h" +#endif + +#if defined(MLD_SYS_X86_64) && defined(MLD_SYS_X86_64_AVX2) +#include "x86_64/xkcp.h" +#endif + +#endif /* !MLD_FIPS202_NATIVE_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c new file mode 100644 index 0000000000..4eaad2fd66 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* +Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, +Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby +denoted as "the implementer". + +For more information, feedback or questions, please refer to our websites: +http://keccak.noekeon.org/ +http://keyak.noekeon.org/ +http://ketje.noekeon.org/ + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +/* + * Changes for mlkem-native/mldsa-native: + * - copyFromState and copyToState operate on uninterleaved + * Keccak states in memory. + */ + +#include "../../../../common.h" +#if defined(MLD_FIPS202_X86_64_XKCP) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include + +#include "KeccakP_1600_times4_SIMD256.h" + +#ifndef MLD_SYS_LITTLE_ENDIAN +#error Expecting a little-endian platform +#endif + +#define ANDnu256(a, b) _mm256_andnot_si256(a, b) +#define CONST256(a) _mm256_load_si256((const __m256i *)&(a)) +#define CONST256_64(a) (__m256i) _mm256_broadcast_sd((const double *)(&a)) +#define ROL64in256(d, a, o) \ + d = _mm256_or_si256(_mm256_slli_epi64(a, o), _mm256_srli_epi64(a, 64 - (o))) +#define ROL64in256_8(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho8)) +#define ROL64in256_56(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho56)) +static const uint64_t rho8[4] = {0x0605040302010007, 0x0E0D0C0B0A09080F, + 0x1615141312111017, 0x1E1D1C1B1A19181F}; +static const uint64_t rho56[4] = {0x0007060504030201, 0x080F0E0D0C0B0A09, + 0x1017161514131211, 0x181F1E1D1C1B1A19}; +#define STORE256(a, b) _mm256_store_si256((__m256i *)&(a), b) +#define XOR256(a, b) _mm256_xor_si256(a, b) +#define XOReq256(a, b) a = _mm256_xor_si256(a, b) + +#define SnP_laneLengthInBytes 8 + +#define declareABCDE \ + __m256i Aba, Abe, Abi, Abo, Abu; \ + __m256i Aga, Age, Agi, Ago, Agu; \ + __m256i Aka, Ake, Aki, Ako, Aku; \ + __m256i Ama, Ame, Ami, Amo, Amu; \ + __m256i Asa, Ase, Asi, Aso, Asu; \ + __m256i Bba, Bbe, Bbi, Bbo, Bbu; \ + __m256i Bga, Bge, Bgi, Bgo, Bgu; \ + __m256i Bka, Bke, Bki, Bko, Bku; \ + __m256i Bma, Bme, Bmi, Bmo, Bmu; \ + __m256i Bsa, Bse, Bsi, Bso, Bsu; \ + __m256i Ca, Ce, Ci, Co, Cu; \ + __m256i Ca1, Ce1, Ci1, Co1, Cu1; \ + __m256i Da, De, Di, Do, Du; \ + __m256i Eba, Ebe, Ebi, Ebo, Ebu; \ + __m256i Ega, Ege, Egi, Ego, Egu; \ + __m256i Eka, Eke, Eki, Eko, Eku; \ + __m256i Ema, Eme, Emi, Emo, Emu; \ + __m256i Esa, Ese, Esi, Eso, Esu; + +#define prepareTheta \ + Ca = XOR256(Aba, XOR256(Aga, XOR256(Aka, XOR256(Ama, Asa)))); \ + Ce = XOR256(Abe, XOR256(Age, XOR256(Ake, XOR256(Ame, Ase)))); \ + Ci = XOR256(Abi, XOR256(Agi, XOR256(Aki, XOR256(Ami, Asi)))); \ + Co = XOR256(Abo, XOR256(Ago, XOR256(Ako, XOR256(Amo, Aso)))); \ + Cu = XOR256(Abu, XOR256(Agu, XOR256(Aku, XOR256(Amu, Asu)))); + +/* + * --- Theta Rho Pi Chi Iota Prepare-theta + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + Ca = E##ba; \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + Ce = E##be; \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + Ci = E##bi; \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + Co = E##bo; \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + Cu = E##bu; \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(Ca, E##ga); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(Ce, E##ge); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + XOReq256(Ci, E##gi); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + XOReq256(Co, E##go); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + XOReq256(Cu, E##gu); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(Ca, E##ka); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(Ce, E##ke); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + XOReq256(Ci, E##ki); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + XOReq256(Co, E##ko); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + XOReq256(Cu, E##ku); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(Ca, E##ma); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(Ce, E##me); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + XOReq256(Ci, E##mi); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + XOReq256(Co, E##mo); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + XOReq256(Cu, E##mu); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(Ca, E##sa); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(Ce, E##se); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + XOReq256(Ci, E##si); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + XOReq256(Co, E##so); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); \ + XOReq256(Cu, E##su); + + +/* + * --- Theta Rho Pi Chi Iota + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIota(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); + + +static MLD_ALIGN const uint64_t keccakf1600RoundConstants[24] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +#include + +#define copyFromState(X, state) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m256i _idx = \ + _mm256_set_epi64x((long long)&state64[75], (long long)&state64[50], \ + (long long)&state64[25], (long long)&state64[0]); \ + X##ba = _mm256_i64gather_epi64((long long *)(0 * 8), _idx, 1); \ + X##be = _mm256_i64gather_epi64((long long *)(1 * 8), _idx, 1); \ + X##bi = _mm256_i64gather_epi64((long long *)(2 * 8), _idx, 1); \ + X##bo = _mm256_i64gather_epi64((long long *)(3 * 8), _idx, 1); \ + X##bu = _mm256_i64gather_epi64((long long *)(4 * 8), _idx, 1); \ + X##ga = _mm256_i64gather_epi64((long long *)(5 * 8), _idx, 1); \ + X##ge = _mm256_i64gather_epi64((long long *)(6 * 8), _idx, 1); \ + X##gi = _mm256_i64gather_epi64((long long *)(7 * 8), _idx, 1); \ + X##go = _mm256_i64gather_epi64((long long *)(8 * 8), _idx, 1); \ + X##gu = _mm256_i64gather_epi64((long long *)(9 * 8), _idx, 1); \ + X##ka = _mm256_i64gather_epi64((long long *)(10 * 8), _idx, 1); \ + X##ke = _mm256_i64gather_epi64((long long *)(11 * 8), _idx, 1); \ + X##ki = _mm256_i64gather_epi64((long long *)(12 * 8), _idx, 1); \ + X##ko = _mm256_i64gather_epi64((long long *)(13 * 8), _idx, 1); \ + X##ku = _mm256_i64gather_epi64((long long *)(14 * 8), _idx, 1); \ + X##ma = _mm256_i64gather_epi64((long long *)(15 * 8), _idx, 1); \ + X##me = _mm256_i64gather_epi64((long long *)(16 * 8), _idx, 1); \ + X##mi = _mm256_i64gather_epi64((long long *)(17 * 8), _idx, 1); \ + X##mo = _mm256_i64gather_epi64((long long *)(18 * 8), _idx, 1); \ + X##mu = _mm256_i64gather_epi64((long long *)(19 * 8), _idx, 1); \ + X##sa = _mm256_i64gather_epi64((long long *)(20 * 8), _idx, 1); \ + X##se = _mm256_i64gather_epi64((long long *)(21 * 8), _idx, 1); \ + X##si = _mm256_i64gather_epi64((long long *)(22 * 8), _idx, 1); \ + X##so = _mm256_i64gather_epi64((long long *)(23 * 8), _idx, 1); \ + X##su = _mm256_i64gather_epi64((long long *)(24 * 8), _idx, 1); \ + } while (0); + +#define SCATTER_STORE256(state, idx, v) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m128d t = _mm_castsi128_pd(_mm256_castsi256_si128((v))); \ + _mm_storel_pd((double *)&state64[0 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[25 + (idx)], t); \ + t = _mm_castsi128_pd(_mm256_extracti128_si256((v), 1)); \ + _mm_storel_pd((double *)&state64[50 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[75 + (idx)], t); \ + } while (0) + +#define copyToState(state, X) \ + SCATTER_STORE256(state, 0, X##ba); \ + SCATTER_STORE256(state, 1, X##be); \ + SCATTER_STORE256(state, 2, X##bi); \ + SCATTER_STORE256(state, 3, X##bo); \ + SCATTER_STORE256(state, 4, X##bu); \ + SCATTER_STORE256(state, 5, X##ga); \ + SCATTER_STORE256(state, 6, X##ge); \ + SCATTER_STORE256(state, 7, X##gi); \ + SCATTER_STORE256(state, 8, X##go); \ + SCATTER_STORE256(state, 9, X##gu); \ + SCATTER_STORE256(state, 10, X##ka); \ + SCATTER_STORE256(state, 11, X##ke); \ + SCATTER_STORE256(state, 12, X##ki); \ + SCATTER_STORE256(state, 13, X##ko); \ + SCATTER_STORE256(state, 14, X##ku); \ + SCATTER_STORE256(state, 15, X##ma); \ + SCATTER_STORE256(state, 16, X##me); \ + SCATTER_STORE256(state, 17, X##mi); \ + SCATTER_STORE256(state, 18, X##mo); \ + SCATTER_STORE256(state, 19, X##mu); \ + SCATTER_STORE256(state, 20, X##sa); \ + SCATTER_STORE256(state, 21, X##se); \ + SCATTER_STORE256(state, 22, X##si); \ + SCATTER_STORE256(state, 23, X##so); \ + SCATTER_STORE256(state, 24, X##su); + +#define copyStateVariables(X, Y) \ + X##ba = Y##ba; \ + X##be = Y##be; \ + X##bi = Y##bi; \ + X##bo = Y##bo; \ + X##bu = Y##bu; \ + X##ga = Y##ga; \ + X##ge = Y##ge; \ + X##gi = Y##gi; \ + X##go = Y##go; \ + X##gu = Y##gu; \ + X##ka = Y##ka; \ + X##ke = Y##ke; \ + X##ki = Y##ki; \ + X##ko = Y##ko; \ + X##ku = Y##ku; \ + X##ma = Y##ma; \ + X##me = Y##me; \ + X##mi = Y##mi; \ + X##mo = Y##mo; \ + X##mu = Y##mu; \ + X##sa = Y##sa; \ + X##se = Y##se; \ + X##si = Y##si; \ + X##so = Y##so; \ + X##su = Y##su; + +/* clang-format off */ +#define rounds24 \ + prepareTheta \ + thetaRhoPiChiIotaPrepareTheta( 0, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 1, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 2, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 3, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 4, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 5, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 6, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 7, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 8, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 9, E, A) \ + thetaRhoPiChiIotaPrepareTheta(10, A, E) \ + thetaRhoPiChiIotaPrepareTheta(11, E, A) \ + thetaRhoPiChiIotaPrepareTheta(12, A, E) \ + thetaRhoPiChiIotaPrepareTheta(13, E, A) \ + thetaRhoPiChiIotaPrepareTheta(14, A, E) \ + thetaRhoPiChiIotaPrepareTheta(15, E, A) \ + thetaRhoPiChiIotaPrepareTheta(16, A, E) \ + thetaRhoPiChiIotaPrepareTheta(17, E, A) \ + thetaRhoPiChiIotaPrepareTheta(18, A, E) \ + thetaRhoPiChiIotaPrepareTheta(19, E, A) \ + thetaRhoPiChiIotaPrepareTheta(20, A, E) \ + thetaRhoPiChiIotaPrepareTheta(21, E, A) \ + thetaRhoPiChiIotaPrepareTheta(22, A, E) \ + thetaRhoPiChiIota(23, E, A) +/* clang-format on */ + +void mld_keccakf1600x4_permute24(void *states) +{ + __m256i *statesAsLanes = (__m256i *)states; + declareABCDE copyFromState(A, statesAsLanes) + rounds24 copyToState(statesAsLanes, A) +} + +#else /* MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_avx2_keccakx4) + +#endif /* !(MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef ANDnu256 +#undef CONST256 +#undef CONST256_64 +#undef ROL64in256 +#undef ROL64in256_8 +#undef ROL64in256_56 +#undef STORE256 +#undef XOR256 +#undef XOReq256 +#undef SnP_laneLengthInBytes +#undef declareABCDE +#undef prepareTheta +#undef thetaRhoPiChiIotaPrepareTheta +#undef thetaRhoPiChiIota +#undef copyFromState +#undef SCATTER_STORE256 +#undef copyToState +#undef copyStateVariables +#undef rounds24 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h new file mode 100644 index 0000000000..3499d38e2c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H +#define MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H + +#include "../../../../common.h" + +#define mld_keccakf1600x4_permute24 \ + MLD_NAMESPACE(KeccakP1600times4_PermuteAll_24rounds) +void mld_keccakf1600x4_permute24(void *states); + +#endif /* !MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/x86_64/xkcp.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/x86_64/xkcp.h new file mode 100644 index 0000000000..c03642d7e0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/fips202/native/x86_64/xkcp.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_XKCP_H +#define MLD_FIPS202_NATIVE_X86_64_XKCP_H + +#include "../../../common.h" + +#define MLD_FIPS202_X86_64_XKCP + +#if !defined(__ASSEMBLER__) +#include +#include "../api.h" +#include "src/KeccakP_1600_times4_SIMD256.h" + +#define MLD_USE_FIPS202_X4_NATIVE +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_keccakf1600x4_permute24(state); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_X86_64_XKCP_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/meta.h new file mode 100644 index 0000000000..c6f6ad47b0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/meta.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_META_H +#define MLD_NATIVE_AARCH64_META_H + +/* Set of primitives that this backend replaces */ +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_AARCH64 + + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/arith_native_aarch64.h" + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + mld_ntt_asm(data, mld_aarch64_ntt_zetas_layer123456, + mld_aarch64_ntt_zetas_layer78); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + mld_intt_asm(data, mld_aarch64_intt_zetas_layer78, + mld_aarch64_intt_zetas_layer123456); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + if (len != MLDSA_N || + buflen % 24 != 0) /* NEON support is mandatory for AArch64 */ + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N, hence, this cast is safe. */ + return (int)mld_rej_uniform_asm(r, buf, buflen, mld_rej_uniform_table); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_32_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_88_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + mld_poly_caddq_asm(a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_32_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_88_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + return mld_poly_chknorm_asm(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_17_asm(r, buf, mld_polyz_unpack_17_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_19_asm(r, buf, mld_polyz_unpack_19_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t out[MLDSA_N], const int32_t in0[MLDSA_N], + const int32_t in1[MLDSA_N]) +{ + mld_poly_pointwise_montgomery_asm(out, in0, in1); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l4_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l5_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l7_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ +#endif /* !MLD_NATIVE_AARCH64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/src/aarch64_zetas.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/src/aarch64_zetas.c new file mode 100644 index 0000000000..9ab7b9a68c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/src/aarch64_zetas.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Table of zeta values used in the AArch64 forward NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer123456[] = { + -3572223, -915382907, 3765607, 964937599, 3761513, 963888510, + -3201494, -820383522, -2883726, -738955404, -3145678, -806080660, + -3201430, -820367122, 0, 0, -601683, -154181397, + -3370349, -863652652, -4063053, -1041158200, 3602218, 923069133, + 3182878, 815613168, 2740543, 702264730, -3586446, -919027554, + 0, 0, 3542485, 907762539, 2663378, 682491182, + -1674615, -429120452, -3110818, -797147778, 2101410, 538486762, + 3704823, 949361686, 1159875, 297218217, 0, 0, + 2682288, 687336873, -3524442, -903139016, -434125, -111244624, + 394148, 101000509, 928749, 237992130, 1095468, 280713909, + -3506380, -898510625, 0, 0, 2129892, 545785280, + 676590, 173376332, -1335936, -342333886, 2071829, 530906624, + -4018989, -1029866791, 3241972, 830756018, 2156050, 552488273, + 0, 0, 3764867, 964747974, -3227876, -827143915, + 1714295, 439288460, 3415069, 875112161, 1759347, 450833045, + -817536, -209493775, -3574466, -915957677, 0, 0, + -1005239, -257592709, 2453983, 628833668, 1460718, 374309300, + 3756790, 962678241, -1935799, -496048908, -1716988, -439978542, + -3950053, -1012201926, 0, 0, 557458, 142848732, + -642628, -164673562, -3585098, -918682129, -2897314, -742437332, + 3192354, 818041395, 556856, 142694469, 3870317, 991769559, + 0, 0, -1221177, -312926867, 2815639, 721508096, + 2283733, 585207070, 2917338, 747568486, 1853806, 475038184, + 3345963, 857403734, 1858416, 476219497, 0, 0, +}; + +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer78[] = { + 3073009, 1277625, -2635473, 3852015, 787459213, + 327391679, -675340520, 987079667, 1753, -2659525, + 2660408, -59148, 449207, -681503850, 681730119, + -15156688, -1935420, -1455890, -1780227, 2772600, + -495951789, -373072124, -456183549, 710479343, 4183372, + -3222807, -3121440, -274060, 1071989969, -825844983, + -799869667, -70227934, 1182243, 636927, -3956745, + -3284915, 302950022, 163212680, -1013916752, -841760171, + 87208, -3965306, -2296397, -3716946, 22347069, + -1016110510, -588452222, -952468207, 2508980, 2028118, + 1937570, -3815725, 642926661, 519705671, 496502727, + -977780347, -27812, 1009365, -1979497, -3956944, + -7126831, 258649997, -507246529, -1013967746, 822541, + -2454145, 1596822, -3759465, 210776307, -628875181, + 409185979, -963363710, 2811291, -2983781, -1109516, + 4158088, 720393920, -764594519, -284313712, 1065510939, + -1685153, 2678278, -3551006, -250446, -431820817, + 686309310, -909946047, -64176841, -3410568, -3768948, + 635956, -2455377, -873958779, -965793731, 162963861, + -629190881, 1528066, 482649, 1148858, -2962264, + 391567239, 123678909, 294395108, -759080783, -4146264, + 2192938, 2387513, -268456, -1062481036, 561940831, + 611800717, -68791907, -1772588, -1727088, -3611750, + -3180456, -454226054, -442566669, -925511710, -814992530, + -565603, 169688, 2462444, -3334383, -144935890, + 43482586, 631001801, -854436357, 3747250, 1239911, + 3195676, 1254190, 960233614, 317727459, 818892658, + 321386456, 2296099, -3838479, 2642980, -12417, + 588375860, -983611064, 677264190, -3181859, -4166425, + -3488383, 1987814, -3197248, -1067647297, -893898890, + 509377762, -819295484, 2998219, -89301, -1354892, + -1310261, 768294260, -22883400, -347191365, -335754661, + 141835, 2513018, 613238, -2218467, 36345249, + 643961400, 157142369, -568482643, 1736313, 235407, + -3250154, 3258457, 444930577, 60323094, -832852657, + 834980303, -458740, 4040196, 2039144, -818761, + -117552223, 1035301089, 522531086, -209807681, -1921994, + -3472069, -1879878, -2178965, -492511373, -889718424, + -481719139, -558360247, -2579253, 1787943, -2391089, + -2254727, -660934133, 458160776, -612717067, -577774276, + -1623354, -2374402, 586241, 527981, -415984810, + -608441020, 150224382, 135295244, 2105286, -2033807, + -1179613, -2743411, 539479988, -521163479, -302276083, + -702999655, 3482206, -4182915, -1300016, -2362063, + 892316032, -1071872863, -333129378, -605279149, -1476985, + 2491325, 507927, -724804, -378477722, 638402564, + 130156402, -185731180, 1994046, -1393159, -1187885, + -1834526, 510974714, -356997292, -304395785, -470097680, + -1317678, 2461387, 3035980, 621164, -337655269, + 630730945, 777970524, 159173408, -3033742, 2647994, + -2612853, 749577, -777397036, 678549029, -669544140, + 192079267, -338420, 3009748, 4148469, -4022750, + -86720197, 771248568, 1063046068, -1030830548, 3901472, + -1226661, 2925816, 3374250, 999753034, -314332144, + 749740976, 864652284, 3980599, -1615530, 1665318, + 1163598, 1020029345, -413979908, 426738094, 298172236, + 2569011, 1723229, 2028038, -3369273, 658309618, + 441577800, 519685171, -863376927, 1356448, -2775755, + 2683270, -2778788, 347590090, -711287812, 687588511, + -712065019, 3994671, -1370517, 3363542, 545376, + 1023635298, -351195274, 861908357, 139752717, -11879, + 3020393, 214880, -770441, -3043996, 773976352, + 55063046, -197425671, -3467665, 2312838, -653275, + -459163, -888589898, 592665232, -167401858, -117660617, + 3105558, 508145, 860144, 140244, 795799901, + 130212265, 220412084, 35937555, -1103344, -553718, + 3430436, -1514152, -282732136, -141890356, 879049958, + -388001774, 348812, -327848, 1011223, -2354215, + 89383150, -84011120, 259126110, -603268097, -2185084, + 2358373, -3014420, 2926054, -559928242, 604333585, + -772445769, 749801963, 3123762, -2193087, -1716814, + -392707, 800464680, -561979013, -439933955, -100631253, + -3818627, -1922253, -2236726, 1744507, -978523985, + -492577742, -573161516, 447030292, -303005, -3974485, + 1900052, 1054478, -77645096, -1018462631, 486888731, + 270210213, 3531229, -3773731, -781875, -731434, + 904878186, -967019376, -200355636, -187430119, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer78[] = { + -1744507, 2236726, 1922253, 3818627, -447030292, 573161516, + 492577742, 978523985, 731434, 781875, 3773731, -3531229, + 187430119, 200355636, 967019376, -904878186, -1054478, -1900052, + 3974485, 303005, -270210213, -486888731, 1018462631, 77645096, + 2354215, -1011223, 327848, -348812, 603268097, -259126110, + 84011120, -89383150, 392707, 1716814, 2193087, -3123762, + 100631253, 439933955, 561979013, -800464680, -2926054, 3014420, + -2358373, 2185084, -749801963, 772445769, -604333585, 559928242, + 459163, 653275, -2312838, 3467665, 117660617, 167401858, + -592665232, 888589898, 1514152, -3430436, 553718, 1103344, + 388001774, -879049958, 141890356, 282732136, -140244, -860144, + -508145, -3105558, -35937555, -220412084, -130212265, -795799901, + 2778788, -2683270, 2775755, -1356448, 712065019, -687588511, + 711287812, -347590090, 770441, -214880, -3020393, 11879, + 197425671, -55063046, -773976352, 3043996, -545376, -3363542, + 1370517, -3994671, -139752717, -861908357, 351195274, -1023635298, + -3374250, -2925816, 1226661, -3901472, -864652284, -749740976, + 314332144, -999753034, 3369273, -2028038, -1723229, -2569011, + 863376927, -519685171, -441577800, -658309618, -1163598, -1665318, + 1615530, -3980599, -298172236, -426738094, 413979908, -1020029345, + -621164, -3035980, -2461387, 1317678, -159173408, -777970524, + -630730945, 337655269, 4022750, -4148469, -3009748, 338420, + 1030830548, -1063046068, -771248568, 86720197, -749577, 2612853, + -2647994, 3033742, -192079267, 669544140, -678549029, 777397036, + 2362063, 1300016, 4182915, -3482206, 605279149, 333129378, + 1071872863, -892316032, 1834526, 1187885, 1393159, -1994046, + 470097680, 304395785, 356997292, -510974714, 724804, -507927, + -2491325, 1476985, 185731180, -130156402, -638402564, 378477722, + 2254727, 2391089, -1787943, 2579253, 577774276, 612717067, + -458160776, 660934133, 2743411, 1179613, 2033807, -2105286, + 702999655, 302276083, 521163479, -539479988, -527981, -586241, + 2374402, 1623354, -135295244, -150224382, 608441020, 415984810, + -3258457, 3250154, -235407, -1736313, -834980303, 832852657, + -60323094, -444930577, 2178965, 1879878, 3472069, 1921994, + 558360247, 481719139, 889718424, 492511373, 818761, -2039144, + -4040196, 458740, 209807681, -522531086, -1035301089, 117552223, + 3197248, -1987814, 3488383, 4166425, 819295484, -509377762, + 893898890, 1067647297, 2218467, -613238, -2513018, -141835, + 568482643, -157142369, -643961400, -36345249, 1310261, 1354892, + 89301, -2998219, 335754661, 347191365, 22883400, -768294260, + 3334383, -2462444, -169688, 565603, 854436357, -631001801, + -43482586, 144935890, 12417, -2642980, 3838479, -2296099, + 3181859, -677264190, 983611064, -588375860, -1254190, -3195676, + -1239911, -3747250, -321386456, -818892658, -317727459, -960233614, + 2962264, -1148858, -482649, -1528066, 759080783, -294395108, + -123678909, -391567239, 3180456, 3611750, 1727088, 1772588, + 814992530, 925511710, 442566669, 454226054, 268456, -2387513, + -2192938, 4146264, 68791907, -611800717, -561940831, 1062481036, + -4158088, 1109516, 2983781, -2811291, -1065510939, 284313712, + 764594519, -720393920, 2455377, -635956, 3768948, 3410568, + 629190881, -162963861, 965793731, 873958779, 250446, 3551006, + -2678278, 1685153, 64176841, 909946047, -686309310, 431820817, + 3815725, -1937570, -2028118, -2508980, 977780347, -496502727, + -519705671, -642926661, 3759465, -1596822, 2454145, -822541, + 963363710, -409185979, 628875181, -210776307, 3956944, 1979497, + -1009365, 27812, 1013967746, 507246529, -258649997, 7126831, + 274060, 3121440, 3222807, -4183372, 70227934, 799869667, + 825844983, -1071989969, 3716946, 2296397, 3965306, -87208, + 952468207, 588452222, 1016110510, -22347069, 3284915, 3956745, + -636927, -1182243, 841760171, 1013916752, -163212680, -302950022, + -3852015, 2635473, -1277625, -3073009, -987079667, 675340520, + -327391679, -787459213, -2772600, 1780227, 1455890, 1935420, + -710479343, 456183549, 373072124, 495951789, 59148, -2660408, + 2659525, -1753, 15156688, -681730119, 681503850, -449207, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer123456[] = { + -2283733, -585207070, 0, 0, -1858416, -476219497, + -3345963, -857403734, -2815639, -721508096, 0, 0, + -1853806, -475038184, -2917338, -747568486, 3585098, 918682129, + 0, 0, -3870317, -991769559, -556856, -142694469, + 642628, 164673562, 0, 0, -3192354, -818041395, + 2897314, 742437332, -1460718, -374309300, 0, 0, + 3950053, 1012201926, 1716988, 439978542, -2453983, -628833668, + 0, 0, 1935799, 496048908, -3756790, -962678241, + -1714295, -439288460, 0, 0, 3574466, 915957677, + 817536, 209493775, 3227876, 827143915, 0, 0, + -1759347, -450833045, -3415069, -875112161, 1335936, 342333886, + 0, 0, -2156050, -552488273, -3241972, -830756018, + -676590, -173376332, 0, 0, 4018989, 1029866791, + -2071829, -530906624, 434125, 111244624, 0, 0, + 3506380, 898510625, -1095468, -280713909, 3524442, 903139016, + 0, 0, -928749, -237992130, -394148, -101000509, + 1674615, 429120452, 0, 0, -1159875, -297218217, + -3704823, -949361686, -2663378, -682491182, 0, 0, + -2101410, -538486762, 3110818, 797147778, 4063053, 1041158200, + 0, 0, 3586446, 919027554, -2740543, -702264730, + 3370349, 863652652, 0, 0, -3182878, -815613168, + -3602218, -923069133, -294725, -75523344, -3761513, -963888510, + -3765607, -964937599, 3201430, 820367122, 3145678, 806080660, + 2883726, 738955404, 3201494, 820383522, 1221177, 312926867, + -557458, -142848732, 1005239, 257592709, -3764867, -964747974, + -2129892, -545785280, -2682288, -687336873, -3542485, -907762539, + 601683, 154181397, 0, 0, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_zetas) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h new file mode 100644 index 0000000000..e77f55014c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#define MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H + +#include +#include "../../../common.h" + +#define mld_aarch64_ntt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_ntt_zetas_layer123456) +#define mld_aarch64_ntt_zetas_layer78 MLD_NAMESPACE(aarch64_ntt_zetas_layer78) + +#define mld_aarch64_intt_zetas_layer78 MLD_NAMESPACE(aarch64_intt_zetas_layer78) +#define mld_aarch64_intt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_intt_zetas_layer123456) + +extern const int32_t mld_aarch64_ntt_zetas_layer123456[]; +extern const int32_t mld_aarch64_ntt_zetas_layer78[]; + +extern const int32_t mld_aarch64_intt_zetas_layer78[]; +extern const int32_t mld_aarch64_intt_zetas_layer123456[]; + +#define mld_rej_uniform_table MLD_NAMESPACE(rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[]; +#define mld_rej_uniform_eta_table MLD_NAMESPACE(rej_uniform_eta_table) +extern const uint8_t mld_rej_uniform_eta_table[]; + +#define mld_polyz_unpack_17_indices MLD_NAMESPACE(polyz_unpack_17_indices) +extern const uint8_t mld_polyz_unpack_17_indices[]; +#define mld_polyz_unpack_19_indices MLD_NAMESPACE(polyz_unpack_19_indices) +extern const uint8_t mld_polyz_unpack_19_indices[]; + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_ntt_asm MLD_NAMESPACE(ntt_asm) +void mld_ntt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_intt_asm MLD_NAMESPACE(intt_asm) +void mld_intt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_rej_uniform_asm MLD_NAMESPACE(rej_uniform_asm) +uint64_t mld_rej_uniform_asm(int32_t *r, const uint8_t *buf, unsigned buflen, + const uint8_t *table); + +#define mld_rej_uniform_eta2_asm MLD_NAMESPACE(rej_uniform_eta2_asm) +uint64_t mld_rej_uniform_eta2_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_rej_uniform_eta4_asm MLD_NAMESPACE(rej_uniform_eta4_asm) +uint64_t mld_rej_uniform_eta4_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_poly_decompose_32_asm MLD_NAMESPACE(poly_decompose_32_asm) +void mld_poly_decompose_32_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_asm MLD_NAMESPACE(poly_decompose_88_asm) +void mld_poly_decompose_88_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_asm MLD_NAMESPACE(poly_caddq_asm) +void mld_poly_caddq_asm(int32_t *a); + +#define mld_poly_use_hint_32_asm MLD_NAMESPACE(poly_use_hint_32_asm) +void mld_poly_use_hint_32_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_asm MLD_NAMESPACE(poly_use_hint_88_asm) +void mld_poly_use_hint_88_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_asm MLD_NAMESPACE(poly_chknorm_asm) +int mld_poly_chknorm_asm(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_asm MLD_NAMESPACE(polyz_unpack_17_asm) +void mld_polyz_unpack_17_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_polyz_unpack_19_asm MLD_NAMESPACE(polyz_unpack_19_asm) +void mld_polyz_unpack_19_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_poly_pointwise_montgomery_asm \ + MLD_NAMESPACE(poly_pointwise_montgomery_asm) +void mld_poly_pointwise_montgomery_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l4_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l4_asm) +void mld_polyvecl_pointwise_acc_montgomery_l4_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l5_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l5_asm) +void mld_polyvecl_pointwise_acc_montgomery_l5_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l7_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l7_asm) +void mld_polyvecl_pointwise_acc_montgomery_l7_asm(int32_t *, const int32_t *, + const int32_t *); + +#endif /* !MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c new file mode 100644 index 0000000000..7ef915b587 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* Table of indices used for tbl instructions in polyz_unpack_{17,19}. */ + +MLD_ALIGN const uint8_t mld_polyz_unpack_17_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, + 9, 10, 11, 255, 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, + 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, 8, 9, 10, 255, + 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, 17, 18, 19, 255, +}; + +MLD_ALIGN const uint8_t mld_polyz_unpack_19_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 5, 6, 7, 255, 7, 8, 9, 255, + 10, 11, 12, 255, 12, 13, 14, 255, 15, 16, 17, 255, 17, 18, 19, 255, + 4, 5, 6, 255, 6, 7, 8, 255, 9, 10, 11, 255, 11, 12, 13, 255, + 14, 15, 16, 255, 16, 17, 18, 255, 19, 20, 21, 255, 21, 22, 23, 255, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_polyz_unpack_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c new file mode 100644 index 0000000000..cf21509cbf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by 16-bit rejection sampling (rej_eta). + * Adapted from ML-KEM for ML-DSA eta rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_eta_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 2, 3, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 4, 5, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 2, 3, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 7 */, + 6, 7, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 2, 3, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 11 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 13 */, + 2, 3, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 15 */, + 8, 9, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 16 */, + 0, 1, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 17 */, + 2, 3, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 18 */, + 0, 1, 2, 3, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 19 */, + 4, 5, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 20 */, + 0, 1, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 21 */, + 2, 3, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 22 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 23 */, + 6, 7, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 24 */, + 0, 1, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 25 */, + 2, 3, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 26 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 27 */, + 4, 5, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 28 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 29 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 30 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 255, 255, 255, 255, 255, 255 /* 31 */, + 10, 11, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 32 */, + 0, 1, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 33 */, + 2, 3, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 34 */, + 0, 1, 2, 3, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 35 */, + 4, 5, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 36 */, + 0, 1, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 37 */, + 2, 3, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 38 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 39 */, + 6, 7, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 40 */, + 0, 1, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 41 */, + 2, 3, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 42 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 43 */, + 4, 5, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 44 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 45 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 46 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 255, 255, 255, 255, 255, 255 /* 47 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 48 */, + 0, 1, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 49 */, + 2, 3, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 50 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 51 */, + 4, 5, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 52 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 53 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 54 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 55 */, + 6, 7, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 56 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 57 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 58 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 59 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 60 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 61 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 62 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 63 */, + 12, 13, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 64 */, + 0, 1, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 65 */, + 2, 3, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 66 */, + 0, 1, 2, 3, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 67 */, + 4, 5, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 68 */, + 0, 1, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 69 */, + 2, 3, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 70 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 71 */, + 6, 7, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 72 */, + 0, 1, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 73 */, + 2, 3, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 74 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 75 */, + 4, 5, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 76 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 77 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 78 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 255, 255, 255, 255, 255, 255 /* 79 */, + 8, 9, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 80 */, + 0, 1, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 81 */, + 2, 3, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 82 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 83 */, + 4, 5, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 84 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 85 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 86 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 87 */, + 6, 7, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 88 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 89 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 90 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 91 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 92 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 93 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 94 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 255, 255, 255, 255 /* 95 */, + 10, 11, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 96 */, + 0, 1, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 97 */, + 2, 3, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 98 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 99 */, + 4, 5, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 100 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 101 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 102 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 103 */, + 6, 7, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 104 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 105 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 106 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 107 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 108 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 109 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 110 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 255, 255, 255, 255 /* 111 */, + 8, 9, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 112 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 113 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 114 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 115 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 116 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 117 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 118 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 119 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 120 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 121 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 122 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 123 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 124 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 125 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 126 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 255, 255 /* 127 */, + 14, 15, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 128 */, + 0, 1, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 129 */, + 2, 3, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 130 */, + 0, 1, 2, 3, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 131 */, + 4, 5, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 132 */, + 0, 1, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 133 */, + 2, 3, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 134 */, + 0, 1, 2, 3, 4, 5, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 135 */, + 6, 7, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 136 */, + 0, 1, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 137 */, + 2, 3, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 138 */, + 0, 1, 2, 3, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 139 */, + 4, 5, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 140 */, + 0, 1, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 141 */, + 2, 3, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 142 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 14, 15, 255, 255, 255, 255, 255, 255 /* 143 */, + 8, 9, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 144 */, + 0, 1, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 145 */, + 2, 3, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 146 */, + 0, 1, 2, 3, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 147 */, + 4, 5, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 148 */, + 0, 1, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 149 */, + 2, 3, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 150 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 151 */, + 6, 7, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 152 */, + 0, 1, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 153 */, + 2, 3, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 154 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 155 */, + 4, 5, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 156 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 157 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 158 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 14, 15, 255, 255, 255, 255 /* 159 */, + 10, 11, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 160 */, + 0, 1, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 161 */, + 2, 3, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 162 */, + 0, 1, 2, 3, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 163 */, + 4, 5, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 164 */, + 0, 1, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 165 */, + 2, 3, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 166 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 167 */, + 6, 7, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 168 */, + 0, 1, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 169 */, + 2, 3, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 170 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 171 */, + 4, 5, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 172 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 173 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 174 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 14, 15, 255, 255, 255, 255 /* 175 */, + 8, 9, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 176 */, + 0, 1, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 177 */, + 2, 3, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 178 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 179 */, + 4, 5, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 180 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 181 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 182 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 183 */, + 6, 7, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 184 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 185 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 186 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 187 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 188 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 189 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 190 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 14, 15, 255, 255 /* 191 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 192 */, + 0, 1, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 193 */, + 2, 3, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 194 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 195 */, + 4, 5, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 196 */, + 0, 1, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 197 */, + 2, 3, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 198 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 199 */, + 6, 7, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 200 */, + 0, 1, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 201 */, + 2, 3, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 202 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 203 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 204 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 205 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 206 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 207 */, + 8, 9, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 208 */, + 0, 1, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 209 */, + 2, 3, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 210 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 211 */, + 4, 5, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 212 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 213 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 214 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 215 */, + 6, 7, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 216 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 217 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 218 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 219 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 220 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 221 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 222 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 14, 15, 255, 255 /* 223 */, + 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 224 */, + 0, 1, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 225 */, + 2, 3, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 226 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 227 */, + 4, 5, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 228 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 229 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 230 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 231 */, + 6, 7, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 232 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 233 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 234 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 235 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 236 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 237 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 238 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 14, 15, 255, 255 /* 239 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 240 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 241 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 242 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 243 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 244 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 245 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 246 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 247 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 248 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 249 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 250 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 251 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 252 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 253 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 254 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 255 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_eta_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/src/rej_uniform_table.c new file mode 100644 index 0000000000..65bc3b78d3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/aarch64/src/rej_uniform_table.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by rejection sampling of the public matrix. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 7 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 11 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 13 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 15 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/api.h new file mode 100644 index 0000000000..0f1fdeb168 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/api.h @@ -0,0 +1,594 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_API_H +#define MLD_NATIVE_API_H +/* + * Native arithmetic interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + * + * To ensure consistency with backends, the header will be + * included automatically after inclusion of the active + * backend, to ensure consistency of function signatures, + * and run sanity checks. + */ + +#include +#include "../cbmc.h" +#include "../common.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* Bound on absolute value of coefficients after NTT. + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) + +/* Absolute exclusive upper bound for the output of the inverse NTT + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_INTT_BOUND MLDSA_Q + +/* Absolute bound for range of mld_reduce32() + * + * NOTE: This is the same bound as in reduce.h and has to be kept + * in sync. */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define REDUCE32_RANGE_MAX 6283009 +/* + * This is the C<->native interface allowing for the drop-in of + * native code for performance critical arithmetic components of ML-DSA. + * + * A _backend_ is a specific implementation of (part of) this interface. + * + * To add a function to a backend, define MLD_USE_NATIVE_XXX and + * implement `static inline xxx(...)` in the profile header. + */ + +/* + * Those functions are meant to be trivial wrappers around the chosen native + * implementation. The are static inline to avoid unnecessary calls. + * The macro before each declaration controls whether a native + * implementation is present. + */ + +#if defined(MLD_USE_NATIVE_NTT) +/************************************************* + * Name: mld_ntt_native + * + * Description: Computes negacyclic number-theoretic transform (NTT) of + * a polynomial in place. + * + * The input polynomial is assumed to be in normal order. + * The output polynomial is in bitreversed order. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_ntt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_NTT */ + + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) +/* + * This must only be set if NTT and INTT have native implementations + * that are adapted to the custom order. + */ +#if !defined(MLD_USE_NATIVE_NTT) || !defined(MLD_USE_NATIVE_INTT) +#error \ + "Invalid native profile: MLD_USE_NATIVE_NTT_CUSTOM_ORDER can only be \ +set if there are native implementations for NTT and INTT." +#endif + +/************************************************* + * Name: mlD_poly_permute_bitrev_to_custom + * + * Description: When MLD_USE_NATIVE_NTT_CUSTOM_ORDER is defined, + * convert a polynomial in NTT domain from bitreversed + * order to the custom order output by the native NTT. + * + * This must only be defined if there is native code for + * both the NTT and INTT. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + * + **************************************************/ +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t p[MLDSA_N]) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q))); +#endif /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + + +#if defined(MLD_USE_NATIVE_INTT) +/************************************************* + * Name: mld_intt_native + * + * Description: Computes inverse of negacyclic number-theoretic transform + *(NTT) of a polynomial in place. + * + * The input polynomial is in bitreversed order. + * The output polynomial is assumed to be in normal order. + * + * Arguments: - uint32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_intt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_INTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_INTT */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) +/************************************************* + * Name: mld_rej_uniform_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [0, MLDSA_Q-1] + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform mod q). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + * lengths. Otherwise, returns non-negative number of sampled 32-bit integers + * (at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= ( 5 * 168) && buflen % 3 == 0) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(r, 0, (unsigned) return_value, 0, MLDSA_Q)) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) +/************************************************* + * Name: mld_rej_uniform_eta2_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-2,+2]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-2, +2]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA2 */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) +/************************************************* + * Name: mld_rej_uniform_eta4_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-4,+4]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-4, +4]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) +/************************************************* + * Name: mld_poly_decompose_32_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/32. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: input/output polynomial. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_32 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) +/************************************************* + * Name: mld_poly_decompose_88_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/88. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: output polynomial with coefficients c0. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CADDQ) +/************************************************* + * Name: mld_poly_caddq_native + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *a: pointer to input/output polynomial + **************************************************/ +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_32) +/************************************************* + * Name: mld_poly_use_hint_32_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/32. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_32 */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) +/************************************************* + * Name: mld_poly_use_hint_88_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/88. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) +/************************************************* + * Name: mld_poly_chknorm_native + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const int32_t *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if the infinity norm is strictly smaller than B, and 1 + * otherwise. B must not be larger than MLDSA_Q - MLD_REDUCE32_RANGE_MAX. + **************************************************/ +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(0 <= B && B <= MLDSA_Q - REDUCE32_RANGE_MAX) + requires(array_bound(a, 0, MLDSA_N, -REDUCE32_RANGE_MAX, REDUCE32_RANGE_MAX)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == 0) == array_abs_bound(a, 0, MLDSA_N, B)) +); +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) +/************************************************* + * Name: mld_polyz_unpack_17_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^17. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_17 */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) +/************************************************* + * Name: mld_polyz_unpack_19_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^19. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_19 */ + +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) +/************************************************* + * Name: mld_poly_pointwise_montgomery_native + * + * Description: Pointwise multiplication of polynomials in NTT domain + * with Montgomery reduction. + * + * Computes c[i] = a[i] * b[i] * R^(-1) mod q for all i, + * where R = 2^32. + * + * Arguments: - int32_t c[MLDSA_N]: output polynomial + * - const int32_t a[MLDSA_N]: first input polynomial + * - const int32_t b[MLDSA_N]: second input polynomial + **************************************************/ +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(c, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(c, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(c, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l4_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 4. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 4 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 4 * MLDSA_N)) + requires(forall(l0, 0, 4, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 4, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l5_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 5. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 5 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 5 * MLDSA_N)) + requires(forall(l0, 0, 5, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 5, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l7_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 7. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 7 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 7 * MLDSA_N)) + requires(forall(l0, 0, 7, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 7, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 */ + +#endif /* !MLD_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/meta.h new file mode 100644 index 0000000000..0b46dd5791 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/meta.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_META_H +#define MLD_NATIVE_META_H + +/* + * Default arithmetic backend + */ +#include "../sys.h" + +#ifdef MLD_SYS_AARCH64 +#include "aarch64/meta.h" +#endif + +#ifdef MLD_SYS_X86_64_AVX2 +#include "x86_64/meta.h" +#endif + +#endif /* !MLD_NATIVE_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/meta.h new file mode 100644 index 0000000000..393374c06f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/meta.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_X86_64_META_H +#define MLD_NATIVE_X86_64_META_H + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_X86_64_DEFAULT + +#define MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +#if !defined(__ASSEMBLER__) +#include +#include "../../common.h" +#include "../api.h" +#include "src/arith_native_x86_64.h" + +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t data[MLDSA_N]) +{ + if (mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + mld_nttunpack_avx2(data); + } +} + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_ntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_invntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)mld_rej_uniform_avx2(r, buf); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_32_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_88_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_caddq_avx2(a); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_32_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_88_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + return mld_poly_chknorm_avx2(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_17_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_19_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_avx2(c, a, b, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l4_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l5_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l7_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_NATIVE_X86_64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h new file mode 100644 index 0000000000..08d5abf74a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#define MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#include "../../../common.h" + +#include +#include "consts.h" + +#define MLD_AVX2_REJ_UNIFORM_BUFLEN \ + (5 * 168) /* REJ_UNIFORM_NBLOCKS * SHAKE128_RATE */ + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) + +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_rej_uniform_table MLD_NAMESPACE(mld_rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[256][8]; + +#define mld_ntt_avx2 MLD_NAMESPACE(ntt_avx2) +void mld_ntt_avx2(int32_t *r, const int32_t *qdata) +/* This must be kept in sync with the HOL-Light specification + * in proofs/hol_light/x86_64/proofs/mldsa_ntt.ml */ +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, MLDSA_N, 8380417)) + requires(qdata == mld_qdata) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + /* check-magic: off */ + ensures(array_abs_bound(r, 0, MLDSA_N, 42035262)) + /* check-magic: on */ +); + +#define mld_invntt_avx2 MLD_NAMESPACE(invntt_avx2) +void mld_invntt_avx2(int32_t *r, const int32_t *mld_qdata); + +#define mld_nttunpack_avx2 MLD_NAMESPACE(nttunpack_avx2) +void mld_nttunpack_avx2(int32_t *r); + +#define mld_rej_uniform_avx2 MLD_NAMESPACE(mld_rej_uniform_avx2) +unsigned mld_rej_uniform_avx2(int32_t *r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]); + +#define mld_rej_uniform_eta2_avx2 MLD_NAMESPACE(mld_rej_uniform_eta2_avx2) +unsigned mld_rej_uniform_eta2_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]); + +#define mld_rej_uniform_eta4_avx2 MLD_NAMESPACE(mld_rej_uniform_eta4_avx2) +unsigned mld_rej_uniform_eta4_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]); + +#define mld_poly_decompose_32_avx2 MLD_NAMESPACE(mld_poly_decompose_32_avx2) +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_avx2 MLD_NAMESPACE(mld_poly_decompose_88_avx2) +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_avx2 MLD_NAMESPACE(poly_caddq_avx2) +void mld_poly_caddq_avx2(int32_t *r); + +#define mld_poly_use_hint_32_avx2 MLD_NAMESPACE(mld_poly_use_hint_32_avx2) +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_avx2 MLD_NAMESPACE(mld_poly_use_hint_88_avx2) +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_avx2 MLD_NAMESPACE(mld_poly_chknorm_avx2) +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_avx2 MLD_NAMESPACE(mld_polyz_unpack_17_avx2) +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a); + +#define mld_polyz_unpack_19_avx2 MLD_NAMESPACE(mld_polyz_unpack_19_avx2) +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a); + +#define mld_pointwise_avx2 MLD_NAMESPACE(pointwise_avx2) +void mld_pointwise_avx2(int32_t *c, const int32_t *a, const int32_t *b, + const int32_t *qdata); + +#define mld_pointwise_acc_l4_avx2 MLD_NAMESPACE(pointwise_acc_l4_avx2) +void mld_pointwise_acc_l4_avx2(int32_t c[MLDSA_N], const int32_t a[4][MLDSA_N], + const int32_t b[4][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l5_avx2 MLD_NAMESPACE(pointwise_acc_l5_avx2) +void mld_pointwise_acc_l5_avx2(int32_t c[MLDSA_N], const int32_t a[5][MLDSA_N], + const int32_t b[5][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l7_avx2 MLD_NAMESPACE(pointwise_acc_l7_avx2) +void mld_pointwise_acc_l7_avx2(int32_t c[MLDSA_N], const int32_t a[7][MLDSA_N], + const int32_t b[7][MLDSA_N], + const int32_t *qdata); + +#endif /* !MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/consts.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/consts.c new file mode 100644 index 0000000000..aaca3535ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/consts.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include "consts.h" + +/* + * Table of zeta values used in the AVX2 forward and inverse NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_qdata[624] = { + 8380417, 8380417, 8380417, 8380417, 8380417, + 8380417, 8380417, 8380417, 58728449, 58728449, + 58728449, 58728449, 58728449, 58728449, 58728449, + 58728449, -8395782, -8395782, -8395782, -8395782, + -8395782, -8395782, -8395782, -8395782, 41978, + 41978, 41978, 41978, 41978, 41978, + 41978, 41978, -151046689, 1830765815, -1929875198, + -1927777021, 1640767044, 1477910808, 1612161320, 1640734244, + 308362795, 308362795, 308362795, 308362795, -1815525077, + -1815525077, -1815525077, -1815525077, -1374673747, -1374673747, + -1374673747, -1374673747, -1091570561, -1091570561, -1091570561, + -1091570561, -1929495947, -1929495947, -1929495947, -1929495947, + 515185417, 515185417, 515185417, 515185417, -285697463, + -285697463, -285697463, -285697463, 625853735, 625853735, + 625853735, 625853735, 1727305304, 1727305304, 2082316400, + 2082316400, -1364982364, -1364982364, 858240904, 858240904, + 1806278032, 1806278032, 222489248, 222489248, -346752664, + -346752664, 684667771, 684667771, 1654287830, 1654287830, + -878576921, -878576921, -1257667337, -1257667337, -748618600, + -748618600, 329347125, 329347125, 1837364258, 1837364258, + -1443016191, -1443016191, -1170414139, -1170414139, -1846138265, + -1631226336, -1404529459, 1838055109, 1594295555, -1076973524, + -1898723372, -594436433, -202001019, -475984260, -561427818, + 1797021249, -1061813248, 2059733581, -1661512036, -1104976547, + -1750224323, -901666090, 418987550, 1831915353, -1925356481, + 992097815, 879957084, 2024403852, 1484874664, -1636082790, + -285388938, -1983539117, -1495136972, -950076368, -1714807468, + -952438995, -1574918427, 1350681039, -2143979939, 1599739335, + -1285853323, -993005454, -1440787840, 568627424, -783134478, + -588790216, 289871779, -1262003603, 2135294594, -1018755525, + -889861155, 1665705315, 1321868265, 1225434135, -1784632064, + 666258756, 675310538, -1555941048, -1999506068, -1499481951, + -695180180, -1375177022, 1777179795, 334803717, -178766299, + -518252220, 1957047970, 1146323031, -654783359, -1974159335, + 1651689966, 140455867, -1039411342, 1955560694, 1529189038, + -2131021878, -247357819, 1518161567, -86965173, 1708872713, + 1787797779, 1638590967, -120646188, -1669960606, -916321552, + 1155548552, 2143745726, 1210558298, -1261461890, -318346816, + 628664287, -1729304568, 1422575624, 1424130038, -1185330464, + 235321234, 168022240, 1206536194, 985155484, -894060583, + -898413, -1363460238, -605900043, 2027833504, 14253662, + 1014493059, 863641633, 1819892093, 2124962073, -1223601433, + -1920467227, -1637785316, -1536588520, 694382729, 235104446, + -1045062172, 831969619, -300448763, 756955444, -260312805, + 1554794072, 1339088280, -2040058690, -853476187, -2047270596, + -1723816713, -1591599803, -440824168, 1119856484, 1544891539, + 155290192, -973777462, 991903578, 912367099, -44694137, + 1176904444, -421552614, -818371958, 1747917558, -325927722, + 908452108, 1851023419, -1176751719, -1354528380, -72690498, + -314284737, 985022747, 963438279, -1078959975, 604552167, + -1021949428, 608791570, 173440395, -2126092136, -1316619236, + -1039370342, 6087993, -110126092, 565464272, -1758099917, + -1600929361, 879867909, -1809756372, 400711272, 1363007700, + 30313375, -326425360, 1683520342, -517299994, 2027935492, + -1372618620, 128353682, -1123881663, 137583815, -635454918, + -642772911, 45766801, 671509323, -2070602178, 419615363, + 1216882040, -270590488, -1276805128, 371462360, -1357098057, + -384158533, 827959816, -596344473, 702390549, -279505433, + -260424530, -71875110, -1208667171, -1499603926, 2036925262, + -540420426, 746144248, -1420958686, 2032221021, 1904936414, + 1257750362, 1926727420, 1931587462, 1258381762, 885133339, + 1629985060, 1967222129, 6363718, -1287922800, 1136965286, + 1779436847, 1116720494, 1042326957, 1405999311, 713994583, + 940195359, -1542497137, 2061661095, -883155599, 1726753853, + -1547952704, 394851342, 283780712, 776003547, 1123958025, + 201262505, 1934038751, 374860238, -3975713, 25847, + -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 1826347, 1826347, 1826347, + 2353451, 2353451, 2353451, 2353451, -359251, + -359251, -359251, -359251, -2091905, -2091905, + -2091905, -2091905, 3119733, 3119733, 3119733, + 3119733, -2884855, -2884855, -2884855, -2884855, + 3111497, 3111497, 3111497, 3111497, 2680103, + 2680103, 2680103, 2680103, 2725464, 2725464, + 1024112, 1024112, -1079900, -1079900, 3585928, + 3585928, -549488, -549488, -1119584, -1119584, + 2619752, 2619752, -2108549, -2108549, -2118186, + -2118186, -3859737, -3859737, -1399561, -1399561, + -3277672, -3277672, 1757237, 1757237, -19422, + -19422, 4010497, 4010497, 280005, 280005, + 2706023, 95776, 3077325, 3530437, -1661693, + -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, + -539299, -1699267, -1643818, 3505694, -3821735, + 3507263, -2140649, -1600420, 3699596, 811944, + 531354, 954230, 3881043, 3900724, -2556880, + 2071892, -2797779, -3930395, -3677745, -1452451, + 2176455, -1257611, -4083598, -3190144, -3632928, + 3412210, 2147896, -2967645, -411027, -671102, + -22981, -381987, 1852771, -3343383, 508951, + 44288, 904516, -3724342, 1653064, 2389356, + 759969, 189548, 3159746, -2409325, 1315589, + 1285669, -812732, -3019102, -3628969, -1528703, + -3041255, 3475950, -1585221, 1939314, -1000202, + -3157330, 126922, -983419, 2715295, -3693493, + -2477047, -1228525, -1308169, 1349076, -1430430, + 264944, 3097992, -1100098, 3958618, -8578, + -3249728, -210977, -1316856, -3553272, -1851402, + -177440, 1341330, -1584928, -1439742, -3881060, + 3839961, 2091667, -3342478, 266997, -3520352, + 900702, 495491, -655327, -3556995, 342297, + 3437287, 2842341, 4055324, -3767016, -2994039, + -1333058, -451100, -1279661, 1500165, -542412, + -2584293, -2013608, 1957272, -3183426, 810149, + -3038916, 2213111, -426683, -1667432, -2939036, + 183443, -554416, 3937738, 3407706, 2244091, + 2434439, -3759364, 1859098, -1613174, -3122442, + -525098, 286988, -3342277, 2691481, 1247620, + 1250494, 1869119, 1237275, 1312455, 1917081, + 777191, -2831860, -3724270, 2432395, 3369112, + 162844, 1652634, 3523897, -975884, 1723600, + -1104333, -2235985, -976891, 3919660, 1400424, + 2316500, -2446433, -1235728, -1197226, 909542, + -43260, 2031748, -768622, -2437823, 1735879, + -2590150, 2486353, 2635921, 1903435, -3318210, + 3306115, -2546312, 2235880, -1671176, 594136, + 2454455, 185531, 1616392, -3694233, 3866901, + 1717735, -1803090, -260646, -420899, 1612842, + -48306, -846154, 3817976, -3562462, 3513181, + -3193378, 819034, -522500, 3207046, -3595838, + 4108315, 203044, 1265009, 1595974, -3548272, + -1050970, -1430225, -1962642, -1374803, 3406031, + -1846953, -3776993, -164721, -1207385, 3014001, + -1799107, 269760, 472078, 1910376, -3833893, + -2286327, -3545687, -1362209, 1976782, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_consts) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/consts.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/consts.h new file mode 100644 index 0000000000..7fe08f454b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/consts.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#ifndef MLD_NATIVE_X86_64_SRC_CONSTS_H +#define MLD_NATIVE_X86_64_SRC_CONSTS_H +#include "../../../common.h" +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQ 0 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV 8 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV 16 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV 24 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV 32 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS 328 + +#ifndef __ASSEMBLER__ +#define mld_qdata MLD_NAMESPACE(qdata) +extern const int32_t mld_qdata[624]; +#endif + +#endif /* !MLD_NATIVE_X86_64_SRC_CONSTS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c new file mode 100644 index 0000000000..05d86d14fc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/************************************************* + * Name: mld_poly_caddq_avx2 + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *r: pointer to input/output polynomial + **************************************************/ +void mld_poly_caddq_avx2(int32_t *r) +{ + unsigned int i; + __m256i f, g; + const __m256i q = _mm256_set1_epi32(MLDSA_Q); + const __m256i zero = _mm256_setzero_si256(); + __m256i *rr = (__m256i *)r; + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256(&rr[i]); + g = _mm256_cmpgt_epi32(zero, f); + g = _mm256_and_si256(g, q); + f = _mm256_add_epi32(f, g); + _mm256_store_si256(&rr[i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_reduce) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c new file mode 100644 index 0000000000..50e2c7fa9b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B) +{ + unsigned int i; + __m256i f, t; + const __m256i bound = _mm256_set1_epi32(B - 1); + + t = _mm256_setzero_si256(); + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + f = _mm256_abs_epi32(f); + f = _mm256_cmpgt_epi32(f, bound); + t = _mm256_or_si256(t, f); + } + + return 1 - _mm256_testz_si256(t, t); +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_chknorm) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c new file mode 100644 index 0000000000..76846bf1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(31 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 4092 == intdiv(2 * intdiv(MLDSA_Q - 1, 32), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 4092. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 32*GAMMA2 = 16*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 16B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + * + * round(f1' * 1025 / 2^22) is in turn computed in 2 steps as + * round(floor(f1' * 1025 / 2^16) / 2^6). The mulhi computes f1'' = + * floor(f1' * 1025 / 2^16). As for the next step f1 = round(f1'' / 2^6), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^9) = round(f1'' * 2^9 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 1025 / 2^16) = 1025 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(16B / B) = 16 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 16, i.e. f > 31*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 31*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 15, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c new file mode 100644 index 0000000000..463506b962 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ + +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 1488 == intdiv(2 * intdiv(MLDSA_Q - 1, 88), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 1488. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 88*GAMMA2 = 44*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 44B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + * + * round(f1' * 11275 / 2^24) is in turn computed in 2 steps as + * round(floor(f1' * 11275 / 2^16) / 2^8). The mulhi computes f1'' = + * floor(f1' * 11275 / 2^16). As for the next step f1 = round(f1'' / 2^8), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^7) = round(f1'' * 2^7 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 11275 / 2^16) = 11275 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(44B / B) = 44 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 44, i.e. f > 87*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 87*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 43, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c new file mode 100644 index 0000000000..0094bc93a9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + const __m256i mask = _mm256_set1_epi32(15); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_32_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 16 */ + f1 = _mm256_add_epi32(f1, h); + f1 = _mm256_and_si256(f1, mask); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c new file mode 100644 index 0000000000..b109ab6351 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + const __m256i max = _mm256_set1_epi32(43); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_88_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 44 */ + f1 = _mm256_add_epi32(f1, h); + f1 = MLD_MM256_BLENDV_EPI32(f1, max, f1); + f = _mm256_cmpgt_epi32(f1, max); + f1 = MLD_MM256_BLENDV_EPI32(f1, zero, f); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c new file mode 100644 index 0000000000..f6c08a832f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 27, 26, 25, -1, 25, 24, 23, -1, 8, 7, + 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0); + const __m256i srlvdidx = _mm256_set_epi32(6, 4, 2, 0, 6, 4, 2, 0); + const __m256i mask = _mm256_set1_epi32(0x3FFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 17)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[18 * i]); + /* Load bytes 2..17 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[18 * i + 2]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-8 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 8, 7, 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte8, byte7, byte6, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,27, 26, 25, -1,25, 24, 23] │ + * │ Result: [0, byte17, byte16, byte15, ..., 0, byte11, byte10, byte9] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 18 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 32..55 48..71 + * 72..95 88..111 104..127 120..143 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 18..39 36..55 54..71 + * 72..95 90..111 108..127 126..143 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..17 18..35 36..53 54..71 + * 72..89 90..107 108..125 126..143 */ + + /* Map [0, 1, ..., 2^18-1] to [2^17, 2^17-1, ..., -2^17+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_17) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c new file mode 100644 index 0000000000..4a5ce48f38 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 26, 25, 24, -1, 24, 23, 22, -1, 9, 8, + 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0); + /* Equivalent to _mm256_set_epi32(4, 0, 4, 0, 4, 0, 4, 0) */ + const __m256i srlvdidx = _mm256_set1_epi64x((uint64_t)4 << 32); + const __m256i mask = _mm256_set1_epi32(0xFFFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 19)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[20 * i]); + /* Load bytes 4..19 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[20 * i + 4]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-9 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 9, 8, 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte9, byte8, byte7, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,26, 25, 24, -1,24, 23, 22] │ + * │ Result: [0, byte19, byte18, byte17, ..., 0, byte12, byte11, byte10] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 20 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 40..63 56..79 + * 80..103 96..119 120..143 136..159 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 20..39 40..63 60..79 + * 80..103 100..119 120..143 140..159 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..19 20..39 40..59 60..79 + * 80..99 100..119 120..139 140..159 */ + + /* Map [0, 1, ..., 2^20-1] to [2^19, 2^19-1, ..., -2^19+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_19) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c new file mode 100644 index 0000000000..07a5df9706 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The pqcrystals implementation assumes a buffer that is 8 bytes + *. larger as the first loop overreads by 8 bytes that are then + * discarded. We instead do not pad the buffer and do not overread. + * The performance impact is negligible and it does not force the + * frontend to perform the unintuitive padding. + */ + +unsigned int mld_rej_uniform_avx2( + int32_t *MLD_RESTRICT r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i d, tmp; + const __m256i bound = _mm256_set1_epi32(MLDSA_Q); + const __m256i mask = _mm256_set1_epi32(0x7FFFFF); + const __m256i idx8 = + _mm256_set_epi8(-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4, + -1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 32) + { + d = _mm256_loadu_si256((__m256i *)&buf[pos]); + + /* Permute 64-bit lanes + * 0x94 = 10010100b rearranges 64-bit lanes as: [3,2,1,0] -> [2,1,1,0] + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Original Layout ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ bytes 16..23 │ bytes 24..31 │ + * └─────────────────┴─────────────────┴─────────────────┴─────────────────┘ + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Layout after permute ║ + * ║ Byte indices in high half shifted down by 8 positions ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌───────────────┬─────────────────┐ ┌─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ │ bytes 8..15 │ bytes 16..23 │ + * └───────────────┴─────────────────┘ └─────────────────┴─────────────────┘ + * Lower 128-bit lane (bytes 0-15) Upper 128-bit lane (bytes 16-31) + */ + d = _mm256_permute4x64_epi64(d, 0x94); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-11 into low 128-bit half of permuted vector────────────────┐ + * │ Shuffle: [-1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0] │ + * │ Result: [0, byte11, byte10, byte9, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 4-15 into high 128-bit half of permuted vector ──────────────┐ + * │ Shuffle: [-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4] │ + * │ Result: [0, byte23, byte22, byte21, ..., 0, byte14, byte13, byte12 │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + d = _mm256_shuffle_epi8(d, idx8); + d = _mm256_and_si256(d, mask); + pos += 24; + + tmp = _mm256_sub_epi32(d, bound); + good = (uint32_t)_mm256_movemask_ps((__m256)tmp); + tmp = _mm256_cvtepu8_epi32( + _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good])); + d = _mm256_permutevar8x32_epi32(d, tmp); + + _mm256_storeu_si256((__m256i *)&r[ctr], d); + ctr += (unsigned)_mm_popcnt_u32(good); + } + + while (ctr < MLDSA_N && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 3) + { + uint32_t t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + /* Safe because t < MLDSA_Q. */ + r[ctr++] = (int32_t)t; + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c new file mode 100644 index 0000000000..70c5c42c70 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA2 2 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ +unsigned int mld_rej_uniform_eta2_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1, f2; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA2); + const __m256i bound = mask; + /* check-magic: -6560 == 32*round(-2**10 / 5) */ + const __m256i v = _mm256_set1_epi32(-6560); + const __m256i p = _mm256_set1_epi32(5); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 15) + { + t0 = t0 - (205 * t0 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t0); + } + if (t1 < 15 && ctr < MLDSA_N) + { + t1 = t1 - (205 * t1 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta2) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA2 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c new file mode 100644 index 0000000000..ba00e91252 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA4 4 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ + +unsigned int mld_rej_uniform_eta4_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA4); + const __m256i bound = _mm256_set1_epi8(9); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 9) + { + r[ctr++] = (int32_t)(4 - t0); + } + if (t1 < 9 && ctr < MLDSA_N) + { + r[ctr++] = (int32_t)(4 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta4) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA4 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/rej_uniform_table.c new file mode 100644 index 0000000000..6c537b4542 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/native/x86_64/src/rej_uniform_table.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" + +/* + * Lookup table used by rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[256][8] = { + {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, + {2, 0, 0, 0, 0, 0, 0, 0}, {0, 2, 0, 0, 0, 0, 0, 0}, + {1, 2, 0, 0, 0, 0, 0, 0}, {0, 1, 2, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 0, 0}, {0, 3, 0, 0, 0, 0, 0, 0}, + {1, 3, 0, 0, 0, 0, 0, 0}, {0, 1, 3, 0, 0, 0, 0, 0}, + {2, 3, 0, 0, 0, 0, 0, 0}, {0, 2, 3, 0, 0, 0, 0, 0}, + {1, 2, 3, 0, 0, 0, 0, 0}, {0, 1, 2, 3, 0, 0, 0, 0}, + {4, 0, 0, 0, 0, 0, 0, 0}, {0, 4, 0, 0, 0, 0, 0, 0}, + {1, 4, 0, 0, 0, 0, 0, 0}, {0, 1, 4, 0, 0, 0, 0, 0}, + {2, 4, 0, 0, 0, 0, 0, 0}, {0, 2, 4, 0, 0, 0, 0, 0}, + {1, 2, 4, 0, 0, 0, 0, 0}, {0, 1, 2, 4, 0, 0, 0, 0}, + {3, 4, 0, 0, 0, 0, 0, 0}, {0, 3, 4, 0, 0, 0, 0, 0}, + {1, 3, 4, 0, 0, 0, 0, 0}, {0, 1, 3, 4, 0, 0, 0, 0}, + {2, 3, 4, 0, 0, 0, 0, 0}, {0, 2, 3, 4, 0, 0, 0, 0}, + {1, 2, 3, 4, 0, 0, 0, 0}, {0, 1, 2, 3, 4, 0, 0, 0}, + {5, 0, 0, 0, 0, 0, 0, 0}, {0, 5, 0, 0, 0, 0, 0, 0}, + {1, 5, 0, 0, 0, 0, 0, 0}, {0, 1, 5, 0, 0, 0, 0, 0}, + {2, 5, 0, 0, 0, 0, 0, 0}, {0, 2, 5, 0, 0, 0, 0, 0}, + {1, 2, 5, 0, 0, 0, 0, 0}, {0, 1, 2, 5, 0, 0, 0, 0}, + {3, 5, 0, 0, 0, 0, 0, 0}, {0, 3, 5, 0, 0, 0, 0, 0}, + {1, 3, 5, 0, 0, 0, 0, 0}, {0, 1, 3, 5, 0, 0, 0, 0}, + {2, 3, 5, 0, 0, 0, 0, 0}, {0, 2, 3, 5, 0, 0, 0, 0}, + {1, 2, 3, 5, 0, 0, 0, 0}, {0, 1, 2, 3, 5, 0, 0, 0}, + {4, 5, 0, 0, 0, 0, 0, 0}, {0, 4, 5, 0, 0, 0, 0, 0}, + {1, 4, 5, 0, 0, 0, 0, 0}, {0, 1, 4, 5, 0, 0, 0, 0}, + {2, 4, 5, 0, 0, 0, 0, 0}, {0, 2, 4, 5, 0, 0, 0, 0}, + {1, 2, 4, 5, 0, 0, 0, 0}, {0, 1, 2, 4, 5, 0, 0, 0}, + {3, 4, 5, 0, 0, 0, 0, 0}, {0, 3, 4, 5, 0, 0, 0, 0}, + {1, 3, 4, 5, 0, 0, 0, 0}, {0, 1, 3, 4, 5, 0, 0, 0}, + {2, 3, 4, 5, 0, 0, 0, 0}, {0, 2, 3, 4, 5, 0, 0, 0}, + {1, 2, 3, 4, 5, 0, 0, 0}, {0, 1, 2, 3, 4, 5, 0, 0}, + {6, 0, 0, 0, 0, 0, 0, 0}, {0, 6, 0, 0, 0, 0, 0, 0}, + {1, 6, 0, 0, 0, 0, 0, 0}, {0, 1, 6, 0, 0, 0, 0, 0}, + {2, 6, 0, 0, 0, 0, 0, 0}, {0, 2, 6, 0, 0, 0, 0, 0}, + {1, 2, 6, 0, 0, 0, 0, 0}, {0, 1, 2, 6, 0, 0, 0, 0}, + {3, 6, 0, 0, 0, 0, 0, 0}, {0, 3, 6, 0, 0, 0, 0, 0}, + {1, 3, 6, 0, 0, 0, 0, 0}, {0, 1, 3, 6, 0, 0, 0, 0}, + {2, 3, 6, 0, 0, 0, 0, 0}, {0, 2, 3, 6, 0, 0, 0, 0}, + {1, 2, 3, 6, 0, 0, 0, 0}, {0, 1, 2, 3, 6, 0, 0, 0}, + {4, 6, 0, 0, 0, 0, 0, 0}, {0, 4, 6, 0, 0, 0, 0, 0}, + {1, 4, 6, 0, 0, 0, 0, 0}, {0, 1, 4, 6, 0, 0, 0, 0}, + {2, 4, 6, 0, 0, 0, 0, 0}, {0, 2, 4, 6, 0, 0, 0, 0}, + {1, 2, 4, 6, 0, 0, 0, 0}, {0, 1, 2, 4, 6, 0, 0, 0}, + {3, 4, 6, 0, 0, 0, 0, 0}, {0, 3, 4, 6, 0, 0, 0, 0}, + {1, 3, 4, 6, 0, 0, 0, 0}, {0, 1, 3, 4, 6, 0, 0, 0}, + {2, 3, 4, 6, 0, 0, 0, 0}, {0, 2, 3, 4, 6, 0, 0, 0}, + {1, 2, 3, 4, 6, 0, 0, 0}, {0, 1, 2, 3, 4, 6, 0, 0}, + {5, 6, 0, 0, 0, 0, 0, 0}, {0, 5, 6, 0, 0, 0, 0, 0}, + {1, 5, 6, 0, 0, 0, 0, 0}, {0, 1, 5, 6, 0, 0, 0, 0}, + {2, 5, 6, 0, 0, 0, 0, 0}, {0, 2, 5, 6, 0, 0, 0, 0}, + {1, 2, 5, 6, 0, 0, 0, 0}, {0, 1, 2, 5, 6, 0, 0, 0}, + {3, 5, 6, 0, 0, 0, 0, 0}, {0, 3, 5, 6, 0, 0, 0, 0}, + {1, 3, 5, 6, 0, 0, 0, 0}, {0, 1, 3, 5, 6, 0, 0, 0}, + {2, 3, 5, 6, 0, 0, 0, 0}, {0, 2, 3, 5, 6, 0, 0, 0}, + {1, 2, 3, 5, 6, 0, 0, 0}, {0, 1, 2, 3, 5, 6, 0, 0}, + {4, 5, 6, 0, 0, 0, 0, 0}, {0, 4, 5, 6, 0, 0, 0, 0}, + {1, 4, 5, 6, 0, 0, 0, 0}, {0, 1, 4, 5, 6, 0, 0, 0}, + {2, 4, 5, 6, 0, 0, 0, 0}, {0, 2, 4, 5, 6, 0, 0, 0}, + {1, 2, 4, 5, 6, 0, 0, 0}, {0, 1, 2, 4, 5, 6, 0, 0}, + {3, 4, 5, 6, 0, 0, 0, 0}, {0, 3, 4, 5, 6, 0, 0, 0}, + {1, 3, 4, 5, 6, 0, 0, 0}, {0, 1, 3, 4, 5, 6, 0, 0}, + {2, 3, 4, 5, 6, 0, 0, 0}, {0, 2, 3, 4, 5, 6, 0, 0}, + {1, 2, 3, 4, 5, 6, 0, 0}, {0, 1, 2, 3, 4, 5, 6, 0}, + {7, 0, 0, 0, 0, 0, 0, 0}, {0, 7, 0, 0, 0, 0, 0, 0}, + {1, 7, 0, 0, 0, 0, 0, 0}, {0, 1, 7, 0, 0, 0, 0, 0}, + {2, 7, 0, 0, 0, 0, 0, 0}, {0, 2, 7, 0, 0, 0, 0, 0}, + {1, 2, 7, 0, 0, 0, 0, 0}, {0, 1, 2, 7, 0, 0, 0, 0}, + {3, 7, 0, 0, 0, 0, 0, 0}, {0, 3, 7, 0, 0, 0, 0, 0}, + {1, 3, 7, 0, 0, 0, 0, 0}, {0, 1, 3, 7, 0, 0, 0, 0}, + {2, 3, 7, 0, 0, 0, 0, 0}, {0, 2, 3, 7, 0, 0, 0, 0}, + {1, 2, 3, 7, 0, 0, 0, 0}, {0, 1, 2, 3, 7, 0, 0, 0}, + {4, 7, 0, 0, 0, 0, 0, 0}, {0, 4, 7, 0, 0, 0, 0, 0}, + {1, 4, 7, 0, 0, 0, 0, 0}, {0, 1, 4, 7, 0, 0, 0, 0}, + {2, 4, 7, 0, 0, 0, 0, 0}, {0, 2, 4, 7, 0, 0, 0, 0}, + {1, 2, 4, 7, 0, 0, 0, 0}, {0, 1, 2, 4, 7, 0, 0, 0}, + {3, 4, 7, 0, 0, 0, 0, 0}, {0, 3, 4, 7, 0, 0, 0, 0}, + {1, 3, 4, 7, 0, 0, 0, 0}, {0, 1, 3, 4, 7, 0, 0, 0}, + {2, 3, 4, 7, 0, 0, 0, 0}, {0, 2, 3, 4, 7, 0, 0, 0}, + {1, 2, 3, 4, 7, 0, 0, 0}, {0, 1, 2, 3, 4, 7, 0, 0}, + {5, 7, 0, 0, 0, 0, 0, 0}, {0, 5, 7, 0, 0, 0, 0, 0}, + {1, 5, 7, 0, 0, 0, 0, 0}, {0, 1, 5, 7, 0, 0, 0, 0}, + {2, 5, 7, 0, 0, 0, 0, 0}, {0, 2, 5, 7, 0, 0, 0, 0}, + {1, 2, 5, 7, 0, 0, 0, 0}, {0, 1, 2, 5, 7, 0, 0, 0}, + {3, 5, 7, 0, 0, 0, 0, 0}, {0, 3, 5, 7, 0, 0, 0, 0}, + {1, 3, 5, 7, 0, 0, 0, 0}, {0, 1, 3, 5, 7, 0, 0, 0}, + {2, 3, 5, 7, 0, 0, 0, 0}, {0, 2, 3, 5, 7, 0, 0, 0}, + {1, 2, 3, 5, 7, 0, 0, 0}, {0, 1, 2, 3, 5, 7, 0, 0}, + {4, 5, 7, 0, 0, 0, 0, 0}, {0, 4, 5, 7, 0, 0, 0, 0}, + {1, 4, 5, 7, 0, 0, 0, 0}, {0, 1, 4, 5, 7, 0, 0, 0}, + {2, 4, 5, 7, 0, 0, 0, 0}, {0, 2, 4, 5, 7, 0, 0, 0}, + {1, 2, 4, 5, 7, 0, 0, 0}, {0, 1, 2, 4, 5, 7, 0, 0}, + {3, 4, 5, 7, 0, 0, 0, 0}, {0, 3, 4, 5, 7, 0, 0, 0}, + {1, 3, 4, 5, 7, 0, 0, 0}, {0, 1, 3, 4, 5, 7, 0, 0}, + {2, 3, 4, 5, 7, 0, 0, 0}, {0, 2, 3, 4, 5, 7, 0, 0}, + {1, 2, 3, 4, 5, 7, 0, 0}, {0, 1, 2, 3, 4, 5, 7, 0}, + {6, 7, 0, 0, 0, 0, 0, 0}, {0, 6, 7, 0, 0, 0, 0, 0}, + {1, 6, 7, 0, 0, 0, 0, 0}, {0, 1, 6, 7, 0, 0, 0, 0}, + {2, 6, 7, 0, 0, 0, 0, 0}, {0, 2, 6, 7, 0, 0, 0, 0}, + {1, 2, 6, 7, 0, 0, 0, 0}, {0, 1, 2, 6, 7, 0, 0, 0}, + {3, 6, 7, 0, 0, 0, 0, 0}, {0, 3, 6, 7, 0, 0, 0, 0}, + {1, 3, 6, 7, 0, 0, 0, 0}, {0, 1, 3, 6, 7, 0, 0, 0}, + {2, 3, 6, 7, 0, 0, 0, 0}, {0, 2, 3, 6, 7, 0, 0, 0}, + {1, 2, 3, 6, 7, 0, 0, 0}, {0, 1, 2, 3, 6, 7, 0, 0}, + {4, 6, 7, 0, 0, 0, 0, 0}, {0, 4, 6, 7, 0, 0, 0, 0}, + {1, 4, 6, 7, 0, 0, 0, 0}, {0, 1, 4, 6, 7, 0, 0, 0}, + {2, 4, 6, 7, 0, 0, 0, 0}, {0, 2, 4, 6, 7, 0, 0, 0}, + {1, 2, 4, 6, 7, 0, 0, 0}, {0, 1, 2, 4, 6, 7, 0, 0}, + {3, 4, 6, 7, 0, 0, 0, 0}, {0, 3, 4, 6, 7, 0, 0, 0}, + {1, 3, 4, 6, 7, 0, 0, 0}, {0, 1, 3, 4, 6, 7, 0, 0}, + {2, 3, 4, 6, 7, 0, 0, 0}, {0, 2, 3, 4, 6, 7, 0, 0}, + {1, 2, 3, 4, 6, 7, 0, 0}, {0, 1, 2, 3, 4, 6, 7, 0}, + {5, 6, 7, 0, 0, 0, 0, 0}, {0, 5, 6, 7, 0, 0, 0, 0}, + {1, 5, 6, 7, 0, 0, 0, 0}, {0, 1, 5, 6, 7, 0, 0, 0}, + {2, 5, 6, 7, 0, 0, 0, 0}, {0, 2, 5, 6, 7, 0, 0, 0}, + {1, 2, 5, 6, 7, 0, 0, 0}, {0, 1, 2, 5, 6, 7, 0, 0}, + {3, 5, 6, 7, 0, 0, 0, 0}, {0, 3, 5, 6, 7, 0, 0, 0}, + {1, 3, 5, 6, 7, 0, 0, 0}, {0, 1, 3, 5, 6, 7, 0, 0}, + {2, 3, 5, 6, 7, 0, 0, 0}, {0, 2, 3, 5, 6, 7, 0, 0}, + {1, 2, 3, 5, 6, 7, 0, 0}, {0, 1, 2, 3, 5, 6, 7, 0}, + {4, 5, 6, 7, 0, 0, 0, 0}, {0, 4, 5, 6, 7, 0, 0, 0}, + {1, 4, 5, 6, 7, 0, 0, 0}, {0, 1, 4, 5, 6, 7, 0, 0}, + {2, 4, 5, 6, 7, 0, 0, 0}, {0, 2, 4, 5, 6, 7, 0, 0}, + {1, 2, 4, 5, 6, 7, 0, 0}, {0, 1, 2, 4, 5, 6, 7, 0}, + {3, 4, 5, 6, 7, 0, 0, 0}, {0, 3, 4, 5, 6, 7, 0, 0}, + {1, 3, 4, 5, 6, 7, 0, 0}, {0, 1, 3, 4, 5, 6, 7, 0}, + {2, 3, 4, 5, 6, 7, 0, 0}, {0, 2, 3, 4, 5, 6, 7, 0}, + {1, 2, 3, 4, 5, 6, 7, 0}, {0, 1, 2, 3, 4, 5, 6, 7}, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/packing.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/packing.c new file mode 100644 index 0000000000..26da273856 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/packing.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include + +#include "common.h" +#include "packing.h" +#include "poly.h" +#include "polyvec.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_unpack_hints MLD_ADD_PARAM_SET(mld_unpack_hints) +/* End of parameter set namespacing */ + +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +{ + unsigned int i; + + mld_memcpy(pk, rho, MLDSA_SEEDBYTES); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt1_pack(pk + MLDSA_SEEDBYTES + i * MLDSA_POLYT1_PACKEDBYTES, + &t1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +{ + unsigned int i; + + mld_memcpy(rho, pk, MLDSA_SEEDBYTES); + pk += MLDSA_SEEDBYTES; + + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt1_unpack(&t1->vec[i], pk + i * MLDSA_POLYT1_PACKEDBYTES); + } +} + +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +{ + mld_memcpy(sk, rho, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, key, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, tr, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_pack_eta(sk, s1); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_eta(sk, s2); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_t0(sk, t0); +} + +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +{ + mld_memcpy(rho, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(key, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(tr, sk, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_unpack_eta(s1, sk); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_eta(s2, sk); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_t0(t0, sk); +} + +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +{ + unsigned int i, j, k; + + mld_memcpy(sig, c, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + /* skip z component - packed via mld_pack_sig_z */ + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + /* Encode hints h */ + + /* The final section of sig[] is MLDSA_POLYVECH_PACKEDBYTES long, where + * MLDSA_POLYVECH_PACKEDBYTES = MLDSA_OMEGA + MLDSA_K + * + * The first OMEGA bytes record the index numbers of the coefficients + * that are not equal to 0 + * + * The final K bytes record a running tally of the number of hints + * coming from each of the K polynomials in h. + * + * The pre-condition tells us that number_of_hints <= OMEGA, so some + * bytes may not be written, so we initialize all of them to zero + * to start. + */ + mld_memset(sig, 0, MLDSA_POLYVECH_PACKEDBYTES); + + k = 0; + /* For each polynomial in h... */ + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* For each coefficient in that polynomial, record it as as hint */ + /* if its value is not zero */ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + assigns(j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(j <= MLDSA_N) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* The reference implementation implicitly relies on the total */ + /* number of hints being less than OMEGA, assuming h is valid. */ + /* In mldsa-native, we check this explicitly to ease proof of */ + /* type safety. */ + if (h->vec[i].coeffs[j] != 0 && k < number_of_hints) + { + /* The enclosing if condition AND the loop invariant infer */ + /* that k < MLDSA_OMEGA, so writing to sig[k] is safe and k */ + /* can be incremented. */ + sig[k++] = (uint8_t)j; + } + } + /* Having recorded all the hints for this polynomial, also */ + /* record the running tally into the correct "slot" for that */ + /* coefficient in the final K bytes */ + sig[MLDSA_OMEGA + i] = (uint8_t)k; + } +} + +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +{ + sig += MLDSA_CTILDEBYTES; + sig += i * MLDSA_POLYZ_PACKEDBYTES; + mld_polyz_pack(sig, zi); +} + +/************************************************* + * Name: mld_unpack_hints + * + * Description: Unpack raw hint bytes into a polyveck + * struct + * + * Arguments: - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]: + * raw hint bytes + * + * Returns 1 in case of malformed hints; otherwise 0. + **************************************************/ +static int mld_unpack_hints( + mld_polyveck *h, const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(packed_hints, MLDSA_POLYVECH_PACKEDBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + /* All returned coefficients are either 0 or 1 */ + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +) +{ + unsigned int i, j; + unsigned int old_hint_count; + + /* Set all coefficients of all polynomials to 0. */ + /* Only those that are actually non-zero hints will */ + /* be overwritten below. */ + mld_memset(h, 0, sizeof(mld_polyveck)); + + old_hint_count = 0; + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + /* Grab the hint count for the i'th polynomial */ + const unsigned int new_hint_count = packed_hints[MLDSA_OMEGA + i]; + + /* new_hint_count must increase or stay the same, but also remain */ + /* less than or equal to MLDSA_OMEGA */ + if (new_hint_count < old_hint_count || new_hint_count > MLDSA_OMEGA) + { + /* Error - new_hint_count is invalid */ + return 1; + } + + /* If new_hint_count == old_hint_count, then this polynomial has */ + /* zero hints, so this loop executes zero times and we move */ + /* straight on to the next polynomial. */ + for (j = old_hint_count; j < new_hint_count; ++j) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + const uint8_t this_hint_index = packed_hints[j]; + + /* Coefficients must be ordered for strong unforgeability */ + if (j > old_hint_count && this_hint_index <= packed_hints[j - 1]) + { + return 1; + } + h->vec[i].coeffs[this_hint_index] = 1; + } + + old_hint_count = new_hint_count; + } + + /* Extra indices must be zero for strong unforgeability */ + for (j = old_hint_count; j < MLDSA_OMEGA; ++j) + __loop__( + invariant(j <= MLDSA_OMEGA) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + if (packed_hints[j] != 0) + { + return 1; + } + } + + return 0; +} + +MLD_INTERNAL_API +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +{ + mld_memcpy(c, sig, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + mld_polyvecl_unpack_z(z, sig); + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + return mld_unpack_hints(h, sig); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_unpack_hints diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/packing.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/packing.h new file mode 100644 index 0000000000..19095d08cd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/packing.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PACKING_H +#define MLD_PACKING_H + +#include +#include "polyvec.h" + +#define mld_pack_pk MLD_NAMESPACE_KL(pack_pk) +/************************************************* + * Name: mld_pack_pk + * + * Description: Bit-pack public key pk = (rho, t1). + * + * Arguments: - uint8_t pk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const mld_polyveck *t1: pointer to vector t1 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) +); + + +#define mld_pack_sk MLD_NAMESPACE_KL(pack_sk) +/************************************************* + * Name: mld_pack_sk + * + * Description: Bit-pack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - uint8_t sk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const uint8_t tr[]: byte array containing tr + * - const uint8_t key[]: byte array containing key + * - const mld_polyveck *t0: pointer to vector t0 + * - const mld_polyvecl *s1: pointer to vector s1 + * - const mld_polyveck *s2: pointer to vector s2 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +__contract__( + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + requires(forall(k2, 0, MLDSA_K, + array_abs_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) +); + + +#define mld_pack_sig_c_h MLD_NAMESPACE_KL(pack_sig_c_h) +/************************************************* + * Name: mld_pack_sig_c_h + * + * Description: Bit-pack c and h component of sig = (c, z, h). + * The z component is packed separately using mld_pack_sig_z. + * + * Arguments: - uint8_t sig[]: output byte array + * - const uint8_t *c: pointer to challenge hash length + * MLDSA_SEEDBYTES + * - const mld_polyveck *h: pointer to hint vector h + * - const unsigned int number_of_hints: total + * hints in *h + * + * Note that the number_of_hints argument is not present + * in the reference implementation. It is added here to ease + * proof of type safety. + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + requires(number_of_hints <= MLDSA_OMEGA) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_pack_sig_z MLD_NAMESPACE_KL(pack_sig_z) +/************************************************* + * Name: mld_pack_sig_z + * + * Description: Bit-pack single polynomial of z component of sig = (c, z, h). + * The c and h components are packed separately using + * mld_pack_sig_c_h. + * + * Arguments: - uint8_t sig[]: output byte array + * - const mld_poly *zi: pointer to a single polynomial in z + * - const unsigned int i: index of zi in vector z + * + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(zi, sizeof(mld_poly))) + requires(i < MLDSA_L) + requires(array_bound(zi->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_unpack_pk MLD_NAMESPACE_KL(unpack_pk) +/************************************************* + * Name: mld_unpack_pk + * + * Description: Unpack public key pk = (rho, t1). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const mld_polyveck *t1: pointer to output vector t1 + * - uint8_t pk[]: byte array containing bit-packed pk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) +); + + +#define mld_unpack_sk MLD_NAMESPACE_KL(unpack_sk) +/************************************************* + * Name: mld_unpack_sk + * + * Description: Unpack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const uint8_t tr[]: output byte array for tr + * - const uint8_t key[]: output byte array for key + * - const mld_polyveck *t0: pointer to output vector t0 + * - const mld_polyvecl *s1: pointer to output vector s1 + * - const mld_polyveck *s2: pointer to output vector s2 + * - uint8_t sk[]: byte array containing bit-packed sk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +__contract__( + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(key, MLDSA_SEEDBYTES)) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(s1, sizeof(mld_polyvecl))) + assigns(memory_slice(s2, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_unpack_sig MLD_NAMESPACE_KL(unpack_sig) +/************************************************* + * Name: mld_unpack_sig + * + * Description: Unpack signature sig = (c, z, h). + * + * Arguments: - uint8_t *c: pointer to output challenge hash + * - mld_polyvecl *z: pointer to output vector z + * - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t sig[]: byte array containing + * bit-packed signature + * + * Returns 1 in case of malformed signature; otherwise 0. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(c, MLDSA_CTILDEBYTES)) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(z->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +); +#endif /* !MLD_PACKING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/params.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/params.h new file mode 100644 index 0000000000..c67d2a33fb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/params.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PARAMS_H +#define MLD_PARAMS_H + +#define MLDSA_SEEDBYTES 32 +#define MLDSA_CRHBYTES 64 +#define MLDSA_TRBYTES 64 +#define MLDSA_RNDBYTES 32 +#define MLDSA_N 256 +#define MLDSA_Q 8380417 +#define MLDSA_Q_HALF ((MLDSA_Q + 1) / 2) +#define MLDSA_D 13 + +#if MLD_CONFIG_PARAMETER_SET == 44 + +#define MLDSA_K 4 +#define MLDSA_L 4 +#define MLDSA_ETA 2 +#define MLDSA_TAU 39 +#define MLDSA_BETA 78 +#define MLDSA_GAMMA1 (1 << 17) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 88) +#define MLDSA_OMEGA 80 +#define MLDSA_CTILDEBYTES 32 +#define MLDSA_POLYZ_PACKEDBYTES 576 +#define MLDSA_POLYW1_PACKEDBYTES 192 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#elif MLD_CONFIG_PARAMETER_SET == 65 + +#define MLDSA_K 6 +#define MLDSA_L 5 +#define MLDSA_ETA 4 +#define MLDSA_TAU 49 +#define MLDSA_BETA 196 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 55 +#define MLDSA_CTILDEBYTES 48 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 128 + +#elif MLD_CONFIG_PARAMETER_SET == 87 + +#define MLDSA_K 8 +#define MLDSA_L 7 +#define MLDSA_ETA 2 +#define MLDSA_TAU 60 +#define MLDSA_BETA 120 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 75 +#define MLDSA_CTILDEBYTES 64 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ + +#define MLDSA_POLYT1_PACKEDBYTES 320 +#define MLDSA_POLYT0_PACKEDBYTES 416 +#define MLDSA_POLYVECH_PACKEDBYTES (MLDSA_OMEGA + MLDSA_K) + +#define MLDSA_CRYPTO_PUBLICKEYBYTES \ + (MLDSA_SEEDBYTES + MLDSA_K * MLDSA_POLYT1_PACKEDBYTES) +#define MLDSA_CRYPTO_SECRETKEYBYTES \ + (2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + MLDSA_L * MLDSA_POLYETA_PACKEDBYTES + \ + MLDSA_K * MLDSA_POLYETA_PACKEDBYTES + MLDSA_K * MLDSA_POLYT0_PACKEDBYTES) +#define MLDSA_CRYPTO_BYTES \ + (MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES + \ + MLDSA_POLYVECH_PACKEDBYTES) + +#endif /* !MLD_PARAMS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/poly.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/poly.c new file mode 100644 index 0000000000..e40534e773 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/poly.c @@ -0,0 +1,973 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "common.h" +#include "ct.h" +#include "debug.h" +#include "poly.h" +#include "reduce.h" +#include "rounding.h" +#include "symmetric.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +#include "zetas.inc" + +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + { + a->coeffs[i] = mld_reduce32(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_STATIC_TESTABLE void mld_poly_caddq_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + ) + { + a->coeffs[i] = mld_caddq(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_POLY_CADDQ) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_poly_caddq_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + mld_poly_caddq_c(a); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1])) + invariant(forall(k2, 0, i, r->coeffs[k2] < MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k2, 0, i, r->coeffs[k2] >= INT32_MIN)) + ) + { + r->coeffs[i] = r->coeffs[i] + b->coeffs[i]; + } +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(r->coeffs, 0, i, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + ) + { + r->coeffs[i] = r->coeffs[i] - b->coeffs[i]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N; i++) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))) + { + /* Reference: uses a left shift by MLDSA_D which is undefined behaviour in + * C90/C99 + */ + a->coeffs[i] *= (1 << MLDSA_D); + } + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + + +static MLD_INLINE int32_t mld_fqmul(int32_t a, int32_t b) +__contract__( + requires(b > -MLDSA_Q_HALF && b < MLDSA_Q_HALF) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* Bounds: We argue in mld_montgomery_reduce() that the reult + * of Montgomery reduction is < MLDSA_Q if the input is smaller + * than 2^31 * MLDSA_Q in absolute value. Indeed, we have: + * + * |a * b| = |a| * |b| + * < 2^31 * MLDSA_Q_HALF + * < 2^31 * MLDSA_Q + */ + return mld_montgomery_reduce((int64_t)a * (int64_t)b); +} + +/* mld_ntt_butterfly_block() + * + * Computes a block CT butterflies with a fixed twiddle factor, + * using Montgomery multiplication. + * + * Parameters: + * - r: Pointer to base of polynomial (_not_ the base of butterfly block) + * - zeta: Twiddle factor to use for the butterfly. This must be in + * Montgomery form and signed canonical. + * - start: Offset to the beginning of the butterfly block + * - len: Index difference between coefficients subject to a butterfly + * - bound: Ghost variable describing coefficient bound: Prior to `start`, + * coefficients must be bound by `bound + MLDSA_Q`. Post `start`, + * they must be bound by `bound`. + * When this function returns, output coefficients in the index range + * [start, start+2*len) have bound bumped to `bound + MLDSA_Q`. + * Example: + * - start=8, len=4 + * This would compute the following four butterflies + * 8 -- 12 + * 9 -- 13 + * 10 -- 14 + * 11 -- 15 + * - start=4, len=2 + * This would compute the following two butterflies + * 4 -- 6 + * 5 -- 7 + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_butterfly_block(int32_t r[MLDSA_N], + const int32_t zeta, + const unsigned start, + const unsigned len, + const unsigned bound) +__contract__( + requires(start < MLDSA_N) + requires(1 <= len && len <= MLDSA_N / 2 && start + 2 * len <= MLDSA_N) + requires(0 <= bound && bound < INT32_MAX - MLDSA_Q) + requires(-MLDSA_Q_HALF < zeta && zeta < MLDSA_Q_HALF) + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, start, bound + MLDSA_Q)) + requires(array_abs_bound(r, start, MLDSA_N, bound)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, start + 2*len, bound + MLDSA_Q)) + ensures(array_abs_bound(r, start + 2 * len, MLDSA_N, bound))) +{ + /* `bound` is a ghost variable only needed in the CBMC specification */ + unsigned j; + ((void)bound); + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + /* + * Coefficients are updated in strided pairs, so the bounds for the + * intermediate states alternate twice between the old and new bound + */ + invariant(array_abs_bound(r, 0, j, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, bound)) + invariant(array_abs_bound(r, start + len, j + len, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j + len, MLDSA_N, bound))) + { + int32_t t; + t = mld_fqmul(r[j + len], zeta); + r[j + len] = r[j] - t; + r[j] = r[j] + t; + } +} + +/* mld_ntt_layer() + * + * Compute one layer of forward NTT + * + * Parameters: + * - r: Pointer to base of polynomial + * - layer: Indicates which layer is being applied. + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_layer(int32_t r[MLDSA_N], const unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (layer + 1) * MLDSA_Q))) +{ + unsigned start, k, len; + /* Twiddle factors for layer n are at indices 2^(n-1)..2^n-1. */ + k = 1u << (layer - 1); + len = (unsigned)MLDSA_N >> layer; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start < MLDSA_N + 2 * len) + invariant(k <= MLDSA_N) + invariant(2 * len * k == start + MLDSA_N) + invariant(array_abs_bound(r, 0, start, layer * MLDSA_Q + MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, layer * MLDSA_Q))) + { + int32_t zeta = mld_zetas[k++]; + mld_ntt_butterfly_block(r, zeta, start, len, layer * MLDSA_Q); + } +} + +MLD_STATIC_TESTABLE void mld_poly_ntt_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +) +{ + unsigned int layer; + int32_t *r; + + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + r = a->coeffs; + + for (layer = 1; layer < 9; layer++) + __loop__( + invariant(1 <= layer && layer <= 9) + invariant(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + ) + { + mld_ntt_layer(r, layer); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_NTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_ntt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_NTT */ + mld_poly_ntt_c(a); +} + +/************************************************* + * Name: mld_fqscale + * + * Description: Scales a field element by mont/256 , i.e., performs Montgomery + * multiplication by mont^2/256. + * Input is expected to have absolute value smaller than + * 256 * MLDSA_Q. + * Output has absolute value smaller than MLD_INTT_BOUND. + * + * Arguments: - int32_t a: Field element to be scaled. + **************************************************/ +static MLD_INLINE int32_t mld_fqscale(int32_t a) +__contract__( + requires(a > -256*MLDSA_Q && a < 256*MLDSA_Q) + ensures(return_value > -MLD_INTT_BOUND && return_value < MLD_INTT_BOUND) +) +{ + /* check-magic: 41978 == pow(2,64-8,MLDSA_Q) */ + const int32_t f = 41978; + /* Bounds: MLD_INTT_BOUND is MLDSA_Q, so the bounds reasoning is just + * a special case of that in mld_fqmul(). */ + return mld_montgomery_reduce((int64_t)a * f); +} + +/* Reference: Embedded into `invntt_tomont()` in the reference implementation + * @[REF] */ +static MLD_INLINE void mld_invntt_layer(int32_t r[MLDSA_N], unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> (layer - 1)) * MLDSA_Q))) +{ + unsigned start, k, len; + len = (unsigned)MLDSA_N >> layer; + k = (1u << layer) - 1; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start <= MLDSA_N && k <= 255) + invariant(2 * len * k + start == 2 * MLDSA_N - 2 * len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + unsigned j; + int32_t zeta = -mld_zetas[k--]; + + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, j, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, (MLDSA_N >> layer) * MLDSA_Q)) + invariant(array_abs_bound(r, start + len, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + int32_t t = r[j]; + r[j] = t + r[j + len]; + r[j + len] = t - r[j + len]; + r[j + len] = mld_fqmul(r[j + len], zeta); + } + } +} + +MLD_STATIC_TESTABLE void mld_poly_invntt_tomont_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +) +{ + unsigned int layer, j; + int32_t *r; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + r = a->coeffs; + for (layer = 8; layer >= 1; layer--) + __loop__( + invariant(layer <= 8) + /* Absolute bounds increase from 1Q before layer 8 */ + /* up to 256Q after layer 1 */ + invariant(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + mld_invntt_layer(r, layer); + } + + /* Coefficient bounds are now at 256Q. We now scale by mont / 256, + * i.e., compute the Montgomery multiplication by mont^2 / 256. + * mont corrects the mont^-1 factor introduced in the basemul. + * 1/256 performs that scaling of the inverse NTT. + * The reduced value is bounded by MLD_INTT_BOUND in absolute + * value.*/ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + invariant(j <= MLDSA_N) + invariant(array_abs_bound(r, 0, j, MLD_INTT_BOUND)) + invariant(array_abs_bound(r, j, MLDSA_N, MLDSA_N * MLDSA_Q)) + ) + { + r[j] = mld_fqscale(r[j]); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); +} + + +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_INTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_intt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_INTT */ + mld_poly_invntt_tomont_c(a); +} + +MLD_STATIC_TESTABLE void mld_poly_pointwise_montgomery_c(mld_poly *c, + const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_abs_bound(c->coeffs, 0, i, MLDSA_Q)) + ) + { + c->coeffs[i] = mld_montgomery_reduce((int64_t)a->coeffs[i] * b->coeffs[i]); + } + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +{ +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + ret = mld_poly_pointwise_montgomery_native(c->coeffs, a->coeffs, b->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + mld_poly_pointwise_montgomery_c(c, a, b); +} + +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, 0, i, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + invariant(array_bound(a1->coeffs, 0, i, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) + ) + { + mld_power2round(&a0->coeffs[i], &a1->coeffs[i], a->coeffs[i]); + } + + mld_assert_bound(a0->coeffs, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +#ifndef MLD_POLY_UNIFORM_NBLOCKS +#define MLD_POLY_UNIFORM_NBLOCKS \ + ((768 + MLD_STREAM128_BLOCKBYTES - 1) / MLD_STREAM128_BLOCKBYTES) +#endif +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +MLD_STATIC_TESTABLE unsigned int mld_rej_uniform_c(int32_t *a, + unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ + unsigned int ctr, pos; + uint32_t t; + mld_assert_bound(a, offset, 0, MLDSA_Q); + + ctr = offset; + pos = 0; + /* pos + 3 cannot overflow due to the assumption + buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) */ + while (ctr < target && pos + 3 <= buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_bound(a, 0, ctr, 0, MLDSA_Q))) + { + t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + a[ctr++] = (int32_t)t; + } + } + + mld_assert_bound(a, ctr, 0, MLDSA_Q); + + return ctr; +} +/************************************************* + * Name: mld_rej_uniform + * + * Description: Sample uniformly random coefficients in [0, MLDSA_Q-1] by + * performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes (must be + * multiple of 3) + * + * Returns number of sampled coefficients. Can be smaller than len if not enough + * random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +static unsigned int mld_rej_uniform(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) + int ret; + mld_assert_bound(a, offset, 0, MLDSA_Q); + if (offset == 0) + { + ret = mld_rej_uniform_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_bound(a, res, 0, MLDSA_Q); + return res; + } + } +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + + return mld_rej_uniform_c(a, target, offset, buf, buflen); +} + +/* Reference: poly_uniform() in the reference implementation @[REF]. + * - Simplified from reference by removing buffer tail handling + * since buflen % 3 = 0 always holds true (MLD_STREAM128_BLOCKBYTES + * = 168). + * - Modified rej_uniform interface to track offset directly. + * - Pass nonce packed in the extended seed array instead of a third + * argument. + * */ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +{ + unsigned int ctr; + unsigned int buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + MLD_ALIGN uint8_t buf[MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES]; + mld_xof128_ctx state; + + mld_xof128_init(&state); + mld_xof128_absorb_once(&state, seed, MLDSA_SEEDBYTES + 2); + mld_xof128_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, 0, buf, buflen); + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(a, sizeof(mld_poly)), object_whole(buf)) + invariant(ctr <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, ctr, 0, MLDSA_Q)) + invariant(state.pos <= SHAKE128_RATE) + ) + { + mld_xof128_squeezeblocks(buf, 1, &state); + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, ctr, buf, buflen); + } + mld_xof128_release(&state); + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof128_x4_ctx state; + unsigned buflen; + + mld_xof128_x4_init(&state); + mld_xof128_x4_absorb(&state, seed, MLDSA_SEEDBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_NBLOCKS. + * This should generate the matrix entries with high probability. + */ + + mld_xof128_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all matrix entries have been generated, squeeze + * one more block a time until we're done. + */ + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, object_whole(buf), + memory_slice(vec0, sizeof(mld_poly)), memory_slice(vec1, sizeof(mld_poly)), + memory_slice(vec2, sizeof(mld_poly)), memory_slice(vec3, sizeof(mld_poly))) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_bound(vec0->coeffs, 0, ctr[0], 0, MLDSA_Q)) + invariant(array_bound(vec1->coeffs, 0, ctr[1], 0, MLDSA_Q)) + invariant(array_bound(vec2->coeffs, 0, ctr[2], 0, MLDSA_Q)) + invariant(array_bound(vec3->coeffs, 0, ctr[3], 0, MLDSA_Q))) + { + mld_xof128_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + mld_xof128_x4_release(&state); + + mld_assert_bound(vec0->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec1->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec2->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec3->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0) & 0xFF); + r[5 * i + 1] = + (uint8_t)(((a->coeffs[4 * i + 0] >> 8) | (a->coeffs[4 * i + 1] << 2)) & + 0xFF); + r[5 * i + 2] = + (uint8_t)(((a->coeffs[4 * i + 1] >> 6) | (a->coeffs[4 * i + 2] << 4)) & + 0xFF); + r[5 * i + 3] = + (uint8_t)(((a->coeffs[4 * i + 2] >> 4) | (a->coeffs[4 * i + 3] << 6)) & + 0xFF); + r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, 0, 1 << 10))) + { + r->coeffs[4 * i + 0] = + ((a[5 * i + 0] >> 0) | ((int32_t)a[5 * i + 1] << 8)) & 0x3FF; + r->coeffs[4 * i + 1] = + ((a[5 * i + 1] >> 2) | ((int32_t)a[5 * i + 2] << 6)) & 0x3FF; + r->coeffs[4 * i + 2] = + ((a[5 * i + 2] >> 4) | ((int32_t)a[5 * i + 3] << 4)) & 0x3FF; + r->coeffs[4 * i + 3] = + ((a[5 * i + 3] >> 6) | ((int32_t)a[5 * i + 4] << 2)) & 0x3FF; + } + + mld_assert_bound(r->coeffs, MLDSA_N, 0, 1 << 10); +} + +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[8]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* Safety: a->coeffs[i] <= (1 << (MLDSA_D - 1) as they are output of + * power2round, hence, these casts are safe. */ + t[0] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 0]); + t[1] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 1]); + t[2] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 2]); + t[3] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 3]); + t[4] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 4]); + t[5] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 5]); + t[6] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 6]); + t[7] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 7]); + + r[13 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[13 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[13 * i + 1] |= (uint8_t)((t[1] << 5) & 0xFF); + r[13 * i + 2] = (uint8_t)((t[1] >> 3) & 0xFF); + r[13 * i + 3] = (uint8_t)((t[1] >> 11) & 0xFF); + r[13 * i + 3] |= (uint8_t)((t[2] << 2) & 0xFF); + r[13 * i + 4] = (uint8_t)((t[2] >> 6) & 0xFF); + r[13 * i + 4] |= (uint8_t)((t[3] << 7) & 0xFF); + r[13 * i + 5] = (uint8_t)((t[3] >> 1) & 0xFF); + r[13 * i + 6] = (uint8_t)((t[3] >> 9) & 0xFF); + r[13 * i + 6] |= (uint8_t)((t[4] << 4) & 0xFF); + r[13 * i + 7] = (uint8_t)((t[4] >> 4) & 0xFF); + r[13 * i + 8] = (uint8_t)((t[4] >> 12) & 0xFF); + r[13 * i + 8] |= (uint8_t)((t[5] << 1) & 0xFF); + r[13 * i + 9] = (uint8_t)((t[5] >> 7) & 0xFF); + r[13 * i + 9] |= (uint8_t)((t[6] << 6) & 0xFF); + r[13 * i + 10] = (uint8_t)((t[6] >> 2) & 0xFF); + r[13 * i + 11] = (uint8_t)((t[6] >> 10) & 0xFF); + r[13 * i + 11] |= (uint8_t)((t[7] << 3) & 0xFF); + r[13 * i + 12] = (uint8_t)((t[7] >> 5) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + { + r->coeffs[8 * i + 0] = a[13 * i + 0]; + r->coeffs[8 * i + 0] |= (int32_t)a[13 * i + 1] << 8; + r->coeffs[8 * i + 0] &= 0x1FFF; + + r->coeffs[8 * i + 1] = a[13 * i + 1] >> 5; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 2] << 3; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 3] << 11; + r->coeffs[8 * i + 1] &= 0x1FFF; + + r->coeffs[8 * i + 2] = a[13 * i + 3] >> 2; + r->coeffs[8 * i + 2] |= (int32_t)a[13 * i + 4] << 6; + r->coeffs[8 * i + 2] &= 0x1FFF; + + r->coeffs[8 * i + 3] = a[13 * i + 4] >> 7; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 5] << 1; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 6] << 9; + r->coeffs[8 * i + 3] &= 0x1FFF; + + r->coeffs[8 * i + 4] = a[13 * i + 6] >> 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 7] << 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 8] << 12; + r->coeffs[8 * i + 4] &= 0x1FFF; + + r->coeffs[8 * i + 5] = a[13 * i + 8] >> 1; + r->coeffs[8 * i + 5] |= (int32_t)a[13 * i + 9] << 7; + r->coeffs[8 * i + 5] &= 0x1FFF; + + r->coeffs[8 * i + 6] = a[13 * i + 9] >> 6; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 10] << 2; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 11] << 10; + r->coeffs[8 * i + 6] &= 0x1FFF; + + r->coeffs[8 * i + 7] = a[13 * i + 11] >> 3; + r->coeffs[8 * i + 7] |= (int32_t)a[13 * i + 12] << 5; + r->coeffs[8 * i + 7] &= 0x1FFF; + + r->coeffs[8 * i + 0] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 7]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +MLD_STATIC_TESTABLE uint32_t mld_poly_chknorm_c(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == array_abs_bound(a->coeffs, 0, i, B)) + ) + { + /* + * Since we know that -MLD_REDUCE32_RANGE_MAX <= a < MLD_REDUCE32_RANGE_MAX, + * and B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX, to check if + * -B < (a mod± MLDSA_Q) < B, it suffices to check if -B < a < B. + * + * We prove this to be true using the following CBMC assertions. + * a ==> b expressed as !a || b to also allow run-time assertion. + */ + mld_assert(a->coeffs[i] < B || a->coeffs[i] - MLDSA_Q <= -B); + mld_assert(a->coeffs[i] > -B || a->coeffs[i] + MLDSA_Q >= B); + + /* Reference: Leaks which coefficient violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + + /* if (abs(a[i]) >= B) */ + t |= mld_ct_cmask_neg_i32(B - 1 - mld_ct_abs_i32(a->coeffs[i])); + } + + return t; +} + +/* Reference: explicitly checks the bound B to be <= (MLDSA_Q - 1) / 8). + * This is unnecessary as it's always a compile-time constant. + * We instead model it as a precondition. + * Checking the bound is performed using a conditional arguing + * that it is okay to leak which coefficient violates the bound (while the + * coefficient itself must remain secret). + * We instead perform everything in constant-time. + * Also it is sufficient to check that it is smaller than + * MLDSA_Q - MLD_REDUCE32_RANGE_MAX > (MLDSA_Q - 1) / 8). + */ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +{ +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) + int ret; + int success; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + /* The native backend returns 0 if all coefficients are within the bound, + * 1 if at least one coefficient exceeds the bound, and + * -1 (MLD_NATIVE_FUNC_FALLBACK) if the platform does not have the + * required capabilities to run the native function. + */ + ret = mld_poly_chknorm_native(a->coeffs, B); + + success = (ret != MLD_NATIVE_FUNC_FALLBACK); + /* Constant-time: It would be fine to leak the return value of chknorm + * entirely (as it is fine to leak if any coefficient exceeded the bound or + * not). However, it is cleaner to perform declassification in sign.c. + * Hence, here we only declassify if the native function returned + * MLD_NATIVE_FUNC_FALLBACK or not (which solely depends on system + * capabilities). + */ + MLD_CT_TESTING_DECLASSIFY(&success, sizeof(int)); + if (success) + { + /* Convert 0 / 1 to 0 / 0xFFFFFFFF here */ + return 0U - (uint32_t)ret; + } +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + return mld_poly_chknorm_c(a, B); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ +MLD_EMPTY_CU(mld_poly) +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_POLY_UNIFORM_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/poly.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/poly.h new file mode 100644 index 0000000000..ff7710438e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/poly.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_H +#define MLD_POLY_H + +#include +#include "cbmc.h" +#include "common.h" +#include "reduce.h" +#include "rounding.h" + +/* Absolute exclusive upper bound for the output of the forward NTT */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) +/* Absolute exclusive upper bound for the output of the inverse NTT*/ +#define MLD_INTT_BOUND MLDSA_Q + +typedef struct +{ + int32_t coeffs[MLDSA_N]; +} MLD_ALIGN mld_poly; + +#define mld_poly_reduce MLD_NAMESPACE(poly_reduce) +/************************************************* + * Name: mld_poly_reduce + * + * Description: Inplace reduction of all coefficients of polynomial to + * representative in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) +); + +#define mld_poly_caddq MLD_NAMESPACE(poly_caddq) +/************************************************* + * Name: mld_poly_caddq + * + * Description: For all coefficients of in/out polynomial add MLDSA_Q if + * coefficient is negative. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_add MLD_NAMESPACE(poly_add) +/************************************************* + * Name: mld_poly_add + * + * Description: Add polynomials. No modular reduction is performed. + * + * Arguments: - r: Pointer to input-output polynomial to be added to. + * - b: Pointer to input polynomial that should be added + * to r. Must be disjoint from r. + **************************************************/ + +/* + * NOTE: The reference implementation uses a 3-argument poly_add. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(forall(k0, 0, MLDSA_N, (int64_t) r->coeffs[k0] + b->coeffs[k0] < MLD_REDUCE32_DOMAIN_MAX)) + requires(forall(k1, 0, MLDSA_N, (int64_t) r->coeffs[k1] + b->coeffs[k1] >= INT32_MIN)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(forall(k2, 0, MLDSA_N, r->coeffs[k2] == old(*r).coeffs[k2] + b->coeffs[k2])) + ensures(forall(k3, 0, MLDSA_N, r->coeffs[k3] < MLD_REDUCE32_DOMAIN_MAX)) + ensures(forall(k4, 0, MLDSA_N, r->coeffs[k4] >= INT32_MIN)) +); + +#define mld_poly_sub MLD_NAMESPACE(poly_sub) +/************************************************* + * Name: mld_poly_sub + * + * Description: Subtract polynomials. No modular reduction is + * performed. + * + * Arguments: - mld_poly *r: Pointer to input-output polynomial. + * - const mld_poly *b: Pointer to input polynomial that should be + * subtracted from r. Must be disjoint from r. + **************************************************/ +/* + * NOTE: The reference implementation uses a 3-argument poly_sub. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_Q)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) +); + +#define mld_poly_shiftl MLD_NAMESPACE(poly_shiftl) +/************************************************* + * Name: mld_poly_shiftl + * + * Description: Multiply polynomial by 2^MLDSA_D without modular reduction. + *Assumes input coefficients to be less than 2^{31-MLDSA_D} in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_ntt MLD_NAMESPACE(poly_ntt) +/************************************************* + * Name: mld_poly_ntt + * + * Description: Inplace forward NTT. Coefficients can grow by + * 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +); + + +#define mld_poly_invntt_tomont MLD_NAMESPACE(poly_invntt_tomont) +/************************************************* + * Name: mld_poly_invntt_tomont + * + * Description: Inplace inverse NTT and multiplication by 2^{32}. + * Input coefficients need to be less than MLDSA_Q in absolute + * value and output coefficients are bounded by + * MLD_INTT_BOUND. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +); + +#define mld_poly_pointwise_montgomery MLD_NAMESPACE(poly_pointwise_montgomery) +/************************************************* + * Name: mld_poly_pointwise_montgomery + * + * Description: Pointwise multiplication of polynomials in NTT domain + * representation and multiplication of resulting polynomial + * by 2^{-32}. + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const mld_poly *a: pointer to first input polynomial + * - const mld_poly *b: pointer to second input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + +#define mld_poly_power2round MLD_NAMESPACE(poly_power2round) +/************************************************* + * Name: mld_poly_power2round + * + * Description: For all coefficients c of the input polynomial, + * compute c0, c1 such that c mod MLDSA_Q = c1*2^MLDSA_D + c0 + * with -2^{MLDSA_D-1} < c0 <= 2^{MLDSA_D-1}. Assumes coefficients + *to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + *c1 + * - mld_poly *a0: pointer to output polynomial with coefficients + *c0 + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +__contract__( + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a0->coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) +); + +#define mld_poly_uniform MLD_NAMESPACE(poly_uniform) +/************************************************* + * Name: mld_poly_uniform + * + * Description: Sample polynomial with uniformly random coefficients + * in [0,MLDSA_Q-1] by performing rejection sampling on the + * output stream of SHAKE128(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_SEEDBYTES and the packed 2-byte nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES + 2)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +#define mld_poly_uniform_4x MLD_NAMESPACE(poly_uniform_4x) +/************************************************* + * Name: mld_poly_uniform_x4 + * + * Description: Generate four polynomials using rejection sampling + * on (pseudo-)uniformly random bytes sampled from a seed. + * + * Arguments: - mld_poly *vec0, *vec1, *vec2, *vec3: + * Pointers to 4 polynomials to be sampled. + * - uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]: + * Pointer consecutive array of seed buffers of size + * MLDSA_SEEDBYTES + 2 each, plus padding for alignment. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +__contract__( + requires(memory_no_alias(vec0, sizeof(mld_poly))) + requires(memory_no_alias(vec1, sizeof(mld_poly))) + requires(memory_no_alias(vec2, sizeof(mld_poly))) + requires(memory_no_alias(vec3, sizeof(mld_poly))) + requires(memory_no_alias(seed, 4 * MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2))) + assigns(memory_slice(vec0, sizeof(mld_poly))) + assigns(memory_slice(vec1, sizeof(mld_poly))) + assigns(memory_slice(vec2, sizeof(mld_poly))) + assigns(memory_slice(vec3, sizeof(mld_poly))) + ensures(array_bound(vec0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec1->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec2->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec3->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +#define mld_polyt1_pack MLD_NAMESPACE(polyt1_pack) +/************************************************* + * Name: mld_polyt1_pack + * + * Description: Bit-pack polynomial t1 with coefficients fitting in 10 bits. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(r, MLDSA_POLYT1_PACKEDBYTES)) +); + +#define mld_polyt1_unpack MLD_NAMESPACE(polyt1_unpack) +/************************************************* + * Name: mld_polyt1_unpack + * + * Description: Unpack polynomial t1 with 10-bit coefficients. + * Output coefficients are standard representatives. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT1_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, 0, 1 << 10)) +); + +#define mld_polyt0_pack MLD_NAMESPACE(polyt0_pack) +/************************************************* + * Name: mld_polyt0_pack + * + * Description: Bit-pack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + * 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) + assigns(memory_slice(r, MLDSA_POLYT0_PACKEDBYTES)) +); + + +#define mld_polyt0_unpack MLD_NAMESPACE(polyt0_unpack) +/************************************************* + * Name: mld_polyt0_unpack + * + * Description: Unpack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + *2^{MLDSA_D-1}]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT0_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) +); + +#define mld_poly_chknorm MLD_NAMESPACE(poly_chknorm) +/************************************************* + * Name: mld_poly_chknorm + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const mld_poly *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if norm is strictly smaller than + * B <= (MLDSA_Q - MLD_REDUCE32_RANGE_MAX) and 0xFFFFFFFF otherwise. + * + * Specification: The definition of this FIPS-204 requires signed canonical + * reduction prior to applying the bounds check. + * However, `-B < (a mod± MLDSA_Q) < B` is equivalent to + * `-B < a < B` under the assumption that + * `B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX` (cf. the assertion in + * the code). Hence, the present spec and implementation are + * correct without reduction. + * + **************************************************/ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +); + +#endif /* !MLD_POLY_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/poly_kl.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/poly_kl.c new file mode 100644 index 0000000000..7a319ca515 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/poly_kl.c @@ -0,0 +1,931 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "ct.h" +#include "debug.h" +#include "poly_kl.h" +#include "rounding.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_rej_eta MLD_ADD_PARAM_SET(mld_rej_eta) +#define mld_rej_eta_c MLD_ADD_PARAM_SET(mld_rej_eta_c) +#define mld_poly_decompose_c MLD_ADD_PARAM_SET(mld_poly_decompose_c) +#define mld_poly_use_hint_c MLD_ADD_PARAM_SET(mld_poly_use_hint_c) +#define mld_polyz_unpack_c MLD_ADD_PARAM_SET(mld_polyz_unpack_c) +/* End of parameter set namespacing */ + + +MLD_STATIC_TESTABLE +void mld_poly_decompose_c(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +) +{ + unsigned int i; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, i, MLDSA_N, 0, MLDSA_Q)) + invariant(array_bound(a1->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + invariant(array_abs_bound(a0->coeffs, 0, i, MLDSA_GAMMA2+1)) + ) + { + mld_decompose(&a0->coeffs[i], &a1->coeffs[i], a0->coeffs[i]); + } + + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +{ +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_88_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_32_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_DECOMPOSE_88 && MLD_CONFIG_PARAMETER_SET == \ + 44) && MLD_USE_NATIVE_POLY_DECOMPOSE_32 && (MLD_CONFIG_PARAMETER_SET \ + == 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_decompose_c(a1, a0); +} + +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(s <= i) + invariant(array_bound(h->coeffs, 0, i, 0, 2)) + ) + { + const unsigned int hint_bit = mld_make_hint(a0->coeffs[i], a1->coeffs[i]); + h->coeffs[i] = (int32_t)hint_bit; + s += hint_bit; + } + + mld_assert(s <= MLDSA_N); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + return s; +} + +MLD_STATIC_TESTABLE void mld_poly_use_hint_c(mld_poly *b, const mld_poly *a, + const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(b->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ) + { + b->coeffs[i] = mld_use_hint(a->coeffs[i], h->coeffs[i]); + } + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +{ +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_88_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_USE_HINT_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_32_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_USE_HINT_88 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLY_USE_HINT_32 && (MLD_CONFIG_PARAMETER_SET == \ + 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_use_hint_c(b, a, h); +} + +/************************************************* + * Name: mld_rej_eta + * + * Description: Sample uniformly random coefficients in [-MLDSA_ETA, MLDSA_ETA] + *by performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes + * + * Returns number of sampled coefficients. Can be smaller than target if not + *enough random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_eta()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +#if MLDSA_ETA == 2 +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 1 +#elif MLDSA_ETA == 4 +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 2 +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + +MLD_STATIC_TESTABLE unsigned int mld_rej_eta_c(int32_t *a, unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ + unsigned int ctr, pos; + int t_valid; + uint32_t t0, t1; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + ctr = offset; + pos = 0; + while (ctr < target && pos < buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_abs_bound(a, 0, ctr, MLDSA_ETA + 1)) + ) + { + t0 = buf[pos] & 0x0F; + t1 = buf[pos++] >> 4; + + /* Constant time: The inputs and outputs to the rejection sampling are + * secret. However, it is fine to leak which coefficients have been + * rejected. For constant-time testing, we declassify the result of + * the comparison. + */ +#if MLDSA_ETA == 2 + t_valid = t0 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 15 */ + { + t0 = t0 - (205 * t0 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t0; + } + t_valid = t1 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) /* t1 < 15 */ + { + t1 = t1 - (205 * t1 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t1; + } +#elif MLDSA_ETA == 4 + t_valid = t0 < 9; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 9 */ + { + a[ctr++] = 4 - (int32_t)t0; + } + t_valid = t1 < 9; /* t1 < 9 */ + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) + { + a[ctr++] = 4 - (int32_t)t1; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + } + + mld_assert_abs_bound(a, ctr, MLDSA_ETA + 1); + + return ctr; +} + +static unsigned int mld_rej_eta(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ +#if MLDSA_ETA == 2 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta2_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#elif MLDSA_ETA == 4 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta4_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#endif /* !(MLDSA_ETA == 2 && MLD_USE_NATIVE_REJ_UNIFORM_ETA2) && MLDSA_ETA == \ + 4 && MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + + return mld_rej_eta_c(a, target, offset, buf, buflen); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_ETA_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof256_x4_ctx state; + unsigned buflen; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = nonce0; + extseed[1][MLDSA_CRHBYTES] = nonce1; + extseed[2][MLDSA_CRHBYTES] = nonce2; + extseed[3][MLDSA_CRHBYTES] = nonce3; + extseed[0][MLDSA_CRHBYTES + 1] = 0; + extseed[1][MLDSA_CRHBYTES + 1] = 0; + extseed[2][MLDSA_CRHBYTES + 1] = 0; + extseed[3][MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(r0, sizeof(mld_poly)), + memory_slice(r1, sizeof(mld_poly)), memory_slice(r2, sizeof(mld_poly)), + memory_slice(r3, sizeof(mld_poly)), object_whole(buf[0]), + object_whole(buf[1]), object_whole(buf[2]), + object_whole(buf[3])) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_abs_bound(r0->coeffs, 0, ctr[0], MLDSA_ETA + 1)) + invariant(array_abs_bound(r1->coeffs, 0, ctr[1], MLDSA_ETA + 1)) + invariant(array_abs_bound(r2->coeffs, 0, ctr[2], MLDSA_ETA + 1)) + invariant(array_abs_bound(r3->coeffs, 0, ctr[3], MLDSA_ETA + 1))) + { + mld_xof256_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + + mld_xof256_x4_release(&state); + + mld_assert_abs_bound(r0->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r1->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r2->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r3->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +{ + /* Temporary buffer for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr; + mld_xof256_ctx state; + unsigned buflen; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = nonce; + extseed[MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr = mld_rej_eta(r->coeffs, MLDSA_N, 0, buf, buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, object_whole(&state), + object_whole(buf), memory_slice(r, sizeof(mld_poly))) + invariant(ctr <= MLDSA_N) + invariant(state.pos <= SHAKE256_RATE) + invariant(array_abs_bound(r->coeffs, 0, ctr, MLDSA_ETA + 1))) + { + mld_xof256_squeezeblocks(buf, 1, &state); + ctr = mld_rej_eta(r->coeffs, MLDSA_N, ctr, buf, buflen); + } + + mld_xof256_release(&state); + + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define MLD_POLY_UNIFORM_GAMMA1_NBLOCKS \ + ((MLDSA_POLYZ_PACKEDBYTES + MLD_STREAM256_BLOCKBYTES - 1) / \ + MLD_STREAM256_BLOCKBYTES) + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + mld_xof256_ctx state; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = (uint8_t)(nonce & 0xFF); + extseed[MLDSA_CRHBYTES + 1] = (uint8_t)(nonce >> 8); + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + mld_polyz_unpack(a, buf); + + mld_xof256_release(&state); + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + mld_xof256_x4_ctx state; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = (uint8_t)(nonce0 & 0xFF); + extseed[1][MLDSA_CRHBYTES] = (uint8_t)(nonce1 & 0xFF); + extseed[2][MLDSA_CRHBYTES] = (uint8_t)(nonce2 & 0xFF); + extseed[3][MLDSA_CRHBYTES] = (uint8_t)(nonce3 & 0xFF); + extseed[0][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce0 >> 8); + extseed[1][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce1 >> 8); + extseed[2][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce2 >> 8); + extseed[3][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce3 >> 8); + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + + mld_polyz_unpack(r0, buf[0]); + mld_polyz_unpack(r1, buf[1]); + mld_polyz_unpack(r2, buf[2]); + mld_polyz_unpack(r3, buf[3]); + mld_xof256_x4_release(&state); + + mld_assert_bound(r0->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r1->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r2->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r3->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +{ + unsigned int i, j, pos; + uint64_t signs; + uint64_t offset; + MLD_ALIGN uint8_t buf[SHAKE256_RATE]; + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, seed, MLDSA_CTILDEBYTES); + mld_shake256_finalize(&state); + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + + /* Convert the first 8 bytes of buf[] into an unsigned 64-bit value. */ + /* Each bit of that dictates the sign of the resulting challenge value */ + signs = 0; + for (i = 0; i < 8; ++i) + __loop__( + assigns(i, signs) + invariant(i <= 8) + ) + { + signs |= (uint64_t)buf[i] << 8 * i; + } + pos = 8; + + mld_memset(c, 0, sizeof(mld_poly)); + + for (i = MLDSA_N - MLDSA_TAU; i < MLDSA_N; ++i) + __loop__( + assigns(i, j, object_whole(buf), state, pos, memory_slice(c, sizeof(mld_poly)), signs) + invariant(i >= MLDSA_N - MLDSA_TAU) + invariant(i <= MLDSA_N) + invariant(pos >= 1) + invariant(pos <= SHAKE256_RATE) + invariant(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) + invariant(state.pos <= SHAKE256_RATE) + ) + { + do + __loop__( + assigns(j, object_whole(buf), state, pos) + invariant(state.pos <= SHAKE256_RATE) + ) + { + if (pos >= SHAKE256_RATE) + { + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + pos = 0; + } + j = buf[pos++]; + } while (j > i); + + c->coeffs[i] = c->coeffs[j]; + + /* Reference: Compute coefficent value here in two steps to */ + /* mixinf unsigned and signed arithmetic with implicit */ + /* conversions, and so that CBMC can keep track of ranges */ + /* to complete type-safety proof here. */ + + /* The least-significant bit of signs tells us if we want -1 or +1 */ + offset = 2 * (signs & 1); + + /* offset has value 0 or 2 here, so (1 - (int32_t) offset) has + * value -1 or +1 */ + c->coeffs[j] = 1 - (int32_t)offset; + + /* Move to the next bit of signs for next time */ + signs >>= 1; + } + + mld_assert_bound(c->coeffs, MLDSA_N, -1, 2); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(&signs, sizeof(signs)); +} + +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint8_t t[8]; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_ETA + 1); + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 1]); + t[2] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 2]); + t[3] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 3]); + t[4] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 4]); + t[5] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 5]); + t[6] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 6]); + t[7] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 7]); + + r[3 * i + 0] = (uint8_t)(((t[0] >> 0) | (t[1] << 3) | (t[2] << 6)) & 0xFF); + r[3 * i + 1] = + (uint8_t)(((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)) & + 0xFF); + r[3 * i + 2] = (uint8_t)(((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)) & 0xFF); + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 1]); + r[i] = (uint8_t)(t[0] | (t[1] << 4)); + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ +} + +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -5, MLDSA_ETA + 1))) + { + r->coeffs[8 * i + 0] = (a[3 * i + 0] >> 0) & 7; + r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 7; + r->coeffs[8 * i + 2] = ((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 7; + r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 7; + r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 7; + r->coeffs[8 * i + 5] = ((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 7; + r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 7; + r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5) & 7; + + r->coeffs[8 * i + 0] = MLDSA_ETA - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = MLDSA_ETA - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = MLDSA_ETA - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = MLDSA_ETA - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = MLDSA_ETA - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = MLDSA_ETA - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = MLDSA_ETA - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = MLDSA_ETA - r->coeffs[8 * i + 7]; + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -11, MLDSA_ETA + 1))) + { + r->coeffs[2 * i + 0] = a[i] & 0x0F; + r->coeffs[2 * i + 1] = a[i] >> 4; + r->coeffs[2 * i + 0] = MLDSA_ETA - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_ETA - r->coeffs[2 * i + 1]; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + + mld_assert_bound(r->coeffs, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + + +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[4]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 1]); + t[2] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 2]); + t[3] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 3]); + + r[9 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[9 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[9 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[9 * i + 2] |= (uint8_t)((t[1] << 2) & 0xFF); + r[9 * i + 3] = (uint8_t)((t[1] >> 6) & 0xFF); + r[9 * i + 4] = (uint8_t)((t[1] >> 14) & 0xFF); + r[9 * i + 4] |= (uint8_t)((t[2] << 4) & 0xFF); + r[9 * i + 5] = (uint8_t)((t[2] >> 4) & 0xFF); + r[9 * i + 6] = (uint8_t)((t[2] >> 12) & 0xFF); + r[9 * i + 6] |= (uint8_t)((t[3] << 6) & 0xFF); + r[9 * i + 7] = (uint8_t)((t[3] >> 2) & 0xFF); + r[9 * i + 8] = (uint8_t)((t[3] >> 10) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 1]); + + r[5 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[5 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[5 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[5 * i + 2] |= (uint8_t)((t[1] << 4) & 0xFF); + r[5 * i + 3] = (uint8_t)((t[1] >> 4) & 0xFF); + r[5 * i + 4] = (uint8_t)((t[1] >> 12) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +MLD_STATIC_TESTABLE void mld_polyz_unpack_c( + mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +) +{ + unsigned int i; +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[4 * i + 0] = a[9 * i + 0]; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 2] << 16; + r->coeffs[4 * i + 0] &= 0x3FFFF; + + r->coeffs[4 * i + 1] = a[9 * i + 2] >> 2; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 3] << 6; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 4] << 14; + r->coeffs[4 * i + 1] &= 0x3FFFF; + + r->coeffs[4 * i + 2] = a[9 * i + 4] >> 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 5] << 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 6] << 12; + r->coeffs[4 * i + 2] &= 0x3FFFF; + + r->coeffs[4 * i + 3] = a[9 * i + 6] >> 6; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 7] << 2; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10; + r->coeffs[4 * i + 3] &= 0x3FFFF; + + r->coeffs[4 * i + 0] = MLDSA_GAMMA1 - r->coeffs[4 * i + 0]; + r->coeffs[4 * i + 1] = MLDSA_GAMMA1 - r->coeffs[4 * i + 1]; + r->coeffs[4 * i + 2] = MLDSA_GAMMA1 - r->coeffs[4 * i + 2]; + r->coeffs[4 * i + 3] = MLDSA_GAMMA1 - r->coeffs[4 * i + 3]; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[2 * i + 0] = a[5 * i + 0]; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 2] << 16; + r->coeffs[2 * i + 0] &= 0xFFFFF; + + r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 3] << 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12; + /* r->coeffs[2*i+1] &= 0xFFFFF; */ /* No effect, since we're anyway at 20 + bits */ + + r->coeffs[2 * i + 0] = MLDSA_GAMMA1 - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_GAMMA1 - r->coeffs[2 * i + 1]; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +{ +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + ret = mld_polyz_unpack_17_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#elif defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + ret = mld_polyz_unpack_19_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYZ_UNPACK_17 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLYZ_UNPACK_19 && (MLD_CONFIG_PARAMETER_SET == 65 \ + || MLD_CONFIG_PARAMETER_SET == 87) */ + + mld_polyz_unpack_c(r, a); +} + +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + + mld_assert_bound(a->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[3 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0]) & 0xFF); + r[3 * i + 0] |= (uint8_t)((a->coeffs[4 * i + 1] << 6) & 0xFF); + r[3 * i + 1] = (uint8_t)((a->coeffs[4 * i + 1] >> 2) & 0xFF); + r[3 * i + 1] |= (uint8_t)((a->coeffs[4 * i + 2] << 4) & 0xFF); + r[3 * i + 2] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) & 0xFF); + r[3 * i + 2] |= (uint8_t)((a->coeffs[4 * i + 3] << 2) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + r[i] = + (uint8_t)((a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_rej_eta +#undef mld_rej_eta_c +#undef mld_poly_decompose_c +#undef mld_poly_use_hint_c +#undef mld_polyz_unpack_c +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_GAMMA1_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/poly_kl.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/poly_kl.h new file mode 100644 index 0000000000..c6aa498358 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/poly_kl.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_KL_H +#define MLD_POLY_KL_H + +#include "cbmc.h" +#include "common.h" +#include "poly.h" + +#define mld_poly_decompose MLD_NAMESPACE_KL(poly_decompose) +/************************************************* + * Name: mld_poly_decompose + * + * Description: For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such c mod MLDSA_Q = c1*ALPHA + + * c0 with -ALPHA/2 < c0 <= ALPHA/2 except + * c1 = (MLDSA_Q-1)/ALPHA where we set + * c1 = 0 and -ALPHA/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + * c1 + * - mld_poly *a0: pointer to input/output polynomial. Output + * polynomial has coefficients c0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +); + + +#define mld_poly_make_hint MLD_NAMESPACE_KL(poly_make_hint) +/************************************************* + * Name: mld_poly_make_hint + * + * Description: Compute hint polynomial. The coefficients of which indicate + * whether the low bits of the corresponding coefficient of + * the input polynomial overflow into the high bits. + * + * Arguments: - mld_poly *h: pointer to output hint polynomial + * - const mld_poly *a0: pointer to low part of input polynomial + * - const mld_poly *a1: pointer to high part of input polynomial + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + assigns(memory_slice(h, sizeof(mld_poly))) + ensures(return_value <= MLDSA_N) + ensures(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) +); + +#define mld_poly_use_hint MLD_NAMESPACE_KL(poly_use_hint) +/************************************************* + * Name: mld_poly_use_hint + * + * Description: Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - mld_poly *b: pointer to output polynomial with corrected high + *bits + * - const mld_poly *a: pointer to input polynomial + * - const mld_poly *h: pointer to input hint polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta_4x MLD_NAMESPACE_KL(poly_uniform_eta_4x) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample four polynomials with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce_i) + * + * Arguments: - mld_poly *r0: pointer to first output polynomial + * - mld_poly *r1: pointer to second output polynomial + * - mld_poly *r2: pointer to third output polynomial + * - mld_poly *r3: pointer to fourth output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce0: first nonce + * - uint8_t nonce1: second nonce + * - uint8_t nonce2: third nonce + * - uint8_t nonce3: fourth nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_abs_bound(r0->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r1->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r2->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r3->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta MLD_NAMESPACE_KL(poly_uniform_eta) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample polynomial with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce: nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1 MLD_NAMESPACE_KL(poly_uniform_gamma1) +/************************************************* + * Name: mld_poly_uniform_gamma1 + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1_4x MLD_NAMESPACE_KL(poly_uniform_gamma1_4x) +/************************************************* + * Name: mld_poly_uniform_gamma1_4x + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_bound(r0->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r1->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r2->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r3->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define mld_poly_challenge MLD_NAMESPACE_KL(poly_challenge) +/************************************************* + * Name: mld_poly_challenge + * + * Description: Implementation of H. Samples polynomial with MLDSA_TAU nonzero + * coefficients in {-1,1} using the output stream of + * SHAKE256(seed). + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const uint8_t mu[]: byte array containing seed of length + * MLDSA_CTILDEBYTES + **************************************************/ +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +__contract__( + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CTILDEBYTES)) + assigns(memory_slice(c, sizeof(mld_poly))) + /* All coefficients of c are -1, 0 or +1 */ + ensures(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) +); + +#define mld_polyeta_pack MLD_NAMESPACE_KL(polyeta_pack) +/************************************************* + * Name: mld_polyeta_pack + * + * Description: Bit-pack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYETA_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + assigns(memory_slice(r, MLDSA_POLYETA_PACKEDBYTES)) +); + +/* + * polyeta_unpack produces coefficients in [-MLDSA_ETA,MLDSA_ETA] for + * well-formed inputs (i.e., those produced by polyeta_pack). + * However, when passed an arbitrary byte array, it may produce smaller values, + * i.e, values in [MLD_POLYETA_UNPACK_LOWER_BOUND,MLDSA_ETA] + * Even though this should never happen, we use use the bound for arbitrary + * inputs in the CBMC proofs. + */ +#if MLDSA_ETA == 2 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-5) +#elif MLDSA_ETA == 4 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-11) +#else +#error "Invalid value of MLDSA_ETA" +#endif + +#define mld_polyeta_unpack MLD_NAMESPACE_KL(polyeta_unpack) +/************************************************* + * Name: mld_polyeta_unpack + * + * Description: Unpack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYETA_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)) +); + +#define mld_polyz_pack MLD_NAMESPACE_KL(polyz_pack) +/************************************************* + * Name: mld_polyz_pack + * + * Description: Bit-pack polynomial with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYZ_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(r, MLDSA_POLYZ_PACKEDBYTES)) +); + + +#define mld_polyz_unpack MLD_NAMESPACE_KL(polyz_unpack) +/************************************************* + * Name: mld_polyz_unpack + * + * Description: Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); + +#define mld_polyw1_pack MLD_NAMESPACE_KL(polyw1_pack) +/************************************************* + * Name: mld_polyw1_pack + * + * Description: Bit-pack polynomial w1 with coefficients in [0,15] or [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES)) +); + +#endif /* !MLD_POLY_KL_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/polyvec.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/polyvec.c new file mode 100644 index 0000000000..5c3a08ab32 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/polyvec.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include +#include + +#include "common.h" +#include "debug.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" + +/* This namespacing is not done at the top to avoid a naming conflict + * with native backends, which are currently not yet namespaced. */ +#define mld_polymat_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polymat_permute_bitrev_to_custom) +#define mld_polyvecl_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polyvecl_permute_bitrev_to_custom) +#define mld_polyvecl_pointwise_acc_montgomery_c \ + MLD_ADD_PARAM_SET(mld_polyvecl_pointwise_acc_montgomery_c) + +#if !defined(MLD_CONFIG_REDUCE_RAM) +/* Helper function to ensure that the polynomial entries in the output + * of mld_polyvec_matrix_expand use the standard (bitreversed) ordering + * of coefficients. + * No-op unless a native backend with a custom ordering is used. + */ + +static void mld_polyvecl_permute_bitrev_to_custom(mld_polyvecl *v) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +{ +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + unsigned i; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_permute_bitrev_to_custom(v->vec[i].coeffs); + } +#else /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + /* Nothing to do */ + (void)v; +#endif /* !MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ +} + +static void mld_polymat_permute_bitrev_to_custom(mld_polymat *mat) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; i++) + __loop__( + assigns(i, memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))) + { + mld_polyvecl_permute_bitrev_to_custom(&mat->vec[i]); + } +} +#endif /* !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + unsigned int i; + MLD_ALIGN uint8_t seed_ext[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + mld_memcpy(seed_ext, mat->rho, MLDSA_SEEDBYTES); + + /* Generate row on-demand */ + for (i = 0; i < MLDSA_L; i++) + { + uint8_t x = (uint8_t)row; + uint8_t y = (uint8_t)i; + + seed_ext[MLDSA_SEEDBYTES + 0] = y; + seed_ext[MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(&mat->row_buffer.vec[i], seed_ext); + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + mld_poly_permute_bitrev_to_custom(mat->row_buffer.vec[i].coeffs); +#endif + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); + + return &mat->row_buffer; +#else /* MLD_CONFIG_REDUCE_RAM */ + return &mat->vec[row]; +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + /* In REDUCE_RAM mode, just copy the seed for later on-demand generation */ + mld_memcpy(mat->rho, rho, MLDSA_SEEDBYTES); +#else + unsigned int i, j; + /* + * We generate four separate seed arrays rather than a single one to work + * around limitations in CBMC function contracts dealing with disjoint slices + * of the same parent object. + */ + + MLD_ALIGN uint8_t seed_ext[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + mld_memcpy(seed_ext[j], rho, MLDSA_SEEDBYTES); + } + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + /* Sample 4 matrix entries a time. */ + for (i = 0; i < (MLDSA_K * MLDSA_L / 4) * 4; i += 4) + __loop__( + assigns(i, j, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= (MLDSA_K * MLDSA_L / 4) * 4 && i % 4 == 0) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + uint8_t x = (uint8_t)((i + j) / MLDSA_L); + uint8_t y = (uint8_t)((i + j) % MLDSA_L); + + seed_ext[j][MLDSA_SEEDBYTES + 0] = y; + seed_ext[j][MLDSA_SEEDBYTES + 1] = x; + } + + mld_poly_uniform_4x(&mat->vec[i / MLDSA_L].vec[i % MLDSA_L], + &mat->vec[(i + 1) / MLDSA_L].vec[(i + 1) % MLDSA_L], + &mat->vec[(i + 2) / MLDSA_L].vec[(i + 2) % MLDSA_L], + &mat->vec[(i + 3) / MLDSA_L].vec[(i + 3) % MLDSA_L], + seed_ext); + } +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + i = 0; +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + /* Entries omitted by the batch-sampling are sampled individually. */ + while (i < MLDSA_K * MLDSA_L) + __loop__( + assigns(i, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K * MLDSA_L) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + uint8_t x = (uint8_t)(i / MLDSA_L); + uint8_t y = (uint8_t)(i % MLDSA_L); + mld_poly *this_poly = &mat->vec[i / MLDSA_L].vec[i % MLDSA_L]; + + seed_ext[0][MLDSA_SEEDBYTES + 0] = y; + seed_ext[0][MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(this_poly, seed_ext[0]); + i++; + } + + mld_polymat_permute_bitrev_to_custom(mat); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(t, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + const mld_polyvecl *row = mld_polymat_get_row(mat, i); + mld_polyvecl_pointwise_acc_montgomery(&t->vec[i], row, v); + } + + mld_assert_abs_bound_2d(t->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_L **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; +#endif + + /* Safety: nonce is at most ((UINT16_MAX - MLDSA_L) / MLDSA_L), and, hence, + * this cast is safe. See MLD_NONCE_UB comment in sign.c. */ + nonce = (uint16_t)(MLDSA_L * nonce); + /* Now, nonce <= UINT16_MAX - (MLDSA_L - 1), so the casts below are safe. */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_gamma1(&v->vec[i], seed, (uint16_t)(nonce + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLDSA_L == 4 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); +#elif MLDSA_L == 5 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); + mld_poly_uniform_gamma1(&v->vec[4], seed, (uint16_t)(nonce + 4)); +#elif MLDSA_L == 7 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], + &v->vec[3 /* irrelevant */], seed, nonce, + (uint16_t)(nonce + 1), (uint16_t)(nonce + 2), + 0xFF /* irrelevant */); + mld_poly_uniform_gamma1_4x(&v->vec[3], &v->vec[4], &v->vec[5], &v->vec[6], + seed, (uint16_t)(nonce + 3), (uint16_t)(nonce + 4), + (uint16_t)(nonce + 5), (uint16_t)(nonce + 6)); +#endif /* MLDSA_L == 7 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(k0, i, MLDSA_L, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_STATIC_TESTABLE void mld_polyvecl_pointwise_acc_montgomery_c( + mld_poly *w, const mld_polyvecl *u, const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i, j; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + for (i = 0; i < MLDSA_N; i++) + __loop__( + assigns(i, j, memory_slice(w, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_abs_bound(w->coeffs, 0, i, MLDSA_Q)) + ) + { + int64_t t = 0; + int32_t r; + for (j = 0; j < MLDSA_L; j++) + __loop__( + assigns(j, t) + invariant(j <= MLDSA_L) + invariant(t >= -(int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + invariant(t <= (int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + ) + { + t += (int64_t)u->vec[j].coeffs[i] * v->vec[j].coeffs[i]; + } + + r = mld_montgomery_reduce(t); + w->coeffs[i] = r; + } + + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +{ +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) && \ + MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l4_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) && \ + MLD_CONFIG_PARAMETER_SET == 65 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l5_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) && \ + MLD_CONFIG_PARAMETER_SET == 87 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l7_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 && \ + MLD_CONFIG_PARAMETER_SET == 44) && \ + !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 && \ + MLD_CONFIG_PARAMETER_SET == 65) && \ + MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 && \ + MLD_CONFIG_PARAMETER_SET == 87 */ + /* The first input is bounded by [0, Q-1] inclusive + * The second input is bounded by [-9Q+1, 9Q-1] inclusive . Hence, we can + * safely accumulate in 64-bits without intermediate reductions as + * MLDSA_L * (MLD_NTT_BOUND-1) * (Q-1) < INT64_MAX + * + * The worst case is ML-DSA-87: 7 * (9Q-1) * (Q-1) < 2**52 + * (and likewise for negative values) + */ + mld_polyvecl_pointwise_acc_montgomery_c(w, u, v); +} + +MLD_INTERNAL_API +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + invariant(i <= MLDSA_L) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + return t; +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_K **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k2, 0, i, + array_bound(v->vec[k2].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ) + { + mld_poly_reduce(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_caddq(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, + forall(k1, 0, MLDSA_N, u->vec[k0].coeffs[k1] == loop_entry(*u).vec[k0].coeffs[k1]))) + invariant(forall(k6, 0, i, array_bound(u->vec[k6].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + ) + { + mld_poly_add(&u->vec[i], &v->vec[i]); + } + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(u->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, u->vec[k1].coeffs[n1] == loop_entry(*u).vec[k1].coeffs[n1])))) + { + mld_poly_sub(&u->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, v->vec[k1].coeffs[n1] == loop_entry(*v).vec[k1].coeffs[n1]))) + ) + { + mld_poly_shiftl(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))) + { + mld_poly_invntt_tomont(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_INTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, array_abs_bound(r->vec[k2].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + mld_poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]); + } + mld_assert_abs_bound_2d(r->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + + return t; +} + +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + invariant(forall(k2, 0, i, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) + ) + { + mld_poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +{ + unsigned int i; + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + invariant(forall(k2, 0, i, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) + invariant(forall(k3, i, MLDSA_K, + array_bound(v0->vec[k3].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + ) + { + mld_poly_decompose(&v1->vec[i], &v0->vec[i]); + } + + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + mld_assert_abs_bound_2d(v0->vec, MLDSA_K, MLDSA_N, MLDSA_GAMMA2 + 1); +} + +MLD_INTERNAL_API +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, s, memory_slice(h, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(s <= i * MLDSA_N) + invariant(forall(k1, 0, i, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + s += mld_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]); + } + + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + return s; +} + +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *u, + const mld_polyveck *h) +{ + unsigned int i; + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(w, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)))) + ) + { + mld_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]); + } + + mld_assert_bound_2d(w->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +{ + unsigned int i; + mld_assert_bound_2d(w1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyw1_pack(&r[i * MLDSA_POLYW1_PACKEDBYTES], &w1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt0_pack(&r[i * MLDSA_POLYT0_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyz_unpack(&z->vec[i], r + i * MLDSA_POLYZ_PACKEDBYTES); + } + + mld_assert_bound_2d(z->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt0_unpack(&p->vec[i], r + i * MLDSA_POLYT0_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_polymat_permute_bitrev_to_custom +#undef mld_polyvecl_permute_bitrev_to_custom +#undef mld_polyvecl_pointwise_acc_montgomery_c diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/polyvec.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/polyvec.h new file mode 100644 index 0000000000..d21abc02ff --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/polyvec.h @@ -0,0 +1,725 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLYVEC_H +#define MLD_POLYVEC_H + +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "poly_kl.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_polyvecl MLD_ADD_PARAM_SET(mld_polyvecl) +#define mld_polyveck MLD_ADD_PARAM_SET(mld_polyveck) +#define mld_polymat MLD_ADD_PARAM_SET(mld_polymat) +/* End of parameter set namespacing */ + +/* Vectors of polynomials of length MLDSA_L */ +typedef struct +{ + mld_poly vec[MLDSA_L]; +} mld_polyvecl; + + +#define mld_polyvecl_uniform_gamma1 MLD_NAMESPACE_KL(polyvecl_uniform_gamma1) +/************************************************* + * Name: mld_polyvecl_uniform_gamma1 + * + * Description: Sample vector of polynomials with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_polyvecl *v: pointer to output vector + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + *************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + requires(nonce <= (UINT16_MAX - MLDSA_L) / MLDSA_L) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyvecl_ntt MLD_NAMESPACE_KL(polyvecl_ntt) +/************************************************* + * Name: mld_polyvecl_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_L. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyvecl *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k0, 0, MLDSA_L, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyvecl_pointwise_acc_montgomery \ + MLD_NAMESPACE_KL(polyvecl_pointwise_acc_montgomery) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery + * + * Description: Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * The first input "u" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * + * Arguments: - mld_poly *w: output polynomial + * - const mld_polyvecl *u: pointer to first input vector + * - const mld_polyvecl *v: pointer to second input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + + +#define mld_polyvecl_chknorm MLD_NAMESPACE_KL(polyvecl_chknorm) +/************************************************* + * Name: mld_polyvecl_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_L. + * Assumes input mld_polyvecl to be reduced by polyvecl_reduce(). + * + * Arguments: - const mld_polyvecl *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials is strictly smaller than B <= + * (MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +/* Vectors of polynomials of length MLDSA_K */ +typedef struct +{ + mld_poly vec[MLDSA_K]; +} mld_polyveck; + +/* Matrix of polynomials (K x L) */ +typedef struct +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + mld_polyvecl row_buffer; + uint8_t rho[MLDSA_SEEDBYTES]; +#else + mld_polyvecl vec[MLDSA_K]; +#endif +} mld_polymat; + +#define mld_polyveck_reduce MLD_NAMESPACE_KL(polyveck_reduce) +/************************************************* + * Name: polyveck_reduce + * + * Description: Reduce coefficients of polynomials in vector of length MLDSA_K + * to representatives in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) +); + +#define mld_polyveck_caddq MLD_NAMESPACE_KL(polyveck_caddq) +/************************************************* + * Name: mld_polyveck_caddq + * + * Description: For all coefficients of polynomials in vector of length MLDSA_K + * add MLDSA_Q if coefficient is negative. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_add MLD_NAMESPACE_KL(polyveck_add) +/************************************************* + * Name: mld_polyveck_add + * + * Description: Add vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to input-output vector of polynomials + * to be added to + * - const mld_polyveck *v: pointer to second input vector of + * polynomials + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(p0, 0, MLDSA_K, array_abs_bound(u->vec[p0].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) + requires(forall(p1, 0, MLDSA_K, + array_bound(v->vec[p1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(q2, 0, MLDSA_K, + array_bound(u->vec[q2].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_sub MLD_NAMESPACE_KL(polyveck_sub) +/************************************************* + * Name: mld_polyveck_sub + * + * Description: Subtract vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to first input vector + * - const mld_polyveck *v: pointer to second input vector to be + * subtracted from first input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(u->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_shiftl MLD_NAMESPACE_KL(polyveck_shiftl) +/************************************************* + * Name: mld_polyveck_shiftl + * + * Description: Multiply vector of polynomials of Length MLDSA_K by 2^MLDSA_D + *without modular reduction. Assumes input coefficients to be less than + *2^{31-MLDSA_D}. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_ntt MLD_NAMESPACE_KL(polyveck_ntt) +/************************************************* + * Name: mld_polyveck_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_K. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyveck_invntt_tomont MLD_NAMESPACE_KL(polyveck_invntt_tomont) +/************************************************* + * Name: mld_polyveck_invntt_tomont + * + * Description: Inverse NTT and multiplication by 2^{32} of polynomials + * in vector of length MLDSA_K. + * Input coefficients need to be less than MLDSA_Q, and + * Output coefficients are bounded by MLD_INTT_BOUND. + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) +); + +#define mld_polyveck_pointwise_poly_montgomery \ + MLD_NAMESPACE_KL(polyveck_pointwise_poly_montgomery) +/************************************************* + * Name: mld_polyveck_pointwise_poly_montgomery + * + * Description: Pointwise multiplication of a polynomial vector of length + * MLDSA_K by a single polynomial in NTT domain and multiplication + * of the resulting polynomial vector by 2^{-32}. + * + * Arguments: - mld_polyveck *r: pointer to output vector + * - mld_poly *a: pointer to input polynomial + * - mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(r, sizeof(mld_polyveck))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(r, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(r->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#define mld_polyveck_chknorm MLD_NAMESPACE_KL(polyveck_chknorm) +/************************************************* + * Name: mld_polyveck_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_K. + * Assumes input mld_polyveck to be reduced by polyveck_reduce(). + * + * Arguments: - const mld_polyveck *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials are strictly smaller than B <= + *(MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, + -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +#define mld_polyveck_power2round MLD_NAMESPACE_KL(polyveck_power2round) +/************************************************* + * Name: mld_polyveck_power2round + * + * Description: For all coefficients a of polynomials in vector of length + *MLDSA_K, compute a0, a1 such that a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with + *-2^{MLDSA_D-1} < a0 <= 2^{MLDSA_D-1}. Assumes coefficients to be standard + *representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to output vector of polynomials with + * coefficients a0 + * - const mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) +); + +#define mld_polyveck_decompose MLD_NAMESPACE_KL(polyveck_decompose) +/************************************************* + * Name: mld_polyveck_decompose + * + * Description: For all coefficients a of polynomials in vector of length + * MLDSA_K, compute high and low bits a0, a1 such a mod^+ MLDSA_Q = a1*ALPHA + * + a0 with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (MLDSA_Q-1)/ALPHA where we set + * a1 = 0 and -ALPHA/2 <= a0 = a mod MLDSA_Q - MLDSA_Q < 0. Assumes coefficients + * to be standard representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to input/output vector of + * polynomials with. Output polynomial has + * coefficients a0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v0->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + ensures(forall(k2, 0, MLDSA_K, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) +); + +#define mld_polyveck_make_hint MLD_NAMESPACE_KL(polyveck_make_hint) +/************************************************* + * Name: mld_polyveck_make_hint + * + * Description: Compute hint vector. + * + * Arguments: - mld_polyveck *h: pointer to output vector + * - const mld_polyveck *v0: pointer to low part of input vector + * - const mld_polyveck *v1: pointer to high part of input vector + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(return_value <= MLDSA_N * MLDSA_K) + ensures(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) +); + +#define mld_polyveck_use_hint MLD_NAMESPACE_KL(polyveck_use_hint) +/************************************************* + * Name: mld_polyveck_use_hint + * + * Description: Use hint vector to correct the high bits of input vector. + * + * Arguments: - mld_polyveck *w: pointer to output vector of polynomials with + * corrected high bits + * - const mld_polyveck *u: pointer to input vector + * - const mld_polyveck *h: pointer to input hint vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *v, + const mld_polyveck *h) +__contract__( + requires(memory_no_alias(w, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + assigns(memory_slice(w, sizeof(mld_polyveck))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) +); + +#define mld_polyveck_pack_w1 MLD_NAMESPACE_KL(polyveck_pack_w1) +/************************************************* + * Name: mld_polyveck_pack_w1 + * + * Description: Bit-pack polynomial vector w1 with coefficients in [0,15] or + * [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_K* MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_polyveck *a: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(w1, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(w1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) +); + +#define mld_polyveck_pack_eta MLD_NAMESPACE_KL(polyveck_pack_eta) +/************************************************* + * Name: mld_polyveck_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients + * in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyvecl_pack_eta MLD_NAMESPACE_KL(polyvecl_pack_eta) +/************************************************* + * Name: mld_polyvecl_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_L * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyveck_pack_t0 MLD_NAMESPACE_KL(polyveck_pack_t0) +/************************************************* + * Name: mld_polyveck_pack_t0 + * + * Description: Bit-pack polynomial vector to with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(p->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) +); + +#define mld_polyvecl_unpack_eta MLD_NAMESPACE_KL(polyvecl_unpack_eta) +/************************************************* + * Name: mld_polyvecl_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyvecl *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + assigns(memory_slice(p, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyvecl_unpack_z MLD_NAMESPACE_KL(polyvecl_unpack_z) +/************************************************* + * Name: mld_polyvecl_unpack_z + * + * Description: Unpack polynomial vector with coefficients in + * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_polyvecl *z: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(z->vec[k1].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyveck_unpack_eta MLD_NAMESPACE_KL(polyveck_unpack_eta) +/************************************************* + * Name: mld_polyveck_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyveck_unpack_t0 MLD_NAMESPACE_KL(polyveck_unpack_t0) +/************************************************* + * Name: mld_polyveck_unpack_t0 + * + * Description: Unpack polynomial vector with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) +); + +#define mld_polymat_get_row MLD_NAMESPACE_KL(polymat_get_row) +/************************************************* + * Name: mld_polymat_get_row + * + * Description: Retrieve a pointer to a specific row of the matrix. + * In MLD_CONFIG_REDUCE_RAM mode, generates the row on-demand. + * + * Arguments: - mld_polymat *mat: pointer to matrix + * - unsigned int row: row index (must be < MLDSA_K) + * + * Returns pointer to the row (mld_polyvecl) + **************************************************/ +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row); + +#define mld_polyvec_matrix_expand MLD_NAMESPACE_KL(polyvec_matrix_expand) +/************************************************* + * Name: mld_polyvec_matrix_expand + * + * Description: Implementation of ExpandA. Generates matrix A with uniformly + * random coefficients a_{i,j} by performing rejection + * sampling on the output stream of SHAKE128(rho|j|i) + * + * Arguments: - mld_polymat *mat: pointer to output matrix + * - const uint8_t rho[]: byte array containing seed rho + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +__contract__( + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +); + + + +#define mld_polyvec_matrix_pointwise_montgomery \ + MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery) +/************************************************* + * Name: mld_polyvec_matrix_pointwise_montgomery + * + * Description: Compute matrix-vector multiplication in NTT domain with + * pointwise multiplication and multiplication by 2^{-32}. + * Input matrix and vector must be in NTT domain representation. + * + * The first input "mat" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * Note: In MLD_CONFIG_REDUCE_RAM mode, mat cannot be const + * as rows are generated on-demand. + * + * Arguments: - mld_polyveck *t: pointer to output vector t + * - mld_polymat *mat: pointer to input matrix + * - const mld_polyvecl *v: pointer to input vector v + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(t, sizeof(mld_polyveck))) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(t, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#endif /* !MLD_POLYVEC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/randombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/randombytes.h new file mode 100644 index 0000000000..da55772419 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/randombytes.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_RANDOMBYTES_H +#define MLD_RANDOMBYTES_H + +#include +#include + +#include "cbmc.h" +#include "common.h" + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +#if !defined(MLD_CONFIG_CUSTOM_RANDOMBYTES) +MLD_MUST_CHECK_RETURN_VALUE +int randombytes(uint8_t *out, size_t outlen); +static MLD_INLINE int mld_randombytes(uint8_t *out, size_t outlen) +__contract__( + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) { return randombytes(out, outlen); } +#endif /* !MLD_CONFIG_CUSTOM_RANDOMBYTES */ +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ +#endif /* !MLD_RANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/reduce.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/reduce.h new file mode 100644 index 0000000000..413cf1829e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/reduce.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_REDUCE_H +#define MLD_REDUCE_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* check-magic: -4186625 == pow(2,32,MLDSA_Q) */ +#define MLD_MONT -4186625 + +/* Upper bound for domain of mld_reduce32() */ +#define MLD_REDUCE32_DOMAIN_MAX (INT32_MAX - (1 << 22)) + +/* Absolute bound for range of mld_reduce32() */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define MLD_REDUCE32_RANGE_MAX 6283009 + +/************************************************* + * Name: mld_montgomery_reduce + * + * Description: Generic Montgomery reduction; given a 64-bit integer a, computes + * 32-bit integer congruent to a * R^-1 mod q, where R=2^32 + * + * Arguments: - int64_t a: input integer to be reduced, of absolute value + * smaller or equal to INT64_MAX - 2^31 * MLDSA_Q. + * + * Returns: Integer congruent to a * R^-1 modulo q, with absolute value + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * In particular, if |a| < 2^31 * MLDSA_Q, the absolute value + * of the return value is < MLDSA_Q. + **************************************************/ +static MLD_INLINE int32_t mld_montgomery_reduce(int64_t a) +__contract__( + /* We don't attempt to express an input-dependent output bound + * as the post-condition here, as all call-sites satisfy the + * absolute input bound 2^31 * MLDSA_Q and higher-level + * reasoning can be conducted using |return_value| < MLDSA_Q. */ + requires(a > -(((int64_t)1 << 31) * MLDSA_Q) && + a < (((int64_t)1 << 31) * MLDSA_Q)) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* check-magic: 58728449 == unsigned_mod(pow(MLDSA_Q, -1, 2^32), 2^32) */ + const uint64_t QINV = 58728449; + + /* Compute a*q^{-1} mod 2^32 in unsigned representatives */ + const uint32_t a_reduced = mld_cast_int64_to_uint32(a); + const uint32_t a_inverted = (a_reduced * QINV) & UINT32_MAX; + + /* Lift to signed canonical representative mod 2^32. */ + const int32_t t = mld_cast_uint32_to_int32(a_inverted); + + int64_t r; + + mld_assert(a < +(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)) && + a > -(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q))); + + r = a - (int64_t)t * MLDSA_Q; + + /* + * PORTABILITY: Right-shift on a signed integer is, strictly-speaking, + * implementation-defined for negative left argument. Here, + * we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5)) + */ + r = r >> 32; + + /* Bounds: + * + * By construction of the Montgomery multiplication, by the time we + * compute r >> 32, r is divisible by 2^32, and hence + * + * |r >> 32| = |r| / 2^32 + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * (In general, we would only have |x >> n| <= ceil(|x| / 2^n)). + * + * In particular, if |a| < 2^31 * MLDSA_Q, then |return_value| < MLDSA_Q. + */ + return (int32_t)r; +} + +/************************************************* + * Name: mld_reduce32 + * + * Description: For finite field element a with a <= 2^{31} - 2^{22} - 1, + * compute r \equiv a (mod MLDSA_Q) such that + * -MLD_REDUCE32_RANGE_MAX <= r < MLD_REDUCE32_RANGE_MAX. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_reduce32(int32_t a) +__contract__( + requires(a <= MLD_REDUCE32_DOMAIN_MAX) + ensures(return_value >= -MLD_REDUCE32_RANGE_MAX) + ensures(return_value < MLD_REDUCE32_RANGE_MAX) +) +{ + int32_t t; + + t = (a + (1 << 22)) >> 23; + t = a - t * MLDSA_Q; + mld_assert((t - a) % MLDSA_Q == 0); + return t; +} + +/************************************************* + * Name: mld_caddq + * + * Description: Add MLDSA_Q if input coefficient is negative. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_caddq(int32_t a) +__contract__( + requires(a > -MLDSA_Q) + requires(a < MLDSA_Q) + ensures(return_value >= 0) + ensures(return_value < MLDSA_Q) + ensures(return_value == (a >= 0) ? a : (a + MLDSA_Q)) +) +{ + return mld_ct_sel_int32(a + MLDSA_Q, a, mld_ct_cmask_neg_i32(a)); +} + + +#endif /* !MLD_REDUCE_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/rounding.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/rounding.h new file mode 100644 index 0000000000..a83562b0f1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/rounding.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_ROUNDING_H +#define MLD_ROUNDING_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_power2round MLD_ADD_PARAM_SET(mld_power2round) +#define mld_decompose MLD_ADD_PARAM_SET(mld_decompose) +#define mld_make_hint MLD_ADD_PARAM_SET(mld_make_hint) +#define mld_use_hint MLD_ADD_PARAM_SET(mld_use_hint) +/* End of parameter set namespacing */ + +#define MLD_2_POW_D (1 << MLDSA_D) + +/************************************************* + * Name: mld_power2round + * + * Description: For finite field element a, compute a0, a1 such that + * a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with -2^{MLDSA_D-1} < a0 <= + * 2^{MLDSA_D-1}. Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: In the reference implementation, a1 is passed as a + * return value instead. + **************************************************/ +static MLD_INLINE void mld_power2round(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + ensures(*a0 > -(MLD_2_POW_D/2) && *a0 <= (MLD_2_POW_D/2)) + ensures(*a1 >= 0 && *a1 <= (MLDSA_Q - 1) / MLD_2_POW_D) + ensures((*a1 * MLD_2_POW_D + *a0 - a) % MLDSA_Q == 0) +) +{ + *a1 = (a + (1 << (MLDSA_D - 1)) - 1) >> MLDSA_D; + *a0 = a - (*a1 << MLDSA_D); +} + +/************************************************* + * Name: mld_decompose + * + * Description: For finite field element a, compute high and low bits a0, a1 + * such that a mod^+ MLDSA_Q = a1* 2 * MLDSA_GAMMA2 + a0 with + * -MLDSA_GAMMA2 < a0 <= MLDSA_GAMMA2 except + * if a1 = (MLDSA_Q-1)/(MLDSA_GAMMA2*2) where we set a1 = 0 and + * -MLDSA_GAMMA2 <= a0 = a mod^+ MLDSA_Q - MLDSA_Q < 0. + * Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: a1 is passed as a return value instead + **************************************************/ +static MLD_INLINE void mld_decompose(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + /* a0 = -MLDSA_GAMMA2 can only occur when (q-1) = a - (a mod MLDSA_GAMMA2), + * then a1=1; and a0 = a - (a mod MLDSA_GAMMA2) - 1 (@[FIPS204, Algorithm 36 (Decompose)]) */ + ensures(*a0 >= -MLDSA_GAMMA2 && *a0 <= MLDSA_GAMMA2) + ensures(*a1 >= 0 && *a1 < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) + ensures((*a1 * 2 * MLDSA_GAMMA2 + *a0 - a) % MLDSA_Q == 0) +) +{ + /* + * The goal is to compute f1 = round-(f / (2*GAMMA2)), which can be computed + * alternatively as round-(f / (128B)) = round-(ceil(f / 128) / B) where + * B = 2*GAMMA2 / 128. Here round-() denotes "round half down". + * + * The equality round-(f / (128B)) = round-(ceil(f / 128) / B) can deduced + * as follows. Since changing f to align-up(f, 128) can move f onto but not + * across a rounding boundary for division by 128*B (note that we need B to be + * even for this to work), and round- rounds down on the boundary, we have + * + * round-(f / (128B)) = round-(align-up(f, 128) / (128B)) + * = round-((align-up(f, 128) / 128) / B) + * = round-(ceil(f / 128) / B). + */ + *a1 = (a + 127) >> 7; + /* We know a >= 0 and a < MLDSA_Q, so... */ + /* check-magic: 65472 == round((MLDSA_Q-1)/128) */ + mld_assert(*a1 >= 0 && *a1 <= 65472); + +#if MLD_CONFIG_PARAMETER_SET == 44 + /* check-magic: 1488 == 2 * intdiv(intdiv(MLDSA_Q - 1, 88), 128) */ + /* check-magic: 11275 == floor(2**24 / 1488) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + */ + *a1 = (*a1 * 11275 + (1 << 23)) >> 24; + mld_assert(*a1 >= 0 && *a1 <= 44); + + *a1 = mld_ct_sel_int32(0, *a1, mld_ct_cmask_neg_i32(43 - *a1)); + mld_assert(*a1 >= 0 && *a1 <= 43); +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + /* check-magic: 4092 == 2 * intdiv(intdiv(MLDSA_Q - 1, 32), 128) */ + /* check-magic: 1025 == floor(2**22 / 4092) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + */ + *a1 = (*a1 * 1025 + (1 << 21)) >> 22; + mld_assert(*a1 >= 0 && *a1 <= 16); + + *a1 &= 15; + mld_assert(*a1 >= 0 && *a1 <= 15); + +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + + *a0 = a - *a1 * 2 * MLDSA_GAMMA2; + *a0 = mld_ct_sel_int32(*a0 - MLDSA_Q, *a0, + mld_ct_cmask_neg_i32((MLDSA_Q - 1) / 2 - *a0)); +} + +/************************************************* + * Name: mld_make_hint + * + * Description: Compute hint bit indicating whether the low bits of the + * input element overflow into the high bits. + * + * Arguments: - int32_t a0: low bits of input element + * - int32_t a1: high bits of input element + * + * Returns 1 if overflow, 0 otherwise + **************************************************/ +static MLD_INLINE unsigned int mld_make_hint(int32_t a0, int32_t a1) +__contract__( + ensures(return_value >= 0 && return_value <= 1) +) +{ + if (a0 > MLDSA_GAMMA2 || a0 < -MLDSA_GAMMA2 || + (a0 == -MLDSA_GAMMA2 && a1 != 0)) + { + return 1; + } + + return 0; +} + +/************************************************* + * Name: mld_use_hint + * + * Description: Correct high bits according to hint. + * + * Arguments: - int32_t a: input element + * - int32_t hint: hint bit + * + * Returns corrected high bits. + **************************************************/ +static MLD_INLINE int32_t mld_use_hint(int32_t a, int32_t hint) +__contract__( + requires(hint >= 0 && hint <= 1) + requires(a >= 0 && a < MLDSA_Q) + ensures(return_value >= 0 && return_value < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) +) +{ + int32_t a0, a1; + + mld_decompose(&a0, &a1, a); + if (hint == 0) + { + return a1; + } + +#if MLD_CONFIG_PARAMETER_SET == 44 + if (a0 > 0) + { + return (a1 == 43) ? 0 : a1 + 1; + } + else + { + return (a1 == 0) ? 43 : a1 - 1; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + if (a0 > 0) + { + return (a1 + 1) & 15; + } + else + { + return (a1 - 1) & 15; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + + +#endif /* !MLD_ROUNDING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/sign.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/sign.c new file mode 100644 index 0000000000..32bba52d65 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/sign.c @@ -0,0 +1,1508 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [Round3_Spec] + * CRYSTALS-Dilithium Algorithm Specifications and Supporting Documentation + * (Version 3.1) + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf + */ + +#include +#include + +#include "cbmc.h" +#include "ct.h" +#include "debug.h" +#include "packing.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" +#include "randombytes.h" +#include "sign.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_check_pct MLD_ADD_PARAM_SET(mld_check_pct) MLD_CONTEXT_PARAMETERS_2 +#define mld_sample_s1_s2 MLD_ADD_PARAM_SET(mld_sample_s1_s2) +#define mld_validate_hash_length MLD_ADD_PARAM_SET(mld_validate_hash_length) +#define mld_get_hash_oid MLD_ADD_PARAM_SET(mld_get_hash_oid) +#define mld_H MLD_ADD_PARAM_SET(mld_H) +#define mld_compute_pack_z MLD_ADD_PARAM_SET(mld_compute_pack_z) +#define mld_attempt_signature_generation \ + MLD_ADD_PARAM_SET(mld_attempt_signature_generation) MLD_CONTEXT_PARAMETERS_8 +#define mld_compute_t0_t1_tr_from_sk_components \ + MLD_ADD_PARAM_SET(mld_compute_t0_t1_tr_from_sk_components) \ + MLD_CONTEXT_PARAMETERS_7 +/* End of parameter set namespacing */ + + +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + ensures(return_value == 0 + || return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL) +); + +#if defined(MLD_CONFIG_KEYGEN_PCT) +/************************************************* + * @[FIPS140_3_IG] + * (https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf) + * + * TE10.35.02: Pair-wise Consistency Test (PCT) for DSA keypairs + * + * Purpose: Validates that a generated public/private key pair can correctly + * sign and verify data. Test performs signature generation using the private + * key (sk), followed by signature verification using the public key (pk). + * Returns 0 if the signature was successfully verified, non-zero if it cannot. + * + * Note: @[FIPS204] requires that public/private key pairs are to be used only + * for the calculation and/of verification of digital signatures. + **************************************************/ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t message[1] = {0}; + size_t siglen; + int ret; + MLD_ALLOC(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + MLD_ALLOC(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + + if (signature == NULL || pk_test == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Copy public key for testing */ + mld_memcpy(pk_test, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* Sign a test message using the original secret key */ + ret = mld_sign_signature(signature, &siglen, message, sizeof(message), NULL, + 0, sk, context); + if (ret != 0) + { + goto cleanup; + } + +#if defined(MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST) + /* Deliberately break public key for testing purposes */ + if (mld_break_pct()) + { + pk_test[0] = ~pk_test[0]; + } +#endif /* MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST */ + + /* Verify the signature using the (potentially corrupted) public key */ + ret = mld_sign_verify(signature, siglen, message, sizeof(message), NULL, 0, + pk_test, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + MLD_FREE(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + + return ret; +} +#else /* MLD_CONFIG_KEYGEN_PCT */ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + /* Skip PCT */ + ((void)pk); + ((void)sk); +#if defined(MLD_CONFIG_CONTEXT_PARAMETER) + ((void)context); +#endif + return 0; +} +#endif /* !MLD_CONFIG_KEYGEN_PCT */ + +static void mld_sample_s1_s2(mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t seed[MLDSA_CRHBYTES]) +__contract__( + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(object_whole(s1), object_whole(s2)) + ensures(forall(l0, 0, MLDSA_L, array_abs_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + ensures(forall(k0, 0, MLDSA_K, array_abs_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) +) +{ +/* Sample short vectors s1 and s2 */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; + uint16_t nonce = 0; + /* Safety: The nonces are at most 14 (MLDSA_L + MLDSA_K - 1), and, hence, the + * casts are safe. */ + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_eta(&s1->vec[i], seed, (uint8_t)(nonce + i)); + } + for (i = 0; i < MLDSA_K; i++) + { + mld_poly_uniform_eta(&s2->vec[i], seed, (uint8_t)(nonce + MLDSA_L + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLD_CONFIG_PARAMETER_SET == 44 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 4, 5, 6, 7); +#elif MLD_CONFIG_PARAMETER_SET == 65 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s2->vec[0], &s2->vec[1], + &s2->vec[2] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[2], &s2->vec[3], &s2->vec[4], &s2->vec[5], + seed, 7, 8, 9, 10); +#elif MLD_CONFIG_PARAMETER_SET == 87 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s1->vec[5], &s1->vec[6], + &s2->vec[0] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 7, 8, 9, 10); + mld_poly_uniform_eta_4x(&s2->vec[4], &s2->vec[5], &s2->vec[6], &s2->vec[7], + seed, 11, 12, 13, 14); +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ +} + +/************************************************* + * Name: mld_compute_t0_t1_tr_from_sk_components + * + * Description: Computes t0, t1, tr, and pk from secret key components + * rho, s1, s2. This is the shared computation used by + * both keygen and generating the public key from the + * secret key. + * + * Arguments: - mld_polyveck *t0: output t0 + * - mld_polyveck *t1: output t1 + * - uint8_t tr[MLDSA_TRBYTES]: output tr + * - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t rho[MLDSA_SEEDBYTES]: input rho + * - const mld_polyvecl *s1: input s1 + * - const mld_polyveck *s2: input s2 + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_t0_t1_tr_from_sk_components( + mld_polyveck *t0, mld_polyveck *t1, uint8_t tr[MLDSA_TRBYTES], + uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], const uint8_t rho[MLDSA_SEEDBYTES], + const mld_polyvecl *s1, const mld_polyveck *s2, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(l0, 0, MLDSA_L, array_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + requires(forall(k0, 0, MLDSA_K, array_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(forall(k1, 0, MLDSA_K, array_bound(t0->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(t1->vec[k2].coeffs, 0, MLDSA_N, 0, 1 << 10))) + ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY)) +{ + int ret; + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1hat, mld_polyvecl, 1, context); + MLD_ALLOC(t, mld_polyveck, 1, context); + + if (mat == NULL || s1hat == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Expand matrix */ + mld_polyvec_matrix_expand(mat, rho); + + /* Matrix-vector multiplication */ + *s1hat = *s1; + mld_polyvecl_ntt(s1hat); + mld_polyvec_matrix_pointwise_montgomery(t, mat, s1hat); + mld_polyveck_invntt_tomont(t); + + /* Add error vector s2 */ + mld_polyveck_add(t, s2); + + /* Reference: The following reduction is not present in the reference + * implementation. Omitting this reduction requires the output of + * the invntt to be small enough such that the addition of s2 does + * not result in absolute values >= MLDSA_Q. While our C, x86_64, + * and AArch64 invntt implementations produce small enough + * values for this to work out, it complicates the bounds + * reasoning. We instead add an additional reduction, and can + * consequently, relax the bounds requirements for the invntt. + */ + mld_polyveck_reduce(t); + + /* Decompose to get t1, t0 */ + mld_polyveck_caddq(t); + mld_polyveck_power2round(t1, t0, t); + + /* Pack public key and compute tr */ + mld_pack_pk(pk, rho, t1); + mld_shake256(tr, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + ret = 0; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_polyveck, 1, context); + MLD_FREE(s1hat, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + const uint8_t *rho, *rhoprime, *key; + MLD_ALLOC(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + MLD_ALLOC(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + + if (seedbuf == NULL || inbuf == NULL || tr == NULL || s1 == NULL || + s2 == NULL || t1 == NULL || t0 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Get randomness for rho, rhoprime and key */ + mld_memcpy(inbuf, seed, MLDSA_SEEDBYTES); + inbuf[MLDSA_SEEDBYTES + 0] = MLDSA_K; + inbuf[MLDSA_SEEDBYTES + 1] = MLDSA_L; + mld_shake256(seedbuf, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, inbuf, + MLDSA_SEEDBYTES + 2); + rho = seedbuf; + rhoprime = rho + MLDSA_SEEDBYTES; + key = rhoprime + MLDSA_CRHBYTES; + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + + /* Sample s1 and s2 */ + mld_sample_s1_s2(s1, s2, rhoprime); + + /* Compute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0, t1, tr, pk, rho, s1, s2, + context); + if (ret != 0) + { + goto cleanup; + } + + /* Pack secret key */ + mld_pack_sk(sk, rho, tr, key, t0, s1, s2); + + /* Constant time: pk is the public key, inherently public data */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_FREE(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + + if (ret != 0) + { + return ret; + } + + /* Pairwise Consistency Test (PCT) @[FIPS140_3_IG, p.87] */ + /* Do this after freeing all temporaries. */ + return mld_check_pct(pk, sk, context); +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t seed[MLDSA_SEEDBYTES]; + int ret; + if (mld_randombytes(seed, MLDSA_SEEDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(seed, sizeof(seed)); + ret = mld_sign_keypair_internal(pk, sk, seed, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed, sizeof(seed)); + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +/************************************************* + * Name: mld_H + * + * Description: Abstracts application of SHAKE256 to + * one, two or three blocks of data, + * yielding a user-requested size of + * output. + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in1: pointer to input block 1 + * Must NOT be NULL + * - size_t in1len: length of input in1 bytes + * - const uint8_t *in2: pointer to input block 2 + * May be NULL if in2len=0, in which case + * this block is ignored + * - size_t in2len: length of input in2 bytes + * - const uint8_t *in3: pointer to input block 3 + * May be NULL if in3len=0, in which case + * this block is ignored + * - size_t in3len: length of input in3 bytes + **************************************************/ +static void mld_H(uint8_t *out, size_t outlen, const uint8_t *in1, + size_t in1len, const uint8_t *in2, size_t in2len, + const uint8_t *in3, size_t in3len) +__contract__( + requires(in1len <= MLD_MAX_BUFFER_SIZE) + requires(in2len <= MLD_MAX_BUFFER_SIZE) + requires(in3len <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in1, in1len)) + requires(in2len == 0 || memory_no_alias(in2, in2len)) + requires(in3len == 0 || memory_no_alias(in3, in3len)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) +{ + mld_shake256ctx state; + mld_shake256_init(&state); + mld_shake256_absorb(&state, in1, in1len); + if (in2len != 0) + { + mld_shake256_absorb(&state, in2, in2len); + } + if (in3len != 0) + { + mld_shake256_absorb(&state, in3, in3len); + } + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(&state, sizeof(state)); +} + +/************************************************* + * Name: mld_compute_pack_z + * + * Description: Computes z = y + s1*c, checks that z has coefficients smaller + * than MLDSA_GAMMA1 - MLDSA_BETA, and packs z into the + * signature buffer. + * + * Arguments: - uint8_t *sig: output signature + * - const mld_poly *cp: challenge polynomial + * - const polyvecl *s1: secret vector s1 + * - const polyvecl *y: masking vector y + * + * Returns: - 0: Success (z has coefficients smaller than + * MLDSA_GAMMA1 - MLDSA_BETA,) + * - MLD_ERR_FAIL: z rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This function is inlined into mld_sign_signature in the + * reference implementation. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_pack_z(uint8_t sig[MLDSA_CRYPTO_BYTES], + const mld_poly *cp, const mld_polyvecl *s1, + const mld_polyvecl *y, mld_poly *z) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(cp, sizeof(mld_poly))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(y, sizeof(mld_polyvecl))) + requires(memory_no_alias(z, sizeof(mld_poly))) + requires(array_abs_bound(cp->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_L, + array_bound(y->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + requires(forall(k1, 0, MLDSA_L, array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(memory_slice(z, sizeof(mld_poly))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int i; + uint32_t z_invalid; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(z, sizeof(mld_poly)), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_poly_pointwise_montgomery(z, cp, &s1->vec[i]); + mld_poly_invntt_tomont(z); + mld_poly_add(z, &y->vec[i]); + mld_poly_reduce(z); + + z_invalid = mld_poly_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA); + /* Constant time: It is fine (and prohibitively expensive to avoid) + * to leak the result of the norm check and which polynomial in z caused a + * rejection. It would even be okay to leak which coefficient led to + * rejection as the candidate signature will be discarded anyway. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(&z_invalid, sizeof(uint32_t)); + if (z_invalid) + { + return MLD_ERR_FAIL; /* reject */ + } + /* If z is valid, then its coefficients are bounded by + * MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below + * to prove the pre-condition of pack_sig_z() */ + mld_assert_abs_bound(z, MLDSA_N, (MLDSA_GAMMA1 - MLDSA_BETA)); + + /* After the norm check, the distribution of each coefficient of z is + * independent of the secret key and it can, hence, be considered + * public. It is, hence, okay to immediately pack it into the user-provided + * signature buffer. */ + mld_pack_sig_z(sig, z, i); + } + return 0; +} + +/* Reference: The reference implementation does not explicitly check the + * maximum nonce value, but instead loops indefinitely (even when the nonce + * would overflow). Internally, sampling of y uses + * (nonceL), (nonceL+1), ... (nonce*L+L-1). + * Hence, there are no overflows if nonce < (UINT16_MAX - L)/L. + * Explicitly checking for this explicitly allows us to prove type-safety. + * Note that FIPS204 explicitly allows an upper-bound this loop of + * 814 (< (UINT16_MAX - L)/L) - see @[FIPS204, Appendix C]. */ +#define MLD_NONCE_UB ((UINT16_MAX - MLDSA_L) / MLDSA_L) + +/************************************************* + * Name: attempt_signature_generation + * + * Description: Attempts to generate a single signature. + * + * Arguments: - uint8_t *sig: pointer to output signature + * - const uint8_t *mu: pointer to message or hash + * of exactly MLDSA_CRHBYTES bytes + * - const uint8_t *rhoprime: pointer to randomness seed + * - uint16_t nonce: current nonce value + * - const mld_polymat *mat: expanded matrix + * - const polyvecl *s1: secret vector s1 + * - const polyveck *s2: secret vector s2 + * - const polyveck *t0: vector t0 + * + * Returns: - 0: Signature generation succeeded + * - MLD_ERR_FAIL: Signature rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This code differs from the reference implementation + * in that it factors out the core signature generation + * step into a distinct function here in order to improve + * efficiency of CBMC proof. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_attempt_signature_generation( + uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *mu, + const uint8_t rhoprime[MLDSA_CRHBYTES], uint16_t nonce, mld_polymat *mat, + const mld_polyvecl *s1, const mld_polyveck *s2, const mld_polyveck *t0, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(rhoprime, MLDSA_CRHBYTES)) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(nonce <= MLD_NONCE_UB) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int n; + uint32_t w0_invalid, h_invalid; + int ret; + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyvecl y; + mld_polyveck h; + } + yh_u; + mld_polyvecl *y; + mld_polyveck *h; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck w1; + mld_polyvecl tmp; + } + w1tmp_u; + mld_polyveck *w1; + mld_polyvecl *tmp; + + MLD_ALLOC(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(yh, yh_u, 1, context); + MLD_ALLOC(z, mld_poly, 1, context); + MLD_ALLOC(w1tmp, w1tmp_u, 1, context); + MLD_ALLOC(w0, mld_polyveck, 1, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(t, mld_poly, 1, context); + + if (challenge_bytes == NULL || yh == NULL || z == NULL || w1tmp == NULL || + w0 == NULL || cp == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + y = &yh->y; + h = &yh->h; + w1 = &w1tmp->w1; + tmp = &w1tmp->tmp; + + /* Sample intermediate vector y */ + mld_polyvecl_uniform_gamma1(y, rhoprime, nonce); + + /* Matrix-vector multiplication */ + *tmp = *y; + mld_polyvecl_ntt(tmp); + mld_polyvec_matrix_pointwise_montgomery(w0, mat, tmp); + mld_polyveck_invntt_tomont(w0); + + /* Decompose w and call the random oracle */ + mld_polyveck_caddq(w0); + mld_polyveck_decompose(w1, w0); + mld_polyveck_pack_w1(sig, w1); + + mld_H(challenge_bytes, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, sig, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + /* Constant time: Leaking challenge_bytes does not reveal any information + * about the secret key as H() is modelled as random oracle. + * This also applies to challenges for rejected signatures. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(challenge_bytes, MLDSA_CTILDEBYTES); + mld_poly_challenge(cp, challenge_bytes); + mld_poly_ntt(cp); + + /* Compute z, reject if it reveals secret */ + ret = mld_compute_pack_z(sig, cp, s1, y, t); + if (ret) + { + goto cleanup; + } + + /* Check that subtracting cs2 does not change high bits of w and low bits + * do not reveal secret information */ + mld_polyveck_pointwise_poly_montgomery(h, cp, s2); + mld_polyveck_invntt_tomont(h); + mld_polyveck_sub(w0, h); + mld_polyveck_reduce(w0); + + w0_invalid = mld_polyveck_chknorm(w0, MLDSA_GAMMA2 - MLDSA_BETA); + /* Constant time: w0_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&w0_invalid, sizeof(uint32_t)); + if (w0_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* Compute hints for w1 */ + mld_polyveck_pointwise_poly_montgomery(h, cp, t0); + mld_polyveck_invntt_tomont(h); + mld_polyveck_reduce(h); + + h_invalid = mld_polyveck_chknorm(h, MLDSA_GAMMA2); + /* Constant time: h_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&h_invalid, sizeof(uint32_t)); + if (h_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + mld_polyveck_add(w0, h); + + /* Constant time: At this point all norm checks have passed and we, hence, + * know that the signature does not leak any secret information. + * Consequently, any value that can be computed from the signature and public + * key is considered public. + * w0 and w1 are public as they can be computed from Az - ct = \alpha w1 + w0. + * h=c*t0 is public as both c and t0 are public. + * For a more detailed discussion, refer to https://eprint.iacr.org/2022/1406. + */ + MLD_CT_TESTING_DECLASSIFY(w0, sizeof(*w0)); + MLD_CT_TESTING_DECLASSIFY(w1, sizeof(*w1)); + n = mld_polyveck_make_hint(h, w0, w1); + if (n > MLDSA_OMEGA) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* All is well - write signature */ + mld_pack_sig_c_h(sig, challenge_bytes, h, n); + /* Constant time: At this point it is clear that the signature is valid - it + * can, hence, be considered public. */ + MLD_CT_TESTING_DECLASSIFY(sig, MLDSA_CRYPTO_BYTES); + ret = 0; /* success */ + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_poly, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(w0, mld_polyveck, 1, context); + MLD_FREE(w1tmp, w1tmp_u, 1, context); + MLD_FREE(z, mld_poly, 1, context); + MLD_FREE(yh, yh_u, 1, context); + MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + + return ret; +} +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + uint8_t *rho, *tr, *key, *mu, *rhoprime; + uint16_t nonce = 0; + MLD_ALLOC(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + + if (seedbuf == NULL || mat == NULL || s1 == NULL || t0 == NULL || s2 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + rho = seedbuf; + tr = rho + MLDSA_SEEDBYTES; + key = tr + MLDSA_TRBYTES; + mu = key + MLDSA_SEEDBYTES; + rhoprime = mu + MLDSA_CRHBYTES; + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + if (!externalmu) + { + /* Compute mu = CRH(tr, pre, msg) */ + mld_H(mu, MLDSA_CRHBYTES, tr, MLDSA_TRBYTES, pre, prelen, m, mlen); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Compute rhoprime = CRH(key, rnd, mu) */ + mld_H(rhoprime, MLDSA_CRHBYTES, key, MLDSA_SEEDBYTES, rnd, MLDSA_RNDBYTES, mu, + MLDSA_CRHBYTES); + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + /* Expand matrix and transform vectors */ + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(s1); + mld_polyveck_ntt(s2); + mld_polyveck_ntt(t0); + + /* By default, return failure. Flip to success and write output + * once signature generation succeeds. */ + ret = MLD_ERR_FAIL; + + /* Reference: This code is re-structured using a while(1), */ + /* with explicit "continue" statements (rather than "goto") */ + /* to implement rejection of invalid signatures. */ + while (1) + __loop__( + assigns(nonce, ret, object_whole(siglen), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(nonce <= MLD_NONCE_UB) + + /* t0, s1, s2, and mat are initialized above and are NOT changed by this */ + /* loop. We can therefore re-assert their bounds here as part of the */ + /* loop invariant. This makes proof noticeably faster with CBMC */ + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + invariant(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(ret == MLD_ERR_FAIL) + ) + { + /* Reference: this code explicitly checks for exhaustion of nonce */ + /* values to provide predictable termination and results in that case */ + /* Checking here also means that incrementing nonce below can also */ + /* be proven to be type-safe. */ + if (nonce == MLD_NONCE_UB) + { + /* Note that ret == MLD_ERR_FAIL by default, so we + * don't need to set it here. */ + break; + } + + ret = mld_attempt_signature_generation(sig, mu, rhoprime, nonce, mat, s1, + s2, t0, context); + nonce++; + if (ret == 0) + { + *siglen = MLDSA_CRYPTO_BYTES; + break; + } + else if (ret != MLD_ERR_FAIL) + { + /* For failures such as out-of-memory, propagate and exit immediately. */ + break; + } + + /* Otherwise, try again. */ + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the signature buffer. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + return ret; +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + size_t pre_len; + int ret; + MLD_ALLOC(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + MLD_ALLOC(rnd, uint8_t, MLDSA_RNDBYTES, context); + + if (pre == NULL || rnd == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Prepare domain separation prefix for pure ML-DSA */ + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, m, mlen, pre, pre_len, rnd, sk, + 0, context); + +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(rnd, uint8_t, MLDSA_RNDBYTES, context); + MLD_FREE(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t rnd[MLDSA_RNDBYTES]; + int ret; + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + *siglen = 0; + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, + rnd, sk, 1, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(rnd, sizeof(rnd)); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + for (i = 0; i < mlen; ++i) + __loop__( + assigns(i, object_whole(sm)) + invariant(i <= mlen) + ) + { + sm[MLDSA_CRYPTO_BYTES + mlen - 1 - i] = m[mlen - 1 - i]; + } + ret = mld_sign_signature(sm, smlen, sm + MLDSA_CRYPTO_BYTES, mlen, ctx, + ctxlen, sk, context); + *smlen += mlen; + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret, cmp; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck t1; + mld_polyveck w1; + } + t1w1_u; + mld_polyveck *t1; + mld_polyveck *w1; + + MLD_ALLOC(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_ALLOC(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(z, mld_polyvecl, 1, context); + MLD_ALLOC(t1w1, t1w1_u, 1, context); + MLD_ALLOC(tmp, mld_polyveck, 1, context); + MLD_ALLOC(h, mld_polyveck, 1, context); + + if (buf == NULL || rho == NULL || mu == NULL || c == NULL || c2 == NULL || + cp == NULL || mat == NULL || z == NULL || t1w1 == NULL || tmp == NULL || + h == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + t1 = &t1w1->t1; + w1 = &t1w1->w1; + + if (siglen != MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + mld_unpack_pk(rho, t1, pk); + + /* mld_unpack_sig and mld_polyvecl_chknorm signal failure through a + * single non-zero error code that's not yet aligned with MLD_ERR_XXX. + * Map it to MLD_ERR_FAIL explicitly. */ + if (mld_unpack_sig(c, z, h, sig)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + if (mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + if (!externalmu) + { + /* Compute CRH(H(rho, t1), pre, msg) */ + MLD_ALIGN uint8_t hpk[MLDSA_CRHBYTES]; + mld_H(hpk, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES, NULL, 0, NULL, + 0); + mld_H(mu, MLDSA_CRHBYTES, hpk, MLDSA_TRBYTES, pre, prelen, m, mlen); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(hpk, sizeof(hpk)); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Matrix-vector multiplication; compute Az - c2^dt1 */ + mld_poly_challenge(cp, c); + mld_poly_ntt(cp); + mld_polyveck_shiftl(t1); + mld_polyveck_ntt(t1); + mld_polyveck_pointwise_poly_montgomery(tmp, cp, t1); + + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(z); + mld_polyvec_matrix_pointwise_montgomery(w1, mat, z); + mld_polyveck_sub(w1, tmp); + mld_polyveck_reduce(w1); + mld_polyveck_invntt_tomont(w1); + + /* Reconstruct w1 */ + mld_polyveck_caddq(w1); + mld_polyveck_use_hint(tmp, w1, h); + mld_polyveck_pack_w1(buf, tmp); + /* Call random oracle and verify challenge */ + mld_H(c2, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, buf, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + + cmp = mld_ct_memcmp(c, c2, MLDSA_CTILDEBYTES); + + /* Declassify the result of the verification. */ + MLD_CT_TESTING_DECLASSIFY(&cmp, sizeof(cmp)); + + ret = cmp == 0 ? 0 : MLD_ERR_FAIL; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(h, mld_polyveck, 1, context); + MLD_FREE(tmp, mld_polyveck, 1, context); + MLD_FREE(t1w1, t1w1_u, 1, context); + MLD_FREE(z, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, m, mlen, pre, pre_len, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + return mld_sign_verify_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, pk, + 1, context); +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + if (smlen < MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + *mlen = smlen - MLDSA_CRYPTO_BYTES; + ret = mld_sign_verify(sm, MLDSA_CRYPTO_BYTES, sm + MLDSA_CRYPTO_BYTES, *mlen, + ctx, ctxlen, pk, context); + if (ret == 0) + { + /* All good, copy msg, return 0 */ + for (i = 0; i < *mlen; ++i) + __loop__( + assigns(i, memory_slice(m, *mlen)) + invariant(i <= *mlen) + ) + { + m[i] = sm[MLDSA_CRYPTO_BYTES + i]; + } + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the message buffer. */ + *mlen = 0; + mld_memset(m, 0, smlen); + } + + return ret; +} + + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_signature_internal(sig, siglen, pre, pre_len, NULL, 0, rnd, sk, + 0, context); +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, pre, pre_len, NULL, 0, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_signature_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, rnd, sk, + MLD_PREHASH_SHAKE_256, context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_verify_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, pk, MLD_PREHASH_SHAKE_256, + context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + + +#define MLD_PRE_HASH_OID_LEN 11 + +/************************************************* + * Name: mld_get_hash_oid + * + * Description: Returns the OID of a given SHA-2/SHA-3 hash function. + * + * Arguments: - uint8_t oid[11]: pointer to output oid + * - int hashalg: hash algorithm constant (MLD_PREHASH_*) + * + ***************************************************/ +static void mld_get_hash_oid(uint8_t oid[MLD_PRE_HASH_OID_LEN], int hashalg) +{ + unsigned int i; + static const struct + { + int alg; + uint8_t oid[MLD_PRE_HASH_OID_LEN]; + } oid_map[] = { + {MLD_PREHASH_SHA2_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}}, + {MLD_PREHASH_SHA2_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}}, + {MLD_PREHASH_SHA2_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}}, + {MLD_PREHASH_SHA2_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}}, + {MLD_PREHASH_SHA2_512_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05}}, + {MLD_PREHASH_SHA2_512_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06}}, + {MLD_PREHASH_SHA3_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07}}, + {MLD_PREHASH_SHA3_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08}}, + {MLD_PREHASH_SHA3_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09}}, + {MLD_PREHASH_SHA3_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A}}, + {MLD_PREHASH_SHAKE_128, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B}}, + {MLD_PREHASH_SHAKE_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C}}}; + + for (i = 0; i < sizeof(oid_map) / sizeof(oid_map[0]); i++) + __loop__( + invariant(i <= sizeof(oid_map) / sizeof(oid_map[0])) + ) + { + if (oid_map[i].alg == hashalg) + { + mld_memcpy(oid, oid_map[i].oid, MLD_PRE_HASH_OID_LEN); + return; + } + } +} + +static int mld_validate_hash_length(int hashalg, size_t len) +{ + switch (hashalg) + { + case MLD_PREHASH_SHA2_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_128: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_256: + return (len == 512 / 8) ? 0 : -1; + } + return -1; +} + +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +{ + if (ctxlen > 255) + { + return 0; + } + + if (hashalg != MLD_PREHASH_NONE) + { + if (ph == NULL || mld_validate_hash_length(hashalg, phlen) != 0) + { + return 0; + } + } + + /* Common prefix: 0x00/0x01 || ctxlen || ctx */ + prefix[0] = (hashalg == MLD_PREHASH_NONE) ? 0 : 1; + prefix[1] = (uint8_t)ctxlen; + if (ctxlen > 0) + { + mld_memcpy(prefix + 2, ctx, ctxlen); + } + + if (hashalg == MLD_PREHASH_NONE) + { + return 2 + ctxlen; + } + + /* HashML-DSA: append oid || ph */ + mld_get_hash_oid(prefix + 2 + ctxlen, hashalg); + mld_memcpy(prefix + 2 + ctxlen + MLD_PRE_HASH_OID_LEN, ph, phlen); + return 2 + ctxlen + MLD_PRE_HASH_OID_LEN + phlen; +} + +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + uint8_t check, cmp0, cmp1, chk1, chk2; + int ret; + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(t0_computed, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + + if (rho == NULL || tr == NULL || tr_computed == NULL || key == NULL || + s1 == NULL || s2 == NULL || t0 == NULL || t0_computed == NULL || + t1 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Unpack secret key */ + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + /* Validate s1 and s2 coefficients are within [-MLDSA_ETA, MLDSA_ETA] */ + chk1 = mld_polyvecl_chknorm(s1, MLDSA_ETA + 1) & 0xFF; + chk2 = mld_polyveck_chknorm(s2, MLDSA_ETA + 1) & 0xFF; + + /* Recompute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0_computed, t1, tr_computed, + pk, rho, s1, s2, context); + if (ret != 0) + { + goto cleanup; + } + + /* Validate t0 and tr using constant-time comparisons */ + cmp0 = mld_ct_memcmp((const uint8_t *)t0, (const uint8_t *)t0_computed, + sizeof(mld_polyveck)); + cmp1 = mld_ct_memcmp((const uint8_t *)tr, (const uint8_t *)tr_computed, + MLDSA_TRBYTES); + check = mld_value_barrier_u8(cmp0 | cmp1 | chk1 | chk2); + + /* Declassify the final result of the validity check. */ + MLD_CT_TESTING_DECLASSIFY(&check, sizeof(check)); + ret = (check != 0) ? MLD_ERR_FAIL : 0; + +cleanup: + + if (ret != 0) + { + mld_zeroize(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + } + + /* Constant time: pk is either the valid public key or zeroed on error */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(t0_computed, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + + return ret; +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_check_pct +#undef mld_sample_s1_s2 +#undef mld_validate_hash_length +#undef mld_get_hash_oid +#undef mld_H +#undef mld_compute_pack_z +#undef mld_attempt_signature_generation +#undef mld_compute_t0_t1_tr_from_sk_components +#undef MLD_NONCE_UB +#undef MLD_PRE_HASH_OID_LEN diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/sign.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/sign.h new file mode 100644 index 0000000000..2e0bac32ea --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/sign.h @@ -0,0 +1,807 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_SIGN_H +#define MLD_SIGN_H + +#include +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "polyvec.h" +#include "sys.h" + +#if defined(MLD_CHECK_APIS) +/* Include to ensure consistency between internal sign.h + * and external mldsa_native.h. */ +#include "mldsa_native.h" + +#if MLDSA_CRYPTO_SECRETKEYBYTES != \ + MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for SECRETKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_PUBLICKEYBYTES != \ + MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for PUBLICKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_BYTES != MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for CRYPTO_BYTES between sign.h and mldsa_native.h +#endif + +#endif /* MLD_CHECK_APIS */ + +#define mld_sign_keypair_internal \ + MLD_NAMESPACE_KL(keypair_internal) MLD_CONTEXT_PARAMETERS_3 +#define mld_sign_keypair MLD_NAMESPACE_KL(keypair) MLD_CONTEXT_PARAMETERS_2 +#define mld_sign_signature_internal \ + MLD_NAMESPACE_KL(signature_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_signature MLD_NAMESPACE_KL(signature) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_extmu \ + MLD_NAMESPACE_KL(signature_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign MLD_NAMESPACE_KL(sign) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_internal \ + MLD_NAMESPACE_KL(verify_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify MLD_NAMESPACE_KL(verify) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_extmu \ + MLD_NAMESPACE_KL(verify_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign_open MLD_NAMESPACE_KL(open) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_pre_hash_internal \ + MLD_NAMESPACE_KL(signature_pre_hash_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_verify_pre_hash_internal \ + MLD_NAMESPACE_KL(verify_pre_hash_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_signature_pre_hash_shake256 \ + MLD_NAMESPACE_KL(signature_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify_pre_hash_shake256 \ + MLD_NAMESPACE_KL(verify_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_7 +#define mld_prepare_domain_separation_prefix \ + MLD_NAMESPACE_KL(prepare_domain_separation_prefix) +#define mld_sign_pk_from_sk \ + MLD_NAMESPACE_KL(pk_from_sk) MLD_CONTEXT_PARAMETERS_2 + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: mld_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: input random seed + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int externalmu: indicates input message m is + * processed as mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return MLD_ERR_FAIL in that case. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires((externalmu == 0 && (prelen == 0 || memory_no_alias(pre, prelen))) || + (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) + ensures(return_value == 0 ==> *siglen == MLDSA_CRYPTO_BYTES) + ensures(return_value != 0 ==> *siglen == 0) +); + +/************************************************* + * Name: mld_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_signature_extmu + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign + * + * Description: Compute signed message. + * + * Arguments: - uint8_t *sm: pointer to output signed message + * (allocated array with MLDSA_CRYPTO_BYTES + + *mlen bytes), can be equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sm, MLDSA_CRYPTO_BYTES + mlen)) + requires(memory_no_alias(smlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sm, MLDSA_CRYPTO_BYTES + mlen)) + assigns(object_whole(smlen)) + ensures((return_value == 0 && *smlen == MLDSA_CRYPTO_BYTES + mlen) || + (return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL)) +); + +/************************************************* + * Name: mld_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as + * mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(externalmu == 0 || (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + requires(externalmu == 1 || prelen == 0 || memory_no_alias(pre, prelen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_open + * + * Description: Verify signed message. + * + * Arguments: - uint8_t *m: pointer to output message (allocated array + * with smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context tring + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(smlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(m, smlen)) + requires(memory_no_alias(mlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(sm, smlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + assigns(memory_slice(m, smlen)) + assigns(memory_slice(mlen, sizeof(size_t))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and + * verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/* Maximum formatted domain separation message length: + * - Pure ML-DSA: 0x00 || ctxlen || ctx (max 255) + * - HashML-DSA: 0x01 || ctxlen || ctx (max 255) || oid (11) || ph (max 64) */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +__contract__( + requires(ctxlen <= 255) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(hashalg == MLD_PREHASH_NONE || memory_no_alias(ph, phlen)) + requires(memory_no_alias(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + assigns(memory_slice(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + ensures(return_value <= MLD_DOMAIN_SEPARATION_MAX_BYTES) +); + +/************************************************* + * Name: mld_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: input secret + * key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); +#endif /* !MLD_SIGN_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/symmetric.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/symmetric.h new file mode 100644 index 0000000000..bb70f05552 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/symmetric.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_SYMMETRIC_H +#define MLD_SYMMETRIC_H + +#include +#include "cbmc.h" +#include "common.h" + +#include MLD_FIPS202_HEADER_FILE +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#include MLD_FIPS202X4_HEADER_FILE +#endif + +#define MLD_STREAM128_BLOCKBYTES SHAKE128_RATE +#define MLD_STREAM256_BLOCKBYTES SHAKE256_RATE + +#define mld_xof256_ctx mld_shake256ctx +#define mld_xof256_init(CTX) mld_shake256_init(CTX) + +#define mld_xof256_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake256_absorb(CTX, IN, INBYTES); \ + mld_shake256_finalize(CTX); \ + } while (0) + + +#define mld_xof256_release(CTX) mld_shake256_release(CTX) +#define mld_xof256_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake256_squeeze(OUT, (OUTBLOCKS) * SHAKE256_RATE, STATE) + +#define mld_xof128_ctx mld_shake128ctx +#define mld_xof128_init(CTX) mld_shake128_init(CTX) + +#define mld_xof128_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake128_absorb(CTX, IN, INBYTES); \ + mld_shake128_finalize(CTX); \ + } while (0) + +#define mld_xof128_release(CTX) mld_shake128_release(CTX) +#define mld_xof128_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake128_squeeze(OUT, (OUTBLOCKS) * SHAKE128_RATE, STATE) + +#define mld_xof256_x4_ctx mld_shake256x4ctx +#define mld_xof256_x4_init(CTX) mld_shake256x4_init((CTX)) +#define mld_xof256_x4_absorb(CTX, IN, INBYTES) \ + mld_shake256x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof256_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake256x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof256_x4_release(CTX) mld_shake256x4_release((CTX)) + +#define mld_xof128_x4_ctx mld_shake128x4ctx +#define mld_xof128_x4_init(CTX) mld_shake128x4_init((CTX)) +#define mld_xof128_x4_absorb(CTX, IN, INBYTES) \ + mld_shake128x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof128_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake128x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof128_x4_release(CTX) mld_shake128x4_release((CTX)) + +#endif /* !MLD_SYMMETRIC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/sys.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/sys.h new file mode 100644 index 0000000000..1226526420 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/sys.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_SYS_H +#define MLD_SYS_H + +#if !defined(MLD_CONFIG_NO_ASM) && (defined(__GNUC__) || defined(__clang__)) +#define MLD_HAVE_INLINE_ASM +#endif + +/* Try to find endianness, if not forced through CFLAGS already */ +#if !defined(MLD_SYS_LITTLE_ENDIAN) && !defined(MLD_SYS_BIG_ENDIAN) +#if defined(__BYTE_ORDER__) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define MLD_SYS_LITTLE_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define MLD_SYS_BIG_ENDIAN +#else +#error "__BYTE_ORDER__ defined, but don't recognize value." +#endif +#endif /* __BYTE_ORDER__ */ + +/* MSVC does not define __BYTE_ORDER__. However, MSVC only supports + * little endian x86, x86_64, and AArch64. It is, hence, safe to assume + * little endian. */ +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_IX86) || defined(_M_ARM64)) +#define MLD_SYS_LITTLE_ENDIAN +#endif + +#endif /* !MLD_SYS_LITTLE_ENDIAN && !MLD_SYS_BIG_ENDIAN */ + +/* Check if we're running on an AArch64 little endian system. _M_ARM64 is set by + * MSVC. */ +#if defined(__AARCH64EL__) || defined(_M_ARM64) +#define MLD_SYS_AARCH64 +#endif + +/* Check if we're running on an AArch64 big endian system. */ +#if defined(__AARCH64EB__) +#define MLD_SYS_AARCH64_EB +#endif + +#if defined(__x86_64__) +#define MLD_SYS_X86_64 +#if defined(__AVX2__) +#define MLD_SYS_X86_64_AVX2 +#endif +#endif /* __x86_64__ */ + +#if defined(MLD_SYS_LITTLE_ENDIAN) && defined(__powerpc64__) +#define MLD_SYS_PPC64LE +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 +#define MLD_SYS_RISCV64 +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32 +#define MLD_SYS_RISCV32 +#endif + +#if defined(_WIN64) || defined(_WIN32) +#define MLD_SYS_WINDOWS +#endif + +#if defined(__linux__) +#define MLD_SYS_LINUX +#endif + +#if defined(__APPLE__) +#define MLD_SYS_APPLE +#endif + +/* If MLD_FORCE_AARCH64 is set, assert that we're indeed on an AArch64 system. + */ +#if defined(MLD_FORCE_AARCH64) && !defined(MLD_SYS_AARCH64) +#error "MLD_FORCE_AARCH64 is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_AARCH64_EB is set, assert that we're indeed on a big endian + * AArch64 system. */ +#if defined(MLD_FORCE_AARCH64_EB) && !defined(MLD_SYS_AARCH64_EB) +#error \ + "MLD_FORCE_AARCH64_EB is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_X86_64 is set, assert that we're indeed on an X86_64 system. */ +#if defined(MLD_FORCE_X86_64) && !defined(MLD_SYS_X86_64) +#error "MLD_FORCE_X86_64 is set, but we don't seem to be on an X86_64 system." +#endif + +#if defined(MLD_FORCE_PPC64LE) && !defined(MLD_SYS_PPC64LE) +#error "MLD_FORCE_PPC64LE is set, but we don't seem to be on a PPC64LE system." +#endif + +#if defined(MLD_FORCE_RISCV64) && !defined(MLD_SYS_RISCV64) +#error "MLD_FORCE_RISCV64 is set, but we don't seem to be on a RISCV64 system." +#endif + +#if defined(MLD_FORCE_RISCV32) && !defined(MLD_SYS_RISCV32) +#error "MLD_FORCE_RISCV32 is set, but we don't seem to be on a RISCV32 system." +#endif + +/* + * MLD_INLINE: Hint for inlining. + * - MSVC: __inline + * - C99+: inline + * - GCC/Clang C90: __attribute__((unused)) to silence warnings + * - Other C90: empty + */ +#if !defined(MLD_INLINE) +#if defined(_MSC_VER) +#define MLD_INLINE __inline +#elif defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +#define MLD_INLINE inline +#elif defined(__GNUC__) || defined(__clang__) +#define MLD_INLINE __attribute__((unused)) +#else +#define MLD_INLINE +#endif +#endif /* !MLD_INLINE */ + +/* + * MLD_ALWAYS_INLINE: Force inlining. + * - MSVC: __forceinline + * - GCC/Clang C99+: MLD_INLINE __attribute__((always_inline)) + * - Other: MLD_INLINE (no forced inlining) + */ +#if !defined(MLD_ALWAYS_INLINE) +#if defined(_MSC_VER) +#define MLD_ALWAYS_INLINE __forceinline +#elif (defined(__GNUC__) || defined(__clang__)) && \ + (defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)) +#define MLD_ALWAYS_INLINE MLD_INLINE __attribute__((always_inline)) +#else +#define MLD_ALWAYS_INLINE MLD_INLINE +#endif +#endif /* !MLD_ALWAYS_INLINE */ + +#ifndef MLD_STATIC_TESTABLE +#define MLD_STATIC_TESTABLE static +#endif + +/* + * C90 does not have the restrict compiler directive yet. + * We don't use it in C90 builds. + */ +#if !defined(restrict) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define MLD_RESTRICT restrict +#else +#define MLD_RESTRICT +#endif + +#else /* !restrict */ + +#define MLD_RESTRICT restrict +#endif /* restrict */ + +#define MLD_DEFAULT_ALIGN 32 +#define MLD_ALIGN_UP(N) \ + ((((N) + (MLD_DEFAULT_ALIGN - 1)) / MLD_DEFAULT_ALIGN) * MLD_DEFAULT_ALIGN) +#if defined(__GNUC__) +#define MLD_ALIGN __attribute__((aligned(MLD_DEFAULT_ALIGN))) +#elif defined(_MSC_VER) +#define MLD_ALIGN __declspec(align(MLD_DEFAULT_ALIGN)) +#else +#define MLD_ALIGN /* No known support for alignment constraints */ +#endif + + +/* New X86_64 CPUs support Conflow-flow protection using the CET instructions. + * When enabled (through -fcf-protection=), all compilation units (including + * empty ones) need to support CET for this to work. + * For assembly, this means that source files need to signal support for + * CET by setting the appropriate note.gnu.property section. + * This can be achieved by including the header in all assembly file. + * This file also provides the _CET_ENDBR macro which needs to be placed at + * every potential target of an indirect branch. + * If CET is enabled _CET_ENDBR maps to the endbr64 instruction, otherwise + * it is empty. + * In case the compiler does not support CET (e.g., +#define MLD_CET_ENDBR _CET_ENDBR +#else +#define MLD_CET_ENDBR +#endif +#endif /* MLD_SYS_X86_64 */ + +#if defined(MLD_CONFIG_CT_TESTING_ENABLED) && !defined(__ASSEMBLER__) +#include +#define MLD_CT_TESTING_SECRET(ptr, len) \ + VALGRIND_MAKE_MEM_UNDEFINED((ptr), (len)) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) +#else /* MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__ */ +#define MLD_CT_TESTING_SECRET(ptr, len) \ + do \ + { \ + } while (0) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + do \ + { \ + } while (0) +#endif /* !(MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__) */ + +#if defined(__GNUC__) || defined(__clang__) +#define MLD_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_MUST_CHECK_RETURN_VALUE +#endif + + +#if !defined(__ASSEMBLER__) +/* System capability enumeration */ +typedef enum +{ + /* x86_64 */ + MLD_SYS_CAP_AVX2, + /* AArch64 */ + MLD_SYS_CAP_SHA3 +} mld_sys_cap; + +#if !defined(MLD_CONFIG_CUSTOM_CAPABILITY_FUNC) +#include "cbmc.h" + +static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) +__contract__( + ensures(return_value == 0 || return_value == 1) +) +{ + /* By default, we rely on compile-time feature detection/specification: + * If a feature is enabled at compile-time, we assume it is supported by + * the host that the resulting library/binary will be built on. + * If this assumption is not true, you MUST overwrite this function. + * See the documentation of MLD_CONFIG_CUSTOM_CAPABILITY_FUNC in + * mldsa_native_config.h for more information. */ + (void)cap; + return 1; +} +#endif /* !MLD_CONFIG_CUSTOM_CAPABILITY_FUNC */ +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_SYS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/zetas.inc b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/zetas.inc new file mode 100644 index 0000000000..dc3cf15dd3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/mldsa_native/src/zetas.inc @@ -0,0 +1,56 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include + +/* + * Table of zeta values used in the reference NTT and inverse NTT. + * See autogen for details. + */ +static const int32_t mld_zetas[MLDSA_N] = { + 0, 25847, -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 2353451, -359251, -2091905, 3119733, -2884855, + 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488, + -1119584, 2619752, -2108549, -2118186, -3859737, -1399561, -3277672, + 1757237, -19422, 4010497, 280005, 2706023, 95776, 3077325, + 3530437, -1661693, -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267, + -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596, + 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, + -2797779, -3930395, -1528703, -3677745, -3041255, -1452451, 3475950, + 2176455, -1585221, -1257611, 1939314, -4083598, -1000202, -3190144, + -3157330, -3632928, 126922, 3412210, -983419, 2147896, 2715295, + -2967645, -3693493, -411027, -2477047, -671102, -1228525, -22981, + -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944, + 508951, 3097992, 44288, -1100098, 904516, 3958618, -3724342, + -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856, + 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, + 1341330, 1285669, -1584928, -812732, -1439742, -3019102, -3881060, + -3628969, 3839961, 2091667, 3407706, 2316500, 3817976, -3342478, + 2244091, -2446433, -3562462, 266997, 2434439, -1235728, 3513181, + -3520352, -3759364, -1197226, -3193378, 900702, 1859098, 909542, + 819034, 495491, -1613174, -43260, -522500, -655327, -3122442, + 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297, + 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, + 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, + 1595974, -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, + 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100, + 1312455, 3306115, -1962642, -1279661, 1917081, -2546312, -1374803, + 1500165, 777191, 2235880, 3406031, -542412, -2831860, -1671176, + -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395, + 2454455, -164721, 1957272, 3369112, 185531, -1207385, -3183426, + 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, + -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, + 472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333, + -260646, -3833893, -2939036, -2235985, -420899, -2286327, 183443, + -976891, 1612842, -3545687, -554416, 3919660, -48306, -1362209, + 3937738, 1400424, -846154, 1976782, +}; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/test_only_rng/notrandombytes.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/test_only_rng/notrandombytes.c new file mode 100644 index 0000000000..ef5a423a9e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/test_only_rng/notrandombytes.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* * Based on @[surf]*/ + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +#include +#include + +#include "notrandombytes.h" + +#ifdef ENABLE_CT_TESTING +#include +#endif + +static uint32_t seed[32] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, + 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5}; +static uint32_t in[12]; +static uint32_t out[8]; +static int32_t outleft = 0; + +void randombytes_reset(void) +{ + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + outleft = 0; +} + +#define ROTATE(x, b) (((x) << (b)) | ((x) >> (32 - (b)))) +#define MUSH(i, b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x, b)); + +static void surf(void) +{ + uint32_t t[12]; + uint32_t x; + uint32_t sum = 0; + int32_t r; + int32_t i; + int32_t loop; + + for (i = 0; i < 12; ++i) + { + t[i] = in[i] ^ seed[12 + i]; + } + for (i = 0; i < 8; ++i) + { + out[i] = seed[24 + i]; + } + x = t[11]; + for (loop = 0; loop < 2; ++loop) + { + for (r = 0; r < 16; ++r) + { + sum += 0x9e3779b9; + MUSH(0, 5) + MUSH(1, 7) + MUSH(2, 9) + MUSH(3, 13) + MUSH(4, 5) + MUSH(5, 7) + MUSH(6, 9) + MUSH(7, 13) + MUSH(8, 5) + MUSH(9, 7) + MUSH(10, 9) + MUSH(11, 13) + } + for (i = 0; i < 8; ++i) + { + out[i] ^= t[i + 4]; + } + } +} + +int randombytes(uint8_t *buf, size_t n) +{ +#ifdef ENABLE_CT_TESTING + uint8_t *buf_orig = buf; + size_t n_orig = n; +#endif + + while (n > 0) + { + if (!outleft) + { + if (!++in[0]) + { + if (!++in[1]) + { + if (!++in[2]) + { + ++in[3]; + } + } + } + surf(); + outleft = 8; + } + *buf = (uint8_t)out[--outleft]; + ++buf; + --n; + } + +#ifdef ENABLE_CT_TESTING + /* + * Mark all randombytes output as secret (undefined). + * Valgrind will propagate this to everything derived from it. + */ + VALGRIND_MAKE_MEM_UNDEFINED(buf_orig, n_orig); +#endif /* ENABLE_CT_TESTING */ + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/test_only_rng/notrandombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/test_only_rng/notrandombytes.h new file mode 100644 index 0000000000..bdf9787920 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/basic_lowram/test_only_rng/notrandombytes.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* Based on @[surf]. */ + +#ifndef NOTRANDOMBYTES_H +#define NOTRANDOMBYTES_H + +#include +#include + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +void randombytes_reset(void); +int randombytes(uint8_t *buf, size_t n); + +#endif /* !NOTRANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/.gitignore b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/.gitignore new file mode 100644 index 0000000000..834e997200 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/.gitignore @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +build/ +*.d diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/Makefile new file mode 100644 index 0000000000..5784f0dfe6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/Makefile @@ -0,0 +1,114 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +.PHONY: build run clean +.DEFAULT_GOAL := all + +CC ?= gcc + +# Adjust CFLAGS if needed +CFLAGS := \ + -Wall \ + -Wextra \ + -Werror=unused-result \ + -Wpedantic \ + -Werror \ + -Wmissing-prototypes \ + -Wshadow \ + -Wpointer-arith \ + -Wredundant-decls \ + -Wconversion \ + -Wsign-conversion \ + -Wno-long-long \ + -Wno-unknown-pragmas \ + -Wno-unused-command-line-argument \ + -O3 \ + -fomit-frame-pointer \ + -std=c99 \ + -pedantic \ + -MMD \ + $(CFLAGS) + +# If you want to use the native backends, the compiler needs to know about +# the target architecture. Here, we import the default host detection from +# mldsa-native's tests, but you can write your own or specialize accordingly. +AUTO ?= 1 +include auto.mk + +# The following only concerns the cross-compilation tests. +# You can likely ignore the following for your application. +# +# Append cross-prefix for cross compilation +# When called from the root Makefile, CROSS_PREFIX has already been added here +ifeq (,$(findstring $(CROSS_PREFIX),$(CC))) +CC := $(CROSS_PREFIX)$(CC) +endif + +# Part A: +# +# mldsa-native source and header files +# +# In this example, we compile the individual mldsa-native source files directly. +# Alternatively, you can compile the 'monobuild' source file mldsa_native.c. +# See examples/monolithic_build for that. +MLD_SOURCE=$(wildcard \ + mldsa_native/*.c \ + mldsa_native/**/*.c \ + mldsa_native/**/**/*.c \ + mldsa_native/**/**/**/*.c) + +INC=-Imldsa_native/ + +# Part B: +# +# Custom FIPS-202 implementation +FIPS202_SOURCE=custom_fips202/tiny_sha3/sha3.c + +# Part C: +# +# Random number generator +# +# !!! WARNING !!! +# +# The randombytes() implementation used here is for TESTING ONLY. +# You MUST NOT use this implementation outside of testing. +# +# !!! WARNING !!! +RNG_SOURCE=$(wildcard test_only_rng/*.c) + +# Part D: +# +# Your application source code +APP_SOURCE=$(wildcard *.c) + +ALL_SOURCE=$(MLD_SOURCE) $(FIPS202_SOURCE) $(RNG_SOURCE) $(APP_SOURCE) + +BUILD_DIR=build +BIN=test_binary + +BINARY_NAME_FULL_44=$(BUILD_DIR)/$(BIN)44 +BINARY_NAME_FULL_65=$(BUILD_DIR)/$(BIN)65 +BINARY_NAME_FULL_87=$(BUILD_DIR)/$(BIN)87 +BINARIES_FULL=$(BINARY_NAME_FULL_44) $(BINARY_NAME_FULL_65) $(BINARY_NAME_FULL_87) + +$(BINARY_NAME_FULL_44): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=44 +$(BINARY_NAME_FULL_65): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=65 +$(BINARY_NAME_FULL_87): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=87 + +$(BINARIES_FULL): $(ALL_SOURCE) + echo "$@" + mkdir -p $(BUILD_DIR) + $(CC) $(CFLAGS) $(INC) $^ -o $@ + +all: build + +build: $(BINARIES_FULL) + +run: $(BINARIES_FULL) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_44) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_65) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_87) + +clean: + rm -rf $(BUILD_DIR) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/README.md new file mode 100644 index 0000000000..6f2c58d885 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/README.md @@ -0,0 +1,49 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Bring Your Own FIPS-202 + +This directory contains a minimal example for using mldsa-native with a custom FIPS-202 (SHA-3/SHAKE) +implementation. We use tiny_sha3[^tiny_sha3] as an example. + +## Use Case + +Use this approach when: +- You need only one ML-DSA parameter set (44, 65, or 87) +- Your application already has a FIPS-202 software/hardware implementation you want to reuse + +## Components + +1. Arithmetic part of mldsa-native: [`mldsa/src/`](../../mldsa/src) (excluding `fips202/`) +2. A secure random number generator implementing [`randombytes.h`](../../mldsa/src/randombytes.h) +3. Custom FIPS-202 implementation with headers compatible with: + - [`fips202.h`](../../mldsa/src/fips202/fips202.h) + - [`fips202x4.h`](../../mldsa/src/fips202/fips202x4.h) +4. Your application source code + +## Configuration + +The configuration file [mldsa_native_config.h](mldsa_native/mldsa_native_config.h) sets: +- `MLD_CONFIG_FIPS202_CUSTOM_HEADER`: Path to your custom `fips202.h` +- `MLD_CONFIG_FIPS202X4_CUSTOM_HEADER`: Path to your custom `fips202x4.h` + +Your custom FIPS-202 implementation must impelement the API specified in [FIPS202.md](../../FIPS202.md). + +## Notes + +- The 4x batched functions (`x4`) can fall back to 4 sequential calls if batching isn't available +- Structure definitions may differ from mldsa-native's defaults (e.g., for incremental hashing) + +## Usage + +```bash +make build # Build the example +make run # Run the example +``` + +## Warning + +The `randombytes()` implementation in `test_only_rng/` is for TESTING ONLY. +You MUST provide a cryptographically secure RNG for production use. + + +[^tiny_sha3]: Markku-Juhani O. Saarinen: tiny_sha3, [https://github.com/mjosaarinen/tiny_sha3](https://github.com/mjosaarinen/tiny_sha3) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/auto.mk b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/auto.mk new file mode 100644 index 0000000000..5f71942085 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/auto.mk @@ -0,0 +1,178 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# Automatically detect system architecture and set preprocessor flags accordingly +# This file detects host CPU capabilities and combines them with compiler support +# to enable optimal compilation flags. +# +# Compiler feature detection can be overridden by setting the corresponding variable +# on the command line: +# make MK_COMPILER_SUPPORTS_SHA3=0 # Disable SHA3 detection +# make MK_COMPILER_SUPPORTS_AVX2=0 # Disable AVX2 detection +# make MK_COMPILER_SUPPORTS_BMI2=0 # Disable BMI2 detection +# make MK_COMPILER_SUPPORTS_SSE2=0 # Disable SSE2 detection + +ifndef _AUTO_MK +_AUTO_MK := + +# Override ARCH for cross-compilation based on CROSS_PREFIX +ifeq ($(CROSS_PREFIX),) +ARCH := $(shell uname -m) +# Normalize architecture names +ifeq ($(ARCH),arm64) +ARCH := aarch64 +endif +else # CROSS_PREFIX +ifneq ($(findstring x86_64, $(CROSS_PREFIX)),) +ARCH := x86_64 +else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),) +ARCH := aarch64_be +else ifneq ($(findstring aarch64, $(CROSS_PREFIX)),) +ARCH := aarch64 +else ifneq ($(findstring riscv64, $(CROSS_PREFIX)),) +ARCH := riscv64 +else ifneq ($(findstring riscv32, $(CROSS_PREFIX)),) +ARCH := riscv32 +else ifneq ($(findstring powerpc64le, $(CROSS_PREFIX)),) +ARCH := powerpc64le +else ifneq ($(findstring arm-none-eabi-, $(CROSS_PREFIX)),) +ARCH := arm +else +ifeq ($(AUTO),1) +$(warning Unknown cross-compilation prefix $(CROSS_PREFIX), no automatic detection of CFLAGS.) +ARCH := unknown +endif +endif +endif # CROSS_PREFIX + +# x86_64 compiler feature detection +ifeq ($(ARCH),x86_64) + +# Test AVX2 support using C with inline assembly +MK_COMPILER_SUPPORTS_AVX2 ?= $(shell echo 'int main() { __asm__("vpxor %%ymm0, %%ymm1, %%ymm2" ::: "ymm0", "ymm1", "ymm2"); return 0; }' | $(CC) -mavx2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test SSE2 support using C with inline assembly +MK_COMPILER_SUPPORTS_SSE2 ?= $(shell echo 'int main() { __asm__("pxor %%xmm0, %%xmm1" ::: "xmm0", "xmm1"); return 0; }' | $(CC) -msse2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test BMI2 support using C with inline assembly +MK_COMPILER_SUPPORTS_BMI2 ?= $(shell echo 'int main() { __asm__("pdep %%eax, %%ebx, %%ecx" ::: "eax", "ebx", "ecx"); return 0; }' | $(CC) -mbmi2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # x86_64 compiler detection + +# AArch64 compiler feature detection +ifeq ($(ARCH),aarch64) + +# Test SHA3 support (Armv8.4-a+SHA3) using C with inline assembly +MK_COMPILER_SUPPORTS_SHA3 ?= $(shell echo 'int main() { __asm__("eor3 v0.16b, v1.16b, v2.16b, v3.16b" ::: "v0", "v1", "v2", "v3"); return 0; }' | $(CC) -march=armv8.4-a+sha3 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # aarch64 compiler detection + +# Define HOST_PLATFORM if not already defined +HOST_PLATFORM ?= $(shell uname -s)-$(shell uname -m) + +# Helper function to check if host CPU supports a feature +# Usage: $(call check_host_feature,feature_pattern,source_command) +define check_host_feature +$(shell $(2) 2>/dev/null | grep -q "$(1)" && echo 1 || echo 0) +endef + +# x86_64 architecture detection +ifeq ($(ARCH),x86_64) + +# Host CPU feature detection for x86_64 +ifeq ($(HOST_PLATFORM),Linux-x86_64) +# Linux: Use /proc/cpuinfo +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,avx2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,sse2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,bmi2,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-x86_64) +# macOS: Use sysctl +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,AVX2,sysctl -n machdep.cpu.leaf7_features) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,SSE2,sysctl -n machdep.cpu.features) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,BMI2,sysctl -n machdep.cpu.leaf7_features) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_AVX2 := 1 +MK_HOST_SUPPORTS_SSE2 := 1 +MK_HOST_SUPPORTS_BMI2 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_AVX2 := 0 +MK_HOST_SUPPORTS_SSE2 := 0 +MK_HOST_SUPPORTS_BMI2 := 0 +endif # HOST_PLATFORM x86_64 + +endif # x86_64 + +# AArch64 architecture detection +ifeq ($(ARCH),aarch64) + +# Host CPU feature detection for AArch64 +ifeq ($(HOST_PLATFORM),Linux-aarch64) +# Linux: Use /proc/cpuinfo (look for sha3 in Features line) +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,sha3,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-arm64) +# macOS: Use sysctl to check for SHA3 support +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,1,sysctl -n hw.optional.armv8_2_sha3) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_SHA3 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_SHA3 := 0 +endif # HOST_PLATFORM aarch64 + +endif # aarch64 + +# Only apply CFLAGS modifications if AUTO=1 +ifeq ($(AUTO),1) + +# x86_64 CFLAGS configuration +ifeq ($(ARCH),x86_64) +CFLAGS += -DMLD_FORCE_X86_64 + +# Add flags only if both compiler and host support the feature +ifeq ($(MK_COMPILER_SUPPORTS_AVX2)$(MK_HOST_SUPPORTS_AVX2),11) +CFLAGS += -mavx2 +endif + +ifeq ($(MK_COMPILER_SUPPORTS_BMI2)$(MK_HOST_SUPPORTS_BMI2),11) +CFLAGS += -mbmi2 +endif +endif # x86_64 + +# AArch64 CFLAGS configuration +ifeq ($(ARCH),aarch64) +CFLAGS += -DMLD_FORCE_AARCH64 + +# Add SHA3 flags only if both compiler and host support it +ifeq ($(MK_COMPILER_SUPPORTS_SHA3)$(MK_HOST_SUPPORTS_SHA3),11) +CFLAGS += -march=armv8.4-a+sha3 +endif +endif # aarch64 + +# AArch64 Big Endian CFLAGS configuration +ifeq ($(ARCH),aarch64_be) +CFLAGS += -DMLD_FORCE_AARCH64_EB +endif # aarch64_be + +# RISC-V 64-bit CFLAGS configuration +ifeq ($(ARCH),riscv64) +CFLAGS += -DMLD_FORCE_RISCV64 +CFLAGS += -march=rv64gcv +endif # riscv64 + +# RISC-V 32-bit CFLAGS configuration +ifeq ($(ARCH),riscv32) +CFLAGS += -DMLD_FORCE_RISCV32 +endif # riscv32 + +# PowerPC 64-bit Little Endian CFLAGS configuration +ifeq ($(ARCH),powerpc64le) +CFLAGS += -DMLD_FORCE_PPC64LE +endif # powerpc64le + +endif # AUTO=1 + +endif # _AUTO_MK diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/custom_fips202/fips202.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/custom_fips202/fips202.h new file mode 100644 index 0000000000..2645a4b1cd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/custom_fips202/fips202.h @@ -0,0 +1,244 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * This is a shim establishing the FIPS-202 API required by mldsa-native + * from the API exposed by tiny_sha3. + */ + +#ifndef FIPS202_H +#define FIPS202_H + +#include +#include +#include +#include + +#include "tiny_sha3/sha3.h" + +/* We need the MLD_INLINE definition from sys.h */ +#ifndef MLD_INLINE +#if defined(__GNUC__) || defined(__clang__) +#define MLD_INLINE __attribute__((always_inline)) static inline +#else +#define MLD_INLINE static inline +#endif +#endif /* !MLD_INLINE */ + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 +#define SHA3_256_RATE 136 +#define SHA3_512_RATE 72 +#define SHA3_256_HASHBYTES 32 +#define SHA3_512_HASHBYTES 64 + +typedef enum +{ + FIPS202_STATE_ABSORBING = 1, + FIPS202_STATE_SQUEEZING = 2, + FIPS202_STATE_FINALIZED = 3, + FIPS202_STATE_RESET = 4 +} fips202_state_t; + +/* SHAKE128 context */ +typedef struct +{ + /* We introduce the explicit state as a mechanism to check that + * mldsa-native adheres to the FIPS202 state machine. You can safely + * remove this from your custom wrapper. */ + fips202_state_t state; + sha3_ctx_t ctx; +} mld_shake128ctx; + +/* SHAKE256 context */ +typedef struct +{ + fips202_state_t state; + sha3_ctx_t ctx; +} mld_shake256ctx; + +/************************************************* + * Name: mld_shake128_init + * + * Description: Initializes state for use as SHAKE128 XOF + * + * Arguments: - mld_shake128ctx *state: pointer to (uninitialized) state + **************************************************/ +#define mld_shake128_init MLD_NAMESPACE(shake128_init) +static MLD_INLINE void mld_shake128_init(mld_shake128ctx *state) +{ + shake128_init(&state->ctx); + state->state = FIPS202_STATE_ABSORBING; +} + +/************************************************* + * Name: mld_shake128_absorb + * + * Description: Absorb step of the SHAKE128 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake128ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +#define mld_shake128_absorb MLD_NAMESPACE(shake128_absorb) +static MLD_INLINE void mld_shake128_absorb(mld_shake128ctx *state, + const uint8_t *in, size_t inlen) +{ + assert(state->state == FIPS202_STATE_ABSORBING); + shake_update(&state->ctx, in, inlen); +} + +/************************************************* + * Name: mld_shake128_finalize + * + * Description: Concludes the absorb phase of the SHAKE128 XOF. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +#define mld_shake128_finalize MLD_NAMESPACE(shake128_finalize) +static MLD_INLINE void mld_shake128_finalize(mld_shake128ctx *state) +{ + assert(state->state == FIPS202_STATE_ABSORBING); + shake_xof(&state->ctx); + state->state = FIPS202_STATE_SQUEEZING; +} + +/************************************************* + * Name: mld_shake128_squeeze + * + * Description: Squeeze step of SHAKE128 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake128ctx *s: pointer to input/output state + **************************************************/ +#define mld_shake128_squeeze MLD_NAMESPACE(shake128_squeeze) +static MLD_INLINE void mld_shake128_squeeze(uint8_t *out, size_t outlen, + mld_shake128ctx *state) +{ + assert(state->state == FIPS202_STATE_SQUEEZING); + shake_out(&state->ctx, out, outlen); +} + +/************************************************* + * Name: mld_shake128_release + * + * Description: Release and securely zero the SHAKE128 state. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +#define mld_shake128_release MLD_NAMESPACE(shake128_release) +static MLD_INLINE void mld_shake128_release(mld_shake128ctx *state) +{ + memset(state, 0, sizeof(mld_shake128ctx)); + state->state = FIPS202_STATE_RESET; +} + +/************************************************* + * Name: mld_shake256_init + * + * Description: Initializes state for use as SHAKE256 XOF + * + * Arguments: - mld_shake256ctx *state: pointer to (uninitialized) state + **************************************************/ +#define mld_shake256_init MLD_NAMESPACE(shake256_init) +static MLD_INLINE void mld_shake256_init(mld_shake256ctx *state) +{ + shake256_init(&state->ctx); + state->state = FIPS202_STATE_ABSORBING; +} + +/************************************************* + * Name: mld_shake256_absorb + * + * Description: Absorb step of the SHAKE256 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake256ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +#define mld_shake256_absorb MLD_NAMESPACE(shake256_absorb) +static MLD_INLINE void mld_shake256_absorb(mld_shake256ctx *state, + const uint8_t *in, size_t inlen) +{ + assert(state->state == FIPS202_STATE_ABSORBING); + shake_update(&state->ctx, in, inlen); +} + +/************************************************* + * Name: mld_shake256_finalize + * + * Description: Concludes the absorb phase of the SHAKE256 XOF. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +#define mld_shake256_finalize MLD_NAMESPACE(shake256_finalize) +static MLD_INLINE void mld_shake256_finalize(mld_shake256ctx *state) +{ + assert(state->state == FIPS202_STATE_ABSORBING); + shake_xof(&state->ctx); + state->state = FIPS202_STATE_SQUEEZING; +} + +/************************************************* + * Name: mld_shake256_squeeze + * + * Description: Squeeze step of SHAKE256 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake256ctx *s: pointer to input/output state + **************************************************/ +#define mld_shake256_squeeze MLD_NAMESPACE(shake256_squeeze) +static MLD_INLINE void mld_shake256_squeeze(uint8_t *out, size_t outlen, + mld_shake256ctx *state) +{ + assert(state->state == FIPS202_STATE_SQUEEZING); + shake_out(&state->ctx, out, outlen); +} + +/************************************************* + * Name: mld_shake256_release + * + * Description: Release and securely zero the SHAKE256 state. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +#define mld_shake256_release MLD_NAMESPACE(shake256_release) +static MLD_INLINE void mld_shake256_release(mld_shake256ctx *state) +{ + memset(state, 0, sizeof(mld_shake256ctx)); + state->state = FIPS202_STATE_RESET; +} + +/************************************************* + * Name: mld_shake256 + * + * Description: SHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +#define mld_shake256 MLD_NAMESPACE(shake256) +static MLD_INLINE void mld_shake256(uint8_t *out, size_t outlen, + const uint8_t *in, size_t inlen) +{ + sha3_ctx_t c; + shake256_init(&c); + shake_update(&c, in, inlen); + shake_xof(&c); + shake_out(&c, out, outlen); +} + +#endif /* !FIPS202_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/custom_fips202/fips202x4.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/custom_fips202/fips202x4.h new file mode 100644 index 0000000000..906d753525 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/custom_fips202/fips202x4.h @@ -0,0 +1,217 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * This is a shim establishing the FIPS-202x4 API required by mldsa-native + * using a serial implementation based on tiny_sha3. + * + * NOTE: This is a simple serial implementation that does not provide + * any performance benefits from parallelization. For production use, + * consider using an optimized parallel implementation. + */ + +#ifndef FIPS_202X4_H +#define FIPS_202X4_H + +#include +#include +#include +#include + +#include "fips202.h" + +/* For MLD_KECCAK_WAY - typically 4 */ +#ifndef MLD_KECCAK_WAY +#define MLD_KECCAK_WAY 4 +#endif + +typedef struct +{ + fips202_state_t state; + mld_shake128ctx ctx[4]; +} mld_shake128x4ctx; + +typedef struct +{ + fips202_state_t state; + mld_shake256ctx ctx[4]; +} mld_shake256x4ctx; + +/************************************************* + * Name: mld_shake128x4_init + * + * Description: Initialize 4 parallel SHAKE128 contexts + * + * Arguments: - mld_shake128x4ctx *state: pointer to state + **************************************************/ +#define mld_shake128x4_init MLD_NAMESPACE(shake128x4_init) +static MLD_INLINE void mld_shake128x4_init(mld_shake128x4ctx *state) +{ + mld_shake128_init(&state->ctx[0]); + mld_shake128_init(&state->ctx[1]); + mld_shake128_init(&state->ctx[2]); + mld_shake128_init(&state->ctx[3]); + state->state = FIPS202_STATE_ABSORBING; +} + +/************************************************* + * Name: mld_shake128x4_absorb_once + * + * Description: Absorb step for 4 parallel SHAKE128 contexts + * + * Arguments: - mld_shake128x4ctx *state: pointer to state + * - const uint8_t *in0-3: pointers to input data + * - size_t inlen: length of input in bytes + **************************************************/ +#define mld_shake128x4_absorb_once MLD_NAMESPACE(shake128x4_absorb_once) +static MLD_INLINE void mld_shake128x4_absorb_once( + mld_shake128x4ctx *state, const uint8_t *in0, const uint8_t *in1, + const uint8_t *in2, const uint8_t *in3, size_t inlen) +{ + assert(state->state == FIPS202_STATE_ABSORBING); + + mld_shake128_absorb(&state->ctx[0], in0, inlen); + mld_shake128_finalize(&state->ctx[0]); + + mld_shake128_absorb(&state->ctx[1], in1, inlen); + mld_shake128_finalize(&state->ctx[1]); + + mld_shake128_absorb(&state->ctx[2], in2, inlen); + mld_shake128_finalize(&state->ctx[2]); + + mld_shake128_absorb(&state->ctx[3], in3, inlen); + mld_shake128_finalize(&state->ctx[3]); + + state->state = FIPS202_STATE_SQUEEZING; +} + +/************************************************* + * Name: mld_shake128x4_squeezeblocks + * + * Description: Squeeze blocks from 4 parallel SHAKE128 contexts + * + * Arguments: - uint8_t *out0-3: pointers to output buffers + * - size_t nblocks: number of blocks to squeeze + * - mld_shake128x4ctx *state: pointer to state + **************************************************/ +#define mld_shake128x4_squeezeblocks MLD_NAMESPACE(shake128x4_squeezeblocks) +static MLD_INLINE void mld_shake128x4_squeezeblocks( + uint8_t *out0, uint8_t *out1, uint8_t *out2, uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +{ + assert(state->state == FIPS202_STATE_SQUEEZING); + + mld_shake128_squeeze(out0, nblocks * SHAKE128_RATE, &state->ctx[0]); + mld_shake128_squeeze(out1, nblocks * SHAKE128_RATE, &state->ctx[1]); + mld_shake128_squeeze(out2, nblocks * SHAKE128_RATE, &state->ctx[2]); + mld_shake128_squeeze(out3, nblocks * SHAKE128_RATE, &state->ctx[3]); +} + +/************************************************* + * Name: mld_shake128x4_release + * + * Description: Release 4 parallel SHAKE128 contexts + * + * Arguments: - mld_shake128x4ctx *state: pointer to state + **************************************************/ +#define mld_shake128x4_release MLD_NAMESPACE(shake128x4_release) +static MLD_INLINE void mld_shake128x4_release(mld_shake128x4ctx *state) +{ + mld_shake128_release(&state->ctx[0]); + mld_shake128_release(&state->ctx[1]); + mld_shake128_release(&state->ctx[2]); + mld_shake128_release(&state->ctx[3]); + state->state = FIPS202_STATE_RESET; +} + +/************************************************* + * Name: mld_shake256x4_init + * + * Description: Initialize 4 parallel SHAKE256 contexts + * + * Arguments: - mld_shake256x4ctx *state: pointer to state + **************************************************/ +#define mld_shake256x4_init MLD_NAMESPACE(shake256x4_init) +static MLD_INLINE void mld_shake256x4_init(mld_shake256x4ctx *state) +{ + mld_shake256_init(&state->ctx[0]); + mld_shake256_init(&state->ctx[1]); + mld_shake256_init(&state->ctx[2]); + mld_shake256_init(&state->ctx[3]); + state->state = FIPS202_STATE_ABSORBING; +} + +/************************************************* + * Name: mld_shake256x4_absorb_once + * + * Description: Absorb step for 4 parallel SHAKE256 contexts + * + * Arguments: - mld_shake256x4ctx *state: pointer to state + * - const uint8_t *in0-3: pointers to input data + * - size_t inlen: length of input in bytes + **************************************************/ +#define mld_shake256x4_absorb_once MLD_NAMESPACE(shake256x4_absorb_once) +static MLD_INLINE void mld_shake256x4_absorb_once( + mld_shake256x4ctx *state, const uint8_t *in0, const uint8_t *in1, + const uint8_t *in2, const uint8_t *in3, size_t inlen) +{ + assert(state->state == FIPS202_STATE_ABSORBING); + + mld_shake256_absorb(&state->ctx[0], in0, inlen); + mld_shake256_finalize(&state->ctx[0]); + + mld_shake256_absorb(&state->ctx[1], in1, inlen); + mld_shake256_finalize(&state->ctx[1]); + + mld_shake256_absorb(&state->ctx[2], in2, inlen); + mld_shake256_finalize(&state->ctx[2]); + + mld_shake256_absorb(&state->ctx[3], in3, inlen); + mld_shake256_finalize(&state->ctx[3]); + + state->state = FIPS202_STATE_SQUEEZING; +} + +/************************************************* + * Name: mld_shake256x4_squeezeblocks + * + * Description: Squeeze blocks from 4 parallel SHAKE256 contexts + * + * Arguments: - uint8_t *out0-3: pointers to output buffers + * - size_t nblocks: number of blocks to squeeze + * - mld_shake256x4ctx *state: pointer to state + **************************************************/ +#define mld_shake256x4_squeezeblocks MLD_NAMESPACE(shake256x4_squeezeblocks) +static MLD_INLINE void mld_shake256x4_squeezeblocks( + uint8_t *out0, uint8_t *out1, uint8_t *out2, uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +{ + assert(state->state == FIPS202_STATE_SQUEEZING); + + mld_shake256_squeeze(out0, nblocks * SHAKE256_RATE, &state->ctx[0]); + mld_shake256_squeeze(out1, nblocks * SHAKE256_RATE, &state->ctx[1]); + mld_shake256_squeeze(out2, nblocks * SHAKE256_RATE, &state->ctx[2]); + mld_shake256_squeeze(out3, nblocks * SHAKE256_RATE, &state->ctx[3]); +} + +/************************************************* + * Name: mld_shake256x4_release + * + * Description: Release 4 parallel SHAKE256 contexts + * + * Arguments: - mld_shake256x4ctx *state: pointer to state + **************************************************/ +#define mld_shake256x4_release MLD_NAMESPACE(shake256x4_release) +static MLD_INLINE void mld_shake256x4_release(mld_shake256x4ctx *state) +{ + mld_shake256_release(&state->ctx[0]); + mld_shake256_release(&state->ctx[1]); + mld_shake256_release(&state->ctx[2]); + mld_shake256_release(&state->ctx[3]); + state->state = FIPS202_STATE_RESET; +} + +#endif /* !FIPS_202X4_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/custom_fips202/tiny_sha3/sha3.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/custom_fips202/tiny_sha3/sha3.c new file mode 100644 index 0000000000..d344b0f148 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/custom_fips202/tiny_sha3/sha3.c @@ -0,0 +1,207 @@ +/* SPDX-License-Identifier: MIT + * + * sha3.c + * 19-Nov-11 Markku-Juhani O. Saarinen */ + +/* Revised 07-Aug-15 to match with official release of FIPS PUB 202 "SHA3" */ +/* Revised 03-Sep-15 for portability + OpenSSL - style API */ + +#include "sha3.h" + +/* update the state with given number of rounds */ + +void sha3_keccakf(uint64_t st[25]) +{ + /* constants */ + const uint64_t keccakf_rndc[24] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008}; + const int keccakf_rotc[24] = {1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44}; + const int keccakf_piln[24] = {10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1}; + + /* variables */ + int i, j, r; + uint64_t t, bc[5]; + +#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ + uint8_t *v; + + /* endianness conversion. this is redundant on little-endian targets */ + for (i = 0; i < 25; i++) + { + v = (uint8_t *)&st[i]; + st[i] = ((uint64_t)v[0]) | (((uint64_t)v[1]) << 8) | + (((uint64_t)v[2]) << 16) | (((uint64_t)v[3]) << 24) | + (((uint64_t)v[4]) << 32) | (((uint64_t)v[5]) << 40) | + (((uint64_t)v[6]) << 48) | (((uint64_t)v[7]) << 56); + } +#endif /* __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ */ + + /* actual iteration */ + for (r = 0; r < KECCAKF_ROUNDS; r++) + { + /* Theta */ + for (i = 0; i < 5; i++) + { + bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20]; + } + + for (i = 0; i < 5; i++) + { + t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); + for (j = 0; j < 25; j += 5) + { + st[j + i] ^= t; + } + } + + /* Rho Pi */ + t = st[1]; + for (i = 0; i < 24; i++) + { + j = keccakf_piln[i]; + bc[0] = st[j]; + st[j] = ROTL64(t, keccakf_rotc[i]); + t = bc[0]; + } + + /* Chi */ + for (j = 0; j < 25; j += 5) + { + for (i = 0; i < 5; i++) + { + bc[i] = st[j + i]; + } + for (i = 0; i < 5; i++) + { + st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; + } + } + + /* Iota */ + st[0] ^= keccakf_rndc[r]; + } + +#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ + /* endianness conversion. this is redundant on little-endian targets */ + for (i = 0; i < 25; i++) + { + v = (uint8_t *)&st[i]; + t = st[i]; + v[0] = (uint8_t)(t & 0xFF); + v[1] = (uint8_t)((t >> 8) & 0xFF); + v[2] = (uint8_t)((t >> 16) & 0xFF); + v[3] = (uint8_t)((t >> 24) & 0xFF); + v[4] = (uint8_t)((t >> 32) & 0xFF); + v[5] = (uint8_t)((t >> 40) & 0xFF); + v[6] = (uint8_t)((t >> 48) & 0xFF); + v[7] = (uint8_t)((t >> 56) & 0xFF); + } +#endif /* __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ */ +} + +/* Initialize the context for SHA3 */ + +int sha3_init(sha3_ctx_t *c, int mdlen) +{ + int i; + + for (i = 0; i < 25; i++) + { + c->st.q[i] = 0; + } + c->mdlen = mdlen; + c->rsiz = 200 - 2 * mdlen; + c->pt = 0; + + return 1; +} + +/* update state with more data */ + +int sha3_update(sha3_ctx_t *c, const void *data, size_t len) +{ + size_t i; + int j; + + j = c->pt; + for (i = 0; i < len; i++) + { + c->st.b[j++] ^= ((const uint8_t *)data)[i]; + if (j >= c->rsiz) + { + sha3_keccakf(c->st.q); + j = 0; + } + } + c->pt = j; + + return 1; +} + +/* finalize and output a hash */ + +int sha3_final(void *md, sha3_ctx_t *c) +{ + int i; + + c->st.b[c->pt] ^= 0x06; + c->st.b[c->rsiz - 1] ^= 0x80; + sha3_keccakf(c->st.q); + + for (i = 0; i < c->mdlen; i++) + { + ((uint8_t *)md)[i] = c->st.b[i]; + } + + return 1; +} + +/* compute a SHA-3 hash (md) of given byte length from "in" */ + +void *sha3(const void *in, size_t inlen, void *md, int mdlen) +{ + sha3_ctx_t sha3; + + sha3_init(&sha3, mdlen); + sha3_update(&sha3, in, inlen); + sha3_final(md, &sha3); + + return md; +} + +/* SHAKE128 and SHAKE256 extensible-output functionality */ + +void shake_xof(sha3_ctx_t *c) +{ + c->st.b[c->pt] ^= 0x1F; + c->st.b[c->rsiz - 1] ^= 0x80; + sha3_keccakf(c->st.q); + c->pt = 0; +} + +void shake_out(sha3_ctx_t *c, void *out, size_t len) +{ + size_t i; + int j; + + j = c->pt; + for (i = 0; i < len; i++) + { + if (j >= c->rsiz) + { + sha3_keccakf(c->st.q); + j = 0; + } + ((uint8_t *)out)[i] = c->st.b[j++]; + } + c->pt = j; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/custom_fips202/tiny_sha3/sha3.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/custom_fips202/tiny_sha3/sha3.h new file mode 100644 index 0000000000..158ca86486 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/custom_fips202/tiny_sha3/sha3.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: MIT + * + * sha3.h + * 19-Nov-11 Markku-Juhani O. Saarinen */ + +#ifndef SHA3_H +#define SHA3_H + +#include +#include + +#ifndef KECCAKF_ROUNDS +#define KECCAKF_ROUNDS 24 +#endif + +#ifndef ROTL64 +#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) +#endif + +/* state context */ +typedef struct +{ + union + { /* state: */ + uint8_t b[200]; /* 8-bit bytes */ + uint64_t q[25]; /* 64-bit words */ + } st; + int pt, rsiz, mdlen; /* these don't overflow */ +} sha3_ctx_t; + +/* Compression function. */ +void sha3_keccakf(uint64_t st[25]); + +/* OpenSSL - like interfece */ +int sha3_init(sha3_ctx_t *c, int mdlen); /* mdlen = hash output in bytes */ +int sha3_update(sha3_ctx_t *c, const void *data, size_t len); +int sha3_final(void *md, sha3_ctx_t *c); /* digest goes to md */ + +/* compute a sha3 hash (md) of given byte length from "in" */ +void *sha3(const void *in, size_t inlen, void *md, int mdlen); + +/* SHAKE128 and SHAKE256 extensible-output functions */ +#define shake128_init(c) sha3_init(c, 16) +#define shake256_init(c) sha3_init(c, 32) +#define shake_update sha3_update + +void shake_xof(sha3_ctx_t *c); +void shake_out(sha3_ctx_t *c, void *out, size_t len); + +#endif /* !SHA3_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/expected_signatures.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/expected_signatures.h new file mode 100644 index 0000000000..d52fbe8d5e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/expected_signatures.h @@ -0,0 +1,890 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef EXPECTED_SIGNATURES_H +#define EXPECTED_SIGNATURES_H + +#include + +/* Expected deterministic signatures for each parameter set + * These are generated using the same test message, context, and deterministic + * RNG as used in the basic example. + * + * The PCT modifies the PRNG state, so the KAT tests don't work. + * We run KAT tests only for disabled PCT. */ +#if !defined(MLD_CONFIG_KEYGEN_PCT) +#if MLD_CONFIG_PARAMETER_SET == 44 +const uint8_t expected_signature[] = { + 0x27, 0x5e, 0xbe, 0x2d, 0x23, 0x1a, 0x76, 0xc5, 0xd9, 0x77, 0xcb, 0x62, + 0x25, 0x04, 0xdb, 0x23, 0x31, 0xa9, 0xa8, 0xcd, 0xbc, 0xde, 0xf2, 0x20, + 0xfd, 0xa7, 0xb5, 0xf5, 0x59, 0xae, 0xe6, 0xdd, 0x62, 0xfa, 0x34, 0x96, + 0x4f, 0x1d, 0xcd, 0x84, 0x82, 0xee, 0xc1, 0x74, 0x96, 0x3d, 0x98, 0xd9, + 0x42, 0x9d, 0xd0, 0x77, 0x9c, 0xf9, 0x9e, 0x0e, 0xa7, 0xcb, 0x70, 0xeb, + 0xe7, 0xcd, 0xce, 0x8c, 0xdc, 0x37, 0x15, 0x95, 0x0e, 0x24, 0x70, 0x4f, + 0x33, 0x6e, 0x4f, 0xad, 0xed, 0x4d, 0xf3, 0xe5, 0x38, 0xc1, 0xcd, 0xbb, + 0xde, 0xf1, 0xd2, 0x0d, 0xd6, 0x6b, 0xa3, 0x68, 0x92, 0x4c, 0x4b, 0x4f, + 0x89, 0xa0, 0xa8, 0xc8, 0x36, 0x93, 0x91, 0x17, 0xe7, 0x16, 0xed, 0xcb, + 0xdc, 0xf6, 0x28, 0x13, 0x32, 0x60, 0x14, 0xe0, 0x28, 0x7a, 0x69, 0x05, + 0x1d, 0xf7, 0x3b, 0xdf, 0x18, 0x0c, 0xaf, 0xba, 0x46, 0xf1, 0x5e, 0xd4, + 0xd3, 0xd0, 0x8e, 0x9a, 0xe2, 0xac, 0xdd, 0x0e, 0x5f, 0xb1, 0x69, 0xe2, + 0x74, 0x77, 0x2e, 0x52, 0xf9, 0x11, 0x3d, 0xd8, 0xe5, 0x36, 0x6f, 0x7d, + 0x7d, 0xde, 0x7c, 0xa7, 0x1d, 0x37, 0xdf, 0x6d, 0x5e, 0xea, 0xc8, 0xc0, + 0x72, 0x3f, 0x79, 0xbd, 0x0b, 0x6d, 0x7f, 0x9a, 0x15, 0x90, 0xda, 0xc1, + 0xae, 0xce, 0xf3, 0x44, 0x35, 0x5e, 0x83, 0x86, 0x7e, 0x89, 0x18, 0xa7, + 0x97, 0x8e, 0x87, 0x7c, 0x15, 0xd2, 0xd2, 0x7e, 0xf2, 0xc8, 0x29, 0x4f, + 0x70, 0x0f, 0xa6, 0xd4, 0x76, 0xe8, 0xdd, 0x7d, 0x7a, 0x2d, 0xfe, 0x0a, + 0x0c, 0x5c, 0xb1, 0xef, 0xec, 0x1a, 0x32, 0xca, 0x87, 0xff, 0x6b, 0xb1, + 0xa0, 0xe1, 0x2e, 0x01, 0x52, 0xb2, 0xb8, 0x74, 0x34, 0xb3, 0xfb, 0x15, + 0x0f, 0x17, 0xca, 0x74, 0xc1, 0xc1, 0x61, 0x86, 0x40, 0x38, 0x58, 0xba, + 0x82, 0x26, 0x66, 0x33, 0xa4, 0x52, 0xf3, 0xb5, 0x36, 0x60, 0xd8, 0x5a, + 0x8d, 0x9d, 0x28, 0x18, 0x3a, 0x68, 0x34, 0x2a, 0xa2, 0xe2, 0xb5, 0x39, + 0xed, 0x7d, 0xe5, 0xbe, 0x46, 0xb9, 0x04, 0x0c, 0xf3, 0xef, 0x88, 0x6e, + 0x9d, 0x6f, 0x23, 0xe2, 0x44, 0xe5, 0x2e, 0x3a, 0x7a, 0x1d, 0x49, 0x0f, + 0xdd, 0xcd, 0xd6, 0x4e, 0x0d, 0x0b, 0xc3, 0x35, 0xf2, 0xd1, 0x5d, 0x73, + 0x5d, 0x07, 0xca, 0x5c, 0xbd, 0x14, 0xec, 0x57, 0xb3, 0xbd, 0x37, 0xe7, + 0xdf, 0x06, 0x7d, 0xe0, 0x58, 0x4a, 0xcf, 0x7a, 0xc5, 0xa7, 0x24, 0x62, + 0x6f, 0x09, 0x75, 0x69, 0x74, 0x7f, 0xdf, 0xc8, 0x69, 0x5c, 0x20, 0x10, + 0x3a, 0xe8, 0x01, 0x12, 0xa3, 0xfb, 0xda, 0x4c, 0x3a, 0x0d, 0x3c, 0x3e, + 0x26, 0xe0, 0xa6, 0x7f, 0xb2, 0x6b, 0x0b, 0x68, 0x0a, 0x68, 0x86, 0xb1, + 0xfa, 0x61, 0x3a, 0xe8, 0x77, 0xdc, 0x42, 0xf7, 0xf4, 0x39, 0x9a, 0x40, + 0x58, 0x71, 0xc7, 0x0f, 0xf4, 0x0e, 0xc5, 0x1e, 0xe0, 0x28, 0x45, 0x7d, + 0xba, 0x84, 0xe4, 0x34, 0x69, 0xf9, 0xa5, 0x8a, 0x80, 0x43, 0xc0, 0x8d, + 0x04, 0x33, 0x43, 0xb8, 0xd7, 0x5d, 0x93, 0xed, 0x0f, 0x31, 0x6a, 0x4d, + 0xbf, 0xb7, 0x44, 0x41, 0x1b, 0xd4, 0xac, 0x9d, 0x83, 0x66, 0x08, 0x92, + 0xad, 0x3c, 0x0e, 0x1a, 0xe8, 0xd4, 0xe1, 0x5c, 0x63, 0xcf, 0x27, 0x48, + 0x5a, 0x8f, 0xc5, 0x6f, 0x83, 0x6b, 0x6f, 0xe8, 0xda, 0x1f, 0xba, 0xe9, + 0x7e, 0x11, 0xab, 0x8b, 0x4e, 0xc1, 0x9e, 0x23, 0x69, 0x1f, 0x42, 0x40, + 0xad, 0xbb, 0xfb, 0x4f, 0xe2, 0x50, 0xc9, 0x46, 0xe7, 0x15, 0x15, 0xf8, + 0x61, 0x09, 0x2a, 0x0b, 0x37, 0x43, 0xd4, 0x98, 0x5f, 0xc8, 0x4d, 0x06, + 0xe7, 0x0c, 0x3f, 0x83, 0x59, 0xd5, 0xcd, 0x2d, 0xde, 0x1e, 0x3a, 0x87, + 0x4e, 0xf7, 0x0a, 0x3c, 0x84, 0x72, 0x47, 0x11, 0x02, 0x6c, 0xe8, 0x93, + 0xcd, 0x24, 0xe9, 0x23, 0x86, 0x78, 0x53, 0xe0, 0xc6, 0x2f, 0xba, 0xa7, + 0xed, 0xaf, 0xba, 0x42, 0x80, 0x0d, 0xe6, 0xae, 0xda, 0xed, 0xbc, 0x65, + 0x21, 0x6d, 0x13, 0x90, 0x61, 0xb4, 0x05, 0x7b, 0x07, 0x86, 0xd7, 0x89, + 0x30, 0x9c, 0xc1, 0x9a, 0x41, 0x4d, 0xe8, 0x2b, 0x35, 0x21, 0x3a, 0x8a, + 0x60, 0x83, 0x1a, 0x97, 0x10, 0x98, 0xb6, 0xe1, 0x6b, 0xb5, 0xb1, 0xa1, + 0x36, 0x34, 0x60, 0x1b, 0x96, 0x5d, 0x1f, 0x2a, 0xd8, 0xf2, 0x94, 0xdd, + 0x58, 0x3d, 0x0f, 0xbe, 0x9d, 0xfc, 0xf5, 0x24, 0xb1, 0xd2, 0xc3, 0x36, + 0xef, 0xdb, 0x8e, 0x97, 0x3c, 0x9a, 0x4f, 0x48, 0xe3, 0x84, 0x91, 0xd8, + 0x39, 0x91, 0xf6, 0x55, 0xeb, 0x62, 0x51, 0x3d, 0x8f, 0x55, 0x60, 0x5e, + 0x00, 0xe0, 0xd2, 0xc7, 0x66, 0x51, 0xf1, 0xe2, 0xb7, 0x43, 0xc3, 0xe6, + 0x12, 0x9a, 0xe5, 0x84, 0xe0, 0x10, 0x76, 0xc7, 0x75, 0x6e, 0xa6, 0xee, + 0x11, 0xe4, 0xaf, 0xbd, 0x8a, 0x4f, 0x1d, 0x05, 0x29, 0x4f, 0xce, 0xa5, + 0x73, 0x92, 0x57, 0x7e, 0x0d, 0x11, 0xbc, 0xf8, 0x74, 0x4d, 0xf7, 0xb9, + 0x40, 0x0d, 0x5a, 0xa1, 0x19, 0x76, 0x4a, 0xae, 0x21, 0x16, 0xd4, 0x3f, + 0x76, 0xbf, 0x27, 0xbd, 0x2f, 0xe4, 0x25, 0x21, 0x00, 0x4e, 0xcc, 0x7c, + 0xc6, 0x57, 0xa4, 0xbf, 0xf1, 0x56, 0x90, 0xe0, 0xa4, 0xa3, 0xee, 0xcf, + 0x43, 0x4f, 0xda, 0x77, 0x47, 0x51, 0x79, 0x6a, 0x29, 0xb4, 0x2c, 0xdf, + 0xca, 0x47, 0xcb, 0xb8, 0x82, 0x7e, 0x44, 0x62, 0x9b, 0x8f, 0x61, 0x7b, + 0x3a, 0x93, 0x82, 0x1f, 0x69, 0xb7, 0xb1, 0xa6, 0x2c, 0xe1, 0xb2, 0x65, + 0xa0, 0x6d, 0x6f, 0xe4, 0x79, 0xd8, 0x30, 0xe0, 0xee, 0xd8, 0x83, 0x01, + 0xb2, 0x1f, 0x5c, 0x90, 0x44, 0x86, 0x48, 0x11, 0xf9, 0x11, 0xff, 0xea, + 0x45, 0x43, 0xae, 0x8a, 0x6b, 0x99, 0xf2, 0x1f, 0x02, 0x51, 0x4a, 0x35, + 0x02, 0x34, 0xd3, 0xe8, 0xda, 0xb1, 0x4b, 0xe3, 0xa5, 0x60, 0xce, 0x67, + 0xe3, 0x62, 0x59, 0xfc, 0x00, 0x0a, 0xe2, 0xfe, 0x7b, 0x1e, 0xe6, 0xf5, + 0x75, 0x19, 0x9b, 0x5e, 0xcb, 0xe6, 0xf5, 0x80, 0x9e, 0x3c, 0xb8, 0x54, + 0xd6, 0x0b, 0xfd, 0x48, 0xe0, 0xfa, 0x82, 0x2b, 0x5b, 0x26, 0xf9, 0x49, + 0xaf, 0xbe, 0x9c, 0x78, 0x73, 0xce, 0xc5, 0x65, 0xe2, 0x94, 0x2b, 0xd9, + 0xd0, 0x27, 0x3a, 0x66, 0x3e, 0xe2, 0xe0, 0x10, 0x79, 0x3d, 0xde, 0xc8, + 0x47, 0xdb, 0x1e, 0xc3, 0xe7, 0x51, 0xae, 0x59, 0xeb, 0x38, 0x66, 0x63, + 0x40, 0x8f, 0xbe, 0x1e, 0xb2, 0x2b, 0xeb, 0x64, 0x5f, 0xdd, 0x24, 0xc4, + 0x5a, 0x25, 0x59, 0xa2, 0xda, 0x4f, 0xdf, 0xf8, 0xb0, 0xb0, 0xf7, 0xcd, + 0x1f, 0x14, 0xcd, 0x09, 0x48, 0x70, 0x27, 0x1b, 0xde, 0xc4, 0xf0, 0xf3, + 0x56, 0x97, 0x8a, 0xb7, 0xf4, 0x19, 0x76, 0xe3, 0x9a, 0x33, 0x55, 0xfe, + 0x93, 0x68, 0xca, 0x1f, 0x3d, 0x44, 0x86, 0x39, 0x5d, 0x84, 0x58, 0x50, + 0xf2, 0xf1, 0xea, 0x4a, 0x5c, 0x1c, 0x74, 0xf0, 0x4b, 0xa5, 0x9c, 0x30, + 0xa0, 0x14, 0x1a, 0x80, 0xe0, 0xde, 0x3e, 0xae, 0x7f, 0x10, 0x18, 0x4a, + 0x1e, 0x9e, 0x6b, 0x75, 0x1a, 0xca, 0x08, 0x4e, 0x61, 0x72, 0x43, 0x9b, + 0x18, 0x4d, 0x2c, 0xd8, 0xb4, 0xc9, 0xea, 0x00, 0xb0, 0xdf, 0x1b, 0xcb, + 0x03, 0xc3, 0x7a, 0x27, 0xff, 0x41, 0x9d, 0xf9, 0xfd, 0xb3, 0x0c, 0xc0, + 0x48, 0x5d, 0x7c, 0xae, 0x5a, 0x72, 0x69, 0x93, 0x68, 0xe1, 0x9e, 0x9f, + 0x1f, 0x5c, 0x0a, 0x60, 0x90, 0x1a, 0x8e, 0x5a, 0x30, 0xd4, 0x2c, 0xbd, + 0xe1, 0x20, 0x51, 0xbc, 0x1c, 0x50, 0xb5, 0xf7, 0x42, 0x23, 0x35, 0x0f, + 0x92, 0xe2, 0xbb, 0x2a, 0x04, 0xa7, 0xde, 0x2e, 0x25, 0xfa, 0xed, 0x20, + 0x83, 0x9c, 0xd4, 0x56, 0xe0, 0x4d, 0x8d, 0x79, 0xa5, 0xa0, 0x6f, 0x49, + 0x62, 0x82, 0x9a, 0xa7, 0x4e, 0x54, 0x95, 0x0a, 0xc6, 0x5e, 0x27, 0x65, + 0x6d, 0x11, 0x2b, 0x35, 0x72, 0x34, 0x48, 0xd2, 0xe4, 0x9e, 0x07, 0x7d, + 0x03, 0x27, 0x15, 0x93, 0x55, 0x5c, 0x32, 0x43, 0xdb, 0x34, 0x8d, 0xbd, + 0x8d, 0x88, 0xa5, 0x24, 0x07, 0x93, 0x89, 0x37, 0xb9, 0x17, 0x15, 0xad, + 0xc7, 0x68, 0x86, 0x63, 0x0f, 0x10, 0x53, 0x8f, 0x40, 0xd3, 0x7b, 0x22, + 0x2b, 0x1a, 0x4c, 0xcb, 0x4f, 0x51, 0xf1, 0x3b, 0x19, 0xb8, 0x42, 0x53, + 0xaf, 0xf6, 0xb9, 0x57, 0x7f, 0xba, 0x8d, 0xb8, 0xb7, 0x3b, 0xe3, 0xc5, + 0xab, 0x4a, 0x26, 0x21, 0x6e, 0xce, 0x27, 0xb8, 0xc3, 0x99, 0x56, 0x14, + 0xdd, 0x5b, 0x61, 0x82, 0xbf, 0xd3, 0xc8, 0x76, 0xee, 0x22, 0xaf, 0x21, + 0x21, 0x1d, 0x4e, 0x33, 0xb5, 0x43, 0x3a, 0xfb, 0x91, 0xa0, 0xaa, 0xe3, + 0x10, 0x4a, 0x50, 0x42, 0xd4, 0x5f, 0x92, 0x0e, 0x71, 0x60, 0x4f, 0xaa, + 0xef, 0x66, 0x45, 0xfe, 0xf7, 0xc8, 0xb0, 0x73, 0x75, 0x91, 0x0b, 0x86, + 0x40, 0xa5, 0x02, 0x28, 0xf7, 0xe0, 0x1f, 0x5d, 0xe6, 0xe3, 0xa4, 0x57, + 0xbd, 0x29, 0xaa, 0x53, 0xae, 0x35, 0x30, 0x78, 0x73, 0xd6, 0xb7, 0x01, + 0x9d, 0x13, 0x50, 0xf6, 0x39, 0xa2, 0x3e, 0x03, 0x04, 0xaa, 0x6d, 0xcf, + 0x6b, 0xff, 0x9a, 0xbe, 0x3e, 0x0a, 0xd4, 0x20, 0xce, 0x42, 0x1f, 0xca, + 0x2f, 0xd3, 0x2c, 0xd1, 0xf4, 0xd2, 0x50, 0xd3, 0xa2, 0xc1, 0x1e, 0x87, + 0xbf, 0xeb, 0xb8, 0xa8, 0xd4, 0x1c, 0x96, 0xb8, 0x8e, 0xbe, 0x35, 0x5f, + 0x08, 0x28, 0x20, 0x2b, 0xdc, 0xa4, 0xf5, 0xf6, 0xde, 0xca, 0x1e, 0xcb, + 0x93, 0x3b, 0x64, 0x79, 0x00, 0x3c, 0x8d, 0xbb, 0x5c, 0x7a, 0x40, 0x14, + 0x58, 0x12, 0xa4, 0xf7, 0x6e, 0x51, 0xfb, 0xe7, 0x6f, 0x49, 0x5b, 0xc2, + 0xc9, 0x05, 0x38, 0x9c, 0x08, 0x78, 0x71, 0x27, 0x2b, 0xf5, 0xbf, 0xd6, + 0x38, 0xaa, 0x45, 0xe1, 0xe1, 0x4c, 0xfb, 0xfd, 0xb7, 0xe6, 0xcf, 0xad, + 0x9e, 0x56, 0xaf, 0x12, 0x12, 0x98, 0xe6, 0x38, 0xaa, 0xee, 0xdb, 0x9e, + 0xca, 0xe1, 0x79, 0x6d, 0x44, 0xfb, 0x19, 0x50, 0x92, 0x00, 0x06, 0x2c, + 0x24, 0x71, 0x6c, 0x34, 0x45, 0xac, 0xf9, 0x82, 0x66, 0xa8, 0x63, 0x80, + 0xa8, 0x5b, 0x21, 0x3c, 0x36, 0x71, 0x93, 0x40, 0x7b, 0xff, 0xa2, 0xd0, + 0x72, 0xb4, 0x66, 0xfa, 0xfc, 0xa0, 0xee, 0xca, 0x15, 0x73, 0x52, 0xe7, + 0x9d, 0x11, 0xd3, 0xbc, 0xab, 0x37, 0x31, 0x0e, 0xaf, 0xdc, 0x05, 0x30, + 0x79, 0x8c, 0x25, 0x75, 0x5c, 0x60, 0xc7, 0x9a, 0xfc, 0x88, 0xea, 0xe6, + 0x09, 0x9f, 0xd1, 0x4f, 0x13, 0xf4, 0x41, 0x54, 0x5b, 0x7a, 0xe4, 0x49, + 0x3c, 0x0f, 0x15, 0xe9, 0xa4, 0x85, 0xb2, 0x92, 0x07, 0xea, 0xea, 0x7c, + 0xc1, 0x6d, 0xa9, 0x03, 0xb3, 0x31, 0xce, 0x1e, 0x82, 0xca, 0x9e, 0x3c, + 0x88, 0x88, 0xc1, 0x04, 0x5f, 0xbe, 0xd5, 0x94, 0x0d, 0x67, 0x98, 0x27, + 0xd0, 0x0f, 0x43, 0xf3, 0xb3, 0xfc, 0xff, 0x24, 0xa2, 0x1e, 0x17, 0x06, + 0xb0, 0x52, 0x16, 0x7c, 0xd8, 0x49, 0x74, 0x51, 0xcf, 0x2d, 0x36, 0x16, + 0xb0, 0x88, 0xb2, 0x2b, 0x1d, 0x72, 0x70, 0xab, 0xe2, 0xf6, 0x5f, 0xa5, + 0x2d, 0x4e, 0xd1, 0x42, 0x3c, 0x83, 0x84, 0xb2, 0x56, 0xeb, 0x8d, 0xce, + 0x33, 0x46, 0xdb, 0x3d, 0x4f, 0x97, 0xea, 0x37, 0x5e, 0x0d, 0xd7, 0x4c, + 0x9a, 0x7e, 0xc9, 0x0e, 0x69, 0x4d, 0x97, 0x15, 0x1e, 0x09, 0xbe, 0x7e, + 0xff, 0xe8, 0xf5, 0xab, 0xe9, 0xe7, 0xed, 0x4b, 0x41, 0xa5, 0xf2, 0x2a, + 0x24, 0x48, 0x8b, 0x72, 0x4b, 0x9d, 0xcf, 0x45, 0xdb, 0xc0, 0xaf, 0xa8, + 0x0f, 0x0f, 0x67, 0x37, 0xd3, 0x8b, 0xe1, 0x67, 0x90, 0xd8, 0x1c, 0x58, + 0x36, 0x46, 0x51, 0x52, 0xea, 0xb4, 0x75, 0xb1, 0xcd, 0xc5, 0x39, 0x16, + 0xe0, 0xec, 0x16, 0xf7, 0xf8, 0x0f, 0x5d, 0x13, 0x84, 0x62, 0x34, 0x86, + 0x42, 0x05, 0xa8, 0x08, 0x84, 0xa9, 0x77, 0x12, 0xc1, 0x56, 0xdd, 0x28, + 0xde, 0x39, 0x33, 0x21, 0x3d, 0xbd, 0x94, 0xce, 0xe4, 0xb3, 0x17, 0x9b, + 0x09, 0x20, 0xf0, 0x25, 0xce, 0x00, 0x34, 0x8e, 0x12, 0x94, 0x74, 0x0b, + 0x16, 0xa1, 0x60, 0x76, 0x24, 0xf0, 0xbf, 0xe3, 0x3a, 0x83, 0x8f, 0x40, + 0x47, 0x2e, 0x1c, 0xd5, 0x35, 0x25, 0x87, 0xb3, 0x11, 0xdc, 0x98, 0xb0, + 0xa6, 0x5f, 0x6a, 0x05, 0x1d, 0x06, 0x8d, 0xe8, 0xb0, 0x98, 0xf0, 0x43, + 0x29, 0x84, 0xe4, 0xef, 0x34, 0x67, 0x74, 0x64, 0xe8, 0xb8, 0xf0, 0xd4, + 0x9e, 0xc1, 0x3f, 0x5f, 0xeb, 0xe0, 0x9b, 0x37, 0xf8, 0x75, 0x46, 0x47, + 0xa5, 0x3e, 0x42, 0x20, 0x50, 0xc4, 0x5d, 0xf3, 0xdf, 0x4e, 0xf8, 0x0e, + 0x1e, 0x15, 0x10, 0x3e, 0xf1, 0x68, 0xad, 0x87, 0xad, 0xe5, 0x45, 0x5e, + 0x22, 0xba, 0x2e, 0x51, 0xa0, 0xbf, 0xdc, 0x87, 0xca, 0xe4, 0x1f, 0x2f, + 0x2c, 0xae, 0xa9, 0x14, 0xd7, 0xdd, 0x01, 0xa8, 0x4f, 0x43, 0xcb, 0x84, + 0x92, 0xbf, 0xf9, 0x3d, 0xf0, 0x6b, 0x19, 0x43, 0xb0, 0xdf, 0xff, 0x94, + 0x76, 0xe2, 0x84, 0xf9, 0x31, 0x88, 0x7e, 0xc6, 0x87, 0x58, 0xbe, 0x5d, + 0x8b, 0xf8, 0xb5, 0xdc, 0x95, 0x16, 0x5f, 0xa1, 0x2c, 0xe8, 0x53, 0x36, + 0x64, 0xf5, 0x5d, 0xa0, 0x74, 0x12, 0x78, 0x59, 0x73, 0x69, 0x5a, 0x2b, + 0x36, 0x4a, 0xff, 0x5b, 0xef, 0x49, 0x2c, 0xb2, 0x9e, 0x59, 0xf0, 0x39, + 0x56, 0xe1, 0xd0, 0x1a, 0x05, 0xb2, 0x7c, 0xd1, 0x40, 0x09, 0xdf, 0x00, + 0xc9, 0x15, 0x53, 0xa2, 0xda, 0x84, 0xb5, 0x85, 0x05, 0x76, 0xa6, 0x1b, + 0xcb, 0x06, 0xb2, 0xc8, 0xa0, 0xc5, 0x23, 0x8f, 0xb0, 0xe8, 0xf5, 0xd9, + 0xd0, 0x19, 0x29, 0xfe, 0x2d, 0x9a, 0x57, 0x76, 0x5f, 0xf2, 0xef, 0x71, + 0x16, 0xee, 0x28, 0x7b, 0xe4, 0x48, 0xeb, 0xda, 0xe0, 0xd5, 0xbc, 0x0e, + 0x46, 0x6b, 0x06, 0x5d, 0xe5, 0x91, 0x2d, 0xcb, 0xc4, 0x53, 0xa6, 0x16, + 0xd5, 0xe7, 0xd8, 0xf1, 0xdd, 0x4f, 0xbb, 0xcc, 0x55, 0x67, 0x19, 0x98, + 0x94, 0x95, 0x5e, 0xd6, 0xf5, 0xf7, 0xe8, 0x6a, 0xf7, 0x20, 0x86, 0x3a, + 0x43, 0xbf, 0xe9, 0xec, 0x6b, 0x33, 0x49, 0x19, 0x43, 0xfb, 0xeb, 0x3f, + 0xf4, 0x9d, 0x29, 0x66, 0xb9, 0x6e, 0xb5, 0x15, 0x4b, 0x8d, 0x3c, 0x3c, + 0xfa, 0xf2, 0x87, 0xba, 0x61, 0x11, 0x40, 0xe6, 0xb4, 0x6f, 0xf5, 0xe1, + 0x24, 0x32, 0x69, 0x3e, 0xff, 0xf7, 0xbc, 0xee, 0x82, 0xf2, 0x9e, 0x6d, + 0x3f, 0x6c, 0xcc, 0x0f, 0x4f, 0xc3, 0xf1, 0xdb, 0x1e, 0x81, 0xd7, 0x9b, + 0x22, 0xa8, 0xa7, 0x36, 0x6d, 0xa9, 0x6f, 0x46, 0x1a, 0xa7, 0xff, 0x00, + 0x4b, 0xd8, 0xab, 0xe7, 0x50, 0x3b, 0xe9, 0xc0, 0x57, 0xec, 0x8d, 0x0c, + 0xa0, 0xee, 0x8c, 0x2a, 0x74, 0xf2, 0x94, 0xf9, 0x0c, 0x20, 0x14, 0xd9, + 0xad, 0x0d, 0x4e, 0xac, 0x35, 0x44, 0x59, 0x28, 0x24, 0x31, 0x32, 0xaa, + 0x6d, 0xc2, 0x13, 0xb9, 0xee, 0x75, 0x0c, 0x5f, 0x39, 0xef, 0x31, 0xca, + 0x28, 0x48, 0x56, 0x59, 0xfb, 0xa8, 0xd8, 0x2b, 0x70, 0x61, 0x22, 0x43, + 0x43, 0xb9, 0x60, 0x44, 0xeb, 0xf8, 0x98, 0x87, 0x25, 0x84, 0xa2, 0xaa, + 0x37, 0xd4, 0xb8, 0xd6, 0x3d, 0xa3, 0xa1, 0x4a, 0x81, 0xc2, 0xa9, 0xea, + 0xa2, 0xd6, 0x63, 0x76, 0x50, 0xeb, 0xcd, 0x19, 0x40, 0xb1, 0x7c, 0xf6, + 0xc1, 0x44, 0x01, 0x25, 0xe0, 0xdd, 0xb8, 0x39, 0xef, 0x46, 0x3d, 0x50, + 0x33, 0xed, 0xb1, 0x63, 0x65, 0xd7, 0x50, 0xe7, 0x95, 0xba, 0xab, 0xa7, + 0x14, 0xe5, 0x60, 0xcb, 0x81, 0x6e, 0x88, 0x3c, 0x06, 0x6e, 0x7d, 0x8e, + 0xe7, 0xbb, 0xa5, 0xc2, 0xbd, 0xae, 0x46, 0x8f, 0x43, 0x04, 0x29, 0xe6, + 0x17, 0x38, 0x05, 0x2d, 0x97, 0x93, 0x5b, 0xf9, 0xef, 0x4d, 0x2e, 0x75, + 0x6c, 0x69, 0xba, 0x08, 0xf2, 0x21, 0x1e, 0x21, 0xe6, 0x8a, 0x5b, 0x8c, + 0xd4, 0x8e, 0xde, 0x64, 0x9b, 0x9d, 0x54, 0x58, 0x65, 0x3e, 0xdd, 0x8a, + 0x1e, 0x81, 0x4e, 0x45, 0xe8, 0xfb, 0x20, 0xc3, 0x3a, 0xf0, 0x50, 0x1e, + 0x8a, 0x18, 0xea, 0x2b, 0xf5, 0xe1, 0xa6, 0xb6, 0xc8, 0xa0, 0x02, 0x3d, + 0x6e, 0xfa, 0x0b, 0x51, 0x95, 0x4e, 0x4c, 0x11, 0xb0, 0xc4, 0x62, 0x58, + 0xa6, 0x9c, 0x13, 0x4e, 0xbe, 0xc9, 0x29, 0x93, 0x29, 0x15, 0x5f, 0xaf, + 0x0e, 0xc3, 0xb3, 0x26, 0x3f, 0xdc, 0x4c, 0x33, 0xb8, 0x4b, 0x11, 0xae, + 0x1f, 0xd7, 0x05, 0x39, 0xcf, 0xfe, 0xc3, 0x6d, 0xf0, 0xc0, 0x77, 0x02, + 0xb8, 0x9b, 0x3d, 0x1b, 0x3d, 0x72, 0xfe, 0x7e, 0x18, 0x60, 0x9b, 0xc4, + 0x8b, 0xac, 0x25, 0x6d, 0x3b, 0x80, 0x34, 0xbc, 0x51, 0xaf, 0xf6, 0xff, + 0x66, 0x98, 0x86, 0x6e, 0x9e, 0x9a, 0xfe, 0x6d, 0x21, 0x4d, 0xf1, 0x58, + 0x3e, 0x3e, 0x43, 0xe3, 0x7e, 0x40, 0xb0, 0xb3, 0xd8, 0x12, 0xa5, 0xce, + 0x09, 0x41, 0x8c, 0x1d, 0x73, 0xcd, 0xfc, 0x63, 0xed, 0xeb, 0x08, 0x1e, + 0x34, 0xfb, 0xed, 0x75, 0xb7, 0x86, 0x84, 0x7c, 0x80, 0xe9, 0xe4, 0xa3, + 0x1c, 0x4a, 0x0d, 0x11, 0x16, 0x24, 0xb2, 0xb1, 0x99, 0xe5, 0xe3, 0x2e, + 0x2f, 0x70, 0xcd, 0x1e, 0x35, 0x14, 0x79, 0xba, 0xa2, 0x51, 0x7a, 0x29, + 0x5c, 0x75, 0x8f, 0xdd, 0x22, 0xdf, 0xb2, 0x64, 0xd9, 0x95, 0x11, 0x33, + 0x97, 0xee, 0x69, 0x42, 0x01, 0x96, 0x98, 0x1b, 0x43, 0xc2, 0xec, 0xf9, + 0xb0, 0xdb, 0x69, 0x34, 0xab, 0x98, 0x1b, 0xb2, 0x04, 0x05, 0x14, 0x1d, + 0x25, 0x2f, 0x32, 0x41, 0x50, 0x51, 0x55, 0x62, 0x6d, 0x78, 0x7f, 0x8b, + 0xbb, 0xc2, 0xcd, 0xcf, 0xe4, 0xed, 0x04, 0x1f, 0x25, 0x30, 0x43, 0x64, + 0x69, 0x7c, 0x87, 0xa3, 0xa9, 0xb1, 0xc1, 0xd1, 0xdc, 0x01, 0x10, 0x1d, + 0x27, 0x3f, 0x5c, 0x5d, 0x75, 0x82, 0x9b, 0xaa, 0xb3, 0xe8, 0x0c, 0x11, + 0x1f, 0x24, 0x38, 0x41, 0x45, 0x54, 0x5f, 0x69, 0x85, 0x8d, 0x93, 0x9e, + 0xc5, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x25, 0x32, 0x42}; +#elif MLD_CONFIG_PARAMETER_SET == 65 +const uint8_t expected_signature[] = { + 0x8b, 0x6f, 0x79, 0x00, 0xcc, 0x79, 0x57, 0xee, 0x16, 0x86, 0x87, 0xd5, + 0xcf, 0xb6, 0x90, 0x2c, 0xc6, 0x30, 0xeb, 0x8d, 0x39, 0xae, 0x9b, 0xf1, + 0x66, 0xe0, 0xd6, 0x93, 0xa5, 0x4e, 0x26, 0x9b, 0x96, 0x8f, 0xd1, 0x46, + 0x97, 0xbe, 0x71, 0x1c, 0xf3, 0xa5, 0xe5, 0xae, 0x8d, 0x4b, 0xf2, 0xe6, + 0x48, 0x8f, 0xe9, 0x5e, 0x07, 0xef, 0xe4, 0xbb, 0x39, 0xc1, 0xc9, 0x3c, + 0xc3, 0x0b, 0xfb, 0x2a, 0x29, 0x06, 0xfe, 0x01, 0xcb, 0x63, 0x83, 0x10, + 0xa8, 0xc8, 0xa0, 0x29, 0xa5, 0x80, 0xeb, 0xbd, 0xa9, 0xd9, 0x0b, 0x61, + 0xbc, 0xce, 0x11, 0x55, 0x66, 0x12, 0xc7, 0x5b, 0xd2, 0x7a, 0x5a, 0xc8, + 0xab, 0xab, 0xbf, 0x3a, 0x1f, 0x96, 0x1a, 0x70, 0xcb, 0x41, 0x5f, 0xc8, + 0xb7, 0x09, 0x22, 0x98, 0x9b, 0xb8, 0xf7, 0x2d, 0x49, 0x65, 0x1d, 0x09, + 0x8b, 0x70, 0xb5, 0x42, 0xc9, 0x89, 0x5b, 0x74, 0xb4, 0x28, 0x82, 0x01, + 0x53, 0x12, 0x3e, 0x23, 0xf6, 0x54, 0xf8, 0x51, 0x12, 0x4b, 0x02, 0x3a, + 0x7e, 0xb6, 0x1f, 0xac, 0xa0, 0xe6, 0x6f, 0xf8, 0x61, 0x82, 0xe4, 0xfb, + 0x96, 0x2a, 0xd2, 0xaf, 0x3c, 0xea, 0x6e, 0xdc, 0x18, 0x8a, 0x5d, 0x90, + 0xda, 0xa2, 0x5d, 0xa7, 0x8f, 0x5b, 0x50, 0x46, 0xaf, 0x8c, 0x17, 0x6a, + 0x4c, 0x39, 0xfc, 0x31, 0x4c, 0x4b, 0xc2, 0x57, 0x66, 0x61, 0x98, 0xbf, + 0xe6, 0xfb, 0x54, 0x96, 0xd3, 0x70, 0xb8, 0xaf, 0xcd, 0x8b, 0xcc, 0x00, + 0x07, 0x92, 0x15, 0xc2, 0xbb, 0x48, 0xbb, 0xc6, 0xb7, 0xb5, 0x58, 0x8c, + 0xfc, 0xf0, 0xda, 0x6a, 0x0d, 0xf7, 0x1d, 0x7d, 0xc6, 0x27, 0x26, 0x1a, + 0x99, 0xc5, 0x2f, 0xf8, 0x97, 0x65, 0x43, 0x86, 0xd6, 0x25, 0x23, 0x2b, + 0x06, 0x8f, 0x12, 0xa1, 0xae, 0xbb, 0x58, 0x34, 0x25, 0xec, 0x5b, 0x68, + 0xa4, 0xe1, 0x03, 0xfc, 0x26, 0xa2, 0xd6, 0x2b, 0x61, 0x10, 0x47, 0xbd, + 0x16, 0xe5, 0xca, 0x4a, 0xce, 0xed, 0x89, 0x09, 0x1a, 0xed, 0x22, 0xc1, + 0xca, 0x44, 0xe3, 0xef, 0x72, 0x34, 0xab, 0xab, 0x61, 0x5c, 0x9f, 0x5f, + 0xb5, 0xf5, 0xe8, 0x2d, 0x89, 0xea, 0x4b, 0x40, 0x65, 0x57, 0x8b, 0xa2, + 0x95, 0x40, 0x9c, 0x72, 0xc0, 0x46, 0x69, 0x45, 0x06, 0xf6, 0x07, 0x5b, + 0x2d, 0xa5, 0x46, 0xca, 0x5d, 0xfb, 0x40, 0xb7, 0x48, 0x59, 0x5b, 0xe2, + 0x1b, 0x38, 0xb2, 0x15, 0x75, 0x66, 0x67, 0x58, 0x00, 0x3f, 0xde, 0x8a, + 0x63, 0x13, 0x34, 0x6a, 0x30, 0xca, 0xb4, 0xd5, 0x3e, 0xe0, 0x6d, 0x14, + 0xb8, 0x9a, 0x48, 0xef, 0xfd, 0xbd, 0x6d, 0x20, 0x11, 0x4d, 0x25, 0xe5, + 0xab, 0x15, 0x8d, 0xe5, 0x91, 0xbc, 0xc6, 0x69, 0x8a, 0xf8, 0xab, 0x3a, + 0x82, 0xae, 0xc5, 0x03, 0x2c, 0xcf, 0x54, 0xdc, 0xcd, 0xe8, 0x49, 0x53, + 0xb5, 0xd8, 0xc2, 0x24, 0xf8, 0x8c, 0x38, 0x8f, 0xe3, 0xfe, 0x3a, 0x18, + 0x15, 0xa8, 0xda, 0x77, 0xc8, 0x81, 0x72, 0xc6, 0xc1, 0x60, 0xa3, 0x73, + 0x65, 0x68, 0x5c, 0xf3, 0x1d, 0x8d, 0x61, 0x21, 0x65, 0xfb, 0x45, 0xc4, + 0x4c, 0x31, 0x88, 0x25, 0x0d, 0x52, 0x75, 0x3b, 0xec, 0x54, 0xe0, 0xb1, + 0x9c, 0x7c, 0xdf, 0xe3, 0x3b, 0x77, 0x31, 0x33, 0xd7, 0x25, 0x99, 0xff, + 0xc5, 0x40, 0x1e, 0x85, 0x09, 0xfd, 0x2d, 0x24, 0x4a, 0x92, 0xe7, 0x77, + 0x48, 0xa5, 0x46, 0xf4, 0x8e, 0xa3, 0x6b, 0x24, 0xe4, 0x6b, 0x31, 0xf6, + 0xe0, 0x16, 0x49, 0x9b, 0x9f, 0xa3, 0x1a, 0x5c, 0x05, 0x5e, 0x81, 0x62, + 0xc8, 0x14, 0x52, 0xb4, 0x21, 0xfd, 0x76, 0x6d, 0x88, 0xe9, 0x3b, 0x0b, + 0x75, 0x27, 0x92, 0x47, 0x5a, 0x58, 0x08, 0x26, 0xa7, 0xa2, 0x48, 0x1c, + 0x14, 0x3e, 0x5e, 0xdf, 0x81, 0x83, 0x83, 0x3e, 0xc6, 0x72, 0x27, 0xc4, + 0x6a, 0x46, 0x2b, 0xf2, 0x8d, 0x42, 0x11, 0xb9, 0x15, 0xd7, 0xf0, 0x20, + 0x29, 0x53, 0xba, 0xf0, 0x6e, 0x41, 0x3d, 0xee, 0x19, 0xf2, 0x43, 0xf3, + 0x6d, 0x00, 0xe2, 0x43, 0x77, 0xb9, 0xa9, 0x78, 0x34, 0x48, 0x3c, 0x1a, + 0x8b, 0xbd, 0xa1, 0xe5, 0x90, 0x59, 0x5b, 0xd6, 0x1e, 0x22, 0xdf, 0xb2, + 0xa7, 0x96, 0x7d, 0x55, 0x86, 0x66, 0x95, 0xb7, 0x06, 0xe7, 0x60, 0x2a, + 0x01, 0x48, 0x3f, 0xd4, 0xa7, 0xd4, 0xc2, 0x38, 0xa4, 0x10, 0x8e, 0x4f, + 0x97, 0xad, 0xa3, 0xb9, 0xe2, 0xaa, 0x13, 0xb1, 0x16, 0x89, 0x3d, 0x74, + 0x60, 0x94, 0x8c, 0xc3, 0xe6, 0x5f, 0xcf, 0xdc, 0x58, 0x17, 0x98, 0x27, + 0x86, 0xae, 0x2a, 0x0d, 0xe8, 0x33, 0x79, 0xc8, 0xc8, 0x5b, 0x59, 0xb0, + 0xba, 0xac, 0xd3, 0x6e, 0x2d, 0x7b, 0x0b, 0x9a, 0xb5, 0xfd, 0x58, 0x42, + 0xeb, 0x80, 0xf4, 0x6b, 0x9a, 0x2f, 0x19, 0x43, 0x75, 0xb4, 0xcb, 0xc9, + 0xd5, 0x28, 0xf5, 0xb9, 0x67, 0x82, 0xb4, 0xed, 0x8c, 0x3f, 0x3d, 0x6b, + 0x6d, 0x1b, 0x80, 0x13, 0x5c, 0x7b, 0x2e, 0xfa, 0xa0, 0x32, 0xba, 0xb5, + 0x46, 0xd6, 0xe7, 0x90, 0xe9, 0xd1, 0x91, 0xa0, 0xaa, 0x26, 0x35, 0xa2, + 0x0d, 0x98, 0x44, 0x11, 0xae, 0xf9, 0xc5, 0x12, 0x4d, 0x1a, 0x7c, 0x53, + 0xea, 0xf6, 0x05, 0x8d, 0x3a, 0x74, 0x92, 0xc9, 0x65, 0xeb, 0x6f, 0xb5, + 0xb4, 0xd2, 0xcd, 0x5c, 0xec, 0xaf, 0x95, 0xcb, 0xb4, 0x3c, 0x22, 0xca, + 0x1c, 0x06, 0x85, 0x16, 0x96, 0x24, 0x8c, 0x6c, 0x80, 0xf8, 0xb3, 0xa7, + 0x87, 0x77, 0xeb, 0x09, 0x71, 0xc8, 0x95, 0xfb, 0x5e, 0xe5, 0x6f, 0x78, + 0xf9, 0x60, 0xf9, 0x9e, 0x58, 0x7b, 0xbd, 0x47, 0xdd, 0x48, 0x2e, 0x56, + 0xcd, 0x63, 0x72, 0xc9, 0x4b, 0x65, 0x2d, 0x41, 0xe8, 0x81, 0x19, 0x33, + 0x4b, 0xf6, 0x02, 0xc6, 0xcb, 0x2e, 0xdf, 0x3d, 0xc8, 0xdd, 0x2f, 0x0f, + 0x09, 0x67, 0xf0, 0xaa, 0x3c, 0x51, 0xdc, 0x8d, 0xc6, 0xc3, 0xb2, 0x3b, + 0x15, 0x85, 0xcb, 0xeb, 0x62, 0xef, 0xa3, 0xf9, 0x94, 0xf4, 0x35, 0x9c, + 0x59, 0xcc, 0xc2, 0x68, 0xb4, 0xde, 0x02, 0x75, 0x8e, 0xf5, 0x33, 0xca, + 0xd5, 0xc5, 0x24, 0xae, 0xf6, 0xde, 0x2b, 0x01, 0xf4, 0x56, 0xb9, 0xa5, + 0xa7, 0xe0, 0x64, 0x2e, 0xba, 0x1d, 0x53, 0x54, 0x46, 0xcf, 0x64, 0x16, + 0x12, 0xe2, 0xa6, 0xcc, 0x18, 0xb4, 0x77, 0x8b, 0x19, 0x50, 0x43, 0x96, + 0xc8, 0x5d, 0xc3, 0x58, 0xf0, 0xfd, 0x5e, 0x13, 0xa9, 0x10, 0x67, 0xdf, + 0x25, 0xdb, 0xaf, 0x38, 0x5f, 0xbd, 0x35, 0xc1, 0x49, 0x44, 0xe8, 0x1f, + 0x12, 0xa4, 0x7c, 0x28, 0xa3, 0xd6, 0x0d, 0x6f, 0x44, 0xa9, 0x5f, 0xfc, + 0x9f, 0xfa, 0x11, 0x62, 0x87, 0x5b, 0x0e, 0x91, 0xd4, 0xb6, 0xd3, 0x71, + 0xc2, 0x77, 0x19, 0xf6, 0x7c, 0x11, 0x30, 0x5e, 0x5c, 0xd3, 0x1e, 0x90, + 0x05, 0x31, 0x63, 0xbb, 0xef, 0x85, 0xe0, 0x27, 0x94, 0x80, 0xcb, 0x33, + 0xbc, 0x5e, 0x45, 0x87, 0x62, 0xdf, 0xd4, 0x12, 0x2f, 0xf5, 0x41, 0x15, + 0x03, 0x0c, 0x80, 0xe8, 0xe2, 0x06, 0xde, 0x4b, 0x46, 0x70, 0x94, 0xd2, + 0x0d, 0x85, 0x72, 0x27, 0xe5, 0x6c, 0xeb, 0xd2, 0x78, 0x0b, 0x38, 0x40, + 0xe8, 0xdb, 0x47, 0x5c, 0xba, 0xd0, 0x21, 0x33, 0x8f, 0xb8, 0xc0, 0x66, + 0x1e, 0xd1, 0xb0, 0x94, 0xa3, 0x39, 0xc7, 0x87, 0xaf, 0x97, 0x98, 0xce, + 0x6d, 0x03, 0x1a, 0xdb, 0x52, 0x96, 0x0b, 0x9d, 0x5b, 0xf8, 0xa3, 0xf4, + 0x41, 0x95, 0x72, 0xad, 0x0e, 0x98, 0x61, 0x7f, 0xf3, 0x8f, 0x23, 0xeb, + 0xc0, 0xdf, 0xd7, 0x70, 0x26, 0x8c, 0xb3, 0xb3, 0xf0, 0xa2, 0x8a, 0x39, + 0xdd, 0x61, 0xb4, 0x53, 0xe0, 0x2a, 0x6f, 0x91, 0x34, 0x9c, 0x76, 0xf6, + 0x52, 0x93, 0xe6, 0x39, 0xb7, 0x54, 0x07, 0x46, 0x82, 0x2d, 0x05, 0x6d, + 0x9a, 0x00, 0x53, 0x65, 0x68, 0x93, 0x91, 0x00, 0xda, 0xe0, 0x93, 0x34, + 0x60, 0xb1, 0x93, 0x0b, 0x64, 0xa8, 0x12, 0xd2, 0x51, 0x3c, 0xdb, 0xb0, + 0x4c, 0x39, 0x4e, 0xce, 0xbd, 0xf0, 0x65, 0x12, 0x8a, 0xd4, 0x80, 0x7d, + 0x82, 0x85, 0xe4, 0x92, 0xc2, 0x77, 0x1e, 0xcf, 0xd9, 0xab, 0x0f, 0x9b, + 0x32, 0x2e, 0x3f, 0xe1, 0x0e, 0x87, 0x1c, 0x87, 0x34, 0xe7, 0x93, 0x16, + 0x95, 0x09, 0x7d, 0x24, 0xa8, 0xb5, 0xe0, 0x9f, 0x23, 0x87, 0x5c, 0x0b, + 0x31, 0x4a, 0x2f, 0xe2, 0x5c, 0x82, 0x49, 0x51, 0xe4, 0x93, 0xcb, 0x05, + 0x23, 0x4f, 0x8a, 0x83, 0x88, 0xfb, 0x89, 0xb0, 0x08, 0xd6, 0x64, 0xad, + 0x51, 0x84, 0x40, 0x29, 0xb1, 0xca, 0x74, 0x26, 0x29, 0x5a, 0x61, 0x01, + 0x2e, 0xa0, 0xeb, 0xeb, 0x02, 0xb5, 0xff, 0xd8, 0x20, 0x6a, 0x5e, 0x8d, + 0x17, 0x1e, 0xa3, 0xd7, 0x2f, 0x20, 0x0b, 0x93, 0x17, 0x24, 0xf7, 0x90, + 0x7b, 0xc6, 0xba, 0xd8, 0xf9, 0xe9, 0x0a, 0x2a, 0x7a, 0x81, 0x23, 0x81, + 0x03, 0x6f, 0x1e, 0x0d, 0x87, 0x83, 0xd1, 0xcf, 0x92, 0x2f, 0x19, 0x82, + 0x4e, 0x6c, 0x0a, 0x02, 0xb6, 0x70, 0xbc, 0xe1, 0x58, 0xe7, 0x16, 0xdb, + 0x2f, 0x74, 0x9f, 0xe1, 0xc2, 0x1e, 0x64, 0xc6, 0x48, 0x08, 0xee, 0xea, + 0x52, 0x9a, 0xce, 0x2c, 0xc5, 0x0c, 0x7a, 0x63, 0xf1, 0x6a, 0xbd, 0x2c, + 0x8b, 0xd5, 0x4a, 0xfa, 0x1e, 0xab, 0x9a, 0x5b, 0x25, 0xb8, 0xfa, 0x0a, + 0xe9, 0x68, 0x80, 0x6f, 0x80, 0x57, 0x10, 0x54, 0xb8, 0xa2, 0x16, 0xbd, + 0xfe, 0xf7, 0xea, 0x01, 0xc7, 0x94, 0x5a, 0x95, 0xe3, 0x61, 0xa5, 0x49, + 0x84, 0xf5, 0x79, 0x78, 0xb5, 0x0a, 0x96, 0xca, 0x01, 0x1b, 0xd0, 0x0b, + 0x51, 0x30, 0xd3, 0x48, 0xfc, 0x4d, 0x50, 0x71, 0x09, 0x73, 0xea, 0x37, + 0xcd, 0x9d, 0x3d, 0xde, 0x30, 0x56, 0x21, 0xf0, 0xef, 0x84, 0xad, 0x27, + 0xe1, 0x83, 0xdb, 0xfb, 0xcd, 0x11, 0xb2, 0xbd, 0x30, 0x67, 0x8a, 0x88, + 0x09, 0x0e, 0x9d, 0x96, 0x09, 0xba, 0xda, 0x9d, 0xf0, 0xe9, 0xb4, 0xa6, + 0x7a, 0x04, 0xf9, 0x4b, 0xb8, 0x51, 0xa9, 0x99, 0xf3, 0xbb, 0x77, 0x95, + 0x0a, 0xa1, 0xa6, 0xa1, 0x24, 0xfc, 0xcc, 0x45, 0xe8, 0x83, 0xc8, 0x6f, + 0x48, 0xad, 0x9a, 0x73, 0xd0, 0xe0, 0x57, 0x7d, 0xe4, 0x78, 0x65, 0xef, + 0xae, 0xc2, 0xfe, 0x7a, 0x56, 0xaf, 0x03, 0x71, 0x2b, 0xe6, 0xa1, 0x7e, + 0xe5, 0x12, 0xf8, 0xc3, 0x75, 0xc7, 0x22, 0x5f, 0x1b, 0x52, 0x90, 0xe5, + 0xdf, 0xba, 0x9d, 0xe2, 0x68, 0xe0, 0xb3, 0x7a, 0x9e, 0x14, 0xff, 0xb5, + 0x0a, 0x80, 0x20, 0x49, 0x88, 0xe9, 0x9c, 0xe4, 0xb5, 0xaf, 0x7e, 0x51, + 0xec, 0xe7, 0xfc, 0x64, 0x65, 0x21, 0x10, 0xc6, 0x1f, 0x7f, 0x93, 0x7d, + 0xd8, 0xf5, 0xd0, 0x98, 0x94, 0x44, 0xf8, 0x49, 0x6a, 0x51, 0x0a, 0x54, + 0xf4, 0x9f, 0xee, 0x3c, 0x56, 0xbf, 0x4c, 0xe4, 0xde, 0x1c, 0x9b, 0x11, + 0x7e, 0x9a, 0x71, 0x11, 0x80, 0x33, 0xd5, 0xb0, 0x9b, 0xef, 0x67, 0x29, + 0xa4, 0x7d, 0x70, 0x31, 0x3f, 0x8b, 0x2e, 0x4a, 0x0f, 0x2c, 0x91, 0x3d, + 0x3e, 0x3d, 0x8c, 0x0a, 0x2b, 0xf1, 0xdd, 0xbf, 0x61, 0xe6, 0xa3, 0xef, + 0x6d, 0x82, 0xc8, 0xb7, 0x5e, 0x2b, 0x83, 0xc9, 0x4e, 0xa0, 0x85, 0x7f, + 0x01, 0x5a, 0xca, 0x6e, 0x90, 0xfa, 0x7e, 0x82, 0x4d, 0x35, 0x7e, 0xe0, + 0x26, 0x40, 0xf4, 0xa6, 0xae, 0xc3, 0x89, 0xf3, 0xca, 0x55, 0x2c, 0xb5, + 0x29, 0x05, 0x94, 0x45, 0xa7, 0x45, 0xf3, 0x3d, 0xbb, 0x53, 0x5e, 0xca, + 0x7c, 0x84, 0x8f, 0x72, 0x98, 0x93, 0x90, 0x1f, 0x56, 0x72, 0xdb, 0xbd, + 0xa9, 0xeb, 0xf9, 0xe9, 0xce, 0xb1, 0x41, 0xc3, 0xaa, 0xa0, 0xc4, 0x74, + 0x23, 0xc1, 0xeb, 0x7d, 0x41, 0xcd, 0xa4, 0x62, 0xec, 0xfc, 0x9a, 0xa4, + 0x16, 0xec, 0x67, 0x41, 0x89, 0xf0, 0x0e, 0xf3, 0xd1, 0xa2, 0x2f, 0xba, + 0x5d, 0x93, 0x36, 0x46, 0xf5, 0x52, 0x64, 0x91, 0xe7, 0x40, 0x91, 0x20, + 0xa1, 0xc9, 0xaa, 0x4c, 0x79, 0xc4, 0xbb, 0x67, 0x79, 0xad, 0x43, 0xab, + 0xba, 0xde, 0xfc, 0xf1, 0x74, 0x81, 0x33, 0xc0, 0x3f, 0x39, 0xd1, 0xd1, + 0xdf, 0xc0, 0x53, 0x33, 0xb2, 0x92, 0x37, 0xe6, 0x86, 0x2a, 0xe4, 0xe1, + 0x7c, 0x98, 0xf7, 0xdb, 0x5c, 0xa9, 0xff, 0x8d, 0x9c, 0xab, 0xe2, 0xf2, + 0xd5, 0xb1, 0x42, 0xa9, 0xf4, 0x97, 0x80, 0xcd, 0xde, 0x25, 0x2e, 0x87, + 0x92, 0xdd, 0xcf, 0xed, 0x67, 0x93, 0x8c, 0x5a, 0x1d, 0xee, 0xcf, 0x9d, + 0x50, 0x8f, 0xa7, 0xe3, 0x5c, 0xa3, 0x68, 0x78, 0x24, 0xeb, 0x60, 0xa3, + 0x8b, 0x36, 0xbb, 0xcb, 0x46, 0xee, 0x77, 0xfb, 0xf8, 0x69, 0x24, 0xd1, + 0xfa, 0xad, 0x76, 0x76, 0x5e, 0x54, 0xe5, 0xb6, 0x36, 0xc6, 0xdd, 0xa9, + 0x6c, 0x44, 0x15, 0xf7, 0x0a, 0xf8, 0xbb, 0xba, 0xec, 0x35, 0xff, 0xc9, + 0xd6, 0x5d, 0xf5, 0x73, 0x4a, 0x15, 0x8f, 0x7b, 0x6e, 0xf4, 0xa0, 0x6d, + 0x10, 0xbb, 0x67, 0x0c, 0xb4, 0x69, 0xad, 0xb6, 0x40, 0xf7, 0x5f, 0x37, + 0x28, 0xc4, 0x08, 0x49, 0xd0, 0x16, 0x70, 0x80, 0xea, 0x55, 0x66, 0x07, + 0xc8, 0x03, 0x1b, 0xf6, 0xd3, 0x03, 0x04, 0x74, 0xe0, 0x50, 0x3f, 0xd2, + 0x53, 0x92, 0xa0, 0x9d, 0x59, 0xc9, 0x74, 0xf2, 0x7e, 0x3b, 0x33, 0x02, + 0x10, 0x0b, 0x39, 0xf7, 0x4f, 0x6b, 0x58, 0xb2, 0x1a, 0xda, 0x65, 0x44, + 0xd1, 0x7c, 0x3f, 0xd7, 0xe3, 0xac, 0xe2, 0x1f, 0x38, 0xc1, 0x6a, 0xb0, + 0xdc, 0xc3, 0x9c, 0x7b, 0x11, 0x3c, 0x05, 0x21, 0x96, 0x76, 0x98, 0x76, + 0x82, 0xc1, 0x54, 0xdf, 0xdc, 0x8f, 0x4c, 0xd2, 0x63, 0x04, 0x06, 0x77, + 0x36, 0xe6, 0x2e, 0xd1, 0x00, 0x28, 0x42, 0x7c, 0x4a, 0x27, 0x90, 0x46, + 0xc9, 0xce, 0x33, 0x1c, 0xae, 0xda, 0x79, 0x64, 0x7f, 0x52, 0x3f, 0x58, + 0x11, 0x76, 0x4a, 0xb6, 0x72, 0xd8, 0x76, 0xae, 0xfd, 0x5c, 0x57, 0x69, + 0x76, 0x91, 0x84, 0x21, 0xc4, 0x9b, 0xd8, 0xa2, 0xff, 0x93, 0x02, 0x77, + 0x61, 0x57, 0x96, 0x7b, 0x8e, 0xfc, 0xf2, 0x6c, 0x11, 0x2b, 0x5e, 0x88, + 0x5c, 0x17, 0x1d, 0x12, 0x79, 0x3a, 0x78, 0xb6, 0x9d, 0x70, 0xfa, 0xd4, + 0xc1, 0x5c, 0x90, 0x0e, 0x0a, 0xd1, 0x3c, 0x7d, 0xcf, 0xee, 0x8a, 0xb2, + 0xb2, 0x4d, 0xce, 0x89, 0x32, 0xa9, 0x6c, 0x56, 0x57, 0x85, 0xb1, 0xbf, + 0x18, 0x1d, 0xc6, 0xe1, 0x17, 0xc5, 0x92, 0x42, 0x99, 0xf9, 0x9f, 0x04, + 0xec, 0x38, 0xf8, 0xa0, 0xd2, 0xab, 0xe6, 0x13, 0x4d, 0x9c, 0x18, 0x86, + 0x3e, 0x18, 0x73, 0x2c, 0xac, 0xe0, 0xb9, 0xf9, 0x87, 0x74, 0xb8, 0xd7, + 0x47, 0x6e, 0x42, 0xfc, 0x29, 0xa0, 0x1f, 0x56, 0x68, 0xb6, 0x23, 0x96, + 0xa2, 0x8d, 0x54, 0x81, 0x0f, 0x60, 0xb9, 0xde, 0x93, 0xfc, 0xfd, 0xde, + 0xbe, 0xb3, 0xb5, 0x87, 0xec, 0x9f, 0x17, 0xc2, 0x77, 0x6e, 0xa0, 0x62, + 0xdb, 0x66, 0xba, 0xc5, 0x05, 0x12, 0x46, 0x5d, 0x3c, 0x23, 0x29, 0x68, + 0xe5, 0x31, 0xe3, 0x15, 0xec, 0xac, 0x15, 0x9a, 0xbf, 0x42, 0x65, 0x80, + 0x45, 0x9c, 0x1d, 0xc2, 0x0e, 0x18, 0x47, 0x40, 0x44, 0xc1, 0x55, 0x24, + 0x5a, 0x35, 0xad, 0x59, 0xd2, 0xc6, 0xc3, 0x68, 0x58, 0xbd, 0x6f, 0xcf, + 0x5d, 0xb1, 0x9b, 0x0c, 0x92, 0x39, 0x22, 0x49, 0x66, 0x2e, 0x03, 0x7b, + 0x75, 0x5c, 0x6c, 0xde, 0x37, 0x54, 0xa9, 0x07, 0x2f, 0x7e, 0xc1, 0x3e, + 0x3b, 0xab, 0xd2, 0xa9, 0xfa, 0xc7, 0x6b, 0xd5, 0x14, 0x08, 0x35, 0x89, + 0x0b, 0x31, 0x18, 0x54, 0x7d, 0x6b, 0x53, 0x80, 0x6e, 0x32, 0x9b, 0xff, + 0x61, 0x7f, 0x36, 0xe5, 0x28, 0x40, 0xbc, 0xc7, 0x19, 0xb3, 0xae, 0xfa, + 0x95, 0xa8, 0xae, 0xd2, 0x97, 0x72, 0xc6, 0x91, 0x36, 0x3a, 0xa6, 0xec, + 0x4a, 0x41, 0x63, 0x6b, 0x28, 0xef, 0x5a, 0xa1, 0xdb, 0xf2, 0xd9, 0xfd, + 0x61, 0x72, 0xa4, 0xd2, 0x9e, 0xf7, 0x47, 0xf4, 0x4e, 0xea, 0x2a, 0xa5, + 0x35, 0xe1, 0x77, 0x3a, 0x53, 0x28, 0xa6, 0x55, 0x48, 0x0c, 0x1e, 0x44, + 0xfc, 0xc1, 0x31, 0x5a, 0x00, 0xcd, 0x29, 0xc1, 0x5c, 0xca, 0x2a, 0x07, + 0x01, 0x63, 0xac, 0xb3, 0xfb, 0xf6, 0x0b, 0xac, 0xfd, 0xe8, 0x7b, 0xed, + 0xf9, 0x3d, 0x9a, 0xbc, 0x67, 0x28, 0x1c, 0xd9, 0x3f, 0x97, 0x28, 0x4a, + 0xe7, 0xd0, 0x08, 0xe9, 0x3e, 0xa0, 0xcb, 0x0f, 0xe0, 0x3f, 0x1b, 0x80, + 0x43, 0x74, 0xd9, 0x9d, 0x0b, 0x22, 0x81, 0xf7, 0xec, 0x71, 0x2a, 0x29, + 0x9e, 0x5d, 0x1e, 0x8d, 0xf4, 0x22, 0x95, 0x78, 0x86, 0xcb, 0xf0, 0x9d, + 0xe7, 0x6a, 0x66, 0x7e, 0x28, 0xb5, 0x47, 0xb6, 0xdc, 0x0d, 0x03, 0x3c, + 0x09, 0x58, 0x76, 0x93, 0x39, 0xb2, 0xd3, 0x75, 0xb4, 0x51, 0x55, 0x84, + 0x30, 0x24, 0x0a, 0x76, 0xf4, 0x97, 0xe7, 0x0f, 0x5a, 0x67, 0xee, 0xf4, + 0xc7, 0x69, 0x8d, 0xf2, 0x32, 0x29, 0x5c, 0x33, 0x82, 0x5f, 0x6c, 0x47, + 0xd0, 0xe2, 0xbd, 0x62, 0xd6, 0x4c, 0x6d, 0x0d, 0xba, 0x87, 0xd3, 0x43, + 0x7e, 0x2d, 0xa6, 0x14, 0x09, 0x4f, 0x3b, 0xc3, 0x04, 0x14, 0xe5, 0x65, + 0xe9, 0x3b, 0x6a, 0xca, 0xb5, 0x96, 0x84, 0x3f, 0x53, 0x49, 0x22, 0x45, + 0x91, 0xff, 0xf9, 0x26, 0x75, 0x0d, 0x9c, 0xa7, 0x00, 0xf4, 0x65, 0xc4, + 0x60, 0x72, 0xab, 0xeb, 0xf8, 0xa8, 0x72, 0xfe, 0xd8, 0xde, 0x93, 0x67, + 0xcb, 0x09, 0xcc, 0xa0, 0xce, 0x9f, 0x67, 0x63, 0x26, 0xfa, 0x7f, 0x89, + 0xaa, 0x3e, 0x6d, 0xb2, 0x90, 0xd7, 0xef, 0x3e, 0x2a, 0x66, 0x26, 0x33, + 0xe6, 0x26, 0xc1, 0x58, 0xf8, 0x91, 0xea, 0x2f, 0xd0, 0x84, 0x21, 0x41, + 0x93, 0xa6, 0x36, 0x40, 0xb5, 0x4c, 0xac, 0x21, 0x88, 0x37, 0x47, 0x8a, + 0xb8, 0xf3, 0x33, 0x73, 0x12, 0xd7, 0x5a, 0x55, 0xf9, 0xd1, 0x1e, 0x75, + 0xa4, 0x66, 0x68, 0x3f, 0xf7, 0xb2, 0xc4, 0x5d, 0x1b, 0xb1, 0x61, 0x0f, + 0xaf, 0x4b, 0x9b, 0x20, 0x2b, 0x05, 0x68, 0x1c, 0x6c, 0x97, 0x8d, 0xb8, + 0x7b, 0x96, 0xda, 0xe0, 0x67, 0x15, 0x4c, 0x51, 0x71, 0x0d, 0xd3, 0x7b, + 0xde, 0xaa, 0xd3, 0x58, 0xf5, 0xc9, 0x62, 0x0a, 0xc2, 0x33, 0x1f, 0xf3, + 0xc3, 0x30, 0xb5, 0x64, 0xd1, 0x59, 0x41, 0x0e, 0xae, 0xaa, 0x0d, 0xdf, + 0x9f, 0x5d, 0x3f, 0x15, 0x0d, 0x46, 0x7a, 0x6d, 0x2e, 0x29, 0x1b, 0xc0, + 0xd3, 0x11, 0x10, 0x5d, 0xdc, 0x6a, 0x35, 0x8c, 0x43, 0xc8, 0x9f, 0x05, + 0x80, 0xdc, 0x25, 0x24, 0x37, 0x70, 0x7e, 0x1c, 0xe9, 0x85, 0x5a, 0xef, + 0x83, 0x3a, 0x55, 0x68, 0x83, 0x17, 0xf4, 0xc7, 0xae, 0xe4, 0x84, 0xc9, + 0x64, 0x5d, 0x2f, 0xb6, 0xca, 0x10, 0x95, 0xb8, 0xd6, 0x80, 0xfd, 0x05, + 0xa5, 0x06, 0x32, 0x34, 0x91, 0x01, 0xd2, 0x02, 0x90, 0xe1, 0xf7, 0x89, + 0x8a, 0xee, 0x18, 0x04, 0x93, 0xd9, 0xb4, 0x63, 0x4b, 0xf7, 0x7a, 0x9c, + 0x1b, 0x4b, 0xf9, 0x31, 0x32, 0xd9, 0xf2, 0x55, 0x4e, 0xc1, 0x02, 0xce, + 0x77, 0x38, 0x36, 0x29, 0xb8, 0x54, 0x8c, 0xc2, 0x27, 0x5f, 0xd9, 0xae, + 0x3e, 0x1e, 0xcd, 0xe9, 0x07, 0x90, 0x4c, 0xe0, 0xda, 0x16, 0x6e, 0xdf, + 0xde, 0x3a, 0x61, 0x89, 0x9f, 0x79, 0xd0, 0xd4, 0x66, 0x95, 0xad, 0xe4, + 0x11, 0x7d, 0xa1, 0xae, 0xec, 0x3e, 0x6e, 0x20, 0x5a, 0xd0, 0x28, 0x0e, + 0x55, 0xec, 0xcf, 0x34, 0xec, 0xb7, 0xfc, 0xa4, 0xb3, 0x8f, 0x56, 0x13, + 0x50, 0xcc, 0x15, 0x10, 0x74, 0x40, 0x72, 0x42, 0x20, 0x22, 0xb3, 0xaf, + 0xf3, 0x68, 0xba, 0x95, 0x45, 0xcb, 0xef, 0x92, 0xd5, 0x14, 0x4c, 0x1f, + 0xe3, 0xc1, 0xa6, 0x03, 0x4e, 0x05, 0xd2, 0x1a, 0xee, 0xd2, 0x48, 0x44, + 0x2e, 0x50, 0x3b, 0x86, 0xc8, 0x6a, 0xc8, 0x4c, 0xca, 0x2a, 0xb6, 0xf7, + 0x3c, 0xaf, 0xdc, 0x62, 0xb1, 0x49, 0x13, 0xfe, 0xe7, 0x32, 0xea, 0x78, + 0xfa, 0xba, 0xcf, 0x15, 0x47, 0x58, 0xdc, 0x19, 0x73, 0x1d, 0xff, 0xbd, + 0xcc, 0x27, 0xf6, 0xfc, 0x66, 0x68, 0xa7, 0x29, 0xaf, 0x2b, 0x25, 0x0c, + 0x15, 0x47, 0xff, 0xc1, 0x00, 0x9d, 0xfa, 0x58, 0x9c, 0xaa, 0xf9, 0xcc, + 0x4c, 0x51, 0x1d, 0xda, 0xf3, 0x3c, 0x10, 0xd0, 0x3b, 0x59, 0x30, 0x02, + 0x68, 0x29, 0x1c, 0xa7, 0x22, 0xea, 0x81, 0xd3, 0x29, 0x71, 0x39, 0xe8, + 0x72, 0x7f, 0x7d, 0x94, 0x0a, 0x64, 0x2c, 0xe6, 0x55, 0xfb, 0x90, 0x78, + 0x7e, 0x6c, 0x3e, 0xfe, 0x57, 0x14, 0x61, 0xef, 0xe2, 0x63, 0x57, 0x6c, + 0x13, 0x97, 0x27, 0x2b, 0x38, 0x44, 0xab, 0x74, 0x76, 0x11, 0xa6, 0x60, + 0xad, 0x8e, 0xad, 0xe5, 0xa5, 0xa1, 0x66, 0xc5, 0xe1, 0x4d, 0x27, 0xa0, + 0x79, 0x7a, 0x09, 0xe6, 0xf0, 0x28, 0x3f, 0xcb, 0xc6, 0xf8, 0x94, 0xc0, + 0xf1, 0x13, 0xbe, 0x62, 0x6a, 0x52, 0x75, 0x52, 0xd3, 0x82, 0x31, 0xbd, + 0x15, 0xf2, 0xe8, 0x2e, 0xb1, 0x62, 0x03, 0x1e, 0xe2, 0xb3, 0xec, 0xbc, + 0x3c, 0x12, 0xca, 0x62, 0x4e, 0xc2, 0x3a, 0x51, 0x1c, 0xdf, 0xa2, 0x84, + 0x88, 0xe5, 0x7e, 0xd7, 0x5d, 0xd7, 0xbf, 0xf2, 0x7d, 0xbd, 0x9a, 0x90, + 0x63, 0xfd, 0x8a, 0x84, 0x2b, 0x9d, 0x89, 0x27, 0x63, 0x4c, 0x0a, 0xe3, + 0x70, 0x94, 0x7b, 0xe6, 0xb3, 0xd7, 0xcb, 0xcb, 0x8a, 0xeb, 0x6b, 0x53, + 0x34, 0x2f, 0x62, 0x44, 0x2d, 0x73, 0x63, 0x8a, 0xf4, 0xa2, 0x01, 0xd7, + 0x12, 0xb6, 0x8d, 0x8c, 0x4b, 0x73, 0x2b, 0x44, 0x50, 0x49, 0x6f, 0x01, + 0xac, 0xc5, 0x15, 0x37, 0x6c, 0xde, 0xd4, 0x02, 0xb1, 0x12, 0x80, 0x73, + 0xb2, 0x52, 0x0e, 0xe0, 0xb5, 0x75, 0xc9, 0x48, 0xcf, 0x18, 0x5c, 0xcc, + 0xaf, 0x58, 0xa2, 0x3e, 0x28, 0xe4, 0xab, 0xde, 0xea, 0x2a, 0xcf, 0x58, + 0x22, 0xc4, 0x68, 0xea, 0x9b, 0x7b, 0x90, 0xc5, 0xdc, 0x1c, 0x37, 0xd1, + 0x8a, 0x4f, 0xe7, 0x24, 0x23, 0x39, 0xb9, 0x62, 0xb8, 0x41, 0x13, 0x7b, + 0xe2, 0x1e, 0x0d, 0x4e, 0x38, 0x11, 0xa3, 0xb9, 0x10, 0xbb, 0x10, 0x6f, + 0x40, 0x9f, 0x50, 0x05, 0xc7, 0x0e, 0xb9, 0x9e, 0xab, 0x7c, 0x3c, 0x78, + 0xce, 0x54, 0xbf, 0xbf, 0x40, 0x36, 0x76, 0xbc, 0x4b, 0x64, 0x32, 0xca, + 0x0e, 0x2d, 0x91, 0x87, 0xd5, 0x00, 0x19, 0xbf, 0x12, 0xd0, 0x35, 0x7c, + 0xa1, 0xe5, 0xcf, 0x7a, 0x2d, 0x08, 0x62, 0xed, 0x34, 0x61, 0xe3, 0xda, + 0x2c, 0xcc, 0x1b, 0xf8, 0x12, 0xfe, 0xfd, 0x19, 0xa2, 0xc3, 0x70, 0xfd, + 0x4f, 0x5b, 0x5d, 0x20, 0xd2, 0xe1, 0xc5, 0xac, 0xe7, 0xa1, 0x84, 0x00, + 0xbd, 0x46, 0x81, 0xfd, 0x54, 0x69, 0xed, 0x1a, 0x7a, 0x32, 0xbb, 0x75, + 0x22, 0x76, 0x6d, 0x34, 0x24, 0xcc, 0xe6, 0xbe, 0x78, 0x5a, 0x75, 0x6c, + 0xbc, 0x62, 0xb8, 0x14, 0xf7, 0x13, 0x73, 0xc2, 0xdc, 0xb6, 0xfa, 0xfb, + 0x97, 0xfe, 0x27, 0x7b, 0x33, 0xb8, 0xeb, 0x20, 0xd2, 0x0f, 0x4f, 0xed, + 0xd1, 0xd0, 0x63, 0xf7, 0xc5, 0x8e, 0xec, 0xcc, 0xd2, 0x31, 0x38, 0x35, + 0x65, 0x33, 0x5c, 0x63, 0x85, 0xf7, 0x3d, 0xc3, 0x62, 0x26, 0x52, 0x0a, + 0x67, 0xda, 0x87, 0x1f, 0x9e, 0x47, 0xec, 0x6b, 0xf5, 0x74, 0x1a, 0xc5, + 0xa7, 0xa0, 0x0f, 0xdd, 0xc5, 0x42, 0xf4, 0xda, 0x41, 0x1a, 0x48, 0xa9, + 0xbe, 0x4f, 0xb6, 0x28, 0x17, 0xe9, 0xf5, 0xd7, 0x00, 0xb3, 0xfe, 0x05, + 0x4e, 0xa7, 0xdf, 0x65, 0x7a, 0xb8, 0x4f, 0xe0, 0xfe, 0x58, 0x9e, 0xba, + 0x45, 0x11, 0xba, 0xc2, 0xdb, 0x97, 0x97, 0xa4, 0xbc, 0x18, 0x21, 0x1b, + 0xad, 0x82, 0xef, 0xb1, 0x5f, 0x2f, 0x25, 0x9d, 0xca, 0x52, 0xa5, 0x6d, + 0x8c, 0xab, 0x07, 0x2b, 0x7b, 0x6a, 0x77, 0x9d, 0xdf, 0xfb, 0xae, 0x6e, + 0x49, 0x18, 0x25, 0x4a, 0xf2, 0x7d, 0xa0, 0x32, 0xc8, 0x53, 0x10, 0xc3, + 0xf2, 0xef, 0xf3, 0xe7, 0x79, 0xd7, 0x6a, 0x0e, 0x61, 0xff, 0x89, 0xc9, + 0x42, 0xe8, 0x6e, 0x4f, 0x78, 0xe1, 0x5f, 0xcd, 0x7a, 0xf6, 0x27, 0x72, + 0x67, 0xea, 0x0b, 0xa6, 0xcc, 0x34, 0xb7, 0x8f, 0x92, 0x3c, 0x95, 0xb9, + 0x0a, 0x5d, 0x49, 0x2e, 0xb7, 0x7d, 0x31, 0x9c, 0x79, 0x61, 0x95, 0x9c, + 0x60, 0x56, 0x8d, 0x35, 0x00, 0xc5, 0x8b, 0xe6, 0x02, 0x0f, 0x26, 0x39, + 0x7b, 0x93, 0x94, 0xb1, 0xcd, 0xde, 0xed, 0xfa, 0x2a, 0x4b, 0x63, 0xa8, + 0x1b, 0x31, 0x43, 0x5e, 0x69, 0x7c, 0xd6, 0x15, 0x35, 0x9c, 0xa2, 0xd7, + 0xdf, 0x0e, 0x1a, 0x20, 0x50, 0xf5, 0x02, 0x21, 0x30, 0x35, 0x3c, 0x60, + 0x71, 0xad, 0xd0, 0xe3, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x10, 0x17, 0x1d, 0x22, 0x2d}; +#elif MLD_CONFIG_PARAMETER_SET == 87 +const uint8_t expected_signature[] = { + 0xdf, 0xe6, 0xe1, 0xa5, 0x20, 0xc1, 0xac, 0x98, 0x55, 0x2c, 0xf2, 0x13, + 0x65, 0x42, 0xe2, 0xb0, 0x77, 0x5f, 0x15, 0x00, 0x8f, 0x14, 0x48, 0xa1, + 0xe3, 0xee, 0x81, 0x35, 0x15, 0x34, 0xad, 0x6e, 0x60, 0x85, 0x00, 0xf8, + 0x18, 0x53, 0x0d, 0xa0, 0xc5, 0x41, 0xc4, 0x48, 0x09, 0x1b, 0x34, 0x0c, + 0x0e, 0xcf, 0xc6, 0x3d, 0x38, 0x78, 0x8b, 0x69, 0xe5, 0x6f, 0x4d, 0x43, + 0xfa, 0xa6, 0x75, 0x26, 0x8a, 0x75, 0x97, 0x10, 0x6a, 0x1f, 0x3c, 0xa6, + 0x94, 0xa9, 0x93, 0x8f, 0xe5, 0x62, 0xbf, 0x94, 0xe4, 0xd0, 0x0d, 0x11, + 0x4d, 0x03, 0xe2, 0xd8, 0xdf, 0x68, 0xb7, 0x87, 0x62, 0xc9, 0xdc, 0xc9, + 0x36, 0x4f, 0xcc, 0xd1, 0xa4, 0xae, 0x7e, 0xa4, 0xb9, 0xaf, 0xaf, 0xf0, + 0x8a, 0xe6, 0xff, 0x83, 0xe7, 0x54, 0x22, 0x6e, 0x3f, 0x2e, 0xa0, 0x4f, + 0xa8, 0x31, 0x53, 0xf3, 0x62, 0xeb, 0x04, 0xfa, 0xd1, 0x57, 0x39, 0x43, + 0xf9, 0xe0, 0x31, 0x12, 0x45, 0x09, 0x8b, 0x9e, 0x1e, 0x7a, 0x2b, 0x85, + 0xee, 0xdd, 0xe8, 0x1e, 0xd7, 0xc0, 0x17, 0xb4, 0xd2, 0xdc, 0x36, 0xa9, + 0xe4, 0x49, 0x88, 0xbf, 0x71, 0x43, 0x9d, 0x3e, 0xd2, 0x10, 0xe7, 0x82, + 0xb5, 0xfe, 0xdd, 0x42, 0xc8, 0x1b, 0x11, 0xf6, 0x52, 0x23, 0x98, 0x83, + 0x48, 0xec, 0xec, 0x70, 0x8b, 0xe7, 0x49, 0x9a, 0xd7, 0xd9, 0x7b, 0x47, + 0x4e, 0xe2, 0x5e, 0x17, 0x1a, 0xa0, 0x0e, 0x60, 0x85, 0x3a, 0x30, 0x8c, + 0x1c, 0x26, 0xb4, 0xe1, 0xb5, 0x2b, 0x48, 0xf4, 0xb8, 0x93, 0x2f, 0x79, + 0x3a, 0x1e, 0xb6, 0x3b, 0x07, 0x3b, 0x1e, 0x15, 0xd7, 0x85, 0x5e, 0xd4, + 0x06, 0x0e, 0xcd, 0x6a, 0x93, 0x3a, 0x93, 0x29, 0x6a, 0xbe, 0x68, 0x8a, + 0xb6, 0xb8, 0xfa, 0xc5, 0x63, 0x48, 0x98, 0x10, 0x6d, 0xd9, 0xd3, 0x5b, + 0x29, 0x5f, 0x93, 0x90, 0x08, 0x1c, 0x1a, 0x15, 0x7b, 0x0a, 0x59, 0x9d, + 0x64, 0x24, 0x45, 0xb6, 0xd3, 0x7b, 0xc1, 0x5d, 0x74, 0x1f, 0x0b, 0x8e, + 0x18, 0xf2, 0x92, 0x8e, 0xd4, 0x7f, 0x72, 0x5c, 0x98, 0x1f, 0x8b, 0xa5, + 0xb8, 0xf4, 0x7e, 0x12, 0x6a, 0x93, 0xb9, 0xb5, 0xf1, 0xda, 0x97, 0x75, + 0x4f, 0x56, 0x80, 0x88, 0x64, 0x2b, 0xe0, 0x59, 0xcd, 0x5e, 0x91, 0x64, + 0x9c, 0x0c, 0xa8, 0xdd, 0xac, 0xcb, 0xf3, 0x48, 0x3b, 0x5c, 0xc4, 0xc5, + 0xb9, 0x9a, 0x0b, 0x8e, 0x5d, 0x9a, 0xd5, 0xb7, 0xf0, 0xd4, 0x07, 0x48, + 0xb9, 0x63, 0x02, 0x87, 0x8d, 0xae, 0x7e, 0x03, 0x33, 0x4f, 0x86, 0x15, + 0x1b, 0x3b, 0xdf, 0xda, 0xce, 0xd3, 0x1e, 0xc0, 0x76, 0xb5, 0x1c, 0xdd, + 0xb8, 0x32, 0x87, 0x7d, 0x59, 0x18, 0x72, 0x0c, 0xde, 0x8f, 0x63, 0x2d, + 0x38, 0xf2, 0xe9, 0xc2, 0x81, 0xed, 0xfa, 0x2d, 0x61, 0xef, 0x48, 0xdb, + 0xa2, 0xeb, 0xfe, 0x52, 0x31, 0x1e, 0x21, 0x0a, 0x08, 0xf6, 0x02, 0xd3, + 0xc0, 0x32, 0x3b, 0x6b, 0x2f, 0x64, 0xc4, 0xb3, 0x4b, 0xfe, 0x69, 0x78, + 0xbf, 0x20, 0x62, 0x07, 0x77, 0xdf, 0x2c, 0x18, 0x53, 0x61, 0x8e, 0x05, + 0x01, 0x86, 0xab, 0xab, 0xec, 0x18, 0x8c, 0x15, 0x63, 0x1f, 0xe9, 0x99, + 0xb2, 0x35, 0x77, 0xe1, 0x58, 0xf1, 0xa9, 0x4d, 0x1a, 0xb9, 0x8c, 0x30, + 0x63, 0x6f, 0x9e, 0x7d, 0x4e, 0xcf, 0xb5, 0x6c, 0xf3, 0xe4, 0xdc, 0xab, + 0xf9, 0xae, 0x58, 0xf8, 0x1d, 0x08, 0x7b, 0x73, 0x82, 0x58, 0xc8, 0x67, + 0x48, 0x1a, 0x5e, 0x3d, 0xdb, 0xac, 0x1b, 0x1b, 0xef, 0xeb, 0xa4, 0xe5, + 0x67, 0x48, 0x76, 0xd1, 0x96, 0x4f, 0x6c, 0x7d, 0x06, 0x8c, 0x02, 0x86, + 0x95, 0x83, 0xb6, 0x9b, 0x5e, 0x9a, 0xb5, 0x85, 0xc0, 0x4f, 0x13, 0x1c, + 0x32, 0xf8, 0x29, 0xdf, 0x47, 0x85, 0xdb, 0xe4, 0x37, 0xdc, 0xd8, 0x04, + 0x18, 0xdd, 0xca, 0x97, 0xdd, 0x67, 0x13, 0xbe, 0x74, 0x95, 0xdc, 0xd0, + 0xcc, 0xe6, 0xb5, 0xa5, 0x12, 0x9b, 0x23, 0x4f, 0x41, 0x8c, 0xcc, 0x95, + 0xf4, 0xb0, 0x5f, 0x2a, 0xc4, 0xbf, 0x88, 0xda, 0x55, 0xcb, 0x13, 0x93, + 0x22, 0x60, 0x51, 0x43, 0xc7, 0x9a, 0x2c, 0xfa, 0xb2, 0x59, 0xc1, 0xe6, + 0x8a, 0xa4, 0xb8, 0xfb, 0xd3, 0x31, 0x1d, 0xc7, 0x88, 0xdc, 0xbc, 0xe9, + 0xba, 0xe7, 0xdc, 0xe3, 0xdd, 0x90, 0x96, 0xb4, 0xb4, 0x0a, 0xc1, 0x07, + 0x31, 0x3f, 0xdb, 0xc5, 0x4d, 0x73, 0x58, 0x86, 0x15, 0x37, 0x07, 0x86, + 0x03, 0x17, 0x16, 0x18, 0x15, 0xb9, 0x26, 0x35, 0x8a, 0x43, 0x22, 0xae, + 0x21, 0x52, 0x05, 0x4e, 0x5c, 0x3f, 0x3e, 0xb9, 0x2a, 0x19, 0x13, 0xfd, + 0x31, 0x47, 0x6a, 0x74, 0xaa, 0xb9, 0xc6, 0x2c, 0x13, 0x8c, 0x21, 0xc4, + 0x8d, 0x00, 0xf4, 0x24, 0xf2, 0xb7, 0xd3, 0x13, 0xad, 0x29, 0x5e, 0x50, + 0x0b, 0x0e, 0x9f, 0x9a, 0xb7, 0xf6, 0x9e, 0xba, 0x12, 0x23, 0x84, 0x8c, + 0xbe, 0x2c, 0x14, 0x1e, 0xe6, 0x79, 0x15, 0x20, 0x2d, 0x32, 0x08, 0xd8, + 0x1c, 0x87, 0x1b, 0xa8, 0xc0, 0xbb, 0x85, 0xa9, 0x71, 0x30, 0x5e, 0x39, + 0x48, 0x87, 0xdc, 0x3d, 0x03, 0x29, 0x19, 0xd1, 0xd4, 0x21, 0x3a, 0x53, + 0x2d, 0x5e, 0x78, 0xff, 0x94, 0x4b, 0x91, 0xa6, 0xb5, 0xe5, 0x42, 0x56, + 0x67, 0x6a, 0x0e, 0xf3, 0x2d, 0x6a, 0x4e, 0xd7, 0x3a, 0x81, 0xb1, 0x4d, + 0x0b, 0x66, 0x5f, 0x43, 0x28, 0x7c, 0x75, 0x8b, 0x2b, 0x99, 0x24, 0xc2, + 0x5e, 0x8c, 0x22, 0xf0, 0xd5, 0xb3, 0xfc, 0x86, 0x62, 0xf3, 0xd2, 0x6c, + 0xa7, 0x48, 0x04, 0x44, 0x5d, 0x93, 0x74, 0x37, 0x16, 0x2c, 0x19, 0x12, + 0x57, 0x49, 0xef, 0xd5, 0xd6, 0x92, 0xdc, 0x51, 0xf8, 0x55, 0x3a, 0xc0, + 0x0b, 0xdf, 0x41, 0xb5, 0x01, 0x59, 0x7e, 0x85, 0x65, 0xdb, 0x44, 0xbd, + 0x04, 0x96, 0x1a, 0xd4, 0x6e, 0x22, 0x54, 0x92, 0xdb, 0xc7, 0xc5, 0x3a, + 0xdf, 0x0c, 0xf4, 0x1b, 0xdc, 0x14, 0xf6, 0x91, 0x9c, 0xbe, 0xf8, 0x8e, + 0x70, 0xd1, 0x3a, 0x0e, 0x58, 0xe6, 0xb9, 0xd3, 0xaa, 0xa2, 0x70, 0xba, + 0xdd, 0x16, 0x13, 0x19, 0xd1, 0x96, 0x78, 0x04, 0x2f, 0xd7, 0x38, 0x8c, + 0x35, 0x1f, 0xfc, 0x58, 0xa4, 0x4c, 0xa9, 0x9a, 0xae, 0x13, 0x3b, 0xc1, + 0x20, 0x4b, 0x66, 0x0f, 0x72, 0x42, 0x0a, 0x53, 0x84, 0x54, 0x71, 0x06, + 0xdb, 0x85, 0x8f, 0x40, 0xa6, 0x09, 0xf7, 0x24, 0xc4, 0x35, 0xf7, 0x1d, + 0xd4, 0x3d, 0x54, 0x75, 0xaf, 0xc4, 0x78, 0x0f, 0xce, 0xe0, 0x0c, 0x90, + 0x0f, 0xd5, 0x2e, 0x61, 0xf7, 0x58, 0xaa, 0xf0, 0xc7, 0x37, 0x5a, 0x59, + 0x1f, 0x8a, 0x03, 0x98, 0x43, 0xb7, 0x27, 0x78, 0x4e, 0x44, 0x5a, 0xb5, + 0x29, 0xf5, 0xab, 0x9e, 0xb7, 0x2a, 0xc4, 0xa3, 0x03, 0x00, 0xe3, 0x28, + 0x57, 0xc9, 0x2a, 0x98, 0xb8, 0xa1, 0x45, 0x1d, 0xfa, 0x6e, 0xb3, 0x0d, + 0x42, 0x5a, 0xb6, 0xb1, 0x0e, 0x5c, 0xbe, 0x82, 0xe2, 0x36, 0x40, 0x4b, + 0x05, 0x28, 0xd9, 0xbc, 0x27, 0xd6, 0x77, 0x00, 0xc9, 0x29, 0x6a, 0xd6, + 0x19, 0x8f, 0x8d, 0xda, 0xe1, 0xc3, 0x8b, 0x69, 0x71, 0xd0, 0xf7, 0xc8, + 0x33, 0xef, 0xe6, 0x23, 0x6b, 0xcb, 0x00, 0x56, 0x0a, 0x9b, 0x9d, 0x60, + 0x3a, 0xd3, 0xad, 0xd9, 0x5c, 0x6a, 0x7d, 0xab, 0x35, 0x71, 0x93, 0xc5, + 0xf2, 0x6a, 0x38, 0x0e, 0xfb, 0xd9, 0x9b, 0xa5, 0xda, 0x52, 0x45, 0xef, + 0x93, 0x94, 0x5b, 0x08, 0x8c, 0x07, 0xab, 0x2e, 0x99, 0x88, 0x77, 0xb5, + 0x15, 0x66, 0x7f, 0x0e, 0xfa, 0xb0, 0x29, 0xe4, 0x88, 0xd9, 0xdd, 0x22, + 0xaf, 0x7a, 0x4e, 0xb5, 0xd0, 0x62, 0x85, 0x27, 0x33, 0xf1, 0xb7, 0x34, + 0xb1, 0xe6, 0xda, 0x9f, 0x3c, 0xfe, 0xf5, 0xd4, 0xef, 0x56, 0x48, 0x93, + 0x7a, 0x54, 0xa2, 0x7f, 0x07, 0xea, 0x31, 0xb8, 0x8b, 0xca, 0xb9, 0xdb, + 0x1e, 0x2b, 0xb5, 0x16, 0xe6, 0x0e, 0xd9, 0x3f, 0x7c, 0xf0, 0xc2, 0x3e, + 0x57, 0x64, 0x60, 0x97, 0xfb, 0xdf, 0x8c, 0x3e, 0x56, 0x22, 0x92, 0x2a, + 0xb2, 0x21, 0x00, 0x0a, 0x75, 0x89, 0x68, 0xe7, 0x51, 0xa3, 0x63, 0x05, + 0xe1, 0x6f, 0x1e, 0x1e, 0x80, 0xa2, 0x4b, 0x5d, 0xb7, 0xf4, 0xb7, 0x45, + 0x85, 0x00, 0x84, 0x6e, 0xbe, 0x0b, 0x67, 0xbf, 0x21, 0x06, 0x5a, 0x56, + 0x79, 0xe9, 0x6b, 0x0e, 0x72, 0x19, 0x2d, 0x09, 0x78, 0xd5, 0x5e, 0xc2, + 0x32, 0xee, 0x29, 0xd4, 0x7a, 0x65, 0xc7, 0xfe, 0x16, 0x86, 0xd2, 0x29, + 0x71, 0xe5, 0x91, 0x0e, 0x3e, 0x86, 0xd5, 0x00, 0xc4, 0xfc, 0xd9, 0xae, + 0xd3, 0x7c, 0x13, 0xfd, 0x62, 0xce, 0x0c, 0xb2, 0xe5, 0x1f, 0x6d, 0xed, + 0x55, 0x6f, 0xc1, 0xaa, 0xa1, 0x74, 0x59, 0x46, 0x83, 0xd5, 0x5d, 0x71, + 0x17, 0x13, 0x1d, 0x0b, 0x25, 0xfb, 0x0a, 0xcd, 0x67, 0xfe, 0x57, 0x93, + 0xc2, 0x71, 0x55, 0x6c, 0x68, 0xfa, 0x40, 0xdb, 0xdd, 0xce, 0xd5, 0x5c, + 0xce, 0x0a, 0x1d, 0xfa, 0x19, 0x30, 0xe2, 0x2b, 0x63, 0x98, 0x16, 0x2c, + 0x67, 0x69, 0x55, 0xe5, 0xc1, 0x6c, 0x6e, 0xb7, 0x92, 0x6a, 0xbb, 0x10, + 0xd3, 0x13, 0x2e, 0x73, 0x91, 0x74, 0xcb, 0x9f, 0x5c, 0x7f, 0x5c, 0x48, + 0x58, 0x36, 0x13, 0x47, 0xf7, 0x49, 0xae, 0x90, 0x15, 0x53, 0xb5, 0xe6, + 0x37, 0xfb, 0x81, 0x47, 0xb4, 0x69, 0x84, 0xca, 0x95, 0xab, 0x19, 0x2a, + 0x28, 0xc2, 0x8a, 0xf1, 0xcd, 0xf9, 0x3e, 0xd3, 0xaf, 0xe1, 0x75, 0xf7, + 0x94, 0x74, 0x1c, 0xf5, 0x32, 0xcf, 0x70, 0xbd, 0x69, 0xcc, 0xa8, 0x3c, + 0xca, 0x59, 0x53, 0xfa, 0xcb, 0xe7, 0xb6, 0x36, 0x70, 0xea, 0xe2, 0x84, + 0xfa, 0x5e, 0xbd, 0xd7, 0x59, 0x3d, 0x21, 0xc6, 0x9f, 0x5c, 0x1f, 0xa6, + 0xa9, 0xf1, 0xd3, 0x26, 0x9e, 0xff, 0xbc, 0x81, 0xfe, 0xbe, 0xee, 0x64, + 0xd9, 0x63, 0x94, 0x4b, 0x15, 0xd8, 0x95, 0xaa, 0xec, 0x10, 0xc9, 0xe2, + 0xe1, 0x05, 0x37, 0x64, 0xc4, 0xb0, 0x2e, 0xa5, 0x0e, 0x4c, 0x2d, 0x03, + 0x53, 0xf1, 0x93, 0x77, 0x9d, 0x46, 0x14, 0x67, 0x48, 0x5f, 0xad, 0x1b, + 0xdc, 0xb9, 0x74, 0xa2, 0x6c, 0xfc, 0xd2, 0xa0, 0x1f, 0x43, 0x89, 0x15, + 0xc5, 0x0c, 0xb0, 0x9e, 0x1e, 0xc2, 0xd6, 0x44, 0xd9, 0x6e, 0xfc, 0xb4, + 0x9c, 0x95, 0x90, 0xcd, 0xc3, 0x17, 0x1c, 0x6a, 0xce, 0x03, 0x56, 0x9f, + 0xe7, 0xcd, 0x7e, 0xe7, 0xa2, 0x0c, 0x2b, 0x0d, 0x59, 0xb0, 0xc9, 0x4c, + 0x6e, 0x33, 0x6d, 0x43, 0xc4, 0x3a, 0x10, 0x24, 0x03, 0x3e, 0x09, 0xb6, + 0x86, 0x13, 0xba, 0x18, 0x19, 0xd3, 0xff, 0xeb, 0xa5, 0x25, 0x8f, 0x6f, + 0xc8, 0xe6, 0x96, 0xa4, 0xd2, 0x66, 0x40, 0x81, 0x79, 0xe8, 0x39, 0x18, + 0x41, 0x02, 0x66, 0x5c, 0x30, 0x5f, 0x58, 0x9d, 0x35, 0x16, 0xc6, 0x96, + 0xa8, 0x68, 0xbc, 0x09, 0x83, 0x17, 0x2c, 0x5f, 0x5e, 0xd0, 0x1d, 0xb0, + 0x48, 0x5e, 0xcf, 0x91, 0x16, 0x4d, 0xa0, 0xba, 0xbc, 0x61, 0xa8, 0x3f, + 0x30, 0x09, 0xbb, 0xa3, 0x12, 0xcd, 0xdc, 0x29, 0xf7, 0xb0, 0xad, 0x05, + 0x17, 0xd6, 0xd3, 0x16, 0xfb, 0xe5, 0x99, 0xf4, 0x71, 0x62, 0xa3, 0x45, + 0x45, 0xc7, 0x9b, 0xaa, 0x45, 0xd3, 0x35, 0xfe, 0xfb, 0x63, 0xaf, 0xe7, + 0x85, 0x31, 0xc9, 0x66, 0x26, 0xa9, 0xda, 0x8c, 0xc6, 0xf6, 0xd5, 0xdf, + 0xb1, 0xa9, 0xf1, 0xb6, 0x3d, 0x92, 0xae, 0x4d, 0xbc, 0x74, 0x7d, 0x76, + 0x5a, 0x59, 0x8c, 0x87, 0xff, 0x95, 0x2f, 0x67, 0x37, 0x30, 0x1a, 0xc1, + 0x23, 0x2e, 0x0c, 0xaa, 0x80, 0x1c, 0xf3, 0xa3, 0x74, 0x94, 0xb2, 0xda, + 0x1a, 0xb8, 0x46, 0xec, 0x30, 0x76, 0xf4, 0xdf, 0xfb, 0x00, 0xb3, 0x6f, + 0x86, 0xc1, 0xc5, 0x3a, 0x5d, 0x11, 0x14, 0x87, 0xeb, 0x30, 0xd8, 0x33, + 0x18, 0x00, 0x01, 0x76, 0x43, 0x82, 0xcd, 0x1c, 0x36, 0x54, 0xd2, 0x64, + 0x5b, 0xfb, 0x93, 0xca, 0x20, 0x1d, 0xa3, 0x20, 0x99, 0xc3, 0x8e, 0x5c, + 0x82, 0xfc, 0x56, 0x07, 0x41, 0x4b, 0x4f, 0x54, 0xc7, 0xb5, 0xe8, 0x6d, + 0x7e, 0xd8, 0x8a, 0x56, 0xb4, 0x76, 0x1e, 0xd3, 0x82, 0x97, 0xdd, 0x2b, + 0xd9, 0x80, 0xb7, 0xb6, 0xeb, 0x3d, 0xe5, 0xe0, 0x20, 0x27, 0x8c, 0xf0, + 0xd6, 0x14, 0xc7, 0xcd, 0x79, 0xbc, 0xa0, 0x21, 0x85, 0xc3, 0x02, 0xae, + 0x73, 0xc4, 0x0a, 0x39, 0x1a, 0x98, 0x61, 0xc3, 0x86, 0xd8, 0x97, 0x67, + 0x87, 0xe9, 0x56, 0x0b, 0x61, 0xa6, 0x7e, 0x07, 0xfb, 0x0a, 0x8b, 0xd1, + 0x90, 0xbd, 0x39, 0x22, 0xdb, 0xc2, 0x7f, 0xaa, 0x79, 0xb7, 0x39, 0x09, + 0xc1, 0x69, 0xdb, 0xe2, 0x7f, 0xec, 0xde, 0x80, 0x7a, 0x6c, 0xde, 0x76, + 0xa4, 0xe8, 0xe0, 0x8d, 0x71, 0xfa, 0x62, 0xf0, 0x2e, 0x7b, 0xf4, 0xce, + 0x65, 0x18, 0x42, 0xde, 0x92, 0x1b, 0xdc, 0xc9, 0xa7, 0x8d, 0xa5, 0x91, + 0x0f, 0xa5, 0x1b, 0x89, 0xcf, 0x29, 0x10, 0x1d, 0x94, 0x78, 0x1b, 0xea, + 0x79, 0x35, 0x62, 0xd4, 0x29, 0xe6, 0x59, 0x8c, 0xc1, 0xd2, 0xf3, 0x32, + 0x71, 0x09, 0xce, 0x51, 0xd7, 0x14, 0x29, 0x92, 0xbf, 0xdf, 0x9a, 0x69, + 0xda, 0x61, 0x03, 0x0f, 0xa2, 0x0a, 0xab, 0x57, 0x1c, 0xca, 0xab, 0x42, + 0x63, 0x63, 0x1e, 0x35, 0x5d, 0x8d, 0xba, 0x6f, 0x4b, 0x6b, 0x5e, 0x7c, + 0xc0, 0x1e, 0xb7, 0xf4, 0x65, 0xbd, 0x13, 0x1c, 0xf2, 0xa9, 0x73, 0x38, + 0xc3, 0x47, 0xc9, 0x32, 0xf0, 0x30, 0x57, 0x05, 0x42, 0x52, 0xac, 0x72, + 0xee, 0x9f, 0x4e, 0x21, 0xbf, 0x38, 0x19, 0x6d, 0x48, 0xec, 0x97, 0xcb, + 0x70, 0x9e, 0xee, 0xb3, 0xa1, 0xaa, 0xa6, 0x7e, 0xe9, 0x16, 0xdf, 0xcd, + 0x1c, 0x56, 0xcf, 0xf0, 0x9f, 0x4d, 0xd1, 0x8c, 0x14, 0x50, 0x5d, 0x23, + 0x96, 0xe0, 0x1f, 0x61, 0x79, 0xbf, 0x44, 0xfd, 0xa2, 0x31, 0xf7, 0x4c, + 0x0c, 0x8d, 0x8c, 0x1b, 0xbf, 0x8d, 0x45, 0xbf, 0x0b, 0xd8, 0xfb, 0x6f, + 0xff, 0x15, 0xc0, 0x44, 0x7c, 0xb9, 0xb8, 0xf9, 0xef, 0x0d, 0x79, 0x11, + 0x3b, 0x79, 0xd2, 0x52, 0x89, 0x5a, 0xcd, 0x0f, 0x10, 0x92, 0x42, 0xfe, + 0xcf, 0x0a, 0x11, 0x8a, 0x8a, 0xda, 0xee, 0xc8, 0x6b, 0xd9, 0xab, 0xec, + 0xb4, 0x25, 0x6f, 0x8d, 0x68, 0x26, 0xe8, 0xdd, 0xf5, 0xa4, 0xe8, 0x65, + 0x37, 0x03, 0xb0, 0xad, 0x73, 0x3b, 0x4d, 0x74, 0x57, 0x7f, 0x0f, 0x6c, + 0xb0, 0x5d, 0x59, 0x80, 0x13, 0xa1, 0x6c, 0xb0, 0xed, 0x26, 0xec, 0x79, + 0x50, 0x5f, 0x5c, 0xb7, 0xa6, 0xae, 0xe8, 0x0a, 0x6d, 0x55, 0x9a, 0x7f, + 0x59, 0x23, 0xa3, 0x7e, 0x84, 0x7b, 0x3b, 0xfc, 0xde, 0xe1, 0xd9, 0x7c, + 0xd6, 0x87, 0xb3, 0x0e, 0xdb, 0xc1, 0x8c, 0x5e, 0x77, 0xb7, 0x23, 0xd7, + 0x14, 0xd4, 0x23, 0xb4, 0xac, 0x45, 0xbf, 0xfe, 0x40, 0x20, 0x4d, 0x91, + 0x20, 0x94, 0xbd, 0x58, 0xb1, 0x99, 0x69, 0xaf, 0x31, 0x68, 0xbd, 0x61, + 0x5e, 0x87, 0x81, 0x54, 0x4e, 0x2d, 0x03, 0xc2, 0xe2, 0xcd, 0xdc, 0x59, + 0xe5, 0x35, 0xcf, 0xb8, 0xfc, 0x65, 0xed, 0x46, 0xb3, 0x92, 0xe7, 0xf8, + 0x3a, 0x32, 0xaa, 0x0e, 0x5a, 0x82, 0x58, 0x4e, 0x77, 0xd8, 0x33, 0xc9, + 0xb0, 0x3e, 0xad, 0xa5, 0x92, 0xe9, 0xa9, 0x8c, 0x00, 0x72, 0x8f, 0xdc, + 0x77, 0x9d, 0x5c, 0x97, 0xd6, 0x58, 0x20, 0x1e, 0xf4, 0x55, 0x2d, 0xc0, + 0x30, 0xf0, 0x66, 0xda, 0x2d, 0x11, 0xac, 0xd4, 0x2d, 0xd5, 0x25, 0x42, + 0x1d, 0xce, 0x49, 0xb5, 0x95, 0x79, 0x9b, 0x6c, 0x65, 0xe0, 0x8a, 0xc5, + 0x9f, 0x75, 0xe3, 0xe6, 0xf8, 0xa6, 0x88, 0xd6, 0x93, 0x70, 0x4f, 0x89, + 0x94, 0x74, 0xbd, 0xef, 0xc2, 0x1a, 0x55, 0x74, 0x37, 0x44, 0x85, 0x1e, + 0xa9, 0xbb, 0x3f, 0x15, 0xc7, 0x84, 0x80, 0xa5, 0xab, 0xc3, 0x91, 0x8e, + 0xd6, 0x32, 0x46, 0x0d, 0xfa, 0xd1, 0x19, 0xd1, 0xfc, 0x02, 0xe2, 0x20, + 0xa6, 0xa9, 0xf7, 0xf4, 0xcc, 0x5b, 0x54, 0x4f, 0x4a, 0x73, 0x35, 0xda, + 0xf0, 0x31, 0x81, 0x1a, 0x82, 0xe7, 0xd4, 0xc8, 0xb4, 0x1d, 0x70, 0xa9, + 0x5d, 0x67, 0xb9, 0x7d, 0x4b, 0xcd, 0xa4, 0x81, 0xf9, 0xb2, 0x38, 0x07, + 0x16, 0xd5, 0x28, 0x82, 0xb9, 0x76, 0x5b, 0xa1, 0x09, 0x7a, 0xe7, 0x2a, + 0xcf, 0xc0, 0x3d, 0x2a, 0x42, 0x9a, 0xf3, 0xc8, 0x64, 0x15, 0x7c, 0x94, + 0xd0, 0x97, 0xee, 0x34, 0xb6, 0xf0, 0xb2, 0xba, 0x7e, 0xb2, 0xbb, 0x4e, + 0xbf, 0x88, 0xd0, 0x6b, 0xc5, 0x9c, 0xb9, 0xf2, 0x7d, 0xbf, 0x5d, 0x87, + 0xbc, 0x36, 0x4a, 0xd1, 0x1b, 0x6f, 0x40, 0x09, 0xba, 0x26, 0x51, 0xd6, + 0xc0, 0xaf, 0x27, 0xce, 0x27, 0x8d, 0x93, 0xa8, 0x6c, 0x91, 0xe7, 0x91, + 0x42, 0xc0, 0x68, 0x36, 0x5b, 0xd5, 0x56, 0x4c, 0xe2, 0x77, 0xc3, 0xac, + 0x56, 0xe3, 0x1c, 0xc2, 0xf9, 0x78, 0x02, 0x39, 0x7d, 0xed, 0x18, 0x2a, + 0x01, 0x48, 0xe6, 0xf6, 0x7e, 0x34, 0x50, 0xf4, 0x57, 0x56, 0x93, 0xdb, + 0x85, 0x1b, 0x1e, 0x1a, 0x6f, 0x3e, 0x07, 0x3c, 0xad, 0x3f, 0x8d, 0x75, + 0x53, 0xc3, 0x20, 0x72, 0x93, 0x28, 0xd2, 0x86, 0xc8, 0xa5, 0x90, 0xf2, + 0x5f, 0x13, 0xd5, 0xa5, 0xbe, 0x88, 0x9e, 0x9a, 0x57, 0x2c, 0x53, 0x3f, + 0x11, 0x25, 0x00, 0x00, 0x4a, 0x16, 0x8d, 0xd3, 0x3f, 0x2d, 0x3d, 0x88, + 0xbb, 0x4c, 0x4f, 0x9a, 0xb9, 0x97, 0x5f, 0xed, 0x71, 0xa9, 0x68, 0xd9, + 0x4a, 0x14, 0x24, 0xc7, 0xbe, 0xff, 0x85, 0x57, 0xa3, 0x21, 0xe3, 0x21, + 0x79, 0x1f, 0xd0, 0xbb, 0xb7, 0x73, 0xde, 0x60, 0x02, 0x4b, 0x8f, 0x7d, + 0xb3, 0xb3, 0x8a, 0xda, 0x4c, 0xf4, 0xb8, 0xf1, 0x31, 0xff, 0x32, 0x7b, + 0xd8, 0xfa, 0xb1, 0xcb, 0xb4, 0x58, 0xf5, 0xc8, 0x64, 0xdf, 0xfe, 0x3d, + 0x89, 0x52, 0x5c, 0x52, 0x95, 0xf3, 0xba, 0x0d, 0x1d, 0x2c, 0xc4, 0xf7, + 0x3c, 0x3b, 0x6f, 0x8e, 0xc7, 0xab, 0xad, 0x3d, 0x3d, 0x95, 0x9b, 0xc7, + 0x71, 0x36, 0xae, 0x08, 0xc3, 0x08, 0x79, 0xfa, 0x24, 0xee, 0xd9, 0xf9, + 0x63, 0xc7, 0xd9, 0x16, 0x19, 0x8e, 0x0d, 0xaf, 0x52, 0x87, 0x86, 0x7d, + 0xec, 0xe5, 0xea, 0x5a, 0xda, 0x86, 0x9d, 0x0e, 0x50, 0x53, 0x8c, 0x24, + 0xa8, 0x69, 0xc4, 0xf3, 0x85, 0x7b, 0x34, 0x67, 0x19, 0x35, 0xec, 0xd4, + 0xd4, 0x50, 0xe0, 0xe6, 0xe9, 0x29, 0x5b, 0x92, 0xee, 0xba, 0xa9, 0xef, + 0xf6, 0x35, 0x23, 0x8b, 0xdb, 0x48, 0x32, 0x25, 0x41, 0xf3, 0x55, 0x12, + 0x33, 0xc3, 0x6c, 0xed, 0x32, 0xe1, 0x64, 0x7a, 0x8d, 0xa2, 0x19, 0x5a, + 0x26, 0xf2, 0x83, 0xf1, 0xe4, 0x27, 0xdb, 0x67, 0xc3, 0x89, 0x37, 0xea, + 0x78, 0x19, 0xc6, 0xa3, 0x82, 0x84, 0x1c, 0xf3, 0x2b, 0xbe, 0xde, 0xba, + 0xe7, 0x60, 0x2e, 0xf5, 0x4e, 0xb6, 0x73, 0x29, 0xac, 0xc7, 0x55, 0xab, + 0x21, 0xe9, 0x95, 0x78, 0xd5, 0x8e, 0x27, 0xdc, 0x92, 0x5f, 0xc0, 0xcb, + 0xee, 0x66, 0x09, 0x0a, 0xfc, 0x94, 0x43, 0x44, 0x50, 0x35, 0x57, 0xf8, + 0x08, 0xf9, 0x97, 0xa2, 0x0e, 0xde, 0x81, 0xe1, 0xd1, 0xa0, 0x41, 0xfe, + 0xe6, 0x08, 0x6c, 0x98, 0x8c, 0x81, 0x46, 0x0e, 0xf9, 0x9a, 0x54, 0xfe, + 0xc3, 0x91, 0xe3, 0xd4, 0x46, 0xca, 0x52, 0xa2, 0x73, 0x9e, 0x4d, 0xa7, + 0xfd, 0xa1, 0x8e, 0x43, 0x28, 0xf5, 0xa3, 0xa2, 0x62, 0x20, 0x53, 0x62, + 0x05, 0x49, 0xba, 0x06, 0xe2, 0xeb, 0xba, 0xfb, 0x8e, 0xa0, 0x22, 0xc7, + 0xf9, 0xcc, 0x7f, 0x8b, 0xa8, 0x5d, 0x55, 0xd2, 0x24, 0xff, 0xdd, 0x2c, + 0xc1, 0xd0, 0x3d, 0xe4, 0x79, 0xea, 0xba, 0x62, 0xe5, 0xa2, 0x62, 0xf4, + 0x1f, 0xec, 0xb0, 0x07, 0xf2, 0x0d, 0x32, 0x84, 0x86, 0x81, 0x3d, 0x95, + 0xc1, 0x64, 0xfe, 0x9a, 0x3d, 0x8f, 0x4b, 0x6d, 0xfb, 0x0d, 0x42, 0xcf, + 0xbf, 0xdb, 0x51, 0xb2, 0x16, 0xa2, 0x35, 0xaa, 0xe7, 0x31, 0x54, 0xc2, + 0x87, 0xc6, 0xa5, 0x30, 0x71, 0x64, 0x65, 0xff, 0x41, 0x20, 0xb0, 0x83, + 0xdb, 0xb7, 0x95, 0xce, 0xd7, 0xcc, 0x7a, 0x77, 0xad, 0xb8, 0xb7, 0x4c, + 0xfc, 0x11, 0x05, 0x2b, 0xc4, 0xd4, 0xb6, 0x8b, 0xae, 0x13, 0xa5, 0x40, + 0x18, 0x6e, 0x0d, 0xe3, 0xc6, 0xb0, 0x81, 0x46, 0x46, 0x7e, 0x52, 0x0b, + 0x85, 0x4d, 0x98, 0xd9, 0x42, 0xdf, 0xde, 0x45, 0xc1, 0x5a, 0x33, 0x12, + 0x46, 0x26, 0xb3, 0x6f, 0xf2, 0x8b, 0x37, 0x6b, 0xfd, 0x08, 0xf4, 0x46, + 0x86, 0x89, 0x63, 0x63, 0x21, 0xe5, 0xa9, 0xb7, 0xd0, 0x09, 0x17, 0x52, + 0xee, 0xea, 0xdf, 0x97, 0xb7, 0x73, 0x2e, 0x54, 0x2c, 0x7b, 0x70, 0xd3, + 0xda, 0x26, 0x57, 0x1f, 0xb0, 0x19, 0xd9, 0x91, 0x18, 0x69, 0x75, 0x42, + 0x63, 0xcf, 0x6c, 0x8c, 0x98, 0x5e, 0x17, 0x99, 0x7e, 0x1d, 0xdc, 0x67, + 0x6d, 0x99, 0xd9, 0x02, 0x6e, 0x73, 0x90, 0x5a, 0x4f, 0x0a, 0xb4, 0x48, + 0xfb, 0xc5, 0xbd, 0xd2, 0x10, 0x05, 0xa6, 0x12, 0x68, 0x36, 0x28, 0x51, + 0x60, 0x1c, 0xa1, 0xe9, 0x90, 0x54, 0xa5, 0x53, 0xc3, 0x48, 0x9e, 0xd8, + 0x42, 0x52, 0x85, 0x0e, 0xff, 0xfe, 0xbf, 0xad, 0x3a, 0xa4, 0x57, 0x09, + 0x13, 0x38, 0x64, 0x15, 0x7c, 0xfd, 0xed, 0x91, 0x76, 0x44, 0x20, 0x84, + 0xd9, 0x90, 0xab, 0xfe, 0xfd, 0xd6, 0xab, 0xf1, 0xb3, 0x25, 0x21, 0x3d, + 0x97, 0x72, 0xb2, 0x95, 0xc5, 0x22, 0x80, 0xd9, 0x4a, 0x49, 0x9d, 0x99, + 0xc2, 0x4a, 0x9a, 0x59, 0xb3, 0x71, 0x75, 0x5b, 0xf9, 0x89, 0x7a, 0xdd, + 0xa9, 0xb3, 0xc3, 0xeb, 0x42, 0x91, 0xe2, 0x97, 0x30, 0x40, 0x48, 0x68, + 0x19, 0x3b, 0xf5, 0x7b, 0x4e, 0x33, 0x4b, 0x0c, 0xf3, 0xed, 0xda, 0x76, + 0x3f, 0xb0, 0x4b, 0x53, 0x85, 0x04, 0x33, 0x07, 0x53, 0xd8, 0x55, 0xa2, + 0xfb, 0x30, 0x2c, 0x66, 0xbd, 0x21, 0xf8, 0xfa, 0x20, 0x14, 0x9a, 0x0d, + 0x7f, 0xc9, 0x2f, 0x5b, 0x34, 0x29, 0x09, 0x16, 0xb5, 0x0a, 0x8d, 0xdf, + 0xa2, 0x84, 0x9a, 0xae, 0xe6, 0xa0, 0x50, 0x80, 0x31, 0x04, 0xd3, 0x0c, + 0x8f, 0xd1, 0x8a, 0xfd, 0xb4, 0xa5, 0xae, 0xf5, 0x3c, 0x62, 0xae, 0x45, + 0x70, 0xbb, 0x54, 0x62, 0xc8, 0x50, 0x71, 0x42, 0x85, 0xf6, 0x6f, 0xa0, + 0xf0, 0x10, 0x8a, 0x09, 0xbd, 0x71, 0x78, 0xa6, 0x5e, 0xe4, 0x03, 0x8f, + 0x3b, 0xd0, 0x5c, 0x37, 0x55, 0x1a, 0xc8, 0x57, 0x26, 0x62, 0x6c, 0xc4, + 0x67, 0x71, 0x9d, 0x97, 0xc0, 0xea, 0x35, 0x3e, 0x12, 0xd0, 0x2b, 0xc2, + 0x8f, 0x9e, 0xa6, 0x41, 0x48, 0x33, 0x83, 0x38, 0x37, 0x7e, 0xd4, 0xe3, + 0xee, 0x94, 0x8b, 0x81, 0xa4, 0x60, 0xdd, 0xdd, 0xc1, 0x8a, 0x7b, 0xda, + 0xa8, 0x46, 0xb8, 0x42, 0x3a, 0x25, 0xd6, 0x81, 0x89, 0x29, 0x21, 0xc2, + 0x0c, 0x5b, 0xfd, 0x3e, 0x8c, 0x65, 0x91, 0x52, 0xb3, 0x74, 0x1f, 0xd1, + 0x49, 0x7e, 0x1d, 0x59, 0x58, 0x96, 0xb5, 0xee, 0x32, 0xa4, 0xa8, 0x07, + 0x7c, 0xd1, 0x5b, 0x4b, 0xf8, 0x43, 0x5a, 0xa5, 0xcc, 0x60, 0xcc, 0x08, + 0x6a, 0x3c, 0x41, 0x66, 0x99, 0xe3, 0xa8, 0xe0, 0xb8, 0x87, 0xfc, 0x92, + 0xc0, 0x79, 0xc5, 0x3f, 0xd6, 0xc6, 0x8c, 0x01, 0xf4, 0xa5, 0x05, 0xad, + 0x51, 0xed, 0x04, 0xd7, 0x55, 0xc0, 0x73, 0x05, 0x0e, 0x73, 0xe5, 0x39, + 0x45, 0x5b, 0x95, 0x4a, 0x34, 0x07, 0x99, 0xdf, 0x4c, 0x35, 0xf5, 0x0c, + 0x27, 0x6d, 0xd1, 0x45, 0xf1, 0xfd, 0x24, 0xb7, 0xfe, 0xea, 0x11, 0x5d, + 0xa2, 0xc5, 0xa6, 0x81, 0x37, 0x1d, 0xc2, 0x31, 0x31, 0xfc, 0xe0, 0xf4, + 0xd7, 0xe9, 0x98, 0x8b, 0xe3, 0x70, 0x51, 0x62, 0xc8, 0x61, 0x6d, 0xec, + 0x75, 0x56, 0x71, 0xae, 0x88, 0xe0, 0x80, 0xf5, 0xb7, 0x85, 0x10, 0xb7, + 0x3d, 0x16, 0x78, 0x5f, 0x72, 0xab, 0x8f, 0x63, 0xc6, 0xd5, 0xa8, 0xc9, + 0x9c, 0xef, 0x8d, 0x9a, 0xc5, 0x4f, 0x63, 0xad, 0xc0, 0xf3, 0x1f, 0x69, + 0x0e, 0xce, 0x29, 0x92, 0xc1, 0x3b, 0xb0, 0xc5, 0xed, 0x0a, 0x7b, 0x92, + 0xd0, 0x4c, 0x9c, 0x82, 0xb0, 0x51, 0xf6, 0x33, 0x61, 0x3b, 0x76, 0x48, + 0x38, 0xf4, 0x7c, 0xaa, 0x52, 0x87, 0x15, 0x1a, 0xbe, 0xb8, 0xdc, 0x9b, + 0x16, 0xd2, 0x07, 0xf7, 0xf9, 0x74, 0xe0, 0xaf, 0x0e, 0x29, 0x05, 0xec, + 0x6c, 0x0e, 0x3b, 0xa7, 0xe7, 0xa4, 0xfc, 0xa4, 0xef, 0x57, 0x16, 0x7f, + 0x13, 0xbd, 0x8c, 0x42, 0x02, 0x55, 0x70, 0x56, 0xa5, 0xa9, 0x01, 0x29, + 0x12, 0x7d, 0x80, 0x46, 0x18, 0x8e, 0x39, 0x3f, 0x44, 0x55, 0xec, 0xef, + 0x60, 0x58, 0x7d, 0xce, 0x64, 0x8e, 0x9c, 0xea, 0xe4, 0x73, 0xd1, 0x48, + 0x9c, 0x3f, 0x92, 0xa0, 0x9a, 0x76, 0xa5, 0x5a, 0x13, 0x1f, 0x10, 0xb9, + 0xb7, 0xb1, 0xde, 0x49, 0x22, 0x58, 0xf4, 0x43, 0x5f, 0x03, 0x43, 0xc3, + 0x6c, 0xbf, 0x82, 0xaf, 0x88, 0x39, 0xfd, 0xb2, 0x28, 0x9b, 0x47, 0x3f, + 0x83, 0x3d, 0xd9, 0x7c, 0xf0, 0xc9, 0xc5, 0xa2, 0xb4, 0xd6, 0x0d, 0x59, + 0x51, 0x27, 0x60, 0x10, 0x5e, 0xbb, 0x18, 0xa6, 0x42, 0x4a, 0x9d, 0xc4, + 0x16, 0x0e, 0xb6, 0x57, 0x23, 0x03, 0x24, 0x27, 0xdc, 0x20, 0x56, 0x30, + 0x8b, 0x0f, 0xb6, 0xb7, 0x73, 0xf5, 0x36, 0x3e, 0xf6, 0x7a, 0x71, 0xa5, + 0x57, 0xcc, 0x6d, 0xc6, 0xf3, 0xdc, 0x35, 0xfb, 0x95, 0xf7, 0xa7, 0xd7, + 0x56, 0x38, 0xd4, 0x15, 0xe2, 0xd5, 0x6f, 0x70, 0x30, 0xc8, 0x7d, 0x8a, + 0x87, 0xe6, 0xd1, 0xe0, 0x50, 0x62, 0xde, 0xfa, 0x29, 0x40, 0x97, 0xa0, + 0x54, 0x63, 0x31, 0xd3, 0x08, 0x87, 0x0a, 0xdc, 0x6e, 0x5e, 0xab, 0x8d, + 0x16, 0xaf, 0x6e, 0x8b, 0x1a, 0x77, 0xf6, 0xd4, 0xe0, 0xbf, 0x59, 0xab, + 0xc7, 0xb0, 0x45, 0x18, 0xaa, 0xe6, 0x65, 0x6f, 0x7d, 0x13, 0xb2, 0xbf, + 0xb3, 0x66, 0x72, 0xfa, 0xfd, 0xee, 0xad, 0x07, 0x56, 0x51, 0x6a, 0xe2, + 0xff, 0xb2, 0xaf, 0x4d, 0xd1, 0xf2, 0x77, 0x35, 0x5e, 0x90, 0xcd, 0xe7, + 0xa8, 0x32, 0x4d, 0x9f, 0xbd, 0xa8, 0xce, 0xab, 0xf1, 0x49, 0x98, 0xb5, + 0x23, 0x5c, 0x62, 0x2d, 0x43, 0x31, 0x80, 0x87, 0xc2, 0xa8, 0xf5, 0xb9, + 0xb6, 0xae, 0x7f, 0x37, 0x13, 0xb8, 0x6b, 0x73, 0xf3, 0x56, 0x38, 0xa7, + 0x9b, 0x97, 0x69, 0x37, 0x00, 0xdc, 0xff, 0xfe, 0x58, 0xc9, 0x12, 0x47, + 0x75, 0x98, 0x1f, 0xad, 0xd8, 0xb5, 0xc8, 0x47, 0x4f, 0xd0, 0x72, 0x63, + 0x54, 0x25, 0x6c, 0x88, 0xc9, 0x9f, 0x3c, 0x82, 0xe0, 0xdd, 0x4c, 0xff, + 0x8e, 0xaf, 0x8f, 0x8e, 0xea, 0x84, 0x3f, 0x73, 0xdd, 0x9e, 0x18, 0x73, + 0x47, 0x70, 0xc7, 0xc7, 0x99, 0x65, 0xcf, 0xf3, 0xb6, 0x24, 0xed, 0x97, + 0x8f, 0xcd, 0x93, 0x1e, 0xff, 0x6e, 0x9c, 0xf1, 0x30, 0x14, 0x1a, 0x27, + 0x59, 0x6a, 0x0e, 0xf3, 0xe4, 0xfa, 0x1d, 0x65, 0xb5, 0x53, 0xe4, 0xab, + 0xb1, 0x3e, 0xe1, 0x91, 0xf4, 0x6d, 0x99, 0xca, 0x7d, 0x03, 0x08, 0x50, + 0xea, 0xa9, 0x39, 0x7f, 0x6d, 0xe7, 0x43, 0xfb, 0x64, 0xcc, 0x4b, 0x9e, + 0xa0, 0x26, 0xe4, 0x0e, 0xff, 0xb7, 0x11, 0x0a, 0x29, 0x50, 0x90, 0xd7, + 0x4d, 0x62, 0x9a, 0x4a, 0x23, 0xb7, 0xd3, 0x53, 0xde, 0x3a, 0xd1, 0xba, + 0xd3, 0x10, 0x59, 0xc6, 0xc5, 0x5e, 0xac, 0xf9, 0x61, 0x74, 0x54, 0xf4, + 0x27, 0x9f, 0x9a, 0x61, 0x13, 0xdc, 0xe5, 0x96, 0xe3, 0x95, 0x0d, 0xcc, + 0xbd, 0x81, 0x74, 0x79, 0x73, 0xef, 0x2e, 0x0b, 0x0f, 0x91, 0x65, 0x3c, + 0x26, 0x7c, 0x47, 0x10, 0x31, 0x0b, 0xfb, 0x41, 0x0c, 0xc2, 0xa8, 0xc4, + 0x0e, 0xbd, 0x0a, 0x8c, 0xa4, 0x80, 0x45, 0x57, 0x62, 0x0b, 0x4d, 0x44, + 0x5e, 0x59, 0x77, 0xfd, 0x3d, 0xf3, 0xd7, 0x92, 0x49, 0xc1, 0xcb, 0x8a, + 0x54, 0x56, 0x3b, 0xde, 0xcf, 0x16, 0x9a, 0x65, 0xbe, 0xac, 0x64, 0xe1, + 0xd4, 0xd4, 0x1e, 0xac, 0x6b, 0x4a, 0xad, 0xc4, 0x33, 0xac, 0xcb, 0x83, + 0xf4, 0x4d, 0xe8, 0xb6, 0xd7, 0x23, 0xd7, 0x71, 0x25, 0xa2, 0x25, 0x3d, + 0x7e, 0xf0, 0x3b, 0x7f, 0x61, 0x11, 0x56, 0xd4, 0x83, 0xc8, 0xc0, 0x29, + 0x38, 0x10, 0x73, 0xad, 0x6a, 0xb7, 0xb9, 0xd2, 0x2e, 0x9f, 0xae, 0x16, + 0x5e, 0xa6, 0x13, 0x1c, 0xc2, 0x17, 0x73, 0x43, 0x03, 0xdd, 0xa6, 0xaf, + 0x9a, 0x17, 0x31, 0xb8, 0x86, 0x97, 0xc2, 0xd6, 0xe6, 0xed, 0xd4, 0xe1, + 0x7d, 0xb9, 0xa6, 0x96, 0xc1, 0x4b, 0xcb, 0x11, 0x1e, 0xe1, 0xe0, 0xd2, + 0x28, 0x69, 0x68, 0x3b, 0x21, 0x17, 0x63, 0x0c, 0xc0, 0x49, 0x30, 0x22, + 0x3a, 0x59, 0x72, 0xe6, 0x47, 0xb4, 0xdc, 0xa8, 0x29, 0x1c, 0x89, 0xa6, + 0x3a, 0x77, 0x99, 0xea, 0x46, 0xce, 0x38, 0xda, 0x31, 0x88, 0xad, 0xe7, + 0x26, 0xce, 0xc6, 0x56, 0x04, 0x30, 0xfa, 0x01, 0xac, 0xbb, 0xe2, 0xb8, + 0x23, 0xe4, 0x9d, 0x4f, 0x77, 0x02, 0x00, 0x28, 0xf1, 0xe0, 0x19, 0x3f, + 0x22, 0x4f, 0x22, 0x69, 0x87, 0xc0, 0x4e, 0x26, 0x33, 0xfe, 0x6c, 0x70, + 0x56, 0x3b, 0x60, 0x5f, 0xfb, 0xf8, 0x43, 0xcf, 0x3f, 0xb9, 0xcb, 0x80, + 0x22, 0xbb, 0x0a, 0xa8, 0x1c, 0x3e, 0x7e, 0x4d, 0x42, 0x60, 0x5c, 0x8e, + 0xfa, 0x42, 0xb3, 0x95, 0xe7, 0x92, 0x6b, 0xec, 0x7a, 0x95, 0x88, 0x98, + 0xe3, 0xf9, 0x0d, 0xe5, 0x08, 0xf1, 0x26, 0x96, 0x2a, 0x81, 0x2b, 0x7c, + 0x0d, 0x12, 0xa0, 0x7f, 0x7b, 0x39, 0xf6, 0xcc, 0x1b, 0x2d, 0x2c, 0xe9, + 0x5b, 0x02, 0x9b, 0x5c, 0x94, 0x51, 0x13, 0xe8, 0xa0, 0x19, 0xce, 0xde, + 0x07, 0x1b, 0xda, 0x39, 0x14, 0xb5, 0x8b, 0xcf, 0x79, 0x3e, 0x2b, 0xb8, + 0x75, 0xab, 0x81, 0xee, 0x5e, 0x08, 0x33, 0xc3, 0x49, 0x5b, 0x4a, 0x9c, + 0x74, 0x34, 0xde, 0x08, 0x61, 0x03, 0x38, 0xe3, 0xd8, 0xff, 0xc5, 0xc0, + 0xb5, 0x40, 0xd5, 0x26, 0x57, 0x85, 0xf1, 0xb7, 0x77, 0xb6, 0x36, 0xe0, + 0x8d, 0x43, 0x3a, 0xef, 0xfe, 0x0f, 0xf7, 0xee, 0x67, 0x6c, 0x7b, 0xd1, + 0x83, 0xf6, 0x10, 0xda, 0x67, 0x04, 0x3a, 0x27, 0xd8, 0x3a, 0xcb, 0x9d, + 0x4c, 0xa6, 0x9a, 0xc7, 0xea, 0x07, 0xc6, 0x76, 0x79, 0x1b, 0x23, 0x4a, + 0x68, 0x2f, 0x14, 0x84, 0x42, 0x79, 0xe8, 0x1f, 0xf2, 0xe6, 0xac, 0x72, + 0xb0, 0xb0, 0xb6, 0x39, 0x95, 0x40, 0xa4, 0x6e, 0x54, 0x2e, 0xb7, 0xb5, + 0x13, 0x70, 0x48, 0x0d, 0x27, 0xed, 0x2c, 0xa2, 0x64, 0x53, 0xb4, 0x04, + 0x84, 0xab, 0xd8, 0xea, 0x2a, 0x8c, 0xac, 0x5b, 0x1d, 0xb8, 0xb2, 0xbe, + 0x55, 0x2b, 0x4a, 0x47, 0xfc, 0xe0, 0x15, 0x78, 0xb6, 0xd6, 0xff, 0x20, + 0xa8, 0x8a, 0xec, 0x8b, 0x30, 0xef, 0xc5, 0xc6, 0xec, 0xa0, 0xdf, 0xd3, + 0xc4, 0x2b, 0x4a, 0xdf, 0xef, 0x5c, 0x46, 0xb3, 0x31, 0xc7, 0x5f, 0x8f, + 0x1e, 0x99, 0x76, 0x81, 0x71, 0x61, 0xdb, 0xc3, 0xc4, 0x0f, 0x66, 0x7b, + 0xd7, 0x44, 0xc7, 0x8d, 0x12, 0x38, 0x71, 0x7c, 0xd8, 0x41, 0xf6, 0x8a, + 0xb9, 0xba, 0xd2, 0x1f, 0xa1, 0x27, 0x64, 0x67, 0x51, 0xb2, 0xaf, 0xea, + 0x02, 0x95, 0x79, 0x20, 0x0a, 0xc8, 0xaa, 0x03, 0x11, 0xb6, 0x8b, 0x7d, + 0x86, 0xb7, 0xef, 0x5e, 0x3f, 0x0b, 0x91, 0x47, 0xf0, 0x43, 0xb4, 0x54, + 0x1d, 0x16, 0x66, 0xe9, 0x63, 0x1a, 0x55, 0xaf, 0x34, 0xad, 0x11, 0x68, + 0x4d, 0x36, 0xb7, 0x0c, 0x6d, 0x4d, 0xed, 0xba, 0x14, 0xe8, 0xf6, 0xe2, + 0x15, 0x64, 0xb6, 0x15, 0x28, 0xbf, 0xd2, 0x4d, 0xb6, 0x6f, 0xca, 0x5f, + 0x81, 0x1b, 0xf0, 0x31, 0xf5, 0xd3, 0xe0, 0x06, 0xc7, 0xf3, 0x0c, 0x18, + 0x91, 0x45, 0x22, 0xa2, 0x30, 0x48, 0x82, 0xeb, 0x42, 0xfc, 0x8f, 0x2a, + 0xa3, 0x1a, 0x8d, 0x84, 0x28, 0x20, 0x16, 0x95, 0xd9, 0x66, 0x67, 0x2b, + 0xef, 0xc6, 0x6e, 0x56, 0x1c, 0x62, 0x74, 0x16, 0x5c, 0x3e, 0x17, 0xd0, + 0xb7, 0xdd, 0x70, 0xb6, 0x0e, 0x79, 0x46, 0xc5, 0x4e, 0x72, 0x46, 0x69, + 0xf5, 0xa1, 0x1c, 0x7b, 0xd5, 0x67, 0x5c, 0xb3, 0x46, 0x4d, 0x18, 0x31, + 0x47, 0x42, 0x20, 0xe6, 0x12, 0x84, 0x4e, 0x16, 0x0f, 0x4a, 0xd0, 0xc4, + 0x91, 0xa3, 0xbd, 0x91, 0xcd, 0x86, 0x4c, 0xcd, 0x4b, 0x2e, 0x62, 0x84, + 0xea, 0x19, 0x2d, 0x21, 0x1a, 0x64, 0xc4, 0xd2, 0x24, 0x92, 0x96, 0x04, + 0x66, 0xb5, 0x4a, 0xe4, 0xa9, 0xd6, 0xaf, 0x12, 0x9b, 0xb5, 0x59, 0xe0, + 0x5c, 0x84, 0x84, 0x7c, 0x68, 0x99, 0xd8, 0x23, 0xa2, 0x15, 0xa7, 0x82, + 0xa5, 0x66, 0x95, 0x8f, 0xfe, 0x57, 0xc1, 0x12, 0x6c, 0x89, 0xe5, 0x5b, + 0x5d, 0x64, 0xdb, 0x81, 0x4f, 0x77, 0x3c, 0xc8, 0x52, 0x4e, 0x2a, 0xd6, + 0x74, 0x3c, 0x4b, 0x11, 0xfc, 0xc1, 0x7c, 0x01, 0xba, 0x0f, 0x0f, 0x57, + 0x8a, 0xbe, 0x5b, 0x16, 0x88, 0x96, 0xe6, 0xe9, 0x60, 0xcf, 0x66, 0xe9, + 0xe6, 0x07, 0xb0, 0x0b, 0xa3, 0xa0, 0xad, 0xdf, 0x70, 0xd4, 0xcb, 0x2e, + 0x33, 0x2f, 0xe5, 0xf2, 0x1e, 0x0d, 0x74, 0x7a, 0xf9, 0x4a, 0x0f, 0x32, + 0xb4, 0xa1, 0xc9, 0xf5, 0x3f, 0x0a, 0x06, 0xf9, 0x67, 0x45, 0x9c, 0xd9, + 0x58, 0xd4, 0x0e, 0x72, 0x55, 0x47, 0x49, 0x9b, 0xab, 0x9c, 0x66, 0xe7, + 0x4d, 0x9a, 0x02, 0x1b, 0x41, 0xad, 0xe5, 0x8c, 0x7f, 0xa1, 0xdc, 0xad, + 0xcd, 0x74, 0xda, 0x9f, 0xfa, 0x87, 0x32, 0xc1, 0x07, 0x8e, 0x9b, 0xef, + 0x28, 0x2f, 0x17, 0x6d, 0xdb, 0x84, 0x4b, 0xa8, 0x7d, 0x31, 0xa8, 0x32, + 0xe4, 0x9a, 0x1e, 0x0e, 0xef, 0x68, 0xf4, 0xac, 0x03, 0x6c, 0x68, 0xcc, + 0x28, 0xbb, 0xfb, 0x21, 0xb8, 0x11, 0xd7, 0xf9, 0xe8, 0x24, 0x37, 0xdf, + 0xe0, 0xb2, 0xef, 0xd6, 0xec, 0xdf, 0xcf, 0xf5, 0x50, 0x19, 0xa3, 0xa9, + 0x1b, 0x01, 0x2e, 0x94, 0x42, 0xb0, 0x14, 0x5d, 0x0e, 0x37, 0x46, 0x4a, + 0x52, 0x53, 0x60, 0x6b, 0x89, 0xc9, 0xca, 0xed, 0x0a, 0x0c, 0x18, 0x33, + 0x3c, 0x40, 0x42, 0x76, 0x7a, 0x7d, 0xb6, 0x10, 0x29, 0x3e, 0x42, 0x75, + 0xa6, 0xbf, 0xcb, 0xd3, 0xdc, 0xe1, 0x00, 0x05, 0x08, 0x25, 0x67, 0x6c, + 0x72, 0xde, 0x26, 0x72, 0x88, 0xbe, 0xfa, 0x05, 0x57, 0x77, 0x78, 0x83, + 0xce, 0xd5, 0x44, 0x49, 0x8b, 0xab, 0xbc, 0xca, 0xd3, 0x1c, 0x34, 0x4a, + 0xaa, 0xc7, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x17, 0x22, 0x2a, 0x2f, 0x36, 0x3d, 0x43}; +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_KEYGEN_PCT */ +#endif /* !EXPECTED_SIGNATURES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/main.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/main.c new file mode 100644 index 0000000000..57880555aa --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/main.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include +#include +#include +#include + +/* Import public mldsa-native API + * + * This requires specifying the parameter set and namespace prefix + * used for the build. + */ +#include +#include "expected_signatures.h" +#include "test_only_rng/notrandombytes.h" + +#define CHECK(x) \ + do \ + { \ + int rc; \ + rc = (x); \ + if (!rc) \ + { \ + fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \ + return 1; \ + } \ + } while (0) + +#define TEST_MSG \ + "This is a test message for ML-DSA digital signature algorithm!" +#define TEST_MSG_LEN (sizeof(TEST_MSG) - 1) + +#define TEST_CTX "test_context_123" +#define TEST_CTX_LEN (sizeof(TEST_CTX) - 1) + +int main(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t sig[CRYPTO_BYTES]; + uint8_t sm[TEST_MSG_LEN + CRYPTO_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + CRYPTO_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-%d Bring Your Own FIPS-202 Example\n", + MLD_CONFIG_PARAMETER_SET); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(crypto_sign_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(crypto_sign_signature(sig, &siglen, (const uint8_t *)test_msg, + TEST_MSG_LEN, (const uint8_t *)test_ctx, + TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(crypto_sign_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(crypto_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(crypto_sign_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", CRYPTO_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", CRYPTO_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", CRYPTO_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature)); + CHECK(memcmp(sig, expected_signature, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + printf("Custom FIPS-202 implementation is working correctly.\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/mldsa_native.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/mldsa_native.h new file mode 100644 index 0000000000..fd150a9df1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/mldsa_native.h @@ -0,0 +1,975 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_H +#define MLD_H + +/* + * Public API for mldsa-native + * + * This header defines the public API of a single build of mldsa-native. + * + * Make sure the configuration file is in the include path + * (this is "mldsa_native_config.h" by default, or MLD_CONFIG_FILE if defined). + * + * # Multi-level builds + * + * This header specifies a build of mldsa-native for a fixed security level. + * If you need multiple security levels, leave the security level unspecified + * in the configuration file and include this header multiple times, setting + * MLD_CONFIG_PARAMETER_SET accordingly for each, and #undef'ing the MLD_H + * guard to allow multiple inclusions. + * + * # Legacy configuration (deprecated) + * + * Instead of providing the config file used for the build, you can + * alternatively set the following configuration options prior to + * including this header. + * + * This method of configuration is deprecated. + * It will be removed in mldsa-native-v2. + * + * - MLD_CONFIG_API_PARAMETER_SET [required] + * + * The parameter set used for the build; 44, 65, or 87. + * + * - MLD_CONFIG_API_NAMESPACE_PREFIX [required] + * + * The namespace prefix used for the build. + * + * NOTE: + * For a multi-level build, you must include the 44/65/87 suffixes + * in MLD_CONFIG_API_NAMESPACE_PREFIX. + * + * - MLD_CONFIG_API_NO_SUPERCOP [optional] + * + * By default, this header will also expose the mldsa-native API in the + * SUPERCOP naming convention crypto_sign_xxx. If you don't want/need this, + * set MLD_CONFIG_API_NO_SUPERCOP. You must set this for a multi-level build. + * + * - MLD_CONFIG_API_CONSTANTS_ONLY [optional] + * + * If you don't want this header to expose any function declarations, + * but only constants for the sizes of key material, set + * MLD_CONFIG_API_CONSTANTS_ONLY. In this case, you don't need to set + * MLD_CONFIG_API_PARAMETER_SET or MLD_CONFIG_API_NAMESPACE_PREFIX, + * nor include a configuration. + * + * - MLD_CONFIG_API_QUALIFIER [optional] + * + * Qualifier to apply to external API. + * + ******************************************************************************/ + +/******************************* Key sizes ************************************/ + +/* Sizes of cryptographic material, per parameter set */ +/* See mldsa/src/params.h for the arithmetic expressions giving rise to these */ +/* check-magic: off */ +#define MLDSA44_SECRETKEYBYTES 2560 +#define MLDSA44_PUBLICKEYBYTES 1312 +#define MLDSA44_BYTES 2420 + +#define MLDSA65_SECRETKEYBYTES 4032 +#define MLDSA65_PUBLICKEYBYTES 1952 +#define MLDSA65_BYTES 3309 + +#define MLDSA87_SECRETKEYBYTES 4896 +#define MLDSA87_PUBLICKEYBYTES 2592 +#define MLDSA87_BYTES 4627 +/* check-magic: on */ + +/* Size of seed and randomness in bytes (level-independent) */ +#define MLDSA_SEEDBYTES 32 +#define MLDSA44_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA65_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA87_SEEDBYTES MLDSA_SEEDBYTES + +/* Size of CRH output in bytes (level-independent) */ +#define MLDSA_CRHBYTES 64 +#define MLDSA44_CRHBYTES MLDSA_CRHBYTES +#define MLDSA65_CRHBYTES MLDSA_CRHBYTES +#define MLDSA87_CRHBYTES MLDSA_CRHBYTES + +/* Size of TR output in bytes (level-independent) */ +#define MLDSA_TRBYTES 64 +#define MLDSA44_TRBYTES MLDSA_TRBYTES +#define MLDSA65_TRBYTES MLDSA_TRBYTES +#define MLDSA87_TRBYTES MLDSA_TRBYTES + +/* Size of randomness for signing in bytes (level-independent) */ +#define MLDSA_RNDBYTES 32 +#define MLDSA44_RNDBYTES MLDSA_RNDBYTES +#define MLDSA65_RNDBYTES MLDSA_RNDBYTES +#define MLDSA87_RNDBYTES MLDSA_RNDBYTES + +/* Sizes of cryptographic material, as a function of LVL=44,65,87 */ +#define MLDSA_SECRETKEYBYTES_(LVL) MLDSA##LVL##_SECRETKEYBYTES +#define MLDSA_PUBLICKEYBYTES_(LVL) MLDSA##LVL##_PUBLICKEYBYTES +#define MLDSA_BYTES_(LVL) MLDSA##LVL##_BYTES +#define MLDSA_SECRETKEYBYTES(LVL) MLDSA_SECRETKEYBYTES_(LVL) +#define MLDSA_PUBLICKEYBYTES(LVL) MLDSA_PUBLICKEYBYTES_(LVL) +#define MLDSA_BYTES(LVL) MLDSA_BYTES_(LVL) + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + +/****************************** Function API **********************************/ + +#define MLD_API_CONCAT_(x, y) x##y +#define MLD_API_CONCAT(x, y) MLD_API_CONCAT_(x, y) +#define MLD_API_CONCAT_UNDERSCORE(x, y) MLD_API_CONCAT(MLD_API_CONCAT(x, _), y) + +#if !defined(MLD_CONFIG_API_PARAMETER_SET) +/* Recommended configuration via same config file as used for the build. */ + +/* For now, we derive the legacy API configuration MLD_CONFIG_API_XXX from + * the config file. In mldsa-native-v2, this will be removed and we will + * exclusively work with MLD_CONFIG_XXX. */ + +/* You need to make sure the config file is in the include path. */ +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#define MLD_CONFIG_API_PARAMETER_SET MLD_CONFIG_PARAMETER_SET + +#if defined(MLD_CONFIG_MULTILEVEL_BUILD) +#define MLD_CONFIG_API_NAMESPACE_PREFIX \ + MLD_API_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_CONFIG_API_NAMESPACE_PREFIX MLD_CONFIG_NAMESPACE_PREFIX +#endif + +#if defined(MLD_CONFIG_NO_SUPERCOP) +#define MLD_CONFIG_API_NO_SUPERCOP +#endif + +#if defined(MLD_CONFIG_CONSTANTS_ONLY) +#define MLD_CONFIG_API_CONSTANTS_ONLY +#endif + +#if defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_CONFIG_API_QUALIFIER MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#else /* !MLD_CONFIG_API_PARAMETER_SET */ +#define MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_PARAMETER_SET */ + +#define MLD_API_NAMESPACE(sym) \ + MLD_API_CONCAT_UNDERSCORE(MLD_CONFIG_API_NAMESPACE_PREFIX, sym) + +#if defined(__GNUC__) || defined(clang) +#define MLD_API_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_API_MUST_CHECK_RETURN_VALUE +#endif + +#if defined(MLD_CONFIG_API_QUALIFIER) +#define MLD_API_QUALIFIER MLD_CONFIG_API_QUALIFIER +#else +#define MLD_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_API_CONSTANTS_ONLY) + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************************* + * Name: crypto_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: + * input random seed + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair_internal)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t seed[MLDSA_SEEDBYTES] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: If MLD_CONFIG_KEYGEN_PCT is enabled and the + * PCT check failed. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return -1 in that case. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_extmu + * + * Description: Computes signature. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_extmu)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t *sm: pointer to output signed message (allocated array + * with MLDSA{44,65,87}_BYTES + mlen bytes), can be + * equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(sign)( + uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_extmu)( + const uint8_t *sig, size_t siglen, const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_open + * + * Description: Verify signed message. + * + * Arguments: + * - uint8_t *m: pointer to output message (allocated array with + * smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(open)( + uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: crypto_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *ph, size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_shake256)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_shake256)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/* Maximum formatted domain separation message length */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +size_t MLD_API_NAMESPACE(prepare_domain_separation_prefix)( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg); + +/************************************************* + * Name: crypto_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[CRYPTO_SECRETKEYBYTES]: input secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(pk_from_sk)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +#ifdef __cplusplus +} +#endif + +/****************************** SUPERCOP API *********************************/ + +#if !defined(MLD_CONFIG_API_NO_SUPERCOP) +/* Export API in SUPERCOP naming scheme CRYPTO_xxx / crypto_sign_xxx */ +#define CRYPTO_SECRETKEYBYTES MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_PUBLICKEYBYTES MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_BYTES MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET) + +#define crypto_sign_keypair MLD_API_NAMESPACE(keypair) +#define crypto_sign_signature MLD_API_NAMESPACE(signature) +#define crypto_sign MLD_API_NAMESPACE(sign) +#define crypto_sign_verify MLD_API_NAMESPACE(verify) +#define crypto_sign_open MLD_API_NAMESPACE(open) + +#else /* !MLD_CONFIG_API_NO_SUPERCOP */ + +/* If the SUPERCOP API is not needed, we can undefine the various helper macros + * above. Otherwise, they are needed for lazy evaluation of crypto_sign_xxx. */ +#if !defined(MLD_API_LEGACY_CONFIG) +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_QUALIFIER +#endif /* !MLD_API_LEGACY_CONFIG */ + +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_NAMESPACE +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_QUALIFIER +#undef MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_NO_SUPERCOP */ +#endif /* !MLD_CONFIG_API_CONSTANTS_ONLY */ + + +/***************************** Memory Usage **********************************/ + +/* + * By default mldsa-native performs all memory allocations on the stack. + * Alternatively, mldsa-native supports custom allocation of large structures + * through the `MLD_CONFIG_CUSTOM_ALLOC_FREE` configuration option. + * See mldsa_native_config.h for details. + * + * `MLD_TOTAL_ALLOC_{44,65,87}_{KEYPAIR,SIGN,VERIFY}` indicates the maximum + * (accumulative) allocation via MLD_ALLOC for each parameter set and operation. + * Note that some stack allocation remains even + * when using custom allocators, so these values are lower than total stack + * usage with the default stack-only allocation. + * + * These constants may be used to implement custom allocations using a + * fixed-sized buffer and a simple allocator (e.g., bump allocator). + */ +/* check-magic: off */ +#if defined(MLD_API_LEGACY_CONFIG) || !defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 45248 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 56640 +#define MLD_TOTAL_ALLOC_44_SIGN 52896 +#define MLD_TOTAL_ALLOC_44_VERIFY 38816 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 71872 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 85856 +#define MLD_TOTAL_ALLOC_65_SIGN 80576 +#define MLD_TOTAL_ALLOC_65_VERIFY 62432 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 112832 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 130816 +#define MLD_TOTAL_ALLOC_87_SIGN 123584 +#define MLD_TOTAL_ALLOC_87_VERIFY 99552 +#else /* MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM */ +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 32992 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 36192 +#define MLD_TOTAL_ALLOC_44_SIGN 32448 +#define MLD_TOTAL_ALLOC_44_VERIFY 22464 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 46304 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 50048 +#define MLD_TOTAL_ALLOC_65_SIGN 44768 +#define MLD_TOTAL_ALLOC_65_VERIFY 30720 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 62688 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 66336 +#define MLD_TOTAL_ALLOC_87_SIGN 59104 +#define MLD_TOTAL_ALLOC_87_VERIFY 41216 +#endif /* !(MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM) */ +/* check-magic: on */ + +/* + * MLD_TOTAL_ALLOC_*_KEYPAIR adapts based on MLD_CONFIG_KEYGEN_PCT. + * For legacy config, we don't know which options are used, so assume + * the worst case (PCT enabled). + */ +#if defined(MLD_API_LEGACY_CONFIG) || defined(MLD_CONFIG_KEYGEN_PCT) +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#else +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#endif + +#define MLD_MAX3_(a, b, c) \ + ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c))) + +/* + * `MLD_TOTAL_ALLOC_{44,65,87}` is the maximum across all operations for each + * parameter set. + */ +#define MLD_TOTAL_ALLOC_44 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_44_KEYPAIR, MLD_TOTAL_ALLOC_44_SIGN, \ + MLD_TOTAL_ALLOC_44_VERIFY) +#define MLD_TOTAL_ALLOC_65 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_65_KEYPAIR, MLD_TOTAL_ALLOC_65_SIGN, \ + MLD_TOTAL_ALLOC_65_VERIFY) +#define MLD_TOTAL_ALLOC_87 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_87_KEYPAIR, MLD_TOTAL_ALLOC_87_SIGN, \ + MLD_TOTAL_ALLOC_87_VERIFY) + +#endif /* !MLD_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/mldsa_native_config.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/mldsa_native_config.h new file mode 100644 index 0000000000..ab4bed70dc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/mldsa_native_config.h @@ -0,0 +1,739 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/* + * Test configuration: Configuration for custom FIPS202 implementation + * + * This configuration differs from the default mldsa/mldsa_native_config.h in + * the following places: + * - MLD_CONFIG_NAMESPACE_PREFIX + * - MLD_CONFIG_FIPS202_CUSTOM_HEADER + * - MLD_CONFIG_FIPS202X4_CUSTOM_HEADER + */ + + +#ifndef MLD_CONFIG_H +#define MLD_CONFIG_H + +/****************************************************************************** + * Name: MLD_CONFIG_PARAMETER_SET + * + * Description: Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * If you want to support multiple parameter sets, build the + * library multiple times and set MLD_CONFIG_MULTILEVEL_BUILD. + * See MLD_CONFIG_MULTILEVEL_BUILD for how to do this while + * minimizing code duplication. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of the default configuration file mldsa/mldsa_native_config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * then configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + * + *****************************************************************************/ +/* No need to set this -- we _are_ already in a custom config */ +/* #define MLD_CONFIG_FILE "mldsa_native_config.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_NAMESPACE_PREFIX + * + * Description: The prefix to use to namespace global symbols from mldsa/. + * + * In a multi-level build, level-dependent symbols will + * additionally be prefixed with the parameter set (44/65/87). + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_NAMESPACE_PREFIX mldsa + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_BUILD + * + * Description: Set this if the build is part of a multi-level build supporting + * multiple parameter sets. + * + * If you need only a single parameter set, keep this unset. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them. + * + * See examples/multilevel_build for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_BUILD */ + +/****************************************************************************** + * Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_EXTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_RANDOMIZED_API + * + * Description: If this option is set, mldsa-native will be built without the + * randomized API functions (crypto_sign_keypair, + * crypto_sign, crypto_sign_signature, and + * crypto_sign_signature_extmu). + * This allows users to build mldsa-native without providing a + * randombytes() implementation if they only need the + * internal deterministic API + * (crypto_sign_keypair_internal, crypto_sign_signature_internal). + * + * NOTE: This option is incompatible with MLD_CONFIG_KEYGEN_PCT + * as the current PCT implementation requires + * crypto_sign_signature(). + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_RANDOMIZED_API */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_SUPERCOP + * + * Description: By default, mldsa_native.h exposes the mldsa-native API in the + * SUPERCOP naming convention (crypto_sign_xxx). If you don't need + * this, set MLD_CONFIG_NO_SUPERCOP. + * + * NOTE: You must set this for a multi-level build as the SUPERCOP + * naming does not disambiguate between the parameter sets. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_SUPERCOP */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONSTANTS_ONLY + * + * Description: If you only need the size constants (MLDSA_PUBLICKEYBYTES, etc.) + * but no function declarations, set MLD_CONFIG_CONSTANTS_ONLY. + * + * This only affects the public header mldsa_native.h, not + * the implementation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONSTANTS_ONLY */ + +/****************************************************************************** + * + * Build-only configuration options + * + * The remaining configurations are build-options only. + * They do not affect the API described in mldsa_native.h. + * + *****************************************************************************/ + +#if defined(MLD_BUILD_INTERNAL) +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_WITH_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, all MLD_CONFIG_PARAMETER_SET-independent + * code will be included in the build, including code needed only + * for other parameter sets. + * + * Example: TODO: add example + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_WITH_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_NO_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, no MLD_CONFIG_PARAMETER_SET-independent code + * will be included in the build. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * + * Description: This is only relevant for single compilation unit (SCU) + * builds of mldsa-native. In this case, it determines whether + * directives defined in parameter-set-independent headers should + * be #undef'ined or not at the of the SCU file. This is needed + * in multilevel builds. + * + * See examples/multilevel_build_native for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * + * Description: Determines whether an native arithmetic backend should be used. + * + * The arithmetic backend covers performance critical functions + * such as the number-theoretic transform (NTT). + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the arithmetic backend to be use is + * determined by MLD_CONFIG_ARITH_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_ARITH_BACKEND_FILE + * + * Description: The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * + * Description: Determines whether an native FIPS202 backend should be used. + * + * The FIPS202 backend covers 1x/2x/4x-fold Keccak-f1600, which is + * the performance bottleneck of SHA3 and SHAKE. + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the FIPS202 backend to be use is + * determined by MLD_CONFIG_FIPS202_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_BACKEND_FILE + * + * Description: The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +#define MLD_CONFIG_FIPS202_CUSTOM_HEADER "../custom_fips202/fips202.h" + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202X4_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202-X4 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202x4.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +#define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER "../custom_fips202/fips202x4.h" + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ZEROIZE + * + * Description: In compliance with @[FIPS204, Section 3.6.3], mldsa-native, + * zeroizes intermediate stack buffers before returning from + * function calls. + * + * Set this option and define `mld_zeroize` if you want to + * use a custom method to zeroize intermediate stack buffers. + * The default implementation uses SecureZeroMemory on Windows + * and a memset + compiler barrier otherwise. If neither of those + * is available on the target platform, compilation will fail, + * and you will need to use MLD_CONFIG_CUSTOM_ZEROIZE to provide + * a custom implementation of `mld_zeroize()`. + * + * WARNING: + * The explicit stack zeroization conducted by mldsa-native + * reduces the likelihood of data leaking on the stack, but + * does not eliminate it! The C standard makes no guarantee about + * where a compiler allocates structures and whether/where it makes + * copies of them. Also, in addition to entire structures, there + * may also be potentially exploitable leakage of individual values + * on the stack. + * + * If you need bullet-proof zeroization of the stack, you need to + * consider additional measures instead of what this feature + * provides. In this case, you can set mld_zeroize to a + * no-op. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void mld_zeroize(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * Description: mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to provided by the + * consumer. + * + * If this option is not set, mldsa-native expects a function + * int randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mld_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_RANDOMBYTES + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) + { + ... your implementation ... + return 0; + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + * + * Description: mldsa-native backends may rely on specific hardware features. + * Those backends will only be included in an mldsa-native build + * if support for the respective features is enabled at + * compile-time. However, when building for a heteroneous set + * of CPUs to run the resulting binary/library on, feature + * detection at _runtime_ is needed to decided whether a backend + * can be used or not. + * + * Set this option and define `mld_sys_check_capability` if you + * want to use a custom method to dispatch between implementations. + * + * Return value 1 indicates that a capability is supported. + * Return value 0 indicates that a capability is not supported. + * + * If this option is not set, mldsa-native uses compile-time + * feature detection only to decide which backend to use. + * + * If you compile mldsa-native on a system with different + * capabilities than the system that the resulting binary/library + * will be run on, you must use this option. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) + { + ... your implementation ... + } +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ALLOC_FREE [EXPERIMENTAL] + * + * Description: Set this option and define `MLD_CUSTOM_ALLOC` and + * `MLD_CUSTOM_FREE` if you want to use custom allocation for + * large local structures or buffers. + * + * By default, all buffers/structures are allocated on the stack. + * If this option is set, most of them will be allocated via + * MLD_CUSTOM_ALLOC. + * + * Parameters to MLD_CUSTOM_ALLOC: + * - T* v: Target pointer to declare. + * - T: Type of structure to be allocated + * - N: Number of elements to be allocated. + * + * Parameters to MLD_CUSTOM_FREE: + * - T* v: Target pointer to free. May be NULL. + * - T: Type of structure to be freed. + * - N: Number of elements to be freed. + * + * WARNING: This option is experimental! + * Its scope, configuration and function/macro signatures may + * change at any time. We expect a stable API for v2. + * + * NOTE: Even if this option is set, some allocations further down + * the call stack will still be made from the stack. Those will + * likely be added to the scope of this option in the future. + * + * NOTE: MLD_CUSTOM_ALLOC need not guarantee a successful + * allocation nor include error handling. Upon failure, the + * target pointer should simply be set to NULL. The calling + * code will handle this case and invoke MLD_CUSTOM_FREE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ALLOC_FREE + #if !defined(__ASSEMBLER__) + #include + #define MLD_CUSTOM_ALLOC(v, T, N) \ + T* (v) = (T *)aligned_alloc(MLD_DEFAULT_ALIGN, \ + MLD_ALIGN_UP(sizeof(T) * (N))) + #define MLD_CUSTOM_FREE(v, T, N) free(v) + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMCPY + * + * Description: Set this option and define `mld_memcpy` if you want to + * use a custom method to copy memory instead of the standard + * library memcpy function. + * + * The custom implementation must have the same signature and + * behavior as the standard memcpy function: + * void *mld_memcpy(void *dest, const void *src, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMCPY + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMSET + * + * Description: Set this option and define `mld_memset` if you want to + * use a custom method to set memory instead of the standard + * library memset function. + * + * The custom implementation must have the same signature and + * behavior as the standard memset function: + * void *mld_memset(void *s, int c, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMSET + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memset(void *s, int c, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_INTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of internal API. + * + * The primary use case for this option are single-CU builds, + * in which case this option can be set to `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_INTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CT_TESTING_ENABLED + * + * Description: If set, mldsa-native annotates data as secret / public using + * valgrind's annotations VALGRIND_MAKE_MEM_UNDEFINED and + * VALGRIND_MAKE_MEM_DEFINED, enabling various checks for secret- + * dependent control flow of variable time execution (depending + * on the exact version of valgrind installed). + * + *****************************************************************************/ +/* #define MLD_CONFIG_CT_TESTING_ENABLED */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * and MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT + * + * Description: Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, crypto_sign_keypair_internal and + * crypto_sign_keypair will return a non-zero error code if the + * PCT failed. + * + * NOTE: This feature will drastically lower the performance of + * key generation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * Description: If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "src/src.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Description: Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * NOTE: Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + * + *****************************************************************************/ +/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER + * + * Description: Set this to add a context parameter that is provided to public + * API functions and is then available in custom callbacks. + * + * The type of the context parameter is configured via + * MLD_CONFIG_CONTEXT_PARAMETER_TYPE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER_TYPE + * + * Description: Set this to define the type for the context parameter used by + * MLD_CONFIG_CONTEXT_PARAMETER. + * + * This is only relevant if MLD_CONFIG_CONTEXT_PARAMETER is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER_TYPE void* */ + +/****************************************************************************** + * Name: MLD_CONFIG_REDUCE_RAM [EXPERIMENTAL] + * + * Description: Set this to reduce RAM usage. + * This trades memory for performance. + * + * For expected memory usage, see the MLD_TOTAL_ALLOC_* constants + * defined in mldsa_native.h. + * + * This option is useful for embedded systems with tight RAM + * constraints but relaxed performance requirements. + * + * WARNING: This option is experimental! + * CBMC proofs do not currently cover this configuration option. + * Its scope and configuration may change at any time. + * + *****************************************************************************/ +/* #define MLD_CONFIG_REDUCE_RAM */ + +/************************* Config internals ********************************/ + +#endif /* MLD_BUILD_INTERNAL */ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace is + * + * PQCP_MLDSA_NATIVE_MLDSA_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_ + */ + +#if MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65 +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87 +#endif + +#endif /* !MLD_CONFIG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/cbmc.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/cbmc.h new file mode 100644 index 0000000000..8ed1ecb06b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/cbmc.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_CBMC_H +#define MLD_CBMC_H +/*************************************************** + * Basic replacements for __CPROVER_XXX contracts + ***************************************************/ +#ifndef CBMC + +#define __contract__(x) +#define __loop__(x) +#define cassert(x) + +#else /* !CBMC */ + +#include + +#define __contract__(x) x +#define __loop__(x) x + +/* https://diffblue.github.io/cbmc/contracts-assigns.html */ +#define assigns(...) __CPROVER_assigns(__VA_ARGS__) + +/* https://diffblue.github.io/cbmc/contracts-requires-ensures.html */ +#define requires(...) __CPROVER_requires(__VA_ARGS__) +#define ensures(...) __CPROVER_ensures(__VA_ARGS__) +/* https://diffblue.github.io/cbmc/contracts-loops.html */ +#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__) +#define decreases(...) __CPROVER_decreases(__VA_ARGS__) +/* cassert to avoid confusion with in-built assert */ +#define cassert(x) __CPROVER_assert(x, "cbmc assertion failed") +#define assume(...) __CPROVER_assume(__VA_ARGS__) + +/*************************************************** + * Macros for "expression" forms that may appear + * _inside_ top-level contracts. + ***************************************************/ + +/* + * function return value - useful inside ensures + * https://diffblue.github.io/cbmc/contracts-functions.html + */ +#define return_value (__CPROVER_return_value) + +/* + * assigns l-value targets + * https://diffblue.github.io/cbmc/contracts-assigns.html + */ +#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__) +#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__) +#define same_object(...) __CPROVER_same_object(__VA_ARGS__) + +/* + * Pointer-related predicates + * https://diffblue.github.io/cbmc/contracts-memory-predicates.html + */ +#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__) +#define readable(...) __CPROVER_r_ok(__VA_ARGS__) +#define writeable(...) __CPROVER_w_ok(__VA_ARGS__) + +/* Maximum supported buffer size + * + * Larger buffers may be supported, but due to internal modeling constraints + * in CBMC, the proofs of memory- and type-safety won't be able to run. + * + * If you find yourself in need for a buffer size larger than this, + * please contact the maintainers, so we can prioritize work to relax + * this somewhat artificial bound. + */ +#define MLD_MAX_BUFFER_SIZE (SIZE_MAX >> 12) + + +/* + * History variables + * https://diffblue.github.io/cbmc/contracts-history-variables.html + */ +#define old(...) __CPROVER_old(__VA_ARGS__) +#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__) + +/* + * Quantifiers + * Note that the range on qvar is _exclusive_ between qvar_lb .. qvar_ub + * https://diffblue.github.io/cbmc/contracts-quantifiers.html + */ + +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define forall(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> (predicate) \ + } + +#define exists(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_exists \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) && (predicate) \ + } +/* clang-format on */ + +/*************************************************** + * Convenience macros for common contract patterns + ***************************************************/ +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define CBMC_CONCAT_(left, right) left##right +#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right) + +#define array_bound_core(qvar, qvar_lb, qvar_ub, array_var, \ + value_lb, value_ub) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + (((int)(value_lb) <= ((array_var)[(qvar)])) && \ + (((array_var)[(qvar)]) < (int)(value_ub))) \ + } + +#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \ + array_bound_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (qvar_lb), \ + (qvar_ub), (array_var), (value_lb), (value_ub)) + +#define array_unchanged_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (int32_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged(array_var, N) \ + array_unchanged_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) + +#define array_unchanged_u64_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (uint64_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged_u64(array_var, N) \ + array_unchanged_u64_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) +/* clang-format on */ + +/* Wrapper around array_bound operating on absolute values. + * + * The absolute value bound `k` is exclusive. + * + * Note that since the lower bound in array_bound is inclusive, we have to + * raise it by 1 here. + */ +#define array_abs_bound(arr, lb, ub, k) \ + array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k)) + +#endif /* CBMC */ + +#endif /* !MLD_CBMC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/common.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/common.h new file mode 100644 index 0000000000..4a5bc8109d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/common.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_COMMON_H +#define MLD_COMMON_H + +#define MLD_BUILD_INTERNAL + +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#include "params.h" +#include "sys.h" + +/* Internal and public API have external linkage by default, but + * this can be overwritten by the user, e.g. for single-CU builds. */ +#if !defined(MLD_CONFIG_INTERNAL_API_QUALIFIER) +#define MLD_INTERNAL_API +#else +#define MLD_INTERNAL_API MLD_CONFIG_INTERNAL_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_EXTERNAL_API +#else +#define MLD_EXTERNAL_API MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#if defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) || \ + defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) +#define MLD_MULTILEVEL_BUILD +#endif + +#define MLD_CONCAT_(x1, x2) x1##x2 +#define MLD_CONCAT(x1, x2) MLD_CONCAT_(x1, x2) + +#if defined(MLD_MULTILEVEL_BUILD) +#define MLD_ADD_PARAM_SET(s) MLD_CONCAT(s, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_ADD_PARAM_SET(s) s +#endif + +#define MLD_NAMESPACE_PREFIX MLD_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, _) +#define MLD_NAMESPACE_PREFIX_KL \ + MLD_CONCAT(MLD_ADD_PARAM_SET(MLD_CONFIG_NAMESPACE_PREFIX), _) + +/* Functions are prefixed by MLD_CONFIG_NAMESPACE_PREFIX. + * + * If multiple parameter sets are used, functions depending on the parameter + * set are additionally prefixed with 44/65/87. See mldsa_native_config.h. + * + * Example: If MLD_CONFIG_NAMESPACE_PREFIX is PQCP_MLDSA_NATIVE, then + * MLD_NAMESPACE_KL(keypair) becomes PQCP_MLDSA_NATIVE44_keypair/ + * PQCP_MLDSA_NATIVE65_keypair/PQCP_MLDSA_NATIVE87_keypair. + */ +#define MLD_NAMESPACE(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX, s) +#define MLD_NAMESPACE_KL(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX_KL, s) + +/* On Apple platforms, we need to emit leading underscore + * in front of assembly symbols. We thus introducee a separate + * namespace wrapper for ASM symbols. */ +#if !defined(__APPLE__) +#define MLD_ASM_NAMESPACE(sym) MLD_NAMESPACE(sym) +#else +#define MLD_ASM_NAMESPACE(sym) MLD_CONCAT(_, MLD_NAMESPACE(sym)) +#endif + +/* + * On X86_64 if control-flow protections (CET) are enabled (through + * -fcf-protection=), we add an endbr64 instruction at every global function + * label. See sys.h for more details + */ +#if defined(MLD_SYS_X86_64) +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : MLD_CET_ENDBR +#else +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : +#endif + +/* We aim to simplify the user's life by supporting builds where + * all source files are included, even those that are not needed. + * Those files are appropriately guarded and will be empty when unneeded. + * The following is to avoid compilers complaining about this. */ +#define MLD_EMPTY_CU(s) extern int MLD_NAMESPACE_KL(empty_cu_##s); + +/* MLD_CONFIG_NO_ASM takes precedence over MLD_USE_NATIVE_XXX */ +#if defined(MLD_CONFIG_NO_ASM) +#undef MLD_CONFIG_USE_NATIVE_BACKEND_ARITH +#undef MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, but MLD_CONFIG_ARITH_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, but MLD_CONFIG_FIPS202_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_NO_RANDOMIZED_API) && defined(MLD_CONFIG_KEYGEN_PCT) +#error Bad configuration: MLD_CONFIG_NO_RANDOMIZED_API is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires crypto_sign_signature() +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#include MLD_CONFIG_ARITH_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#include MLD_CONFIG_FIPS202_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "fips202/native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#define MLD_FIPS202_HEADER_FILE "fips202/fips202.h" +#else +#define MLD_FIPS202_HEADER_FILE MLD_CONFIG_FIPS202_CUSTOM_HEADER +#endif + +#if !defined(MLD_CONFIG_FIPS202X4_CUSTOM_HEADER) +#define MLD_FIPS202X4_HEADER_FILE "fips202/fips202x4.h" +#else +#define MLD_FIPS202X4_HEADER_FILE MLD_CONFIG_FIPS202X4_CUSTOM_HEADER +#endif + +/* Standard library function replacements */ +#if !defined(__ASSEMBLER__) +#if !defined(MLD_CONFIG_CUSTOM_MEMCPY) +#include +#define mld_memcpy memcpy +#endif + +#if !defined(MLD_CONFIG_CUSTOM_MEMSET) +#include +#define mld_memset memset +#endif + +/* Allocation macros for large local structures + * + * MLD_ALLOC(v, T, N) declares T *v and attempts to point it to an T[N] + * MLD_FREE(v, T, N) zeroizes and frees the allocation + * + * Default implementation uses stack allocation. + * Can be overridden by setting the config option MLD_CONFIG_CUSTOM_ALLOC_FREE + * and defining MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE. + */ +#if defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) != \ + (defined(MLD_CUSTOM_ALLOC) && defined(MLD_CUSTOM_FREE)) +#error Bad configuration: MLD_CONFIG_CUSTOM_ALLOC_FREE must be set together with MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE +#endif + +/* + * If the integration wants to provide a context parameter for use in + * platform-specific hooks, then it should define this parameter. + * + * The MLD_CONTEXT_PARAMETERS_n macros are intended to be used with macros + * defining the function names and expand to either pass or discard the context + * argument as required by the current build. If there is no context parameter + * requested then these are removed from the prototypes and from all calls. + */ +#ifdef MLD_CONFIG_CONTEXT_PARAMETER +#define MLD_CONTEXT_PARAMETERS_0(context) (context) +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0, context) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1, context) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) \ + (arg0, arg1, arg2, context) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3, context) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4, context) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, context) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, context) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, context) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, context) +#else /* MLD_CONFIG_CONTEXT_PARAMETER */ +#define MLD_CONTEXT_PARAMETERS_0(context) () +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) (arg0, arg1, arg2) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) +#endif /* !MLD_CONFIG_CONTEXT_PARAMETER */ + +#if defined(MLD_CONFIG_CONTEXT_PARAMETER_TYPE) != \ + defined(MLD_CONFIG_CONTEXT_PARAMETER) +#error MLD_CONFIG_CONTEXT_PARAMETER_TYPE must be defined if and only if MLD_CONFIG_CONTEXT_PARAMETER is defined +#endif + +#if !defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) +/* Default: stack allocation */ + +#define MLD_ALLOC(v, T, N, context) \ + MLD_ALIGN T mld_alloc_##v[N]; \ + T *v = mld_alloc_##v + +/* TODO: This leads to a circular dependency between common and ct.h + * It just works out before we're at the end of the file, but it's still + * prone to issues in the future. */ +#include "ct.h" +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + mld_zeroize(mld_alloc_##v, sizeof(mld_alloc_##v)); \ + (v) = NULL; \ + } while (0) + +#else /* !MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* Custom allocation */ + +/* + * The indirection here is necessary to use MLD_CONTEXT_PARAMETERS_3 here. + */ +#define MLD_APPLY(f, args) f args + +#define MLD_ALLOC(v, T, N, context) \ + MLD_APPLY(MLD_CUSTOM_ALLOC, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)) + +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + if (v != NULL) \ + { \ + mld_zeroize(v, sizeof(T) * (N)); \ + MLD_APPLY(MLD_CUSTOM_FREE, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)); \ + v = NULL; \ + } \ + } while (0) + +#endif /* MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* + * We are facing severe CBMC performance issues when using unions. + * As a temporary workaround, we use unions only when MLD_CONFIG_REDUCE_RAM is + * set. + * TODO: Remove the workaround once + * https://github.com/diffblue/cbmc/issues/8813 + * is resolved + */ +#if defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_UNION_OR_STRUCT union +#else +#define MLD_UNION_OR_STRUCT struct +#endif + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_COMMON_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/ct.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/ct.c new file mode 100644 index 0000000000..010b1a52a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/ct.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include "ct.h" + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +/* + * Masking value used in constant-time functions from + * ct.h to block the compiler's range analysis and + * thereby reduce the risk of compiler-introduced branches. + */ +volatile uint64_t mld_ct_opt_blocker_u64 = 0; + +#else /* !MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(ct) + +#endif /* !(!MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/ct.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/ct.h new file mode 100644 index 0000000000..c307456468 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/ct.h @@ -0,0 +1,366 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [libmceliece] + * libmceliece implementation of Classic McEliece + * Bernstein, Chou + * https://lib.mceliece.org/ + * + * - [optblocker] + * PQC forum post on opt-blockers using volatile globals + * Daniel J. Bernstein + * https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ + */ + +#ifndef MLD_CT_H +#define MLD_CT_H + +#include +#include "cbmc.h" +#include "common.h" + +/* Constant-time comparisons and conditional operations + + We reduce the risk for compilation into variable-time code + through the use of 'value barriers'. + + Functionally, a value barrier is a no-op. To the compiler, however, + it constitutes an arbitrary modification of its input, and therefore + harden's value propagation and range analysis. + + We consider two approaches to implement a value barrier: + - An empty inline asm block which marks the target value as clobbered. + - XOR'ing with the value of a volatile global that's set to 0; + see @[optblocker] for a discussion of this idea, and + @[libmceliece, inttypes/crypto_intN.h] for an implementation. + + The first approach is cheap because it only prevents the compiler + from reasoning about the value of the variable past the barrier, + but does not directly generate additional instructions. + + The second approach generates redundant loads and XOR operations + and therefore comes at a higher runtime cost. However, it appears + more robust towards optimization, as compilers should never drop + a volatile load. + + We use the empty-ASM value barrier for GCC and clang, and fall + back to the global volatile barrier otherwise. + + The global value barrier can be forced by setting + MLD_CONFIG_NO_ASM_VALUE_BARRIER. + +*/ + +#if defined(MLD_HAVE_INLINE_ASM) && !defined(MLD_CONFIG_NO_ASM_VALUE_BARRIER) +#define MLD_USE_ASM_VALUE_BARRIER +#endif + + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) +/* + * Declaration of global volatile that the global value barrier + * is loading from and masking with. + */ +#define mld_ct_opt_blocker_u64 MLD_NAMESPACE(ct_opt_blocker_u64) +extern volatile uint64_t mld_ct_opt_blocker_u64; + + +/* Helper functions for obtaining global masks of various sizes */ + +/* This contract is not proved but treated as an axiom. + * + * Its validity relies on the assumption that the global opt-blocker + * constant mld_ct_opt_blocker_u64 is not modified. + */ +static MLD_INLINE uint64_t mld_ct_get_optblocker_u64(void) +__contract__(ensures(return_value == 0)) { return mld_ct_opt_blocker_u64; } + +static MLD_INLINE int64_t mld_ct_get_optblocker_i64(void) +__contract__(ensures(return_value == 0)) { return (int64_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint32_t mld_ct_get_optblocker_u32(void) +__contract__(ensures(return_value == 0)) { return (uint32_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint8_t mld_ct_get_optblocker_u8(void) +__contract__(ensures(return_value == 0)) { return (uint8_t)mld_ct_get_optblocker_u64(); } + +/* Opt-blocker based implementation of value barriers */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_i64()); } + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u32()); } + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u8()); } + + +#else /* !MLD_USE_ASM_VALUE_BARRIER */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} +#endif /* MLD_USE_ASM_VALUE_BARRIER */ + +#ifdef CBMC +#pragma CPROVER check push +#pragma CPROVER check disable "conversion" +#endif + +/************************************************* + * Name: mld_cast_uint32_to_int32 + * + * Description: Cast uint32 value to int32 + * + * Returns: For uint32_t x, the unique y in int32_t + * so that x == y mod 2^32. + * + * Concretely: + * - x < 2^31: returns x + * - x >= 2^31: returns x - 2^31 + * + **************************************************/ +static MLD_ALWAYS_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x) +{ + /* + * PORTABILITY: This relies on uint32_t -> int32_t + * being implemented as the inverse of int32_t -> uint32_t, + * which is implementation-defined (C99 6.3.1.3 (3)) + * CBMC (correctly) fails to prove this conversion is OK, + * so we have to suppress that check here + */ + return (int32_t)x; +} + +#ifdef CBMC +#pragma CPROVER check pop +#endif + + +/************************************************* + * Name: mld_cast_int64_to_uint32 + * + * Description: Cast int64 value to uint32 as per C standard. + * + * Returns: For int64_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int64_to_uint32(int64_t x) +{ + return (uint32_t)(x & (int64_t)UINT32_MAX); +} + +/************************************************* + * Name: mld_cast_int32_to_uint32 + * + * Description: Cast int32 value to uint32 as per C standard. + * + * Returns: For int32_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int32_to_uint32(int32_t x) +{ + return mld_cast_int64_to_uint32((int64_t)x); +} + +/************************************************* + * Name: mld_ct_sel_int32 + * + * Description: Functionally equivalent to cond ? a : b, + * but implemented with guards against + * compiler-introduced branches. + * + * Arguments: int32_t a: First alternative + * int32_t b: Second alternative + * uint32_t cond: Condition variable. + * + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_sel_int32(int32_t a, int32_t b, uint32_t cond) +__contract__( + requires(cond == 0x0 || cond == 0xFFFFFFFF) + ensures(return_value == (cond ? a : b)) +) +{ + uint32_t au = mld_cast_int32_to_uint32(a); + uint32_t bu = mld_cast_int32_to_uint32(b); + uint32_t res = bu ^ (mld_value_barrier_u32(cond) & (au ^ bu)); + return mld_cast_uint32_to_int32(res); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u32 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_nonzero_u32(uint32_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFFFFFFFF))) +{ + int64_t tmp = mld_value_barrier_i64(-((int64_t)x)); + tmp >>= 32; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u8 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint8_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint8_t mld_ct_cmask_nonzero_u8(uint8_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFF))) +{ + uint32_t mask = mld_ct_cmask_nonzero_u32((uint32_t)x); + return (uint8_t)(mask & 0xFF); +} + +/************************************************* + * Name: mld_ct_cmask_neg_i32 + * + * Description: Return 0 if input is non-negative, and -1 otherwise. + * + * Arguments: int32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_neg_i32(int32_t x) +__contract__( + ensures(return_value == ((x < 0) ? 0xFFFFFFFF : 0)) +) +{ + int64_t tmp = mld_value_barrier_i64((int64_t)x); + tmp >>= 31; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_abs_i32 + * + * Description: Return -x if x<0, x otherwise + * + * Arguments: int32_t x: Input value + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_abs_i32(int32_t x) +__contract__( + requires(x >= -INT32_MAX) + ensures(return_value == ((x < 0) ? -x : x)) +) +{ + return mld_ct_sel_int32(-x, x, mld_ct_cmask_neg_i32(x)); +} + +/************************************************* + * Name: mld_ct_memcmp + * + * Description: Compare two arrays for equality in constant time. + * + * Arguments: const uint8_t *a: pointer to first byte array + * const uint8_t *b: pointer to second byte array + * size_t len: length of the byte arrays, upper-bounded + * to UINT16_MAX to control proof complexity + * only. + * + * Returns 0 if the byte arrays are equal, 0xFF otherwise. + **************************************************/ +static MLD_INLINE uint8_t mld_ct_memcmp(const uint8_t *a, const uint8_t *b, + const size_t len) +__contract__( + requires(len <= UINT16_MAX) + requires(memory_no_alias(a, len)) + requires(memory_no_alias(b, len)) + ensures((return_value == 0) || (return_value == 0xFF)) + ensures((return_value == 0) == forall(i, 0, len, (a[i] == b[i])))) +{ + uint8_t r = 0, s = 0; + unsigned i; + + for (i = 0; i < len; i++) + __loop__( + invariant(i <= len) + invariant((r == 0) == (forall(k, 0, i, (a[k] == b[k]))))) + { + r |= a[i] ^ b[i]; + /* s is useless, but prevents the loop from being aborted once r=0xff. */ + s ^= a[i] ^ b[i]; + } + + /* + * - Convert r into a mask; this may not be necessary, but is an additional + * safeguard + * towards leaking information about a and b. + * - XOR twice with s, separated by a value barrier, to prevent the compile + * from dropping the s computation in the loop. + */ + return (mld_value_barrier_u8(mld_ct_cmask_nonzero_u8(r) ^ s) ^ s); +} + +/************************************************* + * Name: mld_zeroize + * + * Description: Force-zeroize a buffer. + * @[FIPS204, Section 3.6.3] Destruction of intermediate + * values. + * + * Arguments: void *ptr: pointer to buffer to be zeroed + * size_t len: Amount of bytes to be zeroed + **************************************************/ +#if !defined(MLD_CONFIG_CUSTOM_ZEROIZE) +#if defined(MLD_SYS_WINDOWS) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) { SecureZeroMemory(ptr, len); } +#elif defined(MLD_HAVE_INLINE_ASM) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) +{ + memset(ptr, 0, len); + /* This follows OpenSSL and seems sufficient to prevent the compiler + * from optimizing away the memset. + * + * If there was a reliable way to detect availability of memset_s(), + * that would be preferred. */ + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +} +#else /* !MLD_SYS_WINDOWS && MLD_HAVE_INLINE_ASM */ +#error No plausibly-secure implementation of mld_zeroize available. Please provide your own using MLD_CONFIG_CUSTOM_ZEROIZE. +#endif /* !MLD_SYS_WINDOWS && !MLD_HAVE_INLINE_ASM */ +#endif /* !MLD_CONFIG_CUSTOM_ZEROIZE */ + +#endif /* !MLD_CT_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/debug.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/debug.c new file mode 100644 index 0000000000..a55d51e8b1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/debug.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* NOTE: You can remove this file unless you compile with MLDSA_DEBUG. */ + +#include "common.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#if defined(MLDSA_DEBUG) + +#include +#include +#include +#include "debug.h" + +#define MLD_DEBUG_ERROR_HEADER "[ERROR:%s:%04d] " + +void mld_debug_check_assert(const char *file, int line, const int val) +{ + if (val == 0) + { + fprintf(stderr, MLD_DEBUG_ERROR_HEADER "Assertion failed (value %d)\n", + file, line, val); + exit(1); + } +} + +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive) +{ + int err = 0; + unsigned i; + for (i = 0; i < len; i++) + { + int32_t val = ptr[i]; + if (!(val > lower_bound_exclusive && val < upper_bound_exclusive)) + { + fprintf(stderr, + MLD_DEBUG_ERROR_HEADER + "Bounds assertion failed: Index %u, value %d out of bounds " + "(%" PRId64 ",%" PRId64 ")\n", + file, line, i, (int)val, lower_bound_exclusive, + upper_bound_exclusive); + err = 1; + } + } + + if (err == 1) + { + exit(1); + } +} + +#else /* MLDSA_DEBUG */ + +MLD_EMPTY_CU(debug) + +#endif /* !MLDSA_DEBUG */ + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(debug) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_DEBUG_ERROR_HEADER diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/debug.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/debug.h new file mode 100644 index 0000000000..af187bb9de --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/debug.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_DEBUG_H +#define MLD_DEBUG_H +#include "common.h" + +#if defined(MLDSA_DEBUG) +#include + +/************************************************* + * Name: mld_assert + * + * Description: Check debug assertion + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - val: Value asserted to be non-zero + **************************************************/ +#define mld_debug_check_assert MLD_NAMESPACE(mldsa_debug_assert) +void mld_debug_check_assert(const char *file, int line, const int val); + +/************************************************* + * Name: mld_debug_check_bounds + * + * Description: Check whether values in an array of int32_t + * are within specified bounds. + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - ptr: Base of array to be checked + * - len: Number of int32_t in ptr + * - lower_bound_exclusive: Exclusive lower bound + * - upper_bound_exclusive: Exclusive upper bound + **************************************************/ +#define mld_debug_check_bounds MLD_NAMESPACE(mldsa_debug_check_bounds) +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive); + +/* Check assertion, calling exit() upon failure + * + * val: Value that's asserted to be non-zero + */ +#define mld_assert(val) mld_debug_check_assert(__FILE__, __LINE__, (val)) + +/* Check bounds in array of int32_t's + * ptr: Base of int32_t array; will be explicitly cast to int32_t*, + * so you may pass a byte-compatible type such as mld_poly or mld_polyvec. + * len: Number of int32_t in array + * value_lb: Inclusive lower value bound + * value_ub: Exclusive upper value bound */ +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + mld_debug_check_bounds(__FILE__, __LINE__, (const int32_t *)(ptr), (len), \ + ((int64_t)(value_lb)) - 1, (value_ub)) + +/* Check absolute bounds in array of int32_t's + * ptr: Base of array, expression of type int32_t* + * len: Number of int32_t in array + * value_abs_bd: Exclusive absolute upper bound */ +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + mld_assert_bound((ptr), (len), (-((int64_t)(value_abs_bd)) + 1), \ + (value_abs_bd)) + +/* Version of bounds assertions for 2-dimensional arrays */ +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + mld_assert_bound((ptr), ((len0) * (len1)), (value_lb), (value_ub)) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + mld_assert_abs_bound((ptr), ((len0) * (len1)), (value_abs_bd)) + +/* When running CBMC, convert debug assertions into proof obligations */ +#elif defined(CBMC) +#include "cbmc.h" + +#define mld_assert(val) cassert(val) + +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + cassert(array_bound(((int32_t *)(ptr)), 0, (len), (value_lb), (value_ub))) + +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + cassert(array_abs_bound(((int32_t *)(ptr)), 0, (len), (value_abs_bd))) + +/* Because of https://github.com/diffblue/cbmc/issues/8570, we can't + * just use a single flattened array_bound(...) here. */ +#define mld_assert_bound_2d(ptr, M, N, value_lb, value_ub) \ + cassert(forall(kN, 0, (M), \ + array_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_lb), (value_ub)))) + +#define mld_assert_abs_bound_2d(ptr, M, N, value_abs_bd) \ + cassert(forall(kN, 0, (M), \ + array_abs_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_abs_bd)))) + +#else /* !MLDSA_DEBUG && CBMC */ + +#define mld_assert(val) \ + do \ + { \ + } while (0) +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + do \ + { \ + } while (0) +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + do \ + { \ + } while (0) + +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + do \ + { \ + } while (0) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + do \ + { \ + } while (0) + + +#endif /* !MLDSA_DEBUG && !CBMC */ +#endif /* !MLD_DEBUG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/fips202.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/fips202.c new file mode 100644 index 0000000000..1112de061c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/fips202.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "../common.h" +#include "../ct.h" +#include "fips202.h" +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +/************************************************* + * Name: keccak_init + * + * Description: Initializes the Keccak state. + * + * Arguments: - uint64_t *s: pointer to Keccak state + **************************************************/ +static void keccak_init(uint64_t s[MLD_KECCAK_LANES]) +__contract__( + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + mld_memset(s, 0, sizeof(uint64_t) * MLD_KECCAK_LANES); +} + +/************************************************* + * Name: keccak_absorb + * + * Description: Absorb step of Keccak; incremental. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_absorb(uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r, + const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(pos <= r) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(in, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + ensures(return_value < r)) +{ + while (inlen >= r - pos) + __loop__( + assigns(pos, in, inlen, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + invariant(inlen <= loop_entry(inlen)) + invariant(pos <= r) + invariant(in == loop_entry(in) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600_xor_bytes(s, in, pos, r - pos); + inlen -= r - pos; + in += r - pos; + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: At this point, inlen < r, so the truncation to unsigned is safe. */ + mld_keccakf1600_xor_bytes(s, in, pos, (unsigned)inlen); + + /* Safety: At this point, inlen < r and pos <= r so the truncation to unsigned + * is safe. */ + return (unsigned)(pos + inlen); +} + +/************************************************* + * Name: keccak_finalize + * + * Description: Finalize absorb step. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - uint8_t p: domain separation byte + **************************************************/ +static void keccak_finalize(uint64_t s[MLD_KECCAK_LANES], unsigned int pos, + unsigned int r, uint8_t p) +__contract__( + requires(pos <= r && r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires((r / 8) >= 1) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + uint8_t b = 0x80; + mld_keccakf1600_xor_bytes(s, &p, pos, 1); + mld_keccakf1600_xor_bytes(s, &b, r - 1, 1); +} + +/************************************************* + * Name: keccak_squeeze + * + * Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes. + * Modifies the state. Can be called multiple times to keep + * squeezing, i.e., is incremental. + * + * Arguments: - uint8_t *out: pointer to output data + * - size_t outlen: number of bytes to be squeezed (written to out) + * - uint64_t *s: pointer to input/output Keccak state + * - unsigned int pos: number of bytes in current block already + *squeezed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_squeeze(uint8_t *out, size_t outlen, + uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r) +__contract__( + requires((r == SHAKE128_RATE && pos <= SHAKE128_RATE) || + (r == SHAKE256_RATE && pos <= SHAKE256_RATE) || + (r == SHA3_512_RATE && pos <= SHA3_512_RATE)) + requires(outlen <= 8 * r /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(out, outlen)) + ensures(return_value <= r)) +{ + unsigned int i; + size_t out_offset = 0; + + /* Reference: This code is re-factored from the reference implementation + * to facilitate proof with CBMC and to improve readability. + * + * Take a mutable copy of outlen to count down the number of bytes + * still to squeeze. The initial value of outlen is needed for the CBMC + * assigns() clauses. */ + size_t bytes_to_go = outlen; + + while (bytes_to_go > 0) + __loop__( + assigns(i, bytes_to_go, pos, out_offset, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES), memory_slice(out, outlen)) + invariant(bytes_to_go <= outlen) + invariant(out_offset == outlen - bytes_to_go) + invariant(pos <= r) + ) + { + if (pos == r) + { + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: If bytes_to_go < r - pos, truncation to unsigned is safe. */ + i = bytes_to_go < r - pos ? (unsigned)bytes_to_go : r - pos; + mld_keccakf1600_extract_bytes(s, out + out_offset, pos, i); + bytes_to_go -= i; + pos += i; + out_offset += i; + } + + return pos; +} + +void mld_shake128_init(mld_shake128ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE128_RATE, in, inlen); +} + +void mld_shake128_finalize(mld_shake128ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE128_RATE, 0x1F); + state->pos = SHAKE128_RATE; +} + +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE128_RATE); +} + +void mld_shake128_release(mld_shake128ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128ctx)); +} + +void mld_shake256_init(mld_shake256ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); +} + +void mld_shake256_finalize(mld_shake256ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); + state->pos = SHAKE256_RATE; +} + +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); +} + +void mld_shake256_release(mld_shake256ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256ctx)); +} + +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +{ + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, in, inlen); + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/fips202.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/fips202.h new file mode 100644 index 0000000000..9f0253cb88 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/fips202.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202_H +#define MLD_FIPS202_FIPS202_H + +#include +#include +#include "../cbmc.h" +#include "../common.h" + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 +#define SHA3_256_RATE 136 +#define SHA3_512_RATE 72 +#define MLD_KECCAK_LANES 25 +#define SHA3_256_HASHBYTES 32 +#define SHA3_512_HASHBYTES 64 + + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake128ctx; + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake256ctx; + +#define mld_shake128_init MLD_NAMESPACE(shake128_init) +/************************************************* + * Name: mld_shake128_init + * + * Description: Initializes state for use as SHAKE128 XOF + * + * Arguments: - mld_shake128ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake128_init(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos == 0) +); + +#define mld_shake128_absorb MLD_NAMESPACE(shake128_absorb) +/************************************************* + * Name: mld_shake128_absorb + * + * Description: Absorb step of the SHAKE128 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake128ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_finalize MLD_NAMESPACE(shake128_finalize) +/************************************************* + * Name: mld_shake128_finalize + * + * Description: Concludes the absorb phase of the SHAKE128 XOF. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_finalize(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_squeeze MLD_NAMESPACE(shake128_squeeze) +/************************************************* + * Name: mld_shake128_squeeze + * + * Description: Squeeze step of SHAKE128 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake128ctx *s: pointer to input/output state + **************************************************/ +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE128_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_release MLD_NAMESPACE(shake128_release) +/************************************************* + * Name: mld_shake128_release + * + * Description: Release and securely zero the SHAKE128 state. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_release(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) +); + +#define mld_shake256_init MLD_NAMESPACE(shake256_init) +/************************************************* + * Name: mld_shake256_init + * + * Description: Initializes state for use as SHAKE256 XOF + * + * Arguments: - mld_shake256ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake256_init(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos == 0) +); + +#define mld_shake256_absorb MLD_NAMESPACE(shake256_absorb) +/************************************************* + * Name: mld_shake256_absorb + * + * Description: Absorb step of the SHAKE256 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake256ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_finalize MLD_NAMESPACE(shake256_finalize) +/************************************************* + * Name: mld_shake256_finalize + * + * Description: Concludes the absorb phase of the SHAKE256 XOF. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_finalize(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_squeeze MLD_NAMESPACE(shake256_squeeze) +/************************************************* + * Name: mld_shake256_squeeze + * + * Description: Squeeze step of SHAKE256 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake256ctx *s: pointer to input/output state + **************************************************/ +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_release MLD_NAMESPACE(shake256_release) +/************************************************* + * Name: mld_shake256_release + * + * Description: Release and securely zero the SHAKE256 state. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_release(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) +); + +#define mld_shake256 MLD_NAMESPACE(shake256) +/************************************************* + * Name: mld_shake256 + * + * Description: SHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +); + +#endif /* !MLD_FIPS202_FIPS202_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/fips202x4.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/fips202x4.c new file mode 100644 index 0000000000..0fb5cd57c7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/fips202x4.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include "../common.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "../ct.h" +#include "fips202.h" +#include "fips202x4.h" +#include "keccakf1600.h" + +static void mld_keccak_absorb_once_x4(uint64_t *s, uint32_t r, + const uint8_t *in0, const uint8_t *in1, + const uint8_t *in2, const uint8_t *in3, + size_t inlen, uint8_t p) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))) +{ + while (inlen >= r) + __loop__( + assigns(inlen, in0, in1, in2, in3, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + invariant(inlen <= loop_entry(inlen)) + invariant(in0 == loop_entry(in0) + (loop_entry(inlen) - inlen)) + invariant(in1 == loop_entry(in1) + (loop_entry(inlen) - inlen)) + invariant(in2 == loop_entry(in2) + (loop_entry(inlen) - inlen)) + invariant(in3 == loop_entry(in3) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, r); + mld_keccakf1600x4_permute(s); + + in0 += r; + in1 += r; + in2 += r; + in3 += r; + inlen -= r; + } + + /* Safety: At this point, inlen < r, so the truncations to unsigned are safe + * below. */ + if (inlen > 0) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, (unsigned)inlen); + } + + if (inlen == r - 1) + { + p |= 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + } + else + { + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + p = 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, r - 1, 1); + } +} + +static void mld_keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1, + uint8_t *out2, uint8_t *out3, + size_t nblocks, uint64_t *s, uint32_t r) +__contract__( + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(out0, nblocks * r)) + requires(memory_no_alias(out1, nblocks * r)) + requires(memory_no_alias(out2, nblocks * r)) + requires(memory_no_alias(out3, nblocks * r)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(out0, nblocks * r)) + assigns(memory_slice(out1, nblocks * r)) + assigns(memory_slice(out2, nblocks * r)) + assigns(memory_slice(out3, nblocks * r))) +{ + while (nblocks > 0) + __loop__( + assigns(out0, out1, out2, out3, nblocks, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY), + memory_slice(out0, nblocks * r), + memory_slice(out1, nblocks * r), + memory_slice(out2, nblocks * r), + memory_slice(out3, nblocks * r)) + invariant(nblocks <= loop_entry(nblocks) && + out0 == loop_entry(out0) + r * (loop_entry(nblocks) - nblocks) && + out1 == loop_entry(out1) + r * (loop_entry(nblocks) - nblocks) && + out2 == loop_entry(out2) + r * (loop_entry(nblocks) - nblocks) && + out3 == loop_entry(out3) + r * (loop_entry(nblocks) - nblocks))) + { + mld_keccakf1600x4_permute(s); + mld_keccakf1600x4_extract_bytes(s, out0, out1, out2, out3, 0, r); + + out0 += r; + out1 += r; + out2 += r; + out3 += r; + nblocks--; + } +} + +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake128x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE128_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE128_RATE); +} + +void mld_shake128x4_init(mld_shake128x4ctx *state) { (void)state; } +void mld_shake128x4_release(mld_shake128x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128x4ctx)); +} + + +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake256x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE256_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE256_RATE); +} + +void mld_shake256x4_init(mld_shake256x4ctx *state) { (void)state; } +void mld_shake256x4_release(mld_shake256x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256x4ctx)); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/fips202x4.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/fips202x4.h new file mode 100644 index 0000000000..e7987207a6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/fips202x4.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202X4_H +#define MLD_FIPS202_FIPS202X4_H + +#include +#include + +#include "../cbmc.h" +#include "../common.h" + +#include "fips202.h" +#include "keccakf1600.h" + +/* Context for non-incremental API */ +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake128x4ctx; + +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake256x4ctx; + +#define mld_shake128x4_absorb_once MLD_NAMESPACE(shake128x4_absorb_once) +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_squeezeblocks MLD_NAMESPACE(shake128x4_squeezeblocks) +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE128_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE128_RATE), + memory_slice(out1, nblocks * SHAKE128_RATE), + memory_slice(out2, nblocks * SHAKE128_RATE), + memory_slice(out3, nblocks * SHAKE128_RATE), + memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_init MLD_NAMESPACE(shake128x4_init) +void mld_shake128x4_init(mld_shake128x4ctx *state); + +#define mld_shake128x4_release MLD_NAMESPACE(shake128x4_release) +void mld_shake128x4_release(mld_shake128x4ctx *state); + + +#define mld_shake256x4_absorb_once MLD_NAMESPACE(shake256x4_absorb_once) +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_squeezeblocks MLD_NAMESPACE(shake256x4_squeezeblocks) +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE256_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE256_RATE), + memory_slice(out1, nblocks * SHAKE256_RATE), + memory_slice(out2, nblocks * SHAKE256_RATE), + memory_slice(out3, nblocks * SHAKE256_RATE), + memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_init MLD_NAMESPACE(shake256x4_init) +void mld_shake256x4_init(mld_shake256x4ctx *state); + +#define mld_shake256x4_release MLD_NAMESPACE(shake256x4_release) +void mld_shake256x4_release(mld_shake256x4ctx *state); + + +#endif /* !MLD_FIPS202_FIPS202X4_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/keccakf1600.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/keccakf1600.c new file mode 100644 index 0000000000..e59120c07c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/keccakf1600.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#define MLD_KECCAK_NROUNDS 24 +#define MLD_KECCAK_ROL(a, offset) ((a << offset) ^ (a >> (64 - offset))) + +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = state_ptr[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = (state[(offset + i) >> 3] >> (8 * ((offset + i) & 0x07))) & 0xFF; + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state_ptr[i] ^= data[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state[(offset + i) >> 3] ^= (uint64_t)data[i] + << (8 * ((offset + i) & 0x07)); + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X4_NATIVE) + if (mld_keccak_f1600_x4_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 0); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 1); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 2); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 3); +} + +static const uint64_t mld_KeccakF_RoundConstants[MLD_KECCAK_NROUNDS] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +static void mld_keccakf1600_permute_c(uint64_t *state) +{ + unsigned round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + uint64_t BCa, BCe, BCi, BCo, BCu; + uint64_t Da, De, Di, Do, Du; + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + /* copyFromState(A, state) */ + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < MLD_KECCAK_NROUNDS; round += 2) + __loop__(invariant(round <= MLD_KECCAK_NROUNDS && round % 2 == 0)) + { + /* prepareTheta */ + BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; + BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + /* thetaRhoPiChiIotaPrepareTheta(round, A, E) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = MLD_KECCAK_ROL(Age, 44); + Aki ^= Di; + BCi = MLD_KECCAK_ROL(Aki, 43); + Amo ^= Do; + BCo = MLD_KECCAK_ROL(Amo, 21); + Asu ^= Du; + BCu = MLD_KECCAK_ROL(Asu, 14); + Eba = BCa ^ ((~BCe) & BCi); + Eba ^= (uint64_t)mld_KeccakF_RoundConstants[round]; + Ebe = BCe ^ ((~BCi) & BCo); + Ebi = BCi ^ ((~BCo) & BCu); + Ebo = BCo ^ ((~BCu) & BCa); + Ebu = BCu ^ ((~BCa) & BCe); + + Abo ^= Do; + BCa = MLD_KECCAK_ROL(Abo, 28); + Agu ^= Du; + BCe = MLD_KECCAK_ROL(Agu, 20); + Aka ^= Da; + BCi = MLD_KECCAK_ROL(Aka, 3); + Ame ^= De; + BCo = MLD_KECCAK_ROL(Ame, 45); + Asi ^= Di; + BCu = MLD_KECCAK_ROL(Asi, 61); + Ega = BCa ^ ((~BCe) & BCi); + Ege = BCe ^ ((~BCi) & BCo); + Egi = BCi ^ ((~BCo) & BCu); + Ego = BCo ^ ((~BCu) & BCa); + Egu = BCu ^ ((~BCa) & BCe); + + Abe ^= De; + BCa = MLD_KECCAK_ROL(Abe, 1); + Agi ^= Di; + BCe = MLD_KECCAK_ROL(Agi, 6); + Ako ^= Do; + BCi = MLD_KECCAK_ROL(Ako, 25); + Amu ^= Du; + BCo = MLD_KECCAK_ROL(Amu, 8); + Asa ^= Da; + BCu = MLD_KECCAK_ROL(Asa, 18); + Eka = BCa ^ ((~BCe) & BCi); + Eke = BCe ^ ((~BCi) & BCo); + Eki = BCi ^ ((~BCo) & BCu); + Eko = BCo ^ ((~BCu) & BCa); + Eku = BCu ^ ((~BCa) & BCe); + + Abu ^= Du; + BCa = MLD_KECCAK_ROL(Abu, 27); + Aga ^= Da; + BCe = MLD_KECCAK_ROL(Aga, 36); + Ake ^= De; + BCi = MLD_KECCAK_ROL(Ake, 10); + Ami ^= Di; + BCo = MLD_KECCAK_ROL(Ami, 15); + Aso ^= Do; + BCu = MLD_KECCAK_ROL(Aso, 56); + Ema = BCa ^ ((~BCe) & BCi); + Eme = BCe ^ ((~BCi) & BCo); + Emi = BCi ^ ((~BCo) & BCu); + Emo = BCo ^ ((~BCu) & BCa); + Emu = BCu ^ ((~BCa) & BCe); + + Abi ^= Di; + BCa = MLD_KECCAK_ROL(Abi, 62); + Ago ^= Do; + BCe = MLD_KECCAK_ROL(Ago, 55); + Aku ^= Du; + BCi = MLD_KECCAK_ROL(Aku, 39); + Ama ^= Da; + BCo = MLD_KECCAK_ROL(Ama, 41); + Ase ^= De; + BCu = MLD_KECCAK_ROL(Ase, 2); + Esa = BCa ^ ((~BCe) & BCi); + Ese = BCe ^ ((~BCi) & BCo); + Esi = BCi ^ ((~BCo) & BCu); + Eso = BCo ^ ((~BCu) & BCa); + Esu = BCu ^ ((~BCa) & BCe); + + /* prepareTheta */ + BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + /* thetaRhoPiChiIotaPrepareTheta(round+1, E, A) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = MLD_KECCAK_ROL(Ege, 44); + Eki ^= Di; + BCi = MLD_KECCAK_ROL(Eki, 43); + Emo ^= Do; + BCo = MLD_KECCAK_ROL(Emo, 21); + Esu ^= Du; + BCu = MLD_KECCAK_ROL(Esu, 14); + Aba = BCa ^ ((~BCe) & BCi); + Aba ^= (uint64_t)mld_KeccakF_RoundConstants[round + 1]; + Abe = BCe ^ ((~BCi) & BCo); + Abi = BCi ^ ((~BCo) & BCu); + Abo = BCo ^ ((~BCu) & BCa); + Abu = BCu ^ ((~BCa) & BCe); + + Ebo ^= Do; + BCa = MLD_KECCAK_ROL(Ebo, 28); + Egu ^= Du; + BCe = MLD_KECCAK_ROL(Egu, 20); + Eka ^= Da; + BCi = MLD_KECCAK_ROL(Eka, 3); + Eme ^= De; + BCo = MLD_KECCAK_ROL(Eme, 45); + Esi ^= Di; + BCu = MLD_KECCAK_ROL(Esi, 61); + Aga = BCa ^ ((~BCe) & BCi); + Age = BCe ^ ((~BCi) & BCo); + Agi = BCi ^ ((~BCo) & BCu); + Ago = BCo ^ ((~BCu) & BCa); + Agu = BCu ^ ((~BCa) & BCe); + + Ebe ^= De; + BCa = MLD_KECCAK_ROL(Ebe, 1); + Egi ^= Di; + BCe = MLD_KECCAK_ROL(Egi, 6); + Eko ^= Do; + BCi = MLD_KECCAK_ROL(Eko, 25); + Emu ^= Du; + BCo = MLD_KECCAK_ROL(Emu, 8); + Esa ^= Da; + BCu = MLD_KECCAK_ROL(Esa, 18); + Aka = BCa ^ ((~BCe) & BCi); + Ake = BCe ^ ((~BCi) & BCo); + Aki = BCi ^ ((~BCo) & BCu); + Ako = BCo ^ ((~BCu) & BCa); + Aku = BCu ^ ((~BCa) & BCe); + + Ebu ^= Du; + BCa = MLD_KECCAK_ROL(Ebu, 27); + Ega ^= Da; + BCe = MLD_KECCAK_ROL(Ega, 36); + Eke ^= De; + BCi = MLD_KECCAK_ROL(Eke, 10); + Emi ^= Di; + BCo = MLD_KECCAK_ROL(Emi, 15); + Eso ^= Do; + BCu = MLD_KECCAK_ROL(Eso, 56); + Ama = BCa ^ ((~BCe) & BCi); + Ame = BCe ^ ((~BCi) & BCo); + Ami = BCi ^ ((~BCo) & BCu); + Amo = BCo ^ ((~BCu) & BCa); + Amu = BCu ^ ((~BCa) & BCe); + + Ebi ^= Di; + BCa = MLD_KECCAK_ROL(Ebi, 62); + Ego ^= Do; + BCe = MLD_KECCAK_ROL(Ego, 55); + Eku ^= Du; + BCi = MLD_KECCAK_ROL(Eku, 39); + Ema ^= Da; + BCo = MLD_KECCAK_ROL(Ema, 41); + Ese ^= De; + BCu = MLD_KECCAK_ROL(Ese, 2); + Asa = BCa ^ ((~BCe) & BCi); + Ase = BCe ^ ((~BCi) & BCo); + Asi = BCi ^ ((~BCo) & BCu); + Aso = BCo ^ ((~BCu) & BCa); + Asu = BCu ^ ((~BCa) & BCe); + } + + /* copyToState(state, A) */ + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} + +void mld_keccakf1600_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X1_NATIVE) + if (mld_keccak_f1600_x1_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X1_NATIVE */ + mld_keccakf1600_permute_c(state); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(keccakf1600) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_KECCAK_NROUNDS +#undef MLD_KECCAK_ROL diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/keccakf1600.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/keccakf1600.h new file mode 100644 index 0000000000..e56adc1561 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/keccakf1600.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_KECCAKF1600_H +#define MLD_FIPS202_KECCAKF1600_H +#include +#include "../cbmc.h" +#include "../common.h" +#include "fips202.h" + +#define MLD_KECCAK_LANES 25 +#define MLD_KECCAK_WAY 4 + +/* + * WARNING: + * The contents of this structure, including the placement + * and interleaving of Keccak lanes, are IMPLEMENTATION-DEFINED. + * The struct is only exposed here to allow its construction on the stack. + */ + +#define mld_keccakf1600_extract_bytes MLD_NAMESPACE(keccakf1600_extract_bytes) +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(data, length)) +); + +#define mld_keccakf1600_xor_bytes MLD_NAMESPACE(keccakf1600_xor_bytes) +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#define mld_keccakf1600x4_extract_bytes \ + MLD_NAMESPACE(keccakf1600x4_extract_bytes) +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + requires(memory_no_alias(data1, length)) + requires(memory_no_alias(data2, length)) + requires(memory_no_alias(data3, length)) + assigns(memory_slice(data0, length)) + assigns(memory_slice(data1, length)) + assigns(memory_slice(data2, length)) + assigns(memory_slice(data3, length)) +); + +#define mld_keccakf1600x4_xor_bytes MLD_NAMESPACE(keccakf1600x4_xor_bytes) +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + /* Case 1: all input buffers are distinct; Case 2: All input buffers are the same */ + requires((data0 == data1 && + data0 == data2 && + data0 == data3) || + (memory_no_alias(data1, length) && + memory_no_alias(data2, length) && + memory_no_alias(data3, length))) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600x4_permute MLD_NAMESPACE(keccakf1600x4_permute) +void mld_keccakf1600x4_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600_permute MLD_NAMESPACE(keccakf1600_permute) +void mld_keccakf1600_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#endif /* !MLD_FIPS202_KECCAKF1600_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/auto.h new file mode 100644 index 0000000000..4375cc1976 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/auto.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [HYBRID] + * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64 + * Becker, Kannwischer + * https://eprint.iacr.org/2022/1243 + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +#define MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* Default FIPS202 assembly profile for AArch64 systems */ + +/* + * Default logic to decide which implementation to use. + * + */ + +/* + * Keccak-f1600 + * + * - On Arm-based Apple CPUs, we pick a pure Neon implementation. + * - Otherwise, unless MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, + * we use lazy-rotation scalar assembly from @[HYBRID]. + * - Otherwise, if MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, we + * fall back to the standard C implementation. + */ +#if defined(__ARM_FEATURE_SHA3) && defined(__APPLE__) +#include "x1_v84a.h" +#elif !defined(MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER) +#include "x1_scalar.h" +#endif + +/* + * Keccak-f1600x2/x4 + * + * The optimal implementation is highly CPU-specific; see @[HYBRID]. + * + * For now, if v8.4-A is not implemented, we fall back to Keccak-f1600. + * If v8.4-A is implemented and we are on an Apple CPU, we use a plain + * Neon-based implementation. + * If v8.4-A is implemented and we are not on an Apple CPU, we use a + * scalar/Neon/Neon hybrid. + * The reason for this distinction is that Apple CPUs appear to implement + * the SHA3 instructions on all SIMD units, while Arm CPUs prior to Cortex-X4 + * don't, and ordinary Neon instructions are still needed. + */ +#if defined(__ARM_FEATURE_SHA3) +/* + * For Apple-M cores, we use a plain implementation leveraging SHA3 + * instructions only. + */ +#if defined(__APPLE__) +#include "x2_v84a.h" +#else +#include "x4_v8a_v84a_scalar.h" +#endif + +#else /* __ARM_FEATURE_SHA3 */ + +#include "x4_v8a_scalar.h" + +#endif /* !__ARM_FEATURE_SHA3 */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h new file mode 100644 index 0000000000..20f6168038 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#define MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H + +#include +#include "../../../../cbmc.h" +#include "../../../../common.h" + + +#define mld_keccakf1600_round_constants \ + MLD_NAMESPACE(keccakf1600_round_constants) +extern const uint64_t mld_keccakf1600_round_constants[]; + +#define mld_keccak_f1600_x1_scalar_asm MLD_NAMESPACE(keccak_f1600_x1_scalar_asm) +void mld_keccak_f1600_x1_scalar_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x1_v84a_asm MLD_NAMESPACE(keccak_f1600_x1_v84a_asm) +void mld_keccak_f1600_x1_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x2_v84a_asm MLD_NAMESPACE(keccak_f1600_x2_v84a_asm) +void mld_keccak_f1600_x2_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 2)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 2)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c new file mode 100644 index 0000000000..05e9cbfeec --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../../common.h" + +#if (defined(MLD_FIPS202_AARCH64_NEED_X1_SCALAR) || \ + defined(MLD_FIPS202_AARCH64_NEED_X1_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X2_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID)) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "fips202_native_aarch64.h" + +MLD_ALIGN const uint64_t mld_keccakf1600_round_constants[] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, +}; + +#else /* (MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_aarch64_round_constants) + +#endif /* !((MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/x1_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/x1_scalar.h new file mode 100644 index 0000000000..681b991371 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/x1_scalar.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_SCALAR + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + mld_keccak_f1600_x1_scalar_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/x1_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/x1_v84a.h new file mode 100644 index 0000000000..d15c8c26f3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/x1_v84a.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x1_v84a_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/x2_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/x2_v84a.h new file mode 100644 index 0000000000..16c22fa1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/x2_v84a.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X2_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" + + +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x2_v84a_asm(state + 0 * 25, mld_keccakf1600_round_constants); + mld_keccak_f1600_x2_v84a_asm(state + 2 * 25, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h new file mode 100644 index 0000000000..0f7f8fe499 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(state, + mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h new file mode 100644 index 0000000000..3da883b762 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm( + state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/api.h new file mode 100644 index 0000000000..4625c9a1ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/api.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_API_H +#define MLD_FIPS202_NATIVE_API_H +/* + * FIPS-202 native interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + */ + +#include +#include "../../cbmc.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* + * This is the C<->native interface allowing for the drop-in + * of custom Keccak-F1600 implementations. + * + * A _backend_ is a specific implementation of parts of this interface. + * + * You can replace 1-fold or 4-fold batched Keccak-F1600. + * To enable, set MLD_USE_FIPS202_X1_NATIVE or MLD_USE_FIPS202_X4_NATIVE + * in your backend, and define the inline wrappers mld_keccak_f1600_x1_native() + * and/or mld_keccak_f1600_x4_native(), respectively, to forward to your + * implementation. + */ + +#if defined(MLD_USE_FIPS202_X1_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 1)) +); +#endif /* MLD_USE_FIPS202_X1_NATIVE */ +#if defined(MLD_USE_FIPS202_X4_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 4)) +); +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + +#endif /* !MLD_FIPS202_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/auto.h new file mode 100644 index 0000000000..0a09c733c8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/auto.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AUTO_H +#define MLD_FIPS202_NATIVE_AUTO_H + +/* + * Default FIPS202 backend + */ +#include "../../sys.h" + +#if defined(MLD_SYS_AARCH64) +#include "aarch64/auto.h" +#endif + +#if defined(MLD_SYS_X86_64) && defined(MLD_SYS_X86_64_AVX2) +#include "x86_64/xkcp.h" +#endif + +#endif /* !MLD_FIPS202_NATIVE_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c new file mode 100644 index 0000000000..4eaad2fd66 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* +Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, +Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby +denoted as "the implementer". + +For more information, feedback or questions, please refer to our websites: +http://keccak.noekeon.org/ +http://keyak.noekeon.org/ +http://ketje.noekeon.org/ + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +/* + * Changes for mlkem-native/mldsa-native: + * - copyFromState and copyToState operate on uninterleaved + * Keccak states in memory. + */ + +#include "../../../../common.h" +#if defined(MLD_FIPS202_X86_64_XKCP) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include + +#include "KeccakP_1600_times4_SIMD256.h" + +#ifndef MLD_SYS_LITTLE_ENDIAN +#error Expecting a little-endian platform +#endif + +#define ANDnu256(a, b) _mm256_andnot_si256(a, b) +#define CONST256(a) _mm256_load_si256((const __m256i *)&(a)) +#define CONST256_64(a) (__m256i) _mm256_broadcast_sd((const double *)(&a)) +#define ROL64in256(d, a, o) \ + d = _mm256_or_si256(_mm256_slli_epi64(a, o), _mm256_srli_epi64(a, 64 - (o))) +#define ROL64in256_8(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho8)) +#define ROL64in256_56(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho56)) +static const uint64_t rho8[4] = {0x0605040302010007, 0x0E0D0C0B0A09080F, + 0x1615141312111017, 0x1E1D1C1B1A19181F}; +static const uint64_t rho56[4] = {0x0007060504030201, 0x080F0E0D0C0B0A09, + 0x1017161514131211, 0x181F1E1D1C1B1A19}; +#define STORE256(a, b) _mm256_store_si256((__m256i *)&(a), b) +#define XOR256(a, b) _mm256_xor_si256(a, b) +#define XOReq256(a, b) a = _mm256_xor_si256(a, b) + +#define SnP_laneLengthInBytes 8 + +#define declareABCDE \ + __m256i Aba, Abe, Abi, Abo, Abu; \ + __m256i Aga, Age, Agi, Ago, Agu; \ + __m256i Aka, Ake, Aki, Ako, Aku; \ + __m256i Ama, Ame, Ami, Amo, Amu; \ + __m256i Asa, Ase, Asi, Aso, Asu; \ + __m256i Bba, Bbe, Bbi, Bbo, Bbu; \ + __m256i Bga, Bge, Bgi, Bgo, Bgu; \ + __m256i Bka, Bke, Bki, Bko, Bku; \ + __m256i Bma, Bme, Bmi, Bmo, Bmu; \ + __m256i Bsa, Bse, Bsi, Bso, Bsu; \ + __m256i Ca, Ce, Ci, Co, Cu; \ + __m256i Ca1, Ce1, Ci1, Co1, Cu1; \ + __m256i Da, De, Di, Do, Du; \ + __m256i Eba, Ebe, Ebi, Ebo, Ebu; \ + __m256i Ega, Ege, Egi, Ego, Egu; \ + __m256i Eka, Eke, Eki, Eko, Eku; \ + __m256i Ema, Eme, Emi, Emo, Emu; \ + __m256i Esa, Ese, Esi, Eso, Esu; + +#define prepareTheta \ + Ca = XOR256(Aba, XOR256(Aga, XOR256(Aka, XOR256(Ama, Asa)))); \ + Ce = XOR256(Abe, XOR256(Age, XOR256(Ake, XOR256(Ame, Ase)))); \ + Ci = XOR256(Abi, XOR256(Agi, XOR256(Aki, XOR256(Ami, Asi)))); \ + Co = XOR256(Abo, XOR256(Ago, XOR256(Ako, XOR256(Amo, Aso)))); \ + Cu = XOR256(Abu, XOR256(Agu, XOR256(Aku, XOR256(Amu, Asu)))); + +/* + * --- Theta Rho Pi Chi Iota Prepare-theta + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + Ca = E##ba; \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + Ce = E##be; \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + Ci = E##bi; \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + Co = E##bo; \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + Cu = E##bu; \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(Ca, E##ga); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(Ce, E##ge); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + XOReq256(Ci, E##gi); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + XOReq256(Co, E##go); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + XOReq256(Cu, E##gu); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(Ca, E##ka); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(Ce, E##ke); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + XOReq256(Ci, E##ki); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + XOReq256(Co, E##ko); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + XOReq256(Cu, E##ku); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(Ca, E##ma); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(Ce, E##me); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + XOReq256(Ci, E##mi); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + XOReq256(Co, E##mo); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + XOReq256(Cu, E##mu); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(Ca, E##sa); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(Ce, E##se); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + XOReq256(Ci, E##si); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + XOReq256(Co, E##so); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); \ + XOReq256(Cu, E##su); + + +/* + * --- Theta Rho Pi Chi Iota + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIota(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); + + +static MLD_ALIGN const uint64_t keccakf1600RoundConstants[24] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +#include + +#define copyFromState(X, state) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m256i _idx = \ + _mm256_set_epi64x((long long)&state64[75], (long long)&state64[50], \ + (long long)&state64[25], (long long)&state64[0]); \ + X##ba = _mm256_i64gather_epi64((long long *)(0 * 8), _idx, 1); \ + X##be = _mm256_i64gather_epi64((long long *)(1 * 8), _idx, 1); \ + X##bi = _mm256_i64gather_epi64((long long *)(2 * 8), _idx, 1); \ + X##bo = _mm256_i64gather_epi64((long long *)(3 * 8), _idx, 1); \ + X##bu = _mm256_i64gather_epi64((long long *)(4 * 8), _idx, 1); \ + X##ga = _mm256_i64gather_epi64((long long *)(5 * 8), _idx, 1); \ + X##ge = _mm256_i64gather_epi64((long long *)(6 * 8), _idx, 1); \ + X##gi = _mm256_i64gather_epi64((long long *)(7 * 8), _idx, 1); \ + X##go = _mm256_i64gather_epi64((long long *)(8 * 8), _idx, 1); \ + X##gu = _mm256_i64gather_epi64((long long *)(9 * 8), _idx, 1); \ + X##ka = _mm256_i64gather_epi64((long long *)(10 * 8), _idx, 1); \ + X##ke = _mm256_i64gather_epi64((long long *)(11 * 8), _idx, 1); \ + X##ki = _mm256_i64gather_epi64((long long *)(12 * 8), _idx, 1); \ + X##ko = _mm256_i64gather_epi64((long long *)(13 * 8), _idx, 1); \ + X##ku = _mm256_i64gather_epi64((long long *)(14 * 8), _idx, 1); \ + X##ma = _mm256_i64gather_epi64((long long *)(15 * 8), _idx, 1); \ + X##me = _mm256_i64gather_epi64((long long *)(16 * 8), _idx, 1); \ + X##mi = _mm256_i64gather_epi64((long long *)(17 * 8), _idx, 1); \ + X##mo = _mm256_i64gather_epi64((long long *)(18 * 8), _idx, 1); \ + X##mu = _mm256_i64gather_epi64((long long *)(19 * 8), _idx, 1); \ + X##sa = _mm256_i64gather_epi64((long long *)(20 * 8), _idx, 1); \ + X##se = _mm256_i64gather_epi64((long long *)(21 * 8), _idx, 1); \ + X##si = _mm256_i64gather_epi64((long long *)(22 * 8), _idx, 1); \ + X##so = _mm256_i64gather_epi64((long long *)(23 * 8), _idx, 1); \ + X##su = _mm256_i64gather_epi64((long long *)(24 * 8), _idx, 1); \ + } while (0); + +#define SCATTER_STORE256(state, idx, v) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m128d t = _mm_castsi128_pd(_mm256_castsi256_si128((v))); \ + _mm_storel_pd((double *)&state64[0 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[25 + (idx)], t); \ + t = _mm_castsi128_pd(_mm256_extracti128_si256((v), 1)); \ + _mm_storel_pd((double *)&state64[50 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[75 + (idx)], t); \ + } while (0) + +#define copyToState(state, X) \ + SCATTER_STORE256(state, 0, X##ba); \ + SCATTER_STORE256(state, 1, X##be); \ + SCATTER_STORE256(state, 2, X##bi); \ + SCATTER_STORE256(state, 3, X##bo); \ + SCATTER_STORE256(state, 4, X##bu); \ + SCATTER_STORE256(state, 5, X##ga); \ + SCATTER_STORE256(state, 6, X##ge); \ + SCATTER_STORE256(state, 7, X##gi); \ + SCATTER_STORE256(state, 8, X##go); \ + SCATTER_STORE256(state, 9, X##gu); \ + SCATTER_STORE256(state, 10, X##ka); \ + SCATTER_STORE256(state, 11, X##ke); \ + SCATTER_STORE256(state, 12, X##ki); \ + SCATTER_STORE256(state, 13, X##ko); \ + SCATTER_STORE256(state, 14, X##ku); \ + SCATTER_STORE256(state, 15, X##ma); \ + SCATTER_STORE256(state, 16, X##me); \ + SCATTER_STORE256(state, 17, X##mi); \ + SCATTER_STORE256(state, 18, X##mo); \ + SCATTER_STORE256(state, 19, X##mu); \ + SCATTER_STORE256(state, 20, X##sa); \ + SCATTER_STORE256(state, 21, X##se); \ + SCATTER_STORE256(state, 22, X##si); \ + SCATTER_STORE256(state, 23, X##so); \ + SCATTER_STORE256(state, 24, X##su); + +#define copyStateVariables(X, Y) \ + X##ba = Y##ba; \ + X##be = Y##be; \ + X##bi = Y##bi; \ + X##bo = Y##bo; \ + X##bu = Y##bu; \ + X##ga = Y##ga; \ + X##ge = Y##ge; \ + X##gi = Y##gi; \ + X##go = Y##go; \ + X##gu = Y##gu; \ + X##ka = Y##ka; \ + X##ke = Y##ke; \ + X##ki = Y##ki; \ + X##ko = Y##ko; \ + X##ku = Y##ku; \ + X##ma = Y##ma; \ + X##me = Y##me; \ + X##mi = Y##mi; \ + X##mo = Y##mo; \ + X##mu = Y##mu; \ + X##sa = Y##sa; \ + X##se = Y##se; \ + X##si = Y##si; \ + X##so = Y##so; \ + X##su = Y##su; + +/* clang-format off */ +#define rounds24 \ + prepareTheta \ + thetaRhoPiChiIotaPrepareTheta( 0, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 1, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 2, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 3, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 4, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 5, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 6, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 7, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 8, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 9, E, A) \ + thetaRhoPiChiIotaPrepareTheta(10, A, E) \ + thetaRhoPiChiIotaPrepareTheta(11, E, A) \ + thetaRhoPiChiIotaPrepareTheta(12, A, E) \ + thetaRhoPiChiIotaPrepareTheta(13, E, A) \ + thetaRhoPiChiIotaPrepareTheta(14, A, E) \ + thetaRhoPiChiIotaPrepareTheta(15, E, A) \ + thetaRhoPiChiIotaPrepareTheta(16, A, E) \ + thetaRhoPiChiIotaPrepareTheta(17, E, A) \ + thetaRhoPiChiIotaPrepareTheta(18, A, E) \ + thetaRhoPiChiIotaPrepareTheta(19, E, A) \ + thetaRhoPiChiIotaPrepareTheta(20, A, E) \ + thetaRhoPiChiIotaPrepareTheta(21, E, A) \ + thetaRhoPiChiIotaPrepareTheta(22, A, E) \ + thetaRhoPiChiIota(23, E, A) +/* clang-format on */ + +void mld_keccakf1600x4_permute24(void *states) +{ + __m256i *statesAsLanes = (__m256i *)states; + declareABCDE copyFromState(A, statesAsLanes) + rounds24 copyToState(statesAsLanes, A) +} + +#else /* MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_avx2_keccakx4) + +#endif /* !(MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef ANDnu256 +#undef CONST256 +#undef CONST256_64 +#undef ROL64in256 +#undef ROL64in256_8 +#undef ROL64in256_56 +#undef STORE256 +#undef XOR256 +#undef XOReq256 +#undef SnP_laneLengthInBytes +#undef declareABCDE +#undef prepareTheta +#undef thetaRhoPiChiIotaPrepareTheta +#undef thetaRhoPiChiIota +#undef copyFromState +#undef SCATTER_STORE256 +#undef copyToState +#undef copyStateVariables +#undef rounds24 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h new file mode 100644 index 0000000000..3499d38e2c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H +#define MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H + +#include "../../../../common.h" + +#define mld_keccakf1600x4_permute24 \ + MLD_NAMESPACE(KeccakP1600times4_PermuteAll_24rounds) +void mld_keccakf1600x4_permute24(void *states); + +#endif /* !MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/x86_64/xkcp.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/x86_64/xkcp.h new file mode 100644 index 0000000000..c03642d7e0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/fips202/native/x86_64/xkcp.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_XKCP_H +#define MLD_FIPS202_NATIVE_X86_64_XKCP_H + +#include "../../../common.h" + +#define MLD_FIPS202_X86_64_XKCP + +#if !defined(__ASSEMBLER__) +#include +#include "../api.h" +#include "src/KeccakP_1600_times4_SIMD256.h" + +#define MLD_USE_FIPS202_X4_NATIVE +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_keccakf1600x4_permute24(state); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_X86_64_XKCP_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/meta.h new file mode 100644 index 0000000000..c6f6ad47b0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/meta.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_META_H +#define MLD_NATIVE_AARCH64_META_H + +/* Set of primitives that this backend replaces */ +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_AARCH64 + + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/arith_native_aarch64.h" + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + mld_ntt_asm(data, mld_aarch64_ntt_zetas_layer123456, + mld_aarch64_ntt_zetas_layer78); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + mld_intt_asm(data, mld_aarch64_intt_zetas_layer78, + mld_aarch64_intt_zetas_layer123456); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + if (len != MLDSA_N || + buflen % 24 != 0) /* NEON support is mandatory for AArch64 */ + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N, hence, this cast is safe. */ + return (int)mld_rej_uniform_asm(r, buf, buflen, mld_rej_uniform_table); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_32_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_88_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + mld_poly_caddq_asm(a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_32_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_88_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + return mld_poly_chknorm_asm(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_17_asm(r, buf, mld_polyz_unpack_17_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_19_asm(r, buf, mld_polyz_unpack_19_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t out[MLDSA_N], const int32_t in0[MLDSA_N], + const int32_t in1[MLDSA_N]) +{ + mld_poly_pointwise_montgomery_asm(out, in0, in1); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l4_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l5_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l7_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ +#endif /* !MLD_NATIVE_AARCH64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/src/aarch64_zetas.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/src/aarch64_zetas.c new file mode 100644 index 0000000000..9ab7b9a68c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/src/aarch64_zetas.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Table of zeta values used in the AArch64 forward NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer123456[] = { + -3572223, -915382907, 3765607, 964937599, 3761513, 963888510, + -3201494, -820383522, -2883726, -738955404, -3145678, -806080660, + -3201430, -820367122, 0, 0, -601683, -154181397, + -3370349, -863652652, -4063053, -1041158200, 3602218, 923069133, + 3182878, 815613168, 2740543, 702264730, -3586446, -919027554, + 0, 0, 3542485, 907762539, 2663378, 682491182, + -1674615, -429120452, -3110818, -797147778, 2101410, 538486762, + 3704823, 949361686, 1159875, 297218217, 0, 0, + 2682288, 687336873, -3524442, -903139016, -434125, -111244624, + 394148, 101000509, 928749, 237992130, 1095468, 280713909, + -3506380, -898510625, 0, 0, 2129892, 545785280, + 676590, 173376332, -1335936, -342333886, 2071829, 530906624, + -4018989, -1029866791, 3241972, 830756018, 2156050, 552488273, + 0, 0, 3764867, 964747974, -3227876, -827143915, + 1714295, 439288460, 3415069, 875112161, 1759347, 450833045, + -817536, -209493775, -3574466, -915957677, 0, 0, + -1005239, -257592709, 2453983, 628833668, 1460718, 374309300, + 3756790, 962678241, -1935799, -496048908, -1716988, -439978542, + -3950053, -1012201926, 0, 0, 557458, 142848732, + -642628, -164673562, -3585098, -918682129, -2897314, -742437332, + 3192354, 818041395, 556856, 142694469, 3870317, 991769559, + 0, 0, -1221177, -312926867, 2815639, 721508096, + 2283733, 585207070, 2917338, 747568486, 1853806, 475038184, + 3345963, 857403734, 1858416, 476219497, 0, 0, +}; + +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer78[] = { + 3073009, 1277625, -2635473, 3852015, 787459213, + 327391679, -675340520, 987079667, 1753, -2659525, + 2660408, -59148, 449207, -681503850, 681730119, + -15156688, -1935420, -1455890, -1780227, 2772600, + -495951789, -373072124, -456183549, 710479343, 4183372, + -3222807, -3121440, -274060, 1071989969, -825844983, + -799869667, -70227934, 1182243, 636927, -3956745, + -3284915, 302950022, 163212680, -1013916752, -841760171, + 87208, -3965306, -2296397, -3716946, 22347069, + -1016110510, -588452222, -952468207, 2508980, 2028118, + 1937570, -3815725, 642926661, 519705671, 496502727, + -977780347, -27812, 1009365, -1979497, -3956944, + -7126831, 258649997, -507246529, -1013967746, 822541, + -2454145, 1596822, -3759465, 210776307, -628875181, + 409185979, -963363710, 2811291, -2983781, -1109516, + 4158088, 720393920, -764594519, -284313712, 1065510939, + -1685153, 2678278, -3551006, -250446, -431820817, + 686309310, -909946047, -64176841, -3410568, -3768948, + 635956, -2455377, -873958779, -965793731, 162963861, + -629190881, 1528066, 482649, 1148858, -2962264, + 391567239, 123678909, 294395108, -759080783, -4146264, + 2192938, 2387513, -268456, -1062481036, 561940831, + 611800717, -68791907, -1772588, -1727088, -3611750, + -3180456, -454226054, -442566669, -925511710, -814992530, + -565603, 169688, 2462444, -3334383, -144935890, + 43482586, 631001801, -854436357, 3747250, 1239911, + 3195676, 1254190, 960233614, 317727459, 818892658, + 321386456, 2296099, -3838479, 2642980, -12417, + 588375860, -983611064, 677264190, -3181859, -4166425, + -3488383, 1987814, -3197248, -1067647297, -893898890, + 509377762, -819295484, 2998219, -89301, -1354892, + -1310261, 768294260, -22883400, -347191365, -335754661, + 141835, 2513018, 613238, -2218467, 36345249, + 643961400, 157142369, -568482643, 1736313, 235407, + -3250154, 3258457, 444930577, 60323094, -832852657, + 834980303, -458740, 4040196, 2039144, -818761, + -117552223, 1035301089, 522531086, -209807681, -1921994, + -3472069, -1879878, -2178965, -492511373, -889718424, + -481719139, -558360247, -2579253, 1787943, -2391089, + -2254727, -660934133, 458160776, -612717067, -577774276, + -1623354, -2374402, 586241, 527981, -415984810, + -608441020, 150224382, 135295244, 2105286, -2033807, + -1179613, -2743411, 539479988, -521163479, -302276083, + -702999655, 3482206, -4182915, -1300016, -2362063, + 892316032, -1071872863, -333129378, -605279149, -1476985, + 2491325, 507927, -724804, -378477722, 638402564, + 130156402, -185731180, 1994046, -1393159, -1187885, + -1834526, 510974714, -356997292, -304395785, -470097680, + -1317678, 2461387, 3035980, 621164, -337655269, + 630730945, 777970524, 159173408, -3033742, 2647994, + -2612853, 749577, -777397036, 678549029, -669544140, + 192079267, -338420, 3009748, 4148469, -4022750, + -86720197, 771248568, 1063046068, -1030830548, 3901472, + -1226661, 2925816, 3374250, 999753034, -314332144, + 749740976, 864652284, 3980599, -1615530, 1665318, + 1163598, 1020029345, -413979908, 426738094, 298172236, + 2569011, 1723229, 2028038, -3369273, 658309618, + 441577800, 519685171, -863376927, 1356448, -2775755, + 2683270, -2778788, 347590090, -711287812, 687588511, + -712065019, 3994671, -1370517, 3363542, 545376, + 1023635298, -351195274, 861908357, 139752717, -11879, + 3020393, 214880, -770441, -3043996, 773976352, + 55063046, -197425671, -3467665, 2312838, -653275, + -459163, -888589898, 592665232, -167401858, -117660617, + 3105558, 508145, 860144, 140244, 795799901, + 130212265, 220412084, 35937555, -1103344, -553718, + 3430436, -1514152, -282732136, -141890356, 879049958, + -388001774, 348812, -327848, 1011223, -2354215, + 89383150, -84011120, 259126110, -603268097, -2185084, + 2358373, -3014420, 2926054, -559928242, 604333585, + -772445769, 749801963, 3123762, -2193087, -1716814, + -392707, 800464680, -561979013, -439933955, -100631253, + -3818627, -1922253, -2236726, 1744507, -978523985, + -492577742, -573161516, 447030292, -303005, -3974485, + 1900052, 1054478, -77645096, -1018462631, 486888731, + 270210213, 3531229, -3773731, -781875, -731434, + 904878186, -967019376, -200355636, -187430119, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer78[] = { + -1744507, 2236726, 1922253, 3818627, -447030292, 573161516, + 492577742, 978523985, 731434, 781875, 3773731, -3531229, + 187430119, 200355636, 967019376, -904878186, -1054478, -1900052, + 3974485, 303005, -270210213, -486888731, 1018462631, 77645096, + 2354215, -1011223, 327848, -348812, 603268097, -259126110, + 84011120, -89383150, 392707, 1716814, 2193087, -3123762, + 100631253, 439933955, 561979013, -800464680, -2926054, 3014420, + -2358373, 2185084, -749801963, 772445769, -604333585, 559928242, + 459163, 653275, -2312838, 3467665, 117660617, 167401858, + -592665232, 888589898, 1514152, -3430436, 553718, 1103344, + 388001774, -879049958, 141890356, 282732136, -140244, -860144, + -508145, -3105558, -35937555, -220412084, -130212265, -795799901, + 2778788, -2683270, 2775755, -1356448, 712065019, -687588511, + 711287812, -347590090, 770441, -214880, -3020393, 11879, + 197425671, -55063046, -773976352, 3043996, -545376, -3363542, + 1370517, -3994671, -139752717, -861908357, 351195274, -1023635298, + -3374250, -2925816, 1226661, -3901472, -864652284, -749740976, + 314332144, -999753034, 3369273, -2028038, -1723229, -2569011, + 863376927, -519685171, -441577800, -658309618, -1163598, -1665318, + 1615530, -3980599, -298172236, -426738094, 413979908, -1020029345, + -621164, -3035980, -2461387, 1317678, -159173408, -777970524, + -630730945, 337655269, 4022750, -4148469, -3009748, 338420, + 1030830548, -1063046068, -771248568, 86720197, -749577, 2612853, + -2647994, 3033742, -192079267, 669544140, -678549029, 777397036, + 2362063, 1300016, 4182915, -3482206, 605279149, 333129378, + 1071872863, -892316032, 1834526, 1187885, 1393159, -1994046, + 470097680, 304395785, 356997292, -510974714, 724804, -507927, + -2491325, 1476985, 185731180, -130156402, -638402564, 378477722, + 2254727, 2391089, -1787943, 2579253, 577774276, 612717067, + -458160776, 660934133, 2743411, 1179613, 2033807, -2105286, + 702999655, 302276083, 521163479, -539479988, -527981, -586241, + 2374402, 1623354, -135295244, -150224382, 608441020, 415984810, + -3258457, 3250154, -235407, -1736313, -834980303, 832852657, + -60323094, -444930577, 2178965, 1879878, 3472069, 1921994, + 558360247, 481719139, 889718424, 492511373, 818761, -2039144, + -4040196, 458740, 209807681, -522531086, -1035301089, 117552223, + 3197248, -1987814, 3488383, 4166425, 819295484, -509377762, + 893898890, 1067647297, 2218467, -613238, -2513018, -141835, + 568482643, -157142369, -643961400, -36345249, 1310261, 1354892, + 89301, -2998219, 335754661, 347191365, 22883400, -768294260, + 3334383, -2462444, -169688, 565603, 854436357, -631001801, + -43482586, 144935890, 12417, -2642980, 3838479, -2296099, + 3181859, -677264190, 983611064, -588375860, -1254190, -3195676, + -1239911, -3747250, -321386456, -818892658, -317727459, -960233614, + 2962264, -1148858, -482649, -1528066, 759080783, -294395108, + -123678909, -391567239, 3180456, 3611750, 1727088, 1772588, + 814992530, 925511710, 442566669, 454226054, 268456, -2387513, + -2192938, 4146264, 68791907, -611800717, -561940831, 1062481036, + -4158088, 1109516, 2983781, -2811291, -1065510939, 284313712, + 764594519, -720393920, 2455377, -635956, 3768948, 3410568, + 629190881, -162963861, 965793731, 873958779, 250446, 3551006, + -2678278, 1685153, 64176841, 909946047, -686309310, 431820817, + 3815725, -1937570, -2028118, -2508980, 977780347, -496502727, + -519705671, -642926661, 3759465, -1596822, 2454145, -822541, + 963363710, -409185979, 628875181, -210776307, 3956944, 1979497, + -1009365, 27812, 1013967746, 507246529, -258649997, 7126831, + 274060, 3121440, 3222807, -4183372, 70227934, 799869667, + 825844983, -1071989969, 3716946, 2296397, 3965306, -87208, + 952468207, 588452222, 1016110510, -22347069, 3284915, 3956745, + -636927, -1182243, 841760171, 1013916752, -163212680, -302950022, + -3852015, 2635473, -1277625, -3073009, -987079667, 675340520, + -327391679, -787459213, -2772600, 1780227, 1455890, 1935420, + -710479343, 456183549, 373072124, 495951789, 59148, -2660408, + 2659525, -1753, 15156688, -681730119, 681503850, -449207, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer123456[] = { + -2283733, -585207070, 0, 0, -1858416, -476219497, + -3345963, -857403734, -2815639, -721508096, 0, 0, + -1853806, -475038184, -2917338, -747568486, 3585098, 918682129, + 0, 0, -3870317, -991769559, -556856, -142694469, + 642628, 164673562, 0, 0, -3192354, -818041395, + 2897314, 742437332, -1460718, -374309300, 0, 0, + 3950053, 1012201926, 1716988, 439978542, -2453983, -628833668, + 0, 0, 1935799, 496048908, -3756790, -962678241, + -1714295, -439288460, 0, 0, 3574466, 915957677, + 817536, 209493775, 3227876, 827143915, 0, 0, + -1759347, -450833045, -3415069, -875112161, 1335936, 342333886, + 0, 0, -2156050, -552488273, -3241972, -830756018, + -676590, -173376332, 0, 0, 4018989, 1029866791, + -2071829, -530906624, 434125, 111244624, 0, 0, + 3506380, 898510625, -1095468, -280713909, 3524442, 903139016, + 0, 0, -928749, -237992130, -394148, -101000509, + 1674615, 429120452, 0, 0, -1159875, -297218217, + -3704823, -949361686, -2663378, -682491182, 0, 0, + -2101410, -538486762, 3110818, 797147778, 4063053, 1041158200, + 0, 0, 3586446, 919027554, -2740543, -702264730, + 3370349, 863652652, 0, 0, -3182878, -815613168, + -3602218, -923069133, -294725, -75523344, -3761513, -963888510, + -3765607, -964937599, 3201430, 820367122, 3145678, 806080660, + 2883726, 738955404, 3201494, 820383522, 1221177, 312926867, + -557458, -142848732, 1005239, 257592709, -3764867, -964747974, + -2129892, -545785280, -2682288, -687336873, -3542485, -907762539, + 601683, 154181397, 0, 0, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_zetas) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h new file mode 100644 index 0000000000..e77f55014c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#define MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H + +#include +#include "../../../common.h" + +#define mld_aarch64_ntt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_ntt_zetas_layer123456) +#define mld_aarch64_ntt_zetas_layer78 MLD_NAMESPACE(aarch64_ntt_zetas_layer78) + +#define mld_aarch64_intt_zetas_layer78 MLD_NAMESPACE(aarch64_intt_zetas_layer78) +#define mld_aarch64_intt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_intt_zetas_layer123456) + +extern const int32_t mld_aarch64_ntt_zetas_layer123456[]; +extern const int32_t mld_aarch64_ntt_zetas_layer78[]; + +extern const int32_t mld_aarch64_intt_zetas_layer78[]; +extern const int32_t mld_aarch64_intt_zetas_layer123456[]; + +#define mld_rej_uniform_table MLD_NAMESPACE(rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[]; +#define mld_rej_uniform_eta_table MLD_NAMESPACE(rej_uniform_eta_table) +extern const uint8_t mld_rej_uniform_eta_table[]; + +#define mld_polyz_unpack_17_indices MLD_NAMESPACE(polyz_unpack_17_indices) +extern const uint8_t mld_polyz_unpack_17_indices[]; +#define mld_polyz_unpack_19_indices MLD_NAMESPACE(polyz_unpack_19_indices) +extern const uint8_t mld_polyz_unpack_19_indices[]; + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_ntt_asm MLD_NAMESPACE(ntt_asm) +void mld_ntt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_intt_asm MLD_NAMESPACE(intt_asm) +void mld_intt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_rej_uniform_asm MLD_NAMESPACE(rej_uniform_asm) +uint64_t mld_rej_uniform_asm(int32_t *r, const uint8_t *buf, unsigned buflen, + const uint8_t *table); + +#define mld_rej_uniform_eta2_asm MLD_NAMESPACE(rej_uniform_eta2_asm) +uint64_t mld_rej_uniform_eta2_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_rej_uniform_eta4_asm MLD_NAMESPACE(rej_uniform_eta4_asm) +uint64_t mld_rej_uniform_eta4_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_poly_decompose_32_asm MLD_NAMESPACE(poly_decompose_32_asm) +void mld_poly_decompose_32_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_asm MLD_NAMESPACE(poly_decompose_88_asm) +void mld_poly_decompose_88_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_asm MLD_NAMESPACE(poly_caddq_asm) +void mld_poly_caddq_asm(int32_t *a); + +#define mld_poly_use_hint_32_asm MLD_NAMESPACE(poly_use_hint_32_asm) +void mld_poly_use_hint_32_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_asm MLD_NAMESPACE(poly_use_hint_88_asm) +void mld_poly_use_hint_88_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_asm MLD_NAMESPACE(poly_chknorm_asm) +int mld_poly_chknorm_asm(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_asm MLD_NAMESPACE(polyz_unpack_17_asm) +void mld_polyz_unpack_17_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_polyz_unpack_19_asm MLD_NAMESPACE(polyz_unpack_19_asm) +void mld_polyz_unpack_19_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_poly_pointwise_montgomery_asm \ + MLD_NAMESPACE(poly_pointwise_montgomery_asm) +void mld_poly_pointwise_montgomery_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l4_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l4_asm) +void mld_polyvecl_pointwise_acc_montgomery_l4_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l5_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l5_asm) +void mld_polyvecl_pointwise_acc_montgomery_l5_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l7_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l7_asm) +void mld_polyvecl_pointwise_acc_montgomery_l7_asm(int32_t *, const int32_t *, + const int32_t *); + +#endif /* !MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c new file mode 100644 index 0000000000..7ef915b587 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* Table of indices used for tbl instructions in polyz_unpack_{17,19}. */ + +MLD_ALIGN const uint8_t mld_polyz_unpack_17_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, + 9, 10, 11, 255, 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, + 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, 8, 9, 10, 255, + 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, 17, 18, 19, 255, +}; + +MLD_ALIGN const uint8_t mld_polyz_unpack_19_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 5, 6, 7, 255, 7, 8, 9, 255, + 10, 11, 12, 255, 12, 13, 14, 255, 15, 16, 17, 255, 17, 18, 19, 255, + 4, 5, 6, 255, 6, 7, 8, 255, 9, 10, 11, 255, 11, 12, 13, 255, + 14, 15, 16, 255, 16, 17, 18, 255, 19, 20, 21, 255, 21, 22, 23, 255, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_polyz_unpack_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c new file mode 100644 index 0000000000..cf21509cbf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by 16-bit rejection sampling (rej_eta). + * Adapted from ML-KEM for ML-DSA eta rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_eta_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 2, 3, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 4, 5, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 2, 3, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 7 */, + 6, 7, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 2, 3, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 11 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 13 */, + 2, 3, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 15 */, + 8, 9, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 16 */, + 0, 1, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 17 */, + 2, 3, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 18 */, + 0, 1, 2, 3, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 19 */, + 4, 5, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 20 */, + 0, 1, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 21 */, + 2, 3, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 22 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 23 */, + 6, 7, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 24 */, + 0, 1, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 25 */, + 2, 3, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 26 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 27 */, + 4, 5, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 28 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 29 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 30 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 255, 255, 255, 255, 255, 255 /* 31 */, + 10, 11, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 32 */, + 0, 1, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 33 */, + 2, 3, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 34 */, + 0, 1, 2, 3, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 35 */, + 4, 5, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 36 */, + 0, 1, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 37 */, + 2, 3, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 38 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 39 */, + 6, 7, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 40 */, + 0, 1, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 41 */, + 2, 3, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 42 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 43 */, + 4, 5, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 44 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 45 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 46 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 255, 255, 255, 255, 255, 255 /* 47 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 48 */, + 0, 1, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 49 */, + 2, 3, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 50 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 51 */, + 4, 5, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 52 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 53 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 54 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 55 */, + 6, 7, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 56 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 57 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 58 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 59 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 60 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 61 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 62 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 63 */, + 12, 13, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 64 */, + 0, 1, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 65 */, + 2, 3, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 66 */, + 0, 1, 2, 3, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 67 */, + 4, 5, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 68 */, + 0, 1, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 69 */, + 2, 3, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 70 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 71 */, + 6, 7, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 72 */, + 0, 1, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 73 */, + 2, 3, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 74 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 75 */, + 4, 5, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 76 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 77 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 78 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 255, 255, 255, 255, 255, 255 /* 79 */, + 8, 9, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 80 */, + 0, 1, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 81 */, + 2, 3, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 82 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 83 */, + 4, 5, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 84 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 85 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 86 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 87 */, + 6, 7, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 88 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 89 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 90 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 91 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 92 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 93 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 94 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 255, 255, 255, 255 /* 95 */, + 10, 11, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 96 */, + 0, 1, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 97 */, + 2, 3, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 98 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 99 */, + 4, 5, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 100 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 101 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 102 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 103 */, + 6, 7, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 104 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 105 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 106 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 107 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 108 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 109 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 110 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 255, 255, 255, 255 /* 111 */, + 8, 9, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 112 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 113 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 114 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 115 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 116 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 117 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 118 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 119 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 120 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 121 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 122 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 123 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 124 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 125 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 126 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 255, 255 /* 127 */, + 14, 15, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 128 */, + 0, 1, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 129 */, + 2, 3, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 130 */, + 0, 1, 2, 3, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 131 */, + 4, 5, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 132 */, + 0, 1, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 133 */, + 2, 3, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 134 */, + 0, 1, 2, 3, 4, 5, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 135 */, + 6, 7, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 136 */, + 0, 1, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 137 */, + 2, 3, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 138 */, + 0, 1, 2, 3, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 139 */, + 4, 5, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 140 */, + 0, 1, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 141 */, + 2, 3, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 142 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 14, 15, 255, 255, 255, 255, 255, 255 /* 143 */, + 8, 9, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 144 */, + 0, 1, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 145 */, + 2, 3, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 146 */, + 0, 1, 2, 3, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 147 */, + 4, 5, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 148 */, + 0, 1, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 149 */, + 2, 3, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 150 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 151 */, + 6, 7, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 152 */, + 0, 1, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 153 */, + 2, 3, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 154 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 155 */, + 4, 5, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 156 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 157 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 158 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 14, 15, 255, 255, 255, 255 /* 159 */, + 10, 11, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 160 */, + 0, 1, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 161 */, + 2, 3, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 162 */, + 0, 1, 2, 3, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 163 */, + 4, 5, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 164 */, + 0, 1, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 165 */, + 2, 3, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 166 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 167 */, + 6, 7, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 168 */, + 0, 1, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 169 */, + 2, 3, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 170 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 171 */, + 4, 5, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 172 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 173 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 174 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 14, 15, 255, 255, 255, 255 /* 175 */, + 8, 9, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 176 */, + 0, 1, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 177 */, + 2, 3, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 178 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 179 */, + 4, 5, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 180 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 181 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 182 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 183 */, + 6, 7, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 184 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 185 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 186 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 187 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 188 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 189 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 190 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 14, 15, 255, 255 /* 191 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 192 */, + 0, 1, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 193 */, + 2, 3, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 194 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 195 */, + 4, 5, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 196 */, + 0, 1, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 197 */, + 2, 3, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 198 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 199 */, + 6, 7, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 200 */, + 0, 1, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 201 */, + 2, 3, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 202 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 203 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 204 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 205 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 206 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 207 */, + 8, 9, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 208 */, + 0, 1, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 209 */, + 2, 3, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 210 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 211 */, + 4, 5, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 212 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 213 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 214 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 215 */, + 6, 7, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 216 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 217 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 218 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 219 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 220 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 221 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 222 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 14, 15, 255, 255 /* 223 */, + 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 224 */, + 0, 1, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 225 */, + 2, 3, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 226 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 227 */, + 4, 5, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 228 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 229 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 230 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 231 */, + 6, 7, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 232 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 233 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 234 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 235 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 236 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 237 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 238 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 14, 15, 255, 255 /* 239 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 240 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 241 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 242 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 243 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 244 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 245 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 246 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 247 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 248 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 249 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 250 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 251 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 252 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 253 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 254 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 255 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_eta_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/src/rej_uniform_table.c new file mode 100644 index 0000000000..65bc3b78d3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/aarch64/src/rej_uniform_table.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by rejection sampling of the public matrix. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 7 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 11 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 13 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 15 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/api.h new file mode 100644 index 0000000000..0f1fdeb168 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/api.h @@ -0,0 +1,594 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_API_H +#define MLD_NATIVE_API_H +/* + * Native arithmetic interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + * + * To ensure consistency with backends, the header will be + * included automatically after inclusion of the active + * backend, to ensure consistency of function signatures, + * and run sanity checks. + */ + +#include +#include "../cbmc.h" +#include "../common.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* Bound on absolute value of coefficients after NTT. + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) + +/* Absolute exclusive upper bound for the output of the inverse NTT + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_INTT_BOUND MLDSA_Q + +/* Absolute bound for range of mld_reduce32() + * + * NOTE: This is the same bound as in reduce.h and has to be kept + * in sync. */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define REDUCE32_RANGE_MAX 6283009 +/* + * This is the C<->native interface allowing for the drop-in of + * native code for performance critical arithmetic components of ML-DSA. + * + * A _backend_ is a specific implementation of (part of) this interface. + * + * To add a function to a backend, define MLD_USE_NATIVE_XXX and + * implement `static inline xxx(...)` in the profile header. + */ + +/* + * Those functions are meant to be trivial wrappers around the chosen native + * implementation. The are static inline to avoid unnecessary calls. + * The macro before each declaration controls whether a native + * implementation is present. + */ + +#if defined(MLD_USE_NATIVE_NTT) +/************************************************* + * Name: mld_ntt_native + * + * Description: Computes negacyclic number-theoretic transform (NTT) of + * a polynomial in place. + * + * The input polynomial is assumed to be in normal order. + * The output polynomial is in bitreversed order. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_ntt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_NTT */ + + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) +/* + * This must only be set if NTT and INTT have native implementations + * that are adapted to the custom order. + */ +#if !defined(MLD_USE_NATIVE_NTT) || !defined(MLD_USE_NATIVE_INTT) +#error \ + "Invalid native profile: MLD_USE_NATIVE_NTT_CUSTOM_ORDER can only be \ +set if there are native implementations for NTT and INTT." +#endif + +/************************************************* + * Name: mlD_poly_permute_bitrev_to_custom + * + * Description: When MLD_USE_NATIVE_NTT_CUSTOM_ORDER is defined, + * convert a polynomial in NTT domain from bitreversed + * order to the custom order output by the native NTT. + * + * This must only be defined if there is native code for + * both the NTT and INTT. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + * + **************************************************/ +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t p[MLDSA_N]) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q))); +#endif /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + + +#if defined(MLD_USE_NATIVE_INTT) +/************************************************* + * Name: mld_intt_native + * + * Description: Computes inverse of negacyclic number-theoretic transform + *(NTT) of a polynomial in place. + * + * The input polynomial is in bitreversed order. + * The output polynomial is assumed to be in normal order. + * + * Arguments: - uint32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_intt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_INTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_INTT */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) +/************************************************* + * Name: mld_rej_uniform_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [0, MLDSA_Q-1] + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform mod q). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + * lengths. Otherwise, returns non-negative number of sampled 32-bit integers + * (at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= ( 5 * 168) && buflen % 3 == 0) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(r, 0, (unsigned) return_value, 0, MLDSA_Q)) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) +/************************************************* + * Name: mld_rej_uniform_eta2_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-2,+2]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-2, +2]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA2 */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) +/************************************************* + * Name: mld_rej_uniform_eta4_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-4,+4]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-4, +4]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) +/************************************************* + * Name: mld_poly_decompose_32_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/32. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: input/output polynomial. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_32 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) +/************************************************* + * Name: mld_poly_decompose_88_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/88. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: output polynomial with coefficients c0. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CADDQ) +/************************************************* + * Name: mld_poly_caddq_native + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *a: pointer to input/output polynomial + **************************************************/ +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_32) +/************************************************* + * Name: mld_poly_use_hint_32_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/32. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_32 */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) +/************************************************* + * Name: mld_poly_use_hint_88_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/88. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) +/************************************************* + * Name: mld_poly_chknorm_native + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const int32_t *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if the infinity norm is strictly smaller than B, and 1 + * otherwise. B must not be larger than MLDSA_Q - MLD_REDUCE32_RANGE_MAX. + **************************************************/ +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(0 <= B && B <= MLDSA_Q - REDUCE32_RANGE_MAX) + requires(array_bound(a, 0, MLDSA_N, -REDUCE32_RANGE_MAX, REDUCE32_RANGE_MAX)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == 0) == array_abs_bound(a, 0, MLDSA_N, B)) +); +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) +/************************************************* + * Name: mld_polyz_unpack_17_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^17. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_17 */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) +/************************************************* + * Name: mld_polyz_unpack_19_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^19. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_19 */ + +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) +/************************************************* + * Name: mld_poly_pointwise_montgomery_native + * + * Description: Pointwise multiplication of polynomials in NTT domain + * with Montgomery reduction. + * + * Computes c[i] = a[i] * b[i] * R^(-1) mod q for all i, + * where R = 2^32. + * + * Arguments: - int32_t c[MLDSA_N]: output polynomial + * - const int32_t a[MLDSA_N]: first input polynomial + * - const int32_t b[MLDSA_N]: second input polynomial + **************************************************/ +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(c, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(c, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(c, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l4_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 4. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 4 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 4 * MLDSA_N)) + requires(forall(l0, 0, 4, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 4, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l5_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 5. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 5 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 5 * MLDSA_N)) + requires(forall(l0, 0, 5, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 5, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l7_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 7. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 7 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 7 * MLDSA_N)) + requires(forall(l0, 0, 7, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 7, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 */ + +#endif /* !MLD_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/meta.h new file mode 100644 index 0000000000..0b46dd5791 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/meta.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_META_H +#define MLD_NATIVE_META_H + +/* + * Default arithmetic backend + */ +#include "../sys.h" + +#ifdef MLD_SYS_AARCH64 +#include "aarch64/meta.h" +#endif + +#ifdef MLD_SYS_X86_64_AVX2 +#include "x86_64/meta.h" +#endif + +#endif /* !MLD_NATIVE_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/meta.h new file mode 100644 index 0000000000..393374c06f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/meta.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_X86_64_META_H +#define MLD_NATIVE_X86_64_META_H + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_X86_64_DEFAULT + +#define MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +#if !defined(__ASSEMBLER__) +#include +#include "../../common.h" +#include "../api.h" +#include "src/arith_native_x86_64.h" + +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t data[MLDSA_N]) +{ + if (mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + mld_nttunpack_avx2(data); + } +} + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_ntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_invntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)mld_rej_uniform_avx2(r, buf); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_32_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_88_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_caddq_avx2(a); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_32_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_88_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + return mld_poly_chknorm_avx2(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_17_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_19_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_avx2(c, a, b, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l4_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l5_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l7_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_NATIVE_X86_64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h new file mode 100644 index 0000000000..08d5abf74a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#define MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#include "../../../common.h" + +#include +#include "consts.h" + +#define MLD_AVX2_REJ_UNIFORM_BUFLEN \ + (5 * 168) /* REJ_UNIFORM_NBLOCKS * SHAKE128_RATE */ + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) + +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_rej_uniform_table MLD_NAMESPACE(mld_rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[256][8]; + +#define mld_ntt_avx2 MLD_NAMESPACE(ntt_avx2) +void mld_ntt_avx2(int32_t *r, const int32_t *qdata) +/* This must be kept in sync with the HOL-Light specification + * in proofs/hol_light/x86_64/proofs/mldsa_ntt.ml */ +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, MLDSA_N, 8380417)) + requires(qdata == mld_qdata) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + /* check-magic: off */ + ensures(array_abs_bound(r, 0, MLDSA_N, 42035262)) + /* check-magic: on */ +); + +#define mld_invntt_avx2 MLD_NAMESPACE(invntt_avx2) +void mld_invntt_avx2(int32_t *r, const int32_t *mld_qdata); + +#define mld_nttunpack_avx2 MLD_NAMESPACE(nttunpack_avx2) +void mld_nttunpack_avx2(int32_t *r); + +#define mld_rej_uniform_avx2 MLD_NAMESPACE(mld_rej_uniform_avx2) +unsigned mld_rej_uniform_avx2(int32_t *r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]); + +#define mld_rej_uniform_eta2_avx2 MLD_NAMESPACE(mld_rej_uniform_eta2_avx2) +unsigned mld_rej_uniform_eta2_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]); + +#define mld_rej_uniform_eta4_avx2 MLD_NAMESPACE(mld_rej_uniform_eta4_avx2) +unsigned mld_rej_uniform_eta4_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]); + +#define mld_poly_decompose_32_avx2 MLD_NAMESPACE(mld_poly_decompose_32_avx2) +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_avx2 MLD_NAMESPACE(mld_poly_decompose_88_avx2) +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_avx2 MLD_NAMESPACE(poly_caddq_avx2) +void mld_poly_caddq_avx2(int32_t *r); + +#define mld_poly_use_hint_32_avx2 MLD_NAMESPACE(mld_poly_use_hint_32_avx2) +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_avx2 MLD_NAMESPACE(mld_poly_use_hint_88_avx2) +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_avx2 MLD_NAMESPACE(mld_poly_chknorm_avx2) +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_avx2 MLD_NAMESPACE(mld_polyz_unpack_17_avx2) +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a); + +#define mld_polyz_unpack_19_avx2 MLD_NAMESPACE(mld_polyz_unpack_19_avx2) +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a); + +#define mld_pointwise_avx2 MLD_NAMESPACE(pointwise_avx2) +void mld_pointwise_avx2(int32_t *c, const int32_t *a, const int32_t *b, + const int32_t *qdata); + +#define mld_pointwise_acc_l4_avx2 MLD_NAMESPACE(pointwise_acc_l4_avx2) +void mld_pointwise_acc_l4_avx2(int32_t c[MLDSA_N], const int32_t a[4][MLDSA_N], + const int32_t b[4][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l5_avx2 MLD_NAMESPACE(pointwise_acc_l5_avx2) +void mld_pointwise_acc_l5_avx2(int32_t c[MLDSA_N], const int32_t a[5][MLDSA_N], + const int32_t b[5][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l7_avx2 MLD_NAMESPACE(pointwise_acc_l7_avx2) +void mld_pointwise_acc_l7_avx2(int32_t c[MLDSA_N], const int32_t a[7][MLDSA_N], + const int32_t b[7][MLDSA_N], + const int32_t *qdata); + +#endif /* !MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/consts.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/consts.c new file mode 100644 index 0000000000..aaca3535ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/consts.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include "consts.h" + +/* + * Table of zeta values used in the AVX2 forward and inverse NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_qdata[624] = { + 8380417, 8380417, 8380417, 8380417, 8380417, + 8380417, 8380417, 8380417, 58728449, 58728449, + 58728449, 58728449, 58728449, 58728449, 58728449, + 58728449, -8395782, -8395782, -8395782, -8395782, + -8395782, -8395782, -8395782, -8395782, 41978, + 41978, 41978, 41978, 41978, 41978, + 41978, 41978, -151046689, 1830765815, -1929875198, + -1927777021, 1640767044, 1477910808, 1612161320, 1640734244, + 308362795, 308362795, 308362795, 308362795, -1815525077, + -1815525077, -1815525077, -1815525077, -1374673747, -1374673747, + -1374673747, -1374673747, -1091570561, -1091570561, -1091570561, + -1091570561, -1929495947, -1929495947, -1929495947, -1929495947, + 515185417, 515185417, 515185417, 515185417, -285697463, + -285697463, -285697463, -285697463, 625853735, 625853735, + 625853735, 625853735, 1727305304, 1727305304, 2082316400, + 2082316400, -1364982364, -1364982364, 858240904, 858240904, + 1806278032, 1806278032, 222489248, 222489248, -346752664, + -346752664, 684667771, 684667771, 1654287830, 1654287830, + -878576921, -878576921, -1257667337, -1257667337, -748618600, + -748618600, 329347125, 329347125, 1837364258, 1837364258, + -1443016191, -1443016191, -1170414139, -1170414139, -1846138265, + -1631226336, -1404529459, 1838055109, 1594295555, -1076973524, + -1898723372, -594436433, -202001019, -475984260, -561427818, + 1797021249, -1061813248, 2059733581, -1661512036, -1104976547, + -1750224323, -901666090, 418987550, 1831915353, -1925356481, + 992097815, 879957084, 2024403852, 1484874664, -1636082790, + -285388938, -1983539117, -1495136972, -950076368, -1714807468, + -952438995, -1574918427, 1350681039, -2143979939, 1599739335, + -1285853323, -993005454, -1440787840, 568627424, -783134478, + -588790216, 289871779, -1262003603, 2135294594, -1018755525, + -889861155, 1665705315, 1321868265, 1225434135, -1784632064, + 666258756, 675310538, -1555941048, -1999506068, -1499481951, + -695180180, -1375177022, 1777179795, 334803717, -178766299, + -518252220, 1957047970, 1146323031, -654783359, -1974159335, + 1651689966, 140455867, -1039411342, 1955560694, 1529189038, + -2131021878, -247357819, 1518161567, -86965173, 1708872713, + 1787797779, 1638590967, -120646188, -1669960606, -916321552, + 1155548552, 2143745726, 1210558298, -1261461890, -318346816, + 628664287, -1729304568, 1422575624, 1424130038, -1185330464, + 235321234, 168022240, 1206536194, 985155484, -894060583, + -898413, -1363460238, -605900043, 2027833504, 14253662, + 1014493059, 863641633, 1819892093, 2124962073, -1223601433, + -1920467227, -1637785316, -1536588520, 694382729, 235104446, + -1045062172, 831969619, -300448763, 756955444, -260312805, + 1554794072, 1339088280, -2040058690, -853476187, -2047270596, + -1723816713, -1591599803, -440824168, 1119856484, 1544891539, + 155290192, -973777462, 991903578, 912367099, -44694137, + 1176904444, -421552614, -818371958, 1747917558, -325927722, + 908452108, 1851023419, -1176751719, -1354528380, -72690498, + -314284737, 985022747, 963438279, -1078959975, 604552167, + -1021949428, 608791570, 173440395, -2126092136, -1316619236, + -1039370342, 6087993, -110126092, 565464272, -1758099917, + -1600929361, 879867909, -1809756372, 400711272, 1363007700, + 30313375, -326425360, 1683520342, -517299994, 2027935492, + -1372618620, 128353682, -1123881663, 137583815, -635454918, + -642772911, 45766801, 671509323, -2070602178, 419615363, + 1216882040, -270590488, -1276805128, 371462360, -1357098057, + -384158533, 827959816, -596344473, 702390549, -279505433, + -260424530, -71875110, -1208667171, -1499603926, 2036925262, + -540420426, 746144248, -1420958686, 2032221021, 1904936414, + 1257750362, 1926727420, 1931587462, 1258381762, 885133339, + 1629985060, 1967222129, 6363718, -1287922800, 1136965286, + 1779436847, 1116720494, 1042326957, 1405999311, 713994583, + 940195359, -1542497137, 2061661095, -883155599, 1726753853, + -1547952704, 394851342, 283780712, 776003547, 1123958025, + 201262505, 1934038751, 374860238, -3975713, 25847, + -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 1826347, 1826347, 1826347, + 2353451, 2353451, 2353451, 2353451, -359251, + -359251, -359251, -359251, -2091905, -2091905, + -2091905, -2091905, 3119733, 3119733, 3119733, + 3119733, -2884855, -2884855, -2884855, -2884855, + 3111497, 3111497, 3111497, 3111497, 2680103, + 2680103, 2680103, 2680103, 2725464, 2725464, + 1024112, 1024112, -1079900, -1079900, 3585928, + 3585928, -549488, -549488, -1119584, -1119584, + 2619752, 2619752, -2108549, -2108549, -2118186, + -2118186, -3859737, -3859737, -1399561, -1399561, + -3277672, -3277672, 1757237, 1757237, -19422, + -19422, 4010497, 4010497, 280005, 280005, + 2706023, 95776, 3077325, 3530437, -1661693, + -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, + -539299, -1699267, -1643818, 3505694, -3821735, + 3507263, -2140649, -1600420, 3699596, 811944, + 531354, 954230, 3881043, 3900724, -2556880, + 2071892, -2797779, -3930395, -3677745, -1452451, + 2176455, -1257611, -4083598, -3190144, -3632928, + 3412210, 2147896, -2967645, -411027, -671102, + -22981, -381987, 1852771, -3343383, 508951, + 44288, 904516, -3724342, 1653064, 2389356, + 759969, 189548, 3159746, -2409325, 1315589, + 1285669, -812732, -3019102, -3628969, -1528703, + -3041255, 3475950, -1585221, 1939314, -1000202, + -3157330, 126922, -983419, 2715295, -3693493, + -2477047, -1228525, -1308169, 1349076, -1430430, + 264944, 3097992, -1100098, 3958618, -8578, + -3249728, -210977, -1316856, -3553272, -1851402, + -177440, 1341330, -1584928, -1439742, -3881060, + 3839961, 2091667, -3342478, 266997, -3520352, + 900702, 495491, -655327, -3556995, 342297, + 3437287, 2842341, 4055324, -3767016, -2994039, + -1333058, -451100, -1279661, 1500165, -542412, + -2584293, -2013608, 1957272, -3183426, 810149, + -3038916, 2213111, -426683, -1667432, -2939036, + 183443, -554416, 3937738, 3407706, 2244091, + 2434439, -3759364, 1859098, -1613174, -3122442, + -525098, 286988, -3342277, 2691481, 1247620, + 1250494, 1869119, 1237275, 1312455, 1917081, + 777191, -2831860, -3724270, 2432395, 3369112, + 162844, 1652634, 3523897, -975884, 1723600, + -1104333, -2235985, -976891, 3919660, 1400424, + 2316500, -2446433, -1235728, -1197226, 909542, + -43260, 2031748, -768622, -2437823, 1735879, + -2590150, 2486353, 2635921, 1903435, -3318210, + 3306115, -2546312, 2235880, -1671176, 594136, + 2454455, 185531, 1616392, -3694233, 3866901, + 1717735, -1803090, -260646, -420899, 1612842, + -48306, -846154, 3817976, -3562462, 3513181, + -3193378, 819034, -522500, 3207046, -3595838, + 4108315, 203044, 1265009, 1595974, -3548272, + -1050970, -1430225, -1962642, -1374803, 3406031, + -1846953, -3776993, -164721, -1207385, 3014001, + -1799107, 269760, 472078, 1910376, -3833893, + -2286327, -3545687, -1362209, 1976782, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_consts) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/consts.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/consts.h new file mode 100644 index 0000000000..7fe08f454b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/consts.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#ifndef MLD_NATIVE_X86_64_SRC_CONSTS_H +#define MLD_NATIVE_X86_64_SRC_CONSTS_H +#include "../../../common.h" +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQ 0 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV 8 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV 16 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV 24 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV 32 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS 328 + +#ifndef __ASSEMBLER__ +#define mld_qdata MLD_NAMESPACE(qdata) +extern const int32_t mld_qdata[624]; +#endif + +#endif /* !MLD_NATIVE_X86_64_SRC_CONSTS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c new file mode 100644 index 0000000000..05d86d14fc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/************************************************* + * Name: mld_poly_caddq_avx2 + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *r: pointer to input/output polynomial + **************************************************/ +void mld_poly_caddq_avx2(int32_t *r) +{ + unsigned int i; + __m256i f, g; + const __m256i q = _mm256_set1_epi32(MLDSA_Q); + const __m256i zero = _mm256_setzero_si256(); + __m256i *rr = (__m256i *)r; + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256(&rr[i]); + g = _mm256_cmpgt_epi32(zero, f); + g = _mm256_and_si256(g, q); + f = _mm256_add_epi32(f, g); + _mm256_store_si256(&rr[i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_reduce) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c new file mode 100644 index 0000000000..50e2c7fa9b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B) +{ + unsigned int i; + __m256i f, t; + const __m256i bound = _mm256_set1_epi32(B - 1); + + t = _mm256_setzero_si256(); + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + f = _mm256_abs_epi32(f); + f = _mm256_cmpgt_epi32(f, bound); + t = _mm256_or_si256(t, f); + } + + return 1 - _mm256_testz_si256(t, t); +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_chknorm) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c new file mode 100644 index 0000000000..76846bf1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(31 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 4092 == intdiv(2 * intdiv(MLDSA_Q - 1, 32), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 4092. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 32*GAMMA2 = 16*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 16B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + * + * round(f1' * 1025 / 2^22) is in turn computed in 2 steps as + * round(floor(f1' * 1025 / 2^16) / 2^6). The mulhi computes f1'' = + * floor(f1' * 1025 / 2^16). As for the next step f1 = round(f1'' / 2^6), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^9) = round(f1'' * 2^9 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 1025 / 2^16) = 1025 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(16B / B) = 16 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 16, i.e. f > 31*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 31*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 15, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c new file mode 100644 index 0000000000..463506b962 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ + +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 1488 == intdiv(2 * intdiv(MLDSA_Q - 1, 88), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 1488. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 88*GAMMA2 = 44*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 44B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + * + * round(f1' * 11275 / 2^24) is in turn computed in 2 steps as + * round(floor(f1' * 11275 / 2^16) / 2^8). The mulhi computes f1'' = + * floor(f1' * 11275 / 2^16). As for the next step f1 = round(f1'' / 2^8), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^7) = round(f1'' * 2^7 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 11275 / 2^16) = 11275 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(44B / B) = 44 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 44, i.e. f > 87*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 87*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 43, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c new file mode 100644 index 0000000000..0094bc93a9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + const __m256i mask = _mm256_set1_epi32(15); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_32_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 16 */ + f1 = _mm256_add_epi32(f1, h); + f1 = _mm256_and_si256(f1, mask); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c new file mode 100644 index 0000000000..b109ab6351 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + const __m256i max = _mm256_set1_epi32(43); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_88_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 44 */ + f1 = _mm256_add_epi32(f1, h); + f1 = MLD_MM256_BLENDV_EPI32(f1, max, f1); + f = _mm256_cmpgt_epi32(f1, max); + f1 = MLD_MM256_BLENDV_EPI32(f1, zero, f); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c new file mode 100644 index 0000000000..f6c08a832f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 27, 26, 25, -1, 25, 24, 23, -1, 8, 7, + 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0); + const __m256i srlvdidx = _mm256_set_epi32(6, 4, 2, 0, 6, 4, 2, 0); + const __m256i mask = _mm256_set1_epi32(0x3FFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 17)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[18 * i]); + /* Load bytes 2..17 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[18 * i + 2]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-8 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 8, 7, 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte8, byte7, byte6, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,27, 26, 25, -1,25, 24, 23] │ + * │ Result: [0, byte17, byte16, byte15, ..., 0, byte11, byte10, byte9] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 18 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 32..55 48..71 + * 72..95 88..111 104..127 120..143 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 18..39 36..55 54..71 + * 72..95 90..111 108..127 126..143 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..17 18..35 36..53 54..71 + * 72..89 90..107 108..125 126..143 */ + + /* Map [0, 1, ..., 2^18-1] to [2^17, 2^17-1, ..., -2^17+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_17) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c new file mode 100644 index 0000000000..4a5ce48f38 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 26, 25, 24, -1, 24, 23, 22, -1, 9, 8, + 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0); + /* Equivalent to _mm256_set_epi32(4, 0, 4, 0, 4, 0, 4, 0) */ + const __m256i srlvdidx = _mm256_set1_epi64x((uint64_t)4 << 32); + const __m256i mask = _mm256_set1_epi32(0xFFFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 19)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[20 * i]); + /* Load bytes 4..19 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[20 * i + 4]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-9 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 9, 8, 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte9, byte8, byte7, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,26, 25, 24, -1,24, 23, 22] │ + * │ Result: [0, byte19, byte18, byte17, ..., 0, byte12, byte11, byte10] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 20 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 40..63 56..79 + * 80..103 96..119 120..143 136..159 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 20..39 40..63 60..79 + * 80..103 100..119 120..143 140..159 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..19 20..39 40..59 60..79 + * 80..99 100..119 120..139 140..159 */ + + /* Map [0, 1, ..., 2^20-1] to [2^19, 2^19-1, ..., -2^19+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_19) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c new file mode 100644 index 0000000000..07a5df9706 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The pqcrystals implementation assumes a buffer that is 8 bytes + *. larger as the first loop overreads by 8 bytes that are then + * discarded. We instead do not pad the buffer and do not overread. + * The performance impact is negligible and it does not force the + * frontend to perform the unintuitive padding. + */ + +unsigned int mld_rej_uniform_avx2( + int32_t *MLD_RESTRICT r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i d, tmp; + const __m256i bound = _mm256_set1_epi32(MLDSA_Q); + const __m256i mask = _mm256_set1_epi32(0x7FFFFF); + const __m256i idx8 = + _mm256_set_epi8(-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4, + -1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 32) + { + d = _mm256_loadu_si256((__m256i *)&buf[pos]); + + /* Permute 64-bit lanes + * 0x94 = 10010100b rearranges 64-bit lanes as: [3,2,1,0] -> [2,1,1,0] + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Original Layout ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ bytes 16..23 │ bytes 24..31 │ + * └─────────────────┴─────────────────┴─────────────────┴─────────────────┘ + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Layout after permute ║ + * ║ Byte indices in high half shifted down by 8 positions ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌───────────────┬─────────────────┐ ┌─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ │ bytes 8..15 │ bytes 16..23 │ + * └───────────────┴─────────────────┘ └─────────────────┴─────────────────┘ + * Lower 128-bit lane (bytes 0-15) Upper 128-bit lane (bytes 16-31) + */ + d = _mm256_permute4x64_epi64(d, 0x94); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-11 into low 128-bit half of permuted vector────────────────┐ + * │ Shuffle: [-1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0] │ + * │ Result: [0, byte11, byte10, byte9, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 4-15 into high 128-bit half of permuted vector ──────────────┐ + * │ Shuffle: [-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4] │ + * │ Result: [0, byte23, byte22, byte21, ..., 0, byte14, byte13, byte12 │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + d = _mm256_shuffle_epi8(d, idx8); + d = _mm256_and_si256(d, mask); + pos += 24; + + tmp = _mm256_sub_epi32(d, bound); + good = (uint32_t)_mm256_movemask_ps((__m256)tmp); + tmp = _mm256_cvtepu8_epi32( + _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good])); + d = _mm256_permutevar8x32_epi32(d, tmp); + + _mm256_storeu_si256((__m256i *)&r[ctr], d); + ctr += (unsigned)_mm_popcnt_u32(good); + } + + while (ctr < MLDSA_N && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 3) + { + uint32_t t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + /* Safe because t < MLDSA_Q. */ + r[ctr++] = (int32_t)t; + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c new file mode 100644 index 0000000000..70c5c42c70 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA2 2 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ +unsigned int mld_rej_uniform_eta2_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1, f2; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA2); + const __m256i bound = mask; + /* check-magic: -6560 == 32*round(-2**10 / 5) */ + const __m256i v = _mm256_set1_epi32(-6560); + const __m256i p = _mm256_set1_epi32(5); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 15) + { + t0 = t0 - (205 * t0 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t0); + } + if (t1 < 15 && ctr < MLDSA_N) + { + t1 = t1 - (205 * t1 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta2) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA2 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c new file mode 100644 index 0000000000..ba00e91252 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA4 4 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ + +unsigned int mld_rej_uniform_eta4_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA4); + const __m256i bound = _mm256_set1_epi8(9); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 9) + { + r[ctr++] = (int32_t)(4 - t0); + } + if (t1 < 9 && ctr < MLDSA_N) + { + r[ctr++] = (int32_t)(4 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta4) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA4 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/rej_uniform_table.c new file mode 100644 index 0000000000..6c537b4542 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/native/x86_64/src/rej_uniform_table.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" + +/* + * Lookup table used by rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[256][8] = { + {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, + {2, 0, 0, 0, 0, 0, 0, 0}, {0, 2, 0, 0, 0, 0, 0, 0}, + {1, 2, 0, 0, 0, 0, 0, 0}, {0, 1, 2, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 0, 0}, {0, 3, 0, 0, 0, 0, 0, 0}, + {1, 3, 0, 0, 0, 0, 0, 0}, {0, 1, 3, 0, 0, 0, 0, 0}, + {2, 3, 0, 0, 0, 0, 0, 0}, {0, 2, 3, 0, 0, 0, 0, 0}, + {1, 2, 3, 0, 0, 0, 0, 0}, {0, 1, 2, 3, 0, 0, 0, 0}, + {4, 0, 0, 0, 0, 0, 0, 0}, {0, 4, 0, 0, 0, 0, 0, 0}, + {1, 4, 0, 0, 0, 0, 0, 0}, {0, 1, 4, 0, 0, 0, 0, 0}, + {2, 4, 0, 0, 0, 0, 0, 0}, {0, 2, 4, 0, 0, 0, 0, 0}, + {1, 2, 4, 0, 0, 0, 0, 0}, {0, 1, 2, 4, 0, 0, 0, 0}, + {3, 4, 0, 0, 0, 0, 0, 0}, {0, 3, 4, 0, 0, 0, 0, 0}, + {1, 3, 4, 0, 0, 0, 0, 0}, {0, 1, 3, 4, 0, 0, 0, 0}, + {2, 3, 4, 0, 0, 0, 0, 0}, {0, 2, 3, 4, 0, 0, 0, 0}, + {1, 2, 3, 4, 0, 0, 0, 0}, {0, 1, 2, 3, 4, 0, 0, 0}, + {5, 0, 0, 0, 0, 0, 0, 0}, {0, 5, 0, 0, 0, 0, 0, 0}, + {1, 5, 0, 0, 0, 0, 0, 0}, {0, 1, 5, 0, 0, 0, 0, 0}, + {2, 5, 0, 0, 0, 0, 0, 0}, {0, 2, 5, 0, 0, 0, 0, 0}, + {1, 2, 5, 0, 0, 0, 0, 0}, {0, 1, 2, 5, 0, 0, 0, 0}, + {3, 5, 0, 0, 0, 0, 0, 0}, {0, 3, 5, 0, 0, 0, 0, 0}, + {1, 3, 5, 0, 0, 0, 0, 0}, {0, 1, 3, 5, 0, 0, 0, 0}, + {2, 3, 5, 0, 0, 0, 0, 0}, {0, 2, 3, 5, 0, 0, 0, 0}, + {1, 2, 3, 5, 0, 0, 0, 0}, {0, 1, 2, 3, 5, 0, 0, 0}, + {4, 5, 0, 0, 0, 0, 0, 0}, {0, 4, 5, 0, 0, 0, 0, 0}, + {1, 4, 5, 0, 0, 0, 0, 0}, {0, 1, 4, 5, 0, 0, 0, 0}, + {2, 4, 5, 0, 0, 0, 0, 0}, {0, 2, 4, 5, 0, 0, 0, 0}, + {1, 2, 4, 5, 0, 0, 0, 0}, {0, 1, 2, 4, 5, 0, 0, 0}, + {3, 4, 5, 0, 0, 0, 0, 0}, {0, 3, 4, 5, 0, 0, 0, 0}, + {1, 3, 4, 5, 0, 0, 0, 0}, {0, 1, 3, 4, 5, 0, 0, 0}, + {2, 3, 4, 5, 0, 0, 0, 0}, {0, 2, 3, 4, 5, 0, 0, 0}, + {1, 2, 3, 4, 5, 0, 0, 0}, {0, 1, 2, 3, 4, 5, 0, 0}, + {6, 0, 0, 0, 0, 0, 0, 0}, {0, 6, 0, 0, 0, 0, 0, 0}, + {1, 6, 0, 0, 0, 0, 0, 0}, {0, 1, 6, 0, 0, 0, 0, 0}, + {2, 6, 0, 0, 0, 0, 0, 0}, {0, 2, 6, 0, 0, 0, 0, 0}, + {1, 2, 6, 0, 0, 0, 0, 0}, {0, 1, 2, 6, 0, 0, 0, 0}, + {3, 6, 0, 0, 0, 0, 0, 0}, {0, 3, 6, 0, 0, 0, 0, 0}, + {1, 3, 6, 0, 0, 0, 0, 0}, {0, 1, 3, 6, 0, 0, 0, 0}, + {2, 3, 6, 0, 0, 0, 0, 0}, {0, 2, 3, 6, 0, 0, 0, 0}, + {1, 2, 3, 6, 0, 0, 0, 0}, {0, 1, 2, 3, 6, 0, 0, 0}, + {4, 6, 0, 0, 0, 0, 0, 0}, {0, 4, 6, 0, 0, 0, 0, 0}, + {1, 4, 6, 0, 0, 0, 0, 0}, {0, 1, 4, 6, 0, 0, 0, 0}, + {2, 4, 6, 0, 0, 0, 0, 0}, {0, 2, 4, 6, 0, 0, 0, 0}, + {1, 2, 4, 6, 0, 0, 0, 0}, {0, 1, 2, 4, 6, 0, 0, 0}, + {3, 4, 6, 0, 0, 0, 0, 0}, {0, 3, 4, 6, 0, 0, 0, 0}, + {1, 3, 4, 6, 0, 0, 0, 0}, {0, 1, 3, 4, 6, 0, 0, 0}, + {2, 3, 4, 6, 0, 0, 0, 0}, {0, 2, 3, 4, 6, 0, 0, 0}, + {1, 2, 3, 4, 6, 0, 0, 0}, {0, 1, 2, 3, 4, 6, 0, 0}, + {5, 6, 0, 0, 0, 0, 0, 0}, {0, 5, 6, 0, 0, 0, 0, 0}, + {1, 5, 6, 0, 0, 0, 0, 0}, {0, 1, 5, 6, 0, 0, 0, 0}, + {2, 5, 6, 0, 0, 0, 0, 0}, {0, 2, 5, 6, 0, 0, 0, 0}, + {1, 2, 5, 6, 0, 0, 0, 0}, {0, 1, 2, 5, 6, 0, 0, 0}, + {3, 5, 6, 0, 0, 0, 0, 0}, {0, 3, 5, 6, 0, 0, 0, 0}, + {1, 3, 5, 6, 0, 0, 0, 0}, {0, 1, 3, 5, 6, 0, 0, 0}, + {2, 3, 5, 6, 0, 0, 0, 0}, {0, 2, 3, 5, 6, 0, 0, 0}, + {1, 2, 3, 5, 6, 0, 0, 0}, {0, 1, 2, 3, 5, 6, 0, 0}, + {4, 5, 6, 0, 0, 0, 0, 0}, {0, 4, 5, 6, 0, 0, 0, 0}, + {1, 4, 5, 6, 0, 0, 0, 0}, {0, 1, 4, 5, 6, 0, 0, 0}, + {2, 4, 5, 6, 0, 0, 0, 0}, {0, 2, 4, 5, 6, 0, 0, 0}, + {1, 2, 4, 5, 6, 0, 0, 0}, {0, 1, 2, 4, 5, 6, 0, 0}, + {3, 4, 5, 6, 0, 0, 0, 0}, {0, 3, 4, 5, 6, 0, 0, 0}, + {1, 3, 4, 5, 6, 0, 0, 0}, {0, 1, 3, 4, 5, 6, 0, 0}, + {2, 3, 4, 5, 6, 0, 0, 0}, {0, 2, 3, 4, 5, 6, 0, 0}, + {1, 2, 3, 4, 5, 6, 0, 0}, {0, 1, 2, 3, 4, 5, 6, 0}, + {7, 0, 0, 0, 0, 0, 0, 0}, {0, 7, 0, 0, 0, 0, 0, 0}, + {1, 7, 0, 0, 0, 0, 0, 0}, {0, 1, 7, 0, 0, 0, 0, 0}, + {2, 7, 0, 0, 0, 0, 0, 0}, {0, 2, 7, 0, 0, 0, 0, 0}, + {1, 2, 7, 0, 0, 0, 0, 0}, {0, 1, 2, 7, 0, 0, 0, 0}, + {3, 7, 0, 0, 0, 0, 0, 0}, {0, 3, 7, 0, 0, 0, 0, 0}, + {1, 3, 7, 0, 0, 0, 0, 0}, {0, 1, 3, 7, 0, 0, 0, 0}, + {2, 3, 7, 0, 0, 0, 0, 0}, {0, 2, 3, 7, 0, 0, 0, 0}, + {1, 2, 3, 7, 0, 0, 0, 0}, {0, 1, 2, 3, 7, 0, 0, 0}, + {4, 7, 0, 0, 0, 0, 0, 0}, {0, 4, 7, 0, 0, 0, 0, 0}, + {1, 4, 7, 0, 0, 0, 0, 0}, {0, 1, 4, 7, 0, 0, 0, 0}, + {2, 4, 7, 0, 0, 0, 0, 0}, {0, 2, 4, 7, 0, 0, 0, 0}, + {1, 2, 4, 7, 0, 0, 0, 0}, {0, 1, 2, 4, 7, 0, 0, 0}, + {3, 4, 7, 0, 0, 0, 0, 0}, {0, 3, 4, 7, 0, 0, 0, 0}, + {1, 3, 4, 7, 0, 0, 0, 0}, {0, 1, 3, 4, 7, 0, 0, 0}, + {2, 3, 4, 7, 0, 0, 0, 0}, {0, 2, 3, 4, 7, 0, 0, 0}, + {1, 2, 3, 4, 7, 0, 0, 0}, {0, 1, 2, 3, 4, 7, 0, 0}, + {5, 7, 0, 0, 0, 0, 0, 0}, {0, 5, 7, 0, 0, 0, 0, 0}, + {1, 5, 7, 0, 0, 0, 0, 0}, {0, 1, 5, 7, 0, 0, 0, 0}, + {2, 5, 7, 0, 0, 0, 0, 0}, {0, 2, 5, 7, 0, 0, 0, 0}, + {1, 2, 5, 7, 0, 0, 0, 0}, {0, 1, 2, 5, 7, 0, 0, 0}, + {3, 5, 7, 0, 0, 0, 0, 0}, {0, 3, 5, 7, 0, 0, 0, 0}, + {1, 3, 5, 7, 0, 0, 0, 0}, {0, 1, 3, 5, 7, 0, 0, 0}, + {2, 3, 5, 7, 0, 0, 0, 0}, {0, 2, 3, 5, 7, 0, 0, 0}, + {1, 2, 3, 5, 7, 0, 0, 0}, {0, 1, 2, 3, 5, 7, 0, 0}, + {4, 5, 7, 0, 0, 0, 0, 0}, {0, 4, 5, 7, 0, 0, 0, 0}, + {1, 4, 5, 7, 0, 0, 0, 0}, {0, 1, 4, 5, 7, 0, 0, 0}, + {2, 4, 5, 7, 0, 0, 0, 0}, {0, 2, 4, 5, 7, 0, 0, 0}, + {1, 2, 4, 5, 7, 0, 0, 0}, {0, 1, 2, 4, 5, 7, 0, 0}, + {3, 4, 5, 7, 0, 0, 0, 0}, {0, 3, 4, 5, 7, 0, 0, 0}, + {1, 3, 4, 5, 7, 0, 0, 0}, {0, 1, 3, 4, 5, 7, 0, 0}, + {2, 3, 4, 5, 7, 0, 0, 0}, {0, 2, 3, 4, 5, 7, 0, 0}, + {1, 2, 3, 4, 5, 7, 0, 0}, {0, 1, 2, 3, 4, 5, 7, 0}, + {6, 7, 0, 0, 0, 0, 0, 0}, {0, 6, 7, 0, 0, 0, 0, 0}, + {1, 6, 7, 0, 0, 0, 0, 0}, {0, 1, 6, 7, 0, 0, 0, 0}, + {2, 6, 7, 0, 0, 0, 0, 0}, {0, 2, 6, 7, 0, 0, 0, 0}, + {1, 2, 6, 7, 0, 0, 0, 0}, {0, 1, 2, 6, 7, 0, 0, 0}, + {3, 6, 7, 0, 0, 0, 0, 0}, {0, 3, 6, 7, 0, 0, 0, 0}, + {1, 3, 6, 7, 0, 0, 0, 0}, {0, 1, 3, 6, 7, 0, 0, 0}, + {2, 3, 6, 7, 0, 0, 0, 0}, {0, 2, 3, 6, 7, 0, 0, 0}, + {1, 2, 3, 6, 7, 0, 0, 0}, {0, 1, 2, 3, 6, 7, 0, 0}, + {4, 6, 7, 0, 0, 0, 0, 0}, {0, 4, 6, 7, 0, 0, 0, 0}, + {1, 4, 6, 7, 0, 0, 0, 0}, {0, 1, 4, 6, 7, 0, 0, 0}, + {2, 4, 6, 7, 0, 0, 0, 0}, {0, 2, 4, 6, 7, 0, 0, 0}, + {1, 2, 4, 6, 7, 0, 0, 0}, {0, 1, 2, 4, 6, 7, 0, 0}, + {3, 4, 6, 7, 0, 0, 0, 0}, {0, 3, 4, 6, 7, 0, 0, 0}, + {1, 3, 4, 6, 7, 0, 0, 0}, {0, 1, 3, 4, 6, 7, 0, 0}, + {2, 3, 4, 6, 7, 0, 0, 0}, {0, 2, 3, 4, 6, 7, 0, 0}, + {1, 2, 3, 4, 6, 7, 0, 0}, {0, 1, 2, 3, 4, 6, 7, 0}, + {5, 6, 7, 0, 0, 0, 0, 0}, {0, 5, 6, 7, 0, 0, 0, 0}, + {1, 5, 6, 7, 0, 0, 0, 0}, {0, 1, 5, 6, 7, 0, 0, 0}, + {2, 5, 6, 7, 0, 0, 0, 0}, {0, 2, 5, 6, 7, 0, 0, 0}, + {1, 2, 5, 6, 7, 0, 0, 0}, {0, 1, 2, 5, 6, 7, 0, 0}, + {3, 5, 6, 7, 0, 0, 0, 0}, {0, 3, 5, 6, 7, 0, 0, 0}, + {1, 3, 5, 6, 7, 0, 0, 0}, {0, 1, 3, 5, 6, 7, 0, 0}, + {2, 3, 5, 6, 7, 0, 0, 0}, {0, 2, 3, 5, 6, 7, 0, 0}, + {1, 2, 3, 5, 6, 7, 0, 0}, {0, 1, 2, 3, 5, 6, 7, 0}, + {4, 5, 6, 7, 0, 0, 0, 0}, {0, 4, 5, 6, 7, 0, 0, 0}, + {1, 4, 5, 6, 7, 0, 0, 0}, {0, 1, 4, 5, 6, 7, 0, 0}, + {2, 4, 5, 6, 7, 0, 0, 0}, {0, 2, 4, 5, 6, 7, 0, 0}, + {1, 2, 4, 5, 6, 7, 0, 0}, {0, 1, 2, 4, 5, 6, 7, 0}, + {3, 4, 5, 6, 7, 0, 0, 0}, {0, 3, 4, 5, 6, 7, 0, 0}, + {1, 3, 4, 5, 6, 7, 0, 0}, {0, 1, 3, 4, 5, 6, 7, 0}, + {2, 3, 4, 5, 6, 7, 0, 0}, {0, 2, 3, 4, 5, 6, 7, 0}, + {1, 2, 3, 4, 5, 6, 7, 0}, {0, 1, 2, 3, 4, 5, 6, 7}, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/packing.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/packing.c new file mode 100644 index 0000000000..26da273856 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/packing.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include + +#include "common.h" +#include "packing.h" +#include "poly.h" +#include "polyvec.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_unpack_hints MLD_ADD_PARAM_SET(mld_unpack_hints) +/* End of parameter set namespacing */ + +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +{ + unsigned int i; + + mld_memcpy(pk, rho, MLDSA_SEEDBYTES); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt1_pack(pk + MLDSA_SEEDBYTES + i * MLDSA_POLYT1_PACKEDBYTES, + &t1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +{ + unsigned int i; + + mld_memcpy(rho, pk, MLDSA_SEEDBYTES); + pk += MLDSA_SEEDBYTES; + + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt1_unpack(&t1->vec[i], pk + i * MLDSA_POLYT1_PACKEDBYTES); + } +} + +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +{ + mld_memcpy(sk, rho, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, key, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, tr, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_pack_eta(sk, s1); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_eta(sk, s2); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_t0(sk, t0); +} + +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +{ + mld_memcpy(rho, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(key, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(tr, sk, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_unpack_eta(s1, sk); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_eta(s2, sk); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_t0(t0, sk); +} + +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +{ + unsigned int i, j, k; + + mld_memcpy(sig, c, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + /* skip z component - packed via mld_pack_sig_z */ + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + /* Encode hints h */ + + /* The final section of sig[] is MLDSA_POLYVECH_PACKEDBYTES long, where + * MLDSA_POLYVECH_PACKEDBYTES = MLDSA_OMEGA + MLDSA_K + * + * The first OMEGA bytes record the index numbers of the coefficients + * that are not equal to 0 + * + * The final K bytes record a running tally of the number of hints + * coming from each of the K polynomials in h. + * + * The pre-condition tells us that number_of_hints <= OMEGA, so some + * bytes may not be written, so we initialize all of them to zero + * to start. + */ + mld_memset(sig, 0, MLDSA_POLYVECH_PACKEDBYTES); + + k = 0; + /* For each polynomial in h... */ + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* For each coefficient in that polynomial, record it as as hint */ + /* if its value is not zero */ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + assigns(j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(j <= MLDSA_N) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* The reference implementation implicitly relies on the total */ + /* number of hints being less than OMEGA, assuming h is valid. */ + /* In mldsa-native, we check this explicitly to ease proof of */ + /* type safety. */ + if (h->vec[i].coeffs[j] != 0 && k < number_of_hints) + { + /* The enclosing if condition AND the loop invariant infer */ + /* that k < MLDSA_OMEGA, so writing to sig[k] is safe and k */ + /* can be incremented. */ + sig[k++] = (uint8_t)j; + } + } + /* Having recorded all the hints for this polynomial, also */ + /* record the running tally into the correct "slot" for that */ + /* coefficient in the final K bytes */ + sig[MLDSA_OMEGA + i] = (uint8_t)k; + } +} + +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +{ + sig += MLDSA_CTILDEBYTES; + sig += i * MLDSA_POLYZ_PACKEDBYTES; + mld_polyz_pack(sig, zi); +} + +/************************************************* + * Name: mld_unpack_hints + * + * Description: Unpack raw hint bytes into a polyveck + * struct + * + * Arguments: - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]: + * raw hint bytes + * + * Returns 1 in case of malformed hints; otherwise 0. + **************************************************/ +static int mld_unpack_hints( + mld_polyveck *h, const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(packed_hints, MLDSA_POLYVECH_PACKEDBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + /* All returned coefficients are either 0 or 1 */ + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +) +{ + unsigned int i, j; + unsigned int old_hint_count; + + /* Set all coefficients of all polynomials to 0. */ + /* Only those that are actually non-zero hints will */ + /* be overwritten below. */ + mld_memset(h, 0, sizeof(mld_polyveck)); + + old_hint_count = 0; + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + /* Grab the hint count for the i'th polynomial */ + const unsigned int new_hint_count = packed_hints[MLDSA_OMEGA + i]; + + /* new_hint_count must increase or stay the same, but also remain */ + /* less than or equal to MLDSA_OMEGA */ + if (new_hint_count < old_hint_count || new_hint_count > MLDSA_OMEGA) + { + /* Error - new_hint_count is invalid */ + return 1; + } + + /* If new_hint_count == old_hint_count, then this polynomial has */ + /* zero hints, so this loop executes zero times and we move */ + /* straight on to the next polynomial. */ + for (j = old_hint_count; j < new_hint_count; ++j) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + const uint8_t this_hint_index = packed_hints[j]; + + /* Coefficients must be ordered for strong unforgeability */ + if (j > old_hint_count && this_hint_index <= packed_hints[j - 1]) + { + return 1; + } + h->vec[i].coeffs[this_hint_index] = 1; + } + + old_hint_count = new_hint_count; + } + + /* Extra indices must be zero for strong unforgeability */ + for (j = old_hint_count; j < MLDSA_OMEGA; ++j) + __loop__( + invariant(j <= MLDSA_OMEGA) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + if (packed_hints[j] != 0) + { + return 1; + } + } + + return 0; +} + +MLD_INTERNAL_API +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +{ + mld_memcpy(c, sig, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + mld_polyvecl_unpack_z(z, sig); + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + return mld_unpack_hints(h, sig); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_unpack_hints diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/packing.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/packing.h new file mode 100644 index 0000000000..19095d08cd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/packing.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PACKING_H +#define MLD_PACKING_H + +#include +#include "polyvec.h" + +#define mld_pack_pk MLD_NAMESPACE_KL(pack_pk) +/************************************************* + * Name: mld_pack_pk + * + * Description: Bit-pack public key pk = (rho, t1). + * + * Arguments: - uint8_t pk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const mld_polyveck *t1: pointer to vector t1 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) +); + + +#define mld_pack_sk MLD_NAMESPACE_KL(pack_sk) +/************************************************* + * Name: mld_pack_sk + * + * Description: Bit-pack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - uint8_t sk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const uint8_t tr[]: byte array containing tr + * - const uint8_t key[]: byte array containing key + * - const mld_polyveck *t0: pointer to vector t0 + * - const mld_polyvecl *s1: pointer to vector s1 + * - const mld_polyveck *s2: pointer to vector s2 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +__contract__( + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + requires(forall(k2, 0, MLDSA_K, + array_abs_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) +); + + +#define mld_pack_sig_c_h MLD_NAMESPACE_KL(pack_sig_c_h) +/************************************************* + * Name: mld_pack_sig_c_h + * + * Description: Bit-pack c and h component of sig = (c, z, h). + * The z component is packed separately using mld_pack_sig_z. + * + * Arguments: - uint8_t sig[]: output byte array + * - const uint8_t *c: pointer to challenge hash length + * MLDSA_SEEDBYTES + * - const mld_polyveck *h: pointer to hint vector h + * - const unsigned int number_of_hints: total + * hints in *h + * + * Note that the number_of_hints argument is not present + * in the reference implementation. It is added here to ease + * proof of type safety. + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + requires(number_of_hints <= MLDSA_OMEGA) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_pack_sig_z MLD_NAMESPACE_KL(pack_sig_z) +/************************************************* + * Name: mld_pack_sig_z + * + * Description: Bit-pack single polynomial of z component of sig = (c, z, h). + * The c and h components are packed separately using + * mld_pack_sig_c_h. + * + * Arguments: - uint8_t sig[]: output byte array + * - const mld_poly *zi: pointer to a single polynomial in z + * - const unsigned int i: index of zi in vector z + * + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(zi, sizeof(mld_poly))) + requires(i < MLDSA_L) + requires(array_bound(zi->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_unpack_pk MLD_NAMESPACE_KL(unpack_pk) +/************************************************* + * Name: mld_unpack_pk + * + * Description: Unpack public key pk = (rho, t1). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const mld_polyveck *t1: pointer to output vector t1 + * - uint8_t pk[]: byte array containing bit-packed pk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) +); + + +#define mld_unpack_sk MLD_NAMESPACE_KL(unpack_sk) +/************************************************* + * Name: mld_unpack_sk + * + * Description: Unpack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const uint8_t tr[]: output byte array for tr + * - const uint8_t key[]: output byte array for key + * - const mld_polyveck *t0: pointer to output vector t0 + * - const mld_polyvecl *s1: pointer to output vector s1 + * - const mld_polyveck *s2: pointer to output vector s2 + * - uint8_t sk[]: byte array containing bit-packed sk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +__contract__( + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(key, MLDSA_SEEDBYTES)) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(s1, sizeof(mld_polyvecl))) + assigns(memory_slice(s2, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_unpack_sig MLD_NAMESPACE_KL(unpack_sig) +/************************************************* + * Name: mld_unpack_sig + * + * Description: Unpack signature sig = (c, z, h). + * + * Arguments: - uint8_t *c: pointer to output challenge hash + * - mld_polyvecl *z: pointer to output vector z + * - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t sig[]: byte array containing + * bit-packed signature + * + * Returns 1 in case of malformed signature; otherwise 0. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(c, MLDSA_CTILDEBYTES)) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(z->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +); +#endif /* !MLD_PACKING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/params.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/params.h new file mode 100644 index 0000000000..c67d2a33fb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/params.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PARAMS_H +#define MLD_PARAMS_H + +#define MLDSA_SEEDBYTES 32 +#define MLDSA_CRHBYTES 64 +#define MLDSA_TRBYTES 64 +#define MLDSA_RNDBYTES 32 +#define MLDSA_N 256 +#define MLDSA_Q 8380417 +#define MLDSA_Q_HALF ((MLDSA_Q + 1) / 2) +#define MLDSA_D 13 + +#if MLD_CONFIG_PARAMETER_SET == 44 + +#define MLDSA_K 4 +#define MLDSA_L 4 +#define MLDSA_ETA 2 +#define MLDSA_TAU 39 +#define MLDSA_BETA 78 +#define MLDSA_GAMMA1 (1 << 17) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 88) +#define MLDSA_OMEGA 80 +#define MLDSA_CTILDEBYTES 32 +#define MLDSA_POLYZ_PACKEDBYTES 576 +#define MLDSA_POLYW1_PACKEDBYTES 192 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#elif MLD_CONFIG_PARAMETER_SET == 65 + +#define MLDSA_K 6 +#define MLDSA_L 5 +#define MLDSA_ETA 4 +#define MLDSA_TAU 49 +#define MLDSA_BETA 196 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 55 +#define MLDSA_CTILDEBYTES 48 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 128 + +#elif MLD_CONFIG_PARAMETER_SET == 87 + +#define MLDSA_K 8 +#define MLDSA_L 7 +#define MLDSA_ETA 2 +#define MLDSA_TAU 60 +#define MLDSA_BETA 120 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 75 +#define MLDSA_CTILDEBYTES 64 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ + +#define MLDSA_POLYT1_PACKEDBYTES 320 +#define MLDSA_POLYT0_PACKEDBYTES 416 +#define MLDSA_POLYVECH_PACKEDBYTES (MLDSA_OMEGA + MLDSA_K) + +#define MLDSA_CRYPTO_PUBLICKEYBYTES \ + (MLDSA_SEEDBYTES + MLDSA_K * MLDSA_POLYT1_PACKEDBYTES) +#define MLDSA_CRYPTO_SECRETKEYBYTES \ + (2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + MLDSA_L * MLDSA_POLYETA_PACKEDBYTES + \ + MLDSA_K * MLDSA_POLYETA_PACKEDBYTES + MLDSA_K * MLDSA_POLYT0_PACKEDBYTES) +#define MLDSA_CRYPTO_BYTES \ + (MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES + \ + MLDSA_POLYVECH_PACKEDBYTES) + +#endif /* !MLD_PARAMS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/poly.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/poly.c new file mode 100644 index 0000000000..e40534e773 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/poly.c @@ -0,0 +1,973 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "common.h" +#include "ct.h" +#include "debug.h" +#include "poly.h" +#include "reduce.h" +#include "rounding.h" +#include "symmetric.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +#include "zetas.inc" + +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + { + a->coeffs[i] = mld_reduce32(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_STATIC_TESTABLE void mld_poly_caddq_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + ) + { + a->coeffs[i] = mld_caddq(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_POLY_CADDQ) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_poly_caddq_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + mld_poly_caddq_c(a); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1])) + invariant(forall(k2, 0, i, r->coeffs[k2] < MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k2, 0, i, r->coeffs[k2] >= INT32_MIN)) + ) + { + r->coeffs[i] = r->coeffs[i] + b->coeffs[i]; + } +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(r->coeffs, 0, i, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + ) + { + r->coeffs[i] = r->coeffs[i] - b->coeffs[i]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N; i++) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))) + { + /* Reference: uses a left shift by MLDSA_D which is undefined behaviour in + * C90/C99 + */ + a->coeffs[i] *= (1 << MLDSA_D); + } + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + + +static MLD_INLINE int32_t mld_fqmul(int32_t a, int32_t b) +__contract__( + requires(b > -MLDSA_Q_HALF && b < MLDSA_Q_HALF) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* Bounds: We argue in mld_montgomery_reduce() that the reult + * of Montgomery reduction is < MLDSA_Q if the input is smaller + * than 2^31 * MLDSA_Q in absolute value. Indeed, we have: + * + * |a * b| = |a| * |b| + * < 2^31 * MLDSA_Q_HALF + * < 2^31 * MLDSA_Q + */ + return mld_montgomery_reduce((int64_t)a * (int64_t)b); +} + +/* mld_ntt_butterfly_block() + * + * Computes a block CT butterflies with a fixed twiddle factor, + * using Montgomery multiplication. + * + * Parameters: + * - r: Pointer to base of polynomial (_not_ the base of butterfly block) + * - zeta: Twiddle factor to use for the butterfly. This must be in + * Montgomery form and signed canonical. + * - start: Offset to the beginning of the butterfly block + * - len: Index difference between coefficients subject to a butterfly + * - bound: Ghost variable describing coefficient bound: Prior to `start`, + * coefficients must be bound by `bound + MLDSA_Q`. Post `start`, + * they must be bound by `bound`. + * When this function returns, output coefficients in the index range + * [start, start+2*len) have bound bumped to `bound + MLDSA_Q`. + * Example: + * - start=8, len=4 + * This would compute the following four butterflies + * 8 -- 12 + * 9 -- 13 + * 10 -- 14 + * 11 -- 15 + * - start=4, len=2 + * This would compute the following two butterflies + * 4 -- 6 + * 5 -- 7 + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_butterfly_block(int32_t r[MLDSA_N], + const int32_t zeta, + const unsigned start, + const unsigned len, + const unsigned bound) +__contract__( + requires(start < MLDSA_N) + requires(1 <= len && len <= MLDSA_N / 2 && start + 2 * len <= MLDSA_N) + requires(0 <= bound && bound < INT32_MAX - MLDSA_Q) + requires(-MLDSA_Q_HALF < zeta && zeta < MLDSA_Q_HALF) + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, start, bound + MLDSA_Q)) + requires(array_abs_bound(r, start, MLDSA_N, bound)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, start + 2*len, bound + MLDSA_Q)) + ensures(array_abs_bound(r, start + 2 * len, MLDSA_N, bound))) +{ + /* `bound` is a ghost variable only needed in the CBMC specification */ + unsigned j; + ((void)bound); + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + /* + * Coefficients are updated in strided pairs, so the bounds for the + * intermediate states alternate twice between the old and new bound + */ + invariant(array_abs_bound(r, 0, j, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, bound)) + invariant(array_abs_bound(r, start + len, j + len, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j + len, MLDSA_N, bound))) + { + int32_t t; + t = mld_fqmul(r[j + len], zeta); + r[j + len] = r[j] - t; + r[j] = r[j] + t; + } +} + +/* mld_ntt_layer() + * + * Compute one layer of forward NTT + * + * Parameters: + * - r: Pointer to base of polynomial + * - layer: Indicates which layer is being applied. + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_layer(int32_t r[MLDSA_N], const unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (layer + 1) * MLDSA_Q))) +{ + unsigned start, k, len; + /* Twiddle factors for layer n are at indices 2^(n-1)..2^n-1. */ + k = 1u << (layer - 1); + len = (unsigned)MLDSA_N >> layer; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start < MLDSA_N + 2 * len) + invariant(k <= MLDSA_N) + invariant(2 * len * k == start + MLDSA_N) + invariant(array_abs_bound(r, 0, start, layer * MLDSA_Q + MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, layer * MLDSA_Q))) + { + int32_t zeta = mld_zetas[k++]; + mld_ntt_butterfly_block(r, zeta, start, len, layer * MLDSA_Q); + } +} + +MLD_STATIC_TESTABLE void mld_poly_ntt_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +) +{ + unsigned int layer; + int32_t *r; + + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + r = a->coeffs; + + for (layer = 1; layer < 9; layer++) + __loop__( + invariant(1 <= layer && layer <= 9) + invariant(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + ) + { + mld_ntt_layer(r, layer); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_NTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_ntt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_NTT */ + mld_poly_ntt_c(a); +} + +/************************************************* + * Name: mld_fqscale + * + * Description: Scales a field element by mont/256 , i.e., performs Montgomery + * multiplication by mont^2/256. + * Input is expected to have absolute value smaller than + * 256 * MLDSA_Q. + * Output has absolute value smaller than MLD_INTT_BOUND. + * + * Arguments: - int32_t a: Field element to be scaled. + **************************************************/ +static MLD_INLINE int32_t mld_fqscale(int32_t a) +__contract__( + requires(a > -256*MLDSA_Q && a < 256*MLDSA_Q) + ensures(return_value > -MLD_INTT_BOUND && return_value < MLD_INTT_BOUND) +) +{ + /* check-magic: 41978 == pow(2,64-8,MLDSA_Q) */ + const int32_t f = 41978; + /* Bounds: MLD_INTT_BOUND is MLDSA_Q, so the bounds reasoning is just + * a special case of that in mld_fqmul(). */ + return mld_montgomery_reduce((int64_t)a * f); +} + +/* Reference: Embedded into `invntt_tomont()` in the reference implementation + * @[REF] */ +static MLD_INLINE void mld_invntt_layer(int32_t r[MLDSA_N], unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> (layer - 1)) * MLDSA_Q))) +{ + unsigned start, k, len; + len = (unsigned)MLDSA_N >> layer; + k = (1u << layer) - 1; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start <= MLDSA_N && k <= 255) + invariant(2 * len * k + start == 2 * MLDSA_N - 2 * len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + unsigned j; + int32_t zeta = -mld_zetas[k--]; + + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, j, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, (MLDSA_N >> layer) * MLDSA_Q)) + invariant(array_abs_bound(r, start + len, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + int32_t t = r[j]; + r[j] = t + r[j + len]; + r[j + len] = t - r[j + len]; + r[j + len] = mld_fqmul(r[j + len], zeta); + } + } +} + +MLD_STATIC_TESTABLE void mld_poly_invntt_tomont_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +) +{ + unsigned int layer, j; + int32_t *r; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + r = a->coeffs; + for (layer = 8; layer >= 1; layer--) + __loop__( + invariant(layer <= 8) + /* Absolute bounds increase from 1Q before layer 8 */ + /* up to 256Q after layer 1 */ + invariant(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + mld_invntt_layer(r, layer); + } + + /* Coefficient bounds are now at 256Q. We now scale by mont / 256, + * i.e., compute the Montgomery multiplication by mont^2 / 256. + * mont corrects the mont^-1 factor introduced in the basemul. + * 1/256 performs that scaling of the inverse NTT. + * The reduced value is bounded by MLD_INTT_BOUND in absolute + * value.*/ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + invariant(j <= MLDSA_N) + invariant(array_abs_bound(r, 0, j, MLD_INTT_BOUND)) + invariant(array_abs_bound(r, j, MLDSA_N, MLDSA_N * MLDSA_Q)) + ) + { + r[j] = mld_fqscale(r[j]); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); +} + + +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_INTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_intt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_INTT */ + mld_poly_invntt_tomont_c(a); +} + +MLD_STATIC_TESTABLE void mld_poly_pointwise_montgomery_c(mld_poly *c, + const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_abs_bound(c->coeffs, 0, i, MLDSA_Q)) + ) + { + c->coeffs[i] = mld_montgomery_reduce((int64_t)a->coeffs[i] * b->coeffs[i]); + } + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +{ +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + ret = mld_poly_pointwise_montgomery_native(c->coeffs, a->coeffs, b->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + mld_poly_pointwise_montgomery_c(c, a, b); +} + +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, 0, i, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + invariant(array_bound(a1->coeffs, 0, i, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) + ) + { + mld_power2round(&a0->coeffs[i], &a1->coeffs[i], a->coeffs[i]); + } + + mld_assert_bound(a0->coeffs, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +#ifndef MLD_POLY_UNIFORM_NBLOCKS +#define MLD_POLY_UNIFORM_NBLOCKS \ + ((768 + MLD_STREAM128_BLOCKBYTES - 1) / MLD_STREAM128_BLOCKBYTES) +#endif +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +MLD_STATIC_TESTABLE unsigned int mld_rej_uniform_c(int32_t *a, + unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ + unsigned int ctr, pos; + uint32_t t; + mld_assert_bound(a, offset, 0, MLDSA_Q); + + ctr = offset; + pos = 0; + /* pos + 3 cannot overflow due to the assumption + buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) */ + while (ctr < target && pos + 3 <= buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_bound(a, 0, ctr, 0, MLDSA_Q))) + { + t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + a[ctr++] = (int32_t)t; + } + } + + mld_assert_bound(a, ctr, 0, MLDSA_Q); + + return ctr; +} +/************************************************* + * Name: mld_rej_uniform + * + * Description: Sample uniformly random coefficients in [0, MLDSA_Q-1] by + * performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes (must be + * multiple of 3) + * + * Returns number of sampled coefficients. Can be smaller than len if not enough + * random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +static unsigned int mld_rej_uniform(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) + int ret; + mld_assert_bound(a, offset, 0, MLDSA_Q); + if (offset == 0) + { + ret = mld_rej_uniform_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_bound(a, res, 0, MLDSA_Q); + return res; + } + } +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + + return mld_rej_uniform_c(a, target, offset, buf, buflen); +} + +/* Reference: poly_uniform() in the reference implementation @[REF]. + * - Simplified from reference by removing buffer tail handling + * since buflen % 3 = 0 always holds true (MLD_STREAM128_BLOCKBYTES + * = 168). + * - Modified rej_uniform interface to track offset directly. + * - Pass nonce packed in the extended seed array instead of a third + * argument. + * */ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +{ + unsigned int ctr; + unsigned int buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + MLD_ALIGN uint8_t buf[MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES]; + mld_xof128_ctx state; + + mld_xof128_init(&state); + mld_xof128_absorb_once(&state, seed, MLDSA_SEEDBYTES + 2); + mld_xof128_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, 0, buf, buflen); + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(a, sizeof(mld_poly)), object_whole(buf)) + invariant(ctr <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, ctr, 0, MLDSA_Q)) + invariant(state.pos <= SHAKE128_RATE) + ) + { + mld_xof128_squeezeblocks(buf, 1, &state); + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, ctr, buf, buflen); + } + mld_xof128_release(&state); + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof128_x4_ctx state; + unsigned buflen; + + mld_xof128_x4_init(&state); + mld_xof128_x4_absorb(&state, seed, MLDSA_SEEDBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_NBLOCKS. + * This should generate the matrix entries with high probability. + */ + + mld_xof128_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all matrix entries have been generated, squeeze + * one more block a time until we're done. + */ + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, object_whole(buf), + memory_slice(vec0, sizeof(mld_poly)), memory_slice(vec1, sizeof(mld_poly)), + memory_slice(vec2, sizeof(mld_poly)), memory_slice(vec3, sizeof(mld_poly))) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_bound(vec0->coeffs, 0, ctr[0], 0, MLDSA_Q)) + invariant(array_bound(vec1->coeffs, 0, ctr[1], 0, MLDSA_Q)) + invariant(array_bound(vec2->coeffs, 0, ctr[2], 0, MLDSA_Q)) + invariant(array_bound(vec3->coeffs, 0, ctr[3], 0, MLDSA_Q))) + { + mld_xof128_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + mld_xof128_x4_release(&state); + + mld_assert_bound(vec0->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec1->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec2->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec3->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0) & 0xFF); + r[5 * i + 1] = + (uint8_t)(((a->coeffs[4 * i + 0] >> 8) | (a->coeffs[4 * i + 1] << 2)) & + 0xFF); + r[5 * i + 2] = + (uint8_t)(((a->coeffs[4 * i + 1] >> 6) | (a->coeffs[4 * i + 2] << 4)) & + 0xFF); + r[5 * i + 3] = + (uint8_t)(((a->coeffs[4 * i + 2] >> 4) | (a->coeffs[4 * i + 3] << 6)) & + 0xFF); + r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, 0, 1 << 10))) + { + r->coeffs[4 * i + 0] = + ((a[5 * i + 0] >> 0) | ((int32_t)a[5 * i + 1] << 8)) & 0x3FF; + r->coeffs[4 * i + 1] = + ((a[5 * i + 1] >> 2) | ((int32_t)a[5 * i + 2] << 6)) & 0x3FF; + r->coeffs[4 * i + 2] = + ((a[5 * i + 2] >> 4) | ((int32_t)a[5 * i + 3] << 4)) & 0x3FF; + r->coeffs[4 * i + 3] = + ((a[5 * i + 3] >> 6) | ((int32_t)a[5 * i + 4] << 2)) & 0x3FF; + } + + mld_assert_bound(r->coeffs, MLDSA_N, 0, 1 << 10); +} + +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[8]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* Safety: a->coeffs[i] <= (1 << (MLDSA_D - 1) as they are output of + * power2round, hence, these casts are safe. */ + t[0] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 0]); + t[1] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 1]); + t[2] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 2]); + t[3] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 3]); + t[4] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 4]); + t[5] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 5]); + t[6] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 6]); + t[7] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 7]); + + r[13 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[13 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[13 * i + 1] |= (uint8_t)((t[1] << 5) & 0xFF); + r[13 * i + 2] = (uint8_t)((t[1] >> 3) & 0xFF); + r[13 * i + 3] = (uint8_t)((t[1] >> 11) & 0xFF); + r[13 * i + 3] |= (uint8_t)((t[2] << 2) & 0xFF); + r[13 * i + 4] = (uint8_t)((t[2] >> 6) & 0xFF); + r[13 * i + 4] |= (uint8_t)((t[3] << 7) & 0xFF); + r[13 * i + 5] = (uint8_t)((t[3] >> 1) & 0xFF); + r[13 * i + 6] = (uint8_t)((t[3] >> 9) & 0xFF); + r[13 * i + 6] |= (uint8_t)((t[4] << 4) & 0xFF); + r[13 * i + 7] = (uint8_t)((t[4] >> 4) & 0xFF); + r[13 * i + 8] = (uint8_t)((t[4] >> 12) & 0xFF); + r[13 * i + 8] |= (uint8_t)((t[5] << 1) & 0xFF); + r[13 * i + 9] = (uint8_t)((t[5] >> 7) & 0xFF); + r[13 * i + 9] |= (uint8_t)((t[6] << 6) & 0xFF); + r[13 * i + 10] = (uint8_t)((t[6] >> 2) & 0xFF); + r[13 * i + 11] = (uint8_t)((t[6] >> 10) & 0xFF); + r[13 * i + 11] |= (uint8_t)((t[7] << 3) & 0xFF); + r[13 * i + 12] = (uint8_t)((t[7] >> 5) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + { + r->coeffs[8 * i + 0] = a[13 * i + 0]; + r->coeffs[8 * i + 0] |= (int32_t)a[13 * i + 1] << 8; + r->coeffs[8 * i + 0] &= 0x1FFF; + + r->coeffs[8 * i + 1] = a[13 * i + 1] >> 5; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 2] << 3; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 3] << 11; + r->coeffs[8 * i + 1] &= 0x1FFF; + + r->coeffs[8 * i + 2] = a[13 * i + 3] >> 2; + r->coeffs[8 * i + 2] |= (int32_t)a[13 * i + 4] << 6; + r->coeffs[8 * i + 2] &= 0x1FFF; + + r->coeffs[8 * i + 3] = a[13 * i + 4] >> 7; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 5] << 1; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 6] << 9; + r->coeffs[8 * i + 3] &= 0x1FFF; + + r->coeffs[8 * i + 4] = a[13 * i + 6] >> 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 7] << 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 8] << 12; + r->coeffs[8 * i + 4] &= 0x1FFF; + + r->coeffs[8 * i + 5] = a[13 * i + 8] >> 1; + r->coeffs[8 * i + 5] |= (int32_t)a[13 * i + 9] << 7; + r->coeffs[8 * i + 5] &= 0x1FFF; + + r->coeffs[8 * i + 6] = a[13 * i + 9] >> 6; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 10] << 2; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 11] << 10; + r->coeffs[8 * i + 6] &= 0x1FFF; + + r->coeffs[8 * i + 7] = a[13 * i + 11] >> 3; + r->coeffs[8 * i + 7] |= (int32_t)a[13 * i + 12] << 5; + r->coeffs[8 * i + 7] &= 0x1FFF; + + r->coeffs[8 * i + 0] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 7]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +MLD_STATIC_TESTABLE uint32_t mld_poly_chknorm_c(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == array_abs_bound(a->coeffs, 0, i, B)) + ) + { + /* + * Since we know that -MLD_REDUCE32_RANGE_MAX <= a < MLD_REDUCE32_RANGE_MAX, + * and B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX, to check if + * -B < (a mod± MLDSA_Q) < B, it suffices to check if -B < a < B. + * + * We prove this to be true using the following CBMC assertions. + * a ==> b expressed as !a || b to also allow run-time assertion. + */ + mld_assert(a->coeffs[i] < B || a->coeffs[i] - MLDSA_Q <= -B); + mld_assert(a->coeffs[i] > -B || a->coeffs[i] + MLDSA_Q >= B); + + /* Reference: Leaks which coefficient violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + + /* if (abs(a[i]) >= B) */ + t |= mld_ct_cmask_neg_i32(B - 1 - mld_ct_abs_i32(a->coeffs[i])); + } + + return t; +} + +/* Reference: explicitly checks the bound B to be <= (MLDSA_Q - 1) / 8). + * This is unnecessary as it's always a compile-time constant. + * We instead model it as a precondition. + * Checking the bound is performed using a conditional arguing + * that it is okay to leak which coefficient violates the bound (while the + * coefficient itself must remain secret). + * We instead perform everything in constant-time. + * Also it is sufficient to check that it is smaller than + * MLDSA_Q - MLD_REDUCE32_RANGE_MAX > (MLDSA_Q - 1) / 8). + */ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +{ +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) + int ret; + int success; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + /* The native backend returns 0 if all coefficients are within the bound, + * 1 if at least one coefficient exceeds the bound, and + * -1 (MLD_NATIVE_FUNC_FALLBACK) if the platform does not have the + * required capabilities to run the native function. + */ + ret = mld_poly_chknorm_native(a->coeffs, B); + + success = (ret != MLD_NATIVE_FUNC_FALLBACK); + /* Constant-time: It would be fine to leak the return value of chknorm + * entirely (as it is fine to leak if any coefficient exceeded the bound or + * not). However, it is cleaner to perform declassification in sign.c. + * Hence, here we only declassify if the native function returned + * MLD_NATIVE_FUNC_FALLBACK or not (which solely depends on system + * capabilities). + */ + MLD_CT_TESTING_DECLASSIFY(&success, sizeof(int)); + if (success) + { + /* Convert 0 / 1 to 0 / 0xFFFFFFFF here */ + return 0U - (uint32_t)ret; + } +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + return mld_poly_chknorm_c(a, B); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ +MLD_EMPTY_CU(mld_poly) +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_POLY_UNIFORM_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/poly.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/poly.h new file mode 100644 index 0000000000..ff7710438e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/poly.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_H +#define MLD_POLY_H + +#include +#include "cbmc.h" +#include "common.h" +#include "reduce.h" +#include "rounding.h" + +/* Absolute exclusive upper bound for the output of the forward NTT */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) +/* Absolute exclusive upper bound for the output of the inverse NTT*/ +#define MLD_INTT_BOUND MLDSA_Q + +typedef struct +{ + int32_t coeffs[MLDSA_N]; +} MLD_ALIGN mld_poly; + +#define mld_poly_reduce MLD_NAMESPACE(poly_reduce) +/************************************************* + * Name: mld_poly_reduce + * + * Description: Inplace reduction of all coefficients of polynomial to + * representative in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) +); + +#define mld_poly_caddq MLD_NAMESPACE(poly_caddq) +/************************************************* + * Name: mld_poly_caddq + * + * Description: For all coefficients of in/out polynomial add MLDSA_Q if + * coefficient is negative. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_add MLD_NAMESPACE(poly_add) +/************************************************* + * Name: mld_poly_add + * + * Description: Add polynomials. No modular reduction is performed. + * + * Arguments: - r: Pointer to input-output polynomial to be added to. + * - b: Pointer to input polynomial that should be added + * to r. Must be disjoint from r. + **************************************************/ + +/* + * NOTE: The reference implementation uses a 3-argument poly_add. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(forall(k0, 0, MLDSA_N, (int64_t) r->coeffs[k0] + b->coeffs[k0] < MLD_REDUCE32_DOMAIN_MAX)) + requires(forall(k1, 0, MLDSA_N, (int64_t) r->coeffs[k1] + b->coeffs[k1] >= INT32_MIN)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(forall(k2, 0, MLDSA_N, r->coeffs[k2] == old(*r).coeffs[k2] + b->coeffs[k2])) + ensures(forall(k3, 0, MLDSA_N, r->coeffs[k3] < MLD_REDUCE32_DOMAIN_MAX)) + ensures(forall(k4, 0, MLDSA_N, r->coeffs[k4] >= INT32_MIN)) +); + +#define mld_poly_sub MLD_NAMESPACE(poly_sub) +/************************************************* + * Name: mld_poly_sub + * + * Description: Subtract polynomials. No modular reduction is + * performed. + * + * Arguments: - mld_poly *r: Pointer to input-output polynomial. + * - const mld_poly *b: Pointer to input polynomial that should be + * subtracted from r. Must be disjoint from r. + **************************************************/ +/* + * NOTE: The reference implementation uses a 3-argument poly_sub. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_Q)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) +); + +#define mld_poly_shiftl MLD_NAMESPACE(poly_shiftl) +/************************************************* + * Name: mld_poly_shiftl + * + * Description: Multiply polynomial by 2^MLDSA_D without modular reduction. + *Assumes input coefficients to be less than 2^{31-MLDSA_D} in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_ntt MLD_NAMESPACE(poly_ntt) +/************************************************* + * Name: mld_poly_ntt + * + * Description: Inplace forward NTT. Coefficients can grow by + * 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +); + + +#define mld_poly_invntt_tomont MLD_NAMESPACE(poly_invntt_tomont) +/************************************************* + * Name: mld_poly_invntt_tomont + * + * Description: Inplace inverse NTT and multiplication by 2^{32}. + * Input coefficients need to be less than MLDSA_Q in absolute + * value and output coefficients are bounded by + * MLD_INTT_BOUND. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +); + +#define mld_poly_pointwise_montgomery MLD_NAMESPACE(poly_pointwise_montgomery) +/************************************************* + * Name: mld_poly_pointwise_montgomery + * + * Description: Pointwise multiplication of polynomials in NTT domain + * representation and multiplication of resulting polynomial + * by 2^{-32}. + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const mld_poly *a: pointer to first input polynomial + * - const mld_poly *b: pointer to second input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + +#define mld_poly_power2round MLD_NAMESPACE(poly_power2round) +/************************************************* + * Name: mld_poly_power2round + * + * Description: For all coefficients c of the input polynomial, + * compute c0, c1 such that c mod MLDSA_Q = c1*2^MLDSA_D + c0 + * with -2^{MLDSA_D-1} < c0 <= 2^{MLDSA_D-1}. Assumes coefficients + *to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + *c1 + * - mld_poly *a0: pointer to output polynomial with coefficients + *c0 + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +__contract__( + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a0->coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) +); + +#define mld_poly_uniform MLD_NAMESPACE(poly_uniform) +/************************************************* + * Name: mld_poly_uniform + * + * Description: Sample polynomial with uniformly random coefficients + * in [0,MLDSA_Q-1] by performing rejection sampling on the + * output stream of SHAKE128(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_SEEDBYTES and the packed 2-byte nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES + 2)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +#define mld_poly_uniform_4x MLD_NAMESPACE(poly_uniform_4x) +/************************************************* + * Name: mld_poly_uniform_x4 + * + * Description: Generate four polynomials using rejection sampling + * on (pseudo-)uniformly random bytes sampled from a seed. + * + * Arguments: - mld_poly *vec0, *vec1, *vec2, *vec3: + * Pointers to 4 polynomials to be sampled. + * - uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]: + * Pointer consecutive array of seed buffers of size + * MLDSA_SEEDBYTES + 2 each, plus padding for alignment. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +__contract__( + requires(memory_no_alias(vec0, sizeof(mld_poly))) + requires(memory_no_alias(vec1, sizeof(mld_poly))) + requires(memory_no_alias(vec2, sizeof(mld_poly))) + requires(memory_no_alias(vec3, sizeof(mld_poly))) + requires(memory_no_alias(seed, 4 * MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2))) + assigns(memory_slice(vec0, sizeof(mld_poly))) + assigns(memory_slice(vec1, sizeof(mld_poly))) + assigns(memory_slice(vec2, sizeof(mld_poly))) + assigns(memory_slice(vec3, sizeof(mld_poly))) + ensures(array_bound(vec0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec1->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec2->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec3->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +#define mld_polyt1_pack MLD_NAMESPACE(polyt1_pack) +/************************************************* + * Name: mld_polyt1_pack + * + * Description: Bit-pack polynomial t1 with coefficients fitting in 10 bits. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(r, MLDSA_POLYT1_PACKEDBYTES)) +); + +#define mld_polyt1_unpack MLD_NAMESPACE(polyt1_unpack) +/************************************************* + * Name: mld_polyt1_unpack + * + * Description: Unpack polynomial t1 with 10-bit coefficients. + * Output coefficients are standard representatives. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT1_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, 0, 1 << 10)) +); + +#define mld_polyt0_pack MLD_NAMESPACE(polyt0_pack) +/************************************************* + * Name: mld_polyt0_pack + * + * Description: Bit-pack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + * 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) + assigns(memory_slice(r, MLDSA_POLYT0_PACKEDBYTES)) +); + + +#define mld_polyt0_unpack MLD_NAMESPACE(polyt0_unpack) +/************************************************* + * Name: mld_polyt0_unpack + * + * Description: Unpack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + *2^{MLDSA_D-1}]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT0_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) +); + +#define mld_poly_chknorm MLD_NAMESPACE(poly_chknorm) +/************************************************* + * Name: mld_poly_chknorm + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const mld_poly *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if norm is strictly smaller than + * B <= (MLDSA_Q - MLD_REDUCE32_RANGE_MAX) and 0xFFFFFFFF otherwise. + * + * Specification: The definition of this FIPS-204 requires signed canonical + * reduction prior to applying the bounds check. + * However, `-B < (a mod± MLDSA_Q) < B` is equivalent to + * `-B < a < B` under the assumption that + * `B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX` (cf. the assertion in + * the code). Hence, the present spec and implementation are + * correct without reduction. + * + **************************************************/ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +); + +#endif /* !MLD_POLY_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/poly_kl.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/poly_kl.c new file mode 100644 index 0000000000..7a319ca515 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/poly_kl.c @@ -0,0 +1,931 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "ct.h" +#include "debug.h" +#include "poly_kl.h" +#include "rounding.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_rej_eta MLD_ADD_PARAM_SET(mld_rej_eta) +#define mld_rej_eta_c MLD_ADD_PARAM_SET(mld_rej_eta_c) +#define mld_poly_decompose_c MLD_ADD_PARAM_SET(mld_poly_decompose_c) +#define mld_poly_use_hint_c MLD_ADD_PARAM_SET(mld_poly_use_hint_c) +#define mld_polyz_unpack_c MLD_ADD_PARAM_SET(mld_polyz_unpack_c) +/* End of parameter set namespacing */ + + +MLD_STATIC_TESTABLE +void mld_poly_decompose_c(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +) +{ + unsigned int i; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, i, MLDSA_N, 0, MLDSA_Q)) + invariant(array_bound(a1->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + invariant(array_abs_bound(a0->coeffs, 0, i, MLDSA_GAMMA2+1)) + ) + { + mld_decompose(&a0->coeffs[i], &a1->coeffs[i], a0->coeffs[i]); + } + + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +{ +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_88_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_32_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_DECOMPOSE_88 && MLD_CONFIG_PARAMETER_SET == \ + 44) && MLD_USE_NATIVE_POLY_DECOMPOSE_32 && (MLD_CONFIG_PARAMETER_SET \ + == 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_decompose_c(a1, a0); +} + +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(s <= i) + invariant(array_bound(h->coeffs, 0, i, 0, 2)) + ) + { + const unsigned int hint_bit = mld_make_hint(a0->coeffs[i], a1->coeffs[i]); + h->coeffs[i] = (int32_t)hint_bit; + s += hint_bit; + } + + mld_assert(s <= MLDSA_N); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + return s; +} + +MLD_STATIC_TESTABLE void mld_poly_use_hint_c(mld_poly *b, const mld_poly *a, + const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(b->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ) + { + b->coeffs[i] = mld_use_hint(a->coeffs[i], h->coeffs[i]); + } + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +{ +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_88_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_USE_HINT_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_32_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_USE_HINT_88 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLY_USE_HINT_32 && (MLD_CONFIG_PARAMETER_SET == \ + 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_use_hint_c(b, a, h); +} + +/************************************************* + * Name: mld_rej_eta + * + * Description: Sample uniformly random coefficients in [-MLDSA_ETA, MLDSA_ETA] + *by performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes + * + * Returns number of sampled coefficients. Can be smaller than target if not + *enough random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_eta()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +#if MLDSA_ETA == 2 +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 1 +#elif MLDSA_ETA == 4 +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 2 +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + +MLD_STATIC_TESTABLE unsigned int mld_rej_eta_c(int32_t *a, unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ + unsigned int ctr, pos; + int t_valid; + uint32_t t0, t1; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + ctr = offset; + pos = 0; + while (ctr < target && pos < buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_abs_bound(a, 0, ctr, MLDSA_ETA + 1)) + ) + { + t0 = buf[pos] & 0x0F; + t1 = buf[pos++] >> 4; + + /* Constant time: The inputs and outputs to the rejection sampling are + * secret. However, it is fine to leak which coefficients have been + * rejected. For constant-time testing, we declassify the result of + * the comparison. + */ +#if MLDSA_ETA == 2 + t_valid = t0 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 15 */ + { + t0 = t0 - (205 * t0 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t0; + } + t_valid = t1 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) /* t1 < 15 */ + { + t1 = t1 - (205 * t1 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t1; + } +#elif MLDSA_ETA == 4 + t_valid = t0 < 9; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 9 */ + { + a[ctr++] = 4 - (int32_t)t0; + } + t_valid = t1 < 9; /* t1 < 9 */ + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) + { + a[ctr++] = 4 - (int32_t)t1; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + } + + mld_assert_abs_bound(a, ctr, MLDSA_ETA + 1); + + return ctr; +} + +static unsigned int mld_rej_eta(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ +#if MLDSA_ETA == 2 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta2_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#elif MLDSA_ETA == 4 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta4_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#endif /* !(MLDSA_ETA == 2 && MLD_USE_NATIVE_REJ_UNIFORM_ETA2) && MLDSA_ETA == \ + 4 && MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + + return mld_rej_eta_c(a, target, offset, buf, buflen); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_ETA_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof256_x4_ctx state; + unsigned buflen; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = nonce0; + extseed[1][MLDSA_CRHBYTES] = nonce1; + extseed[2][MLDSA_CRHBYTES] = nonce2; + extseed[3][MLDSA_CRHBYTES] = nonce3; + extseed[0][MLDSA_CRHBYTES + 1] = 0; + extseed[1][MLDSA_CRHBYTES + 1] = 0; + extseed[2][MLDSA_CRHBYTES + 1] = 0; + extseed[3][MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(r0, sizeof(mld_poly)), + memory_slice(r1, sizeof(mld_poly)), memory_slice(r2, sizeof(mld_poly)), + memory_slice(r3, sizeof(mld_poly)), object_whole(buf[0]), + object_whole(buf[1]), object_whole(buf[2]), + object_whole(buf[3])) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_abs_bound(r0->coeffs, 0, ctr[0], MLDSA_ETA + 1)) + invariant(array_abs_bound(r1->coeffs, 0, ctr[1], MLDSA_ETA + 1)) + invariant(array_abs_bound(r2->coeffs, 0, ctr[2], MLDSA_ETA + 1)) + invariant(array_abs_bound(r3->coeffs, 0, ctr[3], MLDSA_ETA + 1))) + { + mld_xof256_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + + mld_xof256_x4_release(&state); + + mld_assert_abs_bound(r0->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r1->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r2->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r3->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +{ + /* Temporary buffer for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr; + mld_xof256_ctx state; + unsigned buflen; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = nonce; + extseed[MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr = mld_rej_eta(r->coeffs, MLDSA_N, 0, buf, buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, object_whole(&state), + object_whole(buf), memory_slice(r, sizeof(mld_poly))) + invariant(ctr <= MLDSA_N) + invariant(state.pos <= SHAKE256_RATE) + invariant(array_abs_bound(r->coeffs, 0, ctr, MLDSA_ETA + 1))) + { + mld_xof256_squeezeblocks(buf, 1, &state); + ctr = mld_rej_eta(r->coeffs, MLDSA_N, ctr, buf, buflen); + } + + mld_xof256_release(&state); + + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define MLD_POLY_UNIFORM_GAMMA1_NBLOCKS \ + ((MLDSA_POLYZ_PACKEDBYTES + MLD_STREAM256_BLOCKBYTES - 1) / \ + MLD_STREAM256_BLOCKBYTES) + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + mld_xof256_ctx state; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = (uint8_t)(nonce & 0xFF); + extseed[MLDSA_CRHBYTES + 1] = (uint8_t)(nonce >> 8); + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + mld_polyz_unpack(a, buf); + + mld_xof256_release(&state); + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + mld_xof256_x4_ctx state; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = (uint8_t)(nonce0 & 0xFF); + extseed[1][MLDSA_CRHBYTES] = (uint8_t)(nonce1 & 0xFF); + extseed[2][MLDSA_CRHBYTES] = (uint8_t)(nonce2 & 0xFF); + extseed[3][MLDSA_CRHBYTES] = (uint8_t)(nonce3 & 0xFF); + extseed[0][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce0 >> 8); + extseed[1][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce1 >> 8); + extseed[2][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce2 >> 8); + extseed[3][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce3 >> 8); + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + + mld_polyz_unpack(r0, buf[0]); + mld_polyz_unpack(r1, buf[1]); + mld_polyz_unpack(r2, buf[2]); + mld_polyz_unpack(r3, buf[3]); + mld_xof256_x4_release(&state); + + mld_assert_bound(r0->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r1->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r2->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r3->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +{ + unsigned int i, j, pos; + uint64_t signs; + uint64_t offset; + MLD_ALIGN uint8_t buf[SHAKE256_RATE]; + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, seed, MLDSA_CTILDEBYTES); + mld_shake256_finalize(&state); + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + + /* Convert the first 8 bytes of buf[] into an unsigned 64-bit value. */ + /* Each bit of that dictates the sign of the resulting challenge value */ + signs = 0; + for (i = 0; i < 8; ++i) + __loop__( + assigns(i, signs) + invariant(i <= 8) + ) + { + signs |= (uint64_t)buf[i] << 8 * i; + } + pos = 8; + + mld_memset(c, 0, sizeof(mld_poly)); + + for (i = MLDSA_N - MLDSA_TAU; i < MLDSA_N; ++i) + __loop__( + assigns(i, j, object_whole(buf), state, pos, memory_slice(c, sizeof(mld_poly)), signs) + invariant(i >= MLDSA_N - MLDSA_TAU) + invariant(i <= MLDSA_N) + invariant(pos >= 1) + invariant(pos <= SHAKE256_RATE) + invariant(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) + invariant(state.pos <= SHAKE256_RATE) + ) + { + do + __loop__( + assigns(j, object_whole(buf), state, pos) + invariant(state.pos <= SHAKE256_RATE) + ) + { + if (pos >= SHAKE256_RATE) + { + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + pos = 0; + } + j = buf[pos++]; + } while (j > i); + + c->coeffs[i] = c->coeffs[j]; + + /* Reference: Compute coefficent value here in two steps to */ + /* mixinf unsigned and signed arithmetic with implicit */ + /* conversions, and so that CBMC can keep track of ranges */ + /* to complete type-safety proof here. */ + + /* The least-significant bit of signs tells us if we want -1 or +1 */ + offset = 2 * (signs & 1); + + /* offset has value 0 or 2 here, so (1 - (int32_t) offset) has + * value -1 or +1 */ + c->coeffs[j] = 1 - (int32_t)offset; + + /* Move to the next bit of signs for next time */ + signs >>= 1; + } + + mld_assert_bound(c->coeffs, MLDSA_N, -1, 2); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(&signs, sizeof(signs)); +} + +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint8_t t[8]; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_ETA + 1); + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 1]); + t[2] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 2]); + t[3] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 3]); + t[4] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 4]); + t[5] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 5]); + t[6] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 6]); + t[7] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 7]); + + r[3 * i + 0] = (uint8_t)(((t[0] >> 0) | (t[1] << 3) | (t[2] << 6)) & 0xFF); + r[3 * i + 1] = + (uint8_t)(((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)) & + 0xFF); + r[3 * i + 2] = (uint8_t)(((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)) & 0xFF); + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 1]); + r[i] = (uint8_t)(t[0] | (t[1] << 4)); + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ +} + +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -5, MLDSA_ETA + 1))) + { + r->coeffs[8 * i + 0] = (a[3 * i + 0] >> 0) & 7; + r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 7; + r->coeffs[8 * i + 2] = ((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 7; + r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 7; + r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 7; + r->coeffs[8 * i + 5] = ((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 7; + r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 7; + r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5) & 7; + + r->coeffs[8 * i + 0] = MLDSA_ETA - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = MLDSA_ETA - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = MLDSA_ETA - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = MLDSA_ETA - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = MLDSA_ETA - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = MLDSA_ETA - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = MLDSA_ETA - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = MLDSA_ETA - r->coeffs[8 * i + 7]; + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -11, MLDSA_ETA + 1))) + { + r->coeffs[2 * i + 0] = a[i] & 0x0F; + r->coeffs[2 * i + 1] = a[i] >> 4; + r->coeffs[2 * i + 0] = MLDSA_ETA - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_ETA - r->coeffs[2 * i + 1]; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + + mld_assert_bound(r->coeffs, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + + +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[4]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 1]); + t[2] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 2]); + t[3] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 3]); + + r[9 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[9 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[9 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[9 * i + 2] |= (uint8_t)((t[1] << 2) & 0xFF); + r[9 * i + 3] = (uint8_t)((t[1] >> 6) & 0xFF); + r[9 * i + 4] = (uint8_t)((t[1] >> 14) & 0xFF); + r[9 * i + 4] |= (uint8_t)((t[2] << 4) & 0xFF); + r[9 * i + 5] = (uint8_t)((t[2] >> 4) & 0xFF); + r[9 * i + 6] = (uint8_t)((t[2] >> 12) & 0xFF); + r[9 * i + 6] |= (uint8_t)((t[3] << 6) & 0xFF); + r[9 * i + 7] = (uint8_t)((t[3] >> 2) & 0xFF); + r[9 * i + 8] = (uint8_t)((t[3] >> 10) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 1]); + + r[5 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[5 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[5 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[5 * i + 2] |= (uint8_t)((t[1] << 4) & 0xFF); + r[5 * i + 3] = (uint8_t)((t[1] >> 4) & 0xFF); + r[5 * i + 4] = (uint8_t)((t[1] >> 12) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +MLD_STATIC_TESTABLE void mld_polyz_unpack_c( + mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +) +{ + unsigned int i; +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[4 * i + 0] = a[9 * i + 0]; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 2] << 16; + r->coeffs[4 * i + 0] &= 0x3FFFF; + + r->coeffs[4 * i + 1] = a[9 * i + 2] >> 2; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 3] << 6; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 4] << 14; + r->coeffs[4 * i + 1] &= 0x3FFFF; + + r->coeffs[4 * i + 2] = a[9 * i + 4] >> 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 5] << 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 6] << 12; + r->coeffs[4 * i + 2] &= 0x3FFFF; + + r->coeffs[4 * i + 3] = a[9 * i + 6] >> 6; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 7] << 2; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10; + r->coeffs[4 * i + 3] &= 0x3FFFF; + + r->coeffs[4 * i + 0] = MLDSA_GAMMA1 - r->coeffs[4 * i + 0]; + r->coeffs[4 * i + 1] = MLDSA_GAMMA1 - r->coeffs[4 * i + 1]; + r->coeffs[4 * i + 2] = MLDSA_GAMMA1 - r->coeffs[4 * i + 2]; + r->coeffs[4 * i + 3] = MLDSA_GAMMA1 - r->coeffs[4 * i + 3]; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[2 * i + 0] = a[5 * i + 0]; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 2] << 16; + r->coeffs[2 * i + 0] &= 0xFFFFF; + + r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 3] << 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12; + /* r->coeffs[2*i+1] &= 0xFFFFF; */ /* No effect, since we're anyway at 20 + bits */ + + r->coeffs[2 * i + 0] = MLDSA_GAMMA1 - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_GAMMA1 - r->coeffs[2 * i + 1]; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +{ +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + ret = mld_polyz_unpack_17_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#elif defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + ret = mld_polyz_unpack_19_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYZ_UNPACK_17 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLYZ_UNPACK_19 && (MLD_CONFIG_PARAMETER_SET == 65 \ + || MLD_CONFIG_PARAMETER_SET == 87) */ + + mld_polyz_unpack_c(r, a); +} + +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + + mld_assert_bound(a->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[3 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0]) & 0xFF); + r[3 * i + 0] |= (uint8_t)((a->coeffs[4 * i + 1] << 6) & 0xFF); + r[3 * i + 1] = (uint8_t)((a->coeffs[4 * i + 1] >> 2) & 0xFF); + r[3 * i + 1] |= (uint8_t)((a->coeffs[4 * i + 2] << 4) & 0xFF); + r[3 * i + 2] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) & 0xFF); + r[3 * i + 2] |= (uint8_t)((a->coeffs[4 * i + 3] << 2) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + r[i] = + (uint8_t)((a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_rej_eta +#undef mld_rej_eta_c +#undef mld_poly_decompose_c +#undef mld_poly_use_hint_c +#undef mld_polyz_unpack_c +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_GAMMA1_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/poly_kl.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/poly_kl.h new file mode 100644 index 0000000000..c6aa498358 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/poly_kl.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_KL_H +#define MLD_POLY_KL_H + +#include "cbmc.h" +#include "common.h" +#include "poly.h" + +#define mld_poly_decompose MLD_NAMESPACE_KL(poly_decompose) +/************************************************* + * Name: mld_poly_decompose + * + * Description: For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such c mod MLDSA_Q = c1*ALPHA + + * c0 with -ALPHA/2 < c0 <= ALPHA/2 except + * c1 = (MLDSA_Q-1)/ALPHA where we set + * c1 = 0 and -ALPHA/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + * c1 + * - mld_poly *a0: pointer to input/output polynomial. Output + * polynomial has coefficients c0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +); + + +#define mld_poly_make_hint MLD_NAMESPACE_KL(poly_make_hint) +/************************************************* + * Name: mld_poly_make_hint + * + * Description: Compute hint polynomial. The coefficients of which indicate + * whether the low bits of the corresponding coefficient of + * the input polynomial overflow into the high bits. + * + * Arguments: - mld_poly *h: pointer to output hint polynomial + * - const mld_poly *a0: pointer to low part of input polynomial + * - const mld_poly *a1: pointer to high part of input polynomial + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + assigns(memory_slice(h, sizeof(mld_poly))) + ensures(return_value <= MLDSA_N) + ensures(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) +); + +#define mld_poly_use_hint MLD_NAMESPACE_KL(poly_use_hint) +/************************************************* + * Name: mld_poly_use_hint + * + * Description: Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - mld_poly *b: pointer to output polynomial with corrected high + *bits + * - const mld_poly *a: pointer to input polynomial + * - const mld_poly *h: pointer to input hint polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta_4x MLD_NAMESPACE_KL(poly_uniform_eta_4x) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample four polynomials with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce_i) + * + * Arguments: - mld_poly *r0: pointer to first output polynomial + * - mld_poly *r1: pointer to second output polynomial + * - mld_poly *r2: pointer to third output polynomial + * - mld_poly *r3: pointer to fourth output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce0: first nonce + * - uint8_t nonce1: second nonce + * - uint8_t nonce2: third nonce + * - uint8_t nonce3: fourth nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_abs_bound(r0->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r1->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r2->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r3->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta MLD_NAMESPACE_KL(poly_uniform_eta) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample polynomial with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce: nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1 MLD_NAMESPACE_KL(poly_uniform_gamma1) +/************************************************* + * Name: mld_poly_uniform_gamma1 + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1_4x MLD_NAMESPACE_KL(poly_uniform_gamma1_4x) +/************************************************* + * Name: mld_poly_uniform_gamma1_4x + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_bound(r0->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r1->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r2->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r3->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define mld_poly_challenge MLD_NAMESPACE_KL(poly_challenge) +/************************************************* + * Name: mld_poly_challenge + * + * Description: Implementation of H. Samples polynomial with MLDSA_TAU nonzero + * coefficients in {-1,1} using the output stream of + * SHAKE256(seed). + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const uint8_t mu[]: byte array containing seed of length + * MLDSA_CTILDEBYTES + **************************************************/ +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +__contract__( + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CTILDEBYTES)) + assigns(memory_slice(c, sizeof(mld_poly))) + /* All coefficients of c are -1, 0 or +1 */ + ensures(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) +); + +#define mld_polyeta_pack MLD_NAMESPACE_KL(polyeta_pack) +/************************************************* + * Name: mld_polyeta_pack + * + * Description: Bit-pack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYETA_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + assigns(memory_slice(r, MLDSA_POLYETA_PACKEDBYTES)) +); + +/* + * polyeta_unpack produces coefficients in [-MLDSA_ETA,MLDSA_ETA] for + * well-formed inputs (i.e., those produced by polyeta_pack). + * However, when passed an arbitrary byte array, it may produce smaller values, + * i.e, values in [MLD_POLYETA_UNPACK_LOWER_BOUND,MLDSA_ETA] + * Even though this should never happen, we use use the bound for arbitrary + * inputs in the CBMC proofs. + */ +#if MLDSA_ETA == 2 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-5) +#elif MLDSA_ETA == 4 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-11) +#else +#error "Invalid value of MLDSA_ETA" +#endif + +#define mld_polyeta_unpack MLD_NAMESPACE_KL(polyeta_unpack) +/************************************************* + * Name: mld_polyeta_unpack + * + * Description: Unpack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYETA_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)) +); + +#define mld_polyz_pack MLD_NAMESPACE_KL(polyz_pack) +/************************************************* + * Name: mld_polyz_pack + * + * Description: Bit-pack polynomial with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYZ_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(r, MLDSA_POLYZ_PACKEDBYTES)) +); + + +#define mld_polyz_unpack MLD_NAMESPACE_KL(polyz_unpack) +/************************************************* + * Name: mld_polyz_unpack + * + * Description: Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); + +#define mld_polyw1_pack MLD_NAMESPACE_KL(polyw1_pack) +/************************************************* + * Name: mld_polyw1_pack + * + * Description: Bit-pack polynomial w1 with coefficients in [0,15] or [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES)) +); + +#endif /* !MLD_POLY_KL_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/polyvec.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/polyvec.c new file mode 100644 index 0000000000..5c3a08ab32 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/polyvec.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include +#include + +#include "common.h" +#include "debug.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" + +/* This namespacing is not done at the top to avoid a naming conflict + * with native backends, which are currently not yet namespaced. */ +#define mld_polymat_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polymat_permute_bitrev_to_custom) +#define mld_polyvecl_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polyvecl_permute_bitrev_to_custom) +#define mld_polyvecl_pointwise_acc_montgomery_c \ + MLD_ADD_PARAM_SET(mld_polyvecl_pointwise_acc_montgomery_c) + +#if !defined(MLD_CONFIG_REDUCE_RAM) +/* Helper function to ensure that the polynomial entries in the output + * of mld_polyvec_matrix_expand use the standard (bitreversed) ordering + * of coefficients. + * No-op unless a native backend with a custom ordering is used. + */ + +static void mld_polyvecl_permute_bitrev_to_custom(mld_polyvecl *v) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +{ +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + unsigned i; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_permute_bitrev_to_custom(v->vec[i].coeffs); + } +#else /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + /* Nothing to do */ + (void)v; +#endif /* !MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ +} + +static void mld_polymat_permute_bitrev_to_custom(mld_polymat *mat) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; i++) + __loop__( + assigns(i, memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))) + { + mld_polyvecl_permute_bitrev_to_custom(&mat->vec[i]); + } +} +#endif /* !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + unsigned int i; + MLD_ALIGN uint8_t seed_ext[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + mld_memcpy(seed_ext, mat->rho, MLDSA_SEEDBYTES); + + /* Generate row on-demand */ + for (i = 0; i < MLDSA_L; i++) + { + uint8_t x = (uint8_t)row; + uint8_t y = (uint8_t)i; + + seed_ext[MLDSA_SEEDBYTES + 0] = y; + seed_ext[MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(&mat->row_buffer.vec[i], seed_ext); + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + mld_poly_permute_bitrev_to_custom(mat->row_buffer.vec[i].coeffs); +#endif + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); + + return &mat->row_buffer; +#else /* MLD_CONFIG_REDUCE_RAM */ + return &mat->vec[row]; +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + /* In REDUCE_RAM mode, just copy the seed for later on-demand generation */ + mld_memcpy(mat->rho, rho, MLDSA_SEEDBYTES); +#else + unsigned int i, j; + /* + * We generate four separate seed arrays rather than a single one to work + * around limitations in CBMC function contracts dealing with disjoint slices + * of the same parent object. + */ + + MLD_ALIGN uint8_t seed_ext[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + mld_memcpy(seed_ext[j], rho, MLDSA_SEEDBYTES); + } + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + /* Sample 4 matrix entries a time. */ + for (i = 0; i < (MLDSA_K * MLDSA_L / 4) * 4; i += 4) + __loop__( + assigns(i, j, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= (MLDSA_K * MLDSA_L / 4) * 4 && i % 4 == 0) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + uint8_t x = (uint8_t)((i + j) / MLDSA_L); + uint8_t y = (uint8_t)((i + j) % MLDSA_L); + + seed_ext[j][MLDSA_SEEDBYTES + 0] = y; + seed_ext[j][MLDSA_SEEDBYTES + 1] = x; + } + + mld_poly_uniform_4x(&mat->vec[i / MLDSA_L].vec[i % MLDSA_L], + &mat->vec[(i + 1) / MLDSA_L].vec[(i + 1) % MLDSA_L], + &mat->vec[(i + 2) / MLDSA_L].vec[(i + 2) % MLDSA_L], + &mat->vec[(i + 3) / MLDSA_L].vec[(i + 3) % MLDSA_L], + seed_ext); + } +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + i = 0; +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + /* Entries omitted by the batch-sampling are sampled individually. */ + while (i < MLDSA_K * MLDSA_L) + __loop__( + assigns(i, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K * MLDSA_L) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + uint8_t x = (uint8_t)(i / MLDSA_L); + uint8_t y = (uint8_t)(i % MLDSA_L); + mld_poly *this_poly = &mat->vec[i / MLDSA_L].vec[i % MLDSA_L]; + + seed_ext[0][MLDSA_SEEDBYTES + 0] = y; + seed_ext[0][MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(this_poly, seed_ext[0]); + i++; + } + + mld_polymat_permute_bitrev_to_custom(mat); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(t, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + const mld_polyvecl *row = mld_polymat_get_row(mat, i); + mld_polyvecl_pointwise_acc_montgomery(&t->vec[i], row, v); + } + + mld_assert_abs_bound_2d(t->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_L **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; +#endif + + /* Safety: nonce is at most ((UINT16_MAX - MLDSA_L) / MLDSA_L), and, hence, + * this cast is safe. See MLD_NONCE_UB comment in sign.c. */ + nonce = (uint16_t)(MLDSA_L * nonce); + /* Now, nonce <= UINT16_MAX - (MLDSA_L - 1), so the casts below are safe. */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_gamma1(&v->vec[i], seed, (uint16_t)(nonce + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLDSA_L == 4 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); +#elif MLDSA_L == 5 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); + mld_poly_uniform_gamma1(&v->vec[4], seed, (uint16_t)(nonce + 4)); +#elif MLDSA_L == 7 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], + &v->vec[3 /* irrelevant */], seed, nonce, + (uint16_t)(nonce + 1), (uint16_t)(nonce + 2), + 0xFF /* irrelevant */); + mld_poly_uniform_gamma1_4x(&v->vec[3], &v->vec[4], &v->vec[5], &v->vec[6], + seed, (uint16_t)(nonce + 3), (uint16_t)(nonce + 4), + (uint16_t)(nonce + 5), (uint16_t)(nonce + 6)); +#endif /* MLDSA_L == 7 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(k0, i, MLDSA_L, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_STATIC_TESTABLE void mld_polyvecl_pointwise_acc_montgomery_c( + mld_poly *w, const mld_polyvecl *u, const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i, j; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + for (i = 0; i < MLDSA_N; i++) + __loop__( + assigns(i, j, memory_slice(w, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_abs_bound(w->coeffs, 0, i, MLDSA_Q)) + ) + { + int64_t t = 0; + int32_t r; + for (j = 0; j < MLDSA_L; j++) + __loop__( + assigns(j, t) + invariant(j <= MLDSA_L) + invariant(t >= -(int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + invariant(t <= (int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + ) + { + t += (int64_t)u->vec[j].coeffs[i] * v->vec[j].coeffs[i]; + } + + r = mld_montgomery_reduce(t); + w->coeffs[i] = r; + } + + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +{ +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) && \ + MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l4_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) && \ + MLD_CONFIG_PARAMETER_SET == 65 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l5_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) && \ + MLD_CONFIG_PARAMETER_SET == 87 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l7_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 && \ + MLD_CONFIG_PARAMETER_SET == 44) && \ + !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 && \ + MLD_CONFIG_PARAMETER_SET == 65) && \ + MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 && \ + MLD_CONFIG_PARAMETER_SET == 87 */ + /* The first input is bounded by [0, Q-1] inclusive + * The second input is bounded by [-9Q+1, 9Q-1] inclusive . Hence, we can + * safely accumulate in 64-bits without intermediate reductions as + * MLDSA_L * (MLD_NTT_BOUND-1) * (Q-1) < INT64_MAX + * + * The worst case is ML-DSA-87: 7 * (9Q-1) * (Q-1) < 2**52 + * (and likewise for negative values) + */ + mld_polyvecl_pointwise_acc_montgomery_c(w, u, v); +} + +MLD_INTERNAL_API +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + invariant(i <= MLDSA_L) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + return t; +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_K **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k2, 0, i, + array_bound(v->vec[k2].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ) + { + mld_poly_reduce(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_caddq(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, + forall(k1, 0, MLDSA_N, u->vec[k0].coeffs[k1] == loop_entry(*u).vec[k0].coeffs[k1]))) + invariant(forall(k6, 0, i, array_bound(u->vec[k6].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + ) + { + mld_poly_add(&u->vec[i], &v->vec[i]); + } + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(u->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, u->vec[k1].coeffs[n1] == loop_entry(*u).vec[k1].coeffs[n1])))) + { + mld_poly_sub(&u->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, v->vec[k1].coeffs[n1] == loop_entry(*v).vec[k1].coeffs[n1]))) + ) + { + mld_poly_shiftl(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))) + { + mld_poly_invntt_tomont(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_INTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, array_abs_bound(r->vec[k2].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + mld_poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]); + } + mld_assert_abs_bound_2d(r->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + + return t; +} + +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + invariant(forall(k2, 0, i, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) + ) + { + mld_poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +{ + unsigned int i; + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + invariant(forall(k2, 0, i, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) + invariant(forall(k3, i, MLDSA_K, + array_bound(v0->vec[k3].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + ) + { + mld_poly_decompose(&v1->vec[i], &v0->vec[i]); + } + + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + mld_assert_abs_bound_2d(v0->vec, MLDSA_K, MLDSA_N, MLDSA_GAMMA2 + 1); +} + +MLD_INTERNAL_API +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, s, memory_slice(h, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(s <= i * MLDSA_N) + invariant(forall(k1, 0, i, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + s += mld_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]); + } + + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + return s; +} + +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *u, + const mld_polyveck *h) +{ + unsigned int i; + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(w, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)))) + ) + { + mld_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]); + } + + mld_assert_bound_2d(w->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +{ + unsigned int i; + mld_assert_bound_2d(w1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyw1_pack(&r[i * MLDSA_POLYW1_PACKEDBYTES], &w1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt0_pack(&r[i * MLDSA_POLYT0_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyz_unpack(&z->vec[i], r + i * MLDSA_POLYZ_PACKEDBYTES); + } + + mld_assert_bound_2d(z->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt0_unpack(&p->vec[i], r + i * MLDSA_POLYT0_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_polymat_permute_bitrev_to_custom +#undef mld_polyvecl_permute_bitrev_to_custom +#undef mld_polyvecl_pointwise_acc_montgomery_c diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/polyvec.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/polyvec.h new file mode 100644 index 0000000000..d21abc02ff --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/polyvec.h @@ -0,0 +1,725 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLYVEC_H +#define MLD_POLYVEC_H + +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "poly_kl.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_polyvecl MLD_ADD_PARAM_SET(mld_polyvecl) +#define mld_polyveck MLD_ADD_PARAM_SET(mld_polyveck) +#define mld_polymat MLD_ADD_PARAM_SET(mld_polymat) +/* End of parameter set namespacing */ + +/* Vectors of polynomials of length MLDSA_L */ +typedef struct +{ + mld_poly vec[MLDSA_L]; +} mld_polyvecl; + + +#define mld_polyvecl_uniform_gamma1 MLD_NAMESPACE_KL(polyvecl_uniform_gamma1) +/************************************************* + * Name: mld_polyvecl_uniform_gamma1 + * + * Description: Sample vector of polynomials with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_polyvecl *v: pointer to output vector + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + *************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + requires(nonce <= (UINT16_MAX - MLDSA_L) / MLDSA_L) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyvecl_ntt MLD_NAMESPACE_KL(polyvecl_ntt) +/************************************************* + * Name: mld_polyvecl_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_L. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyvecl *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k0, 0, MLDSA_L, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyvecl_pointwise_acc_montgomery \ + MLD_NAMESPACE_KL(polyvecl_pointwise_acc_montgomery) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery + * + * Description: Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * The first input "u" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * + * Arguments: - mld_poly *w: output polynomial + * - const mld_polyvecl *u: pointer to first input vector + * - const mld_polyvecl *v: pointer to second input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + + +#define mld_polyvecl_chknorm MLD_NAMESPACE_KL(polyvecl_chknorm) +/************************************************* + * Name: mld_polyvecl_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_L. + * Assumes input mld_polyvecl to be reduced by polyvecl_reduce(). + * + * Arguments: - const mld_polyvecl *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials is strictly smaller than B <= + * (MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +/* Vectors of polynomials of length MLDSA_K */ +typedef struct +{ + mld_poly vec[MLDSA_K]; +} mld_polyveck; + +/* Matrix of polynomials (K x L) */ +typedef struct +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + mld_polyvecl row_buffer; + uint8_t rho[MLDSA_SEEDBYTES]; +#else + mld_polyvecl vec[MLDSA_K]; +#endif +} mld_polymat; + +#define mld_polyveck_reduce MLD_NAMESPACE_KL(polyveck_reduce) +/************************************************* + * Name: polyveck_reduce + * + * Description: Reduce coefficients of polynomials in vector of length MLDSA_K + * to representatives in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) +); + +#define mld_polyveck_caddq MLD_NAMESPACE_KL(polyveck_caddq) +/************************************************* + * Name: mld_polyveck_caddq + * + * Description: For all coefficients of polynomials in vector of length MLDSA_K + * add MLDSA_Q if coefficient is negative. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_add MLD_NAMESPACE_KL(polyveck_add) +/************************************************* + * Name: mld_polyveck_add + * + * Description: Add vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to input-output vector of polynomials + * to be added to + * - const mld_polyveck *v: pointer to second input vector of + * polynomials + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(p0, 0, MLDSA_K, array_abs_bound(u->vec[p0].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) + requires(forall(p1, 0, MLDSA_K, + array_bound(v->vec[p1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(q2, 0, MLDSA_K, + array_bound(u->vec[q2].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_sub MLD_NAMESPACE_KL(polyveck_sub) +/************************************************* + * Name: mld_polyveck_sub + * + * Description: Subtract vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to first input vector + * - const mld_polyveck *v: pointer to second input vector to be + * subtracted from first input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(u->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_shiftl MLD_NAMESPACE_KL(polyveck_shiftl) +/************************************************* + * Name: mld_polyveck_shiftl + * + * Description: Multiply vector of polynomials of Length MLDSA_K by 2^MLDSA_D + *without modular reduction. Assumes input coefficients to be less than + *2^{31-MLDSA_D}. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_ntt MLD_NAMESPACE_KL(polyveck_ntt) +/************************************************* + * Name: mld_polyveck_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_K. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyveck_invntt_tomont MLD_NAMESPACE_KL(polyveck_invntt_tomont) +/************************************************* + * Name: mld_polyveck_invntt_tomont + * + * Description: Inverse NTT and multiplication by 2^{32} of polynomials + * in vector of length MLDSA_K. + * Input coefficients need to be less than MLDSA_Q, and + * Output coefficients are bounded by MLD_INTT_BOUND. + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) +); + +#define mld_polyveck_pointwise_poly_montgomery \ + MLD_NAMESPACE_KL(polyveck_pointwise_poly_montgomery) +/************************************************* + * Name: mld_polyveck_pointwise_poly_montgomery + * + * Description: Pointwise multiplication of a polynomial vector of length + * MLDSA_K by a single polynomial in NTT domain and multiplication + * of the resulting polynomial vector by 2^{-32}. + * + * Arguments: - mld_polyveck *r: pointer to output vector + * - mld_poly *a: pointer to input polynomial + * - mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(r, sizeof(mld_polyveck))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(r, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(r->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#define mld_polyveck_chknorm MLD_NAMESPACE_KL(polyveck_chknorm) +/************************************************* + * Name: mld_polyveck_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_K. + * Assumes input mld_polyveck to be reduced by polyveck_reduce(). + * + * Arguments: - const mld_polyveck *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials are strictly smaller than B <= + *(MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, + -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +#define mld_polyveck_power2round MLD_NAMESPACE_KL(polyveck_power2round) +/************************************************* + * Name: mld_polyveck_power2round + * + * Description: For all coefficients a of polynomials in vector of length + *MLDSA_K, compute a0, a1 such that a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with + *-2^{MLDSA_D-1} < a0 <= 2^{MLDSA_D-1}. Assumes coefficients to be standard + *representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to output vector of polynomials with + * coefficients a0 + * - const mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) +); + +#define mld_polyveck_decompose MLD_NAMESPACE_KL(polyveck_decompose) +/************************************************* + * Name: mld_polyveck_decompose + * + * Description: For all coefficients a of polynomials in vector of length + * MLDSA_K, compute high and low bits a0, a1 such a mod^+ MLDSA_Q = a1*ALPHA + * + a0 with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (MLDSA_Q-1)/ALPHA where we set + * a1 = 0 and -ALPHA/2 <= a0 = a mod MLDSA_Q - MLDSA_Q < 0. Assumes coefficients + * to be standard representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to input/output vector of + * polynomials with. Output polynomial has + * coefficients a0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v0->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + ensures(forall(k2, 0, MLDSA_K, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) +); + +#define mld_polyveck_make_hint MLD_NAMESPACE_KL(polyveck_make_hint) +/************************************************* + * Name: mld_polyveck_make_hint + * + * Description: Compute hint vector. + * + * Arguments: - mld_polyveck *h: pointer to output vector + * - const mld_polyveck *v0: pointer to low part of input vector + * - const mld_polyveck *v1: pointer to high part of input vector + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(return_value <= MLDSA_N * MLDSA_K) + ensures(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) +); + +#define mld_polyveck_use_hint MLD_NAMESPACE_KL(polyveck_use_hint) +/************************************************* + * Name: mld_polyveck_use_hint + * + * Description: Use hint vector to correct the high bits of input vector. + * + * Arguments: - mld_polyveck *w: pointer to output vector of polynomials with + * corrected high bits + * - const mld_polyveck *u: pointer to input vector + * - const mld_polyveck *h: pointer to input hint vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *v, + const mld_polyveck *h) +__contract__( + requires(memory_no_alias(w, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + assigns(memory_slice(w, sizeof(mld_polyveck))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) +); + +#define mld_polyveck_pack_w1 MLD_NAMESPACE_KL(polyveck_pack_w1) +/************************************************* + * Name: mld_polyveck_pack_w1 + * + * Description: Bit-pack polynomial vector w1 with coefficients in [0,15] or + * [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_K* MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_polyveck *a: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(w1, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(w1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) +); + +#define mld_polyveck_pack_eta MLD_NAMESPACE_KL(polyveck_pack_eta) +/************************************************* + * Name: mld_polyveck_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients + * in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyvecl_pack_eta MLD_NAMESPACE_KL(polyvecl_pack_eta) +/************************************************* + * Name: mld_polyvecl_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_L * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyveck_pack_t0 MLD_NAMESPACE_KL(polyveck_pack_t0) +/************************************************* + * Name: mld_polyveck_pack_t0 + * + * Description: Bit-pack polynomial vector to with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(p->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) +); + +#define mld_polyvecl_unpack_eta MLD_NAMESPACE_KL(polyvecl_unpack_eta) +/************************************************* + * Name: mld_polyvecl_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyvecl *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + assigns(memory_slice(p, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyvecl_unpack_z MLD_NAMESPACE_KL(polyvecl_unpack_z) +/************************************************* + * Name: mld_polyvecl_unpack_z + * + * Description: Unpack polynomial vector with coefficients in + * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_polyvecl *z: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(z->vec[k1].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyveck_unpack_eta MLD_NAMESPACE_KL(polyveck_unpack_eta) +/************************************************* + * Name: mld_polyveck_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyveck_unpack_t0 MLD_NAMESPACE_KL(polyveck_unpack_t0) +/************************************************* + * Name: mld_polyveck_unpack_t0 + * + * Description: Unpack polynomial vector with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) +); + +#define mld_polymat_get_row MLD_NAMESPACE_KL(polymat_get_row) +/************************************************* + * Name: mld_polymat_get_row + * + * Description: Retrieve a pointer to a specific row of the matrix. + * In MLD_CONFIG_REDUCE_RAM mode, generates the row on-demand. + * + * Arguments: - mld_polymat *mat: pointer to matrix + * - unsigned int row: row index (must be < MLDSA_K) + * + * Returns pointer to the row (mld_polyvecl) + **************************************************/ +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row); + +#define mld_polyvec_matrix_expand MLD_NAMESPACE_KL(polyvec_matrix_expand) +/************************************************* + * Name: mld_polyvec_matrix_expand + * + * Description: Implementation of ExpandA. Generates matrix A with uniformly + * random coefficients a_{i,j} by performing rejection + * sampling on the output stream of SHAKE128(rho|j|i) + * + * Arguments: - mld_polymat *mat: pointer to output matrix + * - const uint8_t rho[]: byte array containing seed rho + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +__contract__( + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +); + + + +#define mld_polyvec_matrix_pointwise_montgomery \ + MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery) +/************************************************* + * Name: mld_polyvec_matrix_pointwise_montgomery + * + * Description: Compute matrix-vector multiplication in NTT domain with + * pointwise multiplication and multiplication by 2^{-32}. + * Input matrix and vector must be in NTT domain representation. + * + * The first input "mat" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * Note: In MLD_CONFIG_REDUCE_RAM mode, mat cannot be const + * as rows are generated on-demand. + * + * Arguments: - mld_polyveck *t: pointer to output vector t + * - mld_polymat *mat: pointer to input matrix + * - const mld_polyvecl *v: pointer to input vector v + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(t, sizeof(mld_polyveck))) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(t, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#endif /* !MLD_POLYVEC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/randombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/randombytes.h new file mode 100644 index 0000000000..da55772419 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/randombytes.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_RANDOMBYTES_H +#define MLD_RANDOMBYTES_H + +#include +#include + +#include "cbmc.h" +#include "common.h" + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +#if !defined(MLD_CONFIG_CUSTOM_RANDOMBYTES) +MLD_MUST_CHECK_RETURN_VALUE +int randombytes(uint8_t *out, size_t outlen); +static MLD_INLINE int mld_randombytes(uint8_t *out, size_t outlen) +__contract__( + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) { return randombytes(out, outlen); } +#endif /* !MLD_CONFIG_CUSTOM_RANDOMBYTES */ +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ +#endif /* !MLD_RANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/reduce.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/reduce.h new file mode 100644 index 0000000000..413cf1829e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/reduce.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_REDUCE_H +#define MLD_REDUCE_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* check-magic: -4186625 == pow(2,32,MLDSA_Q) */ +#define MLD_MONT -4186625 + +/* Upper bound for domain of mld_reduce32() */ +#define MLD_REDUCE32_DOMAIN_MAX (INT32_MAX - (1 << 22)) + +/* Absolute bound for range of mld_reduce32() */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define MLD_REDUCE32_RANGE_MAX 6283009 + +/************************************************* + * Name: mld_montgomery_reduce + * + * Description: Generic Montgomery reduction; given a 64-bit integer a, computes + * 32-bit integer congruent to a * R^-1 mod q, where R=2^32 + * + * Arguments: - int64_t a: input integer to be reduced, of absolute value + * smaller or equal to INT64_MAX - 2^31 * MLDSA_Q. + * + * Returns: Integer congruent to a * R^-1 modulo q, with absolute value + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * In particular, if |a| < 2^31 * MLDSA_Q, the absolute value + * of the return value is < MLDSA_Q. + **************************************************/ +static MLD_INLINE int32_t mld_montgomery_reduce(int64_t a) +__contract__( + /* We don't attempt to express an input-dependent output bound + * as the post-condition here, as all call-sites satisfy the + * absolute input bound 2^31 * MLDSA_Q and higher-level + * reasoning can be conducted using |return_value| < MLDSA_Q. */ + requires(a > -(((int64_t)1 << 31) * MLDSA_Q) && + a < (((int64_t)1 << 31) * MLDSA_Q)) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* check-magic: 58728449 == unsigned_mod(pow(MLDSA_Q, -1, 2^32), 2^32) */ + const uint64_t QINV = 58728449; + + /* Compute a*q^{-1} mod 2^32 in unsigned representatives */ + const uint32_t a_reduced = mld_cast_int64_to_uint32(a); + const uint32_t a_inverted = (a_reduced * QINV) & UINT32_MAX; + + /* Lift to signed canonical representative mod 2^32. */ + const int32_t t = mld_cast_uint32_to_int32(a_inverted); + + int64_t r; + + mld_assert(a < +(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)) && + a > -(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q))); + + r = a - (int64_t)t * MLDSA_Q; + + /* + * PORTABILITY: Right-shift on a signed integer is, strictly-speaking, + * implementation-defined for negative left argument. Here, + * we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5)) + */ + r = r >> 32; + + /* Bounds: + * + * By construction of the Montgomery multiplication, by the time we + * compute r >> 32, r is divisible by 2^32, and hence + * + * |r >> 32| = |r| / 2^32 + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * (In general, we would only have |x >> n| <= ceil(|x| / 2^n)). + * + * In particular, if |a| < 2^31 * MLDSA_Q, then |return_value| < MLDSA_Q. + */ + return (int32_t)r; +} + +/************************************************* + * Name: mld_reduce32 + * + * Description: For finite field element a with a <= 2^{31} - 2^{22} - 1, + * compute r \equiv a (mod MLDSA_Q) such that + * -MLD_REDUCE32_RANGE_MAX <= r < MLD_REDUCE32_RANGE_MAX. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_reduce32(int32_t a) +__contract__( + requires(a <= MLD_REDUCE32_DOMAIN_MAX) + ensures(return_value >= -MLD_REDUCE32_RANGE_MAX) + ensures(return_value < MLD_REDUCE32_RANGE_MAX) +) +{ + int32_t t; + + t = (a + (1 << 22)) >> 23; + t = a - t * MLDSA_Q; + mld_assert((t - a) % MLDSA_Q == 0); + return t; +} + +/************************************************* + * Name: mld_caddq + * + * Description: Add MLDSA_Q if input coefficient is negative. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_caddq(int32_t a) +__contract__( + requires(a > -MLDSA_Q) + requires(a < MLDSA_Q) + ensures(return_value >= 0) + ensures(return_value < MLDSA_Q) + ensures(return_value == (a >= 0) ? a : (a + MLDSA_Q)) +) +{ + return mld_ct_sel_int32(a + MLDSA_Q, a, mld_ct_cmask_neg_i32(a)); +} + + +#endif /* !MLD_REDUCE_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/rounding.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/rounding.h new file mode 100644 index 0000000000..a83562b0f1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/rounding.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_ROUNDING_H +#define MLD_ROUNDING_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_power2round MLD_ADD_PARAM_SET(mld_power2round) +#define mld_decompose MLD_ADD_PARAM_SET(mld_decompose) +#define mld_make_hint MLD_ADD_PARAM_SET(mld_make_hint) +#define mld_use_hint MLD_ADD_PARAM_SET(mld_use_hint) +/* End of parameter set namespacing */ + +#define MLD_2_POW_D (1 << MLDSA_D) + +/************************************************* + * Name: mld_power2round + * + * Description: For finite field element a, compute a0, a1 such that + * a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with -2^{MLDSA_D-1} < a0 <= + * 2^{MLDSA_D-1}. Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: In the reference implementation, a1 is passed as a + * return value instead. + **************************************************/ +static MLD_INLINE void mld_power2round(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + ensures(*a0 > -(MLD_2_POW_D/2) && *a0 <= (MLD_2_POW_D/2)) + ensures(*a1 >= 0 && *a1 <= (MLDSA_Q - 1) / MLD_2_POW_D) + ensures((*a1 * MLD_2_POW_D + *a0 - a) % MLDSA_Q == 0) +) +{ + *a1 = (a + (1 << (MLDSA_D - 1)) - 1) >> MLDSA_D; + *a0 = a - (*a1 << MLDSA_D); +} + +/************************************************* + * Name: mld_decompose + * + * Description: For finite field element a, compute high and low bits a0, a1 + * such that a mod^+ MLDSA_Q = a1* 2 * MLDSA_GAMMA2 + a0 with + * -MLDSA_GAMMA2 < a0 <= MLDSA_GAMMA2 except + * if a1 = (MLDSA_Q-1)/(MLDSA_GAMMA2*2) where we set a1 = 0 and + * -MLDSA_GAMMA2 <= a0 = a mod^+ MLDSA_Q - MLDSA_Q < 0. + * Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: a1 is passed as a return value instead + **************************************************/ +static MLD_INLINE void mld_decompose(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + /* a0 = -MLDSA_GAMMA2 can only occur when (q-1) = a - (a mod MLDSA_GAMMA2), + * then a1=1; and a0 = a - (a mod MLDSA_GAMMA2) - 1 (@[FIPS204, Algorithm 36 (Decompose)]) */ + ensures(*a0 >= -MLDSA_GAMMA2 && *a0 <= MLDSA_GAMMA2) + ensures(*a1 >= 0 && *a1 < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) + ensures((*a1 * 2 * MLDSA_GAMMA2 + *a0 - a) % MLDSA_Q == 0) +) +{ + /* + * The goal is to compute f1 = round-(f / (2*GAMMA2)), which can be computed + * alternatively as round-(f / (128B)) = round-(ceil(f / 128) / B) where + * B = 2*GAMMA2 / 128. Here round-() denotes "round half down". + * + * The equality round-(f / (128B)) = round-(ceil(f / 128) / B) can deduced + * as follows. Since changing f to align-up(f, 128) can move f onto but not + * across a rounding boundary for division by 128*B (note that we need B to be + * even for this to work), and round- rounds down on the boundary, we have + * + * round-(f / (128B)) = round-(align-up(f, 128) / (128B)) + * = round-((align-up(f, 128) / 128) / B) + * = round-(ceil(f / 128) / B). + */ + *a1 = (a + 127) >> 7; + /* We know a >= 0 and a < MLDSA_Q, so... */ + /* check-magic: 65472 == round((MLDSA_Q-1)/128) */ + mld_assert(*a1 >= 0 && *a1 <= 65472); + +#if MLD_CONFIG_PARAMETER_SET == 44 + /* check-magic: 1488 == 2 * intdiv(intdiv(MLDSA_Q - 1, 88), 128) */ + /* check-magic: 11275 == floor(2**24 / 1488) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + */ + *a1 = (*a1 * 11275 + (1 << 23)) >> 24; + mld_assert(*a1 >= 0 && *a1 <= 44); + + *a1 = mld_ct_sel_int32(0, *a1, mld_ct_cmask_neg_i32(43 - *a1)); + mld_assert(*a1 >= 0 && *a1 <= 43); +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + /* check-magic: 4092 == 2 * intdiv(intdiv(MLDSA_Q - 1, 32), 128) */ + /* check-magic: 1025 == floor(2**22 / 4092) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + */ + *a1 = (*a1 * 1025 + (1 << 21)) >> 22; + mld_assert(*a1 >= 0 && *a1 <= 16); + + *a1 &= 15; + mld_assert(*a1 >= 0 && *a1 <= 15); + +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + + *a0 = a - *a1 * 2 * MLDSA_GAMMA2; + *a0 = mld_ct_sel_int32(*a0 - MLDSA_Q, *a0, + mld_ct_cmask_neg_i32((MLDSA_Q - 1) / 2 - *a0)); +} + +/************************************************* + * Name: mld_make_hint + * + * Description: Compute hint bit indicating whether the low bits of the + * input element overflow into the high bits. + * + * Arguments: - int32_t a0: low bits of input element + * - int32_t a1: high bits of input element + * + * Returns 1 if overflow, 0 otherwise + **************************************************/ +static MLD_INLINE unsigned int mld_make_hint(int32_t a0, int32_t a1) +__contract__( + ensures(return_value >= 0 && return_value <= 1) +) +{ + if (a0 > MLDSA_GAMMA2 || a0 < -MLDSA_GAMMA2 || + (a0 == -MLDSA_GAMMA2 && a1 != 0)) + { + return 1; + } + + return 0; +} + +/************************************************* + * Name: mld_use_hint + * + * Description: Correct high bits according to hint. + * + * Arguments: - int32_t a: input element + * - int32_t hint: hint bit + * + * Returns corrected high bits. + **************************************************/ +static MLD_INLINE int32_t mld_use_hint(int32_t a, int32_t hint) +__contract__( + requires(hint >= 0 && hint <= 1) + requires(a >= 0 && a < MLDSA_Q) + ensures(return_value >= 0 && return_value < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) +) +{ + int32_t a0, a1; + + mld_decompose(&a0, &a1, a); + if (hint == 0) + { + return a1; + } + +#if MLD_CONFIG_PARAMETER_SET == 44 + if (a0 > 0) + { + return (a1 == 43) ? 0 : a1 + 1; + } + else + { + return (a1 == 0) ? 43 : a1 - 1; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + if (a0 > 0) + { + return (a1 + 1) & 15; + } + else + { + return (a1 - 1) & 15; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + + +#endif /* !MLD_ROUNDING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/sign.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/sign.c new file mode 100644 index 0000000000..32bba52d65 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/sign.c @@ -0,0 +1,1508 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [Round3_Spec] + * CRYSTALS-Dilithium Algorithm Specifications and Supporting Documentation + * (Version 3.1) + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf + */ + +#include +#include + +#include "cbmc.h" +#include "ct.h" +#include "debug.h" +#include "packing.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" +#include "randombytes.h" +#include "sign.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_check_pct MLD_ADD_PARAM_SET(mld_check_pct) MLD_CONTEXT_PARAMETERS_2 +#define mld_sample_s1_s2 MLD_ADD_PARAM_SET(mld_sample_s1_s2) +#define mld_validate_hash_length MLD_ADD_PARAM_SET(mld_validate_hash_length) +#define mld_get_hash_oid MLD_ADD_PARAM_SET(mld_get_hash_oid) +#define mld_H MLD_ADD_PARAM_SET(mld_H) +#define mld_compute_pack_z MLD_ADD_PARAM_SET(mld_compute_pack_z) +#define mld_attempt_signature_generation \ + MLD_ADD_PARAM_SET(mld_attempt_signature_generation) MLD_CONTEXT_PARAMETERS_8 +#define mld_compute_t0_t1_tr_from_sk_components \ + MLD_ADD_PARAM_SET(mld_compute_t0_t1_tr_from_sk_components) \ + MLD_CONTEXT_PARAMETERS_7 +/* End of parameter set namespacing */ + + +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + ensures(return_value == 0 + || return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL) +); + +#if defined(MLD_CONFIG_KEYGEN_PCT) +/************************************************* + * @[FIPS140_3_IG] + * (https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf) + * + * TE10.35.02: Pair-wise Consistency Test (PCT) for DSA keypairs + * + * Purpose: Validates that a generated public/private key pair can correctly + * sign and verify data. Test performs signature generation using the private + * key (sk), followed by signature verification using the public key (pk). + * Returns 0 if the signature was successfully verified, non-zero if it cannot. + * + * Note: @[FIPS204] requires that public/private key pairs are to be used only + * for the calculation and/of verification of digital signatures. + **************************************************/ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t message[1] = {0}; + size_t siglen; + int ret; + MLD_ALLOC(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + MLD_ALLOC(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + + if (signature == NULL || pk_test == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Copy public key for testing */ + mld_memcpy(pk_test, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* Sign a test message using the original secret key */ + ret = mld_sign_signature(signature, &siglen, message, sizeof(message), NULL, + 0, sk, context); + if (ret != 0) + { + goto cleanup; + } + +#if defined(MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST) + /* Deliberately break public key for testing purposes */ + if (mld_break_pct()) + { + pk_test[0] = ~pk_test[0]; + } +#endif /* MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST */ + + /* Verify the signature using the (potentially corrupted) public key */ + ret = mld_sign_verify(signature, siglen, message, sizeof(message), NULL, 0, + pk_test, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + MLD_FREE(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + + return ret; +} +#else /* MLD_CONFIG_KEYGEN_PCT */ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + /* Skip PCT */ + ((void)pk); + ((void)sk); +#if defined(MLD_CONFIG_CONTEXT_PARAMETER) + ((void)context); +#endif + return 0; +} +#endif /* !MLD_CONFIG_KEYGEN_PCT */ + +static void mld_sample_s1_s2(mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t seed[MLDSA_CRHBYTES]) +__contract__( + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(object_whole(s1), object_whole(s2)) + ensures(forall(l0, 0, MLDSA_L, array_abs_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + ensures(forall(k0, 0, MLDSA_K, array_abs_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) +) +{ +/* Sample short vectors s1 and s2 */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; + uint16_t nonce = 0; + /* Safety: The nonces are at most 14 (MLDSA_L + MLDSA_K - 1), and, hence, the + * casts are safe. */ + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_eta(&s1->vec[i], seed, (uint8_t)(nonce + i)); + } + for (i = 0; i < MLDSA_K; i++) + { + mld_poly_uniform_eta(&s2->vec[i], seed, (uint8_t)(nonce + MLDSA_L + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLD_CONFIG_PARAMETER_SET == 44 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 4, 5, 6, 7); +#elif MLD_CONFIG_PARAMETER_SET == 65 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s2->vec[0], &s2->vec[1], + &s2->vec[2] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[2], &s2->vec[3], &s2->vec[4], &s2->vec[5], + seed, 7, 8, 9, 10); +#elif MLD_CONFIG_PARAMETER_SET == 87 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s1->vec[5], &s1->vec[6], + &s2->vec[0] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 7, 8, 9, 10); + mld_poly_uniform_eta_4x(&s2->vec[4], &s2->vec[5], &s2->vec[6], &s2->vec[7], + seed, 11, 12, 13, 14); +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ +} + +/************************************************* + * Name: mld_compute_t0_t1_tr_from_sk_components + * + * Description: Computes t0, t1, tr, and pk from secret key components + * rho, s1, s2. This is the shared computation used by + * both keygen and generating the public key from the + * secret key. + * + * Arguments: - mld_polyveck *t0: output t0 + * - mld_polyveck *t1: output t1 + * - uint8_t tr[MLDSA_TRBYTES]: output tr + * - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t rho[MLDSA_SEEDBYTES]: input rho + * - const mld_polyvecl *s1: input s1 + * - const mld_polyveck *s2: input s2 + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_t0_t1_tr_from_sk_components( + mld_polyveck *t0, mld_polyveck *t1, uint8_t tr[MLDSA_TRBYTES], + uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], const uint8_t rho[MLDSA_SEEDBYTES], + const mld_polyvecl *s1, const mld_polyveck *s2, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(l0, 0, MLDSA_L, array_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + requires(forall(k0, 0, MLDSA_K, array_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(forall(k1, 0, MLDSA_K, array_bound(t0->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(t1->vec[k2].coeffs, 0, MLDSA_N, 0, 1 << 10))) + ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY)) +{ + int ret; + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1hat, mld_polyvecl, 1, context); + MLD_ALLOC(t, mld_polyveck, 1, context); + + if (mat == NULL || s1hat == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Expand matrix */ + mld_polyvec_matrix_expand(mat, rho); + + /* Matrix-vector multiplication */ + *s1hat = *s1; + mld_polyvecl_ntt(s1hat); + mld_polyvec_matrix_pointwise_montgomery(t, mat, s1hat); + mld_polyveck_invntt_tomont(t); + + /* Add error vector s2 */ + mld_polyveck_add(t, s2); + + /* Reference: The following reduction is not present in the reference + * implementation. Omitting this reduction requires the output of + * the invntt to be small enough such that the addition of s2 does + * not result in absolute values >= MLDSA_Q. While our C, x86_64, + * and AArch64 invntt implementations produce small enough + * values for this to work out, it complicates the bounds + * reasoning. We instead add an additional reduction, and can + * consequently, relax the bounds requirements for the invntt. + */ + mld_polyveck_reduce(t); + + /* Decompose to get t1, t0 */ + mld_polyveck_caddq(t); + mld_polyveck_power2round(t1, t0, t); + + /* Pack public key and compute tr */ + mld_pack_pk(pk, rho, t1); + mld_shake256(tr, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + ret = 0; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_polyveck, 1, context); + MLD_FREE(s1hat, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + const uint8_t *rho, *rhoprime, *key; + MLD_ALLOC(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + MLD_ALLOC(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + + if (seedbuf == NULL || inbuf == NULL || tr == NULL || s1 == NULL || + s2 == NULL || t1 == NULL || t0 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Get randomness for rho, rhoprime and key */ + mld_memcpy(inbuf, seed, MLDSA_SEEDBYTES); + inbuf[MLDSA_SEEDBYTES + 0] = MLDSA_K; + inbuf[MLDSA_SEEDBYTES + 1] = MLDSA_L; + mld_shake256(seedbuf, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, inbuf, + MLDSA_SEEDBYTES + 2); + rho = seedbuf; + rhoprime = rho + MLDSA_SEEDBYTES; + key = rhoprime + MLDSA_CRHBYTES; + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + + /* Sample s1 and s2 */ + mld_sample_s1_s2(s1, s2, rhoprime); + + /* Compute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0, t1, tr, pk, rho, s1, s2, + context); + if (ret != 0) + { + goto cleanup; + } + + /* Pack secret key */ + mld_pack_sk(sk, rho, tr, key, t0, s1, s2); + + /* Constant time: pk is the public key, inherently public data */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_FREE(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + + if (ret != 0) + { + return ret; + } + + /* Pairwise Consistency Test (PCT) @[FIPS140_3_IG, p.87] */ + /* Do this after freeing all temporaries. */ + return mld_check_pct(pk, sk, context); +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t seed[MLDSA_SEEDBYTES]; + int ret; + if (mld_randombytes(seed, MLDSA_SEEDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(seed, sizeof(seed)); + ret = mld_sign_keypair_internal(pk, sk, seed, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed, sizeof(seed)); + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +/************************************************* + * Name: mld_H + * + * Description: Abstracts application of SHAKE256 to + * one, two or three blocks of data, + * yielding a user-requested size of + * output. + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in1: pointer to input block 1 + * Must NOT be NULL + * - size_t in1len: length of input in1 bytes + * - const uint8_t *in2: pointer to input block 2 + * May be NULL if in2len=0, in which case + * this block is ignored + * - size_t in2len: length of input in2 bytes + * - const uint8_t *in3: pointer to input block 3 + * May be NULL if in3len=0, in which case + * this block is ignored + * - size_t in3len: length of input in3 bytes + **************************************************/ +static void mld_H(uint8_t *out, size_t outlen, const uint8_t *in1, + size_t in1len, const uint8_t *in2, size_t in2len, + const uint8_t *in3, size_t in3len) +__contract__( + requires(in1len <= MLD_MAX_BUFFER_SIZE) + requires(in2len <= MLD_MAX_BUFFER_SIZE) + requires(in3len <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in1, in1len)) + requires(in2len == 0 || memory_no_alias(in2, in2len)) + requires(in3len == 0 || memory_no_alias(in3, in3len)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) +{ + mld_shake256ctx state; + mld_shake256_init(&state); + mld_shake256_absorb(&state, in1, in1len); + if (in2len != 0) + { + mld_shake256_absorb(&state, in2, in2len); + } + if (in3len != 0) + { + mld_shake256_absorb(&state, in3, in3len); + } + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(&state, sizeof(state)); +} + +/************************************************* + * Name: mld_compute_pack_z + * + * Description: Computes z = y + s1*c, checks that z has coefficients smaller + * than MLDSA_GAMMA1 - MLDSA_BETA, and packs z into the + * signature buffer. + * + * Arguments: - uint8_t *sig: output signature + * - const mld_poly *cp: challenge polynomial + * - const polyvecl *s1: secret vector s1 + * - const polyvecl *y: masking vector y + * + * Returns: - 0: Success (z has coefficients smaller than + * MLDSA_GAMMA1 - MLDSA_BETA,) + * - MLD_ERR_FAIL: z rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This function is inlined into mld_sign_signature in the + * reference implementation. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_pack_z(uint8_t sig[MLDSA_CRYPTO_BYTES], + const mld_poly *cp, const mld_polyvecl *s1, + const mld_polyvecl *y, mld_poly *z) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(cp, sizeof(mld_poly))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(y, sizeof(mld_polyvecl))) + requires(memory_no_alias(z, sizeof(mld_poly))) + requires(array_abs_bound(cp->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_L, + array_bound(y->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + requires(forall(k1, 0, MLDSA_L, array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(memory_slice(z, sizeof(mld_poly))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int i; + uint32_t z_invalid; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(z, sizeof(mld_poly)), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_poly_pointwise_montgomery(z, cp, &s1->vec[i]); + mld_poly_invntt_tomont(z); + mld_poly_add(z, &y->vec[i]); + mld_poly_reduce(z); + + z_invalid = mld_poly_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA); + /* Constant time: It is fine (and prohibitively expensive to avoid) + * to leak the result of the norm check and which polynomial in z caused a + * rejection. It would even be okay to leak which coefficient led to + * rejection as the candidate signature will be discarded anyway. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(&z_invalid, sizeof(uint32_t)); + if (z_invalid) + { + return MLD_ERR_FAIL; /* reject */ + } + /* If z is valid, then its coefficients are bounded by + * MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below + * to prove the pre-condition of pack_sig_z() */ + mld_assert_abs_bound(z, MLDSA_N, (MLDSA_GAMMA1 - MLDSA_BETA)); + + /* After the norm check, the distribution of each coefficient of z is + * independent of the secret key and it can, hence, be considered + * public. It is, hence, okay to immediately pack it into the user-provided + * signature buffer. */ + mld_pack_sig_z(sig, z, i); + } + return 0; +} + +/* Reference: The reference implementation does not explicitly check the + * maximum nonce value, but instead loops indefinitely (even when the nonce + * would overflow). Internally, sampling of y uses + * (nonceL), (nonceL+1), ... (nonce*L+L-1). + * Hence, there are no overflows if nonce < (UINT16_MAX - L)/L. + * Explicitly checking for this explicitly allows us to prove type-safety. + * Note that FIPS204 explicitly allows an upper-bound this loop of + * 814 (< (UINT16_MAX - L)/L) - see @[FIPS204, Appendix C]. */ +#define MLD_NONCE_UB ((UINT16_MAX - MLDSA_L) / MLDSA_L) + +/************************************************* + * Name: attempt_signature_generation + * + * Description: Attempts to generate a single signature. + * + * Arguments: - uint8_t *sig: pointer to output signature + * - const uint8_t *mu: pointer to message or hash + * of exactly MLDSA_CRHBYTES bytes + * - const uint8_t *rhoprime: pointer to randomness seed + * - uint16_t nonce: current nonce value + * - const mld_polymat *mat: expanded matrix + * - const polyvecl *s1: secret vector s1 + * - const polyveck *s2: secret vector s2 + * - const polyveck *t0: vector t0 + * + * Returns: - 0: Signature generation succeeded + * - MLD_ERR_FAIL: Signature rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This code differs from the reference implementation + * in that it factors out the core signature generation + * step into a distinct function here in order to improve + * efficiency of CBMC proof. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_attempt_signature_generation( + uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *mu, + const uint8_t rhoprime[MLDSA_CRHBYTES], uint16_t nonce, mld_polymat *mat, + const mld_polyvecl *s1, const mld_polyveck *s2, const mld_polyveck *t0, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(rhoprime, MLDSA_CRHBYTES)) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(nonce <= MLD_NONCE_UB) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int n; + uint32_t w0_invalid, h_invalid; + int ret; + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyvecl y; + mld_polyveck h; + } + yh_u; + mld_polyvecl *y; + mld_polyveck *h; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck w1; + mld_polyvecl tmp; + } + w1tmp_u; + mld_polyveck *w1; + mld_polyvecl *tmp; + + MLD_ALLOC(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(yh, yh_u, 1, context); + MLD_ALLOC(z, mld_poly, 1, context); + MLD_ALLOC(w1tmp, w1tmp_u, 1, context); + MLD_ALLOC(w0, mld_polyveck, 1, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(t, mld_poly, 1, context); + + if (challenge_bytes == NULL || yh == NULL || z == NULL || w1tmp == NULL || + w0 == NULL || cp == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + y = &yh->y; + h = &yh->h; + w1 = &w1tmp->w1; + tmp = &w1tmp->tmp; + + /* Sample intermediate vector y */ + mld_polyvecl_uniform_gamma1(y, rhoprime, nonce); + + /* Matrix-vector multiplication */ + *tmp = *y; + mld_polyvecl_ntt(tmp); + mld_polyvec_matrix_pointwise_montgomery(w0, mat, tmp); + mld_polyveck_invntt_tomont(w0); + + /* Decompose w and call the random oracle */ + mld_polyveck_caddq(w0); + mld_polyveck_decompose(w1, w0); + mld_polyveck_pack_w1(sig, w1); + + mld_H(challenge_bytes, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, sig, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + /* Constant time: Leaking challenge_bytes does not reveal any information + * about the secret key as H() is modelled as random oracle. + * This also applies to challenges for rejected signatures. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(challenge_bytes, MLDSA_CTILDEBYTES); + mld_poly_challenge(cp, challenge_bytes); + mld_poly_ntt(cp); + + /* Compute z, reject if it reveals secret */ + ret = mld_compute_pack_z(sig, cp, s1, y, t); + if (ret) + { + goto cleanup; + } + + /* Check that subtracting cs2 does not change high bits of w and low bits + * do not reveal secret information */ + mld_polyveck_pointwise_poly_montgomery(h, cp, s2); + mld_polyveck_invntt_tomont(h); + mld_polyveck_sub(w0, h); + mld_polyveck_reduce(w0); + + w0_invalid = mld_polyveck_chknorm(w0, MLDSA_GAMMA2 - MLDSA_BETA); + /* Constant time: w0_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&w0_invalid, sizeof(uint32_t)); + if (w0_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* Compute hints for w1 */ + mld_polyveck_pointwise_poly_montgomery(h, cp, t0); + mld_polyveck_invntt_tomont(h); + mld_polyveck_reduce(h); + + h_invalid = mld_polyveck_chknorm(h, MLDSA_GAMMA2); + /* Constant time: h_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&h_invalid, sizeof(uint32_t)); + if (h_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + mld_polyveck_add(w0, h); + + /* Constant time: At this point all norm checks have passed and we, hence, + * know that the signature does not leak any secret information. + * Consequently, any value that can be computed from the signature and public + * key is considered public. + * w0 and w1 are public as they can be computed from Az - ct = \alpha w1 + w0. + * h=c*t0 is public as both c and t0 are public. + * For a more detailed discussion, refer to https://eprint.iacr.org/2022/1406. + */ + MLD_CT_TESTING_DECLASSIFY(w0, sizeof(*w0)); + MLD_CT_TESTING_DECLASSIFY(w1, sizeof(*w1)); + n = mld_polyveck_make_hint(h, w0, w1); + if (n > MLDSA_OMEGA) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* All is well - write signature */ + mld_pack_sig_c_h(sig, challenge_bytes, h, n); + /* Constant time: At this point it is clear that the signature is valid - it + * can, hence, be considered public. */ + MLD_CT_TESTING_DECLASSIFY(sig, MLDSA_CRYPTO_BYTES); + ret = 0; /* success */ + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_poly, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(w0, mld_polyveck, 1, context); + MLD_FREE(w1tmp, w1tmp_u, 1, context); + MLD_FREE(z, mld_poly, 1, context); + MLD_FREE(yh, yh_u, 1, context); + MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + + return ret; +} +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + uint8_t *rho, *tr, *key, *mu, *rhoprime; + uint16_t nonce = 0; + MLD_ALLOC(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + + if (seedbuf == NULL || mat == NULL || s1 == NULL || t0 == NULL || s2 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + rho = seedbuf; + tr = rho + MLDSA_SEEDBYTES; + key = tr + MLDSA_TRBYTES; + mu = key + MLDSA_SEEDBYTES; + rhoprime = mu + MLDSA_CRHBYTES; + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + if (!externalmu) + { + /* Compute mu = CRH(tr, pre, msg) */ + mld_H(mu, MLDSA_CRHBYTES, tr, MLDSA_TRBYTES, pre, prelen, m, mlen); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Compute rhoprime = CRH(key, rnd, mu) */ + mld_H(rhoprime, MLDSA_CRHBYTES, key, MLDSA_SEEDBYTES, rnd, MLDSA_RNDBYTES, mu, + MLDSA_CRHBYTES); + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + /* Expand matrix and transform vectors */ + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(s1); + mld_polyveck_ntt(s2); + mld_polyveck_ntt(t0); + + /* By default, return failure. Flip to success and write output + * once signature generation succeeds. */ + ret = MLD_ERR_FAIL; + + /* Reference: This code is re-structured using a while(1), */ + /* with explicit "continue" statements (rather than "goto") */ + /* to implement rejection of invalid signatures. */ + while (1) + __loop__( + assigns(nonce, ret, object_whole(siglen), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(nonce <= MLD_NONCE_UB) + + /* t0, s1, s2, and mat are initialized above and are NOT changed by this */ + /* loop. We can therefore re-assert their bounds here as part of the */ + /* loop invariant. This makes proof noticeably faster with CBMC */ + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + invariant(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(ret == MLD_ERR_FAIL) + ) + { + /* Reference: this code explicitly checks for exhaustion of nonce */ + /* values to provide predictable termination and results in that case */ + /* Checking here also means that incrementing nonce below can also */ + /* be proven to be type-safe. */ + if (nonce == MLD_NONCE_UB) + { + /* Note that ret == MLD_ERR_FAIL by default, so we + * don't need to set it here. */ + break; + } + + ret = mld_attempt_signature_generation(sig, mu, rhoprime, nonce, mat, s1, + s2, t0, context); + nonce++; + if (ret == 0) + { + *siglen = MLDSA_CRYPTO_BYTES; + break; + } + else if (ret != MLD_ERR_FAIL) + { + /* For failures such as out-of-memory, propagate and exit immediately. */ + break; + } + + /* Otherwise, try again. */ + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the signature buffer. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + return ret; +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + size_t pre_len; + int ret; + MLD_ALLOC(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + MLD_ALLOC(rnd, uint8_t, MLDSA_RNDBYTES, context); + + if (pre == NULL || rnd == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Prepare domain separation prefix for pure ML-DSA */ + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, m, mlen, pre, pre_len, rnd, sk, + 0, context); + +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(rnd, uint8_t, MLDSA_RNDBYTES, context); + MLD_FREE(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t rnd[MLDSA_RNDBYTES]; + int ret; + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + *siglen = 0; + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, + rnd, sk, 1, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(rnd, sizeof(rnd)); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + for (i = 0; i < mlen; ++i) + __loop__( + assigns(i, object_whole(sm)) + invariant(i <= mlen) + ) + { + sm[MLDSA_CRYPTO_BYTES + mlen - 1 - i] = m[mlen - 1 - i]; + } + ret = mld_sign_signature(sm, smlen, sm + MLDSA_CRYPTO_BYTES, mlen, ctx, + ctxlen, sk, context); + *smlen += mlen; + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret, cmp; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck t1; + mld_polyveck w1; + } + t1w1_u; + mld_polyveck *t1; + mld_polyveck *w1; + + MLD_ALLOC(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_ALLOC(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(z, mld_polyvecl, 1, context); + MLD_ALLOC(t1w1, t1w1_u, 1, context); + MLD_ALLOC(tmp, mld_polyveck, 1, context); + MLD_ALLOC(h, mld_polyveck, 1, context); + + if (buf == NULL || rho == NULL || mu == NULL || c == NULL || c2 == NULL || + cp == NULL || mat == NULL || z == NULL || t1w1 == NULL || tmp == NULL || + h == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + t1 = &t1w1->t1; + w1 = &t1w1->w1; + + if (siglen != MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + mld_unpack_pk(rho, t1, pk); + + /* mld_unpack_sig and mld_polyvecl_chknorm signal failure through a + * single non-zero error code that's not yet aligned with MLD_ERR_XXX. + * Map it to MLD_ERR_FAIL explicitly. */ + if (mld_unpack_sig(c, z, h, sig)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + if (mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + if (!externalmu) + { + /* Compute CRH(H(rho, t1), pre, msg) */ + MLD_ALIGN uint8_t hpk[MLDSA_CRHBYTES]; + mld_H(hpk, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES, NULL, 0, NULL, + 0); + mld_H(mu, MLDSA_CRHBYTES, hpk, MLDSA_TRBYTES, pre, prelen, m, mlen); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(hpk, sizeof(hpk)); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Matrix-vector multiplication; compute Az - c2^dt1 */ + mld_poly_challenge(cp, c); + mld_poly_ntt(cp); + mld_polyveck_shiftl(t1); + mld_polyveck_ntt(t1); + mld_polyveck_pointwise_poly_montgomery(tmp, cp, t1); + + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(z); + mld_polyvec_matrix_pointwise_montgomery(w1, mat, z); + mld_polyveck_sub(w1, tmp); + mld_polyveck_reduce(w1); + mld_polyveck_invntt_tomont(w1); + + /* Reconstruct w1 */ + mld_polyveck_caddq(w1); + mld_polyveck_use_hint(tmp, w1, h); + mld_polyveck_pack_w1(buf, tmp); + /* Call random oracle and verify challenge */ + mld_H(c2, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, buf, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + + cmp = mld_ct_memcmp(c, c2, MLDSA_CTILDEBYTES); + + /* Declassify the result of the verification. */ + MLD_CT_TESTING_DECLASSIFY(&cmp, sizeof(cmp)); + + ret = cmp == 0 ? 0 : MLD_ERR_FAIL; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(h, mld_polyveck, 1, context); + MLD_FREE(tmp, mld_polyveck, 1, context); + MLD_FREE(t1w1, t1w1_u, 1, context); + MLD_FREE(z, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, m, mlen, pre, pre_len, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + return mld_sign_verify_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, pk, + 1, context); +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + if (smlen < MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + *mlen = smlen - MLDSA_CRYPTO_BYTES; + ret = mld_sign_verify(sm, MLDSA_CRYPTO_BYTES, sm + MLDSA_CRYPTO_BYTES, *mlen, + ctx, ctxlen, pk, context); + if (ret == 0) + { + /* All good, copy msg, return 0 */ + for (i = 0; i < *mlen; ++i) + __loop__( + assigns(i, memory_slice(m, *mlen)) + invariant(i <= *mlen) + ) + { + m[i] = sm[MLDSA_CRYPTO_BYTES + i]; + } + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the message buffer. */ + *mlen = 0; + mld_memset(m, 0, smlen); + } + + return ret; +} + + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_signature_internal(sig, siglen, pre, pre_len, NULL, 0, rnd, sk, + 0, context); +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, pre, pre_len, NULL, 0, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_signature_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, rnd, sk, + MLD_PREHASH_SHAKE_256, context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_verify_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, pk, MLD_PREHASH_SHAKE_256, + context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + + +#define MLD_PRE_HASH_OID_LEN 11 + +/************************************************* + * Name: mld_get_hash_oid + * + * Description: Returns the OID of a given SHA-2/SHA-3 hash function. + * + * Arguments: - uint8_t oid[11]: pointer to output oid + * - int hashalg: hash algorithm constant (MLD_PREHASH_*) + * + ***************************************************/ +static void mld_get_hash_oid(uint8_t oid[MLD_PRE_HASH_OID_LEN], int hashalg) +{ + unsigned int i; + static const struct + { + int alg; + uint8_t oid[MLD_PRE_HASH_OID_LEN]; + } oid_map[] = { + {MLD_PREHASH_SHA2_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}}, + {MLD_PREHASH_SHA2_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}}, + {MLD_PREHASH_SHA2_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}}, + {MLD_PREHASH_SHA2_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}}, + {MLD_PREHASH_SHA2_512_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05}}, + {MLD_PREHASH_SHA2_512_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06}}, + {MLD_PREHASH_SHA3_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07}}, + {MLD_PREHASH_SHA3_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08}}, + {MLD_PREHASH_SHA3_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09}}, + {MLD_PREHASH_SHA3_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A}}, + {MLD_PREHASH_SHAKE_128, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B}}, + {MLD_PREHASH_SHAKE_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C}}}; + + for (i = 0; i < sizeof(oid_map) / sizeof(oid_map[0]); i++) + __loop__( + invariant(i <= sizeof(oid_map) / sizeof(oid_map[0])) + ) + { + if (oid_map[i].alg == hashalg) + { + mld_memcpy(oid, oid_map[i].oid, MLD_PRE_HASH_OID_LEN); + return; + } + } +} + +static int mld_validate_hash_length(int hashalg, size_t len) +{ + switch (hashalg) + { + case MLD_PREHASH_SHA2_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_128: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_256: + return (len == 512 / 8) ? 0 : -1; + } + return -1; +} + +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +{ + if (ctxlen > 255) + { + return 0; + } + + if (hashalg != MLD_PREHASH_NONE) + { + if (ph == NULL || mld_validate_hash_length(hashalg, phlen) != 0) + { + return 0; + } + } + + /* Common prefix: 0x00/0x01 || ctxlen || ctx */ + prefix[0] = (hashalg == MLD_PREHASH_NONE) ? 0 : 1; + prefix[1] = (uint8_t)ctxlen; + if (ctxlen > 0) + { + mld_memcpy(prefix + 2, ctx, ctxlen); + } + + if (hashalg == MLD_PREHASH_NONE) + { + return 2 + ctxlen; + } + + /* HashML-DSA: append oid || ph */ + mld_get_hash_oid(prefix + 2 + ctxlen, hashalg); + mld_memcpy(prefix + 2 + ctxlen + MLD_PRE_HASH_OID_LEN, ph, phlen); + return 2 + ctxlen + MLD_PRE_HASH_OID_LEN + phlen; +} + +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + uint8_t check, cmp0, cmp1, chk1, chk2; + int ret; + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(t0_computed, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + + if (rho == NULL || tr == NULL || tr_computed == NULL || key == NULL || + s1 == NULL || s2 == NULL || t0 == NULL || t0_computed == NULL || + t1 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Unpack secret key */ + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + /* Validate s1 and s2 coefficients are within [-MLDSA_ETA, MLDSA_ETA] */ + chk1 = mld_polyvecl_chknorm(s1, MLDSA_ETA + 1) & 0xFF; + chk2 = mld_polyveck_chknorm(s2, MLDSA_ETA + 1) & 0xFF; + + /* Recompute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0_computed, t1, tr_computed, + pk, rho, s1, s2, context); + if (ret != 0) + { + goto cleanup; + } + + /* Validate t0 and tr using constant-time comparisons */ + cmp0 = mld_ct_memcmp((const uint8_t *)t0, (const uint8_t *)t0_computed, + sizeof(mld_polyveck)); + cmp1 = mld_ct_memcmp((const uint8_t *)tr, (const uint8_t *)tr_computed, + MLDSA_TRBYTES); + check = mld_value_barrier_u8(cmp0 | cmp1 | chk1 | chk2); + + /* Declassify the final result of the validity check. */ + MLD_CT_TESTING_DECLASSIFY(&check, sizeof(check)); + ret = (check != 0) ? MLD_ERR_FAIL : 0; + +cleanup: + + if (ret != 0) + { + mld_zeroize(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + } + + /* Constant time: pk is either the valid public key or zeroed on error */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(t0_computed, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + + return ret; +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_check_pct +#undef mld_sample_s1_s2 +#undef mld_validate_hash_length +#undef mld_get_hash_oid +#undef mld_H +#undef mld_compute_pack_z +#undef mld_attempt_signature_generation +#undef mld_compute_t0_t1_tr_from_sk_components +#undef MLD_NONCE_UB +#undef MLD_PRE_HASH_OID_LEN diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/sign.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/sign.h new file mode 100644 index 0000000000..2e0bac32ea --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/sign.h @@ -0,0 +1,807 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_SIGN_H +#define MLD_SIGN_H + +#include +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "polyvec.h" +#include "sys.h" + +#if defined(MLD_CHECK_APIS) +/* Include to ensure consistency between internal sign.h + * and external mldsa_native.h. */ +#include "mldsa_native.h" + +#if MLDSA_CRYPTO_SECRETKEYBYTES != \ + MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for SECRETKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_PUBLICKEYBYTES != \ + MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for PUBLICKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_BYTES != MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for CRYPTO_BYTES between sign.h and mldsa_native.h +#endif + +#endif /* MLD_CHECK_APIS */ + +#define mld_sign_keypair_internal \ + MLD_NAMESPACE_KL(keypair_internal) MLD_CONTEXT_PARAMETERS_3 +#define mld_sign_keypair MLD_NAMESPACE_KL(keypair) MLD_CONTEXT_PARAMETERS_2 +#define mld_sign_signature_internal \ + MLD_NAMESPACE_KL(signature_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_signature MLD_NAMESPACE_KL(signature) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_extmu \ + MLD_NAMESPACE_KL(signature_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign MLD_NAMESPACE_KL(sign) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_internal \ + MLD_NAMESPACE_KL(verify_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify MLD_NAMESPACE_KL(verify) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_extmu \ + MLD_NAMESPACE_KL(verify_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign_open MLD_NAMESPACE_KL(open) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_pre_hash_internal \ + MLD_NAMESPACE_KL(signature_pre_hash_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_verify_pre_hash_internal \ + MLD_NAMESPACE_KL(verify_pre_hash_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_signature_pre_hash_shake256 \ + MLD_NAMESPACE_KL(signature_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify_pre_hash_shake256 \ + MLD_NAMESPACE_KL(verify_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_7 +#define mld_prepare_domain_separation_prefix \ + MLD_NAMESPACE_KL(prepare_domain_separation_prefix) +#define mld_sign_pk_from_sk \ + MLD_NAMESPACE_KL(pk_from_sk) MLD_CONTEXT_PARAMETERS_2 + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: mld_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: input random seed + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int externalmu: indicates input message m is + * processed as mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return MLD_ERR_FAIL in that case. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires((externalmu == 0 && (prelen == 0 || memory_no_alias(pre, prelen))) || + (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) + ensures(return_value == 0 ==> *siglen == MLDSA_CRYPTO_BYTES) + ensures(return_value != 0 ==> *siglen == 0) +); + +/************************************************* + * Name: mld_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_signature_extmu + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign + * + * Description: Compute signed message. + * + * Arguments: - uint8_t *sm: pointer to output signed message + * (allocated array with MLDSA_CRYPTO_BYTES + + *mlen bytes), can be equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sm, MLDSA_CRYPTO_BYTES + mlen)) + requires(memory_no_alias(smlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sm, MLDSA_CRYPTO_BYTES + mlen)) + assigns(object_whole(smlen)) + ensures((return_value == 0 && *smlen == MLDSA_CRYPTO_BYTES + mlen) || + (return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL)) +); + +/************************************************* + * Name: mld_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as + * mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(externalmu == 0 || (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + requires(externalmu == 1 || prelen == 0 || memory_no_alias(pre, prelen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_open + * + * Description: Verify signed message. + * + * Arguments: - uint8_t *m: pointer to output message (allocated array + * with smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context tring + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(smlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(m, smlen)) + requires(memory_no_alias(mlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(sm, smlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + assigns(memory_slice(m, smlen)) + assigns(memory_slice(mlen, sizeof(size_t))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and + * verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/* Maximum formatted domain separation message length: + * - Pure ML-DSA: 0x00 || ctxlen || ctx (max 255) + * - HashML-DSA: 0x01 || ctxlen || ctx (max 255) || oid (11) || ph (max 64) */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +__contract__( + requires(ctxlen <= 255) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(hashalg == MLD_PREHASH_NONE || memory_no_alias(ph, phlen)) + requires(memory_no_alias(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + assigns(memory_slice(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + ensures(return_value <= MLD_DOMAIN_SEPARATION_MAX_BYTES) +); + +/************************************************* + * Name: mld_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: input secret + * key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); +#endif /* !MLD_SIGN_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/symmetric.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/symmetric.h new file mode 100644 index 0000000000..bb70f05552 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/symmetric.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_SYMMETRIC_H +#define MLD_SYMMETRIC_H + +#include +#include "cbmc.h" +#include "common.h" + +#include MLD_FIPS202_HEADER_FILE +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#include MLD_FIPS202X4_HEADER_FILE +#endif + +#define MLD_STREAM128_BLOCKBYTES SHAKE128_RATE +#define MLD_STREAM256_BLOCKBYTES SHAKE256_RATE + +#define mld_xof256_ctx mld_shake256ctx +#define mld_xof256_init(CTX) mld_shake256_init(CTX) + +#define mld_xof256_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake256_absorb(CTX, IN, INBYTES); \ + mld_shake256_finalize(CTX); \ + } while (0) + + +#define mld_xof256_release(CTX) mld_shake256_release(CTX) +#define mld_xof256_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake256_squeeze(OUT, (OUTBLOCKS) * SHAKE256_RATE, STATE) + +#define mld_xof128_ctx mld_shake128ctx +#define mld_xof128_init(CTX) mld_shake128_init(CTX) + +#define mld_xof128_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake128_absorb(CTX, IN, INBYTES); \ + mld_shake128_finalize(CTX); \ + } while (0) + +#define mld_xof128_release(CTX) mld_shake128_release(CTX) +#define mld_xof128_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake128_squeeze(OUT, (OUTBLOCKS) * SHAKE128_RATE, STATE) + +#define mld_xof256_x4_ctx mld_shake256x4ctx +#define mld_xof256_x4_init(CTX) mld_shake256x4_init((CTX)) +#define mld_xof256_x4_absorb(CTX, IN, INBYTES) \ + mld_shake256x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof256_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake256x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof256_x4_release(CTX) mld_shake256x4_release((CTX)) + +#define mld_xof128_x4_ctx mld_shake128x4ctx +#define mld_xof128_x4_init(CTX) mld_shake128x4_init((CTX)) +#define mld_xof128_x4_absorb(CTX, IN, INBYTES) \ + mld_shake128x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof128_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake128x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof128_x4_release(CTX) mld_shake128x4_release((CTX)) + +#endif /* !MLD_SYMMETRIC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/sys.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/sys.h new file mode 100644 index 0000000000..1226526420 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/sys.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_SYS_H +#define MLD_SYS_H + +#if !defined(MLD_CONFIG_NO_ASM) && (defined(__GNUC__) || defined(__clang__)) +#define MLD_HAVE_INLINE_ASM +#endif + +/* Try to find endianness, if not forced through CFLAGS already */ +#if !defined(MLD_SYS_LITTLE_ENDIAN) && !defined(MLD_SYS_BIG_ENDIAN) +#if defined(__BYTE_ORDER__) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define MLD_SYS_LITTLE_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define MLD_SYS_BIG_ENDIAN +#else +#error "__BYTE_ORDER__ defined, but don't recognize value." +#endif +#endif /* __BYTE_ORDER__ */ + +/* MSVC does not define __BYTE_ORDER__. However, MSVC only supports + * little endian x86, x86_64, and AArch64. It is, hence, safe to assume + * little endian. */ +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_IX86) || defined(_M_ARM64)) +#define MLD_SYS_LITTLE_ENDIAN +#endif + +#endif /* !MLD_SYS_LITTLE_ENDIAN && !MLD_SYS_BIG_ENDIAN */ + +/* Check if we're running on an AArch64 little endian system. _M_ARM64 is set by + * MSVC. */ +#if defined(__AARCH64EL__) || defined(_M_ARM64) +#define MLD_SYS_AARCH64 +#endif + +/* Check if we're running on an AArch64 big endian system. */ +#if defined(__AARCH64EB__) +#define MLD_SYS_AARCH64_EB +#endif + +#if defined(__x86_64__) +#define MLD_SYS_X86_64 +#if defined(__AVX2__) +#define MLD_SYS_X86_64_AVX2 +#endif +#endif /* __x86_64__ */ + +#if defined(MLD_SYS_LITTLE_ENDIAN) && defined(__powerpc64__) +#define MLD_SYS_PPC64LE +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 +#define MLD_SYS_RISCV64 +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32 +#define MLD_SYS_RISCV32 +#endif + +#if defined(_WIN64) || defined(_WIN32) +#define MLD_SYS_WINDOWS +#endif + +#if defined(__linux__) +#define MLD_SYS_LINUX +#endif + +#if defined(__APPLE__) +#define MLD_SYS_APPLE +#endif + +/* If MLD_FORCE_AARCH64 is set, assert that we're indeed on an AArch64 system. + */ +#if defined(MLD_FORCE_AARCH64) && !defined(MLD_SYS_AARCH64) +#error "MLD_FORCE_AARCH64 is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_AARCH64_EB is set, assert that we're indeed on a big endian + * AArch64 system. */ +#if defined(MLD_FORCE_AARCH64_EB) && !defined(MLD_SYS_AARCH64_EB) +#error \ + "MLD_FORCE_AARCH64_EB is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_X86_64 is set, assert that we're indeed on an X86_64 system. */ +#if defined(MLD_FORCE_X86_64) && !defined(MLD_SYS_X86_64) +#error "MLD_FORCE_X86_64 is set, but we don't seem to be on an X86_64 system." +#endif + +#if defined(MLD_FORCE_PPC64LE) && !defined(MLD_SYS_PPC64LE) +#error "MLD_FORCE_PPC64LE is set, but we don't seem to be on a PPC64LE system." +#endif + +#if defined(MLD_FORCE_RISCV64) && !defined(MLD_SYS_RISCV64) +#error "MLD_FORCE_RISCV64 is set, but we don't seem to be on a RISCV64 system." +#endif + +#if defined(MLD_FORCE_RISCV32) && !defined(MLD_SYS_RISCV32) +#error "MLD_FORCE_RISCV32 is set, but we don't seem to be on a RISCV32 system." +#endif + +/* + * MLD_INLINE: Hint for inlining. + * - MSVC: __inline + * - C99+: inline + * - GCC/Clang C90: __attribute__((unused)) to silence warnings + * - Other C90: empty + */ +#if !defined(MLD_INLINE) +#if defined(_MSC_VER) +#define MLD_INLINE __inline +#elif defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +#define MLD_INLINE inline +#elif defined(__GNUC__) || defined(__clang__) +#define MLD_INLINE __attribute__((unused)) +#else +#define MLD_INLINE +#endif +#endif /* !MLD_INLINE */ + +/* + * MLD_ALWAYS_INLINE: Force inlining. + * - MSVC: __forceinline + * - GCC/Clang C99+: MLD_INLINE __attribute__((always_inline)) + * - Other: MLD_INLINE (no forced inlining) + */ +#if !defined(MLD_ALWAYS_INLINE) +#if defined(_MSC_VER) +#define MLD_ALWAYS_INLINE __forceinline +#elif (defined(__GNUC__) || defined(__clang__)) && \ + (defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)) +#define MLD_ALWAYS_INLINE MLD_INLINE __attribute__((always_inline)) +#else +#define MLD_ALWAYS_INLINE MLD_INLINE +#endif +#endif /* !MLD_ALWAYS_INLINE */ + +#ifndef MLD_STATIC_TESTABLE +#define MLD_STATIC_TESTABLE static +#endif + +/* + * C90 does not have the restrict compiler directive yet. + * We don't use it in C90 builds. + */ +#if !defined(restrict) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define MLD_RESTRICT restrict +#else +#define MLD_RESTRICT +#endif + +#else /* !restrict */ + +#define MLD_RESTRICT restrict +#endif /* restrict */ + +#define MLD_DEFAULT_ALIGN 32 +#define MLD_ALIGN_UP(N) \ + ((((N) + (MLD_DEFAULT_ALIGN - 1)) / MLD_DEFAULT_ALIGN) * MLD_DEFAULT_ALIGN) +#if defined(__GNUC__) +#define MLD_ALIGN __attribute__((aligned(MLD_DEFAULT_ALIGN))) +#elif defined(_MSC_VER) +#define MLD_ALIGN __declspec(align(MLD_DEFAULT_ALIGN)) +#else +#define MLD_ALIGN /* No known support for alignment constraints */ +#endif + + +/* New X86_64 CPUs support Conflow-flow protection using the CET instructions. + * When enabled (through -fcf-protection=), all compilation units (including + * empty ones) need to support CET for this to work. + * For assembly, this means that source files need to signal support for + * CET by setting the appropriate note.gnu.property section. + * This can be achieved by including the header in all assembly file. + * This file also provides the _CET_ENDBR macro which needs to be placed at + * every potential target of an indirect branch. + * If CET is enabled _CET_ENDBR maps to the endbr64 instruction, otherwise + * it is empty. + * In case the compiler does not support CET (e.g., +#define MLD_CET_ENDBR _CET_ENDBR +#else +#define MLD_CET_ENDBR +#endif +#endif /* MLD_SYS_X86_64 */ + +#if defined(MLD_CONFIG_CT_TESTING_ENABLED) && !defined(__ASSEMBLER__) +#include +#define MLD_CT_TESTING_SECRET(ptr, len) \ + VALGRIND_MAKE_MEM_UNDEFINED((ptr), (len)) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) +#else /* MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__ */ +#define MLD_CT_TESTING_SECRET(ptr, len) \ + do \ + { \ + } while (0) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + do \ + { \ + } while (0) +#endif /* !(MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__) */ + +#if defined(__GNUC__) || defined(__clang__) +#define MLD_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_MUST_CHECK_RETURN_VALUE +#endif + + +#if !defined(__ASSEMBLER__) +/* System capability enumeration */ +typedef enum +{ + /* x86_64 */ + MLD_SYS_CAP_AVX2, + /* AArch64 */ + MLD_SYS_CAP_SHA3 +} mld_sys_cap; + +#if !defined(MLD_CONFIG_CUSTOM_CAPABILITY_FUNC) +#include "cbmc.h" + +static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) +__contract__( + ensures(return_value == 0 || return_value == 1) +) +{ + /* By default, we rely on compile-time feature detection/specification: + * If a feature is enabled at compile-time, we assume it is supported by + * the host that the resulting library/binary will be built on. + * If this assumption is not true, you MUST overwrite this function. + * See the documentation of MLD_CONFIG_CUSTOM_CAPABILITY_FUNC in + * mldsa_native_config.h for more information. */ + (void)cap; + return 1; +} +#endif /* !MLD_CONFIG_CUSTOM_CAPABILITY_FUNC */ +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_SYS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/zetas.inc b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/zetas.inc new file mode 100644 index 0000000000..dc3cf15dd3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/mldsa_native/src/zetas.inc @@ -0,0 +1,56 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include + +/* + * Table of zeta values used in the reference NTT and inverse NTT. + * See autogen for details. + */ +static const int32_t mld_zetas[MLDSA_N] = { + 0, 25847, -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 2353451, -359251, -2091905, 3119733, -2884855, + 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488, + -1119584, 2619752, -2108549, -2118186, -3859737, -1399561, -3277672, + 1757237, -19422, 4010497, 280005, 2706023, 95776, 3077325, + 3530437, -1661693, -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267, + -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596, + 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, + -2797779, -3930395, -1528703, -3677745, -3041255, -1452451, 3475950, + 2176455, -1585221, -1257611, 1939314, -4083598, -1000202, -3190144, + -3157330, -3632928, 126922, 3412210, -983419, 2147896, 2715295, + -2967645, -3693493, -411027, -2477047, -671102, -1228525, -22981, + -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944, + 508951, 3097992, 44288, -1100098, 904516, 3958618, -3724342, + -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856, + 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, + 1341330, 1285669, -1584928, -812732, -1439742, -3019102, -3881060, + -3628969, 3839961, 2091667, 3407706, 2316500, 3817976, -3342478, + 2244091, -2446433, -3562462, 266997, 2434439, -1235728, 3513181, + -3520352, -3759364, -1197226, -3193378, 900702, 1859098, 909542, + 819034, 495491, -1613174, -43260, -522500, -655327, -3122442, + 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297, + 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, + 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, + 1595974, -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, + 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100, + 1312455, 3306115, -1962642, -1279661, 1917081, -2546312, -1374803, + 1500165, 777191, 2235880, 3406031, -542412, -2831860, -1671176, + -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395, + 2454455, -164721, 1957272, 3369112, 185531, -1207385, -3183426, + 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, + -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, + 472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333, + -260646, -3833893, -2939036, -2235985, -420899, -2286327, 183443, + -976891, 1612842, -3545687, -554416, 3919660, -48306, -1362209, + 3937738, 1400424, -846154, 1976782, +}; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/test_only_rng/notrandombytes.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/test_only_rng/notrandombytes.c new file mode 100644 index 0000000000..ef5a423a9e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/test_only_rng/notrandombytes.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* * Based on @[surf]*/ + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +#include +#include + +#include "notrandombytes.h" + +#ifdef ENABLE_CT_TESTING +#include +#endif + +static uint32_t seed[32] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, + 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5}; +static uint32_t in[12]; +static uint32_t out[8]; +static int32_t outleft = 0; + +void randombytes_reset(void) +{ + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + outleft = 0; +} + +#define ROTATE(x, b) (((x) << (b)) | ((x) >> (32 - (b)))) +#define MUSH(i, b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x, b)); + +static void surf(void) +{ + uint32_t t[12]; + uint32_t x; + uint32_t sum = 0; + int32_t r; + int32_t i; + int32_t loop; + + for (i = 0; i < 12; ++i) + { + t[i] = in[i] ^ seed[12 + i]; + } + for (i = 0; i < 8; ++i) + { + out[i] = seed[24 + i]; + } + x = t[11]; + for (loop = 0; loop < 2; ++loop) + { + for (r = 0; r < 16; ++r) + { + sum += 0x9e3779b9; + MUSH(0, 5) + MUSH(1, 7) + MUSH(2, 9) + MUSH(3, 13) + MUSH(4, 5) + MUSH(5, 7) + MUSH(6, 9) + MUSH(7, 13) + MUSH(8, 5) + MUSH(9, 7) + MUSH(10, 9) + MUSH(11, 13) + } + for (i = 0; i < 8; ++i) + { + out[i] ^= t[i + 4]; + } + } +} + +int randombytes(uint8_t *buf, size_t n) +{ +#ifdef ENABLE_CT_TESTING + uint8_t *buf_orig = buf; + size_t n_orig = n; +#endif + + while (n > 0) + { + if (!outleft) + { + if (!++in[0]) + { + if (!++in[1]) + { + if (!++in[2]) + { + ++in[3]; + } + } + } + surf(); + outleft = 8; + } + *buf = (uint8_t)out[--outleft]; + ++buf; + --n; + } + +#ifdef ENABLE_CT_TESTING + /* + * Mark all randombytes output as secret (undefined). + * Valgrind will propagate this to everything derived from it. + */ + VALGRIND_MAKE_MEM_UNDEFINED(buf_orig, n_orig); +#endif /* ENABLE_CT_TESTING */ + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/test_only_rng/notrandombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/test_only_rng/notrandombytes.h new file mode 100644 index 0000000000..bdf9787920 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202/test_only_rng/notrandombytes.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* Based on @[surf]. */ + +#ifndef NOTRANDOMBYTES_H +#define NOTRANDOMBYTES_H + +#include +#include + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +void randombytes_reset(void); +int randombytes(uint8_t *buf, size_t n); + +#endif /* !NOTRANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/.gitignore b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/.gitignore new file mode 100644 index 0000000000..834e997200 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/.gitignore @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +build/ +*.d diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/Makefile new file mode 100644 index 0000000000..5784f0dfe6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/Makefile @@ -0,0 +1,114 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +.PHONY: build run clean +.DEFAULT_GOAL := all + +CC ?= gcc + +# Adjust CFLAGS if needed +CFLAGS := \ + -Wall \ + -Wextra \ + -Werror=unused-result \ + -Wpedantic \ + -Werror \ + -Wmissing-prototypes \ + -Wshadow \ + -Wpointer-arith \ + -Wredundant-decls \ + -Wconversion \ + -Wsign-conversion \ + -Wno-long-long \ + -Wno-unknown-pragmas \ + -Wno-unused-command-line-argument \ + -O3 \ + -fomit-frame-pointer \ + -std=c99 \ + -pedantic \ + -MMD \ + $(CFLAGS) + +# If you want to use the native backends, the compiler needs to know about +# the target architecture. Here, we import the default host detection from +# mldsa-native's tests, but you can write your own or specialize accordingly. +AUTO ?= 1 +include auto.mk + +# The following only concerns the cross-compilation tests. +# You can likely ignore the following for your application. +# +# Append cross-prefix for cross compilation +# When called from the root Makefile, CROSS_PREFIX has already been added here +ifeq (,$(findstring $(CROSS_PREFIX),$(CC))) +CC := $(CROSS_PREFIX)$(CC) +endif + +# Part A: +# +# mldsa-native source and header files +# +# In this example, we compile the individual mldsa-native source files directly. +# Alternatively, you can compile the 'monobuild' source file mldsa_native.c. +# See examples/monolithic_build for that. +MLD_SOURCE=$(wildcard \ + mldsa_native/*.c \ + mldsa_native/**/*.c \ + mldsa_native/**/**/*.c \ + mldsa_native/**/**/**/*.c) + +INC=-Imldsa_native/ + +# Part B: +# +# Custom FIPS-202 implementation +FIPS202_SOURCE=custom_fips202/tiny_sha3/sha3.c + +# Part C: +# +# Random number generator +# +# !!! WARNING !!! +# +# The randombytes() implementation used here is for TESTING ONLY. +# You MUST NOT use this implementation outside of testing. +# +# !!! WARNING !!! +RNG_SOURCE=$(wildcard test_only_rng/*.c) + +# Part D: +# +# Your application source code +APP_SOURCE=$(wildcard *.c) + +ALL_SOURCE=$(MLD_SOURCE) $(FIPS202_SOURCE) $(RNG_SOURCE) $(APP_SOURCE) + +BUILD_DIR=build +BIN=test_binary + +BINARY_NAME_FULL_44=$(BUILD_DIR)/$(BIN)44 +BINARY_NAME_FULL_65=$(BUILD_DIR)/$(BIN)65 +BINARY_NAME_FULL_87=$(BUILD_DIR)/$(BIN)87 +BINARIES_FULL=$(BINARY_NAME_FULL_44) $(BINARY_NAME_FULL_65) $(BINARY_NAME_FULL_87) + +$(BINARY_NAME_FULL_44): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=44 +$(BINARY_NAME_FULL_65): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=65 +$(BINARY_NAME_FULL_87): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=87 + +$(BINARIES_FULL): $(ALL_SOURCE) + echo "$@" + mkdir -p $(BUILD_DIR) + $(CC) $(CFLAGS) $(INC) $^ -o $@ + +all: build + +build: $(BINARIES_FULL) + +run: $(BINARIES_FULL) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_44) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_65) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_87) + +clean: + rm -rf $(BUILD_DIR) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/README.md new file mode 100644 index 0000000000..73de524849 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/README.md @@ -0,0 +1,54 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Bring Your Own FIPS-202 (Static State Variant) + +This directory contains a minimal example for using mldsa-native with a custom FIPS-202 implementation +that uses a single global state. This is common for hardware accelerators that can only hold one +Keccak state at a time. + +## Use Case + +Use this approach when: +- You need only one ML-DSA parameter set (44, 65, or 87) +- Your application already has a FIPS-202 software/hardware implementation you want to reuse +- Your FIPS-202 implementation does not support multiple active SHA3/SHAKE computations. + +## Components + +1. Arithmetic part of mldsa-native: [`mldsa/src/`](../../mldsa/src) (excluding `fips202/`) +2. A secure random number generator implementing [`randombytes.h`](../../mldsa/src/randombytes.h) +3. Custom FIPS-202 implementation with headers compatible with [`fips202.h`](../../mldsa/src/fips202/fips202.h) +4. Your application source code + +## Configuration + +The configuration file [mldsa_native_config.h](mldsa_native/mldsa_native_config.h) sets: +- `MLD_CONFIG_SERIAL_FIPS202_ONLY`: Disables batched Keccak; matrix entries generated one at a time +- `MLD_CONFIG_FIPS202_CUSTOM_HEADER`: Path to your custom `fips202.h` + +Your custom FIPS-202 implementation must provide: +- `mld_shake128_init()`, `mld_shake128_absorb()`, `mld_shake128_finalize()`, `mld_shake128_squeeze()`, `mld_shake128_release()` +- `mld_shake256_init()`, `mld_shake256_absorb()`, `mld_shake256_finalize()`, `mld_shake256_squeeze()`, `mld_shake256_release()` +- `mld_shake256` +- Structure definitions for `mld_shake128ctx` and `mld_shake256ctx` + +## Notes + +- `MLD_CONFIG_SERIAL_FIPS202_ONLY` may reduce performance on CPUs with SIMD support +- Matrix and vector generation becomes sequential instead of batched (4 entries at a time) +- Only enable this when your hardware requires it + +## Usage + +```bash +make build # Build the example +make run # Run the example +``` + +## Warning + +The `randombytes()` implementation in `test_only_rng/` is for TESTING ONLY. +You MUST provide a cryptographically secure RNG for production use. + + +[^tiny_sha3]: Markku-Juhani O. Saarinen: tiny_sha3, [https://github.com/mjosaarinen/tiny_sha3](https://github.com/mjosaarinen/tiny_sha3) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/auto.mk b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/auto.mk new file mode 100644 index 0000000000..5f71942085 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/auto.mk @@ -0,0 +1,178 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# Automatically detect system architecture and set preprocessor flags accordingly +# This file detects host CPU capabilities and combines them with compiler support +# to enable optimal compilation flags. +# +# Compiler feature detection can be overridden by setting the corresponding variable +# on the command line: +# make MK_COMPILER_SUPPORTS_SHA3=0 # Disable SHA3 detection +# make MK_COMPILER_SUPPORTS_AVX2=0 # Disable AVX2 detection +# make MK_COMPILER_SUPPORTS_BMI2=0 # Disable BMI2 detection +# make MK_COMPILER_SUPPORTS_SSE2=0 # Disable SSE2 detection + +ifndef _AUTO_MK +_AUTO_MK := + +# Override ARCH for cross-compilation based on CROSS_PREFIX +ifeq ($(CROSS_PREFIX),) +ARCH := $(shell uname -m) +# Normalize architecture names +ifeq ($(ARCH),arm64) +ARCH := aarch64 +endif +else # CROSS_PREFIX +ifneq ($(findstring x86_64, $(CROSS_PREFIX)),) +ARCH := x86_64 +else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),) +ARCH := aarch64_be +else ifneq ($(findstring aarch64, $(CROSS_PREFIX)),) +ARCH := aarch64 +else ifneq ($(findstring riscv64, $(CROSS_PREFIX)),) +ARCH := riscv64 +else ifneq ($(findstring riscv32, $(CROSS_PREFIX)),) +ARCH := riscv32 +else ifneq ($(findstring powerpc64le, $(CROSS_PREFIX)),) +ARCH := powerpc64le +else ifneq ($(findstring arm-none-eabi-, $(CROSS_PREFIX)),) +ARCH := arm +else +ifeq ($(AUTO),1) +$(warning Unknown cross-compilation prefix $(CROSS_PREFIX), no automatic detection of CFLAGS.) +ARCH := unknown +endif +endif +endif # CROSS_PREFIX + +# x86_64 compiler feature detection +ifeq ($(ARCH),x86_64) + +# Test AVX2 support using C with inline assembly +MK_COMPILER_SUPPORTS_AVX2 ?= $(shell echo 'int main() { __asm__("vpxor %%ymm0, %%ymm1, %%ymm2" ::: "ymm0", "ymm1", "ymm2"); return 0; }' | $(CC) -mavx2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test SSE2 support using C with inline assembly +MK_COMPILER_SUPPORTS_SSE2 ?= $(shell echo 'int main() { __asm__("pxor %%xmm0, %%xmm1" ::: "xmm0", "xmm1"); return 0; }' | $(CC) -msse2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test BMI2 support using C with inline assembly +MK_COMPILER_SUPPORTS_BMI2 ?= $(shell echo 'int main() { __asm__("pdep %%eax, %%ebx, %%ecx" ::: "eax", "ebx", "ecx"); return 0; }' | $(CC) -mbmi2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # x86_64 compiler detection + +# AArch64 compiler feature detection +ifeq ($(ARCH),aarch64) + +# Test SHA3 support (Armv8.4-a+SHA3) using C with inline assembly +MK_COMPILER_SUPPORTS_SHA3 ?= $(shell echo 'int main() { __asm__("eor3 v0.16b, v1.16b, v2.16b, v3.16b" ::: "v0", "v1", "v2", "v3"); return 0; }' | $(CC) -march=armv8.4-a+sha3 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # aarch64 compiler detection + +# Define HOST_PLATFORM if not already defined +HOST_PLATFORM ?= $(shell uname -s)-$(shell uname -m) + +# Helper function to check if host CPU supports a feature +# Usage: $(call check_host_feature,feature_pattern,source_command) +define check_host_feature +$(shell $(2) 2>/dev/null | grep -q "$(1)" && echo 1 || echo 0) +endef + +# x86_64 architecture detection +ifeq ($(ARCH),x86_64) + +# Host CPU feature detection for x86_64 +ifeq ($(HOST_PLATFORM),Linux-x86_64) +# Linux: Use /proc/cpuinfo +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,avx2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,sse2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,bmi2,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-x86_64) +# macOS: Use sysctl +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,AVX2,sysctl -n machdep.cpu.leaf7_features) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,SSE2,sysctl -n machdep.cpu.features) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,BMI2,sysctl -n machdep.cpu.leaf7_features) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_AVX2 := 1 +MK_HOST_SUPPORTS_SSE2 := 1 +MK_HOST_SUPPORTS_BMI2 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_AVX2 := 0 +MK_HOST_SUPPORTS_SSE2 := 0 +MK_HOST_SUPPORTS_BMI2 := 0 +endif # HOST_PLATFORM x86_64 + +endif # x86_64 + +# AArch64 architecture detection +ifeq ($(ARCH),aarch64) + +# Host CPU feature detection for AArch64 +ifeq ($(HOST_PLATFORM),Linux-aarch64) +# Linux: Use /proc/cpuinfo (look for sha3 in Features line) +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,sha3,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-arm64) +# macOS: Use sysctl to check for SHA3 support +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,1,sysctl -n hw.optional.armv8_2_sha3) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_SHA3 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_SHA3 := 0 +endif # HOST_PLATFORM aarch64 + +endif # aarch64 + +# Only apply CFLAGS modifications if AUTO=1 +ifeq ($(AUTO),1) + +# x86_64 CFLAGS configuration +ifeq ($(ARCH),x86_64) +CFLAGS += -DMLD_FORCE_X86_64 + +# Add flags only if both compiler and host support the feature +ifeq ($(MK_COMPILER_SUPPORTS_AVX2)$(MK_HOST_SUPPORTS_AVX2),11) +CFLAGS += -mavx2 +endif + +ifeq ($(MK_COMPILER_SUPPORTS_BMI2)$(MK_HOST_SUPPORTS_BMI2),11) +CFLAGS += -mbmi2 +endif +endif # x86_64 + +# AArch64 CFLAGS configuration +ifeq ($(ARCH),aarch64) +CFLAGS += -DMLD_FORCE_AARCH64 + +# Add SHA3 flags only if both compiler and host support it +ifeq ($(MK_COMPILER_SUPPORTS_SHA3)$(MK_HOST_SUPPORTS_SHA3),11) +CFLAGS += -march=armv8.4-a+sha3 +endif +endif # aarch64 + +# AArch64 Big Endian CFLAGS configuration +ifeq ($(ARCH),aarch64_be) +CFLAGS += -DMLD_FORCE_AARCH64_EB +endif # aarch64_be + +# RISC-V 64-bit CFLAGS configuration +ifeq ($(ARCH),riscv64) +CFLAGS += -DMLD_FORCE_RISCV64 +CFLAGS += -march=rv64gcv +endif # riscv64 + +# RISC-V 32-bit CFLAGS configuration +ifeq ($(ARCH),riscv32) +CFLAGS += -DMLD_FORCE_RISCV32 +endif # riscv32 + +# PowerPC 64-bit Little Endian CFLAGS configuration +ifeq ($(ARCH),powerpc64le) +CFLAGS += -DMLD_FORCE_PPC64LE +endif # powerpc64le + +endif # AUTO=1 + +endif # _AUTO_MK diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/custom_fips202/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/custom_fips202/README.md new file mode 100644 index 0000000000..c507f4baa2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/custom_fips202/README.md @@ -0,0 +1,43 @@ + + +# Custom FIPS-202 Implementation (Static Global State) + +This directory contains a custom FIPS-202 implementation that wraps `tiny_sha3`[^tiny_sha3] +using a **single global static state** for all operations. + +## Purpose + +This example demonstrates how mldsa-native can integrate with FIPS-202 implementations +that maintain a single global state, such as: +- Hardware accelerators with a single Keccak engine +- Embedded systems with limited memory +- Libraries that don't support multiple independent contexts + +## How It Works + +Instead of storing the Keccak state in each context structure, this implementation: + +1. Uses a **static global state** for SHA-3/SHAKE operations +2. Provides **dummy context structures** that are ignored by the API functions +3. Includes **state machine assertions** to verify correct API usage +## Configuration + +Enable this mode with: +```c +#define MLD_CONFIG_FIPS202_CUSTOM_HEADER "\"fips202.h\"" +#define MLD_CONFIG_SERIAL_FIPS202_ONLY +``` + +The `MLD_CONFIG_SERIAL_FIPS202_ONLY` flag tells mldsa-native to avoid +using the parallel x4 API. + +## Files + +- `fips202.h` - Custom FIPS-202 wrapper with static global state +- `tiny_sha3/` - Symlink to the tiny_sha3 implementation +- `README.md` - This file + +[^tiny_sha3]: https://github.com/mjosaarinen/tiny_sha3 + + +[^tiny_sha3]: Markku-Juhani O. Saarinen: tiny_sha3, [https://github.com/mjosaarinen/tiny_sha3](https://github.com/mjosaarinen/tiny_sha3) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/custom_fips202/fips202.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/custom_fips202/fips202.h new file mode 100644 index 0000000000..21777f3810 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/custom_fips202/fips202.h @@ -0,0 +1,262 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * This is a shim establishing the FIPS-202 API required by mldsa-native + * from the API exposed by tiny_sha3. + */ + +#ifndef FIPS202_H +#define FIPS202_H + +#include +#include +#include +#include + +#include "../custom_fips202/tiny_sha3/sha3.h" + +/* We need the MLD_INLINE definition from sys.h */ +#ifndef MLD_INLINE +#if defined(__GNUC__) || defined(__clang__) +#define MLD_INLINE __attribute__((always_inline)) static inline +#else +#define MLD_INLINE static inline +#endif +#endif /* !MLD_INLINE */ + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 +#define SHA3_256_RATE 136 +#define SHA3_512_RATE 72 +#define SHA3_256_HASHBYTES 32 +#define SHA3_512_HASHBYTES 64 + +typedef enum +{ + FIPS202_STATE_ABSORBING = 1, + FIPS202_STATE_SQUEEZING = 2, + FIPS202_STATE_FINALIZED = 3, + FIPS202_STATE_RESET = 4 +} fips202_state_t; + +/* Static state for serial FIPS202 - SHAKE128 */ +static struct +{ + fips202_state_t state; + sha3_ctx_t ctx; +} static_shake128_state = {FIPS202_STATE_RESET, {{{0}}, 0, 0, 0}}; + +/* Static state for serial FIPS202 - SHAKE256 */ +static struct +{ + fips202_state_t state; + sha3_ctx_t ctx; +} static_shake256_state = {FIPS202_STATE_RESET, {{{0}}, 0, 0, 0}}; + +/* Dummy context types - the actual state is static */ +typedef struct +{ + int dummy; +} mld_shake128ctx; + +typedef struct +{ + int dummy; +} mld_shake256ctx; + +/************************************************* + * Name: mld_shake128_init + * + * Description: Initializes state for use as SHAKE128 XOF + * + * Arguments: - mld_shake128ctx *state: pointer to (uninitialized) state + **************************************************/ +#define mld_shake128_init MLD_NAMESPACE(shake128_init) +static MLD_INLINE void mld_shake128_init(mld_shake128ctx *state) +{ + (void)state; + assert(static_shake128_state.state == FIPS202_STATE_RESET); + shake128_init(&static_shake128_state.ctx); + static_shake128_state.state = FIPS202_STATE_ABSORBING; +} + +/************************************************* + * Name: mld_shake128_absorb + * + * Description: Absorb step of the SHAKE128 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake128ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +#define mld_shake128_absorb MLD_NAMESPACE(shake128_absorb) +static MLD_INLINE void mld_shake128_absorb(mld_shake128ctx *state, + const uint8_t *in, size_t inlen) +{ + (void)state; + assert(static_shake128_state.state == FIPS202_STATE_ABSORBING); + shake_update(&static_shake128_state.ctx, in, inlen); +} + +/************************************************* + * Name: mld_shake128_finalize + * + * Description: Concludes the absorb phase of the SHAKE128 XOF. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +#define mld_shake128_finalize MLD_NAMESPACE(shake128_finalize) +static MLD_INLINE void mld_shake128_finalize(mld_shake128ctx *state) +{ + (void)state; + assert(static_shake128_state.state == FIPS202_STATE_ABSORBING); + shake_xof(&static_shake128_state.ctx); + static_shake128_state.state = FIPS202_STATE_SQUEEZING; +} + +/************************************************* + * Name: mld_shake128_squeeze + * + * Description: Squeeze step of SHAKE128 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake128ctx *s: pointer to input/output state + **************************************************/ +#define mld_shake128_squeeze MLD_NAMESPACE(shake128_squeeze) +static MLD_INLINE void mld_shake128_squeeze(uint8_t *out, size_t outlen, + mld_shake128ctx *state) +{ + (void)state; + assert(static_shake128_state.state == FIPS202_STATE_SQUEEZING); + shake_out(&static_shake128_state.ctx, out, outlen); +} + +/************************************************* + * Name: mld_shake128_release + * + * Description: Release and securely zero the SHAKE128 state. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +#define mld_shake128_release MLD_NAMESPACE(shake128_release) +static MLD_INLINE void mld_shake128_release(mld_shake128ctx *state) +{ + (void)state; + static_shake128_state.state = FIPS202_STATE_RESET; +} + +/************************************************* + * Name: mld_shake256_init + * + * Description: Initializes state for use as SHAKE256 XOF + * + * Arguments: - mld_shake256ctx *state: pointer to (uninitialized) state + **************************************************/ +#define mld_shake256_init MLD_NAMESPACE(shake256_init) +static MLD_INLINE void mld_shake256_init(mld_shake256ctx *state) +{ + (void)state; + assert(static_shake256_state.state == FIPS202_STATE_RESET); + shake256_init(&static_shake256_state.ctx); + static_shake256_state.state = FIPS202_STATE_ABSORBING; +} + +/************************************************* + * Name: mld_shake256_absorb + * + * Description: Absorb step of the SHAKE256 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake256ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +#define mld_shake256_absorb MLD_NAMESPACE(shake256_absorb) +static MLD_INLINE void mld_shake256_absorb(mld_shake256ctx *state, + const uint8_t *in, size_t inlen) +{ + (void)state; + assert(static_shake256_state.state == FIPS202_STATE_ABSORBING); + shake_update(&static_shake256_state.ctx, in, inlen); +} + +/************************************************* + * Name: mld_shake256_finalize + * + * Description: Concludes the absorb phase of the SHAKE256 XOF. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +#define mld_shake256_finalize MLD_NAMESPACE(shake256_finalize) +static MLD_INLINE void mld_shake256_finalize(mld_shake256ctx *state) +{ + (void)state; + assert(static_shake256_state.state == FIPS202_STATE_ABSORBING); + shake_xof(&static_shake256_state.ctx); + static_shake256_state.state = FIPS202_STATE_SQUEEZING; +} + +/************************************************* + * Name: mld_shake256_squeeze + * + * Description: Squeeze step of SHAKE256 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake256ctx *s: pointer to input/output state + **************************************************/ +#define mld_shake256_squeeze MLD_NAMESPACE(shake256_squeeze) +static MLD_INLINE void mld_shake256_squeeze(uint8_t *out, size_t outlen, + mld_shake256ctx *state) +{ + (void)state; + assert(static_shake256_state.state == FIPS202_STATE_SQUEEZING); + shake_out(&static_shake256_state.ctx, out, outlen); +} + +/************************************************* + * Name: mld_shake256_release + * + * Description: Release and securely zero the SHAKE256 state. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +#define mld_shake256_release MLD_NAMESPACE(shake256_release) +static MLD_INLINE void mld_shake256_release(mld_shake256ctx *state) +{ + (void)state; + static_shake256_state.state = FIPS202_STATE_RESET; +} + +/************************************************* + * Name: mld_shake256 + * + * Description: SHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +#define mld_shake256 MLD_NAMESPACE(shake256) +static MLD_INLINE void mld_shake256(uint8_t *out, size_t outlen, + const uint8_t *in, size_t inlen) +{ + sha3_ctx_t c; + shake256_init(&c); + shake_update(&c, in, inlen); + shake_xof(&c); + shake_out(&c, out, outlen); +} + +#endif /* !FIPS202_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/custom_fips202/tiny_sha3/sha3.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/custom_fips202/tiny_sha3/sha3.c new file mode 100644 index 0000000000..d344b0f148 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/custom_fips202/tiny_sha3/sha3.c @@ -0,0 +1,207 @@ +/* SPDX-License-Identifier: MIT + * + * sha3.c + * 19-Nov-11 Markku-Juhani O. Saarinen */ + +/* Revised 07-Aug-15 to match with official release of FIPS PUB 202 "SHA3" */ +/* Revised 03-Sep-15 for portability + OpenSSL - style API */ + +#include "sha3.h" + +/* update the state with given number of rounds */ + +void sha3_keccakf(uint64_t st[25]) +{ + /* constants */ + const uint64_t keccakf_rndc[24] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008}; + const int keccakf_rotc[24] = {1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44}; + const int keccakf_piln[24] = {10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1}; + + /* variables */ + int i, j, r; + uint64_t t, bc[5]; + +#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ + uint8_t *v; + + /* endianness conversion. this is redundant on little-endian targets */ + for (i = 0; i < 25; i++) + { + v = (uint8_t *)&st[i]; + st[i] = ((uint64_t)v[0]) | (((uint64_t)v[1]) << 8) | + (((uint64_t)v[2]) << 16) | (((uint64_t)v[3]) << 24) | + (((uint64_t)v[4]) << 32) | (((uint64_t)v[5]) << 40) | + (((uint64_t)v[6]) << 48) | (((uint64_t)v[7]) << 56); + } +#endif /* __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ */ + + /* actual iteration */ + for (r = 0; r < KECCAKF_ROUNDS; r++) + { + /* Theta */ + for (i = 0; i < 5; i++) + { + bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20]; + } + + for (i = 0; i < 5; i++) + { + t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); + for (j = 0; j < 25; j += 5) + { + st[j + i] ^= t; + } + } + + /* Rho Pi */ + t = st[1]; + for (i = 0; i < 24; i++) + { + j = keccakf_piln[i]; + bc[0] = st[j]; + st[j] = ROTL64(t, keccakf_rotc[i]); + t = bc[0]; + } + + /* Chi */ + for (j = 0; j < 25; j += 5) + { + for (i = 0; i < 5; i++) + { + bc[i] = st[j + i]; + } + for (i = 0; i < 5; i++) + { + st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; + } + } + + /* Iota */ + st[0] ^= keccakf_rndc[r]; + } + +#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ + /* endianness conversion. this is redundant on little-endian targets */ + for (i = 0; i < 25; i++) + { + v = (uint8_t *)&st[i]; + t = st[i]; + v[0] = (uint8_t)(t & 0xFF); + v[1] = (uint8_t)((t >> 8) & 0xFF); + v[2] = (uint8_t)((t >> 16) & 0xFF); + v[3] = (uint8_t)((t >> 24) & 0xFF); + v[4] = (uint8_t)((t >> 32) & 0xFF); + v[5] = (uint8_t)((t >> 40) & 0xFF); + v[6] = (uint8_t)((t >> 48) & 0xFF); + v[7] = (uint8_t)((t >> 56) & 0xFF); + } +#endif /* __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ */ +} + +/* Initialize the context for SHA3 */ + +int sha3_init(sha3_ctx_t *c, int mdlen) +{ + int i; + + for (i = 0; i < 25; i++) + { + c->st.q[i] = 0; + } + c->mdlen = mdlen; + c->rsiz = 200 - 2 * mdlen; + c->pt = 0; + + return 1; +} + +/* update state with more data */ + +int sha3_update(sha3_ctx_t *c, const void *data, size_t len) +{ + size_t i; + int j; + + j = c->pt; + for (i = 0; i < len; i++) + { + c->st.b[j++] ^= ((const uint8_t *)data)[i]; + if (j >= c->rsiz) + { + sha3_keccakf(c->st.q); + j = 0; + } + } + c->pt = j; + + return 1; +} + +/* finalize and output a hash */ + +int sha3_final(void *md, sha3_ctx_t *c) +{ + int i; + + c->st.b[c->pt] ^= 0x06; + c->st.b[c->rsiz - 1] ^= 0x80; + sha3_keccakf(c->st.q); + + for (i = 0; i < c->mdlen; i++) + { + ((uint8_t *)md)[i] = c->st.b[i]; + } + + return 1; +} + +/* compute a SHA-3 hash (md) of given byte length from "in" */ + +void *sha3(const void *in, size_t inlen, void *md, int mdlen) +{ + sha3_ctx_t sha3; + + sha3_init(&sha3, mdlen); + sha3_update(&sha3, in, inlen); + sha3_final(md, &sha3); + + return md; +} + +/* SHAKE128 and SHAKE256 extensible-output functionality */ + +void shake_xof(sha3_ctx_t *c) +{ + c->st.b[c->pt] ^= 0x1F; + c->st.b[c->rsiz - 1] ^= 0x80; + sha3_keccakf(c->st.q); + c->pt = 0; +} + +void shake_out(sha3_ctx_t *c, void *out, size_t len) +{ + size_t i; + int j; + + j = c->pt; + for (i = 0; i < len; i++) + { + if (j >= c->rsiz) + { + sha3_keccakf(c->st.q); + j = 0; + } + ((uint8_t *)out)[i] = c->st.b[j++]; + } + c->pt = j; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/custom_fips202/tiny_sha3/sha3.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/custom_fips202/tiny_sha3/sha3.h new file mode 100644 index 0000000000..158ca86486 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/custom_fips202/tiny_sha3/sha3.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: MIT + * + * sha3.h + * 19-Nov-11 Markku-Juhani O. Saarinen */ + +#ifndef SHA3_H +#define SHA3_H + +#include +#include + +#ifndef KECCAKF_ROUNDS +#define KECCAKF_ROUNDS 24 +#endif + +#ifndef ROTL64 +#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) +#endif + +/* state context */ +typedef struct +{ + union + { /* state: */ + uint8_t b[200]; /* 8-bit bytes */ + uint64_t q[25]; /* 64-bit words */ + } st; + int pt, rsiz, mdlen; /* these don't overflow */ +} sha3_ctx_t; + +/* Compression function. */ +void sha3_keccakf(uint64_t st[25]); + +/* OpenSSL - like interfece */ +int sha3_init(sha3_ctx_t *c, int mdlen); /* mdlen = hash output in bytes */ +int sha3_update(sha3_ctx_t *c, const void *data, size_t len); +int sha3_final(void *md, sha3_ctx_t *c); /* digest goes to md */ + +/* compute a sha3 hash (md) of given byte length from "in" */ +void *sha3(const void *in, size_t inlen, void *md, int mdlen); + +/* SHAKE128 and SHAKE256 extensible-output functions */ +#define shake128_init(c) sha3_init(c, 16) +#define shake256_init(c) sha3_init(c, 32) +#define shake_update sha3_update + +void shake_xof(sha3_ctx_t *c); +void shake_out(sha3_ctx_t *c, void *out, size_t len); + +#endif /* !SHA3_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/expected_signatures.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/expected_signatures.h new file mode 100644 index 0000000000..d52fbe8d5e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/expected_signatures.h @@ -0,0 +1,890 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef EXPECTED_SIGNATURES_H +#define EXPECTED_SIGNATURES_H + +#include + +/* Expected deterministic signatures for each parameter set + * These are generated using the same test message, context, and deterministic + * RNG as used in the basic example. + * + * The PCT modifies the PRNG state, so the KAT tests don't work. + * We run KAT tests only for disabled PCT. */ +#if !defined(MLD_CONFIG_KEYGEN_PCT) +#if MLD_CONFIG_PARAMETER_SET == 44 +const uint8_t expected_signature[] = { + 0x27, 0x5e, 0xbe, 0x2d, 0x23, 0x1a, 0x76, 0xc5, 0xd9, 0x77, 0xcb, 0x62, + 0x25, 0x04, 0xdb, 0x23, 0x31, 0xa9, 0xa8, 0xcd, 0xbc, 0xde, 0xf2, 0x20, + 0xfd, 0xa7, 0xb5, 0xf5, 0x59, 0xae, 0xe6, 0xdd, 0x62, 0xfa, 0x34, 0x96, + 0x4f, 0x1d, 0xcd, 0x84, 0x82, 0xee, 0xc1, 0x74, 0x96, 0x3d, 0x98, 0xd9, + 0x42, 0x9d, 0xd0, 0x77, 0x9c, 0xf9, 0x9e, 0x0e, 0xa7, 0xcb, 0x70, 0xeb, + 0xe7, 0xcd, 0xce, 0x8c, 0xdc, 0x37, 0x15, 0x95, 0x0e, 0x24, 0x70, 0x4f, + 0x33, 0x6e, 0x4f, 0xad, 0xed, 0x4d, 0xf3, 0xe5, 0x38, 0xc1, 0xcd, 0xbb, + 0xde, 0xf1, 0xd2, 0x0d, 0xd6, 0x6b, 0xa3, 0x68, 0x92, 0x4c, 0x4b, 0x4f, + 0x89, 0xa0, 0xa8, 0xc8, 0x36, 0x93, 0x91, 0x17, 0xe7, 0x16, 0xed, 0xcb, + 0xdc, 0xf6, 0x28, 0x13, 0x32, 0x60, 0x14, 0xe0, 0x28, 0x7a, 0x69, 0x05, + 0x1d, 0xf7, 0x3b, 0xdf, 0x18, 0x0c, 0xaf, 0xba, 0x46, 0xf1, 0x5e, 0xd4, + 0xd3, 0xd0, 0x8e, 0x9a, 0xe2, 0xac, 0xdd, 0x0e, 0x5f, 0xb1, 0x69, 0xe2, + 0x74, 0x77, 0x2e, 0x52, 0xf9, 0x11, 0x3d, 0xd8, 0xe5, 0x36, 0x6f, 0x7d, + 0x7d, 0xde, 0x7c, 0xa7, 0x1d, 0x37, 0xdf, 0x6d, 0x5e, 0xea, 0xc8, 0xc0, + 0x72, 0x3f, 0x79, 0xbd, 0x0b, 0x6d, 0x7f, 0x9a, 0x15, 0x90, 0xda, 0xc1, + 0xae, 0xce, 0xf3, 0x44, 0x35, 0x5e, 0x83, 0x86, 0x7e, 0x89, 0x18, 0xa7, + 0x97, 0x8e, 0x87, 0x7c, 0x15, 0xd2, 0xd2, 0x7e, 0xf2, 0xc8, 0x29, 0x4f, + 0x70, 0x0f, 0xa6, 0xd4, 0x76, 0xe8, 0xdd, 0x7d, 0x7a, 0x2d, 0xfe, 0x0a, + 0x0c, 0x5c, 0xb1, 0xef, 0xec, 0x1a, 0x32, 0xca, 0x87, 0xff, 0x6b, 0xb1, + 0xa0, 0xe1, 0x2e, 0x01, 0x52, 0xb2, 0xb8, 0x74, 0x34, 0xb3, 0xfb, 0x15, + 0x0f, 0x17, 0xca, 0x74, 0xc1, 0xc1, 0x61, 0x86, 0x40, 0x38, 0x58, 0xba, + 0x82, 0x26, 0x66, 0x33, 0xa4, 0x52, 0xf3, 0xb5, 0x36, 0x60, 0xd8, 0x5a, + 0x8d, 0x9d, 0x28, 0x18, 0x3a, 0x68, 0x34, 0x2a, 0xa2, 0xe2, 0xb5, 0x39, + 0xed, 0x7d, 0xe5, 0xbe, 0x46, 0xb9, 0x04, 0x0c, 0xf3, 0xef, 0x88, 0x6e, + 0x9d, 0x6f, 0x23, 0xe2, 0x44, 0xe5, 0x2e, 0x3a, 0x7a, 0x1d, 0x49, 0x0f, + 0xdd, 0xcd, 0xd6, 0x4e, 0x0d, 0x0b, 0xc3, 0x35, 0xf2, 0xd1, 0x5d, 0x73, + 0x5d, 0x07, 0xca, 0x5c, 0xbd, 0x14, 0xec, 0x57, 0xb3, 0xbd, 0x37, 0xe7, + 0xdf, 0x06, 0x7d, 0xe0, 0x58, 0x4a, 0xcf, 0x7a, 0xc5, 0xa7, 0x24, 0x62, + 0x6f, 0x09, 0x75, 0x69, 0x74, 0x7f, 0xdf, 0xc8, 0x69, 0x5c, 0x20, 0x10, + 0x3a, 0xe8, 0x01, 0x12, 0xa3, 0xfb, 0xda, 0x4c, 0x3a, 0x0d, 0x3c, 0x3e, + 0x26, 0xe0, 0xa6, 0x7f, 0xb2, 0x6b, 0x0b, 0x68, 0x0a, 0x68, 0x86, 0xb1, + 0xfa, 0x61, 0x3a, 0xe8, 0x77, 0xdc, 0x42, 0xf7, 0xf4, 0x39, 0x9a, 0x40, + 0x58, 0x71, 0xc7, 0x0f, 0xf4, 0x0e, 0xc5, 0x1e, 0xe0, 0x28, 0x45, 0x7d, + 0xba, 0x84, 0xe4, 0x34, 0x69, 0xf9, 0xa5, 0x8a, 0x80, 0x43, 0xc0, 0x8d, + 0x04, 0x33, 0x43, 0xb8, 0xd7, 0x5d, 0x93, 0xed, 0x0f, 0x31, 0x6a, 0x4d, + 0xbf, 0xb7, 0x44, 0x41, 0x1b, 0xd4, 0xac, 0x9d, 0x83, 0x66, 0x08, 0x92, + 0xad, 0x3c, 0x0e, 0x1a, 0xe8, 0xd4, 0xe1, 0x5c, 0x63, 0xcf, 0x27, 0x48, + 0x5a, 0x8f, 0xc5, 0x6f, 0x83, 0x6b, 0x6f, 0xe8, 0xda, 0x1f, 0xba, 0xe9, + 0x7e, 0x11, 0xab, 0x8b, 0x4e, 0xc1, 0x9e, 0x23, 0x69, 0x1f, 0x42, 0x40, + 0xad, 0xbb, 0xfb, 0x4f, 0xe2, 0x50, 0xc9, 0x46, 0xe7, 0x15, 0x15, 0xf8, + 0x61, 0x09, 0x2a, 0x0b, 0x37, 0x43, 0xd4, 0x98, 0x5f, 0xc8, 0x4d, 0x06, + 0xe7, 0x0c, 0x3f, 0x83, 0x59, 0xd5, 0xcd, 0x2d, 0xde, 0x1e, 0x3a, 0x87, + 0x4e, 0xf7, 0x0a, 0x3c, 0x84, 0x72, 0x47, 0x11, 0x02, 0x6c, 0xe8, 0x93, + 0xcd, 0x24, 0xe9, 0x23, 0x86, 0x78, 0x53, 0xe0, 0xc6, 0x2f, 0xba, 0xa7, + 0xed, 0xaf, 0xba, 0x42, 0x80, 0x0d, 0xe6, 0xae, 0xda, 0xed, 0xbc, 0x65, + 0x21, 0x6d, 0x13, 0x90, 0x61, 0xb4, 0x05, 0x7b, 0x07, 0x86, 0xd7, 0x89, + 0x30, 0x9c, 0xc1, 0x9a, 0x41, 0x4d, 0xe8, 0x2b, 0x35, 0x21, 0x3a, 0x8a, + 0x60, 0x83, 0x1a, 0x97, 0x10, 0x98, 0xb6, 0xe1, 0x6b, 0xb5, 0xb1, 0xa1, + 0x36, 0x34, 0x60, 0x1b, 0x96, 0x5d, 0x1f, 0x2a, 0xd8, 0xf2, 0x94, 0xdd, + 0x58, 0x3d, 0x0f, 0xbe, 0x9d, 0xfc, 0xf5, 0x24, 0xb1, 0xd2, 0xc3, 0x36, + 0xef, 0xdb, 0x8e, 0x97, 0x3c, 0x9a, 0x4f, 0x48, 0xe3, 0x84, 0x91, 0xd8, + 0x39, 0x91, 0xf6, 0x55, 0xeb, 0x62, 0x51, 0x3d, 0x8f, 0x55, 0x60, 0x5e, + 0x00, 0xe0, 0xd2, 0xc7, 0x66, 0x51, 0xf1, 0xe2, 0xb7, 0x43, 0xc3, 0xe6, + 0x12, 0x9a, 0xe5, 0x84, 0xe0, 0x10, 0x76, 0xc7, 0x75, 0x6e, 0xa6, 0xee, + 0x11, 0xe4, 0xaf, 0xbd, 0x8a, 0x4f, 0x1d, 0x05, 0x29, 0x4f, 0xce, 0xa5, + 0x73, 0x92, 0x57, 0x7e, 0x0d, 0x11, 0xbc, 0xf8, 0x74, 0x4d, 0xf7, 0xb9, + 0x40, 0x0d, 0x5a, 0xa1, 0x19, 0x76, 0x4a, 0xae, 0x21, 0x16, 0xd4, 0x3f, + 0x76, 0xbf, 0x27, 0xbd, 0x2f, 0xe4, 0x25, 0x21, 0x00, 0x4e, 0xcc, 0x7c, + 0xc6, 0x57, 0xa4, 0xbf, 0xf1, 0x56, 0x90, 0xe0, 0xa4, 0xa3, 0xee, 0xcf, + 0x43, 0x4f, 0xda, 0x77, 0x47, 0x51, 0x79, 0x6a, 0x29, 0xb4, 0x2c, 0xdf, + 0xca, 0x47, 0xcb, 0xb8, 0x82, 0x7e, 0x44, 0x62, 0x9b, 0x8f, 0x61, 0x7b, + 0x3a, 0x93, 0x82, 0x1f, 0x69, 0xb7, 0xb1, 0xa6, 0x2c, 0xe1, 0xb2, 0x65, + 0xa0, 0x6d, 0x6f, 0xe4, 0x79, 0xd8, 0x30, 0xe0, 0xee, 0xd8, 0x83, 0x01, + 0xb2, 0x1f, 0x5c, 0x90, 0x44, 0x86, 0x48, 0x11, 0xf9, 0x11, 0xff, 0xea, + 0x45, 0x43, 0xae, 0x8a, 0x6b, 0x99, 0xf2, 0x1f, 0x02, 0x51, 0x4a, 0x35, + 0x02, 0x34, 0xd3, 0xe8, 0xda, 0xb1, 0x4b, 0xe3, 0xa5, 0x60, 0xce, 0x67, + 0xe3, 0x62, 0x59, 0xfc, 0x00, 0x0a, 0xe2, 0xfe, 0x7b, 0x1e, 0xe6, 0xf5, + 0x75, 0x19, 0x9b, 0x5e, 0xcb, 0xe6, 0xf5, 0x80, 0x9e, 0x3c, 0xb8, 0x54, + 0xd6, 0x0b, 0xfd, 0x48, 0xe0, 0xfa, 0x82, 0x2b, 0x5b, 0x26, 0xf9, 0x49, + 0xaf, 0xbe, 0x9c, 0x78, 0x73, 0xce, 0xc5, 0x65, 0xe2, 0x94, 0x2b, 0xd9, + 0xd0, 0x27, 0x3a, 0x66, 0x3e, 0xe2, 0xe0, 0x10, 0x79, 0x3d, 0xde, 0xc8, + 0x47, 0xdb, 0x1e, 0xc3, 0xe7, 0x51, 0xae, 0x59, 0xeb, 0x38, 0x66, 0x63, + 0x40, 0x8f, 0xbe, 0x1e, 0xb2, 0x2b, 0xeb, 0x64, 0x5f, 0xdd, 0x24, 0xc4, + 0x5a, 0x25, 0x59, 0xa2, 0xda, 0x4f, 0xdf, 0xf8, 0xb0, 0xb0, 0xf7, 0xcd, + 0x1f, 0x14, 0xcd, 0x09, 0x48, 0x70, 0x27, 0x1b, 0xde, 0xc4, 0xf0, 0xf3, + 0x56, 0x97, 0x8a, 0xb7, 0xf4, 0x19, 0x76, 0xe3, 0x9a, 0x33, 0x55, 0xfe, + 0x93, 0x68, 0xca, 0x1f, 0x3d, 0x44, 0x86, 0x39, 0x5d, 0x84, 0x58, 0x50, + 0xf2, 0xf1, 0xea, 0x4a, 0x5c, 0x1c, 0x74, 0xf0, 0x4b, 0xa5, 0x9c, 0x30, + 0xa0, 0x14, 0x1a, 0x80, 0xe0, 0xde, 0x3e, 0xae, 0x7f, 0x10, 0x18, 0x4a, + 0x1e, 0x9e, 0x6b, 0x75, 0x1a, 0xca, 0x08, 0x4e, 0x61, 0x72, 0x43, 0x9b, + 0x18, 0x4d, 0x2c, 0xd8, 0xb4, 0xc9, 0xea, 0x00, 0xb0, 0xdf, 0x1b, 0xcb, + 0x03, 0xc3, 0x7a, 0x27, 0xff, 0x41, 0x9d, 0xf9, 0xfd, 0xb3, 0x0c, 0xc0, + 0x48, 0x5d, 0x7c, 0xae, 0x5a, 0x72, 0x69, 0x93, 0x68, 0xe1, 0x9e, 0x9f, + 0x1f, 0x5c, 0x0a, 0x60, 0x90, 0x1a, 0x8e, 0x5a, 0x30, 0xd4, 0x2c, 0xbd, + 0xe1, 0x20, 0x51, 0xbc, 0x1c, 0x50, 0xb5, 0xf7, 0x42, 0x23, 0x35, 0x0f, + 0x92, 0xe2, 0xbb, 0x2a, 0x04, 0xa7, 0xde, 0x2e, 0x25, 0xfa, 0xed, 0x20, + 0x83, 0x9c, 0xd4, 0x56, 0xe0, 0x4d, 0x8d, 0x79, 0xa5, 0xa0, 0x6f, 0x49, + 0x62, 0x82, 0x9a, 0xa7, 0x4e, 0x54, 0x95, 0x0a, 0xc6, 0x5e, 0x27, 0x65, + 0x6d, 0x11, 0x2b, 0x35, 0x72, 0x34, 0x48, 0xd2, 0xe4, 0x9e, 0x07, 0x7d, + 0x03, 0x27, 0x15, 0x93, 0x55, 0x5c, 0x32, 0x43, 0xdb, 0x34, 0x8d, 0xbd, + 0x8d, 0x88, 0xa5, 0x24, 0x07, 0x93, 0x89, 0x37, 0xb9, 0x17, 0x15, 0xad, + 0xc7, 0x68, 0x86, 0x63, 0x0f, 0x10, 0x53, 0x8f, 0x40, 0xd3, 0x7b, 0x22, + 0x2b, 0x1a, 0x4c, 0xcb, 0x4f, 0x51, 0xf1, 0x3b, 0x19, 0xb8, 0x42, 0x53, + 0xaf, 0xf6, 0xb9, 0x57, 0x7f, 0xba, 0x8d, 0xb8, 0xb7, 0x3b, 0xe3, 0xc5, + 0xab, 0x4a, 0x26, 0x21, 0x6e, 0xce, 0x27, 0xb8, 0xc3, 0x99, 0x56, 0x14, + 0xdd, 0x5b, 0x61, 0x82, 0xbf, 0xd3, 0xc8, 0x76, 0xee, 0x22, 0xaf, 0x21, + 0x21, 0x1d, 0x4e, 0x33, 0xb5, 0x43, 0x3a, 0xfb, 0x91, 0xa0, 0xaa, 0xe3, + 0x10, 0x4a, 0x50, 0x42, 0xd4, 0x5f, 0x92, 0x0e, 0x71, 0x60, 0x4f, 0xaa, + 0xef, 0x66, 0x45, 0xfe, 0xf7, 0xc8, 0xb0, 0x73, 0x75, 0x91, 0x0b, 0x86, + 0x40, 0xa5, 0x02, 0x28, 0xf7, 0xe0, 0x1f, 0x5d, 0xe6, 0xe3, 0xa4, 0x57, + 0xbd, 0x29, 0xaa, 0x53, 0xae, 0x35, 0x30, 0x78, 0x73, 0xd6, 0xb7, 0x01, + 0x9d, 0x13, 0x50, 0xf6, 0x39, 0xa2, 0x3e, 0x03, 0x04, 0xaa, 0x6d, 0xcf, + 0x6b, 0xff, 0x9a, 0xbe, 0x3e, 0x0a, 0xd4, 0x20, 0xce, 0x42, 0x1f, 0xca, + 0x2f, 0xd3, 0x2c, 0xd1, 0xf4, 0xd2, 0x50, 0xd3, 0xa2, 0xc1, 0x1e, 0x87, + 0xbf, 0xeb, 0xb8, 0xa8, 0xd4, 0x1c, 0x96, 0xb8, 0x8e, 0xbe, 0x35, 0x5f, + 0x08, 0x28, 0x20, 0x2b, 0xdc, 0xa4, 0xf5, 0xf6, 0xde, 0xca, 0x1e, 0xcb, + 0x93, 0x3b, 0x64, 0x79, 0x00, 0x3c, 0x8d, 0xbb, 0x5c, 0x7a, 0x40, 0x14, + 0x58, 0x12, 0xa4, 0xf7, 0x6e, 0x51, 0xfb, 0xe7, 0x6f, 0x49, 0x5b, 0xc2, + 0xc9, 0x05, 0x38, 0x9c, 0x08, 0x78, 0x71, 0x27, 0x2b, 0xf5, 0xbf, 0xd6, + 0x38, 0xaa, 0x45, 0xe1, 0xe1, 0x4c, 0xfb, 0xfd, 0xb7, 0xe6, 0xcf, 0xad, + 0x9e, 0x56, 0xaf, 0x12, 0x12, 0x98, 0xe6, 0x38, 0xaa, 0xee, 0xdb, 0x9e, + 0xca, 0xe1, 0x79, 0x6d, 0x44, 0xfb, 0x19, 0x50, 0x92, 0x00, 0x06, 0x2c, + 0x24, 0x71, 0x6c, 0x34, 0x45, 0xac, 0xf9, 0x82, 0x66, 0xa8, 0x63, 0x80, + 0xa8, 0x5b, 0x21, 0x3c, 0x36, 0x71, 0x93, 0x40, 0x7b, 0xff, 0xa2, 0xd0, + 0x72, 0xb4, 0x66, 0xfa, 0xfc, 0xa0, 0xee, 0xca, 0x15, 0x73, 0x52, 0xe7, + 0x9d, 0x11, 0xd3, 0xbc, 0xab, 0x37, 0x31, 0x0e, 0xaf, 0xdc, 0x05, 0x30, + 0x79, 0x8c, 0x25, 0x75, 0x5c, 0x60, 0xc7, 0x9a, 0xfc, 0x88, 0xea, 0xe6, + 0x09, 0x9f, 0xd1, 0x4f, 0x13, 0xf4, 0x41, 0x54, 0x5b, 0x7a, 0xe4, 0x49, + 0x3c, 0x0f, 0x15, 0xe9, 0xa4, 0x85, 0xb2, 0x92, 0x07, 0xea, 0xea, 0x7c, + 0xc1, 0x6d, 0xa9, 0x03, 0xb3, 0x31, 0xce, 0x1e, 0x82, 0xca, 0x9e, 0x3c, + 0x88, 0x88, 0xc1, 0x04, 0x5f, 0xbe, 0xd5, 0x94, 0x0d, 0x67, 0x98, 0x27, + 0xd0, 0x0f, 0x43, 0xf3, 0xb3, 0xfc, 0xff, 0x24, 0xa2, 0x1e, 0x17, 0x06, + 0xb0, 0x52, 0x16, 0x7c, 0xd8, 0x49, 0x74, 0x51, 0xcf, 0x2d, 0x36, 0x16, + 0xb0, 0x88, 0xb2, 0x2b, 0x1d, 0x72, 0x70, 0xab, 0xe2, 0xf6, 0x5f, 0xa5, + 0x2d, 0x4e, 0xd1, 0x42, 0x3c, 0x83, 0x84, 0xb2, 0x56, 0xeb, 0x8d, 0xce, + 0x33, 0x46, 0xdb, 0x3d, 0x4f, 0x97, 0xea, 0x37, 0x5e, 0x0d, 0xd7, 0x4c, + 0x9a, 0x7e, 0xc9, 0x0e, 0x69, 0x4d, 0x97, 0x15, 0x1e, 0x09, 0xbe, 0x7e, + 0xff, 0xe8, 0xf5, 0xab, 0xe9, 0xe7, 0xed, 0x4b, 0x41, 0xa5, 0xf2, 0x2a, + 0x24, 0x48, 0x8b, 0x72, 0x4b, 0x9d, 0xcf, 0x45, 0xdb, 0xc0, 0xaf, 0xa8, + 0x0f, 0x0f, 0x67, 0x37, 0xd3, 0x8b, 0xe1, 0x67, 0x90, 0xd8, 0x1c, 0x58, + 0x36, 0x46, 0x51, 0x52, 0xea, 0xb4, 0x75, 0xb1, 0xcd, 0xc5, 0x39, 0x16, + 0xe0, 0xec, 0x16, 0xf7, 0xf8, 0x0f, 0x5d, 0x13, 0x84, 0x62, 0x34, 0x86, + 0x42, 0x05, 0xa8, 0x08, 0x84, 0xa9, 0x77, 0x12, 0xc1, 0x56, 0xdd, 0x28, + 0xde, 0x39, 0x33, 0x21, 0x3d, 0xbd, 0x94, 0xce, 0xe4, 0xb3, 0x17, 0x9b, + 0x09, 0x20, 0xf0, 0x25, 0xce, 0x00, 0x34, 0x8e, 0x12, 0x94, 0x74, 0x0b, + 0x16, 0xa1, 0x60, 0x76, 0x24, 0xf0, 0xbf, 0xe3, 0x3a, 0x83, 0x8f, 0x40, + 0x47, 0x2e, 0x1c, 0xd5, 0x35, 0x25, 0x87, 0xb3, 0x11, 0xdc, 0x98, 0xb0, + 0xa6, 0x5f, 0x6a, 0x05, 0x1d, 0x06, 0x8d, 0xe8, 0xb0, 0x98, 0xf0, 0x43, + 0x29, 0x84, 0xe4, 0xef, 0x34, 0x67, 0x74, 0x64, 0xe8, 0xb8, 0xf0, 0xd4, + 0x9e, 0xc1, 0x3f, 0x5f, 0xeb, 0xe0, 0x9b, 0x37, 0xf8, 0x75, 0x46, 0x47, + 0xa5, 0x3e, 0x42, 0x20, 0x50, 0xc4, 0x5d, 0xf3, 0xdf, 0x4e, 0xf8, 0x0e, + 0x1e, 0x15, 0x10, 0x3e, 0xf1, 0x68, 0xad, 0x87, 0xad, 0xe5, 0x45, 0x5e, + 0x22, 0xba, 0x2e, 0x51, 0xa0, 0xbf, 0xdc, 0x87, 0xca, 0xe4, 0x1f, 0x2f, + 0x2c, 0xae, 0xa9, 0x14, 0xd7, 0xdd, 0x01, 0xa8, 0x4f, 0x43, 0xcb, 0x84, + 0x92, 0xbf, 0xf9, 0x3d, 0xf0, 0x6b, 0x19, 0x43, 0xb0, 0xdf, 0xff, 0x94, + 0x76, 0xe2, 0x84, 0xf9, 0x31, 0x88, 0x7e, 0xc6, 0x87, 0x58, 0xbe, 0x5d, + 0x8b, 0xf8, 0xb5, 0xdc, 0x95, 0x16, 0x5f, 0xa1, 0x2c, 0xe8, 0x53, 0x36, + 0x64, 0xf5, 0x5d, 0xa0, 0x74, 0x12, 0x78, 0x59, 0x73, 0x69, 0x5a, 0x2b, + 0x36, 0x4a, 0xff, 0x5b, 0xef, 0x49, 0x2c, 0xb2, 0x9e, 0x59, 0xf0, 0x39, + 0x56, 0xe1, 0xd0, 0x1a, 0x05, 0xb2, 0x7c, 0xd1, 0x40, 0x09, 0xdf, 0x00, + 0xc9, 0x15, 0x53, 0xa2, 0xda, 0x84, 0xb5, 0x85, 0x05, 0x76, 0xa6, 0x1b, + 0xcb, 0x06, 0xb2, 0xc8, 0xa0, 0xc5, 0x23, 0x8f, 0xb0, 0xe8, 0xf5, 0xd9, + 0xd0, 0x19, 0x29, 0xfe, 0x2d, 0x9a, 0x57, 0x76, 0x5f, 0xf2, 0xef, 0x71, + 0x16, 0xee, 0x28, 0x7b, 0xe4, 0x48, 0xeb, 0xda, 0xe0, 0xd5, 0xbc, 0x0e, + 0x46, 0x6b, 0x06, 0x5d, 0xe5, 0x91, 0x2d, 0xcb, 0xc4, 0x53, 0xa6, 0x16, + 0xd5, 0xe7, 0xd8, 0xf1, 0xdd, 0x4f, 0xbb, 0xcc, 0x55, 0x67, 0x19, 0x98, + 0x94, 0x95, 0x5e, 0xd6, 0xf5, 0xf7, 0xe8, 0x6a, 0xf7, 0x20, 0x86, 0x3a, + 0x43, 0xbf, 0xe9, 0xec, 0x6b, 0x33, 0x49, 0x19, 0x43, 0xfb, 0xeb, 0x3f, + 0xf4, 0x9d, 0x29, 0x66, 0xb9, 0x6e, 0xb5, 0x15, 0x4b, 0x8d, 0x3c, 0x3c, + 0xfa, 0xf2, 0x87, 0xba, 0x61, 0x11, 0x40, 0xe6, 0xb4, 0x6f, 0xf5, 0xe1, + 0x24, 0x32, 0x69, 0x3e, 0xff, 0xf7, 0xbc, 0xee, 0x82, 0xf2, 0x9e, 0x6d, + 0x3f, 0x6c, 0xcc, 0x0f, 0x4f, 0xc3, 0xf1, 0xdb, 0x1e, 0x81, 0xd7, 0x9b, + 0x22, 0xa8, 0xa7, 0x36, 0x6d, 0xa9, 0x6f, 0x46, 0x1a, 0xa7, 0xff, 0x00, + 0x4b, 0xd8, 0xab, 0xe7, 0x50, 0x3b, 0xe9, 0xc0, 0x57, 0xec, 0x8d, 0x0c, + 0xa0, 0xee, 0x8c, 0x2a, 0x74, 0xf2, 0x94, 0xf9, 0x0c, 0x20, 0x14, 0xd9, + 0xad, 0x0d, 0x4e, 0xac, 0x35, 0x44, 0x59, 0x28, 0x24, 0x31, 0x32, 0xaa, + 0x6d, 0xc2, 0x13, 0xb9, 0xee, 0x75, 0x0c, 0x5f, 0x39, 0xef, 0x31, 0xca, + 0x28, 0x48, 0x56, 0x59, 0xfb, 0xa8, 0xd8, 0x2b, 0x70, 0x61, 0x22, 0x43, + 0x43, 0xb9, 0x60, 0x44, 0xeb, 0xf8, 0x98, 0x87, 0x25, 0x84, 0xa2, 0xaa, + 0x37, 0xd4, 0xb8, 0xd6, 0x3d, 0xa3, 0xa1, 0x4a, 0x81, 0xc2, 0xa9, 0xea, + 0xa2, 0xd6, 0x63, 0x76, 0x50, 0xeb, 0xcd, 0x19, 0x40, 0xb1, 0x7c, 0xf6, + 0xc1, 0x44, 0x01, 0x25, 0xe0, 0xdd, 0xb8, 0x39, 0xef, 0x46, 0x3d, 0x50, + 0x33, 0xed, 0xb1, 0x63, 0x65, 0xd7, 0x50, 0xe7, 0x95, 0xba, 0xab, 0xa7, + 0x14, 0xe5, 0x60, 0xcb, 0x81, 0x6e, 0x88, 0x3c, 0x06, 0x6e, 0x7d, 0x8e, + 0xe7, 0xbb, 0xa5, 0xc2, 0xbd, 0xae, 0x46, 0x8f, 0x43, 0x04, 0x29, 0xe6, + 0x17, 0x38, 0x05, 0x2d, 0x97, 0x93, 0x5b, 0xf9, 0xef, 0x4d, 0x2e, 0x75, + 0x6c, 0x69, 0xba, 0x08, 0xf2, 0x21, 0x1e, 0x21, 0xe6, 0x8a, 0x5b, 0x8c, + 0xd4, 0x8e, 0xde, 0x64, 0x9b, 0x9d, 0x54, 0x58, 0x65, 0x3e, 0xdd, 0x8a, + 0x1e, 0x81, 0x4e, 0x45, 0xe8, 0xfb, 0x20, 0xc3, 0x3a, 0xf0, 0x50, 0x1e, + 0x8a, 0x18, 0xea, 0x2b, 0xf5, 0xe1, 0xa6, 0xb6, 0xc8, 0xa0, 0x02, 0x3d, + 0x6e, 0xfa, 0x0b, 0x51, 0x95, 0x4e, 0x4c, 0x11, 0xb0, 0xc4, 0x62, 0x58, + 0xa6, 0x9c, 0x13, 0x4e, 0xbe, 0xc9, 0x29, 0x93, 0x29, 0x15, 0x5f, 0xaf, + 0x0e, 0xc3, 0xb3, 0x26, 0x3f, 0xdc, 0x4c, 0x33, 0xb8, 0x4b, 0x11, 0xae, + 0x1f, 0xd7, 0x05, 0x39, 0xcf, 0xfe, 0xc3, 0x6d, 0xf0, 0xc0, 0x77, 0x02, + 0xb8, 0x9b, 0x3d, 0x1b, 0x3d, 0x72, 0xfe, 0x7e, 0x18, 0x60, 0x9b, 0xc4, + 0x8b, 0xac, 0x25, 0x6d, 0x3b, 0x80, 0x34, 0xbc, 0x51, 0xaf, 0xf6, 0xff, + 0x66, 0x98, 0x86, 0x6e, 0x9e, 0x9a, 0xfe, 0x6d, 0x21, 0x4d, 0xf1, 0x58, + 0x3e, 0x3e, 0x43, 0xe3, 0x7e, 0x40, 0xb0, 0xb3, 0xd8, 0x12, 0xa5, 0xce, + 0x09, 0x41, 0x8c, 0x1d, 0x73, 0xcd, 0xfc, 0x63, 0xed, 0xeb, 0x08, 0x1e, + 0x34, 0xfb, 0xed, 0x75, 0xb7, 0x86, 0x84, 0x7c, 0x80, 0xe9, 0xe4, 0xa3, + 0x1c, 0x4a, 0x0d, 0x11, 0x16, 0x24, 0xb2, 0xb1, 0x99, 0xe5, 0xe3, 0x2e, + 0x2f, 0x70, 0xcd, 0x1e, 0x35, 0x14, 0x79, 0xba, 0xa2, 0x51, 0x7a, 0x29, + 0x5c, 0x75, 0x8f, 0xdd, 0x22, 0xdf, 0xb2, 0x64, 0xd9, 0x95, 0x11, 0x33, + 0x97, 0xee, 0x69, 0x42, 0x01, 0x96, 0x98, 0x1b, 0x43, 0xc2, 0xec, 0xf9, + 0xb0, 0xdb, 0x69, 0x34, 0xab, 0x98, 0x1b, 0xb2, 0x04, 0x05, 0x14, 0x1d, + 0x25, 0x2f, 0x32, 0x41, 0x50, 0x51, 0x55, 0x62, 0x6d, 0x78, 0x7f, 0x8b, + 0xbb, 0xc2, 0xcd, 0xcf, 0xe4, 0xed, 0x04, 0x1f, 0x25, 0x30, 0x43, 0x64, + 0x69, 0x7c, 0x87, 0xa3, 0xa9, 0xb1, 0xc1, 0xd1, 0xdc, 0x01, 0x10, 0x1d, + 0x27, 0x3f, 0x5c, 0x5d, 0x75, 0x82, 0x9b, 0xaa, 0xb3, 0xe8, 0x0c, 0x11, + 0x1f, 0x24, 0x38, 0x41, 0x45, 0x54, 0x5f, 0x69, 0x85, 0x8d, 0x93, 0x9e, + 0xc5, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x25, 0x32, 0x42}; +#elif MLD_CONFIG_PARAMETER_SET == 65 +const uint8_t expected_signature[] = { + 0x8b, 0x6f, 0x79, 0x00, 0xcc, 0x79, 0x57, 0xee, 0x16, 0x86, 0x87, 0xd5, + 0xcf, 0xb6, 0x90, 0x2c, 0xc6, 0x30, 0xeb, 0x8d, 0x39, 0xae, 0x9b, 0xf1, + 0x66, 0xe0, 0xd6, 0x93, 0xa5, 0x4e, 0x26, 0x9b, 0x96, 0x8f, 0xd1, 0x46, + 0x97, 0xbe, 0x71, 0x1c, 0xf3, 0xa5, 0xe5, 0xae, 0x8d, 0x4b, 0xf2, 0xe6, + 0x48, 0x8f, 0xe9, 0x5e, 0x07, 0xef, 0xe4, 0xbb, 0x39, 0xc1, 0xc9, 0x3c, + 0xc3, 0x0b, 0xfb, 0x2a, 0x29, 0x06, 0xfe, 0x01, 0xcb, 0x63, 0x83, 0x10, + 0xa8, 0xc8, 0xa0, 0x29, 0xa5, 0x80, 0xeb, 0xbd, 0xa9, 0xd9, 0x0b, 0x61, + 0xbc, 0xce, 0x11, 0x55, 0x66, 0x12, 0xc7, 0x5b, 0xd2, 0x7a, 0x5a, 0xc8, + 0xab, 0xab, 0xbf, 0x3a, 0x1f, 0x96, 0x1a, 0x70, 0xcb, 0x41, 0x5f, 0xc8, + 0xb7, 0x09, 0x22, 0x98, 0x9b, 0xb8, 0xf7, 0x2d, 0x49, 0x65, 0x1d, 0x09, + 0x8b, 0x70, 0xb5, 0x42, 0xc9, 0x89, 0x5b, 0x74, 0xb4, 0x28, 0x82, 0x01, + 0x53, 0x12, 0x3e, 0x23, 0xf6, 0x54, 0xf8, 0x51, 0x12, 0x4b, 0x02, 0x3a, + 0x7e, 0xb6, 0x1f, 0xac, 0xa0, 0xe6, 0x6f, 0xf8, 0x61, 0x82, 0xe4, 0xfb, + 0x96, 0x2a, 0xd2, 0xaf, 0x3c, 0xea, 0x6e, 0xdc, 0x18, 0x8a, 0x5d, 0x90, + 0xda, 0xa2, 0x5d, 0xa7, 0x8f, 0x5b, 0x50, 0x46, 0xaf, 0x8c, 0x17, 0x6a, + 0x4c, 0x39, 0xfc, 0x31, 0x4c, 0x4b, 0xc2, 0x57, 0x66, 0x61, 0x98, 0xbf, + 0xe6, 0xfb, 0x54, 0x96, 0xd3, 0x70, 0xb8, 0xaf, 0xcd, 0x8b, 0xcc, 0x00, + 0x07, 0x92, 0x15, 0xc2, 0xbb, 0x48, 0xbb, 0xc6, 0xb7, 0xb5, 0x58, 0x8c, + 0xfc, 0xf0, 0xda, 0x6a, 0x0d, 0xf7, 0x1d, 0x7d, 0xc6, 0x27, 0x26, 0x1a, + 0x99, 0xc5, 0x2f, 0xf8, 0x97, 0x65, 0x43, 0x86, 0xd6, 0x25, 0x23, 0x2b, + 0x06, 0x8f, 0x12, 0xa1, 0xae, 0xbb, 0x58, 0x34, 0x25, 0xec, 0x5b, 0x68, + 0xa4, 0xe1, 0x03, 0xfc, 0x26, 0xa2, 0xd6, 0x2b, 0x61, 0x10, 0x47, 0xbd, + 0x16, 0xe5, 0xca, 0x4a, 0xce, 0xed, 0x89, 0x09, 0x1a, 0xed, 0x22, 0xc1, + 0xca, 0x44, 0xe3, 0xef, 0x72, 0x34, 0xab, 0xab, 0x61, 0x5c, 0x9f, 0x5f, + 0xb5, 0xf5, 0xe8, 0x2d, 0x89, 0xea, 0x4b, 0x40, 0x65, 0x57, 0x8b, 0xa2, + 0x95, 0x40, 0x9c, 0x72, 0xc0, 0x46, 0x69, 0x45, 0x06, 0xf6, 0x07, 0x5b, + 0x2d, 0xa5, 0x46, 0xca, 0x5d, 0xfb, 0x40, 0xb7, 0x48, 0x59, 0x5b, 0xe2, + 0x1b, 0x38, 0xb2, 0x15, 0x75, 0x66, 0x67, 0x58, 0x00, 0x3f, 0xde, 0x8a, + 0x63, 0x13, 0x34, 0x6a, 0x30, 0xca, 0xb4, 0xd5, 0x3e, 0xe0, 0x6d, 0x14, + 0xb8, 0x9a, 0x48, 0xef, 0xfd, 0xbd, 0x6d, 0x20, 0x11, 0x4d, 0x25, 0xe5, + 0xab, 0x15, 0x8d, 0xe5, 0x91, 0xbc, 0xc6, 0x69, 0x8a, 0xf8, 0xab, 0x3a, + 0x82, 0xae, 0xc5, 0x03, 0x2c, 0xcf, 0x54, 0xdc, 0xcd, 0xe8, 0x49, 0x53, + 0xb5, 0xd8, 0xc2, 0x24, 0xf8, 0x8c, 0x38, 0x8f, 0xe3, 0xfe, 0x3a, 0x18, + 0x15, 0xa8, 0xda, 0x77, 0xc8, 0x81, 0x72, 0xc6, 0xc1, 0x60, 0xa3, 0x73, + 0x65, 0x68, 0x5c, 0xf3, 0x1d, 0x8d, 0x61, 0x21, 0x65, 0xfb, 0x45, 0xc4, + 0x4c, 0x31, 0x88, 0x25, 0x0d, 0x52, 0x75, 0x3b, 0xec, 0x54, 0xe0, 0xb1, + 0x9c, 0x7c, 0xdf, 0xe3, 0x3b, 0x77, 0x31, 0x33, 0xd7, 0x25, 0x99, 0xff, + 0xc5, 0x40, 0x1e, 0x85, 0x09, 0xfd, 0x2d, 0x24, 0x4a, 0x92, 0xe7, 0x77, + 0x48, 0xa5, 0x46, 0xf4, 0x8e, 0xa3, 0x6b, 0x24, 0xe4, 0x6b, 0x31, 0xf6, + 0xe0, 0x16, 0x49, 0x9b, 0x9f, 0xa3, 0x1a, 0x5c, 0x05, 0x5e, 0x81, 0x62, + 0xc8, 0x14, 0x52, 0xb4, 0x21, 0xfd, 0x76, 0x6d, 0x88, 0xe9, 0x3b, 0x0b, + 0x75, 0x27, 0x92, 0x47, 0x5a, 0x58, 0x08, 0x26, 0xa7, 0xa2, 0x48, 0x1c, + 0x14, 0x3e, 0x5e, 0xdf, 0x81, 0x83, 0x83, 0x3e, 0xc6, 0x72, 0x27, 0xc4, + 0x6a, 0x46, 0x2b, 0xf2, 0x8d, 0x42, 0x11, 0xb9, 0x15, 0xd7, 0xf0, 0x20, + 0x29, 0x53, 0xba, 0xf0, 0x6e, 0x41, 0x3d, 0xee, 0x19, 0xf2, 0x43, 0xf3, + 0x6d, 0x00, 0xe2, 0x43, 0x77, 0xb9, 0xa9, 0x78, 0x34, 0x48, 0x3c, 0x1a, + 0x8b, 0xbd, 0xa1, 0xe5, 0x90, 0x59, 0x5b, 0xd6, 0x1e, 0x22, 0xdf, 0xb2, + 0xa7, 0x96, 0x7d, 0x55, 0x86, 0x66, 0x95, 0xb7, 0x06, 0xe7, 0x60, 0x2a, + 0x01, 0x48, 0x3f, 0xd4, 0xa7, 0xd4, 0xc2, 0x38, 0xa4, 0x10, 0x8e, 0x4f, + 0x97, 0xad, 0xa3, 0xb9, 0xe2, 0xaa, 0x13, 0xb1, 0x16, 0x89, 0x3d, 0x74, + 0x60, 0x94, 0x8c, 0xc3, 0xe6, 0x5f, 0xcf, 0xdc, 0x58, 0x17, 0x98, 0x27, + 0x86, 0xae, 0x2a, 0x0d, 0xe8, 0x33, 0x79, 0xc8, 0xc8, 0x5b, 0x59, 0xb0, + 0xba, 0xac, 0xd3, 0x6e, 0x2d, 0x7b, 0x0b, 0x9a, 0xb5, 0xfd, 0x58, 0x42, + 0xeb, 0x80, 0xf4, 0x6b, 0x9a, 0x2f, 0x19, 0x43, 0x75, 0xb4, 0xcb, 0xc9, + 0xd5, 0x28, 0xf5, 0xb9, 0x67, 0x82, 0xb4, 0xed, 0x8c, 0x3f, 0x3d, 0x6b, + 0x6d, 0x1b, 0x80, 0x13, 0x5c, 0x7b, 0x2e, 0xfa, 0xa0, 0x32, 0xba, 0xb5, + 0x46, 0xd6, 0xe7, 0x90, 0xe9, 0xd1, 0x91, 0xa0, 0xaa, 0x26, 0x35, 0xa2, + 0x0d, 0x98, 0x44, 0x11, 0xae, 0xf9, 0xc5, 0x12, 0x4d, 0x1a, 0x7c, 0x53, + 0xea, 0xf6, 0x05, 0x8d, 0x3a, 0x74, 0x92, 0xc9, 0x65, 0xeb, 0x6f, 0xb5, + 0xb4, 0xd2, 0xcd, 0x5c, 0xec, 0xaf, 0x95, 0xcb, 0xb4, 0x3c, 0x22, 0xca, + 0x1c, 0x06, 0x85, 0x16, 0x96, 0x24, 0x8c, 0x6c, 0x80, 0xf8, 0xb3, 0xa7, + 0x87, 0x77, 0xeb, 0x09, 0x71, 0xc8, 0x95, 0xfb, 0x5e, 0xe5, 0x6f, 0x78, + 0xf9, 0x60, 0xf9, 0x9e, 0x58, 0x7b, 0xbd, 0x47, 0xdd, 0x48, 0x2e, 0x56, + 0xcd, 0x63, 0x72, 0xc9, 0x4b, 0x65, 0x2d, 0x41, 0xe8, 0x81, 0x19, 0x33, + 0x4b, 0xf6, 0x02, 0xc6, 0xcb, 0x2e, 0xdf, 0x3d, 0xc8, 0xdd, 0x2f, 0x0f, + 0x09, 0x67, 0xf0, 0xaa, 0x3c, 0x51, 0xdc, 0x8d, 0xc6, 0xc3, 0xb2, 0x3b, + 0x15, 0x85, 0xcb, 0xeb, 0x62, 0xef, 0xa3, 0xf9, 0x94, 0xf4, 0x35, 0x9c, + 0x59, 0xcc, 0xc2, 0x68, 0xb4, 0xde, 0x02, 0x75, 0x8e, 0xf5, 0x33, 0xca, + 0xd5, 0xc5, 0x24, 0xae, 0xf6, 0xde, 0x2b, 0x01, 0xf4, 0x56, 0xb9, 0xa5, + 0xa7, 0xe0, 0x64, 0x2e, 0xba, 0x1d, 0x53, 0x54, 0x46, 0xcf, 0x64, 0x16, + 0x12, 0xe2, 0xa6, 0xcc, 0x18, 0xb4, 0x77, 0x8b, 0x19, 0x50, 0x43, 0x96, + 0xc8, 0x5d, 0xc3, 0x58, 0xf0, 0xfd, 0x5e, 0x13, 0xa9, 0x10, 0x67, 0xdf, + 0x25, 0xdb, 0xaf, 0x38, 0x5f, 0xbd, 0x35, 0xc1, 0x49, 0x44, 0xe8, 0x1f, + 0x12, 0xa4, 0x7c, 0x28, 0xa3, 0xd6, 0x0d, 0x6f, 0x44, 0xa9, 0x5f, 0xfc, + 0x9f, 0xfa, 0x11, 0x62, 0x87, 0x5b, 0x0e, 0x91, 0xd4, 0xb6, 0xd3, 0x71, + 0xc2, 0x77, 0x19, 0xf6, 0x7c, 0x11, 0x30, 0x5e, 0x5c, 0xd3, 0x1e, 0x90, + 0x05, 0x31, 0x63, 0xbb, 0xef, 0x85, 0xe0, 0x27, 0x94, 0x80, 0xcb, 0x33, + 0xbc, 0x5e, 0x45, 0x87, 0x62, 0xdf, 0xd4, 0x12, 0x2f, 0xf5, 0x41, 0x15, + 0x03, 0x0c, 0x80, 0xe8, 0xe2, 0x06, 0xde, 0x4b, 0x46, 0x70, 0x94, 0xd2, + 0x0d, 0x85, 0x72, 0x27, 0xe5, 0x6c, 0xeb, 0xd2, 0x78, 0x0b, 0x38, 0x40, + 0xe8, 0xdb, 0x47, 0x5c, 0xba, 0xd0, 0x21, 0x33, 0x8f, 0xb8, 0xc0, 0x66, + 0x1e, 0xd1, 0xb0, 0x94, 0xa3, 0x39, 0xc7, 0x87, 0xaf, 0x97, 0x98, 0xce, + 0x6d, 0x03, 0x1a, 0xdb, 0x52, 0x96, 0x0b, 0x9d, 0x5b, 0xf8, 0xa3, 0xf4, + 0x41, 0x95, 0x72, 0xad, 0x0e, 0x98, 0x61, 0x7f, 0xf3, 0x8f, 0x23, 0xeb, + 0xc0, 0xdf, 0xd7, 0x70, 0x26, 0x8c, 0xb3, 0xb3, 0xf0, 0xa2, 0x8a, 0x39, + 0xdd, 0x61, 0xb4, 0x53, 0xe0, 0x2a, 0x6f, 0x91, 0x34, 0x9c, 0x76, 0xf6, + 0x52, 0x93, 0xe6, 0x39, 0xb7, 0x54, 0x07, 0x46, 0x82, 0x2d, 0x05, 0x6d, + 0x9a, 0x00, 0x53, 0x65, 0x68, 0x93, 0x91, 0x00, 0xda, 0xe0, 0x93, 0x34, + 0x60, 0xb1, 0x93, 0x0b, 0x64, 0xa8, 0x12, 0xd2, 0x51, 0x3c, 0xdb, 0xb0, + 0x4c, 0x39, 0x4e, 0xce, 0xbd, 0xf0, 0x65, 0x12, 0x8a, 0xd4, 0x80, 0x7d, + 0x82, 0x85, 0xe4, 0x92, 0xc2, 0x77, 0x1e, 0xcf, 0xd9, 0xab, 0x0f, 0x9b, + 0x32, 0x2e, 0x3f, 0xe1, 0x0e, 0x87, 0x1c, 0x87, 0x34, 0xe7, 0x93, 0x16, + 0x95, 0x09, 0x7d, 0x24, 0xa8, 0xb5, 0xe0, 0x9f, 0x23, 0x87, 0x5c, 0x0b, + 0x31, 0x4a, 0x2f, 0xe2, 0x5c, 0x82, 0x49, 0x51, 0xe4, 0x93, 0xcb, 0x05, + 0x23, 0x4f, 0x8a, 0x83, 0x88, 0xfb, 0x89, 0xb0, 0x08, 0xd6, 0x64, 0xad, + 0x51, 0x84, 0x40, 0x29, 0xb1, 0xca, 0x74, 0x26, 0x29, 0x5a, 0x61, 0x01, + 0x2e, 0xa0, 0xeb, 0xeb, 0x02, 0xb5, 0xff, 0xd8, 0x20, 0x6a, 0x5e, 0x8d, + 0x17, 0x1e, 0xa3, 0xd7, 0x2f, 0x20, 0x0b, 0x93, 0x17, 0x24, 0xf7, 0x90, + 0x7b, 0xc6, 0xba, 0xd8, 0xf9, 0xe9, 0x0a, 0x2a, 0x7a, 0x81, 0x23, 0x81, + 0x03, 0x6f, 0x1e, 0x0d, 0x87, 0x83, 0xd1, 0xcf, 0x92, 0x2f, 0x19, 0x82, + 0x4e, 0x6c, 0x0a, 0x02, 0xb6, 0x70, 0xbc, 0xe1, 0x58, 0xe7, 0x16, 0xdb, + 0x2f, 0x74, 0x9f, 0xe1, 0xc2, 0x1e, 0x64, 0xc6, 0x48, 0x08, 0xee, 0xea, + 0x52, 0x9a, 0xce, 0x2c, 0xc5, 0x0c, 0x7a, 0x63, 0xf1, 0x6a, 0xbd, 0x2c, + 0x8b, 0xd5, 0x4a, 0xfa, 0x1e, 0xab, 0x9a, 0x5b, 0x25, 0xb8, 0xfa, 0x0a, + 0xe9, 0x68, 0x80, 0x6f, 0x80, 0x57, 0x10, 0x54, 0xb8, 0xa2, 0x16, 0xbd, + 0xfe, 0xf7, 0xea, 0x01, 0xc7, 0x94, 0x5a, 0x95, 0xe3, 0x61, 0xa5, 0x49, + 0x84, 0xf5, 0x79, 0x78, 0xb5, 0x0a, 0x96, 0xca, 0x01, 0x1b, 0xd0, 0x0b, + 0x51, 0x30, 0xd3, 0x48, 0xfc, 0x4d, 0x50, 0x71, 0x09, 0x73, 0xea, 0x37, + 0xcd, 0x9d, 0x3d, 0xde, 0x30, 0x56, 0x21, 0xf0, 0xef, 0x84, 0xad, 0x27, + 0xe1, 0x83, 0xdb, 0xfb, 0xcd, 0x11, 0xb2, 0xbd, 0x30, 0x67, 0x8a, 0x88, + 0x09, 0x0e, 0x9d, 0x96, 0x09, 0xba, 0xda, 0x9d, 0xf0, 0xe9, 0xb4, 0xa6, + 0x7a, 0x04, 0xf9, 0x4b, 0xb8, 0x51, 0xa9, 0x99, 0xf3, 0xbb, 0x77, 0x95, + 0x0a, 0xa1, 0xa6, 0xa1, 0x24, 0xfc, 0xcc, 0x45, 0xe8, 0x83, 0xc8, 0x6f, + 0x48, 0xad, 0x9a, 0x73, 0xd0, 0xe0, 0x57, 0x7d, 0xe4, 0x78, 0x65, 0xef, + 0xae, 0xc2, 0xfe, 0x7a, 0x56, 0xaf, 0x03, 0x71, 0x2b, 0xe6, 0xa1, 0x7e, + 0xe5, 0x12, 0xf8, 0xc3, 0x75, 0xc7, 0x22, 0x5f, 0x1b, 0x52, 0x90, 0xe5, + 0xdf, 0xba, 0x9d, 0xe2, 0x68, 0xe0, 0xb3, 0x7a, 0x9e, 0x14, 0xff, 0xb5, + 0x0a, 0x80, 0x20, 0x49, 0x88, 0xe9, 0x9c, 0xe4, 0xb5, 0xaf, 0x7e, 0x51, + 0xec, 0xe7, 0xfc, 0x64, 0x65, 0x21, 0x10, 0xc6, 0x1f, 0x7f, 0x93, 0x7d, + 0xd8, 0xf5, 0xd0, 0x98, 0x94, 0x44, 0xf8, 0x49, 0x6a, 0x51, 0x0a, 0x54, + 0xf4, 0x9f, 0xee, 0x3c, 0x56, 0xbf, 0x4c, 0xe4, 0xde, 0x1c, 0x9b, 0x11, + 0x7e, 0x9a, 0x71, 0x11, 0x80, 0x33, 0xd5, 0xb0, 0x9b, 0xef, 0x67, 0x29, + 0xa4, 0x7d, 0x70, 0x31, 0x3f, 0x8b, 0x2e, 0x4a, 0x0f, 0x2c, 0x91, 0x3d, + 0x3e, 0x3d, 0x8c, 0x0a, 0x2b, 0xf1, 0xdd, 0xbf, 0x61, 0xe6, 0xa3, 0xef, + 0x6d, 0x82, 0xc8, 0xb7, 0x5e, 0x2b, 0x83, 0xc9, 0x4e, 0xa0, 0x85, 0x7f, + 0x01, 0x5a, 0xca, 0x6e, 0x90, 0xfa, 0x7e, 0x82, 0x4d, 0x35, 0x7e, 0xe0, + 0x26, 0x40, 0xf4, 0xa6, 0xae, 0xc3, 0x89, 0xf3, 0xca, 0x55, 0x2c, 0xb5, + 0x29, 0x05, 0x94, 0x45, 0xa7, 0x45, 0xf3, 0x3d, 0xbb, 0x53, 0x5e, 0xca, + 0x7c, 0x84, 0x8f, 0x72, 0x98, 0x93, 0x90, 0x1f, 0x56, 0x72, 0xdb, 0xbd, + 0xa9, 0xeb, 0xf9, 0xe9, 0xce, 0xb1, 0x41, 0xc3, 0xaa, 0xa0, 0xc4, 0x74, + 0x23, 0xc1, 0xeb, 0x7d, 0x41, 0xcd, 0xa4, 0x62, 0xec, 0xfc, 0x9a, 0xa4, + 0x16, 0xec, 0x67, 0x41, 0x89, 0xf0, 0x0e, 0xf3, 0xd1, 0xa2, 0x2f, 0xba, + 0x5d, 0x93, 0x36, 0x46, 0xf5, 0x52, 0x64, 0x91, 0xe7, 0x40, 0x91, 0x20, + 0xa1, 0xc9, 0xaa, 0x4c, 0x79, 0xc4, 0xbb, 0x67, 0x79, 0xad, 0x43, 0xab, + 0xba, 0xde, 0xfc, 0xf1, 0x74, 0x81, 0x33, 0xc0, 0x3f, 0x39, 0xd1, 0xd1, + 0xdf, 0xc0, 0x53, 0x33, 0xb2, 0x92, 0x37, 0xe6, 0x86, 0x2a, 0xe4, 0xe1, + 0x7c, 0x98, 0xf7, 0xdb, 0x5c, 0xa9, 0xff, 0x8d, 0x9c, 0xab, 0xe2, 0xf2, + 0xd5, 0xb1, 0x42, 0xa9, 0xf4, 0x97, 0x80, 0xcd, 0xde, 0x25, 0x2e, 0x87, + 0x92, 0xdd, 0xcf, 0xed, 0x67, 0x93, 0x8c, 0x5a, 0x1d, 0xee, 0xcf, 0x9d, + 0x50, 0x8f, 0xa7, 0xe3, 0x5c, 0xa3, 0x68, 0x78, 0x24, 0xeb, 0x60, 0xa3, + 0x8b, 0x36, 0xbb, 0xcb, 0x46, 0xee, 0x77, 0xfb, 0xf8, 0x69, 0x24, 0xd1, + 0xfa, 0xad, 0x76, 0x76, 0x5e, 0x54, 0xe5, 0xb6, 0x36, 0xc6, 0xdd, 0xa9, + 0x6c, 0x44, 0x15, 0xf7, 0x0a, 0xf8, 0xbb, 0xba, 0xec, 0x35, 0xff, 0xc9, + 0xd6, 0x5d, 0xf5, 0x73, 0x4a, 0x15, 0x8f, 0x7b, 0x6e, 0xf4, 0xa0, 0x6d, + 0x10, 0xbb, 0x67, 0x0c, 0xb4, 0x69, 0xad, 0xb6, 0x40, 0xf7, 0x5f, 0x37, + 0x28, 0xc4, 0x08, 0x49, 0xd0, 0x16, 0x70, 0x80, 0xea, 0x55, 0x66, 0x07, + 0xc8, 0x03, 0x1b, 0xf6, 0xd3, 0x03, 0x04, 0x74, 0xe0, 0x50, 0x3f, 0xd2, + 0x53, 0x92, 0xa0, 0x9d, 0x59, 0xc9, 0x74, 0xf2, 0x7e, 0x3b, 0x33, 0x02, + 0x10, 0x0b, 0x39, 0xf7, 0x4f, 0x6b, 0x58, 0xb2, 0x1a, 0xda, 0x65, 0x44, + 0xd1, 0x7c, 0x3f, 0xd7, 0xe3, 0xac, 0xe2, 0x1f, 0x38, 0xc1, 0x6a, 0xb0, + 0xdc, 0xc3, 0x9c, 0x7b, 0x11, 0x3c, 0x05, 0x21, 0x96, 0x76, 0x98, 0x76, + 0x82, 0xc1, 0x54, 0xdf, 0xdc, 0x8f, 0x4c, 0xd2, 0x63, 0x04, 0x06, 0x77, + 0x36, 0xe6, 0x2e, 0xd1, 0x00, 0x28, 0x42, 0x7c, 0x4a, 0x27, 0x90, 0x46, + 0xc9, 0xce, 0x33, 0x1c, 0xae, 0xda, 0x79, 0x64, 0x7f, 0x52, 0x3f, 0x58, + 0x11, 0x76, 0x4a, 0xb6, 0x72, 0xd8, 0x76, 0xae, 0xfd, 0x5c, 0x57, 0x69, + 0x76, 0x91, 0x84, 0x21, 0xc4, 0x9b, 0xd8, 0xa2, 0xff, 0x93, 0x02, 0x77, + 0x61, 0x57, 0x96, 0x7b, 0x8e, 0xfc, 0xf2, 0x6c, 0x11, 0x2b, 0x5e, 0x88, + 0x5c, 0x17, 0x1d, 0x12, 0x79, 0x3a, 0x78, 0xb6, 0x9d, 0x70, 0xfa, 0xd4, + 0xc1, 0x5c, 0x90, 0x0e, 0x0a, 0xd1, 0x3c, 0x7d, 0xcf, 0xee, 0x8a, 0xb2, + 0xb2, 0x4d, 0xce, 0x89, 0x32, 0xa9, 0x6c, 0x56, 0x57, 0x85, 0xb1, 0xbf, + 0x18, 0x1d, 0xc6, 0xe1, 0x17, 0xc5, 0x92, 0x42, 0x99, 0xf9, 0x9f, 0x04, + 0xec, 0x38, 0xf8, 0xa0, 0xd2, 0xab, 0xe6, 0x13, 0x4d, 0x9c, 0x18, 0x86, + 0x3e, 0x18, 0x73, 0x2c, 0xac, 0xe0, 0xb9, 0xf9, 0x87, 0x74, 0xb8, 0xd7, + 0x47, 0x6e, 0x42, 0xfc, 0x29, 0xa0, 0x1f, 0x56, 0x68, 0xb6, 0x23, 0x96, + 0xa2, 0x8d, 0x54, 0x81, 0x0f, 0x60, 0xb9, 0xde, 0x93, 0xfc, 0xfd, 0xde, + 0xbe, 0xb3, 0xb5, 0x87, 0xec, 0x9f, 0x17, 0xc2, 0x77, 0x6e, 0xa0, 0x62, + 0xdb, 0x66, 0xba, 0xc5, 0x05, 0x12, 0x46, 0x5d, 0x3c, 0x23, 0x29, 0x68, + 0xe5, 0x31, 0xe3, 0x15, 0xec, 0xac, 0x15, 0x9a, 0xbf, 0x42, 0x65, 0x80, + 0x45, 0x9c, 0x1d, 0xc2, 0x0e, 0x18, 0x47, 0x40, 0x44, 0xc1, 0x55, 0x24, + 0x5a, 0x35, 0xad, 0x59, 0xd2, 0xc6, 0xc3, 0x68, 0x58, 0xbd, 0x6f, 0xcf, + 0x5d, 0xb1, 0x9b, 0x0c, 0x92, 0x39, 0x22, 0x49, 0x66, 0x2e, 0x03, 0x7b, + 0x75, 0x5c, 0x6c, 0xde, 0x37, 0x54, 0xa9, 0x07, 0x2f, 0x7e, 0xc1, 0x3e, + 0x3b, 0xab, 0xd2, 0xa9, 0xfa, 0xc7, 0x6b, 0xd5, 0x14, 0x08, 0x35, 0x89, + 0x0b, 0x31, 0x18, 0x54, 0x7d, 0x6b, 0x53, 0x80, 0x6e, 0x32, 0x9b, 0xff, + 0x61, 0x7f, 0x36, 0xe5, 0x28, 0x40, 0xbc, 0xc7, 0x19, 0xb3, 0xae, 0xfa, + 0x95, 0xa8, 0xae, 0xd2, 0x97, 0x72, 0xc6, 0x91, 0x36, 0x3a, 0xa6, 0xec, + 0x4a, 0x41, 0x63, 0x6b, 0x28, 0xef, 0x5a, 0xa1, 0xdb, 0xf2, 0xd9, 0xfd, + 0x61, 0x72, 0xa4, 0xd2, 0x9e, 0xf7, 0x47, 0xf4, 0x4e, 0xea, 0x2a, 0xa5, + 0x35, 0xe1, 0x77, 0x3a, 0x53, 0x28, 0xa6, 0x55, 0x48, 0x0c, 0x1e, 0x44, + 0xfc, 0xc1, 0x31, 0x5a, 0x00, 0xcd, 0x29, 0xc1, 0x5c, 0xca, 0x2a, 0x07, + 0x01, 0x63, 0xac, 0xb3, 0xfb, 0xf6, 0x0b, 0xac, 0xfd, 0xe8, 0x7b, 0xed, + 0xf9, 0x3d, 0x9a, 0xbc, 0x67, 0x28, 0x1c, 0xd9, 0x3f, 0x97, 0x28, 0x4a, + 0xe7, 0xd0, 0x08, 0xe9, 0x3e, 0xa0, 0xcb, 0x0f, 0xe0, 0x3f, 0x1b, 0x80, + 0x43, 0x74, 0xd9, 0x9d, 0x0b, 0x22, 0x81, 0xf7, 0xec, 0x71, 0x2a, 0x29, + 0x9e, 0x5d, 0x1e, 0x8d, 0xf4, 0x22, 0x95, 0x78, 0x86, 0xcb, 0xf0, 0x9d, + 0xe7, 0x6a, 0x66, 0x7e, 0x28, 0xb5, 0x47, 0xb6, 0xdc, 0x0d, 0x03, 0x3c, + 0x09, 0x58, 0x76, 0x93, 0x39, 0xb2, 0xd3, 0x75, 0xb4, 0x51, 0x55, 0x84, + 0x30, 0x24, 0x0a, 0x76, 0xf4, 0x97, 0xe7, 0x0f, 0x5a, 0x67, 0xee, 0xf4, + 0xc7, 0x69, 0x8d, 0xf2, 0x32, 0x29, 0x5c, 0x33, 0x82, 0x5f, 0x6c, 0x47, + 0xd0, 0xe2, 0xbd, 0x62, 0xd6, 0x4c, 0x6d, 0x0d, 0xba, 0x87, 0xd3, 0x43, + 0x7e, 0x2d, 0xa6, 0x14, 0x09, 0x4f, 0x3b, 0xc3, 0x04, 0x14, 0xe5, 0x65, + 0xe9, 0x3b, 0x6a, 0xca, 0xb5, 0x96, 0x84, 0x3f, 0x53, 0x49, 0x22, 0x45, + 0x91, 0xff, 0xf9, 0x26, 0x75, 0x0d, 0x9c, 0xa7, 0x00, 0xf4, 0x65, 0xc4, + 0x60, 0x72, 0xab, 0xeb, 0xf8, 0xa8, 0x72, 0xfe, 0xd8, 0xde, 0x93, 0x67, + 0xcb, 0x09, 0xcc, 0xa0, 0xce, 0x9f, 0x67, 0x63, 0x26, 0xfa, 0x7f, 0x89, + 0xaa, 0x3e, 0x6d, 0xb2, 0x90, 0xd7, 0xef, 0x3e, 0x2a, 0x66, 0x26, 0x33, + 0xe6, 0x26, 0xc1, 0x58, 0xf8, 0x91, 0xea, 0x2f, 0xd0, 0x84, 0x21, 0x41, + 0x93, 0xa6, 0x36, 0x40, 0xb5, 0x4c, 0xac, 0x21, 0x88, 0x37, 0x47, 0x8a, + 0xb8, 0xf3, 0x33, 0x73, 0x12, 0xd7, 0x5a, 0x55, 0xf9, 0xd1, 0x1e, 0x75, + 0xa4, 0x66, 0x68, 0x3f, 0xf7, 0xb2, 0xc4, 0x5d, 0x1b, 0xb1, 0x61, 0x0f, + 0xaf, 0x4b, 0x9b, 0x20, 0x2b, 0x05, 0x68, 0x1c, 0x6c, 0x97, 0x8d, 0xb8, + 0x7b, 0x96, 0xda, 0xe0, 0x67, 0x15, 0x4c, 0x51, 0x71, 0x0d, 0xd3, 0x7b, + 0xde, 0xaa, 0xd3, 0x58, 0xf5, 0xc9, 0x62, 0x0a, 0xc2, 0x33, 0x1f, 0xf3, + 0xc3, 0x30, 0xb5, 0x64, 0xd1, 0x59, 0x41, 0x0e, 0xae, 0xaa, 0x0d, 0xdf, + 0x9f, 0x5d, 0x3f, 0x15, 0x0d, 0x46, 0x7a, 0x6d, 0x2e, 0x29, 0x1b, 0xc0, + 0xd3, 0x11, 0x10, 0x5d, 0xdc, 0x6a, 0x35, 0x8c, 0x43, 0xc8, 0x9f, 0x05, + 0x80, 0xdc, 0x25, 0x24, 0x37, 0x70, 0x7e, 0x1c, 0xe9, 0x85, 0x5a, 0xef, + 0x83, 0x3a, 0x55, 0x68, 0x83, 0x17, 0xf4, 0xc7, 0xae, 0xe4, 0x84, 0xc9, + 0x64, 0x5d, 0x2f, 0xb6, 0xca, 0x10, 0x95, 0xb8, 0xd6, 0x80, 0xfd, 0x05, + 0xa5, 0x06, 0x32, 0x34, 0x91, 0x01, 0xd2, 0x02, 0x90, 0xe1, 0xf7, 0x89, + 0x8a, 0xee, 0x18, 0x04, 0x93, 0xd9, 0xb4, 0x63, 0x4b, 0xf7, 0x7a, 0x9c, + 0x1b, 0x4b, 0xf9, 0x31, 0x32, 0xd9, 0xf2, 0x55, 0x4e, 0xc1, 0x02, 0xce, + 0x77, 0x38, 0x36, 0x29, 0xb8, 0x54, 0x8c, 0xc2, 0x27, 0x5f, 0xd9, 0xae, + 0x3e, 0x1e, 0xcd, 0xe9, 0x07, 0x90, 0x4c, 0xe0, 0xda, 0x16, 0x6e, 0xdf, + 0xde, 0x3a, 0x61, 0x89, 0x9f, 0x79, 0xd0, 0xd4, 0x66, 0x95, 0xad, 0xe4, + 0x11, 0x7d, 0xa1, 0xae, 0xec, 0x3e, 0x6e, 0x20, 0x5a, 0xd0, 0x28, 0x0e, + 0x55, 0xec, 0xcf, 0x34, 0xec, 0xb7, 0xfc, 0xa4, 0xb3, 0x8f, 0x56, 0x13, + 0x50, 0xcc, 0x15, 0x10, 0x74, 0x40, 0x72, 0x42, 0x20, 0x22, 0xb3, 0xaf, + 0xf3, 0x68, 0xba, 0x95, 0x45, 0xcb, 0xef, 0x92, 0xd5, 0x14, 0x4c, 0x1f, + 0xe3, 0xc1, 0xa6, 0x03, 0x4e, 0x05, 0xd2, 0x1a, 0xee, 0xd2, 0x48, 0x44, + 0x2e, 0x50, 0x3b, 0x86, 0xc8, 0x6a, 0xc8, 0x4c, 0xca, 0x2a, 0xb6, 0xf7, + 0x3c, 0xaf, 0xdc, 0x62, 0xb1, 0x49, 0x13, 0xfe, 0xe7, 0x32, 0xea, 0x78, + 0xfa, 0xba, 0xcf, 0x15, 0x47, 0x58, 0xdc, 0x19, 0x73, 0x1d, 0xff, 0xbd, + 0xcc, 0x27, 0xf6, 0xfc, 0x66, 0x68, 0xa7, 0x29, 0xaf, 0x2b, 0x25, 0x0c, + 0x15, 0x47, 0xff, 0xc1, 0x00, 0x9d, 0xfa, 0x58, 0x9c, 0xaa, 0xf9, 0xcc, + 0x4c, 0x51, 0x1d, 0xda, 0xf3, 0x3c, 0x10, 0xd0, 0x3b, 0x59, 0x30, 0x02, + 0x68, 0x29, 0x1c, 0xa7, 0x22, 0xea, 0x81, 0xd3, 0x29, 0x71, 0x39, 0xe8, + 0x72, 0x7f, 0x7d, 0x94, 0x0a, 0x64, 0x2c, 0xe6, 0x55, 0xfb, 0x90, 0x78, + 0x7e, 0x6c, 0x3e, 0xfe, 0x57, 0x14, 0x61, 0xef, 0xe2, 0x63, 0x57, 0x6c, + 0x13, 0x97, 0x27, 0x2b, 0x38, 0x44, 0xab, 0x74, 0x76, 0x11, 0xa6, 0x60, + 0xad, 0x8e, 0xad, 0xe5, 0xa5, 0xa1, 0x66, 0xc5, 0xe1, 0x4d, 0x27, 0xa0, + 0x79, 0x7a, 0x09, 0xe6, 0xf0, 0x28, 0x3f, 0xcb, 0xc6, 0xf8, 0x94, 0xc0, + 0xf1, 0x13, 0xbe, 0x62, 0x6a, 0x52, 0x75, 0x52, 0xd3, 0x82, 0x31, 0xbd, + 0x15, 0xf2, 0xe8, 0x2e, 0xb1, 0x62, 0x03, 0x1e, 0xe2, 0xb3, 0xec, 0xbc, + 0x3c, 0x12, 0xca, 0x62, 0x4e, 0xc2, 0x3a, 0x51, 0x1c, 0xdf, 0xa2, 0x84, + 0x88, 0xe5, 0x7e, 0xd7, 0x5d, 0xd7, 0xbf, 0xf2, 0x7d, 0xbd, 0x9a, 0x90, + 0x63, 0xfd, 0x8a, 0x84, 0x2b, 0x9d, 0x89, 0x27, 0x63, 0x4c, 0x0a, 0xe3, + 0x70, 0x94, 0x7b, 0xe6, 0xb3, 0xd7, 0xcb, 0xcb, 0x8a, 0xeb, 0x6b, 0x53, + 0x34, 0x2f, 0x62, 0x44, 0x2d, 0x73, 0x63, 0x8a, 0xf4, 0xa2, 0x01, 0xd7, + 0x12, 0xb6, 0x8d, 0x8c, 0x4b, 0x73, 0x2b, 0x44, 0x50, 0x49, 0x6f, 0x01, + 0xac, 0xc5, 0x15, 0x37, 0x6c, 0xde, 0xd4, 0x02, 0xb1, 0x12, 0x80, 0x73, + 0xb2, 0x52, 0x0e, 0xe0, 0xb5, 0x75, 0xc9, 0x48, 0xcf, 0x18, 0x5c, 0xcc, + 0xaf, 0x58, 0xa2, 0x3e, 0x28, 0xe4, 0xab, 0xde, 0xea, 0x2a, 0xcf, 0x58, + 0x22, 0xc4, 0x68, 0xea, 0x9b, 0x7b, 0x90, 0xc5, 0xdc, 0x1c, 0x37, 0xd1, + 0x8a, 0x4f, 0xe7, 0x24, 0x23, 0x39, 0xb9, 0x62, 0xb8, 0x41, 0x13, 0x7b, + 0xe2, 0x1e, 0x0d, 0x4e, 0x38, 0x11, 0xa3, 0xb9, 0x10, 0xbb, 0x10, 0x6f, + 0x40, 0x9f, 0x50, 0x05, 0xc7, 0x0e, 0xb9, 0x9e, 0xab, 0x7c, 0x3c, 0x78, + 0xce, 0x54, 0xbf, 0xbf, 0x40, 0x36, 0x76, 0xbc, 0x4b, 0x64, 0x32, 0xca, + 0x0e, 0x2d, 0x91, 0x87, 0xd5, 0x00, 0x19, 0xbf, 0x12, 0xd0, 0x35, 0x7c, + 0xa1, 0xe5, 0xcf, 0x7a, 0x2d, 0x08, 0x62, 0xed, 0x34, 0x61, 0xe3, 0xda, + 0x2c, 0xcc, 0x1b, 0xf8, 0x12, 0xfe, 0xfd, 0x19, 0xa2, 0xc3, 0x70, 0xfd, + 0x4f, 0x5b, 0x5d, 0x20, 0xd2, 0xe1, 0xc5, 0xac, 0xe7, 0xa1, 0x84, 0x00, + 0xbd, 0x46, 0x81, 0xfd, 0x54, 0x69, 0xed, 0x1a, 0x7a, 0x32, 0xbb, 0x75, + 0x22, 0x76, 0x6d, 0x34, 0x24, 0xcc, 0xe6, 0xbe, 0x78, 0x5a, 0x75, 0x6c, + 0xbc, 0x62, 0xb8, 0x14, 0xf7, 0x13, 0x73, 0xc2, 0xdc, 0xb6, 0xfa, 0xfb, + 0x97, 0xfe, 0x27, 0x7b, 0x33, 0xb8, 0xeb, 0x20, 0xd2, 0x0f, 0x4f, 0xed, + 0xd1, 0xd0, 0x63, 0xf7, 0xc5, 0x8e, 0xec, 0xcc, 0xd2, 0x31, 0x38, 0x35, + 0x65, 0x33, 0x5c, 0x63, 0x85, 0xf7, 0x3d, 0xc3, 0x62, 0x26, 0x52, 0x0a, + 0x67, 0xda, 0x87, 0x1f, 0x9e, 0x47, 0xec, 0x6b, 0xf5, 0x74, 0x1a, 0xc5, + 0xa7, 0xa0, 0x0f, 0xdd, 0xc5, 0x42, 0xf4, 0xda, 0x41, 0x1a, 0x48, 0xa9, + 0xbe, 0x4f, 0xb6, 0x28, 0x17, 0xe9, 0xf5, 0xd7, 0x00, 0xb3, 0xfe, 0x05, + 0x4e, 0xa7, 0xdf, 0x65, 0x7a, 0xb8, 0x4f, 0xe0, 0xfe, 0x58, 0x9e, 0xba, + 0x45, 0x11, 0xba, 0xc2, 0xdb, 0x97, 0x97, 0xa4, 0xbc, 0x18, 0x21, 0x1b, + 0xad, 0x82, 0xef, 0xb1, 0x5f, 0x2f, 0x25, 0x9d, 0xca, 0x52, 0xa5, 0x6d, + 0x8c, 0xab, 0x07, 0x2b, 0x7b, 0x6a, 0x77, 0x9d, 0xdf, 0xfb, 0xae, 0x6e, + 0x49, 0x18, 0x25, 0x4a, 0xf2, 0x7d, 0xa0, 0x32, 0xc8, 0x53, 0x10, 0xc3, + 0xf2, 0xef, 0xf3, 0xe7, 0x79, 0xd7, 0x6a, 0x0e, 0x61, 0xff, 0x89, 0xc9, + 0x42, 0xe8, 0x6e, 0x4f, 0x78, 0xe1, 0x5f, 0xcd, 0x7a, 0xf6, 0x27, 0x72, + 0x67, 0xea, 0x0b, 0xa6, 0xcc, 0x34, 0xb7, 0x8f, 0x92, 0x3c, 0x95, 0xb9, + 0x0a, 0x5d, 0x49, 0x2e, 0xb7, 0x7d, 0x31, 0x9c, 0x79, 0x61, 0x95, 0x9c, + 0x60, 0x56, 0x8d, 0x35, 0x00, 0xc5, 0x8b, 0xe6, 0x02, 0x0f, 0x26, 0x39, + 0x7b, 0x93, 0x94, 0xb1, 0xcd, 0xde, 0xed, 0xfa, 0x2a, 0x4b, 0x63, 0xa8, + 0x1b, 0x31, 0x43, 0x5e, 0x69, 0x7c, 0xd6, 0x15, 0x35, 0x9c, 0xa2, 0xd7, + 0xdf, 0x0e, 0x1a, 0x20, 0x50, 0xf5, 0x02, 0x21, 0x30, 0x35, 0x3c, 0x60, + 0x71, 0xad, 0xd0, 0xe3, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x10, 0x17, 0x1d, 0x22, 0x2d}; +#elif MLD_CONFIG_PARAMETER_SET == 87 +const uint8_t expected_signature[] = { + 0xdf, 0xe6, 0xe1, 0xa5, 0x20, 0xc1, 0xac, 0x98, 0x55, 0x2c, 0xf2, 0x13, + 0x65, 0x42, 0xe2, 0xb0, 0x77, 0x5f, 0x15, 0x00, 0x8f, 0x14, 0x48, 0xa1, + 0xe3, 0xee, 0x81, 0x35, 0x15, 0x34, 0xad, 0x6e, 0x60, 0x85, 0x00, 0xf8, + 0x18, 0x53, 0x0d, 0xa0, 0xc5, 0x41, 0xc4, 0x48, 0x09, 0x1b, 0x34, 0x0c, + 0x0e, 0xcf, 0xc6, 0x3d, 0x38, 0x78, 0x8b, 0x69, 0xe5, 0x6f, 0x4d, 0x43, + 0xfa, 0xa6, 0x75, 0x26, 0x8a, 0x75, 0x97, 0x10, 0x6a, 0x1f, 0x3c, 0xa6, + 0x94, 0xa9, 0x93, 0x8f, 0xe5, 0x62, 0xbf, 0x94, 0xe4, 0xd0, 0x0d, 0x11, + 0x4d, 0x03, 0xe2, 0xd8, 0xdf, 0x68, 0xb7, 0x87, 0x62, 0xc9, 0xdc, 0xc9, + 0x36, 0x4f, 0xcc, 0xd1, 0xa4, 0xae, 0x7e, 0xa4, 0xb9, 0xaf, 0xaf, 0xf0, + 0x8a, 0xe6, 0xff, 0x83, 0xe7, 0x54, 0x22, 0x6e, 0x3f, 0x2e, 0xa0, 0x4f, + 0xa8, 0x31, 0x53, 0xf3, 0x62, 0xeb, 0x04, 0xfa, 0xd1, 0x57, 0x39, 0x43, + 0xf9, 0xe0, 0x31, 0x12, 0x45, 0x09, 0x8b, 0x9e, 0x1e, 0x7a, 0x2b, 0x85, + 0xee, 0xdd, 0xe8, 0x1e, 0xd7, 0xc0, 0x17, 0xb4, 0xd2, 0xdc, 0x36, 0xa9, + 0xe4, 0x49, 0x88, 0xbf, 0x71, 0x43, 0x9d, 0x3e, 0xd2, 0x10, 0xe7, 0x82, + 0xb5, 0xfe, 0xdd, 0x42, 0xc8, 0x1b, 0x11, 0xf6, 0x52, 0x23, 0x98, 0x83, + 0x48, 0xec, 0xec, 0x70, 0x8b, 0xe7, 0x49, 0x9a, 0xd7, 0xd9, 0x7b, 0x47, + 0x4e, 0xe2, 0x5e, 0x17, 0x1a, 0xa0, 0x0e, 0x60, 0x85, 0x3a, 0x30, 0x8c, + 0x1c, 0x26, 0xb4, 0xe1, 0xb5, 0x2b, 0x48, 0xf4, 0xb8, 0x93, 0x2f, 0x79, + 0x3a, 0x1e, 0xb6, 0x3b, 0x07, 0x3b, 0x1e, 0x15, 0xd7, 0x85, 0x5e, 0xd4, + 0x06, 0x0e, 0xcd, 0x6a, 0x93, 0x3a, 0x93, 0x29, 0x6a, 0xbe, 0x68, 0x8a, + 0xb6, 0xb8, 0xfa, 0xc5, 0x63, 0x48, 0x98, 0x10, 0x6d, 0xd9, 0xd3, 0x5b, + 0x29, 0x5f, 0x93, 0x90, 0x08, 0x1c, 0x1a, 0x15, 0x7b, 0x0a, 0x59, 0x9d, + 0x64, 0x24, 0x45, 0xb6, 0xd3, 0x7b, 0xc1, 0x5d, 0x74, 0x1f, 0x0b, 0x8e, + 0x18, 0xf2, 0x92, 0x8e, 0xd4, 0x7f, 0x72, 0x5c, 0x98, 0x1f, 0x8b, 0xa5, + 0xb8, 0xf4, 0x7e, 0x12, 0x6a, 0x93, 0xb9, 0xb5, 0xf1, 0xda, 0x97, 0x75, + 0x4f, 0x56, 0x80, 0x88, 0x64, 0x2b, 0xe0, 0x59, 0xcd, 0x5e, 0x91, 0x64, + 0x9c, 0x0c, 0xa8, 0xdd, 0xac, 0xcb, 0xf3, 0x48, 0x3b, 0x5c, 0xc4, 0xc5, + 0xb9, 0x9a, 0x0b, 0x8e, 0x5d, 0x9a, 0xd5, 0xb7, 0xf0, 0xd4, 0x07, 0x48, + 0xb9, 0x63, 0x02, 0x87, 0x8d, 0xae, 0x7e, 0x03, 0x33, 0x4f, 0x86, 0x15, + 0x1b, 0x3b, 0xdf, 0xda, 0xce, 0xd3, 0x1e, 0xc0, 0x76, 0xb5, 0x1c, 0xdd, + 0xb8, 0x32, 0x87, 0x7d, 0x59, 0x18, 0x72, 0x0c, 0xde, 0x8f, 0x63, 0x2d, + 0x38, 0xf2, 0xe9, 0xc2, 0x81, 0xed, 0xfa, 0x2d, 0x61, 0xef, 0x48, 0xdb, + 0xa2, 0xeb, 0xfe, 0x52, 0x31, 0x1e, 0x21, 0x0a, 0x08, 0xf6, 0x02, 0xd3, + 0xc0, 0x32, 0x3b, 0x6b, 0x2f, 0x64, 0xc4, 0xb3, 0x4b, 0xfe, 0x69, 0x78, + 0xbf, 0x20, 0x62, 0x07, 0x77, 0xdf, 0x2c, 0x18, 0x53, 0x61, 0x8e, 0x05, + 0x01, 0x86, 0xab, 0xab, 0xec, 0x18, 0x8c, 0x15, 0x63, 0x1f, 0xe9, 0x99, + 0xb2, 0x35, 0x77, 0xe1, 0x58, 0xf1, 0xa9, 0x4d, 0x1a, 0xb9, 0x8c, 0x30, + 0x63, 0x6f, 0x9e, 0x7d, 0x4e, 0xcf, 0xb5, 0x6c, 0xf3, 0xe4, 0xdc, 0xab, + 0xf9, 0xae, 0x58, 0xf8, 0x1d, 0x08, 0x7b, 0x73, 0x82, 0x58, 0xc8, 0x67, + 0x48, 0x1a, 0x5e, 0x3d, 0xdb, 0xac, 0x1b, 0x1b, 0xef, 0xeb, 0xa4, 0xe5, + 0x67, 0x48, 0x76, 0xd1, 0x96, 0x4f, 0x6c, 0x7d, 0x06, 0x8c, 0x02, 0x86, + 0x95, 0x83, 0xb6, 0x9b, 0x5e, 0x9a, 0xb5, 0x85, 0xc0, 0x4f, 0x13, 0x1c, + 0x32, 0xf8, 0x29, 0xdf, 0x47, 0x85, 0xdb, 0xe4, 0x37, 0xdc, 0xd8, 0x04, + 0x18, 0xdd, 0xca, 0x97, 0xdd, 0x67, 0x13, 0xbe, 0x74, 0x95, 0xdc, 0xd0, + 0xcc, 0xe6, 0xb5, 0xa5, 0x12, 0x9b, 0x23, 0x4f, 0x41, 0x8c, 0xcc, 0x95, + 0xf4, 0xb0, 0x5f, 0x2a, 0xc4, 0xbf, 0x88, 0xda, 0x55, 0xcb, 0x13, 0x93, + 0x22, 0x60, 0x51, 0x43, 0xc7, 0x9a, 0x2c, 0xfa, 0xb2, 0x59, 0xc1, 0xe6, + 0x8a, 0xa4, 0xb8, 0xfb, 0xd3, 0x31, 0x1d, 0xc7, 0x88, 0xdc, 0xbc, 0xe9, + 0xba, 0xe7, 0xdc, 0xe3, 0xdd, 0x90, 0x96, 0xb4, 0xb4, 0x0a, 0xc1, 0x07, + 0x31, 0x3f, 0xdb, 0xc5, 0x4d, 0x73, 0x58, 0x86, 0x15, 0x37, 0x07, 0x86, + 0x03, 0x17, 0x16, 0x18, 0x15, 0xb9, 0x26, 0x35, 0x8a, 0x43, 0x22, 0xae, + 0x21, 0x52, 0x05, 0x4e, 0x5c, 0x3f, 0x3e, 0xb9, 0x2a, 0x19, 0x13, 0xfd, + 0x31, 0x47, 0x6a, 0x74, 0xaa, 0xb9, 0xc6, 0x2c, 0x13, 0x8c, 0x21, 0xc4, + 0x8d, 0x00, 0xf4, 0x24, 0xf2, 0xb7, 0xd3, 0x13, 0xad, 0x29, 0x5e, 0x50, + 0x0b, 0x0e, 0x9f, 0x9a, 0xb7, 0xf6, 0x9e, 0xba, 0x12, 0x23, 0x84, 0x8c, + 0xbe, 0x2c, 0x14, 0x1e, 0xe6, 0x79, 0x15, 0x20, 0x2d, 0x32, 0x08, 0xd8, + 0x1c, 0x87, 0x1b, 0xa8, 0xc0, 0xbb, 0x85, 0xa9, 0x71, 0x30, 0x5e, 0x39, + 0x48, 0x87, 0xdc, 0x3d, 0x03, 0x29, 0x19, 0xd1, 0xd4, 0x21, 0x3a, 0x53, + 0x2d, 0x5e, 0x78, 0xff, 0x94, 0x4b, 0x91, 0xa6, 0xb5, 0xe5, 0x42, 0x56, + 0x67, 0x6a, 0x0e, 0xf3, 0x2d, 0x6a, 0x4e, 0xd7, 0x3a, 0x81, 0xb1, 0x4d, + 0x0b, 0x66, 0x5f, 0x43, 0x28, 0x7c, 0x75, 0x8b, 0x2b, 0x99, 0x24, 0xc2, + 0x5e, 0x8c, 0x22, 0xf0, 0xd5, 0xb3, 0xfc, 0x86, 0x62, 0xf3, 0xd2, 0x6c, + 0xa7, 0x48, 0x04, 0x44, 0x5d, 0x93, 0x74, 0x37, 0x16, 0x2c, 0x19, 0x12, + 0x57, 0x49, 0xef, 0xd5, 0xd6, 0x92, 0xdc, 0x51, 0xf8, 0x55, 0x3a, 0xc0, + 0x0b, 0xdf, 0x41, 0xb5, 0x01, 0x59, 0x7e, 0x85, 0x65, 0xdb, 0x44, 0xbd, + 0x04, 0x96, 0x1a, 0xd4, 0x6e, 0x22, 0x54, 0x92, 0xdb, 0xc7, 0xc5, 0x3a, + 0xdf, 0x0c, 0xf4, 0x1b, 0xdc, 0x14, 0xf6, 0x91, 0x9c, 0xbe, 0xf8, 0x8e, + 0x70, 0xd1, 0x3a, 0x0e, 0x58, 0xe6, 0xb9, 0xd3, 0xaa, 0xa2, 0x70, 0xba, + 0xdd, 0x16, 0x13, 0x19, 0xd1, 0x96, 0x78, 0x04, 0x2f, 0xd7, 0x38, 0x8c, + 0x35, 0x1f, 0xfc, 0x58, 0xa4, 0x4c, 0xa9, 0x9a, 0xae, 0x13, 0x3b, 0xc1, + 0x20, 0x4b, 0x66, 0x0f, 0x72, 0x42, 0x0a, 0x53, 0x84, 0x54, 0x71, 0x06, + 0xdb, 0x85, 0x8f, 0x40, 0xa6, 0x09, 0xf7, 0x24, 0xc4, 0x35, 0xf7, 0x1d, + 0xd4, 0x3d, 0x54, 0x75, 0xaf, 0xc4, 0x78, 0x0f, 0xce, 0xe0, 0x0c, 0x90, + 0x0f, 0xd5, 0x2e, 0x61, 0xf7, 0x58, 0xaa, 0xf0, 0xc7, 0x37, 0x5a, 0x59, + 0x1f, 0x8a, 0x03, 0x98, 0x43, 0xb7, 0x27, 0x78, 0x4e, 0x44, 0x5a, 0xb5, + 0x29, 0xf5, 0xab, 0x9e, 0xb7, 0x2a, 0xc4, 0xa3, 0x03, 0x00, 0xe3, 0x28, + 0x57, 0xc9, 0x2a, 0x98, 0xb8, 0xa1, 0x45, 0x1d, 0xfa, 0x6e, 0xb3, 0x0d, + 0x42, 0x5a, 0xb6, 0xb1, 0x0e, 0x5c, 0xbe, 0x82, 0xe2, 0x36, 0x40, 0x4b, + 0x05, 0x28, 0xd9, 0xbc, 0x27, 0xd6, 0x77, 0x00, 0xc9, 0x29, 0x6a, 0xd6, + 0x19, 0x8f, 0x8d, 0xda, 0xe1, 0xc3, 0x8b, 0x69, 0x71, 0xd0, 0xf7, 0xc8, + 0x33, 0xef, 0xe6, 0x23, 0x6b, 0xcb, 0x00, 0x56, 0x0a, 0x9b, 0x9d, 0x60, + 0x3a, 0xd3, 0xad, 0xd9, 0x5c, 0x6a, 0x7d, 0xab, 0x35, 0x71, 0x93, 0xc5, + 0xf2, 0x6a, 0x38, 0x0e, 0xfb, 0xd9, 0x9b, 0xa5, 0xda, 0x52, 0x45, 0xef, + 0x93, 0x94, 0x5b, 0x08, 0x8c, 0x07, 0xab, 0x2e, 0x99, 0x88, 0x77, 0xb5, + 0x15, 0x66, 0x7f, 0x0e, 0xfa, 0xb0, 0x29, 0xe4, 0x88, 0xd9, 0xdd, 0x22, + 0xaf, 0x7a, 0x4e, 0xb5, 0xd0, 0x62, 0x85, 0x27, 0x33, 0xf1, 0xb7, 0x34, + 0xb1, 0xe6, 0xda, 0x9f, 0x3c, 0xfe, 0xf5, 0xd4, 0xef, 0x56, 0x48, 0x93, + 0x7a, 0x54, 0xa2, 0x7f, 0x07, 0xea, 0x31, 0xb8, 0x8b, 0xca, 0xb9, 0xdb, + 0x1e, 0x2b, 0xb5, 0x16, 0xe6, 0x0e, 0xd9, 0x3f, 0x7c, 0xf0, 0xc2, 0x3e, + 0x57, 0x64, 0x60, 0x97, 0xfb, 0xdf, 0x8c, 0x3e, 0x56, 0x22, 0x92, 0x2a, + 0xb2, 0x21, 0x00, 0x0a, 0x75, 0x89, 0x68, 0xe7, 0x51, 0xa3, 0x63, 0x05, + 0xe1, 0x6f, 0x1e, 0x1e, 0x80, 0xa2, 0x4b, 0x5d, 0xb7, 0xf4, 0xb7, 0x45, + 0x85, 0x00, 0x84, 0x6e, 0xbe, 0x0b, 0x67, 0xbf, 0x21, 0x06, 0x5a, 0x56, + 0x79, 0xe9, 0x6b, 0x0e, 0x72, 0x19, 0x2d, 0x09, 0x78, 0xd5, 0x5e, 0xc2, + 0x32, 0xee, 0x29, 0xd4, 0x7a, 0x65, 0xc7, 0xfe, 0x16, 0x86, 0xd2, 0x29, + 0x71, 0xe5, 0x91, 0x0e, 0x3e, 0x86, 0xd5, 0x00, 0xc4, 0xfc, 0xd9, 0xae, + 0xd3, 0x7c, 0x13, 0xfd, 0x62, 0xce, 0x0c, 0xb2, 0xe5, 0x1f, 0x6d, 0xed, + 0x55, 0x6f, 0xc1, 0xaa, 0xa1, 0x74, 0x59, 0x46, 0x83, 0xd5, 0x5d, 0x71, + 0x17, 0x13, 0x1d, 0x0b, 0x25, 0xfb, 0x0a, 0xcd, 0x67, 0xfe, 0x57, 0x93, + 0xc2, 0x71, 0x55, 0x6c, 0x68, 0xfa, 0x40, 0xdb, 0xdd, 0xce, 0xd5, 0x5c, + 0xce, 0x0a, 0x1d, 0xfa, 0x19, 0x30, 0xe2, 0x2b, 0x63, 0x98, 0x16, 0x2c, + 0x67, 0x69, 0x55, 0xe5, 0xc1, 0x6c, 0x6e, 0xb7, 0x92, 0x6a, 0xbb, 0x10, + 0xd3, 0x13, 0x2e, 0x73, 0x91, 0x74, 0xcb, 0x9f, 0x5c, 0x7f, 0x5c, 0x48, + 0x58, 0x36, 0x13, 0x47, 0xf7, 0x49, 0xae, 0x90, 0x15, 0x53, 0xb5, 0xe6, + 0x37, 0xfb, 0x81, 0x47, 0xb4, 0x69, 0x84, 0xca, 0x95, 0xab, 0x19, 0x2a, + 0x28, 0xc2, 0x8a, 0xf1, 0xcd, 0xf9, 0x3e, 0xd3, 0xaf, 0xe1, 0x75, 0xf7, + 0x94, 0x74, 0x1c, 0xf5, 0x32, 0xcf, 0x70, 0xbd, 0x69, 0xcc, 0xa8, 0x3c, + 0xca, 0x59, 0x53, 0xfa, 0xcb, 0xe7, 0xb6, 0x36, 0x70, 0xea, 0xe2, 0x84, + 0xfa, 0x5e, 0xbd, 0xd7, 0x59, 0x3d, 0x21, 0xc6, 0x9f, 0x5c, 0x1f, 0xa6, + 0xa9, 0xf1, 0xd3, 0x26, 0x9e, 0xff, 0xbc, 0x81, 0xfe, 0xbe, 0xee, 0x64, + 0xd9, 0x63, 0x94, 0x4b, 0x15, 0xd8, 0x95, 0xaa, 0xec, 0x10, 0xc9, 0xe2, + 0xe1, 0x05, 0x37, 0x64, 0xc4, 0xb0, 0x2e, 0xa5, 0x0e, 0x4c, 0x2d, 0x03, + 0x53, 0xf1, 0x93, 0x77, 0x9d, 0x46, 0x14, 0x67, 0x48, 0x5f, 0xad, 0x1b, + 0xdc, 0xb9, 0x74, 0xa2, 0x6c, 0xfc, 0xd2, 0xa0, 0x1f, 0x43, 0x89, 0x15, + 0xc5, 0x0c, 0xb0, 0x9e, 0x1e, 0xc2, 0xd6, 0x44, 0xd9, 0x6e, 0xfc, 0xb4, + 0x9c, 0x95, 0x90, 0xcd, 0xc3, 0x17, 0x1c, 0x6a, 0xce, 0x03, 0x56, 0x9f, + 0xe7, 0xcd, 0x7e, 0xe7, 0xa2, 0x0c, 0x2b, 0x0d, 0x59, 0xb0, 0xc9, 0x4c, + 0x6e, 0x33, 0x6d, 0x43, 0xc4, 0x3a, 0x10, 0x24, 0x03, 0x3e, 0x09, 0xb6, + 0x86, 0x13, 0xba, 0x18, 0x19, 0xd3, 0xff, 0xeb, 0xa5, 0x25, 0x8f, 0x6f, + 0xc8, 0xe6, 0x96, 0xa4, 0xd2, 0x66, 0x40, 0x81, 0x79, 0xe8, 0x39, 0x18, + 0x41, 0x02, 0x66, 0x5c, 0x30, 0x5f, 0x58, 0x9d, 0x35, 0x16, 0xc6, 0x96, + 0xa8, 0x68, 0xbc, 0x09, 0x83, 0x17, 0x2c, 0x5f, 0x5e, 0xd0, 0x1d, 0xb0, + 0x48, 0x5e, 0xcf, 0x91, 0x16, 0x4d, 0xa0, 0xba, 0xbc, 0x61, 0xa8, 0x3f, + 0x30, 0x09, 0xbb, 0xa3, 0x12, 0xcd, 0xdc, 0x29, 0xf7, 0xb0, 0xad, 0x05, + 0x17, 0xd6, 0xd3, 0x16, 0xfb, 0xe5, 0x99, 0xf4, 0x71, 0x62, 0xa3, 0x45, + 0x45, 0xc7, 0x9b, 0xaa, 0x45, 0xd3, 0x35, 0xfe, 0xfb, 0x63, 0xaf, 0xe7, + 0x85, 0x31, 0xc9, 0x66, 0x26, 0xa9, 0xda, 0x8c, 0xc6, 0xf6, 0xd5, 0xdf, + 0xb1, 0xa9, 0xf1, 0xb6, 0x3d, 0x92, 0xae, 0x4d, 0xbc, 0x74, 0x7d, 0x76, + 0x5a, 0x59, 0x8c, 0x87, 0xff, 0x95, 0x2f, 0x67, 0x37, 0x30, 0x1a, 0xc1, + 0x23, 0x2e, 0x0c, 0xaa, 0x80, 0x1c, 0xf3, 0xa3, 0x74, 0x94, 0xb2, 0xda, + 0x1a, 0xb8, 0x46, 0xec, 0x30, 0x76, 0xf4, 0xdf, 0xfb, 0x00, 0xb3, 0x6f, + 0x86, 0xc1, 0xc5, 0x3a, 0x5d, 0x11, 0x14, 0x87, 0xeb, 0x30, 0xd8, 0x33, + 0x18, 0x00, 0x01, 0x76, 0x43, 0x82, 0xcd, 0x1c, 0x36, 0x54, 0xd2, 0x64, + 0x5b, 0xfb, 0x93, 0xca, 0x20, 0x1d, 0xa3, 0x20, 0x99, 0xc3, 0x8e, 0x5c, + 0x82, 0xfc, 0x56, 0x07, 0x41, 0x4b, 0x4f, 0x54, 0xc7, 0xb5, 0xe8, 0x6d, + 0x7e, 0xd8, 0x8a, 0x56, 0xb4, 0x76, 0x1e, 0xd3, 0x82, 0x97, 0xdd, 0x2b, + 0xd9, 0x80, 0xb7, 0xb6, 0xeb, 0x3d, 0xe5, 0xe0, 0x20, 0x27, 0x8c, 0xf0, + 0xd6, 0x14, 0xc7, 0xcd, 0x79, 0xbc, 0xa0, 0x21, 0x85, 0xc3, 0x02, 0xae, + 0x73, 0xc4, 0x0a, 0x39, 0x1a, 0x98, 0x61, 0xc3, 0x86, 0xd8, 0x97, 0x67, + 0x87, 0xe9, 0x56, 0x0b, 0x61, 0xa6, 0x7e, 0x07, 0xfb, 0x0a, 0x8b, 0xd1, + 0x90, 0xbd, 0x39, 0x22, 0xdb, 0xc2, 0x7f, 0xaa, 0x79, 0xb7, 0x39, 0x09, + 0xc1, 0x69, 0xdb, 0xe2, 0x7f, 0xec, 0xde, 0x80, 0x7a, 0x6c, 0xde, 0x76, + 0xa4, 0xe8, 0xe0, 0x8d, 0x71, 0xfa, 0x62, 0xf0, 0x2e, 0x7b, 0xf4, 0xce, + 0x65, 0x18, 0x42, 0xde, 0x92, 0x1b, 0xdc, 0xc9, 0xa7, 0x8d, 0xa5, 0x91, + 0x0f, 0xa5, 0x1b, 0x89, 0xcf, 0x29, 0x10, 0x1d, 0x94, 0x78, 0x1b, 0xea, + 0x79, 0x35, 0x62, 0xd4, 0x29, 0xe6, 0x59, 0x8c, 0xc1, 0xd2, 0xf3, 0x32, + 0x71, 0x09, 0xce, 0x51, 0xd7, 0x14, 0x29, 0x92, 0xbf, 0xdf, 0x9a, 0x69, + 0xda, 0x61, 0x03, 0x0f, 0xa2, 0x0a, 0xab, 0x57, 0x1c, 0xca, 0xab, 0x42, + 0x63, 0x63, 0x1e, 0x35, 0x5d, 0x8d, 0xba, 0x6f, 0x4b, 0x6b, 0x5e, 0x7c, + 0xc0, 0x1e, 0xb7, 0xf4, 0x65, 0xbd, 0x13, 0x1c, 0xf2, 0xa9, 0x73, 0x38, + 0xc3, 0x47, 0xc9, 0x32, 0xf0, 0x30, 0x57, 0x05, 0x42, 0x52, 0xac, 0x72, + 0xee, 0x9f, 0x4e, 0x21, 0xbf, 0x38, 0x19, 0x6d, 0x48, 0xec, 0x97, 0xcb, + 0x70, 0x9e, 0xee, 0xb3, 0xa1, 0xaa, 0xa6, 0x7e, 0xe9, 0x16, 0xdf, 0xcd, + 0x1c, 0x56, 0xcf, 0xf0, 0x9f, 0x4d, 0xd1, 0x8c, 0x14, 0x50, 0x5d, 0x23, + 0x96, 0xe0, 0x1f, 0x61, 0x79, 0xbf, 0x44, 0xfd, 0xa2, 0x31, 0xf7, 0x4c, + 0x0c, 0x8d, 0x8c, 0x1b, 0xbf, 0x8d, 0x45, 0xbf, 0x0b, 0xd8, 0xfb, 0x6f, + 0xff, 0x15, 0xc0, 0x44, 0x7c, 0xb9, 0xb8, 0xf9, 0xef, 0x0d, 0x79, 0x11, + 0x3b, 0x79, 0xd2, 0x52, 0x89, 0x5a, 0xcd, 0x0f, 0x10, 0x92, 0x42, 0xfe, + 0xcf, 0x0a, 0x11, 0x8a, 0x8a, 0xda, 0xee, 0xc8, 0x6b, 0xd9, 0xab, 0xec, + 0xb4, 0x25, 0x6f, 0x8d, 0x68, 0x26, 0xe8, 0xdd, 0xf5, 0xa4, 0xe8, 0x65, + 0x37, 0x03, 0xb0, 0xad, 0x73, 0x3b, 0x4d, 0x74, 0x57, 0x7f, 0x0f, 0x6c, + 0xb0, 0x5d, 0x59, 0x80, 0x13, 0xa1, 0x6c, 0xb0, 0xed, 0x26, 0xec, 0x79, + 0x50, 0x5f, 0x5c, 0xb7, 0xa6, 0xae, 0xe8, 0x0a, 0x6d, 0x55, 0x9a, 0x7f, + 0x59, 0x23, 0xa3, 0x7e, 0x84, 0x7b, 0x3b, 0xfc, 0xde, 0xe1, 0xd9, 0x7c, + 0xd6, 0x87, 0xb3, 0x0e, 0xdb, 0xc1, 0x8c, 0x5e, 0x77, 0xb7, 0x23, 0xd7, + 0x14, 0xd4, 0x23, 0xb4, 0xac, 0x45, 0xbf, 0xfe, 0x40, 0x20, 0x4d, 0x91, + 0x20, 0x94, 0xbd, 0x58, 0xb1, 0x99, 0x69, 0xaf, 0x31, 0x68, 0xbd, 0x61, + 0x5e, 0x87, 0x81, 0x54, 0x4e, 0x2d, 0x03, 0xc2, 0xe2, 0xcd, 0xdc, 0x59, + 0xe5, 0x35, 0xcf, 0xb8, 0xfc, 0x65, 0xed, 0x46, 0xb3, 0x92, 0xe7, 0xf8, + 0x3a, 0x32, 0xaa, 0x0e, 0x5a, 0x82, 0x58, 0x4e, 0x77, 0xd8, 0x33, 0xc9, + 0xb0, 0x3e, 0xad, 0xa5, 0x92, 0xe9, 0xa9, 0x8c, 0x00, 0x72, 0x8f, 0xdc, + 0x77, 0x9d, 0x5c, 0x97, 0xd6, 0x58, 0x20, 0x1e, 0xf4, 0x55, 0x2d, 0xc0, + 0x30, 0xf0, 0x66, 0xda, 0x2d, 0x11, 0xac, 0xd4, 0x2d, 0xd5, 0x25, 0x42, + 0x1d, 0xce, 0x49, 0xb5, 0x95, 0x79, 0x9b, 0x6c, 0x65, 0xe0, 0x8a, 0xc5, + 0x9f, 0x75, 0xe3, 0xe6, 0xf8, 0xa6, 0x88, 0xd6, 0x93, 0x70, 0x4f, 0x89, + 0x94, 0x74, 0xbd, 0xef, 0xc2, 0x1a, 0x55, 0x74, 0x37, 0x44, 0x85, 0x1e, + 0xa9, 0xbb, 0x3f, 0x15, 0xc7, 0x84, 0x80, 0xa5, 0xab, 0xc3, 0x91, 0x8e, + 0xd6, 0x32, 0x46, 0x0d, 0xfa, 0xd1, 0x19, 0xd1, 0xfc, 0x02, 0xe2, 0x20, + 0xa6, 0xa9, 0xf7, 0xf4, 0xcc, 0x5b, 0x54, 0x4f, 0x4a, 0x73, 0x35, 0xda, + 0xf0, 0x31, 0x81, 0x1a, 0x82, 0xe7, 0xd4, 0xc8, 0xb4, 0x1d, 0x70, 0xa9, + 0x5d, 0x67, 0xb9, 0x7d, 0x4b, 0xcd, 0xa4, 0x81, 0xf9, 0xb2, 0x38, 0x07, + 0x16, 0xd5, 0x28, 0x82, 0xb9, 0x76, 0x5b, 0xa1, 0x09, 0x7a, 0xe7, 0x2a, + 0xcf, 0xc0, 0x3d, 0x2a, 0x42, 0x9a, 0xf3, 0xc8, 0x64, 0x15, 0x7c, 0x94, + 0xd0, 0x97, 0xee, 0x34, 0xb6, 0xf0, 0xb2, 0xba, 0x7e, 0xb2, 0xbb, 0x4e, + 0xbf, 0x88, 0xd0, 0x6b, 0xc5, 0x9c, 0xb9, 0xf2, 0x7d, 0xbf, 0x5d, 0x87, + 0xbc, 0x36, 0x4a, 0xd1, 0x1b, 0x6f, 0x40, 0x09, 0xba, 0x26, 0x51, 0xd6, + 0xc0, 0xaf, 0x27, 0xce, 0x27, 0x8d, 0x93, 0xa8, 0x6c, 0x91, 0xe7, 0x91, + 0x42, 0xc0, 0x68, 0x36, 0x5b, 0xd5, 0x56, 0x4c, 0xe2, 0x77, 0xc3, 0xac, + 0x56, 0xe3, 0x1c, 0xc2, 0xf9, 0x78, 0x02, 0x39, 0x7d, 0xed, 0x18, 0x2a, + 0x01, 0x48, 0xe6, 0xf6, 0x7e, 0x34, 0x50, 0xf4, 0x57, 0x56, 0x93, 0xdb, + 0x85, 0x1b, 0x1e, 0x1a, 0x6f, 0x3e, 0x07, 0x3c, 0xad, 0x3f, 0x8d, 0x75, + 0x53, 0xc3, 0x20, 0x72, 0x93, 0x28, 0xd2, 0x86, 0xc8, 0xa5, 0x90, 0xf2, + 0x5f, 0x13, 0xd5, 0xa5, 0xbe, 0x88, 0x9e, 0x9a, 0x57, 0x2c, 0x53, 0x3f, + 0x11, 0x25, 0x00, 0x00, 0x4a, 0x16, 0x8d, 0xd3, 0x3f, 0x2d, 0x3d, 0x88, + 0xbb, 0x4c, 0x4f, 0x9a, 0xb9, 0x97, 0x5f, 0xed, 0x71, 0xa9, 0x68, 0xd9, + 0x4a, 0x14, 0x24, 0xc7, 0xbe, 0xff, 0x85, 0x57, 0xa3, 0x21, 0xe3, 0x21, + 0x79, 0x1f, 0xd0, 0xbb, 0xb7, 0x73, 0xde, 0x60, 0x02, 0x4b, 0x8f, 0x7d, + 0xb3, 0xb3, 0x8a, 0xda, 0x4c, 0xf4, 0xb8, 0xf1, 0x31, 0xff, 0x32, 0x7b, + 0xd8, 0xfa, 0xb1, 0xcb, 0xb4, 0x58, 0xf5, 0xc8, 0x64, 0xdf, 0xfe, 0x3d, + 0x89, 0x52, 0x5c, 0x52, 0x95, 0xf3, 0xba, 0x0d, 0x1d, 0x2c, 0xc4, 0xf7, + 0x3c, 0x3b, 0x6f, 0x8e, 0xc7, 0xab, 0xad, 0x3d, 0x3d, 0x95, 0x9b, 0xc7, + 0x71, 0x36, 0xae, 0x08, 0xc3, 0x08, 0x79, 0xfa, 0x24, 0xee, 0xd9, 0xf9, + 0x63, 0xc7, 0xd9, 0x16, 0x19, 0x8e, 0x0d, 0xaf, 0x52, 0x87, 0x86, 0x7d, + 0xec, 0xe5, 0xea, 0x5a, 0xda, 0x86, 0x9d, 0x0e, 0x50, 0x53, 0x8c, 0x24, + 0xa8, 0x69, 0xc4, 0xf3, 0x85, 0x7b, 0x34, 0x67, 0x19, 0x35, 0xec, 0xd4, + 0xd4, 0x50, 0xe0, 0xe6, 0xe9, 0x29, 0x5b, 0x92, 0xee, 0xba, 0xa9, 0xef, + 0xf6, 0x35, 0x23, 0x8b, 0xdb, 0x48, 0x32, 0x25, 0x41, 0xf3, 0x55, 0x12, + 0x33, 0xc3, 0x6c, 0xed, 0x32, 0xe1, 0x64, 0x7a, 0x8d, 0xa2, 0x19, 0x5a, + 0x26, 0xf2, 0x83, 0xf1, 0xe4, 0x27, 0xdb, 0x67, 0xc3, 0x89, 0x37, 0xea, + 0x78, 0x19, 0xc6, 0xa3, 0x82, 0x84, 0x1c, 0xf3, 0x2b, 0xbe, 0xde, 0xba, + 0xe7, 0x60, 0x2e, 0xf5, 0x4e, 0xb6, 0x73, 0x29, 0xac, 0xc7, 0x55, 0xab, + 0x21, 0xe9, 0x95, 0x78, 0xd5, 0x8e, 0x27, 0xdc, 0x92, 0x5f, 0xc0, 0xcb, + 0xee, 0x66, 0x09, 0x0a, 0xfc, 0x94, 0x43, 0x44, 0x50, 0x35, 0x57, 0xf8, + 0x08, 0xf9, 0x97, 0xa2, 0x0e, 0xde, 0x81, 0xe1, 0xd1, 0xa0, 0x41, 0xfe, + 0xe6, 0x08, 0x6c, 0x98, 0x8c, 0x81, 0x46, 0x0e, 0xf9, 0x9a, 0x54, 0xfe, + 0xc3, 0x91, 0xe3, 0xd4, 0x46, 0xca, 0x52, 0xa2, 0x73, 0x9e, 0x4d, 0xa7, + 0xfd, 0xa1, 0x8e, 0x43, 0x28, 0xf5, 0xa3, 0xa2, 0x62, 0x20, 0x53, 0x62, + 0x05, 0x49, 0xba, 0x06, 0xe2, 0xeb, 0xba, 0xfb, 0x8e, 0xa0, 0x22, 0xc7, + 0xf9, 0xcc, 0x7f, 0x8b, 0xa8, 0x5d, 0x55, 0xd2, 0x24, 0xff, 0xdd, 0x2c, + 0xc1, 0xd0, 0x3d, 0xe4, 0x79, 0xea, 0xba, 0x62, 0xe5, 0xa2, 0x62, 0xf4, + 0x1f, 0xec, 0xb0, 0x07, 0xf2, 0x0d, 0x32, 0x84, 0x86, 0x81, 0x3d, 0x95, + 0xc1, 0x64, 0xfe, 0x9a, 0x3d, 0x8f, 0x4b, 0x6d, 0xfb, 0x0d, 0x42, 0xcf, + 0xbf, 0xdb, 0x51, 0xb2, 0x16, 0xa2, 0x35, 0xaa, 0xe7, 0x31, 0x54, 0xc2, + 0x87, 0xc6, 0xa5, 0x30, 0x71, 0x64, 0x65, 0xff, 0x41, 0x20, 0xb0, 0x83, + 0xdb, 0xb7, 0x95, 0xce, 0xd7, 0xcc, 0x7a, 0x77, 0xad, 0xb8, 0xb7, 0x4c, + 0xfc, 0x11, 0x05, 0x2b, 0xc4, 0xd4, 0xb6, 0x8b, 0xae, 0x13, 0xa5, 0x40, + 0x18, 0x6e, 0x0d, 0xe3, 0xc6, 0xb0, 0x81, 0x46, 0x46, 0x7e, 0x52, 0x0b, + 0x85, 0x4d, 0x98, 0xd9, 0x42, 0xdf, 0xde, 0x45, 0xc1, 0x5a, 0x33, 0x12, + 0x46, 0x26, 0xb3, 0x6f, 0xf2, 0x8b, 0x37, 0x6b, 0xfd, 0x08, 0xf4, 0x46, + 0x86, 0x89, 0x63, 0x63, 0x21, 0xe5, 0xa9, 0xb7, 0xd0, 0x09, 0x17, 0x52, + 0xee, 0xea, 0xdf, 0x97, 0xb7, 0x73, 0x2e, 0x54, 0x2c, 0x7b, 0x70, 0xd3, + 0xda, 0x26, 0x57, 0x1f, 0xb0, 0x19, 0xd9, 0x91, 0x18, 0x69, 0x75, 0x42, + 0x63, 0xcf, 0x6c, 0x8c, 0x98, 0x5e, 0x17, 0x99, 0x7e, 0x1d, 0xdc, 0x67, + 0x6d, 0x99, 0xd9, 0x02, 0x6e, 0x73, 0x90, 0x5a, 0x4f, 0x0a, 0xb4, 0x48, + 0xfb, 0xc5, 0xbd, 0xd2, 0x10, 0x05, 0xa6, 0x12, 0x68, 0x36, 0x28, 0x51, + 0x60, 0x1c, 0xa1, 0xe9, 0x90, 0x54, 0xa5, 0x53, 0xc3, 0x48, 0x9e, 0xd8, + 0x42, 0x52, 0x85, 0x0e, 0xff, 0xfe, 0xbf, 0xad, 0x3a, 0xa4, 0x57, 0x09, + 0x13, 0x38, 0x64, 0x15, 0x7c, 0xfd, 0xed, 0x91, 0x76, 0x44, 0x20, 0x84, + 0xd9, 0x90, 0xab, 0xfe, 0xfd, 0xd6, 0xab, 0xf1, 0xb3, 0x25, 0x21, 0x3d, + 0x97, 0x72, 0xb2, 0x95, 0xc5, 0x22, 0x80, 0xd9, 0x4a, 0x49, 0x9d, 0x99, + 0xc2, 0x4a, 0x9a, 0x59, 0xb3, 0x71, 0x75, 0x5b, 0xf9, 0x89, 0x7a, 0xdd, + 0xa9, 0xb3, 0xc3, 0xeb, 0x42, 0x91, 0xe2, 0x97, 0x30, 0x40, 0x48, 0x68, + 0x19, 0x3b, 0xf5, 0x7b, 0x4e, 0x33, 0x4b, 0x0c, 0xf3, 0xed, 0xda, 0x76, + 0x3f, 0xb0, 0x4b, 0x53, 0x85, 0x04, 0x33, 0x07, 0x53, 0xd8, 0x55, 0xa2, + 0xfb, 0x30, 0x2c, 0x66, 0xbd, 0x21, 0xf8, 0xfa, 0x20, 0x14, 0x9a, 0x0d, + 0x7f, 0xc9, 0x2f, 0x5b, 0x34, 0x29, 0x09, 0x16, 0xb5, 0x0a, 0x8d, 0xdf, + 0xa2, 0x84, 0x9a, 0xae, 0xe6, 0xa0, 0x50, 0x80, 0x31, 0x04, 0xd3, 0x0c, + 0x8f, 0xd1, 0x8a, 0xfd, 0xb4, 0xa5, 0xae, 0xf5, 0x3c, 0x62, 0xae, 0x45, + 0x70, 0xbb, 0x54, 0x62, 0xc8, 0x50, 0x71, 0x42, 0x85, 0xf6, 0x6f, 0xa0, + 0xf0, 0x10, 0x8a, 0x09, 0xbd, 0x71, 0x78, 0xa6, 0x5e, 0xe4, 0x03, 0x8f, + 0x3b, 0xd0, 0x5c, 0x37, 0x55, 0x1a, 0xc8, 0x57, 0x26, 0x62, 0x6c, 0xc4, + 0x67, 0x71, 0x9d, 0x97, 0xc0, 0xea, 0x35, 0x3e, 0x12, 0xd0, 0x2b, 0xc2, + 0x8f, 0x9e, 0xa6, 0x41, 0x48, 0x33, 0x83, 0x38, 0x37, 0x7e, 0xd4, 0xe3, + 0xee, 0x94, 0x8b, 0x81, 0xa4, 0x60, 0xdd, 0xdd, 0xc1, 0x8a, 0x7b, 0xda, + 0xa8, 0x46, 0xb8, 0x42, 0x3a, 0x25, 0xd6, 0x81, 0x89, 0x29, 0x21, 0xc2, + 0x0c, 0x5b, 0xfd, 0x3e, 0x8c, 0x65, 0x91, 0x52, 0xb3, 0x74, 0x1f, 0xd1, + 0x49, 0x7e, 0x1d, 0x59, 0x58, 0x96, 0xb5, 0xee, 0x32, 0xa4, 0xa8, 0x07, + 0x7c, 0xd1, 0x5b, 0x4b, 0xf8, 0x43, 0x5a, 0xa5, 0xcc, 0x60, 0xcc, 0x08, + 0x6a, 0x3c, 0x41, 0x66, 0x99, 0xe3, 0xa8, 0xe0, 0xb8, 0x87, 0xfc, 0x92, + 0xc0, 0x79, 0xc5, 0x3f, 0xd6, 0xc6, 0x8c, 0x01, 0xf4, 0xa5, 0x05, 0xad, + 0x51, 0xed, 0x04, 0xd7, 0x55, 0xc0, 0x73, 0x05, 0x0e, 0x73, 0xe5, 0x39, + 0x45, 0x5b, 0x95, 0x4a, 0x34, 0x07, 0x99, 0xdf, 0x4c, 0x35, 0xf5, 0x0c, + 0x27, 0x6d, 0xd1, 0x45, 0xf1, 0xfd, 0x24, 0xb7, 0xfe, 0xea, 0x11, 0x5d, + 0xa2, 0xc5, 0xa6, 0x81, 0x37, 0x1d, 0xc2, 0x31, 0x31, 0xfc, 0xe0, 0xf4, + 0xd7, 0xe9, 0x98, 0x8b, 0xe3, 0x70, 0x51, 0x62, 0xc8, 0x61, 0x6d, 0xec, + 0x75, 0x56, 0x71, 0xae, 0x88, 0xe0, 0x80, 0xf5, 0xb7, 0x85, 0x10, 0xb7, + 0x3d, 0x16, 0x78, 0x5f, 0x72, 0xab, 0x8f, 0x63, 0xc6, 0xd5, 0xa8, 0xc9, + 0x9c, 0xef, 0x8d, 0x9a, 0xc5, 0x4f, 0x63, 0xad, 0xc0, 0xf3, 0x1f, 0x69, + 0x0e, 0xce, 0x29, 0x92, 0xc1, 0x3b, 0xb0, 0xc5, 0xed, 0x0a, 0x7b, 0x92, + 0xd0, 0x4c, 0x9c, 0x82, 0xb0, 0x51, 0xf6, 0x33, 0x61, 0x3b, 0x76, 0x48, + 0x38, 0xf4, 0x7c, 0xaa, 0x52, 0x87, 0x15, 0x1a, 0xbe, 0xb8, 0xdc, 0x9b, + 0x16, 0xd2, 0x07, 0xf7, 0xf9, 0x74, 0xe0, 0xaf, 0x0e, 0x29, 0x05, 0xec, + 0x6c, 0x0e, 0x3b, 0xa7, 0xe7, 0xa4, 0xfc, 0xa4, 0xef, 0x57, 0x16, 0x7f, + 0x13, 0xbd, 0x8c, 0x42, 0x02, 0x55, 0x70, 0x56, 0xa5, 0xa9, 0x01, 0x29, + 0x12, 0x7d, 0x80, 0x46, 0x18, 0x8e, 0x39, 0x3f, 0x44, 0x55, 0xec, 0xef, + 0x60, 0x58, 0x7d, 0xce, 0x64, 0x8e, 0x9c, 0xea, 0xe4, 0x73, 0xd1, 0x48, + 0x9c, 0x3f, 0x92, 0xa0, 0x9a, 0x76, 0xa5, 0x5a, 0x13, 0x1f, 0x10, 0xb9, + 0xb7, 0xb1, 0xde, 0x49, 0x22, 0x58, 0xf4, 0x43, 0x5f, 0x03, 0x43, 0xc3, + 0x6c, 0xbf, 0x82, 0xaf, 0x88, 0x39, 0xfd, 0xb2, 0x28, 0x9b, 0x47, 0x3f, + 0x83, 0x3d, 0xd9, 0x7c, 0xf0, 0xc9, 0xc5, 0xa2, 0xb4, 0xd6, 0x0d, 0x59, + 0x51, 0x27, 0x60, 0x10, 0x5e, 0xbb, 0x18, 0xa6, 0x42, 0x4a, 0x9d, 0xc4, + 0x16, 0x0e, 0xb6, 0x57, 0x23, 0x03, 0x24, 0x27, 0xdc, 0x20, 0x56, 0x30, + 0x8b, 0x0f, 0xb6, 0xb7, 0x73, 0xf5, 0x36, 0x3e, 0xf6, 0x7a, 0x71, 0xa5, + 0x57, 0xcc, 0x6d, 0xc6, 0xf3, 0xdc, 0x35, 0xfb, 0x95, 0xf7, 0xa7, 0xd7, + 0x56, 0x38, 0xd4, 0x15, 0xe2, 0xd5, 0x6f, 0x70, 0x30, 0xc8, 0x7d, 0x8a, + 0x87, 0xe6, 0xd1, 0xe0, 0x50, 0x62, 0xde, 0xfa, 0x29, 0x40, 0x97, 0xa0, + 0x54, 0x63, 0x31, 0xd3, 0x08, 0x87, 0x0a, 0xdc, 0x6e, 0x5e, 0xab, 0x8d, + 0x16, 0xaf, 0x6e, 0x8b, 0x1a, 0x77, 0xf6, 0xd4, 0xe0, 0xbf, 0x59, 0xab, + 0xc7, 0xb0, 0x45, 0x18, 0xaa, 0xe6, 0x65, 0x6f, 0x7d, 0x13, 0xb2, 0xbf, + 0xb3, 0x66, 0x72, 0xfa, 0xfd, 0xee, 0xad, 0x07, 0x56, 0x51, 0x6a, 0xe2, + 0xff, 0xb2, 0xaf, 0x4d, 0xd1, 0xf2, 0x77, 0x35, 0x5e, 0x90, 0xcd, 0xe7, + 0xa8, 0x32, 0x4d, 0x9f, 0xbd, 0xa8, 0xce, 0xab, 0xf1, 0x49, 0x98, 0xb5, + 0x23, 0x5c, 0x62, 0x2d, 0x43, 0x31, 0x80, 0x87, 0xc2, 0xa8, 0xf5, 0xb9, + 0xb6, 0xae, 0x7f, 0x37, 0x13, 0xb8, 0x6b, 0x73, 0xf3, 0x56, 0x38, 0xa7, + 0x9b, 0x97, 0x69, 0x37, 0x00, 0xdc, 0xff, 0xfe, 0x58, 0xc9, 0x12, 0x47, + 0x75, 0x98, 0x1f, 0xad, 0xd8, 0xb5, 0xc8, 0x47, 0x4f, 0xd0, 0x72, 0x63, + 0x54, 0x25, 0x6c, 0x88, 0xc9, 0x9f, 0x3c, 0x82, 0xe0, 0xdd, 0x4c, 0xff, + 0x8e, 0xaf, 0x8f, 0x8e, 0xea, 0x84, 0x3f, 0x73, 0xdd, 0x9e, 0x18, 0x73, + 0x47, 0x70, 0xc7, 0xc7, 0x99, 0x65, 0xcf, 0xf3, 0xb6, 0x24, 0xed, 0x97, + 0x8f, 0xcd, 0x93, 0x1e, 0xff, 0x6e, 0x9c, 0xf1, 0x30, 0x14, 0x1a, 0x27, + 0x59, 0x6a, 0x0e, 0xf3, 0xe4, 0xfa, 0x1d, 0x65, 0xb5, 0x53, 0xe4, 0xab, + 0xb1, 0x3e, 0xe1, 0x91, 0xf4, 0x6d, 0x99, 0xca, 0x7d, 0x03, 0x08, 0x50, + 0xea, 0xa9, 0x39, 0x7f, 0x6d, 0xe7, 0x43, 0xfb, 0x64, 0xcc, 0x4b, 0x9e, + 0xa0, 0x26, 0xe4, 0x0e, 0xff, 0xb7, 0x11, 0x0a, 0x29, 0x50, 0x90, 0xd7, + 0x4d, 0x62, 0x9a, 0x4a, 0x23, 0xb7, 0xd3, 0x53, 0xde, 0x3a, 0xd1, 0xba, + 0xd3, 0x10, 0x59, 0xc6, 0xc5, 0x5e, 0xac, 0xf9, 0x61, 0x74, 0x54, 0xf4, + 0x27, 0x9f, 0x9a, 0x61, 0x13, 0xdc, 0xe5, 0x96, 0xe3, 0x95, 0x0d, 0xcc, + 0xbd, 0x81, 0x74, 0x79, 0x73, 0xef, 0x2e, 0x0b, 0x0f, 0x91, 0x65, 0x3c, + 0x26, 0x7c, 0x47, 0x10, 0x31, 0x0b, 0xfb, 0x41, 0x0c, 0xc2, 0xa8, 0xc4, + 0x0e, 0xbd, 0x0a, 0x8c, 0xa4, 0x80, 0x45, 0x57, 0x62, 0x0b, 0x4d, 0x44, + 0x5e, 0x59, 0x77, 0xfd, 0x3d, 0xf3, 0xd7, 0x92, 0x49, 0xc1, 0xcb, 0x8a, + 0x54, 0x56, 0x3b, 0xde, 0xcf, 0x16, 0x9a, 0x65, 0xbe, 0xac, 0x64, 0xe1, + 0xd4, 0xd4, 0x1e, 0xac, 0x6b, 0x4a, 0xad, 0xc4, 0x33, 0xac, 0xcb, 0x83, + 0xf4, 0x4d, 0xe8, 0xb6, 0xd7, 0x23, 0xd7, 0x71, 0x25, 0xa2, 0x25, 0x3d, + 0x7e, 0xf0, 0x3b, 0x7f, 0x61, 0x11, 0x56, 0xd4, 0x83, 0xc8, 0xc0, 0x29, + 0x38, 0x10, 0x73, 0xad, 0x6a, 0xb7, 0xb9, 0xd2, 0x2e, 0x9f, 0xae, 0x16, + 0x5e, 0xa6, 0x13, 0x1c, 0xc2, 0x17, 0x73, 0x43, 0x03, 0xdd, 0xa6, 0xaf, + 0x9a, 0x17, 0x31, 0xb8, 0x86, 0x97, 0xc2, 0xd6, 0xe6, 0xed, 0xd4, 0xe1, + 0x7d, 0xb9, 0xa6, 0x96, 0xc1, 0x4b, 0xcb, 0x11, 0x1e, 0xe1, 0xe0, 0xd2, + 0x28, 0x69, 0x68, 0x3b, 0x21, 0x17, 0x63, 0x0c, 0xc0, 0x49, 0x30, 0x22, + 0x3a, 0x59, 0x72, 0xe6, 0x47, 0xb4, 0xdc, 0xa8, 0x29, 0x1c, 0x89, 0xa6, + 0x3a, 0x77, 0x99, 0xea, 0x46, 0xce, 0x38, 0xda, 0x31, 0x88, 0xad, 0xe7, + 0x26, 0xce, 0xc6, 0x56, 0x04, 0x30, 0xfa, 0x01, 0xac, 0xbb, 0xe2, 0xb8, + 0x23, 0xe4, 0x9d, 0x4f, 0x77, 0x02, 0x00, 0x28, 0xf1, 0xe0, 0x19, 0x3f, + 0x22, 0x4f, 0x22, 0x69, 0x87, 0xc0, 0x4e, 0x26, 0x33, 0xfe, 0x6c, 0x70, + 0x56, 0x3b, 0x60, 0x5f, 0xfb, 0xf8, 0x43, 0xcf, 0x3f, 0xb9, 0xcb, 0x80, + 0x22, 0xbb, 0x0a, 0xa8, 0x1c, 0x3e, 0x7e, 0x4d, 0x42, 0x60, 0x5c, 0x8e, + 0xfa, 0x42, 0xb3, 0x95, 0xe7, 0x92, 0x6b, 0xec, 0x7a, 0x95, 0x88, 0x98, + 0xe3, 0xf9, 0x0d, 0xe5, 0x08, 0xf1, 0x26, 0x96, 0x2a, 0x81, 0x2b, 0x7c, + 0x0d, 0x12, 0xa0, 0x7f, 0x7b, 0x39, 0xf6, 0xcc, 0x1b, 0x2d, 0x2c, 0xe9, + 0x5b, 0x02, 0x9b, 0x5c, 0x94, 0x51, 0x13, 0xe8, 0xa0, 0x19, 0xce, 0xde, + 0x07, 0x1b, 0xda, 0x39, 0x14, 0xb5, 0x8b, 0xcf, 0x79, 0x3e, 0x2b, 0xb8, + 0x75, 0xab, 0x81, 0xee, 0x5e, 0x08, 0x33, 0xc3, 0x49, 0x5b, 0x4a, 0x9c, + 0x74, 0x34, 0xde, 0x08, 0x61, 0x03, 0x38, 0xe3, 0xd8, 0xff, 0xc5, 0xc0, + 0xb5, 0x40, 0xd5, 0x26, 0x57, 0x85, 0xf1, 0xb7, 0x77, 0xb6, 0x36, 0xe0, + 0x8d, 0x43, 0x3a, 0xef, 0xfe, 0x0f, 0xf7, 0xee, 0x67, 0x6c, 0x7b, 0xd1, + 0x83, 0xf6, 0x10, 0xda, 0x67, 0x04, 0x3a, 0x27, 0xd8, 0x3a, 0xcb, 0x9d, + 0x4c, 0xa6, 0x9a, 0xc7, 0xea, 0x07, 0xc6, 0x76, 0x79, 0x1b, 0x23, 0x4a, + 0x68, 0x2f, 0x14, 0x84, 0x42, 0x79, 0xe8, 0x1f, 0xf2, 0xe6, 0xac, 0x72, + 0xb0, 0xb0, 0xb6, 0x39, 0x95, 0x40, 0xa4, 0x6e, 0x54, 0x2e, 0xb7, 0xb5, + 0x13, 0x70, 0x48, 0x0d, 0x27, 0xed, 0x2c, 0xa2, 0x64, 0x53, 0xb4, 0x04, + 0x84, 0xab, 0xd8, 0xea, 0x2a, 0x8c, 0xac, 0x5b, 0x1d, 0xb8, 0xb2, 0xbe, + 0x55, 0x2b, 0x4a, 0x47, 0xfc, 0xe0, 0x15, 0x78, 0xb6, 0xd6, 0xff, 0x20, + 0xa8, 0x8a, 0xec, 0x8b, 0x30, 0xef, 0xc5, 0xc6, 0xec, 0xa0, 0xdf, 0xd3, + 0xc4, 0x2b, 0x4a, 0xdf, 0xef, 0x5c, 0x46, 0xb3, 0x31, 0xc7, 0x5f, 0x8f, + 0x1e, 0x99, 0x76, 0x81, 0x71, 0x61, 0xdb, 0xc3, 0xc4, 0x0f, 0x66, 0x7b, + 0xd7, 0x44, 0xc7, 0x8d, 0x12, 0x38, 0x71, 0x7c, 0xd8, 0x41, 0xf6, 0x8a, + 0xb9, 0xba, 0xd2, 0x1f, 0xa1, 0x27, 0x64, 0x67, 0x51, 0xb2, 0xaf, 0xea, + 0x02, 0x95, 0x79, 0x20, 0x0a, 0xc8, 0xaa, 0x03, 0x11, 0xb6, 0x8b, 0x7d, + 0x86, 0xb7, 0xef, 0x5e, 0x3f, 0x0b, 0x91, 0x47, 0xf0, 0x43, 0xb4, 0x54, + 0x1d, 0x16, 0x66, 0xe9, 0x63, 0x1a, 0x55, 0xaf, 0x34, 0xad, 0x11, 0x68, + 0x4d, 0x36, 0xb7, 0x0c, 0x6d, 0x4d, 0xed, 0xba, 0x14, 0xe8, 0xf6, 0xe2, + 0x15, 0x64, 0xb6, 0x15, 0x28, 0xbf, 0xd2, 0x4d, 0xb6, 0x6f, 0xca, 0x5f, + 0x81, 0x1b, 0xf0, 0x31, 0xf5, 0xd3, 0xe0, 0x06, 0xc7, 0xf3, 0x0c, 0x18, + 0x91, 0x45, 0x22, 0xa2, 0x30, 0x48, 0x82, 0xeb, 0x42, 0xfc, 0x8f, 0x2a, + 0xa3, 0x1a, 0x8d, 0x84, 0x28, 0x20, 0x16, 0x95, 0xd9, 0x66, 0x67, 0x2b, + 0xef, 0xc6, 0x6e, 0x56, 0x1c, 0x62, 0x74, 0x16, 0x5c, 0x3e, 0x17, 0xd0, + 0xb7, 0xdd, 0x70, 0xb6, 0x0e, 0x79, 0x46, 0xc5, 0x4e, 0x72, 0x46, 0x69, + 0xf5, 0xa1, 0x1c, 0x7b, 0xd5, 0x67, 0x5c, 0xb3, 0x46, 0x4d, 0x18, 0x31, + 0x47, 0x42, 0x20, 0xe6, 0x12, 0x84, 0x4e, 0x16, 0x0f, 0x4a, 0xd0, 0xc4, + 0x91, 0xa3, 0xbd, 0x91, 0xcd, 0x86, 0x4c, 0xcd, 0x4b, 0x2e, 0x62, 0x84, + 0xea, 0x19, 0x2d, 0x21, 0x1a, 0x64, 0xc4, 0xd2, 0x24, 0x92, 0x96, 0x04, + 0x66, 0xb5, 0x4a, 0xe4, 0xa9, 0xd6, 0xaf, 0x12, 0x9b, 0xb5, 0x59, 0xe0, + 0x5c, 0x84, 0x84, 0x7c, 0x68, 0x99, 0xd8, 0x23, 0xa2, 0x15, 0xa7, 0x82, + 0xa5, 0x66, 0x95, 0x8f, 0xfe, 0x57, 0xc1, 0x12, 0x6c, 0x89, 0xe5, 0x5b, + 0x5d, 0x64, 0xdb, 0x81, 0x4f, 0x77, 0x3c, 0xc8, 0x52, 0x4e, 0x2a, 0xd6, + 0x74, 0x3c, 0x4b, 0x11, 0xfc, 0xc1, 0x7c, 0x01, 0xba, 0x0f, 0x0f, 0x57, + 0x8a, 0xbe, 0x5b, 0x16, 0x88, 0x96, 0xe6, 0xe9, 0x60, 0xcf, 0x66, 0xe9, + 0xe6, 0x07, 0xb0, 0x0b, 0xa3, 0xa0, 0xad, 0xdf, 0x70, 0xd4, 0xcb, 0x2e, + 0x33, 0x2f, 0xe5, 0xf2, 0x1e, 0x0d, 0x74, 0x7a, 0xf9, 0x4a, 0x0f, 0x32, + 0xb4, 0xa1, 0xc9, 0xf5, 0x3f, 0x0a, 0x06, 0xf9, 0x67, 0x45, 0x9c, 0xd9, + 0x58, 0xd4, 0x0e, 0x72, 0x55, 0x47, 0x49, 0x9b, 0xab, 0x9c, 0x66, 0xe7, + 0x4d, 0x9a, 0x02, 0x1b, 0x41, 0xad, 0xe5, 0x8c, 0x7f, 0xa1, 0xdc, 0xad, + 0xcd, 0x74, 0xda, 0x9f, 0xfa, 0x87, 0x32, 0xc1, 0x07, 0x8e, 0x9b, 0xef, + 0x28, 0x2f, 0x17, 0x6d, 0xdb, 0x84, 0x4b, 0xa8, 0x7d, 0x31, 0xa8, 0x32, + 0xe4, 0x9a, 0x1e, 0x0e, 0xef, 0x68, 0xf4, 0xac, 0x03, 0x6c, 0x68, 0xcc, + 0x28, 0xbb, 0xfb, 0x21, 0xb8, 0x11, 0xd7, 0xf9, 0xe8, 0x24, 0x37, 0xdf, + 0xe0, 0xb2, 0xef, 0xd6, 0xec, 0xdf, 0xcf, 0xf5, 0x50, 0x19, 0xa3, 0xa9, + 0x1b, 0x01, 0x2e, 0x94, 0x42, 0xb0, 0x14, 0x5d, 0x0e, 0x37, 0x46, 0x4a, + 0x52, 0x53, 0x60, 0x6b, 0x89, 0xc9, 0xca, 0xed, 0x0a, 0x0c, 0x18, 0x33, + 0x3c, 0x40, 0x42, 0x76, 0x7a, 0x7d, 0xb6, 0x10, 0x29, 0x3e, 0x42, 0x75, + 0xa6, 0xbf, 0xcb, 0xd3, 0xdc, 0xe1, 0x00, 0x05, 0x08, 0x25, 0x67, 0x6c, + 0x72, 0xde, 0x26, 0x72, 0x88, 0xbe, 0xfa, 0x05, 0x57, 0x77, 0x78, 0x83, + 0xce, 0xd5, 0x44, 0x49, 0x8b, 0xab, 0xbc, 0xca, 0xd3, 0x1c, 0x34, 0x4a, + 0xaa, 0xc7, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x17, 0x22, 0x2a, 0x2f, 0x36, 0x3d, 0x43}; +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_KEYGEN_PCT */ +#endif /* !EXPECTED_SIGNATURES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/main.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/main.c new file mode 100644 index 0000000000..a96e35c770 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/main.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include +#include +#include +#include + +/* Import public mldsa-native API + * + * This requires specifying the parameter set and namespace prefix + * used for the build. + */ +#include +#include "expected_signatures.h" +#include "test_only_rng/notrandombytes.h" + +/* + * This example demonstrates a static global state FIPS-202 implementation + * that works correctly with ML-DSA when FIPS-202 operations are used serially. + * + * This implementation uses a single global state for SHAKE128 and SHAKE256, + * requiring that no interleaved FIPS-202 operations occur. + */ + +#define CHECK(x) \ + do \ + { \ + int rc; \ + rc = (x); \ + if (!rc) \ + { \ + fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \ + return 1; \ + } \ + } while (0) + +int main(void) +{ + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t sig[CRYPTO_BYTES]; + size_t siglen; + + const char *test_msg = + "This is a test message for ML-DSA digital signature algorithm!"; + const char *test_ctx = "test_context_123"; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("Generating keypair ... "); + + CHECK(crypto_sign_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing... "); + + CHECK(crypto_sign_signature(sig, &siglen, (const uint8_t *)test_msg, + strlen(test_msg), (const uint8_t *)test_ctx, + strlen(test_ctx), sk) == 0); + + printf("DONE\n"); + printf("Verifying... "); + + CHECK(crypto_sign_verify(sig, siglen, (const uint8_t *)test_msg, + strlen(test_msg), (const uint8_t *)test_ctx, + strlen(test_ctx), pk) == 0); + printf("DONE\n"); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + CHECK(siglen == sizeof(expected_signature)); + CHECK(memcmp(sig, expected_signature, siglen) == 0); + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("OK\n"); + + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/mldsa_native.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/mldsa_native.h new file mode 100644 index 0000000000..fd150a9df1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/mldsa_native.h @@ -0,0 +1,975 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_H +#define MLD_H + +/* + * Public API for mldsa-native + * + * This header defines the public API of a single build of mldsa-native. + * + * Make sure the configuration file is in the include path + * (this is "mldsa_native_config.h" by default, or MLD_CONFIG_FILE if defined). + * + * # Multi-level builds + * + * This header specifies a build of mldsa-native for a fixed security level. + * If you need multiple security levels, leave the security level unspecified + * in the configuration file and include this header multiple times, setting + * MLD_CONFIG_PARAMETER_SET accordingly for each, and #undef'ing the MLD_H + * guard to allow multiple inclusions. + * + * # Legacy configuration (deprecated) + * + * Instead of providing the config file used for the build, you can + * alternatively set the following configuration options prior to + * including this header. + * + * This method of configuration is deprecated. + * It will be removed in mldsa-native-v2. + * + * - MLD_CONFIG_API_PARAMETER_SET [required] + * + * The parameter set used for the build; 44, 65, or 87. + * + * - MLD_CONFIG_API_NAMESPACE_PREFIX [required] + * + * The namespace prefix used for the build. + * + * NOTE: + * For a multi-level build, you must include the 44/65/87 suffixes + * in MLD_CONFIG_API_NAMESPACE_PREFIX. + * + * - MLD_CONFIG_API_NO_SUPERCOP [optional] + * + * By default, this header will also expose the mldsa-native API in the + * SUPERCOP naming convention crypto_sign_xxx. If you don't want/need this, + * set MLD_CONFIG_API_NO_SUPERCOP. You must set this for a multi-level build. + * + * - MLD_CONFIG_API_CONSTANTS_ONLY [optional] + * + * If you don't want this header to expose any function declarations, + * but only constants for the sizes of key material, set + * MLD_CONFIG_API_CONSTANTS_ONLY. In this case, you don't need to set + * MLD_CONFIG_API_PARAMETER_SET or MLD_CONFIG_API_NAMESPACE_PREFIX, + * nor include a configuration. + * + * - MLD_CONFIG_API_QUALIFIER [optional] + * + * Qualifier to apply to external API. + * + ******************************************************************************/ + +/******************************* Key sizes ************************************/ + +/* Sizes of cryptographic material, per parameter set */ +/* See mldsa/src/params.h for the arithmetic expressions giving rise to these */ +/* check-magic: off */ +#define MLDSA44_SECRETKEYBYTES 2560 +#define MLDSA44_PUBLICKEYBYTES 1312 +#define MLDSA44_BYTES 2420 + +#define MLDSA65_SECRETKEYBYTES 4032 +#define MLDSA65_PUBLICKEYBYTES 1952 +#define MLDSA65_BYTES 3309 + +#define MLDSA87_SECRETKEYBYTES 4896 +#define MLDSA87_PUBLICKEYBYTES 2592 +#define MLDSA87_BYTES 4627 +/* check-magic: on */ + +/* Size of seed and randomness in bytes (level-independent) */ +#define MLDSA_SEEDBYTES 32 +#define MLDSA44_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA65_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA87_SEEDBYTES MLDSA_SEEDBYTES + +/* Size of CRH output in bytes (level-independent) */ +#define MLDSA_CRHBYTES 64 +#define MLDSA44_CRHBYTES MLDSA_CRHBYTES +#define MLDSA65_CRHBYTES MLDSA_CRHBYTES +#define MLDSA87_CRHBYTES MLDSA_CRHBYTES + +/* Size of TR output in bytes (level-independent) */ +#define MLDSA_TRBYTES 64 +#define MLDSA44_TRBYTES MLDSA_TRBYTES +#define MLDSA65_TRBYTES MLDSA_TRBYTES +#define MLDSA87_TRBYTES MLDSA_TRBYTES + +/* Size of randomness for signing in bytes (level-independent) */ +#define MLDSA_RNDBYTES 32 +#define MLDSA44_RNDBYTES MLDSA_RNDBYTES +#define MLDSA65_RNDBYTES MLDSA_RNDBYTES +#define MLDSA87_RNDBYTES MLDSA_RNDBYTES + +/* Sizes of cryptographic material, as a function of LVL=44,65,87 */ +#define MLDSA_SECRETKEYBYTES_(LVL) MLDSA##LVL##_SECRETKEYBYTES +#define MLDSA_PUBLICKEYBYTES_(LVL) MLDSA##LVL##_PUBLICKEYBYTES +#define MLDSA_BYTES_(LVL) MLDSA##LVL##_BYTES +#define MLDSA_SECRETKEYBYTES(LVL) MLDSA_SECRETKEYBYTES_(LVL) +#define MLDSA_PUBLICKEYBYTES(LVL) MLDSA_PUBLICKEYBYTES_(LVL) +#define MLDSA_BYTES(LVL) MLDSA_BYTES_(LVL) + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + +/****************************** Function API **********************************/ + +#define MLD_API_CONCAT_(x, y) x##y +#define MLD_API_CONCAT(x, y) MLD_API_CONCAT_(x, y) +#define MLD_API_CONCAT_UNDERSCORE(x, y) MLD_API_CONCAT(MLD_API_CONCAT(x, _), y) + +#if !defined(MLD_CONFIG_API_PARAMETER_SET) +/* Recommended configuration via same config file as used for the build. */ + +/* For now, we derive the legacy API configuration MLD_CONFIG_API_XXX from + * the config file. In mldsa-native-v2, this will be removed and we will + * exclusively work with MLD_CONFIG_XXX. */ + +/* You need to make sure the config file is in the include path. */ +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#define MLD_CONFIG_API_PARAMETER_SET MLD_CONFIG_PARAMETER_SET + +#if defined(MLD_CONFIG_MULTILEVEL_BUILD) +#define MLD_CONFIG_API_NAMESPACE_PREFIX \ + MLD_API_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_CONFIG_API_NAMESPACE_PREFIX MLD_CONFIG_NAMESPACE_PREFIX +#endif + +#if defined(MLD_CONFIG_NO_SUPERCOP) +#define MLD_CONFIG_API_NO_SUPERCOP +#endif + +#if defined(MLD_CONFIG_CONSTANTS_ONLY) +#define MLD_CONFIG_API_CONSTANTS_ONLY +#endif + +#if defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_CONFIG_API_QUALIFIER MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#else /* !MLD_CONFIG_API_PARAMETER_SET */ +#define MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_PARAMETER_SET */ + +#define MLD_API_NAMESPACE(sym) \ + MLD_API_CONCAT_UNDERSCORE(MLD_CONFIG_API_NAMESPACE_PREFIX, sym) + +#if defined(__GNUC__) || defined(clang) +#define MLD_API_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_API_MUST_CHECK_RETURN_VALUE +#endif + +#if defined(MLD_CONFIG_API_QUALIFIER) +#define MLD_API_QUALIFIER MLD_CONFIG_API_QUALIFIER +#else +#define MLD_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_API_CONSTANTS_ONLY) + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************************* + * Name: crypto_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: + * input random seed + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair_internal)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t seed[MLDSA_SEEDBYTES] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: If MLD_CONFIG_KEYGEN_PCT is enabled and the + * PCT check failed. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return -1 in that case. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_extmu + * + * Description: Computes signature. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_extmu)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t *sm: pointer to output signed message (allocated array + * with MLDSA{44,65,87}_BYTES + mlen bytes), can be + * equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(sign)( + uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_extmu)( + const uint8_t *sig, size_t siglen, const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_open + * + * Description: Verify signed message. + * + * Arguments: + * - uint8_t *m: pointer to output message (allocated array with + * smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(open)( + uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: crypto_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *ph, size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_shake256)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_shake256)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/* Maximum formatted domain separation message length */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +size_t MLD_API_NAMESPACE(prepare_domain_separation_prefix)( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg); + +/************************************************* + * Name: crypto_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[CRYPTO_SECRETKEYBYTES]: input secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(pk_from_sk)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +#ifdef __cplusplus +} +#endif + +/****************************** SUPERCOP API *********************************/ + +#if !defined(MLD_CONFIG_API_NO_SUPERCOP) +/* Export API in SUPERCOP naming scheme CRYPTO_xxx / crypto_sign_xxx */ +#define CRYPTO_SECRETKEYBYTES MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_PUBLICKEYBYTES MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_BYTES MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET) + +#define crypto_sign_keypair MLD_API_NAMESPACE(keypair) +#define crypto_sign_signature MLD_API_NAMESPACE(signature) +#define crypto_sign MLD_API_NAMESPACE(sign) +#define crypto_sign_verify MLD_API_NAMESPACE(verify) +#define crypto_sign_open MLD_API_NAMESPACE(open) + +#else /* !MLD_CONFIG_API_NO_SUPERCOP */ + +/* If the SUPERCOP API is not needed, we can undefine the various helper macros + * above. Otherwise, they are needed for lazy evaluation of crypto_sign_xxx. */ +#if !defined(MLD_API_LEGACY_CONFIG) +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_QUALIFIER +#endif /* !MLD_API_LEGACY_CONFIG */ + +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_NAMESPACE +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_QUALIFIER +#undef MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_NO_SUPERCOP */ +#endif /* !MLD_CONFIG_API_CONSTANTS_ONLY */ + + +/***************************** Memory Usage **********************************/ + +/* + * By default mldsa-native performs all memory allocations on the stack. + * Alternatively, mldsa-native supports custom allocation of large structures + * through the `MLD_CONFIG_CUSTOM_ALLOC_FREE` configuration option. + * See mldsa_native_config.h for details. + * + * `MLD_TOTAL_ALLOC_{44,65,87}_{KEYPAIR,SIGN,VERIFY}` indicates the maximum + * (accumulative) allocation via MLD_ALLOC for each parameter set and operation. + * Note that some stack allocation remains even + * when using custom allocators, so these values are lower than total stack + * usage with the default stack-only allocation. + * + * These constants may be used to implement custom allocations using a + * fixed-sized buffer and a simple allocator (e.g., bump allocator). + */ +/* check-magic: off */ +#if defined(MLD_API_LEGACY_CONFIG) || !defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 45248 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 56640 +#define MLD_TOTAL_ALLOC_44_SIGN 52896 +#define MLD_TOTAL_ALLOC_44_VERIFY 38816 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 71872 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 85856 +#define MLD_TOTAL_ALLOC_65_SIGN 80576 +#define MLD_TOTAL_ALLOC_65_VERIFY 62432 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 112832 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 130816 +#define MLD_TOTAL_ALLOC_87_SIGN 123584 +#define MLD_TOTAL_ALLOC_87_VERIFY 99552 +#else /* MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM */ +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 32992 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 36192 +#define MLD_TOTAL_ALLOC_44_SIGN 32448 +#define MLD_TOTAL_ALLOC_44_VERIFY 22464 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 46304 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 50048 +#define MLD_TOTAL_ALLOC_65_SIGN 44768 +#define MLD_TOTAL_ALLOC_65_VERIFY 30720 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 62688 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 66336 +#define MLD_TOTAL_ALLOC_87_SIGN 59104 +#define MLD_TOTAL_ALLOC_87_VERIFY 41216 +#endif /* !(MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM) */ +/* check-magic: on */ + +/* + * MLD_TOTAL_ALLOC_*_KEYPAIR adapts based on MLD_CONFIG_KEYGEN_PCT. + * For legacy config, we don't know which options are used, so assume + * the worst case (PCT enabled). + */ +#if defined(MLD_API_LEGACY_CONFIG) || defined(MLD_CONFIG_KEYGEN_PCT) +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#else +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#endif + +#define MLD_MAX3_(a, b, c) \ + ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c))) + +/* + * `MLD_TOTAL_ALLOC_{44,65,87}` is the maximum across all operations for each + * parameter set. + */ +#define MLD_TOTAL_ALLOC_44 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_44_KEYPAIR, MLD_TOTAL_ALLOC_44_SIGN, \ + MLD_TOTAL_ALLOC_44_VERIFY) +#define MLD_TOTAL_ALLOC_65 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_65_KEYPAIR, MLD_TOTAL_ALLOC_65_SIGN, \ + MLD_TOTAL_ALLOC_65_VERIFY) +#define MLD_TOTAL_ALLOC_87 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_87_KEYPAIR, MLD_TOTAL_ALLOC_87_SIGN, \ + MLD_TOTAL_ALLOC_87_VERIFY) + +#endif /* !MLD_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/mldsa_native_config.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/mldsa_native_config.h new file mode 100644 index 0000000000..05b726a435 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/mldsa_native_config.h @@ -0,0 +1,740 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/* + * Test configuration: Configuration for custom serial FIPS202 implementation + * + * This configuration differs from the default mldsa/mldsa_native_config.h in + * the following places: + * - MLD_CONFIG_NAMESPACE_PREFIX + * - MLD_CONFIG_SERIAL_FIPS202_ONLY + * - MLD_CONFIG_FIPS202_CUSTOM_HEADER + * - MLD_CONFIG_FIPS202X4_CUSTOM_HEADER + */ + + +#ifndef MLD_CONFIG_H +#define MLD_CONFIG_H + +/****************************************************************************** + * Name: MLD_CONFIG_PARAMETER_SET + * + * Description: Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * If you want to support multiple parameter sets, build the + * library multiple times and set MLD_CONFIG_MULTILEVEL_BUILD. + * See MLD_CONFIG_MULTILEVEL_BUILD for how to do this while + * minimizing code duplication. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of the default configuration file mldsa/mldsa_native_config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * then configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + * + *****************************************************************************/ +/* No need to set this -- we _are_ already in a custom config */ +/* #define MLD_CONFIG_FILE "mldsa_native_config.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_NAMESPACE_PREFIX + * + * Description: The prefix to use to namespace global symbols from mldsa/. + * + * In a multi-level build, level-dependent symbols will + * additionally be prefixed with the parameter set (44/65/87). + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_NAMESPACE_PREFIX mldsa + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_BUILD + * + * Description: Set this if the build is part of a multi-level build supporting + * multiple parameter sets. + * + * If you need only a single parameter set, keep this unset. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them. + * + * See examples/multilevel_build for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_BUILD */ + +/****************************************************************************** + * Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_EXTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_RANDOMIZED_API + * + * Description: If this option is set, mldsa-native will be built without the + * randomized API functions (crypto_sign_keypair, + * crypto_sign, crypto_sign_signature, and + * crypto_sign_signature_extmu). + * This allows users to build mldsa-native without providing a + * randombytes() implementation if they only need the + * internal deterministic API + * (crypto_sign_keypair_internal, crypto_sign_signature_internal). + * + * NOTE: This option is incompatible with MLD_CONFIG_KEYGEN_PCT + * as the current PCT implementation requires + * crypto_sign_signature(). + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_RANDOMIZED_API */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_SUPERCOP + * + * Description: By default, mldsa_native.h exposes the mldsa-native API in the + * SUPERCOP naming convention (crypto_sign_xxx). If you don't need + * this, set MLD_CONFIG_NO_SUPERCOP. + * + * NOTE: You must set this for a multi-level build as the SUPERCOP + * naming does not disambiguate between the parameter sets. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_SUPERCOP */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONSTANTS_ONLY + * + * Description: If you only need the size constants (MLDSA_PUBLICKEYBYTES, etc.) + * but no function declarations, set MLD_CONFIG_CONSTANTS_ONLY. + * + * This only affects the public header mldsa_native.h, not + * the implementation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONSTANTS_ONLY */ + +/****************************************************************************** + * + * Build-only configuration options + * + * The remaining configurations are build-options only. + * They do not affect the API described in mldsa_native.h. + * + *****************************************************************************/ + +#if defined(MLD_BUILD_INTERNAL) +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_WITH_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, all MLD_CONFIG_PARAMETER_SET-independent + * code will be included in the build, including code needed only + * for other parameter sets. + * + * Example: TODO: add example + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_WITH_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_NO_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, no MLD_CONFIG_PARAMETER_SET-independent code + * will be included in the build. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * + * Description: This is only relevant for single compilation unit (SCU) + * builds of mldsa-native. In this case, it determines whether + * directives defined in parameter-set-independent headers should + * be #undef'ined or not at the of the SCU file. This is needed + * in multilevel builds. + * + * See examples/multilevel_build_native for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * + * Description: Determines whether an native arithmetic backend should be used. + * + * The arithmetic backend covers performance critical functions + * such as the number-theoretic transform (NTT). + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the arithmetic backend to be use is + * determined by MLD_CONFIG_ARITH_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_ARITH_BACKEND_FILE + * + * Description: The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * + * Description: Determines whether an native FIPS202 backend should be used. + * + * The FIPS202 backend covers 1x/2x/4x-fold Keccak-f1600, which is + * the performance bottleneck of SHA3 and SHAKE. + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the FIPS202 backend to be use is + * determined by MLD_CONFIG_FIPS202_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_BACKEND_FILE + * + * Description: The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +#define MLD_CONFIG_FIPS202_CUSTOM_HEADER "../custom_fips202/fips202.h" + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202X4_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202-X4 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202x4.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +#define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER "../custom_fips202/fips202x4.h" + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ZEROIZE + * + * Description: In compliance with @[FIPS204, Section 3.6.3], mldsa-native, + * zeroizes intermediate stack buffers before returning from + * function calls. + * + * Set this option and define `mld_zeroize` if you want to + * use a custom method to zeroize intermediate stack buffers. + * The default implementation uses SecureZeroMemory on Windows + * and a memset + compiler barrier otherwise. If neither of those + * is available on the target platform, compilation will fail, + * and you will need to use MLD_CONFIG_CUSTOM_ZEROIZE to provide + * a custom implementation of `mld_zeroize()`. + * + * WARNING: + * The explicit stack zeroization conducted by mldsa-native + * reduces the likelihood of data leaking on the stack, but + * does not eliminate it! The C standard makes no guarantee about + * where a compiler allocates structures and whether/where it makes + * copies of them. Also, in addition to entire structures, there + * may also be potentially exploitable leakage of individual values + * on the stack. + * + * If you need bullet-proof zeroization of the stack, you need to + * consider additional measures instead of what this feature + * provides. In this case, you can set mld_zeroize to a + * no-op. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void mld_zeroize(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * Description: mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to provided by the + * consumer. + * + * If this option is not set, mldsa-native expects a function + * int randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mld_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_RANDOMBYTES + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) + { + ... your implementation ... + return 0; + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + * + * Description: mldsa-native backends may rely on specific hardware features. + * Those backends will only be included in an mldsa-native build + * if support for the respective features is enabled at + * compile-time. However, when building for a heteroneous set + * of CPUs to run the resulting binary/library on, feature + * detection at _runtime_ is needed to decided whether a backend + * can be used or not. + * + * Set this option and define `mld_sys_check_capability` if you + * want to use a custom method to dispatch between implementations. + * + * Return value 1 indicates that a capability is supported. + * Return value 0 indicates that a capability is not supported. + * + * If this option is not set, mldsa-native uses compile-time + * feature detection only to decide which backend to use. + * + * If you compile mldsa-native on a system with different + * capabilities than the system that the resulting binary/library + * will be run on, you must use this option. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) + { + ... your implementation ... + } +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ALLOC_FREE [EXPERIMENTAL] + * + * Description: Set this option and define `MLD_CUSTOM_ALLOC` and + * `MLD_CUSTOM_FREE` if you want to use custom allocation for + * large local structures or buffers. + * + * By default, all buffers/structures are allocated on the stack. + * If this option is set, most of them will be allocated via + * MLD_CUSTOM_ALLOC. + * + * Parameters to MLD_CUSTOM_ALLOC: + * - T* v: Target pointer to declare. + * - T: Type of structure to be allocated + * - N: Number of elements to be allocated. + * + * Parameters to MLD_CUSTOM_FREE: + * - T* v: Target pointer to free. May be NULL. + * - T: Type of structure to be freed. + * - N: Number of elements to be freed. + * + * WARNING: This option is experimental! + * Its scope, configuration and function/macro signatures may + * change at any time. We expect a stable API for v2. + * + * NOTE: Even if this option is set, some allocations further down + * the call stack will still be made from the stack. Those will + * likely be added to the scope of this option in the future. + * + * NOTE: MLD_CUSTOM_ALLOC need not guarantee a successful + * allocation nor include error handling. Upon failure, the + * target pointer should simply be set to NULL. The calling + * code will handle this case and invoke MLD_CUSTOM_FREE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ALLOC_FREE + #if !defined(__ASSEMBLER__) + #include + #define MLD_CUSTOM_ALLOC(v, T, N) \ + T* (v) = (T *)aligned_alloc(MLD_DEFAULT_ALIGN, \ + MLD_ALIGN_UP(sizeof(T) * (N))) + #define MLD_CUSTOM_FREE(v, T, N) free(v) + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMCPY + * + * Description: Set this option and define `mld_memcpy` if you want to + * use a custom method to copy memory instead of the standard + * library memcpy function. + * + * The custom implementation must have the same signature and + * behavior as the standard memcpy function: + * void *mld_memcpy(void *dest, const void *src, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMCPY + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMSET + * + * Description: Set this option and define `mld_memset` if you want to + * use a custom method to set memory instead of the standard + * library memset function. + * + * The custom implementation must have the same signature and + * behavior as the standard memset function: + * void *mld_memset(void *s, int c, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMSET + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memset(void *s, int c, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_INTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of internal API. + * + * The primary use case for this option are single-CU builds, + * in which case this option can be set to `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_INTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CT_TESTING_ENABLED + * + * Description: If set, mldsa-native annotates data as secret / public using + * valgrind's annotations VALGRIND_MAKE_MEM_UNDEFINED and + * VALGRIND_MAKE_MEM_DEFINED, enabling various checks for secret- + * dependent control flow of variable time execution (depending + * on the exact version of valgrind installed). + * + *****************************************************************************/ +/* #define MLD_CONFIG_CT_TESTING_ENABLED */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * and MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT + * + * Description: Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, crypto_sign_keypair_internal and + * crypto_sign_keypair will return a non-zero error code if the + * PCT failed. + * + * NOTE: This feature will drastically lower the performance of + * key generation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * Description: If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "src/src.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Description: Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * NOTE: Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + * + *****************************************************************************/ +#define MLD_CONFIG_SERIAL_FIPS202_ONLY + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER + * + * Description: Set this to add a context parameter that is provided to public + * API functions and is then available in custom callbacks. + * + * The type of the context parameter is configured via + * MLD_CONFIG_CONTEXT_PARAMETER_TYPE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER_TYPE + * + * Description: Set this to define the type for the context parameter used by + * MLD_CONFIG_CONTEXT_PARAMETER. + * + * This is only relevant if MLD_CONFIG_CONTEXT_PARAMETER is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER_TYPE void* */ + +/****************************************************************************** + * Name: MLD_CONFIG_REDUCE_RAM [EXPERIMENTAL] + * + * Description: Set this to reduce RAM usage. + * This trades memory for performance. + * + * For expected memory usage, see the MLD_TOTAL_ALLOC_* constants + * defined in mldsa_native.h. + * + * This option is useful for embedded systems with tight RAM + * constraints but relaxed performance requirements. + * + * WARNING: This option is experimental! + * CBMC proofs do not currently cover this configuration option. + * Its scope and configuration may change at any time. + * + *****************************************************************************/ +/* #define MLD_CONFIG_REDUCE_RAM */ + +/************************* Config internals ********************************/ + +#endif /* MLD_BUILD_INTERNAL */ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace is + * + * PQCP_MLDSA_NATIVE_MLDSA_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_ + */ + +#if MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65 +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87 +#endif + +#endif /* !MLD_CONFIG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/cbmc.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/cbmc.h new file mode 100644 index 0000000000..8ed1ecb06b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/cbmc.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_CBMC_H +#define MLD_CBMC_H +/*************************************************** + * Basic replacements for __CPROVER_XXX contracts + ***************************************************/ +#ifndef CBMC + +#define __contract__(x) +#define __loop__(x) +#define cassert(x) + +#else /* !CBMC */ + +#include + +#define __contract__(x) x +#define __loop__(x) x + +/* https://diffblue.github.io/cbmc/contracts-assigns.html */ +#define assigns(...) __CPROVER_assigns(__VA_ARGS__) + +/* https://diffblue.github.io/cbmc/contracts-requires-ensures.html */ +#define requires(...) __CPROVER_requires(__VA_ARGS__) +#define ensures(...) __CPROVER_ensures(__VA_ARGS__) +/* https://diffblue.github.io/cbmc/contracts-loops.html */ +#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__) +#define decreases(...) __CPROVER_decreases(__VA_ARGS__) +/* cassert to avoid confusion with in-built assert */ +#define cassert(x) __CPROVER_assert(x, "cbmc assertion failed") +#define assume(...) __CPROVER_assume(__VA_ARGS__) + +/*************************************************** + * Macros for "expression" forms that may appear + * _inside_ top-level contracts. + ***************************************************/ + +/* + * function return value - useful inside ensures + * https://diffblue.github.io/cbmc/contracts-functions.html + */ +#define return_value (__CPROVER_return_value) + +/* + * assigns l-value targets + * https://diffblue.github.io/cbmc/contracts-assigns.html + */ +#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__) +#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__) +#define same_object(...) __CPROVER_same_object(__VA_ARGS__) + +/* + * Pointer-related predicates + * https://diffblue.github.io/cbmc/contracts-memory-predicates.html + */ +#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__) +#define readable(...) __CPROVER_r_ok(__VA_ARGS__) +#define writeable(...) __CPROVER_w_ok(__VA_ARGS__) + +/* Maximum supported buffer size + * + * Larger buffers may be supported, but due to internal modeling constraints + * in CBMC, the proofs of memory- and type-safety won't be able to run. + * + * If you find yourself in need for a buffer size larger than this, + * please contact the maintainers, so we can prioritize work to relax + * this somewhat artificial bound. + */ +#define MLD_MAX_BUFFER_SIZE (SIZE_MAX >> 12) + + +/* + * History variables + * https://diffblue.github.io/cbmc/contracts-history-variables.html + */ +#define old(...) __CPROVER_old(__VA_ARGS__) +#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__) + +/* + * Quantifiers + * Note that the range on qvar is _exclusive_ between qvar_lb .. qvar_ub + * https://diffblue.github.io/cbmc/contracts-quantifiers.html + */ + +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define forall(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> (predicate) \ + } + +#define exists(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_exists \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) && (predicate) \ + } +/* clang-format on */ + +/*************************************************** + * Convenience macros for common contract patterns + ***************************************************/ +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define CBMC_CONCAT_(left, right) left##right +#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right) + +#define array_bound_core(qvar, qvar_lb, qvar_ub, array_var, \ + value_lb, value_ub) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + (((int)(value_lb) <= ((array_var)[(qvar)])) && \ + (((array_var)[(qvar)]) < (int)(value_ub))) \ + } + +#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \ + array_bound_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (qvar_lb), \ + (qvar_ub), (array_var), (value_lb), (value_ub)) + +#define array_unchanged_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (int32_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged(array_var, N) \ + array_unchanged_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) + +#define array_unchanged_u64_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (uint64_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged_u64(array_var, N) \ + array_unchanged_u64_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) +/* clang-format on */ + +/* Wrapper around array_bound operating on absolute values. + * + * The absolute value bound `k` is exclusive. + * + * Note that since the lower bound in array_bound is inclusive, we have to + * raise it by 1 here. + */ +#define array_abs_bound(arr, lb, ub, k) \ + array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k)) + +#endif /* CBMC */ + +#endif /* !MLD_CBMC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/common.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/common.h new file mode 100644 index 0000000000..4a5bc8109d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/common.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_COMMON_H +#define MLD_COMMON_H + +#define MLD_BUILD_INTERNAL + +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#include "params.h" +#include "sys.h" + +/* Internal and public API have external linkage by default, but + * this can be overwritten by the user, e.g. for single-CU builds. */ +#if !defined(MLD_CONFIG_INTERNAL_API_QUALIFIER) +#define MLD_INTERNAL_API +#else +#define MLD_INTERNAL_API MLD_CONFIG_INTERNAL_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_EXTERNAL_API +#else +#define MLD_EXTERNAL_API MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#if defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) || \ + defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) +#define MLD_MULTILEVEL_BUILD +#endif + +#define MLD_CONCAT_(x1, x2) x1##x2 +#define MLD_CONCAT(x1, x2) MLD_CONCAT_(x1, x2) + +#if defined(MLD_MULTILEVEL_BUILD) +#define MLD_ADD_PARAM_SET(s) MLD_CONCAT(s, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_ADD_PARAM_SET(s) s +#endif + +#define MLD_NAMESPACE_PREFIX MLD_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, _) +#define MLD_NAMESPACE_PREFIX_KL \ + MLD_CONCAT(MLD_ADD_PARAM_SET(MLD_CONFIG_NAMESPACE_PREFIX), _) + +/* Functions are prefixed by MLD_CONFIG_NAMESPACE_PREFIX. + * + * If multiple parameter sets are used, functions depending on the parameter + * set are additionally prefixed with 44/65/87. See mldsa_native_config.h. + * + * Example: If MLD_CONFIG_NAMESPACE_PREFIX is PQCP_MLDSA_NATIVE, then + * MLD_NAMESPACE_KL(keypair) becomes PQCP_MLDSA_NATIVE44_keypair/ + * PQCP_MLDSA_NATIVE65_keypair/PQCP_MLDSA_NATIVE87_keypair. + */ +#define MLD_NAMESPACE(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX, s) +#define MLD_NAMESPACE_KL(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX_KL, s) + +/* On Apple platforms, we need to emit leading underscore + * in front of assembly symbols. We thus introducee a separate + * namespace wrapper for ASM symbols. */ +#if !defined(__APPLE__) +#define MLD_ASM_NAMESPACE(sym) MLD_NAMESPACE(sym) +#else +#define MLD_ASM_NAMESPACE(sym) MLD_CONCAT(_, MLD_NAMESPACE(sym)) +#endif + +/* + * On X86_64 if control-flow protections (CET) are enabled (through + * -fcf-protection=), we add an endbr64 instruction at every global function + * label. See sys.h for more details + */ +#if defined(MLD_SYS_X86_64) +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : MLD_CET_ENDBR +#else +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : +#endif + +/* We aim to simplify the user's life by supporting builds where + * all source files are included, even those that are not needed. + * Those files are appropriately guarded and will be empty when unneeded. + * The following is to avoid compilers complaining about this. */ +#define MLD_EMPTY_CU(s) extern int MLD_NAMESPACE_KL(empty_cu_##s); + +/* MLD_CONFIG_NO_ASM takes precedence over MLD_USE_NATIVE_XXX */ +#if defined(MLD_CONFIG_NO_ASM) +#undef MLD_CONFIG_USE_NATIVE_BACKEND_ARITH +#undef MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, but MLD_CONFIG_ARITH_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, but MLD_CONFIG_FIPS202_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_NO_RANDOMIZED_API) && defined(MLD_CONFIG_KEYGEN_PCT) +#error Bad configuration: MLD_CONFIG_NO_RANDOMIZED_API is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires crypto_sign_signature() +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#include MLD_CONFIG_ARITH_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#include MLD_CONFIG_FIPS202_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "fips202/native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#define MLD_FIPS202_HEADER_FILE "fips202/fips202.h" +#else +#define MLD_FIPS202_HEADER_FILE MLD_CONFIG_FIPS202_CUSTOM_HEADER +#endif + +#if !defined(MLD_CONFIG_FIPS202X4_CUSTOM_HEADER) +#define MLD_FIPS202X4_HEADER_FILE "fips202/fips202x4.h" +#else +#define MLD_FIPS202X4_HEADER_FILE MLD_CONFIG_FIPS202X4_CUSTOM_HEADER +#endif + +/* Standard library function replacements */ +#if !defined(__ASSEMBLER__) +#if !defined(MLD_CONFIG_CUSTOM_MEMCPY) +#include +#define mld_memcpy memcpy +#endif + +#if !defined(MLD_CONFIG_CUSTOM_MEMSET) +#include +#define mld_memset memset +#endif + +/* Allocation macros for large local structures + * + * MLD_ALLOC(v, T, N) declares T *v and attempts to point it to an T[N] + * MLD_FREE(v, T, N) zeroizes and frees the allocation + * + * Default implementation uses stack allocation. + * Can be overridden by setting the config option MLD_CONFIG_CUSTOM_ALLOC_FREE + * and defining MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE. + */ +#if defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) != \ + (defined(MLD_CUSTOM_ALLOC) && defined(MLD_CUSTOM_FREE)) +#error Bad configuration: MLD_CONFIG_CUSTOM_ALLOC_FREE must be set together with MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE +#endif + +/* + * If the integration wants to provide a context parameter for use in + * platform-specific hooks, then it should define this parameter. + * + * The MLD_CONTEXT_PARAMETERS_n macros are intended to be used with macros + * defining the function names and expand to either pass or discard the context + * argument as required by the current build. If there is no context parameter + * requested then these are removed from the prototypes and from all calls. + */ +#ifdef MLD_CONFIG_CONTEXT_PARAMETER +#define MLD_CONTEXT_PARAMETERS_0(context) (context) +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0, context) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1, context) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) \ + (arg0, arg1, arg2, context) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3, context) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4, context) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, context) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, context) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, context) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, context) +#else /* MLD_CONFIG_CONTEXT_PARAMETER */ +#define MLD_CONTEXT_PARAMETERS_0(context) () +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) (arg0, arg1, arg2) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) +#endif /* !MLD_CONFIG_CONTEXT_PARAMETER */ + +#if defined(MLD_CONFIG_CONTEXT_PARAMETER_TYPE) != \ + defined(MLD_CONFIG_CONTEXT_PARAMETER) +#error MLD_CONFIG_CONTEXT_PARAMETER_TYPE must be defined if and only if MLD_CONFIG_CONTEXT_PARAMETER is defined +#endif + +#if !defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) +/* Default: stack allocation */ + +#define MLD_ALLOC(v, T, N, context) \ + MLD_ALIGN T mld_alloc_##v[N]; \ + T *v = mld_alloc_##v + +/* TODO: This leads to a circular dependency between common and ct.h + * It just works out before we're at the end of the file, but it's still + * prone to issues in the future. */ +#include "ct.h" +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + mld_zeroize(mld_alloc_##v, sizeof(mld_alloc_##v)); \ + (v) = NULL; \ + } while (0) + +#else /* !MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* Custom allocation */ + +/* + * The indirection here is necessary to use MLD_CONTEXT_PARAMETERS_3 here. + */ +#define MLD_APPLY(f, args) f args + +#define MLD_ALLOC(v, T, N, context) \ + MLD_APPLY(MLD_CUSTOM_ALLOC, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)) + +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + if (v != NULL) \ + { \ + mld_zeroize(v, sizeof(T) * (N)); \ + MLD_APPLY(MLD_CUSTOM_FREE, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)); \ + v = NULL; \ + } \ + } while (0) + +#endif /* MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* + * We are facing severe CBMC performance issues when using unions. + * As a temporary workaround, we use unions only when MLD_CONFIG_REDUCE_RAM is + * set. + * TODO: Remove the workaround once + * https://github.com/diffblue/cbmc/issues/8813 + * is resolved + */ +#if defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_UNION_OR_STRUCT union +#else +#define MLD_UNION_OR_STRUCT struct +#endif + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_COMMON_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/ct.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/ct.c new file mode 100644 index 0000000000..010b1a52a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/ct.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include "ct.h" + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +/* + * Masking value used in constant-time functions from + * ct.h to block the compiler's range analysis and + * thereby reduce the risk of compiler-introduced branches. + */ +volatile uint64_t mld_ct_opt_blocker_u64 = 0; + +#else /* !MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(ct) + +#endif /* !(!MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/ct.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/ct.h new file mode 100644 index 0000000000..c307456468 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/ct.h @@ -0,0 +1,366 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [libmceliece] + * libmceliece implementation of Classic McEliece + * Bernstein, Chou + * https://lib.mceliece.org/ + * + * - [optblocker] + * PQC forum post on opt-blockers using volatile globals + * Daniel J. Bernstein + * https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ + */ + +#ifndef MLD_CT_H +#define MLD_CT_H + +#include +#include "cbmc.h" +#include "common.h" + +/* Constant-time comparisons and conditional operations + + We reduce the risk for compilation into variable-time code + through the use of 'value barriers'. + + Functionally, a value barrier is a no-op. To the compiler, however, + it constitutes an arbitrary modification of its input, and therefore + harden's value propagation and range analysis. + + We consider two approaches to implement a value barrier: + - An empty inline asm block which marks the target value as clobbered. + - XOR'ing with the value of a volatile global that's set to 0; + see @[optblocker] for a discussion of this idea, and + @[libmceliece, inttypes/crypto_intN.h] for an implementation. + + The first approach is cheap because it only prevents the compiler + from reasoning about the value of the variable past the barrier, + but does not directly generate additional instructions. + + The second approach generates redundant loads and XOR operations + and therefore comes at a higher runtime cost. However, it appears + more robust towards optimization, as compilers should never drop + a volatile load. + + We use the empty-ASM value barrier for GCC and clang, and fall + back to the global volatile barrier otherwise. + + The global value barrier can be forced by setting + MLD_CONFIG_NO_ASM_VALUE_BARRIER. + +*/ + +#if defined(MLD_HAVE_INLINE_ASM) && !defined(MLD_CONFIG_NO_ASM_VALUE_BARRIER) +#define MLD_USE_ASM_VALUE_BARRIER +#endif + + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) +/* + * Declaration of global volatile that the global value barrier + * is loading from and masking with. + */ +#define mld_ct_opt_blocker_u64 MLD_NAMESPACE(ct_opt_blocker_u64) +extern volatile uint64_t mld_ct_opt_blocker_u64; + + +/* Helper functions for obtaining global masks of various sizes */ + +/* This contract is not proved but treated as an axiom. + * + * Its validity relies on the assumption that the global opt-blocker + * constant mld_ct_opt_blocker_u64 is not modified. + */ +static MLD_INLINE uint64_t mld_ct_get_optblocker_u64(void) +__contract__(ensures(return_value == 0)) { return mld_ct_opt_blocker_u64; } + +static MLD_INLINE int64_t mld_ct_get_optblocker_i64(void) +__contract__(ensures(return_value == 0)) { return (int64_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint32_t mld_ct_get_optblocker_u32(void) +__contract__(ensures(return_value == 0)) { return (uint32_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint8_t mld_ct_get_optblocker_u8(void) +__contract__(ensures(return_value == 0)) { return (uint8_t)mld_ct_get_optblocker_u64(); } + +/* Opt-blocker based implementation of value barriers */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_i64()); } + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u32()); } + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u8()); } + + +#else /* !MLD_USE_ASM_VALUE_BARRIER */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} +#endif /* MLD_USE_ASM_VALUE_BARRIER */ + +#ifdef CBMC +#pragma CPROVER check push +#pragma CPROVER check disable "conversion" +#endif + +/************************************************* + * Name: mld_cast_uint32_to_int32 + * + * Description: Cast uint32 value to int32 + * + * Returns: For uint32_t x, the unique y in int32_t + * so that x == y mod 2^32. + * + * Concretely: + * - x < 2^31: returns x + * - x >= 2^31: returns x - 2^31 + * + **************************************************/ +static MLD_ALWAYS_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x) +{ + /* + * PORTABILITY: This relies on uint32_t -> int32_t + * being implemented as the inverse of int32_t -> uint32_t, + * which is implementation-defined (C99 6.3.1.3 (3)) + * CBMC (correctly) fails to prove this conversion is OK, + * so we have to suppress that check here + */ + return (int32_t)x; +} + +#ifdef CBMC +#pragma CPROVER check pop +#endif + + +/************************************************* + * Name: mld_cast_int64_to_uint32 + * + * Description: Cast int64 value to uint32 as per C standard. + * + * Returns: For int64_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int64_to_uint32(int64_t x) +{ + return (uint32_t)(x & (int64_t)UINT32_MAX); +} + +/************************************************* + * Name: mld_cast_int32_to_uint32 + * + * Description: Cast int32 value to uint32 as per C standard. + * + * Returns: For int32_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int32_to_uint32(int32_t x) +{ + return mld_cast_int64_to_uint32((int64_t)x); +} + +/************************************************* + * Name: mld_ct_sel_int32 + * + * Description: Functionally equivalent to cond ? a : b, + * but implemented with guards against + * compiler-introduced branches. + * + * Arguments: int32_t a: First alternative + * int32_t b: Second alternative + * uint32_t cond: Condition variable. + * + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_sel_int32(int32_t a, int32_t b, uint32_t cond) +__contract__( + requires(cond == 0x0 || cond == 0xFFFFFFFF) + ensures(return_value == (cond ? a : b)) +) +{ + uint32_t au = mld_cast_int32_to_uint32(a); + uint32_t bu = mld_cast_int32_to_uint32(b); + uint32_t res = bu ^ (mld_value_barrier_u32(cond) & (au ^ bu)); + return mld_cast_uint32_to_int32(res); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u32 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_nonzero_u32(uint32_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFFFFFFFF))) +{ + int64_t tmp = mld_value_barrier_i64(-((int64_t)x)); + tmp >>= 32; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u8 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint8_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint8_t mld_ct_cmask_nonzero_u8(uint8_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFF))) +{ + uint32_t mask = mld_ct_cmask_nonzero_u32((uint32_t)x); + return (uint8_t)(mask & 0xFF); +} + +/************************************************* + * Name: mld_ct_cmask_neg_i32 + * + * Description: Return 0 if input is non-negative, and -1 otherwise. + * + * Arguments: int32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_neg_i32(int32_t x) +__contract__( + ensures(return_value == ((x < 0) ? 0xFFFFFFFF : 0)) +) +{ + int64_t tmp = mld_value_barrier_i64((int64_t)x); + tmp >>= 31; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_abs_i32 + * + * Description: Return -x if x<0, x otherwise + * + * Arguments: int32_t x: Input value + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_abs_i32(int32_t x) +__contract__( + requires(x >= -INT32_MAX) + ensures(return_value == ((x < 0) ? -x : x)) +) +{ + return mld_ct_sel_int32(-x, x, mld_ct_cmask_neg_i32(x)); +} + +/************************************************* + * Name: mld_ct_memcmp + * + * Description: Compare two arrays for equality in constant time. + * + * Arguments: const uint8_t *a: pointer to first byte array + * const uint8_t *b: pointer to second byte array + * size_t len: length of the byte arrays, upper-bounded + * to UINT16_MAX to control proof complexity + * only. + * + * Returns 0 if the byte arrays are equal, 0xFF otherwise. + **************************************************/ +static MLD_INLINE uint8_t mld_ct_memcmp(const uint8_t *a, const uint8_t *b, + const size_t len) +__contract__( + requires(len <= UINT16_MAX) + requires(memory_no_alias(a, len)) + requires(memory_no_alias(b, len)) + ensures((return_value == 0) || (return_value == 0xFF)) + ensures((return_value == 0) == forall(i, 0, len, (a[i] == b[i])))) +{ + uint8_t r = 0, s = 0; + unsigned i; + + for (i = 0; i < len; i++) + __loop__( + invariant(i <= len) + invariant((r == 0) == (forall(k, 0, i, (a[k] == b[k]))))) + { + r |= a[i] ^ b[i]; + /* s is useless, but prevents the loop from being aborted once r=0xff. */ + s ^= a[i] ^ b[i]; + } + + /* + * - Convert r into a mask; this may not be necessary, but is an additional + * safeguard + * towards leaking information about a and b. + * - XOR twice with s, separated by a value barrier, to prevent the compile + * from dropping the s computation in the loop. + */ + return (mld_value_barrier_u8(mld_ct_cmask_nonzero_u8(r) ^ s) ^ s); +} + +/************************************************* + * Name: mld_zeroize + * + * Description: Force-zeroize a buffer. + * @[FIPS204, Section 3.6.3] Destruction of intermediate + * values. + * + * Arguments: void *ptr: pointer to buffer to be zeroed + * size_t len: Amount of bytes to be zeroed + **************************************************/ +#if !defined(MLD_CONFIG_CUSTOM_ZEROIZE) +#if defined(MLD_SYS_WINDOWS) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) { SecureZeroMemory(ptr, len); } +#elif defined(MLD_HAVE_INLINE_ASM) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) +{ + memset(ptr, 0, len); + /* This follows OpenSSL and seems sufficient to prevent the compiler + * from optimizing away the memset. + * + * If there was a reliable way to detect availability of memset_s(), + * that would be preferred. */ + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +} +#else /* !MLD_SYS_WINDOWS && MLD_HAVE_INLINE_ASM */ +#error No plausibly-secure implementation of mld_zeroize available. Please provide your own using MLD_CONFIG_CUSTOM_ZEROIZE. +#endif /* !MLD_SYS_WINDOWS && !MLD_HAVE_INLINE_ASM */ +#endif /* !MLD_CONFIG_CUSTOM_ZEROIZE */ + +#endif /* !MLD_CT_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/debug.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/debug.c new file mode 100644 index 0000000000..a55d51e8b1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/debug.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* NOTE: You can remove this file unless you compile with MLDSA_DEBUG. */ + +#include "common.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#if defined(MLDSA_DEBUG) + +#include +#include +#include +#include "debug.h" + +#define MLD_DEBUG_ERROR_HEADER "[ERROR:%s:%04d] " + +void mld_debug_check_assert(const char *file, int line, const int val) +{ + if (val == 0) + { + fprintf(stderr, MLD_DEBUG_ERROR_HEADER "Assertion failed (value %d)\n", + file, line, val); + exit(1); + } +} + +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive) +{ + int err = 0; + unsigned i; + for (i = 0; i < len; i++) + { + int32_t val = ptr[i]; + if (!(val > lower_bound_exclusive && val < upper_bound_exclusive)) + { + fprintf(stderr, + MLD_DEBUG_ERROR_HEADER + "Bounds assertion failed: Index %u, value %d out of bounds " + "(%" PRId64 ",%" PRId64 ")\n", + file, line, i, (int)val, lower_bound_exclusive, + upper_bound_exclusive); + err = 1; + } + } + + if (err == 1) + { + exit(1); + } +} + +#else /* MLDSA_DEBUG */ + +MLD_EMPTY_CU(debug) + +#endif /* !MLDSA_DEBUG */ + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(debug) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_DEBUG_ERROR_HEADER diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/debug.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/debug.h new file mode 100644 index 0000000000..af187bb9de --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/debug.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_DEBUG_H +#define MLD_DEBUG_H +#include "common.h" + +#if defined(MLDSA_DEBUG) +#include + +/************************************************* + * Name: mld_assert + * + * Description: Check debug assertion + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - val: Value asserted to be non-zero + **************************************************/ +#define mld_debug_check_assert MLD_NAMESPACE(mldsa_debug_assert) +void mld_debug_check_assert(const char *file, int line, const int val); + +/************************************************* + * Name: mld_debug_check_bounds + * + * Description: Check whether values in an array of int32_t + * are within specified bounds. + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - ptr: Base of array to be checked + * - len: Number of int32_t in ptr + * - lower_bound_exclusive: Exclusive lower bound + * - upper_bound_exclusive: Exclusive upper bound + **************************************************/ +#define mld_debug_check_bounds MLD_NAMESPACE(mldsa_debug_check_bounds) +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive); + +/* Check assertion, calling exit() upon failure + * + * val: Value that's asserted to be non-zero + */ +#define mld_assert(val) mld_debug_check_assert(__FILE__, __LINE__, (val)) + +/* Check bounds in array of int32_t's + * ptr: Base of int32_t array; will be explicitly cast to int32_t*, + * so you may pass a byte-compatible type such as mld_poly or mld_polyvec. + * len: Number of int32_t in array + * value_lb: Inclusive lower value bound + * value_ub: Exclusive upper value bound */ +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + mld_debug_check_bounds(__FILE__, __LINE__, (const int32_t *)(ptr), (len), \ + ((int64_t)(value_lb)) - 1, (value_ub)) + +/* Check absolute bounds in array of int32_t's + * ptr: Base of array, expression of type int32_t* + * len: Number of int32_t in array + * value_abs_bd: Exclusive absolute upper bound */ +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + mld_assert_bound((ptr), (len), (-((int64_t)(value_abs_bd)) + 1), \ + (value_abs_bd)) + +/* Version of bounds assertions for 2-dimensional arrays */ +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + mld_assert_bound((ptr), ((len0) * (len1)), (value_lb), (value_ub)) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + mld_assert_abs_bound((ptr), ((len0) * (len1)), (value_abs_bd)) + +/* When running CBMC, convert debug assertions into proof obligations */ +#elif defined(CBMC) +#include "cbmc.h" + +#define mld_assert(val) cassert(val) + +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + cassert(array_bound(((int32_t *)(ptr)), 0, (len), (value_lb), (value_ub))) + +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + cassert(array_abs_bound(((int32_t *)(ptr)), 0, (len), (value_abs_bd))) + +/* Because of https://github.com/diffblue/cbmc/issues/8570, we can't + * just use a single flattened array_bound(...) here. */ +#define mld_assert_bound_2d(ptr, M, N, value_lb, value_ub) \ + cassert(forall(kN, 0, (M), \ + array_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_lb), (value_ub)))) + +#define mld_assert_abs_bound_2d(ptr, M, N, value_abs_bd) \ + cassert(forall(kN, 0, (M), \ + array_abs_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_abs_bd)))) + +#else /* !MLDSA_DEBUG && CBMC */ + +#define mld_assert(val) \ + do \ + { \ + } while (0) +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + do \ + { \ + } while (0) +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + do \ + { \ + } while (0) + +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + do \ + { \ + } while (0) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + do \ + { \ + } while (0) + + +#endif /* !MLDSA_DEBUG && !CBMC */ +#endif /* !MLD_DEBUG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/fips202.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/fips202.c new file mode 100644 index 0000000000..1112de061c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/fips202.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "../common.h" +#include "../ct.h" +#include "fips202.h" +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +/************************************************* + * Name: keccak_init + * + * Description: Initializes the Keccak state. + * + * Arguments: - uint64_t *s: pointer to Keccak state + **************************************************/ +static void keccak_init(uint64_t s[MLD_KECCAK_LANES]) +__contract__( + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + mld_memset(s, 0, sizeof(uint64_t) * MLD_KECCAK_LANES); +} + +/************************************************* + * Name: keccak_absorb + * + * Description: Absorb step of Keccak; incremental. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_absorb(uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r, + const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(pos <= r) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(in, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + ensures(return_value < r)) +{ + while (inlen >= r - pos) + __loop__( + assigns(pos, in, inlen, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + invariant(inlen <= loop_entry(inlen)) + invariant(pos <= r) + invariant(in == loop_entry(in) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600_xor_bytes(s, in, pos, r - pos); + inlen -= r - pos; + in += r - pos; + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: At this point, inlen < r, so the truncation to unsigned is safe. */ + mld_keccakf1600_xor_bytes(s, in, pos, (unsigned)inlen); + + /* Safety: At this point, inlen < r and pos <= r so the truncation to unsigned + * is safe. */ + return (unsigned)(pos + inlen); +} + +/************************************************* + * Name: keccak_finalize + * + * Description: Finalize absorb step. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - uint8_t p: domain separation byte + **************************************************/ +static void keccak_finalize(uint64_t s[MLD_KECCAK_LANES], unsigned int pos, + unsigned int r, uint8_t p) +__contract__( + requires(pos <= r && r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires((r / 8) >= 1) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + uint8_t b = 0x80; + mld_keccakf1600_xor_bytes(s, &p, pos, 1); + mld_keccakf1600_xor_bytes(s, &b, r - 1, 1); +} + +/************************************************* + * Name: keccak_squeeze + * + * Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes. + * Modifies the state. Can be called multiple times to keep + * squeezing, i.e., is incremental. + * + * Arguments: - uint8_t *out: pointer to output data + * - size_t outlen: number of bytes to be squeezed (written to out) + * - uint64_t *s: pointer to input/output Keccak state + * - unsigned int pos: number of bytes in current block already + *squeezed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_squeeze(uint8_t *out, size_t outlen, + uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r) +__contract__( + requires((r == SHAKE128_RATE && pos <= SHAKE128_RATE) || + (r == SHAKE256_RATE && pos <= SHAKE256_RATE) || + (r == SHA3_512_RATE && pos <= SHA3_512_RATE)) + requires(outlen <= 8 * r /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(out, outlen)) + ensures(return_value <= r)) +{ + unsigned int i; + size_t out_offset = 0; + + /* Reference: This code is re-factored from the reference implementation + * to facilitate proof with CBMC and to improve readability. + * + * Take a mutable copy of outlen to count down the number of bytes + * still to squeeze. The initial value of outlen is needed for the CBMC + * assigns() clauses. */ + size_t bytes_to_go = outlen; + + while (bytes_to_go > 0) + __loop__( + assigns(i, bytes_to_go, pos, out_offset, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES), memory_slice(out, outlen)) + invariant(bytes_to_go <= outlen) + invariant(out_offset == outlen - bytes_to_go) + invariant(pos <= r) + ) + { + if (pos == r) + { + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: If bytes_to_go < r - pos, truncation to unsigned is safe. */ + i = bytes_to_go < r - pos ? (unsigned)bytes_to_go : r - pos; + mld_keccakf1600_extract_bytes(s, out + out_offset, pos, i); + bytes_to_go -= i; + pos += i; + out_offset += i; + } + + return pos; +} + +void mld_shake128_init(mld_shake128ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE128_RATE, in, inlen); +} + +void mld_shake128_finalize(mld_shake128ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE128_RATE, 0x1F); + state->pos = SHAKE128_RATE; +} + +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE128_RATE); +} + +void mld_shake128_release(mld_shake128ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128ctx)); +} + +void mld_shake256_init(mld_shake256ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); +} + +void mld_shake256_finalize(mld_shake256ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); + state->pos = SHAKE256_RATE; +} + +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); +} + +void mld_shake256_release(mld_shake256ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256ctx)); +} + +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +{ + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, in, inlen); + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/fips202.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/fips202.h new file mode 100644 index 0000000000..9f0253cb88 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/fips202.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202_H +#define MLD_FIPS202_FIPS202_H + +#include +#include +#include "../cbmc.h" +#include "../common.h" + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 +#define SHA3_256_RATE 136 +#define SHA3_512_RATE 72 +#define MLD_KECCAK_LANES 25 +#define SHA3_256_HASHBYTES 32 +#define SHA3_512_HASHBYTES 64 + + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake128ctx; + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake256ctx; + +#define mld_shake128_init MLD_NAMESPACE(shake128_init) +/************************************************* + * Name: mld_shake128_init + * + * Description: Initializes state for use as SHAKE128 XOF + * + * Arguments: - mld_shake128ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake128_init(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos == 0) +); + +#define mld_shake128_absorb MLD_NAMESPACE(shake128_absorb) +/************************************************* + * Name: mld_shake128_absorb + * + * Description: Absorb step of the SHAKE128 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake128ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_finalize MLD_NAMESPACE(shake128_finalize) +/************************************************* + * Name: mld_shake128_finalize + * + * Description: Concludes the absorb phase of the SHAKE128 XOF. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_finalize(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_squeeze MLD_NAMESPACE(shake128_squeeze) +/************************************************* + * Name: mld_shake128_squeeze + * + * Description: Squeeze step of SHAKE128 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake128ctx *s: pointer to input/output state + **************************************************/ +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE128_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_release MLD_NAMESPACE(shake128_release) +/************************************************* + * Name: mld_shake128_release + * + * Description: Release and securely zero the SHAKE128 state. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_release(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) +); + +#define mld_shake256_init MLD_NAMESPACE(shake256_init) +/************************************************* + * Name: mld_shake256_init + * + * Description: Initializes state for use as SHAKE256 XOF + * + * Arguments: - mld_shake256ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake256_init(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos == 0) +); + +#define mld_shake256_absorb MLD_NAMESPACE(shake256_absorb) +/************************************************* + * Name: mld_shake256_absorb + * + * Description: Absorb step of the SHAKE256 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake256ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_finalize MLD_NAMESPACE(shake256_finalize) +/************************************************* + * Name: mld_shake256_finalize + * + * Description: Concludes the absorb phase of the SHAKE256 XOF. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_finalize(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_squeeze MLD_NAMESPACE(shake256_squeeze) +/************************************************* + * Name: mld_shake256_squeeze + * + * Description: Squeeze step of SHAKE256 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake256ctx *s: pointer to input/output state + **************************************************/ +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_release MLD_NAMESPACE(shake256_release) +/************************************************* + * Name: mld_shake256_release + * + * Description: Release and securely zero the SHAKE256 state. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_release(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) +); + +#define mld_shake256 MLD_NAMESPACE(shake256) +/************************************************* + * Name: mld_shake256 + * + * Description: SHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +); + +#endif /* !MLD_FIPS202_FIPS202_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/fips202x4.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/fips202x4.c new file mode 100644 index 0000000000..0fb5cd57c7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/fips202x4.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include "../common.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "../ct.h" +#include "fips202.h" +#include "fips202x4.h" +#include "keccakf1600.h" + +static void mld_keccak_absorb_once_x4(uint64_t *s, uint32_t r, + const uint8_t *in0, const uint8_t *in1, + const uint8_t *in2, const uint8_t *in3, + size_t inlen, uint8_t p) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))) +{ + while (inlen >= r) + __loop__( + assigns(inlen, in0, in1, in2, in3, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + invariant(inlen <= loop_entry(inlen)) + invariant(in0 == loop_entry(in0) + (loop_entry(inlen) - inlen)) + invariant(in1 == loop_entry(in1) + (loop_entry(inlen) - inlen)) + invariant(in2 == loop_entry(in2) + (loop_entry(inlen) - inlen)) + invariant(in3 == loop_entry(in3) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, r); + mld_keccakf1600x4_permute(s); + + in0 += r; + in1 += r; + in2 += r; + in3 += r; + inlen -= r; + } + + /* Safety: At this point, inlen < r, so the truncations to unsigned are safe + * below. */ + if (inlen > 0) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, (unsigned)inlen); + } + + if (inlen == r - 1) + { + p |= 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + } + else + { + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + p = 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, r - 1, 1); + } +} + +static void mld_keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1, + uint8_t *out2, uint8_t *out3, + size_t nblocks, uint64_t *s, uint32_t r) +__contract__( + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(out0, nblocks * r)) + requires(memory_no_alias(out1, nblocks * r)) + requires(memory_no_alias(out2, nblocks * r)) + requires(memory_no_alias(out3, nblocks * r)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(out0, nblocks * r)) + assigns(memory_slice(out1, nblocks * r)) + assigns(memory_slice(out2, nblocks * r)) + assigns(memory_slice(out3, nblocks * r))) +{ + while (nblocks > 0) + __loop__( + assigns(out0, out1, out2, out3, nblocks, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY), + memory_slice(out0, nblocks * r), + memory_slice(out1, nblocks * r), + memory_slice(out2, nblocks * r), + memory_slice(out3, nblocks * r)) + invariant(nblocks <= loop_entry(nblocks) && + out0 == loop_entry(out0) + r * (loop_entry(nblocks) - nblocks) && + out1 == loop_entry(out1) + r * (loop_entry(nblocks) - nblocks) && + out2 == loop_entry(out2) + r * (loop_entry(nblocks) - nblocks) && + out3 == loop_entry(out3) + r * (loop_entry(nblocks) - nblocks))) + { + mld_keccakf1600x4_permute(s); + mld_keccakf1600x4_extract_bytes(s, out0, out1, out2, out3, 0, r); + + out0 += r; + out1 += r; + out2 += r; + out3 += r; + nblocks--; + } +} + +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake128x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE128_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE128_RATE); +} + +void mld_shake128x4_init(mld_shake128x4ctx *state) { (void)state; } +void mld_shake128x4_release(mld_shake128x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128x4ctx)); +} + + +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake256x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE256_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE256_RATE); +} + +void mld_shake256x4_init(mld_shake256x4ctx *state) { (void)state; } +void mld_shake256x4_release(mld_shake256x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256x4ctx)); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/fips202x4.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/fips202x4.h new file mode 100644 index 0000000000..e7987207a6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/fips202x4.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202X4_H +#define MLD_FIPS202_FIPS202X4_H + +#include +#include + +#include "../cbmc.h" +#include "../common.h" + +#include "fips202.h" +#include "keccakf1600.h" + +/* Context for non-incremental API */ +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake128x4ctx; + +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake256x4ctx; + +#define mld_shake128x4_absorb_once MLD_NAMESPACE(shake128x4_absorb_once) +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_squeezeblocks MLD_NAMESPACE(shake128x4_squeezeblocks) +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE128_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE128_RATE), + memory_slice(out1, nblocks * SHAKE128_RATE), + memory_slice(out2, nblocks * SHAKE128_RATE), + memory_slice(out3, nblocks * SHAKE128_RATE), + memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_init MLD_NAMESPACE(shake128x4_init) +void mld_shake128x4_init(mld_shake128x4ctx *state); + +#define mld_shake128x4_release MLD_NAMESPACE(shake128x4_release) +void mld_shake128x4_release(mld_shake128x4ctx *state); + + +#define mld_shake256x4_absorb_once MLD_NAMESPACE(shake256x4_absorb_once) +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_squeezeblocks MLD_NAMESPACE(shake256x4_squeezeblocks) +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE256_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE256_RATE), + memory_slice(out1, nblocks * SHAKE256_RATE), + memory_slice(out2, nblocks * SHAKE256_RATE), + memory_slice(out3, nblocks * SHAKE256_RATE), + memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_init MLD_NAMESPACE(shake256x4_init) +void mld_shake256x4_init(mld_shake256x4ctx *state); + +#define mld_shake256x4_release MLD_NAMESPACE(shake256x4_release) +void mld_shake256x4_release(mld_shake256x4ctx *state); + + +#endif /* !MLD_FIPS202_FIPS202X4_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/keccakf1600.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/keccakf1600.c new file mode 100644 index 0000000000..e59120c07c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/keccakf1600.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#define MLD_KECCAK_NROUNDS 24 +#define MLD_KECCAK_ROL(a, offset) ((a << offset) ^ (a >> (64 - offset))) + +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = state_ptr[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = (state[(offset + i) >> 3] >> (8 * ((offset + i) & 0x07))) & 0xFF; + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state_ptr[i] ^= data[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state[(offset + i) >> 3] ^= (uint64_t)data[i] + << (8 * ((offset + i) & 0x07)); + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X4_NATIVE) + if (mld_keccak_f1600_x4_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 0); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 1); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 2); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 3); +} + +static const uint64_t mld_KeccakF_RoundConstants[MLD_KECCAK_NROUNDS] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +static void mld_keccakf1600_permute_c(uint64_t *state) +{ + unsigned round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + uint64_t BCa, BCe, BCi, BCo, BCu; + uint64_t Da, De, Di, Do, Du; + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + /* copyFromState(A, state) */ + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < MLD_KECCAK_NROUNDS; round += 2) + __loop__(invariant(round <= MLD_KECCAK_NROUNDS && round % 2 == 0)) + { + /* prepareTheta */ + BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; + BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + /* thetaRhoPiChiIotaPrepareTheta(round, A, E) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = MLD_KECCAK_ROL(Age, 44); + Aki ^= Di; + BCi = MLD_KECCAK_ROL(Aki, 43); + Amo ^= Do; + BCo = MLD_KECCAK_ROL(Amo, 21); + Asu ^= Du; + BCu = MLD_KECCAK_ROL(Asu, 14); + Eba = BCa ^ ((~BCe) & BCi); + Eba ^= (uint64_t)mld_KeccakF_RoundConstants[round]; + Ebe = BCe ^ ((~BCi) & BCo); + Ebi = BCi ^ ((~BCo) & BCu); + Ebo = BCo ^ ((~BCu) & BCa); + Ebu = BCu ^ ((~BCa) & BCe); + + Abo ^= Do; + BCa = MLD_KECCAK_ROL(Abo, 28); + Agu ^= Du; + BCe = MLD_KECCAK_ROL(Agu, 20); + Aka ^= Da; + BCi = MLD_KECCAK_ROL(Aka, 3); + Ame ^= De; + BCo = MLD_KECCAK_ROL(Ame, 45); + Asi ^= Di; + BCu = MLD_KECCAK_ROL(Asi, 61); + Ega = BCa ^ ((~BCe) & BCi); + Ege = BCe ^ ((~BCi) & BCo); + Egi = BCi ^ ((~BCo) & BCu); + Ego = BCo ^ ((~BCu) & BCa); + Egu = BCu ^ ((~BCa) & BCe); + + Abe ^= De; + BCa = MLD_KECCAK_ROL(Abe, 1); + Agi ^= Di; + BCe = MLD_KECCAK_ROL(Agi, 6); + Ako ^= Do; + BCi = MLD_KECCAK_ROL(Ako, 25); + Amu ^= Du; + BCo = MLD_KECCAK_ROL(Amu, 8); + Asa ^= Da; + BCu = MLD_KECCAK_ROL(Asa, 18); + Eka = BCa ^ ((~BCe) & BCi); + Eke = BCe ^ ((~BCi) & BCo); + Eki = BCi ^ ((~BCo) & BCu); + Eko = BCo ^ ((~BCu) & BCa); + Eku = BCu ^ ((~BCa) & BCe); + + Abu ^= Du; + BCa = MLD_KECCAK_ROL(Abu, 27); + Aga ^= Da; + BCe = MLD_KECCAK_ROL(Aga, 36); + Ake ^= De; + BCi = MLD_KECCAK_ROL(Ake, 10); + Ami ^= Di; + BCo = MLD_KECCAK_ROL(Ami, 15); + Aso ^= Do; + BCu = MLD_KECCAK_ROL(Aso, 56); + Ema = BCa ^ ((~BCe) & BCi); + Eme = BCe ^ ((~BCi) & BCo); + Emi = BCi ^ ((~BCo) & BCu); + Emo = BCo ^ ((~BCu) & BCa); + Emu = BCu ^ ((~BCa) & BCe); + + Abi ^= Di; + BCa = MLD_KECCAK_ROL(Abi, 62); + Ago ^= Do; + BCe = MLD_KECCAK_ROL(Ago, 55); + Aku ^= Du; + BCi = MLD_KECCAK_ROL(Aku, 39); + Ama ^= Da; + BCo = MLD_KECCAK_ROL(Ama, 41); + Ase ^= De; + BCu = MLD_KECCAK_ROL(Ase, 2); + Esa = BCa ^ ((~BCe) & BCi); + Ese = BCe ^ ((~BCi) & BCo); + Esi = BCi ^ ((~BCo) & BCu); + Eso = BCo ^ ((~BCu) & BCa); + Esu = BCu ^ ((~BCa) & BCe); + + /* prepareTheta */ + BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + /* thetaRhoPiChiIotaPrepareTheta(round+1, E, A) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = MLD_KECCAK_ROL(Ege, 44); + Eki ^= Di; + BCi = MLD_KECCAK_ROL(Eki, 43); + Emo ^= Do; + BCo = MLD_KECCAK_ROL(Emo, 21); + Esu ^= Du; + BCu = MLD_KECCAK_ROL(Esu, 14); + Aba = BCa ^ ((~BCe) & BCi); + Aba ^= (uint64_t)mld_KeccakF_RoundConstants[round + 1]; + Abe = BCe ^ ((~BCi) & BCo); + Abi = BCi ^ ((~BCo) & BCu); + Abo = BCo ^ ((~BCu) & BCa); + Abu = BCu ^ ((~BCa) & BCe); + + Ebo ^= Do; + BCa = MLD_KECCAK_ROL(Ebo, 28); + Egu ^= Du; + BCe = MLD_KECCAK_ROL(Egu, 20); + Eka ^= Da; + BCi = MLD_KECCAK_ROL(Eka, 3); + Eme ^= De; + BCo = MLD_KECCAK_ROL(Eme, 45); + Esi ^= Di; + BCu = MLD_KECCAK_ROL(Esi, 61); + Aga = BCa ^ ((~BCe) & BCi); + Age = BCe ^ ((~BCi) & BCo); + Agi = BCi ^ ((~BCo) & BCu); + Ago = BCo ^ ((~BCu) & BCa); + Agu = BCu ^ ((~BCa) & BCe); + + Ebe ^= De; + BCa = MLD_KECCAK_ROL(Ebe, 1); + Egi ^= Di; + BCe = MLD_KECCAK_ROL(Egi, 6); + Eko ^= Do; + BCi = MLD_KECCAK_ROL(Eko, 25); + Emu ^= Du; + BCo = MLD_KECCAK_ROL(Emu, 8); + Esa ^= Da; + BCu = MLD_KECCAK_ROL(Esa, 18); + Aka = BCa ^ ((~BCe) & BCi); + Ake = BCe ^ ((~BCi) & BCo); + Aki = BCi ^ ((~BCo) & BCu); + Ako = BCo ^ ((~BCu) & BCa); + Aku = BCu ^ ((~BCa) & BCe); + + Ebu ^= Du; + BCa = MLD_KECCAK_ROL(Ebu, 27); + Ega ^= Da; + BCe = MLD_KECCAK_ROL(Ega, 36); + Eke ^= De; + BCi = MLD_KECCAK_ROL(Eke, 10); + Emi ^= Di; + BCo = MLD_KECCAK_ROL(Emi, 15); + Eso ^= Do; + BCu = MLD_KECCAK_ROL(Eso, 56); + Ama = BCa ^ ((~BCe) & BCi); + Ame = BCe ^ ((~BCi) & BCo); + Ami = BCi ^ ((~BCo) & BCu); + Amo = BCo ^ ((~BCu) & BCa); + Amu = BCu ^ ((~BCa) & BCe); + + Ebi ^= Di; + BCa = MLD_KECCAK_ROL(Ebi, 62); + Ego ^= Do; + BCe = MLD_KECCAK_ROL(Ego, 55); + Eku ^= Du; + BCi = MLD_KECCAK_ROL(Eku, 39); + Ema ^= Da; + BCo = MLD_KECCAK_ROL(Ema, 41); + Ese ^= De; + BCu = MLD_KECCAK_ROL(Ese, 2); + Asa = BCa ^ ((~BCe) & BCi); + Ase = BCe ^ ((~BCi) & BCo); + Asi = BCi ^ ((~BCo) & BCu); + Aso = BCo ^ ((~BCu) & BCa); + Asu = BCu ^ ((~BCa) & BCe); + } + + /* copyToState(state, A) */ + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} + +void mld_keccakf1600_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X1_NATIVE) + if (mld_keccak_f1600_x1_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X1_NATIVE */ + mld_keccakf1600_permute_c(state); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(keccakf1600) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_KECCAK_NROUNDS +#undef MLD_KECCAK_ROL diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/keccakf1600.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/keccakf1600.h new file mode 100644 index 0000000000..e56adc1561 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/keccakf1600.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_KECCAKF1600_H +#define MLD_FIPS202_KECCAKF1600_H +#include +#include "../cbmc.h" +#include "../common.h" +#include "fips202.h" + +#define MLD_KECCAK_LANES 25 +#define MLD_KECCAK_WAY 4 + +/* + * WARNING: + * The contents of this structure, including the placement + * and interleaving of Keccak lanes, are IMPLEMENTATION-DEFINED. + * The struct is only exposed here to allow its construction on the stack. + */ + +#define mld_keccakf1600_extract_bytes MLD_NAMESPACE(keccakf1600_extract_bytes) +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(data, length)) +); + +#define mld_keccakf1600_xor_bytes MLD_NAMESPACE(keccakf1600_xor_bytes) +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#define mld_keccakf1600x4_extract_bytes \ + MLD_NAMESPACE(keccakf1600x4_extract_bytes) +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + requires(memory_no_alias(data1, length)) + requires(memory_no_alias(data2, length)) + requires(memory_no_alias(data3, length)) + assigns(memory_slice(data0, length)) + assigns(memory_slice(data1, length)) + assigns(memory_slice(data2, length)) + assigns(memory_slice(data3, length)) +); + +#define mld_keccakf1600x4_xor_bytes MLD_NAMESPACE(keccakf1600x4_xor_bytes) +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + /* Case 1: all input buffers are distinct; Case 2: All input buffers are the same */ + requires((data0 == data1 && + data0 == data2 && + data0 == data3) || + (memory_no_alias(data1, length) && + memory_no_alias(data2, length) && + memory_no_alias(data3, length))) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600x4_permute MLD_NAMESPACE(keccakf1600x4_permute) +void mld_keccakf1600x4_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600_permute MLD_NAMESPACE(keccakf1600_permute) +void mld_keccakf1600_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#endif /* !MLD_FIPS202_KECCAKF1600_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/auto.h new file mode 100644 index 0000000000..4375cc1976 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/auto.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [HYBRID] + * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64 + * Becker, Kannwischer + * https://eprint.iacr.org/2022/1243 + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +#define MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* Default FIPS202 assembly profile for AArch64 systems */ + +/* + * Default logic to decide which implementation to use. + * + */ + +/* + * Keccak-f1600 + * + * - On Arm-based Apple CPUs, we pick a pure Neon implementation. + * - Otherwise, unless MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, + * we use lazy-rotation scalar assembly from @[HYBRID]. + * - Otherwise, if MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, we + * fall back to the standard C implementation. + */ +#if defined(__ARM_FEATURE_SHA3) && defined(__APPLE__) +#include "x1_v84a.h" +#elif !defined(MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER) +#include "x1_scalar.h" +#endif + +/* + * Keccak-f1600x2/x4 + * + * The optimal implementation is highly CPU-specific; see @[HYBRID]. + * + * For now, if v8.4-A is not implemented, we fall back to Keccak-f1600. + * If v8.4-A is implemented and we are on an Apple CPU, we use a plain + * Neon-based implementation. + * If v8.4-A is implemented and we are not on an Apple CPU, we use a + * scalar/Neon/Neon hybrid. + * The reason for this distinction is that Apple CPUs appear to implement + * the SHA3 instructions on all SIMD units, while Arm CPUs prior to Cortex-X4 + * don't, and ordinary Neon instructions are still needed. + */ +#if defined(__ARM_FEATURE_SHA3) +/* + * For Apple-M cores, we use a plain implementation leveraging SHA3 + * instructions only. + */ +#if defined(__APPLE__) +#include "x2_v84a.h" +#else +#include "x4_v8a_v84a_scalar.h" +#endif + +#else /* __ARM_FEATURE_SHA3 */ + +#include "x4_v8a_scalar.h" + +#endif /* !__ARM_FEATURE_SHA3 */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h new file mode 100644 index 0000000000..20f6168038 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#define MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H + +#include +#include "../../../../cbmc.h" +#include "../../../../common.h" + + +#define mld_keccakf1600_round_constants \ + MLD_NAMESPACE(keccakf1600_round_constants) +extern const uint64_t mld_keccakf1600_round_constants[]; + +#define mld_keccak_f1600_x1_scalar_asm MLD_NAMESPACE(keccak_f1600_x1_scalar_asm) +void mld_keccak_f1600_x1_scalar_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x1_v84a_asm MLD_NAMESPACE(keccak_f1600_x1_v84a_asm) +void mld_keccak_f1600_x1_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x2_v84a_asm MLD_NAMESPACE(keccak_f1600_x2_v84a_asm) +void mld_keccak_f1600_x2_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 2)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 2)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c new file mode 100644 index 0000000000..05e9cbfeec --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../../common.h" + +#if (defined(MLD_FIPS202_AARCH64_NEED_X1_SCALAR) || \ + defined(MLD_FIPS202_AARCH64_NEED_X1_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X2_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID)) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "fips202_native_aarch64.h" + +MLD_ALIGN const uint64_t mld_keccakf1600_round_constants[] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, +}; + +#else /* (MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_aarch64_round_constants) + +#endif /* !((MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/x1_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/x1_scalar.h new file mode 100644 index 0000000000..681b991371 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/x1_scalar.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_SCALAR + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + mld_keccak_f1600_x1_scalar_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/x1_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/x1_v84a.h new file mode 100644 index 0000000000..d15c8c26f3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/x1_v84a.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x1_v84a_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/x2_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/x2_v84a.h new file mode 100644 index 0000000000..16c22fa1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/x2_v84a.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X2_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" + + +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x2_v84a_asm(state + 0 * 25, mld_keccakf1600_round_constants); + mld_keccak_f1600_x2_v84a_asm(state + 2 * 25, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h new file mode 100644 index 0000000000..0f7f8fe499 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(state, + mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h new file mode 100644 index 0000000000..3da883b762 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm( + state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/api.h new file mode 100644 index 0000000000..4625c9a1ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/api.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_API_H +#define MLD_FIPS202_NATIVE_API_H +/* + * FIPS-202 native interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + */ + +#include +#include "../../cbmc.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* + * This is the C<->native interface allowing for the drop-in + * of custom Keccak-F1600 implementations. + * + * A _backend_ is a specific implementation of parts of this interface. + * + * You can replace 1-fold or 4-fold batched Keccak-F1600. + * To enable, set MLD_USE_FIPS202_X1_NATIVE or MLD_USE_FIPS202_X4_NATIVE + * in your backend, and define the inline wrappers mld_keccak_f1600_x1_native() + * and/or mld_keccak_f1600_x4_native(), respectively, to forward to your + * implementation. + */ + +#if defined(MLD_USE_FIPS202_X1_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 1)) +); +#endif /* MLD_USE_FIPS202_X1_NATIVE */ +#if defined(MLD_USE_FIPS202_X4_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 4)) +); +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + +#endif /* !MLD_FIPS202_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/auto.h new file mode 100644 index 0000000000..0a09c733c8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/auto.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AUTO_H +#define MLD_FIPS202_NATIVE_AUTO_H + +/* + * Default FIPS202 backend + */ +#include "../../sys.h" + +#if defined(MLD_SYS_AARCH64) +#include "aarch64/auto.h" +#endif + +#if defined(MLD_SYS_X86_64) && defined(MLD_SYS_X86_64_AVX2) +#include "x86_64/xkcp.h" +#endif + +#endif /* !MLD_FIPS202_NATIVE_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c new file mode 100644 index 0000000000..4eaad2fd66 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* +Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, +Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby +denoted as "the implementer". + +For more information, feedback or questions, please refer to our websites: +http://keccak.noekeon.org/ +http://keyak.noekeon.org/ +http://ketje.noekeon.org/ + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +/* + * Changes for mlkem-native/mldsa-native: + * - copyFromState and copyToState operate on uninterleaved + * Keccak states in memory. + */ + +#include "../../../../common.h" +#if defined(MLD_FIPS202_X86_64_XKCP) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include + +#include "KeccakP_1600_times4_SIMD256.h" + +#ifndef MLD_SYS_LITTLE_ENDIAN +#error Expecting a little-endian platform +#endif + +#define ANDnu256(a, b) _mm256_andnot_si256(a, b) +#define CONST256(a) _mm256_load_si256((const __m256i *)&(a)) +#define CONST256_64(a) (__m256i) _mm256_broadcast_sd((const double *)(&a)) +#define ROL64in256(d, a, o) \ + d = _mm256_or_si256(_mm256_slli_epi64(a, o), _mm256_srli_epi64(a, 64 - (o))) +#define ROL64in256_8(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho8)) +#define ROL64in256_56(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho56)) +static const uint64_t rho8[4] = {0x0605040302010007, 0x0E0D0C0B0A09080F, + 0x1615141312111017, 0x1E1D1C1B1A19181F}; +static const uint64_t rho56[4] = {0x0007060504030201, 0x080F0E0D0C0B0A09, + 0x1017161514131211, 0x181F1E1D1C1B1A19}; +#define STORE256(a, b) _mm256_store_si256((__m256i *)&(a), b) +#define XOR256(a, b) _mm256_xor_si256(a, b) +#define XOReq256(a, b) a = _mm256_xor_si256(a, b) + +#define SnP_laneLengthInBytes 8 + +#define declareABCDE \ + __m256i Aba, Abe, Abi, Abo, Abu; \ + __m256i Aga, Age, Agi, Ago, Agu; \ + __m256i Aka, Ake, Aki, Ako, Aku; \ + __m256i Ama, Ame, Ami, Amo, Amu; \ + __m256i Asa, Ase, Asi, Aso, Asu; \ + __m256i Bba, Bbe, Bbi, Bbo, Bbu; \ + __m256i Bga, Bge, Bgi, Bgo, Bgu; \ + __m256i Bka, Bke, Bki, Bko, Bku; \ + __m256i Bma, Bme, Bmi, Bmo, Bmu; \ + __m256i Bsa, Bse, Bsi, Bso, Bsu; \ + __m256i Ca, Ce, Ci, Co, Cu; \ + __m256i Ca1, Ce1, Ci1, Co1, Cu1; \ + __m256i Da, De, Di, Do, Du; \ + __m256i Eba, Ebe, Ebi, Ebo, Ebu; \ + __m256i Ega, Ege, Egi, Ego, Egu; \ + __m256i Eka, Eke, Eki, Eko, Eku; \ + __m256i Ema, Eme, Emi, Emo, Emu; \ + __m256i Esa, Ese, Esi, Eso, Esu; + +#define prepareTheta \ + Ca = XOR256(Aba, XOR256(Aga, XOR256(Aka, XOR256(Ama, Asa)))); \ + Ce = XOR256(Abe, XOR256(Age, XOR256(Ake, XOR256(Ame, Ase)))); \ + Ci = XOR256(Abi, XOR256(Agi, XOR256(Aki, XOR256(Ami, Asi)))); \ + Co = XOR256(Abo, XOR256(Ago, XOR256(Ako, XOR256(Amo, Aso)))); \ + Cu = XOR256(Abu, XOR256(Agu, XOR256(Aku, XOR256(Amu, Asu)))); + +/* + * --- Theta Rho Pi Chi Iota Prepare-theta + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + Ca = E##ba; \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + Ce = E##be; \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + Ci = E##bi; \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + Co = E##bo; \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + Cu = E##bu; \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(Ca, E##ga); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(Ce, E##ge); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + XOReq256(Ci, E##gi); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + XOReq256(Co, E##go); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + XOReq256(Cu, E##gu); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(Ca, E##ka); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(Ce, E##ke); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + XOReq256(Ci, E##ki); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + XOReq256(Co, E##ko); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + XOReq256(Cu, E##ku); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(Ca, E##ma); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(Ce, E##me); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + XOReq256(Ci, E##mi); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + XOReq256(Co, E##mo); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + XOReq256(Cu, E##mu); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(Ca, E##sa); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(Ce, E##se); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + XOReq256(Ci, E##si); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + XOReq256(Co, E##so); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); \ + XOReq256(Cu, E##su); + + +/* + * --- Theta Rho Pi Chi Iota + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIota(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); + + +static MLD_ALIGN const uint64_t keccakf1600RoundConstants[24] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +#include + +#define copyFromState(X, state) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m256i _idx = \ + _mm256_set_epi64x((long long)&state64[75], (long long)&state64[50], \ + (long long)&state64[25], (long long)&state64[0]); \ + X##ba = _mm256_i64gather_epi64((long long *)(0 * 8), _idx, 1); \ + X##be = _mm256_i64gather_epi64((long long *)(1 * 8), _idx, 1); \ + X##bi = _mm256_i64gather_epi64((long long *)(2 * 8), _idx, 1); \ + X##bo = _mm256_i64gather_epi64((long long *)(3 * 8), _idx, 1); \ + X##bu = _mm256_i64gather_epi64((long long *)(4 * 8), _idx, 1); \ + X##ga = _mm256_i64gather_epi64((long long *)(5 * 8), _idx, 1); \ + X##ge = _mm256_i64gather_epi64((long long *)(6 * 8), _idx, 1); \ + X##gi = _mm256_i64gather_epi64((long long *)(7 * 8), _idx, 1); \ + X##go = _mm256_i64gather_epi64((long long *)(8 * 8), _idx, 1); \ + X##gu = _mm256_i64gather_epi64((long long *)(9 * 8), _idx, 1); \ + X##ka = _mm256_i64gather_epi64((long long *)(10 * 8), _idx, 1); \ + X##ke = _mm256_i64gather_epi64((long long *)(11 * 8), _idx, 1); \ + X##ki = _mm256_i64gather_epi64((long long *)(12 * 8), _idx, 1); \ + X##ko = _mm256_i64gather_epi64((long long *)(13 * 8), _idx, 1); \ + X##ku = _mm256_i64gather_epi64((long long *)(14 * 8), _idx, 1); \ + X##ma = _mm256_i64gather_epi64((long long *)(15 * 8), _idx, 1); \ + X##me = _mm256_i64gather_epi64((long long *)(16 * 8), _idx, 1); \ + X##mi = _mm256_i64gather_epi64((long long *)(17 * 8), _idx, 1); \ + X##mo = _mm256_i64gather_epi64((long long *)(18 * 8), _idx, 1); \ + X##mu = _mm256_i64gather_epi64((long long *)(19 * 8), _idx, 1); \ + X##sa = _mm256_i64gather_epi64((long long *)(20 * 8), _idx, 1); \ + X##se = _mm256_i64gather_epi64((long long *)(21 * 8), _idx, 1); \ + X##si = _mm256_i64gather_epi64((long long *)(22 * 8), _idx, 1); \ + X##so = _mm256_i64gather_epi64((long long *)(23 * 8), _idx, 1); \ + X##su = _mm256_i64gather_epi64((long long *)(24 * 8), _idx, 1); \ + } while (0); + +#define SCATTER_STORE256(state, idx, v) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m128d t = _mm_castsi128_pd(_mm256_castsi256_si128((v))); \ + _mm_storel_pd((double *)&state64[0 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[25 + (idx)], t); \ + t = _mm_castsi128_pd(_mm256_extracti128_si256((v), 1)); \ + _mm_storel_pd((double *)&state64[50 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[75 + (idx)], t); \ + } while (0) + +#define copyToState(state, X) \ + SCATTER_STORE256(state, 0, X##ba); \ + SCATTER_STORE256(state, 1, X##be); \ + SCATTER_STORE256(state, 2, X##bi); \ + SCATTER_STORE256(state, 3, X##bo); \ + SCATTER_STORE256(state, 4, X##bu); \ + SCATTER_STORE256(state, 5, X##ga); \ + SCATTER_STORE256(state, 6, X##ge); \ + SCATTER_STORE256(state, 7, X##gi); \ + SCATTER_STORE256(state, 8, X##go); \ + SCATTER_STORE256(state, 9, X##gu); \ + SCATTER_STORE256(state, 10, X##ka); \ + SCATTER_STORE256(state, 11, X##ke); \ + SCATTER_STORE256(state, 12, X##ki); \ + SCATTER_STORE256(state, 13, X##ko); \ + SCATTER_STORE256(state, 14, X##ku); \ + SCATTER_STORE256(state, 15, X##ma); \ + SCATTER_STORE256(state, 16, X##me); \ + SCATTER_STORE256(state, 17, X##mi); \ + SCATTER_STORE256(state, 18, X##mo); \ + SCATTER_STORE256(state, 19, X##mu); \ + SCATTER_STORE256(state, 20, X##sa); \ + SCATTER_STORE256(state, 21, X##se); \ + SCATTER_STORE256(state, 22, X##si); \ + SCATTER_STORE256(state, 23, X##so); \ + SCATTER_STORE256(state, 24, X##su); + +#define copyStateVariables(X, Y) \ + X##ba = Y##ba; \ + X##be = Y##be; \ + X##bi = Y##bi; \ + X##bo = Y##bo; \ + X##bu = Y##bu; \ + X##ga = Y##ga; \ + X##ge = Y##ge; \ + X##gi = Y##gi; \ + X##go = Y##go; \ + X##gu = Y##gu; \ + X##ka = Y##ka; \ + X##ke = Y##ke; \ + X##ki = Y##ki; \ + X##ko = Y##ko; \ + X##ku = Y##ku; \ + X##ma = Y##ma; \ + X##me = Y##me; \ + X##mi = Y##mi; \ + X##mo = Y##mo; \ + X##mu = Y##mu; \ + X##sa = Y##sa; \ + X##se = Y##se; \ + X##si = Y##si; \ + X##so = Y##so; \ + X##su = Y##su; + +/* clang-format off */ +#define rounds24 \ + prepareTheta \ + thetaRhoPiChiIotaPrepareTheta( 0, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 1, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 2, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 3, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 4, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 5, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 6, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 7, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 8, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 9, E, A) \ + thetaRhoPiChiIotaPrepareTheta(10, A, E) \ + thetaRhoPiChiIotaPrepareTheta(11, E, A) \ + thetaRhoPiChiIotaPrepareTheta(12, A, E) \ + thetaRhoPiChiIotaPrepareTheta(13, E, A) \ + thetaRhoPiChiIotaPrepareTheta(14, A, E) \ + thetaRhoPiChiIotaPrepareTheta(15, E, A) \ + thetaRhoPiChiIotaPrepareTheta(16, A, E) \ + thetaRhoPiChiIotaPrepareTheta(17, E, A) \ + thetaRhoPiChiIotaPrepareTheta(18, A, E) \ + thetaRhoPiChiIotaPrepareTheta(19, E, A) \ + thetaRhoPiChiIotaPrepareTheta(20, A, E) \ + thetaRhoPiChiIotaPrepareTheta(21, E, A) \ + thetaRhoPiChiIotaPrepareTheta(22, A, E) \ + thetaRhoPiChiIota(23, E, A) +/* clang-format on */ + +void mld_keccakf1600x4_permute24(void *states) +{ + __m256i *statesAsLanes = (__m256i *)states; + declareABCDE copyFromState(A, statesAsLanes) + rounds24 copyToState(statesAsLanes, A) +} + +#else /* MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_avx2_keccakx4) + +#endif /* !(MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef ANDnu256 +#undef CONST256 +#undef CONST256_64 +#undef ROL64in256 +#undef ROL64in256_8 +#undef ROL64in256_56 +#undef STORE256 +#undef XOR256 +#undef XOReq256 +#undef SnP_laneLengthInBytes +#undef declareABCDE +#undef prepareTheta +#undef thetaRhoPiChiIotaPrepareTheta +#undef thetaRhoPiChiIota +#undef copyFromState +#undef SCATTER_STORE256 +#undef copyToState +#undef copyStateVariables +#undef rounds24 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h new file mode 100644 index 0000000000..3499d38e2c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H +#define MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H + +#include "../../../../common.h" + +#define mld_keccakf1600x4_permute24 \ + MLD_NAMESPACE(KeccakP1600times4_PermuteAll_24rounds) +void mld_keccakf1600x4_permute24(void *states); + +#endif /* !MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/x86_64/xkcp.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/x86_64/xkcp.h new file mode 100644 index 0000000000..c03642d7e0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/fips202/native/x86_64/xkcp.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_XKCP_H +#define MLD_FIPS202_NATIVE_X86_64_XKCP_H + +#include "../../../common.h" + +#define MLD_FIPS202_X86_64_XKCP + +#if !defined(__ASSEMBLER__) +#include +#include "../api.h" +#include "src/KeccakP_1600_times4_SIMD256.h" + +#define MLD_USE_FIPS202_X4_NATIVE +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_keccakf1600x4_permute24(state); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_X86_64_XKCP_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/meta.h new file mode 100644 index 0000000000..c6f6ad47b0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/meta.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_META_H +#define MLD_NATIVE_AARCH64_META_H + +/* Set of primitives that this backend replaces */ +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_AARCH64 + + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/arith_native_aarch64.h" + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + mld_ntt_asm(data, mld_aarch64_ntt_zetas_layer123456, + mld_aarch64_ntt_zetas_layer78); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + mld_intt_asm(data, mld_aarch64_intt_zetas_layer78, + mld_aarch64_intt_zetas_layer123456); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + if (len != MLDSA_N || + buflen % 24 != 0) /* NEON support is mandatory for AArch64 */ + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N, hence, this cast is safe. */ + return (int)mld_rej_uniform_asm(r, buf, buflen, mld_rej_uniform_table); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_32_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_88_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + mld_poly_caddq_asm(a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_32_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_88_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + return mld_poly_chknorm_asm(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_17_asm(r, buf, mld_polyz_unpack_17_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_19_asm(r, buf, mld_polyz_unpack_19_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t out[MLDSA_N], const int32_t in0[MLDSA_N], + const int32_t in1[MLDSA_N]) +{ + mld_poly_pointwise_montgomery_asm(out, in0, in1); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l4_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l5_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l7_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ +#endif /* !MLD_NATIVE_AARCH64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/src/aarch64_zetas.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/src/aarch64_zetas.c new file mode 100644 index 0000000000..9ab7b9a68c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/src/aarch64_zetas.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Table of zeta values used in the AArch64 forward NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer123456[] = { + -3572223, -915382907, 3765607, 964937599, 3761513, 963888510, + -3201494, -820383522, -2883726, -738955404, -3145678, -806080660, + -3201430, -820367122, 0, 0, -601683, -154181397, + -3370349, -863652652, -4063053, -1041158200, 3602218, 923069133, + 3182878, 815613168, 2740543, 702264730, -3586446, -919027554, + 0, 0, 3542485, 907762539, 2663378, 682491182, + -1674615, -429120452, -3110818, -797147778, 2101410, 538486762, + 3704823, 949361686, 1159875, 297218217, 0, 0, + 2682288, 687336873, -3524442, -903139016, -434125, -111244624, + 394148, 101000509, 928749, 237992130, 1095468, 280713909, + -3506380, -898510625, 0, 0, 2129892, 545785280, + 676590, 173376332, -1335936, -342333886, 2071829, 530906624, + -4018989, -1029866791, 3241972, 830756018, 2156050, 552488273, + 0, 0, 3764867, 964747974, -3227876, -827143915, + 1714295, 439288460, 3415069, 875112161, 1759347, 450833045, + -817536, -209493775, -3574466, -915957677, 0, 0, + -1005239, -257592709, 2453983, 628833668, 1460718, 374309300, + 3756790, 962678241, -1935799, -496048908, -1716988, -439978542, + -3950053, -1012201926, 0, 0, 557458, 142848732, + -642628, -164673562, -3585098, -918682129, -2897314, -742437332, + 3192354, 818041395, 556856, 142694469, 3870317, 991769559, + 0, 0, -1221177, -312926867, 2815639, 721508096, + 2283733, 585207070, 2917338, 747568486, 1853806, 475038184, + 3345963, 857403734, 1858416, 476219497, 0, 0, +}; + +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer78[] = { + 3073009, 1277625, -2635473, 3852015, 787459213, + 327391679, -675340520, 987079667, 1753, -2659525, + 2660408, -59148, 449207, -681503850, 681730119, + -15156688, -1935420, -1455890, -1780227, 2772600, + -495951789, -373072124, -456183549, 710479343, 4183372, + -3222807, -3121440, -274060, 1071989969, -825844983, + -799869667, -70227934, 1182243, 636927, -3956745, + -3284915, 302950022, 163212680, -1013916752, -841760171, + 87208, -3965306, -2296397, -3716946, 22347069, + -1016110510, -588452222, -952468207, 2508980, 2028118, + 1937570, -3815725, 642926661, 519705671, 496502727, + -977780347, -27812, 1009365, -1979497, -3956944, + -7126831, 258649997, -507246529, -1013967746, 822541, + -2454145, 1596822, -3759465, 210776307, -628875181, + 409185979, -963363710, 2811291, -2983781, -1109516, + 4158088, 720393920, -764594519, -284313712, 1065510939, + -1685153, 2678278, -3551006, -250446, -431820817, + 686309310, -909946047, -64176841, -3410568, -3768948, + 635956, -2455377, -873958779, -965793731, 162963861, + -629190881, 1528066, 482649, 1148858, -2962264, + 391567239, 123678909, 294395108, -759080783, -4146264, + 2192938, 2387513, -268456, -1062481036, 561940831, + 611800717, -68791907, -1772588, -1727088, -3611750, + -3180456, -454226054, -442566669, -925511710, -814992530, + -565603, 169688, 2462444, -3334383, -144935890, + 43482586, 631001801, -854436357, 3747250, 1239911, + 3195676, 1254190, 960233614, 317727459, 818892658, + 321386456, 2296099, -3838479, 2642980, -12417, + 588375860, -983611064, 677264190, -3181859, -4166425, + -3488383, 1987814, -3197248, -1067647297, -893898890, + 509377762, -819295484, 2998219, -89301, -1354892, + -1310261, 768294260, -22883400, -347191365, -335754661, + 141835, 2513018, 613238, -2218467, 36345249, + 643961400, 157142369, -568482643, 1736313, 235407, + -3250154, 3258457, 444930577, 60323094, -832852657, + 834980303, -458740, 4040196, 2039144, -818761, + -117552223, 1035301089, 522531086, -209807681, -1921994, + -3472069, -1879878, -2178965, -492511373, -889718424, + -481719139, -558360247, -2579253, 1787943, -2391089, + -2254727, -660934133, 458160776, -612717067, -577774276, + -1623354, -2374402, 586241, 527981, -415984810, + -608441020, 150224382, 135295244, 2105286, -2033807, + -1179613, -2743411, 539479988, -521163479, -302276083, + -702999655, 3482206, -4182915, -1300016, -2362063, + 892316032, -1071872863, -333129378, -605279149, -1476985, + 2491325, 507927, -724804, -378477722, 638402564, + 130156402, -185731180, 1994046, -1393159, -1187885, + -1834526, 510974714, -356997292, -304395785, -470097680, + -1317678, 2461387, 3035980, 621164, -337655269, + 630730945, 777970524, 159173408, -3033742, 2647994, + -2612853, 749577, -777397036, 678549029, -669544140, + 192079267, -338420, 3009748, 4148469, -4022750, + -86720197, 771248568, 1063046068, -1030830548, 3901472, + -1226661, 2925816, 3374250, 999753034, -314332144, + 749740976, 864652284, 3980599, -1615530, 1665318, + 1163598, 1020029345, -413979908, 426738094, 298172236, + 2569011, 1723229, 2028038, -3369273, 658309618, + 441577800, 519685171, -863376927, 1356448, -2775755, + 2683270, -2778788, 347590090, -711287812, 687588511, + -712065019, 3994671, -1370517, 3363542, 545376, + 1023635298, -351195274, 861908357, 139752717, -11879, + 3020393, 214880, -770441, -3043996, 773976352, + 55063046, -197425671, -3467665, 2312838, -653275, + -459163, -888589898, 592665232, -167401858, -117660617, + 3105558, 508145, 860144, 140244, 795799901, + 130212265, 220412084, 35937555, -1103344, -553718, + 3430436, -1514152, -282732136, -141890356, 879049958, + -388001774, 348812, -327848, 1011223, -2354215, + 89383150, -84011120, 259126110, -603268097, -2185084, + 2358373, -3014420, 2926054, -559928242, 604333585, + -772445769, 749801963, 3123762, -2193087, -1716814, + -392707, 800464680, -561979013, -439933955, -100631253, + -3818627, -1922253, -2236726, 1744507, -978523985, + -492577742, -573161516, 447030292, -303005, -3974485, + 1900052, 1054478, -77645096, -1018462631, 486888731, + 270210213, 3531229, -3773731, -781875, -731434, + 904878186, -967019376, -200355636, -187430119, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer78[] = { + -1744507, 2236726, 1922253, 3818627, -447030292, 573161516, + 492577742, 978523985, 731434, 781875, 3773731, -3531229, + 187430119, 200355636, 967019376, -904878186, -1054478, -1900052, + 3974485, 303005, -270210213, -486888731, 1018462631, 77645096, + 2354215, -1011223, 327848, -348812, 603268097, -259126110, + 84011120, -89383150, 392707, 1716814, 2193087, -3123762, + 100631253, 439933955, 561979013, -800464680, -2926054, 3014420, + -2358373, 2185084, -749801963, 772445769, -604333585, 559928242, + 459163, 653275, -2312838, 3467665, 117660617, 167401858, + -592665232, 888589898, 1514152, -3430436, 553718, 1103344, + 388001774, -879049958, 141890356, 282732136, -140244, -860144, + -508145, -3105558, -35937555, -220412084, -130212265, -795799901, + 2778788, -2683270, 2775755, -1356448, 712065019, -687588511, + 711287812, -347590090, 770441, -214880, -3020393, 11879, + 197425671, -55063046, -773976352, 3043996, -545376, -3363542, + 1370517, -3994671, -139752717, -861908357, 351195274, -1023635298, + -3374250, -2925816, 1226661, -3901472, -864652284, -749740976, + 314332144, -999753034, 3369273, -2028038, -1723229, -2569011, + 863376927, -519685171, -441577800, -658309618, -1163598, -1665318, + 1615530, -3980599, -298172236, -426738094, 413979908, -1020029345, + -621164, -3035980, -2461387, 1317678, -159173408, -777970524, + -630730945, 337655269, 4022750, -4148469, -3009748, 338420, + 1030830548, -1063046068, -771248568, 86720197, -749577, 2612853, + -2647994, 3033742, -192079267, 669544140, -678549029, 777397036, + 2362063, 1300016, 4182915, -3482206, 605279149, 333129378, + 1071872863, -892316032, 1834526, 1187885, 1393159, -1994046, + 470097680, 304395785, 356997292, -510974714, 724804, -507927, + -2491325, 1476985, 185731180, -130156402, -638402564, 378477722, + 2254727, 2391089, -1787943, 2579253, 577774276, 612717067, + -458160776, 660934133, 2743411, 1179613, 2033807, -2105286, + 702999655, 302276083, 521163479, -539479988, -527981, -586241, + 2374402, 1623354, -135295244, -150224382, 608441020, 415984810, + -3258457, 3250154, -235407, -1736313, -834980303, 832852657, + -60323094, -444930577, 2178965, 1879878, 3472069, 1921994, + 558360247, 481719139, 889718424, 492511373, 818761, -2039144, + -4040196, 458740, 209807681, -522531086, -1035301089, 117552223, + 3197248, -1987814, 3488383, 4166425, 819295484, -509377762, + 893898890, 1067647297, 2218467, -613238, -2513018, -141835, + 568482643, -157142369, -643961400, -36345249, 1310261, 1354892, + 89301, -2998219, 335754661, 347191365, 22883400, -768294260, + 3334383, -2462444, -169688, 565603, 854436357, -631001801, + -43482586, 144935890, 12417, -2642980, 3838479, -2296099, + 3181859, -677264190, 983611064, -588375860, -1254190, -3195676, + -1239911, -3747250, -321386456, -818892658, -317727459, -960233614, + 2962264, -1148858, -482649, -1528066, 759080783, -294395108, + -123678909, -391567239, 3180456, 3611750, 1727088, 1772588, + 814992530, 925511710, 442566669, 454226054, 268456, -2387513, + -2192938, 4146264, 68791907, -611800717, -561940831, 1062481036, + -4158088, 1109516, 2983781, -2811291, -1065510939, 284313712, + 764594519, -720393920, 2455377, -635956, 3768948, 3410568, + 629190881, -162963861, 965793731, 873958779, 250446, 3551006, + -2678278, 1685153, 64176841, 909946047, -686309310, 431820817, + 3815725, -1937570, -2028118, -2508980, 977780347, -496502727, + -519705671, -642926661, 3759465, -1596822, 2454145, -822541, + 963363710, -409185979, 628875181, -210776307, 3956944, 1979497, + -1009365, 27812, 1013967746, 507246529, -258649997, 7126831, + 274060, 3121440, 3222807, -4183372, 70227934, 799869667, + 825844983, -1071989969, 3716946, 2296397, 3965306, -87208, + 952468207, 588452222, 1016110510, -22347069, 3284915, 3956745, + -636927, -1182243, 841760171, 1013916752, -163212680, -302950022, + -3852015, 2635473, -1277625, -3073009, -987079667, 675340520, + -327391679, -787459213, -2772600, 1780227, 1455890, 1935420, + -710479343, 456183549, 373072124, 495951789, 59148, -2660408, + 2659525, -1753, 15156688, -681730119, 681503850, -449207, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer123456[] = { + -2283733, -585207070, 0, 0, -1858416, -476219497, + -3345963, -857403734, -2815639, -721508096, 0, 0, + -1853806, -475038184, -2917338, -747568486, 3585098, 918682129, + 0, 0, -3870317, -991769559, -556856, -142694469, + 642628, 164673562, 0, 0, -3192354, -818041395, + 2897314, 742437332, -1460718, -374309300, 0, 0, + 3950053, 1012201926, 1716988, 439978542, -2453983, -628833668, + 0, 0, 1935799, 496048908, -3756790, -962678241, + -1714295, -439288460, 0, 0, 3574466, 915957677, + 817536, 209493775, 3227876, 827143915, 0, 0, + -1759347, -450833045, -3415069, -875112161, 1335936, 342333886, + 0, 0, -2156050, -552488273, -3241972, -830756018, + -676590, -173376332, 0, 0, 4018989, 1029866791, + -2071829, -530906624, 434125, 111244624, 0, 0, + 3506380, 898510625, -1095468, -280713909, 3524442, 903139016, + 0, 0, -928749, -237992130, -394148, -101000509, + 1674615, 429120452, 0, 0, -1159875, -297218217, + -3704823, -949361686, -2663378, -682491182, 0, 0, + -2101410, -538486762, 3110818, 797147778, 4063053, 1041158200, + 0, 0, 3586446, 919027554, -2740543, -702264730, + 3370349, 863652652, 0, 0, -3182878, -815613168, + -3602218, -923069133, -294725, -75523344, -3761513, -963888510, + -3765607, -964937599, 3201430, 820367122, 3145678, 806080660, + 2883726, 738955404, 3201494, 820383522, 1221177, 312926867, + -557458, -142848732, 1005239, 257592709, -3764867, -964747974, + -2129892, -545785280, -2682288, -687336873, -3542485, -907762539, + 601683, 154181397, 0, 0, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_zetas) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h new file mode 100644 index 0000000000..e77f55014c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#define MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H + +#include +#include "../../../common.h" + +#define mld_aarch64_ntt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_ntt_zetas_layer123456) +#define mld_aarch64_ntt_zetas_layer78 MLD_NAMESPACE(aarch64_ntt_zetas_layer78) + +#define mld_aarch64_intt_zetas_layer78 MLD_NAMESPACE(aarch64_intt_zetas_layer78) +#define mld_aarch64_intt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_intt_zetas_layer123456) + +extern const int32_t mld_aarch64_ntt_zetas_layer123456[]; +extern const int32_t mld_aarch64_ntt_zetas_layer78[]; + +extern const int32_t mld_aarch64_intt_zetas_layer78[]; +extern const int32_t mld_aarch64_intt_zetas_layer123456[]; + +#define mld_rej_uniform_table MLD_NAMESPACE(rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[]; +#define mld_rej_uniform_eta_table MLD_NAMESPACE(rej_uniform_eta_table) +extern const uint8_t mld_rej_uniform_eta_table[]; + +#define mld_polyz_unpack_17_indices MLD_NAMESPACE(polyz_unpack_17_indices) +extern const uint8_t mld_polyz_unpack_17_indices[]; +#define mld_polyz_unpack_19_indices MLD_NAMESPACE(polyz_unpack_19_indices) +extern const uint8_t mld_polyz_unpack_19_indices[]; + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_ntt_asm MLD_NAMESPACE(ntt_asm) +void mld_ntt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_intt_asm MLD_NAMESPACE(intt_asm) +void mld_intt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_rej_uniform_asm MLD_NAMESPACE(rej_uniform_asm) +uint64_t mld_rej_uniform_asm(int32_t *r, const uint8_t *buf, unsigned buflen, + const uint8_t *table); + +#define mld_rej_uniform_eta2_asm MLD_NAMESPACE(rej_uniform_eta2_asm) +uint64_t mld_rej_uniform_eta2_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_rej_uniform_eta4_asm MLD_NAMESPACE(rej_uniform_eta4_asm) +uint64_t mld_rej_uniform_eta4_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_poly_decompose_32_asm MLD_NAMESPACE(poly_decompose_32_asm) +void mld_poly_decompose_32_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_asm MLD_NAMESPACE(poly_decompose_88_asm) +void mld_poly_decompose_88_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_asm MLD_NAMESPACE(poly_caddq_asm) +void mld_poly_caddq_asm(int32_t *a); + +#define mld_poly_use_hint_32_asm MLD_NAMESPACE(poly_use_hint_32_asm) +void mld_poly_use_hint_32_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_asm MLD_NAMESPACE(poly_use_hint_88_asm) +void mld_poly_use_hint_88_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_asm MLD_NAMESPACE(poly_chknorm_asm) +int mld_poly_chknorm_asm(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_asm MLD_NAMESPACE(polyz_unpack_17_asm) +void mld_polyz_unpack_17_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_polyz_unpack_19_asm MLD_NAMESPACE(polyz_unpack_19_asm) +void mld_polyz_unpack_19_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_poly_pointwise_montgomery_asm \ + MLD_NAMESPACE(poly_pointwise_montgomery_asm) +void mld_poly_pointwise_montgomery_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l4_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l4_asm) +void mld_polyvecl_pointwise_acc_montgomery_l4_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l5_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l5_asm) +void mld_polyvecl_pointwise_acc_montgomery_l5_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l7_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l7_asm) +void mld_polyvecl_pointwise_acc_montgomery_l7_asm(int32_t *, const int32_t *, + const int32_t *); + +#endif /* !MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c new file mode 100644 index 0000000000..7ef915b587 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* Table of indices used for tbl instructions in polyz_unpack_{17,19}. */ + +MLD_ALIGN const uint8_t mld_polyz_unpack_17_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, + 9, 10, 11, 255, 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, + 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, 8, 9, 10, 255, + 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, 17, 18, 19, 255, +}; + +MLD_ALIGN const uint8_t mld_polyz_unpack_19_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 5, 6, 7, 255, 7, 8, 9, 255, + 10, 11, 12, 255, 12, 13, 14, 255, 15, 16, 17, 255, 17, 18, 19, 255, + 4, 5, 6, 255, 6, 7, 8, 255, 9, 10, 11, 255, 11, 12, 13, 255, + 14, 15, 16, 255, 16, 17, 18, 255, 19, 20, 21, 255, 21, 22, 23, 255, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_polyz_unpack_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c new file mode 100644 index 0000000000..cf21509cbf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by 16-bit rejection sampling (rej_eta). + * Adapted from ML-KEM for ML-DSA eta rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_eta_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 2, 3, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 4, 5, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 2, 3, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 7 */, + 6, 7, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 2, 3, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 11 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 13 */, + 2, 3, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 15 */, + 8, 9, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 16 */, + 0, 1, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 17 */, + 2, 3, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 18 */, + 0, 1, 2, 3, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 19 */, + 4, 5, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 20 */, + 0, 1, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 21 */, + 2, 3, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 22 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 23 */, + 6, 7, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 24 */, + 0, 1, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 25 */, + 2, 3, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 26 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 27 */, + 4, 5, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 28 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 29 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 30 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 255, 255, 255, 255, 255, 255 /* 31 */, + 10, 11, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 32 */, + 0, 1, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 33 */, + 2, 3, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 34 */, + 0, 1, 2, 3, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 35 */, + 4, 5, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 36 */, + 0, 1, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 37 */, + 2, 3, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 38 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 39 */, + 6, 7, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 40 */, + 0, 1, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 41 */, + 2, 3, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 42 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 43 */, + 4, 5, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 44 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 45 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 46 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 255, 255, 255, 255, 255, 255 /* 47 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 48 */, + 0, 1, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 49 */, + 2, 3, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 50 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 51 */, + 4, 5, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 52 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 53 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 54 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 55 */, + 6, 7, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 56 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 57 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 58 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 59 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 60 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 61 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 62 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 63 */, + 12, 13, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 64 */, + 0, 1, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 65 */, + 2, 3, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 66 */, + 0, 1, 2, 3, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 67 */, + 4, 5, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 68 */, + 0, 1, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 69 */, + 2, 3, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 70 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 71 */, + 6, 7, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 72 */, + 0, 1, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 73 */, + 2, 3, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 74 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 75 */, + 4, 5, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 76 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 77 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 78 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 255, 255, 255, 255, 255, 255 /* 79 */, + 8, 9, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 80 */, + 0, 1, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 81 */, + 2, 3, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 82 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 83 */, + 4, 5, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 84 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 85 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 86 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 87 */, + 6, 7, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 88 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 89 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 90 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 91 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 92 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 93 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 94 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 255, 255, 255, 255 /* 95 */, + 10, 11, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 96 */, + 0, 1, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 97 */, + 2, 3, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 98 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 99 */, + 4, 5, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 100 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 101 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 102 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 103 */, + 6, 7, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 104 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 105 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 106 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 107 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 108 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 109 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 110 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 255, 255, 255, 255 /* 111 */, + 8, 9, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 112 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 113 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 114 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 115 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 116 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 117 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 118 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 119 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 120 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 121 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 122 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 123 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 124 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 125 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 126 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 255, 255 /* 127 */, + 14, 15, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 128 */, + 0, 1, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 129 */, + 2, 3, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 130 */, + 0, 1, 2, 3, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 131 */, + 4, 5, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 132 */, + 0, 1, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 133 */, + 2, 3, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 134 */, + 0, 1, 2, 3, 4, 5, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 135 */, + 6, 7, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 136 */, + 0, 1, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 137 */, + 2, 3, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 138 */, + 0, 1, 2, 3, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 139 */, + 4, 5, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 140 */, + 0, 1, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 141 */, + 2, 3, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 142 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 14, 15, 255, 255, 255, 255, 255, 255 /* 143 */, + 8, 9, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 144 */, + 0, 1, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 145 */, + 2, 3, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 146 */, + 0, 1, 2, 3, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 147 */, + 4, 5, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 148 */, + 0, 1, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 149 */, + 2, 3, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 150 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 151 */, + 6, 7, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 152 */, + 0, 1, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 153 */, + 2, 3, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 154 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 155 */, + 4, 5, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 156 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 157 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 158 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 14, 15, 255, 255, 255, 255 /* 159 */, + 10, 11, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 160 */, + 0, 1, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 161 */, + 2, 3, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 162 */, + 0, 1, 2, 3, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 163 */, + 4, 5, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 164 */, + 0, 1, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 165 */, + 2, 3, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 166 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 167 */, + 6, 7, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 168 */, + 0, 1, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 169 */, + 2, 3, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 170 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 171 */, + 4, 5, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 172 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 173 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 174 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 14, 15, 255, 255, 255, 255 /* 175 */, + 8, 9, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 176 */, + 0, 1, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 177 */, + 2, 3, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 178 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 179 */, + 4, 5, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 180 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 181 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 182 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 183 */, + 6, 7, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 184 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 185 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 186 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 187 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 188 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 189 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 190 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 14, 15, 255, 255 /* 191 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 192 */, + 0, 1, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 193 */, + 2, 3, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 194 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 195 */, + 4, 5, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 196 */, + 0, 1, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 197 */, + 2, 3, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 198 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 199 */, + 6, 7, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 200 */, + 0, 1, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 201 */, + 2, 3, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 202 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 203 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 204 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 205 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 206 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 207 */, + 8, 9, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 208 */, + 0, 1, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 209 */, + 2, 3, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 210 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 211 */, + 4, 5, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 212 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 213 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 214 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 215 */, + 6, 7, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 216 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 217 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 218 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 219 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 220 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 221 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 222 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 14, 15, 255, 255 /* 223 */, + 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 224 */, + 0, 1, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 225 */, + 2, 3, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 226 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 227 */, + 4, 5, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 228 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 229 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 230 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 231 */, + 6, 7, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 232 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 233 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 234 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 235 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 236 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 237 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 238 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 14, 15, 255, 255 /* 239 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 240 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 241 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 242 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 243 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 244 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 245 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 246 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 247 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 248 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 249 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 250 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 251 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 252 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 253 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 254 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 255 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_eta_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/src/rej_uniform_table.c new file mode 100644 index 0000000000..65bc3b78d3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/aarch64/src/rej_uniform_table.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by rejection sampling of the public matrix. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 7 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 11 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 13 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 15 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/api.h new file mode 100644 index 0000000000..0f1fdeb168 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/api.h @@ -0,0 +1,594 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_API_H +#define MLD_NATIVE_API_H +/* + * Native arithmetic interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + * + * To ensure consistency with backends, the header will be + * included automatically after inclusion of the active + * backend, to ensure consistency of function signatures, + * and run sanity checks. + */ + +#include +#include "../cbmc.h" +#include "../common.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* Bound on absolute value of coefficients after NTT. + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) + +/* Absolute exclusive upper bound for the output of the inverse NTT + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_INTT_BOUND MLDSA_Q + +/* Absolute bound for range of mld_reduce32() + * + * NOTE: This is the same bound as in reduce.h and has to be kept + * in sync. */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define REDUCE32_RANGE_MAX 6283009 +/* + * This is the C<->native interface allowing for the drop-in of + * native code for performance critical arithmetic components of ML-DSA. + * + * A _backend_ is a specific implementation of (part of) this interface. + * + * To add a function to a backend, define MLD_USE_NATIVE_XXX and + * implement `static inline xxx(...)` in the profile header. + */ + +/* + * Those functions are meant to be trivial wrappers around the chosen native + * implementation. The are static inline to avoid unnecessary calls. + * The macro before each declaration controls whether a native + * implementation is present. + */ + +#if defined(MLD_USE_NATIVE_NTT) +/************************************************* + * Name: mld_ntt_native + * + * Description: Computes negacyclic number-theoretic transform (NTT) of + * a polynomial in place. + * + * The input polynomial is assumed to be in normal order. + * The output polynomial is in bitreversed order. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_ntt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_NTT */ + + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) +/* + * This must only be set if NTT and INTT have native implementations + * that are adapted to the custom order. + */ +#if !defined(MLD_USE_NATIVE_NTT) || !defined(MLD_USE_NATIVE_INTT) +#error \ + "Invalid native profile: MLD_USE_NATIVE_NTT_CUSTOM_ORDER can only be \ +set if there are native implementations for NTT and INTT." +#endif + +/************************************************* + * Name: mlD_poly_permute_bitrev_to_custom + * + * Description: When MLD_USE_NATIVE_NTT_CUSTOM_ORDER is defined, + * convert a polynomial in NTT domain from bitreversed + * order to the custom order output by the native NTT. + * + * This must only be defined if there is native code for + * both the NTT and INTT. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + * + **************************************************/ +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t p[MLDSA_N]) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q))); +#endif /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + + +#if defined(MLD_USE_NATIVE_INTT) +/************************************************* + * Name: mld_intt_native + * + * Description: Computes inverse of negacyclic number-theoretic transform + *(NTT) of a polynomial in place. + * + * The input polynomial is in bitreversed order. + * The output polynomial is assumed to be in normal order. + * + * Arguments: - uint32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_intt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_INTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_INTT */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) +/************************************************* + * Name: mld_rej_uniform_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [0, MLDSA_Q-1] + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform mod q). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + * lengths. Otherwise, returns non-negative number of sampled 32-bit integers + * (at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= ( 5 * 168) && buflen % 3 == 0) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(r, 0, (unsigned) return_value, 0, MLDSA_Q)) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) +/************************************************* + * Name: mld_rej_uniform_eta2_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-2,+2]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-2, +2]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA2 */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) +/************************************************* + * Name: mld_rej_uniform_eta4_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-4,+4]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-4, +4]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) +/************************************************* + * Name: mld_poly_decompose_32_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/32. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: input/output polynomial. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_32 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) +/************************************************* + * Name: mld_poly_decompose_88_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/88. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: output polynomial with coefficients c0. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CADDQ) +/************************************************* + * Name: mld_poly_caddq_native + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *a: pointer to input/output polynomial + **************************************************/ +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_32) +/************************************************* + * Name: mld_poly_use_hint_32_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/32. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_32 */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) +/************************************************* + * Name: mld_poly_use_hint_88_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/88. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) +/************************************************* + * Name: mld_poly_chknorm_native + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const int32_t *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if the infinity norm is strictly smaller than B, and 1 + * otherwise. B must not be larger than MLDSA_Q - MLD_REDUCE32_RANGE_MAX. + **************************************************/ +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(0 <= B && B <= MLDSA_Q - REDUCE32_RANGE_MAX) + requires(array_bound(a, 0, MLDSA_N, -REDUCE32_RANGE_MAX, REDUCE32_RANGE_MAX)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == 0) == array_abs_bound(a, 0, MLDSA_N, B)) +); +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) +/************************************************* + * Name: mld_polyz_unpack_17_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^17. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_17 */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) +/************************************************* + * Name: mld_polyz_unpack_19_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^19. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_19 */ + +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) +/************************************************* + * Name: mld_poly_pointwise_montgomery_native + * + * Description: Pointwise multiplication of polynomials in NTT domain + * with Montgomery reduction. + * + * Computes c[i] = a[i] * b[i] * R^(-1) mod q for all i, + * where R = 2^32. + * + * Arguments: - int32_t c[MLDSA_N]: output polynomial + * - const int32_t a[MLDSA_N]: first input polynomial + * - const int32_t b[MLDSA_N]: second input polynomial + **************************************************/ +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(c, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(c, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(c, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l4_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 4. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 4 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 4 * MLDSA_N)) + requires(forall(l0, 0, 4, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 4, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l5_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 5. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 5 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 5 * MLDSA_N)) + requires(forall(l0, 0, 5, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 5, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l7_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 7. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 7 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 7 * MLDSA_N)) + requires(forall(l0, 0, 7, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 7, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 */ + +#endif /* !MLD_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/meta.h new file mode 100644 index 0000000000..0b46dd5791 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/meta.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_META_H +#define MLD_NATIVE_META_H + +/* + * Default arithmetic backend + */ +#include "../sys.h" + +#ifdef MLD_SYS_AARCH64 +#include "aarch64/meta.h" +#endif + +#ifdef MLD_SYS_X86_64_AVX2 +#include "x86_64/meta.h" +#endif + +#endif /* !MLD_NATIVE_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/meta.h new file mode 100644 index 0000000000..393374c06f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/meta.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_X86_64_META_H +#define MLD_NATIVE_X86_64_META_H + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_X86_64_DEFAULT + +#define MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +#if !defined(__ASSEMBLER__) +#include +#include "../../common.h" +#include "../api.h" +#include "src/arith_native_x86_64.h" + +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t data[MLDSA_N]) +{ + if (mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + mld_nttunpack_avx2(data); + } +} + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_ntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_invntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)mld_rej_uniform_avx2(r, buf); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_32_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_88_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_caddq_avx2(a); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_32_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_88_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + return mld_poly_chknorm_avx2(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_17_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_19_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_avx2(c, a, b, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l4_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l5_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l7_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_NATIVE_X86_64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h new file mode 100644 index 0000000000..08d5abf74a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#define MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#include "../../../common.h" + +#include +#include "consts.h" + +#define MLD_AVX2_REJ_UNIFORM_BUFLEN \ + (5 * 168) /* REJ_UNIFORM_NBLOCKS * SHAKE128_RATE */ + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) + +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_rej_uniform_table MLD_NAMESPACE(mld_rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[256][8]; + +#define mld_ntt_avx2 MLD_NAMESPACE(ntt_avx2) +void mld_ntt_avx2(int32_t *r, const int32_t *qdata) +/* This must be kept in sync with the HOL-Light specification + * in proofs/hol_light/x86_64/proofs/mldsa_ntt.ml */ +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, MLDSA_N, 8380417)) + requires(qdata == mld_qdata) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + /* check-magic: off */ + ensures(array_abs_bound(r, 0, MLDSA_N, 42035262)) + /* check-magic: on */ +); + +#define mld_invntt_avx2 MLD_NAMESPACE(invntt_avx2) +void mld_invntt_avx2(int32_t *r, const int32_t *mld_qdata); + +#define mld_nttunpack_avx2 MLD_NAMESPACE(nttunpack_avx2) +void mld_nttunpack_avx2(int32_t *r); + +#define mld_rej_uniform_avx2 MLD_NAMESPACE(mld_rej_uniform_avx2) +unsigned mld_rej_uniform_avx2(int32_t *r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]); + +#define mld_rej_uniform_eta2_avx2 MLD_NAMESPACE(mld_rej_uniform_eta2_avx2) +unsigned mld_rej_uniform_eta2_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]); + +#define mld_rej_uniform_eta4_avx2 MLD_NAMESPACE(mld_rej_uniform_eta4_avx2) +unsigned mld_rej_uniform_eta4_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]); + +#define mld_poly_decompose_32_avx2 MLD_NAMESPACE(mld_poly_decompose_32_avx2) +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_avx2 MLD_NAMESPACE(mld_poly_decompose_88_avx2) +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_avx2 MLD_NAMESPACE(poly_caddq_avx2) +void mld_poly_caddq_avx2(int32_t *r); + +#define mld_poly_use_hint_32_avx2 MLD_NAMESPACE(mld_poly_use_hint_32_avx2) +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_avx2 MLD_NAMESPACE(mld_poly_use_hint_88_avx2) +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_avx2 MLD_NAMESPACE(mld_poly_chknorm_avx2) +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_avx2 MLD_NAMESPACE(mld_polyz_unpack_17_avx2) +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a); + +#define mld_polyz_unpack_19_avx2 MLD_NAMESPACE(mld_polyz_unpack_19_avx2) +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a); + +#define mld_pointwise_avx2 MLD_NAMESPACE(pointwise_avx2) +void mld_pointwise_avx2(int32_t *c, const int32_t *a, const int32_t *b, + const int32_t *qdata); + +#define mld_pointwise_acc_l4_avx2 MLD_NAMESPACE(pointwise_acc_l4_avx2) +void mld_pointwise_acc_l4_avx2(int32_t c[MLDSA_N], const int32_t a[4][MLDSA_N], + const int32_t b[4][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l5_avx2 MLD_NAMESPACE(pointwise_acc_l5_avx2) +void mld_pointwise_acc_l5_avx2(int32_t c[MLDSA_N], const int32_t a[5][MLDSA_N], + const int32_t b[5][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l7_avx2 MLD_NAMESPACE(pointwise_acc_l7_avx2) +void mld_pointwise_acc_l7_avx2(int32_t c[MLDSA_N], const int32_t a[7][MLDSA_N], + const int32_t b[7][MLDSA_N], + const int32_t *qdata); + +#endif /* !MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/consts.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/consts.c new file mode 100644 index 0000000000..aaca3535ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/consts.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include "consts.h" + +/* + * Table of zeta values used in the AVX2 forward and inverse NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_qdata[624] = { + 8380417, 8380417, 8380417, 8380417, 8380417, + 8380417, 8380417, 8380417, 58728449, 58728449, + 58728449, 58728449, 58728449, 58728449, 58728449, + 58728449, -8395782, -8395782, -8395782, -8395782, + -8395782, -8395782, -8395782, -8395782, 41978, + 41978, 41978, 41978, 41978, 41978, + 41978, 41978, -151046689, 1830765815, -1929875198, + -1927777021, 1640767044, 1477910808, 1612161320, 1640734244, + 308362795, 308362795, 308362795, 308362795, -1815525077, + -1815525077, -1815525077, -1815525077, -1374673747, -1374673747, + -1374673747, -1374673747, -1091570561, -1091570561, -1091570561, + -1091570561, -1929495947, -1929495947, -1929495947, -1929495947, + 515185417, 515185417, 515185417, 515185417, -285697463, + -285697463, -285697463, -285697463, 625853735, 625853735, + 625853735, 625853735, 1727305304, 1727305304, 2082316400, + 2082316400, -1364982364, -1364982364, 858240904, 858240904, + 1806278032, 1806278032, 222489248, 222489248, -346752664, + -346752664, 684667771, 684667771, 1654287830, 1654287830, + -878576921, -878576921, -1257667337, -1257667337, -748618600, + -748618600, 329347125, 329347125, 1837364258, 1837364258, + -1443016191, -1443016191, -1170414139, -1170414139, -1846138265, + -1631226336, -1404529459, 1838055109, 1594295555, -1076973524, + -1898723372, -594436433, -202001019, -475984260, -561427818, + 1797021249, -1061813248, 2059733581, -1661512036, -1104976547, + -1750224323, -901666090, 418987550, 1831915353, -1925356481, + 992097815, 879957084, 2024403852, 1484874664, -1636082790, + -285388938, -1983539117, -1495136972, -950076368, -1714807468, + -952438995, -1574918427, 1350681039, -2143979939, 1599739335, + -1285853323, -993005454, -1440787840, 568627424, -783134478, + -588790216, 289871779, -1262003603, 2135294594, -1018755525, + -889861155, 1665705315, 1321868265, 1225434135, -1784632064, + 666258756, 675310538, -1555941048, -1999506068, -1499481951, + -695180180, -1375177022, 1777179795, 334803717, -178766299, + -518252220, 1957047970, 1146323031, -654783359, -1974159335, + 1651689966, 140455867, -1039411342, 1955560694, 1529189038, + -2131021878, -247357819, 1518161567, -86965173, 1708872713, + 1787797779, 1638590967, -120646188, -1669960606, -916321552, + 1155548552, 2143745726, 1210558298, -1261461890, -318346816, + 628664287, -1729304568, 1422575624, 1424130038, -1185330464, + 235321234, 168022240, 1206536194, 985155484, -894060583, + -898413, -1363460238, -605900043, 2027833504, 14253662, + 1014493059, 863641633, 1819892093, 2124962073, -1223601433, + -1920467227, -1637785316, -1536588520, 694382729, 235104446, + -1045062172, 831969619, -300448763, 756955444, -260312805, + 1554794072, 1339088280, -2040058690, -853476187, -2047270596, + -1723816713, -1591599803, -440824168, 1119856484, 1544891539, + 155290192, -973777462, 991903578, 912367099, -44694137, + 1176904444, -421552614, -818371958, 1747917558, -325927722, + 908452108, 1851023419, -1176751719, -1354528380, -72690498, + -314284737, 985022747, 963438279, -1078959975, 604552167, + -1021949428, 608791570, 173440395, -2126092136, -1316619236, + -1039370342, 6087993, -110126092, 565464272, -1758099917, + -1600929361, 879867909, -1809756372, 400711272, 1363007700, + 30313375, -326425360, 1683520342, -517299994, 2027935492, + -1372618620, 128353682, -1123881663, 137583815, -635454918, + -642772911, 45766801, 671509323, -2070602178, 419615363, + 1216882040, -270590488, -1276805128, 371462360, -1357098057, + -384158533, 827959816, -596344473, 702390549, -279505433, + -260424530, -71875110, -1208667171, -1499603926, 2036925262, + -540420426, 746144248, -1420958686, 2032221021, 1904936414, + 1257750362, 1926727420, 1931587462, 1258381762, 885133339, + 1629985060, 1967222129, 6363718, -1287922800, 1136965286, + 1779436847, 1116720494, 1042326957, 1405999311, 713994583, + 940195359, -1542497137, 2061661095, -883155599, 1726753853, + -1547952704, 394851342, 283780712, 776003547, 1123958025, + 201262505, 1934038751, 374860238, -3975713, 25847, + -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 1826347, 1826347, 1826347, + 2353451, 2353451, 2353451, 2353451, -359251, + -359251, -359251, -359251, -2091905, -2091905, + -2091905, -2091905, 3119733, 3119733, 3119733, + 3119733, -2884855, -2884855, -2884855, -2884855, + 3111497, 3111497, 3111497, 3111497, 2680103, + 2680103, 2680103, 2680103, 2725464, 2725464, + 1024112, 1024112, -1079900, -1079900, 3585928, + 3585928, -549488, -549488, -1119584, -1119584, + 2619752, 2619752, -2108549, -2108549, -2118186, + -2118186, -3859737, -3859737, -1399561, -1399561, + -3277672, -3277672, 1757237, 1757237, -19422, + -19422, 4010497, 4010497, 280005, 280005, + 2706023, 95776, 3077325, 3530437, -1661693, + -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, + -539299, -1699267, -1643818, 3505694, -3821735, + 3507263, -2140649, -1600420, 3699596, 811944, + 531354, 954230, 3881043, 3900724, -2556880, + 2071892, -2797779, -3930395, -3677745, -1452451, + 2176455, -1257611, -4083598, -3190144, -3632928, + 3412210, 2147896, -2967645, -411027, -671102, + -22981, -381987, 1852771, -3343383, 508951, + 44288, 904516, -3724342, 1653064, 2389356, + 759969, 189548, 3159746, -2409325, 1315589, + 1285669, -812732, -3019102, -3628969, -1528703, + -3041255, 3475950, -1585221, 1939314, -1000202, + -3157330, 126922, -983419, 2715295, -3693493, + -2477047, -1228525, -1308169, 1349076, -1430430, + 264944, 3097992, -1100098, 3958618, -8578, + -3249728, -210977, -1316856, -3553272, -1851402, + -177440, 1341330, -1584928, -1439742, -3881060, + 3839961, 2091667, -3342478, 266997, -3520352, + 900702, 495491, -655327, -3556995, 342297, + 3437287, 2842341, 4055324, -3767016, -2994039, + -1333058, -451100, -1279661, 1500165, -542412, + -2584293, -2013608, 1957272, -3183426, 810149, + -3038916, 2213111, -426683, -1667432, -2939036, + 183443, -554416, 3937738, 3407706, 2244091, + 2434439, -3759364, 1859098, -1613174, -3122442, + -525098, 286988, -3342277, 2691481, 1247620, + 1250494, 1869119, 1237275, 1312455, 1917081, + 777191, -2831860, -3724270, 2432395, 3369112, + 162844, 1652634, 3523897, -975884, 1723600, + -1104333, -2235985, -976891, 3919660, 1400424, + 2316500, -2446433, -1235728, -1197226, 909542, + -43260, 2031748, -768622, -2437823, 1735879, + -2590150, 2486353, 2635921, 1903435, -3318210, + 3306115, -2546312, 2235880, -1671176, 594136, + 2454455, 185531, 1616392, -3694233, 3866901, + 1717735, -1803090, -260646, -420899, 1612842, + -48306, -846154, 3817976, -3562462, 3513181, + -3193378, 819034, -522500, 3207046, -3595838, + 4108315, 203044, 1265009, 1595974, -3548272, + -1050970, -1430225, -1962642, -1374803, 3406031, + -1846953, -3776993, -164721, -1207385, 3014001, + -1799107, 269760, 472078, 1910376, -3833893, + -2286327, -3545687, -1362209, 1976782, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_consts) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/consts.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/consts.h new file mode 100644 index 0000000000..7fe08f454b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/consts.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#ifndef MLD_NATIVE_X86_64_SRC_CONSTS_H +#define MLD_NATIVE_X86_64_SRC_CONSTS_H +#include "../../../common.h" +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQ 0 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV 8 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV 16 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV 24 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV 32 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS 328 + +#ifndef __ASSEMBLER__ +#define mld_qdata MLD_NAMESPACE(qdata) +extern const int32_t mld_qdata[624]; +#endif + +#endif /* !MLD_NATIVE_X86_64_SRC_CONSTS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c new file mode 100644 index 0000000000..05d86d14fc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/************************************************* + * Name: mld_poly_caddq_avx2 + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *r: pointer to input/output polynomial + **************************************************/ +void mld_poly_caddq_avx2(int32_t *r) +{ + unsigned int i; + __m256i f, g; + const __m256i q = _mm256_set1_epi32(MLDSA_Q); + const __m256i zero = _mm256_setzero_si256(); + __m256i *rr = (__m256i *)r; + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256(&rr[i]); + g = _mm256_cmpgt_epi32(zero, f); + g = _mm256_and_si256(g, q); + f = _mm256_add_epi32(f, g); + _mm256_store_si256(&rr[i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_reduce) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c new file mode 100644 index 0000000000..50e2c7fa9b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B) +{ + unsigned int i; + __m256i f, t; + const __m256i bound = _mm256_set1_epi32(B - 1); + + t = _mm256_setzero_si256(); + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + f = _mm256_abs_epi32(f); + f = _mm256_cmpgt_epi32(f, bound); + t = _mm256_or_si256(t, f); + } + + return 1 - _mm256_testz_si256(t, t); +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_chknorm) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c new file mode 100644 index 0000000000..76846bf1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(31 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 4092 == intdiv(2 * intdiv(MLDSA_Q - 1, 32), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 4092. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 32*GAMMA2 = 16*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 16B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + * + * round(f1' * 1025 / 2^22) is in turn computed in 2 steps as + * round(floor(f1' * 1025 / 2^16) / 2^6). The mulhi computes f1'' = + * floor(f1' * 1025 / 2^16). As for the next step f1 = round(f1'' / 2^6), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^9) = round(f1'' * 2^9 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 1025 / 2^16) = 1025 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(16B / B) = 16 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 16, i.e. f > 31*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 31*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 15, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c new file mode 100644 index 0000000000..463506b962 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ + +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 1488 == intdiv(2 * intdiv(MLDSA_Q - 1, 88), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 1488. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 88*GAMMA2 = 44*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 44B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + * + * round(f1' * 11275 / 2^24) is in turn computed in 2 steps as + * round(floor(f1' * 11275 / 2^16) / 2^8). The mulhi computes f1'' = + * floor(f1' * 11275 / 2^16). As for the next step f1 = round(f1'' / 2^8), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^7) = round(f1'' * 2^7 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 11275 / 2^16) = 11275 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(44B / B) = 44 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 44, i.e. f > 87*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 87*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 43, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c new file mode 100644 index 0000000000..0094bc93a9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + const __m256i mask = _mm256_set1_epi32(15); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_32_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 16 */ + f1 = _mm256_add_epi32(f1, h); + f1 = _mm256_and_si256(f1, mask); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c new file mode 100644 index 0000000000..b109ab6351 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + const __m256i max = _mm256_set1_epi32(43); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_88_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 44 */ + f1 = _mm256_add_epi32(f1, h); + f1 = MLD_MM256_BLENDV_EPI32(f1, max, f1); + f = _mm256_cmpgt_epi32(f1, max); + f1 = MLD_MM256_BLENDV_EPI32(f1, zero, f); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c new file mode 100644 index 0000000000..f6c08a832f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 27, 26, 25, -1, 25, 24, 23, -1, 8, 7, + 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0); + const __m256i srlvdidx = _mm256_set_epi32(6, 4, 2, 0, 6, 4, 2, 0); + const __m256i mask = _mm256_set1_epi32(0x3FFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 17)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[18 * i]); + /* Load bytes 2..17 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[18 * i + 2]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-8 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 8, 7, 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte8, byte7, byte6, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,27, 26, 25, -1,25, 24, 23] │ + * │ Result: [0, byte17, byte16, byte15, ..., 0, byte11, byte10, byte9] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 18 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 32..55 48..71 + * 72..95 88..111 104..127 120..143 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 18..39 36..55 54..71 + * 72..95 90..111 108..127 126..143 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..17 18..35 36..53 54..71 + * 72..89 90..107 108..125 126..143 */ + + /* Map [0, 1, ..., 2^18-1] to [2^17, 2^17-1, ..., -2^17+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_17) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c new file mode 100644 index 0000000000..4a5ce48f38 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 26, 25, 24, -1, 24, 23, 22, -1, 9, 8, + 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0); + /* Equivalent to _mm256_set_epi32(4, 0, 4, 0, 4, 0, 4, 0) */ + const __m256i srlvdidx = _mm256_set1_epi64x((uint64_t)4 << 32); + const __m256i mask = _mm256_set1_epi32(0xFFFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 19)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[20 * i]); + /* Load bytes 4..19 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[20 * i + 4]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-9 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 9, 8, 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte9, byte8, byte7, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,26, 25, 24, -1,24, 23, 22] │ + * │ Result: [0, byte19, byte18, byte17, ..., 0, byte12, byte11, byte10] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 20 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 40..63 56..79 + * 80..103 96..119 120..143 136..159 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 20..39 40..63 60..79 + * 80..103 100..119 120..143 140..159 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..19 20..39 40..59 60..79 + * 80..99 100..119 120..139 140..159 */ + + /* Map [0, 1, ..., 2^20-1] to [2^19, 2^19-1, ..., -2^19+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_19) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c new file mode 100644 index 0000000000..07a5df9706 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The pqcrystals implementation assumes a buffer that is 8 bytes + *. larger as the first loop overreads by 8 bytes that are then + * discarded. We instead do not pad the buffer and do not overread. + * The performance impact is negligible and it does not force the + * frontend to perform the unintuitive padding. + */ + +unsigned int mld_rej_uniform_avx2( + int32_t *MLD_RESTRICT r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i d, tmp; + const __m256i bound = _mm256_set1_epi32(MLDSA_Q); + const __m256i mask = _mm256_set1_epi32(0x7FFFFF); + const __m256i idx8 = + _mm256_set_epi8(-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4, + -1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 32) + { + d = _mm256_loadu_si256((__m256i *)&buf[pos]); + + /* Permute 64-bit lanes + * 0x94 = 10010100b rearranges 64-bit lanes as: [3,2,1,0] -> [2,1,1,0] + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Original Layout ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ bytes 16..23 │ bytes 24..31 │ + * └─────────────────┴─────────────────┴─────────────────┴─────────────────┘ + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Layout after permute ║ + * ║ Byte indices in high half shifted down by 8 positions ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌───────────────┬─────────────────┐ ┌─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ │ bytes 8..15 │ bytes 16..23 │ + * └───────────────┴─────────────────┘ └─────────────────┴─────────────────┘ + * Lower 128-bit lane (bytes 0-15) Upper 128-bit lane (bytes 16-31) + */ + d = _mm256_permute4x64_epi64(d, 0x94); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-11 into low 128-bit half of permuted vector────────────────┐ + * │ Shuffle: [-1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0] │ + * │ Result: [0, byte11, byte10, byte9, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 4-15 into high 128-bit half of permuted vector ──────────────┐ + * │ Shuffle: [-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4] │ + * │ Result: [0, byte23, byte22, byte21, ..., 0, byte14, byte13, byte12 │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + d = _mm256_shuffle_epi8(d, idx8); + d = _mm256_and_si256(d, mask); + pos += 24; + + tmp = _mm256_sub_epi32(d, bound); + good = (uint32_t)_mm256_movemask_ps((__m256)tmp); + tmp = _mm256_cvtepu8_epi32( + _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good])); + d = _mm256_permutevar8x32_epi32(d, tmp); + + _mm256_storeu_si256((__m256i *)&r[ctr], d); + ctr += (unsigned)_mm_popcnt_u32(good); + } + + while (ctr < MLDSA_N && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 3) + { + uint32_t t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + /* Safe because t < MLDSA_Q. */ + r[ctr++] = (int32_t)t; + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c new file mode 100644 index 0000000000..70c5c42c70 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA2 2 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ +unsigned int mld_rej_uniform_eta2_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1, f2; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA2); + const __m256i bound = mask; + /* check-magic: -6560 == 32*round(-2**10 / 5) */ + const __m256i v = _mm256_set1_epi32(-6560); + const __m256i p = _mm256_set1_epi32(5); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 15) + { + t0 = t0 - (205 * t0 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t0); + } + if (t1 < 15 && ctr < MLDSA_N) + { + t1 = t1 - (205 * t1 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta2) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA2 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c new file mode 100644 index 0000000000..ba00e91252 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA4 4 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ + +unsigned int mld_rej_uniform_eta4_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA4); + const __m256i bound = _mm256_set1_epi8(9); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 9) + { + r[ctr++] = (int32_t)(4 - t0); + } + if (t1 < 9 && ctr < MLDSA_N) + { + r[ctr++] = (int32_t)(4 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta4) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA4 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/rej_uniform_table.c new file mode 100644 index 0000000000..6c537b4542 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/native/x86_64/src/rej_uniform_table.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" + +/* + * Lookup table used by rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[256][8] = { + {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, + {2, 0, 0, 0, 0, 0, 0, 0}, {0, 2, 0, 0, 0, 0, 0, 0}, + {1, 2, 0, 0, 0, 0, 0, 0}, {0, 1, 2, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 0, 0}, {0, 3, 0, 0, 0, 0, 0, 0}, + {1, 3, 0, 0, 0, 0, 0, 0}, {0, 1, 3, 0, 0, 0, 0, 0}, + {2, 3, 0, 0, 0, 0, 0, 0}, {0, 2, 3, 0, 0, 0, 0, 0}, + {1, 2, 3, 0, 0, 0, 0, 0}, {0, 1, 2, 3, 0, 0, 0, 0}, + {4, 0, 0, 0, 0, 0, 0, 0}, {0, 4, 0, 0, 0, 0, 0, 0}, + {1, 4, 0, 0, 0, 0, 0, 0}, {0, 1, 4, 0, 0, 0, 0, 0}, + {2, 4, 0, 0, 0, 0, 0, 0}, {0, 2, 4, 0, 0, 0, 0, 0}, + {1, 2, 4, 0, 0, 0, 0, 0}, {0, 1, 2, 4, 0, 0, 0, 0}, + {3, 4, 0, 0, 0, 0, 0, 0}, {0, 3, 4, 0, 0, 0, 0, 0}, + {1, 3, 4, 0, 0, 0, 0, 0}, {0, 1, 3, 4, 0, 0, 0, 0}, + {2, 3, 4, 0, 0, 0, 0, 0}, {0, 2, 3, 4, 0, 0, 0, 0}, + {1, 2, 3, 4, 0, 0, 0, 0}, {0, 1, 2, 3, 4, 0, 0, 0}, + {5, 0, 0, 0, 0, 0, 0, 0}, {0, 5, 0, 0, 0, 0, 0, 0}, + {1, 5, 0, 0, 0, 0, 0, 0}, {0, 1, 5, 0, 0, 0, 0, 0}, + {2, 5, 0, 0, 0, 0, 0, 0}, {0, 2, 5, 0, 0, 0, 0, 0}, + {1, 2, 5, 0, 0, 0, 0, 0}, {0, 1, 2, 5, 0, 0, 0, 0}, + {3, 5, 0, 0, 0, 0, 0, 0}, {0, 3, 5, 0, 0, 0, 0, 0}, + {1, 3, 5, 0, 0, 0, 0, 0}, {0, 1, 3, 5, 0, 0, 0, 0}, + {2, 3, 5, 0, 0, 0, 0, 0}, {0, 2, 3, 5, 0, 0, 0, 0}, + {1, 2, 3, 5, 0, 0, 0, 0}, {0, 1, 2, 3, 5, 0, 0, 0}, + {4, 5, 0, 0, 0, 0, 0, 0}, {0, 4, 5, 0, 0, 0, 0, 0}, + {1, 4, 5, 0, 0, 0, 0, 0}, {0, 1, 4, 5, 0, 0, 0, 0}, + {2, 4, 5, 0, 0, 0, 0, 0}, {0, 2, 4, 5, 0, 0, 0, 0}, + {1, 2, 4, 5, 0, 0, 0, 0}, {0, 1, 2, 4, 5, 0, 0, 0}, + {3, 4, 5, 0, 0, 0, 0, 0}, {0, 3, 4, 5, 0, 0, 0, 0}, + {1, 3, 4, 5, 0, 0, 0, 0}, {0, 1, 3, 4, 5, 0, 0, 0}, + {2, 3, 4, 5, 0, 0, 0, 0}, {0, 2, 3, 4, 5, 0, 0, 0}, + {1, 2, 3, 4, 5, 0, 0, 0}, {0, 1, 2, 3, 4, 5, 0, 0}, + {6, 0, 0, 0, 0, 0, 0, 0}, {0, 6, 0, 0, 0, 0, 0, 0}, + {1, 6, 0, 0, 0, 0, 0, 0}, {0, 1, 6, 0, 0, 0, 0, 0}, + {2, 6, 0, 0, 0, 0, 0, 0}, {0, 2, 6, 0, 0, 0, 0, 0}, + {1, 2, 6, 0, 0, 0, 0, 0}, {0, 1, 2, 6, 0, 0, 0, 0}, + {3, 6, 0, 0, 0, 0, 0, 0}, {0, 3, 6, 0, 0, 0, 0, 0}, + {1, 3, 6, 0, 0, 0, 0, 0}, {0, 1, 3, 6, 0, 0, 0, 0}, + {2, 3, 6, 0, 0, 0, 0, 0}, {0, 2, 3, 6, 0, 0, 0, 0}, + {1, 2, 3, 6, 0, 0, 0, 0}, {0, 1, 2, 3, 6, 0, 0, 0}, + {4, 6, 0, 0, 0, 0, 0, 0}, {0, 4, 6, 0, 0, 0, 0, 0}, + {1, 4, 6, 0, 0, 0, 0, 0}, {0, 1, 4, 6, 0, 0, 0, 0}, + {2, 4, 6, 0, 0, 0, 0, 0}, {0, 2, 4, 6, 0, 0, 0, 0}, + {1, 2, 4, 6, 0, 0, 0, 0}, {0, 1, 2, 4, 6, 0, 0, 0}, + {3, 4, 6, 0, 0, 0, 0, 0}, {0, 3, 4, 6, 0, 0, 0, 0}, + {1, 3, 4, 6, 0, 0, 0, 0}, {0, 1, 3, 4, 6, 0, 0, 0}, + {2, 3, 4, 6, 0, 0, 0, 0}, {0, 2, 3, 4, 6, 0, 0, 0}, + {1, 2, 3, 4, 6, 0, 0, 0}, {0, 1, 2, 3, 4, 6, 0, 0}, + {5, 6, 0, 0, 0, 0, 0, 0}, {0, 5, 6, 0, 0, 0, 0, 0}, + {1, 5, 6, 0, 0, 0, 0, 0}, {0, 1, 5, 6, 0, 0, 0, 0}, + {2, 5, 6, 0, 0, 0, 0, 0}, {0, 2, 5, 6, 0, 0, 0, 0}, + {1, 2, 5, 6, 0, 0, 0, 0}, {0, 1, 2, 5, 6, 0, 0, 0}, + {3, 5, 6, 0, 0, 0, 0, 0}, {0, 3, 5, 6, 0, 0, 0, 0}, + {1, 3, 5, 6, 0, 0, 0, 0}, {0, 1, 3, 5, 6, 0, 0, 0}, + {2, 3, 5, 6, 0, 0, 0, 0}, {0, 2, 3, 5, 6, 0, 0, 0}, + {1, 2, 3, 5, 6, 0, 0, 0}, {0, 1, 2, 3, 5, 6, 0, 0}, + {4, 5, 6, 0, 0, 0, 0, 0}, {0, 4, 5, 6, 0, 0, 0, 0}, + {1, 4, 5, 6, 0, 0, 0, 0}, {0, 1, 4, 5, 6, 0, 0, 0}, + {2, 4, 5, 6, 0, 0, 0, 0}, {0, 2, 4, 5, 6, 0, 0, 0}, + {1, 2, 4, 5, 6, 0, 0, 0}, {0, 1, 2, 4, 5, 6, 0, 0}, + {3, 4, 5, 6, 0, 0, 0, 0}, {0, 3, 4, 5, 6, 0, 0, 0}, + {1, 3, 4, 5, 6, 0, 0, 0}, {0, 1, 3, 4, 5, 6, 0, 0}, + {2, 3, 4, 5, 6, 0, 0, 0}, {0, 2, 3, 4, 5, 6, 0, 0}, + {1, 2, 3, 4, 5, 6, 0, 0}, {0, 1, 2, 3, 4, 5, 6, 0}, + {7, 0, 0, 0, 0, 0, 0, 0}, {0, 7, 0, 0, 0, 0, 0, 0}, + {1, 7, 0, 0, 0, 0, 0, 0}, {0, 1, 7, 0, 0, 0, 0, 0}, + {2, 7, 0, 0, 0, 0, 0, 0}, {0, 2, 7, 0, 0, 0, 0, 0}, + {1, 2, 7, 0, 0, 0, 0, 0}, {0, 1, 2, 7, 0, 0, 0, 0}, + {3, 7, 0, 0, 0, 0, 0, 0}, {0, 3, 7, 0, 0, 0, 0, 0}, + {1, 3, 7, 0, 0, 0, 0, 0}, {0, 1, 3, 7, 0, 0, 0, 0}, + {2, 3, 7, 0, 0, 0, 0, 0}, {0, 2, 3, 7, 0, 0, 0, 0}, + {1, 2, 3, 7, 0, 0, 0, 0}, {0, 1, 2, 3, 7, 0, 0, 0}, + {4, 7, 0, 0, 0, 0, 0, 0}, {0, 4, 7, 0, 0, 0, 0, 0}, + {1, 4, 7, 0, 0, 0, 0, 0}, {0, 1, 4, 7, 0, 0, 0, 0}, + {2, 4, 7, 0, 0, 0, 0, 0}, {0, 2, 4, 7, 0, 0, 0, 0}, + {1, 2, 4, 7, 0, 0, 0, 0}, {0, 1, 2, 4, 7, 0, 0, 0}, + {3, 4, 7, 0, 0, 0, 0, 0}, {0, 3, 4, 7, 0, 0, 0, 0}, + {1, 3, 4, 7, 0, 0, 0, 0}, {0, 1, 3, 4, 7, 0, 0, 0}, + {2, 3, 4, 7, 0, 0, 0, 0}, {0, 2, 3, 4, 7, 0, 0, 0}, + {1, 2, 3, 4, 7, 0, 0, 0}, {0, 1, 2, 3, 4, 7, 0, 0}, + {5, 7, 0, 0, 0, 0, 0, 0}, {0, 5, 7, 0, 0, 0, 0, 0}, + {1, 5, 7, 0, 0, 0, 0, 0}, {0, 1, 5, 7, 0, 0, 0, 0}, + {2, 5, 7, 0, 0, 0, 0, 0}, {0, 2, 5, 7, 0, 0, 0, 0}, + {1, 2, 5, 7, 0, 0, 0, 0}, {0, 1, 2, 5, 7, 0, 0, 0}, + {3, 5, 7, 0, 0, 0, 0, 0}, {0, 3, 5, 7, 0, 0, 0, 0}, + {1, 3, 5, 7, 0, 0, 0, 0}, {0, 1, 3, 5, 7, 0, 0, 0}, + {2, 3, 5, 7, 0, 0, 0, 0}, {0, 2, 3, 5, 7, 0, 0, 0}, + {1, 2, 3, 5, 7, 0, 0, 0}, {0, 1, 2, 3, 5, 7, 0, 0}, + {4, 5, 7, 0, 0, 0, 0, 0}, {0, 4, 5, 7, 0, 0, 0, 0}, + {1, 4, 5, 7, 0, 0, 0, 0}, {0, 1, 4, 5, 7, 0, 0, 0}, + {2, 4, 5, 7, 0, 0, 0, 0}, {0, 2, 4, 5, 7, 0, 0, 0}, + {1, 2, 4, 5, 7, 0, 0, 0}, {0, 1, 2, 4, 5, 7, 0, 0}, + {3, 4, 5, 7, 0, 0, 0, 0}, {0, 3, 4, 5, 7, 0, 0, 0}, + {1, 3, 4, 5, 7, 0, 0, 0}, {0, 1, 3, 4, 5, 7, 0, 0}, + {2, 3, 4, 5, 7, 0, 0, 0}, {0, 2, 3, 4, 5, 7, 0, 0}, + {1, 2, 3, 4, 5, 7, 0, 0}, {0, 1, 2, 3, 4, 5, 7, 0}, + {6, 7, 0, 0, 0, 0, 0, 0}, {0, 6, 7, 0, 0, 0, 0, 0}, + {1, 6, 7, 0, 0, 0, 0, 0}, {0, 1, 6, 7, 0, 0, 0, 0}, + {2, 6, 7, 0, 0, 0, 0, 0}, {0, 2, 6, 7, 0, 0, 0, 0}, + {1, 2, 6, 7, 0, 0, 0, 0}, {0, 1, 2, 6, 7, 0, 0, 0}, + {3, 6, 7, 0, 0, 0, 0, 0}, {0, 3, 6, 7, 0, 0, 0, 0}, + {1, 3, 6, 7, 0, 0, 0, 0}, {0, 1, 3, 6, 7, 0, 0, 0}, + {2, 3, 6, 7, 0, 0, 0, 0}, {0, 2, 3, 6, 7, 0, 0, 0}, + {1, 2, 3, 6, 7, 0, 0, 0}, {0, 1, 2, 3, 6, 7, 0, 0}, + {4, 6, 7, 0, 0, 0, 0, 0}, {0, 4, 6, 7, 0, 0, 0, 0}, + {1, 4, 6, 7, 0, 0, 0, 0}, {0, 1, 4, 6, 7, 0, 0, 0}, + {2, 4, 6, 7, 0, 0, 0, 0}, {0, 2, 4, 6, 7, 0, 0, 0}, + {1, 2, 4, 6, 7, 0, 0, 0}, {0, 1, 2, 4, 6, 7, 0, 0}, + {3, 4, 6, 7, 0, 0, 0, 0}, {0, 3, 4, 6, 7, 0, 0, 0}, + {1, 3, 4, 6, 7, 0, 0, 0}, {0, 1, 3, 4, 6, 7, 0, 0}, + {2, 3, 4, 6, 7, 0, 0, 0}, {0, 2, 3, 4, 6, 7, 0, 0}, + {1, 2, 3, 4, 6, 7, 0, 0}, {0, 1, 2, 3, 4, 6, 7, 0}, + {5, 6, 7, 0, 0, 0, 0, 0}, {0, 5, 6, 7, 0, 0, 0, 0}, + {1, 5, 6, 7, 0, 0, 0, 0}, {0, 1, 5, 6, 7, 0, 0, 0}, + {2, 5, 6, 7, 0, 0, 0, 0}, {0, 2, 5, 6, 7, 0, 0, 0}, + {1, 2, 5, 6, 7, 0, 0, 0}, {0, 1, 2, 5, 6, 7, 0, 0}, + {3, 5, 6, 7, 0, 0, 0, 0}, {0, 3, 5, 6, 7, 0, 0, 0}, + {1, 3, 5, 6, 7, 0, 0, 0}, {0, 1, 3, 5, 6, 7, 0, 0}, + {2, 3, 5, 6, 7, 0, 0, 0}, {0, 2, 3, 5, 6, 7, 0, 0}, + {1, 2, 3, 5, 6, 7, 0, 0}, {0, 1, 2, 3, 5, 6, 7, 0}, + {4, 5, 6, 7, 0, 0, 0, 0}, {0, 4, 5, 6, 7, 0, 0, 0}, + {1, 4, 5, 6, 7, 0, 0, 0}, {0, 1, 4, 5, 6, 7, 0, 0}, + {2, 4, 5, 6, 7, 0, 0, 0}, {0, 2, 4, 5, 6, 7, 0, 0}, + {1, 2, 4, 5, 6, 7, 0, 0}, {0, 1, 2, 4, 5, 6, 7, 0}, + {3, 4, 5, 6, 7, 0, 0, 0}, {0, 3, 4, 5, 6, 7, 0, 0}, + {1, 3, 4, 5, 6, 7, 0, 0}, {0, 1, 3, 4, 5, 6, 7, 0}, + {2, 3, 4, 5, 6, 7, 0, 0}, {0, 2, 3, 4, 5, 6, 7, 0}, + {1, 2, 3, 4, 5, 6, 7, 0}, {0, 1, 2, 3, 4, 5, 6, 7}, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/packing.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/packing.c new file mode 100644 index 0000000000..26da273856 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/packing.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include + +#include "common.h" +#include "packing.h" +#include "poly.h" +#include "polyvec.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_unpack_hints MLD_ADD_PARAM_SET(mld_unpack_hints) +/* End of parameter set namespacing */ + +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +{ + unsigned int i; + + mld_memcpy(pk, rho, MLDSA_SEEDBYTES); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt1_pack(pk + MLDSA_SEEDBYTES + i * MLDSA_POLYT1_PACKEDBYTES, + &t1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +{ + unsigned int i; + + mld_memcpy(rho, pk, MLDSA_SEEDBYTES); + pk += MLDSA_SEEDBYTES; + + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt1_unpack(&t1->vec[i], pk + i * MLDSA_POLYT1_PACKEDBYTES); + } +} + +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +{ + mld_memcpy(sk, rho, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, key, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, tr, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_pack_eta(sk, s1); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_eta(sk, s2); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_t0(sk, t0); +} + +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +{ + mld_memcpy(rho, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(key, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(tr, sk, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_unpack_eta(s1, sk); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_eta(s2, sk); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_t0(t0, sk); +} + +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +{ + unsigned int i, j, k; + + mld_memcpy(sig, c, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + /* skip z component - packed via mld_pack_sig_z */ + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + /* Encode hints h */ + + /* The final section of sig[] is MLDSA_POLYVECH_PACKEDBYTES long, where + * MLDSA_POLYVECH_PACKEDBYTES = MLDSA_OMEGA + MLDSA_K + * + * The first OMEGA bytes record the index numbers of the coefficients + * that are not equal to 0 + * + * The final K bytes record a running tally of the number of hints + * coming from each of the K polynomials in h. + * + * The pre-condition tells us that number_of_hints <= OMEGA, so some + * bytes may not be written, so we initialize all of them to zero + * to start. + */ + mld_memset(sig, 0, MLDSA_POLYVECH_PACKEDBYTES); + + k = 0; + /* For each polynomial in h... */ + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* For each coefficient in that polynomial, record it as as hint */ + /* if its value is not zero */ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + assigns(j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(j <= MLDSA_N) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* The reference implementation implicitly relies on the total */ + /* number of hints being less than OMEGA, assuming h is valid. */ + /* In mldsa-native, we check this explicitly to ease proof of */ + /* type safety. */ + if (h->vec[i].coeffs[j] != 0 && k < number_of_hints) + { + /* The enclosing if condition AND the loop invariant infer */ + /* that k < MLDSA_OMEGA, so writing to sig[k] is safe and k */ + /* can be incremented. */ + sig[k++] = (uint8_t)j; + } + } + /* Having recorded all the hints for this polynomial, also */ + /* record the running tally into the correct "slot" for that */ + /* coefficient in the final K bytes */ + sig[MLDSA_OMEGA + i] = (uint8_t)k; + } +} + +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +{ + sig += MLDSA_CTILDEBYTES; + sig += i * MLDSA_POLYZ_PACKEDBYTES; + mld_polyz_pack(sig, zi); +} + +/************************************************* + * Name: mld_unpack_hints + * + * Description: Unpack raw hint bytes into a polyveck + * struct + * + * Arguments: - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]: + * raw hint bytes + * + * Returns 1 in case of malformed hints; otherwise 0. + **************************************************/ +static int mld_unpack_hints( + mld_polyveck *h, const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(packed_hints, MLDSA_POLYVECH_PACKEDBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + /* All returned coefficients are either 0 or 1 */ + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +) +{ + unsigned int i, j; + unsigned int old_hint_count; + + /* Set all coefficients of all polynomials to 0. */ + /* Only those that are actually non-zero hints will */ + /* be overwritten below. */ + mld_memset(h, 0, sizeof(mld_polyveck)); + + old_hint_count = 0; + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + /* Grab the hint count for the i'th polynomial */ + const unsigned int new_hint_count = packed_hints[MLDSA_OMEGA + i]; + + /* new_hint_count must increase or stay the same, but also remain */ + /* less than or equal to MLDSA_OMEGA */ + if (new_hint_count < old_hint_count || new_hint_count > MLDSA_OMEGA) + { + /* Error - new_hint_count is invalid */ + return 1; + } + + /* If new_hint_count == old_hint_count, then this polynomial has */ + /* zero hints, so this loop executes zero times and we move */ + /* straight on to the next polynomial. */ + for (j = old_hint_count; j < new_hint_count; ++j) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + const uint8_t this_hint_index = packed_hints[j]; + + /* Coefficients must be ordered for strong unforgeability */ + if (j > old_hint_count && this_hint_index <= packed_hints[j - 1]) + { + return 1; + } + h->vec[i].coeffs[this_hint_index] = 1; + } + + old_hint_count = new_hint_count; + } + + /* Extra indices must be zero for strong unforgeability */ + for (j = old_hint_count; j < MLDSA_OMEGA; ++j) + __loop__( + invariant(j <= MLDSA_OMEGA) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + if (packed_hints[j] != 0) + { + return 1; + } + } + + return 0; +} + +MLD_INTERNAL_API +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +{ + mld_memcpy(c, sig, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + mld_polyvecl_unpack_z(z, sig); + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + return mld_unpack_hints(h, sig); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_unpack_hints diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/packing.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/packing.h new file mode 100644 index 0000000000..19095d08cd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/packing.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PACKING_H +#define MLD_PACKING_H + +#include +#include "polyvec.h" + +#define mld_pack_pk MLD_NAMESPACE_KL(pack_pk) +/************************************************* + * Name: mld_pack_pk + * + * Description: Bit-pack public key pk = (rho, t1). + * + * Arguments: - uint8_t pk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const mld_polyveck *t1: pointer to vector t1 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) +); + + +#define mld_pack_sk MLD_NAMESPACE_KL(pack_sk) +/************************************************* + * Name: mld_pack_sk + * + * Description: Bit-pack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - uint8_t sk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const uint8_t tr[]: byte array containing tr + * - const uint8_t key[]: byte array containing key + * - const mld_polyveck *t0: pointer to vector t0 + * - const mld_polyvecl *s1: pointer to vector s1 + * - const mld_polyveck *s2: pointer to vector s2 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +__contract__( + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + requires(forall(k2, 0, MLDSA_K, + array_abs_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) +); + + +#define mld_pack_sig_c_h MLD_NAMESPACE_KL(pack_sig_c_h) +/************************************************* + * Name: mld_pack_sig_c_h + * + * Description: Bit-pack c and h component of sig = (c, z, h). + * The z component is packed separately using mld_pack_sig_z. + * + * Arguments: - uint8_t sig[]: output byte array + * - const uint8_t *c: pointer to challenge hash length + * MLDSA_SEEDBYTES + * - const mld_polyveck *h: pointer to hint vector h + * - const unsigned int number_of_hints: total + * hints in *h + * + * Note that the number_of_hints argument is not present + * in the reference implementation. It is added here to ease + * proof of type safety. + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + requires(number_of_hints <= MLDSA_OMEGA) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_pack_sig_z MLD_NAMESPACE_KL(pack_sig_z) +/************************************************* + * Name: mld_pack_sig_z + * + * Description: Bit-pack single polynomial of z component of sig = (c, z, h). + * The c and h components are packed separately using + * mld_pack_sig_c_h. + * + * Arguments: - uint8_t sig[]: output byte array + * - const mld_poly *zi: pointer to a single polynomial in z + * - const unsigned int i: index of zi in vector z + * + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(zi, sizeof(mld_poly))) + requires(i < MLDSA_L) + requires(array_bound(zi->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_unpack_pk MLD_NAMESPACE_KL(unpack_pk) +/************************************************* + * Name: mld_unpack_pk + * + * Description: Unpack public key pk = (rho, t1). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const mld_polyveck *t1: pointer to output vector t1 + * - uint8_t pk[]: byte array containing bit-packed pk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) +); + + +#define mld_unpack_sk MLD_NAMESPACE_KL(unpack_sk) +/************************************************* + * Name: mld_unpack_sk + * + * Description: Unpack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const uint8_t tr[]: output byte array for tr + * - const uint8_t key[]: output byte array for key + * - const mld_polyveck *t0: pointer to output vector t0 + * - const mld_polyvecl *s1: pointer to output vector s1 + * - const mld_polyveck *s2: pointer to output vector s2 + * - uint8_t sk[]: byte array containing bit-packed sk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +__contract__( + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(key, MLDSA_SEEDBYTES)) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(s1, sizeof(mld_polyvecl))) + assigns(memory_slice(s2, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_unpack_sig MLD_NAMESPACE_KL(unpack_sig) +/************************************************* + * Name: mld_unpack_sig + * + * Description: Unpack signature sig = (c, z, h). + * + * Arguments: - uint8_t *c: pointer to output challenge hash + * - mld_polyvecl *z: pointer to output vector z + * - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t sig[]: byte array containing + * bit-packed signature + * + * Returns 1 in case of malformed signature; otherwise 0. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(c, MLDSA_CTILDEBYTES)) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(z->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +); +#endif /* !MLD_PACKING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/params.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/params.h new file mode 100644 index 0000000000..c67d2a33fb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/params.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PARAMS_H +#define MLD_PARAMS_H + +#define MLDSA_SEEDBYTES 32 +#define MLDSA_CRHBYTES 64 +#define MLDSA_TRBYTES 64 +#define MLDSA_RNDBYTES 32 +#define MLDSA_N 256 +#define MLDSA_Q 8380417 +#define MLDSA_Q_HALF ((MLDSA_Q + 1) / 2) +#define MLDSA_D 13 + +#if MLD_CONFIG_PARAMETER_SET == 44 + +#define MLDSA_K 4 +#define MLDSA_L 4 +#define MLDSA_ETA 2 +#define MLDSA_TAU 39 +#define MLDSA_BETA 78 +#define MLDSA_GAMMA1 (1 << 17) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 88) +#define MLDSA_OMEGA 80 +#define MLDSA_CTILDEBYTES 32 +#define MLDSA_POLYZ_PACKEDBYTES 576 +#define MLDSA_POLYW1_PACKEDBYTES 192 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#elif MLD_CONFIG_PARAMETER_SET == 65 + +#define MLDSA_K 6 +#define MLDSA_L 5 +#define MLDSA_ETA 4 +#define MLDSA_TAU 49 +#define MLDSA_BETA 196 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 55 +#define MLDSA_CTILDEBYTES 48 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 128 + +#elif MLD_CONFIG_PARAMETER_SET == 87 + +#define MLDSA_K 8 +#define MLDSA_L 7 +#define MLDSA_ETA 2 +#define MLDSA_TAU 60 +#define MLDSA_BETA 120 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 75 +#define MLDSA_CTILDEBYTES 64 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ + +#define MLDSA_POLYT1_PACKEDBYTES 320 +#define MLDSA_POLYT0_PACKEDBYTES 416 +#define MLDSA_POLYVECH_PACKEDBYTES (MLDSA_OMEGA + MLDSA_K) + +#define MLDSA_CRYPTO_PUBLICKEYBYTES \ + (MLDSA_SEEDBYTES + MLDSA_K * MLDSA_POLYT1_PACKEDBYTES) +#define MLDSA_CRYPTO_SECRETKEYBYTES \ + (2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + MLDSA_L * MLDSA_POLYETA_PACKEDBYTES + \ + MLDSA_K * MLDSA_POLYETA_PACKEDBYTES + MLDSA_K * MLDSA_POLYT0_PACKEDBYTES) +#define MLDSA_CRYPTO_BYTES \ + (MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES + \ + MLDSA_POLYVECH_PACKEDBYTES) + +#endif /* !MLD_PARAMS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/poly.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/poly.c new file mode 100644 index 0000000000..e40534e773 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/poly.c @@ -0,0 +1,973 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "common.h" +#include "ct.h" +#include "debug.h" +#include "poly.h" +#include "reduce.h" +#include "rounding.h" +#include "symmetric.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +#include "zetas.inc" + +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + { + a->coeffs[i] = mld_reduce32(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_STATIC_TESTABLE void mld_poly_caddq_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + ) + { + a->coeffs[i] = mld_caddq(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_POLY_CADDQ) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_poly_caddq_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + mld_poly_caddq_c(a); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1])) + invariant(forall(k2, 0, i, r->coeffs[k2] < MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k2, 0, i, r->coeffs[k2] >= INT32_MIN)) + ) + { + r->coeffs[i] = r->coeffs[i] + b->coeffs[i]; + } +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(r->coeffs, 0, i, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + ) + { + r->coeffs[i] = r->coeffs[i] - b->coeffs[i]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N; i++) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))) + { + /* Reference: uses a left shift by MLDSA_D which is undefined behaviour in + * C90/C99 + */ + a->coeffs[i] *= (1 << MLDSA_D); + } + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + + +static MLD_INLINE int32_t mld_fqmul(int32_t a, int32_t b) +__contract__( + requires(b > -MLDSA_Q_HALF && b < MLDSA_Q_HALF) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* Bounds: We argue in mld_montgomery_reduce() that the reult + * of Montgomery reduction is < MLDSA_Q if the input is smaller + * than 2^31 * MLDSA_Q in absolute value. Indeed, we have: + * + * |a * b| = |a| * |b| + * < 2^31 * MLDSA_Q_HALF + * < 2^31 * MLDSA_Q + */ + return mld_montgomery_reduce((int64_t)a * (int64_t)b); +} + +/* mld_ntt_butterfly_block() + * + * Computes a block CT butterflies with a fixed twiddle factor, + * using Montgomery multiplication. + * + * Parameters: + * - r: Pointer to base of polynomial (_not_ the base of butterfly block) + * - zeta: Twiddle factor to use for the butterfly. This must be in + * Montgomery form and signed canonical. + * - start: Offset to the beginning of the butterfly block + * - len: Index difference between coefficients subject to a butterfly + * - bound: Ghost variable describing coefficient bound: Prior to `start`, + * coefficients must be bound by `bound + MLDSA_Q`. Post `start`, + * they must be bound by `bound`. + * When this function returns, output coefficients in the index range + * [start, start+2*len) have bound bumped to `bound + MLDSA_Q`. + * Example: + * - start=8, len=4 + * This would compute the following four butterflies + * 8 -- 12 + * 9 -- 13 + * 10 -- 14 + * 11 -- 15 + * - start=4, len=2 + * This would compute the following two butterflies + * 4 -- 6 + * 5 -- 7 + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_butterfly_block(int32_t r[MLDSA_N], + const int32_t zeta, + const unsigned start, + const unsigned len, + const unsigned bound) +__contract__( + requires(start < MLDSA_N) + requires(1 <= len && len <= MLDSA_N / 2 && start + 2 * len <= MLDSA_N) + requires(0 <= bound && bound < INT32_MAX - MLDSA_Q) + requires(-MLDSA_Q_HALF < zeta && zeta < MLDSA_Q_HALF) + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, start, bound + MLDSA_Q)) + requires(array_abs_bound(r, start, MLDSA_N, bound)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, start + 2*len, bound + MLDSA_Q)) + ensures(array_abs_bound(r, start + 2 * len, MLDSA_N, bound))) +{ + /* `bound` is a ghost variable only needed in the CBMC specification */ + unsigned j; + ((void)bound); + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + /* + * Coefficients are updated in strided pairs, so the bounds for the + * intermediate states alternate twice between the old and new bound + */ + invariant(array_abs_bound(r, 0, j, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, bound)) + invariant(array_abs_bound(r, start + len, j + len, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j + len, MLDSA_N, bound))) + { + int32_t t; + t = mld_fqmul(r[j + len], zeta); + r[j + len] = r[j] - t; + r[j] = r[j] + t; + } +} + +/* mld_ntt_layer() + * + * Compute one layer of forward NTT + * + * Parameters: + * - r: Pointer to base of polynomial + * - layer: Indicates which layer is being applied. + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_layer(int32_t r[MLDSA_N], const unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (layer + 1) * MLDSA_Q))) +{ + unsigned start, k, len; + /* Twiddle factors for layer n are at indices 2^(n-1)..2^n-1. */ + k = 1u << (layer - 1); + len = (unsigned)MLDSA_N >> layer; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start < MLDSA_N + 2 * len) + invariant(k <= MLDSA_N) + invariant(2 * len * k == start + MLDSA_N) + invariant(array_abs_bound(r, 0, start, layer * MLDSA_Q + MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, layer * MLDSA_Q))) + { + int32_t zeta = mld_zetas[k++]; + mld_ntt_butterfly_block(r, zeta, start, len, layer * MLDSA_Q); + } +} + +MLD_STATIC_TESTABLE void mld_poly_ntt_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +) +{ + unsigned int layer; + int32_t *r; + + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + r = a->coeffs; + + for (layer = 1; layer < 9; layer++) + __loop__( + invariant(1 <= layer && layer <= 9) + invariant(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + ) + { + mld_ntt_layer(r, layer); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_NTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_ntt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_NTT */ + mld_poly_ntt_c(a); +} + +/************************************************* + * Name: mld_fqscale + * + * Description: Scales a field element by mont/256 , i.e., performs Montgomery + * multiplication by mont^2/256. + * Input is expected to have absolute value smaller than + * 256 * MLDSA_Q. + * Output has absolute value smaller than MLD_INTT_BOUND. + * + * Arguments: - int32_t a: Field element to be scaled. + **************************************************/ +static MLD_INLINE int32_t mld_fqscale(int32_t a) +__contract__( + requires(a > -256*MLDSA_Q && a < 256*MLDSA_Q) + ensures(return_value > -MLD_INTT_BOUND && return_value < MLD_INTT_BOUND) +) +{ + /* check-magic: 41978 == pow(2,64-8,MLDSA_Q) */ + const int32_t f = 41978; + /* Bounds: MLD_INTT_BOUND is MLDSA_Q, so the bounds reasoning is just + * a special case of that in mld_fqmul(). */ + return mld_montgomery_reduce((int64_t)a * f); +} + +/* Reference: Embedded into `invntt_tomont()` in the reference implementation + * @[REF] */ +static MLD_INLINE void mld_invntt_layer(int32_t r[MLDSA_N], unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> (layer - 1)) * MLDSA_Q))) +{ + unsigned start, k, len; + len = (unsigned)MLDSA_N >> layer; + k = (1u << layer) - 1; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start <= MLDSA_N && k <= 255) + invariant(2 * len * k + start == 2 * MLDSA_N - 2 * len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + unsigned j; + int32_t zeta = -mld_zetas[k--]; + + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, j, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, (MLDSA_N >> layer) * MLDSA_Q)) + invariant(array_abs_bound(r, start + len, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + int32_t t = r[j]; + r[j] = t + r[j + len]; + r[j + len] = t - r[j + len]; + r[j + len] = mld_fqmul(r[j + len], zeta); + } + } +} + +MLD_STATIC_TESTABLE void mld_poly_invntt_tomont_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +) +{ + unsigned int layer, j; + int32_t *r; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + r = a->coeffs; + for (layer = 8; layer >= 1; layer--) + __loop__( + invariant(layer <= 8) + /* Absolute bounds increase from 1Q before layer 8 */ + /* up to 256Q after layer 1 */ + invariant(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + mld_invntt_layer(r, layer); + } + + /* Coefficient bounds are now at 256Q. We now scale by mont / 256, + * i.e., compute the Montgomery multiplication by mont^2 / 256. + * mont corrects the mont^-1 factor introduced in the basemul. + * 1/256 performs that scaling of the inverse NTT. + * The reduced value is bounded by MLD_INTT_BOUND in absolute + * value.*/ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + invariant(j <= MLDSA_N) + invariant(array_abs_bound(r, 0, j, MLD_INTT_BOUND)) + invariant(array_abs_bound(r, j, MLDSA_N, MLDSA_N * MLDSA_Q)) + ) + { + r[j] = mld_fqscale(r[j]); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); +} + + +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_INTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_intt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_INTT */ + mld_poly_invntt_tomont_c(a); +} + +MLD_STATIC_TESTABLE void mld_poly_pointwise_montgomery_c(mld_poly *c, + const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_abs_bound(c->coeffs, 0, i, MLDSA_Q)) + ) + { + c->coeffs[i] = mld_montgomery_reduce((int64_t)a->coeffs[i] * b->coeffs[i]); + } + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +{ +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + ret = mld_poly_pointwise_montgomery_native(c->coeffs, a->coeffs, b->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + mld_poly_pointwise_montgomery_c(c, a, b); +} + +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, 0, i, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + invariant(array_bound(a1->coeffs, 0, i, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) + ) + { + mld_power2round(&a0->coeffs[i], &a1->coeffs[i], a->coeffs[i]); + } + + mld_assert_bound(a0->coeffs, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +#ifndef MLD_POLY_UNIFORM_NBLOCKS +#define MLD_POLY_UNIFORM_NBLOCKS \ + ((768 + MLD_STREAM128_BLOCKBYTES - 1) / MLD_STREAM128_BLOCKBYTES) +#endif +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +MLD_STATIC_TESTABLE unsigned int mld_rej_uniform_c(int32_t *a, + unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ + unsigned int ctr, pos; + uint32_t t; + mld_assert_bound(a, offset, 0, MLDSA_Q); + + ctr = offset; + pos = 0; + /* pos + 3 cannot overflow due to the assumption + buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) */ + while (ctr < target && pos + 3 <= buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_bound(a, 0, ctr, 0, MLDSA_Q))) + { + t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + a[ctr++] = (int32_t)t; + } + } + + mld_assert_bound(a, ctr, 0, MLDSA_Q); + + return ctr; +} +/************************************************* + * Name: mld_rej_uniform + * + * Description: Sample uniformly random coefficients in [0, MLDSA_Q-1] by + * performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes (must be + * multiple of 3) + * + * Returns number of sampled coefficients. Can be smaller than len if not enough + * random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +static unsigned int mld_rej_uniform(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) + int ret; + mld_assert_bound(a, offset, 0, MLDSA_Q); + if (offset == 0) + { + ret = mld_rej_uniform_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_bound(a, res, 0, MLDSA_Q); + return res; + } + } +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + + return mld_rej_uniform_c(a, target, offset, buf, buflen); +} + +/* Reference: poly_uniform() in the reference implementation @[REF]. + * - Simplified from reference by removing buffer tail handling + * since buflen % 3 = 0 always holds true (MLD_STREAM128_BLOCKBYTES + * = 168). + * - Modified rej_uniform interface to track offset directly. + * - Pass nonce packed in the extended seed array instead of a third + * argument. + * */ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +{ + unsigned int ctr; + unsigned int buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + MLD_ALIGN uint8_t buf[MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES]; + mld_xof128_ctx state; + + mld_xof128_init(&state); + mld_xof128_absorb_once(&state, seed, MLDSA_SEEDBYTES + 2); + mld_xof128_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, 0, buf, buflen); + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(a, sizeof(mld_poly)), object_whole(buf)) + invariant(ctr <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, ctr, 0, MLDSA_Q)) + invariant(state.pos <= SHAKE128_RATE) + ) + { + mld_xof128_squeezeblocks(buf, 1, &state); + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, ctr, buf, buflen); + } + mld_xof128_release(&state); + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof128_x4_ctx state; + unsigned buflen; + + mld_xof128_x4_init(&state); + mld_xof128_x4_absorb(&state, seed, MLDSA_SEEDBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_NBLOCKS. + * This should generate the matrix entries with high probability. + */ + + mld_xof128_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all matrix entries have been generated, squeeze + * one more block a time until we're done. + */ + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, object_whole(buf), + memory_slice(vec0, sizeof(mld_poly)), memory_slice(vec1, sizeof(mld_poly)), + memory_slice(vec2, sizeof(mld_poly)), memory_slice(vec3, sizeof(mld_poly))) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_bound(vec0->coeffs, 0, ctr[0], 0, MLDSA_Q)) + invariant(array_bound(vec1->coeffs, 0, ctr[1], 0, MLDSA_Q)) + invariant(array_bound(vec2->coeffs, 0, ctr[2], 0, MLDSA_Q)) + invariant(array_bound(vec3->coeffs, 0, ctr[3], 0, MLDSA_Q))) + { + mld_xof128_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + mld_xof128_x4_release(&state); + + mld_assert_bound(vec0->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec1->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec2->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec3->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0) & 0xFF); + r[5 * i + 1] = + (uint8_t)(((a->coeffs[4 * i + 0] >> 8) | (a->coeffs[4 * i + 1] << 2)) & + 0xFF); + r[5 * i + 2] = + (uint8_t)(((a->coeffs[4 * i + 1] >> 6) | (a->coeffs[4 * i + 2] << 4)) & + 0xFF); + r[5 * i + 3] = + (uint8_t)(((a->coeffs[4 * i + 2] >> 4) | (a->coeffs[4 * i + 3] << 6)) & + 0xFF); + r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, 0, 1 << 10))) + { + r->coeffs[4 * i + 0] = + ((a[5 * i + 0] >> 0) | ((int32_t)a[5 * i + 1] << 8)) & 0x3FF; + r->coeffs[4 * i + 1] = + ((a[5 * i + 1] >> 2) | ((int32_t)a[5 * i + 2] << 6)) & 0x3FF; + r->coeffs[4 * i + 2] = + ((a[5 * i + 2] >> 4) | ((int32_t)a[5 * i + 3] << 4)) & 0x3FF; + r->coeffs[4 * i + 3] = + ((a[5 * i + 3] >> 6) | ((int32_t)a[5 * i + 4] << 2)) & 0x3FF; + } + + mld_assert_bound(r->coeffs, MLDSA_N, 0, 1 << 10); +} + +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[8]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* Safety: a->coeffs[i] <= (1 << (MLDSA_D - 1) as they are output of + * power2round, hence, these casts are safe. */ + t[0] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 0]); + t[1] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 1]); + t[2] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 2]); + t[3] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 3]); + t[4] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 4]); + t[5] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 5]); + t[6] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 6]); + t[7] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 7]); + + r[13 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[13 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[13 * i + 1] |= (uint8_t)((t[1] << 5) & 0xFF); + r[13 * i + 2] = (uint8_t)((t[1] >> 3) & 0xFF); + r[13 * i + 3] = (uint8_t)((t[1] >> 11) & 0xFF); + r[13 * i + 3] |= (uint8_t)((t[2] << 2) & 0xFF); + r[13 * i + 4] = (uint8_t)((t[2] >> 6) & 0xFF); + r[13 * i + 4] |= (uint8_t)((t[3] << 7) & 0xFF); + r[13 * i + 5] = (uint8_t)((t[3] >> 1) & 0xFF); + r[13 * i + 6] = (uint8_t)((t[3] >> 9) & 0xFF); + r[13 * i + 6] |= (uint8_t)((t[4] << 4) & 0xFF); + r[13 * i + 7] = (uint8_t)((t[4] >> 4) & 0xFF); + r[13 * i + 8] = (uint8_t)((t[4] >> 12) & 0xFF); + r[13 * i + 8] |= (uint8_t)((t[5] << 1) & 0xFF); + r[13 * i + 9] = (uint8_t)((t[5] >> 7) & 0xFF); + r[13 * i + 9] |= (uint8_t)((t[6] << 6) & 0xFF); + r[13 * i + 10] = (uint8_t)((t[6] >> 2) & 0xFF); + r[13 * i + 11] = (uint8_t)((t[6] >> 10) & 0xFF); + r[13 * i + 11] |= (uint8_t)((t[7] << 3) & 0xFF); + r[13 * i + 12] = (uint8_t)((t[7] >> 5) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + { + r->coeffs[8 * i + 0] = a[13 * i + 0]; + r->coeffs[8 * i + 0] |= (int32_t)a[13 * i + 1] << 8; + r->coeffs[8 * i + 0] &= 0x1FFF; + + r->coeffs[8 * i + 1] = a[13 * i + 1] >> 5; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 2] << 3; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 3] << 11; + r->coeffs[8 * i + 1] &= 0x1FFF; + + r->coeffs[8 * i + 2] = a[13 * i + 3] >> 2; + r->coeffs[8 * i + 2] |= (int32_t)a[13 * i + 4] << 6; + r->coeffs[8 * i + 2] &= 0x1FFF; + + r->coeffs[8 * i + 3] = a[13 * i + 4] >> 7; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 5] << 1; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 6] << 9; + r->coeffs[8 * i + 3] &= 0x1FFF; + + r->coeffs[8 * i + 4] = a[13 * i + 6] >> 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 7] << 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 8] << 12; + r->coeffs[8 * i + 4] &= 0x1FFF; + + r->coeffs[8 * i + 5] = a[13 * i + 8] >> 1; + r->coeffs[8 * i + 5] |= (int32_t)a[13 * i + 9] << 7; + r->coeffs[8 * i + 5] &= 0x1FFF; + + r->coeffs[8 * i + 6] = a[13 * i + 9] >> 6; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 10] << 2; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 11] << 10; + r->coeffs[8 * i + 6] &= 0x1FFF; + + r->coeffs[8 * i + 7] = a[13 * i + 11] >> 3; + r->coeffs[8 * i + 7] |= (int32_t)a[13 * i + 12] << 5; + r->coeffs[8 * i + 7] &= 0x1FFF; + + r->coeffs[8 * i + 0] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 7]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +MLD_STATIC_TESTABLE uint32_t mld_poly_chknorm_c(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == array_abs_bound(a->coeffs, 0, i, B)) + ) + { + /* + * Since we know that -MLD_REDUCE32_RANGE_MAX <= a < MLD_REDUCE32_RANGE_MAX, + * and B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX, to check if + * -B < (a mod± MLDSA_Q) < B, it suffices to check if -B < a < B. + * + * We prove this to be true using the following CBMC assertions. + * a ==> b expressed as !a || b to also allow run-time assertion. + */ + mld_assert(a->coeffs[i] < B || a->coeffs[i] - MLDSA_Q <= -B); + mld_assert(a->coeffs[i] > -B || a->coeffs[i] + MLDSA_Q >= B); + + /* Reference: Leaks which coefficient violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + + /* if (abs(a[i]) >= B) */ + t |= mld_ct_cmask_neg_i32(B - 1 - mld_ct_abs_i32(a->coeffs[i])); + } + + return t; +} + +/* Reference: explicitly checks the bound B to be <= (MLDSA_Q - 1) / 8). + * This is unnecessary as it's always a compile-time constant. + * We instead model it as a precondition. + * Checking the bound is performed using a conditional arguing + * that it is okay to leak which coefficient violates the bound (while the + * coefficient itself must remain secret). + * We instead perform everything in constant-time. + * Also it is sufficient to check that it is smaller than + * MLDSA_Q - MLD_REDUCE32_RANGE_MAX > (MLDSA_Q - 1) / 8). + */ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +{ +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) + int ret; + int success; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + /* The native backend returns 0 if all coefficients are within the bound, + * 1 if at least one coefficient exceeds the bound, and + * -1 (MLD_NATIVE_FUNC_FALLBACK) if the platform does not have the + * required capabilities to run the native function. + */ + ret = mld_poly_chknorm_native(a->coeffs, B); + + success = (ret != MLD_NATIVE_FUNC_FALLBACK); + /* Constant-time: It would be fine to leak the return value of chknorm + * entirely (as it is fine to leak if any coefficient exceeded the bound or + * not). However, it is cleaner to perform declassification in sign.c. + * Hence, here we only declassify if the native function returned + * MLD_NATIVE_FUNC_FALLBACK or not (which solely depends on system + * capabilities). + */ + MLD_CT_TESTING_DECLASSIFY(&success, sizeof(int)); + if (success) + { + /* Convert 0 / 1 to 0 / 0xFFFFFFFF here */ + return 0U - (uint32_t)ret; + } +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + return mld_poly_chknorm_c(a, B); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ +MLD_EMPTY_CU(mld_poly) +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_POLY_UNIFORM_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/poly.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/poly.h new file mode 100644 index 0000000000..ff7710438e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/poly.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_H +#define MLD_POLY_H + +#include +#include "cbmc.h" +#include "common.h" +#include "reduce.h" +#include "rounding.h" + +/* Absolute exclusive upper bound for the output of the forward NTT */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) +/* Absolute exclusive upper bound for the output of the inverse NTT*/ +#define MLD_INTT_BOUND MLDSA_Q + +typedef struct +{ + int32_t coeffs[MLDSA_N]; +} MLD_ALIGN mld_poly; + +#define mld_poly_reduce MLD_NAMESPACE(poly_reduce) +/************************************************* + * Name: mld_poly_reduce + * + * Description: Inplace reduction of all coefficients of polynomial to + * representative in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) +); + +#define mld_poly_caddq MLD_NAMESPACE(poly_caddq) +/************************************************* + * Name: mld_poly_caddq + * + * Description: For all coefficients of in/out polynomial add MLDSA_Q if + * coefficient is negative. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_add MLD_NAMESPACE(poly_add) +/************************************************* + * Name: mld_poly_add + * + * Description: Add polynomials. No modular reduction is performed. + * + * Arguments: - r: Pointer to input-output polynomial to be added to. + * - b: Pointer to input polynomial that should be added + * to r. Must be disjoint from r. + **************************************************/ + +/* + * NOTE: The reference implementation uses a 3-argument poly_add. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(forall(k0, 0, MLDSA_N, (int64_t) r->coeffs[k0] + b->coeffs[k0] < MLD_REDUCE32_DOMAIN_MAX)) + requires(forall(k1, 0, MLDSA_N, (int64_t) r->coeffs[k1] + b->coeffs[k1] >= INT32_MIN)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(forall(k2, 0, MLDSA_N, r->coeffs[k2] == old(*r).coeffs[k2] + b->coeffs[k2])) + ensures(forall(k3, 0, MLDSA_N, r->coeffs[k3] < MLD_REDUCE32_DOMAIN_MAX)) + ensures(forall(k4, 0, MLDSA_N, r->coeffs[k4] >= INT32_MIN)) +); + +#define mld_poly_sub MLD_NAMESPACE(poly_sub) +/************************************************* + * Name: mld_poly_sub + * + * Description: Subtract polynomials. No modular reduction is + * performed. + * + * Arguments: - mld_poly *r: Pointer to input-output polynomial. + * - const mld_poly *b: Pointer to input polynomial that should be + * subtracted from r. Must be disjoint from r. + **************************************************/ +/* + * NOTE: The reference implementation uses a 3-argument poly_sub. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_Q)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) +); + +#define mld_poly_shiftl MLD_NAMESPACE(poly_shiftl) +/************************************************* + * Name: mld_poly_shiftl + * + * Description: Multiply polynomial by 2^MLDSA_D without modular reduction. + *Assumes input coefficients to be less than 2^{31-MLDSA_D} in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_ntt MLD_NAMESPACE(poly_ntt) +/************************************************* + * Name: mld_poly_ntt + * + * Description: Inplace forward NTT. Coefficients can grow by + * 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +); + + +#define mld_poly_invntt_tomont MLD_NAMESPACE(poly_invntt_tomont) +/************************************************* + * Name: mld_poly_invntt_tomont + * + * Description: Inplace inverse NTT and multiplication by 2^{32}. + * Input coefficients need to be less than MLDSA_Q in absolute + * value and output coefficients are bounded by + * MLD_INTT_BOUND. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +); + +#define mld_poly_pointwise_montgomery MLD_NAMESPACE(poly_pointwise_montgomery) +/************************************************* + * Name: mld_poly_pointwise_montgomery + * + * Description: Pointwise multiplication of polynomials in NTT domain + * representation and multiplication of resulting polynomial + * by 2^{-32}. + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const mld_poly *a: pointer to first input polynomial + * - const mld_poly *b: pointer to second input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + +#define mld_poly_power2round MLD_NAMESPACE(poly_power2round) +/************************************************* + * Name: mld_poly_power2round + * + * Description: For all coefficients c of the input polynomial, + * compute c0, c1 such that c mod MLDSA_Q = c1*2^MLDSA_D + c0 + * with -2^{MLDSA_D-1} < c0 <= 2^{MLDSA_D-1}. Assumes coefficients + *to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + *c1 + * - mld_poly *a0: pointer to output polynomial with coefficients + *c0 + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +__contract__( + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a0->coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) +); + +#define mld_poly_uniform MLD_NAMESPACE(poly_uniform) +/************************************************* + * Name: mld_poly_uniform + * + * Description: Sample polynomial with uniformly random coefficients + * in [0,MLDSA_Q-1] by performing rejection sampling on the + * output stream of SHAKE128(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_SEEDBYTES and the packed 2-byte nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES + 2)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +#define mld_poly_uniform_4x MLD_NAMESPACE(poly_uniform_4x) +/************************************************* + * Name: mld_poly_uniform_x4 + * + * Description: Generate four polynomials using rejection sampling + * on (pseudo-)uniformly random bytes sampled from a seed. + * + * Arguments: - mld_poly *vec0, *vec1, *vec2, *vec3: + * Pointers to 4 polynomials to be sampled. + * - uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]: + * Pointer consecutive array of seed buffers of size + * MLDSA_SEEDBYTES + 2 each, plus padding for alignment. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +__contract__( + requires(memory_no_alias(vec0, sizeof(mld_poly))) + requires(memory_no_alias(vec1, sizeof(mld_poly))) + requires(memory_no_alias(vec2, sizeof(mld_poly))) + requires(memory_no_alias(vec3, sizeof(mld_poly))) + requires(memory_no_alias(seed, 4 * MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2))) + assigns(memory_slice(vec0, sizeof(mld_poly))) + assigns(memory_slice(vec1, sizeof(mld_poly))) + assigns(memory_slice(vec2, sizeof(mld_poly))) + assigns(memory_slice(vec3, sizeof(mld_poly))) + ensures(array_bound(vec0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec1->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec2->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec3->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +#define mld_polyt1_pack MLD_NAMESPACE(polyt1_pack) +/************************************************* + * Name: mld_polyt1_pack + * + * Description: Bit-pack polynomial t1 with coefficients fitting in 10 bits. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(r, MLDSA_POLYT1_PACKEDBYTES)) +); + +#define mld_polyt1_unpack MLD_NAMESPACE(polyt1_unpack) +/************************************************* + * Name: mld_polyt1_unpack + * + * Description: Unpack polynomial t1 with 10-bit coefficients. + * Output coefficients are standard representatives. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT1_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, 0, 1 << 10)) +); + +#define mld_polyt0_pack MLD_NAMESPACE(polyt0_pack) +/************************************************* + * Name: mld_polyt0_pack + * + * Description: Bit-pack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + * 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) + assigns(memory_slice(r, MLDSA_POLYT0_PACKEDBYTES)) +); + + +#define mld_polyt0_unpack MLD_NAMESPACE(polyt0_unpack) +/************************************************* + * Name: mld_polyt0_unpack + * + * Description: Unpack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + *2^{MLDSA_D-1}]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT0_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) +); + +#define mld_poly_chknorm MLD_NAMESPACE(poly_chknorm) +/************************************************* + * Name: mld_poly_chknorm + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const mld_poly *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if norm is strictly smaller than + * B <= (MLDSA_Q - MLD_REDUCE32_RANGE_MAX) and 0xFFFFFFFF otherwise. + * + * Specification: The definition of this FIPS-204 requires signed canonical + * reduction prior to applying the bounds check. + * However, `-B < (a mod± MLDSA_Q) < B` is equivalent to + * `-B < a < B` under the assumption that + * `B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX` (cf. the assertion in + * the code). Hence, the present spec and implementation are + * correct without reduction. + * + **************************************************/ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +); + +#endif /* !MLD_POLY_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/poly_kl.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/poly_kl.c new file mode 100644 index 0000000000..7a319ca515 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/poly_kl.c @@ -0,0 +1,931 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "ct.h" +#include "debug.h" +#include "poly_kl.h" +#include "rounding.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_rej_eta MLD_ADD_PARAM_SET(mld_rej_eta) +#define mld_rej_eta_c MLD_ADD_PARAM_SET(mld_rej_eta_c) +#define mld_poly_decompose_c MLD_ADD_PARAM_SET(mld_poly_decompose_c) +#define mld_poly_use_hint_c MLD_ADD_PARAM_SET(mld_poly_use_hint_c) +#define mld_polyz_unpack_c MLD_ADD_PARAM_SET(mld_polyz_unpack_c) +/* End of parameter set namespacing */ + + +MLD_STATIC_TESTABLE +void mld_poly_decompose_c(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +) +{ + unsigned int i; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, i, MLDSA_N, 0, MLDSA_Q)) + invariant(array_bound(a1->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + invariant(array_abs_bound(a0->coeffs, 0, i, MLDSA_GAMMA2+1)) + ) + { + mld_decompose(&a0->coeffs[i], &a1->coeffs[i], a0->coeffs[i]); + } + + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +{ +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_88_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_32_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_DECOMPOSE_88 && MLD_CONFIG_PARAMETER_SET == \ + 44) && MLD_USE_NATIVE_POLY_DECOMPOSE_32 && (MLD_CONFIG_PARAMETER_SET \ + == 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_decompose_c(a1, a0); +} + +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(s <= i) + invariant(array_bound(h->coeffs, 0, i, 0, 2)) + ) + { + const unsigned int hint_bit = mld_make_hint(a0->coeffs[i], a1->coeffs[i]); + h->coeffs[i] = (int32_t)hint_bit; + s += hint_bit; + } + + mld_assert(s <= MLDSA_N); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + return s; +} + +MLD_STATIC_TESTABLE void mld_poly_use_hint_c(mld_poly *b, const mld_poly *a, + const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(b->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ) + { + b->coeffs[i] = mld_use_hint(a->coeffs[i], h->coeffs[i]); + } + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +{ +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_88_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_USE_HINT_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_32_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_USE_HINT_88 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLY_USE_HINT_32 && (MLD_CONFIG_PARAMETER_SET == \ + 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_use_hint_c(b, a, h); +} + +/************************************************* + * Name: mld_rej_eta + * + * Description: Sample uniformly random coefficients in [-MLDSA_ETA, MLDSA_ETA] + *by performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes + * + * Returns number of sampled coefficients. Can be smaller than target if not + *enough random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_eta()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +#if MLDSA_ETA == 2 +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 1 +#elif MLDSA_ETA == 4 +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 2 +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + +MLD_STATIC_TESTABLE unsigned int mld_rej_eta_c(int32_t *a, unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ + unsigned int ctr, pos; + int t_valid; + uint32_t t0, t1; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + ctr = offset; + pos = 0; + while (ctr < target && pos < buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_abs_bound(a, 0, ctr, MLDSA_ETA + 1)) + ) + { + t0 = buf[pos] & 0x0F; + t1 = buf[pos++] >> 4; + + /* Constant time: The inputs and outputs to the rejection sampling are + * secret. However, it is fine to leak which coefficients have been + * rejected. For constant-time testing, we declassify the result of + * the comparison. + */ +#if MLDSA_ETA == 2 + t_valid = t0 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 15 */ + { + t0 = t0 - (205 * t0 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t0; + } + t_valid = t1 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) /* t1 < 15 */ + { + t1 = t1 - (205 * t1 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t1; + } +#elif MLDSA_ETA == 4 + t_valid = t0 < 9; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 9 */ + { + a[ctr++] = 4 - (int32_t)t0; + } + t_valid = t1 < 9; /* t1 < 9 */ + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) + { + a[ctr++] = 4 - (int32_t)t1; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + } + + mld_assert_abs_bound(a, ctr, MLDSA_ETA + 1); + + return ctr; +} + +static unsigned int mld_rej_eta(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ +#if MLDSA_ETA == 2 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta2_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#elif MLDSA_ETA == 4 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta4_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#endif /* !(MLDSA_ETA == 2 && MLD_USE_NATIVE_REJ_UNIFORM_ETA2) && MLDSA_ETA == \ + 4 && MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + + return mld_rej_eta_c(a, target, offset, buf, buflen); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_ETA_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof256_x4_ctx state; + unsigned buflen; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = nonce0; + extseed[1][MLDSA_CRHBYTES] = nonce1; + extseed[2][MLDSA_CRHBYTES] = nonce2; + extseed[3][MLDSA_CRHBYTES] = nonce3; + extseed[0][MLDSA_CRHBYTES + 1] = 0; + extseed[1][MLDSA_CRHBYTES + 1] = 0; + extseed[2][MLDSA_CRHBYTES + 1] = 0; + extseed[3][MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(r0, sizeof(mld_poly)), + memory_slice(r1, sizeof(mld_poly)), memory_slice(r2, sizeof(mld_poly)), + memory_slice(r3, sizeof(mld_poly)), object_whole(buf[0]), + object_whole(buf[1]), object_whole(buf[2]), + object_whole(buf[3])) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_abs_bound(r0->coeffs, 0, ctr[0], MLDSA_ETA + 1)) + invariant(array_abs_bound(r1->coeffs, 0, ctr[1], MLDSA_ETA + 1)) + invariant(array_abs_bound(r2->coeffs, 0, ctr[2], MLDSA_ETA + 1)) + invariant(array_abs_bound(r3->coeffs, 0, ctr[3], MLDSA_ETA + 1))) + { + mld_xof256_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + + mld_xof256_x4_release(&state); + + mld_assert_abs_bound(r0->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r1->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r2->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r3->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +{ + /* Temporary buffer for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr; + mld_xof256_ctx state; + unsigned buflen; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = nonce; + extseed[MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr = mld_rej_eta(r->coeffs, MLDSA_N, 0, buf, buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, object_whole(&state), + object_whole(buf), memory_slice(r, sizeof(mld_poly))) + invariant(ctr <= MLDSA_N) + invariant(state.pos <= SHAKE256_RATE) + invariant(array_abs_bound(r->coeffs, 0, ctr, MLDSA_ETA + 1))) + { + mld_xof256_squeezeblocks(buf, 1, &state); + ctr = mld_rej_eta(r->coeffs, MLDSA_N, ctr, buf, buflen); + } + + mld_xof256_release(&state); + + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define MLD_POLY_UNIFORM_GAMMA1_NBLOCKS \ + ((MLDSA_POLYZ_PACKEDBYTES + MLD_STREAM256_BLOCKBYTES - 1) / \ + MLD_STREAM256_BLOCKBYTES) + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + mld_xof256_ctx state; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = (uint8_t)(nonce & 0xFF); + extseed[MLDSA_CRHBYTES + 1] = (uint8_t)(nonce >> 8); + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + mld_polyz_unpack(a, buf); + + mld_xof256_release(&state); + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + mld_xof256_x4_ctx state; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = (uint8_t)(nonce0 & 0xFF); + extseed[1][MLDSA_CRHBYTES] = (uint8_t)(nonce1 & 0xFF); + extseed[2][MLDSA_CRHBYTES] = (uint8_t)(nonce2 & 0xFF); + extseed[3][MLDSA_CRHBYTES] = (uint8_t)(nonce3 & 0xFF); + extseed[0][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce0 >> 8); + extseed[1][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce1 >> 8); + extseed[2][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce2 >> 8); + extseed[3][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce3 >> 8); + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + + mld_polyz_unpack(r0, buf[0]); + mld_polyz_unpack(r1, buf[1]); + mld_polyz_unpack(r2, buf[2]); + mld_polyz_unpack(r3, buf[3]); + mld_xof256_x4_release(&state); + + mld_assert_bound(r0->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r1->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r2->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r3->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +{ + unsigned int i, j, pos; + uint64_t signs; + uint64_t offset; + MLD_ALIGN uint8_t buf[SHAKE256_RATE]; + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, seed, MLDSA_CTILDEBYTES); + mld_shake256_finalize(&state); + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + + /* Convert the first 8 bytes of buf[] into an unsigned 64-bit value. */ + /* Each bit of that dictates the sign of the resulting challenge value */ + signs = 0; + for (i = 0; i < 8; ++i) + __loop__( + assigns(i, signs) + invariant(i <= 8) + ) + { + signs |= (uint64_t)buf[i] << 8 * i; + } + pos = 8; + + mld_memset(c, 0, sizeof(mld_poly)); + + for (i = MLDSA_N - MLDSA_TAU; i < MLDSA_N; ++i) + __loop__( + assigns(i, j, object_whole(buf), state, pos, memory_slice(c, sizeof(mld_poly)), signs) + invariant(i >= MLDSA_N - MLDSA_TAU) + invariant(i <= MLDSA_N) + invariant(pos >= 1) + invariant(pos <= SHAKE256_RATE) + invariant(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) + invariant(state.pos <= SHAKE256_RATE) + ) + { + do + __loop__( + assigns(j, object_whole(buf), state, pos) + invariant(state.pos <= SHAKE256_RATE) + ) + { + if (pos >= SHAKE256_RATE) + { + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + pos = 0; + } + j = buf[pos++]; + } while (j > i); + + c->coeffs[i] = c->coeffs[j]; + + /* Reference: Compute coefficent value here in two steps to */ + /* mixinf unsigned and signed arithmetic with implicit */ + /* conversions, and so that CBMC can keep track of ranges */ + /* to complete type-safety proof here. */ + + /* The least-significant bit of signs tells us if we want -1 or +1 */ + offset = 2 * (signs & 1); + + /* offset has value 0 or 2 here, so (1 - (int32_t) offset) has + * value -1 or +1 */ + c->coeffs[j] = 1 - (int32_t)offset; + + /* Move to the next bit of signs for next time */ + signs >>= 1; + } + + mld_assert_bound(c->coeffs, MLDSA_N, -1, 2); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(&signs, sizeof(signs)); +} + +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint8_t t[8]; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_ETA + 1); + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 1]); + t[2] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 2]); + t[3] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 3]); + t[4] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 4]); + t[5] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 5]); + t[6] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 6]); + t[7] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 7]); + + r[3 * i + 0] = (uint8_t)(((t[0] >> 0) | (t[1] << 3) | (t[2] << 6)) & 0xFF); + r[3 * i + 1] = + (uint8_t)(((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)) & + 0xFF); + r[3 * i + 2] = (uint8_t)(((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)) & 0xFF); + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 1]); + r[i] = (uint8_t)(t[0] | (t[1] << 4)); + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ +} + +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -5, MLDSA_ETA + 1))) + { + r->coeffs[8 * i + 0] = (a[3 * i + 0] >> 0) & 7; + r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 7; + r->coeffs[8 * i + 2] = ((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 7; + r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 7; + r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 7; + r->coeffs[8 * i + 5] = ((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 7; + r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 7; + r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5) & 7; + + r->coeffs[8 * i + 0] = MLDSA_ETA - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = MLDSA_ETA - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = MLDSA_ETA - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = MLDSA_ETA - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = MLDSA_ETA - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = MLDSA_ETA - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = MLDSA_ETA - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = MLDSA_ETA - r->coeffs[8 * i + 7]; + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -11, MLDSA_ETA + 1))) + { + r->coeffs[2 * i + 0] = a[i] & 0x0F; + r->coeffs[2 * i + 1] = a[i] >> 4; + r->coeffs[2 * i + 0] = MLDSA_ETA - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_ETA - r->coeffs[2 * i + 1]; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + + mld_assert_bound(r->coeffs, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + + +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[4]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 1]); + t[2] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 2]); + t[3] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 3]); + + r[9 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[9 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[9 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[9 * i + 2] |= (uint8_t)((t[1] << 2) & 0xFF); + r[9 * i + 3] = (uint8_t)((t[1] >> 6) & 0xFF); + r[9 * i + 4] = (uint8_t)((t[1] >> 14) & 0xFF); + r[9 * i + 4] |= (uint8_t)((t[2] << 4) & 0xFF); + r[9 * i + 5] = (uint8_t)((t[2] >> 4) & 0xFF); + r[9 * i + 6] = (uint8_t)((t[2] >> 12) & 0xFF); + r[9 * i + 6] |= (uint8_t)((t[3] << 6) & 0xFF); + r[9 * i + 7] = (uint8_t)((t[3] >> 2) & 0xFF); + r[9 * i + 8] = (uint8_t)((t[3] >> 10) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 1]); + + r[5 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[5 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[5 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[5 * i + 2] |= (uint8_t)((t[1] << 4) & 0xFF); + r[5 * i + 3] = (uint8_t)((t[1] >> 4) & 0xFF); + r[5 * i + 4] = (uint8_t)((t[1] >> 12) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +MLD_STATIC_TESTABLE void mld_polyz_unpack_c( + mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +) +{ + unsigned int i; +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[4 * i + 0] = a[9 * i + 0]; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 2] << 16; + r->coeffs[4 * i + 0] &= 0x3FFFF; + + r->coeffs[4 * i + 1] = a[9 * i + 2] >> 2; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 3] << 6; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 4] << 14; + r->coeffs[4 * i + 1] &= 0x3FFFF; + + r->coeffs[4 * i + 2] = a[9 * i + 4] >> 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 5] << 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 6] << 12; + r->coeffs[4 * i + 2] &= 0x3FFFF; + + r->coeffs[4 * i + 3] = a[9 * i + 6] >> 6; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 7] << 2; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10; + r->coeffs[4 * i + 3] &= 0x3FFFF; + + r->coeffs[4 * i + 0] = MLDSA_GAMMA1 - r->coeffs[4 * i + 0]; + r->coeffs[4 * i + 1] = MLDSA_GAMMA1 - r->coeffs[4 * i + 1]; + r->coeffs[4 * i + 2] = MLDSA_GAMMA1 - r->coeffs[4 * i + 2]; + r->coeffs[4 * i + 3] = MLDSA_GAMMA1 - r->coeffs[4 * i + 3]; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[2 * i + 0] = a[5 * i + 0]; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 2] << 16; + r->coeffs[2 * i + 0] &= 0xFFFFF; + + r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 3] << 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12; + /* r->coeffs[2*i+1] &= 0xFFFFF; */ /* No effect, since we're anyway at 20 + bits */ + + r->coeffs[2 * i + 0] = MLDSA_GAMMA1 - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_GAMMA1 - r->coeffs[2 * i + 1]; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +{ +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + ret = mld_polyz_unpack_17_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#elif defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + ret = mld_polyz_unpack_19_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYZ_UNPACK_17 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLYZ_UNPACK_19 && (MLD_CONFIG_PARAMETER_SET == 65 \ + || MLD_CONFIG_PARAMETER_SET == 87) */ + + mld_polyz_unpack_c(r, a); +} + +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + + mld_assert_bound(a->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[3 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0]) & 0xFF); + r[3 * i + 0] |= (uint8_t)((a->coeffs[4 * i + 1] << 6) & 0xFF); + r[3 * i + 1] = (uint8_t)((a->coeffs[4 * i + 1] >> 2) & 0xFF); + r[3 * i + 1] |= (uint8_t)((a->coeffs[4 * i + 2] << 4) & 0xFF); + r[3 * i + 2] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) & 0xFF); + r[3 * i + 2] |= (uint8_t)((a->coeffs[4 * i + 3] << 2) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + r[i] = + (uint8_t)((a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_rej_eta +#undef mld_rej_eta_c +#undef mld_poly_decompose_c +#undef mld_poly_use_hint_c +#undef mld_polyz_unpack_c +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_GAMMA1_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/poly_kl.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/poly_kl.h new file mode 100644 index 0000000000..c6aa498358 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/poly_kl.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_KL_H +#define MLD_POLY_KL_H + +#include "cbmc.h" +#include "common.h" +#include "poly.h" + +#define mld_poly_decompose MLD_NAMESPACE_KL(poly_decompose) +/************************************************* + * Name: mld_poly_decompose + * + * Description: For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such c mod MLDSA_Q = c1*ALPHA + + * c0 with -ALPHA/2 < c0 <= ALPHA/2 except + * c1 = (MLDSA_Q-1)/ALPHA where we set + * c1 = 0 and -ALPHA/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + * c1 + * - mld_poly *a0: pointer to input/output polynomial. Output + * polynomial has coefficients c0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +); + + +#define mld_poly_make_hint MLD_NAMESPACE_KL(poly_make_hint) +/************************************************* + * Name: mld_poly_make_hint + * + * Description: Compute hint polynomial. The coefficients of which indicate + * whether the low bits of the corresponding coefficient of + * the input polynomial overflow into the high bits. + * + * Arguments: - mld_poly *h: pointer to output hint polynomial + * - const mld_poly *a0: pointer to low part of input polynomial + * - const mld_poly *a1: pointer to high part of input polynomial + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + assigns(memory_slice(h, sizeof(mld_poly))) + ensures(return_value <= MLDSA_N) + ensures(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) +); + +#define mld_poly_use_hint MLD_NAMESPACE_KL(poly_use_hint) +/************************************************* + * Name: mld_poly_use_hint + * + * Description: Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - mld_poly *b: pointer to output polynomial with corrected high + *bits + * - const mld_poly *a: pointer to input polynomial + * - const mld_poly *h: pointer to input hint polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta_4x MLD_NAMESPACE_KL(poly_uniform_eta_4x) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample four polynomials with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce_i) + * + * Arguments: - mld_poly *r0: pointer to first output polynomial + * - mld_poly *r1: pointer to second output polynomial + * - mld_poly *r2: pointer to third output polynomial + * - mld_poly *r3: pointer to fourth output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce0: first nonce + * - uint8_t nonce1: second nonce + * - uint8_t nonce2: third nonce + * - uint8_t nonce3: fourth nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_abs_bound(r0->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r1->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r2->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r3->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta MLD_NAMESPACE_KL(poly_uniform_eta) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample polynomial with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce: nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1 MLD_NAMESPACE_KL(poly_uniform_gamma1) +/************************************************* + * Name: mld_poly_uniform_gamma1 + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1_4x MLD_NAMESPACE_KL(poly_uniform_gamma1_4x) +/************************************************* + * Name: mld_poly_uniform_gamma1_4x + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_bound(r0->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r1->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r2->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r3->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define mld_poly_challenge MLD_NAMESPACE_KL(poly_challenge) +/************************************************* + * Name: mld_poly_challenge + * + * Description: Implementation of H. Samples polynomial with MLDSA_TAU nonzero + * coefficients in {-1,1} using the output stream of + * SHAKE256(seed). + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const uint8_t mu[]: byte array containing seed of length + * MLDSA_CTILDEBYTES + **************************************************/ +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +__contract__( + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CTILDEBYTES)) + assigns(memory_slice(c, sizeof(mld_poly))) + /* All coefficients of c are -1, 0 or +1 */ + ensures(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) +); + +#define mld_polyeta_pack MLD_NAMESPACE_KL(polyeta_pack) +/************************************************* + * Name: mld_polyeta_pack + * + * Description: Bit-pack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYETA_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + assigns(memory_slice(r, MLDSA_POLYETA_PACKEDBYTES)) +); + +/* + * polyeta_unpack produces coefficients in [-MLDSA_ETA,MLDSA_ETA] for + * well-formed inputs (i.e., those produced by polyeta_pack). + * However, when passed an arbitrary byte array, it may produce smaller values, + * i.e, values in [MLD_POLYETA_UNPACK_LOWER_BOUND,MLDSA_ETA] + * Even though this should never happen, we use use the bound for arbitrary + * inputs in the CBMC proofs. + */ +#if MLDSA_ETA == 2 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-5) +#elif MLDSA_ETA == 4 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-11) +#else +#error "Invalid value of MLDSA_ETA" +#endif + +#define mld_polyeta_unpack MLD_NAMESPACE_KL(polyeta_unpack) +/************************************************* + * Name: mld_polyeta_unpack + * + * Description: Unpack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYETA_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)) +); + +#define mld_polyz_pack MLD_NAMESPACE_KL(polyz_pack) +/************************************************* + * Name: mld_polyz_pack + * + * Description: Bit-pack polynomial with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYZ_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(r, MLDSA_POLYZ_PACKEDBYTES)) +); + + +#define mld_polyz_unpack MLD_NAMESPACE_KL(polyz_unpack) +/************************************************* + * Name: mld_polyz_unpack + * + * Description: Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); + +#define mld_polyw1_pack MLD_NAMESPACE_KL(polyw1_pack) +/************************************************* + * Name: mld_polyw1_pack + * + * Description: Bit-pack polynomial w1 with coefficients in [0,15] or [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES)) +); + +#endif /* !MLD_POLY_KL_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/polyvec.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/polyvec.c new file mode 100644 index 0000000000..5c3a08ab32 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/polyvec.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include +#include + +#include "common.h" +#include "debug.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" + +/* This namespacing is not done at the top to avoid a naming conflict + * with native backends, which are currently not yet namespaced. */ +#define mld_polymat_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polymat_permute_bitrev_to_custom) +#define mld_polyvecl_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polyvecl_permute_bitrev_to_custom) +#define mld_polyvecl_pointwise_acc_montgomery_c \ + MLD_ADD_PARAM_SET(mld_polyvecl_pointwise_acc_montgomery_c) + +#if !defined(MLD_CONFIG_REDUCE_RAM) +/* Helper function to ensure that the polynomial entries in the output + * of mld_polyvec_matrix_expand use the standard (bitreversed) ordering + * of coefficients. + * No-op unless a native backend with a custom ordering is used. + */ + +static void mld_polyvecl_permute_bitrev_to_custom(mld_polyvecl *v) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +{ +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + unsigned i; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_permute_bitrev_to_custom(v->vec[i].coeffs); + } +#else /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + /* Nothing to do */ + (void)v; +#endif /* !MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ +} + +static void mld_polymat_permute_bitrev_to_custom(mld_polymat *mat) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; i++) + __loop__( + assigns(i, memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))) + { + mld_polyvecl_permute_bitrev_to_custom(&mat->vec[i]); + } +} +#endif /* !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + unsigned int i; + MLD_ALIGN uint8_t seed_ext[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + mld_memcpy(seed_ext, mat->rho, MLDSA_SEEDBYTES); + + /* Generate row on-demand */ + for (i = 0; i < MLDSA_L; i++) + { + uint8_t x = (uint8_t)row; + uint8_t y = (uint8_t)i; + + seed_ext[MLDSA_SEEDBYTES + 0] = y; + seed_ext[MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(&mat->row_buffer.vec[i], seed_ext); + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + mld_poly_permute_bitrev_to_custom(mat->row_buffer.vec[i].coeffs); +#endif + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); + + return &mat->row_buffer; +#else /* MLD_CONFIG_REDUCE_RAM */ + return &mat->vec[row]; +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + /* In REDUCE_RAM mode, just copy the seed for later on-demand generation */ + mld_memcpy(mat->rho, rho, MLDSA_SEEDBYTES); +#else + unsigned int i, j; + /* + * We generate four separate seed arrays rather than a single one to work + * around limitations in CBMC function contracts dealing with disjoint slices + * of the same parent object. + */ + + MLD_ALIGN uint8_t seed_ext[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + mld_memcpy(seed_ext[j], rho, MLDSA_SEEDBYTES); + } + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + /* Sample 4 matrix entries a time. */ + for (i = 0; i < (MLDSA_K * MLDSA_L / 4) * 4; i += 4) + __loop__( + assigns(i, j, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= (MLDSA_K * MLDSA_L / 4) * 4 && i % 4 == 0) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + uint8_t x = (uint8_t)((i + j) / MLDSA_L); + uint8_t y = (uint8_t)((i + j) % MLDSA_L); + + seed_ext[j][MLDSA_SEEDBYTES + 0] = y; + seed_ext[j][MLDSA_SEEDBYTES + 1] = x; + } + + mld_poly_uniform_4x(&mat->vec[i / MLDSA_L].vec[i % MLDSA_L], + &mat->vec[(i + 1) / MLDSA_L].vec[(i + 1) % MLDSA_L], + &mat->vec[(i + 2) / MLDSA_L].vec[(i + 2) % MLDSA_L], + &mat->vec[(i + 3) / MLDSA_L].vec[(i + 3) % MLDSA_L], + seed_ext); + } +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + i = 0; +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + /* Entries omitted by the batch-sampling are sampled individually. */ + while (i < MLDSA_K * MLDSA_L) + __loop__( + assigns(i, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K * MLDSA_L) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + uint8_t x = (uint8_t)(i / MLDSA_L); + uint8_t y = (uint8_t)(i % MLDSA_L); + mld_poly *this_poly = &mat->vec[i / MLDSA_L].vec[i % MLDSA_L]; + + seed_ext[0][MLDSA_SEEDBYTES + 0] = y; + seed_ext[0][MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(this_poly, seed_ext[0]); + i++; + } + + mld_polymat_permute_bitrev_to_custom(mat); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(t, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + const mld_polyvecl *row = mld_polymat_get_row(mat, i); + mld_polyvecl_pointwise_acc_montgomery(&t->vec[i], row, v); + } + + mld_assert_abs_bound_2d(t->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_L **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; +#endif + + /* Safety: nonce is at most ((UINT16_MAX - MLDSA_L) / MLDSA_L), and, hence, + * this cast is safe. See MLD_NONCE_UB comment in sign.c. */ + nonce = (uint16_t)(MLDSA_L * nonce); + /* Now, nonce <= UINT16_MAX - (MLDSA_L - 1), so the casts below are safe. */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_gamma1(&v->vec[i], seed, (uint16_t)(nonce + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLDSA_L == 4 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); +#elif MLDSA_L == 5 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); + mld_poly_uniform_gamma1(&v->vec[4], seed, (uint16_t)(nonce + 4)); +#elif MLDSA_L == 7 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], + &v->vec[3 /* irrelevant */], seed, nonce, + (uint16_t)(nonce + 1), (uint16_t)(nonce + 2), + 0xFF /* irrelevant */); + mld_poly_uniform_gamma1_4x(&v->vec[3], &v->vec[4], &v->vec[5], &v->vec[6], + seed, (uint16_t)(nonce + 3), (uint16_t)(nonce + 4), + (uint16_t)(nonce + 5), (uint16_t)(nonce + 6)); +#endif /* MLDSA_L == 7 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(k0, i, MLDSA_L, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_STATIC_TESTABLE void mld_polyvecl_pointwise_acc_montgomery_c( + mld_poly *w, const mld_polyvecl *u, const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i, j; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + for (i = 0; i < MLDSA_N; i++) + __loop__( + assigns(i, j, memory_slice(w, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_abs_bound(w->coeffs, 0, i, MLDSA_Q)) + ) + { + int64_t t = 0; + int32_t r; + for (j = 0; j < MLDSA_L; j++) + __loop__( + assigns(j, t) + invariant(j <= MLDSA_L) + invariant(t >= -(int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + invariant(t <= (int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + ) + { + t += (int64_t)u->vec[j].coeffs[i] * v->vec[j].coeffs[i]; + } + + r = mld_montgomery_reduce(t); + w->coeffs[i] = r; + } + + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +{ +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) && \ + MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l4_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) && \ + MLD_CONFIG_PARAMETER_SET == 65 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l5_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) && \ + MLD_CONFIG_PARAMETER_SET == 87 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l7_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 && \ + MLD_CONFIG_PARAMETER_SET == 44) && \ + !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 && \ + MLD_CONFIG_PARAMETER_SET == 65) && \ + MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 && \ + MLD_CONFIG_PARAMETER_SET == 87 */ + /* The first input is bounded by [0, Q-1] inclusive + * The second input is bounded by [-9Q+1, 9Q-1] inclusive . Hence, we can + * safely accumulate in 64-bits without intermediate reductions as + * MLDSA_L * (MLD_NTT_BOUND-1) * (Q-1) < INT64_MAX + * + * The worst case is ML-DSA-87: 7 * (9Q-1) * (Q-1) < 2**52 + * (and likewise for negative values) + */ + mld_polyvecl_pointwise_acc_montgomery_c(w, u, v); +} + +MLD_INTERNAL_API +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + invariant(i <= MLDSA_L) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + return t; +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_K **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k2, 0, i, + array_bound(v->vec[k2].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ) + { + mld_poly_reduce(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_caddq(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, + forall(k1, 0, MLDSA_N, u->vec[k0].coeffs[k1] == loop_entry(*u).vec[k0].coeffs[k1]))) + invariant(forall(k6, 0, i, array_bound(u->vec[k6].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + ) + { + mld_poly_add(&u->vec[i], &v->vec[i]); + } + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(u->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, u->vec[k1].coeffs[n1] == loop_entry(*u).vec[k1].coeffs[n1])))) + { + mld_poly_sub(&u->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, v->vec[k1].coeffs[n1] == loop_entry(*v).vec[k1].coeffs[n1]))) + ) + { + mld_poly_shiftl(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))) + { + mld_poly_invntt_tomont(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_INTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, array_abs_bound(r->vec[k2].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + mld_poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]); + } + mld_assert_abs_bound_2d(r->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + + return t; +} + +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + invariant(forall(k2, 0, i, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) + ) + { + mld_poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +{ + unsigned int i; + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + invariant(forall(k2, 0, i, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) + invariant(forall(k3, i, MLDSA_K, + array_bound(v0->vec[k3].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + ) + { + mld_poly_decompose(&v1->vec[i], &v0->vec[i]); + } + + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + mld_assert_abs_bound_2d(v0->vec, MLDSA_K, MLDSA_N, MLDSA_GAMMA2 + 1); +} + +MLD_INTERNAL_API +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, s, memory_slice(h, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(s <= i * MLDSA_N) + invariant(forall(k1, 0, i, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + s += mld_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]); + } + + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + return s; +} + +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *u, + const mld_polyveck *h) +{ + unsigned int i; + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(w, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)))) + ) + { + mld_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]); + } + + mld_assert_bound_2d(w->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +{ + unsigned int i; + mld_assert_bound_2d(w1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyw1_pack(&r[i * MLDSA_POLYW1_PACKEDBYTES], &w1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt0_pack(&r[i * MLDSA_POLYT0_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyz_unpack(&z->vec[i], r + i * MLDSA_POLYZ_PACKEDBYTES); + } + + mld_assert_bound_2d(z->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt0_unpack(&p->vec[i], r + i * MLDSA_POLYT0_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_polymat_permute_bitrev_to_custom +#undef mld_polyvecl_permute_bitrev_to_custom +#undef mld_polyvecl_pointwise_acc_montgomery_c diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/polyvec.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/polyvec.h new file mode 100644 index 0000000000..d21abc02ff --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/polyvec.h @@ -0,0 +1,725 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLYVEC_H +#define MLD_POLYVEC_H + +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "poly_kl.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_polyvecl MLD_ADD_PARAM_SET(mld_polyvecl) +#define mld_polyveck MLD_ADD_PARAM_SET(mld_polyveck) +#define mld_polymat MLD_ADD_PARAM_SET(mld_polymat) +/* End of parameter set namespacing */ + +/* Vectors of polynomials of length MLDSA_L */ +typedef struct +{ + mld_poly vec[MLDSA_L]; +} mld_polyvecl; + + +#define mld_polyvecl_uniform_gamma1 MLD_NAMESPACE_KL(polyvecl_uniform_gamma1) +/************************************************* + * Name: mld_polyvecl_uniform_gamma1 + * + * Description: Sample vector of polynomials with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_polyvecl *v: pointer to output vector + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + *************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + requires(nonce <= (UINT16_MAX - MLDSA_L) / MLDSA_L) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyvecl_ntt MLD_NAMESPACE_KL(polyvecl_ntt) +/************************************************* + * Name: mld_polyvecl_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_L. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyvecl *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k0, 0, MLDSA_L, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyvecl_pointwise_acc_montgomery \ + MLD_NAMESPACE_KL(polyvecl_pointwise_acc_montgomery) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery + * + * Description: Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * The first input "u" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * + * Arguments: - mld_poly *w: output polynomial + * - const mld_polyvecl *u: pointer to first input vector + * - const mld_polyvecl *v: pointer to second input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + + +#define mld_polyvecl_chknorm MLD_NAMESPACE_KL(polyvecl_chknorm) +/************************************************* + * Name: mld_polyvecl_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_L. + * Assumes input mld_polyvecl to be reduced by polyvecl_reduce(). + * + * Arguments: - const mld_polyvecl *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials is strictly smaller than B <= + * (MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +/* Vectors of polynomials of length MLDSA_K */ +typedef struct +{ + mld_poly vec[MLDSA_K]; +} mld_polyveck; + +/* Matrix of polynomials (K x L) */ +typedef struct +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + mld_polyvecl row_buffer; + uint8_t rho[MLDSA_SEEDBYTES]; +#else + mld_polyvecl vec[MLDSA_K]; +#endif +} mld_polymat; + +#define mld_polyveck_reduce MLD_NAMESPACE_KL(polyveck_reduce) +/************************************************* + * Name: polyveck_reduce + * + * Description: Reduce coefficients of polynomials in vector of length MLDSA_K + * to representatives in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) +); + +#define mld_polyveck_caddq MLD_NAMESPACE_KL(polyveck_caddq) +/************************************************* + * Name: mld_polyveck_caddq + * + * Description: For all coefficients of polynomials in vector of length MLDSA_K + * add MLDSA_Q if coefficient is negative. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_add MLD_NAMESPACE_KL(polyveck_add) +/************************************************* + * Name: mld_polyveck_add + * + * Description: Add vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to input-output vector of polynomials + * to be added to + * - const mld_polyveck *v: pointer to second input vector of + * polynomials + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(p0, 0, MLDSA_K, array_abs_bound(u->vec[p0].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) + requires(forall(p1, 0, MLDSA_K, + array_bound(v->vec[p1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(q2, 0, MLDSA_K, + array_bound(u->vec[q2].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_sub MLD_NAMESPACE_KL(polyveck_sub) +/************************************************* + * Name: mld_polyveck_sub + * + * Description: Subtract vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to first input vector + * - const mld_polyveck *v: pointer to second input vector to be + * subtracted from first input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(u->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_shiftl MLD_NAMESPACE_KL(polyveck_shiftl) +/************************************************* + * Name: mld_polyveck_shiftl + * + * Description: Multiply vector of polynomials of Length MLDSA_K by 2^MLDSA_D + *without modular reduction. Assumes input coefficients to be less than + *2^{31-MLDSA_D}. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_ntt MLD_NAMESPACE_KL(polyveck_ntt) +/************************************************* + * Name: mld_polyveck_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_K. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyveck_invntt_tomont MLD_NAMESPACE_KL(polyveck_invntt_tomont) +/************************************************* + * Name: mld_polyveck_invntt_tomont + * + * Description: Inverse NTT and multiplication by 2^{32} of polynomials + * in vector of length MLDSA_K. + * Input coefficients need to be less than MLDSA_Q, and + * Output coefficients are bounded by MLD_INTT_BOUND. + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) +); + +#define mld_polyveck_pointwise_poly_montgomery \ + MLD_NAMESPACE_KL(polyveck_pointwise_poly_montgomery) +/************************************************* + * Name: mld_polyveck_pointwise_poly_montgomery + * + * Description: Pointwise multiplication of a polynomial vector of length + * MLDSA_K by a single polynomial in NTT domain and multiplication + * of the resulting polynomial vector by 2^{-32}. + * + * Arguments: - mld_polyveck *r: pointer to output vector + * - mld_poly *a: pointer to input polynomial + * - mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(r, sizeof(mld_polyveck))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(r, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(r->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#define mld_polyveck_chknorm MLD_NAMESPACE_KL(polyveck_chknorm) +/************************************************* + * Name: mld_polyveck_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_K. + * Assumes input mld_polyveck to be reduced by polyveck_reduce(). + * + * Arguments: - const mld_polyveck *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials are strictly smaller than B <= + *(MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, + -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +#define mld_polyveck_power2round MLD_NAMESPACE_KL(polyveck_power2round) +/************************************************* + * Name: mld_polyveck_power2round + * + * Description: For all coefficients a of polynomials in vector of length + *MLDSA_K, compute a0, a1 such that a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with + *-2^{MLDSA_D-1} < a0 <= 2^{MLDSA_D-1}. Assumes coefficients to be standard + *representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to output vector of polynomials with + * coefficients a0 + * - const mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) +); + +#define mld_polyveck_decompose MLD_NAMESPACE_KL(polyveck_decompose) +/************************************************* + * Name: mld_polyveck_decompose + * + * Description: For all coefficients a of polynomials in vector of length + * MLDSA_K, compute high and low bits a0, a1 such a mod^+ MLDSA_Q = a1*ALPHA + * + a0 with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (MLDSA_Q-1)/ALPHA where we set + * a1 = 0 and -ALPHA/2 <= a0 = a mod MLDSA_Q - MLDSA_Q < 0. Assumes coefficients + * to be standard representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to input/output vector of + * polynomials with. Output polynomial has + * coefficients a0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v0->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + ensures(forall(k2, 0, MLDSA_K, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) +); + +#define mld_polyveck_make_hint MLD_NAMESPACE_KL(polyveck_make_hint) +/************************************************* + * Name: mld_polyveck_make_hint + * + * Description: Compute hint vector. + * + * Arguments: - mld_polyveck *h: pointer to output vector + * - const mld_polyveck *v0: pointer to low part of input vector + * - const mld_polyveck *v1: pointer to high part of input vector + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(return_value <= MLDSA_N * MLDSA_K) + ensures(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) +); + +#define mld_polyveck_use_hint MLD_NAMESPACE_KL(polyveck_use_hint) +/************************************************* + * Name: mld_polyveck_use_hint + * + * Description: Use hint vector to correct the high bits of input vector. + * + * Arguments: - mld_polyveck *w: pointer to output vector of polynomials with + * corrected high bits + * - const mld_polyveck *u: pointer to input vector + * - const mld_polyveck *h: pointer to input hint vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *v, + const mld_polyveck *h) +__contract__( + requires(memory_no_alias(w, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + assigns(memory_slice(w, sizeof(mld_polyveck))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) +); + +#define mld_polyveck_pack_w1 MLD_NAMESPACE_KL(polyveck_pack_w1) +/************************************************* + * Name: mld_polyveck_pack_w1 + * + * Description: Bit-pack polynomial vector w1 with coefficients in [0,15] or + * [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_K* MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_polyveck *a: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(w1, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(w1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) +); + +#define mld_polyveck_pack_eta MLD_NAMESPACE_KL(polyveck_pack_eta) +/************************************************* + * Name: mld_polyveck_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients + * in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyvecl_pack_eta MLD_NAMESPACE_KL(polyvecl_pack_eta) +/************************************************* + * Name: mld_polyvecl_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_L * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyveck_pack_t0 MLD_NAMESPACE_KL(polyveck_pack_t0) +/************************************************* + * Name: mld_polyveck_pack_t0 + * + * Description: Bit-pack polynomial vector to with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(p->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) +); + +#define mld_polyvecl_unpack_eta MLD_NAMESPACE_KL(polyvecl_unpack_eta) +/************************************************* + * Name: mld_polyvecl_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyvecl *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + assigns(memory_slice(p, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyvecl_unpack_z MLD_NAMESPACE_KL(polyvecl_unpack_z) +/************************************************* + * Name: mld_polyvecl_unpack_z + * + * Description: Unpack polynomial vector with coefficients in + * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_polyvecl *z: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(z->vec[k1].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyveck_unpack_eta MLD_NAMESPACE_KL(polyveck_unpack_eta) +/************************************************* + * Name: mld_polyveck_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyveck_unpack_t0 MLD_NAMESPACE_KL(polyveck_unpack_t0) +/************************************************* + * Name: mld_polyveck_unpack_t0 + * + * Description: Unpack polynomial vector with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) +); + +#define mld_polymat_get_row MLD_NAMESPACE_KL(polymat_get_row) +/************************************************* + * Name: mld_polymat_get_row + * + * Description: Retrieve a pointer to a specific row of the matrix. + * In MLD_CONFIG_REDUCE_RAM mode, generates the row on-demand. + * + * Arguments: - mld_polymat *mat: pointer to matrix + * - unsigned int row: row index (must be < MLDSA_K) + * + * Returns pointer to the row (mld_polyvecl) + **************************************************/ +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row); + +#define mld_polyvec_matrix_expand MLD_NAMESPACE_KL(polyvec_matrix_expand) +/************************************************* + * Name: mld_polyvec_matrix_expand + * + * Description: Implementation of ExpandA. Generates matrix A with uniformly + * random coefficients a_{i,j} by performing rejection + * sampling on the output stream of SHAKE128(rho|j|i) + * + * Arguments: - mld_polymat *mat: pointer to output matrix + * - const uint8_t rho[]: byte array containing seed rho + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +__contract__( + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +); + + + +#define mld_polyvec_matrix_pointwise_montgomery \ + MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery) +/************************************************* + * Name: mld_polyvec_matrix_pointwise_montgomery + * + * Description: Compute matrix-vector multiplication in NTT domain with + * pointwise multiplication and multiplication by 2^{-32}. + * Input matrix and vector must be in NTT domain representation. + * + * The first input "mat" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * Note: In MLD_CONFIG_REDUCE_RAM mode, mat cannot be const + * as rows are generated on-demand. + * + * Arguments: - mld_polyveck *t: pointer to output vector t + * - mld_polymat *mat: pointer to input matrix + * - const mld_polyvecl *v: pointer to input vector v + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(t, sizeof(mld_polyveck))) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(t, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#endif /* !MLD_POLYVEC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/randombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/randombytes.h new file mode 100644 index 0000000000..da55772419 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/randombytes.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_RANDOMBYTES_H +#define MLD_RANDOMBYTES_H + +#include +#include + +#include "cbmc.h" +#include "common.h" + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +#if !defined(MLD_CONFIG_CUSTOM_RANDOMBYTES) +MLD_MUST_CHECK_RETURN_VALUE +int randombytes(uint8_t *out, size_t outlen); +static MLD_INLINE int mld_randombytes(uint8_t *out, size_t outlen) +__contract__( + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) { return randombytes(out, outlen); } +#endif /* !MLD_CONFIG_CUSTOM_RANDOMBYTES */ +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ +#endif /* !MLD_RANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/reduce.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/reduce.h new file mode 100644 index 0000000000..413cf1829e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/reduce.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_REDUCE_H +#define MLD_REDUCE_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* check-magic: -4186625 == pow(2,32,MLDSA_Q) */ +#define MLD_MONT -4186625 + +/* Upper bound for domain of mld_reduce32() */ +#define MLD_REDUCE32_DOMAIN_MAX (INT32_MAX - (1 << 22)) + +/* Absolute bound for range of mld_reduce32() */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define MLD_REDUCE32_RANGE_MAX 6283009 + +/************************************************* + * Name: mld_montgomery_reduce + * + * Description: Generic Montgomery reduction; given a 64-bit integer a, computes + * 32-bit integer congruent to a * R^-1 mod q, where R=2^32 + * + * Arguments: - int64_t a: input integer to be reduced, of absolute value + * smaller or equal to INT64_MAX - 2^31 * MLDSA_Q. + * + * Returns: Integer congruent to a * R^-1 modulo q, with absolute value + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * In particular, if |a| < 2^31 * MLDSA_Q, the absolute value + * of the return value is < MLDSA_Q. + **************************************************/ +static MLD_INLINE int32_t mld_montgomery_reduce(int64_t a) +__contract__( + /* We don't attempt to express an input-dependent output bound + * as the post-condition here, as all call-sites satisfy the + * absolute input bound 2^31 * MLDSA_Q and higher-level + * reasoning can be conducted using |return_value| < MLDSA_Q. */ + requires(a > -(((int64_t)1 << 31) * MLDSA_Q) && + a < (((int64_t)1 << 31) * MLDSA_Q)) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* check-magic: 58728449 == unsigned_mod(pow(MLDSA_Q, -1, 2^32), 2^32) */ + const uint64_t QINV = 58728449; + + /* Compute a*q^{-1} mod 2^32 in unsigned representatives */ + const uint32_t a_reduced = mld_cast_int64_to_uint32(a); + const uint32_t a_inverted = (a_reduced * QINV) & UINT32_MAX; + + /* Lift to signed canonical representative mod 2^32. */ + const int32_t t = mld_cast_uint32_to_int32(a_inverted); + + int64_t r; + + mld_assert(a < +(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)) && + a > -(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q))); + + r = a - (int64_t)t * MLDSA_Q; + + /* + * PORTABILITY: Right-shift on a signed integer is, strictly-speaking, + * implementation-defined for negative left argument. Here, + * we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5)) + */ + r = r >> 32; + + /* Bounds: + * + * By construction of the Montgomery multiplication, by the time we + * compute r >> 32, r is divisible by 2^32, and hence + * + * |r >> 32| = |r| / 2^32 + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * (In general, we would only have |x >> n| <= ceil(|x| / 2^n)). + * + * In particular, if |a| < 2^31 * MLDSA_Q, then |return_value| < MLDSA_Q. + */ + return (int32_t)r; +} + +/************************************************* + * Name: mld_reduce32 + * + * Description: For finite field element a with a <= 2^{31} - 2^{22} - 1, + * compute r \equiv a (mod MLDSA_Q) such that + * -MLD_REDUCE32_RANGE_MAX <= r < MLD_REDUCE32_RANGE_MAX. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_reduce32(int32_t a) +__contract__( + requires(a <= MLD_REDUCE32_DOMAIN_MAX) + ensures(return_value >= -MLD_REDUCE32_RANGE_MAX) + ensures(return_value < MLD_REDUCE32_RANGE_MAX) +) +{ + int32_t t; + + t = (a + (1 << 22)) >> 23; + t = a - t * MLDSA_Q; + mld_assert((t - a) % MLDSA_Q == 0); + return t; +} + +/************************************************* + * Name: mld_caddq + * + * Description: Add MLDSA_Q if input coefficient is negative. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_caddq(int32_t a) +__contract__( + requires(a > -MLDSA_Q) + requires(a < MLDSA_Q) + ensures(return_value >= 0) + ensures(return_value < MLDSA_Q) + ensures(return_value == (a >= 0) ? a : (a + MLDSA_Q)) +) +{ + return mld_ct_sel_int32(a + MLDSA_Q, a, mld_ct_cmask_neg_i32(a)); +} + + +#endif /* !MLD_REDUCE_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/rounding.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/rounding.h new file mode 100644 index 0000000000..a83562b0f1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/rounding.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_ROUNDING_H +#define MLD_ROUNDING_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_power2round MLD_ADD_PARAM_SET(mld_power2round) +#define mld_decompose MLD_ADD_PARAM_SET(mld_decompose) +#define mld_make_hint MLD_ADD_PARAM_SET(mld_make_hint) +#define mld_use_hint MLD_ADD_PARAM_SET(mld_use_hint) +/* End of parameter set namespacing */ + +#define MLD_2_POW_D (1 << MLDSA_D) + +/************************************************* + * Name: mld_power2round + * + * Description: For finite field element a, compute a0, a1 such that + * a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with -2^{MLDSA_D-1} < a0 <= + * 2^{MLDSA_D-1}. Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: In the reference implementation, a1 is passed as a + * return value instead. + **************************************************/ +static MLD_INLINE void mld_power2round(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + ensures(*a0 > -(MLD_2_POW_D/2) && *a0 <= (MLD_2_POW_D/2)) + ensures(*a1 >= 0 && *a1 <= (MLDSA_Q - 1) / MLD_2_POW_D) + ensures((*a1 * MLD_2_POW_D + *a0 - a) % MLDSA_Q == 0) +) +{ + *a1 = (a + (1 << (MLDSA_D - 1)) - 1) >> MLDSA_D; + *a0 = a - (*a1 << MLDSA_D); +} + +/************************************************* + * Name: mld_decompose + * + * Description: For finite field element a, compute high and low bits a0, a1 + * such that a mod^+ MLDSA_Q = a1* 2 * MLDSA_GAMMA2 + a0 with + * -MLDSA_GAMMA2 < a0 <= MLDSA_GAMMA2 except + * if a1 = (MLDSA_Q-1)/(MLDSA_GAMMA2*2) where we set a1 = 0 and + * -MLDSA_GAMMA2 <= a0 = a mod^+ MLDSA_Q - MLDSA_Q < 0. + * Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: a1 is passed as a return value instead + **************************************************/ +static MLD_INLINE void mld_decompose(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + /* a0 = -MLDSA_GAMMA2 can only occur when (q-1) = a - (a mod MLDSA_GAMMA2), + * then a1=1; and a0 = a - (a mod MLDSA_GAMMA2) - 1 (@[FIPS204, Algorithm 36 (Decompose)]) */ + ensures(*a0 >= -MLDSA_GAMMA2 && *a0 <= MLDSA_GAMMA2) + ensures(*a1 >= 0 && *a1 < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) + ensures((*a1 * 2 * MLDSA_GAMMA2 + *a0 - a) % MLDSA_Q == 0) +) +{ + /* + * The goal is to compute f1 = round-(f / (2*GAMMA2)), which can be computed + * alternatively as round-(f / (128B)) = round-(ceil(f / 128) / B) where + * B = 2*GAMMA2 / 128. Here round-() denotes "round half down". + * + * The equality round-(f / (128B)) = round-(ceil(f / 128) / B) can deduced + * as follows. Since changing f to align-up(f, 128) can move f onto but not + * across a rounding boundary for division by 128*B (note that we need B to be + * even for this to work), and round- rounds down on the boundary, we have + * + * round-(f / (128B)) = round-(align-up(f, 128) / (128B)) + * = round-((align-up(f, 128) / 128) / B) + * = round-(ceil(f / 128) / B). + */ + *a1 = (a + 127) >> 7; + /* We know a >= 0 and a < MLDSA_Q, so... */ + /* check-magic: 65472 == round((MLDSA_Q-1)/128) */ + mld_assert(*a1 >= 0 && *a1 <= 65472); + +#if MLD_CONFIG_PARAMETER_SET == 44 + /* check-magic: 1488 == 2 * intdiv(intdiv(MLDSA_Q - 1, 88), 128) */ + /* check-magic: 11275 == floor(2**24 / 1488) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + */ + *a1 = (*a1 * 11275 + (1 << 23)) >> 24; + mld_assert(*a1 >= 0 && *a1 <= 44); + + *a1 = mld_ct_sel_int32(0, *a1, mld_ct_cmask_neg_i32(43 - *a1)); + mld_assert(*a1 >= 0 && *a1 <= 43); +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + /* check-magic: 4092 == 2 * intdiv(intdiv(MLDSA_Q - 1, 32), 128) */ + /* check-magic: 1025 == floor(2**22 / 4092) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + */ + *a1 = (*a1 * 1025 + (1 << 21)) >> 22; + mld_assert(*a1 >= 0 && *a1 <= 16); + + *a1 &= 15; + mld_assert(*a1 >= 0 && *a1 <= 15); + +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + + *a0 = a - *a1 * 2 * MLDSA_GAMMA2; + *a0 = mld_ct_sel_int32(*a0 - MLDSA_Q, *a0, + mld_ct_cmask_neg_i32((MLDSA_Q - 1) / 2 - *a0)); +} + +/************************************************* + * Name: mld_make_hint + * + * Description: Compute hint bit indicating whether the low bits of the + * input element overflow into the high bits. + * + * Arguments: - int32_t a0: low bits of input element + * - int32_t a1: high bits of input element + * + * Returns 1 if overflow, 0 otherwise + **************************************************/ +static MLD_INLINE unsigned int mld_make_hint(int32_t a0, int32_t a1) +__contract__( + ensures(return_value >= 0 && return_value <= 1) +) +{ + if (a0 > MLDSA_GAMMA2 || a0 < -MLDSA_GAMMA2 || + (a0 == -MLDSA_GAMMA2 && a1 != 0)) + { + return 1; + } + + return 0; +} + +/************************************************* + * Name: mld_use_hint + * + * Description: Correct high bits according to hint. + * + * Arguments: - int32_t a: input element + * - int32_t hint: hint bit + * + * Returns corrected high bits. + **************************************************/ +static MLD_INLINE int32_t mld_use_hint(int32_t a, int32_t hint) +__contract__( + requires(hint >= 0 && hint <= 1) + requires(a >= 0 && a < MLDSA_Q) + ensures(return_value >= 0 && return_value < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) +) +{ + int32_t a0, a1; + + mld_decompose(&a0, &a1, a); + if (hint == 0) + { + return a1; + } + +#if MLD_CONFIG_PARAMETER_SET == 44 + if (a0 > 0) + { + return (a1 == 43) ? 0 : a1 + 1; + } + else + { + return (a1 == 0) ? 43 : a1 - 1; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + if (a0 > 0) + { + return (a1 + 1) & 15; + } + else + { + return (a1 - 1) & 15; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + + +#endif /* !MLD_ROUNDING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/sign.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/sign.c new file mode 100644 index 0000000000..32bba52d65 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/sign.c @@ -0,0 +1,1508 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [Round3_Spec] + * CRYSTALS-Dilithium Algorithm Specifications and Supporting Documentation + * (Version 3.1) + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf + */ + +#include +#include + +#include "cbmc.h" +#include "ct.h" +#include "debug.h" +#include "packing.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" +#include "randombytes.h" +#include "sign.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_check_pct MLD_ADD_PARAM_SET(mld_check_pct) MLD_CONTEXT_PARAMETERS_2 +#define mld_sample_s1_s2 MLD_ADD_PARAM_SET(mld_sample_s1_s2) +#define mld_validate_hash_length MLD_ADD_PARAM_SET(mld_validate_hash_length) +#define mld_get_hash_oid MLD_ADD_PARAM_SET(mld_get_hash_oid) +#define mld_H MLD_ADD_PARAM_SET(mld_H) +#define mld_compute_pack_z MLD_ADD_PARAM_SET(mld_compute_pack_z) +#define mld_attempt_signature_generation \ + MLD_ADD_PARAM_SET(mld_attempt_signature_generation) MLD_CONTEXT_PARAMETERS_8 +#define mld_compute_t0_t1_tr_from_sk_components \ + MLD_ADD_PARAM_SET(mld_compute_t0_t1_tr_from_sk_components) \ + MLD_CONTEXT_PARAMETERS_7 +/* End of parameter set namespacing */ + + +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + ensures(return_value == 0 + || return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL) +); + +#if defined(MLD_CONFIG_KEYGEN_PCT) +/************************************************* + * @[FIPS140_3_IG] + * (https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf) + * + * TE10.35.02: Pair-wise Consistency Test (PCT) for DSA keypairs + * + * Purpose: Validates that a generated public/private key pair can correctly + * sign and verify data. Test performs signature generation using the private + * key (sk), followed by signature verification using the public key (pk). + * Returns 0 if the signature was successfully verified, non-zero if it cannot. + * + * Note: @[FIPS204] requires that public/private key pairs are to be used only + * for the calculation and/of verification of digital signatures. + **************************************************/ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t message[1] = {0}; + size_t siglen; + int ret; + MLD_ALLOC(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + MLD_ALLOC(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + + if (signature == NULL || pk_test == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Copy public key for testing */ + mld_memcpy(pk_test, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* Sign a test message using the original secret key */ + ret = mld_sign_signature(signature, &siglen, message, sizeof(message), NULL, + 0, sk, context); + if (ret != 0) + { + goto cleanup; + } + +#if defined(MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST) + /* Deliberately break public key for testing purposes */ + if (mld_break_pct()) + { + pk_test[0] = ~pk_test[0]; + } +#endif /* MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST */ + + /* Verify the signature using the (potentially corrupted) public key */ + ret = mld_sign_verify(signature, siglen, message, sizeof(message), NULL, 0, + pk_test, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + MLD_FREE(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + + return ret; +} +#else /* MLD_CONFIG_KEYGEN_PCT */ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + /* Skip PCT */ + ((void)pk); + ((void)sk); +#if defined(MLD_CONFIG_CONTEXT_PARAMETER) + ((void)context); +#endif + return 0; +} +#endif /* !MLD_CONFIG_KEYGEN_PCT */ + +static void mld_sample_s1_s2(mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t seed[MLDSA_CRHBYTES]) +__contract__( + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(object_whole(s1), object_whole(s2)) + ensures(forall(l0, 0, MLDSA_L, array_abs_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + ensures(forall(k0, 0, MLDSA_K, array_abs_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) +) +{ +/* Sample short vectors s1 and s2 */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; + uint16_t nonce = 0; + /* Safety: The nonces are at most 14 (MLDSA_L + MLDSA_K - 1), and, hence, the + * casts are safe. */ + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_eta(&s1->vec[i], seed, (uint8_t)(nonce + i)); + } + for (i = 0; i < MLDSA_K; i++) + { + mld_poly_uniform_eta(&s2->vec[i], seed, (uint8_t)(nonce + MLDSA_L + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLD_CONFIG_PARAMETER_SET == 44 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 4, 5, 6, 7); +#elif MLD_CONFIG_PARAMETER_SET == 65 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s2->vec[0], &s2->vec[1], + &s2->vec[2] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[2], &s2->vec[3], &s2->vec[4], &s2->vec[5], + seed, 7, 8, 9, 10); +#elif MLD_CONFIG_PARAMETER_SET == 87 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s1->vec[5], &s1->vec[6], + &s2->vec[0] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 7, 8, 9, 10); + mld_poly_uniform_eta_4x(&s2->vec[4], &s2->vec[5], &s2->vec[6], &s2->vec[7], + seed, 11, 12, 13, 14); +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ +} + +/************************************************* + * Name: mld_compute_t0_t1_tr_from_sk_components + * + * Description: Computes t0, t1, tr, and pk from secret key components + * rho, s1, s2. This is the shared computation used by + * both keygen and generating the public key from the + * secret key. + * + * Arguments: - mld_polyveck *t0: output t0 + * - mld_polyveck *t1: output t1 + * - uint8_t tr[MLDSA_TRBYTES]: output tr + * - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t rho[MLDSA_SEEDBYTES]: input rho + * - const mld_polyvecl *s1: input s1 + * - const mld_polyveck *s2: input s2 + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_t0_t1_tr_from_sk_components( + mld_polyveck *t0, mld_polyveck *t1, uint8_t tr[MLDSA_TRBYTES], + uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], const uint8_t rho[MLDSA_SEEDBYTES], + const mld_polyvecl *s1, const mld_polyveck *s2, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(l0, 0, MLDSA_L, array_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + requires(forall(k0, 0, MLDSA_K, array_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(forall(k1, 0, MLDSA_K, array_bound(t0->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(t1->vec[k2].coeffs, 0, MLDSA_N, 0, 1 << 10))) + ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY)) +{ + int ret; + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1hat, mld_polyvecl, 1, context); + MLD_ALLOC(t, mld_polyveck, 1, context); + + if (mat == NULL || s1hat == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Expand matrix */ + mld_polyvec_matrix_expand(mat, rho); + + /* Matrix-vector multiplication */ + *s1hat = *s1; + mld_polyvecl_ntt(s1hat); + mld_polyvec_matrix_pointwise_montgomery(t, mat, s1hat); + mld_polyveck_invntt_tomont(t); + + /* Add error vector s2 */ + mld_polyveck_add(t, s2); + + /* Reference: The following reduction is not present in the reference + * implementation. Omitting this reduction requires the output of + * the invntt to be small enough such that the addition of s2 does + * not result in absolute values >= MLDSA_Q. While our C, x86_64, + * and AArch64 invntt implementations produce small enough + * values for this to work out, it complicates the bounds + * reasoning. We instead add an additional reduction, and can + * consequently, relax the bounds requirements for the invntt. + */ + mld_polyveck_reduce(t); + + /* Decompose to get t1, t0 */ + mld_polyveck_caddq(t); + mld_polyveck_power2round(t1, t0, t); + + /* Pack public key and compute tr */ + mld_pack_pk(pk, rho, t1); + mld_shake256(tr, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + ret = 0; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_polyveck, 1, context); + MLD_FREE(s1hat, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + const uint8_t *rho, *rhoprime, *key; + MLD_ALLOC(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + MLD_ALLOC(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + + if (seedbuf == NULL || inbuf == NULL || tr == NULL || s1 == NULL || + s2 == NULL || t1 == NULL || t0 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Get randomness for rho, rhoprime and key */ + mld_memcpy(inbuf, seed, MLDSA_SEEDBYTES); + inbuf[MLDSA_SEEDBYTES + 0] = MLDSA_K; + inbuf[MLDSA_SEEDBYTES + 1] = MLDSA_L; + mld_shake256(seedbuf, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, inbuf, + MLDSA_SEEDBYTES + 2); + rho = seedbuf; + rhoprime = rho + MLDSA_SEEDBYTES; + key = rhoprime + MLDSA_CRHBYTES; + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + + /* Sample s1 and s2 */ + mld_sample_s1_s2(s1, s2, rhoprime); + + /* Compute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0, t1, tr, pk, rho, s1, s2, + context); + if (ret != 0) + { + goto cleanup; + } + + /* Pack secret key */ + mld_pack_sk(sk, rho, tr, key, t0, s1, s2); + + /* Constant time: pk is the public key, inherently public data */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_FREE(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + + if (ret != 0) + { + return ret; + } + + /* Pairwise Consistency Test (PCT) @[FIPS140_3_IG, p.87] */ + /* Do this after freeing all temporaries. */ + return mld_check_pct(pk, sk, context); +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t seed[MLDSA_SEEDBYTES]; + int ret; + if (mld_randombytes(seed, MLDSA_SEEDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(seed, sizeof(seed)); + ret = mld_sign_keypair_internal(pk, sk, seed, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed, sizeof(seed)); + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +/************************************************* + * Name: mld_H + * + * Description: Abstracts application of SHAKE256 to + * one, two or three blocks of data, + * yielding a user-requested size of + * output. + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in1: pointer to input block 1 + * Must NOT be NULL + * - size_t in1len: length of input in1 bytes + * - const uint8_t *in2: pointer to input block 2 + * May be NULL if in2len=0, in which case + * this block is ignored + * - size_t in2len: length of input in2 bytes + * - const uint8_t *in3: pointer to input block 3 + * May be NULL if in3len=0, in which case + * this block is ignored + * - size_t in3len: length of input in3 bytes + **************************************************/ +static void mld_H(uint8_t *out, size_t outlen, const uint8_t *in1, + size_t in1len, const uint8_t *in2, size_t in2len, + const uint8_t *in3, size_t in3len) +__contract__( + requires(in1len <= MLD_MAX_BUFFER_SIZE) + requires(in2len <= MLD_MAX_BUFFER_SIZE) + requires(in3len <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in1, in1len)) + requires(in2len == 0 || memory_no_alias(in2, in2len)) + requires(in3len == 0 || memory_no_alias(in3, in3len)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) +{ + mld_shake256ctx state; + mld_shake256_init(&state); + mld_shake256_absorb(&state, in1, in1len); + if (in2len != 0) + { + mld_shake256_absorb(&state, in2, in2len); + } + if (in3len != 0) + { + mld_shake256_absorb(&state, in3, in3len); + } + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(&state, sizeof(state)); +} + +/************************************************* + * Name: mld_compute_pack_z + * + * Description: Computes z = y + s1*c, checks that z has coefficients smaller + * than MLDSA_GAMMA1 - MLDSA_BETA, and packs z into the + * signature buffer. + * + * Arguments: - uint8_t *sig: output signature + * - const mld_poly *cp: challenge polynomial + * - const polyvecl *s1: secret vector s1 + * - const polyvecl *y: masking vector y + * + * Returns: - 0: Success (z has coefficients smaller than + * MLDSA_GAMMA1 - MLDSA_BETA,) + * - MLD_ERR_FAIL: z rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This function is inlined into mld_sign_signature in the + * reference implementation. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_pack_z(uint8_t sig[MLDSA_CRYPTO_BYTES], + const mld_poly *cp, const mld_polyvecl *s1, + const mld_polyvecl *y, mld_poly *z) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(cp, sizeof(mld_poly))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(y, sizeof(mld_polyvecl))) + requires(memory_no_alias(z, sizeof(mld_poly))) + requires(array_abs_bound(cp->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_L, + array_bound(y->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + requires(forall(k1, 0, MLDSA_L, array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(memory_slice(z, sizeof(mld_poly))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int i; + uint32_t z_invalid; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(z, sizeof(mld_poly)), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_poly_pointwise_montgomery(z, cp, &s1->vec[i]); + mld_poly_invntt_tomont(z); + mld_poly_add(z, &y->vec[i]); + mld_poly_reduce(z); + + z_invalid = mld_poly_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA); + /* Constant time: It is fine (and prohibitively expensive to avoid) + * to leak the result of the norm check and which polynomial in z caused a + * rejection. It would even be okay to leak which coefficient led to + * rejection as the candidate signature will be discarded anyway. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(&z_invalid, sizeof(uint32_t)); + if (z_invalid) + { + return MLD_ERR_FAIL; /* reject */ + } + /* If z is valid, then its coefficients are bounded by + * MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below + * to prove the pre-condition of pack_sig_z() */ + mld_assert_abs_bound(z, MLDSA_N, (MLDSA_GAMMA1 - MLDSA_BETA)); + + /* After the norm check, the distribution of each coefficient of z is + * independent of the secret key and it can, hence, be considered + * public. It is, hence, okay to immediately pack it into the user-provided + * signature buffer. */ + mld_pack_sig_z(sig, z, i); + } + return 0; +} + +/* Reference: The reference implementation does not explicitly check the + * maximum nonce value, but instead loops indefinitely (even when the nonce + * would overflow). Internally, sampling of y uses + * (nonceL), (nonceL+1), ... (nonce*L+L-1). + * Hence, there are no overflows if nonce < (UINT16_MAX - L)/L. + * Explicitly checking for this explicitly allows us to prove type-safety. + * Note that FIPS204 explicitly allows an upper-bound this loop of + * 814 (< (UINT16_MAX - L)/L) - see @[FIPS204, Appendix C]. */ +#define MLD_NONCE_UB ((UINT16_MAX - MLDSA_L) / MLDSA_L) + +/************************************************* + * Name: attempt_signature_generation + * + * Description: Attempts to generate a single signature. + * + * Arguments: - uint8_t *sig: pointer to output signature + * - const uint8_t *mu: pointer to message or hash + * of exactly MLDSA_CRHBYTES bytes + * - const uint8_t *rhoprime: pointer to randomness seed + * - uint16_t nonce: current nonce value + * - const mld_polymat *mat: expanded matrix + * - const polyvecl *s1: secret vector s1 + * - const polyveck *s2: secret vector s2 + * - const polyveck *t0: vector t0 + * + * Returns: - 0: Signature generation succeeded + * - MLD_ERR_FAIL: Signature rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This code differs from the reference implementation + * in that it factors out the core signature generation + * step into a distinct function here in order to improve + * efficiency of CBMC proof. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_attempt_signature_generation( + uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *mu, + const uint8_t rhoprime[MLDSA_CRHBYTES], uint16_t nonce, mld_polymat *mat, + const mld_polyvecl *s1, const mld_polyveck *s2, const mld_polyveck *t0, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(rhoprime, MLDSA_CRHBYTES)) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(nonce <= MLD_NONCE_UB) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int n; + uint32_t w0_invalid, h_invalid; + int ret; + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyvecl y; + mld_polyveck h; + } + yh_u; + mld_polyvecl *y; + mld_polyveck *h; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck w1; + mld_polyvecl tmp; + } + w1tmp_u; + mld_polyveck *w1; + mld_polyvecl *tmp; + + MLD_ALLOC(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(yh, yh_u, 1, context); + MLD_ALLOC(z, mld_poly, 1, context); + MLD_ALLOC(w1tmp, w1tmp_u, 1, context); + MLD_ALLOC(w0, mld_polyveck, 1, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(t, mld_poly, 1, context); + + if (challenge_bytes == NULL || yh == NULL || z == NULL || w1tmp == NULL || + w0 == NULL || cp == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + y = &yh->y; + h = &yh->h; + w1 = &w1tmp->w1; + tmp = &w1tmp->tmp; + + /* Sample intermediate vector y */ + mld_polyvecl_uniform_gamma1(y, rhoprime, nonce); + + /* Matrix-vector multiplication */ + *tmp = *y; + mld_polyvecl_ntt(tmp); + mld_polyvec_matrix_pointwise_montgomery(w0, mat, tmp); + mld_polyveck_invntt_tomont(w0); + + /* Decompose w and call the random oracle */ + mld_polyveck_caddq(w0); + mld_polyveck_decompose(w1, w0); + mld_polyveck_pack_w1(sig, w1); + + mld_H(challenge_bytes, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, sig, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + /* Constant time: Leaking challenge_bytes does not reveal any information + * about the secret key as H() is modelled as random oracle. + * This also applies to challenges for rejected signatures. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(challenge_bytes, MLDSA_CTILDEBYTES); + mld_poly_challenge(cp, challenge_bytes); + mld_poly_ntt(cp); + + /* Compute z, reject if it reveals secret */ + ret = mld_compute_pack_z(sig, cp, s1, y, t); + if (ret) + { + goto cleanup; + } + + /* Check that subtracting cs2 does not change high bits of w and low bits + * do not reveal secret information */ + mld_polyveck_pointwise_poly_montgomery(h, cp, s2); + mld_polyveck_invntt_tomont(h); + mld_polyveck_sub(w0, h); + mld_polyveck_reduce(w0); + + w0_invalid = mld_polyveck_chknorm(w0, MLDSA_GAMMA2 - MLDSA_BETA); + /* Constant time: w0_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&w0_invalid, sizeof(uint32_t)); + if (w0_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* Compute hints for w1 */ + mld_polyveck_pointwise_poly_montgomery(h, cp, t0); + mld_polyveck_invntt_tomont(h); + mld_polyveck_reduce(h); + + h_invalid = mld_polyveck_chknorm(h, MLDSA_GAMMA2); + /* Constant time: h_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&h_invalid, sizeof(uint32_t)); + if (h_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + mld_polyveck_add(w0, h); + + /* Constant time: At this point all norm checks have passed and we, hence, + * know that the signature does not leak any secret information. + * Consequently, any value that can be computed from the signature and public + * key is considered public. + * w0 and w1 are public as they can be computed from Az - ct = \alpha w1 + w0. + * h=c*t0 is public as both c and t0 are public. + * For a more detailed discussion, refer to https://eprint.iacr.org/2022/1406. + */ + MLD_CT_TESTING_DECLASSIFY(w0, sizeof(*w0)); + MLD_CT_TESTING_DECLASSIFY(w1, sizeof(*w1)); + n = mld_polyveck_make_hint(h, w0, w1); + if (n > MLDSA_OMEGA) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* All is well - write signature */ + mld_pack_sig_c_h(sig, challenge_bytes, h, n); + /* Constant time: At this point it is clear that the signature is valid - it + * can, hence, be considered public. */ + MLD_CT_TESTING_DECLASSIFY(sig, MLDSA_CRYPTO_BYTES); + ret = 0; /* success */ + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_poly, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(w0, mld_polyveck, 1, context); + MLD_FREE(w1tmp, w1tmp_u, 1, context); + MLD_FREE(z, mld_poly, 1, context); + MLD_FREE(yh, yh_u, 1, context); + MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + + return ret; +} +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + uint8_t *rho, *tr, *key, *mu, *rhoprime; + uint16_t nonce = 0; + MLD_ALLOC(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + + if (seedbuf == NULL || mat == NULL || s1 == NULL || t0 == NULL || s2 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + rho = seedbuf; + tr = rho + MLDSA_SEEDBYTES; + key = tr + MLDSA_TRBYTES; + mu = key + MLDSA_SEEDBYTES; + rhoprime = mu + MLDSA_CRHBYTES; + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + if (!externalmu) + { + /* Compute mu = CRH(tr, pre, msg) */ + mld_H(mu, MLDSA_CRHBYTES, tr, MLDSA_TRBYTES, pre, prelen, m, mlen); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Compute rhoprime = CRH(key, rnd, mu) */ + mld_H(rhoprime, MLDSA_CRHBYTES, key, MLDSA_SEEDBYTES, rnd, MLDSA_RNDBYTES, mu, + MLDSA_CRHBYTES); + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + /* Expand matrix and transform vectors */ + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(s1); + mld_polyveck_ntt(s2); + mld_polyveck_ntt(t0); + + /* By default, return failure. Flip to success and write output + * once signature generation succeeds. */ + ret = MLD_ERR_FAIL; + + /* Reference: This code is re-structured using a while(1), */ + /* with explicit "continue" statements (rather than "goto") */ + /* to implement rejection of invalid signatures. */ + while (1) + __loop__( + assigns(nonce, ret, object_whole(siglen), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(nonce <= MLD_NONCE_UB) + + /* t0, s1, s2, and mat are initialized above and are NOT changed by this */ + /* loop. We can therefore re-assert their bounds here as part of the */ + /* loop invariant. This makes proof noticeably faster with CBMC */ + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + invariant(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(ret == MLD_ERR_FAIL) + ) + { + /* Reference: this code explicitly checks for exhaustion of nonce */ + /* values to provide predictable termination and results in that case */ + /* Checking here also means that incrementing nonce below can also */ + /* be proven to be type-safe. */ + if (nonce == MLD_NONCE_UB) + { + /* Note that ret == MLD_ERR_FAIL by default, so we + * don't need to set it here. */ + break; + } + + ret = mld_attempt_signature_generation(sig, mu, rhoprime, nonce, mat, s1, + s2, t0, context); + nonce++; + if (ret == 0) + { + *siglen = MLDSA_CRYPTO_BYTES; + break; + } + else if (ret != MLD_ERR_FAIL) + { + /* For failures such as out-of-memory, propagate and exit immediately. */ + break; + } + + /* Otherwise, try again. */ + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the signature buffer. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + return ret; +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + size_t pre_len; + int ret; + MLD_ALLOC(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + MLD_ALLOC(rnd, uint8_t, MLDSA_RNDBYTES, context); + + if (pre == NULL || rnd == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Prepare domain separation prefix for pure ML-DSA */ + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, m, mlen, pre, pre_len, rnd, sk, + 0, context); + +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(rnd, uint8_t, MLDSA_RNDBYTES, context); + MLD_FREE(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t rnd[MLDSA_RNDBYTES]; + int ret; + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + *siglen = 0; + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, + rnd, sk, 1, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(rnd, sizeof(rnd)); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + for (i = 0; i < mlen; ++i) + __loop__( + assigns(i, object_whole(sm)) + invariant(i <= mlen) + ) + { + sm[MLDSA_CRYPTO_BYTES + mlen - 1 - i] = m[mlen - 1 - i]; + } + ret = mld_sign_signature(sm, smlen, sm + MLDSA_CRYPTO_BYTES, mlen, ctx, + ctxlen, sk, context); + *smlen += mlen; + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret, cmp; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck t1; + mld_polyveck w1; + } + t1w1_u; + mld_polyveck *t1; + mld_polyveck *w1; + + MLD_ALLOC(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_ALLOC(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(z, mld_polyvecl, 1, context); + MLD_ALLOC(t1w1, t1w1_u, 1, context); + MLD_ALLOC(tmp, mld_polyveck, 1, context); + MLD_ALLOC(h, mld_polyveck, 1, context); + + if (buf == NULL || rho == NULL || mu == NULL || c == NULL || c2 == NULL || + cp == NULL || mat == NULL || z == NULL || t1w1 == NULL || tmp == NULL || + h == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + t1 = &t1w1->t1; + w1 = &t1w1->w1; + + if (siglen != MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + mld_unpack_pk(rho, t1, pk); + + /* mld_unpack_sig and mld_polyvecl_chknorm signal failure through a + * single non-zero error code that's not yet aligned with MLD_ERR_XXX. + * Map it to MLD_ERR_FAIL explicitly. */ + if (mld_unpack_sig(c, z, h, sig)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + if (mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + if (!externalmu) + { + /* Compute CRH(H(rho, t1), pre, msg) */ + MLD_ALIGN uint8_t hpk[MLDSA_CRHBYTES]; + mld_H(hpk, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES, NULL, 0, NULL, + 0); + mld_H(mu, MLDSA_CRHBYTES, hpk, MLDSA_TRBYTES, pre, prelen, m, mlen); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(hpk, sizeof(hpk)); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Matrix-vector multiplication; compute Az - c2^dt1 */ + mld_poly_challenge(cp, c); + mld_poly_ntt(cp); + mld_polyveck_shiftl(t1); + mld_polyveck_ntt(t1); + mld_polyveck_pointwise_poly_montgomery(tmp, cp, t1); + + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(z); + mld_polyvec_matrix_pointwise_montgomery(w1, mat, z); + mld_polyveck_sub(w1, tmp); + mld_polyveck_reduce(w1); + mld_polyveck_invntt_tomont(w1); + + /* Reconstruct w1 */ + mld_polyveck_caddq(w1); + mld_polyveck_use_hint(tmp, w1, h); + mld_polyveck_pack_w1(buf, tmp); + /* Call random oracle and verify challenge */ + mld_H(c2, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, buf, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + + cmp = mld_ct_memcmp(c, c2, MLDSA_CTILDEBYTES); + + /* Declassify the result of the verification. */ + MLD_CT_TESTING_DECLASSIFY(&cmp, sizeof(cmp)); + + ret = cmp == 0 ? 0 : MLD_ERR_FAIL; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(h, mld_polyveck, 1, context); + MLD_FREE(tmp, mld_polyveck, 1, context); + MLD_FREE(t1w1, t1w1_u, 1, context); + MLD_FREE(z, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, m, mlen, pre, pre_len, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + return mld_sign_verify_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, pk, + 1, context); +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + if (smlen < MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + *mlen = smlen - MLDSA_CRYPTO_BYTES; + ret = mld_sign_verify(sm, MLDSA_CRYPTO_BYTES, sm + MLDSA_CRYPTO_BYTES, *mlen, + ctx, ctxlen, pk, context); + if (ret == 0) + { + /* All good, copy msg, return 0 */ + for (i = 0; i < *mlen; ++i) + __loop__( + assigns(i, memory_slice(m, *mlen)) + invariant(i <= *mlen) + ) + { + m[i] = sm[MLDSA_CRYPTO_BYTES + i]; + } + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the message buffer. */ + *mlen = 0; + mld_memset(m, 0, smlen); + } + + return ret; +} + + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_signature_internal(sig, siglen, pre, pre_len, NULL, 0, rnd, sk, + 0, context); +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, pre, pre_len, NULL, 0, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_signature_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, rnd, sk, + MLD_PREHASH_SHAKE_256, context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_verify_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, pk, MLD_PREHASH_SHAKE_256, + context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + + +#define MLD_PRE_HASH_OID_LEN 11 + +/************************************************* + * Name: mld_get_hash_oid + * + * Description: Returns the OID of a given SHA-2/SHA-3 hash function. + * + * Arguments: - uint8_t oid[11]: pointer to output oid + * - int hashalg: hash algorithm constant (MLD_PREHASH_*) + * + ***************************************************/ +static void mld_get_hash_oid(uint8_t oid[MLD_PRE_HASH_OID_LEN], int hashalg) +{ + unsigned int i; + static const struct + { + int alg; + uint8_t oid[MLD_PRE_HASH_OID_LEN]; + } oid_map[] = { + {MLD_PREHASH_SHA2_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}}, + {MLD_PREHASH_SHA2_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}}, + {MLD_PREHASH_SHA2_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}}, + {MLD_PREHASH_SHA2_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}}, + {MLD_PREHASH_SHA2_512_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05}}, + {MLD_PREHASH_SHA2_512_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06}}, + {MLD_PREHASH_SHA3_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07}}, + {MLD_PREHASH_SHA3_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08}}, + {MLD_PREHASH_SHA3_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09}}, + {MLD_PREHASH_SHA3_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A}}, + {MLD_PREHASH_SHAKE_128, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B}}, + {MLD_PREHASH_SHAKE_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C}}}; + + for (i = 0; i < sizeof(oid_map) / sizeof(oid_map[0]); i++) + __loop__( + invariant(i <= sizeof(oid_map) / sizeof(oid_map[0])) + ) + { + if (oid_map[i].alg == hashalg) + { + mld_memcpy(oid, oid_map[i].oid, MLD_PRE_HASH_OID_LEN); + return; + } + } +} + +static int mld_validate_hash_length(int hashalg, size_t len) +{ + switch (hashalg) + { + case MLD_PREHASH_SHA2_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_128: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_256: + return (len == 512 / 8) ? 0 : -1; + } + return -1; +} + +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +{ + if (ctxlen > 255) + { + return 0; + } + + if (hashalg != MLD_PREHASH_NONE) + { + if (ph == NULL || mld_validate_hash_length(hashalg, phlen) != 0) + { + return 0; + } + } + + /* Common prefix: 0x00/0x01 || ctxlen || ctx */ + prefix[0] = (hashalg == MLD_PREHASH_NONE) ? 0 : 1; + prefix[1] = (uint8_t)ctxlen; + if (ctxlen > 0) + { + mld_memcpy(prefix + 2, ctx, ctxlen); + } + + if (hashalg == MLD_PREHASH_NONE) + { + return 2 + ctxlen; + } + + /* HashML-DSA: append oid || ph */ + mld_get_hash_oid(prefix + 2 + ctxlen, hashalg); + mld_memcpy(prefix + 2 + ctxlen + MLD_PRE_HASH_OID_LEN, ph, phlen); + return 2 + ctxlen + MLD_PRE_HASH_OID_LEN + phlen; +} + +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + uint8_t check, cmp0, cmp1, chk1, chk2; + int ret; + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(t0_computed, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + + if (rho == NULL || tr == NULL || tr_computed == NULL || key == NULL || + s1 == NULL || s2 == NULL || t0 == NULL || t0_computed == NULL || + t1 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Unpack secret key */ + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + /* Validate s1 and s2 coefficients are within [-MLDSA_ETA, MLDSA_ETA] */ + chk1 = mld_polyvecl_chknorm(s1, MLDSA_ETA + 1) & 0xFF; + chk2 = mld_polyveck_chknorm(s2, MLDSA_ETA + 1) & 0xFF; + + /* Recompute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0_computed, t1, tr_computed, + pk, rho, s1, s2, context); + if (ret != 0) + { + goto cleanup; + } + + /* Validate t0 and tr using constant-time comparisons */ + cmp0 = mld_ct_memcmp((const uint8_t *)t0, (const uint8_t *)t0_computed, + sizeof(mld_polyveck)); + cmp1 = mld_ct_memcmp((const uint8_t *)tr, (const uint8_t *)tr_computed, + MLDSA_TRBYTES); + check = mld_value_barrier_u8(cmp0 | cmp1 | chk1 | chk2); + + /* Declassify the final result of the validity check. */ + MLD_CT_TESTING_DECLASSIFY(&check, sizeof(check)); + ret = (check != 0) ? MLD_ERR_FAIL : 0; + +cleanup: + + if (ret != 0) + { + mld_zeroize(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + } + + /* Constant time: pk is either the valid public key or zeroed on error */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(t0_computed, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + + return ret; +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_check_pct +#undef mld_sample_s1_s2 +#undef mld_validate_hash_length +#undef mld_get_hash_oid +#undef mld_H +#undef mld_compute_pack_z +#undef mld_attempt_signature_generation +#undef mld_compute_t0_t1_tr_from_sk_components +#undef MLD_NONCE_UB +#undef MLD_PRE_HASH_OID_LEN diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/sign.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/sign.h new file mode 100644 index 0000000000..2e0bac32ea --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/sign.h @@ -0,0 +1,807 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_SIGN_H +#define MLD_SIGN_H + +#include +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "polyvec.h" +#include "sys.h" + +#if defined(MLD_CHECK_APIS) +/* Include to ensure consistency between internal sign.h + * and external mldsa_native.h. */ +#include "mldsa_native.h" + +#if MLDSA_CRYPTO_SECRETKEYBYTES != \ + MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for SECRETKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_PUBLICKEYBYTES != \ + MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for PUBLICKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_BYTES != MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for CRYPTO_BYTES between sign.h and mldsa_native.h +#endif + +#endif /* MLD_CHECK_APIS */ + +#define mld_sign_keypair_internal \ + MLD_NAMESPACE_KL(keypair_internal) MLD_CONTEXT_PARAMETERS_3 +#define mld_sign_keypair MLD_NAMESPACE_KL(keypair) MLD_CONTEXT_PARAMETERS_2 +#define mld_sign_signature_internal \ + MLD_NAMESPACE_KL(signature_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_signature MLD_NAMESPACE_KL(signature) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_extmu \ + MLD_NAMESPACE_KL(signature_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign MLD_NAMESPACE_KL(sign) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_internal \ + MLD_NAMESPACE_KL(verify_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify MLD_NAMESPACE_KL(verify) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_extmu \ + MLD_NAMESPACE_KL(verify_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign_open MLD_NAMESPACE_KL(open) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_pre_hash_internal \ + MLD_NAMESPACE_KL(signature_pre_hash_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_verify_pre_hash_internal \ + MLD_NAMESPACE_KL(verify_pre_hash_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_signature_pre_hash_shake256 \ + MLD_NAMESPACE_KL(signature_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify_pre_hash_shake256 \ + MLD_NAMESPACE_KL(verify_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_7 +#define mld_prepare_domain_separation_prefix \ + MLD_NAMESPACE_KL(prepare_domain_separation_prefix) +#define mld_sign_pk_from_sk \ + MLD_NAMESPACE_KL(pk_from_sk) MLD_CONTEXT_PARAMETERS_2 + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: mld_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: input random seed + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int externalmu: indicates input message m is + * processed as mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return MLD_ERR_FAIL in that case. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires((externalmu == 0 && (prelen == 0 || memory_no_alias(pre, prelen))) || + (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) + ensures(return_value == 0 ==> *siglen == MLDSA_CRYPTO_BYTES) + ensures(return_value != 0 ==> *siglen == 0) +); + +/************************************************* + * Name: mld_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_signature_extmu + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign + * + * Description: Compute signed message. + * + * Arguments: - uint8_t *sm: pointer to output signed message + * (allocated array with MLDSA_CRYPTO_BYTES + + *mlen bytes), can be equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sm, MLDSA_CRYPTO_BYTES + mlen)) + requires(memory_no_alias(smlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sm, MLDSA_CRYPTO_BYTES + mlen)) + assigns(object_whole(smlen)) + ensures((return_value == 0 && *smlen == MLDSA_CRYPTO_BYTES + mlen) || + (return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL)) +); + +/************************************************* + * Name: mld_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as + * mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(externalmu == 0 || (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + requires(externalmu == 1 || prelen == 0 || memory_no_alias(pre, prelen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_open + * + * Description: Verify signed message. + * + * Arguments: - uint8_t *m: pointer to output message (allocated array + * with smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context tring + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(smlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(m, smlen)) + requires(memory_no_alias(mlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(sm, smlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + assigns(memory_slice(m, smlen)) + assigns(memory_slice(mlen, sizeof(size_t))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and + * verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/* Maximum formatted domain separation message length: + * - Pure ML-DSA: 0x00 || ctxlen || ctx (max 255) + * - HashML-DSA: 0x01 || ctxlen || ctx (max 255) || oid (11) || ph (max 64) */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +__contract__( + requires(ctxlen <= 255) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(hashalg == MLD_PREHASH_NONE || memory_no_alias(ph, phlen)) + requires(memory_no_alias(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + assigns(memory_slice(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + ensures(return_value <= MLD_DOMAIN_SEPARATION_MAX_BYTES) +); + +/************************************************* + * Name: mld_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: input secret + * key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); +#endif /* !MLD_SIGN_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/symmetric.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/symmetric.h new file mode 100644 index 0000000000..bb70f05552 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/symmetric.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_SYMMETRIC_H +#define MLD_SYMMETRIC_H + +#include +#include "cbmc.h" +#include "common.h" + +#include MLD_FIPS202_HEADER_FILE +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#include MLD_FIPS202X4_HEADER_FILE +#endif + +#define MLD_STREAM128_BLOCKBYTES SHAKE128_RATE +#define MLD_STREAM256_BLOCKBYTES SHAKE256_RATE + +#define mld_xof256_ctx mld_shake256ctx +#define mld_xof256_init(CTX) mld_shake256_init(CTX) + +#define mld_xof256_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake256_absorb(CTX, IN, INBYTES); \ + mld_shake256_finalize(CTX); \ + } while (0) + + +#define mld_xof256_release(CTX) mld_shake256_release(CTX) +#define mld_xof256_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake256_squeeze(OUT, (OUTBLOCKS) * SHAKE256_RATE, STATE) + +#define mld_xof128_ctx mld_shake128ctx +#define mld_xof128_init(CTX) mld_shake128_init(CTX) + +#define mld_xof128_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake128_absorb(CTX, IN, INBYTES); \ + mld_shake128_finalize(CTX); \ + } while (0) + +#define mld_xof128_release(CTX) mld_shake128_release(CTX) +#define mld_xof128_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake128_squeeze(OUT, (OUTBLOCKS) * SHAKE128_RATE, STATE) + +#define mld_xof256_x4_ctx mld_shake256x4ctx +#define mld_xof256_x4_init(CTX) mld_shake256x4_init((CTX)) +#define mld_xof256_x4_absorb(CTX, IN, INBYTES) \ + mld_shake256x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof256_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake256x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof256_x4_release(CTX) mld_shake256x4_release((CTX)) + +#define mld_xof128_x4_ctx mld_shake128x4ctx +#define mld_xof128_x4_init(CTX) mld_shake128x4_init((CTX)) +#define mld_xof128_x4_absorb(CTX, IN, INBYTES) \ + mld_shake128x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof128_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake128x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof128_x4_release(CTX) mld_shake128x4_release((CTX)) + +#endif /* !MLD_SYMMETRIC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/sys.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/sys.h new file mode 100644 index 0000000000..1226526420 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/sys.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_SYS_H +#define MLD_SYS_H + +#if !defined(MLD_CONFIG_NO_ASM) && (defined(__GNUC__) || defined(__clang__)) +#define MLD_HAVE_INLINE_ASM +#endif + +/* Try to find endianness, if not forced through CFLAGS already */ +#if !defined(MLD_SYS_LITTLE_ENDIAN) && !defined(MLD_SYS_BIG_ENDIAN) +#if defined(__BYTE_ORDER__) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define MLD_SYS_LITTLE_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define MLD_SYS_BIG_ENDIAN +#else +#error "__BYTE_ORDER__ defined, but don't recognize value." +#endif +#endif /* __BYTE_ORDER__ */ + +/* MSVC does not define __BYTE_ORDER__. However, MSVC only supports + * little endian x86, x86_64, and AArch64. It is, hence, safe to assume + * little endian. */ +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_IX86) || defined(_M_ARM64)) +#define MLD_SYS_LITTLE_ENDIAN +#endif + +#endif /* !MLD_SYS_LITTLE_ENDIAN && !MLD_SYS_BIG_ENDIAN */ + +/* Check if we're running on an AArch64 little endian system. _M_ARM64 is set by + * MSVC. */ +#if defined(__AARCH64EL__) || defined(_M_ARM64) +#define MLD_SYS_AARCH64 +#endif + +/* Check if we're running on an AArch64 big endian system. */ +#if defined(__AARCH64EB__) +#define MLD_SYS_AARCH64_EB +#endif + +#if defined(__x86_64__) +#define MLD_SYS_X86_64 +#if defined(__AVX2__) +#define MLD_SYS_X86_64_AVX2 +#endif +#endif /* __x86_64__ */ + +#if defined(MLD_SYS_LITTLE_ENDIAN) && defined(__powerpc64__) +#define MLD_SYS_PPC64LE +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 +#define MLD_SYS_RISCV64 +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32 +#define MLD_SYS_RISCV32 +#endif + +#if defined(_WIN64) || defined(_WIN32) +#define MLD_SYS_WINDOWS +#endif + +#if defined(__linux__) +#define MLD_SYS_LINUX +#endif + +#if defined(__APPLE__) +#define MLD_SYS_APPLE +#endif + +/* If MLD_FORCE_AARCH64 is set, assert that we're indeed on an AArch64 system. + */ +#if defined(MLD_FORCE_AARCH64) && !defined(MLD_SYS_AARCH64) +#error "MLD_FORCE_AARCH64 is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_AARCH64_EB is set, assert that we're indeed on a big endian + * AArch64 system. */ +#if defined(MLD_FORCE_AARCH64_EB) && !defined(MLD_SYS_AARCH64_EB) +#error \ + "MLD_FORCE_AARCH64_EB is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_X86_64 is set, assert that we're indeed on an X86_64 system. */ +#if defined(MLD_FORCE_X86_64) && !defined(MLD_SYS_X86_64) +#error "MLD_FORCE_X86_64 is set, but we don't seem to be on an X86_64 system." +#endif + +#if defined(MLD_FORCE_PPC64LE) && !defined(MLD_SYS_PPC64LE) +#error "MLD_FORCE_PPC64LE is set, but we don't seem to be on a PPC64LE system." +#endif + +#if defined(MLD_FORCE_RISCV64) && !defined(MLD_SYS_RISCV64) +#error "MLD_FORCE_RISCV64 is set, but we don't seem to be on a RISCV64 system." +#endif + +#if defined(MLD_FORCE_RISCV32) && !defined(MLD_SYS_RISCV32) +#error "MLD_FORCE_RISCV32 is set, but we don't seem to be on a RISCV32 system." +#endif + +/* + * MLD_INLINE: Hint for inlining. + * - MSVC: __inline + * - C99+: inline + * - GCC/Clang C90: __attribute__((unused)) to silence warnings + * - Other C90: empty + */ +#if !defined(MLD_INLINE) +#if defined(_MSC_VER) +#define MLD_INLINE __inline +#elif defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +#define MLD_INLINE inline +#elif defined(__GNUC__) || defined(__clang__) +#define MLD_INLINE __attribute__((unused)) +#else +#define MLD_INLINE +#endif +#endif /* !MLD_INLINE */ + +/* + * MLD_ALWAYS_INLINE: Force inlining. + * - MSVC: __forceinline + * - GCC/Clang C99+: MLD_INLINE __attribute__((always_inline)) + * - Other: MLD_INLINE (no forced inlining) + */ +#if !defined(MLD_ALWAYS_INLINE) +#if defined(_MSC_VER) +#define MLD_ALWAYS_INLINE __forceinline +#elif (defined(__GNUC__) || defined(__clang__)) && \ + (defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)) +#define MLD_ALWAYS_INLINE MLD_INLINE __attribute__((always_inline)) +#else +#define MLD_ALWAYS_INLINE MLD_INLINE +#endif +#endif /* !MLD_ALWAYS_INLINE */ + +#ifndef MLD_STATIC_TESTABLE +#define MLD_STATIC_TESTABLE static +#endif + +/* + * C90 does not have the restrict compiler directive yet. + * We don't use it in C90 builds. + */ +#if !defined(restrict) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define MLD_RESTRICT restrict +#else +#define MLD_RESTRICT +#endif + +#else /* !restrict */ + +#define MLD_RESTRICT restrict +#endif /* restrict */ + +#define MLD_DEFAULT_ALIGN 32 +#define MLD_ALIGN_UP(N) \ + ((((N) + (MLD_DEFAULT_ALIGN - 1)) / MLD_DEFAULT_ALIGN) * MLD_DEFAULT_ALIGN) +#if defined(__GNUC__) +#define MLD_ALIGN __attribute__((aligned(MLD_DEFAULT_ALIGN))) +#elif defined(_MSC_VER) +#define MLD_ALIGN __declspec(align(MLD_DEFAULT_ALIGN)) +#else +#define MLD_ALIGN /* No known support for alignment constraints */ +#endif + + +/* New X86_64 CPUs support Conflow-flow protection using the CET instructions. + * When enabled (through -fcf-protection=), all compilation units (including + * empty ones) need to support CET for this to work. + * For assembly, this means that source files need to signal support for + * CET by setting the appropriate note.gnu.property section. + * This can be achieved by including the header in all assembly file. + * This file also provides the _CET_ENDBR macro which needs to be placed at + * every potential target of an indirect branch. + * If CET is enabled _CET_ENDBR maps to the endbr64 instruction, otherwise + * it is empty. + * In case the compiler does not support CET (e.g., +#define MLD_CET_ENDBR _CET_ENDBR +#else +#define MLD_CET_ENDBR +#endif +#endif /* MLD_SYS_X86_64 */ + +#if defined(MLD_CONFIG_CT_TESTING_ENABLED) && !defined(__ASSEMBLER__) +#include +#define MLD_CT_TESTING_SECRET(ptr, len) \ + VALGRIND_MAKE_MEM_UNDEFINED((ptr), (len)) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) +#else /* MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__ */ +#define MLD_CT_TESTING_SECRET(ptr, len) \ + do \ + { \ + } while (0) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + do \ + { \ + } while (0) +#endif /* !(MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__) */ + +#if defined(__GNUC__) || defined(__clang__) +#define MLD_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_MUST_CHECK_RETURN_VALUE +#endif + + +#if !defined(__ASSEMBLER__) +/* System capability enumeration */ +typedef enum +{ + /* x86_64 */ + MLD_SYS_CAP_AVX2, + /* AArch64 */ + MLD_SYS_CAP_SHA3 +} mld_sys_cap; + +#if !defined(MLD_CONFIG_CUSTOM_CAPABILITY_FUNC) +#include "cbmc.h" + +static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) +__contract__( + ensures(return_value == 0 || return_value == 1) +) +{ + /* By default, we rely on compile-time feature detection/specification: + * If a feature is enabled at compile-time, we assume it is supported by + * the host that the resulting library/binary will be built on. + * If this assumption is not true, you MUST overwrite this function. + * See the documentation of MLD_CONFIG_CUSTOM_CAPABILITY_FUNC in + * mldsa_native_config.h for more information. */ + (void)cap; + return 1; +} +#endif /* !MLD_CONFIG_CUSTOM_CAPABILITY_FUNC */ +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_SYS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/zetas.inc b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/zetas.inc new file mode 100644 index 0000000000..dc3cf15dd3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/mldsa_native/src/zetas.inc @@ -0,0 +1,56 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include + +/* + * Table of zeta values used in the reference NTT and inverse NTT. + * See autogen for details. + */ +static const int32_t mld_zetas[MLDSA_N] = { + 0, 25847, -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 2353451, -359251, -2091905, 3119733, -2884855, + 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488, + -1119584, 2619752, -2108549, -2118186, -3859737, -1399561, -3277672, + 1757237, -19422, 4010497, 280005, 2706023, 95776, 3077325, + 3530437, -1661693, -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267, + -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596, + 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, + -2797779, -3930395, -1528703, -3677745, -3041255, -1452451, 3475950, + 2176455, -1585221, -1257611, 1939314, -4083598, -1000202, -3190144, + -3157330, -3632928, 126922, 3412210, -983419, 2147896, 2715295, + -2967645, -3693493, -411027, -2477047, -671102, -1228525, -22981, + -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944, + 508951, 3097992, 44288, -1100098, 904516, 3958618, -3724342, + -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856, + 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, + 1341330, 1285669, -1584928, -812732, -1439742, -3019102, -3881060, + -3628969, 3839961, 2091667, 3407706, 2316500, 3817976, -3342478, + 2244091, -2446433, -3562462, 266997, 2434439, -1235728, 3513181, + -3520352, -3759364, -1197226, -3193378, 900702, 1859098, 909542, + 819034, 495491, -1613174, -43260, -522500, -655327, -3122442, + 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297, + 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, + 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, + 1595974, -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, + 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100, + 1312455, 3306115, -1962642, -1279661, 1917081, -2546312, -1374803, + 1500165, 777191, 2235880, 3406031, -542412, -2831860, -1671176, + -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395, + 2454455, -164721, 1957272, 3369112, 185531, -1207385, -3183426, + 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, + -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, + 472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333, + -260646, -3833893, -2939036, -2235985, -420899, -2286327, 183443, + -976891, 1612842, -3545687, -554416, 3919660, -48306, -1362209, + 3937738, 1400424, -846154, 1976782, +}; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/test_only_rng/notrandombytes.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/test_only_rng/notrandombytes.c new file mode 100644 index 0000000000..ef5a423a9e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/test_only_rng/notrandombytes.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* * Based on @[surf]*/ + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +#include +#include + +#include "notrandombytes.h" + +#ifdef ENABLE_CT_TESTING +#include +#endif + +static uint32_t seed[32] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, + 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5}; +static uint32_t in[12]; +static uint32_t out[8]; +static int32_t outleft = 0; + +void randombytes_reset(void) +{ + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + outleft = 0; +} + +#define ROTATE(x, b) (((x) << (b)) | ((x) >> (32 - (b)))) +#define MUSH(i, b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x, b)); + +static void surf(void) +{ + uint32_t t[12]; + uint32_t x; + uint32_t sum = 0; + int32_t r; + int32_t i; + int32_t loop; + + for (i = 0; i < 12; ++i) + { + t[i] = in[i] ^ seed[12 + i]; + } + for (i = 0; i < 8; ++i) + { + out[i] = seed[24 + i]; + } + x = t[11]; + for (loop = 0; loop < 2; ++loop) + { + for (r = 0; r < 16; ++r) + { + sum += 0x9e3779b9; + MUSH(0, 5) + MUSH(1, 7) + MUSH(2, 9) + MUSH(3, 13) + MUSH(4, 5) + MUSH(5, 7) + MUSH(6, 9) + MUSH(7, 13) + MUSH(8, 5) + MUSH(9, 7) + MUSH(10, 9) + MUSH(11, 13) + } + for (i = 0; i < 8; ++i) + { + out[i] ^= t[i + 4]; + } + } +} + +int randombytes(uint8_t *buf, size_t n) +{ +#ifdef ENABLE_CT_TESTING + uint8_t *buf_orig = buf; + size_t n_orig = n; +#endif + + while (n > 0) + { + if (!outleft) + { + if (!++in[0]) + { + if (!++in[1]) + { + if (!++in[2]) + { + ++in[3]; + } + } + } + surf(); + outleft = 8; + } + *buf = (uint8_t)out[--outleft]; + ++buf; + --n; + } + +#ifdef ENABLE_CT_TESTING + /* + * Mark all randombytes output as secret (undefined). + * Valgrind will propagate this to everything derived from it. + */ + VALGRIND_MAKE_MEM_UNDEFINED(buf_orig, n_orig); +#endif /* ENABLE_CT_TESTING */ + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/test_only_rng/notrandombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/test_only_rng/notrandombytes.h new file mode 100644 index 0000000000..bdf9787920 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/bring_your_own_fips202_static/test_only_rng/notrandombytes.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* Based on @[surf]. */ + +#ifndef NOTRANDOMBYTES_H +#define NOTRANDOMBYTES_H + +#include +#include + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +void randombytes_reset(void); +int randombytes(uint8_t *buf, size_t n); + +#endif /* !NOTRANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/.gitignore b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/.gitignore new file mode 100644 index 0000000000..eb98a94f12 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +build diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/Makefile new file mode 100644 index 0000000000..565e4696c8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/Makefile @@ -0,0 +1,109 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +.PHONY: build run clean +.DEFAULT_GOAL := all + +CC ?= gcc + +# Adjust CFLAGS if needed +CFLAGS := \ + -Wall \ + -Wextra \ + -Werror=unused-result \ + -Wpedantic \ + -Werror \ + -Wmissing-prototypes \ + -Wshadow \ + -Wpointer-arith \ + -Wredundant-decls \ + -Wconversion \ + -Wsign-conversion \ + -Wno-long-long \ + -Wno-unknown-pragmas \ + -Wno-unused-command-line-argument \ + -O3 \ + -fomit-frame-pointer \ + -std=c99 \ + -pedantic \ + -MMD \ + $(CFLAGS) + +# If you want to use the native backends, the compiler needs to know about +# the target architecture. Here, we import the default host detection from +# mldsa-native's tests, but you can write your own or specialize accordingly. +AUTO ?= 1 +include auto.mk + +# The following only concerns the cross-compilation tests. +# You can likely ignore the following for your application. +# +# Append cross-prefix for cross compilation +# When called from the root Makefile, CROSS_PREFIX has already been added here +ifeq (,$(findstring $(CROSS_PREFIX),$(CC))) +CC := $(CROSS_PREFIX)$(CC) +endif + +# Part A: +# +# mldsa-native source and header files +# +# In this example, we compile the individual mldsa-native source files directly. +# Alternatively, you can compile the 'monobuild' source file mldsa_native.c. +# See examples/monolithic_build for that. +MLD_SOURCE=$(wildcard \ + mldsa_native/src/*.c \ + mldsa_native/src/**/*.c \ + mldsa_native/src/**/**/*.c \ + mldsa_native/src/**/**/**/*.c \ + mldsa_native/src/**/**/**/**/*.c) + +INC=-Imldsa_native -Imldsa_native/mldsa + +# Part B: +# +# Random number generator +# +# !!! WARNING !!! +# +# The randombytes() implementation used here is for TESTING ONLY. +# You MUST NOT use this implementation outside of testing. +# +# !!! WARNING !!! +RNG_SOURCE=$(wildcard test_only_rng/*.c) + +# Part C: +# +# Your application source code +APP_SOURCE=$(wildcard *.c) + +ALL_SOURCE=$(MLD_SOURCE) $(RNG_SOURCE) $(APP_SOURCE) + +BUILD_DIR=build +BIN=test_binary + +BINARY_NAME_FULL_44=$(BUILD_DIR)/$(BIN)44 +BINARY_NAME_FULL_65=$(BUILD_DIR)/$(BIN)65 +BINARY_NAME_FULL_87=$(BUILD_DIR)/$(BIN)87 +BINARIES_FULL=$(BINARY_NAME_FULL_44) $(BINARY_NAME_FULL_65) $(BINARY_NAME_FULL_87) + +$(BINARY_NAME_FULL_44): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=44 +$(BINARY_NAME_FULL_65): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=65 +$(BINARY_NAME_FULL_87): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=87 + +$(BINARIES_FULL): $(ALL_SOURCE) + echo "$@" + mkdir -p $(BUILD_DIR) + $(CC) $(CFLAGS) $(INC) $^ -o $@ + +all: build + +build: $(BINARIES_FULL) + +run: $(BINARIES_FULL) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_44) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_65) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_87) + +clean: + rm -rf $(BUILD_DIR) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/README.md new file mode 100644 index 0000000000..9412dba972 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/README.md @@ -0,0 +1,70 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Custom FIPS-202 Backend + +This directory contains a minimal example for using mldsa-native with a custom FIPS-202 *backend* +(as opposed to a complete custom FIPS-202 implementation). We use tiny_sha3[^tiny_sha3] as an example. + +## Use Case + +Use this approach when: +- You need only one ML-DSA parameter set (44, 65, 87) +- You want to replace the low-level Keccak-f1600 permutation +- You want to keep mldsa-native's FIPS-202 frontend (absorb/squeeze logic) + +This differs from `bring_your_own_fips202` in that you only replace the *backend* (Keccak permutation), +not the entire FIPS-202 implementation. + +## Components + +1. Arithmetic part of mldsa-native: [`mldsa/src/`](../../mldsa/src) +2. FIPS-202 frontend: [`mldsa/src/fips202/`](../../mldsa/src/fips202) (can remove existing backends) +3. A secure random number generator implementing [`randombytes.h`](../../mldsa/src/randombytes.h) +4. Custom FIPS-202 backend (see below) +5. Your application source code + +## Configuration + +The configuration file [mldsa_native_config.h](mldsa_native/mldsa_native_config.h) sets: +- `MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202`: Enables native FIPS-202 backend +- `MLD_CONFIG_FIPS202_BACKEND_FILE`: Path to your custom backend metadata file + +A custom backend consists of: +1. A metadata header (e.g., [custom.h](mldsa_native/src/fips202/native/custom/custom.h)) that: + - Sets `MLD_USE_FIPS202_X1_NATIVE` (and/or `X4`) to indicate which functions are replaced + - Includes the implementation header +2. An implementation providing `mld_keccakf1600_native()` (and/or batched variants) + +Example backend metadata file: +```c +#ifndef CUSTOM_FIPS202_BACKEND_H +#define CUSTOM_FIPS202_BACKEND_H + +/* Indicate we're replacing 1-fold Keccak-f1600 */ +#define MLD_USE_FIPS202_X1_NATIVE + +/* Include the implementation */ +#include "custom/src/keccak_impl.h" + +#endif +``` + +## Notes + +- The tiny_sha3 code uses byte-reversed Keccak state on big-endian targets; this example removes + that reversal since mldsa-native's frontend assumes standard byte order + +## Usage + +```bash +make build # Build the example +make run # Run the example +``` + +## Warning + +The `randombytes()` implementation in `test_only_rng/` is for TESTING ONLY. +You MUST provide a cryptographically secure RNG for production use. + + +[^tiny_sha3]: Markku-Juhani O. Saarinen: tiny_sha3, [https://github.com/mjosaarinen/tiny_sha3](https://github.com/mjosaarinen/tiny_sha3) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/auto.mk b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/auto.mk new file mode 100644 index 0000000000..5f71942085 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/auto.mk @@ -0,0 +1,178 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# Automatically detect system architecture and set preprocessor flags accordingly +# This file detects host CPU capabilities and combines them with compiler support +# to enable optimal compilation flags. +# +# Compiler feature detection can be overridden by setting the corresponding variable +# on the command line: +# make MK_COMPILER_SUPPORTS_SHA3=0 # Disable SHA3 detection +# make MK_COMPILER_SUPPORTS_AVX2=0 # Disable AVX2 detection +# make MK_COMPILER_SUPPORTS_BMI2=0 # Disable BMI2 detection +# make MK_COMPILER_SUPPORTS_SSE2=0 # Disable SSE2 detection + +ifndef _AUTO_MK +_AUTO_MK := + +# Override ARCH for cross-compilation based on CROSS_PREFIX +ifeq ($(CROSS_PREFIX),) +ARCH := $(shell uname -m) +# Normalize architecture names +ifeq ($(ARCH),arm64) +ARCH := aarch64 +endif +else # CROSS_PREFIX +ifneq ($(findstring x86_64, $(CROSS_PREFIX)),) +ARCH := x86_64 +else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),) +ARCH := aarch64_be +else ifneq ($(findstring aarch64, $(CROSS_PREFIX)),) +ARCH := aarch64 +else ifneq ($(findstring riscv64, $(CROSS_PREFIX)),) +ARCH := riscv64 +else ifneq ($(findstring riscv32, $(CROSS_PREFIX)),) +ARCH := riscv32 +else ifneq ($(findstring powerpc64le, $(CROSS_PREFIX)),) +ARCH := powerpc64le +else ifneq ($(findstring arm-none-eabi-, $(CROSS_PREFIX)),) +ARCH := arm +else +ifeq ($(AUTO),1) +$(warning Unknown cross-compilation prefix $(CROSS_PREFIX), no automatic detection of CFLAGS.) +ARCH := unknown +endif +endif +endif # CROSS_PREFIX + +# x86_64 compiler feature detection +ifeq ($(ARCH),x86_64) + +# Test AVX2 support using C with inline assembly +MK_COMPILER_SUPPORTS_AVX2 ?= $(shell echo 'int main() { __asm__("vpxor %%ymm0, %%ymm1, %%ymm2" ::: "ymm0", "ymm1", "ymm2"); return 0; }' | $(CC) -mavx2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test SSE2 support using C with inline assembly +MK_COMPILER_SUPPORTS_SSE2 ?= $(shell echo 'int main() { __asm__("pxor %%xmm0, %%xmm1" ::: "xmm0", "xmm1"); return 0; }' | $(CC) -msse2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test BMI2 support using C with inline assembly +MK_COMPILER_SUPPORTS_BMI2 ?= $(shell echo 'int main() { __asm__("pdep %%eax, %%ebx, %%ecx" ::: "eax", "ebx", "ecx"); return 0; }' | $(CC) -mbmi2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # x86_64 compiler detection + +# AArch64 compiler feature detection +ifeq ($(ARCH),aarch64) + +# Test SHA3 support (Armv8.4-a+SHA3) using C with inline assembly +MK_COMPILER_SUPPORTS_SHA3 ?= $(shell echo 'int main() { __asm__("eor3 v0.16b, v1.16b, v2.16b, v3.16b" ::: "v0", "v1", "v2", "v3"); return 0; }' | $(CC) -march=armv8.4-a+sha3 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # aarch64 compiler detection + +# Define HOST_PLATFORM if not already defined +HOST_PLATFORM ?= $(shell uname -s)-$(shell uname -m) + +# Helper function to check if host CPU supports a feature +# Usage: $(call check_host_feature,feature_pattern,source_command) +define check_host_feature +$(shell $(2) 2>/dev/null | grep -q "$(1)" && echo 1 || echo 0) +endef + +# x86_64 architecture detection +ifeq ($(ARCH),x86_64) + +# Host CPU feature detection for x86_64 +ifeq ($(HOST_PLATFORM),Linux-x86_64) +# Linux: Use /proc/cpuinfo +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,avx2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,sse2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,bmi2,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-x86_64) +# macOS: Use sysctl +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,AVX2,sysctl -n machdep.cpu.leaf7_features) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,SSE2,sysctl -n machdep.cpu.features) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,BMI2,sysctl -n machdep.cpu.leaf7_features) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_AVX2 := 1 +MK_HOST_SUPPORTS_SSE2 := 1 +MK_HOST_SUPPORTS_BMI2 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_AVX2 := 0 +MK_HOST_SUPPORTS_SSE2 := 0 +MK_HOST_SUPPORTS_BMI2 := 0 +endif # HOST_PLATFORM x86_64 + +endif # x86_64 + +# AArch64 architecture detection +ifeq ($(ARCH),aarch64) + +# Host CPU feature detection for AArch64 +ifeq ($(HOST_PLATFORM),Linux-aarch64) +# Linux: Use /proc/cpuinfo (look for sha3 in Features line) +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,sha3,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-arm64) +# macOS: Use sysctl to check for SHA3 support +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,1,sysctl -n hw.optional.armv8_2_sha3) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_SHA3 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_SHA3 := 0 +endif # HOST_PLATFORM aarch64 + +endif # aarch64 + +# Only apply CFLAGS modifications if AUTO=1 +ifeq ($(AUTO),1) + +# x86_64 CFLAGS configuration +ifeq ($(ARCH),x86_64) +CFLAGS += -DMLD_FORCE_X86_64 + +# Add flags only if both compiler and host support the feature +ifeq ($(MK_COMPILER_SUPPORTS_AVX2)$(MK_HOST_SUPPORTS_AVX2),11) +CFLAGS += -mavx2 +endif + +ifeq ($(MK_COMPILER_SUPPORTS_BMI2)$(MK_HOST_SUPPORTS_BMI2),11) +CFLAGS += -mbmi2 +endif +endif # x86_64 + +# AArch64 CFLAGS configuration +ifeq ($(ARCH),aarch64) +CFLAGS += -DMLD_FORCE_AARCH64 + +# Add SHA3 flags only if both compiler and host support it +ifeq ($(MK_COMPILER_SUPPORTS_SHA3)$(MK_HOST_SUPPORTS_SHA3),11) +CFLAGS += -march=armv8.4-a+sha3 +endif +endif # aarch64 + +# AArch64 Big Endian CFLAGS configuration +ifeq ($(ARCH),aarch64_be) +CFLAGS += -DMLD_FORCE_AARCH64_EB +endif # aarch64_be + +# RISC-V 64-bit CFLAGS configuration +ifeq ($(ARCH),riscv64) +CFLAGS += -DMLD_FORCE_RISCV64 +CFLAGS += -march=rv64gcv +endif # riscv64 + +# RISC-V 32-bit CFLAGS configuration +ifeq ($(ARCH),riscv32) +CFLAGS += -DMLD_FORCE_RISCV32 +endif # riscv32 + +# PowerPC 64-bit Little Endian CFLAGS configuration +ifeq ($(ARCH),powerpc64le) +CFLAGS += -DMLD_FORCE_PPC64LE +endif # powerpc64le + +endif # AUTO=1 + +endif # _AUTO_MK diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/expected_signatures.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/expected_signatures.h new file mode 100644 index 0000000000..d52fbe8d5e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/expected_signatures.h @@ -0,0 +1,890 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef EXPECTED_SIGNATURES_H +#define EXPECTED_SIGNATURES_H + +#include + +/* Expected deterministic signatures for each parameter set + * These are generated using the same test message, context, and deterministic + * RNG as used in the basic example. + * + * The PCT modifies the PRNG state, so the KAT tests don't work. + * We run KAT tests only for disabled PCT. */ +#if !defined(MLD_CONFIG_KEYGEN_PCT) +#if MLD_CONFIG_PARAMETER_SET == 44 +const uint8_t expected_signature[] = { + 0x27, 0x5e, 0xbe, 0x2d, 0x23, 0x1a, 0x76, 0xc5, 0xd9, 0x77, 0xcb, 0x62, + 0x25, 0x04, 0xdb, 0x23, 0x31, 0xa9, 0xa8, 0xcd, 0xbc, 0xde, 0xf2, 0x20, + 0xfd, 0xa7, 0xb5, 0xf5, 0x59, 0xae, 0xe6, 0xdd, 0x62, 0xfa, 0x34, 0x96, + 0x4f, 0x1d, 0xcd, 0x84, 0x82, 0xee, 0xc1, 0x74, 0x96, 0x3d, 0x98, 0xd9, + 0x42, 0x9d, 0xd0, 0x77, 0x9c, 0xf9, 0x9e, 0x0e, 0xa7, 0xcb, 0x70, 0xeb, + 0xe7, 0xcd, 0xce, 0x8c, 0xdc, 0x37, 0x15, 0x95, 0x0e, 0x24, 0x70, 0x4f, + 0x33, 0x6e, 0x4f, 0xad, 0xed, 0x4d, 0xf3, 0xe5, 0x38, 0xc1, 0xcd, 0xbb, + 0xde, 0xf1, 0xd2, 0x0d, 0xd6, 0x6b, 0xa3, 0x68, 0x92, 0x4c, 0x4b, 0x4f, + 0x89, 0xa0, 0xa8, 0xc8, 0x36, 0x93, 0x91, 0x17, 0xe7, 0x16, 0xed, 0xcb, + 0xdc, 0xf6, 0x28, 0x13, 0x32, 0x60, 0x14, 0xe0, 0x28, 0x7a, 0x69, 0x05, + 0x1d, 0xf7, 0x3b, 0xdf, 0x18, 0x0c, 0xaf, 0xba, 0x46, 0xf1, 0x5e, 0xd4, + 0xd3, 0xd0, 0x8e, 0x9a, 0xe2, 0xac, 0xdd, 0x0e, 0x5f, 0xb1, 0x69, 0xe2, + 0x74, 0x77, 0x2e, 0x52, 0xf9, 0x11, 0x3d, 0xd8, 0xe5, 0x36, 0x6f, 0x7d, + 0x7d, 0xde, 0x7c, 0xa7, 0x1d, 0x37, 0xdf, 0x6d, 0x5e, 0xea, 0xc8, 0xc0, + 0x72, 0x3f, 0x79, 0xbd, 0x0b, 0x6d, 0x7f, 0x9a, 0x15, 0x90, 0xda, 0xc1, + 0xae, 0xce, 0xf3, 0x44, 0x35, 0x5e, 0x83, 0x86, 0x7e, 0x89, 0x18, 0xa7, + 0x97, 0x8e, 0x87, 0x7c, 0x15, 0xd2, 0xd2, 0x7e, 0xf2, 0xc8, 0x29, 0x4f, + 0x70, 0x0f, 0xa6, 0xd4, 0x76, 0xe8, 0xdd, 0x7d, 0x7a, 0x2d, 0xfe, 0x0a, + 0x0c, 0x5c, 0xb1, 0xef, 0xec, 0x1a, 0x32, 0xca, 0x87, 0xff, 0x6b, 0xb1, + 0xa0, 0xe1, 0x2e, 0x01, 0x52, 0xb2, 0xb8, 0x74, 0x34, 0xb3, 0xfb, 0x15, + 0x0f, 0x17, 0xca, 0x74, 0xc1, 0xc1, 0x61, 0x86, 0x40, 0x38, 0x58, 0xba, + 0x82, 0x26, 0x66, 0x33, 0xa4, 0x52, 0xf3, 0xb5, 0x36, 0x60, 0xd8, 0x5a, + 0x8d, 0x9d, 0x28, 0x18, 0x3a, 0x68, 0x34, 0x2a, 0xa2, 0xe2, 0xb5, 0x39, + 0xed, 0x7d, 0xe5, 0xbe, 0x46, 0xb9, 0x04, 0x0c, 0xf3, 0xef, 0x88, 0x6e, + 0x9d, 0x6f, 0x23, 0xe2, 0x44, 0xe5, 0x2e, 0x3a, 0x7a, 0x1d, 0x49, 0x0f, + 0xdd, 0xcd, 0xd6, 0x4e, 0x0d, 0x0b, 0xc3, 0x35, 0xf2, 0xd1, 0x5d, 0x73, + 0x5d, 0x07, 0xca, 0x5c, 0xbd, 0x14, 0xec, 0x57, 0xb3, 0xbd, 0x37, 0xe7, + 0xdf, 0x06, 0x7d, 0xe0, 0x58, 0x4a, 0xcf, 0x7a, 0xc5, 0xa7, 0x24, 0x62, + 0x6f, 0x09, 0x75, 0x69, 0x74, 0x7f, 0xdf, 0xc8, 0x69, 0x5c, 0x20, 0x10, + 0x3a, 0xe8, 0x01, 0x12, 0xa3, 0xfb, 0xda, 0x4c, 0x3a, 0x0d, 0x3c, 0x3e, + 0x26, 0xe0, 0xa6, 0x7f, 0xb2, 0x6b, 0x0b, 0x68, 0x0a, 0x68, 0x86, 0xb1, + 0xfa, 0x61, 0x3a, 0xe8, 0x77, 0xdc, 0x42, 0xf7, 0xf4, 0x39, 0x9a, 0x40, + 0x58, 0x71, 0xc7, 0x0f, 0xf4, 0x0e, 0xc5, 0x1e, 0xe0, 0x28, 0x45, 0x7d, + 0xba, 0x84, 0xe4, 0x34, 0x69, 0xf9, 0xa5, 0x8a, 0x80, 0x43, 0xc0, 0x8d, + 0x04, 0x33, 0x43, 0xb8, 0xd7, 0x5d, 0x93, 0xed, 0x0f, 0x31, 0x6a, 0x4d, + 0xbf, 0xb7, 0x44, 0x41, 0x1b, 0xd4, 0xac, 0x9d, 0x83, 0x66, 0x08, 0x92, + 0xad, 0x3c, 0x0e, 0x1a, 0xe8, 0xd4, 0xe1, 0x5c, 0x63, 0xcf, 0x27, 0x48, + 0x5a, 0x8f, 0xc5, 0x6f, 0x83, 0x6b, 0x6f, 0xe8, 0xda, 0x1f, 0xba, 0xe9, + 0x7e, 0x11, 0xab, 0x8b, 0x4e, 0xc1, 0x9e, 0x23, 0x69, 0x1f, 0x42, 0x40, + 0xad, 0xbb, 0xfb, 0x4f, 0xe2, 0x50, 0xc9, 0x46, 0xe7, 0x15, 0x15, 0xf8, + 0x61, 0x09, 0x2a, 0x0b, 0x37, 0x43, 0xd4, 0x98, 0x5f, 0xc8, 0x4d, 0x06, + 0xe7, 0x0c, 0x3f, 0x83, 0x59, 0xd5, 0xcd, 0x2d, 0xde, 0x1e, 0x3a, 0x87, + 0x4e, 0xf7, 0x0a, 0x3c, 0x84, 0x72, 0x47, 0x11, 0x02, 0x6c, 0xe8, 0x93, + 0xcd, 0x24, 0xe9, 0x23, 0x86, 0x78, 0x53, 0xe0, 0xc6, 0x2f, 0xba, 0xa7, + 0xed, 0xaf, 0xba, 0x42, 0x80, 0x0d, 0xe6, 0xae, 0xda, 0xed, 0xbc, 0x65, + 0x21, 0x6d, 0x13, 0x90, 0x61, 0xb4, 0x05, 0x7b, 0x07, 0x86, 0xd7, 0x89, + 0x30, 0x9c, 0xc1, 0x9a, 0x41, 0x4d, 0xe8, 0x2b, 0x35, 0x21, 0x3a, 0x8a, + 0x60, 0x83, 0x1a, 0x97, 0x10, 0x98, 0xb6, 0xe1, 0x6b, 0xb5, 0xb1, 0xa1, + 0x36, 0x34, 0x60, 0x1b, 0x96, 0x5d, 0x1f, 0x2a, 0xd8, 0xf2, 0x94, 0xdd, + 0x58, 0x3d, 0x0f, 0xbe, 0x9d, 0xfc, 0xf5, 0x24, 0xb1, 0xd2, 0xc3, 0x36, + 0xef, 0xdb, 0x8e, 0x97, 0x3c, 0x9a, 0x4f, 0x48, 0xe3, 0x84, 0x91, 0xd8, + 0x39, 0x91, 0xf6, 0x55, 0xeb, 0x62, 0x51, 0x3d, 0x8f, 0x55, 0x60, 0x5e, + 0x00, 0xe0, 0xd2, 0xc7, 0x66, 0x51, 0xf1, 0xe2, 0xb7, 0x43, 0xc3, 0xe6, + 0x12, 0x9a, 0xe5, 0x84, 0xe0, 0x10, 0x76, 0xc7, 0x75, 0x6e, 0xa6, 0xee, + 0x11, 0xe4, 0xaf, 0xbd, 0x8a, 0x4f, 0x1d, 0x05, 0x29, 0x4f, 0xce, 0xa5, + 0x73, 0x92, 0x57, 0x7e, 0x0d, 0x11, 0xbc, 0xf8, 0x74, 0x4d, 0xf7, 0xb9, + 0x40, 0x0d, 0x5a, 0xa1, 0x19, 0x76, 0x4a, 0xae, 0x21, 0x16, 0xd4, 0x3f, + 0x76, 0xbf, 0x27, 0xbd, 0x2f, 0xe4, 0x25, 0x21, 0x00, 0x4e, 0xcc, 0x7c, + 0xc6, 0x57, 0xa4, 0xbf, 0xf1, 0x56, 0x90, 0xe0, 0xa4, 0xa3, 0xee, 0xcf, + 0x43, 0x4f, 0xda, 0x77, 0x47, 0x51, 0x79, 0x6a, 0x29, 0xb4, 0x2c, 0xdf, + 0xca, 0x47, 0xcb, 0xb8, 0x82, 0x7e, 0x44, 0x62, 0x9b, 0x8f, 0x61, 0x7b, + 0x3a, 0x93, 0x82, 0x1f, 0x69, 0xb7, 0xb1, 0xa6, 0x2c, 0xe1, 0xb2, 0x65, + 0xa0, 0x6d, 0x6f, 0xe4, 0x79, 0xd8, 0x30, 0xe0, 0xee, 0xd8, 0x83, 0x01, + 0xb2, 0x1f, 0x5c, 0x90, 0x44, 0x86, 0x48, 0x11, 0xf9, 0x11, 0xff, 0xea, + 0x45, 0x43, 0xae, 0x8a, 0x6b, 0x99, 0xf2, 0x1f, 0x02, 0x51, 0x4a, 0x35, + 0x02, 0x34, 0xd3, 0xe8, 0xda, 0xb1, 0x4b, 0xe3, 0xa5, 0x60, 0xce, 0x67, + 0xe3, 0x62, 0x59, 0xfc, 0x00, 0x0a, 0xe2, 0xfe, 0x7b, 0x1e, 0xe6, 0xf5, + 0x75, 0x19, 0x9b, 0x5e, 0xcb, 0xe6, 0xf5, 0x80, 0x9e, 0x3c, 0xb8, 0x54, + 0xd6, 0x0b, 0xfd, 0x48, 0xe0, 0xfa, 0x82, 0x2b, 0x5b, 0x26, 0xf9, 0x49, + 0xaf, 0xbe, 0x9c, 0x78, 0x73, 0xce, 0xc5, 0x65, 0xe2, 0x94, 0x2b, 0xd9, + 0xd0, 0x27, 0x3a, 0x66, 0x3e, 0xe2, 0xe0, 0x10, 0x79, 0x3d, 0xde, 0xc8, + 0x47, 0xdb, 0x1e, 0xc3, 0xe7, 0x51, 0xae, 0x59, 0xeb, 0x38, 0x66, 0x63, + 0x40, 0x8f, 0xbe, 0x1e, 0xb2, 0x2b, 0xeb, 0x64, 0x5f, 0xdd, 0x24, 0xc4, + 0x5a, 0x25, 0x59, 0xa2, 0xda, 0x4f, 0xdf, 0xf8, 0xb0, 0xb0, 0xf7, 0xcd, + 0x1f, 0x14, 0xcd, 0x09, 0x48, 0x70, 0x27, 0x1b, 0xde, 0xc4, 0xf0, 0xf3, + 0x56, 0x97, 0x8a, 0xb7, 0xf4, 0x19, 0x76, 0xe3, 0x9a, 0x33, 0x55, 0xfe, + 0x93, 0x68, 0xca, 0x1f, 0x3d, 0x44, 0x86, 0x39, 0x5d, 0x84, 0x58, 0x50, + 0xf2, 0xf1, 0xea, 0x4a, 0x5c, 0x1c, 0x74, 0xf0, 0x4b, 0xa5, 0x9c, 0x30, + 0xa0, 0x14, 0x1a, 0x80, 0xe0, 0xde, 0x3e, 0xae, 0x7f, 0x10, 0x18, 0x4a, + 0x1e, 0x9e, 0x6b, 0x75, 0x1a, 0xca, 0x08, 0x4e, 0x61, 0x72, 0x43, 0x9b, + 0x18, 0x4d, 0x2c, 0xd8, 0xb4, 0xc9, 0xea, 0x00, 0xb0, 0xdf, 0x1b, 0xcb, + 0x03, 0xc3, 0x7a, 0x27, 0xff, 0x41, 0x9d, 0xf9, 0xfd, 0xb3, 0x0c, 0xc0, + 0x48, 0x5d, 0x7c, 0xae, 0x5a, 0x72, 0x69, 0x93, 0x68, 0xe1, 0x9e, 0x9f, + 0x1f, 0x5c, 0x0a, 0x60, 0x90, 0x1a, 0x8e, 0x5a, 0x30, 0xd4, 0x2c, 0xbd, + 0xe1, 0x20, 0x51, 0xbc, 0x1c, 0x50, 0xb5, 0xf7, 0x42, 0x23, 0x35, 0x0f, + 0x92, 0xe2, 0xbb, 0x2a, 0x04, 0xa7, 0xde, 0x2e, 0x25, 0xfa, 0xed, 0x20, + 0x83, 0x9c, 0xd4, 0x56, 0xe0, 0x4d, 0x8d, 0x79, 0xa5, 0xa0, 0x6f, 0x49, + 0x62, 0x82, 0x9a, 0xa7, 0x4e, 0x54, 0x95, 0x0a, 0xc6, 0x5e, 0x27, 0x65, + 0x6d, 0x11, 0x2b, 0x35, 0x72, 0x34, 0x48, 0xd2, 0xe4, 0x9e, 0x07, 0x7d, + 0x03, 0x27, 0x15, 0x93, 0x55, 0x5c, 0x32, 0x43, 0xdb, 0x34, 0x8d, 0xbd, + 0x8d, 0x88, 0xa5, 0x24, 0x07, 0x93, 0x89, 0x37, 0xb9, 0x17, 0x15, 0xad, + 0xc7, 0x68, 0x86, 0x63, 0x0f, 0x10, 0x53, 0x8f, 0x40, 0xd3, 0x7b, 0x22, + 0x2b, 0x1a, 0x4c, 0xcb, 0x4f, 0x51, 0xf1, 0x3b, 0x19, 0xb8, 0x42, 0x53, + 0xaf, 0xf6, 0xb9, 0x57, 0x7f, 0xba, 0x8d, 0xb8, 0xb7, 0x3b, 0xe3, 0xc5, + 0xab, 0x4a, 0x26, 0x21, 0x6e, 0xce, 0x27, 0xb8, 0xc3, 0x99, 0x56, 0x14, + 0xdd, 0x5b, 0x61, 0x82, 0xbf, 0xd3, 0xc8, 0x76, 0xee, 0x22, 0xaf, 0x21, + 0x21, 0x1d, 0x4e, 0x33, 0xb5, 0x43, 0x3a, 0xfb, 0x91, 0xa0, 0xaa, 0xe3, + 0x10, 0x4a, 0x50, 0x42, 0xd4, 0x5f, 0x92, 0x0e, 0x71, 0x60, 0x4f, 0xaa, + 0xef, 0x66, 0x45, 0xfe, 0xf7, 0xc8, 0xb0, 0x73, 0x75, 0x91, 0x0b, 0x86, + 0x40, 0xa5, 0x02, 0x28, 0xf7, 0xe0, 0x1f, 0x5d, 0xe6, 0xe3, 0xa4, 0x57, + 0xbd, 0x29, 0xaa, 0x53, 0xae, 0x35, 0x30, 0x78, 0x73, 0xd6, 0xb7, 0x01, + 0x9d, 0x13, 0x50, 0xf6, 0x39, 0xa2, 0x3e, 0x03, 0x04, 0xaa, 0x6d, 0xcf, + 0x6b, 0xff, 0x9a, 0xbe, 0x3e, 0x0a, 0xd4, 0x20, 0xce, 0x42, 0x1f, 0xca, + 0x2f, 0xd3, 0x2c, 0xd1, 0xf4, 0xd2, 0x50, 0xd3, 0xa2, 0xc1, 0x1e, 0x87, + 0xbf, 0xeb, 0xb8, 0xa8, 0xd4, 0x1c, 0x96, 0xb8, 0x8e, 0xbe, 0x35, 0x5f, + 0x08, 0x28, 0x20, 0x2b, 0xdc, 0xa4, 0xf5, 0xf6, 0xde, 0xca, 0x1e, 0xcb, + 0x93, 0x3b, 0x64, 0x79, 0x00, 0x3c, 0x8d, 0xbb, 0x5c, 0x7a, 0x40, 0x14, + 0x58, 0x12, 0xa4, 0xf7, 0x6e, 0x51, 0xfb, 0xe7, 0x6f, 0x49, 0x5b, 0xc2, + 0xc9, 0x05, 0x38, 0x9c, 0x08, 0x78, 0x71, 0x27, 0x2b, 0xf5, 0xbf, 0xd6, + 0x38, 0xaa, 0x45, 0xe1, 0xe1, 0x4c, 0xfb, 0xfd, 0xb7, 0xe6, 0xcf, 0xad, + 0x9e, 0x56, 0xaf, 0x12, 0x12, 0x98, 0xe6, 0x38, 0xaa, 0xee, 0xdb, 0x9e, + 0xca, 0xe1, 0x79, 0x6d, 0x44, 0xfb, 0x19, 0x50, 0x92, 0x00, 0x06, 0x2c, + 0x24, 0x71, 0x6c, 0x34, 0x45, 0xac, 0xf9, 0x82, 0x66, 0xa8, 0x63, 0x80, + 0xa8, 0x5b, 0x21, 0x3c, 0x36, 0x71, 0x93, 0x40, 0x7b, 0xff, 0xa2, 0xd0, + 0x72, 0xb4, 0x66, 0xfa, 0xfc, 0xa0, 0xee, 0xca, 0x15, 0x73, 0x52, 0xe7, + 0x9d, 0x11, 0xd3, 0xbc, 0xab, 0x37, 0x31, 0x0e, 0xaf, 0xdc, 0x05, 0x30, + 0x79, 0x8c, 0x25, 0x75, 0x5c, 0x60, 0xc7, 0x9a, 0xfc, 0x88, 0xea, 0xe6, + 0x09, 0x9f, 0xd1, 0x4f, 0x13, 0xf4, 0x41, 0x54, 0x5b, 0x7a, 0xe4, 0x49, + 0x3c, 0x0f, 0x15, 0xe9, 0xa4, 0x85, 0xb2, 0x92, 0x07, 0xea, 0xea, 0x7c, + 0xc1, 0x6d, 0xa9, 0x03, 0xb3, 0x31, 0xce, 0x1e, 0x82, 0xca, 0x9e, 0x3c, + 0x88, 0x88, 0xc1, 0x04, 0x5f, 0xbe, 0xd5, 0x94, 0x0d, 0x67, 0x98, 0x27, + 0xd0, 0x0f, 0x43, 0xf3, 0xb3, 0xfc, 0xff, 0x24, 0xa2, 0x1e, 0x17, 0x06, + 0xb0, 0x52, 0x16, 0x7c, 0xd8, 0x49, 0x74, 0x51, 0xcf, 0x2d, 0x36, 0x16, + 0xb0, 0x88, 0xb2, 0x2b, 0x1d, 0x72, 0x70, 0xab, 0xe2, 0xf6, 0x5f, 0xa5, + 0x2d, 0x4e, 0xd1, 0x42, 0x3c, 0x83, 0x84, 0xb2, 0x56, 0xeb, 0x8d, 0xce, + 0x33, 0x46, 0xdb, 0x3d, 0x4f, 0x97, 0xea, 0x37, 0x5e, 0x0d, 0xd7, 0x4c, + 0x9a, 0x7e, 0xc9, 0x0e, 0x69, 0x4d, 0x97, 0x15, 0x1e, 0x09, 0xbe, 0x7e, + 0xff, 0xe8, 0xf5, 0xab, 0xe9, 0xe7, 0xed, 0x4b, 0x41, 0xa5, 0xf2, 0x2a, + 0x24, 0x48, 0x8b, 0x72, 0x4b, 0x9d, 0xcf, 0x45, 0xdb, 0xc0, 0xaf, 0xa8, + 0x0f, 0x0f, 0x67, 0x37, 0xd3, 0x8b, 0xe1, 0x67, 0x90, 0xd8, 0x1c, 0x58, + 0x36, 0x46, 0x51, 0x52, 0xea, 0xb4, 0x75, 0xb1, 0xcd, 0xc5, 0x39, 0x16, + 0xe0, 0xec, 0x16, 0xf7, 0xf8, 0x0f, 0x5d, 0x13, 0x84, 0x62, 0x34, 0x86, + 0x42, 0x05, 0xa8, 0x08, 0x84, 0xa9, 0x77, 0x12, 0xc1, 0x56, 0xdd, 0x28, + 0xde, 0x39, 0x33, 0x21, 0x3d, 0xbd, 0x94, 0xce, 0xe4, 0xb3, 0x17, 0x9b, + 0x09, 0x20, 0xf0, 0x25, 0xce, 0x00, 0x34, 0x8e, 0x12, 0x94, 0x74, 0x0b, + 0x16, 0xa1, 0x60, 0x76, 0x24, 0xf0, 0xbf, 0xe3, 0x3a, 0x83, 0x8f, 0x40, + 0x47, 0x2e, 0x1c, 0xd5, 0x35, 0x25, 0x87, 0xb3, 0x11, 0xdc, 0x98, 0xb0, + 0xa6, 0x5f, 0x6a, 0x05, 0x1d, 0x06, 0x8d, 0xe8, 0xb0, 0x98, 0xf0, 0x43, + 0x29, 0x84, 0xe4, 0xef, 0x34, 0x67, 0x74, 0x64, 0xe8, 0xb8, 0xf0, 0xd4, + 0x9e, 0xc1, 0x3f, 0x5f, 0xeb, 0xe0, 0x9b, 0x37, 0xf8, 0x75, 0x46, 0x47, + 0xa5, 0x3e, 0x42, 0x20, 0x50, 0xc4, 0x5d, 0xf3, 0xdf, 0x4e, 0xf8, 0x0e, + 0x1e, 0x15, 0x10, 0x3e, 0xf1, 0x68, 0xad, 0x87, 0xad, 0xe5, 0x45, 0x5e, + 0x22, 0xba, 0x2e, 0x51, 0xa0, 0xbf, 0xdc, 0x87, 0xca, 0xe4, 0x1f, 0x2f, + 0x2c, 0xae, 0xa9, 0x14, 0xd7, 0xdd, 0x01, 0xa8, 0x4f, 0x43, 0xcb, 0x84, + 0x92, 0xbf, 0xf9, 0x3d, 0xf0, 0x6b, 0x19, 0x43, 0xb0, 0xdf, 0xff, 0x94, + 0x76, 0xe2, 0x84, 0xf9, 0x31, 0x88, 0x7e, 0xc6, 0x87, 0x58, 0xbe, 0x5d, + 0x8b, 0xf8, 0xb5, 0xdc, 0x95, 0x16, 0x5f, 0xa1, 0x2c, 0xe8, 0x53, 0x36, + 0x64, 0xf5, 0x5d, 0xa0, 0x74, 0x12, 0x78, 0x59, 0x73, 0x69, 0x5a, 0x2b, + 0x36, 0x4a, 0xff, 0x5b, 0xef, 0x49, 0x2c, 0xb2, 0x9e, 0x59, 0xf0, 0x39, + 0x56, 0xe1, 0xd0, 0x1a, 0x05, 0xb2, 0x7c, 0xd1, 0x40, 0x09, 0xdf, 0x00, + 0xc9, 0x15, 0x53, 0xa2, 0xda, 0x84, 0xb5, 0x85, 0x05, 0x76, 0xa6, 0x1b, + 0xcb, 0x06, 0xb2, 0xc8, 0xa0, 0xc5, 0x23, 0x8f, 0xb0, 0xe8, 0xf5, 0xd9, + 0xd0, 0x19, 0x29, 0xfe, 0x2d, 0x9a, 0x57, 0x76, 0x5f, 0xf2, 0xef, 0x71, + 0x16, 0xee, 0x28, 0x7b, 0xe4, 0x48, 0xeb, 0xda, 0xe0, 0xd5, 0xbc, 0x0e, + 0x46, 0x6b, 0x06, 0x5d, 0xe5, 0x91, 0x2d, 0xcb, 0xc4, 0x53, 0xa6, 0x16, + 0xd5, 0xe7, 0xd8, 0xf1, 0xdd, 0x4f, 0xbb, 0xcc, 0x55, 0x67, 0x19, 0x98, + 0x94, 0x95, 0x5e, 0xd6, 0xf5, 0xf7, 0xe8, 0x6a, 0xf7, 0x20, 0x86, 0x3a, + 0x43, 0xbf, 0xe9, 0xec, 0x6b, 0x33, 0x49, 0x19, 0x43, 0xfb, 0xeb, 0x3f, + 0xf4, 0x9d, 0x29, 0x66, 0xb9, 0x6e, 0xb5, 0x15, 0x4b, 0x8d, 0x3c, 0x3c, + 0xfa, 0xf2, 0x87, 0xba, 0x61, 0x11, 0x40, 0xe6, 0xb4, 0x6f, 0xf5, 0xe1, + 0x24, 0x32, 0x69, 0x3e, 0xff, 0xf7, 0xbc, 0xee, 0x82, 0xf2, 0x9e, 0x6d, + 0x3f, 0x6c, 0xcc, 0x0f, 0x4f, 0xc3, 0xf1, 0xdb, 0x1e, 0x81, 0xd7, 0x9b, + 0x22, 0xa8, 0xa7, 0x36, 0x6d, 0xa9, 0x6f, 0x46, 0x1a, 0xa7, 0xff, 0x00, + 0x4b, 0xd8, 0xab, 0xe7, 0x50, 0x3b, 0xe9, 0xc0, 0x57, 0xec, 0x8d, 0x0c, + 0xa0, 0xee, 0x8c, 0x2a, 0x74, 0xf2, 0x94, 0xf9, 0x0c, 0x20, 0x14, 0xd9, + 0xad, 0x0d, 0x4e, 0xac, 0x35, 0x44, 0x59, 0x28, 0x24, 0x31, 0x32, 0xaa, + 0x6d, 0xc2, 0x13, 0xb9, 0xee, 0x75, 0x0c, 0x5f, 0x39, 0xef, 0x31, 0xca, + 0x28, 0x48, 0x56, 0x59, 0xfb, 0xa8, 0xd8, 0x2b, 0x70, 0x61, 0x22, 0x43, + 0x43, 0xb9, 0x60, 0x44, 0xeb, 0xf8, 0x98, 0x87, 0x25, 0x84, 0xa2, 0xaa, + 0x37, 0xd4, 0xb8, 0xd6, 0x3d, 0xa3, 0xa1, 0x4a, 0x81, 0xc2, 0xa9, 0xea, + 0xa2, 0xd6, 0x63, 0x76, 0x50, 0xeb, 0xcd, 0x19, 0x40, 0xb1, 0x7c, 0xf6, + 0xc1, 0x44, 0x01, 0x25, 0xe0, 0xdd, 0xb8, 0x39, 0xef, 0x46, 0x3d, 0x50, + 0x33, 0xed, 0xb1, 0x63, 0x65, 0xd7, 0x50, 0xe7, 0x95, 0xba, 0xab, 0xa7, + 0x14, 0xe5, 0x60, 0xcb, 0x81, 0x6e, 0x88, 0x3c, 0x06, 0x6e, 0x7d, 0x8e, + 0xe7, 0xbb, 0xa5, 0xc2, 0xbd, 0xae, 0x46, 0x8f, 0x43, 0x04, 0x29, 0xe6, + 0x17, 0x38, 0x05, 0x2d, 0x97, 0x93, 0x5b, 0xf9, 0xef, 0x4d, 0x2e, 0x75, + 0x6c, 0x69, 0xba, 0x08, 0xf2, 0x21, 0x1e, 0x21, 0xe6, 0x8a, 0x5b, 0x8c, + 0xd4, 0x8e, 0xde, 0x64, 0x9b, 0x9d, 0x54, 0x58, 0x65, 0x3e, 0xdd, 0x8a, + 0x1e, 0x81, 0x4e, 0x45, 0xe8, 0xfb, 0x20, 0xc3, 0x3a, 0xf0, 0x50, 0x1e, + 0x8a, 0x18, 0xea, 0x2b, 0xf5, 0xe1, 0xa6, 0xb6, 0xc8, 0xa0, 0x02, 0x3d, + 0x6e, 0xfa, 0x0b, 0x51, 0x95, 0x4e, 0x4c, 0x11, 0xb0, 0xc4, 0x62, 0x58, + 0xa6, 0x9c, 0x13, 0x4e, 0xbe, 0xc9, 0x29, 0x93, 0x29, 0x15, 0x5f, 0xaf, + 0x0e, 0xc3, 0xb3, 0x26, 0x3f, 0xdc, 0x4c, 0x33, 0xb8, 0x4b, 0x11, 0xae, + 0x1f, 0xd7, 0x05, 0x39, 0xcf, 0xfe, 0xc3, 0x6d, 0xf0, 0xc0, 0x77, 0x02, + 0xb8, 0x9b, 0x3d, 0x1b, 0x3d, 0x72, 0xfe, 0x7e, 0x18, 0x60, 0x9b, 0xc4, + 0x8b, 0xac, 0x25, 0x6d, 0x3b, 0x80, 0x34, 0xbc, 0x51, 0xaf, 0xf6, 0xff, + 0x66, 0x98, 0x86, 0x6e, 0x9e, 0x9a, 0xfe, 0x6d, 0x21, 0x4d, 0xf1, 0x58, + 0x3e, 0x3e, 0x43, 0xe3, 0x7e, 0x40, 0xb0, 0xb3, 0xd8, 0x12, 0xa5, 0xce, + 0x09, 0x41, 0x8c, 0x1d, 0x73, 0xcd, 0xfc, 0x63, 0xed, 0xeb, 0x08, 0x1e, + 0x34, 0xfb, 0xed, 0x75, 0xb7, 0x86, 0x84, 0x7c, 0x80, 0xe9, 0xe4, 0xa3, + 0x1c, 0x4a, 0x0d, 0x11, 0x16, 0x24, 0xb2, 0xb1, 0x99, 0xe5, 0xe3, 0x2e, + 0x2f, 0x70, 0xcd, 0x1e, 0x35, 0x14, 0x79, 0xba, 0xa2, 0x51, 0x7a, 0x29, + 0x5c, 0x75, 0x8f, 0xdd, 0x22, 0xdf, 0xb2, 0x64, 0xd9, 0x95, 0x11, 0x33, + 0x97, 0xee, 0x69, 0x42, 0x01, 0x96, 0x98, 0x1b, 0x43, 0xc2, 0xec, 0xf9, + 0xb0, 0xdb, 0x69, 0x34, 0xab, 0x98, 0x1b, 0xb2, 0x04, 0x05, 0x14, 0x1d, + 0x25, 0x2f, 0x32, 0x41, 0x50, 0x51, 0x55, 0x62, 0x6d, 0x78, 0x7f, 0x8b, + 0xbb, 0xc2, 0xcd, 0xcf, 0xe4, 0xed, 0x04, 0x1f, 0x25, 0x30, 0x43, 0x64, + 0x69, 0x7c, 0x87, 0xa3, 0xa9, 0xb1, 0xc1, 0xd1, 0xdc, 0x01, 0x10, 0x1d, + 0x27, 0x3f, 0x5c, 0x5d, 0x75, 0x82, 0x9b, 0xaa, 0xb3, 0xe8, 0x0c, 0x11, + 0x1f, 0x24, 0x38, 0x41, 0x45, 0x54, 0x5f, 0x69, 0x85, 0x8d, 0x93, 0x9e, + 0xc5, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x25, 0x32, 0x42}; +#elif MLD_CONFIG_PARAMETER_SET == 65 +const uint8_t expected_signature[] = { + 0x8b, 0x6f, 0x79, 0x00, 0xcc, 0x79, 0x57, 0xee, 0x16, 0x86, 0x87, 0xd5, + 0xcf, 0xb6, 0x90, 0x2c, 0xc6, 0x30, 0xeb, 0x8d, 0x39, 0xae, 0x9b, 0xf1, + 0x66, 0xe0, 0xd6, 0x93, 0xa5, 0x4e, 0x26, 0x9b, 0x96, 0x8f, 0xd1, 0x46, + 0x97, 0xbe, 0x71, 0x1c, 0xf3, 0xa5, 0xe5, 0xae, 0x8d, 0x4b, 0xf2, 0xe6, + 0x48, 0x8f, 0xe9, 0x5e, 0x07, 0xef, 0xe4, 0xbb, 0x39, 0xc1, 0xc9, 0x3c, + 0xc3, 0x0b, 0xfb, 0x2a, 0x29, 0x06, 0xfe, 0x01, 0xcb, 0x63, 0x83, 0x10, + 0xa8, 0xc8, 0xa0, 0x29, 0xa5, 0x80, 0xeb, 0xbd, 0xa9, 0xd9, 0x0b, 0x61, + 0xbc, 0xce, 0x11, 0x55, 0x66, 0x12, 0xc7, 0x5b, 0xd2, 0x7a, 0x5a, 0xc8, + 0xab, 0xab, 0xbf, 0x3a, 0x1f, 0x96, 0x1a, 0x70, 0xcb, 0x41, 0x5f, 0xc8, + 0xb7, 0x09, 0x22, 0x98, 0x9b, 0xb8, 0xf7, 0x2d, 0x49, 0x65, 0x1d, 0x09, + 0x8b, 0x70, 0xb5, 0x42, 0xc9, 0x89, 0x5b, 0x74, 0xb4, 0x28, 0x82, 0x01, + 0x53, 0x12, 0x3e, 0x23, 0xf6, 0x54, 0xf8, 0x51, 0x12, 0x4b, 0x02, 0x3a, + 0x7e, 0xb6, 0x1f, 0xac, 0xa0, 0xe6, 0x6f, 0xf8, 0x61, 0x82, 0xe4, 0xfb, + 0x96, 0x2a, 0xd2, 0xaf, 0x3c, 0xea, 0x6e, 0xdc, 0x18, 0x8a, 0x5d, 0x90, + 0xda, 0xa2, 0x5d, 0xa7, 0x8f, 0x5b, 0x50, 0x46, 0xaf, 0x8c, 0x17, 0x6a, + 0x4c, 0x39, 0xfc, 0x31, 0x4c, 0x4b, 0xc2, 0x57, 0x66, 0x61, 0x98, 0xbf, + 0xe6, 0xfb, 0x54, 0x96, 0xd3, 0x70, 0xb8, 0xaf, 0xcd, 0x8b, 0xcc, 0x00, + 0x07, 0x92, 0x15, 0xc2, 0xbb, 0x48, 0xbb, 0xc6, 0xb7, 0xb5, 0x58, 0x8c, + 0xfc, 0xf0, 0xda, 0x6a, 0x0d, 0xf7, 0x1d, 0x7d, 0xc6, 0x27, 0x26, 0x1a, + 0x99, 0xc5, 0x2f, 0xf8, 0x97, 0x65, 0x43, 0x86, 0xd6, 0x25, 0x23, 0x2b, + 0x06, 0x8f, 0x12, 0xa1, 0xae, 0xbb, 0x58, 0x34, 0x25, 0xec, 0x5b, 0x68, + 0xa4, 0xe1, 0x03, 0xfc, 0x26, 0xa2, 0xd6, 0x2b, 0x61, 0x10, 0x47, 0xbd, + 0x16, 0xe5, 0xca, 0x4a, 0xce, 0xed, 0x89, 0x09, 0x1a, 0xed, 0x22, 0xc1, + 0xca, 0x44, 0xe3, 0xef, 0x72, 0x34, 0xab, 0xab, 0x61, 0x5c, 0x9f, 0x5f, + 0xb5, 0xf5, 0xe8, 0x2d, 0x89, 0xea, 0x4b, 0x40, 0x65, 0x57, 0x8b, 0xa2, + 0x95, 0x40, 0x9c, 0x72, 0xc0, 0x46, 0x69, 0x45, 0x06, 0xf6, 0x07, 0x5b, + 0x2d, 0xa5, 0x46, 0xca, 0x5d, 0xfb, 0x40, 0xb7, 0x48, 0x59, 0x5b, 0xe2, + 0x1b, 0x38, 0xb2, 0x15, 0x75, 0x66, 0x67, 0x58, 0x00, 0x3f, 0xde, 0x8a, + 0x63, 0x13, 0x34, 0x6a, 0x30, 0xca, 0xb4, 0xd5, 0x3e, 0xe0, 0x6d, 0x14, + 0xb8, 0x9a, 0x48, 0xef, 0xfd, 0xbd, 0x6d, 0x20, 0x11, 0x4d, 0x25, 0xe5, + 0xab, 0x15, 0x8d, 0xe5, 0x91, 0xbc, 0xc6, 0x69, 0x8a, 0xf8, 0xab, 0x3a, + 0x82, 0xae, 0xc5, 0x03, 0x2c, 0xcf, 0x54, 0xdc, 0xcd, 0xe8, 0x49, 0x53, + 0xb5, 0xd8, 0xc2, 0x24, 0xf8, 0x8c, 0x38, 0x8f, 0xe3, 0xfe, 0x3a, 0x18, + 0x15, 0xa8, 0xda, 0x77, 0xc8, 0x81, 0x72, 0xc6, 0xc1, 0x60, 0xa3, 0x73, + 0x65, 0x68, 0x5c, 0xf3, 0x1d, 0x8d, 0x61, 0x21, 0x65, 0xfb, 0x45, 0xc4, + 0x4c, 0x31, 0x88, 0x25, 0x0d, 0x52, 0x75, 0x3b, 0xec, 0x54, 0xe0, 0xb1, + 0x9c, 0x7c, 0xdf, 0xe3, 0x3b, 0x77, 0x31, 0x33, 0xd7, 0x25, 0x99, 0xff, + 0xc5, 0x40, 0x1e, 0x85, 0x09, 0xfd, 0x2d, 0x24, 0x4a, 0x92, 0xe7, 0x77, + 0x48, 0xa5, 0x46, 0xf4, 0x8e, 0xa3, 0x6b, 0x24, 0xe4, 0x6b, 0x31, 0xf6, + 0xe0, 0x16, 0x49, 0x9b, 0x9f, 0xa3, 0x1a, 0x5c, 0x05, 0x5e, 0x81, 0x62, + 0xc8, 0x14, 0x52, 0xb4, 0x21, 0xfd, 0x76, 0x6d, 0x88, 0xe9, 0x3b, 0x0b, + 0x75, 0x27, 0x92, 0x47, 0x5a, 0x58, 0x08, 0x26, 0xa7, 0xa2, 0x48, 0x1c, + 0x14, 0x3e, 0x5e, 0xdf, 0x81, 0x83, 0x83, 0x3e, 0xc6, 0x72, 0x27, 0xc4, + 0x6a, 0x46, 0x2b, 0xf2, 0x8d, 0x42, 0x11, 0xb9, 0x15, 0xd7, 0xf0, 0x20, + 0x29, 0x53, 0xba, 0xf0, 0x6e, 0x41, 0x3d, 0xee, 0x19, 0xf2, 0x43, 0xf3, + 0x6d, 0x00, 0xe2, 0x43, 0x77, 0xb9, 0xa9, 0x78, 0x34, 0x48, 0x3c, 0x1a, + 0x8b, 0xbd, 0xa1, 0xe5, 0x90, 0x59, 0x5b, 0xd6, 0x1e, 0x22, 0xdf, 0xb2, + 0xa7, 0x96, 0x7d, 0x55, 0x86, 0x66, 0x95, 0xb7, 0x06, 0xe7, 0x60, 0x2a, + 0x01, 0x48, 0x3f, 0xd4, 0xa7, 0xd4, 0xc2, 0x38, 0xa4, 0x10, 0x8e, 0x4f, + 0x97, 0xad, 0xa3, 0xb9, 0xe2, 0xaa, 0x13, 0xb1, 0x16, 0x89, 0x3d, 0x74, + 0x60, 0x94, 0x8c, 0xc3, 0xe6, 0x5f, 0xcf, 0xdc, 0x58, 0x17, 0x98, 0x27, + 0x86, 0xae, 0x2a, 0x0d, 0xe8, 0x33, 0x79, 0xc8, 0xc8, 0x5b, 0x59, 0xb0, + 0xba, 0xac, 0xd3, 0x6e, 0x2d, 0x7b, 0x0b, 0x9a, 0xb5, 0xfd, 0x58, 0x42, + 0xeb, 0x80, 0xf4, 0x6b, 0x9a, 0x2f, 0x19, 0x43, 0x75, 0xb4, 0xcb, 0xc9, + 0xd5, 0x28, 0xf5, 0xb9, 0x67, 0x82, 0xb4, 0xed, 0x8c, 0x3f, 0x3d, 0x6b, + 0x6d, 0x1b, 0x80, 0x13, 0x5c, 0x7b, 0x2e, 0xfa, 0xa0, 0x32, 0xba, 0xb5, + 0x46, 0xd6, 0xe7, 0x90, 0xe9, 0xd1, 0x91, 0xa0, 0xaa, 0x26, 0x35, 0xa2, + 0x0d, 0x98, 0x44, 0x11, 0xae, 0xf9, 0xc5, 0x12, 0x4d, 0x1a, 0x7c, 0x53, + 0xea, 0xf6, 0x05, 0x8d, 0x3a, 0x74, 0x92, 0xc9, 0x65, 0xeb, 0x6f, 0xb5, + 0xb4, 0xd2, 0xcd, 0x5c, 0xec, 0xaf, 0x95, 0xcb, 0xb4, 0x3c, 0x22, 0xca, + 0x1c, 0x06, 0x85, 0x16, 0x96, 0x24, 0x8c, 0x6c, 0x80, 0xf8, 0xb3, 0xa7, + 0x87, 0x77, 0xeb, 0x09, 0x71, 0xc8, 0x95, 0xfb, 0x5e, 0xe5, 0x6f, 0x78, + 0xf9, 0x60, 0xf9, 0x9e, 0x58, 0x7b, 0xbd, 0x47, 0xdd, 0x48, 0x2e, 0x56, + 0xcd, 0x63, 0x72, 0xc9, 0x4b, 0x65, 0x2d, 0x41, 0xe8, 0x81, 0x19, 0x33, + 0x4b, 0xf6, 0x02, 0xc6, 0xcb, 0x2e, 0xdf, 0x3d, 0xc8, 0xdd, 0x2f, 0x0f, + 0x09, 0x67, 0xf0, 0xaa, 0x3c, 0x51, 0xdc, 0x8d, 0xc6, 0xc3, 0xb2, 0x3b, + 0x15, 0x85, 0xcb, 0xeb, 0x62, 0xef, 0xa3, 0xf9, 0x94, 0xf4, 0x35, 0x9c, + 0x59, 0xcc, 0xc2, 0x68, 0xb4, 0xde, 0x02, 0x75, 0x8e, 0xf5, 0x33, 0xca, + 0xd5, 0xc5, 0x24, 0xae, 0xf6, 0xde, 0x2b, 0x01, 0xf4, 0x56, 0xb9, 0xa5, + 0xa7, 0xe0, 0x64, 0x2e, 0xba, 0x1d, 0x53, 0x54, 0x46, 0xcf, 0x64, 0x16, + 0x12, 0xe2, 0xa6, 0xcc, 0x18, 0xb4, 0x77, 0x8b, 0x19, 0x50, 0x43, 0x96, + 0xc8, 0x5d, 0xc3, 0x58, 0xf0, 0xfd, 0x5e, 0x13, 0xa9, 0x10, 0x67, 0xdf, + 0x25, 0xdb, 0xaf, 0x38, 0x5f, 0xbd, 0x35, 0xc1, 0x49, 0x44, 0xe8, 0x1f, + 0x12, 0xa4, 0x7c, 0x28, 0xa3, 0xd6, 0x0d, 0x6f, 0x44, 0xa9, 0x5f, 0xfc, + 0x9f, 0xfa, 0x11, 0x62, 0x87, 0x5b, 0x0e, 0x91, 0xd4, 0xb6, 0xd3, 0x71, + 0xc2, 0x77, 0x19, 0xf6, 0x7c, 0x11, 0x30, 0x5e, 0x5c, 0xd3, 0x1e, 0x90, + 0x05, 0x31, 0x63, 0xbb, 0xef, 0x85, 0xe0, 0x27, 0x94, 0x80, 0xcb, 0x33, + 0xbc, 0x5e, 0x45, 0x87, 0x62, 0xdf, 0xd4, 0x12, 0x2f, 0xf5, 0x41, 0x15, + 0x03, 0x0c, 0x80, 0xe8, 0xe2, 0x06, 0xde, 0x4b, 0x46, 0x70, 0x94, 0xd2, + 0x0d, 0x85, 0x72, 0x27, 0xe5, 0x6c, 0xeb, 0xd2, 0x78, 0x0b, 0x38, 0x40, + 0xe8, 0xdb, 0x47, 0x5c, 0xba, 0xd0, 0x21, 0x33, 0x8f, 0xb8, 0xc0, 0x66, + 0x1e, 0xd1, 0xb0, 0x94, 0xa3, 0x39, 0xc7, 0x87, 0xaf, 0x97, 0x98, 0xce, + 0x6d, 0x03, 0x1a, 0xdb, 0x52, 0x96, 0x0b, 0x9d, 0x5b, 0xf8, 0xa3, 0xf4, + 0x41, 0x95, 0x72, 0xad, 0x0e, 0x98, 0x61, 0x7f, 0xf3, 0x8f, 0x23, 0xeb, + 0xc0, 0xdf, 0xd7, 0x70, 0x26, 0x8c, 0xb3, 0xb3, 0xf0, 0xa2, 0x8a, 0x39, + 0xdd, 0x61, 0xb4, 0x53, 0xe0, 0x2a, 0x6f, 0x91, 0x34, 0x9c, 0x76, 0xf6, + 0x52, 0x93, 0xe6, 0x39, 0xb7, 0x54, 0x07, 0x46, 0x82, 0x2d, 0x05, 0x6d, + 0x9a, 0x00, 0x53, 0x65, 0x68, 0x93, 0x91, 0x00, 0xda, 0xe0, 0x93, 0x34, + 0x60, 0xb1, 0x93, 0x0b, 0x64, 0xa8, 0x12, 0xd2, 0x51, 0x3c, 0xdb, 0xb0, + 0x4c, 0x39, 0x4e, 0xce, 0xbd, 0xf0, 0x65, 0x12, 0x8a, 0xd4, 0x80, 0x7d, + 0x82, 0x85, 0xe4, 0x92, 0xc2, 0x77, 0x1e, 0xcf, 0xd9, 0xab, 0x0f, 0x9b, + 0x32, 0x2e, 0x3f, 0xe1, 0x0e, 0x87, 0x1c, 0x87, 0x34, 0xe7, 0x93, 0x16, + 0x95, 0x09, 0x7d, 0x24, 0xa8, 0xb5, 0xe0, 0x9f, 0x23, 0x87, 0x5c, 0x0b, + 0x31, 0x4a, 0x2f, 0xe2, 0x5c, 0x82, 0x49, 0x51, 0xe4, 0x93, 0xcb, 0x05, + 0x23, 0x4f, 0x8a, 0x83, 0x88, 0xfb, 0x89, 0xb0, 0x08, 0xd6, 0x64, 0xad, + 0x51, 0x84, 0x40, 0x29, 0xb1, 0xca, 0x74, 0x26, 0x29, 0x5a, 0x61, 0x01, + 0x2e, 0xa0, 0xeb, 0xeb, 0x02, 0xb5, 0xff, 0xd8, 0x20, 0x6a, 0x5e, 0x8d, + 0x17, 0x1e, 0xa3, 0xd7, 0x2f, 0x20, 0x0b, 0x93, 0x17, 0x24, 0xf7, 0x90, + 0x7b, 0xc6, 0xba, 0xd8, 0xf9, 0xe9, 0x0a, 0x2a, 0x7a, 0x81, 0x23, 0x81, + 0x03, 0x6f, 0x1e, 0x0d, 0x87, 0x83, 0xd1, 0xcf, 0x92, 0x2f, 0x19, 0x82, + 0x4e, 0x6c, 0x0a, 0x02, 0xb6, 0x70, 0xbc, 0xe1, 0x58, 0xe7, 0x16, 0xdb, + 0x2f, 0x74, 0x9f, 0xe1, 0xc2, 0x1e, 0x64, 0xc6, 0x48, 0x08, 0xee, 0xea, + 0x52, 0x9a, 0xce, 0x2c, 0xc5, 0x0c, 0x7a, 0x63, 0xf1, 0x6a, 0xbd, 0x2c, + 0x8b, 0xd5, 0x4a, 0xfa, 0x1e, 0xab, 0x9a, 0x5b, 0x25, 0xb8, 0xfa, 0x0a, + 0xe9, 0x68, 0x80, 0x6f, 0x80, 0x57, 0x10, 0x54, 0xb8, 0xa2, 0x16, 0xbd, + 0xfe, 0xf7, 0xea, 0x01, 0xc7, 0x94, 0x5a, 0x95, 0xe3, 0x61, 0xa5, 0x49, + 0x84, 0xf5, 0x79, 0x78, 0xb5, 0x0a, 0x96, 0xca, 0x01, 0x1b, 0xd0, 0x0b, + 0x51, 0x30, 0xd3, 0x48, 0xfc, 0x4d, 0x50, 0x71, 0x09, 0x73, 0xea, 0x37, + 0xcd, 0x9d, 0x3d, 0xde, 0x30, 0x56, 0x21, 0xf0, 0xef, 0x84, 0xad, 0x27, + 0xe1, 0x83, 0xdb, 0xfb, 0xcd, 0x11, 0xb2, 0xbd, 0x30, 0x67, 0x8a, 0x88, + 0x09, 0x0e, 0x9d, 0x96, 0x09, 0xba, 0xda, 0x9d, 0xf0, 0xe9, 0xb4, 0xa6, + 0x7a, 0x04, 0xf9, 0x4b, 0xb8, 0x51, 0xa9, 0x99, 0xf3, 0xbb, 0x77, 0x95, + 0x0a, 0xa1, 0xa6, 0xa1, 0x24, 0xfc, 0xcc, 0x45, 0xe8, 0x83, 0xc8, 0x6f, + 0x48, 0xad, 0x9a, 0x73, 0xd0, 0xe0, 0x57, 0x7d, 0xe4, 0x78, 0x65, 0xef, + 0xae, 0xc2, 0xfe, 0x7a, 0x56, 0xaf, 0x03, 0x71, 0x2b, 0xe6, 0xa1, 0x7e, + 0xe5, 0x12, 0xf8, 0xc3, 0x75, 0xc7, 0x22, 0x5f, 0x1b, 0x52, 0x90, 0xe5, + 0xdf, 0xba, 0x9d, 0xe2, 0x68, 0xe0, 0xb3, 0x7a, 0x9e, 0x14, 0xff, 0xb5, + 0x0a, 0x80, 0x20, 0x49, 0x88, 0xe9, 0x9c, 0xe4, 0xb5, 0xaf, 0x7e, 0x51, + 0xec, 0xe7, 0xfc, 0x64, 0x65, 0x21, 0x10, 0xc6, 0x1f, 0x7f, 0x93, 0x7d, + 0xd8, 0xf5, 0xd0, 0x98, 0x94, 0x44, 0xf8, 0x49, 0x6a, 0x51, 0x0a, 0x54, + 0xf4, 0x9f, 0xee, 0x3c, 0x56, 0xbf, 0x4c, 0xe4, 0xde, 0x1c, 0x9b, 0x11, + 0x7e, 0x9a, 0x71, 0x11, 0x80, 0x33, 0xd5, 0xb0, 0x9b, 0xef, 0x67, 0x29, + 0xa4, 0x7d, 0x70, 0x31, 0x3f, 0x8b, 0x2e, 0x4a, 0x0f, 0x2c, 0x91, 0x3d, + 0x3e, 0x3d, 0x8c, 0x0a, 0x2b, 0xf1, 0xdd, 0xbf, 0x61, 0xe6, 0xa3, 0xef, + 0x6d, 0x82, 0xc8, 0xb7, 0x5e, 0x2b, 0x83, 0xc9, 0x4e, 0xa0, 0x85, 0x7f, + 0x01, 0x5a, 0xca, 0x6e, 0x90, 0xfa, 0x7e, 0x82, 0x4d, 0x35, 0x7e, 0xe0, + 0x26, 0x40, 0xf4, 0xa6, 0xae, 0xc3, 0x89, 0xf3, 0xca, 0x55, 0x2c, 0xb5, + 0x29, 0x05, 0x94, 0x45, 0xa7, 0x45, 0xf3, 0x3d, 0xbb, 0x53, 0x5e, 0xca, + 0x7c, 0x84, 0x8f, 0x72, 0x98, 0x93, 0x90, 0x1f, 0x56, 0x72, 0xdb, 0xbd, + 0xa9, 0xeb, 0xf9, 0xe9, 0xce, 0xb1, 0x41, 0xc3, 0xaa, 0xa0, 0xc4, 0x74, + 0x23, 0xc1, 0xeb, 0x7d, 0x41, 0xcd, 0xa4, 0x62, 0xec, 0xfc, 0x9a, 0xa4, + 0x16, 0xec, 0x67, 0x41, 0x89, 0xf0, 0x0e, 0xf3, 0xd1, 0xa2, 0x2f, 0xba, + 0x5d, 0x93, 0x36, 0x46, 0xf5, 0x52, 0x64, 0x91, 0xe7, 0x40, 0x91, 0x20, + 0xa1, 0xc9, 0xaa, 0x4c, 0x79, 0xc4, 0xbb, 0x67, 0x79, 0xad, 0x43, 0xab, + 0xba, 0xde, 0xfc, 0xf1, 0x74, 0x81, 0x33, 0xc0, 0x3f, 0x39, 0xd1, 0xd1, + 0xdf, 0xc0, 0x53, 0x33, 0xb2, 0x92, 0x37, 0xe6, 0x86, 0x2a, 0xe4, 0xe1, + 0x7c, 0x98, 0xf7, 0xdb, 0x5c, 0xa9, 0xff, 0x8d, 0x9c, 0xab, 0xe2, 0xf2, + 0xd5, 0xb1, 0x42, 0xa9, 0xf4, 0x97, 0x80, 0xcd, 0xde, 0x25, 0x2e, 0x87, + 0x92, 0xdd, 0xcf, 0xed, 0x67, 0x93, 0x8c, 0x5a, 0x1d, 0xee, 0xcf, 0x9d, + 0x50, 0x8f, 0xa7, 0xe3, 0x5c, 0xa3, 0x68, 0x78, 0x24, 0xeb, 0x60, 0xa3, + 0x8b, 0x36, 0xbb, 0xcb, 0x46, 0xee, 0x77, 0xfb, 0xf8, 0x69, 0x24, 0xd1, + 0xfa, 0xad, 0x76, 0x76, 0x5e, 0x54, 0xe5, 0xb6, 0x36, 0xc6, 0xdd, 0xa9, + 0x6c, 0x44, 0x15, 0xf7, 0x0a, 0xf8, 0xbb, 0xba, 0xec, 0x35, 0xff, 0xc9, + 0xd6, 0x5d, 0xf5, 0x73, 0x4a, 0x15, 0x8f, 0x7b, 0x6e, 0xf4, 0xa0, 0x6d, + 0x10, 0xbb, 0x67, 0x0c, 0xb4, 0x69, 0xad, 0xb6, 0x40, 0xf7, 0x5f, 0x37, + 0x28, 0xc4, 0x08, 0x49, 0xd0, 0x16, 0x70, 0x80, 0xea, 0x55, 0x66, 0x07, + 0xc8, 0x03, 0x1b, 0xf6, 0xd3, 0x03, 0x04, 0x74, 0xe0, 0x50, 0x3f, 0xd2, + 0x53, 0x92, 0xa0, 0x9d, 0x59, 0xc9, 0x74, 0xf2, 0x7e, 0x3b, 0x33, 0x02, + 0x10, 0x0b, 0x39, 0xf7, 0x4f, 0x6b, 0x58, 0xb2, 0x1a, 0xda, 0x65, 0x44, + 0xd1, 0x7c, 0x3f, 0xd7, 0xe3, 0xac, 0xe2, 0x1f, 0x38, 0xc1, 0x6a, 0xb0, + 0xdc, 0xc3, 0x9c, 0x7b, 0x11, 0x3c, 0x05, 0x21, 0x96, 0x76, 0x98, 0x76, + 0x82, 0xc1, 0x54, 0xdf, 0xdc, 0x8f, 0x4c, 0xd2, 0x63, 0x04, 0x06, 0x77, + 0x36, 0xe6, 0x2e, 0xd1, 0x00, 0x28, 0x42, 0x7c, 0x4a, 0x27, 0x90, 0x46, + 0xc9, 0xce, 0x33, 0x1c, 0xae, 0xda, 0x79, 0x64, 0x7f, 0x52, 0x3f, 0x58, + 0x11, 0x76, 0x4a, 0xb6, 0x72, 0xd8, 0x76, 0xae, 0xfd, 0x5c, 0x57, 0x69, + 0x76, 0x91, 0x84, 0x21, 0xc4, 0x9b, 0xd8, 0xa2, 0xff, 0x93, 0x02, 0x77, + 0x61, 0x57, 0x96, 0x7b, 0x8e, 0xfc, 0xf2, 0x6c, 0x11, 0x2b, 0x5e, 0x88, + 0x5c, 0x17, 0x1d, 0x12, 0x79, 0x3a, 0x78, 0xb6, 0x9d, 0x70, 0xfa, 0xd4, + 0xc1, 0x5c, 0x90, 0x0e, 0x0a, 0xd1, 0x3c, 0x7d, 0xcf, 0xee, 0x8a, 0xb2, + 0xb2, 0x4d, 0xce, 0x89, 0x32, 0xa9, 0x6c, 0x56, 0x57, 0x85, 0xb1, 0xbf, + 0x18, 0x1d, 0xc6, 0xe1, 0x17, 0xc5, 0x92, 0x42, 0x99, 0xf9, 0x9f, 0x04, + 0xec, 0x38, 0xf8, 0xa0, 0xd2, 0xab, 0xe6, 0x13, 0x4d, 0x9c, 0x18, 0x86, + 0x3e, 0x18, 0x73, 0x2c, 0xac, 0xe0, 0xb9, 0xf9, 0x87, 0x74, 0xb8, 0xd7, + 0x47, 0x6e, 0x42, 0xfc, 0x29, 0xa0, 0x1f, 0x56, 0x68, 0xb6, 0x23, 0x96, + 0xa2, 0x8d, 0x54, 0x81, 0x0f, 0x60, 0xb9, 0xde, 0x93, 0xfc, 0xfd, 0xde, + 0xbe, 0xb3, 0xb5, 0x87, 0xec, 0x9f, 0x17, 0xc2, 0x77, 0x6e, 0xa0, 0x62, + 0xdb, 0x66, 0xba, 0xc5, 0x05, 0x12, 0x46, 0x5d, 0x3c, 0x23, 0x29, 0x68, + 0xe5, 0x31, 0xe3, 0x15, 0xec, 0xac, 0x15, 0x9a, 0xbf, 0x42, 0x65, 0x80, + 0x45, 0x9c, 0x1d, 0xc2, 0x0e, 0x18, 0x47, 0x40, 0x44, 0xc1, 0x55, 0x24, + 0x5a, 0x35, 0xad, 0x59, 0xd2, 0xc6, 0xc3, 0x68, 0x58, 0xbd, 0x6f, 0xcf, + 0x5d, 0xb1, 0x9b, 0x0c, 0x92, 0x39, 0x22, 0x49, 0x66, 0x2e, 0x03, 0x7b, + 0x75, 0x5c, 0x6c, 0xde, 0x37, 0x54, 0xa9, 0x07, 0x2f, 0x7e, 0xc1, 0x3e, + 0x3b, 0xab, 0xd2, 0xa9, 0xfa, 0xc7, 0x6b, 0xd5, 0x14, 0x08, 0x35, 0x89, + 0x0b, 0x31, 0x18, 0x54, 0x7d, 0x6b, 0x53, 0x80, 0x6e, 0x32, 0x9b, 0xff, + 0x61, 0x7f, 0x36, 0xe5, 0x28, 0x40, 0xbc, 0xc7, 0x19, 0xb3, 0xae, 0xfa, + 0x95, 0xa8, 0xae, 0xd2, 0x97, 0x72, 0xc6, 0x91, 0x36, 0x3a, 0xa6, 0xec, + 0x4a, 0x41, 0x63, 0x6b, 0x28, 0xef, 0x5a, 0xa1, 0xdb, 0xf2, 0xd9, 0xfd, + 0x61, 0x72, 0xa4, 0xd2, 0x9e, 0xf7, 0x47, 0xf4, 0x4e, 0xea, 0x2a, 0xa5, + 0x35, 0xe1, 0x77, 0x3a, 0x53, 0x28, 0xa6, 0x55, 0x48, 0x0c, 0x1e, 0x44, + 0xfc, 0xc1, 0x31, 0x5a, 0x00, 0xcd, 0x29, 0xc1, 0x5c, 0xca, 0x2a, 0x07, + 0x01, 0x63, 0xac, 0xb3, 0xfb, 0xf6, 0x0b, 0xac, 0xfd, 0xe8, 0x7b, 0xed, + 0xf9, 0x3d, 0x9a, 0xbc, 0x67, 0x28, 0x1c, 0xd9, 0x3f, 0x97, 0x28, 0x4a, + 0xe7, 0xd0, 0x08, 0xe9, 0x3e, 0xa0, 0xcb, 0x0f, 0xe0, 0x3f, 0x1b, 0x80, + 0x43, 0x74, 0xd9, 0x9d, 0x0b, 0x22, 0x81, 0xf7, 0xec, 0x71, 0x2a, 0x29, + 0x9e, 0x5d, 0x1e, 0x8d, 0xf4, 0x22, 0x95, 0x78, 0x86, 0xcb, 0xf0, 0x9d, + 0xe7, 0x6a, 0x66, 0x7e, 0x28, 0xb5, 0x47, 0xb6, 0xdc, 0x0d, 0x03, 0x3c, + 0x09, 0x58, 0x76, 0x93, 0x39, 0xb2, 0xd3, 0x75, 0xb4, 0x51, 0x55, 0x84, + 0x30, 0x24, 0x0a, 0x76, 0xf4, 0x97, 0xe7, 0x0f, 0x5a, 0x67, 0xee, 0xf4, + 0xc7, 0x69, 0x8d, 0xf2, 0x32, 0x29, 0x5c, 0x33, 0x82, 0x5f, 0x6c, 0x47, + 0xd0, 0xe2, 0xbd, 0x62, 0xd6, 0x4c, 0x6d, 0x0d, 0xba, 0x87, 0xd3, 0x43, + 0x7e, 0x2d, 0xa6, 0x14, 0x09, 0x4f, 0x3b, 0xc3, 0x04, 0x14, 0xe5, 0x65, + 0xe9, 0x3b, 0x6a, 0xca, 0xb5, 0x96, 0x84, 0x3f, 0x53, 0x49, 0x22, 0x45, + 0x91, 0xff, 0xf9, 0x26, 0x75, 0x0d, 0x9c, 0xa7, 0x00, 0xf4, 0x65, 0xc4, + 0x60, 0x72, 0xab, 0xeb, 0xf8, 0xa8, 0x72, 0xfe, 0xd8, 0xde, 0x93, 0x67, + 0xcb, 0x09, 0xcc, 0xa0, 0xce, 0x9f, 0x67, 0x63, 0x26, 0xfa, 0x7f, 0x89, + 0xaa, 0x3e, 0x6d, 0xb2, 0x90, 0xd7, 0xef, 0x3e, 0x2a, 0x66, 0x26, 0x33, + 0xe6, 0x26, 0xc1, 0x58, 0xf8, 0x91, 0xea, 0x2f, 0xd0, 0x84, 0x21, 0x41, + 0x93, 0xa6, 0x36, 0x40, 0xb5, 0x4c, 0xac, 0x21, 0x88, 0x37, 0x47, 0x8a, + 0xb8, 0xf3, 0x33, 0x73, 0x12, 0xd7, 0x5a, 0x55, 0xf9, 0xd1, 0x1e, 0x75, + 0xa4, 0x66, 0x68, 0x3f, 0xf7, 0xb2, 0xc4, 0x5d, 0x1b, 0xb1, 0x61, 0x0f, + 0xaf, 0x4b, 0x9b, 0x20, 0x2b, 0x05, 0x68, 0x1c, 0x6c, 0x97, 0x8d, 0xb8, + 0x7b, 0x96, 0xda, 0xe0, 0x67, 0x15, 0x4c, 0x51, 0x71, 0x0d, 0xd3, 0x7b, + 0xde, 0xaa, 0xd3, 0x58, 0xf5, 0xc9, 0x62, 0x0a, 0xc2, 0x33, 0x1f, 0xf3, + 0xc3, 0x30, 0xb5, 0x64, 0xd1, 0x59, 0x41, 0x0e, 0xae, 0xaa, 0x0d, 0xdf, + 0x9f, 0x5d, 0x3f, 0x15, 0x0d, 0x46, 0x7a, 0x6d, 0x2e, 0x29, 0x1b, 0xc0, + 0xd3, 0x11, 0x10, 0x5d, 0xdc, 0x6a, 0x35, 0x8c, 0x43, 0xc8, 0x9f, 0x05, + 0x80, 0xdc, 0x25, 0x24, 0x37, 0x70, 0x7e, 0x1c, 0xe9, 0x85, 0x5a, 0xef, + 0x83, 0x3a, 0x55, 0x68, 0x83, 0x17, 0xf4, 0xc7, 0xae, 0xe4, 0x84, 0xc9, + 0x64, 0x5d, 0x2f, 0xb6, 0xca, 0x10, 0x95, 0xb8, 0xd6, 0x80, 0xfd, 0x05, + 0xa5, 0x06, 0x32, 0x34, 0x91, 0x01, 0xd2, 0x02, 0x90, 0xe1, 0xf7, 0x89, + 0x8a, 0xee, 0x18, 0x04, 0x93, 0xd9, 0xb4, 0x63, 0x4b, 0xf7, 0x7a, 0x9c, + 0x1b, 0x4b, 0xf9, 0x31, 0x32, 0xd9, 0xf2, 0x55, 0x4e, 0xc1, 0x02, 0xce, + 0x77, 0x38, 0x36, 0x29, 0xb8, 0x54, 0x8c, 0xc2, 0x27, 0x5f, 0xd9, 0xae, + 0x3e, 0x1e, 0xcd, 0xe9, 0x07, 0x90, 0x4c, 0xe0, 0xda, 0x16, 0x6e, 0xdf, + 0xde, 0x3a, 0x61, 0x89, 0x9f, 0x79, 0xd0, 0xd4, 0x66, 0x95, 0xad, 0xe4, + 0x11, 0x7d, 0xa1, 0xae, 0xec, 0x3e, 0x6e, 0x20, 0x5a, 0xd0, 0x28, 0x0e, + 0x55, 0xec, 0xcf, 0x34, 0xec, 0xb7, 0xfc, 0xa4, 0xb3, 0x8f, 0x56, 0x13, + 0x50, 0xcc, 0x15, 0x10, 0x74, 0x40, 0x72, 0x42, 0x20, 0x22, 0xb3, 0xaf, + 0xf3, 0x68, 0xba, 0x95, 0x45, 0xcb, 0xef, 0x92, 0xd5, 0x14, 0x4c, 0x1f, + 0xe3, 0xc1, 0xa6, 0x03, 0x4e, 0x05, 0xd2, 0x1a, 0xee, 0xd2, 0x48, 0x44, + 0x2e, 0x50, 0x3b, 0x86, 0xc8, 0x6a, 0xc8, 0x4c, 0xca, 0x2a, 0xb6, 0xf7, + 0x3c, 0xaf, 0xdc, 0x62, 0xb1, 0x49, 0x13, 0xfe, 0xe7, 0x32, 0xea, 0x78, + 0xfa, 0xba, 0xcf, 0x15, 0x47, 0x58, 0xdc, 0x19, 0x73, 0x1d, 0xff, 0xbd, + 0xcc, 0x27, 0xf6, 0xfc, 0x66, 0x68, 0xa7, 0x29, 0xaf, 0x2b, 0x25, 0x0c, + 0x15, 0x47, 0xff, 0xc1, 0x00, 0x9d, 0xfa, 0x58, 0x9c, 0xaa, 0xf9, 0xcc, + 0x4c, 0x51, 0x1d, 0xda, 0xf3, 0x3c, 0x10, 0xd0, 0x3b, 0x59, 0x30, 0x02, + 0x68, 0x29, 0x1c, 0xa7, 0x22, 0xea, 0x81, 0xd3, 0x29, 0x71, 0x39, 0xe8, + 0x72, 0x7f, 0x7d, 0x94, 0x0a, 0x64, 0x2c, 0xe6, 0x55, 0xfb, 0x90, 0x78, + 0x7e, 0x6c, 0x3e, 0xfe, 0x57, 0x14, 0x61, 0xef, 0xe2, 0x63, 0x57, 0x6c, + 0x13, 0x97, 0x27, 0x2b, 0x38, 0x44, 0xab, 0x74, 0x76, 0x11, 0xa6, 0x60, + 0xad, 0x8e, 0xad, 0xe5, 0xa5, 0xa1, 0x66, 0xc5, 0xe1, 0x4d, 0x27, 0xa0, + 0x79, 0x7a, 0x09, 0xe6, 0xf0, 0x28, 0x3f, 0xcb, 0xc6, 0xf8, 0x94, 0xc0, + 0xf1, 0x13, 0xbe, 0x62, 0x6a, 0x52, 0x75, 0x52, 0xd3, 0x82, 0x31, 0xbd, + 0x15, 0xf2, 0xe8, 0x2e, 0xb1, 0x62, 0x03, 0x1e, 0xe2, 0xb3, 0xec, 0xbc, + 0x3c, 0x12, 0xca, 0x62, 0x4e, 0xc2, 0x3a, 0x51, 0x1c, 0xdf, 0xa2, 0x84, + 0x88, 0xe5, 0x7e, 0xd7, 0x5d, 0xd7, 0xbf, 0xf2, 0x7d, 0xbd, 0x9a, 0x90, + 0x63, 0xfd, 0x8a, 0x84, 0x2b, 0x9d, 0x89, 0x27, 0x63, 0x4c, 0x0a, 0xe3, + 0x70, 0x94, 0x7b, 0xe6, 0xb3, 0xd7, 0xcb, 0xcb, 0x8a, 0xeb, 0x6b, 0x53, + 0x34, 0x2f, 0x62, 0x44, 0x2d, 0x73, 0x63, 0x8a, 0xf4, 0xa2, 0x01, 0xd7, + 0x12, 0xb6, 0x8d, 0x8c, 0x4b, 0x73, 0x2b, 0x44, 0x50, 0x49, 0x6f, 0x01, + 0xac, 0xc5, 0x15, 0x37, 0x6c, 0xde, 0xd4, 0x02, 0xb1, 0x12, 0x80, 0x73, + 0xb2, 0x52, 0x0e, 0xe0, 0xb5, 0x75, 0xc9, 0x48, 0xcf, 0x18, 0x5c, 0xcc, + 0xaf, 0x58, 0xa2, 0x3e, 0x28, 0xe4, 0xab, 0xde, 0xea, 0x2a, 0xcf, 0x58, + 0x22, 0xc4, 0x68, 0xea, 0x9b, 0x7b, 0x90, 0xc5, 0xdc, 0x1c, 0x37, 0xd1, + 0x8a, 0x4f, 0xe7, 0x24, 0x23, 0x39, 0xb9, 0x62, 0xb8, 0x41, 0x13, 0x7b, + 0xe2, 0x1e, 0x0d, 0x4e, 0x38, 0x11, 0xa3, 0xb9, 0x10, 0xbb, 0x10, 0x6f, + 0x40, 0x9f, 0x50, 0x05, 0xc7, 0x0e, 0xb9, 0x9e, 0xab, 0x7c, 0x3c, 0x78, + 0xce, 0x54, 0xbf, 0xbf, 0x40, 0x36, 0x76, 0xbc, 0x4b, 0x64, 0x32, 0xca, + 0x0e, 0x2d, 0x91, 0x87, 0xd5, 0x00, 0x19, 0xbf, 0x12, 0xd0, 0x35, 0x7c, + 0xa1, 0xe5, 0xcf, 0x7a, 0x2d, 0x08, 0x62, 0xed, 0x34, 0x61, 0xe3, 0xda, + 0x2c, 0xcc, 0x1b, 0xf8, 0x12, 0xfe, 0xfd, 0x19, 0xa2, 0xc3, 0x70, 0xfd, + 0x4f, 0x5b, 0x5d, 0x20, 0xd2, 0xe1, 0xc5, 0xac, 0xe7, 0xa1, 0x84, 0x00, + 0xbd, 0x46, 0x81, 0xfd, 0x54, 0x69, 0xed, 0x1a, 0x7a, 0x32, 0xbb, 0x75, + 0x22, 0x76, 0x6d, 0x34, 0x24, 0xcc, 0xe6, 0xbe, 0x78, 0x5a, 0x75, 0x6c, + 0xbc, 0x62, 0xb8, 0x14, 0xf7, 0x13, 0x73, 0xc2, 0xdc, 0xb6, 0xfa, 0xfb, + 0x97, 0xfe, 0x27, 0x7b, 0x33, 0xb8, 0xeb, 0x20, 0xd2, 0x0f, 0x4f, 0xed, + 0xd1, 0xd0, 0x63, 0xf7, 0xc5, 0x8e, 0xec, 0xcc, 0xd2, 0x31, 0x38, 0x35, + 0x65, 0x33, 0x5c, 0x63, 0x85, 0xf7, 0x3d, 0xc3, 0x62, 0x26, 0x52, 0x0a, + 0x67, 0xda, 0x87, 0x1f, 0x9e, 0x47, 0xec, 0x6b, 0xf5, 0x74, 0x1a, 0xc5, + 0xa7, 0xa0, 0x0f, 0xdd, 0xc5, 0x42, 0xf4, 0xda, 0x41, 0x1a, 0x48, 0xa9, + 0xbe, 0x4f, 0xb6, 0x28, 0x17, 0xe9, 0xf5, 0xd7, 0x00, 0xb3, 0xfe, 0x05, + 0x4e, 0xa7, 0xdf, 0x65, 0x7a, 0xb8, 0x4f, 0xe0, 0xfe, 0x58, 0x9e, 0xba, + 0x45, 0x11, 0xba, 0xc2, 0xdb, 0x97, 0x97, 0xa4, 0xbc, 0x18, 0x21, 0x1b, + 0xad, 0x82, 0xef, 0xb1, 0x5f, 0x2f, 0x25, 0x9d, 0xca, 0x52, 0xa5, 0x6d, + 0x8c, 0xab, 0x07, 0x2b, 0x7b, 0x6a, 0x77, 0x9d, 0xdf, 0xfb, 0xae, 0x6e, + 0x49, 0x18, 0x25, 0x4a, 0xf2, 0x7d, 0xa0, 0x32, 0xc8, 0x53, 0x10, 0xc3, + 0xf2, 0xef, 0xf3, 0xe7, 0x79, 0xd7, 0x6a, 0x0e, 0x61, 0xff, 0x89, 0xc9, + 0x42, 0xe8, 0x6e, 0x4f, 0x78, 0xe1, 0x5f, 0xcd, 0x7a, 0xf6, 0x27, 0x72, + 0x67, 0xea, 0x0b, 0xa6, 0xcc, 0x34, 0xb7, 0x8f, 0x92, 0x3c, 0x95, 0xb9, + 0x0a, 0x5d, 0x49, 0x2e, 0xb7, 0x7d, 0x31, 0x9c, 0x79, 0x61, 0x95, 0x9c, + 0x60, 0x56, 0x8d, 0x35, 0x00, 0xc5, 0x8b, 0xe6, 0x02, 0x0f, 0x26, 0x39, + 0x7b, 0x93, 0x94, 0xb1, 0xcd, 0xde, 0xed, 0xfa, 0x2a, 0x4b, 0x63, 0xa8, + 0x1b, 0x31, 0x43, 0x5e, 0x69, 0x7c, 0xd6, 0x15, 0x35, 0x9c, 0xa2, 0xd7, + 0xdf, 0x0e, 0x1a, 0x20, 0x50, 0xf5, 0x02, 0x21, 0x30, 0x35, 0x3c, 0x60, + 0x71, 0xad, 0xd0, 0xe3, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x10, 0x17, 0x1d, 0x22, 0x2d}; +#elif MLD_CONFIG_PARAMETER_SET == 87 +const uint8_t expected_signature[] = { + 0xdf, 0xe6, 0xe1, 0xa5, 0x20, 0xc1, 0xac, 0x98, 0x55, 0x2c, 0xf2, 0x13, + 0x65, 0x42, 0xe2, 0xb0, 0x77, 0x5f, 0x15, 0x00, 0x8f, 0x14, 0x48, 0xa1, + 0xe3, 0xee, 0x81, 0x35, 0x15, 0x34, 0xad, 0x6e, 0x60, 0x85, 0x00, 0xf8, + 0x18, 0x53, 0x0d, 0xa0, 0xc5, 0x41, 0xc4, 0x48, 0x09, 0x1b, 0x34, 0x0c, + 0x0e, 0xcf, 0xc6, 0x3d, 0x38, 0x78, 0x8b, 0x69, 0xe5, 0x6f, 0x4d, 0x43, + 0xfa, 0xa6, 0x75, 0x26, 0x8a, 0x75, 0x97, 0x10, 0x6a, 0x1f, 0x3c, 0xa6, + 0x94, 0xa9, 0x93, 0x8f, 0xe5, 0x62, 0xbf, 0x94, 0xe4, 0xd0, 0x0d, 0x11, + 0x4d, 0x03, 0xe2, 0xd8, 0xdf, 0x68, 0xb7, 0x87, 0x62, 0xc9, 0xdc, 0xc9, + 0x36, 0x4f, 0xcc, 0xd1, 0xa4, 0xae, 0x7e, 0xa4, 0xb9, 0xaf, 0xaf, 0xf0, + 0x8a, 0xe6, 0xff, 0x83, 0xe7, 0x54, 0x22, 0x6e, 0x3f, 0x2e, 0xa0, 0x4f, + 0xa8, 0x31, 0x53, 0xf3, 0x62, 0xeb, 0x04, 0xfa, 0xd1, 0x57, 0x39, 0x43, + 0xf9, 0xe0, 0x31, 0x12, 0x45, 0x09, 0x8b, 0x9e, 0x1e, 0x7a, 0x2b, 0x85, + 0xee, 0xdd, 0xe8, 0x1e, 0xd7, 0xc0, 0x17, 0xb4, 0xd2, 0xdc, 0x36, 0xa9, + 0xe4, 0x49, 0x88, 0xbf, 0x71, 0x43, 0x9d, 0x3e, 0xd2, 0x10, 0xe7, 0x82, + 0xb5, 0xfe, 0xdd, 0x42, 0xc8, 0x1b, 0x11, 0xf6, 0x52, 0x23, 0x98, 0x83, + 0x48, 0xec, 0xec, 0x70, 0x8b, 0xe7, 0x49, 0x9a, 0xd7, 0xd9, 0x7b, 0x47, + 0x4e, 0xe2, 0x5e, 0x17, 0x1a, 0xa0, 0x0e, 0x60, 0x85, 0x3a, 0x30, 0x8c, + 0x1c, 0x26, 0xb4, 0xe1, 0xb5, 0x2b, 0x48, 0xf4, 0xb8, 0x93, 0x2f, 0x79, + 0x3a, 0x1e, 0xb6, 0x3b, 0x07, 0x3b, 0x1e, 0x15, 0xd7, 0x85, 0x5e, 0xd4, + 0x06, 0x0e, 0xcd, 0x6a, 0x93, 0x3a, 0x93, 0x29, 0x6a, 0xbe, 0x68, 0x8a, + 0xb6, 0xb8, 0xfa, 0xc5, 0x63, 0x48, 0x98, 0x10, 0x6d, 0xd9, 0xd3, 0x5b, + 0x29, 0x5f, 0x93, 0x90, 0x08, 0x1c, 0x1a, 0x15, 0x7b, 0x0a, 0x59, 0x9d, + 0x64, 0x24, 0x45, 0xb6, 0xd3, 0x7b, 0xc1, 0x5d, 0x74, 0x1f, 0x0b, 0x8e, + 0x18, 0xf2, 0x92, 0x8e, 0xd4, 0x7f, 0x72, 0x5c, 0x98, 0x1f, 0x8b, 0xa5, + 0xb8, 0xf4, 0x7e, 0x12, 0x6a, 0x93, 0xb9, 0xb5, 0xf1, 0xda, 0x97, 0x75, + 0x4f, 0x56, 0x80, 0x88, 0x64, 0x2b, 0xe0, 0x59, 0xcd, 0x5e, 0x91, 0x64, + 0x9c, 0x0c, 0xa8, 0xdd, 0xac, 0xcb, 0xf3, 0x48, 0x3b, 0x5c, 0xc4, 0xc5, + 0xb9, 0x9a, 0x0b, 0x8e, 0x5d, 0x9a, 0xd5, 0xb7, 0xf0, 0xd4, 0x07, 0x48, + 0xb9, 0x63, 0x02, 0x87, 0x8d, 0xae, 0x7e, 0x03, 0x33, 0x4f, 0x86, 0x15, + 0x1b, 0x3b, 0xdf, 0xda, 0xce, 0xd3, 0x1e, 0xc0, 0x76, 0xb5, 0x1c, 0xdd, + 0xb8, 0x32, 0x87, 0x7d, 0x59, 0x18, 0x72, 0x0c, 0xde, 0x8f, 0x63, 0x2d, + 0x38, 0xf2, 0xe9, 0xc2, 0x81, 0xed, 0xfa, 0x2d, 0x61, 0xef, 0x48, 0xdb, + 0xa2, 0xeb, 0xfe, 0x52, 0x31, 0x1e, 0x21, 0x0a, 0x08, 0xf6, 0x02, 0xd3, + 0xc0, 0x32, 0x3b, 0x6b, 0x2f, 0x64, 0xc4, 0xb3, 0x4b, 0xfe, 0x69, 0x78, + 0xbf, 0x20, 0x62, 0x07, 0x77, 0xdf, 0x2c, 0x18, 0x53, 0x61, 0x8e, 0x05, + 0x01, 0x86, 0xab, 0xab, 0xec, 0x18, 0x8c, 0x15, 0x63, 0x1f, 0xe9, 0x99, + 0xb2, 0x35, 0x77, 0xe1, 0x58, 0xf1, 0xa9, 0x4d, 0x1a, 0xb9, 0x8c, 0x30, + 0x63, 0x6f, 0x9e, 0x7d, 0x4e, 0xcf, 0xb5, 0x6c, 0xf3, 0xe4, 0xdc, 0xab, + 0xf9, 0xae, 0x58, 0xf8, 0x1d, 0x08, 0x7b, 0x73, 0x82, 0x58, 0xc8, 0x67, + 0x48, 0x1a, 0x5e, 0x3d, 0xdb, 0xac, 0x1b, 0x1b, 0xef, 0xeb, 0xa4, 0xe5, + 0x67, 0x48, 0x76, 0xd1, 0x96, 0x4f, 0x6c, 0x7d, 0x06, 0x8c, 0x02, 0x86, + 0x95, 0x83, 0xb6, 0x9b, 0x5e, 0x9a, 0xb5, 0x85, 0xc0, 0x4f, 0x13, 0x1c, + 0x32, 0xf8, 0x29, 0xdf, 0x47, 0x85, 0xdb, 0xe4, 0x37, 0xdc, 0xd8, 0x04, + 0x18, 0xdd, 0xca, 0x97, 0xdd, 0x67, 0x13, 0xbe, 0x74, 0x95, 0xdc, 0xd0, + 0xcc, 0xe6, 0xb5, 0xa5, 0x12, 0x9b, 0x23, 0x4f, 0x41, 0x8c, 0xcc, 0x95, + 0xf4, 0xb0, 0x5f, 0x2a, 0xc4, 0xbf, 0x88, 0xda, 0x55, 0xcb, 0x13, 0x93, + 0x22, 0x60, 0x51, 0x43, 0xc7, 0x9a, 0x2c, 0xfa, 0xb2, 0x59, 0xc1, 0xe6, + 0x8a, 0xa4, 0xb8, 0xfb, 0xd3, 0x31, 0x1d, 0xc7, 0x88, 0xdc, 0xbc, 0xe9, + 0xba, 0xe7, 0xdc, 0xe3, 0xdd, 0x90, 0x96, 0xb4, 0xb4, 0x0a, 0xc1, 0x07, + 0x31, 0x3f, 0xdb, 0xc5, 0x4d, 0x73, 0x58, 0x86, 0x15, 0x37, 0x07, 0x86, + 0x03, 0x17, 0x16, 0x18, 0x15, 0xb9, 0x26, 0x35, 0x8a, 0x43, 0x22, 0xae, + 0x21, 0x52, 0x05, 0x4e, 0x5c, 0x3f, 0x3e, 0xb9, 0x2a, 0x19, 0x13, 0xfd, + 0x31, 0x47, 0x6a, 0x74, 0xaa, 0xb9, 0xc6, 0x2c, 0x13, 0x8c, 0x21, 0xc4, + 0x8d, 0x00, 0xf4, 0x24, 0xf2, 0xb7, 0xd3, 0x13, 0xad, 0x29, 0x5e, 0x50, + 0x0b, 0x0e, 0x9f, 0x9a, 0xb7, 0xf6, 0x9e, 0xba, 0x12, 0x23, 0x84, 0x8c, + 0xbe, 0x2c, 0x14, 0x1e, 0xe6, 0x79, 0x15, 0x20, 0x2d, 0x32, 0x08, 0xd8, + 0x1c, 0x87, 0x1b, 0xa8, 0xc0, 0xbb, 0x85, 0xa9, 0x71, 0x30, 0x5e, 0x39, + 0x48, 0x87, 0xdc, 0x3d, 0x03, 0x29, 0x19, 0xd1, 0xd4, 0x21, 0x3a, 0x53, + 0x2d, 0x5e, 0x78, 0xff, 0x94, 0x4b, 0x91, 0xa6, 0xb5, 0xe5, 0x42, 0x56, + 0x67, 0x6a, 0x0e, 0xf3, 0x2d, 0x6a, 0x4e, 0xd7, 0x3a, 0x81, 0xb1, 0x4d, + 0x0b, 0x66, 0x5f, 0x43, 0x28, 0x7c, 0x75, 0x8b, 0x2b, 0x99, 0x24, 0xc2, + 0x5e, 0x8c, 0x22, 0xf0, 0xd5, 0xb3, 0xfc, 0x86, 0x62, 0xf3, 0xd2, 0x6c, + 0xa7, 0x48, 0x04, 0x44, 0x5d, 0x93, 0x74, 0x37, 0x16, 0x2c, 0x19, 0x12, + 0x57, 0x49, 0xef, 0xd5, 0xd6, 0x92, 0xdc, 0x51, 0xf8, 0x55, 0x3a, 0xc0, + 0x0b, 0xdf, 0x41, 0xb5, 0x01, 0x59, 0x7e, 0x85, 0x65, 0xdb, 0x44, 0xbd, + 0x04, 0x96, 0x1a, 0xd4, 0x6e, 0x22, 0x54, 0x92, 0xdb, 0xc7, 0xc5, 0x3a, + 0xdf, 0x0c, 0xf4, 0x1b, 0xdc, 0x14, 0xf6, 0x91, 0x9c, 0xbe, 0xf8, 0x8e, + 0x70, 0xd1, 0x3a, 0x0e, 0x58, 0xe6, 0xb9, 0xd3, 0xaa, 0xa2, 0x70, 0xba, + 0xdd, 0x16, 0x13, 0x19, 0xd1, 0x96, 0x78, 0x04, 0x2f, 0xd7, 0x38, 0x8c, + 0x35, 0x1f, 0xfc, 0x58, 0xa4, 0x4c, 0xa9, 0x9a, 0xae, 0x13, 0x3b, 0xc1, + 0x20, 0x4b, 0x66, 0x0f, 0x72, 0x42, 0x0a, 0x53, 0x84, 0x54, 0x71, 0x06, + 0xdb, 0x85, 0x8f, 0x40, 0xa6, 0x09, 0xf7, 0x24, 0xc4, 0x35, 0xf7, 0x1d, + 0xd4, 0x3d, 0x54, 0x75, 0xaf, 0xc4, 0x78, 0x0f, 0xce, 0xe0, 0x0c, 0x90, + 0x0f, 0xd5, 0x2e, 0x61, 0xf7, 0x58, 0xaa, 0xf0, 0xc7, 0x37, 0x5a, 0x59, + 0x1f, 0x8a, 0x03, 0x98, 0x43, 0xb7, 0x27, 0x78, 0x4e, 0x44, 0x5a, 0xb5, + 0x29, 0xf5, 0xab, 0x9e, 0xb7, 0x2a, 0xc4, 0xa3, 0x03, 0x00, 0xe3, 0x28, + 0x57, 0xc9, 0x2a, 0x98, 0xb8, 0xa1, 0x45, 0x1d, 0xfa, 0x6e, 0xb3, 0x0d, + 0x42, 0x5a, 0xb6, 0xb1, 0x0e, 0x5c, 0xbe, 0x82, 0xe2, 0x36, 0x40, 0x4b, + 0x05, 0x28, 0xd9, 0xbc, 0x27, 0xd6, 0x77, 0x00, 0xc9, 0x29, 0x6a, 0xd6, + 0x19, 0x8f, 0x8d, 0xda, 0xe1, 0xc3, 0x8b, 0x69, 0x71, 0xd0, 0xf7, 0xc8, + 0x33, 0xef, 0xe6, 0x23, 0x6b, 0xcb, 0x00, 0x56, 0x0a, 0x9b, 0x9d, 0x60, + 0x3a, 0xd3, 0xad, 0xd9, 0x5c, 0x6a, 0x7d, 0xab, 0x35, 0x71, 0x93, 0xc5, + 0xf2, 0x6a, 0x38, 0x0e, 0xfb, 0xd9, 0x9b, 0xa5, 0xda, 0x52, 0x45, 0xef, + 0x93, 0x94, 0x5b, 0x08, 0x8c, 0x07, 0xab, 0x2e, 0x99, 0x88, 0x77, 0xb5, + 0x15, 0x66, 0x7f, 0x0e, 0xfa, 0xb0, 0x29, 0xe4, 0x88, 0xd9, 0xdd, 0x22, + 0xaf, 0x7a, 0x4e, 0xb5, 0xd0, 0x62, 0x85, 0x27, 0x33, 0xf1, 0xb7, 0x34, + 0xb1, 0xe6, 0xda, 0x9f, 0x3c, 0xfe, 0xf5, 0xd4, 0xef, 0x56, 0x48, 0x93, + 0x7a, 0x54, 0xa2, 0x7f, 0x07, 0xea, 0x31, 0xb8, 0x8b, 0xca, 0xb9, 0xdb, + 0x1e, 0x2b, 0xb5, 0x16, 0xe6, 0x0e, 0xd9, 0x3f, 0x7c, 0xf0, 0xc2, 0x3e, + 0x57, 0x64, 0x60, 0x97, 0xfb, 0xdf, 0x8c, 0x3e, 0x56, 0x22, 0x92, 0x2a, + 0xb2, 0x21, 0x00, 0x0a, 0x75, 0x89, 0x68, 0xe7, 0x51, 0xa3, 0x63, 0x05, + 0xe1, 0x6f, 0x1e, 0x1e, 0x80, 0xa2, 0x4b, 0x5d, 0xb7, 0xf4, 0xb7, 0x45, + 0x85, 0x00, 0x84, 0x6e, 0xbe, 0x0b, 0x67, 0xbf, 0x21, 0x06, 0x5a, 0x56, + 0x79, 0xe9, 0x6b, 0x0e, 0x72, 0x19, 0x2d, 0x09, 0x78, 0xd5, 0x5e, 0xc2, + 0x32, 0xee, 0x29, 0xd4, 0x7a, 0x65, 0xc7, 0xfe, 0x16, 0x86, 0xd2, 0x29, + 0x71, 0xe5, 0x91, 0x0e, 0x3e, 0x86, 0xd5, 0x00, 0xc4, 0xfc, 0xd9, 0xae, + 0xd3, 0x7c, 0x13, 0xfd, 0x62, 0xce, 0x0c, 0xb2, 0xe5, 0x1f, 0x6d, 0xed, + 0x55, 0x6f, 0xc1, 0xaa, 0xa1, 0x74, 0x59, 0x46, 0x83, 0xd5, 0x5d, 0x71, + 0x17, 0x13, 0x1d, 0x0b, 0x25, 0xfb, 0x0a, 0xcd, 0x67, 0xfe, 0x57, 0x93, + 0xc2, 0x71, 0x55, 0x6c, 0x68, 0xfa, 0x40, 0xdb, 0xdd, 0xce, 0xd5, 0x5c, + 0xce, 0x0a, 0x1d, 0xfa, 0x19, 0x30, 0xe2, 0x2b, 0x63, 0x98, 0x16, 0x2c, + 0x67, 0x69, 0x55, 0xe5, 0xc1, 0x6c, 0x6e, 0xb7, 0x92, 0x6a, 0xbb, 0x10, + 0xd3, 0x13, 0x2e, 0x73, 0x91, 0x74, 0xcb, 0x9f, 0x5c, 0x7f, 0x5c, 0x48, + 0x58, 0x36, 0x13, 0x47, 0xf7, 0x49, 0xae, 0x90, 0x15, 0x53, 0xb5, 0xe6, + 0x37, 0xfb, 0x81, 0x47, 0xb4, 0x69, 0x84, 0xca, 0x95, 0xab, 0x19, 0x2a, + 0x28, 0xc2, 0x8a, 0xf1, 0xcd, 0xf9, 0x3e, 0xd3, 0xaf, 0xe1, 0x75, 0xf7, + 0x94, 0x74, 0x1c, 0xf5, 0x32, 0xcf, 0x70, 0xbd, 0x69, 0xcc, 0xa8, 0x3c, + 0xca, 0x59, 0x53, 0xfa, 0xcb, 0xe7, 0xb6, 0x36, 0x70, 0xea, 0xe2, 0x84, + 0xfa, 0x5e, 0xbd, 0xd7, 0x59, 0x3d, 0x21, 0xc6, 0x9f, 0x5c, 0x1f, 0xa6, + 0xa9, 0xf1, 0xd3, 0x26, 0x9e, 0xff, 0xbc, 0x81, 0xfe, 0xbe, 0xee, 0x64, + 0xd9, 0x63, 0x94, 0x4b, 0x15, 0xd8, 0x95, 0xaa, 0xec, 0x10, 0xc9, 0xe2, + 0xe1, 0x05, 0x37, 0x64, 0xc4, 0xb0, 0x2e, 0xa5, 0x0e, 0x4c, 0x2d, 0x03, + 0x53, 0xf1, 0x93, 0x77, 0x9d, 0x46, 0x14, 0x67, 0x48, 0x5f, 0xad, 0x1b, + 0xdc, 0xb9, 0x74, 0xa2, 0x6c, 0xfc, 0xd2, 0xa0, 0x1f, 0x43, 0x89, 0x15, + 0xc5, 0x0c, 0xb0, 0x9e, 0x1e, 0xc2, 0xd6, 0x44, 0xd9, 0x6e, 0xfc, 0xb4, + 0x9c, 0x95, 0x90, 0xcd, 0xc3, 0x17, 0x1c, 0x6a, 0xce, 0x03, 0x56, 0x9f, + 0xe7, 0xcd, 0x7e, 0xe7, 0xa2, 0x0c, 0x2b, 0x0d, 0x59, 0xb0, 0xc9, 0x4c, + 0x6e, 0x33, 0x6d, 0x43, 0xc4, 0x3a, 0x10, 0x24, 0x03, 0x3e, 0x09, 0xb6, + 0x86, 0x13, 0xba, 0x18, 0x19, 0xd3, 0xff, 0xeb, 0xa5, 0x25, 0x8f, 0x6f, + 0xc8, 0xe6, 0x96, 0xa4, 0xd2, 0x66, 0x40, 0x81, 0x79, 0xe8, 0x39, 0x18, + 0x41, 0x02, 0x66, 0x5c, 0x30, 0x5f, 0x58, 0x9d, 0x35, 0x16, 0xc6, 0x96, + 0xa8, 0x68, 0xbc, 0x09, 0x83, 0x17, 0x2c, 0x5f, 0x5e, 0xd0, 0x1d, 0xb0, + 0x48, 0x5e, 0xcf, 0x91, 0x16, 0x4d, 0xa0, 0xba, 0xbc, 0x61, 0xa8, 0x3f, + 0x30, 0x09, 0xbb, 0xa3, 0x12, 0xcd, 0xdc, 0x29, 0xf7, 0xb0, 0xad, 0x05, + 0x17, 0xd6, 0xd3, 0x16, 0xfb, 0xe5, 0x99, 0xf4, 0x71, 0x62, 0xa3, 0x45, + 0x45, 0xc7, 0x9b, 0xaa, 0x45, 0xd3, 0x35, 0xfe, 0xfb, 0x63, 0xaf, 0xe7, + 0x85, 0x31, 0xc9, 0x66, 0x26, 0xa9, 0xda, 0x8c, 0xc6, 0xf6, 0xd5, 0xdf, + 0xb1, 0xa9, 0xf1, 0xb6, 0x3d, 0x92, 0xae, 0x4d, 0xbc, 0x74, 0x7d, 0x76, + 0x5a, 0x59, 0x8c, 0x87, 0xff, 0x95, 0x2f, 0x67, 0x37, 0x30, 0x1a, 0xc1, + 0x23, 0x2e, 0x0c, 0xaa, 0x80, 0x1c, 0xf3, 0xa3, 0x74, 0x94, 0xb2, 0xda, + 0x1a, 0xb8, 0x46, 0xec, 0x30, 0x76, 0xf4, 0xdf, 0xfb, 0x00, 0xb3, 0x6f, + 0x86, 0xc1, 0xc5, 0x3a, 0x5d, 0x11, 0x14, 0x87, 0xeb, 0x30, 0xd8, 0x33, + 0x18, 0x00, 0x01, 0x76, 0x43, 0x82, 0xcd, 0x1c, 0x36, 0x54, 0xd2, 0x64, + 0x5b, 0xfb, 0x93, 0xca, 0x20, 0x1d, 0xa3, 0x20, 0x99, 0xc3, 0x8e, 0x5c, + 0x82, 0xfc, 0x56, 0x07, 0x41, 0x4b, 0x4f, 0x54, 0xc7, 0xb5, 0xe8, 0x6d, + 0x7e, 0xd8, 0x8a, 0x56, 0xb4, 0x76, 0x1e, 0xd3, 0x82, 0x97, 0xdd, 0x2b, + 0xd9, 0x80, 0xb7, 0xb6, 0xeb, 0x3d, 0xe5, 0xe0, 0x20, 0x27, 0x8c, 0xf0, + 0xd6, 0x14, 0xc7, 0xcd, 0x79, 0xbc, 0xa0, 0x21, 0x85, 0xc3, 0x02, 0xae, + 0x73, 0xc4, 0x0a, 0x39, 0x1a, 0x98, 0x61, 0xc3, 0x86, 0xd8, 0x97, 0x67, + 0x87, 0xe9, 0x56, 0x0b, 0x61, 0xa6, 0x7e, 0x07, 0xfb, 0x0a, 0x8b, 0xd1, + 0x90, 0xbd, 0x39, 0x22, 0xdb, 0xc2, 0x7f, 0xaa, 0x79, 0xb7, 0x39, 0x09, + 0xc1, 0x69, 0xdb, 0xe2, 0x7f, 0xec, 0xde, 0x80, 0x7a, 0x6c, 0xde, 0x76, + 0xa4, 0xe8, 0xe0, 0x8d, 0x71, 0xfa, 0x62, 0xf0, 0x2e, 0x7b, 0xf4, 0xce, + 0x65, 0x18, 0x42, 0xde, 0x92, 0x1b, 0xdc, 0xc9, 0xa7, 0x8d, 0xa5, 0x91, + 0x0f, 0xa5, 0x1b, 0x89, 0xcf, 0x29, 0x10, 0x1d, 0x94, 0x78, 0x1b, 0xea, + 0x79, 0x35, 0x62, 0xd4, 0x29, 0xe6, 0x59, 0x8c, 0xc1, 0xd2, 0xf3, 0x32, + 0x71, 0x09, 0xce, 0x51, 0xd7, 0x14, 0x29, 0x92, 0xbf, 0xdf, 0x9a, 0x69, + 0xda, 0x61, 0x03, 0x0f, 0xa2, 0x0a, 0xab, 0x57, 0x1c, 0xca, 0xab, 0x42, + 0x63, 0x63, 0x1e, 0x35, 0x5d, 0x8d, 0xba, 0x6f, 0x4b, 0x6b, 0x5e, 0x7c, + 0xc0, 0x1e, 0xb7, 0xf4, 0x65, 0xbd, 0x13, 0x1c, 0xf2, 0xa9, 0x73, 0x38, + 0xc3, 0x47, 0xc9, 0x32, 0xf0, 0x30, 0x57, 0x05, 0x42, 0x52, 0xac, 0x72, + 0xee, 0x9f, 0x4e, 0x21, 0xbf, 0x38, 0x19, 0x6d, 0x48, 0xec, 0x97, 0xcb, + 0x70, 0x9e, 0xee, 0xb3, 0xa1, 0xaa, 0xa6, 0x7e, 0xe9, 0x16, 0xdf, 0xcd, + 0x1c, 0x56, 0xcf, 0xf0, 0x9f, 0x4d, 0xd1, 0x8c, 0x14, 0x50, 0x5d, 0x23, + 0x96, 0xe0, 0x1f, 0x61, 0x79, 0xbf, 0x44, 0xfd, 0xa2, 0x31, 0xf7, 0x4c, + 0x0c, 0x8d, 0x8c, 0x1b, 0xbf, 0x8d, 0x45, 0xbf, 0x0b, 0xd8, 0xfb, 0x6f, + 0xff, 0x15, 0xc0, 0x44, 0x7c, 0xb9, 0xb8, 0xf9, 0xef, 0x0d, 0x79, 0x11, + 0x3b, 0x79, 0xd2, 0x52, 0x89, 0x5a, 0xcd, 0x0f, 0x10, 0x92, 0x42, 0xfe, + 0xcf, 0x0a, 0x11, 0x8a, 0x8a, 0xda, 0xee, 0xc8, 0x6b, 0xd9, 0xab, 0xec, + 0xb4, 0x25, 0x6f, 0x8d, 0x68, 0x26, 0xe8, 0xdd, 0xf5, 0xa4, 0xe8, 0x65, + 0x37, 0x03, 0xb0, 0xad, 0x73, 0x3b, 0x4d, 0x74, 0x57, 0x7f, 0x0f, 0x6c, + 0xb0, 0x5d, 0x59, 0x80, 0x13, 0xa1, 0x6c, 0xb0, 0xed, 0x26, 0xec, 0x79, + 0x50, 0x5f, 0x5c, 0xb7, 0xa6, 0xae, 0xe8, 0x0a, 0x6d, 0x55, 0x9a, 0x7f, + 0x59, 0x23, 0xa3, 0x7e, 0x84, 0x7b, 0x3b, 0xfc, 0xde, 0xe1, 0xd9, 0x7c, + 0xd6, 0x87, 0xb3, 0x0e, 0xdb, 0xc1, 0x8c, 0x5e, 0x77, 0xb7, 0x23, 0xd7, + 0x14, 0xd4, 0x23, 0xb4, 0xac, 0x45, 0xbf, 0xfe, 0x40, 0x20, 0x4d, 0x91, + 0x20, 0x94, 0xbd, 0x58, 0xb1, 0x99, 0x69, 0xaf, 0x31, 0x68, 0xbd, 0x61, + 0x5e, 0x87, 0x81, 0x54, 0x4e, 0x2d, 0x03, 0xc2, 0xe2, 0xcd, 0xdc, 0x59, + 0xe5, 0x35, 0xcf, 0xb8, 0xfc, 0x65, 0xed, 0x46, 0xb3, 0x92, 0xe7, 0xf8, + 0x3a, 0x32, 0xaa, 0x0e, 0x5a, 0x82, 0x58, 0x4e, 0x77, 0xd8, 0x33, 0xc9, + 0xb0, 0x3e, 0xad, 0xa5, 0x92, 0xe9, 0xa9, 0x8c, 0x00, 0x72, 0x8f, 0xdc, + 0x77, 0x9d, 0x5c, 0x97, 0xd6, 0x58, 0x20, 0x1e, 0xf4, 0x55, 0x2d, 0xc0, + 0x30, 0xf0, 0x66, 0xda, 0x2d, 0x11, 0xac, 0xd4, 0x2d, 0xd5, 0x25, 0x42, + 0x1d, 0xce, 0x49, 0xb5, 0x95, 0x79, 0x9b, 0x6c, 0x65, 0xe0, 0x8a, 0xc5, + 0x9f, 0x75, 0xe3, 0xe6, 0xf8, 0xa6, 0x88, 0xd6, 0x93, 0x70, 0x4f, 0x89, + 0x94, 0x74, 0xbd, 0xef, 0xc2, 0x1a, 0x55, 0x74, 0x37, 0x44, 0x85, 0x1e, + 0xa9, 0xbb, 0x3f, 0x15, 0xc7, 0x84, 0x80, 0xa5, 0xab, 0xc3, 0x91, 0x8e, + 0xd6, 0x32, 0x46, 0x0d, 0xfa, 0xd1, 0x19, 0xd1, 0xfc, 0x02, 0xe2, 0x20, + 0xa6, 0xa9, 0xf7, 0xf4, 0xcc, 0x5b, 0x54, 0x4f, 0x4a, 0x73, 0x35, 0xda, + 0xf0, 0x31, 0x81, 0x1a, 0x82, 0xe7, 0xd4, 0xc8, 0xb4, 0x1d, 0x70, 0xa9, + 0x5d, 0x67, 0xb9, 0x7d, 0x4b, 0xcd, 0xa4, 0x81, 0xf9, 0xb2, 0x38, 0x07, + 0x16, 0xd5, 0x28, 0x82, 0xb9, 0x76, 0x5b, 0xa1, 0x09, 0x7a, 0xe7, 0x2a, + 0xcf, 0xc0, 0x3d, 0x2a, 0x42, 0x9a, 0xf3, 0xc8, 0x64, 0x15, 0x7c, 0x94, + 0xd0, 0x97, 0xee, 0x34, 0xb6, 0xf0, 0xb2, 0xba, 0x7e, 0xb2, 0xbb, 0x4e, + 0xbf, 0x88, 0xd0, 0x6b, 0xc5, 0x9c, 0xb9, 0xf2, 0x7d, 0xbf, 0x5d, 0x87, + 0xbc, 0x36, 0x4a, 0xd1, 0x1b, 0x6f, 0x40, 0x09, 0xba, 0x26, 0x51, 0xd6, + 0xc0, 0xaf, 0x27, 0xce, 0x27, 0x8d, 0x93, 0xa8, 0x6c, 0x91, 0xe7, 0x91, + 0x42, 0xc0, 0x68, 0x36, 0x5b, 0xd5, 0x56, 0x4c, 0xe2, 0x77, 0xc3, 0xac, + 0x56, 0xe3, 0x1c, 0xc2, 0xf9, 0x78, 0x02, 0x39, 0x7d, 0xed, 0x18, 0x2a, + 0x01, 0x48, 0xe6, 0xf6, 0x7e, 0x34, 0x50, 0xf4, 0x57, 0x56, 0x93, 0xdb, + 0x85, 0x1b, 0x1e, 0x1a, 0x6f, 0x3e, 0x07, 0x3c, 0xad, 0x3f, 0x8d, 0x75, + 0x53, 0xc3, 0x20, 0x72, 0x93, 0x28, 0xd2, 0x86, 0xc8, 0xa5, 0x90, 0xf2, + 0x5f, 0x13, 0xd5, 0xa5, 0xbe, 0x88, 0x9e, 0x9a, 0x57, 0x2c, 0x53, 0x3f, + 0x11, 0x25, 0x00, 0x00, 0x4a, 0x16, 0x8d, 0xd3, 0x3f, 0x2d, 0x3d, 0x88, + 0xbb, 0x4c, 0x4f, 0x9a, 0xb9, 0x97, 0x5f, 0xed, 0x71, 0xa9, 0x68, 0xd9, + 0x4a, 0x14, 0x24, 0xc7, 0xbe, 0xff, 0x85, 0x57, 0xa3, 0x21, 0xe3, 0x21, + 0x79, 0x1f, 0xd0, 0xbb, 0xb7, 0x73, 0xde, 0x60, 0x02, 0x4b, 0x8f, 0x7d, + 0xb3, 0xb3, 0x8a, 0xda, 0x4c, 0xf4, 0xb8, 0xf1, 0x31, 0xff, 0x32, 0x7b, + 0xd8, 0xfa, 0xb1, 0xcb, 0xb4, 0x58, 0xf5, 0xc8, 0x64, 0xdf, 0xfe, 0x3d, + 0x89, 0x52, 0x5c, 0x52, 0x95, 0xf3, 0xba, 0x0d, 0x1d, 0x2c, 0xc4, 0xf7, + 0x3c, 0x3b, 0x6f, 0x8e, 0xc7, 0xab, 0xad, 0x3d, 0x3d, 0x95, 0x9b, 0xc7, + 0x71, 0x36, 0xae, 0x08, 0xc3, 0x08, 0x79, 0xfa, 0x24, 0xee, 0xd9, 0xf9, + 0x63, 0xc7, 0xd9, 0x16, 0x19, 0x8e, 0x0d, 0xaf, 0x52, 0x87, 0x86, 0x7d, + 0xec, 0xe5, 0xea, 0x5a, 0xda, 0x86, 0x9d, 0x0e, 0x50, 0x53, 0x8c, 0x24, + 0xa8, 0x69, 0xc4, 0xf3, 0x85, 0x7b, 0x34, 0x67, 0x19, 0x35, 0xec, 0xd4, + 0xd4, 0x50, 0xe0, 0xe6, 0xe9, 0x29, 0x5b, 0x92, 0xee, 0xba, 0xa9, 0xef, + 0xf6, 0x35, 0x23, 0x8b, 0xdb, 0x48, 0x32, 0x25, 0x41, 0xf3, 0x55, 0x12, + 0x33, 0xc3, 0x6c, 0xed, 0x32, 0xe1, 0x64, 0x7a, 0x8d, 0xa2, 0x19, 0x5a, + 0x26, 0xf2, 0x83, 0xf1, 0xe4, 0x27, 0xdb, 0x67, 0xc3, 0x89, 0x37, 0xea, + 0x78, 0x19, 0xc6, 0xa3, 0x82, 0x84, 0x1c, 0xf3, 0x2b, 0xbe, 0xde, 0xba, + 0xe7, 0x60, 0x2e, 0xf5, 0x4e, 0xb6, 0x73, 0x29, 0xac, 0xc7, 0x55, 0xab, + 0x21, 0xe9, 0x95, 0x78, 0xd5, 0x8e, 0x27, 0xdc, 0x92, 0x5f, 0xc0, 0xcb, + 0xee, 0x66, 0x09, 0x0a, 0xfc, 0x94, 0x43, 0x44, 0x50, 0x35, 0x57, 0xf8, + 0x08, 0xf9, 0x97, 0xa2, 0x0e, 0xde, 0x81, 0xe1, 0xd1, 0xa0, 0x41, 0xfe, + 0xe6, 0x08, 0x6c, 0x98, 0x8c, 0x81, 0x46, 0x0e, 0xf9, 0x9a, 0x54, 0xfe, + 0xc3, 0x91, 0xe3, 0xd4, 0x46, 0xca, 0x52, 0xa2, 0x73, 0x9e, 0x4d, 0xa7, + 0xfd, 0xa1, 0x8e, 0x43, 0x28, 0xf5, 0xa3, 0xa2, 0x62, 0x20, 0x53, 0x62, + 0x05, 0x49, 0xba, 0x06, 0xe2, 0xeb, 0xba, 0xfb, 0x8e, 0xa0, 0x22, 0xc7, + 0xf9, 0xcc, 0x7f, 0x8b, 0xa8, 0x5d, 0x55, 0xd2, 0x24, 0xff, 0xdd, 0x2c, + 0xc1, 0xd0, 0x3d, 0xe4, 0x79, 0xea, 0xba, 0x62, 0xe5, 0xa2, 0x62, 0xf4, + 0x1f, 0xec, 0xb0, 0x07, 0xf2, 0x0d, 0x32, 0x84, 0x86, 0x81, 0x3d, 0x95, + 0xc1, 0x64, 0xfe, 0x9a, 0x3d, 0x8f, 0x4b, 0x6d, 0xfb, 0x0d, 0x42, 0xcf, + 0xbf, 0xdb, 0x51, 0xb2, 0x16, 0xa2, 0x35, 0xaa, 0xe7, 0x31, 0x54, 0xc2, + 0x87, 0xc6, 0xa5, 0x30, 0x71, 0x64, 0x65, 0xff, 0x41, 0x20, 0xb0, 0x83, + 0xdb, 0xb7, 0x95, 0xce, 0xd7, 0xcc, 0x7a, 0x77, 0xad, 0xb8, 0xb7, 0x4c, + 0xfc, 0x11, 0x05, 0x2b, 0xc4, 0xd4, 0xb6, 0x8b, 0xae, 0x13, 0xa5, 0x40, + 0x18, 0x6e, 0x0d, 0xe3, 0xc6, 0xb0, 0x81, 0x46, 0x46, 0x7e, 0x52, 0x0b, + 0x85, 0x4d, 0x98, 0xd9, 0x42, 0xdf, 0xde, 0x45, 0xc1, 0x5a, 0x33, 0x12, + 0x46, 0x26, 0xb3, 0x6f, 0xf2, 0x8b, 0x37, 0x6b, 0xfd, 0x08, 0xf4, 0x46, + 0x86, 0x89, 0x63, 0x63, 0x21, 0xe5, 0xa9, 0xb7, 0xd0, 0x09, 0x17, 0x52, + 0xee, 0xea, 0xdf, 0x97, 0xb7, 0x73, 0x2e, 0x54, 0x2c, 0x7b, 0x70, 0xd3, + 0xda, 0x26, 0x57, 0x1f, 0xb0, 0x19, 0xd9, 0x91, 0x18, 0x69, 0x75, 0x42, + 0x63, 0xcf, 0x6c, 0x8c, 0x98, 0x5e, 0x17, 0x99, 0x7e, 0x1d, 0xdc, 0x67, + 0x6d, 0x99, 0xd9, 0x02, 0x6e, 0x73, 0x90, 0x5a, 0x4f, 0x0a, 0xb4, 0x48, + 0xfb, 0xc5, 0xbd, 0xd2, 0x10, 0x05, 0xa6, 0x12, 0x68, 0x36, 0x28, 0x51, + 0x60, 0x1c, 0xa1, 0xe9, 0x90, 0x54, 0xa5, 0x53, 0xc3, 0x48, 0x9e, 0xd8, + 0x42, 0x52, 0x85, 0x0e, 0xff, 0xfe, 0xbf, 0xad, 0x3a, 0xa4, 0x57, 0x09, + 0x13, 0x38, 0x64, 0x15, 0x7c, 0xfd, 0xed, 0x91, 0x76, 0x44, 0x20, 0x84, + 0xd9, 0x90, 0xab, 0xfe, 0xfd, 0xd6, 0xab, 0xf1, 0xb3, 0x25, 0x21, 0x3d, + 0x97, 0x72, 0xb2, 0x95, 0xc5, 0x22, 0x80, 0xd9, 0x4a, 0x49, 0x9d, 0x99, + 0xc2, 0x4a, 0x9a, 0x59, 0xb3, 0x71, 0x75, 0x5b, 0xf9, 0x89, 0x7a, 0xdd, + 0xa9, 0xb3, 0xc3, 0xeb, 0x42, 0x91, 0xe2, 0x97, 0x30, 0x40, 0x48, 0x68, + 0x19, 0x3b, 0xf5, 0x7b, 0x4e, 0x33, 0x4b, 0x0c, 0xf3, 0xed, 0xda, 0x76, + 0x3f, 0xb0, 0x4b, 0x53, 0x85, 0x04, 0x33, 0x07, 0x53, 0xd8, 0x55, 0xa2, + 0xfb, 0x30, 0x2c, 0x66, 0xbd, 0x21, 0xf8, 0xfa, 0x20, 0x14, 0x9a, 0x0d, + 0x7f, 0xc9, 0x2f, 0x5b, 0x34, 0x29, 0x09, 0x16, 0xb5, 0x0a, 0x8d, 0xdf, + 0xa2, 0x84, 0x9a, 0xae, 0xe6, 0xa0, 0x50, 0x80, 0x31, 0x04, 0xd3, 0x0c, + 0x8f, 0xd1, 0x8a, 0xfd, 0xb4, 0xa5, 0xae, 0xf5, 0x3c, 0x62, 0xae, 0x45, + 0x70, 0xbb, 0x54, 0x62, 0xc8, 0x50, 0x71, 0x42, 0x85, 0xf6, 0x6f, 0xa0, + 0xf0, 0x10, 0x8a, 0x09, 0xbd, 0x71, 0x78, 0xa6, 0x5e, 0xe4, 0x03, 0x8f, + 0x3b, 0xd0, 0x5c, 0x37, 0x55, 0x1a, 0xc8, 0x57, 0x26, 0x62, 0x6c, 0xc4, + 0x67, 0x71, 0x9d, 0x97, 0xc0, 0xea, 0x35, 0x3e, 0x12, 0xd0, 0x2b, 0xc2, + 0x8f, 0x9e, 0xa6, 0x41, 0x48, 0x33, 0x83, 0x38, 0x37, 0x7e, 0xd4, 0xe3, + 0xee, 0x94, 0x8b, 0x81, 0xa4, 0x60, 0xdd, 0xdd, 0xc1, 0x8a, 0x7b, 0xda, + 0xa8, 0x46, 0xb8, 0x42, 0x3a, 0x25, 0xd6, 0x81, 0x89, 0x29, 0x21, 0xc2, + 0x0c, 0x5b, 0xfd, 0x3e, 0x8c, 0x65, 0x91, 0x52, 0xb3, 0x74, 0x1f, 0xd1, + 0x49, 0x7e, 0x1d, 0x59, 0x58, 0x96, 0xb5, 0xee, 0x32, 0xa4, 0xa8, 0x07, + 0x7c, 0xd1, 0x5b, 0x4b, 0xf8, 0x43, 0x5a, 0xa5, 0xcc, 0x60, 0xcc, 0x08, + 0x6a, 0x3c, 0x41, 0x66, 0x99, 0xe3, 0xa8, 0xe0, 0xb8, 0x87, 0xfc, 0x92, + 0xc0, 0x79, 0xc5, 0x3f, 0xd6, 0xc6, 0x8c, 0x01, 0xf4, 0xa5, 0x05, 0xad, + 0x51, 0xed, 0x04, 0xd7, 0x55, 0xc0, 0x73, 0x05, 0x0e, 0x73, 0xe5, 0x39, + 0x45, 0x5b, 0x95, 0x4a, 0x34, 0x07, 0x99, 0xdf, 0x4c, 0x35, 0xf5, 0x0c, + 0x27, 0x6d, 0xd1, 0x45, 0xf1, 0xfd, 0x24, 0xb7, 0xfe, 0xea, 0x11, 0x5d, + 0xa2, 0xc5, 0xa6, 0x81, 0x37, 0x1d, 0xc2, 0x31, 0x31, 0xfc, 0xe0, 0xf4, + 0xd7, 0xe9, 0x98, 0x8b, 0xe3, 0x70, 0x51, 0x62, 0xc8, 0x61, 0x6d, 0xec, + 0x75, 0x56, 0x71, 0xae, 0x88, 0xe0, 0x80, 0xf5, 0xb7, 0x85, 0x10, 0xb7, + 0x3d, 0x16, 0x78, 0x5f, 0x72, 0xab, 0x8f, 0x63, 0xc6, 0xd5, 0xa8, 0xc9, + 0x9c, 0xef, 0x8d, 0x9a, 0xc5, 0x4f, 0x63, 0xad, 0xc0, 0xf3, 0x1f, 0x69, + 0x0e, 0xce, 0x29, 0x92, 0xc1, 0x3b, 0xb0, 0xc5, 0xed, 0x0a, 0x7b, 0x92, + 0xd0, 0x4c, 0x9c, 0x82, 0xb0, 0x51, 0xf6, 0x33, 0x61, 0x3b, 0x76, 0x48, + 0x38, 0xf4, 0x7c, 0xaa, 0x52, 0x87, 0x15, 0x1a, 0xbe, 0xb8, 0xdc, 0x9b, + 0x16, 0xd2, 0x07, 0xf7, 0xf9, 0x74, 0xe0, 0xaf, 0x0e, 0x29, 0x05, 0xec, + 0x6c, 0x0e, 0x3b, 0xa7, 0xe7, 0xa4, 0xfc, 0xa4, 0xef, 0x57, 0x16, 0x7f, + 0x13, 0xbd, 0x8c, 0x42, 0x02, 0x55, 0x70, 0x56, 0xa5, 0xa9, 0x01, 0x29, + 0x12, 0x7d, 0x80, 0x46, 0x18, 0x8e, 0x39, 0x3f, 0x44, 0x55, 0xec, 0xef, + 0x60, 0x58, 0x7d, 0xce, 0x64, 0x8e, 0x9c, 0xea, 0xe4, 0x73, 0xd1, 0x48, + 0x9c, 0x3f, 0x92, 0xa0, 0x9a, 0x76, 0xa5, 0x5a, 0x13, 0x1f, 0x10, 0xb9, + 0xb7, 0xb1, 0xde, 0x49, 0x22, 0x58, 0xf4, 0x43, 0x5f, 0x03, 0x43, 0xc3, + 0x6c, 0xbf, 0x82, 0xaf, 0x88, 0x39, 0xfd, 0xb2, 0x28, 0x9b, 0x47, 0x3f, + 0x83, 0x3d, 0xd9, 0x7c, 0xf0, 0xc9, 0xc5, 0xa2, 0xb4, 0xd6, 0x0d, 0x59, + 0x51, 0x27, 0x60, 0x10, 0x5e, 0xbb, 0x18, 0xa6, 0x42, 0x4a, 0x9d, 0xc4, + 0x16, 0x0e, 0xb6, 0x57, 0x23, 0x03, 0x24, 0x27, 0xdc, 0x20, 0x56, 0x30, + 0x8b, 0x0f, 0xb6, 0xb7, 0x73, 0xf5, 0x36, 0x3e, 0xf6, 0x7a, 0x71, 0xa5, + 0x57, 0xcc, 0x6d, 0xc6, 0xf3, 0xdc, 0x35, 0xfb, 0x95, 0xf7, 0xa7, 0xd7, + 0x56, 0x38, 0xd4, 0x15, 0xe2, 0xd5, 0x6f, 0x70, 0x30, 0xc8, 0x7d, 0x8a, + 0x87, 0xe6, 0xd1, 0xe0, 0x50, 0x62, 0xde, 0xfa, 0x29, 0x40, 0x97, 0xa0, + 0x54, 0x63, 0x31, 0xd3, 0x08, 0x87, 0x0a, 0xdc, 0x6e, 0x5e, 0xab, 0x8d, + 0x16, 0xaf, 0x6e, 0x8b, 0x1a, 0x77, 0xf6, 0xd4, 0xe0, 0xbf, 0x59, 0xab, + 0xc7, 0xb0, 0x45, 0x18, 0xaa, 0xe6, 0x65, 0x6f, 0x7d, 0x13, 0xb2, 0xbf, + 0xb3, 0x66, 0x72, 0xfa, 0xfd, 0xee, 0xad, 0x07, 0x56, 0x51, 0x6a, 0xe2, + 0xff, 0xb2, 0xaf, 0x4d, 0xd1, 0xf2, 0x77, 0x35, 0x5e, 0x90, 0xcd, 0xe7, + 0xa8, 0x32, 0x4d, 0x9f, 0xbd, 0xa8, 0xce, 0xab, 0xf1, 0x49, 0x98, 0xb5, + 0x23, 0x5c, 0x62, 0x2d, 0x43, 0x31, 0x80, 0x87, 0xc2, 0xa8, 0xf5, 0xb9, + 0xb6, 0xae, 0x7f, 0x37, 0x13, 0xb8, 0x6b, 0x73, 0xf3, 0x56, 0x38, 0xa7, + 0x9b, 0x97, 0x69, 0x37, 0x00, 0xdc, 0xff, 0xfe, 0x58, 0xc9, 0x12, 0x47, + 0x75, 0x98, 0x1f, 0xad, 0xd8, 0xb5, 0xc8, 0x47, 0x4f, 0xd0, 0x72, 0x63, + 0x54, 0x25, 0x6c, 0x88, 0xc9, 0x9f, 0x3c, 0x82, 0xe0, 0xdd, 0x4c, 0xff, + 0x8e, 0xaf, 0x8f, 0x8e, 0xea, 0x84, 0x3f, 0x73, 0xdd, 0x9e, 0x18, 0x73, + 0x47, 0x70, 0xc7, 0xc7, 0x99, 0x65, 0xcf, 0xf3, 0xb6, 0x24, 0xed, 0x97, + 0x8f, 0xcd, 0x93, 0x1e, 0xff, 0x6e, 0x9c, 0xf1, 0x30, 0x14, 0x1a, 0x27, + 0x59, 0x6a, 0x0e, 0xf3, 0xe4, 0xfa, 0x1d, 0x65, 0xb5, 0x53, 0xe4, 0xab, + 0xb1, 0x3e, 0xe1, 0x91, 0xf4, 0x6d, 0x99, 0xca, 0x7d, 0x03, 0x08, 0x50, + 0xea, 0xa9, 0x39, 0x7f, 0x6d, 0xe7, 0x43, 0xfb, 0x64, 0xcc, 0x4b, 0x9e, + 0xa0, 0x26, 0xe4, 0x0e, 0xff, 0xb7, 0x11, 0x0a, 0x29, 0x50, 0x90, 0xd7, + 0x4d, 0x62, 0x9a, 0x4a, 0x23, 0xb7, 0xd3, 0x53, 0xde, 0x3a, 0xd1, 0xba, + 0xd3, 0x10, 0x59, 0xc6, 0xc5, 0x5e, 0xac, 0xf9, 0x61, 0x74, 0x54, 0xf4, + 0x27, 0x9f, 0x9a, 0x61, 0x13, 0xdc, 0xe5, 0x96, 0xe3, 0x95, 0x0d, 0xcc, + 0xbd, 0x81, 0x74, 0x79, 0x73, 0xef, 0x2e, 0x0b, 0x0f, 0x91, 0x65, 0x3c, + 0x26, 0x7c, 0x47, 0x10, 0x31, 0x0b, 0xfb, 0x41, 0x0c, 0xc2, 0xa8, 0xc4, + 0x0e, 0xbd, 0x0a, 0x8c, 0xa4, 0x80, 0x45, 0x57, 0x62, 0x0b, 0x4d, 0x44, + 0x5e, 0x59, 0x77, 0xfd, 0x3d, 0xf3, 0xd7, 0x92, 0x49, 0xc1, 0xcb, 0x8a, + 0x54, 0x56, 0x3b, 0xde, 0xcf, 0x16, 0x9a, 0x65, 0xbe, 0xac, 0x64, 0xe1, + 0xd4, 0xd4, 0x1e, 0xac, 0x6b, 0x4a, 0xad, 0xc4, 0x33, 0xac, 0xcb, 0x83, + 0xf4, 0x4d, 0xe8, 0xb6, 0xd7, 0x23, 0xd7, 0x71, 0x25, 0xa2, 0x25, 0x3d, + 0x7e, 0xf0, 0x3b, 0x7f, 0x61, 0x11, 0x56, 0xd4, 0x83, 0xc8, 0xc0, 0x29, + 0x38, 0x10, 0x73, 0xad, 0x6a, 0xb7, 0xb9, 0xd2, 0x2e, 0x9f, 0xae, 0x16, + 0x5e, 0xa6, 0x13, 0x1c, 0xc2, 0x17, 0x73, 0x43, 0x03, 0xdd, 0xa6, 0xaf, + 0x9a, 0x17, 0x31, 0xb8, 0x86, 0x97, 0xc2, 0xd6, 0xe6, 0xed, 0xd4, 0xe1, + 0x7d, 0xb9, 0xa6, 0x96, 0xc1, 0x4b, 0xcb, 0x11, 0x1e, 0xe1, 0xe0, 0xd2, + 0x28, 0x69, 0x68, 0x3b, 0x21, 0x17, 0x63, 0x0c, 0xc0, 0x49, 0x30, 0x22, + 0x3a, 0x59, 0x72, 0xe6, 0x47, 0xb4, 0xdc, 0xa8, 0x29, 0x1c, 0x89, 0xa6, + 0x3a, 0x77, 0x99, 0xea, 0x46, 0xce, 0x38, 0xda, 0x31, 0x88, 0xad, 0xe7, + 0x26, 0xce, 0xc6, 0x56, 0x04, 0x30, 0xfa, 0x01, 0xac, 0xbb, 0xe2, 0xb8, + 0x23, 0xe4, 0x9d, 0x4f, 0x77, 0x02, 0x00, 0x28, 0xf1, 0xe0, 0x19, 0x3f, + 0x22, 0x4f, 0x22, 0x69, 0x87, 0xc0, 0x4e, 0x26, 0x33, 0xfe, 0x6c, 0x70, + 0x56, 0x3b, 0x60, 0x5f, 0xfb, 0xf8, 0x43, 0xcf, 0x3f, 0xb9, 0xcb, 0x80, + 0x22, 0xbb, 0x0a, 0xa8, 0x1c, 0x3e, 0x7e, 0x4d, 0x42, 0x60, 0x5c, 0x8e, + 0xfa, 0x42, 0xb3, 0x95, 0xe7, 0x92, 0x6b, 0xec, 0x7a, 0x95, 0x88, 0x98, + 0xe3, 0xf9, 0x0d, 0xe5, 0x08, 0xf1, 0x26, 0x96, 0x2a, 0x81, 0x2b, 0x7c, + 0x0d, 0x12, 0xa0, 0x7f, 0x7b, 0x39, 0xf6, 0xcc, 0x1b, 0x2d, 0x2c, 0xe9, + 0x5b, 0x02, 0x9b, 0x5c, 0x94, 0x51, 0x13, 0xe8, 0xa0, 0x19, 0xce, 0xde, + 0x07, 0x1b, 0xda, 0x39, 0x14, 0xb5, 0x8b, 0xcf, 0x79, 0x3e, 0x2b, 0xb8, + 0x75, 0xab, 0x81, 0xee, 0x5e, 0x08, 0x33, 0xc3, 0x49, 0x5b, 0x4a, 0x9c, + 0x74, 0x34, 0xde, 0x08, 0x61, 0x03, 0x38, 0xe3, 0xd8, 0xff, 0xc5, 0xc0, + 0xb5, 0x40, 0xd5, 0x26, 0x57, 0x85, 0xf1, 0xb7, 0x77, 0xb6, 0x36, 0xe0, + 0x8d, 0x43, 0x3a, 0xef, 0xfe, 0x0f, 0xf7, 0xee, 0x67, 0x6c, 0x7b, 0xd1, + 0x83, 0xf6, 0x10, 0xda, 0x67, 0x04, 0x3a, 0x27, 0xd8, 0x3a, 0xcb, 0x9d, + 0x4c, 0xa6, 0x9a, 0xc7, 0xea, 0x07, 0xc6, 0x76, 0x79, 0x1b, 0x23, 0x4a, + 0x68, 0x2f, 0x14, 0x84, 0x42, 0x79, 0xe8, 0x1f, 0xf2, 0xe6, 0xac, 0x72, + 0xb0, 0xb0, 0xb6, 0x39, 0x95, 0x40, 0xa4, 0x6e, 0x54, 0x2e, 0xb7, 0xb5, + 0x13, 0x70, 0x48, 0x0d, 0x27, 0xed, 0x2c, 0xa2, 0x64, 0x53, 0xb4, 0x04, + 0x84, 0xab, 0xd8, 0xea, 0x2a, 0x8c, 0xac, 0x5b, 0x1d, 0xb8, 0xb2, 0xbe, + 0x55, 0x2b, 0x4a, 0x47, 0xfc, 0xe0, 0x15, 0x78, 0xb6, 0xd6, 0xff, 0x20, + 0xa8, 0x8a, 0xec, 0x8b, 0x30, 0xef, 0xc5, 0xc6, 0xec, 0xa0, 0xdf, 0xd3, + 0xc4, 0x2b, 0x4a, 0xdf, 0xef, 0x5c, 0x46, 0xb3, 0x31, 0xc7, 0x5f, 0x8f, + 0x1e, 0x99, 0x76, 0x81, 0x71, 0x61, 0xdb, 0xc3, 0xc4, 0x0f, 0x66, 0x7b, + 0xd7, 0x44, 0xc7, 0x8d, 0x12, 0x38, 0x71, 0x7c, 0xd8, 0x41, 0xf6, 0x8a, + 0xb9, 0xba, 0xd2, 0x1f, 0xa1, 0x27, 0x64, 0x67, 0x51, 0xb2, 0xaf, 0xea, + 0x02, 0x95, 0x79, 0x20, 0x0a, 0xc8, 0xaa, 0x03, 0x11, 0xb6, 0x8b, 0x7d, + 0x86, 0xb7, 0xef, 0x5e, 0x3f, 0x0b, 0x91, 0x47, 0xf0, 0x43, 0xb4, 0x54, + 0x1d, 0x16, 0x66, 0xe9, 0x63, 0x1a, 0x55, 0xaf, 0x34, 0xad, 0x11, 0x68, + 0x4d, 0x36, 0xb7, 0x0c, 0x6d, 0x4d, 0xed, 0xba, 0x14, 0xe8, 0xf6, 0xe2, + 0x15, 0x64, 0xb6, 0x15, 0x28, 0xbf, 0xd2, 0x4d, 0xb6, 0x6f, 0xca, 0x5f, + 0x81, 0x1b, 0xf0, 0x31, 0xf5, 0xd3, 0xe0, 0x06, 0xc7, 0xf3, 0x0c, 0x18, + 0x91, 0x45, 0x22, 0xa2, 0x30, 0x48, 0x82, 0xeb, 0x42, 0xfc, 0x8f, 0x2a, + 0xa3, 0x1a, 0x8d, 0x84, 0x28, 0x20, 0x16, 0x95, 0xd9, 0x66, 0x67, 0x2b, + 0xef, 0xc6, 0x6e, 0x56, 0x1c, 0x62, 0x74, 0x16, 0x5c, 0x3e, 0x17, 0xd0, + 0xb7, 0xdd, 0x70, 0xb6, 0x0e, 0x79, 0x46, 0xc5, 0x4e, 0x72, 0x46, 0x69, + 0xf5, 0xa1, 0x1c, 0x7b, 0xd5, 0x67, 0x5c, 0xb3, 0x46, 0x4d, 0x18, 0x31, + 0x47, 0x42, 0x20, 0xe6, 0x12, 0x84, 0x4e, 0x16, 0x0f, 0x4a, 0xd0, 0xc4, + 0x91, 0xa3, 0xbd, 0x91, 0xcd, 0x86, 0x4c, 0xcd, 0x4b, 0x2e, 0x62, 0x84, + 0xea, 0x19, 0x2d, 0x21, 0x1a, 0x64, 0xc4, 0xd2, 0x24, 0x92, 0x96, 0x04, + 0x66, 0xb5, 0x4a, 0xe4, 0xa9, 0xd6, 0xaf, 0x12, 0x9b, 0xb5, 0x59, 0xe0, + 0x5c, 0x84, 0x84, 0x7c, 0x68, 0x99, 0xd8, 0x23, 0xa2, 0x15, 0xa7, 0x82, + 0xa5, 0x66, 0x95, 0x8f, 0xfe, 0x57, 0xc1, 0x12, 0x6c, 0x89, 0xe5, 0x5b, + 0x5d, 0x64, 0xdb, 0x81, 0x4f, 0x77, 0x3c, 0xc8, 0x52, 0x4e, 0x2a, 0xd6, + 0x74, 0x3c, 0x4b, 0x11, 0xfc, 0xc1, 0x7c, 0x01, 0xba, 0x0f, 0x0f, 0x57, + 0x8a, 0xbe, 0x5b, 0x16, 0x88, 0x96, 0xe6, 0xe9, 0x60, 0xcf, 0x66, 0xe9, + 0xe6, 0x07, 0xb0, 0x0b, 0xa3, 0xa0, 0xad, 0xdf, 0x70, 0xd4, 0xcb, 0x2e, + 0x33, 0x2f, 0xe5, 0xf2, 0x1e, 0x0d, 0x74, 0x7a, 0xf9, 0x4a, 0x0f, 0x32, + 0xb4, 0xa1, 0xc9, 0xf5, 0x3f, 0x0a, 0x06, 0xf9, 0x67, 0x45, 0x9c, 0xd9, + 0x58, 0xd4, 0x0e, 0x72, 0x55, 0x47, 0x49, 0x9b, 0xab, 0x9c, 0x66, 0xe7, + 0x4d, 0x9a, 0x02, 0x1b, 0x41, 0xad, 0xe5, 0x8c, 0x7f, 0xa1, 0xdc, 0xad, + 0xcd, 0x74, 0xda, 0x9f, 0xfa, 0x87, 0x32, 0xc1, 0x07, 0x8e, 0x9b, 0xef, + 0x28, 0x2f, 0x17, 0x6d, 0xdb, 0x84, 0x4b, 0xa8, 0x7d, 0x31, 0xa8, 0x32, + 0xe4, 0x9a, 0x1e, 0x0e, 0xef, 0x68, 0xf4, 0xac, 0x03, 0x6c, 0x68, 0xcc, + 0x28, 0xbb, 0xfb, 0x21, 0xb8, 0x11, 0xd7, 0xf9, 0xe8, 0x24, 0x37, 0xdf, + 0xe0, 0xb2, 0xef, 0xd6, 0xec, 0xdf, 0xcf, 0xf5, 0x50, 0x19, 0xa3, 0xa9, + 0x1b, 0x01, 0x2e, 0x94, 0x42, 0xb0, 0x14, 0x5d, 0x0e, 0x37, 0x46, 0x4a, + 0x52, 0x53, 0x60, 0x6b, 0x89, 0xc9, 0xca, 0xed, 0x0a, 0x0c, 0x18, 0x33, + 0x3c, 0x40, 0x42, 0x76, 0x7a, 0x7d, 0xb6, 0x10, 0x29, 0x3e, 0x42, 0x75, + 0xa6, 0xbf, 0xcb, 0xd3, 0xdc, 0xe1, 0x00, 0x05, 0x08, 0x25, 0x67, 0x6c, + 0x72, 0xde, 0x26, 0x72, 0x88, 0xbe, 0xfa, 0x05, 0x57, 0x77, 0x78, 0x83, + 0xce, 0xd5, 0x44, 0x49, 0x8b, 0xab, 0xbc, 0xca, 0xd3, 0x1c, 0x34, 0x4a, + 0xaa, 0xc7, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x17, 0x22, 0x2a, 0x2f, 0x36, 0x3d, 0x43}; +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_KEYGEN_PCT */ +#endif /* !EXPECTED_SIGNATURES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/main.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/main.c new file mode 100644 index 0000000000..b62a3ef48e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/main.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include +#include +#include +#include + +/* Import public mldsa-native API + * + * This requires specifying the parameter set and namespace prefix + * used for the build. + */ +#include +#include "expected_signatures.h" +#include "test_only_rng/notrandombytes.h" + +#define CHECK(x) \ + do \ + { \ + int rc; \ + rc = (x); \ + if (!rc) \ + { \ + fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \ + return 1; \ + } \ + } while (0) + +#define TEST_MSG \ + "This is a test message for ML-DSA digital signature algorithm!" +#define TEST_MSG_LEN (sizeof(TEST_MSG) - 1) + +#define TEST_CTX "test_context_123" +#define TEST_CTX_LEN (sizeof(TEST_CTX) - 1) + +int main(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t sig[CRYPTO_BYTES]; + uint8_t sm[TEST_MSG_LEN + CRYPTO_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + CRYPTO_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-%d Custom Backend Example\n", MLD_CONFIG_PARAMETER_SET); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(crypto_sign_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(crypto_sign_signature(sig, &siglen, (const uint8_t *)test_msg, + TEST_MSG_LEN, (const uint8_t *)test_ctx, + TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(crypto_sign_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(crypto_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(crypto_sign_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", CRYPTO_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", CRYPTO_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", CRYPTO_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature)); + CHECK(memcmp(sig, expected_signature, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/mldsa_native.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/mldsa_native.h new file mode 100644 index 0000000000..fd150a9df1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/mldsa_native.h @@ -0,0 +1,975 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_H +#define MLD_H + +/* + * Public API for mldsa-native + * + * This header defines the public API of a single build of mldsa-native. + * + * Make sure the configuration file is in the include path + * (this is "mldsa_native_config.h" by default, or MLD_CONFIG_FILE if defined). + * + * # Multi-level builds + * + * This header specifies a build of mldsa-native for a fixed security level. + * If you need multiple security levels, leave the security level unspecified + * in the configuration file and include this header multiple times, setting + * MLD_CONFIG_PARAMETER_SET accordingly for each, and #undef'ing the MLD_H + * guard to allow multiple inclusions. + * + * # Legacy configuration (deprecated) + * + * Instead of providing the config file used for the build, you can + * alternatively set the following configuration options prior to + * including this header. + * + * This method of configuration is deprecated. + * It will be removed in mldsa-native-v2. + * + * - MLD_CONFIG_API_PARAMETER_SET [required] + * + * The parameter set used for the build; 44, 65, or 87. + * + * - MLD_CONFIG_API_NAMESPACE_PREFIX [required] + * + * The namespace prefix used for the build. + * + * NOTE: + * For a multi-level build, you must include the 44/65/87 suffixes + * in MLD_CONFIG_API_NAMESPACE_PREFIX. + * + * - MLD_CONFIG_API_NO_SUPERCOP [optional] + * + * By default, this header will also expose the mldsa-native API in the + * SUPERCOP naming convention crypto_sign_xxx. If you don't want/need this, + * set MLD_CONFIG_API_NO_SUPERCOP. You must set this for a multi-level build. + * + * - MLD_CONFIG_API_CONSTANTS_ONLY [optional] + * + * If you don't want this header to expose any function declarations, + * but only constants for the sizes of key material, set + * MLD_CONFIG_API_CONSTANTS_ONLY. In this case, you don't need to set + * MLD_CONFIG_API_PARAMETER_SET or MLD_CONFIG_API_NAMESPACE_PREFIX, + * nor include a configuration. + * + * - MLD_CONFIG_API_QUALIFIER [optional] + * + * Qualifier to apply to external API. + * + ******************************************************************************/ + +/******************************* Key sizes ************************************/ + +/* Sizes of cryptographic material, per parameter set */ +/* See mldsa/src/params.h for the arithmetic expressions giving rise to these */ +/* check-magic: off */ +#define MLDSA44_SECRETKEYBYTES 2560 +#define MLDSA44_PUBLICKEYBYTES 1312 +#define MLDSA44_BYTES 2420 + +#define MLDSA65_SECRETKEYBYTES 4032 +#define MLDSA65_PUBLICKEYBYTES 1952 +#define MLDSA65_BYTES 3309 + +#define MLDSA87_SECRETKEYBYTES 4896 +#define MLDSA87_PUBLICKEYBYTES 2592 +#define MLDSA87_BYTES 4627 +/* check-magic: on */ + +/* Size of seed and randomness in bytes (level-independent) */ +#define MLDSA_SEEDBYTES 32 +#define MLDSA44_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA65_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA87_SEEDBYTES MLDSA_SEEDBYTES + +/* Size of CRH output in bytes (level-independent) */ +#define MLDSA_CRHBYTES 64 +#define MLDSA44_CRHBYTES MLDSA_CRHBYTES +#define MLDSA65_CRHBYTES MLDSA_CRHBYTES +#define MLDSA87_CRHBYTES MLDSA_CRHBYTES + +/* Size of TR output in bytes (level-independent) */ +#define MLDSA_TRBYTES 64 +#define MLDSA44_TRBYTES MLDSA_TRBYTES +#define MLDSA65_TRBYTES MLDSA_TRBYTES +#define MLDSA87_TRBYTES MLDSA_TRBYTES + +/* Size of randomness for signing in bytes (level-independent) */ +#define MLDSA_RNDBYTES 32 +#define MLDSA44_RNDBYTES MLDSA_RNDBYTES +#define MLDSA65_RNDBYTES MLDSA_RNDBYTES +#define MLDSA87_RNDBYTES MLDSA_RNDBYTES + +/* Sizes of cryptographic material, as a function of LVL=44,65,87 */ +#define MLDSA_SECRETKEYBYTES_(LVL) MLDSA##LVL##_SECRETKEYBYTES +#define MLDSA_PUBLICKEYBYTES_(LVL) MLDSA##LVL##_PUBLICKEYBYTES +#define MLDSA_BYTES_(LVL) MLDSA##LVL##_BYTES +#define MLDSA_SECRETKEYBYTES(LVL) MLDSA_SECRETKEYBYTES_(LVL) +#define MLDSA_PUBLICKEYBYTES(LVL) MLDSA_PUBLICKEYBYTES_(LVL) +#define MLDSA_BYTES(LVL) MLDSA_BYTES_(LVL) + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + +/****************************** Function API **********************************/ + +#define MLD_API_CONCAT_(x, y) x##y +#define MLD_API_CONCAT(x, y) MLD_API_CONCAT_(x, y) +#define MLD_API_CONCAT_UNDERSCORE(x, y) MLD_API_CONCAT(MLD_API_CONCAT(x, _), y) + +#if !defined(MLD_CONFIG_API_PARAMETER_SET) +/* Recommended configuration via same config file as used for the build. */ + +/* For now, we derive the legacy API configuration MLD_CONFIG_API_XXX from + * the config file. In mldsa-native-v2, this will be removed and we will + * exclusively work with MLD_CONFIG_XXX. */ + +/* You need to make sure the config file is in the include path. */ +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#define MLD_CONFIG_API_PARAMETER_SET MLD_CONFIG_PARAMETER_SET + +#if defined(MLD_CONFIG_MULTILEVEL_BUILD) +#define MLD_CONFIG_API_NAMESPACE_PREFIX \ + MLD_API_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_CONFIG_API_NAMESPACE_PREFIX MLD_CONFIG_NAMESPACE_PREFIX +#endif + +#if defined(MLD_CONFIG_NO_SUPERCOP) +#define MLD_CONFIG_API_NO_SUPERCOP +#endif + +#if defined(MLD_CONFIG_CONSTANTS_ONLY) +#define MLD_CONFIG_API_CONSTANTS_ONLY +#endif + +#if defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_CONFIG_API_QUALIFIER MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#else /* !MLD_CONFIG_API_PARAMETER_SET */ +#define MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_PARAMETER_SET */ + +#define MLD_API_NAMESPACE(sym) \ + MLD_API_CONCAT_UNDERSCORE(MLD_CONFIG_API_NAMESPACE_PREFIX, sym) + +#if defined(__GNUC__) || defined(clang) +#define MLD_API_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_API_MUST_CHECK_RETURN_VALUE +#endif + +#if defined(MLD_CONFIG_API_QUALIFIER) +#define MLD_API_QUALIFIER MLD_CONFIG_API_QUALIFIER +#else +#define MLD_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_API_CONSTANTS_ONLY) + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************************* + * Name: crypto_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: + * input random seed + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair_internal)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t seed[MLDSA_SEEDBYTES] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: If MLD_CONFIG_KEYGEN_PCT is enabled and the + * PCT check failed. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return -1 in that case. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_extmu + * + * Description: Computes signature. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_extmu)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t *sm: pointer to output signed message (allocated array + * with MLDSA{44,65,87}_BYTES + mlen bytes), can be + * equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(sign)( + uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_extmu)( + const uint8_t *sig, size_t siglen, const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_open + * + * Description: Verify signed message. + * + * Arguments: + * - uint8_t *m: pointer to output message (allocated array with + * smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(open)( + uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: crypto_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *ph, size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_shake256)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_shake256)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/* Maximum formatted domain separation message length */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +size_t MLD_API_NAMESPACE(prepare_domain_separation_prefix)( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg); + +/************************************************* + * Name: crypto_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[CRYPTO_SECRETKEYBYTES]: input secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(pk_from_sk)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +#ifdef __cplusplus +} +#endif + +/****************************** SUPERCOP API *********************************/ + +#if !defined(MLD_CONFIG_API_NO_SUPERCOP) +/* Export API in SUPERCOP naming scheme CRYPTO_xxx / crypto_sign_xxx */ +#define CRYPTO_SECRETKEYBYTES MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_PUBLICKEYBYTES MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_BYTES MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET) + +#define crypto_sign_keypair MLD_API_NAMESPACE(keypair) +#define crypto_sign_signature MLD_API_NAMESPACE(signature) +#define crypto_sign MLD_API_NAMESPACE(sign) +#define crypto_sign_verify MLD_API_NAMESPACE(verify) +#define crypto_sign_open MLD_API_NAMESPACE(open) + +#else /* !MLD_CONFIG_API_NO_SUPERCOP */ + +/* If the SUPERCOP API is not needed, we can undefine the various helper macros + * above. Otherwise, they are needed for lazy evaluation of crypto_sign_xxx. */ +#if !defined(MLD_API_LEGACY_CONFIG) +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_QUALIFIER +#endif /* !MLD_API_LEGACY_CONFIG */ + +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_NAMESPACE +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_QUALIFIER +#undef MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_NO_SUPERCOP */ +#endif /* !MLD_CONFIG_API_CONSTANTS_ONLY */ + + +/***************************** Memory Usage **********************************/ + +/* + * By default mldsa-native performs all memory allocations on the stack. + * Alternatively, mldsa-native supports custom allocation of large structures + * through the `MLD_CONFIG_CUSTOM_ALLOC_FREE` configuration option. + * See mldsa_native_config.h for details. + * + * `MLD_TOTAL_ALLOC_{44,65,87}_{KEYPAIR,SIGN,VERIFY}` indicates the maximum + * (accumulative) allocation via MLD_ALLOC for each parameter set and operation. + * Note that some stack allocation remains even + * when using custom allocators, so these values are lower than total stack + * usage with the default stack-only allocation. + * + * These constants may be used to implement custom allocations using a + * fixed-sized buffer and a simple allocator (e.g., bump allocator). + */ +/* check-magic: off */ +#if defined(MLD_API_LEGACY_CONFIG) || !defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 45248 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 56640 +#define MLD_TOTAL_ALLOC_44_SIGN 52896 +#define MLD_TOTAL_ALLOC_44_VERIFY 38816 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 71872 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 85856 +#define MLD_TOTAL_ALLOC_65_SIGN 80576 +#define MLD_TOTAL_ALLOC_65_VERIFY 62432 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 112832 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 130816 +#define MLD_TOTAL_ALLOC_87_SIGN 123584 +#define MLD_TOTAL_ALLOC_87_VERIFY 99552 +#else /* MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM */ +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 32992 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 36192 +#define MLD_TOTAL_ALLOC_44_SIGN 32448 +#define MLD_TOTAL_ALLOC_44_VERIFY 22464 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 46304 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 50048 +#define MLD_TOTAL_ALLOC_65_SIGN 44768 +#define MLD_TOTAL_ALLOC_65_VERIFY 30720 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 62688 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 66336 +#define MLD_TOTAL_ALLOC_87_SIGN 59104 +#define MLD_TOTAL_ALLOC_87_VERIFY 41216 +#endif /* !(MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM) */ +/* check-magic: on */ + +/* + * MLD_TOTAL_ALLOC_*_KEYPAIR adapts based on MLD_CONFIG_KEYGEN_PCT. + * For legacy config, we don't know which options are used, so assume + * the worst case (PCT enabled). + */ +#if defined(MLD_API_LEGACY_CONFIG) || defined(MLD_CONFIG_KEYGEN_PCT) +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#else +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#endif + +#define MLD_MAX3_(a, b, c) \ + ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c))) + +/* + * `MLD_TOTAL_ALLOC_{44,65,87}` is the maximum across all operations for each + * parameter set. + */ +#define MLD_TOTAL_ALLOC_44 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_44_KEYPAIR, MLD_TOTAL_ALLOC_44_SIGN, \ + MLD_TOTAL_ALLOC_44_VERIFY) +#define MLD_TOTAL_ALLOC_65 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_65_KEYPAIR, MLD_TOTAL_ALLOC_65_SIGN, \ + MLD_TOTAL_ALLOC_65_VERIFY) +#define MLD_TOTAL_ALLOC_87 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_87_KEYPAIR, MLD_TOTAL_ALLOC_87_SIGN, \ + MLD_TOTAL_ALLOC_87_VERIFY) + +#endif /* !MLD_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/mldsa_native_config.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/mldsa_native_config.h new file mode 100644 index 0000000000..1ca99a0f2f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/mldsa_native_config.h @@ -0,0 +1,735 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/* + * Test configuration: Custom backend config with tiny SHA3 + * + * This configuration differs from the default mldsa/mldsa_native_config.h in + * the following places: + * - MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * - MLD_CONFIG_NAMESPACE_PREFIX + * - MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * - MLD_CONFIG_FIPS202_BACKEND_FILE + */ + + +#ifndef MLD_CONFIG_H +#define MLD_CONFIG_H + +/****************************************************************************** + * Name: MLD_CONFIG_PARAMETER_SET + * + * Description: Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * If you want to support multiple parameter sets, build the + * library multiple times and set MLD_CONFIG_MULTILEVEL_BUILD. + * See MLD_CONFIG_MULTILEVEL_BUILD for how to do this while + * minimizing code duplication. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* This is set on the command line */ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of the default configuration file mldsa/mldsa_native_config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * then configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + * + *****************************************************************************/ +/* No need to set this -- we _are_ already in a custom config */ +/* #define MLD_CONFIG_FILE "mldsa_native_config.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_NAMESPACE_PREFIX + * + * Description: The prefix to use to namespace global symbols from mldsa/. + * + * In a multi-level build, level-dependent symbols will + * additionally be prefixed with the parameter set (44/65/87). + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_NAMESPACE_PREFIX CUSTOM_TINY_SHA3 + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_BUILD + * + * Description: Set this if the build is part of a multi-level build supporting + * multiple parameter sets. + * + * If you need only a single parameter set, keep this unset. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them. + * + * See examples/multilevel_build for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_BUILD */ + +/****************************************************************************** + * Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_EXTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_RANDOMIZED_API + * + * Description: If this option is set, mldsa-native will be built without the + * randomized API functions (crypto_sign_keypair, + * crypto_sign, crypto_sign_signature, and + * crypto_sign_signature_extmu). + * This allows users to build mldsa-native without providing a + * randombytes() implementation if they only need the + * internal deterministic API + * (crypto_sign_keypair_internal, crypto_sign_signature_internal). + * + * NOTE: This option is incompatible with MLD_CONFIG_KEYGEN_PCT + * as the current PCT implementation requires + * crypto_sign_signature(). + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_RANDOMIZED_API */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_SUPERCOP + * + * Description: By default, mldsa_native.h exposes the mldsa-native API in the + * SUPERCOP naming convention (crypto_sign_xxx). If you don't need + * this, set MLD_CONFIG_NO_SUPERCOP. + * + * NOTE: You must set this for a multi-level build as the SUPERCOP + * naming does not disambiguate between the parameter sets. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_SUPERCOP */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONSTANTS_ONLY + * + * Description: If you only need the size constants (MLDSA_PUBLICKEYBYTES, etc.) + * but no function declarations, set MLD_CONFIG_CONSTANTS_ONLY. + * + * This only affects the public header mldsa_native.h, not + * the implementation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONSTANTS_ONLY */ + +/****************************************************************************** + * + * Build-only configuration options + * + * The remaining configurations are build-options only. + * They do not affect the API described in mldsa_native.h. + * + *****************************************************************************/ + +#if defined(MLD_BUILD_INTERNAL) +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_WITH_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, all MLD_CONFIG_PARAMETER_SET-independent + * code will be included in the build, including code needed only + * for other parameter sets. + * + * Example: TODO: add example + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_WITH_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_NO_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, no MLD_CONFIG_PARAMETER_SET-independent code + * will be included in the build. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * + * Description: This is only relevant for single compilation unit (SCU) + * builds of mldsa-native. In this case, it determines whether + * directives defined in parameter-set-independent headers should + * be #undef'ined or not at the of the SCU file. This is needed + * in multilevel builds. + * + * See examples/multilevel_build_native for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * + * Description: Determines whether an native arithmetic backend should be used. + * + * The arithmetic backend covers performance critical functions + * such as the number-theoretic transform (NTT). + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the arithmetic backend to be use is + * determined by MLD_CONFIG_ARITH_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* No native arithmetic backend */ +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +/****************************************************************************** + * Name: MLD_CONFIG_ARITH_BACKEND_FILE + * + * Description: The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * + * Description: Determines whether an native FIPS202 backend should be used. + * + * The FIPS202 backend covers 1x/2x/4x-fold Keccak-f1600, which is + * the performance bottleneck of SHA3 and SHAKE. + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the FIPS202 backend to be use is + * determined by MLD_CONFIG_FIPS202_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_BACKEND_FILE + * + * Description: The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/custom/custom.h" + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202X4_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202-X4 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202x4.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ZEROIZE + * + * Description: In compliance with @[FIPS204, Section 3.6.3], mldsa-native, + * zeroizes intermediate stack buffers before returning from + * function calls. + * + * Set this option and define `mld_zeroize` if you want to + * use a custom method to zeroize intermediate stack buffers. + * The default implementation uses SecureZeroMemory on Windows + * and a memset + compiler barrier otherwise. If neither of those + * is available on the target platform, compilation will fail, + * and you will need to use MLD_CONFIG_CUSTOM_ZEROIZE to provide + * a custom implementation of `mld_zeroize()`. + * + * WARNING: + * The explicit stack zeroization conducted by mldsa-native + * reduces the likelihood of data leaking on the stack, but + * does not eliminate it! The C standard makes no guarantee about + * where a compiler allocates structures and whether/where it makes + * copies of them. Also, in addition to entire structures, there + * may also be potentially exploitable leakage of individual values + * on the stack. + * + * If you need bullet-proof zeroization of the stack, you need to + * consider additional measures instead of what this feature + * provides. In this case, you can set mld_zeroize to a + * no-op. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void mld_zeroize(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * Description: mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to provided by the + * consumer. + * + * If this option is not set, mldsa-native expects a function + * int randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mld_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_RANDOMBYTES + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) + { + ... your implementation ... + return 0; + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + * + * Description: mldsa-native backends may rely on specific hardware features. + * Those backends will only be included in an mldsa-native build + * if support for the respective features is enabled at + * compile-time. However, when building for a heteroneous set + * of CPUs to run the resulting binary/library on, feature + * detection at _runtime_ is needed to decided whether a backend + * can be used or not. + * + * Set this option and define `mld_sys_check_capability` if you + * want to use a custom method to dispatch between implementations. + * + * Return value 1 indicates that a capability is supported. + * Return value 0 indicates that a capability is not supported. + * + * If this option is not set, mldsa-native uses compile-time + * feature detection only to decide which backend to use. + * + * If you compile mldsa-native on a system with different + * capabilities than the system that the resulting binary/library + * will be run on, you must use this option. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) + { + ... your implementation ... + } +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ALLOC_FREE [EXPERIMENTAL] + * + * Description: Set this option and define `MLD_CUSTOM_ALLOC` and + * `MLD_CUSTOM_FREE` if you want to use custom allocation for + * large local structures or buffers. + * + * By default, all buffers/structures are allocated on the stack. + * If this option is set, most of them will be allocated via + * MLD_CUSTOM_ALLOC. + * + * Parameters to MLD_CUSTOM_ALLOC: + * - T* v: Target pointer to declare. + * - T: Type of structure to be allocated + * - N: Number of elements to be allocated. + * + * Parameters to MLD_CUSTOM_FREE: + * - T* v: Target pointer to free. May be NULL. + * - T: Type of structure to be freed. + * - N: Number of elements to be freed. + * + * WARNING: This option is experimental! + * Its scope, configuration and function/macro signatures may + * change at any time. We expect a stable API for v2. + * + * NOTE: Even if this option is set, some allocations further down + * the call stack will still be made from the stack. Those will + * likely be added to the scope of this option in the future. + * + * NOTE: MLD_CUSTOM_ALLOC need not guarantee a successful + * allocation nor include error handling. Upon failure, the + * target pointer should simply be set to NULL. The calling + * code will handle this case and invoke MLD_CUSTOM_FREE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ALLOC_FREE + #if !defined(__ASSEMBLER__) + #include + #define MLD_CUSTOM_ALLOC(v, T, N) \ + T* (v) = (T *)aligned_alloc(MLD_DEFAULT_ALIGN, \ + MLD_ALIGN_UP(sizeof(T) * (N))) + #define MLD_CUSTOM_FREE(v, T, N) free(v) + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMCPY + * + * Description: Set this option and define `mld_memcpy` if you want to + * use a custom method to copy memory instead of the standard + * library memcpy function. + * + * The custom implementation must have the same signature and + * behavior as the standard memcpy function: + * void *mld_memcpy(void *dest, const void *src, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMCPY + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMSET + * + * Description: Set this option and define `mld_memset` if you want to + * use a custom method to set memory instead of the standard + * library memset function. + * + * The custom implementation must have the same signature and + * behavior as the standard memset function: + * void *mld_memset(void *s, int c, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMSET + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memset(void *s, int c, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_INTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of internal API. + * + * The primary use case for this option are single-CU builds, + * in which case this option can be set to `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_INTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CT_TESTING_ENABLED + * + * Description: If set, mldsa-native annotates data as secret / public using + * valgrind's annotations VALGRIND_MAKE_MEM_UNDEFINED and + * VALGRIND_MAKE_MEM_DEFINED, enabling various checks for secret- + * dependent control flow of variable time execution (depending + * on the exact version of valgrind installed). + * + *****************************************************************************/ +/* #define MLD_CONFIG_CT_TESTING_ENABLED */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * and MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT + * + * Description: Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, crypto_sign_keypair_internal and + * crypto_sign_keypair will return a non-zero error code if the + * PCT failed. + * + * NOTE: This feature will drastically lower the performance of + * key generation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * Description: If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "src/src.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Description: Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * NOTE: Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + * + *****************************************************************************/ +/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER + * + * Description: Set this to add a context parameter that is provided to public + * API functions and is then available in custom callbacks. + * + * The type of the context parameter is configured via + * MLD_CONFIG_CONTEXT_PARAMETER_TYPE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER_TYPE + * + * Description: Set this to define the type for the context parameter used by + * MLD_CONFIG_CONTEXT_PARAMETER. + * + * This is only relevant if MLD_CONFIG_CONTEXT_PARAMETER is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER_TYPE void* */ + +/****************************************************************************** + * Name: MLD_CONFIG_REDUCE_RAM [EXPERIMENTAL] + * + * Description: Set this to reduce RAM usage. + * This trades memory for performance. + * + * For expected memory usage, see the MLD_TOTAL_ALLOC_* constants + * defined in mldsa_native.h. + * + * This option is useful for embedded systems with tight RAM + * constraints but relaxed performance requirements. + * + * WARNING: This option is experimental! + * CBMC proofs do not currently cover this configuration option. + * Its scope and configuration may change at any time. + * + *****************************************************************************/ +/* #define MLD_CONFIG_REDUCE_RAM */ + +/************************* Config internals ********************************/ + +#endif /* MLD_BUILD_INTERNAL */ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace is + * + * PQCP_MLDSA_NATIVE_MLDSA_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_ + */ + +#if MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65 +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87 +#endif + +#endif /* !MLD_CONFIG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/cbmc.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/cbmc.h new file mode 100644 index 0000000000..8ed1ecb06b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/cbmc.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_CBMC_H +#define MLD_CBMC_H +/*************************************************** + * Basic replacements for __CPROVER_XXX contracts + ***************************************************/ +#ifndef CBMC + +#define __contract__(x) +#define __loop__(x) +#define cassert(x) + +#else /* !CBMC */ + +#include + +#define __contract__(x) x +#define __loop__(x) x + +/* https://diffblue.github.io/cbmc/contracts-assigns.html */ +#define assigns(...) __CPROVER_assigns(__VA_ARGS__) + +/* https://diffblue.github.io/cbmc/contracts-requires-ensures.html */ +#define requires(...) __CPROVER_requires(__VA_ARGS__) +#define ensures(...) __CPROVER_ensures(__VA_ARGS__) +/* https://diffblue.github.io/cbmc/contracts-loops.html */ +#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__) +#define decreases(...) __CPROVER_decreases(__VA_ARGS__) +/* cassert to avoid confusion with in-built assert */ +#define cassert(x) __CPROVER_assert(x, "cbmc assertion failed") +#define assume(...) __CPROVER_assume(__VA_ARGS__) + +/*************************************************** + * Macros for "expression" forms that may appear + * _inside_ top-level contracts. + ***************************************************/ + +/* + * function return value - useful inside ensures + * https://diffblue.github.io/cbmc/contracts-functions.html + */ +#define return_value (__CPROVER_return_value) + +/* + * assigns l-value targets + * https://diffblue.github.io/cbmc/contracts-assigns.html + */ +#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__) +#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__) +#define same_object(...) __CPROVER_same_object(__VA_ARGS__) + +/* + * Pointer-related predicates + * https://diffblue.github.io/cbmc/contracts-memory-predicates.html + */ +#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__) +#define readable(...) __CPROVER_r_ok(__VA_ARGS__) +#define writeable(...) __CPROVER_w_ok(__VA_ARGS__) + +/* Maximum supported buffer size + * + * Larger buffers may be supported, but due to internal modeling constraints + * in CBMC, the proofs of memory- and type-safety won't be able to run. + * + * If you find yourself in need for a buffer size larger than this, + * please contact the maintainers, so we can prioritize work to relax + * this somewhat artificial bound. + */ +#define MLD_MAX_BUFFER_SIZE (SIZE_MAX >> 12) + + +/* + * History variables + * https://diffblue.github.io/cbmc/contracts-history-variables.html + */ +#define old(...) __CPROVER_old(__VA_ARGS__) +#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__) + +/* + * Quantifiers + * Note that the range on qvar is _exclusive_ between qvar_lb .. qvar_ub + * https://diffblue.github.io/cbmc/contracts-quantifiers.html + */ + +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define forall(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> (predicate) \ + } + +#define exists(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_exists \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) && (predicate) \ + } +/* clang-format on */ + +/*************************************************** + * Convenience macros for common contract patterns + ***************************************************/ +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define CBMC_CONCAT_(left, right) left##right +#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right) + +#define array_bound_core(qvar, qvar_lb, qvar_ub, array_var, \ + value_lb, value_ub) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + (((int)(value_lb) <= ((array_var)[(qvar)])) && \ + (((array_var)[(qvar)]) < (int)(value_ub))) \ + } + +#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \ + array_bound_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (qvar_lb), \ + (qvar_ub), (array_var), (value_lb), (value_ub)) + +#define array_unchanged_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (int32_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged(array_var, N) \ + array_unchanged_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) + +#define array_unchanged_u64_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (uint64_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged_u64(array_var, N) \ + array_unchanged_u64_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) +/* clang-format on */ + +/* Wrapper around array_bound operating on absolute values. + * + * The absolute value bound `k` is exclusive. + * + * Note that since the lower bound in array_bound is inclusive, we have to + * raise it by 1 here. + */ +#define array_abs_bound(arr, lb, ub, k) \ + array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k)) + +#endif /* CBMC */ + +#endif /* !MLD_CBMC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/common.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/common.h new file mode 100644 index 0000000000..4a5bc8109d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/common.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_COMMON_H +#define MLD_COMMON_H + +#define MLD_BUILD_INTERNAL + +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#include "params.h" +#include "sys.h" + +/* Internal and public API have external linkage by default, but + * this can be overwritten by the user, e.g. for single-CU builds. */ +#if !defined(MLD_CONFIG_INTERNAL_API_QUALIFIER) +#define MLD_INTERNAL_API +#else +#define MLD_INTERNAL_API MLD_CONFIG_INTERNAL_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_EXTERNAL_API +#else +#define MLD_EXTERNAL_API MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#if defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) || \ + defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) +#define MLD_MULTILEVEL_BUILD +#endif + +#define MLD_CONCAT_(x1, x2) x1##x2 +#define MLD_CONCAT(x1, x2) MLD_CONCAT_(x1, x2) + +#if defined(MLD_MULTILEVEL_BUILD) +#define MLD_ADD_PARAM_SET(s) MLD_CONCAT(s, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_ADD_PARAM_SET(s) s +#endif + +#define MLD_NAMESPACE_PREFIX MLD_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, _) +#define MLD_NAMESPACE_PREFIX_KL \ + MLD_CONCAT(MLD_ADD_PARAM_SET(MLD_CONFIG_NAMESPACE_PREFIX), _) + +/* Functions are prefixed by MLD_CONFIG_NAMESPACE_PREFIX. + * + * If multiple parameter sets are used, functions depending on the parameter + * set are additionally prefixed with 44/65/87. See mldsa_native_config.h. + * + * Example: If MLD_CONFIG_NAMESPACE_PREFIX is PQCP_MLDSA_NATIVE, then + * MLD_NAMESPACE_KL(keypair) becomes PQCP_MLDSA_NATIVE44_keypair/ + * PQCP_MLDSA_NATIVE65_keypair/PQCP_MLDSA_NATIVE87_keypair. + */ +#define MLD_NAMESPACE(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX, s) +#define MLD_NAMESPACE_KL(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX_KL, s) + +/* On Apple platforms, we need to emit leading underscore + * in front of assembly symbols. We thus introducee a separate + * namespace wrapper for ASM symbols. */ +#if !defined(__APPLE__) +#define MLD_ASM_NAMESPACE(sym) MLD_NAMESPACE(sym) +#else +#define MLD_ASM_NAMESPACE(sym) MLD_CONCAT(_, MLD_NAMESPACE(sym)) +#endif + +/* + * On X86_64 if control-flow protections (CET) are enabled (through + * -fcf-protection=), we add an endbr64 instruction at every global function + * label. See sys.h for more details + */ +#if defined(MLD_SYS_X86_64) +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : MLD_CET_ENDBR +#else +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : +#endif + +/* We aim to simplify the user's life by supporting builds where + * all source files are included, even those that are not needed. + * Those files are appropriately guarded and will be empty when unneeded. + * The following is to avoid compilers complaining about this. */ +#define MLD_EMPTY_CU(s) extern int MLD_NAMESPACE_KL(empty_cu_##s); + +/* MLD_CONFIG_NO_ASM takes precedence over MLD_USE_NATIVE_XXX */ +#if defined(MLD_CONFIG_NO_ASM) +#undef MLD_CONFIG_USE_NATIVE_BACKEND_ARITH +#undef MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, but MLD_CONFIG_ARITH_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, but MLD_CONFIG_FIPS202_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_NO_RANDOMIZED_API) && defined(MLD_CONFIG_KEYGEN_PCT) +#error Bad configuration: MLD_CONFIG_NO_RANDOMIZED_API is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires crypto_sign_signature() +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#include MLD_CONFIG_ARITH_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#include MLD_CONFIG_FIPS202_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "fips202/native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#define MLD_FIPS202_HEADER_FILE "fips202/fips202.h" +#else +#define MLD_FIPS202_HEADER_FILE MLD_CONFIG_FIPS202_CUSTOM_HEADER +#endif + +#if !defined(MLD_CONFIG_FIPS202X4_CUSTOM_HEADER) +#define MLD_FIPS202X4_HEADER_FILE "fips202/fips202x4.h" +#else +#define MLD_FIPS202X4_HEADER_FILE MLD_CONFIG_FIPS202X4_CUSTOM_HEADER +#endif + +/* Standard library function replacements */ +#if !defined(__ASSEMBLER__) +#if !defined(MLD_CONFIG_CUSTOM_MEMCPY) +#include +#define mld_memcpy memcpy +#endif + +#if !defined(MLD_CONFIG_CUSTOM_MEMSET) +#include +#define mld_memset memset +#endif + +/* Allocation macros for large local structures + * + * MLD_ALLOC(v, T, N) declares T *v and attempts to point it to an T[N] + * MLD_FREE(v, T, N) zeroizes and frees the allocation + * + * Default implementation uses stack allocation. + * Can be overridden by setting the config option MLD_CONFIG_CUSTOM_ALLOC_FREE + * and defining MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE. + */ +#if defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) != \ + (defined(MLD_CUSTOM_ALLOC) && defined(MLD_CUSTOM_FREE)) +#error Bad configuration: MLD_CONFIG_CUSTOM_ALLOC_FREE must be set together with MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE +#endif + +/* + * If the integration wants to provide a context parameter for use in + * platform-specific hooks, then it should define this parameter. + * + * The MLD_CONTEXT_PARAMETERS_n macros are intended to be used with macros + * defining the function names and expand to either pass or discard the context + * argument as required by the current build. If there is no context parameter + * requested then these are removed from the prototypes and from all calls. + */ +#ifdef MLD_CONFIG_CONTEXT_PARAMETER +#define MLD_CONTEXT_PARAMETERS_0(context) (context) +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0, context) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1, context) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) \ + (arg0, arg1, arg2, context) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3, context) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4, context) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, context) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, context) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, context) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, context) +#else /* MLD_CONFIG_CONTEXT_PARAMETER */ +#define MLD_CONTEXT_PARAMETERS_0(context) () +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) (arg0, arg1, arg2) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) +#endif /* !MLD_CONFIG_CONTEXT_PARAMETER */ + +#if defined(MLD_CONFIG_CONTEXT_PARAMETER_TYPE) != \ + defined(MLD_CONFIG_CONTEXT_PARAMETER) +#error MLD_CONFIG_CONTEXT_PARAMETER_TYPE must be defined if and only if MLD_CONFIG_CONTEXT_PARAMETER is defined +#endif + +#if !defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) +/* Default: stack allocation */ + +#define MLD_ALLOC(v, T, N, context) \ + MLD_ALIGN T mld_alloc_##v[N]; \ + T *v = mld_alloc_##v + +/* TODO: This leads to a circular dependency between common and ct.h + * It just works out before we're at the end of the file, but it's still + * prone to issues in the future. */ +#include "ct.h" +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + mld_zeroize(mld_alloc_##v, sizeof(mld_alloc_##v)); \ + (v) = NULL; \ + } while (0) + +#else /* !MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* Custom allocation */ + +/* + * The indirection here is necessary to use MLD_CONTEXT_PARAMETERS_3 here. + */ +#define MLD_APPLY(f, args) f args + +#define MLD_ALLOC(v, T, N, context) \ + MLD_APPLY(MLD_CUSTOM_ALLOC, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)) + +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + if (v != NULL) \ + { \ + mld_zeroize(v, sizeof(T) * (N)); \ + MLD_APPLY(MLD_CUSTOM_FREE, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)); \ + v = NULL; \ + } \ + } while (0) + +#endif /* MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* + * We are facing severe CBMC performance issues when using unions. + * As a temporary workaround, we use unions only when MLD_CONFIG_REDUCE_RAM is + * set. + * TODO: Remove the workaround once + * https://github.com/diffblue/cbmc/issues/8813 + * is resolved + */ +#if defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_UNION_OR_STRUCT union +#else +#define MLD_UNION_OR_STRUCT struct +#endif + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_COMMON_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/ct.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/ct.c new file mode 100644 index 0000000000..010b1a52a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/ct.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include "ct.h" + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +/* + * Masking value used in constant-time functions from + * ct.h to block the compiler's range analysis and + * thereby reduce the risk of compiler-introduced branches. + */ +volatile uint64_t mld_ct_opt_blocker_u64 = 0; + +#else /* !MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(ct) + +#endif /* !(!MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/ct.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/ct.h new file mode 100644 index 0000000000..c307456468 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/ct.h @@ -0,0 +1,366 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [libmceliece] + * libmceliece implementation of Classic McEliece + * Bernstein, Chou + * https://lib.mceliece.org/ + * + * - [optblocker] + * PQC forum post on opt-blockers using volatile globals + * Daniel J. Bernstein + * https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ + */ + +#ifndef MLD_CT_H +#define MLD_CT_H + +#include +#include "cbmc.h" +#include "common.h" + +/* Constant-time comparisons and conditional operations + + We reduce the risk for compilation into variable-time code + through the use of 'value barriers'. + + Functionally, a value barrier is a no-op. To the compiler, however, + it constitutes an arbitrary modification of its input, and therefore + harden's value propagation and range analysis. + + We consider two approaches to implement a value barrier: + - An empty inline asm block which marks the target value as clobbered. + - XOR'ing with the value of a volatile global that's set to 0; + see @[optblocker] for a discussion of this idea, and + @[libmceliece, inttypes/crypto_intN.h] for an implementation. + + The first approach is cheap because it only prevents the compiler + from reasoning about the value of the variable past the barrier, + but does not directly generate additional instructions. + + The second approach generates redundant loads and XOR operations + and therefore comes at a higher runtime cost. However, it appears + more robust towards optimization, as compilers should never drop + a volatile load. + + We use the empty-ASM value barrier for GCC and clang, and fall + back to the global volatile barrier otherwise. + + The global value barrier can be forced by setting + MLD_CONFIG_NO_ASM_VALUE_BARRIER. + +*/ + +#if defined(MLD_HAVE_INLINE_ASM) && !defined(MLD_CONFIG_NO_ASM_VALUE_BARRIER) +#define MLD_USE_ASM_VALUE_BARRIER +#endif + + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) +/* + * Declaration of global volatile that the global value barrier + * is loading from and masking with. + */ +#define mld_ct_opt_blocker_u64 MLD_NAMESPACE(ct_opt_blocker_u64) +extern volatile uint64_t mld_ct_opt_blocker_u64; + + +/* Helper functions for obtaining global masks of various sizes */ + +/* This contract is not proved but treated as an axiom. + * + * Its validity relies on the assumption that the global opt-blocker + * constant mld_ct_opt_blocker_u64 is not modified. + */ +static MLD_INLINE uint64_t mld_ct_get_optblocker_u64(void) +__contract__(ensures(return_value == 0)) { return mld_ct_opt_blocker_u64; } + +static MLD_INLINE int64_t mld_ct_get_optblocker_i64(void) +__contract__(ensures(return_value == 0)) { return (int64_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint32_t mld_ct_get_optblocker_u32(void) +__contract__(ensures(return_value == 0)) { return (uint32_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint8_t mld_ct_get_optblocker_u8(void) +__contract__(ensures(return_value == 0)) { return (uint8_t)mld_ct_get_optblocker_u64(); } + +/* Opt-blocker based implementation of value barriers */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_i64()); } + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u32()); } + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u8()); } + + +#else /* !MLD_USE_ASM_VALUE_BARRIER */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} +#endif /* MLD_USE_ASM_VALUE_BARRIER */ + +#ifdef CBMC +#pragma CPROVER check push +#pragma CPROVER check disable "conversion" +#endif + +/************************************************* + * Name: mld_cast_uint32_to_int32 + * + * Description: Cast uint32 value to int32 + * + * Returns: For uint32_t x, the unique y in int32_t + * so that x == y mod 2^32. + * + * Concretely: + * - x < 2^31: returns x + * - x >= 2^31: returns x - 2^31 + * + **************************************************/ +static MLD_ALWAYS_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x) +{ + /* + * PORTABILITY: This relies on uint32_t -> int32_t + * being implemented as the inverse of int32_t -> uint32_t, + * which is implementation-defined (C99 6.3.1.3 (3)) + * CBMC (correctly) fails to prove this conversion is OK, + * so we have to suppress that check here + */ + return (int32_t)x; +} + +#ifdef CBMC +#pragma CPROVER check pop +#endif + + +/************************************************* + * Name: mld_cast_int64_to_uint32 + * + * Description: Cast int64 value to uint32 as per C standard. + * + * Returns: For int64_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int64_to_uint32(int64_t x) +{ + return (uint32_t)(x & (int64_t)UINT32_MAX); +} + +/************************************************* + * Name: mld_cast_int32_to_uint32 + * + * Description: Cast int32 value to uint32 as per C standard. + * + * Returns: For int32_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int32_to_uint32(int32_t x) +{ + return mld_cast_int64_to_uint32((int64_t)x); +} + +/************************************************* + * Name: mld_ct_sel_int32 + * + * Description: Functionally equivalent to cond ? a : b, + * but implemented with guards against + * compiler-introduced branches. + * + * Arguments: int32_t a: First alternative + * int32_t b: Second alternative + * uint32_t cond: Condition variable. + * + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_sel_int32(int32_t a, int32_t b, uint32_t cond) +__contract__( + requires(cond == 0x0 || cond == 0xFFFFFFFF) + ensures(return_value == (cond ? a : b)) +) +{ + uint32_t au = mld_cast_int32_to_uint32(a); + uint32_t bu = mld_cast_int32_to_uint32(b); + uint32_t res = bu ^ (mld_value_barrier_u32(cond) & (au ^ bu)); + return mld_cast_uint32_to_int32(res); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u32 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_nonzero_u32(uint32_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFFFFFFFF))) +{ + int64_t tmp = mld_value_barrier_i64(-((int64_t)x)); + tmp >>= 32; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u8 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint8_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint8_t mld_ct_cmask_nonzero_u8(uint8_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFF))) +{ + uint32_t mask = mld_ct_cmask_nonzero_u32((uint32_t)x); + return (uint8_t)(mask & 0xFF); +} + +/************************************************* + * Name: mld_ct_cmask_neg_i32 + * + * Description: Return 0 if input is non-negative, and -1 otherwise. + * + * Arguments: int32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_neg_i32(int32_t x) +__contract__( + ensures(return_value == ((x < 0) ? 0xFFFFFFFF : 0)) +) +{ + int64_t tmp = mld_value_barrier_i64((int64_t)x); + tmp >>= 31; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_abs_i32 + * + * Description: Return -x if x<0, x otherwise + * + * Arguments: int32_t x: Input value + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_abs_i32(int32_t x) +__contract__( + requires(x >= -INT32_MAX) + ensures(return_value == ((x < 0) ? -x : x)) +) +{ + return mld_ct_sel_int32(-x, x, mld_ct_cmask_neg_i32(x)); +} + +/************************************************* + * Name: mld_ct_memcmp + * + * Description: Compare two arrays for equality in constant time. + * + * Arguments: const uint8_t *a: pointer to first byte array + * const uint8_t *b: pointer to second byte array + * size_t len: length of the byte arrays, upper-bounded + * to UINT16_MAX to control proof complexity + * only. + * + * Returns 0 if the byte arrays are equal, 0xFF otherwise. + **************************************************/ +static MLD_INLINE uint8_t mld_ct_memcmp(const uint8_t *a, const uint8_t *b, + const size_t len) +__contract__( + requires(len <= UINT16_MAX) + requires(memory_no_alias(a, len)) + requires(memory_no_alias(b, len)) + ensures((return_value == 0) || (return_value == 0xFF)) + ensures((return_value == 0) == forall(i, 0, len, (a[i] == b[i])))) +{ + uint8_t r = 0, s = 0; + unsigned i; + + for (i = 0; i < len; i++) + __loop__( + invariant(i <= len) + invariant((r == 0) == (forall(k, 0, i, (a[k] == b[k]))))) + { + r |= a[i] ^ b[i]; + /* s is useless, but prevents the loop from being aborted once r=0xff. */ + s ^= a[i] ^ b[i]; + } + + /* + * - Convert r into a mask; this may not be necessary, but is an additional + * safeguard + * towards leaking information about a and b. + * - XOR twice with s, separated by a value barrier, to prevent the compile + * from dropping the s computation in the loop. + */ + return (mld_value_barrier_u8(mld_ct_cmask_nonzero_u8(r) ^ s) ^ s); +} + +/************************************************* + * Name: mld_zeroize + * + * Description: Force-zeroize a buffer. + * @[FIPS204, Section 3.6.3] Destruction of intermediate + * values. + * + * Arguments: void *ptr: pointer to buffer to be zeroed + * size_t len: Amount of bytes to be zeroed + **************************************************/ +#if !defined(MLD_CONFIG_CUSTOM_ZEROIZE) +#if defined(MLD_SYS_WINDOWS) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) { SecureZeroMemory(ptr, len); } +#elif defined(MLD_HAVE_INLINE_ASM) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) +{ + memset(ptr, 0, len); + /* This follows OpenSSL and seems sufficient to prevent the compiler + * from optimizing away the memset. + * + * If there was a reliable way to detect availability of memset_s(), + * that would be preferred. */ + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +} +#else /* !MLD_SYS_WINDOWS && MLD_HAVE_INLINE_ASM */ +#error No plausibly-secure implementation of mld_zeroize available. Please provide your own using MLD_CONFIG_CUSTOM_ZEROIZE. +#endif /* !MLD_SYS_WINDOWS && !MLD_HAVE_INLINE_ASM */ +#endif /* !MLD_CONFIG_CUSTOM_ZEROIZE */ + +#endif /* !MLD_CT_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/debug.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/debug.c new file mode 100644 index 0000000000..a55d51e8b1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/debug.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* NOTE: You can remove this file unless you compile with MLDSA_DEBUG. */ + +#include "common.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#if defined(MLDSA_DEBUG) + +#include +#include +#include +#include "debug.h" + +#define MLD_DEBUG_ERROR_HEADER "[ERROR:%s:%04d] " + +void mld_debug_check_assert(const char *file, int line, const int val) +{ + if (val == 0) + { + fprintf(stderr, MLD_DEBUG_ERROR_HEADER "Assertion failed (value %d)\n", + file, line, val); + exit(1); + } +} + +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive) +{ + int err = 0; + unsigned i; + for (i = 0; i < len; i++) + { + int32_t val = ptr[i]; + if (!(val > lower_bound_exclusive && val < upper_bound_exclusive)) + { + fprintf(stderr, + MLD_DEBUG_ERROR_HEADER + "Bounds assertion failed: Index %u, value %d out of bounds " + "(%" PRId64 ",%" PRId64 ")\n", + file, line, i, (int)val, lower_bound_exclusive, + upper_bound_exclusive); + err = 1; + } + } + + if (err == 1) + { + exit(1); + } +} + +#else /* MLDSA_DEBUG */ + +MLD_EMPTY_CU(debug) + +#endif /* !MLDSA_DEBUG */ + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(debug) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_DEBUG_ERROR_HEADER diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/debug.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/debug.h new file mode 100644 index 0000000000..af187bb9de --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/debug.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_DEBUG_H +#define MLD_DEBUG_H +#include "common.h" + +#if defined(MLDSA_DEBUG) +#include + +/************************************************* + * Name: mld_assert + * + * Description: Check debug assertion + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - val: Value asserted to be non-zero + **************************************************/ +#define mld_debug_check_assert MLD_NAMESPACE(mldsa_debug_assert) +void mld_debug_check_assert(const char *file, int line, const int val); + +/************************************************* + * Name: mld_debug_check_bounds + * + * Description: Check whether values in an array of int32_t + * are within specified bounds. + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - ptr: Base of array to be checked + * - len: Number of int32_t in ptr + * - lower_bound_exclusive: Exclusive lower bound + * - upper_bound_exclusive: Exclusive upper bound + **************************************************/ +#define mld_debug_check_bounds MLD_NAMESPACE(mldsa_debug_check_bounds) +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive); + +/* Check assertion, calling exit() upon failure + * + * val: Value that's asserted to be non-zero + */ +#define mld_assert(val) mld_debug_check_assert(__FILE__, __LINE__, (val)) + +/* Check bounds in array of int32_t's + * ptr: Base of int32_t array; will be explicitly cast to int32_t*, + * so you may pass a byte-compatible type such as mld_poly or mld_polyvec. + * len: Number of int32_t in array + * value_lb: Inclusive lower value bound + * value_ub: Exclusive upper value bound */ +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + mld_debug_check_bounds(__FILE__, __LINE__, (const int32_t *)(ptr), (len), \ + ((int64_t)(value_lb)) - 1, (value_ub)) + +/* Check absolute bounds in array of int32_t's + * ptr: Base of array, expression of type int32_t* + * len: Number of int32_t in array + * value_abs_bd: Exclusive absolute upper bound */ +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + mld_assert_bound((ptr), (len), (-((int64_t)(value_abs_bd)) + 1), \ + (value_abs_bd)) + +/* Version of bounds assertions for 2-dimensional arrays */ +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + mld_assert_bound((ptr), ((len0) * (len1)), (value_lb), (value_ub)) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + mld_assert_abs_bound((ptr), ((len0) * (len1)), (value_abs_bd)) + +/* When running CBMC, convert debug assertions into proof obligations */ +#elif defined(CBMC) +#include "cbmc.h" + +#define mld_assert(val) cassert(val) + +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + cassert(array_bound(((int32_t *)(ptr)), 0, (len), (value_lb), (value_ub))) + +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + cassert(array_abs_bound(((int32_t *)(ptr)), 0, (len), (value_abs_bd))) + +/* Because of https://github.com/diffblue/cbmc/issues/8570, we can't + * just use a single flattened array_bound(...) here. */ +#define mld_assert_bound_2d(ptr, M, N, value_lb, value_ub) \ + cassert(forall(kN, 0, (M), \ + array_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_lb), (value_ub)))) + +#define mld_assert_abs_bound_2d(ptr, M, N, value_abs_bd) \ + cassert(forall(kN, 0, (M), \ + array_abs_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_abs_bd)))) + +#else /* !MLDSA_DEBUG && CBMC */ + +#define mld_assert(val) \ + do \ + { \ + } while (0) +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + do \ + { \ + } while (0) +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + do \ + { \ + } while (0) + +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + do \ + { \ + } while (0) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + do \ + { \ + } while (0) + + +#endif /* !MLDSA_DEBUG && !CBMC */ +#endif /* !MLD_DEBUG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/fips202.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/fips202.c new file mode 100644 index 0000000000..1112de061c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/fips202.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "../common.h" +#include "../ct.h" +#include "fips202.h" +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +/************************************************* + * Name: keccak_init + * + * Description: Initializes the Keccak state. + * + * Arguments: - uint64_t *s: pointer to Keccak state + **************************************************/ +static void keccak_init(uint64_t s[MLD_KECCAK_LANES]) +__contract__( + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + mld_memset(s, 0, sizeof(uint64_t) * MLD_KECCAK_LANES); +} + +/************************************************* + * Name: keccak_absorb + * + * Description: Absorb step of Keccak; incremental. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_absorb(uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r, + const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(pos <= r) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(in, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + ensures(return_value < r)) +{ + while (inlen >= r - pos) + __loop__( + assigns(pos, in, inlen, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + invariant(inlen <= loop_entry(inlen)) + invariant(pos <= r) + invariant(in == loop_entry(in) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600_xor_bytes(s, in, pos, r - pos); + inlen -= r - pos; + in += r - pos; + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: At this point, inlen < r, so the truncation to unsigned is safe. */ + mld_keccakf1600_xor_bytes(s, in, pos, (unsigned)inlen); + + /* Safety: At this point, inlen < r and pos <= r so the truncation to unsigned + * is safe. */ + return (unsigned)(pos + inlen); +} + +/************************************************* + * Name: keccak_finalize + * + * Description: Finalize absorb step. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - uint8_t p: domain separation byte + **************************************************/ +static void keccak_finalize(uint64_t s[MLD_KECCAK_LANES], unsigned int pos, + unsigned int r, uint8_t p) +__contract__( + requires(pos <= r && r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires((r / 8) >= 1) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + uint8_t b = 0x80; + mld_keccakf1600_xor_bytes(s, &p, pos, 1); + mld_keccakf1600_xor_bytes(s, &b, r - 1, 1); +} + +/************************************************* + * Name: keccak_squeeze + * + * Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes. + * Modifies the state. Can be called multiple times to keep + * squeezing, i.e., is incremental. + * + * Arguments: - uint8_t *out: pointer to output data + * - size_t outlen: number of bytes to be squeezed (written to out) + * - uint64_t *s: pointer to input/output Keccak state + * - unsigned int pos: number of bytes in current block already + *squeezed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_squeeze(uint8_t *out, size_t outlen, + uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r) +__contract__( + requires((r == SHAKE128_RATE && pos <= SHAKE128_RATE) || + (r == SHAKE256_RATE && pos <= SHAKE256_RATE) || + (r == SHA3_512_RATE && pos <= SHA3_512_RATE)) + requires(outlen <= 8 * r /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(out, outlen)) + ensures(return_value <= r)) +{ + unsigned int i; + size_t out_offset = 0; + + /* Reference: This code is re-factored from the reference implementation + * to facilitate proof with CBMC and to improve readability. + * + * Take a mutable copy of outlen to count down the number of bytes + * still to squeeze. The initial value of outlen is needed for the CBMC + * assigns() clauses. */ + size_t bytes_to_go = outlen; + + while (bytes_to_go > 0) + __loop__( + assigns(i, bytes_to_go, pos, out_offset, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES), memory_slice(out, outlen)) + invariant(bytes_to_go <= outlen) + invariant(out_offset == outlen - bytes_to_go) + invariant(pos <= r) + ) + { + if (pos == r) + { + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: If bytes_to_go < r - pos, truncation to unsigned is safe. */ + i = bytes_to_go < r - pos ? (unsigned)bytes_to_go : r - pos; + mld_keccakf1600_extract_bytes(s, out + out_offset, pos, i); + bytes_to_go -= i; + pos += i; + out_offset += i; + } + + return pos; +} + +void mld_shake128_init(mld_shake128ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE128_RATE, in, inlen); +} + +void mld_shake128_finalize(mld_shake128ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE128_RATE, 0x1F); + state->pos = SHAKE128_RATE; +} + +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE128_RATE); +} + +void mld_shake128_release(mld_shake128ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128ctx)); +} + +void mld_shake256_init(mld_shake256ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); +} + +void mld_shake256_finalize(mld_shake256ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); + state->pos = SHAKE256_RATE; +} + +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); +} + +void mld_shake256_release(mld_shake256ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256ctx)); +} + +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +{ + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, in, inlen); + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/fips202.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/fips202.h new file mode 100644 index 0000000000..9f0253cb88 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/fips202.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202_H +#define MLD_FIPS202_FIPS202_H + +#include +#include +#include "../cbmc.h" +#include "../common.h" + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 +#define SHA3_256_RATE 136 +#define SHA3_512_RATE 72 +#define MLD_KECCAK_LANES 25 +#define SHA3_256_HASHBYTES 32 +#define SHA3_512_HASHBYTES 64 + + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake128ctx; + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake256ctx; + +#define mld_shake128_init MLD_NAMESPACE(shake128_init) +/************************************************* + * Name: mld_shake128_init + * + * Description: Initializes state for use as SHAKE128 XOF + * + * Arguments: - mld_shake128ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake128_init(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos == 0) +); + +#define mld_shake128_absorb MLD_NAMESPACE(shake128_absorb) +/************************************************* + * Name: mld_shake128_absorb + * + * Description: Absorb step of the SHAKE128 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake128ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_finalize MLD_NAMESPACE(shake128_finalize) +/************************************************* + * Name: mld_shake128_finalize + * + * Description: Concludes the absorb phase of the SHAKE128 XOF. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_finalize(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_squeeze MLD_NAMESPACE(shake128_squeeze) +/************************************************* + * Name: mld_shake128_squeeze + * + * Description: Squeeze step of SHAKE128 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake128ctx *s: pointer to input/output state + **************************************************/ +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE128_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_release MLD_NAMESPACE(shake128_release) +/************************************************* + * Name: mld_shake128_release + * + * Description: Release and securely zero the SHAKE128 state. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_release(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) +); + +#define mld_shake256_init MLD_NAMESPACE(shake256_init) +/************************************************* + * Name: mld_shake256_init + * + * Description: Initializes state for use as SHAKE256 XOF + * + * Arguments: - mld_shake256ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake256_init(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos == 0) +); + +#define mld_shake256_absorb MLD_NAMESPACE(shake256_absorb) +/************************************************* + * Name: mld_shake256_absorb + * + * Description: Absorb step of the SHAKE256 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake256ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_finalize MLD_NAMESPACE(shake256_finalize) +/************************************************* + * Name: mld_shake256_finalize + * + * Description: Concludes the absorb phase of the SHAKE256 XOF. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_finalize(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_squeeze MLD_NAMESPACE(shake256_squeeze) +/************************************************* + * Name: mld_shake256_squeeze + * + * Description: Squeeze step of SHAKE256 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake256ctx *s: pointer to input/output state + **************************************************/ +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_release MLD_NAMESPACE(shake256_release) +/************************************************* + * Name: mld_shake256_release + * + * Description: Release and securely zero the SHAKE256 state. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_release(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) +); + +#define mld_shake256 MLD_NAMESPACE(shake256) +/************************************************* + * Name: mld_shake256 + * + * Description: SHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +); + +#endif /* !MLD_FIPS202_FIPS202_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/fips202x4.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/fips202x4.c new file mode 100644 index 0000000000..0fb5cd57c7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/fips202x4.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include "../common.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "../ct.h" +#include "fips202.h" +#include "fips202x4.h" +#include "keccakf1600.h" + +static void mld_keccak_absorb_once_x4(uint64_t *s, uint32_t r, + const uint8_t *in0, const uint8_t *in1, + const uint8_t *in2, const uint8_t *in3, + size_t inlen, uint8_t p) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))) +{ + while (inlen >= r) + __loop__( + assigns(inlen, in0, in1, in2, in3, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + invariant(inlen <= loop_entry(inlen)) + invariant(in0 == loop_entry(in0) + (loop_entry(inlen) - inlen)) + invariant(in1 == loop_entry(in1) + (loop_entry(inlen) - inlen)) + invariant(in2 == loop_entry(in2) + (loop_entry(inlen) - inlen)) + invariant(in3 == loop_entry(in3) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, r); + mld_keccakf1600x4_permute(s); + + in0 += r; + in1 += r; + in2 += r; + in3 += r; + inlen -= r; + } + + /* Safety: At this point, inlen < r, so the truncations to unsigned are safe + * below. */ + if (inlen > 0) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, (unsigned)inlen); + } + + if (inlen == r - 1) + { + p |= 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + } + else + { + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + p = 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, r - 1, 1); + } +} + +static void mld_keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1, + uint8_t *out2, uint8_t *out3, + size_t nblocks, uint64_t *s, uint32_t r) +__contract__( + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(out0, nblocks * r)) + requires(memory_no_alias(out1, nblocks * r)) + requires(memory_no_alias(out2, nblocks * r)) + requires(memory_no_alias(out3, nblocks * r)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(out0, nblocks * r)) + assigns(memory_slice(out1, nblocks * r)) + assigns(memory_slice(out2, nblocks * r)) + assigns(memory_slice(out3, nblocks * r))) +{ + while (nblocks > 0) + __loop__( + assigns(out0, out1, out2, out3, nblocks, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY), + memory_slice(out0, nblocks * r), + memory_slice(out1, nblocks * r), + memory_slice(out2, nblocks * r), + memory_slice(out3, nblocks * r)) + invariant(nblocks <= loop_entry(nblocks) && + out0 == loop_entry(out0) + r * (loop_entry(nblocks) - nblocks) && + out1 == loop_entry(out1) + r * (loop_entry(nblocks) - nblocks) && + out2 == loop_entry(out2) + r * (loop_entry(nblocks) - nblocks) && + out3 == loop_entry(out3) + r * (loop_entry(nblocks) - nblocks))) + { + mld_keccakf1600x4_permute(s); + mld_keccakf1600x4_extract_bytes(s, out0, out1, out2, out3, 0, r); + + out0 += r; + out1 += r; + out2 += r; + out3 += r; + nblocks--; + } +} + +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake128x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE128_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE128_RATE); +} + +void mld_shake128x4_init(mld_shake128x4ctx *state) { (void)state; } +void mld_shake128x4_release(mld_shake128x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128x4ctx)); +} + + +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake256x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE256_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE256_RATE); +} + +void mld_shake256x4_init(mld_shake256x4ctx *state) { (void)state; } +void mld_shake256x4_release(mld_shake256x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256x4ctx)); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/fips202x4.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/fips202x4.h new file mode 100644 index 0000000000..e7987207a6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/fips202x4.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202X4_H +#define MLD_FIPS202_FIPS202X4_H + +#include +#include + +#include "../cbmc.h" +#include "../common.h" + +#include "fips202.h" +#include "keccakf1600.h" + +/* Context for non-incremental API */ +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake128x4ctx; + +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake256x4ctx; + +#define mld_shake128x4_absorb_once MLD_NAMESPACE(shake128x4_absorb_once) +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_squeezeblocks MLD_NAMESPACE(shake128x4_squeezeblocks) +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE128_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE128_RATE), + memory_slice(out1, nblocks * SHAKE128_RATE), + memory_slice(out2, nblocks * SHAKE128_RATE), + memory_slice(out3, nblocks * SHAKE128_RATE), + memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_init MLD_NAMESPACE(shake128x4_init) +void mld_shake128x4_init(mld_shake128x4ctx *state); + +#define mld_shake128x4_release MLD_NAMESPACE(shake128x4_release) +void mld_shake128x4_release(mld_shake128x4ctx *state); + + +#define mld_shake256x4_absorb_once MLD_NAMESPACE(shake256x4_absorb_once) +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_squeezeblocks MLD_NAMESPACE(shake256x4_squeezeblocks) +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE256_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE256_RATE), + memory_slice(out1, nblocks * SHAKE256_RATE), + memory_slice(out2, nblocks * SHAKE256_RATE), + memory_slice(out3, nblocks * SHAKE256_RATE), + memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_init MLD_NAMESPACE(shake256x4_init) +void mld_shake256x4_init(mld_shake256x4ctx *state); + +#define mld_shake256x4_release MLD_NAMESPACE(shake256x4_release) +void mld_shake256x4_release(mld_shake256x4ctx *state); + + +#endif /* !MLD_FIPS202_FIPS202X4_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/keccakf1600.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/keccakf1600.c new file mode 100644 index 0000000000..e59120c07c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/keccakf1600.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#define MLD_KECCAK_NROUNDS 24 +#define MLD_KECCAK_ROL(a, offset) ((a << offset) ^ (a >> (64 - offset))) + +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = state_ptr[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = (state[(offset + i) >> 3] >> (8 * ((offset + i) & 0x07))) & 0xFF; + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state_ptr[i] ^= data[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state[(offset + i) >> 3] ^= (uint64_t)data[i] + << (8 * ((offset + i) & 0x07)); + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X4_NATIVE) + if (mld_keccak_f1600_x4_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 0); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 1); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 2); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 3); +} + +static const uint64_t mld_KeccakF_RoundConstants[MLD_KECCAK_NROUNDS] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +static void mld_keccakf1600_permute_c(uint64_t *state) +{ + unsigned round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + uint64_t BCa, BCe, BCi, BCo, BCu; + uint64_t Da, De, Di, Do, Du; + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + /* copyFromState(A, state) */ + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < MLD_KECCAK_NROUNDS; round += 2) + __loop__(invariant(round <= MLD_KECCAK_NROUNDS && round % 2 == 0)) + { + /* prepareTheta */ + BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; + BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + /* thetaRhoPiChiIotaPrepareTheta(round, A, E) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = MLD_KECCAK_ROL(Age, 44); + Aki ^= Di; + BCi = MLD_KECCAK_ROL(Aki, 43); + Amo ^= Do; + BCo = MLD_KECCAK_ROL(Amo, 21); + Asu ^= Du; + BCu = MLD_KECCAK_ROL(Asu, 14); + Eba = BCa ^ ((~BCe) & BCi); + Eba ^= (uint64_t)mld_KeccakF_RoundConstants[round]; + Ebe = BCe ^ ((~BCi) & BCo); + Ebi = BCi ^ ((~BCo) & BCu); + Ebo = BCo ^ ((~BCu) & BCa); + Ebu = BCu ^ ((~BCa) & BCe); + + Abo ^= Do; + BCa = MLD_KECCAK_ROL(Abo, 28); + Agu ^= Du; + BCe = MLD_KECCAK_ROL(Agu, 20); + Aka ^= Da; + BCi = MLD_KECCAK_ROL(Aka, 3); + Ame ^= De; + BCo = MLD_KECCAK_ROL(Ame, 45); + Asi ^= Di; + BCu = MLD_KECCAK_ROL(Asi, 61); + Ega = BCa ^ ((~BCe) & BCi); + Ege = BCe ^ ((~BCi) & BCo); + Egi = BCi ^ ((~BCo) & BCu); + Ego = BCo ^ ((~BCu) & BCa); + Egu = BCu ^ ((~BCa) & BCe); + + Abe ^= De; + BCa = MLD_KECCAK_ROL(Abe, 1); + Agi ^= Di; + BCe = MLD_KECCAK_ROL(Agi, 6); + Ako ^= Do; + BCi = MLD_KECCAK_ROL(Ako, 25); + Amu ^= Du; + BCo = MLD_KECCAK_ROL(Amu, 8); + Asa ^= Da; + BCu = MLD_KECCAK_ROL(Asa, 18); + Eka = BCa ^ ((~BCe) & BCi); + Eke = BCe ^ ((~BCi) & BCo); + Eki = BCi ^ ((~BCo) & BCu); + Eko = BCo ^ ((~BCu) & BCa); + Eku = BCu ^ ((~BCa) & BCe); + + Abu ^= Du; + BCa = MLD_KECCAK_ROL(Abu, 27); + Aga ^= Da; + BCe = MLD_KECCAK_ROL(Aga, 36); + Ake ^= De; + BCi = MLD_KECCAK_ROL(Ake, 10); + Ami ^= Di; + BCo = MLD_KECCAK_ROL(Ami, 15); + Aso ^= Do; + BCu = MLD_KECCAK_ROL(Aso, 56); + Ema = BCa ^ ((~BCe) & BCi); + Eme = BCe ^ ((~BCi) & BCo); + Emi = BCi ^ ((~BCo) & BCu); + Emo = BCo ^ ((~BCu) & BCa); + Emu = BCu ^ ((~BCa) & BCe); + + Abi ^= Di; + BCa = MLD_KECCAK_ROL(Abi, 62); + Ago ^= Do; + BCe = MLD_KECCAK_ROL(Ago, 55); + Aku ^= Du; + BCi = MLD_KECCAK_ROL(Aku, 39); + Ama ^= Da; + BCo = MLD_KECCAK_ROL(Ama, 41); + Ase ^= De; + BCu = MLD_KECCAK_ROL(Ase, 2); + Esa = BCa ^ ((~BCe) & BCi); + Ese = BCe ^ ((~BCi) & BCo); + Esi = BCi ^ ((~BCo) & BCu); + Eso = BCo ^ ((~BCu) & BCa); + Esu = BCu ^ ((~BCa) & BCe); + + /* prepareTheta */ + BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + /* thetaRhoPiChiIotaPrepareTheta(round+1, E, A) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = MLD_KECCAK_ROL(Ege, 44); + Eki ^= Di; + BCi = MLD_KECCAK_ROL(Eki, 43); + Emo ^= Do; + BCo = MLD_KECCAK_ROL(Emo, 21); + Esu ^= Du; + BCu = MLD_KECCAK_ROL(Esu, 14); + Aba = BCa ^ ((~BCe) & BCi); + Aba ^= (uint64_t)mld_KeccakF_RoundConstants[round + 1]; + Abe = BCe ^ ((~BCi) & BCo); + Abi = BCi ^ ((~BCo) & BCu); + Abo = BCo ^ ((~BCu) & BCa); + Abu = BCu ^ ((~BCa) & BCe); + + Ebo ^= Do; + BCa = MLD_KECCAK_ROL(Ebo, 28); + Egu ^= Du; + BCe = MLD_KECCAK_ROL(Egu, 20); + Eka ^= Da; + BCi = MLD_KECCAK_ROL(Eka, 3); + Eme ^= De; + BCo = MLD_KECCAK_ROL(Eme, 45); + Esi ^= Di; + BCu = MLD_KECCAK_ROL(Esi, 61); + Aga = BCa ^ ((~BCe) & BCi); + Age = BCe ^ ((~BCi) & BCo); + Agi = BCi ^ ((~BCo) & BCu); + Ago = BCo ^ ((~BCu) & BCa); + Agu = BCu ^ ((~BCa) & BCe); + + Ebe ^= De; + BCa = MLD_KECCAK_ROL(Ebe, 1); + Egi ^= Di; + BCe = MLD_KECCAK_ROL(Egi, 6); + Eko ^= Do; + BCi = MLD_KECCAK_ROL(Eko, 25); + Emu ^= Du; + BCo = MLD_KECCAK_ROL(Emu, 8); + Esa ^= Da; + BCu = MLD_KECCAK_ROL(Esa, 18); + Aka = BCa ^ ((~BCe) & BCi); + Ake = BCe ^ ((~BCi) & BCo); + Aki = BCi ^ ((~BCo) & BCu); + Ako = BCo ^ ((~BCu) & BCa); + Aku = BCu ^ ((~BCa) & BCe); + + Ebu ^= Du; + BCa = MLD_KECCAK_ROL(Ebu, 27); + Ega ^= Da; + BCe = MLD_KECCAK_ROL(Ega, 36); + Eke ^= De; + BCi = MLD_KECCAK_ROL(Eke, 10); + Emi ^= Di; + BCo = MLD_KECCAK_ROL(Emi, 15); + Eso ^= Do; + BCu = MLD_KECCAK_ROL(Eso, 56); + Ama = BCa ^ ((~BCe) & BCi); + Ame = BCe ^ ((~BCi) & BCo); + Ami = BCi ^ ((~BCo) & BCu); + Amo = BCo ^ ((~BCu) & BCa); + Amu = BCu ^ ((~BCa) & BCe); + + Ebi ^= Di; + BCa = MLD_KECCAK_ROL(Ebi, 62); + Ego ^= Do; + BCe = MLD_KECCAK_ROL(Ego, 55); + Eku ^= Du; + BCi = MLD_KECCAK_ROL(Eku, 39); + Ema ^= Da; + BCo = MLD_KECCAK_ROL(Ema, 41); + Ese ^= De; + BCu = MLD_KECCAK_ROL(Ese, 2); + Asa = BCa ^ ((~BCe) & BCi); + Ase = BCe ^ ((~BCi) & BCo); + Asi = BCi ^ ((~BCo) & BCu); + Aso = BCo ^ ((~BCu) & BCa); + Asu = BCu ^ ((~BCa) & BCe); + } + + /* copyToState(state, A) */ + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} + +void mld_keccakf1600_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X1_NATIVE) + if (mld_keccak_f1600_x1_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X1_NATIVE */ + mld_keccakf1600_permute_c(state); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(keccakf1600) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_KECCAK_NROUNDS +#undef MLD_KECCAK_ROL diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/keccakf1600.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/keccakf1600.h new file mode 100644 index 0000000000..e56adc1561 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/keccakf1600.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_KECCAKF1600_H +#define MLD_FIPS202_KECCAKF1600_H +#include +#include "../cbmc.h" +#include "../common.h" +#include "fips202.h" + +#define MLD_KECCAK_LANES 25 +#define MLD_KECCAK_WAY 4 + +/* + * WARNING: + * The contents of this structure, including the placement + * and interleaving of Keccak lanes, are IMPLEMENTATION-DEFINED. + * The struct is only exposed here to allow its construction on the stack. + */ + +#define mld_keccakf1600_extract_bytes MLD_NAMESPACE(keccakf1600_extract_bytes) +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(data, length)) +); + +#define mld_keccakf1600_xor_bytes MLD_NAMESPACE(keccakf1600_xor_bytes) +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#define mld_keccakf1600x4_extract_bytes \ + MLD_NAMESPACE(keccakf1600x4_extract_bytes) +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + requires(memory_no_alias(data1, length)) + requires(memory_no_alias(data2, length)) + requires(memory_no_alias(data3, length)) + assigns(memory_slice(data0, length)) + assigns(memory_slice(data1, length)) + assigns(memory_slice(data2, length)) + assigns(memory_slice(data3, length)) +); + +#define mld_keccakf1600x4_xor_bytes MLD_NAMESPACE(keccakf1600x4_xor_bytes) +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + /* Case 1: all input buffers are distinct; Case 2: All input buffers are the same */ + requires((data0 == data1 && + data0 == data2 && + data0 == data3) || + (memory_no_alias(data1, length) && + memory_no_alias(data2, length) && + memory_no_alias(data3, length))) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600x4_permute MLD_NAMESPACE(keccakf1600x4_permute) +void mld_keccakf1600x4_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600_permute MLD_NAMESPACE(keccakf1600_permute) +void mld_keccakf1600_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#endif /* !MLD_FIPS202_KECCAKF1600_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/api.h new file mode 100644 index 0000000000..4625c9a1ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/api.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_API_H +#define MLD_FIPS202_NATIVE_API_H +/* + * FIPS-202 native interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + */ + +#include +#include "../../cbmc.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* + * This is the C<->native interface allowing for the drop-in + * of custom Keccak-F1600 implementations. + * + * A _backend_ is a specific implementation of parts of this interface. + * + * You can replace 1-fold or 4-fold batched Keccak-F1600. + * To enable, set MLD_USE_FIPS202_X1_NATIVE or MLD_USE_FIPS202_X4_NATIVE + * in your backend, and define the inline wrappers mld_keccak_f1600_x1_native() + * and/or mld_keccak_f1600_x4_native(), respectively, to forward to your + * implementation. + */ + +#if defined(MLD_USE_FIPS202_X1_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 1)) +); +#endif /* MLD_USE_FIPS202_X1_NATIVE */ +#if defined(MLD_USE_FIPS202_X4_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 4)) +); +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + +#endif /* !MLD_FIPS202_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/custom/custom.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/custom/custom.h new file mode 100644 index 0000000000..afd8a3fd30 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/custom/custom.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#if !defined(MLD_FIPS202_CUSTOM_TINY_SHA3_H) +#define MLD_FIPS202_CUSTOM_TINY_SHA3_H + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/sha3.h" +/* Replace (single) Keccak-F1600 by tiny-SHA3's */ +#define MLD_USE_FIPS202_X1_NATIVE +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + tiny_sha3_keccakf(state); + + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_CUSTOM_TINY_SHA3_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/custom/src/LICENSE b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/custom/src/LICENSE new file mode 100644 index 0000000000..35741e52a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/custom/src/LICENSE @@ -0,0 +1,23 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +The MIT License (MIT) + +Copyright (c) 2015 Markku-Juhani O. Saarinen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/custom/src/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/custom/src/README.md new file mode 100644 index 0000000000..38785e4626 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/custom/src/README.md @@ -0,0 +1,63 @@ +[//]: # (SPDX-License-Identifier: MIT) + +# tiny_sha3 +Very small, readable implementation of the FIPS 202 and SHA3 hash function. +Public domain. + +### Updated 27-Dec-15: + +Added SHAKE128 and SHAKE256 code and test vectors. The code can actually do +a XOF of arbitrary size (like "SHAKE512"). + + +### Updated 03-Sep-15: + +Made the implementation portable. The API is now pretty much the +same that OpenSSL uses. + + +### Updated 07-Aug-15: + +Now that SHA3 spec is out, I've updated the package to match with the +new padding rules. There is literally one line difference between +Keccak 3.0 and SHA-3 implementations: + +``` + temp[inlen++] = 0x06; // XXX Padding Changed from Keccak 3.0 +``` + +The 0x06 constant there used to be 0x01. But this of course totally +breaks compatibility and test vectors had to be revised. + +SHA-3 Spec: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf + +Cheers, +- markku + + +### Original README.TXT from 19-Nov-11: + +Hi. + +The SHA-3 competition is nearing it's end and I would personally like +to support Keccak as the winner. I have a PhD in hash function cryptanalysis +so don't take my word for it, go ahead and look into the code ! + +Since I couldn't find a *compact* and/or *readable* implementation of Keccak +anywhere, here's one I cooked up as a service to the curious. + +This implementation is intended for study of the algorithm, not for +production use. + +The code works correctly on 64-bit little-endian platforms with gcc. +Like your Linux box. The main.c module contains self-tests for all +officially supported hash sizes. + +If you're looking for production code, the official multi-megabyte package +covers everything you could possibly need and too much much more: +http://keccak.noekeon.org/ + +Cheers, +- Markku 19-Nov-11 + +Dr. Markku-Juhani O. Saarinen diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/custom/src/sha3.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/custom/src/sha3.c new file mode 100644 index 0000000000..c7e0910f0b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/custom/src/sha3.c @@ -0,0 +1,218 @@ +/* SPDX-License-Identifier: MIT + * + * sha3.c + * 19-Nov-11 Markku-Juhani O. Saarinen */ + +/* Revised 07-Aug-15 to match with official release of FIPS PUB 202 "SHA3" */ +/* Revised 03-Sep-15 for portability + OpenSSL - style API */ + +#include "sha3.h" + +/* update the state with given number of rounds */ + +void tiny_sha3_keccakf(uint64_t st[25]) +{ + /* constants */ + const uint64_t keccakf_rndc[24] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008}; + const int keccakf_rotc[24] = {1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44}; + const int keccakf_piln[24] = {10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1}; + + /* variables */ + int i, j, r; + uint64_t t, bc[5]; + + /* NOTE: + * This is present in the tiny_sha3 implementation because it uses + * a byte-reversed presentation of the Keccakf1600 state for big endian + * targets. mldsa-native uses the standard presentation, hence we don't + * the reversal here. */ + /* #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ */ + /* uint8_t *v; */ + + /* /\* endianness conversion. this is redundant on little-endian targets *\/ + */ + /* for (i = 0; i < 25; i++) */ + /* { */ + /* v = (uint8_t *)&st[i]; */ + /* st[i] = ((uint64_t)v[0]) | (((uint64_t)v[1]) << 8) | */ + /* (((uint64_t)v[2]) << 16) | (((uint64_t)v[3]) << 24) | */ + /* (((uint64_t)v[4]) << 32) | (((uint64_t)v[5]) << 40) | */ + /* (((uint64_t)v[6]) << 48) | (((uint64_t)v[7]) << 56); */ + /* } */ + /* #endif */ + + /* actual iteration */ + for (r = 0; r < KECCAKF_ROUNDS; r++) + { + /* Theta */ + for (i = 0; i < 5; i++) + { + bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20]; + } + + for (i = 0; i < 5; i++) + { + t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); + for (j = 0; j < 25; j += 5) + { + st[j + i] ^= t; + } + } + + /* Rho Pi */ + t = st[1]; + for (i = 0; i < 24; i++) + { + j = keccakf_piln[i]; + bc[0] = st[j]; + st[j] = ROTL64(t, keccakf_rotc[i]); + t = bc[0]; + } + + /* Chi */ + for (j = 0; j < 25; j += 5) + { + for (i = 0; i < 5; i++) + { + bc[i] = st[j + i]; + } + for (i = 0; i < 5; i++) + { + st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; + } + } + + /* Iota */ + st[0] ^= keccakf_rndc[r]; + } + /* NOTE: + * This is present in the tiny_sha3 implementation because it uses + * a byte-reversed presentation of the Keccakf1600 state for big endian + * targets. mldsa-native uses the standard presentation, hence we don't + * the reversal here. */ + /* #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ */ + /* /\* endianness conversion. this is redundant on little-endian targets *\/ + */ + /* for (i = 0; i < 25; i++) */ + /* { */ + /* v = (uint8_t *)&st[i]; */ + /* t = st[i]; */ + /* v[0] = t & 0xFF; */ + /* v[1] = (t >> 8) & 0xFF; */ + /* v[2] = (t >> 16) & 0xFF; */ + /* v[3] = (t >> 24) & 0xFF; */ + /* v[4] = (t >> 32) & 0xFF; */ + /* v[5] = (t >> 40) & 0xFF; */ + /* v[6] = (t >> 48) & 0xFF; */ + /* v[7] = (t >> 56) & 0xFF; */ + /* } */ + /* #endif */ +} + +/* Initialize the context for SHA3 */ + +int tiny_sha3_init(sha3_ctx_t *c, int mdlen) +{ + int i; + + for (i = 0; i < 25; i++) + { + c->st.q[i] = 0; + } + c->mdlen = mdlen; + c->rsiz = 200 - 2 * mdlen; + c->pt = 0; + + return 1; +} + +/* update state with more data */ + +int tiny_sha3_update(sha3_ctx_t *c, const void *data, size_t len) +{ + size_t i; + int j; + + j = c->pt; + for (i = 0; i < len; i++) + { + c->st.b[j++] ^= ((const uint8_t *)data)[i]; + if (j >= c->rsiz) + { + tiny_sha3_keccakf(c->st.q); + j = 0; + } + } + c->pt = j; + + return 1; +} + +/* finalize and output a hash */ + +int tiny_sha3_final(void *md, sha3_ctx_t *c) +{ + int i; + + c->st.b[c->pt] ^= 0x06; + c->st.b[c->rsiz - 1] ^= 0x80; + tiny_sha3_keccakf(c->st.q); + + for (i = 0; i < c->mdlen; i++) + { + ((uint8_t *)md)[i] = c->st.b[i]; + } + + return 1; +} + +/* compute a SHA-3 hash (md) of given byte length from "in" */ + +void *tiny_sha3(const void *in, size_t inlen, void *md, int mdlen) +{ + sha3_ctx_t sha3; + + tiny_sha3_init(&sha3, mdlen); + tiny_sha3_update(&sha3, in, inlen); + tiny_sha3_final(md, &sha3); + + return md; +} + +/* SHAKE128 and SHAKE256 extensible-output functionality */ + +void tiny_shake_xof(sha3_ctx_t *c) +{ + c->st.b[c->pt] ^= 0x1F; + c->st.b[c->rsiz - 1] ^= 0x80; + tiny_sha3_keccakf(c->st.q); + c->pt = 0; +} + +void tiny_shake_out(sha3_ctx_t *c, void *out, size_t len) +{ + size_t i; + int j; + + j = c->pt; + for (i = 0; i < len; i++) + { + if (j >= c->rsiz) + { + tiny_sha3_keccakf(c->st.q); + j = 0; + } + ((uint8_t *)out)[i] = c->st.b[j++]; + } + c->pt = j; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/custom/src/sha3.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/custom/src/sha3.h new file mode 100644 index 0000000000..a70c3d3528 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/fips202/native/custom/src/sha3.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: MIT + * + * sha3.h + * 19-Nov-11 Markku-Juhani O. Saarinen */ + +#ifndef SHA3_H +#define SHA3_H + +#include +#include + +#ifndef KECCAKF_ROUNDS +#define KECCAKF_ROUNDS 24 +#endif + +#ifndef ROTL64 +#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) +#endif + +/* state context */ +typedef struct +{ + union + { /* state: */ + uint8_t b[200]; /* 8-bit bytes */ + uint64_t q[25]; /* 64-bit words */ + } st; + int pt, rsiz, mdlen; /* these don't overflow */ +} sha3_ctx_t; + +/* Compression function. */ +void tiny_sha3_keccakf(uint64_t st[25]); + +/* OpenSSL - like interfece */ +int tiny_sha3_init(sha3_ctx_t *c, int mdlen); /* mdlen = hash output in bytes */ +int tiny_sha3_update(sha3_ctx_t *c, const void *data, size_t len); +int tiny_sha3_final(void *md, sha3_ctx_t *c); /* digest goes to md */ + +/* compute a sha3 hash (md) of given byte length from "in" */ +void *tiny_sha3(const void *in, size_t inlen, void *md, int mdlen); + +/* SHAKE128 and SHAKE256 extensible-output functions */ +#define tiny_shake128_init(c) tiny_sha3_init(c, 16) +#define tiny_shake256_init(c) tiny_sha3_init(c, 32) +#define tiny_shake_update tiny_sha3_update + +void tiny_shake_xof(sha3_ctx_t *c); +void tiny_shake_out(sha3_ctx_t *c, void *out, size_t len); + +#endif /* !SHA3_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/packing.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/packing.c new file mode 100644 index 0000000000..26da273856 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/packing.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include + +#include "common.h" +#include "packing.h" +#include "poly.h" +#include "polyvec.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_unpack_hints MLD_ADD_PARAM_SET(mld_unpack_hints) +/* End of parameter set namespacing */ + +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +{ + unsigned int i; + + mld_memcpy(pk, rho, MLDSA_SEEDBYTES); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt1_pack(pk + MLDSA_SEEDBYTES + i * MLDSA_POLYT1_PACKEDBYTES, + &t1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +{ + unsigned int i; + + mld_memcpy(rho, pk, MLDSA_SEEDBYTES); + pk += MLDSA_SEEDBYTES; + + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt1_unpack(&t1->vec[i], pk + i * MLDSA_POLYT1_PACKEDBYTES); + } +} + +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +{ + mld_memcpy(sk, rho, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, key, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, tr, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_pack_eta(sk, s1); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_eta(sk, s2); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_t0(sk, t0); +} + +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +{ + mld_memcpy(rho, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(key, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(tr, sk, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_unpack_eta(s1, sk); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_eta(s2, sk); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_t0(t0, sk); +} + +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +{ + unsigned int i, j, k; + + mld_memcpy(sig, c, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + /* skip z component - packed via mld_pack_sig_z */ + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + /* Encode hints h */ + + /* The final section of sig[] is MLDSA_POLYVECH_PACKEDBYTES long, where + * MLDSA_POLYVECH_PACKEDBYTES = MLDSA_OMEGA + MLDSA_K + * + * The first OMEGA bytes record the index numbers of the coefficients + * that are not equal to 0 + * + * The final K bytes record a running tally of the number of hints + * coming from each of the K polynomials in h. + * + * The pre-condition tells us that number_of_hints <= OMEGA, so some + * bytes may not be written, so we initialize all of them to zero + * to start. + */ + mld_memset(sig, 0, MLDSA_POLYVECH_PACKEDBYTES); + + k = 0; + /* For each polynomial in h... */ + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* For each coefficient in that polynomial, record it as as hint */ + /* if its value is not zero */ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + assigns(j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(j <= MLDSA_N) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* The reference implementation implicitly relies on the total */ + /* number of hints being less than OMEGA, assuming h is valid. */ + /* In mldsa-native, we check this explicitly to ease proof of */ + /* type safety. */ + if (h->vec[i].coeffs[j] != 0 && k < number_of_hints) + { + /* The enclosing if condition AND the loop invariant infer */ + /* that k < MLDSA_OMEGA, so writing to sig[k] is safe and k */ + /* can be incremented. */ + sig[k++] = (uint8_t)j; + } + } + /* Having recorded all the hints for this polynomial, also */ + /* record the running tally into the correct "slot" for that */ + /* coefficient in the final K bytes */ + sig[MLDSA_OMEGA + i] = (uint8_t)k; + } +} + +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +{ + sig += MLDSA_CTILDEBYTES; + sig += i * MLDSA_POLYZ_PACKEDBYTES; + mld_polyz_pack(sig, zi); +} + +/************************************************* + * Name: mld_unpack_hints + * + * Description: Unpack raw hint bytes into a polyveck + * struct + * + * Arguments: - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]: + * raw hint bytes + * + * Returns 1 in case of malformed hints; otherwise 0. + **************************************************/ +static int mld_unpack_hints( + mld_polyveck *h, const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(packed_hints, MLDSA_POLYVECH_PACKEDBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + /* All returned coefficients are either 0 or 1 */ + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +) +{ + unsigned int i, j; + unsigned int old_hint_count; + + /* Set all coefficients of all polynomials to 0. */ + /* Only those that are actually non-zero hints will */ + /* be overwritten below. */ + mld_memset(h, 0, sizeof(mld_polyveck)); + + old_hint_count = 0; + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + /* Grab the hint count for the i'th polynomial */ + const unsigned int new_hint_count = packed_hints[MLDSA_OMEGA + i]; + + /* new_hint_count must increase or stay the same, but also remain */ + /* less than or equal to MLDSA_OMEGA */ + if (new_hint_count < old_hint_count || new_hint_count > MLDSA_OMEGA) + { + /* Error - new_hint_count is invalid */ + return 1; + } + + /* If new_hint_count == old_hint_count, then this polynomial has */ + /* zero hints, so this loop executes zero times and we move */ + /* straight on to the next polynomial. */ + for (j = old_hint_count; j < new_hint_count; ++j) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + const uint8_t this_hint_index = packed_hints[j]; + + /* Coefficients must be ordered for strong unforgeability */ + if (j > old_hint_count && this_hint_index <= packed_hints[j - 1]) + { + return 1; + } + h->vec[i].coeffs[this_hint_index] = 1; + } + + old_hint_count = new_hint_count; + } + + /* Extra indices must be zero for strong unforgeability */ + for (j = old_hint_count; j < MLDSA_OMEGA; ++j) + __loop__( + invariant(j <= MLDSA_OMEGA) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + if (packed_hints[j] != 0) + { + return 1; + } + } + + return 0; +} + +MLD_INTERNAL_API +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +{ + mld_memcpy(c, sig, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + mld_polyvecl_unpack_z(z, sig); + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + return mld_unpack_hints(h, sig); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_unpack_hints diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/packing.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/packing.h new file mode 100644 index 0000000000..19095d08cd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/packing.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PACKING_H +#define MLD_PACKING_H + +#include +#include "polyvec.h" + +#define mld_pack_pk MLD_NAMESPACE_KL(pack_pk) +/************************************************* + * Name: mld_pack_pk + * + * Description: Bit-pack public key pk = (rho, t1). + * + * Arguments: - uint8_t pk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const mld_polyveck *t1: pointer to vector t1 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) +); + + +#define mld_pack_sk MLD_NAMESPACE_KL(pack_sk) +/************************************************* + * Name: mld_pack_sk + * + * Description: Bit-pack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - uint8_t sk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const uint8_t tr[]: byte array containing tr + * - const uint8_t key[]: byte array containing key + * - const mld_polyveck *t0: pointer to vector t0 + * - const mld_polyvecl *s1: pointer to vector s1 + * - const mld_polyveck *s2: pointer to vector s2 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +__contract__( + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + requires(forall(k2, 0, MLDSA_K, + array_abs_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) +); + + +#define mld_pack_sig_c_h MLD_NAMESPACE_KL(pack_sig_c_h) +/************************************************* + * Name: mld_pack_sig_c_h + * + * Description: Bit-pack c and h component of sig = (c, z, h). + * The z component is packed separately using mld_pack_sig_z. + * + * Arguments: - uint8_t sig[]: output byte array + * - const uint8_t *c: pointer to challenge hash length + * MLDSA_SEEDBYTES + * - const mld_polyveck *h: pointer to hint vector h + * - const unsigned int number_of_hints: total + * hints in *h + * + * Note that the number_of_hints argument is not present + * in the reference implementation. It is added here to ease + * proof of type safety. + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + requires(number_of_hints <= MLDSA_OMEGA) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_pack_sig_z MLD_NAMESPACE_KL(pack_sig_z) +/************************************************* + * Name: mld_pack_sig_z + * + * Description: Bit-pack single polynomial of z component of sig = (c, z, h). + * The c and h components are packed separately using + * mld_pack_sig_c_h. + * + * Arguments: - uint8_t sig[]: output byte array + * - const mld_poly *zi: pointer to a single polynomial in z + * - const unsigned int i: index of zi in vector z + * + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(zi, sizeof(mld_poly))) + requires(i < MLDSA_L) + requires(array_bound(zi->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_unpack_pk MLD_NAMESPACE_KL(unpack_pk) +/************************************************* + * Name: mld_unpack_pk + * + * Description: Unpack public key pk = (rho, t1). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const mld_polyveck *t1: pointer to output vector t1 + * - uint8_t pk[]: byte array containing bit-packed pk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) +); + + +#define mld_unpack_sk MLD_NAMESPACE_KL(unpack_sk) +/************************************************* + * Name: mld_unpack_sk + * + * Description: Unpack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const uint8_t tr[]: output byte array for tr + * - const uint8_t key[]: output byte array for key + * - const mld_polyveck *t0: pointer to output vector t0 + * - const mld_polyvecl *s1: pointer to output vector s1 + * - const mld_polyveck *s2: pointer to output vector s2 + * - uint8_t sk[]: byte array containing bit-packed sk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +__contract__( + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(key, MLDSA_SEEDBYTES)) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(s1, sizeof(mld_polyvecl))) + assigns(memory_slice(s2, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_unpack_sig MLD_NAMESPACE_KL(unpack_sig) +/************************************************* + * Name: mld_unpack_sig + * + * Description: Unpack signature sig = (c, z, h). + * + * Arguments: - uint8_t *c: pointer to output challenge hash + * - mld_polyvecl *z: pointer to output vector z + * - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t sig[]: byte array containing + * bit-packed signature + * + * Returns 1 in case of malformed signature; otherwise 0. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(c, MLDSA_CTILDEBYTES)) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(z->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +); +#endif /* !MLD_PACKING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/params.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/params.h new file mode 100644 index 0000000000..c67d2a33fb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/params.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PARAMS_H +#define MLD_PARAMS_H + +#define MLDSA_SEEDBYTES 32 +#define MLDSA_CRHBYTES 64 +#define MLDSA_TRBYTES 64 +#define MLDSA_RNDBYTES 32 +#define MLDSA_N 256 +#define MLDSA_Q 8380417 +#define MLDSA_Q_HALF ((MLDSA_Q + 1) / 2) +#define MLDSA_D 13 + +#if MLD_CONFIG_PARAMETER_SET == 44 + +#define MLDSA_K 4 +#define MLDSA_L 4 +#define MLDSA_ETA 2 +#define MLDSA_TAU 39 +#define MLDSA_BETA 78 +#define MLDSA_GAMMA1 (1 << 17) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 88) +#define MLDSA_OMEGA 80 +#define MLDSA_CTILDEBYTES 32 +#define MLDSA_POLYZ_PACKEDBYTES 576 +#define MLDSA_POLYW1_PACKEDBYTES 192 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#elif MLD_CONFIG_PARAMETER_SET == 65 + +#define MLDSA_K 6 +#define MLDSA_L 5 +#define MLDSA_ETA 4 +#define MLDSA_TAU 49 +#define MLDSA_BETA 196 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 55 +#define MLDSA_CTILDEBYTES 48 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 128 + +#elif MLD_CONFIG_PARAMETER_SET == 87 + +#define MLDSA_K 8 +#define MLDSA_L 7 +#define MLDSA_ETA 2 +#define MLDSA_TAU 60 +#define MLDSA_BETA 120 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 75 +#define MLDSA_CTILDEBYTES 64 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ + +#define MLDSA_POLYT1_PACKEDBYTES 320 +#define MLDSA_POLYT0_PACKEDBYTES 416 +#define MLDSA_POLYVECH_PACKEDBYTES (MLDSA_OMEGA + MLDSA_K) + +#define MLDSA_CRYPTO_PUBLICKEYBYTES \ + (MLDSA_SEEDBYTES + MLDSA_K * MLDSA_POLYT1_PACKEDBYTES) +#define MLDSA_CRYPTO_SECRETKEYBYTES \ + (2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + MLDSA_L * MLDSA_POLYETA_PACKEDBYTES + \ + MLDSA_K * MLDSA_POLYETA_PACKEDBYTES + MLDSA_K * MLDSA_POLYT0_PACKEDBYTES) +#define MLDSA_CRYPTO_BYTES \ + (MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES + \ + MLDSA_POLYVECH_PACKEDBYTES) + +#endif /* !MLD_PARAMS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/poly.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/poly.c new file mode 100644 index 0000000000..e40534e773 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/poly.c @@ -0,0 +1,973 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "common.h" +#include "ct.h" +#include "debug.h" +#include "poly.h" +#include "reduce.h" +#include "rounding.h" +#include "symmetric.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +#include "zetas.inc" + +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + { + a->coeffs[i] = mld_reduce32(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_STATIC_TESTABLE void mld_poly_caddq_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + ) + { + a->coeffs[i] = mld_caddq(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_POLY_CADDQ) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_poly_caddq_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + mld_poly_caddq_c(a); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1])) + invariant(forall(k2, 0, i, r->coeffs[k2] < MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k2, 0, i, r->coeffs[k2] >= INT32_MIN)) + ) + { + r->coeffs[i] = r->coeffs[i] + b->coeffs[i]; + } +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(r->coeffs, 0, i, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + ) + { + r->coeffs[i] = r->coeffs[i] - b->coeffs[i]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N; i++) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))) + { + /* Reference: uses a left shift by MLDSA_D which is undefined behaviour in + * C90/C99 + */ + a->coeffs[i] *= (1 << MLDSA_D); + } + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + + +static MLD_INLINE int32_t mld_fqmul(int32_t a, int32_t b) +__contract__( + requires(b > -MLDSA_Q_HALF && b < MLDSA_Q_HALF) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* Bounds: We argue in mld_montgomery_reduce() that the reult + * of Montgomery reduction is < MLDSA_Q if the input is smaller + * than 2^31 * MLDSA_Q in absolute value. Indeed, we have: + * + * |a * b| = |a| * |b| + * < 2^31 * MLDSA_Q_HALF + * < 2^31 * MLDSA_Q + */ + return mld_montgomery_reduce((int64_t)a * (int64_t)b); +} + +/* mld_ntt_butterfly_block() + * + * Computes a block CT butterflies with a fixed twiddle factor, + * using Montgomery multiplication. + * + * Parameters: + * - r: Pointer to base of polynomial (_not_ the base of butterfly block) + * - zeta: Twiddle factor to use for the butterfly. This must be in + * Montgomery form and signed canonical. + * - start: Offset to the beginning of the butterfly block + * - len: Index difference between coefficients subject to a butterfly + * - bound: Ghost variable describing coefficient bound: Prior to `start`, + * coefficients must be bound by `bound + MLDSA_Q`. Post `start`, + * they must be bound by `bound`. + * When this function returns, output coefficients in the index range + * [start, start+2*len) have bound bumped to `bound + MLDSA_Q`. + * Example: + * - start=8, len=4 + * This would compute the following four butterflies + * 8 -- 12 + * 9 -- 13 + * 10 -- 14 + * 11 -- 15 + * - start=4, len=2 + * This would compute the following two butterflies + * 4 -- 6 + * 5 -- 7 + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_butterfly_block(int32_t r[MLDSA_N], + const int32_t zeta, + const unsigned start, + const unsigned len, + const unsigned bound) +__contract__( + requires(start < MLDSA_N) + requires(1 <= len && len <= MLDSA_N / 2 && start + 2 * len <= MLDSA_N) + requires(0 <= bound && bound < INT32_MAX - MLDSA_Q) + requires(-MLDSA_Q_HALF < zeta && zeta < MLDSA_Q_HALF) + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, start, bound + MLDSA_Q)) + requires(array_abs_bound(r, start, MLDSA_N, bound)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, start + 2*len, bound + MLDSA_Q)) + ensures(array_abs_bound(r, start + 2 * len, MLDSA_N, bound))) +{ + /* `bound` is a ghost variable only needed in the CBMC specification */ + unsigned j; + ((void)bound); + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + /* + * Coefficients are updated in strided pairs, so the bounds for the + * intermediate states alternate twice between the old and new bound + */ + invariant(array_abs_bound(r, 0, j, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, bound)) + invariant(array_abs_bound(r, start + len, j + len, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j + len, MLDSA_N, bound))) + { + int32_t t; + t = mld_fqmul(r[j + len], zeta); + r[j + len] = r[j] - t; + r[j] = r[j] + t; + } +} + +/* mld_ntt_layer() + * + * Compute one layer of forward NTT + * + * Parameters: + * - r: Pointer to base of polynomial + * - layer: Indicates which layer is being applied. + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_layer(int32_t r[MLDSA_N], const unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (layer + 1) * MLDSA_Q))) +{ + unsigned start, k, len; + /* Twiddle factors for layer n are at indices 2^(n-1)..2^n-1. */ + k = 1u << (layer - 1); + len = (unsigned)MLDSA_N >> layer; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start < MLDSA_N + 2 * len) + invariant(k <= MLDSA_N) + invariant(2 * len * k == start + MLDSA_N) + invariant(array_abs_bound(r, 0, start, layer * MLDSA_Q + MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, layer * MLDSA_Q))) + { + int32_t zeta = mld_zetas[k++]; + mld_ntt_butterfly_block(r, zeta, start, len, layer * MLDSA_Q); + } +} + +MLD_STATIC_TESTABLE void mld_poly_ntt_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +) +{ + unsigned int layer; + int32_t *r; + + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + r = a->coeffs; + + for (layer = 1; layer < 9; layer++) + __loop__( + invariant(1 <= layer && layer <= 9) + invariant(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + ) + { + mld_ntt_layer(r, layer); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_NTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_ntt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_NTT */ + mld_poly_ntt_c(a); +} + +/************************************************* + * Name: mld_fqscale + * + * Description: Scales a field element by mont/256 , i.e., performs Montgomery + * multiplication by mont^2/256. + * Input is expected to have absolute value smaller than + * 256 * MLDSA_Q. + * Output has absolute value smaller than MLD_INTT_BOUND. + * + * Arguments: - int32_t a: Field element to be scaled. + **************************************************/ +static MLD_INLINE int32_t mld_fqscale(int32_t a) +__contract__( + requires(a > -256*MLDSA_Q && a < 256*MLDSA_Q) + ensures(return_value > -MLD_INTT_BOUND && return_value < MLD_INTT_BOUND) +) +{ + /* check-magic: 41978 == pow(2,64-8,MLDSA_Q) */ + const int32_t f = 41978; + /* Bounds: MLD_INTT_BOUND is MLDSA_Q, so the bounds reasoning is just + * a special case of that in mld_fqmul(). */ + return mld_montgomery_reduce((int64_t)a * f); +} + +/* Reference: Embedded into `invntt_tomont()` in the reference implementation + * @[REF] */ +static MLD_INLINE void mld_invntt_layer(int32_t r[MLDSA_N], unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> (layer - 1)) * MLDSA_Q))) +{ + unsigned start, k, len; + len = (unsigned)MLDSA_N >> layer; + k = (1u << layer) - 1; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start <= MLDSA_N && k <= 255) + invariant(2 * len * k + start == 2 * MLDSA_N - 2 * len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + unsigned j; + int32_t zeta = -mld_zetas[k--]; + + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, j, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, (MLDSA_N >> layer) * MLDSA_Q)) + invariant(array_abs_bound(r, start + len, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + int32_t t = r[j]; + r[j] = t + r[j + len]; + r[j + len] = t - r[j + len]; + r[j + len] = mld_fqmul(r[j + len], zeta); + } + } +} + +MLD_STATIC_TESTABLE void mld_poly_invntt_tomont_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +) +{ + unsigned int layer, j; + int32_t *r; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + r = a->coeffs; + for (layer = 8; layer >= 1; layer--) + __loop__( + invariant(layer <= 8) + /* Absolute bounds increase from 1Q before layer 8 */ + /* up to 256Q after layer 1 */ + invariant(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + mld_invntt_layer(r, layer); + } + + /* Coefficient bounds are now at 256Q. We now scale by mont / 256, + * i.e., compute the Montgomery multiplication by mont^2 / 256. + * mont corrects the mont^-1 factor introduced in the basemul. + * 1/256 performs that scaling of the inverse NTT. + * The reduced value is bounded by MLD_INTT_BOUND in absolute + * value.*/ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + invariant(j <= MLDSA_N) + invariant(array_abs_bound(r, 0, j, MLD_INTT_BOUND)) + invariant(array_abs_bound(r, j, MLDSA_N, MLDSA_N * MLDSA_Q)) + ) + { + r[j] = mld_fqscale(r[j]); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); +} + + +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_INTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_intt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_INTT */ + mld_poly_invntt_tomont_c(a); +} + +MLD_STATIC_TESTABLE void mld_poly_pointwise_montgomery_c(mld_poly *c, + const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_abs_bound(c->coeffs, 0, i, MLDSA_Q)) + ) + { + c->coeffs[i] = mld_montgomery_reduce((int64_t)a->coeffs[i] * b->coeffs[i]); + } + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +{ +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + ret = mld_poly_pointwise_montgomery_native(c->coeffs, a->coeffs, b->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + mld_poly_pointwise_montgomery_c(c, a, b); +} + +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, 0, i, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + invariant(array_bound(a1->coeffs, 0, i, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) + ) + { + mld_power2round(&a0->coeffs[i], &a1->coeffs[i], a->coeffs[i]); + } + + mld_assert_bound(a0->coeffs, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +#ifndef MLD_POLY_UNIFORM_NBLOCKS +#define MLD_POLY_UNIFORM_NBLOCKS \ + ((768 + MLD_STREAM128_BLOCKBYTES - 1) / MLD_STREAM128_BLOCKBYTES) +#endif +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +MLD_STATIC_TESTABLE unsigned int mld_rej_uniform_c(int32_t *a, + unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ + unsigned int ctr, pos; + uint32_t t; + mld_assert_bound(a, offset, 0, MLDSA_Q); + + ctr = offset; + pos = 0; + /* pos + 3 cannot overflow due to the assumption + buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) */ + while (ctr < target && pos + 3 <= buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_bound(a, 0, ctr, 0, MLDSA_Q))) + { + t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + a[ctr++] = (int32_t)t; + } + } + + mld_assert_bound(a, ctr, 0, MLDSA_Q); + + return ctr; +} +/************************************************* + * Name: mld_rej_uniform + * + * Description: Sample uniformly random coefficients in [0, MLDSA_Q-1] by + * performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes (must be + * multiple of 3) + * + * Returns number of sampled coefficients. Can be smaller than len if not enough + * random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +static unsigned int mld_rej_uniform(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) + int ret; + mld_assert_bound(a, offset, 0, MLDSA_Q); + if (offset == 0) + { + ret = mld_rej_uniform_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_bound(a, res, 0, MLDSA_Q); + return res; + } + } +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + + return mld_rej_uniform_c(a, target, offset, buf, buflen); +} + +/* Reference: poly_uniform() in the reference implementation @[REF]. + * - Simplified from reference by removing buffer tail handling + * since buflen % 3 = 0 always holds true (MLD_STREAM128_BLOCKBYTES + * = 168). + * - Modified rej_uniform interface to track offset directly. + * - Pass nonce packed in the extended seed array instead of a third + * argument. + * */ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +{ + unsigned int ctr; + unsigned int buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + MLD_ALIGN uint8_t buf[MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES]; + mld_xof128_ctx state; + + mld_xof128_init(&state); + mld_xof128_absorb_once(&state, seed, MLDSA_SEEDBYTES + 2); + mld_xof128_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, 0, buf, buflen); + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(a, sizeof(mld_poly)), object_whole(buf)) + invariant(ctr <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, ctr, 0, MLDSA_Q)) + invariant(state.pos <= SHAKE128_RATE) + ) + { + mld_xof128_squeezeblocks(buf, 1, &state); + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, ctr, buf, buflen); + } + mld_xof128_release(&state); + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof128_x4_ctx state; + unsigned buflen; + + mld_xof128_x4_init(&state); + mld_xof128_x4_absorb(&state, seed, MLDSA_SEEDBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_NBLOCKS. + * This should generate the matrix entries with high probability. + */ + + mld_xof128_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all matrix entries have been generated, squeeze + * one more block a time until we're done. + */ + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, object_whole(buf), + memory_slice(vec0, sizeof(mld_poly)), memory_slice(vec1, sizeof(mld_poly)), + memory_slice(vec2, sizeof(mld_poly)), memory_slice(vec3, sizeof(mld_poly))) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_bound(vec0->coeffs, 0, ctr[0], 0, MLDSA_Q)) + invariant(array_bound(vec1->coeffs, 0, ctr[1], 0, MLDSA_Q)) + invariant(array_bound(vec2->coeffs, 0, ctr[2], 0, MLDSA_Q)) + invariant(array_bound(vec3->coeffs, 0, ctr[3], 0, MLDSA_Q))) + { + mld_xof128_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + mld_xof128_x4_release(&state); + + mld_assert_bound(vec0->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec1->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec2->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec3->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0) & 0xFF); + r[5 * i + 1] = + (uint8_t)(((a->coeffs[4 * i + 0] >> 8) | (a->coeffs[4 * i + 1] << 2)) & + 0xFF); + r[5 * i + 2] = + (uint8_t)(((a->coeffs[4 * i + 1] >> 6) | (a->coeffs[4 * i + 2] << 4)) & + 0xFF); + r[5 * i + 3] = + (uint8_t)(((a->coeffs[4 * i + 2] >> 4) | (a->coeffs[4 * i + 3] << 6)) & + 0xFF); + r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, 0, 1 << 10))) + { + r->coeffs[4 * i + 0] = + ((a[5 * i + 0] >> 0) | ((int32_t)a[5 * i + 1] << 8)) & 0x3FF; + r->coeffs[4 * i + 1] = + ((a[5 * i + 1] >> 2) | ((int32_t)a[5 * i + 2] << 6)) & 0x3FF; + r->coeffs[4 * i + 2] = + ((a[5 * i + 2] >> 4) | ((int32_t)a[5 * i + 3] << 4)) & 0x3FF; + r->coeffs[4 * i + 3] = + ((a[5 * i + 3] >> 6) | ((int32_t)a[5 * i + 4] << 2)) & 0x3FF; + } + + mld_assert_bound(r->coeffs, MLDSA_N, 0, 1 << 10); +} + +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[8]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* Safety: a->coeffs[i] <= (1 << (MLDSA_D - 1) as they are output of + * power2round, hence, these casts are safe. */ + t[0] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 0]); + t[1] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 1]); + t[2] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 2]); + t[3] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 3]); + t[4] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 4]); + t[5] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 5]); + t[6] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 6]); + t[7] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 7]); + + r[13 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[13 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[13 * i + 1] |= (uint8_t)((t[1] << 5) & 0xFF); + r[13 * i + 2] = (uint8_t)((t[1] >> 3) & 0xFF); + r[13 * i + 3] = (uint8_t)((t[1] >> 11) & 0xFF); + r[13 * i + 3] |= (uint8_t)((t[2] << 2) & 0xFF); + r[13 * i + 4] = (uint8_t)((t[2] >> 6) & 0xFF); + r[13 * i + 4] |= (uint8_t)((t[3] << 7) & 0xFF); + r[13 * i + 5] = (uint8_t)((t[3] >> 1) & 0xFF); + r[13 * i + 6] = (uint8_t)((t[3] >> 9) & 0xFF); + r[13 * i + 6] |= (uint8_t)((t[4] << 4) & 0xFF); + r[13 * i + 7] = (uint8_t)((t[4] >> 4) & 0xFF); + r[13 * i + 8] = (uint8_t)((t[4] >> 12) & 0xFF); + r[13 * i + 8] |= (uint8_t)((t[5] << 1) & 0xFF); + r[13 * i + 9] = (uint8_t)((t[5] >> 7) & 0xFF); + r[13 * i + 9] |= (uint8_t)((t[6] << 6) & 0xFF); + r[13 * i + 10] = (uint8_t)((t[6] >> 2) & 0xFF); + r[13 * i + 11] = (uint8_t)((t[6] >> 10) & 0xFF); + r[13 * i + 11] |= (uint8_t)((t[7] << 3) & 0xFF); + r[13 * i + 12] = (uint8_t)((t[7] >> 5) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + { + r->coeffs[8 * i + 0] = a[13 * i + 0]; + r->coeffs[8 * i + 0] |= (int32_t)a[13 * i + 1] << 8; + r->coeffs[8 * i + 0] &= 0x1FFF; + + r->coeffs[8 * i + 1] = a[13 * i + 1] >> 5; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 2] << 3; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 3] << 11; + r->coeffs[8 * i + 1] &= 0x1FFF; + + r->coeffs[8 * i + 2] = a[13 * i + 3] >> 2; + r->coeffs[8 * i + 2] |= (int32_t)a[13 * i + 4] << 6; + r->coeffs[8 * i + 2] &= 0x1FFF; + + r->coeffs[8 * i + 3] = a[13 * i + 4] >> 7; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 5] << 1; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 6] << 9; + r->coeffs[8 * i + 3] &= 0x1FFF; + + r->coeffs[8 * i + 4] = a[13 * i + 6] >> 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 7] << 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 8] << 12; + r->coeffs[8 * i + 4] &= 0x1FFF; + + r->coeffs[8 * i + 5] = a[13 * i + 8] >> 1; + r->coeffs[8 * i + 5] |= (int32_t)a[13 * i + 9] << 7; + r->coeffs[8 * i + 5] &= 0x1FFF; + + r->coeffs[8 * i + 6] = a[13 * i + 9] >> 6; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 10] << 2; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 11] << 10; + r->coeffs[8 * i + 6] &= 0x1FFF; + + r->coeffs[8 * i + 7] = a[13 * i + 11] >> 3; + r->coeffs[8 * i + 7] |= (int32_t)a[13 * i + 12] << 5; + r->coeffs[8 * i + 7] &= 0x1FFF; + + r->coeffs[8 * i + 0] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 7]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +MLD_STATIC_TESTABLE uint32_t mld_poly_chknorm_c(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == array_abs_bound(a->coeffs, 0, i, B)) + ) + { + /* + * Since we know that -MLD_REDUCE32_RANGE_MAX <= a < MLD_REDUCE32_RANGE_MAX, + * and B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX, to check if + * -B < (a mod± MLDSA_Q) < B, it suffices to check if -B < a < B. + * + * We prove this to be true using the following CBMC assertions. + * a ==> b expressed as !a || b to also allow run-time assertion. + */ + mld_assert(a->coeffs[i] < B || a->coeffs[i] - MLDSA_Q <= -B); + mld_assert(a->coeffs[i] > -B || a->coeffs[i] + MLDSA_Q >= B); + + /* Reference: Leaks which coefficient violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + + /* if (abs(a[i]) >= B) */ + t |= mld_ct_cmask_neg_i32(B - 1 - mld_ct_abs_i32(a->coeffs[i])); + } + + return t; +} + +/* Reference: explicitly checks the bound B to be <= (MLDSA_Q - 1) / 8). + * This is unnecessary as it's always a compile-time constant. + * We instead model it as a precondition. + * Checking the bound is performed using a conditional arguing + * that it is okay to leak which coefficient violates the bound (while the + * coefficient itself must remain secret). + * We instead perform everything in constant-time. + * Also it is sufficient to check that it is smaller than + * MLDSA_Q - MLD_REDUCE32_RANGE_MAX > (MLDSA_Q - 1) / 8). + */ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +{ +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) + int ret; + int success; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + /* The native backend returns 0 if all coefficients are within the bound, + * 1 if at least one coefficient exceeds the bound, and + * -1 (MLD_NATIVE_FUNC_FALLBACK) if the platform does not have the + * required capabilities to run the native function. + */ + ret = mld_poly_chknorm_native(a->coeffs, B); + + success = (ret != MLD_NATIVE_FUNC_FALLBACK); + /* Constant-time: It would be fine to leak the return value of chknorm + * entirely (as it is fine to leak if any coefficient exceeded the bound or + * not). However, it is cleaner to perform declassification in sign.c. + * Hence, here we only declassify if the native function returned + * MLD_NATIVE_FUNC_FALLBACK or not (which solely depends on system + * capabilities). + */ + MLD_CT_TESTING_DECLASSIFY(&success, sizeof(int)); + if (success) + { + /* Convert 0 / 1 to 0 / 0xFFFFFFFF here */ + return 0U - (uint32_t)ret; + } +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + return mld_poly_chknorm_c(a, B); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ +MLD_EMPTY_CU(mld_poly) +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_POLY_UNIFORM_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/poly.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/poly.h new file mode 100644 index 0000000000..ff7710438e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/poly.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_H +#define MLD_POLY_H + +#include +#include "cbmc.h" +#include "common.h" +#include "reduce.h" +#include "rounding.h" + +/* Absolute exclusive upper bound for the output of the forward NTT */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) +/* Absolute exclusive upper bound for the output of the inverse NTT*/ +#define MLD_INTT_BOUND MLDSA_Q + +typedef struct +{ + int32_t coeffs[MLDSA_N]; +} MLD_ALIGN mld_poly; + +#define mld_poly_reduce MLD_NAMESPACE(poly_reduce) +/************************************************* + * Name: mld_poly_reduce + * + * Description: Inplace reduction of all coefficients of polynomial to + * representative in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) +); + +#define mld_poly_caddq MLD_NAMESPACE(poly_caddq) +/************************************************* + * Name: mld_poly_caddq + * + * Description: For all coefficients of in/out polynomial add MLDSA_Q if + * coefficient is negative. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_add MLD_NAMESPACE(poly_add) +/************************************************* + * Name: mld_poly_add + * + * Description: Add polynomials. No modular reduction is performed. + * + * Arguments: - r: Pointer to input-output polynomial to be added to. + * - b: Pointer to input polynomial that should be added + * to r. Must be disjoint from r. + **************************************************/ + +/* + * NOTE: The reference implementation uses a 3-argument poly_add. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(forall(k0, 0, MLDSA_N, (int64_t) r->coeffs[k0] + b->coeffs[k0] < MLD_REDUCE32_DOMAIN_MAX)) + requires(forall(k1, 0, MLDSA_N, (int64_t) r->coeffs[k1] + b->coeffs[k1] >= INT32_MIN)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(forall(k2, 0, MLDSA_N, r->coeffs[k2] == old(*r).coeffs[k2] + b->coeffs[k2])) + ensures(forall(k3, 0, MLDSA_N, r->coeffs[k3] < MLD_REDUCE32_DOMAIN_MAX)) + ensures(forall(k4, 0, MLDSA_N, r->coeffs[k4] >= INT32_MIN)) +); + +#define mld_poly_sub MLD_NAMESPACE(poly_sub) +/************************************************* + * Name: mld_poly_sub + * + * Description: Subtract polynomials. No modular reduction is + * performed. + * + * Arguments: - mld_poly *r: Pointer to input-output polynomial. + * - const mld_poly *b: Pointer to input polynomial that should be + * subtracted from r. Must be disjoint from r. + **************************************************/ +/* + * NOTE: The reference implementation uses a 3-argument poly_sub. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_Q)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) +); + +#define mld_poly_shiftl MLD_NAMESPACE(poly_shiftl) +/************************************************* + * Name: mld_poly_shiftl + * + * Description: Multiply polynomial by 2^MLDSA_D without modular reduction. + *Assumes input coefficients to be less than 2^{31-MLDSA_D} in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_ntt MLD_NAMESPACE(poly_ntt) +/************************************************* + * Name: mld_poly_ntt + * + * Description: Inplace forward NTT. Coefficients can grow by + * 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +); + + +#define mld_poly_invntt_tomont MLD_NAMESPACE(poly_invntt_tomont) +/************************************************* + * Name: mld_poly_invntt_tomont + * + * Description: Inplace inverse NTT and multiplication by 2^{32}. + * Input coefficients need to be less than MLDSA_Q in absolute + * value and output coefficients are bounded by + * MLD_INTT_BOUND. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +); + +#define mld_poly_pointwise_montgomery MLD_NAMESPACE(poly_pointwise_montgomery) +/************************************************* + * Name: mld_poly_pointwise_montgomery + * + * Description: Pointwise multiplication of polynomials in NTT domain + * representation and multiplication of resulting polynomial + * by 2^{-32}. + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const mld_poly *a: pointer to first input polynomial + * - const mld_poly *b: pointer to second input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + +#define mld_poly_power2round MLD_NAMESPACE(poly_power2round) +/************************************************* + * Name: mld_poly_power2round + * + * Description: For all coefficients c of the input polynomial, + * compute c0, c1 such that c mod MLDSA_Q = c1*2^MLDSA_D + c0 + * with -2^{MLDSA_D-1} < c0 <= 2^{MLDSA_D-1}. Assumes coefficients + *to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + *c1 + * - mld_poly *a0: pointer to output polynomial with coefficients + *c0 + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +__contract__( + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a0->coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) +); + +#define mld_poly_uniform MLD_NAMESPACE(poly_uniform) +/************************************************* + * Name: mld_poly_uniform + * + * Description: Sample polynomial with uniformly random coefficients + * in [0,MLDSA_Q-1] by performing rejection sampling on the + * output stream of SHAKE128(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_SEEDBYTES and the packed 2-byte nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES + 2)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +#define mld_poly_uniform_4x MLD_NAMESPACE(poly_uniform_4x) +/************************************************* + * Name: mld_poly_uniform_x4 + * + * Description: Generate four polynomials using rejection sampling + * on (pseudo-)uniformly random bytes sampled from a seed. + * + * Arguments: - mld_poly *vec0, *vec1, *vec2, *vec3: + * Pointers to 4 polynomials to be sampled. + * - uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]: + * Pointer consecutive array of seed buffers of size + * MLDSA_SEEDBYTES + 2 each, plus padding for alignment. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +__contract__( + requires(memory_no_alias(vec0, sizeof(mld_poly))) + requires(memory_no_alias(vec1, sizeof(mld_poly))) + requires(memory_no_alias(vec2, sizeof(mld_poly))) + requires(memory_no_alias(vec3, sizeof(mld_poly))) + requires(memory_no_alias(seed, 4 * MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2))) + assigns(memory_slice(vec0, sizeof(mld_poly))) + assigns(memory_slice(vec1, sizeof(mld_poly))) + assigns(memory_slice(vec2, sizeof(mld_poly))) + assigns(memory_slice(vec3, sizeof(mld_poly))) + ensures(array_bound(vec0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec1->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec2->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec3->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +#define mld_polyt1_pack MLD_NAMESPACE(polyt1_pack) +/************************************************* + * Name: mld_polyt1_pack + * + * Description: Bit-pack polynomial t1 with coefficients fitting in 10 bits. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(r, MLDSA_POLYT1_PACKEDBYTES)) +); + +#define mld_polyt1_unpack MLD_NAMESPACE(polyt1_unpack) +/************************************************* + * Name: mld_polyt1_unpack + * + * Description: Unpack polynomial t1 with 10-bit coefficients. + * Output coefficients are standard representatives. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT1_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, 0, 1 << 10)) +); + +#define mld_polyt0_pack MLD_NAMESPACE(polyt0_pack) +/************************************************* + * Name: mld_polyt0_pack + * + * Description: Bit-pack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + * 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) + assigns(memory_slice(r, MLDSA_POLYT0_PACKEDBYTES)) +); + + +#define mld_polyt0_unpack MLD_NAMESPACE(polyt0_unpack) +/************************************************* + * Name: mld_polyt0_unpack + * + * Description: Unpack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + *2^{MLDSA_D-1}]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT0_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) +); + +#define mld_poly_chknorm MLD_NAMESPACE(poly_chknorm) +/************************************************* + * Name: mld_poly_chknorm + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const mld_poly *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if norm is strictly smaller than + * B <= (MLDSA_Q - MLD_REDUCE32_RANGE_MAX) and 0xFFFFFFFF otherwise. + * + * Specification: The definition of this FIPS-204 requires signed canonical + * reduction prior to applying the bounds check. + * However, `-B < (a mod± MLDSA_Q) < B` is equivalent to + * `-B < a < B` under the assumption that + * `B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX` (cf. the assertion in + * the code). Hence, the present spec and implementation are + * correct without reduction. + * + **************************************************/ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +); + +#endif /* !MLD_POLY_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/poly_kl.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/poly_kl.c new file mode 100644 index 0000000000..7a319ca515 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/poly_kl.c @@ -0,0 +1,931 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "ct.h" +#include "debug.h" +#include "poly_kl.h" +#include "rounding.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_rej_eta MLD_ADD_PARAM_SET(mld_rej_eta) +#define mld_rej_eta_c MLD_ADD_PARAM_SET(mld_rej_eta_c) +#define mld_poly_decompose_c MLD_ADD_PARAM_SET(mld_poly_decompose_c) +#define mld_poly_use_hint_c MLD_ADD_PARAM_SET(mld_poly_use_hint_c) +#define mld_polyz_unpack_c MLD_ADD_PARAM_SET(mld_polyz_unpack_c) +/* End of parameter set namespacing */ + + +MLD_STATIC_TESTABLE +void mld_poly_decompose_c(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +) +{ + unsigned int i; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, i, MLDSA_N, 0, MLDSA_Q)) + invariant(array_bound(a1->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + invariant(array_abs_bound(a0->coeffs, 0, i, MLDSA_GAMMA2+1)) + ) + { + mld_decompose(&a0->coeffs[i], &a1->coeffs[i], a0->coeffs[i]); + } + + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +{ +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_88_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_32_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_DECOMPOSE_88 && MLD_CONFIG_PARAMETER_SET == \ + 44) && MLD_USE_NATIVE_POLY_DECOMPOSE_32 && (MLD_CONFIG_PARAMETER_SET \ + == 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_decompose_c(a1, a0); +} + +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(s <= i) + invariant(array_bound(h->coeffs, 0, i, 0, 2)) + ) + { + const unsigned int hint_bit = mld_make_hint(a0->coeffs[i], a1->coeffs[i]); + h->coeffs[i] = (int32_t)hint_bit; + s += hint_bit; + } + + mld_assert(s <= MLDSA_N); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + return s; +} + +MLD_STATIC_TESTABLE void mld_poly_use_hint_c(mld_poly *b, const mld_poly *a, + const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(b->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ) + { + b->coeffs[i] = mld_use_hint(a->coeffs[i], h->coeffs[i]); + } + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +{ +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_88_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_USE_HINT_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_32_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_USE_HINT_88 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLY_USE_HINT_32 && (MLD_CONFIG_PARAMETER_SET == \ + 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_use_hint_c(b, a, h); +} + +/************************************************* + * Name: mld_rej_eta + * + * Description: Sample uniformly random coefficients in [-MLDSA_ETA, MLDSA_ETA] + *by performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes + * + * Returns number of sampled coefficients. Can be smaller than target if not + *enough random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_eta()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +#if MLDSA_ETA == 2 +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 1 +#elif MLDSA_ETA == 4 +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 2 +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + +MLD_STATIC_TESTABLE unsigned int mld_rej_eta_c(int32_t *a, unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ + unsigned int ctr, pos; + int t_valid; + uint32_t t0, t1; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + ctr = offset; + pos = 0; + while (ctr < target && pos < buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_abs_bound(a, 0, ctr, MLDSA_ETA + 1)) + ) + { + t0 = buf[pos] & 0x0F; + t1 = buf[pos++] >> 4; + + /* Constant time: The inputs and outputs to the rejection sampling are + * secret. However, it is fine to leak which coefficients have been + * rejected. For constant-time testing, we declassify the result of + * the comparison. + */ +#if MLDSA_ETA == 2 + t_valid = t0 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 15 */ + { + t0 = t0 - (205 * t0 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t0; + } + t_valid = t1 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) /* t1 < 15 */ + { + t1 = t1 - (205 * t1 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t1; + } +#elif MLDSA_ETA == 4 + t_valid = t0 < 9; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 9 */ + { + a[ctr++] = 4 - (int32_t)t0; + } + t_valid = t1 < 9; /* t1 < 9 */ + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) + { + a[ctr++] = 4 - (int32_t)t1; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + } + + mld_assert_abs_bound(a, ctr, MLDSA_ETA + 1); + + return ctr; +} + +static unsigned int mld_rej_eta(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ +#if MLDSA_ETA == 2 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta2_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#elif MLDSA_ETA == 4 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta4_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#endif /* !(MLDSA_ETA == 2 && MLD_USE_NATIVE_REJ_UNIFORM_ETA2) && MLDSA_ETA == \ + 4 && MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + + return mld_rej_eta_c(a, target, offset, buf, buflen); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_ETA_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof256_x4_ctx state; + unsigned buflen; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = nonce0; + extseed[1][MLDSA_CRHBYTES] = nonce1; + extseed[2][MLDSA_CRHBYTES] = nonce2; + extseed[3][MLDSA_CRHBYTES] = nonce3; + extseed[0][MLDSA_CRHBYTES + 1] = 0; + extseed[1][MLDSA_CRHBYTES + 1] = 0; + extseed[2][MLDSA_CRHBYTES + 1] = 0; + extseed[3][MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(r0, sizeof(mld_poly)), + memory_slice(r1, sizeof(mld_poly)), memory_slice(r2, sizeof(mld_poly)), + memory_slice(r3, sizeof(mld_poly)), object_whole(buf[0]), + object_whole(buf[1]), object_whole(buf[2]), + object_whole(buf[3])) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_abs_bound(r0->coeffs, 0, ctr[0], MLDSA_ETA + 1)) + invariant(array_abs_bound(r1->coeffs, 0, ctr[1], MLDSA_ETA + 1)) + invariant(array_abs_bound(r2->coeffs, 0, ctr[2], MLDSA_ETA + 1)) + invariant(array_abs_bound(r3->coeffs, 0, ctr[3], MLDSA_ETA + 1))) + { + mld_xof256_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + + mld_xof256_x4_release(&state); + + mld_assert_abs_bound(r0->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r1->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r2->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r3->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +{ + /* Temporary buffer for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr; + mld_xof256_ctx state; + unsigned buflen; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = nonce; + extseed[MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr = mld_rej_eta(r->coeffs, MLDSA_N, 0, buf, buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, object_whole(&state), + object_whole(buf), memory_slice(r, sizeof(mld_poly))) + invariant(ctr <= MLDSA_N) + invariant(state.pos <= SHAKE256_RATE) + invariant(array_abs_bound(r->coeffs, 0, ctr, MLDSA_ETA + 1))) + { + mld_xof256_squeezeblocks(buf, 1, &state); + ctr = mld_rej_eta(r->coeffs, MLDSA_N, ctr, buf, buflen); + } + + mld_xof256_release(&state); + + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define MLD_POLY_UNIFORM_GAMMA1_NBLOCKS \ + ((MLDSA_POLYZ_PACKEDBYTES + MLD_STREAM256_BLOCKBYTES - 1) / \ + MLD_STREAM256_BLOCKBYTES) + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + mld_xof256_ctx state; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = (uint8_t)(nonce & 0xFF); + extseed[MLDSA_CRHBYTES + 1] = (uint8_t)(nonce >> 8); + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + mld_polyz_unpack(a, buf); + + mld_xof256_release(&state); + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + mld_xof256_x4_ctx state; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = (uint8_t)(nonce0 & 0xFF); + extseed[1][MLDSA_CRHBYTES] = (uint8_t)(nonce1 & 0xFF); + extseed[2][MLDSA_CRHBYTES] = (uint8_t)(nonce2 & 0xFF); + extseed[3][MLDSA_CRHBYTES] = (uint8_t)(nonce3 & 0xFF); + extseed[0][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce0 >> 8); + extseed[1][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce1 >> 8); + extseed[2][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce2 >> 8); + extseed[3][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce3 >> 8); + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + + mld_polyz_unpack(r0, buf[0]); + mld_polyz_unpack(r1, buf[1]); + mld_polyz_unpack(r2, buf[2]); + mld_polyz_unpack(r3, buf[3]); + mld_xof256_x4_release(&state); + + mld_assert_bound(r0->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r1->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r2->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r3->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +{ + unsigned int i, j, pos; + uint64_t signs; + uint64_t offset; + MLD_ALIGN uint8_t buf[SHAKE256_RATE]; + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, seed, MLDSA_CTILDEBYTES); + mld_shake256_finalize(&state); + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + + /* Convert the first 8 bytes of buf[] into an unsigned 64-bit value. */ + /* Each bit of that dictates the sign of the resulting challenge value */ + signs = 0; + for (i = 0; i < 8; ++i) + __loop__( + assigns(i, signs) + invariant(i <= 8) + ) + { + signs |= (uint64_t)buf[i] << 8 * i; + } + pos = 8; + + mld_memset(c, 0, sizeof(mld_poly)); + + for (i = MLDSA_N - MLDSA_TAU; i < MLDSA_N; ++i) + __loop__( + assigns(i, j, object_whole(buf), state, pos, memory_slice(c, sizeof(mld_poly)), signs) + invariant(i >= MLDSA_N - MLDSA_TAU) + invariant(i <= MLDSA_N) + invariant(pos >= 1) + invariant(pos <= SHAKE256_RATE) + invariant(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) + invariant(state.pos <= SHAKE256_RATE) + ) + { + do + __loop__( + assigns(j, object_whole(buf), state, pos) + invariant(state.pos <= SHAKE256_RATE) + ) + { + if (pos >= SHAKE256_RATE) + { + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + pos = 0; + } + j = buf[pos++]; + } while (j > i); + + c->coeffs[i] = c->coeffs[j]; + + /* Reference: Compute coefficent value here in two steps to */ + /* mixinf unsigned and signed arithmetic with implicit */ + /* conversions, and so that CBMC can keep track of ranges */ + /* to complete type-safety proof here. */ + + /* The least-significant bit of signs tells us if we want -1 or +1 */ + offset = 2 * (signs & 1); + + /* offset has value 0 or 2 here, so (1 - (int32_t) offset) has + * value -1 or +1 */ + c->coeffs[j] = 1 - (int32_t)offset; + + /* Move to the next bit of signs for next time */ + signs >>= 1; + } + + mld_assert_bound(c->coeffs, MLDSA_N, -1, 2); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(&signs, sizeof(signs)); +} + +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint8_t t[8]; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_ETA + 1); + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 1]); + t[2] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 2]); + t[3] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 3]); + t[4] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 4]); + t[5] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 5]); + t[6] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 6]); + t[7] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 7]); + + r[3 * i + 0] = (uint8_t)(((t[0] >> 0) | (t[1] << 3) | (t[2] << 6)) & 0xFF); + r[3 * i + 1] = + (uint8_t)(((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)) & + 0xFF); + r[3 * i + 2] = (uint8_t)(((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)) & 0xFF); + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 1]); + r[i] = (uint8_t)(t[0] | (t[1] << 4)); + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ +} + +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -5, MLDSA_ETA + 1))) + { + r->coeffs[8 * i + 0] = (a[3 * i + 0] >> 0) & 7; + r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 7; + r->coeffs[8 * i + 2] = ((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 7; + r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 7; + r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 7; + r->coeffs[8 * i + 5] = ((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 7; + r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 7; + r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5) & 7; + + r->coeffs[8 * i + 0] = MLDSA_ETA - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = MLDSA_ETA - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = MLDSA_ETA - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = MLDSA_ETA - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = MLDSA_ETA - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = MLDSA_ETA - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = MLDSA_ETA - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = MLDSA_ETA - r->coeffs[8 * i + 7]; + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -11, MLDSA_ETA + 1))) + { + r->coeffs[2 * i + 0] = a[i] & 0x0F; + r->coeffs[2 * i + 1] = a[i] >> 4; + r->coeffs[2 * i + 0] = MLDSA_ETA - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_ETA - r->coeffs[2 * i + 1]; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + + mld_assert_bound(r->coeffs, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + + +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[4]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 1]); + t[2] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 2]); + t[3] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 3]); + + r[9 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[9 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[9 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[9 * i + 2] |= (uint8_t)((t[1] << 2) & 0xFF); + r[9 * i + 3] = (uint8_t)((t[1] >> 6) & 0xFF); + r[9 * i + 4] = (uint8_t)((t[1] >> 14) & 0xFF); + r[9 * i + 4] |= (uint8_t)((t[2] << 4) & 0xFF); + r[9 * i + 5] = (uint8_t)((t[2] >> 4) & 0xFF); + r[9 * i + 6] = (uint8_t)((t[2] >> 12) & 0xFF); + r[9 * i + 6] |= (uint8_t)((t[3] << 6) & 0xFF); + r[9 * i + 7] = (uint8_t)((t[3] >> 2) & 0xFF); + r[9 * i + 8] = (uint8_t)((t[3] >> 10) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 1]); + + r[5 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[5 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[5 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[5 * i + 2] |= (uint8_t)((t[1] << 4) & 0xFF); + r[5 * i + 3] = (uint8_t)((t[1] >> 4) & 0xFF); + r[5 * i + 4] = (uint8_t)((t[1] >> 12) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +MLD_STATIC_TESTABLE void mld_polyz_unpack_c( + mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +) +{ + unsigned int i; +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[4 * i + 0] = a[9 * i + 0]; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 2] << 16; + r->coeffs[4 * i + 0] &= 0x3FFFF; + + r->coeffs[4 * i + 1] = a[9 * i + 2] >> 2; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 3] << 6; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 4] << 14; + r->coeffs[4 * i + 1] &= 0x3FFFF; + + r->coeffs[4 * i + 2] = a[9 * i + 4] >> 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 5] << 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 6] << 12; + r->coeffs[4 * i + 2] &= 0x3FFFF; + + r->coeffs[4 * i + 3] = a[9 * i + 6] >> 6; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 7] << 2; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10; + r->coeffs[4 * i + 3] &= 0x3FFFF; + + r->coeffs[4 * i + 0] = MLDSA_GAMMA1 - r->coeffs[4 * i + 0]; + r->coeffs[4 * i + 1] = MLDSA_GAMMA1 - r->coeffs[4 * i + 1]; + r->coeffs[4 * i + 2] = MLDSA_GAMMA1 - r->coeffs[4 * i + 2]; + r->coeffs[4 * i + 3] = MLDSA_GAMMA1 - r->coeffs[4 * i + 3]; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[2 * i + 0] = a[5 * i + 0]; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 2] << 16; + r->coeffs[2 * i + 0] &= 0xFFFFF; + + r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 3] << 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12; + /* r->coeffs[2*i+1] &= 0xFFFFF; */ /* No effect, since we're anyway at 20 + bits */ + + r->coeffs[2 * i + 0] = MLDSA_GAMMA1 - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_GAMMA1 - r->coeffs[2 * i + 1]; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +{ +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + ret = mld_polyz_unpack_17_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#elif defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + ret = mld_polyz_unpack_19_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYZ_UNPACK_17 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLYZ_UNPACK_19 && (MLD_CONFIG_PARAMETER_SET == 65 \ + || MLD_CONFIG_PARAMETER_SET == 87) */ + + mld_polyz_unpack_c(r, a); +} + +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + + mld_assert_bound(a->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[3 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0]) & 0xFF); + r[3 * i + 0] |= (uint8_t)((a->coeffs[4 * i + 1] << 6) & 0xFF); + r[3 * i + 1] = (uint8_t)((a->coeffs[4 * i + 1] >> 2) & 0xFF); + r[3 * i + 1] |= (uint8_t)((a->coeffs[4 * i + 2] << 4) & 0xFF); + r[3 * i + 2] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) & 0xFF); + r[3 * i + 2] |= (uint8_t)((a->coeffs[4 * i + 3] << 2) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + r[i] = + (uint8_t)((a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_rej_eta +#undef mld_rej_eta_c +#undef mld_poly_decompose_c +#undef mld_poly_use_hint_c +#undef mld_polyz_unpack_c +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_GAMMA1_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/poly_kl.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/poly_kl.h new file mode 100644 index 0000000000..c6aa498358 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/poly_kl.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_KL_H +#define MLD_POLY_KL_H + +#include "cbmc.h" +#include "common.h" +#include "poly.h" + +#define mld_poly_decompose MLD_NAMESPACE_KL(poly_decompose) +/************************************************* + * Name: mld_poly_decompose + * + * Description: For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such c mod MLDSA_Q = c1*ALPHA + + * c0 with -ALPHA/2 < c0 <= ALPHA/2 except + * c1 = (MLDSA_Q-1)/ALPHA where we set + * c1 = 0 and -ALPHA/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + * c1 + * - mld_poly *a0: pointer to input/output polynomial. Output + * polynomial has coefficients c0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +); + + +#define mld_poly_make_hint MLD_NAMESPACE_KL(poly_make_hint) +/************************************************* + * Name: mld_poly_make_hint + * + * Description: Compute hint polynomial. The coefficients of which indicate + * whether the low bits of the corresponding coefficient of + * the input polynomial overflow into the high bits. + * + * Arguments: - mld_poly *h: pointer to output hint polynomial + * - const mld_poly *a0: pointer to low part of input polynomial + * - const mld_poly *a1: pointer to high part of input polynomial + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + assigns(memory_slice(h, sizeof(mld_poly))) + ensures(return_value <= MLDSA_N) + ensures(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) +); + +#define mld_poly_use_hint MLD_NAMESPACE_KL(poly_use_hint) +/************************************************* + * Name: mld_poly_use_hint + * + * Description: Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - mld_poly *b: pointer to output polynomial with corrected high + *bits + * - const mld_poly *a: pointer to input polynomial + * - const mld_poly *h: pointer to input hint polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta_4x MLD_NAMESPACE_KL(poly_uniform_eta_4x) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample four polynomials with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce_i) + * + * Arguments: - mld_poly *r0: pointer to first output polynomial + * - mld_poly *r1: pointer to second output polynomial + * - mld_poly *r2: pointer to third output polynomial + * - mld_poly *r3: pointer to fourth output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce0: first nonce + * - uint8_t nonce1: second nonce + * - uint8_t nonce2: third nonce + * - uint8_t nonce3: fourth nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_abs_bound(r0->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r1->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r2->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r3->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta MLD_NAMESPACE_KL(poly_uniform_eta) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample polynomial with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce: nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1 MLD_NAMESPACE_KL(poly_uniform_gamma1) +/************************************************* + * Name: mld_poly_uniform_gamma1 + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1_4x MLD_NAMESPACE_KL(poly_uniform_gamma1_4x) +/************************************************* + * Name: mld_poly_uniform_gamma1_4x + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_bound(r0->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r1->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r2->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r3->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define mld_poly_challenge MLD_NAMESPACE_KL(poly_challenge) +/************************************************* + * Name: mld_poly_challenge + * + * Description: Implementation of H. Samples polynomial with MLDSA_TAU nonzero + * coefficients in {-1,1} using the output stream of + * SHAKE256(seed). + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const uint8_t mu[]: byte array containing seed of length + * MLDSA_CTILDEBYTES + **************************************************/ +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +__contract__( + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CTILDEBYTES)) + assigns(memory_slice(c, sizeof(mld_poly))) + /* All coefficients of c are -1, 0 or +1 */ + ensures(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) +); + +#define mld_polyeta_pack MLD_NAMESPACE_KL(polyeta_pack) +/************************************************* + * Name: mld_polyeta_pack + * + * Description: Bit-pack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYETA_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + assigns(memory_slice(r, MLDSA_POLYETA_PACKEDBYTES)) +); + +/* + * polyeta_unpack produces coefficients in [-MLDSA_ETA,MLDSA_ETA] for + * well-formed inputs (i.e., those produced by polyeta_pack). + * However, when passed an arbitrary byte array, it may produce smaller values, + * i.e, values in [MLD_POLYETA_UNPACK_LOWER_BOUND,MLDSA_ETA] + * Even though this should never happen, we use use the bound for arbitrary + * inputs in the CBMC proofs. + */ +#if MLDSA_ETA == 2 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-5) +#elif MLDSA_ETA == 4 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-11) +#else +#error "Invalid value of MLDSA_ETA" +#endif + +#define mld_polyeta_unpack MLD_NAMESPACE_KL(polyeta_unpack) +/************************************************* + * Name: mld_polyeta_unpack + * + * Description: Unpack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYETA_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)) +); + +#define mld_polyz_pack MLD_NAMESPACE_KL(polyz_pack) +/************************************************* + * Name: mld_polyz_pack + * + * Description: Bit-pack polynomial with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYZ_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(r, MLDSA_POLYZ_PACKEDBYTES)) +); + + +#define mld_polyz_unpack MLD_NAMESPACE_KL(polyz_unpack) +/************************************************* + * Name: mld_polyz_unpack + * + * Description: Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); + +#define mld_polyw1_pack MLD_NAMESPACE_KL(polyw1_pack) +/************************************************* + * Name: mld_polyw1_pack + * + * Description: Bit-pack polynomial w1 with coefficients in [0,15] or [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES)) +); + +#endif /* !MLD_POLY_KL_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/polyvec.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/polyvec.c new file mode 100644 index 0000000000..5c3a08ab32 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/polyvec.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include +#include + +#include "common.h" +#include "debug.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" + +/* This namespacing is not done at the top to avoid a naming conflict + * with native backends, which are currently not yet namespaced. */ +#define mld_polymat_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polymat_permute_bitrev_to_custom) +#define mld_polyvecl_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polyvecl_permute_bitrev_to_custom) +#define mld_polyvecl_pointwise_acc_montgomery_c \ + MLD_ADD_PARAM_SET(mld_polyvecl_pointwise_acc_montgomery_c) + +#if !defined(MLD_CONFIG_REDUCE_RAM) +/* Helper function to ensure that the polynomial entries in the output + * of mld_polyvec_matrix_expand use the standard (bitreversed) ordering + * of coefficients. + * No-op unless a native backend with a custom ordering is used. + */ + +static void mld_polyvecl_permute_bitrev_to_custom(mld_polyvecl *v) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +{ +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + unsigned i; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_permute_bitrev_to_custom(v->vec[i].coeffs); + } +#else /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + /* Nothing to do */ + (void)v; +#endif /* !MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ +} + +static void mld_polymat_permute_bitrev_to_custom(mld_polymat *mat) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; i++) + __loop__( + assigns(i, memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))) + { + mld_polyvecl_permute_bitrev_to_custom(&mat->vec[i]); + } +} +#endif /* !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + unsigned int i; + MLD_ALIGN uint8_t seed_ext[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + mld_memcpy(seed_ext, mat->rho, MLDSA_SEEDBYTES); + + /* Generate row on-demand */ + for (i = 0; i < MLDSA_L; i++) + { + uint8_t x = (uint8_t)row; + uint8_t y = (uint8_t)i; + + seed_ext[MLDSA_SEEDBYTES + 0] = y; + seed_ext[MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(&mat->row_buffer.vec[i], seed_ext); + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + mld_poly_permute_bitrev_to_custom(mat->row_buffer.vec[i].coeffs); +#endif + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); + + return &mat->row_buffer; +#else /* MLD_CONFIG_REDUCE_RAM */ + return &mat->vec[row]; +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + /* In REDUCE_RAM mode, just copy the seed for later on-demand generation */ + mld_memcpy(mat->rho, rho, MLDSA_SEEDBYTES); +#else + unsigned int i, j; + /* + * We generate four separate seed arrays rather than a single one to work + * around limitations in CBMC function contracts dealing with disjoint slices + * of the same parent object. + */ + + MLD_ALIGN uint8_t seed_ext[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + mld_memcpy(seed_ext[j], rho, MLDSA_SEEDBYTES); + } + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + /* Sample 4 matrix entries a time. */ + for (i = 0; i < (MLDSA_K * MLDSA_L / 4) * 4; i += 4) + __loop__( + assigns(i, j, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= (MLDSA_K * MLDSA_L / 4) * 4 && i % 4 == 0) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + uint8_t x = (uint8_t)((i + j) / MLDSA_L); + uint8_t y = (uint8_t)((i + j) % MLDSA_L); + + seed_ext[j][MLDSA_SEEDBYTES + 0] = y; + seed_ext[j][MLDSA_SEEDBYTES + 1] = x; + } + + mld_poly_uniform_4x(&mat->vec[i / MLDSA_L].vec[i % MLDSA_L], + &mat->vec[(i + 1) / MLDSA_L].vec[(i + 1) % MLDSA_L], + &mat->vec[(i + 2) / MLDSA_L].vec[(i + 2) % MLDSA_L], + &mat->vec[(i + 3) / MLDSA_L].vec[(i + 3) % MLDSA_L], + seed_ext); + } +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + i = 0; +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + /* Entries omitted by the batch-sampling are sampled individually. */ + while (i < MLDSA_K * MLDSA_L) + __loop__( + assigns(i, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K * MLDSA_L) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + uint8_t x = (uint8_t)(i / MLDSA_L); + uint8_t y = (uint8_t)(i % MLDSA_L); + mld_poly *this_poly = &mat->vec[i / MLDSA_L].vec[i % MLDSA_L]; + + seed_ext[0][MLDSA_SEEDBYTES + 0] = y; + seed_ext[0][MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(this_poly, seed_ext[0]); + i++; + } + + mld_polymat_permute_bitrev_to_custom(mat); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(t, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + const mld_polyvecl *row = mld_polymat_get_row(mat, i); + mld_polyvecl_pointwise_acc_montgomery(&t->vec[i], row, v); + } + + mld_assert_abs_bound_2d(t->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_L **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; +#endif + + /* Safety: nonce is at most ((UINT16_MAX - MLDSA_L) / MLDSA_L), and, hence, + * this cast is safe. See MLD_NONCE_UB comment in sign.c. */ + nonce = (uint16_t)(MLDSA_L * nonce); + /* Now, nonce <= UINT16_MAX - (MLDSA_L - 1), so the casts below are safe. */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_gamma1(&v->vec[i], seed, (uint16_t)(nonce + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLDSA_L == 4 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); +#elif MLDSA_L == 5 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); + mld_poly_uniform_gamma1(&v->vec[4], seed, (uint16_t)(nonce + 4)); +#elif MLDSA_L == 7 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], + &v->vec[3 /* irrelevant */], seed, nonce, + (uint16_t)(nonce + 1), (uint16_t)(nonce + 2), + 0xFF /* irrelevant */); + mld_poly_uniform_gamma1_4x(&v->vec[3], &v->vec[4], &v->vec[5], &v->vec[6], + seed, (uint16_t)(nonce + 3), (uint16_t)(nonce + 4), + (uint16_t)(nonce + 5), (uint16_t)(nonce + 6)); +#endif /* MLDSA_L == 7 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(k0, i, MLDSA_L, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_STATIC_TESTABLE void mld_polyvecl_pointwise_acc_montgomery_c( + mld_poly *w, const mld_polyvecl *u, const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i, j; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + for (i = 0; i < MLDSA_N; i++) + __loop__( + assigns(i, j, memory_slice(w, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_abs_bound(w->coeffs, 0, i, MLDSA_Q)) + ) + { + int64_t t = 0; + int32_t r; + for (j = 0; j < MLDSA_L; j++) + __loop__( + assigns(j, t) + invariant(j <= MLDSA_L) + invariant(t >= -(int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + invariant(t <= (int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + ) + { + t += (int64_t)u->vec[j].coeffs[i] * v->vec[j].coeffs[i]; + } + + r = mld_montgomery_reduce(t); + w->coeffs[i] = r; + } + + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +{ +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) && \ + MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l4_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) && \ + MLD_CONFIG_PARAMETER_SET == 65 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l5_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) && \ + MLD_CONFIG_PARAMETER_SET == 87 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l7_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 && \ + MLD_CONFIG_PARAMETER_SET == 44) && \ + !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 && \ + MLD_CONFIG_PARAMETER_SET == 65) && \ + MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 && \ + MLD_CONFIG_PARAMETER_SET == 87 */ + /* The first input is bounded by [0, Q-1] inclusive + * The second input is bounded by [-9Q+1, 9Q-1] inclusive . Hence, we can + * safely accumulate in 64-bits without intermediate reductions as + * MLDSA_L * (MLD_NTT_BOUND-1) * (Q-1) < INT64_MAX + * + * The worst case is ML-DSA-87: 7 * (9Q-1) * (Q-1) < 2**52 + * (and likewise for negative values) + */ + mld_polyvecl_pointwise_acc_montgomery_c(w, u, v); +} + +MLD_INTERNAL_API +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + invariant(i <= MLDSA_L) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + return t; +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_K **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k2, 0, i, + array_bound(v->vec[k2].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ) + { + mld_poly_reduce(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_caddq(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, + forall(k1, 0, MLDSA_N, u->vec[k0].coeffs[k1] == loop_entry(*u).vec[k0].coeffs[k1]))) + invariant(forall(k6, 0, i, array_bound(u->vec[k6].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + ) + { + mld_poly_add(&u->vec[i], &v->vec[i]); + } + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(u->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, u->vec[k1].coeffs[n1] == loop_entry(*u).vec[k1].coeffs[n1])))) + { + mld_poly_sub(&u->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, v->vec[k1].coeffs[n1] == loop_entry(*v).vec[k1].coeffs[n1]))) + ) + { + mld_poly_shiftl(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))) + { + mld_poly_invntt_tomont(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_INTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, array_abs_bound(r->vec[k2].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + mld_poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]); + } + mld_assert_abs_bound_2d(r->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + + return t; +} + +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + invariant(forall(k2, 0, i, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) + ) + { + mld_poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +{ + unsigned int i; + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + invariant(forall(k2, 0, i, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) + invariant(forall(k3, i, MLDSA_K, + array_bound(v0->vec[k3].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + ) + { + mld_poly_decompose(&v1->vec[i], &v0->vec[i]); + } + + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + mld_assert_abs_bound_2d(v0->vec, MLDSA_K, MLDSA_N, MLDSA_GAMMA2 + 1); +} + +MLD_INTERNAL_API +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, s, memory_slice(h, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(s <= i * MLDSA_N) + invariant(forall(k1, 0, i, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + s += mld_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]); + } + + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + return s; +} + +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *u, + const mld_polyveck *h) +{ + unsigned int i; + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(w, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)))) + ) + { + mld_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]); + } + + mld_assert_bound_2d(w->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +{ + unsigned int i; + mld_assert_bound_2d(w1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyw1_pack(&r[i * MLDSA_POLYW1_PACKEDBYTES], &w1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt0_pack(&r[i * MLDSA_POLYT0_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyz_unpack(&z->vec[i], r + i * MLDSA_POLYZ_PACKEDBYTES); + } + + mld_assert_bound_2d(z->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt0_unpack(&p->vec[i], r + i * MLDSA_POLYT0_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_polymat_permute_bitrev_to_custom +#undef mld_polyvecl_permute_bitrev_to_custom +#undef mld_polyvecl_pointwise_acc_montgomery_c diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/polyvec.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/polyvec.h new file mode 100644 index 0000000000..d21abc02ff --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/polyvec.h @@ -0,0 +1,725 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLYVEC_H +#define MLD_POLYVEC_H + +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "poly_kl.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_polyvecl MLD_ADD_PARAM_SET(mld_polyvecl) +#define mld_polyveck MLD_ADD_PARAM_SET(mld_polyveck) +#define mld_polymat MLD_ADD_PARAM_SET(mld_polymat) +/* End of parameter set namespacing */ + +/* Vectors of polynomials of length MLDSA_L */ +typedef struct +{ + mld_poly vec[MLDSA_L]; +} mld_polyvecl; + + +#define mld_polyvecl_uniform_gamma1 MLD_NAMESPACE_KL(polyvecl_uniform_gamma1) +/************************************************* + * Name: mld_polyvecl_uniform_gamma1 + * + * Description: Sample vector of polynomials with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_polyvecl *v: pointer to output vector + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + *************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + requires(nonce <= (UINT16_MAX - MLDSA_L) / MLDSA_L) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyvecl_ntt MLD_NAMESPACE_KL(polyvecl_ntt) +/************************************************* + * Name: mld_polyvecl_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_L. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyvecl *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k0, 0, MLDSA_L, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyvecl_pointwise_acc_montgomery \ + MLD_NAMESPACE_KL(polyvecl_pointwise_acc_montgomery) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery + * + * Description: Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * The first input "u" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * + * Arguments: - mld_poly *w: output polynomial + * - const mld_polyvecl *u: pointer to first input vector + * - const mld_polyvecl *v: pointer to second input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + + +#define mld_polyvecl_chknorm MLD_NAMESPACE_KL(polyvecl_chknorm) +/************************************************* + * Name: mld_polyvecl_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_L. + * Assumes input mld_polyvecl to be reduced by polyvecl_reduce(). + * + * Arguments: - const mld_polyvecl *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials is strictly smaller than B <= + * (MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +/* Vectors of polynomials of length MLDSA_K */ +typedef struct +{ + mld_poly vec[MLDSA_K]; +} mld_polyveck; + +/* Matrix of polynomials (K x L) */ +typedef struct +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + mld_polyvecl row_buffer; + uint8_t rho[MLDSA_SEEDBYTES]; +#else + mld_polyvecl vec[MLDSA_K]; +#endif +} mld_polymat; + +#define mld_polyveck_reduce MLD_NAMESPACE_KL(polyveck_reduce) +/************************************************* + * Name: polyveck_reduce + * + * Description: Reduce coefficients of polynomials in vector of length MLDSA_K + * to representatives in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) +); + +#define mld_polyveck_caddq MLD_NAMESPACE_KL(polyveck_caddq) +/************************************************* + * Name: mld_polyveck_caddq + * + * Description: For all coefficients of polynomials in vector of length MLDSA_K + * add MLDSA_Q if coefficient is negative. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_add MLD_NAMESPACE_KL(polyveck_add) +/************************************************* + * Name: mld_polyveck_add + * + * Description: Add vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to input-output vector of polynomials + * to be added to + * - const mld_polyveck *v: pointer to second input vector of + * polynomials + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(p0, 0, MLDSA_K, array_abs_bound(u->vec[p0].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) + requires(forall(p1, 0, MLDSA_K, + array_bound(v->vec[p1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(q2, 0, MLDSA_K, + array_bound(u->vec[q2].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_sub MLD_NAMESPACE_KL(polyveck_sub) +/************************************************* + * Name: mld_polyveck_sub + * + * Description: Subtract vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to first input vector + * - const mld_polyveck *v: pointer to second input vector to be + * subtracted from first input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(u->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_shiftl MLD_NAMESPACE_KL(polyveck_shiftl) +/************************************************* + * Name: mld_polyveck_shiftl + * + * Description: Multiply vector of polynomials of Length MLDSA_K by 2^MLDSA_D + *without modular reduction. Assumes input coefficients to be less than + *2^{31-MLDSA_D}. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_ntt MLD_NAMESPACE_KL(polyveck_ntt) +/************************************************* + * Name: mld_polyveck_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_K. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyveck_invntt_tomont MLD_NAMESPACE_KL(polyveck_invntt_tomont) +/************************************************* + * Name: mld_polyveck_invntt_tomont + * + * Description: Inverse NTT and multiplication by 2^{32} of polynomials + * in vector of length MLDSA_K. + * Input coefficients need to be less than MLDSA_Q, and + * Output coefficients are bounded by MLD_INTT_BOUND. + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) +); + +#define mld_polyveck_pointwise_poly_montgomery \ + MLD_NAMESPACE_KL(polyveck_pointwise_poly_montgomery) +/************************************************* + * Name: mld_polyveck_pointwise_poly_montgomery + * + * Description: Pointwise multiplication of a polynomial vector of length + * MLDSA_K by a single polynomial in NTT domain and multiplication + * of the resulting polynomial vector by 2^{-32}. + * + * Arguments: - mld_polyveck *r: pointer to output vector + * - mld_poly *a: pointer to input polynomial + * - mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(r, sizeof(mld_polyveck))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(r, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(r->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#define mld_polyveck_chknorm MLD_NAMESPACE_KL(polyveck_chknorm) +/************************************************* + * Name: mld_polyveck_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_K. + * Assumes input mld_polyveck to be reduced by polyveck_reduce(). + * + * Arguments: - const mld_polyveck *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials are strictly smaller than B <= + *(MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, + -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +#define mld_polyveck_power2round MLD_NAMESPACE_KL(polyveck_power2round) +/************************************************* + * Name: mld_polyveck_power2round + * + * Description: For all coefficients a of polynomials in vector of length + *MLDSA_K, compute a0, a1 such that a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with + *-2^{MLDSA_D-1} < a0 <= 2^{MLDSA_D-1}. Assumes coefficients to be standard + *representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to output vector of polynomials with + * coefficients a0 + * - const mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) +); + +#define mld_polyveck_decompose MLD_NAMESPACE_KL(polyveck_decompose) +/************************************************* + * Name: mld_polyveck_decompose + * + * Description: For all coefficients a of polynomials in vector of length + * MLDSA_K, compute high and low bits a0, a1 such a mod^+ MLDSA_Q = a1*ALPHA + * + a0 with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (MLDSA_Q-1)/ALPHA where we set + * a1 = 0 and -ALPHA/2 <= a0 = a mod MLDSA_Q - MLDSA_Q < 0. Assumes coefficients + * to be standard representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to input/output vector of + * polynomials with. Output polynomial has + * coefficients a0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v0->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + ensures(forall(k2, 0, MLDSA_K, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) +); + +#define mld_polyveck_make_hint MLD_NAMESPACE_KL(polyveck_make_hint) +/************************************************* + * Name: mld_polyveck_make_hint + * + * Description: Compute hint vector. + * + * Arguments: - mld_polyveck *h: pointer to output vector + * - const mld_polyveck *v0: pointer to low part of input vector + * - const mld_polyveck *v1: pointer to high part of input vector + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(return_value <= MLDSA_N * MLDSA_K) + ensures(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) +); + +#define mld_polyveck_use_hint MLD_NAMESPACE_KL(polyveck_use_hint) +/************************************************* + * Name: mld_polyveck_use_hint + * + * Description: Use hint vector to correct the high bits of input vector. + * + * Arguments: - mld_polyveck *w: pointer to output vector of polynomials with + * corrected high bits + * - const mld_polyveck *u: pointer to input vector + * - const mld_polyveck *h: pointer to input hint vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *v, + const mld_polyveck *h) +__contract__( + requires(memory_no_alias(w, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + assigns(memory_slice(w, sizeof(mld_polyveck))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) +); + +#define mld_polyveck_pack_w1 MLD_NAMESPACE_KL(polyveck_pack_w1) +/************************************************* + * Name: mld_polyveck_pack_w1 + * + * Description: Bit-pack polynomial vector w1 with coefficients in [0,15] or + * [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_K* MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_polyveck *a: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(w1, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(w1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) +); + +#define mld_polyveck_pack_eta MLD_NAMESPACE_KL(polyveck_pack_eta) +/************************************************* + * Name: mld_polyveck_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients + * in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyvecl_pack_eta MLD_NAMESPACE_KL(polyvecl_pack_eta) +/************************************************* + * Name: mld_polyvecl_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_L * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyveck_pack_t0 MLD_NAMESPACE_KL(polyveck_pack_t0) +/************************************************* + * Name: mld_polyveck_pack_t0 + * + * Description: Bit-pack polynomial vector to with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(p->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) +); + +#define mld_polyvecl_unpack_eta MLD_NAMESPACE_KL(polyvecl_unpack_eta) +/************************************************* + * Name: mld_polyvecl_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyvecl *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + assigns(memory_slice(p, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyvecl_unpack_z MLD_NAMESPACE_KL(polyvecl_unpack_z) +/************************************************* + * Name: mld_polyvecl_unpack_z + * + * Description: Unpack polynomial vector with coefficients in + * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_polyvecl *z: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(z->vec[k1].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyveck_unpack_eta MLD_NAMESPACE_KL(polyveck_unpack_eta) +/************************************************* + * Name: mld_polyveck_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyveck_unpack_t0 MLD_NAMESPACE_KL(polyveck_unpack_t0) +/************************************************* + * Name: mld_polyveck_unpack_t0 + * + * Description: Unpack polynomial vector with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) +); + +#define mld_polymat_get_row MLD_NAMESPACE_KL(polymat_get_row) +/************************************************* + * Name: mld_polymat_get_row + * + * Description: Retrieve a pointer to a specific row of the matrix. + * In MLD_CONFIG_REDUCE_RAM mode, generates the row on-demand. + * + * Arguments: - mld_polymat *mat: pointer to matrix + * - unsigned int row: row index (must be < MLDSA_K) + * + * Returns pointer to the row (mld_polyvecl) + **************************************************/ +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row); + +#define mld_polyvec_matrix_expand MLD_NAMESPACE_KL(polyvec_matrix_expand) +/************************************************* + * Name: mld_polyvec_matrix_expand + * + * Description: Implementation of ExpandA. Generates matrix A with uniformly + * random coefficients a_{i,j} by performing rejection + * sampling on the output stream of SHAKE128(rho|j|i) + * + * Arguments: - mld_polymat *mat: pointer to output matrix + * - const uint8_t rho[]: byte array containing seed rho + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +__contract__( + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +); + + + +#define mld_polyvec_matrix_pointwise_montgomery \ + MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery) +/************************************************* + * Name: mld_polyvec_matrix_pointwise_montgomery + * + * Description: Compute matrix-vector multiplication in NTT domain with + * pointwise multiplication and multiplication by 2^{-32}. + * Input matrix and vector must be in NTT domain representation. + * + * The first input "mat" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * Note: In MLD_CONFIG_REDUCE_RAM mode, mat cannot be const + * as rows are generated on-demand. + * + * Arguments: - mld_polyveck *t: pointer to output vector t + * - mld_polymat *mat: pointer to input matrix + * - const mld_polyvecl *v: pointer to input vector v + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(t, sizeof(mld_polyveck))) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(t, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#endif /* !MLD_POLYVEC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/randombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/randombytes.h new file mode 100644 index 0000000000..da55772419 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/randombytes.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_RANDOMBYTES_H +#define MLD_RANDOMBYTES_H + +#include +#include + +#include "cbmc.h" +#include "common.h" + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +#if !defined(MLD_CONFIG_CUSTOM_RANDOMBYTES) +MLD_MUST_CHECK_RETURN_VALUE +int randombytes(uint8_t *out, size_t outlen); +static MLD_INLINE int mld_randombytes(uint8_t *out, size_t outlen) +__contract__( + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) { return randombytes(out, outlen); } +#endif /* !MLD_CONFIG_CUSTOM_RANDOMBYTES */ +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ +#endif /* !MLD_RANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/reduce.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/reduce.h new file mode 100644 index 0000000000..413cf1829e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/reduce.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_REDUCE_H +#define MLD_REDUCE_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* check-magic: -4186625 == pow(2,32,MLDSA_Q) */ +#define MLD_MONT -4186625 + +/* Upper bound for domain of mld_reduce32() */ +#define MLD_REDUCE32_DOMAIN_MAX (INT32_MAX - (1 << 22)) + +/* Absolute bound for range of mld_reduce32() */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define MLD_REDUCE32_RANGE_MAX 6283009 + +/************************************************* + * Name: mld_montgomery_reduce + * + * Description: Generic Montgomery reduction; given a 64-bit integer a, computes + * 32-bit integer congruent to a * R^-1 mod q, where R=2^32 + * + * Arguments: - int64_t a: input integer to be reduced, of absolute value + * smaller or equal to INT64_MAX - 2^31 * MLDSA_Q. + * + * Returns: Integer congruent to a * R^-1 modulo q, with absolute value + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * In particular, if |a| < 2^31 * MLDSA_Q, the absolute value + * of the return value is < MLDSA_Q. + **************************************************/ +static MLD_INLINE int32_t mld_montgomery_reduce(int64_t a) +__contract__( + /* We don't attempt to express an input-dependent output bound + * as the post-condition here, as all call-sites satisfy the + * absolute input bound 2^31 * MLDSA_Q and higher-level + * reasoning can be conducted using |return_value| < MLDSA_Q. */ + requires(a > -(((int64_t)1 << 31) * MLDSA_Q) && + a < (((int64_t)1 << 31) * MLDSA_Q)) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* check-magic: 58728449 == unsigned_mod(pow(MLDSA_Q, -1, 2^32), 2^32) */ + const uint64_t QINV = 58728449; + + /* Compute a*q^{-1} mod 2^32 in unsigned representatives */ + const uint32_t a_reduced = mld_cast_int64_to_uint32(a); + const uint32_t a_inverted = (a_reduced * QINV) & UINT32_MAX; + + /* Lift to signed canonical representative mod 2^32. */ + const int32_t t = mld_cast_uint32_to_int32(a_inverted); + + int64_t r; + + mld_assert(a < +(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)) && + a > -(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q))); + + r = a - (int64_t)t * MLDSA_Q; + + /* + * PORTABILITY: Right-shift on a signed integer is, strictly-speaking, + * implementation-defined for negative left argument. Here, + * we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5)) + */ + r = r >> 32; + + /* Bounds: + * + * By construction of the Montgomery multiplication, by the time we + * compute r >> 32, r is divisible by 2^32, and hence + * + * |r >> 32| = |r| / 2^32 + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * (In general, we would only have |x >> n| <= ceil(|x| / 2^n)). + * + * In particular, if |a| < 2^31 * MLDSA_Q, then |return_value| < MLDSA_Q. + */ + return (int32_t)r; +} + +/************************************************* + * Name: mld_reduce32 + * + * Description: For finite field element a with a <= 2^{31} - 2^{22} - 1, + * compute r \equiv a (mod MLDSA_Q) such that + * -MLD_REDUCE32_RANGE_MAX <= r < MLD_REDUCE32_RANGE_MAX. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_reduce32(int32_t a) +__contract__( + requires(a <= MLD_REDUCE32_DOMAIN_MAX) + ensures(return_value >= -MLD_REDUCE32_RANGE_MAX) + ensures(return_value < MLD_REDUCE32_RANGE_MAX) +) +{ + int32_t t; + + t = (a + (1 << 22)) >> 23; + t = a - t * MLDSA_Q; + mld_assert((t - a) % MLDSA_Q == 0); + return t; +} + +/************************************************* + * Name: mld_caddq + * + * Description: Add MLDSA_Q if input coefficient is negative. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_caddq(int32_t a) +__contract__( + requires(a > -MLDSA_Q) + requires(a < MLDSA_Q) + ensures(return_value >= 0) + ensures(return_value < MLDSA_Q) + ensures(return_value == (a >= 0) ? a : (a + MLDSA_Q)) +) +{ + return mld_ct_sel_int32(a + MLDSA_Q, a, mld_ct_cmask_neg_i32(a)); +} + + +#endif /* !MLD_REDUCE_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/rounding.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/rounding.h new file mode 100644 index 0000000000..a83562b0f1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/rounding.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_ROUNDING_H +#define MLD_ROUNDING_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_power2round MLD_ADD_PARAM_SET(mld_power2round) +#define mld_decompose MLD_ADD_PARAM_SET(mld_decompose) +#define mld_make_hint MLD_ADD_PARAM_SET(mld_make_hint) +#define mld_use_hint MLD_ADD_PARAM_SET(mld_use_hint) +/* End of parameter set namespacing */ + +#define MLD_2_POW_D (1 << MLDSA_D) + +/************************************************* + * Name: mld_power2round + * + * Description: For finite field element a, compute a0, a1 such that + * a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with -2^{MLDSA_D-1} < a0 <= + * 2^{MLDSA_D-1}. Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: In the reference implementation, a1 is passed as a + * return value instead. + **************************************************/ +static MLD_INLINE void mld_power2round(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + ensures(*a0 > -(MLD_2_POW_D/2) && *a0 <= (MLD_2_POW_D/2)) + ensures(*a1 >= 0 && *a1 <= (MLDSA_Q - 1) / MLD_2_POW_D) + ensures((*a1 * MLD_2_POW_D + *a0 - a) % MLDSA_Q == 0) +) +{ + *a1 = (a + (1 << (MLDSA_D - 1)) - 1) >> MLDSA_D; + *a0 = a - (*a1 << MLDSA_D); +} + +/************************************************* + * Name: mld_decompose + * + * Description: For finite field element a, compute high and low bits a0, a1 + * such that a mod^+ MLDSA_Q = a1* 2 * MLDSA_GAMMA2 + a0 with + * -MLDSA_GAMMA2 < a0 <= MLDSA_GAMMA2 except + * if a1 = (MLDSA_Q-1)/(MLDSA_GAMMA2*2) where we set a1 = 0 and + * -MLDSA_GAMMA2 <= a0 = a mod^+ MLDSA_Q - MLDSA_Q < 0. + * Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: a1 is passed as a return value instead + **************************************************/ +static MLD_INLINE void mld_decompose(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + /* a0 = -MLDSA_GAMMA2 can only occur when (q-1) = a - (a mod MLDSA_GAMMA2), + * then a1=1; and a0 = a - (a mod MLDSA_GAMMA2) - 1 (@[FIPS204, Algorithm 36 (Decompose)]) */ + ensures(*a0 >= -MLDSA_GAMMA2 && *a0 <= MLDSA_GAMMA2) + ensures(*a1 >= 0 && *a1 < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) + ensures((*a1 * 2 * MLDSA_GAMMA2 + *a0 - a) % MLDSA_Q == 0) +) +{ + /* + * The goal is to compute f1 = round-(f / (2*GAMMA2)), which can be computed + * alternatively as round-(f / (128B)) = round-(ceil(f / 128) / B) where + * B = 2*GAMMA2 / 128. Here round-() denotes "round half down". + * + * The equality round-(f / (128B)) = round-(ceil(f / 128) / B) can deduced + * as follows. Since changing f to align-up(f, 128) can move f onto but not + * across a rounding boundary for division by 128*B (note that we need B to be + * even for this to work), and round- rounds down on the boundary, we have + * + * round-(f / (128B)) = round-(align-up(f, 128) / (128B)) + * = round-((align-up(f, 128) / 128) / B) + * = round-(ceil(f / 128) / B). + */ + *a1 = (a + 127) >> 7; + /* We know a >= 0 and a < MLDSA_Q, so... */ + /* check-magic: 65472 == round((MLDSA_Q-1)/128) */ + mld_assert(*a1 >= 0 && *a1 <= 65472); + +#if MLD_CONFIG_PARAMETER_SET == 44 + /* check-magic: 1488 == 2 * intdiv(intdiv(MLDSA_Q - 1, 88), 128) */ + /* check-magic: 11275 == floor(2**24 / 1488) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + */ + *a1 = (*a1 * 11275 + (1 << 23)) >> 24; + mld_assert(*a1 >= 0 && *a1 <= 44); + + *a1 = mld_ct_sel_int32(0, *a1, mld_ct_cmask_neg_i32(43 - *a1)); + mld_assert(*a1 >= 0 && *a1 <= 43); +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + /* check-magic: 4092 == 2 * intdiv(intdiv(MLDSA_Q - 1, 32), 128) */ + /* check-magic: 1025 == floor(2**22 / 4092) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + */ + *a1 = (*a1 * 1025 + (1 << 21)) >> 22; + mld_assert(*a1 >= 0 && *a1 <= 16); + + *a1 &= 15; + mld_assert(*a1 >= 0 && *a1 <= 15); + +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + + *a0 = a - *a1 * 2 * MLDSA_GAMMA2; + *a0 = mld_ct_sel_int32(*a0 - MLDSA_Q, *a0, + mld_ct_cmask_neg_i32((MLDSA_Q - 1) / 2 - *a0)); +} + +/************************************************* + * Name: mld_make_hint + * + * Description: Compute hint bit indicating whether the low bits of the + * input element overflow into the high bits. + * + * Arguments: - int32_t a0: low bits of input element + * - int32_t a1: high bits of input element + * + * Returns 1 if overflow, 0 otherwise + **************************************************/ +static MLD_INLINE unsigned int mld_make_hint(int32_t a0, int32_t a1) +__contract__( + ensures(return_value >= 0 && return_value <= 1) +) +{ + if (a0 > MLDSA_GAMMA2 || a0 < -MLDSA_GAMMA2 || + (a0 == -MLDSA_GAMMA2 && a1 != 0)) + { + return 1; + } + + return 0; +} + +/************************************************* + * Name: mld_use_hint + * + * Description: Correct high bits according to hint. + * + * Arguments: - int32_t a: input element + * - int32_t hint: hint bit + * + * Returns corrected high bits. + **************************************************/ +static MLD_INLINE int32_t mld_use_hint(int32_t a, int32_t hint) +__contract__( + requires(hint >= 0 && hint <= 1) + requires(a >= 0 && a < MLDSA_Q) + ensures(return_value >= 0 && return_value < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) +) +{ + int32_t a0, a1; + + mld_decompose(&a0, &a1, a); + if (hint == 0) + { + return a1; + } + +#if MLD_CONFIG_PARAMETER_SET == 44 + if (a0 > 0) + { + return (a1 == 43) ? 0 : a1 + 1; + } + else + { + return (a1 == 0) ? 43 : a1 - 1; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + if (a0 > 0) + { + return (a1 + 1) & 15; + } + else + { + return (a1 - 1) & 15; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + + +#endif /* !MLD_ROUNDING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/sign.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/sign.c new file mode 100644 index 0000000000..32bba52d65 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/sign.c @@ -0,0 +1,1508 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [Round3_Spec] + * CRYSTALS-Dilithium Algorithm Specifications and Supporting Documentation + * (Version 3.1) + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf + */ + +#include +#include + +#include "cbmc.h" +#include "ct.h" +#include "debug.h" +#include "packing.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" +#include "randombytes.h" +#include "sign.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_check_pct MLD_ADD_PARAM_SET(mld_check_pct) MLD_CONTEXT_PARAMETERS_2 +#define mld_sample_s1_s2 MLD_ADD_PARAM_SET(mld_sample_s1_s2) +#define mld_validate_hash_length MLD_ADD_PARAM_SET(mld_validate_hash_length) +#define mld_get_hash_oid MLD_ADD_PARAM_SET(mld_get_hash_oid) +#define mld_H MLD_ADD_PARAM_SET(mld_H) +#define mld_compute_pack_z MLD_ADD_PARAM_SET(mld_compute_pack_z) +#define mld_attempt_signature_generation \ + MLD_ADD_PARAM_SET(mld_attempt_signature_generation) MLD_CONTEXT_PARAMETERS_8 +#define mld_compute_t0_t1_tr_from_sk_components \ + MLD_ADD_PARAM_SET(mld_compute_t0_t1_tr_from_sk_components) \ + MLD_CONTEXT_PARAMETERS_7 +/* End of parameter set namespacing */ + + +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + ensures(return_value == 0 + || return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL) +); + +#if defined(MLD_CONFIG_KEYGEN_PCT) +/************************************************* + * @[FIPS140_3_IG] + * (https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf) + * + * TE10.35.02: Pair-wise Consistency Test (PCT) for DSA keypairs + * + * Purpose: Validates that a generated public/private key pair can correctly + * sign and verify data. Test performs signature generation using the private + * key (sk), followed by signature verification using the public key (pk). + * Returns 0 if the signature was successfully verified, non-zero if it cannot. + * + * Note: @[FIPS204] requires that public/private key pairs are to be used only + * for the calculation and/of verification of digital signatures. + **************************************************/ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t message[1] = {0}; + size_t siglen; + int ret; + MLD_ALLOC(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + MLD_ALLOC(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + + if (signature == NULL || pk_test == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Copy public key for testing */ + mld_memcpy(pk_test, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* Sign a test message using the original secret key */ + ret = mld_sign_signature(signature, &siglen, message, sizeof(message), NULL, + 0, sk, context); + if (ret != 0) + { + goto cleanup; + } + +#if defined(MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST) + /* Deliberately break public key for testing purposes */ + if (mld_break_pct()) + { + pk_test[0] = ~pk_test[0]; + } +#endif /* MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST */ + + /* Verify the signature using the (potentially corrupted) public key */ + ret = mld_sign_verify(signature, siglen, message, sizeof(message), NULL, 0, + pk_test, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + MLD_FREE(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + + return ret; +} +#else /* MLD_CONFIG_KEYGEN_PCT */ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + /* Skip PCT */ + ((void)pk); + ((void)sk); +#if defined(MLD_CONFIG_CONTEXT_PARAMETER) + ((void)context); +#endif + return 0; +} +#endif /* !MLD_CONFIG_KEYGEN_PCT */ + +static void mld_sample_s1_s2(mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t seed[MLDSA_CRHBYTES]) +__contract__( + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(object_whole(s1), object_whole(s2)) + ensures(forall(l0, 0, MLDSA_L, array_abs_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + ensures(forall(k0, 0, MLDSA_K, array_abs_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) +) +{ +/* Sample short vectors s1 and s2 */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; + uint16_t nonce = 0; + /* Safety: The nonces are at most 14 (MLDSA_L + MLDSA_K - 1), and, hence, the + * casts are safe. */ + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_eta(&s1->vec[i], seed, (uint8_t)(nonce + i)); + } + for (i = 0; i < MLDSA_K; i++) + { + mld_poly_uniform_eta(&s2->vec[i], seed, (uint8_t)(nonce + MLDSA_L + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLD_CONFIG_PARAMETER_SET == 44 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 4, 5, 6, 7); +#elif MLD_CONFIG_PARAMETER_SET == 65 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s2->vec[0], &s2->vec[1], + &s2->vec[2] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[2], &s2->vec[3], &s2->vec[4], &s2->vec[5], + seed, 7, 8, 9, 10); +#elif MLD_CONFIG_PARAMETER_SET == 87 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s1->vec[5], &s1->vec[6], + &s2->vec[0] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 7, 8, 9, 10); + mld_poly_uniform_eta_4x(&s2->vec[4], &s2->vec[5], &s2->vec[6], &s2->vec[7], + seed, 11, 12, 13, 14); +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ +} + +/************************************************* + * Name: mld_compute_t0_t1_tr_from_sk_components + * + * Description: Computes t0, t1, tr, and pk from secret key components + * rho, s1, s2. This is the shared computation used by + * both keygen and generating the public key from the + * secret key. + * + * Arguments: - mld_polyveck *t0: output t0 + * - mld_polyveck *t1: output t1 + * - uint8_t tr[MLDSA_TRBYTES]: output tr + * - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t rho[MLDSA_SEEDBYTES]: input rho + * - const mld_polyvecl *s1: input s1 + * - const mld_polyveck *s2: input s2 + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_t0_t1_tr_from_sk_components( + mld_polyveck *t0, mld_polyveck *t1, uint8_t tr[MLDSA_TRBYTES], + uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], const uint8_t rho[MLDSA_SEEDBYTES], + const mld_polyvecl *s1, const mld_polyveck *s2, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(l0, 0, MLDSA_L, array_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + requires(forall(k0, 0, MLDSA_K, array_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(forall(k1, 0, MLDSA_K, array_bound(t0->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(t1->vec[k2].coeffs, 0, MLDSA_N, 0, 1 << 10))) + ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY)) +{ + int ret; + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1hat, mld_polyvecl, 1, context); + MLD_ALLOC(t, mld_polyveck, 1, context); + + if (mat == NULL || s1hat == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Expand matrix */ + mld_polyvec_matrix_expand(mat, rho); + + /* Matrix-vector multiplication */ + *s1hat = *s1; + mld_polyvecl_ntt(s1hat); + mld_polyvec_matrix_pointwise_montgomery(t, mat, s1hat); + mld_polyveck_invntt_tomont(t); + + /* Add error vector s2 */ + mld_polyveck_add(t, s2); + + /* Reference: The following reduction is not present in the reference + * implementation. Omitting this reduction requires the output of + * the invntt to be small enough such that the addition of s2 does + * not result in absolute values >= MLDSA_Q. While our C, x86_64, + * and AArch64 invntt implementations produce small enough + * values for this to work out, it complicates the bounds + * reasoning. We instead add an additional reduction, and can + * consequently, relax the bounds requirements for the invntt. + */ + mld_polyveck_reduce(t); + + /* Decompose to get t1, t0 */ + mld_polyveck_caddq(t); + mld_polyveck_power2round(t1, t0, t); + + /* Pack public key and compute tr */ + mld_pack_pk(pk, rho, t1); + mld_shake256(tr, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + ret = 0; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_polyveck, 1, context); + MLD_FREE(s1hat, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + const uint8_t *rho, *rhoprime, *key; + MLD_ALLOC(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + MLD_ALLOC(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + + if (seedbuf == NULL || inbuf == NULL || tr == NULL || s1 == NULL || + s2 == NULL || t1 == NULL || t0 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Get randomness for rho, rhoprime and key */ + mld_memcpy(inbuf, seed, MLDSA_SEEDBYTES); + inbuf[MLDSA_SEEDBYTES + 0] = MLDSA_K; + inbuf[MLDSA_SEEDBYTES + 1] = MLDSA_L; + mld_shake256(seedbuf, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, inbuf, + MLDSA_SEEDBYTES + 2); + rho = seedbuf; + rhoprime = rho + MLDSA_SEEDBYTES; + key = rhoprime + MLDSA_CRHBYTES; + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + + /* Sample s1 and s2 */ + mld_sample_s1_s2(s1, s2, rhoprime); + + /* Compute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0, t1, tr, pk, rho, s1, s2, + context); + if (ret != 0) + { + goto cleanup; + } + + /* Pack secret key */ + mld_pack_sk(sk, rho, tr, key, t0, s1, s2); + + /* Constant time: pk is the public key, inherently public data */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_FREE(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + + if (ret != 0) + { + return ret; + } + + /* Pairwise Consistency Test (PCT) @[FIPS140_3_IG, p.87] */ + /* Do this after freeing all temporaries. */ + return mld_check_pct(pk, sk, context); +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t seed[MLDSA_SEEDBYTES]; + int ret; + if (mld_randombytes(seed, MLDSA_SEEDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(seed, sizeof(seed)); + ret = mld_sign_keypair_internal(pk, sk, seed, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed, sizeof(seed)); + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +/************************************************* + * Name: mld_H + * + * Description: Abstracts application of SHAKE256 to + * one, two or three blocks of data, + * yielding a user-requested size of + * output. + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in1: pointer to input block 1 + * Must NOT be NULL + * - size_t in1len: length of input in1 bytes + * - const uint8_t *in2: pointer to input block 2 + * May be NULL if in2len=0, in which case + * this block is ignored + * - size_t in2len: length of input in2 bytes + * - const uint8_t *in3: pointer to input block 3 + * May be NULL if in3len=0, in which case + * this block is ignored + * - size_t in3len: length of input in3 bytes + **************************************************/ +static void mld_H(uint8_t *out, size_t outlen, const uint8_t *in1, + size_t in1len, const uint8_t *in2, size_t in2len, + const uint8_t *in3, size_t in3len) +__contract__( + requires(in1len <= MLD_MAX_BUFFER_SIZE) + requires(in2len <= MLD_MAX_BUFFER_SIZE) + requires(in3len <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in1, in1len)) + requires(in2len == 0 || memory_no_alias(in2, in2len)) + requires(in3len == 0 || memory_no_alias(in3, in3len)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) +{ + mld_shake256ctx state; + mld_shake256_init(&state); + mld_shake256_absorb(&state, in1, in1len); + if (in2len != 0) + { + mld_shake256_absorb(&state, in2, in2len); + } + if (in3len != 0) + { + mld_shake256_absorb(&state, in3, in3len); + } + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(&state, sizeof(state)); +} + +/************************************************* + * Name: mld_compute_pack_z + * + * Description: Computes z = y + s1*c, checks that z has coefficients smaller + * than MLDSA_GAMMA1 - MLDSA_BETA, and packs z into the + * signature buffer. + * + * Arguments: - uint8_t *sig: output signature + * - const mld_poly *cp: challenge polynomial + * - const polyvecl *s1: secret vector s1 + * - const polyvecl *y: masking vector y + * + * Returns: - 0: Success (z has coefficients smaller than + * MLDSA_GAMMA1 - MLDSA_BETA,) + * - MLD_ERR_FAIL: z rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This function is inlined into mld_sign_signature in the + * reference implementation. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_pack_z(uint8_t sig[MLDSA_CRYPTO_BYTES], + const mld_poly *cp, const mld_polyvecl *s1, + const mld_polyvecl *y, mld_poly *z) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(cp, sizeof(mld_poly))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(y, sizeof(mld_polyvecl))) + requires(memory_no_alias(z, sizeof(mld_poly))) + requires(array_abs_bound(cp->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_L, + array_bound(y->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + requires(forall(k1, 0, MLDSA_L, array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(memory_slice(z, sizeof(mld_poly))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int i; + uint32_t z_invalid; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(z, sizeof(mld_poly)), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_poly_pointwise_montgomery(z, cp, &s1->vec[i]); + mld_poly_invntt_tomont(z); + mld_poly_add(z, &y->vec[i]); + mld_poly_reduce(z); + + z_invalid = mld_poly_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA); + /* Constant time: It is fine (and prohibitively expensive to avoid) + * to leak the result of the norm check and which polynomial in z caused a + * rejection. It would even be okay to leak which coefficient led to + * rejection as the candidate signature will be discarded anyway. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(&z_invalid, sizeof(uint32_t)); + if (z_invalid) + { + return MLD_ERR_FAIL; /* reject */ + } + /* If z is valid, then its coefficients are bounded by + * MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below + * to prove the pre-condition of pack_sig_z() */ + mld_assert_abs_bound(z, MLDSA_N, (MLDSA_GAMMA1 - MLDSA_BETA)); + + /* After the norm check, the distribution of each coefficient of z is + * independent of the secret key and it can, hence, be considered + * public. It is, hence, okay to immediately pack it into the user-provided + * signature buffer. */ + mld_pack_sig_z(sig, z, i); + } + return 0; +} + +/* Reference: The reference implementation does not explicitly check the + * maximum nonce value, but instead loops indefinitely (even when the nonce + * would overflow). Internally, sampling of y uses + * (nonceL), (nonceL+1), ... (nonce*L+L-1). + * Hence, there are no overflows if nonce < (UINT16_MAX - L)/L. + * Explicitly checking for this explicitly allows us to prove type-safety. + * Note that FIPS204 explicitly allows an upper-bound this loop of + * 814 (< (UINT16_MAX - L)/L) - see @[FIPS204, Appendix C]. */ +#define MLD_NONCE_UB ((UINT16_MAX - MLDSA_L) / MLDSA_L) + +/************************************************* + * Name: attempt_signature_generation + * + * Description: Attempts to generate a single signature. + * + * Arguments: - uint8_t *sig: pointer to output signature + * - const uint8_t *mu: pointer to message or hash + * of exactly MLDSA_CRHBYTES bytes + * - const uint8_t *rhoprime: pointer to randomness seed + * - uint16_t nonce: current nonce value + * - const mld_polymat *mat: expanded matrix + * - const polyvecl *s1: secret vector s1 + * - const polyveck *s2: secret vector s2 + * - const polyveck *t0: vector t0 + * + * Returns: - 0: Signature generation succeeded + * - MLD_ERR_FAIL: Signature rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This code differs from the reference implementation + * in that it factors out the core signature generation + * step into a distinct function here in order to improve + * efficiency of CBMC proof. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_attempt_signature_generation( + uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *mu, + const uint8_t rhoprime[MLDSA_CRHBYTES], uint16_t nonce, mld_polymat *mat, + const mld_polyvecl *s1, const mld_polyveck *s2, const mld_polyveck *t0, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(rhoprime, MLDSA_CRHBYTES)) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(nonce <= MLD_NONCE_UB) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int n; + uint32_t w0_invalid, h_invalid; + int ret; + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyvecl y; + mld_polyveck h; + } + yh_u; + mld_polyvecl *y; + mld_polyveck *h; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck w1; + mld_polyvecl tmp; + } + w1tmp_u; + mld_polyveck *w1; + mld_polyvecl *tmp; + + MLD_ALLOC(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(yh, yh_u, 1, context); + MLD_ALLOC(z, mld_poly, 1, context); + MLD_ALLOC(w1tmp, w1tmp_u, 1, context); + MLD_ALLOC(w0, mld_polyveck, 1, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(t, mld_poly, 1, context); + + if (challenge_bytes == NULL || yh == NULL || z == NULL || w1tmp == NULL || + w0 == NULL || cp == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + y = &yh->y; + h = &yh->h; + w1 = &w1tmp->w1; + tmp = &w1tmp->tmp; + + /* Sample intermediate vector y */ + mld_polyvecl_uniform_gamma1(y, rhoprime, nonce); + + /* Matrix-vector multiplication */ + *tmp = *y; + mld_polyvecl_ntt(tmp); + mld_polyvec_matrix_pointwise_montgomery(w0, mat, tmp); + mld_polyveck_invntt_tomont(w0); + + /* Decompose w and call the random oracle */ + mld_polyveck_caddq(w0); + mld_polyveck_decompose(w1, w0); + mld_polyveck_pack_w1(sig, w1); + + mld_H(challenge_bytes, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, sig, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + /* Constant time: Leaking challenge_bytes does not reveal any information + * about the secret key as H() is modelled as random oracle. + * This also applies to challenges for rejected signatures. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(challenge_bytes, MLDSA_CTILDEBYTES); + mld_poly_challenge(cp, challenge_bytes); + mld_poly_ntt(cp); + + /* Compute z, reject if it reveals secret */ + ret = mld_compute_pack_z(sig, cp, s1, y, t); + if (ret) + { + goto cleanup; + } + + /* Check that subtracting cs2 does not change high bits of w and low bits + * do not reveal secret information */ + mld_polyveck_pointwise_poly_montgomery(h, cp, s2); + mld_polyveck_invntt_tomont(h); + mld_polyveck_sub(w0, h); + mld_polyveck_reduce(w0); + + w0_invalid = mld_polyveck_chknorm(w0, MLDSA_GAMMA2 - MLDSA_BETA); + /* Constant time: w0_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&w0_invalid, sizeof(uint32_t)); + if (w0_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* Compute hints for w1 */ + mld_polyveck_pointwise_poly_montgomery(h, cp, t0); + mld_polyveck_invntt_tomont(h); + mld_polyveck_reduce(h); + + h_invalid = mld_polyveck_chknorm(h, MLDSA_GAMMA2); + /* Constant time: h_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&h_invalid, sizeof(uint32_t)); + if (h_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + mld_polyveck_add(w0, h); + + /* Constant time: At this point all norm checks have passed and we, hence, + * know that the signature does not leak any secret information. + * Consequently, any value that can be computed from the signature and public + * key is considered public. + * w0 and w1 are public as they can be computed from Az - ct = \alpha w1 + w0. + * h=c*t0 is public as both c and t0 are public. + * For a more detailed discussion, refer to https://eprint.iacr.org/2022/1406. + */ + MLD_CT_TESTING_DECLASSIFY(w0, sizeof(*w0)); + MLD_CT_TESTING_DECLASSIFY(w1, sizeof(*w1)); + n = mld_polyveck_make_hint(h, w0, w1); + if (n > MLDSA_OMEGA) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* All is well - write signature */ + mld_pack_sig_c_h(sig, challenge_bytes, h, n); + /* Constant time: At this point it is clear that the signature is valid - it + * can, hence, be considered public. */ + MLD_CT_TESTING_DECLASSIFY(sig, MLDSA_CRYPTO_BYTES); + ret = 0; /* success */ + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_poly, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(w0, mld_polyveck, 1, context); + MLD_FREE(w1tmp, w1tmp_u, 1, context); + MLD_FREE(z, mld_poly, 1, context); + MLD_FREE(yh, yh_u, 1, context); + MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + + return ret; +} +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + uint8_t *rho, *tr, *key, *mu, *rhoprime; + uint16_t nonce = 0; + MLD_ALLOC(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + + if (seedbuf == NULL || mat == NULL || s1 == NULL || t0 == NULL || s2 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + rho = seedbuf; + tr = rho + MLDSA_SEEDBYTES; + key = tr + MLDSA_TRBYTES; + mu = key + MLDSA_SEEDBYTES; + rhoprime = mu + MLDSA_CRHBYTES; + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + if (!externalmu) + { + /* Compute mu = CRH(tr, pre, msg) */ + mld_H(mu, MLDSA_CRHBYTES, tr, MLDSA_TRBYTES, pre, prelen, m, mlen); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Compute rhoprime = CRH(key, rnd, mu) */ + mld_H(rhoprime, MLDSA_CRHBYTES, key, MLDSA_SEEDBYTES, rnd, MLDSA_RNDBYTES, mu, + MLDSA_CRHBYTES); + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + /* Expand matrix and transform vectors */ + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(s1); + mld_polyveck_ntt(s2); + mld_polyveck_ntt(t0); + + /* By default, return failure. Flip to success and write output + * once signature generation succeeds. */ + ret = MLD_ERR_FAIL; + + /* Reference: This code is re-structured using a while(1), */ + /* with explicit "continue" statements (rather than "goto") */ + /* to implement rejection of invalid signatures. */ + while (1) + __loop__( + assigns(nonce, ret, object_whole(siglen), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(nonce <= MLD_NONCE_UB) + + /* t0, s1, s2, and mat are initialized above and are NOT changed by this */ + /* loop. We can therefore re-assert their bounds here as part of the */ + /* loop invariant. This makes proof noticeably faster with CBMC */ + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + invariant(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(ret == MLD_ERR_FAIL) + ) + { + /* Reference: this code explicitly checks for exhaustion of nonce */ + /* values to provide predictable termination and results in that case */ + /* Checking here also means that incrementing nonce below can also */ + /* be proven to be type-safe. */ + if (nonce == MLD_NONCE_UB) + { + /* Note that ret == MLD_ERR_FAIL by default, so we + * don't need to set it here. */ + break; + } + + ret = mld_attempt_signature_generation(sig, mu, rhoprime, nonce, mat, s1, + s2, t0, context); + nonce++; + if (ret == 0) + { + *siglen = MLDSA_CRYPTO_BYTES; + break; + } + else if (ret != MLD_ERR_FAIL) + { + /* For failures such as out-of-memory, propagate and exit immediately. */ + break; + } + + /* Otherwise, try again. */ + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the signature buffer. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + return ret; +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + size_t pre_len; + int ret; + MLD_ALLOC(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + MLD_ALLOC(rnd, uint8_t, MLDSA_RNDBYTES, context); + + if (pre == NULL || rnd == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Prepare domain separation prefix for pure ML-DSA */ + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, m, mlen, pre, pre_len, rnd, sk, + 0, context); + +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(rnd, uint8_t, MLDSA_RNDBYTES, context); + MLD_FREE(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t rnd[MLDSA_RNDBYTES]; + int ret; + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + *siglen = 0; + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, + rnd, sk, 1, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(rnd, sizeof(rnd)); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + for (i = 0; i < mlen; ++i) + __loop__( + assigns(i, object_whole(sm)) + invariant(i <= mlen) + ) + { + sm[MLDSA_CRYPTO_BYTES + mlen - 1 - i] = m[mlen - 1 - i]; + } + ret = mld_sign_signature(sm, smlen, sm + MLDSA_CRYPTO_BYTES, mlen, ctx, + ctxlen, sk, context); + *smlen += mlen; + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret, cmp; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck t1; + mld_polyveck w1; + } + t1w1_u; + mld_polyveck *t1; + mld_polyveck *w1; + + MLD_ALLOC(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_ALLOC(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(z, mld_polyvecl, 1, context); + MLD_ALLOC(t1w1, t1w1_u, 1, context); + MLD_ALLOC(tmp, mld_polyveck, 1, context); + MLD_ALLOC(h, mld_polyveck, 1, context); + + if (buf == NULL || rho == NULL || mu == NULL || c == NULL || c2 == NULL || + cp == NULL || mat == NULL || z == NULL || t1w1 == NULL || tmp == NULL || + h == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + t1 = &t1w1->t1; + w1 = &t1w1->w1; + + if (siglen != MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + mld_unpack_pk(rho, t1, pk); + + /* mld_unpack_sig and mld_polyvecl_chknorm signal failure through a + * single non-zero error code that's not yet aligned with MLD_ERR_XXX. + * Map it to MLD_ERR_FAIL explicitly. */ + if (mld_unpack_sig(c, z, h, sig)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + if (mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + if (!externalmu) + { + /* Compute CRH(H(rho, t1), pre, msg) */ + MLD_ALIGN uint8_t hpk[MLDSA_CRHBYTES]; + mld_H(hpk, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES, NULL, 0, NULL, + 0); + mld_H(mu, MLDSA_CRHBYTES, hpk, MLDSA_TRBYTES, pre, prelen, m, mlen); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(hpk, sizeof(hpk)); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Matrix-vector multiplication; compute Az - c2^dt1 */ + mld_poly_challenge(cp, c); + mld_poly_ntt(cp); + mld_polyveck_shiftl(t1); + mld_polyveck_ntt(t1); + mld_polyveck_pointwise_poly_montgomery(tmp, cp, t1); + + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(z); + mld_polyvec_matrix_pointwise_montgomery(w1, mat, z); + mld_polyveck_sub(w1, tmp); + mld_polyveck_reduce(w1); + mld_polyveck_invntt_tomont(w1); + + /* Reconstruct w1 */ + mld_polyveck_caddq(w1); + mld_polyveck_use_hint(tmp, w1, h); + mld_polyveck_pack_w1(buf, tmp); + /* Call random oracle and verify challenge */ + mld_H(c2, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, buf, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + + cmp = mld_ct_memcmp(c, c2, MLDSA_CTILDEBYTES); + + /* Declassify the result of the verification. */ + MLD_CT_TESTING_DECLASSIFY(&cmp, sizeof(cmp)); + + ret = cmp == 0 ? 0 : MLD_ERR_FAIL; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(h, mld_polyveck, 1, context); + MLD_FREE(tmp, mld_polyveck, 1, context); + MLD_FREE(t1w1, t1w1_u, 1, context); + MLD_FREE(z, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, m, mlen, pre, pre_len, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + return mld_sign_verify_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, pk, + 1, context); +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + if (smlen < MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + *mlen = smlen - MLDSA_CRYPTO_BYTES; + ret = mld_sign_verify(sm, MLDSA_CRYPTO_BYTES, sm + MLDSA_CRYPTO_BYTES, *mlen, + ctx, ctxlen, pk, context); + if (ret == 0) + { + /* All good, copy msg, return 0 */ + for (i = 0; i < *mlen; ++i) + __loop__( + assigns(i, memory_slice(m, *mlen)) + invariant(i <= *mlen) + ) + { + m[i] = sm[MLDSA_CRYPTO_BYTES + i]; + } + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the message buffer. */ + *mlen = 0; + mld_memset(m, 0, smlen); + } + + return ret; +} + + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_signature_internal(sig, siglen, pre, pre_len, NULL, 0, rnd, sk, + 0, context); +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, pre, pre_len, NULL, 0, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_signature_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, rnd, sk, + MLD_PREHASH_SHAKE_256, context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_verify_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, pk, MLD_PREHASH_SHAKE_256, + context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + + +#define MLD_PRE_HASH_OID_LEN 11 + +/************************************************* + * Name: mld_get_hash_oid + * + * Description: Returns the OID of a given SHA-2/SHA-3 hash function. + * + * Arguments: - uint8_t oid[11]: pointer to output oid + * - int hashalg: hash algorithm constant (MLD_PREHASH_*) + * + ***************************************************/ +static void mld_get_hash_oid(uint8_t oid[MLD_PRE_HASH_OID_LEN], int hashalg) +{ + unsigned int i; + static const struct + { + int alg; + uint8_t oid[MLD_PRE_HASH_OID_LEN]; + } oid_map[] = { + {MLD_PREHASH_SHA2_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}}, + {MLD_PREHASH_SHA2_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}}, + {MLD_PREHASH_SHA2_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}}, + {MLD_PREHASH_SHA2_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}}, + {MLD_PREHASH_SHA2_512_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05}}, + {MLD_PREHASH_SHA2_512_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06}}, + {MLD_PREHASH_SHA3_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07}}, + {MLD_PREHASH_SHA3_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08}}, + {MLD_PREHASH_SHA3_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09}}, + {MLD_PREHASH_SHA3_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A}}, + {MLD_PREHASH_SHAKE_128, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B}}, + {MLD_PREHASH_SHAKE_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C}}}; + + for (i = 0; i < sizeof(oid_map) / sizeof(oid_map[0]); i++) + __loop__( + invariant(i <= sizeof(oid_map) / sizeof(oid_map[0])) + ) + { + if (oid_map[i].alg == hashalg) + { + mld_memcpy(oid, oid_map[i].oid, MLD_PRE_HASH_OID_LEN); + return; + } + } +} + +static int mld_validate_hash_length(int hashalg, size_t len) +{ + switch (hashalg) + { + case MLD_PREHASH_SHA2_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_128: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_256: + return (len == 512 / 8) ? 0 : -1; + } + return -1; +} + +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +{ + if (ctxlen > 255) + { + return 0; + } + + if (hashalg != MLD_PREHASH_NONE) + { + if (ph == NULL || mld_validate_hash_length(hashalg, phlen) != 0) + { + return 0; + } + } + + /* Common prefix: 0x00/0x01 || ctxlen || ctx */ + prefix[0] = (hashalg == MLD_PREHASH_NONE) ? 0 : 1; + prefix[1] = (uint8_t)ctxlen; + if (ctxlen > 0) + { + mld_memcpy(prefix + 2, ctx, ctxlen); + } + + if (hashalg == MLD_PREHASH_NONE) + { + return 2 + ctxlen; + } + + /* HashML-DSA: append oid || ph */ + mld_get_hash_oid(prefix + 2 + ctxlen, hashalg); + mld_memcpy(prefix + 2 + ctxlen + MLD_PRE_HASH_OID_LEN, ph, phlen); + return 2 + ctxlen + MLD_PRE_HASH_OID_LEN + phlen; +} + +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + uint8_t check, cmp0, cmp1, chk1, chk2; + int ret; + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(t0_computed, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + + if (rho == NULL || tr == NULL || tr_computed == NULL || key == NULL || + s1 == NULL || s2 == NULL || t0 == NULL || t0_computed == NULL || + t1 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Unpack secret key */ + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + /* Validate s1 and s2 coefficients are within [-MLDSA_ETA, MLDSA_ETA] */ + chk1 = mld_polyvecl_chknorm(s1, MLDSA_ETA + 1) & 0xFF; + chk2 = mld_polyveck_chknorm(s2, MLDSA_ETA + 1) & 0xFF; + + /* Recompute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0_computed, t1, tr_computed, + pk, rho, s1, s2, context); + if (ret != 0) + { + goto cleanup; + } + + /* Validate t0 and tr using constant-time comparisons */ + cmp0 = mld_ct_memcmp((const uint8_t *)t0, (const uint8_t *)t0_computed, + sizeof(mld_polyveck)); + cmp1 = mld_ct_memcmp((const uint8_t *)tr, (const uint8_t *)tr_computed, + MLDSA_TRBYTES); + check = mld_value_barrier_u8(cmp0 | cmp1 | chk1 | chk2); + + /* Declassify the final result of the validity check. */ + MLD_CT_TESTING_DECLASSIFY(&check, sizeof(check)); + ret = (check != 0) ? MLD_ERR_FAIL : 0; + +cleanup: + + if (ret != 0) + { + mld_zeroize(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + } + + /* Constant time: pk is either the valid public key or zeroed on error */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(t0_computed, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + + return ret; +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_check_pct +#undef mld_sample_s1_s2 +#undef mld_validate_hash_length +#undef mld_get_hash_oid +#undef mld_H +#undef mld_compute_pack_z +#undef mld_attempt_signature_generation +#undef mld_compute_t0_t1_tr_from_sk_components +#undef MLD_NONCE_UB +#undef MLD_PRE_HASH_OID_LEN diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/sign.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/sign.h new file mode 100644 index 0000000000..2e0bac32ea --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/sign.h @@ -0,0 +1,807 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_SIGN_H +#define MLD_SIGN_H + +#include +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "polyvec.h" +#include "sys.h" + +#if defined(MLD_CHECK_APIS) +/* Include to ensure consistency between internal sign.h + * and external mldsa_native.h. */ +#include "mldsa_native.h" + +#if MLDSA_CRYPTO_SECRETKEYBYTES != \ + MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for SECRETKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_PUBLICKEYBYTES != \ + MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for PUBLICKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_BYTES != MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for CRYPTO_BYTES between sign.h and mldsa_native.h +#endif + +#endif /* MLD_CHECK_APIS */ + +#define mld_sign_keypair_internal \ + MLD_NAMESPACE_KL(keypair_internal) MLD_CONTEXT_PARAMETERS_3 +#define mld_sign_keypair MLD_NAMESPACE_KL(keypair) MLD_CONTEXT_PARAMETERS_2 +#define mld_sign_signature_internal \ + MLD_NAMESPACE_KL(signature_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_signature MLD_NAMESPACE_KL(signature) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_extmu \ + MLD_NAMESPACE_KL(signature_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign MLD_NAMESPACE_KL(sign) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_internal \ + MLD_NAMESPACE_KL(verify_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify MLD_NAMESPACE_KL(verify) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_extmu \ + MLD_NAMESPACE_KL(verify_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign_open MLD_NAMESPACE_KL(open) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_pre_hash_internal \ + MLD_NAMESPACE_KL(signature_pre_hash_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_verify_pre_hash_internal \ + MLD_NAMESPACE_KL(verify_pre_hash_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_signature_pre_hash_shake256 \ + MLD_NAMESPACE_KL(signature_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify_pre_hash_shake256 \ + MLD_NAMESPACE_KL(verify_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_7 +#define mld_prepare_domain_separation_prefix \ + MLD_NAMESPACE_KL(prepare_domain_separation_prefix) +#define mld_sign_pk_from_sk \ + MLD_NAMESPACE_KL(pk_from_sk) MLD_CONTEXT_PARAMETERS_2 + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: mld_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: input random seed + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int externalmu: indicates input message m is + * processed as mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return MLD_ERR_FAIL in that case. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires((externalmu == 0 && (prelen == 0 || memory_no_alias(pre, prelen))) || + (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) + ensures(return_value == 0 ==> *siglen == MLDSA_CRYPTO_BYTES) + ensures(return_value != 0 ==> *siglen == 0) +); + +/************************************************* + * Name: mld_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_signature_extmu + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign + * + * Description: Compute signed message. + * + * Arguments: - uint8_t *sm: pointer to output signed message + * (allocated array with MLDSA_CRYPTO_BYTES + + *mlen bytes), can be equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sm, MLDSA_CRYPTO_BYTES + mlen)) + requires(memory_no_alias(smlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sm, MLDSA_CRYPTO_BYTES + mlen)) + assigns(object_whole(smlen)) + ensures((return_value == 0 && *smlen == MLDSA_CRYPTO_BYTES + mlen) || + (return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL)) +); + +/************************************************* + * Name: mld_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as + * mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(externalmu == 0 || (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + requires(externalmu == 1 || prelen == 0 || memory_no_alias(pre, prelen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_open + * + * Description: Verify signed message. + * + * Arguments: - uint8_t *m: pointer to output message (allocated array + * with smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context tring + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(smlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(m, smlen)) + requires(memory_no_alias(mlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(sm, smlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + assigns(memory_slice(m, smlen)) + assigns(memory_slice(mlen, sizeof(size_t))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and + * verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/* Maximum formatted domain separation message length: + * - Pure ML-DSA: 0x00 || ctxlen || ctx (max 255) + * - HashML-DSA: 0x01 || ctxlen || ctx (max 255) || oid (11) || ph (max 64) */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +__contract__( + requires(ctxlen <= 255) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(hashalg == MLD_PREHASH_NONE || memory_no_alias(ph, phlen)) + requires(memory_no_alias(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + assigns(memory_slice(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + ensures(return_value <= MLD_DOMAIN_SEPARATION_MAX_BYTES) +); + +/************************************************* + * Name: mld_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: input secret + * key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); +#endif /* !MLD_SIGN_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/symmetric.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/symmetric.h new file mode 100644 index 0000000000..bb70f05552 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/symmetric.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_SYMMETRIC_H +#define MLD_SYMMETRIC_H + +#include +#include "cbmc.h" +#include "common.h" + +#include MLD_FIPS202_HEADER_FILE +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#include MLD_FIPS202X4_HEADER_FILE +#endif + +#define MLD_STREAM128_BLOCKBYTES SHAKE128_RATE +#define MLD_STREAM256_BLOCKBYTES SHAKE256_RATE + +#define mld_xof256_ctx mld_shake256ctx +#define mld_xof256_init(CTX) mld_shake256_init(CTX) + +#define mld_xof256_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake256_absorb(CTX, IN, INBYTES); \ + mld_shake256_finalize(CTX); \ + } while (0) + + +#define mld_xof256_release(CTX) mld_shake256_release(CTX) +#define mld_xof256_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake256_squeeze(OUT, (OUTBLOCKS) * SHAKE256_RATE, STATE) + +#define mld_xof128_ctx mld_shake128ctx +#define mld_xof128_init(CTX) mld_shake128_init(CTX) + +#define mld_xof128_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake128_absorb(CTX, IN, INBYTES); \ + mld_shake128_finalize(CTX); \ + } while (0) + +#define mld_xof128_release(CTX) mld_shake128_release(CTX) +#define mld_xof128_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake128_squeeze(OUT, (OUTBLOCKS) * SHAKE128_RATE, STATE) + +#define mld_xof256_x4_ctx mld_shake256x4ctx +#define mld_xof256_x4_init(CTX) mld_shake256x4_init((CTX)) +#define mld_xof256_x4_absorb(CTX, IN, INBYTES) \ + mld_shake256x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof256_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake256x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof256_x4_release(CTX) mld_shake256x4_release((CTX)) + +#define mld_xof128_x4_ctx mld_shake128x4ctx +#define mld_xof128_x4_init(CTX) mld_shake128x4_init((CTX)) +#define mld_xof128_x4_absorb(CTX, IN, INBYTES) \ + mld_shake128x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof128_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake128x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof128_x4_release(CTX) mld_shake128x4_release((CTX)) + +#endif /* !MLD_SYMMETRIC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/sys.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/sys.h new file mode 100644 index 0000000000..1226526420 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/sys.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_SYS_H +#define MLD_SYS_H + +#if !defined(MLD_CONFIG_NO_ASM) && (defined(__GNUC__) || defined(__clang__)) +#define MLD_HAVE_INLINE_ASM +#endif + +/* Try to find endianness, if not forced through CFLAGS already */ +#if !defined(MLD_SYS_LITTLE_ENDIAN) && !defined(MLD_SYS_BIG_ENDIAN) +#if defined(__BYTE_ORDER__) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define MLD_SYS_LITTLE_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define MLD_SYS_BIG_ENDIAN +#else +#error "__BYTE_ORDER__ defined, but don't recognize value." +#endif +#endif /* __BYTE_ORDER__ */ + +/* MSVC does not define __BYTE_ORDER__. However, MSVC only supports + * little endian x86, x86_64, and AArch64. It is, hence, safe to assume + * little endian. */ +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_IX86) || defined(_M_ARM64)) +#define MLD_SYS_LITTLE_ENDIAN +#endif + +#endif /* !MLD_SYS_LITTLE_ENDIAN && !MLD_SYS_BIG_ENDIAN */ + +/* Check if we're running on an AArch64 little endian system. _M_ARM64 is set by + * MSVC. */ +#if defined(__AARCH64EL__) || defined(_M_ARM64) +#define MLD_SYS_AARCH64 +#endif + +/* Check if we're running on an AArch64 big endian system. */ +#if defined(__AARCH64EB__) +#define MLD_SYS_AARCH64_EB +#endif + +#if defined(__x86_64__) +#define MLD_SYS_X86_64 +#if defined(__AVX2__) +#define MLD_SYS_X86_64_AVX2 +#endif +#endif /* __x86_64__ */ + +#if defined(MLD_SYS_LITTLE_ENDIAN) && defined(__powerpc64__) +#define MLD_SYS_PPC64LE +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 +#define MLD_SYS_RISCV64 +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32 +#define MLD_SYS_RISCV32 +#endif + +#if defined(_WIN64) || defined(_WIN32) +#define MLD_SYS_WINDOWS +#endif + +#if defined(__linux__) +#define MLD_SYS_LINUX +#endif + +#if defined(__APPLE__) +#define MLD_SYS_APPLE +#endif + +/* If MLD_FORCE_AARCH64 is set, assert that we're indeed on an AArch64 system. + */ +#if defined(MLD_FORCE_AARCH64) && !defined(MLD_SYS_AARCH64) +#error "MLD_FORCE_AARCH64 is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_AARCH64_EB is set, assert that we're indeed on a big endian + * AArch64 system. */ +#if defined(MLD_FORCE_AARCH64_EB) && !defined(MLD_SYS_AARCH64_EB) +#error \ + "MLD_FORCE_AARCH64_EB is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_X86_64 is set, assert that we're indeed on an X86_64 system. */ +#if defined(MLD_FORCE_X86_64) && !defined(MLD_SYS_X86_64) +#error "MLD_FORCE_X86_64 is set, but we don't seem to be on an X86_64 system." +#endif + +#if defined(MLD_FORCE_PPC64LE) && !defined(MLD_SYS_PPC64LE) +#error "MLD_FORCE_PPC64LE is set, but we don't seem to be on a PPC64LE system." +#endif + +#if defined(MLD_FORCE_RISCV64) && !defined(MLD_SYS_RISCV64) +#error "MLD_FORCE_RISCV64 is set, but we don't seem to be on a RISCV64 system." +#endif + +#if defined(MLD_FORCE_RISCV32) && !defined(MLD_SYS_RISCV32) +#error "MLD_FORCE_RISCV32 is set, but we don't seem to be on a RISCV32 system." +#endif + +/* + * MLD_INLINE: Hint for inlining. + * - MSVC: __inline + * - C99+: inline + * - GCC/Clang C90: __attribute__((unused)) to silence warnings + * - Other C90: empty + */ +#if !defined(MLD_INLINE) +#if defined(_MSC_VER) +#define MLD_INLINE __inline +#elif defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +#define MLD_INLINE inline +#elif defined(__GNUC__) || defined(__clang__) +#define MLD_INLINE __attribute__((unused)) +#else +#define MLD_INLINE +#endif +#endif /* !MLD_INLINE */ + +/* + * MLD_ALWAYS_INLINE: Force inlining. + * - MSVC: __forceinline + * - GCC/Clang C99+: MLD_INLINE __attribute__((always_inline)) + * - Other: MLD_INLINE (no forced inlining) + */ +#if !defined(MLD_ALWAYS_INLINE) +#if defined(_MSC_VER) +#define MLD_ALWAYS_INLINE __forceinline +#elif (defined(__GNUC__) || defined(__clang__)) && \ + (defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)) +#define MLD_ALWAYS_INLINE MLD_INLINE __attribute__((always_inline)) +#else +#define MLD_ALWAYS_INLINE MLD_INLINE +#endif +#endif /* !MLD_ALWAYS_INLINE */ + +#ifndef MLD_STATIC_TESTABLE +#define MLD_STATIC_TESTABLE static +#endif + +/* + * C90 does not have the restrict compiler directive yet. + * We don't use it in C90 builds. + */ +#if !defined(restrict) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define MLD_RESTRICT restrict +#else +#define MLD_RESTRICT +#endif + +#else /* !restrict */ + +#define MLD_RESTRICT restrict +#endif /* restrict */ + +#define MLD_DEFAULT_ALIGN 32 +#define MLD_ALIGN_UP(N) \ + ((((N) + (MLD_DEFAULT_ALIGN - 1)) / MLD_DEFAULT_ALIGN) * MLD_DEFAULT_ALIGN) +#if defined(__GNUC__) +#define MLD_ALIGN __attribute__((aligned(MLD_DEFAULT_ALIGN))) +#elif defined(_MSC_VER) +#define MLD_ALIGN __declspec(align(MLD_DEFAULT_ALIGN)) +#else +#define MLD_ALIGN /* No known support for alignment constraints */ +#endif + + +/* New X86_64 CPUs support Conflow-flow protection using the CET instructions. + * When enabled (through -fcf-protection=), all compilation units (including + * empty ones) need to support CET for this to work. + * For assembly, this means that source files need to signal support for + * CET by setting the appropriate note.gnu.property section. + * This can be achieved by including the header in all assembly file. + * This file also provides the _CET_ENDBR macro which needs to be placed at + * every potential target of an indirect branch. + * If CET is enabled _CET_ENDBR maps to the endbr64 instruction, otherwise + * it is empty. + * In case the compiler does not support CET (e.g., +#define MLD_CET_ENDBR _CET_ENDBR +#else +#define MLD_CET_ENDBR +#endif +#endif /* MLD_SYS_X86_64 */ + +#if defined(MLD_CONFIG_CT_TESTING_ENABLED) && !defined(__ASSEMBLER__) +#include +#define MLD_CT_TESTING_SECRET(ptr, len) \ + VALGRIND_MAKE_MEM_UNDEFINED((ptr), (len)) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) +#else /* MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__ */ +#define MLD_CT_TESTING_SECRET(ptr, len) \ + do \ + { \ + } while (0) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + do \ + { \ + } while (0) +#endif /* !(MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__) */ + +#if defined(__GNUC__) || defined(__clang__) +#define MLD_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_MUST_CHECK_RETURN_VALUE +#endif + + +#if !defined(__ASSEMBLER__) +/* System capability enumeration */ +typedef enum +{ + /* x86_64 */ + MLD_SYS_CAP_AVX2, + /* AArch64 */ + MLD_SYS_CAP_SHA3 +} mld_sys_cap; + +#if !defined(MLD_CONFIG_CUSTOM_CAPABILITY_FUNC) +#include "cbmc.h" + +static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) +__contract__( + ensures(return_value == 0 || return_value == 1) +) +{ + /* By default, we rely on compile-time feature detection/specification: + * If a feature is enabled at compile-time, we assume it is supported by + * the host that the resulting library/binary will be built on. + * If this assumption is not true, you MUST overwrite this function. + * See the documentation of MLD_CONFIG_CUSTOM_CAPABILITY_FUNC in + * mldsa_native_config.h for more information. */ + (void)cap; + return 1; +} +#endif /* !MLD_CONFIG_CUSTOM_CAPABILITY_FUNC */ +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_SYS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/zetas.inc b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/zetas.inc new file mode 100644 index 0000000000..dc3cf15dd3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/mldsa_native/src/zetas.inc @@ -0,0 +1,56 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include + +/* + * Table of zeta values used in the reference NTT and inverse NTT. + * See autogen for details. + */ +static const int32_t mld_zetas[MLDSA_N] = { + 0, 25847, -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 2353451, -359251, -2091905, 3119733, -2884855, + 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488, + -1119584, 2619752, -2108549, -2118186, -3859737, -1399561, -3277672, + 1757237, -19422, 4010497, 280005, 2706023, 95776, 3077325, + 3530437, -1661693, -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267, + -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596, + 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, + -2797779, -3930395, -1528703, -3677745, -3041255, -1452451, 3475950, + 2176455, -1585221, -1257611, 1939314, -4083598, -1000202, -3190144, + -3157330, -3632928, 126922, 3412210, -983419, 2147896, 2715295, + -2967645, -3693493, -411027, -2477047, -671102, -1228525, -22981, + -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944, + 508951, 3097992, 44288, -1100098, 904516, 3958618, -3724342, + -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856, + 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, + 1341330, 1285669, -1584928, -812732, -1439742, -3019102, -3881060, + -3628969, 3839961, 2091667, 3407706, 2316500, 3817976, -3342478, + 2244091, -2446433, -3562462, 266997, 2434439, -1235728, 3513181, + -3520352, -3759364, -1197226, -3193378, 900702, 1859098, 909542, + 819034, 495491, -1613174, -43260, -522500, -655327, -3122442, + 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297, + 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, + 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, + 1595974, -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, + 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100, + 1312455, 3306115, -1962642, -1279661, 1917081, -2546312, -1374803, + 1500165, 777191, 2235880, 3406031, -542412, -2831860, -1671176, + -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395, + 2454455, -164721, 1957272, 3369112, 185531, -1207385, -3183426, + 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, + -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, + 472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333, + -260646, -3833893, -2939036, -2235985, -420899, -2286327, 183443, + -976891, 1612842, -3545687, -554416, 3919660, -48306, -1362209, + 3937738, 1400424, -846154, 1976782, +}; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/test_only_rng/notrandombytes.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/test_only_rng/notrandombytes.c new file mode 100644 index 0000000000..ef5a423a9e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/test_only_rng/notrandombytes.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* * Based on @[surf]*/ + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +#include +#include + +#include "notrandombytes.h" + +#ifdef ENABLE_CT_TESTING +#include +#endif + +static uint32_t seed[32] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, + 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5}; +static uint32_t in[12]; +static uint32_t out[8]; +static int32_t outleft = 0; + +void randombytes_reset(void) +{ + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + outleft = 0; +} + +#define ROTATE(x, b) (((x) << (b)) | ((x) >> (32 - (b)))) +#define MUSH(i, b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x, b)); + +static void surf(void) +{ + uint32_t t[12]; + uint32_t x; + uint32_t sum = 0; + int32_t r; + int32_t i; + int32_t loop; + + for (i = 0; i < 12; ++i) + { + t[i] = in[i] ^ seed[12 + i]; + } + for (i = 0; i < 8; ++i) + { + out[i] = seed[24 + i]; + } + x = t[11]; + for (loop = 0; loop < 2; ++loop) + { + for (r = 0; r < 16; ++r) + { + sum += 0x9e3779b9; + MUSH(0, 5) + MUSH(1, 7) + MUSH(2, 9) + MUSH(3, 13) + MUSH(4, 5) + MUSH(5, 7) + MUSH(6, 9) + MUSH(7, 13) + MUSH(8, 5) + MUSH(9, 7) + MUSH(10, 9) + MUSH(11, 13) + } + for (i = 0; i < 8; ++i) + { + out[i] ^= t[i + 4]; + } + } +} + +int randombytes(uint8_t *buf, size_t n) +{ +#ifdef ENABLE_CT_TESTING + uint8_t *buf_orig = buf; + size_t n_orig = n; +#endif + + while (n > 0) + { + if (!outleft) + { + if (!++in[0]) + { + if (!++in[1]) + { + if (!++in[2]) + { + ++in[3]; + } + } + } + surf(); + outleft = 8; + } + *buf = (uint8_t)out[--outleft]; + ++buf; + --n; + } + +#ifdef ENABLE_CT_TESTING + /* + * Mark all randombytes output as secret (undefined). + * Valgrind will propagate this to everything derived from it. + */ + VALGRIND_MAKE_MEM_UNDEFINED(buf_orig, n_orig); +#endif /* ENABLE_CT_TESTING */ + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/test_only_rng/notrandombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/test_only_rng/notrandombytes.h new file mode 100644 index 0000000000..bdf9787920 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/custom_backend/test_only_rng/notrandombytes.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* Based on @[surf]. */ + +#ifndef NOTRANDOMBYTES_H +#define NOTRANDOMBYTES_H + +#include +#include + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +void randombytes_reset(void); +int randombytes(uint8_t *buf, size_t n); + +#endif /* !NOTRANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/.gitignore b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/.gitignore new file mode 100644 index 0000000000..eb98a94f12 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +build diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/Makefile new file mode 100644 index 0000000000..aa2d0da96e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/Makefile @@ -0,0 +1,139 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +.PHONY: build run clean +.DEFAULT_GOAL := all + +CC ?= gcc +AR ?= ar + +# Adjust CFLAGS if needed +CFLAGS := \ + -Wall \ + -Wextra \ + -Werror=unused-result \ + -Wpedantic \ + -Werror \ + -Wmissing-prototypes \ + -Wshadow \ + -Wpointer-arith \ + -Wredundant-decls \ + -Wconversion \ + -Wsign-conversion \ + -Wno-long-long \ + -Wno-unknown-pragmas \ + -Wno-unused-command-line-argument \ + -O3 \ + -fomit-frame-pointer \ + -std=c99 \ + -pedantic \ + -MMD \ + $(CFLAGS) + +# The following only concerns the cross-compilation tests. +# You can likely ignore the following for your application. +# +# Append cross-prefix for cross compilation +# When called from the root Makefile, CROSS_PREFIX has already been added here +ifeq (,$(findstring $(CROSS_PREFIX),$(CC))) +CC := $(CROSS_PREFIX)$(CC) +endif + +ifeq (,$(findstring $(CROSS_PREFIX),$(AR))) +AR := $(CROSS_PREFIX)$(AR) +endif + +Q ?= @ + +# Part A: +# +# mldsa-native source and header files +# +# Here, we use just a single monolithic compilation unit to include +# multiple instances of mldsa-native. + +MLD_SOURCE=mldsa_native/mldsa_native.c + +INC=-Imldsa_native/ -I./ + +# Part B: +# +# Random number generator +# +# !!! WARNING !!! +# +# The randombytes() implementation used here is for TESTING ONLY. +# You MUST NOT use this implementation outside of testing. +# +# !!! WARNING !!! +RNG_SOURCE=$(wildcard test_only_rng/*.c) + +# Part C: +# +# Your application source code +APP_SOURCE=$(RNG_SOURCE) main.c + +BUILD_DIR=build +BIN44=test_binary_mldsa44 +BIN65=test_binary_mldsa65 +BIN87=test_binary_mldsa87 +LIB44=libmldsa44.a +LIB65=libmldsa65.a +LIB87=libmldsa87.a + +BIN44_FULL=$(BUILD_DIR)/$(BIN44) +BIN65_FULL=$(BUILD_DIR)/$(BIN65) +BIN87_FULL=$(BUILD_DIR)/$(BIN87) + +LIB44_FULL=$(BUILD_DIR)/$(LIB44) +LIB65_FULL=$(BUILD_DIR)/$(LIB65) +LIB87_FULL=$(BUILD_DIR)/$(LIB87) + +$(LIB44_FULL): $(MLD_SOURCE) + $(Q)echo "$@" + $(Q)[ -d $(@) ] || mkdir -p $(@D) + $(Q)$(CC) -c $(CFLAGS) -DMLD_CONFIG_PARAMETER_SET=44 $(INC) $^ -o $(BUILD_DIR)/mldsa_native44.o + $(Q)$(AR) rcs $@ $(BUILD_DIR)/mldsa_native44.o + $(Q)strip -S $@ + +$(LIB65_FULL): $(MLD_SOURCE) + $(Q)echo "$@" + $(Q)[ -d $(@) ] || mkdir -p $(@D) + $(Q)$(CC) -c $(CFLAGS) -DMLD_CONFIG_PARAMETER_SET=65 $(INC) $^ -o $(BUILD_DIR)/mldsa_native65.o + $(Q)$(AR) rcs $@ $(BUILD_DIR)/mldsa_native65.o + $(Q)strip -S $@ + +$(LIB87_FULL): $(MLD_SOURCE) + $(Q)echo "$@" + $(Q)[ -d $(@) ] || mkdir -p $(@D) + $(Q)$(CC) -c $(CFLAGS) -DMLD_CONFIG_PARAMETER_SET=87 $(INC) $^ -o $(BUILD_DIR)/mldsa_native87.o + $(Q)$(AR) rcs $@ $(BUILD_DIR)/mldsa_native87.o + $(Q)strip -S $@ + +$(BIN44_FULL): $(APP_SOURCE) $(LIB44_FULL) + $(Q)echo "$@" + $(Q)[ -d $(@) ] || mkdir -p $(@D) + $(Q)$(CC) $(CFLAGS) -DMLD_CONFIG_PARAMETER_SET=44 $(INC) $^ -o $@ + +$(BIN65_FULL): $(APP_SOURCE) $(LIB65_FULL) + $(Q)echo "$@" + $(Q)[ -d $(@) ] || mkdir -p $(@D) + $(Q)$(CC) $(CFLAGS) -DMLD_CONFIG_PARAMETER_SET=65 $(INC) $^ -o $@ + +$(BIN87_FULL): $(APP_SOURCE) $(LIB87_FULL) + $(Q)echo "$@" + $(Q)[ -d $(@) ] || mkdir -p $(@D) + $(Q)$(CC) $(CFLAGS) -DMLD_CONFIG_PARAMETER_SET=87 $(INC) $^ -o $@ + +all: build + +build: $(BIN44_FULL) $(BIN65_FULL) $(BIN87_FULL) + +run: $(BIN44_FULL) $(BIN65_FULL) $(BIN87_FULL) + $(Q)$(EXEC_WRAPPER) ./$(BIN44_FULL) + $(Q)$(EXEC_WRAPPER) ./$(BIN65_FULL) + $(Q)$(EXEC_WRAPPER) ./$(BIN87_FULL) + +clean: + rm -rf $(BUILD_DIR) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/README.md new file mode 100644 index 0000000000..b7ae9b938e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/README.md @@ -0,0 +1,50 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Monolithic Build (C Backend) + +This directory contains a minimal example for building mldsa-native for a single +parameter set of ML-DSA as a single compilation unit using the auto-generated +`mldsa_native.c` file. + +## Use Case + +Use this approach when: +- You want the simplest possible build integration (one `.c` file) +- You're using only C (no native backends) +- You need only one ML-DSA parameter set (44, 65, or 87) + +## Components + +1. Source tree [mldsa_native/*](mldsa_native), including top-level compilation unit + [mldsa_native.c](mldsa_native/mldsa_native.c) (gathering all C sources) + and the mldsa-native API [mldsa_native.h](mldsa_native/mldsa_native.h). +2. A secure random number generator implementing [`randombytes.h`](../../mldsa/src/randombytes.h) +3. Your application source code + +## Configuration + +The configuration file [mldsa_native_config.h](mldsa_native/mldsa_native_config.h) sets: +- `MLD_CONFIG_PARAMETER_SET`: Security level (default 65) +- `MLD_CONFIG_NAMESPACE_PREFIX`: Symbol prefix (set to `mldsa`) +- `MLD_CONFIG_INTERNAL_API_QUALIFIER=static`: Makes internal functions static for single-CU builds + +The auto-generated `mldsa_native.c`: +- Includes all mldsa-native C source files +- Clears all internal `#define`s at the end, allowing multiple inclusion + +## Notes + +- The monolithic `.c` file is auto-generated by `scripts/autogen` +- Internal functions become `static`, enabling better compiler optimization + +## Usage + +```bash +make build # Build the example +make run # Run the example +``` + +## Warning + +The `randombytes()` implementation in `test_only_rng/` is for TESTING ONLY. +You MUST provide a cryptographically secure RNG for production use. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/expected_signatures.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/expected_signatures.h new file mode 100644 index 0000000000..d52fbe8d5e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/expected_signatures.h @@ -0,0 +1,890 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef EXPECTED_SIGNATURES_H +#define EXPECTED_SIGNATURES_H + +#include + +/* Expected deterministic signatures for each parameter set + * These are generated using the same test message, context, and deterministic + * RNG as used in the basic example. + * + * The PCT modifies the PRNG state, so the KAT tests don't work. + * We run KAT tests only for disabled PCT. */ +#if !defined(MLD_CONFIG_KEYGEN_PCT) +#if MLD_CONFIG_PARAMETER_SET == 44 +const uint8_t expected_signature[] = { + 0x27, 0x5e, 0xbe, 0x2d, 0x23, 0x1a, 0x76, 0xc5, 0xd9, 0x77, 0xcb, 0x62, + 0x25, 0x04, 0xdb, 0x23, 0x31, 0xa9, 0xa8, 0xcd, 0xbc, 0xde, 0xf2, 0x20, + 0xfd, 0xa7, 0xb5, 0xf5, 0x59, 0xae, 0xe6, 0xdd, 0x62, 0xfa, 0x34, 0x96, + 0x4f, 0x1d, 0xcd, 0x84, 0x82, 0xee, 0xc1, 0x74, 0x96, 0x3d, 0x98, 0xd9, + 0x42, 0x9d, 0xd0, 0x77, 0x9c, 0xf9, 0x9e, 0x0e, 0xa7, 0xcb, 0x70, 0xeb, + 0xe7, 0xcd, 0xce, 0x8c, 0xdc, 0x37, 0x15, 0x95, 0x0e, 0x24, 0x70, 0x4f, + 0x33, 0x6e, 0x4f, 0xad, 0xed, 0x4d, 0xf3, 0xe5, 0x38, 0xc1, 0xcd, 0xbb, + 0xde, 0xf1, 0xd2, 0x0d, 0xd6, 0x6b, 0xa3, 0x68, 0x92, 0x4c, 0x4b, 0x4f, + 0x89, 0xa0, 0xa8, 0xc8, 0x36, 0x93, 0x91, 0x17, 0xe7, 0x16, 0xed, 0xcb, + 0xdc, 0xf6, 0x28, 0x13, 0x32, 0x60, 0x14, 0xe0, 0x28, 0x7a, 0x69, 0x05, + 0x1d, 0xf7, 0x3b, 0xdf, 0x18, 0x0c, 0xaf, 0xba, 0x46, 0xf1, 0x5e, 0xd4, + 0xd3, 0xd0, 0x8e, 0x9a, 0xe2, 0xac, 0xdd, 0x0e, 0x5f, 0xb1, 0x69, 0xe2, + 0x74, 0x77, 0x2e, 0x52, 0xf9, 0x11, 0x3d, 0xd8, 0xe5, 0x36, 0x6f, 0x7d, + 0x7d, 0xde, 0x7c, 0xa7, 0x1d, 0x37, 0xdf, 0x6d, 0x5e, 0xea, 0xc8, 0xc0, + 0x72, 0x3f, 0x79, 0xbd, 0x0b, 0x6d, 0x7f, 0x9a, 0x15, 0x90, 0xda, 0xc1, + 0xae, 0xce, 0xf3, 0x44, 0x35, 0x5e, 0x83, 0x86, 0x7e, 0x89, 0x18, 0xa7, + 0x97, 0x8e, 0x87, 0x7c, 0x15, 0xd2, 0xd2, 0x7e, 0xf2, 0xc8, 0x29, 0x4f, + 0x70, 0x0f, 0xa6, 0xd4, 0x76, 0xe8, 0xdd, 0x7d, 0x7a, 0x2d, 0xfe, 0x0a, + 0x0c, 0x5c, 0xb1, 0xef, 0xec, 0x1a, 0x32, 0xca, 0x87, 0xff, 0x6b, 0xb1, + 0xa0, 0xe1, 0x2e, 0x01, 0x52, 0xb2, 0xb8, 0x74, 0x34, 0xb3, 0xfb, 0x15, + 0x0f, 0x17, 0xca, 0x74, 0xc1, 0xc1, 0x61, 0x86, 0x40, 0x38, 0x58, 0xba, + 0x82, 0x26, 0x66, 0x33, 0xa4, 0x52, 0xf3, 0xb5, 0x36, 0x60, 0xd8, 0x5a, + 0x8d, 0x9d, 0x28, 0x18, 0x3a, 0x68, 0x34, 0x2a, 0xa2, 0xe2, 0xb5, 0x39, + 0xed, 0x7d, 0xe5, 0xbe, 0x46, 0xb9, 0x04, 0x0c, 0xf3, 0xef, 0x88, 0x6e, + 0x9d, 0x6f, 0x23, 0xe2, 0x44, 0xe5, 0x2e, 0x3a, 0x7a, 0x1d, 0x49, 0x0f, + 0xdd, 0xcd, 0xd6, 0x4e, 0x0d, 0x0b, 0xc3, 0x35, 0xf2, 0xd1, 0x5d, 0x73, + 0x5d, 0x07, 0xca, 0x5c, 0xbd, 0x14, 0xec, 0x57, 0xb3, 0xbd, 0x37, 0xe7, + 0xdf, 0x06, 0x7d, 0xe0, 0x58, 0x4a, 0xcf, 0x7a, 0xc5, 0xa7, 0x24, 0x62, + 0x6f, 0x09, 0x75, 0x69, 0x74, 0x7f, 0xdf, 0xc8, 0x69, 0x5c, 0x20, 0x10, + 0x3a, 0xe8, 0x01, 0x12, 0xa3, 0xfb, 0xda, 0x4c, 0x3a, 0x0d, 0x3c, 0x3e, + 0x26, 0xe0, 0xa6, 0x7f, 0xb2, 0x6b, 0x0b, 0x68, 0x0a, 0x68, 0x86, 0xb1, + 0xfa, 0x61, 0x3a, 0xe8, 0x77, 0xdc, 0x42, 0xf7, 0xf4, 0x39, 0x9a, 0x40, + 0x58, 0x71, 0xc7, 0x0f, 0xf4, 0x0e, 0xc5, 0x1e, 0xe0, 0x28, 0x45, 0x7d, + 0xba, 0x84, 0xe4, 0x34, 0x69, 0xf9, 0xa5, 0x8a, 0x80, 0x43, 0xc0, 0x8d, + 0x04, 0x33, 0x43, 0xb8, 0xd7, 0x5d, 0x93, 0xed, 0x0f, 0x31, 0x6a, 0x4d, + 0xbf, 0xb7, 0x44, 0x41, 0x1b, 0xd4, 0xac, 0x9d, 0x83, 0x66, 0x08, 0x92, + 0xad, 0x3c, 0x0e, 0x1a, 0xe8, 0xd4, 0xe1, 0x5c, 0x63, 0xcf, 0x27, 0x48, + 0x5a, 0x8f, 0xc5, 0x6f, 0x83, 0x6b, 0x6f, 0xe8, 0xda, 0x1f, 0xba, 0xe9, + 0x7e, 0x11, 0xab, 0x8b, 0x4e, 0xc1, 0x9e, 0x23, 0x69, 0x1f, 0x42, 0x40, + 0xad, 0xbb, 0xfb, 0x4f, 0xe2, 0x50, 0xc9, 0x46, 0xe7, 0x15, 0x15, 0xf8, + 0x61, 0x09, 0x2a, 0x0b, 0x37, 0x43, 0xd4, 0x98, 0x5f, 0xc8, 0x4d, 0x06, + 0xe7, 0x0c, 0x3f, 0x83, 0x59, 0xd5, 0xcd, 0x2d, 0xde, 0x1e, 0x3a, 0x87, + 0x4e, 0xf7, 0x0a, 0x3c, 0x84, 0x72, 0x47, 0x11, 0x02, 0x6c, 0xe8, 0x93, + 0xcd, 0x24, 0xe9, 0x23, 0x86, 0x78, 0x53, 0xe0, 0xc6, 0x2f, 0xba, 0xa7, + 0xed, 0xaf, 0xba, 0x42, 0x80, 0x0d, 0xe6, 0xae, 0xda, 0xed, 0xbc, 0x65, + 0x21, 0x6d, 0x13, 0x90, 0x61, 0xb4, 0x05, 0x7b, 0x07, 0x86, 0xd7, 0x89, + 0x30, 0x9c, 0xc1, 0x9a, 0x41, 0x4d, 0xe8, 0x2b, 0x35, 0x21, 0x3a, 0x8a, + 0x60, 0x83, 0x1a, 0x97, 0x10, 0x98, 0xb6, 0xe1, 0x6b, 0xb5, 0xb1, 0xa1, + 0x36, 0x34, 0x60, 0x1b, 0x96, 0x5d, 0x1f, 0x2a, 0xd8, 0xf2, 0x94, 0xdd, + 0x58, 0x3d, 0x0f, 0xbe, 0x9d, 0xfc, 0xf5, 0x24, 0xb1, 0xd2, 0xc3, 0x36, + 0xef, 0xdb, 0x8e, 0x97, 0x3c, 0x9a, 0x4f, 0x48, 0xe3, 0x84, 0x91, 0xd8, + 0x39, 0x91, 0xf6, 0x55, 0xeb, 0x62, 0x51, 0x3d, 0x8f, 0x55, 0x60, 0x5e, + 0x00, 0xe0, 0xd2, 0xc7, 0x66, 0x51, 0xf1, 0xe2, 0xb7, 0x43, 0xc3, 0xe6, + 0x12, 0x9a, 0xe5, 0x84, 0xe0, 0x10, 0x76, 0xc7, 0x75, 0x6e, 0xa6, 0xee, + 0x11, 0xe4, 0xaf, 0xbd, 0x8a, 0x4f, 0x1d, 0x05, 0x29, 0x4f, 0xce, 0xa5, + 0x73, 0x92, 0x57, 0x7e, 0x0d, 0x11, 0xbc, 0xf8, 0x74, 0x4d, 0xf7, 0xb9, + 0x40, 0x0d, 0x5a, 0xa1, 0x19, 0x76, 0x4a, 0xae, 0x21, 0x16, 0xd4, 0x3f, + 0x76, 0xbf, 0x27, 0xbd, 0x2f, 0xe4, 0x25, 0x21, 0x00, 0x4e, 0xcc, 0x7c, + 0xc6, 0x57, 0xa4, 0xbf, 0xf1, 0x56, 0x90, 0xe0, 0xa4, 0xa3, 0xee, 0xcf, + 0x43, 0x4f, 0xda, 0x77, 0x47, 0x51, 0x79, 0x6a, 0x29, 0xb4, 0x2c, 0xdf, + 0xca, 0x47, 0xcb, 0xb8, 0x82, 0x7e, 0x44, 0x62, 0x9b, 0x8f, 0x61, 0x7b, + 0x3a, 0x93, 0x82, 0x1f, 0x69, 0xb7, 0xb1, 0xa6, 0x2c, 0xe1, 0xb2, 0x65, + 0xa0, 0x6d, 0x6f, 0xe4, 0x79, 0xd8, 0x30, 0xe0, 0xee, 0xd8, 0x83, 0x01, + 0xb2, 0x1f, 0x5c, 0x90, 0x44, 0x86, 0x48, 0x11, 0xf9, 0x11, 0xff, 0xea, + 0x45, 0x43, 0xae, 0x8a, 0x6b, 0x99, 0xf2, 0x1f, 0x02, 0x51, 0x4a, 0x35, + 0x02, 0x34, 0xd3, 0xe8, 0xda, 0xb1, 0x4b, 0xe3, 0xa5, 0x60, 0xce, 0x67, + 0xe3, 0x62, 0x59, 0xfc, 0x00, 0x0a, 0xe2, 0xfe, 0x7b, 0x1e, 0xe6, 0xf5, + 0x75, 0x19, 0x9b, 0x5e, 0xcb, 0xe6, 0xf5, 0x80, 0x9e, 0x3c, 0xb8, 0x54, + 0xd6, 0x0b, 0xfd, 0x48, 0xe0, 0xfa, 0x82, 0x2b, 0x5b, 0x26, 0xf9, 0x49, + 0xaf, 0xbe, 0x9c, 0x78, 0x73, 0xce, 0xc5, 0x65, 0xe2, 0x94, 0x2b, 0xd9, + 0xd0, 0x27, 0x3a, 0x66, 0x3e, 0xe2, 0xe0, 0x10, 0x79, 0x3d, 0xde, 0xc8, + 0x47, 0xdb, 0x1e, 0xc3, 0xe7, 0x51, 0xae, 0x59, 0xeb, 0x38, 0x66, 0x63, + 0x40, 0x8f, 0xbe, 0x1e, 0xb2, 0x2b, 0xeb, 0x64, 0x5f, 0xdd, 0x24, 0xc4, + 0x5a, 0x25, 0x59, 0xa2, 0xda, 0x4f, 0xdf, 0xf8, 0xb0, 0xb0, 0xf7, 0xcd, + 0x1f, 0x14, 0xcd, 0x09, 0x48, 0x70, 0x27, 0x1b, 0xde, 0xc4, 0xf0, 0xf3, + 0x56, 0x97, 0x8a, 0xb7, 0xf4, 0x19, 0x76, 0xe3, 0x9a, 0x33, 0x55, 0xfe, + 0x93, 0x68, 0xca, 0x1f, 0x3d, 0x44, 0x86, 0x39, 0x5d, 0x84, 0x58, 0x50, + 0xf2, 0xf1, 0xea, 0x4a, 0x5c, 0x1c, 0x74, 0xf0, 0x4b, 0xa5, 0x9c, 0x30, + 0xa0, 0x14, 0x1a, 0x80, 0xe0, 0xde, 0x3e, 0xae, 0x7f, 0x10, 0x18, 0x4a, + 0x1e, 0x9e, 0x6b, 0x75, 0x1a, 0xca, 0x08, 0x4e, 0x61, 0x72, 0x43, 0x9b, + 0x18, 0x4d, 0x2c, 0xd8, 0xb4, 0xc9, 0xea, 0x00, 0xb0, 0xdf, 0x1b, 0xcb, + 0x03, 0xc3, 0x7a, 0x27, 0xff, 0x41, 0x9d, 0xf9, 0xfd, 0xb3, 0x0c, 0xc0, + 0x48, 0x5d, 0x7c, 0xae, 0x5a, 0x72, 0x69, 0x93, 0x68, 0xe1, 0x9e, 0x9f, + 0x1f, 0x5c, 0x0a, 0x60, 0x90, 0x1a, 0x8e, 0x5a, 0x30, 0xd4, 0x2c, 0xbd, + 0xe1, 0x20, 0x51, 0xbc, 0x1c, 0x50, 0xb5, 0xf7, 0x42, 0x23, 0x35, 0x0f, + 0x92, 0xe2, 0xbb, 0x2a, 0x04, 0xa7, 0xde, 0x2e, 0x25, 0xfa, 0xed, 0x20, + 0x83, 0x9c, 0xd4, 0x56, 0xe0, 0x4d, 0x8d, 0x79, 0xa5, 0xa0, 0x6f, 0x49, + 0x62, 0x82, 0x9a, 0xa7, 0x4e, 0x54, 0x95, 0x0a, 0xc6, 0x5e, 0x27, 0x65, + 0x6d, 0x11, 0x2b, 0x35, 0x72, 0x34, 0x48, 0xd2, 0xe4, 0x9e, 0x07, 0x7d, + 0x03, 0x27, 0x15, 0x93, 0x55, 0x5c, 0x32, 0x43, 0xdb, 0x34, 0x8d, 0xbd, + 0x8d, 0x88, 0xa5, 0x24, 0x07, 0x93, 0x89, 0x37, 0xb9, 0x17, 0x15, 0xad, + 0xc7, 0x68, 0x86, 0x63, 0x0f, 0x10, 0x53, 0x8f, 0x40, 0xd3, 0x7b, 0x22, + 0x2b, 0x1a, 0x4c, 0xcb, 0x4f, 0x51, 0xf1, 0x3b, 0x19, 0xb8, 0x42, 0x53, + 0xaf, 0xf6, 0xb9, 0x57, 0x7f, 0xba, 0x8d, 0xb8, 0xb7, 0x3b, 0xe3, 0xc5, + 0xab, 0x4a, 0x26, 0x21, 0x6e, 0xce, 0x27, 0xb8, 0xc3, 0x99, 0x56, 0x14, + 0xdd, 0x5b, 0x61, 0x82, 0xbf, 0xd3, 0xc8, 0x76, 0xee, 0x22, 0xaf, 0x21, + 0x21, 0x1d, 0x4e, 0x33, 0xb5, 0x43, 0x3a, 0xfb, 0x91, 0xa0, 0xaa, 0xe3, + 0x10, 0x4a, 0x50, 0x42, 0xd4, 0x5f, 0x92, 0x0e, 0x71, 0x60, 0x4f, 0xaa, + 0xef, 0x66, 0x45, 0xfe, 0xf7, 0xc8, 0xb0, 0x73, 0x75, 0x91, 0x0b, 0x86, + 0x40, 0xa5, 0x02, 0x28, 0xf7, 0xe0, 0x1f, 0x5d, 0xe6, 0xe3, 0xa4, 0x57, + 0xbd, 0x29, 0xaa, 0x53, 0xae, 0x35, 0x30, 0x78, 0x73, 0xd6, 0xb7, 0x01, + 0x9d, 0x13, 0x50, 0xf6, 0x39, 0xa2, 0x3e, 0x03, 0x04, 0xaa, 0x6d, 0xcf, + 0x6b, 0xff, 0x9a, 0xbe, 0x3e, 0x0a, 0xd4, 0x20, 0xce, 0x42, 0x1f, 0xca, + 0x2f, 0xd3, 0x2c, 0xd1, 0xf4, 0xd2, 0x50, 0xd3, 0xa2, 0xc1, 0x1e, 0x87, + 0xbf, 0xeb, 0xb8, 0xa8, 0xd4, 0x1c, 0x96, 0xb8, 0x8e, 0xbe, 0x35, 0x5f, + 0x08, 0x28, 0x20, 0x2b, 0xdc, 0xa4, 0xf5, 0xf6, 0xde, 0xca, 0x1e, 0xcb, + 0x93, 0x3b, 0x64, 0x79, 0x00, 0x3c, 0x8d, 0xbb, 0x5c, 0x7a, 0x40, 0x14, + 0x58, 0x12, 0xa4, 0xf7, 0x6e, 0x51, 0xfb, 0xe7, 0x6f, 0x49, 0x5b, 0xc2, + 0xc9, 0x05, 0x38, 0x9c, 0x08, 0x78, 0x71, 0x27, 0x2b, 0xf5, 0xbf, 0xd6, + 0x38, 0xaa, 0x45, 0xe1, 0xe1, 0x4c, 0xfb, 0xfd, 0xb7, 0xe6, 0xcf, 0xad, + 0x9e, 0x56, 0xaf, 0x12, 0x12, 0x98, 0xe6, 0x38, 0xaa, 0xee, 0xdb, 0x9e, + 0xca, 0xe1, 0x79, 0x6d, 0x44, 0xfb, 0x19, 0x50, 0x92, 0x00, 0x06, 0x2c, + 0x24, 0x71, 0x6c, 0x34, 0x45, 0xac, 0xf9, 0x82, 0x66, 0xa8, 0x63, 0x80, + 0xa8, 0x5b, 0x21, 0x3c, 0x36, 0x71, 0x93, 0x40, 0x7b, 0xff, 0xa2, 0xd0, + 0x72, 0xb4, 0x66, 0xfa, 0xfc, 0xa0, 0xee, 0xca, 0x15, 0x73, 0x52, 0xe7, + 0x9d, 0x11, 0xd3, 0xbc, 0xab, 0x37, 0x31, 0x0e, 0xaf, 0xdc, 0x05, 0x30, + 0x79, 0x8c, 0x25, 0x75, 0x5c, 0x60, 0xc7, 0x9a, 0xfc, 0x88, 0xea, 0xe6, + 0x09, 0x9f, 0xd1, 0x4f, 0x13, 0xf4, 0x41, 0x54, 0x5b, 0x7a, 0xe4, 0x49, + 0x3c, 0x0f, 0x15, 0xe9, 0xa4, 0x85, 0xb2, 0x92, 0x07, 0xea, 0xea, 0x7c, + 0xc1, 0x6d, 0xa9, 0x03, 0xb3, 0x31, 0xce, 0x1e, 0x82, 0xca, 0x9e, 0x3c, + 0x88, 0x88, 0xc1, 0x04, 0x5f, 0xbe, 0xd5, 0x94, 0x0d, 0x67, 0x98, 0x27, + 0xd0, 0x0f, 0x43, 0xf3, 0xb3, 0xfc, 0xff, 0x24, 0xa2, 0x1e, 0x17, 0x06, + 0xb0, 0x52, 0x16, 0x7c, 0xd8, 0x49, 0x74, 0x51, 0xcf, 0x2d, 0x36, 0x16, + 0xb0, 0x88, 0xb2, 0x2b, 0x1d, 0x72, 0x70, 0xab, 0xe2, 0xf6, 0x5f, 0xa5, + 0x2d, 0x4e, 0xd1, 0x42, 0x3c, 0x83, 0x84, 0xb2, 0x56, 0xeb, 0x8d, 0xce, + 0x33, 0x46, 0xdb, 0x3d, 0x4f, 0x97, 0xea, 0x37, 0x5e, 0x0d, 0xd7, 0x4c, + 0x9a, 0x7e, 0xc9, 0x0e, 0x69, 0x4d, 0x97, 0x15, 0x1e, 0x09, 0xbe, 0x7e, + 0xff, 0xe8, 0xf5, 0xab, 0xe9, 0xe7, 0xed, 0x4b, 0x41, 0xa5, 0xf2, 0x2a, + 0x24, 0x48, 0x8b, 0x72, 0x4b, 0x9d, 0xcf, 0x45, 0xdb, 0xc0, 0xaf, 0xa8, + 0x0f, 0x0f, 0x67, 0x37, 0xd3, 0x8b, 0xe1, 0x67, 0x90, 0xd8, 0x1c, 0x58, + 0x36, 0x46, 0x51, 0x52, 0xea, 0xb4, 0x75, 0xb1, 0xcd, 0xc5, 0x39, 0x16, + 0xe0, 0xec, 0x16, 0xf7, 0xf8, 0x0f, 0x5d, 0x13, 0x84, 0x62, 0x34, 0x86, + 0x42, 0x05, 0xa8, 0x08, 0x84, 0xa9, 0x77, 0x12, 0xc1, 0x56, 0xdd, 0x28, + 0xde, 0x39, 0x33, 0x21, 0x3d, 0xbd, 0x94, 0xce, 0xe4, 0xb3, 0x17, 0x9b, + 0x09, 0x20, 0xf0, 0x25, 0xce, 0x00, 0x34, 0x8e, 0x12, 0x94, 0x74, 0x0b, + 0x16, 0xa1, 0x60, 0x76, 0x24, 0xf0, 0xbf, 0xe3, 0x3a, 0x83, 0x8f, 0x40, + 0x47, 0x2e, 0x1c, 0xd5, 0x35, 0x25, 0x87, 0xb3, 0x11, 0xdc, 0x98, 0xb0, + 0xa6, 0x5f, 0x6a, 0x05, 0x1d, 0x06, 0x8d, 0xe8, 0xb0, 0x98, 0xf0, 0x43, + 0x29, 0x84, 0xe4, 0xef, 0x34, 0x67, 0x74, 0x64, 0xe8, 0xb8, 0xf0, 0xd4, + 0x9e, 0xc1, 0x3f, 0x5f, 0xeb, 0xe0, 0x9b, 0x37, 0xf8, 0x75, 0x46, 0x47, + 0xa5, 0x3e, 0x42, 0x20, 0x50, 0xc4, 0x5d, 0xf3, 0xdf, 0x4e, 0xf8, 0x0e, + 0x1e, 0x15, 0x10, 0x3e, 0xf1, 0x68, 0xad, 0x87, 0xad, 0xe5, 0x45, 0x5e, + 0x22, 0xba, 0x2e, 0x51, 0xa0, 0xbf, 0xdc, 0x87, 0xca, 0xe4, 0x1f, 0x2f, + 0x2c, 0xae, 0xa9, 0x14, 0xd7, 0xdd, 0x01, 0xa8, 0x4f, 0x43, 0xcb, 0x84, + 0x92, 0xbf, 0xf9, 0x3d, 0xf0, 0x6b, 0x19, 0x43, 0xb0, 0xdf, 0xff, 0x94, + 0x76, 0xe2, 0x84, 0xf9, 0x31, 0x88, 0x7e, 0xc6, 0x87, 0x58, 0xbe, 0x5d, + 0x8b, 0xf8, 0xb5, 0xdc, 0x95, 0x16, 0x5f, 0xa1, 0x2c, 0xe8, 0x53, 0x36, + 0x64, 0xf5, 0x5d, 0xa0, 0x74, 0x12, 0x78, 0x59, 0x73, 0x69, 0x5a, 0x2b, + 0x36, 0x4a, 0xff, 0x5b, 0xef, 0x49, 0x2c, 0xb2, 0x9e, 0x59, 0xf0, 0x39, + 0x56, 0xe1, 0xd0, 0x1a, 0x05, 0xb2, 0x7c, 0xd1, 0x40, 0x09, 0xdf, 0x00, + 0xc9, 0x15, 0x53, 0xa2, 0xda, 0x84, 0xb5, 0x85, 0x05, 0x76, 0xa6, 0x1b, + 0xcb, 0x06, 0xb2, 0xc8, 0xa0, 0xc5, 0x23, 0x8f, 0xb0, 0xe8, 0xf5, 0xd9, + 0xd0, 0x19, 0x29, 0xfe, 0x2d, 0x9a, 0x57, 0x76, 0x5f, 0xf2, 0xef, 0x71, + 0x16, 0xee, 0x28, 0x7b, 0xe4, 0x48, 0xeb, 0xda, 0xe0, 0xd5, 0xbc, 0x0e, + 0x46, 0x6b, 0x06, 0x5d, 0xe5, 0x91, 0x2d, 0xcb, 0xc4, 0x53, 0xa6, 0x16, + 0xd5, 0xe7, 0xd8, 0xf1, 0xdd, 0x4f, 0xbb, 0xcc, 0x55, 0x67, 0x19, 0x98, + 0x94, 0x95, 0x5e, 0xd6, 0xf5, 0xf7, 0xe8, 0x6a, 0xf7, 0x20, 0x86, 0x3a, + 0x43, 0xbf, 0xe9, 0xec, 0x6b, 0x33, 0x49, 0x19, 0x43, 0xfb, 0xeb, 0x3f, + 0xf4, 0x9d, 0x29, 0x66, 0xb9, 0x6e, 0xb5, 0x15, 0x4b, 0x8d, 0x3c, 0x3c, + 0xfa, 0xf2, 0x87, 0xba, 0x61, 0x11, 0x40, 0xe6, 0xb4, 0x6f, 0xf5, 0xe1, + 0x24, 0x32, 0x69, 0x3e, 0xff, 0xf7, 0xbc, 0xee, 0x82, 0xf2, 0x9e, 0x6d, + 0x3f, 0x6c, 0xcc, 0x0f, 0x4f, 0xc3, 0xf1, 0xdb, 0x1e, 0x81, 0xd7, 0x9b, + 0x22, 0xa8, 0xa7, 0x36, 0x6d, 0xa9, 0x6f, 0x46, 0x1a, 0xa7, 0xff, 0x00, + 0x4b, 0xd8, 0xab, 0xe7, 0x50, 0x3b, 0xe9, 0xc0, 0x57, 0xec, 0x8d, 0x0c, + 0xa0, 0xee, 0x8c, 0x2a, 0x74, 0xf2, 0x94, 0xf9, 0x0c, 0x20, 0x14, 0xd9, + 0xad, 0x0d, 0x4e, 0xac, 0x35, 0x44, 0x59, 0x28, 0x24, 0x31, 0x32, 0xaa, + 0x6d, 0xc2, 0x13, 0xb9, 0xee, 0x75, 0x0c, 0x5f, 0x39, 0xef, 0x31, 0xca, + 0x28, 0x48, 0x56, 0x59, 0xfb, 0xa8, 0xd8, 0x2b, 0x70, 0x61, 0x22, 0x43, + 0x43, 0xb9, 0x60, 0x44, 0xeb, 0xf8, 0x98, 0x87, 0x25, 0x84, 0xa2, 0xaa, + 0x37, 0xd4, 0xb8, 0xd6, 0x3d, 0xa3, 0xa1, 0x4a, 0x81, 0xc2, 0xa9, 0xea, + 0xa2, 0xd6, 0x63, 0x76, 0x50, 0xeb, 0xcd, 0x19, 0x40, 0xb1, 0x7c, 0xf6, + 0xc1, 0x44, 0x01, 0x25, 0xe0, 0xdd, 0xb8, 0x39, 0xef, 0x46, 0x3d, 0x50, + 0x33, 0xed, 0xb1, 0x63, 0x65, 0xd7, 0x50, 0xe7, 0x95, 0xba, 0xab, 0xa7, + 0x14, 0xe5, 0x60, 0xcb, 0x81, 0x6e, 0x88, 0x3c, 0x06, 0x6e, 0x7d, 0x8e, + 0xe7, 0xbb, 0xa5, 0xc2, 0xbd, 0xae, 0x46, 0x8f, 0x43, 0x04, 0x29, 0xe6, + 0x17, 0x38, 0x05, 0x2d, 0x97, 0x93, 0x5b, 0xf9, 0xef, 0x4d, 0x2e, 0x75, + 0x6c, 0x69, 0xba, 0x08, 0xf2, 0x21, 0x1e, 0x21, 0xe6, 0x8a, 0x5b, 0x8c, + 0xd4, 0x8e, 0xde, 0x64, 0x9b, 0x9d, 0x54, 0x58, 0x65, 0x3e, 0xdd, 0x8a, + 0x1e, 0x81, 0x4e, 0x45, 0xe8, 0xfb, 0x20, 0xc3, 0x3a, 0xf0, 0x50, 0x1e, + 0x8a, 0x18, 0xea, 0x2b, 0xf5, 0xe1, 0xa6, 0xb6, 0xc8, 0xa0, 0x02, 0x3d, + 0x6e, 0xfa, 0x0b, 0x51, 0x95, 0x4e, 0x4c, 0x11, 0xb0, 0xc4, 0x62, 0x58, + 0xa6, 0x9c, 0x13, 0x4e, 0xbe, 0xc9, 0x29, 0x93, 0x29, 0x15, 0x5f, 0xaf, + 0x0e, 0xc3, 0xb3, 0x26, 0x3f, 0xdc, 0x4c, 0x33, 0xb8, 0x4b, 0x11, 0xae, + 0x1f, 0xd7, 0x05, 0x39, 0xcf, 0xfe, 0xc3, 0x6d, 0xf0, 0xc0, 0x77, 0x02, + 0xb8, 0x9b, 0x3d, 0x1b, 0x3d, 0x72, 0xfe, 0x7e, 0x18, 0x60, 0x9b, 0xc4, + 0x8b, 0xac, 0x25, 0x6d, 0x3b, 0x80, 0x34, 0xbc, 0x51, 0xaf, 0xf6, 0xff, + 0x66, 0x98, 0x86, 0x6e, 0x9e, 0x9a, 0xfe, 0x6d, 0x21, 0x4d, 0xf1, 0x58, + 0x3e, 0x3e, 0x43, 0xe3, 0x7e, 0x40, 0xb0, 0xb3, 0xd8, 0x12, 0xa5, 0xce, + 0x09, 0x41, 0x8c, 0x1d, 0x73, 0xcd, 0xfc, 0x63, 0xed, 0xeb, 0x08, 0x1e, + 0x34, 0xfb, 0xed, 0x75, 0xb7, 0x86, 0x84, 0x7c, 0x80, 0xe9, 0xe4, 0xa3, + 0x1c, 0x4a, 0x0d, 0x11, 0x16, 0x24, 0xb2, 0xb1, 0x99, 0xe5, 0xe3, 0x2e, + 0x2f, 0x70, 0xcd, 0x1e, 0x35, 0x14, 0x79, 0xba, 0xa2, 0x51, 0x7a, 0x29, + 0x5c, 0x75, 0x8f, 0xdd, 0x22, 0xdf, 0xb2, 0x64, 0xd9, 0x95, 0x11, 0x33, + 0x97, 0xee, 0x69, 0x42, 0x01, 0x96, 0x98, 0x1b, 0x43, 0xc2, 0xec, 0xf9, + 0xb0, 0xdb, 0x69, 0x34, 0xab, 0x98, 0x1b, 0xb2, 0x04, 0x05, 0x14, 0x1d, + 0x25, 0x2f, 0x32, 0x41, 0x50, 0x51, 0x55, 0x62, 0x6d, 0x78, 0x7f, 0x8b, + 0xbb, 0xc2, 0xcd, 0xcf, 0xe4, 0xed, 0x04, 0x1f, 0x25, 0x30, 0x43, 0x64, + 0x69, 0x7c, 0x87, 0xa3, 0xa9, 0xb1, 0xc1, 0xd1, 0xdc, 0x01, 0x10, 0x1d, + 0x27, 0x3f, 0x5c, 0x5d, 0x75, 0x82, 0x9b, 0xaa, 0xb3, 0xe8, 0x0c, 0x11, + 0x1f, 0x24, 0x38, 0x41, 0x45, 0x54, 0x5f, 0x69, 0x85, 0x8d, 0x93, 0x9e, + 0xc5, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x25, 0x32, 0x42}; +#elif MLD_CONFIG_PARAMETER_SET == 65 +const uint8_t expected_signature[] = { + 0x8b, 0x6f, 0x79, 0x00, 0xcc, 0x79, 0x57, 0xee, 0x16, 0x86, 0x87, 0xd5, + 0xcf, 0xb6, 0x90, 0x2c, 0xc6, 0x30, 0xeb, 0x8d, 0x39, 0xae, 0x9b, 0xf1, + 0x66, 0xe0, 0xd6, 0x93, 0xa5, 0x4e, 0x26, 0x9b, 0x96, 0x8f, 0xd1, 0x46, + 0x97, 0xbe, 0x71, 0x1c, 0xf3, 0xa5, 0xe5, 0xae, 0x8d, 0x4b, 0xf2, 0xe6, + 0x48, 0x8f, 0xe9, 0x5e, 0x07, 0xef, 0xe4, 0xbb, 0x39, 0xc1, 0xc9, 0x3c, + 0xc3, 0x0b, 0xfb, 0x2a, 0x29, 0x06, 0xfe, 0x01, 0xcb, 0x63, 0x83, 0x10, + 0xa8, 0xc8, 0xa0, 0x29, 0xa5, 0x80, 0xeb, 0xbd, 0xa9, 0xd9, 0x0b, 0x61, + 0xbc, 0xce, 0x11, 0x55, 0x66, 0x12, 0xc7, 0x5b, 0xd2, 0x7a, 0x5a, 0xc8, + 0xab, 0xab, 0xbf, 0x3a, 0x1f, 0x96, 0x1a, 0x70, 0xcb, 0x41, 0x5f, 0xc8, + 0xb7, 0x09, 0x22, 0x98, 0x9b, 0xb8, 0xf7, 0x2d, 0x49, 0x65, 0x1d, 0x09, + 0x8b, 0x70, 0xb5, 0x42, 0xc9, 0x89, 0x5b, 0x74, 0xb4, 0x28, 0x82, 0x01, + 0x53, 0x12, 0x3e, 0x23, 0xf6, 0x54, 0xf8, 0x51, 0x12, 0x4b, 0x02, 0x3a, + 0x7e, 0xb6, 0x1f, 0xac, 0xa0, 0xe6, 0x6f, 0xf8, 0x61, 0x82, 0xe4, 0xfb, + 0x96, 0x2a, 0xd2, 0xaf, 0x3c, 0xea, 0x6e, 0xdc, 0x18, 0x8a, 0x5d, 0x90, + 0xda, 0xa2, 0x5d, 0xa7, 0x8f, 0x5b, 0x50, 0x46, 0xaf, 0x8c, 0x17, 0x6a, + 0x4c, 0x39, 0xfc, 0x31, 0x4c, 0x4b, 0xc2, 0x57, 0x66, 0x61, 0x98, 0xbf, + 0xe6, 0xfb, 0x54, 0x96, 0xd3, 0x70, 0xb8, 0xaf, 0xcd, 0x8b, 0xcc, 0x00, + 0x07, 0x92, 0x15, 0xc2, 0xbb, 0x48, 0xbb, 0xc6, 0xb7, 0xb5, 0x58, 0x8c, + 0xfc, 0xf0, 0xda, 0x6a, 0x0d, 0xf7, 0x1d, 0x7d, 0xc6, 0x27, 0x26, 0x1a, + 0x99, 0xc5, 0x2f, 0xf8, 0x97, 0x65, 0x43, 0x86, 0xd6, 0x25, 0x23, 0x2b, + 0x06, 0x8f, 0x12, 0xa1, 0xae, 0xbb, 0x58, 0x34, 0x25, 0xec, 0x5b, 0x68, + 0xa4, 0xe1, 0x03, 0xfc, 0x26, 0xa2, 0xd6, 0x2b, 0x61, 0x10, 0x47, 0xbd, + 0x16, 0xe5, 0xca, 0x4a, 0xce, 0xed, 0x89, 0x09, 0x1a, 0xed, 0x22, 0xc1, + 0xca, 0x44, 0xe3, 0xef, 0x72, 0x34, 0xab, 0xab, 0x61, 0x5c, 0x9f, 0x5f, + 0xb5, 0xf5, 0xe8, 0x2d, 0x89, 0xea, 0x4b, 0x40, 0x65, 0x57, 0x8b, 0xa2, + 0x95, 0x40, 0x9c, 0x72, 0xc0, 0x46, 0x69, 0x45, 0x06, 0xf6, 0x07, 0x5b, + 0x2d, 0xa5, 0x46, 0xca, 0x5d, 0xfb, 0x40, 0xb7, 0x48, 0x59, 0x5b, 0xe2, + 0x1b, 0x38, 0xb2, 0x15, 0x75, 0x66, 0x67, 0x58, 0x00, 0x3f, 0xde, 0x8a, + 0x63, 0x13, 0x34, 0x6a, 0x30, 0xca, 0xb4, 0xd5, 0x3e, 0xe0, 0x6d, 0x14, + 0xb8, 0x9a, 0x48, 0xef, 0xfd, 0xbd, 0x6d, 0x20, 0x11, 0x4d, 0x25, 0xe5, + 0xab, 0x15, 0x8d, 0xe5, 0x91, 0xbc, 0xc6, 0x69, 0x8a, 0xf8, 0xab, 0x3a, + 0x82, 0xae, 0xc5, 0x03, 0x2c, 0xcf, 0x54, 0xdc, 0xcd, 0xe8, 0x49, 0x53, + 0xb5, 0xd8, 0xc2, 0x24, 0xf8, 0x8c, 0x38, 0x8f, 0xe3, 0xfe, 0x3a, 0x18, + 0x15, 0xa8, 0xda, 0x77, 0xc8, 0x81, 0x72, 0xc6, 0xc1, 0x60, 0xa3, 0x73, + 0x65, 0x68, 0x5c, 0xf3, 0x1d, 0x8d, 0x61, 0x21, 0x65, 0xfb, 0x45, 0xc4, + 0x4c, 0x31, 0x88, 0x25, 0x0d, 0x52, 0x75, 0x3b, 0xec, 0x54, 0xe0, 0xb1, + 0x9c, 0x7c, 0xdf, 0xe3, 0x3b, 0x77, 0x31, 0x33, 0xd7, 0x25, 0x99, 0xff, + 0xc5, 0x40, 0x1e, 0x85, 0x09, 0xfd, 0x2d, 0x24, 0x4a, 0x92, 0xe7, 0x77, + 0x48, 0xa5, 0x46, 0xf4, 0x8e, 0xa3, 0x6b, 0x24, 0xe4, 0x6b, 0x31, 0xf6, + 0xe0, 0x16, 0x49, 0x9b, 0x9f, 0xa3, 0x1a, 0x5c, 0x05, 0x5e, 0x81, 0x62, + 0xc8, 0x14, 0x52, 0xb4, 0x21, 0xfd, 0x76, 0x6d, 0x88, 0xe9, 0x3b, 0x0b, + 0x75, 0x27, 0x92, 0x47, 0x5a, 0x58, 0x08, 0x26, 0xa7, 0xa2, 0x48, 0x1c, + 0x14, 0x3e, 0x5e, 0xdf, 0x81, 0x83, 0x83, 0x3e, 0xc6, 0x72, 0x27, 0xc4, + 0x6a, 0x46, 0x2b, 0xf2, 0x8d, 0x42, 0x11, 0xb9, 0x15, 0xd7, 0xf0, 0x20, + 0x29, 0x53, 0xba, 0xf0, 0x6e, 0x41, 0x3d, 0xee, 0x19, 0xf2, 0x43, 0xf3, + 0x6d, 0x00, 0xe2, 0x43, 0x77, 0xb9, 0xa9, 0x78, 0x34, 0x48, 0x3c, 0x1a, + 0x8b, 0xbd, 0xa1, 0xe5, 0x90, 0x59, 0x5b, 0xd6, 0x1e, 0x22, 0xdf, 0xb2, + 0xa7, 0x96, 0x7d, 0x55, 0x86, 0x66, 0x95, 0xb7, 0x06, 0xe7, 0x60, 0x2a, + 0x01, 0x48, 0x3f, 0xd4, 0xa7, 0xd4, 0xc2, 0x38, 0xa4, 0x10, 0x8e, 0x4f, + 0x97, 0xad, 0xa3, 0xb9, 0xe2, 0xaa, 0x13, 0xb1, 0x16, 0x89, 0x3d, 0x74, + 0x60, 0x94, 0x8c, 0xc3, 0xe6, 0x5f, 0xcf, 0xdc, 0x58, 0x17, 0x98, 0x27, + 0x86, 0xae, 0x2a, 0x0d, 0xe8, 0x33, 0x79, 0xc8, 0xc8, 0x5b, 0x59, 0xb0, + 0xba, 0xac, 0xd3, 0x6e, 0x2d, 0x7b, 0x0b, 0x9a, 0xb5, 0xfd, 0x58, 0x42, + 0xeb, 0x80, 0xf4, 0x6b, 0x9a, 0x2f, 0x19, 0x43, 0x75, 0xb4, 0xcb, 0xc9, + 0xd5, 0x28, 0xf5, 0xb9, 0x67, 0x82, 0xb4, 0xed, 0x8c, 0x3f, 0x3d, 0x6b, + 0x6d, 0x1b, 0x80, 0x13, 0x5c, 0x7b, 0x2e, 0xfa, 0xa0, 0x32, 0xba, 0xb5, + 0x46, 0xd6, 0xe7, 0x90, 0xe9, 0xd1, 0x91, 0xa0, 0xaa, 0x26, 0x35, 0xa2, + 0x0d, 0x98, 0x44, 0x11, 0xae, 0xf9, 0xc5, 0x12, 0x4d, 0x1a, 0x7c, 0x53, + 0xea, 0xf6, 0x05, 0x8d, 0x3a, 0x74, 0x92, 0xc9, 0x65, 0xeb, 0x6f, 0xb5, + 0xb4, 0xd2, 0xcd, 0x5c, 0xec, 0xaf, 0x95, 0xcb, 0xb4, 0x3c, 0x22, 0xca, + 0x1c, 0x06, 0x85, 0x16, 0x96, 0x24, 0x8c, 0x6c, 0x80, 0xf8, 0xb3, 0xa7, + 0x87, 0x77, 0xeb, 0x09, 0x71, 0xc8, 0x95, 0xfb, 0x5e, 0xe5, 0x6f, 0x78, + 0xf9, 0x60, 0xf9, 0x9e, 0x58, 0x7b, 0xbd, 0x47, 0xdd, 0x48, 0x2e, 0x56, + 0xcd, 0x63, 0x72, 0xc9, 0x4b, 0x65, 0x2d, 0x41, 0xe8, 0x81, 0x19, 0x33, + 0x4b, 0xf6, 0x02, 0xc6, 0xcb, 0x2e, 0xdf, 0x3d, 0xc8, 0xdd, 0x2f, 0x0f, + 0x09, 0x67, 0xf0, 0xaa, 0x3c, 0x51, 0xdc, 0x8d, 0xc6, 0xc3, 0xb2, 0x3b, + 0x15, 0x85, 0xcb, 0xeb, 0x62, 0xef, 0xa3, 0xf9, 0x94, 0xf4, 0x35, 0x9c, + 0x59, 0xcc, 0xc2, 0x68, 0xb4, 0xde, 0x02, 0x75, 0x8e, 0xf5, 0x33, 0xca, + 0xd5, 0xc5, 0x24, 0xae, 0xf6, 0xde, 0x2b, 0x01, 0xf4, 0x56, 0xb9, 0xa5, + 0xa7, 0xe0, 0x64, 0x2e, 0xba, 0x1d, 0x53, 0x54, 0x46, 0xcf, 0x64, 0x16, + 0x12, 0xe2, 0xa6, 0xcc, 0x18, 0xb4, 0x77, 0x8b, 0x19, 0x50, 0x43, 0x96, + 0xc8, 0x5d, 0xc3, 0x58, 0xf0, 0xfd, 0x5e, 0x13, 0xa9, 0x10, 0x67, 0xdf, + 0x25, 0xdb, 0xaf, 0x38, 0x5f, 0xbd, 0x35, 0xc1, 0x49, 0x44, 0xe8, 0x1f, + 0x12, 0xa4, 0x7c, 0x28, 0xa3, 0xd6, 0x0d, 0x6f, 0x44, 0xa9, 0x5f, 0xfc, + 0x9f, 0xfa, 0x11, 0x62, 0x87, 0x5b, 0x0e, 0x91, 0xd4, 0xb6, 0xd3, 0x71, + 0xc2, 0x77, 0x19, 0xf6, 0x7c, 0x11, 0x30, 0x5e, 0x5c, 0xd3, 0x1e, 0x90, + 0x05, 0x31, 0x63, 0xbb, 0xef, 0x85, 0xe0, 0x27, 0x94, 0x80, 0xcb, 0x33, + 0xbc, 0x5e, 0x45, 0x87, 0x62, 0xdf, 0xd4, 0x12, 0x2f, 0xf5, 0x41, 0x15, + 0x03, 0x0c, 0x80, 0xe8, 0xe2, 0x06, 0xde, 0x4b, 0x46, 0x70, 0x94, 0xd2, + 0x0d, 0x85, 0x72, 0x27, 0xe5, 0x6c, 0xeb, 0xd2, 0x78, 0x0b, 0x38, 0x40, + 0xe8, 0xdb, 0x47, 0x5c, 0xba, 0xd0, 0x21, 0x33, 0x8f, 0xb8, 0xc0, 0x66, + 0x1e, 0xd1, 0xb0, 0x94, 0xa3, 0x39, 0xc7, 0x87, 0xaf, 0x97, 0x98, 0xce, + 0x6d, 0x03, 0x1a, 0xdb, 0x52, 0x96, 0x0b, 0x9d, 0x5b, 0xf8, 0xa3, 0xf4, + 0x41, 0x95, 0x72, 0xad, 0x0e, 0x98, 0x61, 0x7f, 0xf3, 0x8f, 0x23, 0xeb, + 0xc0, 0xdf, 0xd7, 0x70, 0x26, 0x8c, 0xb3, 0xb3, 0xf0, 0xa2, 0x8a, 0x39, + 0xdd, 0x61, 0xb4, 0x53, 0xe0, 0x2a, 0x6f, 0x91, 0x34, 0x9c, 0x76, 0xf6, + 0x52, 0x93, 0xe6, 0x39, 0xb7, 0x54, 0x07, 0x46, 0x82, 0x2d, 0x05, 0x6d, + 0x9a, 0x00, 0x53, 0x65, 0x68, 0x93, 0x91, 0x00, 0xda, 0xe0, 0x93, 0x34, + 0x60, 0xb1, 0x93, 0x0b, 0x64, 0xa8, 0x12, 0xd2, 0x51, 0x3c, 0xdb, 0xb0, + 0x4c, 0x39, 0x4e, 0xce, 0xbd, 0xf0, 0x65, 0x12, 0x8a, 0xd4, 0x80, 0x7d, + 0x82, 0x85, 0xe4, 0x92, 0xc2, 0x77, 0x1e, 0xcf, 0xd9, 0xab, 0x0f, 0x9b, + 0x32, 0x2e, 0x3f, 0xe1, 0x0e, 0x87, 0x1c, 0x87, 0x34, 0xe7, 0x93, 0x16, + 0x95, 0x09, 0x7d, 0x24, 0xa8, 0xb5, 0xe0, 0x9f, 0x23, 0x87, 0x5c, 0x0b, + 0x31, 0x4a, 0x2f, 0xe2, 0x5c, 0x82, 0x49, 0x51, 0xe4, 0x93, 0xcb, 0x05, + 0x23, 0x4f, 0x8a, 0x83, 0x88, 0xfb, 0x89, 0xb0, 0x08, 0xd6, 0x64, 0xad, + 0x51, 0x84, 0x40, 0x29, 0xb1, 0xca, 0x74, 0x26, 0x29, 0x5a, 0x61, 0x01, + 0x2e, 0xa0, 0xeb, 0xeb, 0x02, 0xb5, 0xff, 0xd8, 0x20, 0x6a, 0x5e, 0x8d, + 0x17, 0x1e, 0xa3, 0xd7, 0x2f, 0x20, 0x0b, 0x93, 0x17, 0x24, 0xf7, 0x90, + 0x7b, 0xc6, 0xba, 0xd8, 0xf9, 0xe9, 0x0a, 0x2a, 0x7a, 0x81, 0x23, 0x81, + 0x03, 0x6f, 0x1e, 0x0d, 0x87, 0x83, 0xd1, 0xcf, 0x92, 0x2f, 0x19, 0x82, + 0x4e, 0x6c, 0x0a, 0x02, 0xb6, 0x70, 0xbc, 0xe1, 0x58, 0xe7, 0x16, 0xdb, + 0x2f, 0x74, 0x9f, 0xe1, 0xc2, 0x1e, 0x64, 0xc6, 0x48, 0x08, 0xee, 0xea, + 0x52, 0x9a, 0xce, 0x2c, 0xc5, 0x0c, 0x7a, 0x63, 0xf1, 0x6a, 0xbd, 0x2c, + 0x8b, 0xd5, 0x4a, 0xfa, 0x1e, 0xab, 0x9a, 0x5b, 0x25, 0xb8, 0xfa, 0x0a, + 0xe9, 0x68, 0x80, 0x6f, 0x80, 0x57, 0x10, 0x54, 0xb8, 0xa2, 0x16, 0xbd, + 0xfe, 0xf7, 0xea, 0x01, 0xc7, 0x94, 0x5a, 0x95, 0xe3, 0x61, 0xa5, 0x49, + 0x84, 0xf5, 0x79, 0x78, 0xb5, 0x0a, 0x96, 0xca, 0x01, 0x1b, 0xd0, 0x0b, + 0x51, 0x30, 0xd3, 0x48, 0xfc, 0x4d, 0x50, 0x71, 0x09, 0x73, 0xea, 0x37, + 0xcd, 0x9d, 0x3d, 0xde, 0x30, 0x56, 0x21, 0xf0, 0xef, 0x84, 0xad, 0x27, + 0xe1, 0x83, 0xdb, 0xfb, 0xcd, 0x11, 0xb2, 0xbd, 0x30, 0x67, 0x8a, 0x88, + 0x09, 0x0e, 0x9d, 0x96, 0x09, 0xba, 0xda, 0x9d, 0xf0, 0xe9, 0xb4, 0xa6, + 0x7a, 0x04, 0xf9, 0x4b, 0xb8, 0x51, 0xa9, 0x99, 0xf3, 0xbb, 0x77, 0x95, + 0x0a, 0xa1, 0xa6, 0xa1, 0x24, 0xfc, 0xcc, 0x45, 0xe8, 0x83, 0xc8, 0x6f, + 0x48, 0xad, 0x9a, 0x73, 0xd0, 0xe0, 0x57, 0x7d, 0xe4, 0x78, 0x65, 0xef, + 0xae, 0xc2, 0xfe, 0x7a, 0x56, 0xaf, 0x03, 0x71, 0x2b, 0xe6, 0xa1, 0x7e, + 0xe5, 0x12, 0xf8, 0xc3, 0x75, 0xc7, 0x22, 0x5f, 0x1b, 0x52, 0x90, 0xe5, + 0xdf, 0xba, 0x9d, 0xe2, 0x68, 0xe0, 0xb3, 0x7a, 0x9e, 0x14, 0xff, 0xb5, + 0x0a, 0x80, 0x20, 0x49, 0x88, 0xe9, 0x9c, 0xe4, 0xb5, 0xaf, 0x7e, 0x51, + 0xec, 0xe7, 0xfc, 0x64, 0x65, 0x21, 0x10, 0xc6, 0x1f, 0x7f, 0x93, 0x7d, + 0xd8, 0xf5, 0xd0, 0x98, 0x94, 0x44, 0xf8, 0x49, 0x6a, 0x51, 0x0a, 0x54, + 0xf4, 0x9f, 0xee, 0x3c, 0x56, 0xbf, 0x4c, 0xe4, 0xde, 0x1c, 0x9b, 0x11, + 0x7e, 0x9a, 0x71, 0x11, 0x80, 0x33, 0xd5, 0xb0, 0x9b, 0xef, 0x67, 0x29, + 0xa4, 0x7d, 0x70, 0x31, 0x3f, 0x8b, 0x2e, 0x4a, 0x0f, 0x2c, 0x91, 0x3d, + 0x3e, 0x3d, 0x8c, 0x0a, 0x2b, 0xf1, 0xdd, 0xbf, 0x61, 0xe6, 0xa3, 0xef, + 0x6d, 0x82, 0xc8, 0xb7, 0x5e, 0x2b, 0x83, 0xc9, 0x4e, 0xa0, 0x85, 0x7f, + 0x01, 0x5a, 0xca, 0x6e, 0x90, 0xfa, 0x7e, 0x82, 0x4d, 0x35, 0x7e, 0xe0, + 0x26, 0x40, 0xf4, 0xa6, 0xae, 0xc3, 0x89, 0xf3, 0xca, 0x55, 0x2c, 0xb5, + 0x29, 0x05, 0x94, 0x45, 0xa7, 0x45, 0xf3, 0x3d, 0xbb, 0x53, 0x5e, 0xca, + 0x7c, 0x84, 0x8f, 0x72, 0x98, 0x93, 0x90, 0x1f, 0x56, 0x72, 0xdb, 0xbd, + 0xa9, 0xeb, 0xf9, 0xe9, 0xce, 0xb1, 0x41, 0xc3, 0xaa, 0xa0, 0xc4, 0x74, + 0x23, 0xc1, 0xeb, 0x7d, 0x41, 0xcd, 0xa4, 0x62, 0xec, 0xfc, 0x9a, 0xa4, + 0x16, 0xec, 0x67, 0x41, 0x89, 0xf0, 0x0e, 0xf3, 0xd1, 0xa2, 0x2f, 0xba, + 0x5d, 0x93, 0x36, 0x46, 0xf5, 0x52, 0x64, 0x91, 0xe7, 0x40, 0x91, 0x20, + 0xa1, 0xc9, 0xaa, 0x4c, 0x79, 0xc4, 0xbb, 0x67, 0x79, 0xad, 0x43, 0xab, + 0xba, 0xde, 0xfc, 0xf1, 0x74, 0x81, 0x33, 0xc0, 0x3f, 0x39, 0xd1, 0xd1, + 0xdf, 0xc0, 0x53, 0x33, 0xb2, 0x92, 0x37, 0xe6, 0x86, 0x2a, 0xe4, 0xe1, + 0x7c, 0x98, 0xf7, 0xdb, 0x5c, 0xa9, 0xff, 0x8d, 0x9c, 0xab, 0xe2, 0xf2, + 0xd5, 0xb1, 0x42, 0xa9, 0xf4, 0x97, 0x80, 0xcd, 0xde, 0x25, 0x2e, 0x87, + 0x92, 0xdd, 0xcf, 0xed, 0x67, 0x93, 0x8c, 0x5a, 0x1d, 0xee, 0xcf, 0x9d, + 0x50, 0x8f, 0xa7, 0xe3, 0x5c, 0xa3, 0x68, 0x78, 0x24, 0xeb, 0x60, 0xa3, + 0x8b, 0x36, 0xbb, 0xcb, 0x46, 0xee, 0x77, 0xfb, 0xf8, 0x69, 0x24, 0xd1, + 0xfa, 0xad, 0x76, 0x76, 0x5e, 0x54, 0xe5, 0xb6, 0x36, 0xc6, 0xdd, 0xa9, + 0x6c, 0x44, 0x15, 0xf7, 0x0a, 0xf8, 0xbb, 0xba, 0xec, 0x35, 0xff, 0xc9, + 0xd6, 0x5d, 0xf5, 0x73, 0x4a, 0x15, 0x8f, 0x7b, 0x6e, 0xf4, 0xa0, 0x6d, + 0x10, 0xbb, 0x67, 0x0c, 0xb4, 0x69, 0xad, 0xb6, 0x40, 0xf7, 0x5f, 0x37, + 0x28, 0xc4, 0x08, 0x49, 0xd0, 0x16, 0x70, 0x80, 0xea, 0x55, 0x66, 0x07, + 0xc8, 0x03, 0x1b, 0xf6, 0xd3, 0x03, 0x04, 0x74, 0xe0, 0x50, 0x3f, 0xd2, + 0x53, 0x92, 0xa0, 0x9d, 0x59, 0xc9, 0x74, 0xf2, 0x7e, 0x3b, 0x33, 0x02, + 0x10, 0x0b, 0x39, 0xf7, 0x4f, 0x6b, 0x58, 0xb2, 0x1a, 0xda, 0x65, 0x44, + 0xd1, 0x7c, 0x3f, 0xd7, 0xe3, 0xac, 0xe2, 0x1f, 0x38, 0xc1, 0x6a, 0xb0, + 0xdc, 0xc3, 0x9c, 0x7b, 0x11, 0x3c, 0x05, 0x21, 0x96, 0x76, 0x98, 0x76, + 0x82, 0xc1, 0x54, 0xdf, 0xdc, 0x8f, 0x4c, 0xd2, 0x63, 0x04, 0x06, 0x77, + 0x36, 0xe6, 0x2e, 0xd1, 0x00, 0x28, 0x42, 0x7c, 0x4a, 0x27, 0x90, 0x46, + 0xc9, 0xce, 0x33, 0x1c, 0xae, 0xda, 0x79, 0x64, 0x7f, 0x52, 0x3f, 0x58, + 0x11, 0x76, 0x4a, 0xb6, 0x72, 0xd8, 0x76, 0xae, 0xfd, 0x5c, 0x57, 0x69, + 0x76, 0x91, 0x84, 0x21, 0xc4, 0x9b, 0xd8, 0xa2, 0xff, 0x93, 0x02, 0x77, + 0x61, 0x57, 0x96, 0x7b, 0x8e, 0xfc, 0xf2, 0x6c, 0x11, 0x2b, 0x5e, 0x88, + 0x5c, 0x17, 0x1d, 0x12, 0x79, 0x3a, 0x78, 0xb6, 0x9d, 0x70, 0xfa, 0xd4, + 0xc1, 0x5c, 0x90, 0x0e, 0x0a, 0xd1, 0x3c, 0x7d, 0xcf, 0xee, 0x8a, 0xb2, + 0xb2, 0x4d, 0xce, 0x89, 0x32, 0xa9, 0x6c, 0x56, 0x57, 0x85, 0xb1, 0xbf, + 0x18, 0x1d, 0xc6, 0xe1, 0x17, 0xc5, 0x92, 0x42, 0x99, 0xf9, 0x9f, 0x04, + 0xec, 0x38, 0xf8, 0xa0, 0xd2, 0xab, 0xe6, 0x13, 0x4d, 0x9c, 0x18, 0x86, + 0x3e, 0x18, 0x73, 0x2c, 0xac, 0xe0, 0xb9, 0xf9, 0x87, 0x74, 0xb8, 0xd7, + 0x47, 0x6e, 0x42, 0xfc, 0x29, 0xa0, 0x1f, 0x56, 0x68, 0xb6, 0x23, 0x96, + 0xa2, 0x8d, 0x54, 0x81, 0x0f, 0x60, 0xb9, 0xde, 0x93, 0xfc, 0xfd, 0xde, + 0xbe, 0xb3, 0xb5, 0x87, 0xec, 0x9f, 0x17, 0xc2, 0x77, 0x6e, 0xa0, 0x62, + 0xdb, 0x66, 0xba, 0xc5, 0x05, 0x12, 0x46, 0x5d, 0x3c, 0x23, 0x29, 0x68, + 0xe5, 0x31, 0xe3, 0x15, 0xec, 0xac, 0x15, 0x9a, 0xbf, 0x42, 0x65, 0x80, + 0x45, 0x9c, 0x1d, 0xc2, 0x0e, 0x18, 0x47, 0x40, 0x44, 0xc1, 0x55, 0x24, + 0x5a, 0x35, 0xad, 0x59, 0xd2, 0xc6, 0xc3, 0x68, 0x58, 0xbd, 0x6f, 0xcf, + 0x5d, 0xb1, 0x9b, 0x0c, 0x92, 0x39, 0x22, 0x49, 0x66, 0x2e, 0x03, 0x7b, + 0x75, 0x5c, 0x6c, 0xde, 0x37, 0x54, 0xa9, 0x07, 0x2f, 0x7e, 0xc1, 0x3e, + 0x3b, 0xab, 0xd2, 0xa9, 0xfa, 0xc7, 0x6b, 0xd5, 0x14, 0x08, 0x35, 0x89, + 0x0b, 0x31, 0x18, 0x54, 0x7d, 0x6b, 0x53, 0x80, 0x6e, 0x32, 0x9b, 0xff, + 0x61, 0x7f, 0x36, 0xe5, 0x28, 0x40, 0xbc, 0xc7, 0x19, 0xb3, 0xae, 0xfa, + 0x95, 0xa8, 0xae, 0xd2, 0x97, 0x72, 0xc6, 0x91, 0x36, 0x3a, 0xa6, 0xec, + 0x4a, 0x41, 0x63, 0x6b, 0x28, 0xef, 0x5a, 0xa1, 0xdb, 0xf2, 0xd9, 0xfd, + 0x61, 0x72, 0xa4, 0xd2, 0x9e, 0xf7, 0x47, 0xf4, 0x4e, 0xea, 0x2a, 0xa5, + 0x35, 0xe1, 0x77, 0x3a, 0x53, 0x28, 0xa6, 0x55, 0x48, 0x0c, 0x1e, 0x44, + 0xfc, 0xc1, 0x31, 0x5a, 0x00, 0xcd, 0x29, 0xc1, 0x5c, 0xca, 0x2a, 0x07, + 0x01, 0x63, 0xac, 0xb3, 0xfb, 0xf6, 0x0b, 0xac, 0xfd, 0xe8, 0x7b, 0xed, + 0xf9, 0x3d, 0x9a, 0xbc, 0x67, 0x28, 0x1c, 0xd9, 0x3f, 0x97, 0x28, 0x4a, + 0xe7, 0xd0, 0x08, 0xe9, 0x3e, 0xa0, 0xcb, 0x0f, 0xe0, 0x3f, 0x1b, 0x80, + 0x43, 0x74, 0xd9, 0x9d, 0x0b, 0x22, 0x81, 0xf7, 0xec, 0x71, 0x2a, 0x29, + 0x9e, 0x5d, 0x1e, 0x8d, 0xf4, 0x22, 0x95, 0x78, 0x86, 0xcb, 0xf0, 0x9d, + 0xe7, 0x6a, 0x66, 0x7e, 0x28, 0xb5, 0x47, 0xb6, 0xdc, 0x0d, 0x03, 0x3c, + 0x09, 0x58, 0x76, 0x93, 0x39, 0xb2, 0xd3, 0x75, 0xb4, 0x51, 0x55, 0x84, + 0x30, 0x24, 0x0a, 0x76, 0xf4, 0x97, 0xe7, 0x0f, 0x5a, 0x67, 0xee, 0xf4, + 0xc7, 0x69, 0x8d, 0xf2, 0x32, 0x29, 0x5c, 0x33, 0x82, 0x5f, 0x6c, 0x47, + 0xd0, 0xe2, 0xbd, 0x62, 0xd6, 0x4c, 0x6d, 0x0d, 0xba, 0x87, 0xd3, 0x43, + 0x7e, 0x2d, 0xa6, 0x14, 0x09, 0x4f, 0x3b, 0xc3, 0x04, 0x14, 0xe5, 0x65, + 0xe9, 0x3b, 0x6a, 0xca, 0xb5, 0x96, 0x84, 0x3f, 0x53, 0x49, 0x22, 0x45, + 0x91, 0xff, 0xf9, 0x26, 0x75, 0x0d, 0x9c, 0xa7, 0x00, 0xf4, 0x65, 0xc4, + 0x60, 0x72, 0xab, 0xeb, 0xf8, 0xa8, 0x72, 0xfe, 0xd8, 0xde, 0x93, 0x67, + 0xcb, 0x09, 0xcc, 0xa0, 0xce, 0x9f, 0x67, 0x63, 0x26, 0xfa, 0x7f, 0x89, + 0xaa, 0x3e, 0x6d, 0xb2, 0x90, 0xd7, 0xef, 0x3e, 0x2a, 0x66, 0x26, 0x33, + 0xe6, 0x26, 0xc1, 0x58, 0xf8, 0x91, 0xea, 0x2f, 0xd0, 0x84, 0x21, 0x41, + 0x93, 0xa6, 0x36, 0x40, 0xb5, 0x4c, 0xac, 0x21, 0x88, 0x37, 0x47, 0x8a, + 0xb8, 0xf3, 0x33, 0x73, 0x12, 0xd7, 0x5a, 0x55, 0xf9, 0xd1, 0x1e, 0x75, + 0xa4, 0x66, 0x68, 0x3f, 0xf7, 0xb2, 0xc4, 0x5d, 0x1b, 0xb1, 0x61, 0x0f, + 0xaf, 0x4b, 0x9b, 0x20, 0x2b, 0x05, 0x68, 0x1c, 0x6c, 0x97, 0x8d, 0xb8, + 0x7b, 0x96, 0xda, 0xe0, 0x67, 0x15, 0x4c, 0x51, 0x71, 0x0d, 0xd3, 0x7b, + 0xde, 0xaa, 0xd3, 0x58, 0xf5, 0xc9, 0x62, 0x0a, 0xc2, 0x33, 0x1f, 0xf3, + 0xc3, 0x30, 0xb5, 0x64, 0xd1, 0x59, 0x41, 0x0e, 0xae, 0xaa, 0x0d, 0xdf, + 0x9f, 0x5d, 0x3f, 0x15, 0x0d, 0x46, 0x7a, 0x6d, 0x2e, 0x29, 0x1b, 0xc0, + 0xd3, 0x11, 0x10, 0x5d, 0xdc, 0x6a, 0x35, 0x8c, 0x43, 0xc8, 0x9f, 0x05, + 0x80, 0xdc, 0x25, 0x24, 0x37, 0x70, 0x7e, 0x1c, 0xe9, 0x85, 0x5a, 0xef, + 0x83, 0x3a, 0x55, 0x68, 0x83, 0x17, 0xf4, 0xc7, 0xae, 0xe4, 0x84, 0xc9, + 0x64, 0x5d, 0x2f, 0xb6, 0xca, 0x10, 0x95, 0xb8, 0xd6, 0x80, 0xfd, 0x05, + 0xa5, 0x06, 0x32, 0x34, 0x91, 0x01, 0xd2, 0x02, 0x90, 0xe1, 0xf7, 0x89, + 0x8a, 0xee, 0x18, 0x04, 0x93, 0xd9, 0xb4, 0x63, 0x4b, 0xf7, 0x7a, 0x9c, + 0x1b, 0x4b, 0xf9, 0x31, 0x32, 0xd9, 0xf2, 0x55, 0x4e, 0xc1, 0x02, 0xce, + 0x77, 0x38, 0x36, 0x29, 0xb8, 0x54, 0x8c, 0xc2, 0x27, 0x5f, 0xd9, 0xae, + 0x3e, 0x1e, 0xcd, 0xe9, 0x07, 0x90, 0x4c, 0xe0, 0xda, 0x16, 0x6e, 0xdf, + 0xde, 0x3a, 0x61, 0x89, 0x9f, 0x79, 0xd0, 0xd4, 0x66, 0x95, 0xad, 0xe4, + 0x11, 0x7d, 0xa1, 0xae, 0xec, 0x3e, 0x6e, 0x20, 0x5a, 0xd0, 0x28, 0x0e, + 0x55, 0xec, 0xcf, 0x34, 0xec, 0xb7, 0xfc, 0xa4, 0xb3, 0x8f, 0x56, 0x13, + 0x50, 0xcc, 0x15, 0x10, 0x74, 0x40, 0x72, 0x42, 0x20, 0x22, 0xb3, 0xaf, + 0xf3, 0x68, 0xba, 0x95, 0x45, 0xcb, 0xef, 0x92, 0xd5, 0x14, 0x4c, 0x1f, + 0xe3, 0xc1, 0xa6, 0x03, 0x4e, 0x05, 0xd2, 0x1a, 0xee, 0xd2, 0x48, 0x44, + 0x2e, 0x50, 0x3b, 0x86, 0xc8, 0x6a, 0xc8, 0x4c, 0xca, 0x2a, 0xb6, 0xf7, + 0x3c, 0xaf, 0xdc, 0x62, 0xb1, 0x49, 0x13, 0xfe, 0xe7, 0x32, 0xea, 0x78, + 0xfa, 0xba, 0xcf, 0x15, 0x47, 0x58, 0xdc, 0x19, 0x73, 0x1d, 0xff, 0xbd, + 0xcc, 0x27, 0xf6, 0xfc, 0x66, 0x68, 0xa7, 0x29, 0xaf, 0x2b, 0x25, 0x0c, + 0x15, 0x47, 0xff, 0xc1, 0x00, 0x9d, 0xfa, 0x58, 0x9c, 0xaa, 0xf9, 0xcc, + 0x4c, 0x51, 0x1d, 0xda, 0xf3, 0x3c, 0x10, 0xd0, 0x3b, 0x59, 0x30, 0x02, + 0x68, 0x29, 0x1c, 0xa7, 0x22, 0xea, 0x81, 0xd3, 0x29, 0x71, 0x39, 0xe8, + 0x72, 0x7f, 0x7d, 0x94, 0x0a, 0x64, 0x2c, 0xe6, 0x55, 0xfb, 0x90, 0x78, + 0x7e, 0x6c, 0x3e, 0xfe, 0x57, 0x14, 0x61, 0xef, 0xe2, 0x63, 0x57, 0x6c, + 0x13, 0x97, 0x27, 0x2b, 0x38, 0x44, 0xab, 0x74, 0x76, 0x11, 0xa6, 0x60, + 0xad, 0x8e, 0xad, 0xe5, 0xa5, 0xa1, 0x66, 0xc5, 0xe1, 0x4d, 0x27, 0xa0, + 0x79, 0x7a, 0x09, 0xe6, 0xf0, 0x28, 0x3f, 0xcb, 0xc6, 0xf8, 0x94, 0xc0, + 0xf1, 0x13, 0xbe, 0x62, 0x6a, 0x52, 0x75, 0x52, 0xd3, 0x82, 0x31, 0xbd, + 0x15, 0xf2, 0xe8, 0x2e, 0xb1, 0x62, 0x03, 0x1e, 0xe2, 0xb3, 0xec, 0xbc, + 0x3c, 0x12, 0xca, 0x62, 0x4e, 0xc2, 0x3a, 0x51, 0x1c, 0xdf, 0xa2, 0x84, + 0x88, 0xe5, 0x7e, 0xd7, 0x5d, 0xd7, 0xbf, 0xf2, 0x7d, 0xbd, 0x9a, 0x90, + 0x63, 0xfd, 0x8a, 0x84, 0x2b, 0x9d, 0x89, 0x27, 0x63, 0x4c, 0x0a, 0xe3, + 0x70, 0x94, 0x7b, 0xe6, 0xb3, 0xd7, 0xcb, 0xcb, 0x8a, 0xeb, 0x6b, 0x53, + 0x34, 0x2f, 0x62, 0x44, 0x2d, 0x73, 0x63, 0x8a, 0xf4, 0xa2, 0x01, 0xd7, + 0x12, 0xb6, 0x8d, 0x8c, 0x4b, 0x73, 0x2b, 0x44, 0x50, 0x49, 0x6f, 0x01, + 0xac, 0xc5, 0x15, 0x37, 0x6c, 0xde, 0xd4, 0x02, 0xb1, 0x12, 0x80, 0x73, + 0xb2, 0x52, 0x0e, 0xe0, 0xb5, 0x75, 0xc9, 0x48, 0xcf, 0x18, 0x5c, 0xcc, + 0xaf, 0x58, 0xa2, 0x3e, 0x28, 0xe4, 0xab, 0xde, 0xea, 0x2a, 0xcf, 0x58, + 0x22, 0xc4, 0x68, 0xea, 0x9b, 0x7b, 0x90, 0xc5, 0xdc, 0x1c, 0x37, 0xd1, + 0x8a, 0x4f, 0xe7, 0x24, 0x23, 0x39, 0xb9, 0x62, 0xb8, 0x41, 0x13, 0x7b, + 0xe2, 0x1e, 0x0d, 0x4e, 0x38, 0x11, 0xa3, 0xb9, 0x10, 0xbb, 0x10, 0x6f, + 0x40, 0x9f, 0x50, 0x05, 0xc7, 0x0e, 0xb9, 0x9e, 0xab, 0x7c, 0x3c, 0x78, + 0xce, 0x54, 0xbf, 0xbf, 0x40, 0x36, 0x76, 0xbc, 0x4b, 0x64, 0x32, 0xca, + 0x0e, 0x2d, 0x91, 0x87, 0xd5, 0x00, 0x19, 0xbf, 0x12, 0xd0, 0x35, 0x7c, + 0xa1, 0xe5, 0xcf, 0x7a, 0x2d, 0x08, 0x62, 0xed, 0x34, 0x61, 0xe3, 0xda, + 0x2c, 0xcc, 0x1b, 0xf8, 0x12, 0xfe, 0xfd, 0x19, 0xa2, 0xc3, 0x70, 0xfd, + 0x4f, 0x5b, 0x5d, 0x20, 0xd2, 0xe1, 0xc5, 0xac, 0xe7, 0xa1, 0x84, 0x00, + 0xbd, 0x46, 0x81, 0xfd, 0x54, 0x69, 0xed, 0x1a, 0x7a, 0x32, 0xbb, 0x75, + 0x22, 0x76, 0x6d, 0x34, 0x24, 0xcc, 0xe6, 0xbe, 0x78, 0x5a, 0x75, 0x6c, + 0xbc, 0x62, 0xb8, 0x14, 0xf7, 0x13, 0x73, 0xc2, 0xdc, 0xb6, 0xfa, 0xfb, + 0x97, 0xfe, 0x27, 0x7b, 0x33, 0xb8, 0xeb, 0x20, 0xd2, 0x0f, 0x4f, 0xed, + 0xd1, 0xd0, 0x63, 0xf7, 0xc5, 0x8e, 0xec, 0xcc, 0xd2, 0x31, 0x38, 0x35, + 0x65, 0x33, 0x5c, 0x63, 0x85, 0xf7, 0x3d, 0xc3, 0x62, 0x26, 0x52, 0x0a, + 0x67, 0xda, 0x87, 0x1f, 0x9e, 0x47, 0xec, 0x6b, 0xf5, 0x74, 0x1a, 0xc5, + 0xa7, 0xa0, 0x0f, 0xdd, 0xc5, 0x42, 0xf4, 0xda, 0x41, 0x1a, 0x48, 0xa9, + 0xbe, 0x4f, 0xb6, 0x28, 0x17, 0xe9, 0xf5, 0xd7, 0x00, 0xb3, 0xfe, 0x05, + 0x4e, 0xa7, 0xdf, 0x65, 0x7a, 0xb8, 0x4f, 0xe0, 0xfe, 0x58, 0x9e, 0xba, + 0x45, 0x11, 0xba, 0xc2, 0xdb, 0x97, 0x97, 0xa4, 0xbc, 0x18, 0x21, 0x1b, + 0xad, 0x82, 0xef, 0xb1, 0x5f, 0x2f, 0x25, 0x9d, 0xca, 0x52, 0xa5, 0x6d, + 0x8c, 0xab, 0x07, 0x2b, 0x7b, 0x6a, 0x77, 0x9d, 0xdf, 0xfb, 0xae, 0x6e, + 0x49, 0x18, 0x25, 0x4a, 0xf2, 0x7d, 0xa0, 0x32, 0xc8, 0x53, 0x10, 0xc3, + 0xf2, 0xef, 0xf3, 0xe7, 0x79, 0xd7, 0x6a, 0x0e, 0x61, 0xff, 0x89, 0xc9, + 0x42, 0xe8, 0x6e, 0x4f, 0x78, 0xe1, 0x5f, 0xcd, 0x7a, 0xf6, 0x27, 0x72, + 0x67, 0xea, 0x0b, 0xa6, 0xcc, 0x34, 0xb7, 0x8f, 0x92, 0x3c, 0x95, 0xb9, + 0x0a, 0x5d, 0x49, 0x2e, 0xb7, 0x7d, 0x31, 0x9c, 0x79, 0x61, 0x95, 0x9c, + 0x60, 0x56, 0x8d, 0x35, 0x00, 0xc5, 0x8b, 0xe6, 0x02, 0x0f, 0x26, 0x39, + 0x7b, 0x93, 0x94, 0xb1, 0xcd, 0xde, 0xed, 0xfa, 0x2a, 0x4b, 0x63, 0xa8, + 0x1b, 0x31, 0x43, 0x5e, 0x69, 0x7c, 0xd6, 0x15, 0x35, 0x9c, 0xa2, 0xd7, + 0xdf, 0x0e, 0x1a, 0x20, 0x50, 0xf5, 0x02, 0x21, 0x30, 0x35, 0x3c, 0x60, + 0x71, 0xad, 0xd0, 0xe3, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x10, 0x17, 0x1d, 0x22, 0x2d}; +#elif MLD_CONFIG_PARAMETER_SET == 87 +const uint8_t expected_signature[] = { + 0xdf, 0xe6, 0xe1, 0xa5, 0x20, 0xc1, 0xac, 0x98, 0x55, 0x2c, 0xf2, 0x13, + 0x65, 0x42, 0xe2, 0xb0, 0x77, 0x5f, 0x15, 0x00, 0x8f, 0x14, 0x48, 0xa1, + 0xe3, 0xee, 0x81, 0x35, 0x15, 0x34, 0xad, 0x6e, 0x60, 0x85, 0x00, 0xf8, + 0x18, 0x53, 0x0d, 0xa0, 0xc5, 0x41, 0xc4, 0x48, 0x09, 0x1b, 0x34, 0x0c, + 0x0e, 0xcf, 0xc6, 0x3d, 0x38, 0x78, 0x8b, 0x69, 0xe5, 0x6f, 0x4d, 0x43, + 0xfa, 0xa6, 0x75, 0x26, 0x8a, 0x75, 0x97, 0x10, 0x6a, 0x1f, 0x3c, 0xa6, + 0x94, 0xa9, 0x93, 0x8f, 0xe5, 0x62, 0xbf, 0x94, 0xe4, 0xd0, 0x0d, 0x11, + 0x4d, 0x03, 0xe2, 0xd8, 0xdf, 0x68, 0xb7, 0x87, 0x62, 0xc9, 0xdc, 0xc9, + 0x36, 0x4f, 0xcc, 0xd1, 0xa4, 0xae, 0x7e, 0xa4, 0xb9, 0xaf, 0xaf, 0xf0, + 0x8a, 0xe6, 0xff, 0x83, 0xe7, 0x54, 0x22, 0x6e, 0x3f, 0x2e, 0xa0, 0x4f, + 0xa8, 0x31, 0x53, 0xf3, 0x62, 0xeb, 0x04, 0xfa, 0xd1, 0x57, 0x39, 0x43, + 0xf9, 0xe0, 0x31, 0x12, 0x45, 0x09, 0x8b, 0x9e, 0x1e, 0x7a, 0x2b, 0x85, + 0xee, 0xdd, 0xe8, 0x1e, 0xd7, 0xc0, 0x17, 0xb4, 0xd2, 0xdc, 0x36, 0xa9, + 0xe4, 0x49, 0x88, 0xbf, 0x71, 0x43, 0x9d, 0x3e, 0xd2, 0x10, 0xe7, 0x82, + 0xb5, 0xfe, 0xdd, 0x42, 0xc8, 0x1b, 0x11, 0xf6, 0x52, 0x23, 0x98, 0x83, + 0x48, 0xec, 0xec, 0x70, 0x8b, 0xe7, 0x49, 0x9a, 0xd7, 0xd9, 0x7b, 0x47, + 0x4e, 0xe2, 0x5e, 0x17, 0x1a, 0xa0, 0x0e, 0x60, 0x85, 0x3a, 0x30, 0x8c, + 0x1c, 0x26, 0xb4, 0xe1, 0xb5, 0x2b, 0x48, 0xf4, 0xb8, 0x93, 0x2f, 0x79, + 0x3a, 0x1e, 0xb6, 0x3b, 0x07, 0x3b, 0x1e, 0x15, 0xd7, 0x85, 0x5e, 0xd4, + 0x06, 0x0e, 0xcd, 0x6a, 0x93, 0x3a, 0x93, 0x29, 0x6a, 0xbe, 0x68, 0x8a, + 0xb6, 0xb8, 0xfa, 0xc5, 0x63, 0x48, 0x98, 0x10, 0x6d, 0xd9, 0xd3, 0x5b, + 0x29, 0x5f, 0x93, 0x90, 0x08, 0x1c, 0x1a, 0x15, 0x7b, 0x0a, 0x59, 0x9d, + 0x64, 0x24, 0x45, 0xb6, 0xd3, 0x7b, 0xc1, 0x5d, 0x74, 0x1f, 0x0b, 0x8e, + 0x18, 0xf2, 0x92, 0x8e, 0xd4, 0x7f, 0x72, 0x5c, 0x98, 0x1f, 0x8b, 0xa5, + 0xb8, 0xf4, 0x7e, 0x12, 0x6a, 0x93, 0xb9, 0xb5, 0xf1, 0xda, 0x97, 0x75, + 0x4f, 0x56, 0x80, 0x88, 0x64, 0x2b, 0xe0, 0x59, 0xcd, 0x5e, 0x91, 0x64, + 0x9c, 0x0c, 0xa8, 0xdd, 0xac, 0xcb, 0xf3, 0x48, 0x3b, 0x5c, 0xc4, 0xc5, + 0xb9, 0x9a, 0x0b, 0x8e, 0x5d, 0x9a, 0xd5, 0xb7, 0xf0, 0xd4, 0x07, 0x48, + 0xb9, 0x63, 0x02, 0x87, 0x8d, 0xae, 0x7e, 0x03, 0x33, 0x4f, 0x86, 0x15, + 0x1b, 0x3b, 0xdf, 0xda, 0xce, 0xd3, 0x1e, 0xc0, 0x76, 0xb5, 0x1c, 0xdd, + 0xb8, 0x32, 0x87, 0x7d, 0x59, 0x18, 0x72, 0x0c, 0xde, 0x8f, 0x63, 0x2d, + 0x38, 0xf2, 0xe9, 0xc2, 0x81, 0xed, 0xfa, 0x2d, 0x61, 0xef, 0x48, 0xdb, + 0xa2, 0xeb, 0xfe, 0x52, 0x31, 0x1e, 0x21, 0x0a, 0x08, 0xf6, 0x02, 0xd3, + 0xc0, 0x32, 0x3b, 0x6b, 0x2f, 0x64, 0xc4, 0xb3, 0x4b, 0xfe, 0x69, 0x78, + 0xbf, 0x20, 0x62, 0x07, 0x77, 0xdf, 0x2c, 0x18, 0x53, 0x61, 0x8e, 0x05, + 0x01, 0x86, 0xab, 0xab, 0xec, 0x18, 0x8c, 0x15, 0x63, 0x1f, 0xe9, 0x99, + 0xb2, 0x35, 0x77, 0xe1, 0x58, 0xf1, 0xa9, 0x4d, 0x1a, 0xb9, 0x8c, 0x30, + 0x63, 0x6f, 0x9e, 0x7d, 0x4e, 0xcf, 0xb5, 0x6c, 0xf3, 0xe4, 0xdc, 0xab, + 0xf9, 0xae, 0x58, 0xf8, 0x1d, 0x08, 0x7b, 0x73, 0x82, 0x58, 0xc8, 0x67, + 0x48, 0x1a, 0x5e, 0x3d, 0xdb, 0xac, 0x1b, 0x1b, 0xef, 0xeb, 0xa4, 0xe5, + 0x67, 0x48, 0x76, 0xd1, 0x96, 0x4f, 0x6c, 0x7d, 0x06, 0x8c, 0x02, 0x86, + 0x95, 0x83, 0xb6, 0x9b, 0x5e, 0x9a, 0xb5, 0x85, 0xc0, 0x4f, 0x13, 0x1c, + 0x32, 0xf8, 0x29, 0xdf, 0x47, 0x85, 0xdb, 0xe4, 0x37, 0xdc, 0xd8, 0x04, + 0x18, 0xdd, 0xca, 0x97, 0xdd, 0x67, 0x13, 0xbe, 0x74, 0x95, 0xdc, 0xd0, + 0xcc, 0xe6, 0xb5, 0xa5, 0x12, 0x9b, 0x23, 0x4f, 0x41, 0x8c, 0xcc, 0x95, + 0xf4, 0xb0, 0x5f, 0x2a, 0xc4, 0xbf, 0x88, 0xda, 0x55, 0xcb, 0x13, 0x93, + 0x22, 0x60, 0x51, 0x43, 0xc7, 0x9a, 0x2c, 0xfa, 0xb2, 0x59, 0xc1, 0xe6, + 0x8a, 0xa4, 0xb8, 0xfb, 0xd3, 0x31, 0x1d, 0xc7, 0x88, 0xdc, 0xbc, 0xe9, + 0xba, 0xe7, 0xdc, 0xe3, 0xdd, 0x90, 0x96, 0xb4, 0xb4, 0x0a, 0xc1, 0x07, + 0x31, 0x3f, 0xdb, 0xc5, 0x4d, 0x73, 0x58, 0x86, 0x15, 0x37, 0x07, 0x86, + 0x03, 0x17, 0x16, 0x18, 0x15, 0xb9, 0x26, 0x35, 0x8a, 0x43, 0x22, 0xae, + 0x21, 0x52, 0x05, 0x4e, 0x5c, 0x3f, 0x3e, 0xb9, 0x2a, 0x19, 0x13, 0xfd, + 0x31, 0x47, 0x6a, 0x74, 0xaa, 0xb9, 0xc6, 0x2c, 0x13, 0x8c, 0x21, 0xc4, + 0x8d, 0x00, 0xf4, 0x24, 0xf2, 0xb7, 0xd3, 0x13, 0xad, 0x29, 0x5e, 0x50, + 0x0b, 0x0e, 0x9f, 0x9a, 0xb7, 0xf6, 0x9e, 0xba, 0x12, 0x23, 0x84, 0x8c, + 0xbe, 0x2c, 0x14, 0x1e, 0xe6, 0x79, 0x15, 0x20, 0x2d, 0x32, 0x08, 0xd8, + 0x1c, 0x87, 0x1b, 0xa8, 0xc0, 0xbb, 0x85, 0xa9, 0x71, 0x30, 0x5e, 0x39, + 0x48, 0x87, 0xdc, 0x3d, 0x03, 0x29, 0x19, 0xd1, 0xd4, 0x21, 0x3a, 0x53, + 0x2d, 0x5e, 0x78, 0xff, 0x94, 0x4b, 0x91, 0xa6, 0xb5, 0xe5, 0x42, 0x56, + 0x67, 0x6a, 0x0e, 0xf3, 0x2d, 0x6a, 0x4e, 0xd7, 0x3a, 0x81, 0xb1, 0x4d, + 0x0b, 0x66, 0x5f, 0x43, 0x28, 0x7c, 0x75, 0x8b, 0x2b, 0x99, 0x24, 0xc2, + 0x5e, 0x8c, 0x22, 0xf0, 0xd5, 0xb3, 0xfc, 0x86, 0x62, 0xf3, 0xd2, 0x6c, + 0xa7, 0x48, 0x04, 0x44, 0x5d, 0x93, 0x74, 0x37, 0x16, 0x2c, 0x19, 0x12, + 0x57, 0x49, 0xef, 0xd5, 0xd6, 0x92, 0xdc, 0x51, 0xf8, 0x55, 0x3a, 0xc0, + 0x0b, 0xdf, 0x41, 0xb5, 0x01, 0x59, 0x7e, 0x85, 0x65, 0xdb, 0x44, 0xbd, + 0x04, 0x96, 0x1a, 0xd4, 0x6e, 0x22, 0x54, 0x92, 0xdb, 0xc7, 0xc5, 0x3a, + 0xdf, 0x0c, 0xf4, 0x1b, 0xdc, 0x14, 0xf6, 0x91, 0x9c, 0xbe, 0xf8, 0x8e, + 0x70, 0xd1, 0x3a, 0x0e, 0x58, 0xe6, 0xb9, 0xd3, 0xaa, 0xa2, 0x70, 0xba, + 0xdd, 0x16, 0x13, 0x19, 0xd1, 0x96, 0x78, 0x04, 0x2f, 0xd7, 0x38, 0x8c, + 0x35, 0x1f, 0xfc, 0x58, 0xa4, 0x4c, 0xa9, 0x9a, 0xae, 0x13, 0x3b, 0xc1, + 0x20, 0x4b, 0x66, 0x0f, 0x72, 0x42, 0x0a, 0x53, 0x84, 0x54, 0x71, 0x06, + 0xdb, 0x85, 0x8f, 0x40, 0xa6, 0x09, 0xf7, 0x24, 0xc4, 0x35, 0xf7, 0x1d, + 0xd4, 0x3d, 0x54, 0x75, 0xaf, 0xc4, 0x78, 0x0f, 0xce, 0xe0, 0x0c, 0x90, + 0x0f, 0xd5, 0x2e, 0x61, 0xf7, 0x58, 0xaa, 0xf0, 0xc7, 0x37, 0x5a, 0x59, + 0x1f, 0x8a, 0x03, 0x98, 0x43, 0xb7, 0x27, 0x78, 0x4e, 0x44, 0x5a, 0xb5, + 0x29, 0xf5, 0xab, 0x9e, 0xb7, 0x2a, 0xc4, 0xa3, 0x03, 0x00, 0xe3, 0x28, + 0x57, 0xc9, 0x2a, 0x98, 0xb8, 0xa1, 0x45, 0x1d, 0xfa, 0x6e, 0xb3, 0x0d, + 0x42, 0x5a, 0xb6, 0xb1, 0x0e, 0x5c, 0xbe, 0x82, 0xe2, 0x36, 0x40, 0x4b, + 0x05, 0x28, 0xd9, 0xbc, 0x27, 0xd6, 0x77, 0x00, 0xc9, 0x29, 0x6a, 0xd6, + 0x19, 0x8f, 0x8d, 0xda, 0xe1, 0xc3, 0x8b, 0x69, 0x71, 0xd0, 0xf7, 0xc8, + 0x33, 0xef, 0xe6, 0x23, 0x6b, 0xcb, 0x00, 0x56, 0x0a, 0x9b, 0x9d, 0x60, + 0x3a, 0xd3, 0xad, 0xd9, 0x5c, 0x6a, 0x7d, 0xab, 0x35, 0x71, 0x93, 0xc5, + 0xf2, 0x6a, 0x38, 0x0e, 0xfb, 0xd9, 0x9b, 0xa5, 0xda, 0x52, 0x45, 0xef, + 0x93, 0x94, 0x5b, 0x08, 0x8c, 0x07, 0xab, 0x2e, 0x99, 0x88, 0x77, 0xb5, + 0x15, 0x66, 0x7f, 0x0e, 0xfa, 0xb0, 0x29, 0xe4, 0x88, 0xd9, 0xdd, 0x22, + 0xaf, 0x7a, 0x4e, 0xb5, 0xd0, 0x62, 0x85, 0x27, 0x33, 0xf1, 0xb7, 0x34, + 0xb1, 0xe6, 0xda, 0x9f, 0x3c, 0xfe, 0xf5, 0xd4, 0xef, 0x56, 0x48, 0x93, + 0x7a, 0x54, 0xa2, 0x7f, 0x07, 0xea, 0x31, 0xb8, 0x8b, 0xca, 0xb9, 0xdb, + 0x1e, 0x2b, 0xb5, 0x16, 0xe6, 0x0e, 0xd9, 0x3f, 0x7c, 0xf0, 0xc2, 0x3e, + 0x57, 0x64, 0x60, 0x97, 0xfb, 0xdf, 0x8c, 0x3e, 0x56, 0x22, 0x92, 0x2a, + 0xb2, 0x21, 0x00, 0x0a, 0x75, 0x89, 0x68, 0xe7, 0x51, 0xa3, 0x63, 0x05, + 0xe1, 0x6f, 0x1e, 0x1e, 0x80, 0xa2, 0x4b, 0x5d, 0xb7, 0xf4, 0xb7, 0x45, + 0x85, 0x00, 0x84, 0x6e, 0xbe, 0x0b, 0x67, 0xbf, 0x21, 0x06, 0x5a, 0x56, + 0x79, 0xe9, 0x6b, 0x0e, 0x72, 0x19, 0x2d, 0x09, 0x78, 0xd5, 0x5e, 0xc2, + 0x32, 0xee, 0x29, 0xd4, 0x7a, 0x65, 0xc7, 0xfe, 0x16, 0x86, 0xd2, 0x29, + 0x71, 0xe5, 0x91, 0x0e, 0x3e, 0x86, 0xd5, 0x00, 0xc4, 0xfc, 0xd9, 0xae, + 0xd3, 0x7c, 0x13, 0xfd, 0x62, 0xce, 0x0c, 0xb2, 0xe5, 0x1f, 0x6d, 0xed, + 0x55, 0x6f, 0xc1, 0xaa, 0xa1, 0x74, 0x59, 0x46, 0x83, 0xd5, 0x5d, 0x71, + 0x17, 0x13, 0x1d, 0x0b, 0x25, 0xfb, 0x0a, 0xcd, 0x67, 0xfe, 0x57, 0x93, + 0xc2, 0x71, 0x55, 0x6c, 0x68, 0xfa, 0x40, 0xdb, 0xdd, 0xce, 0xd5, 0x5c, + 0xce, 0x0a, 0x1d, 0xfa, 0x19, 0x30, 0xe2, 0x2b, 0x63, 0x98, 0x16, 0x2c, + 0x67, 0x69, 0x55, 0xe5, 0xc1, 0x6c, 0x6e, 0xb7, 0x92, 0x6a, 0xbb, 0x10, + 0xd3, 0x13, 0x2e, 0x73, 0x91, 0x74, 0xcb, 0x9f, 0x5c, 0x7f, 0x5c, 0x48, + 0x58, 0x36, 0x13, 0x47, 0xf7, 0x49, 0xae, 0x90, 0x15, 0x53, 0xb5, 0xe6, + 0x37, 0xfb, 0x81, 0x47, 0xb4, 0x69, 0x84, 0xca, 0x95, 0xab, 0x19, 0x2a, + 0x28, 0xc2, 0x8a, 0xf1, 0xcd, 0xf9, 0x3e, 0xd3, 0xaf, 0xe1, 0x75, 0xf7, + 0x94, 0x74, 0x1c, 0xf5, 0x32, 0xcf, 0x70, 0xbd, 0x69, 0xcc, 0xa8, 0x3c, + 0xca, 0x59, 0x53, 0xfa, 0xcb, 0xe7, 0xb6, 0x36, 0x70, 0xea, 0xe2, 0x84, + 0xfa, 0x5e, 0xbd, 0xd7, 0x59, 0x3d, 0x21, 0xc6, 0x9f, 0x5c, 0x1f, 0xa6, + 0xa9, 0xf1, 0xd3, 0x26, 0x9e, 0xff, 0xbc, 0x81, 0xfe, 0xbe, 0xee, 0x64, + 0xd9, 0x63, 0x94, 0x4b, 0x15, 0xd8, 0x95, 0xaa, 0xec, 0x10, 0xc9, 0xe2, + 0xe1, 0x05, 0x37, 0x64, 0xc4, 0xb0, 0x2e, 0xa5, 0x0e, 0x4c, 0x2d, 0x03, + 0x53, 0xf1, 0x93, 0x77, 0x9d, 0x46, 0x14, 0x67, 0x48, 0x5f, 0xad, 0x1b, + 0xdc, 0xb9, 0x74, 0xa2, 0x6c, 0xfc, 0xd2, 0xa0, 0x1f, 0x43, 0x89, 0x15, + 0xc5, 0x0c, 0xb0, 0x9e, 0x1e, 0xc2, 0xd6, 0x44, 0xd9, 0x6e, 0xfc, 0xb4, + 0x9c, 0x95, 0x90, 0xcd, 0xc3, 0x17, 0x1c, 0x6a, 0xce, 0x03, 0x56, 0x9f, + 0xe7, 0xcd, 0x7e, 0xe7, 0xa2, 0x0c, 0x2b, 0x0d, 0x59, 0xb0, 0xc9, 0x4c, + 0x6e, 0x33, 0x6d, 0x43, 0xc4, 0x3a, 0x10, 0x24, 0x03, 0x3e, 0x09, 0xb6, + 0x86, 0x13, 0xba, 0x18, 0x19, 0xd3, 0xff, 0xeb, 0xa5, 0x25, 0x8f, 0x6f, + 0xc8, 0xe6, 0x96, 0xa4, 0xd2, 0x66, 0x40, 0x81, 0x79, 0xe8, 0x39, 0x18, + 0x41, 0x02, 0x66, 0x5c, 0x30, 0x5f, 0x58, 0x9d, 0x35, 0x16, 0xc6, 0x96, + 0xa8, 0x68, 0xbc, 0x09, 0x83, 0x17, 0x2c, 0x5f, 0x5e, 0xd0, 0x1d, 0xb0, + 0x48, 0x5e, 0xcf, 0x91, 0x16, 0x4d, 0xa0, 0xba, 0xbc, 0x61, 0xa8, 0x3f, + 0x30, 0x09, 0xbb, 0xa3, 0x12, 0xcd, 0xdc, 0x29, 0xf7, 0xb0, 0xad, 0x05, + 0x17, 0xd6, 0xd3, 0x16, 0xfb, 0xe5, 0x99, 0xf4, 0x71, 0x62, 0xa3, 0x45, + 0x45, 0xc7, 0x9b, 0xaa, 0x45, 0xd3, 0x35, 0xfe, 0xfb, 0x63, 0xaf, 0xe7, + 0x85, 0x31, 0xc9, 0x66, 0x26, 0xa9, 0xda, 0x8c, 0xc6, 0xf6, 0xd5, 0xdf, + 0xb1, 0xa9, 0xf1, 0xb6, 0x3d, 0x92, 0xae, 0x4d, 0xbc, 0x74, 0x7d, 0x76, + 0x5a, 0x59, 0x8c, 0x87, 0xff, 0x95, 0x2f, 0x67, 0x37, 0x30, 0x1a, 0xc1, + 0x23, 0x2e, 0x0c, 0xaa, 0x80, 0x1c, 0xf3, 0xa3, 0x74, 0x94, 0xb2, 0xda, + 0x1a, 0xb8, 0x46, 0xec, 0x30, 0x76, 0xf4, 0xdf, 0xfb, 0x00, 0xb3, 0x6f, + 0x86, 0xc1, 0xc5, 0x3a, 0x5d, 0x11, 0x14, 0x87, 0xeb, 0x30, 0xd8, 0x33, + 0x18, 0x00, 0x01, 0x76, 0x43, 0x82, 0xcd, 0x1c, 0x36, 0x54, 0xd2, 0x64, + 0x5b, 0xfb, 0x93, 0xca, 0x20, 0x1d, 0xa3, 0x20, 0x99, 0xc3, 0x8e, 0x5c, + 0x82, 0xfc, 0x56, 0x07, 0x41, 0x4b, 0x4f, 0x54, 0xc7, 0xb5, 0xe8, 0x6d, + 0x7e, 0xd8, 0x8a, 0x56, 0xb4, 0x76, 0x1e, 0xd3, 0x82, 0x97, 0xdd, 0x2b, + 0xd9, 0x80, 0xb7, 0xb6, 0xeb, 0x3d, 0xe5, 0xe0, 0x20, 0x27, 0x8c, 0xf0, + 0xd6, 0x14, 0xc7, 0xcd, 0x79, 0xbc, 0xa0, 0x21, 0x85, 0xc3, 0x02, 0xae, + 0x73, 0xc4, 0x0a, 0x39, 0x1a, 0x98, 0x61, 0xc3, 0x86, 0xd8, 0x97, 0x67, + 0x87, 0xe9, 0x56, 0x0b, 0x61, 0xa6, 0x7e, 0x07, 0xfb, 0x0a, 0x8b, 0xd1, + 0x90, 0xbd, 0x39, 0x22, 0xdb, 0xc2, 0x7f, 0xaa, 0x79, 0xb7, 0x39, 0x09, + 0xc1, 0x69, 0xdb, 0xe2, 0x7f, 0xec, 0xde, 0x80, 0x7a, 0x6c, 0xde, 0x76, + 0xa4, 0xe8, 0xe0, 0x8d, 0x71, 0xfa, 0x62, 0xf0, 0x2e, 0x7b, 0xf4, 0xce, + 0x65, 0x18, 0x42, 0xde, 0x92, 0x1b, 0xdc, 0xc9, 0xa7, 0x8d, 0xa5, 0x91, + 0x0f, 0xa5, 0x1b, 0x89, 0xcf, 0x29, 0x10, 0x1d, 0x94, 0x78, 0x1b, 0xea, + 0x79, 0x35, 0x62, 0xd4, 0x29, 0xe6, 0x59, 0x8c, 0xc1, 0xd2, 0xf3, 0x32, + 0x71, 0x09, 0xce, 0x51, 0xd7, 0x14, 0x29, 0x92, 0xbf, 0xdf, 0x9a, 0x69, + 0xda, 0x61, 0x03, 0x0f, 0xa2, 0x0a, 0xab, 0x57, 0x1c, 0xca, 0xab, 0x42, + 0x63, 0x63, 0x1e, 0x35, 0x5d, 0x8d, 0xba, 0x6f, 0x4b, 0x6b, 0x5e, 0x7c, + 0xc0, 0x1e, 0xb7, 0xf4, 0x65, 0xbd, 0x13, 0x1c, 0xf2, 0xa9, 0x73, 0x38, + 0xc3, 0x47, 0xc9, 0x32, 0xf0, 0x30, 0x57, 0x05, 0x42, 0x52, 0xac, 0x72, + 0xee, 0x9f, 0x4e, 0x21, 0xbf, 0x38, 0x19, 0x6d, 0x48, 0xec, 0x97, 0xcb, + 0x70, 0x9e, 0xee, 0xb3, 0xa1, 0xaa, 0xa6, 0x7e, 0xe9, 0x16, 0xdf, 0xcd, + 0x1c, 0x56, 0xcf, 0xf0, 0x9f, 0x4d, 0xd1, 0x8c, 0x14, 0x50, 0x5d, 0x23, + 0x96, 0xe0, 0x1f, 0x61, 0x79, 0xbf, 0x44, 0xfd, 0xa2, 0x31, 0xf7, 0x4c, + 0x0c, 0x8d, 0x8c, 0x1b, 0xbf, 0x8d, 0x45, 0xbf, 0x0b, 0xd8, 0xfb, 0x6f, + 0xff, 0x15, 0xc0, 0x44, 0x7c, 0xb9, 0xb8, 0xf9, 0xef, 0x0d, 0x79, 0x11, + 0x3b, 0x79, 0xd2, 0x52, 0x89, 0x5a, 0xcd, 0x0f, 0x10, 0x92, 0x42, 0xfe, + 0xcf, 0x0a, 0x11, 0x8a, 0x8a, 0xda, 0xee, 0xc8, 0x6b, 0xd9, 0xab, 0xec, + 0xb4, 0x25, 0x6f, 0x8d, 0x68, 0x26, 0xe8, 0xdd, 0xf5, 0xa4, 0xe8, 0x65, + 0x37, 0x03, 0xb0, 0xad, 0x73, 0x3b, 0x4d, 0x74, 0x57, 0x7f, 0x0f, 0x6c, + 0xb0, 0x5d, 0x59, 0x80, 0x13, 0xa1, 0x6c, 0xb0, 0xed, 0x26, 0xec, 0x79, + 0x50, 0x5f, 0x5c, 0xb7, 0xa6, 0xae, 0xe8, 0x0a, 0x6d, 0x55, 0x9a, 0x7f, + 0x59, 0x23, 0xa3, 0x7e, 0x84, 0x7b, 0x3b, 0xfc, 0xde, 0xe1, 0xd9, 0x7c, + 0xd6, 0x87, 0xb3, 0x0e, 0xdb, 0xc1, 0x8c, 0x5e, 0x77, 0xb7, 0x23, 0xd7, + 0x14, 0xd4, 0x23, 0xb4, 0xac, 0x45, 0xbf, 0xfe, 0x40, 0x20, 0x4d, 0x91, + 0x20, 0x94, 0xbd, 0x58, 0xb1, 0x99, 0x69, 0xaf, 0x31, 0x68, 0xbd, 0x61, + 0x5e, 0x87, 0x81, 0x54, 0x4e, 0x2d, 0x03, 0xc2, 0xe2, 0xcd, 0xdc, 0x59, + 0xe5, 0x35, 0xcf, 0xb8, 0xfc, 0x65, 0xed, 0x46, 0xb3, 0x92, 0xe7, 0xf8, + 0x3a, 0x32, 0xaa, 0x0e, 0x5a, 0x82, 0x58, 0x4e, 0x77, 0xd8, 0x33, 0xc9, + 0xb0, 0x3e, 0xad, 0xa5, 0x92, 0xe9, 0xa9, 0x8c, 0x00, 0x72, 0x8f, 0xdc, + 0x77, 0x9d, 0x5c, 0x97, 0xd6, 0x58, 0x20, 0x1e, 0xf4, 0x55, 0x2d, 0xc0, + 0x30, 0xf0, 0x66, 0xda, 0x2d, 0x11, 0xac, 0xd4, 0x2d, 0xd5, 0x25, 0x42, + 0x1d, 0xce, 0x49, 0xb5, 0x95, 0x79, 0x9b, 0x6c, 0x65, 0xe0, 0x8a, 0xc5, + 0x9f, 0x75, 0xe3, 0xe6, 0xf8, 0xa6, 0x88, 0xd6, 0x93, 0x70, 0x4f, 0x89, + 0x94, 0x74, 0xbd, 0xef, 0xc2, 0x1a, 0x55, 0x74, 0x37, 0x44, 0x85, 0x1e, + 0xa9, 0xbb, 0x3f, 0x15, 0xc7, 0x84, 0x80, 0xa5, 0xab, 0xc3, 0x91, 0x8e, + 0xd6, 0x32, 0x46, 0x0d, 0xfa, 0xd1, 0x19, 0xd1, 0xfc, 0x02, 0xe2, 0x20, + 0xa6, 0xa9, 0xf7, 0xf4, 0xcc, 0x5b, 0x54, 0x4f, 0x4a, 0x73, 0x35, 0xda, + 0xf0, 0x31, 0x81, 0x1a, 0x82, 0xe7, 0xd4, 0xc8, 0xb4, 0x1d, 0x70, 0xa9, + 0x5d, 0x67, 0xb9, 0x7d, 0x4b, 0xcd, 0xa4, 0x81, 0xf9, 0xb2, 0x38, 0x07, + 0x16, 0xd5, 0x28, 0x82, 0xb9, 0x76, 0x5b, 0xa1, 0x09, 0x7a, 0xe7, 0x2a, + 0xcf, 0xc0, 0x3d, 0x2a, 0x42, 0x9a, 0xf3, 0xc8, 0x64, 0x15, 0x7c, 0x94, + 0xd0, 0x97, 0xee, 0x34, 0xb6, 0xf0, 0xb2, 0xba, 0x7e, 0xb2, 0xbb, 0x4e, + 0xbf, 0x88, 0xd0, 0x6b, 0xc5, 0x9c, 0xb9, 0xf2, 0x7d, 0xbf, 0x5d, 0x87, + 0xbc, 0x36, 0x4a, 0xd1, 0x1b, 0x6f, 0x40, 0x09, 0xba, 0x26, 0x51, 0xd6, + 0xc0, 0xaf, 0x27, 0xce, 0x27, 0x8d, 0x93, 0xa8, 0x6c, 0x91, 0xe7, 0x91, + 0x42, 0xc0, 0x68, 0x36, 0x5b, 0xd5, 0x56, 0x4c, 0xe2, 0x77, 0xc3, 0xac, + 0x56, 0xe3, 0x1c, 0xc2, 0xf9, 0x78, 0x02, 0x39, 0x7d, 0xed, 0x18, 0x2a, + 0x01, 0x48, 0xe6, 0xf6, 0x7e, 0x34, 0x50, 0xf4, 0x57, 0x56, 0x93, 0xdb, + 0x85, 0x1b, 0x1e, 0x1a, 0x6f, 0x3e, 0x07, 0x3c, 0xad, 0x3f, 0x8d, 0x75, + 0x53, 0xc3, 0x20, 0x72, 0x93, 0x28, 0xd2, 0x86, 0xc8, 0xa5, 0x90, 0xf2, + 0x5f, 0x13, 0xd5, 0xa5, 0xbe, 0x88, 0x9e, 0x9a, 0x57, 0x2c, 0x53, 0x3f, + 0x11, 0x25, 0x00, 0x00, 0x4a, 0x16, 0x8d, 0xd3, 0x3f, 0x2d, 0x3d, 0x88, + 0xbb, 0x4c, 0x4f, 0x9a, 0xb9, 0x97, 0x5f, 0xed, 0x71, 0xa9, 0x68, 0xd9, + 0x4a, 0x14, 0x24, 0xc7, 0xbe, 0xff, 0x85, 0x57, 0xa3, 0x21, 0xe3, 0x21, + 0x79, 0x1f, 0xd0, 0xbb, 0xb7, 0x73, 0xde, 0x60, 0x02, 0x4b, 0x8f, 0x7d, + 0xb3, 0xb3, 0x8a, 0xda, 0x4c, 0xf4, 0xb8, 0xf1, 0x31, 0xff, 0x32, 0x7b, + 0xd8, 0xfa, 0xb1, 0xcb, 0xb4, 0x58, 0xf5, 0xc8, 0x64, 0xdf, 0xfe, 0x3d, + 0x89, 0x52, 0x5c, 0x52, 0x95, 0xf3, 0xba, 0x0d, 0x1d, 0x2c, 0xc4, 0xf7, + 0x3c, 0x3b, 0x6f, 0x8e, 0xc7, 0xab, 0xad, 0x3d, 0x3d, 0x95, 0x9b, 0xc7, + 0x71, 0x36, 0xae, 0x08, 0xc3, 0x08, 0x79, 0xfa, 0x24, 0xee, 0xd9, 0xf9, + 0x63, 0xc7, 0xd9, 0x16, 0x19, 0x8e, 0x0d, 0xaf, 0x52, 0x87, 0x86, 0x7d, + 0xec, 0xe5, 0xea, 0x5a, 0xda, 0x86, 0x9d, 0x0e, 0x50, 0x53, 0x8c, 0x24, + 0xa8, 0x69, 0xc4, 0xf3, 0x85, 0x7b, 0x34, 0x67, 0x19, 0x35, 0xec, 0xd4, + 0xd4, 0x50, 0xe0, 0xe6, 0xe9, 0x29, 0x5b, 0x92, 0xee, 0xba, 0xa9, 0xef, + 0xf6, 0x35, 0x23, 0x8b, 0xdb, 0x48, 0x32, 0x25, 0x41, 0xf3, 0x55, 0x12, + 0x33, 0xc3, 0x6c, 0xed, 0x32, 0xe1, 0x64, 0x7a, 0x8d, 0xa2, 0x19, 0x5a, + 0x26, 0xf2, 0x83, 0xf1, 0xe4, 0x27, 0xdb, 0x67, 0xc3, 0x89, 0x37, 0xea, + 0x78, 0x19, 0xc6, 0xa3, 0x82, 0x84, 0x1c, 0xf3, 0x2b, 0xbe, 0xde, 0xba, + 0xe7, 0x60, 0x2e, 0xf5, 0x4e, 0xb6, 0x73, 0x29, 0xac, 0xc7, 0x55, 0xab, + 0x21, 0xe9, 0x95, 0x78, 0xd5, 0x8e, 0x27, 0xdc, 0x92, 0x5f, 0xc0, 0xcb, + 0xee, 0x66, 0x09, 0x0a, 0xfc, 0x94, 0x43, 0x44, 0x50, 0x35, 0x57, 0xf8, + 0x08, 0xf9, 0x97, 0xa2, 0x0e, 0xde, 0x81, 0xe1, 0xd1, 0xa0, 0x41, 0xfe, + 0xe6, 0x08, 0x6c, 0x98, 0x8c, 0x81, 0x46, 0x0e, 0xf9, 0x9a, 0x54, 0xfe, + 0xc3, 0x91, 0xe3, 0xd4, 0x46, 0xca, 0x52, 0xa2, 0x73, 0x9e, 0x4d, 0xa7, + 0xfd, 0xa1, 0x8e, 0x43, 0x28, 0xf5, 0xa3, 0xa2, 0x62, 0x20, 0x53, 0x62, + 0x05, 0x49, 0xba, 0x06, 0xe2, 0xeb, 0xba, 0xfb, 0x8e, 0xa0, 0x22, 0xc7, + 0xf9, 0xcc, 0x7f, 0x8b, 0xa8, 0x5d, 0x55, 0xd2, 0x24, 0xff, 0xdd, 0x2c, + 0xc1, 0xd0, 0x3d, 0xe4, 0x79, 0xea, 0xba, 0x62, 0xe5, 0xa2, 0x62, 0xf4, + 0x1f, 0xec, 0xb0, 0x07, 0xf2, 0x0d, 0x32, 0x84, 0x86, 0x81, 0x3d, 0x95, + 0xc1, 0x64, 0xfe, 0x9a, 0x3d, 0x8f, 0x4b, 0x6d, 0xfb, 0x0d, 0x42, 0xcf, + 0xbf, 0xdb, 0x51, 0xb2, 0x16, 0xa2, 0x35, 0xaa, 0xe7, 0x31, 0x54, 0xc2, + 0x87, 0xc6, 0xa5, 0x30, 0x71, 0x64, 0x65, 0xff, 0x41, 0x20, 0xb0, 0x83, + 0xdb, 0xb7, 0x95, 0xce, 0xd7, 0xcc, 0x7a, 0x77, 0xad, 0xb8, 0xb7, 0x4c, + 0xfc, 0x11, 0x05, 0x2b, 0xc4, 0xd4, 0xb6, 0x8b, 0xae, 0x13, 0xa5, 0x40, + 0x18, 0x6e, 0x0d, 0xe3, 0xc6, 0xb0, 0x81, 0x46, 0x46, 0x7e, 0x52, 0x0b, + 0x85, 0x4d, 0x98, 0xd9, 0x42, 0xdf, 0xde, 0x45, 0xc1, 0x5a, 0x33, 0x12, + 0x46, 0x26, 0xb3, 0x6f, 0xf2, 0x8b, 0x37, 0x6b, 0xfd, 0x08, 0xf4, 0x46, + 0x86, 0x89, 0x63, 0x63, 0x21, 0xe5, 0xa9, 0xb7, 0xd0, 0x09, 0x17, 0x52, + 0xee, 0xea, 0xdf, 0x97, 0xb7, 0x73, 0x2e, 0x54, 0x2c, 0x7b, 0x70, 0xd3, + 0xda, 0x26, 0x57, 0x1f, 0xb0, 0x19, 0xd9, 0x91, 0x18, 0x69, 0x75, 0x42, + 0x63, 0xcf, 0x6c, 0x8c, 0x98, 0x5e, 0x17, 0x99, 0x7e, 0x1d, 0xdc, 0x67, + 0x6d, 0x99, 0xd9, 0x02, 0x6e, 0x73, 0x90, 0x5a, 0x4f, 0x0a, 0xb4, 0x48, + 0xfb, 0xc5, 0xbd, 0xd2, 0x10, 0x05, 0xa6, 0x12, 0x68, 0x36, 0x28, 0x51, + 0x60, 0x1c, 0xa1, 0xe9, 0x90, 0x54, 0xa5, 0x53, 0xc3, 0x48, 0x9e, 0xd8, + 0x42, 0x52, 0x85, 0x0e, 0xff, 0xfe, 0xbf, 0xad, 0x3a, 0xa4, 0x57, 0x09, + 0x13, 0x38, 0x64, 0x15, 0x7c, 0xfd, 0xed, 0x91, 0x76, 0x44, 0x20, 0x84, + 0xd9, 0x90, 0xab, 0xfe, 0xfd, 0xd6, 0xab, 0xf1, 0xb3, 0x25, 0x21, 0x3d, + 0x97, 0x72, 0xb2, 0x95, 0xc5, 0x22, 0x80, 0xd9, 0x4a, 0x49, 0x9d, 0x99, + 0xc2, 0x4a, 0x9a, 0x59, 0xb3, 0x71, 0x75, 0x5b, 0xf9, 0x89, 0x7a, 0xdd, + 0xa9, 0xb3, 0xc3, 0xeb, 0x42, 0x91, 0xe2, 0x97, 0x30, 0x40, 0x48, 0x68, + 0x19, 0x3b, 0xf5, 0x7b, 0x4e, 0x33, 0x4b, 0x0c, 0xf3, 0xed, 0xda, 0x76, + 0x3f, 0xb0, 0x4b, 0x53, 0x85, 0x04, 0x33, 0x07, 0x53, 0xd8, 0x55, 0xa2, + 0xfb, 0x30, 0x2c, 0x66, 0xbd, 0x21, 0xf8, 0xfa, 0x20, 0x14, 0x9a, 0x0d, + 0x7f, 0xc9, 0x2f, 0x5b, 0x34, 0x29, 0x09, 0x16, 0xb5, 0x0a, 0x8d, 0xdf, + 0xa2, 0x84, 0x9a, 0xae, 0xe6, 0xa0, 0x50, 0x80, 0x31, 0x04, 0xd3, 0x0c, + 0x8f, 0xd1, 0x8a, 0xfd, 0xb4, 0xa5, 0xae, 0xf5, 0x3c, 0x62, 0xae, 0x45, + 0x70, 0xbb, 0x54, 0x62, 0xc8, 0x50, 0x71, 0x42, 0x85, 0xf6, 0x6f, 0xa0, + 0xf0, 0x10, 0x8a, 0x09, 0xbd, 0x71, 0x78, 0xa6, 0x5e, 0xe4, 0x03, 0x8f, + 0x3b, 0xd0, 0x5c, 0x37, 0x55, 0x1a, 0xc8, 0x57, 0x26, 0x62, 0x6c, 0xc4, + 0x67, 0x71, 0x9d, 0x97, 0xc0, 0xea, 0x35, 0x3e, 0x12, 0xd0, 0x2b, 0xc2, + 0x8f, 0x9e, 0xa6, 0x41, 0x48, 0x33, 0x83, 0x38, 0x37, 0x7e, 0xd4, 0xe3, + 0xee, 0x94, 0x8b, 0x81, 0xa4, 0x60, 0xdd, 0xdd, 0xc1, 0x8a, 0x7b, 0xda, + 0xa8, 0x46, 0xb8, 0x42, 0x3a, 0x25, 0xd6, 0x81, 0x89, 0x29, 0x21, 0xc2, + 0x0c, 0x5b, 0xfd, 0x3e, 0x8c, 0x65, 0x91, 0x52, 0xb3, 0x74, 0x1f, 0xd1, + 0x49, 0x7e, 0x1d, 0x59, 0x58, 0x96, 0xb5, 0xee, 0x32, 0xa4, 0xa8, 0x07, + 0x7c, 0xd1, 0x5b, 0x4b, 0xf8, 0x43, 0x5a, 0xa5, 0xcc, 0x60, 0xcc, 0x08, + 0x6a, 0x3c, 0x41, 0x66, 0x99, 0xe3, 0xa8, 0xe0, 0xb8, 0x87, 0xfc, 0x92, + 0xc0, 0x79, 0xc5, 0x3f, 0xd6, 0xc6, 0x8c, 0x01, 0xf4, 0xa5, 0x05, 0xad, + 0x51, 0xed, 0x04, 0xd7, 0x55, 0xc0, 0x73, 0x05, 0x0e, 0x73, 0xe5, 0x39, + 0x45, 0x5b, 0x95, 0x4a, 0x34, 0x07, 0x99, 0xdf, 0x4c, 0x35, 0xf5, 0x0c, + 0x27, 0x6d, 0xd1, 0x45, 0xf1, 0xfd, 0x24, 0xb7, 0xfe, 0xea, 0x11, 0x5d, + 0xa2, 0xc5, 0xa6, 0x81, 0x37, 0x1d, 0xc2, 0x31, 0x31, 0xfc, 0xe0, 0xf4, + 0xd7, 0xe9, 0x98, 0x8b, 0xe3, 0x70, 0x51, 0x62, 0xc8, 0x61, 0x6d, 0xec, + 0x75, 0x56, 0x71, 0xae, 0x88, 0xe0, 0x80, 0xf5, 0xb7, 0x85, 0x10, 0xb7, + 0x3d, 0x16, 0x78, 0x5f, 0x72, 0xab, 0x8f, 0x63, 0xc6, 0xd5, 0xa8, 0xc9, + 0x9c, 0xef, 0x8d, 0x9a, 0xc5, 0x4f, 0x63, 0xad, 0xc0, 0xf3, 0x1f, 0x69, + 0x0e, 0xce, 0x29, 0x92, 0xc1, 0x3b, 0xb0, 0xc5, 0xed, 0x0a, 0x7b, 0x92, + 0xd0, 0x4c, 0x9c, 0x82, 0xb0, 0x51, 0xf6, 0x33, 0x61, 0x3b, 0x76, 0x48, + 0x38, 0xf4, 0x7c, 0xaa, 0x52, 0x87, 0x15, 0x1a, 0xbe, 0xb8, 0xdc, 0x9b, + 0x16, 0xd2, 0x07, 0xf7, 0xf9, 0x74, 0xe0, 0xaf, 0x0e, 0x29, 0x05, 0xec, + 0x6c, 0x0e, 0x3b, 0xa7, 0xe7, 0xa4, 0xfc, 0xa4, 0xef, 0x57, 0x16, 0x7f, + 0x13, 0xbd, 0x8c, 0x42, 0x02, 0x55, 0x70, 0x56, 0xa5, 0xa9, 0x01, 0x29, + 0x12, 0x7d, 0x80, 0x46, 0x18, 0x8e, 0x39, 0x3f, 0x44, 0x55, 0xec, 0xef, + 0x60, 0x58, 0x7d, 0xce, 0x64, 0x8e, 0x9c, 0xea, 0xe4, 0x73, 0xd1, 0x48, + 0x9c, 0x3f, 0x92, 0xa0, 0x9a, 0x76, 0xa5, 0x5a, 0x13, 0x1f, 0x10, 0xb9, + 0xb7, 0xb1, 0xde, 0x49, 0x22, 0x58, 0xf4, 0x43, 0x5f, 0x03, 0x43, 0xc3, + 0x6c, 0xbf, 0x82, 0xaf, 0x88, 0x39, 0xfd, 0xb2, 0x28, 0x9b, 0x47, 0x3f, + 0x83, 0x3d, 0xd9, 0x7c, 0xf0, 0xc9, 0xc5, 0xa2, 0xb4, 0xd6, 0x0d, 0x59, + 0x51, 0x27, 0x60, 0x10, 0x5e, 0xbb, 0x18, 0xa6, 0x42, 0x4a, 0x9d, 0xc4, + 0x16, 0x0e, 0xb6, 0x57, 0x23, 0x03, 0x24, 0x27, 0xdc, 0x20, 0x56, 0x30, + 0x8b, 0x0f, 0xb6, 0xb7, 0x73, 0xf5, 0x36, 0x3e, 0xf6, 0x7a, 0x71, 0xa5, + 0x57, 0xcc, 0x6d, 0xc6, 0xf3, 0xdc, 0x35, 0xfb, 0x95, 0xf7, 0xa7, 0xd7, + 0x56, 0x38, 0xd4, 0x15, 0xe2, 0xd5, 0x6f, 0x70, 0x30, 0xc8, 0x7d, 0x8a, + 0x87, 0xe6, 0xd1, 0xe0, 0x50, 0x62, 0xde, 0xfa, 0x29, 0x40, 0x97, 0xa0, + 0x54, 0x63, 0x31, 0xd3, 0x08, 0x87, 0x0a, 0xdc, 0x6e, 0x5e, 0xab, 0x8d, + 0x16, 0xaf, 0x6e, 0x8b, 0x1a, 0x77, 0xf6, 0xd4, 0xe0, 0xbf, 0x59, 0xab, + 0xc7, 0xb0, 0x45, 0x18, 0xaa, 0xe6, 0x65, 0x6f, 0x7d, 0x13, 0xb2, 0xbf, + 0xb3, 0x66, 0x72, 0xfa, 0xfd, 0xee, 0xad, 0x07, 0x56, 0x51, 0x6a, 0xe2, + 0xff, 0xb2, 0xaf, 0x4d, 0xd1, 0xf2, 0x77, 0x35, 0x5e, 0x90, 0xcd, 0xe7, + 0xa8, 0x32, 0x4d, 0x9f, 0xbd, 0xa8, 0xce, 0xab, 0xf1, 0x49, 0x98, 0xb5, + 0x23, 0x5c, 0x62, 0x2d, 0x43, 0x31, 0x80, 0x87, 0xc2, 0xa8, 0xf5, 0xb9, + 0xb6, 0xae, 0x7f, 0x37, 0x13, 0xb8, 0x6b, 0x73, 0xf3, 0x56, 0x38, 0xa7, + 0x9b, 0x97, 0x69, 0x37, 0x00, 0xdc, 0xff, 0xfe, 0x58, 0xc9, 0x12, 0x47, + 0x75, 0x98, 0x1f, 0xad, 0xd8, 0xb5, 0xc8, 0x47, 0x4f, 0xd0, 0x72, 0x63, + 0x54, 0x25, 0x6c, 0x88, 0xc9, 0x9f, 0x3c, 0x82, 0xe0, 0xdd, 0x4c, 0xff, + 0x8e, 0xaf, 0x8f, 0x8e, 0xea, 0x84, 0x3f, 0x73, 0xdd, 0x9e, 0x18, 0x73, + 0x47, 0x70, 0xc7, 0xc7, 0x99, 0x65, 0xcf, 0xf3, 0xb6, 0x24, 0xed, 0x97, + 0x8f, 0xcd, 0x93, 0x1e, 0xff, 0x6e, 0x9c, 0xf1, 0x30, 0x14, 0x1a, 0x27, + 0x59, 0x6a, 0x0e, 0xf3, 0xe4, 0xfa, 0x1d, 0x65, 0xb5, 0x53, 0xe4, 0xab, + 0xb1, 0x3e, 0xe1, 0x91, 0xf4, 0x6d, 0x99, 0xca, 0x7d, 0x03, 0x08, 0x50, + 0xea, 0xa9, 0x39, 0x7f, 0x6d, 0xe7, 0x43, 0xfb, 0x64, 0xcc, 0x4b, 0x9e, + 0xa0, 0x26, 0xe4, 0x0e, 0xff, 0xb7, 0x11, 0x0a, 0x29, 0x50, 0x90, 0xd7, + 0x4d, 0x62, 0x9a, 0x4a, 0x23, 0xb7, 0xd3, 0x53, 0xde, 0x3a, 0xd1, 0xba, + 0xd3, 0x10, 0x59, 0xc6, 0xc5, 0x5e, 0xac, 0xf9, 0x61, 0x74, 0x54, 0xf4, + 0x27, 0x9f, 0x9a, 0x61, 0x13, 0xdc, 0xe5, 0x96, 0xe3, 0x95, 0x0d, 0xcc, + 0xbd, 0x81, 0x74, 0x79, 0x73, 0xef, 0x2e, 0x0b, 0x0f, 0x91, 0x65, 0x3c, + 0x26, 0x7c, 0x47, 0x10, 0x31, 0x0b, 0xfb, 0x41, 0x0c, 0xc2, 0xa8, 0xc4, + 0x0e, 0xbd, 0x0a, 0x8c, 0xa4, 0x80, 0x45, 0x57, 0x62, 0x0b, 0x4d, 0x44, + 0x5e, 0x59, 0x77, 0xfd, 0x3d, 0xf3, 0xd7, 0x92, 0x49, 0xc1, 0xcb, 0x8a, + 0x54, 0x56, 0x3b, 0xde, 0xcf, 0x16, 0x9a, 0x65, 0xbe, 0xac, 0x64, 0xe1, + 0xd4, 0xd4, 0x1e, 0xac, 0x6b, 0x4a, 0xad, 0xc4, 0x33, 0xac, 0xcb, 0x83, + 0xf4, 0x4d, 0xe8, 0xb6, 0xd7, 0x23, 0xd7, 0x71, 0x25, 0xa2, 0x25, 0x3d, + 0x7e, 0xf0, 0x3b, 0x7f, 0x61, 0x11, 0x56, 0xd4, 0x83, 0xc8, 0xc0, 0x29, + 0x38, 0x10, 0x73, 0xad, 0x6a, 0xb7, 0xb9, 0xd2, 0x2e, 0x9f, 0xae, 0x16, + 0x5e, 0xa6, 0x13, 0x1c, 0xc2, 0x17, 0x73, 0x43, 0x03, 0xdd, 0xa6, 0xaf, + 0x9a, 0x17, 0x31, 0xb8, 0x86, 0x97, 0xc2, 0xd6, 0xe6, 0xed, 0xd4, 0xe1, + 0x7d, 0xb9, 0xa6, 0x96, 0xc1, 0x4b, 0xcb, 0x11, 0x1e, 0xe1, 0xe0, 0xd2, + 0x28, 0x69, 0x68, 0x3b, 0x21, 0x17, 0x63, 0x0c, 0xc0, 0x49, 0x30, 0x22, + 0x3a, 0x59, 0x72, 0xe6, 0x47, 0xb4, 0xdc, 0xa8, 0x29, 0x1c, 0x89, 0xa6, + 0x3a, 0x77, 0x99, 0xea, 0x46, 0xce, 0x38, 0xda, 0x31, 0x88, 0xad, 0xe7, + 0x26, 0xce, 0xc6, 0x56, 0x04, 0x30, 0xfa, 0x01, 0xac, 0xbb, 0xe2, 0xb8, + 0x23, 0xe4, 0x9d, 0x4f, 0x77, 0x02, 0x00, 0x28, 0xf1, 0xe0, 0x19, 0x3f, + 0x22, 0x4f, 0x22, 0x69, 0x87, 0xc0, 0x4e, 0x26, 0x33, 0xfe, 0x6c, 0x70, + 0x56, 0x3b, 0x60, 0x5f, 0xfb, 0xf8, 0x43, 0xcf, 0x3f, 0xb9, 0xcb, 0x80, + 0x22, 0xbb, 0x0a, 0xa8, 0x1c, 0x3e, 0x7e, 0x4d, 0x42, 0x60, 0x5c, 0x8e, + 0xfa, 0x42, 0xb3, 0x95, 0xe7, 0x92, 0x6b, 0xec, 0x7a, 0x95, 0x88, 0x98, + 0xe3, 0xf9, 0x0d, 0xe5, 0x08, 0xf1, 0x26, 0x96, 0x2a, 0x81, 0x2b, 0x7c, + 0x0d, 0x12, 0xa0, 0x7f, 0x7b, 0x39, 0xf6, 0xcc, 0x1b, 0x2d, 0x2c, 0xe9, + 0x5b, 0x02, 0x9b, 0x5c, 0x94, 0x51, 0x13, 0xe8, 0xa0, 0x19, 0xce, 0xde, + 0x07, 0x1b, 0xda, 0x39, 0x14, 0xb5, 0x8b, 0xcf, 0x79, 0x3e, 0x2b, 0xb8, + 0x75, 0xab, 0x81, 0xee, 0x5e, 0x08, 0x33, 0xc3, 0x49, 0x5b, 0x4a, 0x9c, + 0x74, 0x34, 0xde, 0x08, 0x61, 0x03, 0x38, 0xe3, 0xd8, 0xff, 0xc5, 0xc0, + 0xb5, 0x40, 0xd5, 0x26, 0x57, 0x85, 0xf1, 0xb7, 0x77, 0xb6, 0x36, 0xe0, + 0x8d, 0x43, 0x3a, 0xef, 0xfe, 0x0f, 0xf7, 0xee, 0x67, 0x6c, 0x7b, 0xd1, + 0x83, 0xf6, 0x10, 0xda, 0x67, 0x04, 0x3a, 0x27, 0xd8, 0x3a, 0xcb, 0x9d, + 0x4c, 0xa6, 0x9a, 0xc7, 0xea, 0x07, 0xc6, 0x76, 0x79, 0x1b, 0x23, 0x4a, + 0x68, 0x2f, 0x14, 0x84, 0x42, 0x79, 0xe8, 0x1f, 0xf2, 0xe6, 0xac, 0x72, + 0xb0, 0xb0, 0xb6, 0x39, 0x95, 0x40, 0xa4, 0x6e, 0x54, 0x2e, 0xb7, 0xb5, + 0x13, 0x70, 0x48, 0x0d, 0x27, 0xed, 0x2c, 0xa2, 0x64, 0x53, 0xb4, 0x04, + 0x84, 0xab, 0xd8, 0xea, 0x2a, 0x8c, 0xac, 0x5b, 0x1d, 0xb8, 0xb2, 0xbe, + 0x55, 0x2b, 0x4a, 0x47, 0xfc, 0xe0, 0x15, 0x78, 0xb6, 0xd6, 0xff, 0x20, + 0xa8, 0x8a, 0xec, 0x8b, 0x30, 0xef, 0xc5, 0xc6, 0xec, 0xa0, 0xdf, 0xd3, + 0xc4, 0x2b, 0x4a, 0xdf, 0xef, 0x5c, 0x46, 0xb3, 0x31, 0xc7, 0x5f, 0x8f, + 0x1e, 0x99, 0x76, 0x81, 0x71, 0x61, 0xdb, 0xc3, 0xc4, 0x0f, 0x66, 0x7b, + 0xd7, 0x44, 0xc7, 0x8d, 0x12, 0x38, 0x71, 0x7c, 0xd8, 0x41, 0xf6, 0x8a, + 0xb9, 0xba, 0xd2, 0x1f, 0xa1, 0x27, 0x64, 0x67, 0x51, 0xb2, 0xaf, 0xea, + 0x02, 0x95, 0x79, 0x20, 0x0a, 0xc8, 0xaa, 0x03, 0x11, 0xb6, 0x8b, 0x7d, + 0x86, 0xb7, 0xef, 0x5e, 0x3f, 0x0b, 0x91, 0x47, 0xf0, 0x43, 0xb4, 0x54, + 0x1d, 0x16, 0x66, 0xe9, 0x63, 0x1a, 0x55, 0xaf, 0x34, 0xad, 0x11, 0x68, + 0x4d, 0x36, 0xb7, 0x0c, 0x6d, 0x4d, 0xed, 0xba, 0x14, 0xe8, 0xf6, 0xe2, + 0x15, 0x64, 0xb6, 0x15, 0x28, 0xbf, 0xd2, 0x4d, 0xb6, 0x6f, 0xca, 0x5f, + 0x81, 0x1b, 0xf0, 0x31, 0xf5, 0xd3, 0xe0, 0x06, 0xc7, 0xf3, 0x0c, 0x18, + 0x91, 0x45, 0x22, 0xa2, 0x30, 0x48, 0x82, 0xeb, 0x42, 0xfc, 0x8f, 0x2a, + 0xa3, 0x1a, 0x8d, 0x84, 0x28, 0x20, 0x16, 0x95, 0xd9, 0x66, 0x67, 0x2b, + 0xef, 0xc6, 0x6e, 0x56, 0x1c, 0x62, 0x74, 0x16, 0x5c, 0x3e, 0x17, 0xd0, + 0xb7, 0xdd, 0x70, 0xb6, 0x0e, 0x79, 0x46, 0xc5, 0x4e, 0x72, 0x46, 0x69, + 0xf5, 0xa1, 0x1c, 0x7b, 0xd5, 0x67, 0x5c, 0xb3, 0x46, 0x4d, 0x18, 0x31, + 0x47, 0x42, 0x20, 0xe6, 0x12, 0x84, 0x4e, 0x16, 0x0f, 0x4a, 0xd0, 0xc4, + 0x91, 0xa3, 0xbd, 0x91, 0xcd, 0x86, 0x4c, 0xcd, 0x4b, 0x2e, 0x62, 0x84, + 0xea, 0x19, 0x2d, 0x21, 0x1a, 0x64, 0xc4, 0xd2, 0x24, 0x92, 0x96, 0x04, + 0x66, 0xb5, 0x4a, 0xe4, 0xa9, 0xd6, 0xaf, 0x12, 0x9b, 0xb5, 0x59, 0xe0, + 0x5c, 0x84, 0x84, 0x7c, 0x68, 0x99, 0xd8, 0x23, 0xa2, 0x15, 0xa7, 0x82, + 0xa5, 0x66, 0x95, 0x8f, 0xfe, 0x57, 0xc1, 0x12, 0x6c, 0x89, 0xe5, 0x5b, + 0x5d, 0x64, 0xdb, 0x81, 0x4f, 0x77, 0x3c, 0xc8, 0x52, 0x4e, 0x2a, 0xd6, + 0x74, 0x3c, 0x4b, 0x11, 0xfc, 0xc1, 0x7c, 0x01, 0xba, 0x0f, 0x0f, 0x57, + 0x8a, 0xbe, 0x5b, 0x16, 0x88, 0x96, 0xe6, 0xe9, 0x60, 0xcf, 0x66, 0xe9, + 0xe6, 0x07, 0xb0, 0x0b, 0xa3, 0xa0, 0xad, 0xdf, 0x70, 0xd4, 0xcb, 0x2e, + 0x33, 0x2f, 0xe5, 0xf2, 0x1e, 0x0d, 0x74, 0x7a, 0xf9, 0x4a, 0x0f, 0x32, + 0xb4, 0xa1, 0xc9, 0xf5, 0x3f, 0x0a, 0x06, 0xf9, 0x67, 0x45, 0x9c, 0xd9, + 0x58, 0xd4, 0x0e, 0x72, 0x55, 0x47, 0x49, 0x9b, 0xab, 0x9c, 0x66, 0xe7, + 0x4d, 0x9a, 0x02, 0x1b, 0x41, 0xad, 0xe5, 0x8c, 0x7f, 0xa1, 0xdc, 0xad, + 0xcd, 0x74, 0xda, 0x9f, 0xfa, 0x87, 0x32, 0xc1, 0x07, 0x8e, 0x9b, 0xef, + 0x28, 0x2f, 0x17, 0x6d, 0xdb, 0x84, 0x4b, 0xa8, 0x7d, 0x31, 0xa8, 0x32, + 0xe4, 0x9a, 0x1e, 0x0e, 0xef, 0x68, 0xf4, 0xac, 0x03, 0x6c, 0x68, 0xcc, + 0x28, 0xbb, 0xfb, 0x21, 0xb8, 0x11, 0xd7, 0xf9, 0xe8, 0x24, 0x37, 0xdf, + 0xe0, 0xb2, 0xef, 0xd6, 0xec, 0xdf, 0xcf, 0xf5, 0x50, 0x19, 0xa3, 0xa9, + 0x1b, 0x01, 0x2e, 0x94, 0x42, 0xb0, 0x14, 0x5d, 0x0e, 0x37, 0x46, 0x4a, + 0x52, 0x53, 0x60, 0x6b, 0x89, 0xc9, 0xca, 0xed, 0x0a, 0x0c, 0x18, 0x33, + 0x3c, 0x40, 0x42, 0x76, 0x7a, 0x7d, 0xb6, 0x10, 0x29, 0x3e, 0x42, 0x75, + 0xa6, 0xbf, 0xcb, 0xd3, 0xdc, 0xe1, 0x00, 0x05, 0x08, 0x25, 0x67, 0x6c, + 0x72, 0xde, 0x26, 0x72, 0x88, 0xbe, 0xfa, 0x05, 0x57, 0x77, 0x78, 0x83, + 0xce, 0xd5, 0x44, 0x49, 0x8b, 0xab, 0xbc, 0xca, 0xd3, 0x1c, 0x34, 0x4a, + 0xaa, 0xc7, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x17, 0x22, 0x2a, 0x2f, 0x36, 0x3d, 0x43}; +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_KEYGEN_PCT */ +#endif /* !EXPECTED_SIGNATURES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/main.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/main.c new file mode 100644 index 0000000000..774602a369 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/main.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include +#include +#include + +/* Import public mldsa-native API + * + * This requires specifying the parameter set and namespace prefix + * used for the build. + * + * The parameter set is configured on the command line + */ + +#include +#include "expected_signatures.h" +#include "test_only_rng/notrandombytes.h" + +#define CHECK(x) \ + do \ + { \ + int rc; \ + rc = (x); \ + if (!rc) \ + { \ + fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \ + return 1; \ + } \ + } while (0) + +#define TEST_MSG \ + "This is a test message for ML-DSA digital signature algorithm!" +#define TEST_MSG_LEN (sizeof(TEST_MSG) - 1) + +#define TEST_CTX "test_context_123" +#define TEST_CTX_LEN (sizeof(TEST_CTX) - 1) + +int main(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t sig[CRYPTO_BYTES]; + uint8_t sm[TEST_MSG_LEN + CRYPTO_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + CRYPTO_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-%d monolithic_build Example\n", MLD_CONFIG_PARAMETER_SET); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(crypto_sign_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(crypto_sign_signature(sig, &siglen, (const uint8_t *)test_msg, + TEST_MSG_LEN, (const uint8_t *)test_ctx, + TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(crypto_sign_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(crypto_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(crypto_sign_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", CRYPTO_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", CRYPTO_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", CRYPTO_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature)); + CHECK(memcmp(sig, expected_signature, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/mldsa_native.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/mldsa_native.c new file mode 100644 index 0000000000..9668cec167 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/mldsa_native.c @@ -0,0 +1,699 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/****************************************************************************** + * + * Single compilation unit (SCU) for fixed-level build of mldsa-native + * + * This compilation unit bundles together all source files for a build + * of mldsa-native for a fixed security level (MLDSA-44/65/87). + * + * # API + * + * The API exposed by this file is described in mldsa_native.h. + * + * # Multi-level build + * + * If you want an SCU build of mldsa-native with support for multiple security + * levels, you need to include this file multiple times, and set + * MLD_CONFIG_MULTILEVEL_WITH_SHARED and MLD_CONFIG_MULTILEVEL_NO_SHARED + * appropriately. This is exemplified in examples/monolithic_build_multilevel + * and examples/monolithic_build_multilevel_native. + * + * # Configuration + * + * The following options from the mldsa-native configuration are relevant: + * + * - MLD_CONFIG_FIPS202_CUSTOM_HEADER + * Set this option if you use a custom FIPS202 implementation. + * + * - MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * Set this option if you want to include the native arithmetic backends + * in your build. + * + * - MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * Set this option if you want to include the native FIPS202 backends + * in your build. + * + * - MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * Set this option if you want to keep the directives defined in + * level-independent headers. This is needed for a multi-level build. + */ + +/* If parts of the mldsa-native source tree are not used, + * consider reducing this header via `unifdef`. + * + * Example: + * ```bash + * unifdef -UMLD_CONFIG_USE_NATIVE_BACKEND_ARITH mldsa_native.c + * ``` + */ + +#include "src/common.h" + +#include "src/ct.c" +#include "src/debug.c" +#include "src/packing.c" +#include "src/poly.c" +#include "src/poly_kl.c" +#include "src/polyvec.c" +#include "src/sign.c" + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#include "src/fips202/fips202.c" +#include "src/fips202/fips202x4.c" +#include "src/fips202/keccakf1600.c" +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#if defined(MLD_SYS_AARCH64) +#include "src/native/aarch64/src/aarch64_zetas.c" +#include "src/native/aarch64/src/polyz_unpack_table.c" +#include "src/native/aarch64/src/rej_uniform_eta_table.c" +#include "src/native/aarch64/src/rej_uniform_table.c" +#endif /* MLD_SYS_AARCH64 */ +#if defined(MLD_SYS_X86_64) +#include "src/native/x86_64/src/consts.c" +#include "src/native/x86_64/src/poly_caddq_avx2.c" +#include "src/native/x86_64/src/poly_chknorm_avx2.c" +#include "src/native/x86_64/src/poly_decompose_32_avx2.c" +#include "src/native/x86_64/src/poly_decompose_88_avx2.c" +#include "src/native/x86_64/src/poly_use_hint_32_avx2.c" +#include "src/native/x86_64/src/poly_use_hint_88_avx2.c" +#include "src/native/x86_64/src/polyz_unpack_17_avx2.c" +#include "src/native/x86_64/src/polyz_unpack_19_avx2.c" +#include "src/native/x86_64/src/rej_uniform_avx2.c" +#include "src/native/x86_64/src/rej_uniform_eta2_avx2.c" +#include "src/native/x86_64/src/rej_uniform_eta4_avx2.c" +#include "src/native/x86_64/src/rej_uniform_table.c" +#endif /* MLD_SYS_X86_64 */ +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#if defined(MLD_SYS_AARCH64) +#include "src/fips202/native/aarch64/src/keccakf1600_round_constants.c" +#endif +#if defined(MLD_SYS_X86_64) +#include "src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +/* Macro #undef's + * + * The following undefines macros from headers + * included by the source files imported above. + * + * This is to allow building and linking multiple builds + * of mldsa-native for varying parameter sets through concatenation + * of this file, as if the files had been compiled separately. + * If this is not relevant to you, you may remove the following. + */ + +/* + * Undefine macros from MLD_CONFIG_PARAMETER_SET-specific files + */ +/* mldsa/mldsa_native.h */ +#undef CRYPTO_BYTES +#undef CRYPTO_PUBLICKEYBYTES +#undef CRYPTO_SECRETKEYBYTES +#undef MLDSA44_BYTES +#undef MLDSA44_CRHBYTES +#undef MLDSA44_PUBLICKEYBYTES +#undef MLDSA44_RNDBYTES +#undef MLDSA44_SECRETKEYBYTES +#undef MLDSA44_SEEDBYTES +#undef MLDSA44_TRBYTES +#undef MLDSA65_BYTES +#undef MLDSA65_CRHBYTES +#undef MLDSA65_PUBLICKEYBYTES +#undef MLDSA65_RNDBYTES +#undef MLDSA65_SECRETKEYBYTES +#undef MLDSA65_SEEDBYTES +#undef MLDSA65_TRBYTES +#undef MLDSA87_BYTES +#undef MLDSA87_CRHBYTES +#undef MLDSA87_PUBLICKEYBYTES +#undef MLDSA87_RNDBYTES +#undef MLDSA87_SECRETKEYBYTES +#undef MLDSA87_SEEDBYTES +#undef MLDSA87_TRBYTES +#undef MLDSA_BYTES +#undef MLDSA_BYTES_ +#undef MLDSA_CRHBYTES +#undef MLDSA_PUBLICKEYBYTES +#undef MLDSA_PUBLICKEYBYTES_ +#undef MLDSA_RNDBYTES +#undef MLDSA_SECRETKEYBYTES +#undef MLDSA_SECRETKEYBYTES_ +#undef MLDSA_SEEDBYTES +#undef MLDSA_TRBYTES +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_LEGACY_CONFIG +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_NAMESPACE +#undef MLD_API_QUALIFIER +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_QUALIFIER +#undef MLD_DOMAIN_SEPARATION_MAX_BYTES +#undef MLD_ERR_FAIL +#undef MLD_ERR_OUT_OF_MEMORY +#undef MLD_ERR_RNG_FAIL +#undef MLD_H +#undef MLD_MAX3_ +#undef MLD_PREHASH_NONE +#undef MLD_PREHASH_SHA2_224 +#undef MLD_PREHASH_SHA2_256 +#undef MLD_PREHASH_SHA2_384 +#undef MLD_PREHASH_SHA2_512 +#undef MLD_PREHASH_SHA2_512_224 +#undef MLD_PREHASH_SHA2_512_256 +#undef MLD_PREHASH_SHA3_224 +#undef MLD_PREHASH_SHA3_256 +#undef MLD_PREHASH_SHA3_384 +#undef MLD_PREHASH_SHA3_512 +#undef MLD_PREHASH_SHAKE_128 +#undef MLD_PREHASH_SHAKE_256 +#undef MLD_TOTAL_ALLOC_44 +#undef MLD_TOTAL_ALLOC_44_KEYPAIR +#undef MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#undef MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#undef MLD_TOTAL_ALLOC_44_SIGN +#undef MLD_TOTAL_ALLOC_44_VERIFY +#undef MLD_TOTAL_ALLOC_65 +#undef MLD_TOTAL_ALLOC_65_KEYPAIR +#undef MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#undef MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#undef MLD_TOTAL_ALLOC_65_SIGN +#undef MLD_TOTAL_ALLOC_65_VERIFY +#undef MLD_TOTAL_ALLOC_87 +#undef MLD_TOTAL_ALLOC_87_KEYPAIR +#undef MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#undef MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#undef MLD_TOTAL_ALLOC_87_SIGN +#undef MLD_TOTAL_ALLOC_87_VERIFY +#undef crypto_sign +#undef crypto_sign_keypair +#undef crypto_sign_open +#undef crypto_sign_signature +#undef crypto_sign_verify +/* mldsa/src/common.h */ +#undef MLD_ADD_PARAM_SET +#undef MLD_ALLOC +#undef MLD_APPLY +#undef MLD_ASM_FN_SYMBOL +#undef MLD_ASM_NAMESPACE +#undef MLD_BUILD_INTERNAL +#undef MLD_COMMON_H +#undef MLD_CONCAT +#undef MLD_CONCAT_ +#undef MLD_CONTEXT_PARAMETERS_0 +#undef MLD_CONTEXT_PARAMETERS_1 +#undef MLD_CONTEXT_PARAMETERS_2 +#undef MLD_CONTEXT_PARAMETERS_3 +#undef MLD_CONTEXT_PARAMETERS_4 +#undef MLD_CONTEXT_PARAMETERS_5 +#undef MLD_CONTEXT_PARAMETERS_6 +#undef MLD_CONTEXT_PARAMETERS_7 +#undef MLD_CONTEXT_PARAMETERS_8 +#undef MLD_CONTEXT_PARAMETERS_9 +#undef MLD_EMPTY_CU +#undef MLD_ERR_FAIL +#undef MLD_ERR_OUT_OF_MEMORY +#undef MLD_ERR_RNG_FAIL +#undef MLD_EXTERNAL_API +#undef MLD_FIPS202X4_HEADER_FILE +#undef MLD_FIPS202_HEADER_FILE +#undef MLD_FREE +#undef MLD_INTERNAL_API +#undef MLD_MULTILEVEL_BUILD +#undef MLD_NAMESPACE +#undef MLD_NAMESPACE_KL +#undef MLD_NAMESPACE_PREFIX +#undef MLD_NAMESPACE_PREFIX_KL +#undef MLD_UNION_OR_STRUCT +#undef mld_memcpy +#undef mld_memset +/* mldsa/src/packing.h */ +#undef MLD_PACKING_H +#undef mld_pack_pk +#undef mld_pack_sig_c_h +#undef mld_pack_sig_z +#undef mld_pack_sk +#undef mld_unpack_pk +#undef mld_unpack_sig +#undef mld_unpack_sk +/* mldsa/src/params.h */ +#undef MLDSA_BETA +#undef MLDSA_CRHBYTES +#undef MLDSA_CRYPTO_BYTES +#undef MLDSA_CRYPTO_PUBLICKEYBYTES +#undef MLDSA_CRYPTO_SECRETKEYBYTES +#undef MLDSA_CTILDEBYTES +#undef MLDSA_D +#undef MLDSA_ETA +#undef MLDSA_GAMMA1 +#undef MLDSA_GAMMA2 +#undef MLDSA_K +#undef MLDSA_L +#undef MLDSA_N +#undef MLDSA_OMEGA +#undef MLDSA_POLYETA_PACKEDBYTES +#undef MLDSA_POLYT0_PACKEDBYTES +#undef MLDSA_POLYT1_PACKEDBYTES +#undef MLDSA_POLYVECH_PACKEDBYTES +#undef MLDSA_POLYW1_PACKEDBYTES +#undef MLDSA_POLYZ_PACKEDBYTES +#undef MLDSA_Q +#undef MLDSA_Q_HALF +#undef MLDSA_RNDBYTES +#undef MLDSA_SEEDBYTES +#undef MLDSA_TAU +#undef MLDSA_TRBYTES +#undef MLD_PARAMS_H +/* mldsa/src/poly_kl.h */ +#undef MLD_POLYETA_UNPACK_LOWER_BOUND +#undef MLD_POLY_KL_H +#undef mld_poly_challenge +#undef mld_poly_decompose +#undef mld_poly_make_hint +#undef mld_poly_uniform_eta +#undef mld_poly_uniform_eta_4x +#undef mld_poly_uniform_gamma1 +#undef mld_poly_uniform_gamma1_4x +#undef mld_poly_use_hint +#undef mld_polyeta_pack +#undef mld_polyeta_unpack +#undef mld_polyw1_pack +#undef mld_polyz_pack +#undef mld_polyz_unpack +/* mldsa/src/polyvec.h */ +#undef MLD_POLYVEC_H +#undef mld_polymat +#undef mld_polymat_get_row +#undef mld_polyvec_matrix_expand +#undef mld_polyvec_matrix_pointwise_montgomery +#undef mld_polyveck +#undef mld_polyveck_add +#undef mld_polyveck_caddq +#undef mld_polyveck_chknorm +#undef mld_polyveck_decompose +#undef mld_polyveck_invntt_tomont +#undef mld_polyveck_make_hint +#undef mld_polyveck_ntt +#undef mld_polyveck_pack_eta +#undef mld_polyveck_pack_t0 +#undef mld_polyveck_pack_w1 +#undef mld_polyveck_pointwise_poly_montgomery +#undef mld_polyveck_power2round +#undef mld_polyveck_reduce +#undef mld_polyveck_shiftl +#undef mld_polyveck_sub +#undef mld_polyveck_unpack_eta +#undef mld_polyveck_unpack_t0 +#undef mld_polyveck_use_hint +#undef mld_polyvecl +#undef mld_polyvecl_chknorm +#undef mld_polyvecl_ntt +#undef mld_polyvecl_pack_eta +#undef mld_polyvecl_pointwise_acc_montgomery +#undef mld_polyvecl_uniform_gamma1 +#undef mld_polyvecl_unpack_eta +#undef mld_polyvecl_unpack_z +/* mldsa/src/rounding.h */ +#undef MLD_2_POW_D +#undef MLD_ROUNDING_H +#undef mld_decompose +#undef mld_make_hint +#undef mld_power2round +#undef mld_use_hint +/* mldsa/src/sign.h */ +#undef MLD_DOMAIN_SEPARATION_MAX_BYTES +#undef MLD_PREHASH_NONE +#undef MLD_PREHASH_SHA2_224 +#undef MLD_PREHASH_SHA2_256 +#undef MLD_PREHASH_SHA2_384 +#undef MLD_PREHASH_SHA2_512 +#undef MLD_PREHASH_SHA2_512_224 +#undef MLD_PREHASH_SHA2_512_256 +#undef MLD_PREHASH_SHA3_224 +#undef MLD_PREHASH_SHA3_256 +#undef MLD_PREHASH_SHA3_384 +#undef MLD_PREHASH_SHA3_512 +#undef MLD_PREHASH_SHAKE_128 +#undef MLD_PREHASH_SHAKE_256 +#undef MLD_SIGN_H +#undef mld_prepare_domain_separation_prefix +#undef mld_sign +#undef mld_sign_keypair +#undef mld_sign_keypair_internal +#undef mld_sign_open +#undef mld_sign_pk_from_sk +#undef mld_sign_signature +#undef mld_sign_signature_extmu +#undef mld_sign_signature_internal +#undef mld_sign_signature_pre_hash_internal +#undef mld_sign_signature_pre_hash_shake256 +#undef mld_sign_verify +#undef mld_sign_verify_extmu +#undef mld_sign_verify_internal +#undef mld_sign_verify_pre_hash_internal +#undef mld_sign_verify_pre_hash_shake256 + +#if !defined(MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS) +/* + * Undefine macros from MLD_CONFIG_PARAMETER_SET-generic files + */ +/* mldsa/src/ct.h */ +#undef MLD_CT_H +#undef MLD_USE_ASM_VALUE_BARRIER +#undef mld_ct_opt_blocker_u64 +/* mldsa/src/debug.h */ +#undef MLD_DEBUG_H +#undef mld_assert +#undef mld_assert_abs_bound +#undef mld_assert_abs_bound_2d +#undef mld_assert_bound +#undef mld_assert_bound_2d +#undef mld_debug_check_assert +#undef mld_debug_check_bounds +/* mldsa/src/poly.h */ +#undef MLD_INTT_BOUND +#undef MLD_NTT_BOUND +#undef MLD_POLY_H +#undef mld_poly_add +#undef mld_poly_caddq +#undef mld_poly_chknorm +#undef mld_poly_invntt_tomont +#undef mld_poly_ntt +#undef mld_poly_pointwise_montgomery +#undef mld_poly_power2round +#undef mld_poly_reduce +#undef mld_poly_shiftl +#undef mld_poly_sub +#undef mld_poly_uniform +#undef mld_poly_uniform_4x +#undef mld_polyt0_pack +#undef mld_polyt0_unpack +#undef mld_polyt1_pack +#undef mld_polyt1_unpack +/* mldsa/src/randombytes.h */ +#undef MLD_RANDOMBYTES_H +/* mldsa/src/reduce.h */ +#undef MLD_MONT +#undef MLD_REDUCE32_DOMAIN_MAX +#undef MLD_REDUCE32_RANGE_MAX +#undef MLD_REDUCE_H +/* mldsa/src/symmetric.h */ +#undef MLD_STREAM128_BLOCKBYTES +#undef MLD_STREAM256_BLOCKBYTES +#undef MLD_SYMMETRIC_H +#undef mld_xof128_absorb_once +#undef mld_xof128_ctx +#undef mld_xof128_init +#undef mld_xof128_release +#undef mld_xof128_squeezeblocks +#undef mld_xof128_x4_absorb +#undef mld_xof128_x4_ctx +#undef mld_xof128_x4_init +#undef mld_xof128_x4_release +#undef mld_xof128_x4_squeezeblocks +#undef mld_xof256_absorb_once +#undef mld_xof256_ctx +#undef mld_xof256_init +#undef mld_xof256_release +#undef mld_xof256_squeezeblocks +#undef mld_xof256_x4_absorb +#undef mld_xof256_x4_ctx +#undef mld_xof256_x4_init +#undef mld_xof256_x4_release +#undef mld_xof256_x4_squeezeblocks +/* mldsa/src/sys.h */ +#undef MLD_ALIGN +#undef MLD_ALIGN_UP +#undef MLD_ALWAYS_INLINE +#undef MLD_CET_ENDBR +#undef MLD_CT_TESTING_DECLASSIFY +#undef MLD_CT_TESTING_SECRET +#undef MLD_DEFAULT_ALIGN +#undef MLD_HAVE_INLINE_ASM +#undef MLD_INLINE +#undef MLD_MUST_CHECK_RETURN_VALUE +#undef MLD_RESTRICT +#undef MLD_STATIC_TESTABLE +#undef MLD_SYS_AARCH64 +#undef MLD_SYS_AARCH64_EB +#undef MLD_SYS_APPLE +#undef MLD_SYS_BIG_ENDIAN +#undef MLD_SYS_H +#undef MLD_SYS_LINUX +#undef MLD_SYS_LITTLE_ENDIAN +#undef MLD_SYS_PPC64LE +#undef MLD_SYS_RISCV32 +#undef MLD_SYS_RISCV64 +#undef MLD_SYS_WINDOWS +#undef MLD_SYS_X86_64 +#undef MLD_SYS_X86_64_AVX2 +/* mldsa/src/cbmc.h */ +#undef MLD_CBMC_H +#undef __contract__ +#undef __loop__ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +/* + * Undefine macros from FIPS-202 files + */ +/* mldsa/src/fips202/fips202.h */ +#undef MLD_FIPS202_FIPS202_H +#undef MLD_KECCAK_LANES +#undef SHA3_256_HASHBYTES +#undef SHA3_256_RATE +#undef SHA3_512_HASHBYTES +#undef SHA3_512_RATE +#undef SHAKE128_RATE +#undef SHAKE256_RATE +#undef mld_shake128_absorb +#undef mld_shake128_finalize +#undef mld_shake128_init +#undef mld_shake128_release +#undef mld_shake128_squeeze +#undef mld_shake256 +#undef mld_shake256_absorb +#undef mld_shake256_finalize +#undef mld_shake256_init +#undef mld_shake256_release +#undef mld_shake256_squeeze +/* mldsa/src/fips202/fips202x4.h */ +#undef MLD_FIPS202_FIPS202X4_H +#undef mld_shake128x4_absorb_once +#undef mld_shake128x4_init +#undef mld_shake128x4_release +#undef mld_shake128x4_squeezeblocks +#undef mld_shake256x4_absorb_once +#undef mld_shake256x4_init +#undef mld_shake256x4_release +#undef mld_shake256x4_squeezeblocks +/* mldsa/src/fips202/keccakf1600.h */ +#undef MLD_FIPS202_KECCAKF1600_H +#undef MLD_KECCAK_LANES +#undef MLD_KECCAK_WAY +#undef mld_keccakf1600_extract_bytes +#undef mld_keccakf1600_permute +#undef mld_keccakf1600_xor_bytes +#undef mld_keccakf1600x4_extract_bytes +#undef mld_keccakf1600x4_permute +#undef mld_keccakf1600x4_xor_bytes +#endif /* !MLD_CONFIG_FIPS202_CUSTOM_HEADER */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +/* mldsa/src/fips202/native/api.h */ +#undef MLD_FIPS202_NATIVE_API_H +#undef MLD_NATIVE_FUNC_FALLBACK +#undef MLD_NATIVE_FUNC_SUCCESS +/* mldsa/src/fips202/native/auto.h */ +#undef MLD_FIPS202_NATIVE_AUTO_H +#if defined(MLD_SYS_AARCH64) +/* + * Undefine macros from native code (FIPS202, AArch64) + */ +/* mldsa/src/fips202/native/aarch64/auto.h */ +#undef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* mldsa/src/fips202/native/aarch64/src/fips202_native_aarch64.h */ +#undef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#undef mld_keccak_f1600_x1_scalar_asm +#undef mld_keccak_f1600_x1_v84a_asm +#undef mld_keccak_f1600_x2_v84a_asm +#undef mld_keccak_f1600_x4_scalar_v8a_hybrid_asm +#undef mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm +#undef mld_keccakf1600_round_constants +/* mldsa/src/fips202/native/aarch64/x1_scalar.h */ +#undef MLD_FIPS202_AARCH64_NEED_X1_SCALAR +#undef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#undef MLD_USE_FIPS202_X1_NATIVE +/* mldsa/src/fips202/native/aarch64/x1_v84a.h */ +#undef MLD_FIPS202_AARCH64_NEED_X1_V84A +#undef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#undef MLD_USE_FIPS202_X1_NATIVE +/* mldsa/src/fips202/native/aarch64/x2_v84a.h */ +#undef MLD_FIPS202_AARCH64_NEED_X2_V84A +#undef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#undef MLD_USE_FIPS202_X4_NATIVE +/* mldsa/src/fips202/native/aarch64/x4_v8a_scalar.h */ +#undef MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID +#undef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#undef MLD_USE_FIPS202_X4_NATIVE +/* mldsa/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h */ +#undef MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID +#undef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#undef MLD_USE_FIPS202_X4_NATIVE +#endif /* MLD_SYS_AARCH64 */ +#if defined(MLD_SYS_X86_64) +/* + * Undefine macros from native code (FIPS202, x86_64) + */ +/* mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h */ +#undef MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H +#undef mld_keccakf1600x4_permute24 +/* mldsa/src/fips202/native/x86_64/xkcp.h */ +#undef MLD_FIPS202_NATIVE_X86_64_XKCP_H +#undef MLD_FIPS202_X86_64_XKCP +#undef MLD_USE_FIPS202_X4_NATIVE +#endif /* MLD_SYS_X86_64 */ +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +/* mldsa/src/native/api.h */ +#undef MLD_INTT_BOUND +#undef MLD_NATIVE_API_H +#undef MLD_NATIVE_FUNC_FALLBACK +#undef MLD_NATIVE_FUNC_SUCCESS +#undef MLD_NTT_BOUND +#undef REDUCE32_RANGE_MAX +/* mldsa/src/native/meta.h */ +#undef MLD_NATIVE_META_H +#if defined(MLD_SYS_AARCH64) +/* + * Undefine macros from native code (Arith, AArch64) + */ +/* mldsa/src/native/aarch64/meta.h */ +#undef MLD_ARITH_BACKEND_AARCH64 +#undef MLD_NATIVE_AARCH64_META_H +#undef MLD_USE_NATIVE_INTT +#undef MLD_USE_NATIVE_NTT +#undef MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_17 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_19 +#undef MLD_USE_NATIVE_POLY_CADDQ +#undef MLD_USE_NATIVE_POLY_CHKNORM +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#undef MLD_USE_NATIVE_POLY_USE_HINT_32 +#undef MLD_USE_NATIVE_POLY_USE_HINT_88 +#undef MLD_USE_NATIVE_REJ_UNIFORM +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +/* mldsa/src/native/aarch64/src/arith_native_aarch64.h */ +#undef MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN +#undef MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN +#undef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#undef mld_aarch64_intt_zetas_layer123456 +#undef mld_aarch64_intt_zetas_layer78 +#undef mld_aarch64_ntt_zetas_layer123456 +#undef mld_aarch64_ntt_zetas_layer78 +#undef mld_intt_asm +#undef mld_ntt_asm +#undef mld_poly_caddq_asm +#undef mld_poly_chknorm_asm +#undef mld_poly_decompose_32_asm +#undef mld_poly_decompose_88_asm +#undef mld_poly_pointwise_montgomery_asm +#undef mld_poly_use_hint_32_asm +#undef mld_poly_use_hint_88_asm +#undef mld_polyvecl_pointwise_acc_montgomery_l4_asm +#undef mld_polyvecl_pointwise_acc_montgomery_l5_asm +#undef mld_polyvecl_pointwise_acc_montgomery_l7_asm +#undef mld_polyz_unpack_17_asm +#undef mld_polyz_unpack_17_indices +#undef mld_polyz_unpack_19_asm +#undef mld_polyz_unpack_19_indices +#undef mld_rej_uniform_asm +#undef mld_rej_uniform_eta2_asm +#undef mld_rej_uniform_eta4_asm +#undef mld_rej_uniform_eta_table +#undef mld_rej_uniform_table +#endif /* MLD_SYS_AARCH64 */ +#if defined(MLD_SYS_X86_64) +/* + * Undefine macros from native code (Arith, X86_64) + */ +/* mldsa/src/native/x86_64/meta.h */ +#undef MLD_ARITH_BACKEND_X86_64_DEFAULT +#undef MLD_NATIVE_X86_64_META_H +#undef MLD_USE_NATIVE_INTT +#undef MLD_USE_NATIVE_NTT +#undef MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#undef MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_17 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_19 +#undef MLD_USE_NATIVE_POLY_CADDQ +#undef MLD_USE_NATIVE_POLY_CHKNORM +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#undef MLD_USE_NATIVE_POLY_USE_HINT_32 +#undef MLD_USE_NATIVE_POLY_USE_HINT_88 +#undef MLD_USE_NATIVE_REJ_UNIFORM +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +/* mldsa/src/native/x86_64/src/arith_native_x86_64.h */ +#undef MLD_AVX2_REJ_UNIFORM_BUFLEN +#undef MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN +#undef MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN +#undef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#undef mld_invntt_avx2 +#undef mld_ntt_avx2 +#undef mld_nttunpack_avx2 +#undef mld_pointwise_acc_l4_avx2 +#undef mld_pointwise_acc_l5_avx2 +#undef mld_pointwise_acc_l7_avx2 +#undef mld_pointwise_avx2 +#undef mld_poly_caddq_avx2 +#undef mld_poly_chknorm_avx2 +#undef mld_poly_decompose_32_avx2 +#undef mld_poly_decompose_88_avx2 +#undef mld_poly_use_hint_32_avx2 +#undef mld_poly_use_hint_88_avx2 +#undef mld_polyz_unpack_17_avx2 +#undef mld_polyz_unpack_19_avx2 +#undef mld_rej_uniform_avx2 +#undef mld_rej_uniform_eta2_avx2 +#undef mld_rej_uniform_eta4_avx2 +#undef mld_rej_uniform_table +/* mldsa/src/native/x86_64/src/consts.h */ +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XQ +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV +#undef MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS +#undef MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV +#undef MLD_NATIVE_X86_64_SRC_CONSTS_H +#undef mld_qdata +#endif /* MLD_SYS_X86_64 */ +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ +#endif /* !MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/mldsa_native.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/mldsa_native.h new file mode 100644 index 0000000000..fd150a9df1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/mldsa_native.h @@ -0,0 +1,975 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_H +#define MLD_H + +/* + * Public API for mldsa-native + * + * This header defines the public API of a single build of mldsa-native. + * + * Make sure the configuration file is in the include path + * (this is "mldsa_native_config.h" by default, or MLD_CONFIG_FILE if defined). + * + * # Multi-level builds + * + * This header specifies a build of mldsa-native for a fixed security level. + * If you need multiple security levels, leave the security level unspecified + * in the configuration file and include this header multiple times, setting + * MLD_CONFIG_PARAMETER_SET accordingly for each, and #undef'ing the MLD_H + * guard to allow multiple inclusions. + * + * # Legacy configuration (deprecated) + * + * Instead of providing the config file used for the build, you can + * alternatively set the following configuration options prior to + * including this header. + * + * This method of configuration is deprecated. + * It will be removed in mldsa-native-v2. + * + * - MLD_CONFIG_API_PARAMETER_SET [required] + * + * The parameter set used for the build; 44, 65, or 87. + * + * - MLD_CONFIG_API_NAMESPACE_PREFIX [required] + * + * The namespace prefix used for the build. + * + * NOTE: + * For a multi-level build, you must include the 44/65/87 suffixes + * in MLD_CONFIG_API_NAMESPACE_PREFIX. + * + * - MLD_CONFIG_API_NO_SUPERCOP [optional] + * + * By default, this header will also expose the mldsa-native API in the + * SUPERCOP naming convention crypto_sign_xxx. If you don't want/need this, + * set MLD_CONFIG_API_NO_SUPERCOP. You must set this for a multi-level build. + * + * - MLD_CONFIG_API_CONSTANTS_ONLY [optional] + * + * If you don't want this header to expose any function declarations, + * but only constants for the sizes of key material, set + * MLD_CONFIG_API_CONSTANTS_ONLY. In this case, you don't need to set + * MLD_CONFIG_API_PARAMETER_SET or MLD_CONFIG_API_NAMESPACE_PREFIX, + * nor include a configuration. + * + * - MLD_CONFIG_API_QUALIFIER [optional] + * + * Qualifier to apply to external API. + * + ******************************************************************************/ + +/******************************* Key sizes ************************************/ + +/* Sizes of cryptographic material, per parameter set */ +/* See mldsa/src/params.h for the arithmetic expressions giving rise to these */ +/* check-magic: off */ +#define MLDSA44_SECRETKEYBYTES 2560 +#define MLDSA44_PUBLICKEYBYTES 1312 +#define MLDSA44_BYTES 2420 + +#define MLDSA65_SECRETKEYBYTES 4032 +#define MLDSA65_PUBLICKEYBYTES 1952 +#define MLDSA65_BYTES 3309 + +#define MLDSA87_SECRETKEYBYTES 4896 +#define MLDSA87_PUBLICKEYBYTES 2592 +#define MLDSA87_BYTES 4627 +/* check-magic: on */ + +/* Size of seed and randomness in bytes (level-independent) */ +#define MLDSA_SEEDBYTES 32 +#define MLDSA44_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA65_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA87_SEEDBYTES MLDSA_SEEDBYTES + +/* Size of CRH output in bytes (level-independent) */ +#define MLDSA_CRHBYTES 64 +#define MLDSA44_CRHBYTES MLDSA_CRHBYTES +#define MLDSA65_CRHBYTES MLDSA_CRHBYTES +#define MLDSA87_CRHBYTES MLDSA_CRHBYTES + +/* Size of TR output in bytes (level-independent) */ +#define MLDSA_TRBYTES 64 +#define MLDSA44_TRBYTES MLDSA_TRBYTES +#define MLDSA65_TRBYTES MLDSA_TRBYTES +#define MLDSA87_TRBYTES MLDSA_TRBYTES + +/* Size of randomness for signing in bytes (level-independent) */ +#define MLDSA_RNDBYTES 32 +#define MLDSA44_RNDBYTES MLDSA_RNDBYTES +#define MLDSA65_RNDBYTES MLDSA_RNDBYTES +#define MLDSA87_RNDBYTES MLDSA_RNDBYTES + +/* Sizes of cryptographic material, as a function of LVL=44,65,87 */ +#define MLDSA_SECRETKEYBYTES_(LVL) MLDSA##LVL##_SECRETKEYBYTES +#define MLDSA_PUBLICKEYBYTES_(LVL) MLDSA##LVL##_PUBLICKEYBYTES +#define MLDSA_BYTES_(LVL) MLDSA##LVL##_BYTES +#define MLDSA_SECRETKEYBYTES(LVL) MLDSA_SECRETKEYBYTES_(LVL) +#define MLDSA_PUBLICKEYBYTES(LVL) MLDSA_PUBLICKEYBYTES_(LVL) +#define MLDSA_BYTES(LVL) MLDSA_BYTES_(LVL) + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + +/****************************** Function API **********************************/ + +#define MLD_API_CONCAT_(x, y) x##y +#define MLD_API_CONCAT(x, y) MLD_API_CONCAT_(x, y) +#define MLD_API_CONCAT_UNDERSCORE(x, y) MLD_API_CONCAT(MLD_API_CONCAT(x, _), y) + +#if !defined(MLD_CONFIG_API_PARAMETER_SET) +/* Recommended configuration via same config file as used for the build. */ + +/* For now, we derive the legacy API configuration MLD_CONFIG_API_XXX from + * the config file. In mldsa-native-v2, this will be removed and we will + * exclusively work with MLD_CONFIG_XXX. */ + +/* You need to make sure the config file is in the include path. */ +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#define MLD_CONFIG_API_PARAMETER_SET MLD_CONFIG_PARAMETER_SET + +#if defined(MLD_CONFIG_MULTILEVEL_BUILD) +#define MLD_CONFIG_API_NAMESPACE_PREFIX \ + MLD_API_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_CONFIG_API_NAMESPACE_PREFIX MLD_CONFIG_NAMESPACE_PREFIX +#endif + +#if defined(MLD_CONFIG_NO_SUPERCOP) +#define MLD_CONFIG_API_NO_SUPERCOP +#endif + +#if defined(MLD_CONFIG_CONSTANTS_ONLY) +#define MLD_CONFIG_API_CONSTANTS_ONLY +#endif + +#if defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_CONFIG_API_QUALIFIER MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#else /* !MLD_CONFIG_API_PARAMETER_SET */ +#define MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_PARAMETER_SET */ + +#define MLD_API_NAMESPACE(sym) \ + MLD_API_CONCAT_UNDERSCORE(MLD_CONFIG_API_NAMESPACE_PREFIX, sym) + +#if defined(__GNUC__) || defined(clang) +#define MLD_API_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_API_MUST_CHECK_RETURN_VALUE +#endif + +#if defined(MLD_CONFIG_API_QUALIFIER) +#define MLD_API_QUALIFIER MLD_CONFIG_API_QUALIFIER +#else +#define MLD_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_API_CONSTANTS_ONLY) + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************************* + * Name: crypto_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: + * input random seed + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair_internal)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t seed[MLDSA_SEEDBYTES] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: If MLD_CONFIG_KEYGEN_PCT is enabled and the + * PCT check failed. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return -1 in that case. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_extmu + * + * Description: Computes signature. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_extmu)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t *sm: pointer to output signed message (allocated array + * with MLDSA{44,65,87}_BYTES + mlen bytes), can be + * equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(sign)( + uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_extmu)( + const uint8_t *sig, size_t siglen, const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_open + * + * Description: Verify signed message. + * + * Arguments: + * - uint8_t *m: pointer to output message (allocated array with + * smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(open)( + uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: crypto_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *ph, size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_shake256)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_shake256)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/* Maximum formatted domain separation message length */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +size_t MLD_API_NAMESPACE(prepare_domain_separation_prefix)( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg); + +/************************************************* + * Name: crypto_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[CRYPTO_SECRETKEYBYTES]: input secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(pk_from_sk)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +#ifdef __cplusplus +} +#endif + +/****************************** SUPERCOP API *********************************/ + +#if !defined(MLD_CONFIG_API_NO_SUPERCOP) +/* Export API in SUPERCOP naming scheme CRYPTO_xxx / crypto_sign_xxx */ +#define CRYPTO_SECRETKEYBYTES MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_PUBLICKEYBYTES MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_BYTES MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET) + +#define crypto_sign_keypair MLD_API_NAMESPACE(keypair) +#define crypto_sign_signature MLD_API_NAMESPACE(signature) +#define crypto_sign MLD_API_NAMESPACE(sign) +#define crypto_sign_verify MLD_API_NAMESPACE(verify) +#define crypto_sign_open MLD_API_NAMESPACE(open) + +#else /* !MLD_CONFIG_API_NO_SUPERCOP */ + +/* If the SUPERCOP API is not needed, we can undefine the various helper macros + * above. Otherwise, they are needed for lazy evaluation of crypto_sign_xxx. */ +#if !defined(MLD_API_LEGACY_CONFIG) +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_QUALIFIER +#endif /* !MLD_API_LEGACY_CONFIG */ + +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_NAMESPACE +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_QUALIFIER +#undef MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_NO_SUPERCOP */ +#endif /* !MLD_CONFIG_API_CONSTANTS_ONLY */ + + +/***************************** Memory Usage **********************************/ + +/* + * By default mldsa-native performs all memory allocations on the stack. + * Alternatively, mldsa-native supports custom allocation of large structures + * through the `MLD_CONFIG_CUSTOM_ALLOC_FREE` configuration option. + * See mldsa_native_config.h for details. + * + * `MLD_TOTAL_ALLOC_{44,65,87}_{KEYPAIR,SIGN,VERIFY}` indicates the maximum + * (accumulative) allocation via MLD_ALLOC for each parameter set and operation. + * Note that some stack allocation remains even + * when using custom allocators, so these values are lower than total stack + * usage with the default stack-only allocation. + * + * These constants may be used to implement custom allocations using a + * fixed-sized buffer and a simple allocator (e.g., bump allocator). + */ +/* check-magic: off */ +#if defined(MLD_API_LEGACY_CONFIG) || !defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 45248 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 56640 +#define MLD_TOTAL_ALLOC_44_SIGN 52896 +#define MLD_TOTAL_ALLOC_44_VERIFY 38816 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 71872 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 85856 +#define MLD_TOTAL_ALLOC_65_SIGN 80576 +#define MLD_TOTAL_ALLOC_65_VERIFY 62432 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 112832 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 130816 +#define MLD_TOTAL_ALLOC_87_SIGN 123584 +#define MLD_TOTAL_ALLOC_87_VERIFY 99552 +#else /* MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM */ +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 32992 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 36192 +#define MLD_TOTAL_ALLOC_44_SIGN 32448 +#define MLD_TOTAL_ALLOC_44_VERIFY 22464 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 46304 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 50048 +#define MLD_TOTAL_ALLOC_65_SIGN 44768 +#define MLD_TOTAL_ALLOC_65_VERIFY 30720 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 62688 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 66336 +#define MLD_TOTAL_ALLOC_87_SIGN 59104 +#define MLD_TOTAL_ALLOC_87_VERIFY 41216 +#endif /* !(MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM) */ +/* check-magic: on */ + +/* + * MLD_TOTAL_ALLOC_*_KEYPAIR adapts based on MLD_CONFIG_KEYGEN_PCT. + * For legacy config, we don't know which options are used, so assume + * the worst case (PCT enabled). + */ +#if defined(MLD_API_LEGACY_CONFIG) || defined(MLD_CONFIG_KEYGEN_PCT) +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#else +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#endif + +#define MLD_MAX3_(a, b, c) \ + ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c))) + +/* + * `MLD_TOTAL_ALLOC_{44,65,87}` is the maximum across all operations for each + * parameter set. + */ +#define MLD_TOTAL_ALLOC_44 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_44_KEYPAIR, MLD_TOTAL_ALLOC_44_SIGN, \ + MLD_TOTAL_ALLOC_44_VERIFY) +#define MLD_TOTAL_ALLOC_65 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_65_KEYPAIR, MLD_TOTAL_ALLOC_65_SIGN, \ + MLD_TOTAL_ALLOC_65_VERIFY) +#define MLD_TOTAL_ALLOC_87 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_87_KEYPAIR, MLD_TOTAL_ALLOC_87_SIGN, \ + MLD_TOTAL_ALLOC_87_VERIFY) + +#endif /* !MLD_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/mldsa_native_config.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/mldsa_native_config.h new file mode 100644 index 0000000000..a8ccf0dc54 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/mldsa_native_config.h @@ -0,0 +1,738 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/* + * Test configuration: Monolithic build config + * + * This configuration differs from the default mldsa/mldsa_native_config.h in + * the following places: + * - MLD_CONFIG_NAMESPACE_PREFIX + * - MLD_CONFIG_INTERNAL_API_QUALIFIER + */ + + +#ifndef MLD_CONFIG_H +#define MLD_CONFIG_H + +/****************************************************************************** + * Name: MLD_CONFIG_PARAMETER_SET + * + * Description: Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * If you want to support multiple parameter sets, build the + * library multiple times and set MLD_CONFIG_MULTILEVEL_BUILD. + * See MLD_CONFIG_MULTILEVEL_BUILD for how to do this while + * minimizing code duplication. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of the default configuration file mldsa/mldsa_native_config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * then configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + * + *****************************************************************************/ +/* No need to set this -- we _are_ already in a custom config */ +/* #define MLD_CONFIG_FILE "mldsa_native_config.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_NAMESPACE_PREFIX + * + * Description: The prefix to use to namespace global symbols from mldsa/. + * + * In a multi-level build, level-dependent symbols will + * additionally be prefixed with the parameter set (44/65/87). + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_NAMESPACE_PREFIX mldsa + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_BUILD + * + * Description: Set this if the build is part of a multi-level build supporting + * multiple parameter sets. + * + * If you need only a single parameter set, keep this unset. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them. + * + * See examples/multilevel_build for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_BUILD */ + +/****************************************************************************** + * Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_EXTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_RANDOMIZED_API + * + * Description: If this option is set, mldsa-native will be built without the + * randomized API functions (crypto_sign_keypair, + * crypto_sign, crypto_sign_signature, and + * crypto_sign_signature_extmu). + * This allows users to build mldsa-native without providing a + * randombytes() implementation if they only need the + * internal deterministic API + * (crypto_sign_keypair_internal, crypto_sign_signature_internal). + * + * NOTE: This option is incompatible with MLD_CONFIG_KEYGEN_PCT + * as the current PCT implementation requires + * crypto_sign_signature(). + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_RANDOMIZED_API */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_SUPERCOP + * + * Description: By default, mldsa_native.h exposes the mldsa-native API in the + * SUPERCOP naming convention (crypto_sign_xxx). If you don't need + * this, set MLD_CONFIG_NO_SUPERCOP. + * + * NOTE: You must set this for a multi-level build as the SUPERCOP + * naming does not disambiguate between the parameter sets. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_SUPERCOP */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONSTANTS_ONLY + * + * Description: If you only need the size constants (MLDSA_PUBLICKEYBYTES, etc.) + * but no function declarations, set MLD_CONFIG_CONSTANTS_ONLY. + * + * This only affects the public header mldsa_native.h, not + * the implementation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONSTANTS_ONLY */ + +/****************************************************************************** + * + * Build-only configuration options + * + * The remaining configurations are build-options only. + * They do not affect the API described in mldsa_native.h. + * + *****************************************************************************/ + +#if defined(MLD_BUILD_INTERNAL) +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_WITH_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, all MLD_CONFIG_PARAMETER_SET-independent + * code will be included in the build, including code needed only + * for other parameter sets. + * + * Example: TODO: add example + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_WITH_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_NO_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, no MLD_CONFIG_PARAMETER_SET-independent code + * will be included in the build. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * + * Description: This is only relevant for single compilation unit (SCU) + * builds of mldsa-native. In this case, it determines whether + * directives defined in parameter-set-independent headers should + * be #undef'ined or not at the of the SCU file. This is needed + * in multilevel builds. + * + * See examples/multilevel_build_native for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * + * Description: Determines whether an native arithmetic backend should be used. + * + * The arithmetic backend covers performance critical functions + * such as the number-theoretic transform (NTT). + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the arithmetic backend to be use is + * determined by MLD_CONFIG_ARITH_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_ARITH_BACKEND_FILE + * + * Description: The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * + * Description: Determines whether an native FIPS202 backend should be used. + * + * The FIPS202 backend covers 1x/2x/4x-fold Keccak-f1600, which is + * the performance bottleneck of SHA3 and SHAKE. + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the FIPS202 backend to be use is + * determined by MLD_CONFIG_FIPS202_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_BACKEND_FILE + * + * Description: The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202X4_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202-X4 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202x4.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ZEROIZE + * + * Description: In compliance with @[FIPS204, Section 3.6.3], mldsa-native, + * zeroizes intermediate stack buffers before returning from + * function calls. + * + * Set this option and define `mld_zeroize` if you want to + * use a custom method to zeroize intermediate stack buffers. + * The default implementation uses SecureZeroMemory on Windows + * and a memset + compiler barrier otherwise. If neither of those + * is available on the target platform, compilation will fail, + * and you will need to use MLD_CONFIG_CUSTOM_ZEROIZE to provide + * a custom implementation of `mld_zeroize()`. + * + * WARNING: + * The explicit stack zeroization conducted by mldsa-native + * reduces the likelihood of data leaking on the stack, but + * does not eliminate it! The C standard makes no guarantee about + * where a compiler allocates structures and whether/where it makes + * copies of them. Also, in addition to entire structures, there + * may also be potentially exploitable leakage of individual values + * on the stack. + * + * If you need bullet-proof zeroization of the stack, you need to + * consider additional measures instead of what this feature + * provides. In this case, you can set mld_zeroize to a + * no-op. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void mld_zeroize(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * Description: mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to provided by the + * consumer. + * + * If this option is not set, mldsa-native expects a function + * int randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mld_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_RANDOMBYTES + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) + { + ... your implementation ... + return 0; + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + * + * Description: mldsa-native backends may rely on specific hardware features. + * Those backends will only be included in an mldsa-native build + * if support for the respective features is enabled at + * compile-time. However, when building for a heteroneous set + * of CPUs to run the resulting binary/library on, feature + * detection at _runtime_ is needed to decided whether a backend + * can be used or not. + * + * Set this option and define `mld_sys_check_capability` if you + * want to use a custom method to dispatch between implementations. + * + * Return value 1 indicates that a capability is supported. + * Return value 0 indicates that a capability is not supported. + * + * If this option is not set, mldsa-native uses compile-time + * feature detection only to decide which backend to use. + * + * If you compile mldsa-native on a system with different + * capabilities than the system that the resulting binary/library + * will be run on, you must use this option. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) + { + ... your implementation ... + } +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ALLOC_FREE [EXPERIMENTAL] + * + * Description: Set this option and define `MLD_CUSTOM_ALLOC` and + * `MLD_CUSTOM_FREE` if you want to use custom allocation for + * large local structures or buffers. + * + * By default, all buffers/structures are allocated on the stack. + * If this option is set, most of them will be allocated via + * MLD_CUSTOM_ALLOC. + * + * Parameters to MLD_CUSTOM_ALLOC: + * - T* v: Target pointer to declare. + * - T: Type of structure to be allocated + * - N: Number of elements to be allocated. + * + * Parameters to MLD_CUSTOM_FREE: + * - T* v: Target pointer to free. May be NULL. + * - T: Type of structure to be freed. + * - N: Number of elements to be freed. + * + * WARNING: This option is experimental! + * Its scope, configuration and function/macro signatures may + * change at any time. We expect a stable API for v2. + * + * NOTE: Even if this option is set, some allocations further down + * the call stack will still be made from the stack. Those will + * likely be added to the scope of this option in the future. + * + * NOTE: MLD_CUSTOM_ALLOC need not guarantee a successful + * allocation nor include error handling. Upon failure, the + * target pointer should simply be set to NULL. The calling + * code will handle this case and invoke MLD_CUSTOM_FREE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ALLOC_FREE + #if !defined(__ASSEMBLER__) + #include + #define MLD_CUSTOM_ALLOC(v, T, N) \ + T* (v) = (T *)aligned_alloc(MLD_DEFAULT_ALIGN, \ + MLD_ALIGN_UP(sizeof(T) * (N))) + #define MLD_CUSTOM_FREE(v, T, N) free(v) + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMCPY + * + * Description: Set this option and define `mld_memcpy` if you want to + * use a custom method to copy memory instead of the standard + * library memcpy function. + * + * The custom implementation must have the same signature and + * behavior as the standard memcpy function: + * void *mld_memcpy(void *dest, const void *src, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMCPY + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMSET + * + * Description: Set this option and define `mld_memset` if you want to + * use a custom method to set memory instead of the standard + * library memset function. + * + * The custom implementation must have the same signature and + * behavior as the standard memset function: + * void *mld_memset(void *s, int c, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMSET + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memset(void *s, int c, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_INTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of internal API. + * + * The primary use case for this option are single-CU builds, + * in which case this option can be set to `static`. + * + *****************************************************************************/ +#define MLD_CONFIG_INTERNAL_API_QUALIFIER static + +/****************************************************************************** + * Name: MLD_CONFIG_CT_TESTING_ENABLED + * + * Description: If set, mldsa-native annotates data as secret / public using + * valgrind's annotations VALGRIND_MAKE_MEM_UNDEFINED and + * VALGRIND_MAKE_MEM_DEFINED, enabling various checks for secret- + * dependent control flow of variable time execution (depending + * on the exact version of valgrind installed). + * + *****************************************************************************/ +/* #define MLD_CONFIG_CT_TESTING_ENABLED */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * and MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT + * + * Description: Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, crypto_sign_keypair_internal and + * crypto_sign_keypair will return a non-zero error code if the + * PCT failed. + * + * NOTE: This feature will drastically lower the performance of + * key generation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * Description: If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "src/src.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Description: Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * NOTE: Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + * + *****************************************************************************/ +/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER + * + * Description: Set this to add a context parameter that is provided to public + * API functions and is then available in custom callbacks. + * + * The type of the context parameter is configured via + * MLD_CONFIG_CONTEXT_PARAMETER_TYPE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER_TYPE + * + * Description: Set this to define the type for the context parameter used by + * MLD_CONFIG_CONTEXT_PARAMETER. + * + * This is only relevant if MLD_CONFIG_CONTEXT_PARAMETER is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER_TYPE void* */ + +/****************************************************************************** + * Name: MLD_CONFIG_REDUCE_RAM [EXPERIMENTAL] + * + * Description: Set this to reduce RAM usage. + * This trades memory for performance. + * + * For expected memory usage, see the MLD_TOTAL_ALLOC_* constants + * defined in mldsa_native.h. + * + * This option is useful for embedded systems with tight RAM + * constraints but relaxed performance requirements. + * + * WARNING: This option is experimental! + * CBMC proofs do not currently cover this configuration option. + * Its scope and configuration may change at any time. + * + *****************************************************************************/ +/* #define MLD_CONFIG_REDUCE_RAM */ + +/************************* Config internals ********************************/ + +#endif /* MLD_BUILD_INTERNAL */ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace is + * + * PQCP_MLDSA_NATIVE_MLDSA_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_ + */ + +#if MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65 +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87 +#endif + +#endif /* !MLD_CONFIG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/cbmc.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/cbmc.h new file mode 100644 index 0000000000..8ed1ecb06b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/cbmc.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_CBMC_H +#define MLD_CBMC_H +/*************************************************** + * Basic replacements for __CPROVER_XXX contracts + ***************************************************/ +#ifndef CBMC + +#define __contract__(x) +#define __loop__(x) +#define cassert(x) + +#else /* !CBMC */ + +#include + +#define __contract__(x) x +#define __loop__(x) x + +/* https://diffblue.github.io/cbmc/contracts-assigns.html */ +#define assigns(...) __CPROVER_assigns(__VA_ARGS__) + +/* https://diffblue.github.io/cbmc/contracts-requires-ensures.html */ +#define requires(...) __CPROVER_requires(__VA_ARGS__) +#define ensures(...) __CPROVER_ensures(__VA_ARGS__) +/* https://diffblue.github.io/cbmc/contracts-loops.html */ +#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__) +#define decreases(...) __CPROVER_decreases(__VA_ARGS__) +/* cassert to avoid confusion with in-built assert */ +#define cassert(x) __CPROVER_assert(x, "cbmc assertion failed") +#define assume(...) __CPROVER_assume(__VA_ARGS__) + +/*************************************************** + * Macros for "expression" forms that may appear + * _inside_ top-level contracts. + ***************************************************/ + +/* + * function return value - useful inside ensures + * https://diffblue.github.io/cbmc/contracts-functions.html + */ +#define return_value (__CPROVER_return_value) + +/* + * assigns l-value targets + * https://diffblue.github.io/cbmc/contracts-assigns.html + */ +#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__) +#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__) +#define same_object(...) __CPROVER_same_object(__VA_ARGS__) + +/* + * Pointer-related predicates + * https://diffblue.github.io/cbmc/contracts-memory-predicates.html + */ +#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__) +#define readable(...) __CPROVER_r_ok(__VA_ARGS__) +#define writeable(...) __CPROVER_w_ok(__VA_ARGS__) + +/* Maximum supported buffer size + * + * Larger buffers may be supported, but due to internal modeling constraints + * in CBMC, the proofs of memory- and type-safety won't be able to run. + * + * If you find yourself in need for a buffer size larger than this, + * please contact the maintainers, so we can prioritize work to relax + * this somewhat artificial bound. + */ +#define MLD_MAX_BUFFER_SIZE (SIZE_MAX >> 12) + + +/* + * History variables + * https://diffblue.github.io/cbmc/contracts-history-variables.html + */ +#define old(...) __CPROVER_old(__VA_ARGS__) +#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__) + +/* + * Quantifiers + * Note that the range on qvar is _exclusive_ between qvar_lb .. qvar_ub + * https://diffblue.github.io/cbmc/contracts-quantifiers.html + */ + +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define forall(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> (predicate) \ + } + +#define exists(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_exists \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) && (predicate) \ + } +/* clang-format on */ + +/*************************************************** + * Convenience macros for common contract patterns + ***************************************************/ +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define CBMC_CONCAT_(left, right) left##right +#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right) + +#define array_bound_core(qvar, qvar_lb, qvar_ub, array_var, \ + value_lb, value_ub) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + (((int)(value_lb) <= ((array_var)[(qvar)])) && \ + (((array_var)[(qvar)]) < (int)(value_ub))) \ + } + +#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \ + array_bound_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (qvar_lb), \ + (qvar_ub), (array_var), (value_lb), (value_ub)) + +#define array_unchanged_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (int32_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged(array_var, N) \ + array_unchanged_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) + +#define array_unchanged_u64_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (uint64_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged_u64(array_var, N) \ + array_unchanged_u64_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) +/* clang-format on */ + +/* Wrapper around array_bound operating on absolute values. + * + * The absolute value bound `k` is exclusive. + * + * Note that since the lower bound in array_bound is inclusive, we have to + * raise it by 1 here. + */ +#define array_abs_bound(arr, lb, ub, k) \ + array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k)) + +#endif /* CBMC */ + +#endif /* !MLD_CBMC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/common.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/common.h new file mode 100644 index 0000000000..4a5bc8109d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/common.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_COMMON_H +#define MLD_COMMON_H + +#define MLD_BUILD_INTERNAL + +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#include "params.h" +#include "sys.h" + +/* Internal and public API have external linkage by default, but + * this can be overwritten by the user, e.g. for single-CU builds. */ +#if !defined(MLD_CONFIG_INTERNAL_API_QUALIFIER) +#define MLD_INTERNAL_API +#else +#define MLD_INTERNAL_API MLD_CONFIG_INTERNAL_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_EXTERNAL_API +#else +#define MLD_EXTERNAL_API MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#if defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) || \ + defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) +#define MLD_MULTILEVEL_BUILD +#endif + +#define MLD_CONCAT_(x1, x2) x1##x2 +#define MLD_CONCAT(x1, x2) MLD_CONCAT_(x1, x2) + +#if defined(MLD_MULTILEVEL_BUILD) +#define MLD_ADD_PARAM_SET(s) MLD_CONCAT(s, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_ADD_PARAM_SET(s) s +#endif + +#define MLD_NAMESPACE_PREFIX MLD_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, _) +#define MLD_NAMESPACE_PREFIX_KL \ + MLD_CONCAT(MLD_ADD_PARAM_SET(MLD_CONFIG_NAMESPACE_PREFIX), _) + +/* Functions are prefixed by MLD_CONFIG_NAMESPACE_PREFIX. + * + * If multiple parameter sets are used, functions depending on the parameter + * set are additionally prefixed with 44/65/87. See mldsa_native_config.h. + * + * Example: If MLD_CONFIG_NAMESPACE_PREFIX is PQCP_MLDSA_NATIVE, then + * MLD_NAMESPACE_KL(keypair) becomes PQCP_MLDSA_NATIVE44_keypair/ + * PQCP_MLDSA_NATIVE65_keypair/PQCP_MLDSA_NATIVE87_keypair. + */ +#define MLD_NAMESPACE(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX, s) +#define MLD_NAMESPACE_KL(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX_KL, s) + +/* On Apple platforms, we need to emit leading underscore + * in front of assembly symbols. We thus introducee a separate + * namespace wrapper for ASM symbols. */ +#if !defined(__APPLE__) +#define MLD_ASM_NAMESPACE(sym) MLD_NAMESPACE(sym) +#else +#define MLD_ASM_NAMESPACE(sym) MLD_CONCAT(_, MLD_NAMESPACE(sym)) +#endif + +/* + * On X86_64 if control-flow protections (CET) are enabled (through + * -fcf-protection=), we add an endbr64 instruction at every global function + * label. See sys.h for more details + */ +#if defined(MLD_SYS_X86_64) +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : MLD_CET_ENDBR +#else +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : +#endif + +/* We aim to simplify the user's life by supporting builds where + * all source files are included, even those that are not needed. + * Those files are appropriately guarded and will be empty when unneeded. + * The following is to avoid compilers complaining about this. */ +#define MLD_EMPTY_CU(s) extern int MLD_NAMESPACE_KL(empty_cu_##s); + +/* MLD_CONFIG_NO_ASM takes precedence over MLD_USE_NATIVE_XXX */ +#if defined(MLD_CONFIG_NO_ASM) +#undef MLD_CONFIG_USE_NATIVE_BACKEND_ARITH +#undef MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, but MLD_CONFIG_ARITH_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, but MLD_CONFIG_FIPS202_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_NO_RANDOMIZED_API) && defined(MLD_CONFIG_KEYGEN_PCT) +#error Bad configuration: MLD_CONFIG_NO_RANDOMIZED_API is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires crypto_sign_signature() +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#include MLD_CONFIG_ARITH_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#include MLD_CONFIG_FIPS202_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "fips202/native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#define MLD_FIPS202_HEADER_FILE "fips202/fips202.h" +#else +#define MLD_FIPS202_HEADER_FILE MLD_CONFIG_FIPS202_CUSTOM_HEADER +#endif + +#if !defined(MLD_CONFIG_FIPS202X4_CUSTOM_HEADER) +#define MLD_FIPS202X4_HEADER_FILE "fips202/fips202x4.h" +#else +#define MLD_FIPS202X4_HEADER_FILE MLD_CONFIG_FIPS202X4_CUSTOM_HEADER +#endif + +/* Standard library function replacements */ +#if !defined(__ASSEMBLER__) +#if !defined(MLD_CONFIG_CUSTOM_MEMCPY) +#include +#define mld_memcpy memcpy +#endif + +#if !defined(MLD_CONFIG_CUSTOM_MEMSET) +#include +#define mld_memset memset +#endif + +/* Allocation macros for large local structures + * + * MLD_ALLOC(v, T, N) declares T *v and attempts to point it to an T[N] + * MLD_FREE(v, T, N) zeroizes and frees the allocation + * + * Default implementation uses stack allocation. + * Can be overridden by setting the config option MLD_CONFIG_CUSTOM_ALLOC_FREE + * and defining MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE. + */ +#if defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) != \ + (defined(MLD_CUSTOM_ALLOC) && defined(MLD_CUSTOM_FREE)) +#error Bad configuration: MLD_CONFIG_CUSTOM_ALLOC_FREE must be set together with MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE +#endif + +/* + * If the integration wants to provide a context parameter for use in + * platform-specific hooks, then it should define this parameter. + * + * The MLD_CONTEXT_PARAMETERS_n macros are intended to be used with macros + * defining the function names and expand to either pass or discard the context + * argument as required by the current build. If there is no context parameter + * requested then these are removed from the prototypes and from all calls. + */ +#ifdef MLD_CONFIG_CONTEXT_PARAMETER +#define MLD_CONTEXT_PARAMETERS_0(context) (context) +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0, context) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1, context) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) \ + (arg0, arg1, arg2, context) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3, context) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4, context) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, context) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, context) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, context) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, context) +#else /* MLD_CONFIG_CONTEXT_PARAMETER */ +#define MLD_CONTEXT_PARAMETERS_0(context) () +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) (arg0, arg1, arg2) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) +#endif /* !MLD_CONFIG_CONTEXT_PARAMETER */ + +#if defined(MLD_CONFIG_CONTEXT_PARAMETER_TYPE) != \ + defined(MLD_CONFIG_CONTEXT_PARAMETER) +#error MLD_CONFIG_CONTEXT_PARAMETER_TYPE must be defined if and only if MLD_CONFIG_CONTEXT_PARAMETER is defined +#endif + +#if !defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) +/* Default: stack allocation */ + +#define MLD_ALLOC(v, T, N, context) \ + MLD_ALIGN T mld_alloc_##v[N]; \ + T *v = mld_alloc_##v + +/* TODO: This leads to a circular dependency between common and ct.h + * It just works out before we're at the end of the file, but it's still + * prone to issues in the future. */ +#include "ct.h" +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + mld_zeroize(mld_alloc_##v, sizeof(mld_alloc_##v)); \ + (v) = NULL; \ + } while (0) + +#else /* !MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* Custom allocation */ + +/* + * The indirection here is necessary to use MLD_CONTEXT_PARAMETERS_3 here. + */ +#define MLD_APPLY(f, args) f args + +#define MLD_ALLOC(v, T, N, context) \ + MLD_APPLY(MLD_CUSTOM_ALLOC, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)) + +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + if (v != NULL) \ + { \ + mld_zeroize(v, sizeof(T) * (N)); \ + MLD_APPLY(MLD_CUSTOM_FREE, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)); \ + v = NULL; \ + } \ + } while (0) + +#endif /* MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* + * We are facing severe CBMC performance issues when using unions. + * As a temporary workaround, we use unions only when MLD_CONFIG_REDUCE_RAM is + * set. + * TODO: Remove the workaround once + * https://github.com/diffblue/cbmc/issues/8813 + * is resolved + */ +#if defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_UNION_OR_STRUCT union +#else +#define MLD_UNION_OR_STRUCT struct +#endif + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_COMMON_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/ct.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/ct.c new file mode 100644 index 0000000000..010b1a52a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/ct.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include "ct.h" + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +/* + * Masking value used in constant-time functions from + * ct.h to block the compiler's range analysis and + * thereby reduce the risk of compiler-introduced branches. + */ +volatile uint64_t mld_ct_opt_blocker_u64 = 0; + +#else /* !MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(ct) + +#endif /* !(!MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/ct.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/ct.h new file mode 100644 index 0000000000..c307456468 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/ct.h @@ -0,0 +1,366 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [libmceliece] + * libmceliece implementation of Classic McEliece + * Bernstein, Chou + * https://lib.mceliece.org/ + * + * - [optblocker] + * PQC forum post on opt-blockers using volatile globals + * Daniel J. Bernstein + * https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ + */ + +#ifndef MLD_CT_H +#define MLD_CT_H + +#include +#include "cbmc.h" +#include "common.h" + +/* Constant-time comparisons and conditional operations + + We reduce the risk for compilation into variable-time code + through the use of 'value barriers'. + + Functionally, a value barrier is a no-op. To the compiler, however, + it constitutes an arbitrary modification of its input, and therefore + harden's value propagation and range analysis. + + We consider two approaches to implement a value barrier: + - An empty inline asm block which marks the target value as clobbered. + - XOR'ing with the value of a volatile global that's set to 0; + see @[optblocker] for a discussion of this idea, and + @[libmceliece, inttypes/crypto_intN.h] for an implementation. + + The first approach is cheap because it only prevents the compiler + from reasoning about the value of the variable past the barrier, + but does not directly generate additional instructions. + + The second approach generates redundant loads and XOR operations + and therefore comes at a higher runtime cost. However, it appears + more robust towards optimization, as compilers should never drop + a volatile load. + + We use the empty-ASM value barrier for GCC and clang, and fall + back to the global volatile barrier otherwise. + + The global value barrier can be forced by setting + MLD_CONFIG_NO_ASM_VALUE_BARRIER. + +*/ + +#if defined(MLD_HAVE_INLINE_ASM) && !defined(MLD_CONFIG_NO_ASM_VALUE_BARRIER) +#define MLD_USE_ASM_VALUE_BARRIER +#endif + + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) +/* + * Declaration of global volatile that the global value barrier + * is loading from and masking with. + */ +#define mld_ct_opt_blocker_u64 MLD_NAMESPACE(ct_opt_blocker_u64) +extern volatile uint64_t mld_ct_opt_blocker_u64; + + +/* Helper functions for obtaining global masks of various sizes */ + +/* This contract is not proved but treated as an axiom. + * + * Its validity relies on the assumption that the global opt-blocker + * constant mld_ct_opt_blocker_u64 is not modified. + */ +static MLD_INLINE uint64_t mld_ct_get_optblocker_u64(void) +__contract__(ensures(return_value == 0)) { return mld_ct_opt_blocker_u64; } + +static MLD_INLINE int64_t mld_ct_get_optblocker_i64(void) +__contract__(ensures(return_value == 0)) { return (int64_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint32_t mld_ct_get_optblocker_u32(void) +__contract__(ensures(return_value == 0)) { return (uint32_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint8_t mld_ct_get_optblocker_u8(void) +__contract__(ensures(return_value == 0)) { return (uint8_t)mld_ct_get_optblocker_u64(); } + +/* Opt-blocker based implementation of value barriers */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_i64()); } + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u32()); } + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u8()); } + + +#else /* !MLD_USE_ASM_VALUE_BARRIER */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} +#endif /* MLD_USE_ASM_VALUE_BARRIER */ + +#ifdef CBMC +#pragma CPROVER check push +#pragma CPROVER check disable "conversion" +#endif + +/************************************************* + * Name: mld_cast_uint32_to_int32 + * + * Description: Cast uint32 value to int32 + * + * Returns: For uint32_t x, the unique y in int32_t + * so that x == y mod 2^32. + * + * Concretely: + * - x < 2^31: returns x + * - x >= 2^31: returns x - 2^31 + * + **************************************************/ +static MLD_ALWAYS_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x) +{ + /* + * PORTABILITY: This relies on uint32_t -> int32_t + * being implemented as the inverse of int32_t -> uint32_t, + * which is implementation-defined (C99 6.3.1.3 (3)) + * CBMC (correctly) fails to prove this conversion is OK, + * so we have to suppress that check here + */ + return (int32_t)x; +} + +#ifdef CBMC +#pragma CPROVER check pop +#endif + + +/************************************************* + * Name: mld_cast_int64_to_uint32 + * + * Description: Cast int64 value to uint32 as per C standard. + * + * Returns: For int64_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int64_to_uint32(int64_t x) +{ + return (uint32_t)(x & (int64_t)UINT32_MAX); +} + +/************************************************* + * Name: mld_cast_int32_to_uint32 + * + * Description: Cast int32 value to uint32 as per C standard. + * + * Returns: For int32_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int32_to_uint32(int32_t x) +{ + return mld_cast_int64_to_uint32((int64_t)x); +} + +/************************************************* + * Name: mld_ct_sel_int32 + * + * Description: Functionally equivalent to cond ? a : b, + * but implemented with guards against + * compiler-introduced branches. + * + * Arguments: int32_t a: First alternative + * int32_t b: Second alternative + * uint32_t cond: Condition variable. + * + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_sel_int32(int32_t a, int32_t b, uint32_t cond) +__contract__( + requires(cond == 0x0 || cond == 0xFFFFFFFF) + ensures(return_value == (cond ? a : b)) +) +{ + uint32_t au = mld_cast_int32_to_uint32(a); + uint32_t bu = mld_cast_int32_to_uint32(b); + uint32_t res = bu ^ (mld_value_barrier_u32(cond) & (au ^ bu)); + return mld_cast_uint32_to_int32(res); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u32 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_nonzero_u32(uint32_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFFFFFFFF))) +{ + int64_t tmp = mld_value_barrier_i64(-((int64_t)x)); + tmp >>= 32; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u8 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint8_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint8_t mld_ct_cmask_nonzero_u8(uint8_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFF))) +{ + uint32_t mask = mld_ct_cmask_nonzero_u32((uint32_t)x); + return (uint8_t)(mask & 0xFF); +} + +/************************************************* + * Name: mld_ct_cmask_neg_i32 + * + * Description: Return 0 if input is non-negative, and -1 otherwise. + * + * Arguments: int32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_neg_i32(int32_t x) +__contract__( + ensures(return_value == ((x < 0) ? 0xFFFFFFFF : 0)) +) +{ + int64_t tmp = mld_value_barrier_i64((int64_t)x); + tmp >>= 31; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_abs_i32 + * + * Description: Return -x if x<0, x otherwise + * + * Arguments: int32_t x: Input value + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_abs_i32(int32_t x) +__contract__( + requires(x >= -INT32_MAX) + ensures(return_value == ((x < 0) ? -x : x)) +) +{ + return mld_ct_sel_int32(-x, x, mld_ct_cmask_neg_i32(x)); +} + +/************************************************* + * Name: mld_ct_memcmp + * + * Description: Compare two arrays for equality in constant time. + * + * Arguments: const uint8_t *a: pointer to first byte array + * const uint8_t *b: pointer to second byte array + * size_t len: length of the byte arrays, upper-bounded + * to UINT16_MAX to control proof complexity + * only. + * + * Returns 0 if the byte arrays are equal, 0xFF otherwise. + **************************************************/ +static MLD_INLINE uint8_t mld_ct_memcmp(const uint8_t *a, const uint8_t *b, + const size_t len) +__contract__( + requires(len <= UINT16_MAX) + requires(memory_no_alias(a, len)) + requires(memory_no_alias(b, len)) + ensures((return_value == 0) || (return_value == 0xFF)) + ensures((return_value == 0) == forall(i, 0, len, (a[i] == b[i])))) +{ + uint8_t r = 0, s = 0; + unsigned i; + + for (i = 0; i < len; i++) + __loop__( + invariant(i <= len) + invariant((r == 0) == (forall(k, 0, i, (a[k] == b[k]))))) + { + r |= a[i] ^ b[i]; + /* s is useless, but prevents the loop from being aborted once r=0xff. */ + s ^= a[i] ^ b[i]; + } + + /* + * - Convert r into a mask; this may not be necessary, but is an additional + * safeguard + * towards leaking information about a and b. + * - XOR twice with s, separated by a value barrier, to prevent the compile + * from dropping the s computation in the loop. + */ + return (mld_value_barrier_u8(mld_ct_cmask_nonzero_u8(r) ^ s) ^ s); +} + +/************************************************* + * Name: mld_zeroize + * + * Description: Force-zeroize a buffer. + * @[FIPS204, Section 3.6.3] Destruction of intermediate + * values. + * + * Arguments: void *ptr: pointer to buffer to be zeroed + * size_t len: Amount of bytes to be zeroed + **************************************************/ +#if !defined(MLD_CONFIG_CUSTOM_ZEROIZE) +#if defined(MLD_SYS_WINDOWS) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) { SecureZeroMemory(ptr, len); } +#elif defined(MLD_HAVE_INLINE_ASM) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) +{ + memset(ptr, 0, len); + /* This follows OpenSSL and seems sufficient to prevent the compiler + * from optimizing away the memset. + * + * If there was a reliable way to detect availability of memset_s(), + * that would be preferred. */ + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +} +#else /* !MLD_SYS_WINDOWS && MLD_HAVE_INLINE_ASM */ +#error No plausibly-secure implementation of mld_zeroize available. Please provide your own using MLD_CONFIG_CUSTOM_ZEROIZE. +#endif /* !MLD_SYS_WINDOWS && !MLD_HAVE_INLINE_ASM */ +#endif /* !MLD_CONFIG_CUSTOM_ZEROIZE */ + +#endif /* !MLD_CT_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/debug.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/debug.c new file mode 100644 index 0000000000..a55d51e8b1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/debug.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* NOTE: You can remove this file unless you compile with MLDSA_DEBUG. */ + +#include "common.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#if defined(MLDSA_DEBUG) + +#include +#include +#include +#include "debug.h" + +#define MLD_DEBUG_ERROR_HEADER "[ERROR:%s:%04d] " + +void mld_debug_check_assert(const char *file, int line, const int val) +{ + if (val == 0) + { + fprintf(stderr, MLD_DEBUG_ERROR_HEADER "Assertion failed (value %d)\n", + file, line, val); + exit(1); + } +} + +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive) +{ + int err = 0; + unsigned i; + for (i = 0; i < len; i++) + { + int32_t val = ptr[i]; + if (!(val > lower_bound_exclusive && val < upper_bound_exclusive)) + { + fprintf(stderr, + MLD_DEBUG_ERROR_HEADER + "Bounds assertion failed: Index %u, value %d out of bounds " + "(%" PRId64 ",%" PRId64 ")\n", + file, line, i, (int)val, lower_bound_exclusive, + upper_bound_exclusive); + err = 1; + } + } + + if (err == 1) + { + exit(1); + } +} + +#else /* MLDSA_DEBUG */ + +MLD_EMPTY_CU(debug) + +#endif /* !MLDSA_DEBUG */ + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(debug) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_DEBUG_ERROR_HEADER diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/debug.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/debug.h new file mode 100644 index 0000000000..af187bb9de --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/debug.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_DEBUG_H +#define MLD_DEBUG_H +#include "common.h" + +#if defined(MLDSA_DEBUG) +#include + +/************************************************* + * Name: mld_assert + * + * Description: Check debug assertion + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - val: Value asserted to be non-zero + **************************************************/ +#define mld_debug_check_assert MLD_NAMESPACE(mldsa_debug_assert) +void mld_debug_check_assert(const char *file, int line, const int val); + +/************************************************* + * Name: mld_debug_check_bounds + * + * Description: Check whether values in an array of int32_t + * are within specified bounds. + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - ptr: Base of array to be checked + * - len: Number of int32_t in ptr + * - lower_bound_exclusive: Exclusive lower bound + * - upper_bound_exclusive: Exclusive upper bound + **************************************************/ +#define mld_debug_check_bounds MLD_NAMESPACE(mldsa_debug_check_bounds) +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive); + +/* Check assertion, calling exit() upon failure + * + * val: Value that's asserted to be non-zero + */ +#define mld_assert(val) mld_debug_check_assert(__FILE__, __LINE__, (val)) + +/* Check bounds in array of int32_t's + * ptr: Base of int32_t array; will be explicitly cast to int32_t*, + * so you may pass a byte-compatible type such as mld_poly or mld_polyvec. + * len: Number of int32_t in array + * value_lb: Inclusive lower value bound + * value_ub: Exclusive upper value bound */ +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + mld_debug_check_bounds(__FILE__, __LINE__, (const int32_t *)(ptr), (len), \ + ((int64_t)(value_lb)) - 1, (value_ub)) + +/* Check absolute bounds in array of int32_t's + * ptr: Base of array, expression of type int32_t* + * len: Number of int32_t in array + * value_abs_bd: Exclusive absolute upper bound */ +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + mld_assert_bound((ptr), (len), (-((int64_t)(value_abs_bd)) + 1), \ + (value_abs_bd)) + +/* Version of bounds assertions for 2-dimensional arrays */ +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + mld_assert_bound((ptr), ((len0) * (len1)), (value_lb), (value_ub)) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + mld_assert_abs_bound((ptr), ((len0) * (len1)), (value_abs_bd)) + +/* When running CBMC, convert debug assertions into proof obligations */ +#elif defined(CBMC) +#include "cbmc.h" + +#define mld_assert(val) cassert(val) + +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + cassert(array_bound(((int32_t *)(ptr)), 0, (len), (value_lb), (value_ub))) + +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + cassert(array_abs_bound(((int32_t *)(ptr)), 0, (len), (value_abs_bd))) + +/* Because of https://github.com/diffblue/cbmc/issues/8570, we can't + * just use a single flattened array_bound(...) here. */ +#define mld_assert_bound_2d(ptr, M, N, value_lb, value_ub) \ + cassert(forall(kN, 0, (M), \ + array_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_lb), (value_ub)))) + +#define mld_assert_abs_bound_2d(ptr, M, N, value_abs_bd) \ + cassert(forall(kN, 0, (M), \ + array_abs_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_abs_bd)))) + +#else /* !MLDSA_DEBUG && CBMC */ + +#define mld_assert(val) \ + do \ + { \ + } while (0) +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + do \ + { \ + } while (0) +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + do \ + { \ + } while (0) + +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + do \ + { \ + } while (0) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + do \ + { \ + } while (0) + + +#endif /* !MLDSA_DEBUG && !CBMC */ +#endif /* !MLD_DEBUG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/fips202.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/fips202.c new file mode 100644 index 0000000000..1112de061c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/fips202.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "../common.h" +#include "../ct.h" +#include "fips202.h" +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +/************************************************* + * Name: keccak_init + * + * Description: Initializes the Keccak state. + * + * Arguments: - uint64_t *s: pointer to Keccak state + **************************************************/ +static void keccak_init(uint64_t s[MLD_KECCAK_LANES]) +__contract__( + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + mld_memset(s, 0, sizeof(uint64_t) * MLD_KECCAK_LANES); +} + +/************************************************* + * Name: keccak_absorb + * + * Description: Absorb step of Keccak; incremental. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_absorb(uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r, + const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(pos <= r) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(in, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + ensures(return_value < r)) +{ + while (inlen >= r - pos) + __loop__( + assigns(pos, in, inlen, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + invariant(inlen <= loop_entry(inlen)) + invariant(pos <= r) + invariant(in == loop_entry(in) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600_xor_bytes(s, in, pos, r - pos); + inlen -= r - pos; + in += r - pos; + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: At this point, inlen < r, so the truncation to unsigned is safe. */ + mld_keccakf1600_xor_bytes(s, in, pos, (unsigned)inlen); + + /* Safety: At this point, inlen < r and pos <= r so the truncation to unsigned + * is safe. */ + return (unsigned)(pos + inlen); +} + +/************************************************* + * Name: keccak_finalize + * + * Description: Finalize absorb step. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - uint8_t p: domain separation byte + **************************************************/ +static void keccak_finalize(uint64_t s[MLD_KECCAK_LANES], unsigned int pos, + unsigned int r, uint8_t p) +__contract__( + requires(pos <= r && r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires((r / 8) >= 1) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + uint8_t b = 0x80; + mld_keccakf1600_xor_bytes(s, &p, pos, 1); + mld_keccakf1600_xor_bytes(s, &b, r - 1, 1); +} + +/************************************************* + * Name: keccak_squeeze + * + * Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes. + * Modifies the state. Can be called multiple times to keep + * squeezing, i.e., is incremental. + * + * Arguments: - uint8_t *out: pointer to output data + * - size_t outlen: number of bytes to be squeezed (written to out) + * - uint64_t *s: pointer to input/output Keccak state + * - unsigned int pos: number of bytes in current block already + *squeezed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_squeeze(uint8_t *out, size_t outlen, + uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r) +__contract__( + requires((r == SHAKE128_RATE && pos <= SHAKE128_RATE) || + (r == SHAKE256_RATE && pos <= SHAKE256_RATE) || + (r == SHA3_512_RATE && pos <= SHA3_512_RATE)) + requires(outlen <= 8 * r /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(out, outlen)) + ensures(return_value <= r)) +{ + unsigned int i; + size_t out_offset = 0; + + /* Reference: This code is re-factored from the reference implementation + * to facilitate proof with CBMC and to improve readability. + * + * Take a mutable copy of outlen to count down the number of bytes + * still to squeeze. The initial value of outlen is needed for the CBMC + * assigns() clauses. */ + size_t bytes_to_go = outlen; + + while (bytes_to_go > 0) + __loop__( + assigns(i, bytes_to_go, pos, out_offset, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES), memory_slice(out, outlen)) + invariant(bytes_to_go <= outlen) + invariant(out_offset == outlen - bytes_to_go) + invariant(pos <= r) + ) + { + if (pos == r) + { + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: If bytes_to_go < r - pos, truncation to unsigned is safe. */ + i = bytes_to_go < r - pos ? (unsigned)bytes_to_go : r - pos; + mld_keccakf1600_extract_bytes(s, out + out_offset, pos, i); + bytes_to_go -= i; + pos += i; + out_offset += i; + } + + return pos; +} + +void mld_shake128_init(mld_shake128ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE128_RATE, in, inlen); +} + +void mld_shake128_finalize(mld_shake128ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE128_RATE, 0x1F); + state->pos = SHAKE128_RATE; +} + +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE128_RATE); +} + +void mld_shake128_release(mld_shake128ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128ctx)); +} + +void mld_shake256_init(mld_shake256ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); +} + +void mld_shake256_finalize(mld_shake256ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); + state->pos = SHAKE256_RATE; +} + +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); +} + +void mld_shake256_release(mld_shake256ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256ctx)); +} + +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +{ + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, in, inlen); + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/fips202.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/fips202.h new file mode 100644 index 0000000000..9f0253cb88 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/fips202.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202_H +#define MLD_FIPS202_FIPS202_H + +#include +#include +#include "../cbmc.h" +#include "../common.h" + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 +#define SHA3_256_RATE 136 +#define SHA3_512_RATE 72 +#define MLD_KECCAK_LANES 25 +#define SHA3_256_HASHBYTES 32 +#define SHA3_512_HASHBYTES 64 + + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake128ctx; + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake256ctx; + +#define mld_shake128_init MLD_NAMESPACE(shake128_init) +/************************************************* + * Name: mld_shake128_init + * + * Description: Initializes state for use as SHAKE128 XOF + * + * Arguments: - mld_shake128ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake128_init(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos == 0) +); + +#define mld_shake128_absorb MLD_NAMESPACE(shake128_absorb) +/************************************************* + * Name: mld_shake128_absorb + * + * Description: Absorb step of the SHAKE128 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake128ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_finalize MLD_NAMESPACE(shake128_finalize) +/************************************************* + * Name: mld_shake128_finalize + * + * Description: Concludes the absorb phase of the SHAKE128 XOF. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_finalize(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_squeeze MLD_NAMESPACE(shake128_squeeze) +/************************************************* + * Name: mld_shake128_squeeze + * + * Description: Squeeze step of SHAKE128 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake128ctx *s: pointer to input/output state + **************************************************/ +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE128_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_release MLD_NAMESPACE(shake128_release) +/************************************************* + * Name: mld_shake128_release + * + * Description: Release and securely zero the SHAKE128 state. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_release(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) +); + +#define mld_shake256_init MLD_NAMESPACE(shake256_init) +/************************************************* + * Name: mld_shake256_init + * + * Description: Initializes state for use as SHAKE256 XOF + * + * Arguments: - mld_shake256ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake256_init(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos == 0) +); + +#define mld_shake256_absorb MLD_NAMESPACE(shake256_absorb) +/************************************************* + * Name: mld_shake256_absorb + * + * Description: Absorb step of the SHAKE256 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake256ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_finalize MLD_NAMESPACE(shake256_finalize) +/************************************************* + * Name: mld_shake256_finalize + * + * Description: Concludes the absorb phase of the SHAKE256 XOF. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_finalize(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_squeeze MLD_NAMESPACE(shake256_squeeze) +/************************************************* + * Name: mld_shake256_squeeze + * + * Description: Squeeze step of SHAKE256 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake256ctx *s: pointer to input/output state + **************************************************/ +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_release MLD_NAMESPACE(shake256_release) +/************************************************* + * Name: mld_shake256_release + * + * Description: Release and securely zero the SHAKE256 state. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_release(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) +); + +#define mld_shake256 MLD_NAMESPACE(shake256) +/************************************************* + * Name: mld_shake256 + * + * Description: SHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +); + +#endif /* !MLD_FIPS202_FIPS202_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/fips202x4.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/fips202x4.c new file mode 100644 index 0000000000..0fb5cd57c7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/fips202x4.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include "../common.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "../ct.h" +#include "fips202.h" +#include "fips202x4.h" +#include "keccakf1600.h" + +static void mld_keccak_absorb_once_x4(uint64_t *s, uint32_t r, + const uint8_t *in0, const uint8_t *in1, + const uint8_t *in2, const uint8_t *in3, + size_t inlen, uint8_t p) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))) +{ + while (inlen >= r) + __loop__( + assigns(inlen, in0, in1, in2, in3, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + invariant(inlen <= loop_entry(inlen)) + invariant(in0 == loop_entry(in0) + (loop_entry(inlen) - inlen)) + invariant(in1 == loop_entry(in1) + (loop_entry(inlen) - inlen)) + invariant(in2 == loop_entry(in2) + (loop_entry(inlen) - inlen)) + invariant(in3 == loop_entry(in3) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, r); + mld_keccakf1600x4_permute(s); + + in0 += r; + in1 += r; + in2 += r; + in3 += r; + inlen -= r; + } + + /* Safety: At this point, inlen < r, so the truncations to unsigned are safe + * below. */ + if (inlen > 0) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, (unsigned)inlen); + } + + if (inlen == r - 1) + { + p |= 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + } + else + { + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + p = 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, r - 1, 1); + } +} + +static void mld_keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1, + uint8_t *out2, uint8_t *out3, + size_t nblocks, uint64_t *s, uint32_t r) +__contract__( + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(out0, nblocks * r)) + requires(memory_no_alias(out1, nblocks * r)) + requires(memory_no_alias(out2, nblocks * r)) + requires(memory_no_alias(out3, nblocks * r)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(out0, nblocks * r)) + assigns(memory_slice(out1, nblocks * r)) + assigns(memory_slice(out2, nblocks * r)) + assigns(memory_slice(out3, nblocks * r))) +{ + while (nblocks > 0) + __loop__( + assigns(out0, out1, out2, out3, nblocks, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY), + memory_slice(out0, nblocks * r), + memory_slice(out1, nblocks * r), + memory_slice(out2, nblocks * r), + memory_slice(out3, nblocks * r)) + invariant(nblocks <= loop_entry(nblocks) && + out0 == loop_entry(out0) + r * (loop_entry(nblocks) - nblocks) && + out1 == loop_entry(out1) + r * (loop_entry(nblocks) - nblocks) && + out2 == loop_entry(out2) + r * (loop_entry(nblocks) - nblocks) && + out3 == loop_entry(out3) + r * (loop_entry(nblocks) - nblocks))) + { + mld_keccakf1600x4_permute(s); + mld_keccakf1600x4_extract_bytes(s, out0, out1, out2, out3, 0, r); + + out0 += r; + out1 += r; + out2 += r; + out3 += r; + nblocks--; + } +} + +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake128x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE128_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE128_RATE); +} + +void mld_shake128x4_init(mld_shake128x4ctx *state) { (void)state; } +void mld_shake128x4_release(mld_shake128x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128x4ctx)); +} + + +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake256x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE256_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE256_RATE); +} + +void mld_shake256x4_init(mld_shake256x4ctx *state) { (void)state; } +void mld_shake256x4_release(mld_shake256x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256x4ctx)); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/fips202x4.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/fips202x4.h new file mode 100644 index 0000000000..e7987207a6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/fips202x4.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202X4_H +#define MLD_FIPS202_FIPS202X4_H + +#include +#include + +#include "../cbmc.h" +#include "../common.h" + +#include "fips202.h" +#include "keccakf1600.h" + +/* Context for non-incremental API */ +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake128x4ctx; + +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake256x4ctx; + +#define mld_shake128x4_absorb_once MLD_NAMESPACE(shake128x4_absorb_once) +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_squeezeblocks MLD_NAMESPACE(shake128x4_squeezeblocks) +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE128_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE128_RATE), + memory_slice(out1, nblocks * SHAKE128_RATE), + memory_slice(out2, nblocks * SHAKE128_RATE), + memory_slice(out3, nblocks * SHAKE128_RATE), + memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_init MLD_NAMESPACE(shake128x4_init) +void mld_shake128x4_init(mld_shake128x4ctx *state); + +#define mld_shake128x4_release MLD_NAMESPACE(shake128x4_release) +void mld_shake128x4_release(mld_shake128x4ctx *state); + + +#define mld_shake256x4_absorb_once MLD_NAMESPACE(shake256x4_absorb_once) +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_squeezeblocks MLD_NAMESPACE(shake256x4_squeezeblocks) +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE256_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE256_RATE), + memory_slice(out1, nblocks * SHAKE256_RATE), + memory_slice(out2, nblocks * SHAKE256_RATE), + memory_slice(out3, nblocks * SHAKE256_RATE), + memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_init MLD_NAMESPACE(shake256x4_init) +void mld_shake256x4_init(mld_shake256x4ctx *state); + +#define mld_shake256x4_release MLD_NAMESPACE(shake256x4_release) +void mld_shake256x4_release(mld_shake256x4ctx *state); + + +#endif /* !MLD_FIPS202_FIPS202X4_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/keccakf1600.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/keccakf1600.c new file mode 100644 index 0000000000..e59120c07c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/keccakf1600.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#define MLD_KECCAK_NROUNDS 24 +#define MLD_KECCAK_ROL(a, offset) ((a << offset) ^ (a >> (64 - offset))) + +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = state_ptr[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = (state[(offset + i) >> 3] >> (8 * ((offset + i) & 0x07))) & 0xFF; + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state_ptr[i] ^= data[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state[(offset + i) >> 3] ^= (uint64_t)data[i] + << (8 * ((offset + i) & 0x07)); + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X4_NATIVE) + if (mld_keccak_f1600_x4_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 0); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 1); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 2); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 3); +} + +static const uint64_t mld_KeccakF_RoundConstants[MLD_KECCAK_NROUNDS] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +static void mld_keccakf1600_permute_c(uint64_t *state) +{ + unsigned round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + uint64_t BCa, BCe, BCi, BCo, BCu; + uint64_t Da, De, Di, Do, Du; + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + /* copyFromState(A, state) */ + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < MLD_KECCAK_NROUNDS; round += 2) + __loop__(invariant(round <= MLD_KECCAK_NROUNDS && round % 2 == 0)) + { + /* prepareTheta */ + BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; + BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + /* thetaRhoPiChiIotaPrepareTheta(round, A, E) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = MLD_KECCAK_ROL(Age, 44); + Aki ^= Di; + BCi = MLD_KECCAK_ROL(Aki, 43); + Amo ^= Do; + BCo = MLD_KECCAK_ROL(Amo, 21); + Asu ^= Du; + BCu = MLD_KECCAK_ROL(Asu, 14); + Eba = BCa ^ ((~BCe) & BCi); + Eba ^= (uint64_t)mld_KeccakF_RoundConstants[round]; + Ebe = BCe ^ ((~BCi) & BCo); + Ebi = BCi ^ ((~BCo) & BCu); + Ebo = BCo ^ ((~BCu) & BCa); + Ebu = BCu ^ ((~BCa) & BCe); + + Abo ^= Do; + BCa = MLD_KECCAK_ROL(Abo, 28); + Agu ^= Du; + BCe = MLD_KECCAK_ROL(Agu, 20); + Aka ^= Da; + BCi = MLD_KECCAK_ROL(Aka, 3); + Ame ^= De; + BCo = MLD_KECCAK_ROL(Ame, 45); + Asi ^= Di; + BCu = MLD_KECCAK_ROL(Asi, 61); + Ega = BCa ^ ((~BCe) & BCi); + Ege = BCe ^ ((~BCi) & BCo); + Egi = BCi ^ ((~BCo) & BCu); + Ego = BCo ^ ((~BCu) & BCa); + Egu = BCu ^ ((~BCa) & BCe); + + Abe ^= De; + BCa = MLD_KECCAK_ROL(Abe, 1); + Agi ^= Di; + BCe = MLD_KECCAK_ROL(Agi, 6); + Ako ^= Do; + BCi = MLD_KECCAK_ROL(Ako, 25); + Amu ^= Du; + BCo = MLD_KECCAK_ROL(Amu, 8); + Asa ^= Da; + BCu = MLD_KECCAK_ROL(Asa, 18); + Eka = BCa ^ ((~BCe) & BCi); + Eke = BCe ^ ((~BCi) & BCo); + Eki = BCi ^ ((~BCo) & BCu); + Eko = BCo ^ ((~BCu) & BCa); + Eku = BCu ^ ((~BCa) & BCe); + + Abu ^= Du; + BCa = MLD_KECCAK_ROL(Abu, 27); + Aga ^= Da; + BCe = MLD_KECCAK_ROL(Aga, 36); + Ake ^= De; + BCi = MLD_KECCAK_ROL(Ake, 10); + Ami ^= Di; + BCo = MLD_KECCAK_ROL(Ami, 15); + Aso ^= Do; + BCu = MLD_KECCAK_ROL(Aso, 56); + Ema = BCa ^ ((~BCe) & BCi); + Eme = BCe ^ ((~BCi) & BCo); + Emi = BCi ^ ((~BCo) & BCu); + Emo = BCo ^ ((~BCu) & BCa); + Emu = BCu ^ ((~BCa) & BCe); + + Abi ^= Di; + BCa = MLD_KECCAK_ROL(Abi, 62); + Ago ^= Do; + BCe = MLD_KECCAK_ROL(Ago, 55); + Aku ^= Du; + BCi = MLD_KECCAK_ROL(Aku, 39); + Ama ^= Da; + BCo = MLD_KECCAK_ROL(Ama, 41); + Ase ^= De; + BCu = MLD_KECCAK_ROL(Ase, 2); + Esa = BCa ^ ((~BCe) & BCi); + Ese = BCe ^ ((~BCi) & BCo); + Esi = BCi ^ ((~BCo) & BCu); + Eso = BCo ^ ((~BCu) & BCa); + Esu = BCu ^ ((~BCa) & BCe); + + /* prepareTheta */ + BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + /* thetaRhoPiChiIotaPrepareTheta(round+1, E, A) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = MLD_KECCAK_ROL(Ege, 44); + Eki ^= Di; + BCi = MLD_KECCAK_ROL(Eki, 43); + Emo ^= Do; + BCo = MLD_KECCAK_ROL(Emo, 21); + Esu ^= Du; + BCu = MLD_KECCAK_ROL(Esu, 14); + Aba = BCa ^ ((~BCe) & BCi); + Aba ^= (uint64_t)mld_KeccakF_RoundConstants[round + 1]; + Abe = BCe ^ ((~BCi) & BCo); + Abi = BCi ^ ((~BCo) & BCu); + Abo = BCo ^ ((~BCu) & BCa); + Abu = BCu ^ ((~BCa) & BCe); + + Ebo ^= Do; + BCa = MLD_KECCAK_ROL(Ebo, 28); + Egu ^= Du; + BCe = MLD_KECCAK_ROL(Egu, 20); + Eka ^= Da; + BCi = MLD_KECCAK_ROL(Eka, 3); + Eme ^= De; + BCo = MLD_KECCAK_ROL(Eme, 45); + Esi ^= Di; + BCu = MLD_KECCAK_ROL(Esi, 61); + Aga = BCa ^ ((~BCe) & BCi); + Age = BCe ^ ((~BCi) & BCo); + Agi = BCi ^ ((~BCo) & BCu); + Ago = BCo ^ ((~BCu) & BCa); + Agu = BCu ^ ((~BCa) & BCe); + + Ebe ^= De; + BCa = MLD_KECCAK_ROL(Ebe, 1); + Egi ^= Di; + BCe = MLD_KECCAK_ROL(Egi, 6); + Eko ^= Do; + BCi = MLD_KECCAK_ROL(Eko, 25); + Emu ^= Du; + BCo = MLD_KECCAK_ROL(Emu, 8); + Esa ^= Da; + BCu = MLD_KECCAK_ROL(Esa, 18); + Aka = BCa ^ ((~BCe) & BCi); + Ake = BCe ^ ((~BCi) & BCo); + Aki = BCi ^ ((~BCo) & BCu); + Ako = BCo ^ ((~BCu) & BCa); + Aku = BCu ^ ((~BCa) & BCe); + + Ebu ^= Du; + BCa = MLD_KECCAK_ROL(Ebu, 27); + Ega ^= Da; + BCe = MLD_KECCAK_ROL(Ega, 36); + Eke ^= De; + BCi = MLD_KECCAK_ROL(Eke, 10); + Emi ^= Di; + BCo = MLD_KECCAK_ROL(Emi, 15); + Eso ^= Do; + BCu = MLD_KECCAK_ROL(Eso, 56); + Ama = BCa ^ ((~BCe) & BCi); + Ame = BCe ^ ((~BCi) & BCo); + Ami = BCi ^ ((~BCo) & BCu); + Amo = BCo ^ ((~BCu) & BCa); + Amu = BCu ^ ((~BCa) & BCe); + + Ebi ^= Di; + BCa = MLD_KECCAK_ROL(Ebi, 62); + Ego ^= Do; + BCe = MLD_KECCAK_ROL(Ego, 55); + Eku ^= Du; + BCi = MLD_KECCAK_ROL(Eku, 39); + Ema ^= Da; + BCo = MLD_KECCAK_ROL(Ema, 41); + Ese ^= De; + BCu = MLD_KECCAK_ROL(Ese, 2); + Asa = BCa ^ ((~BCe) & BCi); + Ase = BCe ^ ((~BCi) & BCo); + Asi = BCi ^ ((~BCo) & BCu); + Aso = BCo ^ ((~BCu) & BCa); + Asu = BCu ^ ((~BCa) & BCe); + } + + /* copyToState(state, A) */ + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} + +void mld_keccakf1600_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X1_NATIVE) + if (mld_keccak_f1600_x1_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X1_NATIVE */ + mld_keccakf1600_permute_c(state); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(keccakf1600) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_KECCAK_NROUNDS +#undef MLD_KECCAK_ROL diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/keccakf1600.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/keccakf1600.h new file mode 100644 index 0000000000..e56adc1561 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/keccakf1600.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_KECCAKF1600_H +#define MLD_FIPS202_KECCAKF1600_H +#include +#include "../cbmc.h" +#include "../common.h" +#include "fips202.h" + +#define MLD_KECCAK_LANES 25 +#define MLD_KECCAK_WAY 4 + +/* + * WARNING: + * The contents of this structure, including the placement + * and interleaving of Keccak lanes, are IMPLEMENTATION-DEFINED. + * The struct is only exposed here to allow its construction on the stack. + */ + +#define mld_keccakf1600_extract_bytes MLD_NAMESPACE(keccakf1600_extract_bytes) +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(data, length)) +); + +#define mld_keccakf1600_xor_bytes MLD_NAMESPACE(keccakf1600_xor_bytes) +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#define mld_keccakf1600x4_extract_bytes \ + MLD_NAMESPACE(keccakf1600x4_extract_bytes) +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + requires(memory_no_alias(data1, length)) + requires(memory_no_alias(data2, length)) + requires(memory_no_alias(data3, length)) + assigns(memory_slice(data0, length)) + assigns(memory_slice(data1, length)) + assigns(memory_slice(data2, length)) + assigns(memory_slice(data3, length)) +); + +#define mld_keccakf1600x4_xor_bytes MLD_NAMESPACE(keccakf1600x4_xor_bytes) +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + /* Case 1: all input buffers are distinct; Case 2: All input buffers are the same */ + requires((data0 == data1 && + data0 == data2 && + data0 == data3) || + (memory_no_alias(data1, length) && + memory_no_alias(data2, length) && + memory_no_alias(data3, length))) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600x4_permute MLD_NAMESPACE(keccakf1600x4_permute) +void mld_keccakf1600x4_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600_permute MLD_NAMESPACE(keccakf1600_permute) +void mld_keccakf1600_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#endif /* !MLD_FIPS202_KECCAKF1600_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/auto.h new file mode 100644 index 0000000000..4375cc1976 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/auto.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [HYBRID] + * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64 + * Becker, Kannwischer + * https://eprint.iacr.org/2022/1243 + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +#define MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* Default FIPS202 assembly profile for AArch64 systems */ + +/* + * Default logic to decide which implementation to use. + * + */ + +/* + * Keccak-f1600 + * + * - On Arm-based Apple CPUs, we pick a pure Neon implementation. + * - Otherwise, unless MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, + * we use lazy-rotation scalar assembly from @[HYBRID]. + * - Otherwise, if MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, we + * fall back to the standard C implementation. + */ +#if defined(__ARM_FEATURE_SHA3) && defined(__APPLE__) +#include "x1_v84a.h" +#elif !defined(MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER) +#include "x1_scalar.h" +#endif + +/* + * Keccak-f1600x2/x4 + * + * The optimal implementation is highly CPU-specific; see @[HYBRID]. + * + * For now, if v8.4-A is not implemented, we fall back to Keccak-f1600. + * If v8.4-A is implemented and we are on an Apple CPU, we use a plain + * Neon-based implementation. + * If v8.4-A is implemented and we are not on an Apple CPU, we use a + * scalar/Neon/Neon hybrid. + * The reason for this distinction is that Apple CPUs appear to implement + * the SHA3 instructions on all SIMD units, while Arm CPUs prior to Cortex-X4 + * don't, and ordinary Neon instructions are still needed. + */ +#if defined(__ARM_FEATURE_SHA3) +/* + * For Apple-M cores, we use a plain implementation leveraging SHA3 + * instructions only. + */ +#if defined(__APPLE__) +#include "x2_v84a.h" +#else +#include "x4_v8a_v84a_scalar.h" +#endif + +#else /* __ARM_FEATURE_SHA3 */ + +#include "x4_v8a_scalar.h" + +#endif /* !__ARM_FEATURE_SHA3 */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h new file mode 100644 index 0000000000..20f6168038 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#define MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H + +#include +#include "../../../../cbmc.h" +#include "../../../../common.h" + + +#define mld_keccakf1600_round_constants \ + MLD_NAMESPACE(keccakf1600_round_constants) +extern const uint64_t mld_keccakf1600_round_constants[]; + +#define mld_keccak_f1600_x1_scalar_asm MLD_NAMESPACE(keccak_f1600_x1_scalar_asm) +void mld_keccak_f1600_x1_scalar_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x1_v84a_asm MLD_NAMESPACE(keccak_f1600_x1_v84a_asm) +void mld_keccak_f1600_x1_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x2_v84a_asm MLD_NAMESPACE(keccak_f1600_x2_v84a_asm) +void mld_keccak_f1600_x2_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 2)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 2)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c new file mode 100644 index 0000000000..05e9cbfeec --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../../common.h" + +#if (defined(MLD_FIPS202_AARCH64_NEED_X1_SCALAR) || \ + defined(MLD_FIPS202_AARCH64_NEED_X1_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X2_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID)) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "fips202_native_aarch64.h" + +MLD_ALIGN const uint64_t mld_keccakf1600_round_constants[] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, +}; + +#else /* (MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_aarch64_round_constants) + +#endif /* !((MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/x1_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/x1_scalar.h new file mode 100644 index 0000000000..681b991371 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/x1_scalar.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_SCALAR + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + mld_keccak_f1600_x1_scalar_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/x1_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/x1_v84a.h new file mode 100644 index 0000000000..d15c8c26f3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/x1_v84a.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x1_v84a_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/x2_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/x2_v84a.h new file mode 100644 index 0000000000..16c22fa1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/x2_v84a.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X2_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" + + +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x2_v84a_asm(state + 0 * 25, mld_keccakf1600_round_constants); + mld_keccak_f1600_x2_v84a_asm(state + 2 * 25, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h new file mode 100644 index 0000000000..0f7f8fe499 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(state, + mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h new file mode 100644 index 0000000000..3da883b762 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm( + state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/api.h new file mode 100644 index 0000000000..4625c9a1ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/api.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_API_H +#define MLD_FIPS202_NATIVE_API_H +/* + * FIPS-202 native interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + */ + +#include +#include "../../cbmc.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* + * This is the C<->native interface allowing for the drop-in + * of custom Keccak-F1600 implementations. + * + * A _backend_ is a specific implementation of parts of this interface. + * + * You can replace 1-fold or 4-fold batched Keccak-F1600. + * To enable, set MLD_USE_FIPS202_X1_NATIVE or MLD_USE_FIPS202_X4_NATIVE + * in your backend, and define the inline wrappers mld_keccak_f1600_x1_native() + * and/or mld_keccak_f1600_x4_native(), respectively, to forward to your + * implementation. + */ + +#if defined(MLD_USE_FIPS202_X1_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 1)) +); +#endif /* MLD_USE_FIPS202_X1_NATIVE */ +#if defined(MLD_USE_FIPS202_X4_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 4)) +); +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + +#endif /* !MLD_FIPS202_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/auto.h new file mode 100644 index 0000000000..0a09c733c8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/auto.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AUTO_H +#define MLD_FIPS202_NATIVE_AUTO_H + +/* + * Default FIPS202 backend + */ +#include "../../sys.h" + +#if defined(MLD_SYS_AARCH64) +#include "aarch64/auto.h" +#endif + +#if defined(MLD_SYS_X86_64) && defined(MLD_SYS_X86_64_AVX2) +#include "x86_64/xkcp.h" +#endif + +#endif /* !MLD_FIPS202_NATIVE_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c new file mode 100644 index 0000000000..4eaad2fd66 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* +Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, +Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby +denoted as "the implementer". + +For more information, feedback or questions, please refer to our websites: +http://keccak.noekeon.org/ +http://keyak.noekeon.org/ +http://ketje.noekeon.org/ + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +/* + * Changes for mlkem-native/mldsa-native: + * - copyFromState and copyToState operate on uninterleaved + * Keccak states in memory. + */ + +#include "../../../../common.h" +#if defined(MLD_FIPS202_X86_64_XKCP) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include + +#include "KeccakP_1600_times4_SIMD256.h" + +#ifndef MLD_SYS_LITTLE_ENDIAN +#error Expecting a little-endian platform +#endif + +#define ANDnu256(a, b) _mm256_andnot_si256(a, b) +#define CONST256(a) _mm256_load_si256((const __m256i *)&(a)) +#define CONST256_64(a) (__m256i) _mm256_broadcast_sd((const double *)(&a)) +#define ROL64in256(d, a, o) \ + d = _mm256_or_si256(_mm256_slli_epi64(a, o), _mm256_srli_epi64(a, 64 - (o))) +#define ROL64in256_8(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho8)) +#define ROL64in256_56(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho56)) +static const uint64_t rho8[4] = {0x0605040302010007, 0x0E0D0C0B0A09080F, + 0x1615141312111017, 0x1E1D1C1B1A19181F}; +static const uint64_t rho56[4] = {0x0007060504030201, 0x080F0E0D0C0B0A09, + 0x1017161514131211, 0x181F1E1D1C1B1A19}; +#define STORE256(a, b) _mm256_store_si256((__m256i *)&(a), b) +#define XOR256(a, b) _mm256_xor_si256(a, b) +#define XOReq256(a, b) a = _mm256_xor_si256(a, b) + +#define SnP_laneLengthInBytes 8 + +#define declareABCDE \ + __m256i Aba, Abe, Abi, Abo, Abu; \ + __m256i Aga, Age, Agi, Ago, Agu; \ + __m256i Aka, Ake, Aki, Ako, Aku; \ + __m256i Ama, Ame, Ami, Amo, Amu; \ + __m256i Asa, Ase, Asi, Aso, Asu; \ + __m256i Bba, Bbe, Bbi, Bbo, Bbu; \ + __m256i Bga, Bge, Bgi, Bgo, Bgu; \ + __m256i Bka, Bke, Bki, Bko, Bku; \ + __m256i Bma, Bme, Bmi, Bmo, Bmu; \ + __m256i Bsa, Bse, Bsi, Bso, Bsu; \ + __m256i Ca, Ce, Ci, Co, Cu; \ + __m256i Ca1, Ce1, Ci1, Co1, Cu1; \ + __m256i Da, De, Di, Do, Du; \ + __m256i Eba, Ebe, Ebi, Ebo, Ebu; \ + __m256i Ega, Ege, Egi, Ego, Egu; \ + __m256i Eka, Eke, Eki, Eko, Eku; \ + __m256i Ema, Eme, Emi, Emo, Emu; \ + __m256i Esa, Ese, Esi, Eso, Esu; + +#define prepareTheta \ + Ca = XOR256(Aba, XOR256(Aga, XOR256(Aka, XOR256(Ama, Asa)))); \ + Ce = XOR256(Abe, XOR256(Age, XOR256(Ake, XOR256(Ame, Ase)))); \ + Ci = XOR256(Abi, XOR256(Agi, XOR256(Aki, XOR256(Ami, Asi)))); \ + Co = XOR256(Abo, XOR256(Ago, XOR256(Ako, XOR256(Amo, Aso)))); \ + Cu = XOR256(Abu, XOR256(Agu, XOR256(Aku, XOR256(Amu, Asu)))); + +/* + * --- Theta Rho Pi Chi Iota Prepare-theta + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + Ca = E##ba; \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + Ce = E##be; \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + Ci = E##bi; \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + Co = E##bo; \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + Cu = E##bu; \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(Ca, E##ga); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(Ce, E##ge); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + XOReq256(Ci, E##gi); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + XOReq256(Co, E##go); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + XOReq256(Cu, E##gu); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(Ca, E##ka); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(Ce, E##ke); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + XOReq256(Ci, E##ki); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + XOReq256(Co, E##ko); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + XOReq256(Cu, E##ku); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(Ca, E##ma); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(Ce, E##me); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + XOReq256(Ci, E##mi); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + XOReq256(Co, E##mo); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + XOReq256(Cu, E##mu); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(Ca, E##sa); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(Ce, E##se); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + XOReq256(Ci, E##si); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + XOReq256(Co, E##so); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); \ + XOReq256(Cu, E##su); + + +/* + * --- Theta Rho Pi Chi Iota + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIota(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); + + +static MLD_ALIGN const uint64_t keccakf1600RoundConstants[24] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +#include + +#define copyFromState(X, state) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m256i _idx = \ + _mm256_set_epi64x((long long)&state64[75], (long long)&state64[50], \ + (long long)&state64[25], (long long)&state64[0]); \ + X##ba = _mm256_i64gather_epi64((long long *)(0 * 8), _idx, 1); \ + X##be = _mm256_i64gather_epi64((long long *)(1 * 8), _idx, 1); \ + X##bi = _mm256_i64gather_epi64((long long *)(2 * 8), _idx, 1); \ + X##bo = _mm256_i64gather_epi64((long long *)(3 * 8), _idx, 1); \ + X##bu = _mm256_i64gather_epi64((long long *)(4 * 8), _idx, 1); \ + X##ga = _mm256_i64gather_epi64((long long *)(5 * 8), _idx, 1); \ + X##ge = _mm256_i64gather_epi64((long long *)(6 * 8), _idx, 1); \ + X##gi = _mm256_i64gather_epi64((long long *)(7 * 8), _idx, 1); \ + X##go = _mm256_i64gather_epi64((long long *)(8 * 8), _idx, 1); \ + X##gu = _mm256_i64gather_epi64((long long *)(9 * 8), _idx, 1); \ + X##ka = _mm256_i64gather_epi64((long long *)(10 * 8), _idx, 1); \ + X##ke = _mm256_i64gather_epi64((long long *)(11 * 8), _idx, 1); \ + X##ki = _mm256_i64gather_epi64((long long *)(12 * 8), _idx, 1); \ + X##ko = _mm256_i64gather_epi64((long long *)(13 * 8), _idx, 1); \ + X##ku = _mm256_i64gather_epi64((long long *)(14 * 8), _idx, 1); \ + X##ma = _mm256_i64gather_epi64((long long *)(15 * 8), _idx, 1); \ + X##me = _mm256_i64gather_epi64((long long *)(16 * 8), _idx, 1); \ + X##mi = _mm256_i64gather_epi64((long long *)(17 * 8), _idx, 1); \ + X##mo = _mm256_i64gather_epi64((long long *)(18 * 8), _idx, 1); \ + X##mu = _mm256_i64gather_epi64((long long *)(19 * 8), _idx, 1); \ + X##sa = _mm256_i64gather_epi64((long long *)(20 * 8), _idx, 1); \ + X##se = _mm256_i64gather_epi64((long long *)(21 * 8), _idx, 1); \ + X##si = _mm256_i64gather_epi64((long long *)(22 * 8), _idx, 1); \ + X##so = _mm256_i64gather_epi64((long long *)(23 * 8), _idx, 1); \ + X##su = _mm256_i64gather_epi64((long long *)(24 * 8), _idx, 1); \ + } while (0); + +#define SCATTER_STORE256(state, idx, v) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m128d t = _mm_castsi128_pd(_mm256_castsi256_si128((v))); \ + _mm_storel_pd((double *)&state64[0 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[25 + (idx)], t); \ + t = _mm_castsi128_pd(_mm256_extracti128_si256((v), 1)); \ + _mm_storel_pd((double *)&state64[50 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[75 + (idx)], t); \ + } while (0) + +#define copyToState(state, X) \ + SCATTER_STORE256(state, 0, X##ba); \ + SCATTER_STORE256(state, 1, X##be); \ + SCATTER_STORE256(state, 2, X##bi); \ + SCATTER_STORE256(state, 3, X##bo); \ + SCATTER_STORE256(state, 4, X##bu); \ + SCATTER_STORE256(state, 5, X##ga); \ + SCATTER_STORE256(state, 6, X##ge); \ + SCATTER_STORE256(state, 7, X##gi); \ + SCATTER_STORE256(state, 8, X##go); \ + SCATTER_STORE256(state, 9, X##gu); \ + SCATTER_STORE256(state, 10, X##ka); \ + SCATTER_STORE256(state, 11, X##ke); \ + SCATTER_STORE256(state, 12, X##ki); \ + SCATTER_STORE256(state, 13, X##ko); \ + SCATTER_STORE256(state, 14, X##ku); \ + SCATTER_STORE256(state, 15, X##ma); \ + SCATTER_STORE256(state, 16, X##me); \ + SCATTER_STORE256(state, 17, X##mi); \ + SCATTER_STORE256(state, 18, X##mo); \ + SCATTER_STORE256(state, 19, X##mu); \ + SCATTER_STORE256(state, 20, X##sa); \ + SCATTER_STORE256(state, 21, X##se); \ + SCATTER_STORE256(state, 22, X##si); \ + SCATTER_STORE256(state, 23, X##so); \ + SCATTER_STORE256(state, 24, X##su); + +#define copyStateVariables(X, Y) \ + X##ba = Y##ba; \ + X##be = Y##be; \ + X##bi = Y##bi; \ + X##bo = Y##bo; \ + X##bu = Y##bu; \ + X##ga = Y##ga; \ + X##ge = Y##ge; \ + X##gi = Y##gi; \ + X##go = Y##go; \ + X##gu = Y##gu; \ + X##ka = Y##ka; \ + X##ke = Y##ke; \ + X##ki = Y##ki; \ + X##ko = Y##ko; \ + X##ku = Y##ku; \ + X##ma = Y##ma; \ + X##me = Y##me; \ + X##mi = Y##mi; \ + X##mo = Y##mo; \ + X##mu = Y##mu; \ + X##sa = Y##sa; \ + X##se = Y##se; \ + X##si = Y##si; \ + X##so = Y##so; \ + X##su = Y##su; + +/* clang-format off */ +#define rounds24 \ + prepareTheta \ + thetaRhoPiChiIotaPrepareTheta( 0, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 1, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 2, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 3, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 4, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 5, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 6, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 7, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 8, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 9, E, A) \ + thetaRhoPiChiIotaPrepareTheta(10, A, E) \ + thetaRhoPiChiIotaPrepareTheta(11, E, A) \ + thetaRhoPiChiIotaPrepareTheta(12, A, E) \ + thetaRhoPiChiIotaPrepareTheta(13, E, A) \ + thetaRhoPiChiIotaPrepareTheta(14, A, E) \ + thetaRhoPiChiIotaPrepareTheta(15, E, A) \ + thetaRhoPiChiIotaPrepareTheta(16, A, E) \ + thetaRhoPiChiIotaPrepareTheta(17, E, A) \ + thetaRhoPiChiIotaPrepareTheta(18, A, E) \ + thetaRhoPiChiIotaPrepareTheta(19, E, A) \ + thetaRhoPiChiIotaPrepareTheta(20, A, E) \ + thetaRhoPiChiIotaPrepareTheta(21, E, A) \ + thetaRhoPiChiIotaPrepareTheta(22, A, E) \ + thetaRhoPiChiIota(23, E, A) +/* clang-format on */ + +void mld_keccakf1600x4_permute24(void *states) +{ + __m256i *statesAsLanes = (__m256i *)states; + declareABCDE copyFromState(A, statesAsLanes) + rounds24 copyToState(statesAsLanes, A) +} + +#else /* MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_avx2_keccakx4) + +#endif /* !(MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef ANDnu256 +#undef CONST256 +#undef CONST256_64 +#undef ROL64in256 +#undef ROL64in256_8 +#undef ROL64in256_56 +#undef STORE256 +#undef XOR256 +#undef XOReq256 +#undef SnP_laneLengthInBytes +#undef declareABCDE +#undef prepareTheta +#undef thetaRhoPiChiIotaPrepareTheta +#undef thetaRhoPiChiIota +#undef copyFromState +#undef SCATTER_STORE256 +#undef copyToState +#undef copyStateVariables +#undef rounds24 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h new file mode 100644 index 0000000000..3499d38e2c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H +#define MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H + +#include "../../../../common.h" + +#define mld_keccakf1600x4_permute24 \ + MLD_NAMESPACE(KeccakP1600times4_PermuteAll_24rounds) +void mld_keccakf1600x4_permute24(void *states); + +#endif /* !MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/x86_64/xkcp.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/x86_64/xkcp.h new file mode 100644 index 0000000000..c03642d7e0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/fips202/native/x86_64/xkcp.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_XKCP_H +#define MLD_FIPS202_NATIVE_X86_64_XKCP_H + +#include "../../../common.h" + +#define MLD_FIPS202_X86_64_XKCP + +#if !defined(__ASSEMBLER__) +#include +#include "../api.h" +#include "src/KeccakP_1600_times4_SIMD256.h" + +#define MLD_USE_FIPS202_X4_NATIVE +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_keccakf1600x4_permute24(state); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_X86_64_XKCP_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/meta.h new file mode 100644 index 0000000000..c6f6ad47b0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/meta.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_META_H +#define MLD_NATIVE_AARCH64_META_H + +/* Set of primitives that this backend replaces */ +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_AARCH64 + + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/arith_native_aarch64.h" + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + mld_ntt_asm(data, mld_aarch64_ntt_zetas_layer123456, + mld_aarch64_ntt_zetas_layer78); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + mld_intt_asm(data, mld_aarch64_intt_zetas_layer78, + mld_aarch64_intt_zetas_layer123456); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + if (len != MLDSA_N || + buflen % 24 != 0) /* NEON support is mandatory for AArch64 */ + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N, hence, this cast is safe. */ + return (int)mld_rej_uniform_asm(r, buf, buflen, mld_rej_uniform_table); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_32_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_88_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + mld_poly_caddq_asm(a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_32_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_88_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + return mld_poly_chknorm_asm(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_17_asm(r, buf, mld_polyz_unpack_17_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_19_asm(r, buf, mld_polyz_unpack_19_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t out[MLDSA_N], const int32_t in0[MLDSA_N], + const int32_t in1[MLDSA_N]) +{ + mld_poly_pointwise_montgomery_asm(out, in0, in1); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l4_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l5_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l7_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ +#endif /* !MLD_NATIVE_AARCH64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/src/aarch64_zetas.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/src/aarch64_zetas.c new file mode 100644 index 0000000000..9ab7b9a68c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/src/aarch64_zetas.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Table of zeta values used in the AArch64 forward NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer123456[] = { + -3572223, -915382907, 3765607, 964937599, 3761513, 963888510, + -3201494, -820383522, -2883726, -738955404, -3145678, -806080660, + -3201430, -820367122, 0, 0, -601683, -154181397, + -3370349, -863652652, -4063053, -1041158200, 3602218, 923069133, + 3182878, 815613168, 2740543, 702264730, -3586446, -919027554, + 0, 0, 3542485, 907762539, 2663378, 682491182, + -1674615, -429120452, -3110818, -797147778, 2101410, 538486762, + 3704823, 949361686, 1159875, 297218217, 0, 0, + 2682288, 687336873, -3524442, -903139016, -434125, -111244624, + 394148, 101000509, 928749, 237992130, 1095468, 280713909, + -3506380, -898510625, 0, 0, 2129892, 545785280, + 676590, 173376332, -1335936, -342333886, 2071829, 530906624, + -4018989, -1029866791, 3241972, 830756018, 2156050, 552488273, + 0, 0, 3764867, 964747974, -3227876, -827143915, + 1714295, 439288460, 3415069, 875112161, 1759347, 450833045, + -817536, -209493775, -3574466, -915957677, 0, 0, + -1005239, -257592709, 2453983, 628833668, 1460718, 374309300, + 3756790, 962678241, -1935799, -496048908, -1716988, -439978542, + -3950053, -1012201926, 0, 0, 557458, 142848732, + -642628, -164673562, -3585098, -918682129, -2897314, -742437332, + 3192354, 818041395, 556856, 142694469, 3870317, 991769559, + 0, 0, -1221177, -312926867, 2815639, 721508096, + 2283733, 585207070, 2917338, 747568486, 1853806, 475038184, + 3345963, 857403734, 1858416, 476219497, 0, 0, +}; + +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer78[] = { + 3073009, 1277625, -2635473, 3852015, 787459213, + 327391679, -675340520, 987079667, 1753, -2659525, + 2660408, -59148, 449207, -681503850, 681730119, + -15156688, -1935420, -1455890, -1780227, 2772600, + -495951789, -373072124, -456183549, 710479343, 4183372, + -3222807, -3121440, -274060, 1071989969, -825844983, + -799869667, -70227934, 1182243, 636927, -3956745, + -3284915, 302950022, 163212680, -1013916752, -841760171, + 87208, -3965306, -2296397, -3716946, 22347069, + -1016110510, -588452222, -952468207, 2508980, 2028118, + 1937570, -3815725, 642926661, 519705671, 496502727, + -977780347, -27812, 1009365, -1979497, -3956944, + -7126831, 258649997, -507246529, -1013967746, 822541, + -2454145, 1596822, -3759465, 210776307, -628875181, + 409185979, -963363710, 2811291, -2983781, -1109516, + 4158088, 720393920, -764594519, -284313712, 1065510939, + -1685153, 2678278, -3551006, -250446, -431820817, + 686309310, -909946047, -64176841, -3410568, -3768948, + 635956, -2455377, -873958779, -965793731, 162963861, + -629190881, 1528066, 482649, 1148858, -2962264, + 391567239, 123678909, 294395108, -759080783, -4146264, + 2192938, 2387513, -268456, -1062481036, 561940831, + 611800717, -68791907, -1772588, -1727088, -3611750, + -3180456, -454226054, -442566669, -925511710, -814992530, + -565603, 169688, 2462444, -3334383, -144935890, + 43482586, 631001801, -854436357, 3747250, 1239911, + 3195676, 1254190, 960233614, 317727459, 818892658, + 321386456, 2296099, -3838479, 2642980, -12417, + 588375860, -983611064, 677264190, -3181859, -4166425, + -3488383, 1987814, -3197248, -1067647297, -893898890, + 509377762, -819295484, 2998219, -89301, -1354892, + -1310261, 768294260, -22883400, -347191365, -335754661, + 141835, 2513018, 613238, -2218467, 36345249, + 643961400, 157142369, -568482643, 1736313, 235407, + -3250154, 3258457, 444930577, 60323094, -832852657, + 834980303, -458740, 4040196, 2039144, -818761, + -117552223, 1035301089, 522531086, -209807681, -1921994, + -3472069, -1879878, -2178965, -492511373, -889718424, + -481719139, -558360247, -2579253, 1787943, -2391089, + -2254727, -660934133, 458160776, -612717067, -577774276, + -1623354, -2374402, 586241, 527981, -415984810, + -608441020, 150224382, 135295244, 2105286, -2033807, + -1179613, -2743411, 539479988, -521163479, -302276083, + -702999655, 3482206, -4182915, -1300016, -2362063, + 892316032, -1071872863, -333129378, -605279149, -1476985, + 2491325, 507927, -724804, -378477722, 638402564, + 130156402, -185731180, 1994046, -1393159, -1187885, + -1834526, 510974714, -356997292, -304395785, -470097680, + -1317678, 2461387, 3035980, 621164, -337655269, + 630730945, 777970524, 159173408, -3033742, 2647994, + -2612853, 749577, -777397036, 678549029, -669544140, + 192079267, -338420, 3009748, 4148469, -4022750, + -86720197, 771248568, 1063046068, -1030830548, 3901472, + -1226661, 2925816, 3374250, 999753034, -314332144, + 749740976, 864652284, 3980599, -1615530, 1665318, + 1163598, 1020029345, -413979908, 426738094, 298172236, + 2569011, 1723229, 2028038, -3369273, 658309618, + 441577800, 519685171, -863376927, 1356448, -2775755, + 2683270, -2778788, 347590090, -711287812, 687588511, + -712065019, 3994671, -1370517, 3363542, 545376, + 1023635298, -351195274, 861908357, 139752717, -11879, + 3020393, 214880, -770441, -3043996, 773976352, + 55063046, -197425671, -3467665, 2312838, -653275, + -459163, -888589898, 592665232, -167401858, -117660617, + 3105558, 508145, 860144, 140244, 795799901, + 130212265, 220412084, 35937555, -1103344, -553718, + 3430436, -1514152, -282732136, -141890356, 879049958, + -388001774, 348812, -327848, 1011223, -2354215, + 89383150, -84011120, 259126110, -603268097, -2185084, + 2358373, -3014420, 2926054, -559928242, 604333585, + -772445769, 749801963, 3123762, -2193087, -1716814, + -392707, 800464680, -561979013, -439933955, -100631253, + -3818627, -1922253, -2236726, 1744507, -978523985, + -492577742, -573161516, 447030292, -303005, -3974485, + 1900052, 1054478, -77645096, -1018462631, 486888731, + 270210213, 3531229, -3773731, -781875, -731434, + 904878186, -967019376, -200355636, -187430119, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer78[] = { + -1744507, 2236726, 1922253, 3818627, -447030292, 573161516, + 492577742, 978523985, 731434, 781875, 3773731, -3531229, + 187430119, 200355636, 967019376, -904878186, -1054478, -1900052, + 3974485, 303005, -270210213, -486888731, 1018462631, 77645096, + 2354215, -1011223, 327848, -348812, 603268097, -259126110, + 84011120, -89383150, 392707, 1716814, 2193087, -3123762, + 100631253, 439933955, 561979013, -800464680, -2926054, 3014420, + -2358373, 2185084, -749801963, 772445769, -604333585, 559928242, + 459163, 653275, -2312838, 3467665, 117660617, 167401858, + -592665232, 888589898, 1514152, -3430436, 553718, 1103344, + 388001774, -879049958, 141890356, 282732136, -140244, -860144, + -508145, -3105558, -35937555, -220412084, -130212265, -795799901, + 2778788, -2683270, 2775755, -1356448, 712065019, -687588511, + 711287812, -347590090, 770441, -214880, -3020393, 11879, + 197425671, -55063046, -773976352, 3043996, -545376, -3363542, + 1370517, -3994671, -139752717, -861908357, 351195274, -1023635298, + -3374250, -2925816, 1226661, -3901472, -864652284, -749740976, + 314332144, -999753034, 3369273, -2028038, -1723229, -2569011, + 863376927, -519685171, -441577800, -658309618, -1163598, -1665318, + 1615530, -3980599, -298172236, -426738094, 413979908, -1020029345, + -621164, -3035980, -2461387, 1317678, -159173408, -777970524, + -630730945, 337655269, 4022750, -4148469, -3009748, 338420, + 1030830548, -1063046068, -771248568, 86720197, -749577, 2612853, + -2647994, 3033742, -192079267, 669544140, -678549029, 777397036, + 2362063, 1300016, 4182915, -3482206, 605279149, 333129378, + 1071872863, -892316032, 1834526, 1187885, 1393159, -1994046, + 470097680, 304395785, 356997292, -510974714, 724804, -507927, + -2491325, 1476985, 185731180, -130156402, -638402564, 378477722, + 2254727, 2391089, -1787943, 2579253, 577774276, 612717067, + -458160776, 660934133, 2743411, 1179613, 2033807, -2105286, + 702999655, 302276083, 521163479, -539479988, -527981, -586241, + 2374402, 1623354, -135295244, -150224382, 608441020, 415984810, + -3258457, 3250154, -235407, -1736313, -834980303, 832852657, + -60323094, -444930577, 2178965, 1879878, 3472069, 1921994, + 558360247, 481719139, 889718424, 492511373, 818761, -2039144, + -4040196, 458740, 209807681, -522531086, -1035301089, 117552223, + 3197248, -1987814, 3488383, 4166425, 819295484, -509377762, + 893898890, 1067647297, 2218467, -613238, -2513018, -141835, + 568482643, -157142369, -643961400, -36345249, 1310261, 1354892, + 89301, -2998219, 335754661, 347191365, 22883400, -768294260, + 3334383, -2462444, -169688, 565603, 854436357, -631001801, + -43482586, 144935890, 12417, -2642980, 3838479, -2296099, + 3181859, -677264190, 983611064, -588375860, -1254190, -3195676, + -1239911, -3747250, -321386456, -818892658, -317727459, -960233614, + 2962264, -1148858, -482649, -1528066, 759080783, -294395108, + -123678909, -391567239, 3180456, 3611750, 1727088, 1772588, + 814992530, 925511710, 442566669, 454226054, 268456, -2387513, + -2192938, 4146264, 68791907, -611800717, -561940831, 1062481036, + -4158088, 1109516, 2983781, -2811291, -1065510939, 284313712, + 764594519, -720393920, 2455377, -635956, 3768948, 3410568, + 629190881, -162963861, 965793731, 873958779, 250446, 3551006, + -2678278, 1685153, 64176841, 909946047, -686309310, 431820817, + 3815725, -1937570, -2028118, -2508980, 977780347, -496502727, + -519705671, -642926661, 3759465, -1596822, 2454145, -822541, + 963363710, -409185979, 628875181, -210776307, 3956944, 1979497, + -1009365, 27812, 1013967746, 507246529, -258649997, 7126831, + 274060, 3121440, 3222807, -4183372, 70227934, 799869667, + 825844983, -1071989969, 3716946, 2296397, 3965306, -87208, + 952468207, 588452222, 1016110510, -22347069, 3284915, 3956745, + -636927, -1182243, 841760171, 1013916752, -163212680, -302950022, + -3852015, 2635473, -1277625, -3073009, -987079667, 675340520, + -327391679, -787459213, -2772600, 1780227, 1455890, 1935420, + -710479343, 456183549, 373072124, 495951789, 59148, -2660408, + 2659525, -1753, 15156688, -681730119, 681503850, -449207, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer123456[] = { + -2283733, -585207070, 0, 0, -1858416, -476219497, + -3345963, -857403734, -2815639, -721508096, 0, 0, + -1853806, -475038184, -2917338, -747568486, 3585098, 918682129, + 0, 0, -3870317, -991769559, -556856, -142694469, + 642628, 164673562, 0, 0, -3192354, -818041395, + 2897314, 742437332, -1460718, -374309300, 0, 0, + 3950053, 1012201926, 1716988, 439978542, -2453983, -628833668, + 0, 0, 1935799, 496048908, -3756790, -962678241, + -1714295, -439288460, 0, 0, 3574466, 915957677, + 817536, 209493775, 3227876, 827143915, 0, 0, + -1759347, -450833045, -3415069, -875112161, 1335936, 342333886, + 0, 0, -2156050, -552488273, -3241972, -830756018, + -676590, -173376332, 0, 0, 4018989, 1029866791, + -2071829, -530906624, 434125, 111244624, 0, 0, + 3506380, 898510625, -1095468, -280713909, 3524442, 903139016, + 0, 0, -928749, -237992130, -394148, -101000509, + 1674615, 429120452, 0, 0, -1159875, -297218217, + -3704823, -949361686, -2663378, -682491182, 0, 0, + -2101410, -538486762, 3110818, 797147778, 4063053, 1041158200, + 0, 0, 3586446, 919027554, -2740543, -702264730, + 3370349, 863652652, 0, 0, -3182878, -815613168, + -3602218, -923069133, -294725, -75523344, -3761513, -963888510, + -3765607, -964937599, 3201430, 820367122, 3145678, 806080660, + 2883726, 738955404, 3201494, 820383522, 1221177, 312926867, + -557458, -142848732, 1005239, 257592709, -3764867, -964747974, + -2129892, -545785280, -2682288, -687336873, -3542485, -907762539, + 601683, 154181397, 0, 0, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_zetas) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h new file mode 100644 index 0000000000..e77f55014c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#define MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H + +#include +#include "../../../common.h" + +#define mld_aarch64_ntt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_ntt_zetas_layer123456) +#define mld_aarch64_ntt_zetas_layer78 MLD_NAMESPACE(aarch64_ntt_zetas_layer78) + +#define mld_aarch64_intt_zetas_layer78 MLD_NAMESPACE(aarch64_intt_zetas_layer78) +#define mld_aarch64_intt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_intt_zetas_layer123456) + +extern const int32_t mld_aarch64_ntt_zetas_layer123456[]; +extern const int32_t mld_aarch64_ntt_zetas_layer78[]; + +extern const int32_t mld_aarch64_intt_zetas_layer78[]; +extern const int32_t mld_aarch64_intt_zetas_layer123456[]; + +#define mld_rej_uniform_table MLD_NAMESPACE(rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[]; +#define mld_rej_uniform_eta_table MLD_NAMESPACE(rej_uniform_eta_table) +extern const uint8_t mld_rej_uniform_eta_table[]; + +#define mld_polyz_unpack_17_indices MLD_NAMESPACE(polyz_unpack_17_indices) +extern const uint8_t mld_polyz_unpack_17_indices[]; +#define mld_polyz_unpack_19_indices MLD_NAMESPACE(polyz_unpack_19_indices) +extern const uint8_t mld_polyz_unpack_19_indices[]; + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_ntt_asm MLD_NAMESPACE(ntt_asm) +void mld_ntt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_intt_asm MLD_NAMESPACE(intt_asm) +void mld_intt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_rej_uniform_asm MLD_NAMESPACE(rej_uniform_asm) +uint64_t mld_rej_uniform_asm(int32_t *r, const uint8_t *buf, unsigned buflen, + const uint8_t *table); + +#define mld_rej_uniform_eta2_asm MLD_NAMESPACE(rej_uniform_eta2_asm) +uint64_t mld_rej_uniform_eta2_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_rej_uniform_eta4_asm MLD_NAMESPACE(rej_uniform_eta4_asm) +uint64_t mld_rej_uniform_eta4_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_poly_decompose_32_asm MLD_NAMESPACE(poly_decompose_32_asm) +void mld_poly_decompose_32_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_asm MLD_NAMESPACE(poly_decompose_88_asm) +void mld_poly_decompose_88_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_asm MLD_NAMESPACE(poly_caddq_asm) +void mld_poly_caddq_asm(int32_t *a); + +#define mld_poly_use_hint_32_asm MLD_NAMESPACE(poly_use_hint_32_asm) +void mld_poly_use_hint_32_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_asm MLD_NAMESPACE(poly_use_hint_88_asm) +void mld_poly_use_hint_88_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_asm MLD_NAMESPACE(poly_chknorm_asm) +int mld_poly_chknorm_asm(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_asm MLD_NAMESPACE(polyz_unpack_17_asm) +void mld_polyz_unpack_17_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_polyz_unpack_19_asm MLD_NAMESPACE(polyz_unpack_19_asm) +void mld_polyz_unpack_19_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_poly_pointwise_montgomery_asm \ + MLD_NAMESPACE(poly_pointwise_montgomery_asm) +void mld_poly_pointwise_montgomery_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l4_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l4_asm) +void mld_polyvecl_pointwise_acc_montgomery_l4_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l5_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l5_asm) +void mld_polyvecl_pointwise_acc_montgomery_l5_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l7_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l7_asm) +void mld_polyvecl_pointwise_acc_montgomery_l7_asm(int32_t *, const int32_t *, + const int32_t *); + +#endif /* !MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c new file mode 100644 index 0000000000..7ef915b587 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* Table of indices used for tbl instructions in polyz_unpack_{17,19}. */ + +MLD_ALIGN const uint8_t mld_polyz_unpack_17_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, + 9, 10, 11, 255, 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, + 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, 8, 9, 10, 255, + 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, 17, 18, 19, 255, +}; + +MLD_ALIGN const uint8_t mld_polyz_unpack_19_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 5, 6, 7, 255, 7, 8, 9, 255, + 10, 11, 12, 255, 12, 13, 14, 255, 15, 16, 17, 255, 17, 18, 19, 255, + 4, 5, 6, 255, 6, 7, 8, 255, 9, 10, 11, 255, 11, 12, 13, 255, + 14, 15, 16, 255, 16, 17, 18, 255, 19, 20, 21, 255, 21, 22, 23, 255, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_polyz_unpack_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c new file mode 100644 index 0000000000..cf21509cbf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by 16-bit rejection sampling (rej_eta). + * Adapted from ML-KEM for ML-DSA eta rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_eta_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 2, 3, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 4, 5, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 2, 3, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 7 */, + 6, 7, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 2, 3, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 11 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 13 */, + 2, 3, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 15 */, + 8, 9, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 16 */, + 0, 1, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 17 */, + 2, 3, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 18 */, + 0, 1, 2, 3, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 19 */, + 4, 5, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 20 */, + 0, 1, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 21 */, + 2, 3, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 22 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 23 */, + 6, 7, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 24 */, + 0, 1, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 25 */, + 2, 3, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 26 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 27 */, + 4, 5, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 28 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 29 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 30 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 255, 255, 255, 255, 255, 255 /* 31 */, + 10, 11, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 32 */, + 0, 1, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 33 */, + 2, 3, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 34 */, + 0, 1, 2, 3, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 35 */, + 4, 5, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 36 */, + 0, 1, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 37 */, + 2, 3, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 38 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 39 */, + 6, 7, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 40 */, + 0, 1, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 41 */, + 2, 3, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 42 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 43 */, + 4, 5, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 44 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 45 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 46 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 255, 255, 255, 255, 255, 255 /* 47 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 48 */, + 0, 1, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 49 */, + 2, 3, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 50 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 51 */, + 4, 5, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 52 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 53 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 54 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 55 */, + 6, 7, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 56 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 57 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 58 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 59 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 60 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 61 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 62 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 63 */, + 12, 13, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 64 */, + 0, 1, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 65 */, + 2, 3, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 66 */, + 0, 1, 2, 3, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 67 */, + 4, 5, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 68 */, + 0, 1, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 69 */, + 2, 3, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 70 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 71 */, + 6, 7, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 72 */, + 0, 1, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 73 */, + 2, 3, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 74 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 75 */, + 4, 5, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 76 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 77 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 78 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 255, 255, 255, 255, 255, 255 /* 79 */, + 8, 9, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 80 */, + 0, 1, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 81 */, + 2, 3, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 82 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 83 */, + 4, 5, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 84 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 85 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 86 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 87 */, + 6, 7, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 88 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 89 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 90 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 91 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 92 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 93 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 94 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 255, 255, 255, 255 /* 95 */, + 10, 11, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 96 */, + 0, 1, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 97 */, + 2, 3, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 98 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 99 */, + 4, 5, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 100 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 101 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 102 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 103 */, + 6, 7, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 104 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 105 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 106 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 107 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 108 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 109 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 110 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 255, 255, 255, 255 /* 111 */, + 8, 9, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 112 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 113 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 114 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 115 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 116 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 117 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 118 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 119 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 120 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 121 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 122 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 123 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 124 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 125 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 126 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 255, 255 /* 127 */, + 14, 15, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 128 */, + 0, 1, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 129 */, + 2, 3, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 130 */, + 0, 1, 2, 3, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 131 */, + 4, 5, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 132 */, + 0, 1, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 133 */, + 2, 3, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 134 */, + 0, 1, 2, 3, 4, 5, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 135 */, + 6, 7, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 136 */, + 0, 1, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 137 */, + 2, 3, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 138 */, + 0, 1, 2, 3, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 139 */, + 4, 5, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 140 */, + 0, 1, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 141 */, + 2, 3, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 142 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 14, 15, 255, 255, 255, 255, 255, 255 /* 143 */, + 8, 9, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 144 */, + 0, 1, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 145 */, + 2, 3, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 146 */, + 0, 1, 2, 3, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 147 */, + 4, 5, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 148 */, + 0, 1, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 149 */, + 2, 3, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 150 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 151 */, + 6, 7, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 152 */, + 0, 1, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 153 */, + 2, 3, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 154 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 155 */, + 4, 5, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 156 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 157 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 158 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 14, 15, 255, 255, 255, 255 /* 159 */, + 10, 11, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 160 */, + 0, 1, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 161 */, + 2, 3, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 162 */, + 0, 1, 2, 3, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 163 */, + 4, 5, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 164 */, + 0, 1, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 165 */, + 2, 3, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 166 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 167 */, + 6, 7, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 168 */, + 0, 1, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 169 */, + 2, 3, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 170 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 171 */, + 4, 5, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 172 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 173 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 174 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 14, 15, 255, 255, 255, 255 /* 175 */, + 8, 9, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 176 */, + 0, 1, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 177 */, + 2, 3, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 178 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 179 */, + 4, 5, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 180 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 181 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 182 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 183 */, + 6, 7, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 184 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 185 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 186 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 187 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 188 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 189 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 190 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 14, 15, 255, 255 /* 191 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 192 */, + 0, 1, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 193 */, + 2, 3, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 194 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 195 */, + 4, 5, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 196 */, + 0, 1, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 197 */, + 2, 3, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 198 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 199 */, + 6, 7, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 200 */, + 0, 1, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 201 */, + 2, 3, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 202 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 203 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 204 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 205 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 206 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 207 */, + 8, 9, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 208 */, + 0, 1, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 209 */, + 2, 3, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 210 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 211 */, + 4, 5, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 212 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 213 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 214 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 215 */, + 6, 7, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 216 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 217 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 218 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 219 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 220 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 221 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 222 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 14, 15, 255, 255 /* 223 */, + 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 224 */, + 0, 1, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 225 */, + 2, 3, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 226 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 227 */, + 4, 5, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 228 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 229 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 230 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 231 */, + 6, 7, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 232 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 233 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 234 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 235 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 236 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 237 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 238 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 14, 15, 255, 255 /* 239 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 240 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 241 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 242 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 243 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 244 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 245 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 246 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 247 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 248 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 249 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 250 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 251 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 252 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 253 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 254 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 255 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_eta_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/src/rej_uniform_table.c new file mode 100644 index 0000000000..65bc3b78d3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/aarch64/src/rej_uniform_table.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by rejection sampling of the public matrix. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 7 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 11 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 13 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 15 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/api.h new file mode 100644 index 0000000000..0f1fdeb168 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/api.h @@ -0,0 +1,594 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_API_H +#define MLD_NATIVE_API_H +/* + * Native arithmetic interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + * + * To ensure consistency with backends, the header will be + * included automatically after inclusion of the active + * backend, to ensure consistency of function signatures, + * and run sanity checks. + */ + +#include +#include "../cbmc.h" +#include "../common.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* Bound on absolute value of coefficients after NTT. + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) + +/* Absolute exclusive upper bound for the output of the inverse NTT + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_INTT_BOUND MLDSA_Q + +/* Absolute bound for range of mld_reduce32() + * + * NOTE: This is the same bound as in reduce.h and has to be kept + * in sync. */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define REDUCE32_RANGE_MAX 6283009 +/* + * This is the C<->native interface allowing for the drop-in of + * native code for performance critical arithmetic components of ML-DSA. + * + * A _backend_ is a specific implementation of (part of) this interface. + * + * To add a function to a backend, define MLD_USE_NATIVE_XXX and + * implement `static inline xxx(...)` in the profile header. + */ + +/* + * Those functions are meant to be trivial wrappers around the chosen native + * implementation. The are static inline to avoid unnecessary calls. + * The macro before each declaration controls whether a native + * implementation is present. + */ + +#if defined(MLD_USE_NATIVE_NTT) +/************************************************* + * Name: mld_ntt_native + * + * Description: Computes negacyclic number-theoretic transform (NTT) of + * a polynomial in place. + * + * The input polynomial is assumed to be in normal order. + * The output polynomial is in bitreversed order. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_ntt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_NTT */ + + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) +/* + * This must only be set if NTT and INTT have native implementations + * that are adapted to the custom order. + */ +#if !defined(MLD_USE_NATIVE_NTT) || !defined(MLD_USE_NATIVE_INTT) +#error \ + "Invalid native profile: MLD_USE_NATIVE_NTT_CUSTOM_ORDER can only be \ +set if there are native implementations for NTT and INTT." +#endif + +/************************************************* + * Name: mlD_poly_permute_bitrev_to_custom + * + * Description: When MLD_USE_NATIVE_NTT_CUSTOM_ORDER is defined, + * convert a polynomial in NTT domain from bitreversed + * order to the custom order output by the native NTT. + * + * This must only be defined if there is native code for + * both the NTT and INTT. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + * + **************************************************/ +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t p[MLDSA_N]) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q))); +#endif /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + + +#if defined(MLD_USE_NATIVE_INTT) +/************************************************* + * Name: mld_intt_native + * + * Description: Computes inverse of negacyclic number-theoretic transform + *(NTT) of a polynomial in place. + * + * The input polynomial is in bitreversed order. + * The output polynomial is assumed to be in normal order. + * + * Arguments: - uint32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_intt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_INTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_INTT */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) +/************************************************* + * Name: mld_rej_uniform_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [0, MLDSA_Q-1] + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform mod q). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + * lengths. Otherwise, returns non-negative number of sampled 32-bit integers + * (at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= ( 5 * 168) && buflen % 3 == 0) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(r, 0, (unsigned) return_value, 0, MLDSA_Q)) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) +/************************************************* + * Name: mld_rej_uniform_eta2_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-2,+2]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-2, +2]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA2 */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) +/************************************************* + * Name: mld_rej_uniform_eta4_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-4,+4]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-4, +4]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) +/************************************************* + * Name: mld_poly_decompose_32_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/32. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: input/output polynomial. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_32 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) +/************************************************* + * Name: mld_poly_decompose_88_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/88. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: output polynomial with coefficients c0. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CADDQ) +/************************************************* + * Name: mld_poly_caddq_native + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *a: pointer to input/output polynomial + **************************************************/ +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_32) +/************************************************* + * Name: mld_poly_use_hint_32_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/32. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_32 */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) +/************************************************* + * Name: mld_poly_use_hint_88_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/88. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) +/************************************************* + * Name: mld_poly_chknorm_native + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const int32_t *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if the infinity norm is strictly smaller than B, and 1 + * otherwise. B must not be larger than MLDSA_Q - MLD_REDUCE32_RANGE_MAX. + **************************************************/ +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(0 <= B && B <= MLDSA_Q - REDUCE32_RANGE_MAX) + requires(array_bound(a, 0, MLDSA_N, -REDUCE32_RANGE_MAX, REDUCE32_RANGE_MAX)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == 0) == array_abs_bound(a, 0, MLDSA_N, B)) +); +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) +/************************************************* + * Name: mld_polyz_unpack_17_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^17. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_17 */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) +/************************************************* + * Name: mld_polyz_unpack_19_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^19. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_19 */ + +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) +/************************************************* + * Name: mld_poly_pointwise_montgomery_native + * + * Description: Pointwise multiplication of polynomials in NTT domain + * with Montgomery reduction. + * + * Computes c[i] = a[i] * b[i] * R^(-1) mod q for all i, + * where R = 2^32. + * + * Arguments: - int32_t c[MLDSA_N]: output polynomial + * - const int32_t a[MLDSA_N]: first input polynomial + * - const int32_t b[MLDSA_N]: second input polynomial + **************************************************/ +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(c, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(c, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(c, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l4_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 4. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 4 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 4 * MLDSA_N)) + requires(forall(l0, 0, 4, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 4, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l5_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 5. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 5 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 5 * MLDSA_N)) + requires(forall(l0, 0, 5, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 5, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l7_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 7. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 7 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 7 * MLDSA_N)) + requires(forall(l0, 0, 7, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 7, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 */ + +#endif /* !MLD_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/meta.h new file mode 100644 index 0000000000..0b46dd5791 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/meta.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_META_H +#define MLD_NATIVE_META_H + +/* + * Default arithmetic backend + */ +#include "../sys.h" + +#ifdef MLD_SYS_AARCH64 +#include "aarch64/meta.h" +#endif + +#ifdef MLD_SYS_X86_64_AVX2 +#include "x86_64/meta.h" +#endif + +#endif /* !MLD_NATIVE_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/meta.h new file mode 100644 index 0000000000..393374c06f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/meta.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_X86_64_META_H +#define MLD_NATIVE_X86_64_META_H + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_X86_64_DEFAULT + +#define MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +#if !defined(__ASSEMBLER__) +#include +#include "../../common.h" +#include "../api.h" +#include "src/arith_native_x86_64.h" + +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t data[MLDSA_N]) +{ + if (mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + mld_nttunpack_avx2(data); + } +} + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_ntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_invntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)mld_rej_uniform_avx2(r, buf); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_32_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_88_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_caddq_avx2(a); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_32_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_88_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + return mld_poly_chknorm_avx2(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_17_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_19_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_avx2(c, a, b, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l4_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l5_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l7_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_NATIVE_X86_64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h new file mode 100644 index 0000000000..08d5abf74a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#define MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#include "../../../common.h" + +#include +#include "consts.h" + +#define MLD_AVX2_REJ_UNIFORM_BUFLEN \ + (5 * 168) /* REJ_UNIFORM_NBLOCKS * SHAKE128_RATE */ + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) + +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_rej_uniform_table MLD_NAMESPACE(mld_rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[256][8]; + +#define mld_ntt_avx2 MLD_NAMESPACE(ntt_avx2) +void mld_ntt_avx2(int32_t *r, const int32_t *qdata) +/* This must be kept in sync with the HOL-Light specification + * in proofs/hol_light/x86_64/proofs/mldsa_ntt.ml */ +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, MLDSA_N, 8380417)) + requires(qdata == mld_qdata) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + /* check-magic: off */ + ensures(array_abs_bound(r, 0, MLDSA_N, 42035262)) + /* check-magic: on */ +); + +#define mld_invntt_avx2 MLD_NAMESPACE(invntt_avx2) +void mld_invntt_avx2(int32_t *r, const int32_t *mld_qdata); + +#define mld_nttunpack_avx2 MLD_NAMESPACE(nttunpack_avx2) +void mld_nttunpack_avx2(int32_t *r); + +#define mld_rej_uniform_avx2 MLD_NAMESPACE(mld_rej_uniform_avx2) +unsigned mld_rej_uniform_avx2(int32_t *r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]); + +#define mld_rej_uniform_eta2_avx2 MLD_NAMESPACE(mld_rej_uniform_eta2_avx2) +unsigned mld_rej_uniform_eta2_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]); + +#define mld_rej_uniform_eta4_avx2 MLD_NAMESPACE(mld_rej_uniform_eta4_avx2) +unsigned mld_rej_uniform_eta4_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]); + +#define mld_poly_decompose_32_avx2 MLD_NAMESPACE(mld_poly_decompose_32_avx2) +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_avx2 MLD_NAMESPACE(mld_poly_decompose_88_avx2) +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_avx2 MLD_NAMESPACE(poly_caddq_avx2) +void mld_poly_caddq_avx2(int32_t *r); + +#define mld_poly_use_hint_32_avx2 MLD_NAMESPACE(mld_poly_use_hint_32_avx2) +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_avx2 MLD_NAMESPACE(mld_poly_use_hint_88_avx2) +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_avx2 MLD_NAMESPACE(mld_poly_chknorm_avx2) +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_avx2 MLD_NAMESPACE(mld_polyz_unpack_17_avx2) +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a); + +#define mld_polyz_unpack_19_avx2 MLD_NAMESPACE(mld_polyz_unpack_19_avx2) +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a); + +#define mld_pointwise_avx2 MLD_NAMESPACE(pointwise_avx2) +void mld_pointwise_avx2(int32_t *c, const int32_t *a, const int32_t *b, + const int32_t *qdata); + +#define mld_pointwise_acc_l4_avx2 MLD_NAMESPACE(pointwise_acc_l4_avx2) +void mld_pointwise_acc_l4_avx2(int32_t c[MLDSA_N], const int32_t a[4][MLDSA_N], + const int32_t b[4][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l5_avx2 MLD_NAMESPACE(pointwise_acc_l5_avx2) +void mld_pointwise_acc_l5_avx2(int32_t c[MLDSA_N], const int32_t a[5][MLDSA_N], + const int32_t b[5][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l7_avx2 MLD_NAMESPACE(pointwise_acc_l7_avx2) +void mld_pointwise_acc_l7_avx2(int32_t c[MLDSA_N], const int32_t a[7][MLDSA_N], + const int32_t b[7][MLDSA_N], + const int32_t *qdata); + +#endif /* !MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/consts.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/consts.c new file mode 100644 index 0000000000..aaca3535ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/consts.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include "consts.h" + +/* + * Table of zeta values used in the AVX2 forward and inverse NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_qdata[624] = { + 8380417, 8380417, 8380417, 8380417, 8380417, + 8380417, 8380417, 8380417, 58728449, 58728449, + 58728449, 58728449, 58728449, 58728449, 58728449, + 58728449, -8395782, -8395782, -8395782, -8395782, + -8395782, -8395782, -8395782, -8395782, 41978, + 41978, 41978, 41978, 41978, 41978, + 41978, 41978, -151046689, 1830765815, -1929875198, + -1927777021, 1640767044, 1477910808, 1612161320, 1640734244, + 308362795, 308362795, 308362795, 308362795, -1815525077, + -1815525077, -1815525077, -1815525077, -1374673747, -1374673747, + -1374673747, -1374673747, -1091570561, -1091570561, -1091570561, + -1091570561, -1929495947, -1929495947, -1929495947, -1929495947, + 515185417, 515185417, 515185417, 515185417, -285697463, + -285697463, -285697463, -285697463, 625853735, 625853735, + 625853735, 625853735, 1727305304, 1727305304, 2082316400, + 2082316400, -1364982364, -1364982364, 858240904, 858240904, + 1806278032, 1806278032, 222489248, 222489248, -346752664, + -346752664, 684667771, 684667771, 1654287830, 1654287830, + -878576921, -878576921, -1257667337, -1257667337, -748618600, + -748618600, 329347125, 329347125, 1837364258, 1837364258, + -1443016191, -1443016191, -1170414139, -1170414139, -1846138265, + -1631226336, -1404529459, 1838055109, 1594295555, -1076973524, + -1898723372, -594436433, -202001019, -475984260, -561427818, + 1797021249, -1061813248, 2059733581, -1661512036, -1104976547, + -1750224323, -901666090, 418987550, 1831915353, -1925356481, + 992097815, 879957084, 2024403852, 1484874664, -1636082790, + -285388938, -1983539117, -1495136972, -950076368, -1714807468, + -952438995, -1574918427, 1350681039, -2143979939, 1599739335, + -1285853323, -993005454, -1440787840, 568627424, -783134478, + -588790216, 289871779, -1262003603, 2135294594, -1018755525, + -889861155, 1665705315, 1321868265, 1225434135, -1784632064, + 666258756, 675310538, -1555941048, -1999506068, -1499481951, + -695180180, -1375177022, 1777179795, 334803717, -178766299, + -518252220, 1957047970, 1146323031, -654783359, -1974159335, + 1651689966, 140455867, -1039411342, 1955560694, 1529189038, + -2131021878, -247357819, 1518161567, -86965173, 1708872713, + 1787797779, 1638590967, -120646188, -1669960606, -916321552, + 1155548552, 2143745726, 1210558298, -1261461890, -318346816, + 628664287, -1729304568, 1422575624, 1424130038, -1185330464, + 235321234, 168022240, 1206536194, 985155484, -894060583, + -898413, -1363460238, -605900043, 2027833504, 14253662, + 1014493059, 863641633, 1819892093, 2124962073, -1223601433, + -1920467227, -1637785316, -1536588520, 694382729, 235104446, + -1045062172, 831969619, -300448763, 756955444, -260312805, + 1554794072, 1339088280, -2040058690, -853476187, -2047270596, + -1723816713, -1591599803, -440824168, 1119856484, 1544891539, + 155290192, -973777462, 991903578, 912367099, -44694137, + 1176904444, -421552614, -818371958, 1747917558, -325927722, + 908452108, 1851023419, -1176751719, -1354528380, -72690498, + -314284737, 985022747, 963438279, -1078959975, 604552167, + -1021949428, 608791570, 173440395, -2126092136, -1316619236, + -1039370342, 6087993, -110126092, 565464272, -1758099917, + -1600929361, 879867909, -1809756372, 400711272, 1363007700, + 30313375, -326425360, 1683520342, -517299994, 2027935492, + -1372618620, 128353682, -1123881663, 137583815, -635454918, + -642772911, 45766801, 671509323, -2070602178, 419615363, + 1216882040, -270590488, -1276805128, 371462360, -1357098057, + -384158533, 827959816, -596344473, 702390549, -279505433, + -260424530, -71875110, -1208667171, -1499603926, 2036925262, + -540420426, 746144248, -1420958686, 2032221021, 1904936414, + 1257750362, 1926727420, 1931587462, 1258381762, 885133339, + 1629985060, 1967222129, 6363718, -1287922800, 1136965286, + 1779436847, 1116720494, 1042326957, 1405999311, 713994583, + 940195359, -1542497137, 2061661095, -883155599, 1726753853, + -1547952704, 394851342, 283780712, 776003547, 1123958025, + 201262505, 1934038751, 374860238, -3975713, 25847, + -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 1826347, 1826347, 1826347, + 2353451, 2353451, 2353451, 2353451, -359251, + -359251, -359251, -359251, -2091905, -2091905, + -2091905, -2091905, 3119733, 3119733, 3119733, + 3119733, -2884855, -2884855, -2884855, -2884855, + 3111497, 3111497, 3111497, 3111497, 2680103, + 2680103, 2680103, 2680103, 2725464, 2725464, + 1024112, 1024112, -1079900, -1079900, 3585928, + 3585928, -549488, -549488, -1119584, -1119584, + 2619752, 2619752, -2108549, -2108549, -2118186, + -2118186, -3859737, -3859737, -1399561, -1399561, + -3277672, -3277672, 1757237, 1757237, -19422, + -19422, 4010497, 4010497, 280005, 280005, + 2706023, 95776, 3077325, 3530437, -1661693, + -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, + -539299, -1699267, -1643818, 3505694, -3821735, + 3507263, -2140649, -1600420, 3699596, 811944, + 531354, 954230, 3881043, 3900724, -2556880, + 2071892, -2797779, -3930395, -3677745, -1452451, + 2176455, -1257611, -4083598, -3190144, -3632928, + 3412210, 2147896, -2967645, -411027, -671102, + -22981, -381987, 1852771, -3343383, 508951, + 44288, 904516, -3724342, 1653064, 2389356, + 759969, 189548, 3159746, -2409325, 1315589, + 1285669, -812732, -3019102, -3628969, -1528703, + -3041255, 3475950, -1585221, 1939314, -1000202, + -3157330, 126922, -983419, 2715295, -3693493, + -2477047, -1228525, -1308169, 1349076, -1430430, + 264944, 3097992, -1100098, 3958618, -8578, + -3249728, -210977, -1316856, -3553272, -1851402, + -177440, 1341330, -1584928, -1439742, -3881060, + 3839961, 2091667, -3342478, 266997, -3520352, + 900702, 495491, -655327, -3556995, 342297, + 3437287, 2842341, 4055324, -3767016, -2994039, + -1333058, -451100, -1279661, 1500165, -542412, + -2584293, -2013608, 1957272, -3183426, 810149, + -3038916, 2213111, -426683, -1667432, -2939036, + 183443, -554416, 3937738, 3407706, 2244091, + 2434439, -3759364, 1859098, -1613174, -3122442, + -525098, 286988, -3342277, 2691481, 1247620, + 1250494, 1869119, 1237275, 1312455, 1917081, + 777191, -2831860, -3724270, 2432395, 3369112, + 162844, 1652634, 3523897, -975884, 1723600, + -1104333, -2235985, -976891, 3919660, 1400424, + 2316500, -2446433, -1235728, -1197226, 909542, + -43260, 2031748, -768622, -2437823, 1735879, + -2590150, 2486353, 2635921, 1903435, -3318210, + 3306115, -2546312, 2235880, -1671176, 594136, + 2454455, 185531, 1616392, -3694233, 3866901, + 1717735, -1803090, -260646, -420899, 1612842, + -48306, -846154, 3817976, -3562462, 3513181, + -3193378, 819034, -522500, 3207046, -3595838, + 4108315, 203044, 1265009, 1595974, -3548272, + -1050970, -1430225, -1962642, -1374803, 3406031, + -1846953, -3776993, -164721, -1207385, 3014001, + -1799107, 269760, 472078, 1910376, -3833893, + -2286327, -3545687, -1362209, 1976782, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_consts) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/consts.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/consts.h new file mode 100644 index 0000000000..7fe08f454b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/consts.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#ifndef MLD_NATIVE_X86_64_SRC_CONSTS_H +#define MLD_NATIVE_X86_64_SRC_CONSTS_H +#include "../../../common.h" +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQ 0 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV 8 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV 16 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV 24 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV 32 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS 328 + +#ifndef __ASSEMBLER__ +#define mld_qdata MLD_NAMESPACE(qdata) +extern const int32_t mld_qdata[624]; +#endif + +#endif /* !MLD_NATIVE_X86_64_SRC_CONSTS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c new file mode 100644 index 0000000000..05d86d14fc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/************************************************* + * Name: mld_poly_caddq_avx2 + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *r: pointer to input/output polynomial + **************************************************/ +void mld_poly_caddq_avx2(int32_t *r) +{ + unsigned int i; + __m256i f, g; + const __m256i q = _mm256_set1_epi32(MLDSA_Q); + const __m256i zero = _mm256_setzero_si256(); + __m256i *rr = (__m256i *)r; + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256(&rr[i]); + g = _mm256_cmpgt_epi32(zero, f); + g = _mm256_and_si256(g, q); + f = _mm256_add_epi32(f, g); + _mm256_store_si256(&rr[i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_reduce) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c new file mode 100644 index 0000000000..50e2c7fa9b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B) +{ + unsigned int i; + __m256i f, t; + const __m256i bound = _mm256_set1_epi32(B - 1); + + t = _mm256_setzero_si256(); + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + f = _mm256_abs_epi32(f); + f = _mm256_cmpgt_epi32(f, bound); + t = _mm256_or_si256(t, f); + } + + return 1 - _mm256_testz_si256(t, t); +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_chknorm) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c new file mode 100644 index 0000000000..76846bf1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(31 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 4092 == intdiv(2 * intdiv(MLDSA_Q - 1, 32), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 4092. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 32*GAMMA2 = 16*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 16B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + * + * round(f1' * 1025 / 2^22) is in turn computed in 2 steps as + * round(floor(f1' * 1025 / 2^16) / 2^6). The mulhi computes f1'' = + * floor(f1' * 1025 / 2^16). As for the next step f1 = round(f1'' / 2^6), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^9) = round(f1'' * 2^9 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 1025 / 2^16) = 1025 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(16B / B) = 16 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 16, i.e. f > 31*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 31*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 15, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c new file mode 100644 index 0000000000..463506b962 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ + +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 1488 == intdiv(2 * intdiv(MLDSA_Q - 1, 88), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 1488. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 88*GAMMA2 = 44*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 44B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + * + * round(f1' * 11275 / 2^24) is in turn computed in 2 steps as + * round(floor(f1' * 11275 / 2^16) / 2^8). The mulhi computes f1'' = + * floor(f1' * 11275 / 2^16). As for the next step f1 = round(f1'' / 2^8), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^7) = round(f1'' * 2^7 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 11275 / 2^16) = 11275 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(44B / B) = 44 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 44, i.e. f > 87*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 87*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 43, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c new file mode 100644 index 0000000000..0094bc93a9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + const __m256i mask = _mm256_set1_epi32(15); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_32_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 16 */ + f1 = _mm256_add_epi32(f1, h); + f1 = _mm256_and_si256(f1, mask); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c new file mode 100644 index 0000000000..b109ab6351 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + const __m256i max = _mm256_set1_epi32(43); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_88_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 44 */ + f1 = _mm256_add_epi32(f1, h); + f1 = MLD_MM256_BLENDV_EPI32(f1, max, f1); + f = _mm256_cmpgt_epi32(f1, max); + f1 = MLD_MM256_BLENDV_EPI32(f1, zero, f); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c new file mode 100644 index 0000000000..f6c08a832f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 27, 26, 25, -1, 25, 24, 23, -1, 8, 7, + 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0); + const __m256i srlvdidx = _mm256_set_epi32(6, 4, 2, 0, 6, 4, 2, 0); + const __m256i mask = _mm256_set1_epi32(0x3FFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 17)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[18 * i]); + /* Load bytes 2..17 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[18 * i + 2]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-8 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 8, 7, 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte8, byte7, byte6, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,27, 26, 25, -1,25, 24, 23] │ + * │ Result: [0, byte17, byte16, byte15, ..., 0, byte11, byte10, byte9] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 18 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 32..55 48..71 + * 72..95 88..111 104..127 120..143 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 18..39 36..55 54..71 + * 72..95 90..111 108..127 126..143 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..17 18..35 36..53 54..71 + * 72..89 90..107 108..125 126..143 */ + + /* Map [0, 1, ..., 2^18-1] to [2^17, 2^17-1, ..., -2^17+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_17) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c new file mode 100644 index 0000000000..4a5ce48f38 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 26, 25, 24, -1, 24, 23, 22, -1, 9, 8, + 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0); + /* Equivalent to _mm256_set_epi32(4, 0, 4, 0, 4, 0, 4, 0) */ + const __m256i srlvdidx = _mm256_set1_epi64x((uint64_t)4 << 32); + const __m256i mask = _mm256_set1_epi32(0xFFFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 19)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[20 * i]); + /* Load bytes 4..19 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[20 * i + 4]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-9 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 9, 8, 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte9, byte8, byte7, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,26, 25, 24, -1,24, 23, 22] │ + * │ Result: [0, byte19, byte18, byte17, ..., 0, byte12, byte11, byte10] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 20 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 40..63 56..79 + * 80..103 96..119 120..143 136..159 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 20..39 40..63 60..79 + * 80..103 100..119 120..143 140..159 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..19 20..39 40..59 60..79 + * 80..99 100..119 120..139 140..159 */ + + /* Map [0, 1, ..., 2^20-1] to [2^19, 2^19-1, ..., -2^19+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_19) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c new file mode 100644 index 0000000000..07a5df9706 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The pqcrystals implementation assumes a buffer that is 8 bytes + *. larger as the first loop overreads by 8 bytes that are then + * discarded. We instead do not pad the buffer and do not overread. + * The performance impact is negligible and it does not force the + * frontend to perform the unintuitive padding. + */ + +unsigned int mld_rej_uniform_avx2( + int32_t *MLD_RESTRICT r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i d, tmp; + const __m256i bound = _mm256_set1_epi32(MLDSA_Q); + const __m256i mask = _mm256_set1_epi32(0x7FFFFF); + const __m256i idx8 = + _mm256_set_epi8(-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4, + -1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 32) + { + d = _mm256_loadu_si256((__m256i *)&buf[pos]); + + /* Permute 64-bit lanes + * 0x94 = 10010100b rearranges 64-bit lanes as: [3,2,1,0] -> [2,1,1,0] + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Original Layout ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ bytes 16..23 │ bytes 24..31 │ + * └─────────────────┴─────────────────┴─────────────────┴─────────────────┘ + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Layout after permute ║ + * ║ Byte indices in high half shifted down by 8 positions ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌───────────────┬─────────────────┐ ┌─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ │ bytes 8..15 │ bytes 16..23 │ + * └───────────────┴─────────────────┘ └─────────────────┴─────────────────┘ + * Lower 128-bit lane (bytes 0-15) Upper 128-bit lane (bytes 16-31) + */ + d = _mm256_permute4x64_epi64(d, 0x94); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-11 into low 128-bit half of permuted vector────────────────┐ + * │ Shuffle: [-1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0] │ + * │ Result: [0, byte11, byte10, byte9, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 4-15 into high 128-bit half of permuted vector ──────────────┐ + * │ Shuffle: [-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4] │ + * │ Result: [0, byte23, byte22, byte21, ..., 0, byte14, byte13, byte12 │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + d = _mm256_shuffle_epi8(d, idx8); + d = _mm256_and_si256(d, mask); + pos += 24; + + tmp = _mm256_sub_epi32(d, bound); + good = (uint32_t)_mm256_movemask_ps((__m256)tmp); + tmp = _mm256_cvtepu8_epi32( + _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good])); + d = _mm256_permutevar8x32_epi32(d, tmp); + + _mm256_storeu_si256((__m256i *)&r[ctr], d); + ctr += (unsigned)_mm_popcnt_u32(good); + } + + while (ctr < MLDSA_N && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 3) + { + uint32_t t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + /* Safe because t < MLDSA_Q. */ + r[ctr++] = (int32_t)t; + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c new file mode 100644 index 0000000000..70c5c42c70 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA2 2 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ +unsigned int mld_rej_uniform_eta2_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1, f2; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA2); + const __m256i bound = mask; + /* check-magic: -6560 == 32*round(-2**10 / 5) */ + const __m256i v = _mm256_set1_epi32(-6560); + const __m256i p = _mm256_set1_epi32(5); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 15) + { + t0 = t0 - (205 * t0 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t0); + } + if (t1 < 15 && ctr < MLDSA_N) + { + t1 = t1 - (205 * t1 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta2) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA2 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c new file mode 100644 index 0000000000..ba00e91252 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA4 4 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ + +unsigned int mld_rej_uniform_eta4_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA4); + const __m256i bound = _mm256_set1_epi8(9); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 9) + { + r[ctr++] = (int32_t)(4 - t0); + } + if (t1 < 9 && ctr < MLDSA_N) + { + r[ctr++] = (int32_t)(4 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta4) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA4 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/rej_uniform_table.c new file mode 100644 index 0000000000..6c537b4542 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/native/x86_64/src/rej_uniform_table.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" + +/* + * Lookup table used by rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[256][8] = { + {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, + {2, 0, 0, 0, 0, 0, 0, 0}, {0, 2, 0, 0, 0, 0, 0, 0}, + {1, 2, 0, 0, 0, 0, 0, 0}, {0, 1, 2, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 0, 0}, {0, 3, 0, 0, 0, 0, 0, 0}, + {1, 3, 0, 0, 0, 0, 0, 0}, {0, 1, 3, 0, 0, 0, 0, 0}, + {2, 3, 0, 0, 0, 0, 0, 0}, {0, 2, 3, 0, 0, 0, 0, 0}, + {1, 2, 3, 0, 0, 0, 0, 0}, {0, 1, 2, 3, 0, 0, 0, 0}, + {4, 0, 0, 0, 0, 0, 0, 0}, {0, 4, 0, 0, 0, 0, 0, 0}, + {1, 4, 0, 0, 0, 0, 0, 0}, {0, 1, 4, 0, 0, 0, 0, 0}, + {2, 4, 0, 0, 0, 0, 0, 0}, {0, 2, 4, 0, 0, 0, 0, 0}, + {1, 2, 4, 0, 0, 0, 0, 0}, {0, 1, 2, 4, 0, 0, 0, 0}, + {3, 4, 0, 0, 0, 0, 0, 0}, {0, 3, 4, 0, 0, 0, 0, 0}, + {1, 3, 4, 0, 0, 0, 0, 0}, {0, 1, 3, 4, 0, 0, 0, 0}, + {2, 3, 4, 0, 0, 0, 0, 0}, {0, 2, 3, 4, 0, 0, 0, 0}, + {1, 2, 3, 4, 0, 0, 0, 0}, {0, 1, 2, 3, 4, 0, 0, 0}, + {5, 0, 0, 0, 0, 0, 0, 0}, {0, 5, 0, 0, 0, 0, 0, 0}, + {1, 5, 0, 0, 0, 0, 0, 0}, {0, 1, 5, 0, 0, 0, 0, 0}, + {2, 5, 0, 0, 0, 0, 0, 0}, {0, 2, 5, 0, 0, 0, 0, 0}, + {1, 2, 5, 0, 0, 0, 0, 0}, {0, 1, 2, 5, 0, 0, 0, 0}, + {3, 5, 0, 0, 0, 0, 0, 0}, {0, 3, 5, 0, 0, 0, 0, 0}, + {1, 3, 5, 0, 0, 0, 0, 0}, {0, 1, 3, 5, 0, 0, 0, 0}, + {2, 3, 5, 0, 0, 0, 0, 0}, {0, 2, 3, 5, 0, 0, 0, 0}, + {1, 2, 3, 5, 0, 0, 0, 0}, {0, 1, 2, 3, 5, 0, 0, 0}, + {4, 5, 0, 0, 0, 0, 0, 0}, {0, 4, 5, 0, 0, 0, 0, 0}, + {1, 4, 5, 0, 0, 0, 0, 0}, {0, 1, 4, 5, 0, 0, 0, 0}, + {2, 4, 5, 0, 0, 0, 0, 0}, {0, 2, 4, 5, 0, 0, 0, 0}, + {1, 2, 4, 5, 0, 0, 0, 0}, {0, 1, 2, 4, 5, 0, 0, 0}, + {3, 4, 5, 0, 0, 0, 0, 0}, {0, 3, 4, 5, 0, 0, 0, 0}, + {1, 3, 4, 5, 0, 0, 0, 0}, {0, 1, 3, 4, 5, 0, 0, 0}, + {2, 3, 4, 5, 0, 0, 0, 0}, {0, 2, 3, 4, 5, 0, 0, 0}, + {1, 2, 3, 4, 5, 0, 0, 0}, {0, 1, 2, 3, 4, 5, 0, 0}, + {6, 0, 0, 0, 0, 0, 0, 0}, {0, 6, 0, 0, 0, 0, 0, 0}, + {1, 6, 0, 0, 0, 0, 0, 0}, {0, 1, 6, 0, 0, 0, 0, 0}, + {2, 6, 0, 0, 0, 0, 0, 0}, {0, 2, 6, 0, 0, 0, 0, 0}, + {1, 2, 6, 0, 0, 0, 0, 0}, {0, 1, 2, 6, 0, 0, 0, 0}, + {3, 6, 0, 0, 0, 0, 0, 0}, {0, 3, 6, 0, 0, 0, 0, 0}, + {1, 3, 6, 0, 0, 0, 0, 0}, {0, 1, 3, 6, 0, 0, 0, 0}, + {2, 3, 6, 0, 0, 0, 0, 0}, {0, 2, 3, 6, 0, 0, 0, 0}, + {1, 2, 3, 6, 0, 0, 0, 0}, {0, 1, 2, 3, 6, 0, 0, 0}, + {4, 6, 0, 0, 0, 0, 0, 0}, {0, 4, 6, 0, 0, 0, 0, 0}, + {1, 4, 6, 0, 0, 0, 0, 0}, {0, 1, 4, 6, 0, 0, 0, 0}, + {2, 4, 6, 0, 0, 0, 0, 0}, {0, 2, 4, 6, 0, 0, 0, 0}, + {1, 2, 4, 6, 0, 0, 0, 0}, {0, 1, 2, 4, 6, 0, 0, 0}, + {3, 4, 6, 0, 0, 0, 0, 0}, {0, 3, 4, 6, 0, 0, 0, 0}, + {1, 3, 4, 6, 0, 0, 0, 0}, {0, 1, 3, 4, 6, 0, 0, 0}, + {2, 3, 4, 6, 0, 0, 0, 0}, {0, 2, 3, 4, 6, 0, 0, 0}, + {1, 2, 3, 4, 6, 0, 0, 0}, {0, 1, 2, 3, 4, 6, 0, 0}, + {5, 6, 0, 0, 0, 0, 0, 0}, {0, 5, 6, 0, 0, 0, 0, 0}, + {1, 5, 6, 0, 0, 0, 0, 0}, {0, 1, 5, 6, 0, 0, 0, 0}, + {2, 5, 6, 0, 0, 0, 0, 0}, {0, 2, 5, 6, 0, 0, 0, 0}, + {1, 2, 5, 6, 0, 0, 0, 0}, {0, 1, 2, 5, 6, 0, 0, 0}, + {3, 5, 6, 0, 0, 0, 0, 0}, {0, 3, 5, 6, 0, 0, 0, 0}, + {1, 3, 5, 6, 0, 0, 0, 0}, {0, 1, 3, 5, 6, 0, 0, 0}, + {2, 3, 5, 6, 0, 0, 0, 0}, {0, 2, 3, 5, 6, 0, 0, 0}, + {1, 2, 3, 5, 6, 0, 0, 0}, {0, 1, 2, 3, 5, 6, 0, 0}, + {4, 5, 6, 0, 0, 0, 0, 0}, {0, 4, 5, 6, 0, 0, 0, 0}, + {1, 4, 5, 6, 0, 0, 0, 0}, {0, 1, 4, 5, 6, 0, 0, 0}, + {2, 4, 5, 6, 0, 0, 0, 0}, {0, 2, 4, 5, 6, 0, 0, 0}, + {1, 2, 4, 5, 6, 0, 0, 0}, {0, 1, 2, 4, 5, 6, 0, 0}, + {3, 4, 5, 6, 0, 0, 0, 0}, {0, 3, 4, 5, 6, 0, 0, 0}, + {1, 3, 4, 5, 6, 0, 0, 0}, {0, 1, 3, 4, 5, 6, 0, 0}, + {2, 3, 4, 5, 6, 0, 0, 0}, {0, 2, 3, 4, 5, 6, 0, 0}, + {1, 2, 3, 4, 5, 6, 0, 0}, {0, 1, 2, 3, 4, 5, 6, 0}, + {7, 0, 0, 0, 0, 0, 0, 0}, {0, 7, 0, 0, 0, 0, 0, 0}, + {1, 7, 0, 0, 0, 0, 0, 0}, {0, 1, 7, 0, 0, 0, 0, 0}, + {2, 7, 0, 0, 0, 0, 0, 0}, {0, 2, 7, 0, 0, 0, 0, 0}, + {1, 2, 7, 0, 0, 0, 0, 0}, {0, 1, 2, 7, 0, 0, 0, 0}, + {3, 7, 0, 0, 0, 0, 0, 0}, {0, 3, 7, 0, 0, 0, 0, 0}, + {1, 3, 7, 0, 0, 0, 0, 0}, {0, 1, 3, 7, 0, 0, 0, 0}, + {2, 3, 7, 0, 0, 0, 0, 0}, {0, 2, 3, 7, 0, 0, 0, 0}, + {1, 2, 3, 7, 0, 0, 0, 0}, {0, 1, 2, 3, 7, 0, 0, 0}, + {4, 7, 0, 0, 0, 0, 0, 0}, {0, 4, 7, 0, 0, 0, 0, 0}, + {1, 4, 7, 0, 0, 0, 0, 0}, {0, 1, 4, 7, 0, 0, 0, 0}, + {2, 4, 7, 0, 0, 0, 0, 0}, {0, 2, 4, 7, 0, 0, 0, 0}, + {1, 2, 4, 7, 0, 0, 0, 0}, {0, 1, 2, 4, 7, 0, 0, 0}, + {3, 4, 7, 0, 0, 0, 0, 0}, {0, 3, 4, 7, 0, 0, 0, 0}, + {1, 3, 4, 7, 0, 0, 0, 0}, {0, 1, 3, 4, 7, 0, 0, 0}, + {2, 3, 4, 7, 0, 0, 0, 0}, {0, 2, 3, 4, 7, 0, 0, 0}, + {1, 2, 3, 4, 7, 0, 0, 0}, {0, 1, 2, 3, 4, 7, 0, 0}, + {5, 7, 0, 0, 0, 0, 0, 0}, {0, 5, 7, 0, 0, 0, 0, 0}, + {1, 5, 7, 0, 0, 0, 0, 0}, {0, 1, 5, 7, 0, 0, 0, 0}, + {2, 5, 7, 0, 0, 0, 0, 0}, {0, 2, 5, 7, 0, 0, 0, 0}, + {1, 2, 5, 7, 0, 0, 0, 0}, {0, 1, 2, 5, 7, 0, 0, 0}, + {3, 5, 7, 0, 0, 0, 0, 0}, {0, 3, 5, 7, 0, 0, 0, 0}, + {1, 3, 5, 7, 0, 0, 0, 0}, {0, 1, 3, 5, 7, 0, 0, 0}, + {2, 3, 5, 7, 0, 0, 0, 0}, {0, 2, 3, 5, 7, 0, 0, 0}, + {1, 2, 3, 5, 7, 0, 0, 0}, {0, 1, 2, 3, 5, 7, 0, 0}, + {4, 5, 7, 0, 0, 0, 0, 0}, {0, 4, 5, 7, 0, 0, 0, 0}, + {1, 4, 5, 7, 0, 0, 0, 0}, {0, 1, 4, 5, 7, 0, 0, 0}, + {2, 4, 5, 7, 0, 0, 0, 0}, {0, 2, 4, 5, 7, 0, 0, 0}, + {1, 2, 4, 5, 7, 0, 0, 0}, {0, 1, 2, 4, 5, 7, 0, 0}, + {3, 4, 5, 7, 0, 0, 0, 0}, {0, 3, 4, 5, 7, 0, 0, 0}, + {1, 3, 4, 5, 7, 0, 0, 0}, {0, 1, 3, 4, 5, 7, 0, 0}, + {2, 3, 4, 5, 7, 0, 0, 0}, {0, 2, 3, 4, 5, 7, 0, 0}, + {1, 2, 3, 4, 5, 7, 0, 0}, {0, 1, 2, 3, 4, 5, 7, 0}, + {6, 7, 0, 0, 0, 0, 0, 0}, {0, 6, 7, 0, 0, 0, 0, 0}, + {1, 6, 7, 0, 0, 0, 0, 0}, {0, 1, 6, 7, 0, 0, 0, 0}, + {2, 6, 7, 0, 0, 0, 0, 0}, {0, 2, 6, 7, 0, 0, 0, 0}, + {1, 2, 6, 7, 0, 0, 0, 0}, {0, 1, 2, 6, 7, 0, 0, 0}, + {3, 6, 7, 0, 0, 0, 0, 0}, {0, 3, 6, 7, 0, 0, 0, 0}, + {1, 3, 6, 7, 0, 0, 0, 0}, {0, 1, 3, 6, 7, 0, 0, 0}, + {2, 3, 6, 7, 0, 0, 0, 0}, {0, 2, 3, 6, 7, 0, 0, 0}, + {1, 2, 3, 6, 7, 0, 0, 0}, {0, 1, 2, 3, 6, 7, 0, 0}, + {4, 6, 7, 0, 0, 0, 0, 0}, {0, 4, 6, 7, 0, 0, 0, 0}, + {1, 4, 6, 7, 0, 0, 0, 0}, {0, 1, 4, 6, 7, 0, 0, 0}, + {2, 4, 6, 7, 0, 0, 0, 0}, {0, 2, 4, 6, 7, 0, 0, 0}, + {1, 2, 4, 6, 7, 0, 0, 0}, {0, 1, 2, 4, 6, 7, 0, 0}, + {3, 4, 6, 7, 0, 0, 0, 0}, {0, 3, 4, 6, 7, 0, 0, 0}, + {1, 3, 4, 6, 7, 0, 0, 0}, {0, 1, 3, 4, 6, 7, 0, 0}, + {2, 3, 4, 6, 7, 0, 0, 0}, {0, 2, 3, 4, 6, 7, 0, 0}, + {1, 2, 3, 4, 6, 7, 0, 0}, {0, 1, 2, 3, 4, 6, 7, 0}, + {5, 6, 7, 0, 0, 0, 0, 0}, {0, 5, 6, 7, 0, 0, 0, 0}, + {1, 5, 6, 7, 0, 0, 0, 0}, {0, 1, 5, 6, 7, 0, 0, 0}, + {2, 5, 6, 7, 0, 0, 0, 0}, {0, 2, 5, 6, 7, 0, 0, 0}, + {1, 2, 5, 6, 7, 0, 0, 0}, {0, 1, 2, 5, 6, 7, 0, 0}, + {3, 5, 6, 7, 0, 0, 0, 0}, {0, 3, 5, 6, 7, 0, 0, 0}, + {1, 3, 5, 6, 7, 0, 0, 0}, {0, 1, 3, 5, 6, 7, 0, 0}, + {2, 3, 5, 6, 7, 0, 0, 0}, {0, 2, 3, 5, 6, 7, 0, 0}, + {1, 2, 3, 5, 6, 7, 0, 0}, {0, 1, 2, 3, 5, 6, 7, 0}, + {4, 5, 6, 7, 0, 0, 0, 0}, {0, 4, 5, 6, 7, 0, 0, 0}, + {1, 4, 5, 6, 7, 0, 0, 0}, {0, 1, 4, 5, 6, 7, 0, 0}, + {2, 4, 5, 6, 7, 0, 0, 0}, {0, 2, 4, 5, 6, 7, 0, 0}, + {1, 2, 4, 5, 6, 7, 0, 0}, {0, 1, 2, 4, 5, 6, 7, 0}, + {3, 4, 5, 6, 7, 0, 0, 0}, {0, 3, 4, 5, 6, 7, 0, 0}, + {1, 3, 4, 5, 6, 7, 0, 0}, {0, 1, 3, 4, 5, 6, 7, 0}, + {2, 3, 4, 5, 6, 7, 0, 0}, {0, 2, 3, 4, 5, 6, 7, 0}, + {1, 2, 3, 4, 5, 6, 7, 0}, {0, 1, 2, 3, 4, 5, 6, 7}, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/packing.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/packing.c new file mode 100644 index 0000000000..26da273856 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/packing.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include + +#include "common.h" +#include "packing.h" +#include "poly.h" +#include "polyvec.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_unpack_hints MLD_ADD_PARAM_SET(mld_unpack_hints) +/* End of parameter set namespacing */ + +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +{ + unsigned int i; + + mld_memcpy(pk, rho, MLDSA_SEEDBYTES); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt1_pack(pk + MLDSA_SEEDBYTES + i * MLDSA_POLYT1_PACKEDBYTES, + &t1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +{ + unsigned int i; + + mld_memcpy(rho, pk, MLDSA_SEEDBYTES); + pk += MLDSA_SEEDBYTES; + + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt1_unpack(&t1->vec[i], pk + i * MLDSA_POLYT1_PACKEDBYTES); + } +} + +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +{ + mld_memcpy(sk, rho, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, key, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, tr, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_pack_eta(sk, s1); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_eta(sk, s2); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_t0(sk, t0); +} + +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +{ + mld_memcpy(rho, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(key, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(tr, sk, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_unpack_eta(s1, sk); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_eta(s2, sk); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_t0(t0, sk); +} + +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +{ + unsigned int i, j, k; + + mld_memcpy(sig, c, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + /* skip z component - packed via mld_pack_sig_z */ + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + /* Encode hints h */ + + /* The final section of sig[] is MLDSA_POLYVECH_PACKEDBYTES long, where + * MLDSA_POLYVECH_PACKEDBYTES = MLDSA_OMEGA + MLDSA_K + * + * The first OMEGA bytes record the index numbers of the coefficients + * that are not equal to 0 + * + * The final K bytes record a running tally of the number of hints + * coming from each of the K polynomials in h. + * + * The pre-condition tells us that number_of_hints <= OMEGA, so some + * bytes may not be written, so we initialize all of them to zero + * to start. + */ + mld_memset(sig, 0, MLDSA_POLYVECH_PACKEDBYTES); + + k = 0; + /* For each polynomial in h... */ + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* For each coefficient in that polynomial, record it as as hint */ + /* if its value is not zero */ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + assigns(j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(j <= MLDSA_N) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* The reference implementation implicitly relies on the total */ + /* number of hints being less than OMEGA, assuming h is valid. */ + /* In mldsa-native, we check this explicitly to ease proof of */ + /* type safety. */ + if (h->vec[i].coeffs[j] != 0 && k < number_of_hints) + { + /* The enclosing if condition AND the loop invariant infer */ + /* that k < MLDSA_OMEGA, so writing to sig[k] is safe and k */ + /* can be incremented. */ + sig[k++] = (uint8_t)j; + } + } + /* Having recorded all the hints for this polynomial, also */ + /* record the running tally into the correct "slot" for that */ + /* coefficient in the final K bytes */ + sig[MLDSA_OMEGA + i] = (uint8_t)k; + } +} + +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +{ + sig += MLDSA_CTILDEBYTES; + sig += i * MLDSA_POLYZ_PACKEDBYTES; + mld_polyz_pack(sig, zi); +} + +/************************************************* + * Name: mld_unpack_hints + * + * Description: Unpack raw hint bytes into a polyveck + * struct + * + * Arguments: - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]: + * raw hint bytes + * + * Returns 1 in case of malformed hints; otherwise 0. + **************************************************/ +static int mld_unpack_hints( + mld_polyveck *h, const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(packed_hints, MLDSA_POLYVECH_PACKEDBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + /* All returned coefficients are either 0 or 1 */ + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +) +{ + unsigned int i, j; + unsigned int old_hint_count; + + /* Set all coefficients of all polynomials to 0. */ + /* Only those that are actually non-zero hints will */ + /* be overwritten below. */ + mld_memset(h, 0, sizeof(mld_polyveck)); + + old_hint_count = 0; + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + /* Grab the hint count for the i'th polynomial */ + const unsigned int new_hint_count = packed_hints[MLDSA_OMEGA + i]; + + /* new_hint_count must increase or stay the same, but also remain */ + /* less than or equal to MLDSA_OMEGA */ + if (new_hint_count < old_hint_count || new_hint_count > MLDSA_OMEGA) + { + /* Error - new_hint_count is invalid */ + return 1; + } + + /* If new_hint_count == old_hint_count, then this polynomial has */ + /* zero hints, so this loop executes zero times and we move */ + /* straight on to the next polynomial. */ + for (j = old_hint_count; j < new_hint_count; ++j) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + const uint8_t this_hint_index = packed_hints[j]; + + /* Coefficients must be ordered for strong unforgeability */ + if (j > old_hint_count && this_hint_index <= packed_hints[j - 1]) + { + return 1; + } + h->vec[i].coeffs[this_hint_index] = 1; + } + + old_hint_count = new_hint_count; + } + + /* Extra indices must be zero for strong unforgeability */ + for (j = old_hint_count; j < MLDSA_OMEGA; ++j) + __loop__( + invariant(j <= MLDSA_OMEGA) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + if (packed_hints[j] != 0) + { + return 1; + } + } + + return 0; +} + +MLD_INTERNAL_API +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +{ + mld_memcpy(c, sig, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + mld_polyvecl_unpack_z(z, sig); + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + return mld_unpack_hints(h, sig); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_unpack_hints diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/packing.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/packing.h new file mode 100644 index 0000000000..19095d08cd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/packing.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PACKING_H +#define MLD_PACKING_H + +#include +#include "polyvec.h" + +#define mld_pack_pk MLD_NAMESPACE_KL(pack_pk) +/************************************************* + * Name: mld_pack_pk + * + * Description: Bit-pack public key pk = (rho, t1). + * + * Arguments: - uint8_t pk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const mld_polyveck *t1: pointer to vector t1 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) +); + + +#define mld_pack_sk MLD_NAMESPACE_KL(pack_sk) +/************************************************* + * Name: mld_pack_sk + * + * Description: Bit-pack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - uint8_t sk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const uint8_t tr[]: byte array containing tr + * - const uint8_t key[]: byte array containing key + * - const mld_polyveck *t0: pointer to vector t0 + * - const mld_polyvecl *s1: pointer to vector s1 + * - const mld_polyveck *s2: pointer to vector s2 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +__contract__( + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + requires(forall(k2, 0, MLDSA_K, + array_abs_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) +); + + +#define mld_pack_sig_c_h MLD_NAMESPACE_KL(pack_sig_c_h) +/************************************************* + * Name: mld_pack_sig_c_h + * + * Description: Bit-pack c and h component of sig = (c, z, h). + * The z component is packed separately using mld_pack_sig_z. + * + * Arguments: - uint8_t sig[]: output byte array + * - const uint8_t *c: pointer to challenge hash length + * MLDSA_SEEDBYTES + * - const mld_polyveck *h: pointer to hint vector h + * - const unsigned int number_of_hints: total + * hints in *h + * + * Note that the number_of_hints argument is not present + * in the reference implementation. It is added here to ease + * proof of type safety. + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + requires(number_of_hints <= MLDSA_OMEGA) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_pack_sig_z MLD_NAMESPACE_KL(pack_sig_z) +/************************************************* + * Name: mld_pack_sig_z + * + * Description: Bit-pack single polynomial of z component of sig = (c, z, h). + * The c and h components are packed separately using + * mld_pack_sig_c_h. + * + * Arguments: - uint8_t sig[]: output byte array + * - const mld_poly *zi: pointer to a single polynomial in z + * - const unsigned int i: index of zi in vector z + * + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(zi, sizeof(mld_poly))) + requires(i < MLDSA_L) + requires(array_bound(zi->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_unpack_pk MLD_NAMESPACE_KL(unpack_pk) +/************************************************* + * Name: mld_unpack_pk + * + * Description: Unpack public key pk = (rho, t1). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const mld_polyveck *t1: pointer to output vector t1 + * - uint8_t pk[]: byte array containing bit-packed pk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) +); + + +#define mld_unpack_sk MLD_NAMESPACE_KL(unpack_sk) +/************************************************* + * Name: mld_unpack_sk + * + * Description: Unpack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const uint8_t tr[]: output byte array for tr + * - const uint8_t key[]: output byte array for key + * - const mld_polyveck *t0: pointer to output vector t0 + * - const mld_polyvecl *s1: pointer to output vector s1 + * - const mld_polyveck *s2: pointer to output vector s2 + * - uint8_t sk[]: byte array containing bit-packed sk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +__contract__( + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(key, MLDSA_SEEDBYTES)) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(s1, sizeof(mld_polyvecl))) + assigns(memory_slice(s2, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_unpack_sig MLD_NAMESPACE_KL(unpack_sig) +/************************************************* + * Name: mld_unpack_sig + * + * Description: Unpack signature sig = (c, z, h). + * + * Arguments: - uint8_t *c: pointer to output challenge hash + * - mld_polyvecl *z: pointer to output vector z + * - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t sig[]: byte array containing + * bit-packed signature + * + * Returns 1 in case of malformed signature; otherwise 0. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(c, MLDSA_CTILDEBYTES)) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(z->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +); +#endif /* !MLD_PACKING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/params.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/params.h new file mode 100644 index 0000000000..c67d2a33fb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/params.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PARAMS_H +#define MLD_PARAMS_H + +#define MLDSA_SEEDBYTES 32 +#define MLDSA_CRHBYTES 64 +#define MLDSA_TRBYTES 64 +#define MLDSA_RNDBYTES 32 +#define MLDSA_N 256 +#define MLDSA_Q 8380417 +#define MLDSA_Q_HALF ((MLDSA_Q + 1) / 2) +#define MLDSA_D 13 + +#if MLD_CONFIG_PARAMETER_SET == 44 + +#define MLDSA_K 4 +#define MLDSA_L 4 +#define MLDSA_ETA 2 +#define MLDSA_TAU 39 +#define MLDSA_BETA 78 +#define MLDSA_GAMMA1 (1 << 17) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 88) +#define MLDSA_OMEGA 80 +#define MLDSA_CTILDEBYTES 32 +#define MLDSA_POLYZ_PACKEDBYTES 576 +#define MLDSA_POLYW1_PACKEDBYTES 192 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#elif MLD_CONFIG_PARAMETER_SET == 65 + +#define MLDSA_K 6 +#define MLDSA_L 5 +#define MLDSA_ETA 4 +#define MLDSA_TAU 49 +#define MLDSA_BETA 196 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 55 +#define MLDSA_CTILDEBYTES 48 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 128 + +#elif MLD_CONFIG_PARAMETER_SET == 87 + +#define MLDSA_K 8 +#define MLDSA_L 7 +#define MLDSA_ETA 2 +#define MLDSA_TAU 60 +#define MLDSA_BETA 120 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 75 +#define MLDSA_CTILDEBYTES 64 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ + +#define MLDSA_POLYT1_PACKEDBYTES 320 +#define MLDSA_POLYT0_PACKEDBYTES 416 +#define MLDSA_POLYVECH_PACKEDBYTES (MLDSA_OMEGA + MLDSA_K) + +#define MLDSA_CRYPTO_PUBLICKEYBYTES \ + (MLDSA_SEEDBYTES + MLDSA_K * MLDSA_POLYT1_PACKEDBYTES) +#define MLDSA_CRYPTO_SECRETKEYBYTES \ + (2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + MLDSA_L * MLDSA_POLYETA_PACKEDBYTES + \ + MLDSA_K * MLDSA_POLYETA_PACKEDBYTES + MLDSA_K * MLDSA_POLYT0_PACKEDBYTES) +#define MLDSA_CRYPTO_BYTES \ + (MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES + \ + MLDSA_POLYVECH_PACKEDBYTES) + +#endif /* !MLD_PARAMS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/poly.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/poly.c new file mode 100644 index 0000000000..e40534e773 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/poly.c @@ -0,0 +1,973 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "common.h" +#include "ct.h" +#include "debug.h" +#include "poly.h" +#include "reduce.h" +#include "rounding.h" +#include "symmetric.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +#include "zetas.inc" + +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + { + a->coeffs[i] = mld_reduce32(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_STATIC_TESTABLE void mld_poly_caddq_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + ) + { + a->coeffs[i] = mld_caddq(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_POLY_CADDQ) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_poly_caddq_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + mld_poly_caddq_c(a); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1])) + invariant(forall(k2, 0, i, r->coeffs[k2] < MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k2, 0, i, r->coeffs[k2] >= INT32_MIN)) + ) + { + r->coeffs[i] = r->coeffs[i] + b->coeffs[i]; + } +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(r->coeffs, 0, i, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + ) + { + r->coeffs[i] = r->coeffs[i] - b->coeffs[i]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N; i++) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))) + { + /* Reference: uses a left shift by MLDSA_D which is undefined behaviour in + * C90/C99 + */ + a->coeffs[i] *= (1 << MLDSA_D); + } + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + + +static MLD_INLINE int32_t mld_fqmul(int32_t a, int32_t b) +__contract__( + requires(b > -MLDSA_Q_HALF && b < MLDSA_Q_HALF) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* Bounds: We argue in mld_montgomery_reduce() that the reult + * of Montgomery reduction is < MLDSA_Q if the input is smaller + * than 2^31 * MLDSA_Q in absolute value. Indeed, we have: + * + * |a * b| = |a| * |b| + * < 2^31 * MLDSA_Q_HALF + * < 2^31 * MLDSA_Q + */ + return mld_montgomery_reduce((int64_t)a * (int64_t)b); +} + +/* mld_ntt_butterfly_block() + * + * Computes a block CT butterflies with a fixed twiddle factor, + * using Montgomery multiplication. + * + * Parameters: + * - r: Pointer to base of polynomial (_not_ the base of butterfly block) + * - zeta: Twiddle factor to use for the butterfly. This must be in + * Montgomery form and signed canonical. + * - start: Offset to the beginning of the butterfly block + * - len: Index difference between coefficients subject to a butterfly + * - bound: Ghost variable describing coefficient bound: Prior to `start`, + * coefficients must be bound by `bound + MLDSA_Q`. Post `start`, + * they must be bound by `bound`. + * When this function returns, output coefficients in the index range + * [start, start+2*len) have bound bumped to `bound + MLDSA_Q`. + * Example: + * - start=8, len=4 + * This would compute the following four butterflies + * 8 -- 12 + * 9 -- 13 + * 10 -- 14 + * 11 -- 15 + * - start=4, len=2 + * This would compute the following two butterflies + * 4 -- 6 + * 5 -- 7 + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_butterfly_block(int32_t r[MLDSA_N], + const int32_t zeta, + const unsigned start, + const unsigned len, + const unsigned bound) +__contract__( + requires(start < MLDSA_N) + requires(1 <= len && len <= MLDSA_N / 2 && start + 2 * len <= MLDSA_N) + requires(0 <= bound && bound < INT32_MAX - MLDSA_Q) + requires(-MLDSA_Q_HALF < zeta && zeta < MLDSA_Q_HALF) + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, start, bound + MLDSA_Q)) + requires(array_abs_bound(r, start, MLDSA_N, bound)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, start + 2*len, bound + MLDSA_Q)) + ensures(array_abs_bound(r, start + 2 * len, MLDSA_N, bound))) +{ + /* `bound` is a ghost variable only needed in the CBMC specification */ + unsigned j; + ((void)bound); + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + /* + * Coefficients are updated in strided pairs, so the bounds for the + * intermediate states alternate twice between the old and new bound + */ + invariant(array_abs_bound(r, 0, j, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, bound)) + invariant(array_abs_bound(r, start + len, j + len, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j + len, MLDSA_N, bound))) + { + int32_t t; + t = mld_fqmul(r[j + len], zeta); + r[j + len] = r[j] - t; + r[j] = r[j] + t; + } +} + +/* mld_ntt_layer() + * + * Compute one layer of forward NTT + * + * Parameters: + * - r: Pointer to base of polynomial + * - layer: Indicates which layer is being applied. + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_layer(int32_t r[MLDSA_N], const unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (layer + 1) * MLDSA_Q))) +{ + unsigned start, k, len; + /* Twiddle factors for layer n are at indices 2^(n-1)..2^n-1. */ + k = 1u << (layer - 1); + len = (unsigned)MLDSA_N >> layer; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start < MLDSA_N + 2 * len) + invariant(k <= MLDSA_N) + invariant(2 * len * k == start + MLDSA_N) + invariant(array_abs_bound(r, 0, start, layer * MLDSA_Q + MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, layer * MLDSA_Q))) + { + int32_t zeta = mld_zetas[k++]; + mld_ntt_butterfly_block(r, zeta, start, len, layer * MLDSA_Q); + } +} + +MLD_STATIC_TESTABLE void mld_poly_ntt_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +) +{ + unsigned int layer; + int32_t *r; + + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + r = a->coeffs; + + for (layer = 1; layer < 9; layer++) + __loop__( + invariant(1 <= layer && layer <= 9) + invariant(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + ) + { + mld_ntt_layer(r, layer); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_NTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_ntt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_NTT */ + mld_poly_ntt_c(a); +} + +/************************************************* + * Name: mld_fqscale + * + * Description: Scales a field element by mont/256 , i.e., performs Montgomery + * multiplication by mont^2/256. + * Input is expected to have absolute value smaller than + * 256 * MLDSA_Q. + * Output has absolute value smaller than MLD_INTT_BOUND. + * + * Arguments: - int32_t a: Field element to be scaled. + **************************************************/ +static MLD_INLINE int32_t mld_fqscale(int32_t a) +__contract__( + requires(a > -256*MLDSA_Q && a < 256*MLDSA_Q) + ensures(return_value > -MLD_INTT_BOUND && return_value < MLD_INTT_BOUND) +) +{ + /* check-magic: 41978 == pow(2,64-8,MLDSA_Q) */ + const int32_t f = 41978; + /* Bounds: MLD_INTT_BOUND is MLDSA_Q, so the bounds reasoning is just + * a special case of that in mld_fqmul(). */ + return mld_montgomery_reduce((int64_t)a * f); +} + +/* Reference: Embedded into `invntt_tomont()` in the reference implementation + * @[REF] */ +static MLD_INLINE void mld_invntt_layer(int32_t r[MLDSA_N], unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> (layer - 1)) * MLDSA_Q))) +{ + unsigned start, k, len; + len = (unsigned)MLDSA_N >> layer; + k = (1u << layer) - 1; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start <= MLDSA_N && k <= 255) + invariant(2 * len * k + start == 2 * MLDSA_N - 2 * len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + unsigned j; + int32_t zeta = -mld_zetas[k--]; + + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, j, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, (MLDSA_N >> layer) * MLDSA_Q)) + invariant(array_abs_bound(r, start + len, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + int32_t t = r[j]; + r[j] = t + r[j + len]; + r[j + len] = t - r[j + len]; + r[j + len] = mld_fqmul(r[j + len], zeta); + } + } +} + +MLD_STATIC_TESTABLE void mld_poly_invntt_tomont_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +) +{ + unsigned int layer, j; + int32_t *r; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + r = a->coeffs; + for (layer = 8; layer >= 1; layer--) + __loop__( + invariant(layer <= 8) + /* Absolute bounds increase from 1Q before layer 8 */ + /* up to 256Q after layer 1 */ + invariant(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + mld_invntt_layer(r, layer); + } + + /* Coefficient bounds are now at 256Q. We now scale by mont / 256, + * i.e., compute the Montgomery multiplication by mont^2 / 256. + * mont corrects the mont^-1 factor introduced in the basemul. + * 1/256 performs that scaling of the inverse NTT. + * The reduced value is bounded by MLD_INTT_BOUND in absolute + * value.*/ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + invariant(j <= MLDSA_N) + invariant(array_abs_bound(r, 0, j, MLD_INTT_BOUND)) + invariant(array_abs_bound(r, j, MLDSA_N, MLDSA_N * MLDSA_Q)) + ) + { + r[j] = mld_fqscale(r[j]); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); +} + + +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_INTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_intt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_INTT */ + mld_poly_invntt_tomont_c(a); +} + +MLD_STATIC_TESTABLE void mld_poly_pointwise_montgomery_c(mld_poly *c, + const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_abs_bound(c->coeffs, 0, i, MLDSA_Q)) + ) + { + c->coeffs[i] = mld_montgomery_reduce((int64_t)a->coeffs[i] * b->coeffs[i]); + } + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +{ +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + ret = mld_poly_pointwise_montgomery_native(c->coeffs, a->coeffs, b->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + mld_poly_pointwise_montgomery_c(c, a, b); +} + +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, 0, i, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + invariant(array_bound(a1->coeffs, 0, i, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) + ) + { + mld_power2round(&a0->coeffs[i], &a1->coeffs[i], a->coeffs[i]); + } + + mld_assert_bound(a0->coeffs, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +#ifndef MLD_POLY_UNIFORM_NBLOCKS +#define MLD_POLY_UNIFORM_NBLOCKS \ + ((768 + MLD_STREAM128_BLOCKBYTES - 1) / MLD_STREAM128_BLOCKBYTES) +#endif +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +MLD_STATIC_TESTABLE unsigned int mld_rej_uniform_c(int32_t *a, + unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ + unsigned int ctr, pos; + uint32_t t; + mld_assert_bound(a, offset, 0, MLDSA_Q); + + ctr = offset; + pos = 0; + /* pos + 3 cannot overflow due to the assumption + buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) */ + while (ctr < target && pos + 3 <= buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_bound(a, 0, ctr, 0, MLDSA_Q))) + { + t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + a[ctr++] = (int32_t)t; + } + } + + mld_assert_bound(a, ctr, 0, MLDSA_Q); + + return ctr; +} +/************************************************* + * Name: mld_rej_uniform + * + * Description: Sample uniformly random coefficients in [0, MLDSA_Q-1] by + * performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes (must be + * multiple of 3) + * + * Returns number of sampled coefficients. Can be smaller than len if not enough + * random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +static unsigned int mld_rej_uniform(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) + int ret; + mld_assert_bound(a, offset, 0, MLDSA_Q); + if (offset == 0) + { + ret = mld_rej_uniform_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_bound(a, res, 0, MLDSA_Q); + return res; + } + } +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + + return mld_rej_uniform_c(a, target, offset, buf, buflen); +} + +/* Reference: poly_uniform() in the reference implementation @[REF]. + * - Simplified from reference by removing buffer tail handling + * since buflen % 3 = 0 always holds true (MLD_STREAM128_BLOCKBYTES + * = 168). + * - Modified rej_uniform interface to track offset directly. + * - Pass nonce packed in the extended seed array instead of a third + * argument. + * */ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +{ + unsigned int ctr; + unsigned int buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + MLD_ALIGN uint8_t buf[MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES]; + mld_xof128_ctx state; + + mld_xof128_init(&state); + mld_xof128_absorb_once(&state, seed, MLDSA_SEEDBYTES + 2); + mld_xof128_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, 0, buf, buflen); + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(a, sizeof(mld_poly)), object_whole(buf)) + invariant(ctr <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, ctr, 0, MLDSA_Q)) + invariant(state.pos <= SHAKE128_RATE) + ) + { + mld_xof128_squeezeblocks(buf, 1, &state); + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, ctr, buf, buflen); + } + mld_xof128_release(&state); + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof128_x4_ctx state; + unsigned buflen; + + mld_xof128_x4_init(&state); + mld_xof128_x4_absorb(&state, seed, MLDSA_SEEDBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_NBLOCKS. + * This should generate the matrix entries with high probability. + */ + + mld_xof128_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all matrix entries have been generated, squeeze + * one more block a time until we're done. + */ + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, object_whole(buf), + memory_slice(vec0, sizeof(mld_poly)), memory_slice(vec1, sizeof(mld_poly)), + memory_slice(vec2, sizeof(mld_poly)), memory_slice(vec3, sizeof(mld_poly))) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_bound(vec0->coeffs, 0, ctr[0], 0, MLDSA_Q)) + invariant(array_bound(vec1->coeffs, 0, ctr[1], 0, MLDSA_Q)) + invariant(array_bound(vec2->coeffs, 0, ctr[2], 0, MLDSA_Q)) + invariant(array_bound(vec3->coeffs, 0, ctr[3], 0, MLDSA_Q))) + { + mld_xof128_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + mld_xof128_x4_release(&state); + + mld_assert_bound(vec0->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec1->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec2->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec3->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0) & 0xFF); + r[5 * i + 1] = + (uint8_t)(((a->coeffs[4 * i + 0] >> 8) | (a->coeffs[4 * i + 1] << 2)) & + 0xFF); + r[5 * i + 2] = + (uint8_t)(((a->coeffs[4 * i + 1] >> 6) | (a->coeffs[4 * i + 2] << 4)) & + 0xFF); + r[5 * i + 3] = + (uint8_t)(((a->coeffs[4 * i + 2] >> 4) | (a->coeffs[4 * i + 3] << 6)) & + 0xFF); + r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, 0, 1 << 10))) + { + r->coeffs[4 * i + 0] = + ((a[5 * i + 0] >> 0) | ((int32_t)a[5 * i + 1] << 8)) & 0x3FF; + r->coeffs[4 * i + 1] = + ((a[5 * i + 1] >> 2) | ((int32_t)a[5 * i + 2] << 6)) & 0x3FF; + r->coeffs[4 * i + 2] = + ((a[5 * i + 2] >> 4) | ((int32_t)a[5 * i + 3] << 4)) & 0x3FF; + r->coeffs[4 * i + 3] = + ((a[5 * i + 3] >> 6) | ((int32_t)a[5 * i + 4] << 2)) & 0x3FF; + } + + mld_assert_bound(r->coeffs, MLDSA_N, 0, 1 << 10); +} + +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[8]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* Safety: a->coeffs[i] <= (1 << (MLDSA_D - 1) as they are output of + * power2round, hence, these casts are safe. */ + t[0] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 0]); + t[1] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 1]); + t[2] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 2]); + t[3] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 3]); + t[4] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 4]); + t[5] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 5]); + t[6] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 6]); + t[7] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 7]); + + r[13 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[13 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[13 * i + 1] |= (uint8_t)((t[1] << 5) & 0xFF); + r[13 * i + 2] = (uint8_t)((t[1] >> 3) & 0xFF); + r[13 * i + 3] = (uint8_t)((t[1] >> 11) & 0xFF); + r[13 * i + 3] |= (uint8_t)((t[2] << 2) & 0xFF); + r[13 * i + 4] = (uint8_t)((t[2] >> 6) & 0xFF); + r[13 * i + 4] |= (uint8_t)((t[3] << 7) & 0xFF); + r[13 * i + 5] = (uint8_t)((t[3] >> 1) & 0xFF); + r[13 * i + 6] = (uint8_t)((t[3] >> 9) & 0xFF); + r[13 * i + 6] |= (uint8_t)((t[4] << 4) & 0xFF); + r[13 * i + 7] = (uint8_t)((t[4] >> 4) & 0xFF); + r[13 * i + 8] = (uint8_t)((t[4] >> 12) & 0xFF); + r[13 * i + 8] |= (uint8_t)((t[5] << 1) & 0xFF); + r[13 * i + 9] = (uint8_t)((t[5] >> 7) & 0xFF); + r[13 * i + 9] |= (uint8_t)((t[6] << 6) & 0xFF); + r[13 * i + 10] = (uint8_t)((t[6] >> 2) & 0xFF); + r[13 * i + 11] = (uint8_t)((t[6] >> 10) & 0xFF); + r[13 * i + 11] |= (uint8_t)((t[7] << 3) & 0xFF); + r[13 * i + 12] = (uint8_t)((t[7] >> 5) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + { + r->coeffs[8 * i + 0] = a[13 * i + 0]; + r->coeffs[8 * i + 0] |= (int32_t)a[13 * i + 1] << 8; + r->coeffs[8 * i + 0] &= 0x1FFF; + + r->coeffs[8 * i + 1] = a[13 * i + 1] >> 5; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 2] << 3; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 3] << 11; + r->coeffs[8 * i + 1] &= 0x1FFF; + + r->coeffs[8 * i + 2] = a[13 * i + 3] >> 2; + r->coeffs[8 * i + 2] |= (int32_t)a[13 * i + 4] << 6; + r->coeffs[8 * i + 2] &= 0x1FFF; + + r->coeffs[8 * i + 3] = a[13 * i + 4] >> 7; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 5] << 1; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 6] << 9; + r->coeffs[8 * i + 3] &= 0x1FFF; + + r->coeffs[8 * i + 4] = a[13 * i + 6] >> 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 7] << 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 8] << 12; + r->coeffs[8 * i + 4] &= 0x1FFF; + + r->coeffs[8 * i + 5] = a[13 * i + 8] >> 1; + r->coeffs[8 * i + 5] |= (int32_t)a[13 * i + 9] << 7; + r->coeffs[8 * i + 5] &= 0x1FFF; + + r->coeffs[8 * i + 6] = a[13 * i + 9] >> 6; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 10] << 2; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 11] << 10; + r->coeffs[8 * i + 6] &= 0x1FFF; + + r->coeffs[8 * i + 7] = a[13 * i + 11] >> 3; + r->coeffs[8 * i + 7] |= (int32_t)a[13 * i + 12] << 5; + r->coeffs[8 * i + 7] &= 0x1FFF; + + r->coeffs[8 * i + 0] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 7]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +MLD_STATIC_TESTABLE uint32_t mld_poly_chknorm_c(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == array_abs_bound(a->coeffs, 0, i, B)) + ) + { + /* + * Since we know that -MLD_REDUCE32_RANGE_MAX <= a < MLD_REDUCE32_RANGE_MAX, + * and B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX, to check if + * -B < (a mod± MLDSA_Q) < B, it suffices to check if -B < a < B. + * + * We prove this to be true using the following CBMC assertions. + * a ==> b expressed as !a || b to also allow run-time assertion. + */ + mld_assert(a->coeffs[i] < B || a->coeffs[i] - MLDSA_Q <= -B); + mld_assert(a->coeffs[i] > -B || a->coeffs[i] + MLDSA_Q >= B); + + /* Reference: Leaks which coefficient violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + + /* if (abs(a[i]) >= B) */ + t |= mld_ct_cmask_neg_i32(B - 1 - mld_ct_abs_i32(a->coeffs[i])); + } + + return t; +} + +/* Reference: explicitly checks the bound B to be <= (MLDSA_Q - 1) / 8). + * This is unnecessary as it's always a compile-time constant. + * We instead model it as a precondition. + * Checking the bound is performed using a conditional arguing + * that it is okay to leak which coefficient violates the bound (while the + * coefficient itself must remain secret). + * We instead perform everything in constant-time. + * Also it is sufficient to check that it is smaller than + * MLDSA_Q - MLD_REDUCE32_RANGE_MAX > (MLDSA_Q - 1) / 8). + */ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +{ +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) + int ret; + int success; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + /* The native backend returns 0 if all coefficients are within the bound, + * 1 if at least one coefficient exceeds the bound, and + * -1 (MLD_NATIVE_FUNC_FALLBACK) if the platform does not have the + * required capabilities to run the native function. + */ + ret = mld_poly_chknorm_native(a->coeffs, B); + + success = (ret != MLD_NATIVE_FUNC_FALLBACK); + /* Constant-time: It would be fine to leak the return value of chknorm + * entirely (as it is fine to leak if any coefficient exceeded the bound or + * not). However, it is cleaner to perform declassification in sign.c. + * Hence, here we only declassify if the native function returned + * MLD_NATIVE_FUNC_FALLBACK or not (which solely depends on system + * capabilities). + */ + MLD_CT_TESTING_DECLASSIFY(&success, sizeof(int)); + if (success) + { + /* Convert 0 / 1 to 0 / 0xFFFFFFFF here */ + return 0U - (uint32_t)ret; + } +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + return mld_poly_chknorm_c(a, B); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ +MLD_EMPTY_CU(mld_poly) +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_POLY_UNIFORM_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/poly.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/poly.h new file mode 100644 index 0000000000..ff7710438e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/poly.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_H +#define MLD_POLY_H + +#include +#include "cbmc.h" +#include "common.h" +#include "reduce.h" +#include "rounding.h" + +/* Absolute exclusive upper bound for the output of the forward NTT */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) +/* Absolute exclusive upper bound for the output of the inverse NTT*/ +#define MLD_INTT_BOUND MLDSA_Q + +typedef struct +{ + int32_t coeffs[MLDSA_N]; +} MLD_ALIGN mld_poly; + +#define mld_poly_reduce MLD_NAMESPACE(poly_reduce) +/************************************************* + * Name: mld_poly_reduce + * + * Description: Inplace reduction of all coefficients of polynomial to + * representative in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) +); + +#define mld_poly_caddq MLD_NAMESPACE(poly_caddq) +/************************************************* + * Name: mld_poly_caddq + * + * Description: For all coefficients of in/out polynomial add MLDSA_Q if + * coefficient is negative. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_add MLD_NAMESPACE(poly_add) +/************************************************* + * Name: mld_poly_add + * + * Description: Add polynomials. No modular reduction is performed. + * + * Arguments: - r: Pointer to input-output polynomial to be added to. + * - b: Pointer to input polynomial that should be added + * to r. Must be disjoint from r. + **************************************************/ + +/* + * NOTE: The reference implementation uses a 3-argument poly_add. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(forall(k0, 0, MLDSA_N, (int64_t) r->coeffs[k0] + b->coeffs[k0] < MLD_REDUCE32_DOMAIN_MAX)) + requires(forall(k1, 0, MLDSA_N, (int64_t) r->coeffs[k1] + b->coeffs[k1] >= INT32_MIN)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(forall(k2, 0, MLDSA_N, r->coeffs[k2] == old(*r).coeffs[k2] + b->coeffs[k2])) + ensures(forall(k3, 0, MLDSA_N, r->coeffs[k3] < MLD_REDUCE32_DOMAIN_MAX)) + ensures(forall(k4, 0, MLDSA_N, r->coeffs[k4] >= INT32_MIN)) +); + +#define mld_poly_sub MLD_NAMESPACE(poly_sub) +/************************************************* + * Name: mld_poly_sub + * + * Description: Subtract polynomials. No modular reduction is + * performed. + * + * Arguments: - mld_poly *r: Pointer to input-output polynomial. + * - const mld_poly *b: Pointer to input polynomial that should be + * subtracted from r. Must be disjoint from r. + **************************************************/ +/* + * NOTE: The reference implementation uses a 3-argument poly_sub. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_Q)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) +); + +#define mld_poly_shiftl MLD_NAMESPACE(poly_shiftl) +/************************************************* + * Name: mld_poly_shiftl + * + * Description: Multiply polynomial by 2^MLDSA_D without modular reduction. + *Assumes input coefficients to be less than 2^{31-MLDSA_D} in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_ntt MLD_NAMESPACE(poly_ntt) +/************************************************* + * Name: mld_poly_ntt + * + * Description: Inplace forward NTT. Coefficients can grow by + * 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +); + + +#define mld_poly_invntt_tomont MLD_NAMESPACE(poly_invntt_tomont) +/************************************************* + * Name: mld_poly_invntt_tomont + * + * Description: Inplace inverse NTT and multiplication by 2^{32}. + * Input coefficients need to be less than MLDSA_Q in absolute + * value and output coefficients are bounded by + * MLD_INTT_BOUND. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +); + +#define mld_poly_pointwise_montgomery MLD_NAMESPACE(poly_pointwise_montgomery) +/************************************************* + * Name: mld_poly_pointwise_montgomery + * + * Description: Pointwise multiplication of polynomials in NTT domain + * representation and multiplication of resulting polynomial + * by 2^{-32}. + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const mld_poly *a: pointer to first input polynomial + * - const mld_poly *b: pointer to second input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + +#define mld_poly_power2round MLD_NAMESPACE(poly_power2round) +/************************************************* + * Name: mld_poly_power2round + * + * Description: For all coefficients c of the input polynomial, + * compute c0, c1 such that c mod MLDSA_Q = c1*2^MLDSA_D + c0 + * with -2^{MLDSA_D-1} < c0 <= 2^{MLDSA_D-1}. Assumes coefficients + *to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + *c1 + * - mld_poly *a0: pointer to output polynomial with coefficients + *c0 + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +__contract__( + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a0->coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) +); + +#define mld_poly_uniform MLD_NAMESPACE(poly_uniform) +/************************************************* + * Name: mld_poly_uniform + * + * Description: Sample polynomial with uniformly random coefficients + * in [0,MLDSA_Q-1] by performing rejection sampling on the + * output stream of SHAKE128(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_SEEDBYTES and the packed 2-byte nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES + 2)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +#define mld_poly_uniform_4x MLD_NAMESPACE(poly_uniform_4x) +/************************************************* + * Name: mld_poly_uniform_x4 + * + * Description: Generate four polynomials using rejection sampling + * on (pseudo-)uniformly random bytes sampled from a seed. + * + * Arguments: - mld_poly *vec0, *vec1, *vec2, *vec3: + * Pointers to 4 polynomials to be sampled. + * - uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]: + * Pointer consecutive array of seed buffers of size + * MLDSA_SEEDBYTES + 2 each, plus padding for alignment. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +__contract__( + requires(memory_no_alias(vec0, sizeof(mld_poly))) + requires(memory_no_alias(vec1, sizeof(mld_poly))) + requires(memory_no_alias(vec2, sizeof(mld_poly))) + requires(memory_no_alias(vec3, sizeof(mld_poly))) + requires(memory_no_alias(seed, 4 * MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2))) + assigns(memory_slice(vec0, sizeof(mld_poly))) + assigns(memory_slice(vec1, sizeof(mld_poly))) + assigns(memory_slice(vec2, sizeof(mld_poly))) + assigns(memory_slice(vec3, sizeof(mld_poly))) + ensures(array_bound(vec0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec1->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec2->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec3->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +#define mld_polyt1_pack MLD_NAMESPACE(polyt1_pack) +/************************************************* + * Name: mld_polyt1_pack + * + * Description: Bit-pack polynomial t1 with coefficients fitting in 10 bits. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(r, MLDSA_POLYT1_PACKEDBYTES)) +); + +#define mld_polyt1_unpack MLD_NAMESPACE(polyt1_unpack) +/************************************************* + * Name: mld_polyt1_unpack + * + * Description: Unpack polynomial t1 with 10-bit coefficients. + * Output coefficients are standard representatives. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT1_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, 0, 1 << 10)) +); + +#define mld_polyt0_pack MLD_NAMESPACE(polyt0_pack) +/************************************************* + * Name: mld_polyt0_pack + * + * Description: Bit-pack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + * 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) + assigns(memory_slice(r, MLDSA_POLYT0_PACKEDBYTES)) +); + + +#define mld_polyt0_unpack MLD_NAMESPACE(polyt0_unpack) +/************************************************* + * Name: mld_polyt0_unpack + * + * Description: Unpack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + *2^{MLDSA_D-1}]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT0_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) +); + +#define mld_poly_chknorm MLD_NAMESPACE(poly_chknorm) +/************************************************* + * Name: mld_poly_chknorm + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const mld_poly *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if norm is strictly smaller than + * B <= (MLDSA_Q - MLD_REDUCE32_RANGE_MAX) and 0xFFFFFFFF otherwise. + * + * Specification: The definition of this FIPS-204 requires signed canonical + * reduction prior to applying the bounds check. + * However, `-B < (a mod± MLDSA_Q) < B` is equivalent to + * `-B < a < B` under the assumption that + * `B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX` (cf. the assertion in + * the code). Hence, the present spec and implementation are + * correct without reduction. + * + **************************************************/ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +); + +#endif /* !MLD_POLY_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/poly_kl.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/poly_kl.c new file mode 100644 index 0000000000..7a319ca515 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/poly_kl.c @@ -0,0 +1,931 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "ct.h" +#include "debug.h" +#include "poly_kl.h" +#include "rounding.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_rej_eta MLD_ADD_PARAM_SET(mld_rej_eta) +#define mld_rej_eta_c MLD_ADD_PARAM_SET(mld_rej_eta_c) +#define mld_poly_decompose_c MLD_ADD_PARAM_SET(mld_poly_decompose_c) +#define mld_poly_use_hint_c MLD_ADD_PARAM_SET(mld_poly_use_hint_c) +#define mld_polyz_unpack_c MLD_ADD_PARAM_SET(mld_polyz_unpack_c) +/* End of parameter set namespacing */ + + +MLD_STATIC_TESTABLE +void mld_poly_decompose_c(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +) +{ + unsigned int i; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, i, MLDSA_N, 0, MLDSA_Q)) + invariant(array_bound(a1->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + invariant(array_abs_bound(a0->coeffs, 0, i, MLDSA_GAMMA2+1)) + ) + { + mld_decompose(&a0->coeffs[i], &a1->coeffs[i], a0->coeffs[i]); + } + + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +{ +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_88_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_32_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_DECOMPOSE_88 && MLD_CONFIG_PARAMETER_SET == \ + 44) && MLD_USE_NATIVE_POLY_DECOMPOSE_32 && (MLD_CONFIG_PARAMETER_SET \ + == 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_decompose_c(a1, a0); +} + +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(s <= i) + invariant(array_bound(h->coeffs, 0, i, 0, 2)) + ) + { + const unsigned int hint_bit = mld_make_hint(a0->coeffs[i], a1->coeffs[i]); + h->coeffs[i] = (int32_t)hint_bit; + s += hint_bit; + } + + mld_assert(s <= MLDSA_N); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + return s; +} + +MLD_STATIC_TESTABLE void mld_poly_use_hint_c(mld_poly *b, const mld_poly *a, + const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(b->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ) + { + b->coeffs[i] = mld_use_hint(a->coeffs[i], h->coeffs[i]); + } + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +{ +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_88_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_USE_HINT_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_32_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_USE_HINT_88 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLY_USE_HINT_32 && (MLD_CONFIG_PARAMETER_SET == \ + 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_use_hint_c(b, a, h); +} + +/************************************************* + * Name: mld_rej_eta + * + * Description: Sample uniformly random coefficients in [-MLDSA_ETA, MLDSA_ETA] + *by performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes + * + * Returns number of sampled coefficients. Can be smaller than target if not + *enough random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_eta()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +#if MLDSA_ETA == 2 +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 1 +#elif MLDSA_ETA == 4 +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 2 +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + +MLD_STATIC_TESTABLE unsigned int mld_rej_eta_c(int32_t *a, unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ + unsigned int ctr, pos; + int t_valid; + uint32_t t0, t1; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + ctr = offset; + pos = 0; + while (ctr < target && pos < buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_abs_bound(a, 0, ctr, MLDSA_ETA + 1)) + ) + { + t0 = buf[pos] & 0x0F; + t1 = buf[pos++] >> 4; + + /* Constant time: The inputs and outputs to the rejection sampling are + * secret. However, it is fine to leak which coefficients have been + * rejected. For constant-time testing, we declassify the result of + * the comparison. + */ +#if MLDSA_ETA == 2 + t_valid = t0 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 15 */ + { + t0 = t0 - (205 * t0 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t0; + } + t_valid = t1 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) /* t1 < 15 */ + { + t1 = t1 - (205 * t1 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t1; + } +#elif MLDSA_ETA == 4 + t_valid = t0 < 9; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 9 */ + { + a[ctr++] = 4 - (int32_t)t0; + } + t_valid = t1 < 9; /* t1 < 9 */ + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) + { + a[ctr++] = 4 - (int32_t)t1; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + } + + mld_assert_abs_bound(a, ctr, MLDSA_ETA + 1); + + return ctr; +} + +static unsigned int mld_rej_eta(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ +#if MLDSA_ETA == 2 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta2_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#elif MLDSA_ETA == 4 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta4_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#endif /* !(MLDSA_ETA == 2 && MLD_USE_NATIVE_REJ_UNIFORM_ETA2) && MLDSA_ETA == \ + 4 && MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + + return mld_rej_eta_c(a, target, offset, buf, buflen); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_ETA_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof256_x4_ctx state; + unsigned buflen; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = nonce0; + extseed[1][MLDSA_CRHBYTES] = nonce1; + extseed[2][MLDSA_CRHBYTES] = nonce2; + extseed[3][MLDSA_CRHBYTES] = nonce3; + extseed[0][MLDSA_CRHBYTES + 1] = 0; + extseed[1][MLDSA_CRHBYTES + 1] = 0; + extseed[2][MLDSA_CRHBYTES + 1] = 0; + extseed[3][MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(r0, sizeof(mld_poly)), + memory_slice(r1, sizeof(mld_poly)), memory_slice(r2, sizeof(mld_poly)), + memory_slice(r3, sizeof(mld_poly)), object_whole(buf[0]), + object_whole(buf[1]), object_whole(buf[2]), + object_whole(buf[3])) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_abs_bound(r0->coeffs, 0, ctr[0], MLDSA_ETA + 1)) + invariant(array_abs_bound(r1->coeffs, 0, ctr[1], MLDSA_ETA + 1)) + invariant(array_abs_bound(r2->coeffs, 0, ctr[2], MLDSA_ETA + 1)) + invariant(array_abs_bound(r3->coeffs, 0, ctr[3], MLDSA_ETA + 1))) + { + mld_xof256_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + + mld_xof256_x4_release(&state); + + mld_assert_abs_bound(r0->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r1->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r2->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r3->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +{ + /* Temporary buffer for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr; + mld_xof256_ctx state; + unsigned buflen; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = nonce; + extseed[MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr = mld_rej_eta(r->coeffs, MLDSA_N, 0, buf, buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, object_whole(&state), + object_whole(buf), memory_slice(r, sizeof(mld_poly))) + invariant(ctr <= MLDSA_N) + invariant(state.pos <= SHAKE256_RATE) + invariant(array_abs_bound(r->coeffs, 0, ctr, MLDSA_ETA + 1))) + { + mld_xof256_squeezeblocks(buf, 1, &state); + ctr = mld_rej_eta(r->coeffs, MLDSA_N, ctr, buf, buflen); + } + + mld_xof256_release(&state); + + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define MLD_POLY_UNIFORM_GAMMA1_NBLOCKS \ + ((MLDSA_POLYZ_PACKEDBYTES + MLD_STREAM256_BLOCKBYTES - 1) / \ + MLD_STREAM256_BLOCKBYTES) + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + mld_xof256_ctx state; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = (uint8_t)(nonce & 0xFF); + extseed[MLDSA_CRHBYTES + 1] = (uint8_t)(nonce >> 8); + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + mld_polyz_unpack(a, buf); + + mld_xof256_release(&state); + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + mld_xof256_x4_ctx state; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = (uint8_t)(nonce0 & 0xFF); + extseed[1][MLDSA_CRHBYTES] = (uint8_t)(nonce1 & 0xFF); + extseed[2][MLDSA_CRHBYTES] = (uint8_t)(nonce2 & 0xFF); + extseed[3][MLDSA_CRHBYTES] = (uint8_t)(nonce3 & 0xFF); + extseed[0][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce0 >> 8); + extseed[1][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce1 >> 8); + extseed[2][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce2 >> 8); + extseed[3][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce3 >> 8); + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + + mld_polyz_unpack(r0, buf[0]); + mld_polyz_unpack(r1, buf[1]); + mld_polyz_unpack(r2, buf[2]); + mld_polyz_unpack(r3, buf[3]); + mld_xof256_x4_release(&state); + + mld_assert_bound(r0->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r1->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r2->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r3->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +{ + unsigned int i, j, pos; + uint64_t signs; + uint64_t offset; + MLD_ALIGN uint8_t buf[SHAKE256_RATE]; + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, seed, MLDSA_CTILDEBYTES); + mld_shake256_finalize(&state); + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + + /* Convert the first 8 bytes of buf[] into an unsigned 64-bit value. */ + /* Each bit of that dictates the sign of the resulting challenge value */ + signs = 0; + for (i = 0; i < 8; ++i) + __loop__( + assigns(i, signs) + invariant(i <= 8) + ) + { + signs |= (uint64_t)buf[i] << 8 * i; + } + pos = 8; + + mld_memset(c, 0, sizeof(mld_poly)); + + for (i = MLDSA_N - MLDSA_TAU; i < MLDSA_N; ++i) + __loop__( + assigns(i, j, object_whole(buf), state, pos, memory_slice(c, sizeof(mld_poly)), signs) + invariant(i >= MLDSA_N - MLDSA_TAU) + invariant(i <= MLDSA_N) + invariant(pos >= 1) + invariant(pos <= SHAKE256_RATE) + invariant(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) + invariant(state.pos <= SHAKE256_RATE) + ) + { + do + __loop__( + assigns(j, object_whole(buf), state, pos) + invariant(state.pos <= SHAKE256_RATE) + ) + { + if (pos >= SHAKE256_RATE) + { + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + pos = 0; + } + j = buf[pos++]; + } while (j > i); + + c->coeffs[i] = c->coeffs[j]; + + /* Reference: Compute coefficent value here in two steps to */ + /* mixinf unsigned and signed arithmetic with implicit */ + /* conversions, and so that CBMC can keep track of ranges */ + /* to complete type-safety proof here. */ + + /* The least-significant bit of signs tells us if we want -1 or +1 */ + offset = 2 * (signs & 1); + + /* offset has value 0 or 2 here, so (1 - (int32_t) offset) has + * value -1 or +1 */ + c->coeffs[j] = 1 - (int32_t)offset; + + /* Move to the next bit of signs for next time */ + signs >>= 1; + } + + mld_assert_bound(c->coeffs, MLDSA_N, -1, 2); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(&signs, sizeof(signs)); +} + +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint8_t t[8]; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_ETA + 1); + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 1]); + t[2] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 2]); + t[3] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 3]); + t[4] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 4]); + t[5] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 5]); + t[6] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 6]); + t[7] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 7]); + + r[3 * i + 0] = (uint8_t)(((t[0] >> 0) | (t[1] << 3) | (t[2] << 6)) & 0xFF); + r[3 * i + 1] = + (uint8_t)(((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)) & + 0xFF); + r[3 * i + 2] = (uint8_t)(((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)) & 0xFF); + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 1]); + r[i] = (uint8_t)(t[0] | (t[1] << 4)); + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ +} + +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -5, MLDSA_ETA + 1))) + { + r->coeffs[8 * i + 0] = (a[3 * i + 0] >> 0) & 7; + r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 7; + r->coeffs[8 * i + 2] = ((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 7; + r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 7; + r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 7; + r->coeffs[8 * i + 5] = ((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 7; + r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 7; + r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5) & 7; + + r->coeffs[8 * i + 0] = MLDSA_ETA - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = MLDSA_ETA - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = MLDSA_ETA - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = MLDSA_ETA - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = MLDSA_ETA - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = MLDSA_ETA - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = MLDSA_ETA - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = MLDSA_ETA - r->coeffs[8 * i + 7]; + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -11, MLDSA_ETA + 1))) + { + r->coeffs[2 * i + 0] = a[i] & 0x0F; + r->coeffs[2 * i + 1] = a[i] >> 4; + r->coeffs[2 * i + 0] = MLDSA_ETA - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_ETA - r->coeffs[2 * i + 1]; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + + mld_assert_bound(r->coeffs, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + + +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[4]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 1]); + t[2] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 2]); + t[3] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 3]); + + r[9 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[9 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[9 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[9 * i + 2] |= (uint8_t)((t[1] << 2) & 0xFF); + r[9 * i + 3] = (uint8_t)((t[1] >> 6) & 0xFF); + r[9 * i + 4] = (uint8_t)((t[1] >> 14) & 0xFF); + r[9 * i + 4] |= (uint8_t)((t[2] << 4) & 0xFF); + r[9 * i + 5] = (uint8_t)((t[2] >> 4) & 0xFF); + r[9 * i + 6] = (uint8_t)((t[2] >> 12) & 0xFF); + r[9 * i + 6] |= (uint8_t)((t[3] << 6) & 0xFF); + r[9 * i + 7] = (uint8_t)((t[3] >> 2) & 0xFF); + r[9 * i + 8] = (uint8_t)((t[3] >> 10) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 1]); + + r[5 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[5 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[5 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[5 * i + 2] |= (uint8_t)((t[1] << 4) & 0xFF); + r[5 * i + 3] = (uint8_t)((t[1] >> 4) & 0xFF); + r[5 * i + 4] = (uint8_t)((t[1] >> 12) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +MLD_STATIC_TESTABLE void mld_polyz_unpack_c( + mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +) +{ + unsigned int i; +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[4 * i + 0] = a[9 * i + 0]; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 2] << 16; + r->coeffs[4 * i + 0] &= 0x3FFFF; + + r->coeffs[4 * i + 1] = a[9 * i + 2] >> 2; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 3] << 6; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 4] << 14; + r->coeffs[4 * i + 1] &= 0x3FFFF; + + r->coeffs[4 * i + 2] = a[9 * i + 4] >> 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 5] << 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 6] << 12; + r->coeffs[4 * i + 2] &= 0x3FFFF; + + r->coeffs[4 * i + 3] = a[9 * i + 6] >> 6; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 7] << 2; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10; + r->coeffs[4 * i + 3] &= 0x3FFFF; + + r->coeffs[4 * i + 0] = MLDSA_GAMMA1 - r->coeffs[4 * i + 0]; + r->coeffs[4 * i + 1] = MLDSA_GAMMA1 - r->coeffs[4 * i + 1]; + r->coeffs[4 * i + 2] = MLDSA_GAMMA1 - r->coeffs[4 * i + 2]; + r->coeffs[4 * i + 3] = MLDSA_GAMMA1 - r->coeffs[4 * i + 3]; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[2 * i + 0] = a[5 * i + 0]; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 2] << 16; + r->coeffs[2 * i + 0] &= 0xFFFFF; + + r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 3] << 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12; + /* r->coeffs[2*i+1] &= 0xFFFFF; */ /* No effect, since we're anyway at 20 + bits */ + + r->coeffs[2 * i + 0] = MLDSA_GAMMA1 - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_GAMMA1 - r->coeffs[2 * i + 1]; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +{ +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + ret = mld_polyz_unpack_17_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#elif defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + ret = mld_polyz_unpack_19_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYZ_UNPACK_17 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLYZ_UNPACK_19 && (MLD_CONFIG_PARAMETER_SET == 65 \ + || MLD_CONFIG_PARAMETER_SET == 87) */ + + mld_polyz_unpack_c(r, a); +} + +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + + mld_assert_bound(a->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[3 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0]) & 0xFF); + r[3 * i + 0] |= (uint8_t)((a->coeffs[4 * i + 1] << 6) & 0xFF); + r[3 * i + 1] = (uint8_t)((a->coeffs[4 * i + 1] >> 2) & 0xFF); + r[3 * i + 1] |= (uint8_t)((a->coeffs[4 * i + 2] << 4) & 0xFF); + r[3 * i + 2] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) & 0xFF); + r[3 * i + 2] |= (uint8_t)((a->coeffs[4 * i + 3] << 2) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + r[i] = + (uint8_t)((a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_rej_eta +#undef mld_rej_eta_c +#undef mld_poly_decompose_c +#undef mld_poly_use_hint_c +#undef mld_polyz_unpack_c +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_GAMMA1_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/poly_kl.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/poly_kl.h new file mode 100644 index 0000000000..c6aa498358 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/poly_kl.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_KL_H +#define MLD_POLY_KL_H + +#include "cbmc.h" +#include "common.h" +#include "poly.h" + +#define mld_poly_decompose MLD_NAMESPACE_KL(poly_decompose) +/************************************************* + * Name: mld_poly_decompose + * + * Description: For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such c mod MLDSA_Q = c1*ALPHA + + * c0 with -ALPHA/2 < c0 <= ALPHA/2 except + * c1 = (MLDSA_Q-1)/ALPHA where we set + * c1 = 0 and -ALPHA/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + * c1 + * - mld_poly *a0: pointer to input/output polynomial. Output + * polynomial has coefficients c0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +); + + +#define mld_poly_make_hint MLD_NAMESPACE_KL(poly_make_hint) +/************************************************* + * Name: mld_poly_make_hint + * + * Description: Compute hint polynomial. The coefficients of which indicate + * whether the low bits of the corresponding coefficient of + * the input polynomial overflow into the high bits. + * + * Arguments: - mld_poly *h: pointer to output hint polynomial + * - const mld_poly *a0: pointer to low part of input polynomial + * - const mld_poly *a1: pointer to high part of input polynomial + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + assigns(memory_slice(h, sizeof(mld_poly))) + ensures(return_value <= MLDSA_N) + ensures(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) +); + +#define mld_poly_use_hint MLD_NAMESPACE_KL(poly_use_hint) +/************************************************* + * Name: mld_poly_use_hint + * + * Description: Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - mld_poly *b: pointer to output polynomial with corrected high + *bits + * - const mld_poly *a: pointer to input polynomial + * - const mld_poly *h: pointer to input hint polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta_4x MLD_NAMESPACE_KL(poly_uniform_eta_4x) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample four polynomials with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce_i) + * + * Arguments: - mld_poly *r0: pointer to first output polynomial + * - mld_poly *r1: pointer to second output polynomial + * - mld_poly *r2: pointer to third output polynomial + * - mld_poly *r3: pointer to fourth output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce0: first nonce + * - uint8_t nonce1: second nonce + * - uint8_t nonce2: third nonce + * - uint8_t nonce3: fourth nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_abs_bound(r0->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r1->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r2->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r3->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta MLD_NAMESPACE_KL(poly_uniform_eta) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample polynomial with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce: nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1 MLD_NAMESPACE_KL(poly_uniform_gamma1) +/************************************************* + * Name: mld_poly_uniform_gamma1 + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1_4x MLD_NAMESPACE_KL(poly_uniform_gamma1_4x) +/************************************************* + * Name: mld_poly_uniform_gamma1_4x + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_bound(r0->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r1->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r2->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r3->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define mld_poly_challenge MLD_NAMESPACE_KL(poly_challenge) +/************************************************* + * Name: mld_poly_challenge + * + * Description: Implementation of H. Samples polynomial with MLDSA_TAU nonzero + * coefficients in {-1,1} using the output stream of + * SHAKE256(seed). + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const uint8_t mu[]: byte array containing seed of length + * MLDSA_CTILDEBYTES + **************************************************/ +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +__contract__( + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CTILDEBYTES)) + assigns(memory_slice(c, sizeof(mld_poly))) + /* All coefficients of c are -1, 0 or +1 */ + ensures(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) +); + +#define mld_polyeta_pack MLD_NAMESPACE_KL(polyeta_pack) +/************************************************* + * Name: mld_polyeta_pack + * + * Description: Bit-pack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYETA_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + assigns(memory_slice(r, MLDSA_POLYETA_PACKEDBYTES)) +); + +/* + * polyeta_unpack produces coefficients in [-MLDSA_ETA,MLDSA_ETA] for + * well-formed inputs (i.e., those produced by polyeta_pack). + * However, when passed an arbitrary byte array, it may produce smaller values, + * i.e, values in [MLD_POLYETA_UNPACK_LOWER_BOUND,MLDSA_ETA] + * Even though this should never happen, we use use the bound for arbitrary + * inputs in the CBMC proofs. + */ +#if MLDSA_ETA == 2 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-5) +#elif MLDSA_ETA == 4 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-11) +#else +#error "Invalid value of MLDSA_ETA" +#endif + +#define mld_polyeta_unpack MLD_NAMESPACE_KL(polyeta_unpack) +/************************************************* + * Name: mld_polyeta_unpack + * + * Description: Unpack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYETA_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)) +); + +#define mld_polyz_pack MLD_NAMESPACE_KL(polyz_pack) +/************************************************* + * Name: mld_polyz_pack + * + * Description: Bit-pack polynomial with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYZ_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(r, MLDSA_POLYZ_PACKEDBYTES)) +); + + +#define mld_polyz_unpack MLD_NAMESPACE_KL(polyz_unpack) +/************************************************* + * Name: mld_polyz_unpack + * + * Description: Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); + +#define mld_polyw1_pack MLD_NAMESPACE_KL(polyw1_pack) +/************************************************* + * Name: mld_polyw1_pack + * + * Description: Bit-pack polynomial w1 with coefficients in [0,15] or [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES)) +); + +#endif /* !MLD_POLY_KL_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/polyvec.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/polyvec.c new file mode 100644 index 0000000000..5c3a08ab32 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/polyvec.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include +#include + +#include "common.h" +#include "debug.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" + +/* This namespacing is not done at the top to avoid a naming conflict + * with native backends, which are currently not yet namespaced. */ +#define mld_polymat_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polymat_permute_bitrev_to_custom) +#define mld_polyvecl_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polyvecl_permute_bitrev_to_custom) +#define mld_polyvecl_pointwise_acc_montgomery_c \ + MLD_ADD_PARAM_SET(mld_polyvecl_pointwise_acc_montgomery_c) + +#if !defined(MLD_CONFIG_REDUCE_RAM) +/* Helper function to ensure that the polynomial entries in the output + * of mld_polyvec_matrix_expand use the standard (bitreversed) ordering + * of coefficients. + * No-op unless a native backend with a custom ordering is used. + */ + +static void mld_polyvecl_permute_bitrev_to_custom(mld_polyvecl *v) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +{ +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + unsigned i; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_permute_bitrev_to_custom(v->vec[i].coeffs); + } +#else /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + /* Nothing to do */ + (void)v; +#endif /* !MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ +} + +static void mld_polymat_permute_bitrev_to_custom(mld_polymat *mat) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; i++) + __loop__( + assigns(i, memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))) + { + mld_polyvecl_permute_bitrev_to_custom(&mat->vec[i]); + } +} +#endif /* !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + unsigned int i; + MLD_ALIGN uint8_t seed_ext[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + mld_memcpy(seed_ext, mat->rho, MLDSA_SEEDBYTES); + + /* Generate row on-demand */ + for (i = 0; i < MLDSA_L; i++) + { + uint8_t x = (uint8_t)row; + uint8_t y = (uint8_t)i; + + seed_ext[MLDSA_SEEDBYTES + 0] = y; + seed_ext[MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(&mat->row_buffer.vec[i], seed_ext); + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + mld_poly_permute_bitrev_to_custom(mat->row_buffer.vec[i].coeffs); +#endif + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); + + return &mat->row_buffer; +#else /* MLD_CONFIG_REDUCE_RAM */ + return &mat->vec[row]; +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + /* In REDUCE_RAM mode, just copy the seed for later on-demand generation */ + mld_memcpy(mat->rho, rho, MLDSA_SEEDBYTES); +#else + unsigned int i, j; + /* + * We generate four separate seed arrays rather than a single one to work + * around limitations in CBMC function contracts dealing with disjoint slices + * of the same parent object. + */ + + MLD_ALIGN uint8_t seed_ext[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + mld_memcpy(seed_ext[j], rho, MLDSA_SEEDBYTES); + } + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + /* Sample 4 matrix entries a time. */ + for (i = 0; i < (MLDSA_K * MLDSA_L / 4) * 4; i += 4) + __loop__( + assigns(i, j, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= (MLDSA_K * MLDSA_L / 4) * 4 && i % 4 == 0) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + uint8_t x = (uint8_t)((i + j) / MLDSA_L); + uint8_t y = (uint8_t)((i + j) % MLDSA_L); + + seed_ext[j][MLDSA_SEEDBYTES + 0] = y; + seed_ext[j][MLDSA_SEEDBYTES + 1] = x; + } + + mld_poly_uniform_4x(&mat->vec[i / MLDSA_L].vec[i % MLDSA_L], + &mat->vec[(i + 1) / MLDSA_L].vec[(i + 1) % MLDSA_L], + &mat->vec[(i + 2) / MLDSA_L].vec[(i + 2) % MLDSA_L], + &mat->vec[(i + 3) / MLDSA_L].vec[(i + 3) % MLDSA_L], + seed_ext); + } +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + i = 0; +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + /* Entries omitted by the batch-sampling are sampled individually. */ + while (i < MLDSA_K * MLDSA_L) + __loop__( + assigns(i, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K * MLDSA_L) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + uint8_t x = (uint8_t)(i / MLDSA_L); + uint8_t y = (uint8_t)(i % MLDSA_L); + mld_poly *this_poly = &mat->vec[i / MLDSA_L].vec[i % MLDSA_L]; + + seed_ext[0][MLDSA_SEEDBYTES + 0] = y; + seed_ext[0][MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(this_poly, seed_ext[0]); + i++; + } + + mld_polymat_permute_bitrev_to_custom(mat); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(t, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + const mld_polyvecl *row = mld_polymat_get_row(mat, i); + mld_polyvecl_pointwise_acc_montgomery(&t->vec[i], row, v); + } + + mld_assert_abs_bound_2d(t->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_L **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; +#endif + + /* Safety: nonce is at most ((UINT16_MAX - MLDSA_L) / MLDSA_L), and, hence, + * this cast is safe. See MLD_NONCE_UB comment in sign.c. */ + nonce = (uint16_t)(MLDSA_L * nonce); + /* Now, nonce <= UINT16_MAX - (MLDSA_L - 1), so the casts below are safe. */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_gamma1(&v->vec[i], seed, (uint16_t)(nonce + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLDSA_L == 4 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); +#elif MLDSA_L == 5 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); + mld_poly_uniform_gamma1(&v->vec[4], seed, (uint16_t)(nonce + 4)); +#elif MLDSA_L == 7 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], + &v->vec[3 /* irrelevant */], seed, nonce, + (uint16_t)(nonce + 1), (uint16_t)(nonce + 2), + 0xFF /* irrelevant */); + mld_poly_uniform_gamma1_4x(&v->vec[3], &v->vec[4], &v->vec[5], &v->vec[6], + seed, (uint16_t)(nonce + 3), (uint16_t)(nonce + 4), + (uint16_t)(nonce + 5), (uint16_t)(nonce + 6)); +#endif /* MLDSA_L == 7 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(k0, i, MLDSA_L, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_STATIC_TESTABLE void mld_polyvecl_pointwise_acc_montgomery_c( + mld_poly *w, const mld_polyvecl *u, const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i, j; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + for (i = 0; i < MLDSA_N; i++) + __loop__( + assigns(i, j, memory_slice(w, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_abs_bound(w->coeffs, 0, i, MLDSA_Q)) + ) + { + int64_t t = 0; + int32_t r; + for (j = 0; j < MLDSA_L; j++) + __loop__( + assigns(j, t) + invariant(j <= MLDSA_L) + invariant(t >= -(int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + invariant(t <= (int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + ) + { + t += (int64_t)u->vec[j].coeffs[i] * v->vec[j].coeffs[i]; + } + + r = mld_montgomery_reduce(t); + w->coeffs[i] = r; + } + + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +{ +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) && \ + MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l4_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) && \ + MLD_CONFIG_PARAMETER_SET == 65 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l5_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) && \ + MLD_CONFIG_PARAMETER_SET == 87 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l7_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 && \ + MLD_CONFIG_PARAMETER_SET == 44) && \ + !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 && \ + MLD_CONFIG_PARAMETER_SET == 65) && \ + MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 && \ + MLD_CONFIG_PARAMETER_SET == 87 */ + /* The first input is bounded by [0, Q-1] inclusive + * The second input is bounded by [-9Q+1, 9Q-1] inclusive . Hence, we can + * safely accumulate in 64-bits without intermediate reductions as + * MLDSA_L * (MLD_NTT_BOUND-1) * (Q-1) < INT64_MAX + * + * The worst case is ML-DSA-87: 7 * (9Q-1) * (Q-1) < 2**52 + * (and likewise for negative values) + */ + mld_polyvecl_pointwise_acc_montgomery_c(w, u, v); +} + +MLD_INTERNAL_API +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + invariant(i <= MLDSA_L) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + return t; +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_K **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k2, 0, i, + array_bound(v->vec[k2].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ) + { + mld_poly_reduce(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_caddq(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, + forall(k1, 0, MLDSA_N, u->vec[k0].coeffs[k1] == loop_entry(*u).vec[k0].coeffs[k1]))) + invariant(forall(k6, 0, i, array_bound(u->vec[k6].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + ) + { + mld_poly_add(&u->vec[i], &v->vec[i]); + } + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(u->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, u->vec[k1].coeffs[n1] == loop_entry(*u).vec[k1].coeffs[n1])))) + { + mld_poly_sub(&u->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, v->vec[k1].coeffs[n1] == loop_entry(*v).vec[k1].coeffs[n1]))) + ) + { + mld_poly_shiftl(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))) + { + mld_poly_invntt_tomont(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_INTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, array_abs_bound(r->vec[k2].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + mld_poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]); + } + mld_assert_abs_bound_2d(r->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + + return t; +} + +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + invariant(forall(k2, 0, i, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) + ) + { + mld_poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +{ + unsigned int i; + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + invariant(forall(k2, 0, i, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) + invariant(forall(k3, i, MLDSA_K, + array_bound(v0->vec[k3].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + ) + { + mld_poly_decompose(&v1->vec[i], &v0->vec[i]); + } + + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + mld_assert_abs_bound_2d(v0->vec, MLDSA_K, MLDSA_N, MLDSA_GAMMA2 + 1); +} + +MLD_INTERNAL_API +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, s, memory_slice(h, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(s <= i * MLDSA_N) + invariant(forall(k1, 0, i, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + s += mld_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]); + } + + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + return s; +} + +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *u, + const mld_polyveck *h) +{ + unsigned int i; + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(w, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)))) + ) + { + mld_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]); + } + + mld_assert_bound_2d(w->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +{ + unsigned int i; + mld_assert_bound_2d(w1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyw1_pack(&r[i * MLDSA_POLYW1_PACKEDBYTES], &w1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt0_pack(&r[i * MLDSA_POLYT0_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyz_unpack(&z->vec[i], r + i * MLDSA_POLYZ_PACKEDBYTES); + } + + mld_assert_bound_2d(z->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt0_unpack(&p->vec[i], r + i * MLDSA_POLYT0_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_polymat_permute_bitrev_to_custom +#undef mld_polyvecl_permute_bitrev_to_custom +#undef mld_polyvecl_pointwise_acc_montgomery_c diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/polyvec.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/polyvec.h new file mode 100644 index 0000000000..d21abc02ff --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/polyvec.h @@ -0,0 +1,725 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLYVEC_H +#define MLD_POLYVEC_H + +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "poly_kl.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_polyvecl MLD_ADD_PARAM_SET(mld_polyvecl) +#define mld_polyveck MLD_ADD_PARAM_SET(mld_polyveck) +#define mld_polymat MLD_ADD_PARAM_SET(mld_polymat) +/* End of parameter set namespacing */ + +/* Vectors of polynomials of length MLDSA_L */ +typedef struct +{ + mld_poly vec[MLDSA_L]; +} mld_polyvecl; + + +#define mld_polyvecl_uniform_gamma1 MLD_NAMESPACE_KL(polyvecl_uniform_gamma1) +/************************************************* + * Name: mld_polyvecl_uniform_gamma1 + * + * Description: Sample vector of polynomials with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_polyvecl *v: pointer to output vector + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + *************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + requires(nonce <= (UINT16_MAX - MLDSA_L) / MLDSA_L) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyvecl_ntt MLD_NAMESPACE_KL(polyvecl_ntt) +/************************************************* + * Name: mld_polyvecl_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_L. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyvecl *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k0, 0, MLDSA_L, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyvecl_pointwise_acc_montgomery \ + MLD_NAMESPACE_KL(polyvecl_pointwise_acc_montgomery) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery + * + * Description: Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * The first input "u" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * + * Arguments: - mld_poly *w: output polynomial + * - const mld_polyvecl *u: pointer to first input vector + * - const mld_polyvecl *v: pointer to second input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + + +#define mld_polyvecl_chknorm MLD_NAMESPACE_KL(polyvecl_chknorm) +/************************************************* + * Name: mld_polyvecl_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_L. + * Assumes input mld_polyvecl to be reduced by polyvecl_reduce(). + * + * Arguments: - const mld_polyvecl *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials is strictly smaller than B <= + * (MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +/* Vectors of polynomials of length MLDSA_K */ +typedef struct +{ + mld_poly vec[MLDSA_K]; +} mld_polyveck; + +/* Matrix of polynomials (K x L) */ +typedef struct +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + mld_polyvecl row_buffer; + uint8_t rho[MLDSA_SEEDBYTES]; +#else + mld_polyvecl vec[MLDSA_K]; +#endif +} mld_polymat; + +#define mld_polyveck_reduce MLD_NAMESPACE_KL(polyveck_reduce) +/************************************************* + * Name: polyveck_reduce + * + * Description: Reduce coefficients of polynomials in vector of length MLDSA_K + * to representatives in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) +); + +#define mld_polyveck_caddq MLD_NAMESPACE_KL(polyveck_caddq) +/************************************************* + * Name: mld_polyveck_caddq + * + * Description: For all coefficients of polynomials in vector of length MLDSA_K + * add MLDSA_Q if coefficient is negative. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_add MLD_NAMESPACE_KL(polyveck_add) +/************************************************* + * Name: mld_polyveck_add + * + * Description: Add vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to input-output vector of polynomials + * to be added to + * - const mld_polyveck *v: pointer to second input vector of + * polynomials + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(p0, 0, MLDSA_K, array_abs_bound(u->vec[p0].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) + requires(forall(p1, 0, MLDSA_K, + array_bound(v->vec[p1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(q2, 0, MLDSA_K, + array_bound(u->vec[q2].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_sub MLD_NAMESPACE_KL(polyveck_sub) +/************************************************* + * Name: mld_polyveck_sub + * + * Description: Subtract vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to first input vector + * - const mld_polyveck *v: pointer to second input vector to be + * subtracted from first input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(u->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_shiftl MLD_NAMESPACE_KL(polyveck_shiftl) +/************************************************* + * Name: mld_polyveck_shiftl + * + * Description: Multiply vector of polynomials of Length MLDSA_K by 2^MLDSA_D + *without modular reduction. Assumes input coefficients to be less than + *2^{31-MLDSA_D}. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_ntt MLD_NAMESPACE_KL(polyveck_ntt) +/************************************************* + * Name: mld_polyveck_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_K. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyveck_invntt_tomont MLD_NAMESPACE_KL(polyveck_invntt_tomont) +/************************************************* + * Name: mld_polyveck_invntt_tomont + * + * Description: Inverse NTT and multiplication by 2^{32} of polynomials + * in vector of length MLDSA_K. + * Input coefficients need to be less than MLDSA_Q, and + * Output coefficients are bounded by MLD_INTT_BOUND. + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) +); + +#define mld_polyveck_pointwise_poly_montgomery \ + MLD_NAMESPACE_KL(polyveck_pointwise_poly_montgomery) +/************************************************* + * Name: mld_polyveck_pointwise_poly_montgomery + * + * Description: Pointwise multiplication of a polynomial vector of length + * MLDSA_K by a single polynomial in NTT domain and multiplication + * of the resulting polynomial vector by 2^{-32}. + * + * Arguments: - mld_polyveck *r: pointer to output vector + * - mld_poly *a: pointer to input polynomial + * - mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(r, sizeof(mld_polyveck))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(r, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(r->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#define mld_polyveck_chknorm MLD_NAMESPACE_KL(polyveck_chknorm) +/************************************************* + * Name: mld_polyveck_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_K. + * Assumes input mld_polyveck to be reduced by polyveck_reduce(). + * + * Arguments: - const mld_polyveck *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials are strictly smaller than B <= + *(MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, + -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +#define mld_polyveck_power2round MLD_NAMESPACE_KL(polyveck_power2round) +/************************************************* + * Name: mld_polyveck_power2round + * + * Description: For all coefficients a of polynomials in vector of length + *MLDSA_K, compute a0, a1 such that a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with + *-2^{MLDSA_D-1} < a0 <= 2^{MLDSA_D-1}. Assumes coefficients to be standard + *representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to output vector of polynomials with + * coefficients a0 + * - const mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) +); + +#define mld_polyveck_decompose MLD_NAMESPACE_KL(polyveck_decompose) +/************************************************* + * Name: mld_polyveck_decompose + * + * Description: For all coefficients a of polynomials in vector of length + * MLDSA_K, compute high and low bits a0, a1 such a mod^+ MLDSA_Q = a1*ALPHA + * + a0 with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (MLDSA_Q-1)/ALPHA where we set + * a1 = 0 and -ALPHA/2 <= a0 = a mod MLDSA_Q - MLDSA_Q < 0. Assumes coefficients + * to be standard representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to input/output vector of + * polynomials with. Output polynomial has + * coefficients a0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v0->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + ensures(forall(k2, 0, MLDSA_K, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) +); + +#define mld_polyveck_make_hint MLD_NAMESPACE_KL(polyveck_make_hint) +/************************************************* + * Name: mld_polyveck_make_hint + * + * Description: Compute hint vector. + * + * Arguments: - mld_polyveck *h: pointer to output vector + * - const mld_polyveck *v0: pointer to low part of input vector + * - const mld_polyveck *v1: pointer to high part of input vector + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(return_value <= MLDSA_N * MLDSA_K) + ensures(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) +); + +#define mld_polyveck_use_hint MLD_NAMESPACE_KL(polyveck_use_hint) +/************************************************* + * Name: mld_polyveck_use_hint + * + * Description: Use hint vector to correct the high bits of input vector. + * + * Arguments: - mld_polyveck *w: pointer to output vector of polynomials with + * corrected high bits + * - const mld_polyveck *u: pointer to input vector + * - const mld_polyveck *h: pointer to input hint vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *v, + const mld_polyveck *h) +__contract__( + requires(memory_no_alias(w, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + assigns(memory_slice(w, sizeof(mld_polyveck))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) +); + +#define mld_polyveck_pack_w1 MLD_NAMESPACE_KL(polyveck_pack_w1) +/************************************************* + * Name: mld_polyveck_pack_w1 + * + * Description: Bit-pack polynomial vector w1 with coefficients in [0,15] or + * [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_K* MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_polyveck *a: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(w1, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(w1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) +); + +#define mld_polyveck_pack_eta MLD_NAMESPACE_KL(polyveck_pack_eta) +/************************************************* + * Name: mld_polyveck_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients + * in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyvecl_pack_eta MLD_NAMESPACE_KL(polyvecl_pack_eta) +/************************************************* + * Name: mld_polyvecl_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_L * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyveck_pack_t0 MLD_NAMESPACE_KL(polyveck_pack_t0) +/************************************************* + * Name: mld_polyveck_pack_t0 + * + * Description: Bit-pack polynomial vector to with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(p->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) +); + +#define mld_polyvecl_unpack_eta MLD_NAMESPACE_KL(polyvecl_unpack_eta) +/************************************************* + * Name: mld_polyvecl_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyvecl *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + assigns(memory_slice(p, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyvecl_unpack_z MLD_NAMESPACE_KL(polyvecl_unpack_z) +/************************************************* + * Name: mld_polyvecl_unpack_z + * + * Description: Unpack polynomial vector with coefficients in + * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_polyvecl *z: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(z->vec[k1].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyveck_unpack_eta MLD_NAMESPACE_KL(polyveck_unpack_eta) +/************************************************* + * Name: mld_polyveck_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyveck_unpack_t0 MLD_NAMESPACE_KL(polyveck_unpack_t0) +/************************************************* + * Name: mld_polyveck_unpack_t0 + * + * Description: Unpack polynomial vector with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) +); + +#define mld_polymat_get_row MLD_NAMESPACE_KL(polymat_get_row) +/************************************************* + * Name: mld_polymat_get_row + * + * Description: Retrieve a pointer to a specific row of the matrix. + * In MLD_CONFIG_REDUCE_RAM mode, generates the row on-demand. + * + * Arguments: - mld_polymat *mat: pointer to matrix + * - unsigned int row: row index (must be < MLDSA_K) + * + * Returns pointer to the row (mld_polyvecl) + **************************************************/ +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row); + +#define mld_polyvec_matrix_expand MLD_NAMESPACE_KL(polyvec_matrix_expand) +/************************************************* + * Name: mld_polyvec_matrix_expand + * + * Description: Implementation of ExpandA. Generates matrix A with uniformly + * random coefficients a_{i,j} by performing rejection + * sampling on the output stream of SHAKE128(rho|j|i) + * + * Arguments: - mld_polymat *mat: pointer to output matrix + * - const uint8_t rho[]: byte array containing seed rho + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +__contract__( + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +); + + + +#define mld_polyvec_matrix_pointwise_montgomery \ + MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery) +/************************************************* + * Name: mld_polyvec_matrix_pointwise_montgomery + * + * Description: Compute matrix-vector multiplication in NTT domain with + * pointwise multiplication and multiplication by 2^{-32}. + * Input matrix and vector must be in NTT domain representation. + * + * The first input "mat" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * Note: In MLD_CONFIG_REDUCE_RAM mode, mat cannot be const + * as rows are generated on-demand. + * + * Arguments: - mld_polyveck *t: pointer to output vector t + * - mld_polymat *mat: pointer to input matrix + * - const mld_polyvecl *v: pointer to input vector v + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(t, sizeof(mld_polyveck))) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(t, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#endif /* !MLD_POLYVEC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/randombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/randombytes.h new file mode 100644 index 0000000000..da55772419 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/randombytes.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_RANDOMBYTES_H +#define MLD_RANDOMBYTES_H + +#include +#include + +#include "cbmc.h" +#include "common.h" + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +#if !defined(MLD_CONFIG_CUSTOM_RANDOMBYTES) +MLD_MUST_CHECK_RETURN_VALUE +int randombytes(uint8_t *out, size_t outlen); +static MLD_INLINE int mld_randombytes(uint8_t *out, size_t outlen) +__contract__( + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) { return randombytes(out, outlen); } +#endif /* !MLD_CONFIG_CUSTOM_RANDOMBYTES */ +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ +#endif /* !MLD_RANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/reduce.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/reduce.h new file mode 100644 index 0000000000..413cf1829e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/reduce.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_REDUCE_H +#define MLD_REDUCE_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* check-magic: -4186625 == pow(2,32,MLDSA_Q) */ +#define MLD_MONT -4186625 + +/* Upper bound for domain of mld_reduce32() */ +#define MLD_REDUCE32_DOMAIN_MAX (INT32_MAX - (1 << 22)) + +/* Absolute bound for range of mld_reduce32() */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define MLD_REDUCE32_RANGE_MAX 6283009 + +/************************************************* + * Name: mld_montgomery_reduce + * + * Description: Generic Montgomery reduction; given a 64-bit integer a, computes + * 32-bit integer congruent to a * R^-1 mod q, where R=2^32 + * + * Arguments: - int64_t a: input integer to be reduced, of absolute value + * smaller or equal to INT64_MAX - 2^31 * MLDSA_Q. + * + * Returns: Integer congruent to a * R^-1 modulo q, with absolute value + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * In particular, if |a| < 2^31 * MLDSA_Q, the absolute value + * of the return value is < MLDSA_Q. + **************************************************/ +static MLD_INLINE int32_t mld_montgomery_reduce(int64_t a) +__contract__( + /* We don't attempt to express an input-dependent output bound + * as the post-condition here, as all call-sites satisfy the + * absolute input bound 2^31 * MLDSA_Q and higher-level + * reasoning can be conducted using |return_value| < MLDSA_Q. */ + requires(a > -(((int64_t)1 << 31) * MLDSA_Q) && + a < (((int64_t)1 << 31) * MLDSA_Q)) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* check-magic: 58728449 == unsigned_mod(pow(MLDSA_Q, -1, 2^32), 2^32) */ + const uint64_t QINV = 58728449; + + /* Compute a*q^{-1} mod 2^32 in unsigned representatives */ + const uint32_t a_reduced = mld_cast_int64_to_uint32(a); + const uint32_t a_inverted = (a_reduced * QINV) & UINT32_MAX; + + /* Lift to signed canonical representative mod 2^32. */ + const int32_t t = mld_cast_uint32_to_int32(a_inverted); + + int64_t r; + + mld_assert(a < +(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)) && + a > -(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q))); + + r = a - (int64_t)t * MLDSA_Q; + + /* + * PORTABILITY: Right-shift on a signed integer is, strictly-speaking, + * implementation-defined for negative left argument. Here, + * we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5)) + */ + r = r >> 32; + + /* Bounds: + * + * By construction of the Montgomery multiplication, by the time we + * compute r >> 32, r is divisible by 2^32, and hence + * + * |r >> 32| = |r| / 2^32 + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * (In general, we would only have |x >> n| <= ceil(|x| / 2^n)). + * + * In particular, if |a| < 2^31 * MLDSA_Q, then |return_value| < MLDSA_Q. + */ + return (int32_t)r; +} + +/************************************************* + * Name: mld_reduce32 + * + * Description: For finite field element a with a <= 2^{31} - 2^{22} - 1, + * compute r \equiv a (mod MLDSA_Q) such that + * -MLD_REDUCE32_RANGE_MAX <= r < MLD_REDUCE32_RANGE_MAX. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_reduce32(int32_t a) +__contract__( + requires(a <= MLD_REDUCE32_DOMAIN_MAX) + ensures(return_value >= -MLD_REDUCE32_RANGE_MAX) + ensures(return_value < MLD_REDUCE32_RANGE_MAX) +) +{ + int32_t t; + + t = (a + (1 << 22)) >> 23; + t = a - t * MLDSA_Q; + mld_assert((t - a) % MLDSA_Q == 0); + return t; +} + +/************************************************* + * Name: mld_caddq + * + * Description: Add MLDSA_Q if input coefficient is negative. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_caddq(int32_t a) +__contract__( + requires(a > -MLDSA_Q) + requires(a < MLDSA_Q) + ensures(return_value >= 0) + ensures(return_value < MLDSA_Q) + ensures(return_value == (a >= 0) ? a : (a + MLDSA_Q)) +) +{ + return mld_ct_sel_int32(a + MLDSA_Q, a, mld_ct_cmask_neg_i32(a)); +} + + +#endif /* !MLD_REDUCE_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/rounding.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/rounding.h new file mode 100644 index 0000000000..a83562b0f1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/rounding.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_ROUNDING_H +#define MLD_ROUNDING_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_power2round MLD_ADD_PARAM_SET(mld_power2round) +#define mld_decompose MLD_ADD_PARAM_SET(mld_decompose) +#define mld_make_hint MLD_ADD_PARAM_SET(mld_make_hint) +#define mld_use_hint MLD_ADD_PARAM_SET(mld_use_hint) +/* End of parameter set namespacing */ + +#define MLD_2_POW_D (1 << MLDSA_D) + +/************************************************* + * Name: mld_power2round + * + * Description: For finite field element a, compute a0, a1 such that + * a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with -2^{MLDSA_D-1} < a0 <= + * 2^{MLDSA_D-1}. Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: In the reference implementation, a1 is passed as a + * return value instead. + **************************************************/ +static MLD_INLINE void mld_power2round(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + ensures(*a0 > -(MLD_2_POW_D/2) && *a0 <= (MLD_2_POW_D/2)) + ensures(*a1 >= 0 && *a1 <= (MLDSA_Q - 1) / MLD_2_POW_D) + ensures((*a1 * MLD_2_POW_D + *a0 - a) % MLDSA_Q == 0) +) +{ + *a1 = (a + (1 << (MLDSA_D - 1)) - 1) >> MLDSA_D; + *a0 = a - (*a1 << MLDSA_D); +} + +/************************************************* + * Name: mld_decompose + * + * Description: For finite field element a, compute high and low bits a0, a1 + * such that a mod^+ MLDSA_Q = a1* 2 * MLDSA_GAMMA2 + a0 with + * -MLDSA_GAMMA2 < a0 <= MLDSA_GAMMA2 except + * if a1 = (MLDSA_Q-1)/(MLDSA_GAMMA2*2) where we set a1 = 0 and + * -MLDSA_GAMMA2 <= a0 = a mod^+ MLDSA_Q - MLDSA_Q < 0. + * Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: a1 is passed as a return value instead + **************************************************/ +static MLD_INLINE void mld_decompose(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + /* a0 = -MLDSA_GAMMA2 can only occur when (q-1) = a - (a mod MLDSA_GAMMA2), + * then a1=1; and a0 = a - (a mod MLDSA_GAMMA2) - 1 (@[FIPS204, Algorithm 36 (Decompose)]) */ + ensures(*a0 >= -MLDSA_GAMMA2 && *a0 <= MLDSA_GAMMA2) + ensures(*a1 >= 0 && *a1 < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) + ensures((*a1 * 2 * MLDSA_GAMMA2 + *a0 - a) % MLDSA_Q == 0) +) +{ + /* + * The goal is to compute f1 = round-(f / (2*GAMMA2)), which can be computed + * alternatively as round-(f / (128B)) = round-(ceil(f / 128) / B) where + * B = 2*GAMMA2 / 128. Here round-() denotes "round half down". + * + * The equality round-(f / (128B)) = round-(ceil(f / 128) / B) can deduced + * as follows. Since changing f to align-up(f, 128) can move f onto but not + * across a rounding boundary for division by 128*B (note that we need B to be + * even for this to work), and round- rounds down on the boundary, we have + * + * round-(f / (128B)) = round-(align-up(f, 128) / (128B)) + * = round-((align-up(f, 128) / 128) / B) + * = round-(ceil(f / 128) / B). + */ + *a1 = (a + 127) >> 7; + /* We know a >= 0 and a < MLDSA_Q, so... */ + /* check-magic: 65472 == round((MLDSA_Q-1)/128) */ + mld_assert(*a1 >= 0 && *a1 <= 65472); + +#if MLD_CONFIG_PARAMETER_SET == 44 + /* check-magic: 1488 == 2 * intdiv(intdiv(MLDSA_Q - 1, 88), 128) */ + /* check-magic: 11275 == floor(2**24 / 1488) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + */ + *a1 = (*a1 * 11275 + (1 << 23)) >> 24; + mld_assert(*a1 >= 0 && *a1 <= 44); + + *a1 = mld_ct_sel_int32(0, *a1, mld_ct_cmask_neg_i32(43 - *a1)); + mld_assert(*a1 >= 0 && *a1 <= 43); +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + /* check-magic: 4092 == 2 * intdiv(intdiv(MLDSA_Q - 1, 32), 128) */ + /* check-magic: 1025 == floor(2**22 / 4092) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + */ + *a1 = (*a1 * 1025 + (1 << 21)) >> 22; + mld_assert(*a1 >= 0 && *a1 <= 16); + + *a1 &= 15; + mld_assert(*a1 >= 0 && *a1 <= 15); + +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + + *a0 = a - *a1 * 2 * MLDSA_GAMMA2; + *a0 = mld_ct_sel_int32(*a0 - MLDSA_Q, *a0, + mld_ct_cmask_neg_i32((MLDSA_Q - 1) / 2 - *a0)); +} + +/************************************************* + * Name: mld_make_hint + * + * Description: Compute hint bit indicating whether the low bits of the + * input element overflow into the high bits. + * + * Arguments: - int32_t a0: low bits of input element + * - int32_t a1: high bits of input element + * + * Returns 1 if overflow, 0 otherwise + **************************************************/ +static MLD_INLINE unsigned int mld_make_hint(int32_t a0, int32_t a1) +__contract__( + ensures(return_value >= 0 && return_value <= 1) +) +{ + if (a0 > MLDSA_GAMMA2 || a0 < -MLDSA_GAMMA2 || + (a0 == -MLDSA_GAMMA2 && a1 != 0)) + { + return 1; + } + + return 0; +} + +/************************************************* + * Name: mld_use_hint + * + * Description: Correct high bits according to hint. + * + * Arguments: - int32_t a: input element + * - int32_t hint: hint bit + * + * Returns corrected high bits. + **************************************************/ +static MLD_INLINE int32_t mld_use_hint(int32_t a, int32_t hint) +__contract__( + requires(hint >= 0 && hint <= 1) + requires(a >= 0 && a < MLDSA_Q) + ensures(return_value >= 0 && return_value < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) +) +{ + int32_t a0, a1; + + mld_decompose(&a0, &a1, a); + if (hint == 0) + { + return a1; + } + +#if MLD_CONFIG_PARAMETER_SET == 44 + if (a0 > 0) + { + return (a1 == 43) ? 0 : a1 + 1; + } + else + { + return (a1 == 0) ? 43 : a1 - 1; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + if (a0 > 0) + { + return (a1 + 1) & 15; + } + else + { + return (a1 - 1) & 15; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + + +#endif /* !MLD_ROUNDING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/sign.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/sign.c new file mode 100644 index 0000000000..32bba52d65 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/sign.c @@ -0,0 +1,1508 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [Round3_Spec] + * CRYSTALS-Dilithium Algorithm Specifications and Supporting Documentation + * (Version 3.1) + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf + */ + +#include +#include + +#include "cbmc.h" +#include "ct.h" +#include "debug.h" +#include "packing.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" +#include "randombytes.h" +#include "sign.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_check_pct MLD_ADD_PARAM_SET(mld_check_pct) MLD_CONTEXT_PARAMETERS_2 +#define mld_sample_s1_s2 MLD_ADD_PARAM_SET(mld_sample_s1_s2) +#define mld_validate_hash_length MLD_ADD_PARAM_SET(mld_validate_hash_length) +#define mld_get_hash_oid MLD_ADD_PARAM_SET(mld_get_hash_oid) +#define mld_H MLD_ADD_PARAM_SET(mld_H) +#define mld_compute_pack_z MLD_ADD_PARAM_SET(mld_compute_pack_z) +#define mld_attempt_signature_generation \ + MLD_ADD_PARAM_SET(mld_attempt_signature_generation) MLD_CONTEXT_PARAMETERS_8 +#define mld_compute_t0_t1_tr_from_sk_components \ + MLD_ADD_PARAM_SET(mld_compute_t0_t1_tr_from_sk_components) \ + MLD_CONTEXT_PARAMETERS_7 +/* End of parameter set namespacing */ + + +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + ensures(return_value == 0 + || return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL) +); + +#if defined(MLD_CONFIG_KEYGEN_PCT) +/************************************************* + * @[FIPS140_3_IG] + * (https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf) + * + * TE10.35.02: Pair-wise Consistency Test (PCT) for DSA keypairs + * + * Purpose: Validates that a generated public/private key pair can correctly + * sign and verify data. Test performs signature generation using the private + * key (sk), followed by signature verification using the public key (pk). + * Returns 0 if the signature was successfully verified, non-zero if it cannot. + * + * Note: @[FIPS204] requires that public/private key pairs are to be used only + * for the calculation and/of verification of digital signatures. + **************************************************/ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t message[1] = {0}; + size_t siglen; + int ret; + MLD_ALLOC(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + MLD_ALLOC(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + + if (signature == NULL || pk_test == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Copy public key for testing */ + mld_memcpy(pk_test, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* Sign a test message using the original secret key */ + ret = mld_sign_signature(signature, &siglen, message, sizeof(message), NULL, + 0, sk, context); + if (ret != 0) + { + goto cleanup; + } + +#if defined(MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST) + /* Deliberately break public key for testing purposes */ + if (mld_break_pct()) + { + pk_test[0] = ~pk_test[0]; + } +#endif /* MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST */ + + /* Verify the signature using the (potentially corrupted) public key */ + ret = mld_sign_verify(signature, siglen, message, sizeof(message), NULL, 0, + pk_test, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + MLD_FREE(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + + return ret; +} +#else /* MLD_CONFIG_KEYGEN_PCT */ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + /* Skip PCT */ + ((void)pk); + ((void)sk); +#if defined(MLD_CONFIG_CONTEXT_PARAMETER) + ((void)context); +#endif + return 0; +} +#endif /* !MLD_CONFIG_KEYGEN_PCT */ + +static void mld_sample_s1_s2(mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t seed[MLDSA_CRHBYTES]) +__contract__( + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(object_whole(s1), object_whole(s2)) + ensures(forall(l0, 0, MLDSA_L, array_abs_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + ensures(forall(k0, 0, MLDSA_K, array_abs_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) +) +{ +/* Sample short vectors s1 and s2 */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; + uint16_t nonce = 0; + /* Safety: The nonces are at most 14 (MLDSA_L + MLDSA_K - 1), and, hence, the + * casts are safe. */ + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_eta(&s1->vec[i], seed, (uint8_t)(nonce + i)); + } + for (i = 0; i < MLDSA_K; i++) + { + mld_poly_uniform_eta(&s2->vec[i], seed, (uint8_t)(nonce + MLDSA_L + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLD_CONFIG_PARAMETER_SET == 44 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 4, 5, 6, 7); +#elif MLD_CONFIG_PARAMETER_SET == 65 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s2->vec[0], &s2->vec[1], + &s2->vec[2] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[2], &s2->vec[3], &s2->vec[4], &s2->vec[5], + seed, 7, 8, 9, 10); +#elif MLD_CONFIG_PARAMETER_SET == 87 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s1->vec[5], &s1->vec[6], + &s2->vec[0] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 7, 8, 9, 10); + mld_poly_uniform_eta_4x(&s2->vec[4], &s2->vec[5], &s2->vec[6], &s2->vec[7], + seed, 11, 12, 13, 14); +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ +} + +/************************************************* + * Name: mld_compute_t0_t1_tr_from_sk_components + * + * Description: Computes t0, t1, tr, and pk from secret key components + * rho, s1, s2. This is the shared computation used by + * both keygen and generating the public key from the + * secret key. + * + * Arguments: - mld_polyveck *t0: output t0 + * - mld_polyveck *t1: output t1 + * - uint8_t tr[MLDSA_TRBYTES]: output tr + * - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t rho[MLDSA_SEEDBYTES]: input rho + * - const mld_polyvecl *s1: input s1 + * - const mld_polyveck *s2: input s2 + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_t0_t1_tr_from_sk_components( + mld_polyveck *t0, mld_polyveck *t1, uint8_t tr[MLDSA_TRBYTES], + uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], const uint8_t rho[MLDSA_SEEDBYTES], + const mld_polyvecl *s1, const mld_polyveck *s2, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(l0, 0, MLDSA_L, array_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + requires(forall(k0, 0, MLDSA_K, array_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(forall(k1, 0, MLDSA_K, array_bound(t0->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(t1->vec[k2].coeffs, 0, MLDSA_N, 0, 1 << 10))) + ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY)) +{ + int ret; + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1hat, mld_polyvecl, 1, context); + MLD_ALLOC(t, mld_polyveck, 1, context); + + if (mat == NULL || s1hat == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Expand matrix */ + mld_polyvec_matrix_expand(mat, rho); + + /* Matrix-vector multiplication */ + *s1hat = *s1; + mld_polyvecl_ntt(s1hat); + mld_polyvec_matrix_pointwise_montgomery(t, mat, s1hat); + mld_polyveck_invntt_tomont(t); + + /* Add error vector s2 */ + mld_polyveck_add(t, s2); + + /* Reference: The following reduction is not present in the reference + * implementation. Omitting this reduction requires the output of + * the invntt to be small enough such that the addition of s2 does + * not result in absolute values >= MLDSA_Q. While our C, x86_64, + * and AArch64 invntt implementations produce small enough + * values for this to work out, it complicates the bounds + * reasoning. We instead add an additional reduction, and can + * consequently, relax the bounds requirements for the invntt. + */ + mld_polyveck_reduce(t); + + /* Decompose to get t1, t0 */ + mld_polyveck_caddq(t); + mld_polyveck_power2round(t1, t0, t); + + /* Pack public key and compute tr */ + mld_pack_pk(pk, rho, t1); + mld_shake256(tr, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + ret = 0; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_polyveck, 1, context); + MLD_FREE(s1hat, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + const uint8_t *rho, *rhoprime, *key; + MLD_ALLOC(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + MLD_ALLOC(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + + if (seedbuf == NULL || inbuf == NULL || tr == NULL || s1 == NULL || + s2 == NULL || t1 == NULL || t0 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Get randomness for rho, rhoprime and key */ + mld_memcpy(inbuf, seed, MLDSA_SEEDBYTES); + inbuf[MLDSA_SEEDBYTES + 0] = MLDSA_K; + inbuf[MLDSA_SEEDBYTES + 1] = MLDSA_L; + mld_shake256(seedbuf, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, inbuf, + MLDSA_SEEDBYTES + 2); + rho = seedbuf; + rhoprime = rho + MLDSA_SEEDBYTES; + key = rhoprime + MLDSA_CRHBYTES; + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + + /* Sample s1 and s2 */ + mld_sample_s1_s2(s1, s2, rhoprime); + + /* Compute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0, t1, tr, pk, rho, s1, s2, + context); + if (ret != 0) + { + goto cleanup; + } + + /* Pack secret key */ + mld_pack_sk(sk, rho, tr, key, t0, s1, s2); + + /* Constant time: pk is the public key, inherently public data */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_FREE(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + + if (ret != 0) + { + return ret; + } + + /* Pairwise Consistency Test (PCT) @[FIPS140_3_IG, p.87] */ + /* Do this after freeing all temporaries. */ + return mld_check_pct(pk, sk, context); +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t seed[MLDSA_SEEDBYTES]; + int ret; + if (mld_randombytes(seed, MLDSA_SEEDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(seed, sizeof(seed)); + ret = mld_sign_keypair_internal(pk, sk, seed, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed, sizeof(seed)); + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +/************************************************* + * Name: mld_H + * + * Description: Abstracts application of SHAKE256 to + * one, two or three blocks of data, + * yielding a user-requested size of + * output. + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in1: pointer to input block 1 + * Must NOT be NULL + * - size_t in1len: length of input in1 bytes + * - const uint8_t *in2: pointer to input block 2 + * May be NULL if in2len=0, in which case + * this block is ignored + * - size_t in2len: length of input in2 bytes + * - const uint8_t *in3: pointer to input block 3 + * May be NULL if in3len=0, in which case + * this block is ignored + * - size_t in3len: length of input in3 bytes + **************************************************/ +static void mld_H(uint8_t *out, size_t outlen, const uint8_t *in1, + size_t in1len, const uint8_t *in2, size_t in2len, + const uint8_t *in3, size_t in3len) +__contract__( + requires(in1len <= MLD_MAX_BUFFER_SIZE) + requires(in2len <= MLD_MAX_BUFFER_SIZE) + requires(in3len <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in1, in1len)) + requires(in2len == 0 || memory_no_alias(in2, in2len)) + requires(in3len == 0 || memory_no_alias(in3, in3len)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) +{ + mld_shake256ctx state; + mld_shake256_init(&state); + mld_shake256_absorb(&state, in1, in1len); + if (in2len != 0) + { + mld_shake256_absorb(&state, in2, in2len); + } + if (in3len != 0) + { + mld_shake256_absorb(&state, in3, in3len); + } + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(&state, sizeof(state)); +} + +/************************************************* + * Name: mld_compute_pack_z + * + * Description: Computes z = y + s1*c, checks that z has coefficients smaller + * than MLDSA_GAMMA1 - MLDSA_BETA, and packs z into the + * signature buffer. + * + * Arguments: - uint8_t *sig: output signature + * - const mld_poly *cp: challenge polynomial + * - const polyvecl *s1: secret vector s1 + * - const polyvecl *y: masking vector y + * + * Returns: - 0: Success (z has coefficients smaller than + * MLDSA_GAMMA1 - MLDSA_BETA,) + * - MLD_ERR_FAIL: z rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This function is inlined into mld_sign_signature in the + * reference implementation. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_pack_z(uint8_t sig[MLDSA_CRYPTO_BYTES], + const mld_poly *cp, const mld_polyvecl *s1, + const mld_polyvecl *y, mld_poly *z) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(cp, sizeof(mld_poly))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(y, sizeof(mld_polyvecl))) + requires(memory_no_alias(z, sizeof(mld_poly))) + requires(array_abs_bound(cp->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_L, + array_bound(y->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + requires(forall(k1, 0, MLDSA_L, array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(memory_slice(z, sizeof(mld_poly))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int i; + uint32_t z_invalid; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(z, sizeof(mld_poly)), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_poly_pointwise_montgomery(z, cp, &s1->vec[i]); + mld_poly_invntt_tomont(z); + mld_poly_add(z, &y->vec[i]); + mld_poly_reduce(z); + + z_invalid = mld_poly_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA); + /* Constant time: It is fine (and prohibitively expensive to avoid) + * to leak the result of the norm check and which polynomial in z caused a + * rejection. It would even be okay to leak which coefficient led to + * rejection as the candidate signature will be discarded anyway. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(&z_invalid, sizeof(uint32_t)); + if (z_invalid) + { + return MLD_ERR_FAIL; /* reject */ + } + /* If z is valid, then its coefficients are bounded by + * MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below + * to prove the pre-condition of pack_sig_z() */ + mld_assert_abs_bound(z, MLDSA_N, (MLDSA_GAMMA1 - MLDSA_BETA)); + + /* After the norm check, the distribution of each coefficient of z is + * independent of the secret key and it can, hence, be considered + * public. It is, hence, okay to immediately pack it into the user-provided + * signature buffer. */ + mld_pack_sig_z(sig, z, i); + } + return 0; +} + +/* Reference: The reference implementation does not explicitly check the + * maximum nonce value, but instead loops indefinitely (even when the nonce + * would overflow). Internally, sampling of y uses + * (nonceL), (nonceL+1), ... (nonce*L+L-1). + * Hence, there are no overflows if nonce < (UINT16_MAX - L)/L. + * Explicitly checking for this explicitly allows us to prove type-safety. + * Note that FIPS204 explicitly allows an upper-bound this loop of + * 814 (< (UINT16_MAX - L)/L) - see @[FIPS204, Appendix C]. */ +#define MLD_NONCE_UB ((UINT16_MAX - MLDSA_L) / MLDSA_L) + +/************************************************* + * Name: attempt_signature_generation + * + * Description: Attempts to generate a single signature. + * + * Arguments: - uint8_t *sig: pointer to output signature + * - const uint8_t *mu: pointer to message or hash + * of exactly MLDSA_CRHBYTES bytes + * - const uint8_t *rhoprime: pointer to randomness seed + * - uint16_t nonce: current nonce value + * - const mld_polymat *mat: expanded matrix + * - const polyvecl *s1: secret vector s1 + * - const polyveck *s2: secret vector s2 + * - const polyveck *t0: vector t0 + * + * Returns: - 0: Signature generation succeeded + * - MLD_ERR_FAIL: Signature rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This code differs from the reference implementation + * in that it factors out the core signature generation + * step into a distinct function here in order to improve + * efficiency of CBMC proof. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_attempt_signature_generation( + uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *mu, + const uint8_t rhoprime[MLDSA_CRHBYTES], uint16_t nonce, mld_polymat *mat, + const mld_polyvecl *s1, const mld_polyveck *s2, const mld_polyveck *t0, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(rhoprime, MLDSA_CRHBYTES)) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(nonce <= MLD_NONCE_UB) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int n; + uint32_t w0_invalid, h_invalid; + int ret; + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyvecl y; + mld_polyveck h; + } + yh_u; + mld_polyvecl *y; + mld_polyveck *h; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck w1; + mld_polyvecl tmp; + } + w1tmp_u; + mld_polyveck *w1; + mld_polyvecl *tmp; + + MLD_ALLOC(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(yh, yh_u, 1, context); + MLD_ALLOC(z, mld_poly, 1, context); + MLD_ALLOC(w1tmp, w1tmp_u, 1, context); + MLD_ALLOC(w0, mld_polyveck, 1, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(t, mld_poly, 1, context); + + if (challenge_bytes == NULL || yh == NULL || z == NULL || w1tmp == NULL || + w0 == NULL || cp == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + y = &yh->y; + h = &yh->h; + w1 = &w1tmp->w1; + tmp = &w1tmp->tmp; + + /* Sample intermediate vector y */ + mld_polyvecl_uniform_gamma1(y, rhoprime, nonce); + + /* Matrix-vector multiplication */ + *tmp = *y; + mld_polyvecl_ntt(tmp); + mld_polyvec_matrix_pointwise_montgomery(w0, mat, tmp); + mld_polyveck_invntt_tomont(w0); + + /* Decompose w and call the random oracle */ + mld_polyveck_caddq(w0); + mld_polyveck_decompose(w1, w0); + mld_polyveck_pack_w1(sig, w1); + + mld_H(challenge_bytes, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, sig, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + /* Constant time: Leaking challenge_bytes does not reveal any information + * about the secret key as H() is modelled as random oracle. + * This also applies to challenges for rejected signatures. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(challenge_bytes, MLDSA_CTILDEBYTES); + mld_poly_challenge(cp, challenge_bytes); + mld_poly_ntt(cp); + + /* Compute z, reject if it reveals secret */ + ret = mld_compute_pack_z(sig, cp, s1, y, t); + if (ret) + { + goto cleanup; + } + + /* Check that subtracting cs2 does not change high bits of w and low bits + * do not reveal secret information */ + mld_polyveck_pointwise_poly_montgomery(h, cp, s2); + mld_polyveck_invntt_tomont(h); + mld_polyveck_sub(w0, h); + mld_polyveck_reduce(w0); + + w0_invalid = mld_polyveck_chknorm(w0, MLDSA_GAMMA2 - MLDSA_BETA); + /* Constant time: w0_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&w0_invalid, sizeof(uint32_t)); + if (w0_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* Compute hints for w1 */ + mld_polyveck_pointwise_poly_montgomery(h, cp, t0); + mld_polyveck_invntt_tomont(h); + mld_polyveck_reduce(h); + + h_invalid = mld_polyveck_chknorm(h, MLDSA_GAMMA2); + /* Constant time: h_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&h_invalid, sizeof(uint32_t)); + if (h_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + mld_polyveck_add(w0, h); + + /* Constant time: At this point all norm checks have passed and we, hence, + * know that the signature does not leak any secret information. + * Consequently, any value that can be computed from the signature and public + * key is considered public. + * w0 and w1 are public as they can be computed from Az - ct = \alpha w1 + w0. + * h=c*t0 is public as both c and t0 are public. + * For a more detailed discussion, refer to https://eprint.iacr.org/2022/1406. + */ + MLD_CT_TESTING_DECLASSIFY(w0, sizeof(*w0)); + MLD_CT_TESTING_DECLASSIFY(w1, sizeof(*w1)); + n = mld_polyveck_make_hint(h, w0, w1); + if (n > MLDSA_OMEGA) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* All is well - write signature */ + mld_pack_sig_c_h(sig, challenge_bytes, h, n); + /* Constant time: At this point it is clear that the signature is valid - it + * can, hence, be considered public. */ + MLD_CT_TESTING_DECLASSIFY(sig, MLDSA_CRYPTO_BYTES); + ret = 0; /* success */ + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_poly, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(w0, mld_polyveck, 1, context); + MLD_FREE(w1tmp, w1tmp_u, 1, context); + MLD_FREE(z, mld_poly, 1, context); + MLD_FREE(yh, yh_u, 1, context); + MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + + return ret; +} +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + uint8_t *rho, *tr, *key, *mu, *rhoprime; + uint16_t nonce = 0; + MLD_ALLOC(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + + if (seedbuf == NULL || mat == NULL || s1 == NULL || t0 == NULL || s2 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + rho = seedbuf; + tr = rho + MLDSA_SEEDBYTES; + key = tr + MLDSA_TRBYTES; + mu = key + MLDSA_SEEDBYTES; + rhoprime = mu + MLDSA_CRHBYTES; + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + if (!externalmu) + { + /* Compute mu = CRH(tr, pre, msg) */ + mld_H(mu, MLDSA_CRHBYTES, tr, MLDSA_TRBYTES, pre, prelen, m, mlen); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Compute rhoprime = CRH(key, rnd, mu) */ + mld_H(rhoprime, MLDSA_CRHBYTES, key, MLDSA_SEEDBYTES, rnd, MLDSA_RNDBYTES, mu, + MLDSA_CRHBYTES); + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + /* Expand matrix and transform vectors */ + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(s1); + mld_polyveck_ntt(s2); + mld_polyveck_ntt(t0); + + /* By default, return failure. Flip to success and write output + * once signature generation succeeds. */ + ret = MLD_ERR_FAIL; + + /* Reference: This code is re-structured using a while(1), */ + /* with explicit "continue" statements (rather than "goto") */ + /* to implement rejection of invalid signatures. */ + while (1) + __loop__( + assigns(nonce, ret, object_whole(siglen), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(nonce <= MLD_NONCE_UB) + + /* t0, s1, s2, and mat are initialized above and are NOT changed by this */ + /* loop. We can therefore re-assert their bounds here as part of the */ + /* loop invariant. This makes proof noticeably faster with CBMC */ + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + invariant(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(ret == MLD_ERR_FAIL) + ) + { + /* Reference: this code explicitly checks for exhaustion of nonce */ + /* values to provide predictable termination and results in that case */ + /* Checking here also means that incrementing nonce below can also */ + /* be proven to be type-safe. */ + if (nonce == MLD_NONCE_UB) + { + /* Note that ret == MLD_ERR_FAIL by default, so we + * don't need to set it here. */ + break; + } + + ret = mld_attempt_signature_generation(sig, mu, rhoprime, nonce, mat, s1, + s2, t0, context); + nonce++; + if (ret == 0) + { + *siglen = MLDSA_CRYPTO_BYTES; + break; + } + else if (ret != MLD_ERR_FAIL) + { + /* For failures such as out-of-memory, propagate and exit immediately. */ + break; + } + + /* Otherwise, try again. */ + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the signature buffer. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + return ret; +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + size_t pre_len; + int ret; + MLD_ALLOC(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + MLD_ALLOC(rnd, uint8_t, MLDSA_RNDBYTES, context); + + if (pre == NULL || rnd == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Prepare domain separation prefix for pure ML-DSA */ + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, m, mlen, pre, pre_len, rnd, sk, + 0, context); + +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(rnd, uint8_t, MLDSA_RNDBYTES, context); + MLD_FREE(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t rnd[MLDSA_RNDBYTES]; + int ret; + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + *siglen = 0; + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, + rnd, sk, 1, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(rnd, sizeof(rnd)); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + for (i = 0; i < mlen; ++i) + __loop__( + assigns(i, object_whole(sm)) + invariant(i <= mlen) + ) + { + sm[MLDSA_CRYPTO_BYTES + mlen - 1 - i] = m[mlen - 1 - i]; + } + ret = mld_sign_signature(sm, smlen, sm + MLDSA_CRYPTO_BYTES, mlen, ctx, + ctxlen, sk, context); + *smlen += mlen; + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret, cmp; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck t1; + mld_polyveck w1; + } + t1w1_u; + mld_polyveck *t1; + mld_polyveck *w1; + + MLD_ALLOC(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_ALLOC(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(z, mld_polyvecl, 1, context); + MLD_ALLOC(t1w1, t1w1_u, 1, context); + MLD_ALLOC(tmp, mld_polyveck, 1, context); + MLD_ALLOC(h, mld_polyveck, 1, context); + + if (buf == NULL || rho == NULL || mu == NULL || c == NULL || c2 == NULL || + cp == NULL || mat == NULL || z == NULL || t1w1 == NULL || tmp == NULL || + h == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + t1 = &t1w1->t1; + w1 = &t1w1->w1; + + if (siglen != MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + mld_unpack_pk(rho, t1, pk); + + /* mld_unpack_sig and mld_polyvecl_chknorm signal failure through a + * single non-zero error code that's not yet aligned with MLD_ERR_XXX. + * Map it to MLD_ERR_FAIL explicitly. */ + if (mld_unpack_sig(c, z, h, sig)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + if (mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + if (!externalmu) + { + /* Compute CRH(H(rho, t1), pre, msg) */ + MLD_ALIGN uint8_t hpk[MLDSA_CRHBYTES]; + mld_H(hpk, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES, NULL, 0, NULL, + 0); + mld_H(mu, MLDSA_CRHBYTES, hpk, MLDSA_TRBYTES, pre, prelen, m, mlen); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(hpk, sizeof(hpk)); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Matrix-vector multiplication; compute Az - c2^dt1 */ + mld_poly_challenge(cp, c); + mld_poly_ntt(cp); + mld_polyveck_shiftl(t1); + mld_polyveck_ntt(t1); + mld_polyveck_pointwise_poly_montgomery(tmp, cp, t1); + + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(z); + mld_polyvec_matrix_pointwise_montgomery(w1, mat, z); + mld_polyveck_sub(w1, tmp); + mld_polyveck_reduce(w1); + mld_polyveck_invntt_tomont(w1); + + /* Reconstruct w1 */ + mld_polyveck_caddq(w1); + mld_polyveck_use_hint(tmp, w1, h); + mld_polyveck_pack_w1(buf, tmp); + /* Call random oracle and verify challenge */ + mld_H(c2, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, buf, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + + cmp = mld_ct_memcmp(c, c2, MLDSA_CTILDEBYTES); + + /* Declassify the result of the verification. */ + MLD_CT_TESTING_DECLASSIFY(&cmp, sizeof(cmp)); + + ret = cmp == 0 ? 0 : MLD_ERR_FAIL; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(h, mld_polyveck, 1, context); + MLD_FREE(tmp, mld_polyveck, 1, context); + MLD_FREE(t1w1, t1w1_u, 1, context); + MLD_FREE(z, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, m, mlen, pre, pre_len, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + return mld_sign_verify_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, pk, + 1, context); +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + if (smlen < MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + *mlen = smlen - MLDSA_CRYPTO_BYTES; + ret = mld_sign_verify(sm, MLDSA_CRYPTO_BYTES, sm + MLDSA_CRYPTO_BYTES, *mlen, + ctx, ctxlen, pk, context); + if (ret == 0) + { + /* All good, copy msg, return 0 */ + for (i = 0; i < *mlen; ++i) + __loop__( + assigns(i, memory_slice(m, *mlen)) + invariant(i <= *mlen) + ) + { + m[i] = sm[MLDSA_CRYPTO_BYTES + i]; + } + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the message buffer. */ + *mlen = 0; + mld_memset(m, 0, smlen); + } + + return ret; +} + + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_signature_internal(sig, siglen, pre, pre_len, NULL, 0, rnd, sk, + 0, context); +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, pre, pre_len, NULL, 0, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_signature_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, rnd, sk, + MLD_PREHASH_SHAKE_256, context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_verify_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, pk, MLD_PREHASH_SHAKE_256, + context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + + +#define MLD_PRE_HASH_OID_LEN 11 + +/************************************************* + * Name: mld_get_hash_oid + * + * Description: Returns the OID of a given SHA-2/SHA-3 hash function. + * + * Arguments: - uint8_t oid[11]: pointer to output oid + * - int hashalg: hash algorithm constant (MLD_PREHASH_*) + * + ***************************************************/ +static void mld_get_hash_oid(uint8_t oid[MLD_PRE_HASH_OID_LEN], int hashalg) +{ + unsigned int i; + static const struct + { + int alg; + uint8_t oid[MLD_PRE_HASH_OID_LEN]; + } oid_map[] = { + {MLD_PREHASH_SHA2_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}}, + {MLD_PREHASH_SHA2_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}}, + {MLD_PREHASH_SHA2_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}}, + {MLD_PREHASH_SHA2_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}}, + {MLD_PREHASH_SHA2_512_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05}}, + {MLD_PREHASH_SHA2_512_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06}}, + {MLD_PREHASH_SHA3_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07}}, + {MLD_PREHASH_SHA3_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08}}, + {MLD_PREHASH_SHA3_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09}}, + {MLD_PREHASH_SHA3_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A}}, + {MLD_PREHASH_SHAKE_128, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B}}, + {MLD_PREHASH_SHAKE_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C}}}; + + for (i = 0; i < sizeof(oid_map) / sizeof(oid_map[0]); i++) + __loop__( + invariant(i <= sizeof(oid_map) / sizeof(oid_map[0])) + ) + { + if (oid_map[i].alg == hashalg) + { + mld_memcpy(oid, oid_map[i].oid, MLD_PRE_HASH_OID_LEN); + return; + } + } +} + +static int mld_validate_hash_length(int hashalg, size_t len) +{ + switch (hashalg) + { + case MLD_PREHASH_SHA2_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_128: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_256: + return (len == 512 / 8) ? 0 : -1; + } + return -1; +} + +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +{ + if (ctxlen > 255) + { + return 0; + } + + if (hashalg != MLD_PREHASH_NONE) + { + if (ph == NULL || mld_validate_hash_length(hashalg, phlen) != 0) + { + return 0; + } + } + + /* Common prefix: 0x00/0x01 || ctxlen || ctx */ + prefix[0] = (hashalg == MLD_PREHASH_NONE) ? 0 : 1; + prefix[1] = (uint8_t)ctxlen; + if (ctxlen > 0) + { + mld_memcpy(prefix + 2, ctx, ctxlen); + } + + if (hashalg == MLD_PREHASH_NONE) + { + return 2 + ctxlen; + } + + /* HashML-DSA: append oid || ph */ + mld_get_hash_oid(prefix + 2 + ctxlen, hashalg); + mld_memcpy(prefix + 2 + ctxlen + MLD_PRE_HASH_OID_LEN, ph, phlen); + return 2 + ctxlen + MLD_PRE_HASH_OID_LEN + phlen; +} + +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + uint8_t check, cmp0, cmp1, chk1, chk2; + int ret; + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(t0_computed, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + + if (rho == NULL || tr == NULL || tr_computed == NULL || key == NULL || + s1 == NULL || s2 == NULL || t0 == NULL || t0_computed == NULL || + t1 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Unpack secret key */ + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + /* Validate s1 and s2 coefficients are within [-MLDSA_ETA, MLDSA_ETA] */ + chk1 = mld_polyvecl_chknorm(s1, MLDSA_ETA + 1) & 0xFF; + chk2 = mld_polyveck_chknorm(s2, MLDSA_ETA + 1) & 0xFF; + + /* Recompute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0_computed, t1, tr_computed, + pk, rho, s1, s2, context); + if (ret != 0) + { + goto cleanup; + } + + /* Validate t0 and tr using constant-time comparisons */ + cmp0 = mld_ct_memcmp((const uint8_t *)t0, (const uint8_t *)t0_computed, + sizeof(mld_polyveck)); + cmp1 = mld_ct_memcmp((const uint8_t *)tr, (const uint8_t *)tr_computed, + MLDSA_TRBYTES); + check = mld_value_barrier_u8(cmp0 | cmp1 | chk1 | chk2); + + /* Declassify the final result of the validity check. */ + MLD_CT_TESTING_DECLASSIFY(&check, sizeof(check)); + ret = (check != 0) ? MLD_ERR_FAIL : 0; + +cleanup: + + if (ret != 0) + { + mld_zeroize(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + } + + /* Constant time: pk is either the valid public key or zeroed on error */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(t0_computed, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + + return ret; +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_check_pct +#undef mld_sample_s1_s2 +#undef mld_validate_hash_length +#undef mld_get_hash_oid +#undef mld_H +#undef mld_compute_pack_z +#undef mld_attempt_signature_generation +#undef mld_compute_t0_t1_tr_from_sk_components +#undef MLD_NONCE_UB +#undef MLD_PRE_HASH_OID_LEN diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/sign.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/sign.h new file mode 100644 index 0000000000..2e0bac32ea --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/sign.h @@ -0,0 +1,807 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_SIGN_H +#define MLD_SIGN_H + +#include +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "polyvec.h" +#include "sys.h" + +#if defined(MLD_CHECK_APIS) +/* Include to ensure consistency between internal sign.h + * and external mldsa_native.h. */ +#include "mldsa_native.h" + +#if MLDSA_CRYPTO_SECRETKEYBYTES != \ + MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for SECRETKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_PUBLICKEYBYTES != \ + MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for PUBLICKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_BYTES != MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for CRYPTO_BYTES between sign.h and mldsa_native.h +#endif + +#endif /* MLD_CHECK_APIS */ + +#define mld_sign_keypair_internal \ + MLD_NAMESPACE_KL(keypair_internal) MLD_CONTEXT_PARAMETERS_3 +#define mld_sign_keypair MLD_NAMESPACE_KL(keypair) MLD_CONTEXT_PARAMETERS_2 +#define mld_sign_signature_internal \ + MLD_NAMESPACE_KL(signature_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_signature MLD_NAMESPACE_KL(signature) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_extmu \ + MLD_NAMESPACE_KL(signature_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign MLD_NAMESPACE_KL(sign) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_internal \ + MLD_NAMESPACE_KL(verify_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify MLD_NAMESPACE_KL(verify) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_extmu \ + MLD_NAMESPACE_KL(verify_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign_open MLD_NAMESPACE_KL(open) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_pre_hash_internal \ + MLD_NAMESPACE_KL(signature_pre_hash_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_verify_pre_hash_internal \ + MLD_NAMESPACE_KL(verify_pre_hash_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_signature_pre_hash_shake256 \ + MLD_NAMESPACE_KL(signature_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify_pre_hash_shake256 \ + MLD_NAMESPACE_KL(verify_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_7 +#define mld_prepare_domain_separation_prefix \ + MLD_NAMESPACE_KL(prepare_domain_separation_prefix) +#define mld_sign_pk_from_sk \ + MLD_NAMESPACE_KL(pk_from_sk) MLD_CONTEXT_PARAMETERS_2 + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: mld_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: input random seed + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int externalmu: indicates input message m is + * processed as mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return MLD_ERR_FAIL in that case. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires((externalmu == 0 && (prelen == 0 || memory_no_alias(pre, prelen))) || + (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) + ensures(return_value == 0 ==> *siglen == MLDSA_CRYPTO_BYTES) + ensures(return_value != 0 ==> *siglen == 0) +); + +/************************************************* + * Name: mld_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_signature_extmu + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign + * + * Description: Compute signed message. + * + * Arguments: - uint8_t *sm: pointer to output signed message + * (allocated array with MLDSA_CRYPTO_BYTES + + *mlen bytes), can be equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sm, MLDSA_CRYPTO_BYTES + mlen)) + requires(memory_no_alias(smlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sm, MLDSA_CRYPTO_BYTES + mlen)) + assigns(object_whole(smlen)) + ensures((return_value == 0 && *smlen == MLDSA_CRYPTO_BYTES + mlen) || + (return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL)) +); + +/************************************************* + * Name: mld_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as + * mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(externalmu == 0 || (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + requires(externalmu == 1 || prelen == 0 || memory_no_alias(pre, prelen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_open + * + * Description: Verify signed message. + * + * Arguments: - uint8_t *m: pointer to output message (allocated array + * with smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context tring + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(smlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(m, smlen)) + requires(memory_no_alias(mlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(sm, smlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + assigns(memory_slice(m, smlen)) + assigns(memory_slice(mlen, sizeof(size_t))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and + * verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/* Maximum formatted domain separation message length: + * - Pure ML-DSA: 0x00 || ctxlen || ctx (max 255) + * - HashML-DSA: 0x01 || ctxlen || ctx (max 255) || oid (11) || ph (max 64) */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +__contract__( + requires(ctxlen <= 255) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(hashalg == MLD_PREHASH_NONE || memory_no_alias(ph, phlen)) + requires(memory_no_alias(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + assigns(memory_slice(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + ensures(return_value <= MLD_DOMAIN_SEPARATION_MAX_BYTES) +); + +/************************************************* + * Name: mld_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: input secret + * key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); +#endif /* !MLD_SIGN_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/symmetric.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/symmetric.h new file mode 100644 index 0000000000..bb70f05552 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/symmetric.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_SYMMETRIC_H +#define MLD_SYMMETRIC_H + +#include +#include "cbmc.h" +#include "common.h" + +#include MLD_FIPS202_HEADER_FILE +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#include MLD_FIPS202X4_HEADER_FILE +#endif + +#define MLD_STREAM128_BLOCKBYTES SHAKE128_RATE +#define MLD_STREAM256_BLOCKBYTES SHAKE256_RATE + +#define mld_xof256_ctx mld_shake256ctx +#define mld_xof256_init(CTX) mld_shake256_init(CTX) + +#define mld_xof256_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake256_absorb(CTX, IN, INBYTES); \ + mld_shake256_finalize(CTX); \ + } while (0) + + +#define mld_xof256_release(CTX) mld_shake256_release(CTX) +#define mld_xof256_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake256_squeeze(OUT, (OUTBLOCKS) * SHAKE256_RATE, STATE) + +#define mld_xof128_ctx mld_shake128ctx +#define mld_xof128_init(CTX) mld_shake128_init(CTX) + +#define mld_xof128_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake128_absorb(CTX, IN, INBYTES); \ + mld_shake128_finalize(CTX); \ + } while (0) + +#define mld_xof128_release(CTX) mld_shake128_release(CTX) +#define mld_xof128_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake128_squeeze(OUT, (OUTBLOCKS) * SHAKE128_RATE, STATE) + +#define mld_xof256_x4_ctx mld_shake256x4ctx +#define mld_xof256_x4_init(CTX) mld_shake256x4_init((CTX)) +#define mld_xof256_x4_absorb(CTX, IN, INBYTES) \ + mld_shake256x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof256_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake256x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof256_x4_release(CTX) mld_shake256x4_release((CTX)) + +#define mld_xof128_x4_ctx mld_shake128x4ctx +#define mld_xof128_x4_init(CTX) mld_shake128x4_init((CTX)) +#define mld_xof128_x4_absorb(CTX, IN, INBYTES) \ + mld_shake128x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof128_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake128x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof128_x4_release(CTX) mld_shake128x4_release((CTX)) + +#endif /* !MLD_SYMMETRIC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/sys.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/sys.h new file mode 100644 index 0000000000..1226526420 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/sys.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_SYS_H +#define MLD_SYS_H + +#if !defined(MLD_CONFIG_NO_ASM) && (defined(__GNUC__) || defined(__clang__)) +#define MLD_HAVE_INLINE_ASM +#endif + +/* Try to find endianness, if not forced through CFLAGS already */ +#if !defined(MLD_SYS_LITTLE_ENDIAN) && !defined(MLD_SYS_BIG_ENDIAN) +#if defined(__BYTE_ORDER__) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define MLD_SYS_LITTLE_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define MLD_SYS_BIG_ENDIAN +#else +#error "__BYTE_ORDER__ defined, but don't recognize value." +#endif +#endif /* __BYTE_ORDER__ */ + +/* MSVC does not define __BYTE_ORDER__. However, MSVC only supports + * little endian x86, x86_64, and AArch64. It is, hence, safe to assume + * little endian. */ +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_IX86) || defined(_M_ARM64)) +#define MLD_SYS_LITTLE_ENDIAN +#endif + +#endif /* !MLD_SYS_LITTLE_ENDIAN && !MLD_SYS_BIG_ENDIAN */ + +/* Check if we're running on an AArch64 little endian system. _M_ARM64 is set by + * MSVC. */ +#if defined(__AARCH64EL__) || defined(_M_ARM64) +#define MLD_SYS_AARCH64 +#endif + +/* Check if we're running on an AArch64 big endian system. */ +#if defined(__AARCH64EB__) +#define MLD_SYS_AARCH64_EB +#endif + +#if defined(__x86_64__) +#define MLD_SYS_X86_64 +#if defined(__AVX2__) +#define MLD_SYS_X86_64_AVX2 +#endif +#endif /* __x86_64__ */ + +#if defined(MLD_SYS_LITTLE_ENDIAN) && defined(__powerpc64__) +#define MLD_SYS_PPC64LE +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 +#define MLD_SYS_RISCV64 +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32 +#define MLD_SYS_RISCV32 +#endif + +#if defined(_WIN64) || defined(_WIN32) +#define MLD_SYS_WINDOWS +#endif + +#if defined(__linux__) +#define MLD_SYS_LINUX +#endif + +#if defined(__APPLE__) +#define MLD_SYS_APPLE +#endif + +/* If MLD_FORCE_AARCH64 is set, assert that we're indeed on an AArch64 system. + */ +#if defined(MLD_FORCE_AARCH64) && !defined(MLD_SYS_AARCH64) +#error "MLD_FORCE_AARCH64 is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_AARCH64_EB is set, assert that we're indeed on a big endian + * AArch64 system. */ +#if defined(MLD_FORCE_AARCH64_EB) && !defined(MLD_SYS_AARCH64_EB) +#error \ + "MLD_FORCE_AARCH64_EB is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_X86_64 is set, assert that we're indeed on an X86_64 system. */ +#if defined(MLD_FORCE_X86_64) && !defined(MLD_SYS_X86_64) +#error "MLD_FORCE_X86_64 is set, but we don't seem to be on an X86_64 system." +#endif + +#if defined(MLD_FORCE_PPC64LE) && !defined(MLD_SYS_PPC64LE) +#error "MLD_FORCE_PPC64LE is set, but we don't seem to be on a PPC64LE system." +#endif + +#if defined(MLD_FORCE_RISCV64) && !defined(MLD_SYS_RISCV64) +#error "MLD_FORCE_RISCV64 is set, but we don't seem to be on a RISCV64 system." +#endif + +#if defined(MLD_FORCE_RISCV32) && !defined(MLD_SYS_RISCV32) +#error "MLD_FORCE_RISCV32 is set, but we don't seem to be on a RISCV32 system." +#endif + +/* + * MLD_INLINE: Hint for inlining. + * - MSVC: __inline + * - C99+: inline + * - GCC/Clang C90: __attribute__((unused)) to silence warnings + * - Other C90: empty + */ +#if !defined(MLD_INLINE) +#if defined(_MSC_VER) +#define MLD_INLINE __inline +#elif defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +#define MLD_INLINE inline +#elif defined(__GNUC__) || defined(__clang__) +#define MLD_INLINE __attribute__((unused)) +#else +#define MLD_INLINE +#endif +#endif /* !MLD_INLINE */ + +/* + * MLD_ALWAYS_INLINE: Force inlining. + * - MSVC: __forceinline + * - GCC/Clang C99+: MLD_INLINE __attribute__((always_inline)) + * - Other: MLD_INLINE (no forced inlining) + */ +#if !defined(MLD_ALWAYS_INLINE) +#if defined(_MSC_VER) +#define MLD_ALWAYS_INLINE __forceinline +#elif (defined(__GNUC__) || defined(__clang__)) && \ + (defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)) +#define MLD_ALWAYS_INLINE MLD_INLINE __attribute__((always_inline)) +#else +#define MLD_ALWAYS_INLINE MLD_INLINE +#endif +#endif /* !MLD_ALWAYS_INLINE */ + +#ifndef MLD_STATIC_TESTABLE +#define MLD_STATIC_TESTABLE static +#endif + +/* + * C90 does not have the restrict compiler directive yet. + * We don't use it in C90 builds. + */ +#if !defined(restrict) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define MLD_RESTRICT restrict +#else +#define MLD_RESTRICT +#endif + +#else /* !restrict */ + +#define MLD_RESTRICT restrict +#endif /* restrict */ + +#define MLD_DEFAULT_ALIGN 32 +#define MLD_ALIGN_UP(N) \ + ((((N) + (MLD_DEFAULT_ALIGN - 1)) / MLD_DEFAULT_ALIGN) * MLD_DEFAULT_ALIGN) +#if defined(__GNUC__) +#define MLD_ALIGN __attribute__((aligned(MLD_DEFAULT_ALIGN))) +#elif defined(_MSC_VER) +#define MLD_ALIGN __declspec(align(MLD_DEFAULT_ALIGN)) +#else +#define MLD_ALIGN /* No known support for alignment constraints */ +#endif + + +/* New X86_64 CPUs support Conflow-flow protection using the CET instructions. + * When enabled (through -fcf-protection=), all compilation units (including + * empty ones) need to support CET for this to work. + * For assembly, this means that source files need to signal support for + * CET by setting the appropriate note.gnu.property section. + * This can be achieved by including the header in all assembly file. + * This file also provides the _CET_ENDBR macro which needs to be placed at + * every potential target of an indirect branch. + * If CET is enabled _CET_ENDBR maps to the endbr64 instruction, otherwise + * it is empty. + * In case the compiler does not support CET (e.g., +#define MLD_CET_ENDBR _CET_ENDBR +#else +#define MLD_CET_ENDBR +#endif +#endif /* MLD_SYS_X86_64 */ + +#if defined(MLD_CONFIG_CT_TESTING_ENABLED) && !defined(__ASSEMBLER__) +#include +#define MLD_CT_TESTING_SECRET(ptr, len) \ + VALGRIND_MAKE_MEM_UNDEFINED((ptr), (len)) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) +#else /* MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__ */ +#define MLD_CT_TESTING_SECRET(ptr, len) \ + do \ + { \ + } while (0) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + do \ + { \ + } while (0) +#endif /* !(MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__) */ + +#if defined(__GNUC__) || defined(__clang__) +#define MLD_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_MUST_CHECK_RETURN_VALUE +#endif + + +#if !defined(__ASSEMBLER__) +/* System capability enumeration */ +typedef enum +{ + /* x86_64 */ + MLD_SYS_CAP_AVX2, + /* AArch64 */ + MLD_SYS_CAP_SHA3 +} mld_sys_cap; + +#if !defined(MLD_CONFIG_CUSTOM_CAPABILITY_FUNC) +#include "cbmc.h" + +static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) +__contract__( + ensures(return_value == 0 || return_value == 1) +) +{ + /* By default, we rely on compile-time feature detection/specification: + * If a feature is enabled at compile-time, we assume it is supported by + * the host that the resulting library/binary will be built on. + * If this assumption is not true, you MUST overwrite this function. + * See the documentation of MLD_CONFIG_CUSTOM_CAPABILITY_FUNC in + * mldsa_native_config.h for more information. */ + (void)cap; + return 1; +} +#endif /* !MLD_CONFIG_CUSTOM_CAPABILITY_FUNC */ +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_SYS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/zetas.inc b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/zetas.inc new file mode 100644 index 0000000000..dc3cf15dd3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/mldsa_native/src/zetas.inc @@ -0,0 +1,56 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include + +/* + * Table of zeta values used in the reference NTT and inverse NTT. + * See autogen for details. + */ +static const int32_t mld_zetas[MLDSA_N] = { + 0, 25847, -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 2353451, -359251, -2091905, 3119733, -2884855, + 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488, + -1119584, 2619752, -2108549, -2118186, -3859737, -1399561, -3277672, + 1757237, -19422, 4010497, 280005, 2706023, 95776, 3077325, + 3530437, -1661693, -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267, + -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596, + 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, + -2797779, -3930395, -1528703, -3677745, -3041255, -1452451, 3475950, + 2176455, -1585221, -1257611, 1939314, -4083598, -1000202, -3190144, + -3157330, -3632928, 126922, 3412210, -983419, 2147896, 2715295, + -2967645, -3693493, -411027, -2477047, -671102, -1228525, -22981, + -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944, + 508951, 3097992, 44288, -1100098, 904516, 3958618, -3724342, + -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856, + 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, + 1341330, 1285669, -1584928, -812732, -1439742, -3019102, -3881060, + -3628969, 3839961, 2091667, 3407706, 2316500, 3817976, -3342478, + 2244091, -2446433, -3562462, 266997, 2434439, -1235728, 3513181, + -3520352, -3759364, -1197226, -3193378, 900702, 1859098, 909542, + 819034, 495491, -1613174, -43260, -522500, -655327, -3122442, + 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297, + 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, + 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, + 1595974, -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, + 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100, + 1312455, 3306115, -1962642, -1279661, 1917081, -2546312, -1374803, + 1500165, 777191, 2235880, 3406031, -542412, -2831860, -1671176, + -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395, + 2454455, -164721, 1957272, 3369112, 185531, -1207385, -3183426, + 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, + -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, + 472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333, + -260646, -3833893, -2939036, -2235985, -420899, -2286327, 183443, + -976891, 1612842, -3545687, -554416, 3919660, -48306, -1362209, + 3937738, 1400424, -846154, 1976782, +}; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/test_only_rng/notrandombytes.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/test_only_rng/notrandombytes.c new file mode 100644 index 0000000000..ef5a423a9e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/test_only_rng/notrandombytes.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* * Based on @[surf]*/ + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +#include +#include + +#include "notrandombytes.h" + +#ifdef ENABLE_CT_TESTING +#include +#endif + +static uint32_t seed[32] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, + 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5}; +static uint32_t in[12]; +static uint32_t out[8]; +static int32_t outleft = 0; + +void randombytes_reset(void) +{ + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + outleft = 0; +} + +#define ROTATE(x, b) (((x) << (b)) | ((x) >> (32 - (b)))) +#define MUSH(i, b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x, b)); + +static void surf(void) +{ + uint32_t t[12]; + uint32_t x; + uint32_t sum = 0; + int32_t r; + int32_t i; + int32_t loop; + + for (i = 0; i < 12; ++i) + { + t[i] = in[i] ^ seed[12 + i]; + } + for (i = 0; i < 8; ++i) + { + out[i] = seed[24 + i]; + } + x = t[11]; + for (loop = 0; loop < 2; ++loop) + { + for (r = 0; r < 16; ++r) + { + sum += 0x9e3779b9; + MUSH(0, 5) + MUSH(1, 7) + MUSH(2, 9) + MUSH(3, 13) + MUSH(4, 5) + MUSH(5, 7) + MUSH(6, 9) + MUSH(7, 13) + MUSH(8, 5) + MUSH(9, 7) + MUSH(10, 9) + MUSH(11, 13) + } + for (i = 0; i < 8; ++i) + { + out[i] ^= t[i + 4]; + } + } +} + +int randombytes(uint8_t *buf, size_t n) +{ +#ifdef ENABLE_CT_TESTING + uint8_t *buf_orig = buf; + size_t n_orig = n; +#endif + + while (n > 0) + { + if (!outleft) + { + if (!++in[0]) + { + if (!++in[1]) + { + if (!++in[2]) + { + ++in[3]; + } + } + } + surf(); + outleft = 8; + } + *buf = (uint8_t)out[--outleft]; + ++buf; + --n; + } + +#ifdef ENABLE_CT_TESTING + /* + * Mark all randombytes output as secret (undefined). + * Valgrind will propagate this to everything derived from it. + */ + VALGRIND_MAKE_MEM_UNDEFINED(buf_orig, n_orig); +#endif /* ENABLE_CT_TESTING */ + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/test_only_rng/notrandombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/test_only_rng/notrandombytes.h new file mode 100644 index 0000000000..bdf9787920 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build/test_only_rng/notrandombytes.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* Based on @[surf]. */ + +#ifndef NOTRANDOMBYTES_H +#define NOTRANDOMBYTES_H + +#include +#include + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +void randombytes_reset(void); +int randombytes(uint8_t *buf, size_t n); + +#endif /* !NOTRANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/.gitignore b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/.gitignore new file mode 100644 index 0000000000..834e997200 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/.gitignore @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +build/ +*.d diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/Makefile new file mode 100644 index 0000000000..2330847c1e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/Makefile @@ -0,0 +1,103 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +.PHONY: build run clean +.DEFAULT_GOAL := all + +CC ?= gcc +AR ?= ar + +# Adjust CFLAGS if needed +CFLAGS := \ + -Wall \ + -Wextra \ + -Werror=unused-result \ + -Wpedantic \ + -Werror \ + -Wmissing-prototypes \ + -Wshadow \ + -Wpointer-arith \ + -Wredundant-decls \ + -Wconversion \ + -Wsign-conversion \ + -Wno-long-long \ + -Wno-unknown-pragmas \ + -Wno-unused-command-line-argument \ + -O3 \ + -fomit-frame-pointer \ + -std=c99 \ + -pedantic \ + -MMD \ + $(CFLAGS) + + +# The following only concerns the cross-compilation tests. +# You can likely ignore the following for your application. +# +# Append cross-prefix for cross compilation +# When called from the root Makefile, CROSS_PREFIX has already been added here +ifeq (,$(findstring $(CROSS_PREFIX),$(CC))) +CC := $(CROSS_PREFIX)$(CC) +endif + +ifeq (,$(findstring $(CROSS_PREFIX),$(AR))) +AR := $(CROSS_PREFIX)$(AR) +endif + +# Part A: +# +# mldsa-native source and header files +# +# Here, we use just a single monolithic compilation unit to include +# multiple instances of mldsa-native. + +MLD_SOURCE=mldsa_native_all.c + +INC=-Imldsa_native/ -I./ + +# Part B: +# +# Random number generator +# +# !!! WARNING !!! +# +# The randombytes() implementation used here is for TESTING ONLY. +# You MUST NOT use this implementation outside of testing. +# +# !!! WARNING !!! +RNG_SOURCE=$(wildcard test_only_rng/*.c) + +# Part C: +# +# Your application source code +APP_SOURCE=$(RNG_SOURCE) main.c + +BUILD_DIR=build +BIN=test_binary +LIB=libmldsa.a + +BINARY_NAME_FULL=$(BUILD_DIR)/$(BIN) +LIB_NAME_FULL=$(BUILD_DIR)/$(LIB) + +$(LIB_NAME_FULL): $(MLD_SOURCE) + echo "$@" + mkdir -p $(BUILD_DIR) + $(CC) -c $(CFLAGS) $(INC) $^ -o $(BUILD_DIR)/mldsa_native.o + $(AR) rcs $@ $(BUILD_DIR)/mldsa_native.o + strip -S $@ + +$(BINARY_NAME_FULL): $(APP_SOURCE) $(LIB_NAME_FULL) + echo "$@" + mkdir -p $(BUILD_DIR) + $(CC) $(CFLAGS) $(INC) $^ -o $@ + +all: build + +build: $(BINARY_NAME_FULL) + +run: $(BINARY_NAME_FULL) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL) + +clean: + rm -rf $(BUILD_DIR) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/README.md new file mode 100644 index 0000000000..c83238fc49 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/README.md @@ -0,0 +1,95 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Monolithic Multi-Level Build (C Backend) + +This directory contains a minimal example for building all three ML-DSA security levels in a single +compilation unit, with shared code deduplicated. + +## Use Case + +Use this approach when: +- You need all ML-DSA security levels in one application +- You want the simplest possible multi-level integration (one `.c` file) +- You're using only C (no native backend) + +## Components + +An application using mldsa-native as a monolithic multi-level build needs: + +1. Source tree [mldsa_native/*](mldsa_native), including top-level compilation unit + [mldsa_native.c](mldsa_native/mldsa_native.c) (gathering all C sources) + and the mldsa-native API [mldsa_native.h](mldsa_native/mldsa_native.h). +2. Manually provided wrapper file [mldsa_native_all.c](mldsa_native_all.c), + including `mldsa_native.c` three times. +3. Manually provided header file [mldsa_native_all.h](mldsa_native_all.h), + including `mldsa_native.h` three times) +4. A secure random number generator implementing [`randombytes.h`](../../mldsa/src/randombytes.h) +5. Your application source code + +## Configuration + +The configuration file [mldsa_native_config.h](mldsa_native/mldsa_native_config.h) sets: +- `MLD_CONFIG_MULTILEVEL_BUILD`: Enables multi-level mode +- `MLD_CONFIG_NAMESPACE_PREFIX=mldsa`: Base prefix +- `MLD_CONFIG_INTERNAL_API_QUALIFIER=static`: Makes internal functions static +- `MLD_CONFIG_NO_SUPERCOP`: Disables the SUPERCOP API (crypto_sign*) + +The wrapper [mldsa_native_all.c](mldsa_native_all.c) includes `mldsa_native.c` three times: +```c +#define MLD_CONFIG_FILE "multilevel_config.h" + +/* Include level-independent code with first level */ +#define MLD_CONFIG_MULTILEVEL_WITH_SHARED +#define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS +#define MLD_CONFIG_PARAMETER_SET 44 +#include "mldsa_native.c" +#undef MLD_CONFIG_PARAMETER_SET +#undef MLD_CONFIG_MULTILEVEL_WITH_SHARED + +/* Exclude level-independent code for subsequent levels */ +#define MLD_CONFIG_MULTILEVEL_NO_SHARED +#define MLD_CONFIG_PARAMETER_SET 65 +#include "mldsa_native.c" +#undef MLD_CONFIG_PARAMETER_SET +#undef MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + +#define MLD_CONFIG_PARAMETER_SET 87 +#include "mldsa_native.c" +#undef MLD_CONFIG_PARAMETER_SET +``` + +The header [mldsa_native_all.h](mldsa_native_all.h) exposes all APIs: +```c +#define MLD_CONFIG_PARAMETER_SET 44 +#include +#undef MLD_CONFIG_PARAMETER_SET +#undef MLD_H + +#define MLD_CONFIG_PARAMETER_SET 65 +#include +#undef MLD_CONFIG_PARAMETER_SET +#undef MLD_H + +#define MLD_CONFIG_PARAMETER_SET 87 +#include +#undef MLD_CONFIG_PARAMETER_SET +#undef MLD_H +``` + +## Notes + +- `MLD_CONFIG_MULTILEVEL_WITH_SHARED` must be set for exactly ONE level +- `MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS` prevents cleanup of shared headers between inclusions +- `MLD_CONFIG_NO_SUPERCOP` is required to avoid conflicting `CRYPTO_*` macro definitions + +## Usage + +```bash +make build # Build the example +make run # Run the example +``` + +## Warning + +The `randombytes()` implementation in `test_only_rng/` is for TESTING ONLY. +You MUST provide a cryptographically secure RNG for production use. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/expected_signatures.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/expected_signatures.h new file mode 100644 index 0000000000..582c6309d4 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/expected_signatures.h @@ -0,0 +1,886 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef EXPECTED_SIGNATURES_H +#define EXPECTED_SIGNATURES_H + +#include + +/* Expected deterministic signatures for each parameter set + * These are generated using the same test message, context, and deterministic + * RNG as used in the basic example. + * + * The PCT modifies the PRNG state, so the KAT tests don't work. + * We run KAT tests only for disabled PCT. */ +#if !defined(MLD_CONFIG_KEYGEN_PCT) +const uint8_t expected_signature_44[] = { + 0x27, 0x5e, 0xbe, 0x2d, 0x23, 0x1a, 0x76, 0xc5, 0xd9, 0x77, 0xcb, 0x62, + 0x25, 0x04, 0xdb, 0x23, 0x31, 0xa9, 0xa8, 0xcd, 0xbc, 0xde, 0xf2, 0x20, + 0xfd, 0xa7, 0xb5, 0xf5, 0x59, 0xae, 0xe6, 0xdd, 0x62, 0xfa, 0x34, 0x96, + 0x4f, 0x1d, 0xcd, 0x84, 0x82, 0xee, 0xc1, 0x74, 0x96, 0x3d, 0x98, 0xd9, + 0x42, 0x9d, 0xd0, 0x77, 0x9c, 0xf9, 0x9e, 0x0e, 0xa7, 0xcb, 0x70, 0xeb, + 0xe7, 0xcd, 0xce, 0x8c, 0xdc, 0x37, 0x15, 0x95, 0x0e, 0x24, 0x70, 0x4f, + 0x33, 0x6e, 0x4f, 0xad, 0xed, 0x4d, 0xf3, 0xe5, 0x38, 0xc1, 0xcd, 0xbb, + 0xde, 0xf1, 0xd2, 0x0d, 0xd6, 0x6b, 0xa3, 0x68, 0x92, 0x4c, 0x4b, 0x4f, + 0x89, 0xa0, 0xa8, 0xc8, 0x36, 0x93, 0x91, 0x17, 0xe7, 0x16, 0xed, 0xcb, + 0xdc, 0xf6, 0x28, 0x13, 0x32, 0x60, 0x14, 0xe0, 0x28, 0x7a, 0x69, 0x05, + 0x1d, 0xf7, 0x3b, 0xdf, 0x18, 0x0c, 0xaf, 0xba, 0x46, 0xf1, 0x5e, 0xd4, + 0xd3, 0xd0, 0x8e, 0x9a, 0xe2, 0xac, 0xdd, 0x0e, 0x5f, 0xb1, 0x69, 0xe2, + 0x74, 0x77, 0x2e, 0x52, 0xf9, 0x11, 0x3d, 0xd8, 0xe5, 0x36, 0x6f, 0x7d, + 0x7d, 0xde, 0x7c, 0xa7, 0x1d, 0x37, 0xdf, 0x6d, 0x5e, 0xea, 0xc8, 0xc0, + 0x72, 0x3f, 0x79, 0xbd, 0x0b, 0x6d, 0x7f, 0x9a, 0x15, 0x90, 0xda, 0xc1, + 0xae, 0xce, 0xf3, 0x44, 0x35, 0x5e, 0x83, 0x86, 0x7e, 0x89, 0x18, 0xa7, + 0x97, 0x8e, 0x87, 0x7c, 0x15, 0xd2, 0xd2, 0x7e, 0xf2, 0xc8, 0x29, 0x4f, + 0x70, 0x0f, 0xa6, 0xd4, 0x76, 0xe8, 0xdd, 0x7d, 0x7a, 0x2d, 0xfe, 0x0a, + 0x0c, 0x5c, 0xb1, 0xef, 0xec, 0x1a, 0x32, 0xca, 0x87, 0xff, 0x6b, 0xb1, + 0xa0, 0xe1, 0x2e, 0x01, 0x52, 0xb2, 0xb8, 0x74, 0x34, 0xb3, 0xfb, 0x15, + 0x0f, 0x17, 0xca, 0x74, 0xc1, 0xc1, 0x61, 0x86, 0x40, 0x38, 0x58, 0xba, + 0x82, 0x26, 0x66, 0x33, 0xa4, 0x52, 0xf3, 0xb5, 0x36, 0x60, 0xd8, 0x5a, + 0x8d, 0x9d, 0x28, 0x18, 0x3a, 0x68, 0x34, 0x2a, 0xa2, 0xe2, 0xb5, 0x39, + 0xed, 0x7d, 0xe5, 0xbe, 0x46, 0xb9, 0x04, 0x0c, 0xf3, 0xef, 0x88, 0x6e, + 0x9d, 0x6f, 0x23, 0xe2, 0x44, 0xe5, 0x2e, 0x3a, 0x7a, 0x1d, 0x49, 0x0f, + 0xdd, 0xcd, 0xd6, 0x4e, 0x0d, 0x0b, 0xc3, 0x35, 0xf2, 0xd1, 0x5d, 0x73, + 0x5d, 0x07, 0xca, 0x5c, 0xbd, 0x14, 0xec, 0x57, 0xb3, 0xbd, 0x37, 0xe7, + 0xdf, 0x06, 0x7d, 0xe0, 0x58, 0x4a, 0xcf, 0x7a, 0xc5, 0xa7, 0x24, 0x62, + 0x6f, 0x09, 0x75, 0x69, 0x74, 0x7f, 0xdf, 0xc8, 0x69, 0x5c, 0x20, 0x10, + 0x3a, 0xe8, 0x01, 0x12, 0xa3, 0xfb, 0xda, 0x4c, 0x3a, 0x0d, 0x3c, 0x3e, + 0x26, 0xe0, 0xa6, 0x7f, 0xb2, 0x6b, 0x0b, 0x68, 0x0a, 0x68, 0x86, 0xb1, + 0xfa, 0x61, 0x3a, 0xe8, 0x77, 0xdc, 0x42, 0xf7, 0xf4, 0x39, 0x9a, 0x40, + 0x58, 0x71, 0xc7, 0x0f, 0xf4, 0x0e, 0xc5, 0x1e, 0xe0, 0x28, 0x45, 0x7d, + 0xba, 0x84, 0xe4, 0x34, 0x69, 0xf9, 0xa5, 0x8a, 0x80, 0x43, 0xc0, 0x8d, + 0x04, 0x33, 0x43, 0xb8, 0xd7, 0x5d, 0x93, 0xed, 0x0f, 0x31, 0x6a, 0x4d, + 0xbf, 0xb7, 0x44, 0x41, 0x1b, 0xd4, 0xac, 0x9d, 0x83, 0x66, 0x08, 0x92, + 0xad, 0x3c, 0x0e, 0x1a, 0xe8, 0xd4, 0xe1, 0x5c, 0x63, 0xcf, 0x27, 0x48, + 0x5a, 0x8f, 0xc5, 0x6f, 0x83, 0x6b, 0x6f, 0xe8, 0xda, 0x1f, 0xba, 0xe9, + 0x7e, 0x11, 0xab, 0x8b, 0x4e, 0xc1, 0x9e, 0x23, 0x69, 0x1f, 0x42, 0x40, + 0xad, 0xbb, 0xfb, 0x4f, 0xe2, 0x50, 0xc9, 0x46, 0xe7, 0x15, 0x15, 0xf8, + 0x61, 0x09, 0x2a, 0x0b, 0x37, 0x43, 0xd4, 0x98, 0x5f, 0xc8, 0x4d, 0x06, + 0xe7, 0x0c, 0x3f, 0x83, 0x59, 0xd5, 0xcd, 0x2d, 0xde, 0x1e, 0x3a, 0x87, + 0x4e, 0xf7, 0x0a, 0x3c, 0x84, 0x72, 0x47, 0x11, 0x02, 0x6c, 0xe8, 0x93, + 0xcd, 0x24, 0xe9, 0x23, 0x86, 0x78, 0x53, 0xe0, 0xc6, 0x2f, 0xba, 0xa7, + 0xed, 0xaf, 0xba, 0x42, 0x80, 0x0d, 0xe6, 0xae, 0xda, 0xed, 0xbc, 0x65, + 0x21, 0x6d, 0x13, 0x90, 0x61, 0xb4, 0x05, 0x7b, 0x07, 0x86, 0xd7, 0x89, + 0x30, 0x9c, 0xc1, 0x9a, 0x41, 0x4d, 0xe8, 0x2b, 0x35, 0x21, 0x3a, 0x8a, + 0x60, 0x83, 0x1a, 0x97, 0x10, 0x98, 0xb6, 0xe1, 0x6b, 0xb5, 0xb1, 0xa1, + 0x36, 0x34, 0x60, 0x1b, 0x96, 0x5d, 0x1f, 0x2a, 0xd8, 0xf2, 0x94, 0xdd, + 0x58, 0x3d, 0x0f, 0xbe, 0x9d, 0xfc, 0xf5, 0x24, 0xb1, 0xd2, 0xc3, 0x36, + 0xef, 0xdb, 0x8e, 0x97, 0x3c, 0x9a, 0x4f, 0x48, 0xe3, 0x84, 0x91, 0xd8, + 0x39, 0x91, 0xf6, 0x55, 0xeb, 0x62, 0x51, 0x3d, 0x8f, 0x55, 0x60, 0x5e, + 0x00, 0xe0, 0xd2, 0xc7, 0x66, 0x51, 0xf1, 0xe2, 0xb7, 0x43, 0xc3, 0xe6, + 0x12, 0x9a, 0xe5, 0x84, 0xe0, 0x10, 0x76, 0xc7, 0x75, 0x6e, 0xa6, 0xee, + 0x11, 0xe4, 0xaf, 0xbd, 0x8a, 0x4f, 0x1d, 0x05, 0x29, 0x4f, 0xce, 0xa5, + 0x73, 0x92, 0x57, 0x7e, 0x0d, 0x11, 0xbc, 0xf8, 0x74, 0x4d, 0xf7, 0xb9, + 0x40, 0x0d, 0x5a, 0xa1, 0x19, 0x76, 0x4a, 0xae, 0x21, 0x16, 0xd4, 0x3f, + 0x76, 0xbf, 0x27, 0xbd, 0x2f, 0xe4, 0x25, 0x21, 0x00, 0x4e, 0xcc, 0x7c, + 0xc6, 0x57, 0xa4, 0xbf, 0xf1, 0x56, 0x90, 0xe0, 0xa4, 0xa3, 0xee, 0xcf, + 0x43, 0x4f, 0xda, 0x77, 0x47, 0x51, 0x79, 0x6a, 0x29, 0xb4, 0x2c, 0xdf, + 0xca, 0x47, 0xcb, 0xb8, 0x82, 0x7e, 0x44, 0x62, 0x9b, 0x8f, 0x61, 0x7b, + 0x3a, 0x93, 0x82, 0x1f, 0x69, 0xb7, 0xb1, 0xa6, 0x2c, 0xe1, 0xb2, 0x65, + 0xa0, 0x6d, 0x6f, 0xe4, 0x79, 0xd8, 0x30, 0xe0, 0xee, 0xd8, 0x83, 0x01, + 0xb2, 0x1f, 0x5c, 0x90, 0x44, 0x86, 0x48, 0x11, 0xf9, 0x11, 0xff, 0xea, + 0x45, 0x43, 0xae, 0x8a, 0x6b, 0x99, 0xf2, 0x1f, 0x02, 0x51, 0x4a, 0x35, + 0x02, 0x34, 0xd3, 0xe8, 0xda, 0xb1, 0x4b, 0xe3, 0xa5, 0x60, 0xce, 0x67, + 0xe3, 0x62, 0x59, 0xfc, 0x00, 0x0a, 0xe2, 0xfe, 0x7b, 0x1e, 0xe6, 0xf5, + 0x75, 0x19, 0x9b, 0x5e, 0xcb, 0xe6, 0xf5, 0x80, 0x9e, 0x3c, 0xb8, 0x54, + 0xd6, 0x0b, 0xfd, 0x48, 0xe0, 0xfa, 0x82, 0x2b, 0x5b, 0x26, 0xf9, 0x49, + 0xaf, 0xbe, 0x9c, 0x78, 0x73, 0xce, 0xc5, 0x65, 0xe2, 0x94, 0x2b, 0xd9, + 0xd0, 0x27, 0x3a, 0x66, 0x3e, 0xe2, 0xe0, 0x10, 0x79, 0x3d, 0xde, 0xc8, + 0x47, 0xdb, 0x1e, 0xc3, 0xe7, 0x51, 0xae, 0x59, 0xeb, 0x38, 0x66, 0x63, + 0x40, 0x8f, 0xbe, 0x1e, 0xb2, 0x2b, 0xeb, 0x64, 0x5f, 0xdd, 0x24, 0xc4, + 0x5a, 0x25, 0x59, 0xa2, 0xda, 0x4f, 0xdf, 0xf8, 0xb0, 0xb0, 0xf7, 0xcd, + 0x1f, 0x14, 0xcd, 0x09, 0x48, 0x70, 0x27, 0x1b, 0xde, 0xc4, 0xf0, 0xf3, + 0x56, 0x97, 0x8a, 0xb7, 0xf4, 0x19, 0x76, 0xe3, 0x9a, 0x33, 0x55, 0xfe, + 0x93, 0x68, 0xca, 0x1f, 0x3d, 0x44, 0x86, 0x39, 0x5d, 0x84, 0x58, 0x50, + 0xf2, 0xf1, 0xea, 0x4a, 0x5c, 0x1c, 0x74, 0xf0, 0x4b, 0xa5, 0x9c, 0x30, + 0xa0, 0x14, 0x1a, 0x80, 0xe0, 0xde, 0x3e, 0xae, 0x7f, 0x10, 0x18, 0x4a, + 0x1e, 0x9e, 0x6b, 0x75, 0x1a, 0xca, 0x08, 0x4e, 0x61, 0x72, 0x43, 0x9b, + 0x18, 0x4d, 0x2c, 0xd8, 0xb4, 0xc9, 0xea, 0x00, 0xb0, 0xdf, 0x1b, 0xcb, + 0x03, 0xc3, 0x7a, 0x27, 0xff, 0x41, 0x9d, 0xf9, 0xfd, 0xb3, 0x0c, 0xc0, + 0x48, 0x5d, 0x7c, 0xae, 0x5a, 0x72, 0x69, 0x93, 0x68, 0xe1, 0x9e, 0x9f, + 0x1f, 0x5c, 0x0a, 0x60, 0x90, 0x1a, 0x8e, 0x5a, 0x30, 0xd4, 0x2c, 0xbd, + 0xe1, 0x20, 0x51, 0xbc, 0x1c, 0x50, 0xb5, 0xf7, 0x42, 0x23, 0x35, 0x0f, + 0x92, 0xe2, 0xbb, 0x2a, 0x04, 0xa7, 0xde, 0x2e, 0x25, 0xfa, 0xed, 0x20, + 0x83, 0x9c, 0xd4, 0x56, 0xe0, 0x4d, 0x8d, 0x79, 0xa5, 0xa0, 0x6f, 0x49, + 0x62, 0x82, 0x9a, 0xa7, 0x4e, 0x54, 0x95, 0x0a, 0xc6, 0x5e, 0x27, 0x65, + 0x6d, 0x11, 0x2b, 0x35, 0x72, 0x34, 0x48, 0xd2, 0xe4, 0x9e, 0x07, 0x7d, + 0x03, 0x27, 0x15, 0x93, 0x55, 0x5c, 0x32, 0x43, 0xdb, 0x34, 0x8d, 0xbd, + 0x8d, 0x88, 0xa5, 0x24, 0x07, 0x93, 0x89, 0x37, 0xb9, 0x17, 0x15, 0xad, + 0xc7, 0x68, 0x86, 0x63, 0x0f, 0x10, 0x53, 0x8f, 0x40, 0xd3, 0x7b, 0x22, + 0x2b, 0x1a, 0x4c, 0xcb, 0x4f, 0x51, 0xf1, 0x3b, 0x19, 0xb8, 0x42, 0x53, + 0xaf, 0xf6, 0xb9, 0x57, 0x7f, 0xba, 0x8d, 0xb8, 0xb7, 0x3b, 0xe3, 0xc5, + 0xab, 0x4a, 0x26, 0x21, 0x6e, 0xce, 0x27, 0xb8, 0xc3, 0x99, 0x56, 0x14, + 0xdd, 0x5b, 0x61, 0x82, 0xbf, 0xd3, 0xc8, 0x76, 0xee, 0x22, 0xaf, 0x21, + 0x21, 0x1d, 0x4e, 0x33, 0xb5, 0x43, 0x3a, 0xfb, 0x91, 0xa0, 0xaa, 0xe3, + 0x10, 0x4a, 0x50, 0x42, 0xd4, 0x5f, 0x92, 0x0e, 0x71, 0x60, 0x4f, 0xaa, + 0xef, 0x66, 0x45, 0xfe, 0xf7, 0xc8, 0xb0, 0x73, 0x75, 0x91, 0x0b, 0x86, + 0x40, 0xa5, 0x02, 0x28, 0xf7, 0xe0, 0x1f, 0x5d, 0xe6, 0xe3, 0xa4, 0x57, + 0xbd, 0x29, 0xaa, 0x53, 0xae, 0x35, 0x30, 0x78, 0x73, 0xd6, 0xb7, 0x01, + 0x9d, 0x13, 0x50, 0xf6, 0x39, 0xa2, 0x3e, 0x03, 0x04, 0xaa, 0x6d, 0xcf, + 0x6b, 0xff, 0x9a, 0xbe, 0x3e, 0x0a, 0xd4, 0x20, 0xce, 0x42, 0x1f, 0xca, + 0x2f, 0xd3, 0x2c, 0xd1, 0xf4, 0xd2, 0x50, 0xd3, 0xa2, 0xc1, 0x1e, 0x87, + 0xbf, 0xeb, 0xb8, 0xa8, 0xd4, 0x1c, 0x96, 0xb8, 0x8e, 0xbe, 0x35, 0x5f, + 0x08, 0x28, 0x20, 0x2b, 0xdc, 0xa4, 0xf5, 0xf6, 0xde, 0xca, 0x1e, 0xcb, + 0x93, 0x3b, 0x64, 0x79, 0x00, 0x3c, 0x8d, 0xbb, 0x5c, 0x7a, 0x40, 0x14, + 0x58, 0x12, 0xa4, 0xf7, 0x6e, 0x51, 0xfb, 0xe7, 0x6f, 0x49, 0x5b, 0xc2, + 0xc9, 0x05, 0x38, 0x9c, 0x08, 0x78, 0x71, 0x27, 0x2b, 0xf5, 0xbf, 0xd6, + 0x38, 0xaa, 0x45, 0xe1, 0xe1, 0x4c, 0xfb, 0xfd, 0xb7, 0xe6, 0xcf, 0xad, + 0x9e, 0x56, 0xaf, 0x12, 0x12, 0x98, 0xe6, 0x38, 0xaa, 0xee, 0xdb, 0x9e, + 0xca, 0xe1, 0x79, 0x6d, 0x44, 0xfb, 0x19, 0x50, 0x92, 0x00, 0x06, 0x2c, + 0x24, 0x71, 0x6c, 0x34, 0x45, 0xac, 0xf9, 0x82, 0x66, 0xa8, 0x63, 0x80, + 0xa8, 0x5b, 0x21, 0x3c, 0x36, 0x71, 0x93, 0x40, 0x7b, 0xff, 0xa2, 0xd0, + 0x72, 0xb4, 0x66, 0xfa, 0xfc, 0xa0, 0xee, 0xca, 0x15, 0x73, 0x52, 0xe7, + 0x9d, 0x11, 0xd3, 0xbc, 0xab, 0x37, 0x31, 0x0e, 0xaf, 0xdc, 0x05, 0x30, + 0x79, 0x8c, 0x25, 0x75, 0x5c, 0x60, 0xc7, 0x9a, 0xfc, 0x88, 0xea, 0xe6, + 0x09, 0x9f, 0xd1, 0x4f, 0x13, 0xf4, 0x41, 0x54, 0x5b, 0x7a, 0xe4, 0x49, + 0x3c, 0x0f, 0x15, 0xe9, 0xa4, 0x85, 0xb2, 0x92, 0x07, 0xea, 0xea, 0x7c, + 0xc1, 0x6d, 0xa9, 0x03, 0xb3, 0x31, 0xce, 0x1e, 0x82, 0xca, 0x9e, 0x3c, + 0x88, 0x88, 0xc1, 0x04, 0x5f, 0xbe, 0xd5, 0x94, 0x0d, 0x67, 0x98, 0x27, + 0xd0, 0x0f, 0x43, 0xf3, 0xb3, 0xfc, 0xff, 0x24, 0xa2, 0x1e, 0x17, 0x06, + 0xb0, 0x52, 0x16, 0x7c, 0xd8, 0x49, 0x74, 0x51, 0xcf, 0x2d, 0x36, 0x16, + 0xb0, 0x88, 0xb2, 0x2b, 0x1d, 0x72, 0x70, 0xab, 0xe2, 0xf6, 0x5f, 0xa5, + 0x2d, 0x4e, 0xd1, 0x42, 0x3c, 0x83, 0x84, 0xb2, 0x56, 0xeb, 0x8d, 0xce, + 0x33, 0x46, 0xdb, 0x3d, 0x4f, 0x97, 0xea, 0x37, 0x5e, 0x0d, 0xd7, 0x4c, + 0x9a, 0x7e, 0xc9, 0x0e, 0x69, 0x4d, 0x97, 0x15, 0x1e, 0x09, 0xbe, 0x7e, + 0xff, 0xe8, 0xf5, 0xab, 0xe9, 0xe7, 0xed, 0x4b, 0x41, 0xa5, 0xf2, 0x2a, + 0x24, 0x48, 0x8b, 0x72, 0x4b, 0x9d, 0xcf, 0x45, 0xdb, 0xc0, 0xaf, 0xa8, + 0x0f, 0x0f, 0x67, 0x37, 0xd3, 0x8b, 0xe1, 0x67, 0x90, 0xd8, 0x1c, 0x58, + 0x36, 0x46, 0x51, 0x52, 0xea, 0xb4, 0x75, 0xb1, 0xcd, 0xc5, 0x39, 0x16, + 0xe0, 0xec, 0x16, 0xf7, 0xf8, 0x0f, 0x5d, 0x13, 0x84, 0x62, 0x34, 0x86, + 0x42, 0x05, 0xa8, 0x08, 0x84, 0xa9, 0x77, 0x12, 0xc1, 0x56, 0xdd, 0x28, + 0xde, 0x39, 0x33, 0x21, 0x3d, 0xbd, 0x94, 0xce, 0xe4, 0xb3, 0x17, 0x9b, + 0x09, 0x20, 0xf0, 0x25, 0xce, 0x00, 0x34, 0x8e, 0x12, 0x94, 0x74, 0x0b, + 0x16, 0xa1, 0x60, 0x76, 0x24, 0xf0, 0xbf, 0xe3, 0x3a, 0x83, 0x8f, 0x40, + 0x47, 0x2e, 0x1c, 0xd5, 0x35, 0x25, 0x87, 0xb3, 0x11, 0xdc, 0x98, 0xb0, + 0xa6, 0x5f, 0x6a, 0x05, 0x1d, 0x06, 0x8d, 0xe8, 0xb0, 0x98, 0xf0, 0x43, + 0x29, 0x84, 0xe4, 0xef, 0x34, 0x67, 0x74, 0x64, 0xe8, 0xb8, 0xf0, 0xd4, + 0x9e, 0xc1, 0x3f, 0x5f, 0xeb, 0xe0, 0x9b, 0x37, 0xf8, 0x75, 0x46, 0x47, + 0xa5, 0x3e, 0x42, 0x20, 0x50, 0xc4, 0x5d, 0xf3, 0xdf, 0x4e, 0xf8, 0x0e, + 0x1e, 0x15, 0x10, 0x3e, 0xf1, 0x68, 0xad, 0x87, 0xad, 0xe5, 0x45, 0x5e, + 0x22, 0xba, 0x2e, 0x51, 0xa0, 0xbf, 0xdc, 0x87, 0xca, 0xe4, 0x1f, 0x2f, + 0x2c, 0xae, 0xa9, 0x14, 0xd7, 0xdd, 0x01, 0xa8, 0x4f, 0x43, 0xcb, 0x84, + 0x92, 0xbf, 0xf9, 0x3d, 0xf0, 0x6b, 0x19, 0x43, 0xb0, 0xdf, 0xff, 0x94, + 0x76, 0xe2, 0x84, 0xf9, 0x31, 0x88, 0x7e, 0xc6, 0x87, 0x58, 0xbe, 0x5d, + 0x8b, 0xf8, 0xb5, 0xdc, 0x95, 0x16, 0x5f, 0xa1, 0x2c, 0xe8, 0x53, 0x36, + 0x64, 0xf5, 0x5d, 0xa0, 0x74, 0x12, 0x78, 0x59, 0x73, 0x69, 0x5a, 0x2b, + 0x36, 0x4a, 0xff, 0x5b, 0xef, 0x49, 0x2c, 0xb2, 0x9e, 0x59, 0xf0, 0x39, + 0x56, 0xe1, 0xd0, 0x1a, 0x05, 0xb2, 0x7c, 0xd1, 0x40, 0x09, 0xdf, 0x00, + 0xc9, 0x15, 0x53, 0xa2, 0xda, 0x84, 0xb5, 0x85, 0x05, 0x76, 0xa6, 0x1b, + 0xcb, 0x06, 0xb2, 0xc8, 0xa0, 0xc5, 0x23, 0x8f, 0xb0, 0xe8, 0xf5, 0xd9, + 0xd0, 0x19, 0x29, 0xfe, 0x2d, 0x9a, 0x57, 0x76, 0x5f, 0xf2, 0xef, 0x71, + 0x16, 0xee, 0x28, 0x7b, 0xe4, 0x48, 0xeb, 0xda, 0xe0, 0xd5, 0xbc, 0x0e, + 0x46, 0x6b, 0x06, 0x5d, 0xe5, 0x91, 0x2d, 0xcb, 0xc4, 0x53, 0xa6, 0x16, + 0xd5, 0xe7, 0xd8, 0xf1, 0xdd, 0x4f, 0xbb, 0xcc, 0x55, 0x67, 0x19, 0x98, + 0x94, 0x95, 0x5e, 0xd6, 0xf5, 0xf7, 0xe8, 0x6a, 0xf7, 0x20, 0x86, 0x3a, + 0x43, 0xbf, 0xe9, 0xec, 0x6b, 0x33, 0x49, 0x19, 0x43, 0xfb, 0xeb, 0x3f, + 0xf4, 0x9d, 0x29, 0x66, 0xb9, 0x6e, 0xb5, 0x15, 0x4b, 0x8d, 0x3c, 0x3c, + 0xfa, 0xf2, 0x87, 0xba, 0x61, 0x11, 0x40, 0xe6, 0xb4, 0x6f, 0xf5, 0xe1, + 0x24, 0x32, 0x69, 0x3e, 0xff, 0xf7, 0xbc, 0xee, 0x82, 0xf2, 0x9e, 0x6d, + 0x3f, 0x6c, 0xcc, 0x0f, 0x4f, 0xc3, 0xf1, 0xdb, 0x1e, 0x81, 0xd7, 0x9b, + 0x22, 0xa8, 0xa7, 0x36, 0x6d, 0xa9, 0x6f, 0x46, 0x1a, 0xa7, 0xff, 0x00, + 0x4b, 0xd8, 0xab, 0xe7, 0x50, 0x3b, 0xe9, 0xc0, 0x57, 0xec, 0x8d, 0x0c, + 0xa0, 0xee, 0x8c, 0x2a, 0x74, 0xf2, 0x94, 0xf9, 0x0c, 0x20, 0x14, 0xd9, + 0xad, 0x0d, 0x4e, 0xac, 0x35, 0x44, 0x59, 0x28, 0x24, 0x31, 0x32, 0xaa, + 0x6d, 0xc2, 0x13, 0xb9, 0xee, 0x75, 0x0c, 0x5f, 0x39, 0xef, 0x31, 0xca, + 0x28, 0x48, 0x56, 0x59, 0xfb, 0xa8, 0xd8, 0x2b, 0x70, 0x61, 0x22, 0x43, + 0x43, 0xb9, 0x60, 0x44, 0xeb, 0xf8, 0x98, 0x87, 0x25, 0x84, 0xa2, 0xaa, + 0x37, 0xd4, 0xb8, 0xd6, 0x3d, 0xa3, 0xa1, 0x4a, 0x81, 0xc2, 0xa9, 0xea, + 0xa2, 0xd6, 0x63, 0x76, 0x50, 0xeb, 0xcd, 0x19, 0x40, 0xb1, 0x7c, 0xf6, + 0xc1, 0x44, 0x01, 0x25, 0xe0, 0xdd, 0xb8, 0x39, 0xef, 0x46, 0x3d, 0x50, + 0x33, 0xed, 0xb1, 0x63, 0x65, 0xd7, 0x50, 0xe7, 0x95, 0xba, 0xab, 0xa7, + 0x14, 0xe5, 0x60, 0xcb, 0x81, 0x6e, 0x88, 0x3c, 0x06, 0x6e, 0x7d, 0x8e, + 0xe7, 0xbb, 0xa5, 0xc2, 0xbd, 0xae, 0x46, 0x8f, 0x43, 0x04, 0x29, 0xe6, + 0x17, 0x38, 0x05, 0x2d, 0x97, 0x93, 0x5b, 0xf9, 0xef, 0x4d, 0x2e, 0x75, + 0x6c, 0x69, 0xba, 0x08, 0xf2, 0x21, 0x1e, 0x21, 0xe6, 0x8a, 0x5b, 0x8c, + 0xd4, 0x8e, 0xde, 0x64, 0x9b, 0x9d, 0x54, 0x58, 0x65, 0x3e, 0xdd, 0x8a, + 0x1e, 0x81, 0x4e, 0x45, 0xe8, 0xfb, 0x20, 0xc3, 0x3a, 0xf0, 0x50, 0x1e, + 0x8a, 0x18, 0xea, 0x2b, 0xf5, 0xe1, 0xa6, 0xb6, 0xc8, 0xa0, 0x02, 0x3d, + 0x6e, 0xfa, 0x0b, 0x51, 0x95, 0x4e, 0x4c, 0x11, 0xb0, 0xc4, 0x62, 0x58, + 0xa6, 0x9c, 0x13, 0x4e, 0xbe, 0xc9, 0x29, 0x93, 0x29, 0x15, 0x5f, 0xaf, + 0x0e, 0xc3, 0xb3, 0x26, 0x3f, 0xdc, 0x4c, 0x33, 0xb8, 0x4b, 0x11, 0xae, + 0x1f, 0xd7, 0x05, 0x39, 0xcf, 0xfe, 0xc3, 0x6d, 0xf0, 0xc0, 0x77, 0x02, + 0xb8, 0x9b, 0x3d, 0x1b, 0x3d, 0x72, 0xfe, 0x7e, 0x18, 0x60, 0x9b, 0xc4, + 0x8b, 0xac, 0x25, 0x6d, 0x3b, 0x80, 0x34, 0xbc, 0x51, 0xaf, 0xf6, 0xff, + 0x66, 0x98, 0x86, 0x6e, 0x9e, 0x9a, 0xfe, 0x6d, 0x21, 0x4d, 0xf1, 0x58, + 0x3e, 0x3e, 0x43, 0xe3, 0x7e, 0x40, 0xb0, 0xb3, 0xd8, 0x12, 0xa5, 0xce, + 0x09, 0x41, 0x8c, 0x1d, 0x73, 0xcd, 0xfc, 0x63, 0xed, 0xeb, 0x08, 0x1e, + 0x34, 0xfb, 0xed, 0x75, 0xb7, 0x86, 0x84, 0x7c, 0x80, 0xe9, 0xe4, 0xa3, + 0x1c, 0x4a, 0x0d, 0x11, 0x16, 0x24, 0xb2, 0xb1, 0x99, 0xe5, 0xe3, 0x2e, + 0x2f, 0x70, 0xcd, 0x1e, 0x35, 0x14, 0x79, 0xba, 0xa2, 0x51, 0x7a, 0x29, + 0x5c, 0x75, 0x8f, 0xdd, 0x22, 0xdf, 0xb2, 0x64, 0xd9, 0x95, 0x11, 0x33, + 0x97, 0xee, 0x69, 0x42, 0x01, 0x96, 0x98, 0x1b, 0x43, 0xc2, 0xec, 0xf9, + 0xb0, 0xdb, 0x69, 0x34, 0xab, 0x98, 0x1b, 0xb2, 0x04, 0x05, 0x14, 0x1d, + 0x25, 0x2f, 0x32, 0x41, 0x50, 0x51, 0x55, 0x62, 0x6d, 0x78, 0x7f, 0x8b, + 0xbb, 0xc2, 0xcd, 0xcf, 0xe4, 0xed, 0x04, 0x1f, 0x25, 0x30, 0x43, 0x64, + 0x69, 0x7c, 0x87, 0xa3, 0xa9, 0xb1, 0xc1, 0xd1, 0xdc, 0x01, 0x10, 0x1d, + 0x27, 0x3f, 0x5c, 0x5d, 0x75, 0x82, 0x9b, 0xaa, 0xb3, 0xe8, 0x0c, 0x11, + 0x1f, 0x24, 0x38, 0x41, 0x45, 0x54, 0x5f, 0x69, 0x85, 0x8d, 0x93, 0x9e, + 0xc5, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x25, 0x32, 0x42}; +const uint8_t expected_signature_65[] = { + 0x8b, 0x6f, 0x79, 0x00, 0xcc, 0x79, 0x57, 0xee, 0x16, 0x86, 0x87, 0xd5, + 0xcf, 0xb6, 0x90, 0x2c, 0xc6, 0x30, 0xeb, 0x8d, 0x39, 0xae, 0x9b, 0xf1, + 0x66, 0xe0, 0xd6, 0x93, 0xa5, 0x4e, 0x26, 0x9b, 0x96, 0x8f, 0xd1, 0x46, + 0x97, 0xbe, 0x71, 0x1c, 0xf3, 0xa5, 0xe5, 0xae, 0x8d, 0x4b, 0xf2, 0xe6, + 0x48, 0x8f, 0xe9, 0x5e, 0x07, 0xef, 0xe4, 0xbb, 0x39, 0xc1, 0xc9, 0x3c, + 0xc3, 0x0b, 0xfb, 0x2a, 0x29, 0x06, 0xfe, 0x01, 0xcb, 0x63, 0x83, 0x10, + 0xa8, 0xc8, 0xa0, 0x29, 0xa5, 0x80, 0xeb, 0xbd, 0xa9, 0xd9, 0x0b, 0x61, + 0xbc, 0xce, 0x11, 0x55, 0x66, 0x12, 0xc7, 0x5b, 0xd2, 0x7a, 0x5a, 0xc8, + 0xab, 0xab, 0xbf, 0x3a, 0x1f, 0x96, 0x1a, 0x70, 0xcb, 0x41, 0x5f, 0xc8, + 0xb7, 0x09, 0x22, 0x98, 0x9b, 0xb8, 0xf7, 0x2d, 0x49, 0x65, 0x1d, 0x09, + 0x8b, 0x70, 0xb5, 0x42, 0xc9, 0x89, 0x5b, 0x74, 0xb4, 0x28, 0x82, 0x01, + 0x53, 0x12, 0x3e, 0x23, 0xf6, 0x54, 0xf8, 0x51, 0x12, 0x4b, 0x02, 0x3a, + 0x7e, 0xb6, 0x1f, 0xac, 0xa0, 0xe6, 0x6f, 0xf8, 0x61, 0x82, 0xe4, 0xfb, + 0x96, 0x2a, 0xd2, 0xaf, 0x3c, 0xea, 0x6e, 0xdc, 0x18, 0x8a, 0x5d, 0x90, + 0xda, 0xa2, 0x5d, 0xa7, 0x8f, 0x5b, 0x50, 0x46, 0xaf, 0x8c, 0x17, 0x6a, + 0x4c, 0x39, 0xfc, 0x31, 0x4c, 0x4b, 0xc2, 0x57, 0x66, 0x61, 0x98, 0xbf, + 0xe6, 0xfb, 0x54, 0x96, 0xd3, 0x70, 0xb8, 0xaf, 0xcd, 0x8b, 0xcc, 0x00, + 0x07, 0x92, 0x15, 0xc2, 0xbb, 0x48, 0xbb, 0xc6, 0xb7, 0xb5, 0x58, 0x8c, + 0xfc, 0xf0, 0xda, 0x6a, 0x0d, 0xf7, 0x1d, 0x7d, 0xc6, 0x27, 0x26, 0x1a, + 0x99, 0xc5, 0x2f, 0xf8, 0x97, 0x65, 0x43, 0x86, 0xd6, 0x25, 0x23, 0x2b, + 0x06, 0x8f, 0x12, 0xa1, 0xae, 0xbb, 0x58, 0x34, 0x25, 0xec, 0x5b, 0x68, + 0xa4, 0xe1, 0x03, 0xfc, 0x26, 0xa2, 0xd6, 0x2b, 0x61, 0x10, 0x47, 0xbd, + 0x16, 0xe5, 0xca, 0x4a, 0xce, 0xed, 0x89, 0x09, 0x1a, 0xed, 0x22, 0xc1, + 0xca, 0x44, 0xe3, 0xef, 0x72, 0x34, 0xab, 0xab, 0x61, 0x5c, 0x9f, 0x5f, + 0xb5, 0xf5, 0xe8, 0x2d, 0x89, 0xea, 0x4b, 0x40, 0x65, 0x57, 0x8b, 0xa2, + 0x95, 0x40, 0x9c, 0x72, 0xc0, 0x46, 0x69, 0x45, 0x06, 0xf6, 0x07, 0x5b, + 0x2d, 0xa5, 0x46, 0xca, 0x5d, 0xfb, 0x40, 0xb7, 0x48, 0x59, 0x5b, 0xe2, + 0x1b, 0x38, 0xb2, 0x15, 0x75, 0x66, 0x67, 0x58, 0x00, 0x3f, 0xde, 0x8a, + 0x63, 0x13, 0x34, 0x6a, 0x30, 0xca, 0xb4, 0xd5, 0x3e, 0xe0, 0x6d, 0x14, + 0xb8, 0x9a, 0x48, 0xef, 0xfd, 0xbd, 0x6d, 0x20, 0x11, 0x4d, 0x25, 0xe5, + 0xab, 0x15, 0x8d, 0xe5, 0x91, 0xbc, 0xc6, 0x69, 0x8a, 0xf8, 0xab, 0x3a, + 0x82, 0xae, 0xc5, 0x03, 0x2c, 0xcf, 0x54, 0xdc, 0xcd, 0xe8, 0x49, 0x53, + 0xb5, 0xd8, 0xc2, 0x24, 0xf8, 0x8c, 0x38, 0x8f, 0xe3, 0xfe, 0x3a, 0x18, + 0x15, 0xa8, 0xda, 0x77, 0xc8, 0x81, 0x72, 0xc6, 0xc1, 0x60, 0xa3, 0x73, + 0x65, 0x68, 0x5c, 0xf3, 0x1d, 0x8d, 0x61, 0x21, 0x65, 0xfb, 0x45, 0xc4, + 0x4c, 0x31, 0x88, 0x25, 0x0d, 0x52, 0x75, 0x3b, 0xec, 0x54, 0xe0, 0xb1, + 0x9c, 0x7c, 0xdf, 0xe3, 0x3b, 0x77, 0x31, 0x33, 0xd7, 0x25, 0x99, 0xff, + 0xc5, 0x40, 0x1e, 0x85, 0x09, 0xfd, 0x2d, 0x24, 0x4a, 0x92, 0xe7, 0x77, + 0x48, 0xa5, 0x46, 0xf4, 0x8e, 0xa3, 0x6b, 0x24, 0xe4, 0x6b, 0x31, 0xf6, + 0xe0, 0x16, 0x49, 0x9b, 0x9f, 0xa3, 0x1a, 0x5c, 0x05, 0x5e, 0x81, 0x62, + 0xc8, 0x14, 0x52, 0xb4, 0x21, 0xfd, 0x76, 0x6d, 0x88, 0xe9, 0x3b, 0x0b, + 0x75, 0x27, 0x92, 0x47, 0x5a, 0x58, 0x08, 0x26, 0xa7, 0xa2, 0x48, 0x1c, + 0x14, 0x3e, 0x5e, 0xdf, 0x81, 0x83, 0x83, 0x3e, 0xc6, 0x72, 0x27, 0xc4, + 0x6a, 0x46, 0x2b, 0xf2, 0x8d, 0x42, 0x11, 0xb9, 0x15, 0xd7, 0xf0, 0x20, + 0x29, 0x53, 0xba, 0xf0, 0x6e, 0x41, 0x3d, 0xee, 0x19, 0xf2, 0x43, 0xf3, + 0x6d, 0x00, 0xe2, 0x43, 0x77, 0xb9, 0xa9, 0x78, 0x34, 0x48, 0x3c, 0x1a, + 0x8b, 0xbd, 0xa1, 0xe5, 0x90, 0x59, 0x5b, 0xd6, 0x1e, 0x22, 0xdf, 0xb2, + 0xa7, 0x96, 0x7d, 0x55, 0x86, 0x66, 0x95, 0xb7, 0x06, 0xe7, 0x60, 0x2a, + 0x01, 0x48, 0x3f, 0xd4, 0xa7, 0xd4, 0xc2, 0x38, 0xa4, 0x10, 0x8e, 0x4f, + 0x97, 0xad, 0xa3, 0xb9, 0xe2, 0xaa, 0x13, 0xb1, 0x16, 0x89, 0x3d, 0x74, + 0x60, 0x94, 0x8c, 0xc3, 0xe6, 0x5f, 0xcf, 0xdc, 0x58, 0x17, 0x98, 0x27, + 0x86, 0xae, 0x2a, 0x0d, 0xe8, 0x33, 0x79, 0xc8, 0xc8, 0x5b, 0x59, 0xb0, + 0xba, 0xac, 0xd3, 0x6e, 0x2d, 0x7b, 0x0b, 0x9a, 0xb5, 0xfd, 0x58, 0x42, + 0xeb, 0x80, 0xf4, 0x6b, 0x9a, 0x2f, 0x19, 0x43, 0x75, 0xb4, 0xcb, 0xc9, + 0xd5, 0x28, 0xf5, 0xb9, 0x67, 0x82, 0xb4, 0xed, 0x8c, 0x3f, 0x3d, 0x6b, + 0x6d, 0x1b, 0x80, 0x13, 0x5c, 0x7b, 0x2e, 0xfa, 0xa0, 0x32, 0xba, 0xb5, + 0x46, 0xd6, 0xe7, 0x90, 0xe9, 0xd1, 0x91, 0xa0, 0xaa, 0x26, 0x35, 0xa2, + 0x0d, 0x98, 0x44, 0x11, 0xae, 0xf9, 0xc5, 0x12, 0x4d, 0x1a, 0x7c, 0x53, + 0xea, 0xf6, 0x05, 0x8d, 0x3a, 0x74, 0x92, 0xc9, 0x65, 0xeb, 0x6f, 0xb5, + 0xb4, 0xd2, 0xcd, 0x5c, 0xec, 0xaf, 0x95, 0xcb, 0xb4, 0x3c, 0x22, 0xca, + 0x1c, 0x06, 0x85, 0x16, 0x96, 0x24, 0x8c, 0x6c, 0x80, 0xf8, 0xb3, 0xa7, + 0x87, 0x77, 0xeb, 0x09, 0x71, 0xc8, 0x95, 0xfb, 0x5e, 0xe5, 0x6f, 0x78, + 0xf9, 0x60, 0xf9, 0x9e, 0x58, 0x7b, 0xbd, 0x47, 0xdd, 0x48, 0x2e, 0x56, + 0xcd, 0x63, 0x72, 0xc9, 0x4b, 0x65, 0x2d, 0x41, 0xe8, 0x81, 0x19, 0x33, + 0x4b, 0xf6, 0x02, 0xc6, 0xcb, 0x2e, 0xdf, 0x3d, 0xc8, 0xdd, 0x2f, 0x0f, + 0x09, 0x67, 0xf0, 0xaa, 0x3c, 0x51, 0xdc, 0x8d, 0xc6, 0xc3, 0xb2, 0x3b, + 0x15, 0x85, 0xcb, 0xeb, 0x62, 0xef, 0xa3, 0xf9, 0x94, 0xf4, 0x35, 0x9c, + 0x59, 0xcc, 0xc2, 0x68, 0xb4, 0xde, 0x02, 0x75, 0x8e, 0xf5, 0x33, 0xca, + 0xd5, 0xc5, 0x24, 0xae, 0xf6, 0xde, 0x2b, 0x01, 0xf4, 0x56, 0xb9, 0xa5, + 0xa7, 0xe0, 0x64, 0x2e, 0xba, 0x1d, 0x53, 0x54, 0x46, 0xcf, 0x64, 0x16, + 0x12, 0xe2, 0xa6, 0xcc, 0x18, 0xb4, 0x77, 0x8b, 0x19, 0x50, 0x43, 0x96, + 0xc8, 0x5d, 0xc3, 0x58, 0xf0, 0xfd, 0x5e, 0x13, 0xa9, 0x10, 0x67, 0xdf, + 0x25, 0xdb, 0xaf, 0x38, 0x5f, 0xbd, 0x35, 0xc1, 0x49, 0x44, 0xe8, 0x1f, + 0x12, 0xa4, 0x7c, 0x28, 0xa3, 0xd6, 0x0d, 0x6f, 0x44, 0xa9, 0x5f, 0xfc, + 0x9f, 0xfa, 0x11, 0x62, 0x87, 0x5b, 0x0e, 0x91, 0xd4, 0xb6, 0xd3, 0x71, + 0xc2, 0x77, 0x19, 0xf6, 0x7c, 0x11, 0x30, 0x5e, 0x5c, 0xd3, 0x1e, 0x90, + 0x05, 0x31, 0x63, 0xbb, 0xef, 0x85, 0xe0, 0x27, 0x94, 0x80, 0xcb, 0x33, + 0xbc, 0x5e, 0x45, 0x87, 0x62, 0xdf, 0xd4, 0x12, 0x2f, 0xf5, 0x41, 0x15, + 0x03, 0x0c, 0x80, 0xe8, 0xe2, 0x06, 0xde, 0x4b, 0x46, 0x70, 0x94, 0xd2, + 0x0d, 0x85, 0x72, 0x27, 0xe5, 0x6c, 0xeb, 0xd2, 0x78, 0x0b, 0x38, 0x40, + 0xe8, 0xdb, 0x47, 0x5c, 0xba, 0xd0, 0x21, 0x33, 0x8f, 0xb8, 0xc0, 0x66, + 0x1e, 0xd1, 0xb0, 0x94, 0xa3, 0x39, 0xc7, 0x87, 0xaf, 0x97, 0x98, 0xce, + 0x6d, 0x03, 0x1a, 0xdb, 0x52, 0x96, 0x0b, 0x9d, 0x5b, 0xf8, 0xa3, 0xf4, + 0x41, 0x95, 0x72, 0xad, 0x0e, 0x98, 0x61, 0x7f, 0xf3, 0x8f, 0x23, 0xeb, + 0xc0, 0xdf, 0xd7, 0x70, 0x26, 0x8c, 0xb3, 0xb3, 0xf0, 0xa2, 0x8a, 0x39, + 0xdd, 0x61, 0xb4, 0x53, 0xe0, 0x2a, 0x6f, 0x91, 0x34, 0x9c, 0x76, 0xf6, + 0x52, 0x93, 0xe6, 0x39, 0xb7, 0x54, 0x07, 0x46, 0x82, 0x2d, 0x05, 0x6d, + 0x9a, 0x00, 0x53, 0x65, 0x68, 0x93, 0x91, 0x00, 0xda, 0xe0, 0x93, 0x34, + 0x60, 0xb1, 0x93, 0x0b, 0x64, 0xa8, 0x12, 0xd2, 0x51, 0x3c, 0xdb, 0xb0, + 0x4c, 0x39, 0x4e, 0xce, 0xbd, 0xf0, 0x65, 0x12, 0x8a, 0xd4, 0x80, 0x7d, + 0x82, 0x85, 0xe4, 0x92, 0xc2, 0x77, 0x1e, 0xcf, 0xd9, 0xab, 0x0f, 0x9b, + 0x32, 0x2e, 0x3f, 0xe1, 0x0e, 0x87, 0x1c, 0x87, 0x34, 0xe7, 0x93, 0x16, + 0x95, 0x09, 0x7d, 0x24, 0xa8, 0xb5, 0xe0, 0x9f, 0x23, 0x87, 0x5c, 0x0b, + 0x31, 0x4a, 0x2f, 0xe2, 0x5c, 0x82, 0x49, 0x51, 0xe4, 0x93, 0xcb, 0x05, + 0x23, 0x4f, 0x8a, 0x83, 0x88, 0xfb, 0x89, 0xb0, 0x08, 0xd6, 0x64, 0xad, + 0x51, 0x84, 0x40, 0x29, 0xb1, 0xca, 0x74, 0x26, 0x29, 0x5a, 0x61, 0x01, + 0x2e, 0xa0, 0xeb, 0xeb, 0x02, 0xb5, 0xff, 0xd8, 0x20, 0x6a, 0x5e, 0x8d, + 0x17, 0x1e, 0xa3, 0xd7, 0x2f, 0x20, 0x0b, 0x93, 0x17, 0x24, 0xf7, 0x90, + 0x7b, 0xc6, 0xba, 0xd8, 0xf9, 0xe9, 0x0a, 0x2a, 0x7a, 0x81, 0x23, 0x81, + 0x03, 0x6f, 0x1e, 0x0d, 0x87, 0x83, 0xd1, 0xcf, 0x92, 0x2f, 0x19, 0x82, + 0x4e, 0x6c, 0x0a, 0x02, 0xb6, 0x70, 0xbc, 0xe1, 0x58, 0xe7, 0x16, 0xdb, + 0x2f, 0x74, 0x9f, 0xe1, 0xc2, 0x1e, 0x64, 0xc6, 0x48, 0x08, 0xee, 0xea, + 0x52, 0x9a, 0xce, 0x2c, 0xc5, 0x0c, 0x7a, 0x63, 0xf1, 0x6a, 0xbd, 0x2c, + 0x8b, 0xd5, 0x4a, 0xfa, 0x1e, 0xab, 0x9a, 0x5b, 0x25, 0xb8, 0xfa, 0x0a, + 0xe9, 0x68, 0x80, 0x6f, 0x80, 0x57, 0x10, 0x54, 0xb8, 0xa2, 0x16, 0xbd, + 0xfe, 0xf7, 0xea, 0x01, 0xc7, 0x94, 0x5a, 0x95, 0xe3, 0x61, 0xa5, 0x49, + 0x84, 0xf5, 0x79, 0x78, 0xb5, 0x0a, 0x96, 0xca, 0x01, 0x1b, 0xd0, 0x0b, + 0x51, 0x30, 0xd3, 0x48, 0xfc, 0x4d, 0x50, 0x71, 0x09, 0x73, 0xea, 0x37, + 0xcd, 0x9d, 0x3d, 0xde, 0x30, 0x56, 0x21, 0xf0, 0xef, 0x84, 0xad, 0x27, + 0xe1, 0x83, 0xdb, 0xfb, 0xcd, 0x11, 0xb2, 0xbd, 0x30, 0x67, 0x8a, 0x88, + 0x09, 0x0e, 0x9d, 0x96, 0x09, 0xba, 0xda, 0x9d, 0xf0, 0xe9, 0xb4, 0xa6, + 0x7a, 0x04, 0xf9, 0x4b, 0xb8, 0x51, 0xa9, 0x99, 0xf3, 0xbb, 0x77, 0x95, + 0x0a, 0xa1, 0xa6, 0xa1, 0x24, 0xfc, 0xcc, 0x45, 0xe8, 0x83, 0xc8, 0x6f, + 0x48, 0xad, 0x9a, 0x73, 0xd0, 0xe0, 0x57, 0x7d, 0xe4, 0x78, 0x65, 0xef, + 0xae, 0xc2, 0xfe, 0x7a, 0x56, 0xaf, 0x03, 0x71, 0x2b, 0xe6, 0xa1, 0x7e, + 0xe5, 0x12, 0xf8, 0xc3, 0x75, 0xc7, 0x22, 0x5f, 0x1b, 0x52, 0x90, 0xe5, + 0xdf, 0xba, 0x9d, 0xe2, 0x68, 0xe0, 0xb3, 0x7a, 0x9e, 0x14, 0xff, 0xb5, + 0x0a, 0x80, 0x20, 0x49, 0x88, 0xe9, 0x9c, 0xe4, 0xb5, 0xaf, 0x7e, 0x51, + 0xec, 0xe7, 0xfc, 0x64, 0x65, 0x21, 0x10, 0xc6, 0x1f, 0x7f, 0x93, 0x7d, + 0xd8, 0xf5, 0xd0, 0x98, 0x94, 0x44, 0xf8, 0x49, 0x6a, 0x51, 0x0a, 0x54, + 0xf4, 0x9f, 0xee, 0x3c, 0x56, 0xbf, 0x4c, 0xe4, 0xde, 0x1c, 0x9b, 0x11, + 0x7e, 0x9a, 0x71, 0x11, 0x80, 0x33, 0xd5, 0xb0, 0x9b, 0xef, 0x67, 0x29, + 0xa4, 0x7d, 0x70, 0x31, 0x3f, 0x8b, 0x2e, 0x4a, 0x0f, 0x2c, 0x91, 0x3d, + 0x3e, 0x3d, 0x8c, 0x0a, 0x2b, 0xf1, 0xdd, 0xbf, 0x61, 0xe6, 0xa3, 0xef, + 0x6d, 0x82, 0xc8, 0xb7, 0x5e, 0x2b, 0x83, 0xc9, 0x4e, 0xa0, 0x85, 0x7f, + 0x01, 0x5a, 0xca, 0x6e, 0x90, 0xfa, 0x7e, 0x82, 0x4d, 0x35, 0x7e, 0xe0, + 0x26, 0x40, 0xf4, 0xa6, 0xae, 0xc3, 0x89, 0xf3, 0xca, 0x55, 0x2c, 0xb5, + 0x29, 0x05, 0x94, 0x45, 0xa7, 0x45, 0xf3, 0x3d, 0xbb, 0x53, 0x5e, 0xca, + 0x7c, 0x84, 0x8f, 0x72, 0x98, 0x93, 0x90, 0x1f, 0x56, 0x72, 0xdb, 0xbd, + 0xa9, 0xeb, 0xf9, 0xe9, 0xce, 0xb1, 0x41, 0xc3, 0xaa, 0xa0, 0xc4, 0x74, + 0x23, 0xc1, 0xeb, 0x7d, 0x41, 0xcd, 0xa4, 0x62, 0xec, 0xfc, 0x9a, 0xa4, + 0x16, 0xec, 0x67, 0x41, 0x89, 0xf0, 0x0e, 0xf3, 0xd1, 0xa2, 0x2f, 0xba, + 0x5d, 0x93, 0x36, 0x46, 0xf5, 0x52, 0x64, 0x91, 0xe7, 0x40, 0x91, 0x20, + 0xa1, 0xc9, 0xaa, 0x4c, 0x79, 0xc4, 0xbb, 0x67, 0x79, 0xad, 0x43, 0xab, + 0xba, 0xde, 0xfc, 0xf1, 0x74, 0x81, 0x33, 0xc0, 0x3f, 0x39, 0xd1, 0xd1, + 0xdf, 0xc0, 0x53, 0x33, 0xb2, 0x92, 0x37, 0xe6, 0x86, 0x2a, 0xe4, 0xe1, + 0x7c, 0x98, 0xf7, 0xdb, 0x5c, 0xa9, 0xff, 0x8d, 0x9c, 0xab, 0xe2, 0xf2, + 0xd5, 0xb1, 0x42, 0xa9, 0xf4, 0x97, 0x80, 0xcd, 0xde, 0x25, 0x2e, 0x87, + 0x92, 0xdd, 0xcf, 0xed, 0x67, 0x93, 0x8c, 0x5a, 0x1d, 0xee, 0xcf, 0x9d, + 0x50, 0x8f, 0xa7, 0xe3, 0x5c, 0xa3, 0x68, 0x78, 0x24, 0xeb, 0x60, 0xa3, + 0x8b, 0x36, 0xbb, 0xcb, 0x46, 0xee, 0x77, 0xfb, 0xf8, 0x69, 0x24, 0xd1, + 0xfa, 0xad, 0x76, 0x76, 0x5e, 0x54, 0xe5, 0xb6, 0x36, 0xc6, 0xdd, 0xa9, + 0x6c, 0x44, 0x15, 0xf7, 0x0a, 0xf8, 0xbb, 0xba, 0xec, 0x35, 0xff, 0xc9, + 0xd6, 0x5d, 0xf5, 0x73, 0x4a, 0x15, 0x8f, 0x7b, 0x6e, 0xf4, 0xa0, 0x6d, + 0x10, 0xbb, 0x67, 0x0c, 0xb4, 0x69, 0xad, 0xb6, 0x40, 0xf7, 0x5f, 0x37, + 0x28, 0xc4, 0x08, 0x49, 0xd0, 0x16, 0x70, 0x80, 0xea, 0x55, 0x66, 0x07, + 0xc8, 0x03, 0x1b, 0xf6, 0xd3, 0x03, 0x04, 0x74, 0xe0, 0x50, 0x3f, 0xd2, + 0x53, 0x92, 0xa0, 0x9d, 0x59, 0xc9, 0x74, 0xf2, 0x7e, 0x3b, 0x33, 0x02, + 0x10, 0x0b, 0x39, 0xf7, 0x4f, 0x6b, 0x58, 0xb2, 0x1a, 0xda, 0x65, 0x44, + 0xd1, 0x7c, 0x3f, 0xd7, 0xe3, 0xac, 0xe2, 0x1f, 0x38, 0xc1, 0x6a, 0xb0, + 0xdc, 0xc3, 0x9c, 0x7b, 0x11, 0x3c, 0x05, 0x21, 0x96, 0x76, 0x98, 0x76, + 0x82, 0xc1, 0x54, 0xdf, 0xdc, 0x8f, 0x4c, 0xd2, 0x63, 0x04, 0x06, 0x77, + 0x36, 0xe6, 0x2e, 0xd1, 0x00, 0x28, 0x42, 0x7c, 0x4a, 0x27, 0x90, 0x46, + 0xc9, 0xce, 0x33, 0x1c, 0xae, 0xda, 0x79, 0x64, 0x7f, 0x52, 0x3f, 0x58, + 0x11, 0x76, 0x4a, 0xb6, 0x72, 0xd8, 0x76, 0xae, 0xfd, 0x5c, 0x57, 0x69, + 0x76, 0x91, 0x84, 0x21, 0xc4, 0x9b, 0xd8, 0xa2, 0xff, 0x93, 0x02, 0x77, + 0x61, 0x57, 0x96, 0x7b, 0x8e, 0xfc, 0xf2, 0x6c, 0x11, 0x2b, 0x5e, 0x88, + 0x5c, 0x17, 0x1d, 0x12, 0x79, 0x3a, 0x78, 0xb6, 0x9d, 0x70, 0xfa, 0xd4, + 0xc1, 0x5c, 0x90, 0x0e, 0x0a, 0xd1, 0x3c, 0x7d, 0xcf, 0xee, 0x8a, 0xb2, + 0xb2, 0x4d, 0xce, 0x89, 0x32, 0xa9, 0x6c, 0x56, 0x57, 0x85, 0xb1, 0xbf, + 0x18, 0x1d, 0xc6, 0xe1, 0x17, 0xc5, 0x92, 0x42, 0x99, 0xf9, 0x9f, 0x04, + 0xec, 0x38, 0xf8, 0xa0, 0xd2, 0xab, 0xe6, 0x13, 0x4d, 0x9c, 0x18, 0x86, + 0x3e, 0x18, 0x73, 0x2c, 0xac, 0xe0, 0xb9, 0xf9, 0x87, 0x74, 0xb8, 0xd7, + 0x47, 0x6e, 0x42, 0xfc, 0x29, 0xa0, 0x1f, 0x56, 0x68, 0xb6, 0x23, 0x96, + 0xa2, 0x8d, 0x54, 0x81, 0x0f, 0x60, 0xb9, 0xde, 0x93, 0xfc, 0xfd, 0xde, + 0xbe, 0xb3, 0xb5, 0x87, 0xec, 0x9f, 0x17, 0xc2, 0x77, 0x6e, 0xa0, 0x62, + 0xdb, 0x66, 0xba, 0xc5, 0x05, 0x12, 0x46, 0x5d, 0x3c, 0x23, 0x29, 0x68, + 0xe5, 0x31, 0xe3, 0x15, 0xec, 0xac, 0x15, 0x9a, 0xbf, 0x42, 0x65, 0x80, + 0x45, 0x9c, 0x1d, 0xc2, 0x0e, 0x18, 0x47, 0x40, 0x44, 0xc1, 0x55, 0x24, + 0x5a, 0x35, 0xad, 0x59, 0xd2, 0xc6, 0xc3, 0x68, 0x58, 0xbd, 0x6f, 0xcf, + 0x5d, 0xb1, 0x9b, 0x0c, 0x92, 0x39, 0x22, 0x49, 0x66, 0x2e, 0x03, 0x7b, + 0x75, 0x5c, 0x6c, 0xde, 0x37, 0x54, 0xa9, 0x07, 0x2f, 0x7e, 0xc1, 0x3e, + 0x3b, 0xab, 0xd2, 0xa9, 0xfa, 0xc7, 0x6b, 0xd5, 0x14, 0x08, 0x35, 0x89, + 0x0b, 0x31, 0x18, 0x54, 0x7d, 0x6b, 0x53, 0x80, 0x6e, 0x32, 0x9b, 0xff, + 0x61, 0x7f, 0x36, 0xe5, 0x28, 0x40, 0xbc, 0xc7, 0x19, 0xb3, 0xae, 0xfa, + 0x95, 0xa8, 0xae, 0xd2, 0x97, 0x72, 0xc6, 0x91, 0x36, 0x3a, 0xa6, 0xec, + 0x4a, 0x41, 0x63, 0x6b, 0x28, 0xef, 0x5a, 0xa1, 0xdb, 0xf2, 0xd9, 0xfd, + 0x61, 0x72, 0xa4, 0xd2, 0x9e, 0xf7, 0x47, 0xf4, 0x4e, 0xea, 0x2a, 0xa5, + 0x35, 0xe1, 0x77, 0x3a, 0x53, 0x28, 0xa6, 0x55, 0x48, 0x0c, 0x1e, 0x44, + 0xfc, 0xc1, 0x31, 0x5a, 0x00, 0xcd, 0x29, 0xc1, 0x5c, 0xca, 0x2a, 0x07, + 0x01, 0x63, 0xac, 0xb3, 0xfb, 0xf6, 0x0b, 0xac, 0xfd, 0xe8, 0x7b, 0xed, + 0xf9, 0x3d, 0x9a, 0xbc, 0x67, 0x28, 0x1c, 0xd9, 0x3f, 0x97, 0x28, 0x4a, + 0xe7, 0xd0, 0x08, 0xe9, 0x3e, 0xa0, 0xcb, 0x0f, 0xe0, 0x3f, 0x1b, 0x80, + 0x43, 0x74, 0xd9, 0x9d, 0x0b, 0x22, 0x81, 0xf7, 0xec, 0x71, 0x2a, 0x29, + 0x9e, 0x5d, 0x1e, 0x8d, 0xf4, 0x22, 0x95, 0x78, 0x86, 0xcb, 0xf0, 0x9d, + 0xe7, 0x6a, 0x66, 0x7e, 0x28, 0xb5, 0x47, 0xb6, 0xdc, 0x0d, 0x03, 0x3c, + 0x09, 0x58, 0x76, 0x93, 0x39, 0xb2, 0xd3, 0x75, 0xb4, 0x51, 0x55, 0x84, + 0x30, 0x24, 0x0a, 0x76, 0xf4, 0x97, 0xe7, 0x0f, 0x5a, 0x67, 0xee, 0xf4, + 0xc7, 0x69, 0x8d, 0xf2, 0x32, 0x29, 0x5c, 0x33, 0x82, 0x5f, 0x6c, 0x47, + 0xd0, 0xe2, 0xbd, 0x62, 0xd6, 0x4c, 0x6d, 0x0d, 0xba, 0x87, 0xd3, 0x43, + 0x7e, 0x2d, 0xa6, 0x14, 0x09, 0x4f, 0x3b, 0xc3, 0x04, 0x14, 0xe5, 0x65, + 0xe9, 0x3b, 0x6a, 0xca, 0xb5, 0x96, 0x84, 0x3f, 0x53, 0x49, 0x22, 0x45, + 0x91, 0xff, 0xf9, 0x26, 0x75, 0x0d, 0x9c, 0xa7, 0x00, 0xf4, 0x65, 0xc4, + 0x60, 0x72, 0xab, 0xeb, 0xf8, 0xa8, 0x72, 0xfe, 0xd8, 0xde, 0x93, 0x67, + 0xcb, 0x09, 0xcc, 0xa0, 0xce, 0x9f, 0x67, 0x63, 0x26, 0xfa, 0x7f, 0x89, + 0xaa, 0x3e, 0x6d, 0xb2, 0x90, 0xd7, 0xef, 0x3e, 0x2a, 0x66, 0x26, 0x33, + 0xe6, 0x26, 0xc1, 0x58, 0xf8, 0x91, 0xea, 0x2f, 0xd0, 0x84, 0x21, 0x41, + 0x93, 0xa6, 0x36, 0x40, 0xb5, 0x4c, 0xac, 0x21, 0x88, 0x37, 0x47, 0x8a, + 0xb8, 0xf3, 0x33, 0x73, 0x12, 0xd7, 0x5a, 0x55, 0xf9, 0xd1, 0x1e, 0x75, + 0xa4, 0x66, 0x68, 0x3f, 0xf7, 0xb2, 0xc4, 0x5d, 0x1b, 0xb1, 0x61, 0x0f, + 0xaf, 0x4b, 0x9b, 0x20, 0x2b, 0x05, 0x68, 0x1c, 0x6c, 0x97, 0x8d, 0xb8, + 0x7b, 0x96, 0xda, 0xe0, 0x67, 0x15, 0x4c, 0x51, 0x71, 0x0d, 0xd3, 0x7b, + 0xde, 0xaa, 0xd3, 0x58, 0xf5, 0xc9, 0x62, 0x0a, 0xc2, 0x33, 0x1f, 0xf3, + 0xc3, 0x30, 0xb5, 0x64, 0xd1, 0x59, 0x41, 0x0e, 0xae, 0xaa, 0x0d, 0xdf, + 0x9f, 0x5d, 0x3f, 0x15, 0x0d, 0x46, 0x7a, 0x6d, 0x2e, 0x29, 0x1b, 0xc0, + 0xd3, 0x11, 0x10, 0x5d, 0xdc, 0x6a, 0x35, 0x8c, 0x43, 0xc8, 0x9f, 0x05, + 0x80, 0xdc, 0x25, 0x24, 0x37, 0x70, 0x7e, 0x1c, 0xe9, 0x85, 0x5a, 0xef, + 0x83, 0x3a, 0x55, 0x68, 0x83, 0x17, 0xf4, 0xc7, 0xae, 0xe4, 0x84, 0xc9, + 0x64, 0x5d, 0x2f, 0xb6, 0xca, 0x10, 0x95, 0xb8, 0xd6, 0x80, 0xfd, 0x05, + 0xa5, 0x06, 0x32, 0x34, 0x91, 0x01, 0xd2, 0x02, 0x90, 0xe1, 0xf7, 0x89, + 0x8a, 0xee, 0x18, 0x04, 0x93, 0xd9, 0xb4, 0x63, 0x4b, 0xf7, 0x7a, 0x9c, + 0x1b, 0x4b, 0xf9, 0x31, 0x32, 0xd9, 0xf2, 0x55, 0x4e, 0xc1, 0x02, 0xce, + 0x77, 0x38, 0x36, 0x29, 0xb8, 0x54, 0x8c, 0xc2, 0x27, 0x5f, 0xd9, 0xae, + 0x3e, 0x1e, 0xcd, 0xe9, 0x07, 0x90, 0x4c, 0xe0, 0xda, 0x16, 0x6e, 0xdf, + 0xde, 0x3a, 0x61, 0x89, 0x9f, 0x79, 0xd0, 0xd4, 0x66, 0x95, 0xad, 0xe4, + 0x11, 0x7d, 0xa1, 0xae, 0xec, 0x3e, 0x6e, 0x20, 0x5a, 0xd0, 0x28, 0x0e, + 0x55, 0xec, 0xcf, 0x34, 0xec, 0xb7, 0xfc, 0xa4, 0xb3, 0x8f, 0x56, 0x13, + 0x50, 0xcc, 0x15, 0x10, 0x74, 0x40, 0x72, 0x42, 0x20, 0x22, 0xb3, 0xaf, + 0xf3, 0x68, 0xba, 0x95, 0x45, 0xcb, 0xef, 0x92, 0xd5, 0x14, 0x4c, 0x1f, + 0xe3, 0xc1, 0xa6, 0x03, 0x4e, 0x05, 0xd2, 0x1a, 0xee, 0xd2, 0x48, 0x44, + 0x2e, 0x50, 0x3b, 0x86, 0xc8, 0x6a, 0xc8, 0x4c, 0xca, 0x2a, 0xb6, 0xf7, + 0x3c, 0xaf, 0xdc, 0x62, 0xb1, 0x49, 0x13, 0xfe, 0xe7, 0x32, 0xea, 0x78, + 0xfa, 0xba, 0xcf, 0x15, 0x47, 0x58, 0xdc, 0x19, 0x73, 0x1d, 0xff, 0xbd, + 0xcc, 0x27, 0xf6, 0xfc, 0x66, 0x68, 0xa7, 0x29, 0xaf, 0x2b, 0x25, 0x0c, + 0x15, 0x47, 0xff, 0xc1, 0x00, 0x9d, 0xfa, 0x58, 0x9c, 0xaa, 0xf9, 0xcc, + 0x4c, 0x51, 0x1d, 0xda, 0xf3, 0x3c, 0x10, 0xd0, 0x3b, 0x59, 0x30, 0x02, + 0x68, 0x29, 0x1c, 0xa7, 0x22, 0xea, 0x81, 0xd3, 0x29, 0x71, 0x39, 0xe8, + 0x72, 0x7f, 0x7d, 0x94, 0x0a, 0x64, 0x2c, 0xe6, 0x55, 0xfb, 0x90, 0x78, + 0x7e, 0x6c, 0x3e, 0xfe, 0x57, 0x14, 0x61, 0xef, 0xe2, 0x63, 0x57, 0x6c, + 0x13, 0x97, 0x27, 0x2b, 0x38, 0x44, 0xab, 0x74, 0x76, 0x11, 0xa6, 0x60, + 0xad, 0x8e, 0xad, 0xe5, 0xa5, 0xa1, 0x66, 0xc5, 0xe1, 0x4d, 0x27, 0xa0, + 0x79, 0x7a, 0x09, 0xe6, 0xf0, 0x28, 0x3f, 0xcb, 0xc6, 0xf8, 0x94, 0xc0, + 0xf1, 0x13, 0xbe, 0x62, 0x6a, 0x52, 0x75, 0x52, 0xd3, 0x82, 0x31, 0xbd, + 0x15, 0xf2, 0xe8, 0x2e, 0xb1, 0x62, 0x03, 0x1e, 0xe2, 0xb3, 0xec, 0xbc, + 0x3c, 0x12, 0xca, 0x62, 0x4e, 0xc2, 0x3a, 0x51, 0x1c, 0xdf, 0xa2, 0x84, + 0x88, 0xe5, 0x7e, 0xd7, 0x5d, 0xd7, 0xbf, 0xf2, 0x7d, 0xbd, 0x9a, 0x90, + 0x63, 0xfd, 0x8a, 0x84, 0x2b, 0x9d, 0x89, 0x27, 0x63, 0x4c, 0x0a, 0xe3, + 0x70, 0x94, 0x7b, 0xe6, 0xb3, 0xd7, 0xcb, 0xcb, 0x8a, 0xeb, 0x6b, 0x53, + 0x34, 0x2f, 0x62, 0x44, 0x2d, 0x73, 0x63, 0x8a, 0xf4, 0xa2, 0x01, 0xd7, + 0x12, 0xb6, 0x8d, 0x8c, 0x4b, 0x73, 0x2b, 0x44, 0x50, 0x49, 0x6f, 0x01, + 0xac, 0xc5, 0x15, 0x37, 0x6c, 0xde, 0xd4, 0x02, 0xb1, 0x12, 0x80, 0x73, + 0xb2, 0x52, 0x0e, 0xe0, 0xb5, 0x75, 0xc9, 0x48, 0xcf, 0x18, 0x5c, 0xcc, + 0xaf, 0x58, 0xa2, 0x3e, 0x28, 0xe4, 0xab, 0xde, 0xea, 0x2a, 0xcf, 0x58, + 0x22, 0xc4, 0x68, 0xea, 0x9b, 0x7b, 0x90, 0xc5, 0xdc, 0x1c, 0x37, 0xd1, + 0x8a, 0x4f, 0xe7, 0x24, 0x23, 0x39, 0xb9, 0x62, 0xb8, 0x41, 0x13, 0x7b, + 0xe2, 0x1e, 0x0d, 0x4e, 0x38, 0x11, 0xa3, 0xb9, 0x10, 0xbb, 0x10, 0x6f, + 0x40, 0x9f, 0x50, 0x05, 0xc7, 0x0e, 0xb9, 0x9e, 0xab, 0x7c, 0x3c, 0x78, + 0xce, 0x54, 0xbf, 0xbf, 0x40, 0x36, 0x76, 0xbc, 0x4b, 0x64, 0x32, 0xca, + 0x0e, 0x2d, 0x91, 0x87, 0xd5, 0x00, 0x19, 0xbf, 0x12, 0xd0, 0x35, 0x7c, + 0xa1, 0xe5, 0xcf, 0x7a, 0x2d, 0x08, 0x62, 0xed, 0x34, 0x61, 0xe3, 0xda, + 0x2c, 0xcc, 0x1b, 0xf8, 0x12, 0xfe, 0xfd, 0x19, 0xa2, 0xc3, 0x70, 0xfd, + 0x4f, 0x5b, 0x5d, 0x20, 0xd2, 0xe1, 0xc5, 0xac, 0xe7, 0xa1, 0x84, 0x00, + 0xbd, 0x46, 0x81, 0xfd, 0x54, 0x69, 0xed, 0x1a, 0x7a, 0x32, 0xbb, 0x75, + 0x22, 0x76, 0x6d, 0x34, 0x24, 0xcc, 0xe6, 0xbe, 0x78, 0x5a, 0x75, 0x6c, + 0xbc, 0x62, 0xb8, 0x14, 0xf7, 0x13, 0x73, 0xc2, 0xdc, 0xb6, 0xfa, 0xfb, + 0x97, 0xfe, 0x27, 0x7b, 0x33, 0xb8, 0xeb, 0x20, 0xd2, 0x0f, 0x4f, 0xed, + 0xd1, 0xd0, 0x63, 0xf7, 0xc5, 0x8e, 0xec, 0xcc, 0xd2, 0x31, 0x38, 0x35, + 0x65, 0x33, 0x5c, 0x63, 0x85, 0xf7, 0x3d, 0xc3, 0x62, 0x26, 0x52, 0x0a, + 0x67, 0xda, 0x87, 0x1f, 0x9e, 0x47, 0xec, 0x6b, 0xf5, 0x74, 0x1a, 0xc5, + 0xa7, 0xa0, 0x0f, 0xdd, 0xc5, 0x42, 0xf4, 0xda, 0x41, 0x1a, 0x48, 0xa9, + 0xbe, 0x4f, 0xb6, 0x28, 0x17, 0xe9, 0xf5, 0xd7, 0x00, 0xb3, 0xfe, 0x05, + 0x4e, 0xa7, 0xdf, 0x65, 0x7a, 0xb8, 0x4f, 0xe0, 0xfe, 0x58, 0x9e, 0xba, + 0x45, 0x11, 0xba, 0xc2, 0xdb, 0x97, 0x97, 0xa4, 0xbc, 0x18, 0x21, 0x1b, + 0xad, 0x82, 0xef, 0xb1, 0x5f, 0x2f, 0x25, 0x9d, 0xca, 0x52, 0xa5, 0x6d, + 0x8c, 0xab, 0x07, 0x2b, 0x7b, 0x6a, 0x77, 0x9d, 0xdf, 0xfb, 0xae, 0x6e, + 0x49, 0x18, 0x25, 0x4a, 0xf2, 0x7d, 0xa0, 0x32, 0xc8, 0x53, 0x10, 0xc3, + 0xf2, 0xef, 0xf3, 0xe7, 0x79, 0xd7, 0x6a, 0x0e, 0x61, 0xff, 0x89, 0xc9, + 0x42, 0xe8, 0x6e, 0x4f, 0x78, 0xe1, 0x5f, 0xcd, 0x7a, 0xf6, 0x27, 0x72, + 0x67, 0xea, 0x0b, 0xa6, 0xcc, 0x34, 0xb7, 0x8f, 0x92, 0x3c, 0x95, 0xb9, + 0x0a, 0x5d, 0x49, 0x2e, 0xb7, 0x7d, 0x31, 0x9c, 0x79, 0x61, 0x95, 0x9c, + 0x60, 0x56, 0x8d, 0x35, 0x00, 0xc5, 0x8b, 0xe6, 0x02, 0x0f, 0x26, 0x39, + 0x7b, 0x93, 0x94, 0xb1, 0xcd, 0xde, 0xed, 0xfa, 0x2a, 0x4b, 0x63, 0xa8, + 0x1b, 0x31, 0x43, 0x5e, 0x69, 0x7c, 0xd6, 0x15, 0x35, 0x9c, 0xa2, 0xd7, + 0xdf, 0x0e, 0x1a, 0x20, 0x50, 0xf5, 0x02, 0x21, 0x30, 0x35, 0x3c, 0x60, + 0x71, 0xad, 0xd0, 0xe3, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x10, 0x17, 0x1d, 0x22, 0x2d}; +const uint8_t expected_signature_87[] = { + 0xdf, 0xe6, 0xe1, 0xa5, 0x20, 0xc1, 0xac, 0x98, 0x55, 0x2c, 0xf2, 0x13, + 0x65, 0x42, 0xe2, 0xb0, 0x77, 0x5f, 0x15, 0x00, 0x8f, 0x14, 0x48, 0xa1, + 0xe3, 0xee, 0x81, 0x35, 0x15, 0x34, 0xad, 0x6e, 0x60, 0x85, 0x00, 0xf8, + 0x18, 0x53, 0x0d, 0xa0, 0xc5, 0x41, 0xc4, 0x48, 0x09, 0x1b, 0x34, 0x0c, + 0x0e, 0xcf, 0xc6, 0x3d, 0x38, 0x78, 0x8b, 0x69, 0xe5, 0x6f, 0x4d, 0x43, + 0xfa, 0xa6, 0x75, 0x26, 0x8a, 0x75, 0x97, 0x10, 0x6a, 0x1f, 0x3c, 0xa6, + 0x94, 0xa9, 0x93, 0x8f, 0xe5, 0x62, 0xbf, 0x94, 0xe4, 0xd0, 0x0d, 0x11, + 0x4d, 0x03, 0xe2, 0xd8, 0xdf, 0x68, 0xb7, 0x87, 0x62, 0xc9, 0xdc, 0xc9, + 0x36, 0x4f, 0xcc, 0xd1, 0xa4, 0xae, 0x7e, 0xa4, 0xb9, 0xaf, 0xaf, 0xf0, + 0x8a, 0xe6, 0xff, 0x83, 0xe7, 0x54, 0x22, 0x6e, 0x3f, 0x2e, 0xa0, 0x4f, + 0xa8, 0x31, 0x53, 0xf3, 0x62, 0xeb, 0x04, 0xfa, 0xd1, 0x57, 0x39, 0x43, + 0xf9, 0xe0, 0x31, 0x12, 0x45, 0x09, 0x8b, 0x9e, 0x1e, 0x7a, 0x2b, 0x85, + 0xee, 0xdd, 0xe8, 0x1e, 0xd7, 0xc0, 0x17, 0xb4, 0xd2, 0xdc, 0x36, 0xa9, + 0xe4, 0x49, 0x88, 0xbf, 0x71, 0x43, 0x9d, 0x3e, 0xd2, 0x10, 0xe7, 0x82, + 0xb5, 0xfe, 0xdd, 0x42, 0xc8, 0x1b, 0x11, 0xf6, 0x52, 0x23, 0x98, 0x83, + 0x48, 0xec, 0xec, 0x70, 0x8b, 0xe7, 0x49, 0x9a, 0xd7, 0xd9, 0x7b, 0x47, + 0x4e, 0xe2, 0x5e, 0x17, 0x1a, 0xa0, 0x0e, 0x60, 0x85, 0x3a, 0x30, 0x8c, + 0x1c, 0x26, 0xb4, 0xe1, 0xb5, 0x2b, 0x48, 0xf4, 0xb8, 0x93, 0x2f, 0x79, + 0x3a, 0x1e, 0xb6, 0x3b, 0x07, 0x3b, 0x1e, 0x15, 0xd7, 0x85, 0x5e, 0xd4, + 0x06, 0x0e, 0xcd, 0x6a, 0x93, 0x3a, 0x93, 0x29, 0x6a, 0xbe, 0x68, 0x8a, + 0xb6, 0xb8, 0xfa, 0xc5, 0x63, 0x48, 0x98, 0x10, 0x6d, 0xd9, 0xd3, 0x5b, + 0x29, 0x5f, 0x93, 0x90, 0x08, 0x1c, 0x1a, 0x15, 0x7b, 0x0a, 0x59, 0x9d, + 0x64, 0x24, 0x45, 0xb6, 0xd3, 0x7b, 0xc1, 0x5d, 0x74, 0x1f, 0x0b, 0x8e, + 0x18, 0xf2, 0x92, 0x8e, 0xd4, 0x7f, 0x72, 0x5c, 0x98, 0x1f, 0x8b, 0xa5, + 0xb8, 0xf4, 0x7e, 0x12, 0x6a, 0x93, 0xb9, 0xb5, 0xf1, 0xda, 0x97, 0x75, + 0x4f, 0x56, 0x80, 0x88, 0x64, 0x2b, 0xe0, 0x59, 0xcd, 0x5e, 0x91, 0x64, + 0x9c, 0x0c, 0xa8, 0xdd, 0xac, 0xcb, 0xf3, 0x48, 0x3b, 0x5c, 0xc4, 0xc5, + 0xb9, 0x9a, 0x0b, 0x8e, 0x5d, 0x9a, 0xd5, 0xb7, 0xf0, 0xd4, 0x07, 0x48, + 0xb9, 0x63, 0x02, 0x87, 0x8d, 0xae, 0x7e, 0x03, 0x33, 0x4f, 0x86, 0x15, + 0x1b, 0x3b, 0xdf, 0xda, 0xce, 0xd3, 0x1e, 0xc0, 0x76, 0xb5, 0x1c, 0xdd, + 0xb8, 0x32, 0x87, 0x7d, 0x59, 0x18, 0x72, 0x0c, 0xde, 0x8f, 0x63, 0x2d, + 0x38, 0xf2, 0xe9, 0xc2, 0x81, 0xed, 0xfa, 0x2d, 0x61, 0xef, 0x48, 0xdb, + 0xa2, 0xeb, 0xfe, 0x52, 0x31, 0x1e, 0x21, 0x0a, 0x08, 0xf6, 0x02, 0xd3, + 0xc0, 0x32, 0x3b, 0x6b, 0x2f, 0x64, 0xc4, 0xb3, 0x4b, 0xfe, 0x69, 0x78, + 0xbf, 0x20, 0x62, 0x07, 0x77, 0xdf, 0x2c, 0x18, 0x53, 0x61, 0x8e, 0x05, + 0x01, 0x86, 0xab, 0xab, 0xec, 0x18, 0x8c, 0x15, 0x63, 0x1f, 0xe9, 0x99, + 0xb2, 0x35, 0x77, 0xe1, 0x58, 0xf1, 0xa9, 0x4d, 0x1a, 0xb9, 0x8c, 0x30, + 0x63, 0x6f, 0x9e, 0x7d, 0x4e, 0xcf, 0xb5, 0x6c, 0xf3, 0xe4, 0xdc, 0xab, + 0xf9, 0xae, 0x58, 0xf8, 0x1d, 0x08, 0x7b, 0x73, 0x82, 0x58, 0xc8, 0x67, + 0x48, 0x1a, 0x5e, 0x3d, 0xdb, 0xac, 0x1b, 0x1b, 0xef, 0xeb, 0xa4, 0xe5, + 0x67, 0x48, 0x76, 0xd1, 0x96, 0x4f, 0x6c, 0x7d, 0x06, 0x8c, 0x02, 0x86, + 0x95, 0x83, 0xb6, 0x9b, 0x5e, 0x9a, 0xb5, 0x85, 0xc0, 0x4f, 0x13, 0x1c, + 0x32, 0xf8, 0x29, 0xdf, 0x47, 0x85, 0xdb, 0xe4, 0x37, 0xdc, 0xd8, 0x04, + 0x18, 0xdd, 0xca, 0x97, 0xdd, 0x67, 0x13, 0xbe, 0x74, 0x95, 0xdc, 0xd0, + 0xcc, 0xe6, 0xb5, 0xa5, 0x12, 0x9b, 0x23, 0x4f, 0x41, 0x8c, 0xcc, 0x95, + 0xf4, 0xb0, 0x5f, 0x2a, 0xc4, 0xbf, 0x88, 0xda, 0x55, 0xcb, 0x13, 0x93, + 0x22, 0x60, 0x51, 0x43, 0xc7, 0x9a, 0x2c, 0xfa, 0xb2, 0x59, 0xc1, 0xe6, + 0x8a, 0xa4, 0xb8, 0xfb, 0xd3, 0x31, 0x1d, 0xc7, 0x88, 0xdc, 0xbc, 0xe9, + 0xba, 0xe7, 0xdc, 0xe3, 0xdd, 0x90, 0x96, 0xb4, 0xb4, 0x0a, 0xc1, 0x07, + 0x31, 0x3f, 0xdb, 0xc5, 0x4d, 0x73, 0x58, 0x86, 0x15, 0x37, 0x07, 0x86, + 0x03, 0x17, 0x16, 0x18, 0x15, 0xb9, 0x26, 0x35, 0x8a, 0x43, 0x22, 0xae, + 0x21, 0x52, 0x05, 0x4e, 0x5c, 0x3f, 0x3e, 0xb9, 0x2a, 0x19, 0x13, 0xfd, + 0x31, 0x47, 0x6a, 0x74, 0xaa, 0xb9, 0xc6, 0x2c, 0x13, 0x8c, 0x21, 0xc4, + 0x8d, 0x00, 0xf4, 0x24, 0xf2, 0xb7, 0xd3, 0x13, 0xad, 0x29, 0x5e, 0x50, + 0x0b, 0x0e, 0x9f, 0x9a, 0xb7, 0xf6, 0x9e, 0xba, 0x12, 0x23, 0x84, 0x8c, + 0xbe, 0x2c, 0x14, 0x1e, 0xe6, 0x79, 0x15, 0x20, 0x2d, 0x32, 0x08, 0xd8, + 0x1c, 0x87, 0x1b, 0xa8, 0xc0, 0xbb, 0x85, 0xa9, 0x71, 0x30, 0x5e, 0x39, + 0x48, 0x87, 0xdc, 0x3d, 0x03, 0x29, 0x19, 0xd1, 0xd4, 0x21, 0x3a, 0x53, + 0x2d, 0x5e, 0x78, 0xff, 0x94, 0x4b, 0x91, 0xa6, 0xb5, 0xe5, 0x42, 0x56, + 0x67, 0x6a, 0x0e, 0xf3, 0x2d, 0x6a, 0x4e, 0xd7, 0x3a, 0x81, 0xb1, 0x4d, + 0x0b, 0x66, 0x5f, 0x43, 0x28, 0x7c, 0x75, 0x8b, 0x2b, 0x99, 0x24, 0xc2, + 0x5e, 0x8c, 0x22, 0xf0, 0xd5, 0xb3, 0xfc, 0x86, 0x62, 0xf3, 0xd2, 0x6c, + 0xa7, 0x48, 0x04, 0x44, 0x5d, 0x93, 0x74, 0x37, 0x16, 0x2c, 0x19, 0x12, + 0x57, 0x49, 0xef, 0xd5, 0xd6, 0x92, 0xdc, 0x51, 0xf8, 0x55, 0x3a, 0xc0, + 0x0b, 0xdf, 0x41, 0xb5, 0x01, 0x59, 0x7e, 0x85, 0x65, 0xdb, 0x44, 0xbd, + 0x04, 0x96, 0x1a, 0xd4, 0x6e, 0x22, 0x54, 0x92, 0xdb, 0xc7, 0xc5, 0x3a, + 0xdf, 0x0c, 0xf4, 0x1b, 0xdc, 0x14, 0xf6, 0x91, 0x9c, 0xbe, 0xf8, 0x8e, + 0x70, 0xd1, 0x3a, 0x0e, 0x58, 0xe6, 0xb9, 0xd3, 0xaa, 0xa2, 0x70, 0xba, + 0xdd, 0x16, 0x13, 0x19, 0xd1, 0x96, 0x78, 0x04, 0x2f, 0xd7, 0x38, 0x8c, + 0x35, 0x1f, 0xfc, 0x58, 0xa4, 0x4c, 0xa9, 0x9a, 0xae, 0x13, 0x3b, 0xc1, + 0x20, 0x4b, 0x66, 0x0f, 0x72, 0x42, 0x0a, 0x53, 0x84, 0x54, 0x71, 0x06, + 0xdb, 0x85, 0x8f, 0x40, 0xa6, 0x09, 0xf7, 0x24, 0xc4, 0x35, 0xf7, 0x1d, + 0xd4, 0x3d, 0x54, 0x75, 0xaf, 0xc4, 0x78, 0x0f, 0xce, 0xe0, 0x0c, 0x90, + 0x0f, 0xd5, 0x2e, 0x61, 0xf7, 0x58, 0xaa, 0xf0, 0xc7, 0x37, 0x5a, 0x59, + 0x1f, 0x8a, 0x03, 0x98, 0x43, 0xb7, 0x27, 0x78, 0x4e, 0x44, 0x5a, 0xb5, + 0x29, 0xf5, 0xab, 0x9e, 0xb7, 0x2a, 0xc4, 0xa3, 0x03, 0x00, 0xe3, 0x28, + 0x57, 0xc9, 0x2a, 0x98, 0xb8, 0xa1, 0x45, 0x1d, 0xfa, 0x6e, 0xb3, 0x0d, + 0x42, 0x5a, 0xb6, 0xb1, 0x0e, 0x5c, 0xbe, 0x82, 0xe2, 0x36, 0x40, 0x4b, + 0x05, 0x28, 0xd9, 0xbc, 0x27, 0xd6, 0x77, 0x00, 0xc9, 0x29, 0x6a, 0xd6, + 0x19, 0x8f, 0x8d, 0xda, 0xe1, 0xc3, 0x8b, 0x69, 0x71, 0xd0, 0xf7, 0xc8, + 0x33, 0xef, 0xe6, 0x23, 0x6b, 0xcb, 0x00, 0x56, 0x0a, 0x9b, 0x9d, 0x60, + 0x3a, 0xd3, 0xad, 0xd9, 0x5c, 0x6a, 0x7d, 0xab, 0x35, 0x71, 0x93, 0xc5, + 0xf2, 0x6a, 0x38, 0x0e, 0xfb, 0xd9, 0x9b, 0xa5, 0xda, 0x52, 0x45, 0xef, + 0x93, 0x94, 0x5b, 0x08, 0x8c, 0x07, 0xab, 0x2e, 0x99, 0x88, 0x77, 0xb5, + 0x15, 0x66, 0x7f, 0x0e, 0xfa, 0xb0, 0x29, 0xe4, 0x88, 0xd9, 0xdd, 0x22, + 0xaf, 0x7a, 0x4e, 0xb5, 0xd0, 0x62, 0x85, 0x27, 0x33, 0xf1, 0xb7, 0x34, + 0xb1, 0xe6, 0xda, 0x9f, 0x3c, 0xfe, 0xf5, 0xd4, 0xef, 0x56, 0x48, 0x93, + 0x7a, 0x54, 0xa2, 0x7f, 0x07, 0xea, 0x31, 0xb8, 0x8b, 0xca, 0xb9, 0xdb, + 0x1e, 0x2b, 0xb5, 0x16, 0xe6, 0x0e, 0xd9, 0x3f, 0x7c, 0xf0, 0xc2, 0x3e, + 0x57, 0x64, 0x60, 0x97, 0xfb, 0xdf, 0x8c, 0x3e, 0x56, 0x22, 0x92, 0x2a, + 0xb2, 0x21, 0x00, 0x0a, 0x75, 0x89, 0x68, 0xe7, 0x51, 0xa3, 0x63, 0x05, + 0xe1, 0x6f, 0x1e, 0x1e, 0x80, 0xa2, 0x4b, 0x5d, 0xb7, 0xf4, 0xb7, 0x45, + 0x85, 0x00, 0x84, 0x6e, 0xbe, 0x0b, 0x67, 0xbf, 0x21, 0x06, 0x5a, 0x56, + 0x79, 0xe9, 0x6b, 0x0e, 0x72, 0x19, 0x2d, 0x09, 0x78, 0xd5, 0x5e, 0xc2, + 0x32, 0xee, 0x29, 0xd4, 0x7a, 0x65, 0xc7, 0xfe, 0x16, 0x86, 0xd2, 0x29, + 0x71, 0xe5, 0x91, 0x0e, 0x3e, 0x86, 0xd5, 0x00, 0xc4, 0xfc, 0xd9, 0xae, + 0xd3, 0x7c, 0x13, 0xfd, 0x62, 0xce, 0x0c, 0xb2, 0xe5, 0x1f, 0x6d, 0xed, + 0x55, 0x6f, 0xc1, 0xaa, 0xa1, 0x74, 0x59, 0x46, 0x83, 0xd5, 0x5d, 0x71, + 0x17, 0x13, 0x1d, 0x0b, 0x25, 0xfb, 0x0a, 0xcd, 0x67, 0xfe, 0x57, 0x93, + 0xc2, 0x71, 0x55, 0x6c, 0x68, 0xfa, 0x40, 0xdb, 0xdd, 0xce, 0xd5, 0x5c, + 0xce, 0x0a, 0x1d, 0xfa, 0x19, 0x30, 0xe2, 0x2b, 0x63, 0x98, 0x16, 0x2c, + 0x67, 0x69, 0x55, 0xe5, 0xc1, 0x6c, 0x6e, 0xb7, 0x92, 0x6a, 0xbb, 0x10, + 0xd3, 0x13, 0x2e, 0x73, 0x91, 0x74, 0xcb, 0x9f, 0x5c, 0x7f, 0x5c, 0x48, + 0x58, 0x36, 0x13, 0x47, 0xf7, 0x49, 0xae, 0x90, 0x15, 0x53, 0xb5, 0xe6, + 0x37, 0xfb, 0x81, 0x47, 0xb4, 0x69, 0x84, 0xca, 0x95, 0xab, 0x19, 0x2a, + 0x28, 0xc2, 0x8a, 0xf1, 0xcd, 0xf9, 0x3e, 0xd3, 0xaf, 0xe1, 0x75, 0xf7, + 0x94, 0x74, 0x1c, 0xf5, 0x32, 0xcf, 0x70, 0xbd, 0x69, 0xcc, 0xa8, 0x3c, + 0xca, 0x59, 0x53, 0xfa, 0xcb, 0xe7, 0xb6, 0x36, 0x70, 0xea, 0xe2, 0x84, + 0xfa, 0x5e, 0xbd, 0xd7, 0x59, 0x3d, 0x21, 0xc6, 0x9f, 0x5c, 0x1f, 0xa6, + 0xa9, 0xf1, 0xd3, 0x26, 0x9e, 0xff, 0xbc, 0x81, 0xfe, 0xbe, 0xee, 0x64, + 0xd9, 0x63, 0x94, 0x4b, 0x15, 0xd8, 0x95, 0xaa, 0xec, 0x10, 0xc9, 0xe2, + 0xe1, 0x05, 0x37, 0x64, 0xc4, 0xb0, 0x2e, 0xa5, 0x0e, 0x4c, 0x2d, 0x03, + 0x53, 0xf1, 0x93, 0x77, 0x9d, 0x46, 0x14, 0x67, 0x48, 0x5f, 0xad, 0x1b, + 0xdc, 0xb9, 0x74, 0xa2, 0x6c, 0xfc, 0xd2, 0xa0, 0x1f, 0x43, 0x89, 0x15, + 0xc5, 0x0c, 0xb0, 0x9e, 0x1e, 0xc2, 0xd6, 0x44, 0xd9, 0x6e, 0xfc, 0xb4, + 0x9c, 0x95, 0x90, 0xcd, 0xc3, 0x17, 0x1c, 0x6a, 0xce, 0x03, 0x56, 0x9f, + 0xe7, 0xcd, 0x7e, 0xe7, 0xa2, 0x0c, 0x2b, 0x0d, 0x59, 0xb0, 0xc9, 0x4c, + 0x6e, 0x33, 0x6d, 0x43, 0xc4, 0x3a, 0x10, 0x24, 0x03, 0x3e, 0x09, 0xb6, + 0x86, 0x13, 0xba, 0x18, 0x19, 0xd3, 0xff, 0xeb, 0xa5, 0x25, 0x8f, 0x6f, + 0xc8, 0xe6, 0x96, 0xa4, 0xd2, 0x66, 0x40, 0x81, 0x79, 0xe8, 0x39, 0x18, + 0x41, 0x02, 0x66, 0x5c, 0x30, 0x5f, 0x58, 0x9d, 0x35, 0x16, 0xc6, 0x96, + 0xa8, 0x68, 0xbc, 0x09, 0x83, 0x17, 0x2c, 0x5f, 0x5e, 0xd0, 0x1d, 0xb0, + 0x48, 0x5e, 0xcf, 0x91, 0x16, 0x4d, 0xa0, 0xba, 0xbc, 0x61, 0xa8, 0x3f, + 0x30, 0x09, 0xbb, 0xa3, 0x12, 0xcd, 0xdc, 0x29, 0xf7, 0xb0, 0xad, 0x05, + 0x17, 0xd6, 0xd3, 0x16, 0xfb, 0xe5, 0x99, 0xf4, 0x71, 0x62, 0xa3, 0x45, + 0x45, 0xc7, 0x9b, 0xaa, 0x45, 0xd3, 0x35, 0xfe, 0xfb, 0x63, 0xaf, 0xe7, + 0x85, 0x31, 0xc9, 0x66, 0x26, 0xa9, 0xda, 0x8c, 0xc6, 0xf6, 0xd5, 0xdf, + 0xb1, 0xa9, 0xf1, 0xb6, 0x3d, 0x92, 0xae, 0x4d, 0xbc, 0x74, 0x7d, 0x76, + 0x5a, 0x59, 0x8c, 0x87, 0xff, 0x95, 0x2f, 0x67, 0x37, 0x30, 0x1a, 0xc1, + 0x23, 0x2e, 0x0c, 0xaa, 0x80, 0x1c, 0xf3, 0xa3, 0x74, 0x94, 0xb2, 0xda, + 0x1a, 0xb8, 0x46, 0xec, 0x30, 0x76, 0xf4, 0xdf, 0xfb, 0x00, 0xb3, 0x6f, + 0x86, 0xc1, 0xc5, 0x3a, 0x5d, 0x11, 0x14, 0x87, 0xeb, 0x30, 0xd8, 0x33, + 0x18, 0x00, 0x01, 0x76, 0x43, 0x82, 0xcd, 0x1c, 0x36, 0x54, 0xd2, 0x64, + 0x5b, 0xfb, 0x93, 0xca, 0x20, 0x1d, 0xa3, 0x20, 0x99, 0xc3, 0x8e, 0x5c, + 0x82, 0xfc, 0x56, 0x07, 0x41, 0x4b, 0x4f, 0x54, 0xc7, 0xb5, 0xe8, 0x6d, + 0x7e, 0xd8, 0x8a, 0x56, 0xb4, 0x76, 0x1e, 0xd3, 0x82, 0x97, 0xdd, 0x2b, + 0xd9, 0x80, 0xb7, 0xb6, 0xeb, 0x3d, 0xe5, 0xe0, 0x20, 0x27, 0x8c, 0xf0, + 0xd6, 0x14, 0xc7, 0xcd, 0x79, 0xbc, 0xa0, 0x21, 0x85, 0xc3, 0x02, 0xae, + 0x73, 0xc4, 0x0a, 0x39, 0x1a, 0x98, 0x61, 0xc3, 0x86, 0xd8, 0x97, 0x67, + 0x87, 0xe9, 0x56, 0x0b, 0x61, 0xa6, 0x7e, 0x07, 0xfb, 0x0a, 0x8b, 0xd1, + 0x90, 0xbd, 0x39, 0x22, 0xdb, 0xc2, 0x7f, 0xaa, 0x79, 0xb7, 0x39, 0x09, + 0xc1, 0x69, 0xdb, 0xe2, 0x7f, 0xec, 0xde, 0x80, 0x7a, 0x6c, 0xde, 0x76, + 0xa4, 0xe8, 0xe0, 0x8d, 0x71, 0xfa, 0x62, 0xf0, 0x2e, 0x7b, 0xf4, 0xce, + 0x65, 0x18, 0x42, 0xde, 0x92, 0x1b, 0xdc, 0xc9, 0xa7, 0x8d, 0xa5, 0x91, + 0x0f, 0xa5, 0x1b, 0x89, 0xcf, 0x29, 0x10, 0x1d, 0x94, 0x78, 0x1b, 0xea, + 0x79, 0x35, 0x62, 0xd4, 0x29, 0xe6, 0x59, 0x8c, 0xc1, 0xd2, 0xf3, 0x32, + 0x71, 0x09, 0xce, 0x51, 0xd7, 0x14, 0x29, 0x92, 0xbf, 0xdf, 0x9a, 0x69, + 0xda, 0x61, 0x03, 0x0f, 0xa2, 0x0a, 0xab, 0x57, 0x1c, 0xca, 0xab, 0x42, + 0x63, 0x63, 0x1e, 0x35, 0x5d, 0x8d, 0xba, 0x6f, 0x4b, 0x6b, 0x5e, 0x7c, + 0xc0, 0x1e, 0xb7, 0xf4, 0x65, 0xbd, 0x13, 0x1c, 0xf2, 0xa9, 0x73, 0x38, + 0xc3, 0x47, 0xc9, 0x32, 0xf0, 0x30, 0x57, 0x05, 0x42, 0x52, 0xac, 0x72, + 0xee, 0x9f, 0x4e, 0x21, 0xbf, 0x38, 0x19, 0x6d, 0x48, 0xec, 0x97, 0xcb, + 0x70, 0x9e, 0xee, 0xb3, 0xa1, 0xaa, 0xa6, 0x7e, 0xe9, 0x16, 0xdf, 0xcd, + 0x1c, 0x56, 0xcf, 0xf0, 0x9f, 0x4d, 0xd1, 0x8c, 0x14, 0x50, 0x5d, 0x23, + 0x96, 0xe0, 0x1f, 0x61, 0x79, 0xbf, 0x44, 0xfd, 0xa2, 0x31, 0xf7, 0x4c, + 0x0c, 0x8d, 0x8c, 0x1b, 0xbf, 0x8d, 0x45, 0xbf, 0x0b, 0xd8, 0xfb, 0x6f, + 0xff, 0x15, 0xc0, 0x44, 0x7c, 0xb9, 0xb8, 0xf9, 0xef, 0x0d, 0x79, 0x11, + 0x3b, 0x79, 0xd2, 0x52, 0x89, 0x5a, 0xcd, 0x0f, 0x10, 0x92, 0x42, 0xfe, + 0xcf, 0x0a, 0x11, 0x8a, 0x8a, 0xda, 0xee, 0xc8, 0x6b, 0xd9, 0xab, 0xec, + 0xb4, 0x25, 0x6f, 0x8d, 0x68, 0x26, 0xe8, 0xdd, 0xf5, 0xa4, 0xe8, 0x65, + 0x37, 0x03, 0xb0, 0xad, 0x73, 0x3b, 0x4d, 0x74, 0x57, 0x7f, 0x0f, 0x6c, + 0xb0, 0x5d, 0x59, 0x80, 0x13, 0xa1, 0x6c, 0xb0, 0xed, 0x26, 0xec, 0x79, + 0x50, 0x5f, 0x5c, 0xb7, 0xa6, 0xae, 0xe8, 0x0a, 0x6d, 0x55, 0x9a, 0x7f, + 0x59, 0x23, 0xa3, 0x7e, 0x84, 0x7b, 0x3b, 0xfc, 0xde, 0xe1, 0xd9, 0x7c, + 0xd6, 0x87, 0xb3, 0x0e, 0xdb, 0xc1, 0x8c, 0x5e, 0x77, 0xb7, 0x23, 0xd7, + 0x14, 0xd4, 0x23, 0xb4, 0xac, 0x45, 0xbf, 0xfe, 0x40, 0x20, 0x4d, 0x91, + 0x20, 0x94, 0xbd, 0x58, 0xb1, 0x99, 0x69, 0xaf, 0x31, 0x68, 0xbd, 0x61, + 0x5e, 0x87, 0x81, 0x54, 0x4e, 0x2d, 0x03, 0xc2, 0xe2, 0xcd, 0xdc, 0x59, + 0xe5, 0x35, 0xcf, 0xb8, 0xfc, 0x65, 0xed, 0x46, 0xb3, 0x92, 0xe7, 0xf8, + 0x3a, 0x32, 0xaa, 0x0e, 0x5a, 0x82, 0x58, 0x4e, 0x77, 0xd8, 0x33, 0xc9, + 0xb0, 0x3e, 0xad, 0xa5, 0x92, 0xe9, 0xa9, 0x8c, 0x00, 0x72, 0x8f, 0xdc, + 0x77, 0x9d, 0x5c, 0x97, 0xd6, 0x58, 0x20, 0x1e, 0xf4, 0x55, 0x2d, 0xc0, + 0x30, 0xf0, 0x66, 0xda, 0x2d, 0x11, 0xac, 0xd4, 0x2d, 0xd5, 0x25, 0x42, + 0x1d, 0xce, 0x49, 0xb5, 0x95, 0x79, 0x9b, 0x6c, 0x65, 0xe0, 0x8a, 0xc5, + 0x9f, 0x75, 0xe3, 0xe6, 0xf8, 0xa6, 0x88, 0xd6, 0x93, 0x70, 0x4f, 0x89, + 0x94, 0x74, 0xbd, 0xef, 0xc2, 0x1a, 0x55, 0x74, 0x37, 0x44, 0x85, 0x1e, + 0xa9, 0xbb, 0x3f, 0x15, 0xc7, 0x84, 0x80, 0xa5, 0xab, 0xc3, 0x91, 0x8e, + 0xd6, 0x32, 0x46, 0x0d, 0xfa, 0xd1, 0x19, 0xd1, 0xfc, 0x02, 0xe2, 0x20, + 0xa6, 0xa9, 0xf7, 0xf4, 0xcc, 0x5b, 0x54, 0x4f, 0x4a, 0x73, 0x35, 0xda, + 0xf0, 0x31, 0x81, 0x1a, 0x82, 0xe7, 0xd4, 0xc8, 0xb4, 0x1d, 0x70, 0xa9, + 0x5d, 0x67, 0xb9, 0x7d, 0x4b, 0xcd, 0xa4, 0x81, 0xf9, 0xb2, 0x38, 0x07, + 0x16, 0xd5, 0x28, 0x82, 0xb9, 0x76, 0x5b, 0xa1, 0x09, 0x7a, 0xe7, 0x2a, + 0xcf, 0xc0, 0x3d, 0x2a, 0x42, 0x9a, 0xf3, 0xc8, 0x64, 0x15, 0x7c, 0x94, + 0xd0, 0x97, 0xee, 0x34, 0xb6, 0xf0, 0xb2, 0xba, 0x7e, 0xb2, 0xbb, 0x4e, + 0xbf, 0x88, 0xd0, 0x6b, 0xc5, 0x9c, 0xb9, 0xf2, 0x7d, 0xbf, 0x5d, 0x87, + 0xbc, 0x36, 0x4a, 0xd1, 0x1b, 0x6f, 0x40, 0x09, 0xba, 0x26, 0x51, 0xd6, + 0xc0, 0xaf, 0x27, 0xce, 0x27, 0x8d, 0x93, 0xa8, 0x6c, 0x91, 0xe7, 0x91, + 0x42, 0xc0, 0x68, 0x36, 0x5b, 0xd5, 0x56, 0x4c, 0xe2, 0x77, 0xc3, 0xac, + 0x56, 0xe3, 0x1c, 0xc2, 0xf9, 0x78, 0x02, 0x39, 0x7d, 0xed, 0x18, 0x2a, + 0x01, 0x48, 0xe6, 0xf6, 0x7e, 0x34, 0x50, 0xf4, 0x57, 0x56, 0x93, 0xdb, + 0x85, 0x1b, 0x1e, 0x1a, 0x6f, 0x3e, 0x07, 0x3c, 0xad, 0x3f, 0x8d, 0x75, + 0x53, 0xc3, 0x20, 0x72, 0x93, 0x28, 0xd2, 0x86, 0xc8, 0xa5, 0x90, 0xf2, + 0x5f, 0x13, 0xd5, 0xa5, 0xbe, 0x88, 0x9e, 0x9a, 0x57, 0x2c, 0x53, 0x3f, + 0x11, 0x25, 0x00, 0x00, 0x4a, 0x16, 0x8d, 0xd3, 0x3f, 0x2d, 0x3d, 0x88, + 0xbb, 0x4c, 0x4f, 0x9a, 0xb9, 0x97, 0x5f, 0xed, 0x71, 0xa9, 0x68, 0xd9, + 0x4a, 0x14, 0x24, 0xc7, 0xbe, 0xff, 0x85, 0x57, 0xa3, 0x21, 0xe3, 0x21, + 0x79, 0x1f, 0xd0, 0xbb, 0xb7, 0x73, 0xde, 0x60, 0x02, 0x4b, 0x8f, 0x7d, + 0xb3, 0xb3, 0x8a, 0xda, 0x4c, 0xf4, 0xb8, 0xf1, 0x31, 0xff, 0x32, 0x7b, + 0xd8, 0xfa, 0xb1, 0xcb, 0xb4, 0x58, 0xf5, 0xc8, 0x64, 0xdf, 0xfe, 0x3d, + 0x89, 0x52, 0x5c, 0x52, 0x95, 0xf3, 0xba, 0x0d, 0x1d, 0x2c, 0xc4, 0xf7, + 0x3c, 0x3b, 0x6f, 0x8e, 0xc7, 0xab, 0xad, 0x3d, 0x3d, 0x95, 0x9b, 0xc7, + 0x71, 0x36, 0xae, 0x08, 0xc3, 0x08, 0x79, 0xfa, 0x24, 0xee, 0xd9, 0xf9, + 0x63, 0xc7, 0xd9, 0x16, 0x19, 0x8e, 0x0d, 0xaf, 0x52, 0x87, 0x86, 0x7d, + 0xec, 0xe5, 0xea, 0x5a, 0xda, 0x86, 0x9d, 0x0e, 0x50, 0x53, 0x8c, 0x24, + 0xa8, 0x69, 0xc4, 0xf3, 0x85, 0x7b, 0x34, 0x67, 0x19, 0x35, 0xec, 0xd4, + 0xd4, 0x50, 0xe0, 0xe6, 0xe9, 0x29, 0x5b, 0x92, 0xee, 0xba, 0xa9, 0xef, + 0xf6, 0x35, 0x23, 0x8b, 0xdb, 0x48, 0x32, 0x25, 0x41, 0xf3, 0x55, 0x12, + 0x33, 0xc3, 0x6c, 0xed, 0x32, 0xe1, 0x64, 0x7a, 0x8d, 0xa2, 0x19, 0x5a, + 0x26, 0xf2, 0x83, 0xf1, 0xe4, 0x27, 0xdb, 0x67, 0xc3, 0x89, 0x37, 0xea, + 0x78, 0x19, 0xc6, 0xa3, 0x82, 0x84, 0x1c, 0xf3, 0x2b, 0xbe, 0xde, 0xba, + 0xe7, 0x60, 0x2e, 0xf5, 0x4e, 0xb6, 0x73, 0x29, 0xac, 0xc7, 0x55, 0xab, + 0x21, 0xe9, 0x95, 0x78, 0xd5, 0x8e, 0x27, 0xdc, 0x92, 0x5f, 0xc0, 0xcb, + 0xee, 0x66, 0x09, 0x0a, 0xfc, 0x94, 0x43, 0x44, 0x50, 0x35, 0x57, 0xf8, + 0x08, 0xf9, 0x97, 0xa2, 0x0e, 0xde, 0x81, 0xe1, 0xd1, 0xa0, 0x41, 0xfe, + 0xe6, 0x08, 0x6c, 0x98, 0x8c, 0x81, 0x46, 0x0e, 0xf9, 0x9a, 0x54, 0xfe, + 0xc3, 0x91, 0xe3, 0xd4, 0x46, 0xca, 0x52, 0xa2, 0x73, 0x9e, 0x4d, 0xa7, + 0xfd, 0xa1, 0x8e, 0x43, 0x28, 0xf5, 0xa3, 0xa2, 0x62, 0x20, 0x53, 0x62, + 0x05, 0x49, 0xba, 0x06, 0xe2, 0xeb, 0xba, 0xfb, 0x8e, 0xa0, 0x22, 0xc7, + 0xf9, 0xcc, 0x7f, 0x8b, 0xa8, 0x5d, 0x55, 0xd2, 0x24, 0xff, 0xdd, 0x2c, + 0xc1, 0xd0, 0x3d, 0xe4, 0x79, 0xea, 0xba, 0x62, 0xe5, 0xa2, 0x62, 0xf4, + 0x1f, 0xec, 0xb0, 0x07, 0xf2, 0x0d, 0x32, 0x84, 0x86, 0x81, 0x3d, 0x95, + 0xc1, 0x64, 0xfe, 0x9a, 0x3d, 0x8f, 0x4b, 0x6d, 0xfb, 0x0d, 0x42, 0xcf, + 0xbf, 0xdb, 0x51, 0xb2, 0x16, 0xa2, 0x35, 0xaa, 0xe7, 0x31, 0x54, 0xc2, + 0x87, 0xc6, 0xa5, 0x30, 0x71, 0x64, 0x65, 0xff, 0x41, 0x20, 0xb0, 0x83, + 0xdb, 0xb7, 0x95, 0xce, 0xd7, 0xcc, 0x7a, 0x77, 0xad, 0xb8, 0xb7, 0x4c, + 0xfc, 0x11, 0x05, 0x2b, 0xc4, 0xd4, 0xb6, 0x8b, 0xae, 0x13, 0xa5, 0x40, + 0x18, 0x6e, 0x0d, 0xe3, 0xc6, 0xb0, 0x81, 0x46, 0x46, 0x7e, 0x52, 0x0b, + 0x85, 0x4d, 0x98, 0xd9, 0x42, 0xdf, 0xde, 0x45, 0xc1, 0x5a, 0x33, 0x12, + 0x46, 0x26, 0xb3, 0x6f, 0xf2, 0x8b, 0x37, 0x6b, 0xfd, 0x08, 0xf4, 0x46, + 0x86, 0x89, 0x63, 0x63, 0x21, 0xe5, 0xa9, 0xb7, 0xd0, 0x09, 0x17, 0x52, + 0xee, 0xea, 0xdf, 0x97, 0xb7, 0x73, 0x2e, 0x54, 0x2c, 0x7b, 0x70, 0xd3, + 0xda, 0x26, 0x57, 0x1f, 0xb0, 0x19, 0xd9, 0x91, 0x18, 0x69, 0x75, 0x42, + 0x63, 0xcf, 0x6c, 0x8c, 0x98, 0x5e, 0x17, 0x99, 0x7e, 0x1d, 0xdc, 0x67, + 0x6d, 0x99, 0xd9, 0x02, 0x6e, 0x73, 0x90, 0x5a, 0x4f, 0x0a, 0xb4, 0x48, + 0xfb, 0xc5, 0xbd, 0xd2, 0x10, 0x05, 0xa6, 0x12, 0x68, 0x36, 0x28, 0x51, + 0x60, 0x1c, 0xa1, 0xe9, 0x90, 0x54, 0xa5, 0x53, 0xc3, 0x48, 0x9e, 0xd8, + 0x42, 0x52, 0x85, 0x0e, 0xff, 0xfe, 0xbf, 0xad, 0x3a, 0xa4, 0x57, 0x09, + 0x13, 0x38, 0x64, 0x15, 0x7c, 0xfd, 0xed, 0x91, 0x76, 0x44, 0x20, 0x84, + 0xd9, 0x90, 0xab, 0xfe, 0xfd, 0xd6, 0xab, 0xf1, 0xb3, 0x25, 0x21, 0x3d, + 0x97, 0x72, 0xb2, 0x95, 0xc5, 0x22, 0x80, 0xd9, 0x4a, 0x49, 0x9d, 0x99, + 0xc2, 0x4a, 0x9a, 0x59, 0xb3, 0x71, 0x75, 0x5b, 0xf9, 0x89, 0x7a, 0xdd, + 0xa9, 0xb3, 0xc3, 0xeb, 0x42, 0x91, 0xe2, 0x97, 0x30, 0x40, 0x48, 0x68, + 0x19, 0x3b, 0xf5, 0x7b, 0x4e, 0x33, 0x4b, 0x0c, 0xf3, 0xed, 0xda, 0x76, + 0x3f, 0xb0, 0x4b, 0x53, 0x85, 0x04, 0x33, 0x07, 0x53, 0xd8, 0x55, 0xa2, + 0xfb, 0x30, 0x2c, 0x66, 0xbd, 0x21, 0xf8, 0xfa, 0x20, 0x14, 0x9a, 0x0d, + 0x7f, 0xc9, 0x2f, 0x5b, 0x34, 0x29, 0x09, 0x16, 0xb5, 0x0a, 0x8d, 0xdf, + 0xa2, 0x84, 0x9a, 0xae, 0xe6, 0xa0, 0x50, 0x80, 0x31, 0x04, 0xd3, 0x0c, + 0x8f, 0xd1, 0x8a, 0xfd, 0xb4, 0xa5, 0xae, 0xf5, 0x3c, 0x62, 0xae, 0x45, + 0x70, 0xbb, 0x54, 0x62, 0xc8, 0x50, 0x71, 0x42, 0x85, 0xf6, 0x6f, 0xa0, + 0xf0, 0x10, 0x8a, 0x09, 0xbd, 0x71, 0x78, 0xa6, 0x5e, 0xe4, 0x03, 0x8f, + 0x3b, 0xd0, 0x5c, 0x37, 0x55, 0x1a, 0xc8, 0x57, 0x26, 0x62, 0x6c, 0xc4, + 0x67, 0x71, 0x9d, 0x97, 0xc0, 0xea, 0x35, 0x3e, 0x12, 0xd0, 0x2b, 0xc2, + 0x8f, 0x9e, 0xa6, 0x41, 0x48, 0x33, 0x83, 0x38, 0x37, 0x7e, 0xd4, 0xe3, + 0xee, 0x94, 0x8b, 0x81, 0xa4, 0x60, 0xdd, 0xdd, 0xc1, 0x8a, 0x7b, 0xda, + 0xa8, 0x46, 0xb8, 0x42, 0x3a, 0x25, 0xd6, 0x81, 0x89, 0x29, 0x21, 0xc2, + 0x0c, 0x5b, 0xfd, 0x3e, 0x8c, 0x65, 0x91, 0x52, 0xb3, 0x74, 0x1f, 0xd1, + 0x49, 0x7e, 0x1d, 0x59, 0x58, 0x96, 0xb5, 0xee, 0x32, 0xa4, 0xa8, 0x07, + 0x7c, 0xd1, 0x5b, 0x4b, 0xf8, 0x43, 0x5a, 0xa5, 0xcc, 0x60, 0xcc, 0x08, + 0x6a, 0x3c, 0x41, 0x66, 0x99, 0xe3, 0xa8, 0xe0, 0xb8, 0x87, 0xfc, 0x92, + 0xc0, 0x79, 0xc5, 0x3f, 0xd6, 0xc6, 0x8c, 0x01, 0xf4, 0xa5, 0x05, 0xad, + 0x51, 0xed, 0x04, 0xd7, 0x55, 0xc0, 0x73, 0x05, 0x0e, 0x73, 0xe5, 0x39, + 0x45, 0x5b, 0x95, 0x4a, 0x34, 0x07, 0x99, 0xdf, 0x4c, 0x35, 0xf5, 0x0c, + 0x27, 0x6d, 0xd1, 0x45, 0xf1, 0xfd, 0x24, 0xb7, 0xfe, 0xea, 0x11, 0x5d, + 0xa2, 0xc5, 0xa6, 0x81, 0x37, 0x1d, 0xc2, 0x31, 0x31, 0xfc, 0xe0, 0xf4, + 0xd7, 0xe9, 0x98, 0x8b, 0xe3, 0x70, 0x51, 0x62, 0xc8, 0x61, 0x6d, 0xec, + 0x75, 0x56, 0x71, 0xae, 0x88, 0xe0, 0x80, 0xf5, 0xb7, 0x85, 0x10, 0xb7, + 0x3d, 0x16, 0x78, 0x5f, 0x72, 0xab, 0x8f, 0x63, 0xc6, 0xd5, 0xa8, 0xc9, + 0x9c, 0xef, 0x8d, 0x9a, 0xc5, 0x4f, 0x63, 0xad, 0xc0, 0xf3, 0x1f, 0x69, + 0x0e, 0xce, 0x29, 0x92, 0xc1, 0x3b, 0xb0, 0xc5, 0xed, 0x0a, 0x7b, 0x92, + 0xd0, 0x4c, 0x9c, 0x82, 0xb0, 0x51, 0xf6, 0x33, 0x61, 0x3b, 0x76, 0x48, + 0x38, 0xf4, 0x7c, 0xaa, 0x52, 0x87, 0x15, 0x1a, 0xbe, 0xb8, 0xdc, 0x9b, + 0x16, 0xd2, 0x07, 0xf7, 0xf9, 0x74, 0xe0, 0xaf, 0x0e, 0x29, 0x05, 0xec, + 0x6c, 0x0e, 0x3b, 0xa7, 0xe7, 0xa4, 0xfc, 0xa4, 0xef, 0x57, 0x16, 0x7f, + 0x13, 0xbd, 0x8c, 0x42, 0x02, 0x55, 0x70, 0x56, 0xa5, 0xa9, 0x01, 0x29, + 0x12, 0x7d, 0x80, 0x46, 0x18, 0x8e, 0x39, 0x3f, 0x44, 0x55, 0xec, 0xef, + 0x60, 0x58, 0x7d, 0xce, 0x64, 0x8e, 0x9c, 0xea, 0xe4, 0x73, 0xd1, 0x48, + 0x9c, 0x3f, 0x92, 0xa0, 0x9a, 0x76, 0xa5, 0x5a, 0x13, 0x1f, 0x10, 0xb9, + 0xb7, 0xb1, 0xde, 0x49, 0x22, 0x58, 0xf4, 0x43, 0x5f, 0x03, 0x43, 0xc3, + 0x6c, 0xbf, 0x82, 0xaf, 0x88, 0x39, 0xfd, 0xb2, 0x28, 0x9b, 0x47, 0x3f, + 0x83, 0x3d, 0xd9, 0x7c, 0xf0, 0xc9, 0xc5, 0xa2, 0xb4, 0xd6, 0x0d, 0x59, + 0x51, 0x27, 0x60, 0x10, 0x5e, 0xbb, 0x18, 0xa6, 0x42, 0x4a, 0x9d, 0xc4, + 0x16, 0x0e, 0xb6, 0x57, 0x23, 0x03, 0x24, 0x27, 0xdc, 0x20, 0x56, 0x30, + 0x8b, 0x0f, 0xb6, 0xb7, 0x73, 0xf5, 0x36, 0x3e, 0xf6, 0x7a, 0x71, 0xa5, + 0x57, 0xcc, 0x6d, 0xc6, 0xf3, 0xdc, 0x35, 0xfb, 0x95, 0xf7, 0xa7, 0xd7, + 0x56, 0x38, 0xd4, 0x15, 0xe2, 0xd5, 0x6f, 0x70, 0x30, 0xc8, 0x7d, 0x8a, + 0x87, 0xe6, 0xd1, 0xe0, 0x50, 0x62, 0xde, 0xfa, 0x29, 0x40, 0x97, 0xa0, + 0x54, 0x63, 0x31, 0xd3, 0x08, 0x87, 0x0a, 0xdc, 0x6e, 0x5e, 0xab, 0x8d, + 0x16, 0xaf, 0x6e, 0x8b, 0x1a, 0x77, 0xf6, 0xd4, 0xe0, 0xbf, 0x59, 0xab, + 0xc7, 0xb0, 0x45, 0x18, 0xaa, 0xe6, 0x65, 0x6f, 0x7d, 0x13, 0xb2, 0xbf, + 0xb3, 0x66, 0x72, 0xfa, 0xfd, 0xee, 0xad, 0x07, 0x56, 0x51, 0x6a, 0xe2, + 0xff, 0xb2, 0xaf, 0x4d, 0xd1, 0xf2, 0x77, 0x35, 0x5e, 0x90, 0xcd, 0xe7, + 0xa8, 0x32, 0x4d, 0x9f, 0xbd, 0xa8, 0xce, 0xab, 0xf1, 0x49, 0x98, 0xb5, + 0x23, 0x5c, 0x62, 0x2d, 0x43, 0x31, 0x80, 0x87, 0xc2, 0xa8, 0xf5, 0xb9, + 0xb6, 0xae, 0x7f, 0x37, 0x13, 0xb8, 0x6b, 0x73, 0xf3, 0x56, 0x38, 0xa7, + 0x9b, 0x97, 0x69, 0x37, 0x00, 0xdc, 0xff, 0xfe, 0x58, 0xc9, 0x12, 0x47, + 0x75, 0x98, 0x1f, 0xad, 0xd8, 0xb5, 0xc8, 0x47, 0x4f, 0xd0, 0x72, 0x63, + 0x54, 0x25, 0x6c, 0x88, 0xc9, 0x9f, 0x3c, 0x82, 0xe0, 0xdd, 0x4c, 0xff, + 0x8e, 0xaf, 0x8f, 0x8e, 0xea, 0x84, 0x3f, 0x73, 0xdd, 0x9e, 0x18, 0x73, + 0x47, 0x70, 0xc7, 0xc7, 0x99, 0x65, 0xcf, 0xf3, 0xb6, 0x24, 0xed, 0x97, + 0x8f, 0xcd, 0x93, 0x1e, 0xff, 0x6e, 0x9c, 0xf1, 0x30, 0x14, 0x1a, 0x27, + 0x59, 0x6a, 0x0e, 0xf3, 0xe4, 0xfa, 0x1d, 0x65, 0xb5, 0x53, 0xe4, 0xab, + 0xb1, 0x3e, 0xe1, 0x91, 0xf4, 0x6d, 0x99, 0xca, 0x7d, 0x03, 0x08, 0x50, + 0xea, 0xa9, 0x39, 0x7f, 0x6d, 0xe7, 0x43, 0xfb, 0x64, 0xcc, 0x4b, 0x9e, + 0xa0, 0x26, 0xe4, 0x0e, 0xff, 0xb7, 0x11, 0x0a, 0x29, 0x50, 0x90, 0xd7, + 0x4d, 0x62, 0x9a, 0x4a, 0x23, 0xb7, 0xd3, 0x53, 0xde, 0x3a, 0xd1, 0xba, + 0xd3, 0x10, 0x59, 0xc6, 0xc5, 0x5e, 0xac, 0xf9, 0x61, 0x74, 0x54, 0xf4, + 0x27, 0x9f, 0x9a, 0x61, 0x13, 0xdc, 0xe5, 0x96, 0xe3, 0x95, 0x0d, 0xcc, + 0xbd, 0x81, 0x74, 0x79, 0x73, 0xef, 0x2e, 0x0b, 0x0f, 0x91, 0x65, 0x3c, + 0x26, 0x7c, 0x47, 0x10, 0x31, 0x0b, 0xfb, 0x41, 0x0c, 0xc2, 0xa8, 0xc4, + 0x0e, 0xbd, 0x0a, 0x8c, 0xa4, 0x80, 0x45, 0x57, 0x62, 0x0b, 0x4d, 0x44, + 0x5e, 0x59, 0x77, 0xfd, 0x3d, 0xf3, 0xd7, 0x92, 0x49, 0xc1, 0xcb, 0x8a, + 0x54, 0x56, 0x3b, 0xde, 0xcf, 0x16, 0x9a, 0x65, 0xbe, 0xac, 0x64, 0xe1, + 0xd4, 0xd4, 0x1e, 0xac, 0x6b, 0x4a, 0xad, 0xc4, 0x33, 0xac, 0xcb, 0x83, + 0xf4, 0x4d, 0xe8, 0xb6, 0xd7, 0x23, 0xd7, 0x71, 0x25, 0xa2, 0x25, 0x3d, + 0x7e, 0xf0, 0x3b, 0x7f, 0x61, 0x11, 0x56, 0xd4, 0x83, 0xc8, 0xc0, 0x29, + 0x38, 0x10, 0x73, 0xad, 0x6a, 0xb7, 0xb9, 0xd2, 0x2e, 0x9f, 0xae, 0x16, + 0x5e, 0xa6, 0x13, 0x1c, 0xc2, 0x17, 0x73, 0x43, 0x03, 0xdd, 0xa6, 0xaf, + 0x9a, 0x17, 0x31, 0xb8, 0x86, 0x97, 0xc2, 0xd6, 0xe6, 0xed, 0xd4, 0xe1, + 0x7d, 0xb9, 0xa6, 0x96, 0xc1, 0x4b, 0xcb, 0x11, 0x1e, 0xe1, 0xe0, 0xd2, + 0x28, 0x69, 0x68, 0x3b, 0x21, 0x17, 0x63, 0x0c, 0xc0, 0x49, 0x30, 0x22, + 0x3a, 0x59, 0x72, 0xe6, 0x47, 0xb4, 0xdc, 0xa8, 0x29, 0x1c, 0x89, 0xa6, + 0x3a, 0x77, 0x99, 0xea, 0x46, 0xce, 0x38, 0xda, 0x31, 0x88, 0xad, 0xe7, + 0x26, 0xce, 0xc6, 0x56, 0x04, 0x30, 0xfa, 0x01, 0xac, 0xbb, 0xe2, 0xb8, + 0x23, 0xe4, 0x9d, 0x4f, 0x77, 0x02, 0x00, 0x28, 0xf1, 0xe0, 0x19, 0x3f, + 0x22, 0x4f, 0x22, 0x69, 0x87, 0xc0, 0x4e, 0x26, 0x33, 0xfe, 0x6c, 0x70, + 0x56, 0x3b, 0x60, 0x5f, 0xfb, 0xf8, 0x43, 0xcf, 0x3f, 0xb9, 0xcb, 0x80, + 0x22, 0xbb, 0x0a, 0xa8, 0x1c, 0x3e, 0x7e, 0x4d, 0x42, 0x60, 0x5c, 0x8e, + 0xfa, 0x42, 0xb3, 0x95, 0xe7, 0x92, 0x6b, 0xec, 0x7a, 0x95, 0x88, 0x98, + 0xe3, 0xf9, 0x0d, 0xe5, 0x08, 0xf1, 0x26, 0x96, 0x2a, 0x81, 0x2b, 0x7c, + 0x0d, 0x12, 0xa0, 0x7f, 0x7b, 0x39, 0xf6, 0xcc, 0x1b, 0x2d, 0x2c, 0xe9, + 0x5b, 0x02, 0x9b, 0x5c, 0x94, 0x51, 0x13, 0xe8, 0xa0, 0x19, 0xce, 0xde, + 0x07, 0x1b, 0xda, 0x39, 0x14, 0xb5, 0x8b, 0xcf, 0x79, 0x3e, 0x2b, 0xb8, + 0x75, 0xab, 0x81, 0xee, 0x5e, 0x08, 0x33, 0xc3, 0x49, 0x5b, 0x4a, 0x9c, + 0x74, 0x34, 0xde, 0x08, 0x61, 0x03, 0x38, 0xe3, 0xd8, 0xff, 0xc5, 0xc0, + 0xb5, 0x40, 0xd5, 0x26, 0x57, 0x85, 0xf1, 0xb7, 0x77, 0xb6, 0x36, 0xe0, + 0x8d, 0x43, 0x3a, 0xef, 0xfe, 0x0f, 0xf7, 0xee, 0x67, 0x6c, 0x7b, 0xd1, + 0x83, 0xf6, 0x10, 0xda, 0x67, 0x04, 0x3a, 0x27, 0xd8, 0x3a, 0xcb, 0x9d, + 0x4c, 0xa6, 0x9a, 0xc7, 0xea, 0x07, 0xc6, 0x76, 0x79, 0x1b, 0x23, 0x4a, + 0x68, 0x2f, 0x14, 0x84, 0x42, 0x79, 0xe8, 0x1f, 0xf2, 0xe6, 0xac, 0x72, + 0xb0, 0xb0, 0xb6, 0x39, 0x95, 0x40, 0xa4, 0x6e, 0x54, 0x2e, 0xb7, 0xb5, + 0x13, 0x70, 0x48, 0x0d, 0x27, 0xed, 0x2c, 0xa2, 0x64, 0x53, 0xb4, 0x04, + 0x84, 0xab, 0xd8, 0xea, 0x2a, 0x8c, 0xac, 0x5b, 0x1d, 0xb8, 0xb2, 0xbe, + 0x55, 0x2b, 0x4a, 0x47, 0xfc, 0xe0, 0x15, 0x78, 0xb6, 0xd6, 0xff, 0x20, + 0xa8, 0x8a, 0xec, 0x8b, 0x30, 0xef, 0xc5, 0xc6, 0xec, 0xa0, 0xdf, 0xd3, + 0xc4, 0x2b, 0x4a, 0xdf, 0xef, 0x5c, 0x46, 0xb3, 0x31, 0xc7, 0x5f, 0x8f, + 0x1e, 0x99, 0x76, 0x81, 0x71, 0x61, 0xdb, 0xc3, 0xc4, 0x0f, 0x66, 0x7b, + 0xd7, 0x44, 0xc7, 0x8d, 0x12, 0x38, 0x71, 0x7c, 0xd8, 0x41, 0xf6, 0x8a, + 0xb9, 0xba, 0xd2, 0x1f, 0xa1, 0x27, 0x64, 0x67, 0x51, 0xb2, 0xaf, 0xea, + 0x02, 0x95, 0x79, 0x20, 0x0a, 0xc8, 0xaa, 0x03, 0x11, 0xb6, 0x8b, 0x7d, + 0x86, 0xb7, 0xef, 0x5e, 0x3f, 0x0b, 0x91, 0x47, 0xf0, 0x43, 0xb4, 0x54, + 0x1d, 0x16, 0x66, 0xe9, 0x63, 0x1a, 0x55, 0xaf, 0x34, 0xad, 0x11, 0x68, + 0x4d, 0x36, 0xb7, 0x0c, 0x6d, 0x4d, 0xed, 0xba, 0x14, 0xe8, 0xf6, 0xe2, + 0x15, 0x64, 0xb6, 0x15, 0x28, 0xbf, 0xd2, 0x4d, 0xb6, 0x6f, 0xca, 0x5f, + 0x81, 0x1b, 0xf0, 0x31, 0xf5, 0xd3, 0xe0, 0x06, 0xc7, 0xf3, 0x0c, 0x18, + 0x91, 0x45, 0x22, 0xa2, 0x30, 0x48, 0x82, 0xeb, 0x42, 0xfc, 0x8f, 0x2a, + 0xa3, 0x1a, 0x8d, 0x84, 0x28, 0x20, 0x16, 0x95, 0xd9, 0x66, 0x67, 0x2b, + 0xef, 0xc6, 0x6e, 0x56, 0x1c, 0x62, 0x74, 0x16, 0x5c, 0x3e, 0x17, 0xd0, + 0xb7, 0xdd, 0x70, 0xb6, 0x0e, 0x79, 0x46, 0xc5, 0x4e, 0x72, 0x46, 0x69, + 0xf5, 0xa1, 0x1c, 0x7b, 0xd5, 0x67, 0x5c, 0xb3, 0x46, 0x4d, 0x18, 0x31, + 0x47, 0x42, 0x20, 0xe6, 0x12, 0x84, 0x4e, 0x16, 0x0f, 0x4a, 0xd0, 0xc4, + 0x91, 0xa3, 0xbd, 0x91, 0xcd, 0x86, 0x4c, 0xcd, 0x4b, 0x2e, 0x62, 0x84, + 0xea, 0x19, 0x2d, 0x21, 0x1a, 0x64, 0xc4, 0xd2, 0x24, 0x92, 0x96, 0x04, + 0x66, 0xb5, 0x4a, 0xe4, 0xa9, 0xd6, 0xaf, 0x12, 0x9b, 0xb5, 0x59, 0xe0, + 0x5c, 0x84, 0x84, 0x7c, 0x68, 0x99, 0xd8, 0x23, 0xa2, 0x15, 0xa7, 0x82, + 0xa5, 0x66, 0x95, 0x8f, 0xfe, 0x57, 0xc1, 0x12, 0x6c, 0x89, 0xe5, 0x5b, + 0x5d, 0x64, 0xdb, 0x81, 0x4f, 0x77, 0x3c, 0xc8, 0x52, 0x4e, 0x2a, 0xd6, + 0x74, 0x3c, 0x4b, 0x11, 0xfc, 0xc1, 0x7c, 0x01, 0xba, 0x0f, 0x0f, 0x57, + 0x8a, 0xbe, 0x5b, 0x16, 0x88, 0x96, 0xe6, 0xe9, 0x60, 0xcf, 0x66, 0xe9, + 0xe6, 0x07, 0xb0, 0x0b, 0xa3, 0xa0, 0xad, 0xdf, 0x70, 0xd4, 0xcb, 0x2e, + 0x33, 0x2f, 0xe5, 0xf2, 0x1e, 0x0d, 0x74, 0x7a, 0xf9, 0x4a, 0x0f, 0x32, + 0xb4, 0xa1, 0xc9, 0xf5, 0x3f, 0x0a, 0x06, 0xf9, 0x67, 0x45, 0x9c, 0xd9, + 0x58, 0xd4, 0x0e, 0x72, 0x55, 0x47, 0x49, 0x9b, 0xab, 0x9c, 0x66, 0xe7, + 0x4d, 0x9a, 0x02, 0x1b, 0x41, 0xad, 0xe5, 0x8c, 0x7f, 0xa1, 0xdc, 0xad, + 0xcd, 0x74, 0xda, 0x9f, 0xfa, 0x87, 0x32, 0xc1, 0x07, 0x8e, 0x9b, 0xef, + 0x28, 0x2f, 0x17, 0x6d, 0xdb, 0x84, 0x4b, 0xa8, 0x7d, 0x31, 0xa8, 0x32, + 0xe4, 0x9a, 0x1e, 0x0e, 0xef, 0x68, 0xf4, 0xac, 0x03, 0x6c, 0x68, 0xcc, + 0x28, 0xbb, 0xfb, 0x21, 0xb8, 0x11, 0xd7, 0xf9, 0xe8, 0x24, 0x37, 0xdf, + 0xe0, 0xb2, 0xef, 0xd6, 0xec, 0xdf, 0xcf, 0xf5, 0x50, 0x19, 0xa3, 0xa9, + 0x1b, 0x01, 0x2e, 0x94, 0x42, 0xb0, 0x14, 0x5d, 0x0e, 0x37, 0x46, 0x4a, + 0x52, 0x53, 0x60, 0x6b, 0x89, 0xc9, 0xca, 0xed, 0x0a, 0x0c, 0x18, 0x33, + 0x3c, 0x40, 0x42, 0x76, 0x7a, 0x7d, 0xb6, 0x10, 0x29, 0x3e, 0x42, 0x75, + 0xa6, 0xbf, 0xcb, 0xd3, 0xdc, 0xe1, 0x00, 0x05, 0x08, 0x25, 0x67, 0x6c, + 0x72, 0xde, 0x26, 0x72, 0x88, 0xbe, 0xfa, 0x05, 0x57, 0x77, 0x78, 0x83, + 0xce, 0xd5, 0x44, 0x49, 0x8b, 0xab, 0xbc, 0xca, 0xd3, 0x1c, 0x34, 0x4a, + 0xaa, 0xc7, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x17, 0x22, 0x2a, 0x2f, 0x36, 0x3d, 0x43}; +#endif /* !MLD_CONFIG_KEYGEN_PCT */ +#endif /* !EXPECTED_SIGNATURES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/main.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/main.c new file mode 100644 index 0000000000..a5054717d6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/main.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include +#include +#include + +#include "expected_signatures.h" +#include "mldsa_native_all.h" +#include "test_only_rng/notrandombytes.h" + +#define CHECK(x) \ + do \ + { \ + int rc; \ + rc = (x); \ + if (!rc) \ + { \ + fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \ + return 1; \ + } \ + } while (0) + +#define TEST_MSG \ + "This is a test message for ML-DSA digital signature algorithm!" +#define TEST_MSG_LEN (sizeof(TEST_MSG) - 1) + +#define TEST_CTX "test_context_123" +#define TEST_CTX_LEN (sizeof(TEST_CTX) - 1) + +static int test_mldsa44(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[MLDSA44_PUBLICKEYBYTES]; + uint8_t sk[MLDSA44_SECRETKEYBYTES]; + uint8_t sig[MLDSA44_BYTES]; + uint8_t sm[TEST_MSG_LEN + MLDSA44_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + MLDSA44_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-44\n"); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(mldsa44_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(mldsa44_signature(sig, &siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(mldsa44_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(mldsa44_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(mldsa44_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", MLDSA44_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", MLDSA44_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", MLDSA44_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature_44)); + CHECK(memcmp(sig, expected_signature_44, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} + +static int test_mldsa65(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[MLDSA65_PUBLICKEYBYTES]; + uint8_t sk[MLDSA65_SECRETKEYBYTES]; + uint8_t sig[MLDSA65_BYTES]; + uint8_t sm[TEST_MSG_LEN + MLDSA65_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + MLDSA65_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-65\n"); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(mldsa65_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(mldsa65_signature(sig, &siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(mldsa65_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(mldsa65_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(mldsa65_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", MLDSA65_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", MLDSA65_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", MLDSA65_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature_65)); + CHECK(memcmp(sig, expected_signature_65, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} + + +static int test_mldsa87(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[MLDSA87_PUBLICKEYBYTES]; + uint8_t sk[MLDSA87_SECRETKEYBYTES]; + uint8_t sig[MLDSA87_BYTES]; + uint8_t sm[TEST_MSG_LEN + MLDSA87_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + MLDSA87_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-87\n"); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(mldsa87_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(mldsa87_signature(sig, &siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(mldsa87_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(mldsa87_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(mldsa87_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", MLDSA87_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", MLDSA87_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", MLDSA87_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature_87)); + CHECK(memcmp(sig, expected_signature_87, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} + +int main(void) +{ + printf("ML-DSA monolithic_build_multilevel Example\n"); + + if (test_mldsa44() != 0) + { + return 1; + } + + if (test_mldsa65() != 0) + { + return 1; + } + + if (test_mldsa87() != 0) + { + return 1; + } + + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/mldsa_native.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/mldsa_native.c new file mode 100644 index 0000000000..9668cec167 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/mldsa_native.c @@ -0,0 +1,699 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/****************************************************************************** + * + * Single compilation unit (SCU) for fixed-level build of mldsa-native + * + * This compilation unit bundles together all source files for a build + * of mldsa-native for a fixed security level (MLDSA-44/65/87). + * + * # API + * + * The API exposed by this file is described in mldsa_native.h. + * + * # Multi-level build + * + * If you want an SCU build of mldsa-native with support for multiple security + * levels, you need to include this file multiple times, and set + * MLD_CONFIG_MULTILEVEL_WITH_SHARED and MLD_CONFIG_MULTILEVEL_NO_SHARED + * appropriately. This is exemplified in examples/monolithic_build_multilevel + * and examples/monolithic_build_multilevel_native. + * + * # Configuration + * + * The following options from the mldsa-native configuration are relevant: + * + * - MLD_CONFIG_FIPS202_CUSTOM_HEADER + * Set this option if you use a custom FIPS202 implementation. + * + * - MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * Set this option if you want to include the native arithmetic backends + * in your build. + * + * - MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * Set this option if you want to include the native FIPS202 backends + * in your build. + * + * - MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * Set this option if you want to keep the directives defined in + * level-independent headers. This is needed for a multi-level build. + */ + +/* If parts of the mldsa-native source tree are not used, + * consider reducing this header via `unifdef`. + * + * Example: + * ```bash + * unifdef -UMLD_CONFIG_USE_NATIVE_BACKEND_ARITH mldsa_native.c + * ``` + */ + +#include "src/common.h" + +#include "src/ct.c" +#include "src/debug.c" +#include "src/packing.c" +#include "src/poly.c" +#include "src/poly_kl.c" +#include "src/polyvec.c" +#include "src/sign.c" + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#include "src/fips202/fips202.c" +#include "src/fips202/fips202x4.c" +#include "src/fips202/keccakf1600.c" +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#if defined(MLD_SYS_AARCH64) +#include "src/native/aarch64/src/aarch64_zetas.c" +#include "src/native/aarch64/src/polyz_unpack_table.c" +#include "src/native/aarch64/src/rej_uniform_eta_table.c" +#include "src/native/aarch64/src/rej_uniform_table.c" +#endif /* MLD_SYS_AARCH64 */ +#if defined(MLD_SYS_X86_64) +#include "src/native/x86_64/src/consts.c" +#include "src/native/x86_64/src/poly_caddq_avx2.c" +#include "src/native/x86_64/src/poly_chknorm_avx2.c" +#include "src/native/x86_64/src/poly_decompose_32_avx2.c" +#include "src/native/x86_64/src/poly_decompose_88_avx2.c" +#include "src/native/x86_64/src/poly_use_hint_32_avx2.c" +#include "src/native/x86_64/src/poly_use_hint_88_avx2.c" +#include "src/native/x86_64/src/polyz_unpack_17_avx2.c" +#include "src/native/x86_64/src/polyz_unpack_19_avx2.c" +#include "src/native/x86_64/src/rej_uniform_avx2.c" +#include "src/native/x86_64/src/rej_uniform_eta2_avx2.c" +#include "src/native/x86_64/src/rej_uniform_eta4_avx2.c" +#include "src/native/x86_64/src/rej_uniform_table.c" +#endif /* MLD_SYS_X86_64 */ +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#if defined(MLD_SYS_AARCH64) +#include "src/fips202/native/aarch64/src/keccakf1600_round_constants.c" +#endif +#if defined(MLD_SYS_X86_64) +#include "src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +/* Macro #undef's + * + * The following undefines macros from headers + * included by the source files imported above. + * + * This is to allow building and linking multiple builds + * of mldsa-native for varying parameter sets through concatenation + * of this file, as if the files had been compiled separately. + * If this is not relevant to you, you may remove the following. + */ + +/* + * Undefine macros from MLD_CONFIG_PARAMETER_SET-specific files + */ +/* mldsa/mldsa_native.h */ +#undef CRYPTO_BYTES +#undef CRYPTO_PUBLICKEYBYTES +#undef CRYPTO_SECRETKEYBYTES +#undef MLDSA44_BYTES +#undef MLDSA44_CRHBYTES +#undef MLDSA44_PUBLICKEYBYTES +#undef MLDSA44_RNDBYTES +#undef MLDSA44_SECRETKEYBYTES +#undef MLDSA44_SEEDBYTES +#undef MLDSA44_TRBYTES +#undef MLDSA65_BYTES +#undef MLDSA65_CRHBYTES +#undef MLDSA65_PUBLICKEYBYTES +#undef MLDSA65_RNDBYTES +#undef MLDSA65_SECRETKEYBYTES +#undef MLDSA65_SEEDBYTES +#undef MLDSA65_TRBYTES +#undef MLDSA87_BYTES +#undef MLDSA87_CRHBYTES +#undef MLDSA87_PUBLICKEYBYTES +#undef MLDSA87_RNDBYTES +#undef MLDSA87_SECRETKEYBYTES +#undef MLDSA87_SEEDBYTES +#undef MLDSA87_TRBYTES +#undef MLDSA_BYTES +#undef MLDSA_BYTES_ +#undef MLDSA_CRHBYTES +#undef MLDSA_PUBLICKEYBYTES +#undef MLDSA_PUBLICKEYBYTES_ +#undef MLDSA_RNDBYTES +#undef MLDSA_SECRETKEYBYTES +#undef MLDSA_SECRETKEYBYTES_ +#undef MLDSA_SEEDBYTES +#undef MLDSA_TRBYTES +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_LEGACY_CONFIG +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_NAMESPACE +#undef MLD_API_QUALIFIER +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_QUALIFIER +#undef MLD_DOMAIN_SEPARATION_MAX_BYTES +#undef MLD_ERR_FAIL +#undef MLD_ERR_OUT_OF_MEMORY +#undef MLD_ERR_RNG_FAIL +#undef MLD_H +#undef MLD_MAX3_ +#undef MLD_PREHASH_NONE +#undef MLD_PREHASH_SHA2_224 +#undef MLD_PREHASH_SHA2_256 +#undef MLD_PREHASH_SHA2_384 +#undef MLD_PREHASH_SHA2_512 +#undef MLD_PREHASH_SHA2_512_224 +#undef MLD_PREHASH_SHA2_512_256 +#undef MLD_PREHASH_SHA3_224 +#undef MLD_PREHASH_SHA3_256 +#undef MLD_PREHASH_SHA3_384 +#undef MLD_PREHASH_SHA3_512 +#undef MLD_PREHASH_SHAKE_128 +#undef MLD_PREHASH_SHAKE_256 +#undef MLD_TOTAL_ALLOC_44 +#undef MLD_TOTAL_ALLOC_44_KEYPAIR +#undef MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#undef MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#undef MLD_TOTAL_ALLOC_44_SIGN +#undef MLD_TOTAL_ALLOC_44_VERIFY +#undef MLD_TOTAL_ALLOC_65 +#undef MLD_TOTAL_ALLOC_65_KEYPAIR +#undef MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#undef MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#undef MLD_TOTAL_ALLOC_65_SIGN +#undef MLD_TOTAL_ALLOC_65_VERIFY +#undef MLD_TOTAL_ALLOC_87 +#undef MLD_TOTAL_ALLOC_87_KEYPAIR +#undef MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#undef MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#undef MLD_TOTAL_ALLOC_87_SIGN +#undef MLD_TOTAL_ALLOC_87_VERIFY +#undef crypto_sign +#undef crypto_sign_keypair +#undef crypto_sign_open +#undef crypto_sign_signature +#undef crypto_sign_verify +/* mldsa/src/common.h */ +#undef MLD_ADD_PARAM_SET +#undef MLD_ALLOC +#undef MLD_APPLY +#undef MLD_ASM_FN_SYMBOL +#undef MLD_ASM_NAMESPACE +#undef MLD_BUILD_INTERNAL +#undef MLD_COMMON_H +#undef MLD_CONCAT +#undef MLD_CONCAT_ +#undef MLD_CONTEXT_PARAMETERS_0 +#undef MLD_CONTEXT_PARAMETERS_1 +#undef MLD_CONTEXT_PARAMETERS_2 +#undef MLD_CONTEXT_PARAMETERS_3 +#undef MLD_CONTEXT_PARAMETERS_4 +#undef MLD_CONTEXT_PARAMETERS_5 +#undef MLD_CONTEXT_PARAMETERS_6 +#undef MLD_CONTEXT_PARAMETERS_7 +#undef MLD_CONTEXT_PARAMETERS_8 +#undef MLD_CONTEXT_PARAMETERS_9 +#undef MLD_EMPTY_CU +#undef MLD_ERR_FAIL +#undef MLD_ERR_OUT_OF_MEMORY +#undef MLD_ERR_RNG_FAIL +#undef MLD_EXTERNAL_API +#undef MLD_FIPS202X4_HEADER_FILE +#undef MLD_FIPS202_HEADER_FILE +#undef MLD_FREE +#undef MLD_INTERNAL_API +#undef MLD_MULTILEVEL_BUILD +#undef MLD_NAMESPACE +#undef MLD_NAMESPACE_KL +#undef MLD_NAMESPACE_PREFIX +#undef MLD_NAMESPACE_PREFIX_KL +#undef MLD_UNION_OR_STRUCT +#undef mld_memcpy +#undef mld_memset +/* mldsa/src/packing.h */ +#undef MLD_PACKING_H +#undef mld_pack_pk +#undef mld_pack_sig_c_h +#undef mld_pack_sig_z +#undef mld_pack_sk +#undef mld_unpack_pk +#undef mld_unpack_sig +#undef mld_unpack_sk +/* mldsa/src/params.h */ +#undef MLDSA_BETA +#undef MLDSA_CRHBYTES +#undef MLDSA_CRYPTO_BYTES +#undef MLDSA_CRYPTO_PUBLICKEYBYTES +#undef MLDSA_CRYPTO_SECRETKEYBYTES +#undef MLDSA_CTILDEBYTES +#undef MLDSA_D +#undef MLDSA_ETA +#undef MLDSA_GAMMA1 +#undef MLDSA_GAMMA2 +#undef MLDSA_K +#undef MLDSA_L +#undef MLDSA_N +#undef MLDSA_OMEGA +#undef MLDSA_POLYETA_PACKEDBYTES +#undef MLDSA_POLYT0_PACKEDBYTES +#undef MLDSA_POLYT1_PACKEDBYTES +#undef MLDSA_POLYVECH_PACKEDBYTES +#undef MLDSA_POLYW1_PACKEDBYTES +#undef MLDSA_POLYZ_PACKEDBYTES +#undef MLDSA_Q +#undef MLDSA_Q_HALF +#undef MLDSA_RNDBYTES +#undef MLDSA_SEEDBYTES +#undef MLDSA_TAU +#undef MLDSA_TRBYTES +#undef MLD_PARAMS_H +/* mldsa/src/poly_kl.h */ +#undef MLD_POLYETA_UNPACK_LOWER_BOUND +#undef MLD_POLY_KL_H +#undef mld_poly_challenge +#undef mld_poly_decompose +#undef mld_poly_make_hint +#undef mld_poly_uniform_eta +#undef mld_poly_uniform_eta_4x +#undef mld_poly_uniform_gamma1 +#undef mld_poly_uniform_gamma1_4x +#undef mld_poly_use_hint +#undef mld_polyeta_pack +#undef mld_polyeta_unpack +#undef mld_polyw1_pack +#undef mld_polyz_pack +#undef mld_polyz_unpack +/* mldsa/src/polyvec.h */ +#undef MLD_POLYVEC_H +#undef mld_polymat +#undef mld_polymat_get_row +#undef mld_polyvec_matrix_expand +#undef mld_polyvec_matrix_pointwise_montgomery +#undef mld_polyveck +#undef mld_polyveck_add +#undef mld_polyveck_caddq +#undef mld_polyveck_chknorm +#undef mld_polyveck_decompose +#undef mld_polyveck_invntt_tomont +#undef mld_polyveck_make_hint +#undef mld_polyveck_ntt +#undef mld_polyveck_pack_eta +#undef mld_polyveck_pack_t0 +#undef mld_polyveck_pack_w1 +#undef mld_polyveck_pointwise_poly_montgomery +#undef mld_polyveck_power2round +#undef mld_polyveck_reduce +#undef mld_polyveck_shiftl +#undef mld_polyveck_sub +#undef mld_polyveck_unpack_eta +#undef mld_polyveck_unpack_t0 +#undef mld_polyveck_use_hint +#undef mld_polyvecl +#undef mld_polyvecl_chknorm +#undef mld_polyvecl_ntt +#undef mld_polyvecl_pack_eta +#undef mld_polyvecl_pointwise_acc_montgomery +#undef mld_polyvecl_uniform_gamma1 +#undef mld_polyvecl_unpack_eta +#undef mld_polyvecl_unpack_z +/* mldsa/src/rounding.h */ +#undef MLD_2_POW_D +#undef MLD_ROUNDING_H +#undef mld_decompose +#undef mld_make_hint +#undef mld_power2round +#undef mld_use_hint +/* mldsa/src/sign.h */ +#undef MLD_DOMAIN_SEPARATION_MAX_BYTES +#undef MLD_PREHASH_NONE +#undef MLD_PREHASH_SHA2_224 +#undef MLD_PREHASH_SHA2_256 +#undef MLD_PREHASH_SHA2_384 +#undef MLD_PREHASH_SHA2_512 +#undef MLD_PREHASH_SHA2_512_224 +#undef MLD_PREHASH_SHA2_512_256 +#undef MLD_PREHASH_SHA3_224 +#undef MLD_PREHASH_SHA3_256 +#undef MLD_PREHASH_SHA3_384 +#undef MLD_PREHASH_SHA3_512 +#undef MLD_PREHASH_SHAKE_128 +#undef MLD_PREHASH_SHAKE_256 +#undef MLD_SIGN_H +#undef mld_prepare_domain_separation_prefix +#undef mld_sign +#undef mld_sign_keypair +#undef mld_sign_keypair_internal +#undef mld_sign_open +#undef mld_sign_pk_from_sk +#undef mld_sign_signature +#undef mld_sign_signature_extmu +#undef mld_sign_signature_internal +#undef mld_sign_signature_pre_hash_internal +#undef mld_sign_signature_pre_hash_shake256 +#undef mld_sign_verify +#undef mld_sign_verify_extmu +#undef mld_sign_verify_internal +#undef mld_sign_verify_pre_hash_internal +#undef mld_sign_verify_pre_hash_shake256 + +#if !defined(MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS) +/* + * Undefine macros from MLD_CONFIG_PARAMETER_SET-generic files + */ +/* mldsa/src/ct.h */ +#undef MLD_CT_H +#undef MLD_USE_ASM_VALUE_BARRIER +#undef mld_ct_opt_blocker_u64 +/* mldsa/src/debug.h */ +#undef MLD_DEBUG_H +#undef mld_assert +#undef mld_assert_abs_bound +#undef mld_assert_abs_bound_2d +#undef mld_assert_bound +#undef mld_assert_bound_2d +#undef mld_debug_check_assert +#undef mld_debug_check_bounds +/* mldsa/src/poly.h */ +#undef MLD_INTT_BOUND +#undef MLD_NTT_BOUND +#undef MLD_POLY_H +#undef mld_poly_add +#undef mld_poly_caddq +#undef mld_poly_chknorm +#undef mld_poly_invntt_tomont +#undef mld_poly_ntt +#undef mld_poly_pointwise_montgomery +#undef mld_poly_power2round +#undef mld_poly_reduce +#undef mld_poly_shiftl +#undef mld_poly_sub +#undef mld_poly_uniform +#undef mld_poly_uniform_4x +#undef mld_polyt0_pack +#undef mld_polyt0_unpack +#undef mld_polyt1_pack +#undef mld_polyt1_unpack +/* mldsa/src/randombytes.h */ +#undef MLD_RANDOMBYTES_H +/* mldsa/src/reduce.h */ +#undef MLD_MONT +#undef MLD_REDUCE32_DOMAIN_MAX +#undef MLD_REDUCE32_RANGE_MAX +#undef MLD_REDUCE_H +/* mldsa/src/symmetric.h */ +#undef MLD_STREAM128_BLOCKBYTES +#undef MLD_STREAM256_BLOCKBYTES +#undef MLD_SYMMETRIC_H +#undef mld_xof128_absorb_once +#undef mld_xof128_ctx +#undef mld_xof128_init +#undef mld_xof128_release +#undef mld_xof128_squeezeblocks +#undef mld_xof128_x4_absorb +#undef mld_xof128_x4_ctx +#undef mld_xof128_x4_init +#undef mld_xof128_x4_release +#undef mld_xof128_x4_squeezeblocks +#undef mld_xof256_absorb_once +#undef mld_xof256_ctx +#undef mld_xof256_init +#undef mld_xof256_release +#undef mld_xof256_squeezeblocks +#undef mld_xof256_x4_absorb +#undef mld_xof256_x4_ctx +#undef mld_xof256_x4_init +#undef mld_xof256_x4_release +#undef mld_xof256_x4_squeezeblocks +/* mldsa/src/sys.h */ +#undef MLD_ALIGN +#undef MLD_ALIGN_UP +#undef MLD_ALWAYS_INLINE +#undef MLD_CET_ENDBR +#undef MLD_CT_TESTING_DECLASSIFY +#undef MLD_CT_TESTING_SECRET +#undef MLD_DEFAULT_ALIGN +#undef MLD_HAVE_INLINE_ASM +#undef MLD_INLINE +#undef MLD_MUST_CHECK_RETURN_VALUE +#undef MLD_RESTRICT +#undef MLD_STATIC_TESTABLE +#undef MLD_SYS_AARCH64 +#undef MLD_SYS_AARCH64_EB +#undef MLD_SYS_APPLE +#undef MLD_SYS_BIG_ENDIAN +#undef MLD_SYS_H +#undef MLD_SYS_LINUX +#undef MLD_SYS_LITTLE_ENDIAN +#undef MLD_SYS_PPC64LE +#undef MLD_SYS_RISCV32 +#undef MLD_SYS_RISCV64 +#undef MLD_SYS_WINDOWS +#undef MLD_SYS_X86_64 +#undef MLD_SYS_X86_64_AVX2 +/* mldsa/src/cbmc.h */ +#undef MLD_CBMC_H +#undef __contract__ +#undef __loop__ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +/* + * Undefine macros from FIPS-202 files + */ +/* mldsa/src/fips202/fips202.h */ +#undef MLD_FIPS202_FIPS202_H +#undef MLD_KECCAK_LANES +#undef SHA3_256_HASHBYTES +#undef SHA3_256_RATE +#undef SHA3_512_HASHBYTES +#undef SHA3_512_RATE +#undef SHAKE128_RATE +#undef SHAKE256_RATE +#undef mld_shake128_absorb +#undef mld_shake128_finalize +#undef mld_shake128_init +#undef mld_shake128_release +#undef mld_shake128_squeeze +#undef mld_shake256 +#undef mld_shake256_absorb +#undef mld_shake256_finalize +#undef mld_shake256_init +#undef mld_shake256_release +#undef mld_shake256_squeeze +/* mldsa/src/fips202/fips202x4.h */ +#undef MLD_FIPS202_FIPS202X4_H +#undef mld_shake128x4_absorb_once +#undef mld_shake128x4_init +#undef mld_shake128x4_release +#undef mld_shake128x4_squeezeblocks +#undef mld_shake256x4_absorb_once +#undef mld_shake256x4_init +#undef mld_shake256x4_release +#undef mld_shake256x4_squeezeblocks +/* mldsa/src/fips202/keccakf1600.h */ +#undef MLD_FIPS202_KECCAKF1600_H +#undef MLD_KECCAK_LANES +#undef MLD_KECCAK_WAY +#undef mld_keccakf1600_extract_bytes +#undef mld_keccakf1600_permute +#undef mld_keccakf1600_xor_bytes +#undef mld_keccakf1600x4_extract_bytes +#undef mld_keccakf1600x4_permute +#undef mld_keccakf1600x4_xor_bytes +#endif /* !MLD_CONFIG_FIPS202_CUSTOM_HEADER */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +/* mldsa/src/fips202/native/api.h */ +#undef MLD_FIPS202_NATIVE_API_H +#undef MLD_NATIVE_FUNC_FALLBACK +#undef MLD_NATIVE_FUNC_SUCCESS +/* mldsa/src/fips202/native/auto.h */ +#undef MLD_FIPS202_NATIVE_AUTO_H +#if defined(MLD_SYS_AARCH64) +/* + * Undefine macros from native code (FIPS202, AArch64) + */ +/* mldsa/src/fips202/native/aarch64/auto.h */ +#undef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* mldsa/src/fips202/native/aarch64/src/fips202_native_aarch64.h */ +#undef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#undef mld_keccak_f1600_x1_scalar_asm +#undef mld_keccak_f1600_x1_v84a_asm +#undef mld_keccak_f1600_x2_v84a_asm +#undef mld_keccak_f1600_x4_scalar_v8a_hybrid_asm +#undef mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm +#undef mld_keccakf1600_round_constants +/* mldsa/src/fips202/native/aarch64/x1_scalar.h */ +#undef MLD_FIPS202_AARCH64_NEED_X1_SCALAR +#undef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#undef MLD_USE_FIPS202_X1_NATIVE +/* mldsa/src/fips202/native/aarch64/x1_v84a.h */ +#undef MLD_FIPS202_AARCH64_NEED_X1_V84A +#undef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#undef MLD_USE_FIPS202_X1_NATIVE +/* mldsa/src/fips202/native/aarch64/x2_v84a.h */ +#undef MLD_FIPS202_AARCH64_NEED_X2_V84A +#undef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#undef MLD_USE_FIPS202_X4_NATIVE +/* mldsa/src/fips202/native/aarch64/x4_v8a_scalar.h */ +#undef MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID +#undef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#undef MLD_USE_FIPS202_X4_NATIVE +/* mldsa/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h */ +#undef MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID +#undef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#undef MLD_USE_FIPS202_X4_NATIVE +#endif /* MLD_SYS_AARCH64 */ +#if defined(MLD_SYS_X86_64) +/* + * Undefine macros from native code (FIPS202, x86_64) + */ +/* mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h */ +#undef MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H +#undef mld_keccakf1600x4_permute24 +/* mldsa/src/fips202/native/x86_64/xkcp.h */ +#undef MLD_FIPS202_NATIVE_X86_64_XKCP_H +#undef MLD_FIPS202_X86_64_XKCP +#undef MLD_USE_FIPS202_X4_NATIVE +#endif /* MLD_SYS_X86_64 */ +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +/* mldsa/src/native/api.h */ +#undef MLD_INTT_BOUND +#undef MLD_NATIVE_API_H +#undef MLD_NATIVE_FUNC_FALLBACK +#undef MLD_NATIVE_FUNC_SUCCESS +#undef MLD_NTT_BOUND +#undef REDUCE32_RANGE_MAX +/* mldsa/src/native/meta.h */ +#undef MLD_NATIVE_META_H +#if defined(MLD_SYS_AARCH64) +/* + * Undefine macros from native code (Arith, AArch64) + */ +/* mldsa/src/native/aarch64/meta.h */ +#undef MLD_ARITH_BACKEND_AARCH64 +#undef MLD_NATIVE_AARCH64_META_H +#undef MLD_USE_NATIVE_INTT +#undef MLD_USE_NATIVE_NTT +#undef MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_17 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_19 +#undef MLD_USE_NATIVE_POLY_CADDQ +#undef MLD_USE_NATIVE_POLY_CHKNORM +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#undef MLD_USE_NATIVE_POLY_USE_HINT_32 +#undef MLD_USE_NATIVE_POLY_USE_HINT_88 +#undef MLD_USE_NATIVE_REJ_UNIFORM +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +/* mldsa/src/native/aarch64/src/arith_native_aarch64.h */ +#undef MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN +#undef MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN +#undef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#undef mld_aarch64_intt_zetas_layer123456 +#undef mld_aarch64_intt_zetas_layer78 +#undef mld_aarch64_ntt_zetas_layer123456 +#undef mld_aarch64_ntt_zetas_layer78 +#undef mld_intt_asm +#undef mld_ntt_asm +#undef mld_poly_caddq_asm +#undef mld_poly_chknorm_asm +#undef mld_poly_decompose_32_asm +#undef mld_poly_decompose_88_asm +#undef mld_poly_pointwise_montgomery_asm +#undef mld_poly_use_hint_32_asm +#undef mld_poly_use_hint_88_asm +#undef mld_polyvecl_pointwise_acc_montgomery_l4_asm +#undef mld_polyvecl_pointwise_acc_montgomery_l5_asm +#undef mld_polyvecl_pointwise_acc_montgomery_l7_asm +#undef mld_polyz_unpack_17_asm +#undef mld_polyz_unpack_17_indices +#undef mld_polyz_unpack_19_asm +#undef mld_polyz_unpack_19_indices +#undef mld_rej_uniform_asm +#undef mld_rej_uniform_eta2_asm +#undef mld_rej_uniform_eta4_asm +#undef mld_rej_uniform_eta_table +#undef mld_rej_uniform_table +#endif /* MLD_SYS_AARCH64 */ +#if defined(MLD_SYS_X86_64) +/* + * Undefine macros from native code (Arith, X86_64) + */ +/* mldsa/src/native/x86_64/meta.h */ +#undef MLD_ARITH_BACKEND_X86_64_DEFAULT +#undef MLD_NATIVE_X86_64_META_H +#undef MLD_USE_NATIVE_INTT +#undef MLD_USE_NATIVE_NTT +#undef MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#undef MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_17 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_19 +#undef MLD_USE_NATIVE_POLY_CADDQ +#undef MLD_USE_NATIVE_POLY_CHKNORM +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#undef MLD_USE_NATIVE_POLY_USE_HINT_32 +#undef MLD_USE_NATIVE_POLY_USE_HINT_88 +#undef MLD_USE_NATIVE_REJ_UNIFORM +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +/* mldsa/src/native/x86_64/src/arith_native_x86_64.h */ +#undef MLD_AVX2_REJ_UNIFORM_BUFLEN +#undef MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN +#undef MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN +#undef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#undef mld_invntt_avx2 +#undef mld_ntt_avx2 +#undef mld_nttunpack_avx2 +#undef mld_pointwise_acc_l4_avx2 +#undef mld_pointwise_acc_l5_avx2 +#undef mld_pointwise_acc_l7_avx2 +#undef mld_pointwise_avx2 +#undef mld_poly_caddq_avx2 +#undef mld_poly_chknorm_avx2 +#undef mld_poly_decompose_32_avx2 +#undef mld_poly_decompose_88_avx2 +#undef mld_poly_use_hint_32_avx2 +#undef mld_poly_use_hint_88_avx2 +#undef mld_polyz_unpack_17_avx2 +#undef mld_polyz_unpack_19_avx2 +#undef mld_rej_uniform_avx2 +#undef mld_rej_uniform_eta2_avx2 +#undef mld_rej_uniform_eta4_avx2 +#undef mld_rej_uniform_table +/* mldsa/src/native/x86_64/src/consts.h */ +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XQ +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV +#undef MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS +#undef MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV +#undef MLD_NATIVE_X86_64_SRC_CONSTS_H +#undef mld_qdata +#endif /* MLD_SYS_X86_64 */ +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ +#endif /* !MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/mldsa_native.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/mldsa_native.h new file mode 100644 index 0000000000..fd150a9df1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/mldsa_native.h @@ -0,0 +1,975 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_H +#define MLD_H + +/* + * Public API for mldsa-native + * + * This header defines the public API of a single build of mldsa-native. + * + * Make sure the configuration file is in the include path + * (this is "mldsa_native_config.h" by default, or MLD_CONFIG_FILE if defined). + * + * # Multi-level builds + * + * This header specifies a build of mldsa-native for a fixed security level. + * If you need multiple security levels, leave the security level unspecified + * in the configuration file and include this header multiple times, setting + * MLD_CONFIG_PARAMETER_SET accordingly for each, and #undef'ing the MLD_H + * guard to allow multiple inclusions. + * + * # Legacy configuration (deprecated) + * + * Instead of providing the config file used for the build, you can + * alternatively set the following configuration options prior to + * including this header. + * + * This method of configuration is deprecated. + * It will be removed in mldsa-native-v2. + * + * - MLD_CONFIG_API_PARAMETER_SET [required] + * + * The parameter set used for the build; 44, 65, or 87. + * + * - MLD_CONFIG_API_NAMESPACE_PREFIX [required] + * + * The namespace prefix used for the build. + * + * NOTE: + * For a multi-level build, you must include the 44/65/87 suffixes + * in MLD_CONFIG_API_NAMESPACE_PREFIX. + * + * - MLD_CONFIG_API_NO_SUPERCOP [optional] + * + * By default, this header will also expose the mldsa-native API in the + * SUPERCOP naming convention crypto_sign_xxx. If you don't want/need this, + * set MLD_CONFIG_API_NO_SUPERCOP. You must set this for a multi-level build. + * + * - MLD_CONFIG_API_CONSTANTS_ONLY [optional] + * + * If you don't want this header to expose any function declarations, + * but only constants for the sizes of key material, set + * MLD_CONFIG_API_CONSTANTS_ONLY. In this case, you don't need to set + * MLD_CONFIG_API_PARAMETER_SET or MLD_CONFIG_API_NAMESPACE_PREFIX, + * nor include a configuration. + * + * - MLD_CONFIG_API_QUALIFIER [optional] + * + * Qualifier to apply to external API. + * + ******************************************************************************/ + +/******************************* Key sizes ************************************/ + +/* Sizes of cryptographic material, per parameter set */ +/* See mldsa/src/params.h for the arithmetic expressions giving rise to these */ +/* check-magic: off */ +#define MLDSA44_SECRETKEYBYTES 2560 +#define MLDSA44_PUBLICKEYBYTES 1312 +#define MLDSA44_BYTES 2420 + +#define MLDSA65_SECRETKEYBYTES 4032 +#define MLDSA65_PUBLICKEYBYTES 1952 +#define MLDSA65_BYTES 3309 + +#define MLDSA87_SECRETKEYBYTES 4896 +#define MLDSA87_PUBLICKEYBYTES 2592 +#define MLDSA87_BYTES 4627 +/* check-magic: on */ + +/* Size of seed and randomness in bytes (level-independent) */ +#define MLDSA_SEEDBYTES 32 +#define MLDSA44_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA65_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA87_SEEDBYTES MLDSA_SEEDBYTES + +/* Size of CRH output in bytes (level-independent) */ +#define MLDSA_CRHBYTES 64 +#define MLDSA44_CRHBYTES MLDSA_CRHBYTES +#define MLDSA65_CRHBYTES MLDSA_CRHBYTES +#define MLDSA87_CRHBYTES MLDSA_CRHBYTES + +/* Size of TR output in bytes (level-independent) */ +#define MLDSA_TRBYTES 64 +#define MLDSA44_TRBYTES MLDSA_TRBYTES +#define MLDSA65_TRBYTES MLDSA_TRBYTES +#define MLDSA87_TRBYTES MLDSA_TRBYTES + +/* Size of randomness for signing in bytes (level-independent) */ +#define MLDSA_RNDBYTES 32 +#define MLDSA44_RNDBYTES MLDSA_RNDBYTES +#define MLDSA65_RNDBYTES MLDSA_RNDBYTES +#define MLDSA87_RNDBYTES MLDSA_RNDBYTES + +/* Sizes of cryptographic material, as a function of LVL=44,65,87 */ +#define MLDSA_SECRETKEYBYTES_(LVL) MLDSA##LVL##_SECRETKEYBYTES +#define MLDSA_PUBLICKEYBYTES_(LVL) MLDSA##LVL##_PUBLICKEYBYTES +#define MLDSA_BYTES_(LVL) MLDSA##LVL##_BYTES +#define MLDSA_SECRETKEYBYTES(LVL) MLDSA_SECRETKEYBYTES_(LVL) +#define MLDSA_PUBLICKEYBYTES(LVL) MLDSA_PUBLICKEYBYTES_(LVL) +#define MLDSA_BYTES(LVL) MLDSA_BYTES_(LVL) + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + +/****************************** Function API **********************************/ + +#define MLD_API_CONCAT_(x, y) x##y +#define MLD_API_CONCAT(x, y) MLD_API_CONCAT_(x, y) +#define MLD_API_CONCAT_UNDERSCORE(x, y) MLD_API_CONCAT(MLD_API_CONCAT(x, _), y) + +#if !defined(MLD_CONFIG_API_PARAMETER_SET) +/* Recommended configuration via same config file as used for the build. */ + +/* For now, we derive the legacy API configuration MLD_CONFIG_API_XXX from + * the config file. In mldsa-native-v2, this will be removed and we will + * exclusively work with MLD_CONFIG_XXX. */ + +/* You need to make sure the config file is in the include path. */ +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#define MLD_CONFIG_API_PARAMETER_SET MLD_CONFIG_PARAMETER_SET + +#if defined(MLD_CONFIG_MULTILEVEL_BUILD) +#define MLD_CONFIG_API_NAMESPACE_PREFIX \ + MLD_API_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_CONFIG_API_NAMESPACE_PREFIX MLD_CONFIG_NAMESPACE_PREFIX +#endif + +#if defined(MLD_CONFIG_NO_SUPERCOP) +#define MLD_CONFIG_API_NO_SUPERCOP +#endif + +#if defined(MLD_CONFIG_CONSTANTS_ONLY) +#define MLD_CONFIG_API_CONSTANTS_ONLY +#endif + +#if defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_CONFIG_API_QUALIFIER MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#else /* !MLD_CONFIG_API_PARAMETER_SET */ +#define MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_PARAMETER_SET */ + +#define MLD_API_NAMESPACE(sym) \ + MLD_API_CONCAT_UNDERSCORE(MLD_CONFIG_API_NAMESPACE_PREFIX, sym) + +#if defined(__GNUC__) || defined(clang) +#define MLD_API_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_API_MUST_CHECK_RETURN_VALUE +#endif + +#if defined(MLD_CONFIG_API_QUALIFIER) +#define MLD_API_QUALIFIER MLD_CONFIG_API_QUALIFIER +#else +#define MLD_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_API_CONSTANTS_ONLY) + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************************* + * Name: crypto_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: + * input random seed + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair_internal)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t seed[MLDSA_SEEDBYTES] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: If MLD_CONFIG_KEYGEN_PCT is enabled and the + * PCT check failed. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return -1 in that case. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_extmu + * + * Description: Computes signature. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_extmu)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t *sm: pointer to output signed message (allocated array + * with MLDSA{44,65,87}_BYTES + mlen bytes), can be + * equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(sign)( + uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_extmu)( + const uint8_t *sig, size_t siglen, const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_open + * + * Description: Verify signed message. + * + * Arguments: + * - uint8_t *m: pointer to output message (allocated array with + * smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(open)( + uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: crypto_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *ph, size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_shake256)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_shake256)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/* Maximum formatted domain separation message length */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +size_t MLD_API_NAMESPACE(prepare_domain_separation_prefix)( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg); + +/************************************************* + * Name: crypto_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[CRYPTO_SECRETKEYBYTES]: input secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(pk_from_sk)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +#ifdef __cplusplus +} +#endif + +/****************************** SUPERCOP API *********************************/ + +#if !defined(MLD_CONFIG_API_NO_SUPERCOP) +/* Export API in SUPERCOP naming scheme CRYPTO_xxx / crypto_sign_xxx */ +#define CRYPTO_SECRETKEYBYTES MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_PUBLICKEYBYTES MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_BYTES MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET) + +#define crypto_sign_keypair MLD_API_NAMESPACE(keypair) +#define crypto_sign_signature MLD_API_NAMESPACE(signature) +#define crypto_sign MLD_API_NAMESPACE(sign) +#define crypto_sign_verify MLD_API_NAMESPACE(verify) +#define crypto_sign_open MLD_API_NAMESPACE(open) + +#else /* !MLD_CONFIG_API_NO_SUPERCOP */ + +/* If the SUPERCOP API is not needed, we can undefine the various helper macros + * above. Otherwise, they are needed for lazy evaluation of crypto_sign_xxx. */ +#if !defined(MLD_API_LEGACY_CONFIG) +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_QUALIFIER +#endif /* !MLD_API_LEGACY_CONFIG */ + +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_NAMESPACE +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_QUALIFIER +#undef MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_NO_SUPERCOP */ +#endif /* !MLD_CONFIG_API_CONSTANTS_ONLY */ + + +/***************************** Memory Usage **********************************/ + +/* + * By default mldsa-native performs all memory allocations on the stack. + * Alternatively, mldsa-native supports custom allocation of large structures + * through the `MLD_CONFIG_CUSTOM_ALLOC_FREE` configuration option. + * See mldsa_native_config.h for details. + * + * `MLD_TOTAL_ALLOC_{44,65,87}_{KEYPAIR,SIGN,VERIFY}` indicates the maximum + * (accumulative) allocation via MLD_ALLOC for each parameter set and operation. + * Note that some stack allocation remains even + * when using custom allocators, so these values are lower than total stack + * usage with the default stack-only allocation. + * + * These constants may be used to implement custom allocations using a + * fixed-sized buffer and a simple allocator (e.g., bump allocator). + */ +/* check-magic: off */ +#if defined(MLD_API_LEGACY_CONFIG) || !defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 45248 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 56640 +#define MLD_TOTAL_ALLOC_44_SIGN 52896 +#define MLD_TOTAL_ALLOC_44_VERIFY 38816 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 71872 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 85856 +#define MLD_TOTAL_ALLOC_65_SIGN 80576 +#define MLD_TOTAL_ALLOC_65_VERIFY 62432 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 112832 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 130816 +#define MLD_TOTAL_ALLOC_87_SIGN 123584 +#define MLD_TOTAL_ALLOC_87_VERIFY 99552 +#else /* MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM */ +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 32992 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 36192 +#define MLD_TOTAL_ALLOC_44_SIGN 32448 +#define MLD_TOTAL_ALLOC_44_VERIFY 22464 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 46304 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 50048 +#define MLD_TOTAL_ALLOC_65_SIGN 44768 +#define MLD_TOTAL_ALLOC_65_VERIFY 30720 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 62688 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 66336 +#define MLD_TOTAL_ALLOC_87_SIGN 59104 +#define MLD_TOTAL_ALLOC_87_VERIFY 41216 +#endif /* !(MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM) */ +/* check-magic: on */ + +/* + * MLD_TOTAL_ALLOC_*_KEYPAIR adapts based on MLD_CONFIG_KEYGEN_PCT. + * For legacy config, we don't know which options are used, so assume + * the worst case (PCT enabled). + */ +#if defined(MLD_API_LEGACY_CONFIG) || defined(MLD_CONFIG_KEYGEN_PCT) +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#else +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#endif + +#define MLD_MAX3_(a, b, c) \ + ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c))) + +/* + * `MLD_TOTAL_ALLOC_{44,65,87}` is the maximum across all operations for each + * parameter set. + */ +#define MLD_TOTAL_ALLOC_44 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_44_KEYPAIR, MLD_TOTAL_ALLOC_44_SIGN, \ + MLD_TOTAL_ALLOC_44_VERIFY) +#define MLD_TOTAL_ALLOC_65 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_65_KEYPAIR, MLD_TOTAL_ALLOC_65_SIGN, \ + MLD_TOTAL_ALLOC_65_VERIFY) +#define MLD_TOTAL_ALLOC_87 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_87_KEYPAIR, MLD_TOTAL_ALLOC_87_SIGN, \ + MLD_TOTAL_ALLOC_87_VERIFY) + +#endif /* !MLD_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/mldsa_native_config.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/mldsa_native_config.h new file mode 100644 index 0000000000..1f5f2ba64f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/mldsa_native_config.h @@ -0,0 +1,740 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/* + * Test configuration: Multilevel monolithic build config + * + * This configuration differs from the default mldsa/mldsa_native_config.h in + * the following places: + * - MLD_CONFIG_NO_SUPERCOP + * - MLD_CONFIG_MULTILEVEL_BUILD + * - MLD_CONFIG_NAMESPACE_PREFIX + * - MLD_CONFIG_INTERNAL_API_QUALIFIER + */ + + +#ifndef MLD_CONFIG_H +#define MLD_CONFIG_H + +/****************************************************************************** + * Name: MLD_CONFIG_PARAMETER_SET + * + * Description: Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * If you want to support multiple parameter sets, build the + * library multiple times and set MLD_CONFIG_MULTILEVEL_BUILD. + * See MLD_CONFIG_MULTILEVEL_BUILD for how to do this while + * minimizing code duplication. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of the default configuration file mldsa/mldsa_native_config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * then configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + * + *****************************************************************************/ +/* No need to set this -- we _are_ already in a custom config */ +/* #define MLD_CONFIG_FILE "mldsa_native_config.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_NAMESPACE_PREFIX + * + * Description: The prefix to use to namespace global symbols from mldsa/. + * + * In a multi-level build, level-dependent symbols will + * additionally be prefixed with the parameter set (44/65/87). + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_NAMESPACE_PREFIX mldsa + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_BUILD + * + * Description: Set this if the build is part of a multi-level build supporting + * multiple parameter sets. + * + * If you need only a single parameter set, keep this unset. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them. + * + * See examples/multilevel_build for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_MULTILEVEL_BUILD + +/****************************************************************************** + * Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_EXTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_RANDOMIZED_API + * + * Description: If this option is set, mldsa-native will be built without the + * randomized API functions (crypto_sign_keypair, + * crypto_sign, crypto_sign_signature, and + * crypto_sign_signature_extmu). + * This allows users to build mldsa-native without providing a + * randombytes() implementation if they only need the + * internal deterministic API + * (crypto_sign_keypair_internal, crypto_sign_signature_internal). + * + * NOTE: This option is incompatible with MLD_CONFIG_KEYGEN_PCT + * as the current PCT implementation requires + * crypto_sign_signature(). + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_RANDOMIZED_API */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_SUPERCOP + * + * Description: By default, mldsa_native.h exposes the mldsa-native API in the + * SUPERCOP naming convention (crypto_sign_xxx). If you don't need + * this, set MLD_CONFIG_NO_SUPERCOP. + * + * NOTE: You must set this for a multi-level build as the SUPERCOP + * naming does not disambiguate between the parameter sets. + * + *****************************************************************************/ +#define MLD_CONFIG_NO_SUPERCOP + +/****************************************************************************** + * Name: MLD_CONFIG_CONSTANTS_ONLY + * + * Description: If you only need the size constants (MLDSA_PUBLICKEYBYTES, etc.) + * but no function declarations, set MLD_CONFIG_CONSTANTS_ONLY. + * + * This only affects the public header mldsa_native.h, not + * the implementation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONSTANTS_ONLY */ + +/****************************************************************************** + * + * Build-only configuration options + * + * The remaining configurations are build-options only. + * They do not affect the API described in mldsa_native.h. + * + *****************************************************************************/ + +#if defined(MLD_BUILD_INTERNAL) +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_WITH_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, all MLD_CONFIG_PARAMETER_SET-independent + * code will be included in the build, including code needed only + * for other parameter sets. + * + * Example: TODO: add example + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_WITH_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_NO_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, no MLD_CONFIG_PARAMETER_SET-independent code + * will be included in the build. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * + * Description: This is only relevant for single compilation unit (SCU) + * builds of mldsa-native. In this case, it determines whether + * directives defined in parameter-set-independent headers should + * be #undef'ined or not at the of the SCU file. This is needed + * in multilevel builds. + * + * See examples/multilevel_build_native for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * + * Description: Determines whether an native arithmetic backend should be used. + * + * The arithmetic backend covers performance critical functions + * such as the number-theoretic transform (NTT). + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the arithmetic backend to be use is + * determined by MLD_CONFIG_ARITH_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_ARITH_BACKEND_FILE + * + * Description: The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * + * Description: Determines whether an native FIPS202 backend should be used. + * + * The FIPS202 backend covers 1x/2x/4x-fold Keccak-f1600, which is + * the performance bottleneck of SHA3 and SHAKE. + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the FIPS202 backend to be use is + * determined by MLD_CONFIG_FIPS202_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_BACKEND_FILE + * + * Description: The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202X4_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202-X4 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202x4.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ZEROIZE + * + * Description: In compliance with @[FIPS204, Section 3.6.3], mldsa-native, + * zeroizes intermediate stack buffers before returning from + * function calls. + * + * Set this option and define `mld_zeroize` if you want to + * use a custom method to zeroize intermediate stack buffers. + * The default implementation uses SecureZeroMemory on Windows + * and a memset + compiler barrier otherwise. If neither of those + * is available on the target platform, compilation will fail, + * and you will need to use MLD_CONFIG_CUSTOM_ZEROIZE to provide + * a custom implementation of `mld_zeroize()`. + * + * WARNING: + * The explicit stack zeroization conducted by mldsa-native + * reduces the likelihood of data leaking on the stack, but + * does not eliminate it! The C standard makes no guarantee about + * where a compiler allocates structures and whether/where it makes + * copies of them. Also, in addition to entire structures, there + * may also be potentially exploitable leakage of individual values + * on the stack. + * + * If you need bullet-proof zeroization of the stack, you need to + * consider additional measures instead of what this feature + * provides. In this case, you can set mld_zeroize to a + * no-op. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void mld_zeroize(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * Description: mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to provided by the + * consumer. + * + * If this option is not set, mldsa-native expects a function + * int randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mld_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_RANDOMBYTES + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) + { + ... your implementation ... + return 0; + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + * + * Description: mldsa-native backends may rely on specific hardware features. + * Those backends will only be included in an mldsa-native build + * if support for the respective features is enabled at + * compile-time. However, when building for a heteroneous set + * of CPUs to run the resulting binary/library on, feature + * detection at _runtime_ is needed to decided whether a backend + * can be used or not. + * + * Set this option and define `mld_sys_check_capability` if you + * want to use a custom method to dispatch between implementations. + * + * Return value 1 indicates that a capability is supported. + * Return value 0 indicates that a capability is not supported. + * + * If this option is not set, mldsa-native uses compile-time + * feature detection only to decide which backend to use. + * + * If you compile mldsa-native on a system with different + * capabilities than the system that the resulting binary/library + * will be run on, you must use this option. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) + { + ... your implementation ... + } +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ALLOC_FREE [EXPERIMENTAL] + * + * Description: Set this option and define `MLD_CUSTOM_ALLOC` and + * `MLD_CUSTOM_FREE` if you want to use custom allocation for + * large local structures or buffers. + * + * By default, all buffers/structures are allocated on the stack. + * If this option is set, most of them will be allocated via + * MLD_CUSTOM_ALLOC. + * + * Parameters to MLD_CUSTOM_ALLOC: + * - T* v: Target pointer to declare. + * - T: Type of structure to be allocated + * - N: Number of elements to be allocated. + * + * Parameters to MLD_CUSTOM_FREE: + * - T* v: Target pointer to free. May be NULL. + * - T: Type of structure to be freed. + * - N: Number of elements to be freed. + * + * WARNING: This option is experimental! + * Its scope, configuration and function/macro signatures may + * change at any time. We expect a stable API for v2. + * + * NOTE: Even if this option is set, some allocations further down + * the call stack will still be made from the stack. Those will + * likely be added to the scope of this option in the future. + * + * NOTE: MLD_CUSTOM_ALLOC need not guarantee a successful + * allocation nor include error handling. Upon failure, the + * target pointer should simply be set to NULL. The calling + * code will handle this case and invoke MLD_CUSTOM_FREE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ALLOC_FREE + #if !defined(__ASSEMBLER__) + #include + #define MLD_CUSTOM_ALLOC(v, T, N) \ + T* (v) = (T *)aligned_alloc(MLD_DEFAULT_ALIGN, \ + MLD_ALIGN_UP(sizeof(T) * (N))) + #define MLD_CUSTOM_FREE(v, T, N) free(v) + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMCPY + * + * Description: Set this option and define `mld_memcpy` if you want to + * use a custom method to copy memory instead of the standard + * library memcpy function. + * + * The custom implementation must have the same signature and + * behavior as the standard memcpy function: + * void *mld_memcpy(void *dest, const void *src, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMCPY + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMSET + * + * Description: Set this option and define `mld_memset` if you want to + * use a custom method to set memory instead of the standard + * library memset function. + * + * The custom implementation must have the same signature and + * behavior as the standard memset function: + * void *mld_memset(void *s, int c, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMSET + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memset(void *s, int c, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_INTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of internal API. + * + * The primary use case for this option are single-CU builds, + * in which case this option can be set to `static`. + * + *****************************************************************************/ +#define MLD_CONFIG_INTERNAL_API_QUALIFIER static + +/****************************************************************************** + * Name: MLD_CONFIG_CT_TESTING_ENABLED + * + * Description: If set, mldsa-native annotates data as secret / public using + * valgrind's annotations VALGRIND_MAKE_MEM_UNDEFINED and + * VALGRIND_MAKE_MEM_DEFINED, enabling various checks for secret- + * dependent control flow of variable time execution (depending + * on the exact version of valgrind installed). + * + *****************************************************************************/ +/* #define MLD_CONFIG_CT_TESTING_ENABLED */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * and MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT + * + * Description: Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, crypto_sign_keypair_internal and + * crypto_sign_keypair will return a non-zero error code if the + * PCT failed. + * + * NOTE: This feature will drastically lower the performance of + * key generation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * Description: If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "src/src.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Description: Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * NOTE: Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + * + *****************************************************************************/ +/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER + * + * Description: Set this to add a context parameter that is provided to public + * API functions and is then available in custom callbacks. + * + * The type of the context parameter is configured via + * MLD_CONFIG_CONTEXT_PARAMETER_TYPE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER_TYPE + * + * Description: Set this to define the type for the context parameter used by + * MLD_CONFIG_CONTEXT_PARAMETER. + * + * This is only relevant if MLD_CONFIG_CONTEXT_PARAMETER is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER_TYPE void* */ + +/****************************************************************************** + * Name: MLD_CONFIG_REDUCE_RAM [EXPERIMENTAL] + * + * Description: Set this to reduce RAM usage. + * This trades memory for performance. + * + * For expected memory usage, see the MLD_TOTAL_ALLOC_* constants + * defined in mldsa_native.h. + * + * This option is useful for embedded systems with tight RAM + * constraints but relaxed performance requirements. + * + * WARNING: This option is experimental! + * CBMC proofs do not currently cover this configuration option. + * Its scope and configuration may change at any time. + * + *****************************************************************************/ +/* #define MLD_CONFIG_REDUCE_RAM */ + +/************************* Config internals ********************************/ + +#endif /* MLD_BUILD_INTERNAL */ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace is + * + * PQCP_MLDSA_NATIVE_MLDSA_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_ + */ + +#if MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65 +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87 +#endif + +#endif /* !MLD_CONFIG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/cbmc.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/cbmc.h new file mode 100644 index 0000000000..8ed1ecb06b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/cbmc.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_CBMC_H +#define MLD_CBMC_H +/*************************************************** + * Basic replacements for __CPROVER_XXX contracts + ***************************************************/ +#ifndef CBMC + +#define __contract__(x) +#define __loop__(x) +#define cassert(x) + +#else /* !CBMC */ + +#include + +#define __contract__(x) x +#define __loop__(x) x + +/* https://diffblue.github.io/cbmc/contracts-assigns.html */ +#define assigns(...) __CPROVER_assigns(__VA_ARGS__) + +/* https://diffblue.github.io/cbmc/contracts-requires-ensures.html */ +#define requires(...) __CPROVER_requires(__VA_ARGS__) +#define ensures(...) __CPROVER_ensures(__VA_ARGS__) +/* https://diffblue.github.io/cbmc/contracts-loops.html */ +#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__) +#define decreases(...) __CPROVER_decreases(__VA_ARGS__) +/* cassert to avoid confusion with in-built assert */ +#define cassert(x) __CPROVER_assert(x, "cbmc assertion failed") +#define assume(...) __CPROVER_assume(__VA_ARGS__) + +/*************************************************** + * Macros for "expression" forms that may appear + * _inside_ top-level contracts. + ***************************************************/ + +/* + * function return value - useful inside ensures + * https://diffblue.github.io/cbmc/contracts-functions.html + */ +#define return_value (__CPROVER_return_value) + +/* + * assigns l-value targets + * https://diffblue.github.io/cbmc/contracts-assigns.html + */ +#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__) +#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__) +#define same_object(...) __CPROVER_same_object(__VA_ARGS__) + +/* + * Pointer-related predicates + * https://diffblue.github.io/cbmc/contracts-memory-predicates.html + */ +#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__) +#define readable(...) __CPROVER_r_ok(__VA_ARGS__) +#define writeable(...) __CPROVER_w_ok(__VA_ARGS__) + +/* Maximum supported buffer size + * + * Larger buffers may be supported, but due to internal modeling constraints + * in CBMC, the proofs of memory- and type-safety won't be able to run. + * + * If you find yourself in need for a buffer size larger than this, + * please contact the maintainers, so we can prioritize work to relax + * this somewhat artificial bound. + */ +#define MLD_MAX_BUFFER_SIZE (SIZE_MAX >> 12) + + +/* + * History variables + * https://diffblue.github.io/cbmc/contracts-history-variables.html + */ +#define old(...) __CPROVER_old(__VA_ARGS__) +#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__) + +/* + * Quantifiers + * Note that the range on qvar is _exclusive_ between qvar_lb .. qvar_ub + * https://diffblue.github.io/cbmc/contracts-quantifiers.html + */ + +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define forall(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> (predicate) \ + } + +#define exists(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_exists \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) && (predicate) \ + } +/* clang-format on */ + +/*************************************************** + * Convenience macros for common contract patterns + ***************************************************/ +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define CBMC_CONCAT_(left, right) left##right +#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right) + +#define array_bound_core(qvar, qvar_lb, qvar_ub, array_var, \ + value_lb, value_ub) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + (((int)(value_lb) <= ((array_var)[(qvar)])) && \ + (((array_var)[(qvar)]) < (int)(value_ub))) \ + } + +#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \ + array_bound_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (qvar_lb), \ + (qvar_ub), (array_var), (value_lb), (value_ub)) + +#define array_unchanged_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (int32_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged(array_var, N) \ + array_unchanged_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) + +#define array_unchanged_u64_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (uint64_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged_u64(array_var, N) \ + array_unchanged_u64_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) +/* clang-format on */ + +/* Wrapper around array_bound operating on absolute values. + * + * The absolute value bound `k` is exclusive. + * + * Note that since the lower bound in array_bound is inclusive, we have to + * raise it by 1 here. + */ +#define array_abs_bound(arr, lb, ub, k) \ + array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k)) + +#endif /* CBMC */ + +#endif /* !MLD_CBMC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/common.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/common.h new file mode 100644 index 0000000000..4a5bc8109d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/common.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_COMMON_H +#define MLD_COMMON_H + +#define MLD_BUILD_INTERNAL + +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#include "params.h" +#include "sys.h" + +/* Internal and public API have external linkage by default, but + * this can be overwritten by the user, e.g. for single-CU builds. */ +#if !defined(MLD_CONFIG_INTERNAL_API_QUALIFIER) +#define MLD_INTERNAL_API +#else +#define MLD_INTERNAL_API MLD_CONFIG_INTERNAL_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_EXTERNAL_API +#else +#define MLD_EXTERNAL_API MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#if defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) || \ + defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) +#define MLD_MULTILEVEL_BUILD +#endif + +#define MLD_CONCAT_(x1, x2) x1##x2 +#define MLD_CONCAT(x1, x2) MLD_CONCAT_(x1, x2) + +#if defined(MLD_MULTILEVEL_BUILD) +#define MLD_ADD_PARAM_SET(s) MLD_CONCAT(s, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_ADD_PARAM_SET(s) s +#endif + +#define MLD_NAMESPACE_PREFIX MLD_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, _) +#define MLD_NAMESPACE_PREFIX_KL \ + MLD_CONCAT(MLD_ADD_PARAM_SET(MLD_CONFIG_NAMESPACE_PREFIX), _) + +/* Functions are prefixed by MLD_CONFIG_NAMESPACE_PREFIX. + * + * If multiple parameter sets are used, functions depending on the parameter + * set are additionally prefixed with 44/65/87. See mldsa_native_config.h. + * + * Example: If MLD_CONFIG_NAMESPACE_PREFIX is PQCP_MLDSA_NATIVE, then + * MLD_NAMESPACE_KL(keypair) becomes PQCP_MLDSA_NATIVE44_keypair/ + * PQCP_MLDSA_NATIVE65_keypair/PQCP_MLDSA_NATIVE87_keypair. + */ +#define MLD_NAMESPACE(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX, s) +#define MLD_NAMESPACE_KL(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX_KL, s) + +/* On Apple platforms, we need to emit leading underscore + * in front of assembly symbols. We thus introducee a separate + * namespace wrapper for ASM symbols. */ +#if !defined(__APPLE__) +#define MLD_ASM_NAMESPACE(sym) MLD_NAMESPACE(sym) +#else +#define MLD_ASM_NAMESPACE(sym) MLD_CONCAT(_, MLD_NAMESPACE(sym)) +#endif + +/* + * On X86_64 if control-flow protections (CET) are enabled (through + * -fcf-protection=), we add an endbr64 instruction at every global function + * label. See sys.h for more details + */ +#if defined(MLD_SYS_X86_64) +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : MLD_CET_ENDBR +#else +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : +#endif + +/* We aim to simplify the user's life by supporting builds where + * all source files are included, even those that are not needed. + * Those files are appropriately guarded and will be empty when unneeded. + * The following is to avoid compilers complaining about this. */ +#define MLD_EMPTY_CU(s) extern int MLD_NAMESPACE_KL(empty_cu_##s); + +/* MLD_CONFIG_NO_ASM takes precedence over MLD_USE_NATIVE_XXX */ +#if defined(MLD_CONFIG_NO_ASM) +#undef MLD_CONFIG_USE_NATIVE_BACKEND_ARITH +#undef MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, but MLD_CONFIG_ARITH_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, but MLD_CONFIG_FIPS202_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_NO_RANDOMIZED_API) && defined(MLD_CONFIG_KEYGEN_PCT) +#error Bad configuration: MLD_CONFIG_NO_RANDOMIZED_API is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires crypto_sign_signature() +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#include MLD_CONFIG_ARITH_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#include MLD_CONFIG_FIPS202_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "fips202/native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#define MLD_FIPS202_HEADER_FILE "fips202/fips202.h" +#else +#define MLD_FIPS202_HEADER_FILE MLD_CONFIG_FIPS202_CUSTOM_HEADER +#endif + +#if !defined(MLD_CONFIG_FIPS202X4_CUSTOM_HEADER) +#define MLD_FIPS202X4_HEADER_FILE "fips202/fips202x4.h" +#else +#define MLD_FIPS202X4_HEADER_FILE MLD_CONFIG_FIPS202X4_CUSTOM_HEADER +#endif + +/* Standard library function replacements */ +#if !defined(__ASSEMBLER__) +#if !defined(MLD_CONFIG_CUSTOM_MEMCPY) +#include +#define mld_memcpy memcpy +#endif + +#if !defined(MLD_CONFIG_CUSTOM_MEMSET) +#include +#define mld_memset memset +#endif + +/* Allocation macros for large local structures + * + * MLD_ALLOC(v, T, N) declares T *v and attempts to point it to an T[N] + * MLD_FREE(v, T, N) zeroizes and frees the allocation + * + * Default implementation uses stack allocation. + * Can be overridden by setting the config option MLD_CONFIG_CUSTOM_ALLOC_FREE + * and defining MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE. + */ +#if defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) != \ + (defined(MLD_CUSTOM_ALLOC) && defined(MLD_CUSTOM_FREE)) +#error Bad configuration: MLD_CONFIG_CUSTOM_ALLOC_FREE must be set together with MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE +#endif + +/* + * If the integration wants to provide a context parameter for use in + * platform-specific hooks, then it should define this parameter. + * + * The MLD_CONTEXT_PARAMETERS_n macros are intended to be used with macros + * defining the function names and expand to either pass or discard the context + * argument as required by the current build. If there is no context parameter + * requested then these are removed from the prototypes and from all calls. + */ +#ifdef MLD_CONFIG_CONTEXT_PARAMETER +#define MLD_CONTEXT_PARAMETERS_0(context) (context) +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0, context) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1, context) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) \ + (arg0, arg1, arg2, context) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3, context) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4, context) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, context) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, context) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, context) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, context) +#else /* MLD_CONFIG_CONTEXT_PARAMETER */ +#define MLD_CONTEXT_PARAMETERS_0(context) () +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) (arg0, arg1, arg2) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) +#endif /* !MLD_CONFIG_CONTEXT_PARAMETER */ + +#if defined(MLD_CONFIG_CONTEXT_PARAMETER_TYPE) != \ + defined(MLD_CONFIG_CONTEXT_PARAMETER) +#error MLD_CONFIG_CONTEXT_PARAMETER_TYPE must be defined if and only if MLD_CONFIG_CONTEXT_PARAMETER is defined +#endif + +#if !defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) +/* Default: stack allocation */ + +#define MLD_ALLOC(v, T, N, context) \ + MLD_ALIGN T mld_alloc_##v[N]; \ + T *v = mld_alloc_##v + +/* TODO: This leads to a circular dependency between common and ct.h + * It just works out before we're at the end of the file, but it's still + * prone to issues in the future. */ +#include "ct.h" +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + mld_zeroize(mld_alloc_##v, sizeof(mld_alloc_##v)); \ + (v) = NULL; \ + } while (0) + +#else /* !MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* Custom allocation */ + +/* + * The indirection here is necessary to use MLD_CONTEXT_PARAMETERS_3 here. + */ +#define MLD_APPLY(f, args) f args + +#define MLD_ALLOC(v, T, N, context) \ + MLD_APPLY(MLD_CUSTOM_ALLOC, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)) + +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + if (v != NULL) \ + { \ + mld_zeroize(v, sizeof(T) * (N)); \ + MLD_APPLY(MLD_CUSTOM_FREE, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)); \ + v = NULL; \ + } \ + } while (0) + +#endif /* MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* + * We are facing severe CBMC performance issues when using unions. + * As a temporary workaround, we use unions only when MLD_CONFIG_REDUCE_RAM is + * set. + * TODO: Remove the workaround once + * https://github.com/diffblue/cbmc/issues/8813 + * is resolved + */ +#if defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_UNION_OR_STRUCT union +#else +#define MLD_UNION_OR_STRUCT struct +#endif + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_COMMON_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/ct.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/ct.c new file mode 100644 index 0000000000..010b1a52a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/ct.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include "ct.h" + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +/* + * Masking value used in constant-time functions from + * ct.h to block the compiler's range analysis and + * thereby reduce the risk of compiler-introduced branches. + */ +volatile uint64_t mld_ct_opt_blocker_u64 = 0; + +#else /* !MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(ct) + +#endif /* !(!MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/ct.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/ct.h new file mode 100644 index 0000000000..c307456468 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/ct.h @@ -0,0 +1,366 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [libmceliece] + * libmceliece implementation of Classic McEliece + * Bernstein, Chou + * https://lib.mceliece.org/ + * + * - [optblocker] + * PQC forum post on opt-blockers using volatile globals + * Daniel J. Bernstein + * https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ + */ + +#ifndef MLD_CT_H +#define MLD_CT_H + +#include +#include "cbmc.h" +#include "common.h" + +/* Constant-time comparisons and conditional operations + + We reduce the risk for compilation into variable-time code + through the use of 'value barriers'. + + Functionally, a value barrier is a no-op. To the compiler, however, + it constitutes an arbitrary modification of its input, and therefore + harden's value propagation and range analysis. + + We consider two approaches to implement a value barrier: + - An empty inline asm block which marks the target value as clobbered. + - XOR'ing with the value of a volatile global that's set to 0; + see @[optblocker] for a discussion of this idea, and + @[libmceliece, inttypes/crypto_intN.h] for an implementation. + + The first approach is cheap because it only prevents the compiler + from reasoning about the value of the variable past the barrier, + but does not directly generate additional instructions. + + The second approach generates redundant loads and XOR operations + and therefore comes at a higher runtime cost. However, it appears + more robust towards optimization, as compilers should never drop + a volatile load. + + We use the empty-ASM value barrier for GCC and clang, and fall + back to the global volatile barrier otherwise. + + The global value barrier can be forced by setting + MLD_CONFIG_NO_ASM_VALUE_BARRIER. + +*/ + +#if defined(MLD_HAVE_INLINE_ASM) && !defined(MLD_CONFIG_NO_ASM_VALUE_BARRIER) +#define MLD_USE_ASM_VALUE_BARRIER +#endif + + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) +/* + * Declaration of global volatile that the global value barrier + * is loading from and masking with. + */ +#define mld_ct_opt_blocker_u64 MLD_NAMESPACE(ct_opt_blocker_u64) +extern volatile uint64_t mld_ct_opt_blocker_u64; + + +/* Helper functions for obtaining global masks of various sizes */ + +/* This contract is not proved but treated as an axiom. + * + * Its validity relies on the assumption that the global opt-blocker + * constant mld_ct_opt_blocker_u64 is not modified. + */ +static MLD_INLINE uint64_t mld_ct_get_optblocker_u64(void) +__contract__(ensures(return_value == 0)) { return mld_ct_opt_blocker_u64; } + +static MLD_INLINE int64_t mld_ct_get_optblocker_i64(void) +__contract__(ensures(return_value == 0)) { return (int64_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint32_t mld_ct_get_optblocker_u32(void) +__contract__(ensures(return_value == 0)) { return (uint32_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint8_t mld_ct_get_optblocker_u8(void) +__contract__(ensures(return_value == 0)) { return (uint8_t)mld_ct_get_optblocker_u64(); } + +/* Opt-blocker based implementation of value barriers */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_i64()); } + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u32()); } + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u8()); } + + +#else /* !MLD_USE_ASM_VALUE_BARRIER */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} +#endif /* MLD_USE_ASM_VALUE_BARRIER */ + +#ifdef CBMC +#pragma CPROVER check push +#pragma CPROVER check disable "conversion" +#endif + +/************************************************* + * Name: mld_cast_uint32_to_int32 + * + * Description: Cast uint32 value to int32 + * + * Returns: For uint32_t x, the unique y in int32_t + * so that x == y mod 2^32. + * + * Concretely: + * - x < 2^31: returns x + * - x >= 2^31: returns x - 2^31 + * + **************************************************/ +static MLD_ALWAYS_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x) +{ + /* + * PORTABILITY: This relies on uint32_t -> int32_t + * being implemented as the inverse of int32_t -> uint32_t, + * which is implementation-defined (C99 6.3.1.3 (3)) + * CBMC (correctly) fails to prove this conversion is OK, + * so we have to suppress that check here + */ + return (int32_t)x; +} + +#ifdef CBMC +#pragma CPROVER check pop +#endif + + +/************************************************* + * Name: mld_cast_int64_to_uint32 + * + * Description: Cast int64 value to uint32 as per C standard. + * + * Returns: For int64_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int64_to_uint32(int64_t x) +{ + return (uint32_t)(x & (int64_t)UINT32_MAX); +} + +/************************************************* + * Name: mld_cast_int32_to_uint32 + * + * Description: Cast int32 value to uint32 as per C standard. + * + * Returns: For int32_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int32_to_uint32(int32_t x) +{ + return mld_cast_int64_to_uint32((int64_t)x); +} + +/************************************************* + * Name: mld_ct_sel_int32 + * + * Description: Functionally equivalent to cond ? a : b, + * but implemented with guards against + * compiler-introduced branches. + * + * Arguments: int32_t a: First alternative + * int32_t b: Second alternative + * uint32_t cond: Condition variable. + * + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_sel_int32(int32_t a, int32_t b, uint32_t cond) +__contract__( + requires(cond == 0x0 || cond == 0xFFFFFFFF) + ensures(return_value == (cond ? a : b)) +) +{ + uint32_t au = mld_cast_int32_to_uint32(a); + uint32_t bu = mld_cast_int32_to_uint32(b); + uint32_t res = bu ^ (mld_value_barrier_u32(cond) & (au ^ bu)); + return mld_cast_uint32_to_int32(res); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u32 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_nonzero_u32(uint32_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFFFFFFFF))) +{ + int64_t tmp = mld_value_barrier_i64(-((int64_t)x)); + tmp >>= 32; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u8 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint8_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint8_t mld_ct_cmask_nonzero_u8(uint8_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFF))) +{ + uint32_t mask = mld_ct_cmask_nonzero_u32((uint32_t)x); + return (uint8_t)(mask & 0xFF); +} + +/************************************************* + * Name: mld_ct_cmask_neg_i32 + * + * Description: Return 0 if input is non-negative, and -1 otherwise. + * + * Arguments: int32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_neg_i32(int32_t x) +__contract__( + ensures(return_value == ((x < 0) ? 0xFFFFFFFF : 0)) +) +{ + int64_t tmp = mld_value_barrier_i64((int64_t)x); + tmp >>= 31; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_abs_i32 + * + * Description: Return -x if x<0, x otherwise + * + * Arguments: int32_t x: Input value + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_abs_i32(int32_t x) +__contract__( + requires(x >= -INT32_MAX) + ensures(return_value == ((x < 0) ? -x : x)) +) +{ + return mld_ct_sel_int32(-x, x, mld_ct_cmask_neg_i32(x)); +} + +/************************************************* + * Name: mld_ct_memcmp + * + * Description: Compare two arrays for equality in constant time. + * + * Arguments: const uint8_t *a: pointer to first byte array + * const uint8_t *b: pointer to second byte array + * size_t len: length of the byte arrays, upper-bounded + * to UINT16_MAX to control proof complexity + * only. + * + * Returns 0 if the byte arrays are equal, 0xFF otherwise. + **************************************************/ +static MLD_INLINE uint8_t mld_ct_memcmp(const uint8_t *a, const uint8_t *b, + const size_t len) +__contract__( + requires(len <= UINT16_MAX) + requires(memory_no_alias(a, len)) + requires(memory_no_alias(b, len)) + ensures((return_value == 0) || (return_value == 0xFF)) + ensures((return_value == 0) == forall(i, 0, len, (a[i] == b[i])))) +{ + uint8_t r = 0, s = 0; + unsigned i; + + for (i = 0; i < len; i++) + __loop__( + invariant(i <= len) + invariant((r == 0) == (forall(k, 0, i, (a[k] == b[k]))))) + { + r |= a[i] ^ b[i]; + /* s is useless, but prevents the loop from being aborted once r=0xff. */ + s ^= a[i] ^ b[i]; + } + + /* + * - Convert r into a mask; this may not be necessary, but is an additional + * safeguard + * towards leaking information about a and b. + * - XOR twice with s, separated by a value barrier, to prevent the compile + * from dropping the s computation in the loop. + */ + return (mld_value_barrier_u8(mld_ct_cmask_nonzero_u8(r) ^ s) ^ s); +} + +/************************************************* + * Name: mld_zeroize + * + * Description: Force-zeroize a buffer. + * @[FIPS204, Section 3.6.3] Destruction of intermediate + * values. + * + * Arguments: void *ptr: pointer to buffer to be zeroed + * size_t len: Amount of bytes to be zeroed + **************************************************/ +#if !defined(MLD_CONFIG_CUSTOM_ZEROIZE) +#if defined(MLD_SYS_WINDOWS) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) { SecureZeroMemory(ptr, len); } +#elif defined(MLD_HAVE_INLINE_ASM) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) +{ + memset(ptr, 0, len); + /* This follows OpenSSL and seems sufficient to prevent the compiler + * from optimizing away the memset. + * + * If there was a reliable way to detect availability of memset_s(), + * that would be preferred. */ + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +} +#else /* !MLD_SYS_WINDOWS && MLD_HAVE_INLINE_ASM */ +#error No plausibly-secure implementation of mld_zeroize available. Please provide your own using MLD_CONFIG_CUSTOM_ZEROIZE. +#endif /* !MLD_SYS_WINDOWS && !MLD_HAVE_INLINE_ASM */ +#endif /* !MLD_CONFIG_CUSTOM_ZEROIZE */ + +#endif /* !MLD_CT_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/debug.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/debug.c new file mode 100644 index 0000000000..a55d51e8b1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/debug.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* NOTE: You can remove this file unless you compile with MLDSA_DEBUG. */ + +#include "common.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#if defined(MLDSA_DEBUG) + +#include +#include +#include +#include "debug.h" + +#define MLD_DEBUG_ERROR_HEADER "[ERROR:%s:%04d] " + +void mld_debug_check_assert(const char *file, int line, const int val) +{ + if (val == 0) + { + fprintf(stderr, MLD_DEBUG_ERROR_HEADER "Assertion failed (value %d)\n", + file, line, val); + exit(1); + } +} + +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive) +{ + int err = 0; + unsigned i; + for (i = 0; i < len; i++) + { + int32_t val = ptr[i]; + if (!(val > lower_bound_exclusive && val < upper_bound_exclusive)) + { + fprintf(stderr, + MLD_DEBUG_ERROR_HEADER + "Bounds assertion failed: Index %u, value %d out of bounds " + "(%" PRId64 ",%" PRId64 ")\n", + file, line, i, (int)val, lower_bound_exclusive, + upper_bound_exclusive); + err = 1; + } + } + + if (err == 1) + { + exit(1); + } +} + +#else /* MLDSA_DEBUG */ + +MLD_EMPTY_CU(debug) + +#endif /* !MLDSA_DEBUG */ + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(debug) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_DEBUG_ERROR_HEADER diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/debug.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/debug.h new file mode 100644 index 0000000000..af187bb9de --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/debug.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_DEBUG_H +#define MLD_DEBUG_H +#include "common.h" + +#if defined(MLDSA_DEBUG) +#include + +/************************************************* + * Name: mld_assert + * + * Description: Check debug assertion + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - val: Value asserted to be non-zero + **************************************************/ +#define mld_debug_check_assert MLD_NAMESPACE(mldsa_debug_assert) +void mld_debug_check_assert(const char *file, int line, const int val); + +/************************************************* + * Name: mld_debug_check_bounds + * + * Description: Check whether values in an array of int32_t + * are within specified bounds. + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - ptr: Base of array to be checked + * - len: Number of int32_t in ptr + * - lower_bound_exclusive: Exclusive lower bound + * - upper_bound_exclusive: Exclusive upper bound + **************************************************/ +#define mld_debug_check_bounds MLD_NAMESPACE(mldsa_debug_check_bounds) +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive); + +/* Check assertion, calling exit() upon failure + * + * val: Value that's asserted to be non-zero + */ +#define mld_assert(val) mld_debug_check_assert(__FILE__, __LINE__, (val)) + +/* Check bounds in array of int32_t's + * ptr: Base of int32_t array; will be explicitly cast to int32_t*, + * so you may pass a byte-compatible type such as mld_poly or mld_polyvec. + * len: Number of int32_t in array + * value_lb: Inclusive lower value bound + * value_ub: Exclusive upper value bound */ +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + mld_debug_check_bounds(__FILE__, __LINE__, (const int32_t *)(ptr), (len), \ + ((int64_t)(value_lb)) - 1, (value_ub)) + +/* Check absolute bounds in array of int32_t's + * ptr: Base of array, expression of type int32_t* + * len: Number of int32_t in array + * value_abs_bd: Exclusive absolute upper bound */ +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + mld_assert_bound((ptr), (len), (-((int64_t)(value_abs_bd)) + 1), \ + (value_abs_bd)) + +/* Version of bounds assertions for 2-dimensional arrays */ +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + mld_assert_bound((ptr), ((len0) * (len1)), (value_lb), (value_ub)) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + mld_assert_abs_bound((ptr), ((len0) * (len1)), (value_abs_bd)) + +/* When running CBMC, convert debug assertions into proof obligations */ +#elif defined(CBMC) +#include "cbmc.h" + +#define mld_assert(val) cassert(val) + +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + cassert(array_bound(((int32_t *)(ptr)), 0, (len), (value_lb), (value_ub))) + +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + cassert(array_abs_bound(((int32_t *)(ptr)), 0, (len), (value_abs_bd))) + +/* Because of https://github.com/diffblue/cbmc/issues/8570, we can't + * just use a single flattened array_bound(...) here. */ +#define mld_assert_bound_2d(ptr, M, N, value_lb, value_ub) \ + cassert(forall(kN, 0, (M), \ + array_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_lb), (value_ub)))) + +#define mld_assert_abs_bound_2d(ptr, M, N, value_abs_bd) \ + cassert(forall(kN, 0, (M), \ + array_abs_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_abs_bd)))) + +#else /* !MLDSA_DEBUG && CBMC */ + +#define mld_assert(val) \ + do \ + { \ + } while (0) +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + do \ + { \ + } while (0) +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + do \ + { \ + } while (0) + +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + do \ + { \ + } while (0) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + do \ + { \ + } while (0) + + +#endif /* !MLDSA_DEBUG && !CBMC */ +#endif /* !MLD_DEBUG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/fips202.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/fips202.c new file mode 100644 index 0000000000..1112de061c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/fips202.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "../common.h" +#include "../ct.h" +#include "fips202.h" +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +/************************************************* + * Name: keccak_init + * + * Description: Initializes the Keccak state. + * + * Arguments: - uint64_t *s: pointer to Keccak state + **************************************************/ +static void keccak_init(uint64_t s[MLD_KECCAK_LANES]) +__contract__( + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + mld_memset(s, 0, sizeof(uint64_t) * MLD_KECCAK_LANES); +} + +/************************************************* + * Name: keccak_absorb + * + * Description: Absorb step of Keccak; incremental. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_absorb(uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r, + const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(pos <= r) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(in, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + ensures(return_value < r)) +{ + while (inlen >= r - pos) + __loop__( + assigns(pos, in, inlen, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + invariant(inlen <= loop_entry(inlen)) + invariant(pos <= r) + invariant(in == loop_entry(in) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600_xor_bytes(s, in, pos, r - pos); + inlen -= r - pos; + in += r - pos; + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: At this point, inlen < r, so the truncation to unsigned is safe. */ + mld_keccakf1600_xor_bytes(s, in, pos, (unsigned)inlen); + + /* Safety: At this point, inlen < r and pos <= r so the truncation to unsigned + * is safe. */ + return (unsigned)(pos + inlen); +} + +/************************************************* + * Name: keccak_finalize + * + * Description: Finalize absorb step. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - uint8_t p: domain separation byte + **************************************************/ +static void keccak_finalize(uint64_t s[MLD_KECCAK_LANES], unsigned int pos, + unsigned int r, uint8_t p) +__contract__( + requires(pos <= r && r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires((r / 8) >= 1) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + uint8_t b = 0x80; + mld_keccakf1600_xor_bytes(s, &p, pos, 1); + mld_keccakf1600_xor_bytes(s, &b, r - 1, 1); +} + +/************************************************* + * Name: keccak_squeeze + * + * Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes. + * Modifies the state. Can be called multiple times to keep + * squeezing, i.e., is incremental. + * + * Arguments: - uint8_t *out: pointer to output data + * - size_t outlen: number of bytes to be squeezed (written to out) + * - uint64_t *s: pointer to input/output Keccak state + * - unsigned int pos: number of bytes in current block already + *squeezed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_squeeze(uint8_t *out, size_t outlen, + uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r) +__contract__( + requires((r == SHAKE128_RATE && pos <= SHAKE128_RATE) || + (r == SHAKE256_RATE && pos <= SHAKE256_RATE) || + (r == SHA3_512_RATE && pos <= SHA3_512_RATE)) + requires(outlen <= 8 * r /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(out, outlen)) + ensures(return_value <= r)) +{ + unsigned int i; + size_t out_offset = 0; + + /* Reference: This code is re-factored from the reference implementation + * to facilitate proof with CBMC and to improve readability. + * + * Take a mutable copy of outlen to count down the number of bytes + * still to squeeze. The initial value of outlen is needed for the CBMC + * assigns() clauses. */ + size_t bytes_to_go = outlen; + + while (bytes_to_go > 0) + __loop__( + assigns(i, bytes_to_go, pos, out_offset, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES), memory_slice(out, outlen)) + invariant(bytes_to_go <= outlen) + invariant(out_offset == outlen - bytes_to_go) + invariant(pos <= r) + ) + { + if (pos == r) + { + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: If bytes_to_go < r - pos, truncation to unsigned is safe. */ + i = bytes_to_go < r - pos ? (unsigned)bytes_to_go : r - pos; + mld_keccakf1600_extract_bytes(s, out + out_offset, pos, i); + bytes_to_go -= i; + pos += i; + out_offset += i; + } + + return pos; +} + +void mld_shake128_init(mld_shake128ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE128_RATE, in, inlen); +} + +void mld_shake128_finalize(mld_shake128ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE128_RATE, 0x1F); + state->pos = SHAKE128_RATE; +} + +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE128_RATE); +} + +void mld_shake128_release(mld_shake128ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128ctx)); +} + +void mld_shake256_init(mld_shake256ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); +} + +void mld_shake256_finalize(mld_shake256ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); + state->pos = SHAKE256_RATE; +} + +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); +} + +void mld_shake256_release(mld_shake256ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256ctx)); +} + +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +{ + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, in, inlen); + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/fips202.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/fips202.h new file mode 100644 index 0000000000..9f0253cb88 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/fips202.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202_H +#define MLD_FIPS202_FIPS202_H + +#include +#include +#include "../cbmc.h" +#include "../common.h" + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 +#define SHA3_256_RATE 136 +#define SHA3_512_RATE 72 +#define MLD_KECCAK_LANES 25 +#define SHA3_256_HASHBYTES 32 +#define SHA3_512_HASHBYTES 64 + + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake128ctx; + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake256ctx; + +#define mld_shake128_init MLD_NAMESPACE(shake128_init) +/************************************************* + * Name: mld_shake128_init + * + * Description: Initializes state for use as SHAKE128 XOF + * + * Arguments: - mld_shake128ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake128_init(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos == 0) +); + +#define mld_shake128_absorb MLD_NAMESPACE(shake128_absorb) +/************************************************* + * Name: mld_shake128_absorb + * + * Description: Absorb step of the SHAKE128 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake128ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_finalize MLD_NAMESPACE(shake128_finalize) +/************************************************* + * Name: mld_shake128_finalize + * + * Description: Concludes the absorb phase of the SHAKE128 XOF. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_finalize(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_squeeze MLD_NAMESPACE(shake128_squeeze) +/************************************************* + * Name: mld_shake128_squeeze + * + * Description: Squeeze step of SHAKE128 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake128ctx *s: pointer to input/output state + **************************************************/ +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE128_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_release MLD_NAMESPACE(shake128_release) +/************************************************* + * Name: mld_shake128_release + * + * Description: Release and securely zero the SHAKE128 state. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_release(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) +); + +#define mld_shake256_init MLD_NAMESPACE(shake256_init) +/************************************************* + * Name: mld_shake256_init + * + * Description: Initializes state for use as SHAKE256 XOF + * + * Arguments: - mld_shake256ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake256_init(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos == 0) +); + +#define mld_shake256_absorb MLD_NAMESPACE(shake256_absorb) +/************************************************* + * Name: mld_shake256_absorb + * + * Description: Absorb step of the SHAKE256 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake256ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_finalize MLD_NAMESPACE(shake256_finalize) +/************************************************* + * Name: mld_shake256_finalize + * + * Description: Concludes the absorb phase of the SHAKE256 XOF. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_finalize(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_squeeze MLD_NAMESPACE(shake256_squeeze) +/************************************************* + * Name: mld_shake256_squeeze + * + * Description: Squeeze step of SHAKE256 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake256ctx *s: pointer to input/output state + **************************************************/ +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_release MLD_NAMESPACE(shake256_release) +/************************************************* + * Name: mld_shake256_release + * + * Description: Release and securely zero the SHAKE256 state. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_release(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) +); + +#define mld_shake256 MLD_NAMESPACE(shake256) +/************************************************* + * Name: mld_shake256 + * + * Description: SHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +); + +#endif /* !MLD_FIPS202_FIPS202_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/fips202x4.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/fips202x4.c new file mode 100644 index 0000000000..0fb5cd57c7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/fips202x4.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include "../common.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "../ct.h" +#include "fips202.h" +#include "fips202x4.h" +#include "keccakf1600.h" + +static void mld_keccak_absorb_once_x4(uint64_t *s, uint32_t r, + const uint8_t *in0, const uint8_t *in1, + const uint8_t *in2, const uint8_t *in3, + size_t inlen, uint8_t p) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))) +{ + while (inlen >= r) + __loop__( + assigns(inlen, in0, in1, in2, in3, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + invariant(inlen <= loop_entry(inlen)) + invariant(in0 == loop_entry(in0) + (loop_entry(inlen) - inlen)) + invariant(in1 == loop_entry(in1) + (loop_entry(inlen) - inlen)) + invariant(in2 == loop_entry(in2) + (loop_entry(inlen) - inlen)) + invariant(in3 == loop_entry(in3) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, r); + mld_keccakf1600x4_permute(s); + + in0 += r; + in1 += r; + in2 += r; + in3 += r; + inlen -= r; + } + + /* Safety: At this point, inlen < r, so the truncations to unsigned are safe + * below. */ + if (inlen > 0) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, (unsigned)inlen); + } + + if (inlen == r - 1) + { + p |= 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + } + else + { + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + p = 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, r - 1, 1); + } +} + +static void mld_keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1, + uint8_t *out2, uint8_t *out3, + size_t nblocks, uint64_t *s, uint32_t r) +__contract__( + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(out0, nblocks * r)) + requires(memory_no_alias(out1, nblocks * r)) + requires(memory_no_alias(out2, nblocks * r)) + requires(memory_no_alias(out3, nblocks * r)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(out0, nblocks * r)) + assigns(memory_slice(out1, nblocks * r)) + assigns(memory_slice(out2, nblocks * r)) + assigns(memory_slice(out3, nblocks * r))) +{ + while (nblocks > 0) + __loop__( + assigns(out0, out1, out2, out3, nblocks, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY), + memory_slice(out0, nblocks * r), + memory_slice(out1, nblocks * r), + memory_slice(out2, nblocks * r), + memory_slice(out3, nblocks * r)) + invariant(nblocks <= loop_entry(nblocks) && + out0 == loop_entry(out0) + r * (loop_entry(nblocks) - nblocks) && + out1 == loop_entry(out1) + r * (loop_entry(nblocks) - nblocks) && + out2 == loop_entry(out2) + r * (loop_entry(nblocks) - nblocks) && + out3 == loop_entry(out3) + r * (loop_entry(nblocks) - nblocks))) + { + mld_keccakf1600x4_permute(s); + mld_keccakf1600x4_extract_bytes(s, out0, out1, out2, out3, 0, r); + + out0 += r; + out1 += r; + out2 += r; + out3 += r; + nblocks--; + } +} + +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake128x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE128_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE128_RATE); +} + +void mld_shake128x4_init(mld_shake128x4ctx *state) { (void)state; } +void mld_shake128x4_release(mld_shake128x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128x4ctx)); +} + + +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake256x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE256_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE256_RATE); +} + +void mld_shake256x4_init(mld_shake256x4ctx *state) { (void)state; } +void mld_shake256x4_release(mld_shake256x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256x4ctx)); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/fips202x4.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/fips202x4.h new file mode 100644 index 0000000000..e7987207a6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/fips202x4.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202X4_H +#define MLD_FIPS202_FIPS202X4_H + +#include +#include + +#include "../cbmc.h" +#include "../common.h" + +#include "fips202.h" +#include "keccakf1600.h" + +/* Context for non-incremental API */ +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake128x4ctx; + +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake256x4ctx; + +#define mld_shake128x4_absorb_once MLD_NAMESPACE(shake128x4_absorb_once) +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_squeezeblocks MLD_NAMESPACE(shake128x4_squeezeblocks) +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE128_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE128_RATE), + memory_slice(out1, nblocks * SHAKE128_RATE), + memory_slice(out2, nblocks * SHAKE128_RATE), + memory_slice(out3, nblocks * SHAKE128_RATE), + memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_init MLD_NAMESPACE(shake128x4_init) +void mld_shake128x4_init(mld_shake128x4ctx *state); + +#define mld_shake128x4_release MLD_NAMESPACE(shake128x4_release) +void mld_shake128x4_release(mld_shake128x4ctx *state); + + +#define mld_shake256x4_absorb_once MLD_NAMESPACE(shake256x4_absorb_once) +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_squeezeblocks MLD_NAMESPACE(shake256x4_squeezeblocks) +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE256_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE256_RATE), + memory_slice(out1, nblocks * SHAKE256_RATE), + memory_slice(out2, nblocks * SHAKE256_RATE), + memory_slice(out3, nblocks * SHAKE256_RATE), + memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_init MLD_NAMESPACE(shake256x4_init) +void mld_shake256x4_init(mld_shake256x4ctx *state); + +#define mld_shake256x4_release MLD_NAMESPACE(shake256x4_release) +void mld_shake256x4_release(mld_shake256x4ctx *state); + + +#endif /* !MLD_FIPS202_FIPS202X4_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/keccakf1600.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/keccakf1600.c new file mode 100644 index 0000000000..e59120c07c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/keccakf1600.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#define MLD_KECCAK_NROUNDS 24 +#define MLD_KECCAK_ROL(a, offset) ((a << offset) ^ (a >> (64 - offset))) + +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = state_ptr[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = (state[(offset + i) >> 3] >> (8 * ((offset + i) & 0x07))) & 0xFF; + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state_ptr[i] ^= data[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state[(offset + i) >> 3] ^= (uint64_t)data[i] + << (8 * ((offset + i) & 0x07)); + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X4_NATIVE) + if (mld_keccak_f1600_x4_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 0); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 1); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 2); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 3); +} + +static const uint64_t mld_KeccakF_RoundConstants[MLD_KECCAK_NROUNDS] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +static void mld_keccakf1600_permute_c(uint64_t *state) +{ + unsigned round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + uint64_t BCa, BCe, BCi, BCo, BCu; + uint64_t Da, De, Di, Do, Du; + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + /* copyFromState(A, state) */ + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < MLD_KECCAK_NROUNDS; round += 2) + __loop__(invariant(round <= MLD_KECCAK_NROUNDS && round % 2 == 0)) + { + /* prepareTheta */ + BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; + BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + /* thetaRhoPiChiIotaPrepareTheta(round, A, E) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = MLD_KECCAK_ROL(Age, 44); + Aki ^= Di; + BCi = MLD_KECCAK_ROL(Aki, 43); + Amo ^= Do; + BCo = MLD_KECCAK_ROL(Amo, 21); + Asu ^= Du; + BCu = MLD_KECCAK_ROL(Asu, 14); + Eba = BCa ^ ((~BCe) & BCi); + Eba ^= (uint64_t)mld_KeccakF_RoundConstants[round]; + Ebe = BCe ^ ((~BCi) & BCo); + Ebi = BCi ^ ((~BCo) & BCu); + Ebo = BCo ^ ((~BCu) & BCa); + Ebu = BCu ^ ((~BCa) & BCe); + + Abo ^= Do; + BCa = MLD_KECCAK_ROL(Abo, 28); + Agu ^= Du; + BCe = MLD_KECCAK_ROL(Agu, 20); + Aka ^= Da; + BCi = MLD_KECCAK_ROL(Aka, 3); + Ame ^= De; + BCo = MLD_KECCAK_ROL(Ame, 45); + Asi ^= Di; + BCu = MLD_KECCAK_ROL(Asi, 61); + Ega = BCa ^ ((~BCe) & BCi); + Ege = BCe ^ ((~BCi) & BCo); + Egi = BCi ^ ((~BCo) & BCu); + Ego = BCo ^ ((~BCu) & BCa); + Egu = BCu ^ ((~BCa) & BCe); + + Abe ^= De; + BCa = MLD_KECCAK_ROL(Abe, 1); + Agi ^= Di; + BCe = MLD_KECCAK_ROL(Agi, 6); + Ako ^= Do; + BCi = MLD_KECCAK_ROL(Ako, 25); + Amu ^= Du; + BCo = MLD_KECCAK_ROL(Amu, 8); + Asa ^= Da; + BCu = MLD_KECCAK_ROL(Asa, 18); + Eka = BCa ^ ((~BCe) & BCi); + Eke = BCe ^ ((~BCi) & BCo); + Eki = BCi ^ ((~BCo) & BCu); + Eko = BCo ^ ((~BCu) & BCa); + Eku = BCu ^ ((~BCa) & BCe); + + Abu ^= Du; + BCa = MLD_KECCAK_ROL(Abu, 27); + Aga ^= Da; + BCe = MLD_KECCAK_ROL(Aga, 36); + Ake ^= De; + BCi = MLD_KECCAK_ROL(Ake, 10); + Ami ^= Di; + BCo = MLD_KECCAK_ROL(Ami, 15); + Aso ^= Do; + BCu = MLD_KECCAK_ROL(Aso, 56); + Ema = BCa ^ ((~BCe) & BCi); + Eme = BCe ^ ((~BCi) & BCo); + Emi = BCi ^ ((~BCo) & BCu); + Emo = BCo ^ ((~BCu) & BCa); + Emu = BCu ^ ((~BCa) & BCe); + + Abi ^= Di; + BCa = MLD_KECCAK_ROL(Abi, 62); + Ago ^= Do; + BCe = MLD_KECCAK_ROL(Ago, 55); + Aku ^= Du; + BCi = MLD_KECCAK_ROL(Aku, 39); + Ama ^= Da; + BCo = MLD_KECCAK_ROL(Ama, 41); + Ase ^= De; + BCu = MLD_KECCAK_ROL(Ase, 2); + Esa = BCa ^ ((~BCe) & BCi); + Ese = BCe ^ ((~BCi) & BCo); + Esi = BCi ^ ((~BCo) & BCu); + Eso = BCo ^ ((~BCu) & BCa); + Esu = BCu ^ ((~BCa) & BCe); + + /* prepareTheta */ + BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + /* thetaRhoPiChiIotaPrepareTheta(round+1, E, A) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = MLD_KECCAK_ROL(Ege, 44); + Eki ^= Di; + BCi = MLD_KECCAK_ROL(Eki, 43); + Emo ^= Do; + BCo = MLD_KECCAK_ROL(Emo, 21); + Esu ^= Du; + BCu = MLD_KECCAK_ROL(Esu, 14); + Aba = BCa ^ ((~BCe) & BCi); + Aba ^= (uint64_t)mld_KeccakF_RoundConstants[round + 1]; + Abe = BCe ^ ((~BCi) & BCo); + Abi = BCi ^ ((~BCo) & BCu); + Abo = BCo ^ ((~BCu) & BCa); + Abu = BCu ^ ((~BCa) & BCe); + + Ebo ^= Do; + BCa = MLD_KECCAK_ROL(Ebo, 28); + Egu ^= Du; + BCe = MLD_KECCAK_ROL(Egu, 20); + Eka ^= Da; + BCi = MLD_KECCAK_ROL(Eka, 3); + Eme ^= De; + BCo = MLD_KECCAK_ROL(Eme, 45); + Esi ^= Di; + BCu = MLD_KECCAK_ROL(Esi, 61); + Aga = BCa ^ ((~BCe) & BCi); + Age = BCe ^ ((~BCi) & BCo); + Agi = BCi ^ ((~BCo) & BCu); + Ago = BCo ^ ((~BCu) & BCa); + Agu = BCu ^ ((~BCa) & BCe); + + Ebe ^= De; + BCa = MLD_KECCAK_ROL(Ebe, 1); + Egi ^= Di; + BCe = MLD_KECCAK_ROL(Egi, 6); + Eko ^= Do; + BCi = MLD_KECCAK_ROL(Eko, 25); + Emu ^= Du; + BCo = MLD_KECCAK_ROL(Emu, 8); + Esa ^= Da; + BCu = MLD_KECCAK_ROL(Esa, 18); + Aka = BCa ^ ((~BCe) & BCi); + Ake = BCe ^ ((~BCi) & BCo); + Aki = BCi ^ ((~BCo) & BCu); + Ako = BCo ^ ((~BCu) & BCa); + Aku = BCu ^ ((~BCa) & BCe); + + Ebu ^= Du; + BCa = MLD_KECCAK_ROL(Ebu, 27); + Ega ^= Da; + BCe = MLD_KECCAK_ROL(Ega, 36); + Eke ^= De; + BCi = MLD_KECCAK_ROL(Eke, 10); + Emi ^= Di; + BCo = MLD_KECCAK_ROL(Emi, 15); + Eso ^= Do; + BCu = MLD_KECCAK_ROL(Eso, 56); + Ama = BCa ^ ((~BCe) & BCi); + Ame = BCe ^ ((~BCi) & BCo); + Ami = BCi ^ ((~BCo) & BCu); + Amo = BCo ^ ((~BCu) & BCa); + Amu = BCu ^ ((~BCa) & BCe); + + Ebi ^= Di; + BCa = MLD_KECCAK_ROL(Ebi, 62); + Ego ^= Do; + BCe = MLD_KECCAK_ROL(Ego, 55); + Eku ^= Du; + BCi = MLD_KECCAK_ROL(Eku, 39); + Ema ^= Da; + BCo = MLD_KECCAK_ROL(Ema, 41); + Ese ^= De; + BCu = MLD_KECCAK_ROL(Ese, 2); + Asa = BCa ^ ((~BCe) & BCi); + Ase = BCe ^ ((~BCi) & BCo); + Asi = BCi ^ ((~BCo) & BCu); + Aso = BCo ^ ((~BCu) & BCa); + Asu = BCu ^ ((~BCa) & BCe); + } + + /* copyToState(state, A) */ + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} + +void mld_keccakf1600_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X1_NATIVE) + if (mld_keccak_f1600_x1_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X1_NATIVE */ + mld_keccakf1600_permute_c(state); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(keccakf1600) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_KECCAK_NROUNDS +#undef MLD_KECCAK_ROL diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/keccakf1600.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/keccakf1600.h new file mode 100644 index 0000000000..e56adc1561 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/keccakf1600.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_KECCAKF1600_H +#define MLD_FIPS202_KECCAKF1600_H +#include +#include "../cbmc.h" +#include "../common.h" +#include "fips202.h" + +#define MLD_KECCAK_LANES 25 +#define MLD_KECCAK_WAY 4 + +/* + * WARNING: + * The contents of this structure, including the placement + * and interleaving of Keccak lanes, are IMPLEMENTATION-DEFINED. + * The struct is only exposed here to allow its construction on the stack. + */ + +#define mld_keccakf1600_extract_bytes MLD_NAMESPACE(keccakf1600_extract_bytes) +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(data, length)) +); + +#define mld_keccakf1600_xor_bytes MLD_NAMESPACE(keccakf1600_xor_bytes) +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#define mld_keccakf1600x4_extract_bytes \ + MLD_NAMESPACE(keccakf1600x4_extract_bytes) +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + requires(memory_no_alias(data1, length)) + requires(memory_no_alias(data2, length)) + requires(memory_no_alias(data3, length)) + assigns(memory_slice(data0, length)) + assigns(memory_slice(data1, length)) + assigns(memory_slice(data2, length)) + assigns(memory_slice(data3, length)) +); + +#define mld_keccakf1600x4_xor_bytes MLD_NAMESPACE(keccakf1600x4_xor_bytes) +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + /* Case 1: all input buffers are distinct; Case 2: All input buffers are the same */ + requires((data0 == data1 && + data0 == data2 && + data0 == data3) || + (memory_no_alias(data1, length) && + memory_no_alias(data2, length) && + memory_no_alias(data3, length))) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600x4_permute MLD_NAMESPACE(keccakf1600x4_permute) +void mld_keccakf1600x4_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600_permute MLD_NAMESPACE(keccakf1600_permute) +void mld_keccakf1600_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#endif /* !MLD_FIPS202_KECCAKF1600_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/auto.h new file mode 100644 index 0000000000..4375cc1976 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/auto.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [HYBRID] + * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64 + * Becker, Kannwischer + * https://eprint.iacr.org/2022/1243 + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +#define MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* Default FIPS202 assembly profile for AArch64 systems */ + +/* + * Default logic to decide which implementation to use. + * + */ + +/* + * Keccak-f1600 + * + * - On Arm-based Apple CPUs, we pick a pure Neon implementation. + * - Otherwise, unless MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, + * we use lazy-rotation scalar assembly from @[HYBRID]. + * - Otherwise, if MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, we + * fall back to the standard C implementation. + */ +#if defined(__ARM_FEATURE_SHA3) && defined(__APPLE__) +#include "x1_v84a.h" +#elif !defined(MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER) +#include "x1_scalar.h" +#endif + +/* + * Keccak-f1600x2/x4 + * + * The optimal implementation is highly CPU-specific; see @[HYBRID]. + * + * For now, if v8.4-A is not implemented, we fall back to Keccak-f1600. + * If v8.4-A is implemented and we are on an Apple CPU, we use a plain + * Neon-based implementation. + * If v8.4-A is implemented and we are not on an Apple CPU, we use a + * scalar/Neon/Neon hybrid. + * The reason for this distinction is that Apple CPUs appear to implement + * the SHA3 instructions on all SIMD units, while Arm CPUs prior to Cortex-X4 + * don't, and ordinary Neon instructions are still needed. + */ +#if defined(__ARM_FEATURE_SHA3) +/* + * For Apple-M cores, we use a plain implementation leveraging SHA3 + * instructions only. + */ +#if defined(__APPLE__) +#include "x2_v84a.h" +#else +#include "x4_v8a_v84a_scalar.h" +#endif + +#else /* __ARM_FEATURE_SHA3 */ + +#include "x4_v8a_scalar.h" + +#endif /* !__ARM_FEATURE_SHA3 */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h new file mode 100644 index 0000000000..20f6168038 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#define MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H + +#include +#include "../../../../cbmc.h" +#include "../../../../common.h" + + +#define mld_keccakf1600_round_constants \ + MLD_NAMESPACE(keccakf1600_round_constants) +extern const uint64_t mld_keccakf1600_round_constants[]; + +#define mld_keccak_f1600_x1_scalar_asm MLD_NAMESPACE(keccak_f1600_x1_scalar_asm) +void mld_keccak_f1600_x1_scalar_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x1_v84a_asm MLD_NAMESPACE(keccak_f1600_x1_v84a_asm) +void mld_keccak_f1600_x1_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x2_v84a_asm MLD_NAMESPACE(keccak_f1600_x2_v84a_asm) +void mld_keccak_f1600_x2_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 2)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 2)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c new file mode 100644 index 0000000000..05e9cbfeec --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../../common.h" + +#if (defined(MLD_FIPS202_AARCH64_NEED_X1_SCALAR) || \ + defined(MLD_FIPS202_AARCH64_NEED_X1_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X2_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID)) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "fips202_native_aarch64.h" + +MLD_ALIGN const uint64_t mld_keccakf1600_round_constants[] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, +}; + +#else /* (MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_aarch64_round_constants) + +#endif /* !((MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/x1_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/x1_scalar.h new file mode 100644 index 0000000000..681b991371 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/x1_scalar.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_SCALAR + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + mld_keccak_f1600_x1_scalar_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/x1_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/x1_v84a.h new file mode 100644 index 0000000000..d15c8c26f3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/x1_v84a.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x1_v84a_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/x2_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/x2_v84a.h new file mode 100644 index 0000000000..16c22fa1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/x2_v84a.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X2_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" + + +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x2_v84a_asm(state + 0 * 25, mld_keccakf1600_round_constants); + mld_keccak_f1600_x2_v84a_asm(state + 2 * 25, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h new file mode 100644 index 0000000000..0f7f8fe499 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(state, + mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h new file mode 100644 index 0000000000..3da883b762 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm( + state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/api.h new file mode 100644 index 0000000000..4625c9a1ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/api.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_API_H +#define MLD_FIPS202_NATIVE_API_H +/* + * FIPS-202 native interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + */ + +#include +#include "../../cbmc.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* + * This is the C<->native interface allowing for the drop-in + * of custom Keccak-F1600 implementations. + * + * A _backend_ is a specific implementation of parts of this interface. + * + * You can replace 1-fold or 4-fold batched Keccak-F1600. + * To enable, set MLD_USE_FIPS202_X1_NATIVE or MLD_USE_FIPS202_X4_NATIVE + * in your backend, and define the inline wrappers mld_keccak_f1600_x1_native() + * and/or mld_keccak_f1600_x4_native(), respectively, to forward to your + * implementation. + */ + +#if defined(MLD_USE_FIPS202_X1_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 1)) +); +#endif /* MLD_USE_FIPS202_X1_NATIVE */ +#if defined(MLD_USE_FIPS202_X4_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 4)) +); +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + +#endif /* !MLD_FIPS202_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/auto.h new file mode 100644 index 0000000000..0a09c733c8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/auto.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AUTO_H +#define MLD_FIPS202_NATIVE_AUTO_H + +/* + * Default FIPS202 backend + */ +#include "../../sys.h" + +#if defined(MLD_SYS_AARCH64) +#include "aarch64/auto.h" +#endif + +#if defined(MLD_SYS_X86_64) && defined(MLD_SYS_X86_64_AVX2) +#include "x86_64/xkcp.h" +#endif + +#endif /* !MLD_FIPS202_NATIVE_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c new file mode 100644 index 0000000000..4eaad2fd66 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* +Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, +Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby +denoted as "the implementer". + +For more information, feedback or questions, please refer to our websites: +http://keccak.noekeon.org/ +http://keyak.noekeon.org/ +http://ketje.noekeon.org/ + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +/* + * Changes for mlkem-native/mldsa-native: + * - copyFromState and copyToState operate on uninterleaved + * Keccak states in memory. + */ + +#include "../../../../common.h" +#if defined(MLD_FIPS202_X86_64_XKCP) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include + +#include "KeccakP_1600_times4_SIMD256.h" + +#ifndef MLD_SYS_LITTLE_ENDIAN +#error Expecting a little-endian platform +#endif + +#define ANDnu256(a, b) _mm256_andnot_si256(a, b) +#define CONST256(a) _mm256_load_si256((const __m256i *)&(a)) +#define CONST256_64(a) (__m256i) _mm256_broadcast_sd((const double *)(&a)) +#define ROL64in256(d, a, o) \ + d = _mm256_or_si256(_mm256_slli_epi64(a, o), _mm256_srli_epi64(a, 64 - (o))) +#define ROL64in256_8(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho8)) +#define ROL64in256_56(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho56)) +static const uint64_t rho8[4] = {0x0605040302010007, 0x0E0D0C0B0A09080F, + 0x1615141312111017, 0x1E1D1C1B1A19181F}; +static const uint64_t rho56[4] = {0x0007060504030201, 0x080F0E0D0C0B0A09, + 0x1017161514131211, 0x181F1E1D1C1B1A19}; +#define STORE256(a, b) _mm256_store_si256((__m256i *)&(a), b) +#define XOR256(a, b) _mm256_xor_si256(a, b) +#define XOReq256(a, b) a = _mm256_xor_si256(a, b) + +#define SnP_laneLengthInBytes 8 + +#define declareABCDE \ + __m256i Aba, Abe, Abi, Abo, Abu; \ + __m256i Aga, Age, Agi, Ago, Agu; \ + __m256i Aka, Ake, Aki, Ako, Aku; \ + __m256i Ama, Ame, Ami, Amo, Amu; \ + __m256i Asa, Ase, Asi, Aso, Asu; \ + __m256i Bba, Bbe, Bbi, Bbo, Bbu; \ + __m256i Bga, Bge, Bgi, Bgo, Bgu; \ + __m256i Bka, Bke, Bki, Bko, Bku; \ + __m256i Bma, Bme, Bmi, Bmo, Bmu; \ + __m256i Bsa, Bse, Bsi, Bso, Bsu; \ + __m256i Ca, Ce, Ci, Co, Cu; \ + __m256i Ca1, Ce1, Ci1, Co1, Cu1; \ + __m256i Da, De, Di, Do, Du; \ + __m256i Eba, Ebe, Ebi, Ebo, Ebu; \ + __m256i Ega, Ege, Egi, Ego, Egu; \ + __m256i Eka, Eke, Eki, Eko, Eku; \ + __m256i Ema, Eme, Emi, Emo, Emu; \ + __m256i Esa, Ese, Esi, Eso, Esu; + +#define prepareTheta \ + Ca = XOR256(Aba, XOR256(Aga, XOR256(Aka, XOR256(Ama, Asa)))); \ + Ce = XOR256(Abe, XOR256(Age, XOR256(Ake, XOR256(Ame, Ase)))); \ + Ci = XOR256(Abi, XOR256(Agi, XOR256(Aki, XOR256(Ami, Asi)))); \ + Co = XOR256(Abo, XOR256(Ago, XOR256(Ako, XOR256(Amo, Aso)))); \ + Cu = XOR256(Abu, XOR256(Agu, XOR256(Aku, XOR256(Amu, Asu)))); + +/* + * --- Theta Rho Pi Chi Iota Prepare-theta + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + Ca = E##ba; \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + Ce = E##be; \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + Ci = E##bi; \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + Co = E##bo; \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + Cu = E##bu; \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(Ca, E##ga); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(Ce, E##ge); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + XOReq256(Ci, E##gi); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + XOReq256(Co, E##go); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + XOReq256(Cu, E##gu); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(Ca, E##ka); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(Ce, E##ke); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + XOReq256(Ci, E##ki); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + XOReq256(Co, E##ko); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + XOReq256(Cu, E##ku); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(Ca, E##ma); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(Ce, E##me); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + XOReq256(Ci, E##mi); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + XOReq256(Co, E##mo); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + XOReq256(Cu, E##mu); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(Ca, E##sa); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(Ce, E##se); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + XOReq256(Ci, E##si); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + XOReq256(Co, E##so); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); \ + XOReq256(Cu, E##su); + + +/* + * --- Theta Rho Pi Chi Iota + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIota(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); + + +static MLD_ALIGN const uint64_t keccakf1600RoundConstants[24] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +#include + +#define copyFromState(X, state) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m256i _idx = \ + _mm256_set_epi64x((long long)&state64[75], (long long)&state64[50], \ + (long long)&state64[25], (long long)&state64[0]); \ + X##ba = _mm256_i64gather_epi64((long long *)(0 * 8), _idx, 1); \ + X##be = _mm256_i64gather_epi64((long long *)(1 * 8), _idx, 1); \ + X##bi = _mm256_i64gather_epi64((long long *)(2 * 8), _idx, 1); \ + X##bo = _mm256_i64gather_epi64((long long *)(3 * 8), _idx, 1); \ + X##bu = _mm256_i64gather_epi64((long long *)(4 * 8), _idx, 1); \ + X##ga = _mm256_i64gather_epi64((long long *)(5 * 8), _idx, 1); \ + X##ge = _mm256_i64gather_epi64((long long *)(6 * 8), _idx, 1); \ + X##gi = _mm256_i64gather_epi64((long long *)(7 * 8), _idx, 1); \ + X##go = _mm256_i64gather_epi64((long long *)(8 * 8), _idx, 1); \ + X##gu = _mm256_i64gather_epi64((long long *)(9 * 8), _idx, 1); \ + X##ka = _mm256_i64gather_epi64((long long *)(10 * 8), _idx, 1); \ + X##ke = _mm256_i64gather_epi64((long long *)(11 * 8), _idx, 1); \ + X##ki = _mm256_i64gather_epi64((long long *)(12 * 8), _idx, 1); \ + X##ko = _mm256_i64gather_epi64((long long *)(13 * 8), _idx, 1); \ + X##ku = _mm256_i64gather_epi64((long long *)(14 * 8), _idx, 1); \ + X##ma = _mm256_i64gather_epi64((long long *)(15 * 8), _idx, 1); \ + X##me = _mm256_i64gather_epi64((long long *)(16 * 8), _idx, 1); \ + X##mi = _mm256_i64gather_epi64((long long *)(17 * 8), _idx, 1); \ + X##mo = _mm256_i64gather_epi64((long long *)(18 * 8), _idx, 1); \ + X##mu = _mm256_i64gather_epi64((long long *)(19 * 8), _idx, 1); \ + X##sa = _mm256_i64gather_epi64((long long *)(20 * 8), _idx, 1); \ + X##se = _mm256_i64gather_epi64((long long *)(21 * 8), _idx, 1); \ + X##si = _mm256_i64gather_epi64((long long *)(22 * 8), _idx, 1); \ + X##so = _mm256_i64gather_epi64((long long *)(23 * 8), _idx, 1); \ + X##su = _mm256_i64gather_epi64((long long *)(24 * 8), _idx, 1); \ + } while (0); + +#define SCATTER_STORE256(state, idx, v) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m128d t = _mm_castsi128_pd(_mm256_castsi256_si128((v))); \ + _mm_storel_pd((double *)&state64[0 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[25 + (idx)], t); \ + t = _mm_castsi128_pd(_mm256_extracti128_si256((v), 1)); \ + _mm_storel_pd((double *)&state64[50 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[75 + (idx)], t); \ + } while (0) + +#define copyToState(state, X) \ + SCATTER_STORE256(state, 0, X##ba); \ + SCATTER_STORE256(state, 1, X##be); \ + SCATTER_STORE256(state, 2, X##bi); \ + SCATTER_STORE256(state, 3, X##bo); \ + SCATTER_STORE256(state, 4, X##bu); \ + SCATTER_STORE256(state, 5, X##ga); \ + SCATTER_STORE256(state, 6, X##ge); \ + SCATTER_STORE256(state, 7, X##gi); \ + SCATTER_STORE256(state, 8, X##go); \ + SCATTER_STORE256(state, 9, X##gu); \ + SCATTER_STORE256(state, 10, X##ka); \ + SCATTER_STORE256(state, 11, X##ke); \ + SCATTER_STORE256(state, 12, X##ki); \ + SCATTER_STORE256(state, 13, X##ko); \ + SCATTER_STORE256(state, 14, X##ku); \ + SCATTER_STORE256(state, 15, X##ma); \ + SCATTER_STORE256(state, 16, X##me); \ + SCATTER_STORE256(state, 17, X##mi); \ + SCATTER_STORE256(state, 18, X##mo); \ + SCATTER_STORE256(state, 19, X##mu); \ + SCATTER_STORE256(state, 20, X##sa); \ + SCATTER_STORE256(state, 21, X##se); \ + SCATTER_STORE256(state, 22, X##si); \ + SCATTER_STORE256(state, 23, X##so); \ + SCATTER_STORE256(state, 24, X##su); + +#define copyStateVariables(X, Y) \ + X##ba = Y##ba; \ + X##be = Y##be; \ + X##bi = Y##bi; \ + X##bo = Y##bo; \ + X##bu = Y##bu; \ + X##ga = Y##ga; \ + X##ge = Y##ge; \ + X##gi = Y##gi; \ + X##go = Y##go; \ + X##gu = Y##gu; \ + X##ka = Y##ka; \ + X##ke = Y##ke; \ + X##ki = Y##ki; \ + X##ko = Y##ko; \ + X##ku = Y##ku; \ + X##ma = Y##ma; \ + X##me = Y##me; \ + X##mi = Y##mi; \ + X##mo = Y##mo; \ + X##mu = Y##mu; \ + X##sa = Y##sa; \ + X##se = Y##se; \ + X##si = Y##si; \ + X##so = Y##so; \ + X##su = Y##su; + +/* clang-format off */ +#define rounds24 \ + prepareTheta \ + thetaRhoPiChiIotaPrepareTheta( 0, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 1, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 2, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 3, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 4, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 5, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 6, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 7, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 8, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 9, E, A) \ + thetaRhoPiChiIotaPrepareTheta(10, A, E) \ + thetaRhoPiChiIotaPrepareTheta(11, E, A) \ + thetaRhoPiChiIotaPrepareTheta(12, A, E) \ + thetaRhoPiChiIotaPrepareTheta(13, E, A) \ + thetaRhoPiChiIotaPrepareTheta(14, A, E) \ + thetaRhoPiChiIotaPrepareTheta(15, E, A) \ + thetaRhoPiChiIotaPrepareTheta(16, A, E) \ + thetaRhoPiChiIotaPrepareTheta(17, E, A) \ + thetaRhoPiChiIotaPrepareTheta(18, A, E) \ + thetaRhoPiChiIotaPrepareTheta(19, E, A) \ + thetaRhoPiChiIotaPrepareTheta(20, A, E) \ + thetaRhoPiChiIotaPrepareTheta(21, E, A) \ + thetaRhoPiChiIotaPrepareTheta(22, A, E) \ + thetaRhoPiChiIota(23, E, A) +/* clang-format on */ + +void mld_keccakf1600x4_permute24(void *states) +{ + __m256i *statesAsLanes = (__m256i *)states; + declareABCDE copyFromState(A, statesAsLanes) + rounds24 copyToState(statesAsLanes, A) +} + +#else /* MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_avx2_keccakx4) + +#endif /* !(MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef ANDnu256 +#undef CONST256 +#undef CONST256_64 +#undef ROL64in256 +#undef ROL64in256_8 +#undef ROL64in256_56 +#undef STORE256 +#undef XOR256 +#undef XOReq256 +#undef SnP_laneLengthInBytes +#undef declareABCDE +#undef prepareTheta +#undef thetaRhoPiChiIotaPrepareTheta +#undef thetaRhoPiChiIota +#undef copyFromState +#undef SCATTER_STORE256 +#undef copyToState +#undef copyStateVariables +#undef rounds24 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h new file mode 100644 index 0000000000..3499d38e2c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H +#define MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H + +#include "../../../../common.h" + +#define mld_keccakf1600x4_permute24 \ + MLD_NAMESPACE(KeccakP1600times4_PermuteAll_24rounds) +void mld_keccakf1600x4_permute24(void *states); + +#endif /* !MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/x86_64/xkcp.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/x86_64/xkcp.h new file mode 100644 index 0000000000..c03642d7e0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/fips202/native/x86_64/xkcp.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_XKCP_H +#define MLD_FIPS202_NATIVE_X86_64_XKCP_H + +#include "../../../common.h" + +#define MLD_FIPS202_X86_64_XKCP + +#if !defined(__ASSEMBLER__) +#include +#include "../api.h" +#include "src/KeccakP_1600_times4_SIMD256.h" + +#define MLD_USE_FIPS202_X4_NATIVE +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_keccakf1600x4_permute24(state); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_X86_64_XKCP_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/meta.h new file mode 100644 index 0000000000..c6f6ad47b0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/meta.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_META_H +#define MLD_NATIVE_AARCH64_META_H + +/* Set of primitives that this backend replaces */ +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_AARCH64 + + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/arith_native_aarch64.h" + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + mld_ntt_asm(data, mld_aarch64_ntt_zetas_layer123456, + mld_aarch64_ntt_zetas_layer78); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + mld_intt_asm(data, mld_aarch64_intt_zetas_layer78, + mld_aarch64_intt_zetas_layer123456); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + if (len != MLDSA_N || + buflen % 24 != 0) /* NEON support is mandatory for AArch64 */ + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N, hence, this cast is safe. */ + return (int)mld_rej_uniform_asm(r, buf, buflen, mld_rej_uniform_table); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_32_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_88_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + mld_poly_caddq_asm(a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_32_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_88_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + return mld_poly_chknorm_asm(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_17_asm(r, buf, mld_polyz_unpack_17_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_19_asm(r, buf, mld_polyz_unpack_19_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t out[MLDSA_N], const int32_t in0[MLDSA_N], + const int32_t in1[MLDSA_N]) +{ + mld_poly_pointwise_montgomery_asm(out, in0, in1); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l4_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l5_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l7_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ +#endif /* !MLD_NATIVE_AARCH64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/src/aarch64_zetas.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/src/aarch64_zetas.c new file mode 100644 index 0000000000..9ab7b9a68c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/src/aarch64_zetas.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Table of zeta values used in the AArch64 forward NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer123456[] = { + -3572223, -915382907, 3765607, 964937599, 3761513, 963888510, + -3201494, -820383522, -2883726, -738955404, -3145678, -806080660, + -3201430, -820367122, 0, 0, -601683, -154181397, + -3370349, -863652652, -4063053, -1041158200, 3602218, 923069133, + 3182878, 815613168, 2740543, 702264730, -3586446, -919027554, + 0, 0, 3542485, 907762539, 2663378, 682491182, + -1674615, -429120452, -3110818, -797147778, 2101410, 538486762, + 3704823, 949361686, 1159875, 297218217, 0, 0, + 2682288, 687336873, -3524442, -903139016, -434125, -111244624, + 394148, 101000509, 928749, 237992130, 1095468, 280713909, + -3506380, -898510625, 0, 0, 2129892, 545785280, + 676590, 173376332, -1335936, -342333886, 2071829, 530906624, + -4018989, -1029866791, 3241972, 830756018, 2156050, 552488273, + 0, 0, 3764867, 964747974, -3227876, -827143915, + 1714295, 439288460, 3415069, 875112161, 1759347, 450833045, + -817536, -209493775, -3574466, -915957677, 0, 0, + -1005239, -257592709, 2453983, 628833668, 1460718, 374309300, + 3756790, 962678241, -1935799, -496048908, -1716988, -439978542, + -3950053, -1012201926, 0, 0, 557458, 142848732, + -642628, -164673562, -3585098, -918682129, -2897314, -742437332, + 3192354, 818041395, 556856, 142694469, 3870317, 991769559, + 0, 0, -1221177, -312926867, 2815639, 721508096, + 2283733, 585207070, 2917338, 747568486, 1853806, 475038184, + 3345963, 857403734, 1858416, 476219497, 0, 0, +}; + +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer78[] = { + 3073009, 1277625, -2635473, 3852015, 787459213, + 327391679, -675340520, 987079667, 1753, -2659525, + 2660408, -59148, 449207, -681503850, 681730119, + -15156688, -1935420, -1455890, -1780227, 2772600, + -495951789, -373072124, -456183549, 710479343, 4183372, + -3222807, -3121440, -274060, 1071989969, -825844983, + -799869667, -70227934, 1182243, 636927, -3956745, + -3284915, 302950022, 163212680, -1013916752, -841760171, + 87208, -3965306, -2296397, -3716946, 22347069, + -1016110510, -588452222, -952468207, 2508980, 2028118, + 1937570, -3815725, 642926661, 519705671, 496502727, + -977780347, -27812, 1009365, -1979497, -3956944, + -7126831, 258649997, -507246529, -1013967746, 822541, + -2454145, 1596822, -3759465, 210776307, -628875181, + 409185979, -963363710, 2811291, -2983781, -1109516, + 4158088, 720393920, -764594519, -284313712, 1065510939, + -1685153, 2678278, -3551006, -250446, -431820817, + 686309310, -909946047, -64176841, -3410568, -3768948, + 635956, -2455377, -873958779, -965793731, 162963861, + -629190881, 1528066, 482649, 1148858, -2962264, + 391567239, 123678909, 294395108, -759080783, -4146264, + 2192938, 2387513, -268456, -1062481036, 561940831, + 611800717, -68791907, -1772588, -1727088, -3611750, + -3180456, -454226054, -442566669, -925511710, -814992530, + -565603, 169688, 2462444, -3334383, -144935890, + 43482586, 631001801, -854436357, 3747250, 1239911, + 3195676, 1254190, 960233614, 317727459, 818892658, + 321386456, 2296099, -3838479, 2642980, -12417, + 588375860, -983611064, 677264190, -3181859, -4166425, + -3488383, 1987814, -3197248, -1067647297, -893898890, + 509377762, -819295484, 2998219, -89301, -1354892, + -1310261, 768294260, -22883400, -347191365, -335754661, + 141835, 2513018, 613238, -2218467, 36345249, + 643961400, 157142369, -568482643, 1736313, 235407, + -3250154, 3258457, 444930577, 60323094, -832852657, + 834980303, -458740, 4040196, 2039144, -818761, + -117552223, 1035301089, 522531086, -209807681, -1921994, + -3472069, -1879878, -2178965, -492511373, -889718424, + -481719139, -558360247, -2579253, 1787943, -2391089, + -2254727, -660934133, 458160776, -612717067, -577774276, + -1623354, -2374402, 586241, 527981, -415984810, + -608441020, 150224382, 135295244, 2105286, -2033807, + -1179613, -2743411, 539479988, -521163479, -302276083, + -702999655, 3482206, -4182915, -1300016, -2362063, + 892316032, -1071872863, -333129378, -605279149, -1476985, + 2491325, 507927, -724804, -378477722, 638402564, + 130156402, -185731180, 1994046, -1393159, -1187885, + -1834526, 510974714, -356997292, -304395785, -470097680, + -1317678, 2461387, 3035980, 621164, -337655269, + 630730945, 777970524, 159173408, -3033742, 2647994, + -2612853, 749577, -777397036, 678549029, -669544140, + 192079267, -338420, 3009748, 4148469, -4022750, + -86720197, 771248568, 1063046068, -1030830548, 3901472, + -1226661, 2925816, 3374250, 999753034, -314332144, + 749740976, 864652284, 3980599, -1615530, 1665318, + 1163598, 1020029345, -413979908, 426738094, 298172236, + 2569011, 1723229, 2028038, -3369273, 658309618, + 441577800, 519685171, -863376927, 1356448, -2775755, + 2683270, -2778788, 347590090, -711287812, 687588511, + -712065019, 3994671, -1370517, 3363542, 545376, + 1023635298, -351195274, 861908357, 139752717, -11879, + 3020393, 214880, -770441, -3043996, 773976352, + 55063046, -197425671, -3467665, 2312838, -653275, + -459163, -888589898, 592665232, -167401858, -117660617, + 3105558, 508145, 860144, 140244, 795799901, + 130212265, 220412084, 35937555, -1103344, -553718, + 3430436, -1514152, -282732136, -141890356, 879049958, + -388001774, 348812, -327848, 1011223, -2354215, + 89383150, -84011120, 259126110, -603268097, -2185084, + 2358373, -3014420, 2926054, -559928242, 604333585, + -772445769, 749801963, 3123762, -2193087, -1716814, + -392707, 800464680, -561979013, -439933955, -100631253, + -3818627, -1922253, -2236726, 1744507, -978523985, + -492577742, -573161516, 447030292, -303005, -3974485, + 1900052, 1054478, -77645096, -1018462631, 486888731, + 270210213, 3531229, -3773731, -781875, -731434, + 904878186, -967019376, -200355636, -187430119, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer78[] = { + -1744507, 2236726, 1922253, 3818627, -447030292, 573161516, + 492577742, 978523985, 731434, 781875, 3773731, -3531229, + 187430119, 200355636, 967019376, -904878186, -1054478, -1900052, + 3974485, 303005, -270210213, -486888731, 1018462631, 77645096, + 2354215, -1011223, 327848, -348812, 603268097, -259126110, + 84011120, -89383150, 392707, 1716814, 2193087, -3123762, + 100631253, 439933955, 561979013, -800464680, -2926054, 3014420, + -2358373, 2185084, -749801963, 772445769, -604333585, 559928242, + 459163, 653275, -2312838, 3467665, 117660617, 167401858, + -592665232, 888589898, 1514152, -3430436, 553718, 1103344, + 388001774, -879049958, 141890356, 282732136, -140244, -860144, + -508145, -3105558, -35937555, -220412084, -130212265, -795799901, + 2778788, -2683270, 2775755, -1356448, 712065019, -687588511, + 711287812, -347590090, 770441, -214880, -3020393, 11879, + 197425671, -55063046, -773976352, 3043996, -545376, -3363542, + 1370517, -3994671, -139752717, -861908357, 351195274, -1023635298, + -3374250, -2925816, 1226661, -3901472, -864652284, -749740976, + 314332144, -999753034, 3369273, -2028038, -1723229, -2569011, + 863376927, -519685171, -441577800, -658309618, -1163598, -1665318, + 1615530, -3980599, -298172236, -426738094, 413979908, -1020029345, + -621164, -3035980, -2461387, 1317678, -159173408, -777970524, + -630730945, 337655269, 4022750, -4148469, -3009748, 338420, + 1030830548, -1063046068, -771248568, 86720197, -749577, 2612853, + -2647994, 3033742, -192079267, 669544140, -678549029, 777397036, + 2362063, 1300016, 4182915, -3482206, 605279149, 333129378, + 1071872863, -892316032, 1834526, 1187885, 1393159, -1994046, + 470097680, 304395785, 356997292, -510974714, 724804, -507927, + -2491325, 1476985, 185731180, -130156402, -638402564, 378477722, + 2254727, 2391089, -1787943, 2579253, 577774276, 612717067, + -458160776, 660934133, 2743411, 1179613, 2033807, -2105286, + 702999655, 302276083, 521163479, -539479988, -527981, -586241, + 2374402, 1623354, -135295244, -150224382, 608441020, 415984810, + -3258457, 3250154, -235407, -1736313, -834980303, 832852657, + -60323094, -444930577, 2178965, 1879878, 3472069, 1921994, + 558360247, 481719139, 889718424, 492511373, 818761, -2039144, + -4040196, 458740, 209807681, -522531086, -1035301089, 117552223, + 3197248, -1987814, 3488383, 4166425, 819295484, -509377762, + 893898890, 1067647297, 2218467, -613238, -2513018, -141835, + 568482643, -157142369, -643961400, -36345249, 1310261, 1354892, + 89301, -2998219, 335754661, 347191365, 22883400, -768294260, + 3334383, -2462444, -169688, 565603, 854436357, -631001801, + -43482586, 144935890, 12417, -2642980, 3838479, -2296099, + 3181859, -677264190, 983611064, -588375860, -1254190, -3195676, + -1239911, -3747250, -321386456, -818892658, -317727459, -960233614, + 2962264, -1148858, -482649, -1528066, 759080783, -294395108, + -123678909, -391567239, 3180456, 3611750, 1727088, 1772588, + 814992530, 925511710, 442566669, 454226054, 268456, -2387513, + -2192938, 4146264, 68791907, -611800717, -561940831, 1062481036, + -4158088, 1109516, 2983781, -2811291, -1065510939, 284313712, + 764594519, -720393920, 2455377, -635956, 3768948, 3410568, + 629190881, -162963861, 965793731, 873958779, 250446, 3551006, + -2678278, 1685153, 64176841, 909946047, -686309310, 431820817, + 3815725, -1937570, -2028118, -2508980, 977780347, -496502727, + -519705671, -642926661, 3759465, -1596822, 2454145, -822541, + 963363710, -409185979, 628875181, -210776307, 3956944, 1979497, + -1009365, 27812, 1013967746, 507246529, -258649997, 7126831, + 274060, 3121440, 3222807, -4183372, 70227934, 799869667, + 825844983, -1071989969, 3716946, 2296397, 3965306, -87208, + 952468207, 588452222, 1016110510, -22347069, 3284915, 3956745, + -636927, -1182243, 841760171, 1013916752, -163212680, -302950022, + -3852015, 2635473, -1277625, -3073009, -987079667, 675340520, + -327391679, -787459213, -2772600, 1780227, 1455890, 1935420, + -710479343, 456183549, 373072124, 495951789, 59148, -2660408, + 2659525, -1753, 15156688, -681730119, 681503850, -449207, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer123456[] = { + -2283733, -585207070, 0, 0, -1858416, -476219497, + -3345963, -857403734, -2815639, -721508096, 0, 0, + -1853806, -475038184, -2917338, -747568486, 3585098, 918682129, + 0, 0, -3870317, -991769559, -556856, -142694469, + 642628, 164673562, 0, 0, -3192354, -818041395, + 2897314, 742437332, -1460718, -374309300, 0, 0, + 3950053, 1012201926, 1716988, 439978542, -2453983, -628833668, + 0, 0, 1935799, 496048908, -3756790, -962678241, + -1714295, -439288460, 0, 0, 3574466, 915957677, + 817536, 209493775, 3227876, 827143915, 0, 0, + -1759347, -450833045, -3415069, -875112161, 1335936, 342333886, + 0, 0, -2156050, -552488273, -3241972, -830756018, + -676590, -173376332, 0, 0, 4018989, 1029866791, + -2071829, -530906624, 434125, 111244624, 0, 0, + 3506380, 898510625, -1095468, -280713909, 3524442, 903139016, + 0, 0, -928749, -237992130, -394148, -101000509, + 1674615, 429120452, 0, 0, -1159875, -297218217, + -3704823, -949361686, -2663378, -682491182, 0, 0, + -2101410, -538486762, 3110818, 797147778, 4063053, 1041158200, + 0, 0, 3586446, 919027554, -2740543, -702264730, + 3370349, 863652652, 0, 0, -3182878, -815613168, + -3602218, -923069133, -294725, -75523344, -3761513, -963888510, + -3765607, -964937599, 3201430, 820367122, 3145678, 806080660, + 2883726, 738955404, 3201494, 820383522, 1221177, 312926867, + -557458, -142848732, 1005239, 257592709, -3764867, -964747974, + -2129892, -545785280, -2682288, -687336873, -3542485, -907762539, + 601683, 154181397, 0, 0, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_zetas) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h new file mode 100644 index 0000000000..e77f55014c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#define MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H + +#include +#include "../../../common.h" + +#define mld_aarch64_ntt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_ntt_zetas_layer123456) +#define mld_aarch64_ntt_zetas_layer78 MLD_NAMESPACE(aarch64_ntt_zetas_layer78) + +#define mld_aarch64_intt_zetas_layer78 MLD_NAMESPACE(aarch64_intt_zetas_layer78) +#define mld_aarch64_intt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_intt_zetas_layer123456) + +extern const int32_t mld_aarch64_ntt_zetas_layer123456[]; +extern const int32_t mld_aarch64_ntt_zetas_layer78[]; + +extern const int32_t mld_aarch64_intt_zetas_layer78[]; +extern const int32_t mld_aarch64_intt_zetas_layer123456[]; + +#define mld_rej_uniform_table MLD_NAMESPACE(rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[]; +#define mld_rej_uniform_eta_table MLD_NAMESPACE(rej_uniform_eta_table) +extern const uint8_t mld_rej_uniform_eta_table[]; + +#define mld_polyz_unpack_17_indices MLD_NAMESPACE(polyz_unpack_17_indices) +extern const uint8_t mld_polyz_unpack_17_indices[]; +#define mld_polyz_unpack_19_indices MLD_NAMESPACE(polyz_unpack_19_indices) +extern const uint8_t mld_polyz_unpack_19_indices[]; + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_ntt_asm MLD_NAMESPACE(ntt_asm) +void mld_ntt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_intt_asm MLD_NAMESPACE(intt_asm) +void mld_intt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_rej_uniform_asm MLD_NAMESPACE(rej_uniform_asm) +uint64_t mld_rej_uniform_asm(int32_t *r, const uint8_t *buf, unsigned buflen, + const uint8_t *table); + +#define mld_rej_uniform_eta2_asm MLD_NAMESPACE(rej_uniform_eta2_asm) +uint64_t mld_rej_uniform_eta2_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_rej_uniform_eta4_asm MLD_NAMESPACE(rej_uniform_eta4_asm) +uint64_t mld_rej_uniform_eta4_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_poly_decompose_32_asm MLD_NAMESPACE(poly_decompose_32_asm) +void mld_poly_decompose_32_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_asm MLD_NAMESPACE(poly_decompose_88_asm) +void mld_poly_decompose_88_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_asm MLD_NAMESPACE(poly_caddq_asm) +void mld_poly_caddq_asm(int32_t *a); + +#define mld_poly_use_hint_32_asm MLD_NAMESPACE(poly_use_hint_32_asm) +void mld_poly_use_hint_32_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_asm MLD_NAMESPACE(poly_use_hint_88_asm) +void mld_poly_use_hint_88_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_asm MLD_NAMESPACE(poly_chknorm_asm) +int mld_poly_chknorm_asm(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_asm MLD_NAMESPACE(polyz_unpack_17_asm) +void mld_polyz_unpack_17_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_polyz_unpack_19_asm MLD_NAMESPACE(polyz_unpack_19_asm) +void mld_polyz_unpack_19_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_poly_pointwise_montgomery_asm \ + MLD_NAMESPACE(poly_pointwise_montgomery_asm) +void mld_poly_pointwise_montgomery_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l4_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l4_asm) +void mld_polyvecl_pointwise_acc_montgomery_l4_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l5_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l5_asm) +void mld_polyvecl_pointwise_acc_montgomery_l5_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l7_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l7_asm) +void mld_polyvecl_pointwise_acc_montgomery_l7_asm(int32_t *, const int32_t *, + const int32_t *); + +#endif /* !MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c new file mode 100644 index 0000000000..7ef915b587 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* Table of indices used for tbl instructions in polyz_unpack_{17,19}. */ + +MLD_ALIGN const uint8_t mld_polyz_unpack_17_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, + 9, 10, 11, 255, 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, + 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, 8, 9, 10, 255, + 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, 17, 18, 19, 255, +}; + +MLD_ALIGN const uint8_t mld_polyz_unpack_19_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 5, 6, 7, 255, 7, 8, 9, 255, + 10, 11, 12, 255, 12, 13, 14, 255, 15, 16, 17, 255, 17, 18, 19, 255, + 4, 5, 6, 255, 6, 7, 8, 255, 9, 10, 11, 255, 11, 12, 13, 255, + 14, 15, 16, 255, 16, 17, 18, 255, 19, 20, 21, 255, 21, 22, 23, 255, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_polyz_unpack_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c new file mode 100644 index 0000000000..cf21509cbf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by 16-bit rejection sampling (rej_eta). + * Adapted from ML-KEM for ML-DSA eta rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_eta_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 2, 3, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 4, 5, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 2, 3, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 7 */, + 6, 7, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 2, 3, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 11 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 13 */, + 2, 3, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 15 */, + 8, 9, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 16 */, + 0, 1, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 17 */, + 2, 3, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 18 */, + 0, 1, 2, 3, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 19 */, + 4, 5, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 20 */, + 0, 1, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 21 */, + 2, 3, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 22 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 23 */, + 6, 7, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 24 */, + 0, 1, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 25 */, + 2, 3, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 26 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 27 */, + 4, 5, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 28 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 29 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 30 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 255, 255, 255, 255, 255, 255 /* 31 */, + 10, 11, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 32 */, + 0, 1, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 33 */, + 2, 3, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 34 */, + 0, 1, 2, 3, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 35 */, + 4, 5, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 36 */, + 0, 1, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 37 */, + 2, 3, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 38 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 39 */, + 6, 7, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 40 */, + 0, 1, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 41 */, + 2, 3, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 42 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 43 */, + 4, 5, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 44 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 45 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 46 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 255, 255, 255, 255, 255, 255 /* 47 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 48 */, + 0, 1, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 49 */, + 2, 3, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 50 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 51 */, + 4, 5, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 52 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 53 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 54 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 55 */, + 6, 7, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 56 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 57 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 58 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 59 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 60 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 61 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 62 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 63 */, + 12, 13, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 64 */, + 0, 1, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 65 */, + 2, 3, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 66 */, + 0, 1, 2, 3, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 67 */, + 4, 5, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 68 */, + 0, 1, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 69 */, + 2, 3, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 70 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 71 */, + 6, 7, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 72 */, + 0, 1, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 73 */, + 2, 3, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 74 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 75 */, + 4, 5, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 76 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 77 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 78 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 255, 255, 255, 255, 255, 255 /* 79 */, + 8, 9, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 80 */, + 0, 1, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 81 */, + 2, 3, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 82 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 83 */, + 4, 5, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 84 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 85 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 86 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 87 */, + 6, 7, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 88 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 89 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 90 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 91 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 92 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 93 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 94 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 255, 255, 255, 255 /* 95 */, + 10, 11, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 96 */, + 0, 1, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 97 */, + 2, 3, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 98 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 99 */, + 4, 5, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 100 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 101 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 102 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 103 */, + 6, 7, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 104 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 105 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 106 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 107 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 108 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 109 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 110 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 255, 255, 255, 255 /* 111 */, + 8, 9, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 112 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 113 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 114 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 115 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 116 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 117 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 118 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 119 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 120 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 121 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 122 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 123 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 124 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 125 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 126 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 255, 255 /* 127 */, + 14, 15, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 128 */, + 0, 1, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 129 */, + 2, 3, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 130 */, + 0, 1, 2, 3, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 131 */, + 4, 5, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 132 */, + 0, 1, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 133 */, + 2, 3, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 134 */, + 0, 1, 2, 3, 4, 5, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 135 */, + 6, 7, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 136 */, + 0, 1, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 137 */, + 2, 3, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 138 */, + 0, 1, 2, 3, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 139 */, + 4, 5, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 140 */, + 0, 1, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 141 */, + 2, 3, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 142 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 14, 15, 255, 255, 255, 255, 255, 255 /* 143 */, + 8, 9, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 144 */, + 0, 1, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 145 */, + 2, 3, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 146 */, + 0, 1, 2, 3, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 147 */, + 4, 5, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 148 */, + 0, 1, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 149 */, + 2, 3, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 150 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 151 */, + 6, 7, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 152 */, + 0, 1, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 153 */, + 2, 3, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 154 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 155 */, + 4, 5, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 156 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 157 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 158 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 14, 15, 255, 255, 255, 255 /* 159 */, + 10, 11, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 160 */, + 0, 1, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 161 */, + 2, 3, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 162 */, + 0, 1, 2, 3, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 163 */, + 4, 5, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 164 */, + 0, 1, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 165 */, + 2, 3, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 166 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 167 */, + 6, 7, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 168 */, + 0, 1, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 169 */, + 2, 3, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 170 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 171 */, + 4, 5, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 172 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 173 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 174 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 14, 15, 255, 255, 255, 255 /* 175 */, + 8, 9, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 176 */, + 0, 1, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 177 */, + 2, 3, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 178 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 179 */, + 4, 5, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 180 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 181 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 182 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 183 */, + 6, 7, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 184 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 185 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 186 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 187 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 188 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 189 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 190 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 14, 15, 255, 255 /* 191 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 192 */, + 0, 1, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 193 */, + 2, 3, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 194 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 195 */, + 4, 5, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 196 */, + 0, 1, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 197 */, + 2, 3, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 198 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 199 */, + 6, 7, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 200 */, + 0, 1, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 201 */, + 2, 3, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 202 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 203 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 204 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 205 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 206 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 207 */, + 8, 9, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 208 */, + 0, 1, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 209 */, + 2, 3, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 210 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 211 */, + 4, 5, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 212 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 213 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 214 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 215 */, + 6, 7, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 216 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 217 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 218 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 219 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 220 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 221 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 222 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 14, 15, 255, 255 /* 223 */, + 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 224 */, + 0, 1, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 225 */, + 2, 3, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 226 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 227 */, + 4, 5, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 228 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 229 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 230 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 231 */, + 6, 7, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 232 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 233 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 234 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 235 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 236 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 237 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 238 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 14, 15, 255, 255 /* 239 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 240 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 241 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 242 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 243 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 244 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 245 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 246 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 247 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 248 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 249 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 250 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 251 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 252 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 253 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 254 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 255 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_eta_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/src/rej_uniform_table.c new file mode 100644 index 0000000000..65bc3b78d3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/aarch64/src/rej_uniform_table.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by rejection sampling of the public matrix. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 7 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 11 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 13 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 15 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/api.h new file mode 100644 index 0000000000..0f1fdeb168 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/api.h @@ -0,0 +1,594 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_API_H +#define MLD_NATIVE_API_H +/* + * Native arithmetic interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + * + * To ensure consistency with backends, the header will be + * included automatically after inclusion of the active + * backend, to ensure consistency of function signatures, + * and run sanity checks. + */ + +#include +#include "../cbmc.h" +#include "../common.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* Bound on absolute value of coefficients after NTT. + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) + +/* Absolute exclusive upper bound for the output of the inverse NTT + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_INTT_BOUND MLDSA_Q + +/* Absolute bound for range of mld_reduce32() + * + * NOTE: This is the same bound as in reduce.h and has to be kept + * in sync. */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define REDUCE32_RANGE_MAX 6283009 +/* + * This is the C<->native interface allowing for the drop-in of + * native code for performance critical arithmetic components of ML-DSA. + * + * A _backend_ is a specific implementation of (part of) this interface. + * + * To add a function to a backend, define MLD_USE_NATIVE_XXX and + * implement `static inline xxx(...)` in the profile header. + */ + +/* + * Those functions are meant to be trivial wrappers around the chosen native + * implementation. The are static inline to avoid unnecessary calls. + * The macro before each declaration controls whether a native + * implementation is present. + */ + +#if defined(MLD_USE_NATIVE_NTT) +/************************************************* + * Name: mld_ntt_native + * + * Description: Computes negacyclic number-theoretic transform (NTT) of + * a polynomial in place. + * + * The input polynomial is assumed to be in normal order. + * The output polynomial is in bitreversed order. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_ntt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_NTT */ + + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) +/* + * This must only be set if NTT and INTT have native implementations + * that are adapted to the custom order. + */ +#if !defined(MLD_USE_NATIVE_NTT) || !defined(MLD_USE_NATIVE_INTT) +#error \ + "Invalid native profile: MLD_USE_NATIVE_NTT_CUSTOM_ORDER can only be \ +set if there are native implementations for NTT and INTT." +#endif + +/************************************************* + * Name: mlD_poly_permute_bitrev_to_custom + * + * Description: When MLD_USE_NATIVE_NTT_CUSTOM_ORDER is defined, + * convert a polynomial in NTT domain from bitreversed + * order to the custom order output by the native NTT. + * + * This must only be defined if there is native code for + * both the NTT and INTT. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + * + **************************************************/ +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t p[MLDSA_N]) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q))); +#endif /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + + +#if defined(MLD_USE_NATIVE_INTT) +/************************************************* + * Name: mld_intt_native + * + * Description: Computes inverse of negacyclic number-theoretic transform + *(NTT) of a polynomial in place. + * + * The input polynomial is in bitreversed order. + * The output polynomial is assumed to be in normal order. + * + * Arguments: - uint32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_intt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_INTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_INTT */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) +/************************************************* + * Name: mld_rej_uniform_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [0, MLDSA_Q-1] + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform mod q). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + * lengths. Otherwise, returns non-negative number of sampled 32-bit integers + * (at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= ( 5 * 168) && buflen % 3 == 0) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(r, 0, (unsigned) return_value, 0, MLDSA_Q)) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) +/************************************************* + * Name: mld_rej_uniform_eta2_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-2,+2]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-2, +2]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA2 */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) +/************************************************* + * Name: mld_rej_uniform_eta4_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-4,+4]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-4, +4]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) +/************************************************* + * Name: mld_poly_decompose_32_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/32. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: input/output polynomial. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_32 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) +/************************************************* + * Name: mld_poly_decompose_88_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/88. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: output polynomial with coefficients c0. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CADDQ) +/************************************************* + * Name: mld_poly_caddq_native + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *a: pointer to input/output polynomial + **************************************************/ +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_32) +/************************************************* + * Name: mld_poly_use_hint_32_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/32. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_32 */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) +/************************************************* + * Name: mld_poly_use_hint_88_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/88. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) +/************************************************* + * Name: mld_poly_chknorm_native + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const int32_t *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if the infinity norm is strictly smaller than B, and 1 + * otherwise. B must not be larger than MLDSA_Q - MLD_REDUCE32_RANGE_MAX. + **************************************************/ +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(0 <= B && B <= MLDSA_Q - REDUCE32_RANGE_MAX) + requires(array_bound(a, 0, MLDSA_N, -REDUCE32_RANGE_MAX, REDUCE32_RANGE_MAX)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == 0) == array_abs_bound(a, 0, MLDSA_N, B)) +); +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) +/************************************************* + * Name: mld_polyz_unpack_17_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^17. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_17 */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) +/************************************************* + * Name: mld_polyz_unpack_19_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^19. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_19 */ + +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) +/************************************************* + * Name: mld_poly_pointwise_montgomery_native + * + * Description: Pointwise multiplication of polynomials in NTT domain + * with Montgomery reduction. + * + * Computes c[i] = a[i] * b[i] * R^(-1) mod q for all i, + * where R = 2^32. + * + * Arguments: - int32_t c[MLDSA_N]: output polynomial + * - const int32_t a[MLDSA_N]: first input polynomial + * - const int32_t b[MLDSA_N]: second input polynomial + **************************************************/ +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(c, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(c, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(c, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l4_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 4. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 4 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 4 * MLDSA_N)) + requires(forall(l0, 0, 4, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 4, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l5_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 5. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 5 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 5 * MLDSA_N)) + requires(forall(l0, 0, 5, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 5, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l7_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 7. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 7 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 7 * MLDSA_N)) + requires(forall(l0, 0, 7, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 7, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 */ + +#endif /* !MLD_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/meta.h new file mode 100644 index 0000000000..0b46dd5791 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/meta.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_META_H +#define MLD_NATIVE_META_H + +/* + * Default arithmetic backend + */ +#include "../sys.h" + +#ifdef MLD_SYS_AARCH64 +#include "aarch64/meta.h" +#endif + +#ifdef MLD_SYS_X86_64_AVX2 +#include "x86_64/meta.h" +#endif + +#endif /* !MLD_NATIVE_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/meta.h new file mode 100644 index 0000000000..393374c06f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/meta.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_X86_64_META_H +#define MLD_NATIVE_X86_64_META_H + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_X86_64_DEFAULT + +#define MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +#if !defined(__ASSEMBLER__) +#include +#include "../../common.h" +#include "../api.h" +#include "src/arith_native_x86_64.h" + +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t data[MLDSA_N]) +{ + if (mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + mld_nttunpack_avx2(data); + } +} + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_ntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_invntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)mld_rej_uniform_avx2(r, buf); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_32_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_88_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_caddq_avx2(a); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_32_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_88_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + return mld_poly_chknorm_avx2(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_17_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_19_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_avx2(c, a, b, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l4_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l5_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l7_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_NATIVE_X86_64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h new file mode 100644 index 0000000000..08d5abf74a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#define MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#include "../../../common.h" + +#include +#include "consts.h" + +#define MLD_AVX2_REJ_UNIFORM_BUFLEN \ + (5 * 168) /* REJ_UNIFORM_NBLOCKS * SHAKE128_RATE */ + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) + +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_rej_uniform_table MLD_NAMESPACE(mld_rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[256][8]; + +#define mld_ntt_avx2 MLD_NAMESPACE(ntt_avx2) +void mld_ntt_avx2(int32_t *r, const int32_t *qdata) +/* This must be kept in sync with the HOL-Light specification + * in proofs/hol_light/x86_64/proofs/mldsa_ntt.ml */ +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, MLDSA_N, 8380417)) + requires(qdata == mld_qdata) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + /* check-magic: off */ + ensures(array_abs_bound(r, 0, MLDSA_N, 42035262)) + /* check-magic: on */ +); + +#define mld_invntt_avx2 MLD_NAMESPACE(invntt_avx2) +void mld_invntt_avx2(int32_t *r, const int32_t *mld_qdata); + +#define mld_nttunpack_avx2 MLD_NAMESPACE(nttunpack_avx2) +void mld_nttunpack_avx2(int32_t *r); + +#define mld_rej_uniform_avx2 MLD_NAMESPACE(mld_rej_uniform_avx2) +unsigned mld_rej_uniform_avx2(int32_t *r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]); + +#define mld_rej_uniform_eta2_avx2 MLD_NAMESPACE(mld_rej_uniform_eta2_avx2) +unsigned mld_rej_uniform_eta2_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]); + +#define mld_rej_uniform_eta4_avx2 MLD_NAMESPACE(mld_rej_uniform_eta4_avx2) +unsigned mld_rej_uniform_eta4_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]); + +#define mld_poly_decompose_32_avx2 MLD_NAMESPACE(mld_poly_decompose_32_avx2) +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_avx2 MLD_NAMESPACE(mld_poly_decompose_88_avx2) +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_avx2 MLD_NAMESPACE(poly_caddq_avx2) +void mld_poly_caddq_avx2(int32_t *r); + +#define mld_poly_use_hint_32_avx2 MLD_NAMESPACE(mld_poly_use_hint_32_avx2) +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_avx2 MLD_NAMESPACE(mld_poly_use_hint_88_avx2) +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_avx2 MLD_NAMESPACE(mld_poly_chknorm_avx2) +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_avx2 MLD_NAMESPACE(mld_polyz_unpack_17_avx2) +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a); + +#define mld_polyz_unpack_19_avx2 MLD_NAMESPACE(mld_polyz_unpack_19_avx2) +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a); + +#define mld_pointwise_avx2 MLD_NAMESPACE(pointwise_avx2) +void mld_pointwise_avx2(int32_t *c, const int32_t *a, const int32_t *b, + const int32_t *qdata); + +#define mld_pointwise_acc_l4_avx2 MLD_NAMESPACE(pointwise_acc_l4_avx2) +void mld_pointwise_acc_l4_avx2(int32_t c[MLDSA_N], const int32_t a[4][MLDSA_N], + const int32_t b[4][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l5_avx2 MLD_NAMESPACE(pointwise_acc_l5_avx2) +void mld_pointwise_acc_l5_avx2(int32_t c[MLDSA_N], const int32_t a[5][MLDSA_N], + const int32_t b[5][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l7_avx2 MLD_NAMESPACE(pointwise_acc_l7_avx2) +void mld_pointwise_acc_l7_avx2(int32_t c[MLDSA_N], const int32_t a[7][MLDSA_N], + const int32_t b[7][MLDSA_N], + const int32_t *qdata); + +#endif /* !MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/consts.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/consts.c new file mode 100644 index 0000000000..aaca3535ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/consts.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include "consts.h" + +/* + * Table of zeta values used in the AVX2 forward and inverse NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_qdata[624] = { + 8380417, 8380417, 8380417, 8380417, 8380417, + 8380417, 8380417, 8380417, 58728449, 58728449, + 58728449, 58728449, 58728449, 58728449, 58728449, + 58728449, -8395782, -8395782, -8395782, -8395782, + -8395782, -8395782, -8395782, -8395782, 41978, + 41978, 41978, 41978, 41978, 41978, + 41978, 41978, -151046689, 1830765815, -1929875198, + -1927777021, 1640767044, 1477910808, 1612161320, 1640734244, + 308362795, 308362795, 308362795, 308362795, -1815525077, + -1815525077, -1815525077, -1815525077, -1374673747, -1374673747, + -1374673747, -1374673747, -1091570561, -1091570561, -1091570561, + -1091570561, -1929495947, -1929495947, -1929495947, -1929495947, + 515185417, 515185417, 515185417, 515185417, -285697463, + -285697463, -285697463, -285697463, 625853735, 625853735, + 625853735, 625853735, 1727305304, 1727305304, 2082316400, + 2082316400, -1364982364, -1364982364, 858240904, 858240904, + 1806278032, 1806278032, 222489248, 222489248, -346752664, + -346752664, 684667771, 684667771, 1654287830, 1654287830, + -878576921, -878576921, -1257667337, -1257667337, -748618600, + -748618600, 329347125, 329347125, 1837364258, 1837364258, + -1443016191, -1443016191, -1170414139, -1170414139, -1846138265, + -1631226336, -1404529459, 1838055109, 1594295555, -1076973524, + -1898723372, -594436433, -202001019, -475984260, -561427818, + 1797021249, -1061813248, 2059733581, -1661512036, -1104976547, + -1750224323, -901666090, 418987550, 1831915353, -1925356481, + 992097815, 879957084, 2024403852, 1484874664, -1636082790, + -285388938, -1983539117, -1495136972, -950076368, -1714807468, + -952438995, -1574918427, 1350681039, -2143979939, 1599739335, + -1285853323, -993005454, -1440787840, 568627424, -783134478, + -588790216, 289871779, -1262003603, 2135294594, -1018755525, + -889861155, 1665705315, 1321868265, 1225434135, -1784632064, + 666258756, 675310538, -1555941048, -1999506068, -1499481951, + -695180180, -1375177022, 1777179795, 334803717, -178766299, + -518252220, 1957047970, 1146323031, -654783359, -1974159335, + 1651689966, 140455867, -1039411342, 1955560694, 1529189038, + -2131021878, -247357819, 1518161567, -86965173, 1708872713, + 1787797779, 1638590967, -120646188, -1669960606, -916321552, + 1155548552, 2143745726, 1210558298, -1261461890, -318346816, + 628664287, -1729304568, 1422575624, 1424130038, -1185330464, + 235321234, 168022240, 1206536194, 985155484, -894060583, + -898413, -1363460238, -605900043, 2027833504, 14253662, + 1014493059, 863641633, 1819892093, 2124962073, -1223601433, + -1920467227, -1637785316, -1536588520, 694382729, 235104446, + -1045062172, 831969619, -300448763, 756955444, -260312805, + 1554794072, 1339088280, -2040058690, -853476187, -2047270596, + -1723816713, -1591599803, -440824168, 1119856484, 1544891539, + 155290192, -973777462, 991903578, 912367099, -44694137, + 1176904444, -421552614, -818371958, 1747917558, -325927722, + 908452108, 1851023419, -1176751719, -1354528380, -72690498, + -314284737, 985022747, 963438279, -1078959975, 604552167, + -1021949428, 608791570, 173440395, -2126092136, -1316619236, + -1039370342, 6087993, -110126092, 565464272, -1758099917, + -1600929361, 879867909, -1809756372, 400711272, 1363007700, + 30313375, -326425360, 1683520342, -517299994, 2027935492, + -1372618620, 128353682, -1123881663, 137583815, -635454918, + -642772911, 45766801, 671509323, -2070602178, 419615363, + 1216882040, -270590488, -1276805128, 371462360, -1357098057, + -384158533, 827959816, -596344473, 702390549, -279505433, + -260424530, -71875110, -1208667171, -1499603926, 2036925262, + -540420426, 746144248, -1420958686, 2032221021, 1904936414, + 1257750362, 1926727420, 1931587462, 1258381762, 885133339, + 1629985060, 1967222129, 6363718, -1287922800, 1136965286, + 1779436847, 1116720494, 1042326957, 1405999311, 713994583, + 940195359, -1542497137, 2061661095, -883155599, 1726753853, + -1547952704, 394851342, 283780712, 776003547, 1123958025, + 201262505, 1934038751, 374860238, -3975713, 25847, + -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 1826347, 1826347, 1826347, + 2353451, 2353451, 2353451, 2353451, -359251, + -359251, -359251, -359251, -2091905, -2091905, + -2091905, -2091905, 3119733, 3119733, 3119733, + 3119733, -2884855, -2884855, -2884855, -2884855, + 3111497, 3111497, 3111497, 3111497, 2680103, + 2680103, 2680103, 2680103, 2725464, 2725464, + 1024112, 1024112, -1079900, -1079900, 3585928, + 3585928, -549488, -549488, -1119584, -1119584, + 2619752, 2619752, -2108549, -2108549, -2118186, + -2118186, -3859737, -3859737, -1399561, -1399561, + -3277672, -3277672, 1757237, 1757237, -19422, + -19422, 4010497, 4010497, 280005, 280005, + 2706023, 95776, 3077325, 3530437, -1661693, + -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, + -539299, -1699267, -1643818, 3505694, -3821735, + 3507263, -2140649, -1600420, 3699596, 811944, + 531354, 954230, 3881043, 3900724, -2556880, + 2071892, -2797779, -3930395, -3677745, -1452451, + 2176455, -1257611, -4083598, -3190144, -3632928, + 3412210, 2147896, -2967645, -411027, -671102, + -22981, -381987, 1852771, -3343383, 508951, + 44288, 904516, -3724342, 1653064, 2389356, + 759969, 189548, 3159746, -2409325, 1315589, + 1285669, -812732, -3019102, -3628969, -1528703, + -3041255, 3475950, -1585221, 1939314, -1000202, + -3157330, 126922, -983419, 2715295, -3693493, + -2477047, -1228525, -1308169, 1349076, -1430430, + 264944, 3097992, -1100098, 3958618, -8578, + -3249728, -210977, -1316856, -3553272, -1851402, + -177440, 1341330, -1584928, -1439742, -3881060, + 3839961, 2091667, -3342478, 266997, -3520352, + 900702, 495491, -655327, -3556995, 342297, + 3437287, 2842341, 4055324, -3767016, -2994039, + -1333058, -451100, -1279661, 1500165, -542412, + -2584293, -2013608, 1957272, -3183426, 810149, + -3038916, 2213111, -426683, -1667432, -2939036, + 183443, -554416, 3937738, 3407706, 2244091, + 2434439, -3759364, 1859098, -1613174, -3122442, + -525098, 286988, -3342277, 2691481, 1247620, + 1250494, 1869119, 1237275, 1312455, 1917081, + 777191, -2831860, -3724270, 2432395, 3369112, + 162844, 1652634, 3523897, -975884, 1723600, + -1104333, -2235985, -976891, 3919660, 1400424, + 2316500, -2446433, -1235728, -1197226, 909542, + -43260, 2031748, -768622, -2437823, 1735879, + -2590150, 2486353, 2635921, 1903435, -3318210, + 3306115, -2546312, 2235880, -1671176, 594136, + 2454455, 185531, 1616392, -3694233, 3866901, + 1717735, -1803090, -260646, -420899, 1612842, + -48306, -846154, 3817976, -3562462, 3513181, + -3193378, 819034, -522500, 3207046, -3595838, + 4108315, 203044, 1265009, 1595974, -3548272, + -1050970, -1430225, -1962642, -1374803, 3406031, + -1846953, -3776993, -164721, -1207385, 3014001, + -1799107, 269760, 472078, 1910376, -3833893, + -2286327, -3545687, -1362209, 1976782, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_consts) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/consts.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/consts.h new file mode 100644 index 0000000000..7fe08f454b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/consts.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#ifndef MLD_NATIVE_X86_64_SRC_CONSTS_H +#define MLD_NATIVE_X86_64_SRC_CONSTS_H +#include "../../../common.h" +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQ 0 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV 8 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV 16 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV 24 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV 32 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS 328 + +#ifndef __ASSEMBLER__ +#define mld_qdata MLD_NAMESPACE(qdata) +extern const int32_t mld_qdata[624]; +#endif + +#endif /* !MLD_NATIVE_X86_64_SRC_CONSTS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c new file mode 100644 index 0000000000..05d86d14fc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/************************************************* + * Name: mld_poly_caddq_avx2 + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *r: pointer to input/output polynomial + **************************************************/ +void mld_poly_caddq_avx2(int32_t *r) +{ + unsigned int i; + __m256i f, g; + const __m256i q = _mm256_set1_epi32(MLDSA_Q); + const __m256i zero = _mm256_setzero_si256(); + __m256i *rr = (__m256i *)r; + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256(&rr[i]); + g = _mm256_cmpgt_epi32(zero, f); + g = _mm256_and_si256(g, q); + f = _mm256_add_epi32(f, g); + _mm256_store_si256(&rr[i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_reduce) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c new file mode 100644 index 0000000000..50e2c7fa9b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B) +{ + unsigned int i; + __m256i f, t; + const __m256i bound = _mm256_set1_epi32(B - 1); + + t = _mm256_setzero_si256(); + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + f = _mm256_abs_epi32(f); + f = _mm256_cmpgt_epi32(f, bound); + t = _mm256_or_si256(t, f); + } + + return 1 - _mm256_testz_si256(t, t); +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_chknorm) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c new file mode 100644 index 0000000000..76846bf1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(31 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 4092 == intdiv(2 * intdiv(MLDSA_Q - 1, 32), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 4092. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 32*GAMMA2 = 16*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 16B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + * + * round(f1' * 1025 / 2^22) is in turn computed in 2 steps as + * round(floor(f1' * 1025 / 2^16) / 2^6). The mulhi computes f1'' = + * floor(f1' * 1025 / 2^16). As for the next step f1 = round(f1'' / 2^6), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^9) = round(f1'' * 2^9 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 1025 / 2^16) = 1025 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(16B / B) = 16 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 16, i.e. f > 31*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 31*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 15, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c new file mode 100644 index 0000000000..463506b962 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ + +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 1488 == intdiv(2 * intdiv(MLDSA_Q - 1, 88), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 1488. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 88*GAMMA2 = 44*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 44B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + * + * round(f1' * 11275 / 2^24) is in turn computed in 2 steps as + * round(floor(f1' * 11275 / 2^16) / 2^8). The mulhi computes f1'' = + * floor(f1' * 11275 / 2^16). As for the next step f1 = round(f1'' / 2^8), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^7) = round(f1'' * 2^7 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 11275 / 2^16) = 11275 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(44B / B) = 44 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 44, i.e. f > 87*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 87*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 43, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c new file mode 100644 index 0000000000..0094bc93a9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + const __m256i mask = _mm256_set1_epi32(15); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_32_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 16 */ + f1 = _mm256_add_epi32(f1, h); + f1 = _mm256_and_si256(f1, mask); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c new file mode 100644 index 0000000000..b109ab6351 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + const __m256i max = _mm256_set1_epi32(43); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_88_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 44 */ + f1 = _mm256_add_epi32(f1, h); + f1 = MLD_MM256_BLENDV_EPI32(f1, max, f1); + f = _mm256_cmpgt_epi32(f1, max); + f1 = MLD_MM256_BLENDV_EPI32(f1, zero, f); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c new file mode 100644 index 0000000000..f6c08a832f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 27, 26, 25, -1, 25, 24, 23, -1, 8, 7, + 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0); + const __m256i srlvdidx = _mm256_set_epi32(6, 4, 2, 0, 6, 4, 2, 0); + const __m256i mask = _mm256_set1_epi32(0x3FFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 17)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[18 * i]); + /* Load bytes 2..17 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[18 * i + 2]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-8 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 8, 7, 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte8, byte7, byte6, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,27, 26, 25, -1,25, 24, 23] │ + * │ Result: [0, byte17, byte16, byte15, ..., 0, byte11, byte10, byte9] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 18 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 32..55 48..71 + * 72..95 88..111 104..127 120..143 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 18..39 36..55 54..71 + * 72..95 90..111 108..127 126..143 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..17 18..35 36..53 54..71 + * 72..89 90..107 108..125 126..143 */ + + /* Map [0, 1, ..., 2^18-1] to [2^17, 2^17-1, ..., -2^17+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_17) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c new file mode 100644 index 0000000000..4a5ce48f38 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 26, 25, 24, -1, 24, 23, 22, -1, 9, 8, + 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0); + /* Equivalent to _mm256_set_epi32(4, 0, 4, 0, 4, 0, 4, 0) */ + const __m256i srlvdidx = _mm256_set1_epi64x((uint64_t)4 << 32); + const __m256i mask = _mm256_set1_epi32(0xFFFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 19)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[20 * i]); + /* Load bytes 4..19 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[20 * i + 4]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-9 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 9, 8, 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte9, byte8, byte7, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,26, 25, 24, -1,24, 23, 22] │ + * │ Result: [0, byte19, byte18, byte17, ..., 0, byte12, byte11, byte10] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 20 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 40..63 56..79 + * 80..103 96..119 120..143 136..159 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 20..39 40..63 60..79 + * 80..103 100..119 120..143 140..159 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..19 20..39 40..59 60..79 + * 80..99 100..119 120..139 140..159 */ + + /* Map [0, 1, ..., 2^20-1] to [2^19, 2^19-1, ..., -2^19+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_19) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c new file mode 100644 index 0000000000..07a5df9706 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The pqcrystals implementation assumes a buffer that is 8 bytes + *. larger as the first loop overreads by 8 bytes that are then + * discarded. We instead do not pad the buffer and do not overread. + * The performance impact is negligible and it does not force the + * frontend to perform the unintuitive padding. + */ + +unsigned int mld_rej_uniform_avx2( + int32_t *MLD_RESTRICT r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i d, tmp; + const __m256i bound = _mm256_set1_epi32(MLDSA_Q); + const __m256i mask = _mm256_set1_epi32(0x7FFFFF); + const __m256i idx8 = + _mm256_set_epi8(-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4, + -1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 32) + { + d = _mm256_loadu_si256((__m256i *)&buf[pos]); + + /* Permute 64-bit lanes + * 0x94 = 10010100b rearranges 64-bit lanes as: [3,2,1,0] -> [2,1,1,0] + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Original Layout ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ bytes 16..23 │ bytes 24..31 │ + * └─────────────────┴─────────────────┴─────────────────┴─────────────────┘ + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Layout after permute ║ + * ║ Byte indices in high half shifted down by 8 positions ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌───────────────┬─────────────────┐ ┌─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ │ bytes 8..15 │ bytes 16..23 │ + * └───────────────┴─────────────────┘ └─────────────────┴─────────────────┘ + * Lower 128-bit lane (bytes 0-15) Upper 128-bit lane (bytes 16-31) + */ + d = _mm256_permute4x64_epi64(d, 0x94); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-11 into low 128-bit half of permuted vector────────────────┐ + * │ Shuffle: [-1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0] │ + * │ Result: [0, byte11, byte10, byte9, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 4-15 into high 128-bit half of permuted vector ──────────────┐ + * │ Shuffle: [-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4] │ + * │ Result: [0, byte23, byte22, byte21, ..., 0, byte14, byte13, byte12 │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + d = _mm256_shuffle_epi8(d, idx8); + d = _mm256_and_si256(d, mask); + pos += 24; + + tmp = _mm256_sub_epi32(d, bound); + good = (uint32_t)_mm256_movemask_ps((__m256)tmp); + tmp = _mm256_cvtepu8_epi32( + _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good])); + d = _mm256_permutevar8x32_epi32(d, tmp); + + _mm256_storeu_si256((__m256i *)&r[ctr], d); + ctr += (unsigned)_mm_popcnt_u32(good); + } + + while (ctr < MLDSA_N && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 3) + { + uint32_t t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + /* Safe because t < MLDSA_Q. */ + r[ctr++] = (int32_t)t; + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c new file mode 100644 index 0000000000..70c5c42c70 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA2 2 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ +unsigned int mld_rej_uniform_eta2_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1, f2; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA2); + const __m256i bound = mask; + /* check-magic: -6560 == 32*round(-2**10 / 5) */ + const __m256i v = _mm256_set1_epi32(-6560); + const __m256i p = _mm256_set1_epi32(5); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 15) + { + t0 = t0 - (205 * t0 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t0); + } + if (t1 < 15 && ctr < MLDSA_N) + { + t1 = t1 - (205 * t1 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta2) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA2 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c new file mode 100644 index 0000000000..ba00e91252 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA4 4 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ + +unsigned int mld_rej_uniform_eta4_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA4); + const __m256i bound = _mm256_set1_epi8(9); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 9) + { + r[ctr++] = (int32_t)(4 - t0); + } + if (t1 < 9 && ctr < MLDSA_N) + { + r[ctr++] = (int32_t)(4 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta4) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA4 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/rej_uniform_table.c new file mode 100644 index 0000000000..6c537b4542 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/native/x86_64/src/rej_uniform_table.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" + +/* + * Lookup table used by rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[256][8] = { + {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, + {2, 0, 0, 0, 0, 0, 0, 0}, {0, 2, 0, 0, 0, 0, 0, 0}, + {1, 2, 0, 0, 0, 0, 0, 0}, {0, 1, 2, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 0, 0}, {0, 3, 0, 0, 0, 0, 0, 0}, + {1, 3, 0, 0, 0, 0, 0, 0}, {0, 1, 3, 0, 0, 0, 0, 0}, + {2, 3, 0, 0, 0, 0, 0, 0}, {0, 2, 3, 0, 0, 0, 0, 0}, + {1, 2, 3, 0, 0, 0, 0, 0}, {0, 1, 2, 3, 0, 0, 0, 0}, + {4, 0, 0, 0, 0, 0, 0, 0}, {0, 4, 0, 0, 0, 0, 0, 0}, + {1, 4, 0, 0, 0, 0, 0, 0}, {0, 1, 4, 0, 0, 0, 0, 0}, + {2, 4, 0, 0, 0, 0, 0, 0}, {0, 2, 4, 0, 0, 0, 0, 0}, + {1, 2, 4, 0, 0, 0, 0, 0}, {0, 1, 2, 4, 0, 0, 0, 0}, + {3, 4, 0, 0, 0, 0, 0, 0}, {0, 3, 4, 0, 0, 0, 0, 0}, + {1, 3, 4, 0, 0, 0, 0, 0}, {0, 1, 3, 4, 0, 0, 0, 0}, + {2, 3, 4, 0, 0, 0, 0, 0}, {0, 2, 3, 4, 0, 0, 0, 0}, + {1, 2, 3, 4, 0, 0, 0, 0}, {0, 1, 2, 3, 4, 0, 0, 0}, + {5, 0, 0, 0, 0, 0, 0, 0}, {0, 5, 0, 0, 0, 0, 0, 0}, + {1, 5, 0, 0, 0, 0, 0, 0}, {0, 1, 5, 0, 0, 0, 0, 0}, + {2, 5, 0, 0, 0, 0, 0, 0}, {0, 2, 5, 0, 0, 0, 0, 0}, + {1, 2, 5, 0, 0, 0, 0, 0}, {0, 1, 2, 5, 0, 0, 0, 0}, + {3, 5, 0, 0, 0, 0, 0, 0}, {0, 3, 5, 0, 0, 0, 0, 0}, + {1, 3, 5, 0, 0, 0, 0, 0}, {0, 1, 3, 5, 0, 0, 0, 0}, + {2, 3, 5, 0, 0, 0, 0, 0}, {0, 2, 3, 5, 0, 0, 0, 0}, + {1, 2, 3, 5, 0, 0, 0, 0}, {0, 1, 2, 3, 5, 0, 0, 0}, + {4, 5, 0, 0, 0, 0, 0, 0}, {0, 4, 5, 0, 0, 0, 0, 0}, + {1, 4, 5, 0, 0, 0, 0, 0}, {0, 1, 4, 5, 0, 0, 0, 0}, + {2, 4, 5, 0, 0, 0, 0, 0}, {0, 2, 4, 5, 0, 0, 0, 0}, + {1, 2, 4, 5, 0, 0, 0, 0}, {0, 1, 2, 4, 5, 0, 0, 0}, + {3, 4, 5, 0, 0, 0, 0, 0}, {0, 3, 4, 5, 0, 0, 0, 0}, + {1, 3, 4, 5, 0, 0, 0, 0}, {0, 1, 3, 4, 5, 0, 0, 0}, + {2, 3, 4, 5, 0, 0, 0, 0}, {0, 2, 3, 4, 5, 0, 0, 0}, + {1, 2, 3, 4, 5, 0, 0, 0}, {0, 1, 2, 3, 4, 5, 0, 0}, + {6, 0, 0, 0, 0, 0, 0, 0}, {0, 6, 0, 0, 0, 0, 0, 0}, + {1, 6, 0, 0, 0, 0, 0, 0}, {0, 1, 6, 0, 0, 0, 0, 0}, + {2, 6, 0, 0, 0, 0, 0, 0}, {0, 2, 6, 0, 0, 0, 0, 0}, + {1, 2, 6, 0, 0, 0, 0, 0}, {0, 1, 2, 6, 0, 0, 0, 0}, + {3, 6, 0, 0, 0, 0, 0, 0}, {0, 3, 6, 0, 0, 0, 0, 0}, + {1, 3, 6, 0, 0, 0, 0, 0}, {0, 1, 3, 6, 0, 0, 0, 0}, + {2, 3, 6, 0, 0, 0, 0, 0}, {0, 2, 3, 6, 0, 0, 0, 0}, + {1, 2, 3, 6, 0, 0, 0, 0}, {0, 1, 2, 3, 6, 0, 0, 0}, + {4, 6, 0, 0, 0, 0, 0, 0}, {0, 4, 6, 0, 0, 0, 0, 0}, + {1, 4, 6, 0, 0, 0, 0, 0}, {0, 1, 4, 6, 0, 0, 0, 0}, + {2, 4, 6, 0, 0, 0, 0, 0}, {0, 2, 4, 6, 0, 0, 0, 0}, + {1, 2, 4, 6, 0, 0, 0, 0}, {0, 1, 2, 4, 6, 0, 0, 0}, + {3, 4, 6, 0, 0, 0, 0, 0}, {0, 3, 4, 6, 0, 0, 0, 0}, + {1, 3, 4, 6, 0, 0, 0, 0}, {0, 1, 3, 4, 6, 0, 0, 0}, + {2, 3, 4, 6, 0, 0, 0, 0}, {0, 2, 3, 4, 6, 0, 0, 0}, + {1, 2, 3, 4, 6, 0, 0, 0}, {0, 1, 2, 3, 4, 6, 0, 0}, + {5, 6, 0, 0, 0, 0, 0, 0}, {0, 5, 6, 0, 0, 0, 0, 0}, + {1, 5, 6, 0, 0, 0, 0, 0}, {0, 1, 5, 6, 0, 0, 0, 0}, + {2, 5, 6, 0, 0, 0, 0, 0}, {0, 2, 5, 6, 0, 0, 0, 0}, + {1, 2, 5, 6, 0, 0, 0, 0}, {0, 1, 2, 5, 6, 0, 0, 0}, + {3, 5, 6, 0, 0, 0, 0, 0}, {0, 3, 5, 6, 0, 0, 0, 0}, + {1, 3, 5, 6, 0, 0, 0, 0}, {0, 1, 3, 5, 6, 0, 0, 0}, + {2, 3, 5, 6, 0, 0, 0, 0}, {0, 2, 3, 5, 6, 0, 0, 0}, + {1, 2, 3, 5, 6, 0, 0, 0}, {0, 1, 2, 3, 5, 6, 0, 0}, + {4, 5, 6, 0, 0, 0, 0, 0}, {0, 4, 5, 6, 0, 0, 0, 0}, + {1, 4, 5, 6, 0, 0, 0, 0}, {0, 1, 4, 5, 6, 0, 0, 0}, + {2, 4, 5, 6, 0, 0, 0, 0}, {0, 2, 4, 5, 6, 0, 0, 0}, + {1, 2, 4, 5, 6, 0, 0, 0}, {0, 1, 2, 4, 5, 6, 0, 0}, + {3, 4, 5, 6, 0, 0, 0, 0}, {0, 3, 4, 5, 6, 0, 0, 0}, + {1, 3, 4, 5, 6, 0, 0, 0}, {0, 1, 3, 4, 5, 6, 0, 0}, + {2, 3, 4, 5, 6, 0, 0, 0}, {0, 2, 3, 4, 5, 6, 0, 0}, + {1, 2, 3, 4, 5, 6, 0, 0}, {0, 1, 2, 3, 4, 5, 6, 0}, + {7, 0, 0, 0, 0, 0, 0, 0}, {0, 7, 0, 0, 0, 0, 0, 0}, + {1, 7, 0, 0, 0, 0, 0, 0}, {0, 1, 7, 0, 0, 0, 0, 0}, + {2, 7, 0, 0, 0, 0, 0, 0}, {0, 2, 7, 0, 0, 0, 0, 0}, + {1, 2, 7, 0, 0, 0, 0, 0}, {0, 1, 2, 7, 0, 0, 0, 0}, + {3, 7, 0, 0, 0, 0, 0, 0}, {0, 3, 7, 0, 0, 0, 0, 0}, + {1, 3, 7, 0, 0, 0, 0, 0}, {0, 1, 3, 7, 0, 0, 0, 0}, + {2, 3, 7, 0, 0, 0, 0, 0}, {0, 2, 3, 7, 0, 0, 0, 0}, + {1, 2, 3, 7, 0, 0, 0, 0}, {0, 1, 2, 3, 7, 0, 0, 0}, + {4, 7, 0, 0, 0, 0, 0, 0}, {0, 4, 7, 0, 0, 0, 0, 0}, + {1, 4, 7, 0, 0, 0, 0, 0}, {0, 1, 4, 7, 0, 0, 0, 0}, + {2, 4, 7, 0, 0, 0, 0, 0}, {0, 2, 4, 7, 0, 0, 0, 0}, + {1, 2, 4, 7, 0, 0, 0, 0}, {0, 1, 2, 4, 7, 0, 0, 0}, + {3, 4, 7, 0, 0, 0, 0, 0}, {0, 3, 4, 7, 0, 0, 0, 0}, + {1, 3, 4, 7, 0, 0, 0, 0}, {0, 1, 3, 4, 7, 0, 0, 0}, + {2, 3, 4, 7, 0, 0, 0, 0}, {0, 2, 3, 4, 7, 0, 0, 0}, + {1, 2, 3, 4, 7, 0, 0, 0}, {0, 1, 2, 3, 4, 7, 0, 0}, + {5, 7, 0, 0, 0, 0, 0, 0}, {0, 5, 7, 0, 0, 0, 0, 0}, + {1, 5, 7, 0, 0, 0, 0, 0}, {0, 1, 5, 7, 0, 0, 0, 0}, + {2, 5, 7, 0, 0, 0, 0, 0}, {0, 2, 5, 7, 0, 0, 0, 0}, + {1, 2, 5, 7, 0, 0, 0, 0}, {0, 1, 2, 5, 7, 0, 0, 0}, + {3, 5, 7, 0, 0, 0, 0, 0}, {0, 3, 5, 7, 0, 0, 0, 0}, + {1, 3, 5, 7, 0, 0, 0, 0}, {0, 1, 3, 5, 7, 0, 0, 0}, + {2, 3, 5, 7, 0, 0, 0, 0}, {0, 2, 3, 5, 7, 0, 0, 0}, + {1, 2, 3, 5, 7, 0, 0, 0}, {0, 1, 2, 3, 5, 7, 0, 0}, + {4, 5, 7, 0, 0, 0, 0, 0}, {0, 4, 5, 7, 0, 0, 0, 0}, + {1, 4, 5, 7, 0, 0, 0, 0}, {0, 1, 4, 5, 7, 0, 0, 0}, + {2, 4, 5, 7, 0, 0, 0, 0}, {0, 2, 4, 5, 7, 0, 0, 0}, + {1, 2, 4, 5, 7, 0, 0, 0}, {0, 1, 2, 4, 5, 7, 0, 0}, + {3, 4, 5, 7, 0, 0, 0, 0}, {0, 3, 4, 5, 7, 0, 0, 0}, + {1, 3, 4, 5, 7, 0, 0, 0}, {0, 1, 3, 4, 5, 7, 0, 0}, + {2, 3, 4, 5, 7, 0, 0, 0}, {0, 2, 3, 4, 5, 7, 0, 0}, + {1, 2, 3, 4, 5, 7, 0, 0}, {0, 1, 2, 3, 4, 5, 7, 0}, + {6, 7, 0, 0, 0, 0, 0, 0}, {0, 6, 7, 0, 0, 0, 0, 0}, + {1, 6, 7, 0, 0, 0, 0, 0}, {0, 1, 6, 7, 0, 0, 0, 0}, + {2, 6, 7, 0, 0, 0, 0, 0}, {0, 2, 6, 7, 0, 0, 0, 0}, + {1, 2, 6, 7, 0, 0, 0, 0}, {0, 1, 2, 6, 7, 0, 0, 0}, + {3, 6, 7, 0, 0, 0, 0, 0}, {0, 3, 6, 7, 0, 0, 0, 0}, + {1, 3, 6, 7, 0, 0, 0, 0}, {0, 1, 3, 6, 7, 0, 0, 0}, + {2, 3, 6, 7, 0, 0, 0, 0}, {0, 2, 3, 6, 7, 0, 0, 0}, + {1, 2, 3, 6, 7, 0, 0, 0}, {0, 1, 2, 3, 6, 7, 0, 0}, + {4, 6, 7, 0, 0, 0, 0, 0}, {0, 4, 6, 7, 0, 0, 0, 0}, + {1, 4, 6, 7, 0, 0, 0, 0}, {0, 1, 4, 6, 7, 0, 0, 0}, + {2, 4, 6, 7, 0, 0, 0, 0}, {0, 2, 4, 6, 7, 0, 0, 0}, + {1, 2, 4, 6, 7, 0, 0, 0}, {0, 1, 2, 4, 6, 7, 0, 0}, + {3, 4, 6, 7, 0, 0, 0, 0}, {0, 3, 4, 6, 7, 0, 0, 0}, + {1, 3, 4, 6, 7, 0, 0, 0}, {0, 1, 3, 4, 6, 7, 0, 0}, + {2, 3, 4, 6, 7, 0, 0, 0}, {0, 2, 3, 4, 6, 7, 0, 0}, + {1, 2, 3, 4, 6, 7, 0, 0}, {0, 1, 2, 3, 4, 6, 7, 0}, + {5, 6, 7, 0, 0, 0, 0, 0}, {0, 5, 6, 7, 0, 0, 0, 0}, + {1, 5, 6, 7, 0, 0, 0, 0}, {0, 1, 5, 6, 7, 0, 0, 0}, + {2, 5, 6, 7, 0, 0, 0, 0}, {0, 2, 5, 6, 7, 0, 0, 0}, + {1, 2, 5, 6, 7, 0, 0, 0}, {0, 1, 2, 5, 6, 7, 0, 0}, + {3, 5, 6, 7, 0, 0, 0, 0}, {0, 3, 5, 6, 7, 0, 0, 0}, + {1, 3, 5, 6, 7, 0, 0, 0}, {0, 1, 3, 5, 6, 7, 0, 0}, + {2, 3, 5, 6, 7, 0, 0, 0}, {0, 2, 3, 5, 6, 7, 0, 0}, + {1, 2, 3, 5, 6, 7, 0, 0}, {0, 1, 2, 3, 5, 6, 7, 0}, + {4, 5, 6, 7, 0, 0, 0, 0}, {0, 4, 5, 6, 7, 0, 0, 0}, + {1, 4, 5, 6, 7, 0, 0, 0}, {0, 1, 4, 5, 6, 7, 0, 0}, + {2, 4, 5, 6, 7, 0, 0, 0}, {0, 2, 4, 5, 6, 7, 0, 0}, + {1, 2, 4, 5, 6, 7, 0, 0}, {0, 1, 2, 4, 5, 6, 7, 0}, + {3, 4, 5, 6, 7, 0, 0, 0}, {0, 3, 4, 5, 6, 7, 0, 0}, + {1, 3, 4, 5, 6, 7, 0, 0}, {0, 1, 3, 4, 5, 6, 7, 0}, + {2, 3, 4, 5, 6, 7, 0, 0}, {0, 2, 3, 4, 5, 6, 7, 0}, + {1, 2, 3, 4, 5, 6, 7, 0}, {0, 1, 2, 3, 4, 5, 6, 7}, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/packing.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/packing.c new file mode 100644 index 0000000000..26da273856 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/packing.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include + +#include "common.h" +#include "packing.h" +#include "poly.h" +#include "polyvec.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_unpack_hints MLD_ADD_PARAM_SET(mld_unpack_hints) +/* End of parameter set namespacing */ + +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +{ + unsigned int i; + + mld_memcpy(pk, rho, MLDSA_SEEDBYTES); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt1_pack(pk + MLDSA_SEEDBYTES + i * MLDSA_POLYT1_PACKEDBYTES, + &t1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +{ + unsigned int i; + + mld_memcpy(rho, pk, MLDSA_SEEDBYTES); + pk += MLDSA_SEEDBYTES; + + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt1_unpack(&t1->vec[i], pk + i * MLDSA_POLYT1_PACKEDBYTES); + } +} + +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +{ + mld_memcpy(sk, rho, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, key, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, tr, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_pack_eta(sk, s1); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_eta(sk, s2); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_t0(sk, t0); +} + +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +{ + mld_memcpy(rho, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(key, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(tr, sk, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_unpack_eta(s1, sk); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_eta(s2, sk); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_t0(t0, sk); +} + +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +{ + unsigned int i, j, k; + + mld_memcpy(sig, c, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + /* skip z component - packed via mld_pack_sig_z */ + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + /* Encode hints h */ + + /* The final section of sig[] is MLDSA_POLYVECH_PACKEDBYTES long, where + * MLDSA_POLYVECH_PACKEDBYTES = MLDSA_OMEGA + MLDSA_K + * + * The first OMEGA bytes record the index numbers of the coefficients + * that are not equal to 0 + * + * The final K bytes record a running tally of the number of hints + * coming from each of the K polynomials in h. + * + * The pre-condition tells us that number_of_hints <= OMEGA, so some + * bytes may not be written, so we initialize all of them to zero + * to start. + */ + mld_memset(sig, 0, MLDSA_POLYVECH_PACKEDBYTES); + + k = 0; + /* For each polynomial in h... */ + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* For each coefficient in that polynomial, record it as as hint */ + /* if its value is not zero */ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + assigns(j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(j <= MLDSA_N) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* The reference implementation implicitly relies on the total */ + /* number of hints being less than OMEGA, assuming h is valid. */ + /* In mldsa-native, we check this explicitly to ease proof of */ + /* type safety. */ + if (h->vec[i].coeffs[j] != 0 && k < number_of_hints) + { + /* The enclosing if condition AND the loop invariant infer */ + /* that k < MLDSA_OMEGA, so writing to sig[k] is safe and k */ + /* can be incremented. */ + sig[k++] = (uint8_t)j; + } + } + /* Having recorded all the hints for this polynomial, also */ + /* record the running tally into the correct "slot" for that */ + /* coefficient in the final K bytes */ + sig[MLDSA_OMEGA + i] = (uint8_t)k; + } +} + +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +{ + sig += MLDSA_CTILDEBYTES; + sig += i * MLDSA_POLYZ_PACKEDBYTES; + mld_polyz_pack(sig, zi); +} + +/************************************************* + * Name: mld_unpack_hints + * + * Description: Unpack raw hint bytes into a polyveck + * struct + * + * Arguments: - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]: + * raw hint bytes + * + * Returns 1 in case of malformed hints; otherwise 0. + **************************************************/ +static int mld_unpack_hints( + mld_polyveck *h, const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(packed_hints, MLDSA_POLYVECH_PACKEDBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + /* All returned coefficients are either 0 or 1 */ + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +) +{ + unsigned int i, j; + unsigned int old_hint_count; + + /* Set all coefficients of all polynomials to 0. */ + /* Only those that are actually non-zero hints will */ + /* be overwritten below. */ + mld_memset(h, 0, sizeof(mld_polyveck)); + + old_hint_count = 0; + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + /* Grab the hint count for the i'th polynomial */ + const unsigned int new_hint_count = packed_hints[MLDSA_OMEGA + i]; + + /* new_hint_count must increase or stay the same, but also remain */ + /* less than or equal to MLDSA_OMEGA */ + if (new_hint_count < old_hint_count || new_hint_count > MLDSA_OMEGA) + { + /* Error - new_hint_count is invalid */ + return 1; + } + + /* If new_hint_count == old_hint_count, then this polynomial has */ + /* zero hints, so this loop executes zero times and we move */ + /* straight on to the next polynomial. */ + for (j = old_hint_count; j < new_hint_count; ++j) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + const uint8_t this_hint_index = packed_hints[j]; + + /* Coefficients must be ordered for strong unforgeability */ + if (j > old_hint_count && this_hint_index <= packed_hints[j - 1]) + { + return 1; + } + h->vec[i].coeffs[this_hint_index] = 1; + } + + old_hint_count = new_hint_count; + } + + /* Extra indices must be zero for strong unforgeability */ + for (j = old_hint_count; j < MLDSA_OMEGA; ++j) + __loop__( + invariant(j <= MLDSA_OMEGA) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + if (packed_hints[j] != 0) + { + return 1; + } + } + + return 0; +} + +MLD_INTERNAL_API +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +{ + mld_memcpy(c, sig, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + mld_polyvecl_unpack_z(z, sig); + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + return mld_unpack_hints(h, sig); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_unpack_hints diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/packing.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/packing.h new file mode 100644 index 0000000000..19095d08cd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/packing.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PACKING_H +#define MLD_PACKING_H + +#include +#include "polyvec.h" + +#define mld_pack_pk MLD_NAMESPACE_KL(pack_pk) +/************************************************* + * Name: mld_pack_pk + * + * Description: Bit-pack public key pk = (rho, t1). + * + * Arguments: - uint8_t pk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const mld_polyveck *t1: pointer to vector t1 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) +); + + +#define mld_pack_sk MLD_NAMESPACE_KL(pack_sk) +/************************************************* + * Name: mld_pack_sk + * + * Description: Bit-pack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - uint8_t sk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const uint8_t tr[]: byte array containing tr + * - const uint8_t key[]: byte array containing key + * - const mld_polyveck *t0: pointer to vector t0 + * - const mld_polyvecl *s1: pointer to vector s1 + * - const mld_polyveck *s2: pointer to vector s2 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +__contract__( + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + requires(forall(k2, 0, MLDSA_K, + array_abs_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) +); + + +#define mld_pack_sig_c_h MLD_NAMESPACE_KL(pack_sig_c_h) +/************************************************* + * Name: mld_pack_sig_c_h + * + * Description: Bit-pack c and h component of sig = (c, z, h). + * The z component is packed separately using mld_pack_sig_z. + * + * Arguments: - uint8_t sig[]: output byte array + * - const uint8_t *c: pointer to challenge hash length + * MLDSA_SEEDBYTES + * - const mld_polyveck *h: pointer to hint vector h + * - const unsigned int number_of_hints: total + * hints in *h + * + * Note that the number_of_hints argument is not present + * in the reference implementation. It is added here to ease + * proof of type safety. + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + requires(number_of_hints <= MLDSA_OMEGA) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_pack_sig_z MLD_NAMESPACE_KL(pack_sig_z) +/************************************************* + * Name: mld_pack_sig_z + * + * Description: Bit-pack single polynomial of z component of sig = (c, z, h). + * The c and h components are packed separately using + * mld_pack_sig_c_h. + * + * Arguments: - uint8_t sig[]: output byte array + * - const mld_poly *zi: pointer to a single polynomial in z + * - const unsigned int i: index of zi in vector z + * + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(zi, sizeof(mld_poly))) + requires(i < MLDSA_L) + requires(array_bound(zi->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_unpack_pk MLD_NAMESPACE_KL(unpack_pk) +/************************************************* + * Name: mld_unpack_pk + * + * Description: Unpack public key pk = (rho, t1). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const mld_polyveck *t1: pointer to output vector t1 + * - uint8_t pk[]: byte array containing bit-packed pk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) +); + + +#define mld_unpack_sk MLD_NAMESPACE_KL(unpack_sk) +/************************************************* + * Name: mld_unpack_sk + * + * Description: Unpack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const uint8_t tr[]: output byte array for tr + * - const uint8_t key[]: output byte array for key + * - const mld_polyveck *t0: pointer to output vector t0 + * - const mld_polyvecl *s1: pointer to output vector s1 + * - const mld_polyveck *s2: pointer to output vector s2 + * - uint8_t sk[]: byte array containing bit-packed sk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +__contract__( + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(key, MLDSA_SEEDBYTES)) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(s1, sizeof(mld_polyvecl))) + assigns(memory_slice(s2, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_unpack_sig MLD_NAMESPACE_KL(unpack_sig) +/************************************************* + * Name: mld_unpack_sig + * + * Description: Unpack signature sig = (c, z, h). + * + * Arguments: - uint8_t *c: pointer to output challenge hash + * - mld_polyvecl *z: pointer to output vector z + * - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t sig[]: byte array containing + * bit-packed signature + * + * Returns 1 in case of malformed signature; otherwise 0. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(c, MLDSA_CTILDEBYTES)) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(z->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +); +#endif /* !MLD_PACKING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/params.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/params.h new file mode 100644 index 0000000000..c67d2a33fb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/params.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PARAMS_H +#define MLD_PARAMS_H + +#define MLDSA_SEEDBYTES 32 +#define MLDSA_CRHBYTES 64 +#define MLDSA_TRBYTES 64 +#define MLDSA_RNDBYTES 32 +#define MLDSA_N 256 +#define MLDSA_Q 8380417 +#define MLDSA_Q_HALF ((MLDSA_Q + 1) / 2) +#define MLDSA_D 13 + +#if MLD_CONFIG_PARAMETER_SET == 44 + +#define MLDSA_K 4 +#define MLDSA_L 4 +#define MLDSA_ETA 2 +#define MLDSA_TAU 39 +#define MLDSA_BETA 78 +#define MLDSA_GAMMA1 (1 << 17) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 88) +#define MLDSA_OMEGA 80 +#define MLDSA_CTILDEBYTES 32 +#define MLDSA_POLYZ_PACKEDBYTES 576 +#define MLDSA_POLYW1_PACKEDBYTES 192 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#elif MLD_CONFIG_PARAMETER_SET == 65 + +#define MLDSA_K 6 +#define MLDSA_L 5 +#define MLDSA_ETA 4 +#define MLDSA_TAU 49 +#define MLDSA_BETA 196 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 55 +#define MLDSA_CTILDEBYTES 48 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 128 + +#elif MLD_CONFIG_PARAMETER_SET == 87 + +#define MLDSA_K 8 +#define MLDSA_L 7 +#define MLDSA_ETA 2 +#define MLDSA_TAU 60 +#define MLDSA_BETA 120 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 75 +#define MLDSA_CTILDEBYTES 64 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ + +#define MLDSA_POLYT1_PACKEDBYTES 320 +#define MLDSA_POLYT0_PACKEDBYTES 416 +#define MLDSA_POLYVECH_PACKEDBYTES (MLDSA_OMEGA + MLDSA_K) + +#define MLDSA_CRYPTO_PUBLICKEYBYTES \ + (MLDSA_SEEDBYTES + MLDSA_K * MLDSA_POLYT1_PACKEDBYTES) +#define MLDSA_CRYPTO_SECRETKEYBYTES \ + (2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + MLDSA_L * MLDSA_POLYETA_PACKEDBYTES + \ + MLDSA_K * MLDSA_POLYETA_PACKEDBYTES + MLDSA_K * MLDSA_POLYT0_PACKEDBYTES) +#define MLDSA_CRYPTO_BYTES \ + (MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES + \ + MLDSA_POLYVECH_PACKEDBYTES) + +#endif /* !MLD_PARAMS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/poly.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/poly.c new file mode 100644 index 0000000000..e40534e773 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/poly.c @@ -0,0 +1,973 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "common.h" +#include "ct.h" +#include "debug.h" +#include "poly.h" +#include "reduce.h" +#include "rounding.h" +#include "symmetric.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +#include "zetas.inc" + +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + { + a->coeffs[i] = mld_reduce32(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_STATIC_TESTABLE void mld_poly_caddq_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + ) + { + a->coeffs[i] = mld_caddq(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_POLY_CADDQ) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_poly_caddq_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + mld_poly_caddq_c(a); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1])) + invariant(forall(k2, 0, i, r->coeffs[k2] < MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k2, 0, i, r->coeffs[k2] >= INT32_MIN)) + ) + { + r->coeffs[i] = r->coeffs[i] + b->coeffs[i]; + } +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(r->coeffs, 0, i, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + ) + { + r->coeffs[i] = r->coeffs[i] - b->coeffs[i]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N; i++) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))) + { + /* Reference: uses a left shift by MLDSA_D which is undefined behaviour in + * C90/C99 + */ + a->coeffs[i] *= (1 << MLDSA_D); + } + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + + +static MLD_INLINE int32_t mld_fqmul(int32_t a, int32_t b) +__contract__( + requires(b > -MLDSA_Q_HALF && b < MLDSA_Q_HALF) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* Bounds: We argue in mld_montgomery_reduce() that the reult + * of Montgomery reduction is < MLDSA_Q if the input is smaller + * than 2^31 * MLDSA_Q in absolute value. Indeed, we have: + * + * |a * b| = |a| * |b| + * < 2^31 * MLDSA_Q_HALF + * < 2^31 * MLDSA_Q + */ + return mld_montgomery_reduce((int64_t)a * (int64_t)b); +} + +/* mld_ntt_butterfly_block() + * + * Computes a block CT butterflies with a fixed twiddle factor, + * using Montgomery multiplication. + * + * Parameters: + * - r: Pointer to base of polynomial (_not_ the base of butterfly block) + * - zeta: Twiddle factor to use for the butterfly. This must be in + * Montgomery form and signed canonical. + * - start: Offset to the beginning of the butterfly block + * - len: Index difference between coefficients subject to a butterfly + * - bound: Ghost variable describing coefficient bound: Prior to `start`, + * coefficients must be bound by `bound + MLDSA_Q`. Post `start`, + * they must be bound by `bound`. + * When this function returns, output coefficients in the index range + * [start, start+2*len) have bound bumped to `bound + MLDSA_Q`. + * Example: + * - start=8, len=4 + * This would compute the following four butterflies + * 8 -- 12 + * 9 -- 13 + * 10 -- 14 + * 11 -- 15 + * - start=4, len=2 + * This would compute the following two butterflies + * 4 -- 6 + * 5 -- 7 + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_butterfly_block(int32_t r[MLDSA_N], + const int32_t zeta, + const unsigned start, + const unsigned len, + const unsigned bound) +__contract__( + requires(start < MLDSA_N) + requires(1 <= len && len <= MLDSA_N / 2 && start + 2 * len <= MLDSA_N) + requires(0 <= bound && bound < INT32_MAX - MLDSA_Q) + requires(-MLDSA_Q_HALF < zeta && zeta < MLDSA_Q_HALF) + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, start, bound + MLDSA_Q)) + requires(array_abs_bound(r, start, MLDSA_N, bound)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, start + 2*len, bound + MLDSA_Q)) + ensures(array_abs_bound(r, start + 2 * len, MLDSA_N, bound))) +{ + /* `bound` is a ghost variable only needed in the CBMC specification */ + unsigned j; + ((void)bound); + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + /* + * Coefficients are updated in strided pairs, so the bounds for the + * intermediate states alternate twice between the old and new bound + */ + invariant(array_abs_bound(r, 0, j, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, bound)) + invariant(array_abs_bound(r, start + len, j + len, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j + len, MLDSA_N, bound))) + { + int32_t t; + t = mld_fqmul(r[j + len], zeta); + r[j + len] = r[j] - t; + r[j] = r[j] + t; + } +} + +/* mld_ntt_layer() + * + * Compute one layer of forward NTT + * + * Parameters: + * - r: Pointer to base of polynomial + * - layer: Indicates which layer is being applied. + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_layer(int32_t r[MLDSA_N], const unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (layer + 1) * MLDSA_Q))) +{ + unsigned start, k, len; + /* Twiddle factors for layer n are at indices 2^(n-1)..2^n-1. */ + k = 1u << (layer - 1); + len = (unsigned)MLDSA_N >> layer; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start < MLDSA_N + 2 * len) + invariant(k <= MLDSA_N) + invariant(2 * len * k == start + MLDSA_N) + invariant(array_abs_bound(r, 0, start, layer * MLDSA_Q + MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, layer * MLDSA_Q))) + { + int32_t zeta = mld_zetas[k++]; + mld_ntt_butterfly_block(r, zeta, start, len, layer * MLDSA_Q); + } +} + +MLD_STATIC_TESTABLE void mld_poly_ntt_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +) +{ + unsigned int layer; + int32_t *r; + + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + r = a->coeffs; + + for (layer = 1; layer < 9; layer++) + __loop__( + invariant(1 <= layer && layer <= 9) + invariant(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + ) + { + mld_ntt_layer(r, layer); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_NTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_ntt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_NTT */ + mld_poly_ntt_c(a); +} + +/************************************************* + * Name: mld_fqscale + * + * Description: Scales a field element by mont/256 , i.e., performs Montgomery + * multiplication by mont^2/256. + * Input is expected to have absolute value smaller than + * 256 * MLDSA_Q. + * Output has absolute value smaller than MLD_INTT_BOUND. + * + * Arguments: - int32_t a: Field element to be scaled. + **************************************************/ +static MLD_INLINE int32_t mld_fqscale(int32_t a) +__contract__( + requires(a > -256*MLDSA_Q && a < 256*MLDSA_Q) + ensures(return_value > -MLD_INTT_BOUND && return_value < MLD_INTT_BOUND) +) +{ + /* check-magic: 41978 == pow(2,64-8,MLDSA_Q) */ + const int32_t f = 41978; + /* Bounds: MLD_INTT_BOUND is MLDSA_Q, so the bounds reasoning is just + * a special case of that in mld_fqmul(). */ + return mld_montgomery_reduce((int64_t)a * f); +} + +/* Reference: Embedded into `invntt_tomont()` in the reference implementation + * @[REF] */ +static MLD_INLINE void mld_invntt_layer(int32_t r[MLDSA_N], unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> (layer - 1)) * MLDSA_Q))) +{ + unsigned start, k, len; + len = (unsigned)MLDSA_N >> layer; + k = (1u << layer) - 1; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start <= MLDSA_N && k <= 255) + invariant(2 * len * k + start == 2 * MLDSA_N - 2 * len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + unsigned j; + int32_t zeta = -mld_zetas[k--]; + + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, j, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, (MLDSA_N >> layer) * MLDSA_Q)) + invariant(array_abs_bound(r, start + len, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + int32_t t = r[j]; + r[j] = t + r[j + len]; + r[j + len] = t - r[j + len]; + r[j + len] = mld_fqmul(r[j + len], zeta); + } + } +} + +MLD_STATIC_TESTABLE void mld_poly_invntt_tomont_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +) +{ + unsigned int layer, j; + int32_t *r; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + r = a->coeffs; + for (layer = 8; layer >= 1; layer--) + __loop__( + invariant(layer <= 8) + /* Absolute bounds increase from 1Q before layer 8 */ + /* up to 256Q after layer 1 */ + invariant(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + mld_invntt_layer(r, layer); + } + + /* Coefficient bounds are now at 256Q. We now scale by mont / 256, + * i.e., compute the Montgomery multiplication by mont^2 / 256. + * mont corrects the mont^-1 factor introduced in the basemul. + * 1/256 performs that scaling of the inverse NTT. + * The reduced value is bounded by MLD_INTT_BOUND in absolute + * value.*/ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + invariant(j <= MLDSA_N) + invariant(array_abs_bound(r, 0, j, MLD_INTT_BOUND)) + invariant(array_abs_bound(r, j, MLDSA_N, MLDSA_N * MLDSA_Q)) + ) + { + r[j] = mld_fqscale(r[j]); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); +} + + +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_INTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_intt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_INTT */ + mld_poly_invntt_tomont_c(a); +} + +MLD_STATIC_TESTABLE void mld_poly_pointwise_montgomery_c(mld_poly *c, + const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_abs_bound(c->coeffs, 0, i, MLDSA_Q)) + ) + { + c->coeffs[i] = mld_montgomery_reduce((int64_t)a->coeffs[i] * b->coeffs[i]); + } + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +{ +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + ret = mld_poly_pointwise_montgomery_native(c->coeffs, a->coeffs, b->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + mld_poly_pointwise_montgomery_c(c, a, b); +} + +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, 0, i, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + invariant(array_bound(a1->coeffs, 0, i, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) + ) + { + mld_power2round(&a0->coeffs[i], &a1->coeffs[i], a->coeffs[i]); + } + + mld_assert_bound(a0->coeffs, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +#ifndef MLD_POLY_UNIFORM_NBLOCKS +#define MLD_POLY_UNIFORM_NBLOCKS \ + ((768 + MLD_STREAM128_BLOCKBYTES - 1) / MLD_STREAM128_BLOCKBYTES) +#endif +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +MLD_STATIC_TESTABLE unsigned int mld_rej_uniform_c(int32_t *a, + unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ + unsigned int ctr, pos; + uint32_t t; + mld_assert_bound(a, offset, 0, MLDSA_Q); + + ctr = offset; + pos = 0; + /* pos + 3 cannot overflow due to the assumption + buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) */ + while (ctr < target && pos + 3 <= buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_bound(a, 0, ctr, 0, MLDSA_Q))) + { + t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + a[ctr++] = (int32_t)t; + } + } + + mld_assert_bound(a, ctr, 0, MLDSA_Q); + + return ctr; +} +/************************************************* + * Name: mld_rej_uniform + * + * Description: Sample uniformly random coefficients in [0, MLDSA_Q-1] by + * performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes (must be + * multiple of 3) + * + * Returns number of sampled coefficients. Can be smaller than len if not enough + * random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +static unsigned int mld_rej_uniform(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) + int ret; + mld_assert_bound(a, offset, 0, MLDSA_Q); + if (offset == 0) + { + ret = mld_rej_uniform_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_bound(a, res, 0, MLDSA_Q); + return res; + } + } +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + + return mld_rej_uniform_c(a, target, offset, buf, buflen); +} + +/* Reference: poly_uniform() in the reference implementation @[REF]. + * - Simplified from reference by removing buffer tail handling + * since buflen % 3 = 0 always holds true (MLD_STREAM128_BLOCKBYTES + * = 168). + * - Modified rej_uniform interface to track offset directly. + * - Pass nonce packed in the extended seed array instead of a third + * argument. + * */ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +{ + unsigned int ctr; + unsigned int buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + MLD_ALIGN uint8_t buf[MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES]; + mld_xof128_ctx state; + + mld_xof128_init(&state); + mld_xof128_absorb_once(&state, seed, MLDSA_SEEDBYTES + 2); + mld_xof128_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, 0, buf, buflen); + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(a, sizeof(mld_poly)), object_whole(buf)) + invariant(ctr <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, ctr, 0, MLDSA_Q)) + invariant(state.pos <= SHAKE128_RATE) + ) + { + mld_xof128_squeezeblocks(buf, 1, &state); + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, ctr, buf, buflen); + } + mld_xof128_release(&state); + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof128_x4_ctx state; + unsigned buflen; + + mld_xof128_x4_init(&state); + mld_xof128_x4_absorb(&state, seed, MLDSA_SEEDBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_NBLOCKS. + * This should generate the matrix entries with high probability. + */ + + mld_xof128_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all matrix entries have been generated, squeeze + * one more block a time until we're done. + */ + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, object_whole(buf), + memory_slice(vec0, sizeof(mld_poly)), memory_slice(vec1, sizeof(mld_poly)), + memory_slice(vec2, sizeof(mld_poly)), memory_slice(vec3, sizeof(mld_poly))) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_bound(vec0->coeffs, 0, ctr[0], 0, MLDSA_Q)) + invariant(array_bound(vec1->coeffs, 0, ctr[1], 0, MLDSA_Q)) + invariant(array_bound(vec2->coeffs, 0, ctr[2], 0, MLDSA_Q)) + invariant(array_bound(vec3->coeffs, 0, ctr[3], 0, MLDSA_Q))) + { + mld_xof128_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + mld_xof128_x4_release(&state); + + mld_assert_bound(vec0->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec1->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec2->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec3->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0) & 0xFF); + r[5 * i + 1] = + (uint8_t)(((a->coeffs[4 * i + 0] >> 8) | (a->coeffs[4 * i + 1] << 2)) & + 0xFF); + r[5 * i + 2] = + (uint8_t)(((a->coeffs[4 * i + 1] >> 6) | (a->coeffs[4 * i + 2] << 4)) & + 0xFF); + r[5 * i + 3] = + (uint8_t)(((a->coeffs[4 * i + 2] >> 4) | (a->coeffs[4 * i + 3] << 6)) & + 0xFF); + r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, 0, 1 << 10))) + { + r->coeffs[4 * i + 0] = + ((a[5 * i + 0] >> 0) | ((int32_t)a[5 * i + 1] << 8)) & 0x3FF; + r->coeffs[4 * i + 1] = + ((a[5 * i + 1] >> 2) | ((int32_t)a[5 * i + 2] << 6)) & 0x3FF; + r->coeffs[4 * i + 2] = + ((a[5 * i + 2] >> 4) | ((int32_t)a[5 * i + 3] << 4)) & 0x3FF; + r->coeffs[4 * i + 3] = + ((a[5 * i + 3] >> 6) | ((int32_t)a[5 * i + 4] << 2)) & 0x3FF; + } + + mld_assert_bound(r->coeffs, MLDSA_N, 0, 1 << 10); +} + +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[8]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* Safety: a->coeffs[i] <= (1 << (MLDSA_D - 1) as they are output of + * power2round, hence, these casts are safe. */ + t[0] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 0]); + t[1] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 1]); + t[2] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 2]); + t[3] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 3]); + t[4] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 4]); + t[5] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 5]); + t[6] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 6]); + t[7] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 7]); + + r[13 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[13 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[13 * i + 1] |= (uint8_t)((t[1] << 5) & 0xFF); + r[13 * i + 2] = (uint8_t)((t[1] >> 3) & 0xFF); + r[13 * i + 3] = (uint8_t)((t[1] >> 11) & 0xFF); + r[13 * i + 3] |= (uint8_t)((t[2] << 2) & 0xFF); + r[13 * i + 4] = (uint8_t)((t[2] >> 6) & 0xFF); + r[13 * i + 4] |= (uint8_t)((t[3] << 7) & 0xFF); + r[13 * i + 5] = (uint8_t)((t[3] >> 1) & 0xFF); + r[13 * i + 6] = (uint8_t)((t[3] >> 9) & 0xFF); + r[13 * i + 6] |= (uint8_t)((t[4] << 4) & 0xFF); + r[13 * i + 7] = (uint8_t)((t[4] >> 4) & 0xFF); + r[13 * i + 8] = (uint8_t)((t[4] >> 12) & 0xFF); + r[13 * i + 8] |= (uint8_t)((t[5] << 1) & 0xFF); + r[13 * i + 9] = (uint8_t)((t[5] >> 7) & 0xFF); + r[13 * i + 9] |= (uint8_t)((t[6] << 6) & 0xFF); + r[13 * i + 10] = (uint8_t)((t[6] >> 2) & 0xFF); + r[13 * i + 11] = (uint8_t)((t[6] >> 10) & 0xFF); + r[13 * i + 11] |= (uint8_t)((t[7] << 3) & 0xFF); + r[13 * i + 12] = (uint8_t)((t[7] >> 5) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + { + r->coeffs[8 * i + 0] = a[13 * i + 0]; + r->coeffs[8 * i + 0] |= (int32_t)a[13 * i + 1] << 8; + r->coeffs[8 * i + 0] &= 0x1FFF; + + r->coeffs[8 * i + 1] = a[13 * i + 1] >> 5; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 2] << 3; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 3] << 11; + r->coeffs[8 * i + 1] &= 0x1FFF; + + r->coeffs[8 * i + 2] = a[13 * i + 3] >> 2; + r->coeffs[8 * i + 2] |= (int32_t)a[13 * i + 4] << 6; + r->coeffs[8 * i + 2] &= 0x1FFF; + + r->coeffs[8 * i + 3] = a[13 * i + 4] >> 7; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 5] << 1; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 6] << 9; + r->coeffs[8 * i + 3] &= 0x1FFF; + + r->coeffs[8 * i + 4] = a[13 * i + 6] >> 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 7] << 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 8] << 12; + r->coeffs[8 * i + 4] &= 0x1FFF; + + r->coeffs[8 * i + 5] = a[13 * i + 8] >> 1; + r->coeffs[8 * i + 5] |= (int32_t)a[13 * i + 9] << 7; + r->coeffs[8 * i + 5] &= 0x1FFF; + + r->coeffs[8 * i + 6] = a[13 * i + 9] >> 6; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 10] << 2; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 11] << 10; + r->coeffs[8 * i + 6] &= 0x1FFF; + + r->coeffs[8 * i + 7] = a[13 * i + 11] >> 3; + r->coeffs[8 * i + 7] |= (int32_t)a[13 * i + 12] << 5; + r->coeffs[8 * i + 7] &= 0x1FFF; + + r->coeffs[8 * i + 0] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 7]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +MLD_STATIC_TESTABLE uint32_t mld_poly_chknorm_c(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == array_abs_bound(a->coeffs, 0, i, B)) + ) + { + /* + * Since we know that -MLD_REDUCE32_RANGE_MAX <= a < MLD_REDUCE32_RANGE_MAX, + * and B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX, to check if + * -B < (a mod± MLDSA_Q) < B, it suffices to check if -B < a < B. + * + * We prove this to be true using the following CBMC assertions. + * a ==> b expressed as !a || b to also allow run-time assertion. + */ + mld_assert(a->coeffs[i] < B || a->coeffs[i] - MLDSA_Q <= -B); + mld_assert(a->coeffs[i] > -B || a->coeffs[i] + MLDSA_Q >= B); + + /* Reference: Leaks which coefficient violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + + /* if (abs(a[i]) >= B) */ + t |= mld_ct_cmask_neg_i32(B - 1 - mld_ct_abs_i32(a->coeffs[i])); + } + + return t; +} + +/* Reference: explicitly checks the bound B to be <= (MLDSA_Q - 1) / 8). + * This is unnecessary as it's always a compile-time constant. + * We instead model it as a precondition. + * Checking the bound is performed using a conditional arguing + * that it is okay to leak which coefficient violates the bound (while the + * coefficient itself must remain secret). + * We instead perform everything in constant-time. + * Also it is sufficient to check that it is smaller than + * MLDSA_Q - MLD_REDUCE32_RANGE_MAX > (MLDSA_Q - 1) / 8). + */ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +{ +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) + int ret; + int success; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + /* The native backend returns 0 if all coefficients are within the bound, + * 1 if at least one coefficient exceeds the bound, and + * -1 (MLD_NATIVE_FUNC_FALLBACK) if the platform does not have the + * required capabilities to run the native function. + */ + ret = mld_poly_chknorm_native(a->coeffs, B); + + success = (ret != MLD_NATIVE_FUNC_FALLBACK); + /* Constant-time: It would be fine to leak the return value of chknorm + * entirely (as it is fine to leak if any coefficient exceeded the bound or + * not). However, it is cleaner to perform declassification in sign.c. + * Hence, here we only declassify if the native function returned + * MLD_NATIVE_FUNC_FALLBACK or not (which solely depends on system + * capabilities). + */ + MLD_CT_TESTING_DECLASSIFY(&success, sizeof(int)); + if (success) + { + /* Convert 0 / 1 to 0 / 0xFFFFFFFF here */ + return 0U - (uint32_t)ret; + } +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + return mld_poly_chknorm_c(a, B); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ +MLD_EMPTY_CU(mld_poly) +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_POLY_UNIFORM_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/poly.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/poly.h new file mode 100644 index 0000000000..ff7710438e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/poly.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_H +#define MLD_POLY_H + +#include +#include "cbmc.h" +#include "common.h" +#include "reduce.h" +#include "rounding.h" + +/* Absolute exclusive upper bound for the output of the forward NTT */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) +/* Absolute exclusive upper bound for the output of the inverse NTT*/ +#define MLD_INTT_BOUND MLDSA_Q + +typedef struct +{ + int32_t coeffs[MLDSA_N]; +} MLD_ALIGN mld_poly; + +#define mld_poly_reduce MLD_NAMESPACE(poly_reduce) +/************************************************* + * Name: mld_poly_reduce + * + * Description: Inplace reduction of all coefficients of polynomial to + * representative in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) +); + +#define mld_poly_caddq MLD_NAMESPACE(poly_caddq) +/************************************************* + * Name: mld_poly_caddq + * + * Description: For all coefficients of in/out polynomial add MLDSA_Q if + * coefficient is negative. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_add MLD_NAMESPACE(poly_add) +/************************************************* + * Name: mld_poly_add + * + * Description: Add polynomials. No modular reduction is performed. + * + * Arguments: - r: Pointer to input-output polynomial to be added to. + * - b: Pointer to input polynomial that should be added + * to r. Must be disjoint from r. + **************************************************/ + +/* + * NOTE: The reference implementation uses a 3-argument poly_add. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(forall(k0, 0, MLDSA_N, (int64_t) r->coeffs[k0] + b->coeffs[k0] < MLD_REDUCE32_DOMAIN_MAX)) + requires(forall(k1, 0, MLDSA_N, (int64_t) r->coeffs[k1] + b->coeffs[k1] >= INT32_MIN)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(forall(k2, 0, MLDSA_N, r->coeffs[k2] == old(*r).coeffs[k2] + b->coeffs[k2])) + ensures(forall(k3, 0, MLDSA_N, r->coeffs[k3] < MLD_REDUCE32_DOMAIN_MAX)) + ensures(forall(k4, 0, MLDSA_N, r->coeffs[k4] >= INT32_MIN)) +); + +#define mld_poly_sub MLD_NAMESPACE(poly_sub) +/************************************************* + * Name: mld_poly_sub + * + * Description: Subtract polynomials. No modular reduction is + * performed. + * + * Arguments: - mld_poly *r: Pointer to input-output polynomial. + * - const mld_poly *b: Pointer to input polynomial that should be + * subtracted from r. Must be disjoint from r. + **************************************************/ +/* + * NOTE: The reference implementation uses a 3-argument poly_sub. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_Q)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) +); + +#define mld_poly_shiftl MLD_NAMESPACE(poly_shiftl) +/************************************************* + * Name: mld_poly_shiftl + * + * Description: Multiply polynomial by 2^MLDSA_D without modular reduction. + *Assumes input coefficients to be less than 2^{31-MLDSA_D} in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_ntt MLD_NAMESPACE(poly_ntt) +/************************************************* + * Name: mld_poly_ntt + * + * Description: Inplace forward NTT. Coefficients can grow by + * 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +); + + +#define mld_poly_invntt_tomont MLD_NAMESPACE(poly_invntt_tomont) +/************************************************* + * Name: mld_poly_invntt_tomont + * + * Description: Inplace inverse NTT and multiplication by 2^{32}. + * Input coefficients need to be less than MLDSA_Q in absolute + * value and output coefficients are bounded by + * MLD_INTT_BOUND. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +); + +#define mld_poly_pointwise_montgomery MLD_NAMESPACE(poly_pointwise_montgomery) +/************************************************* + * Name: mld_poly_pointwise_montgomery + * + * Description: Pointwise multiplication of polynomials in NTT domain + * representation and multiplication of resulting polynomial + * by 2^{-32}. + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const mld_poly *a: pointer to first input polynomial + * - const mld_poly *b: pointer to second input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + +#define mld_poly_power2round MLD_NAMESPACE(poly_power2round) +/************************************************* + * Name: mld_poly_power2round + * + * Description: For all coefficients c of the input polynomial, + * compute c0, c1 such that c mod MLDSA_Q = c1*2^MLDSA_D + c0 + * with -2^{MLDSA_D-1} < c0 <= 2^{MLDSA_D-1}. Assumes coefficients + *to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + *c1 + * - mld_poly *a0: pointer to output polynomial with coefficients + *c0 + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +__contract__( + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a0->coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) +); + +#define mld_poly_uniform MLD_NAMESPACE(poly_uniform) +/************************************************* + * Name: mld_poly_uniform + * + * Description: Sample polynomial with uniformly random coefficients + * in [0,MLDSA_Q-1] by performing rejection sampling on the + * output stream of SHAKE128(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_SEEDBYTES and the packed 2-byte nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES + 2)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +#define mld_poly_uniform_4x MLD_NAMESPACE(poly_uniform_4x) +/************************************************* + * Name: mld_poly_uniform_x4 + * + * Description: Generate four polynomials using rejection sampling + * on (pseudo-)uniformly random bytes sampled from a seed. + * + * Arguments: - mld_poly *vec0, *vec1, *vec2, *vec3: + * Pointers to 4 polynomials to be sampled. + * - uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]: + * Pointer consecutive array of seed buffers of size + * MLDSA_SEEDBYTES + 2 each, plus padding for alignment. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +__contract__( + requires(memory_no_alias(vec0, sizeof(mld_poly))) + requires(memory_no_alias(vec1, sizeof(mld_poly))) + requires(memory_no_alias(vec2, sizeof(mld_poly))) + requires(memory_no_alias(vec3, sizeof(mld_poly))) + requires(memory_no_alias(seed, 4 * MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2))) + assigns(memory_slice(vec0, sizeof(mld_poly))) + assigns(memory_slice(vec1, sizeof(mld_poly))) + assigns(memory_slice(vec2, sizeof(mld_poly))) + assigns(memory_slice(vec3, sizeof(mld_poly))) + ensures(array_bound(vec0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec1->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec2->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec3->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +#define mld_polyt1_pack MLD_NAMESPACE(polyt1_pack) +/************************************************* + * Name: mld_polyt1_pack + * + * Description: Bit-pack polynomial t1 with coefficients fitting in 10 bits. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(r, MLDSA_POLYT1_PACKEDBYTES)) +); + +#define mld_polyt1_unpack MLD_NAMESPACE(polyt1_unpack) +/************************************************* + * Name: mld_polyt1_unpack + * + * Description: Unpack polynomial t1 with 10-bit coefficients. + * Output coefficients are standard representatives. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT1_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, 0, 1 << 10)) +); + +#define mld_polyt0_pack MLD_NAMESPACE(polyt0_pack) +/************************************************* + * Name: mld_polyt0_pack + * + * Description: Bit-pack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + * 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) + assigns(memory_slice(r, MLDSA_POLYT0_PACKEDBYTES)) +); + + +#define mld_polyt0_unpack MLD_NAMESPACE(polyt0_unpack) +/************************************************* + * Name: mld_polyt0_unpack + * + * Description: Unpack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + *2^{MLDSA_D-1}]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT0_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) +); + +#define mld_poly_chknorm MLD_NAMESPACE(poly_chknorm) +/************************************************* + * Name: mld_poly_chknorm + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const mld_poly *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if norm is strictly smaller than + * B <= (MLDSA_Q - MLD_REDUCE32_RANGE_MAX) and 0xFFFFFFFF otherwise. + * + * Specification: The definition of this FIPS-204 requires signed canonical + * reduction prior to applying the bounds check. + * However, `-B < (a mod± MLDSA_Q) < B` is equivalent to + * `-B < a < B` under the assumption that + * `B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX` (cf. the assertion in + * the code). Hence, the present spec and implementation are + * correct without reduction. + * + **************************************************/ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +); + +#endif /* !MLD_POLY_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/poly_kl.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/poly_kl.c new file mode 100644 index 0000000000..7a319ca515 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/poly_kl.c @@ -0,0 +1,931 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "ct.h" +#include "debug.h" +#include "poly_kl.h" +#include "rounding.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_rej_eta MLD_ADD_PARAM_SET(mld_rej_eta) +#define mld_rej_eta_c MLD_ADD_PARAM_SET(mld_rej_eta_c) +#define mld_poly_decompose_c MLD_ADD_PARAM_SET(mld_poly_decompose_c) +#define mld_poly_use_hint_c MLD_ADD_PARAM_SET(mld_poly_use_hint_c) +#define mld_polyz_unpack_c MLD_ADD_PARAM_SET(mld_polyz_unpack_c) +/* End of parameter set namespacing */ + + +MLD_STATIC_TESTABLE +void mld_poly_decompose_c(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +) +{ + unsigned int i; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, i, MLDSA_N, 0, MLDSA_Q)) + invariant(array_bound(a1->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + invariant(array_abs_bound(a0->coeffs, 0, i, MLDSA_GAMMA2+1)) + ) + { + mld_decompose(&a0->coeffs[i], &a1->coeffs[i], a0->coeffs[i]); + } + + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +{ +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_88_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_32_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_DECOMPOSE_88 && MLD_CONFIG_PARAMETER_SET == \ + 44) && MLD_USE_NATIVE_POLY_DECOMPOSE_32 && (MLD_CONFIG_PARAMETER_SET \ + == 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_decompose_c(a1, a0); +} + +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(s <= i) + invariant(array_bound(h->coeffs, 0, i, 0, 2)) + ) + { + const unsigned int hint_bit = mld_make_hint(a0->coeffs[i], a1->coeffs[i]); + h->coeffs[i] = (int32_t)hint_bit; + s += hint_bit; + } + + mld_assert(s <= MLDSA_N); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + return s; +} + +MLD_STATIC_TESTABLE void mld_poly_use_hint_c(mld_poly *b, const mld_poly *a, + const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(b->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ) + { + b->coeffs[i] = mld_use_hint(a->coeffs[i], h->coeffs[i]); + } + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +{ +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_88_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_USE_HINT_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_32_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_USE_HINT_88 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLY_USE_HINT_32 && (MLD_CONFIG_PARAMETER_SET == \ + 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_use_hint_c(b, a, h); +} + +/************************************************* + * Name: mld_rej_eta + * + * Description: Sample uniformly random coefficients in [-MLDSA_ETA, MLDSA_ETA] + *by performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes + * + * Returns number of sampled coefficients. Can be smaller than target if not + *enough random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_eta()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +#if MLDSA_ETA == 2 +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 1 +#elif MLDSA_ETA == 4 +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 2 +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + +MLD_STATIC_TESTABLE unsigned int mld_rej_eta_c(int32_t *a, unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ + unsigned int ctr, pos; + int t_valid; + uint32_t t0, t1; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + ctr = offset; + pos = 0; + while (ctr < target && pos < buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_abs_bound(a, 0, ctr, MLDSA_ETA + 1)) + ) + { + t0 = buf[pos] & 0x0F; + t1 = buf[pos++] >> 4; + + /* Constant time: The inputs and outputs to the rejection sampling are + * secret. However, it is fine to leak which coefficients have been + * rejected. For constant-time testing, we declassify the result of + * the comparison. + */ +#if MLDSA_ETA == 2 + t_valid = t0 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 15 */ + { + t0 = t0 - (205 * t0 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t0; + } + t_valid = t1 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) /* t1 < 15 */ + { + t1 = t1 - (205 * t1 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t1; + } +#elif MLDSA_ETA == 4 + t_valid = t0 < 9; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 9 */ + { + a[ctr++] = 4 - (int32_t)t0; + } + t_valid = t1 < 9; /* t1 < 9 */ + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) + { + a[ctr++] = 4 - (int32_t)t1; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + } + + mld_assert_abs_bound(a, ctr, MLDSA_ETA + 1); + + return ctr; +} + +static unsigned int mld_rej_eta(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ +#if MLDSA_ETA == 2 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta2_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#elif MLDSA_ETA == 4 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta4_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#endif /* !(MLDSA_ETA == 2 && MLD_USE_NATIVE_REJ_UNIFORM_ETA2) && MLDSA_ETA == \ + 4 && MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + + return mld_rej_eta_c(a, target, offset, buf, buflen); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_ETA_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof256_x4_ctx state; + unsigned buflen; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = nonce0; + extseed[1][MLDSA_CRHBYTES] = nonce1; + extseed[2][MLDSA_CRHBYTES] = nonce2; + extseed[3][MLDSA_CRHBYTES] = nonce3; + extseed[0][MLDSA_CRHBYTES + 1] = 0; + extseed[1][MLDSA_CRHBYTES + 1] = 0; + extseed[2][MLDSA_CRHBYTES + 1] = 0; + extseed[3][MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(r0, sizeof(mld_poly)), + memory_slice(r1, sizeof(mld_poly)), memory_slice(r2, sizeof(mld_poly)), + memory_slice(r3, sizeof(mld_poly)), object_whole(buf[0]), + object_whole(buf[1]), object_whole(buf[2]), + object_whole(buf[3])) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_abs_bound(r0->coeffs, 0, ctr[0], MLDSA_ETA + 1)) + invariant(array_abs_bound(r1->coeffs, 0, ctr[1], MLDSA_ETA + 1)) + invariant(array_abs_bound(r2->coeffs, 0, ctr[2], MLDSA_ETA + 1)) + invariant(array_abs_bound(r3->coeffs, 0, ctr[3], MLDSA_ETA + 1))) + { + mld_xof256_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + + mld_xof256_x4_release(&state); + + mld_assert_abs_bound(r0->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r1->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r2->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r3->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +{ + /* Temporary buffer for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr; + mld_xof256_ctx state; + unsigned buflen; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = nonce; + extseed[MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr = mld_rej_eta(r->coeffs, MLDSA_N, 0, buf, buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, object_whole(&state), + object_whole(buf), memory_slice(r, sizeof(mld_poly))) + invariant(ctr <= MLDSA_N) + invariant(state.pos <= SHAKE256_RATE) + invariant(array_abs_bound(r->coeffs, 0, ctr, MLDSA_ETA + 1))) + { + mld_xof256_squeezeblocks(buf, 1, &state); + ctr = mld_rej_eta(r->coeffs, MLDSA_N, ctr, buf, buflen); + } + + mld_xof256_release(&state); + + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define MLD_POLY_UNIFORM_GAMMA1_NBLOCKS \ + ((MLDSA_POLYZ_PACKEDBYTES + MLD_STREAM256_BLOCKBYTES - 1) / \ + MLD_STREAM256_BLOCKBYTES) + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + mld_xof256_ctx state; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = (uint8_t)(nonce & 0xFF); + extseed[MLDSA_CRHBYTES + 1] = (uint8_t)(nonce >> 8); + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + mld_polyz_unpack(a, buf); + + mld_xof256_release(&state); + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + mld_xof256_x4_ctx state; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = (uint8_t)(nonce0 & 0xFF); + extseed[1][MLDSA_CRHBYTES] = (uint8_t)(nonce1 & 0xFF); + extseed[2][MLDSA_CRHBYTES] = (uint8_t)(nonce2 & 0xFF); + extseed[3][MLDSA_CRHBYTES] = (uint8_t)(nonce3 & 0xFF); + extseed[0][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce0 >> 8); + extseed[1][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce1 >> 8); + extseed[2][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce2 >> 8); + extseed[3][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce3 >> 8); + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + + mld_polyz_unpack(r0, buf[0]); + mld_polyz_unpack(r1, buf[1]); + mld_polyz_unpack(r2, buf[2]); + mld_polyz_unpack(r3, buf[3]); + mld_xof256_x4_release(&state); + + mld_assert_bound(r0->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r1->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r2->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r3->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +{ + unsigned int i, j, pos; + uint64_t signs; + uint64_t offset; + MLD_ALIGN uint8_t buf[SHAKE256_RATE]; + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, seed, MLDSA_CTILDEBYTES); + mld_shake256_finalize(&state); + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + + /* Convert the first 8 bytes of buf[] into an unsigned 64-bit value. */ + /* Each bit of that dictates the sign of the resulting challenge value */ + signs = 0; + for (i = 0; i < 8; ++i) + __loop__( + assigns(i, signs) + invariant(i <= 8) + ) + { + signs |= (uint64_t)buf[i] << 8 * i; + } + pos = 8; + + mld_memset(c, 0, sizeof(mld_poly)); + + for (i = MLDSA_N - MLDSA_TAU; i < MLDSA_N; ++i) + __loop__( + assigns(i, j, object_whole(buf), state, pos, memory_slice(c, sizeof(mld_poly)), signs) + invariant(i >= MLDSA_N - MLDSA_TAU) + invariant(i <= MLDSA_N) + invariant(pos >= 1) + invariant(pos <= SHAKE256_RATE) + invariant(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) + invariant(state.pos <= SHAKE256_RATE) + ) + { + do + __loop__( + assigns(j, object_whole(buf), state, pos) + invariant(state.pos <= SHAKE256_RATE) + ) + { + if (pos >= SHAKE256_RATE) + { + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + pos = 0; + } + j = buf[pos++]; + } while (j > i); + + c->coeffs[i] = c->coeffs[j]; + + /* Reference: Compute coefficent value here in two steps to */ + /* mixinf unsigned and signed arithmetic with implicit */ + /* conversions, and so that CBMC can keep track of ranges */ + /* to complete type-safety proof here. */ + + /* The least-significant bit of signs tells us if we want -1 or +1 */ + offset = 2 * (signs & 1); + + /* offset has value 0 or 2 here, so (1 - (int32_t) offset) has + * value -1 or +1 */ + c->coeffs[j] = 1 - (int32_t)offset; + + /* Move to the next bit of signs for next time */ + signs >>= 1; + } + + mld_assert_bound(c->coeffs, MLDSA_N, -1, 2); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(&signs, sizeof(signs)); +} + +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint8_t t[8]; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_ETA + 1); + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 1]); + t[2] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 2]); + t[3] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 3]); + t[4] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 4]); + t[5] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 5]); + t[6] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 6]); + t[7] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 7]); + + r[3 * i + 0] = (uint8_t)(((t[0] >> 0) | (t[1] << 3) | (t[2] << 6)) & 0xFF); + r[3 * i + 1] = + (uint8_t)(((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)) & + 0xFF); + r[3 * i + 2] = (uint8_t)(((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)) & 0xFF); + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 1]); + r[i] = (uint8_t)(t[0] | (t[1] << 4)); + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ +} + +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -5, MLDSA_ETA + 1))) + { + r->coeffs[8 * i + 0] = (a[3 * i + 0] >> 0) & 7; + r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 7; + r->coeffs[8 * i + 2] = ((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 7; + r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 7; + r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 7; + r->coeffs[8 * i + 5] = ((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 7; + r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 7; + r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5) & 7; + + r->coeffs[8 * i + 0] = MLDSA_ETA - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = MLDSA_ETA - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = MLDSA_ETA - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = MLDSA_ETA - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = MLDSA_ETA - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = MLDSA_ETA - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = MLDSA_ETA - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = MLDSA_ETA - r->coeffs[8 * i + 7]; + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -11, MLDSA_ETA + 1))) + { + r->coeffs[2 * i + 0] = a[i] & 0x0F; + r->coeffs[2 * i + 1] = a[i] >> 4; + r->coeffs[2 * i + 0] = MLDSA_ETA - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_ETA - r->coeffs[2 * i + 1]; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + + mld_assert_bound(r->coeffs, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + + +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[4]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 1]); + t[2] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 2]); + t[3] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 3]); + + r[9 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[9 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[9 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[9 * i + 2] |= (uint8_t)((t[1] << 2) & 0xFF); + r[9 * i + 3] = (uint8_t)((t[1] >> 6) & 0xFF); + r[9 * i + 4] = (uint8_t)((t[1] >> 14) & 0xFF); + r[9 * i + 4] |= (uint8_t)((t[2] << 4) & 0xFF); + r[9 * i + 5] = (uint8_t)((t[2] >> 4) & 0xFF); + r[9 * i + 6] = (uint8_t)((t[2] >> 12) & 0xFF); + r[9 * i + 6] |= (uint8_t)((t[3] << 6) & 0xFF); + r[9 * i + 7] = (uint8_t)((t[3] >> 2) & 0xFF); + r[9 * i + 8] = (uint8_t)((t[3] >> 10) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 1]); + + r[5 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[5 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[5 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[5 * i + 2] |= (uint8_t)((t[1] << 4) & 0xFF); + r[5 * i + 3] = (uint8_t)((t[1] >> 4) & 0xFF); + r[5 * i + 4] = (uint8_t)((t[1] >> 12) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +MLD_STATIC_TESTABLE void mld_polyz_unpack_c( + mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +) +{ + unsigned int i; +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[4 * i + 0] = a[9 * i + 0]; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 2] << 16; + r->coeffs[4 * i + 0] &= 0x3FFFF; + + r->coeffs[4 * i + 1] = a[9 * i + 2] >> 2; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 3] << 6; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 4] << 14; + r->coeffs[4 * i + 1] &= 0x3FFFF; + + r->coeffs[4 * i + 2] = a[9 * i + 4] >> 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 5] << 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 6] << 12; + r->coeffs[4 * i + 2] &= 0x3FFFF; + + r->coeffs[4 * i + 3] = a[9 * i + 6] >> 6; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 7] << 2; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10; + r->coeffs[4 * i + 3] &= 0x3FFFF; + + r->coeffs[4 * i + 0] = MLDSA_GAMMA1 - r->coeffs[4 * i + 0]; + r->coeffs[4 * i + 1] = MLDSA_GAMMA1 - r->coeffs[4 * i + 1]; + r->coeffs[4 * i + 2] = MLDSA_GAMMA1 - r->coeffs[4 * i + 2]; + r->coeffs[4 * i + 3] = MLDSA_GAMMA1 - r->coeffs[4 * i + 3]; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[2 * i + 0] = a[5 * i + 0]; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 2] << 16; + r->coeffs[2 * i + 0] &= 0xFFFFF; + + r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 3] << 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12; + /* r->coeffs[2*i+1] &= 0xFFFFF; */ /* No effect, since we're anyway at 20 + bits */ + + r->coeffs[2 * i + 0] = MLDSA_GAMMA1 - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_GAMMA1 - r->coeffs[2 * i + 1]; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +{ +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + ret = mld_polyz_unpack_17_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#elif defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + ret = mld_polyz_unpack_19_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYZ_UNPACK_17 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLYZ_UNPACK_19 && (MLD_CONFIG_PARAMETER_SET == 65 \ + || MLD_CONFIG_PARAMETER_SET == 87) */ + + mld_polyz_unpack_c(r, a); +} + +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + + mld_assert_bound(a->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[3 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0]) & 0xFF); + r[3 * i + 0] |= (uint8_t)((a->coeffs[4 * i + 1] << 6) & 0xFF); + r[3 * i + 1] = (uint8_t)((a->coeffs[4 * i + 1] >> 2) & 0xFF); + r[3 * i + 1] |= (uint8_t)((a->coeffs[4 * i + 2] << 4) & 0xFF); + r[3 * i + 2] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) & 0xFF); + r[3 * i + 2] |= (uint8_t)((a->coeffs[4 * i + 3] << 2) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + r[i] = + (uint8_t)((a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_rej_eta +#undef mld_rej_eta_c +#undef mld_poly_decompose_c +#undef mld_poly_use_hint_c +#undef mld_polyz_unpack_c +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_GAMMA1_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/poly_kl.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/poly_kl.h new file mode 100644 index 0000000000..c6aa498358 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/poly_kl.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_KL_H +#define MLD_POLY_KL_H + +#include "cbmc.h" +#include "common.h" +#include "poly.h" + +#define mld_poly_decompose MLD_NAMESPACE_KL(poly_decompose) +/************************************************* + * Name: mld_poly_decompose + * + * Description: For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such c mod MLDSA_Q = c1*ALPHA + + * c0 with -ALPHA/2 < c0 <= ALPHA/2 except + * c1 = (MLDSA_Q-1)/ALPHA where we set + * c1 = 0 and -ALPHA/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + * c1 + * - mld_poly *a0: pointer to input/output polynomial. Output + * polynomial has coefficients c0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +); + + +#define mld_poly_make_hint MLD_NAMESPACE_KL(poly_make_hint) +/************************************************* + * Name: mld_poly_make_hint + * + * Description: Compute hint polynomial. The coefficients of which indicate + * whether the low bits of the corresponding coefficient of + * the input polynomial overflow into the high bits. + * + * Arguments: - mld_poly *h: pointer to output hint polynomial + * - const mld_poly *a0: pointer to low part of input polynomial + * - const mld_poly *a1: pointer to high part of input polynomial + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + assigns(memory_slice(h, sizeof(mld_poly))) + ensures(return_value <= MLDSA_N) + ensures(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) +); + +#define mld_poly_use_hint MLD_NAMESPACE_KL(poly_use_hint) +/************************************************* + * Name: mld_poly_use_hint + * + * Description: Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - mld_poly *b: pointer to output polynomial with corrected high + *bits + * - const mld_poly *a: pointer to input polynomial + * - const mld_poly *h: pointer to input hint polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta_4x MLD_NAMESPACE_KL(poly_uniform_eta_4x) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample four polynomials with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce_i) + * + * Arguments: - mld_poly *r0: pointer to first output polynomial + * - mld_poly *r1: pointer to second output polynomial + * - mld_poly *r2: pointer to third output polynomial + * - mld_poly *r3: pointer to fourth output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce0: first nonce + * - uint8_t nonce1: second nonce + * - uint8_t nonce2: third nonce + * - uint8_t nonce3: fourth nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_abs_bound(r0->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r1->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r2->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r3->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta MLD_NAMESPACE_KL(poly_uniform_eta) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample polynomial with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce: nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1 MLD_NAMESPACE_KL(poly_uniform_gamma1) +/************************************************* + * Name: mld_poly_uniform_gamma1 + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1_4x MLD_NAMESPACE_KL(poly_uniform_gamma1_4x) +/************************************************* + * Name: mld_poly_uniform_gamma1_4x + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_bound(r0->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r1->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r2->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r3->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define mld_poly_challenge MLD_NAMESPACE_KL(poly_challenge) +/************************************************* + * Name: mld_poly_challenge + * + * Description: Implementation of H. Samples polynomial with MLDSA_TAU nonzero + * coefficients in {-1,1} using the output stream of + * SHAKE256(seed). + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const uint8_t mu[]: byte array containing seed of length + * MLDSA_CTILDEBYTES + **************************************************/ +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +__contract__( + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CTILDEBYTES)) + assigns(memory_slice(c, sizeof(mld_poly))) + /* All coefficients of c are -1, 0 or +1 */ + ensures(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) +); + +#define mld_polyeta_pack MLD_NAMESPACE_KL(polyeta_pack) +/************************************************* + * Name: mld_polyeta_pack + * + * Description: Bit-pack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYETA_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + assigns(memory_slice(r, MLDSA_POLYETA_PACKEDBYTES)) +); + +/* + * polyeta_unpack produces coefficients in [-MLDSA_ETA,MLDSA_ETA] for + * well-formed inputs (i.e., those produced by polyeta_pack). + * However, when passed an arbitrary byte array, it may produce smaller values, + * i.e, values in [MLD_POLYETA_UNPACK_LOWER_BOUND,MLDSA_ETA] + * Even though this should never happen, we use use the bound for arbitrary + * inputs in the CBMC proofs. + */ +#if MLDSA_ETA == 2 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-5) +#elif MLDSA_ETA == 4 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-11) +#else +#error "Invalid value of MLDSA_ETA" +#endif + +#define mld_polyeta_unpack MLD_NAMESPACE_KL(polyeta_unpack) +/************************************************* + * Name: mld_polyeta_unpack + * + * Description: Unpack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYETA_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)) +); + +#define mld_polyz_pack MLD_NAMESPACE_KL(polyz_pack) +/************************************************* + * Name: mld_polyz_pack + * + * Description: Bit-pack polynomial with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYZ_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(r, MLDSA_POLYZ_PACKEDBYTES)) +); + + +#define mld_polyz_unpack MLD_NAMESPACE_KL(polyz_unpack) +/************************************************* + * Name: mld_polyz_unpack + * + * Description: Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); + +#define mld_polyw1_pack MLD_NAMESPACE_KL(polyw1_pack) +/************************************************* + * Name: mld_polyw1_pack + * + * Description: Bit-pack polynomial w1 with coefficients in [0,15] or [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES)) +); + +#endif /* !MLD_POLY_KL_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/polyvec.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/polyvec.c new file mode 100644 index 0000000000..5c3a08ab32 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/polyvec.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include +#include + +#include "common.h" +#include "debug.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" + +/* This namespacing is not done at the top to avoid a naming conflict + * with native backends, which are currently not yet namespaced. */ +#define mld_polymat_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polymat_permute_bitrev_to_custom) +#define mld_polyvecl_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polyvecl_permute_bitrev_to_custom) +#define mld_polyvecl_pointwise_acc_montgomery_c \ + MLD_ADD_PARAM_SET(mld_polyvecl_pointwise_acc_montgomery_c) + +#if !defined(MLD_CONFIG_REDUCE_RAM) +/* Helper function to ensure that the polynomial entries in the output + * of mld_polyvec_matrix_expand use the standard (bitreversed) ordering + * of coefficients. + * No-op unless a native backend with a custom ordering is used. + */ + +static void mld_polyvecl_permute_bitrev_to_custom(mld_polyvecl *v) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +{ +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + unsigned i; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_permute_bitrev_to_custom(v->vec[i].coeffs); + } +#else /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + /* Nothing to do */ + (void)v; +#endif /* !MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ +} + +static void mld_polymat_permute_bitrev_to_custom(mld_polymat *mat) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; i++) + __loop__( + assigns(i, memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))) + { + mld_polyvecl_permute_bitrev_to_custom(&mat->vec[i]); + } +} +#endif /* !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + unsigned int i; + MLD_ALIGN uint8_t seed_ext[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + mld_memcpy(seed_ext, mat->rho, MLDSA_SEEDBYTES); + + /* Generate row on-demand */ + for (i = 0; i < MLDSA_L; i++) + { + uint8_t x = (uint8_t)row; + uint8_t y = (uint8_t)i; + + seed_ext[MLDSA_SEEDBYTES + 0] = y; + seed_ext[MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(&mat->row_buffer.vec[i], seed_ext); + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + mld_poly_permute_bitrev_to_custom(mat->row_buffer.vec[i].coeffs); +#endif + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); + + return &mat->row_buffer; +#else /* MLD_CONFIG_REDUCE_RAM */ + return &mat->vec[row]; +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + /* In REDUCE_RAM mode, just copy the seed for later on-demand generation */ + mld_memcpy(mat->rho, rho, MLDSA_SEEDBYTES); +#else + unsigned int i, j; + /* + * We generate four separate seed arrays rather than a single one to work + * around limitations in CBMC function contracts dealing with disjoint slices + * of the same parent object. + */ + + MLD_ALIGN uint8_t seed_ext[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + mld_memcpy(seed_ext[j], rho, MLDSA_SEEDBYTES); + } + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + /* Sample 4 matrix entries a time. */ + for (i = 0; i < (MLDSA_K * MLDSA_L / 4) * 4; i += 4) + __loop__( + assigns(i, j, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= (MLDSA_K * MLDSA_L / 4) * 4 && i % 4 == 0) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + uint8_t x = (uint8_t)((i + j) / MLDSA_L); + uint8_t y = (uint8_t)((i + j) % MLDSA_L); + + seed_ext[j][MLDSA_SEEDBYTES + 0] = y; + seed_ext[j][MLDSA_SEEDBYTES + 1] = x; + } + + mld_poly_uniform_4x(&mat->vec[i / MLDSA_L].vec[i % MLDSA_L], + &mat->vec[(i + 1) / MLDSA_L].vec[(i + 1) % MLDSA_L], + &mat->vec[(i + 2) / MLDSA_L].vec[(i + 2) % MLDSA_L], + &mat->vec[(i + 3) / MLDSA_L].vec[(i + 3) % MLDSA_L], + seed_ext); + } +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + i = 0; +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + /* Entries omitted by the batch-sampling are sampled individually. */ + while (i < MLDSA_K * MLDSA_L) + __loop__( + assigns(i, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K * MLDSA_L) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + uint8_t x = (uint8_t)(i / MLDSA_L); + uint8_t y = (uint8_t)(i % MLDSA_L); + mld_poly *this_poly = &mat->vec[i / MLDSA_L].vec[i % MLDSA_L]; + + seed_ext[0][MLDSA_SEEDBYTES + 0] = y; + seed_ext[0][MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(this_poly, seed_ext[0]); + i++; + } + + mld_polymat_permute_bitrev_to_custom(mat); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(t, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + const mld_polyvecl *row = mld_polymat_get_row(mat, i); + mld_polyvecl_pointwise_acc_montgomery(&t->vec[i], row, v); + } + + mld_assert_abs_bound_2d(t->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_L **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; +#endif + + /* Safety: nonce is at most ((UINT16_MAX - MLDSA_L) / MLDSA_L), and, hence, + * this cast is safe. See MLD_NONCE_UB comment in sign.c. */ + nonce = (uint16_t)(MLDSA_L * nonce); + /* Now, nonce <= UINT16_MAX - (MLDSA_L - 1), so the casts below are safe. */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_gamma1(&v->vec[i], seed, (uint16_t)(nonce + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLDSA_L == 4 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); +#elif MLDSA_L == 5 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); + mld_poly_uniform_gamma1(&v->vec[4], seed, (uint16_t)(nonce + 4)); +#elif MLDSA_L == 7 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], + &v->vec[3 /* irrelevant */], seed, nonce, + (uint16_t)(nonce + 1), (uint16_t)(nonce + 2), + 0xFF /* irrelevant */); + mld_poly_uniform_gamma1_4x(&v->vec[3], &v->vec[4], &v->vec[5], &v->vec[6], + seed, (uint16_t)(nonce + 3), (uint16_t)(nonce + 4), + (uint16_t)(nonce + 5), (uint16_t)(nonce + 6)); +#endif /* MLDSA_L == 7 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(k0, i, MLDSA_L, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_STATIC_TESTABLE void mld_polyvecl_pointwise_acc_montgomery_c( + mld_poly *w, const mld_polyvecl *u, const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i, j; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + for (i = 0; i < MLDSA_N; i++) + __loop__( + assigns(i, j, memory_slice(w, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_abs_bound(w->coeffs, 0, i, MLDSA_Q)) + ) + { + int64_t t = 0; + int32_t r; + for (j = 0; j < MLDSA_L; j++) + __loop__( + assigns(j, t) + invariant(j <= MLDSA_L) + invariant(t >= -(int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + invariant(t <= (int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + ) + { + t += (int64_t)u->vec[j].coeffs[i] * v->vec[j].coeffs[i]; + } + + r = mld_montgomery_reduce(t); + w->coeffs[i] = r; + } + + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +{ +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) && \ + MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l4_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) && \ + MLD_CONFIG_PARAMETER_SET == 65 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l5_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) && \ + MLD_CONFIG_PARAMETER_SET == 87 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l7_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 && \ + MLD_CONFIG_PARAMETER_SET == 44) && \ + !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 && \ + MLD_CONFIG_PARAMETER_SET == 65) && \ + MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 && \ + MLD_CONFIG_PARAMETER_SET == 87 */ + /* The first input is bounded by [0, Q-1] inclusive + * The second input is bounded by [-9Q+1, 9Q-1] inclusive . Hence, we can + * safely accumulate in 64-bits without intermediate reductions as + * MLDSA_L * (MLD_NTT_BOUND-1) * (Q-1) < INT64_MAX + * + * The worst case is ML-DSA-87: 7 * (9Q-1) * (Q-1) < 2**52 + * (and likewise for negative values) + */ + mld_polyvecl_pointwise_acc_montgomery_c(w, u, v); +} + +MLD_INTERNAL_API +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + invariant(i <= MLDSA_L) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + return t; +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_K **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k2, 0, i, + array_bound(v->vec[k2].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ) + { + mld_poly_reduce(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_caddq(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, + forall(k1, 0, MLDSA_N, u->vec[k0].coeffs[k1] == loop_entry(*u).vec[k0].coeffs[k1]))) + invariant(forall(k6, 0, i, array_bound(u->vec[k6].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + ) + { + mld_poly_add(&u->vec[i], &v->vec[i]); + } + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(u->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, u->vec[k1].coeffs[n1] == loop_entry(*u).vec[k1].coeffs[n1])))) + { + mld_poly_sub(&u->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, v->vec[k1].coeffs[n1] == loop_entry(*v).vec[k1].coeffs[n1]))) + ) + { + mld_poly_shiftl(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))) + { + mld_poly_invntt_tomont(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_INTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, array_abs_bound(r->vec[k2].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + mld_poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]); + } + mld_assert_abs_bound_2d(r->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + + return t; +} + +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + invariant(forall(k2, 0, i, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) + ) + { + mld_poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +{ + unsigned int i; + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + invariant(forall(k2, 0, i, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) + invariant(forall(k3, i, MLDSA_K, + array_bound(v0->vec[k3].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + ) + { + mld_poly_decompose(&v1->vec[i], &v0->vec[i]); + } + + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + mld_assert_abs_bound_2d(v0->vec, MLDSA_K, MLDSA_N, MLDSA_GAMMA2 + 1); +} + +MLD_INTERNAL_API +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, s, memory_slice(h, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(s <= i * MLDSA_N) + invariant(forall(k1, 0, i, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + s += mld_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]); + } + + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + return s; +} + +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *u, + const mld_polyveck *h) +{ + unsigned int i; + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(w, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)))) + ) + { + mld_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]); + } + + mld_assert_bound_2d(w->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +{ + unsigned int i; + mld_assert_bound_2d(w1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyw1_pack(&r[i * MLDSA_POLYW1_PACKEDBYTES], &w1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt0_pack(&r[i * MLDSA_POLYT0_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyz_unpack(&z->vec[i], r + i * MLDSA_POLYZ_PACKEDBYTES); + } + + mld_assert_bound_2d(z->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt0_unpack(&p->vec[i], r + i * MLDSA_POLYT0_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_polymat_permute_bitrev_to_custom +#undef mld_polyvecl_permute_bitrev_to_custom +#undef mld_polyvecl_pointwise_acc_montgomery_c diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/polyvec.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/polyvec.h new file mode 100644 index 0000000000..d21abc02ff --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/polyvec.h @@ -0,0 +1,725 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLYVEC_H +#define MLD_POLYVEC_H + +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "poly_kl.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_polyvecl MLD_ADD_PARAM_SET(mld_polyvecl) +#define mld_polyveck MLD_ADD_PARAM_SET(mld_polyveck) +#define mld_polymat MLD_ADD_PARAM_SET(mld_polymat) +/* End of parameter set namespacing */ + +/* Vectors of polynomials of length MLDSA_L */ +typedef struct +{ + mld_poly vec[MLDSA_L]; +} mld_polyvecl; + + +#define mld_polyvecl_uniform_gamma1 MLD_NAMESPACE_KL(polyvecl_uniform_gamma1) +/************************************************* + * Name: mld_polyvecl_uniform_gamma1 + * + * Description: Sample vector of polynomials with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_polyvecl *v: pointer to output vector + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + *************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + requires(nonce <= (UINT16_MAX - MLDSA_L) / MLDSA_L) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyvecl_ntt MLD_NAMESPACE_KL(polyvecl_ntt) +/************************************************* + * Name: mld_polyvecl_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_L. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyvecl *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k0, 0, MLDSA_L, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyvecl_pointwise_acc_montgomery \ + MLD_NAMESPACE_KL(polyvecl_pointwise_acc_montgomery) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery + * + * Description: Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * The first input "u" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * + * Arguments: - mld_poly *w: output polynomial + * - const mld_polyvecl *u: pointer to first input vector + * - const mld_polyvecl *v: pointer to second input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + + +#define mld_polyvecl_chknorm MLD_NAMESPACE_KL(polyvecl_chknorm) +/************************************************* + * Name: mld_polyvecl_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_L. + * Assumes input mld_polyvecl to be reduced by polyvecl_reduce(). + * + * Arguments: - const mld_polyvecl *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials is strictly smaller than B <= + * (MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +/* Vectors of polynomials of length MLDSA_K */ +typedef struct +{ + mld_poly vec[MLDSA_K]; +} mld_polyveck; + +/* Matrix of polynomials (K x L) */ +typedef struct +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + mld_polyvecl row_buffer; + uint8_t rho[MLDSA_SEEDBYTES]; +#else + mld_polyvecl vec[MLDSA_K]; +#endif +} mld_polymat; + +#define mld_polyveck_reduce MLD_NAMESPACE_KL(polyveck_reduce) +/************************************************* + * Name: polyveck_reduce + * + * Description: Reduce coefficients of polynomials in vector of length MLDSA_K + * to representatives in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) +); + +#define mld_polyveck_caddq MLD_NAMESPACE_KL(polyveck_caddq) +/************************************************* + * Name: mld_polyveck_caddq + * + * Description: For all coefficients of polynomials in vector of length MLDSA_K + * add MLDSA_Q if coefficient is negative. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_add MLD_NAMESPACE_KL(polyveck_add) +/************************************************* + * Name: mld_polyveck_add + * + * Description: Add vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to input-output vector of polynomials + * to be added to + * - const mld_polyveck *v: pointer to second input vector of + * polynomials + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(p0, 0, MLDSA_K, array_abs_bound(u->vec[p0].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) + requires(forall(p1, 0, MLDSA_K, + array_bound(v->vec[p1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(q2, 0, MLDSA_K, + array_bound(u->vec[q2].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_sub MLD_NAMESPACE_KL(polyveck_sub) +/************************************************* + * Name: mld_polyveck_sub + * + * Description: Subtract vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to first input vector + * - const mld_polyveck *v: pointer to second input vector to be + * subtracted from first input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(u->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_shiftl MLD_NAMESPACE_KL(polyveck_shiftl) +/************************************************* + * Name: mld_polyveck_shiftl + * + * Description: Multiply vector of polynomials of Length MLDSA_K by 2^MLDSA_D + *without modular reduction. Assumes input coefficients to be less than + *2^{31-MLDSA_D}. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_ntt MLD_NAMESPACE_KL(polyveck_ntt) +/************************************************* + * Name: mld_polyveck_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_K. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyveck_invntt_tomont MLD_NAMESPACE_KL(polyveck_invntt_tomont) +/************************************************* + * Name: mld_polyveck_invntt_tomont + * + * Description: Inverse NTT and multiplication by 2^{32} of polynomials + * in vector of length MLDSA_K. + * Input coefficients need to be less than MLDSA_Q, and + * Output coefficients are bounded by MLD_INTT_BOUND. + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) +); + +#define mld_polyveck_pointwise_poly_montgomery \ + MLD_NAMESPACE_KL(polyveck_pointwise_poly_montgomery) +/************************************************* + * Name: mld_polyveck_pointwise_poly_montgomery + * + * Description: Pointwise multiplication of a polynomial vector of length + * MLDSA_K by a single polynomial in NTT domain and multiplication + * of the resulting polynomial vector by 2^{-32}. + * + * Arguments: - mld_polyveck *r: pointer to output vector + * - mld_poly *a: pointer to input polynomial + * - mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(r, sizeof(mld_polyveck))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(r, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(r->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#define mld_polyveck_chknorm MLD_NAMESPACE_KL(polyveck_chknorm) +/************************************************* + * Name: mld_polyveck_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_K. + * Assumes input mld_polyveck to be reduced by polyveck_reduce(). + * + * Arguments: - const mld_polyveck *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials are strictly smaller than B <= + *(MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, + -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +#define mld_polyveck_power2round MLD_NAMESPACE_KL(polyveck_power2round) +/************************************************* + * Name: mld_polyveck_power2round + * + * Description: For all coefficients a of polynomials in vector of length + *MLDSA_K, compute a0, a1 such that a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with + *-2^{MLDSA_D-1} < a0 <= 2^{MLDSA_D-1}. Assumes coefficients to be standard + *representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to output vector of polynomials with + * coefficients a0 + * - const mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) +); + +#define mld_polyveck_decompose MLD_NAMESPACE_KL(polyveck_decompose) +/************************************************* + * Name: mld_polyveck_decompose + * + * Description: For all coefficients a of polynomials in vector of length + * MLDSA_K, compute high and low bits a0, a1 such a mod^+ MLDSA_Q = a1*ALPHA + * + a0 with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (MLDSA_Q-1)/ALPHA where we set + * a1 = 0 and -ALPHA/2 <= a0 = a mod MLDSA_Q - MLDSA_Q < 0. Assumes coefficients + * to be standard representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to input/output vector of + * polynomials with. Output polynomial has + * coefficients a0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v0->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + ensures(forall(k2, 0, MLDSA_K, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) +); + +#define mld_polyveck_make_hint MLD_NAMESPACE_KL(polyveck_make_hint) +/************************************************* + * Name: mld_polyveck_make_hint + * + * Description: Compute hint vector. + * + * Arguments: - mld_polyveck *h: pointer to output vector + * - const mld_polyveck *v0: pointer to low part of input vector + * - const mld_polyveck *v1: pointer to high part of input vector + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(return_value <= MLDSA_N * MLDSA_K) + ensures(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) +); + +#define mld_polyveck_use_hint MLD_NAMESPACE_KL(polyveck_use_hint) +/************************************************* + * Name: mld_polyveck_use_hint + * + * Description: Use hint vector to correct the high bits of input vector. + * + * Arguments: - mld_polyveck *w: pointer to output vector of polynomials with + * corrected high bits + * - const mld_polyveck *u: pointer to input vector + * - const mld_polyveck *h: pointer to input hint vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *v, + const mld_polyveck *h) +__contract__( + requires(memory_no_alias(w, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + assigns(memory_slice(w, sizeof(mld_polyveck))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) +); + +#define mld_polyveck_pack_w1 MLD_NAMESPACE_KL(polyveck_pack_w1) +/************************************************* + * Name: mld_polyveck_pack_w1 + * + * Description: Bit-pack polynomial vector w1 with coefficients in [0,15] or + * [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_K* MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_polyveck *a: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(w1, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(w1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) +); + +#define mld_polyveck_pack_eta MLD_NAMESPACE_KL(polyveck_pack_eta) +/************************************************* + * Name: mld_polyveck_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients + * in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyvecl_pack_eta MLD_NAMESPACE_KL(polyvecl_pack_eta) +/************************************************* + * Name: mld_polyvecl_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_L * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyveck_pack_t0 MLD_NAMESPACE_KL(polyveck_pack_t0) +/************************************************* + * Name: mld_polyveck_pack_t0 + * + * Description: Bit-pack polynomial vector to with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(p->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) +); + +#define mld_polyvecl_unpack_eta MLD_NAMESPACE_KL(polyvecl_unpack_eta) +/************************************************* + * Name: mld_polyvecl_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyvecl *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + assigns(memory_slice(p, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyvecl_unpack_z MLD_NAMESPACE_KL(polyvecl_unpack_z) +/************************************************* + * Name: mld_polyvecl_unpack_z + * + * Description: Unpack polynomial vector with coefficients in + * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_polyvecl *z: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(z->vec[k1].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyveck_unpack_eta MLD_NAMESPACE_KL(polyveck_unpack_eta) +/************************************************* + * Name: mld_polyveck_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyveck_unpack_t0 MLD_NAMESPACE_KL(polyveck_unpack_t0) +/************************************************* + * Name: mld_polyveck_unpack_t0 + * + * Description: Unpack polynomial vector with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) +); + +#define mld_polymat_get_row MLD_NAMESPACE_KL(polymat_get_row) +/************************************************* + * Name: mld_polymat_get_row + * + * Description: Retrieve a pointer to a specific row of the matrix. + * In MLD_CONFIG_REDUCE_RAM mode, generates the row on-demand. + * + * Arguments: - mld_polymat *mat: pointer to matrix + * - unsigned int row: row index (must be < MLDSA_K) + * + * Returns pointer to the row (mld_polyvecl) + **************************************************/ +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row); + +#define mld_polyvec_matrix_expand MLD_NAMESPACE_KL(polyvec_matrix_expand) +/************************************************* + * Name: mld_polyvec_matrix_expand + * + * Description: Implementation of ExpandA. Generates matrix A with uniformly + * random coefficients a_{i,j} by performing rejection + * sampling on the output stream of SHAKE128(rho|j|i) + * + * Arguments: - mld_polymat *mat: pointer to output matrix + * - const uint8_t rho[]: byte array containing seed rho + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +__contract__( + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +); + + + +#define mld_polyvec_matrix_pointwise_montgomery \ + MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery) +/************************************************* + * Name: mld_polyvec_matrix_pointwise_montgomery + * + * Description: Compute matrix-vector multiplication in NTT domain with + * pointwise multiplication and multiplication by 2^{-32}. + * Input matrix and vector must be in NTT domain representation. + * + * The first input "mat" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * Note: In MLD_CONFIG_REDUCE_RAM mode, mat cannot be const + * as rows are generated on-demand. + * + * Arguments: - mld_polyveck *t: pointer to output vector t + * - mld_polymat *mat: pointer to input matrix + * - const mld_polyvecl *v: pointer to input vector v + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(t, sizeof(mld_polyveck))) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(t, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#endif /* !MLD_POLYVEC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/randombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/randombytes.h new file mode 100644 index 0000000000..da55772419 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/randombytes.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_RANDOMBYTES_H +#define MLD_RANDOMBYTES_H + +#include +#include + +#include "cbmc.h" +#include "common.h" + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +#if !defined(MLD_CONFIG_CUSTOM_RANDOMBYTES) +MLD_MUST_CHECK_RETURN_VALUE +int randombytes(uint8_t *out, size_t outlen); +static MLD_INLINE int mld_randombytes(uint8_t *out, size_t outlen) +__contract__( + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) { return randombytes(out, outlen); } +#endif /* !MLD_CONFIG_CUSTOM_RANDOMBYTES */ +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ +#endif /* !MLD_RANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/reduce.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/reduce.h new file mode 100644 index 0000000000..413cf1829e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/reduce.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_REDUCE_H +#define MLD_REDUCE_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* check-magic: -4186625 == pow(2,32,MLDSA_Q) */ +#define MLD_MONT -4186625 + +/* Upper bound for domain of mld_reduce32() */ +#define MLD_REDUCE32_DOMAIN_MAX (INT32_MAX - (1 << 22)) + +/* Absolute bound for range of mld_reduce32() */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define MLD_REDUCE32_RANGE_MAX 6283009 + +/************************************************* + * Name: mld_montgomery_reduce + * + * Description: Generic Montgomery reduction; given a 64-bit integer a, computes + * 32-bit integer congruent to a * R^-1 mod q, where R=2^32 + * + * Arguments: - int64_t a: input integer to be reduced, of absolute value + * smaller or equal to INT64_MAX - 2^31 * MLDSA_Q. + * + * Returns: Integer congruent to a * R^-1 modulo q, with absolute value + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * In particular, if |a| < 2^31 * MLDSA_Q, the absolute value + * of the return value is < MLDSA_Q. + **************************************************/ +static MLD_INLINE int32_t mld_montgomery_reduce(int64_t a) +__contract__( + /* We don't attempt to express an input-dependent output bound + * as the post-condition here, as all call-sites satisfy the + * absolute input bound 2^31 * MLDSA_Q and higher-level + * reasoning can be conducted using |return_value| < MLDSA_Q. */ + requires(a > -(((int64_t)1 << 31) * MLDSA_Q) && + a < (((int64_t)1 << 31) * MLDSA_Q)) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* check-magic: 58728449 == unsigned_mod(pow(MLDSA_Q, -1, 2^32), 2^32) */ + const uint64_t QINV = 58728449; + + /* Compute a*q^{-1} mod 2^32 in unsigned representatives */ + const uint32_t a_reduced = mld_cast_int64_to_uint32(a); + const uint32_t a_inverted = (a_reduced * QINV) & UINT32_MAX; + + /* Lift to signed canonical representative mod 2^32. */ + const int32_t t = mld_cast_uint32_to_int32(a_inverted); + + int64_t r; + + mld_assert(a < +(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)) && + a > -(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q))); + + r = a - (int64_t)t * MLDSA_Q; + + /* + * PORTABILITY: Right-shift on a signed integer is, strictly-speaking, + * implementation-defined for negative left argument. Here, + * we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5)) + */ + r = r >> 32; + + /* Bounds: + * + * By construction of the Montgomery multiplication, by the time we + * compute r >> 32, r is divisible by 2^32, and hence + * + * |r >> 32| = |r| / 2^32 + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * (In general, we would only have |x >> n| <= ceil(|x| / 2^n)). + * + * In particular, if |a| < 2^31 * MLDSA_Q, then |return_value| < MLDSA_Q. + */ + return (int32_t)r; +} + +/************************************************* + * Name: mld_reduce32 + * + * Description: For finite field element a with a <= 2^{31} - 2^{22} - 1, + * compute r \equiv a (mod MLDSA_Q) such that + * -MLD_REDUCE32_RANGE_MAX <= r < MLD_REDUCE32_RANGE_MAX. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_reduce32(int32_t a) +__contract__( + requires(a <= MLD_REDUCE32_DOMAIN_MAX) + ensures(return_value >= -MLD_REDUCE32_RANGE_MAX) + ensures(return_value < MLD_REDUCE32_RANGE_MAX) +) +{ + int32_t t; + + t = (a + (1 << 22)) >> 23; + t = a - t * MLDSA_Q; + mld_assert((t - a) % MLDSA_Q == 0); + return t; +} + +/************************************************* + * Name: mld_caddq + * + * Description: Add MLDSA_Q if input coefficient is negative. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_caddq(int32_t a) +__contract__( + requires(a > -MLDSA_Q) + requires(a < MLDSA_Q) + ensures(return_value >= 0) + ensures(return_value < MLDSA_Q) + ensures(return_value == (a >= 0) ? a : (a + MLDSA_Q)) +) +{ + return mld_ct_sel_int32(a + MLDSA_Q, a, mld_ct_cmask_neg_i32(a)); +} + + +#endif /* !MLD_REDUCE_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/rounding.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/rounding.h new file mode 100644 index 0000000000..a83562b0f1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/rounding.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_ROUNDING_H +#define MLD_ROUNDING_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_power2round MLD_ADD_PARAM_SET(mld_power2round) +#define mld_decompose MLD_ADD_PARAM_SET(mld_decompose) +#define mld_make_hint MLD_ADD_PARAM_SET(mld_make_hint) +#define mld_use_hint MLD_ADD_PARAM_SET(mld_use_hint) +/* End of parameter set namespacing */ + +#define MLD_2_POW_D (1 << MLDSA_D) + +/************************************************* + * Name: mld_power2round + * + * Description: For finite field element a, compute a0, a1 such that + * a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with -2^{MLDSA_D-1} < a0 <= + * 2^{MLDSA_D-1}. Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: In the reference implementation, a1 is passed as a + * return value instead. + **************************************************/ +static MLD_INLINE void mld_power2round(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + ensures(*a0 > -(MLD_2_POW_D/2) && *a0 <= (MLD_2_POW_D/2)) + ensures(*a1 >= 0 && *a1 <= (MLDSA_Q - 1) / MLD_2_POW_D) + ensures((*a1 * MLD_2_POW_D + *a0 - a) % MLDSA_Q == 0) +) +{ + *a1 = (a + (1 << (MLDSA_D - 1)) - 1) >> MLDSA_D; + *a0 = a - (*a1 << MLDSA_D); +} + +/************************************************* + * Name: mld_decompose + * + * Description: For finite field element a, compute high and low bits a0, a1 + * such that a mod^+ MLDSA_Q = a1* 2 * MLDSA_GAMMA2 + a0 with + * -MLDSA_GAMMA2 < a0 <= MLDSA_GAMMA2 except + * if a1 = (MLDSA_Q-1)/(MLDSA_GAMMA2*2) where we set a1 = 0 and + * -MLDSA_GAMMA2 <= a0 = a mod^+ MLDSA_Q - MLDSA_Q < 0. + * Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: a1 is passed as a return value instead + **************************************************/ +static MLD_INLINE void mld_decompose(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + /* a0 = -MLDSA_GAMMA2 can only occur when (q-1) = a - (a mod MLDSA_GAMMA2), + * then a1=1; and a0 = a - (a mod MLDSA_GAMMA2) - 1 (@[FIPS204, Algorithm 36 (Decompose)]) */ + ensures(*a0 >= -MLDSA_GAMMA2 && *a0 <= MLDSA_GAMMA2) + ensures(*a1 >= 0 && *a1 < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) + ensures((*a1 * 2 * MLDSA_GAMMA2 + *a0 - a) % MLDSA_Q == 0) +) +{ + /* + * The goal is to compute f1 = round-(f / (2*GAMMA2)), which can be computed + * alternatively as round-(f / (128B)) = round-(ceil(f / 128) / B) where + * B = 2*GAMMA2 / 128. Here round-() denotes "round half down". + * + * The equality round-(f / (128B)) = round-(ceil(f / 128) / B) can deduced + * as follows. Since changing f to align-up(f, 128) can move f onto but not + * across a rounding boundary for division by 128*B (note that we need B to be + * even for this to work), and round- rounds down on the boundary, we have + * + * round-(f / (128B)) = round-(align-up(f, 128) / (128B)) + * = round-((align-up(f, 128) / 128) / B) + * = round-(ceil(f / 128) / B). + */ + *a1 = (a + 127) >> 7; + /* We know a >= 0 and a < MLDSA_Q, so... */ + /* check-magic: 65472 == round((MLDSA_Q-1)/128) */ + mld_assert(*a1 >= 0 && *a1 <= 65472); + +#if MLD_CONFIG_PARAMETER_SET == 44 + /* check-magic: 1488 == 2 * intdiv(intdiv(MLDSA_Q - 1, 88), 128) */ + /* check-magic: 11275 == floor(2**24 / 1488) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + */ + *a1 = (*a1 * 11275 + (1 << 23)) >> 24; + mld_assert(*a1 >= 0 && *a1 <= 44); + + *a1 = mld_ct_sel_int32(0, *a1, mld_ct_cmask_neg_i32(43 - *a1)); + mld_assert(*a1 >= 0 && *a1 <= 43); +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + /* check-magic: 4092 == 2 * intdiv(intdiv(MLDSA_Q - 1, 32), 128) */ + /* check-magic: 1025 == floor(2**22 / 4092) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + */ + *a1 = (*a1 * 1025 + (1 << 21)) >> 22; + mld_assert(*a1 >= 0 && *a1 <= 16); + + *a1 &= 15; + mld_assert(*a1 >= 0 && *a1 <= 15); + +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + + *a0 = a - *a1 * 2 * MLDSA_GAMMA2; + *a0 = mld_ct_sel_int32(*a0 - MLDSA_Q, *a0, + mld_ct_cmask_neg_i32((MLDSA_Q - 1) / 2 - *a0)); +} + +/************************************************* + * Name: mld_make_hint + * + * Description: Compute hint bit indicating whether the low bits of the + * input element overflow into the high bits. + * + * Arguments: - int32_t a0: low bits of input element + * - int32_t a1: high bits of input element + * + * Returns 1 if overflow, 0 otherwise + **************************************************/ +static MLD_INLINE unsigned int mld_make_hint(int32_t a0, int32_t a1) +__contract__( + ensures(return_value >= 0 && return_value <= 1) +) +{ + if (a0 > MLDSA_GAMMA2 || a0 < -MLDSA_GAMMA2 || + (a0 == -MLDSA_GAMMA2 && a1 != 0)) + { + return 1; + } + + return 0; +} + +/************************************************* + * Name: mld_use_hint + * + * Description: Correct high bits according to hint. + * + * Arguments: - int32_t a: input element + * - int32_t hint: hint bit + * + * Returns corrected high bits. + **************************************************/ +static MLD_INLINE int32_t mld_use_hint(int32_t a, int32_t hint) +__contract__( + requires(hint >= 0 && hint <= 1) + requires(a >= 0 && a < MLDSA_Q) + ensures(return_value >= 0 && return_value < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) +) +{ + int32_t a0, a1; + + mld_decompose(&a0, &a1, a); + if (hint == 0) + { + return a1; + } + +#if MLD_CONFIG_PARAMETER_SET == 44 + if (a0 > 0) + { + return (a1 == 43) ? 0 : a1 + 1; + } + else + { + return (a1 == 0) ? 43 : a1 - 1; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + if (a0 > 0) + { + return (a1 + 1) & 15; + } + else + { + return (a1 - 1) & 15; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + + +#endif /* !MLD_ROUNDING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/sign.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/sign.c new file mode 100644 index 0000000000..32bba52d65 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/sign.c @@ -0,0 +1,1508 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [Round3_Spec] + * CRYSTALS-Dilithium Algorithm Specifications and Supporting Documentation + * (Version 3.1) + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf + */ + +#include +#include + +#include "cbmc.h" +#include "ct.h" +#include "debug.h" +#include "packing.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" +#include "randombytes.h" +#include "sign.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_check_pct MLD_ADD_PARAM_SET(mld_check_pct) MLD_CONTEXT_PARAMETERS_2 +#define mld_sample_s1_s2 MLD_ADD_PARAM_SET(mld_sample_s1_s2) +#define mld_validate_hash_length MLD_ADD_PARAM_SET(mld_validate_hash_length) +#define mld_get_hash_oid MLD_ADD_PARAM_SET(mld_get_hash_oid) +#define mld_H MLD_ADD_PARAM_SET(mld_H) +#define mld_compute_pack_z MLD_ADD_PARAM_SET(mld_compute_pack_z) +#define mld_attempt_signature_generation \ + MLD_ADD_PARAM_SET(mld_attempt_signature_generation) MLD_CONTEXT_PARAMETERS_8 +#define mld_compute_t0_t1_tr_from_sk_components \ + MLD_ADD_PARAM_SET(mld_compute_t0_t1_tr_from_sk_components) \ + MLD_CONTEXT_PARAMETERS_7 +/* End of parameter set namespacing */ + + +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + ensures(return_value == 0 + || return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL) +); + +#if defined(MLD_CONFIG_KEYGEN_PCT) +/************************************************* + * @[FIPS140_3_IG] + * (https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf) + * + * TE10.35.02: Pair-wise Consistency Test (PCT) for DSA keypairs + * + * Purpose: Validates that a generated public/private key pair can correctly + * sign and verify data. Test performs signature generation using the private + * key (sk), followed by signature verification using the public key (pk). + * Returns 0 if the signature was successfully verified, non-zero if it cannot. + * + * Note: @[FIPS204] requires that public/private key pairs are to be used only + * for the calculation and/of verification of digital signatures. + **************************************************/ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t message[1] = {0}; + size_t siglen; + int ret; + MLD_ALLOC(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + MLD_ALLOC(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + + if (signature == NULL || pk_test == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Copy public key for testing */ + mld_memcpy(pk_test, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* Sign a test message using the original secret key */ + ret = mld_sign_signature(signature, &siglen, message, sizeof(message), NULL, + 0, sk, context); + if (ret != 0) + { + goto cleanup; + } + +#if defined(MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST) + /* Deliberately break public key for testing purposes */ + if (mld_break_pct()) + { + pk_test[0] = ~pk_test[0]; + } +#endif /* MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST */ + + /* Verify the signature using the (potentially corrupted) public key */ + ret = mld_sign_verify(signature, siglen, message, sizeof(message), NULL, 0, + pk_test, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + MLD_FREE(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + + return ret; +} +#else /* MLD_CONFIG_KEYGEN_PCT */ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + /* Skip PCT */ + ((void)pk); + ((void)sk); +#if defined(MLD_CONFIG_CONTEXT_PARAMETER) + ((void)context); +#endif + return 0; +} +#endif /* !MLD_CONFIG_KEYGEN_PCT */ + +static void mld_sample_s1_s2(mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t seed[MLDSA_CRHBYTES]) +__contract__( + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(object_whole(s1), object_whole(s2)) + ensures(forall(l0, 0, MLDSA_L, array_abs_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + ensures(forall(k0, 0, MLDSA_K, array_abs_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) +) +{ +/* Sample short vectors s1 and s2 */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; + uint16_t nonce = 0; + /* Safety: The nonces are at most 14 (MLDSA_L + MLDSA_K - 1), and, hence, the + * casts are safe. */ + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_eta(&s1->vec[i], seed, (uint8_t)(nonce + i)); + } + for (i = 0; i < MLDSA_K; i++) + { + mld_poly_uniform_eta(&s2->vec[i], seed, (uint8_t)(nonce + MLDSA_L + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLD_CONFIG_PARAMETER_SET == 44 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 4, 5, 6, 7); +#elif MLD_CONFIG_PARAMETER_SET == 65 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s2->vec[0], &s2->vec[1], + &s2->vec[2] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[2], &s2->vec[3], &s2->vec[4], &s2->vec[5], + seed, 7, 8, 9, 10); +#elif MLD_CONFIG_PARAMETER_SET == 87 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s1->vec[5], &s1->vec[6], + &s2->vec[0] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 7, 8, 9, 10); + mld_poly_uniform_eta_4x(&s2->vec[4], &s2->vec[5], &s2->vec[6], &s2->vec[7], + seed, 11, 12, 13, 14); +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ +} + +/************************************************* + * Name: mld_compute_t0_t1_tr_from_sk_components + * + * Description: Computes t0, t1, tr, and pk from secret key components + * rho, s1, s2. This is the shared computation used by + * both keygen and generating the public key from the + * secret key. + * + * Arguments: - mld_polyveck *t0: output t0 + * - mld_polyveck *t1: output t1 + * - uint8_t tr[MLDSA_TRBYTES]: output tr + * - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t rho[MLDSA_SEEDBYTES]: input rho + * - const mld_polyvecl *s1: input s1 + * - const mld_polyveck *s2: input s2 + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_t0_t1_tr_from_sk_components( + mld_polyveck *t0, mld_polyveck *t1, uint8_t tr[MLDSA_TRBYTES], + uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], const uint8_t rho[MLDSA_SEEDBYTES], + const mld_polyvecl *s1, const mld_polyveck *s2, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(l0, 0, MLDSA_L, array_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + requires(forall(k0, 0, MLDSA_K, array_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(forall(k1, 0, MLDSA_K, array_bound(t0->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(t1->vec[k2].coeffs, 0, MLDSA_N, 0, 1 << 10))) + ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY)) +{ + int ret; + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1hat, mld_polyvecl, 1, context); + MLD_ALLOC(t, mld_polyveck, 1, context); + + if (mat == NULL || s1hat == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Expand matrix */ + mld_polyvec_matrix_expand(mat, rho); + + /* Matrix-vector multiplication */ + *s1hat = *s1; + mld_polyvecl_ntt(s1hat); + mld_polyvec_matrix_pointwise_montgomery(t, mat, s1hat); + mld_polyveck_invntt_tomont(t); + + /* Add error vector s2 */ + mld_polyveck_add(t, s2); + + /* Reference: The following reduction is not present in the reference + * implementation. Omitting this reduction requires the output of + * the invntt to be small enough such that the addition of s2 does + * not result in absolute values >= MLDSA_Q. While our C, x86_64, + * and AArch64 invntt implementations produce small enough + * values for this to work out, it complicates the bounds + * reasoning. We instead add an additional reduction, and can + * consequently, relax the bounds requirements for the invntt. + */ + mld_polyveck_reduce(t); + + /* Decompose to get t1, t0 */ + mld_polyveck_caddq(t); + mld_polyveck_power2round(t1, t0, t); + + /* Pack public key and compute tr */ + mld_pack_pk(pk, rho, t1); + mld_shake256(tr, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + ret = 0; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_polyveck, 1, context); + MLD_FREE(s1hat, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + const uint8_t *rho, *rhoprime, *key; + MLD_ALLOC(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + MLD_ALLOC(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + + if (seedbuf == NULL || inbuf == NULL || tr == NULL || s1 == NULL || + s2 == NULL || t1 == NULL || t0 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Get randomness for rho, rhoprime and key */ + mld_memcpy(inbuf, seed, MLDSA_SEEDBYTES); + inbuf[MLDSA_SEEDBYTES + 0] = MLDSA_K; + inbuf[MLDSA_SEEDBYTES + 1] = MLDSA_L; + mld_shake256(seedbuf, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, inbuf, + MLDSA_SEEDBYTES + 2); + rho = seedbuf; + rhoprime = rho + MLDSA_SEEDBYTES; + key = rhoprime + MLDSA_CRHBYTES; + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + + /* Sample s1 and s2 */ + mld_sample_s1_s2(s1, s2, rhoprime); + + /* Compute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0, t1, tr, pk, rho, s1, s2, + context); + if (ret != 0) + { + goto cleanup; + } + + /* Pack secret key */ + mld_pack_sk(sk, rho, tr, key, t0, s1, s2); + + /* Constant time: pk is the public key, inherently public data */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_FREE(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + + if (ret != 0) + { + return ret; + } + + /* Pairwise Consistency Test (PCT) @[FIPS140_3_IG, p.87] */ + /* Do this after freeing all temporaries. */ + return mld_check_pct(pk, sk, context); +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t seed[MLDSA_SEEDBYTES]; + int ret; + if (mld_randombytes(seed, MLDSA_SEEDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(seed, sizeof(seed)); + ret = mld_sign_keypair_internal(pk, sk, seed, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed, sizeof(seed)); + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +/************************************************* + * Name: mld_H + * + * Description: Abstracts application of SHAKE256 to + * one, two or three blocks of data, + * yielding a user-requested size of + * output. + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in1: pointer to input block 1 + * Must NOT be NULL + * - size_t in1len: length of input in1 bytes + * - const uint8_t *in2: pointer to input block 2 + * May be NULL if in2len=0, in which case + * this block is ignored + * - size_t in2len: length of input in2 bytes + * - const uint8_t *in3: pointer to input block 3 + * May be NULL if in3len=0, in which case + * this block is ignored + * - size_t in3len: length of input in3 bytes + **************************************************/ +static void mld_H(uint8_t *out, size_t outlen, const uint8_t *in1, + size_t in1len, const uint8_t *in2, size_t in2len, + const uint8_t *in3, size_t in3len) +__contract__( + requires(in1len <= MLD_MAX_BUFFER_SIZE) + requires(in2len <= MLD_MAX_BUFFER_SIZE) + requires(in3len <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in1, in1len)) + requires(in2len == 0 || memory_no_alias(in2, in2len)) + requires(in3len == 0 || memory_no_alias(in3, in3len)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) +{ + mld_shake256ctx state; + mld_shake256_init(&state); + mld_shake256_absorb(&state, in1, in1len); + if (in2len != 0) + { + mld_shake256_absorb(&state, in2, in2len); + } + if (in3len != 0) + { + mld_shake256_absorb(&state, in3, in3len); + } + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(&state, sizeof(state)); +} + +/************************************************* + * Name: mld_compute_pack_z + * + * Description: Computes z = y + s1*c, checks that z has coefficients smaller + * than MLDSA_GAMMA1 - MLDSA_BETA, and packs z into the + * signature buffer. + * + * Arguments: - uint8_t *sig: output signature + * - const mld_poly *cp: challenge polynomial + * - const polyvecl *s1: secret vector s1 + * - const polyvecl *y: masking vector y + * + * Returns: - 0: Success (z has coefficients smaller than + * MLDSA_GAMMA1 - MLDSA_BETA,) + * - MLD_ERR_FAIL: z rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This function is inlined into mld_sign_signature in the + * reference implementation. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_pack_z(uint8_t sig[MLDSA_CRYPTO_BYTES], + const mld_poly *cp, const mld_polyvecl *s1, + const mld_polyvecl *y, mld_poly *z) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(cp, sizeof(mld_poly))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(y, sizeof(mld_polyvecl))) + requires(memory_no_alias(z, sizeof(mld_poly))) + requires(array_abs_bound(cp->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_L, + array_bound(y->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + requires(forall(k1, 0, MLDSA_L, array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(memory_slice(z, sizeof(mld_poly))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int i; + uint32_t z_invalid; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(z, sizeof(mld_poly)), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_poly_pointwise_montgomery(z, cp, &s1->vec[i]); + mld_poly_invntt_tomont(z); + mld_poly_add(z, &y->vec[i]); + mld_poly_reduce(z); + + z_invalid = mld_poly_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA); + /* Constant time: It is fine (and prohibitively expensive to avoid) + * to leak the result of the norm check and which polynomial in z caused a + * rejection. It would even be okay to leak which coefficient led to + * rejection as the candidate signature will be discarded anyway. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(&z_invalid, sizeof(uint32_t)); + if (z_invalid) + { + return MLD_ERR_FAIL; /* reject */ + } + /* If z is valid, then its coefficients are bounded by + * MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below + * to prove the pre-condition of pack_sig_z() */ + mld_assert_abs_bound(z, MLDSA_N, (MLDSA_GAMMA1 - MLDSA_BETA)); + + /* After the norm check, the distribution of each coefficient of z is + * independent of the secret key and it can, hence, be considered + * public. It is, hence, okay to immediately pack it into the user-provided + * signature buffer. */ + mld_pack_sig_z(sig, z, i); + } + return 0; +} + +/* Reference: The reference implementation does not explicitly check the + * maximum nonce value, but instead loops indefinitely (even when the nonce + * would overflow). Internally, sampling of y uses + * (nonceL), (nonceL+1), ... (nonce*L+L-1). + * Hence, there are no overflows if nonce < (UINT16_MAX - L)/L. + * Explicitly checking for this explicitly allows us to prove type-safety. + * Note that FIPS204 explicitly allows an upper-bound this loop of + * 814 (< (UINT16_MAX - L)/L) - see @[FIPS204, Appendix C]. */ +#define MLD_NONCE_UB ((UINT16_MAX - MLDSA_L) / MLDSA_L) + +/************************************************* + * Name: attempt_signature_generation + * + * Description: Attempts to generate a single signature. + * + * Arguments: - uint8_t *sig: pointer to output signature + * - const uint8_t *mu: pointer to message or hash + * of exactly MLDSA_CRHBYTES bytes + * - const uint8_t *rhoprime: pointer to randomness seed + * - uint16_t nonce: current nonce value + * - const mld_polymat *mat: expanded matrix + * - const polyvecl *s1: secret vector s1 + * - const polyveck *s2: secret vector s2 + * - const polyveck *t0: vector t0 + * + * Returns: - 0: Signature generation succeeded + * - MLD_ERR_FAIL: Signature rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This code differs from the reference implementation + * in that it factors out the core signature generation + * step into a distinct function here in order to improve + * efficiency of CBMC proof. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_attempt_signature_generation( + uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *mu, + const uint8_t rhoprime[MLDSA_CRHBYTES], uint16_t nonce, mld_polymat *mat, + const mld_polyvecl *s1, const mld_polyveck *s2, const mld_polyveck *t0, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(rhoprime, MLDSA_CRHBYTES)) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(nonce <= MLD_NONCE_UB) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int n; + uint32_t w0_invalid, h_invalid; + int ret; + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyvecl y; + mld_polyveck h; + } + yh_u; + mld_polyvecl *y; + mld_polyveck *h; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck w1; + mld_polyvecl tmp; + } + w1tmp_u; + mld_polyveck *w1; + mld_polyvecl *tmp; + + MLD_ALLOC(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(yh, yh_u, 1, context); + MLD_ALLOC(z, mld_poly, 1, context); + MLD_ALLOC(w1tmp, w1tmp_u, 1, context); + MLD_ALLOC(w0, mld_polyveck, 1, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(t, mld_poly, 1, context); + + if (challenge_bytes == NULL || yh == NULL || z == NULL || w1tmp == NULL || + w0 == NULL || cp == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + y = &yh->y; + h = &yh->h; + w1 = &w1tmp->w1; + tmp = &w1tmp->tmp; + + /* Sample intermediate vector y */ + mld_polyvecl_uniform_gamma1(y, rhoprime, nonce); + + /* Matrix-vector multiplication */ + *tmp = *y; + mld_polyvecl_ntt(tmp); + mld_polyvec_matrix_pointwise_montgomery(w0, mat, tmp); + mld_polyveck_invntt_tomont(w0); + + /* Decompose w and call the random oracle */ + mld_polyveck_caddq(w0); + mld_polyveck_decompose(w1, w0); + mld_polyveck_pack_w1(sig, w1); + + mld_H(challenge_bytes, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, sig, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + /* Constant time: Leaking challenge_bytes does not reveal any information + * about the secret key as H() is modelled as random oracle. + * This also applies to challenges for rejected signatures. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(challenge_bytes, MLDSA_CTILDEBYTES); + mld_poly_challenge(cp, challenge_bytes); + mld_poly_ntt(cp); + + /* Compute z, reject if it reveals secret */ + ret = mld_compute_pack_z(sig, cp, s1, y, t); + if (ret) + { + goto cleanup; + } + + /* Check that subtracting cs2 does not change high bits of w and low bits + * do not reveal secret information */ + mld_polyveck_pointwise_poly_montgomery(h, cp, s2); + mld_polyveck_invntt_tomont(h); + mld_polyveck_sub(w0, h); + mld_polyveck_reduce(w0); + + w0_invalid = mld_polyveck_chknorm(w0, MLDSA_GAMMA2 - MLDSA_BETA); + /* Constant time: w0_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&w0_invalid, sizeof(uint32_t)); + if (w0_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* Compute hints for w1 */ + mld_polyveck_pointwise_poly_montgomery(h, cp, t0); + mld_polyveck_invntt_tomont(h); + mld_polyveck_reduce(h); + + h_invalid = mld_polyveck_chknorm(h, MLDSA_GAMMA2); + /* Constant time: h_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&h_invalid, sizeof(uint32_t)); + if (h_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + mld_polyveck_add(w0, h); + + /* Constant time: At this point all norm checks have passed and we, hence, + * know that the signature does not leak any secret information. + * Consequently, any value that can be computed from the signature and public + * key is considered public. + * w0 and w1 are public as they can be computed from Az - ct = \alpha w1 + w0. + * h=c*t0 is public as both c and t0 are public. + * For a more detailed discussion, refer to https://eprint.iacr.org/2022/1406. + */ + MLD_CT_TESTING_DECLASSIFY(w0, sizeof(*w0)); + MLD_CT_TESTING_DECLASSIFY(w1, sizeof(*w1)); + n = mld_polyveck_make_hint(h, w0, w1); + if (n > MLDSA_OMEGA) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* All is well - write signature */ + mld_pack_sig_c_h(sig, challenge_bytes, h, n); + /* Constant time: At this point it is clear that the signature is valid - it + * can, hence, be considered public. */ + MLD_CT_TESTING_DECLASSIFY(sig, MLDSA_CRYPTO_BYTES); + ret = 0; /* success */ + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_poly, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(w0, mld_polyveck, 1, context); + MLD_FREE(w1tmp, w1tmp_u, 1, context); + MLD_FREE(z, mld_poly, 1, context); + MLD_FREE(yh, yh_u, 1, context); + MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + + return ret; +} +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + uint8_t *rho, *tr, *key, *mu, *rhoprime; + uint16_t nonce = 0; + MLD_ALLOC(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + + if (seedbuf == NULL || mat == NULL || s1 == NULL || t0 == NULL || s2 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + rho = seedbuf; + tr = rho + MLDSA_SEEDBYTES; + key = tr + MLDSA_TRBYTES; + mu = key + MLDSA_SEEDBYTES; + rhoprime = mu + MLDSA_CRHBYTES; + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + if (!externalmu) + { + /* Compute mu = CRH(tr, pre, msg) */ + mld_H(mu, MLDSA_CRHBYTES, tr, MLDSA_TRBYTES, pre, prelen, m, mlen); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Compute rhoprime = CRH(key, rnd, mu) */ + mld_H(rhoprime, MLDSA_CRHBYTES, key, MLDSA_SEEDBYTES, rnd, MLDSA_RNDBYTES, mu, + MLDSA_CRHBYTES); + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + /* Expand matrix and transform vectors */ + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(s1); + mld_polyveck_ntt(s2); + mld_polyveck_ntt(t0); + + /* By default, return failure. Flip to success and write output + * once signature generation succeeds. */ + ret = MLD_ERR_FAIL; + + /* Reference: This code is re-structured using a while(1), */ + /* with explicit "continue" statements (rather than "goto") */ + /* to implement rejection of invalid signatures. */ + while (1) + __loop__( + assigns(nonce, ret, object_whole(siglen), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(nonce <= MLD_NONCE_UB) + + /* t0, s1, s2, and mat are initialized above and are NOT changed by this */ + /* loop. We can therefore re-assert their bounds here as part of the */ + /* loop invariant. This makes proof noticeably faster with CBMC */ + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + invariant(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(ret == MLD_ERR_FAIL) + ) + { + /* Reference: this code explicitly checks for exhaustion of nonce */ + /* values to provide predictable termination and results in that case */ + /* Checking here also means that incrementing nonce below can also */ + /* be proven to be type-safe. */ + if (nonce == MLD_NONCE_UB) + { + /* Note that ret == MLD_ERR_FAIL by default, so we + * don't need to set it here. */ + break; + } + + ret = mld_attempt_signature_generation(sig, mu, rhoprime, nonce, mat, s1, + s2, t0, context); + nonce++; + if (ret == 0) + { + *siglen = MLDSA_CRYPTO_BYTES; + break; + } + else if (ret != MLD_ERR_FAIL) + { + /* For failures such as out-of-memory, propagate and exit immediately. */ + break; + } + + /* Otherwise, try again. */ + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the signature buffer. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + return ret; +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + size_t pre_len; + int ret; + MLD_ALLOC(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + MLD_ALLOC(rnd, uint8_t, MLDSA_RNDBYTES, context); + + if (pre == NULL || rnd == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Prepare domain separation prefix for pure ML-DSA */ + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, m, mlen, pre, pre_len, rnd, sk, + 0, context); + +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(rnd, uint8_t, MLDSA_RNDBYTES, context); + MLD_FREE(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t rnd[MLDSA_RNDBYTES]; + int ret; + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + *siglen = 0; + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, + rnd, sk, 1, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(rnd, sizeof(rnd)); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + for (i = 0; i < mlen; ++i) + __loop__( + assigns(i, object_whole(sm)) + invariant(i <= mlen) + ) + { + sm[MLDSA_CRYPTO_BYTES + mlen - 1 - i] = m[mlen - 1 - i]; + } + ret = mld_sign_signature(sm, smlen, sm + MLDSA_CRYPTO_BYTES, mlen, ctx, + ctxlen, sk, context); + *smlen += mlen; + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret, cmp; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck t1; + mld_polyveck w1; + } + t1w1_u; + mld_polyveck *t1; + mld_polyveck *w1; + + MLD_ALLOC(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_ALLOC(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(z, mld_polyvecl, 1, context); + MLD_ALLOC(t1w1, t1w1_u, 1, context); + MLD_ALLOC(tmp, mld_polyveck, 1, context); + MLD_ALLOC(h, mld_polyveck, 1, context); + + if (buf == NULL || rho == NULL || mu == NULL || c == NULL || c2 == NULL || + cp == NULL || mat == NULL || z == NULL || t1w1 == NULL || tmp == NULL || + h == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + t1 = &t1w1->t1; + w1 = &t1w1->w1; + + if (siglen != MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + mld_unpack_pk(rho, t1, pk); + + /* mld_unpack_sig and mld_polyvecl_chknorm signal failure through a + * single non-zero error code that's not yet aligned with MLD_ERR_XXX. + * Map it to MLD_ERR_FAIL explicitly. */ + if (mld_unpack_sig(c, z, h, sig)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + if (mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + if (!externalmu) + { + /* Compute CRH(H(rho, t1), pre, msg) */ + MLD_ALIGN uint8_t hpk[MLDSA_CRHBYTES]; + mld_H(hpk, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES, NULL, 0, NULL, + 0); + mld_H(mu, MLDSA_CRHBYTES, hpk, MLDSA_TRBYTES, pre, prelen, m, mlen); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(hpk, sizeof(hpk)); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Matrix-vector multiplication; compute Az - c2^dt1 */ + mld_poly_challenge(cp, c); + mld_poly_ntt(cp); + mld_polyveck_shiftl(t1); + mld_polyveck_ntt(t1); + mld_polyveck_pointwise_poly_montgomery(tmp, cp, t1); + + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(z); + mld_polyvec_matrix_pointwise_montgomery(w1, mat, z); + mld_polyveck_sub(w1, tmp); + mld_polyveck_reduce(w1); + mld_polyveck_invntt_tomont(w1); + + /* Reconstruct w1 */ + mld_polyveck_caddq(w1); + mld_polyveck_use_hint(tmp, w1, h); + mld_polyveck_pack_w1(buf, tmp); + /* Call random oracle and verify challenge */ + mld_H(c2, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, buf, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + + cmp = mld_ct_memcmp(c, c2, MLDSA_CTILDEBYTES); + + /* Declassify the result of the verification. */ + MLD_CT_TESTING_DECLASSIFY(&cmp, sizeof(cmp)); + + ret = cmp == 0 ? 0 : MLD_ERR_FAIL; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(h, mld_polyveck, 1, context); + MLD_FREE(tmp, mld_polyveck, 1, context); + MLD_FREE(t1w1, t1w1_u, 1, context); + MLD_FREE(z, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, m, mlen, pre, pre_len, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + return mld_sign_verify_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, pk, + 1, context); +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + if (smlen < MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + *mlen = smlen - MLDSA_CRYPTO_BYTES; + ret = mld_sign_verify(sm, MLDSA_CRYPTO_BYTES, sm + MLDSA_CRYPTO_BYTES, *mlen, + ctx, ctxlen, pk, context); + if (ret == 0) + { + /* All good, copy msg, return 0 */ + for (i = 0; i < *mlen; ++i) + __loop__( + assigns(i, memory_slice(m, *mlen)) + invariant(i <= *mlen) + ) + { + m[i] = sm[MLDSA_CRYPTO_BYTES + i]; + } + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the message buffer. */ + *mlen = 0; + mld_memset(m, 0, smlen); + } + + return ret; +} + + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_signature_internal(sig, siglen, pre, pre_len, NULL, 0, rnd, sk, + 0, context); +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, pre, pre_len, NULL, 0, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_signature_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, rnd, sk, + MLD_PREHASH_SHAKE_256, context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_verify_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, pk, MLD_PREHASH_SHAKE_256, + context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + + +#define MLD_PRE_HASH_OID_LEN 11 + +/************************************************* + * Name: mld_get_hash_oid + * + * Description: Returns the OID of a given SHA-2/SHA-3 hash function. + * + * Arguments: - uint8_t oid[11]: pointer to output oid + * - int hashalg: hash algorithm constant (MLD_PREHASH_*) + * + ***************************************************/ +static void mld_get_hash_oid(uint8_t oid[MLD_PRE_HASH_OID_LEN], int hashalg) +{ + unsigned int i; + static const struct + { + int alg; + uint8_t oid[MLD_PRE_HASH_OID_LEN]; + } oid_map[] = { + {MLD_PREHASH_SHA2_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}}, + {MLD_PREHASH_SHA2_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}}, + {MLD_PREHASH_SHA2_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}}, + {MLD_PREHASH_SHA2_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}}, + {MLD_PREHASH_SHA2_512_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05}}, + {MLD_PREHASH_SHA2_512_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06}}, + {MLD_PREHASH_SHA3_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07}}, + {MLD_PREHASH_SHA3_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08}}, + {MLD_PREHASH_SHA3_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09}}, + {MLD_PREHASH_SHA3_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A}}, + {MLD_PREHASH_SHAKE_128, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B}}, + {MLD_PREHASH_SHAKE_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C}}}; + + for (i = 0; i < sizeof(oid_map) / sizeof(oid_map[0]); i++) + __loop__( + invariant(i <= sizeof(oid_map) / sizeof(oid_map[0])) + ) + { + if (oid_map[i].alg == hashalg) + { + mld_memcpy(oid, oid_map[i].oid, MLD_PRE_HASH_OID_LEN); + return; + } + } +} + +static int mld_validate_hash_length(int hashalg, size_t len) +{ + switch (hashalg) + { + case MLD_PREHASH_SHA2_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_128: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_256: + return (len == 512 / 8) ? 0 : -1; + } + return -1; +} + +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +{ + if (ctxlen > 255) + { + return 0; + } + + if (hashalg != MLD_PREHASH_NONE) + { + if (ph == NULL || mld_validate_hash_length(hashalg, phlen) != 0) + { + return 0; + } + } + + /* Common prefix: 0x00/0x01 || ctxlen || ctx */ + prefix[0] = (hashalg == MLD_PREHASH_NONE) ? 0 : 1; + prefix[1] = (uint8_t)ctxlen; + if (ctxlen > 0) + { + mld_memcpy(prefix + 2, ctx, ctxlen); + } + + if (hashalg == MLD_PREHASH_NONE) + { + return 2 + ctxlen; + } + + /* HashML-DSA: append oid || ph */ + mld_get_hash_oid(prefix + 2 + ctxlen, hashalg); + mld_memcpy(prefix + 2 + ctxlen + MLD_PRE_HASH_OID_LEN, ph, phlen); + return 2 + ctxlen + MLD_PRE_HASH_OID_LEN + phlen; +} + +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + uint8_t check, cmp0, cmp1, chk1, chk2; + int ret; + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(t0_computed, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + + if (rho == NULL || tr == NULL || tr_computed == NULL || key == NULL || + s1 == NULL || s2 == NULL || t0 == NULL || t0_computed == NULL || + t1 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Unpack secret key */ + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + /* Validate s1 and s2 coefficients are within [-MLDSA_ETA, MLDSA_ETA] */ + chk1 = mld_polyvecl_chknorm(s1, MLDSA_ETA + 1) & 0xFF; + chk2 = mld_polyveck_chknorm(s2, MLDSA_ETA + 1) & 0xFF; + + /* Recompute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0_computed, t1, tr_computed, + pk, rho, s1, s2, context); + if (ret != 0) + { + goto cleanup; + } + + /* Validate t0 and tr using constant-time comparisons */ + cmp0 = mld_ct_memcmp((const uint8_t *)t0, (const uint8_t *)t0_computed, + sizeof(mld_polyveck)); + cmp1 = mld_ct_memcmp((const uint8_t *)tr, (const uint8_t *)tr_computed, + MLDSA_TRBYTES); + check = mld_value_barrier_u8(cmp0 | cmp1 | chk1 | chk2); + + /* Declassify the final result of the validity check. */ + MLD_CT_TESTING_DECLASSIFY(&check, sizeof(check)); + ret = (check != 0) ? MLD_ERR_FAIL : 0; + +cleanup: + + if (ret != 0) + { + mld_zeroize(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + } + + /* Constant time: pk is either the valid public key or zeroed on error */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(t0_computed, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + + return ret; +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_check_pct +#undef mld_sample_s1_s2 +#undef mld_validate_hash_length +#undef mld_get_hash_oid +#undef mld_H +#undef mld_compute_pack_z +#undef mld_attempt_signature_generation +#undef mld_compute_t0_t1_tr_from_sk_components +#undef MLD_NONCE_UB +#undef MLD_PRE_HASH_OID_LEN diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/sign.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/sign.h new file mode 100644 index 0000000000..2e0bac32ea --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/sign.h @@ -0,0 +1,807 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_SIGN_H +#define MLD_SIGN_H + +#include +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "polyvec.h" +#include "sys.h" + +#if defined(MLD_CHECK_APIS) +/* Include to ensure consistency between internal sign.h + * and external mldsa_native.h. */ +#include "mldsa_native.h" + +#if MLDSA_CRYPTO_SECRETKEYBYTES != \ + MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for SECRETKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_PUBLICKEYBYTES != \ + MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for PUBLICKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_BYTES != MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for CRYPTO_BYTES between sign.h and mldsa_native.h +#endif + +#endif /* MLD_CHECK_APIS */ + +#define mld_sign_keypair_internal \ + MLD_NAMESPACE_KL(keypair_internal) MLD_CONTEXT_PARAMETERS_3 +#define mld_sign_keypair MLD_NAMESPACE_KL(keypair) MLD_CONTEXT_PARAMETERS_2 +#define mld_sign_signature_internal \ + MLD_NAMESPACE_KL(signature_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_signature MLD_NAMESPACE_KL(signature) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_extmu \ + MLD_NAMESPACE_KL(signature_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign MLD_NAMESPACE_KL(sign) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_internal \ + MLD_NAMESPACE_KL(verify_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify MLD_NAMESPACE_KL(verify) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_extmu \ + MLD_NAMESPACE_KL(verify_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign_open MLD_NAMESPACE_KL(open) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_pre_hash_internal \ + MLD_NAMESPACE_KL(signature_pre_hash_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_verify_pre_hash_internal \ + MLD_NAMESPACE_KL(verify_pre_hash_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_signature_pre_hash_shake256 \ + MLD_NAMESPACE_KL(signature_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify_pre_hash_shake256 \ + MLD_NAMESPACE_KL(verify_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_7 +#define mld_prepare_domain_separation_prefix \ + MLD_NAMESPACE_KL(prepare_domain_separation_prefix) +#define mld_sign_pk_from_sk \ + MLD_NAMESPACE_KL(pk_from_sk) MLD_CONTEXT_PARAMETERS_2 + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: mld_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: input random seed + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int externalmu: indicates input message m is + * processed as mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return MLD_ERR_FAIL in that case. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires((externalmu == 0 && (prelen == 0 || memory_no_alias(pre, prelen))) || + (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) + ensures(return_value == 0 ==> *siglen == MLDSA_CRYPTO_BYTES) + ensures(return_value != 0 ==> *siglen == 0) +); + +/************************************************* + * Name: mld_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_signature_extmu + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign + * + * Description: Compute signed message. + * + * Arguments: - uint8_t *sm: pointer to output signed message + * (allocated array with MLDSA_CRYPTO_BYTES + + *mlen bytes), can be equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sm, MLDSA_CRYPTO_BYTES + mlen)) + requires(memory_no_alias(smlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sm, MLDSA_CRYPTO_BYTES + mlen)) + assigns(object_whole(smlen)) + ensures((return_value == 0 && *smlen == MLDSA_CRYPTO_BYTES + mlen) || + (return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL)) +); + +/************************************************* + * Name: mld_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as + * mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(externalmu == 0 || (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + requires(externalmu == 1 || prelen == 0 || memory_no_alias(pre, prelen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_open + * + * Description: Verify signed message. + * + * Arguments: - uint8_t *m: pointer to output message (allocated array + * with smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context tring + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(smlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(m, smlen)) + requires(memory_no_alias(mlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(sm, smlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + assigns(memory_slice(m, smlen)) + assigns(memory_slice(mlen, sizeof(size_t))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and + * verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/* Maximum formatted domain separation message length: + * - Pure ML-DSA: 0x00 || ctxlen || ctx (max 255) + * - HashML-DSA: 0x01 || ctxlen || ctx (max 255) || oid (11) || ph (max 64) */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +__contract__( + requires(ctxlen <= 255) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(hashalg == MLD_PREHASH_NONE || memory_no_alias(ph, phlen)) + requires(memory_no_alias(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + assigns(memory_slice(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + ensures(return_value <= MLD_DOMAIN_SEPARATION_MAX_BYTES) +); + +/************************************************* + * Name: mld_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: input secret + * key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); +#endif /* !MLD_SIGN_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/symmetric.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/symmetric.h new file mode 100644 index 0000000000..bb70f05552 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/symmetric.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_SYMMETRIC_H +#define MLD_SYMMETRIC_H + +#include +#include "cbmc.h" +#include "common.h" + +#include MLD_FIPS202_HEADER_FILE +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#include MLD_FIPS202X4_HEADER_FILE +#endif + +#define MLD_STREAM128_BLOCKBYTES SHAKE128_RATE +#define MLD_STREAM256_BLOCKBYTES SHAKE256_RATE + +#define mld_xof256_ctx mld_shake256ctx +#define mld_xof256_init(CTX) mld_shake256_init(CTX) + +#define mld_xof256_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake256_absorb(CTX, IN, INBYTES); \ + mld_shake256_finalize(CTX); \ + } while (0) + + +#define mld_xof256_release(CTX) mld_shake256_release(CTX) +#define mld_xof256_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake256_squeeze(OUT, (OUTBLOCKS) * SHAKE256_RATE, STATE) + +#define mld_xof128_ctx mld_shake128ctx +#define mld_xof128_init(CTX) mld_shake128_init(CTX) + +#define mld_xof128_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake128_absorb(CTX, IN, INBYTES); \ + mld_shake128_finalize(CTX); \ + } while (0) + +#define mld_xof128_release(CTX) mld_shake128_release(CTX) +#define mld_xof128_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake128_squeeze(OUT, (OUTBLOCKS) * SHAKE128_RATE, STATE) + +#define mld_xof256_x4_ctx mld_shake256x4ctx +#define mld_xof256_x4_init(CTX) mld_shake256x4_init((CTX)) +#define mld_xof256_x4_absorb(CTX, IN, INBYTES) \ + mld_shake256x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof256_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake256x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof256_x4_release(CTX) mld_shake256x4_release((CTX)) + +#define mld_xof128_x4_ctx mld_shake128x4ctx +#define mld_xof128_x4_init(CTX) mld_shake128x4_init((CTX)) +#define mld_xof128_x4_absorb(CTX, IN, INBYTES) \ + mld_shake128x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof128_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake128x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof128_x4_release(CTX) mld_shake128x4_release((CTX)) + +#endif /* !MLD_SYMMETRIC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/sys.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/sys.h new file mode 100644 index 0000000000..1226526420 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/sys.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_SYS_H +#define MLD_SYS_H + +#if !defined(MLD_CONFIG_NO_ASM) && (defined(__GNUC__) || defined(__clang__)) +#define MLD_HAVE_INLINE_ASM +#endif + +/* Try to find endianness, if not forced through CFLAGS already */ +#if !defined(MLD_SYS_LITTLE_ENDIAN) && !defined(MLD_SYS_BIG_ENDIAN) +#if defined(__BYTE_ORDER__) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define MLD_SYS_LITTLE_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define MLD_SYS_BIG_ENDIAN +#else +#error "__BYTE_ORDER__ defined, but don't recognize value." +#endif +#endif /* __BYTE_ORDER__ */ + +/* MSVC does not define __BYTE_ORDER__. However, MSVC only supports + * little endian x86, x86_64, and AArch64. It is, hence, safe to assume + * little endian. */ +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_IX86) || defined(_M_ARM64)) +#define MLD_SYS_LITTLE_ENDIAN +#endif + +#endif /* !MLD_SYS_LITTLE_ENDIAN && !MLD_SYS_BIG_ENDIAN */ + +/* Check if we're running on an AArch64 little endian system. _M_ARM64 is set by + * MSVC. */ +#if defined(__AARCH64EL__) || defined(_M_ARM64) +#define MLD_SYS_AARCH64 +#endif + +/* Check if we're running on an AArch64 big endian system. */ +#if defined(__AARCH64EB__) +#define MLD_SYS_AARCH64_EB +#endif + +#if defined(__x86_64__) +#define MLD_SYS_X86_64 +#if defined(__AVX2__) +#define MLD_SYS_X86_64_AVX2 +#endif +#endif /* __x86_64__ */ + +#if defined(MLD_SYS_LITTLE_ENDIAN) && defined(__powerpc64__) +#define MLD_SYS_PPC64LE +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 +#define MLD_SYS_RISCV64 +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32 +#define MLD_SYS_RISCV32 +#endif + +#if defined(_WIN64) || defined(_WIN32) +#define MLD_SYS_WINDOWS +#endif + +#if defined(__linux__) +#define MLD_SYS_LINUX +#endif + +#if defined(__APPLE__) +#define MLD_SYS_APPLE +#endif + +/* If MLD_FORCE_AARCH64 is set, assert that we're indeed on an AArch64 system. + */ +#if defined(MLD_FORCE_AARCH64) && !defined(MLD_SYS_AARCH64) +#error "MLD_FORCE_AARCH64 is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_AARCH64_EB is set, assert that we're indeed on a big endian + * AArch64 system. */ +#if defined(MLD_FORCE_AARCH64_EB) && !defined(MLD_SYS_AARCH64_EB) +#error \ + "MLD_FORCE_AARCH64_EB is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_X86_64 is set, assert that we're indeed on an X86_64 system. */ +#if defined(MLD_FORCE_X86_64) && !defined(MLD_SYS_X86_64) +#error "MLD_FORCE_X86_64 is set, but we don't seem to be on an X86_64 system." +#endif + +#if defined(MLD_FORCE_PPC64LE) && !defined(MLD_SYS_PPC64LE) +#error "MLD_FORCE_PPC64LE is set, but we don't seem to be on a PPC64LE system." +#endif + +#if defined(MLD_FORCE_RISCV64) && !defined(MLD_SYS_RISCV64) +#error "MLD_FORCE_RISCV64 is set, but we don't seem to be on a RISCV64 system." +#endif + +#if defined(MLD_FORCE_RISCV32) && !defined(MLD_SYS_RISCV32) +#error "MLD_FORCE_RISCV32 is set, but we don't seem to be on a RISCV32 system." +#endif + +/* + * MLD_INLINE: Hint for inlining. + * - MSVC: __inline + * - C99+: inline + * - GCC/Clang C90: __attribute__((unused)) to silence warnings + * - Other C90: empty + */ +#if !defined(MLD_INLINE) +#if defined(_MSC_VER) +#define MLD_INLINE __inline +#elif defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +#define MLD_INLINE inline +#elif defined(__GNUC__) || defined(__clang__) +#define MLD_INLINE __attribute__((unused)) +#else +#define MLD_INLINE +#endif +#endif /* !MLD_INLINE */ + +/* + * MLD_ALWAYS_INLINE: Force inlining. + * - MSVC: __forceinline + * - GCC/Clang C99+: MLD_INLINE __attribute__((always_inline)) + * - Other: MLD_INLINE (no forced inlining) + */ +#if !defined(MLD_ALWAYS_INLINE) +#if defined(_MSC_VER) +#define MLD_ALWAYS_INLINE __forceinline +#elif (defined(__GNUC__) || defined(__clang__)) && \ + (defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)) +#define MLD_ALWAYS_INLINE MLD_INLINE __attribute__((always_inline)) +#else +#define MLD_ALWAYS_INLINE MLD_INLINE +#endif +#endif /* !MLD_ALWAYS_INLINE */ + +#ifndef MLD_STATIC_TESTABLE +#define MLD_STATIC_TESTABLE static +#endif + +/* + * C90 does not have the restrict compiler directive yet. + * We don't use it in C90 builds. + */ +#if !defined(restrict) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define MLD_RESTRICT restrict +#else +#define MLD_RESTRICT +#endif + +#else /* !restrict */ + +#define MLD_RESTRICT restrict +#endif /* restrict */ + +#define MLD_DEFAULT_ALIGN 32 +#define MLD_ALIGN_UP(N) \ + ((((N) + (MLD_DEFAULT_ALIGN - 1)) / MLD_DEFAULT_ALIGN) * MLD_DEFAULT_ALIGN) +#if defined(__GNUC__) +#define MLD_ALIGN __attribute__((aligned(MLD_DEFAULT_ALIGN))) +#elif defined(_MSC_VER) +#define MLD_ALIGN __declspec(align(MLD_DEFAULT_ALIGN)) +#else +#define MLD_ALIGN /* No known support for alignment constraints */ +#endif + + +/* New X86_64 CPUs support Conflow-flow protection using the CET instructions. + * When enabled (through -fcf-protection=), all compilation units (including + * empty ones) need to support CET for this to work. + * For assembly, this means that source files need to signal support for + * CET by setting the appropriate note.gnu.property section. + * This can be achieved by including the header in all assembly file. + * This file also provides the _CET_ENDBR macro which needs to be placed at + * every potential target of an indirect branch. + * If CET is enabled _CET_ENDBR maps to the endbr64 instruction, otherwise + * it is empty. + * In case the compiler does not support CET (e.g., +#define MLD_CET_ENDBR _CET_ENDBR +#else +#define MLD_CET_ENDBR +#endif +#endif /* MLD_SYS_X86_64 */ + +#if defined(MLD_CONFIG_CT_TESTING_ENABLED) && !defined(__ASSEMBLER__) +#include +#define MLD_CT_TESTING_SECRET(ptr, len) \ + VALGRIND_MAKE_MEM_UNDEFINED((ptr), (len)) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) +#else /* MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__ */ +#define MLD_CT_TESTING_SECRET(ptr, len) \ + do \ + { \ + } while (0) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + do \ + { \ + } while (0) +#endif /* !(MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__) */ + +#if defined(__GNUC__) || defined(__clang__) +#define MLD_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_MUST_CHECK_RETURN_VALUE +#endif + + +#if !defined(__ASSEMBLER__) +/* System capability enumeration */ +typedef enum +{ + /* x86_64 */ + MLD_SYS_CAP_AVX2, + /* AArch64 */ + MLD_SYS_CAP_SHA3 +} mld_sys_cap; + +#if !defined(MLD_CONFIG_CUSTOM_CAPABILITY_FUNC) +#include "cbmc.h" + +static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) +__contract__( + ensures(return_value == 0 || return_value == 1) +) +{ + /* By default, we rely on compile-time feature detection/specification: + * If a feature is enabled at compile-time, we assume it is supported by + * the host that the resulting library/binary will be built on. + * If this assumption is not true, you MUST overwrite this function. + * See the documentation of MLD_CONFIG_CUSTOM_CAPABILITY_FUNC in + * mldsa_native_config.h for more information. */ + (void)cap; + return 1; +} +#endif /* !MLD_CONFIG_CUSTOM_CAPABILITY_FUNC */ +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_SYS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/zetas.inc b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/zetas.inc new file mode 100644 index 0000000000..dc3cf15dd3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native/src/zetas.inc @@ -0,0 +1,56 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include + +/* + * Table of zeta values used in the reference NTT and inverse NTT. + * See autogen for details. + */ +static const int32_t mld_zetas[MLDSA_N] = { + 0, 25847, -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 2353451, -359251, -2091905, 3119733, -2884855, + 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488, + -1119584, 2619752, -2108549, -2118186, -3859737, -1399561, -3277672, + 1757237, -19422, 4010497, 280005, 2706023, 95776, 3077325, + 3530437, -1661693, -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267, + -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596, + 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, + -2797779, -3930395, -1528703, -3677745, -3041255, -1452451, 3475950, + 2176455, -1585221, -1257611, 1939314, -4083598, -1000202, -3190144, + -3157330, -3632928, 126922, 3412210, -983419, 2147896, 2715295, + -2967645, -3693493, -411027, -2477047, -671102, -1228525, -22981, + -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944, + 508951, 3097992, 44288, -1100098, 904516, 3958618, -3724342, + -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856, + 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, + 1341330, 1285669, -1584928, -812732, -1439742, -3019102, -3881060, + -3628969, 3839961, 2091667, 3407706, 2316500, 3817976, -3342478, + 2244091, -2446433, -3562462, 266997, 2434439, -1235728, 3513181, + -3520352, -3759364, -1197226, -3193378, 900702, 1859098, 909542, + 819034, 495491, -1613174, -43260, -522500, -655327, -3122442, + 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297, + 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, + 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, + 1595974, -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, + 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100, + 1312455, 3306115, -1962642, -1279661, 1917081, -2546312, -1374803, + 1500165, 777191, 2235880, 3406031, -542412, -2831860, -1671176, + -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395, + 2454455, -164721, 1957272, 3369112, 185531, -1207385, -3183426, + 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, + -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, + 472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333, + -260646, -3833893, -2939036, -2235985, -420899, -2286327, 183443, + -976891, 1612842, -3545687, -554416, 3919660, -48306, -1362209, + 3937738, 1400424, -846154, 1976782, +}; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native_all.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native_all.c new file mode 100644 index 0000000000..56a1b1b8d5 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native_all.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* Three instances of mldsa-native for all security levels */ + +/* Include level-independent code */ +#define MLD_CONFIG_MULTILEVEL_WITH_SHARED +/* Keep level-independent headers at the end of monobuild file */ +#define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS +#define MLD_CONFIG_PARAMETER_SET 44 +#include "mldsa_native.c" +#undef MLD_CONFIG_PARAMETER_SET +#undef MLD_CONFIG_MULTILEVEL_WITH_SHARED + +/* Exclude level-independent code */ +#define MLD_CONFIG_MULTILEVEL_NO_SHARED +#define MLD_CONFIG_PARAMETER_SET 65 +#include "mldsa_native.c" +#undef MLD_CONFIG_PARAMETER_SET +/* `#undef` all headers at the and of the monobuild file */ +#undef MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + +#define MLD_CONFIG_PARAMETER_SET 87 +#include "mldsa_native.c" +#undef MLD_CONFIG_PARAMETER_SET diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native_all.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native_all.h new file mode 100644 index 0000000000..3cfd58deea --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/mldsa_native_all.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_ALL_H +#define MLD_ALL_H + +/* API for MLDSA-44 */ +#define MLD_CONFIG_PARAMETER_SET 44 +#include +#undef MLD_CONFIG_PARAMETER_SET +#undef MLD_H + +/* API for MLDSA-65 */ +#define MLD_CONFIG_PARAMETER_SET 65 +#include +#undef MLD_CONFIG_PARAMETER_SET +#undef MLD_H + +/* API for MLDSA-87 */ +#define MLD_CONFIG_PARAMETER_SET 87 +#include +#undef MLD_CONFIG_PARAMETER_SET +#undef MLD_CONFIG_NO_SUPERCOP +#undef MLD_H + +#endif /* !MLD_ALL_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/test_only_rng/notrandombytes.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/test_only_rng/notrandombytes.c new file mode 100644 index 0000000000..ef5a423a9e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/test_only_rng/notrandombytes.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* * Based on @[surf]*/ + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +#include +#include + +#include "notrandombytes.h" + +#ifdef ENABLE_CT_TESTING +#include +#endif + +static uint32_t seed[32] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, + 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5}; +static uint32_t in[12]; +static uint32_t out[8]; +static int32_t outleft = 0; + +void randombytes_reset(void) +{ + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + outleft = 0; +} + +#define ROTATE(x, b) (((x) << (b)) | ((x) >> (32 - (b)))) +#define MUSH(i, b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x, b)); + +static void surf(void) +{ + uint32_t t[12]; + uint32_t x; + uint32_t sum = 0; + int32_t r; + int32_t i; + int32_t loop; + + for (i = 0; i < 12; ++i) + { + t[i] = in[i] ^ seed[12 + i]; + } + for (i = 0; i < 8; ++i) + { + out[i] = seed[24 + i]; + } + x = t[11]; + for (loop = 0; loop < 2; ++loop) + { + for (r = 0; r < 16; ++r) + { + sum += 0x9e3779b9; + MUSH(0, 5) + MUSH(1, 7) + MUSH(2, 9) + MUSH(3, 13) + MUSH(4, 5) + MUSH(5, 7) + MUSH(6, 9) + MUSH(7, 13) + MUSH(8, 5) + MUSH(9, 7) + MUSH(10, 9) + MUSH(11, 13) + } + for (i = 0; i < 8; ++i) + { + out[i] ^= t[i + 4]; + } + } +} + +int randombytes(uint8_t *buf, size_t n) +{ +#ifdef ENABLE_CT_TESTING + uint8_t *buf_orig = buf; + size_t n_orig = n; +#endif + + while (n > 0) + { + if (!outleft) + { + if (!++in[0]) + { + if (!++in[1]) + { + if (!++in[2]) + { + ++in[3]; + } + } + } + surf(); + outleft = 8; + } + *buf = (uint8_t)out[--outleft]; + ++buf; + --n; + } + +#ifdef ENABLE_CT_TESTING + /* + * Mark all randombytes output as secret (undefined). + * Valgrind will propagate this to everything derived from it. + */ + VALGRIND_MAKE_MEM_UNDEFINED(buf_orig, n_orig); +#endif /* ENABLE_CT_TESTING */ + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/test_only_rng/notrandombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/test_only_rng/notrandombytes.h new file mode 100644 index 0000000000..bdf9787920 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel/test_only_rng/notrandombytes.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* Based on @[surf]. */ + +#ifndef NOTRANDOMBYTES_H +#define NOTRANDOMBYTES_H + +#include +#include + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +void randombytes_reset(void); +int randombytes(uint8_t *buf, size_t n); + +#endif /* !NOTRANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/.gitignore b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/.gitignore new file mode 100644 index 0000000000..834e997200 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/.gitignore @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +build/ +*.d diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/Makefile new file mode 100644 index 0000000000..8e9a6e70ab --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/Makefile @@ -0,0 +1,121 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +.PHONY: build run clean +.DEFAULT_GOAL := all + +CC ?= gcc +AR ?= ar + +# Adjust CFLAGS if needed +CFLAGS := \ + -Wall \ + -Wextra \ + -Werror=unused-result \ + -Wpedantic \ + -Werror \ + -Wmissing-prototypes \ + -Wshadow \ + -Wpointer-arith \ + -Wredundant-decls \ + -Wconversion \ + -Wsign-conversion \ + -Wno-long-long \ + -Wno-unknown-pragmas \ + -Wno-unused-command-line-argument \ + -Wno-unused-function \ + -O3 \ + -fomit-frame-pointer \ + -std=c99 \ + -pedantic \ + -MMD \ + $(CFLAGS) + +# If you want to use the native backends, the compiler needs to know about +# the target architecture. Here, we import the default host detection from +# mldsa-native's tests, but you can write your own or specialize accordingly. +AUTO ?= 1 +include auto.mk + +# The following only concerns the cross-compilation tests. +# You can likely ignore the following for your application. +# +# Append cross-prefix for cross compilation +# When called from the root Makefile, CROSS_PREFIX has already been added here +ifeq (,$(findstring $(CROSS_PREFIX),$(CC))) +CC := $(CROSS_PREFIX)$(CC) +endif + +ifeq (,$(findstring $(CROSS_PREFIX),$(AR))) +AR := $(CROSS_PREFIX)$(AR) +endif + +# Part A: +# +# mldsa-native source and header files +# +# Here, the monolithic C file for mldsa-native is directly included in main.c, +# However, we still need to incldue the monolithic assembly file. +MLD_SOURCE_ASM = mldsa_native/mldsa_native.S + +INC=-Imldsa_native/ -I./ + +# Part B: +# +# Random number generator +# +# !!! WARNING !!! +# +# The randombytes() implementation used here is for TESTING ONLY. +# You MUST NOT use this implementation outside of testing. +# +# !!! WARNING !!! +RNG_SOURCE=$(wildcard test_only_rng/*.c) + +# Part C: +# +# Your application source code +APP_SOURCE=$(RNG_SOURCE) main.c + +BUILD_DIR=build +BIN=test_binary + +# +# Configuration adjustments +# + +ASMFLAGS = -DMLD_CONFIG_MULTILEVEL_WITH_SHARED + +BINARY_NAME_FULL=$(BUILD_DIR)/$(BIN) + +MLD_OBJ_C=$(patsubst %,$(BUILD_DIR)/%.o,$(MLD_SOURCE_C)) +MLD_OBJ_ASM=$(patsubst %,$(BUILD_DIR)/%.o,$(MLD_SOURCE_ASM)) + +Q ?= @ + +$(BUILD_DIR)/%.c.o: %.c + $(Q)echo "CC $^" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -c $(CFLAGS) $(INC) $^ -o $@ + +$(BUILD_DIR)/%.S.o: %.S + $(Q)echo "AS $^" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -c $(CFLAGS) $(ASMFLAGS) $(INC) $^ -o $@ + +$(BINARY_NAME_FULL): $(APP_SOURCE) $(MLD_OBJ_ASM) + $(Q)echo "CC $@" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) $(CFLAGS) $(INC) $^ -o $@ + $(Q)strip -S $@ + +all: build + +build: $(BINARY_NAME_FULL) + +run: $(BINARY_NAME_FULL) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL) + +clean: + rm -rf $(BUILD_DIR) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/README.md new file mode 100644 index 0000000000..2d4305a863 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/README.md @@ -0,0 +1,85 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Monolithic Multi-Level Build (Native Backend) + +This directory contains a minimal example for building all three ML-DSA security levels in a single +compilation unit with native assembly backends, with shared code deduplicated. + +## Use Case + +Use this approach when: +- You need all ML-DSA security levels in one application +- You want optimal performance via native assembly +- You want the simplest possible multi-level native integration + +## Components + +1. Source tree [mldsa_native/*](mldsa_native), including top-level compilation unit + [mldsa_native.c](mldsa_native/mldsa_native.c) (gathering all C sources), + [mldsa_native.S](mldsa_native/mldsa_native.S) (gathering all assembly sources), + and the mldsa-native API [mldsa_native.h](mldsa_native/mldsa_native.h). +2. Manually provided wrapper file [mldsa_native_all.c](mldsa_native_all.c), + including `mldsa_native.c` three times (in this example, we don't use a + wrapper header since we directly include `mldsa_native_all.c` into `main.c`). +3. A secure random number generator implementing [`randombytes.h`](../../mldsa/src/randombytes.h) +4. Your application source code + +## Configuration + +The configuration file [mldsa_native_config.h](mldsa_native/mldsa_native_config.h) sets: +- `MLD_CONFIG_MULTILEVEL_BUILD`: Enables multi-level mode +- `MLD_CONFIG_NAMESPACE_PREFIX=mldsa`: Base prefix +- `MLD_CONFIG_USE_NATIVE_BACKEND_ARITH`: Enables native arithmetic backend +- `MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202`: Enables native FIPS-202 backend +- `MLD_CONFIG_NO_SUPERCOP`: Disables the SUPERCOP API (crypto_sign*) + +The wrapper [mldsa_native_all.c](mldsa_native_all.c) includes `mldsa_native.c` three times: +```c +#define MLD_CONFIG_FILE "multilevel_config.h" + +/* Include level-independent code with first level */ +#define MLD_CONFIG_MULTILEVEL_WITH_SHARED 1 +#define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS +#define MLD_CONFIG_PARAMETER_SET 44 +#include "mldsa_native.c" +#undef MLD_CONFIG_MULTILEVEL_WITH_SHARED +#undef MLD_CONFIG_PARAMETER_SET + +/* Exclude level-independent code for subsequent levels */ +#define MLD_CONFIG_MULTILEVEL_NO_SHARED +#define MLD_CONFIG_PARAMETER_SET 65 +#include "mldsa_native.c" +#undef MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS +#undef MLD_CONFIG_PARAMETER_SET + +#define MLD_CONFIG_PARAMETER_SET 87 +#include "mldsa_native.c" +#undef MLD_CONFIG_PARAMETER_SET +``` + +The application [main.c](main.c) embeds the wrapper and imports constants: +```c +#include "mldsa_native_all.c" + +#define MLD_CONFIG_CONSTANTS_ONLY +#include +``` + +## Notes + +- Both `mldsa_native_all.c` and `mldsa_native.S` must be compiled and linked +- `MLD_CONFIG_MULTILEVEL_WITH_SHARED` must be set for exactly ONE level +- `MLD_CONFIG_CONSTANTS_ONLY` imports size constants without function declarations +- Native backends are auto-selected based on target architecture + +## Usage + +```bash +make build # Build the example +make run # Run the example +``` + +## Warning + +The `randombytes()` implementation in `test_only_rng/` is for TESTING ONLY. +You MUST provide a cryptographically secure RNG for production use. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/auto.mk b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/auto.mk new file mode 100644 index 0000000000..5f71942085 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/auto.mk @@ -0,0 +1,178 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# Automatically detect system architecture and set preprocessor flags accordingly +# This file detects host CPU capabilities and combines them with compiler support +# to enable optimal compilation flags. +# +# Compiler feature detection can be overridden by setting the corresponding variable +# on the command line: +# make MK_COMPILER_SUPPORTS_SHA3=0 # Disable SHA3 detection +# make MK_COMPILER_SUPPORTS_AVX2=0 # Disable AVX2 detection +# make MK_COMPILER_SUPPORTS_BMI2=0 # Disable BMI2 detection +# make MK_COMPILER_SUPPORTS_SSE2=0 # Disable SSE2 detection + +ifndef _AUTO_MK +_AUTO_MK := + +# Override ARCH for cross-compilation based on CROSS_PREFIX +ifeq ($(CROSS_PREFIX),) +ARCH := $(shell uname -m) +# Normalize architecture names +ifeq ($(ARCH),arm64) +ARCH := aarch64 +endif +else # CROSS_PREFIX +ifneq ($(findstring x86_64, $(CROSS_PREFIX)),) +ARCH := x86_64 +else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),) +ARCH := aarch64_be +else ifneq ($(findstring aarch64, $(CROSS_PREFIX)),) +ARCH := aarch64 +else ifneq ($(findstring riscv64, $(CROSS_PREFIX)),) +ARCH := riscv64 +else ifneq ($(findstring riscv32, $(CROSS_PREFIX)),) +ARCH := riscv32 +else ifneq ($(findstring powerpc64le, $(CROSS_PREFIX)),) +ARCH := powerpc64le +else ifneq ($(findstring arm-none-eabi-, $(CROSS_PREFIX)),) +ARCH := arm +else +ifeq ($(AUTO),1) +$(warning Unknown cross-compilation prefix $(CROSS_PREFIX), no automatic detection of CFLAGS.) +ARCH := unknown +endif +endif +endif # CROSS_PREFIX + +# x86_64 compiler feature detection +ifeq ($(ARCH),x86_64) + +# Test AVX2 support using C with inline assembly +MK_COMPILER_SUPPORTS_AVX2 ?= $(shell echo 'int main() { __asm__("vpxor %%ymm0, %%ymm1, %%ymm2" ::: "ymm0", "ymm1", "ymm2"); return 0; }' | $(CC) -mavx2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test SSE2 support using C with inline assembly +MK_COMPILER_SUPPORTS_SSE2 ?= $(shell echo 'int main() { __asm__("pxor %%xmm0, %%xmm1" ::: "xmm0", "xmm1"); return 0; }' | $(CC) -msse2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test BMI2 support using C with inline assembly +MK_COMPILER_SUPPORTS_BMI2 ?= $(shell echo 'int main() { __asm__("pdep %%eax, %%ebx, %%ecx" ::: "eax", "ebx", "ecx"); return 0; }' | $(CC) -mbmi2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # x86_64 compiler detection + +# AArch64 compiler feature detection +ifeq ($(ARCH),aarch64) + +# Test SHA3 support (Armv8.4-a+SHA3) using C with inline assembly +MK_COMPILER_SUPPORTS_SHA3 ?= $(shell echo 'int main() { __asm__("eor3 v0.16b, v1.16b, v2.16b, v3.16b" ::: "v0", "v1", "v2", "v3"); return 0; }' | $(CC) -march=armv8.4-a+sha3 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # aarch64 compiler detection + +# Define HOST_PLATFORM if not already defined +HOST_PLATFORM ?= $(shell uname -s)-$(shell uname -m) + +# Helper function to check if host CPU supports a feature +# Usage: $(call check_host_feature,feature_pattern,source_command) +define check_host_feature +$(shell $(2) 2>/dev/null | grep -q "$(1)" && echo 1 || echo 0) +endef + +# x86_64 architecture detection +ifeq ($(ARCH),x86_64) + +# Host CPU feature detection for x86_64 +ifeq ($(HOST_PLATFORM),Linux-x86_64) +# Linux: Use /proc/cpuinfo +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,avx2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,sse2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,bmi2,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-x86_64) +# macOS: Use sysctl +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,AVX2,sysctl -n machdep.cpu.leaf7_features) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,SSE2,sysctl -n machdep.cpu.features) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,BMI2,sysctl -n machdep.cpu.leaf7_features) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_AVX2 := 1 +MK_HOST_SUPPORTS_SSE2 := 1 +MK_HOST_SUPPORTS_BMI2 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_AVX2 := 0 +MK_HOST_SUPPORTS_SSE2 := 0 +MK_HOST_SUPPORTS_BMI2 := 0 +endif # HOST_PLATFORM x86_64 + +endif # x86_64 + +# AArch64 architecture detection +ifeq ($(ARCH),aarch64) + +# Host CPU feature detection for AArch64 +ifeq ($(HOST_PLATFORM),Linux-aarch64) +# Linux: Use /proc/cpuinfo (look for sha3 in Features line) +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,sha3,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-arm64) +# macOS: Use sysctl to check for SHA3 support +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,1,sysctl -n hw.optional.armv8_2_sha3) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_SHA3 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_SHA3 := 0 +endif # HOST_PLATFORM aarch64 + +endif # aarch64 + +# Only apply CFLAGS modifications if AUTO=1 +ifeq ($(AUTO),1) + +# x86_64 CFLAGS configuration +ifeq ($(ARCH),x86_64) +CFLAGS += -DMLD_FORCE_X86_64 + +# Add flags only if both compiler and host support the feature +ifeq ($(MK_COMPILER_SUPPORTS_AVX2)$(MK_HOST_SUPPORTS_AVX2),11) +CFLAGS += -mavx2 +endif + +ifeq ($(MK_COMPILER_SUPPORTS_BMI2)$(MK_HOST_SUPPORTS_BMI2),11) +CFLAGS += -mbmi2 +endif +endif # x86_64 + +# AArch64 CFLAGS configuration +ifeq ($(ARCH),aarch64) +CFLAGS += -DMLD_FORCE_AARCH64 + +# Add SHA3 flags only if both compiler and host support it +ifeq ($(MK_COMPILER_SUPPORTS_SHA3)$(MK_HOST_SUPPORTS_SHA3),11) +CFLAGS += -march=armv8.4-a+sha3 +endif +endif # aarch64 + +# AArch64 Big Endian CFLAGS configuration +ifeq ($(ARCH),aarch64_be) +CFLAGS += -DMLD_FORCE_AARCH64_EB +endif # aarch64_be + +# RISC-V 64-bit CFLAGS configuration +ifeq ($(ARCH),riscv64) +CFLAGS += -DMLD_FORCE_RISCV64 +CFLAGS += -march=rv64gcv +endif # riscv64 + +# RISC-V 32-bit CFLAGS configuration +ifeq ($(ARCH),riscv32) +CFLAGS += -DMLD_FORCE_RISCV32 +endif # riscv32 + +# PowerPC 64-bit Little Endian CFLAGS configuration +ifeq ($(ARCH),powerpc64le) +CFLAGS += -DMLD_FORCE_PPC64LE +endif # powerpc64le + +endif # AUTO=1 + +endif # _AUTO_MK diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/expected_signatures.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/expected_signatures.h new file mode 100644 index 0000000000..582c6309d4 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/expected_signatures.h @@ -0,0 +1,886 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef EXPECTED_SIGNATURES_H +#define EXPECTED_SIGNATURES_H + +#include + +/* Expected deterministic signatures for each parameter set + * These are generated using the same test message, context, and deterministic + * RNG as used in the basic example. + * + * The PCT modifies the PRNG state, so the KAT tests don't work. + * We run KAT tests only for disabled PCT. */ +#if !defined(MLD_CONFIG_KEYGEN_PCT) +const uint8_t expected_signature_44[] = { + 0x27, 0x5e, 0xbe, 0x2d, 0x23, 0x1a, 0x76, 0xc5, 0xd9, 0x77, 0xcb, 0x62, + 0x25, 0x04, 0xdb, 0x23, 0x31, 0xa9, 0xa8, 0xcd, 0xbc, 0xde, 0xf2, 0x20, + 0xfd, 0xa7, 0xb5, 0xf5, 0x59, 0xae, 0xe6, 0xdd, 0x62, 0xfa, 0x34, 0x96, + 0x4f, 0x1d, 0xcd, 0x84, 0x82, 0xee, 0xc1, 0x74, 0x96, 0x3d, 0x98, 0xd9, + 0x42, 0x9d, 0xd0, 0x77, 0x9c, 0xf9, 0x9e, 0x0e, 0xa7, 0xcb, 0x70, 0xeb, + 0xe7, 0xcd, 0xce, 0x8c, 0xdc, 0x37, 0x15, 0x95, 0x0e, 0x24, 0x70, 0x4f, + 0x33, 0x6e, 0x4f, 0xad, 0xed, 0x4d, 0xf3, 0xe5, 0x38, 0xc1, 0xcd, 0xbb, + 0xde, 0xf1, 0xd2, 0x0d, 0xd6, 0x6b, 0xa3, 0x68, 0x92, 0x4c, 0x4b, 0x4f, + 0x89, 0xa0, 0xa8, 0xc8, 0x36, 0x93, 0x91, 0x17, 0xe7, 0x16, 0xed, 0xcb, + 0xdc, 0xf6, 0x28, 0x13, 0x32, 0x60, 0x14, 0xe0, 0x28, 0x7a, 0x69, 0x05, + 0x1d, 0xf7, 0x3b, 0xdf, 0x18, 0x0c, 0xaf, 0xba, 0x46, 0xf1, 0x5e, 0xd4, + 0xd3, 0xd0, 0x8e, 0x9a, 0xe2, 0xac, 0xdd, 0x0e, 0x5f, 0xb1, 0x69, 0xe2, + 0x74, 0x77, 0x2e, 0x52, 0xf9, 0x11, 0x3d, 0xd8, 0xe5, 0x36, 0x6f, 0x7d, + 0x7d, 0xde, 0x7c, 0xa7, 0x1d, 0x37, 0xdf, 0x6d, 0x5e, 0xea, 0xc8, 0xc0, + 0x72, 0x3f, 0x79, 0xbd, 0x0b, 0x6d, 0x7f, 0x9a, 0x15, 0x90, 0xda, 0xc1, + 0xae, 0xce, 0xf3, 0x44, 0x35, 0x5e, 0x83, 0x86, 0x7e, 0x89, 0x18, 0xa7, + 0x97, 0x8e, 0x87, 0x7c, 0x15, 0xd2, 0xd2, 0x7e, 0xf2, 0xc8, 0x29, 0x4f, + 0x70, 0x0f, 0xa6, 0xd4, 0x76, 0xe8, 0xdd, 0x7d, 0x7a, 0x2d, 0xfe, 0x0a, + 0x0c, 0x5c, 0xb1, 0xef, 0xec, 0x1a, 0x32, 0xca, 0x87, 0xff, 0x6b, 0xb1, + 0xa0, 0xe1, 0x2e, 0x01, 0x52, 0xb2, 0xb8, 0x74, 0x34, 0xb3, 0xfb, 0x15, + 0x0f, 0x17, 0xca, 0x74, 0xc1, 0xc1, 0x61, 0x86, 0x40, 0x38, 0x58, 0xba, + 0x82, 0x26, 0x66, 0x33, 0xa4, 0x52, 0xf3, 0xb5, 0x36, 0x60, 0xd8, 0x5a, + 0x8d, 0x9d, 0x28, 0x18, 0x3a, 0x68, 0x34, 0x2a, 0xa2, 0xe2, 0xb5, 0x39, + 0xed, 0x7d, 0xe5, 0xbe, 0x46, 0xb9, 0x04, 0x0c, 0xf3, 0xef, 0x88, 0x6e, + 0x9d, 0x6f, 0x23, 0xe2, 0x44, 0xe5, 0x2e, 0x3a, 0x7a, 0x1d, 0x49, 0x0f, + 0xdd, 0xcd, 0xd6, 0x4e, 0x0d, 0x0b, 0xc3, 0x35, 0xf2, 0xd1, 0x5d, 0x73, + 0x5d, 0x07, 0xca, 0x5c, 0xbd, 0x14, 0xec, 0x57, 0xb3, 0xbd, 0x37, 0xe7, + 0xdf, 0x06, 0x7d, 0xe0, 0x58, 0x4a, 0xcf, 0x7a, 0xc5, 0xa7, 0x24, 0x62, + 0x6f, 0x09, 0x75, 0x69, 0x74, 0x7f, 0xdf, 0xc8, 0x69, 0x5c, 0x20, 0x10, + 0x3a, 0xe8, 0x01, 0x12, 0xa3, 0xfb, 0xda, 0x4c, 0x3a, 0x0d, 0x3c, 0x3e, + 0x26, 0xe0, 0xa6, 0x7f, 0xb2, 0x6b, 0x0b, 0x68, 0x0a, 0x68, 0x86, 0xb1, + 0xfa, 0x61, 0x3a, 0xe8, 0x77, 0xdc, 0x42, 0xf7, 0xf4, 0x39, 0x9a, 0x40, + 0x58, 0x71, 0xc7, 0x0f, 0xf4, 0x0e, 0xc5, 0x1e, 0xe0, 0x28, 0x45, 0x7d, + 0xba, 0x84, 0xe4, 0x34, 0x69, 0xf9, 0xa5, 0x8a, 0x80, 0x43, 0xc0, 0x8d, + 0x04, 0x33, 0x43, 0xb8, 0xd7, 0x5d, 0x93, 0xed, 0x0f, 0x31, 0x6a, 0x4d, + 0xbf, 0xb7, 0x44, 0x41, 0x1b, 0xd4, 0xac, 0x9d, 0x83, 0x66, 0x08, 0x92, + 0xad, 0x3c, 0x0e, 0x1a, 0xe8, 0xd4, 0xe1, 0x5c, 0x63, 0xcf, 0x27, 0x48, + 0x5a, 0x8f, 0xc5, 0x6f, 0x83, 0x6b, 0x6f, 0xe8, 0xda, 0x1f, 0xba, 0xe9, + 0x7e, 0x11, 0xab, 0x8b, 0x4e, 0xc1, 0x9e, 0x23, 0x69, 0x1f, 0x42, 0x40, + 0xad, 0xbb, 0xfb, 0x4f, 0xe2, 0x50, 0xc9, 0x46, 0xe7, 0x15, 0x15, 0xf8, + 0x61, 0x09, 0x2a, 0x0b, 0x37, 0x43, 0xd4, 0x98, 0x5f, 0xc8, 0x4d, 0x06, + 0xe7, 0x0c, 0x3f, 0x83, 0x59, 0xd5, 0xcd, 0x2d, 0xde, 0x1e, 0x3a, 0x87, + 0x4e, 0xf7, 0x0a, 0x3c, 0x84, 0x72, 0x47, 0x11, 0x02, 0x6c, 0xe8, 0x93, + 0xcd, 0x24, 0xe9, 0x23, 0x86, 0x78, 0x53, 0xe0, 0xc6, 0x2f, 0xba, 0xa7, + 0xed, 0xaf, 0xba, 0x42, 0x80, 0x0d, 0xe6, 0xae, 0xda, 0xed, 0xbc, 0x65, + 0x21, 0x6d, 0x13, 0x90, 0x61, 0xb4, 0x05, 0x7b, 0x07, 0x86, 0xd7, 0x89, + 0x30, 0x9c, 0xc1, 0x9a, 0x41, 0x4d, 0xe8, 0x2b, 0x35, 0x21, 0x3a, 0x8a, + 0x60, 0x83, 0x1a, 0x97, 0x10, 0x98, 0xb6, 0xe1, 0x6b, 0xb5, 0xb1, 0xa1, + 0x36, 0x34, 0x60, 0x1b, 0x96, 0x5d, 0x1f, 0x2a, 0xd8, 0xf2, 0x94, 0xdd, + 0x58, 0x3d, 0x0f, 0xbe, 0x9d, 0xfc, 0xf5, 0x24, 0xb1, 0xd2, 0xc3, 0x36, + 0xef, 0xdb, 0x8e, 0x97, 0x3c, 0x9a, 0x4f, 0x48, 0xe3, 0x84, 0x91, 0xd8, + 0x39, 0x91, 0xf6, 0x55, 0xeb, 0x62, 0x51, 0x3d, 0x8f, 0x55, 0x60, 0x5e, + 0x00, 0xe0, 0xd2, 0xc7, 0x66, 0x51, 0xf1, 0xe2, 0xb7, 0x43, 0xc3, 0xe6, + 0x12, 0x9a, 0xe5, 0x84, 0xe0, 0x10, 0x76, 0xc7, 0x75, 0x6e, 0xa6, 0xee, + 0x11, 0xe4, 0xaf, 0xbd, 0x8a, 0x4f, 0x1d, 0x05, 0x29, 0x4f, 0xce, 0xa5, + 0x73, 0x92, 0x57, 0x7e, 0x0d, 0x11, 0xbc, 0xf8, 0x74, 0x4d, 0xf7, 0xb9, + 0x40, 0x0d, 0x5a, 0xa1, 0x19, 0x76, 0x4a, 0xae, 0x21, 0x16, 0xd4, 0x3f, + 0x76, 0xbf, 0x27, 0xbd, 0x2f, 0xe4, 0x25, 0x21, 0x00, 0x4e, 0xcc, 0x7c, + 0xc6, 0x57, 0xa4, 0xbf, 0xf1, 0x56, 0x90, 0xe0, 0xa4, 0xa3, 0xee, 0xcf, + 0x43, 0x4f, 0xda, 0x77, 0x47, 0x51, 0x79, 0x6a, 0x29, 0xb4, 0x2c, 0xdf, + 0xca, 0x47, 0xcb, 0xb8, 0x82, 0x7e, 0x44, 0x62, 0x9b, 0x8f, 0x61, 0x7b, + 0x3a, 0x93, 0x82, 0x1f, 0x69, 0xb7, 0xb1, 0xa6, 0x2c, 0xe1, 0xb2, 0x65, + 0xa0, 0x6d, 0x6f, 0xe4, 0x79, 0xd8, 0x30, 0xe0, 0xee, 0xd8, 0x83, 0x01, + 0xb2, 0x1f, 0x5c, 0x90, 0x44, 0x86, 0x48, 0x11, 0xf9, 0x11, 0xff, 0xea, + 0x45, 0x43, 0xae, 0x8a, 0x6b, 0x99, 0xf2, 0x1f, 0x02, 0x51, 0x4a, 0x35, + 0x02, 0x34, 0xd3, 0xe8, 0xda, 0xb1, 0x4b, 0xe3, 0xa5, 0x60, 0xce, 0x67, + 0xe3, 0x62, 0x59, 0xfc, 0x00, 0x0a, 0xe2, 0xfe, 0x7b, 0x1e, 0xe6, 0xf5, + 0x75, 0x19, 0x9b, 0x5e, 0xcb, 0xe6, 0xf5, 0x80, 0x9e, 0x3c, 0xb8, 0x54, + 0xd6, 0x0b, 0xfd, 0x48, 0xe0, 0xfa, 0x82, 0x2b, 0x5b, 0x26, 0xf9, 0x49, + 0xaf, 0xbe, 0x9c, 0x78, 0x73, 0xce, 0xc5, 0x65, 0xe2, 0x94, 0x2b, 0xd9, + 0xd0, 0x27, 0x3a, 0x66, 0x3e, 0xe2, 0xe0, 0x10, 0x79, 0x3d, 0xde, 0xc8, + 0x47, 0xdb, 0x1e, 0xc3, 0xe7, 0x51, 0xae, 0x59, 0xeb, 0x38, 0x66, 0x63, + 0x40, 0x8f, 0xbe, 0x1e, 0xb2, 0x2b, 0xeb, 0x64, 0x5f, 0xdd, 0x24, 0xc4, + 0x5a, 0x25, 0x59, 0xa2, 0xda, 0x4f, 0xdf, 0xf8, 0xb0, 0xb0, 0xf7, 0xcd, + 0x1f, 0x14, 0xcd, 0x09, 0x48, 0x70, 0x27, 0x1b, 0xde, 0xc4, 0xf0, 0xf3, + 0x56, 0x97, 0x8a, 0xb7, 0xf4, 0x19, 0x76, 0xe3, 0x9a, 0x33, 0x55, 0xfe, + 0x93, 0x68, 0xca, 0x1f, 0x3d, 0x44, 0x86, 0x39, 0x5d, 0x84, 0x58, 0x50, + 0xf2, 0xf1, 0xea, 0x4a, 0x5c, 0x1c, 0x74, 0xf0, 0x4b, 0xa5, 0x9c, 0x30, + 0xa0, 0x14, 0x1a, 0x80, 0xe0, 0xde, 0x3e, 0xae, 0x7f, 0x10, 0x18, 0x4a, + 0x1e, 0x9e, 0x6b, 0x75, 0x1a, 0xca, 0x08, 0x4e, 0x61, 0x72, 0x43, 0x9b, + 0x18, 0x4d, 0x2c, 0xd8, 0xb4, 0xc9, 0xea, 0x00, 0xb0, 0xdf, 0x1b, 0xcb, + 0x03, 0xc3, 0x7a, 0x27, 0xff, 0x41, 0x9d, 0xf9, 0xfd, 0xb3, 0x0c, 0xc0, + 0x48, 0x5d, 0x7c, 0xae, 0x5a, 0x72, 0x69, 0x93, 0x68, 0xe1, 0x9e, 0x9f, + 0x1f, 0x5c, 0x0a, 0x60, 0x90, 0x1a, 0x8e, 0x5a, 0x30, 0xd4, 0x2c, 0xbd, + 0xe1, 0x20, 0x51, 0xbc, 0x1c, 0x50, 0xb5, 0xf7, 0x42, 0x23, 0x35, 0x0f, + 0x92, 0xe2, 0xbb, 0x2a, 0x04, 0xa7, 0xde, 0x2e, 0x25, 0xfa, 0xed, 0x20, + 0x83, 0x9c, 0xd4, 0x56, 0xe0, 0x4d, 0x8d, 0x79, 0xa5, 0xa0, 0x6f, 0x49, + 0x62, 0x82, 0x9a, 0xa7, 0x4e, 0x54, 0x95, 0x0a, 0xc6, 0x5e, 0x27, 0x65, + 0x6d, 0x11, 0x2b, 0x35, 0x72, 0x34, 0x48, 0xd2, 0xe4, 0x9e, 0x07, 0x7d, + 0x03, 0x27, 0x15, 0x93, 0x55, 0x5c, 0x32, 0x43, 0xdb, 0x34, 0x8d, 0xbd, + 0x8d, 0x88, 0xa5, 0x24, 0x07, 0x93, 0x89, 0x37, 0xb9, 0x17, 0x15, 0xad, + 0xc7, 0x68, 0x86, 0x63, 0x0f, 0x10, 0x53, 0x8f, 0x40, 0xd3, 0x7b, 0x22, + 0x2b, 0x1a, 0x4c, 0xcb, 0x4f, 0x51, 0xf1, 0x3b, 0x19, 0xb8, 0x42, 0x53, + 0xaf, 0xf6, 0xb9, 0x57, 0x7f, 0xba, 0x8d, 0xb8, 0xb7, 0x3b, 0xe3, 0xc5, + 0xab, 0x4a, 0x26, 0x21, 0x6e, 0xce, 0x27, 0xb8, 0xc3, 0x99, 0x56, 0x14, + 0xdd, 0x5b, 0x61, 0x82, 0xbf, 0xd3, 0xc8, 0x76, 0xee, 0x22, 0xaf, 0x21, + 0x21, 0x1d, 0x4e, 0x33, 0xb5, 0x43, 0x3a, 0xfb, 0x91, 0xa0, 0xaa, 0xe3, + 0x10, 0x4a, 0x50, 0x42, 0xd4, 0x5f, 0x92, 0x0e, 0x71, 0x60, 0x4f, 0xaa, + 0xef, 0x66, 0x45, 0xfe, 0xf7, 0xc8, 0xb0, 0x73, 0x75, 0x91, 0x0b, 0x86, + 0x40, 0xa5, 0x02, 0x28, 0xf7, 0xe0, 0x1f, 0x5d, 0xe6, 0xe3, 0xa4, 0x57, + 0xbd, 0x29, 0xaa, 0x53, 0xae, 0x35, 0x30, 0x78, 0x73, 0xd6, 0xb7, 0x01, + 0x9d, 0x13, 0x50, 0xf6, 0x39, 0xa2, 0x3e, 0x03, 0x04, 0xaa, 0x6d, 0xcf, + 0x6b, 0xff, 0x9a, 0xbe, 0x3e, 0x0a, 0xd4, 0x20, 0xce, 0x42, 0x1f, 0xca, + 0x2f, 0xd3, 0x2c, 0xd1, 0xf4, 0xd2, 0x50, 0xd3, 0xa2, 0xc1, 0x1e, 0x87, + 0xbf, 0xeb, 0xb8, 0xa8, 0xd4, 0x1c, 0x96, 0xb8, 0x8e, 0xbe, 0x35, 0x5f, + 0x08, 0x28, 0x20, 0x2b, 0xdc, 0xa4, 0xf5, 0xf6, 0xde, 0xca, 0x1e, 0xcb, + 0x93, 0x3b, 0x64, 0x79, 0x00, 0x3c, 0x8d, 0xbb, 0x5c, 0x7a, 0x40, 0x14, + 0x58, 0x12, 0xa4, 0xf7, 0x6e, 0x51, 0xfb, 0xe7, 0x6f, 0x49, 0x5b, 0xc2, + 0xc9, 0x05, 0x38, 0x9c, 0x08, 0x78, 0x71, 0x27, 0x2b, 0xf5, 0xbf, 0xd6, + 0x38, 0xaa, 0x45, 0xe1, 0xe1, 0x4c, 0xfb, 0xfd, 0xb7, 0xe6, 0xcf, 0xad, + 0x9e, 0x56, 0xaf, 0x12, 0x12, 0x98, 0xe6, 0x38, 0xaa, 0xee, 0xdb, 0x9e, + 0xca, 0xe1, 0x79, 0x6d, 0x44, 0xfb, 0x19, 0x50, 0x92, 0x00, 0x06, 0x2c, + 0x24, 0x71, 0x6c, 0x34, 0x45, 0xac, 0xf9, 0x82, 0x66, 0xa8, 0x63, 0x80, + 0xa8, 0x5b, 0x21, 0x3c, 0x36, 0x71, 0x93, 0x40, 0x7b, 0xff, 0xa2, 0xd0, + 0x72, 0xb4, 0x66, 0xfa, 0xfc, 0xa0, 0xee, 0xca, 0x15, 0x73, 0x52, 0xe7, + 0x9d, 0x11, 0xd3, 0xbc, 0xab, 0x37, 0x31, 0x0e, 0xaf, 0xdc, 0x05, 0x30, + 0x79, 0x8c, 0x25, 0x75, 0x5c, 0x60, 0xc7, 0x9a, 0xfc, 0x88, 0xea, 0xe6, + 0x09, 0x9f, 0xd1, 0x4f, 0x13, 0xf4, 0x41, 0x54, 0x5b, 0x7a, 0xe4, 0x49, + 0x3c, 0x0f, 0x15, 0xe9, 0xa4, 0x85, 0xb2, 0x92, 0x07, 0xea, 0xea, 0x7c, + 0xc1, 0x6d, 0xa9, 0x03, 0xb3, 0x31, 0xce, 0x1e, 0x82, 0xca, 0x9e, 0x3c, + 0x88, 0x88, 0xc1, 0x04, 0x5f, 0xbe, 0xd5, 0x94, 0x0d, 0x67, 0x98, 0x27, + 0xd0, 0x0f, 0x43, 0xf3, 0xb3, 0xfc, 0xff, 0x24, 0xa2, 0x1e, 0x17, 0x06, + 0xb0, 0x52, 0x16, 0x7c, 0xd8, 0x49, 0x74, 0x51, 0xcf, 0x2d, 0x36, 0x16, + 0xb0, 0x88, 0xb2, 0x2b, 0x1d, 0x72, 0x70, 0xab, 0xe2, 0xf6, 0x5f, 0xa5, + 0x2d, 0x4e, 0xd1, 0x42, 0x3c, 0x83, 0x84, 0xb2, 0x56, 0xeb, 0x8d, 0xce, + 0x33, 0x46, 0xdb, 0x3d, 0x4f, 0x97, 0xea, 0x37, 0x5e, 0x0d, 0xd7, 0x4c, + 0x9a, 0x7e, 0xc9, 0x0e, 0x69, 0x4d, 0x97, 0x15, 0x1e, 0x09, 0xbe, 0x7e, + 0xff, 0xe8, 0xf5, 0xab, 0xe9, 0xe7, 0xed, 0x4b, 0x41, 0xa5, 0xf2, 0x2a, + 0x24, 0x48, 0x8b, 0x72, 0x4b, 0x9d, 0xcf, 0x45, 0xdb, 0xc0, 0xaf, 0xa8, + 0x0f, 0x0f, 0x67, 0x37, 0xd3, 0x8b, 0xe1, 0x67, 0x90, 0xd8, 0x1c, 0x58, + 0x36, 0x46, 0x51, 0x52, 0xea, 0xb4, 0x75, 0xb1, 0xcd, 0xc5, 0x39, 0x16, + 0xe0, 0xec, 0x16, 0xf7, 0xf8, 0x0f, 0x5d, 0x13, 0x84, 0x62, 0x34, 0x86, + 0x42, 0x05, 0xa8, 0x08, 0x84, 0xa9, 0x77, 0x12, 0xc1, 0x56, 0xdd, 0x28, + 0xde, 0x39, 0x33, 0x21, 0x3d, 0xbd, 0x94, 0xce, 0xe4, 0xb3, 0x17, 0x9b, + 0x09, 0x20, 0xf0, 0x25, 0xce, 0x00, 0x34, 0x8e, 0x12, 0x94, 0x74, 0x0b, + 0x16, 0xa1, 0x60, 0x76, 0x24, 0xf0, 0xbf, 0xe3, 0x3a, 0x83, 0x8f, 0x40, + 0x47, 0x2e, 0x1c, 0xd5, 0x35, 0x25, 0x87, 0xb3, 0x11, 0xdc, 0x98, 0xb0, + 0xa6, 0x5f, 0x6a, 0x05, 0x1d, 0x06, 0x8d, 0xe8, 0xb0, 0x98, 0xf0, 0x43, + 0x29, 0x84, 0xe4, 0xef, 0x34, 0x67, 0x74, 0x64, 0xe8, 0xb8, 0xf0, 0xd4, + 0x9e, 0xc1, 0x3f, 0x5f, 0xeb, 0xe0, 0x9b, 0x37, 0xf8, 0x75, 0x46, 0x47, + 0xa5, 0x3e, 0x42, 0x20, 0x50, 0xc4, 0x5d, 0xf3, 0xdf, 0x4e, 0xf8, 0x0e, + 0x1e, 0x15, 0x10, 0x3e, 0xf1, 0x68, 0xad, 0x87, 0xad, 0xe5, 0x45, 0x5e, + 0x22, 0xba, 0x2e, 0x51, 0xa0, 0xbf, 0xdc, 0x87, 0xca, 0xe4, 0x1f, 0x2f, + 0x2c, 0xae, 0xa9, 0x14, 0xd7, 0xdd, 0x01, 0xa8, 0x4f, 0x43, 0xcb, 0x84, + 0x92, 0xbf, 0xf9, 0x3d, 0xf0, 0x6b, 0x19, 0x43, 0xb0, 0xdf, 0xff, 0x94, + 0x76, 0xe2, 0x84, 0xf9, 0x31, 0x88, 0x7e, 0xc6, 0x87, 0x58, 0xbe, 0x5d, + 0x8b, 0xf8, 0xb5, 0xdc, 0x95, 0x16, 0x5f, 0xa1, 0x2c, 0xe8, 0x53, 0x36, + 0x64, 0xf5, 0x5d, 0xa0, 0x74, 0x12, 0x78, 0x59, 0x73, 0x69, 0x5a, 0x2b, + 0x36, 0x4a, 0xff, 0x5b, 0xef, 0x49, 0x2c, 0xb2, 0x9e, 0x59, 0xf0, 0x39, + 0x56, 0xe1, 0xd0, 0x1a, 0x05, 0xb2, 0x7c, 0xd1, 0x40, 0x09, 0xdf, 0x00, + 0xc9, 0x15, 0x53, 0xa2, 0xda, 0x84, 0xb5, 0x85, 0x05, 0x76, 0xa6, 0x1b, + 0xcb, 0x06, 0xb2, 0xc8, 0xa0, 0xc5, 0x23, 0x8f, 0xb0, 0xe8, 0xf5, 0xd9, + 0xd0, 0x19, 0x29, 0xfe, 0x2d, 0x9a, 0x57, 0x76, 0x5f, 0xf2, 0xef, 0x71, + 0x16, 0xee, 0x28, 0x7b, 0xe4, 0x48, 0xeb, 0xda, 0xe0, 0xd5, 0xbc, 0x0e, + 0x46, 0x6b, 0x06, 0x5d, 0xe5, 0x91, 0x2d, 0xcb, 0xc4, 0x53, 0xa6, 0x16, + 0xd5, 0xe7, 0xd8, 0xf1, 0xdd, 0x4f, 0xbb, 0xcc, 0x55, 0x67, 0x19, 0x98, + 0x94, 0x95, 0x5e, 0xd6, 0xf5, 0xf7, 0xe8, 0x6a, 0xf7, 0x20, 0x86, 0x3a, + 0x43, 0xbf, 0xe9, 0xec, 0x6b, 0x33, 0x49, 0x19, 0x43, 0xfb, 0xeb, 0x3f, + 0xf4, 0x9d, 0x29, 0x66, 0xb9, 0x6e, 0xb5, 0x15, 0x4b, 0x8d, 0x3c, 0x3c, + 0xfa, 0xf2, 0x87, 0xba, 0x61, 0x11, 0x40, 0xe6, 0xb4, 0x6f, 0xf5, 0xe1, + 0x24, 0x32, 0x69, 0x3e, 0xff, 0xf7, 0xbc, 0xee, 0x82, 0xf2, 0x9e, 0x6d, + 0x3f, 0x6c, 0xcc, 0x0f, 0x4f, 0xc3, 0xf1, 0xdb, 0x1e, 0x81, 0xd7, 0x9b, + 0x22, 0xa8, 0xa7, 0x36, 0x6d, 0xa9, 0x6f, 0x46, 0x1a, 0xa7, 0xff, 0x00, + 0x4b, 0xd8, 0xab, 0xe7, 0x50, 0x3b, 0xe9, 0xc0, 0x57, 0xec, 0x8d, 0x0c, + 0xa0, 0xee, 0x8c, 0x2a, 0x74, 0xf2, 0x94, 0xf9, 0x0c, 0x20, 0x14, 0xd9, + 0xad, 0x0d, 0x4e, 0xac, 0x35, 0x44, 0x59, 0x28, 0x24, 0x31, 0x32, 0xaa, + 0x6d, 0xc2, 0x13, 0xb9, 0xee, 0x75, 0x0c, 0x5f, 0x39, 0xef, 0x31, 0xca, + 0x28, 0x48, 0x56, 0x59, 0xfb, 0xa8, 0xd8, 0x2b, 0x70, 0x61, 0x22, 0x43, + 0x43, 0xb9, 0x60, 0x44, 0xeb, 0xf8, 0x98, 0x87, 0x25, 0x84, 0xa2, 0xaa, + 0x37, 0xd4, 0xb8, 0xd6, 0x3d, 0xa3, 0xa1, 0x4a, 0x81, 0xc2, 0xa9, 0xea, + 0xa2, 0xd6, 0x63, 0x76, 0x50, 0xeb, 0xcd, 0x19, 0x40, 0xb1, 0x7c, 0xf6, + 0xc1, 0x44, 0x01, 0x25, 0xe0, 0xdd, 0xb8, 0x39, 0xef, 0x46, 0x3d, 0x50, + 0x33, 0xed, 0xb1, 0x63, 0x65, 0xd7, 0x50, 0xe7, 0x95, 0xba, 0xab, 0xa7, + 0x14, 0xe5, 0x60, 0xcb, 0x81, 0x6e, 0x88, 0x3c, 0x06, 0x6e, 0x7d, 0x8e, + 0xe7, 0xbb, 0xa5, 0xc2, 0xbd, 0xae, 0x46, 0x8f, 0x43, 0x04, 0x29, 0xe6, + 0x17, 0x38, 0x05, 0x2d, 0x97, 0x93, 0x5b, 0xf9, 0xef, 0x4d, 0x2e, 0x75, + 0x6c, 0x69, 0xba, 0x08, 0xf2, 0x21, 0x1e, 0x21, 0xe6, 0x8a, 0x5b, 0x8c, + 0xd4, 0x8e, 0xde, 0x64, 0x9b, 0x9d, 0x54, 0x58, 0x65, 0x3e, 0xdd, 0x8a, + 0x1e, 0x81, 0x4e, 0x45, 0xe8, 0xfb, 0x20, 0xc3, 0x3a, 0xf0, 0x50, 0x1e, + 0x8a, 0x18, 0xea, 0x2b, 0xf5, 0xe1, 0xa6, 0xb6, 0xc8, 0xa0, 0x02, 0x3d, + 0x6e, 0xfa, 0x0b, 0x51, 0x95, 0x4e, 0x4c, 0x11, 0xb0, 0xc4, 0x62, 0x58, + 0xa6, 0x9c, 0x13, 0x4e, 0xbe, 0xc9, 0x29, 0x93, 0x29, 0x15, 0x5f, 0xaf, + 0x0e, 0xc3, 0xb3, 0x26, 0x3f, 0xdc, 0x4c, 0x33, 0xb8, 0x4b, 0x11, 0xae, + 0x1f, 0xd7, 0x05, 0x39, 0xcf, 0xfe, 0xc3, 0x6d, 0xf0, 0xc0, 0x77, 0x02, + 0xb8, 0x9b, 0x3d, 0x1b, 0x3d, 0x72, 0xfe, 0x7e, 0x18, 0x60, 0x9b, 0xc4, + 0x8b, 0xac, 0x25, 0x6d, 0x3b, 0x80, 0x34, 0xbc, 0x51, 0xaf, 0xf6, 0xff, + 0x66, 0x98, 0x86, 0x6e, 0x9e, 0x9a, 0xfe, 0x6d, 0x21, 0x4d, 0xf1, 0x58, + 0x3e, 0x3e, 0x43, 0xe3, 0x7e, 0x40, 0xb0, 0xb3, 0xd8, 0x12, 0xa5, 0xce, + 0x09, 0x41, 0x8c, 0x1d, 0x73, 0xcd, 0xfc, 0x63, 0xed, 0xeb, 0x08, 0x1e, + 0x34, 0xfb, 0xed, 0x75, 0xb7, 0x86, 0x84, 0x7c, 0x80, 0xe9, 0xe4, 0xa3, + 0x1c, 0x4a, 0x0d, 0x11, 0x16, 0x24, 0xb2, 0xb1, 0x99, 0xe5, 0xe3, 0x2e, + 0x2f, 0x70, 0xcd, 0x1e, 0x35, 0x14, 0x79, 0xba, 0xa2, 0x51, 0x7a, 0x29, + 0x5c, 0x75, 0x8f, 0xdd, 0x22, 0xdf, 0xb2, 0x64, 0xd9, 0x95, 0x11, 0x33, + 0x97, 0xee, 0x69, 0x42, 0x01, 0x96, 0x98, 0x1b, 0x43, 0xc2, 0xec, 0xf9, + 0xb0, 0xdb, 0x69, 0x34, 0xab, 0x98, 0x1b, 0xb2, 0x04, 0x05, 0x14, 0x1d, + 0x25, 0x2f, 0x32, 0x41, 0x50, 0x51, 0x55, 0x62, 0x6d, 0x78, 0x7f, 0x8b, + 0xbb, 0xc2, 0xcd, 0xcf, 0xe4, 0xed, 0x04, 0x1f, 0x25, 0x30, 0x43, 0x64, + 0x69, 0x7c, 0x87, 0xa3, 0xa9, 0xb1, 0xc1, 0xd1, 0xdc, 0x01, 0x10, 0x1d, + 0x27, 0x3f, 0x5c, 0x5d, 0x75, 0x82, 0x9b, 0xaa, 0xb3, 0xe8, 0x0c, 0x11, + 0x1f, 0x24, 0x38, 0x41, 0x45, 0x54, 0x5f, 0x69, 0x85, 0x8d, 0x93, 0x9e, + 0xc5, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x25, 0x32, 0x42}; +const uint8_t expected_signature_65[] = { + 0x8b, 0x6f, 0x79, 0x00, 0xcc, 0x79, 0x57, 0xee, 0x16, 0x86, 0x87, 0xd5, + 0xcf, 0xb6, 0x90, 0x2c, 0xc6, 0x30, 0xeb, 0x8d, 0x39, 0xae, 0x9b, 0xf1, + 0x66, 0xe0, 0xd6, 0x93, 0xa5, 0x4e, 0x26, 0x9b, 0x96, 0x8f, 0xd1, 0x46, + 0x97, 0xbe, 0x71, 0x1c, 0xf3, 0xa5, 0xe5, 0xae, 0x8d, 0x4b, 0xf2, 0xe6, + 0x48, 0x8f, 0xe9, 0x5e, 0x07, 0xef, 0xe4, 0xbb, 0x39, 0xc1, 0xc9, 0x3c, + 0xc3, 0x0b, 0xfb, 0x2a, 0x29, 0x06, 0xfe, 0x01, 0xcb, 0x63, 0x83, 0x10, + 0xa8, 0xc8, 0xa0, 0x29, 0xa5, 0x80, 0xeb, 0xbd, 0xa9, 0xd9, 0x0b, 0x61, + 0xbc, 0xce, 0x11, 0x55, 0x66, 0x12, 0xc7, 0x5b, 0xd2, 0x7a, 0x5a, 0xc8, + 0xab, 0xab, 0xbf, 0x3a, 0x1f, 0x96, 0x1a, 0x70, 0xcb, 0x41, 0x5f, 0xc8, + 0xb7, 0x09, 0x22, 0x98, 0x9b, 0xb8, 0xf7, 0x2d, 0x49, 0x65, 0x1d, 0x09, + 0x8b, 0x70, 0xb5, 0x42, 0xc9, 0x89, 0x5b, 0x74, 0xb4, 0x28, 0x82, 0x01, + 0x53, 0x12, 0x3e, 0x23, 0xf6, 0x54, 0xf8, 0x51, 0x12, 0x4b, 0x02, 0x3a, + 0x7e, 0xb6, 0x1f, 0xac, 0xa0, 0xe6, 0x6f, 0xf8, 0x61, 0x82, 0xe4, 0xfb, + 0x96, 0x2a, 0xd2, 0xaf, 0x3c, 0xea, 0x6e, 0xdc, 0x18, 0x8a, 0x5d, 0x90, + 0xda, 0xa2, 0x5d, 0xa7, 0x8f, 0x5b, 0x50, 0x46, 0xaf, 0x8c, 0x17, 0x6a, + 0x4c, 0x39, 0xfc, 0x31, 0x4c, 0x4b, 0xc2, 0x57, 0x66, 0x61, 0x98, 0xbf, + 0xe6, 0xfb, 0x54, 0x96, 0xd3, 0x70, 0xb8, 0xaf, 0xcd, 0x8b, 0xcc, 0x00, + 0x07, 0x92, 0x15, 0xc2, 0xbb, 0x48, 0xbb, 0xc6, 0xb7, 0xb5, 0x58, 0x8c, + 0xfc, 0xf0, 0xda, 0x6a, 0x0d, 0xf7, 0x1d, 0x7d, 0xc6, 0x27, 0x26, 0x1a, + 0x99, 0xc5, 0x2f, 0xf8, 0x97, 0x65, 0x43, 0x86, 0xd6, 0x25, 0x23, 0x2b, + 0x06, 0x8f, 0x12, 0xa1, 0xae, 0xbb, 0x58, 0x34, 0x25, 0xec, 0x5b, 0x68, + 0xa4, 0xe1, 0x03, 0xfc, 0x26, 0xa2, 0xd6, 0x2b, 0x61, 0x10, 0x47, 0xbd, + 0x16, 0xe5, 0xca, 0x4a, 0xce, 0xed, 0x89, 0x09, 0x1a, 0xed, 0x22, 0xc1, + 0xca, 0x44, 0xe3, 0xef, 0x72, 0x34, 0xab, 0xab, 0x61, 0x5c, 0x9f, 0x5f, + 0xb5, 0xf5, 0xe8, 0x2d, 0x89, 0xea, 0x4b, 0x40, 0x65, 0x57, 0x8b, 0xa2, + 0x95, 0x40, 0x9c, 0x72, 0xc0, 0x46, 0x69, 0x45, 0x06, 0xf6, 0x07, 0x5b, + 0x2d, 0xa5, 0x46, 0xca, 0x5d, 0xfb, 0x40, 0xb7, 0x48, 0x59, 0x5b, 0xe2, + 0x1b, 0x38, 0xb2, 0x15, 0x75, 0x66, 0x67, 0x58, 0x00, 0x3f, 0xde, 0x8a, + 0x63, 0x13, 0x34, 0x6a, 0x30, 0xca, 0xb4, 0xd5, 0x3e, 0xe0, 0x6d, 0x14, + 0xb8, 0x9a, 0x48, 0xef, 0xfd, 0xbd, 0x6d, 0x20, 0x11, 0x4d, 0x25, 0xe5, + 0xab, 0x15, 0x8d, 0xe5, 0x91, 0xbc, 0xc6, 0x69, 0x8a, 0xf8, 0xab, 0x3a, + 0x82, 0xae, 0xc5, 0x03, 0x2c, 0xcf, 0x54, 0xdc, 0xcd, 0xe8, 0x49, 0x53, + 0xb5, 0xd8, 0xc2, 0x24, 0xf8, 0x8c, 0x38, 0x8f, 0xe3, 0xfe, 0x3a, 0x18, + 0x15, 0xa8, 0xda, 0x77, 0xc8, 0x81, 0x72, 0xc6, 0xc1, 0x60, 0xa3, 0x73, + 0x65, 0x68, 0x5c, 0xf3, 0x1d, 0x8d, 0x61, 0x21, 0x65, 0xfb, 0x45, 0xc4, + 0x4c, 0x31, 0x88, 0x25, 0x0d, 0x52, 0x75, 0x3b, 0xec, 0x54, 0xe0, 0xb1, + 0x9c, 0x7c, 0xdf, 0xe3, 0x3b, 0x77, 0x31, 0x33, 0xd7, 0x25, 0x99, 0xff, + 0xc5, 0x40, 0x1e, 0x85, 0x09, 0xfd, 0x2d, 0x24, 0x4a, 0x92, 0xe7, 0x77, + 0x48, 0xa5, 0x46, 0xf4, 0x8e, 0xa3, 0x6b, 0x24, 0xe4, 0x6b, 0x31, 0xf6, + 0xe0, 0x16, 0x49, 0x9b, 0x9f, 0xa3, 0x1a, 0x5c, 0x05, 0x5e, 0x81, 0x62, + 0xc8, 0x14, 0x52, 0xb4, 0x21, 0xfd, 0x76, 0x6d, 0x88, 0xe9, 0x3b, 0x0b, + 0x75, 0x27, 0x92, 0x47, 0x5a, 0x58, 0x08, 0x26, 0xa7, 0xa2, 0x48, 0x1c, + 0x14, 0x3e, 0x5e, 0xdf, 0x81, 0x83, 0x83, 0x3e, 0xc6, 0x72, 0x27, 0xc4, + 0x6a, 0x46, 0x2b, 0xf2, 0x8d, 0x42, 0x11, 0xb9, 0x15, 0xd7, 0xf0, 0x20, + 0x29, 0x53, 0xba, 0xf0, 0x6e, 0x41, 0x3d, 0xee, 0x19, 0xf2, 0x43, 0xf3, + 0x6d, 0x00, 0xe2, 0x43, 0x77, 0xb9, 0xa9, 0x78, 0x34, 0x48, 0x3c, 0x1a, + 0x8b, 0xbd, 0xa1, 0xe5, 0x90, 0x59, 0x5b, 0xd6, 0x1e, 0x22, 0xdf, 0xb2, + 0xa7, 0x96, 0x7d, 0x55, 0x86, 0x66, 0x95, 0xb7, 0x06, 0xe7, 0x60, 0x2a, + 0x01, 0x48, 0x3f, 0xd4, 0xa7, 0xd4, 0xc2, 0x38, 0xa4, 0x10, 0x8e, 0x4f, + 0x97, 0xad, 0xa3, 0xb9, 0xe2, 0xaa, 0x13, 0xb1, 0x16, 0x89, 0x3d, 0x74, + 0x60, 0x94, 0x8c, 0xc3, 0xe6, 0x5f, 0xcf, 0xdc, 0x58, 0x17, 0x98, 0x27, + 0x86, 0xae, 0x2a, 0x0d, 0xe8, 0x33, 0x79, 0xc8, 0xc8, 0x5b, 0x59, 0xb0, + 0xba, 0xac, 0xd3, 0x6e, 0x2d, 0x7b, 0x0b, 0x9a, 0xb5, 0xfd, 0x58, 0x42, + 0xeb, 0x80, 0xf4, 0x6b, 0x9a, 0x2f, 0x19, 0x43, 0x75, 0xb4, 0xcb, 0xc9, + 0xd5, 0x28, 0xf5, 0xb9, 0x67, 0x82, 0xb4, 0xed, 0x8c, 0x3f, 0x3d, 0x6b, + 0x6d, 0x1b, 0x80, 0x13, 0x5c, 0x7b, 0x2e, 0xfa, 0xa0, 0x32, 0xba, 0xb5, + 0x46, 0xd6, 0xe7, 0x90, 0xe9, 0xd1, 0x91, 0xa0, 0xaa, 0x26, 0x35, 0xa2, + 0x0d, 0x98, 0x44, 0x11, 0xae, 0xf9, 0xc5, 0x12, 0x4d, 0x1a, 0x7c, 0x53, + 0xea, 0xf6, 0x05, 0x8d, 0x3a, 0x74, 0x92, 0xc9, 0x65, 0xeb, 0x6f, 0xb5, + 0xb4, 0xd2, 0xcd, 0x5c, 0xec, 0xaf, 0x95, 0xcb, 0xb4, 0x3c, 0x22, 0xca, + 0x1c, 0x06, 0x85, 0x16, 0x96, 0x24, 0x8c, 0x6c, 0x80, 0xf8, 0xb3, 0xa7, + 0x87, 0x77, 0xeb, 0x09, 0x71, 0xc8, 0x95, 0xfb, 0x5e, 0xe5, 0x6f, 0x78, + 0xf9, 0x60, 0xf9, 0x9e, 0x58, 0x7b, 0xbd, 0x47, 0xdd, 0x48, 0x2e, 0x56, + 0xcd, 0x63, 0x72, 0xc9, 0x4b, 0x65, 0x2d, 0x41, 0xe8, 0x81, 0x19, 0x33, + 0x4b, 0xf6, 0x02, 0xc6, 0xcb, 0x2e, 0xdf, 0x3d, 0xc8, 0xdd, 0x2f, 0x0f, + 0x09, 0x67, 0xf0, 0xaa, 0x3c, 0x51, 0xdc, 0x8d, 0xc6, 0xc3, 0xb2, 0x3b, + 0x15, 0x85, 0xcb, 0xeb, 0x62, 0xef, 0xa3, 0xf9, 0x94, 0xf4, 0x35, 0x9c, + 0x59, 0xcc, 0xc2, 0x68, 0xb4, 0xde, 0x02, 0x75, 0x8e, 0xf5, 0x33, 0xca, + 0xd5, 0xc5, 0x24, 0xae, 0xf6, 0xde, 0x2b, 0x01, 0xf4, 0x56, 0xb9, 0xa5, + 0xa7, 0xe0, 0x64, 0x2e, 0xba, 0x1d, 0x53, 0x54, 0x46, 0xcf, 0x64, 0x16, + 0x12, 0xe2, 0xa6, 0xcc, 0x18, 0xb4, 0x77, 0x8b, 0x19, 0x50, 0x43, 0x96, + 0xc8, 0x5d, 0xc3, 0x58, 0xf0, 0xfd, 0x5e, 0x13, 0xa9, 0x10, 0x67, 0xdf, + 0x25, 0xdb, 0xaf, 0x38, 0x5f, 0xbd, 0x35, 0xc1, 0x49, 0x44, 0xe8, 0x1f, + 0x12, 0xa4, 0x7c, 0x28, 0xa3, 0xd6, 0x0d, 0x6f, 0x44, 0xa9, 0x5f, 0xfc, + 0x9f, 0xfa, 0x11, 0x62, 0x87, 0x5b, 0x0e, 0x91, 0xd4, 0xb6, 0xd3, 0x71, + 0xc2, 0x77, 0x19, 0xf6, 0x7c, 0x11, 0x30, 0x5e, 0x5c, 0xd3, 0x1e, 0x90, + 0x05, 0x31, 0x63, 0xbb, 0xef, 0x85, 0xe0, 0x27, 0x94, 0x80, 0xcb, 0x33, + 0xbc, 0x5e, 0x45, 0x87, 0x62, 0xdf, 0xd4, 0x12, 0x2f, 0xf5, 0x41, 0x15, + 0x03, 0x0c, 0x80, 0xe8, 0xe2, 0x06, 0xde, 0x4b, 0x46, 0x70, 0x94, 0xd2, + 0x0d, 0x85, 0x72, 0x27, 0xe5, 0x6c, 0xeb, 0xd2, 0x78, 0x0b, 0x38, 0x40, + 0xe8, 0xdb, 0x47, 0x5c, 0xba, 0xd0, 0x21, 0x33, 0x8f, 0xb8, 0xc0, 0x66, + 0x1e, 0xd1, 0xb0, 0x94, 0xa3, 0x39, 0xc7, 0x87, 0xaf, 0x97, 0x98, 0xce, + 0x6d, 0x03, 0x1a, 0xdb, 0x52, 0x96, 0x0b, 0x9d, 0x5b, 0xf8, 0xa3, 0xf4, + 0x41, 0x95, 0x72, 0xad, 0x0e, 0x98, 0x61, 0x7f, 0xf3, 0x8f, 0x23, 0xeb, + 0xc0, 0xdf, 0xd7, 0x70, 0x26, 0x8c, 0xb3, 0xb3, 0xf0, 0xa2, 0x8a, 0x39, + 0xdd, 0x61, 0xb4, 0x53, 0xe0, 0x2a, 0x6f, 0x91, 0x34, 0x9c, 0x76, 0xf6, + 0x52, 0x93, 0xe6, 0x39, 0xb7, 0x54, 0x07, 0x46, 0x82, 0x2d, 0x05, 0x6d, + 0x9a, 0x00, 0x53, 0x65, 0x68, 0x93, 0x91, 0x00, 0xda, 0xe0, 0x93, 0x34, + 0x60, 0xb1, 0x93, 0x0b, 0x64, 0xa8, 0x12, 0xd2, 0x51, 0x3c, 0xdb, 0xb0, + 0x4c, 0x39, 0x4e, 0xce, 0xbd, 0xf0, 0x65, 0x12, 0x8a, 0xd4, 0x80, 0x7d, + 0x82, 0x85, 0xe4, 0x92, 0xc2, 0x77, 0x1e, 0xcf, 0xd9, 0xab, 0x0f, 0x9b, + 0x32, 0x2e, 0x3f, 0xe1, 0x0e, 0x87, 0x1c, 0x87, 0x34, 0xe7, 0x93, 0x16, + 0x95, 0x09, 0x7d, 0x24, 0xa8, 0xb5, 0xe0, 0x9f, 0x23, 0x87, 0x5c, 0x0b, + 0x31, 0x4a, 0x2f, 0xe2, 0x5c, 0x82, 0x49, 0x51, 0xe4, 0x93, 0xcb, 0x05, + 0x23, 0x4f, 0x8a, 0x83, 0x88, 0xfb, 0x89, 0xb0, 0x08, 0xd6, 0x64, 0xad, + 0x51, 0x84, 0x40, 0x29, 0xb1, 0xca, 0x74, 0x26, 0x29, 0x5a, 0x61, 0x01, + 0x2e, 0xa0, 0xeb, 0xeb, 0x02, 0xb5, 0xff, 0xd8, 0x20, 0x6a, 0x5e, 0x8d, + 0x17, 0x1e, 0xa3, 0xd7, 0x2f, 0x20, 0x0b, 0x93, 0x17, 0x24, 0xf7, 0x90, + 0x7b, 0xc6, 0xba, 0xd8, 0xf9, 0xe9, 0x0a, 0x2a, 0x7a, 0x81, 0x23, 0x81, + 0x03, 0x6f, 0x1e, 0x0d, 0x87, 0x83, 0xd1, 0xcf, 0x92, 0x2f, 0x19, 0x82, + 0x4e, 0x6c, 0x0a, 0x02, 0xb6, 0x70, 0xbc, 0xe1, 0x58, 0xe7, 0x16, 0xdb, + 0x2f, 0x74, 0x9f, 0xe1, 0xc2, 0x1e, 0x64, 0xc6, 0x48, 0x08, 0xee, 0xea, + 0x52, 0x9a, 0xce, 0x2c, 0xc5, 0x0c, 0x7a, 0x63, 0xf1, 0x6a, 0xbd, 0x2c, + 0x8b, 0xd5, 0x4a, 0xfa, 0x1e, 0xab, 0x9a, 0x5b, 0x25, 0xb8, 0xfa, 0x0a, + 0xe9, 0x68, 0x80, 0x6f, 0x80, 0x57, 0x10, 0x54, 0xb8, 0xa2, 0x16, 0xbd, + 0xfe, 0xf7, 0xea, 0x01, 0xc7, 0x94, 0x5a, 0x95, 0xe3, 0x61, 0xa5, 0x49, + 0x84, 0xf5, 0x79, 0x78, 0xb5, 0x0a, 0x96, 0xca, 0x01, 0x1b, 0xd0, 0x0b, + 0x51, 0x30, 0xd3, 0x48, 0xfc, 0x4d, 0x50, 0x71, 0x09, 0x73, 0xea, 0x37, + 0xcd, 0x9d, 0x3d, 0xde, 0x30, 0x56, 0x21, 0xf0, 0xef, 0x84, 0xad, 0x27, + 0xe1, 0x83, 0xdb, 0xfb, 0xcd, 0x11, 0xb2, 0xbd, 0x30, 0x67, 0x8a, 0x88, + 0x09, 0x0e, 0x9d, 0x96, 0x09, 0xba, 0xda, 0x9d, 0xf0, 0xe9, 0xb4, 0xa6, + 0x7a, 0x04, 0xf9, 0x4b, 0xb8, 0x51, 0xa9, 0x99, 0xf3, 0xbb, 0x77, 0x95, + 0x0a, 0xa1, 0xa6, 0xa1, 0x24, 0xfc, 0xcc, 0x45, 0xe8, 0x83, 0xc8, 0x6f, + 0x48, 0xad, 0x9a, 0x73, 0xd0, 0xe0, 0x57, 0x7d, 0xe4, 0x78, 0x65, 0xef, + 0xae, 0xc2, 0xfe, 0x7a, 0x56, 0xaf, 0x03, 0x71, 0x2b, 0xe6, 0xa1, 0x7e, + 0xe5, 0x12, 0xf8, 0xc3, 0x75, 0xc7, 0x22, 0x5f, 0x1b, 0x52, 0x90, 0xe5, + 0xdf, 0xba, 0x9d, 0xe2, 0x68, 0xe0, 0xb3, 0x7a, 0x9e, 0x14, 0xff, 0xb5, + 0x0a, 0x80, 0x20, 0x49, 0x88, 0xe9, 0x9c, 0xe4, 0xb5, 0xaf, 0x7e, 0x51, + 0xec, 0xe7, 0xfc, 0x64, 0x65, 0x21, 0x10, 0xc6, 0x1f, 0x7f, 0x93, 0x7d, + 0xd8, 0xf5, 0xd0, 0x98, 0x94, 0x44, 0xf8, 0x49, 0x6a, 0x51, 0x0a, 0x54, + 0xf4, 0x9f, 0xee, 0x3c, 0x56, 0xbf, 0x4c, 0xe4, 0xde, 0x1c, 0x9b, 0x11, + 0x7e, 0x9a, 0x71, 0x11, 0x80, 0x33, 0xd5, 0xb0, 0x9b, 0xef, 0x67, 0x29, + 0xa4, 0x7d, 0x70, 0x31, 0x3f, 0x8b, 0x2e, 0x4a, 0x0f, 0x2c, 0x91, 0x3d, + 0x3e, 0x3d, 0x8c, 0x0a, 0x2b, 0xf1, 0xdd, 0xbf, 0x61, 0xe6, 0xa3, 0xef, + 0x6d, 0x82, 0xc8, 0xb7, 0x5e, 0x2b, 0x83, 0xc9, 0x4e, 0xa0, 0x85, 0x7f, + 0x01, 0x5a, 0xca, 0x6e, 0x90, 0xfa, 0x7e, 0x82, 0x4d, 0x35, 0x7e, 0xe0, + 0x26, 0x40, 0xf4, 0xa6, 0xae, 0xc3, 0x89, 0xf3, 0xca, 0x55, 0x2c, 0xb5, + 0x29, 0x05, 0x94, 0x45, 0xa7, 0x45, 0xf3, 0x3d, 0xbb, 0x53, 0x5e, 0xca, + 0x7c, 0x84, 0x8f, 0x72, 0x98, 0x93, 0x90, 0x1f, 0x56, 0x72, 0xdb, 0xbd, + 0xa9, 0xeb, 0xf9, 0xe9, 0xce, 0xb1, 0x41, 0xc3, 0xaa, 0xa0, 0xc4, 0x74, + 0x23, 0xc1, 0xeb, 0x7d, 0x41, 0xcd, 0xa4, 0x62, 0xec, 0xfc, 0x9a, 0xa4, + 0x16, 0xec, 0x67, 0x41, 0x89, 0xf0, 0x0e, 0xf3, 0xd1, 0xa2, 0x2f, 0xba, + 0x5d, 0x93, 0x36, 0x46, 0xf5, 0x52, 0x64, 0x91, 0xe7, 0x40, 0x91, 0x20, + 0xa1, 0xc9, 0xaa, 0x4c, 0x79, 0xc4, 0xbb, 0x67, 0x79, 0xad, 0x43, 0xab, + 0xba, 0xde, 0xfc, 0xf1, 0x74, 0x81, 0x33, 0xc0, 0x3f, 0x39, 0xd1, 0xd1, + 0xdf, 0xc0, 0x53, 0x33, 0xb2, 0x92, 0x37, 0xe6, 0x86, 0x2a, 0xe4, 0xe1, + 0x7c, 0x98, 0xf7, 0xdb, 0x5c, 0xa9, 0xff, 0x8d, 0x9c, 0xab, 0xe2, 0xf2, + 0xd5, 0xb1, 0x42, 0xa9, 0xf4, 0x97, 0x80, 0xcd, 0xde, 0x25, 0x2e, 0x87, + 0x92, 0xdd, 0xcf, 0xed, 0x67, 0x93, 0x8c, 0x5a, 0x1d, 0xee, 0xcf, 0x9d, + 0x50, 0x8f, 0xa7, 0xe3, 0x5c, 0xa3, 0x68, 0x78, 0x24, 0xeb, 0x60, 0xa3, + 0x8b, 0x36, 0xbb, 0xcb, 0x46, 0xee, 0x77, 0xfb, 0xf8, 0x69, 0x24, 0xd1, + 0xfa, 0xad, 0x76, 0x76, 0x5e, 0x54, 0xe5, 0xb6, 0x36, 0xc6, 0xdd, 0xa9, + 0x6c, 0x44, 0x15, 0xf7, 0x0a, 0xf8, 0xbb, 0xba, 0xec, 0x35, 0xff, 0xc9, + 0xd6, 0x5d, 0xf5, 0x73, 0x4a, 0x15, 0x8f, 0x7b, 0x6e, 0xf4, 0xa0, 0x6d, + 0x10, 0xbb, 0x67, 0x0c, 0xb4, 0x69, 0xad, 0xb6, 0x40, 0xf7, 0x5f, 0x37, + 0x28, 0xc4, 0x08, 0x49, 0xd0, 0x16, 0x70, 0x80, 0xea, 0x55, 0x66, 0x07, + 0xc8, 0x03, 0x1b, 0xf6, 0xd3, 0x03, 0x04, 0x74, 0xe0, 0x50, 0x3f, 0xd2, + 0x53, 0x92, 0xa0, 0x9d, 0x59, 0xc9, 0x74, 0xf2, 0x7e, 0x3b, 0x33, 0x02, + 0x10, 0x0b, 0x39, 0xf7, 0x4f, 0x6b, 0x58, 0xb2, 0x1a, 0xda, 0x65, 0x44, + 0xd1, 0x7c, 0x3f, 0xd7, 0xe3, 0xac, 0xe2, 0x1f, 0x38, 0xc1, 0x6a, 0xb0, + 0xdc, 0xc3, 0x9c, 0x7b, 0x11, 0x3c, 0x05, 0x21, 0x96, 0x76, 0x98, 0x76, + 0x82, 0xc1, 0x54, 0xdf, 0xdc, 0x8f, 0x4c, 0xd2, 0x63, 0x04, 0x06, 0x77, + 0x36, 0xe6, 0x2e, 0xd1, 0x00, 0x28, 0x42, 0x7c, 0x4a, 0x27, 0x90, 0x46, + 0xc9, 0xce, 0x33, 0x1c, 0xae, 0xda, 0x79, 0x64, 0x7f, 0x52, 0x3f, 0x58, + 0x11, 0x76, 0x4a, 0xb6, 0x72, 0xd8, 0x76, 0xae, 0xfd, 0x5c, 0x57, 0x69, + 0x76, 0x91, 0x84, 0x21, 0xc4, 0x9b, 0xd8, 0xa2, 0xff, 0x93, 0x02, 0x77, + 0x61, 0x57, 0x96, 0x7b, 0x8e, 0xfc, 0xf2, 0x6c, 0x11, 0x2b, 0x5e, 0x88, + 0x5c, 0x17, 0x1d, 0x12, 0x79, 0x3a, 0x78, 0xb6, 0x9d, 0x70, 0xfa, 0xd4, + 0xc1, 0x5c, 0x90, 0x0e, 0x0a, 0xd1, 0x3c, 0x7d, 0xcf, 0xee, 0x8a, 0xb2, + 0xb2, 0x4d, 0xce, 0x89, 0x32, 0xa9, 0x6c, 0x56, 0x57, 0x85, 0xb1, 0xbf, + 0x18, 0x1d, 0xc6, 0xe1, 0x17, 0xc5, 0x92, 0x42, 0x99, 0xf9, 0x9f, 0x04, + 0xec, 0x38, 0xf8, 0xa0, 0xd2, 0xab, 0xe6, 0x13, 0x4d, 0x9c, 0x18, 0x86, + 0x3e, 0x18, 0x73, 0x2c, 0xac, 0xe0, 0xb9, 0xf9, 0x87, 0x74, 0xb8, 0xd7, + 0x47, 0x6e, 0x42, 0xfc, 0x29, 0xa0, 0x1f, 0x56, 0x68, 0xb6, 0x23, 0x96, + 0xa2, 0x8d, 0x54, 0x81, 0x0f, 0x60, 0xb9, 0xde, 0x93, 0xfc, 0xfd, 0xde, + 0xbe, 0xb3, 0xb5, 0x87, 0xec, 0x9f, 0x17, 0xc2, 0x77, 0x6e, 0xa0, 0x62, + 0xdb, 0x66, 0xba, 0xc5, 0x05, 0x12, 0x46, 0x5d, 0x3c, 0x23, 0x29, 0x68, + 0xe5, 0x31, 0xe3, 0x15, 0xec, 0xac, 0x15, 0x9a, 0xbf, 0x42, 0x65, 0x80, + 0x45, 0x9c, 0x1d, 0xc2, 0x0e, 0x18, 0x47, 0x40, 0x44, 0xc1, 0x55, 0x24, + 0x5a, 0x35, 0xad, 0x59, 0xd2, 0xc6, 0xc3, 0x68, 0x58, 0xbd, 0x6f, 0xcf, + 0x5d, 0xb1, 0x9b, 0x0c, 0x92, 0x39, 0x22, 0x49, 0x66, 0x2e, 0x03, 0x7b, + 0x75, 0x5c, 0x6c, 0xde, 0x37, 0x54, 0xa9, 0x07, 0x2f, 0x7e, 0xc1, 0x3e, + 0x3b, 0xab, 0xd2, 0xa9, 0xfa, 0xc7, 0x6b, 0xd5, 0x14, 0x08, 0x35, 0x89, + 0x0b, 0x31, 0x18, 0x54, 0x7d, 0x6b, 0x53, 0x80, 0x6e, 0x32, 0x9b, 0xff, + 0x61, 0x7f, 0x36, 0xe5, 0x28, 0x40, 0xbc, 0xc7, 0x19, 0xb3, 0xae, 0xfa, + 0x95, 0xa8, 0xae, 0xd2, 0x97, 0x72, 0xc6, 0x91, 0x36, 0x3a, 0xa6, 0xec, + 0x4a, 0x41, 0x63, 0x6b, 0x28, 0xef, 0x5a, 0xa1, 0xdb, 0xf2, 0xd9, 0xfd, + 0x61, 0x72, 0xa4, 0xd2, 0x9e, 0xf7, 0x47, 0xf4, 0x4e, 0xea, 0x2a, 0xa5, + 0x35, 0xe1, 0x77, 0x3a, 0x53, 0x28, 0xa6, 0x55, 0x48, 0x0c, 0x1e, 0x44, + 0xfc, 0xc1, 0x31, 0x5a, 0x00, 0xcd, 0x29, 0xc1, 0x5c, 0xca, 0x2a, 0x07, + 0x01, 0x63, 0xac, 0xb3, 0xfb, 0xf6, 0x0b, 0xac, 0xfd, 0xe8, 0x7b, 0xed, + 0xf9, 0x3d, 0x9a, 0xbc, 0x67, 0x28, 0x1c, 0xd9, 0x3f, 0x97, 0x28, 0x4a, + 0xe7, 0xd0, 0x08, 0xe9, 0x3e, 0xa0, 0xcb, 0x0f, 0xe0, 0x3f, 0x1b, 0x80, + 0x43, 0x74, 0xd9, 0x9d, 0x0b, 0x22, 0x81, 0xf7, 0xec, 0x71, 0x2a, 0x29, + 0x9e, 0x5d, 0x1e, 0x8d, 0xf4, 0x22, 0x95, 0x78, 0x86, 0xcb, 0xf0, 0x9d, + 0xe7, 0x6a, 0x66, 0x7e, 0x28, 0xb5, 0x47, 0xb6, 0xdc, 0x0d, 0x03, 0x3c, + 0x09, 0x58, 0x76, 0x93, 0x39, 0xb2, 0xd3, 0x75, 0xb4, 0x51, 0x55, 0x84, + 0x30, 0x24, 0x0a, 0x76, 0xf4, 0x97, 0xe7, 0x0f, 0x5a, 0x67, 0xee, 0xf4, + 0xc7, 0x69, 0x8d, 0xf2, 0x32, 0x29, 0x5c, 0x33, 0x82, 0x5f, 0x6c, 0x47, + 0xd0, 0xe2, 0xbd, 0x62, 0xd6, 0x4c, 0x6d, 0x0d, 0xba, 0x87, 0xd3, 0x43, + 0x7e, 0x2d, 0xa6, 0x14, 0x09, 0x4f, 0x3b, 0xc3, 0x04, 0x14, 0xe5, 0x65, + 0xe9, 0x3b, 0x6a, 0xca, 0xb5, 0x96, 0x84, 0x3f, 0x53, 0x49, 0x22, 0x45, + 0x91, 0xff, 0xf9, 0x26, 0x75, 0x0d, 0x9c, 0xa7, 0x00, 0xf4, 0x65, 0xc4, + 0x60, 0x72, 0xab, 0xeb, 0xf8, 0xa8, 0x72, 0xfe, 0xd8, 0xde, 0x93, 0x67, + 0xcb, 0x09, 0xcc, 0xa0, 0xce, 0x9f, 0x67, 0x63, 0x26, 0xfa, 0x7f, 0x89, + 0xaa, 0x3e, 0x6d, 0xb2, 0x90, 0xd7, 0xef, 0x3e, 0x2a, 0x66, 0x26, 0x33, + 0xe6, 0x26, 0xc1, 0x58, 0xf8, 0x91, 0xea, 0x2f, 0xd0, 0x84, 0x21, 0x41, + 0x93, 0xa6, 0x36, 0x40, 0xb5, 0x4c, 0xac, 0x21, 0x88, 0x37, 0x47, 0x8a, + 0xb8, 0xf3, 0x33, 0x73, 0x12, 0xd7, 0x5a, 0x55, 0xf9, 0xd1, 0x1e, 0x75, + 0xa4, 0x66, 0x68, 0x3f, 0xf7, 0xb2, 0xc4, 0x5d, 0x1b, 0xb1, 0x61, 0x0f, + 0xaf, 0x4b, 0x9b, 0x20, 0x2b, 0x05, 0x68, 0x1c, 0x6c, 0x97, 0x8d, 0xb8, + 0x7b, 0x96, 0xda, 0xe0, 0x67, 0x15, 0x4c, 0x51, 0x71, 0x0d, 0xd3, 0x7b, + 0xde, 0xaa, 0xd3, 0x58, 0xf5, 0xc9, 0x62, 0x0a, 0xc2, 0x33, 0x1f, 0xf3, + 0xc3, 0x30, 0xb5, 0x64, 0xd1, 0x59, 0x41, 0x0e, 0xae, 0xaa, 0x0d, 0xdf, + 0x9f, 0x5d, 0x3f, 0x15, 0x0d, 0x46, 0x7a, 0x6d, 0x2e, 0x29, 0x1b, 0xc0, + 0xd3, 0x11, 0x10, 0x5d, 0xdc, 0x6a, 0x35, 0x8c, 0x43, 0xc8, 0x9f, 0x05, + 0x80, 0xdc, 0x25, 0x24, 0x37, 0x70, 0x7e, 0x1c, 0xe9, 0x85, 0x5a, 0xef, + 0x83, 0x3a, 0x55, 0x68, 0x83, 0x17, 0xf4, 0xc7, 0xae, 0xe4, 0x84, 0xc9, + 0x64, 0x5d, 0x2f, 0xb6, 0xca, 0x10, 0x95, 0xb8, 0xd6, 0x80, 0xfd, 0x05, + 0xa5, 0x06, 0x32, 0x34, 0x91, 0x01, 0xd2, 0x02, 0x90, 0xe1, 0xf7, 0x89, + 0x8a, 0xee, 0x18, 0x04, 0x93, 0xd9, 0xb4, 0x63, 0x4b, 0xf7, 0x7a, 0x9c, + 0x1b, 0x4b, 0xf9, 0x31, 0x32, 0xd9, 0xf2, 0x55, 0x4e, 0xc1, 0x02, 0xce, + 0x77, 0x38, 0x36, 0x29, 0xb8, 0x54, 0x8c, 0xc2, 0x27, 0x5f, 0xd9, 0xae, + 0x3e, 0x1e, 0xcd, 0xe9, 0x07, 0x90, 0x4c, 0xe0, 0xda, 0x16, 0x6e, 0xdf, + 0xde, 0x3a, 0x61, 0x89, 0x9f, 0x79, 0xd0, 0xd4, 0x66, 0x95, 0xad, 0xe4, + 0x11, 0x7d, 0xa1, 0xae, 0xec, 0x3e, 0x6e, 0x20, 0x5a, 0xd0, 0x28, 0x0e, + 0x55, 0xec, 0xcf, 0x34, 0xec, 0xb7, 0xfc, 0xa4, 0xb3, 0x8f, 0x56, 0x13, + 0x50, 0xcc, 0x15, 0x10, 0x74, 0x40, 0x72, 0x42, 0x20, 0x22, 0xb3, 0xaf, + 0xf3, 0x68, 0xba, 0x95, 0x45, 0xcb, 0xef, 0x92, 0xd5, 0x14, 0x4c, 0x1f, + 0xe3, 0xc1, 0xa6, 0x03, 0x4e, 0x05, 0xd2, 0x1a, 0xee, 0xd2, 0x48, 0x44, + 0x2e, 0x50, 0x3b, 0x86, 0xc8, 0x6a, 0xc8, 0x4c, 0xca, 0x2a, 0xb6, 0xf7, + 0x3c, 0xaf, 0xdc, 0x62, 0xb1, 0x49, 0x13, 0xfe, 0xe7, 0x32, 0xea, 0x78, + 0xfa, 0xba, 0xcf, 0x15, 0x47, 0x58, 0xdc, 0x19, 0x73, 0x1d, 0xff, 0xbd, + 0xcc, 0x27, 0xf6, 0xfc, 0x66, 0x68, 0xa7, 0x29, 0xaf, 0x2b, 0x25, 0x0c, + 0x15, 0x47, 0xff, 0xc1, 0x00, 0x9d, 0xfa, 0x58, 0x9c, 0xaa, 0xf9, 0xcc, + 0x4c, 0x51, 0x1d, 0xda, 0xf3, 0x3c, 0x10, 0xd0, 0x3b, 0x59, 0x30, 0x02, + 0x68, 0x29, 0x1c, 0xa7, 0x22, 0xea, 0x81, 0xd3, 0x29, 0x71, 0x39, 0xe8, + 0x72, 0x7f, 0x7d, 0x94, 0x0a, 0x64, 0x2c, 0xe6, 0x55, 0xfb, 0x90, 0x78, + 0x7e, 0x6c, 0x3e, 0xfe, 0x57, 0x14, 0x61, 0xef, 0xe2, 0x63, 0x57, 0x6c, + 0x13, 0x97, 0x27, 0x2b, 0x38, 0x44, 0xab, 0x74, 0x76, 0x11, 0xa6, 0x60, + 0xad, 0x8e, 0xad, 0xe5, 0xa5, 0xa1, 0x66, 0xc5, 0xe1, 0x4d, 0x27, 0xa0, + 0x79, 0x7a, 0x09, 0xe6, 0xf0, 0x28, 0x3f, 0xcb, 0xc6, 0xf8, 0x94, 0xc0, + 0xf1, 0x13, 0xbe, 0x62, 0x6a, 0x52, 0x75, 0x52, 0xd3, 0x82, 0x31, 0xbd, + 0x15, 0xf2, 0xe8, 0x2e, 0xb1, 0x62, 0x03, 0x1e, 0xe2, 0xb3, 0xec, 0xbc, + 0x3c, 0x12, 0xca, 0x62, 0x4e, 0xc2, 0x3a, 0x51, 0x1c, 0xdf, 0xa2, 0x84, + 0x88, 0xe5, 0x7e, 0xd7, 0x5d, 0xd7, 0xbf, 0xf2, 0x7d, 0xbd, 0x9a, 0x90, + 0x63, 0xfd, 0x8a, 0x84, 0x2b, 0x9d, 0x89, 0x27, 0x63, 0x4c, 0x0a, 0xe3, + 0x70, 0x94, 0x7b, 0xe6, 0xb3, 0xd7, 0xcb, 0xcb, 0x8a, 0xeb, 0x6b, 0x53, + 0x34, 0x2f, 0x62, 0x44, 0x2d, 0x73, 0x63, 0x8a, 0xf4, 0xa2, 0x01, 0xd7, + 0x12, 0xb6, 0x8d, 0x8c, 0x4b, 0x73, 0x2b, 0x44, 0x50, 0x49, 0x6f, 0x01, + 0xac, 0xc5, 0x15, 0x37, 0x6c, 0xde, 0xd4, 0x02, 0xb1, 0x12, 0x80, 0x73, + 0xb2, 0x52, 0x0e, 0xe0, 0xb5, 0x75, 0xc9, 0x48, 0xcf, 0x18, 0x5c, 0xcc, + 0xaf, 0x58, 0xa2, 0x3e, 0x28, 0xe4, 0xab, 0xde, 0xea, 0x2a, 0xcf, 0x58, + 0x22, 0xc4, 0x68, 0xea, 0x9b, 0x7b, 0x90, 0xc5, 0xdc, 0x1c, 0x37, 0xd1, + 0x8a, 0x4f, 0xe7, 0x24, 0x23, 0x39, 0xb9, 0x62, 0xb8, 0x41, 0x13, 0x7b, + 0xe2, 0x1e, 0x0d, 0x4e, 0x38, 0x11, 0xa3, 0xb9, 0x10, 0xbb, 0x10, 0x6f, + 0x40, 0x9f, 0x50, 0x05, 0xc7, 0x0e, 0xb9, 0x9e, 0xab, 0x7c, 0x3c, 0x78, + 0xce, 0x54, 0xbf, 0xbf, 0x40, 0x36, 0x76, 0xbc, 0x4b, 0x64, 0x32, 0xca, + 0x0e, 0x2d, 0x91, 0x87, 0xd5, 0x00, 0x19, 0xbf, 0x12, 0xd0, 0x35, 0x7c, + 0xa1, 0xe5, 0xcf, 0x7a, 0x2d, 0x08, 0x62, 0xed, 0x34, 0x61, 0xe3, 0xda, + 0x2c, 0xcc, 0x1b, 0xf8, 0x12, 0xfe, 0xfd, 0x19, 0xa2, 0xc3, 0x70, 0xfd, + 0x4f, 0x5b, 0x5d, 0x20, 0xd2, 0xe1, 0xc5, 0xac, 0xe7, 0xa1, 0x84, 0x00, + 0xbd, 0x46, 0x81, 0xfd, 0x54, 0x69, 0xed, 0x1a, 0x7a, 0x32, 0xbb, 0x75, + 0x22, 0x76, 0x6d, 0x34, 0x24, 0xcc, 0xe6, 0xbe, 0x78, 0x5a, 0x75, 0x6c, + 0xbc, 0x62, 0xb8, 0x14, 0xf7, 0x13, 0x73, 0xc2, 0xdc, 0xb6, 0xfa, 0xfb, + 0x97, 0xfe, 0x27, 0x7b, 0x33, 0xb8, 0xeb, 0x20, 0xd2, 0x0f, 0x4f, 0xed, + 0xd1, 0xd0, 0x63, 0xf7, 0xc5, 0x8e, 0xec, 0xcc, 0xd2, 0x31, 0x38, 0x35, + 0x65, 0x33, 0x5c, 0x63, 0x85, 0xf7, 0x3d, 0xc3, 0x62, 0x26, 0x52, 0x0a, + 0x67, 0xda, 0x87, 0x1f, 0x9e, 0x47, 0xec, 0x6b, 0xf5, 0x74, 0x1a, 0xc5, + 0xa7, 0xa0, 0x0f, 0xdd, 0xc5, 0x42, 0xf4, 0xda, 0x41, 0x1a, 0x48, 0xa9, + 0xbe, 0x4f, 0xb6, 0x28, 0x17, 0xe9, 0xf5, 0xd7, 0x00, 0xb3, 0xfe, 0x05, + 0x4e, 0xa7, 0xdf, 0x65, 0x7a, 0xb8, 0x4f, 0xe0, 0xfe, 0x58, 0x9e, 0xba, + 0x45, 0x11, 0xba, 0xc2, 0xdb, 0x97, 0x97, 0xa4, 0xbc, 0x18, 0x21, 0x1b, + 0xad, 0x82, 0xef, 0xb1, 0x5f, 0x2f, 0x25, 0x9d, 0xca, 0x52, 0xa5, 0x6d, + 0x8c, 0xab, 0x07, 0x2b, 0x7b, 0x6a, 0x77, 0x9d, 0xdf, 0xfb, 0xae, 0x6e, + 0x49, 0x18, 0x25, 0x4a, 0xf2, 0x7d, 0xa0, 0x32, 0xc8, 0x53, 0x10, 0xc3, + 0xf2, 0xef, 0xf3, 0xe7, 0x79, 0xd7, 0x6a, 0x0e, 0x61, 0xff, 0x89, 0xc9, + 0x42, 0xe8, 0x6e, 0x4f, 0x78, 0xe1, 0x5f, 0xcd, 0x7a, 0xf6, 0x27, 0x72, + 0x67, 0xea, 0x0b, 0xa6, 0xcc, 0x34, 0xb7, 0x8f, 0x92, 0x3c, 0x95, 0xb9, + 0x0a, 0x5d, 0x49, 0x2e, 0xb7, 0x7d, 0x31, 0x9c, 0x79, 0x61, 0x95, 0x9c, + 0x60, 0x56, 0x8d, 0x35, 0x00, 0xc5, 0x8b, 0xe6, 0x02, 0x0f, 0x26, 0x39, + 0x7b, 0x93, 0x94, 0xb1, 0xcd, 0xde, 0xed, 0xfa, 0x2a, 0x4b, 0x63, 0xa8, + 0x1b, 0x31, 0x43, 0x5e, 0x69, 0x7c, 0xd6, 0x15, 0x35, 0x9c, 0xa2, 0xd7, + 0xdf, 0x0e, 0x1a, 0x20, 0x50, 0xf5, 0x02, 0x21, 0x30, 0x35, 0x3c, 0x60, + 0x71, 0xad, 0xd0, 0xe3, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x10, 0x17, 0x1d, 0x22, 0x2d}; +const uint8_t expected_signature_87[] = { + 0xdf, 0xe6, 0xe1, 0xa5, 0x20, 0xc1, 0xac, 0x98, 0x55, 0x2c, 0xf2, 0x13, + 0x65, 0x42, 0xe2, 0xb0, 0x77, 0x5f, 0x15, 0x00, 0x8f, 0x14, 0x48, 0xa1, + 0xe3, 0xee, 0x81, 0x35, 0x15, 0x34, 0xad, 0x6e, 0x60, 0x85, 0x00, 0xf8, + 0x18, 0x53, 0x0d, 0xa0, 0xc5, 0x41, 0xc4, 0x48, 0x09, 0x1b, 0x34, 0x0c, + 0x0e, 0xcf, 0xc6, 0x3d, 0x38, 0x78, 0x8b, 0x69, 0xe5, 0x6f, 0x4d, 0x43, + 0xfa, 0xa6, 0x75, 0x26, 0x8a, 0x75, 0x97, 0x10, 0x6a, 0x1f, 0x3c, 0xa6, + 0x94, 0xa9, 0x93, 0x8f, 0xe5, 0x62, 0xbf, 0x94, 0xe4, 0xd0, 0x0d, 0x11, + 0x4d, 0x03, 0xe2, 0xd8, 0xdf, 0x68, 0xb7, 0x87, 0x62, 0xc9, 0xdc, 0xc9, + 0x36, 0x4f, 0xcc, 0xd1, 0xa4, 0xae, 0x7e, 0xa4, 0xb9, 0xaf, 0xaf, 0xf0, + 0x8a, 0xe6, 0xff, 0x83, 0xe7, 0x54, 0x22, 0x6e, 0x3f, 0x2e, 0xa0, 0x4f, + 0xa8, 0x31, 0x53, 0xf3, 0x62, 0xeb, 0x04, 0xfa, 0xd1, 0x57, 0x39, 0x43, + 0xf9, 0xe0, 0x31, 0x12, 0x45, 0x09, 0x8b, 0x9e, 0x1e, 0x7a, 0x2b, 0x85, + 0xee, 0xdd, 0xe8, 0x1e, 0xd7, 0xc0, 0x17, 0xb4, 0xd2, 0xdc, 0x36, 0xa9, + 0xe4, 0x49, 0x88, 0xbf, 0x71, 0x43, 0x9d, 0x3e, 0xd2, 0x10, 0xe7, 0x82, + 0xb5, 0xfe, 0xdd, 0x42, 0xc8, 0x1b, 0x11, 0xf6, 0x52, 0x23, 0x98, 0x83, + 0x48, 0xec, 0xec, 0x70, 0x8b, 0xe7, 0x49, 0x9a, 0xd7, 0xd9, 0x7b, 0x47, + 0x4e, 0xe2, 0x5e, 0x17, 0x1a, 0xa0, 0x0e, 0x60, 0x85, 0x3a, 0x30, 0x8c, + 0x1c, 0x26, 0xb4, 0xe1, 0xb5, 0x2b, 0x48, 0xf4, 0xb8, 0x93, 0x2f, 0x79, + 0x3a, 0x1e, 0xb6, 0x3b, 0x07, 0x3b, 0x1e, 0x15, 0xd7, 0x85, 0x5e, 0xd4, + 0x06, 0x0e, 0xcd, 0x6a, 0x93, 0x3a, 0x93, 0x29, 0x6a, 0xbe, 0x68, 0x8a, + 0xb6, 0xb8, 0xfa, 0xc5, 0x63, 0x48, 0x98, 0x10, 0x6d, 0xd9, 0xd3, 0x5b, + 0x29, 0x5f, 0x93, 0x90, 0x08, 0x1c, 0x1a, 0x15, 0x7b, 0x0a, 0x59, 0x9d, + 0x64, 0x24, 0x45, 0xb6, 0xd3, 0x7b, 0xc1, 0x5d, 0x74, 0x1f, 0x0b, 0x8e, + 0x18, 0xf2, 0x92, 0x8e, 0xd4, 0x7f, 0x72, 0x5c, 0x98, 0x1f, 0x8b, 0xa5, + 0xb8, 0xf4, 0x7e, 0x12, 0x6a, 0x93, 0xb9, 0xb5, 0xf1, 0xda, 0x97, 0x75, + 0x4f, 0x56, 0x80, 0x88, 0x64, 0x2b, 0xe0, 0x59, 0xcd, 0x5e, 0x91, 0x64, + 0x9c, 0x0c, 0xa8, 0xdd, 0xac, 0xcb, 0xf3, 0x48, 0x3b, 0x5c, 0xc4, 0xc5, + 0xb9, 0x9a, 0x0b, 0x8e, 0x5d, 0x9a, 0xd5, 0xb7, 0xf0, 0xd4, 0x07, 0x48, + 0xb9, 0x63, 0x02, 0x87, 0x8d, 0xae, 0x7e, 0x03, 0x33, 0x4f, 0x86, 0x15, + 0x1b, 0x3b, 0xdf, 0xda, 0xce, 0xd3, 0x1e, 0xc0, 0x76, 0xb5, 0x1c, 0xdd, + 0xb8, 0x32, 0x87, 0x7d, 0x59, 0x18, 0x72, 0x0c, 0xde, 0x8f, 0x63, 0x2d, + 0x38, 0xf2, 0xe9, 0xc2, 0x81, 0xed, 0xfa, 0x2d, 0x61, 0xef, 0x48, 0xdb, + 0xa2, 0xeb, 0xfe, 0x52, 0x31, 0x1e, 0x21, 0x0a, 0x08, 0xf6, 0x02, 0xd3, + 0xc0, 0x32, 0x3b, 0x6b, 0x2f, 0x64, 0xc4, 0xb3, 0x4b, 0xfe, 0x69, 0x78, + 0xbf, 0x20, 0x62, 0x07, 0x77, 0xdf, 0x2c, 0x18, 0x53, 0x61, 0x8e, 0x05, + 0x01, 0x86, 0xab, 0xab, 0xec, 0x18, 0x8c, 0x15, 0x63, 0x1f, 0xe9, 0x99, + 0xb2, 0x35, 0x77, 0xe1, 0x58, 0xf1, 0xa9, 0x4d, 0x1a, 0xb9, 0x8c, 0x30, + 0x63, 0x6f, 0x9e, 0x7d, 0x4e, 0xcf, 0xb5, 0x6c, 0xf3, 0xe4, 0xdc, 0xab, + 0xf9, 0xae, 0x58, 0xf8, 0x1d, 0x08, 0x7b, 0x73, 0x82, 0x58, 0xc8, 0x67, + 0x48, 0x1a, 0x5e, 0x3d, 0xdb, 0xac, 0x1b, 0x1b, 0xef, 0xeb, 0xa4, 0xe5, + 0x67, 0x48, 0x76, 0xd1, 0x96, 0x4f, 0x6c, 0x7d, 0x06, 0x8c, 0x02, 0x86, + 0x95, 0x83, 0xb6, 0x9b, 0x5e, 0x9a, 0xb5, 0x85, 0xc0, 0x4f, 0x13, 0x1c, + 0x32, 0xf8, 0x29, 0xdf, 0x47, 0x85, 0xdb, 0xe4, 0x37, 0xdc, 0xd8, 0x04, + 0x18, 0xdd, 0xca, 0x97, 0xdd, 0x67, 0x13, 0xbe, 0x74, 0x95, 0xdc, 0xd0, + 0xcc, 0xe6, 0xb5, 0xa5, 0x12, 0x9b, 0x23, 0x4f, 0x41, 0x8c, 0xcc, 0x95, + 0xf4, 0xb0, 0x5f, 0x2a, 0xc4, 0xbf, 0x88, 0xda, 0x55, 0xcb, 0x13, 0x93, + 0x22, 0x60, 0x51, 0x43, 0xc7, 0x9a, 0x2c, 0xfa, 0xb2, 0x59, 0xc1, 0xe6, + 0x8a, 0xa4, 0xb8, 0xfb, 0xd3, 0x31, 0x1d, 0xc7, 0x88, 0xdc, 0xbc, 0xe9, + 0xba, 0xe7, 0xdc, 0xe3, 0xdd, 0x90, 0x96, 0xb4, 0xb4, 0x0a, 0xc1, 0x07, + 0x31, 0x3f, 0xdb, 0xc5, 0x4d, 0x73, 0x58, 0x86, 0x15, 0x37, 0x07, 0x86, + 0x03, 0x17, 0x16, 0x18, 0x15, 0xb9, 0x26, 0x35, 0x8a, 0x43, 0x22, 0xae, + 0x21, 0x52, 0x05, 0x4e, 0x5c, 0x3f, 0x3e, 0xb9, 0x2a, 0x19, 0x13, 0xfd, + 0x31, 0x47, 0x6a, 0x74, 0xaa, 0xb9, 0xc6, 0x2c, 0x13, 0x8c, 0x21, 0xc4, + 0x8d, 0x00, 0xf4, 0x24, 0xf2, 0xb7, 0xd3, 0x13, 0xad, 0x29, 0x5e, 0x50, + 0x0b, 0x0e, 0x9f, 0x9a, 0xb7, 0xf6, 0x9e, 0xba, 0x12, 0x23, 0x84, 0x8c, + 0xbe, 0x2c, 0x14, 0x1e, 0xe6, 0x79, 0x15, 0x20, 0x2d, 0x32, 0x08, 0xd8, + 0x1c, 0x87, 0x1b, 0xa8, 0xc0, 0xbb, 0x85, 0xa9, 0x71, 0x30, 0x5e, 0x39, + 0x48, 0x87, 0xdc, 0x3d, 0x03, 0x29, 0x19, 0xd1, 0xd4, 0x21, 0x3a, 0x53, + 0x2d, 0x5e, 0x78, 0xff, 0x94, 0x4b, 0x91, 0xa6, 0xb5, 0xe5, 0x42, 0x56, + 0x67, 0x6a, 0x0e, 0xf3, 0x2d, 0x6a, 0x4e, 0xd7, 0x3a, 0x81, 0xb1, 0x4d, + 0x0b, 0x66, 0x5f, 0x43, 0x28, 0x7c, 0x75, 0x8b, 0x2b, 0x99, 0x24, 0xc2, + 0x5e, 0x8c, 0x22, 0xf0, 0xd5, 0xb3, 0xfc, 0x86, 0x62, 0xf3, 0xd2, 0x6c, + 0xa7, 0x48, 0x04, 0x44, 0x5d, 0x93, 0x74, 0x37, 0x16, 0x2c, 0x19, 0x12, + 0x57, 0x49, 0xef, 0xd5, 0xd6, 0x92, 0xdc, 0x51, 0xf8, 0x55, 0x3a, 0xc0, + 0x0b, 0xdf, 0x41, 0xb5, 0x01, 0x59, 0x7e, 0x85, 0x65, 0xdb, 0x44, 0xbd, + 0x04, 0x96, 0x1a, 0xd4, 0x6e, 0x22, 0x54, 0x92, 0xdb, 0xc7, 0xc5, 0x3a, + 0xdf, 0x0c, 0xf4, 0x1b, 0xdc, 0x14, 0xf6, 0x91, 0x9c, 0xbe, 0xf8, 0x8e, + 0x70, 0xd1, 0x3a, 0x0e, 0x58, 0xe6, 0xb9, 0xd3, 0xaa, 0xa2, 0x70, 0xba, + 0xdd, 0x16, 0x13, 0x19, 0xd1, 0x96, 0x78, 0x04, 0x2f, 0xd7, 0x38, 0x8c, + 0x35, 0x1f, 0xfc, 0x58, 0xa4, 0x4c, 0xa9, 0x9a, 0xae, 0x13, 0x3b, 0xc1, + 0x20, 0x4b, 0x66, 0x0f, 0x72, 0x42, 0x0a, 0x53, 0x84, 0x54, 0x71, 0x06, + 0xdb, 0x85, 0x8f, 0x40, 0xa6, 0x09, 0xf7, 0x24, 0xc4, 0x35, 0xf7, 0x1d, + 0xd4, 0x3d, 0x54, 0x75, 0xaf, 0xc4, 0x78, 0x0f, 0xce, 0xe0, 0x0c, 0x90, + 0x0f, 0xd5, 0x2e, 0x61, 0xf7, 0x58, 0xaa, 0xf0, 0xc7, 0x37, 0x5a, 0x59, + 0x1f, 0x8a, 0x03, 0x98, 0x43, 0xb7, 0x27, 0x78, 0x4e, 0x44, 0x5a, 0xb5, + 0x29, 0xf5, 0xab, 0x9e, 0xb7, 0x2a, 0xc4, 0xa3, 0x03, 0x00, 0xe3, 0x28, + 0x57, 0xc9, 0x2a, 0x98, 0xb8, 0xa1, 0x45, 0x1d, 0xfa, 0x6e, 0xb3, 0x0d, + 0x42, 0x5a, 0xb6, 0xb1, 0x0e, 0x5c, 0xbe, 0x82, 0xe2, 0x36, 0x40, 0x4b, + 0x05, 0x28, 0xd9, 0xbc, 0x27, 0xd6, 0x77, 0x00, 0xc9, 0x29, 0x6a, 0xd6, + 0x19, 0x8f, 0x8d, 0xda, 0xe1, 0xc3, 0x8b, 0x69, 0x71, 0xd0, 0xf7, 0xc8, + 0x33, 0xef, 0xe6, 0x23, 0x6b, 0xcb, 0x00, 0x56, 0x0a, 0x9b, 0x9d, 0x60, + 0x3a, 0xd3, 0xad, 0xd9, 0x5c, 0x6a, 0x7d, 0xab, 0x35, 0x71, 0x93, 0xc5, + 0xf2, 0x6a, 0x38, 0x0e, 0xfb, 0xd9, 0x9b, 0xa5, 0xda, 0x52, 0x45, 0xef, + 0x93, 0x94, 0x5b, 0x08, 0x8c, 0x07, 0xab, 0x2e, 0x99, 0x88, 0x77, 0xb5, + 0x15, 0x66, 0x7f, 0x0e, 0xfa, 0xb0, 0x29, 0xe4, 0x88, 0xd9, 0xdd, 0x22, + 0xaf, 0x7a, 0x4e, 0xb5, 0xd0, 0x62, 0x85, 0x27, 0x33, 0xf1, 0xb7, 0x34, + 0xb1, 0xe6, 0xda, 0x9f, 0x3c, 0xfe, 0xf5, 0xd4, 0xef, 0x56, 0x48, 0x93, + 0x7a, 0x54, 0xa2, 0x7f, 0x07, 0xea, 0x31, 0xb8, 0x8b, 0xca, 0xb9, 0xdb, + 0x1e, 0x2b, 0xb5, 0x16, 0xe6, 0x0e, 0xd9, 0x3f, 0x7c, 0xf0, 0xc2, 0x3e, + 0x57, 0x64, 0x60, 0x97, 0xfb, 0xdf, 0x8c, 0x3e, 0x56, 0x22, 0x92, 0x2a, + 0xb2, 0x21, 0x00, 0x0a, 0x75, 0x89, 0x68, 0xe7, 0x51, 0xa3, 0x63, 0x05, + 0xe1, 0x6f, 0x1e, 0x1e, 0x80, 0xa2, 0x4b, 0x5d, 0xb7, 0xf4, 0xb7, 0x45, + 0x85, 0x00, 0x84, 0x6e, 0xbe, 0x0b, 0x67, 0xbf, 0x21, 0x06, 0x5a, 0x56, + 0x79, 0xe9, 0x6b, 0x0e, 0x72, 0x19, 0x2d, 0x09, 0x78, 0xd5, 0x5e, 0xc2, + 0x32, 0xee, 0x29, 0xd4, 0x7a, 0x65, 0xc7, 0xfe, 0x16, 0x86, 0xd2, 0x29, + 0x71, 0xe5, 0x91, 0x0e, 0x3e, 0x86, 0xd5, 0x00, 0xc4, 0xfc, 0xd9, 0xae, + 0xd3, 0x7c, 0x13, 0xfd, 0x62, 0xce, 0x0c, 0xb2, 0xe5, 0x1f, 0x6d, 0xed, + 0x55, 0x6f, 0xc1, 0xaa, 0xa1, 0x74, 0x59, 0x46, 0x83, 0xd5, 0x5d, 0x71, + 0x17, 0x13, 0x1d, 0x0b, 0x25, 0xfb, 0x0a, 0xcd, 0x67, 0xfe, 0x57, 0x93, + 0xc2, 0x71, 0x55, 0x6c, 0x68, 0xfa, 0x40, 0xdb, 0xdd, 0xce, 0xd5, 0x5c, + 0xce, 0x0a, 0x1d, 0xfa, 0x19, 0x30, 0xe2, 0x2b, 0x63, 0x98, 0x16, 0x2c, + 0x67, 0x69, 0x55, 0xe5, 0xc1, 0x6c, 0x6e, 0xb7, 0x92, 0x6a, 0xbb, 0x10, + 0xd3, 0x13, 0x2e, 0x73, 0x91, 0x74, 0xcb, 0x9f, 0x5c, 0x7f, 0x5c, 0x48, + 0x58, 0x36, 0x13, 0x47, 0xf7, 0x49, 0xae, 0x90, 0x15, 0x53, 0xb5, 0xe6, + 0x37, 0xfb, 0x81, 0x47, 0xb4, 0x69, 0x84, 0xca, 0x95, 0xab, 0x19, 0x2a, + 0x28, 0xc2, 0x8a, 0xf1, 0xcd, 0xf9, 0x3e, 0xd3, 0xaf, 0xe1, 0x75, 0xf7, + 0x94, 0x74, 0x1c, 0xf5, 0x32, 0xcf, 0x70, 0xbd, 0x69, 0xcc, 0xa8, 0x3c, + 0xca, 0x59, 0x53, 0xfa, 0xcb, 0xe7, 0xb6, 0x36, 0x70, 0xea, 0xe2, 0x84, + 0xfa, 0x5e, 0xbd, 0xd7, 0x59, 0x3d, 0x21, 0xc6, 0x9f, 0x5c, 0x1f, 0xa6, + 0xa9, 0xf1, 0xd3, 0x26, 0x9e, 0xff, 0xbc, 0x81, 0xfe, 0xbe, 0xee, 0x64, + 0xd9, 0x63, 0x94, 0x4b, 0x15, 0xd8, 0x95, 0xaa, 0xec, 0x10, 0xc9, 0xe2, + 0xe1, 0x05, 0x37, 0x64, 0xc4, 0xb0, 0x2e, 0xa5, 0x0e, 0x4c, 0x2d, 0x03, + 0x53, 0xf1, 0x93, 0x77, 0x9d, 0x46, 0x14, 0x67, 0x48, 0x5f, 0xad, 0x1b, + 0xdc, 0xb9, 0x74, 0xa2, 0x6c, 0xfc, 0xd2, 0xa0, 0x1f, 0x43, 0x89, 0x15, + 0xc5, 0x0c, 0xb0, 0x9e, 0x1e, 0xc2, 0xd6, 0x44, 0xd9, 0x6e, 0xfc, 0xb4, + 0x9c, 0x95, 0x90, 0xcd, 0xc3, 0x17, 0x1c, 0x6a, 0xce, 0x03, 0x56, 0x9f, + 0xe7, 0xcd, 0x7e, 0xe7, 0xa2, 0x0c, 0x2b, 0x0d, 0x59, 0xb0, 0xc9, 0x4c, + 0x6e, 0x33, 0x6d, 0x43, 0xc4, 0x3a, 0x10, 0x24, 0x03, 0x3e, 0x09, 0xb6, + 0x86, 0x13, 0xba, 0x18, 0x19, 0xd3, 0xff, 0xeb, 0xa5, 0x25, 0x8f, 0x6f, + 0xc8, 0xe6, 0x96, 0xa4, 0xd2, 0x66, 0x40, 0x81, 0x79, 0xe8, 0x39, 0x18, + 0x41, 0x02, 0x66, 0x5c, 0x30, 0x5f, 0x58, 0x9d, 0x35, 0x16, 0xc6, 0x96, + 0xa8, 0x68, 0xbc, 0x09, 0x83, 0x17, 0x2c, 0x5f, 0x5e, 0xd0, 0x1d, 0xb0, + 0x48, 0x5e, 0xcf, 0x91, 0x16, 0x4d, 0xa0, 0xba, 0xbc, 0x61, 0xa8, 0x3f, + 0x30, 0x09, 0xbb, 0xa3, 0x12, 0xcd, 0xdc, 0x29, 0xf7, 0xb0, 0xad, 0x05, + 0x17, 0xd6, 0xd3, 0x16, 0xfb, 0xe5, 0x99, 0xf4, 0x71, 0x62, 0xa3, 0x45, + 0x45, 0xc7, 0x9b, 0xaa, 0x45, 0xd3, 0x35, 0xfe, 0xfb, 0x63, 0xaf, 0xe7, + 0x85, 0x31, 0xc9, 0x66, 0x26, 0xa9, 0xda, 0x8c, 0xc6, 0xf6, 0xd5, 0xdf, + 0xb1, 0xa9, 0xf1, 0xb6, 0x3d, 0x92, 0xae, 0x4d, 0xbc, 0x74, 0x7d, 0x76, + 0x5a, 0x59, 0x8c, 0x87, 0xff, 0x95, 0x2f, 0x67, 0x37, 0x30, 0x1a, 0xc1, + 0x23, 0x2e, 0x0c, 0xaa, 0x80, 0x1c, 0xf3, 0xa3, 0x74, 0x94, 0xb2, 0xda, + 0x1a, 0xb8, 0x46, 0xec, 0x30, 0x76, 0xf4, 0xdf, 0xfb, 0x00, 0xb3, 0x6f, + 0x86, 0xc1, 0xc5, 0x3a, 0x5d, 0x11, 0x14, 0x87, 0xeb, 0x30, 0xd8, 0x33, + 0x18, 0x00, 0x01, 0x76, 0x43, 0x82, 0xcd, 0x1c, 0x36, 0x54, 0xd2, 0x64, + 0x5b, 0xfb, 0x93, 0xca, 0x20, 0x1d, 0xa3, 0x20, 0x99, 0xc3, 0x8e, 0x5c, + 0x82, 0xfc, 0x56, 0x07, 0x41, 0x4b, 0x4f, 0x54, 0xc7, 0xb5, 0xe8, 0x6d, + 0x7e, 0xd8, 0x8a, 0x56, 0xb4, 0x76, 0x1e, 0xd3, 0x82, 0x97, 0xdd, 0x2b, + 0xd9, 0x80, 0xb7, 0xb6, 0xeb, 0x3d, 0xe5, 0xe0, 0x20, 0x27, 0x8c, 0xf0, + 0xd6, 0x14, 0xc7, 0xcd, 0x79, 0xbc, 0xa0, 0x21, 0x85, 0xc3, 0x02, 0xae, + 0x73, 0xc4, 0x0a, 0x39, 0x1a, 0x98, 0x61, 0xc3, 0x86, 0xd8, 0x97, 0x67, + 0x87, 0xe9, 0x56, 0x0b, 0x61, 0xa6, 0x7e, 0x07, 0xfb, 0x0a, 0x8b, 0xd1, + 0x90, 0xbd, 0x39, 0x22, 0xdb, 0xc2, 0x7f, 0xaa, 0x79, 0xb7, 0x39, 0x09, + 0xc1, 0x69, 0xdb, 0xe2, 0x7f, 0xec, 0xde, 0x80, 0x7a, 0x6c, 0xde, 0x76, + 0xa4, 0xe8, 0xe0, 0x8d, 0x71, 0xfa, 0x62, 0xf0, 0x2e, 0x7b, 0xf4, 0xce, + 0x65, 0x18, 0x42, 0xde, 0x92, 0x1b, 0xdc, 0xc9, 0xa7, 0x8d, 0xa5, 0x91, + 0x0f, 0xa5, 0x1b, 0x89, 0xcf, 0x29, 0x10, 0x1d, 0x94, 0x78, 0x1b, 0xea, + 0x79, 0x35, 0x62, 0xd4, 0x29, 0xe6, 0x59, 0x8c, 0xc1, 0xd2, 0xf3, 0x32, + 0x71, 0x09, 0xce, 0x51, 0xd7, 0x14, 0x29, 0x92, 0xbf, 0xdf, 0x9a, 0x69, + 0xda, 0x61, 0x03, 0x0f, 0xa2, 0x0a, 0xab, 0x57, 0x1c, 0xca, 0xab, 0x42, + 0x63, 0x63, 0x1e, 0x35, 0x5d, 0x8d, 0xba, 0x6f, 0x4b, 0x6b, 0x5e, 0x7c, + 0xc0, 0x1e, 0xb7, 0xf4, 0x65, 0xbd, 0x13, 0x1c, 0xf2, 0xa9, 0x73, 0x38, + 0xc3, 0x47, 0xc9, 0x32, 0xf0, 0x30, 0x57, 0x05, 0x42, 0x52, 0xac, 0x72, + 0xee, 0x9f, 0x4e, 0x21, 0xbf, 0x38, 0x19, 0x6d, 0x48, 0xec, 0x97, 0xcb, + 0x70, 0x9e, 0xee, 0xb3, 0xa1, 0xaa, 0xa6, 0x7e, 0xe9, 0x16, 0xdf, 0xcd, + 0x1c, 0x56, 0xcf, 0xf0, 0x9f, 0x4d, 0xd1, 0x8c, 0x14, 0x50, 0x5d, 0x23, + 0x96, 0xe0, 0x1f, 0x61, 0x79, 0xbf, 0x44, 0xfd, 0xa2, 0x31, 0xf7, 0x4c, + 0x0c, 0x8d, 0x8c, 0x1b, 0xbf, 0x8d, 0x45, 0xbf, 0x0b, 0xd8, 0xfb, 0x6f, + 0xff, 0x15, 0xc0, 0x44, 0x7c, 0xb9, 0xb8, 0xf9, 0xef, 0x0d, 0x79, 0x11, + 0x3b, 0x79, 0xd2, 0x52, 0x89, 0x5a, 0xcd, 0x0f, 0x10, 0x92, 0x42, 0xfe, + 0xcf, 0x0a, 0x11, 0x8a, 0x8a, 0xda, 0xee, 0xc8, 0x6b, 0xd9, 0xab, 0xec, + 0xb4, 0x25, 0x6f, 0x8d, 0x68, 0x26, 0xe8, 0xdd, 0xf5, 0xa4, 0xe8, 0x65, + 0x37, 0x03, 0xb0, 0xad, 0x73, 0x3b, 0x4d, 0x74, 0x57, 0x7f, 0x0f, 0x6c, + 0xb0, 0x5d, 0x59, 0x80, 0x13, 0xa1, 0x6c, 0xb0, 0xed, 0x26, 0xec, 0x79, + 0x50, 0x5f, 0x5c, 0xb7, 0xa6, 0xae, 0xe8, 0x0a, 0x6d, 0x55, 0x9a, 0x7f, + 0x59, 0x23, 0xa3, 0x7e, 0x84, 0x7b, 0x3b, 0xfc, 0xde, 0xe1, 0xd9, 0x7c, + 0xd6, 0x87, 0xb3, 0x0e, 0xdb, 0xc1, 0x8c, 0x5e, 0x77, 0xb7, 0x23, 0xd7, + 0x14, 0xd4, 0x23, 0xb4, 0xac, 0x45, 0xbf, 0xfe, 0x40, 0x20, 0x4d, 0x91, + 0x20, 0x94, 0xbd, 0x58, 0xb1, 0x99, 0x69, 0xaf, 0x31, 0x68, 0xbd, 0x61, + 0x5e, 0x87, 0x81, 0x54, 0x4e, 0x2d, 0x03, 0xc2, 0xe2, 0xcd, 0xdc, 0x59, + 0xe5, 0x35, 0xcf, 0xb8, 0xfc, 0x65, 0xed, 0x46, 0xb3, 0x92, 0xe7, 0xf8, + 0x3a, 0x32, 0xaa, 0x0e, 0x5a, 0x82, 0x58, 0x4e, 0x77, 0xd8, 0x33, 0xc9, + 0xb0, 0x3e, 0xad, 0xa5, 0x92, 0xe9, 0xa9, 0x8c, 0x00, 0x72, 0x8f, 0xdc, + 0x77, 0x9d, 0x5c, 0x97, 0xd6, 0x58, 0x20, 0x1e, 0xf4, 0x55, 0x2d, 0xc0, + 0x30, 0xf0, 0x66, 0xda, 0x2d, 0x11, 0xac, 0xd4, 0x2d, 0xd5, 0x25, 0x42, + 0x1d, 0xce, 0x49, 0xb5, 0x95, 0x79, 0x9b, 0x6c, 0x65, 0xe0, 0x8a, 0xc5, + 0x9f, 0x75, 0xe3, 0xe6, 0xf8, 0xa6, 0x88, 0xd6, 0x93, 0x70, 0x4f, 0x89, + 0x94, 0x74, 0xbd, 0xef, 0xc2, 0x1a, 0x55, 0x74, 0x37, 0x44, 0x85, 0x1e, + 0xa9, 0xbb, 0x3f, 0x15, 0xc7, 0x84, 0x80, 0xa5, 0xab, 0xc3, 0x91, 0x8e, + 0xd6, 0x32, 0x46, 0x0d, 0xfa, 0xd1, 0x19, 0xd1, 0xfc, 0x02, 0xe2, 0x20, + 0xa6, 0xa9, 0xf7, 0xf4, 0xcc, 0x5b, 0x54, 0x4f, 0x4a, 0x73, 0x35, 0xda, + 0xf0, 0x31, 0x81, 0x1a, 0x82, 0xe7, 0xd4, 0xc8, 0xb4, 0x1d, 0x70, 0xa9, + 0x5d, 0x67, 0xb9, 0x7d, 0x4b, 0xcd, 0xa4, 0x81, 0xf9, 0xb2, 0x38, 0x07, + 0x16, 0xd5, 0x28, 0x82, 0xb9, 0x76, 0x5b, 0xa1, 0x09, 0x7a, 0xe7, 0x2a, + 0xcf, 0xc0, 0x3d, 0x2a, 0x42, 0x9a, 0xf3, 0xc8, 0x64, 0x15, 0x7c, 0x94, + 0xd0, 0x97, 0xee, 0x34, 0xb6, 0xf0, 0xb2, 0xba, 0x7e, 0xb2, 0xbb, 0x4e, + 0xbf, 0x88, 0xd0, 0x6b, 0xc5, 0x9c, 0xb9, 0xf2, 0x7d, 0xbf, 0x5d, 0x87, + 0xbc, 0x36, 0x4a, 0xd1, 0x1b, 0x6f, 0x40, 0x09, 0xba, 0x26, 0x51, 0xd6, + 0xc0, 0xaf, 0x27, 0xce, 0x27, 0x8d, 0x93, 0xa8, 0x6c, 0x91, 0xe7, 0x91, + 0x42, 0xc0, 0x68, 0x36, 0x5b, 0xd5, 0x56, 0x4c, 0xe2, 0x77, 0xc3, 0xac, + 0x56, 0xe3, 0x1c, 0xc2, 0xf9, 0x78, 0x02, 0x39, 0x7d, 0xed, 0x18, 0x2a, + 0x01, 0x48, 0xe6, 0xf6, 0x7e, 0x34, 0x50, 0xf4, 0x57, 0x56, 0x93, 0xdb, + 0x85, 0x1b, 0x1e, 0x1a, 0x6f, 0x3e, 0x07, 0x3c, 0xad, 0x3f, 0x8d, 0x75, + 0x53, 0xc3, 0x20, 0x72, 0x93, 0x28, 0xd2, 0x86, 0xc8, 0xa5, 0x90, 0xf2, + 0x5f, 0x13, 0xd5, 0xa5, 0xbe, 0x88, 0x9e, 0x9a, 0x57, 0x2c, 0x53, 0x3f, + 0x11, 0x25, 0x00, 0x00, 0x4a, 0x16, 0x8d, 0xd3, 0x3f, 0x2d, 0x3d, 0x88, + 0xbb, 0x4c, 0x4f, 0x9a, 0xb9, 0x97, 0x5f, 0xed, 0x71, 0xa9, 0x68, 0xd9, + 0x4a, 0x14, 0x24, 0xc7, 0xbe, 0xff, 0x85, 0x57, 0xa3, 0x21, 0xe3, 0x21, + 0x79, 0x1f, 0xd0, 0xbb, 0xb7, 0x73, 0xde, 0x60, 0x02, 0x4b, 0x8f, 0x7d, + 0xb3, 0xb3, 0x8a, 0xda, 0x4c, 0xf4, 0xb8, 0xf1, 0x31, 0xff, 0x32, 0x7b, + 0xd8, 0xfa, 0xb1, 0xcb, 0xb4, 0x58, 0xf5, 0xc8, 0x64, 0xdf, 0xfe, 0x3d, + 0x89, 0x52, 0x5c, 0x52, 0x95, 0xf3, 0xba, 0x0d, 0x1d, 0x2c, 0xc4, 0xf7, + 0x3c, 0x3b, 0x6f, 0x8e, 0xc7, 0xab, 0xad, 0x3d, 0x3d, 0x95, 0x9b, 0xc7, + 0x71, 0x36, 0xae, 0x08, 0xc3, 0x08, 0x79, 0xfa, 0x24, 0xee, 0xd9, 0xf9, + 0x63, 0xc7, 0xd9, 0x16, 0x19, 0x8e, 0x0d, 0xaf, 0x52, 0x87, 0x86, 0x7d, + 0xec, 0xe5, 0xea, 0x5a, 0xda, 0x86, 0x9d, 0x0e, 0x50, 0x53, 0x8c, 0x24, + 0xa8, 0x69, 0xc4, 0xf3, 0x85, 0x7b, 0x34, 0x67, 0x19, 0x35, 0xec, 0xd4, + 0xd4, 0x50, 0xe0, 0xe6, 0xe9, 0x29, 0x5b, 0x92, 0xee, 0xba, 0xa9, 0xef, + 0xf6, 0x35, 0x23, 0x8b, 0xdb, 0x48, 0x32, 0x25, 0x41, 0xf3, 0x55, 0x12, + 0x33, 0xc3, 0x6c, 0xed, 0x32, 0xe1, 0x64, 0x7a, 0x8d, 0xa2, 0x19, 0x5a, + 0x26, 0xf2, 0x83, 0xf1, 0xe4, 0x27, 0xdb, 0x67, 0xc3, 0x89, 0x37, 0xea, + 0x78, 0x19, 0xc6, 0xa3, 0x82, 0x84, 0x1c, 0xf3, 0x2b, 0xbe, 0xde, 0xba, + 0xe7, 0x60, 0x2e, 0xf5, 0x4e, 0xb6, 0x73, 0x29, 0xac, 0xc7, 0x55, 0xab, + 0x21, 0xe9, 0x95, 0x78, 0xd5, 0x8e, 0x27, 0xdc, 0x92, 0x5f, 0xc0, 0xcb, + 0xee, 0x66, 0x09, 0x0a, 0xfc, 0x94, 0x43, 0x44, 0x50, 0x35, 0x57, 0xf8, + 0x08, 0xf9, 0x97, 0xa2, 0x0e, 0xde, 0x81, 0xe1, 0xd1, 0xa0, 0x41, 0xfe, + 0xe6, 0x08, 0x6c, 0x98, 0x8c, 0x81, 0x46, 0x0e, 0xf9, 0x9a, 0x54, 0xfe, + 0xc3, 0x91, 0xe3, 0xd4, 0x46, 0xca, 0x52, 0xa2, 0x73, 0x9e, 0x4d, 0xa7, + 0xfd, 0xa1, 0x8e, 0x43, 0x28, 0xf5, 0xa3, 0xa2, 0x62, 0x20, 0x53, 0x62, + 0x05, 0x49, 0xba, 0x06, 0xe2, 0xeb, 0xba, 0xfb, 0x8e, 0xa0, 0x22, 0xc7, + 0xf9, 0xcc, 0x7f, 0x8b, 0xa8, 0x5d, 0x55, 0xd2, 0x24, 0xff, 0xdd, 0x2c, + 0xc1, 0xd0, 0x3d, 0xe4, 0x79, 0xea, 0xba, 0x62, 0xe5, 0xa2, 0x62, 0xf4, + 0x1f, 0xec, 0xb0, 0x07, 0xf2, 0x0d, 0x32, 0x84, 0x86, 0x81, 0x3d, 0x95, + 0xc1, 0x64, 0xfe, 0x9a, 0x3d, 0x8f, 0x4b, 0x6d, 0xfb, 0x0d, 0x42, 0xcf, + 0xbf, 0xdb, 0x51, 0xb2, 0x16, 0xa2, 0x35, 0xaa, 0xe7, 0x31, 0x54, 0xc2, + 0x87, 0xc6, 0xa5, 0x30, 0x71, 0x64, 0x65, 0xff, 0x41, 0x20, 0xb0, 0x83, + 0xdb, 0xb7, 0x95, 0xce, 0xd7, 0xcc, 0x7a, 0x77, 0xad, 0xb8, 0xb7, 0x4c, + 0xfc, 0x11, 0x05, 0x2b, 0xc4, 0xd4, 0xb6, 0x8b, 0xae, 0x13, 0xa5, 0x40, + 0x18, 0x6e, 0x0d, 0xe3, 0xc6, 0xb0, 0x81, 0x46, 0x46, 0x7e, 0x52, 0x0b, + 0x85, 0x4d, 0x98, 0xd9, 0x42, 0xdf, 0xde, 0x45, 0xc1, 0x5a, 0x33, 0x12, + 0x46, 0x26, 0xb3, 0x6f, 0xf2, 0x8b, 0x37, 0x6b, 0xfd, 0x08, 0xf4, 0x46, + 0x86, 0x89, 0x63, 0x63, 0x21, 0xe5, 0xa9, 0xb7, 0xd0, 0x09, 0x17, 0x52, + 0xee, 0xea, 0xdf, 0x97, 0xb7, 0x73, 0x2e, 0x54, 0x2c, 0x7b, 0x70, 0xd3, + 0xda, 0x26, 0x57, 0x1f, 0xb0, 0x19, 0xd9, 0x91, 0x18, 0x69, 0x75, 0x42, + 0x63, 0xcf, 0x6c, 0x8c, 0x98, 0x5e, 0x17, 0x99, 0x7e, 0x1d, 0xdc, 0x67, + 0x6d, 0x99, 0xd9, 0x02, 0x6e, 0x73, 0x90, 0x5a, 0x4f, 0x0a, 0xb4, 0x48, + 0xfb, 0xc5, 0xbd, 0xd2, 0x10, 0x05, 0xa6, 0x12, 0x68, 0x36, 0x28, 0x51, + 0x60, 0x1c, 0xa1, 0xe9, 0x90, 0x54, 0xa5, 0x53, 0xc3, 0x48, 0x9e, 0xd8, + 0x42, 0x52, 0x85, 0x0e, 0xff, 0xfe, 0xbf, 0xad, 0x3a, 0xa4, 0x57, 0x09, + 0x13, 0x38, 0x64, 0x15, 0x7c, 0xfd, 0xed, 0x91, 0x76, 0x44, 0x20, 0x84, + 0xd9, 0x90, 0xab, 0xfe, 0xfd, 0xd6, 0xab, 0xf1, 0xb3, 0x25, 0x21, 0x3d, + 0x97, 0x72, 0xb2, 0x95, 0xc5, 0x22, 0x80, 0xd9, 0x4a, 0x49, 0x9d, 0x99, + 0xc2, 0x4a, 0x9a, 0x59, 0xb3, 0x71, 0x75, 0x5b, 0xf9, 0x89, 0x7a, 0xdd, + 0xa9, 0xb3, 0xc3, 0xeb, 0x42, 0x91, 0xe2, 0x97, 0x30, 0x40, 0x48, 0x68, + 0x19, 0x3b, 0xf5, 0x7b, 0x4e, 0x33, 0x4b, 0x0c, 0xf3, 0xed, 0xda, 0x76, + 0x3f, 0xb0, 0x4b, 0x53, 0x85, 0x04, 0x33, 0x07, 0x53, 0xd8, 0x55, 0xa2, + 0xfb, 0x30, 0x2c, 0x66, 0xbd, 0x21, 0xf8, 0xfa, 0x20, 0x14, 0x9a, 0x0d, + 0x7f, 0xc9, 0x2f, 0x5b, 0x34, 0x29, 0x09, 0x16, 0xb5, 0x0a, 0x8d, 0xdf, + 0xa2, 0x84, 0x9a, 0xae, 0xe6, 0xa0, 0x50, 0x80, 0x31, 0x04, 0xd3, 0x0c, + 0x8f, 0xd1, 0x8a, 0xfd, 0xb4, 0xa5, 0xae, 0xf5, 0x3c, 0x62, 0xae, 0x45, + 0x70, 0xbb, 0x54, 0x62, 0xc8, 0x50, 0x71, 0x42, 0x85, 0xf6, 0x6f, 0xa0, + 0xf0, 0x10, 0x8a, 0x09, 0xbd, 0x71, 0x78, 0xa6, 0x5e, 0xe4, 0x03, 0x8f, + 0x3b, 0xd0, 0x5c, 0x37, 0x55, 0x1a, 0xc8, 0x57, 0x26, 0x62, 0x6c, 0xc4, + 0x67, 0x71, 0x9d, 0x97, 0xc0, 0xea, 0x35, 0x3e, 0x12, 0xd0, 0x2b, 0xc2, + 0x8f, 0x9e, 0xa6, 0x41, 0x48, 0x33, 0x83, 0x38, 0x37, 0x7e, 0xd4, 0xe3, + 0xee, 0x94, 0x8b, 0x81, 0xa4, 0x60, 0xdd, 0xdd, 0xc1, 0x8a, 0x7b, 0xda, + 0xa8, 0x46, 0xb8, 0x42, 0x3a, 0x25, 0xd6, 0x81, 0x89, 0x29, 0x21, 0xc2, + 0x0c, 0x5b, 0xfd, 0x3e, 0x8c, 0x65, 0x91, 0x52, 0xb3, 0x74, 0x1f, 0xd1, + 0x49, 0x7e, 0x1d, 0x59, 0x58, 0x96, 0xb5, 0xee, 0x32, 0xa4, 0xa8, 0x07, + 0x7c, 0xd1, 0x5b, 0x4b, 0xf8, 0x43, 0x5a, 0xa5, 0xcc, 0x60, 0xcc, 0x08, + 0x6a, 0x3c, 0x41, 0x66, 0x99, 0xe3, 0xa8, 0xe0, 0xb8, 0x87, 0xfc, 0x92, + 0xc0, 0x79, 0xc5, 0x3f, 0xd6, 0xc6, 0x8c, 0x01, 0xf4, 0xa5, 0x05, 0xad, + 0x51, 0xed, 0x04, 0xd7, 0x55, 0xc0, 0x73, 0x05, 0x0e, 0x73, 0xe5, 0x39, + 0x45, 0x5b, 0x95, 0x4a, 0x34, 0x07, 0x99, 0xdf, 0x4c, 0x35, 0xf5, 0x0c, + 0x27, 0x6d, 0xd1, 0x45, 0xf1, 0xfd, 0x24, 0xb7, 0xfe, 0xea, 0x11, 0x5d, + 0xa2, 0xc5, 0xa6, 0x81, 0x37, 0x1d, 0xc2, 0x31, 0x31, 0xfc, 0xe0, 0xf4, + 0xd7, 0xe9, 0x98, 0x8b, 0xe3, 0x70, 0x51, 0x62, 0xc8, 0x61, 0x6d, 0xec, + 0x75, 0x56, 0x71, 0xae, 0x88, 0xe0, 0x80, 0xf5, 0xb7, 0x85, 0x10, 0xb7, + 0x3d, 0x16, 0x78, 0x5f, 0x72, 0xab, 0x8f, 0x63, 0xc6, 0xd5, 0xa8, 0xc9, + 0x9c, 0xef, 0x8d, 0x9a, 0xc5, 0x4f, 0x63, 0xad, 0xc0, 0xf3, 0x1f, 0x69, + 0x0e, 0xce, 0x29, 0x92, 0xc1, 0x3b, 0xb0, 0xc5, 0xed, 0x0a, 0x7b, 0x92, + 0xd0, 0x4c, 0x9c, 0x82, 0xb0, 0x51, 0xf6, 0x33, 0x61, 0x3b, 0x76, 0x48, + 0x38, 0xf4, 0x7c, 0xaa, 0x52, 0x87, 0x15, 0x1a, 0xbe, 0xb8, 0xdc, 0x9b, + 0x16, 0xd2, 0x07, 0xf7, 0xf9, 0x74, 0xe0, 0xaf, 0x0e, 0x29, 0x05, 0xec, + 0x6c, 0x0e, 0x3b, 0xa7, 0xe7, 0xa4, 0xfc, 0xa4, 0xef, 0x57, 0x16, 0x7f, + 0x13, 0xbd, 0x8c, 0x42, 0x02, 0x55, 0x70, 0x56, 0xa5, 0xa9, 0x01, 0x29, + 0x12, 0x7d, 0x80, 0x46, 0x18, 0x8e, 0x39, 0x3f, 0x44, 0x55, 0xec, 0xef, + 0x60, 0x58, 0x7d, 0xce, 0x64, 0x8e, 0x9c, 0xea, 0xe4, 0x73, 0xd1, 0x48, + 0x9c, 0x3f, 0x92, 0xa0, 0x9a, 0x76, 0xa5, 0x5a, 0x13, 0x1f, 0x10, 0xb9, + 0xb7, 0xb1, 0xde, 0x49, 0x22, 0x58, 0xf4, 0x43, 0x5f, 0x03, 0x43, 0xc3, + 0x6c, 0xbf, 0x82, 0xaf, 0x88, 0x39, 0xfd, 0xb2, 0x28, 0x9b, 0x47, 0x3f, + 0x83, 0x3d, 0xd9, 0x7c, 0xf0, 0xc9, 0xc5, 0xa2, 0xb4, 0xd6, 0x0d, 0x59, + 0x51, 0x27, 0x60, 0x10, 0x5e, 0xbb, 0x18, 0xa6, 0x42, 0x4a, 0x9d, 0xc4, + 0x16, 0x0e, 0xb6, 0x57, 0x23, 0x03, 0x24, 0x27, 0xdc, 0x20, 0x56, 0x30, + 0x8b, 0x0f, 0xb6, 0xb7, 0x73, 0xf5, 0x36, 0x3e, 0xf6, 0x7a, 0x71, 0xa5, + 0x57, 0xcc, 0x6d, 0xc6, 0xf3, 0xdc, 0x35, 0xfb, 0x95, 0xf7, 0xa7, 0xd7, + 0x56, 0x38, 0xd4, 0x15, 0xe2, 0xd5, 0x6f, 0x70, 0x30, 0xc8, 0x7d, 0x8a, + 0x87, 0xe6, 0xd1, 0xe0, 0x50, 0x62, 0xde, 0xfa, 0x29, 0x40, 0x97, 0xa0, + 0x54, 0x63, 0x31, 0xd3, 0x08, 0x87, 0x0a, 0xdc, 0x6e, 0x5e, 0xab, 0x8d, + 0x16, 0xaf, 0x6e, 0x8b, 0x1a, 0x77, 0xf6, 0xd4, 0xe0, 0xbf, 0x59, 0xab, + 0xc7, 0xb0, 0x45, 0x18, 0xaa, 0xe6, 0x65, 0x6f, 0x7d, 0x13, 0xb2, 0xbf, + 0xb3, 0x66, 0x72, 0xfa, 0xfd, 0xee, 0xad, 0x07, 0x56, 0x51, 0x6a, 0xe2, + 0xff, 0xb2, 0xaf, 0x4d, 0xd1, 0xf2, 0x77, 0x35, 0x5e, 0x90, 0xcd, 0xe7, + 0xa8, 0x32, 0x4d, 0x9f, 0xbd, 0xa8, 0xce, 0xab, 0xf1, 0x49, 0x98, 0xb5, + 0x23, 0x5c, 0x62, 0x2d, 0x43, 0x31, 0x80, 0x87, 0xc2, 0xa8, 0xf5, 0xb9, + 0xb6, 0xae, 0x7f, 0x37, 0x13, 0xb8, 0x6b, 0x73, 0xf3, 0x56, 0x38, 0xa7, + 0x9b, 0x97, 0x69, 0x37, 0x00, 0xdc, 0xff, 0xfe, 0x58, 0xc9, 0x12, 0x47, + 0x75, 0x98, 0x1f, 0xad, 0xd8, 0xb5, 0xc8, 0x47, 0x4f, 0xd0, 0x72, 0x63, + 0x54, 0x25, 0x6c, 0x88, 0xc9, 0x9f, 0x3c, 0x82, 0xe0, 0xdd, 0x4c, 0xff, + 0x8e, 0xaf, 0x8f, 0x8e, 0xea, 0x84, 0x3f, 0x73, 0xdd, 0x9e, 0x18, 0x73, + 0x47, 0x70, 0xc7, 0xc7, 0x99, 0x65, 0xcf, 0xf3, 0xb6, 0x24, 0xed, 0x97, + 0x8f, 0xcd, 0x93, 0x1e, 0xff, 0x6e, 0x9c, 0xf1, 0x30, 0x14, 0x1a, 0x27, + 0x59, 0x6a, 0x0e, 0xf3, 0xe4, 0xfa, 0x1d, 0x65, 0xb5, 0x53, 0xe4, 0xab, + 0xb1, 0x3e, 0xe1, 0x91, 0xf4, 0x6d, 0x99, 0xca, 0x7d, 0x03, 0x08, 0x50, + 0xea, 0xa9, 0x39, 0x7f, 0x6d, 0xe7, 0x43, 0xfb, 0x64, 0xcc, 0x4b, 0x9e, + 0xa0, 0x26, 0xe4, 0x0e, 0xff, 0xb7, 0x11, 0x0a, 0x29, 0x50, 0x90, 0xd7, + 0x4d, 0x62, 0x9a, 0x4a, 0x23, 0xb7, 0xd3, 0x53, 0xde, 0x3a, 0xd1, 0xba, + 0xd3, 0x10, 0x59, 0xc6, 0xc5, 0x5e, 0xac, 0xf9, 0x61, 0x74, 0x54, 0xf4, + 0x27, 0x9f, 0x9a, 0x61, 0x13, 0xdc, 0xe5, 0x96, 0xe3, 0x95, 0x0d, 0xcc, + 0xbd, 0x81, 0x74, 0x79, 0x73, 0xef, 0x2e, 0x0b, 0x0f, 0x91, 0x65, 0x3c, + 0x26, 0x7c, 0x47, 0x10, 0x31, 0x0b, 0xfb, 0x41, 0x0c, 0xc2, 0xa8, 0xc4, + 0x0e, 0xbd, 0x0a, 0x8c, 0xa4, 0x80, 0x45, 0x57, 0x62, 0x0b, 0x4d, 0x44, + 0x5e, 0x59, 0x77, 0xfd, 0x3d, 0xf3, 0xd7, 0x92, 0x49, 0xc1, 0xcb, 0x8a, + 0x54, 0x56, 0x3b, 0xde, 0xcf, 0x16, 0x9a, 0x65, 0xbe, 0xac, 0x64, 0xe1, + 0xd4, 0xd4, 0x1e, 0xac, 0x6b, 0x4a, 0xad, 0xc4, 0x33, 0xac, 0xcb, 0x83, + 0xf4, 0x4d, 0xe8, 0xb6, 0xd7, 0x23, 0xd7, 0x71, 0x25, 0xa2, 0x25, 0x3d, + 0x7e, 0xf0, 0x3b, 0x7f, 0x61, 0x11, 0x56, 0xd4, 0x83, 0xc8, 0xc0, 0x29, + 0x38, 0x10, 0x73, 0xad, 0x6a, 0xb7, 0xb9, 0xd2, 0x2e, 0x9f, 0xae, 0x16, + 0x5e, 0xa6, 0x13, 0x1c, 0xc2, 0x17, 0x73, 0x43, 0x03, 0xdd, 0xa6, 0xaf, + 0x9a, 0x17, 0x31, 0xb8, 0x86, 0x97, 0xc2, 0xd6, 0xe6, 0xed, 0xd4, 0xe1, + 0x7d, 0xb9, 0xa6, 0x96, 0xc1, 0x4b, 0xcb, 0x11, 0x1e, 0xe1, 0xe0, 0xd2, + 0x28, 0x69, 0x68, 0x3b, 0x21, 0x17, 0x63, 0x0c, 0xc0, 0x49, 0x30, 0x22, + 0x3a, 0x59, 0x72, 0xe6, 0x47, 0xb4, 0xdc, 0xa8, 0x29, 0x1c, 0x89, 0xa6, + 0x3a, 0x77, 0x99, 0xea, 0x46, 0xce, 0x38, 0xda, 0x31, 0x88, 0xad, 0xe7, + 0x26, 0xce, 0xc6, 0x56, 0x04, 0x30, 0xfa, 0x01, 0xac, 0xbb, 0xe2, 0xb8, + 0x23, 0xe4, 0x9d, 0x4f, 0x77, 0x02, 0x00, 0x28, 0xf1, 0xe0, 0x19, 0x3f, + 0x22, 0x4f, 0x22, 0x69, 0x87, 0xc0, 0x4e, 0x26, 0x33, 0xfe, 0x6c, 0x70, + 0x56, 0x3b, 0x60, 0x5f, 0xfb, 0xf8, 0x43, 0xcf, 0x3f, 0xb9, 0xcb, 0x80, + 0x22, 0xbb, 0x0a, 0xa8, 0x1c, 0x3e, 0x7e, 0x4d, 0x42, 0x60, 0x5c, 0x8e, + 0xfa, 0x42, 0xb3, 0x95, 0xe7, 0x92, 0x6b, 0xec, 0x7a, 0x95, 0x88, 0x98, + 0xe3, 0xf9, 0x0d, 0xe5, 0x08, 0xf1, 0x26, 0x96, 0x2a, 0x81, 0x2b, 0x7c, + 0x0d, 0x12, 0xa0, 0x7f, 0x7b, 0x39, 0xf6, 0xcc, 0x1b, 0x2d, 0x2c, 0xe9, + 0x5b, 0x02, 0x9b, 0x5c, 0x94, 0x51, 0x13, 0xe8, 0xa0, 0x19, 0xce, 0xde, + 0x07, 0x1b, 0xda, 0x39, 0x14, 0xb5, 0x8b, 0xcf, 0x79, 0x3e, 0x2b, 0xb8, + 0x75, 0xab, 0x81, 0xee, 0x5e, 0x08, 0x33, 0xc3, 0x49, 0x5b, 0x4a, 0x9c, + 0x74, 0x34, 0xde, 0x08, 0x61, 0x03, 0x38, 0xe3, 0xd8, 0xff, 0xc5, 0xc0, + 0xb5, 0x40, 0xd5, 0x26, 0x57, 0x85, 0xf1, 0xb7, 0x77, 0xb6, 0x36, 0xe0, + 0x8d, 0x43, 0x3a, 0xef, 0xfe, 0x0f, 0xf7, 0xee, 0x67, 0x6c, 0x7b, 0xd1, + 0x83, 0xf6, 0x10, 0xda, 0x67, 0x04, 0x3a, 0x27, 0xd8, 0x3a, 0xcb, 0x9d, + 0x4c, 0xa6, 0x9a, 0xc7, 0xea, 0x07, 0xc6, 0x76, 0x79, 0x1b, 0x23, 0x4a, + 0x68, 0x2f, 0x14, 0x84, 0x42, 0x79, 0xe8, 0x1f, 0xf2, 0xe6, 0xac, 0x72, + 0xb0, 0xb0, 0xb6, 0x39, 0x95, 0x40, 0xa4, 0x6e, 0x54, 0x2e, 0xb7, 0xb5, + 0x13, 0x70, 0x48, 0x0d, 0x27, 0xed, 0x2c, 0xa2, 0x64, 0x53, 0xb4, 0x04, + 0x84, 0xab, 0xd8, 0xea, 0x2a, 0x8c, 0xac, 0x5b, 0x1d, 0xb8, 0xb2, 0xbe, + 0x55, 0x2b, 0x4a, 0x47, 0xfc, 0xe0, 0x15, 0x78, 0xb6, 0xd6, 0xff, 0x20, + 0xa8, 0x8a, 0xec, 0x8b, 0x30, 0xef, 0xc5, 0xc6, 0xec, 0xa0, 0xdf, 0xd3, + 0xc4, 0x2b, 0x4a, 0xdf, 0xef, 0x5c, 0x46, 0xb3, 0x31, 0xc7, 0x5f, 0x8f, + 0x1e, 0x99, 0x76, 0x81, 0x71, 0x61, 0xdb, 0xc3, 0xc4, 0x0f, 0x66, 0x7b, + 0xd7, 0x44, 0xc7, 0x8d, 0x12, 0x38, 0x71, 0x7c, 0xd8, 0x41, 0xf6, 0x8a, + 0xb9, 0xba, 0xd2, 0x1f, 0xa1, 0x27, 0x64, 0x67, 0x51, 0xb2, 0xaf, 0xea, + 0x02, 0x95, 0x79, 0x20, 0x0a, 0xc8, 0xaa, 0x03, 0x11, 0xb6, 0x8b, 0x7d, + 0x86, 0xb7, 0xef, 0x5e, 0x3f, 0x0b, 0x91, 0x47, 0xf0, 0x43, 0xb4, 0x54, + 0x1d, 0x16, 0x66, 0xe9, 0x63, 0x1a, 0x55, 0xaf, 0x34, 0xad, 0x11, 0x68, + 0x4d, 0x36, 0xb7, 0x0c, 0x6d, 0x4d, 0xed, 0xba, 0x14, 0xe8, 0xf6, 0xe2, + 0x15, 0x64, 0xb6, 0x15, 0x28, 0xbf, 0xd2, 0x4d, 0xb6, 0x6f, 0xca, 0x5f, + 0x81, 0x1b, 0xf0, 0x31, 0xf5, 0xd3, 0xe0, 0x06, 0xc7, 0xf3, 0x0c, 0x18, + 0x91, 0x45, 0x22, 0xa2, 0x30, 0x48, 0x82, 0xeb, 0x42, 0xfc, 0x8f, 0x2a, + 0xa3, 0x1a, 0x8d, 0x84, 0x28, 0x20, 0x16, 0x95, 0xd9, 0x66, 0x67, 0x2b, + 0xef, 0xc6, 0x6e, 0x56, 0x1c, 0x62, 0x74, 0x16, 0x5c, 0x3e, 0x17, 0xd0, + 0xb7, 0xdd, 0x70, 0xb6, 0x0e, 0x79, 0x46, 0xc5, 0x4e, 0x72, 0x46, 0x69, + 0xf5, 0xa1, 0x1c, 0x7b, 0xd5, 0x67, 0x5c, 0xb3, 0x46, 0x4d, 0x18, 0x31, + 0x47, 0x42, 0x20, 0xe6, 0x12, 0x84, 0x4e, 0x16, 0x0f, 0x4a, 0xd0, 0xc4, + 0x91, 0xa3, 0xbd, 0x91, 0xcd, 0x86, 0x4c, 0xcd, 0x4b, 0x2e, 0x62, 0x84, + 0xea, 0x19, 0x2d, 0x21, 0x1a, 0x64, 0xc4, 0xd2, 0x24, 0x92, 0x96, 0x04, + 0x66, 0xb5, 0x4a, 0xe4, 0xa9, 0xd6, 0xaf, 0x12, 0x9b, 0xb5, 0x59, 0xe0, + 0x5c, 0x84, 0x84, 0x7c, 0x68, 0x99, 0xd8, 0x23, 0xa2, 0x15, 0xa7, 0x82, + 0xa5, 0x66, 0x95, 0x8f, 0xfe, 0x57, 0xc1, 0x12, 0x6c, 0x89, 0xe5, 0x5b, + 0x5d, 0x64, 0xdb, 0x81, 0x4f, 0x77, 0x3c, 0xc8, 0x52, 0x4e, 0x2a, 0xd6, + 0x74, 0x3c, 0x4b, 0x11, 0xfc, 0xc1, 0x7c, 0x01, 0xba, 0x0f, 0x0f, 0x57, + 0x8a, 0xbe, 0x5b, 0x16, 0x88, 0x96, 0xe6, 0xe9, 0x60, 0xcf, 0x66, 0xe9, + 0xe6, 0x07, 0xb0, 0x0b, 0xa3, 0xa0, 0xad, 0xdf, 0x70, 0xd4, 0xcb, 0x2e, + 0x33, 0x2f, 0xe5, 0xf2, 0x1e, 0x0d, 0x74, 0x7a, 0xf9, 0x4a, 0x0f, 0x32, + 0xb4, 0xa1, 0xc9, 0xf5, 0x3f, 0x0a, 0x06, 0xf9, 0x67, 0x45, 0x9c, 0xd9, + 0x58, 0xd4, 0x0e, 0x72, 0x55, 0x47, 0x49, 0x9b, 0xab, 0x9c, 0x66, 0xe7, + 0x4d, 0x9a, 0x02, 0x1b, 0x41, 0xad, 0xe5, 0x8c, 0x7f, 0xa1, 0xdc, 0xad, + 0xcd, 0x74, 0xda, 0x9f, 0xfa, 0x87, 0x32, 0xc1, 0x07, 0x8e, 0x9b, 0xef, + 0x28, 0x2f, 0x17, 0x6d, 0xdb, 0x84, 0x4b, 0xa8, 0x7d, 0x31, 0xa8, 0x32, + 0xe4, 0x9a, 0x1e, 0x0e, 0xef, 0x68, 0xf4, 0xac, 0x03, 0x6c, 0x68, 0xcc, + 0x28, 0xbb, 0xfb, 0x21, 0xb8, 0x11, 0xd7, 0xf9, 0xe8, 0x24, 0x37, 0xdf, + 0xe0, 0xb2, 0xef, 0xd6, 0xec, 0xdf, 0xcf, 0xf5, 0x50, 0x19, 0xa3, 0xa9, + 0x1b, 0x01, 0x2e, 0x94, 0x42, 0xb0, 0x14, 0x5d, 0x0e, 0x37, 0x46, 0x4a, + 0x52, 0x53, 0x60, 0x6b, 0x89, 0xc9, 0xca, 0xed, 0x0a, 0x0c, 0x18, 0x33, + 0x3c, 0x40, 0x42, 0x76, 0x7a, 0x7d, 0xb6, 0x10, 0x29, 0x3e, 0x42, 0x75, + 0xa6, 0xbf, 0xcb, 0xd3, 0xdc, 0xe1, 0x00, 0x05, 0x08, 0x25, 0x67, 0x6c, + 0x72, 0xde, 0x26, 0x72, 0x88, 0xbe, 0xfa, 0x05, 0x57, 0x77, 0x78, 0x83, + 0xce, 0xd5, 0x44, 0x49, 0x8b, 0xab, 0xbc, 0xca, 0xd3, 0x1c, 0x34, 0x4a, + 0xaa, 0xc7, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x17, 0x22, 0x2a, 0x2f, 0x36, 0x3d, 0x43}; +#endif /* !MLD_CONFIG_KEYGEN_PCT */ +#endif /* !EXPECTED_SIGNATURES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/main.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/main.c new file mode 100644 index 0000000000..637fcada0c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/main.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include +#include +#include + +#include "mldsa_native_all.c" + +#define MLD_CONFIG_API_CONSTANTS_ONLY +#include + +#include "expected_signatures.h" +#include "test_only_rng/notrandombytes.h" + +#define CHECK(x) \ + do \ + { \ + int rc; \ + rc = (x); \ + if (!rc) \ + { \ + fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \ + return 1; \ + } \ + } while (0) + +#define TEST_MSG \ + "This is a test message for ML-DSA digital signature algorithm!" +#define TEST_MSG_LEN (sizeof(TEST_MSG) - 1) + +#define TEST_CTX "test_context_123" +#define TEST_CTX_LEN (sizeof(TEST_CTX) - 1) + +static int test_mldsa44(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[MLDSA44_PUBLICKEYBYTES]; + uint8_t sk[MLDSA44_SECRETKEYBYTES]; + uint8_t sig[MLDSA44_BYTES]; + uint8_t sm[TEST_MSG_LEN + MLDSA44_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + MLDSA44_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-44\n"); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(mldsa44_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(mldsa44_signature(sig, &siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(mldsa44_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(mldsa44_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(mldsa44_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", MLDSA44_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", MLDSA44_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", MLDSA44_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature_44)); + CHECK(memcmp(sig, expected_signature_44, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} + +static int test_mldsa65(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[MLDSA65_PUBLICKEYBYTES]; + uint8_t sk[MLDSA65_SECRETKEYBYTES]; + uint8_t sig[MLDSA65_BYTES]; + uint8_t sm[TEST_MSG_LEN + MLDSA65_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + MLDSA65_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-65\n"); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(mldsa65_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(mldsa65_signature(sig, &siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(mldsa65_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(mldsa65_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(mldsa65_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", MLDSA65_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", MLDSA65_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", MLDSA65_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature_65)); + CHECK(memcmp(sig, expected_signature_65, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} + + +static int test_mldsa87(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[MLDSA87_PUBLICKEYBYTES]; + uint8_t sk[MLDSA87_SECRETKEYBYTES]; + uint8_t sig[MLDSA87_BYTES]; + uint8_t sm[TEST_MSG_LEN + MLDSA87_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + MLDSA87_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-87\n"); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(mldsa87_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(mldsa87_signature(sig, &siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(mldsa87_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(mldsa87_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(mldsa87_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", MLDSA87_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", MLDSA87_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", MLDSA87_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature_87)); + CHECK(memcmp(sig, expected_signature_87, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} + +int main(void) +{ + printf("ML-DSA monolithic_build_multilevel Example\n"); + + if (test_mldsa44() != 0) + { + return 1; + } + + if (test_mldsa65() != 0) + { + return 1; + } + + if (test_mldsa87() != 0) + { + return 1; + } + + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/mldsa_native.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/mldsa_native.c new file mode 100644 index 0000000000..9668cec167 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/mldsa_native.c @@ -0,0 +1,699 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/****************************************************************************** + * + * Single compilation unit (SCU) for fixed-level build of mldsa-native + * + * This compilation unit bundles together all source files for a build + * of mldsa-native for a fixed security level (MLDSA-44/65/87). + * + * # API + * + * The API exposed by this file is described in mldsa_native.h. + * + * # Multi-level build + * + * If you want an SCU build of mldsa-native with support for multiple security + * levels, you need to include this file multiple times, and set + * MLD_CONFIG_MULTILEVEL_WITH_SHARED and MLD_CONFIG_MULTILEVEL_NO_SHARED + * appropriately. This is exemplified in examples/monolithic_build_multilevel + * and examples/monolithic_build_multilevel_native. + * + * # Configuration + * + * The following options from the mldsa-native configuration are relevant: + * + * - MLD_CONFIG_FIPS202_CUSTOM_HEADER + * Set this option if you use a custom FIPS202 implementation. + * + * - MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * Set this option if you want to include the native arithmetic backends + * in your build. + * + * - MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * Set this option if you want to include the native FIPS202 backends + * in your build. + * + * - MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * Set this option if you want to keep the directives defined in + * level-independent headers. This is needed for a multi-level build. + */ + +/* If parts of the mldsa-native source tree are not used, + * consider reducing this header via `unifdef`. + * + * Example: + * ```bash + * unifdef -UMLD_CONFIG_USE_NATIVE_BACKEND_ARITH mldsa_native.c + * ``` + */ + +#include "src/common.h" + +#include "src/ct.c" +#include "src/debug.c" +#include "src/packing.c" +#include "src/poly.c" +#include "src/poly_kl.c" +#include "src/polyvec.c" +#include "src/sign.c" + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#include "src/fips202/fips202.c" +#include "src/fips202/fips202x4.c" +#include "src/fips202/keccakf1600.c" +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#if defined(MLD_SYS_AARCH64) +#include "src/native/aarch64/src/aarch64_zetas.c" +#include "src/native/aarch64/src/polyz_unpack_table.c" +#include "src/native/aarch64/src/rej_uniform_eta_table.c" +#include "src/native/aarch64/src/rej_uniform_table.c" +#endif /* MLD_SYS_AARCH64 */ +#if defined(MLD_SYS_X86_64) +#include "src/native/x86_64/src/consts.c" +#include "src/native/x86_64/src/poly_caddq_avx2.c" +#include "src/native/x86_64/src/poly_chknorm_avx2.c" +#include "src/native/x86_64/src/poly_decompose_32_avx2.c" +#include "src/native/x86_64/src/poly_decompose_88_avx2.c" +#include "src/native/x86_64/src/poly_use_hint_32_avx2.c" +#include "src/native/x86_64/src/poly_use_hint_88_avx2.c" +#include "src/native/x86_64/src/polyz_unpack_17_avx2.c" +#include "src/native/x86_64/src/polyz_unpack_19_avx2.c" +#include "src/native/x86_64/src/rej_uniform_avx2.c" +#include "src/native/x86_64/src/rej_uniform_eta2_avx2.c" +#include "src/native/x86_64/src/rej_uniform_eta4_avx2.c" +#include "src/native/x86_64/src/rej_uniform_table.c" +#endif /* MLD_SYS_X86_64 */ +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#if defined(MLD_SYS_AARCH64) +#include "src/fips202/native/aarch64/src/keccakf1600_round_constants.c" +#endif +#if defined(MLD_SYS_X86_64) +#include "src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +/* Macro #undef's + * + * The following undefines macros from headers + * included by the source files imported above. + * + * This is to allow building and linking multiple builds + * of mldsa-native for varying parameter sets through concatenation + * of this file, as if the files had been compiled separately. + * If this is not relevant to you, you may remove the following. + */ + +/* + * Undefine macros from MLD_CONFIG_PARAMETER_SET-specific files + */ +/* mldsa/mldsa_native.h */ +#undef CRYPTO_BYTES +#undef CRYPTO_PUBLICKEYBYTES +#undef CRYPTO_SECRETKEYBYTES +#undef MLDSA44_BYTES +#undef MLDSA44_CRHBYTES +#undef MLDSA44_PUBLICKEYBYTES +#undef MLDSA44_RNDBYTES +#undef MLDSA44_SECRETKEYBYTES +#undef MLDSA44_SEEDBYTES +#undef MLDSA44_TRBYTES +#undef MLDSA65_BYTES +#undef MLDSA65_CRHBYTES +#undef MLDSA65_PUBLICKEYBYTES +#undef MLDSA65_RNDBYTES +#undef MLDSA65_SECRETKEYBYTES +#undef MLDSA65_SEEDBYTES +#undef MLDSA65_TRBYTES +#undef MLDSA87_BYTES +#undef MLDSA87_CRHBYTES +#undef MLDSA87_PUBLICKEYBYTES +#undef MLDSA87_RNDBYTES +#undef MLDSA87_SECRETKEYBYTES +#undef MLDSA87_SEEDBYTES +#undef MLDSA87_TRBYTES +#undef MLDSA_BYTES +#undef MLDSA_BYTES_ +#undef MLDSA_CRHBYTES +#undef MLDSA_PUBLICKEYBYTES +#undef MLDSA_PUBLICKEYBYTES_ +#undef MLDSA_RNDBYTES +#undef MLDSA_SECRETKEYBYTES +#undef MLDSA_SECRETKEYBYTES_ +#undef MLDSA_SEEDBYTES +#undef MLDSA_TRBYTES +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_LEGACY_CONFIG +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_NAMESPACE +#undef MLD_API_QUALIFIER +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_QUALIFIER +#undef MLD_DOMAIN_SEPARATION_MAX_BYTES +#undef MLD_ERR_FAIL +#undef MLD_ERR_OUT_OF_MEMORY +#undef MLD_ERR_RNG_FAIL +#undef MLD_H +#undef MLD_MAX3_ +#undef MLD_PREHASH_NONE +#undef MLD_PREHASH_SHA2_224 +#undef MLD_PREHASH_SHA2_256 +#undef MLD_PREHASH_SHA2_384 +#undef MLD_PREHASH_SHA2_512 +#undef MLD_PREHASH_SHA2_512_224 +#undef MLD_PREHASH_SHA2_512_256 +#undef MLD_PREHASH_SHA3_224 +#undef MLD_PREHASH_SHA3_256 +#undef MLD_PREHASH_SHA3_384 +#undef MLD_PREHASH_SHA3_512 +#undef MLD_PREHASH_SHAKE_128 +#undef MLD_PREHASH_SHAKE_256 +#undef MLD_TOTAL_ALLOC_44 +#undef MLD_TOTAL_ALLOC_44_KEYPAIR +#undef MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#undef MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#undef MLD_TOTAL_ALLOC_44_SIGN +#undef MLD_TOTAL_ALLOC_44_VERIFY +#undef MLD_TOTAL_ALLOC_65 +#undef MLD_TOTAL_ALLOC_65_KEYPAIR +#undef MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#undef MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#undef MLD_TOTAL_ALLOC_65_SIGN +#undef MLD_TOTAL_ALLOC_65_VERIFY +#undef MLD_TOTAL_ALLOC_87 +#undef MLD_TOTAL_ALLOC_87_KEYPAIR +#undef MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#undef MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#undef MLD_TOTAL_ALLOC_87_SIGN +#undef MLD_TOTAL_ALLOC_87_VERIFY +#undef crypto_sign +#undef crypto_sign_keypair +#undef crypto_sign_open +#undef crypto_sign_signature +#undef crypto_sign_verify +/* mldsa/src/common.h */ +#undef MLD_ADD_PARAM_SET +#undef MLD_ALLOC +#undef MLD_APPLY +#undef MLD_ASM_FN_SYMBOL +#undef MLD_ASM_NAMESPACE +#undef MLD_BUILD_INTERNAL +#undef MLD_COMMON_H +#undef MLD_CONCAT +#undef MLD_CONCAT_ +#undef MLD_CONTEXT_PARAMETERS_0 +#undef MLD_CONTEXT_PARAMETERS_1 +#undef MLD_CONTEXT_PARAMETERS_2 +#undef MLD_CONTEXT_PARAMETERS_3 +#undef MLD_CONTEXT_PARAMETERS_4 +#undef MLD_CONTEXT_PARAMETERS_5 +#undef MLD_CONTEXT_PARAMETERS_6 +#undef MLD_CONTEXT_PARAMETERS_7 +#undef MLD_CONTEXT_PARAMETERS_8 +#undef MLD_CONTEXT_PARAMETERS_9 +#undef MLD_EMPTY_CU +#undef MLD_ERR_FAIL +#undef MLD_ERR_OUT_OF_MEMORY +#undef MLD_ERR_RNG_FAIL +#undef MLD_EXTERNAL_API +#undef MLD_FIPS202X4_HEADER_FILE +#undef MLD_FIPS202_HEADER_FILE +#undef MLD_FREE +#undef MLD_INTERNAL_API +#undef MLD_MULTILEVEL_BUILD +#undef MLD_NAMESPACE +#undef MLD_NAMESPACE_KL +#undef MLD_NAMESPACE_PREFIX +#undef MLD_NAMESPACE_PREFIX_KL +#undef MLD_UNION_OR_STRUCT +#undef mld_memcpy +#undef mld_memset +/* mldsa/src/packing.h */ +#undef MLD_PACKING_H +#undef mld_pack_pk +#undef mld_pack_sig_c_h +#undef mld_pack_sig_z +#undef mld_pack_sk +#undef mld_unpack_pk +#undef mld_unpack_sig +#undef mld_unpack_sk +/* mldsa/src/params.h */ +#undef MLDSA_BETA +#undef MLDSA_CRHBYTES +#undef MLDSA_CRYPTO_BYTES +#undef MLDSA_CRYPTO_PUBLICKEYBYTES +#undef MLDSA_CRYPTO_SECRETKEYBYTES +#undef MLDSA_CTILDEBYTES +#undef MLDSA_D +#undef MLDSA_ETA +#undef MLDSA_GAMMA1 +#undef MLDSA_GAMMA2 +#undef MLDSA_K +#undef MLDSA_L +#undef MLDSA_N +#undef MLDSA_OMEGA +#undef MLDSA_POLYETA_PACKEDBYTES +#undef MLDSA_POLYT0_PACKEDBYTES +#undef MLDSA_POLYT1_PACKEDBYTES +#undef MLDSA_POLYVECH_PACKEDBYTES +#undef MLDSA_POLYW1_PACKEDBYTES +#undef MLDSA_POLYZ_PACKEDBYTES +#undef MLDSA_Q +#undef MLDSA_Q_HALF +#undef MLDSA_RNDBYTES +#undef MLDSA_SEEDBYTES +#undef MLDSA_TAU +#undef MLDSA_TRBYTES +#undef MLD_PARAMS_H +/* mldsa/src/poly_kl.h */ +#undef MLD_POLYETA_UNPACK_LOWER_BOUND +#undef MLD_POLY_KL_H +#undef mld_poly_challenge +#undef mld_poly_decompose +#undef mld_poly_make_hint +#undef mld_poly_uniform_eta +#undef mld_poly_uniform_eta_4x +#undef mld_poly_uniform_gamma1 +#undef mld_poly_uniform_gamma1_4x +#undef mld_poly_use_hint +#undef mld_polyeta_pack +#undef mld_polyeta_unpack +#undef mld_polyw1_pack +#undef mld_polyz_pack +#undef mld_polyz_unpack +/* mldsa/src/polyvec.h */ +#undef MLD_POLYVEC_H +#undef mld_polymat +#undef mld_polymat_get_row +#undef mld_polyvec_matrix_expand +#undef mld_polyvec_matrix_pointwise_montgomery +#undef mld_polyveck +#undef mld_polyveck_add +#undef mld_polyveck_caddq +#undef mld_polyveck_chknorm +#undef mld_polyveck_decompose +#undef mld_polyveck_invntt_tomont +#undef mld_polyveck_make_hint +#undef mld_polyveck_ntt +#undef mld_polyveck_pack_eta +#undef mld_polyveck_pack_t0 +#undef mld_polyveck_pack_w1 +#undef mld_polyveck_pointwise_poly_montgomery +#undef mld_polyveck_power2round +#undef mld_polyveck_reduce +#undef mld_polyveck_shiftl +#undef mld_polyveck_sub +#undef mld_polyveck_unpack_eta +#undef mld_polyveck_unpack_t0 +#undef mld_polyveck_use_hint +#undef mld_polyvecl +#undef mld_polyvecl_chknorm +#undef mld_polyvecl_ntt +#undef mld_polyvecl_pack_eta +#undef mld_polyvecl_pointwise_acc_montgomery +#undef mld_polyvecl_uniform_gamma1 +#undef mld_polyvecl_unpack_eta +#undef mld_polyvecl_unpack_z +/* mldsa/src/rounding.h */ +#undef MLD_2_POW_D +#undef MLD_ROUNDING_H +#undef mld_decompose +#undef mld_make_hint +#undef mld_power2round +#undef mld_use_hint +/* mldsa/src/sign.h */ +#undef MLD_DOMAIN_SEPARATION_MAX_BYTES +#undef MLD_PREHASH_NONE +#undef MLD_PREHASH_SHA2_224 +#undef MLD_PREHASH_SHA2_256 +#undef MLD_PREHASH_SHA2_384 +#undef MLD_PREHASH_SHA2_512 +#undef MLD_PREHASH_SHA2_512_224 +#undef MLD_PREHASH_SHA2_512_256 +#undef MLD_PREHASH_SHA3_224 +#undef MLD_PREHASH_SHA3_256 +#undef MLD_PREHASH_SHA3_384 +#undef MLD_PREHASH_SHA3_512 +#undef MLD_PREHASH_SHAKE_128 +#undef MLD_PREHASH_SHAKE_256 +#undef MLD_SIGN_H +#undef mld_prepare_domain_separation_prefix +#undef mld_sign +#undef mld_sign_keypair +#undef mld_sign_keypair_internal +#undef mld_sign_open +#undef mld_sign_pk_from_sk +#undef mld_sign_signature +#undef mld_sign_signature_extmu +#undef mld_sign_signature_internal +#undef mld_sign_signature_pre_hash_internal +#undef mld_sign_signature_pre_hash_shake256 +#undef mld_sign_verify +#undef mld_sign_verify_extmu +#undef mld_sign_verify_internal +#undef mld_sign_verify_pre_hash_internal +#undef mld_sign_verify_pre_hash_shake256 + +#if !defined(MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS) +/* + * Undefine macros from MLD_CONFIG_PARAMETER_SET-generic files + */ +/* mldsa/src/ct.h */ +#undef MLD_CT_H +#undef MLD_USE_ASM_VALUE_BARRIER +#undef mld_ct_opt_blocker_u64 +/* mldsa/src/debug.h */ +#undef MLD_DEBUG_H +#undef mld_assert +#undef mld_assert_abs_bound +#undef mld_assert_abs_bound_2d +#undef mld_assert_bound +#undef mld_assert_bound_2d +#undef mld_debug_check_assert +#undef mld_debug_check_bounds +/* mldsa/src/poly.h */ +#undef MLD_INTT_BOUND +#undef MLD_NTT_BOUND +#undef MLD_POLY_H +#undef mld_poly_add +#undef mld_poly_caddq +#undef mld_poly_chknorm +#undef mld_poly_invntt_tomont +#undef mld_poly_ntt +#undef mld_poly_pointwise_montgomery +#undef mld_poly_power2round +#undef mld_poly_reduce +#undef mld_poly_shiftl +#undef mld_poly_sub +#undef mld_poly_uniform +#undef mld_poly_uniform_4x +#undef mld_polyt0_pack +#undef mld_polyt0_unpack +#undef mld_polyt1_pack +#undef mld_polyt1_unpack +/* mldsa/src/randombytes.h */ +#undef MLD_RANDOMBYTES_H +/* mldsa/src/reduce.h */ +#undef MLD_MONT +#undef MLD_REDUCE32_DOMAIN_MAX +#undef MLD_REDUCE32_RANGE_MAX +#undef MLD_REDUCE_H +/* mldsa/src/symmetric.h */ +#undef MLD_STREAM128_BLOCKBYTES +#undef MLD_STREAM256_BLOCKBYTES +#undef MLD_SYMMETRIC_H +#undef mld_xof128_absorb_once +#undef mld_xof128_ctx +#undef mld_xof128_init +#undef mld_xof128_release +#undef mld_xof128_squeezeblocks +#undef mld_xof128_x4_absorb +#undef mld_xof128_x4_ctx +#undef mld_xof128_x4_init +#undef mld_xof128_x4_release +#undef mld_xof128_x4_squeezeblocks +#undef mld_xof256_absorb_once +#undef mld_xof256_ctx +#undef mld_xof256_init +#undef mld_xof256_release +#undef mld_xof256_squeezeblocks +#undef mld_xof256_x4_absorb +#undef mld_xof256_x4_ctx +#undef mld_xof256_x4_init +#undef mld_xof256_x4_release +#undef mld_xof256_x4_squeezeblocks +/* mldsa/src/sys.h */ +#undef MLD_ALIGN +#undef MLD_ALIGN_UP +#undef MLD_ALWAYS_INLINE +#undef MLD_CET_ENDBR +#undef MLD_CT_TESTING_DECLASSIFY +#undef MLD_CT_TESTING_SECRET +#undef MLD_DEFAULT_ALIGN +#undef MLD_HAVE_INLINE_ASM +#undef MLD_INLINE +#undef MLD_MUST_CHECK_RETURN_VALUE +#undef MLD_RESTRICT +#undef MLD_STATIC_TESTABLE +#undef MLD_SYS_AARCH64 +#undef MLD_SYS_AARCH64_EB +#undef MLD_SYS_APPLE +#undef MLD_SYS_BIG_ENDIAN +#undef MLD_SYS_H +#undef MLD_SYS_LINUX +#undef MLD_SYS_LITTLE_ENDIAN +#undef MLD_SYS_PPC64LE +#undef MLD_SYS_RISCV32 +#undef MLD_SYS_RISCV64 +#undef MLD_SYS_WINDOWS +#undef MLD_SYS_X86_64 +#undef MLD_SYS_X86_64_AVX2 +/* mldsa/src/cbmc.h */ +#undef MLD_CBMC_H +#undef __contract__ +#undef __loop__ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +/* + * Undefine macros from FIPS-202 files + */ +/* mldsa/src/fips202/fips202.h */ +#undef MLD_FIPS202_FIPS202_H +#undef MLD_KECCAK_LANES +#undef SHA3_256_HASHBYTES +#undef SHA3_256_RATE +#undef SHA3_512_HASHBYTES +#undef SHA3_512_RATE +#undef SHAKE128_RATE +#undef SHAKE256_RATE +#undef mld_shake128_absorb +#undef mld_shake128_finalize +#undef mld_shake128_init +#undef mld_shake128_release +#undef mld_shake128_squeeze +#undef mld_shake256 +#undef mld_shake256_absorb +#undef mld_shake256_finalize +#undef mld_shake256_init +#undef mld_shake256_release +#undef mld_shake256_squeeze +/* mldsa/src/fips202/fips202x4.h */ +#undef MLD_FIPS202_FIPS202X4_H +#undef mld_shake128x4_absorb_once +#undef mld_shake128x4_init +#undef mld_shake128x4_release +#undef mld_shake128x4_squeezeblocks +#undef mld_shake256x4_absorb_once +#undef mld_shake256x4_init +#undef mld_shake256x4_release +#undef mld_shake256x4_squeezeblocks +/* mldsa/src/fips202/keccakf1600.h */ +#undef MLD_FIPS202_KECCAKF1600_H +#undef MLD_KECCAK_LANES +#undef MLD_KECCAK_WAY +#undef mld_keccakf1600_extract_bytes +#undef mld_keccakf1600_permute +#undef mld_keccakf1600_xor_bytes +#undef mld_keccakf1600x4_extract_bytes +#undef mld_keccakf1600x4_permute +#undef mld_keccakf1600x4_xor_bytes +#endif /* !MLD_CONFIG_FIPS202_CUSTOM_HEADER */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +/* mldsa/src/fips202/native/api.h */ +#undef MLD_FIPS202_NATIVE_API_H +#undef MLD_NATIVE_FUNC_FALLBACK +#undef MLD_NATIVE_FUNC_SUCCESS +/* mldsa/src/fips202/native/auto.h */ +#undef MLD_FIPS202_NATIVE_AUTO_H +#if defined(MLD_SYS_AARCH64) +/* + * Undefine macros from native code (FIPS202, AArch64) + */ +/* mldsa/src/fips202/native/aarch64/auto.h */ +#undef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* mldsa/src/fips202/native/aarch64/src/fips202_native_aarch64.h */ +#undef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#undef mld_keccak_f1600_x1_scalar_asm +#undef mld_keccak_f1600_x1_v84a_asm +#undef mld_keccak_f1600_x2_v84a_asm +#undef mld_keccak_f1600_x4_scalar_v8a_hybrid_asm +#undef mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm +#undef mld_keccakf1600_round_constants +/* mldsa/src/fips202/native/aarch64/x1_scalar.h */ +#undef MLD_FIPS202_AARCH64_NEED_X1_SCALAR +#undef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#undef MLD_USE_FIPS202_X1_NATIVE +/* mldsa/src/fips202/native/aarch64/x1_v84a.h */ +#undef MLD_FIPS202_AARCH64_NEED_X1_V84A +#undef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#undef MLD_USE_FIPS202_X1_NATIVE +/* mldsa/src/fips202/native/aarch64/x2_v84a.h */ +#undef MLD_FIPS202_AARCH64_NEED_X2_V84A +#undef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#undef MLD_USE_FIPS202_X4_NATIVE +/* mldsa/src/fips202/native/aarch64/x4_v8a_scalar.h */ +#undef MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID +#undef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#undef MLD_USE_FIPS202_X4_NATIVE +/* mldsa/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h */ +#undef MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID +#undef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#undef MLD_USE_FIPS202_X4_NATIVE +#endif /* MLD_SYS_AARCH64 */ +#if defined(MLD_SYS_X86_64) +/* + * Undefine macros from native code (FIPS202, x86_64) + */ +/* mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h */ +#undef MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H +#undef mld_keccakf1600x4_permute24 +/* mldsa/src/fips202/native/x86_64/xkcp.h */ +#undef MLD_FIPS202_NATIVE_X86_64_XKCP_H +#undef MLD_FIPS202_X86_64_XKCP +#undef MLD_USE_FIPS202_X4_NATIVE +#endif /* MLD_SYS_X86_64 */ +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +/* mldsa/src/native/api.h */ +#undef MLD_INTT_BOUND +#undef MLD_NATIVE_API_H +#undef MLD_NATIVE_FUNC_FALLBACK +#undef MLD_NATIVE_FUNC_SUCCESS +#undef MLD_NTT_BOUND +#undef REDUCE32_RANGE_MAX +/* mldsa/src/native/meta.h */ +#undef MLD_NATIVE_META_H +#if defined(MLD_SYS_AARCH64) +/* + * Undefine macros from native code (Arith, AArch64) + */ +/* mldsa/src/native/aarch64/meta.h */ +#undef MLD_ARITH_BACKEND_AARCH64 +#undef MLD_NATIVE_AARCH64_META_H +#undef MLD_USE_NATIVE_INTT +#undef MLD_USE_NATIVE_NTT +#undef MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_17 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_19 +#undef MLD_USE_NATIVE_POLY_CADDQ +#undef MLD_USE_NATIVE_POLY_CHKNORM +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#undef MLD_USE_NATIVE_POLY_USE_HINT_32 +#undef MLD_USE_NATIVE_POLY_USE_HINT_88 +#undef MLD_USE_NATIVE_REJ_UNIFORM +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +/* mldsa/src/native/aarch64/src/arith_native_aarch64.h */ +#undef MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN +#undef MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN +#undef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#undef mld_aarch64_intt_zetas_layer123456 +#undef mld_aarch64_intt_zetas_layer78 +#undef mld_aarch64_ntt_zetas_layer123456 +#undef mld_aarch64_ntt_zetas_layer78 +#undef mld_intt_asm +#undef mld_ntt_asm +#undef mld_poly_caddq_asm +#undef mld_poly_chknorm_asm +#undef mld_poly_decompose_32_asm +#undef mld_poly_decompose_88_asm +#undef mld_poly_pointwise_montgomery_asm +#undef mld_poly_use_hint_32_asm +#undef mld_poly_use_hint_88_asm +#undef mld_polyvecl_pointwise_acc_montgomery_l4_asm +#undef mld_polyvecl_pointwise_acc_montgomery_l5_asm +#undef mld_polyvecl_pointwise_acc_montgomery_l7_asm +#undef mld_polyz_unpack_17_asm +#undef mld_polyz_unpack_17_indices +#undef mld_polyz_unpack_19_asm +#undef mld_polyz_unpack_19_indices +#undef mld_rej_uniform_asm +#undef mld_rej_uniform_eta2_asm +#undef mld_rej_uniform_eta4_asm +#undef mld_rej_uniform_eta_table +#undef mld_rej_uniform_table +#endif /* MLD_SYS_AARCH64 */ +#if defined(MLD_SYS_X86_64) +/* + * Undefine macros from native code (Arith, X86_64) + */ +/* mldsa/src/native/x86_64/meta.h */ +#undef MLD_ARITH_BACKEND_X86_64_DEFAULT +#undef MLD_NATIVE_X86_64_META_H +#undef MLD_USE_NATIVE_INTT +#undef MLD_USE_NATIVE_NTT +#undef MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#undef MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_17 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_19 +#undef MLD_USE_NATIVE_POLY_CADDQ +#undef MLD_USE_NATIVE_POLY_CHKNORM +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#undef MLD_USE_NATIVE_POLY_USE_HINT_32 +#undef MLD_USE_NATIVE_POLY_USE_HINT_88 +#undef MLD_USE_NATIVE_REJ_UNIFORM +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +/* mldsa/src/native/x86_64/src/arith_native_x86_64.h */ +#undef MLD_AVX2_REJ_UNIFORM_BUFLEN +#undef MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN +#undef MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN +#undef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#undef mld_invntt_avx2 +#undef mld_ntt_avx2 +#undef mld_nttunpack_avx2 +#undef mld_pointwise_acc_l4_avx2 +#undef mld_pointwise_acc_l5_avx2 +#undef mld_pointwise_acc_l7_avx2 +#undef mld_pointwise_avx2 +#undef mld_poly_caddq_avx2 +#undef mld_poly_chknorm_avx2 +#undef mld_poly_decompose_32_avx2 +#undef mld_poly_decompose_88_avx2 +#undef mld_poly_use_hint_32_avx2 +#undef mld_poly_use_hint_88_avx2 +#undef mld_polyz_unpack_17_avx2 +#undef mld_polyz_unpack_19_avx2 +#undef mld_rej_uniform_avx2 +#undef mld_rej_uniform_eta2_avx2 +#undef mld_rej_uniform_eta4_avx2 +#undef mld_rej_uniform_table +/* mldsa/src/native/x86_64/src/consts.h */ +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XQ +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV +#undef MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS +#undef MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV +#undef MLD_NATIVE_X86_64_SRC_CONSTS_H +#undef mld_qdata +#endif /* MLD_SYS_X86_64 */ +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ +#endif /* !MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/mldsa_native.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/mldsa_native.h new file mode 100644 index 0000000000..fd150a9df1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/mldsa_native.h @@ -0,0 +1,975 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_H +#define MLD_H + +/* + * Public API for mldsa-native + * + * This header defines the public API of a single build of mldsa-native. + * + * Make sure the configuration file is in the include path + * (this is "mldsa_native_config.h" by default, or MLD_CONFIG_FILE if defined). + * + * # Multi-level builds + * + * This header specifies a build of mldsa-native for a fixed security level. + * If you need multiple security levels, leave the security level unspecified + * in the configuration file and include this header multiple times, setting + * MLD_CONFIG_PARAMETER_SET accordingly for each, and #undef'ing the MLD_H + * guard to allow multiple inclusions. + * + * # Legacy configuration (deprecated) + * + * Instead of providing the config file used for the build, you can + * alternatively set the following configuration options prior to + * including this header. + * + * This method of configuration is deprecated. + * It will be removed in mldsa-native-v2. + * + * - MLD_CONFIG_API_PARAMETER_SET [required] + * + * The parameter set used for the build; 44, 65, or 87. + * + * - MLD_CONFIG_API_NAMESPACE_PREFIX [required] + * + * The namespace prefix used for the build. + * + * NOTE: + * For a multi-level build, you must include the 44/65/87 suffixes + * in MLD_CONFIG_API_NAMESPACE_PREFIX. + * + * - MLD_CONFIG_API_NO_SUPERCOP [optional] + * + * By default, this header will also expose the mldsa-native API in the + * SUPERCOP naming convention crypto_sign_xxx. If you don't want/need this, + * set MLD_CONFIG_API_NO_SUPERCOP. You must set this for a multi-level build. + * + * - MLD_CONFIG_API_CONSTANTS_ONLY [optional] + * + * If you don't want this header to expose any function declarations, + * but only constants for the sizes of key material, set + * MLD_CONFIG_API_CONSTANTS_ONLY. In this case, you don't need to set + * MLD_CONFIG_API_PARAMETER_SET or MLD_CONFIG_API_NAMESPACE_PREFIX, + * nor include a configuration. + * + * - MLD_CONFIG_API_QUALIFIER [optional] + * + * Qualifier to apply to external API. + * + ******************************************************************************/ + +/******************************* Key sizes ************************************/ + +/* Sizes of cryptographic material, per parameter set */ +/* See mldsa/src/params.h for the arithmetic expressions giving rise to these */ +/* check-magic: off */ +#define MLDSA44_SECRETKEYBYTES 2560 +#define MLDSA44_PUBLICKEYBYTES 1312 +#define MLDSA44_BYTES 2420 + +#define MLDSA65_SECRETKEYBYTES 4032 +#define MLDSA65_PUBLICKEYBYTES 1952 +#define MLDSA65_BYTES 3309 + +#define MLDSA87_SECRETKEYBYTES 4896 +#define MLDSA87_PUBLICKEYBYTES 2592 +#define MLDSA87_BYTES 4627 +/* check-magic: on */ + +/* Size of seed and randomness in bytes (level-independent) */ +#define MLDSA_SEEDBYTES 32 +#define MLDSA44_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA65_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA87_SEEDBYTES MLDSA_SEEDBYTES + +/* Size of CRH output in bytes (level-independent) */ +#define MLDSA_CRHBYTES 64 +#define MLDSA44_CRHBYTES MLDSA_CRHBYTES +#define MLDSA65_CRHBYTES MLDSA_CRHBYTES +#define MLDSA87_CRHBYTES MLDSA_CRHBYTES + +/* Size of TR output in bytes (level-independent) */ +#define MLDSA_TRBYTES 64 +#define MLDSA44_TRBYTES MLDSA_TRBYTES +#define MLDSA65_TRBYTES MLDSA_TRBYTES +#define MLDSA87_TRBYTES MLDSA_TRBYTES + +/* Size of randomness for signing in bytes (level-independent) */ +#define MLDSA_RNDBYTES 32 +#define MLDSA44_RNDBYTES MLDSA_RNDBYTES +#define MLDSA65_RNDBYTES MLDSA_RNDBYTES +#define MLDSA87_RNDBYTES MLDSA_RNDBYTES + +/* Sizes of cryptographic material, as a function of LVL=44,65,87 */ +#define MLDSA_SECRETKEYBYTES_(LVL) MLDSA##LVL##_SECRETKEYBYTES +#define MLDSA_PUBLICKEYBYTES_(LVL) MLDSA##LVL##_PUBLICKEYBYTES +#define MLDSA_BYTES_(LVL) MLDSA##LVL##_BYTES +#define MLDSA_SECRETKEYBYTES(LVL) MLDSA_SECRETKEYBYTES_(LVL) +#define MLDSA_PUBLICKEYBYTES(LVL) MLDSA_PUBLICKEYBYTES_(LVL) +#define MLDSA_BYTES(LVL) MLDSA_BYTES_(LVL) + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + +/****************************** Function API **********************************/ + +#define MLD_API_CONCAT_(x, y) x##y +#define MLD_API_CONCAT(x, y) MLD_API_CONCAT_(x, y) +#define MLD_API_CONCAT_UNDERSCORE(x, y) MLD_API_CONCAT(MLD_API_CONCAT(x, _), y) + +#if !defined(MLD_CONFIG_API_PARAMETER_SET) +/* Recommended configuration via same config file as used for the build. */ + +/* For now, we derive the legacy API configuration MLD_CONFIG_API_XXX from + * the config file. In mldsa-native-v2, this will be removed and we will + * exclusively work with MLD_CONFIG_XXX. */ + +/* You need to make sure the config file is in the include path. */ +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#define MLD_CONFIG_API_PARAMETER_SET MLD_CONFIG_PARAMETER_SET + +#if defined(MLD_CONFIG_MULTILEVEL_BUILD) +#define MLD_CONFIG_API_NAMESPACE_PREFIX \ + MLD_API_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_CONFIG_API_NAMESPACE_PREFIX MLD_CONFIG_NAMESPACE_PREFIX +#endif + +#if defined(MLD_CONFIG_NO_SUPERCOP) +#define MLD_CONFIG_API_NO_SUPERCOP +#endif + +#if defined(MLD_CONFIG_CONSTANTS_ONLY) +#define MLD_CONFIG_API_CONSTANTS_ONLY +#endif + +#if defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_CONFIG_API_QUALIFIER MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#else /* !MLD_CONFIG_API_PARAMETER_SET */ +#define MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_PARAMETER_SET */ + +#define MLD_API_NAMESPACE(sym) \ + MLD_API_CONCAT_UNDERSCORE(MLD_CONFIG_API_NAMESPACE_PREFIX, sym) + +#if defined(__GNUC__) || defined(clang) +#define MLD_API_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_API_MUST_CHECK_RETURN_VALUE +#endif + +#if defined(MLD_CONFIG_API_QUALIFIER) +#define MLD_API_QUALIFIER MLD_CONFIG_API_QUALIFIER +#else +#define MLD_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_API_CONSTANTS_ONLY) + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************************* + * Name: crypto_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: + * input random seed + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair_internal)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t seed[MLDSA_SEEDBYTES] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: If MLD_CONFIG_KEYGEN_PCT is enabled and the + * PCT check failed. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return -1 in that case. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_extmu + * + * Description: Computes signature. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_extmu)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t *sm: pointer to output signed message (allocated array + * with MLDSA{44,65,87}_BYTES + mlen bytes), can be + * equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(sign)( + uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_extmu)( + const uint8_t *sig, size_t siglen, const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_open + * + * Description: Verify signed message. + * + * Arguments: + * - uint8_t *m: pointer to output message (allocated array with + * smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(open)( + uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: crypto_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *ph, size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_shake256)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_shake256)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/* Maximum formatted domain separation message length */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +size_t MLD_API_NAMESPACE(prepare_domain_separation_prefix)( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg); + +/************************************************* + * Name: crypto_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[CRYPTO_SECRETKEYBYTES]: input secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(pk_from_sk)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +#ifdef __cplusplus +} +#endif + +/****************************** SUPERCOP API *********************************/ + +#if !defined(MLD_CONFIG_API_NO_SUPERCOP) +/* Export API in SUPERCOP naming scheme CRYPTO_xxx / crypto_sign_xxx */ +#define CRYPTO_SECRETKEYBYTES MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_PUBLICKEYBYTES MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_BYTES MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET) + +#define crypto_sign_keypair MLD_API_NAMESPACE(keypair) +#define crypto_sign_signature MLD_API_NAMESPACE(signature) +#define crypto_sign MLD_API_NAMESPACE(sign) +#define crypto_sign_verify MLD_API_NAMESPACE(verify) +#define crypto_sign_open MLD_API_NAMESPACE(open) + +#else /* !MLD_CONFIG_API_NO_SUPERCOP */ + +/* If the SUPERCOP API is not needed, we can undefine the various helper macros + * above. Otherwise, they are needed for lazy evaluation of crypto_sign_xxx. */ +#if !defined(MLD_API_LEGACY_CONFIG) +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_QUALIFIER +#endif /* !MLD_API_LEGACY_CONFIG */ + +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_NAMESPACE +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_QUALIFIER +#undef MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_NO_SUPERCOP */ +#endif /* !MLD_CONFIG_API_CONSTANTS_ONLY */ + + +/***************************** Memory Usage **********************************/ + +/* + * By default mldsa-native performs all memory allocations on the stack. + * Alternatively, mldsa-native supports custom allocation of large structures + * through the `MLD_CONFIG_CUSTOM_ALLOC_FREE` configuration option. + * See mldsa_native_config.h for details. + * + * `MLD_TOTAL_ALLOC_{44,65,87}_{KEYPAIR,SIGN,VERIFY}` indicates the maximum + * (accumulative) allocation via MLD_ALLOC for each parameter set and operation. + * Note that some stack allocation remains even + * when using custom allocators, so these values are lower than total stack + * usage with the default stack-only allocation. + * + * These constants may be used to implement custom allocations using a + * fixed-sized buffer and a simple allocator (e.g., bump allocator). + */ +/* check-magic: off */ +#if defined(MLD_API_LEGACY_CONFIG) || !defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 45248 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 56640 +#define MLD_TOTAL_ALLOC_44_SIGN 52896 +#define MLD_TOTAL_ALLOC_44_VERIFY 38816 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 71872 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 85856 +#define MLD_TOTAL_ALLOC_65_SIGN 80576 +#define MLD_TOTAL_ALLOC_65_VERIFY 62432 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 112832 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 130816 +#define MLD_TOTAL_ALLOC_87_SIGN 123584 +#define MLD_TOTAL_ALLOC_87_VERIFY 99552 +#else /* MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM */ +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 32992 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 36192 +#define MLD_TOTAL_ALLOC_44_SIGN 32448 +#define MLD_TOTAL_ALLOC_44_VERIFY 22464 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 46304 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 50048 +#define MLD_TOTAL_ALLOC_65_SIGN 44768 +#define MLD_TOTAL_ALLOC_65_VERIFY 30720 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 62688 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 66336 +#define MLD_TOTAL_ALLOC_87_SIGN 59104 +#define MLD_TOTAL_ALLOC_87_VERIFY 41216 +#endif /* !(MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM) */ +/* check-magic: on */ + +/* + * MLD_TOTAL_ALLOC_*_KEYPAIR adapts based on MLD_CONFIG_KEYGEN_PCT. + * For legacy config, we don't know which options are used, so assume + * the worst case (PCT enabled). + */ +#if defined(MLD_API_LEGACY_CONFIG) || defined(MLD_CONFIG_KEYGEN_PCT) +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#else +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#endif + +#define MLD_MAX3_(a, b, c) \ + ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c))) + +/* + * `MLD_TOTAL_ALLOC_{44,65,87}` is the maximum across all operations for each + * parameter set. + */ +#define MLD_TOTAL_ALLOC_44 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_44_KEYPAIR, MLD_TOTAL_ALLOC_44_SIGN, \ + MLD_TOTAL_ALLOC_44_VERIFY) +#define MLD_TOTAL_ALLOC_65 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_65_KEYPAIR, MLD_TOTAL_ALLOC_65_SIGN, \ + MLD_TOTAL_ALLOC_65_VERIFY) +#define MLD_TOTAL_ALLOC_87 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_87_KEYPAIR, MLD_TOTAL_ALLOC_87_SIGN, \ + MLD_TOTAL_ALLOC_87_VERIFY) + +#endif /* !MLD_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/mldsa_native_config.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/mldsa_native_config.h new file mode 100644 index 0000000000..80052d3f15 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/mldsa_native_config.h @@ -0,0 +1,746 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/* + * Test configuration: Multilevel monolithic build config with native backends + * + * This configuration differs from the default mldsa/mldsa_native_config.h in + * the following places: + * - MLD_CONFIG_NO_SUPERCOP + * - MLD_CONFIG_MULTILEVEL_BUILD + * - MLD_CONFIG_NAMESPACE_PREFIX + * - MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * - MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * - MLD_CONFIG_INTERNAL_API_QUALIFIER + * - MLD_CONFIG_EXTERNAL_API_QUALIFIER + * - MLD_CONFIG_CUSTOM_RANDOMBYTES + */ + + +#ifndef MLD_CONFIG_H +#define MLD_CONFIG_H + +/****************************************************************************** + * Name: MLD_CONFIG_PARAMETER_SET + * + * Description: Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * If you want to support multiple parameter sets, build the + * library multiple times and set MLD_CONFIG_MULTILEVEL_BUILD. + * See MLD_CONFIG_MULTILEVEL_BUILD for how to do this while + * minimizing code duplication. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of the default configuration file mldsa/mldsa_native_config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * then configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + * + *****************************************************************************/ +/* No need to set this -- we _are_ already in a custom config */ +/* #define MLD_CONFIG_FILE "mldsa_native_config.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_NAMESPACE_PREFIX + * + * Description: The prefix to use to namespace global symbols from mldsa/. + * + * In a multi-level build, level-dependent symbols will + * additionally be prefixed with the parameter set (44/65/87). + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_NAMESPACE_PREFIX mldsa + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_BUILD + * + * Description: Set this if the build is part of a multi-level build supporting + * multiple parameter sets. + * + * If you need only a single parameter set, keep this unset. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them. + * + * See examples/multilevel_build for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_MULTILEVEL_BUILD + +/****************************************************************************** + * Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + * + *****************************************************************************/ +#define MLD_CONFIG_EXTERNAL_API_QUALIFIER static + +/****************************************************************************** + * Name: MLD_CONFIG_NO_RANDOMIZED_API + * + * Description: If this option is set, mldsa-native will be built without the + * randomized API functions (crypto_sign_keypair, + * crypto_sign, crypto_sign_signature, and + * crypto_sign_signature_extmu). + * This allows users to build mldsa-native without providing a + * randombytes() implementation if they only need the + * internal deterministic API + * (crypto_sign_keypair_internal, crypto_sign_signature_internal). + * + * NOTE: This option is incompatible with MLD_CONFIG_KEYGEN_PCT + * as the current PCT implementation requires + * crypto_sign_signature(). + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_RANDOMIZED_API */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_SUPERCOP + * + * Description: By default, mldsa_native.h exposes the mldsa-native API in the + * SUPERCOP naming convention (crypto_sign_xxx). If you don't need + * this, set MLD_CONFIG_NO_SUPERCOP. + * + * NOTE: You must set this for a multi-level build as the SUPERCOP + * naming does not disambiguate between the parameter sets. + * + *****************************************************************************/ +#define MLD_CONFIG_NO_SUPERCOP + +/****************************************************************************** + * Name: MLD_CONFIG_CONSTANTS_ONLY + * + * Description: If you only need the size constants (MLDSA_PUBLICKEYBYTES, etc.) + * but no function declarations, set MLD_CONFIG_CONSTANTS_ONLY. + * + * This only affects the public header mldsa_native.h, not + * the implementation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONSTANTS_ONLY */ + +/****************************************************************************** + * + * Build-only configuration options + * + * The remaining configurations are build-options only. + * They do not affect the API described in mldsa_native.h. + * + *****************************************************************************/ + +#if defined(MLD_BUILD_INTERNAL) +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_WITH_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, all MLD_CONFIG_PARAMETER_SET-independent + * code will be included in the build, including code needed only + * for other parameter sets. + * + * Example: TODO: add example + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_WITH_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_NO_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, no MLD_CONFIG_PARAMETER_SET-independent code + * will be included in the build. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * + * Description: This is only relevant for single compilation unit (SCU) + * builds of mldsa-native. In this case, it determines whether + * directives defined in parameter-set-independent headers should + * be #undef'ined or not at the of the SCU file. This is needed + * in multilevel builds. + * + * See examples/multilevel_build_native for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * + * Description: Determines whether an native arithmetic backend should be used. + * + * The arithmetic backend covers performance critical functions + * such as the number-theoretic transform (NTT). + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the arithmetic backend to be use is + * determined by MLD_CONFIG_ARITH_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + +/****************************************************************************** + * Name: MLD_CONFIG_ARITH_BACKEND_FILE + * + * Description: The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * + * Description: Determines whether an native FIPS202 backend should be used. + * + * The FIPS202 backend covers 1x/2x/4x-fold Keccak-f1600, which is + * the performance bottleneck of SHA3 and SHAKE. + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the FIPS202 backend to be use is + * determined by MLD_CONFIG_FIPS202_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_BACKEND_FILE + * + * Description: The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202X4_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202-X4 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202x4.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ZEROIZE + * + * Description: In compliance with @[FIPS204, Section 3.6.3], mldsa-native, + * zeroizes intermediate stack buffers before returning from + * function calls. + * + * Set this option and define `mld_zeroize` if you want to + * use a custom method to zeroize intermediate stack buffers. + * The default implementation uses SecureZeroMemory on Windows + * and a memset + compiler barrier otherwise. If neither of those + * is available on the target platform, compilation will fail, + * and you will need to use MLD_CONFIG_CUSTOM_ZEROIZE to provide + * a custom implementation of `mld_zeroize()`. + * + * WARNING: + * The explicit stack zeroization conducted by mldsa-native + * reduces the likelihood of data leaking on the stack, but + * does not eliminate it! The C standard makes no guarantee about + * where a compiler allocates structures and whether/where it makes + * copies of them. Also, in addition to entire structures, there + * may also be potentially exploitable leakage of individual values + * on the stack. + * + * If you need bullet-proof zeroization of the stack, you need to + * consider additional measures instead of what this feature + * provides. In this case, you can set mld_zeroize to a + * no-op. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void mld_zeroize(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * Description: mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to provided by the + * consumer. + * + * If this option is not set, mldsa-native expects a function + * int randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mld_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + * + *****************************************************************************/ +/* Even though we use the default randombytes signature here, registering it + * as a custom implementation avoids double-declaration of randombytes via + * mldsa/src/randombytes.h and test_only_rng/notrandombytes.h: The former is by + * default included by mldsa-native, and the latter is needed for this example + * since we rely on the additional randombytes_reset() API. */ + +#define MLD_CONFIG_CUSTOM_RANDOMBYTES +#if !defined(__ASSEMBLER__) +#include +#include "src/sys.h" +#include "test_only_rng/notrandombytes.h" +static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) +{ + return randombytes(ptr, len); +} +#endif /* !__ASSEMBLER__ */ + + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + * + * Description: mldsa-native backends may rely on specific hardware features. + * Those backends will only be included in an mldsa-native build + * if support for the respective features is enabled at + * compile-time. However, when building for a heteroneous set + * of CPUs to run the resulting binary/library on, feature + * detection at _runtime_ is needed to decided whether a backend + * can be used or not. + * + * Set this option and define `mld_sys_check_capability` if you + * want to use a custom method to dispatch between implementations. + * + * Return value 1 indicates that a capability is supported. + * Return value 0 indicates that a capability is not supported. + * + * If this option is not set, mldsa-native uses compile-time + * feature detection only to decide which backend to use. + * + * If you compile mldsa-native on a system with different + * capabilities than the system that the resulting binary/library + * will be run on, you must use this option. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) + { + ... your implementation ... + } +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ALLOC_FREE [EXPERIMENTAL] + * + * Description: Set this option and define `MLD_CUSTOM_ALLOC` and + * `MLD_CUSTOM_FREE` if you want to use custom allocation for + * large local structures or buffers. + * + * By default, all buffers/structures are allocated on the stack. + * If this option is set, most of them will be allocated via + * MLD_CUSTOM_ALLOC. + * + * Parameters to MLD_CUSTOM_ALLOC: + * - T* v: Target pointer to declare. + * - T: Type of structure to be allocated + * - N: Number of elements to be allocated. + * + * Parameters to MLD_CUSTOM_FREE: + * - T* v: Target pointer to free. May be NULL. + * - T: Type of structure to be freed. + * - N: Number of elements to be freed. + * + * WARNING: This option is experimental! + * Its scope, configuration and function/macro signatures may + * change at any time. We expect a stable API for v2. + * + * NOTE: Even if this option is set, some allocations further down + * the call stack will still be made from the stack. Those will + * likely be added to the scope of this option in the future. + * + * NOTE: MLD_CUSTOM_ALLOC need not guarantee a successful + * allocation nor include error handling. Upon failure, the + * target pointer should simply be set to NULL. The calling + * code will handle this case and invoke MLD_CUSTOM_FREE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ALLOC_FREE + #if !defined(__ASSEMBLER__) + #include + #define MLD_CUSTOM_ALLOC(v, T, N) \ + T* (v) = (T *)aligned_alloc(MLD_DEFAULT_ALIGN, \ + MLD_ALIGN_UP(sizeof(T) * (N))) + #define MLD_CUSTOM_FREE(v, T, N) free(v) + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMCPY + * + * Description: Set this option and define `mld_memcpy` if you want to + * use a custom method to copy memory instead of the standard + * library memcpy function. + * + * The custom implementation must have the same signature and + * behavior as the standard memcpy function: + * void *mld_memcpy(void *dest, const void *src, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMCPY + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMSET + * + * Description: Set this option and define `mld_memset` if you want to + * use a custom method to set memory instead of the standard + * library memset function. + * + * The custom implementation must have the same signature and + * behavior as the standard memset function: + * void *mld_memset(void *s, int c, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMSET + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memset(void *s, int c, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_INTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of internal API. + * + * The primary use case for this option are single-CU builds, + * in which case this option can be set to `static`. + * + *****************************************************************************/ +#define MLD_CONFIG_INTERNAL_API_QUALIFIER static + +/****************************************************************************** + * Name: MLD_CONFIG_CT_TESTING_ENABLED + * + * Description: If set, mldsa-native annotates data as secret / public using + * valgrind's annotations VALGRIND_MAKE_MEM_UNDEFINED and + * VALGRIND_MAKE_MEM_DEFINED, enabling various checks for secret- + * dependent control flow of variable time execution (depending + * on the exact version of valgrind installed). + * + *****************************************************************************/ +/* #define MLD_CONFIG_CT_TESTING_ENABLED */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * and MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT + * + * Description: Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, crypto_sign_keypair_internal and + * crypto_sign_keypair will return a non-zero error code if the + * PCT failed. + * + * NOTE: This feature will drastically lower the performance of + * key generation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * Description: If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "src/src.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Description: Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * NOTE: Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + * + *****************************************************************************/ +/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER + * + * Description: Set this to add a context parameter that is provided to public + * API functions and is then available in custom callbacks. + * + * The type of the context parameter is configured via + * MLD_CONFIG_CONTEXT_PARAMETER_TYPE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER_TYPE + * + * Description: Set this to define the type for the context parameter used by + * MLD_CONFIG_CONTEXT_PARAMETER. + * + * This is only relevant if MLD_CONFIG_CONTEXT_PARAMETER is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER_TYPE void* */ + +/****************************************************************************** + * Name: MLD_CONFIG_REDUCE_RAM [EXPERIMENTAL] + * + * Description: Set this to reduce RAM usage. + * This trades memory for performance. + * + * For expected memory usage, see the MLD_TOTAL_ALLOC_* constants + * defined in mldsa_native.h. + * + * This option is useful for embedded systems with tight RAM + * constraints but relaxed performance requirements. + * + * WARNING: This option is experimental! + * CBMC proofs do not currently cover this configuration option. + * Its scope and configuration may change at any time. + * + *****************************************************************************/ +/* #define MLD_CONFIG_REDUCE_RAM */ + +/************************* Config internals ********************************/ + +#endif /* MLD_BUILD_INTERNAL */ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace is + * + * PQCP_MLDSA_NATIVE_MLDSA_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_ + */ + +#if MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65 +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87 +#endif + +#endif /* !MLD_CONFIG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/cbmc.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/cbmc.h new file mode 100644 index 0000000000..8ed1ecb06b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/cbmc.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_CBMC_H +#define MLD_CBMC_H +/*************************************************** + * Basic replacements for __CPROVER_XXX contracts + ***************************************************/ +#ifndef CBMC + +#define __contract__(x) +#define __loop__(x) +#define cassert(x) + +#else /* !CBMC */ + +#include + +#define __contract__(x) x +#define __loop__(x) x + +/* https://diffblue.github.io/cbmc/contracts-assigns.html */ +#define assigns(...) __CPROVER_assigns(__VA_ARGS__) + +/* https://diffblue.github.io/cbmc/contracts-requires-ensures.html */ +#define requires(...) __CPROVER_requires(__VA_ARGS__) +#define ensures(...) __CPROVER_ensures(__VA_ARGS__) +/* https://diffblue.github.io/cbmc/contracts-loops.html */ +#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__) +#define decreases(...) __CPROVER_decreases(__VA_ARGS__) +/* cassert to avoid confusion with in-built assert */ +#define cassert(x) __CPROVER_assert(x, "cbmc assertion failed") +#define assume(...) __CPROVER_assume(__VA_ARGS__) + +/*************************************************** + * Macros for "expression" forms that may appear + * _inside_ top-level contracts. + ***************************************************/ + +/* + * function return value - useful inside ensures + * https://diffblue.github.io/cbmc/contracts-functions.html + */ +#define return_value (__CPROVER_return_value) + +/* + * assigns l-value targets + * https://diffblue.github.io/cbmc/contracts-assigns.html + */ +#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__) +#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__) +#define same_object(...) __CPROVER_same_object(__VA_ARGS__) + +/* + * Pointer-related predicates + * https://diffblue.github.io/cbmc/contracts-memory-predicates.html + */ +#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__) +#define readable(...) __CPROVER_r_ok(__VA_ARGS__) +#define writeable(...) __CPROVER_w_ok(__VA_ARGS__) + +/* Maximum supported buffer size + * + * Larger buffers may be supported, but due to internal modeling constraints + * in CBMC, the proofs of memory- and type-safety won't be able to run. + * + * If you find yourself in need for a buffer size larger than this, + * please contact the maintainers, so we can prioritize work to relax + * this somewhat artificial bound. + */ +#define MLD_MAX_BUFFER_SIZE (SIZE_MAX >> 12) + + +/* + * History variables + * https://diffblue.github.io/cbmc/contracts-history-variables.html + */ +#define old(...) __CPROVER_old(__VA_ARGS__) +#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__) + +/* + * Quantifiers + * Note that the range on qvar is _exclusive_ between qvar_lb .. qvar_ub + * https://diffblue.github.io/cbmc/contracts-quantifiers.html + */ + +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define forall(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> (predicate) \ + } + +#define exists(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_exists \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) && (predicate) \ + } +/* clang-format on */ + +/*************************************************** + * Convenience macros for common contract patterns + ***************************************************/ +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define CBMC_CONCAT_(left, right) left##right +#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right) + +#define array_bound_core(qvar, qvar_lb, qvar_ub, array_var, \ + value_lb, value_ub) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + (((int)(value_lb) <= ((array_var)[(qvar)])) && \ + (((array_var)[(qvar)]) < (int)(value_ub))) \ + } + +#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \ + array_bound_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (qvar_lb), \ + (qvar_ub), (array_var), (value_lb), (value_ub)) + +#define array_unchanged_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (int32_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged(array_var, N) \ + array_unchanged_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) + +#define array_unchanged_u64_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (uint64_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged_u64(array_var, N) \ + array_unchanged_u64_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) +/* clang-format on */ + +/* Wrapper around array_bound operating on absolute values. + * + * The absolute value bound `k` is exclusive. + * + * Note that since the lower bound in array_bound is inclusive, we have to + * raise it by 1 here. + */ +#define array_abs_bound(arr, lb, ub, k) \ + array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k)) + +#endif /* CBMC */ + +#endif /* !MLD_CBMC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/common.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/common.h new file mode 100644 index 0000000000..4a5bc8109d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/common.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_COMMON_H +#define MLD_COMMON_H + +#define MLD_BUILD_INTERNAL + +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#include "params.h" +#include "sys.h" + +/* Internal and public API have external linkage by default, but + * this can be overwritten by the user, e.g. for single-CU builds. */ +#if !defined(MLD_CONFIG_INTERNAL_API_QUALIFIER) +#define MLD_INTERNAL_API +#else +#define MLD_INTERNAL_API MLD_CONFIG_INTERNAL_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_EXTERNAL_API +#else +#define MLD_EXTERNAL_API MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#if defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) || \ + defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) +#define MLD_MULTILEVEL_BUILD +#endif + +#define MLD_CONCAT_(x1, x2) x1##x2 +#define MLD_CONCAT(x1, x2) MLD_CONCAT_(x1, x2) + +#if defined(MLD_MULTILEVEL_BUILD) +#define MLD_ADD_PARAM_SET(s) MLD_CONCAT(s, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_ADD_PARAM_SET(s) s +#endif + +#define MLD_NAMESPACE_PREFIX MLD_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, _) +#define MLD_NAMESPACE_PREFIX_KL \ + MLD_CONCAT(MLD_ADD_PARAM_SET(MLD_CONFIG_NAMESPACE_PREFIX), _) + +/* Functions are prefixed by MLD_CONFIG_NAMESPACE_PREFIX. + * + * If multiple parameter sets are used, functions depending on the parameter + * set are additionally prefixed with 44/65/87. See mldsa_native_config.h. + * + * Example: If MLD_CONFIG_NAMESPACE_PREFIX is PQCP_MLDSA_NATIVE, then + * MLD_NAMESPACE_KL(keypair) becomes PQCP_MLDSA_NATIVE44_keypair/ + * PQCP_MLDSA_NATIVE65_keypair/PQCP_MLDSA_NATIVE87_keypair. + */ +#define MLD_NAMESPACE(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX, s) +#define MLD_NAMESPACE_KL(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX_KL, s) + +/* On Apple platforms, we need to emit leading underscore + * in front of assembly symbols. We thus introducee a separate + * namespace wrapper for ASM symbols. */ +#if !defined(__APPLE__) +#define MLD_ASM_NAMESPACE(sym) MLD_NAMESPACE(sym) +#else +#define MLD_ASM_NAMESPACE(sym) MLD_CONCAT(_, MLD_NAMESPACE(sym)) +#endif + +/* + * On X86_64 if control-flow protections (CET) are enabled (through + * -fcf-protection=), we add an endbr64 instruction at every global function + * label. See sys.h for more details + */ +#if defined(MLD_SYS_X86_64) +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : MLD_CET_ENDBR +#else +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : +#endif + +/* We aim to simplify the user's life by supporting builds where + * all source files are included, even those that are not needed. + * Those files are appropriately guarded and will be empty when unneeded. + * The following is to avoid compilers complaining about this. */ +#define MLD_EMPTY_CU(s) extern int MLD_NAMESPACE_KL(empty_cu_##s); + +/* MLD_CONFIG_NO_ASM takes precedence over MLD_USE_NATIVE_XXX */ +#if defined(MLD_CONFIG_NO_ASM) +#undef MLD_CONFIG_USE_NATIVE_BACKEND_ARITH +#undef MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, but MLD_CONFIG_ARITH_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, but MLD_CONFIG_FIPS202_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_NO_RANDOMIZED_API) && defined(MLD_CONFIG_KEYGEN_PCT) +#error Bad configuration: MLD_CONFIG_NO_RANDOMIZED_API is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires crypto_sign_signature() +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#include MLD_CONFIG_ARITH_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#include MLD_CONFIG_FIPS202_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "fips202/native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#define MLD_FIPS202_HEADER_FILE "fips202/fips202.h" +#else +#define MLD_FIPS202_HEADER_FILE MLD_CONFIG_FIPS202_CUSTOM_HEADER +#endif + +#if !defined(MLD_CONFIG_FIPS202X4_CUSTOM_HEADER) +#define MLD_FIPS202X4_HEADER_FILE "fips202/fips202x4.h" +#else +#define MLD_FIPS202X4_HEADER_FILE MLD_CONFIG_FIPS202X4_CUSTOM_HEADER +#endif + +/* Standard library function replacements */ +#if !defined(__ASSEMBLER__) +#if !defined(MLD_CONFIG_CUSTOM_MEMCPY) +#include +#define mld_memcpy memcpy +#endif + +#if !defined(MLD_CONFIG_CUSTOM_MEMSET) +#include +#define mld_memset memset +#endif + +/* Allocation macros for large local structures + * + * MLD_ALLOC(v, T, N) declares T *v and attempts to point it to an T[N] + * MLD_FREE(v, T, N) zeroizes and frees the allocation + * + * Default implementation uses stack allocation. + * Can be overridden by setting the config option MLD_CONFIG_CUSTOM_ALLOC_FREE + * and defining MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE. + */ +#if defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) != \ + (defined(MLD_CUSTOM_ALLOC) && defined(MLD_CUSTOM_FREE)) +#error Bad configuration: MLD_CONFIG_CUSTOM_ALLOC_FREE must be set together with MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE +#endif + +/* + * If the integration wants to provide a context parameter for use in + * platform-specific hooks, then it should define this parameter. + * + * The MLD_CONTEXT_PARAMETERS_n macros are intended to be used with macros + * defining the function names and expand to either pass or discard the context + * argument as required by the current build. If there is no context parameter + * requested then these are removed from the prototypes and from all calls. + */ +#ifdef MLD_CONFIG_CONTEXT_PARAMETER +#define MLD_CONTEXT_PARAMETERS_0(context) (context) +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0, context) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1, context) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) \ + (arg0, arg1, arg2, context) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3, context) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4, context) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, context) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, context) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, context) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, context) +#else /* MLD_CONFIG_CONTEXT_PARAMETER */ +#define MLD_CONTEXT_PARAMETERS_0(context) () +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) (arg0, arg1, arg2) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) +#endif /* !MLD_CONFIG_CONTEXT_PARAMETER */ + +#if defined(MLD_CONFIG_CONTEXT_PARAMETER_TYPE) != \ + defined(MLD_CONFIG_CONTEXT_PARAMETER) +#error MLD_CONFIG_CONTEXT_PARAMETER_TYPE must be defined if and only if MLD_CONFIG_CONTEXT_PARAMETER is defined +#endif + +#if !defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) +/* Default: stack allocation */ + +#define MLD_ALLOC(v, T, N, context) \ + MLD_ALIGN T mld_alloc_##v[N]; \ + T *v = mld_alloc_##v + +/* TODO: This leads to a circular dependency between common and ct.h + * It just works out before we're at the end of the file, but it's still + * prone to issues in the future. */ +#include "ct.h" +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + mld_zeroize(mld_alloc_##v, sizeof(mld_alloc_##v)); \ + (v) = NULL; \ + } while (0) + +#else /* !MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* Custom allocation */ + +/* + * The indirection here is necessary to use MLD_CONTEXT_PARAMETERS_3 here. + */ +#define MLD_APPLY(f, args) f args + +#define MLD_ALLOC(v, T, N, context) \ + MLD_APPLY(MLD_CUSTOM_ALLOC, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)) + +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + if (v != NULL) \ + { \ + mld_zeroize(v, sizeof(T) * (N)); \ + MLD_APPLY(MLD_CUSTOM_FREE, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)); \ + v = NULL; \ + } \ + } while (0) + +#endif /* MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* + * We are facing severe CBMC performance issues when using unions. + * As a temporary workaround, we use unions only when MLD_CONFIG_REDUCE_RAM is + * set. + * TODO: Remove the workaround once + * https://github.com/diffblue/cbmc/issues/8813 + * is resolved + */ +#if defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_UNION_OR_STRUCT union +#else +#define MLD_UNION_OR_STRUCT struct +#endif + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_COMMON_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/ct.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/ct.c new file mode 100644 index 0000000000..010b1a52a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/ct.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include "ct.h" + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +/* + * Masking value used in constant-time functions from + * ct.h to block the compiler's range analysis and + * thereby reduce the risk of compiler-introduced branches. + */ +volatile uint64_t mld_ct_opt_blocker_u64 = 0; + +#else /* !MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(ct) + +#endif /* !(!MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/ct.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/ct.h new file mode 100644 index 0000000000..c307456468 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/ct.h @@ -0,0 +1,366 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [libmceliece] + * libmceliece implementation of Classic McEliece + * Bernstein, Chou + * https://lib.mceliece.org/ + * + * - [optblocker] + * PQC forum post on opt-blockers using volatile globals + * Daniel J. Bernstein + * https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ + */ + +#ifndef MLD_CT_H +#define MLD_CT_H + +#include +#include "cbmc.h" +#include "common.h" + +/* Constant-time comparisons and conditional operations + + We reduce the risk for compilation into variable-time code + through the use of 'value barriers'. + + Functionally, a value barrier is a no-op. To the compiler, however, + it constitutes an arbitrary modification of its input, and therefore + harden's value propagation and range analysis. + + We consider two approaches to implement a value barrier: + - An empty inline asm block which marks the target value as clobbered. + - XOR'ing with the value of a volatile global that's set to 0; + see @[optblocker] for a discussion of this idea, and + @[libmceliece, inttypes/crypto_intN.h] for an implementation. + + The first approach is cheap because it only prevents the compiler + from reasoning about the value of the variable past the barrier, + but does not directly generate additional instructions. + + The second approach generates redundant loads and XOR operations + and therefore comes at a higher runtime cost. However, it appears + more robust towards optimization, as compilers should never drop + a volatile load. + + We use the empty-ASM value barrier for GCC and clang, and fall + back to the global volatile barrier otherwise. + + The global value barrier can be forced by setting + MLD_CONFIG_NO_ASM_VALUE_BARRIER. + +*/ + +#if defined(MLD_HAVE_INLINE_ASM) && !defined(MLD_CONFIG_NO_ASM_VALUE_BARRIER) +#define MLD_USE_ASM_VALUE_BARRIER +#endif + + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) +/* + * Declaration of global volatile that the global value barrier + * is loading from and masking with. + */ +#define mld_ct_opt_blocker_u64 MLD_NAMESPACE(ct_opt_blocker_u64) +extern volatile uint64_t mld_ct_opt_blocker_u64; + + +/* Helper functions for obtaining global masks of various sizes */ + +/* This contract is not proved but treated as an axiom. + * + * Its validity relies on the assumption that the global opt-blocker + * constant mld_ct_opt_blocker_u64 is not modified. + */ +static MLD_INLINE uint64_t mld_ct_get_optblocker_u64(void) +__contract__(ensures(return_value == 0)) { return mld_ct_opt_blocker_u64; } + +static MLD_INLINE int64_t mld_ct_get_optblocker_i64(void) +__contract__(ensures(return_value == 0)) { return (int64_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint32_t mld_ct_get_optblocker_u32(void) +__contract__(ensures(return_value == 0)) { return (uint32_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint8_t mld_ct_get_optblocker_u8(void) +__contract__(ensures(return_value == 0)) { return (uint8_t)mld_ct_get_optblocker_u64(); } + +/* Opt-blocker based implementation of value barriers */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_i64()); } + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u32()); } + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u8()); } + + +#else /* !MLD_USE_ASM_VALUE_BARRIER */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} +#endif /* MLD_USE_ASM_VALUE_BARRIER */ + +#ifdef CBMC +#pragma CPROVER check push +#pragma CPROVER check disable "conversion" +#endif + +/************************************************* + * Name: mld_cast_uint32_to_int32 + * + * Description: Cast uint32 value to int32 + * + * Returns: For uint32_t x, the unique y in int32_t + * so that x == y mod 2^32. + * + * Concretely: + * - x < 2^31: returns x + * - x >= 2^31: returns x - 2^31 + * + **************************************************/ +static MLD_ALWAYS_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x) +{ + /* + * PORTABILITY: This relies on uint32_t -> int32_t + * being implemented as the inverse of int32_t -> uint32_t, + * which is implementation-defined (C99 6.3.1.3 (3)) + * CBMC (correctly) fails to prove this conversion is OK, + * so we have to suppress that check here + */ + return (int32_t)x; +} + +#ifdef CBMC +#pragma CPROVER check pop +#endif + + +/************************************************* + * Name: mld_cast_int64_to_uint32 + * + * Description: Cast int64 value to uint32 as per C standard. + * + * Returns: For int64_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int64_to_uint32(int64_t x) +{ + return (uint32_t)(x & (int64_t)UINT32_MAX); +} + +/************************************************* + * Name: mld_cast_int32_to_uint32 + * + * Description: Cast int32 value to uint32 as per C standard. + * + * Returns: For int32_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int32_to_uint32(int32_t x) +{ + return mld_cast_int64_to_uint32((int64_t)x); +} + +/************************************************* + * Name: mld_ct_sel_int32 + * + * Description: Functionally equivalent to cond ? a : b, + * but implemented with guards against + * compiler-introduced branches. + * + * Arguments: int32_t a: First alternative + * int32_t b: Second alternative + * uint32_t cond: Condition variable. + * + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_sel_int32(int32_t a, int32_t b, uint32_t cond) +__contract__( + requires(cond == 0x0 || cond == 0xFFFFFFFF) + ensures(return_value == (cond ? a : b)) +) +{ + uint32_t au = mld_cast_int32_to_uint32(a); + uint32_t bu = mld_cast_int32_to_uint32(b); + uint32_t res = bu ^ (mld_value_barrier_u32(cond) & (au ^ bu)); + return mld_cast_uint32_to_int32(res); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u32 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_nonzero_u32(uint32_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFFFFFFFF))) +{ + int64_t tmp = mld_value_barrier_i64(-((int64_t)x)); + tmp >>= 32; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u8 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint8_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint8_t mld_ct_cmask_nonzero_u8(uint8_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFF))) +{ + uint32_t mask = mld_ct_cmask_nonzero_u32((uint32_t)x); + return (uint8_t)(mask & 0xFF); +} + +/************************************************* + * Name: mld_ct_cmask_neg_i32 + * + * Description: Return 0 if input is non-negative, and -1 otherwise. + * + * Arguments: int32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_neg_i32(int32_t x) +__contract__( + ensures(return_value == ((x < 0) ? 0xFFFFFFFF : 0)) +) +{ + int64_t tmp = mld_value_barrier_i64((int64_t)x); + tmp >>= 31; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_abs_i32 + * + * Description: Return -x if x<0, x otherwise + * + * Arguments: int32_t x: Input value + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_abs_i32(int32_t x) +__contract__( + requires(x >= -INT32_MAX) + ensures(return_value == ((x < 0) ? -x : x)) +) +{ + return mld_ct_sel_int32(-x, x, mld_ct_cmask_neg_i32(x)); +} + +/************************************************* + * Name: mld_ct_memcmp + * + * Description: Compare two arrays for equality in constant time. + * + * Arguments: const uint8_t *a: pointer to first byte array + * const uint8_t *b: pointer to second byte array + * size_t len: length of the byte arrays, upper-bounded + * to UINT16_MAX to control proof complexity + * only. + * + * Returns 0 if the byte arrays are equal, 0xFF otherwise. + **************************************************/ +static MLD_INLINE uint8_t mld_ct_memcmp(const uint8_t *a, const uint8_t *b, + const size_t len) +__contract__( + requires(len <= UINT16_MAX) + requires(memory_no_alias(a, len)) + requires(memory_no_alias(b, len)) + ensures((return_value == 0) || (return_value == 0xFF)) + ensures((return_value == 0) == forall(i, 0, len, (a[i] == b[i])))) +{ + uint8_t r = 0, s = 0; + unsigned i; + + for (i = 0; i < len; i++) + __loop__( + invariant(i <= len) + invariant((r == 0) == (forall(k, 0, i, (a[k] == b[k]))))) + { + r |= a[i] ^ b[i]; + /* s is useless, but prevents the loop from being aborted once r=0xff. */ + s ^= a[i] ^ b[i]; + } + + /* + * - Convert r into a mask; this may not be necessary, but is an additional + * safeguard + * towards leaking information about a and b. + * - XOR twice with s, separated by a value barrier, to prevent the compile + * from dropping the s computation in the loop. + */ + return (mld_value_barrier_u8(mld_ct_cmask_nonzero_u8(r) ^ s) ^ s); +} + +/************************************************* + * Name: mld_zeroize + * + * Description: Force-zeroize a buffer. + * @[FIPS204, Section 3.6.3] Destruction of intermediate + * values. + * + * Arguments: void *ptr: pointer to buffer to be zeroed + * size_t len: Amount of bytes to be zeroed + **************************************************/ +#if !defined(MLD_CONFIG_CUSTOM_ZEROIZE) +#if defined(MLD_SYS_WINDOWS) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) { SecureZeroMemory(ptr, len); } +#elif defined(MLD_HAVE_INLINE_ASM) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) +{ + memset(ptr, 0, len); + /* This follows OpenSSL and seems sufficient to prevent the compiler + * from optimizing away the memset. + * + * If there was a reliable way to detect availability of memset_s(), + * that would be preferred. */ + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +} +#else /* !MLD_SYS_WINDOWS && MLD_HAVE_INLINE_ASM */ +#error No plausibly-secure implementation of mld_zeroize available. Please provide your own using MLD_CONFIG_CUSTOM_ZEROIZE. +#endif /* !MLD_SYS_WINDOWS && !MLD_HAVE_INLINE_ASM */ +#endif /* !MLD_CONFIG_CUSTOM_ZEROIZE */ + +#endif /* !MLD_CT_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/debug.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/debug.c new file mode 100644 index 0000000000..a55d51e8b1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/debug.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* NOTE: You can remove this file unless you compile with MLDSA_DEBUG. */ + +#include "common.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#if defined(MLDSA_DEBUG) + +#include +#include +#include +#include "debug.h" + +#define MLD_DEBUG_ERROR_HEADER "[ERROR:%s:%04d] " + +void mld_debug_check_assert(const char *file, int line, const int val) +{ + if (val == 0) + { + fprintf(stderr, MLD_DEBUG_ERROR_HEADER "Assertion failed (value %d)\n", + file, line, val); + exit(1); + } +} + +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive) +{ + int err = 0; + unsigned i; + for (i = 0; i < len; i++) + { + int32_t val = ptr[i]; + if (!(val > lower_bound_exclusive && val < upper_bound_exclusive)) + { + fprintf(stderr, + MLD_DEBUG_ERROR_HEADER + "Bounds assertion failed: Index %u, value %d out of bounds " + "(%" PRId64 ",%" PRId64 ")\n", + file, line, i, (int)val, lower_bound_exclusive, + upper_bound_exclusive); + err = 1; + } + } + + if (err == 1) + { + exit(1); + } +} + +#else /* MLDSA_DEBUG */ + +MLD_EMPTY_CU(debug) + +#endif /* !MLDSA_DEBUG */ + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(debug) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_DEBUG_ERROR_HEADER diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/debug.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/debug.h new file mode 100644 index 0000000000..af187bb9de --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/debug.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_DEBUG_H +#define MLD_DEBUG_H +#include "common.h" + +#if defined(MLDSA_DEBUG) +#include + +/************************************************* + * Name: mld_assert + * + * Description: Check debug assertion + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - val: Value asserted to be non-zero + **************************************************/ +#define mld_debug_check_assert MLD_NAMESPACE(mldsa_debug_assert) +void mld_debug_check_assert(const char *file, int line, const int val); + +/************************************************* + * Name: mld_debug_check_bounds + * + * Description: Check whether values in an array of int32_t + * are within specified bounds. + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - ptr: Base of array to be checked + * - len: Number of int32_t in ptr + * - lower_bound_exclusive: Exclusive lower bound + * - upper_bound_exclusive: Exclusive upper bound + **************************************************/ +#define mld_debug_check_bounds MLD_NAMESPACE(mldsa_debug_check_bounds) +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive); + +/* Check assertion, calling exit() upon failure + * + * val: Value that's asserted to be non-zero + */ +#define mld_assert(val) mld_debug_check_assert(__FILE__, __LINE__, (val)) + +/* Check bounds in array of int32_t's + * ptr: Base of int32_t array; will be explicitly cast to int32_t*, + * so you may pass a byte-compatible type such as mld_poly or mld_polyvec. + * len: Number of int32_t in array + * value_lb: Inclusive lower value bound + * value_ub: Exclusive upper value bound */ +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + mld_debug_check_bounds(__FILE__, __LINE__, (const int32_t *)(ptr), (len), \ + ((int64_t)(value_lb)) - 1, (value_ub)) + +/* Check absolute bounds in array of int32_t's + * ptr: Base of array, expression of type int32_t* + * len: Number of int32_t in array + * value_abs_bd: Exclusive absolute upper bound */ +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + mld_assert_bound((ptr), (len), (-((int64_t)(value_abs_bd)) + 1), \ + (value_abs_bd)) + +/* Version of bounds assertions for 2-dimensional arrays */ +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + mld_assert_bound((ptr), ((len0) * (len1)), (value_lb), (value_ub)) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + mld_assert_abs_bound((ptr), ((len0) * (len1)), (value_abs_bd)) + +/* When running CBMC, convert debug assertions into proof obligations */ +#elif defined(CBMC) +#include "cbmc.h" + +#define mld_assert(val) cassert(val) + +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + cassert(array_bound(((int32_t *)(ptr)), 0, (len), (value_lb), (value_ub))) + +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + cassert(array_abs_bound(((int32_t *)(ptr)), 0, (len), (value_abs_bd))) + +/* Because of https://github.com/diffblue/cbmc/issues/8570, we can't + * just use a single flattened array_bound(...) here. */ +#define mld_assert_bound_2d(ptr, M, N, value_lb, value_ub) \ + cassert(forall(kN, 0, (M), \ + array_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_lb), (value_ub)))) + +#define mld_assert_abs_bound_2d(ptr, M, N, value_abs_bd) \ + cassert(forall(kN, 0, (M), \ + array_abs_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_abs_bd)))) + +#else /* !MLDSA_DEBUG && CBMC */ + +#define mld_assert(val) \ + do \ + { \ + } while (0) +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + do \ + { \ + } while (0) +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + do \ + { \ + } while (0) + +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + do \ + { \ + } while (0) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + do \ + { \ + } while (0) + + +#endif /* !MLDSA_DEBUG && !CBMC */ +#endif /* !MLD_DEBUG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/fips202.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/fips202.c new file mode 100644 index 0000000000..1112de061c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/fips202.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "../common.h" +#include "../ct.h" +#include "fips202.h" +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +/************************************************* + * Name: keccak_init + * + * Description: Initializes the Keccak state. + * + * Arguments: - uint64_t *s: pointer to Keccak state + **************************************************/ +static void keccak_init(uint64_t s[MLD_KECCAK_LANES]) +__contract__( + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + mld_memset(s, 0, sizeof(uint64_t) * MLD_KECCAK_LANES); +} + +/************************************************* + * Name: keccak_absorb + * + * Description: Absorb step of Keccak; incremental. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_absorb(uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r, + const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(pos <= r) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(in, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + ensures(return_value < r)) +{ + while (inlen >= r - pos) + __loop__( + assigns(pos, in, inlen, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + invariant(inlen <= loop_entry(inlen)) + invariant(pos <= r) + invariant(in == loop_entry(in) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600_xor_bytes(s, in, pos, r - pos); + inlen -= r - pos; + in += r - pos; + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: At this point, inlen < r, so the truncation to unsigned is safe. */ + mld_keccakf1600_xor_bytes(s, in, pos, (unsigned)inlen); + + /* Safety: At this point, inlen < r and pos <= r so the truncation to unsigned + * is safe. */ + return (unsigned)(pos + inlen); +} + +/************************************************* + * Name: keccak_finalize + * + * Description: Finalize absorb step. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - uint8_t p: domain separation byte + **************************************************/ +static void keccak_finalize(uint64_t s[MLD_KECCAK_LANES], unsigned int pos, + unsigned int r, uint8_t p) +__contract__( + requires(pos <= r && r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires((r / 8) >= 1) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + uint8_t b = 0x80; + mld_keccakf1600_xor_bytes(s, &p, pos, 1); + mld_keccakf1600_xor_bytes(s, &b, r - 1, 1); +} + +/************************************************* + * Name: keccak_squeeze + * + * Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes. + * Modifies the state. Can be called multiple times to keep + * squeezing, i.e., is incremental. + * + * Arguments: - uint8_t *out: pointer to output data + * - size_t outlen: number of bytes to be squeezed (written to out) + * - uint64_t *s: pointer to input/output Keccak state + * - unsigned int pos: number of bytes in current block already + *squeezed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_squeeze(uint8_t *out, size_t outlen, + uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r) +__contract__( + requires((r == SHAKE128_RATE && pos <= SHAKE128_RATE) || + (r == SHAKE256_RATE && pos <= SHAKE256_RATE) || + (r == SHA3_512_RATE && pos <= SHA3_512_RATE)) + requires(outlen <= 8 * r /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(out, outlen)) + ensures(return_value <= r)) +{ + unsigned int i; + size_t out_offset = 0; + + /* Reference: This code is re-factored from the reference implementation + * to facilitate proof with CBMC and to improve readability. + * + * Take a mutable copy of outlen to count down the number of bytes + * still to squeeze. The initial value of outlen is needed for the CBMC + * assigns() clauses. */ + size_t bytes_to_go = outlen; + + while (bytes_to_go > 0) + __loop__( + assigns(i, bytes_to_go, pos, out_offset, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES), memory_slice(out, outlen)) + invariant(bytes_to_go <= outlen) + invariant(out_offset == outlen - bytes_to_go) + invariant(pos <= r) + ) + { + if (pos == r) + { + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: If bytes_to_go < r - pos, truncation to unsigned is safe. */ + i = bytes_to_go < r - pos ? (unsigned)bytes_to_go : r - pos; + mld_keccakf1600_extract_bytes(s, out + out_offset, pos, i); + bytes_to_go -= i; + pos += i; + out_offset += i; + } + + return pos; +} + +void mld_shake128_init(mld_shake128ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE128_RATE, in, inlen); +} + +void mld_shake128_finalize(mld_shake128ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE128_RATE, 0x1F); + state->pos = SHAKE128_RATE; +} + +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE128_RATE); +} + +void mld_shake128_release(mld_shake128ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128ctx)); +} + +void mld_shake256_init(mld_shake256ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); +} + +void mld_shake256_finalize(mld_shake256ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); + state->pos = SHAKE256_RATE; +} + +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); +} + +void mld_shake256_release(mld_shake256ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256ctx)); +} + +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +{ + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, in, inlen); + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/fips202.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/fips202.h new file mode 100644 index 0000000000..9f0253cb88 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/fips202.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202_H +#define MLD_FIPS202_FIPS202_H + +#include +#include +#include "../cbmc.h" +#include "../common.h" + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 +#define SHA3_256_RATE 136 +#define SHA3_512_RATE 72 +#define MLD_KECCAK_LANES 25 +#define SHA3_256_HASHBYTES 32 +#define SHA3_512_HASHBYTES 64 + + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake128ctx; + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake256ctx; + +#define mld_shake128_init MLD_NAMESPACE(shake128_init) +/************************************************* + * Name: mld_shake128_init + * + * Description: Initializes state for use as SHAKE128 XOF + * + * Arguments: - mld_shake128ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake128_init(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos == 0) +); + +#define mld_shake128_absorb MLD_NAMESPACE(shake128_absorb) +/************************************************* + * Name: mld_shake128_absorb + * + * Description: Absorb step of the SHAKE128 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake128ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_finalize MLD_NAMESPACE(shake128_finalize) +/************************************************* + * Name: mld_shake128_finalize + * + * Description: Concludes the absorb phase of the SHAKE128 XOF. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_finalize(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_squeeze MLD_NAMESPACE(shake128_squeeze) +/************************************************* + * Name: mld_shake128_squeeze + * + * Description: Squeeze step of SHAKE128 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake128ctx *s: pointer to input/output state + **************************************************/ +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE128_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_release MLD_NAMESPACE(shake128_release) +/************************************************* + * Name: mld_shake128_release + * + * Description: Release and securely zero the SHAKE128 state. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_release(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) +); + +#define mld_shake256_init MLD_NAMESPACE(shake256_init) +/************************************************* + * Name: mld_shake256_init + * + * Description: Initializes state for use as SHAKE256 XOF + * + * Arguments: - mld_shake256ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake256_init(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos == 0) +); + +#define mld_shake256_absorb MLD_NAMESPACE(shake256_absorb) +/************************************************* + * Name: mld_shake256_absorb + * + * Description: Absorb step of the SHAKE256 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake256ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_finalize MLD_NAMESPACE(shake256_finalize) +/************************************************* + * Name: mld_shake256_finalize + * + * Description: Concludes the absorb phase of the SHAKE256 XOF. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_finalize(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_squeeze MLD_NAMESPACE(shake256_squeeze) +/************************************************* + * Name: mld_shake256_squeeze + * + * Description: Squeeze step of SHAKE256 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake256ctx *s: pointer to input/output state + **************************************************/ +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_release MLD_NAMESPACE(shake256_release) +/************************************************* + * Name: mld_shake256_release + * + * Description: Release and securely zero the SHAKE256 state. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_release(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) +); + +#define mld_shake256 MLD_NAMESPACE(shake256) +/************************************************* + * Name: mld_shake256 + * + * Description: SHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +); + +#endif /* !MLD_FIPS202_FIPS202_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/fips202x4.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/fips202x4.c new file mode 100644 index 0000000000..0fb5cd57c7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/fips202x4.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include "../common.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "../ct.h" +#include "fips202.h" +#include "fips202x4.h" +#include "keccakf1600.h" + +static void mld_keccak_absorb_once_x4(uint64_t *s, uint32_t r, + const uint8_t *in0, const uint8_t *in1, + const uint8_t *in2, const uint8_t *in3, + size_t inlen, uint8_t p) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))) +{ + while (inlen >= r) + __loop__( + assigns(inlen, in0, in1, in2, in3, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + invariant(inlen <= loop_entry(inlen)) + invariant(in0 == loop_entry(in0) + (loop_entry(inlen) - inlen)) + invariant(in1 == loop_entry(in1) + (loop_entry(inlen) - inlen)) + invariant(in2 == loop_entry(in2) + (loop_entry(inlen) - inlen)) + invariant(in3 == loop_entry(in3) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, r); + mld_keccakf1600x4_permute(s); + + in0 += r; + in1 += r; + in2 += r; + in3 += r; + inlen -= r; + } + + /* Safety: At this point, inlen < r, so the truncations to unsigned are safe + * below. */ + if (inlen > 0) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, (unsigned)inlen); + } + + if (inlen == r - 1) + { + p |= 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + } + else + { + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + p = 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, r - 1, 1); + } +} + +static void mld_keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1, + uint8_t *out2, uint8_t *out3, + size_t nblocks, uint64_t *s, uint32_t r) +__contract__( + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(out0, nblocks * r)) + requires(memory_no_alias(out1, nblocks * r)) + requires(memory_no_alias(out2, nblocks * r)) + requires(memory_no_alias(out3, nblocks * r)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(out0, nblocks * r)) + assigns(memory_slice(out1, nblocks * r)) + assigns(memory_slice(out2, nblocks * r)) + assigns(memory_slice(out3, nblocks * r))) +{ + while (nblocks > 0) + __loop__( + assigns(out0, out1, out2, out3, nblocks, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY), + memory_slice(out0, nblocks * r), + memory_slice(out1, nblocks * r), + memory_slice(out2, nblocks * r), + memory_slice(out3, nblocks * r)) + invariant(nblocks <= loop_entry(nblocks) && + out0 == loop_entry(out0) + r * (loop_entry(nblocks) - nblocks) && + out1 == loop_entry(out1) + r * (loop_entry(nblocks) - nblocks) && + out2 == loop_entry(out2) + r * (loop_entry(nblocks) - nblocks) && + out3 == loop_entry(out3) + r * (loop_entry(nblocks) - nblocks))) + { + mld_keccakf1600x4_permute(s); + mld_keccakf1600x4_extract_bytes(s, out0, out1, out2, out3, 0, r); + + out0 += r; + out1 += r; + out2 += r; + out3 += r; + nblocks--; + } +} + +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake128x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE128_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE128_RATE); +} + +void mld_shake128x4_init(mld_shake128x4ctx *state) { (void)state; } +void mld_shake128x4_release(mld_shake128x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128x4ctx)); +} + + +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake256x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE256_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE256_RATE); +} + +void mld_shake256x4_init(mld_shake256x4ctx *state) { (void)state; } +void mld_shake256x4_release(mld_shake256x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256x4ctx)); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/fips202x4.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/fips202x4.h new file mode 100644 index 0000000000..e7987207a6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/fips202x4.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202X4_H +#define MLD_FIPS202_FIPS202X4_H + +#include +#include + +#include "../cbmc.h" +#include "../common.h" + +#include "fips202.h" +#include "keccakf1600.h" + +/* Context for non-incremental API */ +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake128x4ctx; + +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake256x4ctx; + +#define mld_shake128x4_absorb_once MLD_NAMESPACE(shake128x4_absorb_once) +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_squeezeblocks MLD_NAMESPACE(shake128x4_squeezeblocks) +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE128_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE128_RATE), + memory_slice(out1, nblocks * SHAKE128_RATE), + memory_slice(out2, nblocks * SHAKE128_RATE), + memory_slice(out3, nblocks * SHAKE128_RATE), + memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_init MLD_NAMESPACE(shake128x4_init) +void mld_shake128x4_init(mld_shake128x4ctx *state); + +#define mld_shake128x4_release MLD_NAMESPACE(shake128x4_release) +void mld_shake128x4_release(mld_shake128x4ctx *state); + + +#define mld_shake256x4_absorb_once MLD_NAMESPACE(shake256x4_absorb_once) +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_squeezeblocks MLD_NAMESPACE(shake256x4_squeezeblocks) +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE256_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE256_RATE), + memory_slice(out1, nblocks * SHAKE256_RATE), + memory_slice(out2, nblocks * SHAKE256_RATE), + memory_slice(out3, nblocks * SHAKE256_RATE), + memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_init MLD_NAMESPACE(shake256x4_init) +void mld_shake256x4_init(mld_shake256x4ctx *state); + +#define mld_shake256x4_release MLD_NAMESPACE(shake256x4_release) +void mld_shake256x4_release(mld_shake256x4ctx *state); + + +#endif /* !MLD_FIPS202_FIPS202X4_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/keccakf1600.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/keccakf1600.c new file mode 100644 index 0000000000..e59120c07c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/keccakf1600.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#define MLD_KECCAK_NROUNDS 24 +#define MLD_KECCAK_ROL(a, offset) ((a << offset) ^ (a >> (64 - offset))) + +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = state_ptr[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = (state[(offset + i) >> 3] >> (8 * ((offset + i) & 0x07))) & 0xFF; + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state_ptr[i] ^= data[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state[(offset + i) >> 3] ^= (uint64_t)data[i] + << (8 * ((offset + i) & 0x07)); + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X4_NATIVE) + if (mld_keccak_f1600_x4_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 0); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 1); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 2); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 3); +} + +static const uint64_t mld_KeccakF_RoundConstants[MLD_KECCAK_NROUNDS] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +static void mld_keccakf1600_permute_c(uint64_t *state) +{ + unsigned round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + uint64_t BCa, BCe, BCi, BCo, BCu; + uint64_t Da, De, Di, Do, Du; + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + /* copyFromState(A, state) */ + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < MLD_KECCAK_NROUNDS; round += 2) + __loop__(invariant(round <= MLD_KECCAK_NROUNDS && round % 2 == 0)) + { + /* prepareTheta */ + BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; + BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + /* thetaRhoPiChiIotaPrepareTheta(round, A, E) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = MLD_KECCAK_ROL(Age, 44); + Aki ^= Di; + BCi = MLD_KECCAK_ROL(Aki, 43); + Amo ^= Do; + BCo = MLD_KECCAK_ROL(Amo, 21); + Asu ^= Du; + BCu = MLD_KECCAK_ROL(Asu, 14); + Eba = BCa ^ ((~BCe) & BCi); + Eba ^= (uint64_t)mld_KeccakF_RoundConstants[round]; + Ebe = BCe ^ ((~BCi) & BCo); + Ebi = BCi ^ ((~BCo) & BCu); + Ebo = BCo ^ ((~BCu) & BCa); + Ebu = BCu ^ ((~BCa) & BCe); + + Abo ^= Do; + BCa = MLD_KECCAK_ROL(Abo, 28); + Agu ^= Du; + BCe = MLD_KECCAK_ROL(Agu, 20); + Aka ^= Da; + BCi = MLD_KECCAK_ROL(Aka, 3); + Ame ^= De; + BCo = MLD_KECCAK_ROL(Ame, 45); + Asi ^= Di; + BCu = MLD_KECCAK_ROL(Asi, 61); + Ega = BCa ^ ((~BCe) & BCi); + Ege = BCe ^ ((~BCi) & BCo); + Egi = BCi ^ ((~BCo) & BCu); + Ego = BCo ^ ((~BCu) & BCa); + Egu = BCu ^ ((~BCa) & BCe); + + Abe ^= De; + BCa = MLD_KECCAK_ROL(Abe, 1); + Agi ^= Di; + BCe = MLD_KECCAK_ROL(Agi, 6); + Ako ^= Do; + BCi = MLD_KECCAK_ROL(Ako, 25); + Amu ^= Du; + BCo = MLD_KECCAK_ROL(Amu, 8); + Asa ^= Da; + BCu = MLD_KECCAK_ROL(Asa, 18); + Eka = BCa ^ ((~BCe) & BCi); + Eke = BCe ^ ((~BCi) & BCo); + Eki = BCi ^ ((~BCo) & BCu); + Eko = BCo ^ ((~BCu) & BCa); + Eku = BCu ^ ((~BCa) & BCe); + + Abu ^= Du; + BCa = MLD_KECCAK_ROL(Abu, 27); + Aga ^= Da; + BCe = MLD_KECCAK_ROL(Aga, 36); + Ake ^= De; + BCi = MLD_KECCAK_ROL(Ake, 10); + Ami ^= Di; + BCo = MLD_KECCAK_ROL(Ami, 15); + Aso ^= Do; + BCu = MLD_KECCAK_ROL(Aso, 56); + Ema = BCa ^ ((~BCe) & BCi); + Eme = BCe ^ ((~BCi) & BCo); + Emi = BCi ^ ((~BCo) & BCu); + Emo = BCo ^ ((~BCu) & BCa); + Emu = BCu ^ ((~BCa) & BCe); + + Abi ^= Di; + BCa = MLD_KECCAK_ROL(Abi, 62); + Ago ^= Do; + BCe = MLD_KECCAK_ROL(Ago, 55); + Aku ^= Du; + BCi = MLD_KECCAK_ROL(Aku, 39); + Ama ^= Da; + BCo = MLD_KECCAK_ROL(Ama, 41); + Ase ^= De; + BCu = MLD_KECCAK_ROL(Ase, 2); + Esa = BCa ^ ((~BCe) & BCi); + Ese = BCe ^ ((~BCi) & BCo); + Esi = BCi ^ ((~BCo) & BCu); + Eso = BCo ^ ((~BCu) & BCa); + Esu = BCu ^ ((~BCa) & BCe); + + /* prepareTheta */ + BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + /* thetaRhoPiChiIotaPrepareTheta(round+1, E, A) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = MLD_KECCAK_ROL(Ege, 44); + Eki ^= Di; + BCi = MLD_KECCAK_ROL(Eki, 43); + Emo ^= Do; + BCo = MLD_KECCAK_ROL(Emo, 21); + Esu ^= Du; + BCu = MLD_KECCAK_ROL(Esu, 14); + Aba = BCa ^ ((~BCe) & BCi); + Aba ^= (uint64_t)mld_KeccakF_RoundConstants[round + 1]; + Abe = BCe ^ ((~BCi) & BCo); + Abi = BCi ^ ((~BCo) & BCu); + Abo = BCo ^ ((~BCu) & BCa); + Abu = BCu ^ ((~BCa) & BCe); + + Ebo ^= Do; + BCa = MLD_KECCAK_ROL(Ebo, 28); + Egu ^= Du; + BCe = MLD_KECCAK_ROL(Egu, 20); + Eka ^= Da; + BCi = MLD_KECCAK_ROL(Eka, 3); + Eme ^= De; + BCo = MLD_KECCAK_ROL(Eme, 45); + Esi ^= Di; + BCu = MLD_KECCAK_ROL(Esi, 61); + Aga = BCa ^ ((~BCe) & BCi); + Age = BCe ^ ((~BCi) & BCo); + Agi = BCi ^ ((~BCo) & BCu); + Ago = BCo ^ ((~BCu) & BCa); + Agu = BCu ^ ((~BCa) & BCe); + + Ebe ^= De; + BCa = MLD_KECCAK_ROL(Ebe, 1); + Egi ^= Di; + BCe = MLD_KECCAK_ROL(Egi, 6); + Eko ^= Do; + BCi = MLD_KECCAK_ROL(Eko, 25); + Emu ^= Du; + BCo = MLD_KECCAK_ROL(Emu, 8); + Esa ^= Da; + BCu = MLD_KECCAK_ROL(Esa, 18); + Aka = BCa ^ ((~BCe) & BCi); + Ake = BCe ^ ((~BCi) & BCo); + Aki = BCi ^ ((~BCo) & BCu); + Ako = BCo ^ ((~BCu) & BCa); + Aku = BCu ^ ((~BCa) & BCe); + + Ebu ^= Du; + BCa = MLD_KECCAK_ROL(Ebu, 27); + Ega ^= Da; + BCe = MLD_KECCAK_ROL(Ega, 36); + Eke ^= De; + BCi = MLD_KECCAK_ROL(Eke, 10); + Emi ^= Di; + BCo = MLD_KECCAK_ROL(Emi, 15); + Eso ^= Do; + BCu = MLD_KECCAK_ROL(Eso, 56); + Ama = BCa ^ ((~BCe) & BCi); + Ame = BCe ^ ((~BCi) & BCo); + Ami = BCi ^ ((~BCo) & BCu); + Amo = BCo ^ ((~BCu) & BCa); + Amu = BCu ^ ((~BCa) & BCe); + + Ebi ^= Di; + BCa = MLD_KECCAK_ROL(Ebi, 62); + Ego ^= Do; + BCe = MLD_KECCAK_ROL(Ego, 55); + Eku ^= Du; + BCi = MLD_KECCAK_ROL(Eku, 39); + Ema ^= Da; + BCo = MLD_KECCAK_ROL(Ema, 41); + Ese ^= De; + BCu = MLD_KECCAK_ROL(Ese, 2); + Asa = BCa ^ ((~BCe) & BCi); + Ase = BCe ^ ((~BCi) & BCo); + Asi = BCi ^ ((~BCo) & BCu); + Aso = BCo ^ ((~BCu) & BCa); + Asu = BCu ^ ((~BCa) & BCe); + } + + /* copyToState(state, A) */ + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} + +void mld_keccakf1600_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X1_NATIVE) + if (mld_keccak_f1600_x1_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X1_NATIVE */ + mld_keccakf1600_permute_c(state); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(keccakf1600) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_KECCAK_NROUNDS +#undef MLD_KECCAK_ROL diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/keccakf1600.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/keccakf1600.h new file mode 100644 index 0000000000..e56adc1561 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/keccakf1600.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_KECCAKF1600_H +#define MLD_FIPS202_KECCAKF1600_H +#include +#include "../cbmc.h" +#include "../common.h" +#include "fips202.h" + +#define MLD_KECCAK_LANES 25 +#define MLD_KECCAK_WAY 4 + +/* + * WARNING: + * The contents of this structure, including the placement + * and interleaving of Keccak lanes, are IMPLEMENTATION-DEFINED. + * The struct is only exposed here to allow its construction on the stack. + */ + +#define mld_keccakf1600_extract_bytes MLD_NAMESPACE(keccakf1600_extract_bytes) +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(data, length)) +); + +#define mld_keccakf1600_xor_bytes MLD_NAMESPACE(keccakf1600_xor_bytes) +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#define mld_keccakf1600x4_extract_bytes \ + MLD_NAMESPACE(keccakf1600x4_extract_bytes) +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + requires(memory_no_alias(data1, length)) + requires(memory_no_alias(data2, length)) + requires(memory_no_alias(data3, length)) + assigns(memory_slice(data0, length)) + assigns(memory_slice(data1, length)) + assigns(memory_slice(data2, length)) + assigns(memory_slice(data3, length)) +); + +#define mld_keccakf1600x4_xor_bytes MLD_NAMESPACE(keccakf1600x4_xor_bytes) +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + /* Case 1: all input buffers are distinct; Case 2: All input buffers are the same */ + requires((data0 == data1 && + data0 == data2 && + data0 == data3) || + (memory_no_alias(data1, length) && + memory_no_alias(data2, length) && + memory_no_alias(data3, length))) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600x4_permute MLD_NAMESPACE(keccakf1600x4_permute) +void mld_keccakf1600x4_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600_permute MLD_NAMESPACE(keccakf1600_permute) +void mld_keccakf1600_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#endif /* !MLD_FIPS202_KECCAKF1600_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/auto.h new file mode 100644 index 0000000000..4375cc1976 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/auto.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [HYBRID] + * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64 + * Becker, Kannwischer + * https://eprint.iacr.org/2022/1243 + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +#define MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* Default FIPS202 assembly profile for AArch64 systems */ + +/* + * Default logic to decide which implementation to use. + * + */ + +/* + * Keccak-f1600 + * + * - On Arm-based Apple CPUs, we pick a pure Neon implementation. + * - Otherwise, unless MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, + * we use lazy-rotation scalar assembly from @[HYBRID]. + * - Otherwise, if MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, we + * fall back to the standard C implementation. + */ +#if defined(__ARM_FEATURE_SHA3) && defined(__APPLE__) +#include "x1_v84a.h" +#elif !defined(MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER) +#include "x1_scalar.h" +#endif + +/* + * Keccak-f1600x2/x4 + * + * The optimal implementation is highly CPU-specific; see @[HYBRID]. + * + * For now, if v8.4-A is not implemented, we fall back to Keccak-f1600. + * If v8.4-A is implemented and we are on an Apple CPU, we use a plain + * Neon-based implementation. + * If v8.4-A is implemented and we are not on an Apple CPU, we use a + * scalar/Neon/Neon hybrid. + * The reason for this distinction is that Apple CPUs appear to implement + * the SHA3 instructions on all SIMD units, while Arm CPUs prior to Cortex-X4 + * don't, and ordinary Neon instructions are still needed. + */ +#if defined(__ARM_FEATURE_SHA3) +/* + * For Apple-M cores, we use a plain implementation leveraging SHA3 + * instructions only. + */ +#if defined(__APPLE__) +#include "x2_v84a.h" +#else +#include "x4_v8a_v84a_scalar.h" +#endif + +#else /* __ARM_FEATURE_SHA3 */ + +#include "x4_v8a_scalar.h" + +#endif /* !__ARM_FEATURE_SHA3 */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h new file mode 100644 index 0000000000..20f6168038 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#define MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H + +#include +#include "../../../../cbmc.h" +#include "../../../../common.h" + + +#define mld_keccakf1600_round_constants \ + MLD_NAMESPACE(keccakf1600_round_constants) +extern const uint64_t mld_keccakf1600_round_constants[]; + +#define mld_keccak_f1600_x1_scalar_asm MLD_NAMESPACE(keccak_f1600_x1_scalar_asm) +void mld_keccak_f1600_x1_scalar_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x1_v84a_asm MLD_NAMESPACE(keccak_f1600_x1_v84a_asm) +void mld_keccak_f1600_x1_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x2_v84a_asm MLD_NAMESPACE(keccak_f1600_x2_v84a_asm) +void mld_keccak_f1600_x2_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 2)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 2)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c new file mode 100644 index 0000000000..05e9cbfeec --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../../common.h" + +#if (defined(MLD_FIPS202_AARCH64_NEED_X1_SCALAR) || \ + defined(MLD_FIPS202_AARCH64_NEED_X1_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X2_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID)) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "fips202_native_aarch64.h" + +MLD_ALIGN const uint64_t mld_keccakf1600_round_constants[] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, +}; + +#else /* (MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_aarch64_round_constants) + +#endif /* !((MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/x1_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/x1_scalar.h new file mode 100644 index 0000000000..681b991371 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/x1_scalar.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_SCALAR + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + mld_keccak_f1600_x1_scalar_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/x1_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/x1_v84a.h new file mode 100644 index 0000000000..d15c8c26f3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/x1_v84a.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x1_v84a_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/x2_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/x2_v84a.h new file mode 100644 index 0000000000..16c22fa1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/x2_v84a.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X2_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" + + +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x2_v84a_asm(state + 0 * 25, mld_keccakf1600_round_constants); + mld_keccak_f1600_x2_v84a_asm(state + 2 * 25, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h new file mode 100644 index 0000000000..0f7f8fe499 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(state, + mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h new file mode 100644 index 0000000000..3da883b762 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm( + state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/api.h new file mode 100644 index 0000000000..4625c9a1ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/api.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_API_H +#define MLD_FIPS202_NATIVE_API_H +/* + * FIPS-202 native interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + */ + +#include +#include "../../cbmc.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* + * This is the C<->native interface allowing for the drop-in + * of custom Keccak-F1600 implementations. + * + * A _backend_ is a specific implementation of parts of this interface. + * + * You can replace 1-fold or 4-fold batched Keccak-F1600. + * To enable, set MLD_USE_FIPS202_X1_NATIVE or MLD_USE_FIPS202_X4_NATIVE + * in your backend, and define the inline wrappers mld_keccak_f1600_x1_native() + * and/or mld_keccak_f1600_x4_native(), respectively, to forward to your + * implementation. + */ + +#if defined(MLD_USE_FIPS202_X1_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 1)) +); +#endif /* MLD_USE_FIPS202_X1_NATIVE */ +#if defined(MLD_USE_FIPS202_X4_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 4)) +); +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + +#endif /* !MLD_FIPS202_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/auto.h new file mode 100644 index 0000000000..0a09c733c8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/auto.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AUTO_H +#define MLD_FIPS202_NATIVE_AUTO_H + +/* + * Default FIPS202 backend + */ +#include "../../sys.h" + +#if defined(MLD_SYS_AARCH64) +#include "aarch64/auto.h" +#endif + +#if defined(MLD_SYS_X86_64) && defined(MLD_SYS_X86_64_AVX2) +#include "x86_64/xkcp.h" +#endif + +#endif /* !MLD_FIPS202_NATIVE_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c new file mode 100644 index 0000000000..4eaad2fd66 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* +Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, +Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby +denoted as "the implementer". + +For more information, feedback or questions, please refer to our websites: +http://keccak.noekeon.org/ +http://keyak.noekeon.org/ +http://ketje.noekeon.org/ + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +/* + * Changes for mlkem-native/mldsa-native: + * - copyFromState and copyToState operate on uninterleaved + * Keccak states in memory. + */ + +#include "../../../../common.h" +#if defined(MLD_FIPS202_X86_64_XKCP) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include + +#include "KeccakP_1600_times4_SIMD256.h" + +#ifndef MLD_SYS_LITTLE_ENDIAN +#error Expecting a little-endian platform +#endif + +#define ANDnu256(a, b) _mm256_andnot_si256(a, b) +#define CONST256(a) _mm256_load_si256((const __m256i *)&(a)) +#define CONST256_64(a) (__m256i) _mm256_broadcast_sd((const double *)(&a)) +#define ROL64in256(d, a, o) \ + d = _mm256_or_si256(_mm256_slli_epi64(a, o), _mm256_srli_epi64(a, 64 - (o))) +#define ROL64in256_8(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho8)) +#define ROL64in256_56(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho56)) +static const uint64_t rho8[4] = {0x0605040302010007, 0x0E0D0C0B0A09080F, + 0x1615141312111017, 0x1E1D1C1B1A19181F}; +static const uint64_t rho56[4] = {0x0007060504030201, 0x080F0E0D0C0B0A09, + 0x1017161514131211, 0x181F1E1D1C1B1A19}; +#define STORE256(a, b) _mm256_store_si256((__m256i *)&(a), b) +#define XOR256(a, b) _mm256_xor_si256(a, b) +#define XOReq256(a, b) a = _mm256_xor_si256(a, b) + +#define SnP_laneLengthInBytes 8 + +#define declareABCDE \ + __m256i Aba, Abe, Abi, Abo, Abu; \ + __m256i Aga, Age, Agi, Ago, Agu; \ + __m256i Aka, Ake, Aki, Ako, Aku; \ + __m256i Ama, Ame, Ami, Amo, Amu; \ + __m256i Asa, Ase, Asi, Aso, Asu; \ + __m256i Bba, Bbe, Bbi, Bbo, Bbu; \ + __m256i Bga, Bge, Bgi, Bgo, Bgu; \ + __m256i Bka, Bke, Bki, Bko, Bku; \ + __m256i Bma, Bme, Bmi, Bmo, Bmu; \ + __m256i Bsa, Bse, Bsi, Bso, Bsu; \ + __m256i Ca, Ce, Ci, Co, Cu; \ + __m256i Ca1, Ce1, Ci1, Co1, Cu1; \ + __m256i Da, De, Di, Do, Du; \ + __m256i Eba, Ebe, Ebi, Ebo, Ebu; \ + __m256i Ega, Ege, Egi, Ego, Egu; \ + __m256i Eka, Eke, Eki, Eko, Eku; \ + __m256i Ema, Eme, Emi, Emo, Emu; \ + __m256i Esa, Ese, Esi, Eso, Esu; + +#define prepareTheta \ + Ca = XOR256(Aba, XOR256(Aga, XOR256(Aka, XOR256(Ama, Asa)))); \ + Ce = XOR256(Abe, XOR256(Age, XOR256(Ake, XOR256(Ame, Ase)))); \ + Ci = XOR256(Abi, XOR256(Agi, XOR256(Aki, XOR256(Ami, Asi)))); \ + Co = XOR256(Abo, XOR256(Ago, XOR256(Ako, XOR256(Amo, Aso)))); \ + Cu = XOR256(Abu, XOR256(Agu, XOR256(Aku, XOR256(Amu, Asu)))); + +/* + * --- Theta Rho Pi Chi Iota Prepare-theta + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + Ca = E##ba; \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + Ce = E##be; \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + Ci = E##bi; \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + Co = E##bo; \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + Cu = E##bu; \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(Ca, E##ga); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(Ce, E##ge); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + XOReq256(Ci, E##gi); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + XOReq256(Co, E##go); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + XOReq256(Cu, E##gu); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(Ca, E##ka); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(Ce, E##ke); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + XOReq256(Ci, E##ki); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + XOReq256(Co, E##ko); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + XOReq256(Cu, E##ku); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(Ca, E##ma); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(Ce, E##me); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + XOReq256(Ci, E##mi); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + XOReq256(Co, E##mo); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + XOReq256(Cu, E##mu); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(Ca, E##sa); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(Ce, E##se); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + XOReq256(Ci, E##si); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + XOReq256(Co, E##so); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); \ + XOReq256(Cu, E##su); + + +/* + * --- Theta Rho Pi Chi Iota + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIota(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); + + +static MLD_ALIGN const uint64_t keccakf1600RoundConstants[24] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +#include + +#define copyFromState(X, state) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m256i _idx = \ + _mm256_set_epi64x((long long)&state64[75], (long long)&state64[50], \ + (long long)&state64[25], (long long)&state64[0]); \ + X##ba = _mm256_i64gather_epi64((long long *)(0 * 8), _idx, 1); \ + X##be = _mm256_i64gather_epi64((long long *)(1 * 8), _idx, 1); \ + X##bi = _mm256_i64gather_epi64((long long *)(2 * 8), _idx, 1); \ + X##bo = _mm256_i64gather_epi64((long long *)(3 * 8), _idx, 1); \ + X##bu = _mm256_i64gather_epi64((long long *)(4 * 8), _idx, 1); \ + X##ga = _mm256_i64gather_epi64((long long *)(5 * 8), _idx, 1); \ + X##ge = _mm256_i64gather_epi64((long long *)(6 * 8), _idx, 1); \ + X##gi = _mm256_i64gather_epi64((long long *)(7 * 8), _idx, 1); \ + X##go = _mm256_i64gather_epi64((long long *)(8 * 8), _idx, 1); \ + X##gu = _mm256_i64gather_epi64((long long *)(9 * 8), _idx, 1); \ + X##ka = _mm256_i64gather_epi64((long long *)(10 * 8), _idx, 1); \ + X##ke = _mm256_i64gather_epi64((long long *)(11 * 8), _idx, 1); \ + X##ki = _mm256_i64gather_epi64((long long *)(12 * 8), _idx, 1); \ + X##ko = _mm256_i64gather_epi64((long long *)(13 * 8), _idx, 1); \ + X##ku = _mm256_i64gather_epi64((long long *)(14 * 8), _idx, 1); \ + X##ma = _mm256_i64gather_epi64((long long *)(15 * 8), _idx, 1); \ + X##me = _mm256_i64gather_epi64((long long *)(16 * 8), _idx, 1); \ + X##mi = _mm256_i64gather_epi64((long long *)(17 * 8), _idx, 1); \ + X##mo = _mm256_i64gather_epi64((long long *)(18 * 8), _idx, 1); \ + X##mu = _mm256_i64gather_epi64((long long *)(19 * 8), _idx, 1); \ + X##sa = _mm256_i64gather_epi64((long long *)(20 * 8), _idx, 1); \ + X##se = _mm256_i64gather_epi64((long long *)(21 * 8), _idx, 1); \ + X##si = _mm256_i64gather_epi64((long long *)(22 * 8), _idx, 1); \ + X##so = _mm256_i64gather_epi64((long long *)(23 * 8), _idx, 1); \ + X##su = _mm256_i64gather_epi64((long long *)(24 * 8), _idx, 1); \ + } while (0); + +#define SCATTER_STORE256(state, idx, v) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m128d t = _mm_castsi128_pd(_mm256_castsi256_si128((v))); \ + _mm_storel_pd((double *)&state64[0 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[25 + (idx)], t); \ + t = _mm_castsi128_pd(_mm256_extracti128_si256((v), 1)); \ + _mm_storel_pd((double *)&state64[50 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[75 + (idx)], t); \ + } while (0) + +#define copyToState(state, X) \ + SCATTER_STORE256(state, 0, X##ba); \ + SCATTER_STORE256(state, 1, X##be); \ + SCATTER_STORE256(state, 2, X##bi); \ + SCATTER_STORE256(state, 3, X##bo); \ + SCATTER_STORE256(state, 4, X##bu); \ + SCATTER_STORE256(state, 5, X##ga); \ + SCATTER_STORE256(state, 6, X##ge); \ + SCATTER_STORE256(state, 7, X##gi); \ + SCATTER_STORE256(state, 8, X##go); \ + SCATTER_STORE256(state, 9, X##gu); \ + SCATTER_STORE256(state, 10, X##ka); \ + SCATTER_STORE256(state, 11, X##ke); \ + SCATTER_STORE256(state, 12, X##ki); \ + SCATTER_STORE256(state, 13, X##ko); \ + SCATTER_STORE256(state, 14, X##ku); \ + SCATTER_STORE256(state, 15, X##ma); \ + SCATTER_STORE256(state, 16, X##me); \ + SCATTER_STORE256(state, 17, X##mi); \ + SCATTER_STORE256(state, 18, X##mo); \ + SCATTER_STORE256(state, 19, X##mu); \ + SCATTER_STORE256(state, 20, X##sa); \ + SCATTER_STORE256(state, 21, X##se); \ + SCATTER_STORE256(state, 22, X##si); \ + SCATTER_STORE256(state, 23, X##so); \ + SCATTER_STORE256(state, 24, X##su); + +#define copyStateVariables(X, Y) \ + X##ba = Y##ba; \ + X##be = Y##be; \ + X##bi = Y##bi; \ + X##bo = Y##bo; \ + X##bu = Y##bu; \ + X##ga = Y##ga; \ + X##ge = Y##ge; \ + X##gi = Y##gi; \ + X##go = Y##go; \ + X##gu = Y##gu; \ + X##ka = Y##ka; \ + X##ke = Y##ke; \ + X##ki = Y##ki; \ + X##ko = Y##ko; \ + X##ku = Y##ku; \ + X##ma = Y##ma; \ + X##me = Y##me; \ + X##mi = Y##mi; \ + X##mo = Y##mo; \ + X##mu = Y##mu; \ + X##sa = Y##sa; \ + X##se = Y##se; \ + X##si = Y##si; \ + X##so = Y##so; \ + X##su = Y##su; + +/* clang-format off */ +#define rounds24 \ + prepareTheta \ + thetaRhoPiChiIotaPrepareTheta( 0, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 1, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 2, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 3, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 4, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 5, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 6, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 7, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 8, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 9, E, A) \ + thetaRhoPiChiIotaPrepareTheta(10, A, E) \ + thetaRhoPiChiIotaPrepareTheta(11, E, A) \ + thetaRhoPiChiIotaPrepareTheta(12, A, E) \ + thetaRhoPiChiIotaPrepareTheta(13, E, A) \ + thetaRhoPiChiIotaPrepareTheta(14, A, E) \ + thetaRhoPiChiIotaPrepareTheta(15, E, A) \ + thetaRhoPiChiIotaPrepareTheta(16, A, E) \ + thetaRhoPiChiIotaPrepareTheta(17, E, A) \ + thetaRhoPiChiIotaPrepareTheta(18, A, E) \ + thetaRhoPiChiIotaPrepareTheta(19, E, A) \ + thetaRhoPiChiIotaPrepareTheta(20, A, E) \ + thetaRhoPiChiIotaPrepareTheta(21, E, A) \ + thetaRhoPiChiIotaPrepareTheta(22, A, E) \ + thetaRhoPiChiIota(23, E, A) +/* clang-format on */ + +void mld_keccakf1600x4_permute24(void *states) +{ + __m256i *statesAsLanes = (__m256i *)states; + declareABCDE copyFromState(A, statesAsLanes) + rounds24 copyToState(statesAsLanes, A) +} + +#else /* MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_avx2_keccakx4) + +#endif /* !(MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef ANDnu256 +#undef CONST256 +#undef CONST256_64 +#undef ROL64in256 +#undef ROL64in256_8 +#undef ROL64in256_56 +#undef STORE256 +#undef XOR256 +#undef XOReq256 +#undef SnP_laneLengthInBytes +#undef declareABCDE +#undef prepareTheta +#undef thetaRhoPiChiIotaPrepareTheta +#undef thetaRhoPiChiIota +#undef copyFromState +#undef SCATTER_STORE256 +#undef copyToState +#undef copyStateVariables +#undef rounds24 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h new file mode 100644 index 0000000000..3499d38e2c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H +#define MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H + +#include "../../../../common.h" + +#define mld_keccakf1600x4_permute24 \ + MLD_NAMESPACE(KeccakP1600times4_PermuteAll_24rounds) +void mld_keccakf1600x4_permute24(void *states); + +#endif /* !MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/x86_64/xkcp.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/x86_64/xkcp.h new file mode 100644 index 0000000000..c03642d7e0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/fips202/native/x86_64/xkcp.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_XKCP_H +#define MLD_FIPS202_NATIVE_X86_64_XKCP_H + +#include "../../../common.h" + +#define MLD_FIPS202_X86_64_XKCP + +#if !defined(__ASSEMBLER__) +#include +#include "../api.h" +#include "src/KeccakP_1600_times4_SIMD256.h" + +#define MLD_USE_FIPS202_X4_NATIVE +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_keccakf1600x4_permute24(state); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_X86_64_XKCP_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/meta.h new file mode 100644 index 0000000000..c6f6ad47b0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/meta.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_META_H +#define MLD_NATIVE_AARCH64_META_H + +/* Set of primitives that this backend replaces */ +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_AARCH64 + + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/arith_native_aarch64.h" + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + mld_ntt_asm(data, mld_aarch64_ntt_zetas_layer123456, + mld_aarch64_ntt_zetas_layer78); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + mld_intt_asm(data, mld_aarch64_intt_zetas_layer78, + mld_aarch64_intt_zetas_layer123456); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + if (len != MLDSA_N || + buflen % 24 != 0) /* NEON support is mandatory for AArch64 */ + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N, hence, this cast is safe. */ + return (int)mld_rej_uniform_asm(r, buf, buflen, mld_rej_uniform_table); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_32_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_88_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + mld_poly_caddq_asm(a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_32_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_88_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + return mld_poly_chknorm_asm(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_17_asm(r, buf, mld_polyz_unpack_17_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_19_asm(r, buf, mld_polyz_unpack_19_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t out[MLDSA_N], const int32_t in0[MLDSA_N], + const int32_t in1[MLDSA_N]) +{ + mld_poly_pointwise_montgomery_asm(out, in0, in1); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l4_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l5_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l7_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ +#endif /* !MLD_NATIVE_AARCH64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/src/aarch64_zetas.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/src/aarch64_zetas.c new file mode 100644 index 0000000000..9ab7b9a68c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/src/aarch64_zetas.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Table of zeta values used in the AArch64 forward NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer123456[] = { + -3572223, -915382907, 3765607, 964937599, 3761513, 963888510, + -3201494, -820383522, -2883726, -738955404, -3145678, -806080660, + -3201430, -820367122, 0, 0, -601683, -154181397, + -3370349, -863652652, -4063053, -1041158200, 3602218, 923069133, + 3182878, 815613168, 2740543, 702264730, -3586446, -919027554, + 0, 0, 3542485, 907762539, 2663378, 682491182, + -1674615, -429120452, -3110818, -797147778, 2101410, 538486762, + 3704823, 949361686, 1159875, 297218217, 0, 0, + 2682288, 687336873, -3524442, -903139016, -434125, -111244624, + 394148, 101000509, 928749, 237992130, 1095468, 280713909, + -3506380, -898510625, 0, 0, 2129892, 545785280, + 676590, 173376332, -1335936, -342333886, 2071829, 530906624, + -4018989, -1029866791, 3241972, 830756018, 2156050, 552488273, + 0, 0, 3764867, 964747974, -3227876, -827143915, + 1714295, 439288460, 3415069, 875112161, 1759347, 450833045, + -817536, -209493775, -3574466, -915957677, 0, 0, + -1005239, -257592709, 2453983, 628833668, 1460718, 374309300, + 3756790, 962678241, -1935799, -496048908, -1716988, -439978542, + -3950053, -1012201926, 0, 0, 557458, 142848732, + -642628, -164673562, -3585098, -918682129, -2897314, -742437332, + 3192354, 818041395, 556856, 142694469, 3870317, 991769559, + 0, 0, -1221177, -312926867, 2815639, 721508096, + 2283733, 585207070, 2917338, 747568486, 1853806, 475038184, + 3345963, 857403734, 1858416, 476219497, 0, 0, +}; + +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer78[] = { + 3073009, 1277625, -2635473, 3852015, 787459213, + 327391679, -675340520, 987079667, 1753, -2659525, + 2660408, -59148, 449207, -681503850, 681730119, + -15156688, -1935420, -1455890, -1780227, 2772600, + -495951789, -373072124, -456183549, 710479343, 4183372, + -3222807, -3121440, -274060, 1071989969, -825844983, + -799869667, -70227934, 1182243, 636927, -3956745, + -3284915, 302950022, 163212680, -1013916752, -841760171, + 87208, -3965306, -2296397, -3716946, 22347069, + -1016110510, -588452222, -952468207, 2508980, 2028118, + 1937570, -3815725, 642926661, 519705671, 496502727, + -977780347, -27812, 1009365, -1979497, -3956944, + -7126831, 258649997, -507246529, -1013967746, 822541, + -2454145, 1596822, -3759465, 210776307, -628875181, + 409185979, -963363710, 2811291, -2983781, -1109516, + 4158088, 720393920, -764594519, -284313712, 1065510939, + -1685153, 2678278, -3551006, -250446, -431820817, + 686309310, -909946047, -64176841, -3410568, -3768948, + 635956, -2455377, -873958779, -965793731, 162963861, + -629190881, 1528066, 482649, 1148858, -2962264, + 391567239, 123678909, 294395108, -759080783, -4146264, + 2192938, 2387513, -268456, -1062481036, 561940831, + 611800717, -68791907, -1772588, -1727088, -3611750, + -3180456, -454226054, -442566669, -925511710, -814992530, + -565603, 169688, 2462444, -3334383, -144935890, + 43482586, 631001801, -854436357, 3747250, 1239911, + 3195676, 1254190, 960233614, 317727459, 818892658, + 321386456, 2296099, -3838479, 2642980, -12417, + 588375860, -983611064, 677264190, -3181859, -4166425, + -3488383, 1987814, -3197248, -1067647297, -893898890, + 509377762, -819295484, 2998219, -89301, -1354892, + -1310261, 768294260, -22883400, -347191365, -335754661, + 141835, 2513018, 613238, -2218467, 36345249, + 643961400, 157142369, -568482643, 1736313, 235407, + -3250154, 3258457, 444930577, 60323094, -832852657, + 834980303, -458740, 4040196, 2039144, -818761, + -117552223, 1035301089, 522531086, -209807681, -1921994, + -3472069, -1879878, -2178965, -492511373, -889718424, + -481719139, -558360247, -2579253, 1787943, -2391089, + -2254727, -660934133, 458160776, -612717067, -577774276, + -1623354, -2374402, 586241, 527981, -415984810, + -608441020, 150224382, 135295244, 2105286, -2033807, + -1179613, -2743411, 539479988, -521163479, -302276083, + -702999655, 3482206, -4182915, -1300016, -2362063, + 892316032, -1071872863, -333129378, -605279149, -1476985, + 2491325, 507927, -724804, -378477722, 638402564, + 130156402, -185731180, 1994046, -1393159, -1187885, + -1834526, 510974714, -356997292, -304395785, -470097680, + -1317678, 2461387, 3035980, 621164, -337655269, + 630730945, 777970524, 159173408, -3033742, 2647994, + -2612853, 749577, -777397036, 678549029, -669544140, + 192079267, -338420, 3009748, 4148469, -4022750, + -86720197, 771248568, 1063046068, -1030830548, 3901472, + -1226661, 2925816, 3374250, 999753034, -314332144, + 749740976, 864652284, 3980599, -1615530, 1665318, + 1163598, 1020029345, -413979908, 426738094, 298172236, + 2569011, 1723229, 2028038, -3369273, 658309618, + 441577800, 519685171, -863376927, 1356448, -2775755, + 2683270, -2778788, 347590090, -711287812, 687588511, + -712065019, 3994671, -1370517, 3363542, 545376, + 1023635298, -351195274, 861908357, 139752717, -11879, + 3020393, 214880, -770441, -3043996, 773976352, + 55063046, -197425671, -3467665, 2312838, -653275, + -459163, -888589898, 592665232, -167401858, -117660617, + 3105558, 508145, 860144, 140244, 795799901, + 130212265, 220412084, 35937555, -1103344, -553718, + 3430436, -1514152, -282732136, -141890356, 879049958, + -388001774, 348812, -327848, 1011223, -2354215, + 89383150, -84011120, 259126110, -603268097, -2185084, + 2358373, -3014420, 2926054, -559928242, 604333585, + -772445769, 749801963, 3123762, -2193087, -1716814, + -392707, 800464680, -561979013, -439933955, -100631253, + -3818627, -1922253, -2236726, 1744507, -978523985, + -492577742, -573161516, 447030292, -303005, -3974485, + 1900052, 1054478, -77645096, -1018462631, 486888731, + 270210213, 3531229, -3773731, -781875, -731434, + 904878186, -967019376, -200355636, -187430119, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer78[] = { + -1744507, 2236726, 1922253, 3818627, -447030292, 573161516, + 492577742, 978523985, 731434, 781875, 3773731, -3531229, + 187430119, 200355636, 967019376, -904878186, -1054478, -1900052, + 3974485, 303005, -270210213, -486888731, 1018462631, 77645096, + 2354215, -1011223, 327848, -348812, 603268097, -259126110, + 84011120, -89383150, 392707, 1716814, 2193087, -3123762, + 100631253, 439933955, 561979013, -800464680, -2926054, 3014420, + -2358373, 2185084, -749801963, 772445769, -604333585, 559928242, + 459163, 653275, -2312838, 3467665, 117660617, 167401858, + -592665232, 888589898, 1514152, -3430436, 553718, 1103344, + 388001774, -879049958, 141890356, 282732136, -140244, -860144, + -508145, -3105558, -35937555, -220412084, -130212265, -795799901, + 2778788, -2683270, 2775755, -1356448, 712065019, -687588511, + 711287812, -347590090, 770441, -214880, -3020393, 11879, + 197425671, -55063046, -773976352, 3043996, -545376, -3363542, + 1370517, -3994671, -139752717, -861908357, 351195274, -1023635298, + -3374250, -2925816, 1226661, -3901472, -864652284, -749740976, + 314332144, -999753034, 3369273, -2028038, -1723229, -2569011, + 863376927, -519685171, -441577800, -658309618, -1163598, -1665318, + 1615530, -3980599, -298172236, -426738094, 413979908, -1020029345, + -621164, -3035980, -2461387, 1317678, -159173408, -777970524, + -630730945, 337655269, 4022750, -4148469, -3009748, 338420, + 1030830548, -1063046068, -771248568, 86720197, -749577, 2612853, + -2647994, 3033742, -192079267, 669544140, -678549029, 777397036, + 2362063, 1300016, 4182915, -3482206, 605279149, 333129378, + 1071872863, -892316032, 1834526, 1187885, 1393159, -1994046, + 470097680, 304395785, 356997292, -510974714, 724804, -507927, + -2491325, 1476985, 185731180, -130156402, -638402564, 378477722, + 2254727, 2391089, -1787943, 2579253, 577774276, 612717067, + -458160776, 660934133, 2743411, 1179613, 2033807, -2105286, + 702999655, 302276083, 521163479, -539479988, -527981, -586241, + 2374402, 1623354, -135295244, -150224382, 608441020, 415984810, + -3258457, 3250154, -235407, -1736313, -834980303, 832852657, + -60323094, -444930577, 2178965, 1879878, 3472069, 1921994, + 558360247, 481719139, 889718424, 492511373, 818761, -2039144, + -4040196, 458740, 209807681, -522531086, -1035301089, 117552223, + 3197248, -1987814, 3488383, 4166425, 819295484, -509377762, + 893898890, 1067647297, 2218467, -613238, -2513018, -141835, + 568482643, -157142369, -643961400, -36345249, 1310261, 1354892, + 89301, -2998219, 335754661, 347191365, 22883400, -768294260, + 3334383, -2462444, -169688, 565603, 854436357, -631001801, + -43482586, 144935890, 12417, -2642980, 3838479, -2296099, + 3181859, -677264190, 983611064, -588375860, -1254190, -3195676, + -1239911, -3747250, -321386456, -818892658, -317727459, -960233614, + 2962264, -1148858, -482649, -1528066, 759080783, -294395108, + -123678909, -391567239, 3180456, 3611750, 1727088, 1772588, + 814992530, 925511710, 442566669, 454226054, 268456, -2387513, + -2192938, 4146264, 68791907, -611800717, -561940831, 1062481036, + -4158088, 1109516, 2983781, -2811291, -1065510939, 284313712, + 764594519, -720393920, 2455377, -635956, 3768948, 3410568, + 629190881, -162963861, 965793731, 873958779, 250446, 3551006, + -2678278, 1685153, 64176841, 909946047, -686309310, 431820817, + 3815725, -1937570, -2028118, -2508980, 977780347, -496502727, + -519705671, -642926661, 3759465, -1596822, 2454145, -822541, + 963363710, -409185979, 628875181, -210776307, 3956944, 1979497, + -1009365, 27812, 1013967746, 507246529, -258649997, 7126831, + 274060, 3121440, 3222807, -4183372, 70227934, 799869667, + 825844983, -1071989969, 3716946, 2296397, 3965306, -87208, + 952468207, 588452222, 1016110510, -22347069, 3284915, 3956745, + -636927, -1182243, 841760171, 1013916752, -163212680, -302950022, + -3852015, 2635473, -1277625, -3073009, -987079667, 675340520, + -327391679, -787459213, -2772600, 1780227, 1455890, 1935420, + -710479343, 456183549, 373072124, 495951789, 59148, -2660408, + 2659525, -1753, 15156688, -681730119, 681503850, -449207, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer123456[] = { + -2283733, -585207070, 0, 0, -1858416, -476219497, + -3345963, -857403734, -2815639, -721508096, 0, 0, + -1853806, -475038184, -2917338, -747568486, 3585098, 918682129, + 0, 0, -3870317, -991769559, -556856, -142694469, + 642628, 164673562, 0, 0, -3192354, -818041395, + 2897314, 742437332, -1460718, -374309300, 0, 0, + 3950053, 1012201926, 1716988, 439978542, -2453983, -628833668, + 0, 0, 1935799, 496048908, -3756790, -962678241, + -1714295, -439288460, 0, 0, 3574466, 915957677, + 817536, 209493775, 3227876, 827143915, 0, 0, + -1759347, -450833045, -3415069, -875112161, 1335936, 342333886, + 0, 0, -2156050, -552488273, -3241972, -830756018, + -676590, -173376332, 0, 0, 4018989, 1029866791, + -2071829, -530906624, 434125, 111244624, 0, 0, + 3506380, 898510625, -1095468, -280713909, 3524442, 903139016, + 0, 0, -928749, -237992130, -394148, -101000509, + 1674615, 429120452, 0, 0, -1159875, -297218217, + -3704823, -949361686, -2663378, -682491182, 0, 0, + -2101410, -538486762, 3110818, 797147778, 4063053, 1041158200, + 0, 0, 3586446, 919027554, -2740543, -702264730, + 3370349, 863652652, 0, 0, -3182878, -815613168, + -3602218, -923069133, -294725, -75523344, -3761513, -963888510, + -3765607, -964937599, 3201430, 820367122, 3145678, 806080660, + 2883726, 738955404, 3201494, 820383522, 1221177, 312926867, + -557458, -142848732, 1005239, 257592709, -3764867, -964747974, + -2129892, -545785280, -2682288, -687336873, -3542485, -907762539, + 601683, 154181397, 0, 0, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_zetas) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h new file mode 100644 index 0000000000..e77f55014c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#define MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H + +#include +#include "../../../common.h" + +#define mld_aarch64_ntt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_ntt_zetas_layer123456) +#define mld_aarch64_ntt_zetas_layer78 MLD_NAMESPACE(aarch64_ntt_zetas_layer78) + +#define mld_aarch64_intt_zetas_layer78 MLD_NAMESPACE(aarch64_intt_zetas_layer78) +#define mld_aarch64_intt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_intt_zetas_layer123456) + +extern const int32_t mld_aarch64_ntt_zetas_layer123456[]; +extern const int32_t mld_aarch64_ntt_zetas_layer78[]; + +extern const int32_t mld_aarch64_intt_zetas_layer78[]; +extern const int32_t mld_aarch64_intt_zetas_layer123456[]; + +#define mld_rej_uniform_table MLD_NAMESPACE(rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[]; +#define mld_rej_uniform_eta_table MLD_NAMESPACE(rej_uniform_eta_table) +extern const uint8_t mld_rej_uniform_eta_table[]; + +#define mld_polyz_unpack_17_indices MLD_NAMESPACE(polyz_unpack_17_indices) +extern const uint8_t mld_polyz_unpack_17_indices[]; +#define mld_polyz_unpack_19_indices MLD_NAMESPACE(polyz_unpack_19_indices) +extern const uint8_t mld_polyz_unpack_19_indices[]; + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_ntt_asm MLD_NAMESPACE(ntt_asm) +void mld_ntt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_intt_asm MLD_NAMESPACE(intt_asm) +void mld_intt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_rej_uniform_asm MLD_NAMESPACE(rej_uniform_asm) +uint64_t mld_rej_uniform_asm(int32_t *r, const uint8_t *buf, unsigned buflen, + const uint8_t *table); + +#define mld_rej_uniform_eta2_asm MLD_NAMESPACE(rej_uniform_eta2_asm) +uint64_t mld_rej_uniform_eta2_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_rej_uniform_eta4_asm MLD_NAMESPACE(rej_uniform_eta4_asm) +uint64_t mld_rej_uniform_eta4_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_poly_decompose_32_asm MLD_NAMESPACE(poly_decompose_32_asm) +void mld_poly_decompose_32_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_asm MLD_NAMESPACE(poly_decompose_88_asm) +void mld_poly_decompose_88_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_asm MLD_NAMESPACE(poly_caddq_asm) +void mld_poly_caddq_asm(int32_t *a); + +#define mld_poly_use_hint_32_asm MLD_NAMESPACE(poly_use_hint_32_asm) +void mld_poly_use_hint_32_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_asm MLD_NAMESPACE(poly_use_hint_88_asm) +void mld_poly_use_hint_88_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_asm MLD_NAMESPACE(poly_chknorm_asm) +int mld_poly_chknorm_asm(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_asm MLD_NAMESPACE(polyz_unpack_17_asm) +void mld_polyz_unpack_17_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_polyz_unpack_19_asm MLD_NAMESPACE(polyz_unpack_19_asm) +void mld_polyz_unpack_19_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_poly_pointwise_montgomery_asm \ + MLD_NAMESPACE(poly_pointwise_montgomery_asm) +void mld_poly_pointwise_montgomery_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l4_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l4_asm) +void mld_polyvecl_pointwise_acc_montgomery_l4_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l5_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l5_asm) +void mld_polyvecl_pointwise_acc_montgomery_l5_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l7_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l7_asm) +void mld_polyvecl_pointwise_acc_montgomery_l7_asm(int32_t *, const int32_t *, + const int32_t *); + +#endif /* !MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c new file mode 100644 index 0000000000..7ef915b587 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* Table of indices used for tbl instructions in polyz_unpack_{17,19}. */ + +MLD_ALIGN const uint8_t mld_polyz_unpack_17_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, + 9, 10, 11, 255, 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, + 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, 8, 9, 10, 255, + 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, 17, 18, 19, 255, +}; + +MLD_ALIGN const uint8_t mld_polyz_unpack_19_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 5, 6, 7, 255, 7, 8, 9, 255, + 10, 11, 12, 255, 12, 13, 14, 255, 15, 16, 17, 255, 17, 18, 19, 255, + 4, 5, 6, 255, 6, 7, 8, 255, 9, 10, 11, 255, 11, 12, 13, 255, + 14, 15, 16, 255, 16, 17, 18, 255, 19, 20, 21, 255, 21, 22, 23, 255, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_polyz_unpack_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c new file mode 100644 index 0000000000..cf21509cbf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by 16-bit rejection sampling (rej_eta). + * Adapted from ML-KEM for ML-DSA eta rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_eta_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 2, 3, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 4, 5, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 2, 3, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 7 */, + 6, 7, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 2, 3, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 11 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 13 */, + 2, 3, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 15 */, + 8, 9, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 16 */, + 0, 1, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 17 */, + 2, 3, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 18 */, + 0, 1, 2, 3, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 19 */, + 4, 5, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 20 */, + 0, 1, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 21 */, + 2, 3, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 22 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 23 */, + 6, 7, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 24 */, + 0, 1, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 25 */, + 2, 3, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 26 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 27 */, + 4, 5, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 28 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 29 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 30 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 255, 255, 255, 255, 255, 255 /* 31 */, + 10, 11, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 32 */, + 0, 1, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 33 */, + 2, 3, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 34 */, + 0, 1, 2, 3, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 35 */, + 4, 5, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 36 */, + 0, 1, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 37 */, + 2, 3, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 38 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 39 */, + 6, 7, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 40 */, + 0, 1, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 41 */, + 2, 3, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 42 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 43 */, + 4, 5, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 44 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 45 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 46 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 255, 255, 255, 255, 255, 255 /* 47 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 48 */, + 0, 1, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 49 */, + 2, 3, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 50 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 51 */, + 4, 5, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 52 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 53 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 54 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 55 */, + 6, 7, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 56 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 57 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 58 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 59 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 60 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 61 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 62 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 63 */, + 12, 13, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 64 */, + 0, 1, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 65 */, + 2, 3, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 66 */, + 0, 1, 2, 3, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 67 */, + 4, 5, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 68 */, + 0, 1, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 69 */, + 2, 3, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 70 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 71 */, + 6, 7, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 72 */, + 0, 1, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 73 */, + 2, 3, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 74 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 75 */, + 4, 5, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 76 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 77 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 78 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 255, 255, 255, 255, 255, 255 /* 79 */, + 8, 9, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 80 */, + 0, 1, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 81 */, + 2, 3, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 82 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 83 */, + 4, 5, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 84 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 85 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 86 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 87 */, + 6, 7, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 88 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 89 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 90 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 91 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 92 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 93 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 94 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 255, 255, 255, 255 /* 95 */, + 10, 11, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 96 */, + 0, 1, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 97 */, + 2, 3, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 98 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 99 */, + 4, 5, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 100 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 101 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 102 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 103 */, + 6, 7, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 104 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 105 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 106 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 107 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 108 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 109 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 110 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 255, 255, 255, 255 /* 111 */, + 8, 9, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 112 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 113 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 114 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 115 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 116 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 117 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 118 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 119 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 120 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 121 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 122 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 123 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 124 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 125 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 126 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 255, 255 /* 127 */, + 14, 15, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 128 */, + 0, 1, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 129 */, + 2, 3, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 130 */, + 0, 1, 2, 3, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 131 */, + 4, 5, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 132 */, + 0, 1, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 133 */, + 2, 3, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 134 */, + 0, 1, 2, 3, 4, 5, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 135 */, + 6, 7, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 136 */, + 0, 1, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 137 */, + 2, 3, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 138 */, + 0, 1, 2, 3, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 139 */, + 4, 5, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 140 */, + 0, 1, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 141 */, + 2, 3, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 142 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 14, 15, 255, 255, 255, 255, 255, 255 /* 143 */, + 8, 9, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 144 */, + 0, 1, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 145 */, + 2, 3, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 146 */, + 0, 1, 2, 3, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 147 */, + 4, 5, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 148 */, + 0, 1, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 149 */, + 2, 3, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 150 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 151 */, + 6, 7, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 152 */, + 0, 1, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 153 */, + 2, 3, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 154 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 155 */, + 4, 5, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 156 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 157 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 158 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 14, 15, 255, 255, 255, 255 /* 159 */, + 10, 11, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 160 */, + 0, 1, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 161 */, + 2, 3, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 162 */, + 0, 1, 2, 3, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 163 */, + 4, 5, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 164 */, + 0, 1, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 165 */, + 2, 3, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 166 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 167 */, + 6, 7, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 168 */, + 0, 1, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 169 */, + 2, 3, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 170 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 171 */, + 4, 5, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 172 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 173 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 174 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 14, 15, 255, 255, 255, 255 /* 175 */, + 8, 9, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 176 */, + 0, 1, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 177 */, + 2, 3, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 178 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 179 */, + 4, 5, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 180 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 181 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 182 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 183 */, + 6, 7, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 184 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 185 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 186 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 187 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 188 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 189 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 190 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 14, 15, 255, 255 /* 191 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 192 */, + 0, 1, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 193 */, + 2, 3, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 194 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 195 */, + 4, 5, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 196 */, + 0, 1, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 197 */, + 2, 3, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 198 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 199 */, + 6, 7, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 200 */, + 0, 1, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 201 */, + 2, 3, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 202 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 203 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 204 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 205 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 206 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 207 */, + 8, 9, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 208 */, + 0, 1, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 209 */, + 2, 3, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 210 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 211 */, + 4, 5, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 212 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 213 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 214 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 215 */, + 6, 7, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 216 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 217 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 218 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 219 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 220 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 221 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 222 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 14, 15, 255, 255 /* 223 */, + 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 224 */, + 0, 1, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 225 */, + 2, 3, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 226 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 227 */, + 4, 5, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 228 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 229 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 230 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 231 */, + 6, 7, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 232 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 233 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 234 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 235 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 236 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 237 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 238 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 14, 15, 255, 255 /* 239 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 240 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 241 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 242 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 243 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 244 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 245 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 246 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 247 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 248 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 249 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 250 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 251 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 252 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 253 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 254 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 255 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_eta_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/src/rej_uniform_table.c new file mode 100644 index 0000000000..65bc3b78d3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/aarch64/src/rej_uniform_table.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by rejection sampling of the public matrix. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 7 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 11 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 13 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 15 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/api.h new file mode 100644 index 0000000000..0f1fdeb168 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/api.h @@ -0,0 +1,594 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_API_H +#define MLD_NATIVE_API_H +/* + * Native arithmetic interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + * + * To ensure consistency with backends, the header will be + * included automatically after inclusion of the active + * backend, to ensure consistency of function signatures, + * and run sanity checks. + */ + +#include +#include "../cbmc.h" +#include "../common.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* Bound on absolute value of coefficients after NTT. + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) + +/* Absolute exclusive upper bound for the output of the inverse NTT + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_INTT_BOUND MLDSA_Q + +/* Absolute bound for range of mld_reduce32() + * + * NOTE: This is the same bound as in reduce.h and has to be kept + * in sync. */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define REDUCE32_RANGE_MAX 6283009 +/* + * This is the C<->native interface allowing for the drop-in of + * native code for performance critical arithmetic components of ML-DSA. + * + * A _backend_ is a specific implementation of (part of) this interface. + * + * To add a function to a backend, define MLD_USE_NATIVE_XXX and + * implement `static inline xxx(...)` in the profile header. + */ + +/* + * Those functions are meant to be trivial wrappers around the chosen native + * implementation. The are static inline to avoid unnecessary calls. + * The macro before each declaration controls whether a native + * implementation is present. + */ + +#if defined(MLD_USE_NATIVE_NTT) +/************************************************* + * Name: mld_ntt_native + * + * Description: Computes negacyclic number-theoretic transform (NTT) of + * a polynomial in place. + * + * The input polynomial is assumed to be in normal order. + * The output polynomial is in bitreversed order. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_ntt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_NTT */ + + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) +/* + * This must only be set if NTT and INTT have native implementations + * that are adapted to the custom order. + */ +#if !defined(MLD_USE_NATIVE_NTT) || !defined(MLD_USE_NATIVE_INTT) +#error \ + "Invalid native profile: MLD_USE_NATIVE_NTT_CUSTOM_ORDER can only be \ +set if there are native implementations for NTT and INTT." +#endif + +/************************************************* + * Name: mlD_poly_permute_bitrev_to_custom + * + * Description: When MLD_USE_NATIVE_NTT_CUSTOM_ORDER is defined, + * convert a polynomial in NTT domain from bitreversed + * order to the custom order output by the native NTT. + * + * This must only be defined if there is native code for + * both the NTT and INTT. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + * + **************************************************/ +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t p[MLDSA_N]) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q))); +#endif /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + + +#if defined(MLD_USE_NATIVE_INTT) +/************************************************* + * Name: mld_intt_native + * + * Description: Computes inverse of negacyclic number-theoretic transform + *(NTT) of a polynomial in place. + * + * The input polynomial is in bitreversed order. + * The output polynomial is assumed to be in normal order. + * + * Arguments: - uint32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_intt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_INTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_INTT */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) +/************************************************* + * Name: mld_rej_uniform_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [0, MLDSA_Q-1] + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform mod q). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + * lengths. Otherwise, returns non-negative number of sampled 32-bit integers + * (at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= ( 5 * 168) && buflen % 3 == 0) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(r, 0, (unsigned) return_value, 0, MLDSA_Q)) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) +/************************************************* + * Name: mld_rej_uniform_eta2_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-2,+2]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-2, +2]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA2 */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) +/************************************************* + * Name: mld_rej_uniform_eta4_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-4,+4]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-4, +4]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) +/************************************************* + * Name: mld_poly_decompose_32_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/32. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: input/output polynomial. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_32 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) +/************************************************* + * Name: mld_poly_decompose_88_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/88. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: output polynomial with coefficients c0. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CADDQ) +/************************************************* + * Name: mld_poly_caddq_native + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *a: pointer to input/output polynomial + **************************************************/ +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_32) +/************************************************* + * Name: mld_poly_use_hint_32_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/32. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_32 */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) +/************************************************* + * Name: mld_poly_use_hint_88_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/88. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) +/************************************************* + * Name: mld_poly_chknorm_native + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const int32_t *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if the infinity norm is strictly smaller than B, and 1 + * otherwise. B must not be larger than MLDSA_Q - MLD_REDUCE32_RANGE_MAX. + **************************************************/ +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(0 <= B && B <= MLDSA_Q - REDUCE32_RANGE_MAX) + requires(array_bound(a, 0, MLDSA_N, -REDUCE32_RANGE_MAX, REDUCE32_RANGE_MAX)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == 0) == array_abs_bound(a, 0, MLDSA_N, B)) +); +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) +/************************************************* + * Name: mld_polyz_unpack_17_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^17. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_17 */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) +/************************************************* + * Name: mld_polyz_unpack_19_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^19. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_19 */ + +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) +/************************************************* + * Name: mld_poly_pointwise_montgomery_native + * + * Description: Pointwise multiplication of polynomials in NTT domain + * with Montgomery reduction. + * + * Computes c[i] = a[i] * b[i] * R^(-1) mod q for all i, + * where R = 2^32. + * + * Arguments: - int32_t c[MLDSA_N]: output polynomial + * - const int32_t a[MLDSA_N]: first input polynomial + * - const int32_t b[MLDSA_N]: second input polynomial + **************************************************/ +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(c, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(c, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(c, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l4_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 4. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 4 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 4 * MLDSA_N)) + requires(forall(l0, 0, 4, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 4, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l5_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 5. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 5 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 5 * MLDSA_N)) + requires(forall(l0, 0, 5, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 5, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l7_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 7. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 7 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 7 * MLDSA_N)) + requires(forall(l0, 0, 7, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 7, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 */ + +#endif /* !MLD_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/meta.h new file mode 100644 index 0000000000..0b46dd5791 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/meta.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_META_H +#define MLD_NATIVE_META_H + +/* + * Default arithmetic backend + */ +#include "../sys.h" + +#ifdef MLD_SYS_AARCH64 +#include "aarch64/meta.h" +#endif + +#ifdef MLD_SYS_X86_64_AVX2 +#include "x86_64/meta.h" +#endif + +#endif /* !MLD_NATIVE_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/meta.h new file mode 100644 index 0000000000..393374c06f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/meta.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_X86_64_META_H +#define MLD_NATIVE_X86_64_META_H + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_X86_64_DEFAULT + +#define MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +#if !defined(__ASSEMBLER__) +#include +#include "../../common.h" +#include "../api.h" +#include "src/arith_native_x86_64.h" + +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t data[MLDSA_N]) +{ + if (mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + mld_nttunpack_avx2(data); + } +} + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_ntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_invntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)mld_rej_uniform_avx2(r, buf); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_32_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_88_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_caddq_avx2(a); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_32_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_88_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + return mld_poly_chknorm_avx2(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_17_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_19_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_avx2(c, a, b, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l4_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l5_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l7_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_NATIVE_X86_64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h new file mode 100644 index 0000000000..08d5abf74a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#define MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#include "../../../common.h" + +#include +#include "consts.h" + +#define MLD_AVX2_REJ_UNIFORM_BUFLEN \ + (5 * 168) /* REJ_UNIFORM_NBLOCKS * SHAKE128_RATE */ + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) + +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_rej_uniform_table MLD_NAMESPACE(mld_rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[256][8]; + +#define mld_ntt_avx2 MLD_NAMESPACE(ntt_avx2) +void mld_ntt_avx2(int32_t *r, const int32_t *qdata) +/* This must be kept in sync with the HOL-Light specification + * in proofs/hol_light/x86_64/proofs/mldsa_ntt.ml */ +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, MLDSA_N, 8380417)) + requires(qdata == mld_qdata) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + /* check-magic: off */ + ensures(array_abs_bound(r, 0, MLDSA_N, 42035262)) + /* check-magic: on */ +); + +#define mld_invntt_avx2 MLD_NAMESPACE(invntt_avx2) +void mld_invntt_avx2(int32_t *r, const int32_t *mld_qdata); + +#define mld_nttunpack_avx2 MLD_NAMESPACE(nttunpack_avx2) +void mld_nttunpack_avx2(int32_t *r); + +#define mld_rej_uniform_avx2 MLD_NAMESPACE(mld_rej_uniform_avx2) +unsigned mld_rej_uniform_avx2(int32_t *r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]); + +#define mld_rej_uniform_eta2_avx2 MLD_NAMESPACE(mld_rej_uniform_eta2_avx2) +unsigned mld_rej_uniform_eta2_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]); + +#define mld_rej_uniform_eta4_avx2 MLD_NAMESPACE(mld_rej_uniform_eta4_avx2) +unsigned mld_rej_uniform_eta4_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]); + +#define mld_poly_decompose_32_avx2 MLD_NAMESPACE(mld_poly_decompose_32_avx2) +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_avx2 MLD_NAMESPACE(mld_poly_decompose_88_avx2) +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_avx2 MLD_NAMESPACE(poly_caddq_avx2) +void mld_poly_caddq_avx2(int32_t *r); + +#define mld_poly_use_hint_32_avx2 MLD_NAMESPACE(mld_poly_use_hint_32_avx2) +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_avx2 MLD_NAMESPACE(mld_poly_use_hint_88_avx2) +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_avx2 MLD_NAMESPACE(mld_poly_chknorm_avx2) +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_avx2 MLD_NAMESPACE(mld_polyz_unpack_17_avx2) +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a); + +#define mld_polyz_unpack_19_avx2 MLD_NAMESPACE(mld_polyz_unpack_19_avx2) +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a); + +#define mld_pointwise_avx2 MLD_NAMESPACE(pointwise_avx2) +void mld_pointwise_avx2(int32_t *c, const int32_t *a, const int32_t *b, + const int32_t *qdata); + +#define mld_pointwise_acc_l4_avx2 MLD_NAMESPACE(pointwise_acc_l4_avx2) +void mld_pointwise_acc_l4_avx2(int32_t c[MLDSA_N], const int32_t a[4][MLDSA_N], + const int32_t b[4][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l5_avx2 MLD_NAMESPACE(pointwise_acc_l5_avx2) +void mld_pointwise_acc_l5_avx2(int32_t c[MLDSA_N], const int32_t a[5][MLDSA_N], + const int32_t b[5][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l7_avx2 MLD_NAMESPACE(pointwise_acc_l7_avx2) +void mld_pointwise_acc_l7_avx2(int32_t c[MLDSA_N], const int32_t a[7][MLDSA_N], + const int32_t b[7][MLDSA_N], + const int32_t *qdata); + +#endif /* !MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/consts.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/consts.c new file mode 100644 index 0000000000..aaca3535ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/consts.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include "consts.h" + +/* + * Table of zeta values used in the AVX2 forward and inverse NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_qdata[624] = { + 8380417, 8380417, 8380417, 8380417, 8380417, + 8380417, 8380417, 8380417, 58728449, 58728449, + 58728449, 58728449, 58728449, 58728449, 58728449, + 58728449, -8395782, -8395782, -8395782, -8395782, + -8395782, -8395782, -8395782, -8395782, 41978, + 41978, 41978, 41978, 41978, 41978, + 41978, 41978, -151046689, 1830765815, -1929875198, + -1927777021, 1640767044, 1477910808, 1612161320, 1640734244, + 308362795, 308362795, 308362795, 308362795, -1815525077, + -1815525077, -1815525077, -1815525077, -1374673747, -1374673747, + -1374673747, -1374673747, -1091570561, -1091570561, -1091570561, + -1091570561, -1929495947, -1929495947, -1929495947, -1929495947, + 515185417, 515185417, 515185417, 515185417, -285697463, + -285697463, -285697463, -285697463, 625853735, 625853735, + 625853735, 625853735, 1727305304, 1727305304, 2082316400, + 2082316400, -1364982364, -1364982364, 858240904, 858240904, + 1806278032, 1806278032, 222489248, 222489248, -346752664, + -346752664, 684667771, 684667771, 1654287830, 1654287830, + -878576921, -878576921, -1257667337, -1257667337, -748618600, + -748618600, 329347125, 329347125, 1837364258, 1837364258, + -1443016191, -1443016191, -1170414139, -1170414139, -1846138265, + -1631226336, -1404529459, 1838055109, 1594295555, -1076973524, + -1898723372, -594436433, -202001019, -475984260, -561427818, + 1797021249, -1061813248, 2059733581, -1661512036, -1104976547, + -1750224323, -901666090, 418987550, 1831915353, -1925356481, + 992097815, 879957084, 2024403852, 1484874664, -1636082790, + -285388938, -1983539117, -1495136972, -950076368, -1714807468, + -952438995, -1574918427, 1350681039, -2143979939, 1599739335, + -1285853323, -993005454, -1440787840, 568627424, -783134478, + -588790216, 289871779, -1262003603, 2135294594, -1018755525, + -889861155, 1665705315, 1321868265, 1225434135, -1784632064, + 666258756, 675310538, -1555941048, -1999506068, -1499481951, + -695180180, -1375177022, 1777179795, 334803717, -178766299, + -518252220, 1957047970, 1146323031, -654783359, -1974159335, + 1651689966, 140455867, -1039411342, 1955560694, 1529189038, + -2131021878, -247357819, 1518161567, -86965173, 1708872713, + 1787797779, 1638590967, -120646188, -1669960606, -916321552, + 1155548552, 2143745726, 1210558298, -1261461890, -318346816, + 628664287, -1729304568, 1422575624, 1424130038, -1185330464, + 235321234, 168022240, 1206536194, 985155484, -894060583, + -898413, -1363460238, -605900043, 2027833504, 14253662, + 1014493059, 863641633, 1819892093, 2124962073, -1223601433, + -1920467227, -1637785316, -1536588520, 694382729, 235104446, + -1045062172, 831969619, -300448763, 756955444, -260312805, + 1554794072, 1339088280, -2040058690, -853476187, -2047270596, + -1723816713, -1591599803, -440824168, 1119856484, 1544891539, + 155290192, -973777462, 991903578, 912367099, -44694137, + 1176904444, -421552614, -818371958, 1747917558, -325927722, + 908452108, 1851023419, -1176751719, -1354528380, -72690498, + -314284737, 985022747, 963438279, -1078959975, 604552167, + -1021949428, 608791570, 173440395, -2126092136, -1316619236, + -1039370342, 6087993, -110126092, 565464272, -1758099917, + -1600929361, 879867909, -1809756372, 400711272, 1363007700, + 30313375, -326425360, 1683520342, -517299994, 2027935492, + -1372618620, 128353682, -1123881663, 137583815, -635454918, + -642772911, 45766801, 671509323, -2070602178, 419615363, + 1216882040, -270590488, -1276805128, 371462360, -1357098057, + -384158533, 827959816, -596344473, 702390549, -279505433, + -260424530, -71875110, -1208667171, -1499603926, 2036925262, + -540420426, 746144248, -1420958686, 2032221021, 1904936414, + 1257750362, 1926727420, 1931587462, 1258381762, 885133339, + 1629985060, 1967222129, 6363718, -1287922800, 1136965286, + 1779436847, 1116720494, 1042326957, 1405999311, 713994583, + 940195359, -1542497137, 2061661095, -883155599, 1726753853, + -1547952704, 394851342, 283780712, 776003547, 1123958025, + 201262505, 1934038751, 374860238, -3975713, 25847, + -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 1826347, 1826347, 1826347, + 2353451, 2353451, 2353451, 2353451, -359251, + -359251, -359251, -359251, -2091905, -2091905, + -2091905, -2091905, 3119733, 3119733, 3119733, + 3119733, -2884855, -2884855, -2884855, -2884855, + 3111497, 3111497, 3111497, 3111497, 2680103, + 2680103, 2680103, 2680103, 2725464, 2725464, + 1024112, 1024112, -1079900, -1079900, 3585928, + 3585928, -549488, -549488, -1119584, -1119584, + 2619752, 2619752, -2108549, -2108549, -2118186, + -2118186, -3859737, -3859737, -1399561, -1399561, + -3277672, -3277672, 1757237, 1757237, -19422, + -19422, 4010497, 4010497, 280005, 280005, + 2706023, 95776, 3077325, 3530437, -1661693, + -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, + -539299, -1699267, -1643818, 3505694, -3821735, + 3507263, -2140649, -1600420, 3699596, 811944, + 531354, 954230, 3881043, 3900724, -2556880, + 2071892, -2797779, -3930395, -3677745, -1452451, + 2176455, -1257611, -4083598, -3190144, -3632928, + 3412210, 2147896, -2967645, -411027, -671102, + -22981, -381987, 1852771, -3343383, 508951, + 44288, 904516, -3724342, 1653064, 2389356, + 759969, 189548, 3159746, -2409325, 1315589, + 1285669, -812732, -3019102, -3628969, -1528703, + -3041255, 3475950, -1585221, 1939314, -1000202, + -3157330, 126922, -983419, 2715295, -3693493, + -2477047, -1228525, -1308169, 1349076, -1430430, + 264944, 3097992, -1100098, 3958618, -8578, + -3249728, -210977, -1316856, -3553272, -1851402, + -177440, 1341330, -1584928, -1439742, -3881060, + 3839961, 2091667, -3342478, 266997, -3520352, + 900702, 495491, -655327, -3556995, 342297, + 3437287, 2842341, 4055324, -3767016, -2994039, + -1333058, -451100, -1279661, 1500165, -542412, + -2584293, -2013608, 1957272, -3183426, 810149, + -3038916, 2213111, -426683, -1667432, -2939036, + 183443, -554416, 3937738, 3407706, 2244091, + 2434439, -3759364, 1859098, -1613174, -3122442, + -525098, 286988, -3342277, 2691481, 1247620, + 1250494, 1869119, 1237275, 1312455, 1917081, + 777191, -2831860, -3724270, 2432395, 3369112, + 162844, 1652634, 3523897, -975884, 1723600, + -1104333, -2235985, -976891, 3919660, 1400424, + 2316500, -2446433, -1235728, -1197226, 909542, + -43260, 2031748, -768622, -2437823, 1735879, + -2590150, 2486353, 2635921, 1903435, -3318210, + 3306115, -2546312, 2235880, -1671176, 594136, + 2454455, 185531, 1616392, -3694233, 3866901, + 1717735, -1803090, -260646, -420899, 1612842, + -48306, -846154, 3817976, -3562462, 3513181, + -3193378, 819034, -522500, 3207046, -3595838, + 4108315, 203044, 1265009, 1595974, -3548272, + -1050970, -1430225, -1962642, -1374803, 3406031, + -1846953, -3776993, -164721, -1207385, 3014001, + -1799107, 269760, 472078, 1910376, -3833893, + -2286327, -3545687, -1362209, 1976782, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_consts) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/consts.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/consts.h new file mode 100644 index 0000000000..7fe08f454b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/consts.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#ifndef MLD_NATIVE_X86_64_SRC_CONSTS_H +#define MLD_NATIVE_X86_64_SRC_CONSTS_H +#include "../../../common.h" +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQ 0 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV 8 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV 16 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV 24 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV 32 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS 328 + +#ifndef __ASSEMBLER__ +#define mld_qdata MLD_NAMESPACE(qdata) +extern const int32_t mld_qdata[624]; +#endif + +#endif /* !MLD_NATIVE_X86_64_SRC_CONSTS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c new file mode 100644 index 0000000000..05d86d14fc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/************************************************* + * Name: mld_poly_caddq_avx2 + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *r: pointer to input/output polynomial + **************************************************/ +void mld_poly_caddq_avx2(int32_t *r) +{ + unsigned int i; + __m256i f, g; + const __m256i q = _mm256_set1_epi32(MLDSA_Q); + const __m256i zero = _mm256_setzero_si256(); + __m256i *rr = (__m256i *)r; + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256(&rr[i]); + g = _mm256_cmpgt_epi32(zero, f); + g = _mm256_and_si256(g, q); + f = _mm256_add_epi32(f, g); + _mm256_store_si256(&rr[i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_reduce) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c new file mode 100644 index 0000000000..50e2c7fa9b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B) +{ + unsigned int i; + __m256i f, t; + const __m256i bound = _mm256_set1_epi32(B - 1); + + t = _mm256_setzero_si256(); + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + f = _mm256_abs_epi32(f); + f = _mm256_cmpgt_epi32(f, bound); + t = _mm256_or_si256(t, f); + } + + return 1 - _mm256_testz_si256(t, t); +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_chknorm) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c new file mode 100644 index 0000000000..76846bf1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(31 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 4092 == intdiv(2 * intdiv(MLDSA_Q - 1, 32), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 4092. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 32*GAMMA2 = 16*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 16B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + * + * round(f1' * 1025 / 2^22) is in turn computed in 2 steps as + * round(floor(f1' * 1025 / 2^16) / 2^6). The mulhi computes f1'' = + * floor(f1' * 1025 / 2^16). As for the next step f1 = round(f1'' / 2^6), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^9) = round(f1'' * 2^9 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 1025 / 2^16) = 1025 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(16B / B) = 16 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 16, i.e. f > 31*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 31*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 15, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c new file mode 100644 index 0000000000..463506b962 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ + +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 1488 == intdiv(2 * intdiv(MLDSA_Q - 1, 88), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 1488. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 88*GAMMA2 = 44*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 44B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + * + * round(f1' * 11275 / 2^24) is in turn computed in 2 steps as + * round(floor(f1' * 11275 / 2^16) / 2^8). The mulhi computes f1'' = + * floor(f1' * 11275 / 2^16). As for the next step f1 = round(f1'' / 2^8), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^7) = round(f1'' * 2^7 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 11275 / 2^16) = 11275 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(44B / B) = 44 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 44, i.e. f > 87*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 87*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 43, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c new file mode 100644 index 0000000000..0094bc93a9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + const __m256i mask = _mm256_set1_epi32(15); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_32_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 16 */ + f1 = _mm256_add_epi32(f1, h); + f1 = _mm256_and_si256(f1, mask); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c new file mode 100644 index 0000000000..b109ab6351 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + const __m256i max = _mm256_set1_epi32(43); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_88_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 44 */ + f1 = _mm256_add_epi32(f1, h); + f1 = MLD_MM256_BLENDV_EPI32(f1, max, f1); + f = _mm256_cmpgt_epi32(f1, max); + f1 = MLD_MM256_BLENDV_EPI32(f1, zero, f); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c new file mode 100644 index 0000000000..f6c08a832f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 27, 26, 25, -1, 25, 24, 23, -1, 8, 7, + 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0); + const __m256i srlvdidx = _mm256_set_epi32(6, 4, 2, 0, 6, 4, 2, 0); + const __m256i mask = _mm256_set1_epi32(0x3FFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 17)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[18 * i]); + /* Load bytes 2..17 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[18 * i + 2]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-8 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 8, 7, 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte8, byte7, byte6, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,27, 26, 25, -1,25, 24, 23] │ + * │ Result: [0, byte17, byte16, byte15, ..., 0, byte11, byte10, byte9] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 18 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 32..55 48..71 + * 72..95 88..111 104..127 120..143 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 18..39 36..55 54..71 + * 72..95 90..111 108..127 126..143 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..17 18..35 36..53 54..71 + * 72..89 90..107 108..125 126..143 */ + + /* Map [0, 1, ..., 2^18-1] to [2^17, 2^17-1, ..., -2^17+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_17) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c new file mode 100644 index 0000000000..4a5ce48f38 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 26, 25, 24, -1, 24, 23, 22, -1, 9, 8, + 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0); + /* Equivalent to _mm256_set_epi32(4, 0, 4, 0, 4, 0, 4, 0) */ + const __m256i srlvdidx = _mm256_set1_epi64x((uint64_t)4 << 32); + const __m256i mask = _mm256_set1_epi32(0xFFFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 19)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[20 * i]); + /* Load bytes 4..19 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[20 * i + 4]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-9 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 9, 8, 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte9, byte8, byte7, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,26, 25, 24, -1,24, 23, 22] │ + * │ Result: [0, byte19, byte18, byte17, ..., 0, byte12, byte11, byte10] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 20 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 40..63 56..79 + * 80..103 96..119 120..143 136..159 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 20..39 40..63 60..79 + * 80..103 100..119 120..143 140..159 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..19 20..39 40..59 60..79 + * 80..99 100..119 120..139 140..159 */ + + /* Map [0, 1, ..., 2^20-1] to [2^19, 2^19-1, ..., -2^19+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_19) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c new file mode 100644 index 0000000000..07a5df9706 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The pqcrystals implementation assumes a buffer that is 8 bytes + *. larger as the first loop overreads by 8 bytes that are then + * discarded. We instead do not pad the buffer and do not overread. + * The performance impact is negligible and it does not force the + * frontend to perform the unintuitive padding. + */ + +unsigned int mld_rej_uniform_avx2( + int32_t *MLD_RESTRICT r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i d, tmp; + const __m256i bound = _mm256_set1_epi32(MLDSA_Q); + const __m256i mask = _mm256_set1_epi32(0x7FFFFF); + const __m256i idx8 = + _mm256_set_epi8(-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4, + -1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 32) + { + d = _mm256_loadu_si256((__m256i *)&buf[pos]); + + /* Permute 64-bit lanes + * 0x94 = 10010100b rearranges 64-bit lanes as: [3,2,1,0] -> [2,1,1,0] + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Original Layout ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ bytes 16..23 │ bytes 24..31 │ + * └─────────────────┴─────────────────┴─────────────────┴─────────────────┘ + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Layout after permute ║ + * ║ Byte indices in high half shifted down by 8 positions ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌───────────────┬─────────────────┐ ┌─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ │ bytes 8..15 │ bytes 16..23 │ + * └───────────────┴─────────────────┘ └─────────────────┴─────────────────┘ + * Lower 128-bit lane (bytes 0-15) Upper 128-bit lane (bytes 16-31) + */ + d = _mm256_permute4x64_epi64(d, 0x94); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-11 into low 128-bit half of permuted vector────────────────┐ + * │ Shuffle: [-1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0] │ + * │ Result: [0, byte11, byte10, byte9, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 4-15 into high 128-bit half of permuted vector ──────────────┐ + * │ Shuffle: [-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4] │ + * │ Result: [0, byte23, byte22, byte21, ..., 0, byte14, byte13, byte12 │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + d = _mm256_shuffle_epi8(d, idx8); + d = _mm256_and_si256(d, mask); + pos += 24; + + tmp = _mm256_sub_epi32(d, bound); + good = (uint32_t)_mm256_movemask_ps((__m256)tmp); + tmp = _mm256_cvtepu8_epi32( + _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good])); + d = _mm256_permutevar8x32_epi32(d, tmp); + + _mm256_storeu_si256((__m256i *)&r[ctr], d); + ctr += (unsigned)_mm_popcnt_u32(good); + } + + while (ctr < MLDSA_N && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 3) + { + uint32_t t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + /* Safe because t < MLDSA_Q. */ + r[ctr++] = (int32_t)t; + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c new file mode 100644 index 0000000000..70c5c42c70 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA2 2 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ +unsigned int mld_rej_uniform_eta2_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1, f2; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA2); + const __m256i bound = mask; + /* check-magic: -6560 == 32*round(-2**10 / 5) */ + const __m256i v = _mm256_set1_epi32(-6560); + const __m256i p = _mm256_set1_epi32(5); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 15) + { + t0 = t0 - (205 * t0 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t0); + } + if (t1 < 15 && ctr < MLDSA_N) + { + t1 = t1 - (205 * t1 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta2) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA2 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c new file mode 100644 index 0000000000..ba00e91252 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA4 4 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ + +unsigned int mld_rej_uniform_eta4_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA4); + const __m256i bound = _mm256_set1_epi8(9); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 9) + { + r[ctr++] = (int32_t)(4 - t0); + } + if (t1 < 9 && ctr < MLDSA_N) + { + r[ctr++] = (int32_t)(4 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta4) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA4 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/rej_uniform_table.c new file mode 100644 index 0000000000..6c537b4542 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/native/x86_64/src/rej_uniform_table.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" + +/* + * Lookup table used by rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[256][8] = { + {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, + {2, 0, 0, 0, 0, 0, 0, 0}, {0, 2, 0, 0, 0, 0, 0, 0}, + {1, 2, 0, 0, 0, 0, 0, 0}, {0, 1, 2, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 0, 0}, {0, 3, 0, 0, 0, 0, 0, 0}, + {1, 3, 0, 0, 0, 0, 0, 0}, {0, 1, 3, 0, 0, 0, 0, 0}, + {2, 3, 0, 0, 0, 0, 0, 0}, {0, 2, 3, 0, 0, 0, 0, 0}, + {1, 2, 3, 0, 0, 0, 0, 0}, {0, 1, 2, 3, 0, 0, 0, 0}, + {4, 0, 0, 0, 0, 0, 0, 0}, {0, 4, 0, 0, 0, 0, 0, 0}, + {1, 4, 0, 0, 0, 0, 0, 0}, {0, 1, 4, 0, 0, 0, 0, 0}, + {2, 4, 0, 0, 0, 0, 0, 0}, {0, 2, 4, 0, 0, 0, 0, 0}, + {1, 2, 4, 0, 0, 0, 0, 0}, {0, 1, 2, 4, 0, 0, 0, 0}, + {3, 4, 0, 0, 0, 0, 0, 0}, {0, 3, 4, 0, 0, 0, 0, 0}, + {1, 3, 4, 0, 0, 0, 0, 0}, {0, 1, 3, 4, 0, 0, 0, 0}, + {2, 3, 4, 0, 0, 0, 0, 0}, {0, 2, 3, 4, 0, 0, 0, 0}, + {1, 2, 3, 4, 0, 0, 0, 0}, {0, 1, 2, 3, 4, 0, 0, 0}, + {5, 0, 0, 0, 0, 0, 0, 0}, {0, 5, 0, 0, 0, 0, 0, 0}, + {1, 5, 0, 0, 0, 0, 0, 0}, {0, 1, 5, 0, 0, 0, 0, 0}, + {2, 5, 0, 0, 0, 0, 0, 0}, {0, 2, 5, 0, 0, 0, 0, 0}, + {1, 2, 5, 0, 0, 0, 0, 0}, {0, 1, 2, 5, 0, 0, 0, 0}, + {3, 5, 0, 0, 0, 0, 0, 0}, {0, 3, 5, 0, 0, 0, 0, 0}, + {1, 3, 5, 0, 0, 0, 0, 0}, {0, 1, 3, 5, 0, 0, 0, 0}, + {2, 3, 5, 0, 0, 0, 0, 0}, {0, 2, 3, 5, 0, 0, 0, 0}, + {1, 2, 3, 5, 0, 0, 0, 0}, {0, 1, 2, 3, 5, 0, 0, 0}, + {4, 5, 0, 0, 0, 0, 0, 0}, {0, 4, 5, 0, 0, 0, 0, 0}, + {1, 4, 5, 0, 0, 0, 0, 0}, {0, 1, 4, 5, 0, 0, 0, 0}, + {2, 4, 5, 0, 0, 0, 0, 0}, {0, 2, 4, 5, 0, 0, 0, 0}, + {1, 2, 4, 5, 0, 0, 0, 0}, {0, 1, 2, 4, 5, 0, 0, 0}, + {3, 4, 5, 0, 0, 0, 0, 0}, {0, 3, 4, 5, 0, 0, 0, 0}, + {1, 3, 4, 5, 0, 0, 0, 0}, {0, 1, 3, 4, 5, 0, 0, 0}, + {2, 3, 4, 5, 0, 0, 0, 0}, {0, 2, 3, 4, 5, 0, 0, 0}, + {1, 2, 3, 4, 5, 0, 0, 0}, {0, 1, 2, 3, 4, 5, 0, 0}, + {6, 0, 0, 0, 0, 0, 0, 0}, {0, 6, 0, 0, 0, 0, 0, 0}, + {1, 6, 0, 0, 0, 0, 0, 0}, {0, 1, 6, 0, 0, 0, 0, 0}, + {2, 6, 0, 0, 0, 0, 0, 0}, {0, 2, 6, 0, 0, 0, 0, 0}, + {1, 2, 6, 0, 0, 0, 0, 0}, {0, 1, 2, 6, 0, 0, 0, 0}, + {3, 6, 0, 0, 0, 0, 0, 0}, {0, 3, 6, 0, 0, 0, 0, 0}, + {1, 3, 6, 0, 0, 0, 0, 0}, {0, 1, 3, 6, 0, 0, 0, 0}, + {2, 3, 6, 0, 0, 0, 0, 0}, {0, 2, 3, 6, 0, 0, 0, 0}, + {1, 2, 3, 6, 0, 0, 0, 0}, {0, 1, 2, 3, 6, 0, 0, 0}, + {4, 6, 0, 0, 0, 0, 0, 0}, {0, 4, 6, 0, 0, 0, 0, 0}, + {1, 4, 6, 0, 0, 0, 0, 0}, {0, 1, 4, 6, 0, 0, 0, 0}, + {2, 4, 6, 0, 0, 0, 0, 0}, {0, 2, 4, 6, 0, 0, 0, 0}, + {1, 2, 4, 6, 0, 0, 0, 0}, {0, 1, 2, 4, 6, 0, 0, 0}, + {3, 4, 6, 0, 0, 0, 0, 0}, {0, 3, 4, 6, 0, 0, 0, 0}, + {1, 3, 4, 6, 0, 0, 0, 0}, {0, 1, 3, 4, 6, 0, 0, 0}, + {2, 3, 4, 6, 0, 0, 0, 0}, {0, 2, 3, 4, 6, 0, 0, 0}, + {1, 2, 3, 4, 6, 0, 0, 0}, {0, 1, 2, 3, 4, 6, 0, 0}, + {5, 6, 0, 0, 0, 0, 0, 0}, {0, 5, 6, 0, 0, 0, 0, 0}, + {1, 5, 6, 0, 0, 0, 0, 0}, {0, 1, 5, 6, 0, 0, 0, 0}, + {2, 5, 6, 0, 0, 0, 0, 0}, {0, 2, 5, 6, 0, 0, 0, 0}, + {1, 2, 5, 6, 0, 0, 0, 0}, {0, 1, 2, 5, 6, 0, 0, 0}, + {3, 5, 6, 0, 0, 0, 0, 0}, {0, 3, 5, 6, 0, 0, 0, 0}, + {1, 3, 5, 6, 0, 0, 0, 0}, {0, 1, 3, 5, 6, 0, 0, 0}, + {2, 3, 5, 6, 0, 0, 0, 0}, {0, 2, 3, 5, 6, 0, 0, 0}, + {1, 2, 3, 5, 6, 0, 0, 0}, {0, 1, 2, 3, 5, 6, 0, 0}, + {4, 5, 6, 0, 0, 0, 0, 0}, {0, 4, 5, 6, 0, 0, 0, 0}, + {1, 4, 5, 6, 0, 0, 0, 0}, {0, 1, 4, 5, 6, 0, 0, 0}, + {2, 4, 5, 6, 0, 0, 0, 0}, {0, 2, 4, 5, 6, 0, 0, 0}, + {1, 2, 4, 5, 6, 0, 0, 0}, {0, 1, 2, 4, 5, 6, 0, 0}, + {3, 4, 5, 6, 0, 0, 0, 0}, {0, 3, 4, 5, 6, 0, 0, 0}, + {1, 3, 4, 5, 6, 0, 0, 0}, {0, 1, 3, 4, 5, 6, 0, 0}, + {2, 3, 4, 5, 6, 0, 0, 0}, {0, 2, 3, 4, 5, 6, 0, 0}, + {1, 2, 3, 4, 5, 6, 0, 0}, {0, 1, 2, 3, 4, 5, 6, 0}, + {7, 0, 0, 0, 0, 0, 0, 0}, {0, 7, 0, 0, 0, 0, 0, 0}, + {1, 7, 0, 0, 0, 0, 0, 0}, {0, 1, 7, 0, 0, 0, 0, 0}, + {2, 7, 0, 0, 0, 0, 0, 0}, {0, 2, 7, 0, 0, 0, 0, 0}, + {1, 2, 7, 0, 0, 0, 0, 0}, {0, 1, 2, 7, 0, 0, 0, 0}, + {3, 7, 0, 0, 0, 0, 0, 0}, {0, 3, 7, 0, 0, 0, 0, 0}, + {1, 3, 7, 0, 0, 0, 0, 0}, {0, 1, 3, 7, 0, 0, 0, 0}, + {2, 3, 7, 0, 0, 0, 0, 0}, {0, 2, 3, 7, 0, 0, 0, 0}, + {1, 2, 3, 7, 0, 0, 0, 0}, {0, 1, 2, 3, 7, 0, 0, 0}, + {4, 7, 0, 0, 0, 0, 0, 0}, {0, 4, 7, 0, 0, 0, 0, 0}, + {1, 4, 7, 0, 0, 0, 0, 0}, {0, 1, 4, 7, 0, 0, 0, 0}, + {2, 4, 7, 0, 0, 0, 0, 0}, {0, 2, 4, 7, 0, 0, 0, 0}, + {1, 2, 4, 7, 0, 0, 0, 0}, {0, 1, 2, 4, 7, 0, 0, 0}, + {3, 4, 7, 0, 0, 0, 0, 0}, {0, 3, 4, 7, 0, 0, 0, 0}, + {1, 3, 4, 7, 0, 0, 0, 0}, {0, 1, 3, 4, 7, 0, 0, 0}, + {2, 3, 4, 7, 0, 0, 0, 0}, {0, 2, 3, 4, 7, 0, 0, 0}, + {1, 2, 3, 4, 7, 0, 0, 0}, {0, 1, 2, 3, 4, 7, 0, 0}, + {5, 7, 0, 0, 0, 0, 0, 0}, {0, 5, 7, 0, 0, 0, 0, 0}, + {1, 5, 7, 0, 0, 0, 0, 0}, {0, 1, 5, 7, 0, 0, 0, 0}, + {2, 5, 7, 0, 0, 0, 0, 0}, {0, 2, 5, 7, 0, 0, 0, 0}, + {1, 2, 5, 7, 0, 0, 0, 0}, {0, 1, 2, 5, 7, 0, 0, 0}, + {3, 5, 7, 0, 0, 0, 0, 0}, {0, 3, 5, 7, 0, 0, 0, 0}, + {1, 3, 5, 7, 0, 0, 0, 0}, {0, 1, 3, 5, 7, 0, 0, 0}, + {2, 3, 5, 7, 0, 0, 0, 0}, {0, 2, 3, 5, 7, 0, 0, 0}, + {1, 2, 3, 5, 7, 0, 0, 0}, {0, 1, 2, 3, 5, 7, 0, 0}, + {4, 5, 7, 0, 0, 0, 0, 0}, {0, 4, 5, 7, 0, 0, 0, 0}, + {1, 4, 5, 7, 0, 0, 0, 0}, {0, 1, 4, 5, 7, 0, 0, 0}, + {2, 4, 5, 7, 0, 0, 0, 0}, {0, 2, 4, 5, 7, 0, 0, 0}, + {1, 2, 4, 5, 7, 0, 0, 0}, {0, 1, 2, 4, 5, 7, 0, 0}, + {3, 4, 5, 7, 0, 0, 0, 0}, {0, 3, 4, 5, 7, 0, 0, 0}, + {1, 3, 4, 5, 7, 0, 0, 0}, {0, 1, 3, 4, 5, 7, 0, 0}, + {2, 3, 4, 5, 7, 0, 0, 0}, {0, 2, 3, 4, 5, 7, 0, 0}, + {1, 2, 3, 4, 5, 7, 0, 0}, {0, 1, 2, 3, 4, 5, 7, 0}, + {6, 7, 0, 0, 0, 0, 0, 0}, {0, 6, 7, 0, 0, 0, 0, 0}, + {1, 6, 7, 0, 0, 0, 0, 0}, {0, 1, 6, 7, 0, 0, 0, 0}, + {2, 6, 7, 0, 0, 0, 0, 0}, {0, 2, 6, 7, 0, 0, 0, 0}, + {1, 2, 6, 7, 0, 0, 0, 0}, {0, 1, 2, 6, 7, 0, 0, 0}, + {3, 6, 7, 0, 0, 0, 0, 0}, {0, 3, 6, 7, 0, 0, 0, 0}, + {1, 3, 6, 7, 0, 0, 0, 0}, {0, 1, 3, 6, 7, 0, 0, 0}, + {2, 3, 6, 7, 0, 0, 0, 0}, {0, 2, 3, 6, 7, 0, 0, 0}, + {1, 2, 3, 6, 7, 0, 0, 0}, {0, 1, 2, 3, 6, 7, 0, 0}, + {4, 6, 7, 0, 0, 0, 0, 0}, {0, 4, 6, 7, 0, 0, 0, 0}, + {1, 4, 6, 7, 0, 0, 0, 0}, {0, 1, 4, 6, 7, 0, 0, 0}, + {2, 4, 6, 7, 0, 0, 0, 0}, {0, 2, 4, 6, 7, 0, 0, 0}, + {1, 2, 4, 6, 7, 0, 0, 0}, {0, 1, 2, 4, 6, 7, 0, 0}, + {3, 4, 6, 7, 0, 0, 0, 0}, {0, 3, 4, 6, 7, 0, 0, 0}, + {1, 3, 4, 6, 7, 0, 0, 0}, {0, 1, 3, 4, 6, 7, 0, 0}, + {2, 3, 4, 6, 7, 0, 0, 0}, {0, 2, 3, 4, 6, 7, 0, 0}, + {1, 2, 3, 4, 6, 7, 0, 0}, {0, 1, 2, 3, 4, 6, 7, 0}, + {5, 6, 7, 0, 0, 0, 0, 0}, {0, 5, 6, 7, 0, 0, 0, 0}, + {1, 5, 6, 7, 0, 0, 0, 0}, {0, 1, 5, 6, 7, 0, 0, 0}, + {2, 5, 6, 7, 0, 0, 0, 0}, {0, 2, 5, 6, 7, 0, 0, 0}, + {1, 2, 5, 6, 7, 0, 0, 0}, {0, 1, 2, 5, 6, 7, 0, 0}, + {3, 5, 6, 7, 0, 0, 0, 0}, {0, 3, 5, 6, 7, 0, 0, 0}, + {1, 3, 5, 6, 7, 0, 0, 0}, {0, 1, 3, 5, 6, 7, 0, 0}, + {2, 3, 5, 6, 7, 0, 0, 0}, {0, 2, 3, 5, 6, 7, 0, 0}, + {1, 2, 3, 5, 6, 7, 0, 0}, {0, 1, 2, 3, 5, 6, 7, 0}, + {4, 5, 6, 7, 0, 0, 0, 0}, {0, 4, 5, 6, 7, 0, 0, 0}, + {1, 4, 5, 6, 7, 0, 0, 0}, {0, 1, 4, 5, 6, 7, 0, 0}, + {2, 4, 5, 6, 7, 0, 0, 0}, {0, 2, 4, 5, 6, 7, 0, 0}, + {1, 2, 4, 5, 6, 7, 0, 0}, {0, 1, 2, 4, 5, 6, 7, 0}, + {3, 4, 5, 6, 7, 0, 0, 0}, {0, 3, 4, 5, 6, 7, 0, 0}, + {1, 3, 4, 5, 6, 7, 0, 0}, {0, 1, 3, 4, 5, 6, 7, 0}, + {2, 3, 4, 5, 6, 7, 0, 0}, {0, 2, 3, 4, 5, 6, 7, 0}, + {1, 2, 3, 4, 5, 6, 7, 0}, {0, 1, 2, 3, 4, 5, 6, 7}, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/packing.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/packing.c new file mode 100644 index 0000000000..26da273856 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/packing.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include + +#include "common.h" +#include "packing.h" +#include "poly.h" +#include "polyvec.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_unpack_hints MLD_ADD_PARAM_SET(mld_unpack_hints) +/* End of parameter set namespacing */ + +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +{ + unsigned int i; + + mld_memcpy(pk, rho, MLDSA_SEEDBYTES); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt1_pack(pk + MLDSA_SEEDBYTES + i * MLDSA_POLYT1_PACKEDBYTES, + &t1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +{ + unsigned int i; + + mld_memcpy(rho, pk, MLDSA_SEEDBYTES); + pk += MLDSA_SEEDBYTES; + + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt1_unpack(&t1->vec[i], pk + i * MLDSA_POLYT1_PACKEDBYTES); + } +} + +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +{ + mld_memcpy(sk, rho, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, key, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, tr, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_pack_eta(sk, s1); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_eta(sk, s2); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_t0(sk, t0); +} + +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +{ + mld_memcpy(rho, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(key, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(tr, sk, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_unpack_eta(s1, sk); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_eta(s2, sk); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_t0(t0, sk); +} + +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +{ + unsigned int i, j, k; + + mld_memcpy(sig, c, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + /* skip z component - packed via mld_pack_sig_z */ + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + /* Encode hints h */ + + /* The final section of sig[] is MLDSA_POLYVECH_PACKEDBYTES long, where + * MLDSA_POLYVECH_PACKEDBYTES = MLDSA_OMEGA + MLDSA_K + * + * The first OMEGA bytes record the index numbers of the coefficients + * that are not equal to 0 + * + * The final K bytes record a running tally of the number of hints + * coming from each of the K polynomials in h. + * + * The pre-condition tells us that number_of_hints <= OMEGA, so some + * bytes may not be written, so we initialize all of them to zero + * to start. + */ + mld_memset(sig, 0, MLDSA_POLYVECH_PACKEDBYTES); + + k = 0; + /* For each polynomial in h... */ + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* For each coefficient in that polynomial, record it as as hint */ + /* if its value is not zero */ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + assigns(j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(j <= MLDSA_N) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* The reference implementation implicitly relies on the total */ + /* number of hints being less than OMEGA, assuming h is valid. */ + /* In mldsa-native, we check this explicitly to ease proof of */ + /* type safety. */ + if (h->vec[i].coeffs[j] != 0 && k < number_of_hints) + { + /* The enclosing if condition AND the loop invariant infer */ + /* that k < MLDSA_OMEGA, so writing to sig[k] is safe and k */ + /* can be incremented. */ + sig[k++] = (uint8_t)j; + } + } + /* Having recorded all the hints for this polynomial, also */ + /* record the running tally into the correct "slot" for that */ + /* coefficient in the final K bytes */ + sig[MLDSA_OMEGA + i] = (uint8_t)k; + } +} + +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +{ + sig += MLDSA_CTILDEBYTES; + sig += i * MLDSA_POLYZ_PACKEDBYTES; + mld_polyz_pack(sig, zi); +} + +/************************************************* + * Name: mld_unpack_hints + * + * Description: Unpack raw hint bytes into a polyveck + * struct + * + * Arguments: - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]: + * raw hint bytes + * + * Returns 1 in case of malformed hints; otherwise 0. + **************************************************/ +static int mld_unpack_hints( + mld_polyveck *h, const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(packed_hints, MLDSA_POLYVECH_PACKEDBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + /* All returned coefficients are either 0 or 1 */ + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +) +{ + unsigned int i, j; + unsigned int old_hint_count; + + /* Set all coefficients of all polynomials to 0. */ + /* Only those that are actually non-zero hints will */ + /* be overwritten below. */ + mld_memset(h, 0, sizeof(mld_polyveck)); + + old_hint_count = 0; + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + /* Grab the hint count for the i'th polynomial */ + const unsigned int new_hint_count = packed_hints[MLDSA_OMEGA + i]; + + /* new_hint_count must increase or stay the same, but also remain */ + /* less than or equal to MLDSA_OMEGA */ + if (new_hint_count < old_hint_count || new_hint_count > MLDSA_OMEGA) + { + /* Error - new_hint_count is invalid */ + return 1; + } + + /* If new_hint_count == old_hint_count, then this polynomial has */ + /* zero hints, so this loop executes zero times and we move */ + /* straight on to the next polynomial. */ + for (j = old_hint_count; j < new_hint_count; ++j) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + const uint8_t this_hint_index = packed_hints[j]; + + /* Coefficients must be ordered for strong unforgeability */ + if (j > old_hint_count && this_hint_index <= packed_hints[j - 1]) + { + return 1; + } + h->vec[i].coeffs[this_hint_index] = 1; + } + + old_hint_count = new_hint_count; + } + + /* Extra indices must be zero for strong unforgeability */ + for (j = old_hint_count; j < MLDSA_OMEGA; ++j) + __loop__( + invariant(j <= MLDSA_OMEGA) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + if (packed_hints[j] != 0) + { + return 1; + } + } + + return 0; +} + +MLD_INTERNAL_API +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +{ + mld_memcpy(c, sig, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + mld_polyvecl_unpack_z(z, sig); + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + return mld_unpack_hints(h, sig); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_unpack_hints diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/packing.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/packing.h new file mode 100644 index 0000000000..19095d08cd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/packing.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PACKING_H +#define MLD_PACKING_H + +#include +#include "polyvec.h" + +#define mld_pack_pk MLD_NAMESPACE_KL(pack_pk) +/************************************************* + * Name: mld_pack_pk + * + * Description: Bit-pack public key pk = (rho, t1). + * + * Arguments: - uint8_t pk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const mld_polyveck *t1: pointer to vector t1 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) +); + + +#define mld_pack_sk MLD_NAMESPACE_KL(pack_sk) +/************************************************* + * Name: mld_pack_sk + * + * Description: Bit-pack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - uint8_t sk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const uint8_t tr[]: byte array containing tr + * - const uint8_t key[]: byte array containing key + * - const mld_polyveck *t0: pointer to vector t0 + * - const mld_polyvecl *s1: pointer to vector s1 + * - const mld_polyveck *s2: pointer to vector s2 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +__contract__( + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + requires(forall(k2, 0, MLDSA_K, + array_abs_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) +); + + +#define mld_pack_sig_c_h MLD_NAMESPACE_KL(pack_sig_c_h) +/************************************************* + * Name: mld_pack_sig_c_h + * + * Description: Bit-pack c and h component of sig = (c, z, h). + * The z component is packed separately using mld_pack_sig_z. + * + * Arguments: - uint8_t sig[]: output byte array + * - const uint8_t *c: pointer to challenge hash length + * MLDSA_SEEDBYTES + * - const mld_polyveck *h: pointer to hint vector h + * - const unsigned int number_of_hints: total + * hints in *h + * + * Note that the number_of_hints argument is not present + * in the reference implementation. It is added here to ease + * proof of type safety. + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + requires(number_of_hints <= MLDSA_OMEGA) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_pack_sig_z MLD_NAMESPACE_KL(pack_sig_z) +/************************************************* + * Name: mld_pack_sig_z + * + * Description: Bit-pack single polynomial of z component of sig = (c, z, h). + * The c and h components are packed separately using + * mld_pack_sig_c_h. + * + * Arguments: - uint8_t sig[]: output byte array + * - const mld_poly *zi: pointer to a single polynomial in z + * - const unsigned int i: index of zi in vector z + * + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(zi, sizeof(mld_poly))) + requires(i < MLDSA_L) + requires(array_bound(zi->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_unpack_pk MLD_NAMESPACE_KL(unpack_pk) +/************************************************* + * Name: mld_unpack_pk + * + * Description: Unpack public key pk = (rho, t1). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const mld_polyveck *t1: pointer to output vector t1 + * - uint8_t pk[]: byte array containing bit-packed pk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) +); + + +#define mld_unpack_sk MLD_NAMESPACE_KL(unpack_sk) +/************************************************* + * Name: mld_unpack_sk + * + * Description: Unpack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const uint8_t tr[]: output byte array for tr + * - const uint8_t key[]: output byte array for key + * - const mld_polyveck *t0: pointer to output vector t0 + * - const mld_polyvecl *s1: pointer to output vector s1 + * - const mld_polyveck *s2: pointer to output vector s2 + * - uint8_t sk[]: byte array containing bit-packed sk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +__contract__( + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(key, MLDSA_SEEDBYTES)) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(s1, sizeof(mld_polyvecl))) + assigns(memory_slice(s2, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_unpack_sig MLD_NAMESPACE_KL(unpack_sig) +/************************************************* + * Name: mld_unpack_sig + * + * Description: Unpack signature sig = (c, z, h). + * + * Arguments: - uint8_t *c: pointer to output challenge hash + * - mld_polyvecl *z: pointer to output vector z + * - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t sig[]: byte array containing + * bit-packed signature + * + * Returns 1 in case of malformed signature; otherwise 0. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(c, MLDSA_CTILDEBYTES)) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(z->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +); +#endif /* !MLD_PACKING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/params.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/params.h new file mode 100644 index 0000000000..c67d2a33fb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/params.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PARAMS_H +#define MLD_PARAMS_H + +#define MLDSA_SEEDBYTES 32 +#define MLDSA_CRHBYTES 64 +#define MLDSA_TRBYTES 64 +#define MLDSA_RNDBYTES 32 +#define MLDSA_N 256 +#define MLDSA_Q 8380417 +#define MLDSA_Q_HALF ((MLDSA_Q + 1) / 2) +#define MLDSA_D 13 + +#if MLD_CONFIG_PARAMETER_SET == 44 + +#define MLDSA_K 4 +#define MLDSA_L 4 +#define MLDSA_ETA 2 +#define MLDSA_TAU 39 +#define MLDSA_BETA 78 +#define MLDSA_GAMMA1 (1 << 17) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 88) +#define MLDSA_OMEGA 80 +#define MLDSA_CTILDEBYTES 32 +#define MLDSA_POLYZ_PACKEDBYTES 576 +#define MLDSA_POLYW1_PACKEDBYTES 192 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#elif MLD_CONFIG_PARAMETER_SET == 65 + +#define MLDSA_K 6 +#define MLDSA_L 5 +#define MLDSA_ETA 4 +#define MLDSA_TAU 49 +#define MLDSA_BETA 196 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 55 +#define MLDSA_CTILDEBYTES 48 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 128 + +#elif MLD_CONFIG_PARAMETER_SET == 87 + +#define MLDSA_K 8 +#define MLDSA_L 7 +#define MLDSA_ETA 2 +#define MLDSA_TAU 60 +#define MLDSA_BETA 120 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 75 +#define MLDSA_CTILDEBYTES 64 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ + +#define MLDSA_POLYT1_PACKEDBYTES 320 +#define MLDSA_POLYT0_PACKEDBYTES 416 +#define MLDSA_POLYVECH_PACKEDBYTES (MLDSA_OMEGA + MLDSA_K) + +#define MLDSA_CRYPTO_PUBLICKEYBYTES \ + (MLDSA_SEEDBYTES + MLDSA_K * MLDSA_POLYT1_PACKEDBYTES) +#define MLDSA_CRYPTO_SECRETKEYBYTES \ + (2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + MLDSA_L * MLDSA_POLYETA_PACKEDBYTES + \ + MLDSA_K * MLDSA_POLYETA_PACKEDBYTES + MLDSA_K * MLDSA_POLYT0_PACKEDBYTES) +#define MLDSA_CRYPTO_BYTES \ + (MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES + \ + MLDSA_POLYVECH_PACKEDBYTES) + +#endif /* !MLD_PARAMS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/poly.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/poly.c new file mode 100644 index 0000000000..e40534e773 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/poly.c @@ -0,0 +1,973 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "common.h" +#include "ct.h" +#include "debug.h" +#include "poly.h" +#include "reduce.h" +#include "rounding.h" +#include "symmetric.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +#include "zetas.inc" + +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + { + a->coeffs[i] = mld_reduce32(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_STATIC_TESTABLE void mld_poly_caddq_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + ) + { + a->coeffs[i] = mld_caddq(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_POLY_CADDQ) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_poly_caddq_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + mld_poly_caddq_c(a); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1])) + invariant(forall(k2, 0, i, r->coeffs[k2] < MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k2, 0, i, r->coeffs[k2] >= INT32_MIN)) + ) + { + r->coeffs[i] = r->coeffs[i] + b->coeffs[i]; + } +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(r->coeffs, 0, i, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + ) + { + r->coeffs[i] = r->coeffs[i] - b->coeffs[i]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N; i++) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))) + { + /* Reference: uses a left shift by MLDSA_D which is undefined behaviour in + * C90/C99 + */ + a->coeffs[i] *= (1 << MLDSA_D); + } + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + + +static MLD_INLINE int32_t mld_fqmul(int32_t a, int32_t b) +__contract__( + requires(b > -MLDSA_Q_HALF && b < MLDSA_Q_HALF) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* Bounds: We argue in mld_montgomery_reduce() that the reult + * of Montgomery reduction is < MLDSA_Q if the input is smaller + * than 2^31 * MLDSA_Q in absolute value. Indeed, we have: + * + * |a * b| = |a| * |b| + * < 2^31 * MLDSA_Q_HALF + * < 2^31 * MLDSA_Q + */ + return mld_montgomery_reduce((int64_t)a * (int64_t)b); +} + +/* mld_ntt_butterfly_block() + * + * Computes a block CT butterflies with a fixed twiddle factor, + * using Montgomery multiplication. + * + * Parameters: + * - r: Pointer to base of polynomial (_not_ the base of butterfly block) + * - zeta: Twiddle factor to use for the butterfly. This must be in + * Montgomery form and signed canonical. + * - start: Offset to the beginning of the butterfly block + * - len: Index difference between coefficients subject to a butterfly + * - bound: Ghost variable describing coefficient bound: Prior to `start`, + * coefficients must be bound by `bound + MLDSA_Q`. Post `start`, + * they must be bound by `bound`. + * When this function returns, output coefficients in the index range + * [start, start+2*len) have bound bumped to `bound + MLDSA_Q`. + * Example: + * - start=8, len=4 + * This would compute the following four butterflies + * 8 -- 12 + * 9 -- 13 + * 10 -- 14 + * 11 -- 15 + * - start=4, len=2 + * This would compute the following two butterflies + * 4 -- 6 + * 5 -- 7 + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_butterfly_block(int32_t r[MLDSA_N], + const int32_t zeta, + const unsigned start, + const unsigned len, + const unsigned bound) +__contract__( + requires(start < MLDSA_N) + requires(1 <= len && len <= MLDSA_N / 2 && start + 2 * len <= MLDSA_N) + requires(0 <= bound && bound < INT32_MAX - MLDSA_Q) + requires(-MLDSA_Q_HALF < zeta && zeta < MLDSA_Q_HALF) + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, start, bound + MLDSA_Q)) + requires(array_abs_bound(r, start, MLDSA_N, bound)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, start + 2*len, bound + MLDSA_Q)) + ensures(array_abs_bound(r, start + 2 * len, MLDSA_N, bound))) +{ + /* `bound` is a ghost variable only needed in the CBMC specification */ + unsigned j; + ((void)bound); + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + /* + * Coefficients are updated in strided pairs, so the bounds for the + * intermediate states alternate twice between the old and new bound + */ + invariant(array_abs_bound(r, 0, j, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, bound)) + invariant(array_abs_bound(r, start + len, j + len, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j + len, MLDSA_N, bound))) + { + int32_t t; + t = mld_fqmul(r[j + len], zeta); + r[j + len] = r[j] - t; + r[j] = r[j] + t; + } +} + +/* mld_ntt_layer() + * + * Compute one layer of forward NTT + * + * Parameters: + * - r: Pointer to base of polynomial + * - layer: Indicates which layer is being applied. + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_layer(int32_t r[MLDSA_N], const unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (layer + 1) * MLDSA_Q))) +{ + unsigned start, k, len; + /* Twiddle factors for layer n are at indices 2^(n-1)..2^n-1. */ + k = 1u << (layer - 1); + len = (unsigned)MLDSA_N >> layer; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start < MLDSA_N + 2 * len) + invariant(k <= MLDSA_N) + invariant(2 * len * k == start + MLDSA_N) + invariant(array_abs_bound(r, 0, start, layer * MLDSA_Q + MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, layer * MLDSA_Q))) + { + int32_t zeta = mld_zetas[k++]; + mld_ntt_butterfly_block(r, zeta, start, len, layer * MLDSA_Q); + } +} + +MLD_STATIC_TESTABLE void mld_poly_ntt_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +) +{ + unsigned int layer; + int32_t *r; + + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + r = a->coeffs; + + for (layer = 1; layer < 9; layer++) + __loop__( + invariant(1 <= layer && layer <= 9) + invariant(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + ) + { + mld_ntt_layer(r, layer); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_NTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_ntt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_NTT */ + mld_poly_ntt_c(a); +} + +/************************************************* + * Name: mld_fqscale + * + * Description: Scales a field element by mont/256 , i.e., performs Montgomery + * multiplication by mont^2/256. + * Input is expected to have absolute value smaller than + * 256 * MLDSA_Q. + * Output has absolute value smaller than MLD_INTT_BOUND. + * + * Arguments: - int32_t a: Field element to be scaled. + **************************************************/ +static MLD_INLINE int32_t mld_fqscale(int32_t a) +__contract__( + requires(a > -256*MLDSA_Q && a < 256*MLDSA_Q) + ensures(return_value > -MLD_INTT_BOUND && return_value < MLD_INTT_BOUND) +) +{ + /* check-magic: 41978 == pow(2,64-8,MLDSA_Q) */ + const int32_t f = 41978; + /* Bounds: MLD_INTT_BOUND is MLDSA_Q, so the bounds reasoning is just + * a special case of that in mld_fqmul(). */ + return mld_montgomery_reduce((int64_t)a * f); +} + +/* Reference: Embedded into `invntt_tomont()` in the reference implementation + * @[REF] */ +static MLD_INLINE void mld_invntt_layer(int32_t r[MLDSA_N], unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> (layer - 1)) * MLDSA_Q))) +{ + unsigned start, k, len; + len = (unsigned)MLDSA_N >> layer; + k = (1u << layer) - 1; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start <= MLDSA_N && k <= 255) + invariant(2 * len * k + start == 2 * MLDSA_N - 2 * len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + unsigned j; + int32_t zeta = -mld_zetas[k--]; + + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, j, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, (MLDSA_N >> layer) * MLDSA_Q)) + invariant(array_abs_bound(r, start + len, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + int32_t t = r[j]; + r[j] = t + r[j + len]; + r[j + len] = t - r[j + len]; + r[j + len] = mld_fqmul(r[j + len], zeta); + } + } +} + +MLD_STATIC_TESTABLE void mld_poly_invntt_tomont_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +) +{ + unsigned int layer, j; + int32_t *r; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + r = a->coeffs; + for (layer = 8; layer >= 1; layer--) + __loop__( + invariant(layer <= 8) + /* Absolute bounds increase from 1Q before layer 8 */ + /* up to 256Q after layer 1 */ + invariant(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + mld_invntt_layer(r, layer); + } + + /* Coefficient bounds are now at 256Q. We now scale by mont / 256, + * i.e., compute the Montgomery multiplication by mont^2 / 256. + * mont corrects the mont^-1 factor introduced in the basemul. + * 1/256 performs that scaling of the inverse NTT. + * The reduced value is bounded by MLD_INTT_BOUND in absolute + * value.*/ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + invariant(j <= MLDSA_N) + invariant(array_abs_bound(r, 0, j, MLD_INTT_BOUND)) + invariant(array_abs_bound(r, j, MLDSA_N, MLDSA_N * MLDSA_Q)) + ) + { + r[j] = mld_fqscale(r[j]); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); +} + + +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_INTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_intt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_INTT */ + mld_poly_invntt_tomont_c(a); +} + +MLD_STATIC_TESTABLE void mld_poly_pointwise_montgomery_c(mld_poly *c, + const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_abs_bound(c->coeffs, 0, i, MLDSA_Q)) + ) + { + c->coeffs[i] = mld_montgomery_reduce((int64_t)a->coeffs[i] * b->coeffs[i]); + } + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +{ +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + ret = mld_poly_pointwise_montgomery_native(c->coeffs, a->coeffs, b->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + mld_poly_pointwise_montgomery_c(c, a, b); +} + +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, 0, i, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + invariant(array_bound(a1->coeffs, 0, i, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) + ) + { + mld_power2round(&a0->coeffs[i], &a1->coeffs[i], a->coeffs[i]); + } + + mld_assert_bound(a0->coeffs, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +#ifndef MLD_POLY_UNIFORM_NBLOCKS +#define MLD_POLY_UNIFORM_NBLOCKS \ + ((768 + MLD_STREAM128_BLOCKBYTES - 1) / MLD_STREAM128_BLOCKBYTES) +#endif +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +MLD_STATIC_TESTABLE unsigned int mld_rej_uniform_c(int32_t *a, + unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ + unsigned int ctr, pos; + uint32_t t; + mld_assert_bound(a, offset, 0, MLDSA_Q); + + ctr = offset; + pos = 0; + /* pos + 3 cannot overflow due to the assumption + buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) */ + while (ctr < target && pos + 3 <= buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_bound(a, 0, ctr, 0, MLDSA_Q))) + { + t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + a[ctr++] = (int32_t)t; + } + } + + mld_assert_bound(a, ctr, 0, MLDSA_Q); + + return ctr; +} +/************************************************* + * Name: mld_rej_uniform + * + * Description: Sample uniformly random coefficients in [0, MLDSA_Q-1] by + * performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes (must be + * multiple of 3) + * + * Returns number of sampled coefficients. Can be smaller than len if not enough + * random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +static unsigned int mld_rej_uniform(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) + int ret; + mld_assert_bound(a, offset, 0, MLDSA_Q); + if (offset == 0) + { + ret = mld_rej_uniform_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_bound(a, res, 0, MLDSA_Q); + return res; + } + } +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + + return mld_rej_uniform_c(a, target, offset, buf, buflen); +} + +/* Reference: poly_uniform() in the reference implementation @[REF]. + * - Simplified from reference by removing buffer tail handling + * since buflen % 3 = 0 always holds true (MLD_STREAM128_BLOCKBYTES + * = 168). + * - Modified rej_uniform interface to track offset directly. + * - Pass nonce packed in the extended seed array instead of a third + * argument. + * */ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +{ + unsigned int ctr; + unsigned int buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + MLD_ALIGN uint8_t buf[MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES]; + mld_xof128_ctx state; + + mld_xof128_init(&state); + mld_xof128_absorb_once(&state, seed, MLDSA_SEEDBYTES + 2); + mld_xof128_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, 0, buf, buflen); + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(a, sizeof(mld_poly)), object_whole(buf)) + invariant(ctr <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, ctr, 0, MLDSA_Q)) + invariant(state.pos <= SHAKE128_RATE) + ) + { + mld_xof128_squeezeblocks(buf, 1, &state); + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, ctr, buf, buflen); + } + mld_xof128_release(&state); + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof128_x4_ctx state; + unsigned buflen; + + mld_xof128_x4_init(&state); + mld_xof128_x4_absorb(&state, seed, MLDSA_SEEDBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_NBLOCKS. + * This should generate the matrix entries with high probability. + */ + + mld_xof128_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all matrix entries have been generated, squeeze + * one more block a time until we're done. + */ + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, object_whole(buf), + memory_slice(vec0, sizeof(mld_poly)), memory_slice(vec1, sizeof(mld_poly)), + memory_slice(vec2, sizeof(mld_poly)), memory_slice(vec3, sizeof(mld_poly))) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_bound(vec0->coeffs, 0, ctr[0], 0, MLDSA_Q)) + invariant(array_bound(vec1->coeffs, 0, ctr[1], 0, MLDSA_Q)) + invariant(array_bound(vec2->coeffs, 0, ctr[2], 0, MLDSA_Q)) + invariant(array_bound(vec3->coeffs, 0, ctr[3], 0, MLDSA_Q))) + { + mld_xof128_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + mld_xof128_x4_release(&state); + + mld_assert_bound(vec0->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec1->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec2->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec3->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0) & 0xFF); + r[5 * i + 1] = + (uint8_t)(((a->coeffs[4 * i + 0] >> 8) | (a->coeffs[4 * i + 1] << 2)) & + 0xFF); + r[5 * i + 2] = + (uint8_t)(((a->coeffs[4 * i + 1] >> 6) | (a->coeffs[4 * i + 2] << 4)) & + 0xFF); + r[5 * i + 3] = + (uint8_t)(((a->coeffs[4 * i + 2] >> 4) | (a->coeffs[4 * i + 3] << 6)) & + 0xFF); + r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, 0, 1 << 10))) + { + r->coeffs[4 * i + 0] = + ((a[5 * i + 0] >> 0) | ((int32_t)a[5 * i + 1] << 8)) & 0x3FF; + r->coeffs[4 * i + 1] = + ((a[5 * i + 1] >> 2) | ((int32_t)a[5 * i + 2] << 6)) & 0x3FF; + r->coeffs[4 * i + 2] = + ((a[5 * i + 2] >> 4) | ((int32_t)a[5 * i + 3] << 4)) & 0x3FF; + r->coeffs[4 * i + 3] = + ((a[5 * i + 3] >> 6) | ((int32_t)a[5 * i + 4] << 2)) & 0x3FF; + } + + mld_assert_bound(r->coeffs, MLDSA_N, 0, 1 << 10); +} + +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[8]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* Safety: a->coeffs[i] <= (1 << (MLDSA_D - 1) as they are output of + * power2round, hence, these casts are safe. */ + t[0] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 0]); + t[1] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 1]); + t[2] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 2]); + t[3] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 3]); + t[4] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 4]); + t[5] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 5]); + t[6] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 6]); + t[7] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 7]); + + r[13 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[13 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[13 * i + 1] |= (uint8_t)((t[1] << 5) & 0xFF); + r[13 * i + 2] = (uint8_t)((t[1] >> 3) & 0xFF); + r[13 * i + 3] = (uint8_t)((t[1] >> 11) & 0xFF); + r[13 * i + 3] |= (uint8_t)((t[2] << 2) & 0xFF); + r[13 * i + 4] = (uint8_t)((t[2] >> 6) & 0xFF); + r[13 * i + 4] |= (uint8_t)((t[3] << 7) & 0xFF); + r[13 * i + 5] = (uint8_t)((t[3] >> 1) & 0xFF); + r[13 * i + 6] = (uint8_t)((t[3] >> 9) & 0xFF); + r[13 * i + 6] |= (uint8_t)((t[4] << 4) & 0xFF); + r[13 * i + 7] = (uint8_t)((t[4] >> 4) & 0xFF); + r[13 * i + 8] = (uint8_t)((t[4] >> 12) & 0xFF); + r[13 * i + 8] |= (uint8_t)((t[5] << 1) & 0xFF); + r[13 * i + 9] = (uint8_t)((t[5] >> 7) & 0xFF); + r[13 * i + 9] |= (uint8_t)((t[6] << 6) & 0xFF); + r[13 * i + 10] = (uint8_t)((t[6] >> 2) & 0xFF); + r[13 * i + 11] = (uint8_t)((t[6] >> 10) & 0xFF); + r[13 * i + 11] |= (uint8_t)((t[7] << 3) & 0xFF); + r[13 * i + 12] = (uint8_t)((t[7] >> 5) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + { + r->coeffs[8 * i + 0] = a[13 * i + 0]; + r->coeffs[8 * i + 0] |= (int32_t)a[13 * i + 1] << 8; + r->coeffs[8 * i + 0] &= 0x1FFF; + + r->coeffs[8 * i + 1] = a[13 * i + 1] >> 5; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 2] << 3; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 3] << 11; + r->coeffs[8 * i + 1] &= 0x1FFF; + + r->coeffs[8 * i + 2] = a[13 * i + 3] >> 2; + r->coeffs[8 * i + 2] |= (int32_t)a[13 * i + 4] << 6; + r->coeffs[8 * i + 2] &= 0x1FFF; + + r->coeffs[8 * i + 3] = a[13 * i + 4] >> 7; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 5] << 1; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 6] << 9; + r->coeffs[8 * i + 3] &= 0x1FFF; + + r->coeffs[8 * i + 4] = a[13 * i + 6] >> 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 7] << 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 8] << 12; + r->coeffs[8 * i + 4] &= 0x1FFF; + + r->coeffs[8 * i + 5] = a[13 * i + 8] >> 1; + r->coeffs[8 * i + 5] |= (int32_t)a[13 * i + 9] << 7; + r->coeffs[8 * i + 5] &= 0x1FFF; + + r->coeffs[8 * i + 6] = a[13 * i + 9] >> 6; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 10] << 2; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 11] << 10; + r->coeffs[8 * i + 6] &= 0x1FFF; + + r->coeffs[8 * i + 7] = a[13 * i + 11] >> 3; + r->coeffs[8 * i + 7] |= (int32_t)a[13 * i + 12] << 5; + r->coeffs[8 * i + 7] &= 0x1FFF; + + r->coeffs[8 * i + 0] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 7]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +MLD_STATIC_TESTABLE uint32_t mld_poly_chknorm_c(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == array_abs_bound(a->coeffs, 0, i, B)) + ) + { + /* + * Since we know that -MLD_REDUCE32_RANGE_MAX <= a < MLD_REDUCE32_RANGE_MAX, + * and B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX, to check if + * -B < (a mod± MLDSA_Q) < B, it suffices to check if -B < a < B. + * + * We prove this to be true using the following CBMC assertions. + * a ==> b expressed as !a || b to also allow run-time assertion. + */ + mld_assert(a->coeffs[i] < B || a->coeffs[i] - MLDSA_Q <= -B); + mld_assert(a->coeffs[i] > -B || a->coeffs[i] + MLDSA_Q >= B); + + /* Reference: Leaks which coefficient violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + + /* if (abs(a[i]) >= B) */ + t |= mld_ct_cmask_neg_i32(B - 1 - mld_ct_abs_i32(a->coeffs[i])); + } + + return t; +} + +/* Reference: explicitly checks the bound B to be <= (MLDSA_Q - 1) / 8). + * This is unnecessary as it's always a compile-time constant. + * We instead model it as a precondition. + * Checking the bound is performed using a conditional arguing + * that it is okay to leak which coefficient violates the bound (while the + * coefficient itself must remain secret). + * We instead perform everything in constant-time. + * Also it is sufficient to check that it is smaller than + * MLDSA_Q - MLD_REDUCE32_RANGE_MAX > (MLDSA_Q - 1) / 8). + */ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +{ +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) + int ret; + int success; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + /* The native backend returns 0 if all coefficients are within the bound, + * 1 if at least one coefficient exceeds the bound, and + * -1 (MLD_NATIVE_FUNC_FALLBACK) if the platform does not have the + * required capabilities to run the native function. + */ + ret = mld_poly_chknorm_native(a->coeffs, B); + + success = (ret != MLD_NATIVE_FUNC_FALLBACK); + /* Constant-time: It would be fine to leak the return value of chknorm + * entirely (as it is fine to leak if any coefficient exceeded the bound or + * not). However, it is cleaner to perform declassification in sign.c. + * Hence, here we only declassify if the native function returned + * MLD_NATIVE_FUNC_FALLBACK or not (which solely depends on system + * capabilities). + */ + MLD_CT_TESTING_DECLASSIFY(&success, sizeof(int)); + if (success) + { + /* Convert 0 / 1 to 0 / 0xFFFFFFFF here */ + return 0U - (uint32_t)ret; + } +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + return mld_poly_chknorm_c(a, B); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ +MLD_EMPTY_CU(mld_poly) +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_POLY_UNIFORM_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/poly.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/poly.h new file mode 100644 index 0000000000..ff7710438e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/poly.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_H +#define MLD_POLY_H + +#include +#include "cbmc.h" +#include "common.h" +#include "reduce.h" +#include "rounding.h" + +/* Absolute exclusive upper bound for the output of the forward NTT */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) +/* Absolute exclusive upper bound for the output of the inverse NTT*/ +#define MLD_INTT_BOUND MLDSA_Q + +typedef struct +{ + int32_t coeffs[MLDSA_N]; +} MLD_ALIGN mld_poly; + +#define mld_poly_reduce MLD_NAMESPACE(poly_reduce) +/************************************************* + * Name: mld_poly_reduce + * + * Description: Inplace reduction of all coefficients of polynomial to + * representative in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) +); + +#define mld_poly_caddq MLD_NAMESPACE(poly_caddq) +/************************************************* + * Name: mld_poly_caddq + * + * Description: For all coefficients of in/out polynomial add MLDSA_Q if + * coefficient is negative. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_add MLD_NAMESPACE(poly_add) +/************************************************* + * Name: mld_poly_add + * + * Description: Add polynomials. No modular reduction is performed. + * + * Arguments: - r: Pointer to input-output polynomial to be added to. + * - b: Pointer to input polynomial that should be added + * to r. Must be disjoint from r. + **************************************************/ + +/* + * NOTE: The reference implementation uses a 3-argument poly_add. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(forall(k0, 0, MLDSA_N, (int64_t) r->coeffs[k0] + b->coeffs[k0] < MLD_REDUCE32_DOMAIN_MAX)) + requires(forall(k1, 0, MLDSA_N, (int64_t) r->coeffs[k1] + b->coeffs[k1] >= INT32_MIN)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(forall(k2, 0, MLDSA_N, r->coeffs[k2] == old(*r).coeffs[k2] + b->coeffs[k2])) + ensures(forall(k3, 0, MLDSA_N, r->coeffs[k3] < MLD_REDUCE32_DOMAIN_MAX)) + ensures(forall(k4, 0, MLDSA_N, r->coeffs[k4] >= INT32_MIN)) +); + +#define mld_poly_sub MLD_NAMESPACE(poly_sub) +/************************************************* + * Name: mld_poly_sub + * + * Description: Subtract polynomials. No modular reduction is + * performed. + * + * Arguments: - mld_poly *r: Pointer to input-output polynomial. + * - const mld_poly *b: Pointer to input polynomial that should be + * subtracted from r. Must be disjoint from r. + **************************************************/ +/* + * NOTE: The reference implementation uses a 3-argument poly_sub. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_Q)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) +); + +#define mld_poly_shiftl MLD_NAMESPACE(poly_shiftl) +/************************************************* + * Name: mld_poly_shiftl + * + * Description: Multiply polynomial by 2^MLDSA_D without modular reduction. + *Assumes input coefficients to be less than 2^{31-MLDSA_D} in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_ntt MLD_NAMESPACE(poly_ntt) +/************************************************* + * Name: mld_poly_ntt + * + * Description: Inplace forward NTT. Coefficients can grow by + * 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +); + + +#define mld_poly_invntt_tomont MLD_NAMESPACE(poly_invntt_tomont) +/************************************************* + * Name: mld_poly_invntt_tomont + * + * Description: Inplace inverse NTT and multiplication by 2^{32}. + * Input coefficients need to be less than MLDSA_Q in absolute + * value and output coefficients are bounded by + * MLD_INTT_BOUND. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +); + +#define mld_poly_pointwise_montgomery MLD_NAMESPACE(poly_pointwise_montgomery) +/************************************************* + * Name: mld_poly_pointwise_montgomery + * + * Description: Pointwise multiplication of polynomials in NTT domain + * representation and multiplication of resulting polynomial + * by 2^{-32}. + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const mld_poly *a: pointer to first input polynomial + * - const mld_poly *b: pointer to second input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + +#define mld_poly_power2round MLD_NAMESPACE(poly_power2round) +/************************************************* + * Name: mld_poly_power2round + * + * Description: For all coefficients c of the input polynomial, + * compute c0, c1 such that c mod MLDSA_Q = c1*2^MLDSA_D + c0 + * with -2^{MLDSA_D-1} < c0 <= 2^{MLDSA_D-1}. Assumes coefficients + *to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + *c1 + * - mld_poly *a0: pointer to output polynomial with coefficients + *c0 + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +__contract__( + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a0->coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) +); + +#define mld_poly_uniform MLD_NAMESPACE(poly_uniform) +/************************************************* + * Name: mld_poly_uniform + * + * Description: Sample polynomial with uniformly random coefficients + * in [0,MLDSA_Q-1] by performing rejection sampling on the + * output stream of SHAKE128(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_SEEDBYTES and the packed 2-byte nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES + 2)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +#define mld_poly_uniform_4x MLD_NAMESPACE(poly_uniform_4x) +/************************************************* + * Name: mld_poly_uniform_x4 + * + * Description: Generate four polynomials using rejection sampling + * on (pseudo-)uniformly random bytes sampled from a seed. + * + * Arguments: - mld_poly *vec0, *vec1, *vec2, *vec3: + * Pointers to 4 polynomials to be sampled. + * - uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]: + * Pointer consecutive array of seed buffers of size + * MLDSA_SEEDBYTES + 2 each, plus padding for alignment. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +__contract__( + requires(memory_no_alias(vec0, sizeof(mld_poly))) + requires(memory_no_alias(vec1, sizeof(mld_poly))) + requires(memory_no_alias(vec2, sizeof(mld_poly))) + requires(memory_no_alias(vec3, sizeof(mld_poly))) + requires(memory_no_alias(seed, 4 * MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2))) + assigns(memory_slice(vec0, sizeof(mld_poly))) + assigns(memory_slice(vec1, sizeof(mld_poly))) + assigns(memory_slice(vec2, sizeof(mld_poly))) + assigns(memory_slice(vec3, sizeof(mld_poly))) + ensures(array_bound(vec0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec1->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec2->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec3->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +#define mld_polyt1_pack MLD_NAMESPACE(polyt1_pack) +/************************************************* + * Name: mld_polyt1_pack + * + * Description: Bit-pack polynomial t1 with coefficients fitting in 10 bits. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(r, MLDSA_POLYT1_PACKEDBYTES)) +); + +#define mld_polyt1_unpack MLD_NAMESPACE(polyt1_unpack) +/************************************************* + * Name: mld_polyt1_unpack + * + * Description: Unpack polynomial t1 with 10-bit coefficients. + * Output coefficients are standard representatives. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT1_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, 0, 1 << 10)) +); + +#define mld_polyt0_pack MLD_NAMESPACE(polyt0_pack) +/************************************************* + * Name: mld_polyt0_pack + * + * Description: Bit-pack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + * 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) + assigns(memory_slice(r, MLDSA_POLYT0_PACKEDBYTES)) +); + + +#define mld_polyt0_unpack MLD_NAMESPACE(polyt0_unpack) +/************************************************* + * Name: mld_polyt0_unpack + * + * Description: Unpack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + *2^{MLDSA_D-1}]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT0_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) +); + +#define mld_poly_chknorm MLD_NAMESPACE(poly_chknorm) +/************************************************* + * Name: mld_poly_chknorm + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const mld_poly *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if norm is strictly smaller than + * B <= (MLDSA_Q - MLD_REDUCE32_RANGE_MAX) and 0xFFFFFFFF otherwise. + * + * Specification: The definition of this FIPS-204 requires signed canonical + * reduction prior to applying the bounds check. + * However, `-B < (a mod± MLDSA_Q) < B` is equivalent to + * `-B < a < B` under the assumption that + * `B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX` (cf. the assertion in + * the code). Hence, the present spec and implementation are + * correct without reduction. + * + **************************************************/ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +); + +#endif /* !MLD_POLY_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/poly_kl.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/poly_kl.c new file mode 100644 index 0000000000..7a319ca515 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/poly_kl.c @@ -0,0 +1,931 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "ct.h" +#include "debug.h" +#include "poly_kl.h" +#include "rounding.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_rej_eta MLD_ADD_PARAM_SET(mld_rej_eta) +#define mld_rej_eta_c MLD_ADD_PARAM_SET(mld_rej_eta_c) +#define mld_poly_decompose_c MLD_ADD_PARAM_SET(mld_poly_decompose_c) +#define mld_poly_use_hint_c MLD_ADD_PARAM_SET(mld_poly_use_hint_c) +#define mld_polyz_unpack_c MLD_ADD_PARAM_SET(mld_polyz_unpack_c) +/* End of parameter set namespacing */ + + +MLD_STATIC_TESTABLE +void mld_poly_decompose_c(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +) +{ + unsigned int i; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, i, MLDSA_N, 0, MLDSA_Q)) + invariant(array_bound(a1->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + invariant(array_abs_bound(a0->coeffs, 0, i, MLDSA_GAMMA2+1)) + ) + { + mld_decompose(&a0->coeffs[i], &a1->coeffs[i], a0->coeffs[i]); + } + + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +{ +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_88_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_32_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_DECOMPOSE_88 && MLD_CONFIG_PARAMETER_SET == \ + 44) && MLD_USE_NATIVE_POLY_DECOMPOSE_32 && (MLD_CONFIG_PARAMETER_SET \ + == 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_decompose_c(a1, a0); +} + +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(s <= i) + invariant(array_bound(h->coeffs, 0, i, 0, 2)) + ) + { + const unsigned int hint_bit = mld_make_hint(a0->coeffs[i], a1->coeffs[i]); + h->coeffs[i] = (int32_t)hint_bit; + s += hint_bit; + } + + mld_assert(s <= MLDSA_N); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + return s; +} + +MLD_STATIC_TESTABLE void mld_poly_use_hint_c(mld_poly *b, const mld_poly *a, + const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(b->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ) + { + b->coeffs[i] = mld_use_hint(a->coeffs[i], h->coeffs[i]); + } + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +{ +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_88_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_USE_HINT_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_32_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_USE_HINT_88 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLY_USE_HINT_32 && (MLD_CONFIG_PARAMETER_SET == \ + 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_use_hint_c(b, a, h); +} + +/************************************************* + * Name: mld_rej_eta + * + * Description: Sample uniformly random coefficients in [-MLDSA_ETA, MLDSA_ETA] + *by performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes + * + * Returns number of sampled coefficients. Can be smaller than target if not + *enough random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_eta()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +#if MLDSA_ETA == 2 +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 1 +#elif MLDSA_ETA == 4 +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 2 +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + +MLD_STATIC_TESTABLE unsigned int mld_rej_eta_c(int32_t *a, unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ + unsigned int ctr, pos; + int t_valid; + uint32_t t0, t1; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + ctr = offset; + pos = 0; + while (ctr < target && pos < buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_abs_bound(a, 0, ctr, MLDSA_ETA + 1)) + ) + { + t0 = buf[pos] & 0x0F; + t1 = buf[pos++] >> 4; + + /* Constant time: The inputs and outputs to the rejection sampling are + * secret. However, it is fine to leak which coefficients have been + * rejected. For constant-time testing, we declassify the result of + * the comparison. + */ +#if MLDSA_ETA == 2 + t_valid = t0 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 15 */ + { + t0 = t0 - (205 * t0 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t0; + } + t_valid = t1 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) /* t1 < 15 */ + { + t1 = t1 - (205 * t1 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t1; + } +#elif MLDSA_ETA == 4 + t_valid = t0 < 9; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 9 */ + { + a[ctr++] = 4 - (int32_t)t0; + } + t_valid = t1 < 9; /* t1 < 9 */ + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) + { + a[ctr++] = 4 - (int32_t)t1; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + } + + mld_assert_abs_bound(a, ctr, MLDSA_ETA + 1); + + return ctr; +} + +static unsigned int mld_rej_eta(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ +#if MLDSA_ETA == 2 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta2_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#elif MLDSA_ETA == 4 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta4_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#endif /* !(MLDSA_ETA == 2 && MLD_USE_NATIVE_REJ_UNIFORM_ETA2) && MLDSA_ETA == \ + 4 && MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + + return mld_rej_eta_c(a, target, offset, buf, buflen); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_ETA_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof256_x4_ctx state; + unsigned buflen; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = nonce0; + extseed[1][MLDSA_CRHBYTES] = nonce1; + extseed[2][MLDSA_CRHBYTES] = nonce2; + extseed[3][MLDSA_CRHBYTES] = nonce3; + extseed[0][MLDSA_CRHBYTES + 1] = 0; + extseed[1][MLDSA_CRHBYTES + 1] = 0; + extseed[2][MLDSA_CRHBYTES + 1] = 0; + extseed[3][MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(r0, sizeof(mld_poly)), + memory_slice(r1, sizeof(mld_poly)), memory_slice(r2, sizeof(mld_poly)), + memory_slice(r3, sizeof(mld_poly)), object_whole(buf[0]), + object_whole(buf[1]), object_whole(buf[2]), + object_whole(buf[3])) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_abs_bound(r0->coeffs, 0, ctr[0], MLDSA_ETA + 1)) + invariant(array_abs_bound(r1->coeffs, 0, ctr[1], MLDSA_ETA + 1)) + invariant(array_abs_bound(r2->coeffs, 0, ctr[2], MLDSA_ETA + 1)) + invariant(array_abs_bound(r3->coeffs, 0, ctr[3], MLDSA_ETA + 1))) + { + mld_xof256_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + + mld_xof256_x4_release(&state); + + mld_assert_abs_bound(r0->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r1->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r2->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r3->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +{ + /* Temporary buffer for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr; + mld_xof256_ctx state; + unsigned buflen; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = nonce; + extseed[MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr = mld_rej_eta(r->coeffs, MLDSA_N, 0, buf, buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, object_whole(&state), + object_whole(buf), memory_slice(r, sizeof(mld_poly))) + invariant(ctr <= MLDSA_N) + invariant(state.pos <= SHAKE256_RATE) + invariant(array_abs_bound(r->coeffs, 0, ctr, MLDSA_ETA + 1))) + { + mld_xof256_squeezeblocks(buf, 1, &state); + ctr = mld_rej_eta(r->coeffs, MLDSA_N, ctr, buf, buflen); + } + + mld_xof256_release(&state); + + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define MLD_POLY_UNIFORM_GAMMA1_NBLOCKS \ + ((MLDSA_POLYZ_PACKEDBYTES + MLD_STREAM256_BLOCKBYTES - 1) / \ + MLD_STREAM256_BLOCKBYTES) + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + mld_xof256_ctx state; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = (uint8_t)(nonce & 0xFF); + extseed[MLDSA_CRHBYTES + 1] = (uint8_t)(nonce >> 8); + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + mld_polyz_unpack(a, buf); + + mld_xof256_release(&state); + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + mld_xof256_x4_ctx state; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = (uint8_t)(nonce0 & 0xFF); + extseed[1][MLDSA_CRHBYTES] = (uint8_t)(nonce1 & 0xFF); + extseed[2][MLDSA_CRHBYTES] = (uint8_t)(nonce2 & 0xFF); + extseed[3][MLDSA_CRHBYTES] = (uint8_t)(nonce3 & 0xFF); + extseed[0][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce0 >> 8); + extseed[1][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce1 >> 8); + extseed[2][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce2 >> 8); + extseed[3][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce3 >> 8); + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + + mld_polyz_unpack(r0, buf[0]); + mld_polyz_unpack(r1, buf[1]); + mld_polyz_unpack(r2, buf[2]); + mld_polyz_unpack(r3, buf[3]); + mld_xof256_x4_release(&state); + + mld_assert_bound(r0->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r1->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r2->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r3->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +{ + unsigned int i, j, pos; + uint64_t signs; + uint64_t offset; + MLD_ALIGN uint8_t buf[SHAKE256_RATE]; + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, seed, MLDSA_CTILDEBYTES); + mld_shake256_finalize(&state); + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + + /* Convert the first 8 bytes of buf[] into an unsigned 64-bit value. */ + /* Each bit of that dictates the sign of the resulting challenge value */ + signs = 0; + for (i = 0; i < 8; ++i) + __loop__( + assigns(i, signs) + invariant(i <= 8) + ) + { + signs |= (uint64_t)buf[i] << 8 * i; + } + pos = 8; + + mld_memset(c, 0, sizeof(mld_poly)); + + for (i = MLDSA_N - MLDSA_TAU; i < MLDSA_N; ++i) + __loop__( + assigns(i, j, object_whole(buf), state, pos, memory_slice(c, sizeof(mld_poly)), signs) + invariant(i >= MLDSA_N - MLDSA_TAU) + invariant(i <= MLDSA_N) + invariant(pos >= 1) + invariant(pos <= SHAKE256_RATE) + invariant(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) + invariant(state.pos <= SHAKE256_RATE) + ) + { + do + __loop__( + assigns(j, object_whole(buf), state, pos) + invariant(state.pos <= SHAKE256_RATE) + ) + { + if (pos >= SHAKE256_RATE) + { + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + pos = 0; + } + j = buf[pos++]; + } while (j > i); + + c->coeffs[i] = c->coeffs[j]; + + /* Reference: Compute coefficent value here in two steps to */ + /* mixinf unsigned and signed arithmetic with implicit */ + /* conversions, and so that CBMC can keep track of ranges */ + /* to complete type-safety proof here. */ + + /* The least-significant bit of signs tells us if we want -1 or +1 */ + offset = 2 * (signs & 1); + + /* offset has value 0 or 2 here, so (1 - (int32_t) offset) has + * value -1 or +1 */ + c->coeffs[j] = 1 - (int32_t)offset; + + /* Move to the next bit of signs for next time */ + signs >>= 1; + } + + mld_assert_bound(c->coeffs, MLDSA_N, -1, 2); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(&signs, sizeof(signs)); +} + +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint8_t t[8]; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_ETA + 1); + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 1]); + t[2] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 2]); + t[3] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 3]); + t[4] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 4]); + t[5] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 5]); + t[6] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 6]); + t[7] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 7]); + + r[3 * i + 0] = (uint8_t)(((t[0] >> 0) | (t[1] << 3) | (t[2] << 6)) & 0xFF); + r[3 * i + 1] = + (uint8_t)(((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)) & + 0xFF); + r[3 * i + 2] = (uint8_t)(((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)) & 0xFF); + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 1]); + r[i] = (uint8_t)(t[0] | (t[1] << 4)); + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ +} + +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -5, MLDSA_ETA + 1))) + { + r->coeffs[8 * i + 0] = (a[3 * i + 0] >> 0) & 7; + r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 7; + r->coeffs[8 * i + 2] = ((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 7; + r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 7; + r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 7; + r->coeffs[8 * i + 5] = ((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 7; + r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 7; + r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5) & 7; + + r->coeffs[8 * i + 0] = MLDSA_ETA - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = MLDSA_ETA - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = MLDSA_ETA - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = MLDSA_ETA - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = MLDSA_ETA - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = MLDSA_ETA - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = MLDSA_ETA - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = MLDSA_ETA - r->coeffs[8 * i + 7]; + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -11, MLDSA_ETA + 1))) + { + r->coeffs[2 * i + 0] = a[i] & 0x0F; + r->coeffs[2 * i + 1] = a[i] >> 4; + r->coeffs[2 * i + 0] = MLDSA_ETA - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_ETA - r->coeffs[2 * i + 1]; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + + mld_assert_bound(r->coeffs, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + + +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[4]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 1]); + t[2] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 2]); + t[3] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 3]); + + r[9 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[9 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[9 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[9 * i + 2] |= (uint8_t)((t[1] << 2) & 0xFF); + r[9 * i + 3] = (uint8_t)((t[1] >> 6) & 0xFF); + r[9 * i + 4] = (uint8_t)((t[1] >> 14) & 0xFF); + r[9 * i + 4] |= (uint8_t)((t[2] << 4) & 0xFF); + r[9 * i + 5] = (uint8_t)((t[2] >> 4) & 0xFF); + r[9 * i + 6] = (uint8_t)((t[2] >> 12) & 0xFF); + r[9 * i + 6] |= (uint8_t)((t[3] << 6) & 0xFF); + r[9 * i + 7] = (uint8_t)((t[3] >> 2) & 0xFF); + r[9 * i + 8] = (uint8_t)((t[3] >> 10) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 1]); + + r[5 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[5 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[5 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[5 * i + 2] |= (uint8_t)((t[1] << 4) & 0xFF); + r[5 * i + 3] = (uint8_t)((t[1] >> 4) & 0xFF); + r[5 * i + 4] = (uint8_t)((t[1] >> 12) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +MLD_STATIC_TESTABLE void mld_polyz_unpack_c( + mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +) +{ + unsigned int i; +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[4 * i + 0] = a[9 * i + 0]; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 2] << 16; + r->coeffs[4 * i + 0] &= 0x3FFFF; + + r->coeffs[4 * i + 1] = a[9 * i + 2] >> 2; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 3] << 6; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 4] << 14; + r->coeffs[4 * i + 1] &= 0x3FFFF; + + r->coeffs[4 * i + 2] = a[9 * i + 4] >> 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 5] << 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 6] << 12; + r->coeffs[4 * i + 2] &= 0x3FFFF; + + r->coeffs[4 * i + 3] = a[9 * i + 6] >> 6; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 7] << 2; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10; + r->coeffs[4 * i + 3] &= 0x3FFFF; + + r->coeffs[4 * i + 0] = MLDSA_GAMMA1 - r->coeffs[4 * i + 0]; + r->coeffs[4 * i + 1] = MLDSA_GAMMA1 - r->coeffs[4 * i + 1]; + r->coeffs[4 * i + 2] = MLDSA_GAMMA1 - r->coeffs[4 * i + 2]; + r->coeffs[4 * i + 3] = MLDSA_GAMMA1 - r->coeffs[4 * i + 3]; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[2 * i + 0] = a[5 * i + 0]; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 2] << 16; + r->coeffs[2 * i + 0] &= 0xFFFFF; + + r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 3] << 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12; + /* r->coeffs[2*i+1] &= 0xFFFFF; */ /* No effect, since we're anyway at 20 + bits */ + + r->coeffs[2 * i + 0] = MLDSA_GAMMA1 - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_GAMMA1 - r->coeffs[2 * i + 1]; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +{ +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + ret = mld_polyz_unpack_17_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#elif defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + ret = mld_polyz_unpack_19_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYZ_UNPACK_17 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLYZ_UNPACK_19 && (MLD_CONFIG_PARAMETER_SET == 65 \ + || MLD_CONFIG_PARAMETER_SET == 87) */ + + mld_polyz_unpack_c(r, a); +} + +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + + mld_assert_bound(a->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[3 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0]) & 0xFF); + r[3 * i + 0] |= (uint8_t)((a->coeffs[4 * i + 1] << 6) & 0xFF); + r[3 * i + 1] = (uint8_t)((a->coeffs[4 * i + 1] >> 2) & 0xFF); + r[3 * i + 1] |= (uint8_t)((a->coeffs[4 * i + 2] << 4) & 0xFF); + r[3 * i + 2] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) & 0xFF); + r[3 * i + 2] |= (uint8_t)((a->coeffs[4 * i + 3] << 2) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + r[i] = + (uint8_t)((a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_rej_eta +#undef mld_rej_eta_c +#undef mld_poly_decompose_c +#undef mld_poly_use_hint_c +#undef mld_polyz_unpack_c +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_GAMMA1_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/poly_kl.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/poly_kl.h new file mode 100644 index 0000000000..c6aa498358 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/poly_kl.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_KL_H +#define MLD_POLY_KL_H + +#include "cbmc.h" +#include "common.h" +#include "poly.h" + +#define mld_poly_decompose MLD_NAMESPACE_KL(poly_decompose) +/************************************************* + * Name: mld_poly_decompose + * + * Description: For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such c mod MLDSA_Q = c1*ALPHA + + * c0 with -ALPHA/2 < c0 <= ALPHA/2 except + * c1 = (MLDSA_Q-1)/ALPHA where we set + * c1 = 0 and -ALPHA/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + * c1 + * - mld_poly *a0: pointer to input/output polynomial. Output + * polynomial has coefficients c0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +); + + +#define mld_poly_make_hint MLD_NAMESPACE_KL(poly_make_hint) +/************************************************* + * Name: mld_poly_make_hint + * + * Description: Compute hint polynomial. The coefficients of which indicate + * whether the low bits of the corresponding coefficient of + * the input polynomial overflow into the high bits. + * + * Arguments: - mld_poly *h: pointer to output hint polynomial + * - const mld_poly *a0: pointer to low part of input polynomial + * - const mld_poly *a1: pointer to high part of input polynomial + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + assigns(memory_slice(h, sizeof(mld_poly))) + ensures(return_value <= MLDSA_N) + ensures(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) +); + +#define mld_poly_use_hint MLD_NAMESPACE_KL(poly_use_hint) +/************************************************* + * Name: mld_poly_use_hint + * + * Description: Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - mld_poly *b: pointer to output polynomial with corrected high + *bits + * - const mld_poly *a: pointer to input polynomial + * - const mld_poly *h: pointer to input hint polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta_4x MLD_NAMESPACE_KL(poly_uniform_eta_4x) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample four polynomials with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce_i) + * + * Arguments: - mld_poly *r0: pointer to first output polynomial + * - mld_poly *r1: pointer to second output polynomial + * - mld_poly *r2: pointer to third output polynomial + * - mld_poly *r3: pointer to fourth output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce0: first nonce + * - uint8_t nonce1: second nonce + * - uint8_t nonce2: third nonce + * - uint8_t nonce3: fourth nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_abs_bound(r0->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r1->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r2->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r3->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta MLD_NAMESPACE_KL(poly_uniform_eta) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample polynomial with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce: nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1 MLD_NAMESPACE_KL(poly_uniform_gamma1) +/************************************************* + * Name: mld_poly_uniform_gamma1 + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1_4x MLD_NAMESPACE_KL(poly_uniform_gamma1_4x) +/************************************************* + * Name: mld_poly_uniform_gamma1_4x + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_bound(r0->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r1->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r2->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r3->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define mld_poly_challenge MLD_NAMESPACE_KL(poly_challenge) +/************************************************* + * Name: mld_poly_challenge + * + * Description: Implementation of H. Samples polynomial with MLDSA_TAU nonzero + * coefficients in {-1,1} using the output stream of + * SHAKE256(seed). + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const uint8_t mu[]: byte array containing seed of length + * MLDSA_CTILDEBYTES + **************************************************/ +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +__contract__( + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CTILDEBYTES)) + assigns(memory_slice(c, sizeof(mld_poly))) + /* All coefficients of c are -1, 0 or +1 */ + ensures(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) +); + +#define mld_polyeta_pack MLD_NAMESPACE_KL(polyeta_pack) +/************************************************* + * Name: mld_polyeta_pack + * + * Description: Bit-pack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYETA_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + assigns(memory_slice(r, MLDSA_POLYETA_PACKEDBYTES)) +); + +/* + * polyeta_unpack produces coefficients in [-MLDSA_ETA,MLDSA_ETA] for + * well-formed inputs (i.e., those produced by polyeta_pack). + * However, when passed an arbitrary byte array, it may produce smaller values, + * i.e, values in [MLD_POLYETA_UNPACK_LOWER_BOUND,MLDSA_ETA] + * Even though this should never happen, we use use the bound for arbitrary + * inputs in the CBMC proofs. + */ +#if MLDSA_ETA == 2 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-5) +#elif MLDSA_ETA == 4 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-11) +#else +#error "Invalid value of MLDSA_ETA" +#endif + +#define mld_polyeta_unpack MLD_NAMESPACE_KL(polyeta_unpack) +/************************************************* + * Name: mld_polyeta_unpack + * + * Description: Unpack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYETA_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)) +); + +#define mld_polyz_pack MLD_NAMESPACE_KL(polyz_pack) +/************************************************* + * Name: mld_polyz_pack + * + * Description: Bit-pack polynomial with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYZ_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(r, MLDSA_POLYZ_PACKEDBYTES)) +); + + +#define mld_polyz_unpack MLD_NAMESPACE_KL(polyz_unpack) +/************************************************* + * Name: mld_polyz_unpack + * + * Description: Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); + +#define mld_polyw1_pack MLD_NAMESPACE_KL(polyw1_pack) +/************************************************* + * Name: mld_polyw1_pack + * + * Description: Bit-pack polynomial w1 with coefficients in [0,15] or [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES)) +); + +#endif /* !MLD_POLY_KL_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/polyvec.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/polyvec.c new file mode 100644 index 0000000000..5c3a08ab32 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/polyvec.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include +#include + +#include "common.h" +#include "debug.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" + +/* This namespacing is not done at the top to avoid a naming conflict + * with native backends, which are currently not yet namespaced. */ +#define mld_polymat_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polymat_permute_bitrev_to_custom) +#define mld_polyvecl_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polyvecl_permute_bitrev_to_custom) +#define mld_polyvecl_pointwise_acc_montgomery_c \ + MLD_ADD_PARAM_SET(mld_polyvecl_pointwise_acc_montgomery_c) + +#if !defined(MLD_CONFIG_REDUCE_RAM) +/* Helper function to ensure that the polynomial entries in the output + * of mld_polyvec_matrix_expand use the standard (bitreversed) ordering + * of coefficients. + * No-op unless a native backend with a custom ordering is used. + */ + +static void mld_polyvecl_permute_bitrev_to_custom(mld_polyvecl *v) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +{ +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + unsigned i; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_permute_bitrev_to_custom(v->vec[i].coeffs); + } +#else /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + /* Nothing to do */ + (void)v; +#endif /* !MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ +} + +static void mld_polymat_permute_bitrev_to_custom(mld_polymat *mat) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; i++) + __loop__( + assigns(i, memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))) + { + mld_polyvecl_permute_bitrev_to_custom(&mat->vec[i]); + } +} +#endif /* !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + unsigned int i; + MLD_ALIGN uint8_t seed_ext[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + mld_memcpy(seed_ext, mat->rho, MLDSA_SEEDBYTES); + + /* Generate row on-demand */ + for (i = 0; i < MLDSA_L; i++) + { + uint8_t x = (uint8_t)row; + uint8_t y = (uint8_t)i; + + seed_ext[MLDSA_SEEDBYTES + 0] = y; + seed_ext[MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(&mat->row_buffer.vec[i], seed_ext); + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + mld_poly_permute_bitrev_to_custom(mat->row_buffer.vec[i].coeffs); +#endif + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); + + return &mat->row_buffer; +#else /* MLD_CONFIG_REDUCE_RAM */ + return &mat->vec[row]; +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + /* In REDUCE_RAM mode, just copy the seed for later on-demand generation */ + mld_memcpy(mat->rho, rho, MLDSA_SEEDBYTES); +#else + unsigned int i, j; + /* + * We generate four separate seed arrays rather than a single one to work + * around limitations in CBMC function contracts dealing with disjoint slices + * of the same parent object. + */ + + MLD_ALIGN uint8_t seed_ext[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + mld_memcpy(seed_ext[j], rho, MLDSA_SEEDBYTES); + } + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + /* Sample 4 matrix entries a time. */ + for (i = 0; i < (MLDSA_K * MLDSA_L / 4) * 4; i += 4) + __loop__( + assigns(i, j, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= (MLDSA_K * MLDSA_L / 4) * 4 && i % 4 == 0) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + uint8_t x = (uint8_t)((i + j) / MLDSA_L); + uint8_t y = (uint8_t)((i + j) % MLDSA_L); + + seed_ext[j][MLDSA_SEEDBYTES + 0] = y; + seed_ext[j][MLDSA_SEEDBYTES + 1] = x; + } + + mld_poly_uniform_4x(&mat->vec[i / MLDSA_L].vec[i % MLDSA_L], + &mat->vec[(i + 1) / MLDSA_L].vec[(i + 1) % MLDSA_L], + &mat->vec[(i + 2) / MLDSA_L].vec[(i + 2) % MLDSA_L], + &mat->vec[(i + 3) / MLDSA_L].vec[(i + 3) % MLDSA_L], + seed_ext); + } +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + i = 0; +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + /* Entries omitted by the batch-sampling are sampled individually. */ + while (i < MLDSA_K * MLDSA_L) + __loop__( + assigns(i, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K * MLDSA_L) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + uint8_t x = (uint8_t)(i / MLDSA_L); + uint8_t y = (uint8_t)(i % MLDSA_L); + mld_poly *this_poly = &mat->vec[i / MLDSA_L].vec[i % MLDSA_L]; + + seed_ext[0][MLDSA_SEEDBYTES + 0] = y; + seed_ext[0][MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(this_poly, seed_ext[0]); + i++; + } + + mld_polymat_permute_bitrev_to_custom(mat); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(t, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + const mld_polyvecl *row = mld_polymat_get_row(mat, i); + mld_polyvecl_pointwise_acc_montgomery(&t->vec[i], row, v); + } + + mld_assert_abs_bound_2d(t->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_L **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; +#endif + + /* Safety: nonce is at most ((UINT16_MAX - MLDSA_L) / MLDSA_L), and, hence, + * this cast is safe. See MLD_NONCE_UB comment in sign.c. */ + nonce = (uint16_t)(MLDSA_L * nonce); + /* Now, nonce <= UINT16_MAX - (MLDSA_L - 1), so the casts below are safe. */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_gamma1(&v->vec[i], seed, (uint16_t)(nonce + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLDSA_L == 4 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); +#elif MLDSA_L == 5 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); + mld_poly_uniform_gamma1(&v->vec[4], seed, (uint16_t)(nonce + 4)); +#elif MLDSA_L == 7 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], + &v->vec[3 /* irrelevant */], seed, nonce, + (uint16_t)(nonce + 1), (uint16_t)(nonce + 2), + 0xFF /* irrelevant */); + mld_poly_uniform_gamma1_4x(&v->vec[3], &v->vec[4], &v->vec[5], &v->vec[6], + seed, (uint16_t)(nonce + 3), (uint16_t)(nonce + 4), + (uint16_t)(nonce + 5), (uint16_t)(nonce + 6)); +#endif /* MLDSA_L == 7 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(k0, i, MLDSA_L, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_STATIC_TESTABLE void mld_polyvecl_pointwise_acc_montgomery_c( + mld_poly *w, const mld_polyvecl *u, const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i, j; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + for (i = 0; i < MLDSA_N; i++) + __loop__( + assigns(i, j, memory_slice(w, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_abs_bound(w->coeffs, 0, i, MLDSA_Q)) + ) + { + int64_t t = 0; + int32_t r; + for (j = 0; j < MLDSA_L; j++) + __loop__( + assigns(j, t) + invariant(j <= MLDSA_L) + invariant(t >= -(int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + invariant(t <= (int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + ) + { + t += (int64_t)u->vec[j].coeffs[i] * v->vec[j].coeffs[i]; + } + + r = mld_montgomery_reduce(t); + w->coeffs[i] = r; + } + + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +{ +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) && \ + MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l4_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) && \ + MLD_CONFIG_PARAMETER_SET == 65 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l5_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) && \ + MLD_CONFIG_PARAMETER_SET == 87 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l7_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 && \ + MLD_CONFIG_PARAMETER_SET == 44) && \ + !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 && \ + MLD_CONFIG_PARAMETER_SET == 65) && \ + MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 && \ + MLD_CONFIG_PARAMETER_SET == 87 */ + /* The first input is bounded by [0, Q-1] inclusive + * The second input is bounded by [-9Q+1, 9Q-1] inclusive . Hence, we can + * safely accumulate in 64-bits without intermediate reductions as + * MLDSA_L * (MLD_NTT_BOUND-1) * (Q-1) < INT64_MAX + * + * The worst case is ML-DSA-87: 7 * (9Q-1) * (Q-1) < 2**52 + * (and likewise for negative values) + */ + mld_polyvecl_pointwise_acc_montgomery_c(w, u, v); +} + +MLD_INTERNAL_API +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + invariant(i <= MLDSA_L) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + return t; +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_K **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k2, 0, i, + array_bound(v->vec[k2].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ) + { + mld_poly_reduce(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_caddq(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, + forall(k1, 0, MLDSA_N, u->vec[k0].coeffs[k1] == loop_entry(*u).vec[k0].coeffs[k1]))) + invariant(forall(k6, 0, i, array_bound(u->vec[k6].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + ) + { + mld_poly_add(&u->vec[i], &v->vec[i]); + } + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(u->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, u->vec[k1].coeffs[n1] == loop_entry(*u).vec[k1].coeffs[n1])))) + { + mld_poly_sub(&u->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, v->vec[k1].coeffs[n1] == loop_entry(*v).vec[k1].coeffs[n1]))) + ) + { + mld_poly_shiftl(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))) + { + mld_poly_invntt_tomont(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_INTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, array_abs_bound(r->vec[k2].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + mld_poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]); + } + mld_assert_abs_bound_2d(r->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + + return t; +} + +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + invariant(forall(k2, 0, i, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) + ) + { + mld_poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +{ + unsigned int i; + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + invariant(forall(k2, 0, i, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) + invariant(forall(k3, i, MLDSA_K, + array_bound(v0->vec[k3].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + ) + { + mld_poly_decompose(&v1->vec[i], &v0->vec[i]); + } + + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + mld_assert_abs_bound_2d(v0->vec, MLDSA_K, MLDSA_N, MLDSA_GAMMA2 + 1); +} + +MLD_INTERNAL_API +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, s, memory_slice(h, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(s <= i * MLDSA_N) + invariant(forall(k1, 0, i, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + s += mld_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]); + } + + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + return s; +} + +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *u, + const mld_polyveck *h) +{ + unsigned int i; + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(w, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)))) + ) + { + mld_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]); + } + + mld_assert_bound_2d(w->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +{ + unsigned int i; + mld_assert_bound_2d(w1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyw1_pack(&r[i * MLDSA_POLYW1_PACKEDBYTES], &w1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt0_pack(&r[i * MLDSA_POLYT0_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyz_unpack(&z->vec[i], r + i * MLDSA_POLYZ_PACKEDBYTES); + } + + mld_assert_bound_2d(z->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt0_unpack(&p->vec[i], r + i * MLDSA_POLYT0_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_polymat_permute_bitrev_to_custom +#undef mld_polyvecl_permute_bitrev_to_custom +#undef mld_polyvecl_pointwise_acc_montgomery_c diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/polyvec.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/polyvec.h new file mode 100644 index 0000000000..d21abc02ff --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/polyvec.h @@ -0,0 +1,725 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLYVEC_H +#define MLD_POLYVEC_H + +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "poly_kl.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_polyvecl MLD_ADD_PARAM_SET(mld_polyvecl) +#define mld_polyveck MLD_ADD_PARAM_SET(mld_polyveck) +#define mld_polymat MLD_ADD_PARAM_SET(mld_polymat) +/* End of parameter set namespacing */ + +/* Vectors of polynomials of length MLDSA_L */ +typedef struct +{ + mld_poly vec[MLDSA_L]; +} mld_polyvecl; + + +#define mld_polyvecl_uniform_gamma1 MLD_NAMESPACE_KL(polyvecl_uniform_gamma1) +/************************************************* + * Name: mld_polyvecl_uniform_gamma1 + * + * Description: Sample vector of polynomials with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_polyvecl *v: pointer to output vector + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + *************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + requires(nonce <= (UINT16_MAX - MLDSA_L) / MLDSA_L) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyvecl_ntt MLD_NAMESPACE_KL(polyvecl_ntt) +/************************************************* + * Name: mld_polyvecl_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_L. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyvecl *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k0, 0, MLDSA_L, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyvecl_pointwise_acc_montgomery \ + MLD_NAMESPACE_KL(polyvecl_pointwise_acc_montgomery) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery + * + * Description: Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * The first input "u" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * + * Arguments: - mld_poly *w: output polynomial + * - const mld_polyvecl *u: pointer to first input vector + * - const mld_polyvecl *v: pointer to second input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + + +#define mld_polyvecl_chknorm MLD_NAMESPACE_KL(polyvecl_chknorm) +/************************************************* + * Name: mld_polyvecl_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_L. + * Assumes input mld_polyvecl to be reduced by polyvecl_reduce(). + * + * Arguments: - const mld_polyvecl *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials is strictly smaller than B <= + * (MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +/* Vectors of polynomials of length MLDSA_K */ +typedef struct +{ + mld_poly vec[MLDSA_K]; +} mld_polyveck; + +/* Matrix of polynomials (K x L) */ +typedef struct +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + mld_polyvecl row_buffer; + uint8_t rho[MLDSA_SEEDBYTES]; +#else + mld_polyvecl vec[MLDSA_K]; +#endif +} mld_polymat; + +#define mld_polyveck_reduce MLD_NAMESPACE_KL(polyveck_reduce) +/************************************************* + * Name: polyveck_reduce + * + * Description: Reduce coefficients of polynomials in vector of length MLDSA_K + * to representatives in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) +); + +#define mld_polyveck_caddq MLD_NAMESPACE_KL(polyveck_caddq) +/************************************************* + * Name: mld_polyveck_caddq + * + * Description: For all coefficients of polynomials in vector of length MLDSA_K + * add MLDSA_Q if coefficient is negative. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_add MLD_NAMESPACE_KL(polyveck_add) +/************************************************* + * Name: mld_polyveck_add + * + * Description: Add vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to input-output vector of polynomials + * to be added to + * - const mld_polyveck *v: pointer to second input vector of + * polynomials + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(p0, 0, MLDSA_K, array_abs_bound(u->vec[p0].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) + requires(forall(p1, 0, MLDSA_K, + array_bound(v->vec[p1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(q2, 0, MLDSA_K, + array_bound(u->vec[q2].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_sub MLD_NAMESPACE_KL(polyveck_sub) +/************************************************* + * Name: mld_polyveck_sub + * + * Description: Subtract vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to first input vector + * - const mld_polyveck *v: pointer to second input vector to be + * subtracted from first input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(u->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_shiftl MLD_NAMESPACE_KL(polyveck_shiftl) +/************************************************* + * Name: mld_polyveck_shiftl + * + * Description: Multiply vector of polynomials of Length MLDSA_K by 2^MLDSA_D + *without modular reduction. Assumes input coefficients to be less than + *2^{31-MLDSA_D}. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_ntt MLD_NAMESPACE_KL(polyveck_ntt) +/************************************************* + * Name: mld_polyveck_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_K. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyveck_invntt_tomont MLD_NAMESPACE_KL(polyveck_invntt_tomont) +/************************************************* + * Name: mld_polyveck_invntt_tomont + * + * Description: Inverse NTT and multiplication by 2^{32} of polynomials + * in vector of length MLDSA_K. + * Input coefficients need to be less than MLDSA_Q, and + * Output coefficients are bounded by MLD_INTT_BOUND. + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) +); + +#define mld_polyveck_pointwise_poly_montgomery \ + MLD_NAMESPACE_KL(polyveck_pointwise_poly_montgomery) +/************************************************* + * Name: mld_polyveck_pointwise_poly_montgomery + * + * Description: Pointwise multiplication of a polynomial vector of length + * MLDSA_K by a single polynomial in NTT domain and multiplication + * of the resulting polynomial vector by 2^{-32}. + * + * Arguments: - mld_polyveck *r: pointer to output vector + * - mld_poly *a: pointer to input polynomial + * - mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(r, sizeof(mld_polyveck))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(r, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(r->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#define mld_polyveck_chknorm MLD_NAMESPACE_KL(polyveck_chknorm) +/************************************************* + * Name: mld_polyveck_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_K. + * Assumes input mld_polyveck to be reduced by polyveck_reduce(). + * + * Arguments: - const mld_polyveck *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials are strictly smaller than B <= + *(MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, + -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +#define mld_polyveck_power2round MLD_NAMESPACE_KL(polyveck_power2round) +/************************************************* + * Name: mld_polyveck_power2round + * + * Description: For all coefficients a of polynomials in vector of length + *MLDSA_K, compute a0, a1 such that a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with + *-2^{MLDSA_D-1} < a0 <= 2^{MLDSA_D-1}. Assumes coefficients to be standard + *representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to output vector of polynomials with + * coefficients a0 + * - const mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) +); + +#define mld_polyveck_decompose MLD_NAMESPACE_KL(polyveck_decompose) +/************************************************* + * Name: mld_polyveck_decompose + * + * Description: For all coefficients a of polynomials in vector of length + * MLDSA_K, compute high and low bits a0, a1 such a mod^+ MLDSA_Q = a1*ALPHA + * + a0 with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (MLDSA_Q-1)/ALPHA where we set + * a1 = 0 and -ALPHA/2 <= a0 = a mod MLDSA_Q - MLDSA_Q < 0. Assumes coefficients + * to be standard representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to input/output vector of + * polynomials with. Output polynomial has + * coefficients a0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v0->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + ensures(forall(k2, 0, MLDSA_K, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) +); + +#define mld_polyveck_make_hint MLD_NAMESPACE_KL(polyveck_make_hint) +/************************************************* + * Name: mld_polyveck_make_hint + * + * Description: Compute hint vector. + * + * Arguments: - mld_polyveck *h: pointer to output vector + * - const mld_polyveck *v0: pointer to low part of input vector + * - const mld_polyveck *v1: pointer to high part of input vector + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(return_value <= MLDSA_N * MLDSA_K) + ensures(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) +); + +#define mld_polyveck_use_hint MLD_NAMESPACE_KL(polyveck_use_hint) +/************************************************* + * Name: mld_polyveck_use_hint + * + * Description: Use hint vector to correct the high bits of input vector. + * + * Arguments: - mld_polyveck *w: pointer to output vector of polynomials with + * corrected high bits + * - const mld_polyveck *u: pointer to input vector + * - const mld_polyveck *h: pointer to input hint vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *v, + const mld_polyveck *h) +__contract__( + requires(memory_no_alias(w, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + assigns(memory_slice(w, sizeof(mld_polyveck))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) +); + +#define mld_polyveck_pack_w1 MLD_NAMESPACE_KL(polyveck_pack_w1) +/************************************************* + * Name: mld_polyveck_pack_w1 + * + * Description: Bit-pack polynomial vector w1 with coefficients in [0,15] or + * [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_K* MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_polyveck *a: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(w1, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(w1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) +); + +#define mld_polyveck_pack_eta MLD_NAMESPACE_KL(polyveck_pack_eta) +/************************************************* + * Name: mld_polyveck_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients + * in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyvecl_pack_eta MLD_NAMESPACE_KL(polyvecl_pack_eta) +/************************************************* + * Name: mld_polyvecl_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_L * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyveck_pack_t0 MLD_NAMESPACE_KL(polyveck_pack_t0) +/************************************************* + * Name: mld_polyveck_pack_t0 + * + * Description: Bit-pack polynomial vector to with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(p->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) +); + +#define mld_polyvecl_unpack_eta MLD_NAMESPACE_KL(polyvecl_unpack_eta) +/************************************************* + * Name: mld_polyvecl_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyvecl *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + assigns(memory_slice(p, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyvecl_unpack_z MLD_NAMESPACE_KL(polyvecl_unpack_z) +/************************************************* + * Name: mld_polyvecl_unpack_z + * + * Description: Unpack polynomial vector with coefficients in + * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_polyvecl *z: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(z->vec[k1].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyveck_unpack_eta MLD_NAMESPACE_KL(polyveck_unpack_eta) +/************************************************* + * Name: mld_polyveck_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyveck_unpack_t0 MLD_NAMESPACE_KL(polyveck_unpack_t0) +/************************************************* + * Name: mld_polyveck_unpack_t0 + * + * Description: Unpack polynomial vector with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) +); + +#define mld_polymat_get_row MLD_NAMESPACE_KL(polymat_get_row) +/************************************************* + * Name: mld_polymat_get_row + * + * Description: Retrieve a pointer to a specific row of the matrix. + * In MLD_CONFIG_REDUCE_RAM mode, generates the row on-demand. + * + * Arguments: - mld_polymat *mat: pointer to matrix + * - unsigned int row: row index (must be < MLDSA_K) + * + * Returns pointer to the row (mld_polyvecl) + **************************************************/ +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row); + +#define mld_polyvec_matrix_expand MLD_NAMESPACE_KL(polyvec_matrix_expand) +/************************************************* + * Name: mld_polyvec_matrix_expand + * + * Description: Implementation of ExpandA. Generates matrix A with uniformly + * random coefficients a_{i,j} by performing rejection + * sampling on the output stream of SHAKE128(rho|j|i) + * + * Arguments: - mld_polymat *mat: pointer to output matrix + * - const uint8_t rho[]: byte array containing seed rho + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +__contract__( + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +); + + + +#define mld_polyvec_matrix_pointwise_montgomery \ + MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery) +/************************************************* + * Name: mld_polyvec_matrix_pointwise_montgomery + * + * Description: Compute matrix-vector multiplication in NTT domain with + * pointwise multiplication and multiplication by 2^{-32}. + * Input matrix and vector must be in NTT domain representation. + * + * The first input "mat" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * Note: In MLD_CONFIG_REDUCE_RAM mode, mat cannot be const + * as rows are generated on-demand. + * + * Arguments: - mld_polyveck *t: pointer to output vector t + * - mld_polymat *mat: pointer to input matrix + * - const mld_polyvecl *v: pointer to input vector v + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(t, sizeof(mld_polyveck))) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(t, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#endif /* !MLD_POLYVEC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/randombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/randombytes.h new file mode 100644 index 0000000000..da55772419 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/randombytes.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_RANDOMBYTES_H +#define MLD_RANDOMBYTES_H + +#include +#include + +#include "cbmc.h" +#include "common.h" + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +#if !defined(MLD_CONFIG_CUSTOM_RANDOMBYTES) +MLD_MUST_CHECK_RETURN_VALUE +int randombytes(uint8_t *out, size_t outlen); +static MLD_INLINE int mld_randombytes(uint8_t *out, size_t outlen) +__contract__( + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) { return randombytes(out, outlen); } +#endif /* !MLD_CONFIG_CUSTOM_RANDOMBYTES */ +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ +#endif /* !MLD_RANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/reduce.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/reduce.h new file mode 100644 index 0000000000..413cf1829e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/reduce.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_REDUCE_H +#define MLD_REDUCE_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* check-magic: -4186625 == pow(2,32,MLDSA_Q) */ +#define MLD_MONT -4186625 + +/* Upper bound for domain of mld_reduce32() */ +#define MLD_REDUCE32_DOMAIN_MAX (INT32_MAX - (1 << 22)) + +/* Absolute bound for range of mld_reduce32() */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define MLD_REDUCE32_RANGE_MAX 6283009 + +/************************************************* + * Name: mld_montgomery_reduce + * + * Description: Generic Montgomery reduction; given a 64-bit integer a, computes + * 32-bit integer congruent to a * R^-1 mod q, where R=2^32 + * + * Arguments: - int64_t a: input integer to be reduced, of absolute value + * smaller or equal to INT64_MAX - 2^31 * MLDSA_Q. + * + * Returns: Integer congruent to a * R^-1 modulo q, with absolute value + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * In particular, if |a| < 2^31 * MLDSA_Q, the absolute value + * of the return value is < MLDSA_Q. + **************************************************/ +static MLD_INLINE int32_t mld_montgomery_reduce(int64_t a) +__contract__( + /* We don't attempt to express an input-dependent output bound + * as the post-condition here, as all call-sites satisfy the + * absolute input bound 2^31 * MLDSA_Q and higher-level + * reasoning can be conducted using |return_value| < MLDSA_Q. */ + requires(a > -(((int64_t)1 << 31) * MLDSA_Q) && + a < (((int64_t)1 << 31) * MLDSA_Q)) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* check-magic: 58728449 == unsigned_mod(pow(MLDSA_Q, -1, 2^32), 2^32) */ + const uint64_t QINV = 58728449; + + /* Compute a*q^{-1} mod 2^32 in unsigned representatives */ + const uint32_t a_reduced = mld_cast_int64_to_uint32(a); + const uint32_t a_inverted = (a_reduced * QINV) & UINT32_MAX; + + /* Lift to signed canonical representative mod 2^32. */ + const int32_t t = mld_cast_uint32_to_int32(a_inverted); + + int64_t r; + + mld_assert(a < +(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)) && + a > -(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q))); + + r = a - (int64_t)t * MLDSA_Q; + + /* + * PORTABILITY: Right-shift on a signed integer is, strictly-speaking, + * implementation-defined for negative left argument. Here, + * we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5)) + */ + r = r >> 32; + + /* Bounds: + * + * By construction of the Montgomery multiplication, by the time we + * compute r >> 32, r is divisible by 2^32, and hence + * + * |r >> 32| = |r| / 2^32 + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * (In general, we would only have |x >> n| <= ceil(|x| / 2^n)). + * + * In particular, if |a| < 2^31 * MLDSA_Q, then |return_value| < MLDSA_Q. + */ + return (int32_t)r; +} + +/************************************************* + * Name: mld_reduce32 + * + * Description: For finite field element a with a <= 2^{31} - 2^{22} - 1, + * compute r \equiv a (mod MLDSA_Q) such that + * -MLD_REDUCE32_RANGE_MAX <= r < MLD_REDUCE32_RANGE_MAX. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_reduce32(int32_t a) +__contract__( + requires(a <= MLD_REDUCE32_DOMAIN_MAX) + ensures(return_value >= -MLD_REDUCE32_RANGE_MAX) + ensures(return_value < MLD_REDUCE32_RANGE_MAX) +) +{ + int32_t t; + + t = (a + (1 << 22)) >> 23; + t = a - t * MLDSA_Q; + mld_assert((t - a) % MLDSA_Q == 0); + return t; +} + +/************************************************* + * Name: mld_caddq + * + * Description: Add MLDSA_Q if input coefficient is negative. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_caddq(int32_t a) +__contract__( + requires(a > -MLDSA_Q) + requires(a < MLDSA_Q) + ensures(return_value >= 0) + ensures(return_value < MLDSA_Q) + ensures(return_value == (a >= 0) ? a : (a + MLDSA_Q)) +) +{ + return mld_ct_sel_int32(a + MLDSA_Q, a, mld_ct_cmask_neg_i32(a)); +} + + +#endif /* !MLD_REDUCE_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/rounding.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/rounding.h new file mode 100644 index 0000000000..a83562b0f1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/rounding.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_ROUNDING_H +#define MLD_ROUNDING_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_power2round MLD_ADD_PARAM_SET(mld_power2round) +#define mld_decompose MLD_ADD_PARAM_SET(mld_decompose) +#define mld_make_hint MLD_ADD_PARAM_SET(mld_make_hint) +#define mld_use_hint MLD_ADD_PARAM_SET(mld_use_hint) +/* End of parameter set namespacing */ + +#define MLD_2_POW_D (1 << MLDSA_D) + +/************************************************* + * Name: mld_power2round + * + * Description: For finite field element a, compute a0, a1 such that + * a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with -2^{MLDSA_D-1} < a0 <= + * 2^{MLDSA_D-1}. Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: In the reference implementation, a1 is passed as a + * return value instead. + **************************************************/ +static MLD_INLINE void mld_power2round(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + ensures(*a0 > -(MLD_2_POW_D/2) && *a0 <= (MLD_2_POW_D/2)) + ensures(*a1 >= 0 && *a1 <= (MLDSA_Q - 1) / MLD_2_POW_D) + ensures((*a1 * MLD_2_POW_D + *a0 - a) % MLDSA_Q == 0) +) +{ + *a1 = (a + (1 << (MLDSA_D - 1)) - 1) >> MLDSA_D; + *a0 = a - (*a1 << MLDSA_D); +} + +/************************************************* + * Name: mld_decompose + * + * Description: For finite field element a, compute high and low bits a0, a1 + * such that a mod^+ MLDSA_Q = a1* 2 * MLDSA_GAMMA2 + a0 with + * -MLDSA_GAMMA2 < a0 <= MLDSA_GAMMA2 except + * if a1 = (MLDSA_Q-1)/(MLDSA_GAMMA2*2) where we set a1 = 0 and + * -MLDSA_GAMMA2 <= a0 = a mod^+ MLDSA_Q - MLDSA_Q < 0. + * Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: a1 is passed as a return value instead + **************************************************/ +static MLD_INLINE void mld_decompose(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + /* a0 = -MLDSA_GAMMA2 can only occur when (q-1) = a - (a mod MLDSA_GAMMA2), + * then a1=1; and a0 = a - (a mod MLDSA_GAMMA2) - 1 (@[FIPS204, Algorithm 36 (Decompose)]) */ + ensures(*a0 >= -MLDSA_GAMMA2 && *a0 <= MLDSA_GAMMA2) + ensures(*a1 >= 0 && *a1 < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) + ensures((*a1 * 2 * MLDSA_GAMMA2 + *a0 - a) % MLDSA_Q == 0) +) +{ + /* + * The goal is to compute f1 = round-(f / (2*GAMMA2)), which can be computed + * alternatively as round-(f / (128B)) = round-(ceil(f / 128) / B) where + * B = 2*GAMMA2 / 128. Here round-() denotes "round half down". + * + * The equality round-(f / (128B)) = round-(ceil(f / 128) / B) can deduced + * as follows. Since changing f to align-up(f, 128) can move f onto but not + * across a rounding boundary for division by 128*B (note that we need B to be + * even for this to work), and round- rounds down on the boundary, we have + * + * round-(f / (128B)) = round-(align-up(f, 128) / (128B)) + * = round-((align-up(f, 128) / 128) / B) + * = round-(ceil(f / 128) / B). + */ + *a1 = (a + 127) >> 7; + /* We know a >= 0 and a < MLDSA_Q, so... */ + /* check-magic: 65472 == round((MLDSA_Q-1)/128) */ + mld_assert(*a1 >= 0 && *a1 <= 65472); + +#if MLD_CONFIG_PARAMETER_SET == 44 + /* check-magic: 1488 == 2 * intdiv(intdiv(MLDSA_Q - 1, 88), 128) */ + /* check-magic: 11275 == floor(2**24 / 1488) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + */ + *a1 = (*a1 * 11275 + (1 << 23)) >> 24; + mld_assert(*a1 >= 0 && *a1 <= 44); + + *a1 = mld_ct_sel_int32(0, *a1, mld_ct_cmask_neg_i32(43 - *a1)); + mld_assert(*a1 >= 0 && *a1 <= 43); +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + /* check-magic: 4092 == 2 * intdiv(intdiv(MLDSA_Q - 1, 32), 128) */ + /* check-magic: 1025 == floor(2**22 / 4092) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + */ + *a1 = (*a1 * 1025 + (1 << 21)) >> 22; + mld_assert(*a1 >= 0 && *a1 <= 16); + + *a1 &= 15; + mld_assert(*a1 >= 0 && *a1 <= 15); + +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + + *a0 = a - *a1 * 2 * MLDSA_GAMMA2; + *a0 = mld_ct_sel_int32(*a0 - MLDSA_Q, *a0, + mld_ct_cmask_neg_i32((MLDSA_Q - 1) / 2 - *a0)); +} + +/************************************************* + * Name: mld_make_hint + * + * Description: Compute hint bit indicating whether the low bits of the + * input element overflow into the high bits. + * + * Arguments: - int32_t a0: low bits of input element + * - int32_t a1: high bits of input element + * + * Returns 1 if overflow, 0 otherwise + **************************************************/ +static MLD_INLINE unsigned int mld_make_hint(int32_t a0, int32_t a1) +__contract__( + ensures(return_value >= 0 && return_value <= 1) +) +{ + if (a0 > MLDSA_GAMMA2 || a0 < -MLDSA_GAMMA2 || + (a0 == -MLDSA_GAMMA2 && a1 != 0)) + { + return 1; + } + + return 0; +} + +/************************************************* + * Name: mld_use_hint + * + * Description: Correct high bits according to hint. + * + * Arguments: - int32_t a: input element + * - int32_t hint: hint bit + * + * Returns corrected high bits. + **************************************************/ +static MLD_INLINE int32_t mld_use_hint(int32_t a, int32_t hint) +__contract__( + requires(hint >= 0 && hint <= 1) + requires(a >= 0 && a < MLDSA_Q) + ensures(return_value >= 0 && return_value < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) +) +{ + int32_t a0, a1; + + mld_decompose(&a0, &a1, a); + if (hint == 0) + { + return a1; + } + +#if MLD_CONFIG_PARAMETER_SET == 44 + if (a0 > 0) + { + return (a1 == 43) ? 0 : a1 + 1; + } + else + { + return (a1 == 0) ? 43 : a1 - 1; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + if (a0 > 0) + { + return (a1 + 1) & 15; + } + else + { + return (a1 - 1) & 15; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + + +#endif /* !MLD_ROUNDING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/sign.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/sign.c new file mode 100644 index 0000000000..32bba52d65 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/sign.c @@ -0,0 +1,1508 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [Round3_Spec] + * CRYSTALS-Dilithium Algorithm Specifications and Supporting Documentation + * (Version 3.1) + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf + */ + +#include +#include + +#include "cbmc.h" +#include "ct.h" +#include "debug.h" +#include "packing.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" +#include "randombytes.h" +#include "sign.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_check_pct MLD_ADD_PARAM_SET(mld_check_pct) MLD_CONTEXT_PARAMETERS_2 +#define mld_sample_s1_s2 MLD_ADD_PARAM_SET(mld_sample_s1_s2) +#define mld_validate_hash_length MLD_ADD_PARAM_SET(mld_validate_hash_length) +#define mld_get_hash_oid MLD_ADD_PARAM_SET(mld_get_hash_oid) +#define mld_H MLD_ADD_PARAM_SET(mld_H) +#define mld_compute_pack_z MLD_ADD_PARAM_SET(mld_compute_pack_z) +#define mld_attempt_signature_generation \ + MLD_ADD_PARAM_SET(mld_attempt_signature_generation) MLD_CONTEXT_PARAMETERS_8 +#define mld_compute_t0_t1_tr_from_sk_components \ + MLD_ADD_PARAM_SET(mld_compute_t0_t1_tr_from_sk_components) \ + MLD_CONTEXT_PARAMETERS_7 +/* End of parameter set namespacing */ + + +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + ensures(return_value == 0 + || return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL) +); + +#if defined(MLD_CONFIG_KEYGEN_PCT) +/************************************************* + * @[FIPS140_3_IG] + * (https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf) + * + * TE10.35.02: Pair-wise Consistency Test (PCT) for DSA keypairs + * + * Purpose: Validates that a generated public/private key pair can correctly + * sign and verify data. Test performs signature generation using the private + * key (sk), followed by signature verification using the public key (pk). + * Returns 0 if the signature was successfully verified, non-zero if it cannot. + * + * Note: @[FIPS204] requires that public/private key pairs are to be used only + * for the calculation and/of verification of digital signatures. + **************************************************/ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t message[1] = {0}; + size_t siglen; + int ret; + MLD_ALLOC(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + MLD_ALLOC(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + + if (signature == NULL || pk_test == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Copy public key for testing */ + mld_memcpy(pk_test, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* Sign a test message using the original secret key */ + ret = mld_sign_signature(signature, &siglen, message, sizeof(message), NULL, + 0, sk, context); + if (ret != 0) + { + goto cleanup; + } + +#if defined(MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST) + /* Deliberately break public key for testing purposes */ + if (mld_break_pct()) + { + pk_test[0] = ~pk_test[0]; + } +#endif /* MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST */ + + /* Verify the signature using the (potentially corrupted) public key */ + ret = mld_sign_verify(signature, siglen, message, sizeof(message), NULL, 0, + pk_test, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + MLD_FREE(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + + return ret; +} +#else /* MLD_CONFIG_KEYGEN_PCT */ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + /* Skip PCT */ + ((void)pk); + ((void)sk); +#if defined(MLD_CONFIG_CONTEXT_PARAMETER) + ((void)context); +#endif + return 0; +} +#endif /* !MLD_CONFIG_KEYGEN_PCT */ + +static void mld_sample_s1_s2(mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t seed[MLDSA_CRHBYTES]) +__contract__( + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(object_whole(s1), object_whole(s2)) + ensures(forall(l0, 0, MLDSA_L, array_abs_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + ensures(forall(k0, 0, MLDSA_K, array_abs_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) +) +{ +/* Sample short vectors s1 and s2 */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; + uint16_t nonce = 0; + /* Safety: The nonces are at most 14 (MLDSA_L + MLDSA_K - 1), and, hence, the + * casts are safe. */ + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_eta(&s1->vec[i], seed, (uint8_t)(nonce + i)); + } + for (i = 0; i < MLDSA_K; i++) + { + mld_poly_uniform_eta(&s2->vec[i], seed, (uint8_t)(nonce + MLDSA_L + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLD_CONFIG_PARAMETER_SET == 44 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 4, 5, 6, 7); +#elif MLD_CONFIG_PARAMETER_SET == 65 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s2->vec[0], &s2->vec[1], + &s2->vec[2] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[2], &s2->vec[3], &s2->vec[4], &s2->vec[5], + seed, 7, 8, 9, 10); +#elif MLD_CONFIG_PARAMETER_SET == 87 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s1->vec[5], &s1->vec[6], + &s2->vec[0] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 7, 8, 9, 10); + mld_poly_uniform_eta_4x(&s2->vec[4], &s2->vec[5], &s2->vec[6], &s2->vec[7], + seed, 11, 12, 13, 14); +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ +} + +/************************************************* + * Name: mld_compute_t0_t1_tr_from_sk_components + * + * Description: Computes t0, t1, tr, and pk from secret key components + * rho, s1, s2. This is the shared computation used by + * both keygen and generating the public key from the + * secret key. + * + * Arguments: - mld_polyveck *t0: output t0 + * - mld_polyveck *t1: output t1 + * - uint8_t tr[MLDSA_TRBYTES]: output tr + * - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t rho[MLDSA_SEEDBYTES]: input rho + * - const mld_polyvecl *s1: input s1 + * - const mld_polyveck *s2: input s2 + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_t0_t1_tr_from_sk_components( + mld_polyveck *t0, mld_polyveck *t1, uint8_t tr[MLDSA_TRBYTES], + uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], const uint8_t rho[MLDSA_SEEDBYTES], + const mld_polyvecl *s1, const mld_polyveck *s2, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(l0, 0, MLDSA_L, array_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + requires(forall(k0, 0, MLDSA_K, array_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(forall(k1, 0, MLDSA_K, array_bound(t0->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(t1->vec[k2].coeffs, 0, MLDSA_N, 0, 1 << 10))) + ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY)) +{ + int ret; + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1hat, mld_polyvecl, 1, context); + MLD_ALLOC(t, mld_polyveck, 1, context); + + if (mat == NULL || s1hat == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Expand matrix */ + mld_polyvec_matrix_expand(mat, rho); + + /* Matrix-vector multiplication */ + *s1hat = *s1; + mld_polyvecl_ntt(s1hat); + mld_polyvec_matrix_pointwise_montgomery(t, mat, s1hat); + mld_polyveck_invntt_tomont(t); + + /* Add error vector s2 */ + mld_polyveck_add(t, s2); + + /* Reference: The following reduction is not present in the reference + * implementation. Omitting this reduction requires the output of + * the invntt to be small enough such that the addition of s2 does + * not result in absolute values >= MLDSA_Q. While our C, x86_64, + * and AArch64 invntt implementations produce small enough + * values for this to work out, it complicates the bounds + * reasoning. We instead add an additional reduction, and can + * consequently, relax the bounds requirements for the invntt. + */ + mld_polyveck_reduce(t); + + /* Decompose to get t1, t0 */ + mld_polyveck_caddq(t); + mld_polyveck_power2round(t1, t0, t); + + /* Pack public key and compute tr */ + mld_pack_pk(pk, rho, t1); + mld_shake256(tr, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + ret = 0; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_polyveck, 1, context); + MLD_FREE(s1hat, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + const uint8_t *rho, *rhoprime, *key; + MLD_ALLOC(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + MLD_ALLOC(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + + if (seedbuf == NULL || inbuf == NULL || tr == NULL || s1 == NULL || + s2 == NULL || t1 == NULL || t0 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Get randomness for rho, rhoprime and key */ + mld_memcpy(inbuf, seed, MLDSA_SEEDBYTES); + inbuf[MLDSA_SEEDBYTES + 0] = MLDSA_K; + inbuf[MLDSA_SEEDBYTES + 1] = MLDSA_L; + mld_shake256(seedbuf, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, inbuf, + MLDSA_SEEDBYTES + 2); + rho = seedbuf; + rhoprime = rho + MLDSA_SEEDBYTES; + key = rhoprime + MLDSA_CRHBYTES; + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + + /* Sample s1 and s2 */ + mld_sample_s1_s2(s1, s2, rhoprime); + + /* Compute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0, t1, tr, pk, rho, s1, s2, + context); + if (ret != 0) + { + goto cleanup; + } + + /* Pack secret key */ + mld_pack_sk(sk, rho, tr, key, t0, s1, s2); + + /* Constant time: pk is the public key, inherently public data */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_FREE(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + + if (ret != 0) + { + return ret; + } + + /* Pairwise Consistency Test (PCT) @[FIPS140_3_IG, p.87] */ + /* Do this after freeing all temporaries. */ + return mld_check_pct(pk, sk, context); +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t seed[MLDSA_SEEDBYTES]; + int ret; + if (mld_randombytes(seed, MLDSA_SEEDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(seed, sizeof(seed)); + ret = mld_sign_keypair_internal(pk, sk, seed, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed, sizeof(seed)); + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +/************************************************* + * Name: mld_H + * + * Description: Abstracts application of SHAKE256 to + * one, two or three blocks of data, + * yielding a user-requested size of + * output. + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in1: pointer to input block 1 + * Must NOT be NULL + * - size_t in1len: length of input in1 bytes + * - const uint8_t *in2: pointer to input block 2 + * May be NULL if in2len=0, in which case + * this block is ignored + * - size_t in2len: length of input in2 bytes + * - const uint8_t *in3: pointer to input block 3 + * May be NULL if in3len=0, in which case + * this block is ignored + * - size_t in3len: length of input in3 bytes + **************************************************/ +static void mld_H(uint8_t *out, size_t outlen, const uint8_t *in1, + size_t in1len, const uint8_t *in2, size_t in2len, + const uint8_t *in3, size_t in3len) +__contract__( + requires(in1len <= MLD_MAX_BUFFER_SIZE) + requires(in2len <= MLD_MAX_BUFFER_SIZE) + requires(in3len <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in1, in1len)) + requires(in2len == 0 || memory_no_alias(in2, in2len)) + requires(in3len == 0 || memory_no_alias(in3, in3len)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) +{ + mld_shake256ctx state; + mld_shake256_init(&state); + mld_shake256_absorb(&state, in1, in1len); + if (in2len != 0) + { + mld_shake256_absorb(&state, in2, in2len); + } + if (in3len != 0) + { + mld_shake256_absorb(&state, in3, in3len); + } + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(&state, sizeof(state)); +} + +/************************************************* + * Name: mld_compute_pack_z + * + * Description: Computes z = y + s1*c, checks that z has coefficients smaller + * than MLDSA_GAMMA1 - MLDSA_BETA, and packs z into the + * signature buffer. + * + * Arguments: - uint8_t *sig: output signature + * - const mld_poly *cp: challenge polynomial + * - const polyvecl *s1: secret vector s1 + * - const polyvecl *y: masking vector y + * + * Returns: - 0: Success (z has coefficients smaller than + * MLDSA_GAMMA1 - MLDSA_BETA,) + * - MLD_ERR_FAIL: z rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This function is inlined into mld_sign_signature in the + * reference implementation. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_pack_z(uint8_t sig[MLDSA_CRYPTO_BYTES], + const mld_poly *cp, const mld_polyvecl *s1, + const mld_polyvecl *y, mld_poly *z) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(cp, sizeof(mld_poly))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(y, sizeof(mld_polyvecl))) + requires(memory_no_alias(z, sizeof(mld_poly))) + requires(array_abs_bound(cp->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_L, + array_bound(y->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + requires(forall(k1, 0, MLDSA_L, array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(memory_slice(z, sizeof(mld_poly))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int i; + uint32_t z_invalid; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(z, sizeof(mld_poly)), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_poly_pointwise_montgomery(z, cp, &s1->vec[i]); + mld_poly_invntt_tomont(z); + mld_poly_add(z, &y->vec[i]); + mld_poly_reduce(z); + + z_invalid = mld_poly_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA); + /* Constant time: It is fine (and prohibitively expensive to avoid) + * to leak the result of the norm check and which polynomial in z caused a + * rejection. It would even be okay to leak which coefficient led to + * rejection as the candidate signature will be discarded anyway. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(&z_invalid, sizeof(uint32_t)); + if (z_invalid) + { + return MLD_ERR_FAIL; /* reject */ + } + /* If z is valid, then its coefficients are bounded by + * MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below + * to prove the pre-condition of pack_sig_z() */ + mld_assert_abs_bound(z, MLDSA_N, (MLDSA_GAMMA1 - MLDSA_BETA)); + + /* After the norm check, the distribution of each coefficient of z is + * independent of the secret key and it can, hence, be considered + * public. It is, hence, okay to immediately pack it into the user-provided + * signature buffer. */ + mld_pack_sig_z(sig, z, i); + } + return 0; +} + +/* Reference: The reference implementation does not explicitly check the + * maximum nonce value, but instead loops indefinitely (even when the nonce + * would overflow). Internally, sampling of y uses + * (nonceL), (nonceL+1), ... (nonce*L+L-1). + * Hence, there are no overflows if nonce < (UINT16_MAX - L)/L. + * Explicitly checking for this explicitly allows us to prove type-safety. + * Note that FIPS204 explicitly allows an upper-bound this loop of + * 814 (< (UINT16_MAX - L)/L) - see @[FIPS204, Appendix C]. */ +#define MLD_NONCE_UB ((UINT16_MAX - MLDSA_L) / MLDSA_L) + +/************************************************* + * Name: attempt_signature_generation + * + * Description: Attempts to generate a single signature. + * + * Arguments: - uint8_t *sig: pointer to output signature + * - const uint8_t *mu: pointer to message or hash + * of exactly MLDSA_CRHBYTES bytes + * - const uint8_t *rhoprime: pointer to randomness seed + * - uint16_t nonce: current nonce value + * - const mld_polymat *mat: expanded matrix + * - const polyvecl *s1: secret vector s1 + * - const polyveck *s2: secret vector s2 + * - const polyveck *t0: vector t0 + * + * Returns: - 0: Signature generation succeeded + * - MLD_ERR_FAIL: Signature rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This code differs from the reference implementation + * in that it factors out the core signature generation + * step into a distinct function here in order to improve + * efficiency of CBMC proof. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_attempt_signature_generation( + uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *mu, + const uint8_t rhoprime[MLDSA_CRHBYTES], uint16_t nonce, mld_polymat *mat, + const mld_polyvecl *s1, const mld_polyveck *s2, const mld_polyveck *t0, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(rhoprime, MLDSA_CRHBYTES)) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(nonce <= MLD_NONCE_UB) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int n; + uint32_t w0_invalid, h_invalid; + int ret; + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyvecl y; + mld_polyveck h; + } + yh_u; + mld_polyvecl *y; + mld_polyveck *h; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck w1; + mld_polyvecl tmp; + } + w1tmp_u; + mld_polyveck *w1; + mld_polyvecl *tmp; + + MLD_ALLOC(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(yh, yh_u, 1, context); + MLD_ALLOC(z, mld_poly, 1, context); + MLD_ALLOC(w1tmp, w1tmp_u, 1, context); + MLD_ALLOC(w0, mld_polyveck, 1, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(t, mld_poly, 1, context); + + if (challenge_bytes == NULL || yh == NULL || z == NULL || w1tmp == NULL || + w0 == NULL || cp == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + y = &yh->y; + h = &yh->h; + w1 = &w1tmp->w1; + tmp = &w1tmp->tmp; + + /* Sample intermediate vector y */ + mld_polyvecl_uniform_gamma1(y, rhoprime, nonce); + + /* Matrix-vector multiplication */ + *tmp = *y; + mld_polyvecl_ntt(tmp); + mld_polyvec_matrix_pointwise_montgomery(w0, mat, tmp); + mld_polyveck_invntt_tomont(w0); + + /* Decompose w and call the random oracle */ + mld_polyveck_caddq(w0); + mld_polyveck_decompose(w1, w0); + mld_polyveck_pack_w1(sig, w1); + + mld_H(challenge_bytes, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, sig, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + /* Constant time: Leaking challenge_bytes does not reveal any information + * about the secret key as H() is modelled as random oracle. + * This also applies to challenges for rejected signatures. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(challenge_bytes, MLDSA_CTILDEBYTES); + mld_poly_challenge(cp, challenge_bytes); + mld_poly_ntt(cp); + + /* Compute z, reject if it reveals secret */ + ret = mld_compute_pack_z(sig, cp, s1, y, t); + if (ret) + { + goto cleanup; + } + + /* Check that subtracting cs2 does not change high bits of w and low bits + * do not reveal secret information */ + mld_polyveck_pointwise_poly_montgomery(h, cp, s2); + mld_polyveck_invntt_tomont(h); + mld_polyveck_sub(w0, h); + mld_polyveck_reduce(w0); + + w0_invalid = mld_polyveck_chknorm(w0, MLDSA_GAMMA2 - MLDSA_BETA); + /* Constant time: w0_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&w0_invalid, sizeof(uint32_t)); + if (w0_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* Compute hints for w1 */ + mld_polyveck_pointwise_poly_montgomery(h, cp, t0); + mld_polyveck_invntt_tomont(h); + mld_polyveck_reduce(h); + + h_invalid = mld_polyveck_chknorm(h, MLDSA_GAMMA2); + /* Constant time: h_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&h_invalid, sizeof(uint32_t)); + if (h_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + mld_polyveck_add(w0, h); + + /* Constant time: At this point all norm checks have passed and we, hence, + * know that the signature does not leak any secret information. + * Consequently, any value that can be computed from the signature and public + * key is considered public. + * w0 and w1 are public as they can be computed from Az - ct = \alpha w1 + w0. + * h=c*t0 is public as both c and t0 are public. + * For a more detailed discussion, refer to https://eprint.iacr.org/2022/1406. + */ + MLD_CT_TESTING_DECLASSIFY(w0, sizeof(*w0)); + MLD_CT_TESTING_DECLASSIFY(w1, sizeof(*w1)); + n = mld_polyveck_make_hint(h, w0, w1); + if (n > MLDSA_OMEGA) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* All is well - write signature */ + mld_pack_sig_c_h(sig, challenge_bytes, h, n); + /* Constant time: At this point it is clear that the signature is valid - it + * can, hence, be considered public. */ + MLD_CT_TESTING_DECLASSIFY(sig, MLDSA_CRYPTO_BYTES); + ret = 0; /* success */ + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_poly, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(w0, mld_polyveck, 1, context); + MLD_FREE(w1tmp, w1tmp_u, 1, context); + MLD_FREE(z, mld_poly, 1, context); + MLD_FREE(yh, yh_u, 1, context); + MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + + return ret; +} +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + uint8_t *rho, *tr, *key, *mu, *rhoprime; + uint16_t nonce = 0; + MLD_ALLOC(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + + if (seedbuf == NULL || mat == NULL || s1 == NULL || t0 == NULL || s2 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + rho = seedbuf; + tr = rho + MLDSA_SEEDBYTES; + key = tr + MLDSA_TRBYTES; + mu = key + MLDSA_SEEDBYTES; + rhoprime = mu + MLDSA_CRHBYTES; + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + if (!externalmu) + { + /* Compute mu = CRH(tr, pre, msg) */ + mld_H(mu, MLDSA_CRHBYTES, tr, MLDSA_TRBYTES, pre, prelen, m, mlen); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Compute rhoprime = CRH(key, rnd, mu) */ + mld_H(rhoprime, MLDSA_CRHBYTES, key, MLDSA_SEEDBYTES, rnd, MLDSA_RNDBYTES, mu, + MLDSA_CRHBYTES); + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + /* Expand matrix and transform vectors */ + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(s1); + mld_polyveck_ntt(s2); + mld_polyveck_ntt(t0); + + /* By default, return failure. Flip to success and write output + * once signature generation succeeds. */ + ret = MLD_ERR_FAIL; + + /* Reference: This code is re-structured using a while(1), */ + /* with explicit "continue" statements (rather than "goto") */ + /* to implement rejection of invalid signatures. */ + while (1) + __loop__( + assigns(nonce, ret, object_whole(siglen), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(nonce <= MLD_NONCE_UB) + + /* t0, s1, s2, and mat are initialized above and are NOT changed by this */ + /* loop. We can therefore re-assert their bounds here as part of the */ + /* loop invariant. This makes proof noticeably faster with CBMC */ + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + invariant(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(ret == MLD_ERR_FAIL) + ) + { + /* Reference: this code explicitly checks for exhaustion of nonce */ + /* values to provide predictable termination and results in that case */ + /* Checking here also means that incrementing nonce below can also */ + /* be proven to be type-safe. */ + if (nonce == MLD_NONCE_UB) + { + /* Note that ret == MLD_ERR_FAIL by default, so we + * don't need to set it here. */ + break; + } + + ret = mld_attempt_signature_generation(sig, mu, rhoprime, nonce, mat, s1, + s2, t0, context); + nonce++; + if (ret == 0) + { + *siglen = MLDSA_CRYPTO_BYTES; + break; + } + else if (ret != MLD_ERR_FAIL) + { + /* For failures such as out-of-memory, propagate and exit immediately. */ + break; + } + + /* Otherwise, try again. */ + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the signature buffer. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + return ret; +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + size_t pre_len; + int ret; + MLD_ALLOC(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + MLD_ALLOC(rnd, uint8_t, MLDSA_RNDBYTES, context); + + if (pre == NULL || rnd == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Prepare domain separation prefix for pure ML-DSA */ + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, m, mlen, pre, pre_len, rnd, sk, + 0, context); + +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(rnd, uint8_t, MLDSA_RNDBYTES, context); + MLD_FREE(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t rnd[MLDSA_RNDBYTES]; + int ret; + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + *siglen = 0; + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, + rnd, sk, 1, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(rnd, sizeof(rnd)); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + for (i = 0; i < mlen; ++i) + __loop__( + assigns(i, object_whole(sm)) + invariant(i <= mlen) + ) + { + sm[MLDSA_CRYPTO_BYTES + mlen - 1 - i] = m[mlen - 1 - i]; + } + ret = mld_sign_signature(sm, smlen, sm + MLDSA_CRYPTO_BYTES, mlen, ctx, + ctxlen, sk, context); + *smlen += mlen; + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret, cmp; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck t1; + mld_polyveck w1; + } + t1w1_u; + mld_polyveck *t1; + mld_polyveck *w1; + + MLD_ALLOC(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_ALLOC(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(z, mld_polyvecl, 1, context); + MLD_ALLOC(t1w1, t1w1_u, 1, context); + MLD_ALLOC(tmp, mld_polyveck, 1, context); + MLD_ALLOC(h, mld_polyveck, 1, context); + + if (buf == NULL || rho == NULL || mu == NULL || c == NULL || c2 == NULL || + cp == NULL || mat == NULL || z == NULL || t1w1 == NULL || tmp == NULL || + h == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + t1 = &t1w1->t1; + w1 = &t1w1->w1; + + if (siglen != MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + mld_unpack_pk(rho, t1, pk); + + /* mld_unpack_sig and mld_polyvecl_chknorm signal failure through a + * single non-zero error code that's not yet aligned with MLD_ERR_XXX. + * Map it to MLD_ERR_FAIL explicitly. */ + if (mld_unpack_sig(c, z, h, sig)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + if (mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + if (!externalmu) + { + /* Compute CRH(H(rho, t1), pre, msg) */ + MLD_ALIGN uint8_t hpk[MLDSA_CRHBYTES]; + mld_H(hpk, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES, NULL, 0, NULL, + 0); + mld_H(mu, MLDSA_CRHBYTES, hpk, MLDSA_TRBYTES, pre, prelen, m, mlen); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(hpk, sizeof(hpk)); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Matrix-vector multiplication; compute Az - c2^dt1 */ + mld_poly_challenge(cp, c); + mld_poly_ntt(cp); + mld_polyveck_shiftl(t1); + mld_polyveck_ntt(t1); + mld_polyveck_pointwise_poly_montgomery(tmp, cp, t1); + + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(z); + mld_polyvec_matrix_pointwise_montgomery(w1, mat, z); + mld_polyveck_sub(w1, tmp); + mld_polyveck_reduce(w1); + mld_polyveck_invntt_tomont(w1); + + /* Reconstruct w1 */ + mld_polyveck_caddq(w1); + mld_polyveck_use_hint(tmp, w1, h); + mld_polyveck_pack_w1(buf, tmp); + /* Call random oracle and verify challenge */ + mld_H(c2, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, buf, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + + cmp = mld_ct_memcmp(c, c2, MLDSA_CTILDEBYTES); + + /* Declassify the result of the verification. */ + MLD_CT_TESTING_DECLASSIFY(&cmp, sizeof(cmp)); + + ret = cmp == 0 ? 0 : MLD_ERR_FAIL; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(h, mld_polyveck, 1, context); + MLD_FREE(tmp, mld_polyveck, 1, context); + MLD_FREE(t1w1, t1w1_u, 1, context); + MLD_FREE(z, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, m, mlen, pre, pre_len, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + return mld_sign_verify_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, pk, + 1, context); +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + if (smlen < MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + *mlen = smlen - MLDSA_CRYPTO_BYTES; + ret = mld_sign_verify(sm, MLDSA_CRYPTO_BYTES, sm + MLDSA_CRYPTO_BYTES, *mlen, + ctx, ctxlen, pk, context); + if (ret == 0) + { + /* All good, copy msg, return 0 */ + for (i = 0; i < *mlen; ++i) + __loop__( + assigns(i, memory_slice(m, *mlen)) + invariant(i <= *mlen) + ) + { + m[i] = sm[MLDSA_CRYPTO_BYTES + i]; + } + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the message buffer. */ + *mlen = 0; + mld_memset(m, 0, smlen); + } + + return ret; +} + + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_signature_internal(sig, siglen, pre, pre_len, NULL, 0, rnd, sk, + 0, context); +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, pre, pre_len, NULL, 0, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_signature_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, rnd, sk, + MLD_PREHASH_SHAKE_256, context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_verify_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, pk, MLD_PREHASH_SHAKE_256, + context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + + +#define MLD_PRE_HASH_OID_LEN 11 + +/************************************************* + * Name: mld_get_hash_oid + * + * Description: Returns the OID of a given SHA-2/SHA-3 hash function. + * + * Arguments: - uint8_t oid[11]: pointer to output oid + * - int hashalg: hash algorithm constant (MLD_PREHASH_*) + * + ***************************************************/ +static void mld_get_hash_oid(uint8_t oid[MLD_PRE_HASH_OID_LEN], int hashalg) +{ + unsigned int i; + static const struct + { + int alg; + uint8_t oid[MLD_PRE_HASH_OID_LEN]; + } oid_map[] = { + {MLD_PREHASH_SHA2_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}}, + {MLD_PREHASH_SHA2_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}}, + {MLD_PREHASH_SHA2_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}}, + {MLD_PREHASH_SHA2_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}}, + {MLD_PREHASH_SHA2_512_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05}}, + {MLD_PREHASH_SHA2_512_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06}}, + {MLD_PREHASH_SHA3_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07}}, + {MLD_PREHASH_SHA3_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08}}, + {MLD_PREHASH_SHA3_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09}}, + {MLD_PREHASH_SHA3_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A}}, + {MLD_PREHASH_SHAKE_128, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B}}, + {MLD_PREHASH_SHAKE_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C}}}; + + for (i = 0; i < sizeof(oid_map) / sizeof(oid_map[0]); i++) + __loop__( + invariant(i <= sizeof(oid_map) / sizeof(oid_map[0])) + ) + { + if (oid_map[i].alg == hashalg) + { + mld_memcpy(oid, oid_map[i].oid, MLD_PRE_HASH_OID_LEN); + return; + } + } +} + +static int mld_validate_hash_length(int hashalg, size_t len) +{ + switch (hashalg) + { + case MLD_PREHASH_SHA2_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_128: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_256: + return (len == 512 / 8) ? 0 : -1; + } + return -1; +} + +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +{ + if (ctxlen > 255) + { + return 0; + } + + if (hashalg != MLD_PREHASH_NONE) + { + if (ph == NULL || mld_validate_hash_length(hashalg, phlen) != 0) + { + return 0; + } + } + + /* Common prefix: 0x00/0x01 || ctxlen || ctx */ + prefix[0] = (hashalg == MLD_PREHASH_NONE) ? 0 : 1; + prefix[1] = (uint8_t)ctxlen; + if (ctxlen > 0) + { + mld_memcpy(prefix + 2, ctx, ctxlen); + } + + if (hashalg == MLD_PREHASH_NONE) + { + return 2 + ctxlen; + } + + /* HashML-DSA: append oid || ph */ + mld_get_hash_oid(prefix + 2 + ctxlen, hashalg); + mld_memcpy(prefix + 2 + ctxlen + MLD_PRE_HASH_OID_LEN, ph, phlen); + return 2 + ctxlen + MLD_PRE_HASH_OID_LEN + phlen; +} + +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + uint8_t check, cmp0, cmp1, chk1, chk2; + int ret; + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(t0_computed, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + + if (rho == NULL || tr == NULL || tr_computed == NULL || key == NULL || + s1 == NULL || s2 == NULL || t0 == NULL || t0_computed == NULL || + t1 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Unpack secret key */ + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + /* Validate s1 and s2 coefficients are within [-MLDSA_ETA, MLDSA_ETA] */ + chk1 = mld_polyvecl_chknorm(s1, MLDSA_ETA + 1) & 0xFF; + chk2 = mld_polyveck_chknorm(s2, MLDSA_ETA + 1) & 0xFF; + + /* Recompute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0_computed, t1, tr_computed, + pk, rho, s1, s2, context); + if (ret != 0) + { + goto cleanup; + } + + /* Validate t0 and tr using constant-time comparisons */ + cmp0 = mld_ct_memcmp((const uint8_t *)t0, (const uint8_t *)t0_computed, + sizeof(mld_polyveck)); + cmp1 = mld_ct_memcmp((const uint8_t *)tr, (const uint8_t *)tr_computed, + MLDSA_TRBYTES); + check = mld_value_barrier_u8(cmp0 | cmp1 | chk1 | chk2); + + /* Declassify the final result of the validity check. */ + MLD_CT_TESTING_DECLASSIFY(&check, sizeof(check)); + ret = (check != 0) ? MLD_ERR_FAIL : 0; + +cleanup: + + if (ret != 0) + { + mld_zeroize(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + } + + /* Constant time: pk is either the valid public key or zeroed on error */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(t0_computed, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + + return ret; +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_check_pct +#undef mld_sample_s1_s2 +#undef mld_validate_hash_length +#undef mld_get_hash_oid +#undef mld_H +#undef mld_compute_pack_z +#undef mld_attempt_signature_generation +#undef mld_compute_t0_t1_tr_from_sk_components +#undef MLD_NONCE_UB +#undef MLD_PRE_HASH_OID_LEN diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/sign.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/sign.h new file mode 100644 index 0000000000..2e0bac32ea --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/sign.h @@ -0,0 +1,807 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_SIGN_H +#define MLD_SIGN_H + +#include +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "polyvec.h" +#include "sys.h" + +#if defined(MLD_CHECK_APIS) +/* Include to ensure consistency between internal sign.h + * and external mldsa_native.h. */ +#include "mldsa_native.h" + +#if MLDSA_CRYPTO_SECRETKEYBYTES != \ + MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for SECRETKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_PUBLICKEYBYTES != \ + MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for PUBLICKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_BYTES != MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for CRYPTO_BYTES between sign.h and mldsa_native.h +#endif + +#endif /* MLD_CHECK_APIS */ + +#define mld_sign_keypair_internal \ + MLD_NAMESPACE_KL(keypair_internal) MLD_CONTEXT_PARAMETERS_3 +#define mld_sign_keypair MLD_NAMESPACE_KL(keypair) MLD_CONTEXT_PARAMETERS_2 +#define mld_sign_signature_internal \ + MLD_NAMESPACE_KL(signature_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_signature MLD_NAMESPACE_KL(signature) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_extmu \ + MLD_NAMESPACE_KL(signature_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign MLD_NAMESPACE_KL(sign) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_internal \ + MLD_NAMESPACE_KL(verify_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify MLD_NAMESPACE_KL(verify) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_extmu \ + MLD_NAMESPACE_KL(verify_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign_open MLD_NAMESPACE_KL(open) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_pre_hash_internal \ + MLD_NAMESPACE_KL(signature_pre_hash_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_verify_pre_hash_internal \ + MLD_NAMESPACE_KL(verify_pre_hash_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_signature_pre_hash_shake256 \ + MLD_NAMESPACE_KL(signature_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify_pre_hash_shake256 \ + MLD_NAMESPACE_KL(verify_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_7 +#define mld_prepare_domain_separation_prefix \ + MLD_NAMESPACE_KL(prepare_domain_separation_prefix) +#define mld_sign_pk_from_sk \ + MLD_NAMESPACE_KL(pk_from_sk) MLD_CONTEXT_PARAMETERS_2 + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: mld_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: input random seed + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int externalmu: indicates input message m is + * processed as mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return MLD_ERR_FAIL in that case. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires((externalmu == 0 && (prelen == 0 || memory_no_alias(pre, prelen))) || + (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) + ensures(return_value == 0 ==> *siglen == MLDSA_CRYPTO_BYTES) + ensures(return_value != 0 ==> *siglen == 0) +); + +/************************************************* + * Name: mld_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_signature_extmu + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign + * + * Description: Compute signed message. + * + * Arguments: - uint8_t *sm: pointer to output signed message + * (allocated array with MLDSA_CRYPTO_BYTES + + *mlen bytes), can be equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sm, MLDSA_CRYPTO_BYTES + mlen)) + requires(memory_no_alias(smlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sm, MLDSA_CRYPTO_BYTES + mlen)) + assigns(object_whole(smlen)) + ensures((return_value == 0 && *smlen == MLDSA_CRYPTO_BYTES + mlen) || + (return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL)) +); + +/************************************************* + * Name: mld_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as + * mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(externalmu == 0 || (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + requires(externalmu == 1 || prelen == 0 || memory_no_alias(pre, prelen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_open + * + * Description: Verify signed message. + * + * Arguments: - uint8_t *m: pointer to output message (allocated array + * with smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context tring + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(smlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(m, smlen)) + requires(memory_no_alias(mlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(sm, smlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + assigns(memory_slice(m, smlen)) + assigns(memory_slice(mlen, sizeof(size_t))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and + * verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/* Maximum formatted domain separation message length: + * - Pure ML-DSA: 0x00 || ctxlen || ctx (max 255) + * - HashML-DSA: 0x01 || ctxlen || ctx (max 255) || oid (11) || ph (max 64) */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +__contract__( + requires(ctxlen <= 255) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(hashalg == MLD_PREHASH_NONE || memory_no_alias(ph, phlen)) + requires(memory_no_alias(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + assigns(memory_slice(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + ensures(return_value <= MLD_DOMAIN_SEPARATION_MAX_BYTES) +); + +/************************************************* + * Name: mld_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: input secret + * key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); +#endif /* !MLD_SIGN_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/symmetric.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/symmetric.h new file mode 100644 index 0000000000..bb70f05552 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/symmetric.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_SYMMETRIC_H +#define MLD_SYMMETRIC_H + +#include +#include "cbmc.h" +#include "common.h" + +#include MLD_FIPS202_HEADER_FILE +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#include MLD_FIPS202X4_HEADER_FILE +#endif + +#define MLD_STREAM128_BLOCKBYTES SHAKE128_RATE +#define MLD_STREAM256_BLOCKBYTES SHAKE256_RATE + +#define mld_xof256_ctx mld_shake256ctx +#define mld_xof256_init(CTX) mld_shake256_init(CTX) + +#define mld_xof256_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake256_absorb(CTX, IN, INBYTES); \ + mld_shake256_finalize(CTX); \ + } while (0) + + +#define mld_xof256_release(CTX) mld_shake256_release(CTX) +#define mld_xof256_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake256_squeeze(OUT, (OUTBLOCKS) * SHAKE256_RATE, STATE) + +#define mld_xof128_ctx mld_shake128ctx +#define mld_xof128_init(CTX) mld_shake128_init(CTX) + +#define mld_xof128_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake128_absorb(CTX, IN, INBYTES); \ + mld_shake128_finalize(CTX); \ + } while (0) + +#define mld_xof128_release(CTX) mld_shake128_release(CTX) +#define mld_xof128_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake128_squeeze(OUT, (OUTBLOCKS) * SHAKE128_RATE, STATE) + +#define mld_xof256_x4_ctx mld_shake256x4ctx +#define mld_xof256_x4_init(CTX) mld_shake256x4_init((CTX)) +#define mld_xof256_x4_absorb(CTX, IN, INBYTES) \ + mld_shake256x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof256_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake256x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof256_x4_release(CTX) mld_shake256x4_release((CTX)) + +#define mld_xof128_x4_ctx mld_shake128x4ctx +#define mld_xof128_x4_init(CTX) mld_shake128x4_init((CTX)) +#define mld_xof128_x4_absorb(CTX, IN, INBYTES) \ + mld_shake128x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof128_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake128x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof128_x4_release(CTX) mld_shake128x4_release((CTX)) + +#endif /* !MLD_SYMMETRIC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/sys.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/sys.h new file mode 100644 index 0000000000..1226526420 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/sys.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_SYS_H +#define MLD_SYS_H + +#if !defined(MLD_CONFIG_NO_ASM) && (defined(__GNUC__) || defined(__clang__)) +#define MLD_HAVE_INLINE_ASM +#endif + +/* Try to find endianness, if not forced through CFLAGS already */ +#if !defined(MLD_SYS_LITTLE_ENDIAN) && !defined(MLD_SYS_BIG_ENDIAN) +#if defined(__BYTE_ORDER__) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define MLD_SYS_LITTLE_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define MLD_SYS_BIG_ENDIAN +#else +#error "__BYTE_ORDER__ defined, but don't recognize value." +#endif +#endif /* __BYTE_ORDER__ */ + +/* MSVC does not define __BYTE_ORDER__. However, MSVC only supports + * little endian x86, x86_64, and AArch64. It is, hence, safe to assume + * little endian. */ +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_IX86) || defined(_M_ARM64)) +#define MLD_SYS_LITTLE_ENDIAN +#endif + +#endif /* !MLD_SYS_LITTLE_ENDIAN && !MLD_SYS_BIG_ENDIAN */ + +/* Check if we're running on an AArch64 little endian system. _M_ARM64 is set by + * MSVC. */ +#if defined(__AARCH64EL__) || defined(_M_ARM64) +#define MLD_SYS_AARCH64 +#endif + +/* Check if we're running on an AArch64 big endian system. */ +#if defined(__AARCH64EB__) +#define MLD_SYS_AARCH64_EB +#endif + +#if defined(__x86_64__) +#define MLD_SYS_X86_64 +#if defined(__AVX2__) +#define MLD_SYS_X86_64_AVX2 +#endif +#endif /* __x86_64__ */ + +#if defined(MLD_SYS_LITTLE_ENDIAN) && defined(__powerpc64__) +#define MLD_SYS_PPC64LE +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 +#define MLD_SYS_RISCV64 +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32 +#define MLD_SYS_RISCV32 +#endif + +#if defined(_WIN64) || defined(_WIN32) +#define MLD_SYS_WINDOWS +#endif + +#if defined(__linux__) +#define MLD_SYS_LINUX +#endif + +#if defined(__APPLE__) +#define MLD_SYS_APPLE +#endif + +/* If MLD_FORCE_AARCH64 is set, assert that we're indeed on an AArch64 system. + */ +#if defined(MLD_FORCE_AARCH64) && !defined(MLD_SYS_AARCH64) +#error "MLD_FORCE_AARCH64 is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_AARCH64_EB is set, assert that we're indeed on a big endian + * AArch64 system. */ +#if defined(MLD_FORCE_AARCH64_EB) && !defined(MLD_SYS_AARCH64_EB) +#error \ + "MLD_FORCE_AARCH64_EB is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_X86_64 is set, assert that we're indeed on an X86_64 system. */ +#if defined(MLD_FORCE_X86_64) && !defined(MLD_SYS_X86_64) +#error "MLD_FORCE_X86_64 is set, but we don't seem to be on an X86_64 system." +#endif + +#if defined(MLD_FORCE_PPC64LE) && !defined(MLD_SYS_PPC64LE) +#error "MLD_FORCE_PPC64LE is set, but we don't seem to be on a PPC64LE system." +#endif + +#if defined(MLD_FORCE_RISCV64) && !defined(MLD_SYS_RISCV64) +#error "MLD_FORCE_RISCV64 is set, but we don't seem to be on a RISCV64 system." +#endif + +#if defined(MLD_FORCE_RISCV32) && !defined(MLD_SYS_RISCV32) +#error "MLD_FORCE_RISCV32 is set, but we don't seem to be on a RISCV32 system." +#endif + +/* + * MLD_INLINE: Hint for inlining. + * - MSVC: __inline + * - C99+: inline + * - GCC/Clang C90: __attribute__((unused)) to silence warnings + * - Other C90: empty + */ +#if !defined(MLD_INLINE) +#if defined(_MSC_VER) +#define MLD_INLINE __inline +#elif defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +#define MLD_INLINE inline +#elif defined(__GNUC__) || defined(__clang__) +#define MLD_INLINE __attribute__((unused)) +#else +#define MLD_INLINE +#endif +#endif /* !MLD_INLINE */ + +/* + * MLD_ALWAYS_INLINE: Force inlining. + * - MSVC: __forceinline + * - GCC/Clang C99+: MLD_INLINE __attribute__((always_inline)) + * - Other: MLD_INLINE (no forced inlining) + */ +#if !defined(MLD_ALWAYS_INLINE) +#if defined(_MSC_VER) +#define MLD_ALWAYS_INLINE __forceinline +#elif (defined(__GNUC__) || defined(__clang__)) && \ + (defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)) +#define MLD_ALWAYS_INLINE MLD_INLINE __attribute__((always_inline)) +#else +#define MLD_ALWAYS_INLINE MLD_INLINE +#endif +#endif /* !MLD_ALWAYS_INLINE */ + +#ifndef MLD_STATIC_TESTABLE +#define MLD_STATIC_TESTABLE static +#endif + +/* + * C90 does not have the restrict compiler directive yet. + * We don't use it in C90 builds. + */ +#if !defined(restrict) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define MLD_RESTRICT restrict +#else +#define MLD_RESTRICT +#endif + +#else /* !restrict */ + +#define MLD_RESTRICT restrict +#endif /* restrict */ + +#define MLD_DEFAULT_ALIGN 32 +#define MLD_ALIGN_UP(N) \ + ((((N) + (MLD_DEFAULT_ALIGN - 1)) / MLD_DEFAULT_ALIGN) * MLD_DEFAULT_ALIGN) +#if defined(__GNUC__) +#define MLD_ALIGN __attribute__((aligned(MLD_DEFAULT_ALIGN))) +#elif defined(_MSC_VER) +#define MLD_ALIGN __declspec(align(MLD_DEFAULT_ALIGN)) +#else +#define MLD_ALIGN /* No known support for alignment constraints */ +#endif + + +/* New X86_64 CPUs support Conflow-flow protection using the CET instructions. + * When enabled (through -fcf-protection=), all compilation units (including + * empty ones) need to support CET for this to work. + * For assembly, this means that source files need to signal support for + * CET by setting the appropriate note.gnu.property section. + * This can be achieved by including the header in all assembly file. + * This file also provides the _CET_ENDBR macro which needs to be placed at + * every potential target of an indirect branch. + * If CET is enabled _CET_ENDBR maps to the endbr64 instruction, otherwise + * it is empty. + * In case the compiler does not support CET (e.g., +#define MLD_CET_ENDBR _CET_ENDBR +#else +#define MLD_CET_ENDBR +#endif +#endif /* MLD_SYS_X86_64 */ + +#if defined(MLD_CONFIG_CT_TESTING_ENABLED) && !defined(__ASSEMBLER__) +#include +#define MLD_CT_TESTING_SECRET(ptr, len) \ + VALGRIND_MAKE_MEM_UNDEFINED((ptr), (len)) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) +#else /* MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__ */ +#define MLD_CT_TESTING_SECRET(ptr, len) \ + do \ + { \ + } while (0) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + do \ + { \ + } while (0) +#endif /* !(MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__) */ + +#if defined(__GNUC__) || defined(__clang__) +#define MLD_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_MUST_CHECK_RETURN_VALUE +#endif + + +#if !defined(__ASSEMBLER__) +/* System capability enumeration */ +typedef enum +{ + /* x86_64 */ + MLD_SYS_CAP_AVX2, + /* AArch64 */ + MLD_SYS_CAP_SHA3 +} mld_sys_cap; + +#if !defined(MLD_CONFIG_CUSTOM_CAPABILITY_FUNC) +#include "cbmc.h" + +static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) +__contract__( + ensures(return_value == 0 || return_value == 1) +) +{ + /* By default, we rely on compile-time feature detection/specification: + * If a feature is enabled at compile-time, we assume it is supported by + * the host that the resulting library/binary will be built on. + * If this assumption is not true, you MUST overwrite this function. + * See the documentation of MLD_CONFIG_CUSTOM_CAPABILITY_FUNC in + * mldsa_native_config.h for more information. */ + (void)cap; + return 1; +} +#endif /* !MLD_CONFIG_CUSTOM_CAPABILITY_FUNC */ +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_SYS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/zetas.inc b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/zetas.inc new file mode 100644 index 0000000000..dc3cf15dd3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native/src/zetas.inc @@ -0,0 +1,56 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include + +/* + * Table of zeta values used in the reference NTT and inverse NTT. + * See autogen for details. + */ +static const int32_t mld_zetas[MLDSA_N] = { + 0, 25847, -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 2353451, -359251, -2091905, 3119733, -2884855, + 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488, + -1119584, 2619752, -2108549, -2118186, -3859737, -1399561, -3277672, + 1757237, -19422, 4010497, 280005, 2706023, 95776, 3077325, + 3530437, -1661693, -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267, + -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596, + 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, + -2797779, -3930395, -1528703, -3677745, -3041255, -1452451, 3475950, + 2176455, -1585221, -1257611, 1939314, -4083598, -1000202, -3190144, + -3157330, -3632928, 126922, 3412210, -983419, 2147896, 2715295, + -2967645, -3693493, -411027, -2477047, -671102, -1228525, -22981, + -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944, + 508951, 3097992, 44288, -1100098, 904516, 3958618, -3724342, + -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856, + 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, + 1341330, 1285669, -1584928, -812732, -1439742, -3019102, -3881060, + -3628969, 3839961, 2091667, 3407706, 2316500, 3817976, -3342478, + 2244091, -2446433, -3562462, 266997, 2434439, -1235728, 3513181, + -3520352, -3759364, -1197226, -3193378, 900702, 1859098, 909542, + 819034, 495491, -1613174, -43260, -522500, -655327, -3122442, + 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297, + 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, + 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, + 1595974, -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, + 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100, + 1312455, 3306115, -1962642, -1279661, 1917081, -2546312, -1374803, + 1500165, 777191, 2235880, 3406031, -542412, -2831860, -1671176, + -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395, + 2454455, -164721, 1957272, 3369112, 185531, -1207385, -3183426, + 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, + -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, + 472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333, + -260646, -3833893, -2939036, -2235985, -420899, -2286327, 183443, + -976891, 1612842, -3545687, -554416, 3919660, -48306, -1362209, + 3937738, 1400424, -846154, 1976782, +}; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native_all.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native_all.c new file mode 100644 index 0000000000..397a4da91c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/mldsa_native_all.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* Three instances of mldsa-native for all security levels */ + +/* Include level-independent code */ +#define MLD_CONFIG_MULTILEVEL_WITH_SHARED 1 +/* Keep level-independent headers at the end of monobuild file */ +#define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS +#define MLD_CONFIG_PARAMETER_SET 44 +#include "mldsa_native.c" +#undef MLD_CONFIG_MULTILEVEL_WITH_SHARED +#undef MLD_CONFIG_PARAMETER_SET + +/* Exclude level-independent code */ +#define MLD_CONFIG_MULTILEVEL_NO_SHARED +#define MLD_CONFIG_PARAMETER_SET 65 +#include "mldsa_native.c" +/* `#undef` all headers at the and of the monobuild file */ +#undef MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS +#undef MLD_CONFIG_PARAMETER_SET + +#define MLD_CONFIG_PARAMETER_SET 87 +#include "mldsa_native.c" +#undef MLD_CONFIG_PARAMETER_SET diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/test_only_rng/notrandombytes.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/test_only_rng/notrandombytes.c new file mode 100644 index 0000000000..ef5a423a9e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/test_only_rng/notrandombytes.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* * Based on @[surf]*/ + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +#include +#include + +#include "notrandombytes.h" + +#ifdef ENABLE_CT_TESTING +#include +#endif + +static uint32_t seed[32] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, + 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5}; +static uint32_t in[12]; +static uint32_t out[8]; +static int32_t outleft = 0; + +void randombytes_reset(void) +{ + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + outleft = 0; +} + +#define ROTATE(x, b) (((x) << (b)) | ((x) >> (32 - (b)))) +#define MUSH(i, b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x, b)); + +static void surf(void) +{ + uint32_t t[12]; + uint32_t x; + uint32_t sum = 0; + int32_t r; + int32_t i; + int32_t loop; + + for (i = 0; i < 12; ++i) + { + t[i] = in[i] ^ seed[12 + i]; + } + for (i = 0; i < 8; ++i) + { + out[i] = seed[24 + i]; + } + x = t[11]; + for (loop = 0; loop < 2; ++loop) + { + for (r = 0; r < 16; ++r) + { + sum += 0x9e3779b9; + MUSH(0, 5) + MUSH(1, 7) + MUSH(2, 9) + MUSH(3, 13) + MUSH(4, 5) + MUSH(5, 7) + MUSH(6, 9) + MUSH(7, 13) + MUSH(8, 5) + MUSH(9, 7) + MUSH(10, 9) + MUSH(11, 13) + } + for (i = 0; i < 8; ++i) + { + out[i] ^= t[i + 4]; + } + } +} + +int randombytes(uint8_t *buf, size_t n) +{ +#ifdef ENABLE_CT_TESTING + uint8_t *buf_orig = buf; + size_t n_orig = n; +#endif + + while (n > 0) + { + if (!outleft) + { + if (!++in[0]) + { + if (!++in[1]) + { + if (!++in[2]) + { + ++in[3]; + } + } + } + surf(); + outleft = 8; + } + *buf = (uint8_t)out[--outleft]; + ++buf; + --n; + } + +#ifdef ENABLE_CT_TESTING + /* + * Mark all randombytes output as secret (undefined). + * Valgrind will propagate this to everything derived from it. + */ + VALGRIND_MAKE_MEM_UNDEFINED(buf_orig, n_orig); +#endif /* ENABLE_CT_TESTING */ + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/test_only_rng/notrandombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/test_only_rng/notrandombytes.h new file mode 100644 index 0000000000..bdf9787920 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_multilevel_native/test_only_rng/notrandombytes.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* Based on @[surf]. */ + +#ifndef NOTRANDOMBYTES_H +#define NOTRANDOMBYTES_H + +#include +#include + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +void randombytes_reset(void); +int randombytes(uint8_t *buf, size_t n); + +#endif /* !NOTRANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/.gitignore b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/.gitignore new file mode 100644 index 0000000000..eb98a94f12 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +build diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/Makefile new file mode 100644 index 0000000000..2c8d32d0b2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/Makefile @@ -0,0 +1,147 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +.PHONY: build run clean +.DEFAULT_GOAL := all + +CC ?= gcc +AR ?= ar + +# Adjust CFLAGS if needed +CFLAGS := \ + -Wall \ + -Wextra \ + -Werror=unused-result \ + -Wpedantic \ + -Werror \ + -Wmissing-prototypes \ + -Wshadow \ + -Wpointer-arith \ + -Wredundant-decls \ + -Wconversion \ + -Wsign-conversion \ + -Wno-long-long \ + -Wno-unknown-pragmas \ + -Wno-unused-command-line-argument \ + -O3 \ + -fomit-frame-pointer \ + -std=c99 \ + -pedantic \ + -MMD \ + $(CFLAGS) + +# If you want to use the native backends, the compiler needs to know about +# the target architecture. Here, we import the default host detection from +# mldsa-native's tests, but you can write your own or specialize accordingly. +AUTO ?= 1 +include auto.mk + +# The following only concerns the cross-compilation tests. +# You can likely ignore the following for your application. +# +# Append cross-prefix for cross compilation +# When called from the root Makefile, CROSS_PREFIX has already been added here +ifeq (,$(findstring $(CROSS_PREFIX),$(CC))) +CC := $(CROSS_PREFIX)$(CC) +endif + +ifeq (,$(findstring $(CROSS_PREFIX),$(AR))) +AR := $(CROSS_PREFIX)$(AR) +endif + +Q ?= @ + +# Part A: +# +# mldsa-native source and header files +# +# Here, we use just a single C and assembly unit. + +MLD_SOURCE=mldsa_native/mldsa_native.c mldsa_native/mldsa_native.S + +INC=-Imldsa_native/ -I./ + +# Part B: +# +# Random number generator +# +# !!! WARNING !!! +# +# The randombytes() implementation used here is for TESTING ONLY. +# You MUST NOT use this implementation outside of testing. +# +# !!! WARNING !!! +RNG_SOURCE=$(wildcard test_only_rng/*.c) + +# Part C: +# +# Your application source code +APP_SOURCE=$(RNG_SOURCE) main.c + +BUILD_DIR=build +BIN44=test_binary_mldsa44 +BIN65=test_binary_mldsa65 +BIN87=test_binary_mldsa87 +LIB44=libmldsa44.a +LIB65=libmldsa65.a +LIB87=libmldsa87.a + +BIN44_FULL=$(BUILD_DIR)/$(BIN44) +BIN65_FULL=$(BUILD_DIR)/$(BIN65) +BIN87_FULL=$(BUILD_DIR)/$(BIN87) + +LIB44_FULL=$(BUILD_DIR)/$(LIB44) +LIB65_FULL=$(BUILD_DIR)/$(LIB65) +LIB87_FULL=$(BUILD_DIR)/$(LIB87) + +$(LIB44_FULL): $(MLD_SOURCE) + $(Q)echo "$@" + $(Q)[ -d $(@) ] || mkdir -p $(@D) + $(Q)$(CC) -c $(CFLAGS) -DMLD_CONFIG_PARAMETER_SET=44 $(INC) mldsa_native/mldsa_native.c -o $(BUILD_DIR)/mldsa_native44.c.o + $(Q)$(CC) -c $(CFLAGS) -DMLD_CONFIG_PARAMETER_SET=44 $(INC) mldsa_native/mldsa_native.S -o $(BUILD_DIR)/mldsa_native44.S.o + $(Q)$(AR) rcs $@ $(BUILD_DIR)/mldsa_native44.c.o $(BUILD_DIR)/mldsa_native44.S.o + $(Q)strip -S $@ + +$(LIB65_FULL): $(MLD_SOURCE) + $(Q)echo "$@" + $(Q)[ -d $(@) ] || mkdir -p $(@D) + $(Q)$(CC) -c $(CFLAGS) -DMLD_CONFIG_PARAMETER_SET=65 $(INC) mldsa_native/mldsa_native.c -o $(BUILD_DIR)/mldsa_native65.c.o + $(Q)$(CC) -c $(CFLAGS) -DMLD_CONFIG_PARAMETER_SET=65 $(INC) mldsa_native/mldsa_native.S -o $(BUILD_DIR)/mldsa_native65.S.o + $(Q)$(AR) rcs $@ $(BUILD_DIR)/mldsa_native65.c.o $(BUILD_DIR)/mldsa_native65.S.o + $(Q)strip -S $@ + +$(LIB87_FULL): $(MLD_SOURCE) + $(Q)echo "$@" + $(Q)[ -d $(@) ] || mkdir -p $(@D) + $(Q)$(CC) -c $(CFLAGS) -DMLD_CONFIG_PARAMETER_SET=87 $(INC) mldsa_native/mldsa_native.c -o $(BUILD_DIR)/mldsa_native87.c.o + $(Q)$(CC) -c $(CFLAGS) -DMLD_CONFIG_PARAMETER_SET=87 $(INC) mldsa_native/mldsa_native.S -o $(BUILD_DIR)/mldsa_native87.S.o + $(Q)$(AR) rcs $@ $(BUILD_DIR)/mldsa_native87.c.o $(BUILD_DIR)/mldsa_native87.S.o + $(Q)strip -S $@ + +$(BIN44_FULL): $(APP_SOURCE) $(LIB44_FULL) + $(Q)echo "$@" + $(Q)[ -d $(@) ] || mkdir -p $(@D) + $(Q)$(CC) $(CFLAGS) -DMLD_CONFIG_PARAMETER_SET=44 $(INC) $^ -o $@ + +$(BIN65_FULL): $(APP_SOURCE) $(LIB65_FULL) + $(Q)echo "$@" + $(Q)[ -d $(@) ] || mkdir -p $(@D) + $(Q)$(CC) $(CFLAGS) -DMLD_CONFIG_PARAMETER_SET=65 $(INC) $^ -o $@ + +$(BIN87_FULL): $(APP_SOURCE) $(LIB87_FULL) + $(Q)echo "$@" + $(Q)[ -d $(@) ] || mkdir -p $(@D) + $(Q)$(CC) $(CFLAGS) -DMLD_CONFIG_PARAMETER_SET=87 $(INC) $^ -o $@ + +all: build + +build: $(BIN44_FULL) $(BIN65_FULL) $(BIN87_FULL) + +run: $(BIN44_FULL) $(BIN65_FULL) $(BIN87_FULL) + $(Q)$(EXEC_WRAPPER) ./$(BIN44_FULL) + $(Q)$(EXEC_WRAPPER) ./$(BIN65_FULL) + $(Q)$(EXEC_WRAPPER) ./$(BIN87_FULL) + +clean: + rm -rf $(BUILD_DIR) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/README.md new file mode 100644 index 0000000000..ba2acb08fd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/README.md @@ -0,0 +1,47 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Monolithic Build (Native Backend) + +This directory contains a minimal example for building mldsa-native as a single compilation unit +with native assembly backends, using the auto-generated `mldsa_native.c` and `mldsa_native.S` files. + +## Use Case + +Use this approach when: +- You need only one ML-DSA parameter set (44, 65, or 87) +- You want simple build integration with optimal performance + +## Components + +1. Source tree [mldsa_native/*](mldsa_native), including top-level compilation unit + [mldsa_native.c](mldsa_native/mldsa_native.c) (gathering all C sources), + [mldsa_native.S](mldsa_native/mldsa_native.S) (gathering all assembly sources), + and the mldsa-native API [mldsa_native.h](mldsa_native/mldsa_native.h). +2. A secure random number generator implementing [`randombytes.h`](../../mldsa/src/randombytes.h) +3. Your application source code + +## Configuration + +The configuration file [mldsa_native_config.h](mldsa_native/mldsa_native_config.h) sets: +- `MLD_CONFIG_PARAMETER_SET`: Security level (default 65) +- `MLD_CONFIG_NAMESPACE_PREFIX`: Symbol prefix (set to `mldsa`) +- `MLD_CONFIG_USE_NATIVE_BACKEND_ARITH`: Enables native arithmetic backend +- `MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202`: Enables native FIPS-202 backend + +## Notes + +- Both `mldsa_native.c` and `mldsa_native.S` must be compiled and linked +- Native backends are auto-selected based on target architecture +- On unsupported platforms, the C backend is used automatically + +## Usage + +```bash +make build # Build the example +make run # Run the example +``` + +## Warning + +The `randombytes()` implementation in `test_only_rng/` is for TESTING ONLY. +You MUST provide a cryptographically secure RNG for production use. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/auto.mk b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/auto.mk new file mode 100644 index 0000000000..5f71942085 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/auto.mk @@ -0,0 +1,178 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# Automatically detect system architecture and set preprocessor flags accordingly +# This file detects host CPU capabilities and combines them with compiler support +# to enable optimal compilation flags. +# +# Compiler feature detection can be overridden by setting the corresponding variable +# on the command line: +# make MK_COMPILER_SUPPORTS_SHA3=0 # Disable SHA3 detection +# make MK_COMPILER_SUPPORTS_AVX2=0 # Disable AVX2 detection +# make MK_COMPILER_SUPPORTS_BMI2=0 # Disable BMI2 detection +# make MK_COMPILER_SUPPORTS_SSE2=0 # Disable SSE2 detection + +ifndef _AUTO_MK +_AUTO_MK := + +# Override ARCH for cross-compilation based on CROSS_PREFIX +ifeq ($(CROSS_PREFIX),) +ARCH := $(shell uname -m) +# Normalize architecture names +ifeq ($(ARCH),arm64) +ARCH := aarch64 +endif +else # CROSS_PREFIX +ifneq ($(findstring x86_64, $(CROSS_PREFIX)),) +ARCH := x86_64 +else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),) +ARCH := aarch64_be +else ifneq ($(findstring aarch64, $(CROSS_PREFIX)),) +ARCH := aarch64 +else ifneq ($(findstring riscv64, $(CROSS_PREFIX)),) +ARCH := riscv64 +else ifneq ($(findstring riscv32, $(CROSS_PREFIX)),) +ARCH := riscv32 +else ifneq ($(findstring powerpc64le, $(CROSS_PREFIX)),) +ARCH := powerpc64le +else ifneq ($(findstring arm-none-eabi-, $(CROSS_PREFIX)),) +ARCH := arm +else +ifeq ($(AUTO),1) +$(warning Unknown cross-compilation prefix $(CROSS_PREFIX), no automatic detection of CFLAGS.) +ARCH := unknown +endif +endif +endif # CROSS_PREFIX + +# x86_64 compiler feature detection +ifeq ($(ARCH),x86_64) + +# Test AVX2 support using C with inline assembly +MK_COMPILER_SUPPORTS_AVX2 ?= $(shell echo 'int main() { __asm__("vpxor %%ymm0, %%ymm1, %%ymm2" ::: "ymm0", "ymm1", "ymm2"); return 0; }' | $(CC) -mavx2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test SSE2 support using C with inline assembly +MK_COMPILER_SUPPORTS_SSE2 ?= $(shell echo 'int main() { __asm__("pxor %%xmm0, %%xmm1" ::: "xmm0", "xmm1"); return 0; }' | $(CC) -msse2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test BMI2 support using C with inline assembly +MK_COMPILER_SUPPORTS_BMI2 ?= $(shell echo 'int main() { __asm__("pdep %%eax, %%ebx, %%ecx" ::: "eax", "ebx", "ecx"); return 0; }' | $(CC) -mbmi2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # x86_64 compiler detection + +# AArch64 compiler feature detection +ifeq ($(ARCH),aarch64) + +# Test SHA3 support (Armv8.4-a+SHA3) using C with inline assembly +MK_COMPILER_SUPPORTS_SHA3 ?= $(shell echo 'int main() { __asm__("eor3 v0.16b, v1.16b, v2.16b, v3.16b" ::: "v0", "v1", "v2", "v3"); return 0; }' | $(CC) -march=armv8.4-a+sha3 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # aarch64 compiler detection + +# Define HOST_PLATFORM if not already defined +HOST_PLATFORM ?= $(shell uname -s)-$(shell uname -m) + +# Helper function to check if host CPU supports a feature +# Usage: $(call check_host_feature,feature_pattern,source_command) +define check_host_feature +$(shell $(2) 2>/dev/null | grep -q "$(1)" && echo 1 || echo 0) +endef + +# x86_64 architecture detection +ifeq ($(ARCH),x86_64) + +# Host CPU feature detection for x86_64 +ifeq ($(HOST_PLATFORM),Linux-x86_64) +# Linux: Use /proc/cpuinfo +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,avx2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,sse2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,bmi2,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-x86_64) +# macOS: Use sysctl +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,AVX2,sysctl -n machdep.cpu.leaf7_features) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,SSE2,sysctl -n machdep.cpu.features) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,BMI2,sysctl -n machdep.cpu.leaf7_features) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_AVX2 := 1 +MK_HOST_SUPPORTS_SSE2 := 1 +MK_HOST_SUPPORTS_BMI2 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_AVX2 := 0 +MK_HOST_SUPPORTS_SSE2 := 0 +MK_HOST_SUPPORTS_BMI2 := 0 +endif # HOST_PLATFORM x86_64 + +endif # x86_64 + +# AArch64 architecture detection +ifeq ($(ARCH),aarch64) + +# Host CPU feature detection for AArch64 +ifeq ($(HOST_PLATFORM),Linux-aarch64) +# Linux: Use /proc/cpuinfo (look for sha3 in Features line) +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,sha3,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-arm64) +# macOS: Use sysctl to check for SHA3 support +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,1,sysctl -n hw.optional.armv8_2_sha3) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_SHA3 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_SHA3 := 0 +endif # HOST_PLATFORM aarch64 + +endif # aarch64 + +# Only apply CFLAGS modifications if AUTO=1 +ifeq ($(AUTO),1) + +# x86_64 CFLAGS configuration +ifeq ($(ARCH),x86_64) +CFLAGS += -DMLD_FORCE_X86_64 + +# Add flags only if both compiler and host support the feature +ifeq ($(MK_COMPILER_SUPPORTS_AVX2)$(MK_HOST_SUPPORTS_AVX2),11) +CFLAGS += -mavx2 +endif + +ifeq ($(MK_COMPILER_SUPPORTS_BMI2)$(MK_HOST_SUPPORTS_BMI2),11) +CFLAGS += -mbmi2 +endif +endif # x86_64 + +# AArch64 CFLAGS configuration +ifeq ($(ARCH),aarch64) +CFLAGS += -DMLD_FORCE_AARCH64 + +# Add SHA3 flags only if both compiler and host support it +ifeq ($(MK_COMPILER_SUPPORTS_SHA3)$(MK_HOST_SUPPORTS_SHA3),11) +CFLAGS += -march=armv8.4-a+sha3 +endif +endif # aarch64 + +# AArch64 Big Endian CFLAGS configuration +ifeq ($(ARCH),aarch64_be) +CFLAGS += -DMLD_FORCE_AARCH64_EB +endif # aarch64_be + +# RISC-V 64-bit CFLAGS configuration +ifeq ($(ARCH),riscv64) +CFLAGS += -DMLD_FORCE_RISCV64 +CFLAGS += -march=rv64gcv +endif # riscv64 + +# RISC-V 32-bit CFLAGS configuration +ifeq ($(ARCH),riscv32) +CFLAGS += -DMLD_FORCE_RISCV32 +endif # riscv32 + +# PowerPC 64-bit Little Endian CFLAGS configuration +ifeq ($(ARCH),powerpc64le) +CFLAGS += -DMLD_FORCE_PPC64LE +endif # powerpc64le + +endif # AUTO=1 + +endif # _AUTO_MK diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/expected_signatures.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/expected_signatures.h new file mode 100644 index 0000000000..d52fbe8d5e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/expected_signatures.h @@ -0,0 +1,890 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef EXPECTED_SIGNATURES_H +#define EXPECTED_SIGNATURES_H + +#include + +/* Expected deterministic signatures for each parameter set + * These are generated using the same test message, context, and deterministic + * RNG as used in the basic example. + * + * The PCT modifies the PRNG state, so the KAT tests don't work. + * We run KAT tests only for disabled PCT. */ +#if !defined(MLD_CONFIG_KEYGEN_PCT) +#if MLD_CONFIG_PARAMETER_SET == 44 +const uint8_t expected_signature[] = { + 0x27, 0x5e, 0xbe, 0x2d, 0x23, 0x1a, 0x76, 0xc5, 0xd9, 0x77, 0xcb, 0x62, + 0x25, 0x04, 0xdb, 0x23, 0x31, 0xa9, 0xa8, 0xcd, 0xbc, 0xde, 0xf2, 0x20, + 0xfd, 0xa7, 0xb5, 0xf5, 0x59, 0xae, 0xe6, 0xdd, 0x62, 0xfa, 0x34, 0x96, + 0x4f, 0x1d, 0xcd, 0x84, 0x82, 0xee, 0xc1, 0x74, 0x96, 0x3d, 0x98, 0xd9, + 0x42, 0x9d, 0xd0, 0x77, 0x9c, 0xf9, 0x9e, 0x0e, 0xa7, 0xcb, 0x70, 0xeb, + 0xe7, 0xcd, 0xce, 0x8c, 0xdc, 0x37, 0x15, 0x95, 0x0e, 0x24, 0x70, 0x4f, + 0x33, 0x6e, 0x4f, 0xad, 0xed, 0x4d, 0xf3, 0xe5, 0x38, 0xc1, 0xcd, 0xbb, + 0xde, 0xf1, 0xd2, 0x0d, 0xd6, 0x6b, 0xa3, 0x68, 0x92, 0x4c, 0x4b, 0x4f, + 0x89, 0xa0, 0xa8, 0xc8, 0x36, 0x93, 0x91, 0x17, 0xe7, 0x16, 0xed, 0xcb, + 0xdc, 0xf6, 0x28, 0x13, 0x32, 0x60, 0x14, 0xe0, 0x28, 0x7a, 0x69, 0x05, + 0x1d, 0xf7, 0x3b, 0xdf, 0x18, 0x0c, 0xaf, 0xba, 0x46, 0xf1, 0x5e, 0xd4, + 0xd3, 0xd0, 0x8e, 0x9a, 0xe2, 0xac, 0xdd, 0x0e, 0x5f, 0xb1, 0x69, 0xe2, + 0x74, 0x77, 0x2e, 0x52, 0xf9, 0x11, 0x3d, 0xd8, 0xe5, 0x36, 0x6f, 0x7d, + 0x7d, 0xde, 0x7c, 0xa7, 0x1d, 0x37, 0xdf, 0x6d, 0x5e, 0xea, 0xc8, 0xc0, + 0x72, 0x3f, 0x79, 0xbd, 0x0b, 0x6d, 0x7f, 0x9a, 0x15, 0x90, 0xda, 0xc1, + 0xae, 0xce, 0xf3, 0x44, 0x35, 0x5e, 0x83, 0x86, 0x7e, 0x89, 0x18, 0xa7, + 0x97, 0x8e, 0x87, 0x7c, 0x15, 0xd2, 0xd2, 0x7e, 0xf2, 0xc8, 0x29, 0x4f, + 0x70, 0x0f, 0xa6, 0xd4, 0x76, 0xe8, 0xdd, 0x7d, 0x7a, 0x2d, 0xfe, 0x0a, + 0x0c, 0x5c, 0xb1, 0xef, 0xec, 0x1a, 0x32, 0xca, 0x87, 0xff, 0x6b, 0xb1, + 0xa0, 0xe1, 0x2e, 0x01, 0x52, 0xb2, 0xb8, 0x74, 0x34, 0xb3, 0xfb, 0x15, + 0x0f, 0x17, 0xca, 0x74, 0xc1, 0xc1, 0x61, 0x86, 0x40, 0x38, 0x58, 0xba, + 0x82, 0x26, 0x66, 0x33, 0xa4, 0x52, 0xf3, 0xb5, 0x36, 0x60, 0xd8, 0x5a, + 0x8d, 0x9d, 0x28, 0x18, 0x3a, 0x68, 0x34, 0x2a, 0xa2, 0xe2, 0xb5, 0x39, + 0xed, 0x7d, 0xe5, 0xbe, 0x46, 0xb9, 0x04, 0x0c, 0xf3, 0xef, 0x88, 0x6e, + 0x9d, 0x6f, 0x23, 0xe2, 0x44, 0xe5, 0x2e, 0x3a, 0x7a, 0x1d, 0x49, 0x0f, + 0xdd, 0xcd, 0xd6, 0x4e, 0x0d, 0x0b, 0xc3, 0x35, 0xf2, 0xd1, 0x5d, 0x73, + 0x5d, 0x07, 0xca, 0x5c, 0xbd, 0x14, 0xec, 0x57, 0xb3, 0xbd, 0x37, 0xe7, + 0xdf, 0x06, 0x7d, 0xe0, 0x58, 0x4a, 0xcf, 0x7a, 0xc5, 0xa7, 0x24, 0x62, + 0x6f, 0x09, 0x75, 0x69, 0x74, 0x7f, 0xdf, 0xc8, 0x69, 0x5c, 0x20, 0x10, + 0x3a, 0xe8, 0x01, 0x12, 0xa3, 0xfb, 0xda, 0x4c, 0x3a, 0x0d, 0x3c, 0x3e, + 0x26, 0xe0, 0xa6, 0x7f, 0xb2, 0x6b, 0x0b, 0x68, 0x0a, 0x68, 0x86, 0xb1, + 0xfa, 0x61, 0x3a, 0xe8, 0x77, 0xdc, 0x42, 0xf7, 0xf4, 0x39, 0x9a, 0x40, + 0x58, 0x71, 0xc7, 0x0f, 0xf4, 0x0e, 0xc5, 0x1e, 0xe0, 0x28, 0x45, 0x7d, + 0xba, 0x84, 0xe4, 0x34, 0x69, 0xf9, 0xa5, 0x8a, 0x80, 0x43, 0xc0, 0x8d, + 0x04, 0x33, 0x43, 0xb8, 0xd7, 0x5d, 0x93, 0xed, 0x0f, 0x31, 0x6a, 0x4d, + 0xbf, 0xb7, 0x44, 0x41, 0x1b, 0xd4, 0xac, 0x9d, 0x83, 0x66, 0x08, 0x92, + 0xad, 0x3c, 0x0e, 0x1a, 0xe8, 0xd4, 0xe1, 0x5c, 0x63, 0xcf, 0x27, 0x48, + 0x5a, 0x8f, 0xc5, 0x6f, 0x83, 0x6b, 0x6f, 0xe8, 0xda, 0x1f, 0xba, 0xe9, + 0x7e, 0x11, 0xab, 0x8b, 0x4e, 0xc1, 0x9e, 0x23, 0x69, 0x1f, 0x42, 0x40, + 0xad, 0xbb, 0xfb, 0x4f, 0xe2, 0x50, 0xc9, 0x46, 0xe7, 0x15, 0x15, 0xf8, + 0x61, 0x09, 0x2a, 0x0b, 0x37, 0x43, 0xd4, 0x98, 0x5f, 0xc8, 0x4d, 0x06, + 0xe7, 0x0c, 0x3f, 0x83, 0x59, 0xd5, 0xcd, 0x2d, 0xde, 0x1e, 0x3a, 0x87, + 0x4e, 0xf7, 0x0a, 0x3c, 0x84, 0x72, 0x47, 0x11, 0x02, 0x6c, 0xe8, 0x93, + 0xcd, 0x24, 0xe9, 0x23, 0x86, 0x78, 0x53, 0xe0, 0xc6, 0x2f, 0xba, 0xa7, + 0xed, 0xaf, 0xba, 0x42, 0x80, 0x0d, 0xe6, 0xae, 0xda, 0xed, 0xbc, 0x65, + 0x21, 0x6d, 0x13, 0x90, 0x61, 0xb4, 0x05, 0x7b, 0x07, 0x86, 0xd7, 0x89, + 0x30, 0x9c, 0xc1, 0x9a, 0x41, 0x4d, 0xe8, 0x2b, 0x35, 0x21, 0x3a, 0x8a, + 0x60, 0x83, 0x1a, 0x97, 0x10, 0x98, 0xb6, 0xe1, 0x6b, 0xb5, 0xb1, 0xa1, + 0x36, 0x34, 0x60, 0x1b, 0x96, 0x5d, 0x1f, 0x2a, 0xd8, 0xf2, 0x94, 0xdd, + 0x58, 0x3d, 0x0f, 0xbe, 0x9d, 0xfc, 0xf5, 0x24, 0xb1, 0xd2, 0xc3, 0x36, + 0xef, 0xdb, 0x8e, 0x97, 0x3c, 0x9a, 0x4f, 0x48, 0xe3, 0x84, 0x91, 0xd8, + 0x39, 0x91, 0xf6, 0x55, 0xeb, 0x62, 0x51, 0x3d, 0x8f, 0x55, 0x60, 0x5e, + 0x00, 0xe0, 0xd2, 0xc7, 0x66, 0x51, 0xf1, 0xe2, 0xb7, 0x43, 0xc3, 0xe6, + 0x12, 0x9a, 0xe5, 0x84, 0xe0, 0x10, 0x76, 0xc7, 0x75, 0x6e, 0xa6, 0xee, + 0x11, 0xe4, 0xaf, 0xbd, 0x8a, 0x4f, 0x1d, 0x05, 0x29, 0x4f, 0xce, 0xa5, + 0x73, 0x92, 0x57, 0x7e, 0x0d, 0x11, 0xbc, 0xf8, 0x74, 0x4d, 0xf7, 0xb9, + 0x40, 0x0d, 0x5a, 0xa1, 0x19, 0x76, 0x4a, 0xae, 0x21, 0x16, 0xd4, 0x3f, + 0x76, 0xbf, 0x27, 0xbd, 0x2f, 0xe4, 0x25, 0x21, 0x00, 0x4e, 0xcc, 0x7c, + 0xc6, 0x57, 0xa4, 0xbf, 0xf1, 0x56, 0x90, 0xe0, 0xa4, 0xa3, 0xee, 0xcf, + 0x43, 0x4f, 0xda, 0x77, 0x47, 0x51, 0x79, 0x6a, 0x29, 0xb4, 0x2c, 0xdf, + 0xca, 0x47, 0xcb, 0xb8, 0x82, 0x7e, 0x44, 0x62, 0x9b, 0x8f, 0x61, 0x7b, + 0x3a, 0x93, 0x82, 0x1f, 0x69, 0xb7, 0xb1, 0xa6, 0x2c, 0xe1, 0xb2, 0x65, + 0xa0, 0x6d, 0x6f, 0xe4, 0x79, 0xd8, 0x30, 0xe0, 0xee, 0xd8, 0x83, 0x01, + 0xb2, 0x1f, 0x5c, 0x90, 0x44, 0x86, 0x48, 0x11, 0xf9, 0x11, 0xff, 0xea, + 0x45, 0x43, 0xae, 0x8a, 0x6b, 0x99, 0xf2, 0x1f, 0x02, 0x51, 0x4a, 0x35, + 0x02, 0x34, 0xd3, 0xe8, 0xda, 0xb1, 0x4b, 0xe3, 0xa5, 0x60, 0xce, 0x67, + 0xe3, 0x62, 0x59, 0xfc, 0x00, 0x0a, 0xe2, 0xfe, 0x7b, 0x1e, 0xe6, 0xf5, + 0x75, 0x19, 0x9b, 0x5e, 0xcb, 0xe6, 0xf5, 0x80, 0x9e, 0x3c, 0xb8, 0x54, + 0xd6, 0x0b, 0xfd, 0x48, 0xe0, 0xfa, 0x82, 0x2b, 0x5b, 0x26, 0xf9, 0x49, + 0xaf, 0xbe, 0x9c, 0x78, 0x73, 0xce, 0xc5, 0x65, 0xe2, 0x94, 0x2b, 0xd9, + 0xd0, 0x27, 0x3a, 0x66, 0x3e, 0xe2, 0xe0, 0x10, 0x79, 0x3d, 0xde, 0xc8, + 0x47, 0xdb, 0x1e, 0xc3, 0xe7, 0x51, 0xae, 0x59, 0xeb, 0x38, 0x66, 0x63, + 0x40, 0x8f, 0xbe, 0x1e, 0xb2, 0x2b, 0xeb, 0x64, 0x5f, 0xdd, 0x24, 0xc4, + 0x5a, 0x25, 0x59, 0xa2, 0xda, 0x4f, 0xdf, 0xf8, 0xb0, 0xb0, 0xf7, 0xcd, + 0x1f, 0x14, 0xcd, 0x09, 0x48, 0x70, 0x27, 0x1b, 0xde, 0xc4, 0xf0, 0xf3, + 0x56, 0x97, 0x8a, 0xb7, 0xf4, 0x19, 0x76, 0xe3, 0x9a, 0x33, 0x55, 0xfe, + 0x93, 0x68, 0xca, 0x1f, 0x3d, 0x44, 0x86, 0x39, 0x5d, 0x84, 0x58, 0x50, + 0xf2, 0xf1, 0xea, 0x4a, 0x5c, 0x1c, 0x74, 0xf0, 0x4b, 0xa5, 0x9c, 0x30, + 0xa0, 0x14, 0x1a, 0x80, 0xe0, 0xde, 0x3e, 0xae, 0x7f, 0x10, 0x18, 0x4a, + 0x1e, 0x9e, 0x6b, 0x75, 0x1a, 0xca, 0x08, 0x4e, 0x61, 0x72, 0x43, 0x9b, + 0x18, 0x4d, 0x2c, 0xd8, 0xb4, 0xc9, 0xea, 0x00, 0xb0, 0xdf, 0x1b, 0xcb, + 0x03, 0xc3, 0x7a, 0x27, 0xff, 0x41, 0x9d, 0xf9, 0xfd, 0xb3, 0x0c, 0xc0, + 0x48, 0x5d, 0x7c, 0xae, 0x5a, 0x72, 0x69, 0x93, 0x68, 0xe1, 0x9e, 0x9f, + 0x1f, 0x5c, 0x0a, 0x60, 0x90, 0x1a, 0x8e, 0x5a, 0x30, 0xd4, 0x2c, 0xbd, + 0xe1, 0x20, 0x51, 0xbc, 0x1c, 0x50, 0xb5, 0xf7, 0x42, 0x23, 0x35, 0x0f, + 0x92, 0xe2, 0xbb, 0x2a, 0x04, 0xa7, 0xde, 0x2e, 0x25, 0xfa, 0xed, 0x20, + 0x83, 0x9c, 0xd4, 0x56, 0xe0, 0x4d, 0x8d, 0x79, 0xa5, 0xa0, 0x6f, 0x49, + 0x62, 0x82, 0x9a, 0xa7, 0x4e, 0x54, 0x95, 0x0a, 0xc6, 0x5e, 0x27, 0x65, + 0x6d, 0x11, 0x2b, 0x35, 0x72, 0x34, 0x48, 0xd2, 0xe4, 0x9e, 0x07, 0x7d, + 0x03, 0x27, 0x15, 0x93, 0x55, 0x5c, 0x32, 0x43, 0xdb, 0x34, 0x8d, 0xbd, + 0x8d, 0x88, 0xa5, 0x24, 0x07, 0x93, 0x89, 0x37, 0xb9, 0x17, 0x15, 0xad, + 0xc7, 0x68, 0x86, 0x63, 0x0f, 0x10, 0x53, 0x8f, 0x40, 0xd3, 0x7b, 0x22, + 0x2b, 0x1a, 0x4c, 0xcb, 0x4f, 0x51, 0xf1, 0x3b, 0x19, 0xb8, 0x42, 0x53, + 0xaf, 0xf6, 0xb9, 0x57, 0x7f, 0xba, 0x8d, 0xb8, 0xb7, 0x3b, 0xe3, 0xc5, + 0xab, 0x4a, 0x26, 0x21, 0x6e, 0xce, 0x27, 0xb8, 0xc3, 0x99, 0x56, 0x14, + 0xdd, 0x5b, 0x61, 0x82, 0xbf, 0xd3, 0xc8, 0x76, 0xee, 0x22, 0xaf, 0x21, + 0x21, 0x1d, 0x4e, 0x33, 0xb5, 0x43, 0x3a, 0xfb, 0x91, 0xa0, 0xaa, 0xe3, + 0x10, 0x4a, 0x50, 0x42, 0xd4, 0x5f, 0x92, 0x0e, 0x71, 0x60, 0x4f, 0xaa, + 0xef, 0x66, 0x45, 0xfe, 0xf7, 0xc8, 0xb0, 0x73, 0x75, 0x91, 0x0b, 0x86, + 0x40, 0xa5, 0x02, 0x28, 0xf7, 0xe0, 0x1f, 0x5d, 0xe6, 0xe3, 0xa4, 0x57, + 0xbd, 0x29, 0xaa, 0x53, 0xae, 0x35, 0x30, 0x78, 0x73, 0xd6, 0xb7, 0x01, + 0x9d, 0x13, 0x50, 0xf6, 0x39, 0xa2, 0x3e, 0x03, 0x04, 0xaa, 0x6d, 0xcf, + 0x6b, 0xff, 0x9a, 0xbe, 0x3e, 0x0a, 0xd4, 0x20, 0xce, 0x42, 0x1f, 0xca, + 0x2f, 0xd3, 0x2c, 0xd1, 0xf4, 0xd2, 0x50, 0xd3, 0xa2, 0xc1, 0x1e, 0x87, + 0xbf, 0xeb, 0xb8, 0xa8, 0xd4, 0x1c, 0x96, 0xb8, 0x8e, 0xbe, 0x35, 0x5f, + 0x08, 0x28, 0x20, 0x2b, 0xdc, 0xa4, 0xf5, 0xf6, 0xde, 0xca, 0x1e, 0xcb, + 0x93, 0x3b, 0x64, 0x79, 0x00, 0x3c, 0x8d, 0xbb, 0x5c, 0x7a, 0x40, 0x14, + 0x58, 0x12, 0xa4, 0xf7, 0x6e, 0x51, 0xfb, 0xe7, 0x6f, 0x49, 0x5b, 0xc2, + 0xc9, 0x05, 0x38, 0x9c, 0x08, 0x78, 0x71, 0x27, 0x2b, 0xf5, 0xbf, 0xd6, + 0x38, 0xaa, 0x45, 0xe1, 0xe1, 0x4c, 0xfb, 0xfd, 0xb7, 0xe6, 0xcf, 0xad, + 0x9e, 0x56, 0xaf, 0x12, 0x12, 0x98, 0xe6, 0x38, 0xaa, 0xee, 0xdb, 0x9e, + 0xca, 0xe1, 0x79, 0x6d, 0x44, 0xfb, 0x19, 0x50, 0x92, 0x00, 0x06, 0x2c, + 0x24, 0x71, 0x6c, 0x34, 0x45, 0xac, 0xf9, 0x82, 0x66, 0xa8, 0x63, 0x80, + 0xa8, 0x5b, 0x21, 0x3c, 0x36, 0x71, 0x93, 0x40, 0x7b, 0xff, 0xa2, 0xd0, + 0x72, 0xb4, 0x66, 0xfa, 0xfc, 0xa0, 0xee, 0xca, 0x15, 0x73, 0x52, 0xe7, + 0x9d, 0x11, 0xd3, 0xbc, 0xab, 0x37, 0x31, 0x0e, 0xaf, 0xdc, 0x05, 0x30, + 0x79, 0x8c, 0x25, 0x75, 0x5c, 0x60, 0xc7, 0x9a, 0xfc, 0x88, 0xea, 0xe6, + 0x09, 0x9f, 0xd1, 0x4f, 0x13, 0xf4, 0x41, 0x54, 0x5b, 0x7a, 0xe4, 0x49, + 0x3c, 0x0f, 0x15, 0xe9, 0xa4, 0x85, 0xb2, 0x92, 0x07, 0xea, 0xea, 0x7c, + 0xc1, 0x6d, 0xa9, 0x03, 0xb3, 0x31, 0xce, 0x1e, 0x82, 0xca, 0x9e, 0x3c, + 0x88, 0x88, 0xc1, 0x04, 0x5f, 0xbe, 0xd5, 0x94, 0x0d, 0x67, 0x98, 0x27, + 0xd0, 0x0f, 0x43, 0xf3, 0xb3, 0xfc, 0xff, 0x24, 0xa2, 0x1e, 0x17, 0x06, + 0xb0, 0x52, 0x16, 0x7c, 0xd8, 0x49, 0x74, 0x51, 0xcf, 0x2d, 0x36, 0x16, + 0xb0, 0x88, 0xb2, 0x2b, 0x1d, 0x72, 0x70, 0xab, 0xe2, 0xf6, 0x5f, 0xa5, + 0x2d, 0x4e, 0xd1, 0x42, 0x3c, 0x83, 0x84, 0xb2, 0x56, 0xeb, 0x8d, 0xce, + 0x33, 0x46, 0xdb, 0x3d, 0x4f, 0x97, 0xea, 0x37, 0x5e, 0x0d, 0xd7, 0x4c, + 0x9a, 0x7e, 0xc9, 0x0e, 0x69, 0x4d, 0x97, 0x15, 0x1e, 0x09, 0xbe, 0x7e, + 0xff, 0xe8, 0xf5, 0xab, 0xe9, 0xe7, 0xed, 0x4b, 0x41, 0xa5, 0xf2, 0x2a, + 0x24, 0x48, 0x8b, 0x72, 0x4b, 0x9d, 0xcf, 0x45, 0xdb, 0xc0, 0xaf, 0xa8, + 0x0f, 0x0f, 0x67, 0x37, 0xd3, 0x8b, 0xe1, 0x67, 0x90, 0xd8, 0x1c, 0x58, + 0x36, 0x46, 0x51, 0x52, 0xea, 0xb4, 0x75, 0xb1, 0xcd, 0xc5, 0x39, 0x16, + 0xe0, 0xec, 0x16, 0xf7, 0xf8, 0x0f, 0x5d, 0x13, 0x84, 0x62, 0x34, 0x86, + 0x42, 0x05, 0xa8, 0x08, 0x84, 0xa9, 0x77, 0x12, 0xc1, 0x56, 0xdd, 0x28, + 0xde, 0x39, 0x33, 0x21, 0x3d, 0xbd, 0x94, 0xce, 0xe4, 0xb3, 0x17, 0x9b, + 0x09, 0x20, 0xf0, 0x25, 0xce, 0x00, 0x34, 0x8e, 0x12, 0x94, 0x74, 0x0b, + 0x16, 0xa1, 0x60, 0x76, 0x24, 0xf0, 0xbf, 0xe3, 0x3a, 0x83, 0x8f, 0x40, + 0x47, 0x2e, 0x1c, 0xd5, 0x35, 0x25, 0x87, 0xb3, 0x11, 0xdc, 0x98, 0xb0, + 0xa6, 0x5f, 0x6a, 0x05, 0x1d, 0x06, 0x8d, 0xe8, 0xb0, 0x98, 0xf0, 0x43, + 0x29, 0x84, 0xe4, 0xef, 0x34, 0x67, 0x74, 0x64, 0xe8, 0xb8, 0xf0, 0xd4, + 0x9e, 0xc1, 0x3f, 0x5f, 0xeb, 0xe0, 0x9b, 0x37, 0xf8, 0x75, 0x46, 0x47, + 0xa5, 0x3e, 0x42, 0x20, 0x50, 0xc4, 0x5d, 0xf3, 0xdf, 0x4e, 0xf8, 0x0e, + 0x1e, 0x15, 0x10, 0x3e, 0xf1, 0x68, 0xad, 0x87, 0xad, 0xe5, 0x45, 0x5e, + 0x22, 0xba, 0x2e, 0x51, 0xa0, 0xbf, 0xdc, 0x87, 0xca, 0xe4, 0x1f, 0x2f, + 0x2c, 0xae, 0xa9, 0x14, 0xd7, 0xdd, 0x01, 0xa8, 0x4f, 0x43, 0xcb, 0x84, + 0x92, 0xbf, 0xf9, 0x3d, 0xf0, 0x6b, 0x19, 0x43, 0xb0, 0xdf, 0xff, 0x94, + 0x76, 0xe2, 0x84, 0xf9, 0x31, 0x88, 0x7e, 0xc6, 0x87, 0x58, 0xbe, 0x5d, + 0x8b, 0xf8, 0xb5, 0xdc, 0x95, 0x16, 0x5f, 0xa1, 0x2c, 0xe8, 0x53, 0x36, + 0x64, 0xf5, 0x5d, 0xa0, 0x74, 0x12, 0x78, 0x59, 0x73, 0x69, 0x5a, 0x2b, + 0x36, 0x4a, 0xff, 0x5b, 0xef, 0x49, 0x2c, 0xb2, 0x9e, 0x59, 0xf0, 0x39, + 0x56, 0xe1, 0xd0, 0x1a, 0x05, 0xb2, 0x7c, 0xd1, 0x40, 0x09, 0xdf, 0x00, + 0xc9, 0x15, 0x53, 0xa2, 0xda, 0x84, 0xb5, 0x85, 0x05, 0x76, 0xa6, 0x1b, + 0xcb, 0x06, 0xb2, 0xc8, 0xa0, 0xc5, 0x23, 0x8f, 0xb0, 0xe8, 0xf5, 0xd9, + 0xd0, 0x19, 0x29, 0xfe, 0x2d, 0x9a, 0x57, 0x76, 0x5f, 0xf2, 0xef, 0x71, + 0x16, 0xee, 0x28, 0x7b, 0xe4, 0x48, 0xeb, 0xda, 0xe0, 0xd5, 0xbc, 0x0e, + 0x46, 0x6b, 0x06, 0x5d, 0xe5, 0x91, 0x2d, 0xcb, 0xc4, 0x53, 0xa6, 0x16, + 0xd5, 0xe7, 0xd8, 0xf1, 0xdd, 0x4f, 0xbb, 0xcc, 0x55, 0x67, 0x19, 0x98, + 0x94, 0x95, 0x5e, 0xd6, 0xf5, 0xf7, 0xe8, 0x6a, 0xf7, 0x20, 0x86, 0x3a, + 0x43, 0xbf, 0xe9, 0xec, 0x6b, 0x33, 0x49, 0x19, 0x43, 0xfb, 0xeb, 0x3f, + 0xf4, 0x9d, 0x29, 0x66, 0xb9, 0x6e, 0xb5, 0x15, 0x4b, 0x8d, 0x3c, 0x3c, + 0xfa, 0xf2, 0x87, 0xba, 0x61, 0x11, 0x40, 0xe6, 0xb4, 0x6f, 0xf5, 0xe1, + 0x24, 0x32, 0x69, 0x3e, 0xff, 0xf7, 0xbc, 0xee, 0x82, 0xf2, 0x9e, 0x6d, + 0x3f, 0x6c, 0xcc, 0x0f, 0x4f, 0xc3, 0xf1, 0xdb, 0x1e, 0x81, 0xd7, 0x9b, + 0x22, 0xa8, 0xa7, 0x36, 0x6d, 0xa9, 0x6f, 0x46, 0x1a, 0xa7, 0xff, 0x00, + 0x4b, 0xd8, 0xab, 0xe7, 0x50, 0x3b, 0xe9, 0xc0, 0x57, 0xec, 0x8d, 0x0c, + 0xa0, 0xee, 0x8c, 0x2a, 0x74, 0xf2, 0x94, 0xf9, 0x0c, 0x20, 0x14, 0xd9, + 0xad, 0x0d, 0x4e, 0xac, 0x35, 0x44, 0x59, 0x28, 0x24, 0x31, 0x32, 0xaa, + 0x6d, 0xc2, 0x13, 0xb9, 0xee, 0x75, 0x0c, 0x5f, 0x39, 0xef, 0x31, 0xca, + 0x28, 0x48, 0x56, 0x59, 0xfb, 0xa8, 0xd8, 0x2b, 0x70, 0x61, 0x22, 0x43, + 0x43, 0xb9, 0x60, 0x44, 0xeb, 0xf8, 0x98, 0x87, 0x25, 0x84, 0xa2, 0xaa, + 0x37, 0xd4, 0xb8, 0xd6, 0x3d, 0xa3, 0xa1, 0x4a, 0x81, 0xc2, 0xa9, 0xea, + 0xa2, 0xd6, 0x63, 0x76, 0x50, 0xeb, 0xcd, 0x19, 0x40, 0xb1, 0x7c, 0xf6, + 0xc1, 0x44, 0x01, 0x25, 0xe0, 0xdd, 0xb8, 0x39, 0xef, 0x46, 0x3d, 0x50, + 0x33, 0xed, 0xb1, 0x63, 0x65, 0xd7, 0x50, 0xe7, 0x95, 0xba, 0xab, 0xa7, + 0x14, 0xe5, 0x60, 0xcb, 0x81, 0x6e, 0x88, 0x3c, 0x06, 0x6e, 0x7d, 0x8e, + 0xe7, 0xbb, 0xa5, 0xc2, 0xbd, 0xae, 0x46, 0x8f, 0x43, 0x04, 0x29, 0xe6, + 0x17, 0x38, 0x05, 0x2d, 0x97, 0x93, 0x5b, 0xf9, 0xef, 0x4d, 0x2e, 0x75, + 0x6c, 0x69, 0xba, 0x08, 0xf2, 0x21, 0x1e, 0x21, 0xe6, 0x8a, 0x5b, 0x8c, + 0xd4, 0x8e, 0xde, 0x64, 0x9b, 0x9d, 0x54, 0x58, 0x65, 0x3e, 0xdd, 0x8a, + 0x1e, 0x81, 0x4e, 0x45, 0xe8, 0xfb, 0x20, 0xc3, 0x3a, 0xf0, 0x50, 0x1e, + 0x8a, 0x18, 0xea, 0x2b, 0xf5, 0xe1, 0xa6, 0xb6, 0xc8, 0xa0, 0x02, 0x3d, + 0x6e, 0xfa, 0x0b, 0x51, 0x95, 0x4e, 0x4c, 0x11, 0xb0, 0xc4, 0x62, 0x58, + 0xa6, 0x9c, 0x13, 0x4e, 0xbe, 0xc9, 0x29, 0x93, 0x29, 0x15, 0x5f, 0xaf, + 0x0e, 0xc3, 0xb3, 0x26, 0x3f, 0xdc, 0x4c, 0x33, 0xb8, 0x4b, 0x11, 0xae, + 0x1f, 0xd7, 0x05, 0x39, 0xcf, 0xfe, 0xc3, 0x6d, 0xf0, 0xc0, 0x77, 0x02, + 0xb8, 0x9b, 0x3d, 0x1b, 0x3d, 0x72, 0xfe, 0x7e, 0x18, 0x60, 0x9b, 0xc4, + 0x8b, 0xac, 0x25, 0x6d, 0x3b, 0x80, 0x34, 0xbc, 0x51, 0xaf, 0xf6, 0xff, + 0x66, 0x98, 0x86, 0x6e, 0x9e, 0x9a, 0xfe, 0x6d, 0x21, 0x4d, 0xf1, 0x58, + 0x3e, 0x3e, 0x43, 0xe3, 0x7e, 0x40, 0xb0, 0xb3, 0xd8, 0x12, 0xa5, 0xce, + 0x09, 0x41, 0x8c, 0x1d, 0x73, 0xcd, 0xfc, 0x63, 0xed, 0xeb, 0x08, 0x1e, + 0x34, 0xfb, 0xed, 0x75, 0xb7, 0x86, 0x84, 0x7c, 0x80, 0xe9, 0xe4, 0xa3, + 0x1c, 0x4a, 0x0d, 0x11, 0x16, 0x24, 0xb2, 0xb1, 0x99, 0xe5, 0xe3, 0x2e, + 0x2f, 0x70, 0xcd, 0x1e, 0x35, 0x14, 0x79, 0xba, 0xa2, 0x51, 0x7a, 0x29, + 0x5c, 0x75, 0x8f, 0xdd, 0x22, 0xdf, 0xb2, 0x64, 0xd9, 0x95, 0x11, 0x33, + 0x97, 0xee, 0x69, 0x42, 0x01, 0x96, 0x98, 0x1b, 0x43, 0xc2, 0xec, 0xf9, + 0xb0, 0xdb, 0x69, 0x34, 0xab, 0x98, 0x1b, 0xb2, 0x04, 0x05, 0x14, 0x1d, + 0x25, 0x2f, 0x32, 0x41, 0x50, 0x51, 0x55, 0x62, 0x6d, 0x78, 0x7f, 0x8b, + 0xbb, 0xc2, 0xcd, 0xcf, 0xe4, 0xed, 0x04, 0x1f, 0x25, 0x30, 0x43, 0x64, + 0x69, 0x7c, 0x87, 0xa3, 0xa9, 0xb1, 0xc1, 0xd1, 0xdc, 0x01, 0x10, 0x1d, + 0x27, 0x3f, 0x5c, 0x5d, 0x75, 0x82, 0x9b, 0xaa, 0xb3, 0xe8, 0x0c, 0x11, + 0x1f, 0x24, 0x38, 0x41, 0x45, 0x54, 0x5f, 0x69, 0x85, 0x8d, 0x93, 0x9e, + 0xc5, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x25, 0x32, 0x42}; +#elif MLD_CONFIG_PARAMETER_SET == 65 +const uint8_t expected_signature[] = { + 0x8b, 0x6f, 0x79, 0x00, 0xcc, 0x79, 0x57, 0xee, 0x16, 0x86, 0x87, 0xd5, + 0xcf, 0xb6, 0x90, 0x2c, 0xc6, 0x30, 0xeb, 0x8d, 0x39, 0xae, 0x9b, 0xf1, + 0x66, 0xe0, 0xd6, 0x93, 0xa5, 0x4e, 0x26, 0x9b, 0x96, 0x8f, 0xd1, 0x46, + 0x97, 0xbe, 0x71, 0x1c, 0xf3, 0xa5, 0xe5, 0xae, 0x8d, 0x4b, 0xf2, 0xe6, + 0x48, 0x8f, 0xe9, 0x5e, 0x07, 0xef, 0xe4, 0xbb, 0x39, 0xc1, 0xc9, 0x3c, + 0xc3, 0x0b, 0xfb, 0x2a, 0x29, 0x06, 0xfe, 0x01, 0xcb, 0x63, 0x83, 0x10, + 0xa8, 0xc8, 0xa0, 0x29, 0xa5, 0x80, 0xeb, 0xbd, 0xa9, 0xd9, 0x0b, 0x61, + 0xbc, 0xce, 0x11, 0x55, 0x66, 0x12, 0xc7, 0x5b, 0xd2, 0x7a, 0x5a, 0xc8, + 0xab, 0xab, 0xbf, 0x3a, 0x1f, 0x96, 0x1a, 0x70, 0xcb, 0x41, 0x5f, 0xc8, + 0xb7, 0x09, 0x22, 0x98, 0x9b, 0xb8, 0xf7, 0x2d, 0x49, 0x65, 0x1d, 0x09, + 0x8b, 0x70, 0xb5, 0x42, 0xc9, 0x89, 0x5b, 0x74, 0xb4, 0x28, 0x82, 0x01, + 0x53, 0x12, 0x3e, 0x23, 0xf6, 0x54, 0xf8, 0x51, 0x12, 0x4b, 0x02, 0x3a, + 0x7e, 0xb6, 0x1f, 0xac, 0xa0, 0xe6, 0x6f, 0xf8, 0x61, 0x82, 0xe4, 0xfb, + 0x96, 0x2a, 0xd2, 0xaf, 0x3c, 0xea, 0x6e, 0xdc, 0x18, 0x8a, 0x5d, 0x90, + 0xda, 0xa2, 0x5d, 0xa7, 0x8f, 0x5b, 0x50, 0x46, 0xaf, 0x8c, 0x17, 0x6a, + 0x4c, 0x39, 0xfc, 0x31, 0x4c, 0x4b, 0xc2, 0x57, 0x66, 0x61, 0x98, 0xbf, + 0xe6, 0xfb, 0x54, 0x96, 0xd3, 0x70, 0xb8, 0xaf, 0xcd, 0x8b, 0xcc, 0x00, + 0x07, 0x92, 0x15, 0xc2, 0xbb, 0x48, 0xbb, 0xc6, 0xb7, 0xb5, 0x58, 0x8c, + 0xfc, 0xf0, 0xda, 0x6a, 0x0d, 0xf7, 0x1d, 0x7d, 0xc6, 0x27, 0x26, 0x1a, + 0x99, 0xc5, 0x2f, 0xf8, 0x97, 0x65, 0x43, 0x86, 0xd6, 0x25, 0x23, 0x2b, + 0x06, 0x8f, 0x12, 0xa1, 0xae, 0xbb, 0x58, 0x34, 0x25, 0xec, 0x5b, 0x68, + 0xa4, 0xe1, 0x03, 0xfc, 0x26, 0xa2, 0xd6, 0x2b, 0x61, 0x10, 0x47, 0xbd, + 0x16, 0xe5, 0xca, 0x4a, 0xce, 0xed, 0x89, 0x09, 0x1a, 0xed, 0x22, 0xc1, + 0xca, 0x44, 0xe3, 0xef, 0x72, 0x34, 0xab, 0xab, 0x61, 0x5c, 0x9f, 0x5f, + 0xb5, 0xf5, 0xe8, 0x2d, 0x89, 0xea, 0x4b, 0x40, 0x65, 0x57, 0x8b, 0xa2, + 0x95, 0x40, 0x9c, 0x72, 0xc0, 0x46, 0x69, 0x45, 0x06, 0xf6, 0x07, 0x5b, + 0x2d, 0xa5, 0x46, 0xca, 0x5d, 0xfb, 0x40, 0xb7, 0x48, 0x59, 0x5b, 0xe2, + 0x1b, 0x38, 0xb2, 0x15, 0x75, 0x66, 0x67, 0x58, 0x00, 0x3f, 0xde, 0x8a, + 0x63, 0x13, 0x34, 0x6a, 0x30, 0xca, 0xb4, 0xd5, 0x3e, 0xe0, 0x6d, 0x14, + 0xb8, 0x9a, 0x48, 0xef, 0xfd, 0xbd, 0x6d, 0x20, 0x11, 0x4d, 0x25, 0xe5, + 0xab, 0x15, 0x8d, 0xe5, 0x91, 0xbc, 0xc6, 0x69, 0x8a, 0xf8, 0xab, 0x3a, + 0x82, 0xae, 0xc5, 0x03, 0x2c, 0xcf, 0x54, 0xdc, 0xcd, 0xe8, 0x49, 0x53, + 0xb5, 0xd8, 0xc2, 0x24, 0xf8, 0x8c, 0x38, 0x8f, 0xe3, 0xfe, 0x3a, 0x18, + 0x15, 0xa8, 0xda, 0x77, 0xc8, 0x81, 0x72, 0xc6, 0xc1, 0x60, 0xa3, 0x73, + 0x65, 0x68, 0x5c, 0xf3, 0x1d, 0x8d, 0x61, 0x21, 0x65, 0xfb, 0x45, 0xc4, + 0x4c, 0x31, 0x88, 0x25, 0x0d, 0x52, 0x75, 0x3b, 0xec, 0x54, 0xe0, 0xb1, + 0x9c, 0x7c, 0xdf, 0xe3, 0x3b, 0x77, 0x31, 0x33, 0xd7, 0x25, 0x99, 0xff, + 0xc5, 0x40, 0x1e, 0x85, 0x09, 0xfd, 0x2d, 0x24, 0x4a, 0x92, 0xe7, 0x77, + 0x48, 0xa5, 0x46, 0xf4, 0x8e, 0xa3, 0x6b, 0x24, 0xe4, 0x6b, 0x31, 0xf6, + 0xe0, 0x16, 0x49, 0x9b, 0x9f, 0xa3, 0x1a, 0x5c, 0x05, 0x5e, 0x81, 0x62, + 0xc8, 0x14, 0x52, 0xb4, 0x21, 0xfd, 0x76, 0x6d, 0x88, 0xe9, 0x3b, 0x0b, + 0x75, 0x27, 0x92, 0x47, 0x5a, 0x58, 0x08, 0x26, 0xa7, 0xa2, 0x48, 0x1c, + 0x14, 0x3e, 0x5e, 0xdf, 0x81, 0x83, 0x83, 0x3e, 0xc6, 0x72, 0x27, 0xc4, + 0x6a, 0x46, 0x2b, 0xf2, 0x8d, 0x42, 0x11, 0xb9, 0x15, 0xd7, 0xf0, 0x20, + 0x29, 0x53, 0xba, 0xf0, 0x6e, 0x41, 0x3d, 0xee, 0x19, 0xf2, 0x43, 0xf3, + 0x6d, 0x00, 0xe2, 0x43, 0x77, 0xb9, 0xa9, 0x78, 0x34, 0x48, 0x3c, 0x1a, + 0x8b, 0xbd, 0xa1, 0xe5, 0x90, 0x59, 0x5b, 0xd6, 0x1e, 0x22, 0xdf, 0xb2, + 0xa7, 0x96, 0x7d, 0x55, 0x86, 0x66, 0x95, 0xb7, 0x06, 0xe7, 0x60, 0x2a, + 0x01, 0x48, 0x3f, 0xd4, 0xa7, 0xd4, 0xc2, 0x38, 0xa4, 0x10, 0x8e, 0x4f, + 0x97, 0xad, 0xa3, 0xb9, 0xe2, 0xaa, 0x13, 0xb1, 0x16, 0x89, 0x3d, 0x74, + 0x60, 0x94, 0x8c, 0xc3, 0xe6, 0x5f, 0xcf, 0xdc, 0x58, 0x17, 0x98, 0x27, + 0x86, 0xae, 0x2a, 0x0d, 0xe8, 0x33, 0x79, 0xc8, 0xc8, 0x5b, 0x59, 0xb0, + 0xba, 0xac, 0xd3, 0x6e, 0x2d, 0x7b, 0x0b, 0x9a, 0xb5, 0xfd, 0x58, 0x42, + 0xeb, 0x80, 0xf4, 0x6b, 0x9a, 0x2f, 0x19, 0x43, 0x75, 0xb4, 0xcb, 0xc9, + 0xd5, 0x28, 0xf5, 0xb9, 0x67, 0x82, 0xb4, 0xed, 0x8c, 0x3f, 0x3d, 0x6b, + 0x6d, 0x1b, 0x80, 0x13, 0x5c, 0x7b, 0x2e, 0xfa, 0xa0, 0x32, 0xba, 0xb5, + 0x46, 0xd6, 0xe7, 0x90, 0xe9, 0xd1, 0x91, 0xa0, 0xaa, 0x26, 0x35, 0xa2, + 0x0d, 0x98, 0x44, 0x11, 0xae, 0xf9, 0xc5, 0x12, 0x4d, 0x1a, 0x7c, 0x53, + 0xea, 0xf6, 0x05, 0x8d, 0x3a, 0x74, 0x92, 0xc9, 0x65, 0xeb, 0x6f, 0xb5, + 0xb4, 0xd2, 0xcd, 0x5c, 0xec, 0xaf, 0x95, 0xcb, 0xb4, 0x3c, 0x22, 0xca, + 0x1c, 0x06, 0x85, 0x16, 0x96, 0x24, 0x8c, 0x6c, 0x80, 0xf8, 0xb3, 0xa7, + 0x87, 0x77, 0xeb, 0x09, 0x71, 0xc8, 0x95, 0xfb, 0x5e, 0xe5, 0x6f, 0x78, + 0xf9, 0x60, 0xf9, 0x9e, 0x58, 0x7b, 0xbd, 0x47, 0xdd, 0x48, 0x2e, 0x56, + 0xcd, 0x63, 0x72, 0xc9, 0x4b, 0x65, 0x2d, 0x41, 0xe8, 0x81, 0x19, 0x33, + 0x4b, 0xf6, 0x02, 0xc6, 0xcb, 0x2e, 0xdf, 0x3d, 0xc8, 0xdd, 0x2f, 0x0f, + 0x09, 0x67, 0xf0, 0xaa, 0x3c, 0x51, 0xdc, 0x8d, 0xc6, 0xc3, 0xb2, 0x3b, + 0x15, 0x85, 0xcb, 0xeb, 0x62, 0xef, 0xa3, 0xf9, 0x94, 0xf4, 0x35, 0x9c, + 0x59, 0xcc, 0xc2, 0x68, 0xb4, 0xde, 0x02, 0x75, 0x8e, 0xf5, 0x33, 0xca, + 0xd5, 0xc5, 0x24, 0xae, 0xf6, 0xde, 0x2b, 0x01, 0xf4, 0x56, 0xb9, 0xa5, + 0xa7, 0xe0, 0x64, 0x2e, 0xba, 0x1d, 0x53, 0x54, 0x46, 0xcf, 0x64, 0x16, + 0x12, 0xe2, 0xa6, 0xcc, 0x18, 0xb4, 0x77, 0x8b, 0x19, 0x50, 0x43, 0x96, + 0xc8, 0x5d, 0xc3, 0x58, 0xf0, 0xfd, 0x5e, 0x13, 0xa9, 0x10, 0x67, 0xdf, + 0x25, 0xdb, 0xaf, 0x38, 0x5f, 0xbd, 0x35, 0xc1, 0x49, 0x44, 0xe8, 0x1f, + 0x12, 0xa4, 0x7c, 0x28, 0xa3, 0xd6, 0x0d, 0x6f, 0x44, 0xa9, 0x5f, 0xfc, + 0x9f, 0xfa, 0x11, 0x62, 0x87, 0x5b, 0x0e, 0x91, 0xd4, 0xb6, 0xd3, 0x71, + 0xc2, 0x77, 0x19, 0xf6, 0x7c, 0x11, 0x30, 0x5e, 0x5c, 0xd3, 0x1e, 0x90, + 0x05, 0x31, 0x63, 0xbb, 0xef, 0x85, 0xe0, 0x27, 0x94, 0x80, 0xcb, 0x33, + 0xbc, 0x5e, 0x45, 0x87, 0x62, 0xdf, 0xd4, 0x12, 0x2f, 0xf5, 0x41, 0x15, + 0x03, 0x0c, 0x80, 0xe8, 0xe2, 0x06, 0xde, 0x4b, 0x46, 0x70, 0x94, 0xd2, + 0x0d, 0x85, 0x72, 0x27, 0xe5, 0x6c, 0xeb, 0xd2, 0x78, 0x0b, 0x38, 0x40, + 0xe8, 0xdb, 0x47, 0x5c, 0xba, 0xd0, 0x21, 0x33, 0x8f, 0xb8, 0xc0, 0x66, + 0x1e, 0xd1, 0xb0, 0x94, 0xa3, 0x39, 0xc7, 0x87, 0xaf, 0x97, 0x98, 0xce, + 0x6d, 0x03, 0x1a, 0xdb, 0x52, 0x96, 0x0b, 0x9d, 0x5b, 0xf8, 0xa3, 0xf4, + 0x41, 0x95, 0x72, 0xad, 0x0e, 0x98, 0x61, 0x7f, 0xf3, 0x8f, 0x23, 0xeb, + 0xc0, 0xdf, 0xd7, 0x70, 0x26, 0x8c, 0xb3, 0xb3, 0xf0, 0xa2, 0x8a, 0x39, + 0xdd, 0x61, 0xb4, 0x53, 0xe0, 0x2a, 0x6f, 0x91, 0x34, 0x9c, 0x76, 0xf6, + 0x52, 0x93, 0xe6, 0x39, 0xb7, 0x54, 0x07, 0x46, 0x82, 0x2d, 0x05, 0x6d, + 0x9a, 0x00, 0x53, 0x65, 0x68, 0x93, 0x91, 0x00, 0xda, 0xe0, 0x93, 0x34, + 0x60, 0xb1, 0x93, 0x0b, 0x64, 0xa8, 0x12, 0xd2, 0x51, 0x3c, 0xdb, 0xb0, + 0x4c, 0x39, 0x4e, 0xce, 0xbd, 0xf0, 0x65, 0x12, 0x8a, 0xd4, 0x80, 0x7d, + 0x82, 0x85, 0xe4, 0x92, 0xc2, 0x77, 0x1e, 0xcf, 0xd9, 0xab, 0x0f, 0x9b, + 0x32, 0x2e, 0x3f, 0xe1, 0x0e, 0x87, 0x1c, 0x87, 0x34, 0xe7, 0x93, 0x16, + 0x95, 0x09, 0x7d, 0x24, 0xa8, 0xb5, 0xe0, 0x9f, 0x23, 0x87, 0x5c, 0x0b, + 0x31, 0x4a, 0x2f, 0xe2, 0x5c, 0x82, 0x49, 0x51, 0xe4, 0x93, 0xcb, 0x05, + 0x23, 0x4f, 0x8a, 0x83, 0x88, 0xfb, 0x89, 0xb0, 0x08, 0xd6, 0x64, 0xad, + 0x51, 0x84, 0x40, 0x29, 0xb1, 0xca, 0x74, 0x26, 0x29, 0x5a, 0x61, 0x01, + 0x2e, 0xa0, 0xeb, 0xeb, 0x02, 0xb5, 0xff, 0xd8, 0x20, 0x6a, 0x5e, 0x8d, + 0x17, 0x1e, 0xa3, 0xd7, 0x2f, 0x20, 0x0b, 0x93, 0x17, 0x24, 0xf7, 0x90, + 0x7b, 0xc6, 0xba, 0xd8, 0xf9, 0xe9, 0x0a, 0x2a, 0x7a, 0x81, 0x23, 0x81, + 0x03, 0x6f, 0x1e, 0x0d, 0x87, 0x83, 0xd1, 0xcf, 0x92, 0x2f, 0x19, 0x82, + 0x4e, 0x6c, 0x0a, 0x02, 0xb6, 0x70, 0xbc, 0xe1, 0x58, 0xe7, 0x16, 0xdb, + 0x2f, 0x74, 0x9f, 0xe1, 0xc2, 0x1e, 0x64, 0xc6, 0x48, 0x08, 0xee, 0xea, + 0x52, 0x9a, 0xce, 0x2c, 0xc5, 0x0c, 0x7a, 0x63, 0xf1, 0x6a, 0xbd, 0x2c, + 0x8b, 0xd5, 0x4a, 0xfa, 0x1e, 0xab, 0x9a, 0x5b, 0x25, 0xb8, 0xfa, 0x0a, + 0xe9, 0x68, 0x80, 0x6f, 0x80, 0x57, 0x10, 0x54, 0xb8, 0xa2, 0x16, 0xbd, + 0xfe, 0xf7, 0xea, 0x01, 0xc7, 0x94, 0x5a, 0x95, 0xe3, 0x61, 0xa5, 0x49, + 0x84, 0xf5, 0x79, 0x78, 0xb5, 0x0a, 0x96, 0xca, 0x01, 0x1b, 0xd0, 0x0b, + 0x51, 0x30, 0xd3, 0x48, 0xfc, 0x4d, 0x50, 0x71, 0x09, 0x73, 0xea, 0x37, + 0xcd, 0x9d, 0x3d, 0xde, 0x30, 0x56, 0x21, 0xf0, 0xef, 0x84, 0xad, 0x27, + 0xe1, 0x83, 0xdb, 0xfb, 0xcd, 0x11, 0xb2, 0xbd, 0x30, 0x67, 0x8a, 0x88, + 0x09, 0x0e, 0x9d, 0x96, 0x09, 0xba, 0xda, 0x9d, 0xf0, 0xe9, 0xb4, 0xa6, + 0x7a, 0x04, 0xf9, 0x4b, 0xb8, 0x51, 0xa9, 0x99, 0xf3, 0xbb, 0x77, 0x95, + 0x0a, 0xa1, 0xa6, 0xa1, 0x24, 0xfc, 0xcc, 0x45, 0xe8, 0x83, 0xc8, 0x6f, + 0x48, 0xad, 0x9a, 0x73, 0xd0, 0xe0, 0x57, 0x7d, 0xe4, 0x78, 0x65, 0xef, + 0xae, 0xc2, 0xfe, 0x7a, 0x56, 0xaf, 0x03, 0x71, 0x2b, 0xe6, 0xa1, 0x7e, + 0xe5, 0x12, 0xf8, 0xc3, 0x75, 0xc7, 0x22, 0x5f, 0x1b, 0x52, 0x90, 0xe5, + 0xdf, 0xba, 0x9d, 0xe2, 0x68, 0xe0, 0xb3, 0x7a, 0x9e, 0x14, 0xff, 0xb5, + 0x0a, 0x80, 0x20, 0x49, 0x88, 0xe9, 0x9c, 0xe4, 0xb5, 0xaf, 0x7e, 0x51, + 0xec, 0xe7, 0xfc, 0x64, 0x65, 0x21, 0x10, 0xc6, 0x1f, 0x7f, 0x93, 0x7d, + 0xd8, 0xf5, 0xd0, 0x98, 0x94, 0x44, 0xf8, 0x49, 0x6a, 0x51, 0x0a, 0x54, + 0xf4, 0x9f, 0xee, 0x3c, 0x56, 0xbf, 0x4c, 0xe4, 0xde, 0x1c, 0x9b, 0x11, + 0x7e, 0x9a, 0x71, 0x11, 0x80, 0x33, 0xd5, 0xb0, 0x9b, 0xef, 0x67, 0x29, + 0xa4, 0x7d, 0x70, 0x31, 0x3f, 0x8b, 0x2e, 0x4a, 0x0f, 0x2c, 0x91, 0x3d, + 0x3e, 0x3d, 0x8c, 0x0a, 0x2b, 0xf1, 0xdd, 0xbf, 0x61, 0xe6, 0xa3, 0xef, + 0x6d, 0x82, 0xc8, 0xb7, 0x5e, 0x2b, 0x83, 0xc9, 0x4e, 0xa0, 0x85, 0x7f, + 0x01, 0x5a, 0xca, 0x6e, 0x90, 0xfa, 0x7e, 0x82, 0x4d, 0x35, 0x7e, 0xe0, + 0x26, 0x40, 0xf4, 0xa6, 0xae, 0xc3, 0x89, 0xf3, 0xca, 0x55, 0x2c, 0xb5, + 0x29, 0x05, 0x94, 0x45, 0xa7, 0x45, 0xf3, 0x3d, 0xbb, 0x53, 0x5e, 0xca, + 0x7c, 0x84, 0x8f, 0x72, 0x98, 0x93, 0x90, 0x1f, 0x56, 0x72, 0xdb, 0xbd, + 0xa9, 0xeb, 0xf9, 0xe9, 0xce, 0xb1, 0x41, 0xc3, 0xaa, 0xa0, 0xc4, 0x74, + 0x23, 0xc1, 0xeb, 0x7d, 0x41, 0xcd, 0xa4, 0x62, 0xec, 0xfc, 0x9a, 0xa4, + 0x16, 0xec, 0x67, 0x41, 0x89, 0xf0, 0x0e, 0xf3, 0xd1, 0xa2, 0x2f, 0xba, + 0x5d, 0x93, 0x36, 0x46, 0xf5, 0x52, 0x64, 0x91, 0xe7, 0x40, 0x91, 0x20, + 0xa1, 0xc9, 0xaa, 0x4c, 0x79, 0xc4, 0xbb, 0x67, 0x79, 0xad, 0x43, 0xab, + 0xba, 0xde, 0xfc, 0xf1, 0x74, 0x81, 0x33, 0xc0, 0x3f, 0x39, 0xd1, 0xd1, + 0xdf, 0xc0, 0x53, 0x33, 0xb2, 0x92, 0x37, 0xe6, 0x86, 0x2a, 0xe4, 0xe1, + 0x7c, 0x98, 0xf7, 0xdb, 0x5c, 0xa9, 0xff, 0x8d, 0x9c, 0xab, 0xe2, 0xf2, + 0xd5, 0xb1, 0x42, 0xa9, 0xf4, 0x97, 0x80, 0xcd, 0xde, 0x25, 0x2e, 0x87, + 0x92, 0xdd, 0xcf, 0xed, 0x67, 0x93, 0x8c, 0x5a, 0x1d, 0xee, 0xcf, 0x9d, + 0x50, 0x8f, 0xa7, 0xe3, 0x5c, 0xa3, 0x68, 0x78, 0x24, 0xeb, 0x60, 0xa3, + 0x8b, 0x36, 0xbb, 0xcb, 0x46, 0xee, 0x77, 0xfb, 0xf8, 0x69, 0x24, 0xd1, + 0xfa, 0xad, 0x76, 0x76, 0x5e, 0x54, 0xe5, 0xb6, 0x36, 0xc6, 0xdd, 0xa9, + 0x6c, 0x44, 0x15, 0xf7, 0x0a, 0xf8, 0xbb, 0xba, 0xec, 0x35, 0xff, 0xc9, + 0xd6, 0x5d, 0xf5, 0x73, 0x4a, 0x15, 0x8f, 0x7b, 0x6e, 0xf4, 0xa0, 0x6d, + 0x10, 0xbb, 0x67, 0x0c, 0xb4, 0x69, 0xad, 0xb6, 0x40, 0xf7, 0x5f, 0x37, + 0x28, 0xc4, 0x08, 0x49, 0xd0, 0x16, 0x70, 0x80, 0xea, 0x55, 0x66, 0x07, + 0xc8, 0x03, 0x1b, 0xf6, 0xd3, 0x03, 0x04, 0x74, 0xe0, 0x50, 0x3f, 0xd2, + 0x53, 0x92, 0xa0, 0x9d, 0x59, 0xc9, 0x74, 0xf2, 0x7e, 0x3b, 0x33, 0x02, + 0x10, 0x0b, 0x39, 0xf7, 0x4f, 0x6b, 0x58, 0xb2, 0x1a, 0xda, 0x65, 0x44, + 0xd1, 0x7c, 0x3f, 0xd7, 0xe3, 0xac, 0xe2, 0x1f, 0x38, 0xc1, 0x6a, 0xb0, + 0xdc, 0xc3, 0x9c, 0x7b, 0x11, 0x3c, 0x05, 0x21, 0x96, 0x76, 0x98, 0x76, + 0x82, 0xc1, 0x54, 0xdf, 0xdc, 0x8f, 0x4c, 0xd2, 0x63, 0x04, 0x06, 0x77, + 0x36, 0xe6, 0x2e, 0xd1, 0x00, 0x28, 0x42, 0x7c, 0x4a, 0x27, 0x90, 0x46, + 0xc9, 0xce, 0x33, 0x1c, 0xae, 0xda, 0x79, 0x64, 0x7f, 0x52, 0x3f, 0x58, + 0x11, 0x76, 0x4a, 0xb6, 0x72, 0xd8, 0x76, 0xae, 0xfd, 0x5c, 0x57, 0x69, + 0x76, 0x91, 0x84, 0x21, 0xc4, 0x9b, 0xd8, 0xa2, 0xff, 0x93, 0x02, 0x77, + 0x61, 0x57, 0x96, 0x7b, 0x8e, 0xfc, 0xf2, 0x6c, 0x11, 0x2b, 0x5e, 0x88, + 0x5c, 0x17, 0x1d, 0x12, 0x79, 0x3a, 0x78, 0xb6, 0x9d, 0x70, 0xfa, 0xd4, + 0xc1, 0x5c, 0x90, 0x0e, 0x0a, 0xd1, 0x3c, 0x7d, 0xcf, 0xee, 0x8a, 0xb2, + 0xb2, 0x4d, 0xce, 0x89, 0x32, 0xa9, 0x6c, 0x56, 0x57, 0x85, 0xb1, 0xbf, + 0x18, 0x1d, 0xc6, 0xe1, 0x17, 0xc5, 0x92, 0x42, 0x99, 0xf9, 0x9f, 0x04, + 0xec, 0x38, 0xf8, 0xa0, 0xd2, 0xab, 0xe6, 0x13, 0x4d, 0x9c, 0x18, 0x86, + 0x3e, 0x18, 0x73, 0x2c, 0xac, 0xe0, 0xb9, 0xf9, 0x87, 0x74, 0xb8, 0xd7, + 0x47, 0x6e, 0x42, 0xfc, 0x29, 0xa0, 0x1f, 0x56, 0x68, 0xb6, 0x23, 0x96, + 0xa2, 0x8d, 0x54, 0x81, 0x0f, 0x60, 0xb9, 0xde, 0x93, 0xfc, 0xfd, 0xde, + 0xbe, 0xb3, 0xb5, 0x87, 0xec, 0x9f, 0x17, 0xc2, 0x77, 0x6e, 0xa0, 0x62, + 0xdb, 0x66, 0xba, 0xc5, 0x05, 0x12, 0x46, 0x5d, 0x3c, 0x23, 0x29, 0x68, + 0xe5, 0x31, 0xe3, 0x15, 0xec, 0xac, 0x15, 0x9a, 0xbf, 0x42, 0x65, 0x80, + 0x45, 0x9c, 0x1d, 0xc2, 0x0e, 0x18, 0x47, 0x40, 0x44, 0xc1, 0x55, 0x24, + 0x5a, 0x35, 0xad, 0x59, 0xd2, 0xc6, 0xc3, 0x68, 0x58, 0xbd, 0x6f, 0xcf, + 0x5d, 0xb1, 0x9b, 0x0c, 0x92, 0x39, 0x22, 0x49, 0x66, 0x2e, 0x03, 0x7b, + 0x75, 0x5c, 0x6c, 0xde, 0x37, 0x54, 0xa9, 0x07, 0x2f, 0x7e, 0xc1, 0x3e, + 0x3b, 0xab, 0xd2, 0xa9, 0xfa, 0xc7, 0x6b, 0xd5, 0x14, 0x08, 0x35, 0x89, + 0x0b, 0x31, 0x18, 0x54, 0x7d, 0x6b, 0x53, 0x80, 0x6e, 0x32, 0x9b, 0xff, + 0x61, 0x7f, 0x36, 0xe5, 0x28, 0x40, 0xbc, 0xc7, 0x19, 0xb3, 0xae, 0xfa, + 0x95, 0xa8, 0xae, 0xd2, 0x97, 0x72, 0xc6, 0x91, 0x36, 0x3a, 0xa6, 0xec, + 0x4a, 0x41, 0x63, 0x6b, 0x28, 0xef, 0x5a, 0xa1, 0xdb, 0xf2, 0xd9, 0xfd, + 0x61, 0x72, 0xa4, 0xd2, 0x9e, 0xf7, 0x47, 0xf4, 0x4e, 0xea, 0x2a, 0xa5, + 0x35, 0xe1, 0x77, 0x3a, 0x53, 0x28, 0xa6, 0x55, 0x48, 0x0c, 0x1e, 0x44, + 0xfc, 0xc1, 0x31, 0x5a, 0x00, 0xcd, 0x29, 0xc1, 0x5c, 0xca, 0x2a, 0x07, + 0x01, 0x63, 0xac, 0xb3, 0xfb, 0xf6, 0x0b, 0xac, 0xfd, 0xe8, 0x7b, 0xed, + 0xf9, 0x3d, 0x9a, 0xbc, 0x67, 0x28, 0x1c, 0xd9, 0x3f, 0x97, 0x28, 0x4a, + 0xe7, 0xd0, 0x08, 0xe9, 0x3e, 0xa0, 0xcb, 0x0f, 0xe0, 0x3f, 0x1b, 0x80, + 0x43, 0x74, 0xd9, 0x9d, 0x0b, 0x22, 0x81, 0xf7, 0xec, 0x71, 0x2a, 0x29, + 0x9e, 0x5d, 0x1e, 0x8d, 0xf4, 0x22, 0x95, 0x78, 0x86, 0xcb, 0xf0, 0x9d, + 0xe7, 0x6a, 0x66, 0x7e, 0x28, 0xb5, 0x47, 0xb6, 0xdc, 0x0d, 0x03, 0x3c, + 0x09, 0x58, 0x76, 0x93, 0x39, 0xb2, 0xd3, 0x75, 0xb4, 0x51, 0x55, 0x84, + 0x30, 0x24, 0x0a, 0x76, 0xf4, 0x97, 0xe7, 0x0f, 0x5a, 0x67, 0xee, 0xf4, + 0xc7, 0x69, 0x8d, 0xf2, 0x32, 0x29, 0x5c, 0x33, 0x82, 0x5f, 0x6c, 0x47, + 0xd0, 0xe2, 0xbd, 0x62, 0xd6, 0x4c, 0x6d, 0x0d, 0xba, 0x87, 0xd3, 0x43, + 0x7e, 0x2d, 0xa6, 0x14, 0x09, 0x4f, 0x3b, 0xc3, 0x04, 0x14, 0xe5, 0x65, + 0xe9, 0x3b, 0x6a, 0xca, 0xb5, 0x96, 0x84, 0x3f, 0x53, 0x49, 0x22, 0x45, + 0x91, 0xff, 0xf9, 0x26, 0x75, 0x0d, 0x9c, 0xa7, 0x00, 0xf4, 0x65, 0xc4, + 0x60, 0x72, 0xab, 0xeb, 0xf8, 0xa8, 0x72, 0xfe, 0xd8, 0xde, 0x93, 0x67, + 0xcb, 0x09, 0xcc, 0xa0, 0xce, 0x9f, 0x67, 0x63, 0x26, 0xfa, 0x7f, 0x89, + 0xaa, 0x3e, 0x6d, 0xb2, 0x90, 0xd7, 0xef, 0x3e, 0x2a, 0x66, 0x26, 0x33, + 0xe6, 0x26, 0xc1, 0x58, 0xf8, 0x91, 0xea, 0x2f, 0xd0, 0x84, 0x21, 0x41, + 0x93, 0xa6, 0x36, 0x40, 0xb5, 0x4c, 0xac, 0x21, 0x88, 0x37, 0x47, 0x8a, + 0xb8, 0xf3, 0x33, 0x73, 0x12, 0xd7, 0x5a, 0x55, 0xf9, 0xd1, 0x1e, 0x75, + 0xa4, 0x66, 0x68, 0x3f, 0xf7, 0xb2, 0xc4, 0x5d, 0x1b, 0xb1, 0x61, 0x0f, + 0xaf, 0x4b, 0x9b, 0x20, 0x2b, 0x05, 0x68, 0x1c, 0x6c, 0x97, 0x8d, 0xb8, + 0x7b, 0x96, 0xda, 0xe0, 0x67, 0x15, 0x4c, 0x51, 0x71, 0x0d, 0xd3, 0x7b, + 0xde, 0xaa, 0xd3, 0x58, 0xf5, 0xc9, 0x62, 0x0a, 0xc2, 0x33, 0x1f, 0xf3, + 0xc3, 0x30, 0xb5, 0x64, 0xd1, 0x59, 0x41, 0x0e, 0xae, 0xaa, 0x0d, 0xdf, + 0x9f, 0x5d, 0x3f, 0x15, 0x0d, 0x46, 0x7a, 0x6d, 0x2e, 0x29, 0x1b, 0xc0, + 0xd3, 0x11, 0x10, 0x5d, 0xdc, 0x6a, 0x35, 0x8c, 0x43, 0xc8, 0x9f, 0x05, + 0x80, 0xdc, 0x25, 0x24, 0x37, 0x70, 0x7e, 0x1c, 0xe9, 0x85, 0x5a, 0xef, + 0x83, 0x3a, 0x55, 0x68, 0x83, 0x17, 0xf4, 0xc7, 0xae, 0xe4, 0x84, 0xc9, + 0x64, 0x5d, 0x2f, 0xb6, 0xca, 0x10, 0x95, 0xb8, 0xd6, 0x80, 0xfd, 0x05, + 0xa5, 0x06, 0x32, 0x34, 0x91, 0x01, 0xd2, 0x02, 0x90, 0xe1, 0xf7, 0x89, + 0x8a, 0xee, 0x18, 0x04, 0x93, 0xd9, 0xb4, 0x63, 0x4b, 0xf7, 0x7a, 0x9c, + 0x1b, 0x4b, 0xf9, 0x31, 0x32, 0xd9, 0xf2, 0x55, 0x4e, 0xc1, 0x02, 0xce, + 0x77, 0x38, 0x36, 0x29, 0xb8, 0x54, 0x8c, 0xc2, 0x27, 0x5f, 0xd9, 0xae, + 0x3e, 0x1e, 0xcd, 0xe9, 0x07, 0x90, 0x4c, 0xe0, 0xda, 0x16, 0x6e, 0xdf, + 0xde, 0x3a, 0x61, 0x89, 0x9f, 0x79, 0xd0, 0xd4, 0x66, 0x95, 0xad, 0xe4, + 0x11, 0x7d, 0xa1, 0xae, 0xec, 0x3e, 0x6e, 0x20, 0x5a, 0xd0, 0x28, 0x0e, + 0x55, 0xec, 0xcf, 0x34, 0xec, 0xb7, 0xfc, 0xa4, 0xb3, 0x8f, 0x56, 0x13, + 0x50, 0xcc, 0x15, 0x10, 0x74, 0x40, 0x72, 0x42, 0x20, 0x22, 0xb3, 0xaf, + 0xf3, 0x68, 0xba, 0x95, 0x45, 0xcb, 0xef, 0x92, 0xd5, 0x14, 0x4c, 0x1f, + 0xe3, 0xc1, 0xa6, 0x03, 0x4e, 0x05, 0xd2, 0x1a, 0xee, 0xd2, 0x48, 0x44, + 0x2e, 0x50, 0x3b, 0x86, 0xc8, 0x6a, 0xc8, 0x4c, 0xca, 0x2a, 0xb6, 0xf7, + 0x3c, 0xaf, 0xdc, 0x62, 0xb1, 0x49, 0x13, 0xfe, 0xe7, 0x32, 0xea, 0x78, + 0xfa, 0xba, 0xcf, 0x15, 0x47, 0x58, 0xdc, 0x19, 0x73, 0x1d, 0xff, 0xbd, + 0xcc, 0x27, 0xf6, 0xfc, 0x66, 0x68, 0xa7, 0x29, 0xaf, 0x2b, 0x25, 0x0c, + 0x15, 0x47, 0xff, 0xc1, 0x00, 0x9d, 0xfa, 0x58, 0x9c, 0xaa, 0xf9, 0xcc, + 0x4c, 0x51, 0x1d, 0xda, 0xf3, 0x3c, 0x10, 0xd0, 0x3b, 0x59, 0x30, 0x02, + 0x68, 0x29, 0x1c, 0xa7, 0x22, 0xea, 0x81, 0xd3, 0x29, 0x71, 0x39, 0xe8, + 0x72, 0x7f, 0x7d, 0x94, 0x0a, 0x64, 0x2c, 0xe6, 0x55, 0xfb, 0x90, 0x78, + 0x7e, 0x6c, 0x3e, 0xfe, 0x57, 0x14, 0x61, 0xef, 0xe2, 0x63, 0x57, 0x6c, + 0x13, 0x97, 0x27, 0x2b, 0x38, 0x44, 0xab, 0x74, 0x76, 0x11, 0xa6, 0x60, + 0xad, 0x8e, 0xad, 0xe5, 0xa5, 0xa1, 0x66, 0xc5, 0xe1, 0x4d, 0x27, 0xa0, + 0x79, 0x7a, 0x09, 0xe6, 0xf0, 0x28, 0x3f, 0xcb, 0xc6, 0xf8, 0x94, 0xc0, + 0xf1, 0x13, 0xbe, 0x62, 0x6a, 0x52, 0x75, 0x52, 0xd3, 0x82, 0x31, 0xbd, + 0x15, 0xf2, 0xe8, 0x2e, 0xb1, 0x62, 0x03, 0x1e, 0xe2, 0xb3, 0xec, 0xbc, + 0x3c, 0x12, 0xca, 0x62, 0x4e, 0xc2, 0x3a, 0x51, 0x1c, 0xdf, 0xa2, 0x84, + 0x88, 0xe5, 0x7e, 0xd7, 0x5d, 0xd7, 0xbf, 0xf2, 0x7d, 0xbd, 0x9a, 0x90, + 0x63, 0xfd, 0x8a, 0x84, 0x2b, 0x9d, 0x89, 0x27, 0x63, 0x4c, 0x0a, 0xe3, + 0x70, 0x94, 0x7b, 0xe6, 0xb3, 0xd7, 0xcb, 0xcb, 0x8a, 0xeb, 0x6b, 0x53, + 0x34, 0x2f, 0x62, 0x44, 0x2d, 0x73, 0x63, 0x8a, 0xf4, 0xa2, 0x01, 0xd7, + 0x12, 0xb6, 0x8d, 0x8c, 0x4b, 0x73, 0x2b, 0x44, 0x50, 0x49, 0x6f, 0x01, + 0xac, 0xc5, 0x15, 0x37, 0x6c, 0xde, 0xd4, 0x02, 0xb1, 0x12, 0x80, 0x73, + 0xb2, 0x52, 0x0e, 0xe0, 0xb5, 0x75, 0xc9, 0x48, 0xcf, 0x18, 0x5c, 0xcc, + 0xaf, 0x58, 0xa2, 0x3e, 0x28, 0xe4, 0xab, 0xde, 0xea, 0x2a, 0xcf, 0x58, + 0x22, 0xc4, 0x68, 0xea, 0x9b, 0x7b, 0x90, 0xc5, 0xdc, 0x1c, 0x37, 0xd1, + 0x8a, 0x4f, 0xe7, 0x24, 0x23, 0x39, 0xb9, 0x62, 0xb8, 0x41, 0x13, 0x7b, + 0xe2, 0x1e, 0x0d, 0x4e, 0x38, 0x11, 0xa3, 0xb9, 0x10, 0xbb, 0x10, 0x6f, + 0x40, 0x9f, 0x50, 0x05, 0xc7, 0x0e, 0xb9, 0x9e, 0xab, 0x7c, 0x3c, 0x78, + 0xce, 0x54, 0xbf, 0xbf, 0x40, 0x36, 0x76, 0xbc, 0x4b, 0x64, 0x32, 0xca, + 0x0e, 0x2d, 0x91, 0x87, 0xd5, 0x00, 0x19, 0xbf, 0x12, 0xd0, 0x35, 0x7c, + 0xa1, 0xe5, 0xcf, 0x7a, 0x2d, 0x08, 0x62, 0xed, 0x34, 0x61, 0xe3, 0xda, + 0x2c, 0xcc, 0x1b, 0xf8, 0x12, 0xfe, 0xfd, 0x19, 0xa2, 0xc3, 0x70, 0xfd, + 0x4f, 0x5b, 0x5d, 0x20, 0xd2, 0xe1, 0xc5, 0xac, 0xe7, 0xa1, 0x84, 0x00, + 0xbd, 0x46, 0x81, 0xfd, 0x54, 0x69, 0xed, 0x1a, 0x7a, 0x32, 0xbb, 0x75, + 0x22, 0x76, 0x6d, 0x34, 0x24, 0xcc, 0xe6, 0xbe, 0x78, 0x5a, 0x75, 0x6c, + 0xbc, 0x62, 0xb8, 0x14, 0xf7, 0x13, 0x73, 0xc2, 0xdc, 0xb6, 0xfa, 0xfb, + 0x97, 0xfe, 0x27, 0x7b, 0x33, 0xb8, 0xeb, 0x20, 0xd2, 0x0f, 0x4f, 0xed, + 0xd1, 0xd0, 0x63, 0xf7, 0xc5, 0x8e, 0xec, 0xcc, 0xd2, 0x31, 0x38, 0x35, + 0x65, 0x33, 0x5c, 0x63, 0x85, 0xf7, 0x3d, 0xc3, 0x62, 0x26, 0x52, 0x0a, + 0x67, 0xda, 0x87, 0x1f, 0x9e, 0x47, 0xec, 0x6b, 0xf5, 0x74, 0x1a, 0xc5, + 0xa7, 0xa0, 0x0f, 0xdd, 0xc5, 0x42, 0xf4, 0xda, 0x41, 0x1a, 0x48, 0xa9, + 0xbe, 0x4f, 0xb6, 0x28, 0x17, 0xe9, 0xf5, 0xd7, 0x00, 0xb3, 0xfe, 0x05, + 0x4e, 0xa7, 0xdf, 0x65, 0x7a, 0xb8, 0x4f, 0xe0, 0xfe, 0x58, 0x9e, 0xba, + 0x45, 0x11, 0xba, 0xc2, 0xdb, 0x97, 0x97, 0xa4, 0xbc, 0x18, 0x21, 0x1b, + 0xad, 0x82, 0xef, 0xb1, 0x5f, 0x2f, 0x25, 0x9d, 0xca, 0x52, 0xa5, 0x6d, + 0x8c, 0xab, 0x07, 0x2b, 0x7b, 0x6a, 0x77, 0x9d, 0xdf, 0xfb, 0xae, 0x6e, + 0x49, 0x18, 0x25, 0x4a, 0xf2, 0x7d, 0xa0, 0x32, 0xc8, 0x53, 0x10, 0xc3, + 0xf2, 0xef, 0xf3, 0xe7, 0x79, 0xd7, 0x6a, 0x0e, 0x61, 0xff, 0x89, 0xc9, + 0x42, 0xe8, 0x6e, 0x4f, 0x78, 0xe1, 0x5f, 0xcd, 0x7a, 0xf6, 0x27, 0x72, + 0x67, 0xea, 0x0b, 0xa6, 0xcc, 0x34, 0xb7, 0x8f, 0x92, 0x3c, 0x95, 0xb9, + 0x0a, 0x5d, 0x49, 0x2e, 0xb7, 0x7d, 0x31, 0x9c, 0x79, 0x61, 0x95, 0x9c, + 0x60, 0x56, 0x8d, 0x35, 0x00, 0xc5, 0x8b, 0xe6, 0x02, 0x0f, 0x26, 0x39, + 0x7b, 0x93, 0x94, 0xb1, 0xcd, 0xde, 0xed, 0xfa, 0x2a, 0x4b, 0x63, 0xa8, + 0x1b, 0x31, 0x43, 0x5e, 0x69, 0x7c, 0xd6, 0x15, 0x35, 0x9c, 0xa2, 0xd7, + 0xdf, 0x0e, 0x1a, 0x20, 0x50, 0xf5, 0x02, 0x21, 0x30, 0x35, 0x3c, 0x60, + 0x71, 0xad, 0xd0, 0xe3, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x10, 0x17, 0x1d, 0x22, 0x2d}; +#elif MLD_CONFIG_PARAMETER_SET == 87 +const uint8_t expected_signature[] = { + 0xdf, 0xe6, 0xe1, 0xa5, 0x20, 0xc1, 0xac, 0x98, 0x55, 0x2c, 0xf2, 0x13, + 0x65, 0x42, 0xe2, 0xb0, 0x77, 0x5f, 0x15, 0x00, 0x8f, 0x14, 0x48, 0xa1, + 0xe3, 0xee, 0x81, 0x35, 0x15, 0x34, 0xad, 0x6e, 0x60, 0x85, 0x00, 0xf8, + 0x18, 0x53, 0x0d, 0xa0, 0xc5, 0x41, 0xc4, 0x48, 0x09, 0x1b, 0x34, 0x0c, + 0x0e, 0xcf, 0xc6, 0x3d, 0x38, 0x78, 0x8b, 0x69, 0xe5, 0x6f, 0x4d, 0x43, + 0xfa, 0xa6, 0x75, 0x26, 0x8a, 0x75, 0x97, 0x10, 0x6a, 0x1f, 0x3c, 0xa6, + 0x94, 0xa9, 0x93, 0x8f, 0xe5, 0x62, 0xbf, 0x94, 0xe4, 0xd0, 0x0d, 0x11, + 0x4d, 0x03, 0xe2, 0xd8, 0xdf, 0x68, 0xb7, 0x87, 0x62, 0xc9, 0xdc, 0xc9, + 0x36, 0x4f, 0xcc, 0xd1, 0xa4, 0xae, 0x7e, 0xa4, 0xb9, 0xaf, 0xaf, 0xf0, + 0x8a, 0xe6, 0xff, 0x83, 0xe7, 0x54, 0x22, 0x6e, 0x3f, 0x2e, 0xa0, 0x4f, + 0xa8, 0x31, 0x53, 0xf3, 0x62, 0xeb, 0x04, 0xfa, 0xd1, 0x57, 0x39, 0x43, + 0xf9, 0xe0, 0x31, 0x12, 0x45, 0x09, 0x8b, 0x9e, 0x1e, 0x7a, 0x2b, 0x85, + 0xee, 0xdd, 0xe8, 0x1e, 0xd7, 0xc0, 0x17, 0xb4, 0xd2, 0xdc, 0x36, 0xa9, + 0xe4, 0x49, 0x88, 0xbf, 0x71, 0x43, 0x9d, 0x3e, 0xd2, 0x10, 0xe7, 0x82, + 0xb5, 0xfe, 0xdd, 0x42, 0xc8, 0x1b, 0x11, 0xf6, 0x52, 0x23, 0x98, 0x83, + 0x48, 0xec, 0xec, 0x70, 0x8b, 0xe7, 0x49, 0x9a, 0xd7, 0xd9, 0x7b, 0x47, + 0x4e, 0xe2, 0x5e, 0x17, 0x1a, 0xa0, 0x0e, 0x60, 0x85, 0x3a, 0x30, 0x8c, + 0x1c, 0x26, 0xb4, 0xe1, 0xb5, 0x2b, 0x48, 0xf4, 0xb8, 0x93, 0x2f, 0x79, + 0x3a, 0x1e, 0xb6, 0x3b, 0x07, 0x3b, 0x1e, 0x15, 0xd7, 0x85, 0x5e, 0xd4, + 0x06, 0x0e, 0xcd, 0x6a, 0x93, 0x3a, 0x93, 0x29, 0x6a, 0xbe, 0x68, 0x8a, + 0xb6, 0xb8, 0xfa, 0xc5, 0x63, 0x48, 0x98, 0x10, 0x6d, 0xd9, 0xd3, 0x5b, + 0x29, 0x5f, 0x93, 0x90, 0x08, 0x1c, 0x1a, 0x15, 0x7b, 0x0a, 0x59, 0x9d, + 0x64, 0x24, 0x45, 0xb6, 0xd3, 0x7b, 0xc1, 0x5d, 0x74, 0x1f, 0x0b, 0x8e, + 0x18, 0xf2, 0x92, 0x8e, 0xd4, 0x7f, 0x72, 0x5c, 0x98, 0x1f, 0x8b, 0xa5, + 0xb8, 0xf4, 0x7e, 0x12, 0x6a, 0x93, 0xb9, 0xb5, 0xf1, 0xda, 0x97, 0x75, + 0x4f, 0x56, 0x80, 0x88, 0x64, 0x2b, 0xe0, 0x59, 0xcd, 0x5e, 0x91, 0x64, + 0x9c, 0x0c, 0xa8, 0xdd, 0xac, 0xcb, 0xf3, 0x48, 0x3b, 0x5c, 0xc4, 0xc5, + 0xb9, 0x9a, 0x0b, 0x8e, 0x5d, 0x9a, 0xd5, 0xb7, 0xf0, 0xd4, 0x07, 0x48, + 0xb9, 0x63, 0x02, 0x87, 0x8d, 0xae, 0x7e, 0x03, 0x33, 0x4f, 0x86, 0x15, + 0x1b, 0x3b, 0xdf, 0xda, 0xce, 0xd3, 0x1e, 0xc0, 0x76, 0xb5, 0x1c, 0xdd, + 0xb8, 0x32, 0x87, 0x7d, 0x59, 0x18, 0x72, 0x0c, 0xde, 0x8f, 0x63, 0x2d, + 0x38, 0xf2, 0xe9, 0xc2, 0x81, 0xed, 0xfa, 0x2d, 0x61, 0xef, 0x48, 0xdb, + 0xa2, 0xeb, 0xfe, 0x52, 0x31, 0x1e, 0x21, 0x0a, 0x08, 0xf6, 0x02, 0xd3, + 0xc0, 0x32, 0x3b, 0x6b, 0x2f, 0x64, 0xc4, 0xb3, 0x4b, 0xfe, 0x69, 0x78, + 0xbf, 0x20, 0x62, 0x07, 0x77, 0xdf, 0x2c, 0x18, 0x53, 0x61, 0x8e, 0x05, + 0x01, 0x86, 0xab, 0xab, 0xec, 0x18, 0x8c, 0x15, 0x63, 0x1f, 0xe9, 0x99, + 0xb2, 0x35, 0x77, 0xe1, 0x58, 0xf1, 0xa9, 0x4d, 0x1a, 0xb9, 0x8c, 0x30, + 0x63, 0x6f, 0x9e, 0x7d, 0x4e, 0xcf, 0xb5, 0x6c, 0xf3, 0xe4, 0xdc, 0xab, + 0xf9, 0xae, 0x58, 0xf8, 0x1d, 0x08, 0x7b, 0x73, 0x82, 0x58, 0xc8, 0x67, + 0x48, 0x1a, 0x5e, 0x3d, 0xdb, 0xac, 0x1b, 0x1b, 0xef, 0xeb, 0xa4, 0xe5, + 0x67, 0x48, 0x76, 0xd1, 0x96, 0x4f, 0x6c, 0x7d, 0x06, 0x8c, 0x02, 0x86, + 0x95, 0x83, 0xb6, 0x9b, 0x5e, 0x9a, 0xb5, 0x85, 0xc0, 0x4f, 0x13, 0x1c, + 0x32, 0xf8, 0x29, 0xdf, 0x47, 0x85, 0xdb, 0xe4, 0x37, 0xdc, 0xd8, 0x04, + 0x18, 0xdd, 0xca, 0x97, 0xdd, 0x67, 0x13, 0xbe, 0x74, 0x95, 0xdc, 0xd0, + 0xcc, 0xe6, 0xb5, 0xa5, 0x12, 0x9b, 0x23, 0x4f, 0x41, 0x8c, 0xcc, 0x95, + 0xf4, 0xb0, 0x5f, 0x2a, 0xc4, 0xbf, 0x88, 0xda, 0x55, 0xcb, 0x13, 0x93, + 0x22, 0x60, 0x51, 0x43, 0xc7, 0x9a, 0x2c, 0xfa, 0xb2, 0x59, 0xc1, 0xe6, + 0x8a, 0xa4, 0xb8, 0xfb, 0xd3, 0x31, 0x1d, 0xc7, 0x88, 0xdc, 0xbc, 0xe9, + 0xba, 0xe7, 0xdc, 0xe3, 0xdd, 0x90, 0x96, 0xb4, 0xb4, 0x0a, 0xc1, 0x07, + 0x31, 0x3f, 0xdb, 0xc5, 0x4d, 0x73, 0x58, 0x86, 0x15, 0x37, 0x07, 0x86, + 0x03, 0x17, 0x16, 0x18, 0x15, 0xb9, 0x26, 0x35, 0x8a, 0x43, 0x22, 0xae, + 0x21, 0x52, 0x05, 0x4e, 0x5c, 0x3f, 0x3e, 0xb9, 0x2a, 0x19, 0x13, 0xfd, + 0x31, 0x47, 0x6a, 0x74, 0xaa, 0xb9, 0xc6, 0x2c, 0x13, 0x8c, 0x21, 0xc4, + 0x8d, 0x00, 0xf4, 0x24, 0xf2, 0xb7, 0xd3, 0x13, 0xad, 0x29, 0x5e, 0x50, + 0x0b, 0x0e, 0x9f, 0x9a, 0xb7, 0xf6, 0x9e, 0xba, 0x12, 0x23, 0x84, 0x8c, + 0xbe, 0x2c, 0x14, 0x1e, 0xe6, 0x79, 0x15, 0x20, 0x2d, 0x32, 0x08, 0xd8, + 0x1c, 0x87, 0x1b, 0xa8, 0xc0, 0xbb, 0x85, 0xa9, 0x71, 0x30, 0x5e, 0x39, + 0x48, 0x87, 0xdc, 0x3d, 0x03, 0x29, 0x19, 0xd1, 0xd4, 0x21, 0x3a, 0x53, + 0x2d, 0x5e, 0x78, 0xff, 0x94, 0x4b, 0x91, 0xa6, 0xb5, 0xe5, 0x42, 0x56, + 0x67, 0x6a, 0x0e, 0xf3, 0x2d, 0x6a, 0x4e, 0xd7, 0x3a, 0x81, 0xb1, 0x4d, + 0x0b, 0x66, 0x5f, 0x43, 0x28, 0x7c, 0x75, 0x8b, 0x2b, 0x99, 0x24, 0xc2, + 0x5e, 0x8c, 0x22, 0xf0, 0xd5, 0xb3, 0xfc, 0x86, 0x62, 0xf3, 0xd2, 0x6c, + 0xa7, 0x48, 0x04, 0x44, 0x5d, 0x93, 0x74, 0x37, 0x16, 0x2c, 0x19, 0x12, + 0x57, 0x49, 0xef, 0xd5, 0xd6, 0x92, 0xdc, 0x51, 0xf8, 0x55, 0x3a, 0xc0, + 0x0b, 0xdf, 0x41, 0xb5, 0x01, 0x59, 0x7e, 0x85, 0x65, 0xdb, 0x44, 0xbd, + 0x04, 0x96, 0x1a, 0xd4, 0x6e, 0x22, 0x54, 0x92, 0xdb, 0xc7, 0xc5, 0x3a, + 0xdf, 0x0c, 0xf4, 0x1b, 0xdc, 0x14, 0xf6, 0x91, 0x9c, 0xbe, 0xf8, 0x8e, + 0x70, 0xd1, 0x3a, 0x0e, 0x58, 0xe6, 0xb9, 0xd3, 0xaa, 0xa2, 0x70, 0xba, + 0xdd, 0x16, 0x13, 0x19, 0xd1, 0x96, 0x78, 0x04, 0x2f, 0xd7, 0x38, 0x8c, + 0x35, 0x1f, 0xfc, 0x58, 0xa4, 0x4c, 0xa9, 0x9a, 0xae, 0x13, 0x3b, 0xc1, + 0x20, 0x4b, 0x66, 0x0f, 0x72, 0x42, 0x0a, 0x53, 0x84, 0x54, 0x71, 0x06, + 0xdb, 0x85, 0x8f, 0x40, 0xa6, 0x09, 0xf7, 0x24, 0xc4, 0x35, 0xf7, 0x1d, + 0xd4, 0x3d, 0x54, 0x75, 0xaf, 0xc4, 0x78, 0x0f, 0xce, 0xe0, 0x0c, 0x90, + 0x0f, 0xd5, 0x2e, 0x61, 0xf7, 0x58, 0xaa, 0xf0, 0xc7, 0x37, 0x5a, 0x59, + 0x1f, 0x8a, 0x03, 0x98, 0x43, 0xb7, 0x27, 0x78, 0x4e, 0x44, 0x5a, 0xb5, + 0x29, 0xf5, 0xab, 0x9e, 0xb7, 0x2a, 0xc4, 0xa3, 0x03, 0x00, 0xe3, 0x28, + 0x57, 0xc9, 0x2a, 0x98, 0xb8, 0xa1, 0x45, 0x1d, 0xfa, 0x6e, 0xb3, 0x0d, + 0x42, 0x5a, 0xb6, 0xb1, 0x0e, 0x5c, 0xbe, 0x82, 0xe2, 0x36, 0x40, 0x4b, + 0x05, 0x28, 0xd9, 0xbc, 0x27, 0xd6, 0x77, 0x00, 0xc9, 0x29, 0x6a, 0xd6, + 0x19, 0x8f, 0x8d, 0xda, 0xe1, 0xc3, 0x8b, 0x69, 0x71, 0xd0, 0xf7, 0xc8, + 0x33, 0xef, 0xe6, 0x23, 0x6b, 0xcb, 0x00, 0x56, 0x0a, 0x9b, 0x9d, 0x60, + 0x3a, 0xd3, 0xad, 0xd9, 0x5c, 0x6a, 0x7d, 0xab, 0x35, 0x71, 0x93, 0xc5, + 0xf2, 0x6a, 0x38, 0x0e, 0xfb, 0xd9, 0x9b, 0xa5, 0xda, 0x52, 0x45, 0xef, + 0x93, 0x94, 0x5b, 0x08, 0x8c, 0x07, 0xab, 0x2e, 0x99, 0x88, 0x77, 0xb5, + 0x15, 0x66, 0x7f, 0x0e, 0xfa, 0xb0, 0x29, 0xe4, 0x88, 0xd9, 0xdd, 0x22, + 0xaf, 0x7a, 0x4e, 0xb5, 0xd0, 0x62, 0x85, 0x27, 0x33, 0xf1, 0xb7, 0x34, + 0xb1, 0xe6, 0xda, 0x9f, 0x3c, 0xfe, 0xf5, 0xd4, 0xef, 0x56, 0x48, 0x93, + 0x7a, 0x54, 0xa2, 0x7f, 0x07, 0xea, 0x31, 0xb8, 0x8b, 0xca, 0xb9, 0xdb, + 0x1e, 0x2b, 0xb5, 0x16, 0xe6, 0x0e, 0xd9, 0x3f, 0x7c, 0xf0, 0xc2, 0x3e, + 0x57, 0x64, 0x60, 0x97, 0xfb, 0xdf, 0x8c, 0x3e, 0x56, 0x22, 0x92, 0x2a, + 0xb2, 0x21, 0x00, 0x0a, 0x75, 0x89, 0x68, 0xe7, 0x51, 0xa3, 0x63, 0x05, + 0xe1, 0x6f, 0x1e, 0x1e, 0x80, 0xa2, 0x4b, 0x5d, 0xb7, 0xf4, 0xb7, 0x45, + 0x85, 0x00, 0x84, 0x6e, 0xbe, 0x0b, 0x67, 0xbf, 0x21, 0x06, 0x5a, 0x56, + 0x79, 0xe9, 0x6b, 0x0e, 0x72, 0x19, 0x2d, 0x09, 0x78, 0xd5, 0x5e, 0xc2, + 0x32, 0xee, 0x29, 0xd4, 0x7a, 0x65, 0xc7, 0xfe, 0x16, 0x86, 0xd2, 0x29, + 0x71, 0xe5, 0x91, 0x0e, 0x3e, 0x86, 0xd5, 0x00, 0xc4, 0xfc, 0xd9, 0xae, + 0xd3, 0x7c, 0x13, 0xfd, 0x62, 0xce, 0x0c, 0xb2, 0xe5, 0x1f, 0x6d, 0xed, + 0x55, 0x6f, 0xc1, 0xaa, 0xa1, 0x74, 0x59, 0x46, 0x83, 0xd5, 0x5d, 0x71, + 0x17, 0x13, 0x1d, 0x0b, 0x25, 0xfb, 0x0a, 0xcd, 0x67, 0xfe, 0x57, 0x93, + 0xc2, 0x71, 0x55, 0x6c, 0x68, 0xfa, 0x40, 0xdb, 0xdd, 0xce, 0xd5, 0x5c, + 0xce, 0x0a, 0x1d, 0xfa, 0x19, 0x30, 0xe2, 0x2b, 0x63, 0x98, 0x16, 0x2c, + 0x67, 0x69, 0x55, 0xe5, 0xc1, 0x6c, 0x6e, 0xb7, 0x92, 0x6a, 0xbb, 0x10, + 0xd3, 0x13, 0x2e, 0x73, 0x91, 0x74, 0xcb, 0x9f, 0x5c, 0x7f, 0x5c, 0x48, + 0x58, 0x36, 0x13, 0x47, 0xf7, 0x49, 0xae, 0x90, 0x15, 0x53, 0xb5, 0xe6, + 0x37, 0xfb, 0x81, 0x47, 0xb4, 0x69, 0x84, 0xca, 0x95, 0xab, 0x19, 0x2a, + 0x28, 0xc2, 0x8a, 0xf1, 0xcd, 0xf9, 0x3e, 0xd3, 0xaf, 0xe1, 0x75, 0xf7, + 0x94, 0x74, 0x1c, 0xf5, 0x32, 0xcf, 0x70, 0xbd, 0x69, 0xcc, 0xa8, 0x3c, + 0xca, 0x59, 0x53, 0xfa, 0xcb, 0xe7, 0xb6, 0x36, 0x70, 0xea, 0xe2, 0x84, + 0xfa, 0x5e, 0xbd, 0xd7, 0x59, 0x3d, 0x21, 0xc6, 0x9f, 0x5c, 0x1f, 0xa6, + 0xa9, 0xf1, 0xd3, 0x26, 0x9e, 0xff, 0xbc, 0x81, 0xfe, 0xbe, 0xee, 0x64, + 0xd9, 0x63, 0x94, 0x4b, 0x15, 0xd8, 0x95, 0xaa, 0xec, 0x10, 0xc9, 0xe2, + 0xe1, 0x05, 0x37, 0x64, 0xc4, 0xb0, 0x2e, 0xa5, 0x0e, 0x4c, 0x2d, 0x03, + 0x53, 0xf1, 0x93, 0x77, 0x9d, 0x46, 0x14, 0x67, 0x48, 0x5f, 0xad, 0x1b, + 0xdc, 0xb9, 0x74, 0xa2, 0x6c, 0xfc, 0xd2, 0xa0, 0x1f, 0x43, 0x89, 0x15, + 0xc5, 0x0c, 0xb0, 0x9e, 0x1e, 0xc2, 0xd6, 0x44, 0xd9, 0x6e, 0xfc, 0xb4, + 0x9c, 0x95, 0x90, 0xcd, 0xc3, 0x17, 0x1c, 0x6a, 0xce, 0x03, 0x56, 0x9f, + 0xe7, 0xcd, 0x7e, 0xe7, 0xa2, 0x0c, 0x2b, 0x0d, 0x59, 0xb0, 0xc9, 0x4c, + 0x6e, 0x33, 0x6d, 0x43, 0xc4, 0x3a, 0x10, 0x24, 0x03, 0x3e, 0x09, 0xb6, + 0x86, 0x13, 0xba, 0x18, 0x19, 0xd3, 0xff, 0xeb, 0xa5, 0x25, 0x8f, 0x6f, + 0xc8, 0xe6, 0x96, 0xa4, 0xd2, 0x66, 0x40, 0x81, 0x79, 0xe8, 0x39, 0x18, + 0x41, 0x02, 0x66, 0x5c, 0x30, 0x5f, 0x58, 0x9d, 0x35, 0x16, 0xc6, 0x96, + 0xa8, 0x68, 0xbc, 0x09, 0x83, 0x17, 0x2c, 0x5f, 0x5e, 0xd0, 0x1d, 0xb0, + 0x48, 0x5e, 0xcf, 0x91, 0x16, 0x4d, 0xa0, 0xba, 0xbc, 0x61, 0xa8, 0x3f, + 0x30, 0x09, 0xbb, 0xa3, 0x12, 0xcd, 0xdc, 0x29, 0xf7, 0xb0, 0xad, 0x05, + 0x17, 0xd6, 0xd3, 0x16, 0xfb, 0xe5, 0x99, 0xf4, 0x71, 0x62, 0xa3, 0x45, + 0x45, 0xc7, 0x9b, 0xaa, 0x45, 0xd3, 0x35, 0xfe, 0xfb, 0x63, 0xaf, 0xe7, + 0x85, 0x31, 0xc9, 0x66, 0x26, 0xa9, 0xda, 0x8c, 0xc6, 0xf6, 0xd5, 0xdf, + 0xb1, 0xa9, 0xf1, 0xb6, 0x3d, 0x92, 0xae, 0x4d, 0xbc, 0x74, 0x7d, 0x76, + 0x5a, 0x59, 0x8c, 0x87, 0xff, 0x95, 0x2f, 0x67, 0x37, 0x30, 0x1a, 0xc1, + 0x23, 0x2e, 0x0c, 0xaa, 0x80, 0x1c, 0xf3, 0xa3, 0x74, 0x94, 0xb2, 0xda, + 0x1a, 0xb8, 0x46, 0xec, 0x30, 0x76, 0xf4, 0xdf, 0xfb, 0x00, 0xb3, 0x6f, + 0x86, 0xc1, 0xc5, 0x3a, 0x5d, 0x11, 0x14, 0x87, 0xeb, 0x30, 0xd8, 0x33, + 0x18, 0x00, 0x01, 0x76, 0x43, 0x82, 0xcd, 0x1c, 0x36, 0x54, 0xd2, 0x64, + 0x5b, 0xfb, 0x93, 0xca, 0x20, 0x1d, 0xa3, 0x20, 0x99, 0xc3, 0x8e, 0x5c, + 0x82, 0xfc, 0x56, 0x07, 0x41, 0x4b, 0x4f, 0x54, 0xc7, 0xb5, 0xe8, 0x6d, + 0x7e, 0xd8, 0x8a, 0x56, 0xb4, 0x76, 0x1e, 0xd3, 0x82, 0x97, 0xdd, 0x2b, + 0xd9, 0x80, 0xb7, 0xb6, 0xeb, 0x3d, 0xe5, 0xe0, 0x20, 0x27, 0x8c, 0xf0, + 0xd6, 0x14, 0xc7, 0xcd, 0x79, 0xbc, 0xa0, 0x21, 0x85, 0xc3, 0x02, 0xae, + 0x73, 0xc4, 0x0a, 0x39, 0x1a, 0x98, 0x61, 0xc3, 0x86, 0xd8, 0x97, 0x67, + 0x87, 0xe9, 0x56, 0x0b, 0x61, 0xa6, 0x7e, 0x07, 0xfb, 0x0a, 0x8b, 0xd1, + 0x90, 0xbd, 0x39, 0x22, 0xdb, 0xc2, 0x7f, 0xaa, 0x79, 0xb7, 0x39, 0x09, + 0xc1, 0x69, 0xdb, 0xe2, 0x7f, 0xec, 0xde, 0x80, 0x7a, 0x6c, 0xde, 0x76, + 0xa4, 0xe8, 0xe0, 0x8d, 0x71, 0xfa, 0x62, 0xf0, 0x2e, 0x7b, 0xf4, 0xce, + 0x65, 0x18, 0x42, 0xde, 0x92, 0x1b, 0xdc, 0xc9, 0xa7, 0x8d, 0xa5, 0x91, + 0x0f, 0xa5, 0x1b, 0x89, 0xcf, 0x29, 0x10, 0x1d, 0x94, 0x78, 0x1b, 0xea, + 0x79, 0x35, 0x62, 0xd4, 0x29, 0xe6, 0x59, 0x8c, 0xc1, 0xd2, 0xf3, 0x32, + 0x71, 0x09, 0xce, 0x51, 0xd7, 0x14, 0x29, 0x92, 0xbf, 0xdf, 0x9a, 0x69, + 0xda, 0x61, 0x03, 0x0f, 0xa2, 0x0a, 0xab, 0x57, 0x1c, 0xca, 0xab, 0x42, + 0x63, 0x63, 0x1e, 0x35, 0x5d, 0x8d, 0xba, 0x6f, 0x4b, 0x6b, 0x5e, 0x7c, + 0xc0, 0x1e, 0xb7, 0xf4, 0x65, 0xbd, 0x13, 0x1c, 0xf2, 0xa9, 0x73, 0x38, + 0xc3, 0x47, 0xc9, 0x32, 0xf0, 0x30, 0x57, 0x05, 0x42, 0x52, 0xac, 0x72, + 0xee, 0x9f, 0x4e, 0x21, 0xbf, 0x38, 0x19, 0x6d, 0x48, 0xec, 0x97, 0xcb, + 0x70, 0x9e, 0xee, 0xb3, 0xa1, 0xaa, 0xa6, 0x7e, 0xe9, 0x16, 0xdf, 0xcd, + 0x1c, 0x56, 0xcf, 0xf0, 0x9f, 0x4d, 0xd1, 0x8c, 0x14, 0x50, 0x5d, 0x23, + 0x96, 0xe0, 0x1f, 0x61, 0x79, 0xbf, 0x44, 0xfd, 0xa2, 0x31, 0xf7, 0x4c, + 0x0c, 0x8d, 0x8c, 0x1b, 0xbf, 0x8d, 0x45, 0xbf, 0x0b, 0xd8, 0xfb, 0x6f, + 0xff, 0x15, 0xc0, 0x44, 0x7c, 0xb9, 0xb8, 0xf9, 0xef, 0x0d, 0x79, 0x11, + 0x3b, 0x79, 0xd2, 0x52, 0x89, 0x5a, 0xcd, 0x0f, 0x10, 0x92, 0x42, 0xfe, + 0xcf, 0x0a, 0x11, 0x8a, 0x8a, 0xda, 0xee, 0xc8, 0x6b, 0xd9, 0xab, 0xec, + 0xb4, 0x25, 0x6f, 0x8d, 0x68, 0x26, 0xe8, 0xdd, 0xf5, 0xa4, 0xe8, 0x65, + 0x37, 0x03, 0xb0, 0xad, 0x73, 0x3b, 0x4d, 0x74, 0x57, 0x7f, 0x0f, 0x6c, + 0xb0, 0x5d, 0x59, 0x80, 0x13, 0xa1, 0x6c, 0xb0, 0xed, 0x26, 0xec, 0x79, + 0x50, 0x5f, 0x5c, 0xb7, 0xa6, 0xae, 0xe8, 0x0a, 0x6d, 0x55, 0x9a, 0x7f, + 0x59, 0x23, 0xa3, 0x7e, 0x84, 0x7b, 0x3b, 0xfc, 0xde, 0xe1, 0xd9, 0x7c, + 0xd6, 0x87, 0xb3, 0x0e, 0xdb, 0xc1, 0x8c, 0x5e, 0x77, 0xb7, 0x23, 0xd7, + 0x14, 0xd4, 0x23, 0xb4, 0xac, 0x45, 0xbf, 0xfe, 0x40, 0x20, 0x4d, 0x91, + 0x20, 0x94, 0xbd, 0x58, 0xb1, 0x99, 0x69, 0xaf, 0x31, 0x68, 0xbd, 0x61, + 0x5e, 0x87, 0x81, 0x54, 0x4e, 0x2d, 0x03, 0xc2, 0xe2, 0xcd, 0xdc, 0x59, + 0xe5, 0x35, 0xcf, 0xb8, 0xfc, 0x65, 0xed, 0x46, 0xb3, 0x92, 0xe7, 0xf8, + 0x3a, 0x32, 0xaa, 0x0e, 0x5a, 0x82, 0x58, 0x4e, 0x77, 0xd8, 0x33, 0xc9, + 0xb0, 0x3e, 0xad, 0xa5, 0x92, 0xe9, 0xa9, 0x8c, 0x00, 0x72, 0x8f, 0xdc, + 0x77, 0x9d, 0x5c, 0x97, 0xd6, 0x58, 0x20, 0x1e, 0xf4, 0x55, 0x2d, 0xc0, + 0x30, 0xf0, 0x66, 0xda, 0x2d, 0x11, 0xac, 0xd4, 0x2d, 0xd5, 0x25, 0x42, + 0x1d, 0xce, 0x49, 0xb5, 0x95, 0x79, 0x9b, 0x6c, 0x65, 0xe0, 0x8a, 0xc5, + 0x9f, 0x75, 0xe3, 0xe6, 0xf8, 0xa6, 0x88, 0xd6, 0x93, 0x70, 0x4f, 0x89, + 0x94, 0x74, 0xbd, 0xef, 0xc2, 0x1a, 0x55, 0x74, 0x37, 0x44, 0x85, 0x1e, + 0xa9, 0xbb, 0x3f, 0x15, 0xc7, 0x84, 0x80, 0xa5, 0xab, 0xc3, 0x91, 0x8e, + 0xd6, 0x32, 0x46, 0x0d, 0xfa, 0xd1, 0x19, 0xd1, 0xfc, 0x02, 0xe2, 0x20, + 0xa6, 0xa9, 0xf7, 0xf4, 0xcc, 0x5b, 0x54, 0x4f, 0x4a, 0x73, 0x35, 0xda, + 0xf0, 0x31, 0x81, 0x1a, 0x82, 0xe7, 0xd4, 0xc8, 0xb4, 0x1d, 0x70, 0xa9, + 0x5d, 0x67, 0xb9, 0x7d, 0x4b, 0xcd, 0xa4, 0x81, 0xf9, 0xb2, 0x38, 0x07, + 0x16, 0xd5, 0x28, 0x82, 0xb9, 0x76, 0x5b, 0xa1, 0x09, 0x7a, 0xe7, 0x2a, + 0xcf, 0xc0, 0x3d, 0x2a, 0x42, 0x9a, 0xf3, 0xc8, 0x64, 0x15, 0x7c, 0x94, + 0xd0, 0x97, 0xee, 0x34, 0xb6, 0xf0, 0xb2, 0xba, 0x7e, 0xb2, 0xbb, 0x4e, + 0xbf, 0x88, 0xd0, 0x6b, 0xc5, 0x9c, 0xb9, 0xf2, 0x7d, 0xbf, 0x5d, 0x87, + 0xbc, 0x36, 0x4a, 0xd1, 0x1b, 0x6f, 0x40, 0x09, 0xba, 0x26, 0x51, 0xd6, + 0xc0, 0xaf, 0x27, 0xce, 0x27, 0x8d, 0x93, 0xa8, 0x6c, 0x91, 0xe7, 0x91, + 0x42, 0xc0, 0x68, 0x36, 0x5b, 0xd5, 0x56, 0x4c, 0xe2, 0x77, 0xc3, 0xac, + 0x56, 0xe3, 0x1c, 0xc2, 0xf9, 0x78, 0x02, 0x39, 0x7d, 0xed, 0x18, 0x2a, + 0x01, 0x48, 0xe6, 0xf6, 0x7e, 0x34, 0x50, 0xf4, 0x57, 0x56, 0x93, 0xdb, + 0x85, 0x1b, 0x1e, 0x1a, 0x6f, 0x3e, 0x07, 0x3c, 0xad, 0x3f, 0x8d, 0x75, + 0x53, 0xc3, 0x20, 0x72, 0x93, 0x28, 0xd2, 0x86, 0xc8, 0xa5, 0x90, 0xf2, + 0x5f, 0x13, 0xd5, 0xa5, 0xbe, 0x88, 0x9e, 0x9a, 0x57, 0x2c, 0x53, 0x3f, + 0x11, 0x25, 0x00, 0x00, 0x4a, 0x16, 0x8d, 0xd3, 0x3f, 0x2d, 0x3d, 0x88, + 0xbb, 0x4c, 0x4f, 0x9a, 0xb9, 0x97, 0x5f, 0xed, 0x71, 0xa9, 0x68, 0xd9, + 0x4a, 0x14, 0x24, 0xc7, 0xbe, 0xff, 0x85, 0x57, 0xa3, 0x21, 0xe3, 0x21, + 0x79, 0x1f, 0xd0, 0xbb, 0xb7, 0x73, 0xde, 0x60, 0x02, 0x4b, 0x8f, 0x7d, + 0xb3, 0xb3, 0x8a, 0xda, 0x4c, 0xf4, 0xb8, 0xf1, 0x31, 0xff, 0x32, 0x7b, + 0xd8, 0xfa, 0xb1, 0xcb, 0xb4, 0x58, 0xf5, 0xc8, 0x64, 0xdf, 0xfe, 0x3d, + 0x89, 0x52, 0x5c, 0x52, 0x95, 0xf3, 0xba, 0x0d, 0x1d, 0x2c, 0xc4, 0xf7, + 0x3c, 0x3b, 0x6f, 0x8e, 0xc7, 0xab, 0xad, 0x3d, 0x3d, 0x95, 0x9b, 0xc7, + 0x71, 0x36, 0xae, 0x08, 0xc3, 0x08, 0x79, 0xfa, 0x24, 0xee, 0xd9, 0xf9, + 0x63, 0xc7, 0xd9, 0x16, 0x19, 0x8e, 0x0d, 0xaf, 0x52, 0x87, 0x86, 0x7d, + 0xec, 0xe5, 0xea, 0x5a, 0xda, 0x86, 0x9d, 0x0e, 0x50, 0x53, 0x8c, 0x24, + 0xa8, 0x69, 0xc4, 0xf3, 0x85, 0x7b, 0x34, 0x67, 0x19, 0x35, 0xec, 0xd4, + 0xd4, 0x50, 0xe0, 0xe6, 0xe9, 0x29, 0x5b, 0x92, 0xee, 0xba, 0xa9, 0xef, + 0xf6, 0x35, 0x23, 0x8b, 0xdb, 0x48, 0x32, 0x25, 0x41, 0xf3, 0x55, 0x12, + 0x33, 0xc3, 0x6c, 0xed, 0x32, 0xe1, 0x64, 0x7a, 0x8d, 0xa2, 0x19, 0x5a, + 0x26, 0xf2, 0x83, 0xf1, 0xe4, 0x27, 0xdb, 0x67, 0xc3, 0x89, 0x37, 0xea, + 0x78, 0x19, 0xc6, 0xa3, 0x82, 0x84, 0x1c, 0xf3, 0x2b, 0xbe, 0xde, 0xba, + 0xe7, 0x60, 0x2e, 0xf5, 0x4e, 0xb6, 0x73, 0x29, 0xac, 0xc7, 0x55, 0xab, + 0x21, 0xe9, 0x95, 0x78, 0xd5, 0x8e, 0x27, 0xdc, 0x92, 0x5f, 0xc0, 0xcb, + 0xee, 0x66, 0x09, 0x0a, 0xfc, 0x94, 0x43, 0x44, 0x50, 0x35, 0x57, 0xf8, + 0x08, 0xf9, 0x97, 0xa2, 0x0e, 0xde, 0x81, 0xe1, 0xd1, 0xa0, 0x41, 0xfe, + 0xe6, 0x08, 0x6c, 0x98, 0x8c, 0x81, 0x46, 0x0e, 0xf9, 0x9a, 0x54, 0xfe, + 0xc3, 0x91, 0xe3, 0xd4, 0x46, 0xca, 0x52, 0xa2, 0x73, 0x9e, 0x4d, 0xa7, + 0xfd, 0xa1, 0x8e, 0x43, 0x28, 0xf5, 0xa3, 0xa2, 0x62, 0x20, 0x53, 0x62, + 0x05, 0x49, 0xba, 0x06, 0xe2, 0xeb, 0xba, 0xfb, 0x8e, 0xa0, 0x22, 0xc7, + 0xf9, 0xcc, 0x7f, 0x8b, 0xa8, 0x5d, 0x55, 0xd2, 0x24, 0xff, 0xdd, 0x2c, + 0xc1, 0xd0, 0x3d, 0xe4, 0x79, 0xea, 0xba, 0x62, 0xe5, 0xa2, 0x62, 0xf4, + 0x1f, 0xec, 0xb0, 0x07, 0xf2, 0x0d, 0x32, 0x84, 0x86, 0x81, 0x3d, 0x95, + 0xc1, 0x64, 0xfe, 0x9a, 0x3d, 0x8f, 0x4b, 0x6d, 0xfb, 0x0d, 0x42, 0xcf, + 0xbf, 0xdb, 0x51, 0xb2, 0x16, 0xa2, 0x35, 0xaa, 0xe7, 0x31, 0x54, 0xc2, + 0x87, 0xc6, 0xa5, 0x30, 0x71, 0x64, 0x65, 0xff, 0x41, 0x20, 0xb0, 0x83, + 0xdb, 0xb7, 0x95, 0xce, 0xd7, 0xcc, 0x7a, 0x77, 0xad, 0xb8, 0xb7, 0x4c, + 0xfc, 0x11, 0x05, 0x2b, 0xc4, 0xd4, 0xb6, 0x8b, 0xae, 0x13, 0xa5, 0x40, + 0x18, 0x6e, 0x0d, 0xe3, 0xc6, 0xb0, 0x81, 0x46, 0x46, 0x7e, 0x52, 0x0b, + 0x85, 0x4d, 0x98, 0xd9, 0x42, 0xdf, 0xde, 0x45, 0xc1, 0x5a, 0x33, 0x12, + 0x46, 0x26, 0xb3, 0x6f, 0xf2, 0x8b, 0x37, 0x6b, 0xfd, 0x08, 0xf4, 0x46, + 0x86, 0x89, 0x63, 0x63, 0x21, 0xe5, 0xa9, 0xb7, 0xd0, 0x09, 0x17, 0x52, + 0xee, 0xea, 0xdf, 0x97, 0xb7, 0x73, 0x2e, 0x54, 0x2c, 0x7b, 0x70, 0xd3, + 0xda, 0x26, 0x57, 0x1f, 0xb0, 0x19, 0xd9, 0x91, 0x18, 0x69, 0x75, 0x42, + 0x63, 0xcf, 0x6c, 0x8c, 0x98, 0x5e, 0x17, 0x99, 0x7e, 0x1d, 0xdc, 0x67, + 0x6d, 0x99, 0xd9, 0x02, 0x6e, 0x73, 0x90, 0x5a, 0x4f, 0x0a, 0xb4, 0x48, + 0xfb, 0xc5, 0xbd, 0xd2, 0x10, 0x05, 0xa6, 0x12, 0x68, 0x36, 0x28, 0x51, + 0x60, 0x1c, 0xa1, 0xe9, 0x90, 0x54, 0xa5, 0x53, 0xc3, 0x48, 0x9e, 0xd8, + 0x42, 0x52, 0x85, 0x0e, 0xff, 0xfe, 0xbf, 0xad, 0x3a, 0xa4, 0x57, 0x09, + 0x13, 0x38, 0x64, 0x15, 0x7c, 0xfd, 0xed, 0x91, 0x76, 0x44, 0x20, 0x84, + 0xd9, 0x90, 0xab, 0xfe, 0xfd, 0xd6, 0xab, 0xf1, 0xb3, 0x25, 0x21, 0x3d, + 0x97, 0x72, 0xb2, 0x95, 0xc5, 0x22, 0x80, 0xd9, 0x4a, 0x49, 0x9d, 0x99, + 0xc2, 0x4a, 0x9a, 0x59, 0xb3, 0x71, 0x75, 0x5b, 0xf9, 0x89, 0x7a, 0xdd, + 0xa9, 0xb3, 0xc3, 0xeb, 0x42, 0x91, 0xe2, 0x97, 0x30, 0x40, 0x48, 0x68, + 0x19, 0x3b, 0xf5, 0x7b, 0x4e, 0x33, 0x4b, 0x0c, 0xf3, 0xed, 0xda, 0x76, + 0x3f, 0xb0, 0x4b, 0x53, 0x85, 0x04, 0x33, 0x07, 0x53, 0xd8, 0x55, 0xa2, + 0xfb, 0x30, 0x2c, 0x66, 0xbd, 0x21, 0xf8, 0xfa, 0x20, 0x14, 0x9a, 0x0d, + 0x7f, 0xc9, 0x2f, 0x5b, 0x34, 0x29, 0x09, 0x16, 0xb5, 0x0a, 0x8d, 0xdf, + 0xa2, 0x84, 0x9a, 0xae, 0xe6, 0xa0, 0x50, 0x80, 0x31, 0x04, 0xd3, 0x0c, + 0x8f, 0xd1, 0x8a, 0xfd, 0xb4, 0xa5, 0xae, 0xf5, 0x3c, 0x62, 0xae, 0x45, + 0x70, 0xbb, 0x54, 0x62, 0xc8, 0x50, 0x71, 0x42, 0x85, 0xf6, 0x6f, 0xa0, + 0xf0, 0x10, 0x8a, 0x09, 0xbd, 0x71, 0x78, 0xa6, 0x5e, 0xe4, 0x03, 0x8f, + 0x3b, 0xd0, 0x5c, 0x37, 0x55, 0x1a, 0xc8, 0x57, 0x26, 0x62, 0x6c, 0xc4, + 0x67, 0x71, 0x9d, 0x97, 0xc0, 0xea, 0x35, 0x3e, 0x12, 0xd0, 0x2b, 0xc2, + 0x8f, 0x9e, 0xa6, 0x41, 0x48, 0x33, 0x83, 0x38, 0x37, 0x7e, 0xd4, 0xe3, + 0xee, 0x94, 0x8b, 0x81, 0xa4, 0x60, 0xdd, 0xdd, 0xc1, 0x8a, 0x7b, 0xda, + 0xa8, 0x46, 0xb8, 0x42, 0x3a, 0x25, 0xd6, 0x81, 0x89, 0x29, 0x21, 0xc2, + 0x0c, 0x5b, 0xfd, 0x3e, 0x8c, 0x65, 0x91, 0x52, 0xb3, 0x74, 0x1f, 0xd1, + 0x49, 0x7e, 0x1d, 0x59, 0x58, 0x96, 0xb5, 0xee, 0x32, 0xa4, 0xa8, 0x07, + 0x7c, 0xd1, 0x5b, 0x4b, 0xf8, 0x43, 0x5a, 0xa5, 0xcc, 0x60, 0xcc, 0x08, + 0x6a, 0x3c, 0x41, 0x66, 0x99, 0xe3, 0xa8, 0xe0, 0xb8, 0x87, 0xfc, 0x92, + 0xc0, 0x79, 0xc5, 0x3f, 0xd6, 0xc6, 0x8c, 0x01, 0xf4, 0xa5, 0x05, 0xad, + 0x51, 0xed, 0x04, 0xd7, 0x55, 0xc0, 0x73, 0x05, 0x0e, 0x73, 0xe5, 0x39, + 0x45, 0x5b, 0x95, 0x4a, 0x34, 0x07, 0x99, 0xdf, 0x4c, 0x35, 0xf5, 0x0c, + 0x27, 0x6d, 0xd1, 0x45, 0xf1, 0xfd, 0x24, 0xb7, 0xfe, 0xea, 0x11, 0x5d, + 0xa2, 0xc5, 0xa6, 0x81, 0x37, 0x1d, 0xc2, 0x31, 0x31, 0xfc, 0xe0, 0xf4, + 0xd7, 0xe9, 0x98, 0x8b, 0xe3, 0x70, 0x51, 0x62, 0xc8, 0x61, 0x6d, 0xec, + 0x75, 0x56, 0x71, 0xae, 0x88, 0xe0, 0x80, 0xf5, 0xb7, 0x85, 0x10, 0xb7, + 0x3d, 0x16, 0x78, 0x5f, 0x72, 0xab, 0x8f, 0x63, 0xc6, 0xd5, 0xa8, 0xc9, + 0x9c, 0xef, 0x8d, 0x9a, 0xc5, 0x4f, 0x63, 0xad, 0xc0, 0xf3, 0x1f, 0x69, + 0x0e, 0xce, 0x29, 0x92, 0xc1, 0x3b, 0xb0, 0xc5, 0xed, 0x0a, 0x7b, 0x92, + 0xd0, 0x4c, 0x9c, 0x82, 0xb0, 0x51, 0xf6, 0x33, 0x61, 0x3b, 0x76, 0x48, + 0x38, 0xf4, 0x7c, 0xaa, 0x52, 0x87, 0x15, 0x1a, 0xbe, 0xb8, 0xdc, 0x9b, + 0x16, 0xd2, 0x07, 0xf7, 0xf9, 0x74, 0xe0, 0xaf, 0x0e, 0x29, 0x05, 0xec, + 0x6c, 0x0e, 0x3b, 0xa7, 0xe7, 0xa4, 0xfc, 0xa4, 0xef, 0x57, 0x16, 0x7f, + 0x13, 0xbd, 0x8c, 0x42, 0x02, 0x55, 0x70, 0x56, 0xa5, 0xa9, 0x01, 0x29, + 0x12, 0x7d, 0x80, 0x46, 0x18, 0x8e, 0x39, 0x3f, 0x44, 0x55, 0xec, 0xef, + 0x60, 0x58, 0x7d, 0xce, 0x64, 0x8e, 0x9c, 0xea, 0xe4, 0x73, 0xd1, 0x48, + 0x9c, 0x3f, 0x92, 0xa0, 0x9a, 0x76, 0xa5, 0x5a, 0x13, 0x1f, 0x10, 0xb9, + 0xb7, 0xb1, 0xde, 0x49, 0x22, 0x58, 0xf4, 0x43, 0x5f, 0x03, 0x43, 0xc3, + 0x6c, 0xbf, 0x82, 0xaf, 0x88, 0x39, 0xfd, 0xb2, 0x28, 0x9b, 0x47, 0x3f, + 0x83, 0x3d, 0xd9, 0x7c, 0xf0, 0xc9, 0xc5, 0xa2, 0xb4, 0xd6, 0x0d, 0x59, + 0x51, 0x27, 0x60, 0x10, 0x5e, 0xbb, 0x18, 0xa6, 0x42, 0x4a, 0x9d, 0xc4, + 0x16, 0x0e, 0xb6, 0x57, 0x23, 0x03, 0x24, 0x27, 0xdc, 0x20, 0x56, 0x30, + 0x8b, 0x0f, 0xb6, 0xb7, 0x73, 0xf5, 0x36, 0x3e, 0xf6, 0x7a, 0x71, 0xa5, + 0x57, 0xcc, 0x6d, 0xc6, 0xf3, 0xdc, 0x35, 0xfb, 0x95, 0xf7, 0xa7, 0xd7, + 0x56, 0x38, 0xd4, 0x15, 0xe2, 0xd5, 0x6f, 0x70, 0x30, 0xc8, 0x7d, 0x8a, + 0x87, 0xe6, 0xd1, 0xe0, 0x50, 0x62, 0xde, 0xfa, 0x29, 0x40, 0x97, 0xa0, + 0x54, 0x63, 0x31, 0xd3, 0x08, 0x87, 0x0a, 0xdc, 0x6e, 0x5e, 0xab, 0x8d, + 0x16, 0xaf, 0x6e, 0x8b, 0x1a, 0x77, 0xf6, 0xd4, 0xe0, 0xbf, 0x59, 0xab, + 0xc7, 0xb0, 0x45, 0x18, 0xaa, 0xe6, 0x65, 0x6f, 0x7d, 0x13, 0xb2, 0xbf, + 0xb3, 0x66, 0x72, 0xfa, 0xfd, 0xee, 0xad, 0x07, 0x56, 0x51, 0x6a, 0xe2, + 0xff, 0xb2, 0xaf, 0x4d, 0xd1, 0xf2, 0x77, 0x35, 0x5e, 0x90, 0xcd, 0xe7, + 0xa8, 0x32, 0x4d, 0x9f, 0xbd, 0xa8, 0xce, 0xab, 0xf1, 0x49, 0x98, 0xb5, + 0x23, 0x5c, 0x62, 0x2d, 0x43, 0x31, 0x80, 0x87, 0xc2, 0xa8, 0xf5, 0xb9, + 0xb6, 0xae, 0x7f, 0x37, 0x13, 0xb8, 0x6b, 0x73, 0xf3, 0x56, 0x38, 0xa7, + 0x9b, 0x97, 0x69, 0x37, 0x00, 0xdc, 0xff, 0xfe, 0x58, 0xc9, 0x12, 0x47, + 0x75, 0x98, 0x1f, 0xad, 0xd8, 0xb5, 0xc8, 0x47, 0x4f, 0xd0, 0x72, 0x63, + 0x54, 0x25, 0x6c, 0x88, 0xc9, 0x9f, 0x3c, 0x82, 0xe0, 0xdd, 0x4c, 0xff, + 0x8e, 0xaf, 0x8f, 0x8e, 0xea, 0x84, 0x3f, 0x73, 0xdd, 0x9e, 0x18, 0x73, + 0x47, 0x70, 0xc7, 0xc7, 0x99, 0x65, 0xcf, 0xf3, 0xb6, 0x24, 0xed, 0x97, + 0x8f, 0xcd, 0x93, 0x1e, 0xff, 0x6e, 0x9c, 0xf1, 0x30, 0x14, 0x1a, 0x27, + 0x59, 0x6a, 0x0e, 0xf3, 0xe4, 0xfa, 0x1d, 0x65, 0xb5, 0x53, 0xe4, 0xab, + 0xb1, 0x3e, 0xe1, 0x91, 0xf4, 0x6d, 0x99, 0xca, 0x7d, 0x03, 0x08, 0x50, + 0xea, 0xa9, 0x39, 0x7f, 0x6d, 0xe7, 0x43, 0xfb, 0x64, 0xcc, 0x4b, 0x9e, + 0xa0, 0x26, 0xe4, 0x0e, 0xff, 0xb7, 0x11, 0x0a, 0x29, 0x50, 0x90, 0xd7, + 0x4d, 0x62, 0x9a, 0x4a, 0x23, 0xb7, 0xd3, 0x53, 0xde, 0x3a, 0xd1, 0xba, + 0xd3, 0x10, 0x59, 0xc6, 0xc5, 0x5e, 0xac, 0xf9, 0x61, 0x74, 0x54, 0xf4, + 0x27, 0x9f, 0x9a, 0x61, 0x13, 0xdc, 0xe5, 0x96, 0xe3, 0x95, 0x0d, 0xcc, + 0xbd, 0x81, 0x74, 0x79, 0x73, 0xef, 0x2e, 0x0b, 0x0f, 0x91, 0x65, 0x3c, + 0x26, 0x7c, 0x47, 0x10, 0x31, 0x0b, 0xfb, 0x41, 0x0c, 0xc2, 0xa8, 0xc4, + 0x0e, 0xbd, 0x0a, 0x8c, 0xa4, 0x80, 0x45, 0x57, 0x62, 0x0b, 0x4d, 0x44, + 0x5e, 0x59, 0x77, 0xfd, 0x3d, 0xf3, 0xd7, 0x92, 0x49, 0xc1, 0xcb, 0x8a, + 0x54, 0x56, 0x3b, 0xde, 0xcf, 0x16, 0x9a, 0x65, 0xbe, 0xac, 0x64, 0xe1, + 0xd4, 0xd4, 0x1e, 0xac, 0x6b, 0x4a, 0xad, 0xc4, 0x33, 0xac, 0xcb, 0x83, + 0xf4, 0x4d, 0xe8, 0xb6, 0xd7, 0x23, 0xd7, 0x71, 0x25, 0xa2, 0x25, 0x3d, + 0x7e, 0xf0, 0x3b, 0x7f, 0x61, 0x11, 0x56, 0xd4, 0x83, 0xc8, 0xc0, 0x29, + 0x38, 0x10, 0x73, 0xad, 0x6a, 0xb7, 0xb9, 0xd2, 0x2e, 0x9f, 0xae, 0x16, + 0x5e, 0xa6, 0x13, 0x1c, 0xc2, 0x17, 0x73, 0x43, 0x03, 0xdd, 0xa6, 0xaf, + 0x9a, 0x17, 0x31, 0xb8, 0x86, 0x97, 0xc2, 0xd6, 0xe6, 0xed, 0xd4, 0xe1, + 0x7d, 0xb9, 0xa6, 0x96, 0xc1, 0x4b, 0xcb, 0x11, 0x1e, 0xe1, 0xe0, 0xd2, + 0x28, 0x69, 0x68, 0x3b, 0x21, 0x17, 0x63, 0x0c, 0xc0, 0x49, 0x30, 0x22, + 0x3a, 0x59, 0x72, 0xe6, 0x47, 0xb4, 0xdc, 0xa8, 0x29, 0x1c, 0x89, 0xa6, + 0x3a, 0x77, 0x99, 0xea, 0x46, 0xce, 0x38, 0xda, 0x31, 0x88, 0xad, 0xe7, + 0x26, 0xce, 0xc6, 0x56, 0x04, 0x30, 0xfa, 0x01, 0xac, 0xbb, 0xe2, 0xb8, + 0x23, 0xe4, 0x9d, 0x4f, 0x77, 0x02, 0x00, 0x28, 0xf1, 0xe0, 0x19, 0x3f, + 0x22, 0x4f, 0x22, 0x69, 0x87, 0xc0, 0x4e, 0x26, 0x33, 0xfe, 0x6c, 0x70, + 0x56, 0x3b, 0x60, 0x5f, 0xfb, 0xf8, 0x43, 0xcf, 0x3f, 0xb9, 0xcb, 0x80, + 0x22, 0xbb, 0x0a, 0xa8, 0x1c, 0x3e, 0x7e, 0x4d, 0x42, 0x60, 0x5c, 0x8e, + 0xfa, 0x42, 0xb3, 0x95, 0xe7, 0x92, 0x6b, 0xec, 0x7a, 0x95, 0x88, 0x98, + 0xe3, 0xf9, 0x0d, 0xe5, 0x08, 0xf1, 0x26, 0x96, 0x2a, 0x81, 0x2b, 0x7c, + 0x0d, 0x12, 0xa0, 0x7f, 0x7b, 0x39, 0xf6, 0xcc, 0x1b, 0x2d, 0x2c, 0xe9, + 0x5b, 0x02, 0x9b, 0x5c, 0x94, 0x51, 0x13, 0xe8, 0xa0, 0x19, 0xce, 0xde, + 0x07, 0x1b, 0xda, 0x39, 0x14, 0xb5, 0x8b, 0xcf, 0x79, 0x3e, 0x2b, 0xb8, + 0x75, 0xab, 0x81, 0xee, 0x5e, 0x08, 0x33, 0xc3, 0x49, 0x5b, 0x4a, 0x9c, + 0x74, 0x34, 0xde, 0x08, 0x61, 0x03, 0x38, 0xe3, 0xd8, 0xff, 0xc5, 0xc0, + 0xb5, 0x40, 0xd5, 0x26, 0x57, 0x85, 0xf1, 0xb7, 0x77, 0xb6, 0x36, 0xe0, + 0x8d, 0x43, 0x3a, 0xef, 0xfe, 0x0f, 0xf7, 0xee, 0x67, 0x6c, 0x7b, 0xd1, + 0x83, 0xf6, 0x10, 0xda, 0x67, 0x04, 0x3a, 0x27, 0xd8, 0x3a, 0xcb, 0x9d, + 0x4c, 0xa6, 0x9a, 0xc7, 0xea, 0x07, 0xc6, 0x76, 0x79, 0x1b, 0x23, 0x4a, + 0x68, 0x2f, 0x14, 0x84, 0x42, 0x79, 0xe8, 0x1f, 0xf2, 0xe6, 0xac, 0x72, + 0xb0, 0xb0, 0xb6, 0x39, 0x95, 0x40, 0xa4, 0x6e, 0x54, 0x2e, 0xb7, 0xb5, + 0x13, 0x70, 0x48, 0x0d, 0x27, 0xed, 0x2c, 0xa2, 0x64, 0x53, 0xb4, 0x04, + 0x84, 0xab, 0xd8, 0xea, 0x2a, 0x8c, 0xac, 0x5b, 0x1d, 0xb8, 0xb2, 0xbe, + 0x55, 0x2b, 0x4a, 0x47, 0xfc, 0xe0, 0x15, 0x78, 0xb6, 0xd6, 0xff, 0x20, + 0xa8, 0x8a, 0xec, 0x8b, 0x30, 0xef, 0xc5, 0xc6, 0xec, 0xa0, 0xdf, 0xd3, + 0xc4, 0x2b, 0x4a, 0xdf, 0xef, 0x5c, 0x46, 0xb3, 0x31, 0xc7, 0x5f, 0x8f, + 0x1e, 0x99, 0x76, 0x81, 0x71, 0x61, 0xdb, 0xc3, 0xc4, 0x0f, 0x66, 0x7b, + 0xd7, 0x44, 0xc7, 0x8d, 0x12, 0x38, 0x71, 0x7c, 0xd8, 0x41, 0xf6, 0x8a, + 0xb9, 0xba, 0xd2, 0x1f, 0xa1, 0x27, 0x64, 0x67, 0x51, 0xb2, 0xaf, 0xea, + 0x02, 0x95, 0x79, 0x20, 0x0a, 0xc8, 0xaa, 0x03, 0x11, 0xb6, 0x8b, 0x7d, + 0x86, 0xb7, 0xef, 0x5e, 0x3f, 0x0b, 0x91, 0x47, 0xf0, 0x43, 0xb4, 0x54, + 0x1d, 0x16, 0x66, 0xe9, 0x63, 0x1a, 0x55, 0xaf, 0x34, 0xad, 0x11, 0x68, + 0x4d, 0x36, 0xb7, 0x0c, 0x6d, 0x4d, 0xed, 0xba, 0x14, 0xe8, 0xf6, 0xe2, + 0x15, 0x64, 0xb6, 0x15, 0x28, 0xbf, 0xd2, 0x4d, 0xb6, 0x6f, 0xca, 0x5f, + 0x81, 0x1b, 0xf0, 0x31, 0xf5, 0xd3, 0xe0, 0x06, 0xc7, 0xf3, 0x0c, 0x18, + 0x91, 0x45, 0x22, 0xa2, 0x30, 0x48, 0x82, 0xeb, 0x42, 0xfc, 0x8f, 0x2a, + 0xa3, 0x1a, 0x8d, 0x84, 0x28, 0x20, 0x16, 0x95, 0xd9, 0x66, 0x67, 0x2b, + 0xef, 0xc6, 0x6e, 0x56, 0x1c, 0x62, 0x74, 0x16, 0x5c, 0x3e, 0x17, 0xd0, + 0xb7, 0xdd, 0x70, 0xb6, 0x0e, 0x79, 0x46, 0xc5, 0x4e, 0x72, 0x46, 0x69, + 0xf5, 0xa1, 0x1c, 0x7b, 0xd5, 0x67, 0x5c, 0xb3, 0x46, 0x4d, 0x18, 0x31, + 0x47, 0x42, 0x20, 0xe6, 0x12, 0x84, 0x4e, 0x16, 0x0f, 0x4a, 0xd0, 0xc4, + 0x91, 0xa3, 0xbd, 0x91, 0xcd, 0x86, 0x4c, 0xcd, 0x4b, 0x2e, 0x62, 0x84, + 0xea, 0x19, 0x2d, 0x21, 0x1a, 0x64, 0xc4, 0xd2, 0x24, 0x92, 0x96, 0x04, + 0x66, 0xb5, 0x4a, 0xe4, 0xa9, 0xd6, 0xaf, 0x12, 0x9b, 0xb5, 0x59, 0xe0, + 0x5c, 0x84, 0x84, 0x7c, 0x68, 0x99, 0xd8, 0x23, 0xa2, 0x15, 0xa7, 0x82, + 0xa5, 0x66, 0x95, 0x8f, 0xfe, 0x57, 0xc1, 0x12, 0x6c, 0x89, 0xe5, 0x5b, + 0x5d, 0x64, 0xdb, 0x81, 0x4f, 0x77, 0x3c, 0xc8, 0x52, 0x4e, 0x2a, 0xd6, + 0x74, 0x3c, 0x4b, 0x11, 0xfc, 0xc1, 0x7c, 0x01, 0xba, 0x0f, 0x0f, 0x57, + 0x8a, 0xbe, 0x5b, 0x16, 0x88, 0x96, 0xe6, 0xe9, 0x60, 0xcf, 0x66, 0xe9, + 0xe6, 0x07, 0xb0, 0x0b, 0xa3, 0xa0, 0xad, 0xdf, 0x70, 0xd4, 0xcb, 0x2e, + 0x33, 0x2f, 0xe5, 0xf2, 0x1e, 0x0d, 0x74, 0x7a, 0xf9, 0x4a, 0x0f, 0x32, + 0xb4, 0xa1, 0xc9, 0xf5, 0x3f, 0x0a, 0x06, 0xf9, 0x67, 0x45, 0x9c, 0xd9, + 0x58, 0xd4, 0x0e, 0x72, 0x55, 0x47, 0x49, 0x9b, 0xab, 0x9c, 0x66, 0xe7, + 0x4d, 0x9a, 0x02, 0x1b, 0x41, 0xad, 0xe5, 0x8c, 0x7f, 0xa1, 0xdc, 0xad, + 0xcd, 0x74, 0xda, 0x9f, 0xfa, 0x87, 0x32, 0xc1, 0x07, 0x8e, 0x9b, 0xef, + 0x28, 0x2f, 0x17, 0x6d, 0xdb, 0x84, 0x4b, 0xa8, 0x7d, 0x31, 0xa8, 0x32, + 0xe4, 0x9a, 0x1e, 0x0e, 0xef, 0x68, 0xf4, 0xac, 0x03, 0x6c, 0x68, 0xcc, + 0x28, 0xbb, 0xfb, 0x21, 0xb8, 0x11, 0xd7, 0xf9, 0xe8, 0x24, 0x37, 0xdf, + 0xe0, 0xb2, 0xef, 0xd6, 0xec, 0xdf, 0xcf, 0xf5, 0x50, 0x19, 0xa3, 0xa9, + 0x1b, 0x01, 0x2e, 0x94, 0x42, 0xb0, 0x14, 0x5d, 0x0e, 0x37, 0x46, 0x4a, + 0x52, 0x53, 0x60, 0x6b, 0x89, 0xc9, 0xca, 0xed, 0x0a, 0x0c, 0x18, 0x33, + 0x3c, 0x40, 0x42, 0x76, 0x7a, 0x7d, 0xb6, 0x10, 0x29, 0x3e, 0x42, 0x75, + 0xa6, 0xbf, 0xcb, 0xd3, 0xdc, 0xe1, 0x00, 0x05, 0x08, 0x25, 0x67, 0x6c, + 0x72, 0xde, 0x26, 0x72, 0x88, 0xbe, 0xfa, 0x05, 0x57, 0x77, 0x78, 0x83, + 0xce, 0xd5, 0x44, 0x49, 0x8b, 0xab, 0xbc, 0xca, 0xd3, 0x1c, 0x34, 0x4a, + 0xaa, 0xc7, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x17, 0x22, 0x2a, 0x2f, 0x36, 0x3d, 0x43}; +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_KEYGEN_PCT */ +#endif /* !EXPECTED_SIGNATURES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/main.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/main.c new file mode 100644 index 0000000000..a18341f384 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/main.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include +#include +#include + +/* Import public mldsa-native API + * + * This requires specifying the parameter set and namespace prefix + * used for the build. + * + * The parameter set is configured on the command line + */ + +#include +#include "expected_signatures.h" +#include "test_only_rng/notrandombytes.h" + +#define CHECK(x) \ + do \ + { \ + int rc; \ + rc = (x); \ + if (!rc) \ + { \ + fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \ + return 1; \ + } \ + } while (0) + +#define TEST_MSG \ + "This is a test message for ML-DSA digital signature algorithm!" +#define TEST_MSG_LEN (sizeof(TEST_MSG) - 1) + +#define TEST_CTX "test_context_123" +#define TEST_CTX_LEN (sizeof(TEST_CTX) - 1) + +int main(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t sig[CRYPTO_BYTES]; + uint8_t sm[TEST_MSG_LEN + CRYPTO_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + CRYPTO_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-%d monolithic_build_native Example\n", + MLD_CONFIG_API_PARAMETER_SET); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(crypto_sign_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(crypto_sign_signature(sig, &siglen, (const uint8_t *)test_msg, + TEST_MSG_LEN, (const uint8_t *)test_ctx, + TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(crypto_sign_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(crypto_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(crypto_sign_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", CRYPTO_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", CRYPTO_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", CRYPTO_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature)); + CHECK(memcmp(sig, expected_signature, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/mldsa_native.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/mldsa_native.c new file mode 100644 index 0000000000..9668cec167 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/mldsa_native.c @@ -0,0 +1,699 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/****************************************************************************** + * + * Single compilation unit (SCU) for fixed-level build of mldsa-native + * + * This compilation unit bundles together all source files for a build + * of mldsa-native for a fixed security level (MLDSA-44/65/87). + * + * # API + * + * The API exposed by this file is described in mldsa_native.h. + * + * # Multi-level build + * + * If you want an SCU build of mldsa-native with support for multiple security + * levels, you need to include this file multiple times, and set + * MLD_CONFIG_MULTILEVEL_WITH_SHARED and MLD_CONFIG_MULTILEVEL_NO_SHARED + * appropriately. This is exemplified in examples/monolithic_build_multilevel + * and examples/monolithic_build_multilevel_native. + * + * # Configuration + * + * The following options from the mldsa-native configuration are relevant: + * + * - MLD_CONFIG_FIPS202_CUSTOM_HEADER + * Set this option if you use a custom FIPS202 implementation. + * + * - MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * Set this option if you want to include the native arithmetic backends + * in your build. + * + * - MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * Set this option if you want to include the native FIPS202 backends + * in your build. + * + * - MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * Set this option if you want to keep the directives defined in + * level-independent headers. This is needed for a multi-level build. + */ + +/* If parts of the mldsa-native source tree are not used, + * consider reducing this header via `unifdef`. + * + * Example: + * ```bash + * unifdef -UMLD_CONFIG_USE_NATIVE_BACKEND_ARITH mldsa_native.c + * ``` + */ + +#include "src/common.h" + +#include "src/ct.c" +#include "src/debug.c" +#include "src/packing.c" +#include "src/poly.c" +#include "src/poly_kl.c" +#include "src/polyvec.c" +#include "src/sign.c" + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#include "src/fips202/fips202.c" +#include "src/fips202/fips202x4.c" +#include "src/fips202/keccakf1600.c" +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#if defined(MLD_SYS_AARCH64) +#include "src/native/aarch64/src/aarch64_zetas.c" +#include "src/native/aarch64/src/polyz_unpack_table.c" +#include "src/native/aarch64/src/rej_uniform_eta_table.c" +#include "src/native/aarch64/src/rej_uniform_table.c" +#endif /* MLD_SYS_AARCH64 */ +#if defined(MLD_SYS_X86_64) +#include "src/native/x86_64/src/consts.c" +#include "src/native/x86_64/src/poly_caddq_avx2.c" +#include "src/native/x86_64/src/poly_chknorm_avx2.c" +#include "src/native/x86_64/src/poly_decompose_32_avx2.c" +#include "src/native/x86_64/src/poly_decompose_88_avx2.c" +#include "src/native/x86_64/src/poly_use_hint_32_avx2.c" +#include "src/native/x86_64/src/poly_use_hint_88_avx2.c" +#include "src/native/x86_64/src/polyz_unpack_17_avx2.c" +#include "src/native/x86_64/src/polyz_unpack_19_avx2.c" +#include "src/native/x86_64/src/rej_uniform_avx2.c" +#include "src/native/x86_64/src/rej_uniform_eta2_avx2.c" +#include "src/native/x86_64/src/rej_uniform_eta4_avx2.c" +#include "src/native/x86_64/src/rej_uniform_table.c" +#endif /* MLD_SYS_X86_64 */ +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#if defined(MLD_SYS_AARCH64) +#include "src/fips202/native/aarch64/src/keccakf1600_round_constants.c" +#endif +#if defined(MLD_SYS_X86_64) +#include "src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +/* Macro #undef's + * + * The following undefines macros from headers + * included by the source files imported above. + * + * This is to allow building and linking multiple builds + * of mldsa-native for varying parameter sets through concatenation + * of this file, as if the files had been compiled separately. + * If this is not relevant to you, you may remove the following. + */ + +/* + * Undefine macros from MLD_CONFIG_PARAMETER_SET-specific files + */ +/* mldsa/mldsa_native.h */ +#undef CRYPTO_BYTES +#undef CRYPTO_PUBLICKEYBYTES +#undef CRYPTO_SECRETKEYBYTES +#undef MLDSA44_BYTES +#undef MLDSA44_CRHBYTES +#undef MLDSA44_PUBLICKEYBYTES +#undef MLDSA44_RNDBYTES +#undef MLDSA44_SECRETKEYBYTES +#undef MLDSA44_SEEDBYTES +#undef MLDSA44_TRBYTES +#undef MLDSA65_BYTES +#undef MLDSA65_CRHBYTES +#undef MLDSA65_PUBLICKEYBYTES +#undef MLDSA65_RNDBYTES +#undef MLDSA65_SECRETKEYBYTES +#undef MLDSA65_SEEDBYTES +#undef MLDSA65_TRBYTES +#undef MLDSA87_BYTES +#undef MLDSA87_CRHBYTES +#undef MLDSA87_PUBLICKEYBYTES +#undef MLDSA87_RNDBYTES +#undef MLDSA87_SECRETKEYBYTES +#undef MLDSA87_SEEDBYTES +#undef MLDSA87_TRBYTES +#undef MLDSA_BYTES +#undef MLDSA_BYTES_ +#undef MLDSA_CRHBYTES +#undef MLDSA_PUBLICKEYBYTES +#undef MLDSA_PUBLICKEYBYTES_ +#undef MLDSA_RNDBYTES +#undef MLDSA_SECRETKEYBYTES +#undef MLDSA_SECRETKEYBYTES_ +#undef MLDSA_SEEDBYTES +#undef MLDSA_TRBYTES +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_LEGACY_CONFIG +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_NAMESPACE +#undef MLD_API_QUALIFIER +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_QUALIFIER +#undef MLD_DOMAIN_SEPARATION_MAX_BYTES +#undef MLD_ERR_FAIL +#undef MLD_ERR_OUT_OF_MEMORY +#undef MLD_ERR_RNG_FAIL +#undef MLD_H +#undef MLD_MAX3_ +#undef MLD_PREHASH_NONE +#undef MLD_PREHASH_SHA2_224 +#undef MLD_PREHASH_SHA2_256 +#undef MLD_PREHASH_SHA2_384 +#undef MLD_PREHASH_SHA2_512 +#undef MLD_PREHASH_SHA2_512_224 +#undef MLD_PREHASH_SHA2_512_256 +#undef MLD_PREHASH_SHA3_224 +#undef MLD_PREHASH_SHA3_256 +#undef MLD_PREHASH_SHA3_384 +#undef MLD_PREHASH_SHA3_512 +#undef MLD_PREHASH_SHAKE_128 +#undef MLD_PREHASH_SHAKE_256 +#undef MLD_TOTAL_ALLOC_44 +#undef MLD_TOTAL_ALLOC_44_KEYPAIR +#undef MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#undef MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#undef MLD_TOTAL_ALLOC_44_SIGN +#undef MLD_TOTAL_ALLOC_44_VERIFY +#undef MLD_TOTAL_ALLOC_65 +#undef MLD_TOTAL_ALLOC_65_KEYPAIR +#undef MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#undef MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#undef MLD_TOTAL_ALLOC_65_SIGN +#undef MLD_TOTAL_ALLOC_65_VERIFY +#undef MLD_TOTAL_ALLOC_87 +#undef MLD_TOTAL_ALLOC_87_KEYPAIR +#undef MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#undef MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#undef MLD_TOTAL_ALLOC_87_SIGN +#undef MLD_TOTAL_ALLOC_87_VERIFY +#undef crypto_sign +#undef crypto_sign_keypair +#undef crypto_sign_open +#undef crypto_sign_signature +#undef crypto_sign_verify +/* mldsa/src/common.h */ +#undef MLD_ADD_PARAM_SET +#undef MLD_ALLOC +#undef MLD_APPLY +#undef MLD_ASM_FN_SYMBOL +#undef MLD_ASM_NAMESPACE +#undef MLD_BUILD_INTERNAL +#undef MLD_COMMON_H +#undef MLD_CONCAT +#undef MLD_CONCAT_ +#undef MLD_CONTEXT_PARAMETERS_0 +#undef MLD_CONTEXT_PARAMETERS_1 +#undef MLD_CONTEXT_PARAMETERS_2 +#undef MLD_CONTEXT_PARAMETERS_3 +#undef MLD_CONTEXT_PARAMETERS_4 +#undef MLD_CONTEXT_PARAMETERS_5 +#undef MLD_CONTEXT_PARAMETERS_6 +#undef MLD_CONTEXT_PARAMETERS_7 +#undef MLD_CONTEXT_PARAMETERS_8 +#undef MLD_CONTEXT_PARAMETERS_9 +#undef MLD_EMPTY_CU +#undef MLD_ERR_FAIL +#undef MLD_ERR_OUT_OF_MEMORY +#undef MLD_ERR_RNG_FAIL +#undef MLD_EXTERNAL_API +#undef MLD_FIPS202X4_HEADER_FILE +#undef MLD_FIPS202_HEADER_FILE +#undef MLD_FREE +#undef MLD_INTERNAL_API +#undef MLD_MULTILEVEL_BUILD +#undef MLD_NAMESPACE +#undef MLD_NAMESPACE_KL +#undef MLD_NAMESPACE_PREFIX +#undef MLD_NAMESPACE_PREFIX_KL +#undef MLD_UNION_OR_STRUCT +#undef mld_memcpy +#undef mld_memset +/* mldsa/src/packing.h */ +#undef MLD_PACKING_H +#undef mld_pack_pk +#undef mld_pack_sig_c_h +#undef mld_pack_sig_z +#undef mld_pack_sk +#undef mld_unpack_pk +#undef mld_unpack_sig +#undef mld_unpack_sk +/* mldsa/src/params.h */ +#undef MLDSA_BETA +#undef MLDSA_CRHBYTES +#undef MLDSA_CRYPTO_BYTES +#undef MLDSA_CRYPTO_PUBLICKEYBYTES +#undef MLDSA_CRYPTO_SECRETKEYBYTES +#undef MLDSA_CTILDEBYTES +#undef MLDSA_D +#undef MLDSA_ETA +#undef MLDSA_GAMMA1 +#undef MLDSA_GAMMA2 +#undef MLDSA_K +#undef MLDSA_L +#undef MLDSA_N +#undef MLDSA_OMEGA +#undef MLDSA_POLYETA_PACKEDBYTES +#undef MLDSA_POLYT0_PACKEDBYTES +#undef MLDSA_POLYT1_PACKEDBYTES +#undef MLDSA_POLYVECH_PACKEDBYTES +#undef MLDSA_POLYW1_PACKEDBYTES +#undef MLDSA_POLYZ_PACKEDBYTES +#undef MLDSA_Q +#undef MLDSA_Q_HALF +#undef MLDSA_RNDBYTES +#undef MLDSA_SEEDBYTES +#undef MLDSA_TAU +#undef MLDSA_TRBYTES +#undef MLD_PARAMS_H +/* mldsa/src/poly_kl.h */ +#undef MLD_POLYETA_UNPACK_LOWER_BOUND +#undef MLD_POLY_KL_H +#undef mld_poly_challenge +#undef mld_poly_decompose +#undef mld_poly_make_hint +#undef mld_poly_uniform_eta +#undef mld_poly_uniform_eta_4x +#undef mld_poly_uniform_gamma1 +#undef mld_poly_uniform_gamma1_4x +#undef mld_poly_use_hint +#undef mld_polyeta_pack +#undef mld_polyeta_unpack +#undef mld_polyw1_pack +#undef mld_polyz_pack +#undef mld_polyz_unpack +/* mldsa/src/polyvec.h */ +#undef MLD_POLYVEC_H +#undef mld_polymat +#undef mld_polymat_get_row +#undef mld_polyvec_matrix_expand +#undef mld_polyvec_matrix_pointwise_montgomery +#undef mld_polyveck +#undef mld_polyveck_add +#undef mld_polyveck_caddq +#undef mld_polyveck_chknorm +#undef mld_polyveck_decompose +#undef mld_polyveck_invntt_tomont +#undef mld_polyveck_make_hint +#undef mld_polyveck_ntt +#undef mld_polyveck_pack_eta +#undef mld_polyveck_pack_t0 +#undef mld_polyveck_pack_w1 +#undef mld_polyveck_pointwise_poly_montgomery +#undef mld_polyveck_power2round +#undef mld_polyveck_reduce +#undef mld_polyveck_shiftl +#undef mld_polyveck_sub +#undef mld_polyveck_unpack_eta +#undef mld_polyveck_unpack_t0 +#undef mld_polyveck_use_hint +#undef mld_polyvecl +#undef mld_polyvecl_chknorm +#undef mld_polyvecl_ntt +#undef mld_polyvecl_pack_eta +#undef mld_polyvecl_pointwise_acc_montgomery +#undef mld_polyvecl_uniform_gamma1 +#undef mld_polyvecl_unpack_eta +#undef mld_polyvecl_unpack_z +/* mldsa/src/rounding.h */ +#undef MLD_2_POW_D +#undef MLD_ROUNDING_H +#undef mld_decompose +#undef mld_make_hint +#undef mld_power2round +#undef mld_use_hint +/* mldsa/src/sign.h */ +#undef MLD_DOMAIN_SEPARATION_MAX_BYTES +#undef MLD_PREHASH_NONE +#undef MLD_PREHASH_SHA2_224 +#undef MLD_PREHASH_SHA2_256 +#undef MLD_PREHASH_SHA2_384 +#undef MLD_PREHASH_SHA2_512 +#undef MLD_PREHASH_SHA2_512_224 +#undef MLD_PREHASH_SHA2_512_256 +#undef MLD_PREHASH_SHA3_224 +#undef MLD_PREHASH_SHA3_256 +#undef MLD_PREHASH_SHA3_384 +#undef MLD_PREHASH_SHA3_512 +#undef MLD_PREHASH_SHAKE_128 +#undef MLD_PREHASH_SHAKE_256 +#undef MLD_SIGN_H +#undef mld_prepare_domain_separation_prefix +#undef mld_sign +#undef mld_sign_keypair +#undef mld_sign_keypair_internal +#undef mld_sign_open +#undef mld_sign_pk_from_sk +#undef mld_sign_signature +#undef mld_sign_signature_extmu +#undef mld_sign_signature_internal +#undef mld_sign_signature_pre_hash_internal +#undef mld_sign_signature_pre_hash_shake256 +#undef mld_sign_verify +#undef mld_sign_verify_extmu +#undef mld_sign_verify_internal +#undef mld_sign_verify_pre_hash_internal +#undef mld_sign_verify_pre_hash_shake256 + +#if !defined(MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS) +/* + * Undefine macros from MLD_CONFIG_PARAMETER_SET-generic files + */ +/* mldsa/src/ct.h */ +#undef MLD_CT_H +#undef MLD_USE_ASM_VALUE_BARRIER +#undef mld_ct_opt_blocker_u64 +/* mldsa/src/debug.h */ +#undef MLD_DEBUG_H +#undef mld_assert +#undef mld_assert_abs_bound +#undef mld_assert_abs_bound_2d +#undef mld_assert_bound +#undef mld_assert_bound_2d +#undef mld_debug_check_assert +#undef mld_debug_check_bounds +/* mldsa/src/poly.h */ +#undef MLD_INTT_BOUND +#undef MLD_NTT_BOUND +#undef MLD_POLY_H +#undef mld_poly_add +#undef mld_poly_caddq +#undef mld_poly_chknorm +#undef mld_poly_invntt_tomont +#undef mld_poly_ntt +#undef mld_poly_pointwise_montgomery +#undef mld_poly_power2round +#undef mld_poly_reduce +#undef mld_poly_shiftl +#undef mld_poly_sub +#undef mld_poly_uniform +#undef mld_poly_uniform_4x +#undef mld_polyt0_pack +#undef mld_polyt0_unpack +#undef mld_polyt1_pack +#undef mld_polyt1_unpack +/* mldsa/src/randombytes.h */ +#undef MLD_RANDOMBYTES_H +/* mldsa/src/reduce.h */ +#undef MLD_MONT +#undef MLD_REDUCE32_DOMAIN_MAX +#undef MLD_REDUCE32_RANGE_MAX +#undef MLD_REDUCE_H +/* mldsa/src/symmetric.h */ +#undef MLD_STREAM128_BLOCKBYTES +#undef MLD_STREAM256_BLOCKBYTES +#undef MLD_SYMMETRIC_H +#undef mld_xof128_absorb_once +#undef mld_xof128_ctx +#undef mld_xof128_init +#undef mld_xof128_release +#undef mld_xof128_squeezeblocks +#undef mld_xof128_x4_absorb +#undef mld_xof128_x4_ctx +#undef mld_xof128_x4_init +#undef mld_xof128_x4_release +#undef mld_xof128_x4_squeezeblocks +#undef mld_xof256_absorb_once +#undef mld_xof256_ctx +#undef mld_xof256_init +#undef mld_xof256_release +#undef mld_xof256_squeezeblocks +#undef mld_xof256_x4_absorb +#undef mld_xof256_x4_ctx +#undef mld_xof256_x4_init +#undef mld_xof256_x4_release +#undef mld_xof256_x4_squeezeblocks +/* mldsa/src/sys.h */ +#undef MLD_ALIGN +#undef MLD_ALIGN_UP +#undef MLD_ALWAYS_INLINE +#undef MLD_CET_ENDBR +#undef MLD_CT_TESTING_DECLASSIFY +#undef MLD_CT_TESTING_SECRET +#undef MLD_DEFAULT_ALIGN +#undef MLD_HAVE_INLINE_ASM +#undef MLD_INLINE +#undef MLD_MUST_CHECK_RETURN_VALUE +#undef MLD_RESTRICT +#undef MLD_STATIC_TESTABLE +#undef MLD_SYS_AARCH64 +#undef MLD_SYS_AARCH64_EB +#undef MLD_SYS_APPLE +#undef MLD_SYS_BIG_ENDIAN +#undef MLD_SYS_H +#undef MLD_SYS_LINUX +#undef MLD_SYS_LITTLE_ENDIAN +#undef MLD_SYS_PPC64LE +#undef MLD_SYS_RISCV32 +#undef MLD_SYS_RISCV64 +#undef MLD_SYS_WINDOWS +#undef MLD_SYS_X86_64 +#undef MLD_SYS_X86_64_AVX2 +/* mldsa/src/cbmc.h */ +#undef MLD_CBMC_H +#undef __contract__ +#undef __loop__ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +/* + * Undefine macros from FIPS-202 files + */ +/* mldsa/src/fips202/fips202.h */ +#undef MLD_FIPS202_FIPS202_H +#undef MLD_KECCAK_LANES +#undef SHA3_256_HASHBYTES +#undef SHA3_256_RATE +#undef SHA3_512_HASHBYTES +#undef SHA3_512_RATE +#undef SHAKE128_RATE +#undef SHAKE256_RATE +#undef mld_shake128_absorb +#undef mld_shake128_finalize +#undef mld_shake128_init +#undef mld_shake128_release +#undef mld_shake128_squeeze +#undef mld_shake256 +#undef mld_shake256_absorb +#undef mld_shake256_finalize +#undef mld_shake256_init +#undef mld_shake256_release +#undef mld_shake256_squeeze +/* mldsa/src/fips202/fips202x4.h */ +#undef MLD_FIPS202_FIPS202X4_H +#undef mld_shake128x4_absorb_once +#undef mld_shake128x4_init +#undef mld_shake128x4_release +#undef mld_shake128x4_squeezeblocks +#undef mld_shake256x4_absorb_once +#undef mld_shake256x4_init +#undef mld_shake256x4_release +#undef mld_shake256x4_squeezeblocks +/* mldsa/src/fips202/keccakf1600.h */ +#undef MLD_FIPS202_KECCAKF1600_H +#undef MLD_KECCAK_LANES +#undef MLD_KECCAK_WAY +#undef mld_keccakf1600_extract_bytes +#undef mld_keccakf1600_permute +#undef mld_keccakf1600_xor_bytes +#undef mld_keccakf1600x4_extract_bytes +#undef mld_keccakf1600x4_permute +#undef mld_keccakf1600x4_xor_bytes +#endif /* !MLD_CONFIG_FIPS202_CUSTOM_HEADER */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +/* mldsa/src/fips202/native/api.h */ +#undef MLD_FIPS202_NATIVE_API_H +#undef MLD_NATIVE_FUNC_FALLBACK +#undef MLD_NATIVE_FUNC_SUCCESS +/* mldsa/src/fips202/native/auto.h */ +#undef MLD_FIPS202_NATIVE_AUTO_H +#if defined(MLD_SYS_AARCH64) +/* + * Undefine macros from native code (FIPS202, AArch64) + */ +/* mldsa/src/fips202/native/aarch64/auto.h */ +#undef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* mldsa/src/fips202/native/aarch64/src/fips202_native_aarch64.h */ +#undef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#undef mld_keccak_f1600_x1_scalar_asm +#undef mld_keccak_f1600_x1_v84a_asm +#undef mld_keccak_f1600_x2_v84a_asm +#undef mld_keccak_f1600_x4_scalar_v8a_hybrid_asm +#undef mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm +#undef mld_keccakf1600_round_constants +/* mldsa/src/fips202/native/aarch64/x1_scalar.h */ +#undef MLD_FIPS202_AARCH64_NEED_X1_SCALAR +#undef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#undef MLD_USE_FIPS202_X1_NATIVE +/* mldsa/src/fips202/native/aarch64/x1_v84a.h */ +#undef MLD_FIPS202_AARCH64_NEED_X1_V84A +#undef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#undef MLD_USE_FIPS202_X1_NATIVE +/* mldsa/src/fips202/native/aarch64/x2_v84a.h */ +#undef MLD_FIPS202_AARCH64_NEED_X2_V84A +#undef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#undef MLD_USE_FIPS202_X4_NATIVE +/* mldsa/src/fips202/native/aarch64/x4_v8a_scalar.h */ +#undef MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID +#undef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#undef MLD_USE_FIPS202_X4_NATIVE +/* mldsa/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h */ +#undef MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID +#undef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#undef MLD_USE_FIPS202_X4_NATIVE +#endif /* MLD_SYS_AARCH64 */ +#if defined(MLD_SYS_X86_64) +/* + * Undefine macros from native code (FIPS202, x86_64) + */ +/* mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h */ +#undef MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H +#undef mld_keccakf1600x4_permute24 +/* mldsa/src/fips202/native/x86_64/xkcp.h */ +#undef MLD_FIPS202_NATIVE_X86_64_XKCP_H +#undef MLD_FIPS202_X86_64_XKCP +#undef MLD_USE_FIPS202_X4_NATIVE +#endif /* MLD_SYS_X86_64 */ +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +/* mldsa/src/native/api.h */ +#undef MLD_INTT_BOUND +#undef MLD_NATIVE_API_H +#undef MLD_NATIVE_FUNC_FALLBACK +#undef MLD_NATIVE_FUNC_SUCCESS +#undef MLD_NTT_BOUND +#undef REDUCE32_RANGE_MAX +/* mldsa/src/native/meta.h */ +#undef MLD_NATIVE_META_H +#if defined(MLD_SYS_AARCH64) +/* + * Undefine macros from native code (Arith, AArch64) + */ +/* mldsa/src/native/aarch64/meta.h */ +#undef MLD_ARITH_BACKEND_AARCH64 +#undef MLD_NATIVE_AARCH64_META_H +#undef MLD_USE_NATIVE_INTT +#undef MLD_USE_NATIVE_NTT +#undef MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_17 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_19 +#undef MLD_USE_NATIVE_POLY_CADDQ +#undef MLD_USE_NATIVE_POLY_CHKNORM +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#undef MLD_USE_NATIVE_POLY_USE_HINT_32 +#undef MLD_USE_NATIVE_POLY_USE_HINT_88 +#undef MLD_USE_NATIVE_REJ_UNIFORM +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +/* mldsa/src/native/aarch64/src/arith_native_aarch64.h */ +#undef MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN +#undef MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN +#undef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#undef mld_aarch64_intt_zetas_layer123456 +#undef mld_aarch64_intt_zetas_layer78 +#undef mld_aarch64_ntt_zetas_layer123456 +#undef mld_aarch64_ntt_zetas_layer78 +#undef mld_intt_asm +#undef mld_ntt_asm +#undef mld_poly_caddq_asm +#undef mld_poly_chknorm_asm +#undef mld_poly_decompose_32_asm +#undef mld_poly_decompose_88_asm +#undef mld_poly_pointwise_montgomery_asm +#undef mld_poly_use_hint_32_asm +#undef mld_poly_use_hint_88_asm +#undef mld_polyvecl_pointwise_acc_montgomery_l4_asm +#undef mld_polyvecl_pointwise_acc_montgomery_l5_asm +#undef mld_polyvecl_pointwise_acc_montgomery_l7_asm +#undef mld_polyz_unpack_17_asm +#undef mld_polyz_unpack_17_indices +#undef mld_polyz_unpack_19_asm +#undef mld_polyz_unpack_19_indices +#undef mld_rej_uniform_asm +#undef mld_rej_uniform_eta2_asm +#undef mld_rej_uniform_eta4_asm +#undef mld_rej_uniform_eta_table +#undef mld_rej_uniform_table +#endif /* MLD_SYS_AARCH64 */ +#if defined(MLD_SYS_X86_64) +/* + * Undefine macros from native code (Arith, X86_64) + */ +/* mldsa/src/native/x86_64/meta.h */ +#undef MLD_ARITH_BACKEND_X86_64_DEFAULT +#undef MLD_NATIVE_X86_64_META_H +#undef MLD_USE_NATIVE_INTT +#undef MLD_USE_NATIVE_NTT +#undef MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#undef MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_17 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_19 +#undef MLD_USE_NATIVE_POLY_CADDQ +#undef MLD_USE_NATIVE_POLY_CHKNORM +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#undef MLD_USE_NATIVE_POLY_USE_HINT_32 +#undef MLD_USE_NATIVE_POLY_USE_HINT_88 +#undef MLD_USE_NATIVE_REJ_UNIFORM +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +/* mldsa/src/native/x86_64/src/arith_native_x86_64.h */ +#undef MLD_AVX2_REJ_UNIFORM_BUFLEN +#undef MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN +#undef MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN +#undef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#undef mld_invntt_avx2 +#undef mld_ntt_avx2 +#undef mld_nttunpack_avx2 +#undef mld_pointwise_acc_l4_avx2 +#undef mld_pointwise_acc_l5_avx2 +#undef mld_pointwise_acc_l7_avx2 +#undef mld_pointwise_avx2 +#undef mld_poly_caddq_avx2 +#undef mld_poly_chknorm_avx2 +#undef mld_poly_decompose_32_avx2 +#undef mld_poly_decompose_88_avx2 +#undef mld_poly_use_hint_32_avx2 +#undef mld_poly_use_hint_88_avx2 +#undef mld_polyz_unpack_17_avx2 +#undef mld_polyz_unpack_19_avx2 +#undef mld_rej_uniform_avx2 +#undef mld_rej_uniform_eta2_avx2 +#undef mld_rej_uniform_eta4_avx2 +#undef mld_rej_uniform_table +/* mldsa/src/native/x86_64/src/consts.h */ +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XQ +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV +#undef MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS +#undef MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV +#undef MLD_NATIVE_X86_64_SRC_CONSTS_H +#undef mld_qdata +#endif /* MLD_SYS_X86_64 */ +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ +#endif /* !MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/mldsa_native.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/mldsa_native.h new file mode 100644 index 0000000000..fd150a9df1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/mldsa_native.h @@ -0,0 +1,975 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_H +#define MLD_H + +/* + * Public API for mldsa-native + * + * This header defines the public API of a single build of mldsa-native. + * + * Make sure the configuration file is in the include path + * (this is "mldsa_native_config.h" by default, or MLD_CONFIG_FILE if defined). + * + * # Multi-level builds + * + * This header specifies a build of mldsa-native for a fixed security level. + * If you need multiple security levels, leave the security level unspecified + * in the configuration file and include this header multiple times, setting + * MLD_CONFIG_PARAMETER_SET accordingly for each, and #undef'ing the MLD_H + * guard to allow multiple inclusions. + * + * # Legacy configuration (deprecated) + * + * Instead of providing the config file used for the build, you can + * alternatively set the following configuration options prior to + * including this header. + * + * This method of configuration is deprecated. + * It will be removed in mldsa-native-v2. + * + * - MLD_CONFIG_API_PARAMETER_SET [required] + * + * The parameter set used for the build; 44, 65, or 87. + * + * - MLD_CONFIG_API_NAMESPACE_PREFIX [required] + * + * The namespace prefix used for the build. + * + * NOTE: + * For a multi-level build, you must include the 44/65/87 suffixes + * in MLD_CONFIG_API_NAMESPACE_PREFIX. + * + * - MLD_CONFIG_API_NO_SUPERCOP [optional] + * + * By default, this header will also expose the mldsa-native API in the + * SUPERCOP naming convention crypto_sign_xxx. If you don't want/need this, + * set MLD_CONFIG_API_NO_SUPERCOP. You must set this for a multi-level build. + * + * - MLD_CONFIG_API_CONSTANTS_ONLY [optional] + * + * If you don't want this header to expose any function declarations, + * but only constants for the sizes of key material, set + * MLD_CONFIG_API_CONSTANTS_ONLY. In this case, you don't need to set + * MLD_CONFIG_API_PARAMETER_SET or MLD_CONFIG_API_NAMESPACE_PREFIX, + * nor include a configuration. + * + * - MLD_CONFIG_API_QUALIFIER [optional] + * + * Qualifier to apply to external API. + * + ******************************************************************************/ + +/******************************* Key sizes ************************************/ + +/* Sizes of cryptographic material, per parameter set */ +/* See mldsa/src/params.h for the arithmetic expressions giving rise to these */ +/* check-magic: off */ +#define MLDSA44_SECRETKEYBYTES 2560 +#define MLDSA44_PUBLICKEYBYTES 1312 +#define MLDSA44_BYTES 2420 + +#define MLDSA65_SECRETKEYBYTES 4032 +#define MLDSA65_PUBLICKEYBYTES 1952 +#define MLDSA65_BYTES 3309 + +#define MLDSA87_SECRETKEYBYTES 4896 +#define MLDSA87_PUBLICKEYBYTES 2592 +#define MLDSA87_BYTES 4627 +/* check-magic: on */ + +/* Size of seed and randomness in bytes (level-independent) */ +#define MLDSA_SEEDBYTES 32 +#define MLDSA44_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA65_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA87_SEEDBYTES MLDSA_SEEDBYTES + +/* Size of CRH output in bytes (level-independent) */ +#define MLDSA_CRHBYTES 64 +#define MLDSA44_CRHBYTES MLDSA_CRHBYTES +#define MLDSA65_CRHBYTES MLDSA_CRHBYTES +#define MLDSA87_CRHBYTES MLDSA_CRHBYTES + +/* Size of TR output in bytes (level-independent) */ +#define MLDSA_TRBYTES 64 +#define MLDSA44_TRBYTES MLDSA_TRBYTES +#define MLDSA65_TRBYTES MLDSA_TRBYTES +#define MLDSA87_TRBYTES MLDSA_TRBYTES + +/* Size of randomness for signing in bytes (level-independent) */ +#define MLDSA_RNDBYTES 32 +#define MLDSA44_RNDBYTES MLDSA_RNDBYTES +#define MLDSA65_RNDBYTES MLDSA_RNDBYTES +#define MLDSA87_RNDBYTES MLDSA_RNDBYTES + +/* Sizes of cryptographic material, as a function of LVL=44,65,87 */ +#define MLDSA_SECRETKEYBYTES_(LVL) MLDSA##LVL##_SECRETKEYBYTES +#define MLDSA_PUBLICKEYBYTES_(LVL) MLDSA##LVL##_PUBLICKEYBYTES +#define MLDSA_BYTES_(LVL) MLDSA##LVL##_BYTES +#define MLDSA_SECRETKEYBYTES(LVL) MLDSA_SECRETKEYBYTES_(LVL) +#define MLDSA_PUBLICKEYBYTES(LVL) MLDSA_PUBLICKEYBYTES_(LVL) +#define MLDSA_BYTES(LVL) MLDSA_BYTES_(LVL) + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + +/****************************** Function API **********************************/ + +#define MLD_API_CONCAT_(x, y) x##y +#define MLD_API_CONCAT(x, y) MLD_API_CONCAT_(x, y) +#define MLD_API_CONCAT_UNDERSCORE(x, y) MLD_API_CONCAT(MLD_API_CONCAT(x, _), y) + +#if !defined(MLD_CONFIG_API_PARAMETER_SET) +/* Recommended configuration via same config file as used for the build. */ + +/* For now, we derive the legacy API configuration MLD_CONFIG_API_XXX from + * the config file. In mldsa-native-v2, this will be removed and we will + * exclusively work with MLD_CONFIG_XXX. */ + +/* You need to make sure the config file is in the include path. */ +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#define MLD_CONFIG_API_PARAMETER_SET MLD_CONFIG_PARAMETER_SET + +#if defined(MLD_CONFIG_MULTILEVEL_BUILD) +#define MLD_CONFIG_API_NAMESPACE_PREFIX \ + MLD_API_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_CONFIG_API_NAMESPACE_PREFIX MLD_CONFIG_NAMESPACE_PREFIX +#endif + +#if defined(MLD_CONFIG_NO_SUPERCOP) +#define MLD_CONFIG_API_NO_SUPERCOP +#endif + +#if defined(MLD_CONFIG_CONSTANTS_ONLY) +#define MLD_CONFIG_API_CONSTANTS_ONLY +#endif + +#if defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_CONFIG_API_QUALIFIER MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#else /* !MLD_CONFIG_API_PARAMETER_SET */ +#define MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_PARAMETER_SET */ + +#define MLD_API_NAMESPACE(sym) \ + MLD_API_CONCAT_UNDERSCORE(MLD_CONFIG_API_NAMESPACE_PREFIX, sym) + +#if defined(__GNUC__) || defined(clang) +#define MLD_API_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_API_MUST_CHECK_RETURN_VALUE +#endif + +#if defined(MLD_CONFIG_API_QUALIFIER) +#define MLD_API_QUALIFIER MLD_CONFIG_API_QUALIFIER +#else +#define MLD_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_API_CONSTANTS_ONLY) + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************************* + * Name: crypto_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: + * input random seed + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair_internal)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t seed[MLDSA_SEEDBYTES] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: If MLD_CONFIG_KEYGEN_PCT is enabled and the + * PCT check failed. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return -1 in that case. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_extmu + * + * Description: Computes signature. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_extmu)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t *sm: pointer to output signed message (allocated array + * with MLDSA{44,65,87}_BYTES + mlen bytes), can be + * equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(sign)( + uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_extmu)( + const uint8_t *sig, size_t siglen, const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_open + * + * Description: Verify signed message. + * + * Arguments: + * - uint8_t *m: pointer to output message (allocated array with + * smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(open)( + uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: crypto_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *ph, size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_shake256)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_shake256)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/* Maximum formatted domain separation message length */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +size_t MLD_API_NAMESPACE(prepare_domain_separation_prefix)( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg); + +/************************************************* + * Name: crypto_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[CRYPTO_SECRETKEYBYTES]: input secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(pk_from_sk)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +#ifdef __cplusplus +} +#endif + +/****************************** SUPERCOP API *********************************/ + +#if !defined(MLD_CONFIG_API_NO_SUPERCOP) +/* Export API in SUPERCOP naming scheme CRYPTO_xxx / crypto_sign_xxx */ +#define CRYPTO_SECRETKEYBYTES MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_PUBLICKEYBYTES MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_BYTES MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET) + +#define crypto_sign_keypair MLD_API_NAMESPACE(keypair) +#define crypto_sign_signature MLD_API_NAMESPACE(signature) +#define crypto_sign MLD_API_NAMESPACE(sign) +#define crypto_sign_verify MLD_API_NAMESPACE(verify) +#define crypto_sign_open MLD_API_NAMESPACE(open) + +#else /* !MLD_CONFIG_API_NO_SUPERCOP */ + +/* If the SUPERCOP API is not needed, we can undefine the various helper macros + * above. Otherwise, they are needed for lazy evaluation of crypto_sign_xxx. */ +#if !defined(MLD_API_LEGACY_CONFIG) +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_QUALIFIER +#endif /* !MLD_API_LEGACY_CONFIG */ + +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_NAMESPACE +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_QUALIFIER +#undef MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_NO_SUPERCOP */ +#endif /* !MLD_CONFIG_API_CONSTANTS_ONLY */ + + +/***************************** Memory Usage **********************************/ + +/* + * By default mldsa-native performs all memory allocations on the stack. + * Alternatively, mldsa-native supports custom allocation of large structures + * through the `MLD_CONFIG_CUSTOM_ALLOC_FREE` configuration option. + * See mldsa_native_config.h for details. + * + * `MLD_TOTAL_ALLOC_{44,65,87}_{KEYPAIR,SIGN,VERIFY}` indicates the maximum + * (accumulative) allocation via MLD_ALLOC for each parameter set and operation. + * Note that some stack allocation remains even + * when using custom allocators, so these values are lower than total stack + * usage with the default stack-only allocation. + * + * These constants may be used to implement custom allocations using a + * fixed-sized buffer and a simple allocator (e.g., bump allocator). + */ +/* check-magic: off */ +#if defined(MLD_API_LEGACY_CONFIG) || !defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 45248 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 56640 +#define MLD_TOTAL_ALLOC_44_SIGN 52896 +#define MLD_TOTAL_ALLOC_44_VERIFY 38816 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 71872 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 85856 +#define MLD_TOTAL_ALLOC_65_SIGN 80576 +#define MLD_TOTAL_ALLOC_65_VERIFY 62432 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 112832 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 130816 +#define MLD_TOTAL_ALLOC_87_SIGN 123584 +#define MLD_TOTAL_ALLOC_87_VERIFY 99552 +#else /* MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM */ +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 32992 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 36192 +#define MLD_TOTAL_ALLOC_44_SIGN 32448 +#define MLD_TOTAL_ALLOC_44_VERIFY 22464 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 46304 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 50048 +#define MLD_TOTAL_ALLOC_65_SIGN 44768 +#define MLD_TOTAL_ALLOC_65_VERIFY 30720 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 62688 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 66336 +#define MLD_TOTAL_ALLOC_87_SIGN 59104 +#define MLD_TOTAL_ALLOC_87_VERIFY 41216 +#endif /* !(MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM) */ +/* check-magic: on */ + +/* + * MLD_TOTAL_ALLOC_*_KEYPAIR adapts based on MLD_CONFIG_KEYGEN_PCT. + * For legacy config, we don't know which options are used, so assume + * the worst case (PCT enabled). + */ +#if defined(MLD_API_LEGACY_CONFIG) || defined(MLD_CONFIG_KEYGEN_PCT) +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#else +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#endif + +#define MLD_MAX3_(a, b, c) \ + ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c))) + +/* + * `MLD_TOTAL_ALLOC_{44,65,87}` is the maximum across all operations for each + * parameter set. + */ +#define MLD_TOTAL_ALLOC_44 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_44_KEYPAIR, MLD_TOTAL_ALLOC_44_SIGN, \ + MLD_TOTAL_ALLOC_44_VERIFY) +#define MLD_TOTAL_ALLOC_65 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_65_KEYPAIR, MLD_TOTAL_ALLOC_65_SIGN, \ + MLD_TOTAL_ALLOC_65_VERIFY) +#define MLD_TOTAL_ALLOC_87 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_87_KEYPAIR, MLD_TOTAL_ALLOC_87_SIGN, \ + MLD_TOTAL_ALLOC_87_VERIFY) + +#endif /* !MLD_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/mldsa_native_config.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/mldsa_native_config.h new file mode 100644 index 0000000000..cd9c692c9d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/mldsa_native_config.h @@ -0,0 +1,738 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/* + * Test configuration: Monolithic build config (native backends disabled) + * + * This configuration differs from the default mldsa/mldsa_native_config.h in + * the following places: + * - MLD_CONFIG_NAMESPACE_PREFIX + * - MLD_CONFIG_INTERNAL_API_QUALIFIER + */ + + +#ifndef MLD_CONFIG_H +#define MLD_CONFIG_H + +/****************************************************************************** + * Name: MLD_CONFIG_PARAMETER_SET + * + * Description: Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * If you want to support multiple parameter sets, build the + * library multiple times and set MLD_CONFIG_MULTILEVEL_BUILD. + * See MLD_CONFIG_MULTILEVEL_BUILD for how to do this while + * minimizing code duplication. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of the default configuration file mldsa/mldsa_native_config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * then configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + * + *****************************************************************************/ +/* No need to set this -- we _are_ already in a custom config */ +/* #define MLD_CONFIG_FILE "mldsa_native_config.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_NAMESPACE_PREFIX + * + * Description: The prefix to use to namespace global symbols from mldsa/. + * + * In a multi-level build, level-dependent symbols will + * additionally be prefixed with the parameter set (44/65/87). + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_NAMESPACE_PREFIX mldsa + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_BUILD + * + * Description: Set this if the build is part of a multi-level build supporting + * multiple parameter sets. + * + * If you need only a single parameter set, keep this unset. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them. + * + * See examples/multilevel_build for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_BUILD */ + +/****************************************************************************** + * Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_EXTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_RANDOMIZED_API + * + * Description: If this option is set, mldsa-native will be built without the + * randomized API functions (crypto_sign_keypair, + * crypto_sign, crypto_sign_signature, and + * crypto_sign_signature_extmu). + * This allows users to build mldsa-native without providing a + * randombytes() implementation if they only need the + * internal deterministic API + * (crypto_sign_keypair_internal, crypto_sign_signature_internal). + * + * NOTE: This option is incompatible with MLD_CONFIG_KEYGEN_PCT + * as the current PCT implementation requires + * crypto_sign_signature(). + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_RANDOMIZED_API */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_SUPERCOP + * + * Description: By default, mldsa_native.h exposes the mldsa-native API in the + * SUPERCOP naming convention (crypto_sign_xxx). If you don't need + * this, set MLD_CONFIG_NO_SUPERCOP. + * + * NOTE: You must set this for a multi-level build as the SUPERCOP + * naming does not disambiguate between the parameter sets. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_SUPERCOP */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONSTANTS_ONLY + * + * Description: If you only need the size constants (MLDSA_PUBLICKEYBYTES, etc.) + * but no function declarations, set MLD_CONFIG_CONSTANTS_ONLY. + * + * This only affects the public header mldsa_native.h, not + * the implementation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONSTANTS_ONLY */ + +/****************************************************************************** + * + * Build-only configuration options + * + * The remaining configurations are build-options only. + * They do not affect the API described in mldsa_native.h. + * + *****************************************************************************/ + +#if defined(MLD_BUILD_INTERNAL) +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_WITH_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, all MLD_CONFIG_PARAMETER_SET-independent + * code will be included in the build, including code needed only + * for other parameter sets. + * + * Example: TODO: add example + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_WITH_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_NO_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, no MLD_CONFIG_PARAMETER_SET-independent code + * will be included in the build. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * + * Description: This is only relevant for single compilation unit (SCU) + * builds of mldsa-native. In this case, it determines whether + * directives defined in parameter-set-independent headers should + * be #undef'ined or not at the of the SCU file. This is needed + * in multilevel builds. + * + * See examples/multilevel_build_native for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * + * Description: Determines whether an native arithmetic backend should be used. + * + * The arithmetic backend covers performance critical functions + * such as the number-theoretic transform (NTT). + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the arithmetic backend to be use is + * determined by MLD_CONFIG_ARITH_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_ARITH_BACKEND_FILE + * + * Description: The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * + * Description: Determines whether an native FIPS202 backend should be used. + * + * The FIPS202 backend covers 1x/2x/4x-fold Keccak-f1600, which is + * the performance bottleneck of SHA3 and SHAKE. + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the FIPS202 backend to be use is + * determined by MLD_CONFIG_FIPS202_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_BACKEND_FILE + * + * Description: The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202X4_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202-X4 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202x4.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ZEROIZE + * + * Description: In compliance with @[FIPS204, Section 3.6.3], mldsa-native, + * zeroizes intermediate stack buffers before returning from + * function calls. + * + * Set this option and define `mld_zeroize` if you want to + * use a custom method to zeroize intermediate stack buffers. + * The default implementation uses SecureZeroMemory on Windows + * and a memset + compiler barrier otherwise. If neither of those + * is available on the target platform, compilation will fail, + * and you will need to use MLD_CONFIG_CUSTOM_ZEROIZE to provide + * a custom implementation of `mld_zeroize()`. + * + * WARNING: + * The explicit stack zeroization conducted by mldsa-native + * reduces the likelihood of data leaking on the stack, but + * does not eliminate it! The C standard makes no guarantee about + * where a compiler allocates structures and whether/where it makes + * copies of them. Also, in addition to entire structures, there + * may also be potentially exploitable leakage of individual values + * on the stack. + * + * If you need bullet-proof zeroization of the stack, you need to + * consider additional measures instead of what this feature + * provides. In this case, you can set mld_zeroize to a + * no-op. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void mld_zeroize(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * Description: mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to provided by the + * consumer. + * + * If this option is not set, mldsa-native expects a function + * int randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mld_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_RANDOMBYTES + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) + { + ... your implementation ... + return 0; + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + * + * Description: mldsa-native backends may rely on specific hardware features. + * Those backends will only be included in an mldsa-native build + * if support for the respective features is enabled at + * compile-time. However, when building for a heteroneous set + * of CPUs to run the resulting binary/library on, feature + * detection at _runtime_ is needed to decided whether a backend + * can be used or not. + * + * Set this option and define `mld_sys_check_capability` if you + * want to use a custom method to dispatch between implementations. + * + * Return value 1 indicates that a capability is supported. + * Return value 0 indicates that a capability is not supported. + * + * If this option is not set, mldsa-native uses compile-time + * feature detection only to decide which backend to use. + * + * If you compile mldsa-native on a system with different + * capabilities than the system that the resulting binary/library + * will be run on, you must use this option. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) + { + ... your implementation ... + } +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ALLOC_FREE [EXPERIMENTAL] + * + * Description: Set this option and define `MLD_CUSTOM_ALLOC` and + * `MLD_CUSTOM_FREE` if you want to use custom allocation for + * large local structures or buffers. + * + * By default, all buffers/structures are allocated on the stack. + * If this option is set, most of them will be allocated via + * MLD_CUSTOM_ALLOC. + * + * Parameters to MLD_CUSTOM_ALLOC: + * - T* v: Target pointer to declare. + * - T: Type of structure to be allocated + * - N: Number of elements to be allocated. + * + * Parameters to MLD_CUSTOM_FREE: + * - T* v: Target pointer to free. May be NULL. + * - T: Type of structure to be freed. + * - N: Number of elements to be freed. + * + * WARNING: This option is experimental! + * Its scope, configuration and function/macro signatures may + * change at any time. We expect a stable API for v2. + * + * NOTE: Even if this option is set, some allocations further down + * the call stack will still be made from the stack. Those will + * likely be added to the scope of this option in the future. + * + * NOTE: MLD_CUSTOM_ALLOC need not guarantee a successful + * allocation nor include error handling. Upon failure, the + * target pointer should simply be set to NULL. The calling + * code will handle this case and invoke MLD_CUSTOM_FREE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ALLOC_FREE + #if !defined(__ASSEMBLER__) + #include + #define MLD_CUSTOM_ALLOC(v, T, N) \ + T* (v) = (T *)aligned_alloc(MLD_DEFAULT_ALIGN, \ + MLD_ALIGN_UP(sizeof(T) * (N))) + #define MLD_CUSTOM_FREE(v, T, N) free(v) + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMCPY + * + * Description: Set this option and define `mld_memcpy` if you want to + * use a custom method to copy memory instead of the standard + * library memcpy function. + * + * The custom implementation must have the same signature and + * behavior as the standard memcpy function: + * void *mld_memcpy(void *dest, const void *src, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMCPY + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMSET + * + * Description: Set this option and define `mld_memset` if you want to + * use a custom method to set memory instead of the standard + * library memset function. + * + * The custom implementation must have the same signature and + * behavior as the standard memset function: + * void *mld_memset(void *s, int c, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMSET + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memset(void *s, int c, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_INTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of internal API. + * + * The primary use case for this option are single-CU builds, + * in which case this option can be set to `static`. + * + *****************************************************************************/ +#define MLD_CONFIG_INTERNAL_API_QUALIFIER static + +/****************************************************************************** + * Name: MLD_CONFIG_CT_TESTING_ENABLED + * + * Description: If set, mldsa-native annotates data as secret / public using + * valgrind's annotations VALGRIND_MAKE_MEM_UNDEFINED and + * VALGRIND_MAKE_MEM_DEFINED, enabling various checks for secret- + * dependent control flow of variable time execution (depending + * on the exact version of valgrind installed). + * + *****************************************************************************/ +/* #define MLD_CONFIG_CT_TESTING_ENABLED */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * and MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT + * + * Description: Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, crypto_sign_keypair_internal and + * crypto_sign_keypair will return a non-zero error code if the + * PCT failed. + * + * NOTE: This feature will drastically lower the performance of + * key generation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * Description: If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "src/src.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Description: Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * NOTE: Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + * + *****************************************************************************/ +/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER + * + * Description: Set this to add a context parameter that is provided to public + * API functions and is then available in custom callbacks. + * + * The type of the context parameter is configured via + * MLD_CONFIG_CONTEXT_PARAMETER_TYPE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER_TYPE + * + * Description: Set this to define the type for the context parameter used by + * MLD_CONFIG_CONTEXT_PARAMETER. + * + * This is only relevant if MLD_CONFIG_CONTEXT_PARAMETER is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER_TYPE void* */ + +/****************************************************************************** + * Name: MLD_CONFIG_REDUCE_RAM [EXPERIMENTAL] + * + * Description: Set this to reduce RAM usage. + * This trades memory for performance. + * + * For expected memory usage, see the MLD_TOTAL_ALLOC_* constants + * defined in mldsa_native.h. + * + * This option is useful for embedded systems with tight RAM + * constraints but relaxed performance requirements. + * + * WARNING: This option is experimental! + * CBMC proofs do not currently cover this configuration option. + * Its scope and configuration may change at any time. + * + *****************************************************************************/ +/* #define MLD_CONFIG_REDUCE_RAM */ + +/************************* Config internals ********************************/ + +#endif /* MLD_BUILD_INTERNAL */ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace is + * + * PQCP_MLDSA_NATIVE_MLDSA_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_ + */ + +#if MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65 +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87 +#endif + +#endif /* !MLD_CONFIG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/cbmc.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/cbmc.h new file mode 100644 index 0000000000..8ed1ecb06b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/cbmc.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_CBMC_H +#define MLD_CBMC_H +/*************************************************** + * Basic replacements for __CPROVER_XXX contracts + ***************************************************/ +#ifndef CBMC + +#define __contract__(x) +#define __loop__(x) +#define cassert(x) + +#else /* !CBMC */ + +#include + +#define __contract__(x) x +#define __loop__(x) x + +/* https://diffblue.github.io/cbmc/contracts-assigns.html */ +#define assigns(...) __CPROVER_assigns(__VA_ARGS__) + +/* https://diffblue.github.io/cbmc/contracts-requires-ensures.html */ +#define requires(...) __CPROVER_requires(__VA_ARGS__) +#define ensures(...) __CPROVER_ensures(__VA_ARGS__) +/* https://diffblue.github.io/cbmc/contracts-loops.html */ +#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__) +#define decreases(...) __CPROVER_decreases(__VA_ARGS__) +/* cassert to avoid confusion with in-built assert */ +#define cassert(x) __CPROVER_assert(x, "cbmc assertion failed") +#define assume(...) __CPROVER_assume(__VA_ARGS__) + +/*************************************************** + * Macros for "expression" forms that may appear + * _inside_ top-level contracts. + ***************************************************/ + +/* + * function return value - useful inside ensures + * https://diffblue.github.io/cbmc/contracts-functions.html + */ +#define return_value (__CPROVER_return_value) + +/* + * assigns l-value targets + * https://diffblue.github.io/cbmc/contracts-assigns.html + */ +#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__) +#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__) +#define same_object(...) __CPROVER_same_object(__VA_ARGS__) + +/* + * Pointer-related predicates + * https://diffblue.github.io/cbmc/contracts-memory-predicates.html + */ +#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__) +#define readable(...) __CPROVER_r_ok(__VA_ARGS__) +#define writeable(...) __CPROVER_w_ok(__VA_ARGS__) + +/* Maximum supported buffer size + * + * Larger buffers may be supported, but due to internal modeling constraints + * in CBMC, the proofs of memory- and type-safety won't be able to run. + * + * If you find yourself in need for a buffer size larger than this, + * please contact the maintainers, so we can prioritize work to relax + * this somewhat artificial bound. + */ +#define MLD_MAX_BUFFER_SIZE (SIZE_MAX >> 12) + + +/* + * History variables + * https://diffblue.github.io/cbmc/contracts-history-variables.html + */ +#define old(...) __CPROVER_old(__VA_ARGS__) +#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__) + +/* + * Quantifiers + * Note that the range on qvar is _exclusive_ between qvar_lb .. qvar_ub + * https://diffblue.github.io/cbmc/contracts-quantifiers.html + */ + +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define forall(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> (predicate) \ + } + +#define exists(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_exists \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) && (predicate) \ + } +/* clang-format on */ + +/*************************************************** + * Convenience macros for common contract patterns + ***************************************************/ +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define CBMC_CONCAT_(left, right) left##right +#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right) + +#define array_bound_core(qvar, qvar_lb, qvar_ub, array_var, \ + value_lb, value_ub) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + (((int)(value_lb) <= ((array_var)[(qvar)])) && \ + (((array_var)[(qvar)]) < (int)(value_ub))) \ + } + +#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \ + array_bound_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (qvar_lb), \ + (qvar_ub), (array_var), (value_lb), (value_ub)) + +#define array_unchanged_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (int32_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged(array_var, N) \ + array_unchanged_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) + +#define array_unchanged_u64_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (uint64_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged_u64(array_var, N) \ + array_unchanged_u64_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) +/* clang-format on */ + +/* Wrapper around array_bound operating on absolute values. + * + * The absolute value bound `k` is exclusive. + * + * Note that since the lower bound in array_bound is inclusive, we have to + * raise it by 1 here. + */ +#define array_abs_bound(arr, lb, ub, k) \ + array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k)) + +#endif /* CBMC */ + +#endif /* !MLD_CBMC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/common.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/common.h new file mode 100644 index 0000000000..4a5bc8109d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/common.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_COMMON_H +#define MLD_COMMON_H + +#define MLD_BUILD_INTERNAL + +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#include "params.h" +#include "sys.h" + +/* Internal and public API have external linkage by default, but + * this can be overwritten by the user, e.g. for single-CU builds. */ +#if !defined(MLD_CONFIG_INTERNAL_API_QUALIFIER) +#define MLD_INTERNAL_API +#else +#define MLD_INTERNAL_API MLD_CONFIG_INTERNAL_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_EXTERNAL_API +#else +#define MLD_EXTERNAL_API MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#if defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) || \ + defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) +#define MLD_MULTILEVEL_BUILD +#endif + +#define MLD_CONCAT_(x1, x2) x1##x2 +#define MLD_CONCAT(x1, x2) MLD_CONCAT_(x1, x2) + +#if defined(MLD_MULTILEVEL_BUILD) +#define MLD_ADD_PARAM_SET(s) MLD_CONCAT(s, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_ADD_PARAM_SET(s) s +#endif + +#define MLD_NAMESPACE_PREFIX MLD_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, _) +#define MLD_NAMESPACE_PREFIX_KL \ + MLD_CONCAT(MLD_ADD_PARAM_SET(MLD_CONFIG_NAMESPACE_PREFIX), _) + +/* Functions are prefixed by MLD_CONFIG_NAMESPACE_PREFIX. + * + * If multiple parameter sets are used, functions depending on the parameter + * set are additionally prefixed with 44/65/87. See mldsa_native_config.h. + * + * Example: If MLD_CONFIG_NAMESPACE_PREFIX is PQCP_MLDSA_NATIVE, then + * MLD_NAMESPACE_KL(keypair) becomes PQCP_MLDSA_NATIVE44_keypair/ + * PQCP_MLDSA_NATIVE65_keypair/PQCP_MLDSA_NATIVE87_keypair. + */ +#define MLD_NAMESPACE(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX, s) +#define MLD_NAMESPACE_KL(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX_KL, s) + +/* On Apple platforms, we need to emit leading underscore + * in front of assembly symbols. We thus introducee a separate + * namespace wrapper for ASM symbols. */ +#if !defined(__APPLE__) +#define MLD_ASM_NAMESPACE(sym) MLD_NAMESPACE(sym) +#else +#define MLD_ASM_NAMESPACE(sym) MLD_CONCAT(_, MLD_NAMESPACE(sym)) +#endif + +/* + * On X86_64 if control-flow protections (CET) are enabled (through + * -fcf-protection=), we add an endbr64 instruction at every global function + * label. See sys.h for more details + */ +#if defined(MLD_SYS_X86_64) +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : MLD_CET_ENDBR +#else +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : +#endif + +/* We aim to simplify the user's life by supporting builds where + * all source files are included, even those that are not needed. + * Those files are appropriately guarded and will be empty when unneeded. + * The following is to avoid compilers complaining about this. */ +#define MLD_EMPTY_CU(s) extern int MLD_NAMESPACE_KL(empty_cu_##s); + +/* MLD_CONFIG_NO_ASM takes precedence over MLD_USE_NATIVE_XXX */ +#if defined(MLD_CONFIG_NO_ASM) +#undef MLD_CONFIG_USE_NATIVE_BACKEND_ARITH +#undef MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, but MLD_CONFIG_ARITH_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, but MLD_CONFIG_FIPS202_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_NO_RANDOMIZED_API) && defined(MLD_CONFIG_KEYGEN_PCT) +#error Bad configuration: MLD_CONFIG_NO_RANDOMIZED_API is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires crypto_sign_signature() +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#include MLD_CONFIG_ARITH_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#include MLD_CONFIG_FIPS202_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "fips202/native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#define MLD_FIPS202_HEADER_FILE "fips202/fips202.h" +#else +#define MLD_FIPS202_HEADER_FILE MLD_CONFIG_FIPS202_CUSTOM_HEADER +#endif + +#if !defined(MLD_CONFIG_FIPS202X4_CUSTOM_HEADER) +#define MLD_FIPS202X4_HEADER_FILE "fips202/fips202x4.h" +#else +#define MLD_FIPS202X4_HEADER_FILE MLD_CONFIG_FIPS202X4_CUSTOM_HEADER +#endif + +/* Standard library function replacements */ +#if !defined(__ASSEMBLER__) +#if !defined(MLD_CONFIG_CUSTOM_MEMCPY) +#include +#define mld_memcpy memcpy +#endif + +#if !defined(MLD_CONFIG_CUSTOM_MEMSET) +#include +#define mld_memset memset +#endif + +/* Allocation macros for large local structures + * + * MLD_ALLOC(v, T, N) declares T *v and attempts to point it to an T[N] + * MLD_FREE(v, T, N) zeroizes and frees the allocation + * + * Default implementation uses stack allocation. + * Can be overridden by setting the config option MLD_CONFIG_CUSTOM_ALLOC_FREE + * and defining MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE. + */ +#if defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) != \ + (defined(MLD_CUSTOM_ALLOC) && defined(MLD_CUSTOM_FREE)) +#error Bad configuration: MLD_CONFIG_CUSTOM_ALLOC_FREE must be set together with MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE +#endif + +/* + * If the integration wants to provide a context parameter for use in + * platform-specific hooks, then it should define this parameter. + * + * The MLD_CONTEXT_PARAMETERS_n macros are intended to be used with macros + * defining the function names and expand to either pass or discard the context + * argument as required by the current build. If there is no context parameter + * requested then these are removed from the prototypes and from all calls. + */ +#ifdef MLD_CONFIG_CONTEXT_PARAMETER +#define MLD_CONTEXT_PARAMETERS_0(context) (context) +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0, context) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1, context) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) \ + (arg0, arg1, arg2, context) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3, context) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4, context) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, context) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, context) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, context) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, context) +#else /* MLD_CONFIG_CONTEXT_PARAMETER */ +#define MLD_CONTEXT_PARAMETERS_0(context) () +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) (arg0, arg1, arg2) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) +#endif /* !MLD_CONFIG_CONTEXT_PARAMETER */ + +#if defined(MLD_CONFIG_CONTEXT_PARAMETER_TYPE) != \ + defined(MLD_CONFIG_CONTEXT_PARAMETER) +#error MLD_CONFIG_CONTEXT_PARAMETER_TYPE must be defined if and only if MLD_CONFIG_CONTEXT_PARAMETER is defined +#endif + +#if !defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) +/* Default: stack allocation */ + +#define MLD_ALLOC(v, T, N, context) \ + MLD_ALIGN T mld_alloc_##v[N]; \ + T *v = mld_alloc_##v + +/* TODO: This leads to a circular dependency between common and ct.h + * It just works out before we're at the end of the file, but it's still + * prone to issues in the future. */ +#include "ct.h" +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + mld_zeroize(mld_alloc_##v, sizeof(mld_alloc_##v)); \ + (v) = NULL; \ + } while (0) + +#else /* !MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* Custom allocation */ + +/* + * The indirection here is necessary to use MLD_CONTEXT_PARAMETERS_3 here. + */ +#define MLD_APPLY(f, args) f args + +#define MLD_ALLOC(v, T, N, context) \ + MLD_APPLY(MLD_CUSTOM_ALLOC, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)) + +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + if (v != NULL) \ + { \ + mld_zeroize(v, sizeof(T) * (N)); \ + MLD_APPLY(MLD_CUSTOM_FREE, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)); \ + v = NULL; \ + } \ + } while (0) + +#endif /* MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* + * We are facing severe CBMC performance issues when using unions. + * As a temporary workaround, we use unions only when MLD_CONFIG_REDUCE_RAM is + * set. + * TODO: Remove the workaround once + * https://github.com/diffblue/cbmc/issues/8813 + * is resolved + */ +#if defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_UNION_OR_STRUCT union +#else +#define MLD_UNION_OR_STRUCT struct +#endif + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_COMMON_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/ct.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/ct.c new file mode 100644 index 0000000000..010b1a52a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/ct.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include "ct.h" + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +/* + * Masking value used in constant-time functions from + * ct.h to block the compiler's range analysis and + * thereby reduce the risk of compiler-introduced branches. + */ +volatile uint64_t mld_ct_opt_blocker_u64 = 0; + +#else /* !MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(ct) + +#endif /* !(!MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/ct.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/ct.h new file mode 100644 index 0000000000..c307456468 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/ct.h @@ -0,0 +1,366 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [libmceliece] + * libmceliece implementation of Classic McEliece + * Bernstein, Chou + * https://lib.mceliece.org/ + * + * - [optblocker] + * PQC forum post on opt-blockers using volatile globals + * Daniel J. Bernstein + * https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ + */ + +#ifndef MLD_CT_H +#define MLD_CT_H + +#include +#include "cbmc.h" +#include "common.h" + +/* Constant-time comparisons and conditional operations + + We reduce the risk for compilation into variable-time code + through the use of 'value barriers'. + + Functionally, a value barrier is a no-op. To the compiler, however, + it constitutes an arbitrary modification of its input, and therefore + harden's value propagation and range analysis. + + We consider two approaches to implement a value barrier: + - An empty inline asm block which marks the target value as clobbered. + - XOR'ing with the value of a volatile global that's set to 0; + see @[optblocker] for a discussion of this idea, and + @[libmceliece, inttypes/crypto_intN.h] for an implementation. + + The first approach is cheap because it only prevents the compiler + from reasoning about the value of the variable past the barrier, + but does not directly generate additional instructions. + + The second approach generates redundant loads and XOR operations + and therefore comes at a higher runtime cost. However, it appears + more robust towards optimization, as compilers should never drop + a volatile load. + + We use the empty-ASM value barrier for GCC and clang, and fall + back to the global volatile barrier otherwise. + + The global value barrier can be forced by setting + MLD_CONFIG_NO_ASM_VALUE_BARRIER. + +*/ + +#if defined(MLD_HAVE_INLINE_ASM) && !defined(MLD_CONFIG_NO_ASM_VALUE_BARRIER) +#define MLD_USE_ASM_VALUE_BARRIER +#endif + + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) +/* + * Declaration of global volatile that the global value barrier + * is loading from and masking with. + */ +#define mld_ct_opt_blocker_u64 MLD_NAMESPACE(ct_opt_blocker_u64) +extern volatile uint64_t mld_ct_opt_blocker_u64; + + +/* Helper functions for obtaining global masks of various sizes */ + +/* This contract is not proved but treated as an axiom. + * + * Its validity relies on the assumption that the global opt-blocker + * constant mld_ct_opt_blocker_u64 is not modified. + */ +static MLD_INLINE uint64_t mld_ct_get_optblocker_u64(void) +__contract__(ensures(return_value == 0)) { return mld_ct_opt_blocker_u64; } + +static MLD_INLINE int64_t mld_ct_get_optblocker_i64(void) +__contract__(ensures(return_value == 0)) { return (int64_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint32_t mld_ct_get_optblocker_u32(void) +__contract__(ensures(return_value == 0)) { return (uint32_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint8_t mld_ct_get_optblocker_u8(void) +__contract__(ensures(return_value == 0)) { return (uint8_t)mld_ct_get_optblocker_u64(); } + +/* Opt-blocker based implementation of value barriers */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_i64()); } + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u32()); } + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u8()); } + + +#else /* !MLD_USE_ASM_VALUE_BARRIER */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} +#endif /* MLD_USE_ASM_VALUE_BARRIER */ + +#ifdef CBMC +#pragma CPROVER check push +#pragma CPROVER check disable "conversion" +#endif + +/************************************************* + * Name: mld_cast_uint32_to_int32 + * + * Description: Cast uint32 value to int32 + * + * Returns: For uint32_t x, the unique y in int32_t + * so that x == y mod 2^32. + * + * Concretely: + * - x < 2^31: returns x + * - x >= 2^31: returns x - 2^31 + * + **************************************************/ +static MLD_ALWAYS_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x) +{ + /* + * PORTABILITY: This relies on uint32_t -> int32_t + * being implemented as the inverse of int32_t -> uint32_t, + * which is implementation-defined (C99 6.3.1.3 (3)) + * CBMC (correctly) fails to prove this conversion is OK, + * so we have to suppress that check here + */ + return (int32_t)x; +} + +#ifdef CBMC +#pragma CPROVER check pop +#endif + + +/************************************************* + * Name: mld_cast_int64_to_uint32 + * + * Description: Cast int64 value to uint32 as per C standard. + * + * Returns: For int64_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int64_to_uint32(int64_t x) +{ + return (uint32_t)(x & (int64_t)UINT32_MAX); +} + +/************************************************* + * Name: mld_cast_int32_to_uint32 + * + * Description: Cast int32 value to uint32 as per C standard. + * + * Returns: For int32_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int32_to_uint32(int32_t x) +{ + return mld_cast_int64_to_uint32((int64_t)x); +} + +/************************************************* + * Name: mld_ct_sel_int32 + * + * Description: Functionally equivalent to cond ? a : b, + * but implemented with guards against + * compiler-introduced branches. + * + * Arguments: int32_t a: First alternative + * int32_t b: Second alternative + * uint32_t cond: Condition variable. + * + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_sel_int32(int32_t a, int32_t b, uint32_t cond) +__contract__( + requires(cond == 0x0 || cond == 0xFFFFFFFF) + ensures(return_value == (cond ? a : b)) +) +{ + uint32_t au = mld_cast_int32_to_uint32(a); + uint32_t bu = mld_cast_int32_to_uint32(b); + uint32_t res = bu ^ (mld_value_barrier_u32(cond) & (au ^ bu)); + return mld_cast_uint32_to_int32(res); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u32 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_nonzero_u32(uint32_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFFFFFFFF))) +{ + int64_t tmp = mld_value_barrier_i64(-((int64_t)x)); + tmp >>= 32; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u8 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint8_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint8_t mld_ct_cmask_nonzero_u8(uint8_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFF))) +{ + uint32_t mask = mld_ct_cmask_nonzero_u32((uint32_t)x); + return (uint8_t)(mask & 0xFF); +} + +/************************************************* + * Name: mld_ct_cmask_neg_i32 + * + * Description: Return 0 if input is non-negative, and -1 otherwise. + * + * Arguments: int32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_neg_i32(int32_t x) +__contract__( + ensures(return_value == ((x < 0) ? 0xFFFFFFFF : 0)) +) +{ + int64_t tmp = mld_value_barrier_i64((int64_t)x); + tmp >>= 31; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_abs_i32 + * + * Description: Return -x if x<0, x otherwise + * + * Arguments: int32_t x: Input value + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_abs_i32(int32_t x) +__contract__( + requires(x >= -INT32_MAX) + ensures(return_value == ((x < 0) ? -x : x)) +) +{ + return mld_ct_sel_int32(-x, x, mld_ct_cmask_neg_i32(x)); +} + +/************************************************* + * Name: mld_ct_memcmp + * + * Description: Compare two arrays for equality in constant time. + * + * Arguments: const uint8_t *a: pointer to first byte array + * const uint8_t *b: pointer to second byte array + * size_t len: length of the byte arrays, upper-bounded + * to UINT16_MAX to control proof complexity + * only. + * + * Returns 0 if the byte arrays are equal, 0xFF otherwise. + **************************************************/ +static MLD_INLINE uint8_t mld_ct_memcmp(const uint8_t *a, const uint8_t *b, + const size_t len) +__contract__( + requires(len <= UINT16_MAX) + requires(memory_no_alias(a, len)) + requires(memory_no_alias(b, len)) + ensures((return_value == 0) || (return_value == 0xFF)) + ensures((return_value == 0) == forall(i, 0, len, (a[i] == b[i])))) +{ + uint8_t r = 0, s = 0; + unsigned i; + + for (i = 0; i < len; i++) + __loop__( + invariant(i <= len) + invariant((r == 0) == (forall(k, 0, i, (a[k] == b[k]))))) + { + r |= a[i] ^ b[i]; + /* s is useless, but prevents the loop from being aborted once r=0xff. */ + s ^= a[i] ^ b[i]; + } + + /* + * - Convert r into a mask; this may not be necessary, but is an additional + * safeguard + * towards leaking information about a and b. + * - XOR twice with s, separated by a value barrier, to prevent the compile + * from dropping the s computation in the loop. + */ + return (mld_value_barrier_u8(mld_ct_cmask_nonzero_u8(r) ^ s) ^ s); +} + +/************************************************* + * Name: mld_zeroize + * + * Description: Force-zeroize a buffer. + * @[FIPS204, Section 3.6.3] Destruction of intermediate + * values. + * + * Arguments: void *ptr: pointer to buffer to be zeroed + * size_t len: Amount of bytes to be zeroed + **************************************************/ +#if !defined(MLD_CONFIG_CUSTOM_ZEROIZE) +#if defined(MLD_SYS_WINDOWS) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) { SecureZeroMemory(ptr, len); } +#elif defined(MLD_HAVE_INLINE_ASM) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) +{ + memset(ptr, 0, len); + /* This follows OpenSSL and seems sufficient to prevent the compiler + * from optimizing away the memset. + * + * If there was a reliable way to detect availability of memset_s(), + * that would be preferred. */ + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +} +#else /* !MLD_SYS_WINDOWS && MLD_HAVE_INLINE_ASM */ +#error No plausibly-secure implementation of mld_zeroize available. Please provide your own using MLD_CONFIG_CUSTOM_ZEROIZE. +#endif /* !MLD_SYS_WINDOWS && !MLD_HAVE_INLINE_ASM */ +#endif /* !MLD_CONFIG_CUSTOM_ZEROIZE */ + +#endif /* !MLD_CT_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/debug.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/debug.c new file mode 100644 index 0000000000..a55d51e8b1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/debug.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* NOTE: You can remove this file unless you compile with MLDSA_DEBUG. */ + +#include "common.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#if defined(MLDSA_DEBUG) + +#include +#include +#include +#include "debug.h" + +#define MLD_DEBUG_ERROR_HEADER "[ERROR:%s:%04d] " + +void mld_debug_check_assert(const char *file, int line, const int val) +{ + if (val == 0) + { + fprintf(stderr, MLD_DEBUG_ERROR_HEADER "Assertion failed (value %d)\n", + file, line, val); + exit(1); + } +} + +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive) +{ + int err = 0; + unsigned i; + for (i = 0; i < len; i++) + { + int32_t val = ptr[i]; + if (!(val > lower_bound_exclusive && val < upper_bound_exclusive)) + { + fprintf(stderr, + MLD_DEBUG_ERROR_HEADER + "Bounds assertion failed: Index %u, value %d out of bounds " + "(%" PRId64 ",%" PRId64 ")\n", + file, line, i, (int)val, lower_bound_exclusive, + upper_bound_exclusive); + err = 1; + } + } + + if (err == 1) + { + exit(1); + } +} + +#else /* MLDSA_DEBUG */ + +MLD_EMPTY_CU(debug) + +#endif /* !MLDSA_DEBUG */ + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(debug) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_DEBUG_ERROR_HEADER diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/debug.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/debug.h new file mode 100644 index 0000000000..af187bb9de --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/debug.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_DEBUG_H +#define MLD_DEBUG_H +#include "common.h" + +#if defined(MLDSA_DEBUG) +#include + +/************************************************* + * Name: mld_assert + * + * Description: Check debug assertion + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - val: Value asserted to be non-zero + **************************************************/ +#define mld_debug_check_assert MLD_NAMESPACE(mldsa_debug_assert) +void mld_debug_check_assert(const char *file, int line, const int val); + +/************************************************* + * Name: mld_debug_check_bounds + * + * Description: Check whether values in an array of int32_t + * are within specified bounds. + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - ptr: Base of array to be checked + * - len: Number of int32_t in ptr + * - lower_bound_exclusive: Exclusive lower bound + * - upper_bound_exclusive: Exclusive upper bound + **************************************************/ +#define mld_debug_check_bounds MLD_NAMESPACE(mldsa_debug_check_bounds) +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive); + +/* Check assertion, calling exit() upon failure + * + * val: Value that's asserted to be non-zero + */ +#define mld_assert(val) mld_debug_check_assert(__FILE__, __LINE__, (val)) + +/* Check bounds in array of int32_t's + * ptr: Base of int32_t array; will be explicitly cast to int32_t*, + * so you may pass a byte-compatible type such as mld_poly or mld_polyvec. + * len: Number of int32_t in array + * value_lb: Inclusive lower value bound + * value_ub: Exclusive upper value bound */ +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + mld_debug_check_bounds(__FILE__, __LINE__, (const int32_t *)(ptr), (len), \ + ((int64_t)(value_lb)) - 1, (value_ub)) + +/* Check absolute bounds in array of int32_t's + * ptr: Base of array, expression of type int32_t* + * len: Number of int32_t in array + * value_abs_bd: Exclusive absolute upper bound */ +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + mld_assert_bound((ptr), (len), (-((int64_t)(value_abs_bd)) + 1), \ + (value_abs_bd)) + +/* Version of bounds assertions for 2-dimensional arrays */ +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + mld_assert_bound((ptr), ((len0) * (len1)), (value_lb), (value_ub)) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + mld_assert_abs_bound((ptr), ((len0) * (len1)), (value_abs_bd)) + +/* When running CBMC, convert debug assertions into proof obligations */ +#elif defined(CBMC) +#include "cbmc.h" + +#define mld_assert(val) cassert(val) + +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + cassert(array_bound(((int32_t *)(ptr)), 0, (len), (value_lb), (value_ub))) + +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + cassert(array_abs_bound(((int32_t *)(ptr)), 0, (len), (value_abs_bd))) + +/* Because of https://github.com/diffblue/cbmc/issues/8570, we can't + * just use a single flattened array_bound(...) here. */ +#define mld_assert_bound_2d(ptr, M, N, value_lb, value_ub) \ + cassert(forall(kN, 0, (M), \ + array_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_lb), (value_ub)))) + +#define mld_assert_abs_bound_2d(ptr, M, N, value_abs_bd) \ + cassert(forall(kN, 0, (M), \ + array_abs_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_abs_bd)))) + +#else /* !MLDSA_DEBUG && CBMC */ + +#define mld_assert(val) \ + do \ + { \ + } while (0) +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + do \ + { \ + } while (0) +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + do \ + { \ + } while (0) + +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + do \ + { \ + } while (0) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + do \ + { \ + } while (0) + + +#endif /* !MLDSA_DEBUG && !CBMC */ +#endif /* !MLD_DEBUG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/fips202.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/fips202.c new file mode 100644 index 0000000000..1112de061c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/fips202.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "../common.h" +#include "../ct.h" +#include "fips202.h" +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +/************************************************* + * Name: keccak_init + * + * Description: Initializes the Keccak state. + * + * Arguments: - uint64_t *s: pointer to Keccak state + **************************************************/ +static void keccak_init(uint64_t s[MLD_KECCAK_LANES]) +__contract__( + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + mld_memset(s, 0, sizeof(uint64_t) * MLD_KECCAK_LANES); +} + +/************************************************* + * Name: keccak_absorb + * + * Description: Absorb step of Keccak; incremental. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_absorb(uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r, + const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(pos <= r) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(in, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + ensures(return_value < r)) +{ + while (inlen >= r - pos) + __loop__( + assigns(pos, in, inlen, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + invariant(inlen <= loop_entry(inlen)) + invariant(pos <= r) + invariant(in == loop_entry(in) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600_xor_bytes(s, in, pos, r - pos); + inlen -= r - pos; + in += r - pos; + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: At this point, inlen < r, so the truncation to unsigned is safe. */ + mld_keccakf1600_xor_bytes(s, in, pos, (unsigned)inlen); + + /* Safety: At this point, inlen < r and pos <= r so the truncation to unsigned + * is safe. */ + return (unsigned)(pos + inlen); +} + +/************************************************* + * Name: keccak_finalize + * + * Description: Finalize absorb step. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - uint8_t p: domain separation byte + **************************************************/ +static void keccak_finalize(uint64_t s[MLD_KECCAK_LANES], unsigned int pos, + unsigned int r, uint8_t p) +__contract__( + requires(pos <= r && r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires((r / 8) >= 1) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + uint8_t b = 0x80; + mld_keccakf1600_xor_bytes(s, &p, pos, 1); + mld_keccakf1600_xor_bytes(s, &b, r - 1, 1); +} + +/************************************************* + * Name: keccak_squeeze + * + * Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes. + * Modifies the state. Can be called multiple times to keep + * squeezing, i.e., is incremental. + * + * Arguments: - uint8_t *out: pointer to output data + * - size_t outlen: number of bytes to be squeezed (written to out) + * - uint64_t *s: pointer to input/output Keccak state + * - unsigned int pos: number of bytes in current block already + *squeezed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_squeeze(uint8_t *out, size_t outlen, + uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r) +__contract__( + requires((r == SHAKE128_RATE && pos <= SHAKE128_RATE) || + (r == SHAKE256_RATE && pos <= SHAKE256_RATE) || + (r == SHA3_512_RATE && pos <= SHA3_512_RATE)) + requires(outlen <= 8 * r /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(out, outlen)) + ensures(return_value <= r)) +{ + unsigned int i; + size_t out_offset = 0; + + /* Reference: This code is re-factored from the reference implementation + * to facilitate proof with CBMC and to improve readability. + * + * Take a mutable copy of outlen to count down the number of bytes + * still to squeeze. The initial value of outlen is needed for the CBMC + * assigns() clauses. */ + size_t bytes_to_go = outlen; + + while (bytes_to_go > 0) + __loop__( + assigns(i, bytes_to_go, pos, out_offset, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES), memory_slice(out, outlen)) + invariant(bytes_to_go <= outlen) + invariant(out_offset == outlen - bytes_to_go) + invariant(pos <= r) + ) + { + if (pos == r) + { + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: If bytes_to_go < r - pos, truncation to unsigned is safe. */ + i = bytes_to_go < r - pos ? (unsigned)bytes_to_go : r - pos; + mld_keccakf1600_extract_bytes(s, out + out_offset, pos, i); + bytes_to_go -= i; + pos += i; + out_offset += i; + } + + return pos; +} + +void mld_shake128_init(mld_shake128ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE128_RATE, in, inlen); +} + +void mld_shake128_finalize(mld_shake128ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE128_RATE, 0x1F); + state->pos = SHAKE128_RATE; +} + +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE128_RATE); +} + +void mld_shake128_release(mld_shake128ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128ctx)); +} + +void mld_shake256_init(mld_shake256ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); +} + +void mld_shake256_finalize(mld_shake256ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); + state->pos = SHAKE256_RATE; +} + +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); +} + +void mld_shake256_release(mld_shake256ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256ctx)); +} + +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +{ + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, in, inlen); + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/fips202.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/fips202.h new file mode 100644 index 0000000000..9f0253cb88 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/fips202.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202_H +#define MLD_FIPS202_FIPS202_H + +#include +#include +#include "../cbmc.h" +#include "../common.h" + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 +#define SHA3_256_RATE 136 +#define SHA3_512_RATE 72 +#define MLD_KECCAK_LANES 25 +#define SHA3_256_HASHBYTES 32 +#define SHA3_512_HASHBYTES 64 + + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake128ctx; + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake256ctx; + +#define mld_shake128_init MLD_NAMESPACE(shake128_init) +/************************************************* + * Name: mld_shake128_init + * + * Description: Initializes state for use as SHAKE128 XOF + * + * Arguments: - mld_shake128ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake128_init(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos == 0) +); + +#define mld_shake128_absorb MLD_NAMESPACE(shake128_absorb) +/************************************************* + * Name: mld_shake128_absorb + * + * Description: Absorb step of the SHAKE128 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake128ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_finalize MLD_NAMESPACE(shake128_finalize) +/************************************************* + * Name: mld_shake128_finalize + * + * Description: Concludes the absorb phase of the SHAKE128 XOF. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_finalize(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_squeeze MLD_NAMESPACE(shake128_squeeze) +/************************************************* + * Name: mld_shake128_squeeze + * + * Description: Squeeze step of SHAKE128 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake128ctx *s: pointer to input/output state + **************************************************/ +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE128_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_release MLD_NAMESPACE(shake128_release) +/************************************************* + * Name: mld_shake128_release + * + * Description: Release and securely zero the SHAKE128 state. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_release(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) +); + +#define mld_shake256_init MLD_NAMESPACE(shake256_init) +/************************************************* + * Name: mld_shake256_init + * + * Description: Initializes state for use as SHAKE256 XOF + * + * Arguments: - mld_shake256ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake256_init(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos == 0) +); + +#define mld_shake256_absorb MLD_NAMESPACE(shake256_absorb) +/************************************************* + * Name: mld_shake256_absorb + * + * Description: Absorb step of the SHAKE256 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake256ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_finalize MLD_NAMESPACE(shake256_finalize) +/************************************************* + * Name: mld_shake256_finalize + * + * Description: Concludes the absorb phase of the SHAKE256 XOF. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_finalize(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_squeeze MLD_NAMESPACE(shake256_squeeze) +/************************************************* + * Name: mld_shake256_squeeze + * + * Description: Squeeze step of SHAKE256 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake256ctx *s: pointer to input/output state + **************************************************/ +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_release MLD_NAMESPACE(shake256_release) +/************************************************* + * Name: mld_shake256_release + * + * Description: Release and securely zero the SHAKE256 state. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_release(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) +); + +#define mld_shake256 MLD_NAMESPACE(shake256) +/************************************************* + * Name: mld_shake256 + * + * Description: SHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +); + +#endif /* !MLD_FIPS202_FIPS202_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/fips202x4.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/fips202x4.c new file mode 100644 index 0000000000..0fb5cd57c7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/fips202x4.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include "../common.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "../ct.h" +#include "fips202.h" +#include "fips202x4.h" +#include "keccakf1600.h" + +static void mld_keccak_absorb_once_x4(uint64_t *s, uint32_t r, + const uint8_t *in0, const uint8_t *in1, + const uint8_t *in2, const uint8_t *in3, + size_t inlen, uint8_t p) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))) +{ + while (inlen >= r) + __loop__( + assigns(inlen, in0, in1, in2, in3, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + invariant(inlen <= loop_entry(inlen)) + invariant(in0 == loop_entry(in0) + (loop_entry(inlen) - inlen)) + invariant(in1 == loop_entry(in1) + (loop_entry(inlen) - inlen)) + invariant(in2 == loop_entry(in2) + (loop_entry(inlen) - inlen)) + invariant(in3 == loop_entry(in3) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, r); + mld_keccakf1600x4_permute(s); + + in0 += r; + in1 += r; + in2 += r; + in3 += r; + inlen -= r; + } + + /* Safety: At this point, inlen < r, so the truncations to unsigned are safe + * below. */ + if (inlen > 0) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, (unsigned)inlen); + } + + if (inlen == r - 1) + { + p |= 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + } + else + { + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + p = 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, r - 1, 1); + } +} + +static void mld_keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1, + uint8_t *out2, uint8_t *out3, + size_t nblocks, uint64_t *s, uint32_t r) +__contract__( + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(out0, nblocks * r)) + requires(memory_no_alias(out1, nblocks * r)) + requires(memory_no_alias(out2, nblocks * r)) + requires(memory_no_alias(out3, nblocks * r)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(out0, nblocks * r)) + assigns(memory_slice(out1, nblocks * r)) + assigns(memory_slice(out2, nblocks * r)) + assigns(memory_slice(out3, nblocks * r))) +{ + while (nblocks > 0) + __loop__( + assigns(out0, out1, out2, out3, nblocks, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY), + memory_slice(out0, nblocks * r), + memory_slice(out1, nblocks * r), + memory_slice(out2, nblocks * r), + memory_slice(out3, nblocks * r)) + invariant(nblocks <= loop_entry(nblocks) && + out0 == loop_entry(out0) + r * (loop_entry(nblocks) - nblocks) && + out1 == loop_entry(out1) + r * (loop_entry(nblocks) - nblocks) && + out2 == loop_entry(out2) + r * (loop_entry(nblocks) - nblocks) && + out3 == loop_entry(out3) + r * (loop_entry(nblocks) - nblocks))) + { + mld_keccakf1600x4_permute(s); + mld_keccakf1600x4_extract_bytes(s, out0, out1, out2, out3, 0, r); + + out0 += r; + out1 += r; + out2 += r; + out3 += r; + nblocks--; + } +} + +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake128x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE128_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE128_RATE); +} + +void mld_shake128x4_init(mld_shake128x4ctx *state) { (void)state; } +void mld_shake128x4_release(mld_shake128x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128x4ctx)); +} + + +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake256x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE256_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE256_RATE); +} + +void mld_shake256x4_init(mld_shake256x4ctx *state) { (void)state; } +void mld_shake256x4_release(mld_shake256x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256x4ctx)); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/fips202x4.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/fips202x4.h new file mode 100644 index 0000000000..e7987207a6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/fips202x4.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202X4_H +#define MLD_FIPS202_FIPS202X4_H + +#include +#include + +#include "../cbmc.h" +#include "../common.h" + +#include "fips202.h" +#include "keccakf1600.h" + +/* Context for non-incremental API */ +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake128x4ctx; + +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake256x4ctx; + +#define mld_shake128x4_absorb_once MLD_NAMESPACE(shake128x4_absorb_once) +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_squeezeblocks MLD_NAMESPACE(shake128x4_squeezeblocks) +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE128_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE128_RATE), + memory_slice(out1, nblocks * SHAKE128_RATE), + memory_slice(out2, nblocks * SHAKE128_RATE), + memory_slice(out3, nblocks * SHAKE128_RATE), + memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_init MLD_NAMESPACE(shake128x4_init) +void mld_shake128x4_init(mld_shake128x4ctx *state); + +#define mld_shake128x4_release MLD_NAMESPACE(shake128x4_release) +void mld_shake128x4_release(mld_shake128x4ctx *state); + + +#define mld_shake256x4_absorb_once MLD_NAMESPACE(shake256x4_absorb_once) +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_squeezeblocks MLD_NAMESPACE(shake256x4_squeezeblocks) +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE256_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE256_RATE), + memory_slice(out1, nblocks * SHAKE256_RATE), + memory_slice(out2, nblocks * SHAKE256_RATE), + memory_slice(out3, nblocks * SHAKE256_RATE), + memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_init MLD_NAMESPACE(shake256x4_init) +void mld_shake256x4_init(mld_shake256x4ctx *state); + +#define mld_shake256x4_release MLD_NAMESPACE(shake256x4_release) +void mld_shake256x4_release(mld_shake256x4ctx *state); + + +#endif /* !MLD_FIPS202_FIPS202X4_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/keccakf1600.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/keccakf1600.c new file mode 100644 index 0000000000..e59120c07c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/keccakf1600.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#define MLD_KECCAK_NROUNDS 24 +#define MLD_KECCAK_ROL(a, offset) ((a << offset) ^ (a >> (64 - offset))) + +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = state_ptr[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = (state[(offset + i) >> 3] >> (8 * ((offset + i) & 0x07))) & 0xFF; + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state_ptr[i] ^= data[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state[(offset + i) >> 3] ^= (uint64_t)data[i] + << (8 * ((offset + i) & 0x07)); + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X4_NATIVE) + if (mld_keccak_f1600_x4_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 0); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 1); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 2); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 3); +} + +static const uint64_t mld_KeccakF_RoundConstants[MLD_KECCAK_NROUNDS] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +static void mld_keccakf1600_permute_c(uint64_t *state) +{ + unsigned round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + uint64_t BCa, BCe, BCi, BCo, BCu; + uint64_t Da, De, Di, Do, Du; + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + /* copyFromState(A, state) */ + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < MLD_KECCAK_NROUNDS; round += 2) + __loop__(invariant(round <= MLD_KECCAK_NROUNDS && round % 2 == 0)) + { + /* prepareTheta */ + BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; + BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + /* thetaRhoPiChiIotaPrepareTheta(round, A, E) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = MLD_KECCAK_ROL(Age, 44); + Aki ^= Di; + BCi = MLD_KECCAK_ROL(Aki, 43); + Amo ^= Do; + BCo = MLD_KECCAK_ROL(Amo, 21); + Asu ^= Du; + BCu = MLD_KECCAK_ROL(Asu, 14); + Eba = BCa ^ ((~BCe) & BCi); + Eba ^= (uint64_t)mld_KeccakF_RoundConstants[round]; + Ebe = BCe ^ ((~BCi) & BCo); + Ebi = BCi ^ ((~BCo) & BCu); + Ebo = BCo ^ ((~BCu) & BCa); + Ebu = BCu ^ ((~BCa) & BCe); + + Abo ^= Do; + BCa = MLD_KECCAK_ROL(Abo, 28); + Agu ^= Du; + BCe = MLD_KECCAK_ROL(Agu, 20); + Aka ^= Da; + BCi = MLD_KECCAK_ROL(Aka, 3); + Ame ^= De; + BCo = MLD_KECCAK_ROL(Ame, 45); + Asi ^= Di; + BCu = MLD_KECCAK_ROL(Asi, 61); + Ega = BCa ^ ((~BCe) & BCi); + Ege = BCe ^ ((~BCi) & BCo); + Egi = BCi ^ ((~BCo) & BCu); + Ego = BCo ^ ((~BCu) & BCa); + Egu = BCu ^ ((~BCa) & BCe); + + Abe ^= De; + BCa = MLD_KECCAK_ROL(Abe, 1); + Agi ^= Di; + BCe = MLD_KECCAK_ROL(Agi, 6); + Ako ^= Do; + BCi = MLD_KECCAK_ROL(Ako, 25); + Amu ^= Du; + BCo = MLD_KECCAK_ROL(Amu, 8); + Asa ^= Da; + BCu = MLD_KECCAK_ROL(Asa, 18); + Eka = BCa ^ ((~BCe) & BCi); + Eke = BCe ^ ((~BCi) & BCo); + Eki = BCi ^ ((~BCo) & BCu); + Eko = BCo ^ ((~BCu) & BCa); + Eku = BCu ^ ((~BCa) & BCe); + + Abu ^= Du; + BCa = MLD_KECCAK_ROL(Abu, 27); + Aga ^= Da; + BCe = MLD_KECCAK_ROL(Aga, 36); + Ake ^= De; + BCi = MLD_KECCAK_ROL(Ake, 10); + Ami ^= Di; + BCo = MLD_KECCAK_ROL(Ami, 15); + Aso ^= Do; + BCu = MLD_KECCAK_ROL(Aso, 56); + Ema = BCa ^ ((~BCe) & BCi); + Eme = BCe ^ ((~BCi) & BCo); + Emi = BCi ^ ((~BCo) & BCu); + Emo = BCo ^ ((~BCu) & BCa); + Emu = BCu ^ ((~BCa) & BCe); + + Abi ^= Di; + BCa = MLD_KECCAK_ROL(Abi, 62); + Ago ^= Do; + BCe = MLD_KECCAK_ROL(Ago, 55); + Aku ^= Du; + BCi = MLD_KECCAK_ROL(Aku, 39); + Ama ^= Da; + BCo = MLD_KECCAK_ROL(Ama, 41); + Ase ^= De; + BCu = MLD_KECCAK_ROL(Ase, 2); + Esa = BCa ^ ((~BCe) & BCi); + Ese = BCe ^ ((~BCi) & BCo); + Esi = BCi ^ ((~BCo) & BCu); + Eso = BCo ^ ((~BCu) & BCa); + Esu = BCu ^ ((~BCa) & BCe); + + /* prepareTheta */ + BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + /* thetaRhoPiChiIotaPrepareTheta(round+1, E, A) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = MLD_KECCAK_ROL(Ege, 44); + Eki ^= Di; + BCi = MLD_KECCAK_ROL(Eki, 43); + Emo ^= Do; + BCo = MLD_KECCAK_ROL(Emo, 21); + Esu ^= Du; + BCu = MLD_KECCAK_ROL(Esu, 14); + Aba = BCa ^ ((~BCe) & BCi); + Aba ^= (uint64_t)mld_KeccakF_RoundConstants[round + 1]; + Abe = BCe ^ ((~BCi) & BCo); + Abi = BCi ^ ((~BCo) & BCu); + Abo = BCo ^ ((~BCu) & BCa); + Abu = BCu ^ ((~BCa) & BCe); + + Ebo ^= Do; + BCa = MLD_KECCAK_ROL(Ebo, 28); + Egu ^= Du; + BCe = MLD_KECCAK_ROL(Egu, 20); + Eka ^= Da; + BCi = MLD_KECCAK_ROL(Eka, 3); + Eme ^= De; + BCo = MLD_KECCAK_ROL(Eme, 45); + Esi ^= Di; + BCu = MLD_KECCAK_ROL(Esi, 61); + Aga = BCa ^ ((~BCe) & BCi); + Age = BCe ^ ((~BCi) & BCo); + Agi = BCi ^ ((~BCo) & BCu); + Ago = BCo ^ ((~BCu) & BCa); + Agu = BCu ^ ((~BCa) & BCe); + + Ebe ^= De; + BCa = MLD_KECCAK_ROL(Ebe, 1); + Egi ^= Di; + BCe = MLD_KECCAK_ROL(Egi, 6); + Eko ^= Do; + BCi = MLD_KECCAK_ROL(Eko, 25); + Emu ^= Du; + BCo = MLD_KECCAK_ROL(Emu, 8); + Esa ^= Da; + BCu = MLD_KECCAK_ROL(Esa, 18); + Aka = BCa ^ ((~BCe) & BCi); + Ake = BCe ^ ((~BCi) & BCo); + Aki = BCi ^ ((~BCo) & BCu); + Ako = BCo ^ ((~BCu) & BCa); + Aku = BCu ^ ((~BCa) & BCe); + + Ebu ^= Du; + BCa = MLD_KECCAK_ROL(Ebu, 27); + Ega ^= Da; + BCe = MLD_KECCAK_ROL(Ega, 36); + Eke ^= De; + BCi = MLD_KECCAK_ROL(Eke, 10); + Emi ^= Di; + BCo = MLD_KECCAK_ROL(Emi, 15); + Eso ^= Do; + BCu = MLD_KECCAK_ROL(Eso, 56); + Ama = BCa ^ ((~BCe) & BCi); + Ame = BCe ^ ((~BCi) & BCo); + Ami = BCi ^ ((~BCo) & BCu); + Amo = BCo ^ ((~BCu) & BCa); + Amu = BCu ^ ((~BCa) & BCe); + + Ebi ^= Di; + BCa = MLD_KECCAK_ROL(Ebi, 62); + Ego ^= Do; + BCe = MLD_KECCAK_ROL(Ego, 55); + Eku ^= Du; + BCi = MLD_KECCAK_ROL(Eku, 39); + Ema ^= Da; + BCo = MLD_KECCAK_ROL(Ema, 41); + Ese ^= De; + BCu = MLD_KECCAK_ROL(Ese, 2); + Asa = BCa ^ ((~BCe) & BCi); + Ase = BCe ^ ((~BCi) & BCo); + Asi = BCi ^ ((~BCo) & BCu); + Aso = BCo ^ ((~BCu) & BCa); + Asu = BCu ^ ((~BCa) & BCe); + } + + /* copyToState(state, A) */ + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} + +void mld_keccakf1600_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X1_NATIVE) + if (mld_keccak_f1600_x1_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X1_NATIVE */ + mld_keccakf1600_permute_c(state); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(keccakf1600) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_KECCAK_NROUNDS +#undef MLD_KECCAK_ROL diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/keccakf1600.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/keccakf1600.h new file mode 100644 index 0000000000..e56adc1561 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/keccakf1600.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_KECCAKF1600_H +#define MLD_FIPS202_KECCAKF1600_H +#include +#include "../cbmc.h" +#include "../common.h" +#include "fips202.h" + +#define MLD_KECCAK_LANES 25 +#define MLD_KECCAK_WAY 4 + +/* + * WARNING: + * The contents of this structure, including the placement + * and interleaving of Keccak lanes, are IMPLEMENTATION-DEFINED. + * The struct is only exposed here to allow its construction on the stack. + */ + +#define mld_keccakf1600_extract_bytes MLD_NAMESPACE(keccakf1600_extract_bytes) +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(data, length)) +); + +#define mld_keccakf1600_xor_bytes MLD_NAMESPACE(keccakf1600_xor_bytes) +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#define mld_keccakf1600x4_extract_bytes \ + MLD_NAMESPACE(keccakf1600x4_extract_bytes) +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + requires(memory_no_alias(data1, length)) + requires(memory_no_alias(data2, length)) + requires(memory_no_alias(data3, length)) + assigns(memory_slice(data0, length)) + assigns(memory_slice(data1, length)) + assigns(memory_slice(data2, length)) + assigns(memory_slice(data3, length)) +); + +#define mld_keccakf1600x4_xor_bytes MLD_NAMESPACE(keccakf1600x4_xor_bytes) +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + /* Case 1: all input buffers are distinct; Case 2: All input buffers are the same */ + requires((data0 == data1 && + data0 == data2 && + data0 == data3) || + (memory_no_alias(data1, length) && + memory_no_alias(data2, length) && + memory_no_alias(data3, length))) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600x4_permute MLD_NAMESPACE(keccakf1600x4_permute) +void mld_keccakf1600x4_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600_permute MLD_NAMESPACE(keccakf1600_permute) +void mld_keccakf1600_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#endif /* !MLD_FIPS202_KECCAKF1600_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/auto.h new file mode 100644 index 0000000000..4375cc1976 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/auto.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [HYBRID] + * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64 + * Becker, Kannwischer + * https://eprint.iacr.org/2022/1243 + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +#define MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* Default FIPS202 assembly profile for AArch64 systems */ + +/* + * Default logic to decide which implementation to use. + * + */ + +/* + * Keccak-f1600 + * + * - On Arm-based Apple CPUs, we pick a pure Neon implementation. + * - Otherwise, unless MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, + * we use lazy-rotation scalar assembly from @[HYBRID]. + * - Otherwise, if MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, we + * fall back to the standard C implementation. + */ +#if defined(__ARM_FEATURE_SHA3) && defined(__APPLE__) +#include "x1_v84a.h" +#elif !defined(MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER) +#include "x1_scalar.h" +#endif + +/* + * Keccak-f1600x2/x4 + * + * The optimal implementation is highly CPU-specific; see @[HYBRID]. + * + * For now, if v8.4-A is not implemented, we fall back to Keccak-f1600. + * If v8.4-A is implemented and we are on an Apple CPU, we use a plain + * Neon-based implementation. + * If v8.4-A is implemented and we are not on an Apple CPU, we use a + * scalar/Neon/Neon hybrid. + * The reason for this distinction is that Apple CPUs appear to implement + * the SHA3 instructions on all SIMD units, while Arm CPUs prior to Cortex-X4 + * don't, and ordinary Neon instructions are still needed. + */ +#if defined(__ARM_FEATURE_SHA3) +/* + * For Apple-M cores, we use a plain implementation leveraging SHA3 + * instructions only. + */ +#if defined(__APPLE__) +#include "x2_v84a.h" +#else +#include "x4_v8a_v84a_scalar.h" +#endif + +#else /* __ARM_FEATURE_SHA3 */ + +#include "x4_v8a_scalar.h" + +#endif /* !__ARM_FEATURE_SHA3 */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h new file mode 100644 index 0000000000..20f6168038 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#define MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H + +#include +#include "../../../../cbmc.h" +#include "../../../../common.h" + + +#define mld_keccakf1600_round_constants \ + MLD_NAMESPACE(keccakf1600_round_constants) +extern const uint64_t mld_keccakf1600_round_constants[]; + +#define mld_keccak_f1600_x1_scalar_asm MLD_NAMESPACE(keccak_f1600_x1_scalar_asm) +void mld_keccak_f1600_x1_scalar_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x1_v84a_asm MLD_NAMESPACE(keccak_f1600_x1_v84a_asm) +void mld_keccak_f1600_x1_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x2_v84a_asm MLD_NAMESPACE(keccak_f1600_x2_v84a_asm) +void mld_keccak_f1600_x2_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 2)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 2)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c new file mode 100644 index 0000000000..05e9cbfeec --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../../common.h" + +#if (defined(MLD_FIPS202_AARCH64_NEED_X1_SCALAR) || \ + defined(MLD_FIPS202_AARCH64_NEED_X1_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X2_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID)) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "fips202_native_aarch64.h" + +MLD_ALIGN const uint64_t mld_keccakf1600_round_constants[] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, +}; + +#else /* (MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_aarch64_round_constants) + +#endif /* !((MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/x1_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/x1_scalar.h new file mode 100644 index 0000000000..681b991371 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/x1_scalar.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_SCALAR + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + mld_keccak_f1600_x1_scalar_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/x1_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/x1_v84a.h new file mode 100644 index 0000000000..d15c8c26f3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/x1_v84a.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x1_v84a_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/x2_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/x2_v84a.h new file mode 100644 index 0000000000..16c22fa1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/x2_v84a.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X2_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" + + +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x2_v84a_asm(state + 0 * 25, mld_keccakf1600_round_constants); + mld_keccak_f1600_x2_v84a_asm(state + 2 * 25, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h new file mode 100644 index 0000000000..0f7f8fe499 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(state, + mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h new file mode 100644 index 0000000000..3da883b762 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm( + state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/api.h new file mode 100644 index 0000000000..4625c9a1ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/api.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_API_H +#define MLD_FIPS202_NATIVE_API_H +/* + * FIPS-202 native interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + */ + +#include +#include "../../cbmc.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* + * This is the C<->native interface allowing for the drop-in + * of custom Keccak-F1600 implementations. + * + * A _backend_ is a specific implementation of parts of this interface. + * + * You can replace 1-fold or 4-fold batched Keccak-F1600. + * To enable, set MLD_USE_FIPS202_X1_NATIVE or MLD_USE_FIPS202_X4_NATIVE + * in your backend, and define the inline wrappers mld_keccak_f1600_x1_native() + * and/or mld_keccak_f1600_x4_native(), respectively, to forward to your + * implementation. + */ + +#if defined(MLD_USE_FIPS202_X1_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 1)) +); +#endif /* MLD_USE_FIPS202_X1_NATIVE */ +#if defined(MLD_USE_FIPS202_X4_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 4)) +); +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + +#endif /* !MLD_FIPS202_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/auto.h new file mode 100644 index 0000000000..0a09c733c8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/auto.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AUTO_H +#define MLD_FIPS202_NATIVE_AUTO_H + +/* + * Default FIPS202 backend + */ +#include "../../sys.h" + +#if defined(MLD_SYS_AARCH64) +#include "aarch64/auto.h" +#endif + +#if defined(MLD_SYS_X86_64) && defined(MLD_SYS_X86_64_AVX2) +#include "x86_64/xkcp.h" +#endif + +#endif /* !MLD_FIPS202_NATIVE_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c new file mode 100644 index 0000000000..4eaad2fd66 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* +Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, +Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby +denoted as "the implementer". + +For more information, feedback or questions, please refer to our websites: +http://keccak.noekeon.org/ +http://keyak.noekeon.org/ +http://ketje.noekeon.org/ + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +/* + * Changes for mlkem-native/mldsa-native: + * - copyFromState and copyToState operate on uninterleaved + * Keccak states in memory. + */ + +#include "../../../../common.h" +#if defined(MLD_FIPS202_X86_64_XKCP) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include + +#include "KeccakP_1600_times4_SIMD256.h" + +#ifndef MLD_SYS_LITTLE_ENDIAN +#error Expecting a little-endian platform +#endif + +#define ANDnu256(a, b) _mm256_andnot_si256(a, b) +#define CONST256(a) _mm256_load_si256((const __m256i *)&(a)) +#define CONST256_64(a) (__m256i) _mm256_broadcast_sd((const double *)(&a)) +#define ROL64in256(d, a, o) \ + d = _mm256_or_si256(_mm256_slli_epi64(a, o), _mm256_srli_epi64(a, 64 - (o))) +#define ROL64in256_8(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho8)) +#define ROL64in256_56(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho56)) +static const uint64_t rho8[4] = {0x0605040302010007, 0x0E0D0C0B0A09080F, + 0x1615141312111017, 0x1E1D1C1B1A19181F}; +static const uint64_t rho56[4] = {0x0007060504030201, 0x080F0E0D0C0B0A09, + 0x1017161514131211, 0x181F1E1D1C1B1A19}; +#define STORE256(a, b) _mm256_store_si256((__m256i *)&(a), b) +#define XOR256(a, b) _mm256_xor_si256(a, b) +#define XOReq256(a, b) a = _mm256_xor_si256(a, b) + +#define SnP_laneLengthInBytes 8 + +#define declareABCDE \ + __m256i Aba, Abe, Abi, Abo, Abu; \ + __m256i Aga, Age, Agi, Ago, Agu; \ + __m256i Aka, Ake, Aki, Ako, Aku; \ + __m256i Ama, Ame, Ami, Amo, Amu; \ + __m256i Asa, Ase, Asi, Aso, Asu; \ + __m256i Bba, Bbe, Bbi, Bbo, Bbu; \ + __m256i Bga, Bge, Bgi, Bgo, Bgu; \ + __m256i Bka, Bke, Bki, Bko, Bku; \ + __m256i Bma, Bme, Bmi, Bmo, Bmu; \ + __m256i Bsa, Bse, Bsi, Bso, Bsu; \ + __m256i Ca, Ce, Ci, Co, Cu; \ + __m256i Ca1, Ce1, Ci1, Co1, Cu1; \ + __m256i Da, De, Di, Do, Du; \ + __m256i Eba, Ebe, Ebi, Ebo, Ebu; \ + __m256i Ega, Ege, Egi, Ego, Egu; \ + __m256i Eka, Eke, Eki, Eko, Eku; \ + __m256i Ema, Eme, Emi, Emo, Emu; \ + __m256i Esa, Ese, Esi, Eso, Esu; + +#define prepareTheta \ + Ca = XOR256(Aba, XOR256(Aga, XOR256(Aka, XOR256(Ama, Asa)))); \ + Ce = XOR256(Abe, XOR256(Age, XOR256(Ake, XOR256(Ame, Ase)))); \ + Ci = XOR256(Abi, XOR256(Agi, XOR256(Aki, XOR256(Ami, Asi)))); \ + Co = XOR256(Abo, XOR256(Ago, XOR256(Ako, XOR256(Amo, Aso)))); \ + Cu = XOR256(Abu, XOR256(Agu, XOR256(Aku, XOR256(Amu, Asu)))); + +/* + * --- Theta Rho Pi Chi Iota Prepare-theta + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + Ca = E##ba; \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + Ce = E##be; \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + Ci = E##bi; \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + Co = E##bo; \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + Cu = E##bu; \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(Ca, E##ga); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(Ce, E##ge); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + XOReq256(Ci, E##gi); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + XOReq256(Co, E##go); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + XOReq256(Cu, E##gu); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(Ca, E##ka); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(Ce, E##ke); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + XOReq256(Ci, E##ki); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + XOReq256(Co, E##ko); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + XOReq256(Cu, E##ku); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(Ca, E##ma); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(Ce, E##me); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + XOReq256(Ci, E##mi); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + XOReq256(Co, E##mo); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + XOReq256(Cu, E##mu); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(Ca, E##sa); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(Ce, E##se); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + XOReq256(Ci, E##si); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + XOReq256(Co, E##so); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); \ + XOReq256(Cu, E##su); + + +/* + * --- Theta Rho Pi Chi Iota + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIota(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); + + +static MLD_ALIGN const uint64_t keccakf1600RoundConstants[24] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +#include + +#define copyFromState(X, state) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m256i _idx = \ + _mm256_set_epi64x((long long)&state64[75], (long long)&state64[50], \ + (long long)&state64[25], (long long)&state64[0]); \ + X##ba = _mm256_i64gather_epi64((long long *)(0 * 8), _idx, 1); \ + X##be = _mm256_i64gather_epi64((long long *)(1 * 8), _idx, 1); \ + X##bi = _mm256_i64gather_epi64((long long *)(2 * 8), _idx, 1); \ + X##bo = _mm256_i64gather_epi64((long long *)(3 * 8), _idx, 1); \ + X##bu = _mm256_i64gather_epi64((long long *)(4 * 8), _idx, 1); \ + X##ga = _mm256_i64gather_epi64((long long *)(5 * 8), _idx, 1); \ + X##ge = _mm256_i64gather_epi64((long long *)(6 * 8), _idx, 1); \ + X##gi = _mm256_i64gather_epi64((long long *)(7 * 8), _idx, 1); \ + X##go = _mm256_i64gather_epi64((long long *)(8 * 8), _idx, 1); \ + X##gu = _mm256_i64gather_epi64((long long *)(9 * 8), _idx, 1); \ + X##ka = _mm256_i64gather_epi64((long long *)(10 * 8), _idx, 1); \ + X##ke = _mm256_i64gather_epi64((long long *)(11 * 8), _idx, 1); \ + X##ki = _mm256_i64gather_epi64((long long *)(12 * 8), _idx, 1); \ + X##ko = _mm256_i64gather_epi64((long long *)(13 * 8), _idx, 1); \ + X##ku = _mm256_i64gather_epi64((long long *)(14 * 8), _idx, 1); \ + X##ma = _mm256_i64gather_epi64((long long *)(15 * 8), _idx, 1); \ + X##me = _mm256_i64gather_epi64((long long *)(16 * 8), _idx, 1); \ + X##mi = _mm256_i64gather_epi64((long long *)(17 * 8), _idx, 1); \ + X##mo = _mm256_i64gather_epi64((long long *)(18 * 8), _idx, 1); \ + X##mu = _mm256_i64gather_epi64((long long *)(19 * 8), _idx, 1); \ + X##sa = _mm256_i64gather_epi64((long long *)(20 * 8), _idx, 1); \ + X##se = _mm256_i64gather_epi64((long long *)(21 * 8), _idx, 1); \ + X##si = _mm256_i64gather_epi64((long long *)(22 * 8), _idx, 1); \ + X##so = _mm256_i64gather_epi64((long long *)(23 * 8), _idx, 1); \ + X##su = _mm256_i64gather_epi64((long long *)(24 * 8), _idx, 1); \ + } while (0); + +#define SCATTER_STORE256(state, idx, v) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m128d t = _mm_castsi128_pd(_mm256_castsi256_si128((v))); \ + _mm_storel_pd((double *)&state64[0 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[25 + (idx)], t); \ + t = _mm_castsi128_pd(_mm256_extracti128_si256((v), 1)); \ + _mm_storel_pd((double *)&state64[50 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[75 + (idx)], t); \ + } while (0) + +#define copyToState(state, X) \ + SCATTER_STORE256(state, 0, X##ba); \ + SCATTER_STORE256(state, 1, X##be); \ + SCATTER_STORE256(state, 2, X##bi); \ + SCATTER_STORE256(state, 3, X##bo); \ + SCATTER_STORE256(state, 4, X##bu); \ + SCATTER_STORE256(state, 5, X##ga); \ + SCATTER_STORE256(state, 6, X##ge); \ + SCATTER_STORE256(state, 7, X##gi); \ + SCATTER_STORE256(state, 8, X##go); \ + SCATTER_STORE256(state, 9, X##gu); \ + SCATTER_STORE256(state, 10, X##ka); \ + SCATTER_STORE256(state, 11, X##ke); \ + SCATTER_STORE256(state, 12, X##ki); \ + SCATTER_STORE256(state, 13, X##ko); \ + SCATTER_STORE256(state, 14, X##ku); \ + SCATTER_STORE256(state, 15, X##ma); \ + SCATTER_STORE256(state, 16, X##me); \ + SCATTER_STORE256(state, 17, X##mi); \ + SCATTER_STORE256(state, 18, X##mo); \ + SCATTER_STORE256(state, 19, X##mu); \ + SCATTER_STORE256(state, 20, X##sa); \ + SCATTER_STORE256(state, 21, X##se); \ + SCATTER_STORE256(state, 22, X##si); \ + SCATTER_STORE256(state, 23, X##so); \ + SCATTER_STORE256(state, 24, X##su); + +#define copyStateVariables(X, Y) \ + X##ba = Y##ba; \ + X##be = Y##be; \ + X##bi = Y##bi; \ + X##bo = Y##bo; \ + X##bu = Y##bu; \ + X##ga = Y##ga; \ + X##ge = Y##ge; \ + X##gi = Y##gi; \ + X##go = Y##go; \ + X##gu = Y##gu; \ + X##ka = Y##ka; \ + X##ke = Y##ke; \ + X##ki = Y##ki; \ + X##ko = Y##ko; \ + X##ku = Y##ku; \ + X##ma = Y##ma; \ + X##me = Y##me; \ + X##mi = Y##mi; \ + X##mo = Y##mo; \ + X##mu = Y##mu; \ + X##sa = Y##sa; \ + X##se = Y##se; \ + X##si = Y##si; \ + X##so = Y##so; \ + X##su = Y##su; + +/* clang-format off */ +#define rounds24 \ + prepareTheta \ + thetaRhoPiChiIotaPrepareTheta( 0, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 1, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 2, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 3, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 4, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 5, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 6, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 7, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 8, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 9, E, A) \ + thetaRhoPiChiIotaPrepareTheta(10, A, E) \ + thetaRhoPiChiIotaPrepareTheta(11, E, A) \ + thetaRhoPiChiIotaPrepareTheta(12, A, E) \ + thetaRhoPiChiIotaPrepareTheta(13, E, A) \ + thetaRhoPiChiIotaPrepareTheta(14, A, E) \ + thetaRhoPiChiIotaPrepareTheta(15, E, A) \ + thetaRhoPiChiIotaPrepareTheta(16, A, E) \ + thetaRhoPiChiIotaPrepareTheta(17, E, A) \ + thetaRhoPiChiIotaPrepareTheta(18, A, E) \ + thetaRhoPiChiIotaPrepareTheta(19, E, A) \ + thetaRhoPiChiIotaPrepareTheta(20, A, E) \ + thetaRhoPiChiIotaPrepareTheta(21, E, A) \ + thetaRhoPiChiIotaPrepareTheta(22, A, E) \ + thetaRhoPiChiIota(23, E, A) +/* clang-format on */ + +void mld_keccakf1600x4_permute24(void *states) +{ + __m256i *statesAsLanes = (__m256i *)states; + declareABCDE copyFromState(A, statesAsLanes) + rounds24 copyToState(statesAsLanes, A) +} + +#else /* MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_avx2_keccakx4) + +#endif /* !(MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef ANDnu256 +#undef CONST256 +#undef CONST256_64 +#undef ROL64in256 +#undef ROL64in256_8 +#undef ROL64in256_56 +#undef STORE256 +#undef XOR256 +#undef XOReq256 +#undef SnP_laneLengthInBytes +#undef declareABCDE +#undef prepareTheta +#undef thetaRhoPiChiIotaPrepareTheta +#undef thetaRhoPiChiIota +#undef copyFromState +#undef SCATTER_STORE256 +#undef copyToState +#undef copyStateVariables +#undef rounds24 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h new file mode 100644 index 0000000000..3499d38e2c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H +#define MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H + +#include "../../../../common.h" + +#define mld_keccakf1600x4_permute24 \ + MLD_NAMESPACE(KeccakP1600times4_PermuteAll_24rounds) +void mld_keccakf1600x4_permute24(void *states); + +#endif /* !MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/x86_64/xkcp.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/x86_64/xkcp.h new file mode 100644 index 0000000000..c03642d7e0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/fips202/native/x86_64/xkcp.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_XKCP_H +#define MLD_FIPS202_NATIVE_X86_64_XKCP_H + +#include "../../../common.h" + +#define MLD_FIPS202_X86_64_XKCP + +#if !defined(__ASSEMBLER__) +#include +#include "../api.h" +#include "src/KeccakP_1600_times4_SIMD256.h" + +#define MLD_USE_FIPS202_X4_NATIVE +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_keccakf1600x4_permute24(state); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_X86_64_XKCP_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/meta.h new file mode 100644 index 0000000000..c6f6ad47b0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/meta.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_META_H +#define MLD_NATIVE_AARCH64_META_H + +/* Set of primitives that this backend replaces */ +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_AARCH64 + + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/arith_native_aarch64.h" + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + mld_ntt_asm(data, mld_aarch64_ntt_zetas_layer123456, + mld_aarch64_ntt_zetas_layer78); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + mld_intt_asm(data, mld_aarch64_intt_zetas_layer78, + mld_aarch64_intt_zetas_layer123456); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + if (len != MLDSA_N || + buflen % 24 != 0) /* NEON support is mandatory for AArch64 */ + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N, hence, this cast is safe. */ + return (int)mld_rej_uniform_asm(r, buf, buflen, mld_rej_uniform_table); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_32_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_88_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + mld_poly_caddq_asm(a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_32_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_88_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + return mld_poly_chknorm_asm(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_17_asm(r, buf, mld_polyz_unpack_17_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_19_asm(r, buf, mld_polyz_unpack_19_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t out[MLDSA_N], const int32_t in0[MLDSA_N], + const int32_t in1[MLDSA_N]) +{ + mld_poly_pointwise_montgomery_asm(out, in0, in1); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l4_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l5_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l7_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ +#endif /* !MLD_NATIVE_AARCH64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/src/aarch64_zetas.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/src/aarch64_zetas.c new file mode 100644 index 0000000000..9ab7b9a68c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/src/aarch64_zetas.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Table of zeta values used in the AArch64 forward NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer123456[] = { + -3572223, -915382907, 3765607, 964937599, 3761513, 963888510, + -3201494, -820383522, -2883726, -738955404, -3145678, -806080660, + -3201430, -820367122, 0, 0, -601683, -154181397, + -3370349, -863652652, -4063053, -1041158200, 3602218, 923069133, + 3182878, 815613168, 2740543, 702264730, -3586446, -919027554, + 0, 0, 3542485, 907762539, 2663378, 682491182, + -1674615, -429120452, -3110818, -797147778, 2101410, 538486762, + 3704823, 949361686, 1159875, 297218217, 0, 0, + 2682288, 687336873, -3524442, -903139016, -434125, -111244624, + 394148, 101000509, 928749, 237992130, 1095468, 280713909, + -3506380, -898510625, 0, 0, 2129892, 545785280, + 676590, 173376332, -1335936, -342333886, 2071829, 530906624, + -4018989, -1029866791, 3241972, 830756018, 2156050, 552488273, + 0, 0, 3764867, 964747974, -3227876, -827143915, + 1714295, 439288460, 3415069, 875112161, 1759347, 450833045, + -817536, -209493775, -3574466, -915957677, 0, 0, + -1005239, -257592709, 2453983, 628833668, 1460718, 374309300, + 3756790, 962678241, -1935799, -496048908, -1716988, -439978542, + -3950053, -1012201926, 0, 0, 557458, 142848732, + -642628, -164673562, -3585098, -918682129, -2897314, -742437332, + 3192354, 818041395, 556856, 142694469, 3870317, 991769559, + 0, 0, -1221177, -312926867, 2815639, 721508096, + 2283733, 585207070, 2917338, 747568486, 1853806, 475038184, + 3345963, 857403734, 1858416, 476219497, 0, 0, +}; + +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer78[] = { + 3073009, 1277625, -2635473, 3852015, 787459213, + 327391679, -675340520, 987079667, 1753, -2659525, + 2660408, -59148, 449207, -681503850, 681730119, + -15156688, -1935420, -1455890, -1780227, 2772600, + -495951789, -373072124, -456183549, 710479343, 4183372, + -3222807, -3121440, -274060, 1071989969, -825844983, + -799869667, -70227934, 1182243, 636927, -3956745, + -3284915, 302950022, 163212680, -1013916752, -841760171, + 87208, -3965306, -2296397, -3716946, 22347069, + -1016110510, -588452222, -952468207, 2508980, 2028118, + 1937570, -3815725, 642926661, 519705671, 496502727, + -977780347, -27812, 1009365, -1979497, -3956944, + -7126831, 258649997, -507246529, -1013967746, 822541, + -2454145, 1596822, -3759465, 210776307, -628875181, + 409185979, -963363710, 2811291, -2983781, -1109516, + 4158088, 720393920, -764594519, -284313712, 1065510939, + -1685153, 2678278, -3551006, -250446, -431820817, + 686309310, -909946047, -64176841, -3410568, -3768948, + 635956, -2455377, -873958779, -965793731, 162963861, + -629190881, 1528066, 482649, 1148858, -2962264, + 391567239, 123678909, 294395108, -759080783, -4146264, + 2192938, 2387513, -268456, -1062481036, 561940831, + 611800717, -68791907, -1772588, -1727088, -3611750, + -3180456, -454226054, -442566669, -925511710, -814992530, + -565603, 169688, 2462444, -3334383, -144935890, + 43482586, 631001801, -854436357, 3747250, 1239911, + 3195676, 1254190, 960233614, 317727459, 818892658, + 321386456, 2296099, -3838479, 2642980, -12417, + 588375860, -983611064, 677264190, -3181859, -4166425, + -3488383, 1987814, -3197248, -1067647297, -893898890, + 509377762, -819295484, 2998219, -89301, -1354892, + -1310261, 768294260, -22883400, -347191365, -335754661, + 141835, 2513018, 613238, -2218467, 36345249, + 643961400, 157142369, -568482643, 1736313, 235407, + -3250154, 3258457, 444930577, 60323094, -832852657, + 834980303, -458740, 4040196, 2039144, -818761, + -117552223, 1035301089, 522531086, -209807681, -1921994, + -3472069, -1879878, -2178965, -492511373, -889718424, + -481719139, -558360247, -2579253, 1787943, -2391089, + -2254727, -660934133, 458160776, -612717067, -577774276, + -1623354, -2374402, 586241, 527981, -415984810, + -608441020, 150224382, 135295244, 2105286, -2033807, + -1179613, -2743411, 539479988, -521163479, -302276083, + -702999655, 3482206, -4182915, -1300016, -2362063, + 892316032, -1071872863, -333129378, -605279149, -1476985, + 2491325, 507927, -724804, -378477722, 638402564, + 130156402, -185731180, 1994046, -1393159, -1187885, + -1834526, 510974714, -356997292, -304395785, -470097680, + -1317678, 2461387, 3035980, 621164, -337655269, + 630730945, 777970524, 159173408, -3033742, 2647994, + -2612853, 749577, -777397036, 678549029, -669544140, + 192079267, -338420, 3009748, 4148469, -4022750, + -86720197, 771248568, 1063046068, -1030830548, 3901472, + -1226661, 2925816, 3374250, 999753034, -314332144, + 749740976, 864652284, 3980599, -1615530, 1665318, + 1163598, 1020029345, -413979908, 426738094, 298172236, + 2569011, 1723229, 2028038, -3369273, 658309618, + 441577800, 519685171, -863376927, 1356448, -2775755, + 2683270, -2778788, 347590090, -711287812, 687588511, + -712065019, 3994671, -1370517, 3363542, 545376, + 1023635298, -351195274, 861908357, 139752717, -11879, + 3020393, 214880, -770441, -3043996, 773976352, + 55063046, -197425671, -3467665, 2312838, -653275, + -459163, -888589898, 592665232, -167401858, -117660617, + 3105558, 508145, 860144, 140244, 795799901, + 130212265, 220412084, 35937555, -1103344, -553718, + 3430436, -1514152, -282732136, -141890356, 879049958, + -388001774, 348812, -327848, 1011223, -2354215, + 89383150, -84011120, 259126110, -603268097, -2185084, + 2358373, -3014420, 2926054, -559928242, 604333585, + -772445769, 749801963, 3123762, -2193087, -1716814, + -392707, 800464680, -561979013, -439933955, -100631253, + -3818627, -1922253, -2236726, 1744507, -978523985, + -492577742, -573161516, 447030292, -303005, -3974485, + 1900052, 1054478, -77645096, -1018462631, 486888731, + 270210213, 3531229, -3773731, -781875, -731434, + 904878186, -967019376, -200355636, -187430119, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer78[] = { + -1744507, 2236726, 1922253, 3818627, -447030292, 573161516, + 492577742, 978523985, 731434, 781875, 3773731, -3531229, + 187430119, 200355636, 967019376, -904878186, -1054478, -1900052, + 3974485, 303005, -270210213, -486888731, 1018462631, 77645096, + 2354215, -1011223, 327848, -348812, 603268097, -259126110, + 84011120, -89383150, 392707, 1716814, 2193087, -3123762, + 100631253, 439933955, 561979013, -800464680, -2926054, 3014420, + -2358373, 2185084, -749801963, 772445769, -604333585, 559928242, + 459163, 653275, -2312838, 3467665, 117660617, 167401858, + -592665232, 888589898, 1514152, -3430436, 553718, 1103344, + 388001774, -879049958, 141890356, 282732136, -140244, -860144, + -508145, -3105558, -35937555, -220412084, -130212265, -795799901, + 2778788, -2683270, 2775755, -1356448, 712065019, -687588511, + 711287812, -347590090, 770441, -214880, -3020393, 11879, + 197425671, -55063046, -773976352, 3043996, -545376, -3363542, + 1370517, -3994671, -139752717, -861908357, 351195274, -1023635298, + -3374250, -2925816, 1226661, -3901472, -864652284, -749740976, + 314332144, -999753034, 3369273, -2028038, -1723229, -2569011, + 863376927, -519685171, -441577800, -658309618, -1163598, -1665318, + 1615530, -3980599, -298172236, -426738094, 413979908, -1020029345, + -621164, -3035980, -2461387, 1317678, -159173408, -777970524, + -630730945, 337655269, 4022750, -4148469, -3009748, 338420, + 1030830548, -1063046068, -771248568, 86720197, -749577, 2612853, + -2647994, 3033742, -192079267, 669544140, -678549029, 777397036, + 2362063, 1300016, 4182915, -3482206, 605279149, 333129378, + 1071872863, -892316032, 1834526, 1187885, 1393159, -1994046, + 470097680, 304395785, 356997292, -510974714, 724804, -507927, + -2491325, 1476985, 185731180, -130156402, -638402564, 378477722, + 2254727, 2391089, -1787943, 2579253, 577774276, 612717067, + -458160776, 660934133, 2743411, 1179613, 2033807, -2105286, + 702999655, 302276083, 521163479, -539479988, -527981, -586241, + 2374402, 1623354, -135295244, -150224382, 608441020, 415984810, + -3258457, 3250154, -235407, -1736313, -834980303, 832852657, + -60323094, -444930577, 2178965, 1879878, 3472069, 1921994, + 558360247, 481719139, 889718424, 492511373, 818761, -2039144, + -4040196, 458740, 209807681, -522531086, -1035301089, 117552223, + 3197248, -1987814, 3488383, 4166425, 819295484, -509377762, + 893898890, 1067647297, 2218467, -613238, -2513018, -141835, + 568482643, -157142369, -643961400, -36345249, 1310261, 1354892, + 89301, -2998219, 335754661, 347191365, 22883400, -768294260, + 3334383, -2462444, -169688, 565603, 854436357, -631001801, + -43482586, 144935890, 12417, -2642980, 3838479, -2296099, + 3181859, -677264190, 983611064, -588375860, -1254190, -3195676, + -1239911, -3747250, -321386456, -818892658, -317727459, -960233614, + 2962264, -1148858, -482649, -1528066, 759080783, -294395108, + -123678909, -391567239, 3180456, 3611750, 1727088, 1772588, + 814992530, 925511710, 442566669, 454226054, 268456, -2387513, + -2192938, 4146264, 68791907, -611800717, -561940831, 1062481036, + -4158088, 1109516, 2983781, -2811291, -1065510939, 284313712, + 764594519, -720393920, 2455377, -635956, 3768948, 3410568, + 629190881, -162963861, 965793731, 873958779, 250446, 3551006, + -2678278, 1685153, 64176841, 909946047, -686309310, 431820817, + 3815725, -1937570, -2028118, -2508980, 977780347, -496502727, + -519705671, -642926661, 3759465, -1596822, 2454145, -822541, + 963363710, -409185979, 628875181, -210776307, 3956944, 1979497, + -1009365, 27812, 1013967746, 507246529, -258649997, 7126831, + 274060, 3121440, 3222807, -4183372, 70227934, 799869667, + 825844983, -1071989969, 3716946, 2296397, 3965306, -87208, + 952468207, 588452222, 1016110510, -22347069, 3284915, 3956745, + -636927, -1182243, 841760171, 1013916752, -163212680, -302950022, + -3852015, 2635473, -1277625, -3073009, -987079667, 675340520, + -327391679, -787459213, -2772600, 1780227, 1455890, 1935420, + -710479343, 456183549, 373072124, 495951789, 59148, -2660408, + 2659525, -1753, 15156688, -681730119, 681503850, -449207, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer123456[] = { + -2283733, -585207070, 0, 0, -1858416, -476219497, + -3345963, -857403734, -2815639, -721508096, 0, 0, + -1853806, -475038184, -2917338, -747568486, 3585098, 918682129, + 0, 0, -3870317, -991769559, -556856, -142694469, + 642628, 164673562, 0, 0, -3192354, -818041395, + 2897314, 742437332, -1460718, -374309300, 0, 0, + 3950053, 1012201926, 1716988, 439978542, -2453983, -628833668, + 0, 0, 1935799, 496048908, -3756790, -962678241, + -1714295, -439288460, 0, 0, 3574466, 915957677, + 817536, 209493775, 3227876, 827143915, 0, 0, + -1759347, -450833045, -3415069, -875112161, 1335936, 342333886, + 0, 0, -2156050, -552488273, -3241972, -830756018, + -676590, -173376332, 0, 0, 4018989, 1029866791, + -2071829, -530906624, 434125, 111244624, 0, 0, + 3506380, 898510625, -1095468, -280713909, 3524442, 903139016, + 0, 0, -928749, -237992130, -394148, -101000509, + 1674615, 429120452, 0, 0, -1159875, -297218217, + -3704823, -949361686, -2663378, -682491182, 0, 0, + -2101410, -538486762, 3110818, 797147778, 4063053, 1041158200, + 0, 0, 3586446, 919027554, -2740543, -702264730, + 3370349, 863652652, 0, 0, -3182878, -815613168, + -3602218, -923069133, -294725, -75523344, -3761513, -963888510, + -3765607, -964937599, 3201430, 820367122, 3145678, 806080660, + 2883726, 738955404, 3201494, 820383522, 1221177, 312926867, + -557458, -142848732, 1005239, 257592709, -3764867, -964747974, + -2129892, -545785280, -2682288, -687336873, -3542485, -907762539, + 601683, 154181397, 0, 0, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_zetas) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h new file mode 100644 index 0000000000..e77f55014c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#define MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H + +#include +#include "../../../common.h" + +#define mld_aarch64_ntt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_ntt_zetas_layer123456) +#define mld_aarch64_ntt_zetas_layer78 MLD_NAMESPACE(aarch64_ntt_zetas_layer78) + +#define mld_aarch64_intt_zetas_layer78 MLD_NAMESPACE(aarch64_intt_zetas_layer78) +#define mld_aarch64_intt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_intt_zetas_layer123456) + +extern const int32_t mld_aarch64_ntt_zetas_layer123456[]; +extern const int32_t mld_aarch64_ntt_zetas_layer78[]; + +extern const int32_t mld_aarch64_intt_zetas_layer78[]; +extern const int32_t mld_aarch64_intt_zetas_layer123456[]; + +#define mld_rej_uniform_table MLD_NAMESPACE(rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[]; +#define mld_rej_uniform_eta_table MLD_NAMESPACE(rej_uniform_eta_table) +extern const uint8_t mld_rej_uniform_eta_table[]; + +#define mld_polyz_unpack_17_indices MLD_NAMESPACE(polyz_unpack_17_indices) +extern const uint8_t mld_polyz_unpack_17_indices[]; +#define mld_polyz_unpack_19_indices MLD_NAMESPACE(polyz_unpack_19_indices) +extern const uint8_t mld_polyz_unpack_19_indices[]; + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_ntt_asm MLD_NAMESPACE(ntt_asm) +void mld_ntt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_intt_asm MLD_NAMESPACE(intt_asm) +void mld_intt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_rej_uniform_asm MLD_NAMESPACE(rej_uniform_asm) +uint64_t mld_rej_uniform_asm(int32_t *r, const uint8_t *buf, unsigned buflen, + const uint8_t *table); + +#define mld_rej_uniform_eta2_asm MLD_NAMESPACE(rej_uniform_eta2_asm) +uint64_t mld_rej_uniform_eta2_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_rej_uniform_eta4_asm MLD_NAMESPACE(rej_uniform_eta4_asm) +uint64_t mld_rej_uniform_eta4_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_poly_decompose_32_asm MLD_NAMESPACE(poly_decompose_32_asm) +void mld_poly_decompose_32_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_asm MLD_NAMESPACE(poly_decompose_88_asm) +void mld_poly_decompose_88_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_asm MLD_NAMESPACE(poly_caddq_asm) +void mld_poly_caddq_asm(int32_t *a); + +#define mld_poly_use_hint_32_asm MLD_NAMESPACE(poly_use_hint_32_asm) +void mld_poly_use_hint_32_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_asm MLD_NAMESPACE(poly_use_hint_88_asm) +void mld_poly_use_hint_88_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_asm MLD_NAMESPACE(poly_chknorm_asm) +int mld_poly_chknorm_asm(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_asm MLD_NAMESPACE(polyz_unpack_17_asm) +void mld_polyz_unpack_17_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_polyz_unpack_19_asm MLD_NAMESPACE(polyz_unpack_19_asm) +void mld_polyz_unpack_19_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_poly_pointwise_montgomery_asm \ + MLD_NAMESPACE(poly_pointwise_montgomery_asm) +void mld_poly_pointwise_montgomery_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l4_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l4_asm) +void mld_polyvecl_pointwise_acc_montgomery_l4_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l5_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l5_asm) +void mld_polyvecl_pointwise_acc_montgomery_l5_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l7_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l7_asm) +void mld_polyvecl_pointwise_acc_montgomery_l7_asm(int32_t *, const int32_t *, + const int32_t *); + +#endif /* !MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c new file mode 100644 index 0000000000..7ef915b587 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* Table of indices used for tbl instructions in polyz_unpack_{17,19}. */ + +MLD_ALIGN const uint8_t mld_polyz_unpack_17_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, + 9, 10, 11, 255, 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, + 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, 8, 9, 10, 255, + 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, 17, 18, 19, 255, +}; + +MLD_ALIGN const uint8_t mld_polyz_unpack_19_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 5, 6, 7, 255, 7, 8, 9, 255, + 10, 11, 12, 255, 12, 13, 14, 255, 15, 16, 17, 255, 17, 18, 19, 255, + 4, 5, 6, 255, 6, 7, 8, 255, 9, 10, 11, 255, 11, 12, 13, 255, + 14, 15, 16, 255, 16, 17, 18, 255, 19, 20, 21, 255, 21, 22, 23, 255, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_polyz_unpack_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c new file mode 100644 index 0000000000..cf21509cbf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by 16-bit rejection sampling (rej_eta). + * Adapted from ML-KEM for ML-DSA eta rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_eta_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 2, 3, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 4, 5, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 2, 3, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 7 */, + 6, 7, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 2, 3, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 11 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 13 */, + 2, 3, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 15 */, + 8, 9, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 16 */, + 0, 1, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 17 */, + 2, 3, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 18 */, + 0, 1, 2, 3, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 19 */, + 4, 5, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 20 */, + 0, 1, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 21 */, + 2, 3, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 22 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 23 */, + 6, 7, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 24 */, + 0, 1, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 25 */, + 2, 3, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 26 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 27 */, + 4, 5, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 28 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 29 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 30 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 255, 255, 255, 255, 255, 255 /* 31 */, + 10, 11, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 32 */, + 0, 1, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 33 */, + 2, 3, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 34 */, + 0, 1, 2, 3, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 35 */, + 4, 5, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 36 */, + 0, 1, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 37 */, + 2, 3, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 38 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 39 */, + 6, 7, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 40 */, + 0, 1, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 41 */, + 2, 3, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 42 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 43 */, + 4, 5, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 44 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 45 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 46 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 255, 255, 255, 255, 255, 255 /* 47 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 48 */, + 0, 1, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 49 */, + 2, 3, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 50 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 51 */, + 4, 5, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 52 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 53 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 54 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 55 */, + 6, 7, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 56 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 57 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 58 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 59 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 60 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 61 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 62 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 63 */, + 12, 13, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 64 */, + 0, 1, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 65 */, + 2, 3, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 66 */, + 0, 1, 2, 3, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 67 */, + 4, 5, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 68 */, + 0, 1, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 69 */, + 2, 3, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 70 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 71 */, + 6, 7, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 72 */, + 0, 1, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 73 */, + 2, 3, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 74 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 75 */, + 4, 5, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 76 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 77 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 78 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 255, 255, 255, 255, 255, 255 /* 79 */, + 8, 9, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 80 */, + 0, 1, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 81 */, + 2, 3, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 82 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 83 */, + 4, 5, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 84 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 85 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 86 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 87 */, + 6, 7, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 88 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 89 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 90 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 91 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 92 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 93 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 94 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 255, 255, 255, 255 /* 95 */, + 10, 11, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 96 */, + 0, 1, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 97 */, + 2, 3, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 98 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 99 */, + 4, 5, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 100 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 101 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 102 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 103 */, + 6, 7, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 104 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 105 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 106 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 107 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 108 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 109 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 110 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 255, 255, 255, 255 /* 111 */, + 8, 9, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 112 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 113 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 114 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 115 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 116 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 117 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 118 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 119 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 120 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 121 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 122 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 123 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 124 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 125 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 126 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 255, 255 /* 127 */, + 14, 15, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 128 */, + 0, 1, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 129 */, + 2, 3, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 130 */, + 0, 1, 2, 3, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 131 */, + 4, 5, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 132 */, + 0, 1, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 133 */, + 2, 3, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 134 */, + 0, 1, 2, 3, 4, 5, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 135 */, + 6, 7, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 136 */, + 0, 1, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 137 */, + 2, 3, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 138 */, + 0, 1, 2, 3, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 139 */, + 4, 5, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 140 */, + 0, 1, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 141 */, + 2, 3, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 142 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 14, 15, 255, 255, 255, 255, 255, 255 /* 143 */, + 8, 9, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 144 */, + 0, 1, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 145 */, + 2, 3, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 146 */, + 0, 1, 2, 3, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 147 */, + 4, 5, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 148 */, + 0, 1, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 149 */, + 2, 3, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 150 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 151 */, + 6, 7, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 152 */, + 0, 1, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 153 */, + 2, 3, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 154 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 155 */, + 4, 5, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 156 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 157 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 158 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 14, 15, 255, 255, 255, 255 /* 159 */, + 10, 11, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 160 */, + 0, 1, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 161 */, + 2, 3, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 162 */, + 0, 1, 2, 3, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 163 */, + 4, 5, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 164 */, + 0, 1, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 165 */, + 2, 3, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 166 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 167 */, + 6, 7, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 168 */, + 0, 1, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 169 */, + 2, 3, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 170 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 171 */, + 4, 5, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 172 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 173 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 174 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 14, 15, 255, 255, 255, 255 /* 175 */, + 8, 9, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 176 */, + 0, 1, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 177 */, + 2, 3, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 178 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 179 */, + 4, 5, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 180 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 181 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 182 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 183 */, + 6, 7, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 184 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 185 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 186 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 187 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 188 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 189 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 190 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 14, 15, 255, 255 /* 191 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 192 */, + 0, 1, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 193 */, + 2, 3, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 194 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 195 */, + 4, 5, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 196 */, + 0, 1, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 197 */, + 2, 3, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 198 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 199 */, + 6, 7, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 200 */, + 0, 1, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 201 */, + 2, 3, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 202 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 203 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 204 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 205 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 206 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 207 */, + 8, 9, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 208 */, + 0, 1, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 209 */, + 2, 3, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 210 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 211 */, + 4, 5, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 212 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 213 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 214 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 215 */, + 6, 7, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 216 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 217 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 218 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 219 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 220 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 221 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 222 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 14, 15, 255, 255 /* 223 */, + 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 224 */, + 0, 1, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 225 */, + 2, 3, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 226 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 227 */, + 4, 5, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 228 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 229 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 230 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 231 */, + 6, 7, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 232 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 233 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 234 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 235 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 236 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 237 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 238 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 14, 15, 255, 255 /* 239 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 240 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 241 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 242 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 243 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 244 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 245 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 246 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 247 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 248 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 249 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 250 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 251 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 252 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 253 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 254 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 255 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_eta_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/src/rej_uniform_table.c new file mode 100644 index 0000000000..65bc3b78d3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/aarch64/src/rej_uniform_table.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by rejection sampling of the public matrix. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 7 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 11 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 13 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 15 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/api.h new file mode 100644 index 0000000000..0f1fdeb168 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/api.h @@ -0,0 +1,594 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_API_H +#define MLD_NATIVE_API_H +/* + * Native arithmetic interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + * + * To ensure consistency with backends, the header will be + * included automatically after inclusion of the active + * backend, to ensure consistency of function signatures, + * and run sanity checks. + */ + +#include +#include "../cbmc.h" +#include "../common.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* Bound on absolute value of coefficients after NTT. + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) + +/* Absolute exclusive upper bound for the output of the inverse NTT + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_INTT_BOUND MLDSA_Q + +/* Absolute bound for range of mld_reduce32() + * + * NOTE: This is the same bound as in reduce.h and has to be kept + * in sync. */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define REDUCE32_RANGE_MAX 6283009 +/* + * This is the C<->native interface allowing for the drop-in of + * native code for performance critical arithmetic components of ML-DSA. + * + * A _backend_ is a specific implementation of (part of) this interface. + * + * To add a function to a backend, define MLD_USE_NATIVE_XXX and + * implement `static inline xxx(...)` in the profile header. + */ + +/* + * Those functions are meant to be trivial wrappers around the chosen native + * implementation. The are static inline to avoid unnecessary calls. + * The macro before each declaration controls whether a native + * implementation is present. + */ + +#if defined(MLD_USE_NATIVE_NTT) +/************************************************* + * Name: mld_ntt_native + * + * Description: Computes negacyclic number-theoretic transform (NTT) of + * a polynomial in place. + * + * The input polynomial is assumed to be in normal order. + * The output polynomial is in bitreversed order. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_ntt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_NTT */ + + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) +/* + * This must only be set if NTT and INTT have native implementations + * that are adapted to the custom order. + */ +#if !defined(MLD_USE_NATIVE_NTT) || !defined(MLD_USE_NATIVE_INTT) +#error \ + "Invalid native profile: MLD_USE_NATIVE_NTT_CUSTOM_ORDER can only be \ +set if there are native implementations for NTT and INTT." +#endif + +/************************************************* + * Name: mlD_poly_permute_bitrev_to_custom + * + * Description: When MLD_USE_NATIVE_NTT_CUSTOM_ORDER is defined, + * convert a polynomial in NTT domain from bitreversed + * order to the custom order output by the native NTT. + * + * This must only be defined if there is native code for + * both the NTT and INTT. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + * + **************************************************/ +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t p[MLDSA_N]) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q))); +#endif /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + + +#if defined(MLD_USE_NATIVE_INTT) +/************************************************* + * Name: mld_intt_native + * + * Description: Computes inverse of negacyclic number-theoretic transform + *(NTT) of a polynomial in place. + * + * The input polynomial is in bitreversed order. + * The output polynomial is assumed to be in normal order. + * + * Arguments: - uint32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_intt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_INTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_INTT */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) +/************************************************* + * Name: mld_rej_uniform_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [0, MLDSA_Q-1] + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform mod q). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + * lengths. Otherwise, returns non-negative number of sampled 32-bit integers + * (at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= ( 5 * 168) && buflen % 3 == 0) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(r, 0, (unsigned) return_value, 0, MLDSA_Q)) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) +/************************************************* + * Name: mld_rej_uniform_eta2_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-2,+2]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-2, +2]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA2 */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) +/************************************************* + * Name: mld_rej_uniform_eta4_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-4,+4]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-4, +4]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) +/************************************************* + * Name: mld_poly_decompose_32_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/32. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: input/output polynomial. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_32 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) +/************************************************* + * Name: mld_poly_decompose_88_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/88. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: output polynomial with coefficients c0. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CADDQ) +/************************************************* + * Name: mld_poly_caddq_native + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *a: pointer to input/output polynomial + **************************************************/ +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_32) +/************************************************* + * Name: mld_poly_use_hint_32_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/32. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_32 */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) +/************************************************* + * Name: mld_poly_use_hint_88_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/88. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) +/************************************************* + * Name: mld_poly_chknorm_native + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const int32_t *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if the infinity norm is strictly smaller than B, and 1 + * otherwise. B must not be larger than MLDSA_Q - MLD_REDUCE32_RANGE_MAX. + **************************************************/ +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(0 <= B && B <= MLDSA_Q - REDUCE32_RANGE_MAX) + requires(array_bound(a, 0, MLDSA_N, -REDUCE32_RANGE_MAX, REDUCE32_RANGE_MAX)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == 0) == array_abs_bound(a, 0, MLDSA_N, B)) +); +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) +/************************************************* + * Name: mld_polyz_unpack_17_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^17. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_17 */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) +/************************************************* + * Name: mld_polyz_unpack_19_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^19. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_19 */ + +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) +/************************************************* + * Name: mld_poly_pointwise_montgomery_native + * + * Description: Pointwise multiplication of polynomials in NTT domain + * with Montgomery reduction. + * + * Computes c[i] = a[i] * b[i] * R^(-1) mod q for all i, + * where R = 2^32. + * + * Arguments: - int32_t c[MLDSA_N]: output polynomial + * - const int32_t a[MLDSA_N]: first input polynomial + * - const int32_t b[MLDSA_N]: second input polynomial + **************************************************/ +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(c, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(c, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(c, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l4_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 4. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 4 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 4 * MLDSA_N)) + requires(forall(l0, 0, 4, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 4, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l5_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 5. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 5 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 5 * MLDSA_N)) + requires(forall(l0, 0, 5, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 5, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l7_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 7. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 7 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 7 * MLDSA_N)) + requires(forall(l0, 0, 7, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 7, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 */ + +#endif /* !MLD_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/meta.h new file mode 100644 index 0000000000..0b46dd5791 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/meta.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_META_H +#define MLD_NATIVE_META_H + +/* + * Default arithmetic backend + */ +#include "../sys.h" + +#ifdef MLD_SYS_AARCH64 +#include "aarch64/meta.h" +#endif + +#ifdef MLD_SYS_X86_64_AVX2 +#include "x86_64/meta.h" +#endif + +#endif /* !MLD_NATIVE_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/meta.h new file mode 100644 index 0000000000..393374c06f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/meta.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_X86_64_META_H +#define MLD_NATIVE_X86_64_META_H + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_X86_64_DEFAULT + +#define MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +#if !defined(__ASSEMBLER__) +#include +#include "../../common.h" +#include "../api.h" +#include "src/arith_native_x86_64.h" + +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t data[MLDSA_N]) +{ + if (mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + mld_nttunpack_avx2(data); + } +} + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_ntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_invntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)mld_rej_uniform_avx2(r, buf); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_32_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_88_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_caddq_avx2(a); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_32_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_88_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + return mld_poly_chknorm_avx2(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_17_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_19_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_avx2(c, a, b, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l4_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l5_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l7_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_NATIVE_X86_64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h new file mode 100644 index 0000000000..08d5abf74a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#define MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#include "../../../common.h" + +#include +#include "consts.h" + +#define MLD_AVX2_REJ_UNIFORM_BUFLEN \ + (5 * 168) /* REJ_UNIFORM_NBLOCKS * SHAKE128_RATE */ + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) + +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_rej_uniform_table MLD_NAMESPACE(mld_rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[256][8]; + +#define mld_ntt_avx2 MLD_NAMESPACE(ntt_avx2) +void mld_ntt_avx2(int32_t *r, const int32_t *qdata) +/* This must be kept in sync with the HOL-Light specification + * in proofs/hol_light/x86_64/proofs/mldsa_ntt.ml */ +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, MLDSA_N, 8380417)) + requires(qdata == mld_qdata) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + /* check-magic: off */ + ensures(array_abs_bound(r, 0, MLDSA_N, 42035262)) + /* check-magic: on */ +); + +#define mld_invntt_avx2 MLD_NAMESPACE(invntt_avx2) +void mld_invntt_avx2(int32_t *r, const int32_t *mld_qdata); + +#define mld_nttunpack_avx2 MLD_NAMESPACE(nttunpack_avx2) +void mld_nttunpack_avx2(int32_t *r); + +#define mld_rej_uniform_avx2 MLD_NAMESPACE(mld_rej_uniform_avx2) +unsigned mld_rej_uniform_avx2(int32_t *r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]); + +#define mld_rej_uniform_eta2_avx2 MLD_NAMESPACE(mld_rej_uniform_eta2_avx2) +unsigned mld_rej_uniform_eta2_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]); + +#define mld_rej_uniform_eta4_avx2 MLD_NAMESPACE(mld_rej_uniform_eta4_avx2) +unsigned mld_rej_uniform_eta4_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]); + +#define mld_poly_decompose_32_avx2 MLD_NAMESPACE(mld_poly_decompose_32_avx2) +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_avx2 MLD_NAMESPACE(mld_poly_decompose_88_avx2) +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_avx2 MLD_NAMESPACE(poly_caddq_avx2) +void mld_poly_caddq_avx2(int32_t *r); + +#define mld_poly_use_hint_32_avx2 MLD_NAMESPACE(mld_poly_use_hint_32_avx2) +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_avx2 MLD_NAMESPACE(mld_poly_use_hint_88_avx2) +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_avx2 MLD_NAMESPACE(mld_poly_chknorm_avx2) +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_avx2 MLD_NAMESPACE(mld_polyz_unpack_17_avx2) +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a); + +#define mld_polyz_unpack_19_avx2 MLD_NAMESPACE(mld_polyz_unpack_19_avx2) +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a); + +#define mld_pointwise_avx2 MLD_NAMESPACE(pointwise_avx2) +void mld_pointwise_avx2(int32_t *c, const int32_t *a, const int32_t *b, + const int32_t *qdata); + +#define mld_pointwise_acc_l4_avx2 MLD_NAMESPACE(pointwise_acc_l4_avx2) +void mld_pointwise_acc_l4_avx2(int32_t c[MLDSA_N], const int32_t a[4][MLDSA_N], + const int32_t b[4][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l5_avx2 MLD_NAMESPACE(pointwise_acc_l5_avx2) +void mld_pointwise_acc_l5_avx2(int32_t c[MLDSA_N], const int32_t a[5][MLDSA_N], + const int32_t b[5][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l7_avx2 MLD_NAMESPACE(pointwise_acc_l7_avx2) +void mld_pointwise_acc_l7_avx2(int32_t c[MLDSA_N], const int32_t a[7][MLDSA_N], + const int32_t b[7][MLDSA_N], + const int32_t *qdata); + +#endif /* !MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/consts.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/consts.c new file mode 100644 index 0000000000..aaca3535ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/consts.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include "consts.h" + +/* + * Table of zeta values used in the AVX2 forward and inverse NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_qdata[624] = { + 8380417, 8380417, 8380417, 8380417, 8380417, + 8380417, 8380417, 8380417, 58728449, 58728449, + 58728449, 58728449, 58728449, 58728449, 58728449, + 58728449, -8395782, -8395782, -8395782, -8395782, + -8395782, -8395782, -8395782, -8395782, 41978, + 41978, 41978, 41978, 41978, 41978, + 41978, 41978, -151046689, 1830765815, -1929875198, + -1927777021, 1640767044, 1477910808, 1612161320, 1640734244, + 308362795, 308362795, 308362795, 308362795, -1815525077, + -1815525077, -1815525077, -1815525077, -1374673747, -1374673747, + -1374673747, -1374673747, -1091570561, -1091570561, -1091570561, + -1091570561, -1929495947, -1929495947, -1929495947, -1929495947, + 515185417, 515185417, 515185417, 515185417, -285697463, + -285697463, -285697463, -285697463, 625853735, 625853735, + 625853735, 625853735, 1727305304, 1727305304, 2082316400, + 2082316400, -1364982364, -1364982364, 858240904, 858240904, + 1806278032, 1806278032, 222489248, 222489248, -346752664, + -346752664, 684667771, 684667771, 1654287830, 1654287830, + -878576921, -878576921, -1257667337, -1257667337, -748618600, + -748618600, 329347125, 329347125, 1837364258, 1837364258, + -1443016191, -1443016191, -1170414139, -1170414139, -1846138265, + -1631226336, -1404529459, 1838055109, 1594295555, -1076973524, + -1898723372, -594436433, -202001019, -475984260, -561427818, + 1797021249, -1061813248, 2059733581, -1661512036, -1104976547, + -1750224323, -901666090, 418987550, 1831915353, -1925356481, + 992097815, 879957084, 2024403852, 1484874664, -1636082790, + -285388938, -1983539117, -1495136972, -950076368, -1714807468, + -952438995, -1574918427, 1350681039, -2143979939, 1599739335, + -1285853323, -993005454, -1440787840, 568627424, -783134478, + -588790216, 289871779, -1262003603, 2135294594, -1018755525, + -889861155, 1665705315, 1321868265, 1225434135, -1784632064, + 666258756, 675310538, -1555941048, -1999506068, -1499481951, + -695180180, -1375177022, 1777179795, 334803717, -178766299, + -518252220, 1957047970, 1146323031, -654783359, -1974159335, + 1651689966, 140455867, -1039411342, 1955560694, 1529189038, + -2131021878, -247357819, 1518161567, -86965173, 1708872713, + 1787797779, 1638590967, -120646188, -1669960606, -916321552, + 1155548552, 2143745726, 1210558298, -1261461890, -318346816, + 628664287, -1729304568, 1422575624, 1424130038, -1185330464, + 235321234, 168022240, 1206536194, 985155484, -894060583, + -898413, -1363460238, -605900043, 2027833504, 14253662, + 1014493059, 863641633, 1819892093, 2124962073, -1223601433, + -1920467227, -1637785316, -1536588520, 694382729, 235104446, + -1045062172, 831969619, -300448763, 756955444, -260312805, + 1554794072, 1339088280, -2040058690, -853476187, -2047270596, + -1723816713, -1591599803, -440824168, 1119856484, 1544891539, + 155290192, -973777462, 991903578, 912367099, -44694137, + 1176904444, -421552614, -818371958, 1747917558, -325927722, + 908452108, 1851023419, -1176751719, -1354528380, -72690498, + -314284737, 985022747, 963438279, -1078959975, 604552167, + -1021949428, 608791570, 173440395, -2126092136, -1316619236, + -1039370342, 6087993, -110126092, 565464272, -1758099917, + -1600929361, 879867909, -1809756372, 400711272, 1363007700, + 30313375, -326425360, 1683520342, -517299994, 2027935492, + -1372618620, 128353682, -1123881663, 137583815, -635454918, + -642772911, 45766801, 671509323, -2070602178, 419615363, + 1216882040, -270590488, -1276805128, 371462360, -1357098057, + -384158533, 827959816, -596344473, 702390549, -279505433, + -260424530, -71875110, -1208667171, -1499603926, 2036925262, + -540420426, 746144248, -1420958686, 2032221021, 1904936414, + 1257750362, 1926727420, 1931587462, 1258381762, 885133339, + 1629985060, 1967222129, 6363718, -1287922800, 1136965286, + 1779436847, 1116720494, 1042326957, 1405999311, 713994583, + 940195359, -1542497137, 2061661095, -883155599, 1726753853, + -1547952704, 394851342, 283780712, 776003547, 1123958025, + 201262505, 1934038751, 374860238, -3975713, 25847, + -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 1826347, 1826347, 1826347, + 2353451, 2353451, 2353451, 2353451, -359251, + -359251, -359251, -359251, -2091905, -2091905, + -2091905, -2091905, 3119733, 3119733, 3119733, + 3119733, -2884855, -2884855, -2884855, -2884855, + 3111497, 3111497, 3111497, 3111497, 2680103, + 2680103, 2680103, 2680103, 2725464, 2725464, + 1024112, 1024112, -1079900, -1079900, 3585928, + 3585928, -549488, -549488, -1119584, -1119584, + 2619752, 2619752, -2108549, -2108549, -2118186, + -2118186, -3859737, -3859737, -1399561, -1399561, + -3277672, -3277672, 1757237, 1757237, -19422, + -19422, 4010497, 4010497, 280005, 280005, + 2706023, 95776, 3077325, 3530437, -1661693, + -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, + -539299, -1699267, -1643818, 3505694, -3821735, + 3507263, -2140649, -1600420, 3699596, 811944, + 531354, 954230, 3881043, 3900724, -2556880, + 2071892, -2797779, -3930395, -3677745, -1452451, + 2176455, -1257611, -4083598, -3190144, -3632928, + 3412210, 2147896, -2967645, -411027, -671102, + -22981, -381987, 1852771, -3343383, 508951, + 44288, 904516, -3724342, 1653064, 2389356, + 759969, 189548, 3159746, -2409325, 1315589, + 1285669, -812732, -3019102, -3628969, -1528703, + -3041255, 3475950, -1585221, 1939314, -1000202, + -3157330, 126922, -983419, 2715295, -3693493, + -2477047, -1228525, -1308169, 1349076, -1430430, + 264944, 3097992, -1100098, 3958618, -8578, + -3249728, -210977, -1316856, -3553272, -1851402, + -177440, 1341330, -1584928, -1439742, -3881060, + 3839961, 2091667, -3342478, 266997, -3520352, + 900702, 495491, -655327, -3556995, 342297, + 3437287, 2842341, 4055324, -3767016, -2994039, + -1333058, -451100, -1279661, 1500165, -542412, + -2584293, -2013608, 1957272, -3183426, 810149, + -3038916, 2213111, -426683, -1667432, -2939036, + 183443, -554416, 3937738, 3407706, 2244091, + 2434439, -3759364, 1859098, -1613174, -3122442, + -525098, 286988, -3342277, 2691481, 1247620, + 1250494, 1869119, 1237275, 1312455, 1917081, + 777191, -2831860, -3724270, 2432395, 3369112, + 162844, 1652634, 3523897, -975884, 1723600, + -1104333, -2235985, -976891, 3919660, 1400424, + 2316500, -2446433, -1235728, -1197226, 909542, + -43260, 2031748, -768622, -2437823, 1735879, + -2590150, 2486353, 2635921, 1903435, -3318210, + 3306115, -2546312, 2235880, -1671176, 594136, + 2454455, 185531, 1616392, -3694233, 3866901, + 1717735, -1803090, -260646, -420899, 1612842, + -48306, -846154, 3817976, -3562462, 3513181, + -3193378, 819034, -522500, 3207046, -3595838, + 4108315, 203044, 1265009, 1595974, -3548272, + -1050970, -1430225, -1962642, -1374803, 3406031, + -1846953, -3776993, -164721, -1207385, 3014001, + -1799107, 269760, 472078, 1910376, -3833893, + -2286327, -3545687, -1362209, 1976782, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_consts) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/consts.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/consts.h new file mode 100644 index 0000000000..7fe08f454b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/consts.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#ifndef MLD_NATIVE_X86_64_SRC_CONSTS_H +#define MLD_NATIVE_X86_64_SRC_CONSTS_H +#include "../../../common.h" +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQ 0 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV 8 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV 16 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV 24 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV 32 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS 328 + +#ifndef __ASSEMBLER__ +#define mld_qdata MLD_NAMESPACE(qdata) +extern const int32_t mld_qdata[624]; +#endif + +#endif /* !MLD_NATIVE_X86_64_SRC_CONSTS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c new file mode 100644 index 0000000000..05d86d14fc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/************************************************* + * Name: mld_poly_caddq_avx2 + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *r: pointer to input/output polynomial + **************************************************/ +void mld_poly_caddq_avx2(int32_t *r) +{ + unsigned int i; + __m256i f, g; + const __m256i q = _mm256_set1_epi32(MLDSA_Q); + const __m256i zero = _mm256_setzero_si256(); + __m256i *rr = (__m256i *)r; + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256(&rr[i]); + g = _mm256_cmpgt_epi32(zero, f); + g = _mm256_and_si256(g, q); + f = _mm256_add_epi32(f, g); + _mm256_store_si256(&rr[i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_reduce) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c new file mode 100644 index 0000000000..50e2c7fa9b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B) +{ + unsigned int i; + __m256i f, t; + const __m256i bound = _mm256_set1_epi32(B - 1); + + t = _mm256_setzero_si256(); + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + f = _mm256_abs_epi32(f); + f = _mm256_cmpgt_epi32(f, bound); + t = _mm256_or_si256(t, f); + } + + return 1 - _mm256_testz_si256(t, t); +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_chknorm) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c new file mode 100644 index 0000000000..76846bf1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(31 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 4092 == intdiv(2 * intdiv(MLDSA_Q - 1, 32), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 4092. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 32*GAMMA2 = 16*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 16B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + * + * round(f1' * 1025 / 2^22) is in turn computed in 2 steps as + * round(floor(f1' * 1025 / 2^16) / 2^6). The mulhi computes f1'' = + * floor(f1' * 1025 / 2^16). As for the next step f1 = round(f1'' / 2^6), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^9) = round(f1'' * 2^9 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 1025 / 2^16) = 1025 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(16B / B) = 16 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 16, i.e. f > 31*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 31*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 15, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c new file mode 100644 index 0000000000..463506b962 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ + +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 1488 == intdiv(2 * intdiv(MLDSA_Q - 1, 88), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 1488. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 88*GAMMA2 = 44*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 44B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + * + * round(f1' * 11275 / 2^24) is in turn computed in 2 steps as + * round(floor(f1' * 11275 / 2^16) / 2^8). The mulhi computes f1'' = + * floor(f1' * 11275 / 2^16). As for the next step f1 = round(f1'' / 2^8), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^7) = round(f1'' * 2^7 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 11275 / 2^16) = 11275 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(44B / B) = 44 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 44, i.e. f > 87*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 87*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 43, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c new file mode 100644 index 0000000000..0094bc93a9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + const __m256i mask = _mm256_set1_epi32(15); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_32_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 16 */ + f1 = _mm256_add_epi32(f1, h); + f1 = _mm256_and_si256(f1, mask); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c new file mode 100644 index 0000000000..b109ab6351 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + const __m256i max = _mm256_set1_epi32(43); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_88_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 44 */ + f1 = _mm256_add_epi32(f1, h); + f1 = MLD_MM256_BLENDV_EPI32(f1, max, f1); + f = _mm256_cmpgt_epi32(f1, max); + f1 = MLD_MM256_BLENDV_EPI32(f1, zero, f); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c new file mode 100644 index 0000000000..f6c08a832f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 27, 26, 25, -1, 25, 24, 23, -1, 8, 7, + 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0); + const __m256i srlvdidx = _mm256_set_epi32(6, 4, 2, 0, 6, 4, 2, 0); + const __m256i mask = _mm256_set1_epi32(0x3FFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 17)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[18 * i]); + /* Load bytes 2..17 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[18 * i + 2]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-8 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 8, 7, 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte8, byte7, byte6, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,27, 26, 25, -1,25, 24, 23] │ + * │ Result: [0, byte17, byte16, byte15, ..., 0, byte11, byte10, byte9] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 18 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 32..55 48..71 + * 72..95 88..111 104..127 120..143 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 18..39 36..55 54..71 + * 72..95 90..111 108..127 126..143 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..17 18..35 36..53 54..71 + * 72..89 90..107 108..125 126..143 */ + + /* Map [0, 1, ..., 2^18-1] to [2^17, 2^17-1, ..., -2^17+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_17) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c new file mode 100644 index 0000000000..4a5ce48f38 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 26, 25, 24, -1, 24, 23, 22, -1, 9, 8, + 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0); + /* Equivalent to _mm256_set_epi32(4, 0, 4, 0, 4, 0, 4, 0) */ + const __m256i srlvdidx = _mm256_set1_epi64x((uint64_t)4 << 32); + const __m256i mask = _mm256_set1_epi32(0xFFFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 19)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[20 * i]); + /* Load bytes 4..19 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[20 * i + 4]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-9 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 9, 8, 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte9, byte8, byte7, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,26, 25, 24, -1,24, 23, 22] │ + * │ Result: [0, byte19, byte18, byte17, ..., 0, byte12, byte11, byte10] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 20 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 40..63 56..79 + * 80..103 96..119 120..143 136..159 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 20..39 40..63 60..79 + * 80..103 100..119 120..143 140..159 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..19 20..39 40..59 60..79 + * 80..99 100..119 120..139 140..159 */ + + /* Map [0, 1, ..., 2^20-1] to [2^19, 2^19-1, ..., -2^19+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_19) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c new file mode 100644 index 0000000000..07a5df9706 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The pqcrystals implementation assumes a buffer that is 8 bytes + *. larger as the first loop overreads by 8 bytes that are then + * discarded. We instead do not pad the buffer and do not overread. + * The performance impact is negligible and it does not force the + * frontend to perform the unintuitive padding. + */ + +unsigned int mld_rej_uniform_avx2( + int32_t *MLD_RESTRICT r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i d, tmp; + const __m256i bound = _mm256_set1_epi32(MLDSA_Q); + const __m256i mask = _mm256_set1_epi32(0x7FFFFF); + const __m256i idx8 = + _mm256_set_epi8(-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4, + -1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 32) + { + d = _mm256_loadu_si256((__m256i *)&buf[pos]); + + /* Permute 64-bit lanes + * 0x94 = 10010100b rearranges 64-bit lanes as: [3,2,1,0] -> [2,1,1,0] + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Original Layout ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ bytes 16..23 │ bytes 24..31 │ + * └─────────────────┴─────────────────┴─────────────────┴─────────────────┘ + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Layout after permute ║ + * ║ Byte indices in high half shifted down by 8 positions ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌───────────────┬─────────────────┐ ┌─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ │ bytes 8..15 │ bytes 16..23 │ + * └───────────────┴─────────────────┘ └─────────────────┴─────────────────┘ + * Lower 128-bit lane (bytes 0-15) Upper 128-bit lane (bytes 16-31) + */ + d = _mm256_permute4x64_epi64(d, 0x94); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-11 into low 128-bit half of permuted vector────────────────┐ + * │ Shuffle: [-1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0] │ + * │ Result: [0, byte11, byte10, byte9, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 4-15 into high 128-bit half of permuted vector ──────────────┐ + * │ Shuffle: [-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4] │ + * │ Result: [0, byte23, byte22, byte21, ..., 0, byte14, byte13, byte12 │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + d = _mm256_shuffle_epi8(d, idx8); + d = _mm256_and_si256(d, mask); + pos += 24; + + tmp = _mm256_sub_epi32(d, bound); + good = (uint32_t)_mm256_movemask_ps((__m256)tmp); + tmp = _mm256_cvtepu8_epi32( + _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good])); + d = _mm256_permutevar8x32_epi32(d, tmp); + + _mm256_storeu_si256((__m256i *)&r[ctr], d); + ctr += (unsigned)_mm_popcnt_u32(good); + } + + while (ctr < MLDSA_N && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 3) + { + uint32_t t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + /* Safe because t < MLDSA_Q. */ + r[ctr++] = (int32_t)t; + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c new file mode 100644 index 0000000000..70c5c42c70 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA2 2 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ +unsigned int mld_rej_uniform_eta2_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1, f2; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA2); + const __m256i bound = mask; + /* check-magic: -6560 == 32*round(-2**10 / 5) */ + const __m256i v = _mm256_set1_epi32(-6560); + const __m256i p = _mm256_set1_epi32(5); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 15) + { + t0 = t0 - (205 * t0 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t0); + } + if (t1 < 15 && ctr < MLDSA_N) + { + t1 = t1 - (205 * t1 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta2) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA2 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c new file mode 100644 index 0000000000..ba00e91252 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA4 4 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ + +unsigned int mld_rej_uniform_eta4_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA4); + const __m256i bound = _mm256_set1_epi8(9); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 9) + { + r[ctr++] = (int32_t)(4 - t0); + } + if (t1 < 9 && ctr < MLDSA_N) + { + r[ctr++] = (int32_t)(4 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta4) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA4 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_table.c new file mode 100644 index 0000000000..6c537b4542 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_table.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" + +/* + * Lookup table used by rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[256][8] = { + {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, + {2, 0, 0, 0, 0, 0, 0, 0}, {0, 2, 0, 0, 0, 0, 0, 0}, + {1, 2, 0, 0, 0, 0, 0, 0}, {0, 1, 2, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 0, 0}, {0, 3, 0, 0, 0, 0, 0, 0}, + {1, 3, 0, 0, 0, 0, 0, 0}, {0, 1, 3, 0, 0, 0, 0, 0}, + {2, 3, 0, 0, 0, 0, 0, 0}, {0, 2, 3, 0, 0, 0, 0, 0}, + {1, 2, 3, 0, 0, 0, 0, 0}, {0, 1, 2, 3, 0, 0, 0, 0}, + {4, 0, 0, 0, 0, 0, 0, 0}, {0, 4, 0, 0, 0, 0, 0, 0}, + {1, 4, 0, 0, 0, 0, 0, 0}, {0, 1, 4, 0, 0, 0, 0, 0}, + {2, 4, 0, 0, 0, 0, 0, 0}, {0, 2, 4, 0, 0, 0, 0, 0}, + {1, 2, 4, 0, 0, 0, 0, 0}, {0, 1, 2, 4, 0, 0, 0, 0}, + {3, 4, 0, 0, 0, 0, 0, 0}, {0, 3, 4, 0, 0, 0, 0, 0}, + {1, 3, 4, 0, 0, 0, 0, 0}, {0, 1, 3, 4, 0, 0, 0, 0}, + {2, 3, 4, 0, 0, 0, 0, 0}, {0, 2, 3, 4, 0, 0, 0, 0}, + {1, 2, 3, 4, 0, 0, 0, 0}, {0, 1, 2, 3, 4, 0, 0, 0}, + {5, 0, 0, 0, 0, 0, 0, 0}, {0, 5, 0, 0, 0, 0, 0, 0}, + {1, 5, 0, 0, 0, 0, 0, 0}, {0, 1, 5, 0, 0, 0, 0, 0}, + {2, 5, 0, 0, 0, 0, 0, 0}, {0, 2, 5, 0, 0, 0, 0, 0}, + {1, 2, 5, 0, 0, 0, 0, 0}, {0, 1, 2, 5, 0, 0, 0, 0}, + {3, 5, 0, 0, 0, 0, 0, 0}, {0, 3, 5, 0, 0, 0, 0, 0}, + {1, 3, 5, 0, 0, 0, 0, 0}, {0, 1, 3, 5, 0, 0, 0, 0}, + {2, 3, 5, 0, 0, 0, 0, 0}, {0, 2, 3, 5, 0, 0, 0, 0}, + {1, 2, 3, 5, 0, 0, 0, 0}, {0, 1, 2, 3, 5, 0, 0, 0}, + {4, 5, 0, 0, 0, 0, 0, 0}, {0, 4, 5, 0, 0, 0, 0, 0}, + {1, 4, 5, 0, 0, 0, 0, 0}, {0, 1, 4, 5, 0, 0, 0, 0}, + {2, 4, 5, 0, 0, 0, 0, 0}, {0, 2, 4, 5, 0, 0, 0, 0}, + {1, 2, 4, 5, 0, 0, 0, 0}, {0, 1, 2, 4, 5, 0, 0, 0}, + {3, 4, 5, 0, 0, 0, 0, 0}, {0, 3, 4, 5, 0, 0, 0, 0}, + {1, 3, 4, 5, 0, 0, 0, 0}, {0, 1, 3, 4, 5, 0, 0, 0}, + {2, 3, 4, 5, 0, 0, 0, 0}, {0, 2, 3, 4, 5, 0, 0, 0}, + {1, 2, 3, 4, 5, 0, 0, 0}, {0, 1, 2, 3, 4, 5, 0, 0}, + {6, 0, 0, 0, 0, 0, 0, 0}, {0, 6, 0, 0, 0, 0, 0, 0}, + {1, 6, 0, 0, 0, 0, 0, 0}, {0, 1, 6, 0, 0, 0, 0, 0}, + {2, 6, 0, 0, 0, 0, 0, 0}, {0, 2, 6, 0, 0, 0, 0, 0}, + {1, 2, 6, 0, 0, 0, 0, 0}, {0, 1, 2, 6, 0, 0, 0, 0}, + {3, 6, 0, 0, 0, 0, 0, 0}, {0, 3, 6, 0, 0, 0, 0, 0}, + {1, 3, 6, 0, 0, 0, 0, 0}, {0, 1, 3, 6, 0, 0, 0, 0}, + {2, 3, 6, 0, 0, 0, 0, 0}, {0, 2, 3, 6, 0, 0, 0, 0}, + {1, 2, 3, 6, 0, 0, 0, 0}, {0, 1, 2, 3, 6, 0, 0, 0}, + {4, 6, 0, 0, 0, 0, 0, 0}, {0, 4, 6, 0, 0, 0, 0, 0}, + {1, 4, 6, 0, 0, 0, 0, 0}, {0, 1, 4, 6, 0, 0, 0, 0}, + {2, 4, 6, 0, 0, 0, 0, 0}, {0, 2, 4, 6, 0, 0, 0, 0}, + {1, 2, 4, 6, 0, 0, 0, 0}, {0, 1, 2, 4, 6, 0, 0, 0}, + {3, 4, 6, 0, 0, 0, 0, 0}, {0, 3, 4, 6, 0, 0, 0, 0}, + {1, 3, 4, 6, 0, 0, 0, 0}, {0, 1, 3, 4, 6, 0, 0, 0}, + {2, 3, 4, 6, 0, 0, 0, 0}, {0, 2, 3, 4, 6, 0, 0, 0}, + {1, 2, 3, 4, 6, 0, 0, 0}, {0, 1, 2, 3, 4, 6, 0, 0}, + {5, 6, 0, 0, 0, 0, 0, 0}, {0, 5, 6, 0, 0, 0, 0, 0}, + {1, 5, 6, 0, 0, 0, 0, 0}, {0, 1, 5, 6, 0, 0, 0, 0}, + {2, 5, 6, 0, 0, 0, 0, 0}, {0, 2, 5, 6, 0, 0, 0, 0}, + {1, 2, 5, 6, 0, 0, 0, 0}, {0, 1, 2, 5, 6, 0, 0, 0}, + {3, 5, 6, 0, 0, 0, 0, 0}, {0, 3, 5, 6, 0, 0, 0, 0}, + {1, 3, 5, 6, 0, 0, 0, 0}, {0, 1, 3, 5, 6, 0, 0, 0}, + {2, 3, 5, 6, 0, 0, 0, 0}, {0, 2, 3, 5, 6, 0, 0, 0}, + {1, 2, 3, 5, 6, 0, 0, 0}, {0, 1, 2, 3, 5, 6, 0, 0}, + {4, 5, 6, 0, 0, 0, 0, 0}, {0, 4, 5, 6, 0, 0, 0, 0}, + {1, 4, 5, 6, 0, 0, 0, 0}, {0, 1, 4, 5, 6, 0, 0, 0}, + {2, 4, 5, 6, 0, 0, 0, 0}, {0, 2, 4, 5, 6, 0, 0, 0}, + {1, 2, 4, 5, 6, 0, 0, 0}, {0, 1, 2, 4, 5, 6, 0, 0}, + {3, 4, 5, 6, 0, 0, 0, 0}, {0, 3, 4, 5, 6, 0, 0, 0}, + {1, 3, 4, 5, 6, 0, 0, 0}, {0, 1, 3, 4, 5, 6, 0, 0}, + {2, 3, 4, 5, 6, 0, 0, 0}, {0, 2, 3, 4, 5, 6, 0, 0}, + {1, 2, 3, 4, 5, 6, 0, 0}, {0, 1, 2, 3, 4, 5, 6, 0}, + {7, 0, 0, 0, 0, 0, 0, 0}, {0, 7, 0, 0, 0, 0, 0, 0}, + {1, 7, 0, 0, 0, 0, 0, 0}, {0, 1, 7, 0, 0, 0, 0, 0}, + {2, 7, 0, 0, 0, 0, 0, 0}, {0, 2, 7, 0, 0, 0, 0, 0}, + {1, 2, 7, 0, 0, 0, 0, 0}, {0, 1, 2, 7, 0, 0, 0, 0}, + {3, 7, 0, 0, 0, 0, 0, 0}, {0, 3, 7, 0, 0, 0, 0, 0}, + {1, 3, 7, 0, 0, 0, 0, 0}, {0, 1, 3, 7, 0, 0, 0, 0}, + {2, 3, 7, 0, 0, 0, 0, 0}, {0, 2, 3, 7, 0, 0, 0, 0}, + {1, 2, 3, 7, 0, 0, 0, 0}, {0, 1, 2, 3, 7, 0, 0, 0}, + {4, 7, 0, 0, 0, 0, 0, 0}, {0, 4, 7, 0, 0, 0, 0, 0}, + {1, 4, 7, 0, 0, 0, 0, 0}, {0, 1, 4, 7, 0, 0, 0, 0}, + {2, 4, 7, 0, 0, 0, 0, 0}, {0, 2, 4, 7, 0, 0, 0, 0}, + {1, 2, 4, 7, 0, 0, 0, 0}, {0, 1, 2, 4, 7, 0, 0, 0}, + {3, 4, 7, 0, 0, 0, 0, 0}, {0, 3, 4, 7, 0, 0, 0, 0}, + {1, 3, 4, 7, 0, 0, 0, 0}, {0, 1, 3, 4, 7, 0, 0, 0}, + {2, 3, 4, 7, 0, 0, 0, 0}, {0, 2, 3, 4, 7, 0, 0, 0}, + {1, 2, 3, 4, 7, 0, 0, 0}, {0, 1, 2, 3, 4, 7, 0, 0}, + {5, 7, 0, 0, 0, 0, 0, 0}, {0, 5, 7, 0, 0, 0, 0, 0}, + {1, 5, 7, 0, 0, 0, 0, 0}, {0, 1, 5, 7, 0, 0, 0, 0}, + {2, 5, 7, 0, 0, 0, 0, 0}, {0, 2, 5, 7, 0, 0, 0, 0}, + {1, 2, 5, 7, 0, 0, 0, 0}, {0, 1, 2, 5, 7, 0, 0, 0}, + {3, 5, 7, 0, 0, 0, 0, 0}, {0, 3, 5, 7, 0, 0, 0, 0}, + {1, 3, 5, 7, 0, 0, 0, 0}, {0, 1, 3, 5, 7, 0, 0, 0}, + {2, 3, 5, 7, 0, 0, 0, 0}, {0, 2, 3, 5, 7, 0, 0, 0}, + {1, 2, 3, 5, 7, 0, 0, 0}, {0, 1, 2, 3, 5, 7, 0, 0}, + {4, 5, 7, 0, 0, 0, 0, 0}, {0, 4, 5, 7, 0, 0, 0, 0}, + {1, 4, 5, 7, 0, 0, 0, 0}, {0, 1, 4, 5, 7, 0, 0, 0}, + {2, 4, 5, 7, 0, 0, 0, 0}, {0, 2, 4, 5, 7, 0, 0, 0}, + {1, 2, 4, 5, 7, 0, 0, 0}, {0, 1, 2, 4, 5, 7, 0, 0}, + {3, 4, 5, 7, 0, 0, 0, 0}, {0, 3, 4, 5, 7, 0, 0, 0}, + {1, 3, 4, 5, 7, 0, 0, 0}, {0, 1, 3, 4, 5, 7, 0, 0}, + {2, 3, 4, 5, 7, 0, 0, 0}, {0, 2, 3, 4, 5, 7, 0, 0}, + {1, 2, 3, 4, 5, 7, 0, 0}, {0, 1, 2, 3, 4, 5, 7, 0}, + {6, 7, 0, 0, 0, 0, 0, 0}, {0, 6, 7, 0, 0, 0, 0, 0}, + {1, 6, 7, 0, 0, 0, 0, 0}, {0, 1, 6, 7, 0, 0, 0, 0}, + {2, 6, 7, 0, 0, 0, 0, 0}, {0, 2, 6, 7, 0, 0, 0, 0}, + {1, 2, 6, 7, 0, 0, 0, 0}, {0, 1, 2, 6, 7, 0, 0, 0}, + {3, 6, 7, 0, 0, 0, 0, 0}, {0, 3, 6, 7, 0, 0, 0, 0}, + {1, 3, 6, 7, 0, 0, 0, 0}, {0, 1, 3, 6, 7, 0, 0, 0}, + {2, 3, 6, 7, 0, 0, 0, 0}, {0, 2, 3, 6, 7, 0, 0, 0}, + {1, 2, 3, 6, 7, 0, 0, 0}, {0, 1, 2, 3, 6, 7, 0, 0}, + {4, 6, 7, 0, 0, 0, 0, 0}, {0, 4, 6, 7, 0, 0, 0, 0}, + {1, 4, 6, 7, 0, 0, 0, 0}, {0, 1, 4, 6, 7, 0, 0, 0}, + {2, 4, 6, 7, 0, 0, 0, 0}, {0, 2, 4, 6, 7, 0, 0, 0}, + {1, 2, 4, 6, 7, 0, 0, 0}, {0, 1, 2, 4, 6, 7, 0, 0}, + {3, 4, 6, 7, 0, 0, 0, 0}, {0, 3, 4, 6, 7, 0, 0, 0}, + {1, 3, 4, 6, 7, 0, 0, 0}, {0, 1, 3, 4, 6, 7, 0, 0}, + {2, 3, 4, 6, 7, 0, 0, 0}, {0, 2, 3, 4, 6, 7, 0, 0}, + {1, 2, 3, 4, 6, 7, 0, 0}, {0, 1, 2, 3, 4, 6, 7, 0}, + {5, 6, 7, 0, 0, 0, 0, 0}, {0, 5, 6, 7, 0, 0, 0, 0}, + {1, 5, 6, 7, 0, 0, 0, 0}, {0, 1, 5, 6, 7, 0, 0, 0}, + {2, 5, 6, 7, 0, 0, 0, 0}, {0, 2, 5, 6, 7, 0, 0, 0}, + {1, 2, 5, 6, 7, 0, 0, 0}, {0, 1, 2, 5, 6, 7, 0, 0}, + {3, 5, 6, 7, 0, 0, 0, 0}, {0, 3, 5, 6, 7, 0, 0, 0}, + {1, 3, 5, 6, 7, 0, 0, 0}, {0, 1, 3, 5, 6, 7, 0, 0}, + {2, 3, 5, 6, 7, 0, 0, 0}, {0, 2, 3, 5, 6, 7, 0, 0}, + {1, 2, 3, 5, 6, 7, 0, 0}, {0, 1, 2, 3, 5, 6, 7, 0}, + {4, 5, 6, 7, 0, 0, 0, 0}, {0, 4, 5, 6, 7, 0, 0, 0}, + {1, 4, 5, 6, 7, 0, 0, 0}, {0, 1, 4, 5, 6, 7, 0, 0}, + {2, 4, 5, 6, 7, 0, 0, 0}, {0, 2, 4, 5, 6, 7, 0, 0}, + {1, 2, 4, 5, 6, 7, 0, 0}, {0, 1, 2, 4, 5, 6, 7, 0}, + {3, 4, 5, 6, 7, 0, 0, 0}, {0, 3, 4, 5, 6, 7, 0, 0}, + {1, 3, 4, 5, 6, 7, 0, 0}, {0, 1, 3, 4, 5, 6, 7, 0}, + {2, 3, 4, 5, 6, 7, 0, 0}, {0, 2, 3, 4, 5, 6, 7, 0}, + {1, 2, 3, 4, 5, 6, 7, 0}, {0, 1, 2, 3, 4, 5, 6, 7}, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/packing.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/packing.c new file mode 100644 index 0000000000..26da273856 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/packing.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include + +#include "common.h" +#include "packing.h" +#include "poly.h" +#include "polyvec.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_unpack_hints MLD_ADD_PARAM_SET(mld_unpack_hints) +/* End of parameter set namespacing */ + +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +{ + unsigned int i; + + mld_memcpy(pk, rho, MLDSA_SEEDBYTES); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt1_pack(pk + MLDSA_SEEDBYTES + i * MLDSA_POLYT1_PACKEDBYTES, + &t1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +{ + unsigned int i; + + mld_memcpy(rho, pk, MLDSA_SEEDBYTES); + pk += MLDSA_SEEDBYTES; + + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt1_unpack(&t1->vec[i], pk + i * MLDSA_POLYT1_PACKEDBYTES); + } +} + +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +{ + mld_memcpy(sk, rho, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, key, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, tr, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_pack_eta(sk, s1); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_eta(sk, s2); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_t0(sk, t0); +} + +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +{ + mld_memcpy(rho, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(key, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(tr, sk, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_unpack_eta(s1, sk); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_eta(s2, sk); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_t0(t0, sk); +} + +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +{ + unsigned int i, j, k; + + mld_memcpy(sig, c, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + /* skip z component - packed via mld_pack_sig_z */ + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + /* Encode hints h */ + + /* The final section of sig[] is MLDSA_POLYVECH_PACKEDBYTES long, where + * MLDSA_POLYVECH_PACKEDBYTES = MLDSA_OMEGA + MLDSA_K + * + * The first OMEGA bytes record the index numbers of the coefficients + * that are not equal to 0 + * + * The final K bytes record a running tally of the number of hints + * coming from each of the K polynomials in h. + * + * The pre-condition tells us that number_of_hints <= OMEGA, so some + * bytes may not be written, so we initialize all of them to zero + * to start. + */ + mld_memset(sig, 0, MLDSA_POLYVECH_PACKEDBYTES); + + k = 0; + /* For each polynomial in h... */ + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* For each coefficient in that polynomial, record it as as hint */ + /* if its value is not zero */ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + assigns(j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(j <= MLDSA_N) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* The reference implementation implicitly relies on the total */ + /* number of hints being less than OMEGA, assuming h is valid. */ + /* In mldsa-native, we check this explicitly to ease proof of */ + /* type safety. */ + if (h->vec[i].coeffs[j] != 0 && k < number_of_hints) + { + /* The enclosing if condition AND the loop invariant infer */ + /* that k < MLDSA_OMEGA, so writing to sig[k] is safe and k */ + /* can be incremented. */ + sig[k++] = (uint8_t)j; + } + } + /* Having recorded all the hints for this polynomial, also */ + /* record the running tally into the correct "slot" for that */ + /* coefficient in the final K bytes */ + sig[MLDSA_OMEGA + i] = (uint8_t)k; + } +} + +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +{ + sig += MLDSA_CTILDEBYTES; + sig += i * MLDSA_POLYZ_PACKEDBYTES; + mld_polyz_pack(sig, zi); +} + +/************************************************* + * Name: mld_unpack_hints + * + * Description: Unpack raw hint bytes into a polyveck + * struct + * + * Arguments: - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]: + * raw hint bytes + * + * Returns 1 in case of malformed hints; otherwise 0. + **************************************************/ +static int mld_unpack_hints( + mld_polyveck *h, const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(packed_hints, MLDSA_POLYVECH_PACKEDBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + /* All returned coefficients are either 0 or 1 */ + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +) +{ + unsigned int i, j; + unsigned int old_hint_count; + + /* Set all coefficients of all polynomials to 0. */ + /* Only those that are actually non-zero hints will */ + /* be overwritten below. */ + mld_memset(h, 0, sizeof(mld_polyveck)); + + old_hint_count = 0; + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + /* Grab the hint count for the i'th polynomial */ + const unsigned int new_hint_count = packed_hints[MLDSA_OMEGA + i]; + + /* new_hint_count must increase or stay the same, but also remain */ + /* less than or equal to MLDSA_OMEGA */ + if (new_hint_count < old_hint_count || new_hint_count > MLDSA_OMEGA) + { + /* Error - new_hint_count is invalid */ + return 1; + } + + /* If new_hint_count == old_hint_count, then this polynomial has */ + /* zero hints, so this loop executes zero times and we move */ + /* straight on to the next polynomial. */ + for (j = old_hint_count; j < new_hint_count; ++j) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + const uint8_t this_hint_index = packed_hints[j]; + + /* Coefficients must be ordered for strong unforgeability */ + if (j > old_hint_count && this_hint_index <= packed_hints[j - 1]) + { + return 1; + } + h->vec[i].coeffs[this_hint_index] = 1; + } + + old_hint_count = new_hint_count; + } + + /* Extra indices must be zero for strong unforgeability */ + for (j = old_hint_count; j < MLDSA_OMEGA; ++j) + __loop__( + invariant(j <= MLDSA_OMEGA) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + if (packed_hints[j] != 0) + { + return 1; + } + } + + return 0; +} + +MLD_INTERNAL_API +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +{ + mld_memcpy(c, sig, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + mld_polyvecl_unpack_z(z, sig); + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + return mld_unpack_hints(h, sig); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_unpack_hints diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/packing.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/packing.h new file mode 100644 index 0000000000..19095d08cd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/packing.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PACKING_H +#define MLD_PACKING_H + +#include +#include "polyvec.h" + +#define mld_pack_pk MLD_NAMESPACE_KL(pack_pk) +/************************************************* + * Name: mld_pack_pk + * + * Description: Bit-pack public key pk = (rho, t1). + * + * Arguments: - uint8_t pk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const mld_polyveck *t1: pointer to vector t1 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) +); + + +#define mld_pack_sk MLD_NAMESPACE_KL(pack_sk) +/************************************************* + * Name: mld_pack_sk + * + * Description: Bit-pack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - uint8_t sk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const uint8_t tr[]: byte array containing tr + * - const uint8_t key[]: byte array containing key + * - const mld_polyveck *t0: pointer to vector t0 + * - const mld_polyvecl *s1: pointer to vector s1 + * - const mld_polyveck *s2: pointer to vector s2 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +__contract__( + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + requires(forall(k2, 0, MLDSA_K, + array_abs_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) +); + + +#define mld_pack_sig_c_h MLD_NAMESPACE_KL(pack_sig_c_h) +/************************************************* + * Name: mld_pack_sig_c_h + * + * Description: Bit-pack c and h component of sig = (c, z, h). + * The z component is packed separately using mld_pack_sig_z. + * + * Arguments: - uint8_t sig[]: output byte array + * - const uint8_t *c: pointer to challenge hash length + * MLDSA_SEEDBYTES + * - const mld_polyveck *h: pointer to hint vector h + * - const unsigned int number_of_hints: total + * hints in *h + * + * Note that the number_of_hints argument is not present + * in the reference implementation. It is added here to ease + * proof of type safety. + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + requires(number_of_hints <= MLDSA_OMEGA) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_pack_sig_z MLD_NAMESPACE_KL(pack_sig_z) +/************************************************* + * Name: mld_pack_sig_z + * + * Description: Bit-pack single polynomial of z component of sig = (c, z, h). + * The c and h components are packed separately using + * mld_pack_sig_c_h. + * + * Arguments: - uint8_t sig[]: output byte array + * - const mld_poly *zi: pointer to a single polynomial in z + * - const unsigned int i: index of zi in vector z + * + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(zi, sizeof(mld_poly))) + requires(i < MLDSA_L) + requires(array_bound(zi->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_unpack_pk MLD_NAMESPACE_KL(unpack_pk) +/************************************************* + * Name: mld_unpack_pk + * + * Description: Unpack public key pk = (rho, t1). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const mld_polyveck *t1: pointer to output vector t1 + * - uint8_t pk[]: byte array containing bit-packed pk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) +); + + +#define mld_unpack_sk MLD_NAMESPACE_KL(unpack_sk) +/************************************************* + * Name: mld_unpack_sk + * + * Description: Unpack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const uint8_t tr[]: output byte array for tr + * - const uint8_t key[]: output byte array for key + * - const mld_polyveck *t0: pointer to output vector t0 + * - const mld_polyvecl *s1: pointer to output vector s1 + * - const mld_polyveck *s2: pointer to output vector s2 + * - uint8_t sk[]: byte array containing bit-packed sk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +__contract__( + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(key, MLDSA_SEEDBYTES)) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(s1, sizeof(mld_polyvecl))) + assigns(memory_slice(s2, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_unpack_sig MLD_NAMESPACE_KL(unpack_sig) +/************************************************* + * Name: mld_unpack_sig + * + * Description: Unpack signature sig = (c, z, h). + * + * Arguments: - uint8_t *c: pointer to output challenge hash + * - mld_polyvecl *z: pointer to output vector z + * - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t sig[]: byte array containing + * bit-packed signature + * + * Returns 1 in case of malformed signature; otherwise 0. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(c, MLDSA_CTILDEBYTES)) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(z->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +); +#endif /* !MLD_PACKING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/params.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/params.h new file mode 100644 index 0000000000..c67d2a33fb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/params.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PARAMS_H +#define MLD_PARAMS_H + +#define MLDSA_SEEDBYTES 32 +#define MLDSA_CRHBYTES 64 +#define MLDSA_TRBYTES 64 +#define MLDSA_RNDBYTES 32 +#define MLDSA_N 256 +#define MLDSA_Q 8380417 +#define MLDSA_Q_HALF ((MLDSA_Q + 1) / 2) +#define MLDSA_D 13 + +#if MLD_CONFIG_PARAMETER_SET == 44 + +#define MLDSA_K 4 +#define MLDSA_L 4 +#define MLDSA_ETA 2 +#define MLDSA_TAU 39 +#define MLDSA_BETA 78 +#define MLDSA_GAMMA1 (1 << 17) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 88) +#define MLDSA_OMEGA 80 +#define MLDSA_CTILDEBYTES 32 +#define MLDSA_POLYZ_PACKEDBYTES 576 +#define MLDSA_POLYW1_PACKEDBYTES 192 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#elif MLD_CONFIG_PARAMETER_SET == 65 + +#define MLDSA_K 6 +#define MLDSA_L 5 +#define MLDSA_ETA 4 +#define MLDSA_TAU 49 +#define MLDSA_BETA 196 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 55 +#define MLDSA_CTILDEBYTES 48 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 128 + +#elif MLD_CONFIG_PARAMETER_SET == 87 + +#define MLDSA_K 8 +#define MLDSA_L 7 +#define MLDSA_ETA 2 +#define MLDSA_TAU 60 +#define MLDSA_BETA 120 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 75 +#define MLDSA_CTILDEBYTES 64 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ + +#define MLDSA_POLYT1_PACKEDBYTES 320 +#define MLDSA_POLYT0_PACKEDBYTES 416 +#define MLDSA_POLYVECH_PACKEDBYTES (MLDSA_OMEGA + MLDSA_K) + +#define MLDSA_CRYPTO_PUBLICKEYBYTES \ + (MLDSA_SEEDBYTES + MLDSA_K * MLDSA_POLYT1_PACKEDBYTES) +#define MLDSA_CRYPTO_SECRETKEYBYTES \ + (2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + MLDSA_L * MLDSA_POLYETA_PACKEDBYTES + \ + MLDSA_K * MLDSA_POLYETA_PACKEDBYTES + MLDSA_K * MLDSA_POLYT0_PACKEDBYTES) +#define MLDSA_CRYPTO_BYTES \ + (MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES + \ + MLDSA_POLYVECH_PACKEDBYTES) + +#endif /* !MLD_PARAMS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/poly.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/poly.c new file mode 100644 index 0000000000..e40534e773 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/poly.c @@ -0,0 +1,973 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "common.h" +#include "ct.h" +#include "debug.h" +#include "poly.h" +#include "reduce.h" +#include "rounding.h" +#include "symmetric.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +#include "zetas.inc" + +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + { + a->coeffs[i] = mld_reduce32(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_STATIC_TESTABLE void mld_poly_caddq_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + ) + { + a->coeffs[i] = mld_caddq(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_POLY_CADDQ) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_poly_caddq_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + mld_poly_caddq_c(a); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1])) + invariant(forall(k2, 0, i, r->coeffs[k2] < MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k2, 0, i, r->coeffs[k2] >= INT32_MIN)) + ) + { + r->coeffs[i] = r->coeffs[i] + b->coeffs[i]; + } +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(r->coeffs, 0, i, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + ) + { + r->coeffs[i] = r->coeffs[i] - b->coeffs[i]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N; i++) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))) + { + /* Reference: uses a left shift by MLDSA_D which is undefined behaviour in + * C90/C99 + */ + a->coeffs[i] *= (1 << MLDSA_D); + } + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + + +static MLD_INLINE int32_t mld_fqmul(int32_t a, int32_t b) +__contract__( + requires(b > -MLDSA_Q_HALF && b < MLDSA_Q_HALF) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* Bounds: We argue in mld_montgomery_reduce() that the reult + * of Montgomery reduction is < MLDSA_Q if the input is smaller + * than 2^31 * MLDSA_Q in absolute value. Indeed, we have: + * + * |a * b| = |a| * |b| + * < 2^31 * MLDSA_Q_HALF + * < 2^31 * MLDSA_Q + */ + return mld_montgomery_reduce((int64_t)a * (int64_t)b); +} + +/* mld_ntt_butterfly_block() + * + * Computes a block CT butterflies with a fixed twiddle factor, + * using Montgomery multiplication. + * + * Parameters: + * - r: Pointer to base of polynomial (_not_ the base of butterfly block) + * - zeta: Twiddle factor to use for the butterfly. This must be in + * Montgomery form and signed canonical. + * - start: Offset to the beginning of the butterfly block + * - len: Index difference between coefficients subject to a butterfly + * - bound: Ghost variable describing coefficient bound: Prior to `start`, + * coefficients must be bound by `bound + MLDSA_Q`. Post `start`, + * they must be bound by `bound`. + * When this function returns, output coefficients in the index range + * [start, start+2*len) have bound bumped to `bound + MLDSA_Q`. + * Example: + * - start=8, len=4 + * This would compute the following four butterflies + * 8 -- 12 + * 9 -- 13 + * 10 -- 14 + * 11 -- 15 + * - start=4, len=2 + * This would compute the following two butterflies + * 4 -- 6 + * 5 -- 7 + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_butterfly_block(int32_t r[MLDSA_N], + const int32_t zeta, + const unsigned start, + const unsigned len, + const unsigned bound) +__contract__( + requires(start < MLDSA_N) + requires(1 <= len && len <= MLDSA_N / 2 && start + 2 * len <= MLDSA_N) + requires(0 <= bound && bound < INT32_MAX - MLDSA_Q) + requires(-MLDSA_Q_HALF < zeta && zeta < MLDSA_Q_HALF) + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, start, bound + MLDSA_Q)) + requires(array_abs_bound(r, start, MLDSA_N, bound)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, start + 2*len, bound + MLDSA_Q)) + ensures(array_abs_bound(r, start + 2 * len, MLDSA_N, bound))) +{ + /* `bound` is a ghost variable only needed in the CBMC specification */ + unsigned j; + ((void)bound); + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + /* + * Coefficients are updated in strided pairs, so the bounds for the + * intermediate states alternate twice between the old and new bound + */ + invariant(array_abs_bound(r, 0, j, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, bound)) + invariant(array_abs_bound(r, start + len, j + len, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j + len, MLDSA_N, bound))) + { + int32_t t; + t = mld_fqmul(r[j + len], zeta); + r[j + len] = r[j] - t; + r[j] = r[j] + t; + } +} + +/* mld_ntt_layer() + * + * Compute one layer of forward NTT + * + * Parameters: + * - r: Pointer to base of polynomial + * - layer: Indicates which layer is being applied. + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_layer(int32_t r[MLDSA_N], const unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (layer + 1) * MLDSA_Q))) +{ + unsigned start, k, len; + /* Twiddle factors for layer n are at indices 2^(n-1)..2^n-1. */ + k = 1u << (layer - 1); + len = (unsigned)MLDSA_N >> layer; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start < MLDSA_N + 2 * len) + invariant(k <= MLDSA_N) + invariant(2 * len * k == start + MLDSA_N) + invariant(array_abs_bound(r, 0, start, layer * MLDSA_Q + MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, layer * MLDSA_Q))) + { + int32_t zeta = mld_zetas[k++]; + mld_ntt_butterfly_block(r, zeta, start, len, layer * MLDSA_Q); + } +} + +MLD_STATIC_TESTABLE void mld_poly_ntt_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +) +{ + unsigned int layer; + int32_t *r; + + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + r = a->coeffs; + + for (layer = 1; layer < 9; layer++) + __loop__( + invariant(1 <= layer && layer <= 9) + invariant(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + ) + { + mld_ntt_layer(r, layer); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_NTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_ntt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_NTT */ + mld_poly_ntt_c(a); +} + +/************************************************* + * Name: mld_fqscale + * + * Description: Scales a field element by mont/256 , i.e., performs Montgomery + * multiplication by mont^2/256. + * Input is expected to have absolute value smaller than + * 256 * MLDSA_Q. + * Output has absolute value smaller than MLD_INTT_BOUND. + * + * Arguments: - int32_t a: Field element to be scaled. + **************************************************/ +static MLD_INLINE int32_t mld_fqscale(int32_t a) +__contract__( + requires(a > -256*MLDSA_Q && a < 256*MLDSA_Q) + ensures(return_value > -MLD_INTT_BOUND && return_value < MLD_INTT_BOUND) +) +{ + /* check-magic: 41978 == pow(2,64-8,MLDSA_Q) */ + const int32_t f = 41978; + /* Bounds: MLD_INTT_BOUND is MLDSA_Q, so the bounds reasoning is just + * a special case of that in mld_fqmul(). */ + return mld_montgomery_reduce((int64_t)a * f); +} + +/* Reference: Embedded into `invntt_tomont()` in the reference implementation + * @[REF] */ +static MLD_INLINE void mld_invntt_layer(int32_t r[MLDSA_N], unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> (layer - 1)) * MLDSA_Q))) +{ + unsigned start, k, len; + len = (unsigned)MLDSA_N >> layer; + k = (1u << layer) - 1; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start <= MLDSA_N && k <= 255) + invariant(2 * len * k + start == 2 * MLDSA_N - 2 * len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + unsigned j; + int32_t zeta = -mld_zetas[k--]; + + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, j, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, (MLDSA_N >> layer) * MLDSA_Q)) + invariant(array_abs_bound(r, start + len, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + int32_t t = r[j]; + r[j] = t + r[j + len]; + r[j + len] = t - r[j + len]; + r[j + len] = mld_fqmul(r[j + len], zeta); + } + } +} + +MLD_STATIC_TESTABLE void mld_poly_invntt_tomont_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +) +{ + unsigned int layer, j; + int32_t *r; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + r = a->coeffs; + for (layer = 8; layer >= 1; layer--) + __loop__( + invariant(layer <= 8) + /* Absolute bounds increase from 1Q before layer 8 */ + /* up to 256Q after layer 1 */ + invariant(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + mld_invntt_layer(r, layer); + } + + /* Coefficient bounds are now at 256Q. We now scale by mont / 256, + * i.e., compute the Montgomery multiplication by mont^2 / 256. + * mont corrects the mont^-1 factor introduced in the basemul. + * 1/256 performs that scaling of the inverse NTT. + * The reduced value is bounded by MLD_INTT_BOUND in absolute + * value.*/ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + invariant(j <= MLDSA_N) + invariant(array_abs_bound(r, 0, j, MLD_INTT_BOUND)) + invariant(array_abs_bound(r, j, MLDSA_N, MLDSA_N * MLDSA_Q)) + ) + { + r[j] = mld_fqscale(r[j]); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); +} + + +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_INTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_intt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_INTT */ + mld_poly_invntt_tomont_c(a); +} + +MLD_STATIC_TESTABLE void mld_poly_pointwise_montgomery_c(mld_poly *c, + const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_abs_bound(c->coeffs, 0, i, MLDSA_Q)) + ) + { + c->coeffs[i] = mld_montgomery_reduce((int64_t)a->coeffs[i] * b->coeffs[i]); + } + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +{ +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + ret = mld_poly_pointwise_montgomery_native(c->coeffs, a->coeffs, b->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + mld_poly_pointwise_montgomery_c(c, a, b); +} + +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, 0, i, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + invariant(array_bound(a1->coeffs, 0, i, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) + ) + { + mld_power2round(&a0->coeffs[i], &a1->coeffs[i], a->coeffs[i]); + } + + mld_assert_bound(a0->coeffs, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +#ifndef MLD_POLY_UNIFORM_NBLOCKS +#define MLD_POLY_UNIFORM_NBLOCKS \ + ((768 + MLD_STREAM128_BLOCKBYTES - 1) / MLD_STREAM128_BLOCKBYTES) +#endif +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +MLD_STATIC_TESTABLE unsigned int mld_rej_uniform_c(int32_t *a, + unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ + unsigned int ctr, pos; + uint32_t t; + mld_assert_bound(a, offset, 0, MLDSA_Q); + + ctr = offset; + pos = 0; + /* pos + 3 cannot overflow due to the assumption + buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) */ + while (ctr < target && pos + 3 <= buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_bound(a, 0, ctr, 0, MLDSA_Q))) + { + t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + a[ctr++] = (int32_t)t; + } + } + + mld_assert_bound(a, ctr, 0, MLDSA_Q); + + return ctr; +} +/************************************************* + * Name: mld_rej_uniform + * + * Description: Sample uniformly random coefficients in [0, MLDSA_Q-1] by + * performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes (must be + * multiple of 3) + * + * Returns number of sampled coefficients. Can be smaller than len if not enough + * random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +static unsigned int mld_rej_uniform(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) + int ret; + mld_assert_bound(a, offset, 0, MLDSA_Q); + if (offset == 0) + { + ret = mld_rej_uniform_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_bound(a, res, 0, MLDSA_Q); + return res; + } + } +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + + return mld_rej_uniform_c(a, target, offset, buf, buflen); +} + +/* Reference: poly_uniform() in the reference implementation @[REF]. + * - Simplified from reference by removing buffer tail handling + * since buflen % 3 = 0 always holds true (MLD_STREAM128_BLOCKBYTES + * = 168). + * - Modified rej_uniform interface to track offset directly. + * - Pass nonce packed in the extended seed array instead of a third + * argument. + * */ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +{ + unsigned int ctr; + unsigned int buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + MLD_ALIGN uint8_t buf[MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES]; + mld_xof128_ctx state; + + mld_xof128_init(&state); + mld_xof128_absorb_once(&state, seed, MLDSA_SEEDBYTES + 2); + mld_xof128_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, 0, buf, buflen); + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(a, sizeof(mld_poly)), object_whole(buf)) + invariant(ctr <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, ctr, 0, MLDSA_Q)) + invariant(state.pos <= SHAKE128_RATE) + ) + { + mld_xof128_squeezeblocks(buf, 1, &state); + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, ctr, buf, buflen); + } + mld_xof128_release(&state); + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof128_x4_ctx state; + unsigned buflen; + + mld_xof128_x4_init(&state); + mld_xof128_x4_absorb(&state, seed, MLDSA_SEEDBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_NBLOCKS. + * This should generate the matrix entries with high probability. + */ + + mld_xof128_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all matrix entries have been generated, squeeze + * one more block a time until we're done. + */ + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, object_whole(buf), + memory_slice(vec0, sizeof(mld_poly)), memory_slice(vec1, sizeof(mld_poly)), + memory_slice(vec2, sizeof(mld_poly)), memory_slice(vec3, sizeof(mld_poly))) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_bound(vec0->coeffs, 0, ctr[0], 0, MLDSA_Q)) + invariant(array_bound(vec1->coeffs, 0, ctr[1], 0, MLDSA_Q)) + invariant(array_bound(vec2->coeffs, 0, ctr[2], 0, MLDSA_Q)) + invariant(array_bound(vec3->coeffs, 0, ctr[3], 0, MLDSA_Q))) + { + mld_xof128_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + mld_xof128_x4_release(&state); + + mld_assert_bound(vec0->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec1->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec2->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec3->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0) & 0xFF); + r[5 * i + 1] = + (uint8_t)(((a->coeffs[4 * i + 0] >> 8) | (a->coeffs[4 * i + 1] << 2)) & + 0xFF); + r[5 * i + 2] = + (uint8_t)(((a->coeffs[4 * i + 1] >> 6) | (a->coeffs[4 * i + 2] << 4)) & + 0xFF); + r[5 * i + 3] = + (uint8_t)(((a->coeffs[4 * i + 2] >> 4) | (a->coeffs[4 * i + 3] << 6)) & + 0xFF); + r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, 0, 1 << 10))) + { + r->coeffs[4 * i + 0] = + ((a[5 * i + 0] >> 0) | ((int32_t)a[5 * i + 1] << 8)) & 0x3FF; + r->coeffs[4 * i + 1] = + ((a[5 * i + 1] >> 2) | ((int32_t)a[5 * i + 2] << 6)) & 0x3FF; + r->coeffs[4 * i + 2] = + ((a[5 * i + 2] >> 4) | ((int32_t)a[5 * i + 3] << 4)) & 0x3FF; + r->coeffs[4 * i + 3] = + ((a[5 * i + 3] >> 6) | ((int32_t)a[5 * i + 4] << 2)) & 0x3FF; + } + + mld_assert_bound(r->coeffs, MLDSA_N, 0, 1 << 10); +} + +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[8]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* Safety: a->coeffs[i] <= (1 << (MLDSA_D - 1) as they are output of + * power2round, hence, these casts are safe. */ + t[0] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 0]); + t[1] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 1]); + t[2] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 2]); + t[3] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 3]); + t[4] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 4]); + t[5] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 5]); + t[6] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 6]); + t[7] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 7]); + + r[13 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[13 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[13 * i + 1] |= (uint8_t)((t[1] << 5) & 0xFF); + r[13 * i + 2] = (uint8_t)((t[1] >> 3) & 0xFF); + r[13 * i + 3] = (uint8_t)((t[1] >> 11) & 0xFF); + r[13 * i + 3] |= (uint8_t)((t[2] << 2) & 0xFF); + r[13 * i + 4] = (uint8_t)((t[2] >> 6) & 0xFF); + r[13 * i + 4] |= (uint8_t)((t[3] << 7) & 0xFF); + r[13 * i + 5] = (uint8_t)((t[3] >> 1) & 0xFF); + r[13 * i + 6] = (uint8_t)((t[3] >> 9) & 0xFF); + r[13 * i + 6] |= (uint8_t)((t[4] << 4) & 0xFF); + r[13 * i + 7] = (uint8_t)((t[4] >> 4) & 0xFF); + r[13 * i + 8] = (uint8_t)((t[4] >> 12) & 0xFF); + r[13 * i + 8] |= (uint8_t)((t[5] << 1) & 0xFF); + r[13 * i + 9] = (uint8_t)((t[5] >> 7) & 0xFF); + r[13 * i + 9] |= (uint8_t)((t[6] << 6) & 0xFF); + r[13 * i + 10] = (uint8_t)((t[6] >> 2) & 0xFF); + r[13 * i + 11] = (uint8_t)((t[6] >> 10) & 0xFF); + r[13 * i + 11] |= (uint8_t)((t[7] << 3) & 0xFF); + r[13 * i + 12] = (uint8_t)((t[7] >> 5) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + { + r->coeffs[8 * i + 0] = a[13 * i + 0]; + r->coeffs[8 * i + 0] |= (int32_t)a[13 * i + 1] << 8; + r->coeffs[8 * i + 0] &= 0x1FFF; + + r->coeffs[8 * i + 1] = a[13 * i + 1] >> 5; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 2] << 3; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 3] << 11; + r->coeffs[8 * i + 1] &= 0x1FFF; + + r->coeffs[8 * i + 2] = a[13 * i + 3] >> 2; + r->coeffs[8 * i + 2] |= (int32_t)a[13 * i + 4] << 6; + r->coeffs[8 * i + 2] &= 0x1FFF; + + r->coeffs[8 * i + 3] = a[13 * i + 4] >> 7; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 5] << 1; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 6] << 9; + r->coeffs[8 * i + 3] &= 0x1FFF; + + r->coeffs[8 * i + 4] = a[13 * i + 6] >> 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 7] << 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 8] << 12; + r->coeffs[8 * i + 4] &= 0x1FFF; + + r->coeffs[8 * i + 5] = a[13 * i + 8] >> 1; + r->coeffs[8 * i + 5] |= (int32_t)a[13 * i + 9] << 7; + r->coeffs[8 * i + 5] &= 0x1FFF; + + r->coeffs[8 * i + 6] = a[13 * i + 9] >> 6; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 10] << 2; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 11] << 10; + r->coeffs[8 * i + 6] &= 0x1FFF; + + r->coeffs[8 * i + 7] = a[13 * i + 11] >> 3; + r->coeffs[8 * i + 7] |= (int32_t)a[13 * i + 12] << 5; + r->coeffs[8 * i + 7] &= 0x1FFF; + + r->coeffs[8 * i + 0] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 7]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +MLD_STATIC_TESTABLE uint32_t mld_poly_chknorm_c(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == array_abs_bound(a->coeffs, 0, i, B)) + ) + { + /* + * Since we know that -MLD_REDUCE32_RANGE_MAX <= a < MLD_REDUCE32_RANGE_MAX, + * and B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX, to check if + * -B < (a mod± MLDSA_Q) < B, it suffices to check if -B < a < B. + * + * We prove this to be true using the following CBMC assertions. + * a ==> b expressed as !a || b to also allow run-time assertion. + */ + mld_assert(a->coeffs[i] < B || a->coeffs[i] - MLDSA_Q <= -B); + mld_assert(a->coeffs[i] > -B || a->coeffs[i] + MLDSA_Q >= B); + + /* Reference: Leaks which coefficient violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + + /* if (abs(a[i]) >= B) */ + t |= mld_ct_cmask_neg_i32(B - 1 - mld_ct_abs_i32(a->coeffs[i])); + } + + return t; +} + +/* Reference: explicitly checks the bound B to be <= (MLDSA_Q - 1) / 8). + * This is unnecessary as it's always a compile-time constant. + * We instead model it as a precondition. + * Checking the bound is performed using a conditional arguing + * that it is okay to leak which coefficient violates the bound (while the + * coefficient itself must remain secret). + * We instead perform everything in constant-time. + * Also it is sufficient to check that it is smaller than + * MLDSA_Q - MLD_REDUCE32_RANGE_MAX > (MLDSA_Q - 1) / 8). + */ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +{ +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) + int ret; + int success; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + /* The native backend returns 0 if all coefficients are within the bound, + * 1 if at least one coefficient exceeds the bound, and + * -1 (MLD_NATIVE_FUNC_FALLBACK) if the platform does not have the + * required capabilities to run the native function. + */ + ret = mld_poly_chknorm_native(a->coeffs, B); + + success = (ret != MLD_NATIVE_FUNC_FALLBACK); + /* Constant-time: It would be fine to leak the return value of chknorm + * entirely (as it is fine to leak if any coefficient exceeded the bound or + * not). However, it is cleaner to perform declassification in sign.c. + * Hence, here we only declassify if the native function returned + * MLD_NATIVE_FUNC_FALLBACK or not (which solely depends on system + * capabilities). + */ + MLD_CT_TESTING_DECLASSIFY(&success, sizeof(int)); + if (success) + { + /* Convert 0 / 1 to 0 / 0xFFFFFFFF here */ + return 0U - (uint32_t)ret; + } +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + return mld_poly_chknorm_c(a, B); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ +MLD_EMPTY_CU(mld_poly) +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_POLY_UNIFORM_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/poly.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/poly.h new file mode 100644 index 0000000000..ff7710438e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/poly.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_H +#define MLD_POLY_H + +#include +#include "cbmc.h" +#include "common.h" +#include "reduce.h" +#include "rounding.h" + +/* Absolute exclusive upper bound for the output of the forward NTT */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) +/* Absolute exclusive upper bound for the output of the inverse NTT*/ +#define MLD_INTT_BOUND MLDSA_Q + +typedef struct +{ + int32_t coeffs[MLDSA_N]; +} MLD_ALIGN mld_poly; + +#define mld_poly_reduce MLD_NAMESPACE(poly_reduce) +/************************************************* + * Name: mld_poly_reduce + * + * Description: Inplace reduction of all coefficients of polynomial to + * representative in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) +); + +#define mld_poly_caddq MLD_NAMESPACE(poly_caddq) +/************************************************* + * Name: mld_poly_caddq + * + * Description: For all coefficients of in/out polynomial add MLDSA_Q if + * coefficient is negative. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_add MLD_NAMESPACE(poly_add) +/************************************************* + * Name: mld_poly_add + * + * Description: Add polynomials. No modular reduction is performed. + * + * Arguments: - r: Pointer to input-output polynomial to be added to. + * - b: Pointer to input polynomial that should be added + * to r. Must be disjoint from r. + **************************************************/ + +/* + * NOTE: The reference implementation uses a 3-argument poly_add. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(forall(k0, 0, MLDSA_N, (int64_t) r->coeffs[k0] + b->coeffs[k0] < MLD_REDUCE32_DOMAIN_MAX)) + requires(forall(k1, 0, MLDSA_N, (int64_t) r->coeffs[k1] + b->coeffs[k1] >= INT32_MIN)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(forall(k2, 0, MLDSA_N, r->coeffs[k2] == old(*r).coeffs[k2] + b->coeffs[k2])) + ensures(forall(k3, 0, MLDSA_N, r->coeffs[k3] < MLD_REDUCE32_DOMAIN_MAX)) + ensures(forall(k4, 0, MLDSA_N, r->coeffs[k4] >= INT32_MIN)) +); + +#define mld_poly_sub MLD_NAMESPACE(poly_sub) +/************************************************* + * Name: mld_poly_sub + * + * Description: Subtract polynomials. No modular reduction is + * performed. + * + * Arguments: - mld_poly *r: Pointer to input-output polynomial. + * - const mld_poly *b: Pointer to input polynomial that should be + * subtracted from r. Must be disjoint from r. + **************************************************/ +/* + * NOTE: The reference implementation uses a 3-argument poly_sub. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_Q)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) +); + +#define mld_poly_shiftl MLD_NAMESPACE(poly_shiftl) +/************************************************* + * Name: mld_poly_shiftl + * + * Description: Multiply polynomial by 2^MLDSA_D without modular reduction. + *Assumes input coefficients to be less than 2^{31-MLDSA_D} in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_ntt MLD_NAMESPACE(poly_ntt) +/************************************************* + * Name: mld_poly_ntt + * + * Description: Inplace forward NTT. Coefficients can grow by + * 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +); + + +#define mld_poly_invntt_tomont MLD_NAMESPACE(poly_invntt_tomont) +/************************************************* + * Name: mld_poly_invntt_tomont + * + * Description: Inplace inverse NTT and multiplication by 2^{32}. + * Input coefficients need to be less than MLDSA_Q in absolute + * value and output coefficients are bounded by + * MLD_INTT_BOUND. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +); + +#define mld_poly_pointwise_montgomery MLD_NAMESPACE(poly_pointwise_montgomery) +/************************************************* + * Name: mld_poly_pointwise_montgomery + * + * Description: Pointwise multiplication of polynomials in NTT domain + * representation and multiplication of resulting polynomial + * by 2^{-32}. + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const mld_poly *a: pointer to first input polynomial + * - const mld_poly *b: pointer to second input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + +#define mld_poly_power2round MLD_NAMESPACE(poly_power2round) +/************************************************* + * Name: mld_poly_power2round + * + * Description: For all coefficients c of the input polynomial, + * compute c0, c1 such that c mod MLDSA_Q = c1*2^MLDSA_D + c0 + * with -2^{MLDSA_D-1} < c0 <= 2^{MLDSA_D-1}. Assumes coefficients + *to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + *c1 + * - mld_poly *a0: pointer to output polynomial with coefficients + *c0 + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +__contract__( + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a0->coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) +); + +#define mld_poly_uniform MLD_NAMESPACE(poly_uniform) +/************************************************* + * Name: mld_poly_uniform + * + * Description: Sample polynomial with uniformly random coefficients + * in [0,MLDSA_Q-1] by performing rejection sampling on the + * output stream of SHAKE128(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_SEEDBYTES and the packed 2-byte nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES + 2)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +#define mld_poly_uniform_4x MLD_NAMESPACE(poly_uniform_4x) +/************************************************* + * Name: mld_poly_uniform_x4 + * + * Description: Generate four polynomials using rejection sampling + * on (pseudo-)uniformly random bytes sampled from a seed. + * + * Arguments: - mld_poly *vec0, *vec1, *vec2, *vec3: + * Pointers to 4 polynomials to be sampled. + * - uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]: + * Pointer consecutive array of seed buffers of size + * MLDSA_SEEDBYTES + 2 each, plus padding for alignment. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +__contract__( + requires(memory_no_alias(vec0, sizeof(mld_poly))) + requires(memory_no_alias(vec1, sizeof(mld_poly))) + requires(memory_no_alias(vec2, sizeof(mld_poly))) + requires(memory_no_alias(vec3, sizeof(mld_poly))) + requires(memory_no_alias(seed, 4 * MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2))) + assigns(memory_slice(vec0, sizeof(mld_poly))) + assigns(memory_slice(vec1, sizeof(mld_poly))) + assigns(memory_slice(vec2, sizeof(mld_poly))) + assigns(memory_slice(vec3, sizeof(mld_poly))) + ensures(array_bound(vec0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec1->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec2->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec3->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +#define mld_polyt1_pack MLD_NAMESPACE(polyt1_pack) +/************************************************* + * Name: mld_polyt1_pack + * + * Description: Bit-pack polynomial t1 with coefficients fitting in 10 bits. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(r, MLDSA_POLYT1_PACKEDBYTES)) +); + +#define mld_polyt1_unpack MLD_NAMESPACE(polyt1_unpack) +/************************************************* + * Name: mld_polyt1_unpack + * + * Description: Unpack polynomial t1 with 10-bit coefficients. + * Output coefficients are standard representatives. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT1_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, 0, 1 << 10)) +); + +#define mld_polyt0_pack MLD_NAMESPACE(polyt0_pack) +/************************************************* + * Name: mld_polyt0_pack + * + * Description: Bit-pack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + * 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) + assigns(memory_slice(r, MLDSA_POLYT0_PACKEDBYTES)) +); + + +#define mld_polyt0_unpack MLD_NAMESPACE(polyt0_unpack) +/************************************************* + * Name: mld_polyt0_unpack + * + * Description: Unpack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + *2^{MLDSA_D-1}]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT0_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) +); + +#define mld_poly_chknorm MLD_NAMESPACE(poly_chknorm) +/************************************************* + * Name: mld_poly_chknorm + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const mld_poly *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if norm is strictly smaller than + * B <= (MLDSA_Q - MLD_REDUCE32_RANGE_MAX) and 0xFFFFFFFF otherwise. + * + * Specification: The definition of this FIPS-204 requires signed canonical + * reduction prior to applying the bounds check. + * However, `-B < (a mod± MLDSA_Q) < B` is equivalent to + * `-B < a < B` under the assumption that + * `B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX` (cf. the assertion in + * the code). Hence, the present spec and implementation are + * correct without reduction. + * + **************************************************/ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +); + +#endif /* !MLD_POLY_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/poly_kl.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/poly_kl.c new file mode 100644 index 0000000000..7a319ca515 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/poly_kl.c @@ -0,0 +1,931 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "ct.h" +#include "debug.h" +#include "poly_kl.h" +#include "rounding.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_rej_eta MLD_ADD_PARAM_SET(mld_rej_eta) +#define mld_rej_eta_c MLD_ADD_PARAM_SET(mld_rej_eta_c) +#define mld_poly_decompose_c MLD_ADD_PARAM_SET(mld_poly_decompose_c) +#define mld_poly_use_hint_c MLD_ADD_PARAM_SET(mld_poly_use_hint_c) +#define mld_polyz_unpack_c MLD_ADD_PARAM_SET(mld_polyz_unpack_c) +/* End of parameter set namespacing */ + + +MLD_STATIC_TESTABLE +void mld_poly_decompose_c(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +) +{ + unsigned int i; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, i, MLDSA_N, 0, MLDSA_Q)) + invariant(array_bound(a1->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + invariant(array_abs_bound(a0->coeffs, 0, i, MLDSA_GAMMA2+1)) + ) + { + mld_decompose(&a0->coeffs[i], &a1->coeffs[i], a0->coeffs[i]); + } + + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +{ +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_88_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_32_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_DECOMPOSE_88 && MLD_CONFIG_PARAMETER_SET == \ + 44) && MLD_USE_NATIVE_POLY_DECOMPOSE_32 && (MLD_CONFIG_PARAMETER_SET \ + == 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_decompose_c(a1, a0); +} + +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(s <= i) + invariant(array_bound(h->coeffs, 0, i, 0, 2)) + ) + { + const unsigned int hint_bit = mld_make_hint(a0->coeffs[i], a1->coeffs[i]); + h->coeffs[i] = (int32_t)hint_bit; + s += hint_bit; + } + + mld_assert(s <= MLDSA_N); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + return s; +} + +MLD_STATIC_TESTABLE void mld_poly_use_hint_c(mld_poly *b, const mld_poly *a, + const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(b->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ) + { + b->coeffs[i] = mld_use_hint(a->coeffs[i], h->coeffs[i]); + } + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +{ +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_88_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_USE_HINT_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_32_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_USE_HINT_88 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLY_USE_HINT_32 && (MLD_CONFIG_PARAMETER_SET == \ + 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_use_hint_c(b, a, h); +} + +/************************************************* + * Name: mld_rej_eta + * + * Description: Sample uniformly random coefficients in [-MLDSA_ETA, MLDSA_ETA] + *by performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes + * + * Returns number of sampled coefficients. Can be smaller than target if not + *enough random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_eta()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +#if MLDSA_ETA == 2 +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 1 +#elif MLDSA_ETA == 4 +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 2 +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + +MLD_STATIC_TESTABLE unsigned int mld_rej_eta_c(int32_t *a, unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ + unsigned int ctr, pos; + int t_valid; + uint32_t t0, t1; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + ctr = offset; + pos = 0; + while (ctr < target && pos < buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_abs_bound(a, 0, ctr, MLDSA_ETA + 1)) + ) + { + t0 = buf[pos] & 0x0F; + t1 = buf[pos++] >> 4; + + /* Constant time: The inputs and outputs to the rejection sampling are + * secret. However, it is fine to leak which coefficients have been + * rejected. For constant-time testing, we declassify the result of + * the comparison. + */ +#if MLDSA_ETA == 2 + t_valid = t0 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 15 */ + { + t0 = t0 - (205 * t0 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t0; + } + t_valid = t1 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) /* t1 < 15 */ + { + t1 = t1 - (205 * t1 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t1; + } +#elif MLDSA_ETA == 4 + t_valid = t0 < 9; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 9 */ + { + a[ctr++] = 4 - (int32_t)t0; + } + t_valid = t1 < 9; /* t1 < 9 */ + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) + { + a[ctr++] = 4 - (int32_t)t1; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + } + + mld_assert_abs_bound(a, ctr, MLDSA_ETA + 1); + + return ctr; +} + +static unsigned int mld_rej_eta(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ +#if MLDSA_ETA == 2 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta2_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#elif MLDSA_ETA == 4 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta4_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#endif /* !(MLDSA_ETA == 2 && MLD_USE_NATIVE_REJ_UNIFORM_ETA2) && MLDSA_ETA == \ + 4 && MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + + return mld_rej_eta_c(a, target, offset, buf, buflen); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_ETA_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof256_x4_ctx state; + unsigned buflen; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = nonce0; + extseed[1][MLDSA_CRHBYTES] = nonce1; + extseed[2][MLDSA_CRHBYTES] = nonce2; + extseed[3][MLDSA_CRHBYTES] = nonce3; + extseed[0][MLDSA_CRHBYTES + 1] = 0; + extseed[1][MLDSA_CRHBYTES + 1] = 0; + extseed[2][MLDSA_CRHBYTES + 1] = 0; + extseed[3][MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(r0, sizeof(mld_poly)), + memory_slice(r1, sizeof(mld_poly)), memory_slice(r2, sizeof(mld_poly)), + memory_slice(r3, sizeof(mld_poly)), object_whole(buf[0]), + object_whole(buf[1]), object_whole(buf[2]), + object_whole(buf[3])) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_abs_bound(r0->coeffs, 0, ctr[0], MLDSA_ETA + 1)) + invariant(array_abs_bound(r1->coeffs, 0, ctr[1], MLDSA_ETA + 1)) + invariant(array_abs_bound(r2->coeffs, 0, ctr[2], MLDSA_ETA + 1)) + invariant(array_abs_bound(r3->coeffs, 0, ctr[3], MLDSA_ETA + 1))) + { + mld_xof256_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + + mld_xof256_x4_release(&state); + + mld_assert_abs_bound(r0->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r1->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r2->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r3->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +{ + /* Temporary buffer for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr; + mld_xof256_ctx state; + unsigned buflen; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = nonce; + extseed[MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr = mld_rej_eta(r->coeffs, MLDSA_N, 0, buf, buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, object_whole(&state), + object_whole(buf), memory_slice(r, sizeof(mld_poly))) + invariant(ctr <= MLDSA_N) + invariant(state.pos <= SHAKE256_RATE) + invariant(array_abs_bound(r->coeffs, 0, ctr, MLDSA_ETA + 1))) + { + mld_xof256_squeezeblocks(buf, 1, &state); + ctr = mld_rej_eta(r->coeffs, MLDSA_N, ctr, buf, buflen); + } + + mld_xof256_release(&state); + + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define MLD_POLY_UNIFORM_GAMMA1_NBLOCKS \ + ((MLDSA_POLYZ_PACKEDBYTES + MLD_STREAM256_BLOCKBYTES - 1) / \ + MLD_STREAM256_BLOCKBYTES) + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + mld_xof256_ctx state; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = (uint8_t)(nonce & 0xFF); + extseed[MLDSA_CRHBYTES + 1] = (uint8_t)(nonce >> 8); + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + mld_polyz_unpack(a, buf); + + mld_xof256_release(&state); + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + mld_xof256_x4_ctx state; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = (uint8_t)(nonce0 & 0xFF); + extseed[1][MLDSA_CRHBYTES] = (uint8_t)(nonce1 & 0xFF); + extseed[2][MLDSA_CRHBYTES] = (uint8_t)(nonce2 & 0xFF); + extseed[3][MLDSA_CRHBYTES] = (uint8_t)(nonce3 & 0xFF); + extseed[0][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce0 >> 8); + extseed[1][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce1 >> 8); + extseed[2][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce2 >> 8); + extseed[3][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce3 >> 8); + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + + mld_polyz_unpack(r0, buf[0]); + mld_polyz_unpack(r1, buf[1]); + mld_polyz_unpack(r2, buf[2]); + mld_polyz_unpack(r3, buf[3]); + mld_xof256_x4_release(&state); + + mld_assert_bound(r0->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r1->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r2->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r3->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +{ + unsigned int i, j, pos; + uint64_t signs; + uint64_t offset; + MLD_ALIGN uint8_t buf[SHAKE256_RATE]; + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, seed, MLDSA_CTILDEBYTES); + mld_shake256_finalize(&state); + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + + /* Convert the first 8 bytes of buf[] into an unsigned 64-bit value. */ + /* Each bit of that dictates the sign of the resulting challenge value */ + signs = 0; + for (i = 0; i < 8; ++i) + __loop__( + assigns(i, signs) + invariant(i <= 8) + ) + { + signs |= (uint64_t)buf[i] << 8 * i; + } + pos = 8; + + mld_memset(c, 0, sizeof(mld_poly)); + + for (i = MLDSA_N - MLDSA_TAU; i < MLDSA_N; ++i) + __loop__( + assigns(i, j, object_whole(buf), state, pos, memory_slice(c, sizeof(mld_poly)), signs) + invariant(i >= MLDSA_N - MLDSA_TAU) + invariant(i <= MLDSA_N) + invariant(pos >= 1) + invariant(pos <= SHAKE256_RATE) + invariant(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) + invariant(state.pos <= SHAKE256_RATE) + ) + { + do + __loop__( + assigns(j, object_whole(buf), state, pos) + invariant(state.pos <= SHAKE256_RATE) + ) + { + if (pos >= SHAKE256_RATE) + { + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + pos = 0; + } + j = buf[pos++]; + } while (j > i); + + c->coeffs[i] = c->coeffs[j]; + + /* Reference: Compute coefficent value here in two steps to */ + /* mixinf unsigned and signed arithmetic with implicit */ + /* conversions, and so that CBMC can keep track of ranges */ + /* to complete type-safety proof here. */ + + /* The least-significant bit of signs tells us if we want -1 or +1 */ + offset = 2 * (signs & 1); + + /* offset has value 0 or 2 here, so (1 - (int32_t) offset) has + * value -1 or +1 */ + c->coeffs[j] = 1 - (int32_t)offset; + + /* Move to the next bit of signs for next time */ + signs >>= 1; + } + + mld_assert_bound(c->coeffs, MLDSA_N, -1, 2); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(&signs, sizeof(signs)); +} + +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint8_t t[8]; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_ETA + 1); + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 1]); + t[2] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 2]); + t[3] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 3]); + t[4] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 4]); + t[5] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 5]); + t[6] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 6]); + t[7] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 7]); + + r[3 * i + 0] = (uint8_t)(((t[0] >> 0) | (t[1] << 3) | (t[2] << 6)) & 0xFF); + r[3 * i + 1] = + (uint8_t)(((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)) & + 0xFF); + r[3 * i + 2] = (uint8_t)(((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)) & 0xFF); + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 1]); + r[i] = (uint8_t)(t[0] | (t[1] << 4)); + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ +} + +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -5, MLDSA_ETA + 1))) + { + r->coeffs[8 * i + 0] = (a[3 * i + 0] >> 0) & 7; + r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 7; + r->coeffs[8 * i + 2] = ((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 7; + r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 7; + r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 7; + r->coeffs[8 * i + 5] = ((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 7; + r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 7; + r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5) & 7; + + r->coeffs[8 * i + 0] = MLDSA_ETA - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = MLDSA_ETA - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = MLDSA_ETA - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = MLDSA_ETA - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = MLDSA_ETA - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = MLDSA_ETA - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = MLDSA_ETA - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = MLDSA_ETA - r->coeffs[8 * i + 7]; + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -11, MLDSA_ETA + 1))) + { + r->coeffs[2 * i + 0] = a[i] & 0x0F; + r->coeffs[2 * i + 1] = a[i] >> 4; + r->coeffs[2 * i + 0] = MLDSA_ETA - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_ETA - r->coeffs[2 * i + 1]; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + + mld_assert_bound(r->coeffs, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + + +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[4]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 1]); + t[2] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 2]); + t[3] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 3]); + + r[9 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[9 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[9 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[9 * i + 2] |= (uint8_t)((t[1] << 2) & 0xFF); + r[9 * i + 3] = (uint8_t)((t[1] >> 6) & 0xFF); + r[9 * i + 4] = (uint8_t)((t[1] >> 14) & 0xFF); + r[9 * i + 4] |= (uint8_t)((t[2] << 4) & 0xFF); + r[9 * i + 5] = (uint8_t)((t[2] >> 4) & 0xFF); + r[9 * i + 6] = (uint8_t)((t[2] >> 12) & 0xFF); + r[9 * i + 6] |= (uint8_t)((t[3] << 6) & 0xFF); + r[9 * i + 7] = (uint8_t)((t[3] >> 2) & 0xFF); + r[9 * i + 8] = (uint8_t)((t[3] >> 10) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 1]); + + r[5 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[5 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[5 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[5 * i + 2] |= (uint8_t)((t[1] << 4) & 0xFF); + r[5 * i + 3] = (uint8_t)((t[1] >> 4) & 0xFF); + r[5 * i + 4] = (uint8_t)((t[1] >> 12) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +MLD_STATIC_TESTABLE void mld_polyz_unpack_c( + mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +) +{ + unsigned int i; +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[4 * i + 0] = a[9 * i + 0]; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 2] << 16; + r->coeffs[4 * i + 0] &= 0x3FFFF; + + r->coeffs[4 * i + 1] = a[9 * i + 2] >> 2; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 3] << 6; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 4] << 14; + r->coeffs[4 * i + 1] &= 0x3FFFF; + + r->coeffs[4 * i + 2] = a[9 * i + 4] >> 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 5] << 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 6] << 12; + r->coeffs[4 * i + 2] &= 0x3FFFF; + + r->coeffs[4 * i + 3] = a[9 * i + 6] >> 6; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 7] << 2; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10; + r->coeffs[4 * i + 3] &= 0x3FFFF; + + r->coeffs[4 * i + 0] = MLDSA_GAMMA1 - r->coeffs[4 * i + 0]; + r->coeffs[4 * i + 1] = MLDSA_GAMMA1 - r->coeffs[4 * i + 1]; + r->coeffs[4 * i + 2] = MLDSA_GAMMA1 - r->coeffs[4 * i + 2]; + r->coeffs[4 * i + 3] = MLDSA_GAMMA1 - r->coeffs[4 * i + 3]; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[2 * i + 0] = a[5 * i + 0]; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 2] << 16; + r->coeffs[2 * i + 0] &= 0xFFFFF; + + r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 3] << 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12; + /* r->coeffs[2*i+1] &= 0xFFFFF; */ /* No effect, since we're anyway at 20 + bits */ + + r->coeffs[2 * i + 0] = MLDSA_GAMMA1 - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_GAMMA1 - r->coeffs[2 * i + 1]; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +{ +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + ret = mld_polyz_unpack_17_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#elif defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + ret = mld_polyz_unpack_19_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYZ_UNPACK_17 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLYZ_UNPACK_19 && (MLD_CONFIG_PARAMETER_SET == 65 \ + || MLD_CONFIG_PARAMETER_SET == 87) */ + + mld_polyz_unpack_c(r, a); +} + +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + + mld_assert_bound(a->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[3 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0]) & 0xFF); + r[3 * i + 0] |= (uint8_t)((a->coeffs[4 * i + 1] << 6) & 0xFF); + r[3 * i + 1] = (uint8_t)((a->coeffs[4 * i + 1] >> 2) & 0xFF); + r[3 * i + 1] |= (uint8_t)((a->coeffs[4 * i + 2] << 4) & 0xFF); + r[3 * i + 2] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) & 0xFF); + r[3 * i + 2] |= (uint8_t)((a->coeffs[4 * i + 3] << 2) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + r[i] = + (uint8_t)((a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_rej_eta +#undef mld_rej_eta_c +#undef mld_poly_decompose_c +#undef mld_poly_use_hint_c +#undef mld_polyz_unpack_c +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_GAMMA1_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/poly_kl.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/poly_kl.h new file mode 100644 index 0000000000..c6aa498358 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/poly_kl.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_KL_H +#define MLD_POLY_KL_H + +#include "cbmc.h" +#include "common.h" +#include "poly.h" + +#define mld_poly_decompose MLD_NAMESPACE_KL(poly_decompose) +/************************************************* + * Name: mld_poly_decompose + * + * Description: For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such c mod MLDSA_Q = c1*ALPHA + + * c0 with -ALPHA/2 < c0 <= ALPHA/2 except + * c1 = (MLDSA_Q-1)/ALPHA where we set + * c1 = 0 and -ALPHA/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + * c1 + * - mld_poly *a0: pointer to input/output polynomial. Output + * polynomial has coefficients c0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +); + + +#define mld_poly_make_hint MLD_NAMESPACE_KL(poly_make_hint) +/************************************************* + * Name: mld_poly_make_hint + * + * Description: Compute hint polynomial. The coefficients of which indicate + * whether the low bits of the corresponding coefficient of + * the input polynomial overflow into the high bits. + * + * Arguments: - mld_poly *h: pointer to output hint polynomial + * - const mld_poly *a0: pointer to low part of input polynomial + * - const mld_poly *a1: pointer to high part of input polynomial + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + assigns(memory_slice(h, sizeof(mld_poly))) + ensures(return_value <= MLDSA_N) + ensures(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) +); + +#define mld_poly_use_hint MLD_NAMESPACE_KL(poly_use_hint) +/************************************************* + * Name: mld_poly_use_hint + * + * Description: Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - mld_poly *b: pointer to output polynomial with corrected high + *bits + * - const mld_poly *a: pointer to input polynomial + * - const mld_poly *h: pointer to input hint polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta_4x MLD_NAMESPACE_KL(poly_uniform_eta_4x) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample four polynomials with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce_i) + * + * Arguments: - mld_poly *r0: pointer to first output polynomial + * - mld_poly *r1: pointer to second output polynomial + * - mld_poly *r2: pointer to third output polynomial + * - mld_poly *r3: pointer to fourth output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce0: first nonce + * - uint8_t nonce1: second nonce + * - uint8_t nonce2: third nonce + * - uint8_t nonce3: fourth nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_abs_bound(r0->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r1->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r2->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r3->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta MLD_NAMESPACE_KL(poly_uniform_eta) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample polynomial with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce: nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1 MLD_NAMESPACE_KL(poly_uniform_gamma1) +/************************************************* + * Name: mld_poly_uniform_gamma1 + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1_4x MLD_NAMESPACE_KL(poly_uniform_gamma1_4x) +/************************************************* + * Name: mld_poly_uniform_gamma1_4x + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_bound(r0->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r1->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r2->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r3->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define mld_poly_challenge MLD_NAMESPACE_KL(poly_challenge) +/************************************************* + * Name: mld_poly_challenge + * + * Description: Implementation of H. Samples polynomial with MLDSA_TAU nonzero + * coefficients in {-1,1} using the output stream of + * SHAKE256(seed). + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const uint8_t mu[]: byte array containing seed of length + * MLDSA_CTILDEBYTES + **************************************************/ +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +__contract__( + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CTILDEBYTES)) + assigns(memory_slice(c, sizeof(mld_poly))) + /* All coefficients of c are -1, 0 or +1 */ + ensures(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) +); + +#define mld_polyeta_pack MLD_NAMESPACE_KL(polyeta_pack) +/************************************************* + * Name: mld_polyeta_pack + * + * Description: Bit-pack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYETA_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + assigns(memory_slice(r, MLDSA_POLYETA_PACKEDBYTES)) +); + +/* + * polyeta_unpack produces coefficients in [-MLDSA_ETA,MLDSA_ETA] for + * well-formed inputs (i.e., those produced by polyeta_pack). + * However, when passed an arbitrary byte array, it may produce smaller values, + * i.e, values in [MLD_POLYETA_UNPACK_LOWER_BOUND,MLDSA_ETA] + * Even though this should never happen, we use use the bound for arbitrary + * inputs in the CBMC proofs. + */ +#if MLDSA_ETA == 2 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-5) +#elif MLDSA_ETA == 4 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-11) +#else +#error "Invalid value of MLDSA_ETA" +#endif + +#define mld_polyeta_unpack MLD_NAMESPACE_KL(polyeta_unpack) +/************************************************* + * Name: mld_polyeta_unpack + * + * Description: Unpack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYETA_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)) +); + +#define mld_polyz_pack MLD_NAMESPACE_KL(polyz_pack) +/************************************************* + * Name: mld_polyz_pack + * + * Description: Bit-pack polynomial with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYZ_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(r, MLDSA_POLYZ_PACKEDBYTES)) +); + + +#define mld_polyz_unpack MLD_NAMESPACE_KL(polyz_unpack) +/************************************************* + * Name: mld_polyz_unpack + * + * Description: Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); + +#define mld_polyw1_pack MLD_NAMESPACE_KL(polyw1_pack) +/************************************************* + * Name: mld_polyw1_pack + * + * Description: Bit-pack polynomial w1 with coefficients in [0,15] or [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES)) +); + +#endif /* !MLD_POLY_KL_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/polyvec.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/polyvec.c new file mode 100644 index 0000000000..5c3a08ab32 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/polyvec.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include +#include + +#include "common.h" +#include "debug.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" + +/* This namespacing is not done at the top to avoid a naming conflict + * with native backends, which are currently not yet namespaced. */ +#define mld_polymat_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polymat_permute_bitrev_to_custom) +#define mld_polyvecl_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polyvecl_permute_bitrev_to_custom) +#define mld_polyvecl_pointwise_acc_montgomery_c \ + MLD_ADD_PARAM_SET(mld_polyvecl_pointwise_acc_montgomery_c) + +#if !defined(MLD_CONFIG_REDUCE_RAM) +/* Helper function to ensure that the polynomial entries in the output + * of mld_polyvec_matrix_expand use the standard (bitreversed) ordering + * of coefficients. + * No-op unless a native backend with a custom ordering is used. + */ + +static void mld_polyvecl_permute_bitrev_to_custom(mld_polyvecl *v) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +{ +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + unsigned i; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_permute_bitrev_to_custom(v->vec[i].coeffs); + } +#else /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + /* Nothing to do */ + (void)v; +#endif /* !MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ +} + +static void mld_polymat_permute_bitrev_to_custom(mld_polymat *mat) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; i++) + __loop__( + assigns(i, memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))) + { + mld_polyvecl_permute_bitrev_to_custom(&mat->vec[i]); + } +} +#endif /* !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + unsigned int i; + MLD_ALIGN uint8_t seed_ext[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + mld_memcpy(seed_ext, mat->rho, MLDSA_SEEDBYTES); + + /* Generate row on-demand */ + for (i = 0; i < MLDSA_L; i++) + { + uint8_t x = (uint8_t)row; + uint8_t y = (uint8_t)i; + + seed_ext[MLDSA_SEEDBYTES + 0] = y; + seed_ext[MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(&mat->row_buffer.vec[i], seed_ext); + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + mld_poly_permute_bitrev_to_custom(mat->row_buffer.vec[i].coeffs); +#endif + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); + + return &mat->row_buffer; +#else /* MLD_CONFIG_REDUCE_RAM */ + return &mat->vec[row]; +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + /* In REDUCE_RAM mode, just copy the seed for later on-demand generation */ + mld_memcpy(mat->rho, rho, MLDSA_SEEDBYTES); +#else + unsigned int i, j; + /* + * We generate four separate seed arrays rather than a single one to work + * around limitations in CBMC function contracts dealing with disjoint slices + * of the same parent object. + */ + + MLD_ALIGN uint8_t seed_ext[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + mld_memcpy(seed_ext[j], rho, MLDSA_SEEDBYTES); + } + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + /* Sample 4 matrix entries a time. */ + for (i = 0; i < (MLDSA_K * MLDSA_L / 4) * 4; i += 4) + __loop__( + assigns(i, j, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= (MLDSA_K * MLDSA_L / 4) * 4 && i % 4 == 0) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + uint8_t x = (uint8_t)((i + j) / MLDSA_L); + uint8_t y = (uint8_t)((i + j) % MLDSA_L); + + seed_ext[j][MLDSA_SEEDBYTES + 0] = y; + seed_ext[j][MLDSA_SEEDBYTES + 1] = x; + } + + mld_poly_uniform_4x(&mat->vec[i / MLDSA_L].vec[i % MLDSA_L], + &mat->vec[(i + 1) / MLDSA_L].vec[(i + 1) % MLDSA_L], + &mat->vec[(i + 2) / MLDSA_L].vec[(i + 2) % MLDSA_L], + &mat->vec[(i + 3) / MLDSA_L].vec[(i + 3) % MLDSA_L], + seed_ext); + } +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + i = 0; +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + /* Entries omitted by the batch-sampling are sampled individually. */ + while (i < MLDSA_K * MLDSA_L) + __loop__( + assigns(i, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K * MLDSA_L) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + uint8_t x = (uint8_t)(i / MLDSA_L); + uint8_t y = (uint8_t)(i % MLDSA_L); + mld_poly *this_poly = &mat->vec[i / MLDSA_L].vec[i % MLDSA_L]; + + seed_ext[0][MLDSA_SEEDBYTES + 0] = y; + seed_ext[0][MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(this_poly, seed_ext[0]); + i++; + } + + mld_polymat_permute_bitrev_to_custom(mat); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(t, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + const mld_polyvecl *row = mld_polymat_get_row(mat, i); + mld_polyvecl_pointwise_acc_montgomery(&t->vec[i], row, v); + } + + mld_assert_abs_bound_2d(t->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_L **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; +#endif + + /* Safety: nonce is at most ((UINT16_MAX - MLDSA_L) / MLDSA_L), and, hence, + * this cast is safe. See MLD_NONCE_UB comment in sign.c. */ + nonce = (uint16_t)(MLDSA_L * nonce); + /* Now, nonce <= UINT16_MAX - (MLDSA_L - 1), so the casts below are safe. */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_gamma1(&v->vec[i], seed, (uint16_t)(nonce + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLDSA_L == 4 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); +#elif MLDSA_L == 5 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); + mld_poly_uniform_gamma1(&v->vec[4], seed, (uint16_t)(nonce + 4)); +#elif MLDSA_L == 7 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], + &v->vec[3 /* irrelevant */], seed, nonce, + (uint16_t)(nonce + 1), (uint16_t)(nonce + 2), + 0xFF /* irrelevant */); + mld_poly_uniform_gamma1_4x(&v->vec[3], &v->vec[4], &v->vec[5], &v->vec[6], + seed, (uint16_t)(nonce + 3), (uint16_t)(nonce + 4), + (uint16_t)(nonce + 5), (uint16_t)(nonce + 6)); +#endif /* MLDSA_L == 7 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(k0, i, MLDSA_L, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_STATIC_TESTABLE void mld_polyvecl_pointwise_acc_montgomery_c( + mld_poly *w, const mld_polyvecl *u, const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i, j; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + for (i = 0; i < MLDSA_N; i++) + __loop__( + assigns(i, j, memory_slice(w, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_abs_bound(w->coeffs, 0, i, MLDSA_Q)) + ) + { + int64_t t = 0; + int32_t r; + for (j = 0; j < MLDSA_L; j++) + __loop__( + assigns(j, t) + invariant(j <= MLDSA_L) + invariant(t >= -(int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + invariant(t <= (int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + ) + { + t += (int64_t)u->vec[j].coeffs[i] * v->vec[j].coeffs[i]; + } + + r = mld_montgomery_reduce(t); + w->coeffs[i] = r; + } + + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +{ +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) && \ + MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l4_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) && \ + MLD_CONFIG_PARAMETER_SET == 65 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l5_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) && \ + MLD_CONFIG_PARAMETER_SET == 87 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l7_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 && \ + MLD_CONFIG_PARAMETER_SET == 44) && \ + !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 && \ + MLD_CONFIG_PARAMETER_SET == 65) && \ + MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 && \ + MLD_CONFIG_PARAMETER_SET == 87 */ + /* The first input is bounded by [0, Q-1] inclusive + * The second input is bounded by [-9Q+1, 9Q-1] inclusive . Hence, we can + * safely accumulate in 64-bits without intermediate reductions as + * MLDSA_L * (MLD_NTT_BOUND-1) * (Q-1) < INT64_MAX + * + * The worst case is ML-DSA-87: 7 * (9Q-1) * (Q-1) < 2**52 + * (and likewise for negative values) + */ + mld_polyvecl_pointwise_acc_montgomery_c(w, u, v); +} + +MLD_INTERNAL_API +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + invariant(i <= MLDSA_L) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + return t; +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_K **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k2, 0, i, + array_bound(v->vec[k2].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ) + { + mld_poly_reduce(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_caddq(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, + forall(k1, 0, MLDSA_N, u->vec[k0].coeffs[k1] == loop_entry(*u).vec[k0].coeffs[k1]))) + invariant(forall(k6, 0, i, array_bound(u->vec[k6].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + ) + { + mld_poly_add(&u->vec[i], &v->vec[i]); + } + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(u->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, u->vec[k1].coeffs[n1] == loop_entry(*u).vec[k1].coeffs[n1])))) + { + mld_poly_sub(&u->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, v->vec[k1].coeffs[n1] == loop_entry(*v).vec[k1].coeffs[n1]))) + ) + { + mld_poly_shiftl(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))) + { + mld_poly_invntt_tomont(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_INTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, array_abs_bound(r->vec[k2].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + mld_poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]); + } + mld_assert_abs_bound_2d(r->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + + return t; +} + +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + invariant(forall(k2, 0, i, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) + ) + { + mld_poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +{ + unsigned int i; + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + invariant(forall(k2, 0, i, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) + invariant(forall(k3, i, MLDSA_K, + array_bound(v0->vec[k3].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + ) + { + mld_poly_decompose(&v1->vec[i], &v0->vec[i]); + } + + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + mld_assert_abs_bound_2d(v0->vec, MLDSA_K, MLDSA_N, MLDSA_GAMMA2 + 1); +} + +MLD_INTERNAL_API +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, s, memory_slice(h, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(s <= i * MLDSA_N) + invariant(forall(k1, 0, i, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + s += mld_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]); + } + + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + return s; +} + +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *u, + const mld_polyveck *h) +{ + unsigned int i; + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(w, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)))) + ) + { + mld_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]); + } + + mld_assert_bound_2d(w->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +{ + unsigned int i; + mld_assert_bound_2d(w1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyw1_pack(&r[i * MLDSA_POLYW1_PACKEDBYTES], &w1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt0_pack(&r[i * MLDSA_POLYT0_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyz_unpack(&z->vec[i], r + i * MLDSA_POLYZ_PACKEDBYTES); + } + + mld_assert_bound_2d(z->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt0_unpack(&p->vec[i], r + i * MLDSA_POLYT0_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_polymat_permute_bitrev_to_custom +#undef mld_polyvecl_permute_bitrev_to_custom +#undef mld_polyvecl_pointwise_acc_montgomery_c diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/polyvec.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/polyvec.h new file mode 100644 index 0000000000..d21abc02ff --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/polyvec.h @@ -0,0 +1,725 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLYVEC_H +#define MLD_POLYVEC_H + +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "poly_kl.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_polyvecl MLD_ADD_PARAM_SET(mld_polyvecl) +#define mld_polyveck MLD_ADD_PARAM_SET(mld_polyveck) +#define mld_polymat MLD_ADD_PARAM_SET(mld_polymat) +/* End of parameter set namespacing */ + +/* Vectors of polynomials of length MLDSA_L */ +typedef struct +{ + mld_poly vec[MLDSA_L]; +} mld_polyvecl; + + +#define mld_polyvecl_uniform_gamma1 MLD_NAMESPACE_KL(polyvecl_uniform_gamma1) +/************************************************* + * Name: mld_polyvecl_uniform_gamma1 + * + * Description: Sample vector of polynomials with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_polyvecl *v: pointer to output vector + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + *************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + requires(nonce <= (UINT16_MAX - MLDSA_L) / MLDSA_L) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyvecl_ntt MLD_NAMESPACE_KL(polyvecl_ntt) +/************************************************* + * Name: mld_polyvecl_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_L. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyvecl *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k0, 0, MLDSA_L, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyvecl_pointwise_acc_montgomery \ + MLD_NAMESPACE_KL(polyvecl_pointwise_acc_montgomery) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery + * + * Description: Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * The first input "u" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * + * Arguments: - mld_poly *w: output polynomial + * - const mld_polyvecl *u: pointer to first input vector + * - const mld_polyvecl *v: pointer to second input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + + +#define mld_polyvecl_chknorm MLD_NAMESPACE_KL(polyvecl_chknorm) +/************************************************* + * Name: mld_polyvecl_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_L. + * Assumes input mld_polyvecl to be reduced by polyvecl_reduce(). + * + * Arguments: - const mld_polyvecl *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials is strictly smaller than B <= + * (MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +/* Vectors of polynomials of length MLDSA_K */ +typedef struct +{ + mld_poly vec[MLDSA_K]; +} mld_polyveck; + +/* Matrix of polynomials (K x L) */ +typedef struct +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + mld_polyvecl row_buffer; + uint8_t rho[MLDSA_SEEDBYTES]; +#else + mld_polyvecl vec[MLDSA_K]; +#endif +} mld_polymat; + +#define mld_polyveck_reduce MLD_NAMESPACE_KL(polyveck_reduce) +/************************************************* + * Name: polyveck_reduce + * + * Description: Reduce coefficients of polynomials in vector of length MLDSA_K + * to representatives in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) +); + +#define mld_polyveck_caddq MLD_NAMESPACE_KL(polyveck_caddq) +/************************************************* + * Name: mld_polyveck_caddq + * + * Description: For all coefficients of polynomials in vector of length MLDSA_K + * add MLDSA_Q if coefficient is negative. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_add MLD_NAMESPACE_KL(polyveck_add) +/************************************************* + * Name: mld_polyveck_add + * + * Description: Add vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to input-output vector of polynomials + * to be added to + * - const mld_polyveck *v: pointer to second input vector of + * polynomials + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(p0, 0, MLDSA_K, array_abs_bound(u->vec[p0].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) + requires(forall(p1, 0, MLDSA_K, + array_bound(v->vec[p1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(q2, 0, MLDSA_K, + array_bound(u->vec[q2].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_sub MLD_NAMESPACE_KL(polyveck_sub) +/************************************************* + * Name: mld_polyveck_sub + * + * Description: Subtract vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to first input vector + * - const mld_polyveck *v: pointer to second input vector to be + * subtracted from first input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(u->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_shiftl MLD_NAMESPACE_KL(polyveck_shiftl) +/************************************************* + * Name: mld_polyveck_shiftl + * + * Description: Multiply vector of polynomials of Length MLDSA_K by 2^MLDSA_D + *without modular reduction. Assumes input coefficients to be less than + *2^{31-MLDSA_D}. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_ntt MLD_NAMESPACE_KL(polyveck_ntt) +/************************************************* + * Name: mld_polyveck_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_K. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyveck_invntt_tomont MLD_NAMESPACE_KL(polyveck_invntt_tomont) +/************************************************* + * Name: mld_polyveck_invntt_tomont + * + * Description: Inverse NTT and multiplication by 2^{32} of polynomials + * in vector of length MLDSA_K. + * Input coefficients need to be less than MLDSA_Q, and + * Output coefficients are bounded by MLD_INTT_BOUND. + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) +); + +#define mld_polyveck_pointwise_poly_montgomery \ + MLD_NAMESPACE_KL(polyveck_pointwise_poly_montgomery) +/************************************************* + * Name: mld_polyveck_pointwise_poly_montgomery + * + * Description: Pointwise multiplication of a polynomial vector of length + * MLDSA_K by a single polynomial in NTT domain and multiplication + * of the resulting polynomial vector by 2^{-32}. + * + * Arguments: - mld_polyveck *r: pointer to output vector + * - mld_poly *a: pointer to input polynomial + * - mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(r, sizeof(mld_polyveck))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(r, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(r->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#define mld_polyveck_chknorm MLD_NAMESPACE_KL(polyveck_chknorm) +/************************************************* + * Name: mld_polyveck_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_K. + * Assumes input mld_polyveck to be reduced by polyveck_reduce(). + * + * Arguments: - const mld_polyveck *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials are strictly smaller than B <= + *(MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, + -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +#define mld_polyveck_power2round MLD_NAMESPACE_KL(polyveck_power2round) +/************************************************* + * Name: mld_polyveck_power2round + * + * Description: For all coefficients a of polynomials in vector of length + *MLDSA_K, compute a0, a1 such that a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with + *-2^{MLDSA_D-1} < a0 <= 2^{MLDSA_D-1}. Assumes coefficients to be standard + *representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to output vector of polynomials with + * coefficients a0 + * - const mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) +); + +#define mld_polyveck_decompose MLD_NAMESPACE_KL(polyveck_decompose) +/************************************************* + * Name: mld_polyveck_decompose + * + * Description: For all coefficients a of polynomials in vector of length + * MLDSA_K, compute high and low bits a0, a1 such a mod^+ MLDSA_Q = a1*ALPHA + * + a0 with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (MLDSA_Q-1)/ALPHA where we set + * a1 = 0 and -ALPHA/2 <= a0 = a mod MLDSA_Q - MLDSA_Q < 0. Assumes coefficients + * to be standard representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to input/output vector of + * polynomials with. Output polynomial has + * coefficients a0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v0->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + ensures(forall(k2, 0, MLDSA_K, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) +); + +#define mld_polyveck_make_hint MLD_NAMESPACE_KL(polyveck_make_hint) +/************************************************* + * Name: mld_polyveck_make_hint + * + * Description: Compute hint vector. + * + * Arguments: - mld_polyveck *h: pointer to output vector + * - const mld_polyveck *v0: pointer to low part of input vector + * - const mld_polyveck *v1: pointer to high part of input vector + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(return_value <= MLDSA_N * MLDSA_K) + ensures(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) +); + +#define mld_polyveck_use_hint MLD_NAMESPACE_KL(polyveck_use_hint) +/************************************************* + * Name: mld_polyveck_use_hint + * + * Description: Use hint vector to correct the high bits of input vector. + * + * Arguments: - mld_polyveck *w: pointer to output vector of polynomials with + * corrected high bits + * - const mld_polyveck *u: pointer to input vector + * - const mld_polyveck *h: pointer to input hint vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *v, + const mld_polyveck *h) +__contract__( + requires(memory_no_alias(w, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + assigns(memory_slice(w, sizeof(mld_polyveck))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) +); + +#define mld_polyveck_pack_w1 MLD_NAMESPACE_KL(polyveck_pack_w1) +/************************************************* + * Name: mld_polyveck_pack_w1 + * + * Description: Bit-pack polynomial vector w1 with coefficients in [0,15] or + * [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_K* MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_polyveck *a: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(w1, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(w1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) +); + +#define mld_polyveck_pack_eta MLD_NAMESPACE_KL(polyveck_pack_eta) +/************************************************* + * Name: mld_polyveck_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients + * in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyvecl_pack_eta MLD_NAMESPACE_KL(polyvecl_pack_eta) +/************************************************* + * Name: mld_polyvecl_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_L * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyveck_pack_t0 MLD_NAMESPACE_KL(polyveck_pack_t0) +/************************************************* + * Name: mld_polyveck_pack_t0 + * + * Description: Bit-pack polynomial vector to with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(p->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) +); + +#define mld_polyvecl_unpack_eta MLD_NAMESPACE_KL(polyvecl_unpack_eta) +/************************************************* + * Name: mld_polyvecl_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyvecl *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + assigns(memory_slice(p, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyvecl_unpack_z MLD_NAMESPACE_KL(polyvecl_unpack_z) +/************************************************* + * Name: mld_polyvecl_unpack_z + * + * Description: Unpack polynomial vector with coefficients in + * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_polyvecl *z: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(z->vec[k1].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyveck_unpack_eta MLD_NAMESPACE_KL(polyveck_unpack_eta) +/************************************************* + * Name: mld_polyveck_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyveck_unpack_t0 MLD_NAMESPACE_KL(polyveck_unpack_t0) +/************************************************* + * Name: mld_polyveck_unpack_t0 + * + * Description: Unpack polynomial vector with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) +); + +#define mld_polymat_get_row MLD_NAMESPACE_KL(polymat_get_row) +/************************************************* + * Name: mld_polymat_get_row + * + * Description: Retrieve a pointer to a specific row of the matrix. + * In MLD_CONFIG_REDUCE_RAM mode, generates the row on-demand. + * + * Arguments: - mld_polymat *mat: pointer to matrix + * - unsigned int row: row index (must be < MLDSA_K) + * + * Returns pointer to the row (mld_polyvecl) + **************************************************/ +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row); + +#define mld_polyvec_matrix_expand MLD_NAMESPACE_KL(polyvec_matrix_expand) +/************************************************* + * Name: mld_polyvec_matrix_expand + * + * Description: Implementation of ExpandA. Generates matrix A with uniformly + * random coefficients a_{i,j} by performing rejection + * sampling on the output stream of SHAKE128(rho|j|i) + * + * Arguments: - mld_polymat *mat: pointer to output matrix + * - const uint8_t rho[]: byte array containing seed rho + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +__contract__( + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +); + + + +#define mld_polyvec_matrix_pointwise_montgomery \ + MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery) +/************************************************* + * Name: mld_polyvec_matrix_pointwise_montgomery + * + * Description: Compute matrix-vector multiplication in NTT domain with + * pointwise multiplication and multiplication by 2^{-32}. + * Input matrix and vector must be in NTT domain representation. + * + * The first input "mat" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * Note: In MLD_CONFIG_REDUCE_RAM mode, mat cannot be const + * as rows are generated on-demand. + * + * Arguments: - mld_polyveck *t: pointer to output vector t + * - mld_polymat *mat: pointer to input matrix + * - const mld_polyvecl *v: pointer to input vector v + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(t, sizeof(mld_polyveck))) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(t, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#endif /* !MLD_POLYVEC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/randombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/randombytes.h new file mode 100644 index 0000000000..da55772419 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/randombytes.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_RANDOMBYTES_H +#define MLD_RANDOMBYTES_H + +#include +#include + +#include "cbmc.h" +#include "common.h" + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +#if !defined(MLD_CONFIG_CUSTOM_RANDOMBYTES) +MLD_MUST_CHECK_RETURN_VALUE +int randombytes(uint8_t *out, size_t outlen); +static MLD_INLINE int mld_randombytes(uint8_t *out, size_t outlen) +__contract__( + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) { return randombytes(out, outlen); } +#endif /* !MLD_CONFIG_CUSTOM_RANDOMBYTES */ +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ +#endif /* !MLD_RANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/reduce.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/reduce.h new file mode 100644 index 0000000000..413cf1829e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/reduce.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_REDUCE_H +#define MLD_REDUCE_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* check-magic: -4186625 == pow(2,32,MLDSA_Q) */ +#define MLD_MONT -4186625 + +/* Upper bound for domain of mld_reduce32() */ +#define MLD_REDUCE32_DOMAIN_MAX (INT32_MAX - (1 << 22)) + +/* Absolute bound for range of mld_reduce32() */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define MLD_REDUCE32_RANGE_MAX 6283009 + +/************************************************* + * Name: mld_montgomery_reduce + * + * Description: Generic Montgomery reduction; given a 64-bit integer a, computes + * 32-bit integer congruent to a * R^-1 mod q, where R=2^32 + * + * Arguments: - int64_t a: input integer to be reduced, of absolute value + * smaller or equal to INT64_MAX - 2^31 * MLDSA_Q. + * + * Returns: Integer congruent to a * R^-1 modulo q, with absolute value + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * In particular, if |a| < 2^31 * MLDSA_Q, the absolute value + * of the return value is < MLDSA_Q. + **************************************************/ +static MLD_INLINE int32_t mld_montgomery_reduce(int64_t a) +__contract__( + /* We don't attempt to express an input-dependent output bound + * as the post-condition here, as all call-sites satisfy the + * absolute input bound 2^31 * MLDSA_Q and higher-level + * reasoning can be conducted using |return_value| < MLDSA_Q. */ + requires(a > -(((int64_t)1 << 31) * MLDSA_Q) && + a < (((int64_t)1 << 31) * MLDSA_Q)) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* check-magic: 58728449 == unsigned_mod(pow(MLDSA_Q, -1, 2^32), 2^32) */ + const uint64_t QINV = 58728449; + + /* Compute a*q^{-1} mod 2^32 in unsigned representatives */ + const uint32_t a_reduced = mld_cast_int64_to_uint32(a); + const uint32_t a_inverted = (a_reduced * QINV) & UINT32_MAX; + + /* Lift to signed canonical representative mod 2^32. */ + const int32_t t = mld_cast_uint32_to_int32(a_inverted); + + int64_t r; + + mld_assert(a < +(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)) && + a > -(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q))); + + r = a - (int64_t)t * MLDSA_Q; + + /* + * PORTABILITY: Right-shift on a signed integer is, strictly-speaking, + * implementation-defined for negative left argument. Here, + * we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5)) + */ + r = r >> 32; + + /* Bounds: + * + * By construction of the Montgomery multiplication, by the time we + * compute r >> 32, r is divisible by 2^32, and hence + * + * |r >> 32| = |r| / 2^32 + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * (In general, we would only have |x >> n| <= ceil(|x| / 2^n)). + * + * In particular, if |a| < 2^31 * MLDSA_Q, then |return_value| < MLDSA_Q. + */ + return (int32_t)r; +} + +/************************************************* + * Name: mld_reduce32 + * + * Description: For finite field element a with a <= 2^{31} - 2^{22} - 1, + * compute r \equiv a (mod MLDSA_Q) such that + * -MLD_REDUCE32_RANGE_MAX <= r < MLD_REDUCE32_RANGE_MAX. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_reduce32(int32_t a) +__contract__( + requires(a <= MLD_REDUCE32_DOMAIN_MAX) + ensures(return_value >= -MLD_REDUCE32_RANGE_MAX) + ensures(return_value < MLD_REDUCE32_RANGE_MAX) +) +{ + int32_t t; + + t = (a + (1 << 22)) >> 23; + t = a - t * MLDSA_Q; + mld_assert((t - a) % MLDSA_Q == 0); + return t; +} + +/************************************************* + * Name: mld_caddq + * + * Description: Add MLDSA_Q if input coefficient is negative. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_caddq(int32_t a) +__contract__( + requires(a > -MLDSA_Q) + requires(a < MLDSA_Q) + ensures(return_value >= 0) + ensures(return_value < MLDSA_Q) + ensures(return_value == (a >= 0) ? a : (a + MLDSA_Q)) +) +{ + return mld_ct_sel_int32(a + MLDSA_Q, a, mld_ct_cmask_neg_i32(a)); +} + + +#endif /* !MLD_REDUCE_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/rounding.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/rounding.h new file mode 100644 index 0000000000..a83562b0f1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/rounding.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_ROUNDING_H +#define MLD_ROUNDING_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_power2round MLD_ADD_PARAM_SET(mld_power2round) +#define mld_decompose MLD_ADD_PARAM_SET(mld_decompose) +#define mld_make_hint MLD_ADD_PARAM_SET(mld_make_hint) +#define mld_use_hint MLD_ADD_PARAM_SET(mld_use_hint) +/* End of parameter set namespacing */ + +#define MLD_2_POW_D (1 << MLDSA_D) + +/************************************************* + * Name: mld_power2round + * + * Description: For finite field element a, compute a0, a1 such that + * a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with -2^{MLDSA_D-1} < a0 <= + * 2^{MLDSA_D-1}. Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: In the reference implementation, a1 is passed as a + * return value instead. + **************************************************/ +static MLD_INLINE void mld_power2round(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + ensures(*a0 > -(MLD_2_POW_D/2) && *a0 <= (MLD_2_POW_D/2)) + ensures(*a1 >= 0 && *a1 <= (MLDSA_Q - 1) / MLD_2_POW_D) + ensures((*a1 * MLD_2_POW_D + *a0 - a) % MLDSA_Q == 0) +) +{ + *a1 = (a + (1 << (MLDSA_D - 1)) - 1) >> MLDSA_D; + *a0 = a - (*a1 << MLDSA_D); +} + +/************************************************* + * Name: mld_decompose + * + * Description: For finite field element a, compute high and low bits a0, a1 + * such that a mod^+ MLDSA_Q = a1* 2 * MLDSA_GAMMA2 + a0 with + * -MLDSA_GAMMA2 < a0 <= MLDSA_GAMMA2 except + * if a1 = (MLDSA_Q-1)/(MLDSA_GAMMA2*2) where we set a1 = 0 and + * -MLDSA_GAMMA2 <= a0 = a mod^+ MLDSA_Q - MLDSA_Q < 0. + * Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: a1 is passed as a return value instead + **************************************************/ +static MLD_INLINE void mld_decompose(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + /* a0 = -MLDSA_GAMMA2 can only occur when (q-1) = a - (a mod MLDSA_GAMMA2), + * then a1=1; and a0 = a - (a mod MLDSA_GAMMA2) - 1 (@[FIPS204, Algorithm 36 (Decompose)]) */ + ensures(*a0 >= -MLDSA_GAMMA2 && *a0 <= MLDSA_GAMMA2) + ensures(*a1 >= 0 && *a1 < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) + ensures((*a1 * 2 * MLDSA_GAMMA2 + *a0 - a) % MLDSA_Q == 0) +) +{ + /* + * The goal is to compute f1 = round-(f / (2*GAMMA2)), which can be computed + * alternatively as round-(f / (128B)) = round-(ceil(f / 128) / B) where + * B = 2*GAMMA2 / 128. Here round-() denotes "round half down". + * + * The equality round-(f / (128B)) = round-(ceil(f / 128) / B) can deduced + * as follows. Since changing f to align-up(f, 128) can move f onto but not + * across a rounding boundary for division by 128*B (note that we need B to be + * even for this to work), and round- rounds down on the boundary, we have + * + * round-(f / (128B)) = round-(align-up(f, 128) / (128B)) + * = round-((align-up(f, 128) / 128) / B) + * = round-(ceil(f / 128) / B). + */ + *a1 = (a + 127) >> 7; + /* We know a >= 0 and a < MLDSA_Q, so... */ + /* check-magic: 65472 == round((MLDSA_Q-1)/128) */ + mld_assert(*a1 >= 0 && *a1 <= 65472); + +#if MLD_CONFIG_PARAMETER_SET == 44 + /* check-magic: 1488 == 2 * intdiv(intdiv(MLDSA_Q - 1, 88), 128) */ + /* check-magic: 11275 == floor(2**24 / 1488) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + */ + *a1 = (*a1 * 11275 + (1 << 23)) >> 24; + mld_assert(*a1 >= 0 && *a1 <= 44); + + *a1 = mld_ct_sel_int32(0, *a1, mld_ct_cmask_neg_i32(43 - *a1)); + mld_assert(*a1 >= 0 && *a1 <= 43); +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + /* check-magic: 4092 == 2 * intdiv(intdiv(MLDSA_Q - 1, 32), 128) */ + /* check-magic: 1025 == floor(2**22 / 4092) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + */ + *a1 = (*a1 * 1025 + (1 << 21)) >> 22; + mld_assert(*a1 >= 0 && *a1 <= 16); + + *a1 &= 15; + mld_assert(*a1 >= 0 && *a1 <= 15); + +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + + *a0 = a - *a1 * 2 * MLDSA_GAMMA2; + *a0 = mld_ct_sel_int32(*a0 - MLDSA_Q, *a0, + mld_ct_cmask_neg_i32((MLDSA_Q - 1) / 2 - *a0)); +} + +/************************************************* + * Name: mld_make_hint + * + * Description: Compute hint bit indicating whether the low bits of the + * input element overflow into the high bits. + * + * Arguments: - int32_t a0: low bits of input element + * - int32_t a1: high bits of input element + * + * Returns 1 if overflow, 0 otherwise + **************************************************/ +static MLD_INLINE unsigned int mld_make_hint(int32_t a0, int32_t a1) +__contract__( + ensures(return_value >= 0 && return_value <= 1) +) +{ + if (a0 > MLDSA_GAMMA2 || a0 < -MLDSA_GAMMA2 || + (a0 == -MLDSA_GAMMA2 && a1 != 0)) + { + return 1; + } + + return 0; +} + +/************************************************* + * Name: mld_use_hint + * + * Description: Correct high bits according to hint. + * + * Arguments: - int32_t a: input element + * - int32_t hint: hint bit + * + * Returns corrected high bits. + **************************************************/ +static MLD_INLINE int32_t mld_use_hint(int32_t a, int32_t hint) +__contract__( + requires(hint >= 0 && hint <= 1) + requires(a >= 0 && a < MLDSA_Q) + ensures(return_value >= 0 && return_value < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) +) +{ + int32_t a0, a1; + + mld_decompose(&a0, &a1, a); + if (hint == 0) + { + return a1; + } + +#if MLD_CONFIG_PARAMETER_SET == 44 + if (a0 > 0) + { + return (a1 == 43) ? 0 : a1 + 1; + } + else + { + return (a1 == 0) ? 43 : a1 - 1; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + if (a0 > 0) + { + return (a1 + 1) & 15; + } + else + { + return (a1 - 1) & 15; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + + +#endif /* !MLD_ROUNDING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/sign.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/sign.c new file mode 100644 index 0000000000..32bba52d65 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/sign.c @@ -0,0 +1,1508 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [Round3_Spec] + * CRYSTALS-Dilithium Algorithm Specifications and Supporting Documentation + * (Version 3.1) + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf + */ + +#include +#include + +#include "cbmc.h" +#include "ct.h" +#include "debug.h" +#include "packing.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" +#include "randombytes.h" +#include "sign.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_check_pct MLD_ADD_PARAM_SET(mld_check_pct) MLD_CONTEXT_PARAMETERS_2 +#define mld_sample_s1_s2 MLD_ADD_PARAM_SET(mld_sample_s1_s2) +#define mld_validate_hash_length MLD_ADD_PARAM_SET(mld_validate_hash_length) +#define mld_get_hash_oid MLD_ADD_PARAM_SET(mld_get_hash_oid) +#define mld_H MLD_ADD_PARAM_SET(mld_H) +#define mld_compute_pack_z MLD_ADD_PARAM_SET(mld_compute_pack_z) +#define mld_attempt_signature_generation \ + MLD_ADD_PARAM_SET(mld_attempt_signature_generation) MLD_CONTEXT_PARAMETERS_8 +#define mld_compute_t0_t1_tr_from_sk_components \ + MLD_ADD_PARAM_SET(mld_compute_t0_t1_tr_from_sk_components) \ + MLD_CONTEXT_PARAMETERS_7 +/* End of parameter set namespacing */ + + +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + ensures(return_value == 0 + || return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL) +); + +#if defined(MLD_CONFIG_KEYGEN_PCT) +/************************************************* + * @[FIPS140_3_IG] + * (https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf) + * + * TE10.35.02: Pair-wise Consistency Test (PCT) for DSA keypairs + * + * Purpose: Validates that a generated public/private key pair can correctly + * sign and verify data. Test performs signature generation using the private + * key (sk), followed by signature verification using the public key (pk). + * Returns 0 if the signature was successfully verified, non-zero if it cannot. + * + * Note: @[FIPS204] requires that public/private key pairs are to be used only + * for the calculation and/of verification of digital signatures. + **************************************************/ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t message[1] = {0}; + size_t siglen; + int ret; + MLD_ALLOC(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + MLD_ALLOC(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + + if (signature == NULL || pk_test == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Copy public key for testing */ + mld_memcpy(pk_test, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* Sign a test message using the original secret key */ + ret = mld_sign_signature(signature, &siglen, message, sizeof(message), NULL, + 0, sk, context); + if (ret != 0) + { + goto cleanup; + } + +#if defined(MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST) + /* Deliberately break public key for testing purposes */ + if (mld_break_pct()) + { + pk_test[0] = ~pk_test[0]; + } +#endif /* MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST */ + + /* Verify the signature using the (potentially corrupted) public key */ + ret = mld_sign_verify(signature, siglen, message, sizeof(message), NULL, 0, + pk_test, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + MLD_FREE(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + + return ret; +} +#else /* MLD_CONFIG_KEYGEN_PCT */ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + /* Skip PCT */ + ((void)pk); + ((void)sk); +#if defined(MLD_CONFIG_CONTEXT_PARAMETER) + ((void)context); +#endif + return 0; +} +#endif /* !MLD_CONFIG_KEYGEN_PCT */ + +static void mld_sample_s1_s2(mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t seed[MLDSA_CRHBYTES]) +__contract__( + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(object_whole(s1), object_whole(s2)) + ensures(forall(l0, 0, MLDSA_L, array_abs_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + ensures(forall(k0, 0, MLDSA_K, array_abs_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) +) +{ +/* Sample short vectors s1 and s2 */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; + uint16_t nonce = 0; + /* Safety: The nonces are at most 14 (MLDSA_L + MLDSA_K - 1), and, hence, the + * casts are safe. */ + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_eta(&s1->vec[i], seed, (uint8_t)(nonce + i)); + } + for (i = 0; i < MLDSA_K; i++) + { + mld_poly_uniform_eta(&s2->vec[i], seed, (uint8_t)(nonce + MLDSA_L + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLD_CONFIG_PARAMETER_SET == 44 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 4, 5, 6, 7); +#elif MLD_CONFIG_PARAMETER_SET == 65 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s2->vec[0], &s2->vec[1], + &s2->vec[2] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[2], &s2->vec[3], &s2->vec[4], &s2->vec[5], + seed, 7, 8, 9, 10); +#elif MLD_CONFIG_PARAMETER_SET == 87 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s1->vec[5], &s1->vec[6], + &s2->vec[0] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 7, 8, 9, 10); + mld_poly_uniform_eta_4x(&s2->vec[4], &s2->vec[5], &s2->vec[6], &s2->vec[7], + seed, 11, 12, 13, 14); +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ +} + +/************************************************* + * Name: mld_compute_t0_t1_tr_from_sk_components + * + * Description: Computes t0, t1, tr, and pk from secret key components + * rho, s1, s2. This is the shared computation used by + * both keygen and generating the public key from the + * secret key. + * + * Arguments: - mld_polyveck *t0: output t0 + * - mld_polyveck *t1: output t1 + * - uint8_t tr[MLDSA_TRBYTES]: output tr + * - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t rho[MLDSA_SEEDBYTES]: input rho + * - const mld_polyvecl *s1: input s1 + * - const mld_polyveck *s2: input s2 + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_t0_t1_tr_from_sk_components( + mld_polyveck *t0, mld_polyveck *t1, uint8_t tr[MLDSA_TRBYTES], + uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], const uint8_t rho[MLDSA_SEEDBYTES], + const mld_polyvecl *s1, const mld_polyveck *s2, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(l0, 0, MLDSA_L, array_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + requires(forall(k0, 0, MLDSA_K, array_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(forall(k1, 0, MLDSA_K, array_bound(t0->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(t1->vec[k2].coeffs, 0, MLDSA_N, 0, 1 << 10))) + ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY)) +{ + int ret; + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1hat, mld_polyvecl, 1, context); + MLD_ALLOC(t, mld_polyveck, 1, context); + + if (mat == NULL || s1hat == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Expand matrix */ + mld_polyvec_matrix_expand(mat, rho); + + /* Matrix-vector multiplication */ + *s1hat = *s1; + mld_polyvecl_ntt(s1hat); + mld_polyvec_matrix_pointwise_montgomery(t, mat, s1hat); + mld_polyveck_invntt_tomont(t); + + /* Add error vector s2 */ + mld_polyveck_add(t, s2); + + /* Reference: The following reduction is not present in the reference + * implementation. Omitting this reduction requires the output of + * the invntt to be small enough such that the addition of s2 does + * not result in absolute values >= MLDSA_Q. While our C, x86_64, + * and AArch64 invntt implementations produce small enough + * values for this to work out, it complicates the bounds + * reasoning. We instead add an additional reduction, and can + * consequently, relax the bounds requirements for the invntt. + */ + mld_polyveck_reduce(t); + + /* Decompose to get t1, t0 */ + mld_polyveck_caddq(t); + mld_polyveck_power2round(t1, t0, t); + + /* Pack public key and compute tr */ + mld_pack_pk(pk, rho, t1); + mld_shake256(tr, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + ret = 0; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_polyveck, 1, context); + MLD_FREE(s1hat, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + const uint8_t *rho, *rhoprime, *key; + MLD_ALLOC(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + MLD_ALLOC(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + + if (seedbuf == NULL || inbuf == NULL || tr == NULL || s1 == NULL || + s2 == NULL || t1 == NULL || t0 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Get randomness for rho, rhoprime and key */ + mld_memcpy(inbuf, seed, MLDSA_SEEDBYTES); + inbuf[MLDSA_SEEDBYTES + 0] = MLDSA_K; + inbuf[MLDSA_SEEDBYTES + 1] = MLDSA_L; + mld_shake256(seedbuf, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, inbuf, + MLDSA_SEEDBYTES + 2); + rho = seedbuf; + rhoprime = rho + MLDSA_SEEDBYTES; + key = rhoprime + MLDSA_CRHBYTES; + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + + /* Sample s1 and s2 */ + mld_sample_s1_s2(s1, s2, rhoprime); + + /* Compute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0, t1, tr, pk, rho, s1, s2, + context); + if (ret != 0) + { + goto cleanup; + } + + /* Pack secret key */ + mld_pack_sk(sk, rho, tr, key, t0, s1, s2); + + /* Constant time: pk is the public key, inherently public data */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_FREE(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + + if (ret != 0) + { + return ret; + } + + /* Pairwise Consistency Test (PCT) @[FIPS140_3_IG, p.87] */ + /* Do this after freeing all temporaries. */ + return mld_check_pct(pk, sk, context); +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t seed[MLDSA_SEEDBYTES]; + int ret; + if (mld_randombytes(seed, MLDSA_SEEDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(seed, sizeof(seed)); + ret = mld_sign_keypair_internal(pk, sk, seed, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed, sizeof(seed)); + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +/************************************************* + * Name: mld_H + * + * Description: Abstracts application of SHAKE256 to + * one, two or three blocks of data, + * yielding a user-requested size of + * output. + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in1: pointer to input block 1 + * Must NOT be NULL + * - size_t in1len: length of input in1 bytes + * - const uint8_t *in2: pointer to input block 2 + * May be NULL if in2len=0, in which case + * this block is ignored + * - size_t in2len: length of input in2 bytes + * - const uint8_t *in3: pointer to input block 3 + * May be NULL if in3len=0, in which case + * this block is ignored + * - size_t in3len: length of input in3 bytes + **************************************************/ +static void mld_H(uint8_t *out, size_t outlen, const uint8_t *in1, + size_t in1len, const uint8_t *in2, size_t in2len, + const uint8_t *in3, size_t in3len) +__contract__( + requires(in1len <= MLD_MAX_BUFFER_SIZE) + requires(in2len <= MLD_MAX_BUFFER_SIZE) + requires(in3len <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in1, in1len)) + requires(in2len == 0 || memory_no_alias(in2, in2len)) + requires(in3len == 0 || memory_no_alias(in3, in3len)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) +{ + mld_shake256ctx state; + mld_shake256_init(&state); + mld_shake256_absorb(&state, in1, in1len); + if (in2len != 0) + { + mld_shake256_absorb(&state, in2, in2len); + } + if (in3len != 0) + { + mld_shake256_absorb(&state, in3, in3len); + } + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(&state, sizeof(state)); +} + +/************************************************* + * Name: mld_compute_pack_z + * + * Description: Computes z = y + s1*c, checks that z has coefficients smaller + * than MLDSA_GAMMA1 - MLDSA_BETA, and packs z into the + * signature buffer. + * + * Arguments: - uint8_t *sig: output signature + * - const mld_poly *cp: challenge polynomial + * - const polyvecl *s1: secret vector s1 + * - const polyvecl *y: masking vector y + * + * Returns: - 0: Success (z has coefficients smaller than + * MLDSA_GAMMA1 - MLDSA_BETA,) + * - MLD_ERR_FAIL: z rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This function is inlined into mld_sign_signature in the + * reference implementation. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_pack_z(uint8_t sig[MLDSA_CRYPTO_BYTES], + const mld_poly *cp, const mld_polyvecl *s1, + const mld_polyvecl *y, mld_poly *z) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(cp, sizeof(mld_poly))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(y, sizeof(mld_polyvecl))) + requires(memory_no_alias(z, sizeof(mld_poly))) + requires(array_abs_bound(cp->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_L, + array_bound(y->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + requires(forall(k1, 0, MLDSA_L, array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(memory_slice(z, sizeof(mld_poly))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int i; + uint32_t z_invalid; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(z, sizeof(mld_poly)), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_poly_pointwise_montgomery(z, cp, &s1->vec[i]); + mld_poly_invntt_tomont(z); + mld_poly_add(z, &y->vec[i]); + mld_poly_reduce(z); + + z_invalid = mld_poly_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA); + /* Constant time: It is fine (and prohibitively expensive to avoid) + * to leak the result of the norm check and which polynomial in z caused a + * rejection. It would even be okay to leak which coefficient led to + * rejection as the candidate signature will be discarded anyway. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(&z_invalid, sizeof(uint32_t)); + if (z_invalid) + { + return MLD_ERR_FAIL; /* reject */ + } + /* If z is valid, then its coefficients are bounded by + * MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below + * to prove the pre-condition of pack_sig_z() */ + mld_assert_abs_bound(z, MLDSA_N, (MLDSA_GAMMA1 - MLDSA_BETA)); + + /* After the norm check, the distribution of each coefficient of z is + * independent of the secret key and it can, hence, be considered + * public. It is, hence, okay to immediately pack it into the user-provided + * signature buffer. */ + mld_pack_sig_z(sig, z, i); + } + return 0; +} + +/* Reference: The reference implementation does not explicitly check the + * maximum nonce value, but instead loops indefinitely (even when the nonce + * would overflow). Internally, sampling of y uses + * (nonceL), (nonceL+1), ... (nonce*L+L-1). + * Hence, there are no overflows if nonce < (UINT16_MAX - L)/L. + * Explicitly checking for this explicitly allows us to prove type-safety. + * Note that FIPS204 explicitly allows an upper-bound this loop of + * 814 (< (UINT16_MAX - L)/L) - see @[FIPS204, Appendix C]. */ +#define MLD_NONCE_UB ((UINT16_MAX - MLDSA_L) / MLDSA_L) + +/************************************************* + * Name: attempt_signature_generation + * + * Description: Attempts to generate a single signature. + * + * Arguments: - uint8_t *sig: pointer to output signature + * - const uint8_t *mu: pointer to message or hash + * of exactly MLDSA_CRHBYTES bytes + * - const uint8_t *rhoprime: pointer to randomness seed + * - uint16_t nonce: current nonce value + * - const mld_polymat *mat: expanded matrix + * - const polyvecl *s1: secret vector s1 + * - const polyveck *s2: secret vector s2 + * - const polyveck *t0: vector t0 + * + * Returns: - 0: Signature generation succeeded + * - MLD_ERR_FAIL: Signature rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This code differs from the reference implementation + * in that it factors out the core signature generation + * step into a distinct function here in order to improve + * efficiency of CBMC proof. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_attempt_signature_generation( + uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *mu, + const uint8_t rhoprime[MLDSA_CRHBYTES], uint16_t nonce, mld_polymat *mat, + const mld_polyvecl *s1, const mld_polyveck *s2, const mld_polyveck *t0, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(rhoprime, MLDSA_CRHBYTES)) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(nonce <= MLD_NONCE_UB) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int n; + uint32_t w0_invalid, h_invalid; + int ret; + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyvecl y; + mld_polyveck h; + } + yh_u; + mld_polyvecl *y; + mld_polyveck *h; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck w1; + mld_polyvecl tmp; + } + w1tmp_u; + mld_polyveck *w1; + mld_polyvecl *tmp; + + MLD_ALLOC(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(yh, yh_u, 1, context); + MLD_ALLOC(z, mld_poly, 1, context); + MLD_ALLOC(w1tmp, w1tmp_u, 1, context); + MLD_ALLOC(w0, mld_polyveck, 1, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(t, mld_poly, 1, context); + + if (challenge_bytes == NULL || yh == NULL || z == NULL || w1tmp == NULL || + w0 == NULL || cp == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + y = &yh->y; + h = &yh->h; + w1 = &w1tmp->w1; + tmp = &w1tmp->tmp; + + /* Sample intermediate vector y */ + mld_polyvecl_uniform_gamma1(y, rhoprime, nonce); + + /* Matrix-vector multiplication */ + *tmp = *y; + mld_polyvecl_ntt(tmp); + mld_polyvec_matrix_pointwise_montgomery(w0, mat, tmp); + mld_polyveck_invntt_tomont(w0); + + /* Decompose w and call the random oracle */ + mld_polyveck_caddq(w0); + mld_polyveck_decompose(w1, w0); + mld_polyveck_pack_w1(sig, w1); + + mld_H(challenge_bytes, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, sig, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + /* Constant time: Leaking challenge_bytes does not reveal any information + * about the secret key as H() is modelled as random oracle. + * This also applies to challenges for rejected signatures. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(challenge_bytes, MLDSA_CTILDEBYTES); + mld_poly_challenge(cp, challenge_bytes); + mld_poly_ntt(cp); + + /* Compute z, reject if it reveals secret */ + ret = mld_compute_pack_z(sig, cp, s1, y, t); + if (ret) + { + goto cleanup; + } + + /* Check that subtracting cs2 does not change high bits of w and low bits + * do not reveal secret information */ + mld_polyveck_pointwise_poly_montgomery(h, cp, s2); + mld_polyveck_invntt_tomont(h); + mld_polyveck_sub(w0, h); + mld_polyveck_reduce(w0); + + w0_invalid = mld_polyveck_chknorm(w0, MLDSA_GAMMA2 - MLDSA_BETA); + /* Constant time: w0_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&w0_invalid, sizeof(uint32_t)); + if (w0_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* Compute hints for w1 */ + mld_polyveck_pointwise_poly_montgomery(h, cp, t0); + mld_polyveck_invntt_tomont(h); + mld_polyveck_reduce(h); + + h_invalid = mld_polyveck_chknorm(h, MLDSA_GAMMA2); + /* Constant time: h_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&h_invalid, sizeof(uint32_t)); + if (h_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + mld_polyveck_add(w0, h); + + /* Constant time: At this point all norm checks have passed and we, hence, + * know that the signature does not leak any secret information. + * Consequently, any value that can be computed from the signature and public + * key is considered public. + * w0 and w1 are public as they can be computed from Az - ct = \alpha w1 + w0. + * h=c*t0 is public as both c and t0 are public. + * For a more detailed discussion, refer to https://eprint.iacr.org/2022/1406. + */ + MLD_CT_TESTING_DECLASSIFY(w0, sizeof(*w0)); + MLD_CT_TESTING_DECLASSIFY(w1, sizeof(*w1)); + n = mld_polyveck_make_hint(h, w0, w1); + if (n > MLDSA_OMEGA) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* All is well - write signature */ + mld_pack_sig_c_h(sig, challenge_bytes, h, n); + /* Constant time: At this point it is clear that the signature is valid - it + * can, hence, be considered public. */ + MLD_CT_TESTING_DECLASSIFY(sig, MLDSA_CRYPTO_BYTES); + ret = 0; /* success */ + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_poly, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(w0, mld_polyveck, 1, context); + MLD_FREE(w1tmp, w1tmp_u, 1, context); + MLD_FREE(z, mld_poly, 1, context); + MLD_FREE(yh, yh_u, 1, context); + MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + + return ret; +} +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + uint8_t *rho, *tr, *key, *mu, *rhoprime; + uint16_t nonce = 0; + MLD_ALLOC(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + + if (seedbuf == NULL || mat == NULL || s1 == NULL || t0 == NULL || s2 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + rho = seedbuf; + tr = rho + MLDSA_SEEDBYTES; + key = tr + MLDSA_TRBYTES; + mu = key + MLDSA_SEEDBYTES; + rhoprime = mu + MLDSA_CRHBYTES; + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + if (!externalmu) + { + /* Compute mu = CRH(tr, pre, msg) */ + mld_H(mu, MLDSA_CRHBYTES, tr, MLDSA_TRBYTES, pre, prelen, m, mlen); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Compute rhoprime = CRH(key, rnd, mu) */ + mld_H(rhoprime, MLDSA_CRHBYTES, key, MLDSA_SEEDBYTES, rnd, MLDSA_RNDBYTES, mu, + MLDSA_CRHBYTES); + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + /* Expand matrix and transform vectors */ + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(s1); + mld_polyveck_ntt(s2); + mld_polyveck_ntt(t0); + + /* By default, return failure. Flip to success and write output + * once signature generation succeeds. */ + ret = MLD_ERR_FAIL; + + /* Reference: This code is re-structured using a while(1), */ + /* with explicit "continue" statements (rather than "goto") */ + /* to implement rejection of invalid signatures. */ + while (1) + __loop__( + assigns(nonce, ret, object_whole(siglen), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(nonce <= MLD_NONCE_UB) + + /* t0, s1, s2, and mat are initialized above and are NOT changed by this */ + /* loop. We can therefore re-assert their bounds here as part of the */ + /* loop invariant. This makes proof noticeably faster with CBMC */ + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + invariant(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(ret == MLD_ERR_FAIL) + ) + { + /* Reference: this code explicitly checks for exhaustion of nonce */ + /* values to provide predictable termination and results in that case */ + /* Checking here also means that incrementing nonce below can also */ + /* be proven to be type-safe. */ + if (nonce == MLD_NONCE_UB) + { + /* Note that ret == MLD_ERR_FAIL by default, so we + * don't need to set it here. */ + break; + } + + ret = mld_attempt_signature_generation(sig, mu, rhoprime, nonce, mat, s1, + s2, t0, context); + nonce++; + if (ret == 0) + { + *siglen = MLDSA_CRYPTO_BYTES; + break; + } + else if (ret != MLD_ERR_FAIL) + { + /* For failures such as out-of-memory, propagate and exit immediately. */ + break; + } + + /* Otherwise, try again. */ + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the signature buffer. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + return ret; +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + size_t pre_len; + int ret; + MLD_ALLOC(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + MLD_ALLOC(rnd, uint8_t, MLDSA_RNDBYTES, context); + + if (pre == NULL || rnd == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Prepare domain separation prefix for pure ML-DSA */ + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, m, mlen, pre, pre_len, rnd, sk, + 0, context); + +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(rnd, uint8_t, MLDSA_RNDBYTES, context); + MLD_FREE(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t rnd[MLDSA_RNDBYTES]; + int ret; + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + *siglen = 0; + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, + rnd, sk, 1, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(rnd, sizeof(rnd)); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + for (i = 0; i < mlen; ++i) + __loop__( + assigns(i, object_whole(sm)) + invariant(i <= mlen) + ) + { + sm[MLDSA_CRYPTO_BYTES + mlen - 1 - i] = m[mlen - 1 - i]; + } + ret = mld_sign_signature(sm, smlen, sm + MLDSA_CRYPTO_BYTES, mlen, ctx, + ctxlen, sk, context); + *smlen += mlen; + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret, cmp; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck t1; + mld_polyveck w1; + } + t1w1_u; + mld_polyveck *t1; + mld_polyveck *w1; + + MLD_ALLOC(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_ALLOC(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(z, mld_polyvecl, 1, context); + MLD_ALLOC(t1w1, t1w1_u, 1, context); + MLD_ALLOC(tmp, mld_polyveck, 1, context); + MLD_ALLOC(h, mld_polyveck, 1, context); + + if (buf == NULL || rho == NULL || mu == NULL || c == NULL || c2 == NULL || + cp == NULL || mat == NULL || z == NULL || t1w1 == NULL || tmp == NULL || + h == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + t1 = &t1w1->t1; + w1 = &t1w1->w1; + + if (siglen != MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + mld_unpack_pk(rho, t1, pk); + + /* mld_unpack_sig and mld_polyvecl_chknorm signal failure through a + * single non-zero error code that's not yet aligned with MLD_ERR_XXX. + * Map it to MLD_ERR_FAIL explicitly. */ + if (mld_unpack_sig(c, z, h, sig)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + if (mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + if (!externalmu) + { + /* Compute CRH(H(rho, t1), pre, msg) */ + MLD_ALIGN uint8_t hpk[MLDSA_CRHBYTES]; + mld_H(hpk, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES, NULL, 0, NULL, + 0); + mld_H(mu, MLDSA_CRHBYTES, hpk, MLDSA_TRBYTES, pre, prelen, m, mlen); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(hpk, sizeof(hpk)); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Matrix-vector multiplication; compute Az - c2^dt1 */ + mld_poly_challenge(cp, c); + mld_poly_ntt(cp); + mld_polyveck_shiftl(t1); + mld_polyveck_ntt(t1); + mld_polyveck_pointwise_poly_montgomery(tmp, cp, t1); + + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(z); + mld_polyvec_matrix_pointwise_montgomery(w1, mat, z); + mld_polyveck_sub(w1, tmp); + mld_polyveck_reduce(w1); + mld_polyveck_invntt_tomont(w1); + + /* Reconstruct w1 */ + mld_polyveck_caddq(w1); + mld_polyveck_use_hint(tmp, w1, h); + mld_polyveck_pack_w1(buf, tmp); + /* Call random oracle and verify challenge */ + mld_H(c2, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, buf, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + + cmp = mld_ct_memcmp(c, c2, MLDSA_CTILDEBYTES); + + /* Declassify the result of the verification. */ + MLD_CT_TESTING_DECLASSIFY(&cmp, sizeof(cmp)); + + ret = cmp == 0 ? 0 : MLD_ERR_FAIL; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(h, mld_polyveck, 1, context); + MLD_FREE(tmp, mld_polyveck, 1, context); + MLD_FREE(t1w1, t1w1_u, 1, context); + MLD_FREE(z, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, m, mlen, pre, pre_len, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + return mld_sign_verify_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, pk, + 1, context); +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + if (smlen < MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + *mlen = smlen - MLDSA_CRYPTO_BYTES; + ret = mld_sign_verify(sm, MLDSA_CRYPTO_BYTES, sm + MLDSA_CRYPTO_BYTES, *mlen, + ctx, ctxlen, pk, context); + if (ret == 0) + { + /* All good, copy msg, return 0 */ + for (i = 0; i < *mlen; ++i) + __loop__( + assigns(i, memory_slice(m, *mlen)) + invariant(i <= *mlen) + ) + { + m[i] = sm[MLDSA_CRYPTO_BYTES + i]; + } + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the message buffer. */ + *mlen = 0; + mld_memset(m, 0, smlen); + } + + return ret; +} + + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_signature_internal(sig, siglen, pre, pre_len, NULL, 0, rnd, sk, + 0, context); +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, pre, pre_len, NULL, 0, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_signature_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, rnd, sk, + MLD_PREHASH_SHAKE_256, context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_verify_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, pk, MLD_PREHASH_SHAKE_256, + context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + + +#define MLD_PRE_HASH_OID_LEN 11 + +/************************************************* + * Name: mld_get_hash_oid + * + * Description: Returns the OID of a given SHA-2/SHA-3 hash function. + * + * Arguments: - uint8_t oid[11]: pointer to output oid + * - int hashalg: hash algorithm constant (MLD_PREHASH_*) + * + ***************************************************/ +static void mld_get_hash_oid(uint8_t oid[MLD_PRE_HASH_OID_LEN], int hashalg) +{ + unsigned int i; + static const struct + { + int alg; + uint8_t oid[MLD_PRE_HASH_OID_LEN]; + } oid_map[] = { + {MLD_PREHASH_SHA2_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}}, + {MLD_PREHASH_SHA2_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}}, + {MLD_PREHASH_SHA2_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}}, + {MLD_PREHASH_SHA2_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}}, + {MLD_PREHASH_SHA2_512_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05}}, + {MLD_PREHASH_SHA2_512_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06}}, + {MLD_PREHASH_SHA3_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07}}, + {MLD_PREHASH_SHA3_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08}}, + {MLD_PREHASH_SHA3_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09}}, + {MLD_PREHASH_SHA3_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A}}, + {MLD_PREHASH_SHAKE_128, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B}}, + {MLD_PREHASH_SHAKE_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C}}}; + + for (i = 0; i < sizeof(oid_map) / sizeof(oid_map[0]); i++) + __loop__( + invariant(i <= sizeof(oid_map) / sizeof(oid_map[0])) + ) + { + if (oid_map[i].alg == hashalg) + { + mld_memcpy(oid, oid_map[i].oid, MLD_PRE_HASH_OID_LEN); + return; + } + } +} + +static int mld_validate_hash_length(int hashalg, size_t len) +{ + switch (hashalg) + { + case MLD_PREHASH_SHA2_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_128: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_256: + return (len == 512 / 8) ? 0 : -1; + } + return -1; +} + +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +{ + if (ctxlen > 255) + { + return 0; + } + + if (hashalg != MLD_PREHASH_NONE) + { + if (ph == NULL || mld_validate_hash_length(hashalg, phlen) != 0) + { + return 0; + } + } + + /* Common prefix: 0x00/0x01 || ctxlen || ctx */ + prefix[0] = (hashalg == MLD_PREHASH_NONE) ? 0 : 1; + prefix[1] = (uint8_t)ctxlen; + if (ctxlen > 0) + { + mld_memcpy(prefix + 2, ctx, ctxlen); + } + + if (hashalg == MLD_PREHASH_NONE) + { + return 2 + ctxlen; + } + + /* HashML-DSA: append oid || ph */ + mld_get_hash_oid(prefix + 2 + ctxlen, hashalg); + mld_memcpy(prefix + 2 + ctxlen + MLD_PRE_HASH_OID_LEN, ph, phlen); + return 2 + ctxlen + MLD_PRE_HASH_OID_LEN + phlen; +} + +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + uint8_t check, cmp0, cmp1, chk1, chk2; + int ret; + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(t0_computed, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + + if (rho == NULL || tr == NULL || tr_computed == NULL || key == NULL || + s1 == NULL || s2 == NULL || t0 == NULL || t0_computed == NULL || + t1 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Unpack secret key */ + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + /* Validate s1 and s2 coefficients are within [-MLDSA_ETA, MLDSA_ETA] */ + chk1 = mld_polyvecl_chknorm(s1, MLDSA_ETA + 1) & 0xFF; + chk2 = mld_polyveck_chknorm(s2, MLDSA_ETA + 1) & 0xFF; + + /* Recompute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0_computed, t1, tr_computed, + pk, rho, s1, s2, context); + if (ret != 0) + { + goto cleanup; + } + + /* Validate t0 and tr using constant-time comparisons */ + cmp0 = mld_ct_memcmp((const uint8_t *)t0, (const uint8_t *)t0_computed, + sizeof(mld_polyveck)); + cmp1 = mld_ct_memcmp((const uint8_t *)tr, (const uint8_t *)tr_computed, + MLDSA_TRBYTES); + check = mld_value_barrier_u8(cmp0 | cmp1 | chk1 | chk2); + + /* Declassify the final result of the validity check. */ + MLD_CT_TESTING_DECLASSIFY(&check, sizeof(check)); + ret = (check != 0) ? MLD_ERR_FAIL : 0; + +cleanup: + + if (ret != 0) + { + mld_zeroize(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + } + + /* Constant time: pk is either the valid public key or zeroed on error */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(t0_computed, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + + return ret; +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_check_pct +#undef mld_sample_s1_s2 +#undef mld_validate_hash_length +#undef mld_get_hash_oid +#undef mld_H +#undef mld_compute_pack_z +#undef mld_attempt_signature_generation +#undef mld_compute_t0_t1_tr_from_sk_components +#undef MLD_NONCE_UB +#undef MLD_PRE_HASH_OID_LEN diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/sign.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/sign.h new file mode 100644 index 0000000000..2e0bac32ea --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/sign.h @@ -0,0 +1,807 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_SIGN_H +#define MLD_SIGN_H + +#include +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "polyvec.h" +#include "sys.h" + +#if defined(MLD_CHECK_APIS) +/* Include to ensure consistency between internal sign.h + * and external mldsa_native.h. */ +#include "mldsa_native.h" + +#if MLDSA_CRYPTO_SECRETKEYBYTES != \ + MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for SECRETKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_PUBLICKEYBYTES != \ + MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for PUBLICKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_BYTES != MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for CRYPTO_BYTES between sign.h and mldsa_native.h +#endif + +#endif /* MLD_CHECK_APIS */ + +#define mld_sign_keypair_internal \ + MLD_NAMESPACE_KL(keypair_internal) MLD_CONTEXT_PARAMETERS_3 +#define mld_sign_keypair MLD_NAMESPACE_KL(keypair) MLD_CONTEXT_PARAMETERS_2 +#define mld_sign_signature_internal \ + MLD_NAMESPACE_KL(signature_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_signature MLD_NAMESPACE_KL(signature) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_extmu \ + MLD_NAMESPACE_KL(signature_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign MLD_NAMESPACE_KL(sign) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_internal \ + MLD_NAMESPACE_KL(verify_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify MLD_NAMESPACE_KL(verify) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_extmu \ + MLD_NAMESPACE_KL(verify_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign_open MLD_NAMESPACE_KL(open) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_pre_hash_internal \ + MLD_NAMESPACE_KL(signature_pre_hash_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_verify_pre_hash_internal \ + MLD_NAMESPACE_KL(verify_pre_hash_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_signature_pre_hash_shake256 \ + MLD_NAMESPACE_KL(signature_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify_pre_hash_shake256 \ + MLD_NAMESPACE_KL(verify_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_7 +#define mld_prepare_domain_separation_prefix \ + MLD_NAMESPACE_KL(prepare_domain_separation_prefix) +#define mld_sign_pk_from_sk \ + MLD_NAMESPACE_KL(pk_from_sk) MLD_CONTEXT_PARAMETERS_2 + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: mld_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: input random seed + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int externalmu: indicates input message m is + * processed as mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return MLD_ERR_FAIL in that case. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires((externalmu == 0 && (prelen == 0 || memory_no_alias(pre, prelen))) || + (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) + ensures(return_value == 0 ==> *siglen == MLDSA_CRYPTO_BYTES) + ensures(return_value != 0 ==> *siglen == 0) +); + +/************************************************* + * Name: mld_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_signature_extmu + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign + * + * Description: Compute signed message. + * + * Arguments: - uint8_t *sm: pointer to output signed message + * (allocated array with MLDSA_CRYPTO_BYTES + + *mlen bytes), can be equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sm, MLDSA_CRYPTO_BYTES + mlen)) + requires(memory_no_alias(smlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sm, MLDSA_CRYPTO_BYTES + mlen)) + assigns(object_whole(smlen)) + ensures((return_value == 0 && *smlen == MLDSA_CRYPTO_BYTES + mlen) || + (return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL)) +); + +/************************************************* + * Name: mld_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as + * mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(externalmu == 0 || (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + requires(externalmu == 1 || prelen == 0 || memory_no_alias(pre, prelen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_open + * + * Description: Verify signed message. + * + * Arguments: - uint8_t *m: pointer to output message (allocated array + * with smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context tring + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(smlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(m, smlen)) + requires(memory_no_alias(mlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(sm, smlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + assigns(memory_slice(m, smlen)) + assigns(memory_slice(mlen, sizeof(size_t))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and + * verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/* Maximum formatted domain separation message length: + * - Pure ML-DSA: 0x00 || ctxlen || ctx (max 255) + * - HashML-DSA: 0x01 || ctxlen || ctx (max 255) || oid (11) || ph (max 64) */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +__contract__( + requires(ctxlen <= 255) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(hashalg == MLD_PREHASH_NONE || memory_no_alias(ph, phlen)) + requires(memory_no_alias(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + assigns(memory_slice(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + ensures(return_value <= MLD_DOMAIN_SEPARATION_MAX_BYTES) +); + +/************************************************* + * Name: mld_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: input secret + * key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); +#endif /* !MLD_SIGN_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/symmetric.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/symmetric.h new file mode 100644 index 0000000000..bb70f05552 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/symmetric.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_SYMMETRIC_H +#define MLD_SYMMETRIC_H + +#include +#include "cbmc.h" +#include "common.h" + +#include MLD_FIPS202_HEADER_FILE +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#include MLD_FIPS202X4_HEADER_FILE +#endif + +#define MLD_STREAM128_BLOCKBYTES SHAKE128_RATE +#define MLD_STREAM256_BLOCKBYTES SHAKE256_RATE + +#define mld_xof256_ctx mld_shake256ctx +#define mld_xof256_init(CTX) mld_shake256_init(CTX) + +#define mld_xof256_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake256_absorb(CTX, IN, INBYTES); \ + mld_shake256_finalize(CTX); \ + } while (0) + + +#define mld_xof256_release(CTX) mld_shake256_release(CTX) +#define mld_xof256_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake256_squeeze(OUT, (OUTBLOCKS) * SHAKE256_RATE, STATE) + +#define mld_xof128_ctx mld_shake128ctx +#define mld_xof128_init(CTX) mld_shake128_init(CTX) + +#define mld_xof128_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake128_absorb(CTX, IN, INBYTES); \ + mld_shake128_finalize(CTX); \ + } while (0) + +#define mld_xof128_release(CTX) mld_shake128_release(CTX) +#define mld_xof128_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake128_squeeze(OUT, (OUTBLOCKS) * SHAKE128_RATE, STATE) + +#define mld_xof256_x4_ctx mld_shake256x4ctx +#define mld_xof256_x4_init(CTX) mld_shake256x4_init((CTX)) +#define mld_xof256_x4_absorb(CTX, IN, INBYTES) \ + mld_shake256x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof256_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake256x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof256_x4_release(CTX) mld_shake256x4_release((CTX)) + +#define mld_xof128_x4_ctx mld_shake128x4ctx +#define mld_xof128_x4_init(CTX) mld_shake128x4_init((CTX)) +#define mld_xof128_x4_absorb(CTX, IN, INBYTES) \ + mld_shake128x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof128_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake128x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof128_x4_release(CTX) mld_shake128x4_release((CTX)) + +#endif /* !MLD_SYMMETRIC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/sys.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/sys.h new file mode 100644 index 0000000000..1226526420 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/sys.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_SYS_H +#define MLD_SYS_H + +#if !defined(MLD_CONFIG_NO_ASM) && (defined(__GNUC__) || defined(__clang__)) +#define MLD_HAVE_INLINE_ASM +#endif + +/* Try to find endianness, if not forced through CFLAGS already */ +#if !defined(MLD_SYS_LITTLE_ENDIAN) && !defined(MLD_SYS_BIG_ENDIAN) +#if defined(__BYTE_ORDER__) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define MLD_SYS_LITTLE_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define MLD_SYS_BIG_ENDIAN +#else +#error "__BYTE_ORDER__ defined, but don't recognize value." +#endif +#endif /* __BYTE_ORDER__ */ + +/* MSVC does not define __BYTE_ORDER__. However, MSVC only supports + * little endian x86, x86_64, and AArch64. It is, hence, safe to assume + * little endian. */ +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_IX86) || defined(_M_ARM64)) +#define MLD_SYS_LITTLE_ENDIAN +#endif + +#endif /* !MLD_SYS_LITTLE_ENDIAN && !MLD_SYS_BIG_ENDIAN */ + +/* Check if we're running on an AArch64 little endian system. _M_ARM64 is set by + * MSVC. */ +#if defined(__AARCH64EL__) || defined(_M_ARM64) +#define MLD_SYS_AARCH64 +#endif + +/* Check if we're running on an AArch64 big endian system. */ +#if defined(__AARCH64EB__) +#define MLD_SYS_AARCH64_EB +#endif + +#if defined(__x86_64__) +#define MLD_SYS_X86_64 +#if defined(__AVX2__) +#define MLD_SYS_X86_64_AVX2 +#endif +#endif /* __x86_64__ */ + +#if defined(MLD_SYS_LITTLE_ENDIAN) && defined(__powerpc64__) +#define MLD_SYS_PPC64LE +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 +#define MLD_SYS_RISCV64 +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32 +#define MLD_SYS_RISCV32 +#endif + +#if defined(_WIN64) || defined(_WIN32) +#define MLD_SYS_WINDOWS +#endif + +#if defined(__linux__) +#define MLD_SYS_LINUX +#endif + +#if defined(__APPLE__) +#define MLD_SYS_APPLE +#endif + +/* If MLD_FORCE_AARCH64 is set, assert that we're indeed on an AArch64 system. + */ +#if defined(MLD_FORCE_AARCH64) && !defined(MLD_SYS_AARCH64) +#error "MLD_FORCE_AARCH64 is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_AARCH64_EB is set, assert that we're indeed on a big endian + * AArch64 system. */ +#if defined(MLD_FORCE_AARCH64_EB) && !defined(MLD_SYS_AARCH64_EB) +#error \ + "MLD_FORCE_AARCH64_EB is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_X86_64 is set, assert that we're indeed on an X86_64 system. */ +#if defined(MLD_FORCE_X86_64) && !defined(MLD_SYS_X86_64) +#error "MLD_FORCE_X86_64 is set, but we don't seem to be on an X86_64 system." +#endif + +#if defined(MLD_FORCE_PPC64LE) && !defined(MLD_SYS_PPC64LE) +#error "MLD_FORCE_PPC64LE is set, but we don't seem to be on a PPC64LE system." +#endif + +#if defined(MLD_FORCE_RISCV64) && !defined(MLD_SYS_RISCV64) +#error "MLD_FORCE_RISCV64 is set, but we don't seem to be on a RISCV64 system." +#endif + +#if defined(MLD_FORCE_RISCV32) && !defined(MLD_SYS_RISCV32) +#error "MLD_FORCE_RISCV32 is set, but we don't seem to be on a RISCV32 system." +#endif + +/* + * MLD_INLINE: Hint for inlining. + * - MSVC: __inline + * - C99+: inline + * - GCC/Clang C90: __attribute__((unused)) to silence warnings + * - Other C90: empty + */ +#if !defined(MLD_INLINE) +#if defined(_MSC_VER) +#define MLD_INLINE __inline +#elif defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +#define MLD_INLINE inline +#elif defined(__GNUC__) || defined(__clang__) +#define MLD_INLINE __attribute__((unused)) +#else +#define MLD_INLINE +#endif +#endif /* !MLD_INLINE */ + +/* + * MLD_ALWAYS_INLINE: Force inlining. + * - MSVC: __forceinline + * - GCC/Clang C99+: MLD_INLINE __attribute__((always_inline)) + * - Other: MLD_INLINE (no forced inlining) + */ +#if !defined(MLD_ALWAYS_INLINE) +#if defined(_MSC_VER) +#define MLD_ALWAYS_INLINE __forceinline +#elif (defined(__GNUC__) || defined(__clang__)) && \ + (defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)) +#define MLD_ALWAYS_INLINE MLD_INLINE __attribute__((always_inline)) +#else +#define MLD_ALWAYS_INLINE MLD_INLINE +#endif +#endif /* !MLD_ALWAYS_INLINE */ + +#ifndef MLD_STATIC_TESTABLE +#define MLD_STATIC_TESTABLE static +#endif + +/* + * C90 does not have the restrict compiler directive yet. + * We don't use it in C90 builds. + */ +#if !defined(restrict) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define MLD_RESTRICT restrict +#else +#define MLD_RESTRICT +#endif + +#else /* !restrict */ + +#define MLD_RESTRICT restrict +#endif /* restrict */ + +#define MLD_DEFAULT_ALIGN 32 +#define MLD_ALIGN_UP(N) \ + ((((N) + (MLD_DEFAULT_ALIGN - 1)) / MLD_DEFAULT_ALIGN) * MLD_DEFAULT_ALIGN) +#if defined(__GNUC__) +#define MLD_ALIGN __attribute__((aligned(MLD_DEFAULT_ALIGN))) +#elif defined(_MSC_VER) +#define MLD_ALIGN __declspec(align(MLD_DEFAULT_ALIGN)) +#else +#define MLD_ALIGN /* No known support for alignment constraints */ +#endif + + +/* New X86_64 CPUs support Conflow-flow protection using the CET instructions. + * When enabled (through -fcf-protection=), all compilation units (including + * empty ones) need to support CET for this to work. + * For assembly, this means that source files need to signal support for + * CET by setting the appropriate note.gnu.property section. + * This can be achieved by including the header in all assembly file. + * This file also provides the _CET_ENDBR macro which needs to be placed at + * every potential target of an indirect branch. + * If CET is enabled _CET_ENDBR maps to the endbr64 instruction, otherwise + * it is empty. + * In case the compiler does not support CET (e.g., +#define MLD_CET_ENDBR _CET_ENDBR +#else +#define MLD_CET_ENDBR +#endif +#endif /* MLD_SYS_X86_64 */ + +#if defined(MLD_CONFIG_CT_TESTING_ENABLED) && !defined(__ASSEMBLER__) +#include +#define MLD_CT_TESTING_SECRET(ptr, len) \ + VALGRIND_MAKE_MEM_UNDEFINED((ptr), (len)) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) +#else /* MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__ */ +#define MLD_CT_TESTING_SECRET(ptr, len) \ + do \ + { \ + } while (0) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + do \ + { \ + } while (0) +#endif /* !(MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__) */ + +#if defined(__GNUC__) || defined(__clang__) +#define MLD_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_MUST_CHECK_RETURN_VALUE +#endif + + +#if !defined(__ASSEMBLER__) +/* System capability enumeration */ +typedef enum +{ + /* x86_64 */ + MLD_SYS_CAP_AVX2, + /* AArch64 */ + MLD_SYS_CAP_SHA3 +} mld_sys_cap; + +#if !defined(MLD_CONFIG_CUSTOM_CAPABILITY_FUNC) +#include "cbmc.h" + +static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) +__contract__( + ensures(return_value == 0 || return_value == 1) +) +{ + /* By default, we rely on compile-time feature detection/specification: + * If a feature is enabled at compile-time, we assume it is supported by + * the host that the resulting library/binary will be built on. + * If this assumption is not true, you MUST overwrite this function. + * See the documentation of MLD_CONFIG_CUSTOM_CAPABILITY_FUNC in + * mldsa_native_config.h for more information. */ + (void)cap; + return 1; +} +#endif /* !MLD_CONFIG_CUSTOM_CAPABILITY_FUNC */ +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_SYS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/zetas.inc b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/zetas.inc new file mode 100644 index 0000000000..dc3cf15dd3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/mldsa_native/src/zetas.inc @@ -0,0 +1,56 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include + +/* + * Table of zeta values used in the reference NTT and inverse NTT. + * See autogen for details. + */ +static const int32_t mld_zetas[MLDSA_N] = { + 0, 25847, -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 2353451, -359251, -2091905, 3119733, -2884855, + 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488, + -1119584, 2619752, -2108549, -2118186, -3859737, -1399561, -3277672, + 1757237, -19422, 4010497, 280005, 2706023, 95776, 3077325, + 3530437, -1661693, -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267, + -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596, + 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, + -2797779, -3930395, -1528703, -3677745, -3041255, -1452451, 3475950, + 2176455, -1585221, -1257611, 1939314, -4083598, -1000202, -3190144, + -3157330, -3632928, 126922, 3412210, -983419, 2147896, 2715295, + -2967645, -3693493, -411027, -2477047, -671102, -1228525, -22981, + -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944, + 508951, 3097992, 44288, -1100098, 904516, 3958618, -3724342, + -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856, + 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, + 1341330, 1285669, -1584928, -812732, -1439742, -3019102, -3881060, + -3628969, 3839961, 2091667, 3407706, 2316500, 3817976, -3342478, + 2244091, -2446433, -3562462, 266997, 2434439, -1235728, 3513181, + -3520352, -3759364, -1197226, -3193378, 900702, 1859098, 909542, + 819034, 495491, -1613174, -43260, -522500, -655327, -3122442, + 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297, + 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, + 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, + 1595974, -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, + 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100, + 1312455, 3306115, -1962642, -1279661, 1917081, -2546312, -1374803, + 1500165, 777191, 2235880, 3406031, -542412, -2831860, -1671176, + -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395, + 2454455, -164721, 1957272, 3369112, 185531, -1207385, -3183426, + 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, + -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, + 472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333, + -260646, -3833893, -2939036, -2235985, -420899, -2286327, 183443, + -976891, 1612842, -3545687, -554416, 3919660, -48306, -1362209, + 3937738, 1400424, -846154, 1976782, +}; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/test_only_rng/notrandombytes.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/test_only_rng/notrandombytes.c new file mode 100644 index 0000000000..ef5a423a9e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/test_only_rng/notrandombytes.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* * Based on @[surf]*/ + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +#include +#include + +#include "notrandombytes.h" + +#ifdef ENABLE_CT_TESTING +#include +#endif + +static uint32_t seed[32] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, + 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5}; +static uint32_t in[12]; +static uint32_t out[8]; +static int32_t outleft = 0; + +void randombytes_reset(void) +{ + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + outleft = 0; +} + +#define ROTATE(x, b) (((x) << (b)) | ((x) >> (32 - (b)))) +#define MUSH(i, b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x, b)); + +static void surf(void) +{ + uint32_t t[12]; + uint32_t x; + uint32_t sum = 0; + int32_t r; + int32_t i; + int32_t loop; + + for (i = 0; i < 12; ++i) + { + t[i] = in[i] ^ seed[12 + i]; + } + for (i = 0; i < 8; ++i) + { + out[i] = seed[24 + i]; + } + x = t[11]; + for (loop = 0; loop < 2; ++loop) + { + for (r = 0; r < 16; ++r) + { + sum += 0x9e3779b9; + MUSH(0, 5) + MUSH(1, 7) + MUSH(2, 9) + MUSH(3, 13) + MUSH(4, 5) + MUSH(5, 7) + MUSH(6, 9) + MUSH(7, 13) + MUSH(8, 5) + MUSH(9, 7) + MUSH(10, 9) + MUSH(11, 13) + } + for (i = 0; i < 8; ++i) + { + out[i] ^= t[i + 4]; + } + } +} + +int randombytes(uint8_t *buf, size_t n) +{ +#ifdef ENABLE_CT_TESTING + uint8_t *buf_orig = buf; + size_t n_orig = n; +#endif + + while (n > 0) + { + if (!outleft) + { + if (!++in[0]) + { + if (!++in[1]) + { + if (!++in[2]) + { + ++in[3]; + } + } + } + surf(); + outleft = 8; + } + *buf = (uint8_t)out[--outleft]; + ++buf; + --n; + } + +#ifdef ENABLE_CT_TESTING + /* + * Mark all randombytes output as secret (undefined). + * Valgrind will propagate this to everything derived from it. + */ + VALGRIND_MAKE_MEM_UNDEFINED(buf_orig, n_orig); +#endif /* ENABLE_CT_TESTING */ + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/test_only_rng/notrandombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/test_only_rng/notrandombytes.h new file mode 100644 index 0000000000..bdf9787920 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/monolithic_build_native/test_only_rng/notrandombytes.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* Based on @[surf]. */ + +#ifndef NOTRANDOMBYTES_H +#define NOTRANDOMBYTES_H + +#include +#include + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +void randombytes_reset(void); +int randombytes(uint8_t *buf, size_t n); + +#endif /* !NOTRANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/.gitignore b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/.gitignore new file mode 100644 index 0000000000..eb98a94f12 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +build diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/Makefile new file mode 100644 index 0000000000..efe789c319 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/Makefile @@ -0,0 +1,126 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +.PHONY: build run clean mldsa44_objs mldsa65_objs mldsa87_objs mldsa_objs +.DEFAULT_GOAL := all + +Q ?= @ + +CC ?= gcc + +# Adjust CFLAGS if needed +CFLAGS := \ + -Wall \ + -Wextra \ + -Werror=unused-result \ + -Wpedantic \ + -Werror \ + -Wmissing-prototypes \ + -Wshadow \ + -Wpointer-arith \ + -Wredundant-decls \ + -Wconversion \ + -Wsign-conversion \ + -Wno-long-long \ + -Wno-unknown-pragmas \ + -Wno-unused-command-line-argument \ + -O3 \ + -fomit-frame-pointer \ + -Imldsa_native/ \ + -DMLD_CONFIG_NAMESPACE_PREFIX=mldsa \ + -std=c99 \ + -pedantic \ + -MMD \ + $(CFLAGS) + +# If you want to use the native backends, the compiler needs to know about +# the target architecture. Here, we import the default host detection from +# mldsa-native's tests, but you can write your own or specialize accordingly. +AUTO ?= 1 +include auto.mk + +# The following only concerns the cross-compilation tests. +# You can likely ignore the following for your application. +# +# Append cross-prefix for cross compilation +# When called from the root Makefile, CROSS_PREFIX has already been added here +ifeq (,$(findstring $(CROSS_PREFIX),$(CC))) +CC := $(CROSS_PREFIX)$(CC) +endif + +# Part A: +# +# mldsa-native source and header files +# +# In this example, we compile the individual mldsa-native source files directly. +# Alternatively, you can compile the 'monobuild' source file mldsa_native.c. +# See examples/monolithic_build for that. +MLD_SOURCE_ALL := $(wildcard \ + mldsa_native/src/*.c \ + mldsa_native/src/**/*.c \ + mldsa_native/src/**/**/*.c \ + mldsa_native/src/**/**/**/*.c) +MLD_SOURCE:=$(foreach S,$(MLD_SOURCE_ALL),\ + $(if $(findstring /native/,$S),,$S)) + +BUILD_DIR=build +MLDSA44_DIR = $(BUILD_DIR)/mldsa44 +MLDSA65_DIR = $(BUILD_DIR)/mldsa65 +MLDSA87_DIR = $(BUILD_DIR)/mldsa87 + +MLDSA44_OBJS=$(patsubst %,$(MLDSA44_DIR)/%.o,$(MLD_SOURCE)) +MLDSA65_OBJS=$(patsubst %,$(MLDSA65_DIR)/%.o,$(MLD_SOURCE)) +MLDSA87_OBJS=$(patsubst %,$(MLDSA87_DIR)/%.o,$(MLD_SOURCE)) + +$(MLDSA44_OBJS): $(MLDSA44_DIR)/%.c.o: %.c + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -DMLD_CONFIG_MULTILEVEL_WITH_SHARED -DMLD_CONFIG_PARAMETER_SET=44 $(CFLAGS) -c $^ -o $@ + +$(MLDSA65_OBJS): $(MLDSA65_DIR)/%.c.o: %.c + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -DMLD_CONFIG_MULTILEVEL_NO_SHARED -DMLD_CONFIG_PARAMETER_SET=65 $(CFLAGS) -c $^ -o $@ + +$(MLDSA87_OBJS): $(MLDSA87_DIR)/%.c.o: %.c + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -DMLD_CONFIG_MULTILEVEL_NO_SHARED -DMLD_CONFIG_PARAMETER_SET=87 $(CFLAGS) -c $^ -o $@ + +mldsa44_objs: $(MLDSA44_OBJS) +mldsa65_objs: $(MLDSA65_OBJS) +mldsa87_objs: $(MLDSA87_OBJS) +mldsa_objs: mldsa44_objs mldsa65_objs mldsa87_objs + +# Part B: +# +# Random number generator +# +# !!! WARNING !!! +# +# The randombytes() implementation used here is for TESTING ONLY. +# You MUST NOT use this implementation outside of testing. +# +# !!! WARNING !!! +RNG_SOURCE=$(wildcard test_only_rng/*.c) + +# Part C: +# +# Your application source code +APP_SOURCE=$(wildcard *.c) + +BIN=test_binary + +BINARY_NAME_FULL=$(BUILD_DIR)/$(BIN) + +$(BINARY_NAME_FULL): $(APP_SOURCE) $(RNG_SOURCE) $(MLDSA44_OBJS) $(MLDSA65_OBJS) $(MLDSA87_OBJS) + echo "$@" + mkdir -p $(BUILD_DIR) + $(CC) $(CFLAGS) $^ -o $@ + +all: build + +build: $(BINARY_NAME_FULL) + +run: $(BINARY_NAME_FULL) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL) + +clean: + rm -rf $(BUILD_DIR) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/README.md new file mode 100644 index 0000000000..577f1a863b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/README.md @@ -0,0 +1,51 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Multi-Level Build (C Backend) + +This directory contains a minimal example for building mldsa-native with support for all three security levels +(ML-DSA-44, ML-DSA-65, ML-DSA-87), with level-independent code shared to reduce binary size. + +## Use Case + +Use this approach when: +- You need multiple ML-DSA security levels in the same application +- You want to minimize code duplication across levels +- You want to build the mldsa-native C files separately, not as a single compilation unit. +- You're only using C (no native backends) + +## Components + +1. mldsa-native source tree: [`mldsa/src/`](../../mldsa/src) and [`mldsa/src/fips202/`](../../mldsa/src/fips202) +2. A secure random number generator implementing [`randombytes.h`](../../mldsa/src/randombytes.h) +3. Your application source code + +## Configuration + +The library is built 3 times into separate directories (`build/mldsa44`, `build/mldsa65`, `build/mldsa87`). + +The configuration file [mldsa_native_config.h](mldsa_native/mldsa_native_config.h) sets: +- `MLD_CONFIG_MULTILEVEL_BUILD`: Enables multi-level build mode +- `MLD_CONFIG_NAMESPACE_PREFIX=mldsa`: Base prefix; level suffix added automatically +- `MLD_CONFIG_NO_SUPERCOP`: Disables the SUPERCOP API (crypto_sign*) + +Build-time flags passed via CFLAGS: +- `MLD_CONFIG_PARAMETER_SET=44/65/87`: Selects the security level +- `MLD_CONFIG_MULTILEVEL_WITH_SHARED`: Set for ONE build (e.g., 44) to include shared code +- `MLD_CONFIG_MULTILEVEL_NO_SHARED`: Set for OTHER builds to exclude shared code + +The resulting API functions are namespaced as: +- `mldsa44_keypair()`, `mldsa44_signature()`, `mldsa44_verify()`, ... +- `mldsa65_keypair()`, `mldsa65_signature()`, `mldsa65_verify()`, ... +- `mldsa87_keypair()`, `mldsa87_signature()`, `mldsa87_verify()`, ... + +## Usage + +```bash +make build # Build all three security levels +make run # Run the example +``` + +## Warning + +The `randombytes()` implementation in `test_only_rng/` is for TESTING ONLY. +You MUST provide a cryptographically secure RNG for production use. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/auto.mk b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/auto.mk new file mode 100644 index 0000000000..5f71942085 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/auto.mk @@ -0,0 +1,178 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# Automatically detect system architecture and set preprocessor flags accordingly +# This file detects host CPU capabilities and combines them with compiler support +# to enable optimal compilation flags. +# +# Compiler feature detection can be overridden by setting the corresponding variable +# on the command line: +# make MK_COMPILER_SUPPORTS_SHA3=0 # Disable SHA3 detection +# make MK_COMPILER_SUPPORTS_AVX2=0 # Disable AVX2 detection +# make MK_COMPILER_SUPPORTS_BMI2=0 # Disable BMI2 detection +# make MK_COMPILER_SUPPORTS_SSE2=0 # Disable SSE2 detection + +ifndef _AUTO_MK +_AUTO_MK := + +# Override ARCH for cross-compilation based on CROSS_PREFIX +ifeq ($(CROSS_PREFIX),) +ARCH := $(shell uname -m) +# Normalize architecture names +ifeq ($(ARCH),arm64) +ARCH := aarch64 +endif +else # CROSS_PREFIX +ifneq ($(findstring x86_64, $(CROSS_PREFIX)),) +ARCH := x86_64 +else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),) +ARCH := aarch64_be +else ifneq ($(findstring aarch64, $(CROSS_PREFIX)),) +ARCH := aarch64 +else ifneq ($(findstring riscv64, $(CROSS_PREFIX)),) +ARCH := riscv64 +else ifneq ($(findstring riscv32, $(CROSS_PREFIX)),) +ARCH := riscv32 +else ifneq ($(findstring powerpc64le, $(CROSS_PREFIX)),) +ARCH := powerpc64le +else ifneq ($(findstring arm-none-eabi-, $(CROSS_PREFIX)),) +ARCH := arm +else +ifeq ($(AUTO),1) +$(warning Unknown cross-compilation prefix $(CROSS_PREFIX), no automatic detection of CFLAGS.) +ARCH := unknown +endif +endif +endif # CROSS_PREFIX + +# x86_64 compiler feature detection +ifeq ($(ARCH),x86_64) + +# Test AVX2 support using C with inline assembly +MK_COMPILER_SUPPORTS_AVX2 ?= $(shell echo 'int main() { __asm__("vpxor %%ymm0, %%ymm1, %%ymm2" ::: "ymm0", "ymm1", "ymm2"); return 0; }' | $(CC) -mavx2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test SSE2 support using C with inline assembly +MK_COMPILER_SUPPORTS_SSE2 ?= $(shell echo 'int main() { __asm__("pxor %%xmm0, %%xmm1" ::: "xmm0", "xmm1"); return 0; }' | $(CC) -msse2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test BMI2 support using C with inline assembly +MK_COMPILER_SUPPORTS_BMI2 ?= $(shell echo 'int main() { __asm__("pdep %%eax, %%ebx, %%ecx" ::: "eax", "ebx", "ecx"); return 0; }' | $(CC) -mbmi2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # x86_64 compiler detection + +# AArch64 compiler feature detection +ifeq ($(ARCH),aarch64) + +# Test SHA3 support (Armv8.4-a+SHA3) using C with inline assembly +MK_COMPILER_SUPPORTS_SHA3 ?= $(shell echo 'int main() { __asm__("eor3 v0.16b, v1.16b, v2.16b, v3.16b" ::: "v0", "v1", "v2", "v3"); return 0; }' | $(CC) -march=armv8.4-a+sha3 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # aarch64 compiler detection + +# Define HOST_PLATFORM if not already defined +HOST_PLATFORM ?= $(shell uname -s)-$(shell uname -m) + +# Helper function to check if host CPU supports a feature +# Usage: $(call check_host_feature,feature_pattern,source_command) +define check_host_feature +$(shell $(2) 2>/dev/null | grep -q "$(1)" && echo 1 || echo 0) +endef + +# x86_64 architecture detection +ifeq ($(ARCH),x86_64) + +# Host CPU feature detection for x86_64 +ifeq ($(HOST_PLATFORM),Linux-x86_64) +# Linux: Use /proc/cpuinfo +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,avx2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,sse2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,bmi2,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-x86_64) +# macOS: Use sysctl +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,AVX2,sysctl -n machdep.cpu.leaf7_features) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,SSE2,sysctl -n machdep.cpu.features) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,BMI2,sysctl -n machdep.cpu.leaf7_features) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_AVX2 := 1 +MK_HOST_SUPPORTS_SSE2 := 1 +MK_HOST_SUPPORTS_BMI2 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_AVX2 := 0 +MK_HOST_SUPPORTS_SSE2 := 0 +MK_HOST_SUPPORTS_BMI2 := 0 +endif # HOST_PLATFORM x86_64 + +endif # x86_64 + +# AArch64 architecture detection +ifeq ($(ARCH),aarch64) + +# Host CPU feature detection for AArch64 +ifeq ($(HOST_PLATFORM),Linux-aarch64) +# Linux: Use /proc/cpuinfo (look for sha3 in Features line) +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,sha3,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-arm64) +# macOS: Use sysctl to check for SHA3 support +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,1,sysctl -n hw.optional.armv8_2_sha3) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_SHA3 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_SHA3 := 0 +endif # HOST_PLATFORM aarch64 + +endif # aarch64 + +# Only apply CFLAGS modifications if AUTO=1 +ifeq ($(AUTO),1) + +# x86_64 CFLAGS configuration +ifeq ($(ARCH),x86_64) +CFLAGS += -DMLD_FORCE_X86_64 + +# Add flags only if both compiler and host support the feature +ifeq ($(MK_COMPILER_SUPPORTS_AVX2)$(MK_HOST_SUPPORTS_AVX2),11) +CFLAGS += -mavx2 +endif + +ifeq ($(MK_COMPILER_SUPPORTS_BMI2)$(MK_HOST_SUPPORTS_BMI2),11) +CFLAGS += -mbmi2 +endif +endif # x86_64 + +# AArch64 CFLAGS configuration +ifeq ($(ARCH),aarch64) +CFLAGS += -DMLD_FORCE_AARCH64 + +# Add SHA3 flags only if both compiler and host support it +ifeq ($(MK_COMPILER_SUPPORTS_SHA3)$(MK_HOST_SUPPORTS_SHA3),11) +CFLAGS += -march=armv8.4-a+sha3 +endif +endif # aarch64 + +# AArch64 Big Endian CFLAGS configuration +ifeq ($(ARCH),aarch64_be) +CFLAGS += -DMLD_FORCE_AARCH64_EB +endif # aarch64_be + +# RISC-V 64-bit CFLAGS configuration +ifeq ($(ARCH),riscv64) +CFLAGS += -DMLD_FORCE_RISCV64 +CFLAGS += -march=rv64gcv +endif # riscv64 + +# RISC-V 32-bit CFLAGS configuration +ifeq ($(ARCH),riscv32) +CFLAGS += -DMLD_FORCE_RISCV32 +endif # riscv32 + +# PowerPC 64-bit Little Endian CFLAGS configuration +ifeq ($(ARCH),powerpc64le) +CFLAGS += -DMLD_FORCE_PPC64LE +endif # powerpc64le + +endif # AUTO=1 + +endif # _AUTO_MK diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/expected_signatures.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/expected_signatures.h new file mode 100644 index 0000000000..582c6309d4 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/expected_signatures.h @@ -0,0 +1,886 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef EXPECTED_SIGNATURES_H +#define EXPECTED_SIGNATURES_H + +#include + +/* Expected deterministic signatures for each parameter set + * These are generated using the same test message, context, and deterministic + * RNG as used in the basic example. + * + * The PCT modifies the PRNG state, so the KAT tests don't work. + * We run KAT tests only for disabled PCT. */ +#if !defined(MLD_CONFIG_KEYGEN_PCT) +const uint8_t expected_signature_44[] = { + 0x27, 0x5e, 0xbe, 0x2d, 0x23, 0x1a, 0x76, 0xc5, 0xd9, 0x77, 0xcb, 0x62, + 0x25, 0x04, 0xdb, 0x23, 0x31, 0xa9, 0xa8, 0xcd, 0xbc, 0xde, 0xf2, 0x20, + 0xfd, 0xa7, 0xb5, 0xf5, 0x59, 0xae, 0xe6, 0xdd, 0x62, 0xfa, 0x34, 0x96, + 0x4f, 0x1d, 0xcd, 0x84, 0x82, 0xee, 0xc1, 0x74, 0x96, 0x3d, 0x98, 0xd9, + 0x42, 0x9d, 0xd0, 0x77, 0x9c, 0xf9, 0x9e, 0x0e, 0xa7, 0xcb, 0x70, 0xeb, + 0xe7, 0xcd, 0xce, 0x8c, 0xdc, 0x37, 0x15, 0x95, 0x0e, 0x24, 0x70, 0x4f, + 0x33, 0x6e, 0x4f, 0xad, 0xed, 0x4d, 0xf3, 0xe5, 0x38, 0xc1, 0xcd, 0xbb, + 0xde, 0xf1, 0xd2, 0x0d, 0xd6, 0x6b, 0xa3, 0x68, 0x92, 0x4c, 0x4b, 0x4f, + 0x89, 0xa0, 0xa8, 0xc8, 0x36, 0x93, 0x91, 0x17, 0xe7, 0x16, 0xed, 0xcb, + 0xdc, 0xf6, 0x28, 0x13, 0x32, 0x60, 0x14, 0xe0, 0x28, 0x7a, 0x69, 0x05, + 0x1d, 0xf7, 0x3b, 0xdf, 0x18, 0x0c, 0xaf, 0xba, 0x46, 0xf1, 0x5e, 0xd4, + 0xd3, 0xd0, 0x8e, 0x9a, 0xe2, 0xac, 0xdd, 0x0e, 0x5f, 0xb1, 0x69, 0xe2, + 0x74, 0x77, 0x2e, 0x52, 0xf9, 0x11, 0x3d, 0xd8, 0xe5, 0x36, 0x6f, 0x7d, + 0x7d, 0xde, 0x7c, 0xa7, 0x1d, 0x37, 0xdf, 0x6d, 0x5e, 0xea, 0xc8, 0xc0, + 0x72, 0x3f, 0x79, 0xbd, 0x0b, 0x6d, 0x7f, 0x9a, 0x15, 0x90, 0xda, 0xc1, + 0xae, 0xce, 0xf3, 0x44, 0x35, 0x5e, 0x83, 0x86, 0x7e, 0x89, 0x18, 0xa7, + 0x97, 0x8e, 0x87, 0x7c, 0x15, 0xd2, 0xd2, 0x7e, 0xf2, 0xc8, 0x29, 0x4f, + 0x70, 0x0f, 0xa6, 0xd4, 0x76, 0xe8, 0xdd, 0x7d, 0x7a, 0x2d, 0xfe, 0x0a, + 0x0c, 0x5c, 0xb1, 0xef, 0xec, 0x1a, 0x32, 0xca, 0x87, 0xff, 0x6b, 0xb1, + 0xa0, 0xe1, 0x2e, 0x01, 0x52, 0xb2, 0xb8, 0x74, 0x34, 0xb3, 0xfb, 0x15, + 0x0f, 0x17, 0xca, 0x74, 0xc1, 0xc1, 0x61, 0x86, 0x40, 0x38, 0x58, 0xba, + 0x82, 0x26, 0x66, 0x33, 0xa4, 0x52, 0xf3, 0xb5, 0x36, 0x60, 0xd8, 0x5a, + 0x8d, 0x9d, 0x28, 0x18, 0x3a, 0x68, 0x34, 0x2a, 0xa2, 0xe2, 0xb5, 0x39, + 0xed, 0x7d, 0xe5, 0xbe, 0x46, 0xb9, 0x04, 0x0c, 0xf3, 0xef, 0x88, 0x6e, + 0x9d, 0x6f, 0x23, 0xe2, 0x44, 0xe5, 0x2e, 0x3a, 0x7a, 0x1d, 0x49, 0x0f, + 0xdd, 0xcd, 0xd6, 0x4e, 0x0d, 0x0b, 0xc3, 0x35, 0xf2, 0xd1, 0x5d, 0x73, + 0x5d, 0x07, 0xca, 0x5c, 0xbd, 0x14, 0xec, 0x57, 0xb3, 0xbd, 0x37, 0xe7, + 0xdf, 0x06, 0x7d, 0xe0, 0x58, 0x4a, 0xcf, 0x7a, 0xc5, 0xa7, 0x24, 0x62, + 0x6f, 0x09, 0x75, 0x69, 0x74, 0x7f, 0xdf, 0xc8, 0x69, 0x5c, 0x20, 0x10, + 0x3a, 0xe8, 0x01, 0x12, 0xa3, 0xfb, 0xda, 0x4c, 0x3a, 0x0d, 0x3c, 0x3e, + 0x26, 0xe0, 0xa6, 0x7f, 0xb2, 0x6b, 0x0b, 0x68, 0x0a, 0x68, 0x86, 0xb1, + 0xfa, 0x61, 0x3a, 0xe8, 0x77, 0xdc, 0x42, 0xf7, 0xf4, 0x39, 0x9a, 0x40, + 0x58, 0x71, 0xc7, 0x0f, 0xf4, 0x0e, 0xc5, 0x1e, 0xe0, 0x28, 0x45, 0x7d, + 0xba, 0x84, 0xe4, 0x34, 0x69, 0xf9, 0xa5, 0x8a, 0x80, 0x43, 0xc0, 0x8d, + 0x04, 0x33, 0x43, 0xb8, 0xd7, 0x5d, 0x93, 0xed, 0x0f, 0x31, 0x6a, 0x4d, + 0xbf, 0xb7, 0x44, 0x41, 0x1b, 0xd4, 0xac, 0x9d, 0x83, 0x66, 0x08, 0x92, + 0xad, 0x3c, 0x0e, 0x1a, 0xe8, 0xd4, 0xe1, 0x5c, 0x63, 0xcf, 0x27, 0x48, + 0x5a, 0x8f, 0xc5, 0x6f, 0x83, 0x6b, 0x6f, 0xe8, 0xda, 0x1f, 0xba, 0xe9, + 0x7e, 0x11, 0xab, 0x8b, 0x4e, 0xc1, 0x9e, 0x23, 0x69, 0x1f, 0x42, 0x40, + 0xad, 0xbb, 0xfb, 0x4f, 0xe2, 0x50, 0xc9, 0x46, 0xe7, 0x15, 0x15, 0xf8, + 0x61, 0x09, 0x2a, 0x0b, 0x37, 0x43, 0xd4, 0x98, 0x5f, 0xc8, 0x4d, 0x06, + 0xe7, 0x0c, 0x3f, 0x83, 0x59, 0xd5, 0xcd, 0x2d, 0xde, 0x1e, 0x3a, 0x87, + 0x4e, 0xf7, 0x0a, 0x3c, 0x84, 0x72, 0x47, 0x11, 0x02, 0x6c, 0xe8, 0x93, + 0xcd, 0x24, 0xe9, 0x23, 0x86, 0x78, 0x53, 0xe0, 0xc6, 0x2f, 0xba, 0xa7, + 0xed, 0xaf, 0xba, 0x42, 0x80, 0x0d, 0xe6, 0xae, 0xda, 0xed, 0xbc, 0x65, + 0x21, 0x6d, 0x13, 0x90, 0x61, 0xb4, 0x05, 0x7b, 0x07, 0x86, 0xd7, 0x89, + 0x30, 0x9c, 0xc1, 0x9a, 0x41, 0x4d, 0xe8, 0x2b, 0x35, 0x21, 0x3a, 0x8a, + 0x60, 0x83, 0x1a, 0x97, 0x10, 0x98, 0xb6, 0xe1, 0x6b, 0xb5, 0xb1, 0xa1, + 0x36, 0x34, 0x60, 0x1b, 0x96, 0x5d, 0x1f, 0x2a, 0xd8, 0xf2, 0x94, 0xdd, + 0x58, 0x3d, 0x0f, 0xbe, 0x9d, 0xfc, 0xf5, 0x24, 0xb1, 0xd2, 0xc3, 0x36, + 0xef, 0xdb, 0x8e, 0x97, 0x3c, 0x9a, 0x4f, 0x48, 0xe3, 0x84, 0x91, 0xd8, + 0x39, 0x91, 0xf6, 0x55, 0xeb, 0x62, 0x51, 0x3d, 0x8f, 0x55, 0x60, 0x5e, + 0x00, 0xe0, 0xd2, 0xc7, 0x66, 0x51, 0xf1, 0xe2, 0xb7, 0x43, 0xc3, 0xe6, + 0x12, 0x9a, 0xe5, 0x84, 0xe0, 0x10, 0x76, 0xc7, 0x75, 0x6e, 0xa6, 0xee, + 0x11, 0xe4, 0xaf, 0xbd, 0x8a, 0x4f, 0x1d, 0x05, 0x29, 0x4f, 0xce, 0xa5, + 0x73, 0x92, 0x57, 0x7e, 0x0d, 0x11, 0xbc, 0xf8, 0x74, 0x4d, 0xf7, 0xb9, + 0x40, 0x0d, 0x5a, 0xa1, 0x19, 0x76, 0x4a, 0xae, 0x21, 0x16, 0xd4, 0x3f, + 0x76, 0xbf, 0x27, 0xbd, 0x2f, 0xe4, 0x25, 0x21, 0x00, 0x4e, 0xcc, 0x7c, + 0xc6, 0x57, 0xa4, 0xbf, 0xf1, 0x56, 0x90, 0xe0, 0xa4, 0xa3, 0xee, 0xcf, + 0x43, 0x4f, 0xda, 0x77, 0x47, 0x51, 0x79, 0x6a, 0x29, 0xb4, 0x2c, 0xdf, + 0xca, 0x47, 0xcb, 0xb8, 0x82, 0x7e, 0x44, 0x62, 0x9b, 0x8f, 0x61, 0x7b, + 0x3a, 0x93, 0x82, 0x1f, 0x69, 0xb7, 0xb1, 0xa6, 0x2c, 0xe1, 0xb2, 0x65, + 0xa0, 0x6d, 0x6f, 0xe4, 0x79, 0xd8, 0x30, 0xe0, 0xee, 0xd8, 0x83, 0x01, + 0xb2, 0x1f, 0x5c, 0x90, 0x44, 0x86, 0x48, 0x11, 0xf9, 0x11, 0xff, 0xea, + 0x45, 0x43, 0xae, 0x8a, 0x6b, 0x99, 0xf2, 0x1f, 0x02, 0x51, 0x4a, 0x35, + 0x02, 0x34, 0xd3, 0xe8, 0xda, 0xb1, 0x4b, 0xe3, 0xa5, 0x60, 0xce, 0x67, + 0xe3, 0x62, 0x59, 0xfc, 0x00, 0x0a, 0xe2, 0xfe, 0x7b, 0x1e, 0xe6, 0xf5, + 0x75, 0x19, 0x9b, 0x5e, 0xcb, 0xe6, 0xf5, 0x80, 0x9e, 0x3c, 0xb8, 0x54, + 0xd6, 0x0b, 0xfd, 0x48, 0xe0, 0xfa, 0x82, 0x2b, 0x5b, 0x26, 0xf9, 0x49, + 0xaf, 0xbe, 0x9c, 0x78, 0x73, 0xce, 0xc5, 0x65, 0xe2, 0x94, 0x2b, 0xd9, + 0xd0, 0x27, 0x3a, 0x66, 0x3e, 0xe2, 0xe0, 0x10, 0x79, 0x3d, 0xde, 0xc8, + 0x47, 0xdb, 0x1e, 0xc3, 0xe7, 0x51, 0xae, 0x59, 0xeb, 0x38, 0x66, 0x63, + 0x40, 0x8f, 0xbe, 0x1e, 0xb2, 0x2b, 0xeb, 0x64, 0x5f, 0xdd, 0x24, 0xc4, + 0x5a, 0x25, 0x59, 0xa2, 0xda, 0x4f, 0xdf, 0xf8, 0xb0, 0xb0, 0xf7, 0xcd, + 0x1f, 0x14, 0xcd, 0x09, 0x48, 0x70, 0x27, 0x1b, 0xde, 0xc4, 0xf0, 0xf3, + 0x56, 0x97, 0x8a, 0xb7, 0xf4, 0x19, 0x76, 0xe3, 0x9a, 0x33, 0x55, 0xfe, + 0x93, 0x68, 0xca, 0x1f, 0x3d, 0x44, 0x86, 0x39, 0x5d, 0x84, 0x58, 0x50, + 0xf2, 0xf1, 0xea, 0x4a, 0x5c, 0x1c, 0x74, 0xf0, 0x4b, 0xa5, 0x9c, 0x30, + 0xa0, 0x14, 0x1a, 0x80, 0xe0, 0xde, 0x3e, 0xae, 0x7f, 0x10, 0x18, 0x4a, + 0x1e, 0x9e, 0x6b, 0x75, 0x1a, 0xca, 0x08, 0x4e, 0x61, 0x72, 0x43, 0x9b, + 0x18, 0x4d, 0x2c, 0xd8, 0xb4, 0xc9, 0xea, 0x00, 0xb0, 0xdf, 0x1b, 0xcb, + 0x03, 0xc3, 0x7a, 0x27, 0xff, 0x41, 0x9d, 0xf9, 0xfd, 0xb3, 0x0c, 0xc0, + 0x48, 0x5d, 0x7c, 0xae, 0x5a, 0x72, 0x69, 0x93, 0x68, 0xe1, 0x9e, 0x9f, + 0x1f, 0x5c, 0x0a, 0x60, 0x90, 0x1a, 0x8e, 0x5a, 0x30, 0xd4, 0x2c, 0xbd, + 0xe1, 0x20, 0x51, 0xbc, 0x1c, 0x50, 0xb5, 0xf7, 0x42, 0x23, 0x35, 0x0f, + 0x92, 0xe2, 0xbb, 0x2a, 0x04, 0xa7, 0xde, 0x2e, 0x25, 0xfa, 0xed, 0x20, + 0x83, 0x9c, 0xd4, 0x56, 0xe0, 0x4d, 0x8d, 0x79, 0xa5, 0xa0, 0x6f, 0x49, + 0x62, 0x82, 0x9a, 0xa7, 0x4e, 0x54, 0x95, 0x0a, 0xc6, 0x5e, 0x27, 0x65, + 0x6d, 0x11, 0x2b, 0x35, 0x72, 0x34, 0x48, 0xd2, 0xe4, 0x9e, 0x07, 0x7d, + 0x03, 0x27, 0x15, 0x93, 0x55, 0x5c, 0x32, 0x43, 0xdb, 0x34, 0x8d, 0xbd, + 0x8d, 0x88, 0xa5, 0x24, 0x07, 0x93, 0x89, 0x37, 0xb9, 0x17, 0x15, 0xad, + 0xc7, 0x68, 0x86, 0x63, 0x0f, 0x10, 0x53, 0x8f, 0x40, 0xd3, 0x7b, 0x22, + 0x2b, 0x1a, 0x4c, 0xcb, 0x4f, 0x51, 0xf1, 0x3b, 0x19, 0xb8, 0x42, 0x53, + 0xaf, 0xf6, 0xb9, 0x57, 0x7f, 0xba, 0x8d, 0xb8, 0xb7, 0x3b, 0xe3, 0xc5, + 0xab, 0x4a, 0x26, 0x21, 0x6e, 0xce, 0x27, 0xb8, 0xc3, 0x99, 0x56, 0x14, + 0xdd, 0x5b, 0x61, 0x82, 0xbf, 0xd3, 0xc8, 0x76, 0xee, 0x22, 0xaf, 0x21, + 0x21, 0x1d, 0x4e, 0x33, 0xb5, 0x43, 0x3a, 0xfb, 0x91, 0xa0, 0xaa, 0xe3, + 0x10, 0x4a, 0x50, 0x42, 0xd4, 0x5f, 0x92, 0x0e, 0x71, 0x60, 0x4f, 0xaa, + 0xef, 0x66, 0x45, 0xfe, 0xf7, 0xc8, 0xb0, 0x73, 0x75, 0x91, 0x0b, 0x86, + 0x40, 0xa5, 0x02, 0x28, 0xf7, 0xe0, 0x1f, 0x5d, 0xe6, 0xe3, 0xa4, 0x57, + 0xbd, 0x29, 0xaa, 0x53, 0xae, 0x35, 0x30, 0x78, 0x73, 0xd6, 0xb7, 0x01, + 0x9d, 0x13, 0x50, 0xf6, 0x39, 0xa2, 0x3e, 0x03, 0x04, 0xaa, 0x6d, 0xcf, + 0x6b, 0xff, 0x9a, 0xbe, 0x3e, 0x0a, 0xd4, 0x20, 0xce, 0x42, 0x1f, 0xca, + 0x2f, 0xd3, 0x2c, 0xd1, 0xf4, 0xd2, 0x50, 0xd3, 0xa2, 0xc1, 0x1e, 0x87, + 0xbf, 0xeb, 0xb8, 0xa8, 0xd4, 0x1c, 0x96, 0xb8, 0x8e, 0xbe, 0x35, 0x5f, + 0x08, 0x28, 0x20, 0x2b, 0xdc, 0xa4, 0xf5, 0xf6, 0xde, 0xca, 0x1e, 0xcb, + 0x93, 0x3b, 0x64, 0x79, 0x00, 0x3c, 0x8d, 0xbb, 0x5c, 0x7a, 0x40, 0x14, + 0x58, 0x12, 0xa4, 0xf7, 0x6e, 0x51, 0xfb, 0xe7, 0x6f, 0x49, 0x5b, 0xc2, + 0xc9, 0x05, 0x38, 0x9c, 0x08, 0x78, 0x71, 0x27, 0x2b, 0xf5, 0xbf, 0xd6, + 0x38, 0xaa, 0x45, 0xe1, 0xe1, 0x4c, 0xfb, 0xfd, 0xb7, 0xe6, 0xcf, 0xad, + 0x9e, 0x56, 0xaf, 0x12, 0x12, 0x98, 0xe6, 0x38, 0xaa, 0xee, 0xdb, 0x9e, + 0xca, 0xe1, 0x79, 0x6d, 0x44, 0xfb, 0x19, 0x50, 0x92, 0x00, 0x06, 0x2c, + 0x24, 0x71, 0x6c, 0x34, 0x45, 0xac, 0xf9, 0x82, 0x66, 0xa8, 0x63, 0x80, + 0xa8, 0x5b, 0x21, 0x3c, 0x36, 0x71, 0x93, 0x40, 0x7b, 0xff, 0xa2, 0xd0, + 0x72, 0xb4, 0x66, 0xfa, 0xfc, 0xa0, 0xee, 0xca, 0x15, 0x73, 0x52, 0xe7, + 0x9d, 0x11, 0xd3, 0xbc, 0xab, 0x37, 0x31, 0x0e, 0xaf, 0xdc, 0x05, 0x30, + 0x79, 0x8c, 0x25, 0x75, 0x5c, 0x60, 0xc7, 0x9a, 0xfc, 0x88, 0xea, 0xe6, + 0x09, 0x9f, 0xd1, 0x4f, 0x13, 0xf4, 0x41, 0x54, 0x5b, 0x7a, 0xe4, 0x49, + 0x3c, 0x0f, 0x15, 0xe9, 0xa4, 0x85, 0xb2, 0x92, 0x07, 0xea, 0xea, 0x7c, + 0xc1, 0x6d, 0xa9, 0x03, 0xb3, 0x31, 0xce, 0x1e, 0x82, 0xca, 0x9e, 0x3c, + 0x88, 0x88, 0xc1, 0x04, 0x5f, 0xbe, 0xd5, 0x94, 0x0d, 0x67, 0x98, 0x27, + 0xd0, 0x0f, 0x43, 0xf3, 0xb3, 0xfc, 0xff, 0x24, 0xa2, 0x1e, 0x17, 0x06, + 0xb0, 0x52, 0x16, 0x7c, 0xd8, 0x49, 0x74, 0x51, 0xcf, 0x2d, 0x36, 0x16, + 0xb0, 0x88, 0xb2, 0x2b, 0x1d, 0x72, 0x70, 0xab, 0xe2, 0xf6, 0x5f, 0xa5, + 0x2d, 0x4e, 0xd1, 0x42, 0x3c, 0x83, 0x84, 0xb2, 0x56, 0xeb, 0x8d, 0xce, + 0x33, 0x46, 0xdb, 0x3d, 0x4f, 0x97, 0xea, 0x37, 0x5e, 0x0d, 0xd7, 0x4c, + 0x9a, 0x7e, 0xc9, 0x0e, 0x69, 0x4d, 0x97, 0x15, 0x1e, 0x09, 0xbe, 0x7e, + 0xff, 0xe8, 0xf5, 0xab, 0xe9, 0xe7, 0xed, 0x4b, 0x41, 0xa5, 0xf2, 0x2a, + 0x24, 0x48, 0x8b, 0x72, 0x4b, 0x9d, 0xcf, 0x45, 0xdb, 0xc0, 0xaf, 0xa8, + 0x0f, 0x0f, 0x67, 0x37, 0xd3, 0x8b, 0xe1, 0x67, 0x90, 0xd8, 0x1c, 0x58, + 0x36, 0x46, 0x51, 0x52, 0xea, 0xb4, 0x75, 0xb1, 0xcd, 0xc5, 0x39, 0x16, + 0xe0, 0xec, 0x16, 0xf7, 0xf8, 0x0f, 0x5d, 0x13, 0x84, 0x62, 0x34, 0x86, + 0x42, 0x05, 0xa8, 0x08, 0x84, 0xa9, 0x77, 0x12, 0xc1, 0x56, 0xdd, 0x28, + 0xde, 0x39, 0x33, 0x21, 0x3d, 0xbd, 0x94, 0xce, 0xe4, 0xb3, 0x17, 0x9b, + 0x09, 0x20, 0xf0, 0x25, 0xce, 0x00, 0x34, 0x8e, 0x12, 0x94, 0x74, 0x0b, + 0x16, 0xa1, 0x60, 0x76, 0x24, 0xf0, 0xbf, 0xe3, 0x3a, 0x83, 0x8f, 0x40, + 0x47, 0x2e, 0x1c, 0xd5, 0x35, 0x25, 0x87, 0xb3, 0x11, 0xdc, 0x98, 0xb0, + 0xa6, 0x5f, 0x6a, 0x05, 0x1d, 0x06, 0x8d, 0xe8, 0xb0, 0x98, 0xf0, 0x43, + 0x29, 0x84, 0xe4, 0xef, 0x34, 0x67, 0x74, 0x64, 0xe8, 0xb8, 0xf0, 0xd4, + 0x9e, 0xc1, 0x3f, 0x5f, 0xeb, 0xe0, 0x9b, 0x37, 0xf8, 0x75, 0x46, 0x47, + 0xa5, 0x3e, 0x42, 0x20, 0x50, 0xc4, 0x5d, 0xf3, 0xdf, 0x4e, 0xf8, 0x0e, + 0x1e, 0x15, 0x10, 0x3e, 0xf1, 0x68, 0xad, 0x87, 0xad, 0xe5, 0x45, 0x5e, + 0x22, 0xba, 0x2e, 0x51, 0xa0, 0xbf, 0xdc, 0x87, 0xca, 0xe4, 0x1f, 0x2f, + 0x2c, 0xae, 0xa9, 0x14, 0xd7, 0xdd, 0x01, 0xa8, 0x4f, 0x43, 0xcb, 0x84, + 0x92, 0xbf, 0xf9, 0x3d, 0xf0, 0x6b, 0x19, 0x43, 0xb0, 0xdf, 0xff, 0x94, + 0x76, 0xe2, 0x84, 0xf9, 0x31, 0x88, 0x7e, 0xc6, 0x87, 0x58, 0xbe, 0x5d, + 0x8b, 0xf8, 0xb5, 0xdc, 0x95, 0x16, 0x5f, 0xa1, 0x2c, 0xe8, 0x53, 0x36, + 0x64, 0xf5, 0x5d, 0xa0, 0x74, 0x12, 0x78, 0x59, 0x73, 0x69, 0x5a, 0x2b, + 0x36, 0x4a, 0xff, 0x5b, 0xef, 0x49, 0x2c, 0xb2, 0x9e, 0x59, 0xf0, 0x39, + 0x56, 0xe1, 0xd0, 0x1a, 0x05, 0xb2, 0x7c, 0xd1, 0x40, 0x09, 0xdf, 0x00, + 0xc9, 0x15, 0x53, 0xa2, 0xda, 0x84, 0xb5, 0x85, 0x05, 0x76, 0xa6, 0x1b, + 0xcb, 0x06, 0xb2, 0xc8, 0xa0, 0xc5, 0x23, 0x8f, 0xb0, 0xe8, 0xf5, 0xd9, + 0xd0, 0x19, 0x29, 0xfe, 0x2d, 0x9a, 0x57, 0x76, 0x5f, 0xf2, 0xef, 0x71, + 0x16, 0xee, 0x28, 0x7b, 0xe4, 0x48, 0xeb, 0xda, 0xe0, 0xd5, 0xbc, 0x0e, + 0x46, 0x6b, 0x06, 0x5d, 0xe5, 0x91, 0x2d, 0xcb, 0xc4, 0x53, 0xa6, 0x16, + 0xd5, 0xe7, 0xd8, 0xf1, 0xdd, 0x4f, 0xbb, 0xcc, 0x55, 0x67, 0x19, 0x98, + 0x94, 0x95, 0x5e, 0xd6, 0xf5, 0xf7, 0xe8, 0x6a, 0xf7, 0x20, 0x86, 0x3a, + 0x43, 0xbf, 0xe9, 0xec, 0x6b, 0x33, 0x49, 0x19, 0x43, 0xfb, 0xeb, 0x3f, + 0xf4, 0x9d, 0x29, 0x66, 0xb9, 0x6e, 0xb5, 0x15, 0x4b, 0x8d, 0x3c, 0x3c, + 0xfa, 0xf2, 0x87, 0xba, 0x61, 0x11, 0x40, 0xe6, 0xb4, 0x6f, 0xf5, 0xe1, + 0x24, 0x32, 0x69, 0x3e, 0xff, 0xf7, 0xbc, 0xee, 0x82, 0xf2, 0x9e, 0x6d, + 0x3f, 0x6c, 0xcc, 0x0f, 0x4f, 0xc3, 0xf1, 0xdb, 0x1e, 0x81, 0xd7, 0x9b, + 0x22, 0xa8, 0xa7, 0x36, 0x6d, 0xa9, 0x6f, 0x46, 0x1a, 0xa7, 0xff, 0x00, + 0x4b, 0xd8, 0xab, 0xe7, 0x50, 0x3b, 0xe9, 0xc0, 0x57, 0xec, 0x8d, 0x0c, + 0xa0, 0xee, 0x8c, 0x2a, 0x74, 0xf2, 0x94, 0xf9, 0x0c, 0x20, 0x14, 0xd9, + 0xad, 0x0d, 0x4e, 0xac, 0x35, 0x44, 0x59, 0x28, 0x24, 0x31, 0x32, 0xaa, + 0x6d, 0xc2, 0x13, 0xb9, 0xee, 0x75, 0x0c, 0x5f, 0x39, 0xef, 0x31, 0xca, + 0x28, 0x48, 0x56, 0x59, 0xfb, 0xa8, 0xd8, 0x2b, 0x70, 0x61, 0x22, 0x43, + 0x43, 0xb9, 0x60, 0x44, 0xeb, 0xf8, 0x98, 0x87, 0x25, 0x84, 0xa2, 0xaa, + 0x37, 0xd4, 0xb8, 0xd6, 0x3d, 0xa3, 0xa1, 0x4a, 0x81, 0xc2, 0xa9, 0xea, + 0xa2, 0xd6, 0x63, 0x76, 0x50, 0xeb, 0xcd, 0x19, 0x40, 0xb1, 0x7c, 0xf6, + 0xc1, 0x44, 0x01, 0x25, 0xe0, 0xdd, 0xb8, 0x39, 0xef, 0x46, 0x3d, 0x50, + 0x33, 0xed, 0xb1, 0x63, 0x65, 0xd7, 0x50, 0xe7, 0x95, 0xba, 0xab, 0xa7, + 0x14, 0xe5, 0x60, 0xcb, 0x81, 0x6e, 0x88, 0x3c, 0x06, 0x6e, 0x7d, 0x8e, + 0xe7, 0xbb, 0xa5, 0xc2, 0xbd, 0xae, 0x46, 0x8f, 0x43, 0x04, 0x29, 0xe6, + 0x17, 0x38, 0x05, 0x2d, 0x97, 0x93, 0x5b, 0xf9, 0xef, 0x4d, 0x2e, 0x75, + 0x6c, 0x69, 0xba, 0x08, 0xf2, 0x21, 0x1e, 0x21, 0xe6, 0x8a, 0x5b, 0x8c, + 0xd4, 0x8e, 0xde, 0x64, 0x9b, 0x9d, 0x54, 0x58, 0x65, 0x3e, 0xdd, 0x8a, + 0x1e, 0x81, 0x4e, 0x45, 0xe8, 0xfb, 0x20, 0xc3, 0x3a, 0xf0, 0x50, 0x1e, + 0x8a, 0x18, 0xea, 0x2b, 0xf5, 0xe1, 0xa6, 0xb6, 0xc8, 0xa0, 0x02, 0x3d, + 0x6e, 0xfa, 0x0b, 0x51, 0x95, 0x4e, 0x4c, 0x11, 0xb0, 0xc4, 0x62, 0x58, + 0xa6, 0x9c, 0x13, 0x4e, 0xbe, 0xc9, 0x29, 0x93, 0x29, 0x15, 0x5f, 0xaf, + 0x0e, 0xc3, 0xb3, 0x26, 0x3f, 0xdc, 0x4c, 0x33, 0xb8, 0x4b, 0x11, 0xae, + 0x1f, 0xd7, 0x05, 0x39, 0xcf, 0xfe, 0xc3, 0x6d, 0xf0, 0xc0, 0x77, 0x02, + 0xb8, 0x9b, 0x3d, 0x1b, 0x3d, 0x72, 0xfe, 0x7e, 0x18, 0x60, 0x9b, 0xc4, + 0x8b, 0xac, 0x25, 0x6d, 0x3b, 0x80, 0x34, 0xbc, 0x51, 0xaf, 0xf6, 0xff, + 0x66, 0x98, 0x86, 0x6e, 0x9e, 0x9a, 0xfe, 0x6d, 0x21, 0x4d, 0xf1, 0x58, + 0x3e, 0x3e, 0x43, 0xe3, 0x7e, 0x40, 0xb0, 0xb3, 0xd8, 0x12, 0xa5, 0xce, + 0x09, 0x41, 0x8c, 0x1d, 0x73, 0xcd, 0xfc, 0x63, 0xed, 0xeb, 0x08, 0x1e, + 0x34, 0xfb, 0xed, 0x75, 0xb7, 0x86, 0x84, 0x7c, 0x80, 0xe9, 0xe4, 0xa3, + 0x1c, 0x4a, 0x0d, 0x11, 0x16, 0x24, 0xb2, 0xb1, 0x99, 0xe5, 0xe3, 0x2e, + 0x2f, 0x70, 0xcd, 0x1e, 0x35, 0x14, 0x79, 0xba, 0xa2, 0x51, 0x7a, 0x29, + 0x5c, 0x75, 0x8f, 0xdd, 0x22, 0xdf, 0xb2, 0x64, 0xd9, 0x95, 0x11, 0x33, + 0x97, 0xee, 0x69, 0x42, 0x01, 0x96, 0x98, 0x1b, 0x43, 0xc2, 0xec, 0xf9, + 0xb0, 0xdb, 0x69, 0x34, 0xab, 0x98, 0x1b, 0xb2, 0x04, 0x05, 0x14, 0x1d, + 0x25, 0x2f, 0x32, 0x41, 0x50, 0x51, 0x55, 0x62, 0x6d, 0x78, 0x7f, 0x8b, + 0xbb, 0xc2, 0xcd, 0xcf, 0xe4, 0xed, 0x04, 0x1f, 0x25, 0x30, 0x43, 0x64, + 0x69, 0x7c, 0x87, 0xa3, 0xa9, 0xb1, 0xc1, 0xd1, 0xdc, 0x01, 0x10, 0x1d, + 0x27, 0x3f, 0x5c, 0x5d, 0x75, 0x82, 0x9b, 0xaa, 0xb3, 0xe8, 0x0c, 0x11, + 0x1f, 0x24, 0x38, 0x41, 0x45, 0x54, 0x5f, 0x69, 0x85, 0x8d, 0x93, 0x9e, + 0xc5, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x25, 0x32, 0x42}; +const uint8_t expected_signature_65[] = { + 0x8b, 0x6f, 0x79, 0x00, 0xcc, 0x79, 0x57, 0xee, 0x16, 0x86, 0x87, 0xd5, + 0xcf, 0xb6, 0x90, 0x2c, 0xc6, 0x30, 0xeb, 0x8d, 0x39, 0xae, 0x9b, 0xf1, + 0x66, 0xe0, 0xd6, 0x93, 0xa5, 0x4e, 0x26, 0x9b, 0x96, 0x8f, 0xd1, 0x46, + 0x97, 0xbe, 0x71, 0x1c, 0xf3, 0xa5, 0xe5, 0xae, 0x8d, 0x4b, 0xf2, 0xe6, + 0x48, 0x8f, 0xe9, 0x5e, 0x07, 0xef, 0xe4, 0xbb, 0x39, 0xc1, 0xc9, 0x3c, + 0xc3, 0x0b, 0xfb, 0x2a, 0x29, 0x06, 0xfe, 0x01, 0xcb, 0x63, 0x83, 0x10, + 0xa8, 0xc8, 0xa0, 0x29, 0xa5, 0x80, 0xeb, 0xbd, 0xa9, 0xd9, 0x0b, 0x61, + 0xbc, 0xce, 0x11, 0x55, 0x66, 0x12, 0xc7, 0x5b, 0xd2, 0x7a, 0x5a, 0xc8, + 0xab, 0xab, 0xbf, 0x3a, 0x1f, 0x96, 0x1a, 0x70, 0xcb, 0x41, 0x5f, 0xc8, + 0xb7, 0x09, 0x22, 0x98, 0x9b, 0xb8, 0xf7, 0x2d, 0x49, 0x65, 0x1d, 0x09, + 0x8b, 0x70, 0xb5, 0x42, 0xc9, 0x89, 0x5b, 0x74, 0xb4, 0x28, 0x82, 0x01, + 0x53, 0x12, 0x3e, 0x23, 0xf6, 0x54, 0xf8, 0x51, 0x12, 0x4b, 0x02, 0x3a, + 0x7e, 0xb6, 0x1f, 0xac, 0xa0, 0xe6, 0x6f, 0xf8, 0x61, 0x82, 0xe4, 0xfb, + 0x96, 0x2a, 0xd2, 0xaf, 0x3c, 0xea, 0x6e, 0xdc, 0x18, 0x8a, 0x5d, 0x90, + 0xda, 0xa2, 0x5d, 0xa7, 0x8f, 0x5b, 0x50, 0x46, 0xaf, 0x8c, 0x17, 0x6a, + 0x4c, 0x39, 0xfc, 0x31, 0x4c, 0x4b, 0xc2, 0x57, 0x66, 0x61, 0x98, 0xbf, + 0xe6, 0xfb, 0x54, 0x96, 0xd3, 0x70, 0xb8, 0xaf, 0xcd, 0x8b, 0xcc, 0x00, + 0x07, 0x92, 0x15, 0xc2, 0xbb, 0x48, 0xbb, 0xc6, 0xb7, 0xb5, 0x58, 0x8c, + 0xfc, 0xf0, 0xda, 0x6a, 0x0d, 0xf7, 0x1d, 0x7d, 0xc6, 0x27, 0x26, 0x1a, + 0x99, 0xc5, 0x2f, 0xf8, 0x97, 0x65, 0x43, 0x86, 0xd6, 0x25, 0x23, 0x2b, + 0x06, 0x8f, 0x12, 0xa1, 0xae, 0xbb, 0x58, 0x34, 0x25, 0xec, 0x5b, 0x68, + 0xa4, 0xe1, 0x03, 0xfc, 0x26, 0xa2, 0xd6, 0x2b, 0x61, 0x10, 0x47, 0xbd, + 0x16, 0xe5, 0xca, 0x4a, 0xce, 0xed, 0x89, 0x09, 0x1a, 0xed, 0x22, 0xc1, + 0xca, 0x44, 0xe3, 0xef, 0x72, 0x34, 0xab, 0xab, 0x61, 0x5c, 0x9f, 0x5f, + 0xb5, 0xf5, 0xe8, 0x2d, 0x89, 0xea, 0x4b, 0x40, 0x65, 0x57, 0x8b, 0xa2, + 0x95, 0x40, 0x9c, 0x72, 0xc0, 0x46, 0x69, 0x45, 0x06, 0xf6, 0x07, 0x5b, + 0x2d, 0xa5, 0x46, 0xca, 0x5d, 0xfb, 0x40, 0xb7, 0x48, 0x59, 0x5b, 0xe2, + 0x1b, 0x38, 0xb2, 0x15, 0x75, 0x66, 0x67, 0x58, 0x00, 0x3f, 0xde, 0x8a, + 0x63, 0x13, 0x34, 0x6a, 0x30, 0xca, 0xb4, 0xd5, 0x3e, 0xe0, 0x6d, 0x14, + 0xb8, 0x9a, 0x48, 0xef, 0xfd, 0xbd, 0x6d, 0x20, 0x11, 0x4d, 0x25, 0xe5, + 0xab, 0x15, 0x8d, 0xe5, 0x91, 0xbc, 0xc6, 0x69, 0x8a, 0xf8, 0xab, 0x3a, + 0x82, 0xae, 0xc5, 0x03, 0x2c, 0xcf, 0x54, 0xdc, 0xcd, 0xe8, 0x49, 0x53, + 0xb5, 0xd8, 0xc2, 0x24, 0xf8, 0x8c, 0x38, 0x8f, 0xe3, 0xfe, 0x3a, 0x18, + 0x15, 0xa8, 0xda, 0x77, 0xc8, 0x81, 0x72, 0xc6, 0xc1, 0x60, 0xa3, 0x73, + 0x65, 0x68, 0x5c, 0xf3, 0x1d, 0x8d, 0x61, 0x21, 0x65, 0xfb, 0x45, 0xc4, + 0x4c, 0x31, 0x88, 0x25, 0x0d, 0x52, 0x75, 0x3b, 0xec, 0x54, 0xe0, 0xb1, + 0x9c, 0x7c, 0xdf, 0xe3, 0x3b, 0x77, 0x31, 0x33, 0xd7, 0x25, 0x99, 0xff, + 0xc5, 0x40, 0x1e, 0x85, 0x09, 0xfd, 0x2d, 0x24, 0x4a, 0x92, 0xe7, 0x77, + 0x48, 0xa5, 0x46, 0xf4, 0x8e, 0xa3, 0x6b, 0x24, 0xe4, 0x6b, 0x31, 0xf6, + 0xe0, 0x16, 0x49, 0x9b, 0x9f, 0xa3, 0x1a, 0x5c, 0x05, 0x5e, 0x81, 0x62, + 0xc8, 0x14, 0x52, 0xb4, 0x21, 0xfd, 0x76, 0x6d, 0x88, 0xe9, 0x3b, 0x0b, + 0x75, 0x27, 0x92, 0x47, 0x5a, 0x58, 0x08, 0x26, 0xa7, 0xa2, 0x48, 0x1c, + 0x14, 0x3e, 0x5e, 0xdf, 0x81, 0x83, 0x83, 0x3e, 0xc6, 0x72, 0x27, 0xc4, + 0x6a, 0x46, 0x2b, 0xf2, 0x8d, 0x42, 0x11, 0xb9, 0x15, 0xd7, 0xf0, 0x20, + 0x29, 0x53, 0xba, 0xf0, 0x6e, 0x41, 0x3d, 0xee, 0x19, 0xf2, 0x43, 0xf3, + 0x6d, 0x00, 0xe2, 0x43, 0x77, 0xb9, 0xa9, 0x78, 0x34, 0x48, 0x3c, 0x1a, + 0x8b, 0xbd, 0xa1, 0xe5, 0x90, 0x59, 0x5b, 0xd6, 0x1e, 0x22, 0xdf, 0xb2, + 0xa7, 0x96, 0x7d, 0x55, 0x86, 0x66, 0x95, 0xb7, 0x06, 0xe7, 0x60, 0x2a, + 0x01, 0x48, 0x3f, 0xd4, 0xa7, 0xd4, 0xc2, 0x38, 0xa4, 0x10, 0x8e, 0x4f, + 0x97, 0xad, 0xa3, 0xb9, 0xe2, 0xaa, 0x13, 0xb1, 0x16, 0x89, 0x3d, 0x74, + 0x60, 0x94, 0x8c, 0xc3, 0xe6, 0x5f, 0xcf, 0xdc, 0x58, 0x17, 0x98, 0x27, + 0x86, 0xae, 0x2a, 0x0d, 0xe8, 0x33, 0x79, 0xc8, 0xc8, 0x5b, 0x59, 0xb0, + 0xba, 0xac, 0xd3, 0x6e, 0x2d, 0x7b, 0x0b, 0x9a, 0xb5, 0xfd, 0x58, 0x42, + 0xeb, 0x80, 0xf4, 0x6b, 0x9a, 0x2f, 0x19, 0x43, 0x75, 0xb4, 0xcb, 0xc9, + 0xd5, 0x28, 0xf5, 0xb9, 0x67, 0x82, 0xb4, 0xed, 0x8c, 0x3f, 0x3d, 0x6b, + 0x6d, 0x1b, 0x80, 0x13, 0x5c, 0x7b, 0x2e, 0xfa, 0xa0, 0x32, 0xba, 0xb5, + 0x46, 0xd6, 0xe7, 0x90, 0xe9, 0xd1, 0x91, 0xa0, 0xaa, 0x26, 0x35, 0xa2, + 0x0d, 0x98, 0x44, 0x11, 0xae, 0xf9, 0xc5, 0x12, 0x4d, 0x1a, 0x7c, 0x53, + 0xea, 0xf6, 0x05, 0x8d, 0x3a, 0x74, 0x92, 0xc9, 0x65, 0xeb, 0x6f, 0xb5, + 0xb4, 0xd2, 0xcd, 0x5c, 0xec, 0xaf, 0x95, 0xcb, 0xb4, 0x3c, 0x22, 0xca, + 0x1c, 0x06, 0x85, 0x16, 0x96, 0x24, 0x8c, 0x6c, 0x80, 0xf8, 0xb3, 0xa7, + 0x87, 0x77, 0xeb, 0x09, 0x71, 0xc8, 0x95, 0xfb, 0x5e, 0xe5, 0x6f, 0x78, + 0xf9, 0x60, 0xf9, 0x9e, 0x58, 0x7b, 0xbd, 0x47, 0xdd, 0x48, 0x2e, 0x56, + 0xcd, 0x63, 0x72, 0xc9, 0x4b, 0x65, 0x2d, 0x41, 0xe8, 0x81, 0x19, 0x33, + 0x4b, 0xf6, 0x02, 0xc6, 0xcb, 0x2e, 0xdf, 0x3d, 0xc8, 0xdd, 0x2f, 0x0f, + 0x09, 0x67, 0xf0, 0xaa, 0x3c, 0x51, 0xdc, 0x8d, 0xc6, 0xc3, 0xb2, 0x3b, + 0x15, 0x85, 0xcb, 0xeb, 0x62, 0xef, 0xa3, 0xf9, 0x94, 0xf4, 0x35, 0x9c, + 0x59, 0xcc, 0xc2, 0x68, 0xb4, 0xde, 0x02, 0x75, 0x8e, 0xf5, 0x33, 0xca, + 0xd5, 0xc5, 0x24, 0xae, 0xf6, 0xde, 0x2b, 0x01, 0xf4, 0x56, 0xb9, 0xa5, + 0xa7, 0xe0, 0x64, 0x2e, 0xba, 0x1d, 0x53, 0x54, 0x46, 0xcf, 0x64, 0x16, + 0x12, 0xe2, 0xa6, 0xcc, 0x18, 0xb4, 0x77, 0x8b, 0x19, 0x50, 0x43, 0x96, + 0xc8, 0x5d, 0xc3, 0x58, 0xf0, 0xfd, 0x5e, 0x13, 0xa9, 0x10, 0x67, 0xdf, + 0x25, 0xdb, 0xaf, 0x38, 0x5f, 0xbd, 0x35, 0xc1, 0x49, 0x44, 0xe8, 0x1f, + 0x12, 0xa4, 0x7c, 0x28, 0xa3, 0xd6, 0x0d, 0x6f, 0x44, 0xa9, 0x5f, 0xfc, + 0x9f, 0xfa, 0x11, 0x62, 0x87, 0x5b, 0x0e, 0x91, 0xd4, 0xb6, 0xd3, 0x71, + 0xc2, 0x77, 0x19, 0xf6, 0x7c, 0x11, 0x30, 0x5e, 0x5c, 0xd3, 0x1e, 0x90, + 0x05, 0x31, 0x63, 0xbb, 0xef, 0x85, 0xe0, 0x27, 0x94, 0x80, 0xcb, 0x33, + 0xbc, 0x5e, 0x45, 0x87, 0x62, 0xdf, 0xd4, 0x12, 0x2f, 0xf5, 0x41, 0x15, + 0x03, 0x0c, 0x80, 0xe8, 0xe2, 0x06, 0xde, 0x4b, 0x46, 0x70, 0x94, 0xd2, + 0x0d, 0x85, 0x72, 0x27, 0xe5, 0x6c, 0xeb, 0xd2, 0x78, 0x0b, 0x38, 0x40, + 0xe8, 0xdb, 0x47, 0x5c, 0xba, 0xd0, 0x21, 0x33, 0x8f, 0xb8, 0xc0, 0x66, + 0x1e, 0xd1, 0xb0, 0x94, 0xa3, 0x39, 0xc7, 0x87, 0xaf, 0x97, 0x98, 0xce, + 0x6d, 0x03, 0x1a, 0xdb, 0x52, 0x96, 0x0b, 0x9d, 0x5b, 0xf8, 0xa3, 0xf4, + 0x41, 0x95, 0x72, 0xad, 0x0e, 0x98, 0x61, 0x7f, 0xf3, 0x8f, 0x23, 0xeb, + 0xc0, 0xdf, 0xd7, 0x70, 0x26, 0x8c, 0xb3, 0xb3, 0xf0, 0xa2, 0x8a, 0x39, + 0xdd, 0x61, 0xb4, 0x53, 0xe0, 0x2a, 0x6f, 0x91, 0x34, 0x9c, 0x76, 0xf6, + 0x52, 0x93, 0xe6, 0x39, 0xb7, 0x54, 0x07, 0x46, 0x82, 0x2d, 0x05, 0x6d, + 0x9a, 0x00, 0x53, 0x65, 0x68, 0x93, 0x91, 0x00, 0xda, 0xe0, 0x93, 0x34, + 0x60, 0xb1, 0x93, 0x0b, 0x64, 0xa8, 0x12, 0xd2, 0x51, 0x3c, 0xdb, 0xb0, + 0x4c, 0x39, 0x4e, 0xce, 0xbd, 0xf0, 0x65, 0x12, 0x8a, 0xd4, 0x80, 0x7d, + 0x82, 0x85, 0xe4, 0x92, 0xc2, 0x77, 0x1e, 0xcf, 0xd9, 0xab, 0x0f, 0x9b, + 0x32, 0x2e, 0x3f, 0xe1, 0x0e, 0x87, 0x1c, 0x87, 0x34, 0xe7, 0x93, 0x16, + 0x95, 0x09, 0x7d, 0x24, 0xa8, 0xb5, 0xe0, 0x9f, 0x23, 0x87, 0x5c, 0x0b, + 0x31, 0x4a, 0x2f, 0xe2, 0x5c, 0x82, 0x49, 0x51, 0xe4, 0x93, 0xcb, 0x05, + 0x23, 0x4f, 0x8a, 0x83, 0x88, 0xfb, 0x89, 0xb0, 0x08, 0xd6, 0x64, 0xad, + 0x51, 0x84, 0x40, 0x29, 0xb1, 0xca, 0x74, 0x26, 0x29, 0x5a, 0x61, 0x01, + 0x2e, 0xa0, 0xeb, 0xeb, 0x02, 0xb5, 0xff, 0xd8, 0x20, 0x6a, 0x5e, 0x8d, + 0x17, 0x1e, 0xa3, 0xd7, 0x2f, 0x20, 0x0b, 0x93, 0x17, 0x24, 0xf7, 0x90, + 0x7b, 0xc6, 0xba, 0xd8, 0xf9, 0xe9, 0x0a, 0x2a, 0x7a, 0x81, 0x23, 0x81, + 0x03, 0x6f, 0x1e, 0x0d, 0x87, 0x83, 0xd1, 0xcf, 0x92, 0x2f, 0x19, 0x82, + 0x4e, 0x6c, 0x0a, 0x02, 0xb6, 0x70, 0xbc, 0xe1, 0x58, 0xe7, 0x16, 0xdb, + 0x2f, 0x74, 0x9f, 0xe1, 0xc2, 0x1e, 0x64, 0xc6, 0x48, 0x08, 0xee, 0xea, + 0x52, 0x9a, 0xce, 0x2c, 0xc5, 0x0c, 0x7a, 0x63, 0xf1, 0x6a, 0xbd, 0x2c, + 0x8b, 0xd5, 0x4a, 0xfa, 0x1e, 0xab, 0x9a, 0x5b, 0x25, 0xb8, 0xfa, 0x0a, + 0xe9, 0x68, 0x80, 0x6f, 0x80, 0x57, 0x10, 0x54, 0xb8, 0xa2, 0x16, 0xbd, + 0xfe, 0xf7, 0xea, 0x01, 0xc7, 0x94, 0x5a, 0x95, 0xe3, 0x61, 0xa5, 0x49, + 0x84, 0xf5, 0x79, 0x78, 0xb5, 0x0a, 0x96, 0xca, 0x01, 0x1b, 0xd0, 0x0b, + 0x51, 0x30, 0xd3, 0x48, 0xfc, 0x4d, 0x50, 0x71, 0x09, 0x73, 0xea, 0x37, + 0xcd, 0x9d, 0x3d, 0xde, 0x30, 0x56, 0x21, 0xf0, 0xef, 0x84, 0xad, 0x27, + 0xe1, 0x83, 0xdb, 0xfb, 0xcd, 0x11, 0xb2, 0xbd, 0x30, 0x67, 0x8a, 0x88, + 0x09, 0x0e, 0x9d, 0x96, 0x09, 0xba, 0xda, 0x9d, 0xf0, 0xe9, 0xb4, 0xa6, + 0x7a, 0x04, 0xf9, 0x4b, 0xb8, 0x51, 0xa9, 0x99, 0xf3, 0xbb, 0x77, 0x95, + 0x0a, 0xa1, 0xa6, 0xa1, 0x24, 0xfc, 0xcc, 0x45, 0xe8, 0x83, 0xc8, 0x6f, + 0x48, 0xad, 0x9a, 0x73, 0xd0, 0xe0, 0x57, 0x7d, 0xe4, 0x78, 0x65, 0xef, + 0xae, 0xc2, 0xfe, 0x7a, 0x56, 0xaf, 0x03, 0x71, 0x2b, 0xe6, 0xa1, 0x7e, + 0xe5, 0x12, 0xf8, 0xc3, 0x75, 0xc7, 0x22, 0x5f, 0x1b, 0x52, 0x90, 0xe5, + 0xdf, 0xba, 0x9d, 0xe2, 0x68, 0xe0, 0xb3, 0x7a, 0x9e, 0x14, 0xff, 0xb5, + 0x0a, 0x80, 0x20, 0x49, 0x88, 0xe9, 0x9c, 0xe4, 0xb5, 0xaf, 0x7e, 0x51, + 0xec, 0xe7, 0xfc, 0x64, 0x65, 0x21, 0x10, 0xc6, 0x1f, 0x7f, 0x93, 0x7d, + 0xd8, 0xf5, 0xd0, 0x98, 0x94, 0x44, 0xf8, 0x49, 0x6a, 0x51, 0x0a, 0x54, + 0xf4, 0x9f, 0xee, 0x3c, 0x56, 0xbf, 0x4c, 0xe4, 0xde, 0x1c, 0x9b, 0x11, + 0x7e, 0x9a, 0x71, 0x11, 0x80, 0x33, 0xd5, 0xb0, 0x9b, 0xef, 0x67, 0x29, + 0xa4, 0x7d, 0x70, 0x31, 0x3f, 0x8b, 0x2e, 0x4a, 0x0f, 0x2c, 0x91, 0x3d, + 0x3e, 0x3d, 0x8c, 0x0a, 0x2b, 0xf1, 0xdd, 0xbf, 0x61, 0xe6, 0xa3, 0xef, + 0x6d, 0x82, 0xc8, 0xb7, 0x5e, 0x2b, 0x83, 0xc9, 0x4e, 0xa0, 0x85, 0x7f, + 0x01, 0x5a, 0xca, 0x6e, 0x90, 0xfa, 0x7e, 0x82, 0x4d, 0x35, 0x7e, 0xe0, + 0x26, 0x40, 0xf4, 0xa6, 0xae, 0xc3, 0x89, 0xf3, 0xca, 0x55, 0x2c, 0xb5, + 0x29, 0x05, 0x94, 0x45, 0xa7, 0x45, 0xf3, 0x3d, 0xbb, 0x53, 0x5e, 0xca, + 0x7c, 0x84, 0x8f, 0x72, 0x98, 0x93, 0x90, 0x1f, 0x56, 0x72, 0xdb, 0xbd, + 0xa9, 0xeb, 0xf9, 0xe9, 0xce, 0xb1, 0x41, 0xc3, 0xaa, 0xa0, 0xc4, 0x74, + 0x23, 0xc1, 0xeb, 0x7d, 0x41, 0xcd, 0xa4, 0x62, 0xec, 0xfc, 0x9a, 0xa4, + 0x16, 0xec, 0x67, 0x41, 0x89, 0xf0, 0x0e, 0xf3, 0xd1, 0xa2, 0x2f, 0xba, + 0x5d, 0x93, 0x36, 0x46, 0xf5, 0x52, 0x64, 0x91, 0xe7, 0x40, 0x91, 0x20, + 0xa1, 0xc9, 0xaa, 0x4c, 0x79, 0xc4, 0xbb, 0x67, 0x79, 0xad, 0x43, 0xab, + 0xba, 0xde, 0xfc, 0xf1, 0x74, 0x81, 0x33, 0xc0, 0x3f, 0x39, 0xd1, 0xd1, + 0xdf, 0xc0, 0x53, 0x33, 0xb2, 0x92, 0x37, 0xe6, 0x86, 0x2a, 0xe4, 0xe1, + 0x7c, 0x98, 0xf7, 0xdb, 0x5c, 0xa9, 0xff, 0x8d, 0x9c, 0xab, 0xe2, 0xf2, + 0xd5, 0xb1, 0x42, 0xa9, 0xf4, 0x97, 0x80, 0xcd, 0xde, 0x25, 0x2e, 0x87, + 0x92, 0xdd, 0xcf, 0xed, 0x67, 0x93, 0x8c, 0x5a, 0x1d, 0xee, 0xcf, 0x9d, + 0x50, 0x8f, 0xa7, 0xe3, 0x5c, 0xa3, 0x68, 0x78, 0x24, 0xeb, 0x60, 0xa3, + 0x8b, 0x36, 0xbb, 0xcb, 0x46, 0xee, 0x77, 0xfb, 0xf8, 0x69, 0x24, 0xd1, + 0xfa, 0xad, 0x76, 0x76, 0x5e, 0x54, 0xe5, 0xb6, 0x36, 0xc6, 0xdd, 0xa9, + 0x6c, 0x44, 0x15, 0xf7, 0x0a, 0xf8, 0xbb, 0xba, 0xec, 0x35, 0xff, 0xc9, + 0xd6, 0x5d, 0xf5, 0x73, 0x4a, 0x15, 0x8f, 0x7b, 0x6e, 0xf4, 0xa0, 0x6d, + 0x10, 0xbb, 0x67, 0x0c, 0xb4, 0x69, 0xad, 0xb6, 0x40, 0xf7, 0x5f, 0x37, + 0x28, 0xc4, 0x08, 0x49, 0xd0, 0x16, 0x70, 0x80, 0xea, 0x55, 0x66, 0x07, + 0xc8, 0x03, 0x1b, 0xf6, 0xd3, 0x03, 0x04, 0x74, 0xe0, 0x50, 0x3f, 0xd2, + 0x53, 0x92, 0xa0, 0x9d, 0x59, 0xc9, 0x74, 0xf2, 0x7e, 0x3b, 0x33, 0x02, + 0x10, 0x0b, 0x39, 0xf7, 0x4f, 0x6b, 0x58, 0xb2, 0x1a, 0xda, 0x65, 0x44, + 0xd1, 0x7c, 0x3f, 0xd7, 0xe3, 0xac, 0xe2, 0x1f, 0x38, 0xc1, 0x6a, 0xb0, + 0xdc, 0xc3, 0x9c, 0x7b, 0x11, 0x3c, 0x05, 0x21, 0x96, 0x76, 0x98, 0x76, + 0x82, 0xc1, 0x54, 0xdf, 0xdc, 0x8f, 0x4c, 0xd2, 0x63, 0x04, 0x06, 0x77, + 0x36, 0xe6, 0x2e, 0xd1, 0x00, 0x28, 0x42, 0x7c, 0x4a, 0x27, 0x90, 0x46, + 0xc9, 0xce, 0x33, 0x1c, 0xae, 0xda, 0x79, 0x64, 0x7f, 0x52, 0x3f, 0x58, + 0x11, 0x76, 0x4a, 0xb6, 0x72, 0xd8, 0x76, 0xae, 0xfd, 0x5c, 0x57, 0x69, + 0x76, 0x91, 0x84, 0x21, 0xc4, 0x9b, 0xd8, 0xa2, 0xff, 0x93, 0x02, 0x77, + 0x61, 0x57, 0x96, 0x7b, 0x8e, 0xfc, 0xf2, 0x6c, 0x11, 0x2b, 0x5e, 0x88, + 0x5c, 0x17, 0x1d, 0x12, 0x79, 0x3a, 0x78, 0xb6, 0x9d, 0x70, 0xfa, 0xd4, + 0xc1, 0x5c, 0x90, 0x0e, 0x0a, 0xd1, 0x3c, 0x7d, 0xcf, 0xee, 0x8a, 0xb2, + 0xb2, 0x4d, 0xce, 0x89, 0x32, 0xa9, 0x6c, 0x56, 0x57, 0x85, 0xb1, 0xbf, + 0x18, 0x1d, 0xc6, 0xe1, 0x17, 0xc5, 0x92, 0x42, 0x99, 0xf9, 0x9f, 0x04, + 0xec, 0x38, 0xf8, 0xa0, 0xd2, 0xab, 0xe6, 0x13, 0x4d, 0x9c, 0x18, 0x86, + 0x3e, 0x18, 0x73, 0x2c, 0xac, 0xe0, 0xb9, 0xf9, 0x87, 0x74, 0xb8, 0xd7, + 0x47, 0x6e, 0x42, 0xfc, 0x29, 0xa0, 0x1f, 0x56, 0x68, 0xb6, 0x23, 0x96, + 0xa2, 0x8d, 0x54, 0x81, 0x0f, 0x60, 0xb9, 0xde, 0x93, 0xfc, 0xfd, 0xde, + 0xbe, 0xb3, 0xb5, 0x87, 0xec, 0x9f, 0x17, 0xc2, 0x77, 0x6e, 0xa0, 0x62, + 0xdb, 0x66, 0xba, 0xc5, 0x05, 0x12, 0x46, 0x5d, 0x3c, 0x23, 0x29, 0x68, + 0xe5, 0x31, 0xe3, 0x15, 0xec, 0xac, 0x15, 0x9a, 0xbf, 0x42, 0x65, 0x80, + 0x45, 0x9c, 0x1d, 0xc2, 0x0e, 0x18, 0x47, 0x40, 0x44, 0xc1, 0x55, 0x24, + 0x5a, 0x35, 0xad, 0x59, 0xd2, 0xc6, 0xc3, 0x68, 0x58, 0xbd, 0x6f, 0xcf, + 0x5d, 0xb1, 0x9b, 0x0c, 0x92, 0x39, 0x22, 0x49, 0x66, 0x2e, 0x03, 0x7b, + 0x75, 0x5c, 0x6c, 0xde, 0x37, 0x54, 0xa9, 0x07, 0x2f, 0x7e, 0xc1, 0x3e, + 0x3b, 0xab, 0xd2, 0xa9, 0xfa, 0xc7, 0x6b, 0xd5, 0x14, 0x08, 0x35, 0x89, + 0x0b, 0x31, 0x18, 0x54, 0x7d, 0x6b, 0x53, 0x80, 0x6e, 0x32, 0x9b, 0xff, + 0x61, 0x7f, 0x36, 0xe5, 0x28, 0x40, 0xbc, 0xc7, 0x19, 0xb3, 0xae, 0xfa, + 0x95, 0xa8, 0xae, 0xd2, 0x97, 0x72, 0xc6, 0x91, 0x36, 0x3a, 0xa6, 0xec, + 0x4a, 0x41, 0x63, 0x6b, 0x28, 0xef, 0x5a, 0xa1, 0xdb, 0xf2, 0xd9, 0xfd, + 0x61, 0x72, 0xa4, 0xd2, 0x9e, 0xf7, 0x47, 0xf4, 0x4e, 0xea, 0x2a, 0xa5, + 0x35, 0xe1, 0x77, 0x3a, 0x53, 0x28, 0xa6, 0x55, 0x48, 0x0c, 0x1e, 0x44, + 0xfc, 0xc1, 0x31, 0x5a, 0x00, 0xcd, 0x29, 0xc1, 0x5c, 0xca, 0x2a, 0x07, + 0x01, 0x63, 0xac, 0xb3, 0xfb, 0xf6, 0x0b, 0xac, 0xfd, 0xe8, 0x7b, 0xed, + 0xf9, 0x3d, 0x9a, 0xbc, 0x67, 0x28, 0x1c, 0xd9, 0x3f, 0x97, 0x28, 0x4a, + 0xe7, 0xd0, 0x08, 0xe9, 0x3e, 0xa0, 0xcb, 0x0f, 0xe0, 0x3f, 0x1b, 0x80, + 0x43, 0x74, 0xd9, 0x9d, 0x0b, 0x22, 0x81, 0xf7, 0xec, 0x71, 0x2a, 0x29, + 0x9e, 0x5d, 0x1e, 0x8d, 0xf4, 0x22, 0x95, 0x78, 0x86, 0xcb, 0xf0, 0x9d, + 0xe7, 0x6a, 0x66, 0x7e, 0x28, 0xb5, 0x47, 0xb6, 0xdc, 0x0d, 0x03, 0x3c, + 0x09, 0x58, 0x76, 0x93, 0x39, 0xb2, 0xd3, 0x75, 0xb4, 0x51, 0x55, 0x84, + 0x30, 0x24, 0x0a, 0x76, 0xf4, 0x97, 0xe7, 0x0f, 0x5a, 0x67, 0xee, 0xf4, + 0xc7, 0x69, 0x8d, 0xf2, 0x32, 0x29, 0x5c, 0x33, 0x82, 0x5f, 0x6c, 0x47, + 0xd0, 0xe2, 0xbd, 0x62, 0xd6, 0x4c, 0x6d, 0x0d, 0xba, 0x87, 0xd3, 0x43, + 0x7e, 0x2d, 0xa6, 0x14, 0x09, 0x4f, 0x3b, 0xc3, 0x04, 0x14, 0xe5, 0x65, + 0xe9, 0x3b, 0x6a, 0xca, 0xb5, 0x96, 0x84, 0x3f, 0x53, 0x49, 0x22, 0x45, + 0x91, 0xff, 0xf9, 0x26, 0x75, 0x0d, 0x9c, 0xa7, 0x00, 0xf4, 0x65, 0xc4, + 0x60, 0x72, 0xab, 0xeb, 0xf8, 0xa8, 0x72, 0xfe, 0xd8, 0xde, 0x93, 0x67, + 0xcb, 0x09, 0xcc, 0xa0, 0xce, 0x9f, 0x67, 0x63, 0x26, 0xfa, 0x7f, 0x89, + 0xaa, 0x3e, 0x6d, 0xb2, 0x90, 0xd7, 0xef, 0x3e, 0x2a, 0x66, 0x26, 0x33, + 0xe6, 0x26, 0xc1, 0x58, 0xf8, 0x91, 0xea, 0x2f, 0xd0, 0x84, 0x21, 0x41, + 0x93, 0xa6, 0x36, 0x40, 0xb5, 0x4c, 0xac, 0x21, 0x88, 0x37, 0x47, 0x8a, + 0xb8, 0xf3, 0x33, 0x73, 0x12, 0xd7, 0x5a, 0x55, 0xf9, 0xd1, 0x1e, 0x75, + 0xa4, 0x66, 0x68, 0x3f, 0xf7, 0xb2, 0xc4, 0x5d, 0x1b, 0xb1, 0x61, 0x0f, + 0xaf, 0x4b, 0x9b, 0x20, 0x2b, 0x05, 0x68, 0x1c, 0x6c, 0x97, 0x8d, 0xb8, + 0x7b, 0x96, 0xda, 0xe0, 0x67, 0x15, 0x4c, 0x51, 0x71, 0x0d, 0xd3, 0x7b, + 0xde, 0xaa, 0xd3, 0x58, 0xf5, 0xc9, 0x62, 0x0a, 0xc2, 0x33, 0x1f, 0xf3, + 0xc3, 0x30, 0xb5, 0x64, 0xd1, 0x59, 0x41, 0x0e, 0xae, 0xaa, 0x0d, 0xdf, + 0x9f, 0x5d, 0x3f, 0x15, 0x0d, 0x46, 0x7a, 0x6d, 0x2e, 0x29, 0x1b, 0xc0, + 0xd3, 0x11, 0x10, 0x5d, 0xdc, 0x6a, 0x35, 0x8c, 0x43, 0xc8, 0x9f, 0x05, + 0x80, 0xdc, 0x25, 0x24, 0x37, 0x70, 0x7e, 0x1c, 0xe9, 0x85, 0x5a, 0xef, + 0x83, 0x3a, 0x55, 0x68, 0x83, 0x17, 0xf4, 0xc7, 0xae, 0xe4, 0x84, 0xc9, + 0x64, 0x5d, 0x2f, 0xb6, 0xca, 0x10, 0x95, 0xb8, 0xd6, 0x80, 0xfd, 0x05, + 0xa5, 0x06, 0x32, 0x34, 0x91, 0x01, 0xd2, 0x02, 0x90, 0xe1, 0xf7, 0x89, + 0x8a, 0xee, 0x18, 0x04, 0x93, 0xd9, 0xb4, 0x63, 0x4b, 0xf7, 0x7a, 0x9c, + 0x1b, 0x4b, 0xf9, 0x31, 0x32, 0xd9, 0xf2, 0x55, 0x4e, 0xc1, 0x02, 0xce, + 0x77, 0x38, 0x36, 0x29, 0xb8, 0x54, 0x8c, 0xc2, 0x27, 0x5f, 0xd9, 0xae, + 0x3e, 0x1e, 0xcd, 0xe9, 0x07, 0x90, 0x4c, 0xe0, 0xda, 0x16, 0x6e, 0xdf, + 0xde, 0x3a, 0x61, 0x89, 0x9f, 0x79, 0xd0, 0xd4, 0x66, 0x95, 0xad, 0xe4, + 0x11, 0x7d, 0xa1, 0xae, 0xec, 0x3e, 0x6e, 0x20, 0x5a, 0xd0, 0x28, 0x0e, + 0x55, 0xec, 0xcf, 0x34, 0xec, 0xb7, 0xfc, 0xa4, 0xb3, 0x8f, 0x56, 0x13, + 0x50, 0xcc, 0x15, 0x10, 0x74, 0x40, 0x72, 0x42, 0x20, 0x22, 0xb3, 0xaf, + 0xf3, 0x68, 0xba, 0x95, 0x45, 0xcb, 0xef, 0x92, 0xd5, 0x14, 0x4c, 0x1f, + 0xe3, 0xc1, 0xa6, 0x03, 0x4e, 0x05, 0xd2, 0x1a, 0xee, 0xd2, 0x48, 0x44, + 0x2e, 0x50, 0x3b, 0x86, 0xc8, 0x6a, 0xc8, 0x4c, 0xca, 0x2a, 0xb6, 0xf7, + 0x3c, 0xaf, 0xdc, 0x62, 0xb1, 0x49, 0x13, 0xfe, 0xe7, 0x32, 0xea, 0x78, + 0xfa, 0xba, 0xcf, 0x15, 0x47, 0x58, 0xdc, 0x19, 0x73, 0x1d, 0xff, 0xbd, + 0xcc, 0x27, 0xf6, 0xfc, 0x66, 0x68, 0xa7, 0x29, 0xaf, 0x2b, 0x25, 0x0c, + 0x15, 0x47, 0xff, 0xc1, 0x00, 0x9d, 0xfa, 0x58, 0x9c, 0xaa, 0xf9, 0xcc, + 0x4c, 0x51, 0x1d, 0xda, 0xf3, 0x3c, 0x10, 0xd0, 0x3b, 0x59, 0x30, 0x02, + 0x68, 0x29, 0x1c, 0xa7, 0x22, 0xea, 0x81, 0xd3, 0x29, 0x71, 0x39, 0xe8, + 0x72, 0x7f, 0x7d, 0x94, 0x0a, 0x64, 0x2c, 0xe6, 0x55, 0xfb, 0x90, 0x78, + 0x7e, 0x6c, 0x3e, 0xfe, 0x57, 0x14, 0x61, 0xef, 0xe2, 0x63, 0x57, 0x6c, + 0x13, 0x97, 0x27, 0x2b, 0x38, 0x44, 0xab, 0x74, 0x76, 0x11, 0xa6, 0x60, + 0xad, 0x8e, 0xad, 0xe5, 0xa5, 0xa1, 0x66, 0xc5, 0xe1, 0x4d, 0x27, 0xa0, + 0x79, 0x7a, 0x09, 0xe6, 0xf0, 0x28, 0x3f, 0xcb, 0xc6, 0xf8, 0x94, 0xc0, + 0xf1, 0x13, 0xbe, 0x62, 0x6a, 0x52, 0x75, 0x52, 0xd3, 0x82, 0x31, 0xbd, + 0x15, 0xf2, 0xe8, 0x2e, 0xb1, 0x62, 0x03, 0x1e, 0xe2, 0xb3, 0xec, 0xbc, + 0x3c, 0x12, 0xca, 0x62, 0x4e, 0xc2, 0x3a, 0x51, 0x1c, 0xdf, 0xa2, 0x84, + 0x88, 0xe5, 0x7e, 0xd7, 0x5d, 0xd7, 0xbf, 0xf2, 0x7d, 0xbd, 0x9a, 0x90, + 0x63, 0xfd, 0x8a, 0x84, 0x2b, 0x9d, 0x89, 0x27, 0x63, 0x4c, 0x0a, 0xe3, + 0x70, 0x94, 0x7b, 0xe6, 0xb3, 0xd7, 0xcb, 0xcb, 0x8a, 0xeb, 0x6b, 0x53, + 0x34, 0x2f, 0x62, 0x44, 0x2d, 0x73, 0x63, 0x8a, 0xf4, 0xa2, 0x01, 0xd7, + 0x12, 0xb6, 0x8d, 0x8c, 0x4b, 0x73, 0x2b, 0x44, 0x50, 0x49, 0x6f, 0x01, + 0xac, 0xc5, 0x15, 0x37, 0x6c, 0xde, 0xd4, 0x02, 0xb1, 0x12, 0x80, 0x73, + 0xb2, 0x52, 0x0e, 0xe0, 0xb5, 0x75, 0xc9, 0x48, 0xcf, 0x18, 0x5c, 0xcc, + 0xaf, 0x58, 0xa2, 0x3e, 0x28, 0xe4, 0xab, 0xde, 0xea, 0x2a, 0xcf, 0x58, + 0x22, 0xc4, 0x68, 0xea, 0x9b, 0x7b, 0x90, 0xc5, 0xdc, 0x1c, 0x37, 0xd1, + 0x8a, 0x4f, 0xe7, 0x24, 0x23, 0x39, 0xb9, 0x62, 0xb8, 0x41, 0x13, 0x7b, + 0xe2, 0x1e, 0x0d, 0x4e, 0x38, 0x11, 0xa3, 0xb9, 0x10, 0xbb, 0x10, 0x6f, + 0x40, 0x9f, 0x50, 0x05, 0xc7, 0x0e, 0xb9, 0x9e, 0xab, 0x7c, 0x3c, 0x78, + 0xce, 0x54, 0xbf, 0xbf, 0x40, 0x36, 0x76, 0xbc, 0x4b, 0x64, 0x32, 0xca, + 0x0e, 0x2d, 0x91, 0x87, 0xd5, 0x00, 0x19, 0xbf, 0x12, 0xd0, 0x35, 0x7c, + 0xa1, 0xe5, 0xcf, 0x7a, 0x2d, 0x08, 0x62, 0xed, 0x34, 0x61, 0xe3, 0xda, + 0x2c, 0xcc, 0x1b, 0xf8, 0x12, 0xfe, 0xfd, 0x19, 0xa2, 0xc3, 0x70, 0xfd, + 0x4f, 0x5b, 0x5d, 0x20, 0xd2, 0xe1, 0xc5, 0xac, 0xe7, 0xa1, 0x84, 0x00, + 0xbd, 0x46, 0x81, 0xfd, 0x54, 0x69, 0xed, 0x1a, 0x7a, 0x32, 0xbb, 0x75, + 0x22, 0x76, 0x6d, 0x34, 0x24, 0xcc, 0xe6, 0xbe, 0x78, 0x5a, 0x75, 0x6c, + 0xbc, 0x62, 0xb8, 0x14, 0xf7, 0x13, 0x73, 0xc2, 0xdc, 0xb6, 0xfa, 0xfb, + 0x97, 0xfe, 0x27, 0x7b, 0x33, 0xb8, 0xeb, 0x20, 0xd2, 0x0f, 0x4f, 0xed, + 0xd1, 0xd0, 0x63, 0xf7, 0xc5, 0x8e, 0xec, 0xcc, 0xd2, 0x31, 0x38, 0x35, + 0x65, 0x33, 0x5c, 0x63, 0x85, 0xf7, 0x3d, 0xc3, 0x62, 0x26, 0x52, 0x0a, + 0x67, 0xda, 0x87, 0x1f, 0x9e, 0x47, 0xec, 0x6b, 0xf5, 0x74, 0x1a, 0xc5, + 0xa7, 0xa0, 0x0f, 0xdd, 0xc5, 0x42, 0xf4, 0xda, 0x41, 0x1a, 0x48, 0xa9, + 0xbe, 0x4f, 0xb6, 0x28, 0x17, 0xe9, 0xf5, 0xd7, 0x00, 0xb3, 0xfe, 0x05, + 0x4e, 0xa7, 0xdf, 0x65, 0x7a, 0xb8, 0x4f, 0xe0, 0xfe, 0x58, 0x9e, 0xba, + 0x45, 0x11, 0xba, 0xc2, 0xdb, 0x97, 0x97, 0xa4, 0xbc, 0x18, 0x21, 0x1b, + 0xad, 0x82, 0xef, 0xb1, 0x5f, 0x2f, 0x25, 0x9d, 0xca, 0x52, 0xa5, 0x6d, + 0x8c, 0xab, 0x07, 0x2b, 0x7b, 0x6a, 0x77, 0x9d, 0xdf, 0xfb, 0xae, 0x6e, + 0x49, 0x18, 0x25, 0x4a, 0xf2, 0x7d, 0xa0, 0x32, 0xc8, 0x53, 0x10, 0xc3, + 0xf2, 0xef, 0xf3, 0xe7, 0x79, 0xd7, 0x6a, 0x0e, 0x61, 0xff, 0x89, 0xc9, + 0x42, 0xe8, 0x6e, 0x4f, 0x78, 0xe1, 0x5f, 0xcd, 0x7a, 0xf6, 0x27, 0x72, + 0x67, 0xea, 0x0b, 0xa6, 0xcc, 0x34, 0xb7, 0x8f, 0x92, 0x3c, 0x95, 0xb9, + 0x0a, 0x5d, 0x49, 0x2e, 0xb7, 0x7d, 0x31, 0x9c, 0x79, 0x61, 0x95, 0x9c, + 0x60, 0x56, 0x8d, 0x35, 0x00, 0xc5, 0x8b, 0xe6, 0x02, 0x0f, 0x26, 0x39, + 0x7b, 0x93, 0x94, 0xb1, 0xcd, 0xde, 0xed, 0xfa, 0x2a, 0x4b, 0x63, 0xa8, + 0x1b, 0x31, 0x43, 0x5e, 0x69, 0x7c, 0xd6, 0x15, 0x35, 0x9c, 0xa2, 0xd7, + 0xdf, 0x0e, 0x1a, 0x20, 0x50, 0xf5, 0x02, 0x21, 0x30, 0x35, 0x3c, 0x60, + 0x71, 0xad, 0xd0, 0xe3, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x10, 0x17, 0x1d, 0x22, 0x2d}; +const uint8_t expected_signature_87[] = { + 0xdf, 0xe6, 0xe1, 0xa5, 0x20, 0xc1, 0xac, 0x98, 0x55, 0x2c, 0xf2, 0x13, + 0x65, 0x42, 0xe2, 0xb0, 0x77, 0x5f, 0x15, 0x00, 0x8f, 0x14, 0x48, 0xa1, + 0xe3, 0xee, 0x81, 0x35, 0x15, 0x34, 0xad, 0x6e, 0x60, 0x85, 0x00, 0xf8, + 0x18, 0x53, 0x0d, 0xa0, 0xc5, 0x41, 0xc4, 0x48, 0x09, 0x1b, 0x34, 0x0c, + 0x0e, 0xcf, 0xc6, 0x3d, 0x38, 0x78, 0x8b, 0x69, 0xe5, 0x6f, 0x4d, 0x43, + 0xfa, 0xa6, 0x75, 0x26, 0x8a, 0x75, 0x97, 0x10, 0x6a, 0x1f, 0x3c, 0xa6, + 0x94, 0xa9, 0x93, 0x8f, 0xe5, 0x62, 0xbf, 0x94, 0xe4, 0xd0, 0x0d, 0x11, + 0x4d, 0x03, 0xe2, 0xd8, 0xdf, 0x68, 0xb7, 0x87, 0x62, 0xc9, 0xdc, 0xc9, + 0x36, 0x4f, 0xcc, 0xd1, 0xa4, 0xae, 0x7e, 0xa4, 0xb9, 0xaf, 0xaf, 0xf0, + 0x8a, 0xe6, 0xff, 0x83, 0xe7, 0x54, 0x22, 0x6e, 0x3f, 0x2e, 0xa0, 0x4f, + 0xa8, 0x31, 0x53, 0xf3, 0x62, 0xeb, 0x04, 0xfa, 0xd1, 0x57, 0x39, 0x43, + 0xf9, 0xe0, 0x31, 0x12, 0x45, 0x09, 0x8b, 0x9e, 0x1e, 0x7a, 0x2b, 0x85, + 0xee, 0xdd, 0xe8, 0x1e, 0xd7, 0xc0, 0x17, 0xb4, 0xd2, 0xdc, 0x36, 0xa9, + 0xe4, 0x49, 0x88, 0xbf, 0x71, 0x43, 0x9d, 0x3e, 0xd2, 0x10, 0xe7, 0x82, + 0xb5, 0xfe, 0xdd, 0x42, 0xc8, 0x1b, 0x11, 0xf6, 0x52, 0x23, 0x98, 0x83, + 0x48, 0xec, 0xec, 0x70, 0x8b, 0xe7, 0x49, 0x9a, 0xd7, 0xd9, 0x7b, 0x47, + 0x4e, 0xe2, 0x5e, 0x17, 0x1a, 0xa0, 0x0e, 0x60, 0x85, 0x3a, 0x30, 0x8c, + 0x1c, 0x26, 0xb4, 0xe1, 0xb5, 0x2b, 0x48, 0xf4, 0xb8, 0x93, 0x2f, 0x79, + 0x3a, 0x1e, 0xb6, 0x3b, 0x07, 0x3b, 0x1e, 0x15, 0xd7, 0x85, 0x5e, 0xd4, + 0x06, 0x0e, 0xcd, 0x6a, 0x93, 0x3a, 0x93, 0x29, 0x6a, 0xbe, 0x68, 0x8a, + 0xb6, 0xb8, 0xfa, 0xc5, 0x63, 0x48, 0x98, 0x10, 0x6d, 0xd9, 0xd3, 0x5b, + 0x29, 0x5f, 0x93, 0x90, 0x08, 0x1c, 0x1a, 0x15, 0x7b, 0x0a, 0x59, 0x9d, + 0x64, 0x24, 0x45, 0xb6, 0xd3, 0x7b, 0xc1, 0x5d, 0x74, 0x1f, 0x0b, 0x8e, + 0x18, 0xf2, 0x92, 0x8e, 0xd4, 0x7f, 0x72, 0x5c, 0x98, 0x1f, 0x8b, 0xa5, + 0xb8, 0xf4, 0x7e, 0x12, 0x6a, 0x93, 0xb9, 0xb5, 0xf1, 0xda, 0x97, 0x75, + 0x4f, 0x56, 0x80, 0x88, 0x64, 0x2b, 0xe0, 0x59, 0xcd, 0x5e, 0x91, 0x64, + 0x9c, 0x0c, 0xa8, 0xdd, 0xac, 0xcb, 0xf3, 0x48, 0x3b, 0x5c, 0xc4, 0xc5, + 0xb9, 0x9a, 0x0b, 0x8e, 0x5d, 0x9a, 0xd5, 0xb7, 0xf0, 0xd4, 0x07, 0x48, + 0xb9, 0x63, 0x02, 0x87, 0x8d, 0xae, 0x7e, 0x03, 0x33, 0x4f, 0x86, 0x15, + 0x1b, 0x3b, 0xdf, 0xda, 0xce, 0xd3, 0x1e, 0xc0, 0x76, 0xb5, 0x1c, 0xdd, + 0xb8, 0x32, 0x87, 0x7d, 0x59, 0x18, 0x72, 0x0c, 0xde, 0x8f, 0x63, 0x2d, + 0x38, 0xf2, 0xe9, 0xc2, 0x81, 0xed, 0xfa, 0x2d, 0x61, 0xef, 0x48, 0xdb, + 0xa2, 0xeb, 0xfe, 0x52, 0x31, 0x1e, 0x21, 0x0a, 0x08, 0xf6, 0x02, 0xd3, + 0xc0, 0x32, 0x3b, 0x6b, 0x2f, 0x64, 0xc4, 0xb3, 0x4b, 0xfe, 0x69, 0x78, + 0xbf, 0x20, 0x62, 0x07, 0x77, 0xdf, 0x2c, 0x18, 0x53, 0x61, 0x8e, 0x05, + 0x01, 0x86, 0xab, 0xab, 0xec, 0x18, 0x8c, 0x15, 0x63, 0x1f, 0xe9, 0x99, + 0xb2, 0x35, 0x77, 0xe1, 0x58, 0xf1, 0xa9, 0x4d, 0x1a, 0xb9, 0x8c, 0x30, + 0x63, 0x6f, 0x9e, 0x7d, 0x4e, 0xcf, 0xb5, 0x6c, 0xf3, 0xe4, 0xdc, 0xab, + 0xf9, 0xae, 0x58, 0xf8, 0x1d, 0x08, 0x7b, 0x73, 0x82, 0x58, 0xc8, 0x67, + 0x48, 0x1a, 0x5e, 0x3d, 0xdb, 0xac, 0x1b, 0x1b, 0xef, 0xeb, 0xa4, 0xe5, + 0x67, 0x48, 0x76, 0xd1, 0x96, 0x4f, 0x6c, 0x7d, 0x06, 0x8c, 0x02, 0x86, + 0x95, 0x83, 0xb6, 0x9b, 0x5e, 0x9a, 0xb5, 0x85, 0xc0, 0x4f, 0x13, 0x1c, + 0x32, 0xf8, 0x29, 0xdf, 0x47, 0x85, 0xdb, 0xe4, 0x37, 0xdc, 0xd8, 0x04, + 0x18, 0xdd, 0xca, 0x97, 0xdd, 0x67, 0x13, 0xbe, 0x74, 0x95, 0xdc, 0xd0, + 0xcc, 0xe6, 0xb5, 0xa5, 0x12, 0x9b, 0x23, 0x4f, 0x41, 0x8c, 0xcc, 0x95, + 0xf4, 0xb0, 0x5f, 0x2a, 0xc4, 0xbf, 0x88, 0xda, 0x55, 0xcb, 0x13, 0x93, + 0x22, 0x60, 0x51, 0x43, 0xc7, 0x9a, 0x2c, 0xfa, 0xb2, 0x59, 0xc1, 0xe6, + 0x8a, 0xa4, 0xb8, 0xfb, 0xd3, 0x31, 0x1d, 0xc7, 0x88, 0xdc, 0xbc, 0xe9, + 0xba, 0xe7, 0xdc, 0xe3, 0xdd, 0x90, 0x96, 0xb4, 0xb4, 0x0a, 0xc1, 0x07, + 0x31, 0x3f, 0xdb, 0xc5, 0x4d, 0x73, 0x58, 0x86, 0x15, 0x37, 0x07, 0x86, + 0x03, 0x17, 0x16, 0x18, 0x15, 0xb9, 0x26, 0x35, 0x8a, 0x43, 0x22, 0xae, + 0x21, 0x52, 0x05, 0x4e, 0x5c, 0x3f, 0x3e, 0xb9, 0x2a, 0x19, 0x13, 0xfd, + 0x31, 0x47, 0x6a, 0x74, 0xaa, 0xb9, 0xc6, 0x2c, 0x13, 0x8c, 0x21, 0xc4, + 0x8d, 0x00, 0xf4, 0x24, 0xf2, 0xb7, 0xd3, 0x13, 0xad, 0x29, 0x5e, 0x50, + 0x0b, 0x0e, 0x9f, 0x9a, 0xb7, 0xf6, 0x9e, 0xba, 0x12, 0x23, 0x84, 0x8c, + 0xbe, 0x2c, 0x14, 0x1e, 0xe6, 0x79, 0x15, 0x20, 0x2d, 0x32, 0x08, 0xd8, + 0x1c, 0x87, 0x1b, 0xa8, 0xc0, 0xbb, 0x85, 0xa9, 0x71, 0x30, 0x5e, 0x39, + 0x48, 0x87, 0xdc, 0x3d, 0x03, 0x29, 0x19, 0xd1, 0xd4, 0x21, 0x3a, 0x53, + 0x2d, 0x5e, 0x78, 0xff, 0x94, 0x4b, 0x91, 0xa6, 0xb5, 0xe5, 0x42, 0x56, + 0x67, 0x6a, 0x0e, 0xf3, 0x2d, 0x6a, 0x4e, 0xd7, 0x3a, 0x81, 0xb1, 0x4d, + 0x0b, 0x66, 0x5f, 0x43, 0x28, 0x7c, 0x75, 0x8b, 0x2b, 0x99, 0x24, 0xc2, + 0x5e, 0x8c, 0x22, 0xf0, 0xd5, 0xb3, 0xfc, 0x86, 0x62, 0xf3, 0xd2, 0x6c, + 0xa7, 0x48, 0x04, 0x44, 0x5d, 0x93, 0x74, 0x37, 0x16, 0x2c, 0x19, 0x12, + 0x57, 0x49, 0xef, 0xd5, 0xd6, 0x92, 0xdc, 0x51, 0xf8, 0x55, 0x3a, 0xc0, + 0x0b, 0xdf, 0x41, 0xb5, 0x01, 0x59, 0x7e, 0x85, 0x65, 0xdb, 0x44, 0xbd, + 0x04, 0x96, 0x1a, 0xd4, 0x6e, 0x22, 0x54, 0x92, 0xdb, 0xc7, 0xc5, 0x3a, + 0xdf, 0x0c, 0xf4, 0x1b, 0xdc, 0x14, 0xf6, 0x91, 0x9c, 0xbe, 0xf8, 0x8e, + 0x70, 0xd1, 0x3a, 0x0e, 0x58, 0xe6, 0xb9, 0xd3, 0xaa, 0xa2, 0x70, 0xba, + 0xdd, 0x16, 0x13, 0x19, 0xd1, 0x96, 0x78, 0x04, 0x2f, 0xd7, 0x38, 0x8c, + 0x35, 0x1f, 0xfc, 0x58, 0xa4, 0x4c, 0xa9, 0x9a, 0xae, 0x13, 0x3b, 0xc1, + 0x20, 0x4b, 0x66, 0x0f, 0x72, 0x42, 0x0a, 0x53, 0x84, 0x54, 0x71, 0x06, + 0xdb, 0x85, 0x8f, 0x40, 0xa6, 0x09, 0xf7, 0x24, 0xc4, 0x35, 0xf7, 0x1d, + 0xd4, 0x3d, 0x54, 0x75, 0xaf, 0xc4, 0x78, 0x0f, 0xce, 0xe0, 0x0c, 0x90, + 0x0f, 0xd5, 0x2e, 0x61, 0xf7, 0x58, 0xaa, 0xf0, 0xc7, 0x37, 0x5a, 0x59, + 0x1f, 0x8a, 0x03, 0x98, 0x43, 0xb7, 0x27, 0x78, 0x4e, 0x44, 0x5a, 0xb5, + 0x29, 0xf5, 0xab, 0x9e, 0xb7, 0x2a, 0xc4, 0xa3, 0x03, 0x00, 0xe3, 0x28, + 0x57, 0xc9, 0x2a, 0x98, 0xb8, 0xa1, 0x45, 0x1d, 0xfa, 0x6e, 0xb3, 0x0d, + 0x42, 0x5a, 0xb6, 0xb1, 0x0e, 0x5c, 0xbe, 0x82, 0xe2, 0x36, 0x40, 0x4b, + 0x05, 0x28, 0xd9, 0xbc, 0x27, 0xd6, 0x77, 0x00, 0xc9, 0x29, 0x6a, 0xd6, + 0x19, 0x8f, 0x8d, 0xda, 0xe1, 0xc3, 0x8b, 0x69, 0x71, 0xd0, 0xf7, 0xc8, + 0x33, 0xef, 0xe6, 0x23, 0x6b, 0xcb, 0x00, 0x56, 0x0a, 0x9b, 0x9d, 0x60, + 0x3a, 0xd3, 0xad, 0xd9, 0x5c, 0x6a, 0x7d, 0xab, 0x35, 0x71, 0x93, 0xc5, + 0xf2, 0x6a, 0x38, 0x0e, 0xfb, 0xd9, 0x9b, 0xa5, 0xda, 0x52, 0x45, 0xef, + 0x93, 0x94, 0x5b, 0x08, 0x8c, 0x07, 0xab, 0x2e, 0x99, 0x88, 0x77, 0xb5, + 0x15, 0x66, 0x7f, 0x0e, 0xfa, 0xb0, 0x29, 0xe4, 0x88, 0xd9, 0xdd, 0x22, + 0xaf, 0x7a, 0x4e, 0xb5, 0xd0, 0x62, 0x85, 0x27, 0x33, 0xf1, 0xb7, 0x34, + 0xb1, 0xe6, 0xda, 0x9f, 0x3c, 0xfe, 0xf5, 0xd4, 0xef, 0x56, 0x48, 0x93, + 0x7a, 0x54, 0xa2, 0x7f, 0x07, 0xea, 0x31, 0xb8, 0x8b, 0xca, 0xb9, 0xdb, + 0x1e, 0x2b, 0xb5, 0x16, 0xe6, 0x0e, 0xd9, 0x3f, 0x7c, 0xf0, 0xc2, 0x3e, + 0x57, 0x64, 0x60, 0x97, 0xfb, 0xdf, 0x8c, 0x3e, 0x56, 0x22, 0x92, 0x2a, + 0xb2, 0x21, 0x00, 0x0a, 0x75, 0x89, 0x68, 0xe7, 0x51, 0xa3, 0x63, 0x05, + 0xe1, 0x6f, 0x1e, 0x1e, 0x80, 0xa2, 0x4b, 0x5d, 0xb7, 0xf4, 0xb7, 0x45, + 0x85, 0x00, 0x84, 0x6e, 0xbe, 0x0b, 0x67, 0xbf, 0x21, 0x06, 0x5a, 0x56, + 0x79, 0xe9, 0x6b, 0x0e, 0x72, 0x19, 0x2d, 0x09, 0x78, 0xd5, 0x5e, 0xc2, + 0x32, 0xee, 0x29, 0xd4, 0x7a, 0x65, 0xc7, 0xfe, 0x16, 0x86, 0xd2, 0x29, + 0x71, 0xe5, 0x91, 0x0e, 0x3e, 0x86, 0xd5, 0x00, 0xc4, 0xfc, 0xd9, 0xae, + 0xd3, 0x7c, 0x13, 0xfd, 0x62, 0xce, 0x0c, 0xb2, 0xe5, 0x1f, 0x6d, 0xed, + 0x55, 0x6f, 0xc1, 0xaa, 0xa1, 0x74, 0x59, 0x46, 0x83, 0xd5, 0x5d, 0x71, + 0x17, 0x13, 0x1d, 0x0b, 0x25, 0xfb, 0x0a, 0xcd, 0x67, 0xfe, 0x57, 0x93, + 0xc2, 0x71, 0x55, 0x6c, 0x68, 0xfa, 0x40, 0xdb, 0xdd, 0xce, 0xd5, 0x5c, + 0xce, 0x0a, 0x1d, 0xfa, 0x19, 0x30, 0xe2, 0x2b, 0x63, 0x98, 0x16, 0x2c, + 0x67, 0x69, 0x55, 0xe5, 0xc1, 0x6c, 0x6e, 0xb7, 0x92, 0x6a, 0xbb, 0x10, + 0xd3, 0x13, 0x2e, 0x73, 0x91, 0x74, 0xcb, 0x9f, 0x5c, 0x7f, 0x5c, 0x48, + 0x58, 0x36, 0x13, 0x47, 0xf7, 0x49, 0xae, 0x90, 0x15, 0x53, 0xb5, 0xe6, + 0x37, 0xfb, 0x81, 0x47, 0xb4, 0x69, 0x84, 0xca, 0x95, 0xab, 0x19, 0x2a, + 0x28, 0xc2, 0x8a, 0xf1, 0xcd, 0xf9, 0x3e, 0xd3, 0xaf, 0xe1, 0x75, 0xf7, + 0x94, 0x74, 0x1c, 0xf5, 0x32, 0xcf, 0x70, 0xbd, 0x69, 0xcc, 0xa8, 0x3c, + 0xca, 0x59, 0x53, 0xfa, 0xcb, 0xe7, 0xb6, 0x36, 0x70, 0xea, 0xe2, 0x84, + 0xfa, 0x5e, 0xbd, 0xd7, 0x59, 0x3d, 0x21, 0xc6, 0x9f, 0x5c, 0x1f, 0xa6, + 0xa9, 0xf1, 0xd3, 0x26, 0x9e, 0xff, 0xbc, 0x81, 0xfe, 0xbe, 0xee, 0x64, + 0xd9, 0x63, 0x94, 0x4b, 0x15, 0xd8, 0x95, 0xaa, 0xec, 0x10, 0xc9, 0xe2, + 0xe1, 0x05, 0x37, 0x64, 0xc4, 0xb0, 0x2e, 0xa5, 0x0e, 0x4c, 0x2d, 0x03, + 0x53, 0xf1, 0x93, 0x77, 0x9d, 0x46, 0x14, 0x67, 0x48, 0x5f, 0xad, 0x1b, + 0xdc, 0xb9, 0x74, 0xa2, 0x6c, 0xfc, 0xd2, 0xa0, 0x1f, 0x43, 0x89, 0x15, + 0xc5, 0x0c, 0xb0, 0x9e, 0x1e, 0xc2, 0xd6, 0x44, 0xd9, 0x6e, 0xfc, 0xb4, + 0x9c, 0x95, 0x90, 0xcd, 0xc3, 0x17, 0x1c, 0x6a, 0xce, 0x03, 0x56, 0x9f, + 0xe7, 0xcd, 0x7e, 0xe7, 0xa2, 0x0c, 0x2b, 0x0d, 0x59, 0xb0, 0xc9, 0x4c, + 0x6e, 0x33, 0x6d, 0x43, 0xc4, 0x3a, 0x10, 0x24, 0x03, 0x3e, 0x09, 0xb6, + 0x86, 0x13, 0xba, 0x18, 0x19, 0xd3, 0xff, 0xeb, 0xa5, 0x25, 0x8f, 0x6f, + 0xc8, 0xe6, 0x96, 0xa4, 0xd2, 0x66, 0x40, 0x81, 0x79, 0xe8, 0x39, 0x18, + 0x41, 0x02, 0x66, 0x5c, 0x30, 0x5f, 0x58, 0x9d, 0x35, 0x16, 0xc6, 0x96, + 0xa8, 0x68, 0xbc, 0x09, 0x83, 0x17, 0x2c, 0x5f, 0x5e, 0xd0, 0x1d, 0xb0, + 0x48, 0x5e, 0xcf, 0x91, 0x16, 0x4d, 0xa0, 0xba, 0xbc, 0x61, 0xa8, 0x3f, + 0x30, 0x09, 0xbb, 0xa3, 0x12, 0xcd, 0xdc, 0x29, 0xf7, 0xb0, 0xad, 0x05, + 0x17, 0xd6, 0xd3, 0x16, 0xfb, 0xe5, 0x99, 0xf4, 0x71, 0x62, 0xa3, 0x45, + 0x45, 0xc7, 0x9b, 0xaa, 0x45, 0xd3, 0x35, 0xfe, 0xfb, 0x63, 0xaf, 0xe7, + 0x85, 0x31, 0xc9, 0x66, 0x26, 0xa9, 0xda, 0x8c, 0xc6, 0xf6, 0xd5, 0xdf, + 0xb1, 0xa9, 0xf1, 0xb6, 0x3d, 0x92, 0xae, 0x4d, 0xbc, 0x74, 0x7d, 0x76, + 0x5a, 0x59, 0x8c, 0x87, 0xff, 0x95, 0x2f, 0x67, 0x37, 0x30, 0x1a, 0xc1, + 0x23, 0x2e, 0x0c, 0xaa, 0x80, 0x1c, 0xf3, 0xa3, 0x74, 0x94, 0xb2, 0xda, + 0x1a, 0xb8, 0x46, 0xec, 0x30, 0x76, 0xf4, 0xdf, 0xfb, 0x00, 0xb3, 0x6f, + 0x86, 0xc1, 0xc5, 0x3a, 0x5d, 0x11, 0x14, 0x87, 0xeb, 0x30, 0xd8, 0x33, + 0x18, 0x00, 0x01, 0x76, 0x43, 0x82, 0xcd, 0x1c, 0x36, 0x54, 0xd2, 0x64, + 0x5b, 0xfb, 0x93, 0xca, 0x20, 0x1d, 0xa3, 0x20, 0x99, 0xc3, 0x8e, 0x5c, + 0x82, 0xfc, 0x56, 0x07, 0x41, 0x4b, 0x4f, 0x54, 0xc7, 0xb5, 0xe8, 0x6d, + 0x7e, 0xd8, 0x8a, 0x56, 0xb4, 0x76, 0x1e, 0xd3, 0x82, 0x97, 0xdd, 0x2b, + 0xd9, 0x80, 0xb7, 0xb6, 0xeb, 0x3d, 0xe5, 0xe0, 0x20, 0x27, 0x8c, 0xf0, + 0xd6, 0x14, 0xc7, 0xcd, 0x79, 0xbc, 0xa0, 0x21, 0x85, 0xc3, 0x02, 0xae, + 0x73, 0xc4, 0x0a, 0x39, 0x1a, 0x98, 0x61, 0xc3, 0x86, 0xd8, 0x97, 0x67, + 0x87, 0xe9, 0x56, 0x0b, 0x61, 0xa6, 0x7e, 0x07, 0xfb, 0x0a, 0x8b, 0xd1, + 0x90, 0xbd, 0x39, 0x22, 0xdb, 0xc2, 0x7f, 0xaa, 0x79, 0xb7, 0x39, 0x09, + 0xc1, 0x69, 0xdb, 0xe2, 0x7f, 0xec, 0xde, 0x80, 0x7a, 0x6c, 0xde, 0x76, + 0xa4, 0xe8, 0xe0, 0x8d, 0x71, 0xfa, 0x62, 0xf0, 0x2e, 0x7b, 0xf4, 0xce, + 0x65, 0x18, 0x42, 0xde, 0x92, 0x1b, 0xdc, 0xc9, 0xa7, 0x8d, 0xa5, 0x91, + 0x0f, 0xa5, 0x1b, 0x89, 0xcf, 0x29, 0x10, 0x1d, 0x94, 0x78, 0x1b, 0xea, + 0x79, 0x35, 0x62, 0xd4, 0x29, 0xe6, 0x59, 0x8c, 0xc1, 0xd2, 0xf3, 0x32, + 0x71, 0x09, 0xce, 0x51, 0xd7, 0x14, 0x29, 0x92, 0xbf, 0xdf, 0x9a, 0x69, + 0xda, 0x61, 0x03, 0x0f, 0xa2, 0x0a, 0xab, 0x57, 0x1c, 0xca, 0xab, 0x42, + 0x63, 0x63, 0x1e, 0x35, 0x5d, 0x8d, 0xba, 0x6f, 0x4b, 0x6b, 0x5e, 0x7c, + 0xc0, 0x1e, 0xb7, 0xf4, 0x65, 0xbd, 0x13, 0x1c, 0xf2, 0xa9, 0x73, 0x38, + 0xc3, 0x47, 0xc9, 0x32, 0xf0, 0x30, 0x57, 0x05, 0x42, 0x52, 0xac, 0x72, + 0xee, 0x9f, 0x4e, 0x21, 0xbf, 0x38, 0x19, 0x6d, 0x48, 0xec, 0x97, 0xcb, + 0x70, 0x9e, 0xee, 0xb3, 0xa1, 0xaa, 0xa6, 0x7e, 0xe9, 0x16, 0xdf, 0xcd, + 0x1c, 0x56, 0xcf, 0xf0, 0x9f, 0x4d, 0xd1, 0x8c, 0x14, 0x50, 0x5d, 0x23, + 0x96, 0xe0, 0x1f, 0x61, 0x79, 0xbf, 0x44, 0xfd, 0xa2, 0x31, 0xf7, 0x4c, + 0x0c, 0x8d, 0x8c, 0x1b, 0xbf, 0x8d, 0x45, 0xbf, 0x0b, 0xd8, 0xfb, 0x6f, + 0xff, 0x15, 0xc0, 0x44, 0x7c, 0xb9, 0xb8, 0xf9, 0xef, 0x0d, 0x79, 0x11, + 0x3b, 0x79, 0xd2, 0x52, 0x89, 0x5a, 0xcd, 0x0f, 0x10, 0x92, 0x42, 0xfe, + 0xcf, 0x0a, 0x11, 0x8a, 0x8a, 0xda, 0xee, 0xc8, 0x6b, 0xd9, 0xab, 0xec, + 0xb4, 0x25, 0x6f, 0x8d, 0x68, 0x26, 0xe8, 0xdd, 0xf5, 0xa4, 0xe8, 0x65, + 0x37, 0x03, 0xb0, 0xad, 0x73, 0x3b, 0x4d, 0x74, 0x57, 0x7f, 0x0f, 0x6c, + 0xb0, 0x5d, 0x59, 0x80, 0x13, 0xa1, 0x6c, 0xb0, 0xed, 0x26, 0xec, 0x79, + 0x50, 0x5f, 0x5c, 0xb7, 0xa6, 0xae, 0xe8, 0x0a, 0x6d, 0x55, 0x9a, 0x7f, + 0x59, 0x23, 0xa3, 0x7e, 0x84, 0x7b, 0x3b, 0xfc, 0xde, 0xe1, 0xd9, 0x7c, + 0xd6, 0x87, 0xb3, 0x0e, 0xdb, 0xc1, 0x8c, 0x5e, 0x77, 0xb7, 0x23, 0xd7, + 0x14, 0xd4, 0x23, 0xb4, 0xac, 0x45, 0xbf, 0xfe, 0x40, 0x20, 0x4d, 0x91, + 0x20, 0x94, 0xbd, 0x58, 0xb1, 0x99, 0x69, 0xaf, 0x31, 0x68, 0xbd, 0x61, + 0x5e, 0x87, 0x81, 0x54, 0x4e, 0x2d, 0x03, 0xc2, 0xe2, 0xcd, 0xdc, 0x59, + 0xe5, 0x35, 0xcf, 0xb8, 0xfc, 0x65, 0xed, 0x46, 0xb3, 0x92, 0xe7, 0xf8, + 0x3a, 0x32, 0xaa, 0x0e, 0x5a, 0x82, 0x58, 0x4e, 0x77, 0xd8, 0x33, 0xc9, + 0xb0, 0x3e, 0xad, 0xa5, 0x92, 0xe9, 0xa9, 0x8c, 0x00, 0x72, 0x8f, 0xdc, + 0x77, 0x9d, 0x5c, 0x97, 0xd6, 0x58, 0x20, 0x1e, 0xf4, 0x55, 0x2d, 0xc0, + 0x30, 0xf0, 0x66, 0xda, 0x2d, 0x11, 0xac, 0xd4, 0x2d, 0xd5, 0x25, 0x42, + 0x1d, 0xce, 0x49, 0xb5, 0x95, 0x79, 0x9b, 0x6c, 0x65, 0xe0, 0x8a, 0xc5, + 0x9f, 0x75, 0xe3, 0xe6, 0xf8, 0xa6, 0x88, 0xd6, 0x93, 0x70, 0x4f, 0x89, + 0x94, 0x74, 0xbd, 0xef, 0xc2, 0x1a, 0x55, 0x74, 0x37, 0x44, 0x85, 0x1e, + 0xa9, 0xbb, 0x3f, 0x15, 0xc7, 0x84, 0x80, 0xa5, 0xab, 0xc3, 0x91, 0x8e, + 0xd6, 0x32, 0x46, 0x0d, 0xfa, 0xd1, 0x19, 0xd1, 0xfc, 0x02, 0xe2, 0x20, + 0xa6, 0xa9, 0xf7, 0xf4, 0xcc, 0x5b, 0x54, 0x4f, 0x4a, 0x73, 0x35, 0xda, + 0xf0, 0x31, 0x81, 0x1a, 0x82, 0xe7, 0xd4, 0xc8, 0xb4, 0x1d, 0x70, 0xa9, + 0x5d, 0x67, 0xb9, 0x7d, 0x4b, 0xcd, 0xa4, 0x81, 0xf9, 0xb2, 0x38, 0x07, + 0x16, 0xd5, 0x28, 0x82, 0xb9, 0x76, 0x5b, 0xa1, 0x09, 0x7a, 0xe7, 0x2a, + 0xcf, 0xc0, 0x3d, 0x2a, 0x42, 0x9a, 0xf3, 0xc8, 0x64, 0x15, 0x7c, 0x94, + 0xd0, 0x97, 0xee, 0x34, 0xb6, 0xf0, 0xb2, 0xba, 0x7e, 0xb2, 0xbb, 0x4e, + 0xbf, 0x88, 0xd0, 0x6b, 0xc5, 0x9c, 0xb9, 0xf2, 0x7d, 0xbf, 0x5d, 0x87, + 0xbc, 0x36, 0x4a, 0xd1, 0x1b, 0x6f, 0x40, 0x09, 0xba, 0x26, 0x51, 0xd6, + 0xc0, 0xaf, 0x27, 0xce, 0x27, 0x8d, 0x93, 0xa8, 0x6c, 0x91, 0xe7, 0x91, + 0x42, 0xc0, 0x68, 0x36, 0x5b, 0xd5, 0x56, 0x4c, 0xe2, 0x77, 0xc3, 0xac, + 0x56, 0xe3, 0x1c, 0xc2, 0xf9, 0x78, 0x02, 0x39, 0x7d, 0xed, 0x18, 0x2a, + 0x01, 0x48, 0xe6, 0xf6, 0x7e, 0x34, 0x50, 0xf4, 0x57, 0x56, 0x93, 0xdb, + 0x85, 0x1b, 0x1e, 0x1a, 0x6f, 0x3e, 0x07, 0x3c, 0xad, 0x3f, 0x8d, 0x75, + 0x53, 0xc3, 0x20, 0x72, 0x93, 0x28, 0xd2, 0x86, 0xc8, 0xa5, 0x90, 0xf2, + 0x5f, 0x13, 0xd5, 0xa5, 0xbe, 0x88, 0x9e, 0x9a, 0x57, 0x2c, 0x53, 0x3f, + 0x11, 0x25, 0x00, 0x00, 0x4a, 0x16, 0x8d, 0xd3, 0x3f, 0x2d, 0x3d, 0x88, + 0xbb, 0x4c, 0x4f, 0x9a, 0xb9, 0x97, 0x5f, 0xed, 0x71, 0xa9, 0x68, 0xd9, + 0x4a, 0x14, 0x24, 0xc7, 0xbe, 0xff, 0x85, 0x57, 0xa3, 0x21, 0xe3, 0x21, + 0x79, 0x1f, 0xd0, 0xbb, 0xb7, 0x73, 0xde, 0x60, 0x02, 0x4b, 0x8f, 0x7d, + 0xb3, 0xb3, 0x8a, 0xda, 0x4c, 0xf4, 0xb8, 0xf1, 0x31, 0xff, 0x32, 0x7b, + 0xd8, 0xfa, 0xb1, 0xcb, 0xb4, 0x58, 0xf5, 0xc8, 0x64, 0xdf, 0xfe, 0x3d, + 0x89, 0x52, 0x5c, 0x52, 0x95, 0xf3, 0xba, 0x0d, 0x1d, 0x2c, 0xc4, 0xf7, + 0x3c, 0x3b, 0x6f, 0x8e, 0xc7, 0xab, 0xad, 0x3d, 0x3d, 0x95, 0x9b, 0xc7, + 0x71, 0x36, 0xae, 0x08, 0xc3, 0x08, 0x79, 0xfa, 0x24, 0xee, 0xd9, 0xf9, + 0x63, 0xc7, 0xd9, 0x16, 0x19, 0x8e, 0x0d, 0xaf, 0x52, 0x87, 0x86, 0x7d, + 0xec, 0xe5, 0xea, 0x5a, 0xda, 0x86, 0x9d, 0x0e, 0x50, 0x53, 0x8c, 0x24, + 0xa8, 0x69, 0xc4, 0xf3, 0x85, 0x7b, 0x34, 0x67, 0x19, 0x35, 0xec, 0xd4, + 0xd4, 0x50, 0xe0, 0xe6, 0xe9, 0x29, 0x5b, 0x92, 0xee, 0xba, 0xa9, 0xef, + 0xf6, 0x35, 0x23, 0x8b, 0xdb, 0x48, 0x32, 0x25, 0x41, 0xf3, 0x55, 0x12, + 0x33, 0xc3, 0x6c, 0xed, 0x32, 0xe1, 0x64, 0x7a, 0x8d, 0xa2, 0x19, 0x5a, + 0x26, 0xf2, 0x83, 0xf1, 0xe4, 0x27, 0xdb, 0x67, 0xc3, 0x89, 0x37, 0xea, + 0x78, 0x19, 0xc6, 0xa3, 0x82, 0x84, 0x1c, 0xf3, 0x2b, 0xbe, 0xde, 0xba, + 0xe7, 0x60, 0x2e, 0xf5, 0x4e, 0xb6, 0x73, 0x29, 0xac, 0xc7, 0x55, 0xab, + 0x21, 0xe9, 0x95, 0x78, 0xd5, 0x8e, 0x27, 0xdc, 0x92, 0x5f, 0xc0, 0xcb, + 0xee, 0x66, 0x09, 0x0a, 0xfc, 0x94, 0x43, 0x44, 0x50, 0x35, 0x57, 0xf8, + 0x08, 0xf9, 0x97, 0xa2, 0x0e, 0xde, 0x81, 0xe1, 0xd1, 0xa0, 0x41, 0xfe, + 0xe6, 0x08, 0x6c, 0x98, 0x8c, 0x81, 0x46, 0x0e, 0xf9, 0x9a, 0x54, 0xfe, + 0xc3, 0x91, 0xe3, 0xd4, 0x46, 0xca, 0x52, 0xa2, 0x73, 0x9e, 0x4d, 0xa7, + 0xfd, 0xa1, 0x8e, 0x43, 0x28, 0xf5, 0xa3, 0xa2, 0x62, 0x20, 0x53, 0x62, + 0x05, 0x49, 0xba, 0x06, 0xe2, 0xeb, 0xba, 0xfb, 0x8e, 0xa0, 0x22, 0xc7, + 0xf9, 0xcc, 0x7f, 0x8b, 0xa8, 0x5d, 0x55, 0xd2, 0x24, 0xff, 0xdd, 0x2c, + 0xc1, 0xd0, 0x3d, 0xe4, 0x79, 0xea, 0xba, 0x62, 0xe5, 0xa2, 0x62, 0xf4, + 0x1f, 0xec, 0xb0, 0x07, 0xf2, 0x0d, 0x32, 0x84, 0x86, 0x81, 0x3d, 0x95, + 0xc1, 0x64, 0xfe, 0x9a, 0x3d, 0x8f, 0x4b, 0x6d, 0xfb, 0x0d, 0x42, 0xcf, + 0xbf, 0xdb, 0x51, 0xb2, 0x16, 0xa2, 0x35, 0xaa, 0xe7, 0x31, 0x54, 0xc2, + 0x87, 0xc6, 0xa5, 0x30, 0x71, 0x64, 0x65, 0xff, 0x41, 0x20, 0xb0, 0x83, + 0xdb, 0xb7, 0x95, 0xce, 0xd7, 0xcc, 0x7a, 0x77, 0xad, 0xb8, 0xb7, 0x4c, + 0xfc, 0x11, 0x05, 0x2b, 0xc4, 0xd4, 0xb6, 0x8b, 0xae, 0x13, 0xa5, 0x40, + 0x18, 0x6e, 0x0d, 0xe3, 0xc6, 0xb0, 0x81, 0x46, 0x46, 0x7e, 0x52, 0x0b, + 0x85, 0x4d, 0x98, 0xd9, 0x42, 0xdf, 0xde, 0x45, 0xc1, 0x5a, 0x33, 0x12, + 0x46, 0x26, 0xb3, 0x6f, 0xf2, 0x8b, 0x37, 0x6b, 0xfd, 0x08, 0xf4, 0x46, + 0x86, 0x89, 0x63, 0x63, 0x21, 0xe5, 0xa9, 0xb7, 0xd0, 0x09, 0x17, 0x52, + 0xee, 0xea, 0xdf, 0x97, 0xb7, 0x73, 0x2e, 0x54, 0x2c, 0x7b, 0x70, 0xd3, + 0xda, 0x26, 0x57, 0x1f, 0xb0, 0x19, 0xd9, 0x91, 0x18, 0x69, 0x75, 0x42, + 0x63, 0xcf, 0x6c, 0x8c, 0x98, 0x5e, 0x17, 0x99, 0x7e, 0x1d, 0xdc, 0x67, + 0x6d, 0x99, 0xd9, 0x02, 0x6e, 0x73, 0x90, 0x5a, 0x4f, 0x0a, 0xb4, 0x48, + 0xfb, 0xc5, 0xbd, 0xd2, 0x10, 0x05, 0xa6, 0x12, 0x68, 0x36, 0x28, 0x51, + 0x60, 0x1c, 0xa1, 0xe9, 0x90, 0x54, 0xa5, 0x53, 0xc3, 0x48, 0x9e, 0xd8, + 0x42, 0x52, 0x85, 0x0e, 0xff, 0xfe, 0xbf, 0xad, 0x3a, 0xa4, 0x57, 0x09, + 0x13, 0x38, 0x64, 0x15, 0x7c, 0xfd, 0xed, 0x91, 0x76, 0x44, 0x20, 0x84, + 0xd9, 0x90, 0xab, 0xfe, 0xfd, 0xd6, 0xab, 0xf1, 0xb3, 0x25, 0x21, 0x3d, + 0x97, 0x72, 0xb2, 0x95, 0xc5, 0x22, 0x80, 0xd9, 0x4a, 0x49, 0x9d, 0x99, + 0xc2, 0x4a, 0x9a, 0x59, 0xb3, 0x71, 0x75, 0x5b, 0xf9, 0x89, 0x7a, 0xdd, + 0xa9, 0xb3, 0xc3, 0xeb, 0x42, 0x91, 0xe2, 0x97, 0x30, 0x40, 0x48, 0x68, + 0x19, 0x3b, 0xf5, 0x7b, 0x4e, 0x33, 0x4b, 0x0c, 0xf3, 0xed, 0xda, 0x76, + 0x3f, 0xb0, 0x4b, 0x53, 0x85, 0x04, 0x33, 0x07, 0x53, 0xd8, 0x55, 0xa2, + 0xfb, 0x30, 0x2c, 0x66, 0xbd, 0x21, 0xf8, 0xfa, 0x20, 0x14, 0x9a, 0x0d, + 0x7f, 0xc9, 0x2f, 0x5b, 0x34, 0x29, 0x09, 0x16, 0xb5, 0x0a, 0x8d, 0xdf, + 0xa2, 0x84, 0x9a, 0xae, 0xe6, 0xa0, 0x50, 0x80, 0x31, 0x04, 0xd3, 0x0c, + 0x8f, 0xd1, 0x8a, 0xfd, 0xb4, 0xa5, 0xae, 0xf5, 0x3c, 0x62, 0xae, 0x45, + 0x70, 0xbb, 0x54, 0x62, 0xc8, 0x50, 0x71, 0x42, 0x85, 0xf6, 0x6f, 0xa0, + 0xf0, 0x10, 0x8a, 0x09, 0xbd, 0x71, 0x78, 0xa6, 0x5e, 0xe4, 0x03, 0x8f, + 0x3b, 0xd0, 0x5c, 0x37, 0x55, 0x1a, 0xc8, 0x57, 0x26, 0x62, 0x6c, 0xc4, + 0x67, 0x71, 0x9d, 0x97, 0xc0, 0xea, 0x35, 0x3e, 0x12, 0xd0, 0x2b, 0xc2, + 0x8f, 0x9e, 0xa6, 0x41, 0x48, 0x33, 0x83, 0x38, 0x37, 0x7e, 0xd4, 0xe3, + 0xee, 0x94, 0x8b, 0x81, 0xa4, 0x60, 0xdd, 0xdd, 0xc1, 0x8a, 0x7b, 0xda, + 0xa8, 0x46, 0xb8, 0x42, 0x3a, 0x25, 0xd6, 0x81, 0x89, 0x29, 0x21, 0xc2, + 0x0c, 0x5b, 0xfd, 0x3e, 0x8c, 0x65, 0x91, 0x52, 0xb3, 0x74, 0x1f, 0xd1, + 0x49, 0x7e, 0x1d, 0x59, 0x58, 0x96, 0xb5, 0xee, 0x32, 0xa4, 0xa8, 0x07, + 0x7c, 0xd1, 0x5b, 0x4b, 0xf8, 0x43, 0x5a, 0xa5, 0xcc, 0x60, 0xcc, 0x08, + 0x6a, 0x3c, 0x41, 0x66, 0x99, 0xe3, 0xa8, 0xe0, 0xb8, 0x87, 0xfc, 0x92, + 0xc0, 0x79, 0xc5, 0x3f, 0xd6, 0xc6, 0x8c, 0x01, 0xf4, 0xa5, 0x05, 0xad, + 0x51, 0xed, 0x04, 0xd7, 0x55, 0xc0, 0x73, 0x05, 0x0e, 0x73, 0xe5, 0x39, + 0x45, 0x5b, 0x95, 0x4a, 0x34, 0x07, 0x99, 0xdf, 0x4c, 0x35, 0xf5, 0x0c, + 0x27, 0x6d, 0xd1, 0x45, 0xf1, 0xfd, 0x24, 0xb7, 0xfe, 0xea, 0x11, 0x5d, + 0xa2, 0xc5, 0xa6, 0x81, 0x37, 0x1d, 0xc2, 0x31, 0x31, 0xfc, 0xe0, 0xf4, + 0xd7, 0xe9, 0x98, 0x8b, 0xe3, 0x70, 0x51, 0x62, 0xc8, 0x61, 0x6d, 0xec, + 0x75, 0x56, 0x71, 0xae, 0x88, 0xe0, 0x80, 0xf5, 0xb7, 0x85, 0x10, 0xb7, + 0x3d, 0x16, 0x78, 0x5f, 0x72, 0xab, 0x8f, 0x63, 0xc6, 0xd5, 0xa8, 0xc9, + 0x9c, 0xef, 0x8d, 0x9a, 0xc5, 0x4f, 0x63, 0xad, 0xc0, 0xf3, 0x1f, 0x69, + 0x0e, 0xce, 0x29, 0x92, 0xc1, 0x3b, 0xb0, 0xc5, 0xed, 0x0a, 0x7b, 0x92, + 0xd0, 0x4c, 0x9c, 0x82, 0xb0, 0x51, 0xf6, 0x33, 0x61, 0x3b, 0x76, 0x48, + 0x38, 0xf4, 0x7c, 0xaa, 0x52, 0x87, 0x15, 0x1a, 0xbe, 0xb8, 0xdc, 0x9b, + 0x16, 0xd2, 0x07, 0xf7, 0xf9, 0x74, 0xe0, 0xaf, 0x0e, 0x29, 0x05, 0xec, + 0x6c, 0x0e, 0x3b, 0xa7, 0xe7, 0xa4, 0xfc, 0xa4, 0xef, 0x57, 0x16, 0x7f, + 0x13, 0xbd, 0x8c, 0x42, 0x02, 0x55, 0x70, 0x56, 0xa5, 0xa9, 0x01, 0x29, + 0x12, 0x7d, 0x80, 0x46, 0x18, 0x8e, 0x39, 0x3f, 0x44, 0x55, 0xec, 0xef, + 0x60, 0x58, 0x7d, 0xce, 0x64, 0x8e, 0x9c, 0xea, 0xe4, 0x73, 0xd1, 0x48, + 0x9c, 0x3f, 0x92, 0xa0, 0x9a, 0x76, 0xa5, 0x5a, 0x13, 0x1f, 0x10, 0xb9, + 0xb7, 0xb1, 0xde, 0x49, 0x22, 0x58, 0xf4, 0x43, 0x5f, 0x03, 0x43, 0xc3, + 0x6c, 0xbf, 0x82, 0xaf, 0x88, 0x39, 0xfd, 0xb2, 0x28, 0x9b, 0x47, 0x3f, + 0x83, 0x3d, 0xd9, 0x7c, 0xf0, 0xc9, 0xc5, 0xa2, 0xb4, 0xd6, 0x0d, 0x59, + 0x51, 0x27, 0x60, 0x10, 0x5e, 0xbb, 0x18, 0xa6, 0x42, 0x4a, 0x9d, 0xc4, + 0x16, 0x0e, 0xb6, 0x57, 0x23, 0x03, 0x24, 0x27, 0xdc, 0x20, 0x56, 0x30, + 0x8b, 0x0f, 0xb6, 0xb7, 0x73, 0xf5, 0x36, 0x3e, 0xf6, 0x7a, 0x71, 0xa5, + 0x57, 0xcc, 0x6d, 0xc6, 0xf3, 0xdc, 0x35, 0xfb, 0x95, 0xf7, 0xa7, 0xd7, + 0x56, 0x38, 0xd4, 0x15, 0xe2, 0xd5, 0x6f, 0x70, 0x30, 0xc8, 0x7d, 0x8a, + 0x87, 0xe6, 0xd1, 0xe0, 0x50, 0x62, 0xde, 0xfa, 0x29, 0x40, 0x97, 0xa0, + 0x54, 0x63, 0x31, 0xd3, 0x08, 0x87, 0x0a, 0xdc, 0x6e, 0x5e, 0xab, 0x8d, + 0x16, 0xaf, 0x6e, 0x8b, 0x1a, 0x77, 0xf6, 0xd4, 0xe0, 0xbf, 0x59, 0xab, + 0xc7, 0xb0, 0x45, 0x18, 0xaa, 0xe6, 0x65, 0x6f, 0x7d, 0x13, 0xb2, 0xbf, + 0xb3, 0x66, 0x72, 0xfa, 0xfd, 0xee, 0xad, 0x07, 0x56, 0x51, 0x6a, 0xe2, + 0xff, 0xb2, 0xaf, 0x4d, 0xd1, 0xf2, 0x77, 0x35, 0x5e, 0x90, 0xcd, 0xe7, + 0xa8, 0x32, 0x4d, 0x9f, 0xbd, 0xa8, 0xce, 0xab, 0xf1, 0x49, 0x98, 0xb5, + 0x23, 0x5c, 0x62, 0x2d, 0x43, 0x31, 0x80, 0x87, 0xc2, 0xa8, 0xf5, 0xb9, + 0xb6, 0xae, 0x7f, 0x37, 0x13, 0xb8, 0x6b, 0x73, 0xf3, 0x56, 0x38, 0xa7, + 0x9b, 0x97, 0x69, 0x37, 0x00, 0xdc, 0xff, 0xfe, 0x58, 0xc9, 0x12, 0x47, + 0x75, 0x98, 0x1f, 0xad, 0xd8, 0xb5, 0xc8, 0x47, 0x4f, 0xd0, 0x72, 0x63, + 0x54, 0x25, 0x6c, 0x88, 0xc9, 0x9f, 0x3c, 0x82, 0xe0, 0xdd, 0x4c, 0xff, + 0x8e, 0xaf, 0x8f, 0x8e, 0xea, 0x84, 0x3f, 0x73, 0xdd, 0x9e, 0x18, 0x73, + 0x47, 0x70, 0xc7, 0xc7, 0x99, 0x65, 0xcf, 0xf3, 0xb6, 0x24, 0xed, 0x97, + 0x8f, 0xcd, 0x93, 0x1e, 0xff, 0x6e, 0x9c, 0xf1, 0x30, 0x14, 0x1a, 0x27, + 0x59, 0x6a, 0x0e, 0xf3, 0xe4, 0xfa, 0x1d, 0x65, 0xb5, 0x53, 0xe4, 0xab, + 0xb1, 0x3e, 0xe1, 0x91, 0xf4, 0x6d, 0x99, 0xca, 0x7d, 0x03, 0x08, 0x50, + 0xea, 0xa9, 0x39, 0x7f, 0x6d, 0xe7, 0x43, 0xfb, 0x64, 0xcc, 0x4b, 0x9e, + 0xa0, 0x26, 0xe4, 0x0e, 0xff, 0xb7, 0x11, 0x0a, 0x29, 0x50, 0x90, 0xd7, + 0x4d, 0x62, 0x9a, 0x4a, 0x23, 0xb7, 0xd3, 0x53, 0xde, 0x3a, 0xd1, 0xba, + 0xd3, 0x10, 0x59, 0xc6, 0xc5, 0x5e, 0xac, 0xf9, 0x61, 0x74, 0x54, 0xf4, + 0x27, 0x9f, 0x9a, 0x61, 0x13, 0xdc, 0xe5, 0x96, 0xe3, 0x95, 0x0d, 0xcc, + 0xbd, 0x81, 0x74, 0x79, 0x73, 0xef, 0x2e, 0x0b, 0x0f, 0x91, 0x65, 0x3c, + 0x26, 0x7c, 0x47, 0x10, 0x31, 0x0b, 0xfb, 0x41, 0x0c, 0xc2, 0xa8, 0xc4, + 0x0e, 0xbd, 0x0a, 0x8c, 0xa4, 0x80, 0x45, 0x57, 0x62, 0x0b, 0x4d, 0x44, + 0x5e, 0x59, 0x77, 0xfd, 0x3d, 0xf3, 0xd7, 0x92, 0x49, 0xc1, 0xcb, 0x8a, + 0x54, 0x56, 0x3b, 0xde, 0xcf, 0x16, 0x9a, 0x65, 0xbe, 0xac, 0x64, 0xe1, + 0xd4, 0xd4, 0x1e, 0xac, 0x6b, 0x4a, 0xad, 0xc4, 0x33, 0xac, 0xcb, 0x83, + 0xf4, 0x4d, 0xe8, 0xb6, 0xd7, 0x23, 0xd7, 0x71, 0x25, 0xa2, 0x25, 0x3d, + 0x7e, 0xf0, 0x3b, 0x7f, 0x61, 0x11, 0x56, 0xd4, 0x83, 0xc8, 0xc0, 0x29, + 0x38, 0x10, 0x73, 0xad, 0x6a, 0xb7, 0xb9, 0xd2, 0x2e, 0x9f, 0xae, 0x16, + 0x5e, 0xa6, 0x13, 0x1c, 0xc2, 0x17, 0x73, 0x43, 0x03, 0xdd, 0xa6, 0xaf, + 0x9a, 0x17, 0x31, 0xb8, 0x86, 0x97, 0xc2, 0xd6, 0xe6, 0xed, 0xd4, 0xe1, + 0x7d, 0xb9, 0xa6, 0x96, 0xc1, 0x4b, 0xcb, 0x11, 0x1e, 0xe1, 0xe0, 0xd2, + 0x28, 0x69, 0x68, 0x3b, 0x21, 0x17, 0x63, 0x0c, 0xc0, 0x49, 0x30, 0x22, + 0x3a, 0x59, 0x72, 0xe6, 0x47, 0xb4, 0xdc, 0xa8, 0x29, 0x1c, 0x89, 0xa6, + 0x3a, 0x77, 0x99, 0xea, 0x46, 0xce, 0x38, 0xda, 0x31, 0x88, 0xad, 0xe7, + 0x26, 0xce, 0xc6, 0x56, 0x04, 0x30, 0xfa, 0x01, 0xac, 0xbb, 0xe2, 0xb8, + 0x23, 0xe4, 0x9d, 0x4f, 0x77, 0x02, 0x00, 0x28, 0xf1, 0xe0, 0x19, 0x3f, + 0x22, 0x4f, 0x22, 0x69, 0x87, 0xc0, 0x4e, 0x26, 0x33, 0xfe, 0x6c, 0x70, + 0x56, 0x3b, 0x60, 0x5f, 0xfb, 0xf8, 0x43, 0xcf, 0x3f, 0xb9, 0xcb, 0x80, + 0x22, 0xbb, 0x0a, 0xa8, 0x1c, 0x3e, 0x7e, 0x4d, 0x42, 0x60, 0x5c, 0x8e, + 0xfa, 0x42, 0xb3, 0x95, 0xe7, 0x92, 0x6b, 0xec, 0x7a, 0x95, 0x88, 0x98, + 0xe3, 0xf9, 0x0d, 0xe5, 0x08, 0xf1, 0x26, 0x96, 0x2a, 0x81, 0x2b, 0x7c, + 0x0d, 0x12, 0xa0, 0x7f, 0x7b, 0x39, 0xf6, 0xcc, 0x1b, 0x2d, 0x2c, 0xe9, + 0x5b, 0x02, 0x9b, 0x5c, 0x94, 0x51, 0x13, 0xe8, 0xa0, 0x19, 0xce, 0xde, + 0x07, 0x1b, 0xda, 0x39, 0x14, 0xb5, 0x8b, 0xcf, 0x79, 0x3e, 0x2b, 0xb8, + 0x75, 0xab, 0x81, 0xee, 0x5e, 0x08, 0x33, 0xc3, 0x49, 0x5b, 0x4a, 0x9c, + 0x74, 0x34, 0xde, 0x08, 0x61, 0x03, 0x38, 0xe3, 0xd8, 0xff, 0xc5, 0xc0, + 0xb5, 0x40, 0xd5, 0x26, 0x57, 0x85, 0xf1, 0xb7, 0x77, 0xb6, 0x36, 0xe0, + 0x8d, 0x43, 0x3a, 0xef, 0xfe, 0x0f, 0xf7, 0xee, 0x67, 0x6c, 0x7b, 0xd1, + 0x83, 0xf6, 0x10, 0xda, 0x67, 0x04, 0x3a, 0x27, 0xd8, 0x3a, 0xcb, 0x9d, + 0x4c, 0xa6, 0x9a, 0xc7, 0xea, 0x07, 0xc6, 0x76, 0x79, 0x1b, 0x23, 0x4a, + 0x68, 0x2f, 0x14, 0x84, 0x42, 0x79, 0xe8, 0x1f, 0xf2, 0xe6, 0xac, 0x72, + 0xb0, 0xb0, 0xb6, 0x39, 0x95, 0x40, 0xa4, 0x6e, 0x54, 0x2e, 0xb7, 0xb5, + 0x13, 0x70, 0x48, 0x0d, 0x27, 0xed, 0x2c, 0xa2, 0x64, 0x53, 0xb4, 0x04, + 0x84, 0xab, 0xd8, 0xea, 0x2a, 0x8c, 0xac, 0x5b, 0x1d, 0xb8, 0xb2, 0xbe, + 0x55, 0x2b, 0x4a, 0x47, 0xfc, 0xe0, 0x15, 0x78, 0xb6, 0xd6, 0xff, 0x20, + 0xa8, 0x8a, 0xec, 0x8b, 0x30, 0xef, 0xc5, 0xc6, 0xec, 0xa0, 0xdf, 0xd3, + 0xc4, 0x2b, 0x4a, 0xdf, 0xef, 0x5c, 0x46, 0xb3, 0x31, 0xc7, 0x5f, 0x8f, + 0x1e, 0x99, 0x76, 0x81, 0x71, 0x61, 0xdb, 0xc3, 0xc4, 0x0f, 0x66, 0x7b, + 0xd7, 0x44, 0xc7, 0x8d, 0x12, 0x38, 0x71, 0x7c, 0xd8, 0x41, 0xf6, 0x8a, + 0xb9, 0xba, 0xd2, 0x1f, 0xa1, 0x27, 0x64, 0x67, 0x51, 0xb2, 0xaf, 0xea, + 0x02, 0x95, 0x79, 0x20, 0x0a, 0xc8, 0xaa, 0x03, 0x11, 0xb6, 0x8b, 0x7d, + 0x86, 0xb7, 0xef, 0x5e, 0x3f, 0x0b, 0x91, 0x47, 0xf0, 0x43, 0xb4, 0x54, + 0x1d, 0x16, 0x66, 0xe9, 0x63, 0x1a, 0x55, 0xaf, 0x34, 0xad, 0x11, 0x68, + 0x4d, 0x36, 0xb7, 0x0c, 0x6d, 0x4d, 0xed, 0xba, 0x14, 0xe8, 0xf6, 0xe2, + 0x15, 0x64, 0xb6, 0x15, 0x28, 0xbf, 0xd2, 0x4d, 0xb6, 0x6f, 0xca, 0x5f, + 0x81, 0x1b, 0xf0, 0x31, 0xf5, 0xd3, 0xe0, 0x06, 0xc7, 0xf3, 0x0c, 0x18, + 0x91, 0x45, 0x22, 0xa2, 0x30, 0x48, 0x82, 0xeb, 0x42, 0xfc, 0x8f, 0x2a, + 0xa3, 0x1a, 0x8d, 0x84, 0x28, 0x20, 0x16, 0x95, 0xd9, 0x66, 0x67, 0x2b, + 0xef, 0xc6, 0x6e, 0x56, 0x1c, 0x62, 0x74, 0x16, 0x5c, 0x3e, 0x17, 0xd0, + 0xb7, 0xdd, 0x70, 0xb6, 0x0e, 0x79, 0x46, 0xc5, 0x4e, 0x72, 0x46, 0x69, + 0xf5, 0xa1, 0x1c, 0x7b, 0xd5, 0x67, 0x5c, 0xb3, 0x46, 0x4d, 0x18, 0x31, + 0x47, 0x42, 0x20, 0xe6, 0x12, 0x84, 0x4e, 0x16, 0x0f, 0x4a, 0xd0, 0xc4, + 0x91, 0xa3, 0xbd, 0x91, 0xcd, 0x86, 0x4c, 0xcd, 0x4b, 0x2e, 0x62, 0x84, + 0xea, 0x19, 0x2d, 0x21, 0x1a, 0x64, 0xc4, 0xd2, 0x24, 0x92, 0x96, 0x04, + 0x66, 0xb5, 0x4a, 0xe4, 0xa9, 0xd6, 0xaf, 0x12, 0x9b, 0xb5, 0x59, 0xe0, + 0x5c, 0x84, 0x84, 0x7c, 0x68, 0x99, 0xd8, 0x23, 0xa2, 0x15, 0xa7, 0x82, + 0xa5, 0x66, 0x95, 0x8f, 0xfe, 0x57, 0xc1, 0x12, 0x6c, 0x89, 0xe5, 0x5b, + 0x5d, 0x64, 0xdb, 0x81, 0x4f, 0x77, 0x3c, 0xc8, 0x52, 0x4e, 0x2a, 0xd6, + 0x74, 0x3c, 0x4b, 0x11, 0xfc, 0xc1, 0x7c, 0x01, 0xba, 0x0f, 0x0f, 0x57, + 0x8a, 0xbe, 0x5b, 0x16, 0x88, 0x96, 0xe6, 0xe9, 0x60, 0xcf, 0x66, 0xe9, + 0xe6, 0x07, 0xb0, 0x0b, 0xa3, 0xa0, 0xad, 0xdf, 0x70, 0xd4, 0xcb, 0x2e, + 0x33, 0x2f, 0xe5, 0xf2, 0x1e, 0x0d, 0x74, 0x7a, 0xf9, 0x4a, 0x0f, 0x32, + 0xb4, 0xa1, 0xc9, 0xf5, 0x3f, 0x0a, 0x06, 0xf9, 0x67, 0x45, 0x9c, 0xd9, + 0x58, 0xd4, 0x0e, 0x72, 0x55, 0x47, 0x49, 0x9b, 0xab, 0x9c, 0x66, 0xe7, + 0x4d, 0x9a, 0x02, 0x1b, 0x41, 0xad, 0xe5, 0x8c, 0x7f, 0xa1, 0xdc, 0xad, + 0xcd, 0x74, 0xda, 0x9f, 0xfa, 0x87, 0x32, 0xc1, 0x07, 0x8e, 0x9b, 0xef, + 0x28, 0x2f, 0x17, 0x6d, 0xdb, 0x84, 0x4b, 0xa8, 0x7d, 0x31, 0xa8, 0x32, + 0xe4, 0x9a, 0x1e, 0x0e, 0xef, 0x68, 0xf4, 0xac, 0x03, 0x6c, 0x68, 0xcc, + 0x28, 0xbb, 0xfb, 0x21, 0xb8, 0x11, 0xd7, 0xf9, 0xe8, 0x24, 0x37, 0xdf, + 0xe0, 0xb2, 0xef, 0xd6, 0xec, 0xdf, 0xcf, 0xf5, 0x50, 0x19, 0xa3, 0xa9, + 0x1b, 0x01, 0x2e, 0x94, 0x42, 0xb0, 0x14, 0x5d, 0x0e, 0x37, 0x46, 0x4a, + 0x52, 0x53, 0x60, 0x6b, 0x89, 0xc9, 0xca, 0xed, 0x0a, 0x0c, 0x18, 0x33, + 0x3c, 0x40, 0x42, 0x76, 0x7a, 0x7d, 0xb6, 0x10, 0x29, 0x3e, 0x42, 0x75, + 0xa6, 0xbf, 0xcb, 0xd3, 0xdc, 0xe1, 0x00, 0x05, 0x08, 0x25, 0x67, 0x6c, + 0x72, 0xde, 0x26, 0x72, 0x88, 0xbe, 0xfa, 0x05, 0x57, 0x77, 0x78, 0x83, + 0xce, 0xd5, 0x44, 0x49, 0x8b, 0xab, 0xbc, 0xca, 0xd3, 0x1c, 0x34, 0x4a, + 0xaa, 0xc7, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x17, 0x22, 0x2a, 0x2f, 0x36, 0x3d, 0x43}; +#endif /* !MLD_CONFIG_KEYGEN_PCT */ +#endif /* !EXPECTED_SIGNATURES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/main.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/main.c new file mode 100644 index 0000000000..e199a37a96 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/main.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include +#include +#include + +#include "expected_signatures.h" +#include "mldsa_native_all.h" +#include "test_only_rng/notrandombytes.h" + +#define CHECK(x) \ + do \ + { \ + int rc; \ + rc = (x); \ + if (!rc) \ + { \ + fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \ + return 1; \ + } \ + } while (0) + +#define TEST_MSG \ + "This is a test message for ML-DSA digital signature algorithm!" +#define TEST_MSG_LEN (sizeof(TEST_MSG) - 1) + +#define TEST_CTX "test_context_123" +#define TEST_CTX_LEN (sizeof(TEST_CTX) - 1) + +static int test_mldsa44(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[MLDSA44_PUBLICKEYBYTES]; + uint8_t sk[MLDSA44_SECRETKEYBYTES]; + uint8_t sig[MLDSA44_BYTES]; + uint8_t sm[TEST_MSG_LEN + MLDSA44_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + MLDSA44_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-44\n"); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(mldsa44_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(mldsa44_signature(sig, &siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(mldsa44_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(mldsa44_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(mldsa44_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", MLDSA44_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", MLDSA44_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", MLDSA44_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature_44)); + CHECK(memcmp(sig, expected_signature_44, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} + +static int test_mldsa65(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[MLDSA65_PUBLICKEYBYTES]; + uint8_t sk[MLDSA65_SECRETKEYBYTES]; + uint8_t sig[MLDSA65_BYTES]; + uint8_t sm[TEST_MSG_LEN + MLDSA65_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + MLDSA65_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-65\n"); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(mldsa65_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(mldsa65_signature(sig, &siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(mldsa65_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(mldsa65_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(mldsa65_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", MLDSA65_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", MLDSA65_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", MLDSA65_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature_65)); + CHECK(memcmp(sig, expected_signature_65, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} + + +static int test_mldsa87(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[MLDSA87_PUBLICKEYBYTES]; + uint8_t sk[MLDSA87_SECRETKEYBYTES]; + uint8_t sig[MLDSA87_BYTES]; + uint8_t sm[TEST_MSG_LEN + MLDSA87_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + MLDSA87_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-87\n"); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(mldsa87_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(mldsa87_signature(sig, &siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(mldsa87_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(mldsa87_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(mldsa87_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", MLDSA87_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", MLDSA87_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", MLDSA87_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature_87)); + CHECK(memcmp(sig, expected_signature_87, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} + +int main(void) +{ + printf("ML-DSA multilevel_build Example\n"); + + if (test_mldsa44() != 0) + { + return 1; + } + + if (test_mldsa65() != 0) + { + return 1; + } + + if (test_mldsa87() != 0) + { + return 1; + } + + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/mldsa_native.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/mldsa_native.h new file mode 100644 index 0000000000..fd150a9df1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/mldsa_native.h @@ -0,0 +1,975 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_H +#define MLD_H + +/* + * Public API for mldsa-native + * + * This header defines the public API of a single build of mldsa-native. + * + * Make sure the configuration file is in the include path + * (this is "mldsa_native_config.h" by default, or MLD_CONFIG_FILE if defined). + * + * # Multi-level builds + * + * This header specifies a build of mldsa-native for a fixed security level. + * If you need multiple security levels, leave the security level unspecified + * in the configuration file and include this header multiple times, setting + * MLD_CONFIG_PARAMETER_SET accordingly for each, and #undef'ing the MLD_H + * guard to allow multiple inclusions. + * + * # Legacy configuration (deprecated) + * + * Instead of providing the config file used for the build, you can + * alternatively set the following configuration options prior to + * including this header. + * + * This method of configuration is deprecated. + * It will be removed in mldsa-native-v2. + * + * - MLD_CONFIG_API_PARAMETER_SET [required] + * + * The parameter set used for the build; 44, 65, or 87. + * + * - MLD_CONFIG_API_NAMESPACE_PREFIX [required] + * + * The namespace prefix used for the build. + * + * NOTE: + * For a multi-level build, you must include the 44/65/87 suffixes + * in MLD_CONFIG_API_NAMESPACE_PREFIX. + * + * - MLD_CONFIG_API_NO_SUPERCOP [optional] + * + * By default, this header will also expose the mldsa-native API in the + * SUPERCOP naming convention crypto_sign_xxx. If you don't want/need this, + * set MLD_CONFIG_API_NO_SUPERCOP. You must set this for a multi-level build. + * + * - MLD_CONFIG_API_CONSTANTS_ONLY [optional] + * + * If you don't want this header to expose any function declarations, + * but only constants for the sizes of key material, set + * MLD_CONFIG_API_CONSTANTS_ONLY. In this case, you don't need to set + * MLD_CONFIG_API_PARAMETER_SET or MLD_CONFIG_API_NAMESPACE_PREFIX, + * nor include a configuration. + * + * - MLD_CONFIG_API_QUALIFIER [optional] + * + * Qualifier to apply to external API. + * + ******************************************************************************/ + +/******************************* Key sizes ************************************/ + +/* Sizes of cryptographic material, per parameter set */ +/* See mldsa/src/params.h for the arithmetic expressions giving rise to these */ +/* check-magic: off */ +#define MLDSA44_SECRETKEYBYTES 2560 +#define MLDSA44_PUBLICKEYBYTES 1312 +#define MLDSA44_BYTES 2420 + +#define MLDSA65_SECRETKEYBYTES 4032 +#define MLDSA65_PUBLICKEYBYTES 1952 +#define MLDSA65_BYTES 3309 + +#define MLDSA87_SECRETKEYBYTES 4896 +#define MLDSA87_PUBLICKEYBYTES 2592 +#define MLDSA87_BYTES 4627 +/* check-magic: on */ + +/* Size of seed and randomness in bytes (level-independent) */ +#define MLDSA_SEEDBYTES 32 +#define MLDSA44_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA65_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA87_SEEDBYTES MLDSA_SEEDBYTES + +/* Size of CRH output in bytes (level-independent) */ +#define MLDSA_CRHBYTES 64 +#define MLDSA44_CRHBYTES MLDSA_CRHBYTES +#define MLDSA65_CRHBYTES MLDSA_CRHBYTES +#define MLDSA87_CRHBYTES MLDSA_CRHBYTES + +/* Size of TR output in bytes (level-independent) */ +#define MLDSA_TRBYTES 64 +#define MLDSA44_TRBYTES MLDSA_TRBYTES +#define MLDSA65_TRBYTES MLDSA_TRBYTES +#define MLDSA87_TRBYTES MLDSA_TRBYTES + +/* Size of randomness for signing in bytes (level-independent) */ +#define MLDSA_RNDBYTES 32 +#define MLDSA44_RNDBYTES MLDSA_RNDBYTES +#define MLDSA65_RNDBYTES MLDSA_RNDBYTES +#define MLDSA87_RNDBYTES MLDSA_RNDBYTES + +/* Sizes of cryptographic material, as a function of LVL=44,65,87 */ +#define MLDSA_SECRETKEYBYTES_(LVL) MLDSA##LVL##_SECRETKEYBYTES +#define MLDSA_PUBLICKEYBYTES_(LVL) MLDSA##LVL##_PUBLICKEYBYTES +#define MLDSA_BYTES_(LVL) MLDSA##LVL##_BYTES +#define MLDSA_SECRETKEYBYTES(LVL) MLDSA_SECRETKEYBYTES_(LVL) +#define MLDSA_PUBLICKEYBYTES(LVL) MLDSA_PUBLICKEYBYTES_(LVL) +#define MLDSA_BYTES(LVL) MLDSA_BYTES_(LVL) + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + +/****************************** Function API **********************************/ + +#define MLD_API_CONCAT_(x, y) x##y +#define MLD_API_CONCAT(x, y) MLD_API_CONCAT_(x, y) +#define MLD_API_CONCAT_UNDERSCORE(x, y) MLD_API_CONCAT(MLD_API_CONCAT(x, _), y) + +#if !defined(MLD_CONFIG_API_PARAMETER_SET) +/* Recommended configuration via same config file as used for the build. */ + +/* For now, we derive the legacy API configuration MLD_CONFIG_API_XXX from + * the config file. In mldsa-native-v2, this will be removed and we will + * exclusively work with MLD_CONFIG_XXX. */ + +/* You need to make sure the config file is in the include path. */ +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#define MLD_CONFIG_API_PARAMETER_SET MLD_CONFIG_PARAMETER_SET + +#if defined(MLD_CONFIG_MULTILEVEL_BUILD) +#define MLD_CONFIG_API_NAMESPACE_PREFIX \ + MLD_API_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_CONFIG_API_NAMESPACE_PREFIX MLD_CONFIG_NAMESPACE_PREFIX +#endif + +#if defined(MLD_CONFIG_NO_SUPERCOP) +#define MLD_CONFIG_API_NO_SUPERCOP +#endif + +#if defined(MLD_CONFIG_CONSTANTS_ONLY) +#define MLD_CONFIG_API_CONSTANTS_ONLY +#endif + +#if defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_CONFIG_API_QUALIFIER MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#else /* !MLD_CONFIG_API_PARAMETER_SET */ +#define MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_PARAMETER_SET */ + +#define MLD_API_NAMESPACE(sym) \ + MLD_API_CONCAT_UNDERSCORE(MLD_CONFIG_API_NAMESPACE_PREFIX, sym) + +#if defined(__GNUC__) || defined(clang) +#define MLD_API_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_API_MUST_CHECK_RETURN_VALUE +#endif + +#if defined(MLD_CONFIG_API_QUALIFIER) +#define MLD_API_QUALIFIER MLD_CONFIG_API_QUALIFIER +#else +#define MLD_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_API_CONSTANTS_ONLY) + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************************* + * Name: crypto_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: + * input random seed + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair_internal)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t seed[MLDSA_SEEDBYTES] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: If MLD_CONFIG_KEYGEN_PCT is enabled and the + * PCT check failed. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return -1 in that case. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_extmu + * + * Description: Computes signature. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_extmu)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t *sm: pointer to output signed message (allocated array + * with MLDSA{44,65,87}_BYTES + mlen bytes), can be + * equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(sign)( + uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_extmu)( + const uint8_t *sig, size_t siglen, const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_open + * + * Description: Verify signed message. + * + * Arguments: + * - uint8_t *m: pointer to output message (allocated array with + * smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(open)( + uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: crypto_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *ph, size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_shake256)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_shake256)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/* Maximum formatted domain separation message length */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +size_t MLD_API_NAMESPACE(prepare_domain_separation_prefix)( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg); + +/************************************************* + * Name: crypto_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[CRYPTO_SECRETKEYBYTES]: input secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(pk_from_sk)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +#ifdef __cplusplus +} +#endif + +/****************************** SUPERCOP API *********************************/ + +#if !defined(MLD_CONFIG_API_NO_SUPERCOP) +/* Export API in SUPERCOP naming scheme CRYPTO_xxx / crypto_sign_xxx */ +#define CRYPTO_SECRETKEYBYTES MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_PUBLICKEYBYTES MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_BYTES MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET) + +#define crypto_sign_keypair MLD_API_NAMESPACE(keypair) +#define crypto_sign_signature MLD_API_NAMESPACE(signature) +#define crypto_sign MLD_API_NAMESPACE(sign) +#define crypto_sign_verify MLD_API_NAMESPACE(verify) +#define crypto_sign_open MLD_API_NAMESPACE(open) + +#else /* !MLD_CONFIG_API_NO_SUPERCOP */ + +/* If the SUPERCOP API is not needed, we can undefine the various helper macros + * above. Otherwise, they are needed for lazy evaluation of crypto_sign_xxx. */ +#if !defined(MLD_API_LEGACY_CONFIG) +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_QUALIFIER +#endif /* !MLD_API_LEGACY_CONFIG */ + +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_NAMESPACE +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_QUALIFIER +#undef MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_NO_SUPERCOP */ +#endif /* !MLD_CONFIG_API_CONSTANTS_ONLY */ + + +/***************************** Memory Usage **********************************/ + +/* + * By default mldsa-native performs all memory allocations on the stack. + * Alternatively, mldsa-native supports custom allocation of large structures + * through the `MLD_CONFIG_CUSTOM_ALLOC_FREE` configuration option. + * See mldsa_native_config.h for details. + * + * `MLD_TOTAL_ALLOC_{44,65,87}_{KEYPAIR,SIGN,VERIFY}` indicates the maximum + * (accumulative) allocation via MLD_ALLOC for each parameter set and operation. + * Note that some stack allocation remains even + * when using custom allocators, so these values are lower than total stack + * usage with the default stack-only allocation. + * + * These constants may be used to implement custom allocations using a + * fixed-sized buffer and a simple allocator (e.g., bump allocator). + */ +/* check-magic: off */ +#if defined(MLD_API_LEGACY_CONFIG) || !defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 45248 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 56640 +#define MLD_TOTAL_ALLOC_44_SIGN 52896 +#define MLD_TOTAL_ALLOC_44_VERIFY 38816 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 71872 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 85856 +#define MLD_TOTAL_ALLOC_65_SIGN 80576 +#define MLD_TOTAL_ALLOC_65_VERIFY 62432 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 112832 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 130816 +#define MLD_TOTAL_ALLOC_87_SIGN 123584 +#define MLD_TOTAL_ALLOC_87_VERIFY 99552 +#else /* MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM */ +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 32992 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 36192 +#define MLD_TOTAL_ALLOC_44_SIGN 32448 +#define MLD_TOTAL_ALLOC_44_VERIFY 22464 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 46304 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 50048 +#define MLD_TOTAL_ALLOC_65_SIGN 44768 +#define MLD_TOTAL_ALLOC_65_VERIFY 30720 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 62688 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 66336 +#define MLD_TOTAL_ALLOC_87_SIGN 59104 +#define MLD_TOTAL_ALLOC_87_VERIFY 41216 +#endif /* !(MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM) */ +/* check-magic: on */ + +/* + * MLD_TOTAL_ALLOC_*_KEYPAIR adapts based on MLD_CONFIG_KEYGEN_PCT. + * For legacy config, we don't know which options are used, so assume + * the worst case (PCT enabled). + */ +#if defined(MLD_API_LEGACY_CONFIG) || defined(MLD_CONFIG_KEYGEN_PCT) +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#else +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#endif + +#define MLD_MAX3_(a, b, c) \ + ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c))) + +/* + * `MLD_TOTAL_ALLOC_{44,65,87}` is the maximum across all operations for each + * parameter set. + */ +#define MLD_TOTAL_ALLOC_44 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_44_KEYPAIR, MLD_TOTAL_ALLOC_44_SIGN, \ + MLD_TOTAL_ALLOC_44_VERIFY) +#define MLD_TOTAL_ALLOC_65 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_65_KEYPAIR, MLD_TOTAL_ALLOC_65_SIGN, \ + MLD_TOTAL_ALLOC_65_VERIFY) +#define MLD_TOTAL_ALLOC_87 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_87_KEYPAIR, MLD_TOTAL_ALLOC_87_SIGN, \ + MLD_TOTAL_ALLOC_87_VERIFY) + +#endif /* !MLD_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/mldsa_native_config.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/mldsa_native_config.h new file mode 100644 index 0000000000..39a1008194 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/mldsa_native_config.h @@ -0,0 +1,739 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/* + * Test configuration: Multilevel build config + * + * This configuration differs from the default mldsa/mldsa_native_config.h in + * the following places: + * - MLD_CONFIG_NO_SUPERCOP + * - MLD_CONFIG_MULTILEVEL_BUILD + * - MLD_CONFIG_NAMESPACE_PREFIX + */ + + +#ifndef MLD_CONFIG_H +#define MLD_CONFIG_H + +/****************************************************************************** + * Name: MLD_CONFIG_PARAMETER_SET + * + * Description: Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * If you want to support multiple parameter sets, build the + * library multiple times and set MLD_CONFIG_MULTILEVEL_BUILD. + * See MLD_CONFIG_MULTILEVEL_BUILD for how to do this while + * minimizing code duplication. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of the default configuration file mldsa/mldsa_native_config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * then configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + * + *****************************************************************************/ +/* No need to set this -- we _are_ already in a custom config */ +/* #define MLD_CONFIG_FILE "mldsa_native_config.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_NAMESPACE_PREFIX + * + * Description: The prefix to use to namespace global symbols from mldsa/. + * + * In a multi-level build, level-dependent symbols will + * additionally be prefixed with the parameter set (44/65/87). + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_NAMESPACE_PREFIX mldsa + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_BUILD + * + * Description: Set this if the build is part of a multi-level build supporting + * multiple parameter sets. + * + * If you need only a single parameter set, keep this unset. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them. + * + * See examples/multilevel_build for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_MULTILEVEL_BUILD + +/****************************************************************************** + * Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_EXTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_RANDOMIZED_API + * + * Description: If this option is set, mldsa-native will be built without the + * randomized API functions (crypto_sign_keypair, + * crypto_sign, crypto_sign_signature, and + * crypto_sign_signature_extmu). + * This allows users to build mldsa-native without providing a + * randombytes() implementation if they only need the + * internal deterministic API + * (crypto_sign_keypair_internal, crypto_sign_signature_internal). + * + * NOTE: This option is incompatible with MLD_CONFIG_KEYGEN_PCT + * as the current PCT implementation requires + * crypto_sign_signature(). + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_RANDOMIZED_API */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_SUPERCOP + * + * Description: By default, mldsa_native.h exposes the mldsa-native API in the + * SUPERCOP naming convention (crypto_sign_xxx). If you don't need + * this, set MLD_CONFIG_NO_SUPERCOP. + * + * NOTE: You must set this for a multi-level build as the SUPERCOP + * naming does not disambiguate between the parameter sets. + * + *****************************************************************************/ +#define MLD_CONFIG_NO_SUPERCOP + +/****************************************************************************** + * Name: MLD_CONFIG_CONSTANTS_ONLY + * + * Description: If you only need the size constants (MLDSA_PUBLICKEYBYTES, etc.) + * but no function declarations, set MLD_CONFIG_CONSTANTS_ONLY. + * + * This only affects the public header mldsa_native.h, not + * the implementation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONSTANTS_ONLY */ + +/****************************************************************************** + * + * Build-only configuration options + * + * The remaining configurations are build-options only. + * They do not affect the API described in mldsa_native.h. + * + *****************************************************************************/ + +#if defined(MLD_BUILD_INTERNAL) +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_WITH_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, all MLD_CONFIG_PARAMETER_SET-independent + * code will be included in the build, including code needed only + * for other parameter sets. + * + * Example: TODO: add example + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_WITH_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_NO_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, no MLD_CONFIG_PARAMETER_SET-independent code + * will be included in the build. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * + * Description: This is only relevant for single compilation unit (SCU) + * builds of mldsa-native. In this case, it determines whether + * directives defined in parameter-set-independent headers should + * be #undef'ined or not at the of the SCU file. This is needed + * in multilevel builds. + * + * See examples/multilevel_build_native for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * + * Description: Determines whether an native arithmetic backend should be used. + * + * The arithmetic backend covers performance critical functions + * such as the number-theoretic transform (NTT). + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the arithmetic backend to be use is + * determined by MLD_CONFIG_ARITH_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_ARITH_BACKEND_FILE + * + * Description: The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * + * Description: Determines whether an native FIPS202 backend should be used. + * + * The FIPS202 backend covers 1x/2x/4x-fold Keccak-f1600, which is + * the performance bottleneck of SHA3 and SHAKE. + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the FIPS202 backend to be use is + * determined by MLD_CONFIG_FIPS202_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_BACKEND_FILE + * + * Description: The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202X4_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202-X4 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202x4.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ZEROIZE + * + * Description: In compliance with @[FIPS204, Section 3.6.3], mldsa-native, + * zeroizes intermediate stack buffers before returning from + * function calls. + * + * Set this option and define `mld_zeroize` if you want to + * use a custom method to zeroize intermediate stack buffers. + * The default implementation uses SecureZeroMemory on Windows + * and a memset + compiler barrier otherwise. If neither of those + * is available on the target platform, compilation will fail, + * and you will need to use MLD_CONFIG_CUSTOM_ZEROIZE to provide + * a custom implementation of `mld_zeroize()`. + * + * WARNING: + * The explicit stack zeroization conducted by mldsa-native + * reduces the likelihood of data leaking on the stack, but + * does not eliminate it! The C standard makes no guarantee about + * where a compiler allocates structures and whether/where it makes + * copies of them. Also, in addition to entire structures, there + * may also be potentially exploitable leakage of individual values + * on the stack. + * + * If you need bullet-proof zeroization of the stack, you need to + * consider additional measures instead of what this feature + * provides. In this case, you can set mld_zeroize to a + * no-op. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void mld_zeroize(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * Description: mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to provided by the + * consumer. + * + * If this option is not set, mldsa-native expects a function + * int randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mld_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_RANDOMBYTES + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) + { + ... your implementation ... + return 0; + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + * + * Description: mldsa-native backends may rely on specific hardware features. + * Those backends will only be included in an mldsa-native build + * if support for the respective features is enabled at + * compile-time. However, when building for a heteroneous set + * of CPUs to run the resulting binary/library on, feature + * detection at _runtime_ is needed to decided whether a backend + * can be used or not. + * + * Set this option and define `mld_sys_check_capability` if you + * want to use a custom method to dispatch between implementations. + * + * Return value 1 indicates that a capability is supported. + * Return value 0 indicates that a capability is not supported. + * + * If this option is not set, mldsa-native uses compile-time + * feature detection only to decide which backend to use. + * + * If you compile mldsa-native on a system with different + * capabilities than the system that the resulting binary/library + * will be run on, you must use this option. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) + { + ... your implementation ... + } +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ALLOC_FREE [EXPERIMENTAL] + * + * Description: Set this option and define `MLD_CUSTOM_ALLOC` and + * `MLD_CUSTOM_FREE` if you want to use custom allocation for + * large local structures or buffers. + * + * By default, all buffers/structures are allocated on the stack. + * If this option is set, most of them will be allocated via + * MLD_CUSTOM_ALLOC. + * + * Parameters to MLD_CUSTOM_ALLOC: + * - T* v: Target pointer to declare. + * - T: Type of structure to be allocated + * - N: Number of elements to be allocated. + * + * Parameters to MLD_CUSTOM_FREE: + * - T* v: Target pointer to free. May be NULL. + * - T: Type of structure to be freed. + * - N: Number of elements to be freed. + * + * WARNING: This option is experimental! + * Its scope, configuration and function/macro signatures may + * change at any time. We expect a stable API for v2. + * + * NOTE: Even if this option is set, some allocations further down + * the call stack will still be made from the stack. Those will + * likely be added to the scope of this option in the future. + * + * NOTE: MLD_CUSTOM_ALLOC need not guarantee a successful + * allocation nor include error handling. Upon failure, the + * target pointer should simply be set to NULL. The calling + * code will handle this case and invoke MLD_CUSTOM_FREE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ALLOC_FREE + #if !defined(__ASSEMBLER__) + #include + #define MLD_CUSTOM_ALLOC(v, T, N) \ + T* (v) = (T *)aligned_alloc(MLD_DEFAULT_ALIGN, \ + MLD_ALIGN_UP(sizeof(T) * (N))) + #define MLD_CUSTOM_FREE(v, T, N) free(v) + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMCPY + * + * Description: Set this option and define `mld_memcpy` if you want to + * use a custom method to copy memory instead of the standard + * library memcpy function. + * + * The custom implementation must have the same signature and + * behavior as the standard memcpy function: + * void *mld_memcpy(void *dest, const void *src, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMCPY + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMSET + * + * Description: Set this option and define `mld_memset` if you want to + * use a custom method to set memory instead of the standard + * library memset function. + * + * The custom implementation must have the same signature and + * behavior as the standard memset function: + * void *mld_memset(void *s, int c, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMSET + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memset(void *s, int c, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_INTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of internal API. + * + * The primary use case for this option are single-CU builds, + * in which case this option can be set to `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_INTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CT_TESTING_ENABLED + * + * Description: If set, mldsa-native annotates data as secret / public using + * valgrind's annotations VALGRIND_MAKE_MEM_UNDEFINED and + * VALGRIND_MAKE_MEM_DEFINED, enabling various checks for secret- + * dependent control flow of variable time execution (depending + * on the exact version of valgrind installed). + * + *****************************************************************************/ +/* #define MLD_CONFIG_CT_TESTING_ENABLED */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * and MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT + * + * Description: Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, crypto_sign_keypair_internal and + * crypto_sign_keypair will return a non-zero error code if the + * PCT failed. + * + * NOTE: This feature will drastically lower the performance of + * key generation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * Description: If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "src/src.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Description: Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * NOTE: Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + * + *****************************************************************************/ +/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER + * + * Description: Set this to add a context parameter that is provided to public + * API functions and is then available in custom callbacks. + * + * The type of the context parameter is configured via + * MLD_CONFIG_CONTEXT_PARAMETER_TYPE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER_TYPE + * + * Description: Set this to define the type for the context parameter used by + * MLD_CONFIG_CONTEXT_PARAMETER. + * + * This is only relevant if MLD_CONFIG_CONTEXT_PARAMETER is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER_TYPE void* */ + +/****************************************************************************** + * Name: MLD_CONFIG_REDUCE_RAM [EXPERIMENTAL] + * + * Description: Set this to reduce RAM usage. + * This trades memory for performance. + * + * For expected memory usage, see the MLD_TOTAL_ALLOC_* constants + * defined in mldsa_native.h. + * + * This option is useful for embedded systems with tight RAM + * constraints but relaxed performance requirements. + * + * WARNING: This option is experimental! + * CBMC proofs do not currently cover this configuration option. + * Its scope and configuration may change at any time. + * + *****************************************************************************/ +/* #define MLD_CONFIG_REDUCE_RAM */ + +/************************* Config internals ********************************/ + +#endif /* MLD_BUILD_INTERNAL */ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace is + * + * PQCP_MLDSA_NATIVE_MLDSA_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_ + */ + +#if MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65 +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87 +#endif + +#endif /* !MLD_CONFIG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/cbmc.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/cbmc.h new file mode 100644 index 0000000000..8ed1ecb06b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/cbmc.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_CBMC_H +#define MLD_CBMC_H +/*************************************************** + * Basic replacements for __CPROVER_XXX contracts + ***************************************************/ +#ifndef CBMC + +#define __contract__(x) +#define __loop__(x) +#define cassert(x) + +#else /* !CBMC */ + +#include + +#define __contract__(x) x +#define __loop__(x) x + +/* https://diffblue.github.io/cbmc/contracts-assigns.html */ +#define assigns(...) __CPROVER_assigns(__VA_ARGS__) + +/* https://diffblue.github.io/cbmc/contracts-requires-ensures.html */ +#define requires(...) __CPROVER_requires(__VA_ARGS__) +#define ensures(...) __CPROVER_ensures(__VA_ARGS__) +/* https://diffblue.github.io/cbmc/contracts-loops.html */ +#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__) +#define decreases(...) __CPROVER_decreases(__VA_ARGS__) +/* cassert to avoid confusion with in-built assert */ +#define cassert(x) __CPROVER_assert(x, "cbmc assertion failed") +#define assume(...) __CPROVER_assume(__VA_ARGS__) + +/*************************************************** + * Macros for "expression" forms that may appear + * _inside_ top-level contracts. + ***************************************************/ + +/* + * function return value - useful inside ensures + * https://diffblue.github.io/cbmc/contracts-functions.html + */ +#define return_value (__CPROVER_return_value) + +/* + * assigns l-value targets + * https://diffblue.github.io/cbmc/contracts-assigns.html + */ +#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__) +#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__) +#define same_object(...) __CPROVER_same_object(__VA_ARGS__) + +/* + * Pointer-related predicates + * https://diffblue.github.io/cbmc/contracts-memory-predicates.html + */ +#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__) +#define readable(...) __CPROVER_r_ok(__VA_ARGS__) +#define writeable(...) __CPROVER_w_ok(__VA_ARGS__) + +/* Maximum supported buffer size + * + * Larger buffers may be supported, but due to internal modeling constraints + * in CBMC, the proofs of memory- and type-safety won't be able to run. + * + * If you find yourself in need for a buffer size larger than this, + * please contact the maintainers, so we can prioritize work to relax + * this somewhat artificial bound. + */ +#define MLD_MAX_BUFFER_SIZE (SIZE_MAX >> 12) + + +/* + * History variables + * https://diffblue.github.io/cbmc/contracts-history-variables.html + */ +#define old(...) __CPROVER_old(__VA_ARGS__) +#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__) + +/* + * Quantifiers + * Note that the range on qvar is _exclusive_ between qvar_lb .. qvar_ub + * https://diffblue.github.io/cbmc/contracts-quantifiers.html + */ + +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define forall(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> (predicate) \ + } + +#define exists(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_exists \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) && (predicate) \ + } +/* clang-format on */ + +/*************************************************** + * Convenience macros for common contract patterns + ***************************************************/ +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define CBMC_CONCAT_(left, right) left##right +#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right) + +#define array_bound_core(qvar, qvar_lb, qvar_ub, array_var, \ + value_lb, value_ub) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + (((int)(value_lb) <= ((array_var)[(qvar)])) && \ + (((array_var)[(qvar)]) < (int)(value_ub))) \ + } + +#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \ + array_bound_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (qvar_lb), \ + (qvar_ub), (array_var), (value_lb), (value_ub)) + +#define array_unchanged_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (int32_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged(array_var, N) \ + array_unchanged_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) + +#define array_unchanged_u64_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (uint64_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged_u64(array_var, N) \ + array_unchanged_u64_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) +/* clang-format on */ + +/* Wrapper around array_bound operating on absolute values. + * + * The absolute value bound `k` is exclusive. + * + * Note that since the lower bound in array_bound is inclusive, we have to + * raise it by 1 here. + */ +#define array_abs_bound(arr, lb, ub, k) \ + array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k)) + +#endif /* CBMC */ + +#endif /* !MLD_CBMC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/common.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/common.h new file mode 100644 index 0000000000..4a5bc8109d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/common.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_COMMON_H +#define MLD_COMMON_H + +#define MLD_BUILD_INTERNAL + +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#include "params.h" +#include "sys.h" + +/* Internal and public API have external linkage by default, but + * this can be overwritten by the user, e.g. for single-CU builds. */ +#if !defined(MLD_CONFIG_INTERNAL_API_QUALIFIER) +#define MLD_INTERNAL_API +#else +#define MLD_INTERNAL_API MLD_CONFIG_INTERNAL_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_EXTERNAL_API +#else +#define MLD_EXTERNAL_API MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#if defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) || \ + defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) +#define MLD_MULTILEVEL_BUILD +#endif + +#define MLD_CONCAT_(x1, x2) x1##x2 +#define MLD_CONCAT(x1, x2) MLD_CONCAT_(x1, x2) + +#if defined(MLD_MULTILEVEL_BUILD) +#define MLD_ADD_PARAM_SET(s) MLD_CONCAT(s, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_ADD_PARAM_SET(s) s +#endif + +#define MLD_NAMESPACE_PREFIX MLD_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, _) +#define MLD_NAMESPACE_PREFIX_KL \ + MLD_CONCAT(MLD_ADD_PARAM_SET(MLD_CONFIG_NAMESPACE_PREFIX), _) + +/* Functions are prefixed by MLD_CONFIG_NAMESPACE_PREFIX. + * + * If multiple parameter sets are used, functions depending on the parameter + * set are additionally prefixed with 44/65/87. See mldsa_native_config.h. + * + * Example: If MLD_CONFIG_NAMESPACE_PREFIX is PQCP_MLDSA_NATIVE, then + * MLD_NAMESPACE_KL(keypair) becomes PQCP_MLDSA_NATIVE44_keypair/ + * PQCP_MLDSA_NATIVE65_keypair/PQCP_MLDSA_NATIVE87_keypair. + */ +#define MLD_NAMESPACE(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX, s) +#define MLD_NAMESPACE_KL(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX_KL, s) + +/* On Apple platforms, we need to emit leading underscore + * in front of assembly symbols. We thus introducee a separate + * namespace wrapper for ASM symbols. */ +#if !defined(__APPLE__) +#define MLD_ASM_NAMESPACE(sym) MLD_NAMESPACE(sym) +#else +#define MLD_ASM_NAMESPACE(sym) MLD_CONCAT(_, MLD_NAMESPACE(sym)) +#endif + +/* + * On X86_64 if control-flow protections (CET) are enabled (through + * -fcf-protection=), we add an endbr64 instruction at every global function + * label. See sys.h for more details + */ +#if defined(MLD_SYS_X86_64) +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : MLD_CET_ENDBR +#else +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : +#endif + +/* We aim to simplify the user's life by supporting builds where + * all source files are included, even those that are not needed. + * Those files are appropriately guarded and will be empty when unneeded. + * The following is to avoid compilers complaining about this. */ +#define MLD_EMPTY_CU(s) extern int MLD_NAMESPACE_KL(empty_cu_##s); + +/* MLD_CONFIG_NO_ASM takes precedence over MLD_USE_NATIVE_XXX */ +#if defined(MLD_CONFIG_NO_ASM) +#undef MLD_CONFIG_USE_NATIVE_BACKEND_ARITH +#undef MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, but MLD_CONFIG_ARITH_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, but MLD_CONFIG_FIPS202_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_NO_RANDOMIZED_API) && defined(MLD_CONFIG_KEYGEN_PCT) +#error Bad configuration: MLD_CONFIG_NO_RANDOMIZED_API is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires crypto_sign_signature() +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#include MLD_CONFIG_ARITH_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#include MLD_CONFIG_FIPS202_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "fips202/native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#define MLD_FIPS202_HEADER_FILE "fips202/fips202.h" +#else +#define MLD_FIPS202_HEADER_FILE MLD_CONFIG_FIPS202_CUSTOM_HEADER +#endif + +#if !defined(MLD_CONFIG_FIPS202X4_CUSTOM_HEADER) +#define MLD_FIPS202X4_HEADER_FILE "fips202/fips202x4.h" +#else +#define MLD_FIPS202X4_HEADER_FILE MLD_CONFIG_FIPS202X4_CUSTOM_HEADER +#endif + +/* Standard library function replacements */ +#if !defined(__ASSEMBLER__) +#if !defined(MLD_CONFIG_CUSTOM_MEMCPY) +#include +#define mld_memcpy memcpy +#endif + +#if !defined(MLD_CONFIG_CUSTOM_MEMSET) +#include +#define mld_memset memset +#endif + +/* Allocation macros for large local structures + * + * MLD_ALLOC(v, T, N) declares T *v and attempts to point it to an T[N] + * MLD_FREE(v, T, N) zeroizes and frees the allocation + * + * Default implementation uses stack allocation. + * Can be overridden by setting the config option MLD_CONFIG_CUSTOM_ALLOC_FREE + * and defining MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE. + */ +#if defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) != \ + (defined(MLD_CUSTOM_ALLOC) && defined(MLD_CUSTOM_FREE)) +#error Bad configuration: MLD_CONFIG_CUSTOM_ALLOC_FREE must be set together with MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE +#endif + +/* + * If the integration wants to provide a context parameter for use in + * platform-specific hooks, then it should define this parameter. + * + * The MLD_CONTEXT_PARAMETERS_n macros are intended to be used with macros + * defining the function names and expand to either pass or discard the context + * argument as required by the current build. If there is no context parameter + * requested then these are removed from the prototypes and from all calls. + */ +#ifdef MLD_CONFIG_CONTEXT_PARAMETER +#define MLD_CONTEXT_PARAMETERS_0(context) (context) +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0, context) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1, context) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) \ + (arg0, arg1, arg2, context) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3, context) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4, context) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, context) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, context) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, context) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, context) +#else /* MLD_CONFIG_CONTEXT_PARAMETER */ +#define MLD_CONTEXT_PARAMETERS_0(context) () +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) (arg0, arg1, arg2) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) +#endif /* !MLD_CONFIG_CONTEXT_PARAMETER */ + +#if defined(MLD_CONFIG_CONTEXT_PARAMETER_TYPE) != \ + defined(MLD_CONFIG_CONTEXT_PARAMETER) +#error MLD_CONFIG_CONTEXT_PARAMETER_TYPE must be defined if and only if MLD_CONFIG_CONTEXT_PARAMETER is defined +#endif + +#if !defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) +/* Default: stack allocation */ + +#define MLD_ALLOC(v, T, N, context) \ + MLD_ALIGN T mld_alloc_##v[N]; \ + T *v = mld_alloc_##v + +/* TODO: This leads to a circular dependency between common and ct.h + * It just works out before we're at the end of the file, but it's still + * prone to issues in the future. */ +#include "ct.h" +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + mld_zeroize(mld_alloc_##v, sizeof(mld_alloc_##v)); \ + (v) = NULL; \ + } while (0) + +#else /* !MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* Custom allocation */ + +/* + * The indirection here is necessary to use MLD_CONTEXT_PARAMETERS_3 here. + */ +#define MLD_APPLY(f, args) f args + +#define MLD_ALLOC(v, T, N, context) \ + MLD_APPLY(MLD_CUSTOM_ALLOC, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)) + +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + if (v != NULL) \ + { \ + mld_zeroize(v, sizeof(T) * (N)); \ + MLD_APPLY(MLD_CUSTOM_FREE, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)); \ + v = NULL; \ + } \ + } while (0) + +#endif /* MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* + * We are facing severe CBMC performance issues when using unions. + * As a temporary workaround, we use unions only when MLD_CONFIG_REDUCE_RAM is + * set. + * TODO: Remove the workaround once + * https://github.com/diffblue/cbmc/issues/8813 + * is resolved + */ +#if defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_UNION_OR_STRUCT union +#else +#define MLD_UNION_OR_STRUCT struct +#endif + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_COMMON_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/ct.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/ct.c new file mode 100644 index 0000000000..010b1a52a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/ct.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include "ct.h" + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +/* + * Masking value used in constant-time functions from + * ct.h to block the compiler's range analysis and + * thereby reduce the risk of compiler-introduced branches. + */ +volatile uint64_t mld_ct_opt_blocker_u64 = 0; + +#else /* !MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(ct) + +#endif /* !(!MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/ct.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/ct.h new file mode 100644 index 0000000000..c307456468 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/ct.h @@ -0,0 +1,366 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [libmceliece] + * libmceliece implementation of Classic McEliece + * Bernstein, Chou + * https://lib.mceliece.org/ + * + * - [optblocker] + * PQC forum post on opt-blockers using volatile globals + * Daniel J. Bernstein + * https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ + */ + +#ifndef MLD_CT_H +#define MLD_CT_H + +#include +#include "cbmc.h" +#include "common.h" + +/* Constant-time comparisons and conditional operations + + We reduce the risk for compilation into variable-time code + through the use of 'value barriers'. + + Functionally, a value barrier is a no-op. To the compiler, however, + it constitutes an arbitrary modification of its input, and therefore + harden's value propagation and range analysis. + + We consider two approaches to implement a value barrier: + - An empty inline asm block which marks the target value as clobbered. + - XOR'ing with the value of a volatile global that's set to 0; + see @[optblocker] for a discussion of this idea, and + @[libmceliece, inttypes/crypto_intN.h] for an implementation. + + The first approach is cheap because it only prevents the compiler + from reasoning about the value of the variable past the barrier, + but does not directly generate additional instructions. + + The second approach generates redundant loads and XOR operations + and therefore comes at a higher runtime cost. However, it appears + more robust towards optimization, as compilers should never drop + a volatile load. + + We use the empty-ASM value barrier for GCC and clang, and fall + back to the global volatile barrier otherwise. + + The global value barrier can be forced by setting + MLD_CONFIG_NO_ASM_VALUE_BARRIER. + +*/ + +#if defined(MLD_HAVE_INLINE_ASM) && !defined(MLD_CONFIG_NO_ASM_VALUE_BARRIER) +#define MLD_USE_ASM_VALUE_BARRIER +#endif + + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) +/* + * Declaration of global volatile that the global value barrier + * is loading from and masking with. + */ +#define mld_ct_opt_blocker_u64 MLD_NAMESPACE(ct_opt_blocker_u64) +extern volatile uint64_t mld_ct_opt_blocker_u64; + + +/* Helper functions for obtaining global masks of various sizes */ + +/* This contract is not proved but treated as an axiom. + * + * Its validity relies on the assumption that the global opt-blocker + * constant mld_ct_opt_blocker_u64 is not modified. + */ +static MLD_INLINE uint64_t mld_ct_get_optblocker_u64(void) +__contract__(ensures(return_value == 0)) { return mld_ct_opt_blocker_u64; } + +static MLD_INLINE int64_t mld_ct_get_optblocker_i64(void) +__contract__(ensures(return_value == 0)) { return (int64_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint32_t mld_ct_get_optblocker_u32(void) +__contract__(ensures(return_value == 0)) { return (uint32_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint8_t mld_ct_get_optblocker_u8(void) +__contract__(ensures(return_value == 0)) { return (uint8_t)mld_ct_get_optblocker_u64(); } + +/* Opt-blocker based implementation of value barriers */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_i64()); } + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u32()); } + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u8()); } + + +#else /* !MLD_USE_ASM_VALUE_BARRIER */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} +#endif /* MLD_USE_ASM_VALUE_BARRIER */ + +#ifdef CBMC +#pragma CPROVER check push +#pragma CPROVER check disable "conversion" +#endif + +/************************************************* + * Name: mld_cast_uint32_to_int32 + * + * Description: Cast uint32 value to int32 + * + * Returns: For uint32_t x, the unique y in int32_t + * so that x == y mod 2^32. + * + * Concretely: + * - x < 2^31: returns x + * - x >= 2^31: returns x - 2^31 + * + **************************************************/ +static MLD_ALWAYS_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x) +{ + /* + * PORTABILITY: This relies on uint32_t -> int32_t + * being implemented as the inverse of int32_t -> uint32_t, + * which is implementation-defined (C99 6.3.1.3 (3)) + * CBMC (correctly) fails to prove this conversion is OK, + * so we have to suppress that check here + */ + return (int32_t)x; +} + +#ifdef CBMC +#pragma CPROVER check pop +#endif + + +/************************************************* + * Name: mld_cast_int64_to_uint32 + * + * Description: Cast int64 value to uint32 as per C standard. + * + * Returns: For int64_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int64_to_uint32(int64_t x) +{ + return (uint32_t)(x & (int64_t)UINT32_MAX); +} + +/************************************************* + * Name: mld_cast_int32_to_uint32 + * + * Description: Cast int32 value to uint32 as per C standard. + * + * Returns: For int32_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int32_to_uint32(int32_t x) +{ + return mld_cast_int64_to_uint32((int64_t)x); +} + +/************************************************* + * Name: mld_ct_sel_int32 + * + * Description: Functionally equivalent to cond ? a : b, + * but implemented with guards against + * compiler-introduced branches. + * + * Arguments: int32_t a: First alternative + * int32_t b: Second alternative + * uint32_t cond: Condition variable. + * + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_sel_int32(int32_t a, int32_t b, uint32_t cond) +__contract__( + requires(cond == 0x0 || cond == 0xFFFFFFFF) + ensures(return_value == (cond ? a : b)) +) +{ + uint32_t au = mld_cast_int32_to_uint32(a); + uint32_t bu = mld_cast_int32_to_uint32(b); + uint32_t res = bu ^ (mld_value_barrier_u32(cond) & (au ^ bu)); + return mld_cast_uint32_to_int32(res); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u32 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_nonzero_u32(uint32_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFFFFFFFF))) +{ + int64_t tmp = mld_value_barrier_i64(-((int64_t)x)); + tmp >>= 32; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u8 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint8_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint8_t mld_ct_cmask_nonzero_u8(uint8_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFF))) +{ + uint32_t mask = mld_ct_cmask_nonzero_u32((uint32_t)x); + return (uint8_t)(mask & 0xFF); +} + +/************************************************* + * Name: mld_ct_cmask_neg_i32 + * + * Description: Return 0 if input is non-negative, and -1 otherwise. + * + * Arguments: int32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_neg_i32(int32_t x) +__contract__( + ensures(return_value == ((x < 0) ? 0xFFFFFFFF : 0)) +) +{ + int64_t tmp = mld_value_barrier_i64((int64_t)x); + tmp >>= 31; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_abs_i32 + * + * Description: Return -x if x<0, x otherwise + * + * Arguments: int32_t x: Input value + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_abs_i32(int32_t x) +__contract__( + requires(x >= -INT32_MAX) + ensures(return_value == ((x < 0) ? -x : x)) +) +{ + return mld_ct_sel_int32(-x, x, mld_ct_cmask_neg_i32(x)); +} + +/************************************************* + * Name: mld_ct_memcmp + * + * Description: Compare two arrays for equality in constant time. + * + * Arguments: const uint8_t *a: pointer to first byte array + * const uint8_t *b: pointer to second byte array + * size_t len: length of the byte arrays, upper-bounded + * to UINT16_MAX to control proof complexity + * only. + * + * Returns 0 if the byte arrays are equal, 0xFF otherwise. + **************************************************/ +static MLD_INLINE uint8_t mld_ct_memcmp(const uint8_t *a, const uint8_t *b, + const size_t len) +__contract__( + requires(len <= UINT16_MAX) + requires(memory_no_alias(a, len)) + requires(memory_no_alias(b, len)) + ensures((return_value == 0) || (return_value == 0xFF)) + ensures((return_value == 0) == forall(i, 0, len, (a[i] == b[i])))) +{ + uint8_t r = 0, s = 0; + unsigned i; + + for (i = 0; i < len; i++) + __loop__( + invariant(i <= len) + invariant((r == 0) == (forall(k, 0, i, (a[k] == b[k]))))) + { + r |= a[i] ^ b[i]; + /* s is useless, but prevents the loop from being aborted once r=0xff. */ + s ^= a[i] ^ b[i]; + } + + /* + * - Convert r into a mask; this may not be necessary, but is an additional + * safeguard + * towards leaking information about a and b. + * - XOR twice with s, separated by a value barrier, to prevent the compile + * from dropping the s computation in the loop. + */ + return (mld_value_barrier_u8(mld_ct_cmask_nonzero_u8(r) ^ s) ^ s); +} + +/************************************************* + * Name: mld_zeroize + * + * Description: Force-zeroize a buffer. + * @[FIPS204, Section 3.6.3] Destruction of intermediate + * values. + * + * Arguments: void *ptr: pointer to buffer to be zeroed + * size_t len: Amount of bytes to be zeroed + **************************************************/ +#if !defined(MLD_CONFIG_CUSTOM_ZEROIZE) +#if defined(MLD_SYS_WINDOWS) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) { SecureZeroMemory(ptr, len); } +#elif defined(MLD_HAVE_INLINE_ASM) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) +{ + memset(ptr, 0, len); + /* This follows OpenSSL and seems sufficient to prevent the compiler + * from optimizing away the memset. + * + * If there was a reliable way to detect availability of memset_s(), + * that would be preferred. */ + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +} +#else /* !MLD_SYS_WINDOWS && MLD_HAVE_INLINE_ASM */ +#error No plausibly-secure implementation of mld_zeroize available. Please provide your own using MLD_CONFIG_CUSTOM_ZEROIZE. +#endif /* !MLD_SYS_WINDOWS && !MLD_HAVE_INLINE_ASM */ +#endif /* !MLD_CONFIG_CUSTOM_ZEROIZE */ + +#endif /* !MLD_CT_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/debug.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/debug.c new file mode 100644 index 0000000000..a55d51e8b1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/debug.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* NOTE: You can remove this file unless you compile with MLDSA_DEBUG. */ + +#include "common.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#if defined(MLDSA_DEBUG) + +#include +#include +#include +#include "debug.h" + +#define MLD_DEBUG_ERROR_HEADER "[ERROR:%s:%04d] " + +void mld_debug_check_assert(const char *file, int line, const int val) +{ + if (val == 0) + { + fprintf(stderr, MLD_DEBUG_ERROR_HEADER "Assertion failed (value %d)\n", + file, line, val); + exit(1); + } +} + +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive) +{ + int err = 0; + unsigned i; + for (i = 0; i < len; i++) + { + int32_t val = ptr[i]; + if (!(val > lower_bound_exclusive && val < upper_bound_exclusive)) + { + fprintf(stderr, + MLD_DEBUG_ERROR_HEADER + "Bounds assertion failed: Index %u, value %d out of bounds " + "(%" PRId64 ",%" PRId64 ")\n", + file, line, i, (int)val, lower_bound_exclusive, + upper_bound_exclusive); + err = 1; + } + } + + if (err == 1) + { + exit(1); + } +} + +#else /* MLDSA_DEBUG */ + +MLD_EMPTY_CU(debug) + +#endif /* !MLDSA_DEBUG */ + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(debug) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_DEBUG_ERROR_HEADER diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/debug.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/debug.h new file mode 100644 index 0000000000..af187bb9de --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/debug.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_DEBUG_H +#define MLD_DEBUG_H +#include "common.h" + +#if defined(MLDSA_DEBUG) +#include + +/************************************************* + * Name: mld_assert + * + * Description: Check debug assertion + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - val: Value asserted to be non-zero + **************************************************/ +#define mld_debug_check_assert MLD_NAMESPACE(mldsa_debug_assert) +void mld_debug_check_assert(const char *file, int line, const int val); + +/************************************************* + * Name: mld_debug_check_bounds + * + * Description: Check whether values in an array of int32_t + * are within specified bounds. + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - ptr: Base of array to be checked + * - len: Number of int32_t in ptr + * - lower_bound_exclusive: Exclusive lower bound + * - upper_bound_exclusive: Exclusive upper bound + **************************************************/ +#define mld_debug_check_bounds MLD_NAMESPACE(mldsa_debug_check_bounds) +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive); + +/* Check assertion, calling exit() upon failure + * + * val: Value that's asserted to be non-zero + */ +#define mld_assert(val) mld_debug_check_assert(__FILE__, __LINE__, (val)) + +/* Check bounds in array of int32_t's + * ptr: Base of int32_t array; will be explicitly cast to int32_t*, + * so you may pass a byte-compatible type such as mld_poly or mld_polyvec. + * len: Number of int32_t in array + * value_lb: Inclusive lower value bound + * value_ub: Exclusive upper value bound */ +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + mld_debug_check_bounds(__FILE__, __LINE__, (const int32_t *)(ptr), (len), \ + ((int64_t)(value_lb)) - 1, (value_ub)) + +/* Check absolute bounds in array of int32_t's + * ptr: Base of array, expression of type int32_t* + * len: Number of int32_t in array + * value_abs_bd: Exclusive absolute upper bound */ +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + mld_assert_bound((ptr), (len), (-((int64_t)(value_abs_bd)) + 1), \ + (value_abs_bd)) + +/* Version of bounds assertions for 2-dimensional arrays */ +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + mld_assert_bound((ptr), ((len0) * (len1)), (value_lb), (value_ub)) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + mld_assert_abs_bound((ptr), ((len0) * (len1)), (value_abs_bd)) + +/* When running CBMC, convert debug assertions into proof obligations */ +#elif defined(CBMC) +#include "cbmc.h" + +#define mld_assert(val) cassert(val) + +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + cassert(array_bound(((int32_t *)(ptr)), 0, (len), (value_lb), (value_ub))) + +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + cassert(array_abs_bound(((int32_t *)(ptr)), 0, (len), (value_abs_bd))) + +/* Because of https://github.com/diffblue/cbmc/issues/8570, we can't + * just use a single flattened array_bound(...) here. */ +#define mld_assert_bound_2d(ptr, M, N, value_lb, value_ub) \ + cassert(forall(kN, 0, (M), \ + array_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_lb), (value_ub)))) + +#define mld_assert_abs_bound_2d(ptr, M, N, value_abs_bd) \ + cassert(forall(kN, 0, (M), \ + array_abs_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_abs_bd)))) + +#else /* !MLDSA_DEBUG && CBMC */ + +#define mld_assert(val) \ + do \ + { \ + } while (0) +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + do \ + { \ + } while (0) +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + do \ + { \ + } while (0) + +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + do \ + { \ + } while (0) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + do \ + { \ + } while (0) + + +#endif /* !MLDSA_DEBUG && !CBMC */ +#endif /* !MLD_DEBUG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/fips202.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/fips202.c new file mode 100644 index 0000000000..1112de061c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/fips202.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "../common.h" +#include "../ct.h" +#include "fips202.h" +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +/************************************************* + * Name: keccak_init + * + * Description: Initializes the Keccak state. + * + * Arguments: - uint64_t *s: pointer to Keccak state + **************************************************/ +static void keccak_init(uint64_t s[MLD_KECCAK_LANES]) +__contract__( + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + mld_memset(s, 0, sizeof(uint64_t) * MLD_KECCAK_LANES); +} + +/************************************************* + * Name: keccak_absorb + * + * Description: Absorb step of Keccak; incremental. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_absorb(uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r, + const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(pos <= r) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(in, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + ensures(return_value < r)) +{ + while (inlen >= r - pos) + __loop__( + assigns(pos, in, inlen, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + invariant(inlen <= loop_entry(inlen)) + invariant(pos <= r) + invariant(in == loop_entry(in) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600_xor_bytes(s, in, pos, r - pos); + inlen -= r - pos; + in += r - pos; + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: At this point, inlen < r, so the truncation to unsigned is safe. */ + mld_keccakf1600_xor_bytes(s, in, pos, (unsigned)inlen); + + /* Safety: At this point, inlen < r and pos <= r so the truncation to unsigned + * is safe. */ + return (unsigned)(pos + inlen); +} + +/************************************************* + * Name: keccak_finalize + * + * Description: Finalize absorb step. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - uint8_t p: domain separation byte + **************************************************/ +static void keccak_finalize(uint64_t s[MLD_KECCAK_LANES], unsigned int pos, + unsigned int r, uint8_t p) +__contract__( + requires(pos <= r && r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires((r / 8) >= 1) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + uint8_t b = 0x80; + mld_keccakf1600_xor_bytes(s, &p, pos, 1); + mld_keccakf1600_xor_bytes(s, &b, r - 1, 1); +} + +/************************************************* + * Name: keccak_squeeze + * + * Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes. + * Modifies the state. Can be called multiple times to keep + * squeezing, i.e., is incremental. + * + * Arguments: - uint8_t *out: pointer to output data + * - size_t outlen: number of bytes to be squeezed (written to out) + * - uint64_t *s: pointer to input/output Keccak state + * - unsigned int pos: number of bytes in current block already + *squeezed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_squeeze(uint8_t *out, size_t outlen, + uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r) +__contract__( + requires((r == SHAKE128_RATE && pos <= SHAKE128_RATE) || + (r == SHAKE256_RATE && pos <= SHAKE256_RATE) || + (r == SHA3_512_RATE && pos <= SHA3_512_RATE)) + requires(outlen <= 8 * r /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(out, outlen)) + ensures(return_value <= r)) +{ + unsigned int i; + size_t out_offset = 0; + + /* Reference: This code is re-factored from the reference implementation + * to facilitate proof with CBMC and to improve readability. + * + * Take a mutable copy of outlen to count down the number of bytes + * still to squeeze. The initial value of outlen is needed for the CBMC + * assigns() clauses. */ + size_t bytes_to_go = outlen; + + while (bytes_to_go > 0) + __loop__( + assigns(i, bytes_to_go, pos, out_offset, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES), memory_slice(out, outlen)) + invariant(bytes_to_go <= outlen) + invariant(out_offset == outlen - bytes_to_go) + invariant(pos <= r) + ) + { + if (pos == r) + { + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: If bytes_to_go < r - pos, truncation to unsigned is safe. */ + i = bytes_to_go < r - pos ? (unsigned)bytes_to_go : r - pos; + mld_keccakf1600_extract_bytes(s, out + out_offset, pos, i); + bytes_to_go -= i; + pos += i; + out_offset += i; + } + + return pos; +} + +void mld_shake128_init(mld_shake128ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE128_RATE, in, inlen); +} + +void mld_shake128_finalize(mld_shake128ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE128_RATE, 0x1F); + state->pos = SHAKE128_RATE; +} + +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE128_RATE); +} + +void mld_shake128_release(mld_shake128ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128ctx)); +} + +void mld_shake256_init(mld_shake256ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); +} + +void mld_shake256_finalize(mld_shake256ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); + state->pos = SHAKE256_RATE; +} + +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); +} + +void mld_shake256_release(mld_shake256ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256ctx)); +} + +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +{ + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, in, inlen); + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/fips202.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/fips202.h new file mode 100644 index 0000000000..9f0253cb88 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/fips202.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202_H +#define MLD_FIPS202_FIPS202_H + +#include +#include +#include "../cbmc.h" +#include "../common.h" + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 +#define SHA3_256_RATE 136 +#define SHA3_512_RATE 72 +#define MLD_KECCAK_LANES 25 +#define SHA3_256_HASHBYTES 32 +#define SHA3_512_HASHBYTES 64 + + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake128ctx; + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake256ctx; + +#define mld_shake128_init MLD_NAMESPACE(shake128_init) +/************************************************* + * Name: mld_shake128_init + * + * Description: Initializes state for use as SHAKE128 XOF + * + * Arguments: - mld_shake128ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake128_init(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos == 0) +); + +#define mld_shake128_absorb MLD_NAMESPACE(shake128_absorb) +/************************************************* + * Name: mld_shake128_absorb + * + * Description: Absorb step of the SHAKE128 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake128ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_finalize MLD_NAMESPACE(shake128_finalize) +/************************************************* + * Name: mld_shake128_finalize + * + * Description: Concludes the absorb phase of the SHAKE128 XOF. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_finalize(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_squeeze MLD_NAMESPACE(shake128_squeeze) +/************************************************* + * Name: mld_shake128_squeeze + * + * Description: Squeeze step of SHAKE128 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake128ctx *s: pointer to input/output state + **************************************************/ +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE128_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_release MLD_NAMESPACE(shake128_release) +/************************************************* + * Name: mld_shake128_release + * + * Description: Release and securely zero the SHAKE128 state. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_release(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) +); + +#define mld_shake256_init MLD_NAMESPACE(shake256_init) +/************************************************* + * Name: mld_shake256_init + * + * Description: Initializes state for use as SHAKE256 XOF + * + * Arguments: - mld_shake256ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake256_init(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos == 0) +); + +#define mld_shake256_absorb MLD_NAMESPACE(shake256_absorb) +/************************************************* + * Name: mld_shake256_absorb + * + * Description: Absorb step of the SHAKE256 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake256ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_finalize MLD_NAMESPACE(shake256_finalize) +/************************************************* + * Name: mld_shake256_finalize + * + * Description: Concludes the absorb phase of the SHAKE256 XOF. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_finalize(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_squeeze MLD_NAMESPACE(shake256_squeeze) +/************************************************* + * Name: mld_shake256_squeeze + * + * Description: Squeeze step of SHAKE256 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake256ctx *s: pointer to input/output state + **************************************************/ +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_release MLD_NAMESPACE(shake256_release) +/************************************************* + * Name: mld_shake256_release + * + * Description: Release and securely zero the SHAKE256 state. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_release(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) +); + +#define mld_shake256 MLD_NAMESPACE(shake256) +/************************************************* + * Name: mld_shake256 + * + * Description: SHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +); + +#endif /* !MLD_FIPS202_FIPS202_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/fips202x4.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/fips202x4.c new file mode 100644 index 0000000000..0fb5cd57c7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/fips202x4.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include "../common.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "../ct.h" +#include "fips202.h" +#include "fips202x4.h" +#include "keccakf1600.h" + +static void mld_keccak_absorb_once_x4(uint64_t *s, uint32_t r, + const uint8_t *in0, const uint8_t *in1, + const uint8_t *in2, const uint8_t *in3, + size_t inlen, uint8_t p) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))) +{ + while (inlen >= r) + __loop__( + assigns(inlen, in0, in1, in2, in3, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + invariant(inlen <= loop_entry(inlen)) + invariant(in0 == loop_entry(in0) + (loop_entry(inlen) - inlen)) + invariant(in1 == loop_entry(in1) + (loop_entry(inlen) - inlen)) + invariant(in2 == loop_entry(in2) + (loop_entry(inlen) - inlen)) + invariant(in3 == loop_entry(in3) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, r); + mld_keccakf1600x4_permute(s); + + in0 += r; + in1 += r; + in2 += r; + in3 += r; + inlen -= r; + } + + /* Safety: At this point, inlen < r, so the truncations to unsigned are safe + * below. */ + if (inlen > 0) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, (unsigned)inlen); + } + + if (inlen == r - 1) + { + p |= 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + } + else + { + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + p = 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, r - 1, 1); + } +} + +static void mld_keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1, + uint8_t *out2, uint8_t *out3, + size_t nblocks, uint64_t *s, uint32_t r) +__contract__( + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(out0, nblocks * r)) + requires(memory_no_alias(out1, nblocks * r)) + requires(memory_no_alias(out2, nblocks * r)) + requires(memory_no_alias(out3, nblocks * r)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(out0, nblocks * r)) + assigns(memory_slice(out1, nblocks * r)) + assigns(memory_slice(out2, nblocks * r)) + assigns(memory_slice(out3, nblocks * r))) +{ + while (nblocks > 0) + __loop__( + assigns(out0, out1, out2, out3, nblocks, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY), + memory_slice(out0, nblocks * r), + memory_slice(out1, nblocks * r), + memory_slice(out2, nblocks * r), + memory_slice(out3, nblocks * r)) + invariant(nblocks <= loop_entry(nblocks) && + out0 == loop_entry(out0) + r * (loop_entry(nblocks) - nblocks) && + out1 == loop_entry(out1) + r * (loop_entry(nblocks) - nblocks) && + out2 == loop_entry(out2) + r * (loop_entry(nblocks) - nblocks) && + out3 == loop_entry(out3) + r * (loop_entry(nblocks) - nblocks))) + { + mld_keccakf1600x4_permute(s); + mld_keccakf1600x4_extract_bytes(s, out0, out1, out2, out3, 0, r); + + out0 += r; + out1 += r; + out2 += r; + out3 += r; + nblocks--; + } +} + +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake128x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE128_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE128_RATE); +} + +void mld_shake128x4_init(mld_shake128x4ctx *state) { (void)state; } +void mld_shake128x4_release(mld_shake128x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128x4ctx)); +} + + +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake256x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE256_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE256_RATE); +} + +void mld_shake256x4_init(mld_shake256x4ctx *state) { (void)state; } +void mld_shake256x4_release(mld_shake256x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256x4ctx)); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/fips202x4.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/fips202x4.h new file mode 100644 index 0000000000..e7987207a6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/fips202x4.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202X4_H +#define MLD_FIPS202_FIPS202X4_H + +#include +#include + +#include "../cbmc.h" +#include "../common.h" + +#include "fips202.h" +#include "keccakf1600.h" + +/* Context for non-incremental API */ +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake128x4ctx; + +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake256x4ctx; + +#define mld_shake128x4_absorb_once MLD_NAMESPACE(shake128x4_absorb_once) +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_squeezeblocks MLD_NAMESPACE(shake128x4_squeezeblocks) +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE128_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE128_RATE), + memory_slice(out1, nblocks * SHAKE128_RATE), + memory_slice(out2, nblocks * SHAKE128_RATE), + memory_slice(out3, nblocks * SHAKE128_RATE), + memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_init MLD_NAMESPACE(shake128x4_init) +void mld_shake128x4_init(mld_shake128x4ctx *state); + +#define mld_shake128x4_release MLD_NAMESPACE(shake128x4_release) +void mld_shake128x4_release(mld_shake128x4ctx *state); + + +#define mld_shake256x4_absorb_once MLD_NAMESPACE(shake256x4_absorb_once) +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_squeezeblocks MLD_NAMESPACE(shake256x4_squeezeblocks) +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE256_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE256_RATE), + memory_slice(out1, nblocks * SHAKE256_RATE), + memory_slice(out2, nblocks * SHAKE256_RATE), + memory_slice(out3, nblocks * SHAKE256_RATE), + memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_init MLD_NAMESPACE(shake256x4_init) +void mld_shake256x4_init(mld_shake256x4ctx *state); + +#define mld_shake256x4_release MLD_NAMESPACE(shake256x4_release) +void mld_shake256x4_release(mld_shake256x4ctx *state); + + +#endif /* !MLD_FIPS202_FIPS202X4_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/keccakf1600.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/keccakf1600.c new file mode 100644 index 0000000000..e59120c07c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/keccakf1600.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#define MLD_KECCAK_NROUNDS 24 +#define MLD_KECCAK_ROL(a, offset) ((a << offset) ^ (a >> (64 - offset))) + +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = state_ptr[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = (state[(offset + i) >> 3] >> (8 * ((offset + i) & 0x07))) & 0xFF; + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state_ptr[i] ^= data[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state[(offset + i) >> 3] ^= (uint64_t)data[i] + << (8 * ((offset + i) & 0x07)); + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X4_NATIVE) + if (mld_keccak_f1600_x4_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 0); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 1); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 2); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 3); +} + +static const uint64_t mld_KeccakF_RoundConstants[MLD_KECCAK_NROUNDS] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +static void mld_keccakf1600_permute_c(uint64_t *state) +{ + unsigned round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + uint64_t BCa, BCe, BCi, BCo, BCu; + uint64_t Da, De, Di, Do, Du; + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + /* copyFromState(A, state) */ + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < MLD_KECCAK_NROUNDS; round += 2) + __loop__(invariant(round <= MLD_KECCAK_NROUNDS && round % 2 == 0)) + { + /* prepareTheta */ + BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; + BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + /* thetaRhoPiChiIotaPrepareTheta(round, A, E) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = MLD_KECCAK_ROL(Age, 44); + Aki ^= Di; + BCi = MLD_KECCAK_ROL(Aki, 43); + Amo ^= Do; + BCo = MLD_KECCAK_ROL(Amo, 21); + Asu ^= Du; + BCu = MLD_KECCAK_ROL(Asu, 14); + Eba = BCa ^ ((~BCe) & BCi); + Eba ^= (uint64_t)mld_KeccakF_RoundConstants[round]; + Ebe = BCe ^ ((~BCi) & BCo); + Ebi = BCi ^ ((~BCo) & BCu); + Ebo = BCo ^ ((~BCu) & BCa); + Ebu = BCu ^ ((~BCa) & BCe); + + Abo ^= Do; + BCa = MLD_KECCAK_ROL(Abo, 28); + Agu ^= Du; + BCe = MLD_KECCAK_ROL(Agu, 20); + Aka ^= Da; + BCi = MLD_KECCAK_ROL(Aka, 3); + Ame ^= De; + BCo = MLD_KECCAK_ROL(Ame, 45); + Asi ^= Di; + BCu = MLD_KECCAK_ROL(Asi, 61); + Ega = BCa ^ ((~BCe) & BCi); + Ege = BCe ^ ((~BCi) & BCo); + Egi = BCi ^ ((~BCo) & BCu); + Ego = BCo ^ ((~BCu) & BCa); + Egu = BCu ^ ((~BCa) & BCe); + + Abe ^= De; + BCa = MLD_KECCAK_ROL(Abe, 1); + Agi ^= Di; + BCe = MLD_KECCAK_ROL(Agi, 6); + Ako ^= Do; + BCi = MLD_KECCAK_ROL(Ako, 25); + Amu ^= Du; + BCo = MLD_KECCAK_ROL(Amu, 8); + Asa ^= Da; + BCu = MLD_KECCAK_ROL(Asa, 18); + Eka = BCa ^ ((~BCe) & BCi); + Eke = BCe ^ ((~BCi) & BCo); + Eki = BCi ^ ((~BCo) & BCu); + Eko = BCo ^ ((~BCu) & BCa); + Eku = BCu ^ ((~BCa) & BCe); + + Abu ^= Du; + BCa = MLD_KECCAK_ROL(Abu, 27); + Aga ^= Da; + BCe = MLD_KECCAK_ROL(Aga, 36); + Ake ^= De; + BCi = MLD_KECCAK_ROL(Ake, 10); + Ami ^= Di; + BCo = MLD_KECCAK_ROL(Ami, 15); + Aso ^= Do; + BCu = MLD_KECCAK_ROL(Aso, 56); + Ema = BCa ^ ((~BCe) & BCi); + Eme = BCe ^ ((~BCi) & BCo); + Emi = BCi ^ ((~BCo) & BCu); + Emo = BCo ^ ((~BCu) & BCa); + Emu = BCu ^ ((~BCa) & BCe); + + Abi ^= Di; + BCa = MLD_KECCAK_ROL(Abi, 62); + Ago ^= Do; + BCe = MLD_KECCAK_ROL(Ago, 55); + Aku ^= Du; + BCi = MLD_KECCAK_ROL(Aku, 39); + Ama ^= Da; + BCo = MLD_KECCAK_ROL(Ama, 41); + Ase ^= De; + BCu = MLD_KECCAK_ROL(Ase, 2); + Esa = BCa ^ ((~BCe) & BCi); + Ese = BCe ^ ((~BCi) & BCo); + Esi = BCi ^ ((~BCo) & BCu); + Eso = BCo ^ ((~BCu) & BCa); + Esu = BCu ^ ((~BCa) & BCe); + + /* prepareTheta */ + BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + /* thetaRhoPiChiIotaPrepareTheta(round+1, E, A) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = MLD_KECCAK_ROL(Ege, 44); + Eki ^= Di; + BCi = MLD_KECCAK_ROL(Eki, 43); + Emo ^= Do; + BCo = MLD_KECCAK_ROL(Emo, 21); + Esu ^= Du; + BCu = MLD_KECCAK_ROL(Esu, 14); + Aba = BCa ^ ((~BCe) & BCi); + Aba ^= (uint64_t)mld_KeccakF_RoundConstants[round + 1]; + Abe = BCe ^ ((~BCi) & BCo); + Abi = BCi ^ ((~BCo) & BCu); + Abo = BCo ^ ((~BCu) & BCa); + Abu = BCu ^ ((~BCa) & BCe); + + Ebo ^= Do; + BCa = MLD_KECCAK_ROL(Ebo, 28); + Egu ^= Du; + BCe = MLD_KECCAK_ROL(Egu, 20); + Eka ^= Da; + BCi = MLD_KECCAK_ROL(Eka, 3); + Eme ^= De; + BCo = MLD_KECCAK_ROL(Eme, 45); + Esi ^= Di; + BCu = MLD_KECCAK_ROL(Esi, 61); + Aga = BCa ^ ((~BCe) & BCi); + Age = BCe ^ ((~BCi) & BCo); + Agi = BCi ^ ((~BCo) & BCu); + Ago = BCo ^ ((~BCu) & BCa); + Agu = BCu ^ ((~BCa) & BCe); + + Ebe ^= De; + BCa = MLD_KECCAK_ROL(Ebe, 1); + Egi ^= Di; + BCe = MLD_KECCAK_ROL(Egi, 6); + Eko ^= Do; + BCi = MLD_KECCAK_ROL(Eko, 25); + Emu ^= Du; + BCo = MLD_KECCAK_ROL(Emu, 8); + Esa ^= Da; + BCu = MLD_KECCAK_ROL(Esa, 18); + Aka = BCa ^ ((~BCe) & BCi); + Ake = BCe ^ ((~BCi) & BCo); + Aki = BCi ^ ((~BCo) & BCu); + Ako = BCo ^ ((~BCu) & BCa); + Aku = BCu ^ ((~BCa) & BCe); + + Ebu ^= Du; + BCa = MLD_KECCAK_ROL(Ebu, 27); + Ega ^= Da; + BCe = MLD_KECCAK_ROL(Ega, 36); + Eke ^= De; + BCi = MLD_KECCAK_ROL(Eke, 10); + Emi ^= Di; + BCo = MLD_KECCAK_ROL(Emi, 15); + Eso ^= Do; + BCu = MLD_KECCAK_ROL(Eso, 56); + Ama = BCa ^ ((~BCe) & BCi); + Ame = BCe ^ ((~BCi) & BCo); + Ami = BCi ^ ((~BCo) & BCu); + Amo = BCo ^ ((~BCu) & BCa); + Amu = BCu ^ ((~BCa) & BCe); + + Ebi ^= Di; + BCa = MLD_KECCAK_ROL(Ebi, 62); + Ego ^= Do; + BCe = MLD_KECCAK_ROL(Ego, 55); + Eku ^= Du; + BCi = MLD_KECCAK_ROL(Eku, 39); + Ema ^= Da; + BCo = MLD_KECCAK_ROL(Ema, 41); + Ese ^= De; + BCu = MLD_KECCAK_ROL(Ese, 2); + Asa = BCa ^ ((~BCe) & BCi); + Ase = BCe ^ ((~BCi) & BCo); + Asi = BCi ^ ((~BCo) & BCu); + Aso = BCo ^ ((~BCu) & BCa); + Asu = BCu ^ ((~BCa) & BCe); + } + + /* copyToState(state, A) */ + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} + +void mld_keccakf1600_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X1_NATIVE) + if (mld_keccak_f1600_x1_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X1_NATIVE */ + mld_keccakf1600_permute_c(state); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(keccakf1600) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_KECCAK_NROUNDS +#undef MLD_KECCAK_ROL diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/keccakf1600.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/keccakf1600.h new file mode 100644 index 0000000000..e56adc1561 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/keccakf1600.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_KECCAKF1600_H +#define MLD_FIPS202_KECCAKF1600_H +#include +#include "../cbmc.h" +#include "../common.h" +#include "fips202.h" + +#define MLD_KECCAK_LANES 25 +#define MLD_KECCAK_WAY 4 + +/* + * WARNING: + * The contents of this structure, including the placement + * and interleaving of Keccak lanes, are IMPLEMENTATION-DEFINED. + * The struct is only exposed here to allow its construction on the stack. + */ + +#define mld_keccakf1600_extract_bytes MLD_NAMESPACE(keccakf1600_extract_bytes) +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(data, length)) +); + +#define mld_keccakf1600_xor_bytes MLD_NAMESPACE(keccakf1600_xor_bytes) +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#define mld_keccakf1600x4_extract_bytes \ + MLD_NAMESPACE(keccakf1600x4_extract_bytes) +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + requires(memory_no_alias(data1, length)) + requires(memory_no_alias(data2, length)) + requires(memory_no_alias(data3, length)) + assigns(memory_slice(data0, length)) + assigns(memory_slice(data1, length)) + assigns(memory_slice(data2, length)) + assigns(memory_slice(data3, length)) +); + +#define mld_keccakf1600x4_xor_bytes MLD_NAMESPACE(keccakf1600x4_xor_bytes) +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + /* Case 1: all input buffers are distinct; Case 2: All input buffers are the same */ + requires((data0 == data1 && + data0 == data2 && + data0 == data3) || + (memory_no_alias(data1, length) && + memory_no_alias(data2, length) && + memory_no_alias(data3, length))) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600x4_permute MLD_NAMESPACE(keccakf1600x4_permute) +void mld_keccakf1600x4_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600_permute MLD_NAMESPACE(keccakf1600_permute) +void mld_keccakf1600_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#endif /* !MLD_FIPS202_KECCAKF1600_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/auto.h new file mode 100644 index 0000000000..4375cc1976 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/auto.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [HYBRID] + * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64 + * Becker, Kannwischer + * https://eprint.iacr.org/2022/1243 + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +#define MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* Default FIPS202 assembly profile for AArch64 systems */ + +/* + * Default logic to decide which implementation to use. + * + */ + +/* + * Keccak-f1600 + * + * - On Arm-based Apple CPUs, we pick a pure Neon implementation. + * - Otherwise, unless MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, + * we use lazy-rotation scalar assembly from @[HYBRID]. + * - Otherwise, if MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, we + * fall back to the standard C implementation. + */ +#if defined(__ARM_FEATURE_SHA3) && defined(__APPLE__) +#include "x1_v84a.h" +#elif !defined(MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER) +#include "x1_scalar.h" +#endif + +/* + * Keccak-f1600x2/x4 + * + * The optimal implementation is highly CPU-specific; see @[HYBRID]. + * + * For now, if v8.4-A is not implemented, we fall back to Keccak-f1600. + * If v8.4-A is implemented and we are on an Apple CPU, we use a plain + * Neon-based implementation. + * If v8.4-A is implemented and we are not on an Apple CPU, we use a + * scalar/Neon/Neon hybrid. + * The reason for this distinction is that Apple CPUs appear to implement + * the SHA3 instructions on all SIMD units, while Arm CPUs prior to Cortex-X4 + * don't, and ordinary Neon instructions are still needed. + */ +#if defined(__ARM_FEATURE_SHA3) +/* + * For Apple-M cores, we use a plain implementation leveraging SHA3 + * instructions only. + */ +#if defined(__APPLE__) +#include "x2_v84a.h" +#else +#include "x4_v8a_v84a_scalar.h" +#endif + +#else /* __ARM_FEATURE_SHA3 */ + +#include "x4_v8a_scalar.h" + +#endif /* !__ARM_FEATURE_SHA3 */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h new file mode 100644 index 0000000000..20f6168038 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#define MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H + +#include +#include "../../../../cbmc.h" +#include "../../../../common.h" + + +#define mld_keccakf1600_round_constants \ + MLD_NAMESPACE(keccakf1600_round_constants) +extern const uint64_t mld_keccakf1600_round_constants[]; + +#define mld_keccak_f1600_x1_scalar_asm MLD_NAMESPACE(keccak_f1600_x1_scalar_asm) +void mld_keccak_f1600_x1_scalar_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x1_v84a_asm MLD_NAMESPACE(keccak_f1600_x1_v84a_asm) +void mld_keccak_f1600_x1_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x2_v84a_asm MLD_NAMESPACE(keccak_f1600_x2_v84a_asm) +void mld_keccak_f1600_x2_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 2)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 2)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c new file mode 100644 index 0000000000..05e9cbfeec --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../../common.h" + +#if (defined(MLD_FIPS202_AARCH64_NEED_X1_SCALAR) || \ + defined(MLD_FIPS202_AARCH64_NEED_X1_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X2_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID)) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "fips202_native_aarch64.h" + +MLD_ALIGN const uint64_t mld_keccakf1600_round_constants[] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, +}; + +#else /* (MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_aarch64_round_constants) + +#endif /* !((MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/x1_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/x1_scalar.h new file mode 100644 index 0000000000..681b991371 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/x1_scalar.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_SCALAR + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + mld_keccak_f1600_x1_scalar_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/x1_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/x1_v84a.h new file mode 100644 index 0000000000..d15c8c26f3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/x1_v84a.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x1_v84a_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/x2_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/x2_v84a.h new file mode 100644 index 0000000000..16c22fa1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/x2_v84a.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X2_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" + + +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x2_v84a_asm(state + 0 * 25, mld_keccakf1600_round_constants); + mld_keccak_f1600_x2_v84a_asm(state + 2 * 25, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h new file mode 100644 index 0000000000..0f7f8fe499 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(state, + mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h new file mode 100644 index 0000000000..3da883b762 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm( + state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/api.h new file mode 100644 index 0000000000..4625c9a1ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/api.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_API_H +#define MLD_FIPS202_NATIVE_API_H +/* + * FIPS-202 native interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + */ + +#include +#include "../../cbmc.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* + * This is the C<->native interface allowing for the drop-in + * of custom Keccak-F1600 implementations. + * + * A _backend_ is a specific implementation of parts of this interface. + * + * You can replace 1-fold or 4-fold batched Keccak-F1600. + * To enable, set MLD_USE_FIPS202_X1_NATIVE or MLD_USE_FIPS202_X4_NATIVE + * in your backend, and define the inline wrappers mld_keccak_f1600_x1_native() + * and/or mld_keccak_f1600_x4_native(), respectively, to forward to your + * implementation. + */ + +#if defined(MLD_USE_FIPS202_X1_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 1)) +); +#endif /* MLD_USE_FIPS202_X1_NATIVE */ +#if defined(MLD_USE_FIPS202_X4_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 4)) +); +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + +#endif /* !MLD_FIPS202_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/auto.h new file mode 100644 index 0000000000..0a09c733c8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/auto.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AUTO_H +#define MLD_FIPS202_NATIVE_AUTO_H + +/* + * Default FIPS202 backend + */ +#include "../../sys.h" + +#if defined(MLD_SYS_AARCH64) +#include "aarch64/auto.h" +#endif + +#if defined(MLD_SYS_X86_64) && defined(MLD_SYS_X86_64_AVX2) +#include "x86_64/xkcp.h" +#endif + +#endif /* !MLD_FIPS202_NATIVE_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c new file mode 100644 index 0000000000..4eaad2fd66 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* +Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, +Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby +denoted as "the implementer". + +For more information, feedback or questions, please refer to our websites: +http://keccak.noekeon.org/ +http://keyak.noekeon.org/ +http://ketje.noekeon.org/ + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +/* + * Changes for mlkem-native/mldsa-native: + * - copyFromState and copyToState operate on uninterleaved + * Keccak states in memory. + */ + +#include "../../../../common.h" +#if defined(MLD_FIPS202_X86_64_XKCP) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include + +#include "KeccakP_1600_times4_SIMD256.h" + +#ifndef MLD_SYS_LITTLE_ENDIAN +#error Expecting a little-endian platform +#endif + +#define ANDnu256(a, b) _mm256_andnot_si256(a, b) +#define CONST256(a) _mm256_load_si256((const __m256i *)&(a)) +#define CONST256_64(a) (__m256i) _mm256_broadcast_sd((const double *)(&a)) +#define ROL64in256(d, a, o) \ + d = _mm256_or_si256(_mm256_slli_epi64(a, o), _mm256_srli_epi64(a, 64 - (o))) +#define ROL64in256_8(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho8)) +#define ROL64in256_56(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho56)) +static const uint64_t rho8[4] = {0x0605040302010007, 0x0E0D0C0B0A09080F, + 0x1615141312111017, 0x1E1D1C1B1A19181F}; +static const uint64_t rho56[4] = {0x0007060504030201, 0x080F0E0D0C0B0A09, + 0x1017161514131211, 0x181F1E1D1C1B1A19}; +#define STORE256(a, b) _mm256_store_si256((__m256i *)&(a), b) +#define XOR256(a, b) _mm256_xor_si256(a, b) +#define XOReq256(a, b) a = _mm256_xor_si256(a, b) + +#define SnP_laneLengthInBytes 8 + +#define declareABCDE \ + __m256i Aba, Abe, Abi, Abo, Abu; \ + __m256i Aga, Age, Agi, Ago, Agu; \ + __m256i Aka, Ake, Aki, Ako, Aku; \ + __m256i Ama, Ame, Ami, Amo, Amu; \ + __m256i Asa, Ase, Asi, Aso, Asu; \ + __m256i Bba, Bbe, Bbi, Bbo, Bbu; \ + __m256i Bga, Bge, Bgi, Bgo, Bgu; \ + __m256i Bka, Bke, Bki, Bko, Bku; \ + __m256i Bma, Bme, Bmi, Bmo, Bmu; \ + __m256i Bsa, Bse, Bsi, Bso, Bsu; \ + __m256i Ca, Ce, Ci, Co, Cu; \ + __m256i Ca1, Ce1, Ci1, Co1, Cu1; \ + __m256i Da, De, Di, Do, Du; \ + __m256i Eba, Ebe, Ebi, Ebo, Ebu; \ + __m256i Ega, Ege, Egi, Ego, Egu; \ + __m256i Eka, Eke, Eki, Eko, Eku; \ + __m256i Ema, Eme, Emi, Emo, Emu; \ + __m256i Esa, Ese, Esi, Eso, Esu; + +#define prepareTheta \ + Ca = XOR256(Aba, XOR256(Aga, XOR256(Aka, XOR256(Ama, Asa)))); \ + Ce = XOR256(Abe, XOR256(Age, XOR256(Ake, XOR256(Ame, Ase)))); \ + Ci = XOR256(Abi, XOR256(Agi, XOR256(Aki, XOR256(Ami, Asi)))); \ + Co = XOR256(Abo, XOR256(Ago, XOR256(Ako, XOR256(Amo, Aso)))); \ + Cu = XOR256(Abu, XOR256(Agu, XOR256(Aku, XOR256(Amu, Asu)))); + +/* + * --- Theta Rho Pi Chi Iota Prepare-theta + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + Ca = E##ba; \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + Ce = E##be; \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + Ci = E##bi; \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + Co = E##bo; \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + Cu = E##bu; \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(Ca, E##ga); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(Ce, E##ge); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + XOReq256(Ci, E##gi); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + XOReq256(Co, E##go); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + XOReq256(Cu, E##gu); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(Ca, E##ka); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(Ce, E##ke); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + XOReq256(Ci, E##ki); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + XOReq256(Co, E##ko); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + XOReq256(Cu, E##ku); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(Ca, E##ma); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(Ce, E##me); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + XOReq256(Ci, E##mi); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + XOReq256(Co, E##mo); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + XOReq256(Cu, E##mu); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(Ca, E##sa); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(Ce, E##se); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + XOReq256(Ci, E##si); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + XOReq256(Co, E##so); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); \ + XOReq256(Cu, E##su); + + +/* + * --- Theta Rho Pi Chi Iota + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIota(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); + + +static MLD_ALIGN const uint64_t keccakf1600RoundConstants[24] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +#include + +#define copyFromState(X, state) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m256i _idx = \ + _mm256_set_epi64x((long long)&state64[75], (long long)&state64[50], \ + (long long)&state64[25], (long long)&state64[0]); \ + X##ba = _mm256_i64gather_epi64((long long *)(0 * 8), _idx, 1); \ + X##be = _mm256_i64gather_epi64((long long *)(1 * 8), _idx, 1); \ + X##bi = _mm256_i64gather_epi64((long long *)(2 * 8), _idx, 1); \ + X##bo = _mm256_i64gather_epi64((long long *)(3 * 8), _idx, 1); \ + X##bu = _mm256_i64gather_epi64((long long *)(4 * 8), _idx, 1); \ + X##ga = _mm256_i64gather_epi64((long long *)(5 * 8), _idx, 1); \ + X##ge = _mm256_i64gather_epi64((long long *)(6 * 8), _idx, 1); \ + X##gi = _mm256_i64gather_epi64((long long *)(7 * 8), _idx, 1); \ + X##go = _mm256_i64gather_epi64((long long *)(8 * 8), _idx, 1); \ + X##gu = _mm256_i64gather_epi64((long long *)(9 * 8), _idx, 1); \ + X##ka = _mm256_i64gather_epi64((long long *)(10 * 8), _idx, 1); \ + X##ke = _mm256_i64gather_epi64((long long *)(11 * 8), _idx, 1); \ + X##ki = _mm256_i64gather_epi64((long long *)(12 * 8), _idx, 1); \ + X##ko = _mm256_i64gather_epi64((long long *)(13 * 8), _idx, 1); \ + X##ku = _mm256_i64gather_epi64((long long *)(14 * 8), _idx, 1); \ + X##ma = _mm256_i64gather_epi64((long long *)(15 * 8), _idx, 1); \ + X##me = _mm256_i64gather_epi64((long long *)(16 * 8), _idx, 1); \ + X##mi = _mm256_i64gather_epi64((long long *)(17 * 8), _idx, 1); \ + X##mo = _mm256_i64gather_epi64((long long *)(18 * 8), _idx, 1); \ + X##mu = _mm256_i64gather_epi64((long long *)(19 * 8), _idx, 1); \ + X##sa = _mm256_i64gather_epi64((long long *)(20 * 8), _idx, 1); \ + X##se = _mm256_i64gather_epi64((long long *)(21 * 8), _idx, 1); \ + X##si = _mm256_i64gather_epi64((long long *)(22 * 8), _idx, 1); \ + X##so = _mm256_i64gather_epi64((long long *)(23 * 8), _idx, 1); \ + X##su = _mm256_i64gather_epi64((long long *)(24 * 8), _idx, 1); \ + } while (0); + +#define SCATTER_STORE256(state, idx, v) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m128d t = _mm_castsi128_pd(_mm256_castsi256_si128((v))); \ + _mm_storel_pd((double *)&state64[0 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[25 + (idx)], t); \ + t = _mm_castsi128_pd(_mm256_extracti128_si256((v), 1)); \ + _mm_storel_pd((double *)&state64[50 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[75 + (idx)], t); \ + } while (0) + +#define copyToState(state, X) \ + SCATTER_STORE256(state, 0, X##ba); \ + SCATTER_STORE256(state, 1, X##be); \ + SCATTER_STORE256(state, 2, X##bi); \ + SCATTER_STORE256(state, 3, X##bo); \ + SCATTER_STORE256(state, 4, X##bu); \ + SCATTER_STORE256(state, 5, X##ga); \ + SCATTER_STORE256(state, 6, X##ge); \ + SCATTER_STORE256(state, 7, X##gi); \ + SCATTER_STORE256(state, 8, X##go); \ + SCATTER_STORE256(state, 9, X##gu); \ + SCATTER_STORE256(state, 10, X##ka); \ + SCATTER_STORE256(state, 11, X##ke); \ + SCATTER_STORE256(state, 12, X##ki); \ + SCATTER_STORE256(state, 13, X##ko); \ + SCATTER_STORE256(state, 14, X##ku); \ + SCATTER_STORE256(state, 15, X##ma); \ + SCATTER_STORE256(state, 16, X##me); \ + SCATTER_STORE256(state, 17, X##mi); \ + SCATTER_STORE256(state, 18, X##mo); \ + SCATTER_STORE256(state, 19, X##mu); \ + SCATTER_STORE256(state, 20, X##sa); \ + SCATTER_STORE256(state, 21, X##se); \ + SCATTER_STORE256(state, 22, X##si); \ + SCATTER_STORE256(state, 23, X##so); \ + SCATTER_STORE256(state, 24, X##su); + +#define copyStateVariables(X, Y) \ + X##ba = Y##ba; \ + X##be = Y##be; \ + X##bi = Y##bi; \ + X##bo = Y##bo; \ + X##bu = Y##bu; \ + X##ga = Y##ga; \ + X##ge = Y##ge; \ + X##gi = Y##gi; \ + X##go = Y##go; \ + X##gu = Y##gu; \ + X##ka = Y##ka; \ + X##ke = Y##ke; \ + X##ki = Y##ki; \ + X##ko = Y##ko; \ + X##ku = Y##ku; \ + X##ma = Y##ma; \ + X##me = Y##me; \ + X##mi = Y##mi; \ + X##mo = Y##mo; \ + X##mu = Y##mu; \ + X##sa = Y##sa; \ + X##se = Y##se; \ + X##si = Y##si; \ + X##so = Y##so; \ + X##su = Y##su; + +/* clang-format off */ +#define rounds24 \ + prepareTheta \ + thetaRhoPiChiIotaPrepareTheta( 0, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 1, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 2, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 3, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 4, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 5, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 6, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 7, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 8, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 9, E, A) \ + thetaRhoPiChiIotaPrepareTheta(10, A, E) \ + thetaRhoPiChiIotaPrepareTheta(11, E, A) \ + thetaRhoPiChiIotaPrepareTheta(12, A, E) \ + thetaRhoPiChiIotaPrepareTheta(13, E, A) \ + thetaRhoPiChiIotaPrepareTheta(14, A, E) \ + thetaRhoPiChiIotaPrepareTheta(15, E, A) \ + thetaRhoPiChiIotaPrepareTheta(16, A, E) \ + thetaRhoPiChiIotaPrepareTheta(17, E, A) \ + thetaRhoPiChiIotaPrepareTheta(18, A, E) \ + thetaRhoPiChiIotaPrepareTheta(19, E, A) \ + thetaRhoPiChiIotaPrepareTheta(20, A, E) \ + thetaRhoPiChiIotaPrepareTheta(21, E, A) \ + thetaRhoPiChiIotaPrepareTheta(22, A, E) \ + thetaRhoPiChiIota(23, E, A) +/* clang-format on */ + +void mld_keccakf1600x4_permute24(void *states) +{ + __m256i *statesAsLanes = (__m256i *)states; + declareABCDE copyFromState(A, statesAsLanes) + rounds24 copyToState(statesAsLanes, A) +} + +#else /* MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_avx2_keccakx4) + +#endif /* !(MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef ANDnu256 +#undef CONST256 +#undef CONST256_64 +#undef ROL64in256 +#undef ROL64in256_8 +#undef ROL64in256_56 +#undef STORE256 +#undef XOR256 +#undef XOReq256 +#undef SnP_laneLengthInBytes +#undef declareABCDE +#undef prepareTheta +#undef thetaRhoPiChiIotaPrepareTheta +#undef thetaRhoPiChiIota +#undef copyFromState +#undef SCATTER_STORE256 +#undef copyToState +#undef copyStateVariables +#undef rounds24 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h new file mode 100644 index 0000000000..3499d38e2c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H +#define MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H + +#include "../../../../common.h" + +#define mld_keccakf1600x4_permute24 \ + MLD_NAMESPACE(KeccakP1600times4_PermuteAll_24rounds) +void mld_keccakf1600x4_permute24(void *states); + +#endif /* !MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/x86_64/xkcp.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/x86_64/xkcp.h new file mode 100644 index 0000000000..c03642d7e0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/fips202/native/x86_64/xkcp.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_XKCP_H +#define MLD_FIPS202_NATIVE_X86_64_XKCP_H + +#include "../../../common.h" + +#define MLD_FIPS202_X86_64_XKCP + +#if !defined(__ASSEMBLER__) +#include +#include "../api.h" +#include "src/KeccakP_1600_times4_SIMD256.h" + +#define MLD_USE_FIPS202_X4_NATIVE +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_keccakf1600x4_permute24(state); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_X86_64_XKCP_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/meta.h new file mode 100644 index 0000000000..c6f6ad47b0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/meta.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_META_H +#define MLD_NATIVE_AARCH64_META_H + +/* Set of primitives that this backend replaces */ +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_AARCH64 + + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/arith_native_aarch64.h" + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + mld_ntt_asm(data, mld_aarch64_ntt_zetas_layer123456, + mld_aarch64_ntt_zetas_layer78); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + mld_intt_asm(data, mld_aarch64_intt_zetas_layer78, + mld_aarch64_intt_zetas_layer123456); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + if (len != MLDSA_N || + buflen % 24 != 0) /* NEON support is mandatory for AArch64 */ + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N, hence, this cast is safe. */ + return (int)mld_rej_uniform_asm(r, buf, buflen, mld_rej_uniform_table); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_32_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_88_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + mld_poly_caddq_asm(a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_32_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_88_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + return mld_poly_chknorm_asm(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_17_asm(r, buf, mld_polyz_unpack_17_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_19_asm(r, buf, mld_polyz_unpack_19_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t out[MLDSA_N], const int32_t in0[MLDSA_N], + const int32_t in1[MLDSA_N]) +{ + mld_poly_pointwise_montgomery_asm(out, in0, in1); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l4_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l5_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l7_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ +#endif /* !MLD_NATIVE_AARCH64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/src/aarch64_zetas.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/src/aarch64_zetas.c new file mode 100644 index 0000000000..9ab7b9a68c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/src/aarch64_zetas.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Table of zeta values used in the AArch64 forward NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer123456[] = { + -3572223, -915382907, 3765607, 964937599, 3761513, 963888510, + -3201494, -820383522, -2883726, -738955404, -3145678, -806080660, + -3201430, -820367122, 0, 0, -601683, -154181397, + -3370349, -863652652, -4063053, -1041158200, 3602218, 923069133, + 3182878, 815613168, 2740543, 702264730, -3586446, -919027554, + 0, 0, 3542485, 907762539, 2663378, 682491182, + -1674615, -429120452, -3110818, -797147778, 2101410, 538486762, + 3704823, 949361686, 1159875, 297218217, 0, 0, + 2682288, 687336873, -3524442, -903139016, -434125, -111244624, + 394148, 101000509, 928749, 237992130, 1095468, 280713909, + -3506380, -898510625, 0, 0, 2129892, 545785280, + 676590, 173376332, -1335936, -342333886, 2071829, 530906624, + -4018989, -1029866791, 3241972, 830756018, 2156050, 552488273, + 0, 0, 3764867, 964747974, -3227876, -827143915, + 1714295, 439288460, 3415069, 875112161, 1759347, 450833045, + -817536, -209493775, -3574466, -915957677, 0, 0, + -1005239, -257592709, 2453983, 628833668, 1460718, 374309300, + 3756790, 962678241, -1935799, -496048908, -1716988, -439978542, + -3950053, -1012201926, 0, 0, 557458, 142848732, + -642628, -164673562, -3585098, -918682129, -2897314, -742437332, + 3192354, 818041395, 556856, 142694469, 3870317, 991769559, + 0, 0, -1221177, -312926867, 2815639, 721508096, + 2283733, 585207070, 2917338, 747568486, 1853806, 475038184, + 3345963, 857403734, 1858416, 476219497, 0, 0, +}; + +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer78[] = { + 3073009, 1277625, -2635473, 3852015, 787459213, + 327391679, -675340520, 987079667, 1753, -2659525, + 2660408, -59148, 449207, -681503850, 681730119, + -15156688, -1935420, -1455890, -1780227, 2772600, + -495951789, -373072124, -456183549, 710479343, 4183372, + -3222807, -3121440, -274060, 1071989969, -825844983, + -799869667, -70227934, 1182243, 636927, -3956745, + -3284915, 302950022, 163212680, -1013916752, -841760171, + 87208, -3965306, -2296397, -3716946, 22347069, + -1016110510, -588452222, -952468207, 2508980, 2028118, + 1937570, -3815725, 642926661, 519705671, 496502727, + -977780347, -27812, 1009365, -1979497, -3956944, + -7126831, 258649997, -507246529, -1013967746, 822541, + -2454145, 1596822, -3759465, 210776307, -628875181, + 409185979, -963363710, 2811291, -2983781, -1109516, + 4158088, 720393920, -764594519, -284313712, 1065510939, + -1685153, 2678278, -3551006, -250446, -431820817, + 686309310, -909946047, -64176841, -3410568, -3768948, + 635956, -2455377, -873958779, -965793731, 162963861, + -629190881, 1528066, 482649, 1148858, -2962264, + 391567239, 123678909, 294395108, -759080783, -4146264, + 2192938, 2387513, -268456, -1062481036, 561940831, + 611800717, -68791907, -1772588, -1727088, -3611750, + -3180456, -454226054, -442566669, -925511710, -814992530, + -565603, 169688, 2462444, -3334383, -144935890, + 43482586, 631001801, -854436357, 3747250, 1239911, + 3195676, 1254190, 960233614, 317727459, 818892658, + 321386456, 2296099, -3838479, 2642980, -12417, + 588375860, -983611064, 677264190, -3181859, -4166425, + -3488383, 1987814, -3197248, -1067647297, -893898890, + 509377762, -819295484, 2998219, -89301, -1354892, + -1310261, 768294260, -22883400, -347191365, -335754661, + 141835, 2513018, 613238, -2218467, 36345249, + 643961400, 157142369, -568482643, 1736313, 235407, + -3250154, 3258457, 444930577, 60323094, -832852657, + 834980303, -458740, 4040196, 2039144, -818761, + -117552223, 1035301089, 522531086, -209807681, -1921994, + -3472069, -1879878, -2178965, -492511373, -889718424, + -481719139, -558360247, -2579253, 1787943, -2391089, + -2254727, -660934133, 458160776, -612717067, -577774276, + -1623354, -2374402, 586241, 527981, -415984810, + -608441020, 150224382, 135295244, 2105286, -2033807, + -1179613, -2743411, 539479988, -521163479, -302276083, + -702999655, 3482206, -4182915, -1300016, -2362063, + 892316032, -1071872863, -333129378, -605279149, -1476985, + 2491325, 507927, -724804, -378477722, 638402564, + 130156402, -185731180, 1994046, -1393159, -1187885, + -1834526, 510974714, -356997292, -304395785, -470097680, + -1317678, 2461387, 3035980, 621164, -337655269, + 630730945, 777970524, 159173408, -3033742, 2647994, + -2612853, 749577, -777397036, 678549029, -669544140, + 192079267, -338420, 3009748, 4148469, -4022750, + -86720197, 771248568, 1063046068, -1030830548, 3901472, + -1226661, 2925816, 3374250, 999753034, -314332144, + 749740976, 864652284, 3980599, -1615530, 1665318, + 1163598, 1020029345, -413979908, 426738094, 298172236, + 2569011, 1723229, 2028038, -3369273, 658309618, + 441577800, 519685171, -863376927, 1356448, -2775755, + 2683270, -2778788, 347590090, -711287812, 687588511, + -712065019, 3994671, -1370517, 3363542, 545376, + 1023635298, -351195274, 861908357, 139752717, -11879, + 3020393, 214880, -770441, -3043996, 773976352, + 55063046, -197425671, -3467665, 2312838, -653275, + -459163, -888589898, 592665232, -167401858, -117660617, + 3105558, 508145, 860144, 140244, 795799901, + 130212265, 220412084, 35937555, -1103344, -553718, + 3430436, -1514152, -282732136, -141890356, 879049958, + -388001774, 348812, -327848, 1011223, -2354215, + 89383150, -84011120, 259126110, -603268097, -2185084, + 2358373, -3014420, 2926054, -559928242, 604333585, + -772445769, 749801963, 3123762, -2193087, -1716814, + -392707, 800464680, -561979013, -439933955, -100631253, + -3818627, -1922253, -2236726, 1744507, -978523985, + -492577742, -573161516, 447030292, -303005, -3974485, + 1900052, 1054478, -77645096, -1018462631, 486888731, + 270210213, 3531229, -3773731, -781875, -731434, + 904878186, -967019376, -200355636, -187430119, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer78[] = { + -1744507, 2236726, 1922253, 3818627, -447030292, 573161516, + 492577742, 978523985, 731434, 781875, 3773731, -3531229, + 187430119, 200355636, 967019376, -904878186, -1054478, -1900052, + 3974485, 303005, -270210213, -486888731, 1018462631, 77645096, + 2354215, -1011223, 327848, -348812, 603268097, -259126110, + 84011120, -89383150, 392707, 1716814, 2193087, -3123762, + 100631253, 439933955, 561979013, -800464680, -2926054, 3014420, + -2358373, 2185084, -749801963, 772445769, -604333585, 559928242, + 459163, 653275, -2312838, 3467665, 117660617, 167401858, + -592665232, 888589898, 1514152, -3430436, 553718, 1103344, + 388001774, -879049958, 141890356, 282732136, -140244, -860144, + -508145, -3105558, -35937555, -220412084, -130212265, -795799901, + 2778788, -2683270, 2775755, -1356448, 712065019, -687588511, + 711287812, -347590090, 770441, -214880, -3020393, 11879, + 197425671, -55063046, -773976352, 3043996, -545376, -3363542, + 1370517, -3994671, -139752717, -861908357, 351195274, -1023635298, + -3374250, -2925816, 1226661, -3901472, -864652284, -749740976, + 314332144, -999753034, 3369273, -2028038, -1723229, -2569011, + 863376927, -519685171, -441577800, -658309618, -1163598, -1665318, + 1615530, -3980599, -298172236, -426738094, 413979908, -1020029345, + -621164, -3035980, -2461387, 1317678, -159173408, -777970524, + -630730945, 337655269, 4022750, -4148469, -3009748, 338420, + 1030830548, -1063046068, -771248568, 86720197, -749577, 2612853, + -2647994, 3033742, -192079267, 669544140, -678549029, 777397036, + 2362063, 1300016, 4182915, -3482206, 605279149, 333129378, + 1071872863, -892316032, 1834526, 1187885, 1393159, -1994046, + 470097680, 304395785, 356997292, -510974714, 724804, -507927, + -2491325, 1476985, 185731180, -130156402, -638402564, 378477722, + 2254727, 2391089, -1787943, 2579253, 577774276, 612717067, + -458160776, 660934133, 2743411, 1179613, 2033807, -2105286, + 702999655, 302276083, 521163479, -539479988, -527981, -586241, + 2374402, 1623354, -135295244, -150224382, 608441020, 415984810, + -3258457, 3250154, -235407, -1736313, -834980303, 832852657, + -60323094, -444930577, 2178965, 1879878, 3472069, 1921994, + 558360247, 481719139, 889718424, 492511373, 818761, -2039144, + -4040196, 458740, 209807681, -522531086, -1035301089, 117552223, + 3197248, -1987814, 3488383, 4166425, 819295484, -509377762, + 893898890, 1067647297, 2218467, -613238, -2513018, -141835, + 568482643, -157142369, -643961400, -36345249, 1310261, 1354892, + 89301, -2998219, 335754661, 347191365, 22883400, -768294260, + 3334383, -2462444, -169688, 565603, 854436357, -631001801, + -43482586, 144935890, 12417, -2642980, 3838479, -2296099, + 3181859, -677264190, 983611064, -588375860, -1254190, -3195676, + -1239911, -3747250, -321386456, -818892658, -317727459, -960233614, + 2962264, -1148858, -482649, -1528066, 759080783, -294395108, + -123678909, -391567239, 3180456, 3611750, 1727088, 1772588, + 814992530, 925511710, 442566669, 454226054, 268456, -2387513, + -2192938, 4146264, 68791907, -611800717, -561940831, 1062481036, + -4158088, 1109516, 2983781, -2811291, -1065510939, 284313712, + 764594519, -720393920, 2455377, -635956, 3768948, 3410568, + 629190881, -162963861, 965793731, 873958779, 250446, 3551006, + -2678278, 1685153, 64176841, 909946047, -686309310, 431820817, + 3815725, -1937570, -2028118, -2508980, 977780347, -496502727, + -519705671, -642926661, 3759465, -1596822, 2454145, -822541, + 963363710, -409185979, 628875181, -210776307, 3956944, 1979497, + -1009365, 27812, 1013967746, 507246529, -258649997, 7126831, + 274060, 3121440, 3222807, -4183372, 70227934, 799869667, + 825844983, -1071989969, 3716946, 2296397, 3965306, -87208, + 952468207, 588452222, 1016110510, -22347069, 3284915, 3956745, + -636927, -1182243, 841760171, 1013916752, -163212680, -302950022, + -3852015, 2635473, -1277625, -3073009, -987079667, 675340520, + -327391679, -787459213, -2772600, 1780227, 1455890, 1935420, + -710479343, 456183549, 373072124, 495951789, 59148, -2660408, + 2659525, -1753, 15156688, -681730119, 681503850, -449207, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer123456[] = { + -2283733, -585207070, 0, 0, -1858416, -476219497, + -3345963, -857403734, -2815639, -721508096, 0, 0, + -1853806, -475038184, -2917338, -747568486, 3585098, 918682129, + 0, 0, -3870317, -991769559, -556856, -142694469, + 642628, 164673562, 0, 0, -3192354, -818041395, + 2897314, 742437332, -1460718, -374309300, 0, 0, + 3950053, 1012201926, 1716988, 439978542, -2453983, -628833668, + 0, 0, 1935799, 496048908, -3756790, -962678241, + -1714295, -439288460, 0, 0, 3574466, 915957677, + 817536, 209493775, 3227876, 827143915, 0, 0, + -1759347, -450833045, -3415069, -875112161, 1335936, 342333886, + 0, 0, -2156050, -552488273, -3241972, -830756018, + -676590, -173376332, 0, 0, 4018989, 1029866791, + -2071829, -530906624, 434125, 111244624, 0, 0, + 3506380, 898510625, -1095468, -280713909, 3524442, 903139016, + 0, 0, -928749, -237992130, -394148, -101000509, + 1674615, 429120452, 0, 0, -1159875, -297218217, + -3704823, -949361686, -2663378, -682491182, 0, 0, + -2101410, -538486762, 3110818, 797147778, 4063053, 1041158200, + 0, 0, 3586446, 919027554, -2740543, -702264730, + 3370349, 863652652, 0, 0, -3182878, -815613168, + -3602218, -923069133, -294725, -75523344, -3761513, -963888510, + -3765607, -964937599, 3201430, 820367122, 3145678, 806080660, + 2883726, 738955404, 3201494, 820383522, 1221177, 312926867, + -557458, -142848732, 1005239, 257592709, -3764867, -964747974, + -2129892, -545785280, -2682288, -687336873, -3542485, -907762539, + 601683, 154181397, 0, 0, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_zetas) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h new file mode 100644 index 0000000000..e77f55014c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#define MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H + +#include +#include "../../../common.h" + +#define mld_aarch64_ntt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_ntt_zetas_layer123456) +#define mld_aarch64_ntt_zetas_layer78 MLD_NAMESPACE(aarch64_ntt_zetas_layer78) + +#define mld_aarch64_intt_zetas_layer78 MLD_NAMESPACE(aarch64_intt_zetas_layer78) +#define mld_aarch64_intt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_intt_zetas_layer123456) + +extern const int32_t mld_aarch64_ntt_zetas_layer123456[]; +extern const int32_t mld_aarch64_ntt_zetas_layer78[]; + +extern const int32_t mld_aarch64_intt_zetas_layer78[]; +extern const int32_t mld_aarch64_intt_zetas_layer123456[]; + +#define mld_rej_uniform_table MLD_NAMESPACE(rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[]; +#define mld_rej_uniform_eta_table MLD_NAMESPACE(rej_uniform_eta_table) +extern const uint8_t mld_rej_uniform_eta_table[]; + +#define mld_polyz_unpack_17_indices MLD_NAMESPACE(polyz_unpack_17_indices) +extern const uint8_t mld_polyz_unpack_17_indices[]; +#define mld_polyz_unpack_19_indices MLD_NAMESPACE(polyz_unpack_19_indices) +extern const uint8_t mld_polyz_unpack_19_indices[]; + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_ntt_asm MLD_NAMESPACE(ntt_asm) +void mld_ntt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_intt_asm MLD_NAMESPACE(intt_asm) +void mld_intt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_rej_uniform_asm MLD_NAMESPACE(rej_uniform_asm) +uint64_t mld_rej_uniform_asm(int32_t *r, const uint8_t *buf, unsigned buflen, + const uint8_t *table); + +#define mld_rej_uniform_eta2_asm MLD_NAMESPACE(rej_uniform_eta2_asm) +uint64_t mld_rej_uniform_eta2_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_rej_uniform_eta4_asm MLD_NAMESPACE(rej_uniform_eta4_asm) +uint64_t mld_rej_uniform_eta4_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_poly_decompose_32_asm MLD_NAMESPACE(poly_decompose_32_asm) +void mld_poly_decompose_32_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_asm MLD_NAMESPACE(poly_decompose_88_asm) +void mld_poly_decompose_88_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_asm MLD_NAMESPACE(poly_caddq_asm) +void mld_poly_caddq_asm(int32_t *a); + +#define mld_poly_use_hint_32_asm MLD_NAMESPACE(poly_use_hint_32_asm) +void mld_poly_use_hint_32_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_asm MLD_NAMESPACE(poly_use_hint_88_asm) +void mld_poly_use_hint_88_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_asm MLD_NAMESPACE(poly_chknorm_asm) +int mld_poly_chknorm_asm(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_asm MLD_NAMESPACE(polyz_unpack_17_asm) +void mld_polyz_unpack_17_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_polyz_unpack_19_asm MLD_NAMESPACE(polyz_unpack_19_asm) +void mld_polyz_unpack_19_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_poly_pointwise_montgomery_asm \ + MLD_NAMESPACE(poly_pointwise_montgomery_asm) +void mld_poly_pointwise_montgomery_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l4_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l4_asm) +void mld_polyvecl_pointwise_acc_montgomery_l4_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l5_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l5_asm) +void mld_polyvecl_pointwise_acc_montgomery_l5_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l7_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l7_asm) +void mld_polyvecl_pointwise_acc_montgomery_l7_asm(int32_t *, const int32_t *, + const int32_t *); + +#endif /* !MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c new file mode 100644 index 0000000000..7ef915b587 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* Table of indices used for tbl instructions in polyz_unpack_{17,19}. */ + +MLD_ALIGN const uint8_t mld_polyz_unpack_17_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, + 9, 10, 11, 255, 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, + 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, 8, 9, 10, 255, + 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, 17, 18, 19, 255, +}; + +MLD_ALIGN const uint8_t mld_polyz_unpack_19_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 5, 6, 7, 255, 7, 8, 9, 255, + 10, 11, 12, 255, 12, 13, 14, 255, 15, 16, 17, 255, 17, 18, 19, 255, + 4, 5, 6, 255, 6, 7, 8, 255, 9, 10, 11, 255, 11, 12, 13, 255, + 14, 15, 16, 255, 16, 17, 18, 255, 19, 20, 21, 255, 21, 22, 23, 255, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_polyz_unpack_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c new file mode 100644 index 0000000000..cf21509cbf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by 16-bit rejection sampling (rej_eta). + * Adapted from ML-KEM for ML-DSA eta rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_eta_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 2, 3, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 4, 5, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 2, 3, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 7 */, + 6, 7, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 2, 3, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 11 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 13 */, + 2, 3, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 15 */, + 8, 9, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 16 */, + 0, 1, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 17 */, + 2, 3, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 18 */, + 0, 1, 2, 3, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 19 */, + 4, 5, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 20 */, + 0, 1, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 21 */, + 2, 3, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 22 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 23 */, + 6, 7, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 24 */, + 0, 1, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 25 */, + 2, 3, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 26 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 27 */, + 4, 5, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 28 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 29 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 30 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 255, 255, 255, 255, 255, 255 /* 31 */, + 10, 11, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 32 */, + 0, 1, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 33 */, + 2, 3, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 34 */, + 0, 1, 2, 3, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 35 */, + 4, 5, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 36 */, + 0, 1, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 37 */, + 2, 3, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 38 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 39 */, + 6, 7, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 40 */, + 0, 1, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 41 */, + 2, 3, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 42 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 43 */, + 4, 5, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 44 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 45 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 46 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 255, 255, 255, 255, 255, 255 /* 47 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 48 */, + 0, 1, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 49 */, + 2, 3, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 50 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 51 */, + 4, 5, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 52 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 53 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 54 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 55 */, + 6, 7, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 56 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 57 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 58 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 59 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 60 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 61 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 62 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 63 */, + 12, 13, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 64 */, + 0, 1, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 65 */, + 2, 3, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 66 */, + 0, 1, 2, 3, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 67 */, + 4, 5, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 68 */, + 0, 1, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 69 */, + 2, 3, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 70 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 71 */, + 6, 7, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 72 */, + 0, 1, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 73 */, + 2, 3, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 74 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 75 */, + 4, 5, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 76 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 77 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 78 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 255, 255, 255, 255, 255, 255 /* 79 */, + 8, 9, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 80 */, + 0, 1, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 81 */, + 2, 3, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 82 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 83 */, + 4, 5, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 84 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 85 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 86 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 87 */, + 6, 7, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 88 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 89 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 90 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 91 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 92 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 93 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 94 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 255, 255, 255, 255 /* 95 */, + 10, 11, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 96 */, + 0, 1, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 97 */, + 2, 3, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 98 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 99 */, + 4, 5, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 100 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 101 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 102 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 103 */, + 6, 7, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 104 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 105 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 106 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 107 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 108 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 109 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 110 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 255, 255, 255, 255 /* 111 */, + 8, 9, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 112 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 113 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 114 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 115 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 116 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 117 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 118 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 119 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 120 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 121 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 122 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 123 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 124 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 125 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 126 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 255, 255 /* 127 */, + 14, 15, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 128 */, + 0, 1, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 129 */, + 2, 3, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 130 */, + 0, 1, 2, 3, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 131 */, + 4, 5, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 132 */, + 0, 1, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 133 */, + 2, 3, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 134 */, + 0, 1, 2, 3, 4, 5, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 135 */, + 6, 7, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 136 */, + 0, 1, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 137 */, + 2, 3, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 138 */, + 0, 1, 2, 3, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 139 */, + 4, 5, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 140 */, + 0, 1, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 141 */, + 2, 3, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 142 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 14, 15, 255, 255, 255, 255, 255, 255 /* 143 */, + 8, 9, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 144 */, + 0, 1, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 145 */, + 2, 3, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 146 */, + 0, 1, 2, 3, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 147 */, + 4, 5, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 148 */, + 0, 1, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 149 */, + 2, 3, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 150 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 151 */, + 6, 7, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 152 */, + 0, 1, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 153 */, + 2, 3, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 154 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 155 */, + 4, 5, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 156 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 157 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 158 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 14, 15, 255, 255, 255, 255 /* 159 */, + 10, 11, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 160 */, + 0, 1, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 161 */, + 2, 3, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 162 */, + 0, 1, 2, 3, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 163 */, + 4, 5, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 164 */, + 0, 1, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 165 */, + 2, 3, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 166 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 167 */, + 6, 7, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 168 */, + 0, 1, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 169 */, + 2, 3, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 170 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 171 */, + 4, 5, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 172 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 173 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 174 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 14, 15, 255, 255, 255, 255 /* 175 */, + 8, 9, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 176 */, + 0, 1, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 177 */, + 2, 3, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 178 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 179 */, + 4, 5, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 180 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 181 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 182 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 183 */, + 6, 7, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 184 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 185 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 186 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 187 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 188 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 189 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 190 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 14, 15, 255, 255 /* 191 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 192 */, + 0, 1, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 193 */, + 2, 3, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 194 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 195 */, + 4, 5, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 196 */, + 0, 1, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 197 */, + 2, 3, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 198 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 199 */, + 6, 7, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 200 */, + 0, 1, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 201 */, + 2, 3, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 202 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 203 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 204 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 205 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 206 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 207 */, + 8, 9, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 208 */, + 0, 1, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 209 */, + 2, 3, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 210 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 211 */, + 4, 5, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 212 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 213 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 214 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 215 */, + 6, 7, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 216 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 217 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 218 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 219 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 220 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 221 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 222 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 14, 15, 255, 255 /* 223 */, + 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 224 */, + 0, 1, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 225 */, + 2, 3, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 226 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 227 */, + 4, 5, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 228 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 229 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 230 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 231 */, + 6, 7, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 232 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 233 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 234 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 235 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 236 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 237 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 238 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 14, 15, 255, 255 /* 239 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 240 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 241 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 242 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 243 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 244 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 245 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 246 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 247 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 248 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 249 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 250 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 251 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 252 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 253 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 254 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 255 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_eta_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/src/rej_uniform_table.c new file mode 100644 index 0000000000..65bc3b78d3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/aarch64/src/rej_uniform_table.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by rejection sampling of the public matrix. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 7 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 11 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 13 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 15 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/api.h new file mode 100644 index 0000000000..0f1fdeb168 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/api.h @@ -0,0 +1,594 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_API_H +#define MLD_NATIVE_API_H +/* + * Native arithmetic interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + * + * To ensure consistency with backends, the header will be + * included automatically after inclusion of the active + * backend, to ensure consistency of function signatures, + * and run sanity checks. + */ + +#include +#include "../cbmc.h" +#include "../common.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* Bound on absolute value of coefficients after NTT. + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) + +/* Absolute exclusive upper bound for the output of the inverse NTT + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_INTT_BOUND MLDSA_Q + +/* Absolute bound for range of mld_reduce32() + * + * NOTE: This is the same bound as in reduce.h and has to be kept + * in sync. */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define REDUCE32_RANGE_MAX 6283009 +/* + * This is the C<->native interface allowing for the drop-in of + * native code for performance critical arithmetic components of ML-DSA. + * + * A _backend_ is a specific implementation of (part of) this interface. + * + * To add a function to a backend, define MLD_USE_NATIVE_XXX and + * implement `static inline xxx(...)` in the profile header. + */ + +/* + * Those functions are meant to be trivial wrappers around the chosen native + * implementation. The are static inline to avoid unnecessary calls. + * The macro before each declaration controls whether a native + * implementation is present. + */ + +#if defined(MLD_USE_NATIVE_NTT) +/************************************************* + * Name: mld_ntt_native + * + * Description: Computes negacyclic number-theoretic transform (NTT) of + * a polynomial in place. + * + * The input polynomial is assumed to be in normal order. + * The output polynomial is in bitreversed order. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_ntt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_NTT */ + + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) +/* + * This must only be set if NTT and INTT have native implementations + * that are adapted to the custom order. + */ +#if !defined(MLD_USE_NATIVE_NTT) || !defined(MLD_USE_NATIVE_INTT) +#error \ + "Invalid native profile: MLD_USE_NATIVE_NTT_CUSTOM_ORDER can only be \ +set if there are native implementations for NTT and INTT." +#endif + +/************************************************* + * Name: mlD_poly_permute_bitrev_to_custom + * + * Description: When MLD_USE_NATIVE_NTT_CUSTOM_ORDER is defined, + * convert a polynomial in NTT domain from bitreversed + * order to the custom order output by the native NTT. + * + * This must only be defined if there is native code for + * both the NTT and INTT. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + * + **************************************************/ +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t p[MLDSA_N]) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q))); +#endif /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + + +#if defined(MLD_USE_NATIVE_INTT) +/************************************************* + * Name: mld_intt_native + * + * Description: Computes inverse of negacyclic number-theoretic transform + *(NTT) of a polynomial in place. + * + * The input polynomial is in bitreversed order. + * The output polynomial is assumed to be in normal order. + * + * Arguments: - uint32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_intt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_INTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_INTT */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) +/************************************************* + * Name: mld_rej_uniform_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [0, MLDSA_Q-1] + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform mod q). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + * lengths. Otherwise, returns non-negative number of sampled 32-bit integers + * (at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= ( 5 * 168) && buflen % 3 == 0) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(r, 0, (unsigned) return_value, 0, MLDSA_Q)) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) +/************************************************* + * Name: mld_rej_uniform_eta2_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-2,+2]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-2, +2]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA2 */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) +/************************************************* + * Name: mld_rej_uniform_eta4_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-4,+4]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-4, +4]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) +/************************************************* + * Name: mld_poly_decompose_32_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/32. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: input/output polynomial. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_32 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) +/************************************************* + * Name: mld_poly_decompose_88_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/88. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: output polynomial with coefficients c0. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CADDQ) +/************************************************* + * Name: mld_poly_caddq_native + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *a: pointer to input/output polynomial + **************************************************/ +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_32) +/************************************************* + * Name: mld_poly_use_hint_32_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/32. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_32 */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) +/************************************************* + * Name: mld_poly_use_hint_88_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/88. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) +/************************************************* + * Name: mld_poly_chknorm_native + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const int32_t *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if the infinity norm is strictly smaller than B, and 1 + * otherwise. B must not be larger than MLDSA_Q - MLD_REDUCE32_RANGE_MAX. + **************************************************/ +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(0 <= B && B <= MLDSA_Q - REDUCE32_RANGE_MAX) + requires(array_bound(a, 0, MLDSA_N, -REDUCE32_RANGE_MAX, REDUCE32_RANGE_MAX)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == 0) == array_abs_bound(a, 0, MLDSA_N, B)) +); +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) +/************************************************* + * Name: mld_polyz_unpack_17_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^17. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_17 */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) +/************************************************* + * Name: mld_polyz_unpack_19_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^19. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_19 */ + +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) +/************************************************* + * Name: mld_poly_pointwise_montgomery_native + * + * Description: Pointwise multiplication of polynomials in NTT domain + * with Montgomery reduction. + * + * Computes c[i] = a[i] * b[i] * R^(-1) mod q for all i, + * where R = 2^32. + * + * Arguments: - int32_t c[MLDSA_N]: output polynomial + * - const int32_t a[MLDSA_N]: first input polynomial + * - const int32_t b[MLDSA_N]: second input polynomial + **************************************************/ +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(c, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(c, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(c, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l4_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 4. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 4 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 4 * MLDSA_N)) + requires(forall(l0, 0, 4, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 4, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l5_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 5. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 5 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 5 * MLDSA_N)) + requires(forall(l0, 0, 5, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 5, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l7_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 7. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 7 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 7 * MLDSA_N)) + requires(forall(l0, 0, 7, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 7, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 */ + +#endif /* !MLD_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/meta.h new file mode 100644 index 0000000000..0b46dd5791 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/meta.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_META_H +#define MLD_NATIVE_META_H + +/* + * Default arithmetic backend + */ +#include "../sys.h" + +#ifdef MLD_SYS_AARCH64 +#include "aarch64/meta.h" +#endif + +#ifdef MLD_SYS_X86_64_AVX2 +#include "x86_64/meta.h" +#endif + +#endif /* !MLD_NATIVE_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/meta.h new file mode 100644 index 0000000000..393374c06f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/meta.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_X86_64_META_H +#define MLD_NATIVE_X86_64_META_H + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_X86_64_DEFAULT + +#define MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +#if !defined(__ASSEMBLER__) +#include +#include "../../common.h" +#include "../api.h" +#include "src/arith_native_x86_64.h" + +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t data[MLDSA_N]) +{ + if (mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + mld_nttunpack_avx2(data); + } +} + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_ntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_invntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)mld_rej_uniform_avx2(r, buf); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_32_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_88_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_caddq_avx2(a); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_32_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_88_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + return mld_poly_chknorm_avx2(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_17_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_19_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_avx2(c, a, b, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l4_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l5_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l7_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_NATIVE_X86_64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h new file mode 100644 index 0000000000..08d5abf74a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#define MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#include "../../../common.h" + +#include +#include "consts.h" + +#define MLD_AVX2_REJ_UNIFORM_BUFLEN \ + (5 * 168) /* REJ_UNIFORM_NBLOCKS * SHAKE128_RATE */ + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) + +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_rej_uniform_table MLD_NAMESPACE(mld_rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[256][8]; + +#define mld_ntt_avx2 MLD_NAMESPACE(ntt_avx2) +void mld_ntt_avx2(int32_t *r, const int32_t *qdata) +/* This must be kept in sync with the HOL-Light specification + * in proofs/hol_light/x86_64/proofs/mldsa_ntt.ml */ +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, MLDSA_N, 8380417)) + requires(qdata == mld_qdata) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + /* check-magic: off */ + ensures(array_abs_bound(r, 0, MLDSA_N, 42035262)) + /* check-magic: on */ +); + +#define mld_invntt_avx2 MLD_NAMESPACE(invntt_avx2) +void mld_invntt_avx2(int32_t *r, const int32_t *mld_qdata); + +#define mld_nttunpack_avx2 MLD_NAMESPACE(nttunpack_avx2) +void mld_nttunpack_avx2(int32_t *r); + +#define mld_rej_uniform_avx2 MLD_NAMESPACE(mld_rej_uniform_avx2) +unsigned mld_rej_uniform_avx2(int32_t *r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]); + +#define mld_rej_uniform_eta2_avx2 MLD_NAMESPACE(mld_rej_uniform_eta2_avx2) +unsigned mld_rej_uniform_eta2_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]); + +#define mld_rej_uniform_eta4_avx2 MLD_NAMESPACE(mld_rej_uniform_eta4_avx2) +unsigned mld_rej_uniform_eta4_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]); + +#define mld_poly_decompose_32_avx2 MLD_NAMESPACE(mld_poly_decompose_32_avx2) +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_avx2 MLD_NAMESPACE(mld_poly_decompose_88_avx2) +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_avx2 MLD_NAMESPACE(poly_caddq_avx2) +void mld_poly_caddq_avx2(int32_t *r); + +#define mld_poly_use_hint_32_avx2 MLD_NAMESPACE(mld_poly_use_hint_32_avx2) +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_avx2 MLD_NAMESPACE(mld_poly_use_hint_88_avx2) +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_avx2 MLD_NAMESPACE(mld_poly_chknorm_avx2) +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_avx2 MLD_NAMESPACE(mld_polyz_unpack_17_avx2) +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a); + +#define mld_polyz_unpack_19_avx2 MLD_NAMESPACE(mld_polyz_unpack_19_avx2) +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a); + +#define mld_pointwise_avx2 MLD_NAMESPACE(pointwise_avx2) +void mld_pointwise_avx2(int32_t *c, const int32_t *a, const int32_t *b, + const int32_t *qdata); + +#define mld_pointwise_acc_l4_avx2 MLD_NAMESPACE(pointwise_acc_l4_avx2) +void mld_pointwise_acc_l4_avx2(int32_t c[MLDSA_N], const int32_t a[4][MLDSA_N], + const int32_t b[4][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l5_avx2 MLD_NAMESPACE(pointwise_acc_l5_avx2) +void mld_pointwise_acc_l5_avx2(int32_t c[MLDSA_N], const int32_t a[5][MLDSA_N], + const int32_t b[5][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l7_avx2 MLD_NAMESPACE(pointwise_acc_l7_avx2) +void mld_pointwise_acc_l7_avx2(int32_t c[MLDSA_N], const int32_t a[7][MLDSA_N], + const int32_t b[7][MLDSA_N], + const int32_t *qdata); + +#endif /* !MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/consts.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/consts.c new file mode 100644 index 0000000000..aaca3535ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/consts.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include "consts.h" + +/* + * Table of zeta values used in the AVX2 forward and inverse NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_qdata[624] = { + 8380417, 8380417, 8380417, 8380417, 8380417, + 8380417, 8380417, 8380417, 58728449, 58728449, + 58728449, 58728449, 58728449, 58728449, 58728449, + 58728449, -8395782, -8395782, -8395782, -8395782, + -8395782, -8395782, -8395782, -8395782, 41978, + 41978, 41978, 41978, 41978, 41978, + 41978, 41978, -151046689, 1830765815, -1929875198, + -1927777021, 1640767044, 1477910808, 1612161320, 1640734244, + 308362795, 308362795, 308362795, 308362795, -1815525077, + -1815525077, -1815525077, -1815525077, -1374673747, -1374673747, + -1374673747, -1374673747, -1091570561, -1091570561, -1091570561, + -1091570561, -1929495947, -1929495947, -1929495947, -1929495947, + 515185417, 515185417, 515185417, 515185417, -285697463, + -285697463, -285697463, -285697463, 625853735, 625853735, + 625853735, 625853735, 1727305304, 1727305304, 2082316400, + 2082316400, -1364982364, -1364982364, 858240904, 858240904, + 1806278032, 1806278032, 222489248, 222489248, -346752664, + -346752664, 684667771, 684667771, 1654287830, 1654287830, + -878576921, -878576921, -1257667337, -1257667337, -748618600, + -748618600, 329347125, 329347125, 1837364258, 1837364258, + -1443016191, -1443016191, -1170414139, -1170414139, -1846138265, + -1631226336, -1404529459, 1838055109, 1594295555, -1076973524, + -1898723372, -594436433, -202001019, -475984260, -561427818, + 1797021249, -1061813248, 2059733581, -1661512036, -1104976547, + -1750224323, -901666090, 418987550, 1831915353, -1925356481, + 992097815, 879957084, 2024403852, 1484874664, -1636082790, + -285388938, -1983539117, -1495136972, -950076368, -1714807468, + -952438995, -1574918427, 1350681039, -2143979939, 1599739335, + -1285853323, -993005454, -1440787840, 568627424, -783134478, + -588790216, 289871779, -1262003603, 2135294594, -1018755525, + -889861155, 1665705315, 1321868265, 1225434135, -1784632064, + 666258756, 675310538, -1555941048, -1999506068, -1499481951, + -695180180, -1375177022, 1777179795, 334803717, -178766299, + -518252220, 1957047970, 1146323031, -654783359, -1974159335, + 1651689966, 140455867, -1039411342, 1955560694, 1529189038, + -2131021878, -247357819, 1518161567, -86965173, 1708872713, + 1787797779, 1638590967, -120646188, -1669960606, -916321552, + 1155548552, 2143745726, 1210558298, -1261461890, -318346816, + 628664287, -1729304568, 1422575624, 1424130038, -1185330464, + 235321234, 168022240, 1206536194, 985155484, -894060583, + -898413, -1363460238, -605900043, 2027833504, 14253662, + 1014493059, 863641633, 1819892093, 2124962073, -1223601433, + -1920467227, -1637785316, -1536588520, 694382729, 235104446, + -1045062172, 831969619, -300448763, 756955444, -260312805, + 1554794072, 1339088280, -2040058690, -853476187, -2047270596, + -1723816713, -1591599803, -440824168, 1119856484, 1544891539, + 155290192, -973777462, 991903578, 912367099, -44694137, + 1176904444, -421552614, -818371958, 1747917558, -325927722, + 908452108, 1851023419, -1176751719, -1354528380, -72690498, + -314284737, 985022747, 963438279, -1078959975, 604552167, + -1021949428, 608791570, 173440395, -2126092136, -1316619236, + -1039370342, 6087993, -110126092, 565464272, -1758099917, + -1600929361, 879867909, -1809756372, 400711272, 1363007700, + 30313375, -326425360, 1683520342, -517299994, 2027935492, + -1372618620, 128353682, -1123881663, 137583815, -635454918, + -642772911, 45766801, 671509323, -2070602178, 419615363, + 1216882040, -270590488, -1276805128, 371462360, -1357098057, + -384158533, 827959816, -596344473, 702390549, -279505433, + -260424530, -71875110, -1208667171, -1499603926, 2036925262, + -540420426, 746144248, -1420958686, 2032221021, 1904936414, + 1257750362, 1926727420, 1931587462, 1258381762, 885133339, + 1629985060, 1967222129, 6363718, -1287922800, 1136965286, + 1779436847, 1116720494, 1042326957, 1405999311, 713994583, + 940195359, -1542497137, 2061661095, -883155599, 1726753853, + -1547952704, 394851342, 283780712, 776003547, 1123958025, + 201262505, 1934038751, 374860238, -3975713, 25847, + -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 1826347, 1826347, 1826347, + 2353451, 2353451, 2353451, 2353451, -359251, + -359251, -359251, -359251, -2091905, -2091905, + -2091905, -2091905, 3119733, 3119733, 3119733, + 3119733, -2884855, -2884855, -2884855, -2884855, + 3111497, 3111497, 3111497, 3111497, 2680103, + 2680103, 2680103, 2680103, 2725464, 2725464, + 1024112, 1024112, -1079900, -1079900, 3585928, + 3585928, -549488, -549488, -1119584, -1119584, + 2619752, 2619752, -2108549, -2108549, -2118186, + -2118186, -3859737, -3859737, -1399561, -1399561, + -3277672, -3277672, 1757237, 1757237, -19422, + -19422, 4010497, 4010497, 280005, 280005, + 2706023, 95776, 3077325, 3530437, -1661693, + -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, + -539299, -1699267, -1643818, 3505694, -3821735, + 3507263, -2140649, -1600420, 3699596, 811944, + 531354, 954230, 3881043, 3900724, -2556880, + 2071892, -2797779, -3930395, -3677745, -1452451, + 2176455, -1257611, -4083598, -3190144, -3632928, + 3412210, 2147896, -2967645, -411027, -671102, + -22981, -381987, 1852771, -3343383, 508951, + 44288, 904516, -3724342, 1653064, 2389356, + 759969, 189548, 3159746, -2409325, 1315589, + 1285669, -812732, -3019102, -3628969, -1528703, + -3041255, 3475950, -1585221, 1939314, -1000202, + -3157330, 126922, -983419, 2715295, -3693493, + -2477047, -1228525, -1308169, 1349076, -1430430, + 264944, 3097992, -1100098, 3958618, -8578, + -3249728, -210977, -1316856, -3553272, -1851402, + -177440, 1341330, -1584928, -1439742, -3881060, + 3839961, 2091667, -3342478, 266997, -3520352, + 900702, 495491, -655327, -3556995, 342297, + 3437287, 2842341, 4055324, -3767016, -2994039, + -1333058, -451100, -1279661, 1500165, -542412, + -2584293, -2013608, 1957272, -3183426, 810149, + -3038916, 2213111, -426683, -1667432, -2939036, + 183443, -554416, 3937738, 3407706, 2244091, + 2434439, -3759364, 1859098, -1613174, -3122442, + -525098, 286988, -3342277, 2691481, 1247620, + 1250494, 1869119, 1237275, 1312455, 1917081, + 777191, -2831860, -3724270, 2432395, 3369112, + 162844, 1652634, 3523897, -975884, 1723600, + -1104333, -2235985, -976891, 3919660, 1400424, + 2316500, -2446433, -1235728, -1197226, 909542, + -43260, 2031748, -768622, -2437823, 1735879, + -2590150, 2486353, 2635921, 1903435, -3318210, + 3306115, -2546312, 2235880, -1671176, 594136, + 2454455, 185531, 1616392, -3694233, 3866901, + 1717735, -1803090, -260646, -420899, 1612842, + -48306, -846154, 3817976, -3562462, 3513181, + -3193378, 819034, -522500, 3207046, -3595838, + 4108315, 203044, 1265009, 1595974, -3548272, + -1050970, -1430225, -1962642, -1374803, 3406031, + -1846953, -3776993, -164721, -1207385, 3014001, + -1799107, 269760, 472078, 1910376, -3833893, + -2286327, -3545687, -1362209, 1976782, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_consts) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/consts.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/consts.h new file mode 100644 index 0000000000..7fe08f454b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/consts.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#ifndef MLD_NATIVE_X86_64_SRC_CONSTS_H +#define MLD_NATIVE_X86_64_SRC_CONSTS_H +#include "../../../common.h" +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQ 0 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV 8 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV 16 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV 24 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV 32 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS 328 + +#ifndef __ASSEMBLER__ +#define mld_qdata MLD_NAMESPACE(qdata) +extern const int32_t mld_qdata[624]; +#endif + +#endif /* !MLD_NATIVE_X86_64_SRC_CONSTS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c new file mode 100644 index 0000000000..05d86d14fc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/************************************************* + * Name: mld_poly_caddq_avx2 + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *r: pointer to input/output polynomial + **************************************************/ +void mld_poly_caddq_avx2(int32_t *r) +{ + unsigned int i; + __m256i f, g; + const __m256i q = _mm256_set1_epi32(MLDSA_Q); + const __m256i zero = _mm256_setzero_si256(); + __m256i *rr = (__m256i *)r; + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256(&rr[i]); + g = _mm256_cmpgt_epi32(zero, f); + g = _mm256_and_si256(g, q); + f = _mm256_add_epi32(f, g); + _mm256_store_si256(&rr[i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_reduce) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c new file mode 100644 index 0000000000..50e2c7fa9b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B) +{ + unsigned int i; + __m256i f, t; + const __m256i bound = _mm256_set1_epi32(B - 1); + + t = _mm256_setzero_si256(); + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + f = _mm256_abs_epi32(f); + f = _mm256_cmpgt_epi32(f, bound); + t = _mm256_or_si256(t, f); + } + + return 1 - _mm256_testz_si256(t, t); +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_chknorm) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c new file mode 100644 index 0000000000..76846bf1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(31 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 4092 == intdiv(2 * intdiv(MLDSA_Q - 1, 32), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 4092. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 32*GAMMA2 = 16*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 16B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + * + * round(f1' * 1025 / 2^22) is in turn computed in 2 steps as + * round(floor(f1' * 1025 / 2^16) / 2^6). The mulhi computes f1'' = + * floor(f1' * 1025 / 2^16). As for the next step f1 = round(f1'' / 2^6), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^9) = round(f1'' * 2^9 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 1025 / 2^16) = 1025 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(16B / B) = 16 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 16, i.e. f > 31*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 31*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 15, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c new file mode 100644 index 0000000000..463506b962 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ + +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 1488 == intdiv(2 * intdiv(MLDSA_Q - 1, 88), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 1488. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 88*GAMMA2 = 44*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 44B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + * + * round(f1' * 11275 / 2^24) is in turn computed in 2 steps as + * round(floor(f1' * 11275 / 2^16) / 2^8). The mulhi computes f1'' = + * floor(f1' * 11275 / 2^16). As for the next step f1 = round(f1'' / 2^8), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^7) = round(f1'' * 2^7 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 11275 / 2^16) = 11275 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(44B / B) = 44 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 44, i.e. f > 87*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 87*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 43, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c new file mode 100644 index 0000000000..0094bc93a9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + const __m256i mask = _mm256_set1_epi32(15); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_32_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 16 */ + f1 = _mm256_add_epi32(f1, h); + f1 = _mm256_and_si256(f1, mask); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c new file mode 100644 index 0000000000..b109ab6351 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + const __m256i max = _mm256_set1_epi32(43); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_88_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 44 */ + f1 = _mm256_add_epi32(f1, h); + f1 = MLD_MM256_BLENDV_EPI32(f1, max, f1); + f = _mm256_cmpgt_epi32(f1, max); + f1 = MLD_MM256_BLENDV_EPI32(f1, zero, f); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c new file mode 100644 index 0000000000..f6c08a832f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 27, 26, 25, -1, 25, 24, 23, -1, 8, 7, + 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0); + const __m256i srlvdidx = _mm256_set_epi32(6, 4, 2, 0, 6, 4, 2, 0); + const __m256i mask = _mm256_set1_epi32(0x3FFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 17)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[18 * i]); + /* Load bytes 2..17 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[18 * i + 2]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-8 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 8, 7, 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte8, byte7, byte6, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,27, 26, 25, -1,25, 24, 23] │ + * │ Result: [0, byte17, byte16, byte15, ..., 0, byte11, byte10, byte9] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 18 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 32..55 48..71 + * 72..95 88..111 104..127 120..143 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 18..39 36..55 54..71 + * 72..95 90..111 108..127 126..143 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..17 18..35 36..53 54..71 + * 72..89 90..107 108..125 126..143 */ + + /* Map [0, 1, ..., 2^18-1] to [2^17, 2^17-1, ..., -2^17+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_17) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c new file mode 100644 index 0000000000..4a5ce48f38 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 26, 25, 24, -1, 24, 23, 22, -1, 9, 8, + 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0); + /* Equivalent to _mm256_set_epi32(4, 0, 4, 0, 4, 0, 4, 0) */ + const __m256i srlvdidx = _mm256_set1_epi64x((uint64_t)4 << 32); + const __m256i mask = _mm256_set1_epi32(0xFFFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 19)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[20 * i]); + /* Load bytes 4..19 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[20 * i + 4]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-9 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 9, 8, 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte9, byte8, byte7, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,26, 25, 24, -1,24, 23, 22] │ + * │ Result: [0, byte19, byte18, byte17, ..., 0, byte12, byte11, byte10] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 20 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 40..63 56..79 + * 80..103 96..119 120..143 136..159 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 20..39 40..63 60..79 + * 80..103 100..119 120..143 140..159 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..19 20..39 40..59 60..79 + * 80..99 100..119 120..139 140..159 */ + + /* Map [0, 1, ..., 2^20-1] to [2^19, 2^19-1, ..., -2^19+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_19) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c new file mode 100644 index 0000000000..07a5df9706 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The pqcrystals implementation assumes a buffer that is 8 bytes + *. larger as the first loop overreads by 8 bytes that are then + * discarded. We instead do not pad the buffer and do not overread. + * The performance impact is negligible and it does not force the + * frontend to perform the unintuitive padding. + */ + +unsigned int mld_rej_uniform_avx2( + int32_t *MLD_RESTRICT r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i d, tmp; + const __m256i bound = _mm256_set1_epi32(MLDSA_Q); + const __m256i mask = _mm256_set1_epi32(0x7FFFFF); + const __m256i idx8 = + _mm256_set_epi8(-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4, + -1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 32) + { + d = _mm256_loadu_si256((__m256i *)&buf[pos]); + + /* Permute 64-bit lanes + * 0x94 = 10010100b rearranges 64-bit lanes as: [3,2,1,0] -> [2,1,1,0] + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Original Layout ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ bytes 16..23 │ bytes 24..31 │ + * └─────────────────┴─────────────────┴─────────────────┴─────────────────┘ + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Layout after permute ║ + * ║ Byte indices in high half shifted down by 8 positions ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌───────────────┬─────────────────┐ ┌─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ │ bytes 8..15 │ bytes 16..23 │ + * └───────────────┴─────────────────┘ └─────────────────┴─────────────────┘ + * Lower 128-bit lane (bytes 0-15) Upper 128-bit lane (bytes 16-31) + */ + d = _mm256_permute4x64_epi64(d, 0x94); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-11 into low 128-bit half of permuted vector────────────────┐ + * │ Shuffle: [-1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0] │ + * │ Result: [0, byte11, byte10, byte9, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 4-15 into high 128-bit half of permuted vector ──────────────┐ + * │ Shuffle: [-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4] │ + * │ Result: [0, byte23, byte22, byte21, ..., 0, byte14, byte13, byte12 │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + d = _mm256_shuffle_epi8(d, idx8); + d = _mm256_and_si256(d, mask); + pos += 24; + + tmp = _mm256_sub_epi32(d, bound); + good = (uint32_t)_mm256_movemask_ps((__m256)tmp); + tmp = _mm256_cvtepu8_epi32( + _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good])); + d = _mm256_permutevar8x32_epi32(d, tmp); + + _mm256_storeu_si256((__m256i *)&r[ctr], d); + ctr += (unsigned)_mm_popcnt_u32(good); + } + + while (ctr < MLDSA_N && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 3) + { + uint32_t t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + /* Safe because t < MLDSA_Q. */ + r[ctr++] = (int32_t)t; + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c new file mode 100644 index 0000000000..70c5c42c70 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA2 2 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ +unsigned int mld_rej_uniform_eta2_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1, f2; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA2); + const __m256i bound = mask; + /* check-magic: -6560 == 32*round(-2**10 / 5) */ + const __m256i v = _mm256_set1_epi32(-6560); + const __m256i p = _mm256_set1_epi32(5); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 15) + { + t0 = t0 - (205 * t0 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t0); + } + if (t1 < 15 && ctr < MLDSA_N) + { + t1 = t1 - (205 * t1 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta2) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA2 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c new file mode 100644 index 0000000000..ba00e91252 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA4 4 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ + +unsigned int mld_rej_uniform_eta4_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA4); + const __m256i bound = _mm256_set1_epi8(9); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 9) + { + r[ctr++] = (int32_t)(4 - t0); + } + if (t1 < 9 && ctr < MLDSA_N) + { + r[ctr++] = (int32_t)(4 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta4) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA4 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/rej_uniform_table.c new file mode 100644 index 0000000000..6c537b4542 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/native/x86_64/src/rej_uniform_table.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" + +/* + * Lookup table used by rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[256][8] = { + {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, + {2, 0, 0, 0, 0, 0, 0, 0}, {0, 2, 0, 0, 0, 0, 0, 0}, + {1, 2, 0, 0, 0, 0, 0, 0}, {0, 1, 2, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 0, 0}, {0, 3, 0, 0, 0, 0, 0, 0}, + {1, 3, 0, 0, 0, 0, 0, 0}, {0, 1, 3, 0, 0, 0, 0, 0}, + {2, 3, 0, 0, 0, 0, 0, 0}, {0, 2, 3, 0, 0, 0, 0, 0}, + {1, 2, 3, 0, 0, 0, 0, 0}, {0, 1, 2, 3, 0, 0, 0, 0}, + {4, 0, 0, 0, 0, 0, 0, 0}, {0, 4, 0, 0, 0, 0, 0, 0}, + {1, 4, 0, 0, 0, 0, 0, 0}, {0, 1, 4, 0, 0, 0, 0, 0}, + {2, 4, 0, 0, 0, 0, 0, 0}, {0, 2, 4, 0, 0, 0, 0, 0}, + {1, 2, 4, 0, 0, 0, 0, 0}, {0, 1, 2, 4, 0, 0, 0, 0}, + {3, 4, 0, 0, 0, 0, 0, 0}, {0, 3, 4, 0, 0, 0, 0, 0}, + {1, 3, 4, 0, 0, 0, 0, 0}, {0, 1, 3, 4, 0, 0, 0, 0}, + {2, 3, 4, 0, 0, 0, 0, 0}, {0, 2, 3, 4, 0, 0, 0, 0}, + {1, 2, 3, 4, 0, 0, 0, 0}, {0, 1, 2, 3, 4, 0, 0, 0}, + {5, 0, 0, 0, 0, 0, 0, 0}, {0, 5, 0, 0, 0, 0, 0, 0}, + {1, 5, 0, 0, 0, 0, 0, 0}, {0, 1, 5, 0, 0, 0, 0, 0}, + {2, 5, 0, 0, 0, 0, 0, 0}, {0, 2, 5, 0, 0, 0, 0, 0}, + {1, 2, 5, 0, 0, 0, 0, 0}, {0, 1, 2, 5, 0, 0, 0, 0}, + {3, 5, 0, 0, 0, 0, 0, 0}, {0, 3, 5, 0, 0, 0, 0, 0}, + {1, 3, 5, 0, 0, 0, 0, 0}, {0, 1, 3, 5, 0, 0, 0, 0}, + {2, 3, 5, 0, 0, 0, 0, 0}, {0, 2, 3, 5, 0, 0, 0, 0}, + {1, 2, 3, 5, 0, 0, 0, 0}, {0, 1, 2, 3, 5, 0, 0, 0}, + {4, 5, 0, 0, 0, 0, 0, 0}, {0, 4, 5, 0, 0, 0, 0, 0}, + {1, 4, 5, 0, 0, 0, 0, 0}, {0, 1, 4, 5, 0, 0, 0, 0}, + {2, 4, 5, 0, 0, 0, 0, 0}, {0, 2, 4, 5, 0, 0, 0, 0}, + {1, 2, 4, 5, 0, 0, 0, 0}, {0, 1, 2, 4, 5, 0, 0, 0}, + {3, 4, 5, 0, 0, 0, 0, 0}, {0, 3, 4, 5, 0, 0, 0, 0}, + {1, 3, 4, 5, 0, 0, 0, 0}, {0, 1, 3, 4, 5, 0, 0, 0}, + {2, 3, 4, 5, 0, 0, 0, 0}, {0, 2, 3, 4, 5, 0, 0, 0}, + {1, 2, 3, 4, 5, 0, 0, 0}, {0, 1, 2, 3, 4, 5, 0, 0}, + {6, 0, 0, 0, 0, 0, 0, 0}, {0, 6, 0, 0, 0, 0, 0, 0}, + {1, 6, 0, 0, 0, 0, 0, 0}, {0, 1, 6, 0, 0, 0, 0, 0}, + {2, 6, 0, 0, 0, 0, 0, 0}, {0, 2, 6, 0, 0, 0, 0, 0}, + {1, 2, 6, 0, 0, 0, 0, 0}, {0, 1, 2, 6, 0, 0, 0, 0}, + {3, 6, 0, 0, 0, 0, 0, 0}, {0, 3, 6, 0, 0, 0, 0, 0}, + {1, 3, 6, 0, 0, 0, 0, 0}, {0, 1, 3, 6, 0, 0, 0, 0}, + {2, 3, 6, 0, 0, 0, 0, 0}, {0, 2, 3, 6, 0, 0, 0, 0}, + {1, 2, 3, 6, 0, 0, 0, 0}, {0, 1, 2, 3, 6, 0, 0, 0}, + {4, 6, 0, 0, 0, 0, 0, 0}, {0, 4, 6, 0, 0, 0, 0, 0}, + {1, 4, 6, 0, 0, 0, 0, 0}, {0, 1, 4, 6, 0, 0, 0, 0}, + {2, 4, 6, 0, 0, 0, 0, 0}, {0, 2, 4, 6, 0, 0, 0, 0}, + {1, 2, 4, 6, 0, 0, 0, 0}, {0, 1, 2, 4, 6, 0, 0, 0}, + {3, 4, 6, 0, 0, 0, 0, 0}, {0, 3, 4, 6, 0, 0, 0, 0}, + {1, 3, 4, 6, 0, 0, 0, 0}, {0, 1, 3, 4, 6, 0, 0, 0}, + {2, 3, 4, 6, 0, 0, 0, 0}, {0, 2, 3, 4, 6, 0, 0, 0}, + {1, 2, 3, 4, 6, 0, 0, 0}, {0, 1, 2, 3, 4, 6, 0, 0}, + {5, 6, 0, 0, 0, 0, 0, 0}, {0, 5, 6, 0, 0, 0, 0, 0}, + {1, 5, 6, 0, 0, 0, 0, 0}, {0, 1, 5, 6, 0, 0, 0, 0}, + {2, 5, 6, 0, 0, 0, 0, 0}, {0, 2, 5, 6, 0, 0, 0, 0}, + {1, 2, 5, 6, 0, 0, 0, 0}, {0, 1, 2, 5, 6, 0, 0, 0}, + {3, 5, 6, 0, 0, 0, 0, 0}, {0, 3, 5, 6, 0, 0, 0, 0}, + {1, 3, 5, 6, 0, 0, 0, 0}, {0, 1, 3, 5, 6, 0, 0, 0}, + {2, 3, 5, 6, 0, 0, 0, 0}, {0, 2, 3, 5, 6, 0, 0, 0}, + {1, 2, 3, 5, 6, 0, 0, 0}, {0, 1, 2, 3, 5, 6, 0, 0}, + {4, 5, 6, 0, 0, 0, 0, 0}, {0, 4, 5, 6, 0, 0, 0, 0}, + {1, 4, 5, 6, 0, 0, 0, 0}, {0, 1, 4, 5, 6, 0, 0, 0}, + {2, 4, 5, 6, 0, 0, 0, 0}, {0, 2, 4, 5, 6, 0, 0, 0}, + {1, 2, 4, 5, 6, 0, 0, 0}, {0, 1, 2, 4, 5, 6, 0, 0}, + {3, 4, 5, 6, 0, 0, 0, 0}, {0, 3, 4, 5, 6, 0, 0, 0}, + {1, 3, 4, 5, 6, 0, 0, 0}, {0, 1, 3, 4, 5, 6, 0, 0}, + {2, 3, 4, 5, 6, 0, 0, 0}, {0, 2, 3, 4, 5, 6, 0, 0}, + {1, 2, 3, 4, 5, 6, 0, 0}, {0, 1, 2, 3, 4, 5, 6, 0}, + {7, 0, 0, 0, 0, 0, 0, 0}, {0, 7, 0, 0, 0, 0, 0, 0}, + {1, 7, 0, 0, 0, 0, 0, 0}, {0, 1, 7, 0, 0, 0, 0, 0}, + {2, 7, 0, 0, 0, 0, 0, 0}, {0, 2, 7, 0, 0, 0, 0, 0}, + {1, 2, 7, 0, 0, 0, 0, 0}, {0, 1, 2, 7, 0, 0, 0, 0}, + {3, 7, 0, 0, 0, 0, 0, 0}, {0, 3, 7, 0, 0, 0, 0, 0}, + {1, 3, 7, 0, 0, 0, 0, 0}, {0, 1, 3, 7, 0, 0, 0, 0}, + {2, 3, 7, 0, 0, 0, 0, 0}, {0, 2, 3, 7, 0, 0, 0, 0}, + {1, 2, 3, 7, 0, 0, 0, 0}, {0, 1, 2, 3, 7, 0, 0, 0}, + {4, 7, 0, 0, 0, 0, 0, 0}, {0, 4, 7, 0, 0, 0, 0, 0}, + {1, 4, 7, 0, 0, 0, 0, 0}, {0, 1, 4, 7, 0, 0, 0, 0}, + {2, 4, 7, 0, 0, 0, 0, 0}, {0, 2, 4, 7, 0, 0, 0, 0}, + {1, 2, 4, 7, 0, 0, 0, 0}, {0, 1, 2, 4, 7, 0, 0, 0}, + {3, 4, 7, 0, 0, 0, 0, 0}, {0, 3, 4, 7, 0, 0, 0, 0}, + {1, 3, 4, 7, 0, 0, 0, 0}, {0, 1, 3, 4, 7, 0, 0, 0}, + {2, 3, 4, 7, 0, 0, 0, 0}, {0, 2, 3, 4, 7, 0, 0, 0}, + {1, 2, 3, 4, 7, 0, 0, 0}, {0, 1, 2, 3, 4, 7, 0, 0}, + {5, 7, 0, 0, 0, 0, 0, 0}, {0, 5, 7, 0, 0, 0, 0, 0}, + {1, 5, 7, 0, 0, 0, 0, 0}, {0, 1, 5, 7, 0, 0, 0, 0}, + {2, 5, 7, 0, 0, 0, 0, 0}, {0, 2, 5, 7, 0, 0, 0, 0}, + {1, 2, 5, 7, 0, 0, 0, 0}, {0, 1, 2, 5, 7, 0, 0, 0}, + {3, 5, 7, 0, 0, 0, 0, 0}, {0, 3, 5, 7, 0, 0, 0, 0}, + {1, 3, 5, 7, 0, 0, 0, 0}, {0, 1, 3, 5, 7, 0, 0, 0}, + {2, 3, 5, 7, 0, 0, 0, 0}, {0, 2, 3, 5, 7, 0, 0, 0}, + {1, 2, 3, 5, 7, 0, 0, 0}, {0, 1, 2, 3, 5, 7, 0, 0}, + {4, 5, 7, 0, 0, 0, 0, 0}, {0, 4, 5, 7, 0, 0, 0, 0}, + {1, 4, 5, 7, 0, 0, 0, 0}, {0, 1, 4, 5, 7, 0, 0, 0}, + {2, 4, 5, 7, 0, 0, 0, 0}, {0, 2, 4, 5, 7, 0, 0, 0}, + {1, 2, 4, 5, 7, 0, 0, 0}, {0, 1, 2, 4, 5, 7, 0, 0}, + {3, 4, 5, 7, 0, 0, 0, 0}, {0, 3, 4, 5, 7, 0, 0, 0}, + {1, 3, 4, 5, 7, 0, 0, 0}, {0, 1, 3, 4, 5, 7, 0, 0}, + {2, 3, 4, 5, 7, 0, 0, 0}, {0, 2, 3, 4, 5, 7, 0, 0}, + {1, 2, 3, 4, 5, 7, 0, 0}, {0, 1, 2, 3, 4, 5, 7, 0}, + {6, 7, 0, 0, 0, 0, 0, 0}, {0, 6, 7, 0, 0, 0, 0, 0}, + {1, 6, 7, 0, 0, 0, 0, 0}, {0, 1, 6, 7, 0, 0, 0, 0}, + {2, 6, 7, 0, 0, 0, 0, 0}, {0, 2, 6, 7, 0, 0, 0, 0}, + {1, 2, 6, 7, 0, 0, 0, 0}, {0, 1, 2, 6, 7, 0, 0, 0}, + {3, 6, 7, 0, 0, 0, 0, 0}, {0, 3, 6, 7, 0, 0, 0, 0}, + {1, 3, 6, 7, 0, 0, 0, 0}, {0, 1, 3, 6, 7, 0, 0, 0}, + {2, 3, 6, 7, 0, 0, 0, 0}, {0, 2, 3, 6, 7, 0, 0, 0}, + {1, 2, 3, 6, 7, 0, 0, 0}, {0, 1, 2, 3, 6, 7, 0, 0}, + {4, 6, 7, 0, 0, 0, 0, 0}, {0, 4, 6, 7, 0, 0, 0, 0}, + {1, 4, 6, 7, 0, 0, 0, 0}, {0, 1, 4, 6, 7, 0, 0, 0}, + {2, 4, 6, 7, 0, 0, 0, 0}, {0, 2, 4, 6, 7, 0, 0, 0}, + {1, 2, 4, 6, 7, 0, 0, 0}, {0, 1, 2, 4, 6, 7, 0, 0}, + {3, 4, 6, 7, 0, 0, 0, 0}, {0, 3, 4, 6, 7, 0, 0, 0}, + {1, 3, 4, 6, 7, 0, 0, 0}, {0, 1, 3, 4, 6, 7, 0, 0}, + {2, 3, 4, 6, 7, 0, 0, 0}, {0, 2, 3, 4, 6, 7, 0, 0}, + {1, 2, 3, 4, 6, 7, 0, 0}, {0, 1, 2, 3, 4, 6, 7, 0}, + {5, 6, 7, 0, 0, 0, 0, 0}, {0, 5, 6, 7, 0, 0, 0, 0}, + {1, 5, 6, 7, 0, 0, 0, 0}, {0, 1, 5, 6, 7, 0, 0, 0}, + {2, 5, 6, 7, 0, 0, 0, 0}, {0, 2, 5, 6, 7, 0, 0, 0}, + {1, 2, 5, 6, 7, 0, 0, 0}, {0, 1, 2, 5, 6, 7, 0, 0}, + {3, 5, 6, 7, 0, 0, 0, 0}, {0, 3, 5, 6, 7, 0, 0, 0}, + {1, 3, 5, 6, 7, 0, 0, 0}, {0, 1, 3, 5, 6, 7, 0, 0}, + {2, 3, 5, 6, 7, 0, 0, 0}, {0, 2, 3, 5, 6, 7, 0, 0}, + {1, 2, 3, 5, 6, 7, 0, 0}, {0, 1, 2, 3, 5, 6, 7, 0}, + {4, 5, 6, 7, 0, 0, 0, 0}, {0, 4, 5, 6, 7, 0, 0, 0}, + {1, 4, 5, 6, 7, 0, 0, 0}, {0, 1, 4, 5, 6, 7, 0, 0}, + {2, 4, 5, 6, 7, 0, 0, 0}, {0, 2, 4, 5, 6, 7, 0, 0}, + {1, 2, 4, 5, 6, 7, 0, 0}, {0, 1, 2, 4, 5, 6, 7, 0}, + {3, 4, 5, 6, 7, 0, 0, 0}, {0, 3, 4, 5, 6, 7, 0, 0}, + {1, 3, 4, 5, 6, 7, 0, 0}, {0, 1, 3, 4, 5, 6, 7, 0}, + {2, 3, 4, 5, 6, 7, 0, 0}, {0, 2, 3, 4, 5, 6, 7, 0}, + {1, 2, 3, 4, 5, 6, 7, 0}, {0, 1, 2, 3, 4, 5, 6, 7}, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/packing.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/packing.c new file mode 100644 index 0000000000..26da273856 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/packing.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include + +#include "common.h" +#include "packing.h" +#include "poly.h" +#include "polyvec.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_unpack_hints MLD_ADD_PARAM_SET(mld_unpack_hints) +/* End of parameter set namespacing */ + +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +{ + unsigned int i; + + mld_memcpy(pk, rho, MLDSA_SEEDBYTES); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt1_pack(pk + MLDSA_SEEDBYTES + i * MLDSA_POLYT1_PACKEDBYTES, + &t1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +{ + unsigned int i; + + mld_memcpy(rho, pk, MLDSA_SEEDBYTES); + pk += MLDSA_SEEDBYTES; + + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt1_unpack(&t1->vec[i], pk + i * MLDSA_POLYT1_PACKEDBYTES); + } +} + +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +{ + mld_memcpy(sk, rho, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, key, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, tr, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_pack_eta(sk, s1); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_eta(sk, s2); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_t0(sk, t0); +} + +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +{ + mld_memcpy(rho, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(key, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(tr, sk, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_unpack_eta(s1, sk); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_eta(s2, sk); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_t0(t0, sk); +} + +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +{ + unsigned int i, j, k; + + mld_memcpy(sig, c, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + /* skip z component - packed via mld_pack_sig_z */ + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + /* Encode hints h */ + + /* The final section of sig[] is MLDSA_POLYVECH_PACKEDBYTES long, where + * MLDSA_POLYVECH_PACKEDBYTES = MLDSA_OMEGA + MLDSA_K + * + * The first OMEGA bytes record the index numbers of the coefficients + * that are not equal to 0 + * + * The final K bytes record a running tally of the number of hints + * coming from each of the K polynomials in h. + * + * The pre-condition tells us that number_of_hints <= OMEGA, so some + * bytes may not be written, so we initialize all of them to zero + * to start. + */ + mld_memset(sig, 0, MLDSA_POLYVECH_PACKEDBYTES); + + k = 0; + /* For each polynomial in h... */ + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* For each coefficient in that polynomial, record it as as hint */ + /* if its value is not zero */ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + assigns(j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(j <= MLDSA_N) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* The reference implementation implicitly relies on the total */ + /* number of hints being less than OMEGA, assuming h is valid. */ + /* In mldsa-native, we check this explicitly to ease proof of */ + /* type safety. */ + if (h->vec[i].coeffs[j] != 0 && k < number_of_hints) + { + /* The enclosing if condition AND the loop invariant infer */ + /* that k < MLDSA_OMEGA, so writing to sig[k] is safe and k */ + /* can be incremented. */ + sig[k++] = (uint8_t)j; + } + } + /* Having recorded all the hints for this polynomial, also */ + /* record the running tally into the correct "slot" for that */ + /* coefficient in the final K bytes */ + sig[MLDSA_OMEGA + i] = (uint8_t)k; + } +} + +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +{ + sig += MLDSA_CTILDEBYTES; + sig += i * MLDSA_POLYZ_PACKEDBYTES; + mld_polyz_pack(sig, zi); +} + +/************************************************* + * Name: mld_unpack_hints + * + * Description: Unpack raw hint bytes into a polyveck + * struct + * + * Arguments: - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]: + * raw hint bytes + * + * Returns 1 in case of malformed hints; otherwise 0. + **************************************************/ +static int mld_unpack_hints( + mld_polyveck *h, const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(packed_hints, MLDSA_POLYVECH_PACKEDBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + /* All returned coefficients are either 0 or 1 */ + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +) +{ + unsigned int i, j; + unsigned int old_hint_count; + + /* Set all coefficients of all polynomials to 0. */ + /* Only those that are actually non-zero hints will */ + /* be overwritten below. */ + mld_memset(h, 0, sizeof(mld_polyveck)); + + old_hint_count = 0; + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + /* Grab the hint count for the i'th polynomial */ + const unsigned int new_hint_count = packed_hints[MLDSA_OMEGA + i]; + + /* new_hint_count must increase or stay the same, but also remain */ + /* less than or equal to MLDSA_OMEGA */ + if (new_hint_count < old_hint_count || new_hint_count > MLDSA_OMEGA) + { + /* Error - new_hint_count is invalid */ + return 1; + } + + /* If new_hint_count == old_hint_count, then this polynomial has */ + /* zero hints, so this loop executes zero times and we move */ + /* straight on to the next polynomial. */ + for (j = old_hint_count; j < new_hint_count; ++j) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + const uint8_t this_hint_index = packed_hints[j]; + + /* Coefficients must be ordered for strong unforgeability */ + if (j > old_hint_count && this_hint_index <= packed_hints[j - 1]) + { + return 1; + } + h->vec[i].coeffs[this_hint_index] = 1; + } + + old_hint_count = new_hint_count; + } + + /* Extra indices must be zero for strong unforgeability */ + for (j = old_hint_count; j < MLDSA_OMEGA; ++j) + __loop__( + invariant(j <= MLDSA_OMEGA) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + if (packed_hints[j] != 0) + { + return 1; + } + } + + return 0; +} + +MLD_INTERNAL_API +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +{ + mld_memcpy(c, sig, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + mld_polyvecl_unpack_z(z, sig); + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + return mld_unpack_hints(h, sig); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_unpack_hints diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/packing.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/packing.h new file mode 100644 index 0000000000..19095d08cd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/packing.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PACKING_H +#define MLD_PACKING_H + +#include +#include "polyvec.h" + +#define mld_pack_pk MLD_NAMESPACE_KL(pack_pk) +/************************************************* + * Name: mld_pack_pk + * + * Description: Bit-pack public key pk = (rho, t1). + * + * Arguments: - uint8_t pk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const mld_polyveck *t1: pointer to vector t1 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) +); + + +#define mld_pack_sk MLD_NAMESPACE_KL(pack_sk) +/************************************************* + * Name: mld_pack_sk + * + * Description: Bit-pack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - uint8_t sk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const uint8_t tr[]: byte array containing tr + * - const uint8_t key[]: byte array containing key + * - const mld_polyveck *t0: pointer to vector t0 + * - const mld_polyvecl *s1: pointer to vector s1 + * - const mld_polyveck *s2: pointer to vector s2 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +__contract__( + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + requires(forall(k2, 0, MLDSA_K, + array_abs_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) +); + + +#define mld_pack_sig_c_h MLD_NAMESPACE_KL(pack_sig_c_h) +/************************************************* + * Name: mld_pack_sig_c_h + * + * Description: Bit-pack c and h component of sig = (c, z, h). + * The z component is packed separately using mld_pack_sig_z. + * + * Arguments: - uint8_t sig[]: output byte array + * - const uint8_t *c: pointer to challenge hash length + * MLDSA_SEEDBYTES + * - const mld_polyveck *h: pointer to hint vector h + * - const unsigned int number_of_hints: total + * hints in *h + * + * Note that the number_of_hints argument is not present + * in the reference implementation. It is added here to ease + * proof of type safety. + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + requires(number_of_hints <= MLDSA_OMEGA) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_pack_sig_z MLD_NAMESPACE_KL(pack_sig_z) +/************************************************* + * Name: mld_pack_sig_z + * + * Description: Bit-pack single polynomial of z component of sig = (c, z, h). + * The c and h components are packed separately using + * mld_pack_sig_c_h. + * + * Arguments: - uint8_t sig[]: output byte array + * - const mld_poly *zi: pointer to a single polynomial in z + * - const unsigned int i: index of zi in vector z + * + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(zi, sizeof(mld_poly))) + requires(i < MLDSA_L) + requires(array_bound(zi->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_unpack_pk MLD_NAMESPACE_KL(unpack_pk) +/************************************************* + * Name: mld_unpack_pk + * + * Description: Unpack public key pk = (rho, t1). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const mld_polyveck *t1: pointer to output vector t1 + * - uint8_t pk[]: byte array containing bit-packed pk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) +); + + +#define mld_unpack_sk MLD_NAMESPACE_KL(unpack_sk) +/************************************************* + * Name: mld_unpack_sk + * + * Description: Unpack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const uint8_t tr[]: output byte array for tr + * - const uint8_t key[]: output byte array for key + * - const mld_polyveck *t0: pointer to output vector t0 + * - const mld_polyvecl *s1: pointer to output vector s1 + * - const mld_polyveck *s2: pointer to output vector s2 + * - uint8_t sk[]: byte array containing bit-packed sk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +__contract__( + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(key, MLDSA_SEEDBYTES)) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(s1, sizeof(mld_polyvecl))) + assigns(memory_slice(s2, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_unpack_sig MLD_NAMESPACE_KL(unpack_sig) +/************************************************* + * Name: mld_unpack_sig + * + * Description: Unpack signature sig = (c, z, h). + * + * Arguments: - uint8_t *c: pointer to output challenge hash + * - mld_polyvecl *z: pointer to output vector z + * - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t sig[]: byte array containing + * bit-packed signature + * + * Returns 1 in case of malformed signature; otherwise 0. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(c, MLDSA_CTILDEBYTES)) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(z->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +); +#endif /* !MLD_PACKING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/params.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/params.h new file mode 100644 index 0000000000..c67d2a33fb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/params.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PARAMS_H +#define MLD_PARAMS_H + +#define MLDSA_SEEDBYTES 32 +#define MLDSA_CRHBYTES 64 +#define MLDSA_TRBYTES 64 +#define MLDSA_RNDBYTES 32 +#define MLDSA_N 256 +#define MLDSA_Q 8380417 +#define MLDSA_Q_HALF ((MLDSA_Q + 1) / 2) +#define MLDSA_D 13 + +#if MLD_CONFIG_PARAMETER_SET == 44 + +#define MLDSA_K 4 +#define MLDSA_L 4 +#define MLDSA_ETA 2 +#define MLDSA_TAU 39 +#define MLDSA_BETA 78 +#define MLDSA_GAMMA1 (1 << 17) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 88) +#define MLDSA_OMEGA 80 +#define MLDSA_CTILDEBYTES 32 +#define MLDSA_POLYZ_PACKEDBYTES 576 +#define MLDSA_POLYW1_PACKEDBYTES 192 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#elif MLD_CONFIG_PARAMETER_SET == 65 + +#define MLDSA_K 6 +#define MLDSA_L 5 +#define MLDSA_ETA 4 +#define MLDSA_TAU 49 +#define MLDSA_BETA 196 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 55 +#define MLDSA_CTILDEBYTES 48 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 128 + +#elif MLD_CONFIG_PARAMETER_SET == 87 + +#define MLDSA_K 8 +#define MLDSA_L 7 +#define MLDSA_ETA 2 +#define MLDSA_TAU 60 +#define MLDSA_BETA 120 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 75 +#define MLDSA_CTILDEBYTES 64 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ + +#define MLDSA_POLYT1_PACKEDBYTES 320 +#define MLDSA_POLYT0_PACKEDBYTES 416 +#define MLDSA_POLYVECH_PACKEDBYTES (MLDSA_OMEGA + MLDSA_K) + +#define MLDSA_CRYPTO_PUBLICKEYBYTES \ + (MLDSA_SEEDBYTES + MLDSA_K * MLDSA_POLYT1_PACKEDBYTES) +#define MLDSA_CRYPTO_SECRETKEYBYTES \ + (2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + MLDSA_L * MLDSA_POLYETA_PACKEDBYTES + \ + MLDSA_K * MLDSA_POLYETA_PACKEDBYTES + MLDSA_K * MLDSA_POLYT0_PACKEDBYTES) +#define MLDSA_CRYPTO_BYTES \ + (MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES + \ + MLDSA_POLYVECH_PACKEDBYTES) + +#endif /* !MLD_PARAMS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/poly.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/poly.c new file mode 100644 index 0000000000..e40534e773 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/poly.c @@ -0,0 +1,973 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "common.h" +#include "ct.h" +#include "debug.h" +#include "poly.h" +#include "reduce.h" +#include "rounding.h" +#include "symmetric.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +#include "zetas.inc" + +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + { + a->coeffs[i] = mld_reduce32(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_STATIC_TESTABLE void mld_poly_caddq_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + ) + { + a->coeffs[i] = mld_caddq(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_POLY_CADDQ) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_poly_caddq_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + mld_poly_caddq_c(a); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1])) + invariant(forall(k2, 0, i, r->coeffs[k2] < MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k2, 0, i, r->coeffs[k2] >= INT32_MIN)) + ) + { + r->coeffs[i] = r->coeffs[i] + b->coeffs[i]; + } +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(r->coeffs, 0, i, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + ) + { + r->coeffs[i] = r->coeffs[i] - b->coeffs[i]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N; i++) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))) + { + /* Reference: uses a left shift by MLDSA_D which is undefined behaviour in + * C90/C99 + */ + a->coeffs[i] *= (1 << MLDSA_D); + } + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + + +static MLD_INLINE int32_t mld_fqmul(int32_t a, int32_t b) +__contract__( + requires(b > -MLDSA_Q_HALF && b < MLDSA_Q_HALF) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* Bounds: We argue in mld_montgomery_reduce() that the reult + * of Montgomery reduction is < MLDSA_Q if the input is smaller + * than 2^31 * MLDSA_Q in absolute value. Indeed, we have: + * + * |a * b| = |a| * |b| + * < 2^31 * MLDSA_Q_HALF + * < 2^31 * MLDSA_Q + */ + return mld_montgomery_reduce((int64_t)a * (int64_t)b); +} + +/* mld_ntt_butterfly_block() + * + * Computes a block CT butterflies with a fixed twiddle factor, + * using Montgomery multiplication. + * + * Parameters: + * - r: Pointer to base of polynomial (_not_ the base of butterfly block) + * - zeta: Twiddle factor to use for the butterfly. This must be in + * Montgomery form and signed canonical. + * - start: Offset to the beginning of the butterfly block + * - len: Index difference between coefficients subject to a butterfly + * - bound: Ghost variable describing coefficient bound: Prior to `start`, + * coefficients must be bound by `bound + MLDSA_Q`. Post `start`, + * they must be bound by `bound`. + * When this function returns, output coefficients in the index range + * [start, start+2*len) have bound bumped to `bound + MLDSA_Q`. + * Example: + * - start=8, len=4 + * This would compute the following four butterflies + * 8 -- 12 + * 9 -- 13 + * 10 -- 14 + * 11 -- 15 + * - start=4, len=2 + * This would compute the following two butterflies + * 4 -- 6 + * 5 -- 7 + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_butterfly_block(int32_t r[MLDSA_N], + const int32_t zeta, + const unsigned start, + const unsigned len, + const unsigned bound) +__contract__( + requires(start < MLDSA_N) + requires(1 <= len && len <= MLDSA_N / 2 && start + 2 * len <= MLDSA_N) + requires(0 <= bound && bound < INT32_MAX - MLDSA_Q) + requires(-MLDSA_Q_HALF < zeta && zeta < MLDSA_Q_HALF) + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, start, bound + MLDSA_Q)) + requires(array_abs_bound(r, start, MLDSA_N, bound)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, start + 2*len, bound + MLDSA_Q)) + ensures(array_abs_bound(r, start + 2 * len, MLDSA_N, bound))) +{ + /* `bound` is a ghost variable only needed in the CBMC specification */ + unsigned j; + ((void)bound); + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + /* + * Coefficients are updated in strided pairs, so the bounds for the + * intermediate states alternate twice between the old and new bound + */ + invariant(array_abs_bound(r, 0, j, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, bound)) + invariant(array_abs_bound(r, start + len, j + len, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j + len, MLDSA_N, bound))) + { + int32_t t; + t = mld_fqmul(r[j + len], zeta); + r[j + len] = r[j] - t; + r[j] = r[j] + t; + } +} + +/* mld_ntt_layer() + * + * Compute one layer of forward NTT + * + * Parameters: + * - r: Pointer to base of polynomial + * - layer: Indicates which layer is being applied. + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_layer(int32_t r[MLDSA_N], const unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (layer + 1) * MLDSA_Q))) +{ + unsigned start, k, len; + /* Twiddle factors for layer n are at indices 2^(n-1)..2^n-1. */ + k = 1u << (layer - 1); + len = (unsigned)MLDSA_N >> layer; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start < MLDSA_N + 2 * len) + invariant(k <= MLDSA_N) + invariant(2 * len * k == start + MLDSA_N) + invariant(array_abs_bound(r, 0, start, layer * MLDSA_Q + MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, layer * MLDSA_Q))) + { + int32_t zeta = mld_zetas[k++]; + mld_ntt_butterfly_block(r, zeta, start, len, layer * MLDSA_Q); + } +} + +MLD_STATIC_TESTABLE void mld_poly_ntt_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +) +{ + unsigned int layer; + int32_t *r; + + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + r = a->coeffs; + + for (layer = 1; layer < 9; layer++) + __loop__( + invariant(1 <= layer && layer <= 9) + invariant(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + ) + { + mld_ntt_layer(r, layer); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_NTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_ntt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_NTT */ + mld_poly_ntt_c(a); +} + +/************************************************* + * Name: mld_fqscale + * + * Description: Scales a field element by mont/256 , i.e., performs Montgomery + * multiplication by mont^2/256. + * Input is expected to have absolute value smaller than + * 256 * MLDSA_Q. + * Output has absolute value smaller than MLD_INTT_BOUND. + * + * Arguments: - int32_t a: Field element to be scaled. + **************************************************/ +static MLD_INLINE int32_t mld_fqscale(int32_t a) +__contract__( + requires(a > -256*MLDSA_Q && a < 256*MLDSA_Q) + ensures(return_value > -MLD_INTT_BOUND && return_value < MLD_INTT_BOUND) +) +{ + /* check-magic: 41978 == pow(2,64-8,MLDSA_Q) */ + const int32_t f = 41978; + /* Bounds: MLD_INTT_BOUND is MLDSA_Q, so the bounds reasoning is just + * a special case of that in mld_fqmul(). */ + return mld_montgomery_reduce((int64_t)a * f); +} + +/* Reference: Embedded into `invntt_tomont()` in the reference implementation + * @[REF] */ +static MLD_INLINE void mld_invntt_layer(int32_t r[MLDSA_N], unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> (layer - 1)) * MLDSA_Q))) +{ + unsigned start, k, len; + len = (unsigned)MLDSA_N >> layer; + k = (1u << layer) - 1; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start <= MLDSA_N && k <= 255) + invariant(2 * len * k + start == 2 * MLDSA_N - 2 * len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + unsigned j; + int32_t zeta = -mld_zetas[k--]; + + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, j, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, (MLDSA_N >> layer) * MLDSA_Q)) + invariant(array_abs_bound(r, start + len, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + int32_t t = r[j]; + r[j] = t + r[j + len]; + r[j + len] = t - r[j + len]; + r[j + len] = mld_fqmul(r[j + len], zeta); + } + } +} + +MLD_STATIC_TESTABLE void mld_poly_invntt_tomont_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +) +{ + unsigned int layer, j; + int32_t *r; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + r = a->coeffs; + for (layer = 8; layer >= 1; layer--) + __loop__( + invariant(layer <= 8) + /* Absolute bounds increase from 1Q before layer 8 */ + /* up to 256Q after layer 1 */ + invariant(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + mld_invntt_layer(r, layer); + } + + /* Coefficient bounds are now at 256Q. We now scale by mont / 256, + * i.e., compute the Montgomery multiplication by mont^2 / 256. + * mont corrects the mont^-1 factor introduced in the basemul. + * 1/256 performs that scaling of the inverse NTT. + * The reduced value is bounded by MLD_INTT_BOUND in absolute + * value.*/ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + invariant(j <= MLDSA_N) + invariant(array_abs_bound(r, 0, j, MLD_INTT_BOUND)) + invariant(array_abs_bound(r, j, MLDSA_N, MLDSA_N * MLDSA_Q)) + ) + { + r[j] = mld_fqscale(r[j]); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); +} + + +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_INTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_intt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_INTT */ + mld_poly_invntt_tomont_c(a); +} + +MLD_STATIC_TESTABLE void mld_poly_pointwise_montgomery_c(mld_poly *c, + const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_abs_bound(c->coeffs, 0, i, MLDSA_Q)) + ) + { + c->coeffs[i] = mld_montgomery_reduce((int64_t)a->coeffs[i] * b->coeffs[i]); + } + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +{ +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + ret = mld_poly_pointwise_montgomery_native(c->coeffs, a->coeffs, b->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + mld_poly_pointwise_montgomery_c(c, a, b); +} + +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, 0, i, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + invariant(array_bound(a1->coeffs, 0, i, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) + ) + { + mld_power2round(&a0->coeffs[i], &a1->coeffs[i], a->coeffs[i]); + } + + mld_assert_bound(a0->coeffs, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +#ifndef MLD_POLY_UNIFORM_NBLOCKS +#define MLD_POLY_UNIFORM_NBLOCKS \ + ((768 + MLD_STREAM128_BLOCKBYTES - 1) / MLD_STREAM128_BLOCKBYTES) +#endif +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +MLD_STATIC_TESTABLE unsigned int mld_rej_uniform_c(int32_t *a, + unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ + unsigned int ctr, pos; + uint32_t t; + mld_assert_bound(a, offset, 0, MLDSA_Q); + + ctr = offset; + pos = 0; + /* pos + 3 cannot overflow due to the assumption + buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) */ + while (ctr < target && pos + 3 <= buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_bound(a, 0, ctr, 0, MLDSA_Q))) + { + t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + a[ctr++] = (int32_t)t; + } + } + + mld_assert_bound(a, ctr, 0, MLDSA_Q); + + return ctr; +} +/************************************************* + * Name: mld_rej_uniform + * + * Description: Sample uniformly random coefficients in [0, MLDSA_Q-1] by + * performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes (must be + * multiple of 3) + * + * Returns number of sampled coefficients. Can be smaller than len if not enough + * random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +static unsigned int mld_rej_uniform(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) + int ret; + mld_assert_bound(a, offset, 0, MLDSA_Q); + if (offset == 0) + { + ret = mld_rej_uniform_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_bound(a, res, 0, MLDSA_Q); + return res; + } + } +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + + return mld_rej_uniform_c(a, target, offset, buf, buflen); +} + +/* Reference: poly_uniform() in the reference implementation @[REF]. + * - Simplified from reference by removing buffer tail handling + * since buflen % 3 = 0 always holds true (MLD_STREAM128_BLOCKBYTES + * = 168). + * - Modified rej_uniform interface to track offset directly. + * - Pass nonce packed in the extended seed array instead of a third + * argument. + * */ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +{ + unsigned int ctr; + unsigned int buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + MLD_ALIGN uint8_t buf[MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES]; + mld_xof128_ctx state; + + mld_xof128_init(&state); + mld_xof128_absorb_once(&state, seed, MLDSA_SEEDBYTES + 2); + mld_xof128_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, 0, buf, buflen); + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(a, sizeof(mld_poly)), object_whole(buf)) + invariant(ctr <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, ctr, 0, MLDSA_Q)) + invariant(state.pos <= SHAKE128_RATE) + ) + { + mld_xof128_squeezeblocks(buf, 1, &state); + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, ctr, buf, buflen); + } + mld_xof128_release(&state); + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof128_x4_ctx state; + unsigned buflen; + + mld_xof128_x4_init(&state); + mld_xof128_x4_absorb(&state, seed, MLDSA_SEEDBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_NBLOCKS. + * This should generate the matrix entries with high probability. + */ + + mld_xof128_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all matrix entries have been generated, squeeze + * one more block a time until we're done. + */ + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, object_whole(buf), + memory_slice(vec0, sizeof(mld_poly)), memory_slice(vec1, sizeof(mld_poly)), + memory_slice(vec2, sizeof(mld_poly)), memory_slice(vec3, sizeof(mld_poly))) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_bound(vec0->coeffs, 0, ctr[0], 0, MLDSA_Q)) + invariant(array_bound(vec1->coeffs, 0, ctr[1], 0, MLDSA_Q)) + invariant(array_bound(vec2->coeffs, 0, ctr[2], 0, MLDSA_Q)) + invariant(array_bound(vec3->coeffs, 0, ctr[3], 0, MLDSA_Q))) + { + mld_xof128_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + mld_xof128_x4_release(&state); + + mld_assert_bound(vec0->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec1->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec2->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec3->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0) & 0xFF); + r[5 * i + 1] = + (uint8_t)(((a->coeffs[4 * i + 0] >> 8) | (a->coeffs[4 * i + 1] << 2)) & + 0xFF); + r[5 * i + 2] = + (uint8_t)(((a->coeffs[4 * i + 1] >> 6) | (a->coeffs[4 * i + 2] << 4)) & + 0xFF); + r[5 * i + 3] = + (uint8_t)(((a->coeffs[4 * i + 2] >> 4) | (a->coeffs[4 * i + 3] << 6)) & + 0xFF); + r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, 0, 1 << 10))) + { + r->coeffs[4 * i + 0] = + ((a[5 * i + 0] >> 0) | ((int32_t)a[5 * i + 1] << 8)) & 0x3FF; + r->coeffs[4 * i + 1] = + ((a[5 * i + 1] >> 2) | ((int32_t)a[5 * i + 2] << 6)) & 0x3FF; + r->coeffs[4 * i + 2] = + ((a[5 * i + 2] >> 4) | ((int32_t)a[5 * i + 3] << 4)) & 0x3FF; + r->coeffs[4 * i + 3] = + ((a[5 * i + 3] >> 6) | ((int32_t)a[5 * i + 4] << 2)) & 0x3FF; + } + + mld_assert_bound(r->coeffs, MLDSA_N, 0, 1 << 10); +} + +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[8]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* Safety: a->coeffs[i] <= (1 << (MLDSA_D - 1) as they are output of + * power2round, hence, these casts are safe. */ + t[0] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 0]); + t[1] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 1]); + t[2] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 2]); + t[3] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 3]); + t[4] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 4]); + t[5] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 5]); + t[6] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 6]); + t[7] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 7]); + + r[13 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[13 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[13 * i + 1] |= (uint8_t)((t[1] << 5) & 0xFF); + r[13 * i + 2] = (uint8_t)((t[1] >> 3) & 0xFF); + r[13 * i + 3] = (uint8_t)((t[1] >> 11) & 0xFF); + r[13 * i + 3] |= (uint8_t)((t[2] << 2) & 0xFF); + r[13 * i + 4] = (uint8_t)((t[2] >> 6) & 0xFF); + r[13 * i + 4] |= (uint8_t)((t[3] << 7) & 0xFF); + r[13 * i + 5] = (uint8_t)((t[3] >> 1) & 0xFF); + r[13 * i + 6] = (uint8_t)((t[3] >> 9) & 0xFF); + r[13 * i + 6] |= (uint8_t)((t[4] << 4) & 0xFF); + r[13 * i + 7] = (uint8_t)((t[4] >> 4) & 0xFF); + r[13 * i + 8] = (uint8_t)((t[4] >> 12) & 0xFF); + r[13 * i + 8] |= (uint8_t)((t[5] << 1) & 0xFF); + r[13 * i + 9] = (uint8_t)((t[5] >> 7) & 0xFF); + r[13 * i + 9] |= (uint8_t)((t[6] << 6) & 0xFF); + r[13 * i + 10] = (uint8_t)((t[6] >> 2) & 0xFF); + r[13 * i + 11] = (uint8_t)((t[6] >> 10) & 0xFF); + r[13 * i + 11] |= (uint8_t)((t[7] << 3) & 0xFF); + r[13 * i + 12] = (uint8_t)((t[7] >> 5) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + { + r->coeffs[8 * i + 0] = a[13 * i + 0]; + r->coeffs[8 * i + 0] |= (int32_t)a[13 * i + 1] << 8; + r->coeffs[8 * i + 0] &= 0x1FFF; + + r->coeffs[8 * i + 1] = a[13 * i + 1] >> 5; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 2] << 3; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 3] << 11; + r->coeffs[8 * i + 1] &= 0x1FFF; + + r->coeffs[8 * i + 2] = a[13 * i + 3] >> 2; + r->coeffs[8 * i + 2] |= (int32_t)a[13 * i + 4] << 6; + r->coeffs[8 * i + 2] &= 0x1FFF; + + r->coeffs[8 * i + 3] = a[13 * i + 4] >> 7; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 5] << 1; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 6] << 9; + r->coeffs[8 * i + 3] &= 0x1FFF; + + r->coeffs[8 * i + 4] = a[13 * i + 6] >> 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 7] << 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 8] << 12; + r->coeffs[8 * i + 4] &= 0x1FFF; + + r->coeffs[8 * i + 5] = a[13 * i + 8] >> 1; + r->coeffs[8 * i + 5] |= (int32_t)a[13 * i + 9] << 7; + r->coeffs[8 * i + 5] &= 0x1FFF; + + r->coeffs[8 * i + 6] = a[13 * i + 9] >> 6; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 10] << 2; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 11] << 10; + r->coeffs[8 * i + 6] &= 0x1FFF; + + r->coeffs[8 * i + 7] = a[13 * i + 11] >> 3; + r->coeffs[8 * i + 7] |= (int32_t)a[13 * i + 12] << 5; + r->coeffs[8 * i + 7] &= 0x1FFF; + + r->coeffs[8 * i + 0] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 7]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +MLD_STATIC_TESTABLE uint32_t mld_poly_chknorm_c(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == array_abs_bound(a->coeffs, 0, i, B)) + ) + { + /* + * Since we know that -MLD_REDUCE32_RANGE_MAX <= a < MLD_REDUCE32_RANGE_MAX, + * and B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX, to check if + * -B < (a mod± MLDSA_Q) < B, it suffices to check if -B < a < B. + * + * We prove this to be true using the following CBMC assertions. + * a ==> b expressed as !a || b to also allow run-time assertion. + */ + mld_assert(a->coeffs[i] < B || a->coeffs[i] - MLDSA_Q <= -B); + mld_assert(a->coeffs[i] > -B || a->coeffs[i] + MLDSA_Q >= B); + + /* Reference: Leaks which coefficient violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + + /* if (abs(a[i]) >= B) */ + t |= mld_ct_cmask_neg_i32(B - 1 - mld_ct_abs_i32(a->coeffs[i])); + } + + return t; +} + +/* Reference: explicitly checks the bound B to be <= (MLDSA_Q - 1) / 8). + * This is unnecessary as it's always a compile-time constant. + * We instead model it as a precondition. + * Checking the bound is performed using a conditional arguing + * that it is okay to leak which coefficient violates the bound (while the + * coefficient itself must remain secret). + * We instead perform everything in constant-time. + * Also it is sufficient to check that it is smaller than + * MLDSA_Q - MLD_REDUCE32_RANGE_MAX > (MLDSA_Q - 1) / 8). + */ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +{ +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) + int ret; + int success; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + /* The native backend returns 0 if all coefficients are within the bound, + * 1 if at least one coefficient exceeds the bound, and + * -1 (MLD_NATIVE_FUNC_FALLBACK) if the platform does not have the + * required capabilities to run the native function. + */ + ret = mld_poly_chknorm_native(a->coeffs, B); + + success = (ret != MLD_NATIVE_FUNC_FALLBACK); + /* Constant-time: It would be fine to leak the return value of chknorm + * entirely (as it is fine to leak if any coefficient exceeded the bound or + * not). However, it is cleaner to perform declassification in sign.c. + * Hence, here we only declassify if the native function returned + * MLD_NATIVE_FUNC_FALLBACK or not (which solely depends on system + * capabilities). + */ + MLD_CT_TESTING_DECLASSIFY(&success, sizeof(int)); + if (success) + { + /* Convert 0 / 1 to 0 / 0xFFFFFFFF here */ + return 0U - (uint32_t)ret; + } +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + return mld_poly_chknorm_c(a, B); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ +MLD_EMPTY_CU(mld_poly) +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_POLY_UNIFORM_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/poly.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/poly.h new file mode 100644 index 0000000000..ff7710438e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/poly.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_H +#define MLD_POLY_H + +#include +#include "cbmc.h" +#include "common.h" +#include "reduce.h" +#include "rounding.h" + +/* Absolute exclusive upper bound for the output of the forward NTT */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) +/* Absolute exclusive upper bound for the output of the inverse NTT*/ +#define MLD_INTT_BOUND MLDSA_Q + +typedef struct +{ + int32_t coeffs[MLDSA_N]; +} MLD_ALIGN mld_poly; + +#define mld_poly_reduce MLD_NAMESPACE(poly_reduce) +/************************************************* + * Name: mld_poly_reduce + * + * Description: Inplace reduction of all coefficients of polynomial to + * representative in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) +); + +#define mld_poly_caddq MLD_NAMESPACE(poly_caddq) +/************************************************* + * Name: mld_poly_caddq + * + * Description: For all coefficients of in/out polynomial add MLDSA_Q if + * coefficient is negative. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_add MLD_NAMESPACE(poly_add) +/************************************************* + * Name: mld_poly_add + * + * Description: Add polynomials. No modular reduction is performed. + * + * Arguments: - r: Pointer to input-output polynomial to be added to. + * - b: Pointer to input polynomial that should be added + * to r. Must be disjoint from r. + **************************************************/ + +/* + * NOTE: The reference implementation uses a 3-argument poly_add. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(forall(k0, 0, MLDSA_N, (int64_t) r->coeffs[k0] + b->coeffs[k0] < MLD_REDUCE32_DOMAIN_MAX)) + requires(forall(k1, 0, MLDSA_N, (int64_t) r->coeffs[k1] + b->coeffs[k1] >= INT32_MIN)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(forall(k2, 0, MLDSA_N, r->coeffs[k2] == old(*r).coeffs[k2] + b->coeffs[k2])) + ensures(forall(k3, 0, MLDSA_N, r->coeffs[k3] < MLD_REDUCE32_DOMAIN_MAX)) + ensures(forall(k4, 0, MLDSA_N, r->coeffs[k4] >= INT32_MIN)) +); + +#define mld_poly_sub MLD_NAMESPACE(poly_sub) +/************************************************* + * Name: mld_poly_sub + * + * Description: Subtract polynomials. No modular reduction is + * performed. + * + * Arguments: - mld_poly *r: Pointer to input-output polynomial. + * - const mld_poly *b: Pointer to input polynomial that should be + * subtracted from r. Must be disjoint from r. + **************************************************/ +/* + * NOTE: The reference implementation uses a 3-argument poly_sub. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_Q)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) +); + +#define mld_poly_shiftl MLD_NAMESPACE(poly_shiftl) +/************************************************* + * Name: mld_poly_shiftl + * + * Description: Multiply polynomial by 2^MLDSA_D without modular reduction. + *Assumes input coefficients to be less than 2^{31-MLDSA_D} in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_ntt MLD_NAMESPACE(poly_ntt) +/************************************************* + * Name: mld_poly_ntt + * + * Description: Inplace forward NTT. Coefficients can grow by + * 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +); + + +#define mld_poly_invntt_tomont MLD_NAMESPACE(poly_invntt_tomont) +/************************************************* + * Name: mld_poly_invntt_tomont + * + * Description: Inplace inverse NTT and multiplication by 2^{32}. + * Input coefficients need to be less than MLDSA_Q in absolute + * value and output coefficients are bounded by + * MLD_INTT_BOUND. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +); + +#define mld_poly_pointwise_montgomery MLD_NAMESPACE(poly_pointwise_montgomery) +/************************************************* + * Name: mld_poly_pointwise_montgomery + * + * Description: Pointwise multiplication of polynomials in NTT domain + * representation and multiplication of resulting polynomial + * by 2^{-32}. + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const mld_poly *a: pointer to first input polynomial + * - const mld_poly *b: pointer to second input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + +#define mld_poly_power2round MLD_NAMESPACE(poly_power2round) +/************************************************* + * Name: mld_poly_power2round + * + * Description: For all coefficients c of the input polynomial, + * compute c0, c1 such that c mod MLDSA_Q = c1*2^MLDSA_D + c0 + * with -2^{MLDSA_D-1} < c0 <= 2^{MLDSA_D-1}. Assumes coefficients + *to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + *c1 + * - mld_poly *a0: pointer to output polynomial with coefficients + *c0 + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +__contract__( + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a0->coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) +); + +#define mld_poly_uniform MLD_NAMESPACE(poly_uniform) +/************************************************* + * Name: mld_poly_uniform + * + * Description: Sample polynomial with uniformly random coefficients + * in [0,MLDSA_Q-1] by performing rejection sampling on the + * output stream of SHAKE128(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_SEEDBYTES and the packed 2-byte nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES + 2)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +#define mld_poly_uniform_4x MLD_NAMESPACE(poly_uniform_4x) +/************************************************* + * Name: mld_poly_uniform_x4 + * + * Description: Generate four polynomials using rejection sampling + * on (pseudo-)uniformly random bytes sampled from a seed. + * + * Arguments: - mld_poly *vec0, *vec1, *vec2, *vec3: + * Pointers to 4 polynomials to be sampled. + * - uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]: + * Pointer consecutive array of seed buffers of size + * MLDSA_SEEDBYTES + 2 each, plus padding for alignment. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +__contract__( + requires(memory_no_alias(vec0, sizeof(mld_poly))) + requires(memory_no_alias(vec1, sizeof(mld_poly))) + requires(memory_no_alias(vec2, sizeof(mld_poly))) + requires(memory_no_alias(vec3, sizeof(mld_poly))) + requires(memory_no_alias(seed, 4 * MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2))) + assigns(memory_slice(vec0, sizeof(mld_poly))) + assigns(memory_slice(vec1, sizeof(mld_poly))) + assigns(memory_slice(vec2, sizeof(mld_poly))) + assigns(memory_slice(vec3, sizeof(mld_poly))) + ensures(array_bound(vec0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec1->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec2->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec3->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +#define mld_polyt1_pack MLD_NAMESPACE(polyt1_pack) +/************************************************* + * Name: mld_polyt1_pack + * + * Description: Bit-pack polynomial t1 with coefficients fitting in 10 bits. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(r, MLDSA_POLYT1_PACKEDBYTES)) +); + +#define mld_polyt1_unpack MLD_NAMESPACE(polyt1_unpack) +/************************************************* + * Name: mld_polyt1_unpack + * + * Description: Unpack polynomial t1 with 10-bit coefficients. + * Output coefficients are standard representatives. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT1_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, 0, 1 << 10)) +); + +#define mld_polyt0_pack MLD_NAMESPACE(polyt0_pack) +/************************************************* + * Name: mld_polyt0_pack + * + * Description: Bit-pack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + * 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) + assigns(memory_slice(r, MLDSA_POLYT0_PACKEDBYTES)) +); + + +#define mld_polyt0_unpack MLD_NAMESPACE(polyt0_unpack) +/************************************************* + * Name: mld_polyt0_unpack + * + * Description: Unpack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + *2^{MLDSA_D-1}]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT0_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) +); + +#define mld_poly_chknorm MLD_NAMESPACE(poly_chknorm) +/************************************************* + * Name: mld_poly_chknorm + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const mld_poly *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if norm is strictly smaller than + * B <= (MLDSA_Q - MLD_REDUCE32_RANGE_MAX) and 0xFFFFFFFF otherwise. + * + * Specification: The definition of this FIPS-204 requires signed canonical + * reduction prior to applying the bounds check. + * However, `-B < (a mod± MLDSA_Q) < B` is equivalent to + * `-B < a < B` under the assumption that + * `B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX` (cf. the assertion in + * the code). Hence, the present spec and implementation are + * correct without reduction. + * + **************************************************/ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +); + +#endif /* !MLD_POLY_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/poly_kl.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/poly_kl.c new file mode 100644 index 0000000000..7a319ca515 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/poly_kl.c @@ -0,0 +1,931 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "ct.h" +#include "debug.h" +#include "poly_kl.h" +#include "rounding.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_rej_eta MLD_ADD_PARAM_SET(mld_rej_eta) +#define mld_rej_eta_c MLD_ADD_PARAM_SET(mld_rej_eta_c) +#define mld_poly_decompose_c MLD_ADD_PARAM_SET(mld_poly_decompose_c) +#define mld_poly_use_hint_c MLD_ADD_PARAM_SET(mld_poly_use_hint_c) +#define mld_polyz_unpack_c MLD_ADD_PARAM_SET(mld_polyz_unpack_c) +/* End of parameter set namespacing */ + + +MLD_STATIC_TESTABLE +void mld_poly_decompose_c(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +) +{ + unsigned int i; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, i, MLDSA_N, 0, MLDSA_Q)) + invariant(array_bound(a1->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + invariant(array_abs_bound(a0->coeffs, 0, i, MLDSA_GAMMA2+1)) + ) + { + mld_decompose(&a0->coeffs[i], &a1->coeffs[i], a0->coeffs[i]); + } + + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +{ +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_88_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_32_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_DECOMPOSE_88 && MLD_CONFIG_PARAMETER_SET == \ + 44) && MLD_USE_NATIVE_POLY_DECOMPOSE_32 && (MLD_CONFIG_PARAMETER_SET \ + == 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_decompose_c(a1, a0); +} + +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(s <= i) + invariant(array_bound(h->coeffs, 0, i, 0, 2)) + ) + { + const unsigned int hint_bit = mld_make_hint(a0->coeffs[i], a1->coeffs[i]); + h->coeffs[i] = (int32_t)hint_bit; + s += hint_bit; + } + + mld_assert(s <= MLDSA_N); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + return s; +} + +MLD_STATIC_TESTABLE void mld_poly_use_hint_c(mld_poly *b, const mld_poly *a, + const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(b->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ) + { + b->coeffs[i] = mld_use_hint(a->coeffs[i], h->coeffs[i]); + } + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +{ +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_88_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_USE_HINT_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_32_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_USE_HINT_88 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLY_USE_HINT_32 && (MLD_CONFIG_PARAMETER_SET == \ + 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_use_hint_c(b, a, h); +} + +/************************************************* + * Name: mld_rej_eta + * + * Description: Sample uniformly random coefficients in [-MLDSA_ETA, MLDSA_ETA] + *by performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes + * + * Returns number of sampled coefficients. Can be smaller than target if not + *enough random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_eta()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +#if MLDSA_ETA == 2 +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 1 +#elif MLDSA_ETA == 4 +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 2 +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + +MLD_STATIC_TESTABLE unsigned int mld_rej_eta_c(int32_t *a, unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ + unsigned int ctr, pos; + int t_valid; + uint32_t t0, t1; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + ctr = offset; + pos = 0; + while (ctr < target && pos < buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_abs_bound(a, 0, ctr, MLDSA_ETA + 1)) + ) + { + t0 = buf[pos] & 0x0F; + t1 = buf[pos++] >> 4; + + /* Constant time: The inputs and outputs to the rejection sampling are + * secret. However, it is fine to leak which coefficients have been + * rejected. For constant-time testing, we declassify the result of + * the comparison. + */ +#if MLDSA_ETA == 2 + t_valid = t0 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 15 */ + { + t0 = t0 - (205 * t0 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t0; + } + t_valid = t1 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) /* t1 < 15 */ + { + t1 = t1 - (205 * t1 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t1; + } +#elif MLDSA_ETA == 4 + t_valid = t0 < 9; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 9 */ + { + a[ctr++] = 4 - (int32_t)t0; + } + t_valid = t1 < 9; /* t1 < 9 */ + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) + { + a[ctr++] = 4 - (int32_t)t1; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + } + + mld_assert_abs_bound(a, ctr, MLDSA_ETA + 1); + + return ctr; +} + +static unsigned int mld_rej_eta(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ +#if MLDSA_ETA == 2 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta2_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#elif MLDSA_ETA == 4 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta4_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#endif /* !(MLDSA_ETA == 2 && MLD_USE_NATIVE_REJ_UNIFORM_ETA2) && MLDSA_ETA == \ + 4 && MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + + return mld_rej_eta_c(a, target, offset, buf, buflen); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_ETA_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof256_x4_ctx state; + unsigned buflen; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = nonce0; + extseed[1][MLDSA_CRHBYTES] = nonce1; + extseed[2][MLDSA_CRHBYTES] = nonce2; + extseed[3][MLDSA_CRHBYTES] = nonce3; + extseed[0][MLDSA_CRHBYTES + 1] = 0; + extseed[1][MLDSA_CRHBYTES + 1] = 0; + extseed[2][MLDSA_CRHBYTES + 1] = 0; + extseed[3][MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(r0, sizeof(mld_poly)), + memory_slice(r1, sizeof(mld_poly)), memory_slice(r2, sizeof(mld_poly)), + memory_slice(r3, sizeof(mld_poly)), object_whole(buf[0]), + object_whole(buf[1]), object_whole(buf[2]), + object_whole(buf[3])) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_abs_bound(r0->coeffs, 0, ctr[0], MLDSA_ETA + 1)) + invariant(array_abs_bound(r1->coeffs, 0, ctr[1], MLDSA_ETA + 1)) + invariant(array_abs_bound(r2->coeffs, 0, ctr[2], MLDSA_ETA + 1)) + invariant(array_abs_bound(r3->coeffs, 0, ctr[3], MLDSA_ETA + 1))) + { + mld_xof256_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + + mld_xof256_x4_release(&state); + + mld_assert_abs_bound(r0->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r1->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r2->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r3->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +{ + /* Temporary buffer for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr; + mld_xof256_ctx state; + unsigned buflen; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = nonce; + extseed[MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr = mld_rej_eta(r->coeffs, MLDSA_N, 0, buf, buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, object_whole(&state), + object_whole(buf), memory_slice(r, sizeof(mld_poly))) + invariant(ctr <= MLDSA_N) + invariant(state.pos <= SHAKE256_RATE) + invariant(array_abs_bound(r->coeffs, 0, ctr, MLDSA_ETA + 1))) + { + mld_xof256_squeezeblocks(buf, 1, &state); + ctr = mld_rej_eta(r->coeffs, MLDSA_N, ctr, buf, buflen); + } + + mld_xof256_release(&state); + + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define MLD_POLY_UNIFORM_GAMMA1_NBLOCKS \ + ((MLDSA_POLYZ_PACKEDBYTES + MLD_STREAM256_BLOCKBYTES - 1) / \ + MLD_STREAM256_BLOCKBYTES) + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + mld_xof256_ctx state; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = (uint8_t)(nonce & 0xFF); + extseed[MLDSA_CRHBYTES + 1] = (uint8_t)(nonce >> 8); + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + mld_polyz_unpack(a, buf); + + mld_xof256_release(&state); + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + mld_xof256_x4_ctx state; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = (uint8_t)(nonce0 & 0xFF); + extseed[1][MLDSA_CRHBYTES] = (uint8_t)(nonce1 & 0xFF); + extseed[2][MLDSA_CRHBYTES] = (uint8_t)(nonce2 & 0xFF); + extseed[3][MLDSA_CRHBYTES] = (uint8_t)(nonce3 & 0xFF); + extseed[0][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce0 >> 8); + extseed[1][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce1 >> 8); + extseed[2][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce2 >> 8); + extseed[3][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce3 >> 8); + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + + mld_polyz_unpack(r0, buf[0]); + mld_polyz_unpack(r1, buf[1]); + mld_polyz_unpack(r2, buf[2]); + mld_polyz_unpack(r3, buf[3]); + mld_xof256_x4_release(&state); + + mld_assert_bound(r0->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r1->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r2->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r3->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +{ + unsigned int i, j, pos; + uint64_t signs; + uint64_t offset; + MLD_ALIGN uint8_t buf[SHAKE256_RATE]; + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, seed, MLDSA_CTILDEBYTES); + mld_shake256_finalize(&state); + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + + /* Convert the first 8 bytes of buf[] into an unsigned 64-bit value. */ + /* Each bit of that dictates the sign of the resulting challenge value */ + signs = 0; + for (i = 0; i < 8; ++i) + __loop__( + assigns(i, signs) + invariant(i <= 8) + ) + { + signs |= (uint64_t)buf[i] << 8 * i; + } + pos = 8; + + mld_memset(c, 0, sizeof(mld_poly)); + + for (i = MLDSA_N - MLDSA_TAU; i < MLDSA_N; ++i) + __loop__( + assigns(i, j, object_whole(buf), state, pos, memory_slice(c, sizeof(mld_poly)), signs) + invariant(i >= MLDSA_N - MLDSA_TAU) + invariant(i <= MLDSA_N) + invariant(pos >= 1) + invariant(pos <= SHAKE256_RATE) + invariant(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) + invariant(state.pos <= SHAKE256_RATE) + ) + { + do + __loop__( + assigns(j, object_whole(buf), state, pos) + invariant(state.pos <= SHAKE256_RATE) + ) + { + if (pos >= SHAKE256_RATE) + { + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + pos = 0; + } + j = buf[pos++]; + } while (j > i); + + c->coeffs[i] = c->coeffs[j]; + + /* Reference: Compute coefficent value here in two steps to */ + /* mixinf unsigned and signed arithmetic with implicit */ + /* conversions, and so that CBMC can keep track of ranges */ + /* to complete type-safety proof here. */ + + /* The least-significant bit of signs tells us if we want -1 or +1 */ + offset = 2 * (signs & 1); + + /* offset has value 0 or 2 here, so (1 - (int32_t) offset) has + * value -1 or +1 */ + c->coeffs[j] = 1 - (int32_t)offset; + + /* Move to the next bit of signs for next time */ + signs >>= 1; + } + + mld_assert_bound(c->coeffs, MLDSA_N, -1, 2); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(&signs, sizeof(signs)); +} + +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint8_t t[8]; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_ETA + 1); + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 1]); + t[2] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 2]); + t[3] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 3]); + t[4] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 4]); + t[5] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 5]); + t[6] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 6]); + t[7] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 7]); + + r[3 * i + 0] = (uint8_t)(((t[0] >> 0) | (t[1] << 3) | (t[2] << 6)) & 0xFF); + r[3 * i + 1] = + (uint8_t)(((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)) & + 0xFF); + r[3 * i + 2] = (uint8_t)(((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)) & 0xFF); + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 1]); + r[i] = (uint8_t)(t[0] | (t[1] << 4)); + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ +} + +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -5, MLDSA_ETA + 1))) + { + r->coeffs[8 * i + 0] = (a[3 * i + 0] >> 0) & 7; + r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 7; + r->coeffs[8 * i + 2] = ((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 7; + r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 7; + r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 7; + r->coeffs[8 * i + 5] = ((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 7; + r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 7; + r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5) & 7; + + r->coeffs[8 * i + 0] = MLDSA_ETA - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = MLDSA_ETA - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = MLDSA_ETA - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = MLDSA_ETA - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = MLDSA_ETA - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = MLDSA_ETA - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = MLDSA_ETA - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = MLDSA_ETA - r->coeffs[8 * i + 7]; + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -11, MLDSA_ETA + 1))) + { + r->coeffs[2 * i + 0] = a[i] & 0x0F; + r->coeffs[2 * i + 1] = a[i] >> 4; + r->coeffs[2 * i + 0] = MLDSA_ETA - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_ETA - r->coeffs[2 * i + 1]; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + + mld_assert_bound(r->coeffs, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + + +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[4]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 1]); + t[2] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 2]); + t[3] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 3]); + + r[9 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[9 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[9 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[9 * i + 2] |= (uint8_t)((t[1] << 2) & 0xFF); + r[9 * i + 3] = (uint8_t)((t[1] >> 6) & 0xFF); + r[9 * i + 4] = (uint8_t)((t[1] >> 14) & 0xFF); + r[9 * i + 4] |= (uint8_t)((t[2] << 4) & 0xFF); + r[9 * i + 5] = (uint8_t)((t[2] >> 4) & 0xFF); + r[9 * i + 6] = (uint8_t)((t[2] >> 12) & 0xFF); + r[9 * i + 6] |= (uint8_t)((t[3] << 6) & 0xFF); + r[9 * i + 7] = (uint8_t)((t[3] >> 2) & 0xFF); + r[9 * i + 8] = (uint8_t)((t[3] >> 10) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 1]); + + r[5 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[5 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[5 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[5 * i + 2] |= (uint8_t)((t[1] << 4) & 0xFF); + r[5 * i + 3] = (uint8_t)((t[1] >> 4) & 0xFF); + r[5 * i + 4] = (uint8_t)((t[1] >> 12) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +MLD_STATIC_TESTABLE void mld_polyz_unpack_c( + mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +) +{ + unsigned int i; +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[4 * i + 0] = a[9 * i + 0]; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 2] << 16; + r->coeffs[4 * i + 0] &= 0x3FFFF; + + r->coeffs[4 * i + 1] = a[9 * i + 2] >> 2; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 3] << 6; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 4] << 14; + r->coeffs[4 * i + 1] &= 0x3FFFF; + + r->coeffs[4 * i + 2] = a[9 * i + 4] >> 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 5] << 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 6] << 12; + r->coeffs[4 * i + 2] &= 0x3FFFF; + + r->coeffs[4 * i + 3] = a[9 * i + 6] >> 6; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 7] << 2; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10; + r->coeffs[4 * i + 3] &= 0x3FFFF; + + r->coeffs[4 * i + 0] = MLDSA_GAMMA1 - r->coeffs[4 * i + 0]; + r->coeffs[4 * i + 1] = MLDSA_GAMMA1 - r->coeffs[4 * i + 1]; + r->coeffs[4 * i + 2] = MLDSA_GAMMA1 - r->coeffs[4 * i + 2]; + r->coeffs[4 * i + 3] = MLDSA_GAMMA1 - r->coeffs[4 * i + 3]; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[2 * i + 0] = a[5 * i + 0]; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 2] << 16; + r->coeffs[2 * i + 0] &= 0xFFFFF; + + r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 3] << 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12; + /* r->coeffs[2*i+1] &= 0xFFFFF; */ /* No effect, since we're anyway at 20 + bits */ + + r->coeffs[2 * i + 0] = MLDSA_GAMMA1 - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_GAMMA1 - r->coeffs[2 * i + 1]; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +{ +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + ret = mld_polyz_unpack_17_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#elif defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + ret = mld_polyz_unpack_19_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYZ_UNPACK_17 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLYZ_UNPACK_19 && (MLD_CONFIG_PARAMETER_SET == 65 \ + || MLD_CONFIG_PARAMETER_SET == 87) */ + + mld_polyz_unpack_c(r, a); +} + +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + + mld_assert_bound(a->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[3 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0]) & 0xFF); + r[3 * i + 0] |= (uint8_t)((a->coeffs[4 * i + 1] << 6) & 0xFF); + r[3 * i + 1] = (uint8_t)((a->coeffs[4 * i + 1] >> 2) & 0xFF); + r[3 * i + 1] |= (uint8_t)((a->coeffs[4 * i + 2] << 4) & 0xFF); + r[3 * i + 2] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) & 0xFF); + r[3 * i + 2] |= (uint8_t)((a->coeffs[4 * i + 3] << 2) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + r[i] = + (uint8_t)((a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_rej_eta +#undef mld_rej_eta_c +#undef mld_poly_decompose_c +#undef mld_poly_use_hint_c +#undef mld_polyz_unpack_c +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_GAMMA1_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/poly_kl.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/poly_kl.h new file mode 100644 index 0000000000..c6aa498358 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/poly_kl.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_KL_H +#define MLD_POLY_KL_H + +#include "cbmc.h" +#include "common.h" +#include "poly.h" + +#define mld_poly_decompose MLD_NAMESPACE_KL(poly_decompose) +/************************************************* + * Name: mld_poly_decompose + * + * Description: For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such c mod MLDSA_Q = c1*ALPHA + + * c0 with -ALPHA/2 < c0 <= ALPHA/2 except + * c1 = (MLDSA_Q-1)/ALPHA where we set + * c1 = 0 and -ALPHA/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + * c1 + * - mld_poly *a0: pointer to input/output polynomial. Output + * polynomial has coefficients c0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +); + + +#define mld_poly_make_hint MLD_NAMESPACE_KL(poly_make_hint) +/************************************************* + * Name: mld_poly_make_hint + * + * Description: Compute hint polynomial. The coefficients of which indicate + * whether the low bits of the corresponding coefficient of + * the input polynomial overflow into the high bits. + * + * Arguments: - mld_poly *h: pointer to output hint polynomial + * - const mld_poly *a0: pointer to low part of input polynomial + * - const mld_poly *a1: pointer to high part of input polynomial + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + assigns(memory_slice(h, sizeof(mld_poly))) + ensures(return_value <= MLDSA_N) + ensures(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) +); + +#define mld_poly_use_hint MLD_NAMESPACE_KL(poly_use_hint) +/************************************************* + * Name: mld_poly_use_hint + * + * Description: Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - mld_poly *b: pointer to output polynomial with corrected high + *bits + * - const mld_poly *a: pointer to input polynomial + * - const mld_poly *h: pointer to input hint polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta_4x MLD_NAMESPACE_KL(poly_uniform_eta_4x) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample four polynomials with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce_i) + * + * Arguments: - mld_poly *r0: pointer to first output polynomial + * - mld_poly *r1: pointer to second output polynomial + * - mld_poly *r2: pointer to third output polynomial + * - mld_poly *r3: pointer to fourth output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce0: first nonce + * - uint8_t nonce1: second nonce + * - uint8_t nonce2: third nonce + * - uint8_t nonce3: fourth nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_abs_bound(r0->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r1->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r2->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r3->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta MLD_NAMESPACE_KL(poly_uniform_eta) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample polynomial with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce: nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1 MLD_NAMESPACE_KL(poly_uniform_gamma1) +/************************************************* + * Name: mld_poly_uniform_gamma1 + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1_4x MLD_NAMESPACE_KL(poly_uniform_gamma1_4x) +/************************************************* + * Name: mld_poly_uniform_gamma1_4x + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_bound(r0->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r1->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r2->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r3->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define mld_poly_challenge MLD_NAMESPACE_KL(poly_challenge) +/************************************************* + * Name: mld_poly_challenge + * + * Description: Implementation of H. Samples polynomial with MLDSA_TAU nonzero + * coefficients in {-1,1} using the output stream of + * SHAKE256(seed). + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const uint8_t mu[]: byte array containing seed of length + * MLDSA_CTILDEBYTES + **************************************************/ +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +__contract__( + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CTILDEBYTES)) + assigns(memory_slice(c, sizeof(mld_poly))) + /* All coefficients of c are -1, 0 or +1 */ + ensures(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) +); + +#define mld_polyeta_pack MLD_NAMESPACE_KL(polyeta_pack) +/************************************************* + * Name: mld_polyeta_pack + * + * Description: Bit-pack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYETA_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + assigns(memory_slice(r, MLDSA_POLYETA_PACKEDBYTES)) +); + +/* + * polyeta_unpack produces coefficients in [-MLDSA_ETA,MLDSA_ETA] for + * well-formed inputs (i.e., those produced by polyeta_pack). + * However, when passed an arbitrary byte array, it may produce smaller values, + * i.e, values in [MLD_POLYETA_UNPACK_LOWER_BOUND,MLDSA_ETA] + * Even though this should never happen, we use use the bound for arbitrary + * inputs in the CBMC proofs. + */ +#if MLDSA_ETA == 2 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-5) +#elif MLDSA_ETA == 4 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-11) +#else +#error "Invalid value of MLDSA_ETA" +#endif + +#define mld_polyeta_unpack MLD_NAMESPACE_KL(polyeta_unpack) +/************************************************* + * Name: mld_polyeta_unpack + * + * Description: Unpack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYETA_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)) +); + +#define mld_polyz_pack MLD_NAMESPACE_KL(polyz_pack) +/************************************************* + * Name: mld_polyz_pack + * + * Description: Bit-pack polynomial with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYZ_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(r, MLDSA_POLYZ_PACKEDBYTES)) +); + + +#define mld_polyz_unpack MLD_NAMESPACE_KL(polyz_unpack) +/************************************************* + * Name: mld_polyz_unpack + * + * Description: Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); + +#define mld_polyw1_pack MLD_NAMESPACE_KL(polyw1_pack) +/************************************************* + * Name: mld_polyw1_pack + * + * Description: Bit-pack polynomial w1 with coefficients in [0,15] or [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES)) +); + +#endif /* !MLD_POLY_KL_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/polyvec.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/polyvec.c new file mode 100644 index 0000000000..5c3a08ab32 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/polyvec.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include +#include + +#include "common.h" +#include "debug.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" + +/* This namespacing is not done at the top to avoid a naming conflict + * with native backends, which are currently not yet namespaced. */ +#define mld_polymat_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polymat_permute_bitrev_to_custom) +#define mld_polyvecl_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polyvecl_permute_bitrev_to_custom) +#define mld_polyvecl_pointwise_acc_montgomery_c \ + MLD_ADD_PARAM_SET(mld_polyvecl_pointwise_acc_montgomery_c) + +#if !defined(MLD_CONFIG_REDUCE_RAM) +/* Helper function to ensure that the polynomial entries in the output + * of mld_polyvec_matrix_expand use the standard (bitreversed) ordering + * of coefficients. + * No-op unless a native backend with a custom ordering is used. + */ + +static void mld_polyvecl_permute_bitrev_to_custom(mld_polyvecl *v) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +{ +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + unsigned i; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_permute_bitrev_to_custom(v->vec[i].coeffs); + } +#else /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + /* Nothing to do */ + (void)v; +#endif /* !MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ +} + +static void mld_polymat_permute_bitrev_to_custom(mld_polymat *mat) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; i++) + __loop__( + assigns(i, memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))) + { + mld_polyvecl_permute_bitrev_to_custom(&mat->vec[i]); + } +} +#endif /* !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + unsigned int i; + MLD_ALIGN uint8_t seed_ext[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + mld_memcpy(seed_ext, mat->rho, MLDSA_SEEDBYTES); + + /* Generate row on-demand */ + for (i = 0; i < MLDSA_L; i++) + { + uint8_t x = (uint8_t)row; + uint8_t y = (uint8_t)i; + + seed_ext[MLDSA_SEEDBYTES + 0] = y; + seed_ext[MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(&mat->row_buffer.vec[i], seed_ext); + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + mld_poly_permute_bitrev_to_custom(mat->row_buffer.vec[i].coeffs); +#endif + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); + + return &mat->row_buffer; +#else /* MLD_CONFIG_REDUCE_RAM */ + return &mat->vec[row]; +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + /* In REDUCE_RAM mode, just copy the seed for later on-demand generation */ + mld_memcpy(mat->rho, rho, MLDSA_SEEDBYTES); +#else + unsigned int i, j; + /* + * We generate four separate seed arrays rather than a single one to work + * around limitations in CBMC function contracts dealing with disjoint slices + * of the same parent object. + */ + + MLD_ALIGN uint8_t seed_ext[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + mld_memcpy(seed_ext[j], rho, MLDSA_SEEDBYTES); + } + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + /* Sample 4 matrix entries a time. */ + for (i = 0; i < (MLDSA_K * MLDSA_L / 4) * 4; i += 4) + __loop__( + assigns(i, j, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= (MLDSA_K * MLDSA_L / 4) * 4 && i % 4 == 0) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + uint8_t x = (uint8_t)((i + j) / MLDSA_L); + uint8_t y = (uint8_t)((i + j) % MLDSA_L); + + seed_ext[j][MLDSA_SEEDBYTES + 0] = y; + seed_ext[j][MLDSA_SEEDBYTES + 1] = x; + } + + mld_poly_uniform_4x(&mat->vec[i / MLDSA_L].vec[i % MLDSA_L], + &mat->vec[(i + 1) / MLDSA_L].vec[(i + 1) % MLDSA_L], + &mat->vec[(i + 2) / MLDSA_L].vec[(i + 2) % MLDSA_L], + &mat->vec[(i + 3) / MLDSA_L].vec[(i + 3) % MLDSA_L], + seed_ext); + } +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + i = 0; +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + /* Entries omitted by the batch-sampling are sampled individually. */ + while (i < MLDSA_K * MLDSA_L) + __loop__( + assigns(i, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K * MLDSA_L) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + uint8_t x = (uint8_t)(i / MLDSA_L); + uint8_t y = (uint8_t)(i % MLDSA_L); + mld_poly *this_poly = &mat->vec[i / MLDSA_L].vec[i % MLDSA_L]; + + seed_ext[0][MLDSA_SEEDBYTES + 0] = y; + seed_ext[0][MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(this_poly, seed_ext[0]); + i++; + } + + mld_polymat_permute_bitrev_to_custom(mat); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(t, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + const mld_polyvecl *row = mld_polymat_get_row(mat, i); + mld_polyvecl_pointwise_acc_montgomery(&t->vec[i], row, v); + } + + mld_assert_abs_bound_2d(t->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_L **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; +#endif + + /* Safety: nonce is at most ((UINT16_MAX - MLDSA_L) / MLDSA_L), and, hence, + * this cast is safe. See MLD_NONCE_UB comment in sign.c. */ + nonce = (uint16_t)(MLDSA_L * nonce); + /* Now, nonce <= UINT16_MAX - (MLDSA_L - 1), so the casts below are safe. */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_gamma1(&v->vec[i], seed, (uint16_t)(nonce + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLDSA_L == 4 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); +#elif MLDSA_L == 5 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); + mld_poly_uniform_gamma1(&v->vec[4], seed, (uint16_t)(nonce + 4)); +#elif MLDSA_L == 7 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], + &v->vec[3 /* irrelevant */], seed, nonce, + (uint16_t)(nonce + 1), (uint16_t)(nonce + 2), + 0xFF /* irrelevant */); + mld_poly_uniform_gamma1_4x(&v->vec[3], &v->vec[4], &v->vec[5], &v->vec[6], + seed, (uint16_t)(nonce + 3), (uint16_t)(nonce + 4), + (uint16_t)(nonce + 5), (uint16_t)(nonce + 6)); +#endif /* MLDSA_L == 7 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(k0, i, MLDSA_L, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_STATIC_TESTABLE void mld_polyvecl_pointwise_acc_montgomery_c( + mld_poly *w, const mld_polyvecl *u, const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i, j; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + for (i = 0; i < MLDSA_N; i++) + __loop__( + assigns(i, j, memory_slice(w, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_abs_bound(w->coeffs, 0, i, MLDSA_Q)) + ) + { + int64_t t = 0; + int32_t r; + for (j = 0; j < MLDSA_L; j++) + __loop__( + assigns(j, t) + invariant(j <= MLDSA_L) + invariant(t >= -(int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + invariant(t <= (int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + ) + { + t += (int64_t)u->vec[j].coeffs[i] * v->vec[j].coeffs[i]; + } + + r = mld_montgomery_reduce(t); + w->coeffs[i] = r; + } + + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +{ +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) && \ + MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l4_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) && \ + MLD_CONFIG_PARAMETER_SET == 65 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l5_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) && \ + MLD_CONFIG_PARAMETER_SET == 87 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l7_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 && \ + MLD_CONFIG_PARAMETER_SET == 44) && \ + !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 && \ + MLD_CONFIG_PARAMETER_SET == 65) && \ + MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 && \ + MLD_CONFIG_PARAMETER_SET == 87 */ + /* The first input is bounded by [0, Q-1] inclusive + * The second input is bounded by [-9Q+1, 9Q-1] inclusive . Hence, we can + * safely accumulate in 64-bits without intermediate reductions as + * MLDSA_L * (MLD_NTT_BOUND-1) * (Q-1) < INT64_MAX + * + * The worst case is ML-DSA-87: 7 * (9Q-1) * (Q-1) < 2**52 + * (and likewise for negative values) + */ + mld_polyvecl_pointwise_acc_montgomery_c(w, u, v); +} + +MLD_INTERNAL_API +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + invariant(i <= MLDSA_L) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + return t; +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_K **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k2, 0, i, + array_bound(v->vec[k2].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ) + { + mld_poly_reduce(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_caddq(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, + forall(k1, 0, MLDSA_N, u->vec[k0].coeffs[k1] == loop_entry(*u).vec[k0].coeffs[k1]))) + invariant(forall(k6, 0, i, array_bound(u->vec[k6].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + ) + { + mld_poly_add(&u->vec[i], &v->vec[i]); + } + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(u->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, u->vec[k1].coeffs[n1] == loop_entry(*u).vec[k1].coeffs[n1])))) + { + mld_poly_sub(&u->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, v->vec[k1].coeffs[n1] == loop_entry(*v).vec[k1].coeffs[n1]))) + ) + { + mld_poly_shiftl(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))) + { + mld_poly_invntt_tomont(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_INTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, array_abs_bound(r->vec[k2].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + mld_poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]); + } + mld_assert_abs_bound_2d(r->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + + return t; +} + +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + invariant(forall(k2, 0, i, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) + ) + { + mld_poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +{ + unsigned int i; + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + invariant(forall(k2, 0, i, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) + invariant(forall(k3, i, MLDSA_K, + array_bound(v0->vec[k3].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + ) + { + mld_poly_decompose(&v1->vec[i], &v0->vec[i]); + } + + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + mld_assert_abs_bound_2d(v0->vec, MLDSA_K, MLDSA_N, MLDSA_GAMMA2 + 1); +} + +MLD_INTERNAL_API +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, s, memory_slice(h, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(s <= i * MLDSA_N) + invariant(forall(k1, 0, i, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + s += mld_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]); + } + + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + return s; +} + +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *u, + const mld_polyveck *h) +{ + unsigned int i; + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(w, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)))) + ) + { + mld_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]); + } + + mld_assert_bound_2d(w->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +{ + unsigned int i; + mld_assert_bound_2d(w1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyw1_pack(&r[i * MLDSA_POLYW1_PACKEDBYTES], &w1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt0_pack(&r[i * MLDSA_POLYT0_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyz_unpack(&z->vec[i], r + i * MLDSA_POLYZ_PACKEDBYTES); + } + + mld_assert_bound_2d(z->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt0_unpack(&p->vec[i], r + i * MLDSA_POLYT0_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_polymat_permute_bitrev_to_custom +#undef mld_polyvecl_permute_bitrev_to_custom +#undef mld_polyvecl_pointwise_acc_montgomery_c diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/polyvec.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/polyvec.h new file mode 100644 index 0000000000..d21abc02ff --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/polyvec.h @@ -0,0 +1,725 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLYVEC_H +#define MLD_POLYVEC_H + +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "poly_kl.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_polyvecl MLD_ADD_PARAM_SET(mld_polyvecl) +#define mld_polyveck MLD_ADD_PARAM_SET(mld_polyveck) +#define mld_polymat MLD_ADD_PARAM_SET(mld_polymat) +/* End of parameter set namespacing */ + +/* Vectors of polynomials of length MLDSA_L */ +typedef struct +{ + mld_poly vec[MLDSA_L]; +} mld_polyvecl; + + +#define mld_polyvecl_uniform_gamma1 MLD_NAMESPACE_KL(polyvecl_uniform_gamma1) +/************************************************* + * Name: mld_polyvecl_uniform_gamma1 + * + * Description: Sample vector of polynomials with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_polyvecl *v: pointer to output vector + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + *************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + requires(nonce <= (UINT16_MAX - MLDSA_L) / MLDSA_L) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyvecl_ntt MLD_NAMESPACE_KL(polyvecl_ntt) +/************************************************* + * Name: mld_polyvecl_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_L. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyvecl *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k0, 0, MLDSA_L, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyvecl_pointwise_acc_montgomery \ + MLD_NAMESPACE_KL(polyvecl_pointwise_acc_montgomery) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery + * + * Description: Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * The first input "u" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * + * Arguments: - mld_poly *w: output polynomial + * - const mld_polyvecl *u: pointer to first input vector + * - const mld_polyvecl *v: pointer to second input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + + +#define mld_polyvecl_chknorm MLD_NAMESPACE_KL(polyvecl_chknorm) +/************************************************* + * Name: mld_polyvecl_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_L. + * Assumes input mld_polyvecl to be reduced by polyvecl_reduce(). + * + * Arguments: - const mld_polyvecl *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials is strictly smaller than B <= + * (MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +/* Vectors of polynomials of length MLDSA_K */ +typedef struct +{ + mld_poly vec[MLDSA_K]; +} mld_polyveck; + +/* Matrix of polynomials (K x L) */ +typedef struct +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + mld_polyvecl row_buffer; + uint8_t rho[MLDSA_SEEDBYTES]; +#else + mld_polyvecl vec[MLDSA_K]; +#endif +} mld_polymat; + +#define mld_polyveck_reduce MLD_NAMESPACE_KL(polyveck_reduce) +/************************************************* + * Name: polyveck_reduce + * + * Description: Reduce coefficients of polynomials in vector of length MLDSA_K + * to representatives in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) +); + +#define mld_polyveck_caddq MLD_NAMESPACE_KL(polyveck_caddq) +/************************************************* + * Name: mld_polyveck_caddq + * + * Description: For all coefficients of polynomials in vector of length MLDSA_K + * add MLDSA_Q if coefficient is negative. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_add MLD_NAMESPACE_KL(polyveck_add) +/************************************************* + * Name: mld_polyveck_add + * + * Description: Add vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to input-output vector of polynomials + * to be added to + * - const mld_polyveck *v: pointer to second input vector of + * polynomials + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(p0, 0, MLDSA_K, array_abs_bound(u->vec[p0].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) + requires(forall(p1, 0, MLDSA_K, + array_bound(v->vec[p1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(q2, 0, MLDSA_K, + array_bound(u->vec[q2].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_sub MLD_NAMESPACE_KL(polyveck_sub) +/************************************************* + * Name: mld_polyveck_sub + * + * Description: Subtract vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to first input vector + * - const mld_polyveck *v: pointer to second input vector to be + * subtracted from first input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(u->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_shiftl MLD_NAMESPACE_KL(polyveck_shiftl) +/************************************************* + * Name: mld_polyveck_shiftl + * + * Description: Multiply vector of polynomials of Length MLDSA_K by 2^MLDSA_D + *without modular reduction. Assumes input coefficients to be less than + *2^{31-MLDSA_D}. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_ntt MLD_NAMESPACE_KL(polyveck_ntt) +/************************************************* + * Name: mld_polyveck_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_K. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyveck_invntt_tomont MLD_NAMESPACE_KL(polyveck_invntt_tomont) +/************************************************* + * Name: mld_polyveck_invntt_tomont + * + * Description: Inverse NTT and multiplication by 2^{32} of polynomials + * in vector of length MLDSA_K. + * Input coefficients need to be less than MLDSA_Q, and + * Output coefficients are bounded by MLD_INTT_BOUND. + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) +); + +#define mld_polyveck_pointwise_poly_montgomery \ + MLD_NAMESPACE_KL(polyveck_pointwise_poly_montgomery) +/************************************************* + * Name: mld_polyveck_pointwise_poly_montgomery + * + * Description: Pointwise multiplication of a polynomial vector of length + * MLDSA_K by a single polynomial in NTT domain and multiplication + * of the resulting polynomial vector by 2^{-32}. + * + * Arguments: - mld_polyveck *r: pointer to output vector + * - mld_poly *a: pointer to input polynomial + * - mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(r, sizeof(mld_polyveck))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(r, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(r->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#define mld_polyveck_chknorm MLD_NAMESPACE_KL(polyveck_chknorm) +/************************************************* + * Name: mld_polyveck_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_K. + * Assumes input mld_polyveck to be reduced by polyveck_reduce(). + * + * Arguments: - const mld_polyveck *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials are strictly smaller than B <= + *(MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, + -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +#define mld_polyveck_power2round MLD_NAMESPACE_KL(polyveck_power2round) +/************************************************* + * Name: mld_polyveck_power2round + * + * Description: For all coefficients a of polynomials in vector of length + *MLDSA_K, compute a0, a1 such that a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with + *-2^{MLDSA_D-1} < a0 <= 2^{MLDSA_D-1}. Assumes coefficients to be standard + *representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to output vector of polynomials with + * coefficients a0 + * - const mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) +); + +#define mld_polyveck_decompose MLD_NAMESPACE_KL(polyveck_decompose) +/************************************************* + * Name: mld_polyveck_decompose + * + * Description: For all coefficients a of polynomials in vector of length + * MLDSA_K, compute high and low bits a0, a1 such a mod^+ MLDSA_Q = a1*ALPHA + * + a0 with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (MLDSA_Q-1)/ALPHA where we set + * a1 = 0 and -ALPHA/2 <= a0 = a mod MLDSA_Q - MLDSA_Q < 0. Assumes coefficients + * to be standard representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to input/output vector of + * polynomials with. Output polynomial has + * coefficients a0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v0->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + ensures(forall(k2, 0, MLDSA_K, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) +); + +#define mld_polyveck_make_hint MLD_NAMESPACE_KL(polyveck_make_hint) +/************************************************* + * Name: mld_polyveck_make_hint + * + * Description: Compute hint vector. + * + * Arguments: - mld_polyveck *h: pointer to output vector + * - const mld_polyveck *v0: pointer to low part of input vector + * - const mld_polyveck *v1: pointer to high part of input vector + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(return_value <= MLDSA_N * MLDSA_K) + ensures(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) +); + +#define mld_polyveck_use_hint MLD_NAMESPACE_KL(polyveck_use_hint) +/************************************************* + * Name: mld_polyveck_use_hint + * + * Description: Use hint vector to correct the high bits of input vector. + * + * Arguments: - mld_polyveck *w: pointer to output vector of polynomials with + * corrected high bits + * - const mld_polyveck *u: pointer to input vector + * - const mld_polyveck *h: pointer to input hint vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *v, + const mld_polyveck *h) +__contract__( + requires(memory_no_alias(w, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + assigns(memory_slice(w, sizeof(mld_polyveck))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) +); + +#define mld_polyveck_pack_w1 MLD_NAMESPACE_KL(polyveck_pack_w1) +/************************************************* + * Name: mld_polyveck_pack_w1 + * + * Description: Bit-pack polynomial vector w1 with coefficients in [0,15] or + * [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_K* MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_polyveck *a: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(w1, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(w1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) +); + +#define mld_polyveck_pack_eta MLD_NAMESPACE_KL(polyveck_pack_eta) +/************************************************* + * Name: mld_polyveck_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients + * in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyvecl_pack_eta MLD_NAMESPACE_KL(polyvecl_pack_eta) +/************************************************* + * Name: mld_polyvecl_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_L * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyveck_pack_t0 MLD_NAMESPACE_KL(polyveck_pack_t0) +/************************************************* + * Name: mld_polyveck_pack_t0 + * + * Description: Bit-pack polynomial vector to with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(p->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) +); + +#define mld_polyvecl_unpack_eta MLD_NAMESPACE_KL(polyvecl_unpack_eta) +/************************************************* + * Name: mld_polyvecl_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyvecl *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + assigns(memory_slice(p, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyvecl_unpack_z MLD_NAMESPACE_KL(polyvecl_unpack_z) +/************************************************* + * Name: mld_polyvecl_unpack_z + * + * Description: Unpack polynomial vector with coefficients in + * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_polyvecl *z: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(z->vec[k1].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyveck_unpack_eta MLD_NAMESPACE_KL(polyveck_unpack_eta) +/************************************************* + * Name: mld_polyveck_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyveck_unpack_t0 MLD_NAMESPACE_KL(polyveck_unpack_t0) +/************************************************* + * Name: mld_polyveck_unpack_t0 + * + * Description: Unpack polynomial vector with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) +); + +#define mld_polymat_get_row MLD_NAMESPACE_KL(polymat_get_row) +/************************************************* + * Name: mld_polymat_get_row + * + * Description: Retrieve a pointer to a specific row of the matrix. + * In MLD_CONFIG_REDUCE_RAM mode, generates the row on-demand. + * + * Arguments: - mld_polymat *mat: pointer to matrix + * - unsigned int row: row index (must be < MLDSA_K) + * + * Returns pointer to the row (mld_polyvecl) + **************************************************/ +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row); + +#define mld_polyvec_matrix_expand MLD_NAMESPACE_KL(polyvec_matrix_expand) +/************************************************* + * Name: mld_polyvec_matrix_expand + * + * Description: Implementation of ExpandA. Generates matrix A with uniformly + * random coefficients a_{i,j} by performing rejection + * sampling on the output stream of SHAKE128(rho|j|i) + * + * Arguments: - mld_polymat *mat: pointer to output matrix + * - const uint8_t rho[]: byte array containing seed rho + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +__contract__( + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +); + + + +#define mld_polyvec_matrix_pointwise_montgomery \ + MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery) +/************************************************* + * Name: mld_polyvec_matrix_pointwise_montgomery + * + * Description: Compute matrix-vector multiplication in NTT domain with + * pointwise multiplication and multiplication by 2^{-32}. + * Input matrix and vector must be in NTT domain representation. + * + * The first input "mat" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * Note: In MLD_CONFIG_REDUCE_RAM mode, mat cannot be const + * as rows are generated on-demand. + * + * Arguments: - mld_polyveck *t: pointer to output vector t + * - mld_polymat *mat: pointer to input matrix + * - const mld_polyvecl *v: pointer to input vector v + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(t, sizeof(mld_polyveck))) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(t, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#endif /* !MLD_POLYVEC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/randombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/randombytes.h new file mode 100644 index 0000000000..da55772419 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/randombytes.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_RANDOMBYTES_H +#define MLD_RANDOMBYTES_H + +#include +#include + +#include "cbmc.h" +#include "common.h" + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +#if !defined(MLD_CONFIG_CUSTOM_RANDOMBYTES) +MLD_MUST_CHECK_RETURN_VALUE +int randombytes(uint8_t *out, size_t outlen); +static MLD_INLINE int mld_randombytes(uint8_t *out, size_t outlen) +__contract__( + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) { return randombytes(out, outlen); } +#endif /* !MLD_CONFIG_CUSTOM_RANDOMBYTES */ +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ +#endif /* !MLD_RANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/reduce.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/reduce.h new file mode 100644 index 0000000000..413cf1829e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/reduce.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_REDUCE_H +#define MLD_REDUCE_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* check-magic: -4186625 == pow(2,32,MLDSA_Q) */ +#define MLD_MONT -4186625 + +/* Upper bound for domain of mld_reduce32() */ +#define MLD_REDUCE32_DOMAIN_MAX (INT32_MAX - (1 << 22)) + +/* Absolute bound for range of mld_reduce32() */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define MLD_REDUCE32_RANGE_MAX 6283009 + +/************************************************* + * Name: mld_montgomery_reduce + * + * Description: Generic Montgomery reduction; given a 64-bit integer a, computes + * 32-bit integer congruent to a * R^-1 mod q, where R=2^32 + * + * Arguments: - int64_t a: input integer to be reduced, of absolute value + * smaller or equal to INT64_MAX - 2^31 * MLDSA_Q. + * + * Returns: Integer congruent to a * R^-1 modulo q, with absolute value + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * In particular, if |a| < 2^31 * MLDSA_Q, the absolute value + * of the return value is < MLDSA_Q. + **************************************************/ +static MLD_INLINE int32_t mld_montgomery_reduce(int64_t a) +__contract__( + /* We don't attempt to express an input-dependent output bound + * as the post-condition here, as all call-sites satisfy the + * absolute input bound 2^31 * MLDSA_Q and higher-level + * reasoning can be conducted using |return_value| < MLDSA_Q. */ + requires(a > -(((int64_t)1 << 31) * MLDSA_Q) && + a < (((int64_t)1 << 31) * MLDSA_Q)) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* check-magic: 58728449 == unsigned_mod(pow(MLDSA_Q, -1, 2^32), 2^32) */ + const uint64_t QINV = 58728449; + + /* Compute a*q^{-1} mod 2^32 in unsigned representatives */ + const uint32_t a_reduced = mld_cast_int64_to_uint32(a); + const uint32_t a_inverted = (a_reduced * QINV) & UINT32_MAX; + + /* Lift to signed canonical representative mod 2^32. */ + const int32_t t = mld_cast_uint32_to_int32(a_inverted); + + int64_t r; + + mld_assert(a < +(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)) && + a > -(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q))); + + r = a - (int64_t)t * MLDSA_Q; + + /* + * PORTABILITY: Right-shift on a signed integer is, strictly-speaking, + * implementation-defined for negative left argument. Here, + * we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5)) + */ + r = r >> 32; + + /* Bounds: + * + * By construction of the Montgomery multiplication, by the time we + * compute r >> 32, r is divisible by 2^32, and hence + * + * |r >> 32| = |r| / 2^32 + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * (In general, we would only have |x >> n| <= ceil(|x| / 2^n)). + * + * In particular, if |a| < 2^31 * MLDSA_Q, then |return_value| < MLDSA_Q. + */ + return (int32_t)r; +} + +/************************************************* + * Name: mld_reduce32 + * + * Description: For finite field element a with a <= 2^{31} - 2^{22} - 1, + * compute r \equiv a (mod MLDSA_Q) such that + * -MLD_REDUCE32_RANGE_MAX <= r < MLD_REDUCE32_RANGE_MAX. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_reduce32(int32_t a) +__contract__( + requires(a <= MLD_REDUCE32_DOMAIN_MAX) + ensures(return_value >= -MLD_REDUCE32_RANGE_MAX) + ensures(return_value < MLD_REDUCE32_RANGE_MAX) +) +{ + int32_t t; + + t = (a + (1 << 22)) >> 23; + t = a - t * MLDSA_Q; + mld_assert((t - a) % MLDSA_Q == 0); + return t; +} + +/************************************************* + * Name: mld_caddq + * + * Description: Add MLDSA_Q if input coefficient is negative. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_caddq(int32_t a) +__contract__( + requires(a > -MLDSA_Q) + requires(a < MLDSA_Q) + ensures(return_value >= 0) + ensures(return_value < MLDSA_Q) + ensures(return_value == (a >= 0) ? a : (a + MLDSA_Q)) +) +{ + return mld_ct_sel_int32(a + MLDSA_Q, a, mld_ct_cmask_neg_i32(a)); +} + + +#endif /* !MLD_REDUCE_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/rounding.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/rounding.h new file mode 100644 index 0000000000..a83562b0f1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/rounding.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_ROUNDING_H +#define MLD_ROUNDING_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_power2round MLD_ADD_PARAM_SET(mld_power2round) +#define mld_decompose MLD_ADD_PARAM_SET(mld_decompose) +#define mld_make_hint MLD_ADD_PARAM_SET(mld_make_hint) +#define mld_use_hint MLD_ADD_PARAM_SET(mld_use_hint) +/* End of parameter set namespacing */ + +#define MLD_2_POW_D (1 << MLDSA_D) + +/************************************************* + * Name: mld_power2round + * + * Description: For finite field element a, compute a0, a1 such that + * a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with -2^{MLDSA_D-1} < a0 <= + * 2^{MLDSA_D-1}. Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: In the reference implementation, a1 is passed as a + * return value instead. + **************************************************/ +static MLD_INLINE void mld_power2round(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + ensures(*a0 > -(MLD_2_POW_D/2) && *a0 <= (MLD_2_POW_D/2)) + ensures(*a1 >= 0 && *a1 <= (MLDSA_Q - 1) / MLD_2_POW_D) + ensures((*a1 * MLD_2_POW_D + *a0 - a) % MLDSA_Q == 0) +) +{ + *a1 = (a + (1 << (MLDSA_D - 1)) - 1) >> MLDSA_D; + *a0 = a - (*a1 << MLDSA_D); +} + +/************************************************* + * Name: mld_decompose + * + * Description: For finite field element a, compute high and low bits a0, a1 + * such that a mod^+ MLDSA_Q = a1* 2 * MLDSA_GAMMA2 + a0 with + * -MLDSA_GAMMA2 < a0 <= MLDSA_GAMMA2 except + * if a1 = (MLDSA_Q-1)/(MLDSA_GAMMA2*2) where we set a1 = 0 and + * -MLDSA_GAMMA2 <= a0 = a mod^+ MLDSA_Q - MLDSA_Q < 0. + * Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: a1 is passed as a return value instead + **************************************************/ +static MLD_INLINE void mld_decompose(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + /* a0 = -MLDSA_GAMMA2 can only occur when (q-1) = a - (a mod MLDSA_GAMMA2), + * then a1=1; and a0 = a - (a mod MLDSA_GAMMA2) - 1 (@[FIPS204, Algorithm 36 (Decompose)]) */ + ensures(*a0 >= -MLDSA_GAMMA2 && *a0 <= MLDSA_GAMMA2) + ensures(*a1 >= 0 && *a1 < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) + ensures((*a1 * 2 * MLDSA_GAMMA2 + *a0 - a) % MLDSA_Q == 0) +) +{ + /* + * The goal is to compute f1 = round-(f / (2*GAMMA2)), which can be computed + * alternatively as round-(f / (128B)) = round-(ceil(f / 128) / B) where + * B = 2*GAMMA2 / 128. Here round-() denotes "round half down". + * + * The equality round-(f / (128B)) = round-(ceil(f / 128) / B) can deduced + * as follows. Since changing f to align-up(f, 128) can move f onto but not + * across a rounding boundary for division by 128*B (note that we need B to be + * even for this to work), and round- rounds down on the boundary, we have + * + * round-(f / (128B)) = round-(align-up(f, 128) / (128B)) + * = round-((align-up(f, 128) / 128) / B) + * = round-(ceil(f / 128) / B). + */ + *a1 = (a + 127) >> 7; + /* We know a >= 0 and a < MLDSA_Q, so... */ + /* check-magic: 65472 == round((MLDSA_Q-1)/128) */ + mld_assert(*a1 >= 0 && *a1 <= 65472); + +#if MLD_CONFIG_PARAMETER_SET == 44 + /* check-magic: 1488 == 2 * intdiv(intdiv(MLDSA_Q - 1, 88), 128) */ + /* check-magic: 11275 == floor(2**24 / 1488) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + */ + *a1 = (*a1 * 11275 + (1 << 23)) >> 24; + mld_assert(*a1 >= 0 && *a1 <= 44); + + *a1 = mld_ct_sel_int32(0, *a1, mld_ct_cmask_neg_i32(43 - *a1)); + mld_assert(*a1 >= 0 && *a1 <= 43); +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + /* check-magic: 4092 == 2 * intdiv(intdiv(MLDSA_Q - 1, 32), 128) */ + /* check-magic: 1025 == floor(2**22 / 4092) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + */ + *a1 = (*a1 * 1025 + (1 << 21)) >> 22; + mld_assert(*a1 >= 0 && *a1 <= 16); + + *a1 &= 15; + mld_assert(*a1 >= 0 && *a1 <= 15); + +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + + *a0 = a - *a1 * 2 * MLDSA_GAMMA2; + *a0 = mld_ct_sel_int32(*a0 - MLDSA_Q, *a0, + mld_ct_cmask_neg_i32((MLDSA_Q - 1) / 2 - *a0)); +} + +/************************************************* + * Name: mld_make_hint + * + * Description: Compute hint bit indicating whether the low bits of the + * input element overflow into the high bits. + * + * Arguments: - int32_t a0: low bits of input element + * - int32_t a1: high bits of input element + * + * Returns 1 if overflow, 0 otherwise + **************************************************/ +static MLD_INLINE unsigned int mld_make_hint(int32_t a0, int32_t a1) +__contract__( + ensures(return_value >= 0 && return_value <= 1) +) +{ + if (a0 > MLDSA_GAMMA2 || a0 < -MLDSA_GAMMA2 || + (a0 == -MLDSA_GAMMA2 && a1 != 0)) + { + return 1; + } + + return 0; +} + +/************************************************* + * Name: mld_use_hint + * + * Description: Correct high bits according to hint. + * + * Arguments: - int32_t a: input element + * - int32_t hint: hint bit + * + * Returns corrected high bits. + **************************************************/ +static MLD_INLINE int32_t mld_use_hint(int32_t a, int32_t hint) +__contract__( + requires(hint >= 0 && hint <= 1) + requires(a >= 0 && a < MLDSA_Q) + ensures(return_value >= 0 && return_value < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) +) +{ + int32_t a0, a1; + + mld_decompose(&a0, &a1, a); + if (hint == 0) + { + return a1; + } + +#if MLD_CONFIG_PARAMETER_SET == 44 + if (a0 > 0) + { + return (a1 == 43) ? 0 : a1 + 1; + } + else + { + return (a1 == 0) ? 43 : a1 - 1; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + if (a0 > 0) + { + return (a1 + 1) & 15; + } + else + { + return (a1 - 1) & 15; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + + +#endif /* !MLD_ROUNDING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/sign.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/sign.c new file mode 100644 index 0000000000..32bba52d65 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/sign.c @@ -0,0 +1,1508 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [Round3_Spec] + * CRYSTALS-Dilithium Algorithm Specifications and Supporting Documentation + * (Version 3.1) + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf + */ + +#include +#include + +#include "cbmc.h" +#include "ct.h" +#include "debug.h" +#include "packing.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" +#include "randombytes.h" +#include "sign.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_check_pct MLD_ADD_PARAM_SET(mld_check_pct) MLD_CONTEXT_PARAMETERS_2 +#define mld_sample_s1_s2 MLD_ADD_PARAM_SET(mld_sample_s1_s2) +#define mld_validate_hash_length MLD_ADD_PARAM_SET(mld_validate_hash_length) +#define mld_get_hash_oid MLD_ADD_PARAM_SET(mld_get_hash_oid) +#define mld_H MLD_ADD_PARAM_SET(mld_H) +#define mld_compute_pack_z MLD_ADD_PARAM_SET(mld_compute_pack_z) +#define mld_attempt_signature_generation \ + MLD_ADD_PARAM_SET(mld_attempt_signature_generation) MLD_CONTEXT_PARAMETERS_8 +#define mld_compute_t0_t1_tr_from_sk_components \ + MLD_ADD_PARAM_SET(mld_compute_t0_t1_tr_from_sk_components) \ + MLD_CONTEXT_PARAMETERS_7 +/* End of parameter set namespacing */ + + +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + ensures(return_value == 0 + || return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL) +); + +#if defined(MLD_CONFIG_KEYGEN_PCT) +/************************************************* + * @[FIPS140_3_IG] + * (https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf) + * + * TE10.35.02: Pair-wise Consistency Test (PCT) for DSA keypairs + * + * Purpose: Validates that a generated public/private key pair can correctly + * sign and verify data. Test performs signature generation using the private + * key (sk), followed by signature verification using the public key (pk). + * Returns 0 if the signature was successfully verified, non-zero if it cannot. + * + * Note: @[FIPS204] requires that public/private key pairs are to be used only + * for the calculation and/of verification of digital signatures. + **************************************************/ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t message[1] = {0}; + size_t siglen; + int ret; + MLD_ALLOC(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + MLD_ALLOC(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + + if (signature == NULL || pk_test == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Copy public key for testing */ + mld_memcpy(pk_test, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* Sign a test message using the original secret key */ + ret = mld_sign_signature(signature, &siglen, message, sizeof(message), NULL, + 0, sk, context); + if (ret != 0) + { + goto cleanup; + } + +#if defined(MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST) + /* Deliberately break public key for testing purposes */ + if (mld_break_pct()) + { + pk_test[0] = ~pk_test[0]; + } +#endif /* MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST */ + + /* Verify the signature using the (potentially corrupted) public key */ + ret = mld_sign_verify(signature, siglen, message, sizeof(message), NULL, 0, + pk_test, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + MLD_FREE(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + + return ret; +} +#else /* MLD_CONFIG_KEYGEN_PCT */ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + /* Skip PCT */ + ((void)pk); + ((void)sk); +#if defined(MLD_CONFIG_CONTEXT_PARAMETER) + ((void)context); +#endif + return 0; +} +#endif /* !MLD_CONFIG_KEYGEN_PCT */ + +static void mld_sample_s1_s2(mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t seed[MLDSA_CRHBYTES]) +__contract__( + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(object_whole(s1), object_whole(s2)) + ensures(forall(l0, 0, MLDSA_L, array_abs_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + ensures(forall(k0, 0, MLDSA_K, array_abs_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) +) +{ +/* Sample short vectors s1 and s2 */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; + uint16_t nonce = 0; + /* Safety: The nonces are at most 14 (MLDSA_L + MLDSA_K - 1), and, hence, the + * casts are safe. */ + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_eta(&s1->vec[i], seed, (uint8_t)(nonce + i)); + } + for (i = 0; i < MLDSA_K; i++) + { + mld_poly_uniform_eta(&s2->vec[i], seed, (uint8_t)(nonce + MLDSA_L + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLD_CONFIG_PARAMETER_SET == 44 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 4, 5, 6, 7); +#elif MLD_CONFIG_PARAMETER_SET == 65 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s2->vec[0], &s2->vec[1], + &s2->vec[2] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[2], &s2->vec[3], &s2->vec[4], &s2->vec[5], + seed, 7, 8, 9, 10); +#elif MLD_CONFIG_PARAMETER_SET == 87 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s1->vec[5], &s1->vec[6], + &s2->vec[0] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 7, 8, 9, 10); + mld_poly_uniform_eta_4x(&s2->vec[4], &s2->vec[5], &s2->vec[6], &s2->vec[7], + seed, 11, 12, 13, 14); +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ +} + +/************************************************* + * Name: mld_compute_t0_t1_tr_from_sk_components + * + * Description: Computes t0, t1, tr, and pk from secret key components + * rho, s1, s2. This is the shared computation used by + * both keygen and generating the public key from the + * secret key. + * + * Arguments: - mld_polyveck *t0: output t0 + * - mld_polyveck *t1: output t1 + * - uint8_t tr[MLDSA_TRBYTES]: output tr + * - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t rho[MLDSA_SEEDBYTES]: input rho + * - const mld_polyvecl *s1: input s1 + * - const mld_polyveck *s2: input s2 + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_t0_t1_tr_from_sk_components( + mld_polyveck *t0, mld_polyveck *t1, uint8_t tr[MLDSA_TRBYTES], + uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], const uint8_t rho[MLDSA_SEEDBYTES], + const mld_polyvecl *s1, const mld_polyveck *s2, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(l0, 0, MLDSA_L, array_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + requires(forall(k0, 0, MLDSA_K, array_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(forall(k1, 0, MLDSA_K, array_bound(t0->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(t1->vec[k2].coeffs, 0, MLDSA_N, 0, 1 << 10))) + ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY)) +{ + int ret; + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1hat, mld_polyvecl, 1, context); + MLD_ALLOC(t, mld_polyveck, 1, context); + + if (mat == NULL || s1hat == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Expand matrix */ + mld_polyvec_matrix_expand(mat, rho); + + /* Matrix-vector multiplication */ + *s1hat = *s1; + mld_polyvecl_ntt(s1hat); + mld_polyvec_matrix_pointwise_montgomery(t, mat, s1hat); + mld_polyveck_invntt_tomont(t); + + /* Add error vector s2 */ + mld_polyveck_add(t, s2); + + /* Reference: The following reduction is not present in the reference + * implementation. Omitting this reduction requires the output of + * the invntt to be small enough such that the addition of s2 does + * not result in absolute values >= MLDSA_Q. While our C, x86_64, + * and AArch64 invntt implementations produce small enough + * values for this to work out, it complicates the bounds + * reasoning. We instead add an additional reduction, and can + * consequently, relax the bounds requirements for the invntt. + */ + mld_polyveck_reduce(t); + + /* Decompose to get t1, t0 */ + mld_polyveck_caddq(t); + mld_polyveck_power2round(t1, t0, t); + + /* Pack public key and compute tr */ + mld_pack_pk(pk, rho, t1); + mld_shake256(tr, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + ret = 0; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_polyveck, 1, context); + MLD_FREE(s1hat, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + const uint8_t *rho, *rhoprime, *key; + MLD_ALLOC(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + MLD_ALLOC(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + + if (seedbuf == NULL || inbuf == NULL || tr == NULL || s1 == NULL || + s2 == NULL || t1 == NULL || t0 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Get randomness for rho, rhoprime and key */ + mld_memcpy(inbuf, seed, MLDSA_SEEDBYTES); + inbuf[MLDSA_SEEDBYTES + 0] = MLDSA_K; + inbuf[MLDSA_SEEDBYTES + 1] = MLDSA_L; + mld_shake256(seedbuf, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, inbuf, + MLDSA_SEEDBYTES + 2); + rho = seedbuf; + rhoprime = rho + MLDSA_SEEDBYTES; + key = rhoprime + MLDSA_CRHBYTES; + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + + /* Sample s1 and s2 */ + mld_sample_s1_s2(s1, s2, rhoprime); + + /* Compute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0, t1, tr, pk, rho, s1, s2, + context); + if (ret != 0) + { + goto cleanup; + } + + /* Pack secret key */ + mld_pack_sk(sk, rho, tr, key, t0, s1, s2); + + /* Constant time: pk is the public key, inherently public data */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_FREE(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + + if (ret != 0) + { + return ret; + } + + /* Pairwise Consistency Test (PCT) @[FIPS140_3_IG, p.87] */ + /* Do this after freeing all temporaries. */ + return mld_check_pct(pk, sk, context); +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t seed[MLDSA_SEEDBYTES]; + int ret; + if (mld_randombytes(seed, MLDSA_SEEDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(seed, sizeof(seed)); + ret = mld_sign_keypair_internal(pk, sk, seed, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed, sizeof(seed)); + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +/************************************************* + * Name: mld_H + * + * Description: Abstracts application of SHAKE256 to + * one, two or three blocks of data, + * yielding a user-requested size of + * output. + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in1: pointer to input block 1 + * Must NOT be NULL + * - size_t in1len: length of input in1 bytes + * - const uint8_t *in2: pointer to input block 2 + * May be NULL if in2len=0, in which case + * this block is ignored + * - size_t in2len: length of input in2 bytes + * - const uint8_t *in3: pointer to input block 3 + * May be NULL if in3len=0, in which case + * this block is ignored + * - size_t in3len: length of input in3 bytes + **************************************************/ +static void mld_H(uint8_t *out, size_t outlen, const uint8_t *in1, + size_t in1len, const uint8_t *in2, size_t in2len, + const uint8_t *in3, size_t in3len) +__contract__( + requires(in1len <= MLD_MAX_BUFFER_SIZE) + requires(in2len <= MLD_MAX_BUFFER_SIZE) + requires(in3len <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in1, in1len)) + requires(in2len == 0 || memory_no_alias(in2, in2len)) + requires(in3len == 0 || memory_no_alias(in3, in3len)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) +{ + mld_shake256ctx state; + mld_shake256_init(&state); + mld_shake256_absorb(&state, in1, in1len); + if (in2len != 0) + { + mld_shake256_absorb(&state, in2, in2len); + } + if (in3len != 0) + { + mld_shake256_absorb(&state, in3, in3len); + } + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(&state, sizeof(state)); +} + +/************************************************* + * Name: mld_compute_pack_z + * + * Description: Computes z = y + s1*c, checks that z has coefficients smaller + * than MLDSA_GAMMA1 - MLDSA_BETA, and packs z into the + * signature buffer. + * + * Arguments: - uint8_t *sig: output signature + * - const mld_poly *cp: challenge polynomial + * - const polyvecl *s1: secret vector s1 + * - const polyvecl *y: masking vector y + * + * Returns: - 0: Success (z has coefficients smaller than + * MLDSA_GAMMA1 - MLDSA_BETA,) + * - MLD_ERR_FAIL: z rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This function is inlined into mld_sign_signature in the + * reference implementation. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_pack_z(uint8_t sig[MLDSA_CRYPTO_BYTES], + const mld_poly *cp, const mld_polyvecl *s1, + const mld_polyvecl *y, mld_poly *z) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(cp, sizeof(mld_poly))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(y, sizeof(mld_polyvecl))) + requires(memory_no_alias(z, sizeof(mld_poly))) + requires(array_abs_bound(cp->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_L, + array_bound(y->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + requires(forall(k1, 0, MLDSA_L, array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(memory_slice(z, sizeof(mld_poly))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int i; + uint32_t z_invalid; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(z, sizeof(mld_poly)), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_poly_pointwise_montgomery(z, cp, &s1->vec[i]); + mld_poly_invntt_tomont(z); + mld_poly_add(z, &y->vec[i]); + mld_poly_reduce(z); + + z_invalid = mld_poly_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA); + /* Constant time: It is fine (and prohibitively expensive to avoid) + * to leak the result of the norm check and which polynomial in z caused a + * rejection. It would even be okay to leak which coefficient led to + * rejection as the candidate signature will be discarded anyway. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(&z_invalid, sizeof(uint32_t)); + if (z_invalid) + { + return MLD_ERR_FAIL; /* reject */ + } + /* If z is valid, then its coefficients are bounded by + * MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below + * to prove the pre-condition of pack_sig_z() */ + mld_assert_abs_bound(z, MLDSA_N, (MLDSA_GAMMA1 - MLDSA_BETA)); + + /* After the norm check, the distribution of each coefficient of z is + * independent of the secret key and it can, hence, be considered + * public. It is, hence, okay to immediately pack it into the user-provided + * signature buffer. */ + mld_pack_sig_z(sig, z, i); + } + return 0; +} + +/* Reference: The reference implementation does not explicitly check the + * maximum nonce value, but instead loops indefinitely (even when the nonce + * would overflow). Internally, sampling of y uses + * (nonceL), (nonceL+1), ... (nonce*L+L-1). + * Hence, there are no overflows if nonce < (UINT16_MAX - L)/L. + * Explicitly checking for this explicitly allows us to prove type-safety. + * Note that FIPS204 explicitly allows an upper-bound this loop of + * 814 (< (UINT16_MAX - L)/L) - see @[FIPS204, Appendix C]. */ +#define MLD_NONCE_UB ((UINT16_MAX - MLDSA_L) / MLDSA_L) + +/************************************************* + * Name: attempt_signature_generation + * + * Description: Attempts to generate a single signature. + * + * Arguments: - uint8_t *sig: pointer to output signature + * - const uint8_t *mu: pointer to message or hash + * of exactly MLDSA_CRHBYTES bytes + * - const uint8_t *rhoprime: pointer to randomness seed + * - uint16_t nonce: current nonce value + * - const mld_polymat *mat: expanded matrix + * - const polyvecl *s1: secret vector s1 + * - const polyveck *s2: secret vector s2 + * - const polyveck *t0: vector t0 + * + * Returns: - 0: Signature generation succeeded + * - MLD_ERR_FAIL: Signature rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This code differs from the reference implementation + * in that it factors out the core signature generation + * step into a distinct function here in order to improve + * efficiency of CBMC proof. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_attempt_signature_generation( + uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *mu, + const uint8_t rhoprime[MLDSA_CRHBYTES], uint16_t nonce, mld_polymat *mat, + const mld_polyvecl *s1, const mld_polyveck *s2, const mld_polyveck *t0, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(rhoprime, MLDSA_CRHBYTES)) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(nonce <= MLD_NONCE_UB) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int n; + uint32_t w0_invalid, h_invalid; + int ret; + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyvecl y; + mld_polyveck h; + } + yh_u; + mld_polyvecl *y; + mld_polyveck *h; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck w1; + mld_polyvecl tmp; + } + w1tmp_u; + mld_polyveck *w1; + mld_polyvecl *tmp; + + MLD_ALLOC(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(yh, yh_u, 1, context); + MLD_ALLOC(z, mld_poly, 1, context); + MLD_ALLOC(w1tmp, w1tmp_u, 1, context); + MLD_ALLOC(w0, mld_polyveck, 1, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(t, mld_poly, 1, context); + + if (challenge_bytes == NULL || yh == NULL || z == NULL || w1tmp == NULL || + w0 == NULL || cp == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + y = &yh->y; + h = &yh->h; + w1 = &w1tmp->w1; + tmp = &w1tmp->tmp; + + /* Sample intermediate vector y */ + mld_polyvecl_uniform_gamma1(y, rhoprime, nonce); + + /* Matrix-vector multiplication */ + *tmp = *y; + mld_polyvecl_ntt(tmp); + mld_polyvec_matrix_pointwise_montgomery(w0, mat, tmp); + mld_polyveck_invntt_tomont(w0); + + /* Decompose w and call the random oracle */ + mld_polyveck_caddq(w0); + mld_polyveck_decompose(w1, w0); + mld_polyveck_pack_w1(sig, w1); + + mld_H(challenge_bytes, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, sig, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + /* Constant time: Leaking challenge_bytes does not reveal any information + * about the secret key as H() is modelled as random oracle. + * This also applies to challenges for rejected signatures. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(challenge_bytes, MLDSA_CTILDEBYTES); + mld_poly_challenge(cp, challenge_bytes); + mld_poly_ntt(cp); + + /* Compute z, reject if it reveals secret */ + ret = mld_compute_pack_z(sig, cp, s1, y, t); + if (ret) + { + goto cleanup; + } + + /* Check that subtracting cs2 does not change high bits of w and low bits + * do not reveal secret information */ + mld_polyveck_pointwise_poly_montgomery(h, cp, s2); + mld_polyveck_invntt_tomont(h); + mld_polyveck_sub(w0, h); + mld_polyveck_reduce(w0); + + w0_invalid = mld_polyveck_chknorm(w0, MLDSA_GAMMA2 - MLDSA_BETA); + /* Constant time: w0_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&w0_invalid, sizeof(uint32_t)); + if (w0_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* Compute hints for w1 */ + mld_polyveck_pointwise_poly_montgomery(h, cp, t0); + mld_polyveck_invntt_tomont(h); + mld_polyveck_reduce(h); + + h_invalid = mld_polyveck_chknorm(h, MLDSA_GAMMA2); + /* Constant time: h_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&h_invalid, sizeof(uint32_t)); + if (h_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + mld_polyveck_add(w0, h); + + /* Constant time: At this point all norm checks have passed and we, hence, + * know that the signature does not leak any secret information. + * Consequently, any value that can be computed from the signature and public + * key is considered public. + * w0 and w1 are public as they can be computed from Az - ct = \alpha w1 + w0. + * h=c*t0 is public as both c and t0 are public. + * For a more detailed discussion, refer to https://eprint.iacr.org/2022/1406. + */ + MLD_CT_TESTING_DECLASSIFY(w0, sizeof(*w0)); + MLD_CT_TESTING_DECLASSIFY(w1, sizeof(*w1)); + n = mld_polyveck_make_hint(h, w0, w1); + if (n > MLDSA_OMEGA) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* All is well - write signature */ + mld_pack_sig_c_h(sig, challenge_bytes, h, n); + /* Constant time: At this point it is clear that the signature is valid - it + * can, hence, be considered public. */ + MLD_CT_TESTING_DECLASSIFY(sig, MLDSA_CRYPTO_BYTES); + ret = 0; /* success */ + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_poly, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(w0, mld_polyveck, 1, context); + MLD_FREE(w1tmp, w1tmp_u, 1, context); + MLD_FREE(z, mld_poly, 1, context); + MLD_FREE(yh, yh_u, 1, context); + MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + + return ret; +} +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + uint8_t *rho, *tr, *key, *mu, *rhoprime; + uint16_t nonce = 0; + MLD_ALLOC(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + + if (seedbuf == NULL || mat == NULL || s1 == NULL || t0 == NULL || s2 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + rho = seedbuf; + tr = rho + MLDSA_SEEDBYTES; + key = tr + MLDSA_TRBYTES; + mu = key + MLDSA_SEEDBYTES; + rhoprime = mu + MLDSA_CRHBYTES; + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + if (!externalmu) + { + /* Compute mu = CRH(tr, pre, msg) */ + mld_H(mu, MLDSA_CRHBYTES, tr, MLDSA_TRBYTES, pre, prelen, m, mlen); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Compute rhoprime = CRH(key, rnd, mu) */ + mld_H(rhoprime, MLDSA_CRHBYTES, key, MLDSA_SEEDBYTES, rnd, MLDSA_RNDBYTES, mu, + MLDSA_CRHBYTES); + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + /* Expand matrix and transform vectors */ + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(s1); + mld_polyveck_ntt(s2); + mld_polyveck_ntt(t0); + + /* By default, return failure. Flip to success and write output + * once signature generation succeeds. */ + ret = MLD_ERR_FAIL; + + /* Reference: This code is re-structured using a while(1), */ + /* with explicit "continue" statements (rather than "goto") */ + /* to implement rejection of invalid signatures. */ + while (1) + __loop__( + assigns(nonce, ret, object_whole(siglen), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(nonce <= MLD_NONCE_UB) + + /* t0, s1, s2, and mat are initialized above and are NOT changed by this */ + /* loop. We can therefore re-assert their bounds here as part of the */ + /* loop invariant. This makes proof noticeably faster with CBMC */ + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + invariant(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(ret == MLD_ERR_FAIL) + ) + { + /* Reference: this code explicitly checks for exhaustion of nonce */ + /* values to provide predictable termination and results in that case */ + /* Checking here also means that incrementing nonce below can also */ + /* be proven to be type-safe. */ + if (nonce == MLD_NONCE_UB) + { + /* Note that ret == MLD_ERR_FAIL by default, so we + * don't need to set it here. */ + break; + } + + ret = mld_attempt_signature_generation(sig, mu, rhoprime, nonce, mat, s1, + s2, t0, context); + nonce++; + if (ret == 0) + { + *siglen = MLDSA_CRYPTO_BYTES; + break; + } + else if (ret != MLD_ERR_FAIL) + { + /* For failures such as out-of-memory, propagate and exit immediately. */ + break; + } + + /* Otherwise, try again. */ + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the signature buffer. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + return ret; +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + size_t pre_len; + int ret; + MLD_ALLOC(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + MLD_ALLOC(rnd, uint8_t, MLDSA_RNDBYTES, context); + + if (pre == NULL || rnd == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Prepare domain separation prefix for pure ML-DSA */ + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, m, mlen, pre, pre_len, rnd, sk, + 0, context); + +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(rnd, uint8_t, MLDSA_RNDBYTES, context); + MLD_FREE(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t rnd[MLDSA_RNDBYTES]; + int ret; + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + *siglen = 0; + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, + rnd, sk, 1, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(rnd, sizeof(rnd)); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + for (i = 0; i < mlen; ++i) + __loop__( + assigns(i, object_whole(sm)) + invariant(i <= mlen) + ) + { + sm[MLDSA_CRYPTO_BYTES + mlen - 1 - i] = m[mlen - 1 - i]; + } + ret = mld_sign_signature(sm, smlen, sm + MLDSA_CRYPTO_BYTES, mlen, ctx, + ctxlen, sk, context); + *smlen += mlen; + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret, cmp; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck t1; + mld_polyveck w1; + } + t1w1_u; + mld_polyveck *t1; + mld_polyveck *w1; + + MLD_ALLOC(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_ALLOC(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(z, mld_polyvecl, 1, context); + MLD_ALLOC(t1w1, t1w1_u, 1, context); + MLD_ALLOC(tmp, mld_polyveck, 1, context); + MLD_ALLOC(h, mld_polyveck, 1, context); + + if (buf == NULL || rho == NULL || mu == NULL || c == NULL || c2 == NULL || + cp == NULL || mat == NULL || z == NULL || t1w1 == NULL || tmp == NULL || + h == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + t1 = &t1w1->t1; + w1 = &t1w1->w1; + + if (siglen != MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + mld_unpack_pk(rho, t1, pk); + + /* mld_unpack_sig and mld_polyvecl_chknorm signal failure through a + * single non-zero error code that's not yet aligned with MLD_ERR_XXX. + * Map it to MLD_ERR_FAIL explicitly. */ + if (mld_unpack_sig(c, z, h, sig)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + if (mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + if (!externalmu) + { + /* Compute CRH(H(rho, t1), pre, msg) */ + MLD_ALIGN uint8_t hpk[MLDSA_CRHBYTES]; + mld_H(hpk, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES, NULL, 0, NULL, + 0); + mld_H(mu, MLDSA_CRHBYTES, hpk, MLDSA_TRBYTES, pre, prelen, m, mlen); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(hpk, sizeof(hpk)); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Matrix-vector multiplication; compute Az - c2^dt1 */ + mld_poly_challenge(cp, c); + mld_poly_ntt(cp); + mld_polyveck_shiftl(t1); + mld_polyveck_ntt(t1); + mld_polyveck_pointwise_poly_montgomery(tmp, cp, t1); + + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(z); + mld_polyvec_matrix_pointwise_montgomery(w1, mat, z); + mld_polyveck_sub(w1, tmp); + mld_polyveck_reduce(w1); + mld_polyveck_invntt_tomont(w1); + + /* Reconstruct w1 */ + mld_polyveck_caddq(w1); + mld_polyveck_use_hint(tmp, w1, h); + mld_polyveck_pack_w1(buf, tmp); + /* Call random oracle and verify challenge */ + mld_H(c2, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, buf, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + + cmp = mld_ct_memcmp(c, c2, MLDSA_CTILDEBYTES); + + /* Declassify the result of the verification. */ + MLD_CT_TESTING_DECLASSIFY(&cmp, sizeof(cmp)); + + ret = cmp == 0 ? 0 : MLD_ERR_FAIL; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(h, mld_polyveck, 1, context); + MLD_FREE(tmp, mld_polyveck, 1, context); + MLD_FREE(t1w1, t1w1_u, 1, context); + MLD_FREE(z, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, m, mlen, pre, pre_len, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + return mld_sign_verify_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, pk, + 1, context); +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + if (smlen < MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + *mlen = smlen - MLDSA_CRYPTO_BYTES; + ret = mld_sign_verify(sm, MLDSA_CRYPTO_BYTES, sm + MLDSA_CRYPTO_BYTES, *mlen, + ctx, ctxlen, pk, context); + if (ret == 0) + { + /* All good, copy msg, return 0 */ + for (i = 0; i < *mlen; ++i) + __loop__( + assigns(i, memory_slice(m, *mlen)) + invariant(i <= *mlen) + ) + { + m[i] = sm[MLDSA_CRYPTO_BYTES + i]; + } + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the message buffer. */ + *mlen = 0; + mld_memset(m, 0, smlen); + } + + return ret; +} + + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_signature_internal(sig, siglen, pre, pre_len, NULL, 0, rnd, sk, + 0, context); +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, pre, pre_len, NULL, 0, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_signature_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, rnd, sk, + MLD_PREHASH_SHAKE_256, context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_verify_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, pk, MLD_PREHASH_SHAKE_256, + context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + + +#define MLD_PRE_HASH_OID_LEN 11 + +/************************************************* + * Name: mld_get_hash_oid + * + * Description: Returns the OID of a given SHA-2/SHA-3 hash function. + * + * Arguments: - uint8_t oid[11]: pointer to output oid + * - int hashalg: hash algorithm constant (MLD_PREHASH_*) + * + ***************************************************/ +static void mld_get_hash_oid(uint8_t oid[MLD_PRE_HASH_OID_LEN], int hashalg) +{ + unsigned int i; + static const struct + { + int alg; + uint8_t oid[MLD_PRE_HASH_OID_LEN]; + } oid_map[] = { + {MLD_PREHASH_SHA2_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}}, + {MLD_PREHASH_SHA2_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}}, + {MLD_PREHASH_SHA2_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}}, + {MLD_PREHASH_SHA2_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}}, + {MLD_PREHASH_SHA2_512_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05}}, + {MLD_PREHASH_SHA2_512_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06}}, + {MLD_PREHASH_SHA3_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07}}, + {MLD_PREHASH_SHA3_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08}}, + {MLD_PREHASH_SHA3_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09}}, + {MLD_PREHASH_SHA3_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A}}, + {MLD_PREHASH_SHAKE_128, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B}}, + {MLD_PREHASH_SHAKE_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C}}}; + + for (i = 0; i < sizeof(oid_map) / sizeof(oid_map[0]); i++) + __loop__( + invariant(i <= sizeof(oid_map) / sizeof(oid_map[0])) + ) + { + if (oid_map[i].alg == hashalg) + { + mld_memcpy(oid, oid_map[i].oid, MLD_PRE_HASH_OID_LEN); + return; + } + } +} + +static int mld_validate_hash_length(int hashalg, size_t len) +{ + switch (hashalg) + { + case MLD_PREHASH_SHA2_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_128: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_256: + return (len == 512 / 8) ? 0 : -1; + } + return -1; +} + +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +{ + if (ctxlen > 255) + { + return 0; + } + + if (hashalg != MLD_PREHASH_NONE) + { + if (ph == NULL || mld_validate_hash_length(hashalg, phlen) != 0) + { + return 0; + } + } + + /* Common prefix: 0x00/0x01 || ctxlen || ctx */ + prefix[0] = (hashalg == MLD_PREHASH_NONE) ? 0 : 1; + prefix[1] = (uint8_t)ctxlen; + if (ctxlen > 0) + { + mld_memcpy(prefix + 2, ctx, ctxlen); + } + + if (hashalg == MLD_PREHASH_NONE) + { + return 2 + ctxlen; + } + + /* HashML-DSA: append oid || ph */ + mld_get_hash_oid(prefix + 2 + ctxlen, hashalg); + mld_memcpy(prefix + 2 + ctxlen + MLD_PRE_HASH_OID_LEN, ph, phlen); + return 2 + ctxlen + MLD_PRE_HASH_OID_LEN + phlen; +} + +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + uint8_t check, cmp0, cmp1, chk1, chk2; + int ret; + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(t0_computed, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + + if (rho == NULL || tr == NULL || tr_computed == NULL || key == NULL || + s1 == NULL || s2 == NULL || t0 == NULL || t0_computed == NULL || + t1 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Unpack secret key */ + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + /* Validate s1 and s2 coefficients are within [-MLDSA_ETA, MLDSA_ETA] */ + chk1 = mld_polyvecl_chknorm(s1, MLDSA_ETA + 1) & 0xFF; + chk2 = mld_polyveck_chknorm(s2, MLDSA_ETA + 1) & 0xFF; + + /* Recompute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0_computed, t1, tr_computed, + pk, rho, s1, s2, context); + if (ret != 0) + { + goto cleanup; + } + + /* Validate t0 and tr using constant-time comparisons */ + cmp0 = mld_ct_memcmp((const uint8_t *)t0, (const uint8_t *)t0_computed, + sizeof(mld_polyveck)); + cmp1 = mld_ct_memcmp((const uint8_t *)tr, (const uint8_t *)tr_computed, + MLDSA_TRBYTES); + check = mld_value_barrier_u8(cmp0 | cmp1 | chk1 | chk2); + + /* Declassify the final result of the validity check. */ + MLD_CT_TESTING_DECLASSIFY(&check, sizeof(check)); + ret = (check != 0) ? MLD_ERR_FAIL : 0; + +cleanup: + + if (ret != 0) + { + mld_zeroize(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + } + + /* Constant time: pk is either the valid public key or zeroed on error */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(t0_computed, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + + return ret; +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_check_pct +#undef mld_sample_s1_s2 +#undef mld_validate_hash_length +#undef mld_get_hash_oid +#undef mld_H +#undef mld_compute_pack_z +#undef mld_attempt_signature_generation +#undef mld_compute_t0_t1_tr_from_sk_components +#undef MLD_NONCE_UB +#undef MLD_PRE_HASH_OID_LEN diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/sign.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/sign.h new file mode 100644 index 0000000000..2e0bac32ea --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/sign.h @@ -0,0 +1,807 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_SIGN_H +#define MLD_SIGN_H + +#include +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "polyvec.h" +#include "sys.h" + +#if defined(MLD_CHECK_APIS) +/* Include to ensure consistency between internal sign.h + * and external mldsa_native.h. */ +#include "mldsa_native.h" + +#if MLDSA_CRYPTO_SECRETKEYBYTES != \ + MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for SECRETKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_PUBLICKEYBYTES != \ + MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for PUBLICKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_BYTES != MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for CRYPTO_BYTES between sign.h and mldsa_native.h +#endif + +#endif /* MLD_CHECK_APIS */ + +#define mld_sign_keypair_internal \ + MLD_NAMESPACE_KL(keypair_internal) MLD_CONTEXT_PARAMETERS_3 +#define mld_sign_keypair MLD_NAMESPACE_KL(keypair) MLD_CONTEXT_PARAMETERS_2 +#define mld_sign_signature_internal \ + MLD_NAMESPACE_KL(signature_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_signature MLD_NAMESPACE_KL(signature) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_extmu \ + MLD_NAMESPACE_KL(signature_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign MLD_NAMESPACE_KL(sign) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_internal \ + MLD_NAMESPACE_KL(verify_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify MLD_NAMESPACE_KL(verify) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_extmu \ + MLD_NAMESPACE_KL(verify_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign_open MLD_NAMESPACE_KL(open) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_pre_hash_internal \ + MLD_NAMESPACE_KL(signature_pre_hash_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_verify_pre_hash_internal \ + MLD_NAMESPACE_KL(verify_pre_hash_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_signature_pre_hash_shake256 \ + MLD_NAMESPACE_KL(signature_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify_pre_hash_shake256 \ + MLD_NAMESPACE_KL(verify_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_7 +#define mld_prepare_domain_separation_prefix \ + MLD_NAMESPACE_KL(prepare_domain_separation_prefix) +#define mld_sign_pk_from_sk \ + MLD_NAMESPACE_KL(pk_from_sk) MLD_CONTEXT_PARAMETERS_2 + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: mld_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: input random seed + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int externalmu: indicates input message m is + * processed as mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return MLD_ERR_FAIL in that case. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires((externalmu == 0 && (prelen == 0 || memory_no_alias(pre, prelen))) || + (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) + ensures(return_value == 0 ==> *siglen == MLDSA_CRYPTO_BYTES) + ensures(return_value != 0 ==> *siglen == 0) +); + +/************************************************* + * Name: mld_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_signature_extmu + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign + * + * Description: Compute signed message. + * + * Arguments: - uint8_t *sm: pointer to output signed message + * (allocated array with MLDSA_CRYPTO_BYTES + + *mlen bytes), can be equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sm, MLDSA_CRYPTO_BYTES + mlen)) + requires(memory_no_alias(smlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sm, MLDSA_CRYPTO_BYTES + mlen)) + assigns(object_whole(smlen)) + ensures((return_value == 0 && *smlen == MLDSA_CRYPTO_BYTES + mlen) || + (return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL)) +); + +/************************************************* + * Name: mld_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as + * mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(externalmu == 0 || (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + requires(externalmu == 1 || prelen == 0 || memory_no_alias(pre, prelen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_open + * + * Description: Verify signed message. + * + * Arguments: - uint8_t *m: pointer to output message (allocated array + * with smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context tring + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(smlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(m, smlen)) + requires(memory_no_alias(mlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(sm, smlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + assigns(memory_slice(m, smlen)) + assigns(memory_slice(mlen, sizeof(size_t))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and + * verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/* Maximum formatted domain separation message length: + * - Pure ML-DSA: 0x00 || ctxlen || ctx (max 255) + * - HashML-DSA: 0x01 || ctxlen || ctx (max 255) || oid (11) || ph (max 64) */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +__contract__( + requires(ctxlen <= 255) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(hashalg == MLD_PREHASH_NONE || memory_no_alias(ph, phlen)) + requires(memory_no_alias(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + assigns(memory_slice(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + ensures(return_value <= MLD_DOMAIN_SEPARATION_MAX_BYTES) +); + +/************************************************* + * Name: mld_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: input secret + * key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); +#endif /* !MLD_SIGN_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/symmetric.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/symmetric.h new file mode 100644 index 0000000000..bb70f05552 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/symmetric.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_SYMMETRIC_H +#define MLD_SYMMETRIC_H + +#include +#include "cbmc.h" +#include "common.h" + +#include MLD_FIPS202_HEADER_FILE +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#include MLD_FIPS202X4_HEADER_FILE +#endif + +#define MLD_STREAM128_BLOCKBYTES SHAKE128_RATE +#define MLD_STREAM256_BLOCKBYTES SHAKE256_RATE + +#define mld_xof256_ctx mld_shake256ctx +#define mld_xof256_init(CTX) mld_shake256_init(CTX) + +#define mld_xof256_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake256_absorb(CTX, IN, INBYTES); \ + mld_shake256_finalize(CTX); \ + } while (0) + + +#define mld_xof256_release(CTX) mld_shake256_release(CTX) +#define mld_xof256_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake256_squeeze(OUT, (OUTBLOCKS) * SHAKE256_RATE, STATE) + +#define mld_xof128_ctx mld_shake128ctx +#define mld_xof128_init(CTX) mld_shake128_init(CTX) + +#define mld_xof128_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake128_absorb(CTX, IN, INBYTES); \ + mld_shake128_finalize(CTX); \ + } while (0) + +#define mld_xof128_release(CTX) mld_shake128_release(CTX) +#define mld_xof128_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake128_squeeze(OUT, (OUTBLOCKS) * SHAKE128_RATE, STATE) + +#define mld_xof256_x4_ctx mld_shake256x4ctx +#define mld_xof256_x4_init(CTX) mld_shake256x4_init((CTX)) +#define mld_xof256_x4_absorb(CTX, IN, INBYTES) \ + mld_shake256x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof256_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake256x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof256_x4_release(CTX) mld_shake256x4_release((CTX)) + +#define mld_xof128_x4_ctx mld_shake128x4ctx +#define mld_xof128_x4_init(CTX) mld_shake128x4_init((CTX)) +#define mld_xof128_x4_absorb(CTX, IN, INBYTES) \ + mld_shake128x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof128_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake128x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof128_x4_release(CTX) mld_shake128x4_release((CTX)) + +#endif /* !MLD_SYMMETRIC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/sys.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/sys.h new file mode 100644 index 0000000000..1226526420 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/sys.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_SYS_H +#define MLD_SYS_H + +#if !defined(MLD_CONFIG_NO_ASM) && (defined(__GNUC__) || defined(__clang__)) +#define MLD_HAVE_INLINE_ASM +#endif + +/* Try to find endianness, if not forced through CFLAGS already */ +#if !defined(MLD_SYS_LITTLE_ENDIAN) && !defined(MLD_SYS_BIG_ENDIAN) +#if defined(__BYTE_ORDER__) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define MLD_SYS_LITTLE_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define MLD_SYS_BIG_ENDIAN +#else +#error "__BYTE_ORDER__ defined, but don't recognize value." +#endif +#endif /* __BYTE_ORDER__ */ + +/* MSVC does not define __BYTE_ORDER__. However, MSVC only supports + * little endian x86, x86_64, and AArch64. It is, hence, safe to assume + * little endian. */ +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_IX86) || defined(_M_ARM64)) +#define MLD_SYS_LITTLE_ENDIAN +#endif + +#endif /* !MLD_SYS_LITTLE_ENDIAN && !MLD_SYS_BIG_ENDIAN */ + +/* Check if we're running on an AArch64 little endian system. _M_ARM64 is set by + * MSVC. */ +#if defined(__AARCH64EL__) || defined(_M_ARM64) +#define MLD_SYS_AARCH64 +#endif + +/* Check if we're running on an AArch64 big endian system. */ +#if defined(__AARCH64EB__) +#define MLD_SYS_AARCH64_EB +#endif + +#if defined(__x86_64__) +#define MLD_SYS_X86_64 +#if defined(__AVX2__) +#define MLD_SYS_X86_64_AVX2 +#endif +#endif /* __x86_64__ */ + +#if defined(MLD_SYS_LITTLE_ENDIAN) && defined(__powerpc64__) +#define MLD_SYS_PPC64LE +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 +#define MLD_SYS_RISCV64 +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32 +#define MLD_SYS_RISCV32 +#endif + +#if defined(_WIN64) || defined(_WIN32) +#define MLD_SYS_WINDOWS +#endif + +#if defined(__linux__) +#define MLD_SYS_LINUX +#endif + +#if defined(__APPLE__) +#define MLD_SYS_APPLE +#endif + +/* If MLD_FORCE_AARCH64 is set, assert that we're indeed on an AArch64 system. + */ +#if defined(MLD_FORCE_AARCH64) && !defined(MLD_SYS_AARCH64) +#error "MLD_FORCE_AARCH64 is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_AARCH64_EB is set, assert that we're indeed on a big endian + * AArch64 system. */ +#if defined(MLD_FORCE_AARCH64_EB) && !defined(MLD_SYS_AARCH64_EB) +#error \ + "MLD_FORCE_AARCH64_EB is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_X86_64 is set, assert that we're indeed on an X86_64 system. */ +#if defined(MLD_FORCE_X86_64) && !defined(MLD_SYS_X86_64) +#error "MLD_FORCE_X86_64 is set, but we don't seem to be on an X86_64 system." +#endif + +#if defined(MLD_FORCE_PPC64LE) && !defined(MLD_SYS_PPC64LE) +#error "MLD_FORCE_PPC64LE is set, but we don't seem to be on a PPC64LE system." +#endif + +#if defined(MLD_FORCE_RISCV64) && !defined(MLD_SYS_RISCV64) +#error "MLD_FORCE_RISCV64 is set, but we don't seem to be on a RISCV64 system." +#endif + +#if defined(MLD_FORCE_RISCV32) && !defined(MLD_SYS_RISCV32) +#error "MLD_FORCE_RISCV32 is set, but we don't seem to be on a RISCV32 system." +#endif + +/* + * MLD_INLINE: Hint for inlining. + * - MSVC: __inline + * - C99+: inline + * - GCC/Clang C90: __attribute__((unused)) to silence warnings + * - Other C90: empty + */ +#if !defined(MLD_INLINE) +#if defined(_MSC_VER) +#define MLD_INLINE __inline +#elif defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +#define MLD_INLINE inline +#elif defined(__GNUC__) || defined(__clang__) +#define MLD_INLINE __attribute__((unused)) +#else +#define MLD_INLINE +#endif +#endif /* !MLD_INLINE */ + +/* + * MLD_ALWAYS_INLINE: Force inlining. + * - MSVC: __forceinline + * - GCC/Clang C99+: MLD_INLINE __attribute__((always_inline)) + * - Other: MLD_INLINE (no forced inlining) + */ +#if !defined(MLD_ALWAYS_INLINE) +#if defined(_MSC_VER) +#define MLD_ALWAYS_INLINE __forceinline +#elif (defined(__GNUC__) || defined(__clang__)) && \ + (defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)) +#define MLD_ALWAYS_INLINE MLD_INLINE __attribute__((always_inline)) +#else +#define MLD_ALWAYS_INLINE MLD_INLINE +#endif +#endif /* !MLD_ALWAYS_INLINE */ + +#ifndef MLD_STATIC_TESTABLE +#define MLD_STATIC_TESTABLE static +#endif + +/* + * C90 does not have the restrict compiler directive yet. + * We don't use it in C90 builds. + */ +#if !defined(restrict) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define MLD_RESTRICT restrict +#else +#define MLD_RESTRICT +#endif + +#else /* !restrict */ + +#define MLD_RESTRICT restrict +#endif /* restrict */ + +#define MLD_DEFAULT_ALIGN 32 +#define MLD_ALIGN_UP(N) \ + ((((N) + (MLD_DEFAULT_ALIGN - 1)) / MLD_DEFAULT_ALIGN) * MLD_DEFAULT_ALIGN) +#if defined(__GNUC__) +#define MLD_ALIGN __attribute__((aligned(MLD_DEFAULT_ALIGN))) +#elif defined(_MSC_VER) +#define MLD_ALIGN __declspec(align(MLD_DEFAULT_ALIGN)) +#else +#define MLD_ALIGN /* No known support for alignment constraints */ +#endif + + +/* New X86_64 CPUs support Conflow-flow protection using the CET instructions. + * When enabled (through -fcf-protection=), all compilation units (including + * empty ones) need to support CET for this to work. + * For assembly, this means that source files need to signal support for + * CET by setting the appropriate note.gnu.property section. + * This can be achieved by including the header in all assembly file. + * This file also provides the _CET_ENDBR macro which needs to be placed at + * every potential target of an indirect branch. + * If CET is enabled _CET_ENDBR maps to the endbr64 instruction, otherwise + * it is empty. + * In case the compiler does not support CET (e.g., +#define MLD_CET_ENDBR _CET_ENDBR +#else +#define MLD_CET_ENDBR +#endif +#endif /* MLD_SYS_X86_64 */ + +#if defined(MLD_CONFIG_CT_TESTING_ENABLED) && !defined(__ASSEMBLER__) +#include +#define MLD_CT_TESTING_SECRET(ptr, len) \ + VALGRIND_MAKE_MEM_UNDEFINED((ptr), (len)) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) +#else /* MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__ */ +#define MLD_CT_TESTING_SECRET(ptr, len) \ + do \ + { \ + } while (0) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + do \ + { \ + } while (0) +#endif /* !(MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__) */ + +#if defined(__GNUC__) || defined(__clang__) +#define MLD_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_MUST_CHECK_RETURN_VALUE +#endif + + +#if !defined(__ASSEMBLER__) +/* System capability enumeration */ +typedef enum +{ + /* x86_64 */ + MLD_SYS_CAP_AVX2, + /* AArch64 */ + MLD_SYS_CAP_SHA3 +} mld_sys_cap; + +#if !defined(MLD_CONFIG_CUSTOM_CAPABILITY_FUNC) +#include "cbmc.h" + +static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) +__contract__( + ensures(return_value == 0 || return_value == 1) +) +{ + /* By default, we rely on compile-time feature detection/specification: + * If a feature is enabled at compile-time, we assume it is supported by + * the host that the resulting library/binary will be built on. + * If this assumption is not true, you MUST overwrite this function. + * See the documentation of MLD_CONFIG_CUSTOM_CAPABILITY_FUNC in + * mldsa_native_config.h for more information. */ + (void)cap; + return 1; +} +#endif /* !MLD_CONFIG_CUSTOM_CAPABILITY_FUNC */ +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_SYS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/zetas.inc b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/zetas.inc new file mode 100644 index 0000000000..dc3cf15dd3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native/src/zetas.inc @@ -0,0 +1,56 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include + +/* + * Table of zeta values used in the reference NTT and inverse NTT. + * See autogen for details. + */ +static const int32_t mld_zetas[MLDSA_N] = { + 0, 25847, -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 2353451, -359251, -2091905, 3119733, -2884855, + 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488, + -1119584, 2619752, -2108549, -2118186, -3859737, -1399561, -3277672, + 1757237, -19422, 4010497, 280005, 2706023, 95776, 3077325, + 3530437, -1661693, -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267, + -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596, + 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, + -2797779, -3930395, -1528703, -3677745, -3041255, -1452451, 3475950, + 2176455, -1585221, -1257611, 1939314, -4083598, -1000202, -3190144, + -3157330, -3632928, 126922, 3412210, -983419, 2147896, 2715295, + -2967645, -3693493, -411027, -2477047, -671102, -1228525, -22981, + -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944, + 508951, 3097992, 44288, -1100098, 904516, 3958618, -3724342, + -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856, + 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, + 1341330, 1285669, -1584928, -812732, -1439742, -3019102, -3881060, + -3628969, 3839961, 2091667, 3407706, 2316500, 3817976, -3342478, + 2244091, -2446433, -3562462, 266997, 2434439, -1235728, 3513181, + -3520352, -3759364, -1197226, -3193378, 900702, 1859098, 909542, + 819034, 495491, -1613174, -43260, -522500, -655327, -3122442, + 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297, + 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, + 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, + 1595974, -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, + 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100, + 1312455, 3306115, -1962642, -1279661, 1917081, -2546312, -1374803, + 1500165, 777191, 2235880, 3406031, -542412, -2831860, -1671176, + -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395, + 2454455, -164721, 1957272, 3369112, 185531, -1207385, -3183426, + 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, + -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, + 472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333, + -260646, -3833893, -2939036, -2235985, -420899, -2286327, 183443, + -976891, 1612842, -3545687, -554416, 3919660, -48306, -1362209, + 3937738, 1400424, -846154, 1976782, +}; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native_all.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native_all.h new file mode 100644 index 0000000000..adcd5bfd73 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/mldsa_native_all.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_ALL_H +#define MLD_ALL_H + + +/* API for MLDSA-44 */ +#define MLD_CONFIG_PARAMETER_SET 44 +#include "mldsa_native/mldsa_native.h" +#undef MLD_CONFIG_PARAMETER_SET +#undef MLD_H + +/* API for MLDSA-65 */ +#define MLD_CONFIG_PARAMETER_SET 65 +#include "mldsa_native/mldsa_native.h" +#undef MLD_CONFIG_PARAMETER_SET +#undef MLD_H + +/* API for MLDSA-87 */ +#define MLD_CONFIG_PARAMETER_SET 87 +#include "mldsa_native/mldsa_native.h" +#undef MLD_CONFIG_PARAMETER_SET +#undef MLD_H + +#endif /* !MLD_ALL_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/test_only_rng/notrandombytes.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/test_only_rng/notrandombytes.c new file mode 100644 index 0000000000..ef5a423a9e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/test_only_rng/notrandombytes.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* * Based on @[surf]*/ + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +#include +#include + +#include "notrandombytes.h" + +#ifdef ENABLE_CT_TESTING +#include +#endif + +static uint32_t seed[32] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, + 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5}; +static uint32_t in[12]; +static uint32_t out[8]; +static int32_t outleft = 0; + +void randombytes_reset(void) +{ + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + outleft = 0; +} + +#define ROTATE(x, b) (((x) << (b)) | ((x) >> (32 - (b)))) +#define MUSH(i, b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x, b)); + +static void surf(void) +{ + uint32_t t[12]; + uint32_t x; + uint32_t sum = 0; + int32_t r; + int32_t i; + int32_t loop; + + for (i = 0; i < 12; ++i) + { + t[i] = in[i] ^ seed[12 + i]; + } + for (i = 0; i < 8; ++i) + { + out[i] = seed[24 + i]; + } + x = t[11]; + for (loop = 0; loop < 2; ++loop) + { + for (r = 0; r < 16; ++r) + { + sum += 0x9e3779b9; + MUSH(0, 5) + MUSH(1, 7) + MUSH(2, 9) + MUSH(3, 13) + MUSH(4, 5) + MUSH(5, 7) + MUSH(6, 9) + MUSH(7, 13) + MUSH(8, 5) + MUSH(9, 7) + MUSH(10, 9) + MUSH(11, 13) + } + for (i = 0; i < 8; ++i) + { + out[i] ^= t[i + 4]; + } + } +} + +int randombytes(uint8_t *buf, size_t n) +{ +#ifdef ENABLE_CT_TESTING + uint8_t *buf_orig = buf; + size_t n_orig = n; +#endif + + while (n > 0) + { + if (!outleft) + { + if (!++in[0]) + { + if (!++in[1]) + { + if (!++in[2]) + { + ++in[3]; + } + } + } + surf(); + outleft = 8; + } + *buf = (uint8_t)out[--outleft]; + ++buf; + --n; + } + +#ifdef ENABLE_CT_TESTING + /* + * Mark all randombytes output as secret (undefined). + * Valgrind will propagate this to everything derived from it. + */ + VALGRIND_MAKE_MEM_UNDEFINED(buf_orig, n_orig); +#endif /* ENABLE_CT_TESTING */ + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/test_only_rng/notrandombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/test_only_rng/notrandombytes.h new file mode 100644 index 0000000000..bdf9787920 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build/test_only_rng/notrandombytes.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* Based on @[surf]. */ + +#ifndef NOTRANDOMBYTES_H +#define NOTRANDOMBYTES_H + +#include +#include + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +void randombytes_reset(void); +int randombytes(uint8_t *buf, size_t n); + +#endif /* !NOTRANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/.gitignore b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/.gitignore new file mode 100644 index 0000000000..eb98a94f12 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +build diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/Makefile new file mode 100644 index 0000000000..e8e8742be4 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/Makefile @@ -0,0 +1,131 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +.PHONY: build run clean mldsa44_objs mldsa65_objs mldsa87_objs mldsa_objs +.DEFAULT_GOAL := all + +Q ?= @ + +CC ?= gcc + +# Adjust CFLAGS if needed +CFLAGS := \ + -Wall \ + -Wextra \ + -Werror=unused-result \ + -Wpedantic \ + -Werror \ + -Wmissing-prototypes \ + -Wshadow \ + -Wpointer-arith \ + -Wredundant-decls \ + -Wconversion \ + -Wsign-conversion \ + -Wno-long-long \ + -Wno-unknown-pragmas \ + -Wno-unused-command-line-argument \ + -O3 \ + -fomit-frame-pointer \ + -Imldsa_native/ \ + -DMLD_CONFIG_NAMESPACE_PREFIX=mldsa \ + -std=c99 \ + -pedantic \ + -MMD \ + $(CFLAGS) + +# If you want to use the native backends, the compiler needs to know about +# the target architecture. Here, we import the default host detection from +# mldsa-native's tests, but you can write your own or specialize accordingly. +AUTO ?= 1 +include auto.mk + +# The following only concerns the cross-compilation tests. +# You can likely ignore the following for your application. +# +# Append cross-prefix for cross compilation +# When called from the root Makefile, CROSS_PREFIX has already been added here +ifeq (,$(findstring $(CROSS_PREFIX),$(CC))) +CC := $(CROSS_PREFIX)$(CC) +endif + +# Part A: +# +# mldsa-native source and header files +# +# In this example, we compile the individual mldsa-native source files directly. +# Alternatively, you can compile the 'monobuild' source file mldsa_native.c. +# See examples/monolithic_build for that. +MLD_SOURCE := $(wildcard \ + mldsa_native/src/*.c \ + mldsa_native/src/**/*.c \ + mldsa_native/src/**/**/*.c \ + mldsa_native/src/**/**/**/*.c \ + mldsa_native/src/**/**/**/**/*.c \ + mldsa_native/src/*.S \ + mldsa_native/src/**/*.S \ + mldsa_native/src/**/**/*.S \ + mldsa_native/src/**/**/**/*.S \ + mldsa_native/src/**/**/**/**/*.S) + +BUILD_DIR=build +MLDSA44_DIR = $(BUILD_DIR)/mldsa44 +MLDSA65_DIR = $(BUILD_DIR)/mldsa65 +MLDSA87_DIR = $(BUILD_DIR)/mldsa87 + +MLDSA44_OBJS=$(patsubst %,$(MLDSA44_DIR)/%.o,$(MLD_SOURCE)) +MLDSA65_OBJS=$(patsubst %,$(MLDSA65_DIR)/%.o,$(MLD_SOURCE)) +MLDSA87_OBJS=$(patsubst %,$(MLDSA87_DIR)/%.o,$(MLD_SOURCE)) + +$(MLDSA44_OBJS): $(MLDSA44_DIR)/%.o: % + $(Q)echo " CC $@" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -DMLD_CONFIG_MULTILEVEL_WITH_SHARED -DMLD_CONFIG_PARAMETER_SET=44 $(CFLAGS) -c $^ -o $@ + +$(MLDSA65_OBJS): $(MLDSA65_DIR)/%.o: % + $(Q)echo " CC $@" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -DMLD_CONFIG_MULTILEVEL_NO_SHARED -DMLD_CONFIG_PARAMETER_SET=65 $(CFLAGS) -c $^ -o $@ + +$(MLDSA87_OBJS): $(MLDSA87_DIR)/%.o: % + $(Q)echo " CC $@" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -DMLD_CONFIG_MULTILEVEL_NO_SHARED -DMLD_CONFIG_PARAMETER_SET=87 $(CFLAGS) -c $^ -o $@ + +mldsa44_objs: $(MLDSA44_OBJS) +mldsa65_objs: $(MLDSA65_OBJS) +mldsa87_objs: $(MLDSA87_OBJS) +mldsa_objs: mldsa44_objs mldsa65_objs mldsa87_objs + +# Part B: +# +# Random number generator +# +# !!! WARNING !!! +# +# The randombytes() implementation used here is for TESTING ONLY. +# You MUST NOT use this implementation outside of testing. +# +# !!! WARNING !!! +RNG_SOURCE=$(wildcard test_only_rng/*.c) + +# Part C: +# +# Your application source code +APP_SOURCE=$(wildcard *.c) + +BIN=test_binary +BINARY_NAME_FULL=$(BUILD_DIR)/$(BIN) + +$(BINARY_NAME_FULL): $(APP_SOURCE) $(RNG_SOURCE) $(MLDSA44_OBJS) $(MLDSA65_OBJS) $(MLDSA87_OBJS) + $(Q)mkdir -p $(BUILD_DIR) + $(Q)$(CC) $(CFLAGS) $^ -o $@ + +all: build + +build: $(BINARY_NAME_FULL) + +run: $(BINARY_NAME_FULL) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL) + +clean: + rm -rf $(BUILD_DIR) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/README.md new file mode 100644 index 0000000000..d253ec8275 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/README.md @@ -0,0 +1,60 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Multi-Level Build (Native Backend) + +This directory contains a minimal example for building mldsa-native with support for all three security levels +(ML-DSA-44, ML-DSA-65, ML-DSA-87), using native backends for optimal performance, with level-independent +code shared to reduce binary size. + +## Use Case + +Use this approach when: +- You need multiple ML-DSA security levels in the same application +- You want optimal performance via native assembly (AArch64/AVX2) +- You want to build the mldsa-native C files separately, not as a single compilation unit. +- You want to minimize code duplication across levels + +## Components + +1. mldsa-native source tree: [`mldsa/src/`](../../mldsa/src), [`mldsa/src/fips202/`](../../mldsa/src/fips202), + and [`mldsa/src/native/`](../../mldsa/src/native) +2. A secure random number generator implementing [`randombytes.h`](../../mldsa/src/randombytes.h) +3. Your application source code + +## Configuration + +The library is built 3 times into separate directories (`build/mldsa44`, `build/mldsa65`, `build/mldsa87`). + +The configuration file [mldsa_native_config.h](mldsa_native/mldsa_native_config.h) sets: +- `MLD_CONFIG_MULTILEVEL_BUILD`: Enables multi-level build mode +- `MLD_CONFIG_NAMESPACE_PREFIX=mldsa`: Base prefix; level suffix added automatically +- `MLD_CONFIG_USE_NATIVE_BACKEND_ARITH`: Enables native arithmetic backend +- `MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202`: Enables native FIPS-202 backend +- `MLD_CONFIG_NO_SUPERCOP`: Disables the SUPERCOP API (crypto_sign*) + +Build-time flags passed via CFLAGS: +- `MLD_CONFIG_PARAMETER_SET=44/65/87`: Selects the security level +- `MLD_CONFIG_MULTILEVEL_WITH_SHARED`: Set for ONE build to include shared code +- `MLD_CONFIG_MULTILEVEL_NO_SHARED`: Set for OTHER builds to exclude shared code + +The resulting API functions are namespaced as: +- `mldsa44_keypair()`, `mldsa44_signature()`, `mldsa44_verify()`, ... +- `mldsa65_keypair()`, `mldsa65_signature()`, `mldsa65_verify()`, ... +- `mldsa87_keypair()`, `mldsa87_signature()`, `mldsa87_verify()`, ... + +## Notes + +- Native backends are auto-selected based on the target architecture +- On unsupported platforms, the build falls back to the C backend + +## Usage + +```bash +make build # Build all three security levels +make run # Run the example +``` + +## Warning + +The `randombytes()` implementation in `test_only_rng/` is for TESTING ONLY. +You MUST provide a cryptographically secure RNG for production use. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/auto.mk b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/auto.mk new file mode 100644 index 0000000000..5f71942085 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/auto.mk @@ -0,0 +1,178 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# Automatically detect system architecture and set preprocessor flags accordingly +# This file detects host CPU capabilities and combines them with compiler support +# to enable optimal compilation flags. +# +# Compiler feature detection can be overridden by setting the corresponding variable +# on the command line: +# make MK_COMPILER_SUPPORTS_SHA3=0 # Disable SHA3 detection +# make MK_COMPILER_SUPPORTS_AVX2=0 # Disable AVX2 detection +# make MK_COMPILER_SUPPORTS_BMI2=0 # Disable BMI2 detection +# make MK_COMPILER_SUPPORTS_SSE2=0 # Disable SSE2 detection + +ifndef _AUTO_MK +_AUTO_MK := + +# Override ARCH for cross-compilation based on CROSS_PREFIX +ifeq ($(CROSS_PREFIX),) +ARCH := $(shell uname -m) +# Normalize architecture names +ifeq ($(ARCH),arm64) +ARCH := aarch64 +endif +else # CROSS_PREFIX +ifneq ($(findstring x86_64, $(CROSS_PREFIX)),) +ARCH := x86_64 +else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),) +ARCH := aarch64_be +else ifneq ($(findstring aarch64, $(CROSS_PREFIX)),) +ARCH := aarch64 +else ifneq ($(findstring riscv64, $(CROSS_PREFIX)),) +ARCH := riscv64 +else ifneq ($(findstring riscv32, $(CROSS_PREFIX)),) +ARCH := riscv32 +else ifneq ($(findstring powerpc64le, $(CROSS_PREFIX)),) +ARCH := powerpc64le +else ifneq ($(findstring arm-none-eabi-, $(CROSS_PREFIX)),) +ARCH := arm +else +ifeq ($(AUTO),1) +$(warning Unknown cross-compilation prefix $(CROSS_PREFIX), no automatic detection of CFLAGS.) +ARCH := unknown +endif +endif +endif # CROSS_PREFIX + +# x86_64 compiler feature detection +ifeq ($(ARCH),x86_64) + +# Test AVX2 support using C with inline assembly +MK_COMPILER_SUPPORTS_AVX2 ?= $(shell echo 'int main() { __asm__("vpxor %%ymm0, %%ymm1, %%ymm2" ::: "ymm0", "ymm1", "ymm2"); return 0; }' | $(CC) -mavx2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test SSE2 support using C with inline assembly +MK_COMPILER_SUPPORTS_SSE2 ?= $(shell echo 'int main() { __asm__("pxor %%xmm0, %%xmm1" ::: "xmm0", "xmm1"); return 0; }' | $(CC) -msse2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +# Test BMI2 support using C with inline assembly +MK_COMPILER_SUPPORTS_BMI2 ?= $(shell echo 'int main() { __asm__("pdep %%eax, %%ebx, %%ecx" ::: "eax", "ebx", "ecx"); return 0; }' | $(CC) -mbmi2 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # x86_64 compiler detection + +# AArch64 compiler feature detection +ifeq ($(ARCH),aarch64) + +# Test SHA3 support (Armv8.4-a+SHA3) using C with inline assembly +MK_COMPILER_SUPPORTS_SHA3 ?= $(shell echo 'int main() { __asm__("eor3 v0.16b, v1.16b, v2.16b, v3.16b" ::: "v0", "v1", "v2", "v3"); return 0; }' | $(CC) -march=armv8.4-a+sha3 -x c - -c -o /dev/null 2>/dev/null && echo 1 || echo 0) + +endif # aarch64 compiler detection + +# Define HOST_PLATFORM if not already defined +HOST_PLATFORM ?= $(shell uname -s)-$(shell uname -m) + +# Helper function to check if host CPU supports a feature +# Usage: $(call check_host_feature,feature_pattern,source_command) +define check_host_feature +$(shell $(2) 2>/dev/null | grep -q "$(1)" && echo 1 || echo 0) +endef + +# x86_64 architecture detection +ifeq ($(ARCH),x86_64) + +# Host CPU feature detection for x86_64 +ifeq ($(HOST_PLATFORM),Linux-x86_64) +# Linux: Use /proc/cpuinfo +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,avx2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,sse2,cat /proc/cpuinfo) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,bmi2,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-x86_64) +# macOS: Use sysctl +MK_HOST_SUPPORTS_AVX2 := $(call check_host_feature,AVX2,sysctl -n machdep.cpu.leaf7_features) +MK_HOST_SUPPORTS_SSE2 := $(call check_host_feature,SSE2,sysctl -n machdep.cpu.features) +MK_HOST_SUPPORTS_BMI2 := $(call check_host_feature,BMI2,sysctl -n machdep.cpu.leaf7_features) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_AVX2 := 1 +MK_HOST_SUPPORTS_SSE2 := 1 +MK_HOST_SUPPORTS_BMI2 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_AVX2 := 0 +MK_HOST_SUPPORTS_SSE2 := 0 +MK_HOST_SUPPORTS_BMI2 := 0 +endif # HOST_PLATFORM x86_64 + +endif # x86_64 + +# AArch64 architecture detection +ifeq ($(ARCH),aarch64) + +# Host CPU feature detection for AArch64 +ifeq ($(HOST_PLATFORM),Linux-aarch64) +# Linux: Use /proc/cpuinfo (look for sha3 in Features line) +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,sha3,cat /proc/cpuinfo) +else ifeq ($(HOST_PLATFORM),Darwin-arm64) +# macOS: Use sysctl to check for SHA3 support +MK_HOST_SUPPORTS_SHA3 := $(call check_host_feature,1,sysctl -n hw.optional.armv8_2_sha3) +else ifneq ($(CROSS_PREFIX),) +# Cross-compilation: assume all features are supported +MK_HOST_SUPPORTS_SHA3 := 1 +else +# Other platforms: assume no support +MK_HOST_SUPPORTS_SHA3 := 0 +endif # HOST_PLATFORM aarch64 + +endif # aarch64 + +# Only apply CFLAGS modifications if AUTO=1 +ifeq ($(AUTO),1) + +# x86_64 CFLAGS configuration +ifeq ($(ARCH),x86_64) +CFLAGS += -DMLD_FORCE_X86_64 + +# Add flags only if both compiler and host support the feature +ifeq ($(MK_COMPILER_SUPPORTS_AVX2)$(MK_HOST_SUPPORTS_AVX2),11) +CFLAGS += -mavx2 +endif + +ifeq ($(MK_COMPILER_SUPPORTS_BMI2)$(MK_HOST_SUPPORTS_BMI2),11) +CFLAGS += -mbmi2 +endif +endif # x86_64 + +# AArch64 CFLAGS configuration +ifeq ($(ARCH),aarch64) +CFLAGS += -DMLD_FORCE_AARCH64 + +# Add SHA3 flags only if both compiler and host support it +ifeq ($(MK_COMPILER_SUPPORTS_SHA3)$(MK_HOST_SUPPORTS_SHA3),11) +CFLAGS += -march=armv8.4-a+sha3 +endif +endif # aarch64 + +# AArch64 Big Endian CFLAGS configuration +ifeq ($(ARCH),aarch64_be) +CFLAGS += -DMLD_FORCE_AARCH64_EB +endif # aarch64_be + +# RISC-V 64-bit CFLAGS configuration +ifeq ($(ARCH),riscv64) +CFLAGS += -DMLD_FORCE_RISCV64 +CFLAGS += -march=rv64gcv +endif # riscv64 + +# RISC-V 32-bit CFLAGS configuration +ifeq ($(ARCH),riscv32) +CFLAGS += -DMLD_FORCE_RISCV32 +endif # riscv32 + +# PowerPC 64-bit Little Endian CFLAGS configuration +ifeq ($(ARCH),powerpc64le) +CFLAGS += -DMLD_FORCE_PPC64LE +endif # powerpc64le + +endif # AUTO=1 + +endif # _AUTO_MK diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/expected_signatures.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/expected_signatures.h new file mode 100644 index 0000000000..582c6309d4 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/expected_signatures.h @@ -0,0 +1,886 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef EXPECTED_SIGNATURES_H +#define EXPECTED_SIGNATURES_H + +#include + +/* Expected deterministic signatures for each parameter set + * These are generated using the same test message, context, and deterministic + * RNG as used in the basic example. + * + * The PCT modifies the PRNG state, so the KAT tests don't work. + * We run KAT tests only for disabled PCT. */ +#if !defined(MLD_CONFIG_KEYGEN_PCT) +const uint8_t expected_signature_44[] = { + 0x27, 0x5e, 0xbe, 0x2d, 0x23, 0x1a, 0x76, 0xc5, 0xd9, 0x77, 0xcb, 0x62, + 0x25, 0x04, 0xdb, 0x23, 0x31, 0xa9, 0xa8, 0xcd, 0xbc, 0xde, 0xf2, 0x20, + 0xfd, 0xa7, 0xb5, 0xf5, 0x59, 0xae, 0xe6, 0xdd, 0x62, 0xfa, 0x34, 0x96, + 0x4f, 0x1d, 0xcd, 0x84, 0x82, 0xee, 0xc1, 0x74, 0x96, 0x3d, 0x98, 0xd9, + 0x42, 0x9d, 0xd0, 0x77, 0x9c, 0xf9, 0x9e, 0x0e, 0xa7, 0xcb, 0x70, 0xeb, + 0xe7, 0xcd, 0xce, 0x8c, 0xdc, 0x37, 0x15, 0x95, 0x0e, 0x24, 0x70, 0x4f, + 0x33, 0x6e, 0x4f, 0xad, 0xed, 0x4d, 0xf3, 0xe5, 0x38, 0xc1, 0xcd, 0xbb, + 0xde, 0xf1, 0xd2, 0x0d, 0xd6, 0x6b, 0xa3, 0x68, 0x92, 0x4c, 0x4b, 0x4f, + 0x89, 0xa0, 0xa8, 0xc8, 0x36, 0x93, 0x91, 0x17, 0xe7, 0x16, 0xed, 0xcb, + 0xdc, 0xf6, 0x28, 0x13, 0x32, 0x60, 0x14, 0xe0, 0x28, 0x7a, 0x69, 0x05, + 0x1d, 0xf7, 0x3b, 0xdf, 0x18, 0x0c, 0xaf, 0xba, 0x46, 0xf1, 0x5e, 0xd4, + 0xd3, 0xd0, 0x8e, 0x9a, 0xe2, 0xac, 0xdd, 0x0e, 0x5f, 0xb1, 0x69, 0xe2, + 0x74, 0x77, 0x2e, 0x52, 0xf9, 0x11, 0x3d, 0xd8, 0xe5, 0x36, 0x6f, 0x7d, + 0x7d, 0xde, 0x7c, 0xa7, 0x1d, 0x37, 0xdf, 0x6d, 0x5e, 0xea, 0xc8, 0xc0, + 0x72, 0x3f, 0x79, 0xbd, 0x0b, 0x6d, 0x7f, 0x9a, 0x15, 0x90, 0xda, 0xc1, + 0xae, 0xce, 0xf3, 0x44, 0x35, 0x5e, 0x83, 0x86, 0x7e, 0x89, 0x18, 0xa7, + 0x97, 0x8e, 0x87, 0x7c, 0x15, 0xd2, 0xd2, 0x7e, 0xf2, 0xc8, 0x29, 0x4f, + 0x70, 0x0f, 0xa6, 0xd4, 0x76, 0xe8, 0xdd, 0x7d, 0x7a, 0x2d, 0xfe, 0x0a, + 0x0c, 0x5c, 0xb1, 0xef, 0xec, 0x1a, 0x32, 0xca, 0x87, 0xff, 0x6b, 0xb1, + 0xa0, 0xe1, 0x2e, 0x01, 0x52, 0xb2, 0xb8, 0x74, 0x34, 0xb3, 0xfb, 0x15, + 0x0f, 0x17, 0xca, 0x74, 0xc1, 0xc1, 0x61, 0x86, 0x40, 0x38, 0x58, 0xba, + 0x82, 0x26, 0x66, 0x33, 0xa4, 0x52, 0xf3, 0xb5, 0x36, 0x60, 0xd8, 0x5a, + 0x8d, 0x9d, 0x28, 0x18, 0x3a, 0x68, 0x34, 0x2a, 0xa2, 0xe2, 0xb5, 0x39, + 0xed, 0x7d, 0xe5, 0xbe, 0x46, 0xb9, 0x04, 0x0c, 0xf3, 0xef, 0x88, 0x6e, + 0x9d, 0x6f, 0x23, 0xe2, 0x44, 0xe5, 0x2e, 0x3a, 0x7a, 0x1d, 0x49, 0x0f, + 0xdd, 0xcd, 0xd6, 0x4e, 0x0d, 0x0b, 0xc3, 0x35, 0xf2, 0xd1, 0x5d, 0x73, + 0x5d, 0x07, 0xca, 0x5c, 0xbd, 0x14, 0xec, 0x57, 0xb3, 0xbd, 0x37, 0xe7, + 0xdf, 0x06, 0x7d, 0xe0, 0x58, 0x4a, 0xcf, 0x7a, 0xc5, 0xa7, 0x24, 0x62, + 0x6f, 0x09, 0x75, 0x69, 0x74, 0x7f, 0xdf, 0xc8, 0x69, 0x5c, 0x20, 0x10, + 0x3a, 0xe8, 0x01, 0x12, 0xa3, 0xfb, 0xda, 0x4c, 0x3a, 0x0d, 0x3c, 0x3e, + 0x26, 0xe0, 0xa6, 0x7f, 0xb2, 0x6b, 0x0b, 0x68, 0x0a, 0x68, 0x86, 0xb1, + 0xfa, 0x61, 0x3a, 0xe8, 0x77, 0xdc, 0x42, 0xf7, 0xf4, 0x39, 0x9a, 0x40, + 0x58, 0x71, 0xc7, 0x0f, 0xf4, 0x0e, 0xc5, 0x1e, 0xe0, 0x28, 0x45, 0x7d, + 0xba, 0x84, 0xe4, 0x34, 0x69, 0xf9, 0xa5, 0x8a, 0x80, 0x43, 0xc0, 0x8d, + 0x04, 0x33, 0x43, 0xb8, 0xd7, 0x5d, 0x93, 0xed, 0x0f, 0x31, 0x6a, 0x4d, + 0xbf, 0xb7, 0x44, 0x41, 0x1b, 0xd4, 0xac, 0x9d, 0x83, 0x66, 0x08, 0x92, + 0xad, 0x3c, 0x0e, 0x1a, 0xe8, 0xd4, 0xe1, 0x5c, 0x63, 0xcf, 0x27, 0x48, + 0x5a, 0x8f, 0xc5, 0x6f, 0x83, 0x6b, 0x6f, 0xe8, 0xda, 0x1f, 0xba, 0xe9, + 0x7e, 0x11, 0xab, 0x8b, 0x4e, 0xc1, 0x9e, 0x23, 0x69, 0x1f, 0x42, 0x40, + 0xad, 0xbb, 0xfb, 0x4f, 0xe2, 0x50, 0xc9, 0x46, 0xe7, 0x15, 0x15, 0xf8, + 0x61, 0x09, 0x2a, 0x0b, 0x37, 0x43, 0xd4, 0x98, 0x5f, 0xc8, 0x4d, 0x06, + 0xe7, 0x0c, 0x3f, 0x83, 0x59, 0xd5, 0xcd, 0x2d, 0xde, 0x1e, 0x3a, 0x87, + 0x4e, 0xf7, 0x0a, 0x3c, 0x84, 0x72, 0x47, 0x11, 0x02, 0x6c, 0xe8, 0x93, + 0xcd, 0x24, 0xe9, 0x23, 0x86, 0x78, 0x53, 0xe0, 0xc6, 0x2f, 0xba, 0xa7, + 0xed, 0xaf, 0xba, 0x42, 0x80, 0x0d, 0xe6, 0xae, 0xda, 0xed, 0xbc, 0x65, + 0x21, 0x6d, 0x13, 0x90, 0x61, 0xb4, 0x05, 0x7b, 0x07, 0x86, 0xd7, 0x89, + 0x30, 0x9c, 0xc1, 0x9a, 0x41, 0x4d, 0xe8, 0x2b, 0x35, 0x21, 0x3a, 0x8a, + 0x60, 0x83, 0x1a, 0x97, 0x10, 0x98, 0xb6, 0xe1, 0x6b, 0xb5, 0xb1, 0xa1, + 0x36, 0x34, 0x60, 0x1b, 0x96, 0x5d, 0x1f, 0x2a, 0xd8, 0xf2, 0x94, 0xdd, + 0x58, 0x3d, 0x0f, 0xbe, 0x9d, 0xfc, 0xf5, 0x24, 0xb1, 0xd2, 0xc3, 0x36, + 0xef, 0xdb, 0x8e, 0x97, 0x3c, 0x9a, 0x4f, 0x48, 0xe3, 0x84, 0x91, 0xd8, + 0x39, 0x91, 0xf6, 0x55, 0xeb, 0x62, 0x51, 0x3d, 0x8f, 0x55, 0x60, 0x5e, + 0x00, 0xe0, 0xd2, 0xc7, 0x66, 0x51, 0xf1, 0xe2, 0xb7, 0x43, 0xc3, 0xe6, + 0x12, 0x9a, 0xe5, 0x84, 0xe0, 0x10, 0x76, 0xc7, 0x75, 0x6e, 0xa6, 0xee, + 0x11, 0xe4, 0xaf, 0xbd, 0x8a, 0x4f, 0x1d, 0x05, 0x29, 0x4f, 0xce, 0xa5, + 0x73, 0x92, 0x57, 0x7e, 0x0d, 0x11, 0xbc, 0xf8, 0x74, 0x4d, 0xf7, 0xb9, + 0x40, 0x0d, 0x5a, 0xa1, 0x19, 0x76, 0x4a, 0xae, 0x21, 0x16, 0xd4, 0x3f, + 0x76, 0xbf, 0x27, 0xbd, 0x2f, 0xe4, 0x25, 0x21, 0x00, 0x4e, 0xcc, 0x7c, + 0xc6, 0x57, 0xa4, 0xbf, 0xf1, 0x56, 0x90, 0xe0, 0xa4, 0xa3, 0xee, 0xcf, + 0x43, 0x4f, 0xda, 0x77, 0x47, 0x51, 0x79, 0x6a, 0x29, 0xb4, 0x2c, 0xdf, + 0xca, 0x47, 0xcb, 0xb8, 0x82, 0x7e, 0x44, 0x62, 0x9b, 0x8f, 0x61, 0x7b, + 0x3a, 0x93, 0x82, 0x1f, 0x69, 0xb7, 0xb1, 0xa6, 0x2c, 0xe1, 0xb2, 0x65, + 0xa0, 0x6d, 0x6f, 0xe4, 0x79, 0xd8, 0x30, 0xe0, 0xee, 0xd8, 0x83, 0x01, + 0xb2, 0x1f, 0x5c, 0x90, 0x44, 0x86, 0x48, 0x11, 0xf9, 0x11, 0xff, 0xea, + 0x45, 0x43, 0xae, 0x8a, 0x6b, 0x99, 0xf2, 0x1f, 0x02, 0x51, 0x4a, 0x35, + 0x02, 0x34, 0xd3, 0xe8, 0xda, 0xb1, 0x4b, 0xe3, 0xa5, 0x60, 0xce, 0x67, + 0xe3, 0x62, 0x59, 0xfc, 0x00, 0x0a, 0xe2, 0xfe, 0x7b, 0x1e, 0xe6, 0xf5, + 0x75, 0x19, 0x9b, 0x5e, 0xcb, 0xe6, 0xf5, 0x80, 0x9e, 0x3c, 0xb8, 0x54, + 0xd6, 0x0b, 0xfd, 0x48, 0xe0, 0xfa, 0x82, 0x2b, 0x5b, 0x26, 0xf9, 0x49, + 0xaf, 0xbe, 0x9c, 0x78, 0x73, 0xce, 0xc5, 0x65, 0xe2, 0x94, 0x2b, 0xd9, + 0xd0, 0x27, 0x3a, 0x66, 0x3e, 0xe2, 0xe0, 0x10, 0x79, 0x3d, 0xde, 0xc8, + 0x47, 0xdb, 0x1e, 0xc3, 0xe7, 0x51, 0xae, 0x59, 0xeb, 0x38, 0x66, 0x63, + 0x40, 0x8f, 0xbe, 0x1e, 0xb2, 0x2b, 0xeb, 0x64, 0x5f, 0xdd, 0x24, 0xc4, + 0x5a, 0x25, 0x59, 0xa2, 0xda, 0x4f, 0xdf, 0xf8, 0xb0, 0xb0, 0xf7, 0xcd, + 0x1f, 0x14, 0xcd, 0x09, 0x48, 0x70, 0x27, 0x1b, 0xde, 0xc4, 0xf0, 0xf3, + 0x56, 0x97, 0x8a, 0xb7, 0xf4, 0x19, 0x76, 0xe3, 0x9a, 0x33, 0x55, 0xfe, + 0x93, 0x68, 0xca, 0x1f, 0x3d, 0x44, 0x86, 0x39, 0x5d, 0x84, 0x58, 0x50, + 0xf2, 0xf1, 0xea, 0x4a, 0x5c, 0x1c, 0x74, 0xf0, 0x4b, 0xa5, 0x9c, 0x30, + 0xa0, 0x14, 0x1a, 0x80, 0xe0, 0xde, 0x3e, 0xae, 0x7f, 0x10, 0x18, 0x4a, + 0x1e, 0x9e, 0x6b, 0x75, 0x1a, 0xca, 0x08, 0x4e, 0x61, 0x72, 0x43, 0x9b, + 0x18, 0x4d, 0x2c, 0xd8, 0xb4, 0xc9, 0xea, 0x00, 0xb0, 0xdf, 0x1b, 0xcb, + 0x03, 0xc3, 0x7a, 0x27, 0xff, 0x41, 0x9d, 0xf9, 0xfd, 0xb3, 0x0c, 0xc0, + 0x48, 0x5d, 0x7c, 0xae, 0x5a, 0x72, 0x69, 0x93, 0x68, 0xe1, 0x9e, 0x9f, + 0x1f, 0x5c, 0x0a, 0x60, 0x90, 0x1a, 0x8e, 0x5a, 0x30, 0xd4, 0x2c, 0xbd, + 0xe1, 0x20, 0x51, 0xbc, 0x1c, 0x50, 0xb5, 0xf7, 0x42, 0x23, 0x35, 0x0f, + 0x92, 0xe2, 0xbb, 0x2a, 0x04, 0xa7, 0xde, 0x2e, 0x25, 0xfa, 0xed, 0x20, + 0x83, 0x9c, 0xd4, 0x56, 0xe0, 0x4d, 0x8d, 0x79, 0xa5, 0xa0, 0x6f, 0x49, + 0x62, 0x82, 0x9a, 0xa7, 0x4e, 0x54, 0x95, 0x0a, 0xc6, 0x5e, 0x27, 0x65, + 0x6d, 0x11, 0x2b, 0x35, 0x72, 0x34, 0x48, 0xd2, 0xe4, 0x9e, 0x07, 0x7d, + 0x03, 0x27, 0x15, 0x93, 0x55, 0x5c, 0x32, 0x43, 0xdb, 0x34, 0x8d, 0xbd, + 0x8d, 0x88, 0xa5, 0x24, 0x07, 0x93, 0x89, 0x37, 0xb9, 0x17, 0x15, 0xad, + 0xc7, 0x68, 0x86, 0x63, 0x0f, 0x10, 0x53, 0x8f, 0x40, 0xd3, 0x7b, 0x22, + 0x2b, 0x1a, 0x4c, 0xcb, 0x4f, 0x51, 0xf1, 0x3b, 0x19, 0xb8, 0x42, 0x53, + 0xaf, 0xf6, 0xb9, 0x57, 0x7f, 0xba, 0x8d, 0xb8, 0xb7, 0x3b, 0xe3, 0xc5, + 0xab, 0x4a, 0x26, 0x21, 0x6e, 0xce, 0x27, 0xb8, 0xc3, 0x99, 0x56, 0x14, + 0xdd, 0x5b, 0x61, 0x82, 0xbf, 0xd3, 0xc8, 0x76, 0xee, 0x22, 0xaf, 0x21, + 0x21, 0x1d, 0x4e, 0x33, 0xb5, 0x43, 0x3a, 0xfb, 0x91, 0xa0, 0xaa, 0xe3, + 0x10, 0x4a, 0x50, 0x42, 0xd4, 0x5f, 0x92, 0x0e, 0x71, 0x60, 0x4f, 0xaa, + 0xef, 0x66, 0x45, 0xfe, 0xf7, 0xc8, 0xb0, 0x73, 0x75, 0x91, 0x0b, 0x86, + 0x40, 0xa5, 0x02, 0x28, 0xf7, 0xe0, 0x1f, 0x5d, 0xe6, 0xe3, 0xa4, 0x57, + 0xbd, 0x29, 0xaa, 0x53, 0xae, 0x35, 0x30, 0x78, 0x73, 0xd6, 0xb7, 0x01, + 0x9d, 0x13, 0x50, 0xf6, 0x39, 0xa2, 0x3e, 0x03, 0x04, 0xaa, 0x6d, 0xcf, + 0x6b, 0xff, 0x9a, 0xbe, 0x3e, 0x0a, 0xd4, 0x20, 0xce, 0x42, 0x1f, 0xca, + 0x2f, 0xd3, 0x2c, 0xd1, 0xf4, 0xd2, 0x50, 0xd3, 0xa2, 0xc1, 0x1e, 0x87, + 0xbf, 0xeb, 0xb8, 0xa8, 0xd4, 0x1c, 0x96, 0xb8, 0x8e, 0xbe, 0x35, 0x5f, + 0x08, 0x28, 0x20, 0x2b, 0xdc, 0xa4, 0xf5, 0xf6, 0xde, 0xca, 0x1e, 0xcb, + 0x93, 0x3b, 0x64, 0x79, 0x00, 0x3c, 0x8d, 0xbb, 0x5c, 0x7a, 0x40, 0x14, + 0x58, 0x12, 0xa4, 0xf7, 0x6e, 0x51, 0xfb, 0xe7, 0x6f, 0x49, 0x5b, 0xc2, + 0xc9, 0x05, 0x38, 0x9c, 0x08, 0x78, 0x71, 0x27, 0x2b, 0xf5, 0xbf, 0xd6, + 0x38, 0xaa, 0x45, 0xe1, 0xe1, 0x4c, 0xfb, 0xfd, 0xb7, 0xe6, 0xcf, 0xad, + 0x9e, 0x56, 0xaf, 0x12, 0x12, 0x98, 0xe6, 0x38, 0xaa, 0xee, 0xdb, 0x9e, + 0xca, 0xe1, 0x79, 0x6d, 0x44, 0xfb, 0x19, 0x50, 0x92, 0x00, 0x06, 0x2c, + 0x24, 0x71, 0x6c, 0x34, 0x45, 0xac, 0xf9, 0x82, 0x66, 0xa8, 0x63, 0x80, + 0xa8, 0x5b, 0x21, 0x3c, 0x36, 0x71, 0x93, 0x40, 0x7b, 0xff, 0xa2, 0xd0, + 0x72, 0xb4, 0x66, 0xfa, 0xfc, 0xa0, 0xee, 0xca, 0x15, 0x73, 0x52, 0xe7, + 0x9d, 0x11, 0xd3, 0xbc, 0xab, 0x37, 0x31, 0x0e, 0xaf, 0xdc, 0x05, 0x30, + 0x79, 0x8c, 0x25, 0x75, 0x5c, 0x60, 0xc7, 0x9a, 0xfc, 0x88, 0xea, 0xe6, + 0x09, 0x9f, 0xd1, 0x4f, 0x13, 0xf4, 0x41, 0x54, 0x5b, 0x7a, 0xe4, 0x49, + 0x3c, 0x0f, 0x15, 0xe9, 0xa4, 0x85, 0xb2, 0x92, 0x07, 0xea, 0xea, 0x7c, + 0xc1, 0x6d, 0xa9, 0x03, 0xb3, 0x31, 0xce, 0x1e, 0x82, 0xca, 0x9e, 0x3c, + 0x88, 0x88, 0xc1, 0x04, 0x5f, 0xbe, 0xd5, 0x94, 0x0d, 0x67, 0x98, 0x27, + 0xd0, 0x0f, 0x43, 0xf3, 0xb3, 0xfc, 0xff, 0x24, 0xa2, 0x1e, 0x17, 0x06, + 0xb0, 0x52, 0x16, 0x7c, 0xd8, 0x49, 0x74, 0x51, 0xcf, 0x2d, 0x36, 0x16, + 0xb0, 0x88, 0xb2, 0x2b, 0x1d, 0x72, 0x70, 0xab, 0xe2, 0xf6, 0x5f, 0xa5, + 0x2d, 0x4e, 0xd1, 0x42, 0x3c, 0x83, 0x84, 0xb2, 0x56, 0xeb, 0x8d, 0xce, + 0x33, 0x46, 0xdb, 0x3d, 0x4f, 0x97, 0xea, 0x37, 0x5e, 0x0d, 0xd7, 0x4c, + 0x9a, 0x7e, 0xc9, 0x0e, 0x69, 0x4d, 0x97, 0x15, 0x1e, 0x09, 0xbe, 0x7e, + 0xff, 0xe8, 0xf5, 0xab, 0xe9, 0xe7, 0xed, 0x4b, 0x41, 0xa5, 0xf2, 0x2a, + 0x24, 0x48, 0x8b, 0x72, 0x4b, 0x9d, 0xcf, 0x45, 0xdb, 0xc0, 0xaf, 0xa8, + 0x0f, 0x0f, 0x67, 0x37, 0xd3, 0x8b, 0xe1, 0x67, 0x90, 0xd8, 0x1c, 0x58, + 0x36, 0x46, 0x51, 0x52, 0xea, 0xb4, 0x75, 0xb1, 0xcd, 0xc5, 0x39, 0x16, + 0xe0, 0xec, 0x16, 0xf7, 0xf8, 0x0f, 0x5d, 0x13, 0x84, 0x62, 0x34, 0x86, + 0x42, 0x05, 0xa8, 0x08, 0x84, 0xa9, 0x77, 0x12, 0xc1, 0x56, 0xdd, 0x28, + 0xde, 0x39, 0x33, 0x21, 0x3d, 0xbd, 0x94, 0xce, 0xe4, 0xb3, 0x17, 0x9b, + 0x09, 0x20, 0xf0, 0x25, 0xce, 0x00, 0x34, 0x8e, 0x12, 0x94, 0x74, 0x0b, + 0x16, 0xa1, 0x60, 0x76, 0x24, 0xf0, 0xbf, 0xe3, 0x3a, 0x83, 0x8f, 0x40, + 0x47, 0x2e, 0x1c, 0xd5, 0x35, 0x25, 0x87, 0xb3, 0x11, 0xdc, 0x98, 0xb0, + 0xa6, 0x5f, 0x6a, 0x05, 0x1d, 0x06, 0x8d, 0xe8, 0xb0, 0x98, 0xf0, 0x43, + 0x29, 0x84, 0xe4, 0xef, 0x34, 0x67, 0x74, 0x64, 0xe8, 0xb8, 0xf0, 0xd4, + 0x9e, 0xc1, 0x3f, 0x5f, 0xeb, 0xe0, 0x9b, 0x37, 0xf8, 0x75, 0x46, 0x47, + 0xa5, 0x3e, 0x42, 0x20, 0x50, 0xc4, 0x5d, 0xf3, 0xdf, 0x4e, 0xf8, 0x0e, + 0x1e, 0x15, 0x10, 0x3e, 0xf1, 0x68, 0xad, 0x87, 0xad, 0xe5, 0x45, 0x5e, + 0x22, 0xba, 0x2e, 0x51, 0xa0, 0xbf, 0xdc, 0x87, 0xca, 0xe4, 0x1f, 0x2f, + 0x2c, 0xae, 0xa9, 0x14, 0xd7, 0xdd, 0x01, 0xa8, 0x4f, 0x43, 0xcb, 0x84, + 0x92, 0xbf, 0xf9, 0x3d, 0xf0, 0x6b, 0x19, 0x43, 0xb0, 0xdf, 0xff, 0x94, + 0x76, 0xe2, 0x84, 0xf9, 0x31, 0x88, 0x7e, 0xc6, 0x87, 0x58, 0xbe, 0x5d, + 0x8b, 0xf8, 0xb5, 0xdc, 0x95, 0x16, 0x5f, 0xa1, 0x2c, 0xe8, 0x53, 0x36, + 0x64, 0xf5, 0x5d, 0xa0, 0x74, 0x12, 0x78, 0x59, 0x73, 0x69, 0x5a, 0x2b, + 0x36, 0x4a, 0xff, 0x5b, 0xef, 0x49, 0x2c, 0xb2, 0x9e, 0x59, 0xf0, 0x39, + 0x56, 0xe1, 0xd0, 0x1a, 0x05, 0xb2, 0x7c, 0xd1, 0x40, 0x09, 0xdf, 0x00, + 0xc9, 0x15, 0x53, 0xa2, 0xda, 0x84, 0xb5, 0x85, 0x05, 0x76, 0xa6, 0x1b, + 0xcb, 0x06, 0xb2, 0xc8, 0xa0, 0xc5, 0x23, 0x8f, 0xb0, 0xe8, 0xf5, 0xd9, + 0xd0, 0x19, 0x29, 0xfe, 0x2d, 0x9a, 0x57, 0x76, 0x5f, 0xf2, 0xef, 0x71, + 0x16, 0xee, 0x28, 0x7b, 0xe4, 0x48, 0xeb, 0xda, 0xe0, 0xd5, 0xbc, 0x0e, + 0x46, 0x6b, 0x06, 0x5d, 0xe5, 0x91, 0x2d, 0xcb, 0xc4, 0x53, 0xa6, 0x16, + 0xd5, 0xe7, 0xd8, 0xf1, 0xdd, 0x4f, 0xbb, 0xcc, 0x55, 0x67, 0x19, 0x98, + 0x94, 0x95, 0x5e, 0xd6, 0xf5, 0xf7, 0xe8, 0x6a, 0xf7, 0x20, 0x86, 0x3a, + 0x43, 0xbf, 0xe9, 0xec, 0x6b, 0x33, 0x49, 0x19, 0x43, 0xfb, 0xeb, 0x3f, + 0xf4, 0x9d, 0x29, 0x66, 0xb9, 0x6e, 0xb5, 0x15, 0x4b, 0x8d, 0x3c, 0x3c, + 0xfa, 0xf2, 0x87, 0xba, 0x61, 0x11, 0x40, 0xe6, 0xb4, 0x6f, 0xf5, 0xe1, + 0x24, 0x32, 0x69, 0x3e, 0xff, 0xf7, 0xbc, 0xee, 0x82, 0xf2, 0x9e, 0x6d, + 0x3f, 0x6c, 0xcc, 0x0f, 0x4f, 0xc3, 0xf1, 0xdb, 0x1e, 0x81, 0xd7, 0x9b, + 0x22, 0xa8, 0xa7, 0x36, 0x6d, 0xa9, 0x6f, 0x46, 0x1a, 0xa7, 0xff, 0x00, + 0x4b, 0xd8, 0xab, 0xe7, 0x50, 0x3b, 0xe9, 0xc0, 0x57, 0xec, 0x8d, 0x0c, + 0xa0, 0xee, 0x8c, 0x2a, 0x74, 0xf2, 0x94, 0xf9, 0x0c, 0x20, 0x14, 0xd9, + 0xad, 0x0d, 0x4e, 0xac, 0x35, 0x44, 0x59, 0x28, 0x24, 0x31, 0x32, 0xaa, + 0x6d, 0xc2, 0x13, 0xb9, 0xee, 0x75, 0x0c, 0x5f, 0x39, 0xef, 0x31, 0xca, + 0x28, 0x48, 0x56, 0x59, 0xfb, 0xa8, 0xd8, 0x2b, 0x70, 0x61, 0x22, 0x43, + 0x43, 0xb9, 0x60, 0x44, 0xeb, 0xf8, 0x98, 0x87, 0x25, 0x84, 0xa2, 0xaa, + 0x37, 0xd4, 0xb8, 0xd6, 0x3d, 0xa3, 0xa1, 0x4a, 0x81, 0xc2, 0xa9, 0xea, + 0xa2, 0xd6, 0x63, 0x76, 0x50, 0xeb, 0xcd, 0x19, 0x40, 0xb1, 0x7c, 0xf6, + 0xc1, 0x44, 0x01, 0x25, 0xe0, 0xdd, 0xb8, 0x39, 0xef, 0x46, 0x3d, 0x50, + 0x33, 0xed, 0xb1, 0x63, 0x65, 0xd7, 0x50, 0xe7, 0x95, 0xba, 0xab, 0xa7, + 0x14, 0xe5, 0x60, 0xcb, 0x81, 0x6e, 0x88, 0x3c, 0x06, 0x6e, 0x7d, 0x8e, + 0xe7, 0xbb, 0xa5, 0xc2, 0xbd, 0xae, 0x46, 0x8f, 0x43, 0x04, 0x29, 0xe6, + 0x17, 0x38, 0x05, 0x2d, 0x97, 0x93, 0x5b, 0xf9, 0xef, 0x4d, 0x2e, 0x75, + 0x6c, 0x69, 0xba, 0x08, 0xf2, 0x21, 0x1e, 0x21, 0xe6, 0x8a, 0x5b, 0x8c, + 0xd4, 0x8e, 0xde, 0x64, 0x9b, 0x9d, 0x54, 0x58, 0x65, 0x3e, 0xdd, 0x8a, + 0x1e, 0x81, 0x4e, 0x45, 0xe8, 0xfb, 0x20, 0xc3, 0x3a, 0xf0, 0x50, 0x1e, + 0x8a, 0x18, 0xea, 0x2b, 0xf5, 0xe1, 0xa6, 0xb6, 0xc8, 0xa0, 0x02, 0x3d, + 0x6e, 0xfa, 0x0b, 0x51, 0x95, 0x4e, 0x4c, 0x11, 0xb0, 0xc4, 0x62, 0x58, + 0xa6, 0x9c, 0x13, 0x4e, 0xbe, 0xc9, 0x29, 0x93, 0x29, 0x15, 0x5f, 0xaf, + 0x0e, 0xc3, 0xb3, 0x26, 0x3f, 0xdc, 0x4c, 0x33, 0xb8, 0x4b, 0x11, 0xae, + 0x1f, 0xd7, 0x05, 0x39, 0xcf, 0xfe, 0xc3, 0x6d, 0xf0, 0xc0, 0x77, 0x02, + 0xb8, 0x9b, 0x3d, 0x1b, 0x3d, 0x72, 0xfe, 0x7e, 0x18, 0x60, 0x9b, 0xc4, + 0x8b, 0xac, 0x25, 0x6d, 0x3b, 0x80, 0x34, 0xbc, 0x51, 0xaf, 0xf6, 0xff, + 0x66, 0x98, 0x86, 0x6e, 0x9e, 0x9a, 0xfe, 0x6d, 0x21, 0x4d, 0xf1, 0x58, + 0x3e, 0x3e, 0x43, 0xe3, 0x7e, 0x40, 0xb0, 0xb3, 0xd8, 0x12, 0xa5, 0xce, + 0x09, 0x41, 0x8c, 0x1d, 0x73, 0xcd, 0xfc, 0x63, 0xed, 0xeb, 0x08, 0x1e, + 0x34, 0xfb, 0xed, 0x75, 0xb7, 0x86, 0x84, 0x7c, 0x80, 0xe9, 0xe4, 0xa3, + 0x1c, 0x4a, 0x0d, 0x11, 0x16, 0x24, 0xb2, 0xb1, 0x99, 0xe5, 0xe3, 0x2e, + 0x2f, 0x70, 0xcd, 0x1e, 0x35, 0x14, 0x79, 0xba, 0xa2, 0x51, 0x7a, 0x29, + 0x5c, 0x75, 0x8f, 0xdd, 0x22, 0xdf, 0xb2, 0x64, 0xd9, 0x95, 0x11, 0x33, + 0x97, 0xee, 0x69, 0x42, 0x01, 0x96, 0x98, 0x1b, 0x43, 0xc2, 0xec, 0xf9, + 0xb0, 0xdb, 0x69, 0x34, 0xab, 0x98, 0x1b, 0xb2, 0x04, 0x05, 0x14, 0x1d, + 0x25, 0x2f, 0x32, 0x41, 0x50, 0x51, 0x55, 0x62, 0x6d, 0x78, 0x7f, 0x8b, + 0xbb, 0xc2, 0xcd, 0xcf, 0xe4, 0xed, 0x04, 0x1f, 0x25, 0x30, 0x43, 0x64, + 0x69, 0x7c, 0x87, 0xa3, 0xa9, 0xb1, 0xc1, 0xd1, 0xdc, 0x01, 0x10, 0x1d, + 0x27, 0x3f, 0x5c, 0x5d, 0x75, 0x82, 0x9b, 0xaa, 0xb3, 0xe8, 0x0c, 0x11, + 0x1f, 0x24, 0x38, 0x41, 0x45, 0x54, 0x5f, 0x69, 0x85, 0x8d, 0x93, 0x9e, + 0xc5, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x25, 0x32, 0x42}; +const uint8_t expected_signature_65[] = { + 0x8b, 0x6f, 0x79, 0x00, 0xcc, 0x79, 0x57, 0xee, 0x16, 0x86, 0x87, 0xd5, + 0xcf, 0xb6, 0x90, 0x2c, 0xc6, 0x30, 0xeb, 0x8d, 0x39, 0xae, 0x9b, 0xf1, + 0x66, 0xe0, 0xd6, 0x93, 0xa5, 0x4e, 0x26, 0x9b, 0x96, 0x8f, 0xd1, 0x46, + 0x97, 0xbe, 0x71, 0x1c, 0xf3, 0xa5, 0xe5, 0xae, 0x8d, 0x4b, 0xf2, 0xe6, + 0x48, 0x8f, 0xe9, 0x5e, 0x07, 0xef, 0xe4, 0xbb, 0x39, 0xc1, 0xc9, 0x3c, + 0xc3, 0x0b, 0xfb, 0x2a, 0x29, 0x06, 0xfe, 0x01, 0xcb, 0x63, 0x83, 0x10, + 0xa8, 0xc8, 0xa0, 0x29, 0xa5, 0x80, 0xeb, 0xbd, 0xa9, 0xd9, 0x0b, 0x61, + 0xbc, 0xce, 0x11, 0x55, 0x66, 0x12, 0xc7, 0x5b, 0xd2, 0x7a, 0x5a, 0xc8, + 0xab, 0xab, 0xbf, 0x3a, 0x1f, 0x96, 0x1a, 0x70, 0xcb, 0x41, 0x5f, 0xc8, + 0xb7, 0x09, 0x22, 0x98, 0x9b, 0xb8, 0xf7, 0x2d, 0x49, 0x65, 0x1d, 0x09, + 0x8b, 0x70, 0xb5, 0x42, 0xc9, 0x89, 0x5b, 0x74, 0xb4, 0x28, 0x82, 0x01, + 0x53, 0x12, 0x3e, 0x23, 0xf6, 0x54, 0xf8, 0x51, 0x12, 0x4b, 0x02, 0x3a, + 0x7e, 0xb6, 0x1f, 0xac, 0xa0, 0xe6, 0x6f, 0xf8, 0x61, 0x82, 0xe4, 0xfb, + 0x96, 0x2a, 0xd2, 0xaf, 0x3c, 0xea, 0x6e, 0xdc, 0x18, 0x8a, 0x5d, 0x90, + 0xda, 0xa2, 0x5d, 0xa7, 0x8f, 0x5b, 0x50, 0x46, 0xaf, 0x8c, 0x17, 0x6a, + 0x4c, 0x39, 0xfc, 0x31, 0x4c, 0x4b, 0xc2, 0x57, 0x66, 0x61, 0x98, 0xbf, + 0xe6, 0xfb, 0x54, 0x96, 0xd3, 0x70, 0xb8, 0xaf, 0xcd, 0x8b, 0xcc, 0x00, + 0x07, 0x92, 0x15, 0xc2, 0xbb, 0x48, 0xbb, 0xc6, 0xb7, 0xb5, 0x58, 0x8c, + 0xfc, 0xf0, 0xda, 0x6a, 0x0d, 0xf7, 0x1d, 0x7d, 0xc6, 0x27, 0x26, 0x1a, + 0x99, 0xc5, 0x2f, 0xf8, 0x97, 0x65, 0x43, 0x86, 0xd6, 0x25, 0x23, 0x2b, + 0x06, 0x8f, 0x12, 0xa1, 0xae, 0xbb, 0x58, 0x34, 0x25, 0xec, 0x5b, 0x68, + 0xa4, 0xe1, 0x03, 0xfc, 0x26, 0xa2, 0xd6, 0x2b, 0x61, 0x10, 0x47, 0xbd, + 0x16, 0xe5, 0xca, 0x4a, 0xce, 0xed, 0x89, 0x09, 0x1a, 0xed, 0x22, 0xc1, + 0xca, 0x44, 0xe3, 0xef, 0x72, 0x34, 0xab, 0xab, 0x61, 0x5c, 0x9f, 0x5f, + 0xb5, 0xf5, 0xe8, 0x2d, 0x89, 0xea, 0x4b, 0x40, 0x65, 0x57, 0x8b, 0xa2, + 0x95, 0x40, 0x9c, 0x72, 0xc0, 0x46, 0x69, 0x45, 0x06, 0xf6, 0x07, 0x5b, + 0x2d, 0xa5, 0x46, 0xca, 0x5d, 0xfb, 0x40, 0xb7, 0x48, 0x59, 0x5b, 0xe2, + 0x1b, 0x38, 0xb2, 0x15, 0x75, 0x66, 0x67, 0x58, 0x00, 0x3f, 0xde, 0x8a, + 0x63, 0x13, 0x34, 0x6a, 0x30, 0xca, 0xb4, 0xd5, 0x3e, 0xe0, 0x6d, 0x14, + 0xb8, 0x9a, 0x48, 0xef, 0xfd, 0xbd, 0x6d, 0x20, 0x11, 0x4d, 0x25, 0xe5, + 0xab, 0x15, 0x8d, 0xe5, 0x91, 0xbc, 0xc6, 0x69, 0x8a, 0xf8, 0xab, 0x3a, + 0x82, 0xae, 0xc5, 0x03, 0x2c, 0xcf, 0x54, 0xdc, 0xcd, 0xe8, 0x49, 0x53, + 0xb5, 0xd8, 0xc2, 0x24, 0xf8, 0x8c, 0x38, 0x8f, 0xe3, 0xfe, 0x3a, 0x18, + 0x15, 0xa8, 0xda, 0x77, 0xc8, 0x81, 0x72, 0xc6, 0xc1, 0x60, 0xa3, 0x73, + 0x65, 0x68, 0x5c, 0xf3, 0x1d, 0x8d, 0x61, 0x21, 0x65, 0xfb, 0x45, 0xc4, + 0x4c, 0x31, 0x88, 0x25, 0x0d, 0x52, 0x75, 0x3b, 0xec, 0x54, 0xe0, 0xb1, + 0x9c, 0x7c, 0xdf, 0xe3, 0x3b, 0x77, 0x31, 0x33, 0xd7, 0x25, 0x99, 0xff, + 0xc5, 0x40, 0x1e, 0x85, 0x09, 0xfd, 0x2d, 0x24, 0x4a, 0x92, 0xe7, 0x77, + 0x48, 0xa5, 0x46, 0xf4, 0x8e, 0xa3, 0x6b, 0x24, 0xe4, 0x6b, 0x31, 0xf6, + 0xe0, 0x16, 0x49, 0x9b, 0x9f, 0xa3, 0x1a, 0x5c, 0x05, 0x5e, 0x81, 0x62, + 0xc8, 0x14, 0x52, 0xb4, 0x21, 0xfd, 0x76, 0x6d, 0x88, 0xe9, 0x3b, 0x0b, + 0x75, 0x27, 0x92, 0x47, 0x5a, 0x58, 0x08, 0x26, 0xa7, 0xa2, 0x48, 0x1c, + 0x14, 0x3e, 0x5e, 0xdf, 0x81, 0x83, 0x83, 0x3e, 0xc6, 0x72, 0x27, 0xc4, + 0x6a, 0x46, 0x2b, 0xf2, 0x8d, 0x42, 0x11, 0xb9, 0x15, 0xd7, 0xf0, 0x20, + 0x29, 0x53, 0xba, 0xf0, 0x6e, 0x41, 0x3d, 0xee, 0x19, 0xf2, 0x43, 0xf3, + 0x6d, 0x00, 0xe2, 0x43, 0x77, 0xb9, 0xa9, 0x78, 0x34, 0x48, 0x3c, 0x1a, + 0x8b, 0xbd, 0xa1, 0xe5, 0x90, 0x59, 0x5b, 0xd6, 0x1e, 0x22, 0xdf, 0xb2, + 0xa7, 0x96, 0x7d, 0x55, 0x86, 0x66, 0x95, 0xb7, 0x06, 0xe7, 0x60, 0x2a, + 0x01, 0x48, 0x3f, 0xd4, 0xa7, 0xd4, 0xc2, 0x38, 0xa4, 0x10, 0x8e, 0x4f, + 0x97, 0xad, 0xa3, 0xb9, 0xe2, 0xaa, 0x13, 0xb1, 0x16, 0x89, 0x3d, 0x74, + 0x60, 0x94, 0x8c, 0xc3, 0xe6, 0x5f, 0xcf, 0xdc, 0x58, 0x17, 0x98, 0x27, + 0x86, 0xae, 0x2a, 0x0d, 0xe8, 0x33, 0x79, 0xc8, 0xc8, 0x5b, 0x59, 0xb0, + 0xba, 0xac, 0xd3, 0x6e, 0x2d, 0x7b, 0x0b, 0x9a, 0xb5, 0xfd, 0x58, 0x42, + 0xeb, 0x80, 0xf4, 0x6b, 0x9a, 0x2f, 0x19, 0x43, 0x75, 0xb4, 0xcb, 0xc9, + 0xd5, 0x28, 0xf5, 0xb9, 0x67, 0x82, 0xb4, 0xed, 0x8c, 0x3f, 0x3d, 0x6b, + 0x6d, 0x1b, 0x80, 0x13, 0x5c, 0x7b, 0x2e, 0xfa, 0xa0, 0x32, 0xba, 0xb5, + 0x46, 0xd6, 0xe7, 0x90, 0xe9, 0xd1, 0x91, 0xa0, 0xaa, 0x26, 0x35, 0xa2, + 0x0d, 0x98, 0x44, 0x11, 0xae, 0xf9, 0xc5, 0x12, 0x4d, 0x1a, 0x7c, 0x53, + 0xea, 0xf6, 0x05, 0x8d, 0x3a, 0x74, 0x92, 0xc9, 0x65, 0xeb, 0x6f, 0xb5, + 0xb4, 0xd2, 0xcd, 0x5c, 0xec, 0xaf, 0x95, 0xcb, 0xb4, 0x3c, 0x22, 0xca, + 0x1c, 0x06, 0x85, 0x16, 0x96, 0x24, 0x8c, 0x6c, 0x80, 0xf8, 0xb3, 0xa7, + 0x87, 0x77, 0xeb, 0x09, 0x71, 0xc8, 0x95, 0xfb, 0x5e, 0xe5, 0x6f, 0x78, + 0xf9, 0x60, 0xf9, 0x9e, 0x58, 0x7b, 0xbd, 0x47, 0xdd, 0x48, 0x2e, 0x56, + 0xcd, 0x63, 0x72, 0xc9, 0x4b, 0x65, 0x2d, 0x41, 0xe8, 0x81, 0x19, 0x33, + 0x4b, 0xf6, 0x02, 0xc6, 0xcb, 0x2e, 0xdf, 0x3d, 0xc8, 0xdd, 0x2f, 0x0f, + 0x09, 0x67, 0xf0, 0xaa, 0x3c, 0x51, 0xdc, 0x8d, 0xc6, 0xc3, 0xb2, 0x3b, + 0x15, 0x85, 0xcb, 0xeb, 0x62, 0xef, 0xa3, 0xf9, 0x94, 0xf4, 0x35, 0x9c, + 0x59, 0xcc, 0xc2, 0x68, 0xb4, 0xde, 0x02, 0x75, 0x8e, 0xf5, 0x33, 0xca, + 0xd5, 0xc5, 0x24, 0xae, 0xf6, 0xde, 0x2b, 0x01, 0xf4, 0x56, 0xb9, 0xa5, + 0xa7, 0xe0, 0x64, 0x2e, 0xba, 0x1d, 0x53, 0x54, 0x46, 0xcf, 0x64, 0x16, + 0x12, 0xe2, 0xa6, 0xcc, 0x18, 0xb4, 0x77, 0x8b, 0x19, 0x50, 0x43, 0x96, + 0xc8, 0x5d, 0xc3, 0x58, 0xf0, 0xfd, 0x5e, 0x13, 0xa9, 0x10, 0x67, 0xdf, + 0x25, 0xdb, 0xaf, 0x38, 0x5f, 0xbd, 0x35, 0xc1, 0x49, 0x44, 0xe8, 0x1f, + 0x12, 0xa4, 0x7c, 0x28, 0xa3, 0xd6, 0x0d, 0x6f, 0x44, 0xa9, 0x5f, 0xfc, + 0x9f, 0xfa, 0x11, 0x62, 0x87, 0x5b, 0x0e, 0x91, 0xd4, 0xb6, 0xd3, 0x71, + 0xc2, 0x77, 0x19, 0xf6, 0x7c, 0x11, 0x30, 0x5e, 0x5c, 0xd3, 0x1e, 0x90, + 0x05, 0x31, 0x63, 0xbb, 0xef, 0x85, 0xe0, 0x27, 0x94, 0x80, 0xcb, 0x33, + 0xbc, 0x5e, 0x45, 0x87, 0x62, 0xdf, 0xd4, 0x12, 0x2f, 0xf5, 0x41, 0x15, + 0x03, 0x0c, 0x80, 0xe8, 0xe2, 0x06, 0xde, 0x4b, 0x46, 0x70, 0x94, 0xd2, + 0x0d, 0x85, 0x72, 0x27, 0xe5, 0x6c, 0xeb, 0xd2, 0x78, 0x0b, 0x38, 0x40, + 0xe8, 0xdb, 0x47, 0x5c, 0xba, 0xd0, 0x21, 0x33, 0x8f, 0xb8, 0xc0, 0x66, + 0x1e, 0xd1, 0xb0, 0x94, 0xa3, 0x39, 0xc7, 0x87, 0xaf, 0x97, 0x98, 0xce, + 0x6d, 0x03, 0x1a, 0xdb, 0x52, 0x96, 0x0b, 0x9d, 0x5b, 0xf8, 0xa3, 0xf4, + 0x41, 0x95, 0x72, 0xad, 0x0e, 0x98, 0x61, 0x7f, 0xf3, 0x8f, 0x23, 0xeb, + 0xc0, 0xdf, 0xd7, 0x70, 0x26, 0x8c, 0xb3, 0xb3, 0xf0, 0xa2, 0x8a, 0x39, + 0xdd, 0x61, 0xb4, 0x53, 0xe0, 0x2a, 0x6f, 0x91, 0x34, 0x9c, 0x76, 0xf6, + 0x52, 0x93, 0xe6, 0x39, 0xb7, 0x54, 0x07, 0x46, 0x82, 0x2d, 0x05, 0x6d, + 0x9a, 0x00, 0x53, 0x65, 0x68, 0x93, 0x91, 0x00, 0xda, 0xe0, 0x93, 0x34, + 0x60, 0xb1, 0x93, 0x0b, 0x64, 0xa8, 0x12, 0xd2, 0x51, 0x3c, 0xdb, 0xb0, + 0x4c, 0x39, 0x4e, 0xce, 0xbd, 0xf0, 0x65, 0x12, 0x8a, 0xd4, 0x80, 0x7d, + 0x82, 0x85, 0xe4, 0x92, 0xc2, 0x77, 0x1e, 0xcf, 0xd9, 0xab, 0x0f, 0x9b, + 0x32, 0x2e, 0x3f, 0xe1, 0x0e, 0x87, 0x1c, 0x87, 0x34, 0xe7, 0x93, 0x16, + 0x95, 0x09, 0x7d, 0x24, 0xa8, 0xb5, 0xe0, 0x9f, 0x23, 0x87, 0x5c, 0x0b, + 0x31, 0x4a, 0x2f, 0xe2, 0x5c, 0x82, 0x49, 0x51, 0xe4, 0x93, 0xcb, 0x05, + 0x23, 0x4f, 0x8a, 0x83, 0x88, 0xfb, 0x89, 0xb0, 0x08, 0xd6, 0x64, 0xad, + 0x51, 0x84, 0x40, 0x29, 0xb1, 0xca, 0x74, 0x26, 0x29, 0x5a, 0x61, 0x01, + 0x2e, 0xa0, 0xeb, 0xeb, 0x02, 0xb5, 0xff, 0xd8, 0x20, 0x6a, 0x5e, 0x8d, + 0x17, 0x1e, 0xa3, 0xd7, 0x2f, 0x20, 0x0b, 0x93, 0x17, 0x24, 0xf7, 0x90, + 0x7b, 0xc6, 0xba, 0xd8, 0xf9, 0xe9, 0x0a, 0x2a, 0x7a, 0x81, 0x23, 0x81, + 0x03, 0x6f, 0x1e, 0x0d, 0x87, 0x83, 0xd1, 0xcf, 0x92, 0x2f, 0x19, 0x82, + 0x4e, 0x6c, 0x0a, 0x02, 0xb6, 0x70, 0xbc, 0xe1, 0x58, 0xe7, 0x16, 0xdb, + 0x2f, 0x74, 0x9f, 0xe1, 0xc2, 0x1e, 0x64, 0xc6, 0x48, 0x08, 0xee, 0xea, + 0x52, 0x9a, 0xce, 0x2c, 0xc5, 0x0c, 0x7a, 0x63, 0xf1, 0x6a, 0xbd, 0x2c, + 0x8b, 0xd5, 0x4a, 0xfa, 0x1e, 0xab, 0x9a, 0x5b, 0x25, 0xb8, 0xfa, 0x0a, + 0xe9, 0x68, 0x80, 0x6f, 0x80, 0x57, 0x10, 0x54, 0xb8, 0xa2, 0x16, 0xbd, + 0xfe, 0xf7, 0xea, 0x01, 0xc7, 0x94, 0x5a, 0x95, 0xe3, 0x61, 0xa5, 0x49, + 0x84, 0xf5, 0x79, 0x78, 0xb5, 0x0a, 0x96, 0xca, 0x01, 0x1b, 0xd0, 0x0b, + 0x51, 0x30, 0xd3, 0x48, 0xfc, 0x4d, 0x50, 0x71, 0x09, 0x73, 0xea, 0x37, + 0xcd, 0x9d, 0x3d, 0xde, 0x30, 0x56, 0x21, 0xf0, 0xef, 0x84, 0xad, 0x27, + 0xe1, 0x83, 0xdb, 0xfb, 0xcd, 0x11, 0xb2, 0xbd, 0x30, 0x67, 0x8a, 0x88, + 0x09, 0x0e, 0x9d, 0x96, 0x09, 0xba, 0xda, 0x9d, 0xf0, 0xe9, 0xb4, 0xa6, + 0x7a, 0x04, 0xf9, 0x4b, 0xb8, 0x51, 0xa9, 0x99, 0xf3, 0xbb, 0x77, 0x95, + 0x0a, 0xa1, 0xa6, 0xa1, 0x24, 0xfc, 0xcc, 0x45, 0xe8, 0x83, 0xc8, 0x6f, + 0x48, 0xad, 0x9a, 0x73, 0xd0, 0xe0, 0x57, 0x7d, 0xe4, 0x78, 0x65, 0xef, + 0xae, 0xc2, 0xfe, 0x7a, 0x56, 0xaf, 0x03, 0x71, 0x2b, 0xe6, 0xa1, 0x7e, + 0xe5, 0x12, 0xf8, 0xc3, 0x75, 0xc7, 0x22, 0x5f, 0x1b, 0x52, 0x90, 0xe5, + 0xdf, 0xba, 0x9d, 0xe2, 0x68, 0xe0, 0xb3, 0x7a, 0x9e, 0x14, 0xff, 0xb5, + 0x0a, 0x80, 0x20, 0x49, 0x88, 0xe9, 0x9c, 0xe4, 0xb5, 0xaf, 0x7e, 0x51, + 0xec, 0xe7, 0xfc, 0x64, 0x65, 0x21, 0x10, 0xc6, 0x1f, 0x7f, 0x93, 0x7d, + 0xd8, 0xf5, 0xd0, 0x98, 0x94, 0x44, 0xf8, 0x49, 0x6a, 0x51, 0x0a, 0x54, + 0xf4, 0x9f, 0xee, 0x3c, 0x56, 0xbf, 0x4c, 0xe4, 0xde, 0x1c, 0x9b, 0x11, + 0x7e, 0x9a, 0x71, 0x11, 0x80, 0x33, 0xd5, 0xb0, 0x9b, 0xef, 0x67, 0x29, + 0xa4, 0x7d, 0x70, 0x31, 0x3f, 0x8b, 0x2e, 0x4a, 0x0f, 0x2c, 0x91, 0x3d, + 0x3e, 0x3d, 0x8c, 0x0a, 0x2b, 0xf1, 0xdd, 0xbf, 0x61, 0xe6, 0xa3, 0xef, + 0x6d, 0x82, 0xc8, 0xb7, 0x5e, 0x2b, 0x83, 0xc9, 0x4e, 0xa0, 0x85, 0x7f, + 0x01, 0x5a, 0xca, 0x6e, 0x90, 0xfa, 0x7e, 0x82, 0x4d, 0x35, 0x7e, 0xe0, + 0x26, 0x40, 0xf4, 0xa6, 0xae, 0xc3, 0x89, 0xf3, 0xca, 0x55, 0x2c, 0xb5, + 0x29, 0x05, 0x94, 0x45, 0xa7, 0x45, 0xf3, 0x3d, 0xbb, 0x53, 0x5e, 0xca, + 0x7c, 0x84, 0x8f, 0x72, 0x98, 0x93, 0x90, 0x1f, 0x56, 0x72, 0xdb, 0xbd, + 0xa9, 0xeb, 0xf9, 0xe9, 0xce, 0xb1, 0x41, 0xc3, 0xaa, 0xa0, 0xc4, 0x74, + 0x23, 0xc1, 0xeb, 0x7d, 0x41, 0xcd, 0xa4, 0x62, 0xec, 0xfc, 0x9a, 0xa4, + 0x16, 0xec, 0x67, 0x41, 0x89, 0xf0, 0x0e, 0xf3, 0xd1, 0xa2, 0x2f, 0xba, + 0x5d, 0x93, 0x36, 0x46, 0xf5, 0x52, 0x64, 0x91, 0xe7, 0x40, 0x91, 0x20, + 0xa1, 0xc9, 0xaa, 0x4c, 0x79, 0xc4, 0xbb, 0x67, 0x79, 0xad, 0x43, 0xab, + 0xba, 0xde, 0xfc, 0xf1, 0x74, 0x81, 0x33, 0xc0, 0x3f, 0x39, 0xd1, 0xd1, + 0xdf, 0xc0, 0x53, 0x33, 0xb2, 0x92, 0x37, 0xe6, 0x86, 0x2a, 0xe4, 0xe1, + 0x7c, 0x98, 0xf7, 0xdb, 0x5c, 0xa9, 0xff, 0x8d, 0x9c, 0xab, 0xe2, 0xf2, + 0xd5, 0xb1, 0x42, 0xa9, 0xf4, 0x97, 0x80, 0xcd, 0xde, 0x25, 0x2e, 0x87, + 0x92, 0xdd, 0xcf, 0xed, 0x67, 0x93, 0x8c, 0x5a, 0x1d, 0xee, 0xcf, 0x9d, + 0x50, 0x8f, 0xa7, 0xe3, 0x5c, 0xa3, 0x68, 0x78, 0x24, 0xeb, 0x60, 0xa3, + 0x8b, 0x36, 0xbb, 0xcb, 0x46, 0xee, 0x77, 0xfb, 0xf8, 0x69, 0x24, 0xd1, + 0xfa, 0xad, 0x76, 0x76, 0x5e, 0x54, 0xe5, 0xb6, 0x36, 0xc6, 0xdd, 0xa9, + 0x6c, 0x44, 0x15, 0xf7, 0x0a, 0xf8, 0xbb, 0xba, 0xec, 0x35, 0xff, 0xc9, + 0xd6, 0x5d, 0xf5, 0x73, 0x4a, 0x15, 0x8f, 0x7b, 0x6e, 0xf4, 0xa0, 0x6d, + 0x10, 0xbb, 0x67, 0x0c, 0xb4, 0x69, 0xad, 0xb6, 0x40, 0xf7, 0x5f, 0x37, + 0x28, 0xc4, 0x08, 0x49, 0xd0, 0x16, 0x70, 0x80, 0xea, 0x55, 0x66, 0x07, + 0xc8, 0x03, 0x1b, 0xf6, 0xd3, 0x03, 0x04, 0x74, 0xe0, 0x50, 0x3f, 0xd2, + 0x53, 0x92, 0xa0, 0x9d, 0x59, 0xc9, 0x74, 0xf2, 0x7e, 0x3b, 0x33, 0x02, + 0x10, 0x0b, 0x39, 0xf7, 0x4f, 0x6b, 0x58, 0xb2, 0x1a, 0xda, 0x65, 0x44, + 0xd1, 0x7c, 0x3f, 0xd7, 0xe3, 0xac, 0xe2, 0x1f, 0x38, 0xc1, 0x6a, 0xb0, + 0xdc, 0xc3, 0x9c, 0x7b, 0x11, 0x3c, 0x05, 0x21, 0x96, 0x76, 0x98, 0x76, + 0x82, 0xc1, 0x54, 0xdf, 0xdc, 0x8f, 0x4c, 0xd2, 0x63, 0x04, 0x06, 0x77, + 0x36, 0xe6, 0x2e, 0xd1, 0x00, 0x28, 0x42, 0x7c, 0x4a, 0x27, 0x90, 0x46, + 0xc9, 0xce, 0x33, 0x1c, 0xae, 0xda, 0x79, 0x64, 0x7f, 0x52, 0x3f, 0x58, + 0x11, 0x76, 0x4a, 0xb6, 0x72, 0xd8, 0x76, 0xae, 0xfd, 0x5c, 0x57, 0x69, + 0x76, 0x91, 0x84, 0x21, 0xc4, 0x9b, 0xd8, 0xa2, 0xff, 0x93, 0x02, 0x77, + 0x61, 0x57, 0x96, 0x7b, 0x8e, 0xfc, 0xf2, 0x6c, 0x11, 0x2b, 0x5e, 0x88, + 0x5c, 0x17, 0x1d, 0x12, 0x79, 0x3a, 0x78, 0xb6, 0x9d, 0x70, 0xfa, 0xd4, + 0xc1, 0x5c, 0x90, 0x0e, 0x0a, 0xd1, 0x3c, 0x7d, 0xcf, 0xee, 0x8a, 0xb2, + 0xb2, 0x4d, 0xce, 0x89, 0x32, 0xa9, 0x6c, 0x56, 0x57, 0x85, 0xb1, 0xbf, + 0x18, 0x1d, 0xc6, 0xe1, 0x17, 0xc5, 0x92, 0x42, 0x99, 0xf9, 0x9f, 0x04, + 0xec, 0x38, 0xf8, 0xa0, 0xd2, 0xab, 0xe6, 0x13, 0x4d, 0x9c, 0x18, 0x86, + 0x3e, 0x18, 0x73, 0x2c, 0xac, 0xe0, 0xb9, 0xf9, 0x87, 0x74, 0xb8, 0xd7, + 0x47, 0x6e, 0x42, 0xfc, 0x29, 0xa0, 0x1f, 0x56, 0x68, 0xb6, 0x23, 0x96, + 0xa2, 0x8d, 0x54, 0x81, 0x0f, 0x60, 0xb9, 0xde, 0x93, 0xfc, 0xfd, 0xde, + 0xbe, 0xb3, 0xb5, 0x87, 0xec, 0x9f, 0x17, 0xc2, 0x77, 0x6e, 0xa0, 0x62, + 0xdb, 0x66, 0xba, 0xc5, 0x05, 0x12, 0x46, 0x5d, 0x3c, 0x23, 0x29, 0x68, + 0xe5, 0x31, 0xe3, 0x15, 0xec, 0xac, 0x15, 0x9a, 0xbf, 0x42, 0x65, 0x80, + 0x45, 0x9c, 0x1d, 0xc2, 0x0e, 0x18, 0x47, 0x40, 0x44, 0xc1, 0x55, 0x24, + 0x5a, 0x35, 0xad, 0x59, 0xd2, 0xc6, 0xc3, 0x68, 0x58, 0xbd, 0x6f, 0xcf, + 0x5d, 0xb1, 0x9b, 0x0c, 0x92, 0x39, 0x22, 0x49, 0x66, 0x2e, 0x03, 0x7b, + 0x75, 0x5c, 0x6c, 0xde, 0x37, 0x54, 0xa9, 0x07, 0x2f, 0x7e, 0xc1, 0x3e, + 0x3b, 0xab, 0xd2, 0xa9, 0xfa, 0xc7, 0x6b, 0xd5, 0x14, 0x08, 0x35, 0x89, + 0x0b, 0x31, 0x18, 0x54, 0x7d, 0x6b, 0x53, 0x80, 0x6e, 0x32, 0x9b, 0xff, + 0x61, 0x7f, 0x36, 0xe5, 0x28, 0x40, 0xbc, 0xc7, 0x19, 0xb3, 0xae, 0xfa, + 0x95, 0xa8, 0xae, 0xd2, 0x97, 0x72, 0xc6, 0x91, 0x36, 0x3a, 0xa6, 0xec, + 0x4a, 0x41, 0x63, 0x6b, 0x28, 0xef, 0x5a, 0xa1, 0xdb, 0xf2, 0xd9, 0xfd, + 0x61, 0x72, 0xa4, 0xd2, 0x9e, 0xf7, 0x47, 0xf4, 0x4e, 0xea, 0x2a, 0xa5, + 0x35, 0xe1, 0x77, 0x3a, 0x53, 0x28, 0xa6, 0x55, 0x48, 0x0c, 0x1e, 0x44, + 0xfc, 0xc1, 0x31, 0x5a, 0x00, 0xcd, 0x29, 0xc1, 0x5c, 0xca, 0x2a, 0x07, + 0x01, 0x63, 0xac, 0xb3, 0xfb, 0xf6, 0x0b, 0xac, 0xfd, 0xe8, 0x7b, 0xed, + 0xf9, 0x3d, 0x9a, 0xbc, 0x67, 0x28, 0x1c, 0xd9, 0x3f, 0x97, 0x28, 0x4a, + 0xe7, 0xd0, 0x08, 0xe9, 0x3e, 0xa0, 0xcb, 0x0f, 0xe0, 0x3f, 0x1b, 0x80, + 0x43, 0x74, 0xd9, 0x9d, 0x0b, 0x22, 0x81, 0xf7, 0xec, 0x71, 0x2a, 0x29, + 0x9e, 0x5d, 0x1e, 0x8d, 0xf4, 0x22, 0x95, 0x78, 0x86, 0xcb, 0xf0, 0x9d, + 0xe7, 0x6a, 0x66, 0x7e, 0x28, 0xb5, 0x47, 0xb6, 0xdc, 0x0d, 0x03, 0x3c, + 0x09, 0x58, 0x76, 0x93, 0x39, 0xb2, 0xd3, 0x75, 0xb4, 0x51, 0x55, 0x84, + 0x30, 0x24, 0x0a, 0x76, 0xf4, 0x97, 0xe7, 0x0f, 0x5a, 0x67, 0xee, 0xf4, + 0xc7, 0x69, 0x8d, 0xf2, 0x32, 0x29, 0x5c, 0x33, 0x82, 0x5f, 0x6c, 0x47, + 0xd0, 0xe2, 0xbd, 0x62, 0xd6, 0x4c, 0x6d, 0x0d, 0xba, 0x87, 0xd3, 0x43, + 0x7e, 0x2d, 0xa6, 0x14, 0x09, 0x4f, 0x3b, 0xc3, 0x04, 0x14, 0xe5, 0x65, + 0xe9, 0x3b, 0x6a, 0xca, 0xb5, 0x96, 0x84, 0x3f, 0x53, 0x49, 0x22, 0x45, + 0x91, 0xff, 0xf9, 0x26, 0x75, 0x0d, 0x9c, 0xa7, 0x00, 0xf4, 0x65, 0xc4, + 0x60, 0x72, 0xab, 0xeb, 0xf8, 0xa8, 0x72, 0xfe, 0xd8, 0xde, 0x93, 0x67, + 0xcb, 0x09, 0xcc, 0xa0, 0xce, 0x9f, 0x67, 0x63, 0x26, 0xfa, 0x7f, 0x89, + 0xaa, 0x3e, 0x6d, 0xb2, 0x90, 0xd7, 0xef, 0x3e, 0x2a, 0x66, 0x26, 0x33, + 0xe6, 0x26, 0xc1, 0x58, 0xf8, 0x91, 0xea, 0x2f, 0xd0, 0x84, 0x21, 0x41, + 0x93, 0xa6, 0x36, 0x40, 0xb5, 0x4c, 0xac, 0x21, 0x88, 0x37, 0x47, 0x8a, + 0xb8, 0xf3, 0x33, 0x73, 0x12, 0xd7, 0x5a, 0x55, 0xf9, 0xd1, 0x1e, 0x75, + 0xa4, 0x66, 0x68, 0x3f, 0xf7, 0xb2, 0xc4, 0x5d, 0x1b, 0xb1, 0x61, 0x0f, + 0xaf, 0x4b, 0x9b, 0x20, 0x2b, 0x05, 0x68, 0x1c, 0x6c, 0x97, 0x8d, 0xb8, + 0x7b, 0x96, 0xda, 0xe0, 0x67, 0x15, 0x4c, 0x51, 0x71, 0x0d, 0xd3, 0x7b, + 0xde, 0xaa, 0xd3, 0x58, 0xf5, 0xc9, 0x62, 0x0a, 0xc2, 0x33, 0x1f, 0xf3, + 0xc3, 0x30, 0xb5, 0x64, 0xd1, 0x59, 0x41, 0x0e, 0xae, 0xaa, 0x0d, 0xdf, + 0x9f, 0x5d, 0x3f, 0x15, 0x0d, 0x46, 0x7a, 0x6d, 0x2e, 0x29, 0x1b, 0xc0, + 0xd3, 0x11, 0x10, 0x5d, 0xdc, 0x6a, 0x35, 0x8c, 0x43, 0xc8, 0x9f, 0x05, + 0x80, 0xdc, 0x25, 0x24, 0x37, 0x70, 0x7e, 0x1c, 0xe9, 0x85, 0x5a, 0xef, + 0x83, 0x3a, 0x55, 0x68, 0x83, 0x17, 0xf4, 0xc7, 0xae, 0xe4, 0x84, 0xc9, + 0x64, 0x5d, 0x2f, 0xb6, 0xca, 0x10, 0x95, 0xb8, 0xd6, 0x80, 0xfd, 0x05, + 0xa5, 0x06, 0x32, 0x34, 0x91, 0x01, 0xd2, 0x02, 0x90, 0xe1, 0xf7, 0x89, + 0x8a, 0xee, 0x18, 0x04, 0x93, 0xd9, 0xb4, 0x63, 0x4b, 0xf7, 0x7a, 0x9c, + 0x1b, 0x4b, 0xf9, 0x31, 0x32, 0xd9, 0xf2, 0x55, 0x4e, 0xc1, 0x02, 0xce, + 0x77, 0x38, 0x36, 0x29, 0xb8, 0x54, 0x8c, 0xc2, 0x27, 0x5f, 0xd9, 0xae, + 0x3e, 0x1e, 0xcd, 0xe9, 0x07, 0x90, 0x4c, 0xe0, 0xda, 0x16, 0x6e, 0xdf, + 0xde, 0x3a, 0x61, 0x89, 0x9f, 0x79, 0xd0, 0xd4, 0x66, 0x95, 0xad, 0xe4, + 0x11, 0x7d, 0xa1, 0xae, 0xec, 0x3e, 0x6e, 0x20, 0x5a, 0xd0, 0x28, 0x0e, + 0x55, 0xec, 0xcf, 0x34, 0xec, 0xb7, 0xfc, 0xa4, 0xb3, 0x8f, 0x56, 0x13, + 0x50, 0xcc, 0x15, 0x10, 0x74, 0x40, 0x72, 0x42, 0x20, 0x22, 0xb3, 0xaf, + 0xf3, 0x68, 0xba, 0x95, 0x45, 0xcb, 0xef, 0x92, 0xd5, 0x14, 0x4c, 0x1f, + 0xe3, 0xc1, 0xa6, 0x03, 0x4e, 0x05, 0xd2, 0x1a, 0xee, 0xd2, 0x48, 0x44, + 0x2e, 0x50, 0x3b, 0x86, 0xc8, 0x6a, 0xc8, 0x4c, 0xca, 0x2a, 0xb6, 0xf7, + 0x3c, 0xaf, 0xdc, 0x62, 0xb1, 0x49, 0x13, 0xfe, 0xe7, 0x32, 0xea, 0x78, + 0xfa, 0xba, 0xcf, 0x15, 0x47, 0x58, 0xdc, 0x19, 0x73, 0x1d, 0xff, 0xbd, + 0xcc, 0x27, 0xf6, 0xfc, 0x66, 0x68, 0xa7, 0x29, 0xaf, 0x2b, 0x25, 0x0c, + 0x15, 0x47, 0xff, 0xc1, 0x00, 0x9d, 0xfa, 0x58, 0x9c, 0xaa, 0xf9, 0xcc, + 0x4c, 0x51, 0x1d, 0xda, 0xf3, 0x3c, 0x10, 0xd0, 0x3b, 0x59, 0x30, 0x02, + 0x68, 0x29, 0x1c, 0xa7, 0x22, 0xea, 0x81, 0xd3, 0x29, 0x71, 0x39, 0xe8, + 0x72, 0x7f, 0x7d, 0x94, 0x0a, 0x64, 0x2c, 0xe6, 0x55, 0xfb, 0x90, 0x78, + 0x7e, 0x6c, 0x3e, 0xfe, 0x57, 0x14, 0x61, 0xef, 0xe2, 0x63, 0x57, 0x6c, + 0x13, 0x97, 0x27, 0x2b, 0x38, 0x44, 0xab, 0x74, 0x76, 0x11, 0xa6, 0x60, + 0xad, 0x8e, 0xad, 0xe5, 0xa5, 0xa1, 0x66, 0xc5, 0xe1, 0x4d, 0x27, 0xa0, + 0x79, 0x7a, 0x09, 0xe6, 0xf0, 0x28, 0x3f, 0xcb, 0xc6, 0xf8, 0x94, 0xc0, + 0xf1, 0x13, 0xbe, 0x62, 0x6a, 0x52, 0x75, 0x52, 0xd3, 0x82, 0x31, 0xbd, + 0x15, 0xf2, 0xe8, 0x2e, 0xb1, 0x62, 0x03, 0x1e, 0xe2, 0xb3, 0xec, 0xbc, + 0x3c, 0x12, 0xca, 0x62, 0x4e, 0xc2, 0x3a, 0x51, 0x1c, 0xdf, 0xa2, 0x84, + 0x88, 0xe5, 0x7e, 0xd7, 0x5d, 0xd7, 0xbf, 0xf2, 0x7d, 0xbd, 0x9a, 0x90, + 0x63, 0xfd, 0x8a, 0x84, 0x2b, 0x9d, 0x89, 0x27, 0x63, 0x4c, 0x0a, 0xe3, + 0x70, 0x94, 0x7b, 0xe6, 0xb3, 0xd7, 0xcb, 0xcb, 0x8a, 0xeb, 0x6b, 0x53, + 0x34, 0x2f, 0x62, 0x44, 0x2d, 0x73, 0x63, 0x8a, 0xf4, 0xa2, 0x01, 0xd7, + 0x12, 0xb6, 0x8d, 0x8c, 0x4b, 0x73, 0x2b, 0x44, 0x50, 0x49, 0x6f, 0x01, + 0xac, 0xc5, 0x15, 0x37, 0x6c, 0xde, 0xd4, 0x02, 0xb1, 0x12, 0x80, 0x73, + 0xb2, 0x52, 0x0e, 0xe0, 0xb5, 0x75, 0xc9, 0x48, 0xcf, 0x18, 0x5c, 0xcc, + 0xaf, 0x58, 0xa2, 0x3e, 0x28, 0xe4, 0xab, 0xde, 0xea, 0x2a, 0xcf, 0x58, + 0x22, 0xc4, 0x68, 0xea, 0x9b, 0x7b, 0x90, 0xc5, 0xdc, 0x1c, 0x37, 0xd1, + 0x8a, 0x4f, 0xe7, 0x24, 0x23, 0x39, 0xb9, 0x62, 0xb8, 0x41, 0x13, 0x7b, + 0xe2, 0x1e, 0x0d, 0x4e, 0x38, 0x11, 0xa3, 0xb9, 0x10, 0xbb, 0x10, 0x6f, + 0x40, 0x9f, 0x50, 0x05, 0xc7, 0x0e, 0xb9, 0x9e, 0xab, 0x7c, 0x3c, 0x78, + 0xce, 0x54, 0xbf, 0xbf, 0x40, 0x36, 0x76, 0xbc, 0x4b, 0x64, 0x32, 0xca, + 0x0e, 0x2d, 0x91, 0x87, 0xd5, 0x00, 0x19, 0xbf, 0x12, 0xd0, 0x35, 0x7c, + 0xa1, 0xe5, 0xcf, 0x7a, 0x2d, 0x08, 0x62, 0xed, 0x34, 0x61, 0xe3, 0xda, + 0x2c, 0xcc, 0x1b, 0xf8, 0x12, 0xfe, 0xfd, 0x19, 0xa2, 0xc3, 0x70, 0xfd, + 0x4f, 0x5b, 0x5d, 0x20, 0xd2, 0xe1, 0xc5, 0xac, 0xe7, 0xa1, 0x84, 0x00, + 0xbd, 0x46, 0x81, 0xfd, 0x54, 0x69, 0xed, 0x1a, 0x7a, 0x32, 0xbb, 0x75, + 0x22, 0x76, 0x6d, 0x34, 0x24, 0xcc, 0xe6, 0xbe, 0x78, 0x5a, 0x75, 0x6c, + 0xbc, 0x62, 0xb8, 0x14, 0xf7, 0x13, 0x73, 0xc2, 0xdc, 0xb6, 0xfa, 0xfb, + 0x97, 0xfe, 0x27, 0x7b, 0x33, 0xb8, 0xeb, 0x20, 0xd2, 0x0f, 0x4f, 0xed, + 0xd1, 0xd0, 0x63, 0xf7, 0xc5, 0x8e, 0xec, 0xcc, 0xd2, 0x31, 0x38, 0x35, + 0x65, 0x33, 0x5c, 0x63, 0x85, 0xf7, 0x3d, 0xc3, 0x62, 0x26, 0x52, 0x0a, + 0x67, 0xda, 0x87, 0x1f, 0x9e, 0x47, 0xec, 0x6b, 0xf5, 0x74, 0x1a, 0xc5, + 0xa7, 0xa0, 0x0f, 0xdd, 0xc5, 0x42, 0xf4, 0xda, 0x41, 0x1a, 0x48, 0xa9, + 0xbe, 0x4f, 0xb6, 0x28, 0x17, 0xe9, 0xf5, 0xd7, 0x00, 0xb3, 0xfe, 0x05, + 0x4e, 0xa7, 0xdf, 0x65, 0x7a, 0xb8, 0x4f, 0xe0, 0xfe, 0x58, 0x9e, 0xba, + 0x45, 0x11, 0xba, 0xc2, 0xdb, 0x97, 0x97, 0xa4, 0xbc, 0x18, 0x21, 0x1b, + 0xad, 0x82, 0xef, 0xb1, 0x5f, 0x2f, 0x25, 0x9d, 0xca, 0x52, 0xa5, 0x6d, + 0x8c, 0xab, 0x07, 0x2b, 0x7b, 0x6a, 0x77, 0x9d, 0xdf, 0xfb, 0xae, 0x6e, + 0x49, 0x18, 0x25, 0x4a, 0xf2, 0x7d, 0xa0, 0x32, 0xc8, 0x53, 0x10, 0xc3, + 0xf2, 0xef, 0xf3, 0xe7, 0x79, 0xd7, 0x6a, 0x0e, 0x61, 0xff, 0x89, 0xc9, + 0x42, 0xe8, 0x6e, 0x4f, 0x78, 0xe1, 0x5f, 0xcd, 0x7a, 0xf6, 0x27, 0x72, + 0x67, 0xea, 0x0b, 0xa6, 0xcc, 0x34, 0xb7, 0x8f, 0x92, 0x3c, 0x95, 0xb9, + 0x0a, 0x5d, 0x49, 0x2e, 0xb7, 0x7d, 0x31, 0x9c, 0x79, 0x61, 0x95, 0x9c, + 0x60, 0x56, 0x8d, 0x35, 0x00, 0xc5, 0x8b, 0xe6, 0x02, 0x0f, 0x26, 0x39, + 0x7b, 0x93, 0x94, 0xb1, 0xcd, 0xde, 0xed, 0xfa, 0x2a, 0x4b, 0x63, 0xa8, + 0x1b, 0x31, 0x43, 0x5e, 0x69, 0x7c, 0xd6, 0x15, 0x35, 0x9c, 0xa2, 0xd7, + 0xdf, 0x0e, 0x1a, 0x20, 0x50, 0xf5, 0x02, 0x21, 0x30, 0x35, 0x3c, 0x60, + 0x71, 0xad, 0xd0, 0xe3, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x10, 0x17, 0x1d, 0x22, 0x2d}; +const uint8_t expected_signature_87[] = { + 0xdf, 0xe6, 0xe1, 0xa5, 0x20, 0xc1, 0xac, 0x98, 0x55, 0x2c, 0xf2, 0x13, + 0x65, 0x42, 0xe2, 0xb0, 0x77, 0x5f, 0x15, 0x00, 0x8f, 0x14, 0x48, 0xa1, + 0xe3, 0xee, 0x81, 0x35, 0x15, 0x34, 0xad, 0x6e, 0x60, 0x85, 0x00, 0xf8, + 0x18, 0x53, 0x0d, 0xa0, 0xc5, 0x41, 0xc4, 0x48, 0x09, 0x1b, 0x34, 0x0c, + 0x0e, 0xcf, 0xc6, 0x3d, 0x38, 0x78, 0x8b, 0x69, 0xe5, 0x6f, 0x4d, 0x43, + 0xfa, 0xa6, 0x75, 0x26, 0x8a, 0x75, 0x97, 0x10, 0x6a, 0x1f, 0x3c, 0xa6, + 0x94, 0xa9, 0x93, 0x8f, 0xe5, 0x62, 0xbf, 0x94, 0xe4, 0xd0, 0x0d, 0x11, + 0x4d, 0x03, 0xe2, 0xd8, 0xdf, 0x68, 0xb7, 0x87, 0x62, 0xc9, 0xdc, 0xc9, + 0x36, 0x4f, 0xcc, 0xd1, 0xa4, 0xae, 0x7e, 0xa4, 0xb9, 0xaf, 0xaf, 0xf0, + 0x8a, 0xe6, 0xff, 0x83, 0xe7, 0x54, 0x22, 0x6e, 0x3f, 0x2e, 0xa0, 0x4f, + 0xa8, 0x31, 0x53, 0xf3, 0x62, 0xeb, 0x04, 0xfa, 0xd1, 0x57, 0x39, 0x43, + 0xf9, 0xe0, 0x31, 0x12, 0x45, 0x09, 0x8b, 0x9e, 0x1e, 0x7a, 0x2b, 0x85, + 0xee, 0xdd, 0xe8, 0x1e, 0xd7, 0xc0, 0x17, 0xb4, 0xd2, 0xdc, 0x36, 0xa9, + 0xe4, 0x49, 0x88, 0xbf, 0x71, 0x43, 0x9d, 0x3e, 0xd2, 0x10, 0xe7, 0x82, + 0xb5, 0xfe, 0xdd, 0x42, 0xc8, 0x1b, 0x11, 0xf6, 0x52, 0x23, 0x98, 0x83, + 0x48, 0xec, 0xec, 0x70, 0x8b, 0xe7, 0x49, 0x9a, 0xd7, 0xd9, 0x7b, 0x47, + 0x4e, 0xe2, 0x5e, 0x17, 0x1a, 0xa0, 0x0e, 0x60, 0x85, 0x3a, 0x30, 0x8c, + 0x1c, 0x26, 0xb4, 0xe1, 0xb5, 0x2b, 0x48, 0xf4, 0xb8, 0x93, 0x2f, 0x79, + 0x3a, 0x1e, 0xb6, 0x3b, 0x07, 0x3b, 0x1e, 0x15, 0xd7, 0x85, 0x5e, 0xd4, + 0x06, 0x0e, 0xcd, 0x6a, 0x93, 0x3a, 0x93, 0x29, 0x6a, 0xbe, 0x68, 0x8a, + 0xb6, 0xb8, 0xfa, 0xc5, 0x63, 0x48, 0x98, 0x10, 0x6d, 0xd9, 0xd3, 0x5b, + 0x29, 0x5f, 0x93, 0x90, 0x08, 0x1c, 0x1a, 0x15, 0x7b, 0x0a, 0x59, 0x9d, + 0x64, 0x24, 0x45, 0xb6, 0xd3, 0x7b, 0xc1, 0x5d, 0x74, 0x1f, 0x0b, 0x8e, + 0x18, 0xf2, 0x92, 0x8e, 0xd4, 0x7f, 0x72, 0x5c, 0x98, 0x1f, 0x8b, 0xa5, + 0xb8, 0xf4, 0x7e, 0x12, 0x6a, 0x93, 0xb9, 0xb5, 0xf1, 0xda, 0x97, 0x75, + 0x4f, 0x56, 0x80, 0x88, 0x64, 0x2b, 0xe0, 0x59, 0xcd, 0x5e, 0x91, 0x64, + 0x9c, 0x0c, 0xa8, 0xdd, 0xac, 0xcb, 0xf3, 0x48, 0x3b, 0x5c, 0xc4, 0xc5, + 0xb9, 0x9a, 0x0b, 0x8e, 0x5d, 0x9a, 0xd5, 0xb7, 0xf0, 0xd4, 0x07, 0x48, + 0xb9, 0x63, 0x02, 0x87, 0x8d, 0xae, 0x7e, 0x03, 0x33, 0x4f, 0x86, 0x15, + 0x1b, 0x3b, 0xdf, 0xda, 0xce, 0xd3, 0x1e, 0xc0, 0x76, 0xb5, 0x1c, 0xdd, + 0xb8, 0x32, 0x87, 0x7d, 0x59, 0x18, 0x72, 0x0c, 0xde, 0x8f, 0x63, 0x2d, + 0x38, 0xf2, 0xe9, 0xc2, 0x81, 0xed, 0xfa, 0x2d, 0x61, 0xef, 0x48, 0xdb, + 0xa2, 0xeb, 0xfe, 0x52, 0x31, 0x1e, 0x21, 0x0a, 0x08, 0xf6, 0x02, 0xd3, + 0xc0, 0x32, 0x3b, 0x6b, 0x2f, 0x64, 0xc4, 0xb3, 0x4b, 0xfe, 0x69, 0x78, + 0xbf, 0x20, 0x62, 0x07, 0x77, 0xdf, 0x2c, 0x18, 0x53, 0x61, 0x8e, 0x05, + 0x01, 0x86, 0xab, 0xab, 0xec, 0x18, 0x8c, 0x15, 0x63, 0x1f, 0xe9, 0x99, + 0xb2, 0x35, 0x77, 0xe1, 0x58, 0xf1, 0xa9, 0x4d, 0x1a, 0xb9, 0x8c, 0x30, + 0x63, 0x6f, 0x9e, 0x7d, 0x4e, 0xcf, 0xb5, 0x6c, 0xf3, 0xe4, 0xdc, 0xab, + 0xf9, 0xae, 0x58, 0xf8, 0x1d, 0x08, 0x7b, 0x73, 0x82, 0x58, 0xc8, 0x67, + 0x48, 0x1a, 0x5e, 0x3d, 0xdb, 0xac, 0x1b, 0x1b, 0xef, 0xeb, 0xa4, 0xe5, + 0x67, 0x48, 0x76, 0xd1, 0x96, 0x4f, 0x6c, 0x7d, 0x06, 0x8c, 0x02, 0x86, + 0x95, 0x83, 0xb6, 0x9b, 0x5e, 0x9a, 0xb5, 0x85, 0xc0, 0x4f, 0x13, 0x1c, + 0x32, 0xf8, 0x29, 0xdf, 0x47, 0x85, 0xdb, 0xe4, 0x37, 0xdc, 0xd8, 0x04, + 0x18, 0xdd, 0xca, 0x97, 0xdd, 0x67, 0x13, 0xbe, 0x74, 0x95, 0xdc, 0xd0, + 0xcc, 0xe6, 0xb5, 0xa5, 0x12, 0x9b, 0x23, 0x4f, 0x41, 0x8c, 0xcc, 0x95, + 0xf4, 0xb0, 0x5f, 0x2a, 0xc4, 0xbf, 0x88, 0xda, 0x55, 0xcb, 0x13, 0x93, + 0x22, 0x60, 0x51, 0x43, 0xc7, 0x9a, 0x2c, 0xfa, 0xb2, 0x59, 0xc1, 0xe6, + 0x8a, 0xa4, 0xb8, 0xfb, 0xd3, 0x31, 0x1d, 0xc7, 0x88, 0xdc, 0xbc, 0xe9, + 0xba, 0xe7, 0xdc, 0xe3, 0xdd, 0x90, 0x96, 0xb4, 0xb4, 0x0a, 0xc1, 0x07, + 0x31, 0x3f, 0xdb, 0xc5, 0x4d, 0x73, 0x58, 0x86, 0x15, 0x37, 0x07, 0x86, + 0x03, 0x17, 0x16, 0x18, 0x15, 0xb9, 0x26, 0x35, 0x8a, 0x43, 0x22, 0xae, + 0x21, 0x52, 0x05, 0x4e, 0x5c, 0x3f, 0x3e, 0xb9, 0x2a, 0x19, 0x13, 0xfd, + 0x31, 0x47, 0x6a, 0x74, 0xaa, 0xb9, 0xc6, 0x2c, 0x13, 0x8c, 0x21, 0xc4, + 0x8d, 0x00, 0xf4, 0x24, 0xf2, 0xb7, 0xd3, 0x13, 0xad, 0x29, 0x5e, 0x50, + 0x0b, 0x0e, 0x9f, 0x9a, 0xb7, 0xf6, 0x9e, 0xba, 0x12, 0x23, 0x84, 0x8c, + 0xbe, 0x2c, 0x14, 0x1e, 0xe6, 0x79, 0x15, 0x20, 0x2d, 0x32, 0x08, 0xd8, + 0x1c, 0x87, 0x1b, 0xa8, 0xc0, 0xbb, 0x85, 0xa9, 0x71, 0x30, 0x5e, 0x39, + 0x48, 0x87, 0xdc, 0x3d, 0x03, 0x29, 0x19, 0xd1, 0xd4, 0x21, 0x3a, 0x53, + 0x2d, 0x5e, 0x78, 0xff, 0x94, 0x4b, 0x91, 0xa6, 0xb5, 0xe5, 0x42, 0x56, + 0x67, 0x6a, 0x0e, 0xf3, 0x2d, 0x6a, 0x4e, 0xd7, 0x3a, 0x81, 0xb1, 0x4d, + 0x0b, 0x66, 0x5f, 0x43, 0x28, 0x7c, 0x75, 0x8b, 0x2b, 0x99, 0x24, 0xc2, + 0x5e, 0x8c, 0x22, 0xf0, 0xd5, 0xb3, 0xfc, 0x86, 0x62, 0xf3, 0xd2, 0x6c, + 0xa7, 0x48, 0x04, 0x44, 0x5d, 0x93, 0x74, 0x37, 0x16, 0x2c, 0x19, 0x12, + 0x57, 0x49, 0xef, 0xd5, 0xd6, 0x92, 0xdc, 0x51, 0xf8, 0x55, 0x3a, 0xc0, + 0x0b, 0xdf, 0x41, 0xb5, 0x01, 0x59, 0x7e, 0x85, 0x65, 0xdb, 0x44, 0xbd, + 0x04, 0x96, 0x1a, 0xd4, 0x6e, 0x22, 0x54, 0x92, 0xdb, 0xc7, 0xc5, 0x3a, + 0xdf, 0x0c, 0xf4, 0x1b, 0xdc, 0x14, 0xf6, 0x91, 0x9c, 0xbe, 0xf8, 0x8e, + 0x70, 0xd1, 0x3a, 0x0e, 0x58, 0xe6, 0xb9, 0xd3, 0xaa, 0xa2, 0x70, 0xba, + 0xdd, 0x16, 0x13, 0x19, 0xd1, 0x96, 0x78, 0x04, 0x2f, 0xd7, 0x38, 0x8c, + 0x35, 0x1f, 0xfc, 0x58, 0xa4, 0x4c, 0xa9, 0x9a, 0xae, 0x13, 0x3b, 0xc1, + 0x20, 0x4b, 0x66, 0x0f, 0x72, 0x42, 0x0a, 0x53, 0x84, 0x54, 0x71, 0x06, + 0xdb, 0x85, 0x8f, 0x40, 0xa6, 0x09, 0xf7, 0x24, 0xc4, 0x35, 0xf7, 0x1d, + 0xd4, 0x3d, 0x54, 0x75, 0xaf, 0xc4, 0x78, 0x0f, 0xce, 0xe0, 0x0c, 0x90, + 0x0f, 0xd5, 0x2e, 0x61, 0xf7, 0x58, 0xaa, 0xf0, 0xc7, 0x37, 0x5a, 0x59, + 0x1f, 0x8a, 0x03, 0x98, 0x43, 0xb7, 0x27, 0x78, 0x4e, 0x44, 0x5a, 0xb5, + 0x29, 0xf5, 0xab, 0x9e, 0xb7, 0x2a, 0xc4, 0xa3, 0x03, 0x00, 0xe3, 0x28, + 0x57, 0xc9, 0x2a, 0x98, 0xb8, 0xa1, 0x45, 0x1d, 0xfa, 0x6e, 0xb3, 0x0d, + 0x42, 0x5a, 0xb6, 0xb1, 0x0e, 0x5c, 0xbe, 0x82, 0xe2, 0x36, 0x40, 0x4b, + 0x05, 0x28, 0xd9, 0xbc, 0x27, 0xd6, 0x77, 0x00, 0xc9, 0x29, 0x6a, 0xd6, + 0x19, 0x8f, 0x8d, 0xda, 0xe1, 0xc3, 0x8b, 0x69, 0x71, 0xd0, 0xf7, 0xc8, + 0x33, 0xef, 0xe6, 0x23, 0x6b, 0xcb, 0x00, 0x56, 0x0a, 0x9b, 0x9d, 0x60, + 0x3a, 0xd3, 0xad, 0xd9, 0x5c, 0x6a, 0x7d, 0xab, 0x35, 0x71, 0x93, 0xc5, + 0xf2, 0x6a, 0x38, 0x0e, 0xfb, 0xd9, 0x9b, 0xa5, 0xda, 0x52, 0x45, 0xef, + 0x93, 0x94, 0x5b, 0x08, 0x8c, 0x07, 0xab, 0x2e, 0x99, 0x88, 0x77, 0xb5, + 0x15, 0x66, 0x7f, 0x0e, 0xfa, 0xb0, 0x29, 0xe4, 0x88, 0xd9, 0xdd, 0x22, + 0xaf, 0x7a, 0x4e, 0xb5, 0xd0, 0x62, 0x85, 0x27, 0x33, 0xf1, 0xb7, 0x34, + 0xb1, 0xe6, 0xda, 0x9f, 0x3c, 0xfe, 0xf5, 0xd4, 0xef, 0x56, 0x48, 0x93, + 0x7a, 0x54, 0xa2, 0x7f, 0x07, 0xea, 0x31, 0xb8, 0x8b, 0xca, 0xb9, 0xdb, + 0x1e, 0x2b, 0xb5, 0x16, 0xe6, 0x0e, 0xd9, 0x3f, 0x7c, 0xf0, 0xc2, 0x3e, + 0x57, 0x64, 0x60, 0x97, 0xfb, 0xdf, 0x8c, 0x3e, 0x56, 0x22, 0x92, 0x2a, + 0xb2, 0x21, 0x00, 0x0a, 0x75, 0x89, 0x68, 0xe7, 0x51, 0xa3, 0x63, 0x05, + 0xe1, 0x6f, 0x1e, 0x1e, 0x80, 0xa2, 0x4b, 0x5d, 0xb7, 0xf4, 0xb7, 0x45, + 0x85, 0x00, 0x84, 0x6e, 0xbe, 0x0b, 0x67, 0xbf, 0x21, 0x06, 0x5a, 0x56, + 0x79, 0xe9, 0x6b, 0x0e, 0x72, 0x19, 0x2d, 0x09, 0x78, 0xd5, 0x5e, 0xc2, + 0x32, 0xee, 0x29, 0xd4, 0x7a, 0x65, 0xc7, 0xfe, 0x16, 0x86, 0xd2, 0x29, + 0x71, 0xe5, 0x91, 0x0e, 0x3e, 0x86, 0xd5, 0x00, 0xc4, 0xfc, 0xd9, 0xae, + 0xd3, 0x7c, 0x13, 0xfd, 0x62, 0xce, 0x0c, 0xb2, 0xe5, 0x1f, 0x6d, 0xed, + 0x55, 0x6f, 0xc1, 0xaa, 0xa1, 0x74, 0x59, 0x46, 0x83, 0xd5, 0x5d, 0x71, + 0x17, 0x13, 0x1d, 0x0b, 0x25, 0xfb, 0x0a, 0xcd, 0x67, 0xfe, 0x57, 0x93, + 0xc2, 0x71, 0x55, 0x6c, 0x68, 0xfa, 0x40, 0xdb, 0xdd, 0xce, 0xd5, 0x5c, + 0xce, 0x0a, 0x1d, 0xfa, 0x19, 0x30, 0xe2, 0x2b, 0x63, 0x98, 0x16, 0x2c, + 0x67, 0x69, 0x55, 0xe5, 0xc1, 0x6c, 0x6e, 0xb7, 0x92, 0x6a, 0xbb, 0x10, + 0xd3, 0x13, 0x2e, 0x73, 0x91, 0x74, 0xcb, 0x9f, 0x5c, 0x7f, 0x5c, 0x48, + 0x58, 0x36, 0x13, 0x47, 0xf7, 0x49, 0xae, 0x90, 0x15, 0x53, 0xb5, 0xe6, + 0x37, 0xfb, 0x81, 0x47, 0xb4, 0x69, 0x84, 0xca, 0x95, 0xab, 0x19, 0x2a, + 0x28, 0xc2, 0x8a, 0xf1, 0xcd, 0xf9, 0x3e, 0xd3, 0xaf, 0xe1, 0x75, 0xf7, + 0x94, 0x74, 0x1c, 0xf5, 0x32, 0xcf, 0x70, 0xbd, 0x69, 0xcc, 0xa8, 0x3c, + 0xca, 0x59, 0x53, 0xfa, 0xcb, 0xe7, 0xb6, 0x36, 0x70, 0xea, 0xe2, 0x84, + 0xfa, 0x5e, 0xbd, 0xd7, 0x59, 0x3d, 0x21, 0xc6, 0x9f, 0x5c, 0x1f, 0xa6, + 0xa9, 0xf1, 0xd3, 0x26, 0x9e, 0xff, 0xbc, 0x81, 0xfe, 0xbe, 0xee, 0x64, + 0xd9, 0x63, 0x94, 0x4b, 0x15, 0xd8, 0x95, 0xaa, 0xec, 0x10, 0xc9, 0xe2, + 0xe1, 0x05, 0x37, 0x64, 0xc4, 0xb0, 0x2e, 0xa5, 0x0e, 0x4c, 0x2d, 0x03, + 0x53, 0xf1, 0x93, 0x77, 0x9d, 0x46, 0x14, 0x67, 0x48, 0x5f, 0xad, 0x1b, + 0xdc, 0xb9, 0x74, 0xa2, 0x6c, 0xfc, 0xd2, 0xa0, 0x1f, 0x43, 0x89, 0x15, + 0xc5, 0x0c, 0xb0, 0x9e, 0x1e, 0xc2, 0xd6, 0x44, 0xd9, 0x6e, 0xfc, 0xb4, + 0x9c, 0x95, 0x90, 0xcd, 0xc3, 0x17, 0x1c, 0x6a, 0xce, 0x03, 0x56, 0x9f, + 0xe7, 0xcd, 0x7e, 0xe7, 0xa2, 0x0c, 0x2b, 0x0d, 0x59, 0xb0, 0xc9, 0x4c, + 0x6e, 0x33, 0x6d, 0x43, 0xc4, 0x3a, 0x10, 0x24, 0x03, 0x3e, 0x09, 0xb6, + 0x86, 0x13, 0xba, 0x18, 0x19, 0xd3, 0xff, 0xeb, 0xa5, 0x25, 0x8f, 0x6f, + 0xc8, 0xe6, 0x96, 0xa4, 0xd2, 0x66, 0x40, 0x81, 0x79, 0xe8, 0x39, 0x18, + 0x41, 0x02, 0x66, 0x5c, 0x30, 0x5f, 0x58, 0x9d, 0x35, 0x16, 0xc6, 0x96, + 0xa8, 0x68, 0xbc, 0x09, 0x83, 0x17, 0x2c, 0x5f, 0x5e, 0xd0, 0x1d, 0xb0, + 0x48, 0x5e, 0xcf, 0x91, 0x16, 0x4d, 0xa0, 0xba, 0xbc, 0x61, 0xa8, 0x3f, + 0x30, 0x09, 0xbb, 0xa3, 0x12, 0xcd, 0xdc, 0x29, 0xf7, 0xb0, 0xad, 0x05, + 0x17, 0xd6, 0xd3, 0x16, 0xfb, 0xe5, 0x99, 0xf4, 0x71, 0x62, 0xa3, 0x45, + 0x45, 0xc7, 0x9b, 0xaa, 0x45, 0xd3, 0x35, 0xfe, 0xfb, 0x63, 0xaf, 0xe7, + 0x85, 0x31, 0xc9, 0x66, 0x26, 0xa9, 0xda, 0x8c, 0xc6, 0xf6, 0xd5, 0xdf, + 0xb1, 0xa9, 0xf1, 0xb6, 0x3d, 0x92, 0xae, 0x4d, 0xbc, 0x74, 0x7d, 0x76, + 0x5a, 0x59, 0x8c, 0x87, 0xff, 0x95, 0x2f, 0x67, 0x37, 0x30, 0x1a, 0xc1, + 0x23, 0x2e, 0x0c, 0xaa, 0x80, 0x1c, 0xf3, 0xa3, 0x74, 0x94, 0xb2, 0xda, + 0x1a, 0xb8, 0x46, 0xec, 0x30, 0x76, 0xf4, 0xdf, 0xfb, 0x00, 0xb3, 0x6f, + 0x86, 0xc1, 0xc5, 0x3a, 0x5d, 0x11, 0x14, 0x87, 0xeb, 0x30, 0xd8, 0x33, + 0x18, 0x00, 0x01, 0x76, 0x43, 0x82, 0xcd, 0x1c, 0x36, 0x54, 0xd2, 0x64, + 0x5b, 0xfb, 0x93, 0xca, 0x20, 0x1d, 0xa3, 0x20, 0x99, 0xc3, 0x8e, 0x5c, + 0x82, 0xfc, 0x56, 0x07, 0x41, 0x4b, 0x4f, 0x54, 0xc7, 0xb5, 0xe8, 0x6d, + 0x7e, 0xd8, 0x8a, 0x56, 0xb4, 0x76, 0x1e, 0xd3, 0x82, 0x97, 0xdd, 0x2b, + 0xd9, 0x80, 0xb7, 0xb6, 0xeb, 0x3d, 0xe5, 0xe0, 0x20, 0x27, 0x8c, 0xf0, + 0xd6, 0x14, 0xc7, 0xcd, 0x79, 0xbc, 0xa0, 0x21, 0x85, 0xc3, 0x02, 0xae, + 0x73, 0xc4, 0x0a, 0x39, 0x1a, 0x98, 0x61, 0xc3, 0x86, 0xd8, 0x97, 0x67, + 0x87, 0xe9, 0x56, 0x0b, 0x61, 0xa6, 0x7e, 0x07, 0xfb, 0x0a, 0x8b, 0xd1, + 0x90, 0xbd, 0x39, 0x22, 0xdb, 0xc2, 0x7f, 0xaa, 0x79, 0xb7, 0x39, 0x09, + 0xc1, 0x69, 0xdb, 0xe2, 0x7f, 0xec, 0xde, 0x80, 0x7a, 0x6c, 0xde, 0x76, + 0xa4, 0xe8, 0xe0, 0x8d, 0x71, 0xfa, 0x62, 0xf0, 0x2e, 0x7b, 0xf4, 0xce, + 0x65, 0x18, 0x42, 0xde, 0x92, 0x1b, 0xdc, 0xc9, 0xa7, 0x8d, 0xa5, 0x91, + 0x0f, 0xa5, 0x1b, 0x89, 0xcf, 0x29, 0x10, 0x1d, 0x94, 0x78, 0x1b, 0xea, + 0x79, 0x35, 0x62, 0xd4, 0x29, 0xe6, 0x59, 0x8c, 0xc1, 0xd2, 0xf3, 0x32, + 0x71, 0x09, 0xce, 0x51, 0xd7, 0x14, 0x29, 0x92, 0xbf, 0xdf, 0x9a, 0x69, + 0xda, 0x61, 0x03, 0x0f, 0xa2, 0x0a, 0xab, 0x57, 0x1c, 0xca, 0xab, 0x42, + 0x63, 0x63, 0x1e, 0x35, 0x5d, 0x8d, 0xba, 0x6f, 0x4b, 0x6b, 0x5e, 0x7c, + 0xc0, 0x1e, 0xb7, 0xf4, 0x65, 0xbd, 0x13, 0x1c, 0xf2, 0xa9, 0x73, 0x38, + 0xc3, 0x47, 0xc9, 0x32, 0xf0, 0x30, 0x57, 0x05, 0x42, 0x52, 0xac, 0x72, + 0xee, 0x9f, 0x4e, 0x21, 0xbf, 0x38, 0x19, 0x6d, 0x48, 0xec, 0x97, 0xcb, + 0x70, 0x9e, 0xee, 0xb3, 0xa1, 0xaa, 0xa6, 0x7e, 0xe9, 0x16, 0xdf, 0xcd, + 0x1c, 0x56, 0xcf, 0xf0, 0x9f, 0x4d, 0xd1, 0x8c, 0x14, 0x50, 0x5d, 0x23, + 0x96, 0xe0, 0x1f, 0x61, 0x79, 0xbf, 0x44, 0xfd, 0xa2, 0x31, 0xf7, 0x4c, + 0x0c, 0x8d, 0x8c, 0x1b, 0xbf, 0x8d, 0x45, 0xbf, 0x0b, 0xd8, 0xfb, 0x6f, + 0xff, 0x15, 0xc0, 0x44, 0x7c, 0xb9, 0xb8, 0xf9, 0xef, 0x0d, 0x79, 0x11, + 0x3b, 0x79, 0xd2, 0x52, 0x89, 0x5a, 0xcd, 0x0f, 0x10, 0x92, 0x42, 0xfe, + 0xcf, 0x0a, 0x11, 0x8a, 0x8a, 0xda, 0xee, 0xc8, 0x6b, 0xd9, 0xab, 0xec, + 0xb4, 0x25, 0x6f, 0x8d, 0x68, 0x26, 0xe8, 0xdd, 0xf5, 0xa4, 0xe8, 0x65, + 0x37, 0x03, 0xb0, 0xad, 0x73, 0x3b, 0x4d, 0x74, 0x57, 0x7f, 0x0f, 0x6c, + 0xb0, 0x5d, 0x59, 0x80, 0x13, 0xa1, 0x6c, 0xb0, 0xed, 0x26, 0xec, 0x79, + 0x50, 0x5f, 0x5c, 0xb7, 0xa6, 0xae, 0xe8, 0x0a, 0x6d, 0x55, 0x9a, 0x7f, + 0x59, 0x23, 0xa3, 0x7e, 0x84, 0x7b, 0x3b, 0xfc, 0xde, 0xe1, 0xd9, 0x7c, + 0xd6, 0x87, 0xb3, 0x0e, 0xdb, 0xc1, 0x8c, 0x5e, 0x77, 0xb7, 0x23, 0xd7, + 0x14, 0xd4, 0x23, 0xb4, 0xac, 0x45, 0xbf, 0xfe, 0x40, 0x20, 0x4d, 0x91, + 0x20, 0x94, 0xbd, 0x58, 0xb1, 0x99, 0x69, 0xaf, 0x31, 0x68, 0xbd, 0x61, + 0x5e, 0x87, 0x81, 0x54, 0x4e, 0x2d, 0x03, 0xc2, 0xe2, 0xcd, 0xdc, 0x59, + 0xe5, 0x35, 0xcf, 0xb8, 0xfc, 0x65, 0xed, 0x46, 0xb3, 0x92, 0xe7, 0xf8, + 0x3a, 0x32, 0xaa, 0x0e, 0x5a, 0x82, 0x58, 0x4e, 0x77, 0xd8, 0x33, 0xc9, + 0xb0, 0x3e, 0xad, 0xa5, 0x92, 0xe9, 0xa9, 0x8c, 0x00, 0x72, 0x8f, 0xdc, + 0x77, 0x9d, 0x5c, 0x97, 0xd6, 0x58, 0x20, 0x1e, 0xf4, 0x55, 0x2d, 0xc0, + 0x30, 0xf0, 0x66, 0xda, 0x2d, 0x11, 0xac, 0xd4, 0x2d, 0xd5, 0x25, 0x42, + 0x1d, 0xce, 0x49, 0xb5, 0x95, 0x79, 0x9b, 0x6c, 0x65, 0xe0, 0x8a, 0xc5, + 0x9f, 0x75, 0xe3, 0xe6, 0xf8, 0xa6, 0x88, 0xd6, 0x93, 0x70, 0x4f, 0x89, + 0x94, 0x74, 0xbd, 0xef, 0xc2, 0x1a, 0x55, 0x74, 0x37, 0x44, 0x85, 0x1e, + 0xa9, 0xbb, 0x3f, 0x15, 0xc7, 0x84, 0x80, 0xa5, 0xab, 0xc3, 0x91, 0x8e, + 0xd6, 0x32, 0x46, 0x0d, 0xfa, 0xd1, 0x19, 0xd1, 0xfc, 0x02, 0xe2, 0x20, + 0xa6, 0xa9, 0xf7, 0xf4, 0xcc, 0x5b, 0x54, 0x4f, 0x4a, 0x73, 0x35, 0xda, + 0xf0, 0x31, 0x81, 0x1a, 0x82, 0xe7, 0xd4, 0xc8, 0xb4, 0x1d, 0x70, 0xa9, + 0x5d, 0x67, 0xb9, 0x7d, 0x4b, 0xcd, 0xa4, 0x81, 0xf9, 0xb2, 0x38, 0x07, + 0x16, 0xd5, 0x28, 0x82, 0xb9, 0x76, 0x5b, 0xa1, 0x09, 0x7a, 0xe7, 0x2a, + 0xcf, 0xc0, 0x3d, 0x2a, 0x42, 0x9a, 0xf3, 0xc8, 0x64, 0x15, 0x7c, 0x94, + 0xd0, 0x97, 0xee, 0x34, 0xb6, 0xf0, 0xb2, 0xba, 0x7e, 0xb2, 0xbb, 0x4e, + 0xbf, 0x88, 0xd0, 0x6b, 0xc5, 0x9c, 0xb9, 0xf2, 0x7d, 0xbf, 0x5d, 0x87, + 0xbc, 0x36, 0x4a, 0xd1, 0x1b, 0x6f, 0x40, 0x09, 0xba, 0x26, 0x51, 0xd6, + 0xc0, 0xaf, 0x27, 0xce, 0x27, 0x8d, 0x93, 0xa8, 0x6c, 0x91, 0xe7, 0x91, + 0x42, 0xc0, 0x68, 0x36, 0x5b, 0xd5, 0x56, 0x4c, 0xe2, 0x77, 0xc3, 0xac, + 0x56, 0xe3, 0x1c, 0xc2, 0xf9, 0x78, 0x02, 0x39, 0x7d, 0xed, 0x18, 0x2a, + 0x01, 0x48, 0xe6, 0xf6, 0x7e, 0x34, 0x50, 0xf4, 0x57, 0x56, 0x93, 0xdb, + 0x85, 0x1b, 0x1e, 0x1a, 0x6f, 0x3e, 0x07, 0x3c, 0xad, 0x3f, 0x8d, 0x75, + 0x53, 0xc3, 0x20, 0x72, 0x93, 0x28, 0xd2, 0x86, 0xc8, 0xa5, 0x90, 0xf2, + 0x5f, 0x13, 0xd5, 0xa5, 0xbe, 0x88, 0x9e, 0x9a, 0x57, 0x2c, 0x53, 0x3f, + 0x11, 0x25, 0x00, 0x00, 0x4a, 0x16, 0x8d, 0xd3, 0x3f, 0x2d, 0x3d, 0x88, + 0xbb, 0x4c, 0x4f, 0x9a, 0xb9, 0x97, 0x5f, 0xed, 0x71, 0xa9, 0x68, 0xd9, + 0x4a, 0x14, 0x24, 0xc7, 0xbe, 0xff, 0x85, 0x57, 0xa3, 0x21, 0xe3, 0x21, + 0x79, 0x1f, 0xd0, 0xbb, 0xb7, 0x73, 0xde, 0x60, 0x02, 0x4b, 0x8f, 0x7d, + 0xb3, 0xb3, 0x8a, 0xda, 0x4c, 0xf4, 0xb8, 0xf1, 0x31, 0xff, 0x32, 0x7b, + 0xd8, 0xfa, 0xb1, 0xcb, 0xb4, 0x58, 0xf5, 0xc8, 0x64, 0xdf, 0xfe, 0x3d, + 0x89, 0x52, 0x5c, 0x52, 0x95, 0xf3, 0xba, 0x0d, 0x1d, 0x2c, 0xc4, 0xf7, + 0x3c, 0x3b, 0x6f, 0x8e, 0xc7, 0xab, 0xad, 0x3d, 0x3d, 0x95, 0x9b, 0xc7, + 0x71, 0x36, 0xae, 0x08, 0xc3, 0x08, 0x79, 0xfa, 0x24, 0xee, 0xd9, 0xf9, + 0x63, 0xc7, 0xd9, 0x16, 0x19, 0x8e, 0x0d, 0xaf, 0x52, 0x87, 0x86, 0x7d, + 0xec, 0xe5, 0xea, 0x5a, 0xda, 0x86, 0x9d, 0x0e, 0x50, 0x53, 0x8c, 0x24, + 0xa8, 0x69, 0xc4, 0xf3, 0x85, 0x7b, 0x34, 0x67, 0x19, 0x35, 0xec, 0xd4, + 0xd4, 0x50, 0xe0, 0xe6, 0xe9, 0x29, 0x5b, 0x92, 0xee, 0xba, 0xa9, 0xef, + 0xf6, 0x35, 0x23, 0x8b, 0xdb, 0x48, 0x32, 0x25, 0x41, 0xf3, 0x55, 0x12, + 0x33, 0xc3, 0x6c, 0xed, 0x32, 0xe1, 0x64, 0x7a, 0x8d, 0xa2, 0x19, 0x5a, + 0x26, 0xf2, 0x83, 0xf1, 0xe4, 0x27, 0xdb, 0x67, 0xc3, 0x89, 0x37, 0xea, + 0x78, 0x19, 0xc6, 0xa3, 0x82, 0x84, 0x1c, 0xf3, 0x2b, 0xbe, 0xde, 0xba, + 0xe7, 0x60, 0x2e, 0xf5, 0x4e, 0xb6, 0x73, 0x29, 0xac, 0xc7, 0x55, 0xab, + 0x21, 0xe9, 0x95, 0x78, 0xd5, 0x8e, 0x27, 0xdc, 0x92, 0x5f, 0xc0, 0xcb, + 0xee, 0x66, 0x09, 0x0a, 0xfc, 0x94, 0x43, 0x44, 0x50, 0x35, 0x57, 0xf8, + 0x08, 0xf9, 0x97, 0xa2, 0x0e, 0xde, 0x81, 0xe1, 0xd1, 0xa0, 0x41, 0xfe, + 0xe6, 0x08, 0x6c, 0x98, 0x8c, 0x81, 0x46, 0x0e, 0xf9, 0x9a, 0x54, 0xfe, + 0xc3, 0x91, 0xe3, 0xd4, 0x46, 0xca, 0x52, 0xa2, 0x73, 0x9e, 0x4d, 0xa7, + 0xfd, 0xa1, 0x8e, 0x43, 0x28, 0xf5, 0xa3, 0xa2, 0x62, 0x20, 0x53, 0x62, + 0x05, 0x49, 0xba, 0x06, 0xe2, 0xeb, 0xba, 0xfb, 0x8e, 0xa0, 0x22, 0xc7, + 0xf9, 0xcc, 0x7f, 0x8b, 0xa8, 0x5d, 0x55, 0xd2, 0x24, 0xff, 0xdd, 0x2c, + 0xc1, 0xd0, 0x3d, 0xe4, 0x79, 0xea, 0xba, 0x62, 0xe5, 0xa2, 0x62, 0xf4, + 0x1f, 0xec, 0xb0, 0x07, 0xf2, 0x0d, 0x32, 0x84, 0x86, 0x81, 0x3d, 0x95, + 0xc1, 0x64, 0xfe, 0x9a, 0x3d, 0x8f, 0x4b, 0x6d, 0xfb, 0x0d, 0x42, 0xcf, + 0xbf, 0xdb, 0x51, 0xb2, 0x16, 0xa2, 0x35, 0xaa, 0xe7, 0x31, 0x54, 0xc2, + 0x87, 0xc6, 0xa5, 0x30, 0x71, 0x64, 0x65, 0xff, 0x41, 0x20, 0xb0, 0x83, + 0xdb, 0xb7, 0x95, 0xce, 0xd7, 0xcc, 0x7a, 0x77, 0xad, 0xb8, 0xb7, 0x4c, + 0xfc, 0x11, 0x05, 0x2b, 0xc4, 0xd4, 0xb6, 0x8b, 0xae, 0x13, 0xa5, 0x40, + 0x18, 0x6e, 0x0d, 0xe3, 0xc6, 0xb0, 0x81, 0x46, 0x46, 0x7e, 0x52, 0x0b, + 0x85, 0x4d, 0x98, 0xd9, 0x42, 0xdf, 0xde, 0x45, 0xc1, 0x5a, 0x33, 0x12, + 0x46, 0x26, 0xb3, 0x6f, 0xf2, 0x8b, 0x37, 0x6b, 0xfd, 0x08, 0xf4, 0x46, + 0x86, 0x89, 0x63, 0x63, 0x21, 0xe5, 0xa9, 0xb7, 0xd0, 0x09, 0x17, 0x52, + 0xee, 0xea, 0xdf, 0x97, 0xb7, 0x73, 0x2e, 0x54, 0x2c, 0x7b, 0x70, 0xd3, + 0xda, 0x26, 0x57, 0x1f, 0xb0, 0x19, 0xd9, 0x91, 0x18, 0x69, 0x75, 0x42, + 0x63, 0xcf, 0x6c, 0x8c, 0x98, 0x5e, 0x17, 0x99, 0x7e, 0x1d, 0xdc, 0x67, + 0x6d, 0x99, 0xd9, 0x02, 0x6e, 0x73, 0x90, 0x5a, 0x4f, 0x0a, 0xb4, 0x48, + 0xfb, 0xc5, 0xbd, 0xd2, 0x10, 0x05, 0xa6, 0x12, 0x68, 0x36, 0x28, 0x51, + 0x60, 0x1c, 0xa1, 0xe9, 0x90, 0x54, 0xa5, 0x53, 0xc3, 0x48, 0x9e, 0xd8, + 0x42, 0x52, 0x85, 0x0e, 0xff, 0xfe, 0xbf, 0xad, 0x3a, 0xa4, 0x57, 0x09, + 0x13, 0x38, 0x64, 0x15, 0x7c, 0xfd, 0xed, 0x91, 0x76, 0x44, 0x20, 0x84, + 0xd9, 0x90, 0xab, 0xfe, 0xfd, 0xd6, 0xab, 0xf1, 0xb3, 0x25, 0x21, 0x3d, + 0x97, 0x72, 0xb2, 0x95, 0xc5, 0x22, 0x80, 0xd9, 0x4a, 0x49, 0x9d, 0x99, + 0xc2, 0x4a, 0x9a, 0x59, 0xb3, 0x71, 0x75, 0x5b, 0xf9, 0x89, 0x7a, 0xdd, + 0xa9, 0xb3, 0xc3, 0xeb, 0x42, 0x91, 0xe2, 0x97, 0x30, 0x40, 0x48, 0x68, + 0x19, 0x3b, 0xf5, 0x7b, 0x4e, 0x33, 0x4b, 0x0c, 0xf3, 0xed, 0xda, 0x76, + 0x3f, 0xb0, 0x4b, 0x53, 0x85, 0x04, 0x33, 0x07, 0x53, 0xd8, 0x55, 0xa2, + 0xfb, 0x30, 0x2c, 0x66, 0xbd, 0x21, 0xf8, 0xfa, 0x20, 0x14, 0x9a, 0x0d, + 0x7f, 0xc9, 0x2f, 0x5b, 0x34, 0x29, 0x09, 0x16, 0xb5, 0x0a, 0x8d, 0xdf, + 0xa2, 0x84, 0x9a, 0xae, 0xe6, 0xa0, 0x50, 0x80, 0x31, 0x04, 0xd3, 0x0c, + 0x8f, 0xd1, 0x8a, 0xfd, 0xb4, 0xa5, 0xae, 0xf5, 0x3c, 0x62, 0xae, 0x45, + 0x70, 0xbb, 0x54, 0x62, 0xc8, 0x50, 0x71, 0x42, 0x85, 0xf6, 0x6f, 0xa0, + 0xf0, 0x10, 0x8a, 0x09, 0xbd, 0x71, 0x78, 0xa6, 0x5e, 0xe4, 0x03, 0x8f, + 0x3b, 0xd0, 0x5c, 0x37, 0x55, 0x1a, 0xc8, 0x57, 0x26, 0x62, 0x6c, 0xc4, + 0x67, 0x71, 0x9d, 0x97, 0xc0, 0xea, 0x35, 0x3e, 0x12, 0xd0, 0x2b, 0xc2, + 0x8f, 0x9e, 0xa6, 0x41, 0x48, 0x33, 0x83, 0x38, 0x37, 0x7e, 0xd4, 0xe3, + 0xee, 0x94, 0x8b, 0x81, 0xa4, 0x60, 0xdd, 0xdd, 0xc1, 0x8a, 0x7b, 0xda, + 0xa8, 0x46, 0xb8, 0x42, 0x3a, 0x25, 0xd6, 0x81, 0x89, 0x29, 0x21, 0xc2, + 0x0c, 0x5b, 0xfd, 0x3e, 0x8c, 0x65, 0x91, 0x52, 0xb3, 0x74, 0x1f, 0xd1, + 0x49, 0x7e, 0x1d, 0x59, 0x58, 0x96, 0xb5, 0xee, 0x32, 0xa4, 0xa8, 0x07, + 0x7c, 0xd1, 0x5b, 0x4b, 0xf8, 0x43, 0x5a, 0xa5, 0xcc, 0x60, 0xcc, 0x08, + 0x6a, 0x3c, 0x41, 0x66, 0x99, 0xe3, 0xa8, 0xe0, 0xb8, 0x87, 0xfc, 0x92, + 0xc0, 0x79, 0xc5, 0x3f, 0xd6, 0xc6, 0x8c, 0x01, 0xf4, 0xa5, 0x05, 0xad, + 0x51, 0xed, 0x04, 0xd7, 0x55, 0xc0, 0x73, 0x05, 0x0e, 0x73, 0xe5, 0x39, + 0x45, 0x5b, 0x95, 0x4a, 0x34, 0x07, 0x99, 0xdf, 0x4c, 0x35, 0xf5, 0x0c, + 0x27, 0x6d, 0xd1, 0x45, 0xf1, 0xfd, 0x24, 0xb7, 0xfe, 0xea, 0x11, 0x5d, + 0xa2, 0xc5, 0xa6, 0x81, 0x37, 0x1d, 0xc2, 0x31, 0x31, 0xfc, 0xe0, 0xf4, + 0xd7, 0xe9, 0x98, 0x8b, 0xe3, 0x70, 0x51, 0x62, 0xc8, 0x61, 0x6d, 0xec, + 0x75, 0x56, 0x71, 0xae, 0x88, 0xe0, 0x80, 0xf5, 0xb7, 0x85, 0x10, 0xb7, + 0x3d, 0x16, 0x78, 0x5f, 0x72, 0xab, 0x8f, 0x63, 0xc6, 0xd5, 0xa8, 0xc9, + 0x9c, 0xef, 0x8d, 0x9a, 0xc5, 0x4f, 0x63, 0xad, 0xc0, 0xf3, 0x1f, 0x69, + 0x0e, 0xce, 0x29, 0x92, 0xc1, 0x3b, 0xb0, 0xc5, 0xed, 0x0a, 0x7b, 0x92, + 0xd0, 0x4c, 0x9c, 0x82, 0xb0, 0x51, 0xf6, 0x33, 0x61, 0x3b, 0x76, 0x48, + 0x38, 0xf4, 0x7c, 0xaa, 0x52, 0x87, 0x15, 0x1a, 0xbe, 0xb8, 0xdc, 0x9b, + 0x16, 0xd2, 0x07, 0xf7, 0xf9, 0x74, 0xe0, 0xaf, 0x0e, 0x29, 0x05, 0xec, + 0x6c, 0x0e, 0x3b, 0xa7, 0xe7, 0xa4, 0xfc, 0xa4, 0xef, 0x57, 0x16, 0x7f, + 0x13, 0xbd, 0x8c, 0x42, 0x02, 0x55, 0x70, 0x56, 0xa5, 0xa9, 0x01, 0x29, + 0x12, 0x7d, 0x80, 0x46, 0x18, 0x8e, 0x39, 0x3f, 0x44, 0x55, 0xec, 0xef, + 0x60, 0x58, 0x7d, 0xce, 0x64, 0x8e, 0x9c, 0xea, 0xe4, 0x73, 0xd1, 0x48, + 0x9c, 0x3f, 0x92, 0xa0, 0x9a, 0x76, 0xa5, 0x5a, 0x13, 0x1f, 0x10, 0xb9, + 0xb7, 0xb1, 0xde, 0x49, 0x22, 0x58, 0xf4, 0x43, 0x5f, 0x03, 0x43, 0xc3, + 0x6c, 0xbf, 0x82, 0xaf, 0x88, 0x39, 0xfd, 0xb2, 0x28, 0x9b, 0x47, 0x3f, + 0x83, 0x3d, 0xd9, 0x7c, 0xf0, 0xc9, 0xc5, 0xa2, 0xb4, 0xd6, 0x0d, 0x59, + 0x51, 0x27, 0x60, 0x10, 0x5e, 0xbb, 0x18, 0xa6, 0x42, 0x4a, 0x9d, 0xc4, + 0x16, 0x0e, 0xb6, 0x57, 0x23, 0x03, 0x24, 0x27, 0xdc, 0x20, 0x56, 0x30, + 0x8b, 0x0f, 0xb6, 0xb7, 0x73, 0xf5, 0x36, 0x3e, 0xf6, 0x7a, 0x71, 0xa5, + 0x57, 0xcc, 0x6d, 0xc6, 0xf3, 0xdc, 0x35, 0xfb, 0x95, 0xf7, 0xa7, 0xd7, + 0x56, 0x38, 0xd4, 0x15, 0xe2, 0xd5, 0x6f, 0x70, 0x30, 0xc8, 0x7d, 0x8a, + 0x87, 0xe6, 0xd1, 0xe0, 0x50, 0x62, 0xde, 0xfa, 0x29, 0x40, 0x97, 0xa0, + 0x54, 0x63, 0x31, 0xd3, 0x08, 0x87, 0x0a, 0xdc, 0x6e, 0x5e, 0xab, 0x8d, + 0x16, 0xaf, 0x6e, 0x8b, 0x1a, 0x77, 0xf6, 0xd4, 0xe0, 0xbf, 0x59, 0xab, + 0xc7, 0xb0, 0x45, 0x18, 0xaa, 0xe6, 0x65, 0x6f, 0x7d, 0x13, 0xb2, 0xbf, + 0xb3, 0x66, 0x72, 0xfa, 0xfd, 0xee, 0xad, 0x07, 0x56, 0x51, 0x6a, 0xe2, + 0xff, 0xb2, 0xaf, 0x4d, 0xd1, 0xf2, 0x77, 0x35, 0x5e, 0x90, 0xcd, 0xe7, + 0xa8, 0x32, 0x4d, 0x9f, 0xbd, 0xa8, 0xce, 0xab, 0xf1, 0x49, 0x98, 0xb5, + 0x23, 0x5c, 0x62, 0x2d, 0x43, 0x31, 0x80, 0x87, 0xc2, 0xa8, 0xf5, 0xb9, + 0xb6, 0xae, 0x7f, 0x37, 0x13, 0xb8, 0x6b, 0x73, 0xf3, 0x56, 0x38, 0xa7, + 0x9b, 0x97, 0x69, 0x37, 0x00, 0xdc, 0xff, 0xfe, 0x58, 0xc9, 0x12, 0x47, + 0x75, 0x98, 0x1f, 0xad, 0xd8, 0xb5, 0xc8, 0x47, 0x4f, 0xd0, 0x72, 0x63, + 0x54, 0x25, 0x6c, 0x88, 0xc9, 0x9f, 0x3c, 0x82, 0xe0, 0xdd, 0x4c, 0xff, + 0x8e, 0xaf, 0x8f, 0x8e, 0xea, 0x84, 0x3f, 0x73, 0xdd, 0x9e, 0x18, 0x73, + 0x47, 0x70, 0xc7, 0xc7, 0x99, 0x65, 0xcf, 0xf3, 0xb6, 0x24, 0xed, 0x97, + 0x8f, 0xcd, 0x93, 0x1e, 0xff, 0x6e, 0x9c, 0xf1, 0x30, 0x14, 0x1a, 0x27, + 0x59, 0x6a, 0x0e, 0xf3, 0xe4, 0xfa, 0x1d, 0x65, 0xb5, 0x53, 0xe4, 0xab, + 0xb1, 0x3e, 0xe1, 0x91, 0xf4, 0x6d, 0x99, 0xca, 0x7d, 0x03, 0x08, 0x50, + 0xea, 0xa9, 0x39, 0x7f, 0x6d, 0xe7, 0x43, 0xfb, 0x64, 0xcc, 0x4b, 0x9e, + 0xa0, 0x26, 0xe4, 0x0e, 0xff, 0xb7, 0x11, 0x0a, 0x29, 0x50, 0x90, 0xd7, + 0x4d, 0x62, 0x9a, 0x4a, 0x23, 0xb7, 0xd3, 0x53, 0xde, 0x3a, 0xd1, 0xba, + 0xd3, 0x10, 0x59, 0xc6, 0xc5, 0x5e, 0xac, 0xf9, 0x61, 0x74, 0x54, 0xf4, + 0x27, 0x9f, 0x9a, 0x61, 0x13, 0xdc, 0xe5, 0x96, 0xe3, 0x95, 0x0d, 0xcc, + 0xbd, 0x81, 0x74, 0x79, 0x73, 0xef, 0x2e, 0x0b, 0x0f, 0x91, 0x65, 0x3c, + 0x26, 0x7c, 0x47, 0x10, 0x31, 0x0b, 0xfb, 0x41, 0x0c, 0xc2, 0xa8, 0xc4, + 0x0e, 0xbd, 0x0a, 0x8c, 0xa4, 0x80, 0x45, 0x57, 0x62, 0x0b, 0x4d, 0x44, + 0x5e, 0x59, 0x77, 0xfd, 0x3d, 0xf3, 0xd7, 0x92, 0x49, 0xc1, 0xcb, 0x8a, + 0x54, 0x56, 0x3b, 0xde, 0xcf, 0x16, 0x9a, 0x65, 0xbe, 0xac, 0x64, 0xe1, + 0xd4, 0xd4, 0x1e, 0xac, 0x6b, 0x4a, 0xad, 0xc4, 0x33, 0xac, 0xcb, 0x83, + 0xf4, 0x4d, 0xe8, 0xb6, 0xd7, 0x23, 0xd7, 0x71, 0x25, 0xa2, 0x25, 0x3d, + 0x7e, 0xf0, 0x3b, 0x7f, 0x61, 0x11, 0x56, 0xd4, 0x83, 0xc8, 0xc0, 0x29, + 0x38, 0x10, 0x73, 0xad, 0x6a, 0xb7, 0xb9, 0xd2, 0x2e, 0x9f, 0xae, 0x16, + 0x5e, 0xa6, 0x13, 0x1c, 0xc2, 0x17, 0x73, 0x43, 0x03, 0xdd, 0xa6, 0xaf, + 0x9a, 0x17, 0x31, 0xb8, 0x86, 0x97, 0xc2, 0xd6, 0xe6, 0xed, 0xd4, 0xe1, + 0x7d, 0xb9, 0xa6, 0x96, 0xc1, 0x4b, 0xcb, 0x11, 0x1e, 0xe1, 0xe0, 0xd2, + 0x28, 0x69, 0x68, 0x3b, 0x21, 0x17, 0x63, 0x0c, 0xc0, 0x49, 0x30, 0x22, + 0x3a, 0x59, 0x72, 0xe6, 0x47, 0xb4, 0xdc, 0xa8, 0x29, 0x1c, 0x89, 0xa6, + 0x3a, 0x77, 0x99, 0xea, 0x46, 0xce, 0x38, 0xda, 0x31, 0x88, 0xad, 0xe7, + 0x26, 0xce, 0xc6, 0x56, 0x04, 0x30, 0xfa, 0x01, 0xac, 0xbb, 0xe2, 0xb8, + 0x23, 0xe4, 0x9d, 0x4f, 0x77, 0x02, 0x00, 0x28, 0xf1, 0xe0, 0x19, 0x3f, + 0x22, 0x4f, 0x22, 0x69, 0x87, 0xc0, 0x4e, 0x26, 0x33, 0xfe, 0x6c, 0x70, + 0x56, 0x3b, 0x60, 0x5f, 0xfb, 0xf8, 0x43, 0xcf, 0x3f, 0xb9, 0xcb, 0x80, + 0x22, 0xbb, 0x0a, 0xa8, 0x1c, 0x3e, 0x7e, 0x4d, 0x42, 0x60, 0x5c, 0x8e, + 0xfa, 0x42, 0xb3, 0x95, 0xe7, 0x92, 0x6b, 0xec, 0x7a, 0x95, 0x88, 0x98, + 0xe3, 0xf9, 0x0d, 0xe5, 0x08, 0xf1, 0x26, 0x96, 0x2a, 0x81, 0x2b, 0x7c, + 0x0d, 0x12, 0xa0, 0x7f, 0x7b, 0x39, 0xf6, 0xcc, 0x1b, 0x2d, 0x2c, 0xe9, + 0x5b, 0x02, 0x9b, 0x5c, 0x94, 0x51, 0x13, 0xe8, 0xa0, 0x19, 0xce, 0xde, + 0x07, 0x1b, 0xda, 0x39, 0x14, 0xb5, 0x8b, 0xcf, 0x79, 0x3e, 0x2b, 0xb8, + 0x75, 0xab, 0x81, 0xee, 0x5e, 0x08, 0x33, 0xc3, 0x49, 0x5b, 0x4a, 0x9c, + 0x74, 0x34, 0xde, 0x08, 0x61, 0x03, 0x38, 0xe3, 0xd8, 0xff, 0xc5, 0xc0, + 0xb5, 0x40, 0xd5, 0x26, 0x57, 0x85, 0xf1, 0xb7, 0x77, 0xb6, 0x36, 0xe0, + 0x8d, 0x43, 0x3a, 0xef, 0xfe, 0x0f, 0xf7, 0xee, 0x67, 0x6c, 0x7b, 0xd1, + 0x83, 0xf6, 0x10, 0xda, 0x67, 0x04, 0x3a, 0x27, 0xd8, 0x3a, 0xcb, 0x9d, + 0x4c, 0xa6, 0x9a, 0xc7, 0xea, 0x07, 0xc6, 0x76, 0x79, 0x1b, 0x23, 0x4a, + 0x68, 0x2f, 0x14, 0x84, 0x42, 0x79, 0xe8, 0x1f, 0xf2, 0xe6, 0xac, 0x72, + 0xb0, 0xb0, 0xb6, 0x39, 0x95, 0x40, 0xa4, 0x6e, 0x54, 0x2e, 0xb7, 0xb5, + 0x13, 0x70, 0x48, 0x0d, 0x27, 0xed, 0x2c, 0xa2, 0x64, 0x53, 0xb4, 0x04, + 0x84, 0xab, 0xd8, 0xea, 0x2a, 0x8c, 0xac, 0x5b, 0x1d, 0xb8, 0xb2, 0xbe, + 0x55, 0x2b, 0x4a, 0x47, 0xfc, 0xe0, 0x15, 0x78, 0xb6, 0xd6, 0xff, 0x20, + 0xa8, 0x8a, 0xec, 0x8b, 0x30, 0xef, 0xc5, 0xc6, 0xec, 0xa0, 0xdf, 0xd3, + 0xc4, 0x2b, 0x4a, 0xdf, 0xef, 0x5c, 0x46, 0xb3, 0x31, 0xc7, 0x5f, 0x8f, + 0x1e, 0x99, 0x76, 0x81, 0x71, 0x61, 0xdb, 0xc3, 0xc4, 0x0f, 0x66, 0x7b, + 0xd7, 0x44, 0xc7, 0x8d, 0x12, 0x38, 0x71, 0x7c, 0xd8, 0x41, 0xf6, 0x8a, + 0xb9, 0xba, 0xd2, 0x1f, 0xa1, 0x27, 0x64, 0x67, 0x51, 0xb2, 0xaf, 0xea, + 0x02, 0x95, 0x79, 0x20, 0x0a, 0xc8, 0xaa, 0x03, 0x11, 0xb6, 0x8b, 0x7d, + 0x86, 0xb7, 0xef, 0x5e, 0x3f, 0x0b, 0x91, 0x47, 0xf0, 0x43, 0xb4, 0x54, + 0x1d, 0x16, 0x66, 0xe9, 0x63, 0x1a, 0x55, 0xaf, 0x34, 0xad, 0x11, 0x68, + 0x4d, 0x36, 0xb7, 0x0c, 0x6d, 0x4d, 0xed, 0xba, 0x14, 0xe8, 0xf6, 0xe2, + 0x15, 0x64, 0xb6, 0x15, 0x28, 0xbf, 0xd2, 0x4d, 0xb6, 0x6f, 0xca, 0x5f, + 0x81, 0x1b, 0xf0, 0x31, 0xf5, 0xd3, 0xe0, 0x06, 0xc7, 0xf3, 0x0c, 0x18, + 0x91, 0x45, 0x22, 0xa2, 0x30, 0x48, 0x82, 0xeb, 0x42, 0xfc, 0x8f, 0x2a, + 0xa3, 0x1a, 0x8d, 0x84, 0x28, 0x20, 0x16, 0x95, 0xd9, 0x66, 0x67, 0x2b, + 0xef, 0xc6, 0x6e, 0x56, 0x1c, 0x62, 0x74, 0x16, 0x5c, 0x3e, 0x17, 0xd0, + 0xb7, 0xdd, 0x70, 0xb6, 0x0e, 0x79, 0x46, 0xc5, 0x4e, 0x72, 0x46, 0x69, + 0xf5, 0xa1, 0x1c, 0x7b, 0xd5, 0x67, 0x5c, 0xb3, 0x46, 0x4d, 0x18, 0x31, + 0x47, 0x42, 0x20, 0xe6, 0x12, 0x84, 0x4e, 0x16, 0x0f, 0x4a, 0xd0, 0xc4, + 0x91, 0xa3, 0xbd, 0x91, 0xcd, 0x86, 0x4c, 0xcd, 0x4b, 0x2e, 0x62, 0x84, + 0xea, 0x19, 0x2d, 0x21, 0x1a, 0x64, 0xc4, 0xd2, 0x24, 0x92, 0x96, 0x04, + 0x66, 0xb5, 0x4a, 0xe4, 0xa9, 0xd6, 0xaf, 0x12, 0x9b, 0xb5, 0x59, 0xe0, + 0x5c, 0x84, 0x84, 0x7c, 0x68, 0x99, 0xd8, 0x23, 0xa2, 0x15, 0xa7, 0x82, + 0xa5, 0x66, 0x95, 0x8f, 0xfe, 0x57, 0xc1, 0x12, 0x6c, 0x89, 0xe5, 0x5b, + 0x5d, 0x64, 0xdb, 0x81, 0x4f, 0x77, 0x3c, 0xc8, 0x52, 0x4e, 0x2a, 0xd6, + 0x74, 0x3c, 0x4b, 0x11, 0xfc, 0xc1, 0x7c, 0x01, 0xba, 0x0f, 0x0f, 0x57, + 0x8a, 0xbe, 0x5b, 0x16, 0x88, 0x96, 0xe6, 0xe9, 0x60, 0xcf, 0x66, 0xe9, + 0xe6, 0x07, 0xb0, 0x0b, 0xa3, 0xa0, 0xad, 0xdf, 0x70, 0xd4, 0xcb, 0x2e, + 0x33, 0x2f, 0xe5, 0xf2, 0x1e, 0x0d, 0x74, 0x7a, 0xf9, 0x4a, 0x0f, 0x32, + 0xb4, 0xa1, 0xc9, 0xf5, 0x3f, 0x0a, 0x06, 0xf9, 0x67, 0x45, 0x9c, 0xd9, + 0x58, 0xd4, 0x0e, 0x72, 0x55, 0x47, 0x49, 0x9b, 0xab, 0x9c, 0x66, 0xe7, + 0x4d, 0x9a, 0x02, 0x1b, 0x41, 0xad, 0xe5, 0x8c, 0x7f, 0xa1, 0xdc, 0xad, + 0xcd, 0x74, 0xda, 0x9f, 0xfa, 0x87, 0x32, 0xc1, 0x07, 0x8e, 0x9b, 0xef, + 0x28, 0x2f, 0x17, 0x6d, 0xdb, 0x84, 0x4b, 0xa8, 0x7d, 0x31, 0xa8, 0x32, + 0xe4, 0x9a, 0x1e, 0x0e, 0xef, 0x68, 0xf4, 0xac, 0x03, 0x6c, 0x68, 0xcc, + 0x28, 0xbb, 0xfb, 0x21, 0xb8, 0x11, 0xd7, 0xf9, 0xe8, 0x24, 0x37, 0xdf, + 0xe0, 0xb2, 0xef, 0xd6, 0xec, 0xdf, 0xcf, 0xf5, 0x50, 0x19, 0xa3, 0xa9, + 0x1b, 0x01, 0x2e, 0x94, 0x42, 0xb0, 0x14, 0x5d, 0x0e, 0x37, 0x46, 0x4a, + 0x52, 0x53, 0x60, 0x6b, 0x89, 0xc9, 0xca, 0xed, 0x0a, 0x0c, 0x18, 0x33, + 0x3c, 0x40, 0x42, 0x76, 0x7a, 0x7d, 0xb6, 0x10, 0x29, 0x3e, 0x42, 0x75, + 0xa6, 0xbf, 0xcb, 0xd3, 0xdc, 0xe1, 0x00, 0x05, 0x08, 0x25, 0x67, 0x6c, + 0x72, 0xde, 0x26, 0x72, 0x88, 0xbe, 0xfa, 0x05, 0x57, 0x77, 0x78, 0x83, + 0xce, 0xd5, 0x44, 0x49, 0x8b, 0xab, 0xbc, 0xca, 0xd3, 0x1c, 0x34, 0x4a, + 0xaa, 0xc7, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x17, 0x22, 0x2a, 0x2f, 0x36, 0x3d, 0x43}; +#endif /* !MLD_CONFIG_KEYGEN_PCT */ +#endif /* !EXPECTED_SIGNATURES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/main.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/main.c new file mode 100644 index 0000000000..6b2bb28bc5 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/main.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include +#include +#include + +#include "expected_signatures.h" +#include "mldsa_native_all.h" +#include "test_only_rng/notrandombytes.h" + +#define CHECK(x) \ + do \ + { \ + int rc; \ + rc = (x); \ + if (!rc) \ + { \ + fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \ + return 1; \ + } \ + } while (0) + +#define TEST_MSG \ + "This is a test message for ML-DSA digital signature algorithm!" +#define TEST_MSG_LEN (sizeof(TEST_MSG) - 1) + +#define TEST_CTX "test_context_123" +#define TEST_CTX_LEN (sizeof(TEST_CTX) - 1) + +static int test_mldsa44(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[MLDSA44_PUBLICKEYBYTES]; + uint8_t sk[MLDSA44_SECRETKEYBYTES]; + uint8_t sig[MLDSA44_BYTES]; + uint8_t sm[TEST_MSG_LEN + MLDSA44_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + MLDSA44_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-44\n"); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(mldsa44_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(mldsa44_signature(sig, &siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(mldsa44_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(mldsa44_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(mldsa44_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", MLDSA44_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", MLDSA44_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", MLDSA44_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature_44)); + CHECK(memcmp(sig, expected_signature_44, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} + +static int test_mldsa65(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[MLDSA65_PUBLICKEYBYTES]; + uint8_t sk[MLDSA65_SECRETKEYBYTES]; + uint8_t sig[MLDSA65_BYTES]; + uint8_t sm[TEST_MSG_LEN + MLDSA65_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + MLDSA65_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-65\n"); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(mldsa65_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(mldsa65_signature(sig, &siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(mldsa65_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(mldsa65_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(mldsa65_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", MLDSA65_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", MLDSA65_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", MLDSA65_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature_65)); + CHECK(memcmp(sig, expected_signature_65, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} + + +static int test_mldsa87(void) +{ + const char test_msg[] = TEST_MSG; + const char test_ctx[] = TEST_CTX; + + uint8_t pk[MLDSA87_PUBLICKEYBYTES]; + uint8_t sk[MLDSA87_SECRETKEYBYTES]; + uint8_t sig[MLDSA87_BYTES]; + uint8_t sm[TEST_MSG_LEN + MLDSA87_BYTES]; /* signed message buffer */ + uint8_t m2[TEST_MSG_LEN + MLDSA87_BYTES]; /* recovered message buffer */ + size_t siglen; + size_t smlen; + size_t mlen; + + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + printf("ML-DSA-87\n"); + printf("======================\n\n"); + + printf("Message: %s\n", test_msg); + printf("Context: %s\n\n", test_ctx); + + printf("Generating keypair ... "); + + /* Alice generates a public/private key pair */ + CHECK(mldsa87_keypair(pk, sk) == 0); + + printf("DONE\n"); + printf("Signing message... "); + + /* Alice signs the message */ + CHECK(mldsa87_signature(sig, &siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Verifying signature... "); + + /* Bob verifies Alice's signature */ + CHECK(mldsa87_verify(sig, siglen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Creating signed message... "); + + /* Alternative API: Create a signed message (signature + message combined) */ + CHECK(mldsa87_sign(sm, &smlen, (const uint8_t *)test_msg, TEST_MSG_LEN, + (const uint8_t *)test_ctx, TEST_CTX_LEN, sk) == 0); + + printf("DONE\n"); + printf("Opening signed message... "); + + /* Bob opens the signed message to recover the original message */ + CHECK(mldsa87_open(m2, &mlen, sm, smlen, (const uint8_t *)test_ctx, + TEST_CTX_LEN, pk) == 0); + + printf("DONE\n"); + printf("Compare messages... "); + + /* Verify the recovered message matches the original */ + CHECK(mlen == TEST_MSG_LEN); + CHECK(memcmp(test_msg, m2, TEST_MSG_LEN) == 0); + + printf("DONE\n\n"); + + printf("Results:\n"); + printf("--------\n"); + printf("Public key size: %d bytes\n", MLDSA87_PUBLICKEYBYTES); + printf("Secret key size: %d bytes\n", MLDSA87_SECRETKEYBYTES); + printf("Signature size: %d bytes\n", MLDSA87_BYTES); + printf("Message length: %lu bytes\n", (unsigned long)TEST_MSG_LEN); + printf("Signature length: %lu bytes\n", (unsigned long)siglen); + printf("Signed msg length: %lu bytes\n", (unsigned long)smlen); + +#if !defined(MLD_CONFIG_KEYGEN_PCT) + /* Check against expected signature to make sure that + * we integrated the library correctly */ + printf("Checking deterministic signature... "); + { + /* Compare the generated signature directly against the expected signature + */ + CHECK(siglen == sizeof(expected_signature_87)); + CHECK(memcmp(sig, expected_signature_87, siglen) == 0); + } + printf("DONE\n"); +#else /* !MLD_CONFIG_KEYGEN_PCT */ + printf( + "[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n"); +#endif /* MLD_CONFIG_KEYGEN_PCT */ + + printf("Signature verification completed successfully!\n"); + + printf("\nAll tests passed! ML-DSA signature verification successful.\n"); + return 0; +} + +int main(void) +{ + printf("ML-DSA multilevel_build_native Example\n"); + + if (test_mldsa44() != 0) + { + return 1; + } + + if (test_mldsa65() != 0) + { + return 1; + } + + if (test_mldsa87() != 0) + { + return 1; + } + + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/mldsa_native.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/mldsa_native.h new file mode 100644 index 0000000000..fd150a9df1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/mldsa_native.h @@ -0,0 +1,975 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_H +#define MLD_H + +/* + * Public API for mldsa-native + * + * This header defines the public API of a single build of mldsa-native. + * + * Make sure the configuration file is in the include path + * (this is "mldsa_native_config.h" by default, or MLD_CONFIG_FILE if defined). + * + * # Multi-level builds + * + * This header specifies a build of mldsa-native for a fixed security level. + * If you need multiple security levels, leave the security level unspecified + * in the configuration file and include this header multiple times, setting + * MLD_CONFIG_PARAMETER_SET accordingly for each, and #undef'ing the MLD_H + * guard to allow multiple inclusions. + * + * # Legacy configuration (deprecated) + * + * Instead of providing the config file used for the build, you can + * alternatively set the following configuration options prior to + * including this header. + * + * This method of configuration is deprecated. + * It will be removed in mldsa-native-v2. + * + * - MLD_CONFIG_API_PARAMETER_SET [required] + * + * The parameter set used for the build; 44, 65, or 87. + * + * - MLD_CONFIG_API_NAMESPACE_PREFIX [required] + * + * The namespace prefix used for the build. + * + * NOTE: + * For a multi-level build, you must include the 44/65/87 suffixes + * in MLD_CONFIG_API_NAMESPACE_PREFIX. + * + * - MLD_CONFIG_API_NO_SUPERCOP [optional] + * + * By default, this header will also expose the mldsa-native API in the + * SUPERCOP naming convention crypto_sign_xxx. If you don't want/need this, + * set MLD_CONFIG_API_NO_SUPERCOP. You must set this for a multi-level build. + * + * - MLD_CONFIG_API_CONSTANTS_ONLY [optional] + * + * If you don't want this header to expose any function declarations, + * but only constants for the sizes of key material, set + * MLD_CONFIG_API_CONSTANTS_ONLY. In this case, you don't need to set + * MLD_CONFIG_API_PARAMETER_SET or MLD_CONFIG_API_NAMESPACE_PREFIX, + * nor include a configuration. + * + * - MLD_CONFIG_API_QUALIFIER [optional] + * + * Qualifier to apply to external API. + * + ******************************************************************************/ + +/******************************* Key sizes ************************************/ + +/* Sizes of cryptographic material, per parameter set */ +/* See mldsa/src/params.h for the arithmetic expressions giving rise to these */ +/* check-magic: off */ +#define MLDSA44_SECRETKEYBYTES 2560 +#define MLDSA44_PUBLICKEYBYTES 1312 +#define MLDSA44_BYTES 2420 + +#define MLDSA65_SECRETKEYBYTES 4032 +#define MLDSA65_PUBLICKEYBYTES 1952 +#define MLDSA65_BYTES 3309 + +#define MLDSA87_SECRETKEYBYTES 4896 +#define MLDSA87_PUBLICKEYBYTES 2592 +#define MLDSA87_BYTES 4627 +/* check-magic: on */ + +/* Size of seed and randomness in bytes (level-independent) */ +#define MLDSA_SEEDBYTES 32 +#define MLDSA44_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA65_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA87_SEEDBYTES MLDSA_SEEDBYTES + +/* Size of CRH output in bytes (level-independent) */ +#define MLDSA_CRHBYTES 64 +#define MLDSA44_CRHBYTES MLDSA_CRHBYTES +#define MLDSA65_CRHBYTES MLDSA_CRHBYTES +#define MLDSA87_CRHBYTES MLDSA_CRHBYTES + +/* Size of TR output in bytes (level-independent) */ +#define MLDSA_TRBYTES 64 +#define MLDSA44_TRBYTES MLDSA_TRBYTES +#define MLDSA65_TRBYTES MLDSA_TRBYTES +#define MLDSA87_TRBYTES MLDSA_TRBYTES + +/* Size of randomness for signing in bytes (level-independent) */ +#define MLDSA_RNDBYTES 32 +#define MLDSA44_RNDBYTES MLDSA_RNDBYTES +#define MLDSA65_RNDBYTES MLDSA_RNDBYTES +#define MLDSA87_RNDBYTES MLDSA_RNDBYTES + +/* Sizes of cryptographic material, as a function of LVL=44,65,87 */ +#define MLDSA_SECRETKEYBYTES_(LVL) MLDSA##LVL##_SECRETKEYBYTES +#define MLDSA_PUBLICKEYBYTES_(LVL) MLDSA##LVL##_PUBLICKEYBYTES +#define MLDSA_BYTES_(LVL) MLDSA##LVL##_BYTES +#define MLDSA_SECRETKEYBYTES(LVL) MLDSA_SECRETKEYBYTES_(LVL) +#define MLDSA_PUBLICKEYBYTES(LVL) MLDSA_PUBLICKEYBYTES_(LVL) +#define MLDSA_BYTES(LVL) MLDSA_BYTES_(LVL) + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + +/****************************** Function API **********************************/ + +#define MLD_API_CONCAT_(x, y) x##y +#define MLD_API_CONCAT(x, y) MLD_API_CONCAT_(x, y) +#define MLD_API_CONCAT_UNDERSCORE(x, y) MLD_API_CONCAT(MLD_API_CONCAT(x, _), y) + +#if !defined(MLD_CONFIG_API_PARAMETER_SET) +/* Recommended configuration via same config file as used for the build. */ + +/* For now, we derive the legacy API configuration MLD_CONFIG_API_XXX from + * the config file. In mldsa-native-v2, this will be removed and we will + * exclusively work with MLD_CONFIG_XXX. */ + +/* You need to make sure the config file is in the include path. */ +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#define MLD_CONFIG_API_PARAMETER_SET MLD_CONFIG_PARAMETER_SET + +#if defined(MLD_CONFIG_MULTILEVEL_BUILD) +#define MLD_CONFIG_API_NAMESPACE_PREFIX \ + MLD_API_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_CONFIG_API_NAMESPACE_PREFIX MLD_CONFIG_NAMESPACE_PREFIX +#endif + +#if defined(MLD_CONFIG_NO_SUPERCOP) +#define MLD_CONFIG_API_NO_SUPERCOP +#endif + +#if defined(MLD_CONFIG_CONSTANTS_ONLY) +#define MLD_CONFIG_API_CONSTANTS_ONLY +#endif + +#if defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_CONFIG_API_QUALIFIER MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#else /* !MLD_CONFIG_API_PARAMETER_SET */ +#define MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_PARAMETER_SET */ + +#define MLD_API_NAMESPACE(sym) \ + MLD_API_CONCAT_UNDERSCORE(MLD_CONFIG_API_NAMESPACE_PREFIX, sym) + +#if defined(__GNUC__) || defined(clang) +#define MLD_API_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_API_MUST_CHECK_RETURN_VALUE +#endif + +#if defined(MLD_CONFIG_API_QUALIFIER) +#define MLD_API_QUALIFIER MLD_CONFIG_API_QUALIFIER +#else +#define MLD_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_API_CONSTANTS_ONLY) + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************************* + * Name: crypto_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: + * input random seed + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair_internal)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t seed[MLDSA_SEEDBYTES] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: If MLD_CONFIG_KEYGEN_PCT is enabled and the + * PCT check failed. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return -1 in that case. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_extmu + * + * Description: Computes signature. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_extmu)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t *sm: pointer to output signed message (allocated array + * with MLDSA{44,65,87}_BYTES + mlen bytes), can be + * equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(sign)( + uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_extmu)( + const uint8_t *sig, size_t siglen, const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_open + * + * Description: Verify signed message. + * + * Arguments: + * - uint8_t *m: pointer to output message (allocated array with + * smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(open)( + uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: crypto_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *ph, size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_shake256)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_shake256)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/* Maximum formatted domain separation message length */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +size_t MLD_API_NAMESPACE(prepare_domain_separation_prefix)( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg); + +/************************************************* + * Name: crypto_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[CRYPTO_SECRETKEYBYTES]: input secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(pk_from_sk)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +#ifdef __cplusplus +} +#endif + +/****************************** SUPERCOP API *********************************/ + +#if !defined(MLD_CONFIG_API_NO_SUPERCOP) +/* Export API in SUPERCOP naming scheme CRYPTO_xxx / crypto_sign_xxx */ +#define CRYPTO_SECRETKEYBYTES MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_PUBLICKEYBYTES MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_BYTES MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET) + +#define crypto_sign_keypair MLD_API_NAMESPACE(keypair) +#define crypto_sign_signature MLD_API_NAMESPACE(signature) +#define crypto_sign MLD_API_NAMESPACE(sign) +#define crypto_sign_verify MLD_API_NAMESPACE(verify) +#define crypto_sign_open MLD_API_NAMESPACE(open) + +#else /* !MLD_CONFIG_API_NO_SUPERCOP */ + +/* If the SUPERCOP API is not needed, we can undefine the various helper macros + * above. Otherwise, they are needed for lazy evaluation of crypto_sign_xxx. */ +#if !defined(MLD_API_LEGACY_CONFIG) +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_QUALIFIER +#endif /* !MLD_API_LEGACY_CONFIG */ + +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_NAMESPACE +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_QUALIFIER +#undef MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_NO_SUPERCOP */ +#endif /* !MLD_CONFIG_API_CONSTANTS_ONLY */ + + +/***************************** Memory Usage **********************************/ + +/* + * By default mldsa-native performs all memory allocations on the stack. + * Alternatively, mldsa-native supports custom allocation of large structures + * through the `MLD_CONFIG_CUSTOM_ALLOC_FREE` configuration option. + * See mldsa_native_config.h for details. + * + * `MLD_TOTAL_ALLOC_{44,65,87}_{KEYPAIR,SIGN,VERIFY}` indicates the maximum + * (accumulative) allocation via MLD_ALLOC for each parameter set and operation. + * Note that some stack allocation remains even + * when using custom allocators, so these values are lower than total stack + * usage with the default stack-only allocation. + * + * These constants may be used to implement custom allocations using a + * fixed-sized buffer and a simple allocator (e.g., bump allocator). + */ +/* check-magic: off */ +#if defined(MLD_API_LEGACY_CONFIG) || !defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 45248 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 56640 +#define MLD_TOTAL_ALLOC_44_SIGN 52896 +#define MLD_TOTAL_ALLOC_44_VERIFY 38816 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 71872 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 85856 +#define MLD_TOTAL_ALLOC_65_SIGN 80576 +#define MLD_TOTAL_ALLOC_65_VERIFY 62432 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 112832 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 130816 +#define MLD_TOTAL_ALLOC_87_SIGN 123584 +#define MLD_TOTAL_ALLOC_87_VERIFY 99552 +#else /* MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM */ +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 32992 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 36192 +#define MLD_TOTAL_ALLOC_44_SIGN 32448 +#define MLD_TOTAL_ALLOC_44_VERIFY 22464 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 46304 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 50048 +#define MLD_TOTAL_ALLOC_65_SIGN 44768 +#define MLD_TOTAL_ALLOC_65_VERIFY 30720 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 62688 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 66336 +#define MLD_TOTAL_ALLOC_87_SIGN 59104 +#define MLD_TOTAL_ALLOC_87_VERIFY 41216 +#endif /* !(MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM) */ +/* check-magic: on */ + +/* + * MLD_TOTAL_ALLOC_*_KEYPAIR adapts based on MLD_CONFIG_KEYGEN_PCT. + * For legacy config, we don't know which options are used, so assume + * the worst case (PCT enabled). + */ +#if defined(MLD_API_LEGACY_CONFIG) || defined(MLD_CONFIG_KEYGEN_PCT) +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#else +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#endif + +#define MLD_MAX3_(a, b, c) \ + ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c))) + +/* + * `MLD_TOTAL_ALLOC_{44,65,87}` is the maximum across all operations for each + * parameter set. + */ +#define MLD_TOTAL_ALLOC_44 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_44_KEYPAIR, MLD_TOTAL_ALLOC_44_SIGN, \ + MLD_TOTAL_ALLOC_44_VERIFY) +#define MLD_TOTAL_ALLOC_65 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_65_KEYPAIR, MLD_TOTAL_ALLOC_65_SIGN, \ + MLD_TOTAL_ALLOC_65_VERIFY) +#define MLD_TOTAL_ALLOC_87 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_87_KEYPAIR, MLD_TOTAL_ALLOC_87_SIGN, \ + MLD_TOTAL_ALLOC_87_VERIFY) + +#endif /* !MLD_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/mldsa_native_config.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/mldsa_native_config.h new file mode 100644 index 0000000000..71b8161b5e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/mldsa_native_config.h @@ -0,0 +1,737 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/* + * Test configuration: Multilevel build config + * + * This configuration differs from the default mldsa/mldsa_native_config.h in + * the following places: + * - MLD_CONFIG_NO_SUPERCOP + * - MLD_CONFIG_MULTILEVEL_BUILD + * - MLD_CONFIG_NAMESPACE_PREFIX + * - MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * - MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + */ + + +#ifndef MLD_CONFIG_H +#define MLD_CONFIG_H + +/****************************************************************************** + * Name: MLD_CONFIG_PARAMETER_SET + * + * Description: Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * If you want to support multiple parameter sets, build the + * library multiple times and set MLD_CONFIG_MULTILEVEL_BUILD. + * See MLD_CONFIG_MULTILEVEL_BUILD for how to do this while + * minimizing code duplication. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of the default configuration file mldsa/mldsa_native_config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * then configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + * + *****************************************************************************/ +/* No need to set this -- we _are_ already in a custom config */ +/* #define MLD_CONFIG_FILE "mldsa_native_config.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_NAMESPACE_PREFIX + * + * Description: The prefix to use to namespace global symbols from mldsa/. + * + * In a multi-level build, level-dependent symbols will + * additionally be prefixed with the parameter set (44/65/87). + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_NAMESPACE_PREFIX mldsa + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_BUILD + * + * Description: Set this if the build is part of a multi-level build supporting + * multiple parameter sets. + * + * If you need only a single parameter set, keep this unset. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them. + * + * See examples/multilevel_build for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_MULTILEVEL_BUILD + +/****************************************************************************** + * Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_EXTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_RANDOMIZED_API + * + * Description: If this option is set, mldsa-native will be built without the + * randomized API functions (crypto_sign_keypair, + * crypto_sign, crypto_sign_signature, and + * crypto_sign_signature_extmu). + * This allows users to build mldsa-native without providing a + * randombytes() implementation if they only need the + * internal deterministic API + * (crypto_sign_keypair_internal, crypto_sign_signature_internal). + * + * NOTE: This option is incompatible with MLD_CONFIG_KEYGEN_PCT + * as the current PCT implementation requires + * crypto_sign_signature(). + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_RANDOMIZED_API */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_SUPERCOP + * + * Description: By default, mldsa_native.h exposes the mldsa-native API in the + * SUPERCOP naming convention (crypto_sign_xxx). If you don't need + * this, set MLD_CONFIG_NO_SUPERCOP. + * + * NOTE: You must set this for a multi-level build as the SUPERCOP + * naming does not disambiguate between the parameter sets. + * + *****************************************************************************/ +#define MLD_CONFIG_NO_SUPERCOP + +/****************************************************************************** + * Name: MLD_CONFIG_CONSTANTS_ONLY + * + * Description: If you only need the size constants (MLDSA_PUBLICKEYBYTES, etc.) + * but no function declarations, set MLD_CONFIG_CONSTANTS_ONLY. + * + * This only affects the public header mldsa_native.h, not + * the implementation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONSTANTS_ONLY */ + +/****************************************************************************** + * + * Build-only configuration options + * + * The remaining configurations are build-options only. + * They do not affect the API described in mldsa_native.h. + * + *****************************************************************************/ + +#if defined(MLD_BUILD_INTERNAL) +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_WITH_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, all MLD_CONFIG_PARAMETER_SET-independent + * code will be included in the build, including code needed only + * for other parameter sets. + * + * Example: TODO: add example + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_WITH_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_NO_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, no MLD_CONFIG_PARAMETER_SET-independent code + * will be included in the build. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * + * Description: This is only relevant for single compilation unit (SCU) + * builds of mldsa-native. In this case, it determines whether + * directives defined in parameter-set-independent headers should + * be #undef'ined or not at the of the SCU file. This is needed + * in multilevel builds. + * + * See examples/multilevel_build_native for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * + * Description: Determines whether an native arithmetic backend should be used. + * + * The arithmetic backend covers performance critical functions + * such as the number-theoretic transform (NTT). + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the arithmetic backend to be use is + * determined by MLD_CONFIG_ARITH_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + +/****************************************************************************** + * Name: MLD_CONFIG_ARITH_BACKEND_FILE + * + * Description: The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * + * Description: Determines whether an native FIPS202 backend should be used. + * + * The FIPS202 backend covers 1x/2x/4x-fold Keccak-f1600, which is + * the performance bottleneck of SHA3 and SHAKE. + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the FIPS202 backend to be use is + * determined by MLD_CONFIG_FIPS202_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_BACKEND_FILE + * + * Description: The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202X4_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202-X4 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202x4.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ZEROIZE + * + * Description: In compliance with @[FIPS204, Section 3.6.3], mldsa-native, + * zeroizes intermediate stack buffers before returning from + * function calls. + * + * Set this option and define `mld_zeroize` if you want to + * use a custom method to zeroize intermediate stack buffers. + * The default implementation uses SecureZeroMemory on Windows + * and a memset + compiler barrier otherwise. If neither of those + * is available on the target platform, compilation will fail, + * and you will need to use MLD_CONFIG_CUSTOM_ZEROIZE to provide + * a custom implementation of `mld_zeroize()`. + * + * WARNING: + * The explicit stack zeroization conducted by mldsa-native + * reduces the likelihood of data leaking on the stack, but + * does not eliminate it! The C standard makes no guarantee about + * where a compiler allocates structures and whether/where it makes + * copies of them. Also, in addition to entire structures, there + * may also be potentially exploitable leakage of individual values + * on the stack. + * + * If you need bullet-proof zeroization of the stack, you need to + * consider additional measures instead of what this feature + * provides. In this case, you can set mld_zeroize to a + * no-op. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void mld_zeroize(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * Description: mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to provided by the + * consumer. + * + * If this option is not set, mldsa-native expects a function + * int randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mld_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_RANDOMBYTES + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) + { + ... your implementation ... + return 0; + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + * + * Description: mldsa-native backends may rely on specific hardware features. + * Those backends will only be included in an mldsa-native build + * if support for the respective features is enabled at + * compile-time. However, when building for a heteroneous set + * of CPUs to run the resulting binary/library on, feature + * detection at _runtime_ is needed to decided whether a backend + * can be used or not. + * + * Set this option and define `mld_sys_check_capability` if you + * want to use a custom method to dispatch between implementations. + * + * Return value 1 indicates that a capability is supported. + * Return value 0 indicates that a capability is not supported. + * + * If this option is not set, mldsa-native uses compile-time + * feature detection only to decide which backend to use. + * + * If you compile mldsa-native on a system with different + * capabilities than the system that the resulting binary/library + * will be run on, you must use this option. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) + { + ... your implementation ... + } +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ALLOC_FREE [EXPERIMENTAL] + * + * Description: Set this option and define `MLD_CUSTOM_ALLOC` and + * `MLD_CUSTOM_FREE` if you want to use custom allocation for + * large local structures or buffers. + * + * By default, all buffers/structures are allocated on the stack. + * If this option is set, most of them will be allocated via + * MLD_CUSTOM_ALLOC. + * + * Parameters to MLD_CUSTOM_ALLOC: + * - T* v: Target pointer to declare. + * - T: Type of structure to be allocated + * - N: Number of elements to be allocated. + * + * Parameters to MLD_CUSTOM_FREE: + * - T* v: Target pointer to free. May be NULL. + * - T: Type of structure to be freed. + * - N: Number of elements to be freed. + * + * WARNING: This option is experimental! + * Its scope, configuration and function/macro signatures may + * change at any time. We expect a stable API for v2. + * + * NOTE: Even if this option is set, some allocations further down + * the call stack will still be made from the stack. Those will + * likely be added to the scope of this option in the future. + * + * NOTE: MLD_CUSTOM_ALLOC need not guarantee a successful + * allocation nor include error handling. Upon failure, the + * target pointer should simply be set to NULL. The calling + * code will handle this case and invoke MLD_CUSTOM_FREE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ALLOC_FREE + #if !defined(__ASSEMBLER__) + #include + #define MLD_CUSTOM_ALLOC(v, T, N) \ + T* (v) = (T *)aligned_alloc(MLD_DEFAULT_ALIGN, \ + MLD_ALIGN_UP(sizeof(T) * (N))) + #define MLD_CUSTOM_FREE(v, T, N) free(v) + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMCPY + * + * Description: Set this option and define `mld_memcpy` if you want to + * use a custom method to copy memory instead of the standard + * library memcpy function. + * + * The custom implementation must have the same signature and + * behavior as the standard memcpy function: + * void *mld_memcpy(void *dest, const void *src, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMCPY + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMSET + * + * Description: Set this option and define `mld_memset` if you want to + * use a custom method to set memory instead of the standard + * library memset function. + * + * The custom implementation must have the same signature and + * behavior as the standard memset function: + * void *mld_memset(void *s, int c, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMSET + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memset(void *s, int c, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_INTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of internal API. + * + * The primary use case for this option are single-CU builds, + * in which case this option can be set to `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_INTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CT_TESTING_ENABLED + * + * Description: If set, mldsa-native annotates data as secret / public using + * valgrind's annotations VALGRIND_MAKE_MEM_UNDEFINED and + * VALGRIND_MAKE_MEM_DEFINED, enabling various checks for secret- + * dependent control flow of variable time execution (depending + * on the exact version of valgrind installed). + * + *****************************************************************************/ +/* #define MLD_CONFIG_CT_TESTING_ENABLED */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * and MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT + * + * Description: Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, crypto_sign_keypair_internal and + * crypto_sign_keypair will return a non-zero error code if the + * PCT failed. + * + * NOTE: This feature will drastically lower the performance of + * key generation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * Description: If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "src/src.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Description: Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * NOTE: Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + * + *****************************************************************************/ +/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER + * + * Description: Set this to add a context parameter that is provided to public + * API functions and is then available in custom callbacks. + * + * The type of the context parameter is configured via + * MLD_CONFIG_CONTEXT_PARAMETER_TYPE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER_TYPE + * + * Description: Set this to define the type for the context parameter used by + * MLD_CONFIG_CONTEXT_PARAMETER. + * + * This is only relevant if MLD_CONFIG_CONTEXT_PARAMETER is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER_TYPE void* */ + +/****************************************************************************** + * Name: MLD_CONFIG_REDUCE_RAM [EXPERIMENTAL] + * + * Description: Set this to reduce RAM usage. + * This trades memory for performance. + * + * For expected memory usage, see the MLD_TOTAL_ALLOC_* constants + * defined in mldsa_native.h. + * + * This option is useful for embedded systems with tight RAM + * constraints but relaxed performance requirements. + * + * WARNING: This option is experimental! + * CBMC proofs do not currently cover this configuration option. + * Its scope and configuration may change at any time. + * + *****************************************************************************/ +/* #define MLD_CONFIG_REDUCE_RAM */ + +/************************* Config internals ********************************/ + +#endif /* MLD_BUILD_INTERNAL */ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace is + * + * PQCP_MLDSA_NATIVE_MLDSA_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_ + */ + +#if MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65 +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87 +#endif + +#endif /* !MLD_CONFIG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/cbmc.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/cbmc.h new file mode 100644 index 0000000000..8ed1ecb06b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/cbmc.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_CBMC_H +#define MLD_CBMC_H +/*************************************************** + * Basic replacements for __CPROVER_XXX contracts + ***************************************************/ +#ifndef CBMC + +#define __contract__(x) +#define __loop__(x) +#define cassert(x) + +#else /* !CBMC */ + +#include + +#define __contract__(x) x +#define __loop__(x) x + +/* https://diffblue.github.io/cbmc/contracts-assigns.html */ +#define assigns(...) __CPROVER_assigns(__VA_ARGS__) + +/* https://diffblue.github.io/cbmc/contracts-requires-ensures.html */ +#define requires(...) __CPROVER_requires(__VA_ARGS__) +#define ensures(...) __CPROVER_ensures(__VA_ARGS__) +/* https://diffblue.github.io/cbmc/contracts-loops.html */ +#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__) +#define decreases(...) __CPROVER_decreases(__VA_ARGS__) +/* cassert to avoid confusion with in-built assert */ +#define cassert(x) __CPROVER_assert(x, "cbmc assertion failed") +#define assume(...) __CPROVER_assume(__VA_ARGS__) + +/*************************************************** + * Macros for "expression" forms that may appear + * _inside_ top-level contracts. + ***************************************************/ + +/* + * function return value - useful inside ensures + * https://diffblue.github.io/cbmc/contracts-functions.html + */ +#define return_value (__CPROVER_return_value) + +/* + * assigns l-value targets + * https://diffblue.github.io/cbmc/contracts-assigns.html + */ +#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__) +#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__) +#define same_object(...) __CPROVER_same_object(__VA_ARGS__) + +/* + * Pointer-related predicates + * https://diffblue.github.io/cbmc/contracts-memory-predicates.html + */ +#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__) +#define readable(...) __CPROVER_r_ok(__VA_ARGS__) +#define writeable(...) __CPROVER_w_ok(__VA_ARGS__) + +/* Maximum supported buffer size + * + * Larger buffers may be supported, but due to internal modeling constraints + * in CBMC, the proofs of memory- and type-safety won't be able to run. + * + * If you find yourself in need for a buffer size larger than this, + * please contact the maintainers, so we can prioritize work to relax + * this somewhat artificial bound. + */ +#define MLD_MAX_BUFFER_SIZE (SIZE_MAX >> 12) + + +/* + * History variables + * https://diffblue.github.io/cbmc/contracts-history-variables.html + */ +#define old(...) __CPROVER_old(__VA_ARGS__) +#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__) + +/* + * Quantifiers + * Note that the range on qvar is _exclusive_ between qvar_lb .. qvar_ub + * https://diffblue.github.io/cbmc/contracts-quantifiers.html + */ + +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define forall(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> (predicate) \ + } + +#define exists(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_exists \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) && (predicate) \ + } +/* clang-format on */ + +/*************************************************** + * Convenience macros for common contract patterns + ***************************************************/ +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define CBMC_CONCAT_(left, right) left##right +#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right) + +#define array_bound_core(qvar, qvar_lb, qvar_ub, array_var, \ + value_lb, value_ub) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + (((int)(value_lb) <= ((array_var)[(qvar)])) && \ + (((array_var)[(qvar)]) < (int)(value_ub))) \ + } + +#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \ + array_bound_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (qvar_lb), \ + (qvar_ub), (array_var), (value_lb), (value_ub)) + +#define array_unchanged_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (int32_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged(array_var, N) \ + array_unchanged_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) + +#define array_unchanged_u64_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (uint64_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged_u64(array_var, N) \ + array_unchanged_u64_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) +/* clang-format on */ + +/* Wrapper around array_bound operating on absolute values. + * + * The absolute value bound `k` is exclusive. + * + * Note that since the lower bound in array_bound is inclusive, we have to + * raise it by 1 here. + */ +#define array_abs_bound(arr, lb, ub, k) \ + array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k)) + +#endif /* CBMC */ + +#endif /* !MLD_CBMC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/common.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/common.h new file mode 100644 index 0000000000..4a5bc8109d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/common.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_COMMON_H +#define MLD_COMMON_H + +#define MLD_BUILD_INTERNAL + +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#include "params.h" +#include "sys.h" + +/* Internal and public API have external linkage by default, but + * this can be overwritten by the user, e.g. for single-CU builds. */ +#if !defined(MLD_CONFIG_INTERNAL_API_QUALIFIER) +#define MLD_INTERNAL_API +#else +#define MLD_INTERNAL_API MLD_CONFIG_INTERNAL_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_EXTERNAL_API +#else +#define MLD_EXTERNAL_API MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#if defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) || \ + defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) +#define MLD_MULTILEVEL_BUILD +#endif + +#define MLD_CONCAT_(x1, x2) x1##x2 +#define MLD_CONCAT(x1, x2) MLD_CONCAT_(x1, x2) + +#if defined(MLD_MULTILEVEL_BUILD) +#define MLD_ADD_PARAM_SET(s) MLD_CONCAT(s, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_ADD_PARAM_SET(s) s +#endif + +#define MLD_NAMESPACE_PREFIX MLD_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, _) +#define MLD_NAMESPACE_PREFIX_KL \ + MLD_CONCAT(MLD_ADD_PARAM_SET(MLD_CONFIG_NAMESPACE_PREFIX), _) + +/* Functions are prefixed by MLD_CONFIG_NAMESPACE_PREFIX. + * + * If multiple parameter sets are used, functions depending on the parameter + * set are additionally prefixed with 44/65/87. See mldsa_native_config.h. + * + * Example: If MLD_CONFIG_NAMESPACE_PREFIX is PQCP_MLDSA_NATIVE, then + * MLD_NAMESPACE_KL(keypair) becomes PQCP_MLDSA_NATIVE44_keypair/ + * PQCP_MLDSA_NATIVE65_keypair/PQCP_MLDSA_NATIVE87_keypair. + */ +#define MLD_NAMESPACE(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX, s) +#define MLD_NAMESPACE_KL(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX_KL, s) + +/* On Apple platforms, we need to emit leading underscore + * in front of assembly symbols. We thus introducee a separate + * namespace wrapper for ASM symbols. */ +#if !defined(__APPLE__) +#define MLD_ASM_NAMESPACE(sym) MLD_NAMESPACE(sym) +#else +#define MLD_ASM_NAMESPACE(sym) MLD_CONCAT(_, MLD_NAMESPACE(sym)) +#endif + +/* + * On X86_64 if control-flow protections (CET) are enabled (through + * -fcf-protection=), we add an endbr64 instruction at every global function + * label. See sys.h for more details + */ +#if defined(MLD_SYS_X86_64) +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : MLD_CET_ENDBR +#else +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : +#endif + +/* We aim to simplify the user's life by supporting builds where + * all source files are included, even those that are not needed. + * Those files are appropriately guarded and will be empty when unneeded. + * The following is to avoid compilers complaining about this. */ +#define MLD_EMPTY_CU(s) extern int MLD_NAMESPACE_KL(empty_cu_##s); + +/* MLD_CONFIG_NO_ASM takes precedence over MLD_USE_NATIVE_XXX */ +#if defined(MLD_CONFIG_NO_ASM) +#undef MLD_CONFIG_USE_NATIVE_BACKEND_ARITH +#undef MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, but MLD_CONFIG_ARITH_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, but MLD_CONFIG_FIPS202_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_NO_RANDOMIZED_API) && defined(MLD_CONFIG_KEYGEN_PCT) +#error Bad configuration: MLD_CONFIG_NO_RANDOMIZED_API is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires crypto_sign_signature() +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#include MLD_CONFIG_ARITH_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#include MLD_CONFIG_FIPS202_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "fips202/native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#define MLD_FIPS202_HEADER_FILE "fips202/fips202.h" +#else +#define MLD_FIPS202_HEADER_FILE MLD_CONFIG_FIPS202_CUSTOM_HEADER +#endif + +#if !defined(MLD_CONFIG_FIPS202X4_CUSTOM_HEADER) +#define MLD_FIPS202X4_HEADER_FILE "fips202/fips202x4.h" +#else +#define MLD_FIPS202X4_HEADER_FILE MLD_CONFIG_FIPS202X4_CUSTOM_HEADER +#endif + +/* Standard library function replacements */ +#if !defined(__ASSEMBLER__) +#if !defined(MLD_CONFIG_CUSTOM_MEMCPY) +#include +#define mld_memcpy memcpy +#endif + +#if !defined(MLD_CONFIG_CUSTOM_MEMSET) +#include +#define mld_memset memset +#endif + +/* Allocation macros for large local structures + * + * MLD_ALLOC(v, T, N) declares T *v and attempts to point it to an T[N] + * MLD_FREE(v, T, N) zeroizes and frees the allocation + * + * Default implementation uses stack allocation. + * Can be overridden by setting the config option MLD_CONFIG_CUSTOM_ALLOC_FREE + * and defining MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE. + */ +#if defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) != \ + (defined(MLD_CUSTOM_ALLOC) && defined(MLD_CUSTOM_FREE)) +#error Bad configuration: MLD_CONFIG_CUSTOM_ALLOC_FREE must be set together with MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE +#endif + +/* + * If the integration wants to provide a context parameter for use in + * platform-specific hooks, then it should define this parameter. + * + * The MLD_CONTEXT_PARAMETERS_n macros are intended to be used with macros + * defining the function names and expand to either pass or discard the context + * argument as required by the current build. If there is no context parameter + * requested then these are removed from the prototypes and from all calls. + */ +#ifdef MLD_CONFIG_CONTEXT_PARAMETER +#define MLD_CONTEXT_PARAMETERS_0(context) (context) +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0, context) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1, context) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) \ + (arg0, arg1, arg2, context) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3, context) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4, context) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, context) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, context) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, context) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, context) +#else /* MLD_CONFIG_CONTEXT_PARAMETER */ +#define MLD_CONTEXT_PARAMETERS_0(context) () +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) (arg0, arg1, arg2) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) +#endif /* !MLD_CONFIG_CONTEXT_PARAMETER */ + +#if defined(MLD_CONFIG_CONTEXT_PARAMETER_TYPE) != \ + defined(MLD_CONFIG_CONTEXT_PARAMETER) +#error MLD_CONFIG_CONTEXT_PARAMETER_TYPE must be defined if and only if MLD_CONFIG_CONTEXT_PARAMETER is defined +#endif + +#if !defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) +/* Default: stack allocation */ + +#define MLD_ALLOC(v, T, N, context) \ + MLD_ALIGN T mld_alloc_##v[N]; \ + T *v = mld_alloc_##v + +/* TODO: This leads to a circular dependency between common and ct.h + * It just works out before we're at the end of the file, but it's still + * prone to issues in the future. */ +#include "ct.h" +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + mld_zeroize(mld_alloc_##v, sizeof(mld_alloc_##v)); \ + (v) = NULL; \ + } while (0) + +#else /* !MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* Custom allocation */ + +/* + * The indirection here is necessary to use MLD_CONTEXT_PARAMETERS_3 here. + */ +#define MLD_APPLY(f, args) f args + +#define MLD_ALLOC(v, T, N, context) \ + MLD_APPLY(MLD_CUSTOM_ALLOC, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)) + +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + if (v != NULL) \ + { \ + mld_zeroize(v, sizeof(T) * (N)); \ + MLD_APPLY(MLD_CUSTOM_FREE, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)); \ + v = NULL; \ + } \ + } while (0) + +#endif /* MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* + * We are facing severe CBMC performance issues when using unions. + * As a temporary workaround, we use unions only when MLD_CONFIG_REDUCE_RAM is + * set. + * TODO: Remove the workaround once + * https://github.com/diffblue/cbmc/issues/8813 + * is resolved + */ +#if defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_UNION_OR_STRUCT union +#else +#define MLD_UNION_OR_STRUCT struct +#endif + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_COMMON_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/ct.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/ct.c new file mode 100644 index 0000000000..010b1a52a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/ct.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include "ct.h" + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +/* + * Masking value used in constant-time functions from + * ct.h to block the compiler's range analysis and + * thereby reduce the risk of compiler-introduced branches. + */ +volatile uint64_t mld_ct_opt_blocker_u64 = 0; + +#else /* !MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(ct) + +#endif /* !(!MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/ct.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/ct.h new file mode 100644 index 0000000000..c307456468 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/ct.h @@ -0,0 +1,366 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [libmceliece] + * libmceliece implementation of Classic McEliece + * Bernstein, Chou + * https://lib.mceliece.org/ + * + * - [optblocker] + * PQC forum post on opt-blockers using volatile globals + * Daniel J. Bernstein + * https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ + */ + +#ifndef MLD_CT_H +#define MLD_CT_H + +#include +#include "cbmc.h" +#include "common.h" + +/* Constant-time comparisons and conditional operations + + We reduce the risk for compilation into variable-time code + through the use of 'value barriers'. + + Functionally, a value barrier is a no-op. To the compiler, however, + it constitutes an arbitrary modification of its input, and therefore + harden's value propagation and range analysis. + + We consider two approaches to implement a value barrier: + - An empty inline asm block which marks the target value as clobbered. + - XOR'ing with the value of a volatile global that's set to 0; + see @[optblocker] for a discussion of this idea, and + @[libmceliece, inttypes/crypto_intN.h] for an implementation. + + The first approach is cheap because it only prevents the compiler + from reasoning about the value of the variable past the barrier, + but does not directly generate additional instructions. + + The second approach generates redundant loads and XOR operations + and therefore comes at a higher runtime cost. However, it appears + more robust towards optimization, as compilers should never drop + a volatile load. + + We use the empty-ASM value barrier for GCC and clang, and fall + back to the global volatile barrier otherwise. + + The global value barrier can be forced by setting + MLD_CONFIG_NO_ASM_VALUE_BARRIER. + +*/ + +#if defined(MLD_HAVE_INLINE_ASM) && !defined(MLD_CONFIG_NO_ASM_VALUE_BARRIER) +#define MLD_USE_ASM_VALUE_BARRIER +#endif + + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) +/* + * Declaration of global volatile that the global value barrier + * is loading from and masking with. + */ +#define mld_ct_opt_blocker_u64 MLD_NAMESPACE(ct_opt_blocker_u64) +extern volatile uint64_t mld_ct_opt_blocker_u64; + + +/* Helper functions for obtaining global masks of various sizes */ + +/* This contract is not proved but treated as an axiom. + * + * Its validity relies on the assumption that the global opt-blocker + * constant mld_ct_opt_blocker_u64 is not modified. + */ +static MLD_INLINE uint64_t mld_ct_get_optblocker_u64(void) +__contract__(ensures(return_value == 0)) { return mld_ct_opt_blocker_u64; } + +static MLD_INLINE int64_t mld_ct_get_optblocker_i64(void) +__contract__(ensures(return_value == 0)) { return (int64_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint32_t mld_ct_get_optblocker_u32(void) +__contract__(ensures(return_value == 0)) { return (uint32_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint8_t mld_ct_get_optblocker_u8(void) +__contract__(ensures(return_value == 0)) { return (uint8_t)mld_ct_get_optblocker_u64(); } + +/* Opt-blocker based implementation of value barriers */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_i64()); } + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u32()); } + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u8()); } + + +#else /* !MLD_USE_ASM_VALUE_BARRIER */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} +#endif /* MLD_USE_ASM_VALUE_BARRIER */ + +#ifdef CBMC +#pragma CPROVER check push +#pragma CPROVER check disable "conversion" +#endif + +/************************************************* + * Name: mld_cast_uint32_to_int32 + * + * Description: Cast uint32 value to int32 + * + * Returns: For uint32_t x, the unique y in int32_t + * so that x == y mod 2^32. + * + * Concretely: + * - x < 2^31: returns x + * - x >= 2^31: returns x - 2^31 + * + **************************************************/ +static MLD_ALWAYS_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x) +{ + /* + * PORTABILITY: This relies on uint32_t -> int32_t + * being implemented as the inverse of int32_t -> uint32_t, + * which is implementation-defined (C99 6.3.1.3 (3)) + * CBMC (correctly) fails to prove this conversion is OK, + * so we have to suppress that check here + */ + return (int32_t)x; +} + +#ifdef CBMC +#pragma CPROVER check pop +#endif + + +/************************************************* + * Name: mld_cast_int64_to_uint32 + * + * Description: Cast int64 value to uint32 as per C standard. + * + * Returns: For int64_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int64_to_uint32(int64_t x) +{ + return (uint32_t)(x & (int64_t)UINT32_MAX); +} + +/************************************************* + * Name: mld_cast_int32_to_uint32 + * + * Description: Cast int32 value to uint32 as per C standard. + * + * Returns: For int32_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int32_to_uint32(int32_t x) +{ + return mld_cast_int64_to_uint32((int64_t)x); +} + +/************************************************* + * Name: mld_ct_sel_int32 + * + * Description: Functionally equivalent to cond ? a : b, + * but implemented with guards against + * compiler-introduced branches. + * + * Arguments: int32_t a: First alternative + * int32_t b: Second alternative + * uint32_t cond: Condition variable. + * + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_sel_int32(int32_t a, int32_t b, uint32_t cond) +__contract__( + requires(cond == 0x0 || cond == 0xFFFFFFFF) + ensures(return_value == (cond ? a : b)) +) +{ + uint32_t au = mld_cast_int32_to_uint32(a); + uint32_t bu = mld_cast_int32_to_uint32(b); + uint32_t res = bu ^ (mld_value_barrier_u32(cond) & (au ^ bu)); + return mld_cast_uint32_to_int32(res); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u32 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_nonzero_u32(uint32_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFFFFFFFF))) +{ + int64_t tmp = mld_value_barrier_i64(-((int64_t)x)); + tmp >>= 32; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u8 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint8_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint8_t mld_ct_cmask_nonzero_u8(uint8_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFF))) +{ + uint32_t mask = mld_ct_cmask_nonzero_u32((uint32_t)x); + return (uint8_t)(mask & 0xFF); +} + +/************************************************* + * Name: mld_ct_cmask_neg_i32 + * + * Description: Return 0 if input is non-negative, and -1 otherwise. + * + * Arguments: int32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_neg_i32(int32_t x) +__contract__( + ensures(return_value == ((x < 0) ? 0xFFFFFFFF : 0)) +) +{ + int64_t tmp = mld_value_barrier_i64((int64_t)x); + tmp >>= 31; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_abs_i32 + * + * Description: Return -x if x<0, x otherwise + * + * Arguments: int32_t x: Input value + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_abs_i32(int32_t x) +__contract__( + requires(x >= -INT32_MAX) + ensures(return_value == ((x < 0) ? -x : x)) +) +{ + return mld_ct_sel_int32(-x, x, mld_ct_cmask_neg_i32(x)); +} + +/************************************************* + * Name: mld_ct_memcmp + * + * Description: Compare two arrays for equality in constant time. + * + * Arguments: const uint8_t *a: pointer to first byte array + * const uint8_t *b: pointer to second byte array + * size_t len: length of the byte arrays, upper-bounded + * to UINT16_MAX to control proof complexity + * only. + * + * Returns 0 if the byte arrays are equal, 0xFF otherwise. + **************************************************/ +static MLD_INLINE uint8_t mld_ct_memcmp(const uint8_t *a, const uint8_t *b, + const size_t len) +__contract__( + requires(len <= UINT16_MAX) + requires(memory_no_alias(a, len)) + requires(memory_no_alias(b, len)) + ensures((return_value == 0) || (return_value == 0xFF)) + ensures((return_value == 0) == forall(i, 0, len, (a[i] == b[i])))) +{ + uint8_t r = 0, s = 0; + unsigned i; + + for (i = 0; i < len; i++) + __loop__( + invariant(i <= len) + invariant((r == 0) == (forall(k, 0, i, (a[k] == b[k]))))) + { + r |= a[i] ^ b[i]; + /* s is useless, but prevents the loop from being aborted once r=0xff. */ + s ^= a[i] ^ b[i]; + } + + /* + * - Convert r into a mask; this may not be necessary, but is an additional + * safeguard + * towards leaking information about a and b. + * - XOR twice with s, separated by a value barrier, to prevent the compile + * from dropping the s computation in the loop. + */ + return (mld_value_barrier_u8(mld_ct_cmask_nonzero_u8(r) ^ s) ^ s); +} + +/************************************************* + * Name: mld_zeroize + * + * Description: Force-zeroize a buffer. + * @[FIPS204, Section 3.6.3] Destruction of intermediate + * values. + * + * Arguments: void *ptr: pointer to buffer to be zeroed + * size_t len: Amount of bytes to be zeroed + **************************************************/ +#if !defined(MLD_CONFIG_CUSTOM_ZEROIZE) +#if defined(MLD_SYS_WINDOWS) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) { SecureZeroMemory(ptr, len); } +#elif defined(MLD_HAVE_INLINE_ASM) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) +{ + memset(ptr, 0, len); + /* This follows OpenSSL and seems sufficient to prevent the compiler + * from optimizing away the memset. + * + * If there was a reliable way to detect availability of memset_s(), + * that would be preferred. */ + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +} +#else /* !MLD_SYS_WINDOWS && MLD_HAVE_INLINE_ASM */ +#error No plausibly-secure implementation of mld_zeroize available. Please provide your own using MLD_CONFIG_CUSTOM_ZEROIZE. +#endif /* !MLD_SYS_WINDOWS && !MLD_HAVE_INLINE_ASM */ +#endif /* !MLD_CONFIG_CUSTOM_ZEROIZE */ + +#endif /* !MLD_CT_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/debug.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/debug.c new file mode 100644 index 0000000000..a55d51e8b1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/debug.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* NOTE: You can remove this file unless you compile with MLDSA_DEBUG. */ + +#include "common.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#if defined(MLDSA_DEBUG) + +#include +#include +#include +#include "debug.h" + +#define MLD_DEBUG_ERROR_HEADER "[ERROR:%s:%04d] " + +void mld_debug_check_assert(const char *file, int line, const int val) +{ + if (val == 0) + { + fprintf(stderr, MLD_DEBUG_ERROR_HEADER "Assertion failed (value %d)\n", + file, line, val); + exit(1); + } +} + +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive) +{ + int err = 0; + unsigned i; + for (i = 0; i < len; i++) + { + int32_t val = ptr[i]; + if (!(val > lower_bound_exclusive && val < upper_bound_exclusive)) + { + fprintf(stderr, + MLD_DEBUG_ERROR_HEADER + "Bounds assertion failed: Index %u, value %d out of bounds " + "(%" PRId64 ",%" PRId64 ")\n", + file, line, i, (int)val, lower_bound_exclusive, + upper_bound_exclusive); + err = 1; + } + } + + if (err == 1) + { + exit(1); + } +} + +#else /* MLDSA_DEBUG */ + +MLD_EMPTY_CU(debug) + +#endif /* !MLDSA_DEBUG */ + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(debug) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_DEBUG_ERROR_HEADER diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/debug.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/debug.h new file mode 100644 index 0000000000..af187bb9de --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/debug.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_DEBUG_H +#define MLD_DEBUG_H +#include "common.h" + +#if defined(MLDSA_DEBUG) +#include + +/************************************************* + * Name: mld_assert + * + * Description: Check debug assertion + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - val: Value asserted to be non-zero + **************************************************/ +#define mld_debug_check_assert MLD_NAMESPACE(mldsa_debug_assert) +void mld_debug_check_assert(const char *file, int line, const int val); + +/************************************************* + * Name: mld_debug_check_bounds + * + * Description: Check whether values in an array of int32_t + * are within specified bounds. + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - ptr: Base of array to be checked + * - len: Number of int32_t in ptr + * - lower_bound_exclusive: Exclusive lower bound + * - upper_bound_exclusive: Exclusive upper bound + **************************************************/ +#define mld_debug_check_bounds MLD_NAMESPACE(mldsa_debug_check_bounds) +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive); + +/* Check assertion, calling exit() upon failure + * + * val: Value that's asserted to be non-zero + */ +#define mld_assert(val) mld_debug_check_assert(__FILE__, __LINE__, (val)) + +/* Check bounds in array of int32_t's + * ptr: Base of int32_t array; will be explicitly cast to int32_t*, + * so you may pass a byte-compatible type such as mld_poly or mld_polyvec. + * len: Number of int32_t in array + * value_lb: Inclusive lower value bound + * value_ub: Exclusive upper value bound */ +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + mld_debug_check_bounds(__FILE__, __LINE__, (const int32_t *)(ptr), (len), \ + ((int64_t)(value_lb)) - 1, (value_ub)) + +/* Check absolute bounds in array of int32_t's + * ptr: Base of array, expression of type int32_t* + * len: Number of int32_t in array + * value_abs_bd: Exclusive absolute upper bound */ +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + mld_assert_bound((ptr), (len), (-((int64_t)(value_abs_bd)) + 1), \ + (value_abs_bd)) + +/* Version of bounds assertions for 2-dimensional arrays */ +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + mld_assert_bound((ptr), ((len0) * (len1)), (value_lb), (value_ub)) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + mld_assert_abs_bound((ptr), ((len0) * (len1)), (value_abs_bd)) + +/* When running CBMC, convert debug assertions into proof obligations */ +#elif defined(CBMC) +#include "cbmc.h" + +#define mld_assert(val) cassert(val) + +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + cassert(array_bound(((int32_t *)(ptr)), 0, (len), (value_lb), (value_ub))) + +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + cassert(array_abs_bound(((int32_t *)(ptr)), 0, (len), (value_abs_bd))) + +/* Because of https://github.com/diffblue/cbmc/issues/8570, we can't + * just use a single flattened array_bound(...) here. */ +#define mld_assert_bound_2d(ptr, M, N, value_lb, value_ub) \ + cassert(forall(kN, 0, (M), \ + array_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_lb), (value_ub)))) + +#define mld_assert_abs_bound_2d(ptr, M, N, value_abs_bd) \ + cassert(forall(kN, 0, (M), \ + array_abs_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_abs_bd)))) + +#else /* !MLDSA_DEBUG && CBMC */ + +#define mld_assert(val) \ + do \ + { \ + } while (0) +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + do \ + { \ + } while (0) +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + do \ + { \ + } while (0) + +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + do \ + { \ + } while (0) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + do \ + { \ + } while (0) + + +#endif /* !MLDSA_DEBUG && !CBMC */ +#endif /* !MLD_DEBUG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/fips202.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/fips202.c new file mode 100644 index 0000000000..1112de061c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/fips202.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "../common.h" +#include "../ct.h" +#include "fips202.h" +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +/************************************************* + * Name: keccak_init + * + * Description: Initializes the Keccak state. + * + * Arguments: - uint64_t *s: pointer to Keccak state + **************************************************/ +static void keccak_init(uint64_t s[MLD_KECCAK_LANES]) +__contract__( + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + mld_memset(s, 0, sizeof(uint64_t) * MLD_KECCAK_LANES); +} + +/************************************************* + * Name: keccak_absorb + * + * Description: Absorb step of Keccak; incremental. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_absorb(uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r, + const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(pos <= r) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(in, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + ensures(return_value < r)) +{ + while (inlen >= r - pos) + __loop__( + assigns(pos, in, inlen, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + invariant(inlen <= loop_entry(inlen)) + invariant(pos <= r) + invariant(in == loop_entry(in) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600_xor_bytes(s, in, pos, r - pos); + inlen -= r - pos; + in += r - pos; + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: At this point, inlen < r, so the truncation to unsigned is safe. */ + mld_keccakf1600_xor_bytes(s, in, pos, (unsigned)inlen); + + /* Safety: At this point, inlen < r and pos <= r so the truncation to unsigned + * is safe. */ + return (unsigned)(pos + inlen); +} + +/************************************************* + * Name: keccak_finalize + * + * Description: Finalize absorb step. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - uint8_t p: domain separation byte + **************************************************/ +static void keccak_finalize(uint64_t s[MLD_KECCAK_LANES], unsigned int pos, + unsigned int r, uint8_t p) +__contract__( + requires(pos <= r && r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires((r / 8) >= 1) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + uint8_t b = 0x80; + mld_keccakf1600_xor_bytes(s, &p, pos, 1); + mld_keccakf1600_xor_bytes(s, &b, r - 1, 1); +} + +/************************************************* + * Name: keccak_squeeze + * + * Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes. + * Modifies the state. Can be called multiple times to keep + * squeezing, i.e., is incremental. + * + * Arguments: - uint8_t *out: pointer to output data + * - size_t outlen: number of bytes to be squeezed (written to out) + * - uint64_t *s: pointer to input/output Keccak state + * - unsigned int pos: number of bytes in current block already + *squeezed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_squeeze(uint8_t *out, size_t outlen, + uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r) +__contract__( + requires((r == SHAKE128_RATE && pos <= SHAKE128_RATE) || + (r == SHAKE256_RATE && pos <= SHAKE256_RATE) || + (r == SHA3_512_RATE && pos <= SHA3_512_RATE)) + requires(outlen <= 8 * r /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(out, outlen)) + ensures(return_value <= r)) +{ + unsigned int i; + size_t out_offset = 0; + + /* Reference: This code is re-factored from the reference implementation + * to facilitate proof with CBMC and to improve readability. + * + * Take a mutable copy of outlen to count down the number of bytes + * still to squeeze. The initial value of outlen is needed for the CBMC + * assigns() clauses. */ + size_t bytes_to_go = outlen; + + while (bytes_to_go > 0) + __loop__( + assigns(i, bytes_to_go, pos, out_offset, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES), memory_slice(out, outlen)) + invariant(bytes_to_go <= outlen) + invariant(out_offset == outlen - bytes_to_go) + invariant(pos <= r) + ) + { + if (pos == r) + { + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: If bytes_to_go < r - pos, truncation to unsigned is safe. */ + i = bytes_to_go < r - pos ? (unsigned)bytes_to_go : r - pos; + mld_keccakf1600_extract_bytes(s, out + out_offset, pos, i); + bytes_to_go -= i; + pos += i; + out_offset += i; + } + + return pos; +} + +void mld_shake128_init(mld_shake128ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE128_RATE, in, inlen); +} + +void mld_shake128_finalize(mld_shake128ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE128_RATE, 0x1F); + state->pos = SHAKE128_RATE; +} + +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE128_RATE); +} + +void mld_shake128_release(mld_shake128ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128ctx)); +} + +void mld_shake256_init(mld_shake256ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); +} + +void mld_shake256_finalize(mld_shake256ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); + state->pos = SHAKE256_RATE; +} + +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); +} + +void mld_shake256_release(mld_shake256ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256ctx)); +} + +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +{ + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, in, inlen); + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/fips202.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/fips202.h new file mode 100644 index 0000000000..9f0253cb88 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/fips202.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202_H +#define MLD_FIPS202_FIPS202_H + +#include +#include +#include "../cbmc.h" +#include "../common.h" + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 +#define SHA3_256_RATE 136 +#define SHA3_512_RATE 72 +#define MLD_KECCAK_LANES 25 +#define SHA3_256_HASHBYTES 32 +#define SHA3_512_HASHBYTES 64 + + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake128ctx; + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake256ctx; + +#define mld_shake128_init MLD_NAMESPACE(shake128_init) +/************************************************* + * Name: mld_shake128_init + * + * Description: Initializes state for use as SHAKE128 XOF + * + * Arguments: - mld_shake128ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake128_init(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos == 0) +); + +#define mld_shake128_absorb MLD_NAMESPACE(shake128_absorb) +/************************************************* + * Name: mld_shake128_absorb + * + * Description: Absorb step of the SHAKE128 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake128ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_finalize MLD_NAMESPACE(shake128_finalize) +/************************************************* + * Name: mld_shake128_finalize + * + * Description: Concludes the absorb phase of the SHAKE128 XOF. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_finalize(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_squeeze MLD_NAMESPACE(shake128_squeeze) +/************************************************* + * Name: mld_shake128_squeeze + * + * Description: Squeeze step of SHAKE128 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake128ctx *s: pointer to input/output state + **************************************************/ +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE128_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_release MLD_NAMESPACE(shake128_release) +/************************************************* + * Name: mld_shake128_release + * + * Description: Release and securely zero the SHAKE128 state. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_release(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) +); + +#define mld_shake256_init MLD_NAMESPACE(shake256_init) +/************************************************* + * Name: mld_shake256_init + * + * Description: Initializes state for use as SHAKE256 XOF + * + * Arguments: - mld_shake256ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake256_init(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos == 0) +); + +#define mld_shake256_absorb MLD_NAMESPACE(shake256_absorb) +/************************************************* + * Name: mld_shake256_absorb + * + * Description: Absorb step of the SHAKE256 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake256ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_finalize MLD_NAMESPACE(shake256_finalize) +/************************************************* + * Name: mld_shake256_finalize + * + * Description: Concludes the absorb phase of the SHAKE256 XOF. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_finalize(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_squeeze MLD_NAMESPACE(shake256_squeeze) +/************************************************* + * Name: mld_shake256_squeeze + * + * Description: Squeeze step of SHAKE256 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake256ctx *s: pointer to input/output state + **************************************************/ +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_release MLD_NAMESPACE(shake256_release) +/************************************************* + * Name: mld_shake256_release + * + * Description: Release and securely zero the SHAKE256 state. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_release(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) +); + +#define mld_shake256 MLD_NAMESPACE(shake256) +/************************************************* + * Name: mld_shake256 + * + * Description: SHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +); + +#endif /* !MLD_FIPS202_FIPS202_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/fips202x4.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/fips202x4.c new file mode 100644 index 0000000000..0fb5cd57c7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/fips202x4.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include "../common.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "../ct.h" +#include "fips202.h" +#include "fips202x4.h" +#include "keccakf1600.h" + +static void mld_keccak_absorb_once_x4(uint64_t *s, uint32_t r, + const uint8_t *in0, const uint8_t *in1, + const uint8_t *in2, const uint8_t *in3, + size_t inlen, uint8_t p) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))) +{ + while (inlen >= r) + __loop__( + assigns(inlen, in0, in1, in2, in3, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + invariant(inlen <= loop_entry(inlen)) + invariant(in0 == loop_entry(in0) + (loop_entry(inlen) - inlen)) + invariant(in1 == loop_entry(in1) + (loop_entry(inlen) - inlen)) + invariant(in2 == loop_entry(in2) + (loop_entry(inlen) - inlen)) + invariant(in3 == loop_entry(in3) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, r); + mld_keccakf1600x4_permute(s); + + in0 += r; + in1 += r; + in2 += r; + in3 += r; + inlen -= r; + } + + /* Safety: At this point, inlen < r, so the truncations to unsigned are safe + * below. */ + if (inlen > 0) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, (unsigned)inlen); + } + + if (inlen == r - 1) + { + p |= 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + } + else + { + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + p = 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, r - 1, 1); + } +} + +static void mld_keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1, + uint8_t *out2, uint8_t *out3, + size_t nblocks, uint64_t *s, uint32_t r) +__contract__( + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(out0, nblocks * r)) + requires(memory_no_alias(out1, nblocks * r)) + requires(memory_no_alias(out2, nblocks * r)) + requires(memory_no_alias(out3, nblocks * r)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(out0, nblocks * r)) + assigns(memory_slice(out1, nblocks * r)) + assigns(memory_slice(out2, nblocks * r)) + assigns(memory_slice(out3, nblocks * r))) +{ + while (nblocks > 0) + __loop__( + assigns(out0, out1, out2, out3, nblocks, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY), + memory_slice(out0, nblocks * r), + memory_slice(out1, nblocks * r), + memory_slice(out2, nblocks * r), + memory_slice(out3, nblocks * r)) + invariant(nblocks <= loop_entry(nblocks) && + out0 == loop_entry(out0) + r * (loop_entry(nblocks) - nblocks) && + out1 == loop_entry(out1) + r * (loop_entry(nblocks) - nblocks) && + out2 == loop_entry(out2) + r * (loop_entry(nblocks) - nblocks) && + out3 == loop_entry(out3) + r * (loop_entry(nblocks) - nblocks))) + { + mld_keccakf1600x4_permute(s); + mld_keccakf1600x4_extract_bytes(s, out0, out1, out2, out3, 0, r); + + out0 += r; + out1 += r; + out2 += r; + out3 += r; + nblocks--; + } +} + +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake128x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE128_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE128_RATE); +} + +void mld_shake128x4_init(mld_shake128x4ctx *state) { (void)state; } +void mld_shake128x4_release(mld_shake128x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128x4ctx)); +} + + +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake256x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE256_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE256_RATE); +} + +void mld_shake256x4_init(mld_shake256x4ctx *state) { (void)state; } +void mld_shake256x4_release(mld_shake256x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256x4ctx)); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/fips202x4.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/fips202x4.h new file mode 100644 index 0000000000..e7987207a6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/fips202x4.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202X4_H +#define MLD_FIPS202_FIPS202X4_H + +#include +#include + +#include "../cbmc.h" +#include "../common.h" + +#include "fips202.h" +#include "keccakf1600.h" + +/* Context for non-incremental API */ +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake128x4ctx; + +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake256x4ctx; + +#define mld_shake128x4_absorb_once MLD_NAMESPACE(shake128x4_absorb_once) +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_squeezeblocks MLD_NAMESPACE(shake128x4_squeezeblocks) +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE128_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE128_RATE), + memory_slice(out1, nblocks * SHAKE128_RATE), + memory_slice(out2, nblocks * SHAKE128_RATE), + memory_slice(out3, nblocks * SHAKE128_RATE), + memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_init MLD_NAMESPACE(shake128x4_init) +void mld_shake128x4_init(mld_shake128x4ctx *state); + +#define mld_shake128x4_release MLD_NAMESPACE(shake128x4_release) +void mld_shake128x4_release(mld_shake128x4ctx *state); + + +#define mld_shake256x4_absorb_once MLD_NAMESPACE(shake256x4_absorb_once) +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_squeezeblocks MLD_NAMESPACE(shake256x4_squeezeblocks) +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE256_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE256_RATE), + memory_slice(out1, nblocks * SHAKE256_RATE), + memory_slice(out2, nblocks * SHAKE256_RATE), + memory_slice(out3, nblocks * SHAKE256_RATE), + memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_init MLD_NAMESPACE(shake256x4_init) +void mld_shake256x4_init(mld_shake256x4ctx *state); + +#define mld_shake256x4_release MLD_NAMESPACE(shake256x4_release) +void mld_shake256x4_release(mld_shake256x4ctx *state); + + +#endif /* !MLD_FIPS202_FIPS202X4_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/keccakf1600.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/keccakf1600.c new file mode 100644 index 0000000000..e59120c07c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/keccakf1600.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#define MLD_KECCAK_NROUNDS 24 +#define MLD_KECCAK_ROL(a, offset) ((a << offset) ^ (a >> (64 - offset))) + +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = state_ptr[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = (state[(offset + i) >> 3] >> (8 * ((offset + i) & 0x07))) & 0xFF; + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state_ptr[i] ^= data[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state[(offset + i) >> 3] ^= (uint64_t)data[i] + << (8 * ((offset + i) & 0x07)); + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X4_NATIVE) + if (mld_keccak_f1600_x4_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 0); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 1); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 2); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 3); +} + +static const uint64_t mld_KeccakF_RoundConstants[MLD_KECCAK_NROUNDS] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +static void mld_keccakf1600_permute_c(uint64_t *state) +{ + unsigned round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + uint64_t BCa, BCe, BCi, BCo, BCu; + uint64_t Da, De, Di, Do, Du; + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + /* copyFromState(A, state) */ + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < MLD_KECCAK_NROUNDS; round += 2) + __loop__(invariant(round <= MLD_KECCAK_NROUNDS && round % 2 == 0)) + { + /* prepareTheta */ + BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; + BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + /* thetaRhoPiChiIotaPrepareTheta(round, A, E) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = MLD_KECCAK_ROL(Age, 44); + Aki ^= Di; + BCi = MLD_KECCAK_ROL(Aki, 43); + Amo ^= Do; + BCo = MLD_KECCAK_ROL(Amo, 21); + Asu ^= Du; + BCu = MLD_KECCAK_ROL(Asu, 14); + Eba = BCa ^ ((~BCe) & BCi); + Eba ^= (uint64_t)mld_KeccakF_RoundConstants[round]; + Ebe = BCe ^ ((~BCi) & BCo); + Ebi = BCi ^ ((~BCo) & BCu); + Ebo = BCo ^ ((~BCu) & BCa); + Ebu = BCu ^ ((~BCa) & BCe); + + Abo ^= Do; + BCa = MLD_KECCAK_ROL(Abo, 28); + Agu ^= Du; + BCe = MLD_KECCAK_ROL(Agu, 20); + Aka ^= Da; + BCi = MLD_KECCAK_ROL(Aka, 3); + Ame ^= De; + BCo = MLD_KECCAK_ROL(Ame, 45); + Asi ^= Di; + BCu = MLD_KECCAK_ROL(Asi, 61); + Ega = BCa ^ ((~BCe) & BCi); + Ege = BCe ^ ((~BCi) & BCo); + Egi = BCi ^ ((~BCo) & BCu); + Ego = BCo ^ ((~BCu) & BCa); + Egu = BCu ^ ((~BCa) & BCe); + + Abe ^= De; + BCa = MLD_KECCAK_ROL(Abe, 1); + Agi ^= Di; + BCe = MLD_KECCAK_ROL(Agi, 6); + Ako ^= Do; + BCi = MLD_KECCAK_ROL(Ako, 25); + Amu ^= Du; + BCo = MLD_KECCAK_ROL(Amu, 8); + Asa ^= Da; + BCu = MLD_KECCAK_ROL(Asa, 18); + Eka = BCa ^ ((~BCe) & BCi); + Eke = BCe ^ ((~BCi) & BCo); + Eki = BCi ^ ((~BCo) & BCu); + Eko = BCo ^ ((~BCu) & BCa); + Eku = BCu ^ ((~BCa) & BCe); + + Abu ^= Du; + BCa = MLD_KECCAK_ROL(Abu, 27); + Aga ^= Da; + BCe = MLD_KECCAK_ROL(Aga, 36); + Ake ^= De; + BCi = MLD_KECCAK_ROL(Ake, 10); + Ami ^= Di; + BCo = MLD_KECCAK_ROL(Ami, 15); + Aso ^= Do; + BCu = MLD_KECCAK_ROL(Aso, 56); + Ema = BCa ^ ((~BCe) & BCi); + Eme = BCe ^ ((~BCi) & BCo); + Emi = BCi ^ ((~BCo) & BCu); + Emo = BCo ^ ((~BCu) & BCa); + Emu = BCu ^ ((~BCa) & BCe); + + Abi ^= Di; + BCa = MLD_KECCAK_ROL(Abi, 62); + Ago ^= Do; + BCe = MLD_KECCAK_ROL(Ago, 55); + Aku ^= Du; + BCi = MLD_KECCAK_ROL(Aku, 39); + Ama ^= Da; + BCo = MLD_KECCAK_ROL(Ama, 41); + Ase ^= De; + BCu = MLD_KECCAK_ROL(Ase, 2); + Esa = BCa ^ ((~BCe) & BCi); + Ese = BCe ^ ((~BCi) & BCo); + Esi = BCi ^ ((~BCo) & BCu); + Eso = BCo ^ ((~BCu) & BCa); + Esu = BCu ^ ((~BCa) & BCe); + + /* prepareTheta */ + BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + /* thetaRhoPiChiIotaPrepareTheta(round+1, E, A) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = MLD_KECCAK_ROL(Ege, 44); + Eki ^= Di; + BCi = MLD_KECCAK_ROL(Eki, 43); + Emo ^= Do; + BCo = MLD_KECCAK_ROL(Emo, 21); + Esu ^= Du; + BCu = MLD_KECCAK_ROL(Esu, 14); + Aba = BCa ^ ((~BCe) & BCi); + Aba ^= (uint64_t)mld_KeccakF_RoundConstants[round + 1]; + Abe = BCe ^ ((~BCi) & BCo); + Abi = BCi ^ ((~BCo) & BCu); + Abo = BCo ^ ((~BCu) & BCa); + Abu = BCu ^ ((~BCa) & BCe); + + Ebo ^= Do; + BCa = MLD_KECCAK_ROL(Ebo, 28); + Egu ^= Du; + BCe = MLD_KECCAK_ROL(Egu, 20); + Eka ^= Da; + BCi = MLD_KECCAK_ROL(Eka, 3); + Eme ^= De; + BCo = MLD_KECCAK_ROL(Eme, 45); + Esi ^= Di; + BCu = MLD_KECCAK_ROL(Esi, 61); + Aga = BCa ^ ((~BCe) & BCi); + Age = BCe ^ ((~BCi) & BCo); + Agi = BCi ^ ((~BCo) & BCu); + Ago = BCo ^ ((~BCu) & BCa); + Agu = BCu ^ ((~BCa) & BCe); + + Ebe ^= De; + BCa = MLD_KECCAK_ROL(Ebe, 1); + Egi ^= Di; + BCe = MLD_KECCAK_ROL(Egi, 6); + Eko ^= Do; + BCi = MLD_KECCAK_ROL(Eko, 25); + Emu ^= Du; + BCo = MLD_KECCAK_ROL(Emu, 8); + Esa ^= Da; + BCu = MLD_KECCAK_ROL(Esa, 18); + Aka = BCa ^ ((~BCe) & BCi); + Ake = BCe ^ ((~BCi) & BCo); + Aki = BCi ^ ((~BCo) & BCu); + Ako = BCo ^ ((~BCu) & BCa); + Aku = BCu ^ ((~BCa) & BCe); + + Ebu ^= Du; + BCa = MLD_KECCAK_ROL(Ebu, 27); + Ega ^= Da; + BCe = MLD_KECCAK_ROL(Ega, 36); + Eke ^= De; + BCi = MLD_KECCAK_ROL(Eke, 10); + Emi ^= Di; + BCo = MLD_KECCAK_ROL(Emi, 15); + Eso ^= Do; + BCu = MLD_KECCAK_ROL(Eso, 56); + Ama = BCa ^ ((~BCe) & BCi); + Ame = BCe ^ ((~BCi) & BCo); + Ami = BCi ^ ((~BCo) & BCu); + Amo = BCo ^ ((~BCu) & BCa); + Amu = BCu ^ ((~BCa) & BCe); + + Ebi ^= Di; + BCa = MLD_KECCAK_ROL(Ebi, 62); + Ego ^= Do; + BCe = MLD_KECCAK_ROL(Ego, 55); + Eku ^= Du; + BCi = MLD_KECCAK_ROL(Eku, 39); + Ema ^= Da; + BCo = MLD_KECCAK_ROL(Ema, 41); + Ese ^= De; + BCu = MLD_KECCAK_ROL(Ese, 2); + Asa = BCa ^ ((~BCe) & BCi); + Ase = BCe ^ ((~BCi) & BCo); + Asi = BCi ^ ((~BCo) & BCu); + Aso = BCo ^ ((~BCu) & BCa); + Asu = BCu ^ ((~BCa) & BCe); + } + + /* copyToState(state, A) */ + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} + +void mld_keccakf1600_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X1_NATIVE) + if (mld_keccak_f1600_x1_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X1_NATIVE */ + mld_keccakf1600_permute_c(state); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(keccakf1600) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_KECCAK_NROUNDS +#undef MLD_KECCAK_ROL diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/keccakf1600.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/keccakf1600.h new file mode 100644 index 0000000000..e56adc1561 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/keccakf1600.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_KECCAKF1600_H +#define MLD_FIPS202_KECCAKF1600_H +#include +#include "../cbmc.h" +#include "../common.h" +#include "fips202.h" + +#define MLD_KECCAK_LANES 25 +#define MLD_KECCAK_WAY 4 + +/* + * WARNING: + * The contents of this structure, including the placement + * and interleaving of Keccak lanes, are IMPLEMENTATION-DEFINED. + * The struct is only exposed here to allow its construction on the stack. + */ + +#define mld_keccakf1600_extract_bytes MLD_NAMESPACE(keccakf1600_extract_bytes) +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(data, length)) +); + +#define mld_keccakf1600_xor_bytes MLD_NAMESPACE(keccakf1600_xor_bytes) +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#define mld_keccakf1600x4_extract_bytes \ + MLD_NAMESPACE(keccakf1600x4_extract_bytes) +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + requires(memory_no_alias(data1, length)) + requires(memory_no_alias(data2, length)) + requires(memory_no_alias(data3, length)) + assigns(memory_slice(data0, length)) + assigns(memory_slice(data1, length)) + assigns(memory_slice(data2, length)) + assigns(memory_slice(data3, length)) +); + +#define mld_keccakf1600x4_xor_bytes MLD_NAMESPACE(keccakf1600x4_xor_bytes) +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + /* Case 1: all input buffers are distinct; Case 2: All input buffers are the same */ + requires((data0 == data1 && + data0 == data2 && + data0 == data3) || + (memory_no_alias(data1, length) && + memory_no_alias(data2, length) && + memory_no_alias(data3, length))) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600x4_permute MLD_NAMESPACE(keccakf1600x4_permute) +void mld_keccakf1600x4_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600_permute MLD_NAMESPACE(keccakf1600_permute) +void mld_keccakf1600_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#endif /* !MLD_FIPS202_KECCAKF1600_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/auto.h new file mode 100644 index 0000000000..4375cc1976 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/auto.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [HYBRID] + * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64 + * Becker, Kannwischer + * https://eprint.iacr.org/2022/1243 + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +#define MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* Default FIPS202 assembly profile for AArch64 systems */ + +/* + * Default logic to decide which implementation to use. + * + */ + +/* + * Keccak-f1600 + * + * - On Arm-based Apple CPUs, we pick a pure Neon implementation. + * - Otherwise, unless MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, + * we use lazy-rotation scalar assembly from @[HYBRID]. + * - Otherwise, if MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, we + * fall back to the standard C implementation. + */ +#if defined(__ARM_FEATURE_SHA3) && defined(__APPLE__) +#include "x1_v84a.h" +#elif !defined(MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER) +#include "x1_scalar.h" +#endif + +/* + * Keccak-f1600x2/x4 + * + * The optimal implementation is highly CPU-specific; see @[HYBRID]. + * + * For now, if v8.4-A is not implemented, we fall back to Keccak-f1600. + * If v8.4-A is implemented and we are on an Apple CPU, we use a plain + * Neon-based implementation. + * If v8.4-A is implemented and we are not on an Apple CPU, we use a + * scalar/Neon/Neon hybrid. + * The reason for this distinction is that Apple CPUs appear to implement + * the SHA3 instructions on all SIMD units, while Arm CPUs prior to Cortex-X4 + * don't, and ordinary Neon instructions are still needed. + */ +#if defined(__ARM_FEATURE_SHA3) +/* + * For Apple-M cores, we use a plain implementation leveraging SHA3 + * instructions only. + */ +#if defined(__APPLE__) +#include "x2_v84a.h" +#else +#include "x4_v8a_v84a_scalar.h" +#endif + +#else /* __ARM_FEATURE_SHA3 */ + +#include "x4_v8a_scalar.h" + +#endif /* !__ARM_FEATURE_SHA3 */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h new file mode 100644 index 0000000000..20f6168038 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/src/fips202_native_aarch64.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#define MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H + +#include +#include "../../../../cbmc.h" +#include "../../../../common.h" + + +#define mld_keccakf1600_round_constants \ + MLD_NAMESPACE(keccakf1600_round_constants) +extern const uint64_t mld_keccakf1600_round_constants[]; + +#define mld_keccak_f1600_x1_scalar_asm MLD_NAMESPACE(keccak_f1600_x1_scalar_asm) +void mld_keccak_f1600_x1_scalar_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x1_v84a_asm MLD_NAMESPACE(keccak_f1600_x1_v84a_asm) +void mld_keccak_f1600_x1_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x2_v84a_asm MLD_NAMESPACE(keccak_f1600_x2_v84a_asm) +void mld_keccak_f1600_x2_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 2)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 2)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c new file mode 100644 index 0000000000..05e9cbfeec --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/src/keccakf1600_round_constants.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../../common.h" + +#if (defined(MLD_FIPS202_AARCH64_NEED_X1_SCALAR) || \ + defined(MLD_FIPS202_AARCH64_NEED_X1_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X2_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID)) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "fips202_native_aarch64.h" + +MLD_ALIGN const uint64_t mld_keccakf1600_round_constants[] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, +}; + +#else /* (MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_aarch64_round_constants) + +#endif /* !((MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/x1_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/x1_scalar.h new file mode 100644 index 0000000000..681b991371 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/x1_scalar.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_SCALAR + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + mld_keccak_f1600_x1_scalar_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/x1_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/x1_v84a.h new file mode 100644 index 0000000000..d15c8c26f3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/x1_v84a.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x1_v84a_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/x2_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/x2_v84a.h new file mode 100644 index 0000000000..16c22fa1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/x2_v84a.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X2_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" + + +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x2_v84a_asm(state + 0 * 25, mld_keccakf1600_round_constants); + mld_keccak_f1600_x2_v84a_asm(state + 2 * 25, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h new file mode 100644 index 0000000000..0f7f8fe499 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_scalar.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(state, + mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h new file mode 100644 index 0000000000..3da883b762 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm( + state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/api.h new file mode 100644 index 0000000000..4625c9a1ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/api.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_API_H +#define MLD_FIPS202_NATIVE_API_H +/* + * FIPS-202 native interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + */ + +#include +#include "../../cbmc.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* + * This is the C<->native interface allowing for the drop-in + * of custom Keccak-F1600 implementations. + * + * A _backend_ is a specific implementation of parts of this interface. + * + * You can replace 1-fold or 4-fold batched Keccak-F1600. + * To enable, set MLD_USE_FIPS202_X1_NATIVE or MLD_USE_FIPS202_X4_NATIVE + * in your backend, and define the inline wrappers mld_keccak_f1600_x1_native() + * and/or mld_keccak_f1600_x4_native(), respectively, to forward to your + * implementation. + */ + +#if defined(MLD_USE_FIPS202_X1_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 1)) +); +#endif /* MLD_USE_FIPS202_X1_NATIVE */ +#if defined(MLD_USE_FIPS202_X4_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 4)) +); +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + +#endif /* !MLD_FIPS202_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/auto.h new file mode 100644 index 0000000000..0a09c733c8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/auto.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AUTO_H +#define MLD_FIPS202_NATIVE_AUTO_H + +/* + * Default FIPS202 backend + */ +#include "../../sys.h" + +#if defined(MLD_SYS_AARCH64) +#include "aarch64/auto.h" +#endif + +#if defined(MLD_SYS_X86_64) && defined(MLD_SYS_X86_64_AVX2) +#include "x86_64/xkcp.h" +#endif + +#endif /* !MLD_FIPS202_NATIVE_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c new file mode 100644 index 0000000000..4eaad2fd66 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* +Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, +Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby +denoted as "the implementer". + +For more information, feedback or questions, please refer to our websites: +http://keccak.noekeon.org/ +http://keyak.noekeon.org/ +http://ketje.noekeon.org/ + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +/* + * Changes for mlkem-native/mldsa-native: + * - copyFromState and copyToState operate on uninterleaved + * Keccak states in memory. + */ + +#include "../../../../common.h" +#if defined(MLD_FIPS202_X86_64_XKCP) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include + +#include "KeccakP_1600_times4_SIMD256.h" + +#ifndef MLD_SYS_LITTLE_ENDIAN +#error Expecting a little-endian platform +#endif + +#define ANDnu256(a, b) _mm256_andnot_si256(a, b) +#define CONST256(a) _mm256_load_si256((const __m256i *)&(a)) +#define CONST256_64(a) (__m256i) _mm256_broadcast_sd((const double *)(&a)) +#define ROL64in256(d, a, o) \ + d = _mm256_or_si256(_mm256_slli_epi64(a, o), _mm256_srli_epi64(a, 64 - (o))) +#define ROL64in256_8(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho8)) +#define ROL64in256_56(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho56)) +static const uint64_t rho8[4] = {0x0605040302010007, 0x0E0D0C0B0A09080F, + 0x1615141312111017, 0x1E1D1C1B1A19181F}; +static const uint64_t rho56[4] = {0x0007060504030201, 0x080F0E0D0C0B0A09, + 0x1017161514131211, 0x181F1E1D1C1B1A19}; +#define STORE256(a, b) _mm256_store_si256((__m256i *)&(a), b) +#define XOR256(a, b) _mm256_xor_si256(a, b) +#define XOReq256(a, b) a = _mm256_xor_si256(a, b) + +#define SnP_laneLengthInBytes 8 + +#define declareABCDE \ + __m256i Aba, Abe, Abi, Abo, Abu; \ + __m256i Aga, Age, Agi, Ago, Agu; \ + __m256i Aka, Ake, Aki, Ako, Aku; \ + __m256i Ama, Ame, Ami, Amo, Amu; \ + __m256i Asa, Ase, Asi, Aso, Asu; \ + __m256i Bba, Bbe, Bbi, Bbo, Bbu; \ + __m256i Bga, Bge, Bgi, Bgo, Bgu; \ + __m256i Bka, Bke, Bki, Bko, Bku; \ + __m256i Bma, Bme, Bmi, Bmo, Bmu; \ + __m256i Bsa, Bse, Bsi, Bso, Bsu; \ + __m256i Ca, Ce, Ci, Co, Cu; \ + __m256i Ca1, Ce1, Ci1, Co1, Cu1; \ + __m256i Da, De, Di, Do, Du; \ + __m256i Eba, Ebe, Ebi, Ebo, Ebu; \ + __m256i Ega, Ege, Egi, Ego, Egu; \ + __m256i Eka, Eke, Eki, Eko, Eku; \ + __m256i Ema, Eme, Emi, Emo, Emu; \ + __m256i Esa, Ese, Esi, Eso, Esu; + +#define prepareTheta \ + Ca = XOR256(Aba, XOR256(Aga, XOR256(Aka, XOR256(Ama, Asa)))); \ + Ce = XOR256(Abe, XOR256(Age, XOR256(Ake, XOR256(Ame, Ase)))); \ + Ci = XOR256(Abi, XOR256(Agi, XOR256(Aki, XOR256(Ami, Asi)))); \ + Co = XOR256(Abo, XOR256(Ago, XOR256(Ako, XOR256(Amo, Aso)))); \ + Cu = XOR256(Abu, XOR256(Agu, XOR256(Aku, XOR256(Amu, Asu)))); + +/* + * --- Theta Rho Pi Chi Iota Prepare-theta + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + Ca = E##ba; \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + Ce = E##be; \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + Ci = E##bi; \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + Co = E##bo; \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + Cu = E##bu; \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(Ca, E##ga); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(Ce, E##ge); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + XOReq256(Ci, E##gi); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + XOReq256(Co, E##go); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + XOReq256(Cu, E##gu); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(Ca, E##ka); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(Ce, E##ke); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + XOReq256(Ci, E##ki); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + XOReq256(Co, E##ko); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + XOReq256(Cu, E##ku); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(Ca, E##ma); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(Ce, E##me); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + XOReq256(Ci, E##mi); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + XOReq256(Co, E##mo); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + XOReq256(Cu, E##mu); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(Ca, E##sa); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(Ce, E##se); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + XOReq256(Ci, E##si); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + XOReq256(Co, E##so); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); \ + XOReq256(Cu, E##su); + + +/* + * --- Theta Rho Pi Chi Iota + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIota(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); + + +static MLD_ALIGN const uint64_t keccakf1600RoundConstants[24] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +#include + +#define copyFromState(X, state) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m256i _idx = \ + _mm256_set_epi64x((long long)&state64[75], (long long)&state64[50], \ + (long long)&state64[25], (long long)&state64[0]); \ + X##ba = _mm256_i64gather_epi64((long long *)(0 * 8), _idx, 1); \ + X##be = _mm256_i64gather_epi64((long long *)(1 * 8), _idx, 1); \ + X##bi = _mm256_i64gather_epi64((long long *)(2 * 8), _idx, 1); \ + X##bo = _mm256_i64gather_epi64((long long *)(3 * 8), _idx, 1); \ + X##bu = _mm256_i64gather_epi64((long long *)(4 * 8), _idx, 1); \ + X##ga = _mm256_i64gather_epi64((long long *)(5 * 8), _idx, 1); \ + X##ge = _mm256_i64gather_epi64((long long *)(6 * 8), _idx, 1); \ + X##gi = _mm256_i64gather_epi64((long long *)(7 * 8), _idx, 1); \ + X##go = _mm256_i64gather_epi64((long long *)(8 * 8), _idx, 1); \ + X##gu = _mm256_i64gather_epi64((long long *)(9 * 8), _idx, 1); \ + X##ka = _mm256_i64gather_epi64((long long *)(10 * 8), _idx, 1); \ + X##ke = _mm256_i64gather_epi64((long long *)(11 * 8), _idx, 1); \ + X##ki = _mm256_i64gather_epi64((long long *)(12 * 8), _idx, 1); \ + X##ko = _mm256_i64gather_epi64((long long *)(13 * 8), _idx, 1); \ + X##ku = _mm256_i64gather_epi64((long long *)(14 * 8), _idx, 1); \ + X##ma = _mm256_i64gather_epi64((long long *)(15 * 8), _idx, 1); \ + X##me = _mm256_i64gather_epi64((long long *)(16 * 8), _idx, 1); \ + X##mi = _mm256_i64gather_epi64((long long *)(17 * 8), _idx, 1); \ + X##mo = _mm256_i64gather_epi64((long long *)(18 * 8), _idx, 1); \ + X##mu = _mm256_i64gather_epi64((long long *)(19 * 8), _idx, 1); \ + X##sa = _mm256_i64gather_epi64((long long *)(20 * 8), _idx, 1); \ + X##se = _mm256_i64gather_epi64((long long *)(21 * 8), _idx, 1); \ + X##si = _mm256_i64gather_epi64((long long *)(22 * 8), _idx, 1); \ + X##so = _mm256_i64gather_epi64((long long *)(23 * 8), _idx, 1); \ + X##su = _mm256_i64gather_epi64((long long *)(24 * 8), _idx, 1); \ + } while (0); + +#define SCATTER_STORE256(state, idx, v) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m128d t = _mm_castsi128_pd(_mm256_castsi256_si128((v))); \ + _mm_storel_pd((double *)&state64[0 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[25 + (idx)], t); \ + t = _mm_castsi128_pd(_mm256_extracti128_si256((v), 1)); \ + _mm_storel_pd((double *)&state64[50 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[75 + (idx)], t); \ + } while (0) + +#define copyToState(state, X) \ + SCATTER_STORE256(state, 0, X##ba); \ + SCATTER_STORE256(state, 1, X##be); \ + SCATTER_STORE256(state, 2, X##bi); \ + SCATTER_STORE256(state, 3, X##bo); \ + SCATTER_STORE256(state, 4, X##bu); \ + SCATTER_STORE256(state, 5, X##ga); \ + SCATTER_STORE256(state, 6, X##ge); \ + SCATTER_STORE256(state, 7, X##gi); \ + SCATTER_STORE256(state, 8, X##go); \ + SCATTER_STORE256(state, 9, X##gu); \ + SCATTER_STORE256(state, 10, X##ka); \ + SCATTER_STORE256(state, 11, X##ke); \ + SCATTER_STORE256(state, 12, X##ki); \ + SCATTER_STORE256(state, 13, X##ko); \ + SCATTER_STORE256(state, 14, X##ku); \ + SCATTER_STORE256(state, 15, X##ma); \ + SCATTER_STORE256(state, 16, X##me); \ + SCATTER_STORE256(state, 17, X##mi); \ + SCATTER_STORE256(state, 18, X##mo); \ + SCATTER_STORE256(state, 19, X##mu); \ + SCATTER_STORE256(state, 20, X##sa); \ + SCATTER_STORE256(state, 21, X##se); \ + SCATTER_STORE256(state, 22, X##si); \ + SCATTER_STORE256(state, 23, X##so); \ + SCATTER_STORE256(state, 24, X##su); + +#define copyStateVariables(X, Y) \ + X##ba = Y##ba; \ + X##be = Y##be; \ + X##bi = Y##bi; \ + X##bo = Y##bo; \ + X##bu = Y##bu; \ + X##ga = Y##ga; \ + X##ge = Y##ge; \ + X##gi = Y##gi; \ + X##go = Y##go; \ + X##gu = Y##gu; \ + X##ka = Y##ka; \ + X##ke = Y##ke; \ + X##ki = Y##ki; \ + X##ko = Y##ko; \ + X##ku = Y##ku; \ + X##ma = Y##ma; \ + X##me = Y##me; \ + X##mi = Y##mi; \ + X##mo = Y##mo; \ + X##mu = Y##mu; \ + X##sa = Y##sa; \ + X##se = Y##se; \ + X##si = Y##si; \ + X##so = Y##so; \ + X##su = Y##su; + +/* clang-format off */ +#define rounds24 \ + prepareTheta \ + thetaRhoPiChiIotaPrepareTheta( 0, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 1, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 2, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 3, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 4, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 5, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 6, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 7, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 8, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 9, E, A) \ + thetaRhoPiChiIotaPrepareTheta(10, A, E) \ + thetaRhoPiChiIotaPrepareTheta(11, E, A) \ + thetaRhoPiChiIotaPrepareTheta(12, A, E) \ + thetaRhoPiChiIotaPrepareTheta(13, E, A) \ + thetaRhoPiChiIotaPrepareTheta(14, A, E) \ + thetaRhoPiChiIotaPrepareTheta(15, E, A) \ + thetaRhoPiChiIotaPrepareTheta(16, A, E) \ + thetaRhoPiChiIotaPrepareTheta(17, E, A) \ + thetaRhoPiChiIotaPrepareTheta(18, A, E) \ + thetaRhoPiChiIotaPrepareTheta(19, E, A) \ + thetaRhoPiChiIotaPrepareTheta(20, A, E) \ + thetaRhoPiChiIotaPrepareTheta(21, E, A) \ + thetaRhoPiChiIotaPrepareTheta(22, A, E) \ + thetaRhoPiChiIota(23, E, A) +/* clang-format on */ + +void mld_keccakf1600x4_permute24(void *states) +{ + __m256i *statesAsLanes = (__m256i *)states; + declareABCDE copyFromState(A, statesAsLanes) + rounds24 copyToState(statesAsLanes, A) +} + +#else /* MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_avx2_keccakx4) + +#endif /* !(MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef ANDnu256 +#undef CONST256 +#undef CONST256_64 +#undef ROL64in256 +#undef ROL64in256_8 +#undef ROL64in256_56 +#undef STORE256 +#undef XOR256 +#undef XOReq256 +#undef SnP_laneLengthInBytes +#undef declareABCDE +#undef prepareTheta +#undef thetaRhoPiChiIotaPrepareTheta +#undef thetaRhoPiChiIota +#undef copyFromState +#undef SCATTER_STORE256 +#undef copyToState +#undef copyStateVariables +#undef rounds24 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h new file mode 100644 index 0000000000..3499d38e2c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H +#define MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H + +#include "../../../../common.h" + +#define mld_keccakf1600x4_permute24 \ + MLD_NAMESPACE(KeccakP1600times4_PermuteAll_24rounds) +void mld_keccakf1600x4_permute24(void *states); + +#endif /* !MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/x86_64/xkcp.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/x86_64/xkcp.h new file mode 100644 index 0000000000..c03642d7e0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/fips202/native/x86_64/xkcp.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_XKCP_H +#define MLD_FIPS202_NATIVE_X86_64_XKCP_H + +#include "../../../common.h" + +#define MLD_FIPS202_X86_64_XKCP + +#if !defined(__ASSEMBLER__) +#include +#include "../api.h" +#include "src/KeccakP_1600_times4_SIMD256.h" + +#define MLD_USE_FIPS202_X4_NATIVE +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_keccakf1600x4_permute24(state); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_X86_64_XKCP_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/meta.h new file mode 100644 index 0000000000..c6f6ad47b0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/meta.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_META_H +#define MLD_NATIVE_AARCH64_META_H + +/* Set of primitives that this backend replaces */ +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_AARCH64 + + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/arith_native_aarch64.h" + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + mld_ntt_asm(data, mld_aarch64_ntt_zetas_layer123456, + mld_aarch64_ntt_zetas_layer78); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + mld_intt_asm(data, mld_aarch64_intt_zetas_layer78, + mld_aarch64_intt_zetas_layer123456); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + if (len != MLDSA_N || + buflen % 24 != 0) /* NEON support is mandatory for AArch64 */ + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N, hence, this cast is safe. */ + return (int)mld_rej_uniform_asm(r, buf, buflen, mld_rej_uniform_table); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_32_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_88_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + mld_poly_caddq_asm(a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_32_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_88_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + return mld_poly_chknorm_asm(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_17_asm(r, buf, mld_polyz_unpack_17_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_19_asm(r, buf, mld_polyz_unpack_19_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t out[MLDSA_N], const int32_t in0[MLDSA_N], + const int32_t in1[MLDSA_N]) +{ + mld_poly_pointwise_montgomery_asm(out, in0, in1); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l4_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l5_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l7_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ +#endif /* !MLD_NATIVE_AARCH64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/src/aarch64_zetas.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/src/aarch64_zetas.c new file mode 100644 index 0000000000..9ab7b9a68c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/src/aarch64_zetas.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Table of zeta values used in the AArch64 forward NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer123456[] = { + -3572223, -915382907, 3765607, 964937599, 3761513, 963888510, + -3201494, -820383522, -2883726, -738955404, -3145678, -806080660, + -3201430, -820367122, 0, 0, -601683, -154181397, + -3370349, -863652652, -4063053, -1041158200, 3602218, 923069133, + 3182878, 815613168, 2740543, 702264730, -3586446, -919027554, + 0, 0, 3542485, 907762539, 2663378, 682491182, + -1674615, -429120452, -3110818, -797147778, 2101410, 538486762, + 3704823, 949361686, 1159875, 297218217, 0, 0, + 2682288, 687336873, -3524442, -903139016, -434125, -111244624, + 394148, 101000509, 928749, 237992130, 1095468, 280713909, + -3506380, -898510625, 0, 0, 2129892, 545785280, + 676590, 173376332, -1335936, -342333886, 2071829, 530906624, + -4018989, -1029866791, 3241972, 830756018, 2156050, 552488273, + 0, 0, 3764867, 964747974, -3227876, -827143915, + 1714295, 439288460, 3415069, 875112161, 1759347, 450833045, + -817536, -209493775, -3574466, -915957677, 0, 0, + -1005239, -257592709, 2453983, 628833668, 1460718, 374309300, + 3756790, 962678241, -1935799, -496048908, -1716988, -439978542, + -3950053, -1012201926, 0, 0, 557458, 142848732, + -642628, -164673562, -3585098, -918682129, -2897314, -742437332, + 3192354, 818041395, 556856, 142694469, 3870317, 991769559, + 0, 0, -1221177, -312926867, 2815639, 721508096, + 2283733, 585207070, 2917338, 747568486, 1853806, 475038184, + 3345963, 857403734, 1858416, 476219497, 0, 0, +}; + +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer78[] = { + 3073009, 1277625, -2635473, 3852015, 787459213, + 327391679, -675340520, 987079667, 1753, -2659525, + 2660408, -59148, 449207, -681503850, 681730119, + -15156688, -1935420, -1455890, -1780227, 2772600, + -495951789, -373072124, -456183549, 710479343, 4183372, + -3222807, -3121440, -274060, 1071989969, -825844983, + -799869667, -70227934, 1182243, 636927, -3956745, + -3284915, 302950022, 163212680, -1013916752, -841760171, + 87208, -3965306, -2296397, -3716946, 22347069, + -1016110510, -588452222, -952468207, 2508980, 2028118, + 1937570, -3815725, 642926661, 519705671, 496502727, + -977780347, -27812, 1009365, -1979497, -3956944, + -7126831, 258649997, -507246529, -1013967746, 822541, + -2454145, 1596822, -3759465, 210776307, -628875181, + 409185979, -963363710, 2811291, -2983781, -1109516, + 4158088, 720393920, -764594519, -284313712, 1065510939, + -1685153, 2678278, -3551006, -250446, -431820817, + 686309310, -909946047, -64176841, -3410568, -3768948, + 635956, -2455377, -873958779, -965793731, 162963861, + -629190881, 1528066, 482649, 1148858, -2962264, + 391567239, 123678909, 294395108, -759080783, -4146264, + 2192938, 2387513, -268456, -1062481036, 561940831, + 611800717, -68791907, -1772588, -1727088, -3611750, + -3180456, -454226054, -442566669, -925511710, -814992530, + -565603, 169688, 2462444, -3334383, -144935890, + 43482586, 631001801, -854436357, 3747250, 1239911, + 3195676, 1254190, 960233614, 317727459, 818892658, + 321386456, 2296099, -3838479, 2642980, -12417, + 588375860, -983611064, 677264190, -3181859, -4166425, + -3488383, 1987814, -3197248, -1067647297, -893898890, + 509377762, -819295484, 2998219, -89301, -1354892, + -1310261, 768294260, -22883400, -347191365, -335754661, + 141835, 2513018, 613238, -2218467, 36345249, + 643961400, 157142369, -568482643, 1736313, 235407, + -3250154, 3258457, 444930577, 60323094, -832852657, + 834980303, -458740, 4040196, 2039144, -818761, + -117552223, 1035301089, 522531086, -209807681, -1921994, + -3472069, -1879878, -2178965, -492511373, -889718424, + -481719139, -558360247, -2579253, 1787943, -2391089, + -2254727, -660934133, 458160776, -612717067, -577774276, + -1623354, -2374402, 586241, 527981, -415984810, + -608441020, 150224382, 135295244, 2105286, -2033807, + -1179613, -2743411, 539479988, -521163479, -302276083, + -702999655, 3482206, -4182915, -1300016, -2362063, + 892316032, -1071872863, -333129378, -605279149, -1476985, + 2491325, 507927, -724804, -378477722, 638402564, + 130156402, -185731180, 1994046, -1393159, -1187885, + -1834526, 510974714, -356997292, -304395785, -470097680, + -1317678, 2461387, 3035980, 621164, -337655269, + 630730945, 777970524, 159173408, -3033742, 2647994, + -2612853, 749577, -777397036, 678549029, -669544140, + 192079267, -338420, 3009748, 4148469, -4022750, + -86720197, 771248568, 1063046068, -1030830548, 3901472, + -1226661, 2925816, 3374250, 999753034, -314332144, + 749740976, 864652284, 3980599, -1615530, 1665318, + 1163598, 1020029345, -413979908, 426738094, 298172236, + 2569011, 1723229, 2028038, -3369273, 658309618, + 441577800, 519685171, -863376927, 1356448, -2775755, + 2683270, -2778788, 347590090, -711287812, 687588511, + -712065019, 3994671, -1370517, 3363542, 545376, + 1023635298, -351195274, 861908357, 139752717, -11879, + 3020393, 214880, -770441, -3043996, 773976352, + 55063046, -197425671, -3467665, 2312838, -653275, + -459163, -888589898, 592665232, -167401858, -117660617, + 3105558, 508145, 860144, 140244, 795799901, + 130212265, 220412084, 35937555, -1103344, -553718, + 3430436, -1514152, -282732136, -141890356, 879049958, + -388001774, 348812, -327848, 1011223, -2354215, + 89383150, -84011120, 259126110, -603268097, -2185084, + 2358373, -3014420, 2926054, -559928242, 604333585, + -772445769, 749801963, 3123762, -2193087, -1716814, + -392707, 800464680, -561979013, -439933955, -100631253, + -3818627, -1922253, -2236726, 1744507, -978523985, + -492577742, -573161516, 447030292, -303005, -3974485, + 1900052, 1054478, -77645096, -1018462631, 486888731, + 270210213, 3531229, -3773731, -781875, -731434, + 904878186, -967019376, -200355636, -187430119, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer78[] = { + -1744507, 2236726, 1922253, 3818627, -447030292, 573161516, + 492577742, 978523985, 731434, 781875, 3773731, -3531229, + 187430119, 200355636, 967019376, -904878186, -1054478, -1900052, + 3974485, 303005, -270210213, -486888731, 1018462631, 77645096, + 2354215, -1011223, 327848, -348812, 603268097, -259126110, + 84011120, -89383150, 392707, 1716814, 2193087, -3123762, + 100631253, 439933955, 561979013, -800464680, -2926054, 3014420, + -2358373, 2185084, -749801963, 772445769, -604333585, 559928242, + 459163, 653275, -2312838, 3467665, 117660617, 167401858, + -592665232, 888589898, 1514152, -3430436, 553718, 1103344, + 388001774, -879049958, 141890356, 282732136, -140244, -860144, + -508145, -3105558, -35937555, -220412084, -130212265, -795799901, + 2778788, -2683270, 2775755, -1356448, 712065019, -687588511, + 711287812, -347590090, 770441, -214880, -3020393, 11879, + 197425671, -55063046, -773976352, 3043996, -545376, -3363542, + 1370517, -3994671, -139752717, -861908357, 351195274, -1023635298, + -3374250, -2925816, 1226661, -3901472, -864652284, -749740976, + 314332144, -999753034, 3369273, -2028038, -1723229, -2569011, + 863376927, -519685171, -441577800, -658309618, -1163598, -1665318, + 1615530, -3980599, -298172236, -426738094, 413979908, -1020029345, + -621164, -3035980, -2461387, 1317678, -159173408, -777970524, + -630730945, 337655269, 4022750, -4148469, -3009748, 338420, + 1030830548, -1063046068, -771248568, 86720197, -749577, 2612853, + -2647994, 3033742, -192079267, 669544140, -678549029, 777397036, + 2362063, 1300016, 4182915, -3482206, 605279149, 333129378, + 1071872863, -892316032, 1834526, 1187885, 1393159, -1994046, + 470097680, 304395785, 356997292, -510974714, 724804, -507927, + -2491325, 1476985, 185731180, -130156402, -638402564, 378477722, + 2254727, 2391089, -1787943, 2579253, 577774276, 612717067, + -458160776, 660934133, 2743411, 1179613, 2033807, -2105286, + 702999655, 302276083, 521163479, -539479988, -527981, -586241, + 2374402, 1623354, -135295244, -150224382, 608441020, 415984810, + -3258457, 3250154, -235407, -1736313, -834980303, 832852657, + -60323094, -444930577, 2178965, 1879878, 3472069, 1921994, + 558360247, 481719139, 889718424, 492511373, 818761, -2039144, + -4040196, 458740, 209807681, -522531086, -1035301089, 117552223, + 3197248, -1987814, 3488383, 4166425, 819295484, -509377762, + 893898890, 1067647297, 2218467, -613238, -2513018, -141835, + 568482643, -157142369, -643961400, -36345249, 1310261, 1354892, + 89301, -2998219, 335754661, 347191365, 22883400, -768294260, + 3334383, -2462444, -169688, 565603, 854436357, -631001801, + -43482586, 144935890, 12417, -2642980, 3838479, -2296099, + 3181859, -677264190, 983611064, -588375860, -1254190, -3195676, + -1239911, -3747250, -321386456, -818892658, -317727459, -960233614, + 2962264, -1148858, -482649, -1528066, 759080783, -294395108, + -123678909, -391567239, 3180456, 3611750, 1727088, 1772588, + 814992530, 925511710, 442566669, 454226054, 268456, -2387513, + -2192938, 4146264, 68791907, -611800717, -561940831, 1062481036, + -4158088, 1109516, 2983781, -2811291, -1065510939, 284313712, + 764594519, -720393920, 2455377, -635956, 3768948, 3410568, + 629190881, -162963861, 965793731, 873958779, 250446, 3551006, + -2678278, 1685153, 64176841, 909946047, -686309310, 431820817, + 3815725, -1937570, -2028118, -2508980, 977780347, -496502727, + -519705671, -642926661, 3759465, -1596822, 2454145, -822541, + 963363710, -409185979, 628875181, -210776307, 3956944, 1979497, + -1009365, 27812, 1013967746, 507246529, -258649997, 7126831, + 274060, 3121440, 3222807, -4183372, 70227934, 799869667, + 825844983, -1071989969, 3716946, 2296397, 3965306, -87208, + 952468207, 588452222, 1016110510, -22347069, 3284915, 3956745, + -636927, -1182243, 841760171, 1013916752, -163212680, -302950022, + -3852015, 2635473, -1277625, -3073009, -987079667, 675340520, + -327391679, -787459213, -2772600, 1780227, 1455890, 1935420, + -710479343, 456183549, 373072124, 495951789, 59148, -2660408, + 2659525, -1753, 15156688, -681730119, 681503850, -449207, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer123456[] = { + -2283733, -585207070, 0, 0, -1858416, -476219497, + -3345963, -857403734, -2815639, -721508096, 0, 0, + -1853806, -475038184, -2917338, -747568486, 3585098, 918682129, + 0, 0, -3870317, -991769559, -556856, -142694469, + 642628, 164673562, 0, 0, -3192354, -818041395, + 2897314, 742437332, -1460718, -374309300, 0, 0, + 3950053, 1012201926, 1716988, 439978542, -2453983, -628833668, + 0, 0, 1935799, 496048908, -3756790, -962678241, + -1714295, -439288460, 0, 0, 3574466, 915957677, + 817536, 209493775, 3227876, 827143915, 0, 0, + -1759347, -450833045, -3415069, -875112161, 1335936, 342333886, + 0, 0, -2156050, -552488273, -3241972, -830756018, + -676590, -173376332, 0, 0, 4018989, 1029866791, + -2071829, -530906624, 434125, 111244624, 0, 0, + 3506380, 898510625, -1095468, -280713909, 3524442, 903139016, + 0, 0, -928749, -237992130, -394148, -101000509, + 1674615, 429120452, 0, 0, -1159875, -297218217, + -3704823, -949361686, -2663378, -682491182, 0, 0, + -2101410, -538486762, 3110818, 797147778, 4063053, 1041158200, + 0, 0, 3586446, 919027554, -2740543, -702264730, + 3370349, 863652652, 0, 0, -3182878, -815613168, + -3602218, -923069133, -294725, -75523344, -3761513, -963888510, + -3765607, -964937599, 3201430, 820367122, 3145678, 806080660, + 2883726, 738955404, 3201494, 820383522, 1221177, 312926867, + -557458, -142848732, 1005239, 257592709, -3764867, -964747974, + -2129892, -545785280, -2682288, -687336873, -3542485, -907762539, + 601683, 154181397, 0, 0, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_zetas) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h new file mode 100644 index 0000000000..e77f55014c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/src/arith_native_aarch64.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#define MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H + +#include +#include "../../../common.h" + +#define mld_aarch64_ntt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_ntt_zetas_layer123456) +#define mld_aarch64_ntt_zetas_layer78 MLD_NAMESPACE(aarch64_ntt_zetas_layer78) + +#define mld_aarch64_intt_zetas_layer78 MLD_NAMESPACE(aarch64_intt_zetas_layer78) +#define mld_aarch64_intt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_intt_zetas_layer123456) + +extern const int32_t mld_aarch64_ntt_zetas_layer123456[]; +extern const int32_t mld_aarch64_ntt_zetas_layer78[]; + +extern const int32_t mld_aarch64_intt_zetas_layer78[]; +extern const int32_t mld_aarch64_intt_zetas_layer123456[]; + +#define mld_rej_uniform_table MLD_NAMESPACE(rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[]; +#define mld_rej_uniform_eta_table MLD_NAMESPACE(rej_uniform_eta_table) +extern const uint8_t mld_rej_uniform_eta_table[]; + +#define mld_polyz_unpack_17_indices MLD_NAMESPACE(polyz_unpack_17_indices) +extern const uint8_t mld_polyz_unpack_17_indices[]; +#define mld_polyz_unpack_19_indices MLD_NAMESPACE(polyz_unpack_19_indices) +extern const uint8_t mld_polyz_unpack_19_indices[]; + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_ntt_asm MLD_NAMESPACE(ntt_asm) +void mld_ntt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_intt_asm MLD_NAMESPACE(intt_asm) +void mld_intt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_rej_uniform_asm MLD_NAMESPACE(rej_uniform_asm) +uint64_t mld_rej_uniform_asm(int32_t *r, const uint8_t *buf, unsigned buflen, + const uint8_t *table); + +#define mld_rej_uniform_eta2_asm MLD_NAMESPACE(rej_uniform_eta2_asm) +uint64_t mld_rej_uniform_eta2_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_rej_uniform_eta4_asm MLD_NAMESPACE(rej_uniform_eta4_asm) +uint64_t mld_rej_uniform_eta4_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_poly_decompose_32_asm MLD_NAMESPACE(poly_decompose_32_asm) +void mld_poly_decompose_32_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_asm MLD_NAMESPACE(poly_decompose_88_asm) +void mld_poly_decompose_88_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_asm MLD_NAMESPACE(poly_caddq_asm) +void mld_poly_caddq_asm(int32_t *a); + +#define mld_poly_use_hint_32_asm MLD_NAMESPACE(poly_use_hint_32_asm) +void mld_poly_use_hint_32_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_asm MLD_NAMESPACE(poly_use_hint_88_asm) +void mld_poly_use_hint_88_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_asm MLD_NAMESPACE(poly_chknorm_asm) +int mld_poly_chknorm_asm(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_asm MLD_NAMESPACE(polyz_unpack_17_asm) +void mld_polyz_unpack_17_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_polyz_unpack_19_asm MLD_NAMESPACE(polyz_unpack_19_asm) +void mld_polyz_unpack_19_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_poly_pointwise_montgomery_asm \ + MLD_NAMESPACE(poly_pointwise_montgomery_asm) +void mld_poly_pointwise_montgomery_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l4_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l4_asm) +void mld_polyvecl_pointwise_acc_montgomery_l4_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l5_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l5_asm) +void mld_polyvecl_pointwise_acc_montgomery_l5_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l7_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l7_asm) +void mld_polyvecl_pointwise_acc_montgomery_l7_asm(int32_t *, const int32_t *, + const int32_t *); + +#endif /* !MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c new file mode 100644 index 0000000000..7ef915b587 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/src/polyz_unpack_table.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* Table of indices used for tbl instructions in polyz_unpack_{17,19}. */ + +MLD_ALIGN const uint8_t mld_polyz_unpack_17_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, + 9, 10, 11, 255, 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, + 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, 8, 9, 10, 255, + 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, 17, 18, 19, 255, +}; + +MLD_ALIGN const uint8_t mld_polyz_unpack_19_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 5, 6, 7, 255, 7, 8, 9, 255, + 10, 11, 12, 255, 12, 13, 14, 255, 15, 16, 17, 255, 17, 18, 19, 255, + 4, 5, 6, 255, 6, 7, 8, 255, 9, 10, 11, 255, 11, 12, 13, 255, + 14, 15, 16, 255, 16, 17, 18, 255, 19, 20, 21, 255, 21, 22, 23, 255, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_polyz_unpack_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c new file mode 100644 index 0000000000..cf21509cbf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/src/rej_uniform_eta_table.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by 16-bit rejection sampling (rej_eta). + * Adapted from ML-KEM for ML-DSA eta rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_eta_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 2, 3, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 4, 5, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 2, 3, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 7 */, + 6, 7, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 2, 3, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 11 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 13 */, + 2, 3, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 15 */, + 8, 9, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 16 */, + 0, 1, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 17 */, + 2, 3, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 18 */, + 0, 1, 2, 3, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 19 */, + 4, 5, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 20 */, + 0, 1, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 21 */, + 2, 3, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 22 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 23 */, + 6, 7, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 24 */, + 0, 1, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 25 */, + 2, 3, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 26 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 27 */, + 4, 5, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 28 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 29 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 30 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 255, 255, 255, 255, 255, 255 /* 31 */, + 10, 11, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 32 */, + 0, 1, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 33 */, + 2, 3, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 34 */, + 0, 1, 2, 3, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 35 */, + 4, 5, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 36 */, + 0, 1, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 37 */, + 2, 3, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 38 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 39 */, + 6, 7, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 40 */, + 0, 1, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 41 */, + 2, 3, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 42 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 43 */, + 4, 5, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 44 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 45 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 46 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 255, 255, 255, 255, 255, 255 /* 47 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 48 */, + 0, 1, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 49 */, + 2, 3, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 50 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 51 */, + 4, 5, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 52 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 53 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 54 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 55 */, + 6, 7, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 56 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 57 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 58 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 59 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 60 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 61 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 62 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 63 */, + 12, 13, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 64 */, + 0, 1, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 65 */, + 2, 3, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 66 */, + 0, 1, 2, 3, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 67 */, + 4, 5, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 68 */, + 0, 1, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 69 */, + 2, 3, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 70 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 71 */, + 6, 7, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 72 */, + 0, 1, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 73 */, + 2, 3, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 74 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 75 */, + 4, 5, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 76 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 77 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 78 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 255, 255, 255, 255, 255, 255 /* 79 */, + 8, 9, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 80 */, + 0, 1, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 81 */, + 2, 3, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 82 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 83 */, + 4, 5, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 84 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 85 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 86 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 87 */, + 6, 7, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 88 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 89 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 90 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 91 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 92 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 93 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 94 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 255, 255, 255, 255 /* 95 */, + 10, 11, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 96 */, + 0, 1, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 97 */, + 2, 3, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 98 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 99 */, + 4, 5, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 100 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 101 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 102 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 103 */, + 6, 7, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 104 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 105 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 106 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 107 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 108 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 109 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 110 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 255, 255, 255, 255 /* 111 */, + 8, 9, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 112 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 113 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 114 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 115 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 116 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 117 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 118 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 119 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 120 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 121 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 122 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 123 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 124 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 125 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 126 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 255, 255 /* 127 */, + 14, 15, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 128 */, + 0, 1, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 129 */, + 2, 3, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 130 */, + 0, 1, 2, 3, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 131 */, + 4, 5, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 132 */, + 0, 1, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 133 */, + 2, 3, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 134 */, + 0, 1, 2, 3, 4, 5, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 135 */, + 6, 7, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 136 */, + 0, 1, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 137 */, + 2, 3, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 138 */, + 0, 1, 2, 3, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 139 */, + 4, 5, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 140 */, + 0, 1, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 141 */, + 2, 3, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 142 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 14, 15, 255, 255, 255, 255, 255, 255 /* 143 */, + 8, 9, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 144 */, + 0, 1, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 145 */, + 2, 3, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 146 */, + 0, 1, 2, 3, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 147 */, + 4, 5, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 148 */, + 0, 1, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 149 */, + 2, 3, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 150 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 151 */, + 6, 7, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 152 */, + 0, 1, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 153 */, + 2, 3, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 154 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 155 */, + 4, 5, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 156 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 157 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 158 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 14, 15, 255, 255, 255, 255 /* 159 */, + 10, 11, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 160 */, + 0, 1, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 161 */, + 2, 3, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 162 */, + 0, 1, 2, 3, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 163 */, + 4, 5, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 164 */, + 0, 1, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 165 */, + 2, 3, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 166 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 167 */, + 6, 7, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 168 */, + 0, 1, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 169 */, + 2, 3, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 170 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 171 */, + 4, 5, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 172 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 173 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 174 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 14, 15, 255, 255, 255, 255 /* 175 */, + 8, 9, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 176 */, + 0, 1, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 177 */, + 2, 3, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 178 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 179 */, + 4, 5, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 180 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 181 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 182 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 183 */, + 6, 7, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 184 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 185 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 186 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 187 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 188 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 189 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 190 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 14, 15, 255, 255 /* 191 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 192 */, + 0, 1, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 193 */, + 2, 3, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 194 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 195 */, + 4, 5, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 196 */, + 0, 1, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 197 */, + 2, 3, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 198 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 199 */, + 6, 7, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 200 */, + 0, 1, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 201 */, + 2, 3, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 202 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 203 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 204 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 205 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 206 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 207 */, + 8, 9, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 208 */, + 0, 1, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 209 */, + 2, 3, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 210 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 211 */, + 4, 5, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 212 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 213 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 214 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 215 */, + 6, 7, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 216 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 217 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 218 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 219 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 220 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 221 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 222 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 14, 15, 255, 255 /* 223 */, + 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 224 */, + 0, 1, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 225 */, + 2, 3, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 226 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 227 */, + 4, 5, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 228 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 229 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 230 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 231 */, + 6, 7, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 232 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 233 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 234 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 235 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 236 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 237 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 238 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 14, 15, 255, 255 /* 239 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 240 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 241 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 242 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 243 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 244 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 245 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 246 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 247 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 248 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 249 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 250 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 251 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 252 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 253 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 254 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 255 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_eta_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/src/rej_uniform_table.c new file mode 100644 index 0000000000..65bc3b78d3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/aarch64/src/rej_uniform_table.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by rejection sampling of the public matrix. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 7 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 11 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 13 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 15 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/api.h new file mode 100644 index 0000000000..0f1fdeb168 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/api.h @@ -0,0 +1,594 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_API_H +#define MLD_NATIVE_API_H +/* + * Native arithmetic interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + * + * To ensure consistency with backends, the header will be + * included automatically after inclusion of the active + * backend, to ensure consistency of function signatures, + * and run sanity checks. + */ + +#include +#include "../cbmc.h" +#include "../common.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* Bound on absolute value of coefficients after NTT. + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) + +/* Absolute exclusive upper bound for the output of the inverse NTT + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_INTT_BOUND MLDSA_Q + +/* Absolute bound for range of mld_reduce32() + * + * NOTE: This is the same bound as in reduce.h and has to be kept + * in sync. */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define REDUCE32_RANGE_MAX 6283009 +/* + * This is the C<->native interface allowing for the drop-in of + * native code for performance critical arithmetic components of ML-DSA. + * + * A _backend_ is a specific implementation of (part of) this interface. + * + * To add a function to a backend, define MLD_USE_NATIVE_XXX and + * implement `static inline xxx(...)` in the profile header. + */ + +/* + * Those functions are meant to be trivial wrappers around the chosen native + * implementation. The are static inline to avoid unnecessary calls. + * The macro before each declaration controls whether a native + * implementation is present. + */ + +#if defined(MLD_USE_NATIVE_NTT) +/************************************************* + * Name: mld_ntt_native + * + * Description: Computes negacyclic number-theoretic transform (NTT) of + * a polynomial in place. + * + * The input polynomial is assumed to be in normal order. + * The output polynomial is in bitreversed order. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_ntt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_NTT */ + + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) +/* + * This must only be set if NTT and INTT have native implementations + * that are adapted to the custom order. + */ +#if !defined(MLD_USE_NATIVE_NTT) || !defined(MLD_USE_NATIVE_INTT) +#error \ + "Invalid native profile: MLD_USE_NATIVE_NTT_CUSTOM_ORDER can only be \ +set if there are native implementations for NTT and INTT." +#endif + +/************************************************* + * Name: mlD_poly_permute_bitrev_to_custom + * + * Description: When MLD_USE_NATIVE_NTT_CUSTOM_ORDER is defined, + * convert a polynomial in NTT domain from bitreversed + * order to the custom order output by the native NTT. + * + * This must only be defined if there is native code for + * both the NTT and INTT. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + * + **************************************************/ +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t p[MLDSA_N]) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q))); +#endif /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + + +#if defined(MLD_USE_NATIVE_INTT) +/************************************************* + * Name: mld_intt_native + * + * Description: Computes inverse of negacyclic number-theoretic transform + *(NTT) of a polynomial in place. + * + * The input polynomial is in bitreversed order. + * The output polynomial is assumed to be in normal order. + * + * Arguments: - uint32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_intt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_INTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_INTT */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) +/************************************************* + * Name: mld_rej_uniform_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [0, MLDSA_Q-1] + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform mod q). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + * lengths. Otherwise, returns non-negative number of sampled 32-bit integers + * (at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= ( 5 * 168) && buflen % 3 == 0) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(r, 0, (unsigned) return_value, 0, MLDSA_Q)) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) +/************************************************* + * Name: mld_rej_uniform_eta2_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-2,+2]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-2, +2]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA2 */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) +/************************************************* + * Name: mld_rej_uniform_eta4_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-4,+4]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-4, +4]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) +/************************************************* + * Name: mld_poly_decompose_32_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/32. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: input/output polynomial. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_32 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) +/************************************************* + * Name: mld_poly_decompose_88_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/88. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: output polynomial with coefficients c0. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CADDQ) +/************************************************* + * Name: mld_poly_caddq_native + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *a: pointer to input/output polynomial + **************************************************/ +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_32) +/************************************************* + * Name: mld_poly_use_hint_32_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/32. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_32 */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) +/************************************************* + * Name: mld_poly_use_hint_88_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/88. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) +/************************************************* + * Name: mld_poly_chknorm_native + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const int32_t *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if the infinity norm is strictly smaller than B, and 1 + * otherwise. B must not be larger than MLDSA_Q - MLD_REDUCE32_RANGE_MAX. + **************************************************/ +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(0 <= B && B <= MLDSA_Q - REDUCE32_RANGE_MAX) + requires(array_bound(a, 0, MLDSA_N, -REDUCE32_RANGE_MAX, REDUCE32_RANGE_MAX)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == 0) == array_abs_bound(a, 0, MLDSA_N, B)) +); +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) +/************************************************* + * Name: mld_polyz_unpack_17_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^17. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_17 */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) +/************************************************* + * Name: mld_polyz_unpack_19_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^19. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_19 */ + +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) +/************************************************* + * Name: mld_poly_pointwise_montgomery_native + * + * Description: Pointwise multiplication of polynomials in NTT domain + * with Montgomery reduction. + * + * Computes c[i] = a[i] * b[i] * R^(-1) mod q for all i, + * where R = 2^32. + * + * Arguments: - int32_t c[MLDSA_N]: output polynomial + * - const int32_t a[MLDSA_N]: first input polynomial + * - const int32_t b[MLDSA_N]: second input polynomial + **************************************************/ +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(c, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(c, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(c, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l4_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 4. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 4 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 4 * MLDSA_N)) + requires(forall(l0, 0, 4, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 4, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l5_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 5. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 5 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 5 * MLDSA_N)) + requires(forall(l0, 0, 5, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 5, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l7_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 7. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 7 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 7 * MLDSA_N)) + requires(forall(l0, 0, 7, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 7, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 */ + +#endif /* !MLD_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/meta.h new file mode 100644 index 0000000000..0b46dd5791 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/meta.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_META_H +#define MLD_NATIVE_META_H + +/* + * Default arithmetic backend + */ +#include "../sys.h" + +#ifdef MLD_SYS_AARCH64 +#include "aarch64/meta.h" +#endif + +#ifdef MLD_SYS_X86_64_AVX2 +#include "x86_64/meta.h" +#endif + +#endif /* !MLD_NATIVE_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/meta.h new file mode 100644 index 0000000000..393374c06f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/meta.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_X86_64_META_H +#define MLD_NATIVE_X86_64_META_H + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_X86_64_DEFAULT + +#define MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +#if !defined(__ASSEMBLER__) +#include +#include "../../common.h" +#include "../api.h" +#include "src/arith_native_x86_64.h" + +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t data[MLDSA_N]) +{ + if (mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + mld_nttunpack_avx2(data); + } +} + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_ntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_invntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)mld_rej_uniform_avx2(r, buf); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_32_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_88_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_caddq_avx2(a); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_32_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_88_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + return mld_poly_chknorm_avx2(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_17_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_19_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_avx2(c, a, b, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l4_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l5_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l7_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_NATIVE_X86_64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h new file mode 100644 index 0000000000..08d5abf74a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/arith_native_x86_64.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#define MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#include "../../../common.h" + +#include +#include "consts.h" + +#define MLD_AVX2_REJ_UNIFORM_BUFLEN \ + (5 * 168) /* REJ_UNIFORM_NBLOCKS * SHAKE128_RATE */ + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) + +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_rej_uniform_table MLD_NAMESPACE(mld_rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[256][8]; + +#define mld_ntt_avx2 MLD_NAMESPACE(ntt_avx2) +void mld_ntt_avx2(int32_t *r, const int32_t *qdata) +/* This must be kept in sync with the HOL-Light specification + * in proofs/hol_light/x86_64/proofs/mldsa_ntt.ml */ +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, MLDSA_N, 8380417)) + requires(qdata == mld_qdata) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + /* check-magic: off */ + ensures(array_abs_bound(r, 0, MLDSA_N, 42035262)) + /* check-magic: on */ +); + +#define mld_invntt_avx2 MLD_NAMESPACE(invntt_avx2) +void mld_invntt_avx2(int32_t *r, const int32_t *mld_qdata); + +#define mld_nttunpack_avx2 MLD_NAMESPACE(nttunpack_avx2) +void mld_nttunpack_avx2(int32_t *r); + +#define mld_rej_uniform_avx2 MLD_NAMESPACE(mld_rej_uniform_avx2) +unsigned mld_rej_uniform_avx2(int32_t *r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]); + +#define mld_rej_uniform_eta2_avx2 MLD_NAMESPACE(mld_rej_uniform_eta2_avx2) +unsigned mld_rej_uniform_eta2_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]); + +#define mld_rej_uniform_eta4_avx2 MLD_NAMESPACE(mld_rej_uniform_eta4_avx2) +unsigned mld_rej_uniform_eta4_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]); + +#define mld_poly_decompose_32_avx2 MLD_NAMESPACE(mld_poly_decompose_32_avx2) +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_avx2 MLD_NAMESPACE(mld_poly_decompose_88_avx2) +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_avx2 MLD_NAMESPACE(poly_caddq_avx2) +void mld_poly_caddq_avx2(int32_t *r); + +#define mld_poly_use_hint_32_avx2 MLD_NAMESPACE(mld_poly_use_hint_32_avx2) +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_avx2 MLD_NAMESPACE(mld_poly_use_hint_88_avx2) +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_avx2 MLD_NAMESPACE(mld_poly_chknorm_avx2) +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_avx2 MLD_NAMESPACE(mld_polyz_unpack_17_avx2) +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a); + +#define mld_polyz_unpack_19_avx2 MLD_NAMESPACE(mld_polyz_unpack_19_avx2) +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a); + +#define mld_pointwise_avx2 MLD_NAMESPACE(pointwise_avx2) +void mld_pointwise_avx2(int32_t *c, const int32_t *a, const int32_t *b, + const int32_t *qdata); + +#define mld_pointwise_acc_l4_avx2 MLD_NAMESPACE(pointwise_acc_l4_avx2) +void mld_pointwise_acc_l4_avx2(int32_t c[MLDSA_N], const int32_t a[4][MLDSA_N], + const int32_t b[4][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l5_avx2 MLD_NAMESPACE(pointwise_acc_l5_avx2) +void mld_pointwise_acc_l5_avx2(int32_t c[MLDSA_N], const int32_t a[5][MLDSA_N], + const int32_t b[5][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l7_avx2 MLD_NAMESPACE(pointwise_acc_l7_avx2) +void mld_pointwise_acc_l7_avx2(int32_t c[MLDSA_N], const int32_t a[7][MLDSA_N], + const int32_t b[7][MLDSA_N], + const int32_t *qdata); + +#endif /* !MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/consts.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/consts.c new file mode 100644 index 0000000000..aaca3535ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/consts.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include "consts.h" + +/* + * Table of zeta values used in the AVX2 forward and inverse NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_qdata[624] = { + 8380417, 8380417, 8380417, 8380417, 8380417, + 8380417, 8380417, 8380417, 58728449, 58728449, + 58728449, 58728449, 58728449, 58728449, 58728449, + 58728449, -8395782, -8395782, -8395782, -8395782, + -8395782, -8395782, -8395782, -8395782, 41978, + 41978, 41978, 41978, 41978, 41978, + 41978, 41978, -151046689, 1830765815, -1929875198, + -1927777021, 1640767044, 1477910808, 1612161320, 1640734244, + 308362795, 308362795, 308362795, 308362795, -1815525077, + -1815525077, -1815525077, -1815525077, -1374673747, -1374673747, + -1374673747, -1374673747, -1091570561, -1091570561, -1091570561, + -1091570561, -1929495947, -1929495947, -1929495947, -1929495947, + 515185417, 515185417, 515185417, 515185417, -285697463, + -285697463, -285697463, -285697463, 625853735, 625853735, + 625853735, 625853735, 1727305304, 1727305304, 2082316400, + 2082316400, -1364982364, -1364982364, 858240904, 858240904, + 1806278032, 1806278032, 222489248, 222489248, -346752664, + -346752664, 684667771, 684667771, 1654287830, 1654287830, + -878576921, -878576921, -1257667337, -1257667337, -748618600, + -748618600, 329347125, 329347125, 1837364258, 1837364258, + -1443016191, -1443016191, -1170414139, -1170414139, -1846138265, + -1631226336, -1404529459, 1838055109, 1594295555, -1076973524, + -1898723372, -594436433, -202001019, -475984260, -561427818, + 1797021249, -1061813248, 2059733581, -1661512036, -1104976547, + -1750224323, -901666090, 418987550, 1831915353, -1925356481, + 992097815, 879957084, 2024403852, 1484874664, -1636082790, + -285388938, -1983539117, -1495136972, -950076368, -1714807468, + -952438995, -1574918427, 1350681039, -2143979939, 1599739335, + -1285853323, -993005454, -1440787840, 568627424, -783134478, + -588790216, 289871779, -1262003603, 2135294594, -1018755525, + -889861155, 1665705315, 1321868265, 1225434135, -1784632064, + 666258756, 675310538, -1555941048, -1999506068, -1499481951, + -695180180, -1375177022, 1777179795, 334803717, -178766299, + -518252220, 1957047970, 1146323031, -654783359, -1974159335, + 1651689966, 140455867, -1039411342, 1955560694, 1529189038, + -2131021878, -247357819, 1518161567, -86965173, 1708872713, + 1787797779, 1638590967, -120646188, -1669960606, -916321552, + 1155548552, 2143745726, 1210558298, -1261461890, -318346816, + 628664287, -1729304568, 1422575624, 1424130038, -1185330464, + 235321234, 168022240, 1206536194, 985155484, -894060583, + -898413, -1363460238, -605900043, 2027833504, 14253662, + 1014493059, 863641633, 1819892093, 2124962073, -1223601433, + -1920467227, -1637785316, -1536588520, 694382729, 235104446, + -1045062172, 831969619, -300448763, 756955444, -260312805, + 1554794072, 1339088280, -2040058690, -853476187, -2047270596, + -1723816713, -1591599803, -440824168, 1119856484, 1544891539, + 155290192, -973777462, 991903578, 912367099, -44694137, + 1176904444, -421552614, -818371958, 1747917558, -325927722, + 908452108, 1851023419, -1176751719, -1354528380, -72690498, + -314284737, 985022747, 963438279, -1078959975, 604552167, + -1021949428, 608791570, 173440395, -2126092136, -1316619236, + -1039370342, 6087993, -110126092, 565464272, -1758099917, + -1600929361, 879867909, -1809756372, 400711272, 1363007700, + 30313375, -326425360, 1683520342, -517299994, 2027935492, + -1372618620, 128353682, -1123881663, 137583815, -635454918, + -642772911, 45766801, 671509323, -2070602178, 419615363, + 1216882040, -270590488, -1276805128, 371462360, -1357098057, + -384158533, 827959816, -596344473, 702390549, -279505433, + -260424530, -71875110, -1208667171, -1499603926, 2036925262, + -540420426, 746144248, -1420958686, 2032221021, 1904936414, + 1257750362, 1926727420, 1931587462, 1258381762, 885133339, + 1629985060, 1967222129, 6363718, -1287922800, 1136965286, + 1779436847, 1116720494, 1042326957, 1405999311, 713994583, + 940195359, -1542497137, 2061661095, -883155599, 1726753853, + -1547952704, 394851342, 283780712, 776003547, 1123958025, + 201262505, 1934038751, 374860238, -3975713, 25847, + -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 1826347, 1826347, 1826347, + 2353451, 2353451, 2353451, 2353451, -359251, + -359251, -359251, -359251, -2091905, -2091905, + -2091905, -2091905, 3119733, 3119733, 3119733, + 3119733, -2884855, -2884855, -2884855, -2884855, + 3111497, 3111497, 3111497, 3111497, 2680103, + 2680103, 2680103, 2680103, 2725464, 2725464, + 1024112, 1024112, -1079900, -1079900, 3585928, + 3585928, -549488, -549488, -1119584, -1119584, + 2619752, 2619752, -2108549, -2108549, -2118186, + -2118186, -3859737, -3859737, -1399561, -1399561, + -3277672, -3277672, 1757237, 1757237, -19422, + -19422, 4010497, 4010497, 280005, 280005, + 2706023, 95776, 3077325, 3530437, -1661693, + -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, + -539299, -1699267, -1643818, 3505694, -3821735, + 3507263, -2140649, -1600420, 3699596, 811944, + 531354, 954230, 3881043, 3900724, -2556880, + 2071892, -2797779, -3930395, -3677745, -1452451, + 2176455, -1257611, -4083598, -3190144, -3632928, + 3412210, 2147896, -2967645, -411027, -671102, + -22981, -381987, 1852771, -3343383, 508951, + 44288, 904516, -3724342, 1653064, 2389356, + 759969, 189548, 3159746, -2409325, 1315589, + 1285669, -812732, -3019102, -3628969, -1528703, + -3041255, 3475950, -1585221, 1939314, -1000202, + -3157330, 126922, -983419, 2715295, -3693493, + -2477047, -1228525, -1308169, 1349076, -1430430, + 264944, 3097992, -1100098, 3958618, -8578, + -3249728, -210977, -1316856, -3553272, -1851402, + -177440, 1341330, -1584928, -1439742, -3881060, + 3839961, 2091667, -3342478, 266997, -3520352, + 900702, 495491, -655327, -3556995, 342297, + 3437287, 2842341, 4055324, -3767016, -2994039, + -1333058, -451100, -1279661, 1500165, -542412, + -2584293, -2013608, 1957272, -3183426, 810149, + -3038916, 2213111, -426683, -1667432, -2939036, + 183443, -554416, 3937738, 3407706, 2244091, + 2434439, -3759364, 1859098, -1613174, -3122442, + -525098, 286988, -3342277, 2691481, 1247620, + 1250494, 1869119, 1237275, 1312455, 1917081, + 777191, -2831860, -3724270, 2432395, 3369112, + 162844, 1652634, 3523897, -975884, 1723600, + -1104333, -2235985, -976891, 3919660, 1400424, + 2316500, -2446433, -1235728, -1197226, 909542, + -43260, 2031748, -768622, -2437823, 1735879, + -2590150, 2486353, 2635921, 1903435, -3318210, + 3306115, -2546312, 2235880, -1671176, 594136, + 2454455, 185531, 1616392, -3694233, 3866901, + 1717735, -1803090, -260646, -420899, 1612842, + -48306, -846154, 3817976, -3562462, 3513181, + -3193378, 819034, -522500, 3207046, -3595838, + 4108315, 203044, 1265009, 1595974, -3548272, + -1050970, -1430225, -1962642, -1374803, 3406031, + -1846953, -3776993, -164721, -1207385, 3014001, + -1799107, 269760, 472078, 1910376, -3833893, + -2286327, -3545687, -1362209, 1976782, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_consts) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/consts.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/consts.h new file mode 100644 index 0000000000..7fe08f454b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/consts.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#ifndef MLD_NATIVE_X86_64_SRC_CONSTS_H +#define MLD_NATIVE_X86_64_SRC_CONSTS_H +#include "../../../common.h" +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQ 0 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV 8 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV 16 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV 24 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV 32 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS 328 + +#ifndef __ASSEMBLER__ +#define mld_qdata MLD_NAMESPACE(qdata) +extern const int32_t mld_qdata[624]; +#endif + +#endif /* !MLD_NATIVE_X86_64_SRC_CONSTS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c new file mode 100644 index 0000000000..05d86d14fc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_caddq_avx2.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/************************************************* + * Name: mld_poly_caddq_avx2 + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *r: pointer to input/output polynomial + **************************************************/ +void mld_poly_caddq_avx2(int32_t *r) +{ + unsigned int i; + __m256i f, g; + const __m256i q = _mm256_set1_epi32(MLDSA_Q); + const __m256i zero = _mm256_setzero_si256(); + __m256i *rr = (__m256i *)r; + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256(&rr[i]); + g = _mm256_cmpgt_epi32(zero, f); + g = _mm256_and_si256(g, q); + f = _mm256_add_epi32(f, g); + _mm256_store_si256(&rr[i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_reduce) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c new file mode 100644 index 0000000000..50e2c7fa9b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_chknorm_avx2.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B) +{ + unsigned int i; + __m256i f, t; + const __m256i bound = _mm256_set1_epi32(B - 1); + + t = _mm256_setzero_si256(); + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + f = _mm256_abs_epi32(f); + f = _mm256_cmpgt_epi32(f, bound); + t = _mm256_or_si256(t, f); + } + + return 1 - _mm256_testz_si256(t, t); +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_chknorm) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c new file mode 100644 index 0000000000..76846bf1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_decompose_32_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(31 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 4092 == intdiv(2 * intdiv(MLDSA_Q - 1, 32), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 4092. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 32*GAMMA2 = 16*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 16B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + * + * round(f1' * 1025 / 2^22) is in turn computed in 2 steps as + * round(floor(f1' * 1025 / 2^16) / 2^6). The mulhi computes f1'' = + * floor(f1' * 1025 / 2^16). As for the next step f1 = round(f1'' / 2^6), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^9) = round(f1'' * 2^9 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 1025 / 2^16) = 1025 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(16B / B) = 16 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 16, i.e. f > 31*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 31*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 15, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c new file mode 100644 index 0000000000..463506b962 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_decompose_88_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ + +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 1488 == intdiv(2 * intdiv(MLDSA_Q - 1, 88), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 1488. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 88*GAMMA2 = 44*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 44B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + * + * round(f1' * 11275 / 2^24) is in turn computed in 2 steps as + * round(floor(f1' * 11275 / 2^16) / 2^8). The mulhi computes f1'' = + * floor(f1' * 11275 / 2^16). As for the next step f1 = round(f1'' / 2^8), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^7) = round(f1'' * 2^7 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 11275 / 2^16) = 11275 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(44B / B) = 44 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 44, i.e. f > 87*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 87*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 43, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c new file mode 100644 index 0000000000..0094bc93a9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_use_hint_32_avx2.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + const __m256i mask = _mm256_set1_epi32(15); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_32_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 16 */ + f1 = _mm256_add_epi32(f1, h); + f1 = _mm256_and_si256(f1, mask); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c new file mode 100644 index 0000000000..b109ab6351 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/poly_use_hint_88_avx2.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + const __m256i max = _mm256_set1_epi32(43); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_88_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 44 */ + f1 = _mm256_add_epi32(f1, h); + f1 = MLD_MM256_BLENDV_EPI32(f1, max, f1); + f = _mm256_cmpgt_epi32(f1, max); + f1 = MLD_MM256_BLENDV_EPI32(f1, zero, f); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c new file mode 100644 index 0000000000..f6c08a832f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/polyz_unpack_17_avx2.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 27, 26, 25, -1, 25, 24, 23, -1, 8, 7, + 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0); + const __m256i srlvdidx = _mm256_set_epi32(6, 4, 2, 0, 6, 4, 2, 0); + const __m256i mask = _mm256_set1_epi32(0x3FFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 17)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[18 * i]); + /* Load bytes 2..17 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[18 * i + 2]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-8 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 8, 7, 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte8, byte7, byte6, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,27, 26, 25, -1,25, 24, 23] │ + * │ Result: [0, byte17, byte16, byte15, ..., 0, byte11, byte10, byte9] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 18 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 32..55 48..71 + * 72..95 88..111 104..127 120..143 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 18..39 36..55 54..71 + * 72..95 90..111 108..127 126..143 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..17 18..35 36..53 54..71 + * 72..89 90..107 108..125 126..143 */ + + /* Map [0, 1, ..., 2^18-1] to [2^17, 2^17-1, ..., -2^17+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_17) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c new file mode 100644 index 0000000000..4a5ce48f38 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/polyz_unpack_19_avx2.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 26, 25, 24, -1, 24, 23, 22, -1, 9, 8, + 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0); + /* Equivalent to _mm256_set_epi32(4, 0, 4, 0, 4, 0, 4, 0) */ + const __m256i srlvdidx = _mm256_set1_epi64x((uint64_t)4 << 32); + const __m256i mask = _mm256_set1_epi32(0xFFFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 19)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[20 * i]); + /* Load bytes 4..19 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[20 * i + 4]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-9 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 9, 8, 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte9, byte8, byte7, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,26, 25, 24, -1,24, 23, 22] │ + * │ Result: [0, byte19, byte18, byte17, ..., 0, byte12, byte11, byte10] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 20 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 40..63 56..79 + * 80..103 96..119 120..143 136..159 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 20..39 40..63 60..79 + * 80..103 100..119 120..143 140..159 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..19 20..39 40..59 60..79 + * 80..99 100..119 120..139 140..159 */ + + /* Map [0, 1, ..., 2^20-1] to [2^19, 2^19-1, ..., -2^19+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_19) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c new file mode 100644 index 0000000000..07a5df9706 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_avx2.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The pqcrystals implementation assumes a buffer that is 8 bytes + *. larger as the first loop overreads by 8 bytes that are then + * discarded. We instead do not pad the buffer and do not overread. + * The performance impact is negligible and it does not force the + * frontend to perform the unintuitive padding. + */ + +unsigned int mld_rej_uniform_avx2( + int32_t *MLD_RESTRICT r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i d, tmp; + const __m256i bound = _mm256_set1_epi32(MLDSA_Q); + const __m256i mask = _mm256_set1_epi32(0x7FFFFF); + const __m256i idx8 = + _mm256_set_epi8(-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4, + -1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 32) + { + d = _mm256_loadu_si256((__m256i *)&buf[pos]); + + /* Permute 64-bit lanes + * 0x94 = 10010100b rearranges 64-bit lanes as: [3,2,1,0] -> [2,1,1,0] + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Original Layout ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ bytes 16..23 │ bytes 24..31 │ + * └─────────────────┴─────────────────┴─────────────────┴─────────────────┘ + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Layout after permute ║ + * ║ Byte indices in high half shifted down by 8 positions ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌───────────────┬─────────────────┐ ┌─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ │ bytes 8..15 │ bytes 16..23 │ + * └───────────────┴─────────────────┘ └─────────────────┴─────────────────┘ + * Lower 128-bit lane (bytes 0-15) Upper 128-bit lane (bytes 16-31) + */ + d = _mm256_permute4x64_epi64(d, 0x94); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-11 into low 128-bit half of permuted vector────────────────┐ + * │ Shuffle: [-1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0] │ + * │ Result: [0, byte11, byte10, byte9, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 4-15 into high 128-bit half of permuted vector ──────────────┐ + * │ Shuffle: [-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4] │ + * │ Result: [0, byte23, byte22, byte21, ..., 0, byte14, byte13, byte12 │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + d = _mm256_shuffle_epi8(d, idx8); + d = _mm256_and_si256(d, mask); + pos += 24; + + tmp = _mm256_sub_epi32(d, bound); + good = (uint32_t)_mm256_movemask_ps((__m256)tmp); + tmp = _mm256_cvtepu8_epi32( + _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good])); + d = _mm256_permutevar8x32_epi32(d, tmp); + + _mm256_storeu_si256((__m256i *)&r[ctr], d); + ctr += (unsigned)_mm_popcnt_u32(good); + } + + while (ctr < MLDSA_N && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 3) + { + uint32_t t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + /* Safe because t < MLDSA_Q. */ + r[ctr++] = (int32_t)t; + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c new file mode 100644 index 0000000000..70c5c42c70 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta2_avx2.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA2 2 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ +unsigned int mld_rej_uniform_eta2_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1, f2; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA2); + const __m256i bound = mask; + /* check-magic: -6560 == 32*round(-2**10 / 5) */ + const __m256i v = _mm256_set1_epi32(-6560); + const __m256i p = _mm256_set1_epi32(5); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 15) + { + t0 = t0 - (205 * t0 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t0); + } + if (t1 < 15 && ctr < MLDSA_N) + { + t1 = t1 - (205 * t1 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta2) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA2 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c new file mode 100644 index 0000000000..ba00e91252 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_eta4_avx2.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA4 4 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ + +unsigned int mld_rej_uniform_eta4_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA4); + const __m256i bound = _mm256_set1_epi8(9); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 9) + { + r[ctr++] = (int32_t)(4 - t0); + } + if (t1 < 9 && ctr < MLDSA_N) + { + r[ctr++] = (int32_t)(4 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta4) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA4 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_table.c new file mode 100644 index 0000000000..6c537b4542 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/native/x86_64/src/rej_uniform_table.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" + +/* + * Lookup table used by rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[256][8] = { + {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, + {2, 0, 0, 0, 0, 0, 0, 0}, {0, 2, 0, 0, 0, 0, 0, 0}, + {1, 2, 0, 0, 0, 0, 0, 0}, {0, 1, 2, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 0, 0}, {0, 3, 0, 0, 0, 0, 0, 0}, + {1, 3, 0, 0, 0, 0, 0, 0}, {0, 1, 3, 0, 0, 0, 0, 0}, + {2, 3, 0, 0, 0, 0, 0, 0}, {0, 2, 3, 0, 0, 0, 0, 0}, + {1, 2, 3, 0, 0, 0, 0, 0}, {0, 1, 2, 3, 0, 0, 0, 0}, + {4, 0, 0, 0, 0, 0, 0, 0}, {0, 4, 0, 0, 0, 0, 0, 0}, + {1, 4, 0, 0, 0, 0, 0, 0}, {0, 1, 4, 0, 0, 0, 0, 0}, + {2, 4, 0, 0, 0, 0, 0, 0}, {0, 2, 4, 0, 0, 0, 0, 0}, + {1, 2, 4, 0, 0, 0, 0, 0}, {0, 1, 2, 4, 0, 0, 0, 0}, + {3, 4, 0, 0, 0, 0, 0, 0}, {0, 3, 4, 0, 0, 0, 0, 0}, + {1, 3, 4, 0, 0, 0, 0, 0}, {0, 1, 3, 4, 0, 0, 0, 0}, + {2, 3, 4, 0, 0, 0, 0, 0}, {0, 2, 3, 4, 0, 0, 0, 0}, + {1, 2, 3, 4, 0, 0, 0, 0}, {0, 1, 2, 3, 4, 0, 0, 0}, + {5, 0, 0, 0, 0, 0, 0, 0}, {0, 5, 0, 0, 0, 0, 0, 0}, + {1, 5, 0, 0, 0, 0, 0, 0}, {0, 1, 5, 0, 0, 0, 0, 0}, + {2, 5, 0, 0, 0, 0, 0, 0}, {0, 2, 5, 0, 0, 0, 0, 0}, + {1, 2, 5, 0, 0, 0, 0, 0}, {0, 1, 2, 5, 0, 0, 0, 0}, + {3, 5, 0, 0, 0, 0, 0, 0}, {0, 3, 5, 0, 0, 0, 0, 0}, + {1, 3, 5, 0, 0, 0, 0, 0}, {0, 1, 3, 5, 0, 0, 0, 0}, + {2, 3, 5, 0, 0, 0, 0, 0}, {0, 2, 3, 5, 0, 0, 0, 0}, + {1, 2, 3, 5, 0, 0, 0, 0}, {0, 1, 2, 3, 5, 0, 0, 0}, + {4, 5, 0, 0, 0, 0, 0, 0}, {0, 4, 5, 0, 0, 0, 0, 0}, + {1, 4, 5, 0, 0, 0, 0, 0}, {0, 1, 4, 5, 0, 0, 0, 0}, + {2, 4, 5, 0, 0, 0, 0, 0}, {0, 2, 4, 5, 0, 0, 0, 0}, + {1, 2, 4, 5, 0, 0, 0, 0}, {0, 1, 2, 4, 5, 0, 0, 0}, + {3, 4, 5, 0, 0, 0, 0, 0}, {0, 3, 4, 5, 0, 0, 0, 0}, + {1, 3, 4, 5, 0, 0, 0, 0}, {0, 1, 3, 4, 5, 0, 0, 0}, + {2, 3, 4, 5, 0, 0, 0, 0}, {0, 2, 3, 4, 5, 0, 0, 0}, + {1, 2, 3, 4, 5, 0, 0, 0}, {0, 1, 2, 3, 4, 5, 0, 0}, + {6, 0, 0, 0, 0, 0, 0, 0}, {0, 6, 0, 0, 0, 0, 0, 0}, + {1, 6, 0, 0, 0, 0, 0, 0}, {0, 1, 6, 0, 0, 0, 0, 0}, + {2, 6, 0, 0, 0, 0, 0, 0}, {0, 2, 6, 0, 0, 0, 0, 0}, + {1, 2, 6, 0, 0, 0, 0, 0}, {0, 1, 2, 6, 0, 0, 0, 0}, + {3, 6, 0, 0, 0, 0, 0, 0}, {0, 3, 6, 0, 0, 0, 0, 0}, + {1, 3, 6, 0, 0, 0, 0, 0}, {0, 1, 3, 6, 0, 0, 0, 0}, + {2, 3, 6, 0, 0, 0, 0, 0}, {0, 2, 3, 6, 0, 0, 0, 0}, + {1, 2, 3, 6, 0, 0, 0, 0}, {0, 1, 2, 3, 6, 0, 0, 0}, + {4, 6, 0, 0, 0, 0, 0, 0}, {0, 4, 6, 0, 0, 0, 0, 0}, + {1, 4, 6, 0, 0, 0, 0, 0}, {0, 1, 4, 6, 0, 0, 0, 0}, + {2, 4, 6, 0, 0, 0, 0, 0}, {0, 2, 4, 6, 0, 0, 0, 0}, + {1, 2, 4, 6, 0, 0, 0, 0}, {0, 1, 2, 4, 6, 0, 0, 0}, + {3, 4, 6, 0, 0, 0, 0, 0}, {0, 3, 4, 6, 0, 0, 0, 0}, + {1, 3, 4, 6, 0, 0, 0, 0}, {0, 1, 3, 4, 6, 0, 0, 0}, + {2, 3, 4, 6, 0, 0, 0, 0}, {0, 2, 3, 4, 6, 0, 0, 0}, + {1, 2, 3, 4, 6, 0, 0, 0}, {0, 1, 2, 3, 4, 6, 0, 0}, + {5, 6, 0, 0, 0, 0, 0, 0}, {0, 5, 6, 0, 0, 0, 0, 0}, + {1, 5, 6, 0, 0, 0, 0, 0}, {0, 1, 5, 6, 0, 0, 0, 0}, + {2, 5, 6, 0, 0, 0, 0, 0}, {0, 2, 5, 6, 0, 0, 0, 0}, + {1, 2, 5, 6, 0, 0, 0, 0}, {0, 1, 2, 5, 6, 0, 0, 0}, + {3, 5, 6, 0, 0, 0, 0, 0}, {0, 3, 5, 6, 0, 0, 0, 0}, + {1, 3, 5, 6, 0, 0, 0, 0}, {0, 1, 3, 5, 6, 0, 0, 0}, + {2, 3, 5, 6, 0, 0, 0, 0}, {0, 2, 3, 5, 6, 0, 0, 0}, + {1, 2, 3, 5, 6, 0, 0, 0}, {0, 1, 2, 3, 5, 6, 0, 0}, + {4, 5, 6, 0, 0, 0, 0, 0}, {0, 4, 5, 6, 0, 0, 0, 0}, + {1, 4, 5, 6, 0, 0, 0, 0}, {0, 1, 4, 5, 6, 0, 0, 0}, + {2, 4, 5, 6, 0, 0, 0, 0}, {0, 2, 4, 5, 6, 0, 0, 0}, + {1, 2, 4, 5, 6, 0, 0, 0}, {0, 1, 2, 4, 5, 6, 0, 0}, + {3, 4, 5, 6, 0, 0, 0, 0}, {0, 3, 4, 5, 6, 0, 0, 0}, + {1, 3, 4, 5, 6, 0, 0, 0}, {0, 1, 3, 4, 5, 6, 0, 0}, + {2, 3, 4, 5, 6, 0, 0, 0}, {0, 2, 3, 4, 5, 6, 0, 0}, + {1, 2, 3, 4, 5, 6, 0, 0}, {0, 1, 2, 3, 4, 5, 6, 0}, + {7, 0, 0, 0, 0, 0, 0, 0}, {0, 7, 0, 0, 0, 0, 0, 0}, + {1, 7, 0, 0, 0, 0, 0, 0}, {0, 1, 7, 0, 0, 0, 0, 0}, + {2, 7, 0, 0, 0, 0, 0, 0}, {0, 2, 7, 0, 0, 0, 0, 0}, + {1, 2, 7, 0, 0, 0, 0, 0}, {0, 1, 2, 7, 0, 0, 0, 0}, + {3, 7, 0, 0, 0, 0, 0, 0}, {0, 3, 7, 0, 0, 0, 0, 0}, + {1, 3, 7, 0, 0, 0, 0, 0}, {0, 1, 3, 7, 0, 0, 0, 0}, + {2, 3, 7, 0, 0, 0, 0, 0}, {0, 2, 3, 7, 0, 0, 0, 0}, + {1, 2, 3, 7, 0, 0, 0, 0}, {0, 1, 2, 3, 7, 0, 0, 0}, + {4, 7, 0, 0, 0, 0, 0, 0}, {0, 4, 7, 0, 0, 0, 0, 0}, + {1, 4, 7, 0, 0, 0, 0, 0}, {0, 1, 4, 7, 0, 0, 0, 0}, + {2, 4, 7, 0, 0, 0, 0, 0}, {0, 2, 4, 7, 0, 0, 0, 0}, + {1, 2, 4, 7, 0, 0, 0, 0}, {0, 1, 2, 4, 7, 0, 0, 0}, + {3, 4, 7, 0, 0, 0, 0, 0}, {0, 3, 4, 7, 0, 0, 0, 0}, + {1, 3, 4, 7, 0, 0, 0, 0}, {0, 1, 3, 4, 7, 0, 0, 0}, + {2, 3, 4, 7, 0, 0, 0, 0}, {0, 2, 3, 4, 7, 0, 0, 0}, + {1, 2, 3, 4, 7, 0, 0, 0}, {0, 1, 2, 3, 4, 7, 0, 0}, + {5, 7, 0, 0, 0, 0, 0, 0}, {0, 5, 7, 0, 0, 0, 0, 0}, + {1, 5, 7, 0, 0, 0, 0, 0}, {0, 1, 5, 7, 0, 0, 0, 0}, + {2, 5, 7, 0, 0, 0, 0, 0}, {0, 2, 5, 7, 0, 0, 0, 0}, + {1, 2, 5, 7, 0, 0, 0, 0}, {0, 1, 2, 5, 7, 0, 0, 0}, + {3, 5, 7, 0, 0, 0, 0, 0}, {0, 3, 5, 7, 0, 0, 0, 0}, + {1, 3, 5, 7, 0, 0, 0, 0}, {0, 1, 3, 5, 7, 0, 0, 0}, + {2, 3, 5, 7, 0, 0, 0, 0}, {0, 2, 3, 5, 7, 0, 0, 0}, + {1, 2, 3, 5, 7, 0, 0, 0}, {0, 1, 2, 3, 5, 7, 0, 0}, + {4, 5, 7, 0, 0, 0, 0, 0}, {0, 4, 5, 7, 0, 0, 0, 0}, + {1, 4, 5, 7, 0, 0, 0, 0}, {0, 1, 4, 5, 7, 0, 0, 0}, + {2, 4, 5, 7, 0, 0, 0, 0}, {0, 2, 4, 5, 7, 0, 0, 0}, + {1, 2, 4, 5, 7, 0, 0, 0}, {0, 1, 2, 4, 5, 7, 0, 0}, + {3, 4, 5, 7, 0, 0, 0, 0}, {0, 3, 4, 5, 7, 0, 0, 0}, + {1, 3, 4, 5, 7, 0, 0, 0}, {0, 1, 3, 4, 5, 7, 0, 0}, + {2, 3, 4, 5, 7, 0, 0, 0}, {0, 2, 3, 4, 5, 7, 0, 0}, + {1, 2, 3, 4, 5, 7, 0, 0}, {0, 1, 2, 3, 4, 5, 7, 0}, + {6, 7, 0, 0, 0, 0, 0, 0}, {0, 6, 7, 0, 0, 0, 0, 0}, + {1, 6, 7, 0, 0, 0, 0, 0}, {0, 1, 6, 7, 0, 0, 0, 0}, + {2, 6, 7, 0, 0, 0, 0, 0}, {0, 2, 6, 7, 0, 0, 0, 0}, + {1, 2, 6, 7, 0, 0, 0, 0}, {0, 1, 2, 6, 7, 0, 0, 0}, + {3, 6, 7, 0, 0, 0, 0, 0}, {0, 3, 6, 7, 0, 0, 0, 0}, + {1, 3, 6, 7, 0, 0, 0, 0}, {0, 1, 3, 6, 7, 0, 0, 0}, + {2, 3, 6, 7, 0, 0, 0, 0}, {0, 2, 3, 6, 7, 0, 0, 0}, + {1, 2, 3, 6, 7, 0, 0, 0}, {0, 1, 2, 3, 6, 7, 0, 0}, + {4, 6, 7, 0, 0, 0, 0, 0}, {0, 4, 6, 7, 0, 0, 0, 0}, + {1, 4, 6, 7, 0, 0, 0, 0}, {0, 1, 4, 6, 7, 0, 0, 0}, + {2, 4, 6, 7, 0, 0, 0, 0}, {0, 2, 4, 6, 7, 0, 0, 0}, + {1, 2, 4, 6, 7, 0, 0, 0}, {0, 1, 2, 4, 6, 7, 0, 0}, + {3, 4, 6, 7, 0, 0, 0, 0}, {0, 3, 4, 6, 7, 0, 0, 0}, + {1, 3, 4, 6, 7, 0, 0, 0}, {0, 1, 3, 4, 6, 7, 0, 0}, + {2, 3, 4, 6, 7, 0, 0, 0}, {0, 2, 3, 4, 6, 7, 0, 0}, + {1, 2, 3, 4, 6, 7, 0, 0}, {0, 1, 2, 3, 4, 6, 7, 0}, + {5, 6, 7, 0, 0, 0, 0, 0}, {0, 5, 6, 7, 0, 0, 0, 0}, + {1, 5, 6, 7, 0, 0, 0, 0}, {0, 1, 5, 6, 7, 0, 0, 0}, + {2, 5, 6, 7, 0, 0, 0, 0}, {0, 2, 5, 6, 7, 0, 0, 0}, + {1, 2, 5, 6, 7, 0, 0, 0}, {0, 1, 2, 5, 6, 7, 0, 0}, + {3, 5, 6, 7, 0, 0, 0, 0}, {0, 3, 5, 6, 7, 0, 0, 0}, + {1, 3, 5, 6, 7, 0, 0, 0}, {0, 1, 3, 5, 6, 7, 0, 0}, + {2, 3, 5, 6, 7, 0, 0, 0}, {0, 2, 3, 5, 6, 7, 0, 0}, + {1, 2, 3, 5, 6, 7, 0, 0}, {0, 1, 2, 3, 5, 6, 7, 0}, + {4, 5, 6, 7, 0, 0, 0, 0}, {0, 4, 5, 6, 7, 0, 0, 0}, + {1, 4, 5, 6, 7, 0, 0, 0}, {0, 1, 4, 5, 6, 7, 0, 0}, + {2, 4, 5, 6, 7, 0, 0, 0}, {0, 2, 4, 5, 6, 7, 0, 0}, + {1, 2, 4, 5, 6, 7, 0, 0}, {0, 1, 2, 4, 5, 6, 7, 0}, + {3, 4, 5, 6, 7, 0, 0, 0}, {0, 3, 4, 5, 6, 7, 0, 0}, + {1, 3, 4, 5, 6, 7, 0, 0}, {0, 1, 3, 4, 5, 6, 7, 0}, + {2, 3, 4, 5, 6, 7, 0, 0}, {0, 2, 3, 4, 5, 6, 7, 0}, + {1, 2, 3, 4, 5, 6, 7, 0}, {0, 1, 2, 3, 4, 5, 6, 7}, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/packing.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/packing.c new file mode 100644 index 0000000000..26da273856 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/packing.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include + +#include "common.h" +#include "packing.h" +#include "poly.h" +#include "polyvec.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_unpack_hints MLD_ADD_PARAM_SET(mld_unpack_hints) +/* End of parameter set namespacing */ + +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +{ + unsigned int i; + + mld_memcpy(pk, rho, MLDSA_SEEDBYTES); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt1_pack(pk + MLDSA_SEEDBYTES + i * MLDSA_POLYT1_PACKEDBYTES, + &t1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +{ + unsigned int i; + + mld_memcpy(rho, pk, MLDSA_SEEDBYTES); + pk += MLDSA_SEEDBYTES; + + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt1_unpack(&t1->vec[i], pk + i * MLDSA_POLYT1_PACKEDBYTES); + } +} + +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +{ + mld_memcpy(sk, rho, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, key, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, tr, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_pack_eta(sk, s1); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_eta(sk, s2); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_t0(sk, t0); +} + +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +{ + mld_memcpy(rho, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(key, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(tr, sk, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_unpack_eta(s1, sk); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_eta(s2, sk); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_t0(t0, sk); +} + +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +{ + unsigned int i, j, k; + + mld_memcpy(sig, c, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + /* skip z component - packed via mld_pack_sig_z */ + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + /* Encode hints h */ + + /* The final section of sig[] is MLDSA_POLYVECH_PACKEDBYTES long, where + * MLDSA_POLYVECH_PACKEDBYTES = MLDSA_OMEGA + MLDSA_K + * + * The first OMEGA bytes record the index numbers of the coefficients + * that are not equal to 0 + * + * The final K bytes record a running tally of the number of hints + * coming from each of the K polynomials in h. + * + * The pre-condition tells us that number_of_hints <= OMEGA, so some + * bytes may not be written, so we initialize all of them to zero + * to start. + */ + mld_memset(sig, 0, MLDSA_POLYVECH_PACKEDBYTES); + + k = 0; + /* For each polynomial in h... */ + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* For each coefficient in that polynomial, record it as as hint */ + /* if its value is not zero */ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + assigns(j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(j <= MLDSA_N) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* The reference implementation implicitly relies on the total */ + /* number of hints being less than OMEGA, assuming h is valid. */ + /* In mldsa-native, we check this explicitly to ease proof of */ + /* type safety. */ + if (h->vec[i].coeffs[j] != 0 && k < number_of_hints) + { + /* The enclosing if condition AND the loop invariant infer */ + /* that k < MLDSA_OMEGA, so writing to sig[k] is safe and k */ + /* can be incremented. */ + sig[k++] = (uint8_t)j; + } + } + /* Having recorded all the hints for this polynomial, also */ + /* record the running tally into the correct "slot" for that */ + /* coefficient in the final K bytes */ + sig[MLDSA_OMEGA + i] = (uint8_t)k; + } +} + +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +{ + sig += MLDSA_CTILDEBYTES; + sig += i * MLDSA_POLYZ_PACKEDBYTES; + mld_polyz_pack(sig, zi); +} + +/************************************************* + * Name: mld_unpack_hints + * + * Description: Unpack raw hint bytes into a polyveck + * struct + * + * Arguments: - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]: + * raw hint bytes + * + * Returns 1 in case of malformed hints; otherwise 0. + **************************************************/ +static int mld_unpack_hints( + mld_polyveck *h, const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(packed_hints, MLDSA_POLYVECH_PACKEDBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + /* All returned coefficients are either 0 or 1 */ + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +) +{ + unsigned int i, j; + unsigned int old_hint_count; + + /* Set all coefficients of all polynomials to 0. */ + /* Only those that are actually non-zero hints will */ + /* be overwritten below. */ + mld_memset(h, 0, sizeof(mld_polyveck)); + + old_hint_count = 0; + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + /* Grab the hint count for the i'th polynomial */ + const unsigned int new_hint_count = packed_hints[MLDSA_OMEGA + i]; + + /* new_hint_count must increase or stay the same, but also remain */ + /* less than or equal to MLDSA_OMEGA */ + if (new_hint_count < old_hint_count || new_hint_count > MLDSA_OMEGA) + { + /* Error - new_hint_count is invalid */ + return 1; + } + + /* If new_hint_count == old_hint_count, then this polynomial has */ + /* zero hints, so this loop executes zero times and we move */ + /* straight on to the next polynomial. */ + for (j = old_hint_count; j < new_hint_count; ++j) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + const uint8_t this_hint_index = packed_hints[j]; + + /* Coefficients must be ordered for strong unforgeability */ + if (j > old_hint_count && this_hint_index <= packed_hints[j - 1]) + { + return 1; + } + h->vec[i].coeffs[this_hint_index] = 1; + } + + old_hint_count = new_hint_count; + } + + /* Extra indices must be zero for strong unforgeability */ + for (j = old_hint_count; j < MLDSA_OMEGA; ++j) + __loop__( + invariant(j <= MLDSA_OMEGA) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + if (packed_hints[j] != 0) + { + return 1; + } + } + + return 0; +} + +MLD_INTERNAL_API +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +{ + mld_memcpy(c, sig, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + mld_polyvecl_unpack_z(z, sig); + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + return mld_unpack_hints(h, sig); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_unpack_hints diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/packing.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/packing.h new file mode 100644 index 0000000000..19095d08cd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/packing.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PACKING_H +#define MLD_PACKING_H + +#include +#include "polyvec.h" + +#define mld_pack_pk MLD_NAMESPACE_KL(pack_pk) +/************************************************* + * Name: mld_pack_pk + * + * Description: Bit-pack public key pk = (rho, t1). + * + * Arguments: - uint8_t pk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const mld_polyveck *t1: pointer to vector t1 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) +); + + +#define mld_pack_sk MLD_NAMESPACE_KL(pack_sk) +/************************************************* + * Name: mld_pack_sk + * + * Description: Bit-pack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - uint8_t sk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const uint8_t tr[]: byte array containing tr + * - const uint8_t key[]: byte array containing key + * - const mld_polyveck *t0: pointer to vector t0 + * - const mld_polyvecl *s1: pointer to vector s1 + * - const mld_polyveck *s2: pointer to vector s2 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +__contract__( + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + requires(forall(k2, 0, MLDSA_K, + array_abs_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) +); + + +#define mld_pack_sig_c_h MLD_NAMESPACE_KL(pack_sig_c_h) +/************************************************* + * Name: mld_pack_sig_c_h + * + * Description: Bit-pack c and h component of sig = (c, z, h). + * The z component is packed separately using mld_pack_sig_z. + * + * Arguments: - uint8_t sig[]: output byte array + * - const uint8_t *c: pointer to challenge hash length + * MLDSA_SEEDBYTES + * - const mld_polyveck *h: pointer to hint vector h + * - const unsigned int number_of_hints: total + * hints in *h + * + * Note that the number_of_hints argument is not present + * in the reference implementation. It is added here to ease + * proof of type safety. + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + requires(number_of_hints <= MLDSA_OMEGA) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_pack_sig_z MLD_NAMESPACE_KL(pack_sig_z) +/************************************************* + * Name: mld_pack_sig_z + * + * Description: Bit-pack single polynomial of z component of sig = (c, z, h). + * The c and h components are packed separately using + * mld_pack_sig_c_h. + * + * Arguments: - uint8_t sig[]: output byte array + * - const mld_poly *zi: pointer to a single polynomial in z + * - const unsigned int i: index of zi in vector z + * + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(zi, sizeof(mld_poly))) + requires(i < MLDSA_L) + requires(array_bound(zi->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_unpack_pk MLD_NAMESPACE_KL(unpack_pk) +/************************************************* + * Name: mld_unpack_pk + * + * Description: Unpack public key pk = (rho, t1). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const mld_polyveck *t1: pointer to output vector t1 + * - uint8_t pk[]: byte array containing bit-packed pk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) +); + + +#define mld_unpack_sk MLD_NAMESPACE_KL(unpack_sk) +/************************************************* + * Name: mld_unpack_sk + * + * Description: Unpack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const uint8_t tr[]: output byte array for tr + * - const uint8_t key[]: output byte array for key + * - const mld_polyveck *t0: pointer to output vector t0 + * - const mld_polyvecl *s1: pointer to output vector s1 + * - const mld_polyveck *s2: pointer to output vector s2 + * - uint8_t sk[]: byte array containing bit-packed sk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +__contract__( + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(key, MLDSA_SEEDBYTES)) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(s1, sizeof(mld_polyvecl))) + assigns(memory_slice(s2, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_unpack_sig MLD_NAMESPACE_KL(unpack_sig) +/************************************************* + * Name: mld_unpack_sig + * + * Description: Unpack signature sig = (c, z, h). + * + * Arguments: - uint8_t *c: pointer to output challenge hash + * - mld_polyvecl *z: pointer to output vector z + * - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t sig[]: byte array containing + * bit-packed signature + * + * Returns 1 in case of malformed signature; otherwise 0. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(c, MLDSA_CTILDEBYTES)) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(z->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +); +#endif /* !MLD_PACKING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/params.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/params.h new file mode 100644 index 0000000000..c67d2a33fb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/params.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PARAMS_H +#define MLD_PARAMS_H + +#define MLDSA_SEEDBYTES 32 +#define MLDSA_CRHBYTES 64 +#define MLDSA_TRBYTES 64 +#define MLDSA_RNDBYTES 32 +#define MLDSA_N 256 +#define MLDSA_Q 8380417 +#define MLDSA_Q_HALF ((MLDSA_Q + 1) / 2) +#define MLDSA_D 13 + +#if MLD_CONFIG_PARAMETER_SET == 44 + +#define MLDSA_K 4 +#define MLDSA_L 4 +#define MLDSA_ETA 2 +#define MLDSA_TAU 39 +#define MLDSA_BETA 78 +#define MLDSA_GAMMA1 (1 << 17) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 88) +#define MLDSA_OMEGA 80 +#define MLDSA_CTILDEBYTES 32 +#define MLDSA_POLYZ_PACKEDBYTES 576 +#define MLDSA_POLYW1_PACKEDBYTES 192 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#elif MLD_CONFIG_PARAMETER_SET == 65 + +#define MLDSA_K 6 +#define MLDSA_L 5 +#define MLDSA_ETA 4 +#define MLDSA_TAU 49 +#define MLDSA_BETA 196 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 55 +#define MLDSA_CTILDEBYTES 48 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 128 + +#elif MLD_CONFIG_PARAMETER_SET == 87 + +#define MLDSA_K 8 +#define MLDSA_L 7 +#define MLDSA_ETA 2 +#define MLDSA_TAU 60 +#define MLDSA_BETA 120 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 75 +#define MLDSA_CTILDEBYTES 64 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ + +#define MLDSA_POLYT1_PACKEDBYTES 320 +#define MLDSA_POLYT0_PACKEDBYTES 416 +#define MLDSA_POLYVECH_PACKEDBYTES (MLDSA_OMEGA + MLDSA_K) + +#define MLDSA_CRYPTO_PUBLICKEYBYTES \ + (MLDSA_SEEDBYTES + MLDSA_K * MLDSA_POLYT1_PACKEDBYTES) +#define MLDSA_CRYPTO_SECRETKEYBYTES \ + (2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + MLDSA_L * MLDSA_POLYETA_PACKEDBYTES + \ + MLDSA_K * MLDSA_POLYETA_PACKEDBYTES + MLDSA_K * MLDSA_POLYT0_PACKEDBYTES) +#define MLDSA_CRYPTO_BYTES \ + (MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES + \ + MLDSA_POLYVECH_PACKEDBYTES) + +#endif /* !MLD_PARAMS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/poly.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/poly.c new file mode 100644 index 0000000000..e40534e773 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/poly.c @@ -0,0 +1,973 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "common.h" +#include "ct.h" +#include "debug.h" +#include "poly.h" +#include "reduce.h" +#include "rounding.h" +#include "symmetric.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +#include "zetas.inc" + +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + { + a->coeffs[i] = mld_reduce32(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_STATIC_TESTABLE void mld_poly_caddq_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + ) + { + a->coeffs[i] = mld_caddq(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_POLY_CADDQ) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_poly_caddq_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + mld_poly_caddq_c(a); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1])) + invariant(forall(k2, 0, i, r->coeffs[k2] < MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k2, 0, i, r->coeffs[k2] >= INT32_MIN)) + ) + { + r->coeffs[i] = r->coeffs[i] + b->coeffs[i]; + } +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(r->coeffs, 0, i, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + ) + { + r->coeffs[i] = r->coeffs[i] - b->coeffs[i]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N; i++) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))) + { + /* Reference: uses a left shift by MLDSA_D which is undefined behaviour in + * C90/C99 + */ + a->coeffs[i] *= (1 << MLDSA_D); + } + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + + +static MLD_INLINE int32_t mld_fqmul(int32_t a, int32_t b) +__contract__( + requires(b > -MLDSA_Q_HALF && b < MLDSA_Q_HALF) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* Bounds: We argue in mld_montgomery_reduce() that the reult + * of Montgomery reduction is < MLDSA_Q if the input is smaller + * than 2^31 * MLDSA_Q in absolute value. Indeed, we have: + * + * |a * b| = |a| * |b| + * < 2^31 * MLDSA_Q_HALF + * < 2^31 * MLDSA_Q + */ + return mld_montgomery_reduce((int64_t)a * (int64_t)b); +} + +/* mld_ntt_butterfly_block() + * + * Computes a block CT butterflies with a fixed twiddle factor, + * using Montgomery multiplication. + * + * Parameters: + * - r: Pointer to base of polynomial (_not_ the base of butterfly block) + * - zeta: Twiddle factor to use for the butterfly. This must be in + * Montgomery form and signed canonical. + * - start: Offset to the beginning of the butterfly block + * - len: Index difference between coefficients subject to a butterfly + * - bound: Ghost variable describing coefficient bound: Prior to `start`, + * coefficients must be bound by `bound + MLDSA_Q`. Post `start`, + * they must be bound by `bound`. + * When this function returns, output coefficients in the index range + * [start, start+2*len) have bound bumped to `bound + MLDSA_Q`. + * Example: + * - start=8, len=4 + * This would compute the following four butterflies + * 8 -- 12 + * 9 -- 13 + * 10 -- 14 + * 11 -- 15 + * - start=4, len=2 + * This would compute the following two butterflies + * 4 -- 6 + * 5 -- 7 + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_butterfly_block(int32_t r[MLDSA_N], + const int32_t zeta, + const unsigned start, + const unsigned len, + const unsigned bound) +__contract__( + requires(start < MLDSA_N) + requires(1 <= len && len <= MLDSA_N / 2 && start + 2 * len <= MLDSA_N) + requires(0 <= bound && bound < INT32_MAX - MLDSA_Q) + requires(-MLDSA_Q_HALF < zeta && zeta < MLDSA_Q_HALF) + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, start, bound + MLDSA_Q)) + requires(array_abs_bound(r, start, MLDSA_N, bound)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, start + 2*len, bound + MLDSA_Q)) + ensures(array_abs_bound(r, start + 2 * len, MLDSA_N, bound))) +{ + /* `bound` is a ghost variable only needed in the CBMC specification */ + unsigned j; + ((void)bound); + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + /* + * Coefficients are updated in strided pairs, so the bounds for the + * intermediate states alternate twice between the old and new bound + */ + invariant(array_abs_bound(r, 0, j, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, bound)) + invariant(array_abs_bound(r, start + len, j + len, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j + len, MLDSA_N, bound))) + { + int32_t t; + t = mld_fqmul(r[j + len], zeta); + r[j + len] = r[j] - t; + r[j] = r[j] + t; + } +} + +/* mld_ntt_layer() + * + * Compute one layer of forward NTT + * + * Parameters: + * - r: Pointer to base of polynomial + * - layer: Indicates which layer is being applied. + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_layer(int32_t r[MLDSA_N], const unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (layer + 1) * MLDSA_Q))) +{ + unsigned start, k, len; + /* Twiddle factors for layer n are at indices 2^(n-1)..2^n-1. */ + k = 1u << (layer - 1); + len = (unsigned)MLDSA_N >> layer; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start < MLDSA_N + 2 * len) + invariant(k <= MLDSA_N) + invariant(2 * len * k == start + MLDSA_N) + invariant(array_abs_bound(r, 0, start, layer * MLDSA_Q + MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, layer * MLDSA_Q))) + { + int32_t zeta = mld_zetas[k++]; + mld_ntt_butterfly_block(r, zeta, start, len, layer * MLDSA_Q); + } +} + +MLD_STATIC_TESTABLE void mld_poly_ntt_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +) +{ + unsigned int layer; + int32_t *r; + + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + r = a->coeffs; + + for (layer = 1; layer < 9; layer++) + __loop__( + invariant(1 <= layer && layer <= 9) + invariant(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + ) + { + mld_ntt_layer(r, layer); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_NTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_ntt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_NTT */ + mld_poly_ntt_c(a); +} + +/************************************************* + * Name: mld_fqscale + * + * Description: Scales a field element by mont/256 , i.e., performs Montgomery + * multiplication by mont^2/256. + * Input is expected to have absolute value smaller than + * 256 * MLDSA_Q. + * Output has absolute value smaller than MLD_INTT_BOUND. + * + * Arguments: - int32_t a: Field element to be scaled. + **************************************************/ +static MLD_INLINE int32_t mld_fqscale(int32_t a) +__contract__( + requires(a > -256*MLDSA_Q && a < 256*MLDSA_Q) + ensures(return_value > -MLD_INTT_BOUND && return_value < MLD_INTT_BOUND) +) +{ + /* check-magic: 41978 == pow(2,64-8,MLDSA_Q) */ + const int32_t f = 41978; + /* Bounds: MLD_INTT_BOUND is MLDSA_Q, so the bounds reasoning is just + * a special case of that in mld_fqmul(). */ + return mld_montgomery_reduce((int64_t)a * f); +} + +/* Reference: Embedded into `invntt_tomont()` in the reference implementation + * @[REF] */ +static MLD_INLINE void mld_invntt_layer(int32_t r[MLDSA_N], unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> (layer - 1)) * MLDSA_Q))) +{ + unsigned start, k, len; + len = (unsigned)MLDSA_N >> layer; + k = (1u << layer) - 1; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start <= MLDSA_N && k <= 255) + invariant(2 * len * k + start == 2 * MLDSA_N - 2 * len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + unsigned j; + int32_t zeta = -mld_zetas[k--]; + + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, j, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, (MLDSA_N >> layer) * MLDSA_Q)) + invariant(array_abs_bound(r, start + len, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + int32_t t = r[j]; + r[j] = t + r[j + len]; + r[j + len] = t - r[j + len]; + r[j + len] = mld_fqmul(r[j + len], zeta); + } + } +} + +MLD_STATIC_TESTABLE void mld_poly_invntt_tomont_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +) +{ + unsigned int layer, j; + int32_t *r; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + r = a->coeffs; + for (layer = 8; layer >= 1; layer--) + __loop__( + invariant(layer <= 8) + /* Absolute bounds increase from 1Q before layer 8 */ + /* up to 256Q after layer 1 */ + invariant(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + mld_invntt_layer(r, layer); + } + + /* Coefficient bounds are now at 256Q. We now scale by mont / 256, + * i.e., compute the Montgomery multiplication by mont^2 / 256. + * mont corrects the mont^-1 factor introduced in the basemul. + * 1/256 performs that scaling of the inverse NTT. + * The reduced value is bounded by MLD_INTT_BOUND in absolute + * value.*/ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + invariant(j <= MLDSA_N) + invariant(array_abs_bound(r, 0, j, MLD_INTT_BOUND)) + invariant(array_abs_bound(r, j, MLDSA_N, MLDSA_N * MLDSA_Q)) + ) + { + r[j] = mld_fqscale(r[j]); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); +} + + +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_INTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_intt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_INTT */ + mld_poly_invntt_tomont_c(a); +} + +MLD_STATIC_TESTABLE void mld_poly_pointwise_montgomery_c(mld_poly *c, + const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_abs_bound(c->coeffs, 0, i, MLDSA_Q)) + ) + { + c->coeffs[i] = mld_montgomery_reduce((int64_t)a->coeffs[i] * b->coeffs[i]); + } + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +{ +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + ret = mld_poly_pointwise_montgomery_native(c->coeffs, a->coeffs, b->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + mld_poly_pointwise_montgomery_c(c, a, b); +} + +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, 0, i, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + invariant(array_bound(a1->coeffs, 0, i, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) + ) + { + mld_power2round(&a0->coeffs[i], &a1->coeffs[i], a->coeffs[i]); + } + + mld_assert_bound(a0->coeffs, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +#ifndef MLD_POLY_UNIFORM_NBLOCKS +#define MLD_POLY_UNIFORM_NBLOCKS \ + ((768 + MLD_STREAM128_BLOCKBYTES - 1) / MLD_STREAM128_BLOCKBYTES) +#endif +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +MLD_STATIC_TESTABLE unsigned int mld_rej_uniform_c(int32_t *a, + unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ + unsigned int ctr, pos; + uint32_t t; + mld_assert_bound(a, offset, 0, MLDSA_Q); + + ctr = offset; + pos = 0; + /* pos + 3 cannot overflow due to the assumption + buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) */ + while (ctr < target && pos + 3 <= buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_bound(a, 0, ctr, 0, MLDSA_Q))) + { + t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + a[ctr++] = (int32_t)t; + } + } + + mld_assert_bound(a, ctr, 0, MLDSA_Q); + + return ctr; +} +/************************************************* + * Name: mld_rej_uniform + * + * Description: Sample uniformly random coefficients in [0, MLDSA_Q-1] by + * performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes (must be + * multiple of 3) + * + * Returns number of sampled coefficients. Can be smaller than len if not enough + * random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +static unsigned int mld_rej_uniform(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) + int ret; + mld_assert_bound(a, offset, 0, MLDSA_Q); + if (offset == 0) + { + ret = mld_rej_uniform_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_bound(a, res, 0, MLDSA_Q); + return res; + } + } +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + + return mld_rej_uniform_c(a, target, offset, buf, buflen); +} + +/* Reference: poly_uniform() in the reference implementation @[REF]. + * - Simplified from reference by removing buffer tail handling + * since buflen % 3 = 0 always holds true (MLD_STREAM128_BLOCKBYTES + * = 168). + * - Modified rej_uniform interface to track offset directly. + * - Pass nonce packed in the extended seed array instead of a third + * argument. + * */ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +{ + unsigned int ctr; + unsigned int buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + MLD_ALIGN uint8_t buf[MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES]; + mld_xof128_ctx state; + + mld_xof128_init(&state); + mld_xof128_absorb_once(&state, seed, MLDSA_SEEDBYTES + 2); + mld_xof128_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, 0, buf, buflen); + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(a, sizeof(mld_poly)), object_whole(buf)) + invariant(ctr <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, ctr, 0, MLDSA_Q)) + invariant(state.pos <= SHAKE128_RATE) + ) + { + mld_xof128_squeezeblocks(buf, 1, &state); + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, ctr, buf, buflen); + } + mld_xof128_release(&state); + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof128_x4_ctx state; + unsigned buflen; + + mld_xof128_x4_init(&state); + mld_xof128_x4_absorb(&state, seed, MLDSA_SEEDBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_NBLOCKS. + * This should generate the matrix entries with high probability. + */ + + mld_xof128_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all matrix entries have been generated, squeeze + * one more block a time until we're done. + */ + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, object_whole(buf), + memory_slice(vec0, sizeof(mld_poly)), memory_slice(vec1, sizeof(mld_poly)), + memory_slice(vec2, sizeof(mld_poly)), memory_slice(vec3, sizeof(mld_poly))) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_bound(vec0->coeffs, 0, ctr[0], 0, MLDSA_Q)) + invariant(array_bound(vec1->coeffs, 0, ctr[1], 0, MLDSA_Q)) + invariant(array_bound(vec2->coeffs, 0, ctr[2], 0, MLDSA_Q)) + invariant(array_bound(vec3->coeffs, 0, ctr[3], 0, MLDSA_Q))) + { + mld_xof128_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + mld_xof128_x4_release(&state); + + mld_assert_bound(vec0->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec1->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec2->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec3->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0) & 0xFF); + r[5 * i + 1] = + (uint8_t)(((a->coeffs[4 * i + 0] >> 8) | (a->coeffs[4 * i + 1] << 2)) & + 0xFF); + r[5 * i + 2] = + (uint8_t)(((a->coeffs[4 * i + 1] >> 6) | (a->coeffs[4 * i + 2] << 4)) & + 0xFF); + r[5 * i + 3] = + (uint8_t)(((a->coeffs[4 * i + 2] >> 4) | (a->coeffs[4 * i + 3] << 6)) & + 0xFF); + r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, 0, 1 << 10))) + { + r->coeffs[4 * i + 0] = + ((a[5 * i + 0] >> 0) | ((int32_t)a[5 * i + 1] << 8)) & 0x3FF; + r->coeffs[4 * i + 1] = + ((a[5 * i + 1] >> 2) | ((int32_t)a[5 * i + 2] << 6)) & 0x3FF; + r->coeffs[4 * i + 2] = + ((a[5 * i + 2] >> 4) | ((int32_t)a[5 * i + 3] << 4)) & 0x3FF; + r->coeffs[4 * i + 3] = + ((a[5 * i + 3] >> 6) | ((int32_t)a[5 * i + 4] << 2)) & 0x3FF; + } + + mld_assert_bound(r->coeffs, MLDSA_N, 0, 1 << 10); +} + +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[8]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* Safety: a->coeffs[i] <= (1 << (MLDSA_D - 1) as they are output of + * power2round, hence, these casts are safe. */ + t[0] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 0]); + t[1] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 1]); + t[2] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 2]); + t[3] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 3]); + t[4] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 4]); + t[5] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 5]); + t[6] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 6]); + t[7] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 7]); + + r[13 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[13 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[13 * i + 1] |= (uint8_t)((t[1] << 5) & 0xFF); + r[13 * i + 2] = (uint8_t)((t[1] >> 3) & 0xFF); + r[13 * i + 3] = (uint8_t)((t[1] >> 11) & 0xFF); + r[13 * i + 3] |= (uint8_t)((t[2] << 2) & 0xFF); + r[13 * i + 4] = (uint8_t)((t[2] >> 6) & 0xFF); + r[13 * i + 4] |= (uint8_t)((t[3] << 7) & 0xFF); + r[13 * i + 5] = (uint8_t)((t[3] >> 1) & 0xFF); + r[13 * i + 6] = (uint8_t)((t[3] >> 9) & 0xFF); + r[13 * i + 6] |= (uint8_t)((t[4] << 4) & 0xFF); + r[13 * i + 7] = (uint8_t)((t[4] >> 4) & 0xFF); + r[13 * i + 8] = (uint8_t)((t[4] >> 12) & 0xFF); + r[13 * i + 8] |= (uint8_t)((t[5] << 1) & 0xFF); + r[13 * i + 9] = (uint8_t)((t[5] >> 7) & 0xFF); + r[13 * i + 9] |= (uint8_t)((t[6] << 6) & 0xFF); + r[13 * i + 10] = (uint8_t)((t[6] >> 2) & 0xFF); + r[13 * i + 11] = (uint8_t)((t[6] >> 10) & 0xFF); + r[13 * i + 11] |= (uint8_t)((t[7] << 3) & 0xFF); + r[13 * i + 12] = (uint8_t)((t[7] >> 5) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + { + r->coeffs[8 * i + 0] = a[13 * i + 0]; + r->coeffs[8 * i + 0] |= (int32_t)a[13 * i + 1] << 8; + r->coeffs[8 * i + 0] &= 0x1FFF; + + r->coeffs[8 * i + 1] = a[13 * i + 1] >> 5; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 2] << 3; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 3] << 11; + r->coeffs[8 * i + 1] &= 0x1FFF; + + r->coeffs[8 * i + 2] = a[13 * i + 3] >> 2; + r->coeffs[8 * i + 2] |= (int32_t)a[13 * i + 4] << 6; + r->coeffs[8 * i + 2] &= 0x1FFF; + + r->coeffs[8 * i + 3] = a[13 * i + 4] >> 7; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 5] << 1; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 6] << 9; + r->coeffs[8 * i + 3] &= 0x1FFF; + + r->coeffs[8 * i + 4] = a[13 * i + 6] >> 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 7] << 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 8] << 12; + r->coeffs[8 * i + 4] &= 0x1FFF; + + r->coeffs[8 * i + 5] = a[13 * i + 8] >> 1; + r->coeffs[8 * i + 5] |= (int32_t)a[13 * i + 9] << 7; + r->coeffs[8 * i + 5] &= 0x1FFF; + + r->coeffs[8 * i + 6] = a[13 * i + 9] >> 6; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 10] << 2; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 11] << 10; + r->coeffs[8 * i + 6] &= 0x1FFF; + + r->coeffs[8 * i + 7] = a[13 * i + 11] >> 3; + r->coeffs[8 * i + 7] |= (int32_t)a[13 * i + 12] << 5; + r->coeffs[8 * i + 7] &= 0x1FFF; + + r->coeffs[8 * i + 0] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 7]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +MLD_STATIC_TESTABLE uint32_t mld_poly_chknorm_c(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == array_abs_bound(a->coeffs, 0, i, B)) + ) + { + /* + * Since we know that -MLD_REDUCE32_RANGE_MAX <= a < MLD_REDUCE32_RANGE_MAX, + * and B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX, to check if + * -B < (a mod± MLDSA_Q) < B, it suffices to check if -B < a < B. + * + * We prove this to be true using the following CBMC assertions. + * a ==> b expressed as !a || b to also allow run-time assertion. + */ + mld_assert(a->coeffs[i] < B || a->coeffs[i] - MLDSA_Q <= -B); + mld_assert(a->coeffs[i] > -B || a->coeffs[i] + MLDSA_Q >= B); + + /* Reference: Leaks which coefficient violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + + /* if (abs(a[i]) >= B) */ + t |= mld_ct_cmask_neg_i32(B - 1 - mld_ct_abs_i32(a->coeffs[i])); + } + + return t; +} + +/* Reference: explicitly checks the bound B to be <= (MLDSA_Q - 1) / 8). + * This is unnecessary as it's always a compile-time constant. + * We instead model it as a precondition. + * Checking the bound is performed using a conditional arguing + * that it is okay to leak which coefficient violates the bound (while the + * coefficient itself must remain secret). + * We instead perform everything in constant-time. + * Also it is sufficient to check that it is smaller than + * MLDSA_Q - MLD_REDUCE32_RANGE_MAX > (MLDSA_Q - 1) / 8). + */ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +{ +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) + int ret; + int success; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + /* The native backend returns 0 if all coefficients are within the bound, + * 1 if at least one coefficient exceeds the bound, and + * -1 (MLD_NATIVE_FUNC_FALLBACK) if the platform does not have the + * required capabilities to run the native function. + */ + ret = mld_poly_chknorm_native(a->coeffs, B); + + success = (ret != MLD_NATIVE_FUNC_FALLBACK); + /* Constant-time: It would be fine to leak the return value of chknorm + * entirely (as it is fine to leak if any coefficient exceeded the bound or + * not). However, it is cleaner to perform declassification in sign.c. + * Hence, here we only declassify if the native function returned + * MLD_NATIVE_FUNC_FALLBACK or not (which solely depends on system + * capabilities). + */ + MLD_CT_TESTING_DECLASSIFY(&success, sizeof(int)); + if (success) + { + /* Convert 0 / 1 to 0 / 0xFFFFFFFF here */ + return 0U - (uint32_t)ret; + } +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + return mld_poly_chknorm_c(a, B); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ +MLD_EMPTY_CU(mld_poly) +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_POLY_UNIFORM_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/poly.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/poly.h new file mode 100644 index 0000000000..ff7710438e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/poly.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_H +#define MLD_POLY_H + +#include +#include "cbmc.h" +#include "common.h" +#include "reduce.h" +#include "rounding.h" + +/* Absolute exclusive upper bound for the output of the forward NTT */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) +/* Absolute exclusive upper bound for the output of the inverse NTT*/ +#define MLD_INTT_BOUND MLDSA_Q + +typedef struct +{ + int32_t coeffs[MLDSA_N]; +} MLD_ALIGN mld_poly; + +#define mld_poly_reduce MLD_NAMESPACE(poly_reduce) +/************************************************* + * Name: mld_poly_reduce + * + * Description: Inplace reduction of all coefficients of polynomial to + * representative in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) +); + +#define mld_poly_caddq MLD_NAMESPACE(poly_caddq) +/************************************************* + * Name: mld_poly_caddq + * + * Description: For all coefficients of in/out polynomial add MLDSA_Q if + * coefficient is negative. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_add MLD_NAMESPACE(poly_add) +/************************************************* + * Name: mld_poly_add + * + * Description: Add polynomials. No modular reduction is performed. + * + * Arguments: - r: Pointer to input-output polynomial to be added to. + * - b: Pointer to input polynomial that should be added + * to r. Must be disjoint from r. + **************************************************/ + +/* + * NOTE: The reference implementation uses a 3-argument poly_add. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(forall(k0, 0, MLDSA_N, (int64_t) r->coeffs[k0] + b->coeffs[k0] < MLD_REDUCE32_DOMAIN_MAX)) + requires(forall(k1, 0, MLDSA_N, (int64_t) r->coeffs[k1] + b->coeffs[k1] >= INT32_MIN)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(forall(k2, 0, MLDSA_N, r->coeffs[k2] == old(*r).coeffs[k2] + b->coeffs[k2])) + ensures(forall(k3, 0, MLDSA_N, r->coeffs[k3] < MLD_REDUCE32_DOMAIN_MAX)) + ensures(forall(k4, 0, MLDSA_N, r->coeffs[k4] >= INT32_MIN)) +); + +#define mld_poly_sub MLD_NAMESPACE(poly_sub) +/************************************************* + * Name: mld_poly_sub + * + * Description: Subtract polynomials. No modular reduction is + * performed. + * + * Arguments: - mld_poly *r: Pointer to input-output polynomial. + * - const mld_poly *b: Pointer to input polynomial that should be + * subtracted from r. Must be disjoint from r. + **************************************************/ +/* + * NOTE: The reference implementation uses a 3-argument poly_sub. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_Q)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) +); + +#define mld_poly_shiftl MLD_NAMESPACE(poly_shiftl) +/************************************************* + * Name: mld_poly_shiftl + * + * Description: Multiply polynomial by 2^MLDSA_D without modular reduction. + *Assumes input coefficients to be less than 2^{31-MLDSA_D} in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_ntt MLD_NAMESPACE(poly_ntt) +/************************************************* + * Name: mld_poly_ntt + * + * Description: Inplace forward NTT. Coefficients can grow by + * 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +); + + +#define mld_poly_invntt_tomont MLD_NAMESPACE(poly_invntt_tomont) +/************************************************* + * Name: mld_poly_invntt_tomont + * + * Description: Inplace inverse NTT and multiplication by 2^{32}. + * Input coefficients need to be less than MLDSA_Q in absolute + * value and output coefficients are bounded by + * MLD_INTT_BOUND. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +); + +#define mld_poly_pointwise_montgomery MLD_NAMESPACE(poly_pointwise_montgomery) +/************************************************* + * Name: mld_poly_pointwise_montgomery + * + * Description: Pointwise multiplication of polynomials in NTT domain + * representation and multiplication of resulting polynomial + * by 2^{-32}. + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const mld_poly *a: pointer to first input polynomial + * - const mld_poly *b: pointer to second input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + +#define mld_poly_power2round MLD_NAMESPACE(poly_power2round) +/************************************************* + * Name: mld_poly_power2round + * + * Description: For all coefficients c of the input polynomial, + * compute c0, c1 such that c mod MLDSA_Q = c1*2^MLDSA_D + c0 + * with -2^{MLDSA_D-1} < c0 <= 2^{MLDSA_D-1}. Assumes coefficients + *to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + *c1 + * - mld_poly *a0: pointer to output polynomial with coefficients + *c0 + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +__contract__( + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a0->coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) +); + +#define mld_poly_uniform MLD_NAMESPACE(poly_uniform) +/************************************************* + * Name: mld_poly_uniform + * + * Description: Sample polynomial with uniformly random coefficients + * in [0,MLDSA_Q-1] by performing rejection sampling on the + * output stream of SHAKE128(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_SEEDBYTES and the packed 2-byte nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES + 2)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +#define mld_poly_uniform_4x MLD_NAMESPACE(poly_uniform_4x) +/************************************************* + * Name: mld_poly_uniform_x4 + * + * Description: Generate four polynomials using rejection sampling + * on (pseudo-)uniformly random bytes sampled from a seed. + * + * Arguments: - mld_poly *vec0, *vec1, *vec2, *vec3: + * Pointers to 4 polynomials to be sampled. + * - uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]: + * Pointer consecutive array of seed buffers of size + * MLDSA_SEEDBYTES + 2 each, plus padding for alignment. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +__contract__( + requires(memory_no_alias(vec0, sizeof(mld_poly))) + requires(memory_no_alias(vec1, sizeof(mld_poly))) + requires(memory_no_alias(vec2, sizeof(mld_poly))) + requires(memory_no_alias(vec3, sizeof(mld_poly))) + requires(memory_no_alias(seed, 4 * MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2))) + assigns(memory_slice(vec0, sizeof(mld_poly))) + assigns(memory_slice(vec1, sizeof(mld_poly))) + assigns(memory_slice(vec2, sizeof(mld_poly))) + assigns(memory_slice(vec3, sizeof(mld_poly))) + ensures(array_bound(vec0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec1->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec2->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec3->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +#define mld_polyt1_pack MLD_NAMESPACE(polyt1_pack) +/************************************************* + * Name: mld_polyt1_pack + * + * Description: Bit-pack polynomial t1 with coefficients fitting in 10 bits. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(r, MLDSA_POLYT1_PACKEDBYTES)) +); + +#define mld_polyt1_unpack MLD_NAMESPACE(polyt1_unpack) +/************************************************* + * Name: mld_polyt1_unpack + * + * Description: Unpack polynomial t1 with 10-bit coefficients. + * Output coefficients are standard representatives. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT1_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, 0, 1 << 10)) +); + +#define mld_polyt0_pack MLD_NAMESPACE(polyt0_pack) +/************************************************* + * Name: mld_polyt0_pack + * + * Description: Bit-pack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + * 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) + assigns(memory_slice(r, MLDSA_POLYT0_PACKEDBYTES)) +); + + +#define mld_polyt0_unpack MLD_NAMESPACE(polyt0_unpack) +/************************************************* + * Name: mld_polyt0_unpack + * + * Description: Unpack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + *2^{MLDSA_D-1}]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT0_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) +); + +#define mld_poly_chknorm MLD_NAMESPACE(poly_chknorm) +/************************************************* + * Name: mld_poly_chknorm + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const mld_poly *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if norm is strictly smaller than + * B <= (MLDSA_Q - MLD_REDUCE32_RANGE_MAX) and 0xFFFFFFFF otherwise. + * + * Specification: The definition of this FIPS-204 requires signed canonical + * reduction prior to applying the bounds check. + * However, `-B < (a mod± MLDSA_Q) < B` is equivalent to + * `-B < a < B` under the assumption that + * `B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX` (cf. the assertion in + * the code). Hence, the present spec and implementation are + * correct without reduction. + * + **************************************************/ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +); + +#endif /* !MLD_POLY_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/poly_kl.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/poly_kl.c new file mode 100644 index 0000000000..7a319ca515 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/poly_kl.c @@ -0,0 +1,931 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "ct.h" +#include "debug.h" +#include "poly_kl.h" +#include "rounding.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_rej_eta MLD_ADD_PARAM_SET(mld_rej_eta) +#define mld_rej_eta_c MLD_ADD_PARAM_SET(mld_rej_eta_c) +#define mld_poly_decompose_c MLD_ADD_PARAM_SET(mld_poly_decompose_c) +#define mld_poly_use_hint_c MLD_ADD_PARAM_SET(mld_poly_use_hint_c) +#define mld_polyz_unpack_c MLD_ADD_PARAM_SET(mld_polyz_unpack_c) +/* End of parameter set namespacing */ + + +MLD_STATIC_TESTABLE +void mld_poly_decompose_c(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +) +{ + unsigned int i; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, i, MLDSA_N, 0, MLDSA_Q)) + invariant(array_bound(a1->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + invariant(array_abs_bound(a0->coeffs, 0, i, MLDSA_GAMMA2+1)) + ) + { + mld_decompose(&a0->coeffs[i], &a1->coeffs[i], a0->coeffs[i]); + } + + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +{ +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_88_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_32_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_DECOMPOSE_88 && MLD_CONFIG_PARAMETER_SET == \ + 44) && MLD_USE_NATIVE_POLY_DECOMPOSE_32 && (MLD_CONFIG_PARAMETER_SET \ + == 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_decompose_c(a1, a0); +} + +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(s <= i) + invariant(array_bound(h->coeffs, 0, i, 0, 2)) + ) + { + const unsigned int hint_bit = mld_make_hint(a0->coeffs[i], a1->coeffs[i]); + h->coeffs[i] = (int32_t)hint_bit; + s += hint_bit; + } + + mld_assert(s <= MLDSA_N); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + return s; +} + +MLD_STATIC_TESTABLE void mld_poly_use_hint_c(mld_poly *b, const mld_poly *a, + const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(b->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ) + { + b->coeffs[i] = mld_use_hint(a->coeffs[i], h->coeffs[i]); + } + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +{ +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_88_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_USE_HINT_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_32_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_USE_HINT_88 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLY_USE_HINT_32 && (MLD_CONFIG_PARAMETER_SET == \ + 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_use_hint_c(b, a, h); +} + +/************************************************* + * Name: mld_rej_eta + * + * Description: Sample uniformly random coefficients in [-MLDSA_ETA, MLDSA_ETA] + *by performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes + * + * Returns number of sampled coefficients. Can be smaller than target if not + *enough random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_eta()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +#if MLDSA_ETA == 2 +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 1 +#elif MLDSA_ETA == 4 +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 2 +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + +MLD_STATIC_TESTABLE unsigned int mld_rej_eta_c(int32_t *a, unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ + unsigned int ctr, pos; + int t_valid; + uint32_t t0, t1; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + ctr = offset; + pos = 0; + while (ctr < target && pos < buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_abs_bound(a, 0, ctr, MLDSA_ETA + 1)) + ) + { + t0 = buf[pos] & 0x0F; + t1 = buf[pos++] >> 4; + + /* Constant time: The inputs and outputs to the rejection sampling are + * secret. However, it is fine to leak which coefficients have been + * rejected. For constant-time testing, we declassify the result of + * the comparison. + */ +#if MLDSA_ETA == 2 + t_valid = t0 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 15 */ + { + t0 = t0 - (205 * t0 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t0; + } + t_valid = t1 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) /* t1 < 15 */ + { + t1 = t1 - (205 * t1 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t1; + } +#elif MLDSA_ETA == 4 + t_valid = t0 < 9; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 9 */ + { + a[ctr++] = 4 - (int32_t)t0; + } + t_valid = t1 < 9; /* t1 < 9 */ + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) + { + a[ctr++] = 4 - (int32_t)t1; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + } + + mld_assert_abs_bound(a, ctr, MLDSA_ETA + 1); + + return ctr; +} + +static unsigned int mld_rej_eta(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ +#if MLDSA_ETA == 2 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta2_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#elif MLDSA_ETA == 4 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta4_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#endif /* !(MLDSA_ETA == 2 && MLD_USE_NATIVE_REJ_UNIFORM_ETA2) && MLDSA_ETA == \ + 4 && MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + + return mld_rej_eta_c(a, target, offset, buf, buflen); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_ETA_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof256_x4_ctx state; + unsigned buflen; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = nonce0; + extseed[1][MLDSA_CRHBYTES] = nonce1; + extseed[2][MLDSA_CRHBYTES] = nonce2; + extseed[3][MLDSA_CRHBYTES] = nonce3; + extseed[0][MLDSA_CRHBYTES + 1] = 0; + extseed[1][MLDSA_CRHBYTES + 1] = 0; + extseed[2][MLDSA_CRHBYTES + 1] = 0; + extseed[3][MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(r0, sizeof(mld_poly)), + memory_slice(r1, sizeof(mld_poly)), memory_slice(r2, sizeof(mld_poly)), + memory_slice(r3, sizeof(mld_poly)), object_whole(buf[0]), + object_whole(buf[1]), object_whole(buf[2]), + object_whole(buf[3])) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_abs_bound(r0->coeffs, 0, ctr[0], MLDSA_ETA + 1)) + invariant(array_abs_bound(r1->coeffs, 0, ctr[1], MLDSA_ETA + 1)) + invariant(array_abs_bound(r2->coeffs, 0, ctr[2], MLDSA_ETA + 1)) + invariant(array_abs_bound(r3->coeffs, 0, ctr[3], MLDSA_ETA + 1))) + { + mld_xof256_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + + mld_xof256_x4_release(&state); + + mld_assert_abs_bound(r0->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r1->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r2->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r3->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +{ + /* Temporary buffer for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr; + mld_xof256_ctx state; + unsigned buflen; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = nonce; + extseed[MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr = mld_rej_eta(r->coeffs, MLDSA_N, 0, buf, buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, object_whole(&state), + object_whole(buf), memory_slice(r, sizeof(mld_poly))) + invariant(ctr <= MLDSA_N) + invariant(state.pos <= SHAKE256_RATE) + invariant(array_abs_bound(r->coeffs, 0, ctr, MLDSA_ETA + 1))) + { + mld_xof256_squeezeblocks(buf, 1, &state); + ctr = mld_rej_eta(r->coeffs, MLDSA_N, ctr, buf, buflen); + } + + mld_xof256_release(&state); + + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define MLD_POLY_UNIFORM_GAMMA1_NBLOCKS \ + ((MLDSA_POLYZ_PACKEDBYTES + MLD_STREAM256_BLOCKBYTES - 1) / \ + MLD_STREAM256_BLOCKBYTES) + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + mld_xof256_ctx state; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = (uint8_t)(nonce & 0xFF); + extseed[MLDSA_CRHBYTES + 1] = (uint8_t)(nonce >> 8); + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + mld_polyz_unpack(a, buf); + + mld_xof256_release(&state); + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + mld_xof256_x4_ctx state; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = (uint8_t)(nonce0 & 0xFF); + extseed[1][MLDSA_CRHBYTES] = (uint8_t)(nonce1 & 0xFF); + extseed[2][MLDSA_CRHBYTES] = (uint8_t)(nonce2 & 0xFF); + extseed[3][MLDSA_CRHBYTES] = (uint8_t)(nonce3 & 0xFF); + extseed[0][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce0 >> 8); + extseed[1][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce1 >> 8); + extseed[2][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce2 >> 8); + extseed[3][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce3 >> 8); + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + + mld_polyz_unpack(r0, buf[0]); + mld_polyz_unpack(r1, buf[1]); + mld_polyz_unpack(r2, buf[2]); + mld_polyz_unpack(r3, buf[3]); + mld_xof256_x4_release(&state); + + mld_assert_bound(r0->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r1->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r2->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r3->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +{ + unsigned int i, j, pos; + uint64_t signs; + uint64_t offset; + MLD_ALIGN uint8_t buf[SHAKE256_RATE]; + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, seed, MLDSA_CTILDEBYTES); + mld_shake256_finalize(&state); + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + + /* Convert the first 8 bytes of buf[] into an unsigned 64-bit value. */ + /* Each bit of that dictates the sign of the resulting challenge value */ + signs = 0; + for (i = 0; i < 8; ++i) + __loop__( + assigns(i, signs) + invariant(i <= 8) + ) + { + signs |= (uint64_t)buf[i] << 8 * i; + } + pos = 8; + + mld_memset(c, 0, sizeof(mld_poly)); + + for (i = MLDSA_N - MLDSA_TAU; i < MLDSA_N; ++i) + __loop__( + assigns(i, j, object_whole(buf), state, pos, memory_slice(c, sizeof(mld_poly)), signs) + invariant(i >= MLDSA_N - MLDSA_TAU) + invariant(i <= MLDSA_N) + invariant(pos >= 1) + invariant(pos <= SHAKE256_RATE) + invariant(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) + invariant(state.pos <= SHAKE256_RATE) + ) + { + do + __loop__( + assigns(j, object_whole(buf), state, pos) + invariant(state.pos <= SHAKE256_RATE) + ) + { + if (pos >= SHAKE256_RATE) + { + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + pos = 0; + } + j = buf[pos++]; + } while (j > i); + + c->coeffs[i] = c->coeffs[j]; + + /* Reference: Compute coefficent value here in two steps to */ + /* mixinf unsigned and signed arithmetic with implicit */ + /* conversions, and so that CBMC can keep track of ranges */ + /* to complete type-safety proof here. */ + + /* The least-significant bit of signs tells us if we want -1 or +1 */ + offset = 2 * (signs & 1); + + /* offset has value 0 or 2 here, so (1 - (int32_t) offset) has + * value -1 or +1 */ + c->coeffs[j] = 1 - (int32_t)offset; + + /* Move to the next bit of signs for next time */ + signs >>= 1; + } + + mld_assert_bound(c->coeffs, MLDSA_N, -1, 2); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(&signs, sizeof(signs)); +} + +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint8_t t[8]; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_ETA + 1); + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 1]); + t[2] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 2]); + t[3] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 3]); + t[4] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 4]); + t[5] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 5]); + t[6] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 6]); + t[7] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 7]); + + r[3 * i + 0] = (uint8_t)(((t[0] >> 0) | (t[1] << 3) | (t[2] << 6)) & 0xFF); + r[3 * i + 1] = + (uint8_t)(((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)) & + 0xFF); + r[3 * i + 2] = (uint8_t)(((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)) & 0xFF); + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 1]); + r[i] = (uint8_t)(t[0] | (t[1] << 4)); + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ +} + +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -5, MLDSA_ETA + 1))) + { + r->coeffs[8 * i + 0] = (a[3 * i + 0] >> 0) & 7; + r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 7; + r->coeffs[8 * i + 2] = ((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 7; + r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 7; + r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 7; + r->coeffs[8 * i + 5] = ((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 7; + r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 7; + r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5) & 7; + + r->coeffs[8 * i + 0] = MLDSA_ETA - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = MLDSA_ETA - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = MLDSA_ETA - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = MLDSA_ETA - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = MLDSA_ETA - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = MLDSA_ETA - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = MLDSA_ETA - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = MLDSA_ETA - r->coeffs[8 * i + 7]; + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -11, MLDSA_ETA + 1))) + { + r->coeffs[2 * i + 0] = a[i] & 0x0F; + r->coeffs[2 * i + 1] = a[i] >> 4; + r->coeffs[2 * i + 0] = MLDSA_ETA - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_ETA - r->coeffs[2 * i + 1]; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + + mld_assert_bound(r->coeffs, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + + +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[4]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 1]); + t[2] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 2]); + t[3] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 3]); + + r[9 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[9 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[9 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[9 * i + 2] |= (uint8_t)((t[1] << 2) & 0xFF); + r[9 * i + 3] = (uint8_t)((t[1] >> 6) & 0xFF); + r[9 * i + 4] = (uint8_t)((t[1] >> 14) & 0xFF); + r[9 * i + 4] |= (uint8_t)((t[2] << 4) & 0xFF); + r[9 * i + 5] = (uint8_t)((t[2] >> 4) & 0xFF); + r[9 * i + 6] = (uint8_t)((t[2] >> 12) & 0xFF); + r[9 * i + 6] |= (uint8_t)((t[3] << 6) & 0xFF); + r[9 * i + 7] = (uint8_t)((t[3] >> 2) & 0xFF); + r[9 * i + 8] = (uint8_t)((t[3] >> 10) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 1]); + + r[5 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[5 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[5 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[5 * i + 2] |= (uint8_t)((t[1] << 4) & 0xFF); + r[5 * i + 3] = (uint8_t)((t[1] >> 4) & 0xFF); + r[5 * i + 4] = (uint8_t)((t[1] >> 12) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +MLD_STATIC_TESTABLE void mld_polyz_unpack_c( + mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +) +{ + unsigned int i; +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[4 * i + 0] = a[9 * i + 0]; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 2] << 16; + r->coeffs[4 * i + 0] &= 0x3FFFF; + + r->coeffs[4 * i + 1] = a[9 * i + 2] >> 2; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 3] << 6; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 4] << 14; + r->coeffs[4 * i + 1] &= 0x3FFFF; + + r->coeffs[4 * i + 2] = a[9 * i + 4] >> 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 5] << 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 6] << 12; + r->coeffs[4 * i + 2] &= 0x3FFFF; + + r->coeffs[4 * i + 3] = a[9 * i + 6] >> 6; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 7] << 2; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10; + r->coeffs[4 * i + 3] &= 0x3FFFF; + + r->coeffs[4 * i + 0] = MLDSA_GAMMA1 - r->coeffs[4 * i + 0]; + r->coeffs[4 * i + 1] = MLDSA_GAMMA1 - r->coeffs[4 * i + 1]; + r->coeffs[4 * i + 2] = MLDSA_GAMMA1 - r->coeffs[4 * i + 2]; + r->coeffs[4 * i + 3] = MLDSA_GAMMA1 - r->coeffs[4 * i + 3]; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[2 * i + 0] = a[5 * i + 0]; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 2] << 16; + r->coeffs[2 * i + 0] &= 0xFFFFF; + + r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 3] << 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12; + /* r->coeffs[2*i+1] &= 0xFFFFF; */ /* No effect, since we're anyway at 20 + bits */ + + r->coeffs[2 * i + 0] = MLDSA_GAMMA1 - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_GAMMA1 - r->coeffs[2 * i + 1]; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +{ +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + ret = mld_polyz_unpack_17_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#elif defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + ret = mld_polyz_unpack_19_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYZ_UNPACK_17 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLYZ_UNPACK_19 && (MLD_CONFIG_PARAMETER_SET == 65 \ + || MLD_CONFIG_PARAMETER_SET == 87) */ + + mld_polyz_unpack_c(r, a); +} + +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + + mld_assert_bound(a->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[3 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0]) & 0xFF); + r[3 * i + 0] |= (uint8_t)((a->coeffs[4 * i + 1] << 6) & 0xFF); + r[3 * i + 1] = (uint8_t)((a->coeffs[4 * i + 1] >> 2) & 0xFF); + r[3 * i + 1] |= (uint8_t)((a->coeffs[4 * i + 2] << 4) & 0xFF); + r[3 * i + 2] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) & 0xFF); + r[3 * i + 2] |= (uint8_t)((a->coeffs[4 * i + 3] << 2) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + r[i] = + (uint8_t)((a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_rej_eta +#undef mld_rej_eta_c +#undef mld_poly_decompose_c +#undef mld_poly_use_hint_c +#undef mld_polyz_unpack_c +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_GAMMA1_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/poly_kl.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/poly_kl.h new file mode 100644 index 0000000000..c6aa498358 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/poly_kl.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_KL_H +#define MLD_POLY_KL_H + +#include "cbmc.h" +#include "common.h" +#include "poly.h" + +#define mld_poly_decompose MLD_NAMESPACE_KL(poly_decompose) +/************************************************* + * Name: mld_poly_decompose + * + * Description: For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such c mod MLDSA_Q = c1*ALPHA + + * c0 with -ALPHA/2 < c0 <= ALPHA/2 except + * c1 = (MLDSA_Q-1)/ALPHA where we set + * c1 = 0 and -ALPHA/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + * c1 + * - mld_poly *a0: pointer to input/output polynomial. Output + * polynomial has coefficients c0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +); + + +#define mld_poly_make_hint MLD_NAMESPACE_KL(poly_make_hint) +/************************************************* + * Name: mld_poly_make_hint + * + * Description: Compute hint polynomial. The coefficients of which indicate + * whether the low bits of the corresponding coefficient of + * the input polynomial overflow into the high bits. + * + * Arguments: - mld_poly *h: pointer to output hint polynomial + * - const mld_poly *a0: pointer to low part of input polynomial + * - const mld_poly *a1: pointer to high part of input polynomial + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + assigns(memory_slice(h, sizeof(mld_poly))) + ensures(return_value <= MLDSA_N) + ensures(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) +); + +#define mld_poly_use_hint MLD_NAMESPACE_KL(poly_use_hint) +/************************************************* + * Name: mld_poly_use_hint + * + * Description: Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - mld_poly *b: pointer to output polynomial with corrected high + *bits + * - const mld_poly *a: pointer to input polynomial + * - const mld_poly *h: pointer to input hint polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta_4x MLD_NAMESPACE_KL(poly_uniform_eta_4x) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample four polynomials with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce_i) + * + * Arguments: - mld_poly *r0: pointer to first output polynomial + * - mld_poly *r1: pointer to second output polynomial + * - mld_poly *r2: pointer to third output polynomial + * - mld_poly *r3: pointer to fourth output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce0: first nonce + * - uint8_t nonce1: second nonce + * - uint8_t nonce2: third nonce + * - uint8_t nonce3: fourth nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_abs_bound(r0->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r1->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r2->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r3->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta MLD_NAMESPACE_KL(poly_uniform_eta) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample polynomial with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce: nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1 MLD_NAMESPACE_KL(poly_uniform_gamma1) +/************************************************* + * Name: mld_poly_uniform_gamma1 + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1_4x MLD_NAMESPACE_KL(poly_uniform_gamma1_4x) +/************************************************* + * Name: mld_poly_uniform_gamma1_4x + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_bound(r0->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r1->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r2->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r3->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define mld_poly_challenge MLD_NAMESPACE_KL(poly_challenge) +/************************************************* + * Name: mld_poly_challenge + * + * Description: Implementation of H. Samples polynomial with MLDSA_TAU nonzero + * coefficients in {-1,1} using the output stream of + * SHAKE256(seed). + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const uint8_t mu[]: byte array containing seed of length + * MLDSA_CTILDEBYTES + **************************************************/ +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +__contract__( + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CTILDEBYTES)) + assigns(memory_slice(c, sizeof(mld_poly))) + /* All coefficients of c are -1, 0 or +1 */ + ensures(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) +); + +#define mld_polyeta_pack MLD_NAMESPACE_KL(polyeta_pack) +/************************************************* + * Name: mld_polyeta_pack + * + * Description: Bit-pack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYETA_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + assigns(memory_slice(r, MLDSA_POLYETA_PACKEDBYTES)) +); + +/* + * polyeta_unpack produces coefficients in [-MLDSA_ETA,MLDSA_ETA] for + * well-formed inputs (i.e., those produced by polyeta_pack). + * However, when passed an arbitrary byte array, it may produce smaller values, + * i.e, values in [MLD_POLYETA_UNPACK_LOWER_BOUND,MLDSA_ETA] + * Even though this should never happen, we use use the bound for arbitrary + * inputs in the CBMC proofs. + */ +#if MLDSA_ETA == 2 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-5) +#elif MLDSA_ETA == 4 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-11) +#else +#error "Invalid value of MLDSA_ETA" +#endif + +#define mld_polyeta_unpack MLD_NAMESPACE_KL(polyeta_unpack) +/************************************************* + * Name: mld_polyeta_unpack + * + * Description: Unpack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYETA_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)) +); + +#define mld_polyz_pack MLD_NAMESPACE_KL(polyz_pack) +/************************************************* + * Name: mld_polyz_pack + * + * Description: Bit-pack polynomial with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYZ_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(r, MLDSA_POLYZ_PACKEDBYTES)) +); + + +#define mld_polyz_unpack MLD_NAMESPACE_KL(polyz_unpack) +/************************************************* + * Name: mld_polyz_unpack + * + * Description: Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); + +#define mld_polyw1_pack MLD_NAMESPACE_KL(polyw1_pack) +/************************************************* + * Name: mld_polyw1_pack + * + * Description: Bit-pack polynomial w1 with coefficients in [0,15] or [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES)) +); + +#endif /* !MLD_POLY_KL_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/polyvec.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/polyvec.c new file mode 100644 index 0000000000..5c3a08ab32 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/polyvec.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include +#include + +#include "common.h" +#include "debug.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" + +/* This namespacing is not done at the top to avoid a naming conflict + * with native backends, which are currently not yet namespaced. */ +#define mld_polymat_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polymat_permute_bitrev_to_custom) +#define mld_polyvecl_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polyvecl_permute_bitrev_to_custom) +#define mld_polyvecl_pointwise_acc_montgomery_c \ + MLD_ADD_PARAM_SET(mld_polyvecl_pointwise_acc_montgomery_c) + +#if !defined(MLD_CONFIG_REDUCE_RAM) +/* Helper function to ensure that the polynomial entries in the output + * of mld_polyvec_matrix_expand use the standard (bitreversed) ordering + * of coefficients. + * No-op unless a native backend with a custom ordering is used. + */ + +static void mld_polyvecl_permute_bitrev_to_custom(mld_polyvecl *v) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +{ +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + unsigned i; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_permute_bitrev_to_custom(v->vec[i].coeffs); + } +#else /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + /* Nothing to do */ + (void)v; +#endif /* !MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ +} + +static void mld_polymat_permute_bitrev_to_custom(mld_polymat *mat) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; i++) + __loop__( + assigns(i, memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))) + { + mld_polyvecl_permute_bitrev_to_custom(&mat->vec[i]); + } +} +#endif /* !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + unsigned int i; + MLD_ALIGN uint8_t seed_ext[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + mld_memcpy(seed_ext, mat->rho, MLDSA_SEEDBYTES); + + /* Generate row on-demand */ + for (i = 0; i < MLDSA_L; i++) + { + uint8_t x = (uint8_t)row; + uint8_t y = (uint8_t)i; + + seed_ext[MLDSA_SEEDBYTES + 0] = y; + seed_ext[MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(&mat->row_buffer.vec[i], seed_ext); + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + mld_poly_permute_bitrev_to_custom(mat->row_buffer.vec[i].coeffs); +#endif + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); + + return &mat->row_buffer; +#else /* MLD_CONFIG_REDUCE_RAM */ + return &mat->vec[row]; +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + /* In REDUCE_RAM mode, just copy the seed for later on-demand generation */ + mld_memcpy(mat->rho, rho, MLDSA_SEEDBYTES); +#else + unsigned int i, j; + /* + * We generate four separate seed arrays rather than a single one to work + * around limitations in CBMC function contracts dealing with disjoint slices + * of the same parent object. + */ + + MLD_ALIGN uint8_t seed_ext[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + mld_memcpy(seed_ext[j], rho, MLDSA_SEEDBYTES); + } + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + /* Sample 4 matrix entries a time. */ + for (i = 0; i < (MLDSA_K * MLDSA_L / 4) * 4; i += 4) + __loop__( + assigns(i, j, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= (MLDSA_K * MLDSA_L / 4) * 4 && i % 4 == 0) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + uint8_t x = (uint8_t)((i + j) / MLDSA_L); + uint8_t y = (uint8_t)((i + j) % MLDSA_L); + + seed_ext[j][MLDSA_SEEDBYTES + 0] = y; + seed_ext[j][MLDSA_SEEDBYTES + 1] = x; + } + + mld_poly_uniform_4x(&mat->vec[i / MLDSA_L].vec[i % MLDSA_L], + &mat->vec[(i + 1) / MLDSA_L].vec[(i + 1) % MLDSA_L], + &mat->vec[(i + 2) / MLDSA_L].vec[(i + 2) % MLDSA_L], + &mat->vec[(i + 3) / MLDSA_L].vec[(i + 3) % MLDSA_L], + seed_ext); + } +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + i = 0; +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + /* Entries omitted by the batch-sampling are sampled individually. */ + while (i < MLDSA_K * MLDSA_L) + __loop__( + assigns(i, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K * MLDSA_L) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + uint8_t x = (uint8_t)(i / MLDSA_L); + uint8_t y = (uint8_t)(i % MLDSA_L); + mld_poly *this_poly = &mat->vec[i / MLDSA_L].vec[i % MLDSA_L]; + + seed_ext[0][MLDSA_SEEDBYTES + 0] = y; + seed_ext[0][MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(this_poly, seed_ext[0]); + i++; + } + + mld_polymat_permute_bitrev_to_custom(mat); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(t, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + const mld_polyvecl *row = mld_polymat_get_row(mat, i); + mld_polyvecl_pointwise_acc_montgomery(&t->vec[i], row, v); + } + + mld_assert_abs_bound_2d(t->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_L **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; +#endif + + /* Safety: nonce is at most ((UINT16_MAX - MLDSA_L) / MLDSA_L), and, hence, + * this cast is safe. See MLD_NONCE_UB comment in sign.c. */ + nonce = (uint16_t)(MLDSA_L * nonce); + /* Now, nonce <= UINT16_MAX - (MLDSA_L - 1), so the casts below are safe. */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_gamma1(&v->vec[i], seed, (uint16_t)(nonce + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLDSA_L == 4 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); +#elif MLDSA_L == 5 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); + mld_poly_uniform_gamma1(&v->vec[4], seed, (uint16_t)(nonce + 4)); +#elif MLDSA_L == 7 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], + &v->vec[3 /* irrelevant */], seed, nonce, + (uint16_t)(nonce + 1), (uint16_t)(nonce + 2), + 0xFF /* irrelevant */); + mld_poly_uniform_gamma1_4x(&v->vec[3], &v->vec[4], &v->vec[5], &v->vec[6], + seed, (uint16_t)(nonce + 3), (uint16_t)(nonce + 4), + (uint16_t)(nonce + 5), (uint16_t)(nonce + 6)); +#endif /* MLDSA_L == 7 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(k0, i, MLDSA_L, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_STATIC_TESTABLE void mld_polyvecl_pointwise_acc_montgomery_c( + mld_poly *w, const mld_polyvecl *u, const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i, j; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + for (i = 0; i < MLDSA_N; i++) + __loop__( + assigns(i, j, memory_slice(w, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_abs_bound(w->coeffs, 0, i, MLDSA_Q)) + ) + { + int64_t t = 0; + int32_t r; + for (j = 0; j < MLDSA_L; j++) + __loop__( + assigns(j, t) + invariant(j <= MLDSA_L) + invariant(t >= -(int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + invariant(t <= (int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + ) + { + t += (int64_t)u->vec[j].coeffs[i] * v->vec[j].coeffs[i]; + } + + r = mld_montgomery_reduce(t); + w->coeffs[i] = r; + } + + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +{ +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) && \ + MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l4_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) && \ + MLD_CONFIG_PARAMETER_SET == 65 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l5_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) && \ + MLD_CONFIG_PARAMETER_SET == 87 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l7_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 && \ + MLD_CONFIG_PARAMETER_SET == 44) && \ + !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 && \ + MLD_CONFIG_PARAMETER_SET == 65) && \ + MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 && \ + MLD_CONFIG_PARAMETER_SET == 87 */ + /* The first input is bounded by [0, Q-1] inclusive + * The second input is bounded by [-9Q+1, 9Q-1] inclusive . Hence, we can + * safely accumulate in 64-bits without intermediate reductions as + * MLDSA_L * (MLD_NTT_BOUND-1) * (Q-1) < INT64_MAX + * + * The worst case is ML-DSA-87: 7 * (9Q-1) * (Q-1) < 2**52 + * (and likewise for negative values) + */ + mld_polyvecl_pointwise_acc_montgomery_c(w, u, v); +} + +MLD_INTERNAL_API +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + invariant(i <= MLDSA_L) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + return t; +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_K **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k2, 0, i, + array_bound(v->vec[k2].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ) + { + mld_poly_reduce(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_caddq(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, + forall(k1, 0, MLDSA_N, u->vec[k0].coeffs[k1] == loop_entry(*u).vec[k0].coeffs[k1]))) + invariant(forall(k6, 0, i, array_bound(u->vec[k6].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + ) + { + mld_poly_add(&u->vec[i], &v->vec[i]); + } + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(u->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, u->vec[k1].coeffs[n1] == loop_entry(*u).vec[k1].coeffs[n1])))) + { + mld_poly_sub(&u->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, v->vec[k1].coeffs[n1] == loop_entry(*v).vec[k1].coeffs[n1]))) + ) + { + mld_poly_shiftl(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))) + { + mld_poly_invntt_tomont(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_INTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, array_abs_bound(r->vec[k2].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + mld_poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]); + } + mld_assert_abs_bound_2d(r->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + + return t; +} + +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + invariant(forall(k2, 0, i, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) + ) + { + mld_poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +{ + unsigned int i; + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + invariant(forall(k2, 0, i, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) + invariant(forall(k3, i, MLDSA_K, + array_bound(v0->vec[k3].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + ) + { + mld_poly_decompose(&v1->vec[i], &v0->vec[i]); + } + + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + mld_assert_abs_bound_2d(v0->vec, MLDSA_K, MLDSA_N, MLDSA_GAMMA2 + 1); +} + +MLD_INTERNAL_API +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, s, memory_slice(h, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(s <= i * MLDSA_N) + invariant(forall(k1, 0, i, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + s += mld_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]); + } + + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + return s; +} + +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *u, + const mld_polyveck *h) +{ + unsigned int i; + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(w, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)))) + ) + { + mld_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]); + } + + mld_assert_bound_2d(w->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +{ + unsigned int i; + mld_assert_bound_2d(w1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyw1_pack(&r[i * MLDSA_POLYW1_PACKEDBYTES], &w1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt0_pack(&r[i * MLDSA_POLYT0_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyz_unpack(&z->vec[i], r + i * MLDSA_POLYZ_PACKEDBYTES); + } + + mld_assert_bound_2d(z->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt0_unpack(&p->vec[i], r + i * MLDSA_POLYT0_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_polymat_permute_bitrev_to_custom +#undef mld_polyvecl_permute_bitrev_to_custom +#undef mld_polyvecl_pointwise_acc_montgomery_c diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/polyvec.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/polyvec.h new file mode 100644 index 0000000000..d21abc02ff --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/polyvec.h @@ -0,0 +1,725 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLYVEC_H +#define MLD_POLYVEC_H + +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "poly_kl.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_polyvecl MLD_ADD_PARAM_SET(mld_polyvecl) +#define mld_polyveck MLD_ADD_PARAM_SET(mld_polyveck) +#define mld_polymat MLD_ADD_PARAM_SET(mld_polymat) +/* End of parameter set namespacing */ + +/* Vectors of polynomials of length MLDSA_L */ +typedef struct +{ + mld_poly vec[MLDSA_L]; +} mld_polyvecl; + + +#define mld_polyvecl_uniform_gamma1 MLD_NAMESPACE_KL(polyvecl_uniform_gamma1) +/************************************************* + * Name: mld_polyvecl_uniform_gamma1 + * + * Description: Sample vector of polynomials with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_polyvecl *v: pointer to output vector + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + *************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + requires(nonce <= (UINT16_MAX - MLDSA_L) / MLDSA_L) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyvecl_ntt MLD_NAMESPACE_KL(polyvecl_ntt) +/************************************************* + * Name: mld_polyvecl_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_L. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyvecl *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k0, 0, MLDSA_L, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyvecl_pointwise_acc_montgomery \ + MLD_NAMESPACE_KL(polyvecl_pointwise_acc_montgomery) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery + * + * Description: Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * The first input "u" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * + * Arguments: - mld_poly *w: output polynomial + * - const mld_polyvecl *u: pointer to first input vector + * - const mld_polyvecl *v: pointer to second input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + + +#define mld_polyvecl_chknorm MLD_NAMESPACE_KL(polyvecl_chknorm) +/************************************************* + * Name: mld_polyvecl_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_L. + * Assumes input mld_polyvecl to be reduced by polyvecl_reduce(). + * + * Arguments: - const mld_polyvecl *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials is strictly smaller than B <= + * (MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +/* Vectors of polynomials of length MLDSA_K */ +typedef struct +{ + mld_poly vec[MLDSA_K]; +} mld_polyveck; + +/* Matrix of polynomials (K x L) */ +typedef struct +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + mld_polyvecl row_buffer; + uint8_t rho[MLDSA_SEEDBYTES]; +#else + mld_polyvecl vec[MLDSA_K]; +#endif +} mld_polymat; + +#define mld_polyveck_reduce MLD_NAMESPACE_KL(polyveck_reduce) +/************************************************* + * Name: polyveck_reduce + * + * Description: Reduce coefficients of polynomials in vector of length MLDSA_K + * to representatives in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) +); + +#define mld_polyveck_caddq MLD_NAMESPACE_KL(polyveck_caddq) +/************************************************* + * Name: mld_polyveck_caddq + * + * Description: For all coefficients of polynomials in vector of length MLDSA_K + * add MLDSA_Q if coefficient is negative. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_add MLD_NAMESPACE_KL(polyveck_add) +/************************************************* + * Name: mld_polyveck_add + * + * Description: Add vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to input-output vector of polynomials + * to be added to + * - const mld_polyveck *v: pointer to second input vector of + * polynomials + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(p0, 0, MLDSA_K, array_abs_bound(u->vec[p0].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) + requires(forall(p1, 0, MLDSA_K, + array_bound(v->vec[p1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(q2, 0, MLDSA_K, + array_bound(u->vec[q2].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_sub MLD_NAMESPACE_KL(polyveck_sub) +/************************************************* + * Name: mld_polyveck_sub + * + * Description: Subtract vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to first input vector + * - const mld_polyveck *v: pointer to second input vector to be + * subtracted from first input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(u->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_shiftl MLD_NAMESPACE_KL(polyveck_shiftl) +/************************************************* + * Name: mld_polyveck_shiftl + * + * Description: Multiply vector of polynomials of Length MLDSA_K by 2^MLDSA_D + *without modular reduction. Assumes input coefficients to be less than + *2^{31-MLDSA_D}. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_ntt MLD_NAMESPACE_KL(polyveck_ntt) +/************************************************* + * Name: mld_polyveck_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_K. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyveck_invntt_tomont MLD_NAMESPACE_KL(polyveck_invntt_tomont) +/************************************************* + * Name: mld_polyveck_invntt_tomont + * + * Description: Inverse NTT and multiplication by 2^{32} of polynomials + * in vector of length MLDSA_K. + * Input coefficients need to be less than MLDSA_Q, and + * Output coefficients are bounded by MLD_INTT_BOUND. + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) +); + +#define mld_polyveck_pointwise_poly_montgomery \ + MLD_NAMESPACE_KL(polyveck_pointwise_poly_montgomery) +/************************************************* + * Name: mld_polyveck_pointwise_poly_montgomery + * + * Description: Pointwise multiplication of a polynomial vector of length + * MLDSA_K by a single polynomial in NTT domain and multiplication + * of the resulting polynomial vector by 2^{-32}. + * + * Arguments: - mld_polyveck *r: pointer to output vector + * - mld_poly *a: pointer to input polynomial + * - mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(r, sizeof(mld_polyveck))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(r, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(r->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#define mld_polyveck_chknorm MLD_NAMESPACE_KL(polyveck_chknorm) +/************************************************* + * Name: mld_polyveck_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_K. + * Assumes input mld_polyveck to be reduced by polyveck_reduce(). + * + * Arguments: - const mld_polyveck *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials are strictly smaller than B <= + *(MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, + -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +#define mld_polyveck_power2round MLD_NAMESPACE_KL(polyveck_power2round) +/************************************************* + * Name: mld_polyveck_power2round + * + * Description: For all coefficients a of polynomials in vector of length + *MLDSA_K, compute a0, a1 such that a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with + *-2^{MLDSA_D-1} < a0 <= 2^{MLDSA_D-1}. Assumes coefficients to be standard + *representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to output vector of polynomials with + * coefficients a0 + * - const mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) +); + +#define mld_polyveck_decompose MLD_NAMESPACE_KL(polyveck_decompose) +/************************************************* + * Name: mld_polyveck_decompose + * + * Description: For all coefficients a of polynomials in vector of length + * MLDSA_K, compute high and low bits a0, a1 such a mod^+ MLDSA_Q = a1*ALPHA + * + a0 with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (MLDSA_Q-1)/ALPHA where we set + * a1 = 0 and -ALPHA/2 <= a0 = a mod MLDSA_Q - MLDSA_Q < 0. Assumes coefficients + * to be standard representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to input/output vector of + * polynomials with. Output polynomial has + * coefficients a0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v0->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + ensures(forall(k2, 0, MLDSA_K, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) +); + +#define mld_polyveck_make_hint MLD_NAMESPACE_KL(polyveck_make_hint) +/************************************************* + * Name: mld_polyveck_make_hint + * + * Description: Compute hint vector. + * + * Arguments: - mld_polyveck *h: pointer to output vector + * - const mld_polyveck *v0: pointer to low part of input vector + * - const mld_polyveck *v1: pointer to high part of input vector + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(return_value <= MLDSA_N * MLDSA_K) + ensures(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) +); + +#define mld_polyveck_use_hint MLD_NAMESPACE_KL(polyveck_use_hint) +/************************************************* + * Name: mld_polyveck_use_hint + * + * Description: Use hint vector to correct the high bits of input vector. + * + * Arguments: - mld_polyveck *w: pointer to output vector of polynomials with + * corrected high bits + * - const mld_polyveck *u: pointer to input vector + * - const mld_polyveck *h: pointer to input hint vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *v, + const mld_polyveck *h) +__contract__( + requires(memory_no_alias(w, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + assigns(memory_slice(w, sizeof(mld_polyveck))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) +); + +#define mld_polyveck_pack_w1 MLD_NAMESPACE_KL(polyveck_pack_w1) +/************************************************* + * Name: mld_polyveck_pack_w1 + * + * Description: Bit-pack polynomial vector w1 with coefficients in [0,15] or + * [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_K* MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_polyveck *a: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(w1, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(w1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) +); + +#define mld_polyveck_pack_eta MLD_NAMESPACE_KL(polyveck_pack_eta) +/************************************************* + * Name: mld_polyveck_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients + * in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyvecl_pack_eta MLD_NAMESPACE_KL(polyvecl_pack_eta) +/************************************************* + * Name: mld_polyvecl_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_L * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyveck_pack_t0 MLD_NAMESPACE_KL(polyveck_pack_t0) +/************************************************* + * Name: mld_polyveck_pack_t0 + * + * Description: Bit-pack polynomial vector to with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(p->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) +); + +#define mld_polyvecl_unpack_eta MLD_NAMESPACE_KL(polyvecl_unpack_eta) +/************************************************* + * Name: mld_polyvecl_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyvecl *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + assigns(memory_slice(p, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyvecl_unpack_z MLD_NAMESPACE_KL(polyvecl_unpack_z) +/************************************************* + * Name: mld_polyvecl_unpack_z + * + * Description: Unpack polynomial vector with coefficients in + * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_polyvecl *z: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(z->vec[k1].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyveck_unpack_eta MLD_NAMESPACE_KL(polyveck_unpack_eta) +/************************************************* + * Name: mld_polyveck_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyveck_unpack_t0 MLD_NAMESPACE_KL(polyveck_unpack_t0) +/************************************************* + * Name: mld_polyveck_unpack_t0 + * + * Description: Unpack polynomial vector with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) +); + +#define mld_polymat_get_row MLD_NAMESPACE_KL(polymat_get_row) +/************************************************* + * Name: mld_polymat_get_row + * + * Description: Retrieve a pointer to a specific row of the matrix. + * In MLD_CONFIG_REDUCE_RAM mode, generates the row on-demand. + * + * Arguments: - mld_polymat *mat: pointer to matrix + * - unsigned int row: row index (must be < MLDSA_K) + * + * Returns pointer to the row (mld_polyvecl) + **************************************************/ +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row); + +#define mld_polyvec_matrix_expand MLD_NAMESPACE_KL(polyvec_matrix_expand) +/************************************************* + * Name: mld_polyvec_matrix_expand + * + * Description: Implementation of ExpandA. Generates matrix A with uniformly + * random coefficients a_{i,j} by performing rejection + * sampling on the output stream of SHAKE128(rho|j|i) + * + * Arguments: - mld_polymat *mat: pointer to output matrix + * - const uint8_t rho[]: byte array containing seed rho + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +__contract__( + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +); + + + +#define mld_polyvec_matrix_pointwise_montgomery \ + MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery) +/************************************************* + * Name: mld_polyvec_matrix_pointwise_montgomery + * + * Description: Compute matrix-vector multiplication in NTT domain with + * pointwise multiplication and multiplication by 2^{-32}. + * Input matrix and vector must be in NTT domain representation. + * + * The first input "mat" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * Note: In MLD_CONFIG_REDUCE_RAM mode, mat cannot be const + * as rows are generated on-demand. + * + * Arguments: - mld_polyveck *t: pointer to output vector t + * - mld_polymat *mat: pointer to input matrix + * - const mld_polyvecl *v: pointer to input vector v + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(t, sizeof(mld_polyveck))) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(t, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#endif /* !MLD_POLYVEC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/randombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/randombytes.h new file mode 100644 index 0000000000..da55772419 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/randombytes.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_RANDOMBYTES_H +#define MLD_RANDOMBYTES_H + +#include +#include + +#include "cbmc.h" +#include "common.h" + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +#if !defined(MLD_CONFIG_CUSTOM_RANDOMBYTES) +MLD_MUST_CHECK_RETURN_VALUE +int randombytes(uint8_t *out, size_t outlen); +static MLD_INLINE int mld_randombytes(uint8_t *out, size_t outlen) +__contract__( + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) { return randombytes(out, outlen); } +#endif /* !MLD_CONFIG_CUSTOM_RANDOMBYTES */ +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ +#endif /* !MLD_RANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/reduce.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/reduce.h new file mode 100644 index 0000000000..413cf1829e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/reduce.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_REDUCE_H +#define MLD_REDUCE_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* check-magic: -4186625 == pow(2,32,MLDSA_Q) */ +#define MLD_MONT -4186625 + +/* Upper bound for domain of mld_reduce32() */ +#define MLD_REDUCE32_DOMAIN_MAX (INT32_MAX - (1 << 22)) + +/* Absolute bound for range of mld_reduce32() */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define MLD_REDUCE32_RANGE_MAX 6283009 + +/************************************************* + * Name: mld_montgomery_reduce + * + * Description: Generic Montgomery reduction; given a 64-bit integer a, computes + * 32-bit integer congruent to a * R^-1 mod q, where R=2^32 + * + * Arguments: - int64_t a: input integer to be reduced, of absolute value + * smaller or equal to INT64_MAX - 2^31 * MLDSA_Q. + * + * Returns: Integer congruent to a * R^-1 modulo q, with absolute value + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * In particular, if |a| < 2^31 * MLDSA_Q, the absolute value + * of the return value is < MLDSA_Q. + **************************************************/ +static MLD_INLINE int32_t mld_montgomery_reduce(int64_t a) +__contract__( + /* We don't attempt to express an input-dependent output bound + * as the post-condition here, as all call-sites satisfy the + * absolute input bound 2^31 * MLDSA_Q and higher-level + * reasoning can be conducted using |return_value| < MLDSA_Q. */ + requires(a > -(((int64_t)1 << 31) * MLDSA_Q) && + a < (((int64_t)1 << 31) * MLDSA_Q)) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* check-magic: 58728449 == unsigned_mod(pow(MLDSA_Q, -1, 2^32), 2^32) */ + const uint64_t QINV = 58728449; + + /* Compute a*q^{-1} mod 2^32 in unsigned representatives */ + const uint32_t a_reduced = mld_cast_int64_to_uint32(a); + const uint32_t a_inverted = (a_reduced * QINV) & UINT32_MAX; + + /* Lift to signed canonical representative mod 2^32. */ + const int32_t t = mld_cast_uint32_to_int32(a_inverted); + + int64_t r; + + mld_assert(a < +(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)) && + a > -(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q))); + + r = a - (int64_t)t * MLDSA_Q; + + /* + * PORTABILITY: Right-shift on a signed integer is, strictly-speaking, + * implementation-defined for negative left argument. Here, + * we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5)) + */ + r = r >> 32; + + /* Bounds: + * + * By construction of the Montgomery multiplication, by the time we + * compute r >> 32, r is divisible by 2^32, and hence + * + * |r >> 32| = |r| / 2^32 + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * (In general, we would only have |x >> n| <= ceil(|x| / 2^n)). + * + * In particular, if |a| < 2^31 * MLDSA_Q, then |return_value| < MLDSA_Q. + */ + return (int32_t)r; +} + +/************************************************* + * Name: mld_reduce32 + * + * Description: For finite field element a with a <= 2^{31} - 2^{22} - 1, + * compute r \equiv a (mod MLDSA_Q) such that + * -MLD_REDUCE32_RANGE_MAX <= r < MLD_REDUCE32_RANGE_MAX. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_reduce32(int32_t a) +__contract__( + requires(a <= MLD_REDUCE32_DOMAIN_MAX) + ensures(return_value >= -MLD_REDUCE32_RANGE_MAX) + ensures(return_value < MLD_REDUCE32_RANGE_MAX) +) +{ + int32_t t; + + t = (a + (1 << 22)) >> 23; + t = a - t * MLDSA_Q; + mld_assert((t - a) % MLDSA_Q == 0); + return t; +} + +/************************************************* + * Name: mld_caddq + * + * Description: Add MLDSA_Q if input coefficient is negative. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_caddq(int32_t a) +__contract__( + requires(a > -MLDSA_Q) + requires(a < MLDSA_Q) + ensures(return_value >= 0) + ensures(return_value < MLDSA_Q) + ensures(return_value == (a >= 0) ? a : (a + MLDSA_Q)) +) +{ + return mld_ct_sel_int32(a + MLDSA_Q, a, mld_ct_cmask_neg_i32(a)); +} + + +#endif /* !MLD_REDUCE_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/rounding.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/rounding.h new file mode 100644 index 0000000000..a83562b0f1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/rounding.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_ROUNDING_H +#define MLD_ROUNDING_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_power2round MLD_ADD_PARAM_SET(mld_power2round) +#define mld_decompose MLD_ADD_PARAM_SET(mld_decompose) +#define mld_make_hint MLD_ADD_PARAM_SET(mld_make_hint) +#define mld_use_hint MLD_ADD_PARAM_SET(mld_use_hint) +/* End of parameter set namespacing */ + +#define MLD_2_POW_D (1 << MLDSA_D) + +/************************************************* + * Name: mld_power2round + * + * Description: For finite field element a, compute a0, a1 such that + * a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with -2^{MLDSA_D-1} < a0 <= + * 2^{MLDSA_D-1}. Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: In the reference implementation, a1 is passed as a + * return value instead. + **************************************************/ +static MLD_INLINE void mld_power2round(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + ensures(*a0 > -(MLD_2_POW_D/2) && *a0 <= (MLD_2_POW_D/2)) + ensures(*a1 >= 0 && *a1 <= (MLDSA_Q - 1) / MLD_2_POW_D) + ensures((*a1 * MLD_2_POW_D + *a0 - a) % MLDSA_Q == 0) +) +{ + *a1 = (a + (1 << (MLDSA_D - 1)) - 1) >> MLDSA_D; + *a0 = a - (*a1 << MLDSA_D); +} + +/************************************************* + * Name: mld_decompose + * + * Description: For finite field element a, compute high and low bits a0, a1 + * such that a mod^+ MLDSA_Q = a1* 2 * MLDSA_GAMMA2 + a0 with + * -MLDSA_GAMMA2 < a0 <= MLDSA_GAMMA2 except + * if a1 = (MLDSA_Q-1)/(MLDSA_GAMMA2*2) where we set a1 = 0 and + * -MLDSA_GAMMA2 <= a0 = a mod^+ MLDSA_Q - MLDSA_Q < 0. + * Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: a1 is passed as a return value instead + **************************************************/ +static MLD_INLINE void mld_decompose(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + /* a0 = -MLDSA_GAMMA2 can only occur when (q-1) = a - (a mod MLDSA_GAMMA2), + * then a1=1; and a0 = a - (a mod MLDSA_GAMMA2) - 1 (@[FIPS204, Algorithm 36 (Decompose)]) */ + ensures(*a0 >= -MLDSA_GAMMA2 && *a0 <= MLDSA_GAMMA2) + ensures(*a1 >= 0 && *a1 < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) + ensures((*a1 * 2 * MLDSA_GAMMA2 + *a0 - a) % MLDSA_Q == 0) +) +{ + /* + * The goal is to compute f1 = round-(f / (2*GAMMA2)), which can be computed + * alternatively as round-(f / (128B)) = round-(ceil(f / 128) / B) where + * B = 2*GAMMA2 / 128. Here round-() denotes "round half down". + * + * The equality round-(f / (128B)) = round-(ceil(f / 128) / B) can deduced + * as follows. Since changing f to align-up(f, 128) can move f onto but not + * across a rounding boundary for division by 128*B (note that we need B to be + * even for this to work), and round- rounds down on the boundary, we have + * + * round-(f / (128B)) = round-(align-up(f, 128) / (128B)) + * = round-((align-up(f, 128) / 128) / B) + * = round-(ceil(f / 128) / B). + */ + *a1 = (a + 127) >> 7; + /* We know a >= 0 and a < MLDSA_Q, so... */ + /* check-magic: 65472 == round((MLDSA_Q-1)/128) */ + mld_assert(*a1 >= 0 && *a1 <= 65472); + +#if MLD_CONFIG_PARAMETER_SET == 44 + /* check-magic: 1488 == 2 * intdiv(intdiv(MLDSA_Q - 1, 88), 128) */ + /* check-magic: 11275 == floor(2**24 / 1488) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + */ + *a1 = (*a1 * 11275 + (1 << 23)) >> 24; + mld_assert(*a1 >= 0 && *a1 <= 44); + + *a1 = mld_ct_sel_int32(0, *a1, mld_ct_cmask_neg_i32(43 - *a1)); + mld_assert(*a1 >= 0 && *a1 <= 43); +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + /* check-magic: 4092 == 2 * intdiv(intdiv(MLDSA_Q - 1, 32), 128) */ + /* check-magic: 1025 == floor(2**22 / 4092) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + */ + *a1 = (*a1 * 1025 + (1 << 21)) >> 22; + mld_assert(*a1 >= 0 && *a1 <= 16); + + *a1 &= 15; + mld_assert(*a1 >= 0 && *a1 <= 15); + +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + + *a0 = a - *a1 * 2 * MLDSA_GAMMA2; + *a0 = mld_ct_sel_int32(*a0 - MLDSA_Q, *a0, + mld_ct_cmask_neg_i32((MLDSA_Q - 1) / 2 - *a0)); +} + +/************************************************* + * Name: mld_make_hint + * + * Description: Compute hint bit indicating whether the low bits of the + * input element overflow into the high bits. + * + * Arguments: - int32_t a0: low bits of input element + * - int32_t a1: high bits of input element + * + * Returns 1 if overflow, 0 otherwise + **************************************************/ +static MLD_INLINE unsigned int mld_make_hint(int32_t a0, int32_t a1) +__contract__( + ensures(return_value >= 0 && return_value <= 1) +) +{ + if (a0 > MLDSA_GAMMA2 || a0 < -MLDSA_GAMMA2 || + (a0 == -MLDSA_GAMMA2 && a1 != 0)) + { + return 1; + } + + return 0; +} + +/************************************************* + * Name: mld_use_hint + * + * Description: Correct high bits according to hint. + * + * Arguments: - int32_t a: input element + * - int32_t hint: hint bit + * + * Returns corrected high bits. + **************************************************/ +static MLD_INLINE int32_t mld_use_hint(int32_t a, int32_t hint) +__contract__( + requires(hint >= 0 && hint <= 1) + requires(a >= 0 && a < MLDSA_Q) + ensures(return_value >= 0 && return_value < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) +) +{ + int32_t a0, a1; + + mld_decompose(&a0, &a1, a); + if (hint == 0) + { + return a1; + } + +#if MLD_CONFIG_PARAMETER_SET == 44 + if (a0 > 0) + { + return (a1 == 43) ? 0 : a1 + 1; + } + else + { + return (a1 == 0) ? 43 : a1 - 1; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + if (a0 > 0) + { + return (a1 + 1) & 15; + } + else + { + return (a1 - 1) & 15; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + + +#endif /* !MLD_ROUNDING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/sign.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/sign.c new file mode 100644 index 0000000000..32bba52d65 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/sign.c @@ -0,0 +1,1508 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [Round3_Spec] + * CRYSTALS-Dilithium Algorithm Specifications and Supporting Documentation + * (Version 3.1) + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf + */ + +#include +#include + +#include "cbmc.h" +#include "ct.h" +#include "debug.h" +#include "packing.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" +#include "randombytes.h" +#include "sign.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_check_pct MLD_ADD_PARAM_SET(mld_check_pct) MLD_CONTEXT_PARAMETERS_2 +#define mld_sample_s1_s2 MLD_ADD_PARAM_SET(mld_sample_s1_s2) +#define mld_validate_hash_length MLD_ADD_PARAM_SET(mld_validate_hash_length) +#define mld_get_hash_oid MLD_ADD_PARAM_SET(mld_get_hash_oid) +#define mld_H MLD_ADD_PARAM_SET(mld_H) +#define mld_compute_pack_z MLD_ADD_PARAM_SET(mld_compute_pack_z) +#define mld_attempt_signature_generation \ + MLD_ADD_PARAM_SET(mld_attempt_signature_generation) MLD_CONTEXT_PARAMETERS_8 +#define mld_compute_t0_t1_tr_from_sk_components \ + MLD_ADD_PARAM_SET(mld_compute_t0_t1_tr_from_sk_components) \ + MLD_CONTEXT_PARAMETERS_7 +/* End of parameter set namespacing */ + + +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + ensures(return_value == 0 + || return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL) +); + +#if defined(MLD_CONFIG_KEYGEN_PCT) +/************************************************* + * @[FIPS140_3_IG] + * (https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf) + * + * TE10.35.02: Pair-wise Consistency Test (PCT) for DSA keypairs + * + * Purpose: Validates that a generated public/private key pair can correctly + * sign and verify data. Test performs signature generation using the private + * key (sk), followed by signature verification using the public key (pk). + * Returns 0 if the signature was successfully verified, non-zero if it cannot. + * + * Note: @[FIPS204] requires that public/private key pairs are to be used only + * for the calculation and/of verification of digital signatures. + **************************************************/ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t message[1] = {0}; + size_t siglen; + int ret; + MLD_ALLOC(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + MLD_ALLOC(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + + if (signature == NULL || pk_test == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Copy public key for testing */ + mld_memcpy(pk_test, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* Sign a test message using the original secret key */ + ret = mld_sign_signature(signature, &siglen, message, sizeof(message), NULL, + 0, sk, context); + if (ret != 0) + { + goto cleanup; + } + +#if defined(MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST) + /* Deliberately break public key for testing purposes */ + if (mld_break_pct()) + { + pk_test[0] = ~pk_test[0]; + } +#endif /* MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST */ + + /* Verify the signature using the (potentially corrupted) public key */ + ret = mld_sign_verify(signature, siglen, message, sizeof(message), NULL, 0, + pk_test, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + MLD_FREE(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + + return ret; +} +#else /* MLD_CONFIG_KEYGEN_PCT */ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + /* Skip PCT */ + ((void)pk); + ((void)sk); +#if defined(MLD_CONFIG_CONTEXT_PARAMETER) + ((void)context); +#endif + return 0; +} +#endif /* !MLD_CONFIG_KEYGEN_PCT */ + +static void mld_sample_s1_s2(mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t seed[MLDSA_CRHBYTES]) +__contract__( + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(object_whole(s1), object_whole(s2)) + ensures(forall(l0, 0, MLDSA_L, array_abs_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + ensures(forall(k0, 0, MLDSA_K, array_abs_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) +) +{ +/* Sample short vectors s1 and s2 */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; + uint16_t nonce = 0; + /* Safety: The nonces are at most 14 (MLDSA_L + MLDSA_K - 1), and, hence, the + * casts are safe. */ + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_eta(&s1->vec[i], seed, (uint8_t)(nonce + i)); + } + for (i = 0; i < MLDSA_K; i++) + { + mld_poly_uniform_eta(&s2->vec[i], seed, (uint8_t)(nonce + MLDSA_L + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLD_CONFIG_PARAMETER_SET == 44 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 4, 5, 6, 7); +#elif MLD_CONFIG_PARAMETER_SET == 65 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s2->vec[0], &s2->vec[1], + &s2->vec[2] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[2], &s2->vec[3], &s2->vec[4], &s2->vec[5], + seed, 7, 8, 9, 10); +#elif MLD_CONFIG_PARAMETER_SET == 87 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s1->vec[5], &s1->vec[6], + &s2->vec[0] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 7, 8, 9, 10); + mld_poly_uniform_eta_4x(&s2->vec[4], &s2->vec[5], &s2->vec[6], &s2->vec[7], + seed, 11, 12, 13, 14); +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ +} + +/************************************************* + * Name: mld_compute_t0_t1_tr_from_sk_components + * + * Description: Computes t0, t1, tr, and pk from secret key components + * rho, s1, s2. This is the shared computation used by + * both keygen and generating the public key from the + * secret key. + * + * Arguments: - mld_polyveck *t0: output t0 + * - mld_polyveck *t1: output t1 + * - uint8_t tr[MLDSA_TRBYTES]: output tr + * - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t rho[MLDSA_SEEDBYTES]: input rho + * - const mld_polyvecl *s1: input s1 + * - const mld_polyveck *s2: input s2 + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_t0_t1_tr_from_sk_components( + mld_polyveck *t0, mld_polyveck *t1, uint8_t tr[MLDSA_TRBYTES], + uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], const uint8_t rho[MLDSA_SEEDBYTES], + const mld_polyvecl *s1, const mld_polyveck *s2, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(l0, 0, MLDSA_L, array_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + requires(forall(k0, 0, MLDSA_K, array_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(forall(k1, 0, MLDSA_K, array_bound(t0->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(t1->vec[k2].coeffs, 0, MLDSA_N, 0, 1 << 10))) + ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY)) +{ + int ret; + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1hat, mld_polyvecl, 1, context); + MLD_ALLOC(t, mld_polyveck, 1, context); + + if (mat == NULL || s1hat == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Expand matrix */ + mld_polyvec_matrix_expand(mat, rho); + + /* Matrix-vector multiplication */ + *s1hat = *s1; + mld_polyvecl_ntt(s1hat); + mld_polyvec_matrix_pointwise_montgomery(t, mat, s1hat); + mld_polyveck_invntt_tomont(t); + + /* Add error vector s2 */ + mld_polyveck_add(t, s2); + + /* Reference: The following reduction is not present in the reference + * implementation. Omitting this reduction requires the output of + * the invntt to be small enough such that the addition of s2 does + * not result in absolute values >= MLDSA_Q. While our C, x86_64, + * and AArch64 invntt implementations produce small enough + * values for this to work out, it complicates the bounds + * reasoning. We instead add an additional reduction, and can + * consequently, relax the bounds requirements for the invntt. + */ + mld_polyveck_reduce(t); + + /* Decompose to get t1, t0 */ + mld_polyveck_caddq(t); + mld_polyveck_power2round(t1, t0, t); + + /* Pack public key and compute tr */ + mld_pack_pk(pk, rho, t1); + mld_shake256(tr, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + ret = 0; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_polyveck, 1, context); + MLD_FREE(s1hat, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + const uint8_t *rho, *rhoprime, *key; + MLD_ALLOC(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + MLD_ALLOC(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + + if (seedbuf == NULL || inbuf == NULL || tr == NULL || s1 == NULL || + s2 == NULL || t1 == NULL || t0 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Get randomness for rho, rhoprime and key */ + mld_memcpy(inbuf, seed, MLDSA_SEEDBYTES); + inbuf[MLDSA_SEEDBYTES + 0] = MLDSA_K; + inbuf[MLDSA_SEEDBYTES + 1] = MLDSA_L; + mld_shake256(seedbuf, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, inbuf, + MLDSA_SEEDBYTES + 2); + rho = seedbuf; + rhoprime = rho + MLDSA_SEEDBYTES; + key = rhoprime + MLDSA_CRHBYTES; + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + + /* Sample s1 and s2 */ + mld_sample_s1_s2(s1, s2, rhoprime); + + /* Compute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0, t1, tr, pk, rho, s1, s2, + context); + if (ret != 0) + { + goto cleanup; + } + + /* Pack secret key */ + mld_pack_sk(sk, rho, tr, key, t0, s1, s2); + + /* Constant time: pk is the public key, inherently public data */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_FREE(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + + if (ret != 0) + { + return ret; + } + + /* Pairwise Consistency Test (PCT) @[FIPS140_3_IG, p.87] */ + /* Do this after freeing all temporaries. */ + return mld_check_pct(pk, sk, context); +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t seed[MLDSA_SEEDBYTES]; + int ret; + if (mld_randombytes(seed, MLDSA_SEEDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(seed, sizeof(seed)); + ret = mld_sign_keypair_internal(pk, sk, seed, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed, sizeof(seed)); + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +/************************************************* + * Name: mld_H + * + * Description: Abstracts application of SHAKE256 to + * one, two or three blocks of data, + * yielding a user-requested size of + * output. + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in1: pointer to input block 1 + * Must NOT be NULL + * - size_t in1len: length of input in1 bytes + * - const uint8_t *in2: pointer to input block 2 + * May be NULL if in2len=0, in which case + * this block is ignored + * - size_t in2len: length of input in2 bytes + * - const uint8_t *in3: pointer to input block 3 + * May be NULL if in3len=0, in which case + * this block is ignored + * - size_t in3len: length of input in3 bytes + **************************************************/ +static void mld_H(uint8_t *out, size_t outlen, const uint8_t *in1, + size_t in1len, const uint8_t *in2, size_t in2len, + const uint8_t *in3, size_t in3len) +__contract__( + requires(in1len <= MLD_MAX_BUFFER_SIZE) + requires(in2len <= MLD_MAX_BUFFER_SIZE) + requires(in3len <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in1, in1len)) + requires(in2len == 0 || memory_no_alias(in2, in2len)) + requires(in3len == 0 || memory_no_alias(in3, in3len)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) +{ + mld_shake256ctx state; + mld_shake256_init(&state); + mld_shake256_absorb(&state, in1, in1len); + if (in2len != 0) + { + mld_shake256_absorb(&state, in2, in2len); + } + if (in3len != 0) + { + mld_shake256_absorb(&state, in3, in3len); + } + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(&state, sizeof(state)); +} + +/************************************************* + * Name: mld_compute_pack_z + * + * Description: Computes z = y + s1*c, checks that z has coefficients smaller + * than MLDSA_GAMMA1 - MLDSA_BETA, and packs z into the + * signature buffer. + * + * Arguments: - uint8_t *sig: output signature + * - const mld_poly *cp: challenge polynomial + * - const polyvecl *s1: secret vector s1 + * - const polyvecl *y: masking vector y + * + * Returns: - 0: Success (z has coefficients smaller than + * MLDSA_GAMMA1 - MLDSA_BETA,) + * - MLD_ERR_FAIL: z rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This function is inlined into mld_sign_signature in the + * reference implementation. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_pack_z(uint8_t sig[MLDSA_CRYPTO_BYTES], + const mld_poly *cp, const mld_polyvecl *s1, + const mld_polyvecl *y, mld_poly *z) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(cp, sizeof(mld_poly))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(y, sizeof(mld_polyvecl))) + requires(memory_no_alias(z, sizeof(mld_poly))) + requires(array_abs_bound(cp->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_L, + array_bound(y->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + requires(forall(k1, 0, MLDSA_L, array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(memory_slice(z, sizeof(mld_poly))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int i; + uint32_t z_invalid; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(z, sizeof(mld_poly)), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_poly_pointwise_montgomery(z, cp, &s1->vec[i]); + mld_poly_invntt_tomont(z); + mld_poly_add(z, &y->vec[i]); + mld_poly_reduce(z); + + z_invalid = mld_poly_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA); + /* Constant time: It is fine (and prohibitively expensive to avoid) + * to leak the result of the norm check and which polynomial in z caused a + * rejection. It would even be okay to leak which coefficient led to + * rejection as the candidate signature will be discarded anyway. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(&z_invalid, sizeof(uint32_t)); + if (z_invalid) + { + return MLD_ERR_FAIL; /* reject */ + } + /* If z is valid, then its coefficients are bounded by + * MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below + * to prove the pre-condition of pack_sig_z() */ + mld_assert_abs_bound(z, MLDSA_N, (MLDSA_GAMMA1 - MLDSA_BETA)); + + /* After the norm check, the distribution of each coefficient of z is + * independent of the secret key and it can, hence, be considered + * public. It is, hence, okay to immediately pack it into the user-provided + * signature buffer. */ + mld_pack_sig_z(sig, z, i); + } + return 0; +} + +/* Reference: The reference implementation does not explicitly check the + * maximum nonce value, but instead loops indefinitely (even when the nonce + * would overflow). Internally, sampling of y uses + * (nonceL), (nonceL+1), ... (nonce*L+L-1). + * Hence, there are no overflows if nonce < (UINT16_MAX - L)/L. + * Explicitly checking for this explicitly allows us to prove type-safety. + * Note that FIPS204 explicitly allows an upper-bound this loop of + * 814 (< (UINT16_MAX - L)/L) - see @[FIPS204, Appendix C]. */ +#define MLD_NONCE_UB ((UINT16_MAX - MLDSA_L) / MLDSA_L) + +/************************************************* + * Name: attempt_signature_generation + * + * Description: Attempts to generate a single signature. + * + * Arguments: - uint8_t *sig: pointer to output signature + * - const uint8_t *mu: pointer to message or hash + * of exactly MLDSA_CRHBYTES bytes + * - const uint8_t *rhoprime: pointer to randomness seed + * - uint16_t nonce: current nonce value + * - const mld_polymat *mat: expanded matrix + * - const polyvecl *s1: secret vector s1 + * - const polyveck *s2: secret vector s2 + * - const polyveck *t0: vector t0 + * + * Returns: - 0: Signature generation succeeded + * - MLD_ERR_FAIL: Signature rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This code differs from the reference implementation + * in that it factors out the core signature generation + * step into a distinct function here in order to improve + * efficiency of CBMC proof. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_attempt_signature_generation( + uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *mu, + const uint8_t rhoprime[MLDSA_CRHBYTES], uint16_t nonce, mld_polymat *mat, + const mld_polyvecl *s1, const mld_polyveck *s2, const mld_polyveck *t0, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(rhoprime, MLDSA_CRHBYTES)) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(nonce <= MLD_NONCE_UB) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int n; + uint32_t w0_invalid, h_invalid; + int ret; + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyvecl y; + mld_polyveck h; + } + yh_u; + mld_polyvecl *y; + mld_polyveck *h; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck w1; + mld_polyvecl tmp; + } + w1tmp_u; + mld_polyveck *w1; + mld_polyvecl *tmp; + + MLD_ALLOC(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(yh, yh_u, 1, context); + MLD_ALLOC(z, mld_poly, 1, context); + MLD_ALLOC(w1tmp, w1tmp_u, 1, context); + MLD_ALLOC(w0, mld_polyveck, 1, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(t, mld_poly, 1, context); + + if (challenge_bytes == NULL || yh == NULL || z == NULL || w1tmp == NULL || + w0 == NULL || cp == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + y = &yh->y; + h = &yh->h; + w1 = &w1tmp->w1; + tmp = &w1tmp->tmp; + + /* Sample intermediate vector y */ + mld_polyvecl_uniform_gamma1(y, rhoprime, nonce); + + /* Matrix-vector multiplication */ + *tmp = *y; + mld_polyvecl_ntt(tmp); + mld_polyvec_matrix_pointwise_montgomery(w0, mat, tmp); + mld_polyveck_invntt_tomont(w0); + + /* Decompose w and call the random oracle */ + mld_polyveck_caddq(w0); + mld_polyveck_decompose(w1, w0); + mld_polyveck_pack_w1(sig, w1); + + mld_H(challenge_bytes, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, sig, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + /* Constant time: Leaking challenge_bytes does not reveal any information + * about the secret key as H() is modelled as random oracle. + * This also applies to challenges for rejected signatures. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(challenge_bytes, MLDSA_CTILDEBYTES); + mld_poly_challenge(cp, challenge_bytes); + mld_poly_ntt(cp); + + /* Compute z, reject if it reveals secret */ + ret = mld_compute_pack_z(sig, cp, s1, y, t); + if (ret) + { + goto cleanup; + } + + /* Check that subtracting cs2 does not change high bits of w and low bits + * do not reveal secret information */ + mld_polyveck_pointwise_poly_montgomery(h, cp, s2); + mld_polyveck_invntt_tomont(h); + mld_polyveck_sub(w0, h); + mld_polyveck_reduce(w0); + + w0_invalid = mld_polyveck_chknorm(w0, MLDSA_GAMMA2 - MLDSA_BETA); + /* Constant time: w0_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&w0_invalid, sizeof(uint32_t)); + if (w0_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* Compute hints for w1 */ + mld_polyveck_pointwise_poly_montgomery(h, cp, t0); + mld_polyveck_invntt_tomont(h); + mld_polyveck_reduce(h); + + h_invalid = mld_polyveck_chknorm(h, MLDSA_GAMMA2); + /* Constant time: h_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&h_invalid, sizeof(uint32_t)); + if (h_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + mld_polyveck_add(w0, h); + + /* Constant time: At this point all norm checks have passed and we, hence, + * know that the signature does not leak any secret information. + * Consequently, any value that can be computed from the signature and public + * key is considered public. + * w0 and w1 are public as they can be computed from Az - ct = \alpha w1 + w0. + * h=c*t0 is public as both c and t0 are public. + * For a more detailed discussion, refer to https://eprint.iacr.org/2022/1406. + */ + MLD_CT_TESTING_DECLASSIFY(w0, sizeof(*w0)); + MLD_CT_TESTING_DECLASSIFY(w1, sizeof(*w1)); + n = mld_polyveck_make_hint(h, w0, w1); + if (n > MLDSA_OMEGA) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* All is well - write signature */ + mld_pack_sig_c_h(sig, challenge_bytes, h, n); + /* Constant time: At this point it is clear that the signature is valid - it + * can, hence, be considered public. */ + MLD_CT_TESTING_DECLASSIFY(sig, MLDSA_CRYPTO_BYTES); + ret = 0; /* success */ + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_poly, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(w0, mld_polyveck, 1, context); + MLD_FREE(w1tmp, w1tmp_u, 1, context); + MLD_FREE(z, mld_poly, 1, context); + MLD_FREE(yh, yh_u, 1, context); + MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + + return ret; +} +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + uint8_t *rho, *tr, *key, *mu, *rhoprime; + uint16_t nonce = 0; + MLD_ALLOC(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + + if (seedbuf == NULL || mat == NULL || s1 == NULL || t0 == NULL || s2 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + rho = seedbuf; + tr = rho + MLDSA_SEEDBYTES; + key = tr + MLDSA_TRBYTES; + mu = key + MLDSA_SEEDBYTES; + rhoprime = mu + MLDSA_CRHBYTES; + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + if (!externalmu) + { + /* Compute mu = CRH(tr, pre, msg) */ + mld_H(mu, MLDSA_CRHBYTES, tr, MLDSA_TRBYTES, pre, prelen, m, mlen); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Compute rhoprime = CRH(key, rnd, mu) */ + mld_H(rhoprime, MLDSA_CRHBYTES, key, MLDSA_SEEDBYTES, rnd, MLDSA_RNDBYTES, mu, + MLDSA_CRHBYTES); + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + /* Expand matrix and transform vectors */ + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(s1); + mld_polyveck_ntt(s2); + mld_polyveck_ntt(t0); + + /* By default, return failure. Flip to success and write output + * once signature generation succeeds. */ + ret = MLD_ERR_FAIL; + + /* Reference: This code is re-structured using a while(1), */ + /* with explicit "continue" statements (rather than "goto") */ + /* to implement rejection of invalid signatures. */ + while (1) + __loop__( + assigns(nonce, ret, object_whole(siglen), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(nonce <= MLD_NONCE_UB) + + /* t0, s1, s2, and mat are initialized above and are NOT changed by this */ + /* loop. We can therefore re-assert their bounds here as part of the */ + /* loop invariant. This makes proof noticeably faster with CBMC */ + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + invariant(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(ret == MLD_ERR_FAIL) + ) + { + /* Reference: this code explicitly checks for exhaustion of nonce */ + /* values to provide predictable termination and results in that case */ + /* Checking here also means that incrementing nonce below can also */ + /* be proven to be type-safe. */ + if (nonce == MLD_NONCE_UB) + { + /* Note that ret == MLD_ERR_FAIL by default, so we + * don't need to set it here. */ + break; + } + + ret = mld_attempt_signature_generation(sig, mu, rhoprime, nonce, mat, s1, + s2, t0, context); + nonce++; + if (ret == 0) + { + *siglen = MLDSA_CRYPTO_BYTES; + break; + } + else if (ret != MLD_ERR_FAIL) + { + /* For failures such as out-of-memory, propagate and exit immediately. */ + break; + } + + /* Otherwise, try again. */ + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the signature buffer. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + return ret; +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + size_t pre_len; + int ret; + MLD_ALLOC(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + MLD_ALLOC(rnd, uint8_t, MLDSA_RNDBYTES, context); + + if (pre == NULL || rnd == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Prepare domain separation prefix for pure ML-DSA */ + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, m, mlen, pre, pre_len, rnd, sk, + 0, context); + +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(rnd, uint8_t, MLDSA_RNDBYTES, context); + MLD_FREE(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t rnd[MLDSA_RNDBYTES]; + int ret; + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + *siglen = 0; + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, + rnd, sk, 1, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(rnd, sizeof(rnd)); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + for (i = 0; i < mlen; ++i) + __loop__( + assigns(i, object_whole(sm)) + invariant(i <= mlen) + ) + { + sm[MLDSA_CRYPTO_BYTES + mlen - 1 - i] = m[mlen - 1 - i]; + } + ret = mld_sign_signature(sm, smlen, sm + MLDSA_CRYPTO_BYTES, mlen, ctx, + ctxlen, sk, context); + *smlen += mlen; + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret, cmp; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck t1; + mld_polyveck w1; + } + t1w1_u; + mld_polyveck *t1; + mld_polyveck *w1; + + MLD_ALLOC(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_ALLOC(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(z, mld_polyvecl, 1, context); + MLD_ALLOC(t1w1, t1w1_u, 1, context); + MLD_ALLOC(tmp, mld_polyveck, 1, context); + MLD_ALLOC(h, mld_polyveck, 1, context); + + if (buf == NULL || rho == NULL || mu == NULL || c == NULL || c2 == NULL || + cp == NULL || mat == NULL || z == NULL || t1w1 == NULL || tmp == NULL || + h == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + t1 = &t1w1->t1; + w1 = &t1w1->w1; + + if (siglen != MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + mld_unpack_pk(rho, t1, pk); + + /* mld_unpack_sig and mld_polyvecl_chknorm signal failure through a + * single non-zero error code that's not yet aligned with MLD_ERR_XXX. + * Map it to MLD_ERR_FAIL explicitly. */ + if (mld_unpack_sig(c, z, h, sig)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + if (mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + if (!externalmu) + { + /* Compute CRH(H(rho, t1), pre, msg) */ + MLD_ALIGN uint8_t hpk[MLDSA_CRHBYTES]; + mld_H(hpk, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES, NULL, 0, NULL, + 0); + mld_H(mu, MLDSA_CRHBYTES, hpk, MLDSA_TRBYTES, pre, prelen, m, mlen); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(hpk, sizeof(hpk)); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Matrix-vector multiplication; compute Az - c2^dt1 */ + mld_poly_challenge(cp, c); + mld_poly_ntt(cp); + mld_polyveck_shiftl(t1); + mld_polyveck_ntt(t1); + mld_polyveck_pointwise_poly_montgomery(tmp, cp, t1); + + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(z); + mld_polyvec_matrix_pointwise_montgomery(w1, mat, z); + mld_polyveck_sub(w1, tmp); + mld_polyveck_reduce(w1); + mld_polyveck_invntt_tomont(w1); + + /* Reconstruct w1 */ + mld_polyveck_caddq(w1); + mld_polyveck_use_hint(tmp, w1, h); + mld_polyveck_pack_w1(buf, tmp); + /* Call random oracle and verify challenge */ + mld_H(c2, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, buf, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + + cmp = mld_ct_memcmp(c, c2, MLDSA_CTILDEBYTES); + + /* Declassify the result of the verification. */ + MLD_CT_TESTING_DECLASSIFY(&cmp, sizeof(cmp)); + + ret = cmp == 0 ? 0 : MLD_ERR_FAIL; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(h, mld_polyveck, 1, context); + MLD_FREE(tmp, mld_polyveck, 1, context); + MLD_FREE(t1w1, t1w1_u, 1, context); + MLD_FREE(z, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, m, mlen, pre, pre_len, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + return mld_sign_verify_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, pk, + 1, context); +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + if (smlen < MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + *mlen = smlen - MLDSA_CRYPTO_BYTES; + ret = mld_sign_verify(sm, MLDSA_CRYPTO_BYTES, sm + MLDSA_CRYPTO_BYTES, *mlen, + ctx, ctxlen, pk, context); + if (ret == 0) + { + /* All good, copy msg, return 0 */ + for (i = 0; i < *mlen; ++i) + __loop__( + assigns(i, memory_slice(m, *mlen)) + invariant(i <= *mlen) + ) + { + m[i] = sm[MLDSA_CRYPTO_BYTES + i]; + } + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the message buffer. */ + *mlen = 0; + mld_memset(m, 0, smlen); + } + + return ret; +} + + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_signature_internal(sig, siglen, pre, pre_len, NULL, 0, rnd, sk, + 0, context); +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, pre, pre_len, NULL, 0, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_signature_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, rnd, sk, + MLD_PREHASH_SHAKE_256, context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_verify_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, pk, MLD_PREHASH_SHAKE_256, + context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + + +#define MLD_PRE_HASH_OID_LEN 11 + +/************************************************* + * Name: mld_get_hash_oid + * + * Description: Returns the OID of a given SHA-2/SHA-3 hash function. + * + * Arguments: - uint8_t oid[11]: pointer to output oid + * - int hashalg: hash algorithm constant (MLD_PREHASH_*) + * + ***************************************************/ +static void mld_get_hash_oid(uint8_t oid[MLD_PRE_HASH_OID_LEN], int hashalg) +{ + unsigned int i; + static const struct + { + int alg; + uint8_t oid[MLD_PRE_HASH_OID_LEN]; + } oid_map[] = { + {MLD_PREHASH_SHA2_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}}, + {MLD_PREHASH_SHA2_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}}, + {MLD_PREHASH_SHA2_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}}, + {MLD_PREHASH_SHA2_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}}, + {MLD_PREHASH_SHA2_512_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05}}, + {MLD_PREHASH_SHA2_512_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06}}, + {MLD_PREHASH_SHA3_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07}}, + {MLD_PREHASH_SHA3_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08}}, + {MLD_PREHASH_SHA3_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09}}, + {MLD_PREHASH_SHA3_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A}}, + {MLD_PREHASH_SHAKE_128, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B}}, + {MLD_PREHASH_SHAKE_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C}}}; + + for (i = 0; i < sizeof(oid_map) / sizeof(oid_map[0]); i++) + __loop__( + invariant(i <= sizeof(oid_map) / sizeof(oid_map[0])) + ) + { + if (oid_map[i].alg == hashalg) + { + mld_memcpy(oid, oid_map[i].oid, MLD_PRE_HASH_OID_LEN); + return; + } + } +} + +static int mld_validate_hash_length(int hashalg, size_t len) +{ + switch (hashalg) + { + case MLD_PREHASH_SHA2_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_128: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_256: + return (len == 512 / 8) ? 0 : -1; + } + return -1; +} + +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +{ + if (ctxlen > 255) + { + return 0; + } + + if (hashalg != MLD_PREHASH_NONE) + { + if (ph == NULL || mld_validate_hash_length(hashalg, phlen) != 0) + { + return 0; + } + } + + /* Common prefix: 0x00/0x01 || ctxlen || ctx */ + prefix[0] = (hashalg == MLD_PREHASH_NONE) ? 0 : 1; + prefix[1] = (uint8_t)ctxlen; + if (ctxlen > 0) + { + mld_memcpy(prefix + 2, ctx, ctxlen); + } + + if (hashalg == MLD_PREHASH_NONE) + { + return 2 + ctxlen; + } + + /* HashML-DSA: append oid || ph */ + mld_get_hash_oid(prefix + 2 + ctxlen, hashalg); + mld_memcpy(prefix + 2 + ctxlen + MLD_PRE_HASH_OID_LEN, ph, phlen); + return 2 + ctxlen + MLD_PRE_HASH_OID_LEN + phlen; +} + +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + uint8_t check, cmp0, cmp1, chk1, chk2; + int ret; + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(t0_computed, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + + if (rho == NULL || tr == NULL || tr_computed == NULL || key == NULL || + s1 == NULL || s2 == NULL || t0 == NULL || t0_computed == NULL || + t1 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Unpack secret key */ + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + /* Validate s1 and s2 coefficients are within [-MLDSA_ETA, MLDSA_ETA] */ + chk1 = mld_polyvecl_chknorm(s1, MLDSA_ETA + 1) & 0xFF; + chk2 = mld_polyveck_chknorm(s2, MLDSA_ETA + 1) & 0xFF; + + /* Recompute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0_computed, t1, tr_computed, + pk, rho, s1, s2, context); + if (ret != 0) + { + goto cleanup; + } + + /* Validate t0 and tr using constant-time comparisons */ + cmp0 = mld_ct_memcmp((const uint8_t *)t0, (const uint8_t *)t0_computed, + sizeof(mld_polyveck)); + cmp1 = mld_ct_memcmp((const uint8_t *)tr, (const uint8_t *)tr_computed, + MLDSA_TRBYTES); + check = mld_value_barrier_u8(cmp0 | cmp1 | chk1 | chk2); + + /* Declassify the final result of the validity check. */ + MLD_CT_TESTING_DECLASSIFY(&check, sizeof(check)); + ret = (check != 0) ? MLD_ERR_FAIL : 0; + +cleanup: + + if (ret != 0) + { + mld_zeroize(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + } + + /* Constant time: pk is either the valid public key or zeroed on error */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(t0_computed, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + + return ret; +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_check_pct +#undef mld_sample_s1_s2 +#undef mld_validate_hash_length +#undef mld_get_hash_oid +#undef mld_H +#undef mld_compute_pack_z +#undef mld_attempt_signature_generation +#undef mld_compute_t0_t1_tr_from_sk_components +#undef MLD_NONCE_UB +#undef MLD_PRE_HASH_OID_LEN diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/sign.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/sign.h new file mode 100644 index 0000000000..2e0bac32ea --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/sign.h @@ -0,0 +1,807 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_SIGN_H +#define MLD_SIGN_H + +#include +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "polyvec.h" +#include "sys.h" + +#if defined(MLD_CHECK_APIS) +/* Include to ensure consistency between internal sign.h + * and external mldsa_native.h. */ +#include "mldsa_native.h" + +#if MLDSA_CRYPTO_SECRETKEYBYTES != \ + MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for SECRETKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_PUBLICKEYBYTES != \ + MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for PUBLICKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_BYTES != MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for CRYPTO_BYTES between sign.h and mldsa_native.h +#endif + +#endif /* MLD_CHECK_APIS */ + +#define mld_sign_keypair_internal \ + MLD_NAMESPACE_KL(keypair_internal) MLD_CONTEXT_PARAMETERS_3 +#define mld_sign_keypair MLD_NAMESPACE_KL(keypair) MLD_CONTEXT_PARAMETERS_2 +#define mld_sign_signature_internal \ + MLD_NAMESPACE_KL(signature_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_signature MLD_NAMESPACE_KL(signature) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_extmu \ + MLD_NAMESPACE_KL(signature_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign MLD_NAMESPACE_KL(sign) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_internal \ + MLD_NAMESPACE_KL(verify_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify MLD_NAMESPACE_KL(verify) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_extmu \ + MLD_NAMESPACE_KL(verify_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign_open MLD_NAMESPACE_KL(open) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_pre_hash_internal \ + MLD_NAMESPACE_KL(signature_pre_hash_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_verify_pre_hash_internal \ + MLD_NAMESPACE_KL(verify_pre_hash_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_signature_pre_hash_shake256 \ + MLD_NAMESPACE_KL(signature_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify_pre_hash_shake256 \ + MLD_NAMESPACE_KL(verify_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_7 +#define mld_prepare_domain_separation_prefix \ + MLD_NAMESPACE_KL(prepare_domain_separation_prefix) +#define mld_sign_pk_from_sk \ + MLD_NAMESPACE_KL(pk_from_sk) MLD_CONTEXT_PARAMETERS_2 + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: mld_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: input random seed + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int externalmu: indicates input message m is + * processed as mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return MLD_ERR_FAIL in that case. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires((externalmu == 0 && (prelen == 0 || memory_no_alias(pre, prelen))) || + (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) + ensures(return_value == 0 ==> *siglen == MLDSA_CRYPTO_BYTES) + ensures(return_value != 0 ==> *siglen == 0) +); + +/************************************************* + * Name: mld_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_signature_extmu + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign + * + * Description: Compute signed message. + * + * Arguments: - uint8_t *sm: pointer to output signed message + * (allocated array with MLDSA_CRYPTO_BYTES + + *mlen bytes), can be equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sm, MLDSA_CRYPTO_BYTES + mlen)) + requires(memory_no_alias(smlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sm, MLDSA_CRYPTO_BYTES + mlen)) + assigns(object_whole(smlen)) + ensures((return_value == 0 && *smlen == MLDSA_CRYPTO_BYTES + mlen) || + (return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL)) +); + +/************************************************* + * Name: mld_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as + * mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(externalmu == 0 || (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + requires(externalmu == 1 || prelen == 0 || memory_no_alias(pre, prelen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_open + * + * Description: Verify signed message. + * + * Arguments: - uint8_t *m: pointer to output message (allocated array + * with smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context tring + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(smlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(m, smlen)) + requires(memory_no_alias(mlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(sm, smlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + assigns(memory_slice(m, smlen)) + assigns(memory_slice(mlen, sizeof(size_t))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and + * verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/* Maximum formatted domain separation message length: + * - Pure ML-DSA: 0x00 || ctxlen || ctx (max 255) + * - HashML-DSA: 0x01 || ctxlen || ctx (max 255) || oid (11) || ph (max 64) */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +__contract__( + requires(ctxlen <= 255) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(hashalg == MLD_PREHASH_NONE || memory_no_alias(ph, phlen)) + requires(memory_no_alias(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + assigns(memory_slice(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + ensures(return_value <= MLD_DOMAIN_SEPARATION_MAX_BYTES) +); + +/************************************************* + * Name: mld_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: input secret + * key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); +#endif /* !MLD_SIGN_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/symmetric.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/symmetric.h new file mode 100644 index 0000000000..bb70f05552 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/symmetric.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_SYMMETRIC_H +#define MLD_SYMMETRIC_H + +#include +#include "cbmc.h" +#include "common.h" + +#include MLD_FIPS202_HEADER_FILE +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#include MLD_FIPS202X4_HEADER_FILE +#endif + +#define MLD_STREAM128_BLOCKBYTES SHAKE128_RATE +#define MLD_STREAM256_BLOCKBYTES SHAKE256_RATE + +#define mld_xof256_ctx mld_shake256ctx +#define mld_xof256_init(CTX) mld_shake256_init(CTX) + +#define mld_xof256_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake256_absorb(CTX, IN, INBYTES); \ + mld_shake256_finalize(CTX); \ + } while (0) + + +#define mld_xof256_release(CTX) mld_shake256_release(CTX) +#define mld_xof256_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake256_squeeze(OUT, (OUTBLOCKS) * SHAKE256_RATE, STATE) + +#define mld_xof128_ctx mld_shake128ctx +#define mld_xof128_init(CTX) mld_shake128_init(CTX) + +#define mld_xof128_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake128_absorb(CTX, IN, INBYTES); \ + mld_shake128_finalize(CTX); \ + } while (0) + +#define mld_xof128_release(CTX) mld_shake128_release(CTX) +#define mld_xof128_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake128_squeeze(OUT, (OUTBLOCKS) * SHAKE128_RATE, STATE) + +#define mld_xof256_x4_ctx mld_shake256x4ctx +#define mld_xof256_x4_init(CTX) mld_shake256x4_init((CTX)) +#define mld_xof256_x4_absorb(CTX, IN, INBYTES) \ + mld_shake256x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof256_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake256x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof256_x4_release(CTX) mld_shake256x4_release((CTX)) + +#define mld_xof128_x4_ctx mld_shake128x4ctx +#define mld_xof128_x4_init(CTX) mld_shake128x4_init((CTX)) +#define mld_xof128_x4_absorb(CTX, IN, INBYTES) \ + mld_shake128x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof128_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake128x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof128_x4_release(CTX) mld_shake128x4_release((CTX)) + +#endif /* !MLD_SYMMETRIC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/sys.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/sys.h new file mode 100644 index 0000000000..1226526420 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/sys.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_SYS_H +#define MLD_SYS_H + +#if !defined(MLD_CONFIG_NO_ASM) && (defined(__GNUC__) || defined(__clang__)) +#define MLD_HAVE_INLINE_ASM +#endif + +/* Try to find endianness, if not forced through CFLAGS already */ +#if !defined(MLD_SYS_LITTLE_ENDIAN) && !defined(MLD_SYS_BIG_ENDIAN) +#if defined(__BYTE_ORDER__) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define MLD_SYS_LITTLE_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define MLD_SYS_BIG_ENDIAN +#else +#error "__BYTE_ORDER__ defined, but don't recognize value." +#endif +#endif /* __BYTE_ORDER__ */ + +/* MSVC does not define __BYTE_ORDER__. However, MSVC only supports + * little endian x86, x86_64, and AArch64. It is, hence, safe to assume + * little endian. */ +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_IX86) || defined(_M_ARM64)) +#define MLD_SYS_LITTLE_ENDIAN +#endif + +#endif /* !MLD_SYS_LITTLE_ENDIAN && !MLD_SYS_BIG_ENDIAN */ + +/* Check if we're running on an AArch64 little endian system. _M_ARM64 is set by + * MSVC. */ +#if defined(__AARCH64EL__) || defined(_M_ARM64) +#define MLD_SYS_AARCH64 +#endif + +/* Check if we're running on an AArch64 big endian system. */ +#if defined(__AARCH64EB__) +#define MLD_SYS_AARCH64_EB +#endif + +#if defined(__x86_64__) +#define MLD_SYS_X86_64 +#if defined(__AVX2__) +#define MLD_SYS_X86_64_AVX2 +#endif +#endif /* __x86_64__ */ + +#if defined(MLD_SYS_LITTLE_ENDIAN) && defined(__powerpc64__) +#define MLD_SYS_PPC64LE +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 +#define MLD_SYS_RISCV64 +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32 +#define MLD_SYS_RISCV32 +#endif + +#if defined(_WIN64) || defined(_WIN32) +#define MLD_SYS_WINDOWS +#endif + +#if defined(__linux__) +#define MLD_SYS_LINUX +#endif + +#if defined(__APPLE__) +#define MLD_SYS_APPLE +#endif + +/* If MLD_FORCE_AARCH64 is set, assert that we're indeed on an AArch64 system. + */ +#if defined(MLD_FORCE_AARCH64) && !defined(MLD_SYS_AARCH64) +#error "MLD_FORCE_AARCH64 is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_AARCH64_EB is set, assert that we're indeed on a big endian + * AArch64 system. */ +#if defined(MLD_FORCE_AARCH64_EB) && !defined(MLD_SYS_AARCH64_EB) +#error \ + "MLD_FORCE_AARCH64_EB is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_X86_64 is set, assert that we're indeed on an X86_64 system. */ +#if defined(MLD_FORCE_X86_64) && !defined(MLD_SYS_X86_64) +#error "MLD_FORCE_X86_64 is set, but we don't seem to be on an X86_64 system." +#endif + +#if defined(MLD_FORCE_PPC64LE) && !defined(MLD_SYS_PPC64LE) +#error "MLD_FORCE_PPC64LE is set, but we don't seem to be on a PPC64LE system." +#endif + +#if defined(MLD_FORCE_RISCV64) && !defined(MLD_SYS_RISCV64) +#error "MLD_FORCE_RISCV64 is set, but we don't seem to be on a RISCV64 system." +#endif + +#if defined(MLD_FORCE_RISCV32) && !defined(MLD_SYS_RISCV32) +#error "MLD_FORCE_RISCV32 is set, but we don't seem to be on a RISCV32 system." +#endif + +/* + * MLD_INLINE: Hint for inlining. + * - MSVC: __inline + * - C99+: inline + * - GCC/Clang C90: __attribute__((unused)) to silence warnings + * - Other C90: empty + */ +#if !defined(MLD_INLINE) +#if defined(_MSC_VER) +#define MLD_INLINE __inline +#elif defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +#define MLD_INLINE inline +#elif defined(__GNUC__) || defined(__clang__) +#define MLD_INLINE __attribute__((unused)) +#else +#define MLD_INLINE +#endif +#endif /* !MLD_INLINE */ + +/* + * MLD_ALWAYS_INLINE: Force inlining. + * - MSVC: __forceinline + * - GCC/Clang C99+: MLD_INLINE __attribute__((always_inline)) + * - Other: MLD_INLINE (no forced inlining) + */ +#if !defined(MLD_ALWAYS_INLINE) +#if defined(_MSC_VER) +#define MLD_ALWAYS_INLINE __forceinline +#elif (defined(__GNUC__) || defined(__clang__)) && \ + (defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)) +#define MLD_ALWAYS_INLINE MLD_INLINE __attribute__((always_inline)) +#else +#define MLD_ALWAYS_INLINE MLD_INLINE +#endif +#endif /* !MLD_ALWAYS_INLINE */ + +#ifndef MLD_STATIC_TESTABLE +#define MLD_STATIC_TESTABLE static +#endif + +/* + * C90 does not have the restrict compiler directive yet. + * We don't use it in C90 builds. + */ +#if !defined(restrict) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define MLD_RESTRICT restrict +#else +#define MLD_RESTRICT +#endif + +#else /* !restrict */ + +#define MLD_RESTRICT restrict +#endif /* restrict */ + +#define MLD_DEFAULT_ALIGN 32 +#define MLD_ALIGN_UP(N) \ + ((((N) + (MLD_DEFAULT_ALIGN - 1)) / MLD_DEFAULT_ALIGN) * MLD_DEFAULT_ALIGN) +#if defined(__GNUC__) +#define MLD_ALIGN __attribute__((aligned(MLD_DEFAULT_ALIGN))) +#elif defined(_MSC_VER) +#define MLD_ALIGN __declspec(align(MLD_DEFAULT_ALIGN)) +#else +#define MLD_ALIGN /* No known support for alignment constraints */ +#endif + + +/* New X86_64 CPUs support Conflow-flow protection using the CET instructions. + * When enabled (through -fcf-protection=), all compilation units (including + * empty ones) need to support CET for this to work. + * For assembly, this means that source files need to signal support for + * CET by setting the appropriate note.gnu.property section. + * This can be achieved by including the header in all assembly file. + * This file also provides the _CET_ENDBR macro which needs to be placed at + * every potential target of an indirect branch. + * If CET is enabled _CET_ENDBR maps to the endbr64 instruction, otherwise + * it is empty. + * In case the compiler does not support CET (e.g., +#define MLD_CET_ENDBR _CET_ENDBR +#else +#define MLD_CET_ENDBR +#endif +#endif /* MLD_SYS_X86_64 */ + +#if defined(MLD_CONFIG_CT_TESTING_ENABLED) && !defined(__ASSEMBLER__) +#include +#define MLD_CT_TESTING_SECRET(ptr, len) \ + VALGRIND_MAKE_MEM_UNDEFINED((ptr), (len)) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) +#else /* MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__ */ +#define MLD_CT_TESTING_SECRET(ptr, len) \ + do \ + { \ + } while (0) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + do \ + { \ + } while (0) +#endif /* !(MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__) */ + +#if defined(__GNUC__) || defined(__clang__) +#define MLD_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_MUST_CHECK_RETURN_VALUE +#endif + + +#if !defined(__ASSEMBLER__) +/* System capability enumeration */ +typedef enum +{ + /* x86_64 */ + MLD_SYS_CAP_AVX2, + /* AArch64 */ + MLD_SYS_CAP_SHA3 +} mld_sys_cap; + +#if !defined(MLD_CONFIG_CUSTOM_CAPABILITY_FUNC) +#include "cbmc.h" + +static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) +__contract__( + ensures(return_value == 0 || return_value == 1) +) +{ + /* By default, we rely on compile-time feature detection/specification: + * If a feature is enabled at compile-time, we assume it is supported by + * the host that the resulting library/binary will be built on. + * If this assumption is not true, you MUST overwrite this function. + * See the documentation of MLD_CONFIG_CUSTOM_CAPABILITY_FUNC in + * mldsa_native_config.h for more information. */ + (void)cap; + return 1; +} +#endif /* !MLD_CONFIG_CUSTOM_CAPABILITY_FUNC */ +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_SYS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/zetas.inc b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/zetas.inc new file mode 100644 index 0000000000..dc3cf15dd3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native/src/zetas.inc @@ -0,0 +1,56 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include + +/* + * Table of zeta values used in the reference NTT and inverse NTT. + * See autogen for details. + */ +static const int32_t mld_zetas[MLDSA_N] = { + 0, 25847, -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 2353451, -359251, -2091905, 3119733, -2884855, + 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488, + -1119584, 2619752, -2108549, -2118186, -3859737, -1399561, -3277672, + 1757237, -19422, 4010497, 280005, 2706023, 95776, 3077325, + 3530437, -1661693, -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267, + -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596, + 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, + -2797779, -3930395, -1528703, -3677745, -3041255, -1452451, 3475950, + 2176455, -1585221, -1257611, 1939314, -4083598, -1000202, -3190144, + -3157330, -3632928, 126922, 3412210, -983419, 2147896, 2715295, + -2967645, -3693493, -411027, -2477047, -671102, -1228525, -22981, + -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944, + 508951, 3097992, 44288, -1100098, 904516, 3958618, -3724342, + -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856, + 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, + 1341330, 1285669, -1584928, -812732, -1439742, -3019102, -3881060, + -3628969, 3839961, 2091667, 3407706, 2316500, 3817976, -3342478, + 2244091, -2446433, -3562462, 266997, 2434439, -1235728, 3513181, + -3520352, -3759364, -1197226, -3193378, 900702, 1859098, 909542, + 819034, 495491, -1613174, -43260, -522500, -655327, -3122442, + 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297, + 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, + 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, + 1595974, -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, + 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100, + 1312455, 3306115, -1962642, -1279661, 1917081, -2546312, -1374803, + 1500165, 777191, 2235880, 3406031, -542412, -2831860, -1671176, + -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395, + 2454455, -164721, 1957272, 3369112, 185531, -1207385, -3183426, + 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, + -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, + 472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333, + -260646, -3833893, -2939036, -2235985, -420899, -2286327, 183443, + -976891, 1612842, -3545687, -554416, 3919660, -48306, -1362209, + 3937738, 1400424, -846154, 1976782, +}; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native_all.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native_all.h new file mode 100644 index 0000000000..825618b796 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/mldsa_native_all.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_ALL_H +#define MLD_ALL_H + +/* API for MLDSA-44 */ +#define MLD_CONFIG_PARAMETER_SET 44 +#include "mldsa_native/mldsa_native.h" +#undef MLD_CONFIG_PARAMETER_SET +#undef MLD_H + +/* API for MLDSA-65 */ +#define MLD_CONFIG_PARAMETER_SET 65 +#include "mldsa_native/mldsa_native.h" +#undef MLD_CONFIG_PARAMETER_SET +#undef MLD_H + +/* API for MLDSA-87 */ +#define MLD_CONFIG_PARAMETER_SET 87 +#include "mldsa_native/mldsa_native.h" +#undef MLD_CONFIG_PARAMETER_SET +#undef MLD_H + +#endif /* !MLD_ALL_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/test_only_rng/notrandombytes.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/test_only_rng/notrandombytes.c new file mode 100644 index 0000000000..ef5a423a9e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/test_only_rng/notrandombytes.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* * Based on @[surf]*/ + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +#include +#include + +#include "notrandombytes.h" + +#ifdef ENABLE_CT_TESTING +#include +#endif + +static uint32_t seed[32] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, + 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5}; +static uint32_t in[12]; +static uint32_t out[8]; +static int32_t outleft = 0; + +void randombytes_reset(void) +{ + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + outleft = 0; +} + +#define ROTATE(x, b) (((x) << (b)) | ((x) >> (32 - (b)))) +#define MUSH(i, b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x, b)); + +static void surf(void) +{ + uint32_t t[12]; + uint32_t x; + uint32_t sum = 0; + int32_t r; + int32_t i; + int32_t loop; + + for (i = 0; i < 12; ++i) + { + t[i] = in[i] ^ seed[12 + i]; + } + for (i = 0; i < 8; ++i) + { + out[i] = seed[24 + i]; + } + x = t[11]; + for (loop = 0; loop < 2; ++loop) + { + for (r = 0; r < 16; ++r) + { + sum += 0x9e3779b9; + MUSH(0, 5) + MUSH(1, 7) + MUSH(2, 9) + MUSH(3, 13) + MUSH(4, 5) + MUSH(5, 7) + MUSH(6, 9) + MUSH(7, 13) + MUSH(8, 5) + MUSH(9, 7) + MUSH(10, 9) + MUSH(11, 13) + } + for (i = 0; i < 8; ++i) + { + out[i] ^= t[i + 4]; + } + } +} + +int randombytes(uint8_t *buf, size_t n) +{ +#ifdef ENABLE_CT_TESTING + uint8_t *buf_orig = buf; + size_t n_orig = n; +#endif + + while (n > 0) + { + if (!outleft) + { + if (!++in[0]) + { + if (!++in[1]) + { + if (!++in[2]) + { + ++in[3]; + } + } + } + surf(); + outleft = 8; + } + *buf = (uint8_t)out[--outleft]; + ++buf; + --n; + } + +#ifdef ENABLE_CT_TESTING + /* + * Mark all randombytes output as secret (undefined). + * Valgrind will propagate this to everything derived from it. + */ + VALGRIND_MAKE_MEM_UNDEFINED(buf_orig, n_orig); +#endif /* ENABLE_CT_TESTING */ + return 0; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/test_only_rng/notrandombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/test_only_rng/notrandombytes.h new file mode 100644 index 0000000000..bdf9787920 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/examples/multilevel_build_native/test_only_rng/notrandombytes.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT + */ + +/* References + * ========== + * + * - [surf] + * SURF: Simple Unpredictable Random Function + * Daniel J. Bernstein + * https://cr.yp.to/papers.html#surf + */ + +/* Based on @[surf]. */ + +#ifndef NOTRANDOMBYTES_H +#define NOTRANDOMBYTES_H + +#include +#include + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +void randombytes_reset(void); +int randombytes(uint8_t *buf, size_t n); + +#endif /* !NOTRANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/flake.lock b/tf-psa-crypto/drivers/pqcp/mldsa-native/flake.lock new file mode 100644 index 0000000000..de6906f8a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/flake.lock @@ -0,0 +1,82 @@ +{ + "nodes": { + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1738453229, + "narHash": "sha256-7H9XgNiGLKN1G1CgRh0vUL4AheZSYzPm+zmZ7vxbJdo=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "32ea77a06711b758da0ad9bd6a844c5740a87abd", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1754028485, + "narHash": "sha256-IiiXB3BDTi6UqzAZcf2S797hWEPCRZOwyNThJIYhUfk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "59e69648d345d6e8fef86158c555730fa12af9de", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-2405": { + "locked": { + "lastModified": 1735563628, + "narHash": "sha256-OnSAY7XDSx7CtDoqNh8jwVwh4xNL/2HaJxGjryLWzX8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b134951a4c9f3c995fd7be05f3243f8ecd65d798", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-unstable": { + "locked": { + "lastModified": 1767116409, + "narHash": "sha256-5vKw92l1GyTnjoLzEagJy5V5mDFck72LiQWZSOnSicw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "cad22e7d996aea55ecab064e84834289143e44a0", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs", + "nixpkgs-2405": "nixpkgs-2405", + "nixpkgs-unstable": "nixpkgs-unstable" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/flake.nix b/tf-psa-crypto/drivers/pqcp/mldsa-native/flake.nix new file mode 100644 index 0000000000..d4874acef0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/flake.nix @@ -0,0 +1,225 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +{ + description = "mldsa-native"; + + inputs = { + nixpkgs-2405.url = "github:NixOS/nixpkgs/nixos-24.05"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05"; + nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable"; + + flake-parts = { + url = "github:hercules-ci/flake-parts"; + inputs.nixpkgs-lib.follows = "nixpkgs"; + }; + }; + + outputs = inputs@{ flake-parts, ... }: + flake-parts.lib.mkFlake { inherit inputs; } { + imports = [ ]; + systems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin" ]; + perSystem = { config, pkgs, system, ... }: + let + pkgs-unstable = inputs.nixpkgs-unstable.legacyPackages.${system}; + pkgs-2405 = inputs.nixpkgs-2405.legacyPackages.${system}; + util = pkgs.callPackage ./nix/util.nix { + # Keep those around in case we want to switch to unstable versions + cbmc = pkgs-unstable.cbmc; + bitwuzla = pkgs-unstable.bitwuzla; + z3 = pkgs-unstable.z3; + }; + zigWrapCC = zig: pkgs.symlinkJoin { + name = "zig-wrappers"; + paths = [ + (pkgs.writeShellScriptBin "cc" + '' + exec ${zig}/bin/zig cc "$@" + '') + (pkgs.writeShellScriptBin "ar" + '' + exec ${zig}/bin/zig ar "$@" + '') + ]; + }; + holLightShellHook = '' + export PATH=$PWD/scripts:$PATH + export PROOF_DIR="$PWD/proofs/hol_light" + ''; + in + { + _module.args.pkgs = import inputs.nixpkgs { + inherit system; + overlays = [ + (_:_: { + gcc48 = pkgs-2405.gcc48; + gcc49 = pkgs-2405.gcc49; + gcc7 = pkgs-2405.gcc7; + gcc15 = pkgs-unstable.gcc15; + clang_21 = pkgs-unstable.clang_21; + zig_0_15 = pkgs-unstable.zig_0_15; + }) + ]; + }; + + packages.linters = util.linters; + packages.cbmc = util.cbmc_pkgs; + packages.hol_light = util.hol_light'; + packages.s2n_bignum = util.s2n_bignum; + packages.valgrind_varlat = util.valgrind_varlat; + packages.slothy = util.slothy; + packages.toolchains = util.toolchains; + packages.toolchains_native = util.toolchains_native; + packages.toolchain_x86_64 = util.toolchain_x86_64; + packages.toolchain_aarch64 = util.toolchain_aarch64; + packages.toolchain_riscv64 = util.toolchain_riscv64; + packages.toolchain_riscv32 = util.toolchain_riscv32; + packages.toolchain_ppc64le = util.toolchain_ppc64le; + packages.toolchain_aarch64_be = util.toolchain_aarch64_be; + + devShells.default = util.mkShell { + packages = builtins.attrValues + { + inherit (config.packages) linters cbmc hol_light s2n_bignum slothy toolchains_native hol_server; + inherit (pkgs) + direnv + nix-direnv + zig_0_13; + } ++ pkgs.lib.optionals (!pkgs.stdenv.isDarwin) [ config.packages.valgrind_varlat ]; + }; + + # arm-none-eabi-gcc + platform files from pqmx + packages.m55-an547 = util.m55-an547; + #packages.avr-toolchain = util.avr-toolchain; # TODO The AVR shell is currently unavaliable for mldsa-native + devShells.arm-embedded = util.mkShell { + packages = builtins.attrValues + { + inherit (config.packages) m55-an547; + inherit (pkgs) gcc-arm-embedded qemu coreutils python3 git; + }; + }; + + devShells.avr = util.mkShell (import ./nix/avr { inherit pkgs; }); + packages.hol_server = util.hol_server.hol_server_start; + devShells.hol_light = (util.mkShell { + packages = builtins.attrValues { inherit (config.packages) linters hol_light s2n_bignum hol_server; }; + }).overrideAttrs (old: { shellHook = holLightShellHook; }); + devShells.hol_light-cross = (util.mkShell { + packages = builtins.attrValues { inherit (config.packages) linters toolchains hol_light s2n_bignum hol_server; }; + }).overrideAttrs (old: { shellHook = holLightShellHook; }); + devShells.hol_light-cross-aarch64 = (util.mkShell { + packages = builtins.attrValues { inherit (config.packages) linters toolchain_aarch64 hol_light s2n_bignum hol_server; }; + }).overrideAttrs (old: { shellHook = holLightShellHook; }); + devShells.hol_light-cross-x86_64 = (util.mkShell { + packages = builtins.attrValues { inherit (config.packages) linters toolchain_x86_64 hol_light s2n_bignum hol_server; }; + }).overrideAttrs (old: { shellHook = holLightShellHook; }); + devShells.ci = util.mkShell { + packages = builtins.attrValues { inherit (config.packages) linters toolchains_native; }; + }; + devShells.ci-bench = util.mkShell { + packages = builtins.attrValues { inherit (config.packages) toolchains_native; }; + }; + devShells.ci-cbmc = util.mkShell { + packages = builtins.attrValues { inherit (config.packages) cbmc toolchains_native; } ++ [ pkgs.gh ]; + }; + devShells.ci-slothy = util.mkShell { + packages = builtins.attrValues { inherit (config.packages) slothy linters toolchains_native; }; + }; + devShells.ci-cross = util.mkShell { + packages = builtins.attrValues { inherit (config.packages) linters toolchains; }; + }; + devShells.ci-cross-x86_64 = util.mkShell { + packages = builtins.attrValues { inherit (config.packages) linters toolchain_x86_64; }; + }; + devShells.ci-cross-aarch64 = util.mkShell { + packages = builtins.attrValues { inherit (config.packages) linters toolchain_aarch64; }; + }; + devShells.ci-cross-riscv64 = util.mkShell { + packages = builtins.attrValues { inherit (config.packages) linters toolchain_riscv64; }; + }; + devShells.ci-cross-riscv32 = util.mkShell { + packages = builtins.attrValues { inherit (config.packages) linters toolchain_riscv32; }; + }; + devShells.ci-cross-ppc64le = util.mkShell { + packages = builtins.attrValues { inherit (config.packages) linters toolchain_ppc64le; }; + }; + devShells.ci-cross-aarch64_be = util.mkShell { + packages = builtins.attrValues { inherit (config.packages) linters toolchain_aarch64_be; }; + }; + devShells.ci-linter = util.mkShellNoCC { + packages = builtins.attrValues { inherit (config.packages) linters; }; + }; + devShells.ci_clang14 = util.mkShellWithCC' pkgs.clang_14; + devShells.ci_clang15 = util.mkShellWithCC' pkgs.clang_15; + devShells.ci_clang16 = util.mkShellWithCC' pkgs.clang_16; + devShells.ci_clang17 = util.mkShellWithCC' pkgs.clang_17; + devShells.ci_clang18 = util.mkShellWithCC' pkgs.clang_18; + devShells.ci_clang19 = util.mkShellWithCC' pkgs.clang_19; + devShells.ci_clang20 = util.mkShellWithCC' pkgs.clang_20; + devShells.ci_clang21 = util.mkShellWithCC' pkgs.clang_21; + + devShells.ci_zig0_12 = util.mkShellWithCC' (zigWrapCC pkgs.zig_0_12); + devShells.ci_zig0_13 = util.mkShellWithCC' (zigWrapCC pkgs.zig_0_13); + devShells.ci_zig0_14 = util.mkShellWithCC' (zigWrapCC pkgs.zig); + devShells.ci_zig0_15 = util.mkShellWithCC' (zigWrapCC pkgs.zig_0_15); + + + devShells.ci_gcc48 = util.mkShellWithCC' pkgs.gcc48; + devShells.ci_gcc49 = util.mkShellWithCC' pkgs.gcc49; + devShells.ci_gcc7 = util.mkShellWithCC' pkgs.gcc7; + devShells.ci_gcc11 = util.mkShellWithCC' pkgs.gcc11; + devShells.ci_gcc12 = util.mkShellWithCC' pkgs.gcc12; + devShells.ci_gcc13 = util.mkShellWithCC' pkgs.gcc13; + devShells.ci_gcc14 = util.mkShellWithCC' pkgs.gcc14; + devShells.ci_gcc15 = util.mkShellWithCC' pkgs.gcc15; + + # valgrind with a patch for detecting variable-latency instructions + devShells.ci_valgrind-varlat_clang14 = util.mkShellWithCC_valgrind' pkgs.clang_14; + devShells.ci_valgrind-varlat_clang15 = util.mkShellWithCC_valgrind' pkgs.clang_15; + devShells.ci_valgrind-varlat_clang16 = util.mkShellWithCC_valgrind' pkgs.clang_16; + devShells.ci_valgrind-varlat_clang17 = util.mkShellWithCC_valgrind' pkgs.clang_17; + devShells.ci_valgrind-varlat_clang18 = util.mkShellWithCC_valgrind' pkgs.clang_18; + devShells.ci_valgrind-varlat_clang19 = util.mkShellWithCC_valgrind' pkgs.clang_19; + devShells.ci_valgrind-varlat_clang20 = util.mkShellWithCC_valgrind' pkgs.clang_20; + devShells.ci_valgrind-varlat_clang21 = util.mkShellWithCC_valgrind' pkgs.clang_21; + devShells.ci_valgrind-varlat_gcc48 = util.mkShellWithCC_valgrind' pkgs.gcc48; + devShells.ci_valgrind-varlat_gcc49 = util.mkShellWithCC_valgrind' pkgs.gcc49; + devShells.ci_valgrind-varlat_gcc7 = util.mkShellWithCC_valgrind' pkgs.gcc7; + devShells.ci_valgrind-varlat_gcc11 = util.mkShellWithCC_valgrind' pkgs.gcc11; + devShells.ci_valgrind-varlat_gcc12 = util.mkShellWithCC_valgrind' pkgs.gcc12; + devShells.ci_valgrind-varlat_gcc13 = util.mkShellWithCC_valgrind' pkgs.gcc13; + devShells.ci_valgrind-varlat_gcc14 = util.mkShellWithCC_valgrind' pkgs.gcc14; + devShells.ci_valgrind-varlat_gcc15 = util.mkShellWithCC_valgrind' pkgs.gcc15; + }; + flake = { + devShell.x86_64-linux = + let + pkgs = inputs.nixpkgs.legacyPackages.x86_64-linux; + pkgs-unstable = inputs.nixpkgs-unstable.legacyPackages.x86_64-linux; + util = pkgs.callPackage ./nix/util.nix { + inherit pkgs; + cbmc = pkgs-unstable.cbmc; + bitwuzla = pkgs-unstable.bitwuzla; + z3 = pkgs-unstable.z3; + }; + in + util.mkShell { + packages = + [ + util.linters + util.cbmc_pkgs + util.hol_light' + util.s2n_bignum + util.toolchains_native + pkgs.zig_0_13 + ] + ++ pkgs.lib.optionals (!pkgs.stdenv.isDarwin) [ util.valgrind_varlat ]; + }; + # The usual flake attributes can be defined here, including system- + # agnostic ones like nixosModule and system-enumerating ones, although + # those are more easily expressed in perSystem. + + }; + }; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/ML-DSA-44_META.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/ML-DSA-44_META.yml new file mode 100644 index 0000000000..0c5f9d395e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/ML-DSA-44_META.yml @@ -0,0 +1,82 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +name: ML-DSA-44 +type: signature +claimed-nist-level: 2 +claimed-security: SUF-CMA +length-public-key: 1312 +length-secret-key: 2560 +length-signature: 2420 +nistkat-sha256: 9a196e7fb32fbc93757dc2d8dc1924460eab66303c0c08aeb8b798fb8d8f8cf3 +testvectors-sha256: 5f0d135c0f7fd43f3fb9727265fcd6ec3651eb8c67c04ea5f3d8dfa1d99740d2 +principal-submitters: +- Vadim Lyubashevsky +auxiliary-submitters: +- Shi Bai +- Léo Ducas +- Eike Kiltz +- Tancrède Lepoint +- Peter Schwabe +- Gregor Seiler +- Damien Stehlé +implementations: +- name: ref + version: FIPS204 + folder_name: . + compile_opts: -DMLD_CONFIG_PARAMETER_SET=44 -DMLD_CONFIG_FILE="../../integration/liboqs/config_c.h" + signature_keypair: PQCP_MLDSA_NATIVE_MLDSA44_C_keypair + signature_signature: PQCP_MLDSA_NATIVE_MLDSA44_C_signature + signature_verify: PQCP_MLDSA_NATIVE_MLDSA44_C_verify + api-with-context-string: true + sources: integration/liboqs/config_c.h integration/liboqs/fips202_glue.h integration/liboqs/fips202x4_glue.h + mldsa/src/cbmc.h mldsa/src/common.h mldsa/src/ct.c mldsa/src/ct.h mldsa/src/debug.c + mldsa/src/debug.h mldsa/src/packing.c mldsa/src/packing.h mldsa/src/params.h mldsa/src/poly.c + mldsa/src/poly.h mldsa/src/poly_kl.c mldsa/src/poly_kl.h mldsa/src/polyvec.c mldsa/src/polyvec.h + mldsa/src/randombytes.h mldsa/src/reduce.h mldsa/src/rounding.h mldsa/src/sign.c + mldsa/src/sign.h mldsa/src/symmetric.h mldsa/src/sys.h mldsa/src/zetas.inc +- name: x86_64 + version: FIPS204 + folder_name: . + compile_opts: -DMLD_CONFIG_PARAMETER_SET=44 -DMLD_CONFIG_FILE="../../integration/liboqs/config_x86_64.h" + signature_keypair: PQCP_MLDSA_NATIVE_MLDSA44_X86_64_keypair + signature_signature: PQCP_MLDSA_NATIVE_MLDSA44_X86_64_signature + signature_verify: PQCP_MLDSA_NATIVE_MLDSA44_X86_64_verify + api-with-context-string: true + sources: integration/liboqs/config_x86_64.h integration/liboqs/fips202_glue.h integration/liboqs/fips202x4_glue.h + mldsa/src/cbmc.h mldsa/src/common.h mldsa/src/ct.c mldsa/src/ct.h mldsa/src/debug.c + mldsa/src/debug.h mldsa/src/native/api.h mldsa/src/native/meta.h mldsa/src/packing.c + mldsa/src/packing.h mldsa/src/params.h mldsa/src/poly.c mldsa/src/poly.h mldsa/src/poly_kl.c + mldsa/src/poly_kl.h mldsa/src/polyvec.c mldsa/src/polyvec.h mldsa/src/randombytes.h + mldsa/src/reduce.h mldsa/src/rounding.h mldsa/src/sign.c mldsa/src/sign.h mldsa/src/symmetric.h + mldsa/src/sys.h mldsa/src/zetas.inc mldsa/src/native/x86_64 + supported_platforms: + - architecture: x86_64 + operating_systems: + - Darwin + - Linux + required_flags: + - avx2 + - bmi2 + - popcnt +- name: aarch64 + version: FIPS204 + folder_name: . + compile_opts: -DMLD_CONFIG_PARAMETER_SET=44 -DMLD_CONFIG_FILE="../../integration/liboqs/config_aarch64.h" + signature_keypair: PQCP_MLDSA_NATIVE_MLDSA44_AARCH64_keypair + signature_signature: PQCP_MLDSA_NATIVE_MLDSA44_AARCH64_signature + signature_verify: PQCP_MLDSA_NATIVE_MLDSA44_AARCH64_verify + api-with-context-string: true + sources: integration/liboqs/config_aarch64.h integration/liboqs/fips202_glue.h integration/liboqs/fips202x4_glue.h + mldsa/src/cbmc.h mldsa/src/common.h mldsa/src/ct.c mldsa/src/ct.h mldsa/src/debug.c + mldsa/src/debug.h mldsa/src/native/api.h mldsa/src/native/meta.h mldsa/src/packing.c + mldsa/src/packing.h mldsa/src/params.h mldsa/src/poly.c mldsa/src/poly.h mldsa/src/poly_kl.c + mldsa/src/poly_kl.h mldsa/src/polyvec.c mldsa/src/polyvec.h mldsa/src/randombytes.h + mldsa/src/reduce.h mldsa/src/rounding.h mldsa/src/sign.c mldsa/src/sign.h mldsa/src/symmetric.h + mldsa/src/sys.h mldsa/src/zetas.inc mldsa/src/native/aarch64 + supported_platforms: + - architecture: arm_8 + operating_systems: + - Linux + - Darwin + required_flags: + - asimd diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/ML-DSA-65_META.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/ML-DSA-65_META.yml new file mode 100644 index 0000000000..8ecdc1a539 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/ML-DSA-65_META.yml @@ -0,0 +1,82 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +name: ML-DSA-65 +type: signature +claimed-nist-level: 3 +claimed-security: SUF-CMA +length-public-key: 1952 +length-secret-key: 4032 +length-signature: 3309 +nistkat-sha256: 7cb96242eac9907a55b5c84c202f0ebd552419c50b2e986dc2e28f07ecebf072 +testvectors-sha256: 14bf84918ee90e7afbd580191d3eb890d4557e0900b1145e39a8399ef7dd3fba +principal-submitters: +- Vadim Lyubashevsky +auxiliary-submitters: +- Shi Bai +- Léo Ducas +- Eike Kiltz +- Tancrède Lepoint +- Peter Schwabe +- Gregor Seiler +- Damien Stehlé +implementations: +- name: ref + version: FIPS204 + folder_name: . + compile_opts: -DMLD_CONFIG_PARAMETER_SET=65 -DMLD_CONFIG_FILE="../../integration/liboqs/config_c.h" + signature_keypair: PQCP_MLDSA_NATIVE_MLDSA65_C_keypair + signature_signature: PQCP_MLDSA_NATIVE_MLDSA65_C_signature + signature_verify: PQCP_MLDSA_NATIVE_MLDSA65_C_verify + api-with-context-string: true + sources: integration/liboqs/config_c.h integration/liboqs/fips202_glue.h integration/liboqs/fips202x4_glue.h + mldsa/src/cbmc.h mldsa/src/common.h mldsa/src/ct.c mldsa/src/ct.h mldsa/src/debug.c + mldsa/src/debug.h mldsa/src/packing.c mldsa/src/packing.h mldsa/src/params.h mldsa/src/poly.c + mldsa/src/poly.h mldsa/src/poly_kl.c mldsa/src/poly_kl.h mldsa/src/polyvec.c mldsa/src/polyvec.h + mldsa/src/randombytes.h mldsa/src/reduce.h mldsa/src/rounding.h mldsa/src/sign.c + mldsa/src/sign.h mldsa/src/symmetric.h mldsa/src/sys.h mldsa/src/zetas.inc +- name: x86_64 + version: FIPS204 + folder_name: . + compile_opts: -DMLD_CONFIG_PARAMETER_SET=65 -DMLD_CONFIG_FILE="../../integration/liboqs/config_x86_64.h" + signature_keypair: PQCP_MLDSA_NATIVE_MLDSA65_X86_64_keypair + signature_signature: PQCP_MLDSA_NATIVE_MLDSA65_X86_64_signature + signature_verify: PQCP_MLDSA_NATIVE_MLDSA65_X86_64_verify + api-with-context-string: true + sources: integration/liboqs/config_x86_64.h integration/liboqs/fips202_glue.h integration/liboqs/fips202x4_glue.h + mldsa/src/cbmc.h mldsa/src/common.h mldsa/src/ct.c mldsa/src/ct.h mldsa/src/debug.c + mldsa/src/debug.h mldsa/src/native/api.h mldsa/src/native/meta.h mldsa/src/packing.c + mldsa/src/packing.h mldsa/src/params.h mldsa/src/poly.c mldsa/src/poly.h mldsa/src/poly_kl.c + mldsa/src/poly_kl.h mldsa/src/polyvec.c mldsa/src/polyvec.h mldsa/src/randombytes.h + mldsa/src/reduce.h mldsa/src/rounding.h mldsa/src/sign.c mldsa/src/sign.h mldsa/src/symmetric.h + mldsa/src/sys.h mldsa/src/zetas.inc mldsa/src/native/x86_64 + supported_platforms: + - architecture: x86_64 + operating_systems: + - Darwin + - Linux + required_flags: + - avx2 + - bmi2 + - popcnt +- name: aarch64 + version: FIPS204 + folder_name: . + compile_opts: -DMLD_CONFIG_PARAMETER_SET=65 -DMLD_CONFIG_FILE="../../integration/liboqs/config_aarch64.h" + signature_keypair: PQCP_MLDSA_NATIVE_MLDSA65_AARCH64_keypair + signature_signature: PQCP_MLDSA_NATIVE_MLDSA65_AARCH64_signature + signature_verify: PQCP_MLDSA_NATIVE_MLDSA65_AARCH64_verify + api-with-context-string: true + sources: integration/liboqs/config_aarch64.h integration/liboqs/fips202_glue.h integration/liboqs/fips202x4_glue.h + mldsa/src/cbmc.h mldsa/src/common.h mldsa/src/ct.c mldsa/src/ct.h mldsa/src/debug.c + mldsa/src/debug.h mldsa/src/native/api.h mldsa/src/native/meta.h mldsa/src/packing.c + mldsa/src/packing.h mldsa/src/params.h mldsa/src/poly.c mldsa/src/poly.h mldsa/src/poly_kl.c + mldsa/src/poly_kl.h mldsa/src/polyvec.c mldsa/src/polyvec.h mldsa/src/randombytes.h + mldsa/src/reduce.h mldsa/src/rounding.h mldsa/src/sign.c mldsa/src/sign.h mldsa/src/symmetric.h + mldsa/src/sys.h mldsa/src/zetas.inc mldsa/src/native/aarch64 + supported_platforms: + - architecture: arm_8 + operating_systems: + - Linux + - Darwin + required_flags: + - asimd diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/ML-DSA-87_META.yml b/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/ML-DSA-87_META.yml new file mode 100644 index 0000000000..ed86505dff --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/ML-DSA-87_META.yml @@ -0,0 +1,81 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +name: ML-DSA-87 +type: signature +claimed-nist-level: 5 +claimed-security: SUF-CMA +length-public-key: 2592 +length-secret-key: 4896 +length-signature: 4627 +nistkat-sha256: 4537905d2aabcf302fab2f242baed293459ecda7c230e6a67063b02c7e2840ed +testvectors-sha256: 759a3ba35210c7e27ff90a7ce5e399295533b82ef125e6ec98af158e00268e44 +principal-submitters: +- Vadim Lyubashevsky +auxiliary-submitters: +- Shi Bai +- Léo Ducas +- Eike Kiltz +- Tancrède Lepoint +- Peter Schwabe +- Gregor Seiler +- Damien Stehlé +implementations: +- name: ref + version: FIPS204 + folder_name: . + compile_opts: -DMLD_CONFIG_PARAMETER_SET=87 -DMLD_CONFIG_FILE="../../integration/liboqs/config_c.h" + signature_keypair: PQCP_MLDSA_NATIVE_MLDSA87_C_keypair + signature_signature: PQCP_MLDSA_NATIVE_MLDSA87_C_signature + signature_verify: PQCP_MLDSA_NATIVE_MLDSA87_C_verify + api-with-context-string: true + sources: integration/liboqs/config_c.h integration/liboqs/fips202_glue.h integration/liboqs/fips202x4_glue.h + mldsa/src/cbmc.h mldsa/src/common.h mldsa/src/ct.c mldsa/src/ct.h mldsa/src/debug.c + mldsa/src/debug.h mldsa/src/packing.c mldsa/src/packing.h mldsa/src/params.h mldsa/src/poly.c + mldsa/src/poly.h mldsa/src/poly_kl.c mldsa/src/poly_kl.h mldsa/src/polyvec.c mldsa/src/polyvec.h + mldsa/src/randombytes.h mldsa/src/reduce.h mldsa/src/rounding.h mldsa/src/sign.c + mldsa/src/sign.h mldsa/src/symmetric.h mldsa/src/sys.h mldsa/src/zetas.inc +- name: x86_64 + version: FIPS204 + folder_name: . + compile_opts: -DMLD_CONFIG_PARAMETER_SET=87 -DMLD_CONFIG_FILE="../../integration/liboqs/config_x86_64.h" + signature_keypair: PQCP_MLDSA_NATIVE_MLDSA87_X86_64_keypair + signature_signature: PQCP_MLDSA_NATIVE_MLDSA87_X86_64_signature + signature_verify: PQCP_MLDSA_NATIVE_MLDSA87_X86_64_verify + api-with-context-string: true + sources: integration/liboqs/config_x86_64.h integration/liboqs/fips202_glue.h integration/liboqs/fips202x4_glue.h + mldsa/src/cbmc.h mldsa/src/common.h mldsa/src/ct.c mldsa/src/ct.h mldsa/src/debug.c + mldsa/src/debug.h mldsa/src/native/api.h mldsa/src/native/meta.h mldsa/src/packing.c + mldsa/src/packing.h mldsa/src/params.h mldsa/src/poly.c mldsa/src/poly.h mldsa/src/poly_kl.c + mldsa/src/poly_kl.h mldsa/src/polyvec.c mldsa/src/polyvec.h mldsa/src/randombytes.h + mldsa/src/reduce.h mldsa/src/rounding.h mldsa/src/sign.c mldsa/src/sign.h mldsa/src/symmetric.h + mldsa/src/sys.h mldsa/src/zetas.inc mldsa/src/native/x86_64 + supported_platforms: + - architecture: x86_64 + operating_systems: + - Darwin + - Linux + required_flags: + - avx2 + - popcnt +- name: aarch64 + version: FIPS204 + folder_name: . + compile_opts: -DMLD_CONFIG_PARAMETER_SET=87 -DMLD_CONFIG_FILE="../../integration/liboqs/config_aarch64.h" + signature_keypair: PQCP_MLDSA_NATIVE_MLDSA87_AARCH64_keypair + signature_signature: PQCP_MLDSA_NATIVE_MLDSA87_AARCH64_signature + signature_verify: PQCP_MLDSA_NATIVE_MLDSA87_AARCH64_verify + api-with-context-string: true + sources: integration/liboqs/config_aarch64.h integration/liboqs/fips202_glue.h integration/liboqs/fips202x4_glue.h + mldsa/src/cbmc.h mldsa/src/common.h mldsa/src/ct.c mldsa/src/ct.h mldsa/src/debug.c + mldsa/src/debug.h mldsa/src/native/api.h mldsa/src/native/meta.h mldsa/src/packing.c + mldsa/src/packing.h mldsa/src/params.h mldsa/src/poly.c mldsa/src/poly.h mldsa/src/poly_kl.c + mldsa/src/poly_kl.h mldsa/src/polyvec.c mldsa/src/polyvec.h mldsa/src/randombytes.h + mldsa/src/reduce.h mldsa/src/rounding.h mldsa/src/sign.c mldsa/src/sign.h mldsa/src/symmetric.h + mldsa/src/sys.h mldsa/src/zetas.inc mldsa/src/native/aarch64 + supported_platforms: + - architecture: arm_8 + operating_systems: + - Linux + - Darwin + required_flags: + - asimd diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/config_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/config_aarch64.h new file mode 100644 index 0000000000..39866a7d3e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/config_aarch64.h @@ -0,0 +1,322 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + */ + +#ifndef MLD_INTEGRATION_LIBOQS_CONFIG_AARCH64_H +#define MLD_INTEGRATION_LIBOQS_CONFIG_AARCH64_H + +/* Enable valgrind-based assertions in mldsa-native through macro + * from libOQS. */ +#if !defined(__ASSEMBLER__) +#include +#if defined(OQS_ENABLE_TEST_CONSTANT_TIME) +#define MLD_CONFIG_CT_TESTING_ENABLED +#endif +#endif /* !__ASSEMBLER__ */ + +/* Use OQS's FIPS202 via glue headers */ +#define MLD_CONFIG_FIPS202_CUSTOM_HEADER \ + "../../integration/liboqs/fips202_glue.h" +#define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER \ + "../../integration/liboqs/fips202x4_glue.h" + +/****************************************************************************** + * Name: MLD_CONFIG_PARAMETER_SET + * + * Description: Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_NAMESPACE_PREFIX + * + * Description: The prefix to use to namespace global symbols from mldsa/. + * For integration builds, this adds an architecture-specific + * suffix to distinguish different builds. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_NAMESPACE_PREFIX) +#define MLD_CONFIG_NAMESPACE_PREFIX MLD_DEFAULT_NAMESPACE_PREFIX +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of this default configuration file mldsa/config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * then configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + * + *****************************************************************************/ +/* #define MLD_CONFIG_FILE "config.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_ARITH_BACKEND_FILE + * + * Description: The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH +#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_BACKEND_FILE + * + * Description: The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +/* + * #define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * #define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h" + */ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ZEROIZE + * + * Description: In compliance with FIPS 204 Section 3.6.3, mldsa-native zeroizes + * intermediate stack buffers before returning from function calls. + * + * Set this option and define `mld_zeroize` if you want to + * use a custom method to zeroize intermediate stack buffers. + * The default implementation uses SecureZeroMemory on Windows + * and a memset + compiler barrier otherwise. If neither of those + * is available on the target platform, compilation will fail, + * and you will need to use MLD_CONFIG_CUSTOM_ZEROIZE to provide + * a custom implementation of `mld_zeroize()`. + * + * WARNING: + * The explicit stack zeroization conducted by mldsa-native + * reduces the likelihood of data leaking on the stack, but + * does not eliminate it! The C standard makes no guarantee about + * where a compiler allocates structures and whether/where it makes + * copies of them. Also, in addition to entire structures, there + * may also be potentially exploitable leakage of individual values + * on the stack. + * + * If you need bullet-proof zeroization of the stack, you need to + * consider additional measures instead of what this feature + * provides. In this case, you can set mld_zeroize to a + * no-op. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "sys.h" + static MLD_INLINE void mld_zeroize(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * Description: mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to provided by the + * consumer. + * + * If this option is not set, mlkem-native expects a function + * int randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mlk_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + * + *****************************************************************************/ +#define MLD_CONFIG_CUSTOM_RANDOMBYTES +#if !defined(__ASSEMBLER__) +#include +#include +#include "../../mldsa/src/sys.h" +static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) +{ + OQS_randombytes(ptr, len); + return 0; +} +#endif /* !__ASSEMBLER__ */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT + * + * Description: Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, crypto_sign_keypair_internal and + * crypto_sign_keypair will return a non-zero error code if the + * PCT failed. + * + * NOTE: This feature will drastically lower the performance of + * key generation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * Description: If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "sys.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * and MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + * + *****************************************************************************/ +#if !defined(__ASSEMBLER__) +#include +#define MLD_CONFIG_EXTERNAL_API_QUALIFIER OQS_API +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Description: Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * NOTE: Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + * + *****************************************************************************/ +/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +/************************* Config internals ********************************/ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace for aarch64 integration is + * + * PQCP_MLDSA_NATIVE_MLDSA_AARCH64_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_AARCH64_ + */ + +#if MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44_AARCH64 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65_AARCH64 +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87_AARCH64 +#endif + +#endif /* !MLD_INTEGRATION_LIBOQS_CONFIG_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/config_c.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/config_c.h new file mode 100644 index 0000000000..190509b6d3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/config_c.h @@ -0,0 +1,326 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + */ + +#ifndef MLD_INTEGRATION_LIBOQS_CONFIG_C_H +#define MLD_INTEGRATION_LIBOQS_CONFIG_C_H + +/* Enable valgrind-based assertions in mldsa-native through macro + * from libOQS. */ +#if !defined(__ASSEMBLER__) +#include +#if defined(OQS_ENABLE_TEST_CONSTANT_TIME) +#define MLD_CONFIG_CT_TESTING_ENABLED +#endif +#endif /* !__ASSEMBLER__ */ + +/* Use OQS's FIPS202 via glue headers */ +#define MLD_CONFIG_FIPS202_CUSTOM_HEADER \ + "../../integration/liboqs/fips202_glue.h" +#define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER \ + "../../integration/liboqs/fips202x4_glue.h" + +/****************************************************************************** + * Name: MLD_CONFIG_PARAMETER_SET + * + * Description: Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_NAMESPACE_PREFIX + * + * Description: The prefix to use to namespace global symbols from mldsa/. + * For integration builds, this adds an architecture-specific + * suffix to distinguish different builds. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_NAMESPACE_PREFIX) +#define MLD_CONFIG_NAMESPACE_PREFIX MLD_DEFAULT_NAMESPACE_PREFIX +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of this default configuration file mldsa/config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * then configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + * + *****************************************************************************/ +/* #define MLD_CONFIG_FILE "config.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_ARITH_BACKEND_FILE + * + * Description: The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +/* #if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) + #define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_BACKEND_FILE + * + * Description: The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +/* #if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) + #define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h" + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ZEROIZE + * + * Description: In compliance with FIPS 204 Section 3.6.3, mldsa-native zeroizes + * intermediate stack buffers before returning from function calls. + * + * Set this option and define `mld_zeroize` if you want to + * use a custom method to zeroize intermediate stack buffers. + * The default implementation uses SecureZeroMemory on Windows + * and a memset + compiler barrier otherwise. If neither of those + * is available on the target platform, compilation will fail, + * and you will need to use MLD_CONFIG_CUSTOM_ZEROIZE to provide + * a custom implementation of `mld_zeroize()`. + * + * WARNING: + * The explicit stack zeroization conducted by mldsa-native + * reduces the likelihood of data leaking on the stack, but + * does not eliminate it! The C standard makes no guarantee about + * where a compiler allocates structures and whether/where it makes + * copies of them. Also, in addition to entire structures, there + * may also be potentially exploitable leakage of individual values + * on the stack. + * + * If you need bullet-proof zeroization of the stack, you need to + * consider additional measures instead of what this feature + * provides. In this case, you can set mld_zeroize to a + * no-op. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "sys.h" + static MLD_INLINE void mld_zeroize(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * Description: mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to provided by the + * consumer. + * + * If this option is not set, mlkem-native expects a function + * int randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mlk_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + * + *****************************************************************************/ +#define MLD_CONFIG_CUSTOM_RANDOMBYTES +#if !defined(__ASSEMBLER__) +#include +#include +#include "../../mldsa/src/sys.h" +static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) +{ + OQS_randombytes(ptr, len); + return 0; +} +#endif /* !__ASSEMBLER__ */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT + * + * Description: Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, crypto_sign_keypair_internal and + * crypto_sign_keypair will return a non-zero error code if the + * PCT failed. + * + * NOTE: This feature will drastically lower the performance of + * key generation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * Description: If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "sys.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * and MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + * + *****************************************************************************/ +#if !defined(__ASSEMBLER__) +#include +#define MLD_CONFIG_EXTERNAL_API_QUALIFIER OQS_API +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Description: Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * NOTE: Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + * + *****************************************************************************/ +/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +/************************* Config internals ********************************/ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace for C integration is + * + * PQCP_MLDSA_NATIVE_MLDSA_C_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_C_ + */ + +#if MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44_C +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65_C +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87_C +#endif + +#endif /* !MLD_INTEGRATION_LIBOQS_CONFIG_C_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/config_x86_64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/config_x86_64.h new file mode 100644 index 0000000000..cc30e23bdd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/config_x86_64.h @@ -0,0 +1,324 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + */ + +#ifndef MLD_INTEGRATION_LIBOQS_CONFIG_X86_64_H +#define MLD_INTEGRATION_LIBOQS_CONFIG_X86_64_H + +/* Enable valgrind-based assertions in mldsa-native through macro + * from libOQS. */ +#if !defined(__ASSEMBLER__) +#include +#if defined(OQS_ENABLE_TEST_CONSTANT_TIME) +#define MLD_CONFIG_CT_TESTING_ENABLED +#endif +#endif /* !__ASSEMBLER__ */ + +/* Use OQS's FIPS202 via glue headers */ +#define MLD_CONFIG_FIPS202_CUSTOM_HEADER \ + "../../integration/liboqs/fips202_glue.h" +#define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER \ + "../../integration/liboqs/fips202x4_glue.h" + +/****************************************************************************** + * Name: MLD_CONFIG_PARAMETER_SET + * + * Description: Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_NAMESPACE_PREFIX + * + * Description: The prefix to use to namespace global symbols from mldsa/. + * For integration builds, this adds an architecture-specific + * suffix to distinguish different builds. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_NAMESPACE_PREFIX) +#define MLD_CONFIG_NAMESPACE_PREFIX MLD_DEFAULT_NAMESPACE_PREFIX +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of this default configuration file mldsa/config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * then configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + * + *****************************************************************************/ +/* #define MLD_CONFIG_FILE "config.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_ARITH_BACKEND_FILE + * + * Description: The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH +#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_BACKEND_FILE + * + * Description: The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +/* + * #define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * #define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h" + */ + + + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ZEROIZE + * + * Description: In compliance with FIPS 204 Section 3.6.3, mldsa-native zeroizes + * intermediate stack buffers before returning from function calls. + * + * Set this option and define `mld_zeroize` if you want to + * use a custom method to zeroize intermediate stack buffers. + * The default implementation uses SecureZeroMemory on Windows + * and a memset + compiler barrier otherwise. If neither of those + * is available on the target platform, compilation will fail, + * and you will need to use MLD_CONFIG_CUSTOM_ZEROIZE to provide + * a custom implementation of `mld_zeroize()`. + * + * WARNING: + * The explicit stack zeroization conducted by mldsa-native + * reduces the likelihood of data leaking on the stack, but + * does not eliminate it! The C standard makes no guarantee about + * where a compiler allocates structures and whether/where it makes + * copies of them. Also, in addition to entire structures, there + * may also be potentially exploitable leakage of individual values + * on the stack. + * + * If you need bullet-proof zeroization of the stack, you need to + * consider additional measures instead of what this feature + * provides. In this case, you can set mld_zeroize to a + * no-op. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "sys.h" + static MLD_INLINE void mld_zeroize(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * Description: mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to provided by the + * consumer. + * + * If this option is not set, mlkem-native expects a function + * int randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mlk_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + * + *****************************************************************************/ +#define MLD_CONFIG_CUSTOM_RANDOMBYTES +#if !defined(__ASSEMBLER__) +#include +#include +#include "../../mldsa/src/sys.h" +static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) +{ + OQS_randombytes(ptr, len); + return 0; +} +#endif /* !__ASSEMBLER__ */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT + * + * Description: Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, crypto_sign_keypair_internal and + * crypto_sign_keypair will return a non-zero error code if the + * PCT failed. + * + * NOTE: This feature will drastically lower the performance of + * key generation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * Description: If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "sys.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * and MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM */ + +/****************************************************************************** + * Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + * + *****************************************************************************/ +#if !defined(__ASSEMBLER__) +#include +#define MLD_CONFIG_EXTERNAL_API_QUALIFIER OQS_API +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Description: Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * NOTE: Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + * + *****************************************************************************/ +/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +/************************* Config internals ********************************/ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace for x86_64 integration is + * + * PQCP_MLDSA_NATIVE_MLDSA_X86_64_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_X86_64_ + */ + +#if MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44_X86_64 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65_X86_64 +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87_X86_64 +#endif + +#endif /* !MLD_INTEGRATION_LIBOQS_CONFIG_X86_64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/fips202_glue.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/fips202_glue.h new file mode 100644 index 0000000000..fb7bf730ad --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/fips202_glue.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_INTEGRATION_LIBOQS_FIPS202_GLUE_H +#define MLD_INTEGRATION_LIBOQS_FIPS202_GLUE_H + +/* Include OQS's own FIPS202 header */ +#include "fips202.h" + +#define mld_shake128ctx shake128incctx +#define mld_shake128_init shake128_inc_init +#define mld_shake128_absorb shake128_inc_absorb +#define mld_shake128_finalize shake128_inc_finalize +#define mld_shake128_squeeze shake128_inc_squeeze +#define mld_shake128_release shake128_inc_ctx_release + +#define mld_shake256ctx shake256incctx +#define mld_shake256_init shake256_inc_init +#define mld_shake256_absorb shake256_inc_absorb +#define mld_shake256_finalize shake256_inc_finalize +#define mld_shake256_squeeze shake256_inc_squeeze +#define mld_shake256_release shake256_inc_ctx_release + +#define mld_shake256 shake256 + +#endif /* !MLD_INTEGRATION_LIBOQS_FIPS202_GLUE_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/fips202x4_glue.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/fips202x4_glue.h new file mode 100644 index 0000000000..34f29a9a21 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/integration/liboqs/fips202x4_glue.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_INTEGRATION_LIBOQS_FIPS202X4_GLUE_H +#define MLD_INTEGRATION_LIBOQS_FIPS202X4_GLUE_H + +/* Include OQS's own FIPS202_X4 header */ +#include "fips202x4.h" + +/* OQS's FIPS202_X4 is as-is compatible with the one expected + * by mldsa-native, so just remove the mld_xxx prefix. */ +#define mld_shake128x4ctx shake128x4incctx +#define mld_shake128x4_absorb_once shake128x4_absorb_once +#define mld_shake128x4_squeezeblocks shake128x4_squeezeblocks +#define mld_shake128x4_init shake128x4_inc_init +#define mld_shake128x4_release shake128x4_inc_ctx_release + +#define mld_shake256x4ctx shake256x4incctx +#define mld_shake256x4_absorb_once shake256x4_absorb_once +#define mld_shake256x4_squeezeblocks shake256x4_squeezeblocks +#define mld_shake256x4_init shake256x4_inc_init +#define mld_shake256x4_release shake256x4_inc_ctx_release + +#endif /* !MLD_INTEGRATION_LIBOQS_FIPS202X4_GLUE_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/mldsa_native.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/mldsa_native.c new file mode 100644 index 0000000000..9668cec167 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/mldsa_native.c @@ -0,0 +1,699 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/****************************************************************************** + * + * Single compilation unit (SCU) for fixed-level build of mldsa-native + * + * This compilation unit bundles together all source files for a build + * of mldsa-native for a fixed security level (MLDSA-44/65/87). + * + * # API + * + * The API exposed by this file is described in mldsa_native.h. + * + * # Multi-level build + * + * If you want an SCU build of mldsa-native with support for multiple security + * levels, you need to include this file multiple times, and set + * MLD_CONFIG_MULTILEVEL_WITH_SHARED and MLD_CONFIG_MULTILEVEL_NO_SHARED + * appropriately. This is exemplified in examples/monolithic_build_multilevel + * and examples/monolithic_build_multilevel_native. + * + * # Configuration + * + * The following options from the mldsa-native configuration are relevant: + * + * - MLD_CONFIG_FIPS202_CUSTOM_HEADER + * Set this option if you use a custom FIPS202 implementation. + * + * - MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * Set this option if you want to include the native arithmetic backends + * in your build. + * + * - MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * Set this option if you want to include the native FIPS202 backends + * in your build. + * + * - MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * Set this option if you want to keep the directives defined in + * level-independent headers. This is needed for a multi-level build. + */ + +/* If parts of the mldsa-native source tree are not used, + * consider reducing this header via `unifdef`. + * + * Example: + * ```bash + * unifdef -UMLD_CONFIG_USE_NATIVE_BACKEND_ARITH mldsa_native.c + * ``` + */ + +#include "src/common.h" + +#include "src/ct.c" +#include "src/debug.c" +#include "src/packing.c" +#include "src/poly.c" +#include "src/poly_kl.c" +#include "src/polyvec.c" +#include "src/sign.c" + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#include "src/fips202/fips202.c" +#include "src/fips202/fips202x4.c" +#include "src/fips202/keccakf1600.c" +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#if defined(MLD_SYS_AARCH64) +#include "src/native/aarch64/src/aarch64_zetas.c" +#include "src/native/aarch64/src/polyz_unpack_table.c" +#include "src/native/aarch64/src/rej_uniform_eta_table.c" +#include "src/native/aarch64/src/rej_uniform_table.c" +#endif /* MLD_SYS_AARCH64 */ +#if defined(MLD_SYS_X86_64) +#include "src/native/x86_64/src/consts.c" +#include "src/native/x86_64/src/poly_caddq_avx2.c" +#include "src/native/x86_64/src/poly_chknorm_avx2.c" +#include "src/native/x86_64/src/poly_decompose_32_avx2.c" +#include "src/native/x86_64/src/poly_decompose_88_avx2.c" +#include "src/native/x86_64/src/poly_use_hint_32_avx2.c" +#include "src/native/x86_64/src/poly_use_hint_88_avx2.c" +#include "src/native/x86_64/src/polyz_unpack_17_avx2.c" +#include "src/native/x86_64/src/polyz_unpack_19_avx2.c" +#include "src/native/x86_64/src/rej_uniform_avx2.c" +#include "src/native/x86_64/src/rej_uniform_eta2_avx2.c" +#include "src/native/x86_64/src/rej_uniform_eta4_avx2.c" +#include "src/native/x86_64/src/rej_uniform_table.c" +#endif /* MLD_SYS_X86_64 */ +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#if defined(MLD_SYS_AARCH64) +#include "src/fips202/native/aarch64/src/keccakf1600_round_constants.c" +#endif +#if defined(MLD_SYS_X86_64) +#include "src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +/* Macro #undef's + * + * The following undefines macros from headers + * included by the source files imported above. + * + * This is to allow building and linking multiple builds + * of mldsa-native for varying parameter sets through concatenation + * of this file, as if the files had been compiled separately. + * If this is not relevant to you, you may remove the following. + */ + +/* + * Undefine macros from MLD_CONFIG_PARAMETER_SET-specific files + */ +/* mldsa/mldsa_native.h */ +#undef CRYPTO_BYTES +#undef CRYPTO_PUBLICKEYBYTES +#undef CRYPTO_SECRETKEYBYTES +#undef MLDSA44_BYTES +#undef MLDSA44_CRHBYTES +#undef MLDSA44_PUBLICKEYBYTES +#undef MLDSA44_RNDBYTES +#undef MLDSA44_SECRETKEYBYTES +#undef MLDSA44_SEEDBYTES +#undef MLDSA44_TRBYTES +#undef MLDSA65_BYTES +#undef MLDSA65_CRHBYTES +#undef MLDSA65_PUBLICKEYBYTES +#undef MLDSA65_RNDBYTES +#undef MLDSA65_SECRETKEYBYTES +#undef MLDSA65_SEEDBYTES +#undef MLDSA65_TRBYTES +#undef MLDSA87_BYTES +#undef MLDSA87_CRHBYTES +#undef MLDSA87_PUBLICKEYBYTES +#undef MLDSA87_RNDBYTES +#undef MLDSA87_SECRETKEYBYTES +#undef MLDSA87_SEEDBYTES +#undef MLDSA87_TRBYTES +#undef MLDSA_BYTES +#undef MLDSA_BYTES_ +#undef MLDSA_CRHBYTES +#undef MLDSA_PUBLICKEYBYTES +#undef MLDSA_PUBLICKEYBYTES_ +#undef MLDSA_RNDBYTES +#undef MLDSA_SECRETKEYBYTES +#undef MLDSA_SECRETKEYBYTES_ +#undef MLDSA_SEEDBYTES +#undef MLDSA_TRBYTES +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_LEGACY_CONFIG +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_NAMESPACE +#undef MLD_API_QUALIFIER +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_QUALIFIER +#undef MLD_DOMAIN_SEPARATION_MAX_BYTES +#undef MLD_ERR_FAIL +#undef MLD_ERR_OUT_OF_MEMORY +#undef MLD_ERR_RNG_FAIL +#undef MLD_H +#undef MLD_MAX3_ +#undef MLD_PREHASH_NONE +#undef MLD_PREHASH_SHA2_224 +#undef MLD_PREHASH_SHA2_256 +#undef MLD_PREHASH_SHA2_384 +#undef MLD_PREHASH_SHA2_512 +#undef MLD_PREHASH_SHA2_512_224 +#undef MLD_PREHASH_SHA2_512_256 +#undef MLD_PREHASH_SHA3_224 +#undef MLD_PREHASH_SHA3_256 +#undef MLD_PREHASH_SHA3_384 +#undef MLD_PREHASH_SHA3_512 +#undef MLD_PREHASH_SHAKE_128 +#undef MLD_PREHASH_SHAKE_256 +#undef MLD_TOTAL_ALLOC_44 +#undef MLD_TOTAL_ALLOC_44_KEYPAIR +#undef MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#undef MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#undef MLD_TOTAL_ALLOC_44_SIGN +#undef MLD_TOTAL_ALLOC_44_VERIFY +#undef MLD_TOTAL_ALLOC_65 +#undef MLD_TOTAL_ALLOC_65_KEYPAIR +#undef MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#undef MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#undef MLD_TOTAL_ALLOC_65_SIGN +#undef MLD_TOTAL_ALLOC_65_VERIFY +#undef MLD_TOTAL_ALLOC_87 +#undef MLD_TOTAL_ALLOC_87_KEYPAIR +#undef MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#undef MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#undef MLD_TOTAL_ALLOC_87_SIGN +#undef MLD_TOTAL_ALLOC_87_VERIFY +#undef crypto_sign +#undef crypto_sign_keypair +#undef crypto_sign_open +#undef crypto_sign_signature +#undef crypto_sign_verify +/* mldsa/src/common.h */ +#undef MLD_ADD_PARAM_SET +#undef MLD_ALLOC +#undef MLD_APPLY +#undef MLD_ASM_FN_SYMBOL +#undef MLD_ASM_NAMESPACE +#undef MLD_BUILD_INTERNAL +#undef MLD_COMMON_H +#undef MLD_CONCAT +#undef MLD_CONCAT_ +#undef MLD_CONTEXT_PARAMETERS_0 +#undef MLD_CONTEXT_PARAMETERS_1 +#undef MLD_CONTEXT_PARAMETERS_2 +#undef MLD_CONTEXT_PARAMETERS_3 +#undef MLD_CONTEXT_PARAMETERS_4 +#undef MLD_CONTEXT_PARAMETERS_5 +#undef MLD_CONTEXT_PARAMETERS_6 +#undef MLD_CONTEXT_PARAMETERS_7 +#undef MLD_CONTEXT_PARAMETERS_8 +#undef MLD_CONTEXT_PARAMETERS_9 +#undef MLD_EMPTY_CU +#undef MLD_ERR_FAIL +#undef MLD_ERR_OUT_OF_MEMORY +#undef MLD_ERR_RNG_FAIL +#undef MLD_EXTERNAL_API +#undef MLD_FIPS202X4_HEADER_FILE +#undef MLD_FIPS202_HEADER_FILE +#undef MLD_FREE +#undef MLD_INTERNAL_API +#undef MLD_MULTILEVEL_BUILD +#undef MLD_NAMESPACE +#undef MLD_NAMESPACE_KL +#undef MLD_NAMESPACE_PREFIX +#undef MLD_NAMESPACE_PREFIX_KL +#undef MLD_UNION_OR_STRUCT +#undef mld_memcpy +#undef mld_memset +/* mldsa/src/packing.h */ +#undef MLD_PACKING_H +#undef mld_pack_pk +#undef mld_pack_sig_c_h +#undef mld_pack_sig_z +#undef mld_pack_sk +#undef mld_unpack_pk +#undef mld_unpack_sig +#undef mld_unpack_sk +/* mldsa/src/params.h */ +#undef MLDSA_BETA +#undef MLDSA_CRHBYTES +#undef MLDSA_CRYPTO_BYTES +#undef MLDSA_CRYPTO_PUBLICKEYBYTES +#undef MLDSA_CRYPTO_SECRETKEYBYTES +#undef MLDSA_CTILDEBYTES +#undef MLDSA_D +#undef MLDSA_ETA +#undef MLDSA_GAMMA1 +#undef MLDSA_GAMMA2 +#undef MLDSA_K +#undef MLDSA_L +#undef MLDSA_N +#undef MLDSA_OMEGA +#undef MLDSA_POLYETA_PACKEDBYTES +#undef MLDSA_POLYT0_PACKEDBYTES +#undef MLDSA_POLYT1_PACKEDBYTES +#undef MLDSA_POLYVECH_PACKEDBYTES +#undef MLDSA_POLYW1_PACKEDBYTES +#undef MLDSA_POLYZ_PACKEDBYTES +#undef MLDSA_Q +#undef MLDSA_Q_HALF +#undef MLDSA_RNDBYTES +#undef MLDSA_SEEDBYTES +#undef MLDSA_TAU +#undef MLDSA_TRBYTES +#undef MLD_PARAMS_H +/* mldsa/src/poly_kl.h */ +#undef MLD_POLYETA_UNPACK_LOWER_BOUND +#undef MLD_POLY_KL_H +#undef mld_poly_challenge +#undef mld_poly_decompose +#undef mld_poly_make_hint +#undef mld_poly_uniform_eta +#undef mld_poly_uniform_eta_4x +#undef mld_poly_uniform_gamma1 +#undef mld_poly_uniform_gamma1_4x +#undef mld_poly_use_hint +#undef mld_polyeta_pack +#undef mld_polyeta_unpack +#undef mld_polyw1_pack +#undef mld_polyz_pack +#undef mld_polyz_unpack +/* mldsa/src/polyvec.h */ +#undef MLD_POLYVEC_H +#undef mld_polymat +#undef mld_polymat_get_row +#undef mld_polyvec_matrix_expand +#undef mld_polyvec_matrix_pointwise_montgomery +#undef mld_polyveck +#undef mld_polyveck_add +#undef mld_polyveck_caddq +#undef mld_polyveck_chknorm +#undef mld_polyveck_decompose +#undef mld_polyveck_invntt_tomont +#undef mld_polyveck_make_hint +#undef mld_polyveck_ntt +#undef mld_polyveck_pack_eta +#undef mld_polyveck_pack_t0 +#undef mld_polyveck_pack_w1 +#undef mld_polyveck_pointwise_poly_montgomery +#undef mld_polyveck_power2round +#undef mld_polyveck_reduce +#undef mld_polyveck_shiftl +#undef mld_polyveck_sub +#undef mld_polyveck_unpack_eta +#undef mld_polyveck_unpack_t0 +#undef mld_polyveck_use_hint +#undef mld_polyvecl +#undef mld_polyvecl_chknorm +#undef mld_polyvecl_ntt +#undef mld_polyvecl_pack_eta +#undef mld_polyvecl_pointwise_acc_montgomery +#undef mld_polyvecl_uniform_gamma1 +#undef mld_polyvecl_unpack_eta +#undef mld_polyvecl_unpack_z +/* mldsa/src/rounding.h */ +#undef MLD_2_POW_D +#undef MLD_ROUNDING_H +#undef mld_decompose +#undef mld_make_hint +#undef mld_power2round +#undef mld_use_hint +/* mldsa/src/sign.h */ +#undef MLD_DOMAIN_SEPARATION_MAX_BYTES +#undef MLD_PREHASH_NONE +#undef MLD_PREHASH_SHA2_224 +#undef MLD_PREHASH_SHA2_256 +#undef MLD_PREHASH_SHA2_384 +#undef MLD_PREHASH_SHA2_512 +#undef MLD_PREHASH_SHA2_512_224 +#undef MLD_PREHASH_SHA2_512_256 +#undef MLD_PREHASH_SHA3_224 +#undef MLD_PREHASH_SHA3_256 +#undef MLD_PREHASH_SHA3_384 +#undef MLD_PREHASH_SHA3_512 +#undef MLD_PREHASH_SHAKE_128 +#undef MLD_PREHASH_SHAKE_256 +#undef MLD_SIGN_H +#undef mld_prepare_domain_separation_prefix +#undef mld_sign +#undef mld_sign_keypair +#undef mld_sign_keypair_internal +#undef mld_sign_open +#undef mld_sign_pk_from_sk +#undef mld_sign_signature +#undef mld_sign_signature_extmu +#undef mld_sign_signature_internal +#undef mld_sign_signature_pre_hash_internal +#undef mld_sign_signature_pre_hash_shake256 +#undef mld_sign_verify +#undef mld_sign_verify_extmu +#undef mld_sign_verify_internal +#undef mld_sign_verify_pre_hash_internal +#undef mld_sign_verify_pre_hash_shake256 + +#if !defined(MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS) +/* + * Undefine macros from MLD_CONFIG_PARAMETER_SET-generic files + */ +/* mldsa/src/ct.h */ +#undef MLD_CT_H +#undef MLD_USE_ASM_VALUE_BARRIER +#undef mld_ct_opt_blocker_u64 +/* mldsa/src/debug.h */ +#undef MLD_DEBUG_H +#undef mld_assert +#undef mld_assert_abs_bound +#undef mld_assert_abs_bound_2d +#undef mld_assert_bound +#undef mld_assert_bound_2d +#undef mld_debug_check_assert +#undef mld_debug_check_bounds +/* mldsa/src/poly.h */ +#undef MLD_INTT_BOUND +#undef MLD_NTT_BOUND +#undef MLD_POLY_H +#undef mld_poly_add +#undef mld_poly_caddq +#undef mld_poly_chknorm +#undef mld_poly_invntt_tomont +#undef mld_poly_ntt +#undef mld_poly_pointwise_montgomery +#undef mld_poly_power2round +#undef mld_poly_reduce +#undef mld_poly_shiftl +#undef mld_poly_sub +#undef mld_poly_uniform +#undef mld_poly_uniform_4x +#undef mld_polyt0_pack +#undef mld_polyt0_unpack +#undef mld_polyt1_pack +#undef mld_polyt1_unpack +/* mldsa/src/randombytes.h */ +#undef MLD_RANDOMBYTES_H +/* mldsa/src/reduce.h */ +#undef MLD_MONT +#undef MLD_REDUCE32_DOMAIN_MAX +#undef MLD_REDUCE32_RANGE_MAX +#undef MLD_REDUCE_H +/* mldsa/src/symmetric.h */ +#undef MLD_STREAM128_BLOCKBYTES +#undef MLD_STREAM256_BLOCKBYTES +#undef MLD_SYMMETRIC_H +#undef mld_xof128_absorb_once +#undef mld_xof128_ctx +#undef mld_xof128_init +#undef mld_xof128_release +#undef mld_xof128_squeezeblocks +#undef mld_xof128_x4_absorb +#undef mld_xof128_x4_ctx +#undef mld_xof128_x4_init +#undef mld_xof128_x4_release +#undef mld_xof128_x4_squeezeblocks +#undef mld_xof256_absorb_once +#undef mld_xof256_ctx +#undef mld_xof256_init +#undef mld_xof256_release +#undef mld_xof256_squeezeblocks +#undef mld_xof256_x4_absorb +#undef mld_xof256_x4_ctx +#undef mld_xof256_x4_init +#undef mld_xof256_x4_release +#undef mld_xof256_x4_squeezeblocks +/* mldsa/src/sys.h */ +#undef MLD_ALIGN +#undef MLD_ALIGN_UP +#undef MLD_ALWAYS_INLINE +#undef MLD_CET_ENDBR +#undef MLD_CT_TESTING_DECLASSIFY +#undef MLD_CT_TESTING_SECRET +#undef MLD_DEFAULT_ALIGN +#undef MLD_HAVE_INLINE_ASM +#undef MLD_INLINE +#undef MLD_MUST_CHECK_RETURN_VALUE +#undef MLD_RESTRICT +#undef MLD_STATIC_TESTABLE +#undef MLD_SYS_AARCH64 +#undef MLD_SYS_AARCH64_EB +#undef MLD_SYS_APPLE +#undef MLD_SYS_BIG_ENDIAN +#undef MLD_SYS_H +#undef MLD_SYS_LINUX +#undef MLD_SYS_LITTLE_ENDIAN +#undef MLD_SYS_PPC64LE +#undef MLD_SYS_RISCV32 +#undef MLD_SYS_RISCV64 +#undef MLD_SYS_WINDOWS +#undef MLD_SYS_X86_64 +#undef MLD_SYS_X86_64_AVX2 +/* mldsa/src/cbmc.h */ +#undef MLD_CBMC_H +#undef __contract__ +#undef __loop__ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +/* + * Undefine macros from FIPS-202 files + */ +/* mldsa/src/fips202/fips202.h */ +#undef MLD_FIPS202_FIPS202_H +#undef MLD_KECCAK_LANES +#undef SHA3_256_HASHBYTES +#undef SHA3_256_RATE +#undef SHA3_512_HASHBYTES +#undef SHA3_512_RATE +#undef SHAKE128_RATE +#undef SHAKE256_RATE +#undef mld_shake128_absorb +#undef mld_shake128_finalize +#undef mld_shake128_init +#undef mld_shake128_release +#undef mld_shake128_squeeze +#undef mld_shake256 +#undef mld_shake256_absorb +#undef mld_shake256_finalize +#undef mld_shake256_init +#undef mld_shake256_release +#undef mld_shake256_squeeze +/* mldsa/src/fips202/fips202x4.h */ +#undef MLD_FIPS202_FIPS202X4_H +#undef mld_shake128x4_absorb_once +#undef mld_shake128x4_init +#undef mld_shake128x4_release +#undef mld_shake128x4_squeezeblocks +#undef mld_shake256x4_absorb_once +#undef mld_shake256x4_init +#undef mld_shake256x4_release +#undef mld_shake256x4_squeezeblocks +/* mldsa/src/fips202/keccakf1600.h */ +#undef MLD_FIPS202_KECCAKF1600_H +#undef MLD_KECCAK_LANES +#undef MLD_KECCAK_WAY +#undef mld_keccakf1600_extract_bytes +#undef mld_keccakf1600_permute +#undef mld_keccakf1600_xor_bytes +#undef mld_keccakf1600x4_extract_bytes +#undef mld_keccakf1600x4_permute +#undef mld_keccakf1600x4_xor_bytes +#endif /* !MLD_CONFIG_FIPS202_CUSTOM_HEADER */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +/* mldsa/src/fips202/native/api.h */ +#undef MLD_FIPS202_NATIVE_API_H +#undef MLD_NATIVE_FUNC_FALLBACK +#undef MLD_NATIVE_FUNC_SUCCESS +/* mldsa/src/fips202/native/auto.h */ +#undef MLD_FIPS202_NATIVE_AUTO_H +#if defined(MLD_SYS_AARCH64) +/* + * Undefine macros from native code (FIPS202, AArch64) + */ +/* mldsa/src/fips202/native/aarch64/auto.h */ +#undef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* mldsa/src/fips202/native/aarch64/src/fips202_native_aarch64.h */ +#undef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#undef mld_keccak_f1600_x1_scalar_asm +#undef mld_keccak_f1600_x1_v84a_asm +#undef mld_keccak_f1600_x2_v84a_asm +#undef mld_keccak_f1600_x4_scalar_v8a_hybrid_asm +#undef mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm +#undef mld_keccakf1600_round_constants +/* mldsa/src/fips202/native/aarch64/x1_scalar.h */ +#undef MLD_FIPS202_AARCH64_NEED_X1_SCALAR +#undef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#undef MLD_USE_FIPS202_X1_NATIVE +/* mldsa/src/fips202/native/aarch64/x1_v84a.h */ +#undef MLD_FIPS202_AARCH64_NEED_X1_V84A +#undef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#undef MLD_USE_FIPS202_X1_NATIVE +/* mldsa/src/fips202/native/aarch64/x2_v84a.h */ +#undef MLD_FIPS202_AARCH64_NEED_X2_V84A +#undef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#undef MLD_USE_FIPS202_X4_NATIVE +/* mldsa/src/fips202/native/aarch64/x4_v8a_scalar.h */ +#undef MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID +#undef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#undef MLD_USE_FIPS202_X4_NATIVE +/* mldsa/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h */ +#undef MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID +#undef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#undef MLD_USE_FIPS202_X4_NATIVE +#endif /* MLD_SYS_AARCH64 */ +#if defined(MLD_SYS_X86_64) +/* + * Undefine macros from native code (FIPS202, x86_64) + */ +/* mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h */ +#undef MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H +#undef mld_keccakf1600x4_permute24 +/* mldsa/src/fips202/native/x86_64/xkcp.h */ +#undef MLD_FIPS202_NATIVE_X86_64_XKCP_H +#undef MLD_FIPS202_X86_64_XKCP +#undef MLD_USE_FIPS202_X4_NATIVE +#endif /* MLD_SYS_X86_64 */ +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +/* mldsa/src/native/api.h */ +#undef MLD_INTT_BOUND +#undef MLD_NATIVE_API_H +#undef MLD_NATIVE_FUNC_FALLBACK +#undef MLD_NATIVE_FUNC_SUCCESS +#undef MLD_NTT_BOUND +#undef REDUCE32_RANGE_MAX +/* mldsa/src/native/meta.h */ +#undef MLD_NATIVE_META_H +#if defined(MLD_SYS_AARCH64) +/* + * Undefine macros from native code (Arith, AArch64) + */ +/* mldsa/src/native/aarch64/meta.h */ +#undef MLD_ARITH_BACKEND_AARCH64 +#undef MLD_NATIVE_AARCH64_META_H +#undef MLD_USE_NATIVE_INTT +#undef MLD_USE_NATIVE_NTT +#undef MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_17 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_19 +#undef MLD_USE_NATIVE_POLY_CADDQ +#undef MLD_USE_NATIVE_POLY_CHKNORM +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#undef MLD_USE_NATIVE_POLY_USE_HINT_32 +#undef MLD_USE_NATIVE_POLY_USE_HINT_88 +#undef MLD_USE_NATIVE_REJ_UNIFORM +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +/* mldsa/src/native/aarch64/src/arith_native_aarch64.h */ +#undef MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN +#undef MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN +#undef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#undef mld_aarch64_intt_zetas_layer123456 +#undef mld_aarch64_intt_zetas_layer78 +#undef mld_aarch64_ntt_zetas_layer123456 +#undef mld_aarch64_ntt_zetas_layer78 +#undef mld_intt_asm +#undef mld_ntt_asm +#undef mld_poly_caddq_asm +#undef mld_poly_chknorm_asm +#undef mld_poly_decompose_32_asm +#undef mld_poly_decompose_88_asm +#undef mld_poly_pointwise_montgomery_asm +#undef mld_poly_use_hint_32_asm +#undef mld_poly_use_hint_88_asm +#undef mld_polyvecl_pointwise_acc_montgomery_l4_asm +#undef mld_polyvecl_pointwise_acc_montgomery_l5_asm +#undef mld_polyvecl_pointwise_acc_montgomery_l7_asm +#undef mld_polyz_unpack_17_asm +#undef mld_polyz_unpack_17_indices +#undef mld_polyz_unpack_19_asm +#undef mld_polyz_unpack_19_indices +#undef mld_rej_uniform_asm +#undef mld_rej_uniform_eta2_asm +#undef mld_rej_uniform_eta4_asm +#undef mld_rej_uniform_eta_table +#undef mld_rej_uniform_table +#endif /* MLD_SYS_AARCH64 */ +#if defined(MLD_SYS_X86_64) +/* + * Undefine macros from native code (Arith, X86_64) + */ +/* mldsa/src/native/x86_64/meta.h */ +#undef MLD_ARITH_BACKEND_X86_64_DEFAULT +#undef MLD_NATIVE_X86_64_META_H +#undef MLD_USE_NATIVE_INTT +#undef MLD_USE_NATIVE_NTT +#undef MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#undef MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_17 +#undef MLD_USE_NATIVE_POLYZ_UNPACK_19 +#undef MLD_USE_NATIVE_POLY_CADDQ +#undef MLD_USE_NATIVE_POLY_CHKNORM +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#undef MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#undef MLD_USE_NATIVE_POLY_USE_HINT_32 +#undef MLD_USE_NATIVE_POLY_USE_HINT_88 +#undef MLD_USE_NATIVE_REJ_UNIFORM +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +/* mldsa/src/native/x86_64/src/arith_native_x86_64.h */ +#undef MLD_AVX2_REJ_UNIFORM_BUFLEN +#undef MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN +#undef MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN +#undef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#undef mld_invntt_avx2 +#undef mld_ntt_avx2 +#undef mld_nttunpack_avx2 +#undef mld_pointwise_acc_l4_avx2 +#undef mld_pointwise_acc_l5_avx2 +#undef mld_pointwise_acc_l7_avx2 +#undef mld_pointwise_avx2 +#undef mld_poly_caddq_avx2 +#undef mld_poly_chknorm_avx2 +#undef mld_poly_decompose_32_avx2 +#undef mld_poly_decompose_88_avx2 +#undef mld_poly_use_hint_32_avx2 +#undef mld_poly_use_hint_88_avx2 +#undef mld_polyz_unpack_17_avx2 +#undef mld_polyz_unpack_19_avx2 +#undef mld_rej_uniform_avx2 +#undef mld_rej_uniform_eta2_avx2 +#undef mld_rej_uniform_eta4_avx2 +#undef mld_rej_uniform_table +/* mldsa/src/native/x86_64/src/consts.h */ +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XQ +#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV +#undef MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS +#undef MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV +#undef MLD_NATIVE_X86_64_SRC_CONSTS_H +#undef mld_qdata +#endif /* MLD_SYS_X86_64 */ +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ +#endif /* !MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/mldsa_native.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/mldsa_native.h new file mode 100644 index 0000000000..fd150a9df1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/mldsa_native.h @@ -0,0 +1,975 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_H +#define MLD_H + +/* + * Public API for mldsa-native + * + * This header defines the public API of a single build of mldsa-native. + * + * Make sure the configuration file is in the include path + * (this is "mldsa_native_config.h" by default, or MLD_CONFIG_FILE if defined). + * + * # Multi-level builds + * + * This header specifies a build of mldsa-native for a fixed security level. + * If you need multiple security levels, leave the security level unspecified + * in the configuration file and include this header multiple times, setting + * MLD_CONFIG_PARAMETER_SET accordingly for each, and #undef'ing the MLD_H + * guard to allow multiple inclusions. + * + * # Legacy configuration (deprecated) + * + * Instead of providing the config file used for the build, you can + * alternatively set the following configuration options prior to + * including this header. + * + * This method of configuration is deprecated. + * It will be removed in mldsa-native-v2. + * + * - MLD_CONFIG_API_PARAMETER_SET [required] + * + * The parameter set used for the build; 44, 65, or 87. + * + * - MLD_CONFIG_API_NAMESPACE_PREFIX [required] + * + * The namespace prefix used for the build. + * + * NOTE: + * For a multi-level build, you must include the 44/65/87 suffixes + * in MLD_CONFIG_API_NAMESPACE_PREFIX. + * + * - MLD_CONFIG_API_NO_SUPERCOP [optional] + * + * By default, this header will also expose the mldsa-native API in the + * SUPERCOP naming convention crypto_sign_xxx. If you don't want/need this, + * set MLD_CONFIG_API_NO_SUPERCOP. You must set this for a multi-level build. + * + * - MLD_CONFIG_API_CONSTANTS_ONLY [optional] + * + * If you don't want this header to expose any function declarations, + * but only constants for the sizes of key material, set + * MLD_CONFIG_API_CONSTANTS_ONLY. In this case, you don't need to set + * MLD_CONFIG_API_PARAMETER_SET or MLD_CONFIG_API_NAMESPACE_PREFIX, + * nor include a configuration. + * + * - MLD_CONFIG_API_QUALIFIER [optional] + * + * Qualifier to apply to external API. + * + ******************************************************************************/ + +/******************************* Key sizes ************************************/ + +/* Sizes of cryptographic material, per parameter set */ +/* See mldsa/src/params.h for the arithmetic expressions giving rise to these */ +/* check-magic: off */ +#define MLDSA44_SECRETKEYBYTES 2560 +#define MLDSA44_PUBLICKEYBYTES 1312 +#define MLDSA44_BYTES 2420 + +#define MLDSA65_SECRETKEYBYTES 4032 +#define MLDSA65_PUBLICKEYBYTES 1952 +#define MLDSA65_BYTES 3309 + +#define MLDSA87_SECRETKEYBYTES 4896 +#define MLDSA87_PUBLICKEYBYTES 2592 +#define MLDSA87_BYTES 4627 +/* check-magic: on */ + +/* Size of seed and randomness in bytes (level-independent) */ +#define MLDSA_SEEDBYTES 32 +#define MLDSA44_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA65_SEEDBYTES MLDSA_SEEDBYTES +#define MLDSA87_SEEDBYTES MLDSA_SEEDBYTES + +/* Size of CRH output in bytes (level-independent) */ +#define MLDSA_CRHBYTES 64 +#define MLDSA44_CRHBYTES MLDSA_CRHBYTES +#define MLDSA65_CRHBYTES MLDSA_CRHBYTES +#define MLDSA87_CRHBYTES MLDSA_CRHBYTES + +/* Size of TR output in bytes (level-independent) */ +#define MLDSA_TRBYTES 64 +#define MLDSA44_TRBYTES MLDSA_TRBYTES +#define MLDSA65_TRBYTES MLDSA_TRBYTES +#define MLDSA87_TRBYTES MLDSA_TRBYTES + +/* Size of randomness for signing in bytes (level-independent) */ +#define MLDSA_RNDBYTES 32 +#define MLDSA44_RNDBYTES MLDSA_RNDBYTES +#define MLDSA65_RNDBYTES MLDSA_RNDBYTES +#define MLDSA87_RNDBYTES MLDSA_RNDBYTES + +/* Sizes of cryptographic material, as a function of LVL=44,65,87 */ +#define MLDSA_SECRETKEYBYTES_(LVL) MLDSA##LVL##_SECRETKEYBYTES +#define MLDSA_PUBLICKEYBYTES_(LVL) MLDSA##LVL##_PUBLICKEYBYTES +#define MLDSA_BYTES_(LVL) MLDSA##LVL##_BYTES +#define MLDSA_SECRETKEYBYTES(LVL) MLDSA_SECRETKEYBYTES_(LVL) +#define MLDSA_PUBLICKEYBYTES(LVL) MLDSA_PUBLICKEYBYTES_(LVL) +#define MLDSA_BYTES(LVL) MLDSA_BYTES_(LVL) + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + +/****************************** Function API **********************************/ + +#define MLD_API_CONCAT_(x, y) x##y +#define MLD_API_CONCAT(x, y) MLD_API_CONCAT_(x, y) +#define MLD_API_CONCAT_UNDERSCORE(x, y) MLD_API_CONCAT(MLD_API_CONCAT(x, _), y) + +#if !defined(MLD_CONFIG_API_PARAMETER_SET) +/* Recommended configuration via same config file as used for the build. */ + +/* For now, we derive the legacy API configuration MLD_CONFIG_API_XXX from + * the config file. In mldsa-native-v2, this will be removed and we will + * exclusively work with MLD_CONFIG_XXX. */ + +/* You need to make sure the config file is in the include path. */ +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#define MLD_CONFIG_API_PARAMETER_SET MLD_CONFIG_PARAMETER_SET + +#if defined(MLD_CONFIG_MULTILEVEL_BUILD) +#define MLD_CONFIG_API_NAMESPACE_PREFIX \ + MLD_API_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_CONFIG_API_NAMESPACE_PREFIX MLD_CONFIG_NAMESPACE_PREFIX +#endif + +#if defined(MLD_CONFIG_NO_SUPERCOP) +#define MLD_CONFIG_API_NO_SUPERCOP +#endif + +#if defined(MLD_CONFIG_CONSTANTS_ONLY) +#define MLD_CONFIG_API_CONSTANTS_ONLY +#endif + +#if defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_CONFIG_API_QUALIFIER MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#else /* !MLD_CONFIG_API_PARAMETER_SET */ +#define MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_PARAMETER_SET */ + +#define MLD_API_NAMESPACE(sym) \ + MLD_API_CONCAT_UNDERSCORE(MLD_CONFIG_API_NAMESPACE_PREFIX, sym) + +#if defined(__GNUC__) || defined(clang) +#define MLD_API_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_API_MUST_CHECK_RETURN_VALUE +#endif + +#if defined(MLD_CONFIG_API_QUALIFIER) +#define MLD_API_QUALIFIER MLD_CONFIG_API_QUALIFIER +#else +#define MLD_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_API_CONSTANTS_ONLY) + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************************* + * Name: crypto_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: + * input random seed + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair_internal)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t seed[MLDSA_SEEDBYTES] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: + * - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output public key + * - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: If MLD_CONFIG_KEYGEN_PCT is enabled and the + * PCT check failed. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(keypair)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return -1 in that case. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_extmu + * + * Description: Computes signature. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_extmu)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use crypto_sign_signature_internal directly. + * + * Arguments: + * - uint8_t *sm: pointer to output signed message (allocated array + * with MLDSA{44,65,87}_BYTES + mlen bytes), can be + * equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(sign)( + uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as mu + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int externalmu +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_extmu)( + const uint8_t *sig, size_t siglen, const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_open + * + * Description: Verify signed message. + * + * Arguments: + * - uint8_t *m: pointer to output message (allocated array with + * smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(open)( + uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: crypto_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_internal)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *ph, size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use crypto_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_internal)( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + int hashalg +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: + * - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed secret key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(signature_pre_hash_shake256)( + uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/************************************************* + * Name: crypto_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: + * - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]: + * bit-packed public key + * + * Returns: + * - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(verify_pre_hash_shake256)( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +/* Maximum formatted domain separation message length */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +size_t MLD_API_NAMESPACE(prepare_domain_separation_prefix)( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg); + +/************************************************* + * Name: crypto_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[CRYPTO_SECRETKEYBYTES]: input secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_API_QUALIFIER +MLD_API_MUST_CHECK_RETURN_VALUE +int MLD_API_NAMESPACE(pk_from_sk)( + uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)], + const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)] +#ifdef MLD_CONFIG_CONTEXT_PARAMETER + , + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context +#endif +); + +#ifdef __cplusplus +} +#endif + +/****************************** SUPERCOP API *********************************/ + +#if !defined(MLD_CONFIG_API_NO_SUPERCOP) +/* Export API in SUPERCOP naming scheme CRYPTO_xxx / crypto_sign_xxx */ +#define CRYPTO_SECRETKEYBYTES MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_PUBLICKEYBYTES MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET) +#define CRYPTO_BYTES MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET) + +#define crypto_sign_keypair MLD_API_NAMESPACE(keypair) +#define crypto_sign_signature MLD_API_NAMESPACE(signature) +#define crypto_sign MLD_API_NAMESPACE(sign) +#define crypto_sign_verify MLD_API_NAMESPACE(verify) +#define crypto_sign_open MLD_API_NAMESPACE(open) + +#else /* !MLD_CONFIG_API_NO_SUPERCOP */ + +/* If the SUPERCOP API is not needed, we can undefine the various helper macros + * above. Otherwise, they are needed for lazy evaluation of crypto_sign_xxx. */ +#if !defined(MLD_API_LEGACY_CONFIG) +#undef MLD_CONFIG_API_PARAMETER_SET +#undef MLD_CONFIG_API_NAMESPACE_PREFIX +#undef MLD_CONFIG_API_NO_SUPERCOP +#undef MLD_CONFIG_API_CONSTANTS_ONLY +#undef MLD_CONFIG_API_QUALIFIER +#endif /* !MLD_API_LEGACY_CONFIG */ + +#undef MLD_API_CONCAT +#undef MLD_API_CONCAT_ +#undef MLD_API_CONCAT_UNDERSCORE +#undef MLD_API_NAMESPACE +#undef MLD_API_MUST_CHECK_RETURN_VALUE +#undef MLD_API_QUALIFIER +#undef MLD_API_LEGACY_CONFIG + +#endif /* MLD_CONFIG_API_NO_SUPERCOP */ +#endif /* !MLD_CONFIG_API_CONSTANTS_ONLY */ + + +/***************************** Memory Usage **********************************/ + +/* + * By default mldsa-native performs all memory allocations on the stack. + * Alternatively, mldsa-native supports custom allocation of large structures + * through the `MLD_CONFIG_CUSTOM_ALLOC_FREE` configuration option. + * See mldsa_native_config.h for details. + * + * `MLD_TOTAL_ALLOC_{44,65,87}_{KEYPAIR,SIGN,VERIFY}` indicates the maximum + * (accumulative) allocation via MLD_ALLOC for each parameter set and operation. + * Note that some stack allocation remains even + * when using custom allocators, so these values are lower than total stack + * usage with the default stack-only allocation. + * + * These constants may be used to implement custom allocations using a + * fixed-sized buffer and a simple allocator (e.g., bump allocator). + */ +/* check-magic: off */ +#if defined(MLD_API_LEGACY_CONFIG) || !defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 45248 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 56640 +#define MLD_TOTAL_ALLOC_44_SIGN 52896 +#define MLD_TOTAL_ALLOC_44_VERIFY 38816 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 71872 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 85856 +#define MLD_TOTAL_ALLOC_65_SIGN 80576 +#define MLD_TOTAL_ALLOC_65_VERIFY 62432 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 112832 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 130816 +#define MLD_TOTAL_ALLOC_87_SIGN 123584 +#define MLD_TOTAL_ALLOC_87_VERIFY 99552 +#else /* MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM */ +#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 32992 +#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 36192 +#define MLD_TOTAL_ALLOC_44_SIGN 32448 +#define MLD_TOTAL_ALLOC_44_VERIFY 22464 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 46304 +#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 50048 +#define MLD_TOTAL_ALLOC_65_SIGN 44768 +#define MLD_TOTAL_ALLOC_65_VERIFY 30720 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 62688 +#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 66336 +#define MLD_TOTAL_ALLOC_87_SIGN 59104 +#define MLD_TOTAL_ALLOC_87_VERIFY 41216 +#endif /* !(MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM) */ +/* check-magic: on */ + +/* + * MLD_TOTAL_ALLOC_*_KEYPAIR adapts based on MLD_CONFIG_KEYGEN_PCT. + * For legacy config, we don't know which options are used, so assume + * the worst case (PCT enabled). + */ +#if defined(MLD_API_LEGACY_CONFIG) || defined(MLD_CONFIG_KEYGEN_PCT) +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_PCT +#else +#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT +#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT +#endif + +#define MLD_MAX3_(a, b, c) \ + ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c))) + +/* + * `MLD_TOTAL_ALLOC_{44,65,87}` is the maximum across all operations for each + * parameter set. + */ +#define MLD_TOTAL_ALLOC_44 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_44_KEYPAIR, MLD_TOTAL_ALLOC_44_SIGN, \ + MLD_TOTAL_ALLOC_44_VERIFY) +#define MLD_TOTAL_ALLOC_65 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_65_KEYPAIR, MLD_TOTAL_ALLOC_65_SIGN, \ + MLD_TOTAL_ALLOC_65_VERIFY) +#define MLD_TOTAL_ALLOC_87 \ + MLD_MAX3_(MLD_TOTAL_ALLOC_87_KEYPAIR, MLD_TOTAL_ALLOC_87_SIGN, \ + MLD_TOTAL_ALLOC_87_VERIFY) + +#endif /* !MLD_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/mldsa_native_config.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/mldsa_native_config.h new file mode 100644 index 0000000000..25dc887718 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/mldsa_native_config.h @@ -0,0 +1,723 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_CONFIG_H +#define MLD_CONFIG_H + +/****************************************************************************** + * Name: MLD_CONFIG_PARAMETER_SET + * + * Description: Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * If you want to support multiple parameter sets, build the + * library multiple times and set MLD_CONFIG_MULTILEVEL_BUILD. + * See MLD_CONFIG_MULTILEVEL_BUILD for how to do this while + * minimizing code duplication. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of the default configuration file mldsa/mldsa_native_config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * then configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + * + *****************************************************************************/ +/* #define MLD_CONFIG_FILE "mldsa_native_config.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_NAMESPACE_PREFIX + * + * Description: The prefix to use to namespace global symbols from mldsa/. + * + * In a multi-level build, level-dependent symbols will + * additionally be prefixed with the parameter set (44/65/87). + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_NAMESPACE_PREFIX) +#define MLD_CONFIG_NAMESPACE_PREFIX MLD_DEFAULT_NAMESPACE_PREFIX +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_BUILD + * + * Description: Set this if the build is part of a multi-level build supporting + * multiple parameter sets. + * + * If you need only a single parameter set, keep this unset. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them. + * + * See examples/multilevel_build for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_BUILD */ + +/****************************************************************************** + * Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_EXTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_RANDOMIZED_API + * + * Description: If this option is set, mldsa-native will be built without the + * randomized API functions (crypto_sign_keypair, + * crypto_sign, crypto_sign_signature, and + * crypto_sign_signature_extmu). + * This allows users to build mldsa-native without providing a + * randombytes() implementation if they only need the + * internal deterministic API + * (crypto_sign_keypair_internal, crypto_sign_signature_internal). + * + * NOTE: This option is incompatible with MLD_CONFIG_KEYGEN_PCT + * as the current PCT implementation requires + * crypto_sign_signature(). + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_RANDOMIZED_API */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_SUPERCOP + * + * Description: By default, mldsa_native.h exposes the mldsa-native API in the + * SUPERCOP naming convention (crypto_sign_xxx). If you don't need + * this, set MLD_CONFIG_NO_SUPERCOP. + * + * NOTE: You must set this for a multi-level build as the SUPERCOP + * naming does not disambiguate between the parameter sets. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_SUPERCOP */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONSTANTS_ONLY + * + * Description: If you only need the size constants (MLDSA_PUBLICKEYBYTES, etc.) + * but no function declarations, set MLD_CONFIG_CONSTANTS_ONLY. + * + * This only affects the public header mldsa_native.h, not + * the implementation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONSTANTS_ONLY */ + +/****************************************************************************** + * + * Build-only configuration options + * + * The remaining configurations are build-options only. + * They do not affect the API described in mldsa_native.h. + * + *****************************************************************************/ + +#if defined(MLD_BUILD_INTERNAL) +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_WITH_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, all MLD_CONFIG_PARAMETER_SET-independent + * code will be included in the build, including code needed only + * for other parameter sets. + * + * Example: TODO: add example + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_WITH_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_NO_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, no MLD_CONFIG_PARAMETER_SET-independent code + * will be included in the build. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * + * Description: This is only relevant for single compilation unit (SCU) + * builds of mldsa-native. In this case, it determines whether + * directives defined in parameter-set-independent headers should + * be #undef'ined or not at the of the SCU file. This is needed + * in multilevel builds. + * + * See examples/multilevel_build_native for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * + * Description: Determines whether an native arithmetic backend should be used. + * + * The arithmetic backend covers performance critical functions + * such as the number-theoretic transform (NTT). + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the arithmetic backend to be use is + * determined by MLD_CONFIG_ARITH_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_ARITH_BACKEND_FILE + * + * Description: The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * + * Description: Determines whether an native FIPS202 backend should be used. + * + * The FIPS202 backend covers 1x/2x/4x-fold Keccak-f1600, which is + * the performance bottleneck of SHA3 and SHAKE. + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the FIPS202 backend to be use is + * determined by MLD_CONFIG_FIPS202_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_BACKEND_FILE + * + * Description: The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202X4_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202-X4 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202x4.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ZEROIZE + * + * Description: In compliance with @[FIPS204, Section 3.6.3], mldsa-native, + * zeroizes intermediate stack buffers before returning from + * function calls. + * + * Set this option and define `mld_zeroize` if you want to + * use a custom method to zeroize intermediate stack buffers. + * The default implementation uses SecureZeroMemory on Windows + * and a memset + compiler barrier otherwise. If neither of those + * is available on the target platform, compilation will fail, + * and you will need to use MLD_CONFIG_CUSTOM_ZEROIZE to provide + * a custom implementation of `mld_zeroize()`. + * + * WARNING: + * The explicit stack zeroization conducted by mldsa-native + * reduces the likelihood of data leaking on the stack, but + * does not eliminate it! The C standard makes no guarantee about + * where a compiler allocates structures and whether/where it makes + * copies of them. Also, in addition to entire structures, there + * may also be potentially exploitable leakage of individual values + * on the stack. + * + * If you need bullet-proof zeroization of the stack, you need to + * consider additional measures instead of what this feature + * provides. In this case, you can set mld_zeroize to a + * no-op. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void mld_zeroize(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * Description: mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to provided by the + * consumer. + * + * If this option is not set, mldsa-native expects a function + * int randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mld_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_RANDOMBYTES + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) + { + ... your implementation ... + return 0; + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + * + * Description: mldsa-native backends may rely on specific hardware features. + * Those backends will only be included in an mldsa-native build + * if support for the respective features is enabled at + * compile-time. However, when building for a heteroneous set + * of CPUs to run the resulting binary/library on, feature + * detection at _runtime_ is needed to decided whether a backend + * can be used or not. + * + * Set this option and define `mld_sys_check_capability` if you + * want to use a custom method to dispatch between implementations. + * + * Return value 1 indicates that a capability is supported. + * Return value 0 indicates that a capability is not supported. + * + * If this option is not set, mldsa-native uses compile-time + * feature detection only to decide which backend to use. + * + * If you compile mldsa-native on a system with different + * capabilities than the system that the resulting binary/library + * will be run on, you must use this option. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) + { + ... your implementation ... + } +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ALLOC_FREE [EXPERIMENTAL] + * + * Description: Set this option and define `MLD_CUSTOM_ALLOC` and + * `MLD_CUSTOM_FREE` if you want to use custom allocation for + * large local structures or buffers. + * + * By default, all buffers/structures are allocated on the stack. + * If this option is set, most of them will be allocated via + * MLD_CUSTOM_ALLOC. + * + * Parameters to MLD_CUSTOM_ALLOC: + * - T* v: Target pointer to declare. + * - T: Type of structure to be allocated + * - N: Number of elements to be allocated. + * + * Parameters to MLD_CUSTOM_FREE: + * - T* v: Target pointer to free. May be NULL. + * - T: Type of structure to be freed. + * - N: Number of elements to be freed. + * + * WARNING: This option is experimental! + * Its scope, configuration and function/macro signatures may + * change at any time. We expect a stable API for v2. + * + * NOTE: Even if this option is set, some allocations further down + * the call stack will still be made from the stack. Those will + * likely be added to the scope of this option in the future. + * + * NOTE: MLD_CUSTOM_ALLOC need not guarantee a successful + * allocation nor include error handling. Upon failure, the + * target pointer should simply be set to NULL. The calling + * code will handle this case and invoke MLD_CUSTOM_FREE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ALLOC_FREE + #if !defined(__ASSEMBLER__) + #include + #define MLD_CUSTOM_ALLOC(v, T, N) \ + T* (v) = (T *)aligned_alloc(MLD_DEFAULT_ALIGN, \ + MLD_ALIGN_UP(sizeof(T) * (N))) + #define MLD_CUSTOM_FREE(v, T, N) free(v) + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMCPY + * + * Description: Set this option and define `mld_memcpy` if you want to + * use a custom method to copy memory instead of the standard + * library memcpy function. + * + * The custom implementation must have the same signature and + * behavior as the standard memcpy function: + * void *mld_memcpy(void *dest, const void *src, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMCPY + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMSET + * + * Description: Set this option and define `mld_memset` if you want to + * use a custom method to set memory instead of the standard + * library memset function. + * + * The custom implementation must have the same signature and + * behavior as the standard memset function: + * void *mld_memset(void *s, int c, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMSET + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memset(void *s, int c, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_INTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of internal API. + * + * The primary use case for this option are single-CU builds, + * in which case this option can be set to `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_INTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CT_TESTING_ENABLED + * + * Description: If set, mldsa-native annotates data as secret / public using + * valgrind's annotations VALGRIND_MAKE_MEM_UNDEFINED and + * VALGRIND_MAKE_MEM_DEFINED, enabling various checks for secret- + * dependent control flow of variable time execution (depending + * on the exact version of valgrind installed). + * + *****************************************************************************/ +/* #define MLD_CONFIG_CT_TESTING_ENABLED */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * and MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT + * + * Description: Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, crypto_sign_keypair_internal and + * crypto_sign_keypair will return a non-zero error code if the + * PCT failed. + * + * NOTE: This feature will drastically lower the performance of + * key generation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * Description: If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "src/src.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Description: Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * NOTE: Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + * + *****************************************************************************/ +/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER + * + * Description: Set this to add a context parameter that is provided to public + * API functions and is then available in custom callbacks. + * + * The type of the context parameter is configured via + * MLD_CONFIG_CONTEXT_PARAMETER_TYPE. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONTEXT_PARAMETER_TYPE + * + * Description: Set this to define the type for the context parameter used by + * MLD_CONFIG_CONTEXT_PARAMETER. + * + * This is only relevant if MLD_CONFIG_CONTEXT_PARAMETER is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONTEXT_PARAMETER_TYPE void* */ + +/****************************************************************************** + * Name: MLD_CONFIG_REDUCE_RAM [EXPERIMENTAL] + * + * Description: Set this to reduce RAM usage. + * This trades memory for performance. + * + * For expected memory usage, see the MLD_TOTAL_ALLOC_* constants + * defined in mldsa_native.h. + * + * This option is useful for embedded systems with tight RAM + * constraints but relaxed performance requirements. + * + * WARNING: This option is experimental! + * CBMC proofs do not currently cover this configuration option. + * Its scope and configuration may change at any time. + * + *****************************************************************************/ +/* #define MLD_CONFIG_REDUCE_RAM */ + +/************************* Config internals ********************************/ + +#endif /* MLD_BUILD_INTERNAL */ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace is + * + * PQCP_MLDSA_NATIVE_MLDSA_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_ + */ + +#if MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65 +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87 +#endif + +#endif /* !MLD_CONFIG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/cbmc.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/cbmc.h new file mode 100644 index 0000000000..8ed1ecb06b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/cbmc.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_CBMC_H +#define MLD_CBMC_H +/*************************************************** + * Basic replacements for __CPROVER_XXX contracts + ***************************************************/ +#ifndef CBMC + +#define __contract__(x) +#define __loop__(x) +#define cassert(x) + +#else /* !CBMC */ + +#include + +#define __contract__(x) x +#define __loop__(x) x + +/* https://diffblue.github.io/cbmc/contracts-assigns.html */ +#define assigns(...) __CPROVER_assigns(__VA_ARGS__) + +/* https://diffblue.github.io/cbmc/contracts-requires-ensures.html */ +#define requires(...) __CPROVER_requires(__VA_ARGS__) +#define ensures(...) __CPROVER_ensures(__VA_ARGS__) +/* https://diffblue.github.io/cbmc/contracts-loops.html */ +#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__) +#define decreases(...) __CPROVER_decreases(__VA_ARGS__) +/* cassert to avoid confusion with in-built assert */ +#define cassert(x) __CPROVER_assert(x, "cbmc assertion failed") +#define assume(...) __CPROVER_assume(__VA_ARGS__) + +/*************************************************** + * Macros for "expression" forms that may appear + * _inside_ top-level contracts. + ***************************************************/ + +/* + * function return value - useful inside ensures + * https://diffblue.github.io/cbmc/contracts-functions.html + */ +#define return_value (__CPROVER_return_value) + +/* + * assigns l-value targets + * https://diffblue.github.io/cbmc/contracts-assigns.html + */ +#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__) +#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__) +#define same_object(...) __CPROVER_same_object(__VA_ARGS__) + +/* + * Pointer-related predicates + * https://diffblue.github.io/cbmc/contracts-memory-predicates.html + */ +#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__) +#define readable(...) __CPROVER_r_ok(__VA_ARGS__) +#define writeable(...) __CPROVER_w_ok(__VA_ARGS__) + +/* Maximum supported buffer size + * + * Larger buffers may be supported, but due to internal modeling constraints + * in CBMC, the proofs of memory- and type-safety won't be able to run. + * + * If you find yourself in need for a buffer size larger than this, + * please contact the maintainers, so we can prioritize work to relax + * this somewhat artificial bound. + */ +#define MLD_MAX_BUFFER_SIZE (SIZE_MAX >> 12) + + +/* + * History variables + * https://diffblue.github.io/cbmc/contracts-history-variables.html + */ +#define old(...) __CPROVER_old(__VA_ARGS__) +#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__) + +/* + * Quantifiers + * Note that the range on qvar is _exclusive_ between qvar_lb .. qvar_ub + * https://diffblue.github.io/cbmc/contracts-quantifiers.html + */ + +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define forall(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> (predicate) \ + } + +#define exists(qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_exists \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) && (predicate) \ + } +/* clang-format on */ + +/*************************************************** + * Convenience macros for common contract patterns + ***************************************************/ +/* + * Prevent clang-format from corrupting CBMC's special ==> operator + */ +/* clang-format off */ +#define CBMC_CONCAT_(left, right) left##right +#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right) + +#define array_bound_core(qvar, qvar_lb, qvar_ub, array_var, \ + value_lb, value_ub) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + (((int)(value_lb) <= ((array_var)[(qvar)])) && \ + (((array_var)[(qvar)]) < (int)(value_ub))) \ + } + +#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \ + array_bound_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (qvar_lb), \ + (qvar_ub), (array_var), (value_lb), (value_ub)) + +#define array_unchanged_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (int32_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged(array_var, N) \ + array_unchanged_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) + +#define array_unchanged_u64_core(qvar, qvar_lb, qvar_ub, array_var) \ + __CPROVER_forall \ + { \ + unsigned qvar; \ + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ + ((array_var)[(qvar)]) == (old(* (uint64_t (*)[(qvar_ub)])(array_var)))[(qvar)] \ + } + +#define array_unchanged_u64(array_var, N) \ + array_unchanged_u64_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var)) +/* clang-format on */ + +/* Wrapper around array_bound operating on absolute values. + * + * The absolute value bound `k` is exclusive. + * + * Note that since the lower bound in array_bound is inclusive, we have to + * raise it by 1 here. + */ +#define array_abs_bound(arr, lb, ub, k) \ + array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k)) + +#endif /* CBMC */ + +#endif /* !MLD_CBMC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/common.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/common.h new file mode 100644 index 0000000000..4a5bc8109d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/common.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_COMMON_H +#define MLD_COMMON_H + +#define MLD_BUILD_INTERNAL + +#if defined(MLD_CONFIG_FILE) +#include MLD_CONFIG_FILE +#else +#include "mldsa_native_config.h" +#endif + +#include "params.h" +#include "sys.h" + +/* Internal and public API have external linkage by default, but + * this can be overwritten by the user, e.g. for single-CU builds. */ +#if !defined(MLD_CONFIG_INTERNAL_API_QUALIFIER) +#define MLD_INTERNAL_API +#else +#define MLD_INTERNAL_API MLD_CONFIG_INTERNAL_API_QUALIFIER +#endif + +#if !defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER) +#define MLD_EXTERNAL_API +#else +#define MLD_EXTERNAL_API MLD_CONFIG_EXTERNAL_API_QUALIFIER +#endif + +#if defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) || \ + defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) +#define MLD_MULTILEVEL_BUILD +#endif + +#define MLD_CONCAT_(x1, x2) x1##x2 +#define MLD_CONCAT(x1, x2) MLD_CONCAT_(x1, x2) + +#if defined(MLD_MULTILEVEL_BUILD) +#define MLD_ADD_PARAM_SET(s) MLD_CONCAT(s, MLD_CONFIG_PARAMETER_SET) +#else +#define MLD_ADD_PARAM_SET(s) s +#endif + +#define MLD_NAMESPACE_PREFIX MLD_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, _) +#define MLD_NAMESPACE_PREFIX_KL \ + MLD_CONCAT(MLD_ADD_PARAM_SET(MLD_CONFIG_NAMESPACE_PREFIX), _) + +/* Functions are prefixed by MLD_CONFIG_NAMESPACE_PREFIX. + * + * If multiple parameter sets are used, functions depending on the parameter + * set are additionally prefixed with 44/65/87. See mldsa_native_config.h. + * + * Example: If MLD_CONFIG_NAMESPACE_PREFIX is PQCP_MLDSA_NATIVE, then + * MLD_NAMESPACE_KL(keypair) becomes PQCP_MLDSA_NATIVE44_keypair/ + * PQCP_MLDSA_NATIVE65_keypair/PQCP_MLDSA_NATIVE87_keypair. + */ +#define MLD_NAMESPACE(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX, s) +#define MLD_NAMESPACE_KL(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX_KL, s) + +/* On Apple platforms, we need to emit leading underscore + * in front of assembly symbols. We thus introducee a separate + * namespace wrapper for ASM symbols. */ +#if !defined(__APPLE__) +#define MLD_ASM_NAMESPACE(sym) MLD_NAMESPACE(sym) +#else +#define MLD_ASM_NAMESPACE(sym) MLD_CONCAT(_, MLD_NAMESPACE(sym)) +#endif + +/* + * On X86_64 if control-flow protections (CET) are enabled (through + * -fcf-protection=), we add an endbr64 instruction at every global function + * label. See sys.h for more details + */ +#if defined(MLD_SYS_X86_64) +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : MLD_CET_ENDBR +#else +#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : +#endif + +/* We aim to simplify the user's life by supporting builds where + * all source files are included, even those that are not needed. + * Those files are appropriately guarded and will be empty when unneeded. + * The following is to avoid compilers complaining about this. */ +#define MLD_EMPTY_CU(s) extern int MLD_NAMESPACE_KL(empty_cu_##s); + +/* MLD_CONFIG_NO_ASM takes precedence over MLD_USE_NATIVE_XXX */ +#if defined(MLD_CONFIG_NO_ASM) +#undef MLD_CONFIG_USE_NATIVE_BACKEND_ARITH +#undef MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, but MLD_CONFIG_ARITH_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, but MLD_CONFIG_FIPS202_BACKEND_FILE is not. +#endif + +#if defined(MLD_CONFIG_NO_RANDOMIZED_API) && defined(MLD_CONFIG_KEYGEN_PCT) +#error Bad configuration: MLD_CONFIG_NO_RANDOMIZED_API is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires crypto_sign_signature() +#endif + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +#include MLD_CONFIG_ARITH_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ + +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +#include MLD_CONFIG_FIPS202_BACKEND_FILE +/* Include to enforce consistency of API and implementation, + * and conduct sanity checks on the backend. + * + * Keep this _after_ the inclusion of the backend; otherwise, + * the sanity checks won't have an effect. */ +#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__) +#include "fips202/native/api.h" +#endif +#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ + +#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER) +#define MLD_FIPS202_HEADER_FILE "fips202/fips202.h" +#else +#define MLD_FIPS202_HEADER_FILE MLD_CONFIG_FIPS202_CUSTOM_HEADER +#endif + +#if !defined(MLD_CONFIG_FIPS202X4_CUSTOM_HEADER) +#define MLD_FIPS202X4_HEADER_FILE "fips202/fips202x4.h" +#else +#define MLD_FIPS202X4_HEADER_FILE MLD_CONFIG_FIPS202X4_CUSTOM_HEADER +#endif + +/* Standard library function replacements */ +#if !defined(__ASSEMBLER__) +#if !defined(MLD_CONFIG_CUSTOM_MEMCPY) +#include +#define mld_memcpy memcpy +#endif + +#if !defined(MLD_CONFIG_CUSTOM_MEMSET) +#include +#define mld_memset memset +#endif + +/* Allocation macros for large local structures + * + * MLD_ALLOC(v, T, N) declares T *v and attempts to point it to an T[N] + * MLD_FREE(v, T, N) zeroizes and frees the allocation + * + * Default implementation uses stack allocation. + * Can be overridden by setting the config option MLD_CONFIG_CUSTOM_ALLOC_FREE + * and defining MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE. + */ +#if defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) != \ + (defined(MLD_CUSTOM_ALLOC) && defined(MLD_CUSTOM_FREE)) +#error Bad configuration: MLD_CONFIG_CUSTOM_ALLOC_FREE must be set together with MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE +#endif + +/* + * If the integration wants to provide a context parameter for use in + * platform-specific hooks, then it should define this parameter. + * + * The MLD_CONTEXT_PARAMETERS_n macros are intended to be used with macros + * defining the function names and expand to either pass or discard the context + * argument as required by the current build. If there is no context parameter + * requested then these are removed from the prototypes and from all calls. + */ +#ifdef MLD_CONFIG_CONTEXT_PARAMETER +#define MLD_CONTEXT_PARAMETERS_0(context) (context) +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0, context) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1, context) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) \ + (arg0, arg1, arg2, context) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3, context) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4, context) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, context) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, context) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, context) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, context) +#else /* MLD_CONFIG_CONTEXT_PARAMETER */ +#define MLD_CONTEXT_PARAMETERS_0(context) () +#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0) +#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1) +#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) (arg0, arg1, arg2) +#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \ + (arg0, arg1, arg2, arg3) +#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \ + (arg0, arg1, arg2, arg3, arg4) +#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5) +#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6) +#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) +#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \ + arg7, arg8, context) \ + (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) +#endif /* !MLD_CONFIG_CONTEXT_PARAMETER */ + +#if defined(MLD_CONFIG_CONTEXT_PARAMETER_TYPE) != \ + defined(MLD_CONFIG_CONTEXT_PARAMETER) +#error MLD_CONFIG_CONTEXT_PARAMETER_TYPE must be defined if and only if MLD_CONFIG_CONTEXT_PARAMETER is defined +#endif + +#if !defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) +/* Default: stack allocation */ + +#define MLD_ALLOC(v, T, N, context) \ + MLD_ALIGN T mld_alloc_##v[N]; \ + T *v = mld_alloc_##v + +/* TODO: This leads to a circular dependency between common and ct.h + * It just works out before we're at the end of the file, but it's still + * prone to issues in the future. */ +#include "ct.h" +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + mld_zeroize(mld_alloc_##v, sizeof(mld_alloc_##v)); \ + (v) = NULL; \ + } while (0) + +#else /* !MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* Custom allocation */ + +/* + * The indirection here is necessary to use MLD_CONTEXT_PARAMETERS_3 here. + */ +#define MLD_APPLY(f, args) f args + +#define MLD_ALLOC(v, T, N, context) \ + MLD_APPLY(MLD_CUSTOM_ALLOC, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)) + +#define MLD_FREE(v, T, N, context) \ + do \ + { \ + if (v != NULL) \ + { \ + mld_zeroize(v, sizeof(T) * (N)); \ + MLD_APPLY(MLD_CUSTOM_FREE, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)); \ + v = NULL; \ + } \ + } while (0) + +#endif /* MLD_CONFIG_CUSTOM_ALLOC_FREE */ + +/* + * We are facing severe CBMC performance issues when using unions. + * As a temporary workaround, we use unions only when MLD_CONFIG_REDUCE_RAM is + * set. + * TODO: Remove the workaround once + * https://github.com/diffblue/cbmc/issues/8813 + * is resolved + */ +#if defined(MLD_CONFIG_REDUCE_RAM) +#define MLD_UNION_OR_STRUCT union +#else +#define MLD_UNION_OR_STRUCT struct +#endif + +/****************************** Error codes ***********************************/ + +/* Generic failure condition */ +#define MLD_ERR_FAIL -1 +/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is defined and the provided MLD_CUSTOM_ALLOC can fail. */ +#define MLD_ERR_OUT_OF_MEMORY -2 +/* An rng failure occured. Might be due to insufficient entropy or + * system misconfiguration. */ +#define MLD_ERR_RNG_FAIL -3 + + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_COMMON_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/ct.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/ct.c new file mode 100644 index 0000000000..010b1a52a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/ct.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include "ct.h" + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +/* + * Masking value used in constant-time functions from + * ct.h to block the compiler's range analysis and + * thereby reduce the risk of compiler-introduced branches. + */ +volatile uint64_t mld_ct_opt_blocker_u64 = 0; + +#else /* !MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(ct) + +#endif /* !(!MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/ct.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/ct.h new file mode 100644 index 0000000000..c307456468 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/ct.h @@ -0,0 +1,366 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [libmceliece] + * libmceliece implementation of Classic McEliece + * Bernstein, Chou + * https://lib.mceliece.org/ + * + * - [optblocker] + * PQC forum post on opt-blockers using volatile globals + * Daniel J. Bernstein + * https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ + */ + +#ifndef MLD_CT_H +#define MLD_CT_H + +#include +#include "cbmc.h" +#include "common.h" + +/* Constant-time comparisons and conditional operations + + We reduce the risk for compilation into variable-time code + through the use of 'value barriers'. + + Functionally, a value barrier is a no-op. To the compiler, however, + it constitutes an arbitrary modification of its input, and therefore + harden's value propagation and range analysis. + + We consider two approaches to implement a value barrier: + - An empty inline asm block which marks the target value as clobbered. + - XOR'ing with the value of a volatile global that's set to 0; + see @[optblocker] for a discussion of this idea, and + @[libmceliece, inttypes/crypto_intN.h] for an implementation. + + The first approach is cheap because it only prevents the compiler + from reasoning about the value of the variable past the barrier, + but does not directly generate additional instructions. + + The second approach generates redundant loads and XOR operations + and therefore comes at a higher runtime cost. However, it appears + more robust towards optimization, as compilers should never drop + a volatile load. + + We use the empty-ASM value barrier for GCC and clang, and fall + back to the global volatile barrier otherwise. + + The global value barrier can be forced by setting + MLD_CONFIG_NO_ASM_VALUE_BARRIER. + +*/ + +#if defined(MLD_HAVE_INLINE_ASM) && !defined(MLD_CONFIG_NO_ASM_VALUE_BARRIER) +#define MLD_USE_ASM_VALUE_BARRIER +#endif + + +#if !defined(MLD_USE_ASM_VALUE_BARRIER) +/* + * Declaration of global volatile that the global value barrier + * is loading from and masking with. + */ +#define mld_ct_opt_blocker_u64 MLD_NAMESPACE(ct_opt_blocker_u64) +extern volatile uint64_t mld_ct_opt_blocker_u64; + + +/* Helper functions for obtaining global masks of various sizes */ + +/* This contract is not proved but treated as an axiom. + * + * Its validity relies on the assumption that the global opt-blocker + * constant mld_ct_opt_blocker_u64 is not modified. + */ +static MLD_INLINE uint64_t mld_ct_get_optblocker_u64(void) +__contract__(ensures(return_value == 0)) { return mld_ct_opt_blocker_u64; } + +static MLD_INLINE int64_t mld_ct_get_optblocker_i64(void) +__contract__(ensures(return_value == 0)) { return (int64_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint32_t mld_ct_get_optblocker_u32(void) +__contract__(ensures(return_value == 0)) { return (uint32_t)mld_ct_get_optblocker_u64(); } + +static MLD_INLINE uint8_t mld_ct_get_optblocker_u8(void) +__contract__(ensures(return_value == 0)) { return (uint8_t)mld_ct_get_optblocker_u64(); } + +/* Opt-blocker based implementation of value barriers */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_i64()); } + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u32()); } + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u8()); } + + +#else /* !MLD_USE_ASM_VALUE_BARRIER */ +static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} + +static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b) +__contract__(ensures(return_value == b)) +{ + __asm__ volatile("" : "+r"(b)); + return b; +} +#endif /* MLD_USE_ASM_VALUE_BARRIER */ + +#ifdef CBMC +#pragma CPROVER check push +#pragma CPROVER check disable "conversion" +#endif + +/************************************************* + * Name: mld_cast_uint32_to_int32 + * + * Description: Cast uint32 value to int32 + * + * Returns: For uint32_t x, the unique y in int32_t + * so that x == y mod 2^32. + * + * Concretely: + * - x < 2^31: returns x + * - x >= 2^31: returns x - 2^31 + * + **************************************************/ +static MLD_ALWAYS_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x) +{ + /* + * PORTABILITY: This relies on uint32_t -> int32_t + * being implemented as the inverse of int32_t -> uint32_t, + * which is implementation-defined (C99 6.3.1.3 (3)) + * CBMC (correctly) fails to prove this conversion is OK, + * so we have to suppress that check here + */ + return (int32_t)x; +} + +#ifdef CBMC +#pragma CPROVER check pop +#endif + + +/************************************************* + * Name: mld_cast_int64_to_uint32 + * + * Description: Cast int64 value to uint32 as per C standard. + * + * Returns: For int64_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int64_to_uint32(int64_t x) +{ + return (uint32_t)(x & (int64_t)UINT32_MAX); +} + +/************************************************* + * Name: mld_cast_int32_to_uint32 + * + * Description: Cast int32 value to uint32 as per C standard. + * + * Returns: For int32_t x, the unique y in uint32_t + * so that x == y mod 2^32. + **************************************************/ +static MLD_ALWAYS_INLINE uint32_t mld_cast_int32_to_uint32(int32_t x) +{ + return mld_cast_int64_to_uint32((int64_t)x); +} + +/************************************************* + * Name: mld_ct_sel_int32 + * + * Description: Functionally equivalent to cond ? a : b, + * but implemented with guards against + * compiler-introduced branches. + * + * Arguments: int32_t a: First alternative + * int32_t b: Second alternative + * uint32_t cond: Condition variable. + * + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_sel_int32(int32_t a, int32_t b, uint32_t cond) +__contract__( + requires(cond == 0x0 || cond == 0xFFFFFFFF) + ensures(return_value == (cond ? a : b)) +) +{ + uint32_t au = mld_cast_int32_to_uint32(a); + uint32_t bu = mld_cast_int32_to_uint32(b); + uint32_t res = bu ^ (mld_value_barrier_u32(cond) & (au ^ bu)); + return mld_cast_uint32_to_int32(res); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u32 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_nonzero_u32(uint32_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFFFFFFFF))) +{ + int64_t tmp = mld_value_barrier_i64(-((int64_t)x)); + tmp >>= 32; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_cmask_nonzero_u8 + * + * Description: Return 0 if input is zero, and -1 otherwise. + * + * Arguments: uint8_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint8_t mld_ct_cmask_nonzero_u8(uint8_t x) +__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFF))) +{ + uint32_t mask = mld_ct_cmask_nonzero_u32((uint32_t)x); + return (uint8_t)(mask & 0xFF); +} + +/************************************************* + * Name: mld_ct_cmask_neg_i32 + * + * Description: Return 0 if input is non-negative, and -1 otherwise. + * + * Arguments: int32_t x: Value to be converted into a mask + * + **************************************************/ +static MLD_INLINE uint32_t mld_ct_cmask_neg_i32(int32_t x) +__contract__( + ensures(return_value == ((x < 0) ? 0xFFFFFFFF : 0)) +) +{ + int64_t tmp = mld_value_barrier_i64((int64_t)x); + tmp >>= 31; + return mld_cast_int64_to_uint32(tmp); +} + +/************************************************* + * Name: mld_ct_abs_i32 + * + * Description: Return -x if x<0, x otherwise + * + * Arguments: int32_t x: Input value + * + **************************************************/ +static MLD_INLINE int32_t mld_ct_abs_i32(int32_t x) +__contract__( + requires(x >= -INT32_MAX) + ensures(return_value == ((x < 0) ? -x : x)) +) +{ + return mld_ct_sel_int32(-x, x, mld_ct_cmask_neg_i32(x)); +} + +/************************************************* + * Name: mld_ct_memcmp + * + * Description: Compare two arrays for equality in constant time. + * + * Arguments: const uint8_t *a: pointer to first byte array + * const uint8_t *b: pointer to second byte array + * size_t len: length of the byte arrays, upper-bounded + * to UINT16_MAX to control proof complexity + * only. + * + * Returns 0 if the byte arrays are equal, 0xFF otherwise. + **************************************************/ +static MLD_INLINE uint8_t mld_ct_memcmp(const uint8_t *a, const uint8_t *b, + const size_t len) +__contract__( + requires(len <= UINT16_MAX) + requires(memory_no_alias(a, len)) + requires(memory_no_alias(b, len)) + ensures((return_value == 0) || (return_value == 0xFF)) + ensures((return_value == 0) == forall(i, 0, len, (a[i] == b[i])))) +{ + uint8_t r = 0, s = 0; + unsigned i; + + for (i = 0; i < len; i++) + __loop__( + invariant(i <= len) + invariant((r == 0) == (forall(k, 0, i, (a[k] == b[k]))))) + { + r |= a[i] ^ b[i]; + /* s is useless, but prevents the loop from being aborted once r=0xff. */ + s ^= a[i] ^ b[i]; + } + + /* + * - Convert r into a mask; this may not be necessary, but is an additional + * safeguard + * towards leaking information about a and b. + * - XOR twice with s, separated by a value barrier, to prevent the compile + * from dropping the s computation in the loop. + */ + return (mld_value_barrier_u8(mld_ct_cmask_nonzero_u8(r) ^ s) ^ s); +} + +/************************************************* + * Name: mld_zeroize + * + * Description: Force-zeroize a buffer. + * @[FIPS204, Section 3.6.3] Destruction of intermediate + * values. + * + * Arguments: void *ptr: pointer to buffer to be zeroed + * size_t len: Amount of bytes to be zeroed + **************************************************/ +#if !defined(MLD_CONFIG_CUSTOM_ZEROIZE) +#if defined(MLD_SYS_WINDOWS) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) { SecureZeroMemory(ptr, len); } +#elif defined(MLD_HAVE_INLINE_ASM) +#include +static MLD_INLINE void mld_zeroize(void *ptr, size_t len) +__contract__( + requires(memory_no_alias(ptr, len)) + assigns(memory_slice(ptr, len))) +{ + memset(ptr, 0, len); + /* This follows OpenSSL and seems sufficient to prevent the compiler + * from optimizing away the memset. + * + * If there was a reliable way to detect availability of memset_s(), + * that would be preferred. */ + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +} +#else /* !MLD_SYS_WINDOWS && MLD_HAVE_INLINE_ASM */ +#error No plausibly-secure implementation of mld_zeroize available. Please provide your own using MLD_CONFIG_CUSTOM_ZEROIZE. +#endif /* !MLD_SYS_WINDOWS && !MLD_HAVE_INLINE_ASM */ +#endif /* !MLD_CONFIG_CUSTOM_ZEROIZE */ + +#endif /* !MLD_CT_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/debug.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/debug.c new file mode 100644 index 0000000000..a55d51e8b1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/debug.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* NOTE: You can remove this file unless you compile with MLDSA_DEBUG. */ + +#include "common.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#if defined(MLDSA_DEBUG) + +#include +#include +#include +#include "debug.h" + +#define MLD_DEBUG_ERROR_HEADER "[ERROR:%s:%04d] " + +void mld_debug_check_assert(const char *file, int line, const int val) +{ + if (val == 0) + { + fprintf(stderr, MLD_DEBUG_ERROR_HEADER "Assertion failed (value %d)\n", + file, line, val); + exit(1); + } +} + +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive) +{ + int err = 0; + unsigned i; + for (i = 0; i < len; i++) + { + int32_t val = ptr[i]; + if (!(val > lower_bound_exclusive && val < upper_bound_exclusive)) + { + fprintf(stderr, + MLD_DEBUG_ERROR_HEADER + "Bounds assertion failed: Index %u, value %d out of bounds " + "(%" PRId64 ",%" PRId64 ")\n", + file, line, i, (int)val, lower_bound_exclusive, + upper_bound_exclusive); + err = 1; + } + } + + if (err == 1) + { + exit(1); + } +} + +#else /* MLDSA_DEBUG */ + +MLD_EMPTY_CU(debug) + +#endif /* !MLDSA_DEBUG */ + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(debug) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_DEBUG_ERROR_HEADER diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/debug.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/debug.h new file mode 100644 index 0000000000..af187bb9de --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/debug.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_DEBUG_H +#define MLD_DEBUG_H +#include "common.h" + +#if defined(MLDSA_DEBUG) +#include + +/************************************************* + * Name: mld_assert + * + * Description: Check debug assertion + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - val: Value asserted to be non-zero + **************************************************/ +#define mld_debug_check_assert MLD_NAMESPACE(mldsa_debug_assert) +void mld_debug_check_assert(const char *file, int line, const int val); + +/************************************************* + * Name: mld_debug_check_bounds + * + * Description: Check whether values in an array of int32_t + * are within specified bounds. + * + * Prints an error message to stderr and calls + * exit(1) if not. + * + * Arguments: - file: filename + * - line: line number + * - ptr: Base of array to be checked + * - len: Number of int32_t in ptr + * - lower_bound_exclusive: Exclusive lower bound + * - upper_bound_exclusive: Exclusive upper bound + **************************************************/ +#define mld_debug_check_bounds MLD_NAMESPACE(mldsa_debug_check_bounds) +void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr, + unsigned len, int64_t lower_bound_exclusive, + int64_t upper_bound_exclusive); + +/* Check assertion, calling exit() upon failure + * + * val: Value that's asserted to be non-zero + */ +#define mld_assert(val) mld_debug_check_assert(__FILE__, __LINE__, (val)) + +/* Check bounds in array of int32_t's + * ptr: Base of int32_t array; will be explicitly cast to int32_t*, + * so you may pass a byte-compatible type such as mld_poly or mld_polyvec. + * len: Number of int32_t in array + * value_lb: Inclusive lower value bound + * value_ub: Exclusive upper value bound */ +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + mld_debug_check_bounds(__FILE__, __LINE__, (const int32_t *)(ptr), (len), \ + ((int64_t)(value_lb)) - 1, (value_ub)) + +/* Check absolute bounds in array of int32_t's + * ptr: Base of array, expression of type int32_t* + * len: Number of int32_t in array + * value_abs_bd: Exclusive absolute upper bound */ +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + mld_assert_bound((ptr), (len), (-((int64_t)(value_abs_bd)) + 1), \ + (value_abs_bd)) + +/* Version of bounds assertions for 2-dimensional arrays */ +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + mld_assert_bound((ptr), ((len0) * (len1)), (value_lb), (value_ub)) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + mld_assert_abs_bound((ptr), ((len0) * (len1)), (value_abs_bd)) + +/* When running CBMC, convert debug assertions into proof obligations */ +#elif defined(CBMC) +#include "cbmc.h" + +#define mld_assert(val) cassert(val) + +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + cassert(array_bound(((int32_t *)(ptr)), 0, (len), (value_lb), (value_ub))) + +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + cassert(array_abs_bound(((int32_t *)(ptr)), 0, (len), (value_abs_bd))) + +/* Because of https://github.com/diffblue/cbmc/issues/8570, we can't + * just use a single flattened array_bound(...) here. */ +#define mld_assert_bound_2d(ptr, M, N, value_lb, value_ub) \ + cassert(forall(kN, 0, (M), \ + array_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_lb), (value_ub)))) + +#define mld_assert_abs_bound_2d(ptr, M, N, value_abs_bd) \ + cassert(forall(kN, 0, (M), \ + array_abs_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \ + (value_abs_bd)))) + +#else /* !MLDSA_DEBUG && CBMC */ + +#define mld_assert(val) \ + do \ + { \ + } while (0) +#define mld_assert_bound(ptr, len, value_lb, value_ub) \ + do \ + { \ + } while (0) +#define mld_assert_abs_bound(ptr, len, value_abs_bd) \ + do \ + { \ + } while (0) + +#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \ + do \ + { \ + } while (0) + +#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \ + do \ + { \ + } while (0) + + +#endif /* !MLDSA_DEBUG && !CBMC */ +#endif /* !MLD_DEBUG_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/fips202.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/fips202.c new file mode 100644 index 0000000000..1112de061c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/fips202.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "../common.h" +#include "../ct.h" +#include "fips202.h" +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +/************************************************* + * Name: keccak_init + * + * Description: Initializes the Keccak state. + * + * Arguments: - uint64_t *s: pointer to Keccak state + **************************************************/ +static void keccak_init(uint64_t s[MLD_KECCAK_LANES]) +__contract__( + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + mld_memset(s, 0, sizeof(uint64_t) * MLD_KECCAK_LANES); +} + +/************************************************* + * Name: keccak_absorb + * + * Description: Absorb step of Keccak; incremental. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_absorb(uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r, + const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(pos <= r) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(in, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + ensures(return_value < r)) +{ + while (inlen >= r - pos) + __loop__( + assigns(pos, in, inlen, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + invariant(inlen <= loop_entry(inlen)) + invariant(pos <= r) + invariant(in == loop_entry(in) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600_xor_bytes(s, in, pos, r - pos); + inlen -= r - pos; + in += r - pos; + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: At this point, inlen < r, so the truncation to unsigned is safe. */ + mld_keccakf1600_xor_bytes(s, in, pos, (unsigned)inlen); + + /* Safety: At this point, inlen < r and pos <= r so the truncation to unsigned + * is safe. */ + return (unsigned)(pos + inlen); +} + +/************************************************* + * Name: keccak_finalize + * + * Description: Finalize absorb step. + * + * Arguments: - uint64_t *s: pointer to Keccak state + * - unsigned int pos: position in current block to be absorbed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * - uint8_t p: domain separation byte + **************************************************/ +static void keccak_finalize(uint64_t s[MLD_KECCAK_LANES], unsigned int pos, + unsigned int r, uint8_t p) +__contract__( + requires(pos <= r && r < sizeof(uint64_t) * MLD_KECCAK_LANES) + requires((r / 8) >= 1) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) +) +{ + uint8_t b = 0x80; + mld_keccakf1600_xor_bytes(s, &p, pos, 1); + mld_keccakf1600_xor_bytes(s, &b, r - 1, 1); +} + +/************************************************* + * Name: keccak_squeeze + * + * Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes. + * Modifies the state. Can be called multiple times to keep + * squeezing, i.e., is incremental. + * + * Arguments: - uint8_t *out: pointer to output data + * - size_t outlen: number of bytes to be squeezed (written to out) + * - uint64_t *s: pointer to input/output Keccak state + * - unsigned int pos: number of bytes in current block already + *squeezed + * - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) + * + * Returns new position pos in current block + **************************************************/ +static unsigned int keccak_squeeze(uint8_t *out, size_t outlen, + uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r) +__contract__( + requires((r == SHAKE128_RATE && pos <= SHAKE128_RATE) || + (r == SHAKE256_RATE && pos <= SHAKE256_RATE) || + (r == SHA3_512_RATE && pos <= SHA3_512_RATE)) + requires(outlen <= 8 * r /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(out, outlen)) + ensures(return_value <= r)) +{ + unsigned int i; + size_t out_offset = 0; + + /* Reference: This code is re-factored from the reference implementation + * to facilitate proof with CBMC and to improve readability. + * + * Take a mutable copy of outlen to count down the number of bytes + * still to squeeze. The initial value of outlen is needed for the CBMC + * assigns() clauses. */ + size_t bytes_to_go = outlen; + + while (bytes_to_go > 0) + __loop__( + assigns(i, bytes_to_go, pos, out_offset, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES), memory_slice(out, outlen)) + invariant(bytes_to_go <= outlen) + invariant(out_offset == outlen - bytes_to_go) + invariant(pos <= r) + ) + { + if (pos == r) + { + mld_keccakf1600_permute(s); + pos = 0; + } + /* Safety: If bytes_to_go < r - pos, truncation to unsigned is safe. */ + i = bytes_to_go < r - pos ? (unsigned)bytes_to_go : r - pos; + mld_keccakf1600_extract_bytes(s, out + out_offset, pos, i); + bytes_to_go -= i; + pos += i; + out_offset += i; + } + + return pos; +} + +void mld_shake128_init(mld_shake128ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE128_RATE, in, inlen); +} + +void mld_shake128_finalize(mld_shake128ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE128_RATE, 0x1F); + state->pos = SHAKE128_RATE; +} + +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE128_RATE); +} + +void mld_shake128_release(mld_shake128ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128ctx)); +} + +void mld_shake256_init(mld_shake256ctx *state) +{ + keccak_init(state->s); + state->pos = 0; +} + +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); +} + +void mld_shake256_finalize(mld_shake256ctx *state) +{ + keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); + state->pos = SHAKE256_RATE; +} + +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); +} + +void mld_shake256_release(mld_shake256ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256ctx)); +} + +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +{ + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, in, inlen); + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/fips202.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/fips202.h new file mode 100644 index 0000000000..9f0253cb88 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/fips202.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202_H +#define MLD_FIPS202_FIPS202_H + +#include +#include +#include "../cbmc.h" +#include "../common.h" + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 +#define SHA3_256_RATE 136 +#define SHA3_512_RATE 72 +#define MLD_KECCAK_LANES 25 +#define SHA3_256_HASHBYTES 32 +#define SHA3_512_HASHBYTES 64 + + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake128ctx; + +typedef struct +{ + uint64_t s[MLD_KECCAK_LANES]; + unsigned int pos; +} mld_shake256ctx; + +#define mld_shake128_init MLD_NAMESPACE(shake128_init) +/************************************************* + * Name: mld_shake128_init + * + * Description: Initializes state for use as SHAKE128 XOF + * + * Arguments: - mld_shake128ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake128_init(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos == 0) +); + +#define mld_shake128_absorb MLD_NAMESPACE(shake128_absorb) +/************************************************* + * Name: mld_shake128_absorb + * + * Description: Absorb step of the SHAKE128 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake128ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake128_absorb(mld_shake128ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_finalize MLD_NAMESPACE(shake128_finalize) +/************************************************* + * Name: mld_shake128_finalize + * + * Description: Concludes the absorb phase of the SHAKE128 XOF. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_finalize(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_squeeze MLD_NAMESPACE(shake128_squeeze) +/************************************************* + * Name: mld_shake128_squeeze + * + * Description: Squeeze step of SHAKE128 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake128ctx *s: pointer to input/output state + **************************************************/ +void mld_shake128_squeeze(uint8_t *out, size_t outlen, mld_shake128ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE128_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE128_RATE) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE128_RATE) +); + +#define mld_shake128_release MLD_NAMESPACE(shake128_release) +/************************************************* + * Name: mld_shake128_release + * + * Description: Release and securely zero the SHAKE128 state. + * + * Arguments: - mld_shake128ctx *state: pointer to state + **************************************************/ +void mld_shake128_release(mld_shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake128ctx))) + assigns(memory_slice(state, sizeof(mld_shake128ctx))) +); + +#define mld_shake256_init MLD_NAMESPACE(shake256_init) +/************************************************* + * Name: mld_shake256_init + * + * Description: Initializes state for use as SHAKE256 XOF + * + * Arguments: - mld_shake256ctx *state: pointer to (uninitialized) state + **************************************************/ +void mld_shake256_init(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos == 0) +); + +#define mld_shake256_absorb MLD_NAMESPACE(shake256_absorb) +/************************************************* + * Name: mld_shake256_absorb + * + * Description: Absorb step of the SHAKE256 XOF. Absorbs arbitrarily many bytes. + * Can be called multiple times to absorb multiple chunks of data. + * + * Arguments: - mld_shake256ctx *state: pointer to (initialized) output state + * - const uint8_t *in: pointer to input to be absorbed into s + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256_absorb(mld_shake256ctx *state, const uint8_t *in, + size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(in, inlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_finalize MLD_NAMESPACE(shake256_finalize) +/************************************************* + * Name: mld_shake256_finalize + * + * Description: Concludes the absorb phase of the SHAKE256 XOF. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_finalize(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_squeeze MLD_NAMESPACE(shake256_squeeze) +/************************************************* + * Name: mld_shake256_squeeze + * + * Description: Squeeze step of SHAKE256 XOF. Squeezes arbitrarily many + * bytes. Can be called multiple times to keep squeezing. + * + * Arguments: - uint8_t *out: pointer to output blocks + * - size_t outlen : number of bytes to be squeezed (written to + *output) + * - mld_shake256ctx *s: pointer to input/output state + **************************************************/ +void mld_shake256_squeeze(uint8_t *out, size_t outlen, mld_shake256ctx *state) +__contract__( + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + requires(memory_no_alias(out, outlen)) + requires(state->pos <= SHAKE256_RATE) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(out, outlen)) + ensures(state->pos <= SHAKE256_RATE) +); + +#define mld_shake256_release MLD_NAMESPACE(shake256_release) +/************************************************* + * Name: mld_shake256_release + * + * Description: Release and securely zero the SHAKE256 state. + * + * Arguments: - mld_shake256ctx *state: pointer to state + **************************************************/ +void mld_shake256_release(mld_shake256ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(mld_shake256ctx))) + assigns(memory_slice(state, sizeof(mld_shake256ctx))) +); + +#define mld_shake256 MLD_NAMESPACE(shake256) +/************************************************* + * Name: mld_shake256 + * + * Description: SHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +); + +#endif /* !MLD_FIPS202_FIPS202_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/fips202x4.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/fips202x4.c new file mode 100644 index 0000000000..0fb5cd57c7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/fips202x4.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include "../common.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "../ct.h" +#include "fips202.h" +#include "fips202x4.h" +#include "keccakf1600.h" + +static void mld_keccak_absorb_once_x4(uint64_t *s, uint32_t r, + const uint8_t *in0, const uint8_t *in1, + const uint8_t *in2, const uint8_t *in3, + size_t inlen, uint8_t p) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY))) +{ + while (inlen >= r) + __loop__( + assigns(inlen, in0, in1, in2, in3, memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + invariant(inlen <= loop_entry(inlen)) + invariant(in0 == loop_entry(in0) + (loop_entry(inlen) - inlen)) + invariant(in1 == loop_entry(in1) + (loop_entry(inlen) - inlen)) + invariant(in2 == loop_entry(in2) + (loop_entry(inlen) - inlen)) + invariant(in3 == loop_entry(in3) + (loop_entry(inlen) - inlen))) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, r); + mld_keccakf1600x4_permute(s); + + in0 += r; + in1 += r; + in2 += r; + in3 += r; + inlen -= r; + } + + /* Safety: At this point, inlen < r, so the truncations to unsigned are safe + * below. */ + if (inlen > 0) + { + mld_keccakf1600x4_xor_bytes(s, in0, in1, in2, in3, 0, (unsigned)inlen); + } + + if (inlen == r - 1) + { + p |= 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + } + else + { + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, (unsigned)inlen, 1); + p = 128; + mld_keccakf1600x4_xor_bytes(s, &p, &p, &p, &p, r - 1, 1); + } +} + +static void mld_keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1, + uint8_t *out2, uint8_t *out3, + size_t nblocks, uint64_t *s, uint32_t r) +__contract__( + requires(r <= sizeof(uint64_t) * MLD_KECCAK_LANES) + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(out0, nblocks * r)) + requires(memory_no_alias(out1, nblocks * r)) + requires(memory_no_alias(out2, nblocks * r)) + requires(memory_no_alias(out3, nblocks * r)) + assigns(memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(out0, nblocks * r)) + assigns(memory_slice(out1, nblocks * r)) + assigns(memory_slice(out2, nblocks * r)) + assigns(memory_slice(out3, nblocks * r))) +{ + while (nblocks > 0) + __loop__( + assigns(out0, out1, out2, out3, nblocks, + memory_slice(s, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY), + memory_slice(out0, nblocks * r), + memory_slice(out1, nblocks * r), + memory_slice(out2, nblocks * r), + memory_slice(out3, nblocks * r)) + invariant(nblocks <= loop_entry(nblocks) && + out0 == loop_entry(out0) + r * (loop_entry(nblocks) - nblocks) && + out1 == loop_entry(out1) + r * (loop_entry(nblocks) - nblocks) && + out2 == loop_entry(out2) + r * (loop_entry(nblocks) - nblocks) && + out3 == loop_entry(out3) + r * (loop_entry(nblocks) - nblocks))) + { + mld_keccakf1600x4_permute(s); + mld_keccakf1600x4_extract_bytes(s, out0, out1, out2, out3, 0, r); + + out0 += r; + out1 += r; + out2 += r; + out3 += r; + nblocks--; + } +} + +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake128x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE128_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE128_RATE); +} + +void mld_shake128x4_init(mld_shake128x4ctx *state) { (void)state; } +void mld_shake128x4_release(mld_shake128x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake128x4ctx)); +} + + +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +{ + mld_memset(state, 0, sizeof(mld_shake256x4ctx)); + mld_keccak_absorb_once_x4(state->ctx, SHAKE256_RATE, in0, in1, in2, in3, + inlen, 0x1F); +} + +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +{ + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx, + SHAKE256_RATE); +} + +void mld_shake256x4_init(mld_shake256x4ctx *state) { (void)state; } +void mld_shake256x4_release(mld_shake256x4ctx *state) +{ + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(state, sizeof(mld_shake256x4ctx)); +} + +#endif /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/fips202x4.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/fips202x4.h new file mode 100644 index 0000000000..e7987207a6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/fips202x4.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_FIPS202X4_H +#define MLD_FIPS202_FIPS202X4_H + +#include +#include + +#include "../cbmc.h" +#include "../common.h" + +#include "fips202.h" +#include "keccakf1600.h" + +/* Context for non-incremental API */ +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake128x4ctx; + +typedef struct +{ + uint64_t ctx[MLD_KECCAK_LANES * MLD_KECCAK_WAY]; +} mld_shake256x4ctx; + +#define mld_shake128x4_absorb_once MLD_NAMESPACE(shake128x4_absorb_once) +void mld_shake128x4_absorb_once(mld_shake128x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_squeezeblocks MLD_NAMESPACE(shake128x4_squeezeblocks) +void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake128x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake128x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE128_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE128_RATE), + memory_slice(out1, nblocks * SHAKE128_RATE), + memory_slice(out2, nblocks * SHAKE128_RATE), + memory_slice(out3, nblocks * SHAKE128_RATE), + memory_slice(state, sizeof(mld_shake128x4ctx))) +); + +#define mld_shake128x4_init MLD_NAMESPACE(shake128x4_init) +void mld_shake128x4_init(mld_shake128x4ctx *state); + +#define mld_shake128x4_release MLD_NAMESPACE(shake128x4_release) +void mld_shake128x4_release(mld_shake128x4ctx *state); + + +#define mld_shake256x4_absorb_once MLD_NAMESPACE(shake256x4_absorb_once) +void mld_shake256x4_absorb_once(mld_shake256x4ctx *state, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_squeezeblocks MLD_NAMESPACE(shake256x4_squeezeblocks) +void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, + mld_shake256x4ctx *state) +__contract__( + requires(nblocks <= 8 /* somewhat arbitrary bound */) + requires(memory_no_alias(state, sizeof(mld_shake256x4ctx))) + requires(memory_no_alias(out0, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE256_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE256_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE256_RATE), + memory_slice(out1, nblocks * SHAKE256_RATE), + memory_slice(out2, nblocks * SHAKE256_RATE), + memory_slice(out3, nblocks * SHAKE256_RATE), + memory_slice(state, sizeof(mld_shake256x4ctx))) +); + +#define mld_shake256x4_init MLD_NAMESPACE(shake256x4_init) +void mld_shake256x4_init(mld_shake256x4ctx *state); + +#define mld_shake256x4_release MLD_NAMESPACE(shake256x4_release) +void mld_shake256x4_release(mld_shake256x4ctx *state); + + +#endif /* !MLD_FIPS202_FIPS202X4_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/keccakf1600.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/keccakf1600.c new file mode 100644 index 0000000000..e59120c07c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/keccakf1600.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [mupq] + * Common files for pqm4, pqm3, pqriscv + * Kannwischer, Petri, Rijneveld, Schwabe, Stoffelen + * https://github.com/mupq/mupq + * + * - [supercop] + * SUPERCOP benchmarking framework + * Daniel J. Bernstein + * http://bench.cr.yp.to/supercop.html + * + * - [tweetfips] + * 'tweetfips202' FIPS202 implementation + * Van Assche, Bernstein, Schwabe + * https://keccak.team/2015/tweetfips202.html + */ + +/* Based on the CC0 implementation from @[mupq] and the public domain + * implementation @[supercop, crypto_hash/keccakc512/simple/] + * by Ronny Van Keer, and the public domain @[tweetfips] implementation. */ + +#include +#include + +#include "keccakf1600.h" +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#define MLD_KECCAK_NROUNDS 24 +#define MLD_KECCAK_ROL(a, offset) ((a << offset) ^ (a >> (64 - offset))) + +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = state_ptr[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + data[i] = (state[(offset + i) >> 3] >> (8 * ((offset + i) & 0x07))) & 0xFF; + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +{ + unsigned i; +#if defined(MLD_SYS_LITTLE_ENDIAN) + uint8_t *state_ptr = (uint8_t *)state + offset; + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state_ptr[i] ^= data[i]; + } +#else /* MLD_SYS_LITTLE_ENDIAN */ + /* Portable version */ + for (i = 0; i < length; i++) + __loop__(invariant(i <= length)) + { + state[(offset + i) >> 3] ^= (uint64_t)data[i] + << (8 * ((offset + i) & 0x07)); + } +#endif /* !MLD_SYS_LITTLE_ENDIAN */ +} + +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_extract_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +{ + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 0, data0, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 1, data1, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 2, data2, offset, + length); + mld_keccakf1600_xor_bytes(state + MLD_KECCAK_LANES * 3, data3, offset, + length); +} + +void mld_keccakf1600x4_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X4_NATIVE) + if (mld_keccak_f1600_x4_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 0); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 1); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 2); + mld_keccakf1600_permute(state + MLD_KECCAK_LANES * 3); +} + +static const uint64_t mld_KeccakF_RoundConstants[MLD_KECCAK_NROUNDS] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +static void mld_keccakf1600_permute_c(uint64_t *state) +{ + unsigned round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + uint64_t BCa, BCe, BCi, BCo, BCu; + uint64_t Da, De, Di, Do, Du; + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + /* copyFromState(A, state) */ + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < MLD_KECCAK_NROUNDS; round += 2) + __loop__(invariant(round <= MLD_KECCAK_NROUNDS && round % 2 == 0)) + { + /* prepareTheta */ + BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; + BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + /* thetaRhoPiChiIotaPrepareTheta(round, A, E) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = MLD_KECCAK_ROL(Age, 44); + Aki ^= Di; + BCi = MLD_KECCAK_ROL(Aki, 43); + Amo ^= Do; + BCo = MLD_KECCAK_ROL(Amo, 21); + Asu ^= Du; + BCu = MLD_KECCAK_ROL(Asu, 14); + Eba = BCa ^ ((~BCe) & BCi); + Eba ^= (uint64_t)mld_KeccakF_RoundConstants[round]; + Ebe = BCe ^ ((~BCi) & BCo); + Ebi = BCi ^ ((~BCo) & BCu); + Ebo = BCo ^ ((~BCu) & BCa); + Ebu = BCu ^ ((~BCa) & BCe); + + Abo ^= Do; + BCa = MLD_KECCAK_ROL(Abo, 28); + Agu ^= Du; + BCe = MLD_KECCAK_ROL(Agu, 20); + Aka ^= Da; + BCi = MLD_KECCAK_ROL(Aka, 3); + Ame ^= De; + BCo = MLD_KECCAK_ROL(Ame, 45); + Asi ^= Di; + BCu = MLD_KECCAK_ROL(Asi, 61); + Ega = BCa ^ ((~BCe) & BCi); + Ege = BCe ^ ((~BCi) & BCo); + Egi = BCi ^ ((~BCo) & BCu); + Ego = BCo ^ ((~BCu) & BCa); + Egu = BCu ^ ((~BCa) & BCe); + + Abe ^= De; + BCa = MLD_KECCAK_ROL(Abe, 1); + Agi ^= Di; + BCe = MLD_KECCAK_ROL(Agi, 6); + Ako ^= Do; + BCi = MLD_KECCAK_ROL(Ako, 25); + Amu ^= Du; + BCo = MLD_KECCAK_ROL(Amu, 8); + Asa ^= Da; + BCu = MLD_KECCAK_ROL(Asa, 18); + Eka = BCa ^ ((~BCe) & BCi); + Eke = BCe ^ ((~BCi) & BCo); + Eki = BCi ^ ((~BCo) & BCu); + Eko = BCo ^ ((~BCu) & BCa); + Eku = BCu ^ ((~BCa) & BCe); + + Abu ^= Du; + BCa = MLD_KECCAK_ROL(Abu, 27); + Aga ^= Da; + BCe = MLD_KECCAK_ROL(Aga, 36); + Ake ^= De; + BCi = MLD_KECCAK_ROL(Ake, 10); + Ami ^= Di; + BCo = MLD_KECCAK_ROL(Ami, 15); + Aso ^= Do; + BCu = MLD_KECCAK_ROL(Aso, 56); + Ema = BCa ^ ((~BCe) & BCi); + Eme = BCe ^ ((~BCi) & BCo); + Emi = BCi ^ ((~BCo) & BCu); + Emo = BCo ^ ((~BCu) & BCa); + Emu = BCu ^ ((~BCa) & BCe); + + Abi ^= Di; + BCa = MLD_KECCAK_ROL(Abi, 62); + Ago ^= Do; + BCe = MLD_KECCAK_ROL(Ago, 55); + Aku ^= Du; + BCi = MLD_KECCAK_ROL(Aku, 39); + Ama ^= Da; + BCo = MLD_KECCAK_ROL(Ama, 41); + Ase ^= De; + BCu = MLD_KECCAK_ROL(Ase, 2); + Esa = BCa ^ ((~BCe) & BCi); + Ese = BCe ^ ((~BCi) & BCo); + Esi = BCi ^ ((~BCo) & BCu); + Eso = BCo ^ ((~BCu) & BCa); + Esu = BCu ^ ((~BCa) & BCe); + + /* prepareTheta */ + BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + /* thetaRhoPiChiIotaPrepareTheta(round+1, E, A) */ + Da = BCu ^ MLD_KECCAK_ROL(BCe, 1); + De = BCa ^ MLD_KECCAK_ROL(BCi, 1); + Di = BCe ^ MLD_KECCAK_ROL(BCo, 1); + Do = BCi ^ MLD_KECCAK_ROL(BCu, 1); + Du = BCo ^ MLD_KECCAK_ROL(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = MLD_KECCAK_ROL(Ege, 44); + Eki ^= Di; + BCi = MLD_KECCAK_ROL(Eki, 43); + Emo ^= Do; + BCo = MLD_KECCAK_ROL(Emo, 21); + Esu ^= Du; + BCu = MLD_KECCAK_ROL(Esu, 14); + Aba = BCa ^ ((~BCe) & BCi); + Aba ^= (uint64_t)mld_KeccakF_RoundConstants[round + 1]; + Abe = BCe ^ ((~BCi) & BCo); + Abi = BCi ^ ((~BCo) & BCu); + Abo = BCo ^ ((~BCu) & BCa); + Abu = BCu ^ ((~BCa) & BCe); + + Ebo ^= Do; + BCa = MLD_KECCAK_ROL(Ebo, 28); + Egu ^= Du; + BCe = MLD_KECCAK_ROL(Egu, 20); + Eka ^= Da; + BCi = MLD_KECCAK_ROL(Eka, 3); + Eme ^= De; + BCo = MLD_KECCAK_ROL(Eme, 45); + Esi ^= Di; + BCu = MLD_KECCAK_ROL(Esi, 61); + Aga = BCa ^ ((~BCe) & BCi); + Age = BCe ^ ((~BCi) & BCo); + Agi = BCi ^ ((~BCo) & BCu); + Ago = BCo ^ ((~BCu) & BCa); + Agu = BCu ^ ((~BCa) & BCe); + + Ebe ^= De; + BCa = MLD_KECCAK_ROL(Ebe, 1); + Egi ^= Di; + BCe = MLD_KECCAK_ROL(Egi, 6); + Eko ^= Do; + BCi = MLD_KECCAK_ROL(Eko, 25); + Emu ^= Du; + BCo = MLD_KECCAK_ROL(Emu, 8); + Esa ^= Da; + BCu = MLD_KECCAK_ROL(Esa, 18); + Aka = BCa ^ ((~BCe) & BCi); + Ake = BCe ^ ((~BCi) & BCo); + Aki = BCi ^ ((~BCo) & BCu); + Ako = BCo ^ ((~BCu) & BCa); + Aku = BCu ^ ((~BCa) & BCe); + + Ebu ^= Du; + BCa = MLD_KECCAK_ROL(Ebu, 27); + Ega ^= Da; + BCe = MLD_KECCAK_ROL(Ega, 36); + Eke ^= De; + BCi = MLD_KECCAK_ROL(Eke, 10); + Emi ^= Di; + BCo = MLD_KECCAK_ROL(Emi, 15); + Eso ^= Do; + BCu = MLD_KECCAK_ROL(Eso, 56); + Ama = BCa ^ ((~BCe) & BCi); + Ame = BCe ^ ((~BCi) & BCo); + Ami = BCi ^ ((~BCo) & BCu); + Amo = BCo ^ ((~BCu) & BCa); + Amu = BCu ^ ((~BCa) & BCe); + + Ebi ^= Di; + BCa = MLD_KECCAK_ROL(Ebi, 62); + Ego ^= Do; + BCe = MLD_KECCAK_ROL(Ego, 55); + Eku ^= Du; + BCi = MLD_KECCAK_ROL(Eku, 39); + Ema ^= Da; + BCo = MLD_KECCAK_ROL(Ema, 41); + Ese ^= De; + BCu = MLD_KECCAK_ROL(Ese, 2); + Asa = BCa ^ ((~BCe) & BCi); + Ase = BCe ^ ((~BCi) & BCo); + Asi = BCi ^ ((~BCo) & BCu); + Aso = BCo ^ ((~BCu) & BCa); + Asu = BCu ^ ((~BCa) & BCe); + } + + /* copyToState(state, A) */ + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} + +void mld_keccakf1600_permute(uint64_t *state) +{ +#if defined(MLD_USE_FIPS202_X1_NATIVE) + if (mld_keccak_f1600_x1_native(state) == MLD_NATIVE_FUNC_SUCCESS) + { + return; + } +#endif /* MLD_USE_FIPS202_X1_NATIVE */ + mld_keccakf1600_permute_c(state); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(keccakf1600) + +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_KECCAK_NROUNDS +#undef MLD_KECCAK_ROL diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/keccakf1600.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/keccakf1600.h new file mode 100644 index 0000000000..e56adc1561 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/keccakf1600.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_KECCAKF1600_H +#define MLD_FIPS202_KECCAKF1600_H +#include +#include "../cbmc.h" +#include "../common.h" +#include "fips202.h" + +#define MLD_KECCAK_LANES 25 +#define MLD_KECCAK_WAY 4 + +/* + * WARNING: + * The contents of this structure, including the placement + * and interleaving of Keccak lanes, are IMPLEMENTATION-DEFINED. + * The struct is only exposed here to allow its construction on the stack. + */ + +#define mld_keccakf1600_extract_bytes MLD_NAMESPACE(keccakf1600_extract_bytes) +void mld_keccakf1600_extract_bytes(uint64_t *state, unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(data, length)) +); + +#define mld_keccakf1600_xor_bytes MLD_NAMESPACE(keccakf1600_xor_bytes) +void mld_keccakf1600_xor_bytes(uint64_t *state, const unsigned char *data, + unsigned offset, unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + requires(memory_no_alias(data, length)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#define mld_keccakf1600x4_extract_bytes \ + MLD_NAMESPACE(keccakf1600x4_extract_bytes) +void mld_keccakf1600x4_extract_bytes(uint64_t *state, unsigned char *data0, + unsigned char *data1, unsigned char *data2, + unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + requires(memory_no_alias(data1, length)) + requires(memory_no_alias(data2, length)) + requires(memory_no_alias(data3, length)) + assigns(memory_slice(data0, length)) + assigns(memory_slice(data1, length)) + assigns(memory_slice(data2, length)) + assigns(memory_slice(data3, length)) +); + +#define mld_keccakf1600x4_xor_bytes MLD_NAMESPACE(keccakf1600x4_xor_bytes) +void mld_keccakf1600x4_xor_bytes(uint64_t *state, const unsigned char *data0, + const unsigned char *data1, + const unsigned char *data2, + const unsigned char *data3, unsigned offset, + unsigned length) +__contract__( + requires(0 <= offset && offset <= MLD_KECCAK_LANES * sizeof(uint64_t) && + 0 <= length && length <= MLD_KECCAK_LANES * sizeof(uint64_t) - offset) + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + requires(memory_no_alias(data0, length)) + /* Case 1: all input buffers are distinct; Case 2: All input buffers are the same */ + requires((data0 == data1 && + data0 == data2 && + data0 == data3) || + (memory_no_alias(data1, length) && + memory_no_alias(data2, length) && + memory_no_alias(data3, length))) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600x4_permute MLD_NAMESPACE(keccakf1600x4_permute) +void mld_keccakf1600x4_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES * MLD_KECCAK_WAY)) +); + +#define mld_keccakf1600_permute MLD_NAMESPACE(keccakf1600_permute) +void mld_keccakf1600_permute(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) + assigns(memory_slice(state, sizeof(uint64_t) * MLD_KECCAK_LANES)) +); + +#endif /* !MLD_FIPS202_KECCAKF1600_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/auto.h new file mode 100644 index 0000000000..4375cc1976 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/auto.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [HYBRID] + * Hybrid scalar/vector implementations of Keccak and SPHINCS+ on AArch64 + * Becker, Kannwischer + * https://eprint.iacr.org/2022/1243 + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_AUTO_H +#define MLD_FIPS202_NATIVE_AARCH64_AUTO_H +/* Default FIPS202 assembly profile for AArch64 systems */ + +/* + * Default logic to decide which implementation to use. + * + */ + +/* + * Keccak-f1600 + * + * - On Arm-based Apple CPUs, we pick a pure Neon implementation. + * - Otherwise, unless MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, + * we use lazy-rotation scalar assembly from @[HYBRID]. + * - Otherwise, if MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER is set, we + * fall back to the standard C implementation. + */ +#if defined(__ARM_FEATURE_SHA3) && defined(__APPLE__) +#include "x1_v84a.h" +#elif !defined(MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER) +#include "x1_scalar.h" +#endif + +/* + * Keccak-f1600x2/x4 + * + * The optimal implementation is highly CPU-specific; see @[HYBRID]. + * + * For now, if v8.4-A is not implemented, we fall back to Keccak-f1600. + * If v8.4-A is implemented and we are on an Apple CPU, we use a plain + * Neon-based implementation. + * If v8.4-A is implemented and we are not on an Apple CPU, we use a + * scalar/Neon/Neon hybrid. + * The reason for this distinction is that Apple CPUs appear to implement + * the SHA3 instructions on all SIMD units, while Arm CPUs prior to Cortex-X4 + * don't, and ordinary Neon instructions are still needed. + */ +#if defined(__ARM_FEATURE_SHA3) +/* + * For Apple-M cores, we use a plain implementation leveraging SHA3 + * instructions only. + */ +#if defined(__APPLE__) +#include "x2_v84a.h" +#else +#include "x4_v8a_v84a_scalar.h" +#endif + +#else /* __ARM_FEATURE_SHA3 */ + +#include "x4_v8a_scalar.h" + +#endif /* !__ARM_FEATURE_SHA3 */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/src/fips202_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/src/fips202_native_aarch64.h new file mode 100644 index 0000000000..20f6168038 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/src/fips202_native_aarch64.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H +#define MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H + +#include +#include "../../../../cbmc.h" +#include "../../../../common.h" + + +#define mld_keccakf1600_round_constants \ + MLD_NAMESPACE(keccakf1600_round_constants) +extern const uint64_t mld_keccakf1600_round_constants[]; + +#define mld_keccak_f1600_x1_scalar_asm MLD_NAMESPACE(keccak_f1600_x1_scalar_asm) +void mld_keccak_f1600_x1_scalar_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x1_v84a_asm MLD_NAMESPACE(keccak_f1600_x1_v84a_asm) +void mld_keccak_f1600_x1_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) +); + +#define mld_keccak_f1600_x2_v84a_asm MLD_NAMESPACE(keccak_f1600_x2_v84a_asm) +void mld_keccak_f1600_x2_v84a_asm(uint64_t *state, uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 2)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 2)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#define mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm \ + MLD_NAMESPACE(keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm) +void mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm(uint64_t *state, + uint64_t const *rc) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + requires(rc == mld_keccakf1600_round_constants) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) +); + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_SRC_FIPS202_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccakf1600_round_constants.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccakf1600_round_constants.c new file mode 100644 index 0000000000..05e9cbfeec --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccakf1600_round_constants.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../../common.h" + +#if (defined(MLD_FIPS202_AARCH64_NEED_X1_SCALAR) || \ + defined(MLD_FIPS202_AARCH64_NEED_X1_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X2_V84A) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID) || \ + defined(MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID)) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "fips202_native_aarch64.h" + +MLD_ALIGN const uint64_t mld_keccakf1600_round_constants[] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, +}; + +#else /* (MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_aarch64_round_constants) + +#endif /* !((MLD_FIPS202_AARCH64_NEED_X1_SCALAR || \ + MLD_FIPS202_AARCH64_NEED_X1_V84A || MLD_FIPS202_AARCH64_NEED_X2_V84A \ + || MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID || \ + MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID) && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/x1_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/x1_scalar.h new file mode 100644 index 0000000000..681b991371 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/x1_scalar.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_SCALAR + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + mld_keccak_f1600_x1_scalar_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/x1_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/x1_v84a.h new file mode 100644 index 0000000000..d15c8c26f3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/x1_v84a.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X1_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X1_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x1_v84a_asm(state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X1_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/x2_v84a.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/x2_v84a.h new file mode 100644 index 0000000000..16c22fa1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/x2_v84a.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H +#define MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X2_V84A + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" + + +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x2_v84a_asm(state + 0 * 25, mld_keccakf1600_round_constants); + mld_keccak_f1600_x2_v84a_asm(state + 2 * 25, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X2_V84A_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/x4_v8a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/x4_v8a_scalar.h new file mode 100644 index 0000000000..0f7f8fe499 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/x4_v8a_scalar.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + mld_keccak_f1600_x4_scalar_v8a_hybrid_asm(state, + mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h new file mode 100644 index 0000000000..3da883b762 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H +#define MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H + +#if !defined(__ARM_FEATURE_SHA3) +#error This backend can only be used if SHA3 extensions are available. +#endif + +/* Part of backend API */ +#define MLD_USE_FIPS202_X4_NATIVE +/* Guard for assembly file */ +#define MLD_FIPS202_AARCH64_NEED_X4_V8A_V84A_SCALAR_HYBRID + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/fips202_native_aarch64.h" +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_SHA3)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm( + state, mld_keccakf1600_round_constants); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_AARCH64_X4_V8A_V84A_SCALAR_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/api.h new file mode 100644 index 0000000000..4625c9a1ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/api.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_API_H +#define MLD_FIPS202_NATIVE_API_H +/* + * FIPS-202 native interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + */ + +#include +#include "../../cbmc.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* + * This is the C<->native interface allowing for the drop-in + * of custom Keccak-F1600 implementations. + * + * A _backend_ is a specific implementation of parts of this interface. + * + * You can replace 1-fold or 4-fold batched Keccak-F1600. + * To enable, set MLD_USE_FIPS202_X1_NATIVE or MLD_USE_FIPS202_X4_NATIVE + * in your backend, and define the inline wrappers mld_keccak_f1600_x1_native() + * and/or mld_keccak_f1600_x4_native(), respectively, to forward to your + * implementation. + */ + +#if defined(MLD_USE_FIPS202_X1_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x1_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 1)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 1)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 1)) +); +#endif /* MLD_USE_FIPS202_X1_NATIVE */ +#if defined(MLD_USE_FIPS202_X4_NATIVE) +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +__contract__( + requires(memory_no_alias(state, sizeof(uint64_t) * 25 * 4)) + assigns(memory_slice(state, sizeof(uint64_t) * 25 * 4)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged_u64(state, 25 * 4)) +); +#endif /* MLD_USE_FIPS202_X4_NATIVE */ + +#endif /* !MLD_FIPS202_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/auto.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/auto.h new file mode 100644 index 0000000000..0a09c733c8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/auto.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_AUTO_H +#define MLD_FIPS202_NATIVE_AUTO_H + +/* + * Default FIPS202 backend + */ +#include "../../sys.h" + +#if defined(MLD_SYS_AARCH64) +#include "aarch64/auto.h" +#endif + +#if defined(MLD_SYS_X86_64) && defined(MLD_SYS_X86_64_AVX2) +#include "x86_64/xkcp.h" +#endif + +#endif /* !MLD_FIPS202_NATIVE_AUTO_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c new file mode 100644 index 0000000000..4eaad2fd66 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* +Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, +Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby +denoted as "the implementer". + +For more information, feedback or questions, please refer to our websites: +http://keccak.noekeon.org/ +http://keyak.noekeon.org/ +http://ketje.noekeon.org/ + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +/* + * Changes for mlkem-native/mldsa-native: + * - copyFromState and copyToState operate on uninterleaved + * Keccak states in memory. + */ + +#include "../../../../common.h" +#if defined(MLD_FIPS202_X86_64_XKCP) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include + +#include "KeccakP_1600_times4_SIMD256.h" + +#ifndef MLD_SYS_LITTLE_ENDIAN +#error Expecting a little-endian platform +#endif + +#define ANDnu256(a, b) _mm256_andnot_si256(a, b) +#define CONST256(a) _mm256_load_si256((const __m256i *)&(a)) +#define CONST256_64(a) (__m256i) _mm256_broadcast_sd((const double *)(&a)) +#define ROL64in256(d, a, o) \ + d = _mm256_or_si256(_mm256_slli_epi64(a, o), _mm256_srli_epi64(a, 64 - (o))) +#define ROL64in256_8(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho8)) +#define ROL64in256_56(d, a) d = _mm256_shuffle_epi8(a, CONST256(rho56)) +static const uint64_t rho8[4] = {0x0605040302010007, 0x0E0D0C0B0A09080F, + 0x1615141312111017, 0x1E1D1C1B1A19181F}; +static const uint64_t rho56[4] = {0x0007060504030201, 0x080F0E0D0C0B0A09, + 0x1017161514131211, 0x181F1E1D1C1B1A19}; +#define STORE256(a, b) _mm256_store_si256((__m256i *)&(a), b) +#define XOR256(a, b) _mm256_xor_si256(a, b) +#define XOReq256(a, b) a = _mm256_xor_si256(a, b) + +#define SnP_laneLengthInBytes 8 + +#define declareABCDE \ + __m256i Aba, Abe, Abi, Abo, Abu; \ + __m256i Aga, Age, Agi, Ago, Agu; \ + __m256i Aka, Ake, Aki, Ako, Aku; \ + __m256i Ama, Ame, Ami, Amo, Amu; \ + __m256i Asa, Ase, Asi, Aso, Asu; \ + __m256i Bba, Bbe, Bbi, Bbo, Bbu; \ + __m256i Bga, Bge, Bgi, Bgo, Bgu; \ + __m256i Bka, Bke, Bki, Bko, Bku; \ + __m256i Bma, Bme, Bmi, Bmo, Bmu; \ + __m256i Bsa, Bse, Bsi, Bso, Bsu; \ + __m256i Ca, Ce, Ci, Co, Cu; \ + __m256i Ca1, Ce1, Ci1, Co1, Cu1; \ + __m256i Da, De, Di, Do, Du; \ + __m256i Eba, Ebe, Ebi, Ebo, Ebu; \ + __m256i Ega, Ege, Egi, Ego, Egu; \ + __m256i Eka, Eke, Eki, Eko, Eku; \ + __m256i Ema, Eme, Emi, Emo, Emu; \ + __m256i Esa, Ese, Esi, Eso, Esu; + +#define prepareTheta \ + Ca = XOR256(Aba, XOR256(Aga, XOR256(Aka, XOR256(Ama, Asa)))); \ + Ce = XOR256(Abe, XOR256(Age, XOR256(Ake, XOR256(Ame, Ase)))); \ + Ci = XOR256(Abi, XOR256(Agi, XOR256(Aki, XOR256(Ami, Asi)))); \ + Co = XOR256(Abo, XOR256(Ago, XOR256(Ako, XOR256(Amo, Aso)))); \ + Cu = XOR256(Abu, XOR256(Agu, XOR256(Aku, XOR256(Amu, Asu)))); + +/* + * --- Theta Rho Pi Chi Iota Prepare-theta + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + Ca = E##ba; \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + Ce = E##be; \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + Ci = E##bi; \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + Co = E##bo; \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + Cu = E##bu; \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(Ca, E##ga); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(Ce, E##ge); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + XOReq256(Ci, E##gi); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + XOReq256(Co, E##go); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + XOReq256(Cu, E##gu); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(Ca, E##ka); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(Ce, E##ke); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + XOReq256(Ci, E##ki); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + XOReq256(Co, E##ko); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + XOReq256(Cu, E##ku); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(Ca, E##ma); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(Ce, E##me); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + XOReq256(Ci, E##mi); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + XOReq256(Co, E##mo); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + XOReq256(Cu, E##mu); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(Ca, E##sa); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(Ce, E##se); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + XOReq256(Ci, E##si); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + XOReq256(Co, E##so); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); \ + XOReq256(Cu, E##su); + + +/* + * --- Theta Rho Pi Chi Iota + * --- 64-bit lanes mapped to 64-bit words + */ +#define thetaRhoPiChiIota(i, A, E) \ + ROL64in256(Ce1, Ce, 1); \ + Da = XOR256(Cu, Ce1); \ + ROL64in256(Ci1, Ci, 1); \ + De = XOR256(Ca, Ci1); \ + ROL64in256(Co1, Co, 1); \ + Di = XOR256(Ce, Co1); \ + ROL64in256(Cu1, Cu, 1); \ + Do = XOR256(Ci, Cu1); \ + ROL64in256(Ca1, Ca, 1); \ + Du = XOR256(Co, Ca1); \ + \ + XOReq256(A##ba, Da); \ + Bba = A##ba; \ + XOReq256(A##ge, De); \ + ROL64in256(Bbe, A##ge, 44); \ + XOReq256(A##ki, Di); \ + ROL64in256(Bbi, A##ki, 43); \ + E##ba = XOR256(Bba, ANDnu256(Bbe, Bbi)); \ + XOReq256(E##ba, CONST256_64(keccakf1600RoundConstants[i])); \ + XOReq256(A##mo, Do); \ + ROL64in256(Bbo, A##mo, 21); \ + E##be = XOR256(Bbe, ANDnu256(Bbi, Bbo)); \ + XOReq256(A##su, Du); \ + ROL64in256(Bbu, A##su, 14); \ + E##bi = XOR256(Bbi, ANDnu256(Bbo, Bbu)); \ + E##bo = XOR256(Bbo, ANDnu256(Bbu, Bba)); \ + E##bu = XOR256(Bbu, ANDnu256(Bba, Bbe)); \ + \ + XOReq256(A##bo, Do); \ + ROL64in256(Bga, A##bo, 28); \ + XOReq256(A##gu, Du); \ + ROL64in256(Bge, A##gu, 20); \ + XOReq256(A##ka, Da); \ + ROL64in256(Bgi, A##ka, 3); \ + E##ga = XOR256(Bga, ANDnu256(Bge, Bgi)); \ + XOReq256(A##me, De); \ + ROL64in256(Bgo, A##me, 45); \ + E##ge = XOR256(Bge, ANDnu256(Bgi, Bgo)); \ + XOReq256(A##si, Di); \ + ROL64in256(Bgu, A##si, 61); \ + E##gi = XOR256(Bgi, ANDnu256(Bgo, Bgu)); \ + E##go = XOR256(Bgo, ANDnu256(Bgu, Bga)); \ + E##gu = XOR256(Bgu, ANDnu256(Bga, Bge)); \ + \ + XOReq256(A##be, De); \ + ROL64in256(Bka, A##be, 1); \ + XOReq256(A##gi, Di); \ + ROL64in256(Bke, A##gi, 6); \ + XOReq256(A##ko, Do); \ + ROL64in256(Bki, A##ko, 25); \ + E##ka = XOR256(Bka, ANDnu256(Bke, Bki)); \ + XOReq256(A##mu, Du); \ + ROL64in256_8(Bko, A##mu); \ + E##ke = XOR256(Bke, ANDnu256(Bki, Bko)); \ + XOReq256(A##sa, Da); \ + ROL64in256(Bku, A##sa, 18); \ + E##ki = XOR256(Bki, ANDnu256(Bko, Bku)); \ + E##ko = XOR256(Bko, ANDnu256(Bku, Bka)); \ + E##ku = XOR256(Bku, ANDnu256(Bka, Bke)); \ + \ + XOReq256(A##bu, Du); \ + ROL64in256(Bma, A##bu, 27); \ + XOReq256(A##ga, Da); \ + ROL64in256(Bme, A##ga, 36); \ + XOReq256(A##ke, De); \ + ROL64in256(Bmi, A##ke, 10); \ + E##ma = XOR256(Bma, ANDnu256(Bme, Bmi)); \ + XOReq256(A##mi, Di); \ + ROL64in256(Bmo, A##mi, 15); \ + E##me = XOR256(Bme, ANDnu256(Bmi, Bmo)); \ + XOReq256(A##so, Do); \ + ROL64in256_56(Bmu, A##so); \ + E##mi = XOR256(Bmi, ANDnu256(Bmo, Bmu)); \ + E##mo = XOR256(Bmo, ANDnu256(Bmu, Bma)); \ + E##mu = XOR256(Bmu, ANDnu256(Bma, Bme)); \ + \ + XOReq256(A##bi, Di); \ + ROL64in256(Bsa, A##bi, 62); \ + XOReq256(A##go, Do); \ + ROL64in256(Bse, A##go, 55); \ + XOReq256(A##ku, Du); \ + ROL64in256(Bsi, A##ku, 39); \ + E##sa = XOR256(Bsa, ANDnu256(Bse, Bsi)); \ + XOReq256(A##ma, Da); \ + ROL64in256(Bso, A##ma, 41); \ + E##se = XOR256(Bse, ANDnu256(Bsi, Bso)); \ + XOReq256(A##se, De); \ + ROL64in256(Bsu, A##se, 2); \ + E##si = XOR256(Bsi, ANDnu256(Bso, Bsu)); \ + E##so = XOR256(Bso, ANDnu256(Bsu, Bsa)); \ + E##su = XOR256(Bsu, ANDnu256(Bsa, Bse)); + + +static MLD_ALIGN const uint64_t keccakf1600RoundConstants[24] = { + (uint64_t)0x0000000000000001ULL, (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; + +#include + +#define copyFromState(X, state) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m256i _idx = \ + _mm256_set_epi64x((long long)&state64[75], (long long)&state64[50], \ + (long long)&state64[25], (long long)&state64[0]); \ + X##ba = _mm256_i64gather_epi64((long long *)(0 * 8), _idx, 1); \ + X##be = _mm256_i64gather_epi64((long long *)(1 * 8), _idx, 1); \ + X##bi = _mm256_i64gather_epi64((long long *)(2 * 8), _idx, 1); \ + X##bo = _mm256_i64gather_epi64((long long *)(3 * 8), _idx, 1); \ + X##bu = _mm256_i64gather_epi64((long long *)(4 * 8), _idx, 1); \ + X##ga = _mm256_i64gather_epi64((long long *)(5 * 8), _idx, 1); \ + X##ge = _mm256_i64gather_epi64((long long *)(6 * 8), _idx, 1); \ + X##gi = _mm256_i64gather_epi64((long long *)(7 * 8), _idx, 1); \ + X##go = _mm256_i64gather_epi64((long long *)(8 * 8), _idx, 1); \ + X##gu = _mm256_i64gather_epi64((long long *)(9 * 8), _idx, 1); \ + X##ka = _mm256_i64gather_epi64((long long *)(10 * 8), _idx, 1); \ + X##ke = _mm256_i64gather_epi64((long long *)(11 * 8), _idx, 1); \ + X##ki = _mm256_i64gather_epi64((long long *)(12 * 8), _idx, 1); \ + X##ko = _mm256_i64gather_epi64((long long *)(13 * 8), _idx, 1); \ + X##ku = _mm256_i64gather_epi64((long long *)(14 * 8), _idx, 1); \ + X##ma = _mm256_i64gather_epi64((long long *)(15 * 8), _idx, 1); \ + X##me = _mm256_i64gather_epi64((long long *)(16 * 8), _idx, 1); \ + X##mi = _mm256_i64gather_epi64((long long *)(17 * 8), _idx, 1); \ + X##mo = _mm256_i64gather_epi64((long long *)(18 * 8), _idx, 1); \ + X##mu = _mm256_i64gather_epi64((long long *)(19 * 8), _idx, 1); \ + X##sa = _mm256_i64gather_epi64((long long *)(20 * 8), _idx, 1); \ + X##se = _mm256_i64gather_epi64((long long *)(21 * 8), _idx, 1); \ + X##si = _mm256_i64gather_epi64((long long *)(22 * 8), _idx, 1); \ + X##so = _mm256_i64gather_epi64((long long *)(23 * 8), _idx, 1); \ + X##su = _mm256_i64gather_epi64((long long *)(24 * 8), _idx, 1); \ + } while (0); + +#define SCATTER_STORE256(state, idx, v) \ + do \ + { \ + const uint64_t *state64 = (const uint64_t *)(state); \ + __m128d t = _mm_castsi128_pd(_mm256_castsi256_si128((v))); \ + _mm_storel_pd((double *)&state64[0 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[25 + (idx)], t); \ + t = _mm_castsi128_pd(_mm256_extracti128_si256((v), 1)); \ + _mm_storel_pd((double *)&state64[50 + (idx)], t); \ + _mm_storeh_pd((double *)&state64[75 + (idx)], t); \ + } while (0) + +#define copyToState(state, X) \ + SCATTER_STORE256(state, 0, X##ba); \ + SCATTER_STORE256(state, 1, X##be); \ + SCATTER_STORE256(state, 2, X##bi); \ + SCATTER_STORE256(state, 3, X##bo); \ + SCATTER_STORE256(state, 4, X##bu); \ + SCATTER_STORE256(state, 5, X##ga); \ + SCATTER_STORE256(state, 6, X##ge); \ + SCATTER_STORE256(state, 7, X##gi); \ + SCATTER_STORE256(state, 8, X##go); \ + SCATTER_STORE256(state, 9, X##gu); \ + SCATTER_STORE256(state, 10, X##ka); \ + SCATTER_STORE256(state, 11, X##ke); \ + SCATTER_STORE256(state, 12, X##ki); \ + SCATTER_STORE256(state, 13, X##ko); \ + SCATTER_STORE256(state, 14, X##ku); \ + SCATTER_STORE256(state, 15, X##ma); \ + SCATTER_STORE256(state, 16, X##me); \ + SCATTER_STORE256(state, 17, X##mi); \ + SCATTER_STORE256(state, 18, X##mo); \ + SCATTER_STORE256(state, 19, X##mu); \ + SCATTER_STORE256(state, 20, X##sa); \ + SCATTER_STORE256(state, 21, X##se); \ + SCATTER_STORE256(state, 22, X##si); \ + SCATTER_STORE256(state, 23, X##so); \ + SCATTER_STORE256(state, 24, X##su); + +#define copyStateVariables(X, Y) \ + X##ba = Y##ba; \ + X##be = Y##be; \ + X##bi = Y##bi; \ + X##bo = Y##bo; \ + X##bu = Y##bu; \ + X##ga = Y##ga; \ + X##ge = Y##ge; \ + X##gi = Y##gi; \ + X##go = Y##go; \ + X##gu = Y##gu; \ + X##ka = Y##ka; \ + X##ke = Y##ke; \ + X##ki = Y##ki; \ + X##ko = Y##ko; \ + X##ku = Y##ku; \ + X##ma = Y##ma; \ + X##me = Y##me; \ + X##mi = Y##mi; \ + X##mo = Y##mo; \ + X##mu = Y##mu; \ + X##sa = Y##sa; \ + X##se = Y##se; \ + X##si = Y##si; \ + X##so = Y##so; \ + X##su = Y##su; + +/* clang-format off */ +#define rounds24 \ + prepareTheta \ + thetaRhoPiChiIotaPrepareTheta( 0, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 1, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 2, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 3, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 4, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 5, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 6, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 7, E, A) \ + thetaRhoPiChiIotaPrepareTheta( 8, A, E) \ + thetaRhoPiChiIotaPrepareTheta( 9, E, A) \ + thetaRhoPiChiIotaPrepareTheta(10, A, E) \ + thetaRhoPiChiIotaPrepareTheta(11, E, A) \ + thetaRhoPiChiIotaPrepareTheta(12, A, E) \ + thetaRhoPiChiIotaPrepareTheta(13, E, A) \ + thetaRhoPiChiIotaPrepareTheta(14, A, E) \ + thetaRhoPiChiIotaPrepareTheta(15, E, A) \ + thetaRhoPiChiIotaPrepareTheta(16, A, E) \ + thetaRhoPiChiIotaPrepareTheta(17, E, A) \ + thetaRhoPiChiIotaPrepareTheta(18, A, E) \ + thetaRhoPiChiIotaPrepareTheta(19, E, A) \ + thetaRhoPiChiIotaPrepareTheta(20, A, E) \ + thetaRhoPiChiIotaPrepareTheta(21, E, A) \ + thetaRhoPiChiIotaPrepareTheta(22, A, E) \ + thetaRhoPiChiIota(23, E, A) +/* clang-format on */ + +void mld_keccakf1600x4_permute24(void *states) +{ + __m256i *statesAsLanes = (__m256i *)states; + declareABCDE copyFromState(A, statesAsLanes) + rounds24 copyToState(statesAsLanes, A) +} + +#else /* MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(fips202_avx2_keccakx4) + +#endif /* !(MLD_FIPS202_X86_64_XKCP && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef ANDnu256 +#undef CONST256 +#undef CONST256_64 +#undef ROL64in256 +#undef ROL64in256_8 +#undef ROL64in256_56 +#undef STORE256 +#undef XOR256 +#undef XOReq256 +#undef SnP_laneLengthInBytes +#undef declareABCDE +#undef prepareTheta +#undef thetaRhoPiChiIotaPrepareTheta +#undef thetaRhoPiChiIota +#undef copyFromState +#undef SCATTER_STORE256 +#undef copyToState +#undef copyStateVariables +#undef rounds24 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h new file mode 100644 index 0000000000..3499d38e2c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H +#define MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H + +#include "../../../../common.h" + +#define mld_keccakf1600x4_permute24 \ + MLD_NAMESPACE(KeccakP1600times4_PermuteAll_24rounds) +void mld_keccakf1600x4_permute24(void *states); + +#endif /* !MLD_FIPS202_NATIVE_X86_64_SRC_KECCAKP_1600_TIMES4_SIMD256_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/x86_64/xkcp.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/x86_64/xkcp.h new file mode 100644 index 0000000000..c03642d7e0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/fips202/native/x86_64/xkcp.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_FIPS202_NATIVE_X86_64_XKCP_H +#define MLD_FIPS202_NATIVE_X86_64_XKCP_H + +#include "../../../common.h" + +#define MLD_FIPS202_X86_64_XKCP + +#if !defined(__ASSEMBLER__) +#include +#include "../api.h" +#include "src/KeccakP_1600_times4_SIMD256.h" + +#define MLD_USE_FIPS202_X4_NATIVE +static MLD_INLINE int mld_keccak_f1600_x4_native(uint64_t *state) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_keccakf1600x4_permute24(state); + return MLD_NATIVE_FUNC_SUCCESS; +} +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_FIPS202_NATIVE_X86_64_XKCP_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/meta.h new file mode 100644 index 0000000000..c6f6ad47b0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/meta.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_META_H +#define MLD_NATIVE_AARCH64_META_H + +/* Set of primitives that this backend replaces */ +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_AARCH64 + + +#if !defined(__ASSEMBLER__) +#include "../api.h" +#include "src/arith_native_aarch64.h" + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + mld_ntt_asm(data, mld_aarch64_ntt_zetas_layer123456, + mld_aarch64_ntt_zetas_layer78); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + mld_intt_asm(data, mld_aarch64_intt_zetas_layer78, + mld_aarch64_intt_zetas_layer123456); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + if (len != MLDSA_N || + buflen % 24 != 0) /* NEON support is mandatory for AArch64 */ + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N, hence, this cast is safe. */ + return (int)mld_rej_uniform_asm(r, buf, buflen, mld_rej_uniform_table); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + uint64_t outlen; + /* AArch64 implementation assumes specific buffer lengths */ + if (len != MLDSA_N || buflen != MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_asm(r, buf, buflen, mld_rej_uniform_eta_table); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_32_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + mld_poly_decompose_88_asm(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + mld_poly_caddq_asm(a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_32_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + mld_poly_use_hint_88_asm(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + return mld_poly_chknorm_asm(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_17_asm(r, buf, mld_polyz_unpack_17_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *buf) +{ + mld_polyz_unpack_19_asm(r, buf, mld_polyz_unpack_19_indices); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t out[MLDSA_N], const int32_t in0[MLDSA_N], + const int32_t in1[MLDSA_N]) +{ + mld_poly_pointwise_montgomery_asm(out, in0, in1); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l4_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l5_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + mld_polyvecl_pointwise_acc_montgomery_l7_asm(w, (const int32_t *)u, + (const int32_t *)v); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ +#endif /* !MLD_NATIVE_AARCH64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/src/aarch64_zetas.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/src/aarch64_zetas.c new file mode 100644 index 0000000000..9ab7b9a68c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/src/aarch64_zetas.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Table of zeta values used in the AArch64 forward NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer123456[] = { + -3572223, -915382907, 3765607, 964937599, 3761513, 963888510, + -3201494, -820383522, -2883726, -738955404, -3145678, -806080660, + -3201430, -820367122, 0, 0, -601683, -154181397, + -3370349, -863652652, -4063053, -1041158200, 3602218, 923069133, + 3182878, 815613168, 2740543, 702264730, -3586446, -919027554, + 0, 0, 3542485, 907762539, 2663378, 682491182, + -1674615, -429120452, -3110818, -797147778, 2101410, 538486762, + 3704823, 949361686, 1159875, 297218217, 0, 0, + 2682288, 687336873, -3524442, -903139016, -434125, -111244624, + 394148, 101000509, 928749, 237992130, 1095468, 280713909, + -3506380, -898510625, 0, 0, 2129892, 545785280, + 676590, 173376332, -1335936, -342333886, 2071829, 530906624, + -4018989, -1029866791, 3241972, 830756018, 2156050, 552488273, + 0, 0, 3764867, 964747974, -3227876, -827143915, + 1714295, 439288460, 3415069, 875112161, 1759347, 450833045, + -817536, -209493775, -3574466, -915957677, 0, 0, + -1005239, -257592709, 2453983, 628833668, 1460718, 374309300, + 3756790, 962678241, -1935799, -496048908, -1716988, -439978542, + -3950053, -1012201926, 0, 0, 557458, 142848732, + -642628, -164673562, -3585098, -918682129, -2897314, -742437332, + 3192354, 818041395, 556856, 142694469, 3870317, 991769559, + 0, 0, -1221177, -312926867, 2815639, 721508096, + 2283733, 585207070, 2917338, 747568486, 1853806, 475038184, + 3345963, 857403734, 1858416, 476219497, 0, 0, +}; + +MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer78[] = { + 3073009, 1277625, -2635473, 3852015, 787459213, + 327391679, -675340520, 987079667, 1753, -2659525, + 2660408, -59148, 449207, -681503850, 681730119, + -15156688, -1935420, -1455890, -1780227, 2772600, + -495951789, -373072124, -456183549, 710479343, 4183372, + -3222807, -3121440, -274060, 1071989969, -825844983, + -799869667, -70227934, 1182243, 636927, -3956745, + -3284915, 302950022, 163212680, -1013916752, -841760171, + 87208, -3965306, -2296397, -3716946, 22347069, + -1016110510, -588452222, -952468207, 2508980, 2028118, + 1937570, -3815725, 642926661, 519705671, 496502727, + -977780347, -27812, 1009365, -1979497, -3956944, + -7126831, 258649997, -507246529, -1013967746, 822541, + -2454145, 1596822, -3759465, 210776307, -628875181, + 409185979, -963363710, 2811291, -2983781, -1109516, + 4158088, 720393920, -764594519, -284313712, 1065510939, + -1685153, 2678278, -3551006, -250446, -431820817, + 686309310, -909946047, -64176841, -3410568, -3768948, + 635956, -2455377, -873958779, -965793731, 162963861, + -629190881, 1528066, 482649, 1148858, -2962264, + 391567239, 123678909, 294395108, -759080783, -4146264, + 2192938, 2387513, -268456, -1062481036, 561940831, + 611800717, -68791907, -1772588, -1727088, -3611750, + -3180456, -454226054, -442566669, -925511710, -814992530, + -565603, 169688, 2462444, -3334383, -144935890, + 43482586, 631001801, -854436357, 3747250, 1239911, + 3195676, 1254190, 960233614, 317727459, 818892658, + 321386456, 2296099, -3838479, 2642980, -12417, + 588375860, -983611064, 677264190, -3181859, -4166425, + -3488383, 1987814, -3197248, -1067647297, -893898890, + 509377762, -819295484, 2998219, -89301, -1354892, + -1310261, 768294260, -22883400, -347191365, -335754661, + 141835, 2513018, 613238, -2218467, 36345249, + 643961400, 157142369, -568482643, 1736313, 235407, + -3250154, 3258457, 444930577, 60323094, -832852657, + 834980303, -458740, 4040196, 2039144, -818761, + -117552223, 1035301089, 522531086, -209807681, -1921994, + -3472069, -1879878, -2178965, -492511373, -889718424, + -481719139, -558360247, -2579253, 1787943, -2391089, + -2254727, -660934133, 458160776, -612717067, -577774276, + -1623354, -2374402, 586241, 527981, -415984810, + -608441020, 150224382, 135295244, 2105286, -2033807, + -1179613, -2743411, 539479988, -521163479, -302276083, + -702999655, 3482206, -4182915, -1300016, -2362063, + 892316032, -1071872863, -333129378, -605279149, -1476985, + 2491325, 507927, -724804, -378477722, 638402564, + 130156402, -185731180, 1994046, -1393159, -1187885, + -1834526, 510974714, -356997292, -304395785, -470097680, + -1317678, 2461387, 3035980, 621164, -337655269, + 630730945, 777970524, 159173408, -3033742, 2647994, + -2612853, 749577, -777397036, 678549029, -669544140, + 192079267, -338420, 3009748, 4148469, -4022750, + -86720197, 771248568, 1063046068, -1030830548, 3901472, + -1226661, 2925816, 3374250, 999753034, -314332144, + 749740976, 864652284, 3980599, -1615530, 1665318, + 1163598, 1020029345, -413979908, 426738094, 298172236, + 2569011, 1723229, 2028038, -3369273, 658309618, + 441577800, 519685171, -863376927, 1356448, -2775755, + 2683270, -2778788, 347590090, -711287812, 687588511, + -712065019, 3994671, -1370517, 3363542, 545376, + 1023635298, -351195274, 861908357, 139752717, -11879, + 3020393, 214880, -770441, -3043996, 773976352, + 55063046, -197425671, -3467665, 2312838, -653275, + -459163, -888589898, 592665232, -167401858, -117660617, + 3105558, 508145, 860144, 140244, 795799901, + 130212265, 220412084, 35937555, -1103344, -553718, + 3430436, -1514152, -282732136, -141890356, 879049958, + -388001774, 348812, -327848, 1011223, -2354215, + 89383150, -84011120, 259126110, -603268097, -2185084, + 2358373, -3014420, 2926054, -559928242, 604333585, + -772445769, 749801963, 3123762, -2193087, -1716814, + -392707, 800464680, -561979013, -439933955, -100631253, + -3818627, -1922253, -2236726, 1744507, -978523985, + -492577742, -573161516, 447030292, -303005, -3974485, + 1900052, 1054478, -77645096, -1018462631, 486888731, + 270210213, 3531229, -3773731, -781875, -731434, + 904878186, -967019376, -200355636, -187430119, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer78[] = { + -1744507, 2236726, 1922253, 3818627, -447030292, 573161516, + 492577742, 978523985, 731434, 781875, 3773731, -3531229, + 187430119, 200355636, 967019376, -904878186, -1054478, -1900052, + 3974485, 303005, -270210213, -486888731, 1018462631, 77645096, + 2354215, -1011223, 327848, -348812, 603268097, -259126110, + 84011120, -89383150, 392707, 1716814, 2193087, -3123762, + 100631253, 439933955, 561979013, -800464680, -2926054, 3014420, + -2358373, 2185084, -749801963, 772445769, -604333585, 559928242, + 459163, 653275, -2312838, 3467665, 117660617, 167401858, + -592665232, 888589898, 1514152, -3430436, 553718, 1103344, + 388001774, -879049958, 141890356, 282732136, -140244, -860144, + -508145, -3105558, -35937555, -220412084, -130212265, -795799901, + 2778788, -2683270, 2775755, -1356448, 712065019, -687588511, + 711287812, -347590090, 770441, -214880, -3020393, 11879, + 197425671, -55063046, -773976352, 3043996, -545376, -3363542, + 1370517, -3994671, -139752717, -861908357, 351195274, -1023635298, + -3374250, -2925816, 1226661, -3901472, -864652284, -749740976, + 314332144, -999753034, 3369273, -2028038, -1723229, -2569011, + 863376927, -519685171, -441577800, -658309618, -1163598, -1665318, + 1615530, -3980599, -298172236, -426738094, 413979908, -1020029345, + -621164, -3035980, -2461387, 1317678, -159173408, -777970524, + -630730945, 337655269, 4022750, -4148469, -3009748, 338420, + 1030830548, -1063046068, -771248568, 86720197, -749577, 2612853, + -2647994, 3033742, -192079267, 669544140, -678549029, 777397036, + 2362063, 1300016, 4182915, -3482206, 605279149, 333129378, + 1071872863, -892316032, 1834526, 1187885, 1393159, -1994046, + 470097680, 304395785, 356997292, -510974714, 724804, -507927, + -2491325, 1476985, 185731180, -130156402, -638402564, 378477722, + 2254727, 2391089, -1787943, 2579253, 577774276, 612717067, + -458160776, 660934133, 2743411, 1179613, 2033807, -2105286, + 702999655, 302276083, 521163479, -539479988, -527981, -586241, + 2374402, 1623354, -135295244, -150224382, 608441020, 415984810, + -3258457, 3250154, -235407, -1736313, -834980303, 832852657, + -60323094, -444930577, 2178965, 1879878, 3472069, 1921994, + 558360247, 481719139, 889718424, 492511373, 818761, -2039144, + -4040196, 458740, 209807681, -522531086, -1035301089, 117552223, + 3197248, -1987814, 3488383, 4166425, 819295484, -509377762, + 893898890, 1067647297, 2218467, -613238, -2513018, -141835, + 568482643, -157142369, -643961400, -36345249, 1310261, 1354892, + 89301, -2998219, 335754661, 347191365, 22883400, -768294260, + 3334383, -2462444, -169688, 565603, 854436357, -631001801, + -43482586, 144935890, 12417, -2642980, 3838479, -2296099, + 3181859, -677264190, 983611064, -588375860, -1254190, -3195676, + -1239911, -3747250, -321386456, -818892658, -317727459, -960233614, + 2962264, -1148858, -482649, -1528066, 759080783, -294395108, + -123678909, -391567239, 3180456, 3611750, 1727088, 1772588, + 814992530, 925511710, 442566669, 454226054, 268456, -2387513, + -2192938, 4146264, 68791907, -611800717, -561940831, 1062481036, + -4158088, 1109516, 2983781, -2811291, -1065510939, 284313712, + 764594519, -720393920, 2455377, -635956, 3768948, 3410568, + 629190881, -162963861, 965793731, 873958779, 250446, 3551006, + -2678278, 1685153, 64176841, 909946047, -686309310, 431820817, + 3815725, -1937570, -2028118, -2508980, 977780347, -496502727, + -519705671, -642926661, 3759465, -1596822, 2454145, -822541, + 963363710, -409185979, 628875181, -210776307, 3956944, 1979497, + -1009365, 27812, 1013967746, 507246529, -258649997, 7126831, + 274060, 3121440, 3222807, -4183372, 70227934, 799869667, + 825844983, -1071989969, 3716946, 2296397, 3965306, -87208, + 952468207, 588452222, 1016110510, -22347069, 3284915, 3956745, + -636927, -1182243, 841760171, 1013916752, -163212680, -302950022, + -3852015, 2635473, -1277625, -3073009, -987079667, 675340520, + -327391679, -787459213, -2772600, 1780227, 1455890, 1935420, + -710479343, 456183549, 373072124, 495951789, 59148, -2660408, + 2659525, -1753, 15156688, -681730119, 681503850, -449207, +}; + +MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer123456[] = { + -2283733, -585207070, 0, 0, -1858416, -476219497, + -3345963, -857403734, -2815639, -721508096, 0, 0, + -1853806, -475038184, -2917338, -747568486, 3585098, 918682129, + 0, 0, -3870317, -991769559, -556856, -142694469, + 642628, 164673562, 0, 0, -3192354, -818041395, + 2897314, 742437332, -1460718, -374309300, 0, 0, + 3950053, 1012201926, 1716988, 439978542, -2453983, -628833668, + 0, 0, 1935799, 496048908, -3756790, -962678241, + -1714295, -439288460, 0, 0, 3574466, 915957677, + 817536, 209493775, 3227876, 827143915, 0, 0, + -1759347, -450833045, -3415069, -875112161, 1335936, 342333886, + 0, 0, -2156050, -552488273, -3241972, -830756018, + -676590, -173376332, 0, 0, 4018989, 1029866791, + -2071829, -530906624, 434125, 111244624, 0, 0, + 3506380, 898510625, -1095468, -280713909, 3524442, 903139016, + 0, 0, -928749, -237992130, -394148, -101000509, + 1674615, 429120452, 0, 0, -1159875, -297218217, + -3704823, -949361686, -2663378, -682491182, 0, 0, + -2101410, -538486762, 3110818, 797147778, 4063053, 1041158200, + 0, 0, 3586446, 919027554, -2740543, -702264730, + 3370349, 863652652, 0, 0, -3182878, -815613168, + -3602218, -923069133, -294725, -75523344, -3761513, -963888510, + -3765607, -964937599, 3201430, 820367122, 3145678, 806080660, + 2883726, 738955404, 3201494, 820383522, 1221177, 312926867, + -557458, -142848732, 1005239, 257592709, -3764867, -964747974, + -2129892, -545785280, -2682288, -687336873, -3542485, -907762539, + 601683, 154181397, 0, 0, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_zetas) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/src/arith_native_aarch64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/src/arith_native_aarch64.h new file mode 100644 index 0000000000..e77f55014c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/src/arith_native_aarch64.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H +#define MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H + +#include +#include "../../../common.h" + +#define mld_aarch64_ntt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_ntt_zetas_layer123456) +#define mld_aarch64_ntt_zetas_layer78 MLD_NAMESPACE(aarch64_ntt_zetas_layer78) + +#define mld_aarch64_intt_zetas_layer78 MLD_NAMESPACE(aarch64_intt_zetas_layer78) +#define mld_aarch64_intt_zetas_layer123456 \ + MLD_NAMESPACE(aarch64_intt_zetas_layer123456) + +extern const int32_t mld_aarch64_ntt_zetas_layer123456[]; +extern const int32_t mld_aarch64_ntt_zetas_layer78[]; + +extern const int32_t mld_aarch64_intt_zetas_layer78[]; +extern const int32_t mld_aarch64_intt_zetas_layer123456[]; + +#define mld_rej_uniform_table MLD_NAMESPACE(rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[]; +#define mld_rej_uniform_eta_table MLD_NAMESPACE(rej_uniform_eta_table) +extern const uint8_t mld_rej_uniform_eta_table[]; + +#define mld_polyz_unpack_17_indices MLD_NAMESPACE(polyz_unpack_17_indices) +extern const uint8_t mld_polyz_unpack_17_indices[]; +#define mld_polyz_unpack_19_indices MLD_NAMESPACE(polyz_unpack_19_indices) +extern const uint8_t mld_polyz_unpack_19_indices[]; + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_ntt_asm MLD_NAMESPACE(ntt_asm) +void mld_ntt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_intt_asm MLD_NAMESPACE(intt_asm) +void mld_intt_asm(int32_t *, const int32_t *, const int32_t *); + +#define mld_rej_uniform_asm MLD_NAMESPACE(rej_uniform_asm) +uint64_t mld_rej_uniform_asm(int32_t *r, const uint8_t *buf, unsigned buflen, + const uint8_t *table); + +#define mld_rej_uniform_eta2_asm MLD_NAMESPACE(rej_uniform_eta2_asm) +uint64_t mld_rej_uniform_eta2_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_rej_uniform_eta4_asm MLD_NAMESPACE(rej_uniform_eta4_asm) +uint64_t mld_rej_uniform_eta4_asm(int32_t *r, const uint8_t *buf, + unsigned buflen, const uint8_t *table); + +#define mld_poly_decompose_32_asm MLD_NAMESPACE(poly_decompose_32_asm) +void mld_poly_decompose_32_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_asm MLD_NAMESPACE(poly_decompose_88_asm) +void mld_poly_decompose_88_asm(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_asm MLD_NAMESPACE(poly_caddq_asm) +void mld_poly_caddq_asm(int32_t *a); + +#define mld_poly_use_hint_32_asm MLD_NAMESPACE(poly_use_hint_32_asm) +void mld_poly_use_hint_32_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_asm MLD_NAMESPACE(poly_use_hint_88_asm) +void mld_poly_use_hint_88_asm(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_asm MLD_NAMESPACE(poly_chknorm_asm) +int mld_poly_chknorm_asm(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_asm MLD_NAMESPACE(polyz_unpack_17_asm) +void mld_polyz_unpack_17_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_polyz_unpack_19_asm MLD_NAMESPACE(polyz_unpack_19_asm) +void mld_polyz_unpack_19_asm(int32_t *r, const uint8_t *buf, + const uint8_t *indices); + +#define mld_poly_pointwise_montgomery_asm \ + MLD_NAMESPACE(poly_pointwise_montgomery_asm) +void mld_poly_pointwise_montgomery_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l4_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l4_asm) +void mld_polyvecl_pointwise_acc_montgomery_l4_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l5_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l5_asm) +void mld_polyvecl_pointwise_acc_montgomery_l5_asm(int32_t *, const int32_t *, + const int32_t *); + +#define mld_polyvecl_pointwise_acc_montgomery_l7_asm \ + MLD_NAMESPACE(polyvecl_pointwise_acc_montgomery_l7_asm) +void mld_polyvecl_pointwise_acc_montgomery_l7_asm(int32_t *, const int32_t *, + const int32_t *); + +#endif /* !MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_table.c new file mode 100644 index 0000000000..7ef915b587 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_table.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* Table of indices used for tbl instructions in polyz_unpack_{17,19}. */ + +MLD_ALIGN const uint8_t mld_polyz_unpack_17_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, + 9, 10, 11, 255, 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, + 2, 3, 4, 255, 4, 5, 6, 255, 6, 7, 8, 255, 8, 9, 10, 255, + 11, 12, 13, 255, 13, 14, 15, 255, 15, 16, 17, 255, 17, 18, 19, 255, +}; + +MLD_ALIGN const uint8_t mld_polyz_unpack_19_indices[] = { + 0, 1, 2, 255, 2, 3, 4, 255, 5, 6, 7, 255, 7, 8, 9, 255, + 10, 11, 12, 255, 12, 13, 14, 255, 15, 16, 17, 255, 17, 18, 19, 255, + 4, 5, 6, 255, 6, 7, 8, 255, 9, 10, 11, 255, 11, 12, 13, 255, + 14, 15, 16, 255, 16, 17, 18, 255, 19, 20, 21, 255, 21, 22, 23, 255, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_polyz_unpack_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta_table.c new file mode 100644 index 0000000000..cf21509cbf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta_table.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by 16-bit rejection sampling (rej_eta). + * Adapted from ML-KEM for ML-DSA eta rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_eta_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 2, 3, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 4, 5, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 2, 3, 4, 5, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 7 */, + 6, 7, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 2, 3, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 11 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 13 */, + 2, 3, 4, 5, 6, 7, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 15 */, + 8, 9, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 16 */, + 0, 1, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 17 */, + 2, 3, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 18 */, + 0, 1, 2, 3, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 19 */, + 4, 5, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 20 */, + 0, 1, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 21 */, + 2, 3, 4, 5, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 22 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 23 */, + 6, 7, 8, 9, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 24 */, + 0, 1, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 25 */, + 2, 3, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 26 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 27 */, + 4, 5, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 28 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 29 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 255, 255, 255, 255, 255, 255, 255, 255 /* 30 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 255, 255, 255, 255, 255, 255 /* 31 */, + 10, 11, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 32 */, + 0, 1, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 33 */, + 2, 3, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 34 */, + 0, 1, 2, 3, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 35 */, + 4, 5, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 36 */, + 0, 1, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 37 */, + 2, 3, 4, 5, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 38 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 39 */, + 6, 7, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 40 */, + 0, 1, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 41 */, + 2, 3, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 42 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 43 */, + 4, 5, 6, 7, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 44 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 45 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 46 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 255, 255, 255, 255, 255, 255 /* 47 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 48 */, + 0, 1, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 49 */, + 2, 3, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 50 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 51 */, + 4, 5, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 52 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 53 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 54 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 55 */, + 6, 7, 8, 9, 10, 11, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 56 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 57 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 58 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 59 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 60 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 61 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 255, 255, 255, 255, 255, 255 /* 62 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 63 */, + 12, 13, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 64 */, + 0, 1, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 65 */, + 2, 3, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 66 */, + 0, 1, 2, 3, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 67 */, + 4, 5, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 68 */, + 0, 1, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 69 */, + 2, 3, 4, 5, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 70 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 71 */, + 6, 7, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 72 */, + 0, 1, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 73 */, + 2, 3, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 74 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 75 */, + 4, 5, 6, 7, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 76 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 77 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 78 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 255, 255, 255, 255, 255, 255 /* 79 */, + 8, 9, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 80 */, + 0, 1, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 81 */, + 2, 3, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 82 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 83 */, + 4, 5, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 84 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 85 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 86 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 87 */, + 6, 7, 8, 9, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 88 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 89 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 90 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 91 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 92 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 93 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 255, 255, 255, 255, 255, 255 /* 94 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 255, 255, 255, 255 /* 95 */, + 10, 11, 12, 13, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 96 */, + 0, 1, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 97 */, + 2, 3, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 98 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 99 */, + 4, 5, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 100 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 101 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 102 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 103 */, + 6, 7, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 104 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 105 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 106 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 107 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 108 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 109 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 110 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 255, 255, 255, 255 /* 111 */, + 8, 9, 10, 11, 12, 13, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 112 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 113 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 114 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 115 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 116 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 117 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 118 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 119 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 255, 255, 255, 255, 255, 255, 255, 255 /* 120 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 121 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 122 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 123 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 255, 255, 255, 255, 255, 255 /* 124 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 125 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 255, 255, 255, 255 /* 126 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 255, 255 /* 127 */, + 14, 15, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 128 */, + 0, 1, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 129 */, + 2, 3, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 130 */, + 0, 1, 2, 3, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 131 */, + 4, 5, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 132 */, + 0, 1, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 133 */, + 2, 3, 4, 5, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 134 */, + 0, 1, 2, 3, 4, 5, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 135 */, + 6, 7, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 136 */, + 0, 1, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 137 */, + 2, 3, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 138 */, + 0, 1, 2, 3, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 139 */, + 4, 5, 6, 7, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 140 */, + 0, 1, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 141 */, + 2, 3, 4, 5, 6, 7, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 142 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 14, 15, 255, 255, 255, 255, 255, 255 /* 143 */, + 8, 9, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 144 */, + 0, 1, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 145 */, + 2, 3, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 146 */, + 0, 1, 2, 3, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 147 */, + 4, 5, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 148 */, + 0, 1, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 149 */, + 2, 3, 4, 5, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 150 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 151 */, + 6, 7, 8, 9, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 152 */, + 0, 1, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 153 */, + 2, 3, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 154 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 155 */, + 4, 5, 6, 7, 8, 9, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 156 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 157 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 14, 15, 255, 255, 255, 255, 255, 255 /* 158 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 14, 15, 255, 255, 255, 255 /* 159 */, + 10, 11, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 160 */, + 0, 1, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 161 */, + 2, 3, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 162 */, + 0, 1, 2, 3, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 163 */, + 4, 5, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 164 */, + 0, 1, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 165 */, + 2, 3, 4, 5, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 166 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 167 */, + 6, 7, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 168 */, + 0, 1, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 169 */, + 2, 3, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 170 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 171 */, + 4, 5, 6, 7, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 172 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 173 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 174 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 14, 15, 255, 255, 255, 255 /* 175 */, + 8, 9, 10, 11, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 176 */, + 0, 1, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 177 */, + 2, 3, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 178 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 179 */, + 4, 5, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 180 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 181 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 182 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 183 */, + 6, 7, 8, 9, 10, 11, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 184 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 185 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 186 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 187 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 14, 15, 255, 255, 255, 255, 255, 255 /* 188 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 189 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 14, 15, 255, 255, 255, 255 /* 190 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 14, 15, 255, 255 /* 191 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 192 */, + 0, 1, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 193 */, + 2, 3, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 194 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 195 */, + 4, 5, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 196 */, + 0, 1, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 197 */, + 2, 3, 4, 5, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 198 */, + 0, 1, 2, 3, 4, 5, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 199 */, + 6, 7, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 200 */, + 0, 1, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 201 */, + 2, 3, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 202 */, + 0, 1, 2, 3, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 203 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 204 */, + 0, 1, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 205 */, + 2, 3, 4, 5, 6, 7, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 206 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 207 */, + 8, 9, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 208 */, + 0, 1, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 209 */, + 2, 3, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 210 */, + 0, 1, 2, 3, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 211 */, + 4, 5, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 212 */, + 0, 1, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 213 */, + 2, 3, 4, 5, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 214 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 215 */, + 6, 7, 8, 9, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 216 */, + 0, 1, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 217 */, + 2, 3, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 218 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 219 */, + 4, 5, 6, 7, 8, 9, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 220 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 221 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 12, 13, 14, 15, 255, 255, 255, 255 /* 222 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 12, 13, 14, 15, 255, 255 /* 223 */, + 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 224 */, + 0, 1, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 225 */, + 2, 3, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 226 */, + 0, 1, 2, 3, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 227 */, + 4, 5, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 228 */, + 0, 1, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 229 */, + 2, 3, 4, 5, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 230 */, + 0, 1, 2, 3, 4, 5, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 231 */, + 6, 7, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 232 */, + 0, 1, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 233 */, + 2, 3, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 234 */, + 0, 1, 2, 3, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 235 */, + 4, 5, 6, 7, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 236 */, + 0, 1, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 237 */, + 2, 3, 4, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 238 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 10, 11, 12, 13, 14, 15, 255, 255 /* 239 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 240 */, + 0, 1, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 241 */, + 2, 3, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 242 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 243 */, + 4, 5, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 244 */, + 0, 1, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 245 */, + 2, 3, 4, 5, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 246 */, + 0, 1, 2, 3, 4, 5, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 247 */, + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 255, 255, 255, 255, 255, 255 /* 248 */, + 0, 1, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 249 */, + 2, 3, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 250 */, + 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 251 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 252 */, + 0, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 253 */, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 255, 255 /* 254 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 255 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_eta_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_table.c new file mode 100644 index 0000000000..65bc3b78d3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_table.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_AARCH64) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_aarch64.h" + +/* + * Lookup table used by rejection sampling of the public matrix. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 0 */, + 0, 1, 2, 3, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 1 */, + 4, 5, 6, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 2 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 255, 255, 255, 255, 255, 255, 255, 255 /* 3 */, + 8, 9, 10, 11, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 4 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 5 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 255, 255, 255, 255, 255, 255, 255, 255 /* 6 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 255, 255, 255, 255 /* 7 */, + 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 /* 8 */, + 0, 1, 2, 3, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 9 */, + 4, 5, 6, 7, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 10 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 12, 13, 14, 15, 255, 255, 255, 255 /* 11 */, + 8, 9, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255 /* 12 */, + 0, 1, 2, 3, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 13 */, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 255, 255, 255, 255 /* 14 */, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 /* 15 */, +}; + +#else /* MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +MLD_EMPTY_CU(aarch64_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_AARCH64 && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/api.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/api.h new file mode 100644 index 0000000000..0f1fdeb168 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/api.h @@ -0,0 +1,594 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_API_H +#define MLD_NATIVE_API_H +/* + * Native arithmetic interface + * + * This header is primarily for documentation purposes. + * It should not be included by backend implementations. + * + * To ensure consistency with backends, the header will be + * included automatically after inclusion of the active + * backend, to ensure consistency of function signatures, + * and run sanity checks. + */ + +#include +#include "../cbmc.h" +#include "../common.h" + +/* Backends must return MLD_NATIVE_FUNC_SUCCESS upon success. */ +#define MLD_NATIVE_FUNC_SUCCESS (0) +/* Backends may return MLD_NATIVE_FUNC_FALLBACK to signal to the frontend that + * the target/parameters are unsupported; typically, this would be because of + * dependencies on CPU features not detected on the host CPU. In this case, + * the frontend falls back to the default C implementation. + * + * IMPORTANT: Backend implementations must ensure that the decision of whether + * to fallback (return MLD_NATIVE_FUNC_FALLBACK) or not must never depend on + * the input data itself. Fallback decisions may only depend on system + * capabilities (e.g., CPU features) and, where present, length information. + * This requirement applies to all backend functions to maintain constant-time + * properties. + */ +#define MLD_NATIVE_FUNC_FALLBACK (-1) + +/* Bound on absolute value of coefficients after NTT. + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) + +/* Absolute exclusive upper bound for the output of the inverse NTT + * + * NOTE: This is the same bound as in ntt.h and has to be kept + * in sync. */ +#define MLD_INTT_BOUND MLDSA_Q + +/* Absolute bound for range of mld_reduce32() + * + * NOTE: This is the same bound as in reduce.h and has to be kept + * in sync. */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define REDUCE32_RANGE_MAX 6283009 +/* + * This is the C<->native interface allowing for the drop-in of + * native code for performance critical arithmetic components of ML-DSA. + * + * A _backend_ is a specific implementation of (part of) this interface. + * + * To add a function to a backend, define MLD_USE_NATIVE_XXX and + * implement `static inline xxx(...)` in the profile header. + */ + +/* + * Those functions are meant to be trivial wrappers around the chosen native + * implementation. The are static inline to avoid unnecessary calls. + * The macro before each declaration controls whether a native + * implementation is present. + */ + +#if defined(MLD_USE_NATIVE_NTT) +/************************************************* + * Name: mld_ntt_native + * + * Description: Computes negacyclic number-theoretic transform (NTT) of + * a polynomial in place. + * + * The input polynomial is assumed to be in normal order. + * The output polynomial is in bitreversed order. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_ntt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_NTT */ + + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) +/* + * This must only be set if NTT and INTT have native implementations + * that are adapted to the custom order. + */ +#if !defined(MLD_USE_NATIVE_NTT) || !defined(MLD_USE_NATIVE_INTT) +#error \ + "Invalid native profile: MLD_USE_NATIVE_NTT_CUSTOM_ORDER can only be \ +set if there are native implementations for NTT and INTT." +#endif + +/************************************************* + * Name: mlD_poly_permute_bitrev_to_custom + * + * Description: When MLD_USE_NATIVE_NTT_CUSTOM_ORDER is defined, + * convert a polynomial in NTT domain from bitreversed + * order to the custom order output by the native NTT. + * + * This must only be defined if there is native code for + * both the NTT and INTT. + * + * Arguments: - int32_t p[MLDSA_N]: pointer to in/output polynomial + * + **************************************************/ +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t p[MLDSA_N]) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q))); +#endif /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + + +#if defined(MLD_USE_NATIVE_INTT) +/************************************************* + * Name: mld_intt_native + * + * Description: Computes inverse of negacyclic number-theoretic transform + *(NTT) of a polynomial in place. + * + * The input polynomial is in bitreversed order. + * The output polynomial is assumed to be in normal order. + * + * Arguments: - uint32_t p[MLDSA_N]: pointer to in/output polynomial + **************************************************/ +static MLD_INLINE int mld_intt_native(int32_t p[MLDSA_N]) +__contract__( + requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_INTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_INTT */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) +/************************************************* + * Name: mld_rej_uniform_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [0, MLDSA_Q-1] + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform mod q). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + * lengths. Otherwise, returns non-negative number of sampled 32-bit integers + * (at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= ( 5 * 168) && buflen % 3 == 0) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(r, 0, (unsigned) return_value, 0, MLDSA_Q)) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) +/************************************************* + * Name: mld_rej_uniform_eta2_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-2,+2]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-2, +2]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA2 */ + +#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) +/************************************************* + * Name: mld_rej_uniform_eta4_native + * + * Description: Run rejection sampling on uniform random bytes to generate + * uniform random integers in [-4,+4]. + * + * Arguments: - int32_t *r: pointer to output buffer + * - unsigned len: requested number of 32-bit integers + * (uniform in [-4, +4]). + * - const uint8_t *buf: pointer to input buffer + * (assumed to be uniform random bytes) + * - unsigned buflen: length of input buffer in bytes. + * + * Return -1 if the native implementation does not support the input + *lengths. Otherwise, returns non-negative number of sampled 32-bit integers + *(at most len). + **************************************************/ +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +__contract__( + requires(len <= MLDSA_N) + requires(buflen <= (2 * 136)) + requires(memory_no_alias(r, sizeof(int32_t) * len)) + requires(memory_no_alias(buf, buflen)) + assigns(memory_slice(r, sizeof(int32_t) * len)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len)) + ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, MLDSA_ETA + 1))) +); +#endif /* MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) +/************************************************* + * Name: mld_poly_decompose_32_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/32. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: input/output polynomial. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_32 */ + +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) +/************************************************* + * Name: mld_poly_decompose_88_native + * + * Description: Native implementation of poly_decompose for GAMMA2 = (Q-1)/88. + * For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such + * c mod MLDSA_Q = c1*(2*GAMMA2) + c0 + * with -(2*GAMMA2)/2 < c0 <= (2*GAMMA2)/2 except + * c1 = (MLDSA_Q-1)/(2*GAMMA2) where we set + * c1 = 0 and -(2*GAMMA2)/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - int32_t *a1: output polynomial with coefficients c1 + * - int32_t *a0: output polynomial with coefficients c0. + * Output has coefficients c0 + **************************************************/ +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N)) + assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_DECOMPOSE_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CADDQ) +/************************************************* + * Name: mld_poly_caddq_native + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *a: pointer to input/output polynomial + **************************************************/ +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_32) +/************************************************* + * Name: mld_poly_use_hint_32_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/32. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_32 */ + +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) +/************************************************* + * Name: mld_poly_use_hint_88_native + * + * Description: Native implementation of poly_use_hint for GAMMA2 = (Q-1)/88. + * Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - int32_t *b: pointer to output polynomial with corrected high + * bits + * - const int32_t *a: pointer to input polynomial + * - const int32_t *h: pointer to input hint polynomial + **************************************************/ +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N)) + requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(b, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(b, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLY_USE_HINT_88 */ + +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) +/************************************************* + * Name: mld_poly_chknorm_native + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const int32_t *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if the infinity norm is strictly smaller than B, and 1 + * otherwise. B must not be larger than MLDSA_Q - MLD_REDUCE32_RANGE_MAX. + **************************************************/ +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(0 <= B && B <= MLDSA_Q - REDUCE32_RANGE_MAX) + requires(array_bound(a, 0, MLDSA_N, -REDUCE32_RANGE_MAX, REDUCE32_RANGE_MAX)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == 0) == array_abs_bound(a, 0, MLDSA_N, B)) +); +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) +/************************************************* + * Name: mld_polyz_unpack_17_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^17. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_17 */ + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) +/************************************************* + * Name: mld_polyz_unpack_19_native + * + * Description: Native implementation of polyz_unpack for GAMMA1 = 2^19. + * Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - int32_t *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_19 */ + +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) +/************************************************* + * Name: mld_poly_pointwise_montgomery_native + * + * Description: Pointwise multiplication of polynomials in NTT domain + * with Montgomery reduction. + * + * Computes c[i] = a[i] * b[i] * R^(-1) mod q for all i, + * where R = 2^32. + * + * Arguments: - int32_t c[MLDSA_N]: output polynomial + * - const int32_t a[MLDSA_N]: first input polynomial + * - const int32_t b[MLDSA_N]: second input polynomial + **************************************************/ +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +__contract__( + requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(c, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(c, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(c, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l4_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 4. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 4 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 4 * MLDSA_N)) + requires(forall(l0, 0, 4, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 4, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l5_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 5. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 5 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 5 * MLDSA_N)) + requires(forall(l0, 0, 5, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 5, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 */ + +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery_l7_native + * + * Description: Native implementation of polyvecl_pointwise_acc_montgomery for + * MLDSA_L = 7. + * Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * Arguments: - int32_t w[MLDSA_N]: output polynomial + * - const int32_t u[MLDSA_L][MLDSA_N]: first input vector + * - const int32_t v[MLDSA_L][MLDSA_N]: second input vector + **************************************************/ +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +__contract__( + requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N)) + requires(memory_no_alias(u, sizeof(int32_t) * 7 * MLDSA_N)) + requires(memory_no_alias(v, sizeof(int32_t) * 7 * MLDSA_N)) + requires(forall(l0, 0, 7, + array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, 7, + array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N)) + ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS) + ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q)) + ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N)) +); +#endif /* MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 */ + +#endif /* !MLD_NATIVE_API_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/meta.h new file mode 100644 index 0000000000..0b46dd5791 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/meta.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_META_H +#define MLD_NATIVE_META_H + +/* + * Default arithmetic backend + */ +#include "../sys.h" + +#ifdef MLD_SYS_AARCH64 +#include "aarch64/meta.h" +#endif + +#ifdef MLD_SYS_X86_64_AVX2 +#include "x86_64/meta.h" +#endif + +#endif /* !MLD_NATIVE_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/meta.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/meta.h new file mode 100644 index 0000000000..393374c06f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/meta.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_NATIVE_X86_64_META_H +#define MLD_NATIVE_X86_64_META_H + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLD_ARITH_BACKEND_X86_64_DEFAULT + +#define MLD_USE_NATIVE_NTT_CUSTOM_ORDER +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 + +#if !defined(__ASSEMBLER__) +#include +#include "../../common.h" +#include "../api.h" +#include "src/arith_native_x86_64.h" + +static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t data[MLDSA_N]) +{ + if (mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + mld_nttunpack_avx2(data); + } +} + +static MLD_INLINE int mld_ntt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + mld_ntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_intt_native(int32_t data[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_invntt_avx2(data, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)mld_rej_uniform_avx2(r, buf); +} + +static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta2_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len, + const uint8_t *buf, + unsigned buflen) +{ + unsigned int outlen; + /* AVX2 implementation assumes specific buffer lengths */ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2) || len != MLDSA_N || + buflen != MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + + /* Constant time: Inputs and outputs to this function are secret. + * It is safe to leak which coefficients are accepted/rejected. + * The assembly implementation must not leak any other information about the + * accepted coefficients. Constant-time testing cannot cover this, and we + * hence have to manually verify the assembly. + * We declassify prior the input data and mark the outputs as secret. + */ + MLD_CT_TESTING_DECLASSIFY(buf, buflen); + outlen = mld_rej_uniform_eta4_avx2(r, buf); + MLD_CT_TESTING_SECRET(r, sizeof(int32_t) * outlen); + /* Safety: outlen is at most MLDSA_N and, hence, this cast is safe. */ + return (int)outlen; +} + +static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_32_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_decompose_88_avx2(a1, a0); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_caddq_avx2(a); + return MLD_NATIVE_FUNC_SUCCESS; +} +static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_32_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *b, const int32_t *a, + const int32_t *h) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_poly_use_hint_88_avx2(b, a, h); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + return mld_poly_chknorm_avx2(a, B); +} + +static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_17_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_polyz_unpack_19_avx2(r, a); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_poly_pointwise_montgomery_native( + int32_t c[MLDSA_N], const int32_t a[MLDSA_N], const int32_t b[MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_avx2(c, a, b, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native( + int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N], + const int32_t v[4][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l4_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native( + int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N], + const int32_t v[5][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l5_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native( + int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N], + const int32_t v[7][MLDSA_N]) +{ + if (!mld_sys_check_capability(MLD_SYS_CAP_AVX2)) + { + return MLD_NATIVE_FUNC_FALLBACK; + } + mld_pointwise_acc_l7_avx2(w, u, v, mld_qdata); + return MLD_NATIVE_FUNC_SUCCESS; +} + +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_NATIVE_X86_64_META_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/arith_native_x86_64.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/arith_native_x86_64.h new file mode 100644 index 0000000000..08d5abf74a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/arith_native_x86_64.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#define MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H +#include "../../../common.h" + +#include +#include "consts.h" + +#define MLD_AVX2_REJ_UNIFORM_BUFLEN \ + (5 * 168) /* REJ_UNIFORM_NBLOCKS * SHAKE128_RATE */ + + +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN (1 * 136) + +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN (2 * 136) + +#define mld_rej_uniform_table MLD_NAMESPACE(mld_rej_uniform_table) +extern const uint8_t mld_rej_uniform_table[256][8]; + +#define mld_ntt_avx2 MLD_NAMESPACE(ntt_avx2) +void mld_ntt_avx2(int32_t *r, const int32_t *qdata) +/* This must be kept in sync with the HOL-Light specification + * in proofs/hol_light/x86_64/proofs/mldsa_ntt.ml */ +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, MLDSA_N, 8380417)) + requires(qdata == mld_qdata) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + /* check-magic: off */ + ensures(array_abs_bound(r, 0, MLDSA_N, 42035262)) + /* check-magic: on */ +); + +#define mld_invntt_avx2 MLD_NAMESPACE(invntt_avx2) +void mld_invntt_avx2(int32_t *r, const int32_t *mld_qdata); + +#define mld_nttunpack_avx2 MLD_NAMESPACE(nttunpack_avx2) +void mld_nttunpack_avx2(int32_t *r); + +#define mld_rej_uniform_avx2 MLD_NAMESPACE(mld_rej_uniform_avx2) +unsigned mld_rej_uniform_avx2(int32_t *r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]); + +#define mld_rej_uniform_eta2_avx2 MLD_NAMESPACE(mld_rej_uniform_eta2_avx2) +unsigned mld_rej_uniform_eta2_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]); + +#define mld_rej_uniform_eta4_avx2 MLD_NAMESPACE(mld_rej_uniform_eta4_avx2) +unsigned mld_rej_uniform_eta4_avx2( + int32_t *r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]); + +#define mld_poly_decompose_32_avx2 MLD_NAMESPACE(mld_poly_decompose_32_avx2) +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_decompose_88_avx2 MLD_NAMESPACE(mld_poly_decompose_88_avx2) +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0); + +#define mld_poly_caddq_avx2 MLD_NAMESPACE(poly_caddq_avx2) +void mld_poly_caddq_avx2(int32_t *r); + +#define mld_poly_use_hint_32_avx2 MLD_NAMESPACE(mld_poly_use_hint_32_avx2) +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_use_hint_88_avx2 MLD_NAMESPACE(mld_poly_use_hint_88_avx2) +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, const int32_t *h); + +#define mld_poly_chknorm_avx2 MLD_NAMESPACE(mld_poly_chknorm_avx2) +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B); + +#define mld_polyz_unpack_17_avx2 MLD_NAMESPACE(mld_polyz_unpack_17_avx2) +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a); + +#define mld_polyz_unpack_19_avx2 MLD_NAMESPACE(mld_polyz_unpack_19_avx2) +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a); + +#define mld_pointwise_avx2 MLD_NAMESPACE(pointwise_avx2) +void mld_pointwise_avx2(int32_t *c, const int32_t *a, const int32_t *b, + const int32_t *qdata); + +#define mld_pointwise_acc_l4_avx2 MLD_NAMESPACE(pointwise_acc_l4_avx2) +void mld_pointwise_acc_l4_avx2(int32_t c[MLDSA_N], const int32_t a[4][MLDSA_N], + const int32_t b[4][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l5_avx2 MLD_NAMESPACE(pointwise_acc_l5_avx2) +void mld_pointwise_acc_l5_avx2(int32_t c[MLDSA_N], const int32_t a[5][MLDSA_N], + const int32_t b[5][MLDSA_N], + const int32_t *qdata); + +#define mld_pointwise_acc_l7_avx2 MLD_NAMESPACE(pointwise_acc_l7_avx2) +void mld_pointwise_acc_l7_avx2(int32_t c[MLDSA_N], const int32_t a[7][MLDSA_N], + const int32_t b[7][MLDSA_N], + const int32_t *qdata); + +#endif /* !MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/consts.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/consts.c new file mode 100644 index 0000000000..aaca3535ae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/consts.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include "consts.h" + +/* + * Table of zeta values used in the AVX2 forward and inverse NTT + * See autogen for details. + */ +MLD_ALIGN const int32_t mld_qdata[624] = { + 8380417, 8380417, 8380417, 8380417, 8380417, + 8380417, 8380417, 8380417, 58728449, 58728449, + 58728449, 58728449, 58728449, 58728449, 58728449, + 58728449, -8395782, -8395782, -8395782, -8395782, + -8395782, -8395782, -8395782, -8395782, 41978, + 41978, 41978, 41978, 41978, 41978, + 41978, 41978, -151046689, 1830765815, -1929875198, + -1927777021, 1640767044, 1477910808, 1612161320, 1640734244, + 308362795, 308362795, 308362795, 308362795, -1815525077, + -1815525077, -1815525077, -1815525077, -1374673747, -1374673747, + -1374673747, -1374673747, -1091570561, -1091570561, -1091570561, + -1091570561, -1929495947, -1929495947, -1929495947, -1929495947, + 515185417, 515185417, 515185417, 515185417, -285697463, + -285697463, -285697463, -285697463, 625853735, 625853735, + 625853735, 625853735, 1727305304, 1727305304, 2082316400, + 2082316400, -1364982364, -1364982364, 858240904, 858240904, + 1806278032, 1806278032, 222489248, 222489248, -346752664, + -346752664, 684667771, 684667771, 1654287830, 1654287830, + -878576921, -878576921, -1257667337, -1257667337, -748618600, + -748618600, 329347125, 329347125, 1837364258, 1837364258, + -1443016191, -1443016191, -1170414139, -1170414139, -1846138265, + -1631226336, -1404529459, 1838055109, 1594295555, -1076973524, + -1898723372, -594436433, -202001019, -475984260, -561427818, + 1797021249, -1061813248, 2059733581, -1661512036, -1104976547, + -1750224323, -901666090, 418987550, 1831915353, -1925356481, + 992097815, 879957084, 2024403852, 1484874664, -1636082790, + -285388938, -1983539117, -1495136972, -950076368, -1714807468, + -952438995, -1574918427, 1350681039, -2143979939, 1599739335, + -1285853323, -993005454, -1440787840, 568627424, -783134478, + -588790216, 289871779, -1262003603, 2135294594, -1018755525, + -889861155, 1665705315, 1321868265, 1225434135, -1784632064, + 666258756, 675310538, -1555941048, -1999506068, -1499481951, + -695180180, -1375177022, 1777179795, 334803717, -178766299, + -518252220, 1957047970, 1146323031, -654783359, -1974159335, + 1651689966, 140455867, -1039411342, 1955560694, 1529189038, + -2131021878, -247357819, 1518161567, -86965173, 1708872713, + 1787797779, 1638590967, -120646188, -1669960606, -916321552, + 1155548552, 2143745726, 1210558298, -1261461890, -318346816, + 628664287, -1729304568, 1422575624, 1424130038, -1185330464, + 235321234, 168022240, 1206536194, 985155484, -894060583, + -898413, -1363460238, -605900043, 2027833504, 14253662, + 1014493059, 863641633, 1819892093, 2124962073, -1223601433, + -1920467227, -1637785316, -1536588520, 694382729, 235104446, + -1045062172, 831969619, -300448763, 756955444, -260312805, + 1554794072, 1339088280, -2040058690, -853476187, -2047270596, + -1723816713, -1591599803, -440824168, 1119856484, 1544891539, + 155290192, -973777462, 991903578, 912367099, -44694137, + 1176904444, -421552614, -818371958, 1747917558, -325927722, + 908452108, 1851023419, -1176751719, -1354528380, -72690498, + -314284737, 985022747, 963438279, -1078959975, 604552167, + -1021949428, 608791570, 173440395, -2126092136, -1316619236, + -1039370342, 6087993, -110126092, 565464272, -1758099917, + -1600929361, 879867909, -1809756372, 400711272, 1363007700, + 30313375, -326425360, 1683520342, -517299994, 2027935492, + -1372618620, 128353682, -1123881663, 137583815, -635454918, + -642772911, 45766801, 671509323, -2070602178, 419615363, + 1216882040, -270590488, -1276805128, 371462360, -1357098057, + -384158533, 827959816, -596344473, 702390549, -279505433, + -260424530, -71875110, -1208667171, -1499603926, 2036925262, + -540420426, 746144248, -1420958686, 2032221021, 1904936414, + 1257750362, 1926727420, 1931587462, 1258381762, 885133339, + 1629985060, 1967222129, 6363718, -1287922800, 1136965286, + 1779436847, 1116720494, 1042326957, 1405999311, 713994583, + 940195359, -1542497137, 2061661095, -883155599, 1726753853, + -1547952704, 394851342, 283780712, 776003547, 1123958025, + 201262505, 1934038751, 374860238, -3975713, 25847, + -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 1826347, 1826347, 1826347, + 2353451, 2353451, 2353451, 2353451, -359251, + -359251, -359251, -359251, -2091905, -2091905, + -2091905, -2091905, 3119733, 3119733, 3119733, + 3119733, -2884855, -2884855, -2884855, -2884855, + 3111497, 3111497, 3111497, 3111497, 2680103, + 2680103, 2680103, 2680103, 2725464, 2725464, + 1024112, 1024112, -1079900, -1079900, 3585928, + 3585928, -549488, -549488, -1119584, -1119584, + 2619752, 2619752, -2108549, -2108549, -2118186, + -2118186, -3859737, -3859737, -1399561, -1399561, + -3277672, -3277672, 1757237, 1757237, -19422, + -19422, 4010497, 4010497, 280005, 280005, + 2706023, 95776, 3077325, 3530437, -1661693, + -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, + -539299, -1699267, -1643818, 3505694, -3821735, + 3507263, -2140649, -1600420, 3699596, 811944, + 531354, 954230, 3881043, 3900724, -2556880, + 2071892, -2797779, -3930395, -3677745, -1452451, + 2176455, -1257611, -4083598, -3190144, -3632928, + 3412210, 2147896, -2967645, -411027, -671102, + -22981, -381987, 1852771, -3343383, 508951, + 44288, 904516, -3724342, 1653064, 2389356, + 759969, 189548, 3159746, -2409325, 1315589, + 1285669, -812732, -3019102, -3628969, -1528703, + -3041255, 3475950, -1585221, 1939314, -1000202, + -3157330, 126922, -983419, 2715295, -3693493, + -2477047, -1228525, -1308169, 1349076, -1430430, + 264944, 3097992, -1100098, 3958618, -8578, + -3249728, -210977, -1316856, -3553272, -1851402, + -177440, 1341330, -1584928, -1439742, -3881060, + 3839961, 2091667, -3342478, 266997, -3520352, + 900702, 495491, -655327, -3556995, 342297, + 3437287, 2842341, 4055324, -3767016, -2994039, + -1333058, -451100, -1279661, 1500165, -542412, + -2584293, -2013608, 1957272, -3183426, 810149, + -3038916, 2213111, -426683, -1667432, -2939036, + 183443, -554416, 3937738, 3407706, 2244091, + 2434439, -3759364, 1859098, -1613174, -3122442, + -525098, 286988, -3342277, 2691481, 1247620, + 1250494, 1869119, 1237275, 1312455, 1917081, + 777191, -2831860, -3724270, 2432395, 3369112, + 162844, 1652634, 3523897, -975884, 1723600, + -1104333, -2235985, -976891, 3919660, 1400424, + 2316500, -2446433, -1235728, -1197226, 909542, + -43260, 2031748, -768622, -2437823, 1735879, + -2590150, 2486353, 2635921, 1903435, -3318210, + 3306115, -2546312, 2235880, -1671176, 594136, + 2454455, 185531, 1616392, -3694233, 3866901, + 1717735, -1803090, -260646, -420899, 1612842, + -48306, -846154, 3817976, -3562462, 3513181, + -3193378, 819034, -522500, 3207046, -3595838, + 4108315, 203044, 1265009, 1595974, -3548272, + -1050970, -1430225, -1962642, -1374803, 3406031, + -1846953, -3776993, -164721, -1207385, 3014001, + -1799107, 269760, 472078, 1910376, -3833893, + -2286327, -3545687, -1362209, 1976782, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_consts) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/consts.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/consts.h new file mode 100644 index 0000000000..7fe08f454b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/consts.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#ifndef MLD_NATIVE_X86_64_SRC_CONSTS_H +#define MLD_NATIVE_X86_64_SRC_CONSTS_H +#include "../../../common.h" +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQ 0 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV 8 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV 16 +#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV 24 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV 32 +#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS 328 + +#ifndef __ASSEMBLER__ +#define mld_qdata MLD_NAMESPACE(qdata) +extern const int32_t mld_qdata[624]; +#endif + +#endif /* !MLD_NATIVE_X86_64_SRC_CONSTS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_caddq_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_caddq_avx2.c new file mode 100644 index 0000000000..05d86d14fc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_caddq_avx2.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/************************************************* + * Name: mld_poly_caddq_avx2 + * + * Description: For all coefficients of in/out polynomial add Q if + * coefficient is negative. + * + * Arguments: - int32_t *r: pointer to input/output polynomial + **************************************************/ +void mld_poly_caddq_avx2(int32_t *r) +{ + unsigned int i; + __m256i f, g; + const __m256i q = _mm256_set1_epi32(MLDSA_Q); + const __m256i zero = _mm256_setzero_si256(); + __m256i *rr = (__m256i *)r; + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256(&rr[i]); + g = _mm256_cmpgt_epi32(zero, f); + g = _mm256_and_si256(g, q); + f = _mm256_add_epi32(f, g); + _mm256_store_si256(&rr[i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_reduce) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_chknorm_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_chknorm_avx2.c new file mode 100644 index 0000000000..50e2c7fa9b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_chknorm_avx2.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +int mld_poly_chknorm_avx2(const int32_t *a, int32_t B) +{ + unsigned int i; + __m256i f, t; + const __m256i bound = _mm256_set1_epi32(B - 1); + + t = _mm256_setzero_si256(); + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + f = _mm256_abs_epi32(f); + f = _mm256_cmpgt_epi32(f, bound); + t = _mm256_or_si256(t, f); + } + + return 1 - _mm256_testz_si256(t, t); +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_chknorm) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_decompose_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_decompose_32_avx2.c new file mode 100644 index 0000000000..76846bf1a8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_decompose_32_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ +void mld_poly_decompose_32_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(31 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 4092 == intdiv(2 * intdiv(MLDSA_Q - 1, 32), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 4092. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 32*GAMMA2 = 16*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 16B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + * + * round(f1' * 1025 / 2^22) is in turn computed in 2 steps as + * round(floor(f1' * 1025 / 2^16) / 2^6). The mulhi computes f1'' = + * floor(f1' * 1025 / 2^16). As for the next step f1 = round(f1'' / 2^6), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^9) = round(f1'' * 2^9 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 1025 / 2^16) = 1025 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(16B / B) = 16 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 16, i.e. f > 31*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 31*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 15, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_decompose_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_decompose_88_avx2.c new file mode 100644 index 0000000000..463506b962 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_decompose_88_avx2.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + * + * The algorithm for Decompose(r) (more specifically the handling for the + * wrap-around cases) are modified. See the "Reference" section in the comments + * below for a more detailed comparison. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + */ + +void mld_poly_decompose_88_avx2(int32_t *a1, int32_t *a0) +{ + unsigned int i; + __m256i f, f0, f1, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((__m256i *)&a0[8 * i]); + + /* check-magic: 1488 == intdiv(2 * intdiv(MLDSA_Q - 1, 88), 128) */ + /* + * Compute f1 = round-(f / (2*GAMMA2)) as round-(f / (128B)) = + * round-(ceil(f / 128) / B) where B = 2*GAMMA2 / 128 = 1488. See + * mld_decompose() in mldsa/src/rounding.h for more details. + * + * range: 0 <= f <= Q-1 = 88*GAMMA2 = 44*128*B + */ + + /* Compute f1' = ceil(f / 128) as floor((f + 127) >> 7) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + /* + * range: 0 <= f1' <= (Q-1)/128 = 44B + * + * Also, f1' <= (Q-1)/128 = 2^16 - 2^6 < 2^16 ensures that the odd-index + * 16-bit lanes are all 0, so no bits will be dropped in the input of the + * _mm256_mulhi_epu16() below. + */ + + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + * + * round(f1' * 11275 / 2^24) is in turn computed in 2 steps as + * round(floor(f1' * 11275 / 2^16) / 2^8). The mulhi computes f1'' = + * floor(f1' * 11275 / 2^16). As for the next step f1 = round(f1'' / 2^8), + * because AVX2 doesn't have rounding right-shift (e.g. urshr in Neon), we + * simulate it using mulhrs with a power of 2, in this case mulhrs(f1'', + * 2^7) = round(f1'' * 2^7 / 2^15). (Note that the denominator is 2^15, + * not 2^16 as in mulhi.) + */ + f1 = _mm256_mulhi_epu16(f1, v); + /* + * range: 0 <= f1'' < floor(2^16 * 11275 / 2^16) = 11275 + * + * Because 0 <= f1'' < 2^15, the multiplication in mulhrs is unsigned, that + * is, no erroneous sign-extension occurs. + */ + f1 = _mm256_mulhrs_epi16(f1, shift); + /* + * range: 0 <= f1 = round-(f1' / B) <= round-(44B / B) = 44 + * + * Note that the odd-index 16-bit lanes are still all 0 right now, so + * reinterpreting f1 as 8 lanes of int32_t (as done in the following) does + * not affect its value. + */ + + /* + * If f1 = 44, i.e. f > 87*GAMMA2, proceed as if f' = f - Q was given + * instead. (For f = 87*GAMMA2 + 1 thus f' = -GAMMA2, we still round it to 0 + * like other "wrapped around" cases.) + * + * Reference: They handle wrap-around in a somewhat convoluted way. Most + * notably, they compute remainder f0 with quotient f1 that's + * already wrapped around, so is off by q (instead of by 1) from + * what it should be ultimately. They detect the need for + * correction by checking if f0 is abnormally large. + * + * Our approach is closer to Algorithm 36 in the specification, + * in that we compute f0 normally and correct f1, f0 in the way + * they prescribed. The only real difference is that we check for + * wrap-around by examining f directly, instead of some other + * intermediates computed from it. + */ + + /* Check for wrap-around */ + t = _mm256_cmpgt_epi32(f, q_bound); + + /* Compute remainder f0 */ + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + /* + * range: -GAMMA2 < f0 <= GAMMA2 + * + * This holds since f1 = round-(f / (2*GAMMA2)) was computed exactly. + */ + + /* If wrap-around is required, set f1 = 0 and f0 -= 1 */ + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + /* range: 0 <= f1 <= 43, -GAMMA2 <= f0 <= GAMMA2 */ + + _mm256_store_si256((__m256i *)&a1[8 * i], f1); + _mm256_store_si256((__m256i *)&a0[8 * i], f0); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_decompose_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_use_hint_32_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_use_hint_32_avx2.c new file mode 100644 index 0000000000..0094bc93a9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_use_hint_32_avx2.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_32_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 32)); + /* check-magic: 1025 == floor(2**22 / 4092) */ + const __m256i v = _mm256_set1_epi32(1025); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 32)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(512); + const __m256i mask = _mm256_set1_epi32(15); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_32_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 16 */ + f1 = _mm256_add_epi32(f1, h); + f1 = _mm256_and_si256(f1, mask); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_32) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_use_hint_88_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_use_hint_88_avx2.c new file mode 100644 index 0000000000..b109ab6351 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/poly_use_hint_88_avx2.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_MM256_BLENDV_EPI32(a, b, mask) \ + _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(a), \ + _mm256_castsi256_ps(b), \ + _mm256_castsi256_ps(mask))) + +void mld_poly_use_hint_88_avx2(int32_t *b, const int32_t *a, + const int32_t *hint) +{ + unsigned int i; + __m256i f, f0, f1, h, t; + const __m256i q_bound = _mm256_set1_epi32(87 * ((MLDSA_Q - 1) / 88)); + /* check-magic: 11275 == floor(2**24 / 1488) */ + const __m256i v = _mm256_set1_epi32(11275); + const __m256i alpha = _mm256_set1_epi32(2 * ((MLDSA_Q - 1) / 88)); + const __m256i off = _mm256_set1_epi32(127); + const __m256i shift = _mm256_set1_epi32(128); + const __m256i max = _mm256_set1_epi32(43); + const __m256i zero = _mm256_setzero_si256(); + + for (i = 0; i < MLDSA_N / 8; i++) + { + f = _mm256_load_si256((const __m256i *)&a[8 * i]); + h = _mm256_load_si256((const __m256i *)&hint[8 * i]); + + /* Reference: + * - @[REF_AVX2] calls poly_decompose to compute all a1, a0 before the loop. + * - Our implementation of decompose() is slightly different from that in + * @[REF_AVX2]. See poly_decompose_88_avx2.c for more information. + */ + /* f1, f2 = decompose(f) */ + f1 = _mm256_add_epi32(f, off); + f1 = _mm256_srli_epi32(f1, 7); + f1 = _mm256_mulhi_epu16(f1, v); + f1 = _mm256_mulhrs_epi16(f1, shift); + t = _mm256_cmpgt_epi32(f, q_bound); + f0 = _mm256_mullo_epi32(f1, alpha); + f0 = _mm256_sub_epi32(f, f0); + f1 = _mm256_andnot_si256(t, f1); + f0 = _mm256_add_epi32(f0, t); + + /* Reference: The reference avx2 implementation checks a0 >= 0, which is + * different from the specification and the reference C implementation. We + * follow the specification and check a0 > 0. + */ + /* t = (f0 > 0) ? h : -h */ + f0 = _mm256_cmpgt_epi32(f0, zero); + t = MLD_MM256_BLENDV_EPI32(h, zero, f0); + t = _mm256_slli_epi32(t, 1); + h = _mm256_sub_epi32(h, t); + + /* f1 = (f1 + t) % 44 */ + f1 = _mm256_add_epi32(f1, h); + f1 = MLD_MM256_BLENDV_EPI32(f1, max, f1); + f = _mm256_cmpgt_epi32(f1, max); + f1 = MLD_MM256_BLENDV_EPI32(f1, zero, f); + + _mm256_store_si256((__m256i *)&b[8 * i], f1); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_poly_use_hint_88) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_MM256_BLENDV_EPI32 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/polyz_unpack_17_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/polyz_unpack_17_avx2.c new file mode 100644 index 0000000000..f6c08a832f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/polyz_unpack_17_avx2.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_17_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 27, 26, 25, -1, 25, 24, 23, -1, 8, 7, + 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0); + const __m256i srlvdidx = _mm256_set_epi32(6, 4, 2, 0, 6, 4, 2, 0); + const __m256i mask = _mm256_set1_epi32(0x3FFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 17)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[18 * i]); + /* Load bytes 2..17 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[18 * i + 2]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-8 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 8, 7, 6, -1, 6, 5, 4, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte8, byte7, byte6, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,27, 26, 25, -1,25, 24, 23] │ + * │ Result: [0, byte17, byte16, byte15, ..., 0, byte11, byte10, byte9] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 18 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 32..55 48..71 + * 72..95 88..111 104..127 120..143 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 18..39 36..55 54..71 + * 72..95 90..111 108..127 126..143 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..17 18..35 36..53 54..71 + * 72..89 90..107 108..125 126..143 */ + + /* Map [0, 1, ..., 2^18-1] to [2^17, 2^17-1, ..., -2^17+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_17) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/polyz_unpack_19_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/polyz_unpack_19_avx2.c new file mode 100644 index 0000000000..4a5ce48f38 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/polyz_unpack_19_avx2.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include "arith_native_x86_64.h" + +void mld_polyz_unpack_19_avx2(int32_t *r, const uint8_t *a) +{ + unsigned int i; + __m256i f; + __m128i low, high; + + const __m256i shufbidx = _mm256_set_epi8( + -1, 31, 30, 29, -1, 29, 28, 27, -1, 26, 25, 24, -1, 24, 23, 22, -1, 9, 8, + 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0); + /* Equivalent to _mm256_set_epi32(4, 0, 4, 0, 4, 0, 4, 0) */ + const __m256i srlvdidx = _mm256_set1_epi64x((uint64_t)4 << 32); + const __m256i mask = _mm256_set1_epi32(0xFFFFF); + const __m256i gamma1 = _mm256_set1_epi32((1 << 19)); + + for (i = 0; i < MLDSA_N / 8; i++) + { + /* Load bytes 0..15 into low 128-bit vector */ + low = _mm_loadu_si128((__m128i *)&a[20 * i]); + /* Load bytes 4..19 into high 128-bit vector */ + high = _mm_loadu_si128((__m128i *)&a[20 * i + 4]); + /* Combine into 256-bit vector */ + f = _mm256_inserti128_si256(_mm256_castsi128_si256(low), high, 1); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-9 into low 128-bit half ───────────────────────────────────┐ + * │ Shuffle: [-1, 9, 8, 7, -1, 7, 6, 5, -1, 4, 3, 2, -1, 2, 1, 0] │ + * │ Result: [0, byte9, byte8, byte7, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 16-31 into high 128-bit half ────────────────────────────────┐ + * │ Shuffle: [-1,31, 30, 29, -1,29, 28, 27, -1,26, 25, 24, -1,24, 23, 22] │ + * │ Result: [0, byte19, byte18, byte17, ..., 0, byte12, byte11, byte10] │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + f = _mm256_shuffle_epi8(f, shufbidx); + + /* Keep only 20 out of 24 bits in each 32-bit lane */ + /* Bits 0..23 16..39 40..63 56..79 + * 80..103 96..119 120..143 136..159 */ + f = _mm256_srlv_epi32(f, srlvdidx); + /* Bits 0..23 20..39 40..63 60..79 + * 80..103 100..119 120..143 140..159 */ + f = _mm256_and_si256(f, mask); + /* Bits 0..19 20..39 40..59 60..79 + * 80..99 100..119 120..139 140..159 */ + + /* Map [0, 1, ..., 2^20-1] to [2^19, 2^19-1, ..., -2^19+1] */ + f = _mm256_sub_epi32(gamma1, f); + + _mm256_store_si256((__m256i *)&r[8 * i], f); + } +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_polyz_unpack_19) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_avx2.c new file mode 100644 index 0000000000..07a5df9706 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_avx2.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +/* + * Reference: The pqcrystals implementation assumes a buffer that is 8 bytes + *. larger as the first loop overreads by 8 bytes that are then + * discarded. We instead do not pad the buffer and do not overread. + * The performance impact is negligible and it does not force the + * frontend to perform the unintuitive padding. + */ + +unsigned int mld_rej_uniform_avx2( + int32_t *MLD_RESTRICT r, const uint8_t buf[MLD_AVX2_REJ_UNIFORM_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i d, tmp; + const __m256i bound = _mm256_set1_epi32(MLDSA_Q); + const __m256i mask = _mm256_set1_epi32(0x7FFFFF); + const __m256i idx8 = + _mm256_set_epi8(-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4, + -1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 32) + { + d = _mm256_loadu_si256((__m256i *)&buf[pos]); + + /* Permute 64-bit lanes + * 0x94 = 10010100b rearranges 64-bit lanes as: [3,2,1,0] -> [2,1,1,0] + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Original Layout ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ bytes 16..23 │ bytes 24..31 │ + * └─────────────────┴─────────────────┴─────────────────┴─────────────────┘ + * + * ╔═══════════════════════════════════════════════════════════════════════╗ + * ║ Layout after permute ║ + * ║ Byte indices in high half shifted down by 8 positions ║ + * ╚═══════════════════════════════════════════════════════════════════════╝ + * ┌───────────────┬─────────────────┐ ┌─────────────────┬─────────────────┐ + * │ Lane 0 │ Lane 1 │ │ Lane 2 │ Lane 3 │ + * │ bytes 0..7 │ bytes 8..15 │ │ bytes 8..15 │ bytes 16..23 │ + * └───────────────┴─────────────────┘ └─────────────────┴─────────────────┘ + * Lower 128-bit lane (bytes 0-15) Upper 128-bit lane (bytes 16-31) + */ + d = _mm256_permute4x64_epi64(d, 0x94); + + /* Shuffling 8-bit lanes + * + * ┌─ Indices 0-11 into low 128-bit half of permuted vector────────────────┐ + * │ Shuffle: [-1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0] │ + * │ Result: [0, byte11, byte10, byte9, ..., 0, byte2, byte1, byte0] │ + * └───────────────────────────────────────────────────────────────────────┘ + * + * ┌─ Indices 4-15 into high 128-bit half of permuted vector ──────────────┐ + * │ Shuffle: [-1, 15, 14, 13, -1, 12, 11, 10, -1, 9, 8, 7, -1, 6, 5, 4] │ + * │ Result: [0, byte23, byte22, byte21, ..., 0, byte14, byte13, byte12 │ + * └───────────────────────────────────────────────────────────────────────┘ + */ + d = _mm256_shuffle_epi8(d, idx8); + d = _mm256_and_si256(d, mask); + pos += 24; + + tmp = _mm256_sub_epi32(d, bound); + good = (uint32_t)_mm256_movemask_ps((__m256)tmp); + tmp = _mm256_cvtepu8_epi32( + _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good])); + d = _mm256_permutevar8x32_epi32(d, tmp); + + _mm256_storeu_si256((__m256i *)&r[ctr], d); + ctr += (unsigned)_mm_popcnt_u32(good); + } + + while (ctr < MLDSA_N && pos <= MLD_AVX2_REJ_UNIFORM_BUFLEN - 3) + { + uint32_t t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + /* Safe because t < MLDSA_Q. */ + r[ctr++] = (int32_t)t; + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_eta2_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_eta2_avx2.c new file mode 100644 index 0000000000..70c5c42c70 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_eta2_avx2.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA2 2 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ +unsigned int mld_rej_uniform_eta2_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1, f2; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA2); + const __m256i bound = mask; + /* check-magic: -6560 == 32*round(-2**10 / 5) */ + const __m256i v = _mm256_set1_epi32(-6560); + const __m256i p = _mm256_set1_epi32(5); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + f2 = _mm256_mulhrs_epi16(f1, v); + f2 = _mm256_mullo_epi16(f2, p); + f1 = _mm256_add_epi32(f1, f2); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 15) + { + t0 = t0 - (205 * t0 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t0); + } + if (t1 < 15 && ctr < MLDSA_N) + { + t1 = t1 - (205 * t1 >> 10) * 5; + r[ctr++] = (int32_t)(2 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta2) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA2 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_eta4_avx2.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_eta4_avx2.c new file mode 100644 index 0000000000..ba00e91252 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_eta4_avx2.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [REF_AVX2] + * CRYSTALS-Dilithium optimized AVX2 implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/avx2 + */ + +/* + * This file is derived from the public domain + * AVX2 Dilithium implementation @[REF_AVX2]. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include +#include +#include "arith_native_x86_64.h" +#include "consts.h" + +#define MLD_AVX2_ETA4 4 + +/* + * Reference: In the pqcrystals implementation this function is called + * rej_eta_avx and supports multiple values for ETA via preprocessor + * conditionals. We move the conditionals to the frontend. + */ + +unsigned int mld_rej_uniform_eta4_avx2( + int32_t *MLD_RESTRICT r, + const uint8_t buf[MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN]) +{ + unsigned int ctr, pos; + uint32_t good; + __m256i f0, f1; + __m128i g0, g1; + const __m256i mask = _mm256_set1_epi8(15); + const __m256i eta = _mm256_set1_epi8(MLD_AVX2_ETA4); + const __m256i bound = _mm256_set1_epi8(9); + + ctr = pos = 0; + while (ctr <= MLDSA_N - 8 && pos <= MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN - 16) + { + f0 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)&buf[pos])); + f1 = _mm256_slli_epi16(f0, 4); + f0 = _mm256_or_si256(f0, f1); + f0 = _mm256_and_si256(f0, mask); + + f1 = _mm256_sub_epi8(f0, bound); + f0 = _mm256_sub_epi8(eta, f0); + good = (uint32_t)_mm256_movemask_epi8(f1); + + g0 = _mm256_castsi256_si128(f0); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm256_extracti128_si256(f0, 1); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good & 0xFF]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good & 0xFF); + good >>= 8; + pos += 4; + + if (ctr > MLDSA_N - 8) + { + break; + } + g0 = _mm_bsrli_si128(g0, 8); + g1 = _mm_loadl_epi64((__m128i *)&mld_rej_uniform_table[good]); + g1 = _mm_shuffle_epi8(g0, g1); + f1 = _mm256_cvtepi8_epi32(g1); + _mm256_storeu_si256((__m256i *)&r[ctr], f1); + ctr += (unsigned)_mm_popcnt_u32(good); + pos += 4; + } + + while (ctr < MLDSA_N && pos < MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN) + { + uint32_t t0 = buf[pos] & 0x0F; + uint32_t t1 = buf[pos++] >> 4; + + if (t0 < 9) + { + r[ctr++] = (int32_t)(4 - t0); + } + if (t1 < 9 && ctr < MLDSA_N) + { + r[ctr++] = (int32_t)(4 - t1); + } + } + + return ctr; +} + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_eta4) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_AVX2_ETA4 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_table.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_table.c new file mode 100644 index 0000000000..6c537b4542 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_table.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include "../../../common.h" + +#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \ + !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) + +#include +#include "arith_native_x86_64.h" + +/* + * Lookup table used by rejection sampling. + * See autogen for details. + */ +MLD_ALIGN const uint8_t mld_rej_uniform_table[256][8] = { + {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, + {2, 0, 0, 0, 0, 0, 0, 0}, {0, 2, 0, 0, 0, 0, 0, 0}, + {1, 2, 0, 0, 0, 0, 0, 0}, {0, 1, 2, 0, 0, 0, 0, 0}, + {3, 0, 0, 0, 0, 0, 0, 0}, {0, 3, 0, 0, 0, 0, 0, 0}, + {1, 3, 0, 0, 0, 0, 0, 0}, {0, 1, 3, 0, 0, 0, 0, 0}, + {2, 3, 0, 0, 0, 0, 0, 0}, {0, 2, 3, 0, 0, 0, 0, 0}, + {1, 2, 3, 0, 0, 0, 0, 0}, {0, 1, 2, 3, 0, 0, 0, 0}, + {4, 0, 0, 0, 0, 0, 0, 0}, {0, 4, 0, 0, 0, 0, 0, 0}, + {1, 4, 0, 0, 0, 0, 0, 0}, {0, 1, 4, 0, 0, 0, 0, 0}, + {2, 4, 0, 0, 0, 0, 0, 0}, {0, 2, 4, 0, 0, 0, 0, 0}, + {1, 2, 4, 0, 0, 0, 0, 0}, {0, 1, 2, 4, 0, 0, 0, 0}, + {3, 4, 0, 0, 0, 0, 0, 0}, {0, 3, 4, 0, 0, 0, 0, 0}, + {1, 3, 4, 0, 0, 0, 0, 0}, {0, 1, 3, 4, 0, 0, 0, 0}, + {2, 3, 4, 0, 0, 0, 0, 0}, {0, 2, 3, 4, 0, 0, 0, 0}, + {1, 2, 3, 4, 0, 0, 0, 0}, {0, 1, 2, 3, 4, 0, 0, 0}, + {5, 0, 0, 0, 0, 0, 0, 0}, {0, 5, 0, 0, 0, 0, 0, 0}, + {1, 5, 0, 0, 0, 0, 0, 0}, {0, 1, 5, 0, 0, 0, 0, 0}, + {2, 5, 0, 0, 0, 0, 0, 0}, {0, 2, 5, 0, 0, 0, 0, 0}, + {1, 2, 5, 0, 0, 0, 0, 0}, {0, 1, 2, 5, 0, 0, 0, 0}, + {3, 5, 0, 0, 0, 0, 0, 0}, {0, 3, 5, 0, 0, 0, 0, 0}, + {1, 3, 5, 0, 0, 0, 0, 0}, {0, 1, 3, 5, 0, 0, 0, 0}, + {2, 3, 5, 0, 0, 0, 0, 0}, {0, 2, 3, 5, 0, 0, 0, 0}, + {1, 2, 3, 5, 0, 0, 0, 0}, {0, 1, 2, 3, 5, 0, 0, 0}, + {4, 5, 0, 0, 0, 0, 0, 0}, {0, 4, 5, 0, 0, 0, 0, 0}, + {1, 4, 5, 0, 0, 0, 0, 0}, {0, 1, 4, 5, 0, 0, 0, 0}, + {2, 4, 5, 0, 0, 0, 0, 0}, {0, 2, 4, 5, 0, 0, 0, 0}, + {1, 2, 4, 5, 0, 0, 0, 0}, {0, 1, 2, 4, 5, 0, 0, 0}, + {3, 4, 5, 0, 0, 0, 0, 0}, {0, 3, 4, 5, 0, 0, 0, 0}, + {1, 3, 4, 5, 0, 0, 0, 0}, {0, 1, 3, 4, 5, 0, 0, 0}, + {2, 3, 4, 5, 0, 0, 0, 0}, {0, 2, 3, 4, 5, 0, 0, 0}, + {1, 2, 3, 4, 5, 0, 0, 0}, {0, 1, 2, 3, 4, 5, 0, 0}, + {6, 0, 0, 0, 0, 0, 0, 0}, {0, 6, 0, 0, 0, 0, 0, 0}, + {1, 6, 0, 0, 0, 0, 0, 0}, {0, 1, 6, 0, 0, 0, 0, 0}, + {2, 6, 0, 0, 0, 0, 0, 0}, {0, 2, 6, 0, 0, 0, 0, 0}, + {1, 2, 6, 0, 0, 0, 0, 0}, {0, 1, 2, 6, 0, 0, 0, 0}, + {3, 6, 0, 0, 0, 0, 0, 0}, {0, 3, 6, 0, 0, 0, 0, 0}, + {1, 3, 6, 0, 0, 0, 0, 0}, {0, 1, 3, 6, 0, 0, 0, 0}, + {2, 3, 6, 0, 0, 0, 0, 0}, {0, 2, 3, 6, 0, 0, 0, 0}, + {1, 2, 3, 6, 0, 0, 0, 0}, {0, 1, 2, 3, 6, 0, 0, 0}, + {4, 6, 0, 0, 0, 0, 0, 0}, {0, 4, 6, 0, 0, 0, 0, 0}, + {1, 4, 6, 0, 0, 0, 0, 0}, {0, 1, 4, 6, 0, 0, 0, 0}, + {2, 4, 6, 0, 0, 0, 0, 0}, {0, 2, 4, 6, 0, 0, 0, 0}, + {1, 2, 4, 6, 0, 0, 0, 0}, {0, 1, 2, 4, 6, 0, 0, 0}, + {3, 4, 6, 0, 0, 0, 0, 0}, {0, 3, 4, 6, 0, 0, 0, 0}, + {1, 3, 4, 6, 0, 0, 0, 0}, {0, 1, 3, 4, 6, 0, 0, 0}, + {2, 3, 4, 6, 0, 0, 0, 0}, {0, 2, 3, 4, 6, 0, 0, 0}, + {1, 2, 3, 4, 6, 0, 0, 0}, {0, 1, 2, 3, 4, 6, 0, 0}, + {5, 6, 0, 0, 0, 0, 0, 0}, {0, 5, 6, 0, 0, 0, 0, 0}, + {1, 5, 6, 0, 0, 0, 0, 0}, {0, 1, 5, 6, 0, 0, 0, 0}, + {2, 5, 6, 0, 0, 0, 0, 0}, {0, 2, 5, 6, 0, 0, 0, 0}, + {1, 2, 5, 6, 0, 0, 0, 0}, {0, 1, 2, 5, 6, 0, 0, 0}, + {3, 5, 6, 0, 0, 0, 0, 0}, {0, 3, 5, 6, 0, 0, 0, 0}, + {1, 3, 5, 6, 0, 0, 0, 0}, {0, 1, 3, 5, 6, 0, 0, 0}, + {2, 3, 5, 6, 0, 0, 0, 0}, {0, 2, 3, 5, 6, 0, 0, 0}, + {1, 2, 3, 5, 6, 0, 0, 0}, {0, 1, 2, 3, 5, 6, 0, 0}, + {4, 5, 6, 0, 0, 0, 0, 0}, {0, 4, 5, 6, 0, 0, 0, 0}, + {1, 4, 5, 6, 0, 0, 0, 0}, {0, 1, 4, 5, 6, 0, 0, 0}, + {2, 4, 5, 6, 0, 0, 0, 0}, {0, 2, 4, 5, 6, 0, 0, 0}, + {1, 2, 4, 5, 6, 0, 0, 0}, {0, 1, 2, 4, 5, 6, 0, 0}, + {3, 4, 5, 6, 0, 0, 0, 0}, {0, 3, 4, 5, 6, 0, 0, 0}, + {1, 3, 4, 5, 6, 0, 0, 0}, {0, 1, 3, 4, 5, 6, 0, 0}, + {2, 3, 4, 5, 6, 0, 0, 0}, {0, 2, 3, 4, 5, 6, 0, 0}, + {1, 2, 3, 4, 5, 6, 0, 0}, {0, 1, 2, 3, 4, 5, 6, 0}, + {7, 0, 0, 0, 0, 0, 0, 0}, {0, 7, 0, 0, 0, 0, 0, 0}, + {1, 7, 0, 0, 0, 0, 0, 0}, {0, 1, 7, 0, 0, 0, 0, 0}, + {2, 7, 0, 0, 0, 0, 0, 0}, {0, 2, 7, 0, 0, 0, 0, 0}, + {1, 2, 7, 0, 0, 0, 0, 0}, {0, 1, 2, 7, 0, 0, 0, 0}, + {3, 7, 0, 0, 0, 0, 0, 0}, {0, 3, 7, 0, 0, 0, 0, 0}, + {1, 3, 7, 0, 0, 0, 0, 0}, {0, 1, 3, 7, 0, 0, 0, 0}, + {2, 3, 7, 0, 0, 0, 0, 0}, {0, 2, 3, 7, 0, 0, 0, 0}, + {1, 2, 3, 7, 0, 0, 0, 0}, {0, 1, 2, 3, 7, 0, 0, 0}, + {4, 7, 0, 0, 0, 0, 0, 0}, {0, 4, 7, 0, 0, 0, 0, 0}, + {1, 4, 7, 0, 0, 0, 0, 0}, {0, 1, 4, 7, 0, 0, 0, 0}, + {2, 4, 7, 0, 0, 0, 0, 0}, {0, 2, 4, 7, 0, 0, 0, 0}, + {1, 2, 4, 7, 0, 0, 0, 0}, {0, 1, 2, 4, 7, 0, 0, 0}, + {3, 4, 7, 0, 0, 0, 0, 0}, {0, 3, 4, 7, 0, 0, 0, 0}, + {1, 3, 4, 7, 0, 0, 0, 0}, {0, 1, 3, 4, 7, 0, 0, 0}, + {2, 3, 4, 7, 0, 0, 0, 0}, {0, 2, 3, 4, 7, 0, 0, 0}, + {1, 2, 3, 4, 7, 0, 0, 0}, {0, 1, 2, 3, 4, 7, 0, 0}, + {5, 7, 0, 0, 0, 0, 0, 0}, {0, 5, 7, 0, 0, 0, 0, 0}, + {1, 5, 7, 0, 0, 0, 0, 0}, {0, 1, 5, 7, 0, 0, 0, 0}, + {2, 5, 7, 0, 0, 0, 0, 0}, {0, 2, 5, 7, 0, 0, 0, 0}, + {1, 2, 5, 7, 0, 0, 0, 0}, {0, 1, 2, 5, 7, 0, 0, 0}, + {3, 5, 7, 0, 0, 0, 0, 0}, {0, 3, 5, 7, 0, 0, 0, 0}, + {1, 3, 5, 7, 0, 0, 0, 0}, {0, 1, 3, 5, 7, 0, 0, 0}, + {2, 3, 5, 7, 0, 0, 0, 0}, {0, 2, 3, 5, 7, 0, 0, 0}, + {1, 2, 3, 5, 7, 0, 0, 0}, {0, 1, 2, 3, 5, 7, 0, 0}, + {4, 5, 7, 0, 0, 0, 0, 0}, {0, 4, 5, 7, 0, 0, 0, 0}, + {1, 4, 5, 7, 0, 0, 0, 0}, {0, 1, 4, 5, 7, 0, 0, 0}, + {2, 4, 5, 7, 0, 0, 0, 0}, {0, 2, 4, 5, 7, 0, 0, 0}, + {1, 2, 4, 5, 7, 0, 0, 0}, {0, 1, 2, 4, 5, 7, 0, 0}, + {3, 4, 5, 7, 0, 0, 0, 0}, {0, 3, 4, 5, 7, 0, 0, 0}, + {1, 3, 4, 5, 7, 0, 0, 0}, {0, 1, 3, 4, 5, 7, 0, 0}, + {2, 3, 4, 5, 7, 0, 0, 0}, {0, 2, 3, 4, 5, 7, 0, 0}, + {1, 2, 3, 4, 5, 7, 0, 0}, {0, 1, 2, 3, 4, 5, 7, 0}, + {6, 7, 0, 0, 0, 0, 0, 0}, {0, 6, 7, 0, 0, 0, 0, 0}, + {1, 6, 7, 0, 0, 0, 0, 0}, {0, 1, 6, 7, 0, 0, 0, 0}, + {2, 6, 7, 0, 0, 0, 0, 0}, {0, 2, 6, 7, 0, 0, 0, 0}, + {1, 2, 6, 7, 0, 0, 0, 0}, {0, 1, 2, 6, 7, 0, 0, 0}, + {3, 6, 7, 0, 0, 0, 0, 0}, {0, 3, 6, 7, 0, 0, 0, 0}, + {1, 3, 6, 7, 0, 0, 0, 0}, {0, 1, 3, 6, 7, 0, 0, 0}, + {2, 3, 6, 7, 0, 0, 0, 0}, {0, 2, 3, 6, 7, 0, 0, 0}, + {1, 2, 3, 6, 7, 0, 0, 0}, {0, 1, 2, 3, 6, 7, 0, 0}, + {4, 6, 7, 0, 0, 0, 0, 0}, {0, 4, 6, 7, 0, 0, 0, 0}, + {1, 4, 6, 7, 0, 0, 0, 0}, {0, 1, 4, 6, 7, 0, 0, 0}, + {2, 4, 6, 7, 0, 0, 0, 0}, {0, 2, 4, 6, 7, 0, 0, 0}, + {1, 2, 4, 6, 7, 0, 0, 0}, {0, 1, 2, 4, 6, 7, 0, 0}, + {3, 4, 6, 7, 0, 0, 0, 0}, {0, 3, 4, 6, 7, 0, 0, 0}, + {1, 3, 4, 6, 7, 0, 0, 0}, {0, 1, 3, 4, 6, 7, 0, 0}, + {2, 3, 4, 6, 7, 0, 0, 0}, {0, 2, 3, 4, 6, 7, 0, 0}, + {1, 2, 3, 4, 6, 7, 0, 0}, {0, 1, 2, 3, 4, 6, 7, 0}, + {5, 6, 7, 0, 0, 0, 0, 0}, {0, 5, 6, 7, 0, 0, 0, 0}, + {1, 5, 6, 7, 0, 0, 0, 0}, {0, 1, 5, 6, 7, 0, 0, 0}, + {2, 5, 6, 7, 0, 0, 0, 0}, {0, 2, 5, 6, 7, 0, 0, 0}, + {1, 2, 5, 6, 7, 0, 0, 0}, {0, 1, 2, 5, 6, 7, 0, 0}, + {3, 5, 6, 7, 0, 0, 0, 0}, {0, 3, 5, 6, 7, 0, 0, 0}, + {1, 3, 5, 6, 7, 0, 0, 0}, {0, 1, 3, 5, 6, 7, 0, 0}, + {2, 3, 5, 6, 7, 0, 0, 0}, {0, 2, 3, 5, 6, 7, 0, 0}, + {1, 2, 3, 5, 6, 7, 0, 0}, {0, 1, 2, 3, 5, 6, 7, 0}, + {4, 5, 6, 7, 0, 0, 0, 0}, {0, 4, 5, 6, 7, 0, 0, 0}, + {1, 4, 5, 6, 7, 0, 0, 0}, {0, 1, 4, 5, 6, 7, 0, 0}, + {2, 4, 5, 6, 7, 0, 0, 0}, {0, 2, 4, 5, 6, 7, 0, 0}, + {1, 2, 4, 5, 6, 7, 0, 0}, {0, 1, 2, 4, 5, 6, 7, 0}, + {3, 4, 5, 6, 7, 0, 0, 0}, {0, 3, 4, 5, 6, 7, 0, 0}, + {1, 3, 4, 5, 6, 7, 0, 0}, {0, 1, 3, 4, 5, 6, 7, 0}, + {2, 3, 4, 5, 6, 7, 0, 0}, {0, 2, 3, 4, 5, 6, 7, 0}, + {1, 2, 3, 4, 5, 6, 7, 0}, {0, 1, 2, 3, 4, 5, 6, 7}, +}; + +#else /* MLD_ARITH_BACKEND_X86_64_DEFAULT && !MLD_CONFIG_MULTILEVEL_NO_SHARED \ + */ + +MLD_EMPTY_CU(avx2_rej_uniform_table) + +#endif /* !(MLD_ARITH_BACKEND_X86_64_DEFAULT && \ + !MLD_CONFIG_MULTILEVEL_NO_SHARED) */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/packing.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/packing.c new file mode 100644 index 0000000000..26da273856 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/packing.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include + +#include "common.h" +#include "packing.h" +#include "poly.h" +#include "polyvec.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_unpack_hints MLD_ADD_PARAM_SET(mld_unpack_hints) +/* End of parameter set namespacing */ + +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +{ + unsigned int i; + + mld_memcpy(pk, rho, MLDSA_SEEDBYTES); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt1_pack(pk + MLDSA_SEEDBYTES + i * MLDSA_POLYT1_PACKEDBYTES, + &t1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +{ + unsigned int i; + + mld_memcpy(rho, pk, MLDSA_SEEDBYTES); + pk += MLDSA_SEEDBYTES; + + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt1_unpack(&t1->vec[i], pk + i * MLDSA_POLYT1_PACKEDBYTES); + } +} + +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +{ + mld_memcpy(sk, rho, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, key, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(sk, tr, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_pack_eta(sk, s1); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_eta(sk, s2); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_pack_t0(sk, t0); +} + +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +{ + mld_memcpy(rho, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(key, sk, MLDSA_SEEDBYTES); + sk += MLDSA_SEEDBYTES; + + mld_memcpy(tr, sk, MLDSA_TRBYTES); + sk += MLDSA_TRBYTES; + + mld_polyvecl_unpack_eta(s1, sk); + sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_eta(s2, sk); + sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES; + + mld_polyveck_unpack_t0(t0, sk); +} + +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +{ + unsigned int i, j, k; + + mld_memcpy(sig, c, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + /* skip z component - packed via mld_pack_sig_z */ + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + /* Encode hints h */ + + /* The final section of sig[] is MLDSA_POLYVECH_PACKEDBYTES long, where + * MLDSA_POLYVECH_PACKEDBYTES = MLDSA_OMEGA + MLDSA_K + * + * The first OMEGA bytes record the index numbers of the coefficients + * that are not equal to 0 + * + * The final K bytes record a running tally of the number of hints + * coming from each of the K polynomials in h. + * + * The pre-condition tells us that number_of_hints <= OMEGA, so some + * bytes may not be written, so we initialize all of them to zero + * to start. + */ + mld_memset(sig, 0, MLDSA_POLYVECH_PACKEDBYTES); + + k = 0; + /* For each polynomial in h... */ + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* For each coefficient in that polynomial, record it as as hint */ + /* if its value is not zero */ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + assigns(j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES)) + invariant(i <= MLDSA_K) + invariant(j <= MLDSA_N) + invariant(k <= number_of_hints) + invariant(number_of_hints <= MLDSA_OMEGA) + ) + { + /* The reference implementation implicitly relies on the total */ + /* number of hints being less than OMEGA, assuming h is valid. */ + /* In mldsa-native, we check this explicitly to ease proof of */ + /* type safety. */ + if (h->vec[i].coeffs[j] != 0 && k < number_of_hints) + { + /* The enclosing if condition AND the loop invariant infer */ + /* that k < MLDSA_OMEGA, so writing to sig[k] is safe and k */ + /* can be incremented. */ + sig[k++] = (uint8_t)j; + } + } + /* Having recorded all the hints for this polynomial, also */ + /* record the running tally into the correct "slot" for that */ + /* coefficient in the final K bytes */ + sig[MLDSA_OMEGA + i] = (uint8_t)k; + } +} + +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +{ + sig += MLDSA_CTILDEBYTES; + sig += i * MLDSA_POLYZ_PACKEDBYTES; + mld_polyz_pack(sig, zi); +} + +/************************************************* + * Name: mld_unpack_hints + * + * Description: Unpack raw hint bytes into a polyveck + * struct + * + * Arguments: - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]: + * raw hint bytes + * + * Returns 1 in case of malformed hints; otherwise 0. + **************************************************/ +static int mld_unpack_hints( + mld_polyveck *h, const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(packed_hints, MLDSA_POLYVECH_PACKEDBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + /* All returned coefficients are either 0 or 1 */ + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +) +{ + unsigned int i, j; + unsigned int old_hint_count; + + /* Set all coefficients of all polynomials to 0. */ + /* Only those that are actually non-zero hints will */ + /* be overwritten below. */ + mld_memset(h, 0, sizeof(mld_polyveck)); + + old_hint_count = 0; + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + /* Grab the hint count for the i'th polynomial */ + const unsigned int new_hint_count = packed_hints[MLDSA_OMEGA + i]; + + /* new_hint_count must increase or stay the same, but also remain */ + /* less than or equal to MLDSA_OMEGA */ + if (new_hint_count < old_hint_count || new_hint_count > MLDSA_OMEGA) + { + /* Error - new_hint_count is invalid */ + return 1; + } + + /* If new_hint_count == old_hint_count, then this polynomial has */ + /* zero hints, so this loop executes zero times and we move */ + /* straight on to the next polynomial. */ + for (j = old_hint_count; j < new_hint_count; ++j) + __loop__( + invariant(i <= MLDSA_K) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + const uint8_t this_hint_index = packed_hints[j]; + + /* Coefficients must be ordered for strong unforgeability */ + if (j > old_hint_count && this_hint_index <= packed_hints[j - 1]) + { + return 1; + } + h->vec[i].coeffs[this_hint_index] = 1; + } + + old_hint_count = new_hint_count; + } + + /* Extra indices must be zero for strong unforgeability */ + for (j = old_hint_count; j < MLDSA_OMEGA; ++j) + __loop__( + invariant(j <= MLDSA_OMEGA) + /* Maintain the post-condition */ + invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + if (packed_hints[j] != 0) + { + return 1; + } + } + + return 0; +} + +MLD_INTERNAL_API +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +{ + mld_memcpy(c, sig, MLDSA_CTILDEBYTES); + sig += MLDSA_CTILDEBYTES; + + mld_polyvecl_unpack_z(z, sig); + sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES; + + return mld_unpack_hints(h, sig); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_unpack_hints diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/packing.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/packing.h new file mode 100644 index 0000000000..19095d08cd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/packing.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PACKING_H +#define MLD_PACKING_H + +#include +#include "polyvec.h" + +#define mld_pack_pk MLD_NAMESPACE_KL(pack_pk) +/************************************************* + * Name: mld_pack_pk + * + * Description: Bit-pack public key pk = (rho, t1). + * + * Arguments: - uint8_t pk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const mld_polyveck *t1: pointer to vector t1 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) +); + + +#define mld_pack_sk MLD_NAMESPACE_KL(pack_sk) +/************************************************* + * Name: mld_pack_sk + * + * Description: Bit-pack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - uint8_t sk[]: output byte array + * - const uint8_t rho[]: byte array containing rho + * - const uint8_t tr[]: byte array containing tr + * - const uint8_t key[]: byte array containing key + * - const mld_polyveck *t0: pointer to vector t0 + * - const mld_polyvecl *s1: pointer to vector s1 + * - const mld_polyveck *s2: pointer to vector s2 + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t rho[MLDSA_SEEDBYTES], + const uint8_t tr[MLDSA_TRBYTES], + const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0, + const mld_polyvecl *s1, const mld_polyveck *s2) +__contract__( + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + requires(forall(k2, 0, MLDSA_K, + array_abs_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) +); + + +#define mld_pack_sig_c_h MLD_NAMESPACE_KL(pack_sig_c_h) +/************************************************* + * Name: mld_pack_sig_c_h + * + * Description: Bit-pack c and h component of sig = (c, z, h). + * The z component is packed separately using mld_pack_sig_z. + * + * Arguments: - uint8_t sig[]: output byte array + * - const uint8_t *c: pointer to challenge hash length + * MLDSA_SEEDBYTES + * - const mld_polyveck *h: pointer to hint vector h + * - const unsigned int number_of_hints: total + * hints in *h + * + * Note that the number_of_hints argument is not present + * in the reference implementation. It is added here to ease + * proof of type safety. + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES], + const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h, + const unsigned int number_of_hints) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + requires(number_of_hints <= MLDSA_OMEGA) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_pack_sig_z MLD_NAMESPACE_KL(pack_sig_z) +/************************************************* + * Name: mld_pack_sig_z + * + * Description: Bit-pack single polynomial of z component of sig = (c, z, h). + * The c and h components are packed separately using + * mld_pack_sig_c_h. + * + * Arguments: - uint8_t sig[]: output byte array + * - const mld_poly *zi: pointer to a single polynomial in z + * - const unsigned int i: index of zi in vector z + * + **************************************************/ +MLD_INTERNAL_API +void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi, + unsigned i) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(zi, sizeof(mld_poly))) + requires(i < MLDSA_L) + requires(array_bound(zi->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) +); + +#define mld_unpack_pk MLD_NAMESPACE_KL(unpack_pk) +/************************************************* + * Name: mld_unpack_pk + * + * Description: Unpack public key pk = (rho, t1). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const mld_polyveck *t1: pointer to output vector t1 + * - uint8_t pk[]: byte array containing bit-packed pk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) +); + + +#define mld_unpack_sk MLD_NAMESPACE_KL(unpack_sk) +/************************************************* + * Name: mld_unpack_sk + * + * Description: Unpack secret key sk = (rho, tr, key, t0, s1, s2). + * + * Arguments: - const uint8_t rho[]: output byte array for rho + * - const uint8_t tr[]: output byte array for tr + * - const uint8_t key[]: output byte array for key + * - const mld_polyveck *t0: pointer to output vector t0 + * - const mld_polyvecl *s1: pointer to output vector s1 + * - const mld_polyveck *s2: pointer to output vector s2 + * - uint8_t sk[]: byte array containing bit-packed sk + **************************************************/ +MLD_INTERNAL_API +void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES], + uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0, + mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]) +__contract__( + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(key, MLDSA_SEEDBYTES)) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(key, MLDSA_SEEDBYTES)) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(s1, sizeof(mld_polyvecl))) + assigns(memory_slice(s2, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_unpack_sig MLD_NAMESPACE_KL(unpack_sig) +/************************************************* + * Name: mld_unpack_sig + * + * Description: Unpack signature sig = (c, z, h). + * + * Arguments: - uint8_t *c: pointer to output challenge hash + * - mld_polyvecl *z: pointer to output vector z + * - mld_polyveck *h: pointer to output hint vector h + * - const uint8_t sig[]: byte array containing + * bit-packed signature + * + * Returns 1 in case of malformed signature; otherwise 0. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z, + mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES]) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(c, MLDSA_CTILDEBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + assigns(memory_slice(c, MLDSA_CTILDEBYTES)) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(z->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ensures(return_value >= 0 && return_value <= 1) +); +#endif /* !MLD_PACKING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/params.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/params.h new file mode 100644 index 0000000000..c67d2a33fb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/params.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_PARAMS_H +#define MLD_PARAMS_H + +#define MLDSA_SEEDBYTES 32 +#define MLDSA_CRHBYTES 64 +#define MLDSA_TRBYTES 64 +#define MLDSA_RNDBYTES 32 +#define MLDSA_N 256 +#define MLDSA_Q 8380417 +#define MLDSA_Q_HALF ((MLDSA_Q + 1) / 2) +#define MLDSA_D 13 + +#if MLD_CONFIG_PARAMETER_SET == 44 + +#define MLDSA_K 4 +#define MLDSA_L 4 +#define MLDSA_ETA 2 +#define MLDSA_TAU 39 +#define MLDSA_BETA 78 +#define MLDSA_GAMMA1 (1 << 17) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 88) +#define MLDSA_OMEGA 80 +#define MLDSA_CTILDEBYTES 32 +#define MLDSA_POLYZ_PACKEDBYTES 576 +#define MLDSA_POLYW1_PACKEDBYTES 192 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#elif MLD_CONFIG_PARAMETER_SET == 65 + +#define MLDSA_K 6 +#define MLDSA_L 5 +#define MLDSA_ETA 4 +#define MLDSA_TAU 49 +#define MLDSA_BETA 196 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 55 +#define MLDSA_CTILDEBYTES 48 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 128 + +#elif MLD_CONFIG_PARAMETER_SET == 87 + +#define MLDSA_K 8 +#define MLDSA_L 7 +#define MLDSA_ETA 2 +#define MLDSA_TAU 60 +#define MLDSA_BETA 120 +#define MLDSA_GAMMA1 (1 << 19) +#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32) +#define MLDSA_OMEGA 75 +#define MLDSA_CTILDEBYTES 64 +#define MLDSA_POLYZ_PACKEDBYTES 640 +#define MLDSA_POLYW1_PACKEDBYTES 128 +#define MLDSA_POLYETA_PACKEDBYTES 96 + +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ + +#define MLDSA_POLYT1_PACKEDBYTES 320 +#define MLDSA_POLYT0_PACKEDBYTES 416 +#define MLDSA_POLYVECH_PACKEDBYTES (MLDSA_OMEGA + MLDSA_K) + +#define MLDSA_CRYPTO_PUBLICKEYBYTES \ + (MLDSA_SEEDBYTES + MLDSA_K * MLDSA_POLYT1_PACKEDBYTES) +#define MLDSA_CRYPTO_SECRETKEYBYTES \ + (2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + MLDSA_L * MLDSA_POLYETA_PACKEDBYTES + \ + MLDSA_K * MLDSA_POLYETA_PACKEDBYTES + MLDSA_K * MLDSA_POLYT0_PACKEDBYTES) +#define MLDSA_CRYPTO_BYTES \ + (MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES + \ + MLDSA_POLYVECH_PACKEDBYTES) + +#endif /* !MLD_PARAMS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/poly.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/poly.c new file mode 100644 index 0000000000..e40534e773 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/poly.c @@ -0,0 +1,973 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "common.h" +#include "ct.h" +#include "debug.h" +#include "poly.h" +#include "reduce.h" +#include "rounding.h" +#include "symmetric.h" + +#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) +#include "zetas.inc" + +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + { + a->coeffs[i] = mld_reduce32(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_STATIC_TESTABLE void mld_poly_caddq_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + ) + { + a->coeffs[i] = mld_caddq(a->coeffs[i]); + } + + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_POLY_CADDQ) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_poly_caddq_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POLY_CADDQ */ + mld_poly_caddq_c(a); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1])) + invariant(forall(k2, 0, i, r->coeffs[k2] < MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k2, 0, i, r->coeffs[k2] >= INT32_MIN)) + ) + { + r->coeffs[i] = r->coeffs[i] + b->coeffs[i]; + } +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +{ + unsigned int i; + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(r->coeffs, 0, i, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + ) + { + r->coeffs[i] = r->coeffs[i] - b->coeffs[i]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N; i++) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q)) + invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))) + { + /* Reference: uses a left shift by MLDSA_D which is undefined behaviour in + * C90/C99 + */ + a->coeffs[i] *= (1 << MLDSA_D); + } + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); +} + + +static MLD_INLINE int32_t mld_fqmul(int32_t a, int32_t b) +__contract__( + requires(b > -MLDSA_Q_HALF && b < MLDSA_Q_HALF) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* Bounds: We argue in mld_montgomery_reduce() that the reult + * of Montgomery reduction is < MLDSA_Q if the input is smaller + * than 2^31 * MLDSA_Q in absolute value. Indeed, we have: + * + * |a * b| = |a| * |b| + * < 2^31 * MLDSA_Q_HALF + * < 2^31 * MLDSA_Q + */ + return mld_montgomery_reduce((int64_t)a * (int64_t)b); +} + +/* mld_ntt_butterfly_block() + * + * Computes a block CT butterflies with a fixed twiddle factor, + * using Montgomery multiplication. + * + * Parameters: + * - r: Pointer to base of polynomial (_not_ the base of butterfly block) + * - zeta: Twiddle factor to use for the butterfly. This must be in + * Montgomery form and signed canonical. + * - start: Offset to the beginning of the butterfly block + * - len: Index difference between coefficients subject to a butterfly + * - bound: Ghost variable describing coefficient bound: Prior to `start`, + * coefficients must be bound by `bound + MLDSA_Q`. Post `start`, + * they must be bound by `bound`. + * When this function returns, output coefficients in the index range + * [start, start+2*len) have bound bumped to `bound + MLDSA_Q`. + * Example: + * - start=8, len=4 + * This would compute the following four butterflies + * 8 -- 12 + * 9 -- 13 + * 10 -- 14 + * 11 -- 15 + * - start=4, len=2 + * This would compute the following two butterflies + * 4 -- 6 + * 5 -- 7 + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_butterfly_block(int32_t r[MLDSA_N], + const int32_t zeta, + const unsigned start, + const unsigned len, + const unsigned bound) +__contract__( + requires(start < MLDSA_N) + requires(1 <= len && len <= MLDSA_N / 2 && start + 2 * len <= MLDSA_N) + requires(0 <= bound && bound < INT32_MAX - MLDSA_Q) + requires(-MLDSA_Q_HALF < zeta && zeta < MLDSA_Q_HALF) + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(array_abs_bound(r, 0, start, bound + MLDSA_Q)) + requires(array_abs_bound(r, start, MLDSA_N, bound)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, start + 2*len, bound + MLDSA_Q)) + ensures(array_abs_bound(r, start + 2 * len, MLDSA_N, bound))) +{ + /* `bound` is a ghost variable only needed in the CBMC specification */ + unsigned j; + ((void)bound); + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + /* + * Coefficients are updated in strided pairs, so the bounds for the + * intermediate states alternate twice between the old and new bound + */ + invariant(array_abs_bound(r, 0, j, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, bound)) + invariant(array_abs_bound(r, start + len, j + len, bound + MLDSA_Q)) + invariant(array_abs_bound(r, j + len, MLDSA_N, bound))) + { + int32_t t; + t = mld_fqmul(r[j + len], zeta); + r[j + len] = r[j] - t; + r[j] = r[j] + t; + } +} + +/* mld_ntt_layer() + * + * Compute one layer of forward NTT + * + * Parameters: + * - r: Pointer to base of polynomial + * - layer: Indicates which layer is being applied. + */ + +/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */ +static MLD_INLINE void mld_ntt_layer(int32_t r[MLDSA_N], const unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (layer + 1) * MLDSA_Q))) +{ + unsigned start, k, len; + /* Twiddle factors for layer n are at indices 2^(n-1)..2^n-1. */ + k = 1u << (layer - 1); + len = (unsigned)MLDSA_N >> layer; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start < MLDSA_N + 2 * len) + invariant(k <= MLDSA_N) + invariant(2 * len * k == start + MLDSA_N) + invariant(array_abs_bound(r, 0, start, layer * MLDSA_Q + MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, layer * MLDSA_Q))) + { + int32_t zeta = mld_zetas[k++]; + mld_ntt_butterfly_block(r, zeta, start, len, layer * MLDSA_Q); + } +} + +MLD_STATIC_TESTABLE void mld_poly_ntt_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +) +{ + unsigned int layer; + int32_t *r; + + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + r = a->coeffs; + + for (layer = 1; layer < 9; layer++) + __loop__( + invariant(1 <= layer && layer <= 9) + invariant(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q)) + ) + { + mld_ntt_layer(r, layer); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_NTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_ntt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_NTT */ + mld_poly_ntt_c(a); +} + +/************************************************* + * Name: mld_fqscale + * + * Description: Scales a field element by mont/256 , i.e., performs Montgomery + * multiplication by mont^2/256. + * Input is expected to have absolute value smaller than + * 256 * MLDSA_Q. + * Output has absolute value smaller than MLD_INTT_BOUND. + * + * Arguments: - int32_t a: Field element to be scaled. + **************************************************/ +static MLD_INLINE int32_t mld_fqscale(int32_t a) +__contract__( + requires(a > -256*MLDSA_Q && a < 256*MLDSA_Q) + ensures(return_value > -MLD_INTT_BOUND && return_value < MLD_INTT_BOUND) +) +{ + /* check-magic: 41978 == pow(2,64-8,MLDSA_Q) */ + const int32_t f = 41978; + /* Bounds: MLD_INTT_BOUND is MLDSA_Q, so the bounds reasoning is just + * a special case of that in mld_fqmul(). */ + return mld_montgomery_reduce((int64_t)a * f); +} + +/* Reference: Embedded into `invntt_tomont()` in the reference implementation + * @[REF] */ +static MLD_INLINE void mld_invntt_layer(int32_t r[MLDSA_N], unsigned layer) +__contract__( + requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N)) + requires(1 <= layer && layer <= 8) + requires(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q)) + assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N)) + ensures(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> (layer - 1)) * MLDSA_Q))) +{ + unsigned start, k, len; + len = (unsigned)MLDSA_N >> layer; + k = (1u << layer) - 1; + for (start = 0; start < MLDSA_N; start += 2 * len) + __loop__( + invariant(start <= MLDSA_N && k <= 255) + invariant(2 * len * k + start == 2 * MLDSA_N - 2 * len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + unsigned j; + int32_t zeta = -mld_zetas[k--]; + + for (j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, start, j, (MLDSA_N >> (layer - 1)) * MLDSA_Q)) + invariant(array_abs_bound(r, j, start + len, (MLDSA_N >> layer) * MLDSA_Q)) + invariant(array_abs_bound(r, start + len, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + int32_t t = r[j]; + r[j] = t + r[j + len]; + r[j + len] = t - r[j + len]; + r[j + len] = mld_fqmul(r[j + len], zeta); + } + } +} + +MLD_STATIC_TESTABLE void mld_poly_invntt_tomont_c(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +) +{ + unsigned int layer, j; + int32_t *r; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + + r = a->coeffs; + for (layer = 8; layer >= 1; layer--) + __loop__( + invariant(layer <= 8) + /* Absolute bounds increase from 1Q before layer 8 */ + /* up to 256Q after layer 1 */ + invariant(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))) + { + mld_invntt_layer(r, layer); + } + + /* Coefficient bounds are now at 256Q. We now scale by mont / 256, + * i.e., compute the Montgomery multiplication by mont^2 / 256. + * mont corrects the mont^-1 factor introduced in the basemul. + * 1/256 performs that scaling of the inverse NTT. + * The reduced value is bounded by MLD_INTT_BOUND in absolute + * value.*/ + for (j = 0; j < MLDSA_N; ++j) + __loop__( + invariant(j <= MLDSA_N) + invariant(array_abs_bound(r, 0, j, MLD_INTT_BOUND)) + invariant(array_abs_bound(r, j, MLDSA_N, MLDSA_N * MLDSA_Q)) + ) + { + r[j] = mld_fqscale(r[j]); + } + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); +} + + +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +{ +#if defined(MLD_USE_NATIVE_INTT) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q); + ret = mld_intt_native(a->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND); + return; + } +#endif /* MLD_USE_NATIVE_INTT */ + mld_poly_invntt_tomont_c(a); +} + +MLD_STATIC_TESTABLE void mld_poly_pointwise_montgomery_c(mld_poly *c, + const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_abs_bound(c->coeffs, 0, i, MLDSA_Q)) + ) + { + c->coeffs[i] = mld_montgomery_reduce((int64_t)a->coeffs[i] * b->coeffs[i]); + } + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +{ +#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY) + int ret; + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND); + mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND); + ret = mld_poly_pointwise_montgomery_native(c->coeffs, a->coeffs, b->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */ + mld_poly_pointwise_montgomery_c(c, a, b); +} + +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, 0, i, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + invariant(array_bound(a1->coeffs, 0, i, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) + ) + { + mld_power2round(&a0->coeffs[i], &a1->coeffs[i], a->coeffs[i]); + } + + mld_assert_bound(a0->coeffs, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +#ifndef MLD_POLY_UNIFORM_NBLOCKS +#define MLD_POLY_UNIFORM_NBLOCKS \ + ((768 + MLD_STREAM128_BLOCKBYTES - 1) / MLD_STREAM128_BLOCKBYTES) +#endif +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +MLD_STATIC_TESTABLE unsigned int mld_rej_uniform_c(int32_t *a, + unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ + unsigned int ctr, pos; + uint32_t t; + mld_assert_bound(a, offset, 0, MLDSA_Q); + + ctr = offset; + pos = 0; + /* pos + 3 cannot overflow due to the assumption + buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) */ + while (ctr < target && pos + 3 <= buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_bound(a, 0, ctr, 0, MLDSA_Q))) + { + t = buf[pos++]; + t |= (uint32_t)buf[pos++] << 8; + t |= (uint32_t)buf[pos++] << 16; + t &= 0x7FFFFF; + + if (t < MLDSA_Q) + { + a[ctr++] = (int32_t)t; + } + } + + mld_assert_bound(a, ctr, 0, MLDSA_Q); + + return ctr; +} +/************************************************* + * Name: mld_rej_uniform + * + * Description: Sample uniformly random coefficients in [0, MLDSA_Q-1] by + * performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes (must be + * multiple of 3) + * + * Returns number of sampled coefficients. Can be smaller than len if not enough + * random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_uniform()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +static unsigned int mld_rej_uniform(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_bound(a, 0, offset, 0, MLDSA_Q)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_bound(a, 0, return_value, 0, MLDSA_Q)) +) +{ +#if defined(MLD_USE_NATIVE_REJ_UNIFORM) + int ret; + mld_assert_bound(a, offset, 0, MLDSA_Q); + if (offset == 0) + { + ret = mld_rej_uniform_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_bound(a, res, 0, MLDSA_Q); + return res; + } + } +#endif /* MLD_USE_NATIVE_REJ_UNIFORM */ + + return mld_rej_uniform_c(a, target, offset, buf, buflen); +} + +/* Reference: poly_uniform() in the reference implementation @[REF]. + * - Simplified from reference by removing buffer tail handling + * since buflen % 3 = 0 always holds true (MLD_STREAM128_BLOCKBYTES + * = 168). + * - Modified rej_uniform interface to track offset directly. + * - Pass nonce packed in the extended seed array instead of a third + * argument. + * */ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +{ + unsigned int ctr; + unsigned int buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + MLD_ALIGN uint8_t buf[MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES]; + mld_xof128_ctx state; + + mld_xof128_init(&state); + mld_xof128_absorb_once(&state, seed, MLDSA_SEEDBYTES + 2); + mld_xof128_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, 0, buf, buflen); + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(a, sizeof(mld_poly)), object_whole(buf)) + invariant(ctr <= MLDSA_N) + invariant(array_bound(a->coeffs, 0, ctr, 0, MLDSA_Q)) + invariant(state.pos <= SHAKE128_RATE) + ) + { + mld_xof128_squeezeblocks(buf, 1, &state); + ctr = mld_rej_uniform(a->coeffs, MLDSA_N, ctr, buf, buflen); + } + mld_xof128_release(&state); + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof128_x4_ctx state; + unsigned buflen; + + mld_xof128_x4_init(&state); + mld_xof128_x4_absorb(&state, seed, MLDSA_SEEDBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_NBLOCKS. + * This should generate the matrix entries with high probability. + */ + + mld_xof128_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES; + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all matrix entries have been generated, squeeze + * one more block a time until we're done. + */ + buflen = MLD_STREAM128_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, object_whole(buf), + memory_slice(vec0, sizeof(mld_poly)), memory_slice(vec1, sizeof(mld_poly)), + memory_slice(vec2, sizeof(mld_poly)), memory_slice(vec3, sizeof(mld_poly))) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_bound(vec0->coeffs, 0, ctr[0], 0, MLDSA_Q)) + invariant(array_bound(vec1->coeffs, 0, ctr[1], 0, MLDSA_Q)) + invariant(array_bound(vec2->coeffs, 0, ctr[2], 0, MLDSA_Q)) + invariant(array_bound(vec3->coeffs, 0, ctr[3], 0, MLDSA_Q))) + { + mld_xof128_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + mld_xof128_x4_release(&state); + + mld_assert_bound(vec0->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec1->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec2->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(vec3->coeffs, MLDSA_N, 0, MLDSA_Q); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); +} + +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0) & 0xFF); + r[5 * i + 1] = + (uint8_t)(((a->coeffs[4 * i + 0] >> 8) | (a->coeffs[4 * i + 1] << 2)) & + 0xFF); + r[5 * i + 2] = + (uint8_t)(((a->coeffs[4 * i + 1] >> 6) | (a->coeffs[4 * i + 2] << 4)) & + 0xFF); + r[5 * i + 3] = + (uint8_t)(((a->coeffs[4 * i + 2] >> 4) | (a->coeffs[4 * i + 3] << 6)) & + 0xFF); + r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, 0, 1 << 10))) + { + r->coeffs[4 * i + 0] = + ((a[5 * i + 0] >> 0) | ((int32_t)a[5 * i + 1] << 8)) & 0x3FF; + r->coeffs[4 * i + 1] = + ((a[5 * i + 1] >> 2) | ((int32_t)a[5 * i + 2] << 6)) & 0x3FF; + r->coeffs[4 * i + 2] = + ((a[5 * i + 2] >> 4) | ((int32_t)a[5 * i + 3] << 4)) & 0x3FF; + r->coeffs[4 * i + 3] = + ((a[5 * i + 3] >> 6) | ((int32_t)a[5 * i + 4] << 2)) & 0x3FF; + } + + mld_assert_bound(r->coeffs, MLDSA_N, 0, 1 << 10); +} + +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[8]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* Safety: a->coeffs[i] <= (1 << (MLDSA_D - 1) as they are output of + * power2round, hence, these casts are safe. */ + t[0] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 0]); + t[1] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 1]); + t[2] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 2]); + t[3] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 3]); + t[4] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 4]); + t[5] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 5]); + t[6] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 6]); + t[7] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 7]); + + r[13 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[13 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[13 * i + 1] |= (uint8_t)((t[1] << 5) & 0xFF); + r[13 * i + 2] = (uint8_t)((t[1] >> 3) & 0xFF); + r[13 * i + 3] = (uint8_t)((t[1] >> 11) & 0xFF); + r[13 * i + 3] |= (uint8_t)((t[2] << 2) & 0xFF); + r[13 * i + 4] = (uint8_t)((t[2] >> 6) & 0xFF); + r[13 * i + 4] |= (uint8_t)((t[3] << 7) & 0xFF); + r[13 * i + 5] = (uint8_t)((t[3] >> 1) & 0xFF); + r[13 * i + 6] = (uint8_t)((t[3] >> 9) & 0xFF); + r[13 * i + 6] |= (uint8_t)((t[4] << 4) & 0xFF); + r[13 * i + 7] = (uint8_t)((t[4] >> 4) & 0xFF); + r[13 * i + 8] = (uint8_t)((t[4] >> 12) & 0xFF); + r[13 * i + 8] |= (uint8_t)((t[5] << 1) & 0xFF); + r[13 * i + 9] = (uint8_t)((t[5] >> 7) & 0xFF); + r[13 * i + 9] |= (uint8_t)((t[6] << 6) & 0xFF); + r[13 * i + 10] = (uint8_t)((t[6] >> 2) & 0xFF); + r[13 * i + 11] = (uint8_t)((t[6] >> 10) & 0xFF); + r[13 * i + 11] |= (uint8_t)((t[7] << 3) & 0xFF); + r[13 * i + 12] = (uint8_t)((t[7] >> 5) & 0xFF); + } +} + +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + { + r->coeffs[8 * i + 0] = a[13 * i + 0]; + r->coeffs[8 * i + 0] |= (int32_t)a[13 * i + 1] << 8; + r->coeffs[8 * i + 0] &= 0x1FFF; + + r->coeffs[8 * i + 1] = a[13 * i + 1] >> 5; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 2] << 3; + r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 3] << 11; + r->coeffs[8 * i + 1] &= 0x1FFF; + + r->coeffs[8 * i + 2] = a[13 * i + 3] >> 2; + r->coeffs[8 * i + 2] |= (int32_t)a[13 * i + 4] << 6; + r->coeffs[8 * i + 2] &= 0x1FFF; + + r->coeffs[8 * i + 3] = a[13 * i + 4] >> 7; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 5] << 1; + r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 6] << 9; + r->coeffs[8 * i + 3] &= 0x1FFF; + + r->coeffs[8 * i + 4] = a[13 * i + 6] >> 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 7] << 4; + r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 8] << 12; + r->coeffs[8 * i + 4] &= 0x1FFF; + + r->coeffs[8 * i + 5] = a[13 * i + 8] >> 1; + r->coeffs[8 * i + 5] |= (int32_t)a[13 * i + 9] << 7; + r->coeffs[8 * i + 5] &= 0x1FFF; + + r->coeffs[8 * i + 6] = a[13 * i + 9] >> 6; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 10] << 2; + r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 11] << 10; + r->coeffs[8 * i + 6] &= 0x1FFF; + + r->coeffs[8 * i + 7] = a[13 * i + 11] >> 3; + r->coeffs[8 * i + 7] |= (int32_t)a[13 * i + 12] << 5; + r->coeffs[8 * i + 7] &= 0x1FFF; + + r->coeffs[8 * i + 0] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 7]; + } + + mld_assert_bound(r->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +MLD_STATIC_TESTABLE uint32_t mld_poly_chknorm_c(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == array_abs_bound(a->coeffs, 0, i, B)) + ) + { + /* + * Since we know that -MLD_REDUCE32_RANGE_MAX <= a < MLD_REDUCE32_RANGE_MAX, + * and B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX, to check if + * -B < (a mod± MLDSA_Q) < B, it suffices to check if -B < a < B. + * + * We prove this to be true using the following CBMC assertions. + * a ==> b expressed as !a || b to also allow run-time assertion. + */ + mld_assert(a->coeffs[i] < B || a->coeffs[i] - MLDSA_Q <= -B); + mld_assert(a->coeffs[i] > -B || a->coeffs[i] + MLDSA_Q >= B); + + /* Reference: Leaks which coefficient violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + + /* if (abs(a[i]) >= B) */ + t |= mld_ct_cmask_neg_i32(B - 1 - mld_ct_abs_i32(a->coeffs[i])); + } + + return t; +} + +/* Reference: explicitly checks the bound B to be <= (MLDSA_Q - 1) / 8). + * This is unnecessary as it's always a compile-time constant. + * We instead model it as a precondition. + * Checking the bound is performed using a conditional arguing + * that it is okay to leak which coefficient violates the bound (while the + * coefficient itself must remain secret). + * We instead perform everything in constant-time. + * Also it is sufficient to check that it is smaller than + * MLDSA_Q - MLD_REDUCE32_RANGE_MAX > (MLDSA_Q - 1) / 8). + */ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +{ +#if defined(MLD_USE_NATIVE_POLY_CHKNORM) + int ret; + int success; + mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + /* The native backend returns 0 if all coefficients are within the bound, + * 1 if at least one coefficient exceeds the bound, and + * -1 (MLD_NATIVE_FUNC_FALLBACK) if the platform does not have the + * required capabilities to run the native function. + */ + ret = mld_poly_chknorm_native(a->coeffs, B); + + success = (ret != MLD_NATIVE_FUNC_FALLBACK); + /* Constant-time: It would be fine to leak the return value of chknorm + * entirely (as it is fine to leak if any coefficient exceeded the bound or + * not). However, it is cleaner to perform declassification in sign.c. + * Hence, here we only declassify if the native function returned + * MLD_NATIVE_FUNC_FALLBACK or not (which solely depends on system + * capabilities). + */ + MLD_CT_TESTING_DECLASSIFY(&success, sizeof(int)); + if (success) + { + /* Convert 0 / 1 to 0 / 0xFFFFFFFF here */ + return 0U - (uint32_t)ret; + } +#endif /* MLD_USE_NATIVE_POLY_CHKNORM */ + return mld_poly_chknorm_c(a, B); +} + +#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */ +MLD_EMPTY_CU(mld_poly) +#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef MLD_POLY_UNIFORM_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/poly.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/poly.h new file mode 100644 index 0000000000..ff7710438e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/poly.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_H +#define MLD_POLY_H + +#include +#include "cbmc.h" +#include "common.h" +#include "reduce.h" +#include "rounding.h" + +/* Absolute exclusive upper bound for the output of the forward NTT */ +#define MLD_NTT_BOUND (9 * MLDSA_Q) +/* Absolute exclusive upper bound for the output of the inverse NTT*/ +#define MLD_INTT_BOUND MLDSA_Q + +typedef struct +{ + int32_t coeffs[MLDSA_N]; +} MLD_ALIGN mld_poly; + +#define mld_poly_reduce MLD_NAMESPACE(poly_reduce) +/************************************************* + * Name: mld_poly_reduce + * + * Description: Inplace reduction of all coefficients of polynomial to + * representative in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_reduce(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) +); + +#define mld_poly_caddq MLD_NAMESPACE(poly_caddq) +/************************************************* + * Name: mld_poly_caddq + * + * Description: For all coefficients of in/out polynomial add MLDSA_Q if + * coefficient is negative. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_caddq(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_add MLD_NAMESPACE(poly_add) +/************************************************* + * Name: mld_poly_add + * + * Description: Add polynomials. No modular reduction is performed. + * + * Arguments: - r: Pointer to input-output polynomial to be added to. + * - b: Pointer to input polynomial that should be added + * to r. Must be disjoint from r. + **************************************************/ + +/* + * NOTE: The reference implementation uses a 3-argument poly_add. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_add(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(forall(k0, 0, MLDSA_N, (int64_t) r->coeffs[k0] + b->coeffs[k0] < MLD_REDUCE32_DOMAIN_MAX)) + requires(forall(k1, 0, MLDSA_N, (int64_t) r->coeffs[k1] + b->coeffs[k1] >= INT32_MIN)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(forall(k2, 0, MLDSA_N, r->coeffs[k2] == old(*r).coeffs[k2] + b->coeffs[k2])) + ensures(forall(k3, 0, MLDSA_N, r->coeffs[k3] < MLD_REDUCE32_DOMAIN_MAX)) + ensures(forall(k4, 0, MLDSA_N, r->coeffs[k4] >= INT32_MIN)) +); + +#define mld_poly_sub MLD_NAMESPACE(poly_sub) +/************************************************* + * Name: mld_poly_sub + * + * Description: Subtract polynomials. No modular reduction is + * performed. + * + * Arguments: - mld_poly *r: Pointer to input-output polynomial. + * - const mld_poly *b: Pointer to input polynomial that should be + * subtracted from r. Must be disjoint from r. + **************************************************/ +/* + * NOTE: The reference implementation uses a 3-argument poly_sub. + * We specialize to the accumulator form to avoid reasoning about aliasing. + */ +MLD_INTERNAL_API +void mld_poly_sub(mld_poly *r, const mld_poly *b) +__contract__( + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_Q)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)) +); + +#define mld_poly_shiftl MLD_NAMESPACE(poly_shiftl) +/************************************************* + * Name: mld_poly_shiftl + * + * Description: Multiply polynomial by 2^MLDSA_D without modular reduction. + *Assumes input coefficients to be less than 2^{31-MLDSA_D} in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_shiftl(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#define mld_poly_ntt MLD_NAMESPACE(poly_ntt) +/************************************************* + * Name: mld_poly_ntt + * + * Description: Inplace forward NTT. Coefficients can grow by + * 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_ntt(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) +); + + +#define mld_poly_invntt_tomont MLD_NAMESPACE(poly_invntt_tomont) +/************************************************* + * Name: mld_poly_invntt_tomont + * + * Description: Inplace inverse NTT and multiplication by 2^{32}. + * Input coefficients need to be less than MLDSA_Q in absolute + * value and output coefficients are bounded by + * MLD_INTT_BOUND. + * + * Arguments: - mld_poly *a: pointer to input/output polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_invntt_tomont(mld_poly *a) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND)) +); + +#define mld_poly_pointwise_montgomery MLD_NAMESPACE(poly_pointwise_montgomery) +/************************************************* + * Name: mld_poly_pointwise_montgomery + * + * Description: Pointwise multiplication of polynomials in NTT domain + * representation and multiplication of resulting polynomial + * by 2^{-32}. + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const mld_poly *a: pointer to first input polynomial + * - const mld_poly *b: pointer to second input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a, + const mld_poly *b) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + assigns(memory_slice(c, sizeof(mld_poly))) + ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + +#define mld_poly_power2round MLD_NAMESPACE(poly_power2round) +/************************************************* + * Name: mld_poly_power2round + * + * Description: For all coefficients c of the input polynomial, + * compute c0, c1 such that c mod MLDSA_Q = c1*2^MLDSA_D + c0 + * with -2^{MLDSA_D-1} < c0 <= 2^{MLDSA_D-1}. Assumes coefficients + *to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + *c1 + * - mld_poly *a0: pointer to output polynomial with coefficients + *c0 + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a) +__contract__( + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a0->coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)) +); + +#define mld_poly_uniform MLD_NAMESPACE(poly_uniform) +/************************************************* + * Name: mld_poly_uniform + * + * Description: Sample polynomial with uniformly random coefficients + * in [0,MLDSA_Q-1] by performing rejection sampling on the + * output stream of SHAKE128(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_SEEDBYTES and the packed 2-byte nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2]) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES + 2)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM) +#define mld_poly_uniform_4x MLD_NAMESPACE(poly_uniform_4x) +/************************************************* + * Name: mld_poly_uniform_x4 + * + * Description: Generate four polynomials using rejection sampling + * on (pseudo-)uniformly random bytes sampled from a seed. + * + * Arguments: - mld_poly *vec0, *vec1, *vec2, *vec3: + * Pointers to 4 polynomials to be sampled. + * - uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]: + * Pointer consecutive array of seed buffers of size + * MLDSA_SEEDBYTES + 2 each, plus padding for alignment. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2, + mld_poly *vec3, + uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]) +__contract__( + requires(memory_no_alias(vec0, sizeof(mld_poly))) + requires(memory_no_alias(vec1, sizeof(mld_poly))) + requires(memory_no_alias(vec2, sizeof(mld_poly))) + requires(memory_no_alias(vec3, sizeof(mld_poly))) + requires(memory_no_alias(seed, 4 * MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2))) + assigns(memory_slice(vec0, sizeof(mld_poly))) + assigns(memory_slice(vec1, sizeof(mld_poly))) + assigns(memory_slice(vec2, sizeof(mld_poly))) + assigns(memory_slice(vec3, sizeof(mld_poly))) + ensures(array_bound(vec0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec1->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec2->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + ensures(array_bound(vec3->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */ + +#define mld_polyt1_pack MLD_NAMESPACE(polyt1_pack) +/************************************************* + * Name: mld_polyt1_pack + * + * Description: Bit-pack polynomial t1 with coefficients fitting in 10 bits. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10)) + assigns(memory_slice(r, MLDSA_POLYT1_PACKEDBYTES)) +); + +#define mld_polyt1_unpack MLD_NAMESPACE(polyt1_unpack) +/************************************************* + * Name: mld_polyt1_unpack + * + * Description: Unpack polynomial t1 with 10-bit coefficients. + * Output coefficients are standard representatives. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT1_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, 0, 1 << 10)) +); + +#define mld_polyt0_pack MLD_NAMESPACE(polyt0_pack) +/************************************************* + * Name: mld_polyt0_pack + * + * Description: Bit-pack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + * 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) + assigns(memory_slice(r, MLDSA_POLYT0_PACKEDBYTES)) +); + + +#define mld_polyt0_unpack MLD_NAMESPACE(polyt0_unpack) +/************************************************* + * Name: mld_polyt0_unpack + * + * Description: Unpack polynomial t0 with coefficients in ]-2^{MLDSA_D-1}, + *2^{MLDSA_D-1}]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYT0_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)) +); + +#define mld_poly_chknorm MLD_NAMESPACE(poly_chknorm) +/************************************************* + * Name: mld_poly_chknorm + * + * Description: Check infinity norm of polynomial against given bound. + * Assumes input coefficients were reduced by mld_reduce32(). + * + * Arguments: - const mld_poly *a: pointer to polynomial + * - int32_t B: norm bound + * + * Returns 0 if norm is strictly smaller than + * B <= (MLDSA_Q - MLD_REDUCE32_RANGE_MAX) and 0xFFFFFFFF otherwise. + * + * Specification: The definition of this FIPS-204 requires signed canonical + * reduction prior to applying the bounds check. + * However, `-B < (a mod± MLDSA_Q) < B` is equivalent to + * `-B < a < B` under the assumption that + * `B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX` (cf. the assertion in + * the code). Hence, the present spec and implementation are + * correct without reduction. + * + **************************************************/ +MLD_INTERNAL_API +uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX) + requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B)) +); + +#endif /* !MLD_POLY_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/poly_kl.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/poly_kl.c new file mode 100644 index 0000000000..7a319ca515 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/poly_kl.c @@ -0,0 +1,931 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [REF] + * CRYSTALS-Dilithium reference implementation + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://github.com/pq-crystals/dilithium/tree/master/ref + */ + +#include +#include + +#include "ct.h" +#include "debug.h" +#include "poly_kl.h" +#include "rounding.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_rej_eta MLD_ADD_PARAM_SET(mld_rej_eta) +#define mld_rej_eta_c MLD_ADD_PARAM_SET(mld_rej_eta_c) +#define mld_poly_decompose_c MLD_ADD_PARAM_SET(mld_poly_decompose_c) +#define mld_poly_use_hint_c MLD_ADD_PARAM_SET(mld_poly_use_hint_c) +#define mld_polyz_unpack_c MLD_ADD_PARAM_SET(mld_polyz_unpack_c) +/* End of parameter set namespacing */ + + +MLD_STATIC_TESTABLE +void mld_poly_decompose_c(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +) +{ + unsigned int i; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + for (i = 0; i < MLDSA_N; ++i) + __loop__( + assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_bound(a0->coeffs, i, MLDSA_N, 0, MLDSA_Q)) + invariant(array_bound(a1->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + invariant(array_abs_bound(a0->coeffs, 0, i, MLDSA_GAMMA2+1)) + ) + { + mld_decompose(&a0->coeffs[i], &a1->coeffs[i], a0->coeffs[i]); + } + + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +{ +#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_88_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q); + ret = mld_poly_decompose_32_native(a1->coeffs, a0->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1); + mld_assert_bound(a1->coeffs, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_DECOMPOSE_88 && MLD_CONFIG_PARAMETER_SET == \ + 44) && MLD_USE_NATIVE_POLY_DECOMPOSE_32 && (MLD_CONFIG_PARAMETER_SET \ + == 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_decompose_c(a1, a0); +} + +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(s <= i) + invariant(array_bound(h->coeffs, 0, i, 0, 2)) + ) + { + const unsigned int hint_bit = mld_make_hint(a0->coeffs[i], a1->coeffs[i]); + h->coeffs[i] = (int32_t)hint_bit; + s += hint_bit; + } + + mld_assert(s <= MLDSA_N); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + return s; +} + +MLD_STATIC_TESTABLE void mld_poly_use_hint_c(mld_poly *b, const mld_poly *a, + const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +) +{ + unsigned int i; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_N; ++i) + __loop__( + invariant(i <= MLDSA_N) + invariant(array_bound(b->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ) + { + b->coeffs[i] = mld_use_hint(a->coeffs[i], h->coeffs[i]); + } + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +{ +#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_88_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#elif defined(MLD_USE_NATIVE_POLY_USE_HINT_32) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound(h->coeffs, MLDSA_N, 0, 2); + ret = mld_poly_use_hint_32_native(b->coeffs, a->coeffs, h->coeffs); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + return; + } +#endif /* !(MLD_USE_NATIVE_POLY_USE_HINT_88 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLY_USE_HINT_32 && (MLD_CONFIG_PARAMETER_SET == \ + 65 || MLD_CONFIG_PARAMETER_SET == 87) */ + mld_poly_use_hint_c(b, a, h); +} + +/************************************************* + * Name: mld_rej_eta + * + * Description: Sample uniformly random coefficients in [-MLDSA_ETA, MLDSA_ETA] + *by performing rejection sampling on array of random bytes. + * + * Arguments: - int32_t *a: pointer to output array (allocated) + * - unsigned int target: requested number of coefficients to + *sample + * - unsigned int offset: number of coefficients already sampled + * - const uint8_t *buf: array of random bytes to sample from + * - unsigned int buflen: length of array of random bytes + * + * Returns number of sampled coefficients. Can be smaller than target if not + *enough random bytes were given. + **************************************************/ + +/* Reference: `mld_rej_eta()` in the reference implementation @[REF]. + * - Our signature differs from the reference implementation + * in that it adds the offset and always expects the base of the + * target buffer. This avoids shifting the buffer base in the + * caller, which appears tricky to reason about. */ +#if MLDSA_ETA == 2 +/* + * Sampling 256 coefficients mod 15 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes. + * We sample 1 block (=136 bytes) of SHAKE256_RATE output initially. + * Sampling 2 blocks initially results in slightly worse performance. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 1 +#elif MLDSA_ETA == 4 +/* + * Sampling 256 coefficients mod 9 using rejection sampling from 4 bits. + * Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes. + * We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially. + */ +#define MLD_POLY_UNIFORM_ETA_NBLOCKS 2 +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + +MLD_STATIC_TESTABLE unsigned int mld_rej_eta_c(int32_t *a, unsigned int target, + unsigned int offset, + const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ + unsigned int ctr, pos; + int t_valid; + uint32_t t0, t1; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + ctr = offset; + pos = 0; + while (ctr < target && pos < buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(array_abs_bound(a, 0, ctr, MLDSA_ETA + 1)) + ) + { + t0 = buf[pos] & 0x0F; + t1 = buf[pos++] >> 4; + + /* Constant time: The inputs and outputs to the rejection sampling are + * secret. However, it is fine to leak which coefficients have been + * rejected. For constant-time testing, we declassify the result of + * the comparison. + */ +#if MLDSA_ETA == 2 + t_valid = t0 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 15 */ + { + t0 = t0 - (205 * t0 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t0; + } + t_valid = t1 < 15; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) /* t1 < 15 */ + { + t1 = t1 - (205 * t1 >> 10) * 5; + a[ctr++] = 2 - (int32_t)t1; + } +#elif MLDSA_ETA == 4 + t_valid = t0 < 9; + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid) /* t0 < 9 */ + { + a[ctr++] = 4 - (int32_t)t0; + } + t_valid = t1 < 9; /* t1 < 9 */ + MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int)); + if (t_valid && ctr < target) + { + a[ctr++] = 4 - (int32_t)t1; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + } + + mld_assert_abs_bound(a, ctr, MLDSA_ETA + 1); + + return ctr; +} + +static unsigned int mld_rej_eta(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen) +__contract__( + requires(offset <= target && target <= MLDSA_N) + requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES)) + requires(memory_no_alias(a, sizeof(int32_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1)) + assigns(memory_slice(a, sizeof(int32_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1)) +) +{ +#if MLDSA_ETA == 2 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta2_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#elif MLDSA_ETA == 4 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4) + int ret; + mld_assert_abs_bound(a, offset, MLDSA_ETA + 1); + if (offset == 0) + { + ret = mld_rej_uniform_eta4_native(a, target, buf, buflen); + if (ret != MLD_NATIVE_FUNC_FALLBACK) + { + unsigned res = (unsigned)ret; + mld_assert_abs_bound(a, res, MLDSA_ETA + 1); + return res; + } + } +#endif /* !(MLDSA_ETA == 2 && MLD_USE_NATIVE_REJ_UNIFORM_ETA2) && MLDSA_ETA == \ + 4 && MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */ + + return mld_rej_eta_c(a, target, offset, buf, buflen); +} + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_ETA_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr[4]; + mld_xof256_x4_ctx state; + unsigned buflen; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = nonce0; + extseed[1][MLDSA_CRHBYTES] = nonce1; + extseed[2][MLDSA_CRHBYTES] = nonce2; + extseed[3][MLDSA_CRHBYTES] = nonce3; + extseed[0][MLDSA_CRHBYTES + 1] = 0; + extseed[1][MLDSA_CRHBYTES + 1] = 0; + extseed[2][MLDSA_CRHBYTES + 1] = 0; + extseed[3][MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, 0, buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, 0, buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, 0, buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, 0, buf[3], buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N || + ctr[3] < MLDSA_N) + __loop__( + assigns(ctr, state, memory_slice(r0, sizeof(mld_poly)), + memory_slice(r1, sizeof(mld_poly)), memory_slice(r2, sizeof(mld_poly)), + memory_slice(r3, sizeof(mld_poly)), object_whole(buf[0]), + object_whole(buf[1]), object_whole(buf[2]), + object_whole(buf[3])) + invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N) + invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N) + invariant(array_abs_bound(r0->coeffs, 0, ctr[0], MLDSA_ETA + 1)) + invariant(array_abs_bound(r1->coeffs, 0, ctr[1], MLDSA_ETA + 1)) + invariant(array_abs_bound(r2->coeffs, 0, ctr[2], MLDSA_ETA + 1)) + invariant(array_abs_bound(r3->coeffs, 0, ctr[3], MLDSA_ETA + 1))) + { + mld_xof256_x4_squeezeblocks(buf, 1, &state); + ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, ctr[0], buf[0], buflen); + ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, ctr[1], buf[1], buflen); + ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, ctr[2], buf[2], buflen); + ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, ctr[3], buf[3], buflen); + } + + mld_xof256_x4_release(&state); + + mld_assert_abs_bound(r0->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r1->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r2->coeffs, MLDSA_N, MLDSA_ETA + 1); + mld_assert_abs_bound(r3->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +{ + /* Temporary buffer for XOF output before rejection sampling */ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + + /* Tracks the number of coefficients we have already sampled */ + unsigned ctr; + mld_xof256_ctx state; + unsigned buflen; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = nonce; + extseed[MLDSA_CRHBYTES + 1] = 0; + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + /* + * Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS. + * This should generate the coefficients with high probability. + */ + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state); + buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES; + + ctr = mld_rej_eta(r->coeffs, MLDSA_N, 0, buf, buflen); + + /* + * So long as not all entries have been generated, squeeze + * one more block at a time until we're done. + */ + buflen = MLD_STREAM256_BLOCKBYTES; + while (ctr < MLDSA_N) + __loop__( + assigns(ctr, object_whole(&state), + object_whole(buf), memory_slice(r, sizeof(mld_poly))) + invariant(ctr <= MLDSA_N) + invariant(state.pos <= SHAKE256_RATE) + invariant(array_abs_bound(r->coeffs, 0, ctr, MLDSA_ETA + 1))) + { + mld_xof256_squeezeblocks(buf, 1, &state); + ctr = mld_rej_eta(r->coeffs, MLDSA_N, ctr, buf, buflen); + } + + mld_xof256_release(&state); + + mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_ETA + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define MLD_POLY_UNIFORM_GAMMA1_NBLOCKS \ + ((MLDSA_POLYZ_PACKEDBYTES + MLD_STREAM256_BLOCKBYTES - 1) / \ + MLD_STREAM256_BLOCKBYTES) + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ + MLD_ALIGN uint8_t + buf[MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * MLD_STREAM256_BLOCKBYTES]; + MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2]; + mld_xof256_ctx state; + + mld_memcpy(extseed, seed, MLDSA_CRHBYTES); + extseed[MLDSA_CRHBYTES] = (uint8_t)(nonce & 0xFF); + extseed[MLDSA_CRHBYTES + 1] = (uint8_t)(nonce >> 8); + + mld_xof256_init(&state); + mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2); + + mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + mld_polyz_unpack(a, buf); + + mld_xof256_release(&state); + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +{ + /* Temporary buffers for XOF output before rejection sampling */ + MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * + MLD_STREAM256_BLOCKBYTES)]; + + MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)]; + + /* Tracks the number of coefficients we have already sampled */ + mld_xof256_x4_ctx state; + + mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES); + mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES); + extseed[0][MLDSA_CRHBYTES] = (uint8_t)(nonce0 & 0xFF); + extseed[1][MLDSA_CRHBYTES] = (uint8_t)(nonce1 & 0xFF); + extseed[2][MLDSA_CRHBYTES] = (uint8_t)(nonce2 & 0xFF); + extseed[3][MLDSA_CRHBYTES] = (uint8_t)(nonce3 & 0xFF); + extseed[0][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce0 >> 8); + extseed[1][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce1 >> 8); + extseed[2][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce2 >> 8); + extseed[3][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce3 >> 8); + + mld_xof256_x4_init(&state); + mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2); + mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state); + + mld_polyz_unpack(r0, buf[0]); + mld_polyz_unpack(r1, buf[1]); + mld_polyz_unpack(r2, buf[2]); + mld_polyz_unpack(r3, buf[3]); + mld_xof256_x4_release(&state); + + mld_assert_bound(r0->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r1->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r2->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + mld_assert_bound(r3->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(extseed, sizeof(extseed)); +} +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +{ + unsigned int i, j, pos; + uint64_t signs; + uint64_t offset; + MLD_ALIGN uint8_t buf[SHAKE256_RATE]; + mld_shake256ctx state; + + mld_shake256_init(&state); + mld_shake256_absorb(&state, seed, MLDSA_CTILDEBYTES); + mld_shake256_finalize(&state); + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + + /* Convert the first 8 bytes of buf[] into an unsigned 64-bit value. */ + /* Each bit of that dictates the sign of the resulting challenge value */ + signs = 0; + for (i = 0; i < 8; ++i) + __loop__( + assigns(i, signs) + invariant(i <= 8) + ) + { + signs |= (uint64_t)buf[i] << 8 * i; + } + pos = 8; + + mld_memset(c, 0, sizeof(mld_poly)); + + for (i = MLDSA_N - MLDSA_TAU; i < MLDSA_N; ++i) + __loop__( + assigns(i, j, object_whole(buf), state, pos, memory_slice(c, sizeof(mld_poly)), signs) + invariant(i >= MLDSA_N - MLDSA_TAU) + invariant(i <= MLDSA_N) + invariant(pos >= 1) + invariant(pos <= SHAKE256_RATE) + invariant(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) + invariant(state.pos <= SHAKE256_RATE) + ) + { + do + __loop__( + assigns(j, object_whole(buf), state, pos) + invariant(state.pos <= SHAKE256_RATE) + ) + { + if (pos >= SHAKE256_RATE) + { + mld_shake256_squeeze(buf, SHAKE256_RATE, &state); + pos = 0; + } + j = buf[pos++]; + } while (j > i); + + c->coeffs[i] = c->coeffs[j]; + + /* Reference: Compute coefficent value here in two steps to */ + /* mixinf unsigned and signed arithmetic with implicit */ + /* conversions, and so that CBMC can keep track of ranges */ + /* to complete type-safety proof here. */ + + /* The least-significant bit of signs tells us if we want -1 or +1 */ + offset = 2 * (signs & 1); + + /* offset has value 0 or 2 here, so (1 - (int32_t) offset) has + * value -1 or +1 */ + c->coeffs[j] = 1 - (int32_t)offset; + + /* Move to the next bit of signs for next time */ + signs >>= 1; + } + + mld_assert_bound(c->coeffs, MLDSA_N, -1, 2); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(buf, sizeof(buf)); + mld_zeroize(&signs, sizeof(signs)); +} + +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint8_t t[8]; + + mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_ETA + 1); + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 1]); + t[2] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 2]); + t[3] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 3]); + t[4] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 4]); + t[5] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 5]); + t[6] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 6]); + t[7] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 7]); + + r[3 * i + 0] = (uint8_t)(((t[0] >> 0) | (t[1] << 3) | (t[2] << 6)) & 0xFF); + r[3 * i + 1] = + (uint8_t)(((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)) & + 0xFF); + r[3 * i + 2] = (uint8_t)(((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)) & 0xFF); + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* The casts are safe since we assume that the coefficients + * of a are <= MLDSA_ETA in absolute value. */ + t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 0]); + t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 1]); + r[i] = (uint8_t)(t[0] | (t[1] << 4)); + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ +} + +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + +#if MLDSA_ETA == 2 + for (i = 0; i < MLDSA_N / 8; ++i) + __loop__( + invariant(i <= MLDSA_N/8) + invariant(array_bound(r->coeffs, 0, i*8, -5, MLDSA_ETA + 1))) + { + r->coeffs[8 * i + 0] = (a[3 * i + 0] >> 0) & 7; + r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 7; + r->coeffs[8 * i + 2] = ((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 7; + r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 7; + r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 7; + r->coeffs[8 * i + 5] = ((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 7; + r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 7; + r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5) & 7; + + r->coeffs[8 * i + 0] = MLDSA_ETA - r->coeffs[8 * i + 0]; + r->coeffs[8 * i + 1] = MLDSA_ETA - r->coeffs[8 * i + 1]; + r->coeffs[8 * i + 2] = MLDSA_ETA - r->coeffs[8 * i + 2]; + r->coeffs[8 * i + 3] = MLDSA_ETA - r->coeffs[8 * i + 3]; + r->coeffs[8 * i + 4] = MLDSA_ETA - r->coeffs[8 * i + 4]; + r->coeffs[8 * i + 5] = MLDSA_ETA - r->coeffs[8 * i + 5]; + r->coeffs[8 * i + 6] = MLDSA_ETA - r->coeffs[8 * i + 6]; + r->coeffs[8 * i + 7] = MLDSA_ETA - r->coeffs[8 * i + 7]; + } +#elif MLDSA_ETA == 4 + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -11, MLDSA_ETA + 1))) + { + r->coeffs[2 * i + 0] = a[i] & 0x0F; + r->coeffs[2 * i + 1] = a[i] >> 4; + r->coeffs[2 * i + 0] = MLDSA_ETA - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_ETA - r->coeffs[2 * i + 1]; + } +#else /* MLDSA_ETA == 4 */ +#error "Invalid value of MLDSA_ETA" +#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */ + + mld_assert_bound(r->coeffs, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + + +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + uint32_t t[4]; + + mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 1]); + t[2] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 2]); + t[3] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 3]); + + r[9 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[9 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[9 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[9 * i + 2] |= (uint8_t)((t[1] << 2) & 0xFF); + r[9 * i + 3] = (uint8_t)((t[1] >> 6) & 0xFF); + r[9 * i + 4] = (uint8_t)((t[1] >> 14) & 0xFF); + r[9 * i + 4] |= (uint8_t)((t[2] << 4) & 0xFF); + r[9 * i + 5] = (uint8_t)((t[2] >> 4) & 0xFF); + r[9 * i + 6] = (uint8_t)((t[2] >> 12) & 0xFF); + r[9 * i + 6] |= (uint8_t)((t[3] << 6) & 0xFF); + r[9 * i + 7] = (uint8_t)((t[3] >> 2) & 0xFF); + r[9 * i + 8] = (uint8_t)((t[3] >> 10) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + /* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */ + t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 0]); + t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 1]); + + r[5 * i + 0] = (uint8_t)((t[0]) & 0xFF); + r[5 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF); + r[5 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF); + r[5 * i + 2] |= (uint8_t)((t[1] << 4) & 0xFF); + r[5 * i + 3] = (uint8_t)((t[1] >> 4) & 0xFF); + r[5 * i + 4] = (uint8_t)((t[1] >> 12) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +MLD_STATIC_TESTABLE void mld_polyz_unpack_c( + mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +) +{ + unsigned int i; +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4) + invariant(array_bound(r->coeffs, 0, i*4, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[4 * i + 0] = a[9 * i + 0]; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8; + r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 2] << 16; + r->coeffs[4 * i + 0] &= 0x3FFFF; + + r->coeffs[4 * i + 1] = a[9 * i + 2] >> 2; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 3] << 6; + r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 4] << 14; + r->coeffs[4 * i + 1] &= 0x3FFFF; + + r->coeffs[4 * i + 2] = a[9 * i + 4] >> 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 5] << 4; + r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 6] << 12; + r->coeffs[4 * i + 2] &= 0x3FFFF; + + r->coeffs[4 * i + 3] = a[9 * i + 6] >> 6; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 7] << 2; + r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10; + r->coeffs[4 * i + 3] &= 0x3FFFF; + + r->coeffs[4 * i + 0] = MLDSA_GAMMA1 - r->coeffs[4 * i + 0]; + r->coeffs[4 * i + 1] = MLDSA_GAMMA1 - r->coeffs[4 * i + 1]; + r->coeffs[4 * i + 2] = MLDSA_GAMMA1 - r->coeffs[4 * i + 2]; + r->coeffs[4 * i + 3] = MLDSA_GAMMA1 - r->coeffs[4 * i + 3]; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2) + invariant(array_bound(r->coeffs, 0, i*2, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + { + r->coeffs[2 * i + 0] = a[5 * i + 0]; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8; + r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 2] << 16; + r->coeffs[2 * i + 0] &= 0xFFFFF; + + r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 3] << 4; + r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12; + /* r->coeffs[2*i+1] &= 0xFFFFF; */ /* No effect, since we're anyway at 20 + bits */ + + r->coeffs[2 * i + 0] = MLDSA_GAMMA1 - r->coeffs[2 * i + 0]; + r->coeffs[2 * i + 1] = MLDSA_GAMMA1 - r->coeffs[2 * i + 1]; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +{ +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) && MLD_CONFIG_PARAMETER_SET == 44 + int ret; + ret = mld_polyz_unpack_17_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#elif defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) && \ + (MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87) + int ret; + ret = mld_polyz_unpack_19_native(r->coeffs, a); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYZ_UNPACK_17 && MLD_CONFIG_PARAMETER_SET == 44) \ + && MLD_USE_NATIVE_POLYZ_UNPACK_19 && (MLD_CONFIG_PARAMETER_SET == 65 \ + || MLD_CONFIG_PARAMETER_SET == 87) */ + + mld_polyz_unpack_c(r, a); +} + +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +{ + unsigned int i; + + mld_assert_bound(a->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + +#if MLD_CONFIG_PARAMETER_SET == 44 + for (i = 0; i < MLDSA_N / 4; ++i) + __loop__( + invariant(i <= MLDSA_N/4)) + { + r[3 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0]) & 0xFF); + r[3 * i + 0] |= (uint8_t)((a->coeffs[4 * i + 1] << 6) & 0xFF); + r[3 * i + 1] = (uint8_t)((a->coeffs[4 * i + 1] >> 2) & 0xFF); + r[3 * i + 1] |= (uint8_t)((a->coeffs[4 * i + 2] << 4) & 0xFF); + r[3 * i + 2] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) & 0xFF); + r[3 * i + 2] |= (uint8_t)((a->coeffs[4 * i + 3] << 2) & 0xFF); + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + for (i = 0; i < MLDSA_N / 2; ++i) + __loop__( + invariant(i <= MLDSA_N/2)) + { + r[i] = + (uint8_t)((a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)) & 0xFF); + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. */ + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_rej_eta +#undef mld_rej_eta_c +#undef mld_poly_decompose_c +#undef mld_poly_use_hint_c +#undef mld_polyz_unpack_c +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_ETA_NBLOCKS +#undef MLD_POLY_UNIFORM_GAMMA1_NBLOCKS diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/poly_kl.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/poly_kl.h new file mode 100644 index 0000000000..c6aa498358 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/poly_kl.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLY_KL_H +#define MLD_POLY_KL_H + +#include "cbmc.h" +#include "common.h" +#include "poly.h" + +#define mld_poly_decompose MLD_NAMESPACE_KL(poly_decompose) +/************************************************* + * Name: mld_poly_decompose + * + * Description: For all coefficients c of the input polynomial, + * compute high and low bits c0, c1 such c mod MLDSA_Q = c1*ALPHA + + * c0 with -ALPHA/2 < c0 <= ALPHA/2 except + * c1 = (MLDSA_Q-1)/ALPHA where we set + * c1 = 0 and -ALPHA/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0. + * Assumes coefficients to be standard representatives. + * + * Arguments: - mld_poly *a1: pointer to output polynomial with coefficients + * c1 + * - mld_poly *a0: pointer to input/output polynomial. Output + * polynomial has coefficients c0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_poly_decompose(mld_poly *a1, mld_poly *a0) +__contract__( + requires(memory_no_alias(a1, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + assigns(memory_slice(a1, sizeof(mld_poly))) + assigns(memory_slice(a0, sizeof(mld_poly))) + ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)) +); + + +#define mld_poly_make_hint MLD_NAMESPACE_KL(poly_make_hint) +/************************************************* + * Name: mld_poly_make_hint + * + * Description: Compute hint polynomial. The coefficients of which indicate + * whether the low bits of the corresponding coefficient of + * the input polynomial overflow into the high bits. + * + * Arguments: - mld_poly *h: pointer to output hint polynomial + * - const mld_poly *a0: pointer to low part of input polynomial + * - const mld_poly *a1: pointer to high part of input polynomial + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0, + const mld_poly *a1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(memory_no_alias(a0, sizeof(mld_poly))) + requires(memory_no_alias(a1, sizeof(mld_poly))) + assigns(memory_slice(h, sizeof(mld_poly))) + ensures(return_value <= MLDSA_N) + ensures(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) +); + +#define mld_poly_use_hint MLD_NAMESPACE_KL(poly_use_hint) +/************************************************* + * Name: mld_poly_use_hint + * + * Description: Use hint polynomial to correct the high bits of a polynomial. + * + * Arguments: - mld_poly *b: pointer to output polynomial with corrected high + *bits + * - const mld_poly *a: pointer to input polynomial + * - const mld_poly *h: pointer to input hint polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(b, sizeof(mld_poly))) + requires(memory_no_alias(h, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q)) + requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2)) + assigns(memory_slice(b, sizeof(mld_poly))) + ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) +); + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta_4x MLD_NAMESPACE_KL(poly_uniform_eta_4x) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample four polynomials with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce_i) + * + * Arguments: - mld_poly *r0: pointer to first output polynomial + * - mld_poly *r1: pointer to second output polynomial + * - mld_poly *r2: pointer to third output polynomial + * - mld_poly *r3: pointer to fourth output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce0: first nonce + * - uint8_t nonce1: second nonce + * - uint8_t nonce2: third nonce + * - uint8_t nonce3: fourth nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, + uint8_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_abs_bound(r0->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r1->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r2->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + ensures(array_abs_bound(r3->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_eta MLD_NAMESPACE_KL(poly_uniform_eta) +/************************************************* + * Name: mld_poly_uniform_eta + * + * Description: Sample polynomial with uniformly random coefficients + * in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on + * the output stream from SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint8_t nonce: nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES], + uint8_t nonce) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) +); +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1 MLD_NAMESPACE_KL(poly_uniform_gamma1) +/************************************************* + * Name: mld_poly_uniform_gamma1 + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(a, sizeof(mld_poly))) + ensures(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#define mld_poly_uniform_gamma1_4x MLD_NAMESPACE_KL(poly_uniform_gamma1_4x) +/************************************************* + * Name: mld_poly_uniform_gamma1_4x + * + * Description: Sample polynomial with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_poly *a: pointer to output polynomial + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + **************************************************/ +MLD_INTERNAL_API +void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2, + mld_poly *r3, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce0, uint16_t nonce1, + uint16_t nonce2, uint16_t nonce3) +__contract__( + requires(memory_no_alias(r0, sizeof(mld_poly))) + requires(memory_no_alias(r1, sizeof(mld_poly))) + requires(memory_no_alias(r2, sizeof(mld_poly))) + requires(memory_no_alias(r3, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(memory_slice(r0, sizeof(mld_poly))) + assigns(memory_slice(r1, sizeof(mld_poly))) + assigns(memory_slice(r2, sizeof(mld_poly))) + assigns(memory_slice(r3, sizeof(mld_poly))) + ensures(array_bound(r0->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r1->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r2->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + ensures(array_bound(r3->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +#define mld_poly_challenge MLD_NAMESPACE_KL(poly_challenge) +/************************************************* + * Name: mld_poly_challenge + * + * Description: Implementation of H. Samples polynomial with MLDSA_TAU nonzero + * coefficients in {-1,1} using the output stream of + * SHAKE256(seed). + * + * Arguments: - mld_poly *c: pointer to output polynomial + * - const uint8_t mu[]: byte array containing seed of length + * MLDSA_CTILDEBYTES + **************************************************/ +MLD_INTERNAL_API +void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES]) +__contract__( + requires(memory_no_alias(c, sizeof(mld_poly))) + requires(memory_no_alias(seed, MLDSA_CTILDEBYTES)) + assigns(memory_slice(c, sizeof(mld_poly))) + /* All coefficients of c are -1, 0 or +1 */ + ensures(array_bound(c->coeffs, 0, MLDSA_N, -1, 2)) +); + +#define mld_polyeta_pack MLD_NAMESPACE_KL(polyeta_pack) +/************************************************* + * Name: mld_polyeta_pack + * + * Description: Bit-pack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYETA_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_ETA + 1)) + assigns(memory_slice(r, MLDSA_POLYETA_PACKEDBYTES)) +); + +/* + * polyeta_unpack produces coefficients in [-MLDSA_ETA,MLDSA_ETA] for + * well-formed inputs (i.e., those produced by polyeta_pack). + * However, when passed an arbitrary byte array, it may produce smaller values, + * i.e, values in [MLD_POLYETA_UNPACK_LOWER_BOUND,MLDSA_ETA] + * Even though this should never happen, we use use the bound for arbitrary + * inputs in the CBMC proofs. + */ +#if MLDSA_ETA == 2 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-5) +#elif MLDSA_ETA == 4 +#define MLD_POLYETA_UNPACK_LOWER_BOUND (-11) +#else +#error "Invalid value of MLDSA_ETA" +#endif + +#define mld_polyeta_unpack MLD_NAMESPACE_KL(polyeta_unpack) +/************************************************* + * Name: mld_polyeta_unpack + * + * Description: Unpack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYETA_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)) +); + +#define mld_polyz_pack MLD_NAMESPACE_KL(polyz_pack) +/************************************************* + * Name: mld_polyz_pack + * + * Description: Bit-pack polynomial with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYZ_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) + assigns(memory_slice(r, MLDSA_POLYZ_PACKEDBYTES)) +); + + +#define mld_polyz_unpack MLD_NAMESPACE_KL(polyz_unpack) +/************************************************* + * Name: mld_polyz_unpack + * + * Description: Unpack polynomial z with coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_poly *r: pointer to output polynomial + * - const uint8_t *a: byte array with bit-packed polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(mld_poly))) + requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES)) + assigns(memory_slice(r, sizeof(mld_poly))) + ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)) +); + +#define mld_polyw1_pack MLD_NAMESPACE_KL(polyw1_pack) +/************************************************* + * Name: mld_polyw1_pack + * + * Description: Bit-pack polynomial w1 with coefficients in [0,15] or [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_poly *a: pointer to input polynomial + **************************************************/ +MLD_INTERNAL_API +void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a) +__contract__( + requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))) + assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES)) +); + +#endif /* !MLD_POLY_KL_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/polyvec.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/polyvec.c new file mode 100644 index 0000000000..5c3a08ab32 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/polyvec.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#include +#include + +#include "common.h" +#include "debug.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" + +/* This namespacing is not done at the top to avoid a naming conflict + * with native backends, which are currently not yet namespaced. */ +#define mld_polymat_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polymat_permute_bitrev_to_custom) +#define mld_polyvecl_permute_bitrev_to_custom \ + MLD_ADD_PARAM_SET(mld_polyvecl_permute_bitrev_to_custom) +#define mld_polyvecl_pointwise_acc_montgomery_c \ + MLD_ADD_PARAM_SET(mld_polyvecl_pointwise_acc_montgomery_c) + +#if !defined(MLD_CONFIG_REDUCE_RAM) +/* Helper function to ensure that the polynomial entries in the output + * of mld_polyvec_matrix_expand use the standard (bitreversed) ordering + * of coefficients. + * No-op unless a native backend with a custom ordering is used. + */ + +static void mld_polyvecl_permute_bitrev_to_custom(mld_polyvecl *v) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +{ +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + unsigned i; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(x, 0, MLDSA_L, + array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_permute_bitrev_to_custom(v->vec[i].coeffs); + } +#else /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ + /* Nothing to do */ + (void)v; +#endif /* !MLD_USE_NATIVE_NTT_CUSTOM_ORDER */ +} + +static void mld_polymat_permute_bitrev_to_custom(mld_polymat *mat) +__contract__( + /* We don't specify that this should be a permutation, but only + * that it does not change the bound established at the end of + * mld_polyvec_matrix_expand. + */ + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; i++) + __loop__( + assigns(i, memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))) + { + mld_polyvecl_permute_bitrev_to_custom(&mat->vec[i]); + } +} +#endif /* !MLD_CONFIG_REDUCE_RAM */ + +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + unsigned int i; + MLD_ALIGN uint8_t seed_ext[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + mld_memcpy(seed_ext, mat->rho, MLDSA_SEEDBYTES); + + /* Generate row on-demand */ + for (i = 0; i < MLDSA_L; i++) + { + uint8_t x = (uint8_t)row; + uint8_t y = (uint8_t)i; + + seed_ext[MLDSA_SEEDBYTES + 0] = y; + seed_ext[MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(&mat->row_buffer.vec[i], seed_ext); + +#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER) + mld_poly_permute_bitrev_to_custom(mat->row_buffer.vec[i].coeffs); +#endif + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); + + return &mat->row_buffer; +#else /* MLD_CONFIG_REDUCE_RAM */ + return &mat->vec[row]; +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + /* In REDUCE_RAM mode, just copy the seed for later on-demand generation */ + mld_memcpy(mat->rho, rho, MLDSA_SEEDBYTES); +#else + unsigned int i, j; + /* + * We generate four separate seed arrays rather than a single one to work + * around limitations in CBMC function contracts dealing with disjoint slices + * of the same parent object. + */ + + MLD_ALIGN uint8_t seed_ext[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + mld_memcpy(seed_ext[j], rho, MLDSA_SEEDBYTES); + } + +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + /* Sample 4 matrix entries a time. */ + for (i = 0; i < (MLDSA_K * MLDSA_L / 4) * 4; i += 4) + __loop__( + assigns(i, j, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= (MLDSA_K * MLDSA_L / 4) * 4 && i % 4 == 0) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + for (j = 0; j < 4; j++) + __loop__( + assigns(j, object_whole(seed_ext)) + invariant(j <= 4) + ) + { + uint8_t x = (uint8_t)((i + j) / MLDSA_L); + uint8_t y = (uint8_t)((i + j) % MLDSA_L); + + seed_ext[j][MLDSA_SEEDBYTES + 0] = y; + seed_ext[j][MLDSA_SEEDBYTES + 1] = x; + } + + mld_poly_uniform_4x(&mat->vec[i / MLDSA_L].vec[i % MLDSA_L], + &mat->vec[(i + 1) / MLDSA_L].vec[(i + 1) % MLDSA_L], + &mat->vec[(i + 2) / MLDSA_L].vec[(i + 2) % MLDSA_L], + &mat->vec[(i + 3) / MLDSA_L].vec[(i + 3) % MLDSA_L], + seed_ext); + } +#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + i = 0; +#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + /* Entries omitted by the batch-sampling are sampled individually. */ + while (i < MLDSA_K * MLDSA_L) + __loop__( + assigns(i, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat))) + invariant(i <= MLDSA_K * MLDSA_L) + /* vectors 0 .. i / MLDSA_L are completely sampled */ + invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + /* last vector is sampled up to i % MLDSA_L */ + invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L, + array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + ) + { + uint8_t x = (uint8_t)(i / MLDSA_L); + uint8_t y = (uint8_t)(i % MLDSA_L); + mld_poly *this_poly = &mat->vec[i / MLDSA_L].vec[i % MLDSA_L]; + + seed_ext[0][MLDSA_SEEDBYTES + 0] = y; + seed_ext[0][MLDSA_SEEDBYTES + 1] = x; + + mld_poly_uniform(this_poly, seed_ext[0]); + i++; + } + + mld_polymat_permute_bitrev_to_custom(mat); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed_ext, sizeof(seed_ext)); +#endif /* !MLD_CONFIG_REDUCE_RAM */ +} + +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(t, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + const mld_polyvecl *row = mld_polymat_get_row(mat, i); + mld_polyvecl_pointwise_acc_montgomery(&t->vec[i], row, v); + } + + mld_assert_abs_bound_2d(t->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_L **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +{ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; +#endif + + /* Safety: nonce is at most ((UINT16_MAX - MLDSA_L) / MLDSA_L), and, hence, + * this cast is safe. See MLD_NONCE_UB comment in sign.c. */ + nonce = (uint16_t)(MLDSA_L * nonce); + /* Now, nonce <= UINT16_MAX - (MLDSA_L - 1), so the casts below are safe. */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_gamma1(&v->vec[i], seed, (uint16_t)(nonce + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLDSA_L == 4 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); +#elif MLDSA_L == 5 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3], + seed, nonce, (uint16_t)(nonce + 1), + (uint16_t)(nonce + 2), (uint16_t)(nonce + 3)); + mld_poly_uniform_gamma1(&v->vec[4], seed, (uint16_t)(nonce + 4)); +#elif MLDSA_L == 7 + mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], + &v->vec[3 /* irrelevant */], seed, nonce, + (uint16_t)(nonce + 1), (uint16_t)(nonce + 2), + 0xFF /* irrelevant */); + mld_poly_uniform_gamma1_4x(&v->vec[3], &v->vec[4], &v->vec[5], &v->vec[6], + seed, (uint16_t)(nonce + 3), (uint16_t)(nonce + 4), + (uint16_t)(nonce + 5), (uint16_t)(nonce + 6)); +#endif /* MLDSA_L == 7 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ + + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyvecl))) + invariant(i <= MLDSA_L) + invariant(forall(k0, i, MLDSA_L, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_STATIC_TESTABLE void mld_polyvecl_pointwise_acc_montgomery_c( + mld_poly *w, const mld_polyvecl *u, const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +) +{ + unsigned int i, j; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + for (i = 0; i < MLDSA_N; i++) + __loop__( + assigns(i, j, memory_slice(w, sizeof(mld_poly))) + invariant(i <= MLDSA_N) + invariant(array_abs_bound(w->coeffs, 0, i, MLDSA_Q)) + ) + { + int64_t t = 0; + int32_t r; + for (j = 0; j < MLDSA_L; j++) + __loop__( + assigns(j, t) + invariant(j <= MLDSA_L) + invariant(t >= -(int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + invariant(t <= (int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1)) + ) + { + t += (int64_t)u->vec[j].coeffs[i] * v->vec[j].coeffs[i]; + } + + r = mld_montgomery_reduce(t); + w->coeffs[i] = r; + } + + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +{ +#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) && \ + MLD_CONFIG_PARAMETER_SET == 44 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l4_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) && \ + MLD_CONFIG_PARAMETER_SET == 65 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l5_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) && \ + MLD_CONFIG_PARAMETER_SET == 87 + int ret; + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND); + ret = mld_polyvecl_pointwise_acc_montgomery_l7_native( + w->coeffs, (const int32_t(*)[MLDSA_N])u->vec, + (const int32_t(*)[MLDSA_N])v->vec); + if (ret == MLD_NATIVE_FUNC_SUCCESS) + { + mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q); + return; + } +#endif /* !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 && \ + MLD_CONFIG_PARAMETER_SET == 44) && \ + !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 && \ + MLD_CONFIG_PARAMETER_SET == 65) && \ + MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 && \ + MLD_CONFIG_PARAMETER_SET == 87 */ + /* The first input is bounded by [0, Q-1] inclusive + * The second input is bounded by [-9Q+1, 9Q-1] inclusive . Hence, we can + * safely accumulate in 64-bits without intermediate reductions as + * MLDSA_L * (MLD_NTT_BOUND-1) * (Q-1) < INT64_MAX + * + * The worst case is ML-DSA-87: 7 * (9Q-1) * (Q-1) < 2**52 + * (and likewise for negative values) + */ + mld_polyvecl_pointwise_acc_montgomery_c(w, u, v); +} + +MLD_INTERNAL_API +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_L; ++i) + __loop__( + invariant(i <= MLDSA_L) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + return t; +} + +/**************************************************************/ +/************ Vectors of polynomials of length MLDSA_K **************/ +/**************************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k2, 0, i, + array_bound(v->vec[k2].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ) + { + mld_poly_reduce(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + { + mld_poly_caddq(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +/* Reference: We use destructive version (output=first input) to avoid + * reasoning about aliasing in the CBMC specification */ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, + forall(k1, 0, MLDSA_N, u->vec[k0].coeffs[k1] == loop_entry(*u).vec[k0].coeffs[k1]))) + invariant(forall(k6, 0, i, array_bound(u->vec[k6].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + ) + { + mld_poly_add(&u->vec[i], &v->vec[i]); + } + mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(u->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(u, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, 0, i, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, u->vec[k1].coeffs[n1] == loop_entry(*u).vec[k1].coeffs[n1])))) + { + mld_poly_sub(&u->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, INT32_MIN, + MLD_REDUCE32_DOMAIN_MAX); +} + +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, 1 << 10); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + invariant(forall(k1, i, MLDSA_K, + forall(n1, 0, MLDSA_N, v->vec[k1].coeffs[n1] == loop_entry(*v).vec[k1].coeffs[n1]))) + ) + { + mld_poly_shiftl(&v->vec[i]); + } + + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); +} + +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))) + { + mld_poly_ntt(&v->vec[i]); + } + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1]))) + invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))) + { + mld_poly_invntt_tomont(&v->vec[i]); + } + + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_INTT_BOUND); +} + +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, array_abs_bound(r->vec[k2].coeffs, 0, MLDSA_N, MLDSA_Q))) + ) + { + mld_poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]); + } + mld_assert_abs_bound_2d(r->vec, MLDSA_K, MLDSA_N, MLDSA_Q); +} + +MLD_INTERNAL_API +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t bound) +{ + unsigned int i; + uint32_t t = 0; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, + MLD_REDUCE32_RANGE_MAX); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + invariant(i <= MLDSA_K) + invariant(t == 0 || t == 0xFFFFFFFF) + invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound))) + ) + { + /* Reference: Leaks which polynomial violates the bound via a conditional. + * We are more conservative to reduce the number of declassifications in + * constant-time testing. + */ + t |= mld_poly_chknorm(&v->vec[i], bound); + } + + return t; +} + +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +{ + unsigned int i; + mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + invariant(forall(k2, 0, i, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) + ) + { + mld_poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]); + } + + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, -(MLD_2_POW_D / 2) + 1, + (MLD_2_POW_D / 2) + 1); + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + ((MLDSA_Q - 1) / MLD_2_POW_D) + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +{ + unsigned int i; + mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k1, 0, i, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + invariant(forall(k2, 0, i, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) + invariant(forall(k3, i, MLDSA_K, + array_bound(v0->vec[k3].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + ) + { + mld_poly_decompose(&v1->vec[i], &v0->vec[i]); + } + + mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + mld_assert_abs_bound_2d(v0->vec, MLDSA_K, MLDSA_N, MLDSA_GAMMA2 + 1); +} + +MLD_INTERNAL_API +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +{ + unsigned int i, s = 0; + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, s, memory_slice(h, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(s <= i * MLDSA_N) + invariant(forall(k1, 0, i, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + ) + { + s += mld_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]); + } + + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + return s; +} + +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *u, + const mld_polyveck *h) +{ + unsigned int i; + mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q); + mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(w, sizeof(mld_polyveck))) + invariant(i <= MLDSA_K) + invariant(forall(k2, 0, i, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)))) + ) + { + mld_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]); + } + + mld_assert_bound_2d(w->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); +} + +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +{ + unsigned int i; + mld_assert_bound_2d(w1->vec, MLDSA_K, MLDSA_N, 0, + (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2)); + + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyw1_pack(&r[i * MLDSA_POLYW1_PACKEDBYTES], &w1->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +{ + unsigned int i; + mld_assert_abs_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLDSA_ETA + 1); + for (i = 0; i < MLDSA_L; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +{ + unsigned int i; + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); + for (i = 0; i < MLDSA_K; ++i) + __loop__( + assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + invariant(i <= MLDSA_K) + ) + { + mld_polyt0_pack(&r[i * MLDSA_POLYT0_PACKEDBYTES], &p->vec[i]); + } +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_L; ++i) + { + mld_polyz_unpack(&z->vec[i], r + i * MLDSA_POLYZ_PACKEDBYTES); + } + + mld_assert_bound_2d(z->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1), + MLDSA_GAMMA1 + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, + MLDSA_ETA + 1); +} + +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +{ + unsigned int i; + for (i = 0; i < MLDSA_K; ++i) + { + mld_polyt0_unpack(&p->vec[i], r + i * MLDSA_POLYT0_PACKEDBYTES); + } + + mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1, + (1 << (MLDSA_D - 1)) + 1); +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_polymat_permute_bitrev_to_custom +#undef mld_polyvecl_permute_bitrev_to_custom +#undef mld_polyvecl_pointwise_acc_montgomery_c diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/polyvec.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/polyvec.h new file mode 100644 index 0000000000..d21abc02ff --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/polyvec.h @@ -0,0 +1,725 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_POLYVEC_H +#define MLD_POLYVEC_H + +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "poly_kl.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_polyvecl MLD_ADD_PARAM_SET(mld_polyvecl) +#define mld_polyveck MLD_ADD_PARAM_SET(mld_polyveck) +#define mld_polymat MLD_ADD_PARAM_SET(mld_polymat) +/* End of parameter set namespacing */ + +/* Vectors of polynomials of length MLDSA_L */ +typedef struct +{ + mld_poly vec[MLDSA_L]; +} mld_polyvecl; + + +#define mld_polyvecl_uniform_gamma1 MLD_NAMESPACE_KL(polyvecl_uniform_gamma1) +/************************************************* + * Name: mld_polyvecl_uniform_gamma1 + * + * Description: Sample vector of polynomials with uniformly random coefficients + * in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output + * stream of SHAKE256(seed|nonce) + * + * Arguments: - mld_polyvecl *v: pointer to output vector + * - const uint8_t seed[]: byte array with seed of length + * MLDSA_CRHBYTES + * - uint16_t nonce: 16-bit nonce + *************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_uniform_gamma1(mld_polyvecl *v, + const uint8_t seed[MLDSA_CRHBYTES], + uint16_t nonce) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + requires(nonce <= (UINT16_MAX - MLDSA_L) / MLDSA_L) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyvecl_ntt MLD_NAMESPACE_KL(polyvecl_ntt) +/************************************************* + * Name: mld_polyvecl_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_L. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyvecl *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_ntt(mld_polyvecl *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k0, 0, MLDSA_L, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyvecl_pointwise_acc_montgomery \ + MLD_NAMESPACE_KL(polyvecl_pointwise_acc_montgomery) +/************************************************* + * Name: mld_polyvecl_pointwise_acc_montgomery + * + * Description: Pointwise multiply vectors of polynomials of length MLDSA_L, + * multiply resulting vector by 2^{-32} and add (accumulate) + * polynomials in it. + * Input/output vectors are in NTT domain representation. + * + * The first input "u" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * + * Arguments: - mld_poly *w: output polynomial + * - const mld_polyvecl *u: pointer to first input vector + * - const mld_polyvecl *v: pointer to second input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(w, sizeof(mld_poly))) + requires(memory_no_alias(u, sizeof(mld_polyvecl))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(l0, 0, MLDSA_L, + array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(w, sizeof(mld_poly))) + ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q)) +); + + +#define mld_polyvecl_chknorm MLD_NAMESPACE_KL(polyvecl_chknorm) +/************************************************* + * Name: mld_polyvecl_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_L. + * Assumes input mld_polyvecl to be reduced by polyvecl_reduce(). + * + * Arguments: - const mld_polyvecl *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials is strictly smaller than B <= + * (MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_L, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +/* Vectors of polynomials of length MLDSA_K */ +typedef struct +{ + mld_poly vec[MLDSA_K]; +} mld_polyveck; + +/* Matrix of polynomials (K x L) */ +typedef struct +{ +#if defined(MLD_CONFIG_REDUCE_RAM) + mld_polyvecl row_buffer; + uint8_t rho[MLDSA_SEEDBYTES]; +#else + mld_polyvecl vec[MLDSA_K]; +#endif +} mld_polymat; + +#define mld_polyveck_reduce MLD_NAMESPACE_KL(polyveck_reduce) +/************************************************* + * Name: polyveck_reduce + * + * Description: Reduce coefficients of polynomials in vector of length MLDSA_K + * to representatives in + *[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX]. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_reduce(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) +); + +#define mld_polyveck_caddq MLD_NAMESPACE_KL(polyveck_caddq) +/************************************************* + * Name: mld_polyveck_caddq + * + * Description: For all coefficients of polynomials in vector of length MLDSA_K + * add MLDSA_Q if coefficient is negative. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_caddq(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_add MLD_NAMESPACE_KL(polyveck_add) +/************************************************* + * Name: mld_polyveck_add + * + * Description: Add vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to input-output vector of polynomials + * to be added to + * - const mld_polyveck *v: pointer to second input vector of + * polynomials + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(p0, 0, MLDSA_K, array_abs_bound(u->vec[p0].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) + requires(forall(p1, 0, MLDSA_K, + array_bound(v->vec[p1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(q2, 0, MLDSA_K, + array_bound(u->vec[q2].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_sub MLD_NAMESPACE_KL(polyveck_sub) +/************************************************* + * Name: mld_polyveck_sub + * + * Description: Subtract vectors of polynomials of length MLDSA_K. + * No modular reduction is performed. + * + * Arguments: - mld_polyveck *u: pointer to first input vector + * - const mld_polyveck *v: pointer to second input vector to be + * subtracted from first input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v) +__contract__( + requires(memory_no_alias(u, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(u->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(u, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))) +); + +#define mld_polyveck_shiftl MLD_NAMESPACE_KL(polyveck_shiftl) +/************************************************* + * Name: mld_polyveck_shiftl + * + * Description: Multiply vector of polynomials of Length MLDSA_K by 2^MLDSA_D + *without modular reduction. Assumes input coefficients to be less than + *2^{31-MLDSA_D}. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_shiftl(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) +); + +#define mld_polyveck_ntt MLD_NAMESPACE_KL(polyveck_ntt) +/************************************************* + * Name: mld_polyveck_ntt + * + * Description: Forward NTT of all polynomials in vector of length MLDSA_K. + * Coefficients can grow by 8*MLDSA_Q in absolute value. + * + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_ntt(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) +); + +#define mld_polyveck_invntt_tomont MLD_NAMESPACE_KL(polyveck_invntt_tomont) +/************************************************* + * Name: mld_polyveck_invntt_tomont + * + * Description: Inverse NTT and multiplication by 2^{32} of polynomials + * in vector of length MLDSA_K. + * Input coefficients need to be less than MLDSA_Q, and + * Output coefficients are bounded by MLD_INTT_BOUND. + * Arguments: - mld_polyveck *v: pointer to input/output vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_invntt_tomont(mld_polyveck *v) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) + assigns(memory_slice(v, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))) +); + +#define mld_polyveck_pointwise_poly_montgomery \ + MLD_NAMESPACE_KL(polyveck_pointwise_poly_montgomery) +/************************************************* + * Name: mld_polyveck_pointwise_poly_montgomery + * + * Description: Pointwise multiplication of a polynomial vector of length + * MLDSA_K by a single polynomial in NTT domain and multiplication + * of the resulting polynomial vector by 2^{-32}. + * + * Arguments: - mld_polyveck *r: pointer to output vector + * - mld_poly *a: pointer to input polynomial + * - mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(r, sizeof(mld_polyveck))) + requires(memory_no_alias(a, sizeof(mld_poly))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(r, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_abs_bound(r->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#define mld_polyveck_chknorm MLD_NAMESPACE_KL(polyveck_chknorm) +/************************************************* + * Name: mld_polyveck_chknorm + * + * Description: Check infinity norm of polynomials in vector of length MLDSA_K. + * Assumes input mld_polyveck to be reduced by polyveck_reduce(). + * + * Arguments: - const mld_polyveck *v: pointer to vector + * - int32_t B: norm bound + * + * Returns 0 if norm of all polynomials are strictly smaller than B <= + *(MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t B) +__contract__( + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(0 <= B && B <= (MLDSA_Q - 1) / 8) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, + -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))) + ensures(return_value == 0 || return_value == 0xFFFFFFFF) + ensures((return_value == 0) == forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B))) +); + +#define mld_polyveck_power2round MLD_NAMESPACE_KL(polyveck_power2round) +/************************************************* + * Name: mld_polyveck_power2round + * + * Description: For all coefficients a of polynomials in vector of length + *MLDSA_K, compute a0, a1 such that a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with + *-2^{MLDSA_D-1} < a0 <= 2^{MLDSA_D-1}. Assumes coefficients to be standard + *representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to output vector of polynomials with + * coefficients a0 + * - const mld_polyveck *v: pointer to input vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0, + const mld_polyveck *v) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))) +); + +#define mld_polyveck_decompose MLD_NAMESPACE_KL(polyveck_decompose) +/************************************************* + * Name: mld_polyveck_decompose + * + * Description: For all coefficients a of polynomials in vector of length + * MLDSA_K, compute high and low bits a0, a1 such a mod^+ MLDSA_Q = a1*ALPHA + * + a0 with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (MLDSA_Q-1)/ALPHA where we set + * a1 = 0 and -ALPHA/2 <= a0 = a mod MLDSA_Q - MLDSA_Q < 0. Assumes coefficients + * to be standard representatives. + * + * Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with + * coefficients a1 + * - mld_polyveck *v0: pointer to input/output vector of + * polynomials with. Output polynomial has + * coefficients a0 + * + * Reference: The reference implementation has the input polynomial as a + * separate argument that may be aliased with either of the outputs. + * Removing the aliasing eases CBMC proofs. + * + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0) +__contract__( + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v0->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + assigns(memory_slice(v1, sizeof(mld_polyveck))) + assigns(memory_slice(v0, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + ensures(forall(k2, 0, MLDSA_K, + array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))) +); + +#define mld_polyveck_make_hint MLD_NAMESPACE_KL(polyveck_make_hint) +/************************************************* + * Name: mld_polyveck_make_hint + * + * Description: Compute hint vector. + * + * Arguments: - mld_polyveck *h: pointer to output vector + * - const mld_polyveck *v0: pointer to low part of input vector + * - const mld_polyveck *v1: pointer to high part of input vector + * + * Returns number of 1 bits. + **************************************************/ +MLD_INTERNAL_API +MLD_MUST_CHECK_RETURN_VALUE +unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0, + const mld_polyveck *v1) +__contract__( + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(memory_no_alias(v0, sizeof(mld_polyveck))) + requires(memory_no_alias(v1, sizeof(mld_polyveck))) + assigns(memory_slice(h, sizeof(mld_polyveck))) + ensures(return_value <= MLDSA_N * MLDSA_K) + ensures(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) +); + +#define mld_polyveck_use_hint MLD_NAMESPACE_KL(polyveck_use_hint) +/************************************************* + * Name: mld_polyveck_use_hint + * + * Description: Use hint vector to correct the high bits of input vector. + * + * Arguments: - mld_polyveck *w: pointer to output vector of polynomials with + * corrected high bits + * - const mld_polyveck *u: pointer to input vector + * - const mld_polyveck *h: pointer to input hint vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *v, + const mld_polyveck *h) +__contract__( + requires(memory_no_alias(w, sizeof(mld_polyveck))) + requires(memory_no_alias(v, sizeof(mld_polyveck))) + requires(memory_no_alias(h, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q))) + requires(forall(k1, 0, MLDSA_K, + array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2))) + assigns(memory_slice(w, sizeof(mld_polyveck))) + ensures(forall(k2, 0, MLDSA_K, + array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) +); + +#define mld_polyveck_pack_w1 MLD_NAMESPACE_KL(polyveck_pack_w1) +/************************************************* + * Name: mld_polyveck_pack_w1 + * + * Description: Bit-pack polynomial vector w1 with coefficients in [0,15] or + * [0,43]. + * Input coefficients are assumed to be standard representatives. + * + * Arguments: - uint8_t *r: pointer to output byte array with at least + * MLDSA_K* MLDSA_POLYW1_PACKEDBYTES bytes + * - const mld_polyveck *a: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES], + const mld_polyveck *w1) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) + requires(memory_no_alias(w1, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_bound(w1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)) +); + +#define mld_polyveck_pack_eta MLD_NAMESPACE_KL(polyveck_pack_eta) +/************************************************* + * Name: mld_polyveck_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients + * in [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k1, 0, MLDSA_K, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyvecl_pack_eta MLD_NAMESPACE_KL(polyvecl_pack_eta) +/************************************************* + * Name: mld_polyvecl_pack_eta + * + * Description: Bit-pack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_L * MLDSA_POLYETA_PACKEDBYTES bytes + * - const polyveck *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES], + const mld_polyvecl *p) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_L, + array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + assigns(memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) +); + +#define mld_polyveck_pack_t0 MLD_NAMESPACE_KL(polyveck_pack_t0) +/************************************************* + * Name: mld_polyveck_pack_t0 + * + * Description: Bit-pack polynomial vector to with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - uint8_t *r: pointer to output byte array with + * MLDSA_K * MLDSA_POLYT0_PACKEDBYTES bytes + * - const mld_poly *p: pointer to input polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES], + const mld_polyveck *p) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + requires(forall(k0, 0, MLDSA_K, + array_bound(p->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + assigns(memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) +); + +#define mld_polyvecl_unpack_eta MLD_NAMESPACE_KL(polyvecl_unpack_eta) +/************************************************* + * Name: mld_polyvecl_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyvecl *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_eta( + mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyvecl))) + assigns(memory_slice(p, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyvecl_unpack_z MLD_NAMESPACE_KL(polyvecl_unpack_z) +/************************************************* + * Name: mld_polyvecl_unpack_z + * + * Description: Unpack polynomial vector with coefficients in + * [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1]. + * + * Arguments: - mld_polyvecl *z: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyvecl_unpack_z(mld_polyvecl *z, + const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYZ_PACKEDBYTES)) + requires(memory_no_alias(z, sizeof(mld_polyvecl))) + assigns(memory_slice(z, sizeof(mld_polyvecl))) + ensures(forall(k1, 0, MLDSA_L, + array_bound(z->vec[k1].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) +); + +#define mld_polyveck_unpack_eta MLD_NAMESPACE_KL(polyveck_unpack_eta) +/************************************************* + * Name: mld_polyveck_unpack_eta + * + * Description: Unpack polynomial vector with coefficients in + * [-MLDSA_ETA,MLDSA_ETA]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_eta( + mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) +); + +#define mld_polyveck_unpack_t0 MLD_NAMESPACE_KL(polyveck_unpack_t0) +/************************************************* + * Name: mld_polyveck_unpack_t0 + * + * Description: Unpack polynomial vector with coefficients in + * ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}]. + * + * Arguments: - mld_polyveck *p: pointer to output polynomial vector + * - const uint8_t *r: input byte array with + * bit-packed polynomial vector + **************************************************/ +MLD_INTERNAL_API +void mld_polyveck_unpack_t0(mld_polyveck *p, + const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES]) +__contract__( + requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)) + requires(memory_no_alias(p, sizeof(mld_polyveck))) + assigns(memory_slice(p, sizeof(mld_polyveck))) + ensures(forall(k1, 0, MLDSA_K, + array_bound(p->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) +); + +#define mld_polymat_get_row MLD_NAMESPACE_KL(polymat_get_row) +/************************************************* + * Name: mld_polymat_get_row + * + * Description: Retrieve a pointer to a specific row of the matrix. + * In MLD_CONFIG_REDUCE_RAM mode, generates the row on-demand. + * + * Arguments: - mld_polymat *mat: pointer to matrix + * - unsigned int row: row index (must be < MLDSA_K) + * + * Returns pointer to the row (mld_polyvecl) + **************************************************/ +MLD_INTERNAL_API +const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row); + +#define mld_polyvec_matrix_expand MLD_NAMESPACE_KL(polyvec_matrix_expand) +/************************************************* + * Name: mld_polyvec_matrix_expand + * + * Description: Implementation of ExpandA. Generates matrix A with uniformly + * random coefficients a_{i,j} by performing rejection + * sampling on the output stream of SHAKE128(rho|j|i) + * + * Arguments: - mld_polymat *mat: pointer to output matrix + * - const uint8_t rho[]: byte array containing seed rho + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_expand(mld_polymat *mat, + const uint8_t rho[MLDSA_SEEDBYTES]) +__contract__( + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + assigns(memory_slice(mat, sizeof(mld_polymat))) + ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) +); + + + +#define mld_polyvec_matrix_pointwise_montgomery \ + MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery) +/************************************************* + * Name: mld_polyvec_matrix_pointwise_montgomery + * + * Description: Compute matrix-vector multiplication in NTT domain with + * pointwise multiplication and multiplication by 2^{-32}. + * Input matrix and vector must be in NTT domain representation. + * + * The first input "mat" must be the output of + * polyvec_matrix_expand() and so have coefficients in [0, Q-1] + * inclusive. + * + * The second input "v" is assumed to be output of an NTT, and + * hence must have coefficients bounded by [-9q+1, +9q-1] + * inclusive. + * + * Note: In MLD_CONFIG_REDUCE_RAM mode, mat cannot be const + * as rows are generated on-demand. + * + * Arguments: - mld_polyveck *t: pointer to output vector t + * - mld_polymat *mat: pointer to input matrix + * - const mld_polyvecl *v: pointer to input vector v + **************************************************/ +MLD_INTERNAL_API +void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat, + const mld_polyvecl *v) +__contract__( + requires(memory_no_alias(t, sizeof(mld_polyveck))) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(v, sizeof(mld_polyvecl))) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(l1, 0, MLDSA_L, + array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(t, sizeof(mld_polyveck))) + ensures(forall(k0, 0, MLDSA_K, + array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q))) +); + +#endif /* !MLD_POLYVEC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/randombytes.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/randombytes.h new file mode 100644 index 0000000000..da55772419 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/randombytes.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_RANDOMBYTES_H +#define MLD_RANDOMBYTES_H + +#include +#include + +#include "cbmc.h" +#include "common.h" + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +#if !defined(MLD_CONFIG_CUSTOM_RANDOMBYTES) +MLD_MUST_CHECK_RETURN_VALUE +int randombytes(uint8_t *out, size_t outlen); +static MLD_INLINE int mld_randombytes(uint8_t *out, size_t outlen) +__contract__( + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) { return randombytes(out, outlen); } +#endif /* !MLD_CONFIG_CUSTOM_RANDOMBYTES */ +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ +#endif /* !MLD_RANDOMBYTES_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/reduce.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/reduce.h new file mode 100644 index 0000000000..413cf1829e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/reduce.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_REDUCE_H +#define MLD_REDUCE_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* check-magic: -4186625 == pow(2,32,MLDSA_Q) */ +#define MLD_MONT -4186625 + +/* Upper bound for domain of mld_reduce32() */ +#define MLD_REDUCE32_DOMAIN_MAX (INT32_MAX - (1 << 22)) + +/* Absolute bound for range of mld_reduce32() */ +/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */ +#define MLD_REDUCE32_RANGE_MAX 6283009 + +/************************************************* + * Name: mld_montgomery_reduce + * + * Description: Generic Montgomery reduction; given a 64-bit integer a, computes + * 32-bit integer congruent to a * R^-1 mod q, where R=2^32 + * + * Arguments: - int64_t a: input integer to be reduced, of absolute value + * smaller or equal to INT64_MAX - 2^31 * MLDSA_Q. + * + * Returns: Integer congruent to a * R^-1 modulo q, with absolute value + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * In particular, if |a| < 2^31 * MLDSA_Q, the absolute value + * of the return value is < MLDSA_Q. + **************************************************/ +static MLD_INLINE int32_t mld_montgomery_reduce(int64_t a) +__contract__( + /* We don't attempt to express an input-dependent output bound + * as the post-condition here, as all call-sites satisfy the + * absolute input bound 2^31 * MLDSA_Q and higher-level + * reasoning can be conducted using |return_value| < MLDSA_Q. */ + requires(a > -(((int64_t)1 << 31) * MLDSA_Q) && + a < (((int64_t)1 << 31) * MLDSA_Q)) + ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q) +) +{ + /* check-magic: 58728449 == unsigned_mod(pow(MLDSA_Q, -1, 2^32), 2^32) */ + const uint64_t QINV = 58728449; + + /* Compute a*q^{-1} mod 2^32 in unsigned representatives */ + const uint32_t a_reduced = mld_cast_int64_to_uint32(a); + const uint32_t a_inverted = (a_reduced * QINV) & UINT32_MAX; + + /* Lift to signed canonical representative mod 2^32. */ + const int32_t t = mld_cast_uint32_to_int32(a_inverted); + + int64_t r; + + mld_assert(a < +(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)) && + a > -(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q))); + + r = a - (int64_t)t * MLDSA_Q; + + /* + * PORTABILITY: Right-shift on a signed integer is, strictly-speaking, + * implementation-defined for negative left argument. Here, + * we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5)) + */ + r = r >> 32; + + /* Bounds: + * + * By construction of the Montgomery multiplication, by the time we + * compute r >> 32, r is divisible by 2^32, and hence + * + * |r >> 32| = |r| / 2^32 + * <= |a| / 2^32 + MLDSA_Q / 2 + * + * (In general, we would only have |x >> n| <= ceil(|x| / 2^n)). + * + * In particular, if |a| < 2^31 * MLDSA_Q, then |return_value| < MLDSA_Q. + */ + return (int32_t)r; +} + +/************************************************* + * Name: mld_reduce32 + * + * Description: For finite field element a with a <= 2^{31} - 2^{22} - 1, + * compute r \equiv a (mod MLDSA_Q) such that + * -MLD_REDUCE32_RANGE_MAX <= r < MLD_REDUCE32_RANGE_MAX. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_reduce32(int32_t a) +__contract__( + requires(a <= MLD_REDUCE32_DOMAIN_MAX) + ensures(return_value >= -MLD_REDUCE32_RANGE_MAX) + ensures(return_value < MLD_REDUCE32_RANGE_MAX) +) +{ + int32_t t; + + t = (a + (1 << 22)) >> 23; + t = a - t * MLDSA_Q; + mld_assert((t - a) % MLDSA_Q == 0); + return t; +} + +/************************************************* + * Name: mld_caddq + * + * Description: Add MLDSA_Q if input coefficient is negative. + * + * Arguments: - int32_t: finite field element a + * + * Returns r. + **************************************************/ +static MLD_INLINE int32_t mld_caddq(int32_t a) +__contract__( + requires(a > -MLDSA_Q) + requires(a < MLDSA_Q) + ensures(return_value >= 0) + ensures(return_value < MLDSA_Q) + ensures(return_value == (a >= 0) ? a : (a + MLDSA_Q)) +) +{ + return mld_ct_sel_int32(a + MLDSA_Q, a, mld_ct_cmask_neg_i32(a)); +} + + +#endif /* !MLD_REDUCE_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/rounding.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/rounding.h new file mode 100644 index 0000000000..a83562b0f1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/rounding.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_ROUNDING_H +#define MLD_ROUNDING_H + +#include +#include "cbmc.h" +#include "common.h" +#include "ct.h" +#include "debug.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_power2round MLD_ADD_PARAM_SET(mld_power2round) +#define mld_decompose MLD_ADD_PARAM_SET(mld_decompose) +#define mld_make_hint MLD_ADD_PARAM_SET(mld_make_hint) +#define mld_use_hint MLD_ADD_PARAM_SET(mld_use_hint) +/* End of parameter set namespacing */ + +#define MLD_2_POW_D (1 << MLDSA_D) + +/************************************************* + * Name: mld_power2round + * + * Description: For finite field element a, compute a0, a1 such that + * a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with -2^{MLDSA_D-1} < a0 <= + * 2^{MLDSA_D-1}. Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: In the reference implementation, a1 is passed as a + * return value instead. + **************************************************/ +static MLD_INLINE void mld_power2round(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + ensures(*a0 > -(MLD_2_POW_D/2) && *a0 <= (MLD_2_POW_D/2)) + ensures(*a1 >= 0 && *a1 <= (MLDSA_Q - 1) / MLD_2_POW_D) + ensures((*a1 * MLD_2_POW_D + *a0 - a) % MLDSA_Q == 0) +) +{ + *a1 = (a + (1 << (MLDSA_D - 1)) - 1) >> MLDSA_D; + *a0 = a - (*a1 << MLDSA_D); +} + +/************************************************* + * Name: mld_decompose + * + * Description: For finite field element a, compute high and low bits a0, a1 + * such that a mod^+ MLDSA_Q = a1* 2 * MLDSA_GAMMA2 + a0 with + * -MLDSA_GAMMA2 < a0 <= MLDSA_GAMMA2 except + * if a1 = (MLDSA_Q-1)/(MLDSA_GAMMA2*2) where we set a1 = 0 and + * -MLDSA_GAMMA2 <= a0 = a mod^+ MLDSA_Q - MLDSA_Q < 0. + * Assumes a to be standard representative. + * + * Arguments: - int32_t a: input element + * - int32_t *a0: pointer to output element a0 + * - int32_t *a1: pointer to output element a1 + * + * Reference: a1 is passed as a return value instead + **************************************************/ +static MLD_INLINE void mld_decompose(int32_t *a0, int32_t *a1, int32_t a) +__contract__( + requires(memory_no_alias(a0, sizeof(int32_t))) + requires(memory_no_alias(a1, sizeof(int32_t))) + requires(a >= 0 && a < MLDSA_Q) + assigns(memory_slice(a0, sizeof(int32_t))) + assigns(memory_slice(a1, sizeof(int32_t))) + /* a0 = -MLDSA_GAMMA2 can only occur when (q-1) = a - (a mod MLDSA_GAMMA2), + * then a1=1; and a0 = a - (a mod MLDSA_GAMMA2) - 1 (@[FIPS204, Algorithm 36 (Decompose)]) */ + ensures(*a0 >= -MLDSA_GAMMA2 && *a0 <= MLDSA_GAMMA2) + ensures(*a1 >= 0 && *a1 < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) + ensures((*a1 * 2 * MLDSA_GAMMA2 + *a0 - a) % MLDSA_Q == 0) +) +{ + /* + * The goal is to compute f1 = round-(f / (2*GAMMA2)), which can be computed + * alternatively as round-(f / (128B)) = round-(ceil(f / 128) / B) where + * B = 2*GAMMA2 / 128. Here round-() denotes "round half down". + * + * The equality round-(f / (128B)) = round-(ceil(f / 128) / B) can deduced + * as follows. Since changing f to align-up(f, 128) can move f onto but not + * across a rounding boundary for division by 128*B (note that we need B to be + * even for this to work), and round- rounds down on the boundary, we have + * + * round-(f / (128B)) = round-(align-up(f, 128) / (128B)) + * = round-((align-up(f, 128) / 128) / B) + * = round-(ceil(f / 128) / B). + */ + *a1 = (a + 127) >> 7; + /* We know a >= 0 and a < MLDSA_Q, so... */ + /* check-magic: 65472 == round((MLDSA_Q-1)/128) */ + mld_assert(*a1 >= 0 && *a1 <= 65472); + +#if MLD_CONFIG_PARAMETER_SET == 44 + /* check-magic: 1488 == 2 * intdiv(intdiv(MLDSA_Q - 1, 88), 128) */ + /* check-magic: 11275 == floor(2**24 / 1488) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲ + * 1 / 1488. + */ + *a1 = (*a1 * 11275 + (1 << 23)) >> 24; + mld_assert(*a1 >= 0 && *a1 <= 44); + + *a1 = mld_ct_sel_int32(0, *a1, mld_ct_cmask_neg_i32(43 - *a1)); + mld_assert(*a1 >= 0 && *a1 <= 43); +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + /* check-magic: 4092 == 2 * intdiv(intdiv(MLDSA_Q - 1, 32), 128) */ + /* check-magic: 1025 == floor(2**22 / 4092) */ + /* + * Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact + * for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲ + * 1 / 4092. + */ + *a1 = (*a1 * 1025 + (1 << 21)) >> 22; + mld_assert(*a1 >= 0 && *a1 <= 16); + + *a1 &= 15; + mld_assert(*a1 >= 0 && *a1 <= 15); + +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ + + *a0 = a - *a1 * 2 * MLDSA_GAMMA2; + *a0 = mld_ct_sel_int32(*a0 - MLDSA_Q, *a0, + mld_ct_cmask_neg_i32((MLDSA_Q - 1) / 2 - *a0)); +} + +/************************************************* + * Name: mld_make_hint + * + * Description: Compute hint bit indicating whether the low bits of the + * input element overflow into the high bits. + * + * Arguments: - int32_t a0: low bits of input element + * - int32_t a1: high bits of input element + * + * Returns 1 if overflow, 0 otherwise + **************************************************/ +static MLD_INLINE unsigned int mld_make_hint(int32_t a0, int32_t a1) +__contract__( + ensures(return_value >= 0 && return_value <= 1) +) +{ + if (a0 > MLDSA_GAMMA2 || a0 < -MLDSA_GAMMA2 || + (a0 == -MLDSA_GAMMA2 && a1 != 0)) + { + return 1; + } + + return 0; +} + +/************************************************* + * Name: mld_use_hint + * + * Description: Correct high bits according to hint. + * + * Arguments: - int32_t a: input element + * - int32_t hint: hint bit + * + * Returns corrected high bits. + **************************************************/ +static MLD_INLINE int32_t mld_use_hint(int32_t a, int32_t hint) +__contract__( + requires(hint >= 0 && hint <= 1) + requires(a >= 0 && a < MLDSA_Q) + ensures(return_value >= 0 && return_value < (MLDSA_Q-1)/(2*MLDSA_GAMMA2)) +) +{ + int32_t a0, a1; + + mld_decompose(&a0, &a1, a); + if (hint == 0) + { + return a1; + } + +#if MLD_CONFIG_PARAMETER_SET == 44 + if (a0 > 0) + { + return (a1 == 43) ? 0 : a1 + 1; + } + else + { + return (a1 == 0) ? 43 : a1 - 1; + } +#else /* MLD_CONFIG_PARAMETER_SET == 44 */ + if (a0 > 0) + { + return (a1 + 1) & 15; + } + else + { + return (a1 - 1) & 15; + } +#endif /* MLD_CONFIG_PARAMETER_SET != 44 */ +} + + +#endif /* !MLD_ROUNDING_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/sign.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/sign.c new file mode 100644 index 0000000000..32bba52d65 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/sign.c @@ -0,0 +1,1508 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [Round3_Spec] + * CRYSTALS-Dilithium Algorithm Specifications and Supporting Documentation + * (Version 3.1) + * Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé + * https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf + */ + +#include +#include + +#include "cbmc.h" +#include "ct.h" +#include "debug.h" +#include "packing.h" +#include "poly.h" +#include "poly_kl.h" +#include "polyvec.h" +#include "randombytes.h" +#include "sign.h" +#include "symmetric.h" + +/* Parameter set namespacing + * This is to facilitate building multiple instances + * of mldsa-native (e.g. with varying parameter sets) + * within a single compilation unit. */ +#define mld_check_pct MLD_ADD_PARAM_SET(mld_check_pct) MLD_CONTEXT_PARAMETERS_2 +#define mld_sample_s1_s2 MLD_ADD_PARAM_SET(mld_sample_s1_s2) +#define mld_validate_hash_length MLD_ADD_PARAM_SET(mld_validate_hash_length) +#define mld_get_hash_oid MLD_ADD_PARAM_SET(mld_get_hash_oid) +#define mld_H MLD_ADD_PARAM_SET(mld_H) +#define mld_compute_pack_z MLD_ADD_PARAM_SET(mld_compute_pack_z) +#define mld_attempt_signature_generation \ + MLD_ADD_PARAM_SET(mld_attempt_signature_generation) MLD_CONTEXT_PARAMETERS_8 +#define mld_compute_t0_t1_tr_from_sk_components \ + MLD_ADD_PARAM_SET(mld_compute_t0_t1_tr_from_sk_components) \ + MLD_CONTEXT_PARAMETERS_7 +/* End of parameter set namespacing */ + + +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + ensures(return_value == 0 + || return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL) +); + +#if defined(MLD_CONFIG_KEYGEN_PCT) +/************************************************* + * @[FIPS140_3_IG] + * (https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf) + * + * TE10.35.02: Pair-wise Consistency Test (PCT) for DSA keypairs + * + * Purpose: Validates that a generated public/private key pair can correctly + * sign and verify data. Test performs signature generation using the private + * key (sk), followed by signature verification using the public key (pk). + * Returns 0 if the signature was successfully verified, non-zero if it cannot. + * + * Note: @[FIPS204] requires that public/private key pairs are to be used only + * for the calculation and/of verification of digital signatures. + **************************************************/ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t message[1] = {0}; + size_t siglen; + int ret; + MLD_ALLOC(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + MLD_ALLOC(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + + if (signature == NULL || pk_test == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Copy public key for testing */ + mld_memcpy(pk_test, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* Sign a test message using the original secret key */ + ret = mld_sign_signature(signature, &siglen, message, sizeof(message), NULL, + 0, sk, context); + if (ret != 0) + { + goto cleanup; + } + +#if defined(MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST) + /* Deliberately break public key for testing purposes */ + if (mld_break_pct()) + { + pk_test[0] = ~pk_test[0]; + } +#endif /* MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST */ + + /* Verify the signature using the (potentially corrupted) public key */ + ret = mld_sign_verify(signature, siglen, message, sizeof(message), NULL, 0, + pk_test, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES, context); + MLD_FREE(signature, uint8_t, MLDSA_CRYPTO_BYTES, context); + + return ret; +} +#else /* MLD_CONFIG_KEYGEN_PCT */ +static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + /* Skip PCT */ + ((void)pk); + ((void)sk); +#if defined(MLD_CONFIG_CONTEXT_PARAMETER) + ((void)context); +#endif + return 0; +} +#endif /* !MLD_CONFIG_KEYGEN_PCT */ + +static void mld_sample_s1_s2(mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t seed[MLDSA_CRHBYTES]) +__contract__( + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(seed, MLDSA_CRHBYTES)) + assigns(object_whole(s1), object_whole(s2)) + ensures(forall(l0, 0, MLDSA_L, array_abs_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) + ensures(forall(k0, 0, MLDSA_K, array_abs_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLDSA_ETA + 1))) +) +{ +/* Sample short vectors s1 and s2 */ +#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) + int i; + uint16_t nonce = 0; + /* Safety: The nonces are at most 14 (MLDSA_L + MLDSA_K - 1), and, hence, the + * casts are safe. */ + for (i = 0; i < MLDSA_L; i++) + { + mld_poly_uniform_eta(&s1->vec[i], seed, (uint8_t)(nonce + i)); + } + for (i = 0; i < MLDSA_K; i++) + { + mld_poly_uniform_eta(&s2->vec[i], seed, (uint8_t)(nonce + MLDSA_L + i)); + } +#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */ +#if MLD_CONFIG_PARAMETER_SET == 44 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 4, 5, 6, 7); +#elif MLD_CONFIG_PARAMETER_SET == 65 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s2->vec[0], &s2->vec[1], + &s2->vec[2] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[2], &s2->vec[3], &s2->vec[4], &s2->vec[5], + seed, 7, 8, 9, 10); +#elif MLD_CONFIG_PARAMETER_SET == 87 + mld_poly_uniform_eta_4x(&s1->vec[0], &s1->vec[1], &s1->vec[2], &s1->vec[3], + seed, 0, 1, 2, 3); + mld_poly_uniform_eta_4x(&s1->vec[4], &s1->vec[5], &s1->vec[6], + &s2->vec[0] /* irrelevant */, seed, 4, 5, 6, + 0xFF /* irrelevant */); + mld_poly_uniform_eta_4x(&s2->vec[0], &s2->vec[1], &s2->vec[2], &s2->vec[3], + seed, 7, 8, 9, 10); + mld_poly_uniform_eta_4x(&s2->vec[4], &s2->vec[5], &s2->vec[6], &s2->vec[7], + seed, 11, 12, 13, 14); +#endif /* MLD_CONFIG_PARAMETER_SET == 87 */ +#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */ +} + +/************************************************* + * Name: mld_compute_t0_t1_tr_from_sk_components + * + * Description: Computes t0, t1, tr, and pk from secret key components + * rho, s1, s2. This is the shared computation used by + * both keygen and generating the public key from the + * secret key. + * + * Arguments: - mld_polyveck *t0: output t0 + * - mld_polyveck *t1: output t1 + * - uint8_t tr[MLDSA_TRBYTES]: output tr + * - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t rho[MLDSA_SEEDBYTES]: input rho + * - const mld_polyvecl *s1: input s1 + * - const mld_polyveck *s2: input s2 + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_t0_t1_tr_from_sk_components( + mld_polyveck *t0, mld_polyveck *t1, uint8_t tr[MLDSA_TRBYTES], + uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], const uint8_t rho[MLDSA_SEEDBYTES], + const mld_polyvecl *s1, const mld_polyveck *s2, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(memory_no_alias(t1, sizeof(mld_polyveck))) + requires(memory_no_alias(tr, MLDSA_TRBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(rho, MLDSA_SEEDBYTES)) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(forall(l0, 0, MLDSA_L, array_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + requires(forall(k0, 0, MLDSA_K, array_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))) + assigns(memory_slice(t0, sizeof(mld_polyveck))) + assigns(memory_slice(t1, sizeof(mld_polyveck))) + assigns(memory_slice(tr, MLDSA_TRBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(forall(k1, 0, MLDSA_K, array_bound(t0->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))) + ensures(forall(k2, 0, MLDSA_K, array_bound(t1->vec[k2].coeffs, 0, MLDSA_N, 0, 1 << 10))) + ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY)) +{ + int ret; + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1hat, mld_polyvecl, 1, context); + MLD_ALLOC(t, mld_polyveck, 1, context); + + if (mat == NULL || s1hat == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Expand matrix */ + mld_polyvec_matrix_expand(mat, rho); + + /* Matrix-vector multiplication */ + *s1hat = *s1; + mld_polyvecl_ntt(s1hat); + mld_polyvec_matrix_pointwise_montgomery(t, mat, s1hat); + mld_polyveck_invntt_tomont(t); + + /* Add error vector s2 */ + mld_polyveck_add(t, s2); + + /* Reference: The following reduction is not present in the reference + * implementation. Omitting this reduction requires the output of + * the invntt to be small enough such that the addition of s2 does + * not result in absolute values >= MLDSA_Q. While our C, x86_64, + * and AArch64 invntt implementations produce small enough + * values for this to work out, it complicates the bounds + * reasoning. We instead add an additional reduction, and can + * consequently, relax the bounds requirements for the invntt. + */ + mld_polyveck_reduce(t); + + /* Decompose to get t1, t0 */ + mld_polyveck_caddq(t); + mld_polyveck_power2round(t1, t0, t); + + /* Pack public key and compute tr */ + mld_pack_pk(pk, rho, t1); + mld_shake256(tr, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + ret = 0; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_polyveck, 1, context); + MLD_FREE(s1hat, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + const uint8_t *rho, *rhoprime, *key; + MLD_ALLOC(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + MLD_ALLOC(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + + if (seedbuf == NULL || inbuf == NULL || tr == NULL || s1 == NULL || + s2 == NULL || t1 == NULL || t0 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Get randomness for rho, rhoprime and key */ + mld_memcpy(inbuf, seed, MLDSA_SEEDBYTES); + inbuf[MLDSA_SEEDBYTES + 0] = MLDSA_K; + inbuf[MLDSA_SEEDBYTES + 1] = MLDSA_L; + mld_shake256(seedbuf, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, inbuf, + MLDSA_SEEDBYTES + 2); + rho = seedbuf; + rhoprime = rho + MLDSA_SEEDBYTES; + key = rhoprime + MLDSA_CRHBYTES; + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + + /* Sample s1 and s2 */ + mld_sample_s1_s2(s1, s2, rhoprime); + + /* Compute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0, t1, tr, pk, rho, s1, s2, + context); + if (ret != 0) + { + goto cleanup; + } + + /* Pack secret key */ + mld_pack_sk(sk, rho, tr, key, t0, s1, s2); + + /* Constant time: pk is the public key, inherently public data */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context); + MLD_FREE(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context); + + if (ret != 0) + { + return ret; + } + + /* Pairwise Consistency Test (PCT) @[FIPS140_3_IG, p.87] */ + /* Do this after freeing all temporaries. */ + return mld_check_pct(pk, sk, context); +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t seed[MLDSA_SEEDBYTES]; + int ret; + if (mld_randombytes(seed, MLDSA_SEEDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(seed, sizeof(seed)); + ret = mld_sign_keypair_internal(pk, sk, seed, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(seed, sizeof(seed)); + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +/************************************************* + * Name: mld_H + * + * Description: Abstracts application of SHAKE256 to + * one, two or three blocks of data, + * yielding a user-requested size of + * output. + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in1: pointer to input block 1 + * Must NOT be NULL + * - size_t in1len: length of input in1 bytes + * - const uint8_t *in2: pointer to input block 2 + * May be NULL if in2len=0, in which case + * this block is ignored + * - size_t in2len: length of input in2 bytes + * - const uint8_t *in3: pointer to input block 3 + * May be NULL if in3len=0, in which case + * this block is ignored + * - size_t in3len: length of input in3 bytes + **************************************************/ +static void mld_H(uint8_t *out, size_t outlen, const uint8_t *in1, + size_t in1len, const uint8_t *in2, size_t in2len, + const uint8_t *in3, size_t in3len) +__contract__( + requires(in1len <= MLD_MAX_BUFFER_SIZE) + requires(in2len <= MLD_MAX_BUFFER_SIZE) + requires(in3len <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE256_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in1, in1len)) + requires(in2len == 0 || memory_no_alias(in2, in2len)) + requires(in3len == 0 || memory_no_alias(in3, in3len)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +) +{ + mld_shake256ctx state; + mld_shake256_init(&state); + mld_shake256_absorb(&state, in1, in1len); + if (in2len != 0) + { + mld_shake256_absorb(&state, in2, in2len); + } + if (in3len != 0) + { + mld_shake256_absorb(&state, in3, in3len); + } + mld_shake256_finalize(&state); + mld_shake256_squeeze(out, outlen, &state); + mld_shake256_release(&state); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(&state, sizeof(state)); +} + +/************************************************* + * Name: mld_compute_pack_z + * + * Description: Computes z = y + s1*c, checks that z has coefficients smaller + * than MLDSA_GAMMA1 - MLDSA_BETA, and packs z into the + * signature buffer. + * + * Arguments: - uint8_t *sig: output signature + * - const mld_poly *cp: challenge polynomial + * - const polyvecl *s1: secret vector s1 + * - const polyvecl *y: masking vector y + * + * Returns: - 0: Success (z has coefficients smaller than + * MLDSA_GAMMA1 - MLDSA_BETA,) + * - MLD_ERR_FAIL: z rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This function is inlined into mld_sign_signature in the + * reference implementation. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_compute_pack_z(uint8_t sig[MLDSA_CRYPTO_BYTES], + const mld_poly *cp, const mld_polyvecl *s1, + const mld_polyvecl *y, mld_poly *z) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(cp, sizeof(mld_poly))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(y, sizeof(mld_polyvecl))) + requires(memory_no_alias(z, sizeof(mld_poly))) + requires(array_abs_bound(cp->coeffs, 0, MLDSA_N, MLD_NTT_BOUND)) + requires(forall(k0, 0, MLDSA_L, + array_bound(y->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))) + requires(forall(k1, 0, MLDSA_L, array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(memory_slice(z, sizeof(mld_poly))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int i; + uint32_t z_invalid; + for (i = 0; i < MLDSA_L; i++) + __loop__( + assigns(i, memory_slice(z, sizeof(mld_poly)), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(i <= MLDSA_L) + ) + { + mld_poly_pointwise_montgomery(z, cp, &s1->vec[i]); + mld_poly_invntt_tomont(z); + mld_poly_add(z, &y->vec[i]); + mld_poly_reduce(z); + + z_invalid = mld_poly_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA); + /* Constant time: It is fine (and prohibitively expensive to avoid) + * to leak the result of the norm check and which polynomial in z caused a + * rejection. It would even be okay to leak which coefficient led to + * rejection as the candidate signature will be discarded anyway. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(&z_invalid, sizeof(uint32_t)); + if (z_invalid) + { + return MLD_ERR_FAIL; /* reject */ + } + /* If z is valid, then its coefficients are bounded by + * MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below + * to prove the pre-condition of pack_sig_z() */ + mld_assert_abs_bound(z, MLDSA_N, (MLDSA_GAMMA1 - MLDSA_BETA)); + + /* After the norm check, the distribution of each coefficient of z is + * independent of the secret key and it can, hence, be considered + * public. It is, hence, okay to immediately pack it into the user-provided + * signature buffer. */ + mld_pack_sig_z(sig, z, i); + } + return 0; +} + +/* Reference: The reference implementation does not explicitly check the + * maximum nonce value, but instead loops indefinitely (even when the nonce + * would overflow). Internally, sampling of y uses + * (nonceL), (nonceL+1), ... (nonce*L+L-1). + * Hence, there are no overflows if nonce < (UINT16_MAX - L)/L. + * Explicitly checking for this explicitly allows us to prove type-safety. + * Note that FIPS204 explicitly allows an upper-bound this loop of + * 814 (< (UINT16_MAX - L)/L) - see @[FIPS204, Appendix C]. */ +#define MLD_NONCE_UB ((UINT16_MAX - MLDSA_L) / MLDSA_L) + +/************************************************* + * Name: attempt_signature_generation + * + * Description: Attempts to generate a single signature. + * + * Arguments: - uint8_t *sig: pointer to output signature + * - const uint8_t *mu: pointer to message or hash + * of exactly MLDSA_CRHBYTES bytes + * - const uint8_t *rhoprime: pointer to randomness seed + * - uint16_t nonce: current nonce value + * - const mld_polymat *mat: expanded matrix + * - const polyvecl *s1: secret vector s1 + * - const polyveck *s2: secret vector s2 + * - const polyveck *t0: vector t0 + * + * Returns: - 0: Signature generation succeeded + * - MLD_ERR_FAIL: Signature rejected (norm check failed) + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * + * Reference: This code differs from the reference implementation + * in that it factors out the core signature generation + * step into a distinct function here in order to improve + * efficiency of CBMC proof. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +static int mld_attempt_signature_generation( + uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *mu, + const uint8_t rhoprime[MLDSA_CRHBYTES], uint16_t nonce, mld_polymat *mat, + const mld_polyvecl *s1, const mld_polyveck *s2, const mld_polyveck *t0, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(rhoprime, MLDSA_CRHBYTES)) + requires(memory_no_alias(mat, sizeof(mld_polymat))) + requires(memory_no_alias(s1, sizeof(mld_polyvecl))) + requires(memory_no_alias(s2, sizeof(mld_polyveck))) + requires(memory_no_alias(t0, sizeof(mld_polyveck))) + requires(nonce <= MLD_NONCE_UB) + requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + requires(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + requires(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) +) +{ + unsigned int n; + uint32_t w0_invalid, h_invalid; + int ret; + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyvecl y; + mld_polyveck h; + } + yh_u; + mld_polyvecl *y; + mld_polyveck *h; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck w1; + mld_polyvecl tmp; + } + w1tmp_u; + mld_polyveck *w1; + mld_polyvecl *tmp; + + MLD_ALLOC(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(yh, yh_u, 1, context); + MLD_ALLOC(z, mld_poly, 1, context); + MLD_ALLOC(w1tmp, w1tmp_u, 1, context); + MLD_ALLOC(w0, mld_polyveck, 1, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(t, mld_poly, 1, context); + + if (challenge_bytes == NULL || yh == NULL || z == NULL || w1tmp == NULL || + w0 == NULL || cp == NULL || t == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + y = &yh->y; + h = &yh->h; + w1 = &w1tmp->w1; + tmp = &w1tmp->tmp; + + /* Sample intermediate vector y */ + mld_polyvecl_uniform_gamma1(y, rhoprime, nonce); + + /* Matrix-vector multiplication */ + *tmp = *y; + mld_polyvecl_ntt(tmp); + mld_polyvec_matrix_pointwise_montgomery(w0, mat, tmp); + mld_polyveck_invntt_tomont(w0); + + /* Decompose w and call the random oracle */ + mld_polyveck_caddq(w0); + mld_polyveck_decompose(w1, w0); + mld_polyveck_pack_w1(sig, w1); + + mld_H(challenge_bytes, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, sig, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + /* Constant time: Leaking challenge_bytes does not reveal any information + * about the secret key as H() is modelled as random oracle. + * This also applies to challenges for rejected signatures. + * See Section 5.5 of @[Round3_Spec]. */ + MLD_CT_TESTING_DECLASSIFY(challenge_bytes, MLDSA_CTILDEBYTES); + mld_poly_challenge(cp, challenge_bytes); + mld_poly_ntt(cp); + + /* Compute z, reject if it reveals secret */ + ret = mld_compute_pack_z(sig, cp, s1, y, t); + if (ret) + { + goto cleanup; + } + + /* Check that subtracting cs2 does not change high bits of w and low bits + * do not reveal secret information */ + mld_polyveck_pointwise_poly_montgomery(h, cp, s2); + mld_polyveck_invntt_tomont(h); + mld_polyveck_sub(w0, h); + mld_polyveck_reduce(w0); + + w0_invalid = mld_polyveck_chknorm(w0, MLDSA_GAMMA2 - MLDSA_BETA); + /* Constant time: w0_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&w0_invalid, sizeof(uint32_t)); + if (w0_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* Compute hints for w1 */ + mld_polyveck_pointwise_poly_montgomery(h, cp, t0); + mld_polyveck_invntt_tomont(h); + mld_polyveck_reduce(h); + + h_invalid = mld_polyveck_chknorm(h, MLDSA_GAMMA2); + /* Constant time: h_invalid may be leaked - see comment for z_invalid. */ + MLD_CT_TESTING_DECLASSIFY(&h_invalid, sizeof(uint32_t)); + if (h_invalid) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + mld_polyveck_add(w0, h); + + /* Constant time: At this point all norm checks have passed and we, hence, + * know that the signature does not leak any secret information. + * Consequently, any value that can be computed from the signature and public + * key is considered public. + * w0 and w1 are public as they can be computed from Az - ct = \alpha w1 + w0. + * h=c*t0 is public as both c and t0 are public. + * For a more detailed discussion, refer to https://eprint.iacr.org/2022/1406. + */ + MLD_CT_TESTING_DECLASSIFY(w0, sizeof(*w0)); + MLD_CT_TESTING_DECLASSIFY(w1, sizeof(*w1)); + n = mld_polyveck_make_hint(h, w0, w1); + if (n > MLDSA_OMEGA) + { + ret = MLD_ERR_FAIL; /* reject */ + goto cleanup; + } + + /* All is well - write signature */ + mld_pack_sig_c_h(sig, challenge_bytes, h, n); + /* Constant time: At this point it is clear that the signature is valid - it + * can, hence, be considered public. */ + MLD_CT_TESTING_DECLASSIFY(sig, MLDSA_CRYPTO_BYTES); + ret = 0; /* success */ + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t, mld_poly, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(w0, mld_polyveck, 1, context); + MLD_FREE(w1tmp, w1tmp_u, 1, context); + MLD_FREE(z, mld_poly, 1, context); + MLD_FREE(yh, yh_u, 1, context); + MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context); + + return ret; +} +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + uint8_t *rho, *tr, *key, *mu, *rhoprime; + uint16_t nonce = 0; + MLD_ALLOC(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + + if (seedbuf == NULL || mat == NULL || s1 == NULL || t0 == NULL || s2 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + rho = seedbuf; + tr = rho + MLDSA_SEEDBYTES; + key = tr + MLDSA_TRBYTES; + mu = key + MLDSA_SEEDBYTES; + rhoprime = mu + MLDSA_CRHBYTES; + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + if (!externalmu) + { + /* Compute mu = CRH(tr, pre, msg) */ + mld_H(mu, MLDSA_CRHBYTES, tr, MLDSA_TRBYTES, pre, prelen, m, mlen); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Compute rhoprime = CRH(key, rnd, mu) */ + mld_H(rhoprime, MLDSA_CRHBYTES, key, MLDSA_SEEDBYTES, rnd, MLDSA_RNDBYTES, mu, + MLDSA_CRHBYTES); + + /* Constant time: rho is part of the public key and, hence, public. */ + MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES); + /* Expand matrix and transform vectors */ + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(s1); + mld_polyveck_ntt(s2); + mld_polyveck_ntt(t0); + + /* By default, return failure. Flip to success and write output + * once signature generation succeeds. */ + ret = MLD_ERR_FAIL; + + /* Reference: This code is re-structured using a while(1), */ + /* with explicit "continue" statements (rather than "goto") */ + /* to implement rejection of invalid signatures. */ + while (1) + __loop__( + assigns(nonce, ret, object_whole(siglen), memory_slice(sig, MLDSA_CRYPTO_BYTES)) + invariant(nonce <= MLD_NONCE_UB) + + /* t0, s1, s2, and mat are initialized above and are NOT changed by this */ + /* loop. We can therefore re-assert their bounds here as part of the */ + /* loop invariant. This makes proof noticeably faster with CBMC */ + invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L, + array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))) + invariant(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))) + invariant(ret == MLD_ERR_FAIL) + ) + { + /* Reference: this code explicitly checks for exhaustion of nonce */ + /* values to provide predictable termination and results in that case */ + /* Checking here also means that incrementing nonce below can also */ + /* be proven to be type-safe. */ + if (nonce == MLD_NONCE_UB) + { + /* Note that ret == MLD_ERR_FAIL by default, so we + * don't need to set it here. */ + break; + } + + ret = mld_attempt_signature_generation(sig, mu, rhoprime, nonce, mat, s1, + s2, t0, context); + nonce++; + if (ret == 0) + { + *siglen = MLDSA_CRYPTO_BYTES; + break; + } + else if (ret != MLD_ERR_FAIL) + { + /* For failures such as out-of-memory, propagate and exit immediately. */ + break; + } + + /* Otherwise, try again. */ + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the signature buffer. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context); + return ret; +} + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + size_t pre_len; + int ret; + MLD_ALLOC(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + MLD_ALLOC(rnd, uint8_t, MLDSA_RNDBYTES, context); + + if (pre == NULL || rnd == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Prepare domain separation prefix for pure ML-DSA */ + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, m, mlen, pre, pre_len, rnd, sk, + 0, context); + +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(rnd, uint8_t, MLDSA_RNDBYTES, context); + MLD_FREE(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t rnd[MLDSA_RNDBYTES]; + int ret; + + /* Randomized variant of ML-DSA. If you need the deterministic variant, + * call mld_sign_signature_internal directly with all-zero rnd. */ + if (mld_randombytes(rnd, MLDSA_RNDBYTES) != 0) + { + *siglen = 0; + ret = MLD_ERR_RNG_FAIL; + goto cleanup; + } + MLD_CT_TESTING_SECRET(rnd, sizeof(rnd)); + + ret = mld_sign_signature_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, + rnd, sk, 1, context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(rnd, sizeof(rnd)); + + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + for (i = 0; i < mlen; ++i) + __loop__( + assigns(i, object_whole(sm)) + invariant(i <= mlen) + ) + { + sm[MLDSA_CRYPTO_BYTES + mlen - 1 - i] = m[mlen - 1 - i]; + } + ret = mld_sign_signature(sm, smlen, sm + MLDSA_CRYPTO_BYTES, mlen, ctx, + ctxlen, sk, context); + *smlen += mlen; + return ret; +} +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret, cmp; + + /* TODO: Remove the following workaround for + * https://github.com/diffblue/cbmc/issues/8813 */ + typedef MLD_UNION_OR_STRUCT + { + mld_polyveck t1; + mld_polyveck w1; + } + t1w1_u; + mld_polyveck *t1; + mld_polyveck *w1; + + MLD_ALLOC(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_ALLOC(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_ALLOC(cp, mld_poly, 1, context); + MLD_ALLOC(mat, mld_polymat, 1, context); + MLD_ALLOC(z, mld_polyvecl, 1, context); + MLD_ALLOC(t1w1, t1w1_u, 1, context); + MLD_ALLOC(tmp, mld_polyveck, 1, context); + MLD_ALLOC(h, mld_polyveck, 1, context); + + if (buf == NULL || rho == NULL || mu == NULL || c == NULL || c2 == NULL || + cp == NULL || mat == NULL || z == NULL || t1w1 == NULL || tmp == NULL || + h == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + t1 = &t1w1->t1; + w1 = &t1w1->w1; + + if (siglen != MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + mld_unpack_pk(rho, t1, pk); + + /* mld_unpack_sig and mld_polyvecl_chknorm signal failure through a + * single non-zero error code that's not yet aligned with MLD_ERR_XXX. + * Map it to MLD_ERR_FAIL explicitly. */ + if (mld_unpack_sig(c, z, h, sig)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + if (mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA)) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + if (!externalmu) + { + /* Compute CRH(H(rho, t1), pre, msg) */ + MLD_ALIGN uint8_t hpk[MLDSA_CRHBYTES]; + mld_H(hpk, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES, NULL, 0, NULL, + 0); + mld_H(mu, MLDSA_CRHBYTES, hpk, MLDSA_TRBYTES, pre, prelen, m, mlen); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(hpk, sizeof(hpk)); + } + else + { + /* mu has been provided directly */ + mld_memcpy(mu, m, MLDSA_CRHBYTES); + } + + /* Matrix-vector multiplication; compute Az - c2^dt1 */ + mld_poly_challenge(cp, c); + mld_poly_ntt(cp); + mld_polyveck_shiftl(t1); + mld_polyveck_ntt(t1); + mld_polyveck_pointwise_poly_montgomery(tmp, cp, t1); + + mld_polyvec_matrix_expand(mat, rho); + mld_polyvecl_ntt(z); + mld_polyvec_matrix_pointwise_montgomery(w1, mat, z); + mld_polyveck_sub(w1, tmp); + mld_polyveck_reduce(w1); + mld_polyveck_invntt_tomont(w1); + + /* Reconstruct w1 */ + mld_polyveck_caddq(w1); + mld_polyveck_use_hint(tmp, w1, h); + mld_polyveck_pack_w1(buf, tmp); + /* Call random oracle and verify challenge */ + mld_H(c2, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, buf, + MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0); + + cmp = mld_ct_memcmp(c, c2, MLDSA_CTILDEBYTES); + + /* Declassify the result of the verification. */ + MLD_CT_TESTING_DECLASSIFY(&cmp, sizeof(cmp)); + + ret = cmp == 0 ? 0 : MLD_ERR_FAIL; + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(h, mld_polyveck, 1, context); + MLD_FREE(tmp, mld_polyveck, 1, context); + MLD_FREE(t1w1, t1w1_u, 1, context); + MLD_FREE(z, mld_polyvecl, 1, context); + MLD_FREE(mat, mld_polymat, 1, context); + MLD_FREE(cp, mld_poly, 1, context); + MLD_FREE(c2, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(c, uint8_t, MLDSA_CTILDEBYTES, context); + MLD_FREE(mu, uint8_t, MLDSA_CRHBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen, + MLD_PREHASH_NONE); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, m, mlen, pre, pre_len, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + return mld_sign_verify_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0, pk, + 1, context); +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + int ret; + size_t i; + + if (smlen < MLDSA_CRYPTO_BYTES) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + *mlen = smlen - MLDSA_CRYPTO_BYTES; + ret = mld_sign_verify(sm, MLDSA_CRYPTO_BYTES, sm + MLDSA_CRYPTO_BYTES, *mlen, + ctx, ctxlen, pk, context); + if (ret == 0) + { + /* All good, copy msg, return 0 */ + for (i = 0; i < *mlen; ++i) + __loop__( + assigns(i, memory_slice(m, *mlen)) + invariant(i <= *mlen) + ) + { + m[i] = sm[MLDSA_CRYPTO_BYTES + i]; + } + } + +cleanup: + + if (ret != 0) + { + /* To be on the safe-side, we zeroize the message buffer. */ + *mlen = 0; + mld_memset(m, 0, smlen); + } + + return ret; +} + + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_signature_internal(sig, siglen, pre, pre_len, NULL, 0, rnd, sk, + 0, context); +cleanup: + if (ret != 0) + { + /* To be on the safe-side, make sure *siglen and sig have a well-defined + * value, even in the case of error. + * + * If we come from mld_sign_signature_internal, both are redundant, + * but the error case should not be the norm, and the added cost of the + * memset insignificant. */ + *siglen = 0; + mld_memset(sig, 0, MLDSA_CRYPTO_BYTES); + } + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + int ret; + + pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen, + hashalg); + if (pre_len == 0) + { + ret = MLD_ERR_FAIL; + goto cleanup; + } + + ret = mld_sign_verify_internal(sig, siglen, pre, pre_len, NULL, 0, pk, 0, + context); + +cleanup: + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(pre, sizeof(pre)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_signature_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, rnd, sk, + MLD_PREHASH_SHAKE_256, context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + MLD_ALIGN uint8_t ph[64]; + int ret; + mld_shake256(ph, sizeof(ph), m, mlen); + ret = mld_sign_verify_pre_hash_internal(sig, siglen, ph, sizeof(ph), ctx, + ctxlen, pk, MLD_PREHASH_SHAKE_256, + context); + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + mld_zeroize(ph, sizeof(ph)); + return ret; +} + + +#define MLD_PRE_HASH_OID_LEN 11 + +/************************************************* + * Name: mld_get_hash_oid + * + * Description: Returns the OID of a given SHA-2/SHA-3 hash function. + * + * Arguments: - uint8_t oid[11]: pointer to output oid + * - int hashalg: hash algorithm constant (MLD_PREHASH_*) + * + ***************************************************/ +static void mld_get_hash_oid(uint8_t oid[MLD_PRE_HASH_OID_LEN], int hashalg) +{ + unsigned int i; + static const struct + { + int alg; + uint8_t oid[MLD_PRE_HASH_OID_LEN]; + } oid_map[] = { + {MLD_PREHASH_SHA2_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}}, + {MLD_PREHASH_SHA2_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}}, + {MLD_PREHASH_SHA2_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}}, + {MLD_PREHASH_SHA2_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}}, + {MLD_PREHASH_SHA2_512_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05}}, + {MLD_PREHASH_SHA2_512_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06}}, + {MLD_PREHASH_SHA3_224, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07}}, + {MLD_PREHASH_SHA3_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08}}, + {MLD_PREHASH_SHA3_384, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09}}, + {MLD_PREHASH_SHA3_512, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A}}, + {MLD_PREHASH_SHAKE_128, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B}}, + {MLD_PREHASH_SHAKE_256, + {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C}}}; + + for (i = 0; i < sizeof(oid_map) / sizeof(oid_map[0]); i++) + __loop__( + invariant(i <= sizeof(oid_map) / sizeof(oid_map[0])) + ) + { + if (oid_map[i].alg == hashalg) + { + mld_memcpy(oid, oid_map[i].oid, MLD_PRE_HASH_OID_LEN); + return; + } + } +} + +static int mld_validate_hash_length(int hashalg, size_t len) +{ + switch (hashalg) + { + case MLD_PREHASH_SHA2_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA2_512_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_224: + return (len == 224 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_256: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_384: + return (len == 384 / 8) ? 0 : -1; + case MLD_PREHASH_SHA3_512: + return (len == 512 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_128: + return (len == 256 / 8) ? 0 : -1; + case MLD_PREHASH_SHAKE_256: + return (len == 512 / 8) ? 0 : -1; + } + return -1; +} + +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +{ + if (ctxlen > 255) + { + return 0; + } + + if (hashalg != MLD_PREHASH_NONE) + { + if (ph == NULL || mld_validate_hash_length(hashalg, phlen) != 0) + { + return 0; + } + } + + /* Common prefix: 0x00/0x01 || ctxlen || ctx */ + prefix[0] = (hashalg == MLD_PREHASH_NONE) ? 0 : 1; + prefix[1] = (uint8_t)ctxlen; + if (ctxlen > 0) + { + mld_memcpy(prefix + 2, ctx, ctxlen); + } + + if (hashalg == MLD_PREHASH_NONE) + { + return 2 + ctxlen; + } + + /* HashML-DSA: append oid || ph */ + mld_get_hash_oid(prefix + 2 + ctxlen, hashalg); + mld_memcpy(prefix + 2 + ctxlen + MLD_PRE_HASH_OID_LEN, ph, phlen); + return 2 + ctxlen + MLD_PRE_HASH_OID_LEN + phlen; +} + +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +{ + uint8_t check, cmp0, cmp1, chk1, chk2; + int ret; + MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_ALLOC(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_ALLOC(s1, mld_polyvecl, 1, context); + MLD_ALLOC(s2, mld_polyveck, 1, context); + MLD_ALLOC(t0, mld_polyveck, 1, context); + MLD_ALLOC(t0_computed, mld_polyveck, 1, context); + MLD_ALLOC(t1, mld_polyveck, 1, context); + + if (rho == NULL || tr == NULL || tr_computed == NULL || key == NULL || + s1 == NULL || s2 == NULL || t0 == NULL || t0_computed == NULL || + t1 == NULL) + { + ret = MLD_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* Unpack secret key */ + mld_unpack_sk(rho, tr, key, t0, s1, s2, sk); + + /* Validate s1 and s2 coefficients are within [-MLDSA_ETA, MLDSA_ETA] */ + chk1 = mld_polyvecl_chknorm(s1, MLDSA_ETA + 1) & 0xFF; + chk2 = mld_polyveck_chknorm(s2, MLDSA_ETA + 1) & 0xFF; + + /* Recompute t0, t1, tr, and pk from rho, s1, s2 */ + ret = mld_compute_t0_t1_tr_from_sk_components(t0_computed, t1, tr_computed, + pk, rho, s1, s2, context); + if (ret != 0) + { + goto cleanup; + } + + /* Validate t0 and tr using constant-time comparisons */ + cmp0 = mld_ct_memcmp((const uint8_t *)t0, (const uint8_t *)t0_computed, + sizeof(mld_polyveck)); + cmp1 = mld_ct_memcmp((const uint8_t *)tr, (const uint8_t *)tr_computed, + MLDSA_TRBYTES); + check = mld_value_barrier_u8(cmp0 | cmp1 | chk1 | chk2); + + /* Declassify the final result of the validity check. */ + MLD_CT_TESTING_DECLASSIFY(&check, sizeof(check)); + ret = (check != 0) ? MLD_ERR_FAIL : 0; + +cleanup: + + if (ret != 0) + { + mld_zeroize(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + } + + /* Constant time: pk is either the valid public key or zeroed on error */ + MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); + + /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ + MLD_FREE(t1, mld_polyveck, 1, context); + MLD_FREE(t0_computed, mld_polyveck, 1, context); + MLD_FREE(t0, mld_polyveck, 1, context); + MLD_FREE(s2, mld_polyveck, 1, context); + MLD_FREE(s1, mld_polyvecl, 1, context); + MLD_FREE(key, uint8_t, MLDSA_SEEDBYTES, context); + MLD_FREE(tr_computed, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context); + + return ret; +} + +/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. + * Don't modify by hand -- this is auto-generated by scripts/autogen. */ +#undef mld_check_pct +#undef mld_sample_s1_s2 +#undef mld_validate_hash_length +#undef mld_get_hash_oid +#undef mld_H +#undef mld_compute_pack_z +#undef mld_attempt_signature_generation +#undef mld_compute_t0_t1_tr_from_sk_components +#undef MLD_NONCE_UB +#undef MLD_PRE_HASH_OID_LEN diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/sign.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/sign.h new file mode 100644 index 0000000000..2e0bac32ea --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/sign.h @@ -0,0 +1,807 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +#ifndef MLD_SIGN_H +#define MLD_SIGN_H + +#include +#include +#include "cbmc.h" +#include "common.h" +#include "poly.h" +#include "polyvec.h" +#include "sys.h" + +#if defined(MLD_CHECK_APIS) +/* Include to ensure consistency between internal sign.h + * and external mldsa_native.h. */ +#include "mldsa_native.h" + +#if MLDSA_CRYPTO_SECRETKEYBYTES != \ + MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for SECRETKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_PUBLICKEYBYTES != \ + MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for PUBLICKEYBYTES between sign.h and mldsa_native.h +#endif + +#if MLDSA_CRYPTO_BYTES != MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) +#error Mismatch for CRYPTO_BYTES between sign.h and mldsa_native.h +#endif + +#endif /* MLD_CHECK_APIS */ + +#define mld_sign_keypair_internal \ + MLD_NAMESPACE_KL(keypair_internal) MLD_CONTEXT_PARAMETERS_3 +#define mld_sign_keypair MLD_NAMESPACE_KL(keypair) MLD_CONTEXT_PARAMETERS_2 +#define mld_sign_signature_internal \ + MLD_NAMESPACE_KL(signature_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_signature MLD_NAMESPACE_KL(signature) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_extmu \ + MLD_NAMESPACE_KL(signature_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign MLD_NAMESPACE_KL(sign) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_internal \ + MLD_NAMESPACE_KL(verify_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify MLD_NAMESPACE_KL(verify) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_verify_extmu \ + MLD_NAMESPACE_KL(verify_extmu) MLD_CONTEXT_PARAMETERS_4 +#define mld_sign_open MLD_NAMESPACE_KL(open) MLD_CONTEXT_PARAMETERS_7 +#define mld_sign_signature_pre_hash_internal \ + MLD_NAMESPACE_KL(signature_pre_hash_internal) MLD_CONTEXT_PARAMETERS_9 +#define mld_sign_verify_pre_hash_internal \ + MLD_NAMESPACE_KL(verify_pre_hash_internal) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_signature_pre_hash_shake256 \ + MLD_NAMESPACE_KL(signature_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_8 +#define mld_sign_verify_pre_hash_shake256 \ + MLD_NAMESPACE_KL(verify_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_7 +#define mld_prepare_domain_separation_prefix \ + MLD_NAMESPACE_KL(prepare_domain_separation_prefix) +#define mld_sign_pk_from_sk \ + MLD_NAMESPACE_KL(pk_from_sk) MLD_CONTEXT_PARAMETERS_2 + +/************************************************* + * Hash algorithm constants for domain separation + **************************************************/ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/************************************************* + * Name: mld_sign_keypair_internal + * + * Description: Generates public and private key. Internal API. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * - const uint8_t seed[MLDSA_SEEDBYTES]: input random seed + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + const uint8_t seed[MLDSA_SEEDBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires(memory_no_alias(seed, MLDSA_SEEDBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_keypair + * + * Description: Generates public and private key. + * When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise + * Consistency Test (PCT) as required by FIPS 140-3 IG. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure + * if MLD_CONFIG_KEYGEN_PCT is enabled. + * + * Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) +); + +/************************************************* + * Name: mld_sign_signature_internal + * + * Description: Computes signature. Internal API. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int externalmu: indicates input message m is + * processed as mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * If the returned value is non-zero, then the values of *sig and + * *siglen should not be referenced. + * + * Reference: This code differs from the reference implementation + * in that it adds an explicit check for nonce exhaustion + * and can return MLD_ERR_FAIL in that case. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *pre, size_t prelen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + requires((externalmu == 0 && (prelen == 0 || memory_no_alias(pre, prelen))) || + (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || + return_value == MLD_ERR_OUT_OF_MEMORY) + ensures(return_value == 0 ==> *siglen == MLDSA_CRYPTO_BYTES) + ensures(return_value != 0 ==> *siglen == 0) +); + +/************************************************* + * Name: mld_sign_signature + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string. + * Should be <= 255. + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t *m, size_t mlen, const uint8_t *ctx, + size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_signature_extmu + * + * Description: Computes signature. This function implements the randomized + * variant of ML-DSA. If you require the deterministic variant, + * use mld_sign_signature_internal directly. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature + * - size_t *siglen: pointer to output length of + * signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu to be signed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_RNG_FAIL: Random number generation failed. + * - MLD_ERR_FAIL: Other kinds of failure. + * + * Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign + * + * Description: Compute signed message. + * + * Arguments: - uint8_t *sm: pointer to output signed message + * (allocated array with MLDSA_CRYPTO_BYTES + + *mlen bytes), can be equal to m + * - size_t *smlen: pointer to output length of signed message + * - const uint8_t *m: pointer to message to be signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sm, MLDSA_CRYPTO_BYTES + mlen)) + requires(memory_no_alias(smlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(m, mlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sm, MLDSA_CRYPTO_BYTES + mlen)) + assigns(object_whole(smlen)) + ensures((return_value == 0 && *smlen == MLDSA_CRYPTO_BYTES + mlen) || + (return_value == MLD_ERR_FAIL + || return_value == MLD_ERR_OUT_OF_MEMORY + || return_value == MLD_ERR_RNG_FAIL)) +); + +/************************************************* + * Name: mld_sign_verify_internal + * + * Description: Verifies signature. Internal API. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *pre: pointer to prefix string + * - size_t prelen: length of prefix string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int externalmu: indicates input message m is processed as + * mu + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_internal(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, const uint8_t *pre, + size_t prelen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + int externalmu, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(prelen <= MLD_MAX_BUFFER_SIZE) + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(externalmu == 0 || (externalmu == 1 && mlen == MLDSA_CRHBYTES)) + requires(externalmu == 1 || prelen == 0 || memory_no_alias(pre, prelen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string. + * May be NULL if ctxlen == 0. + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_verify_extmu + * + * Description: Verifies signature. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t mu[MLDSA_CRHBYTES]: + * input mu + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu + * variant)] + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen, + const uint8_t mu[MLDSA_CRHBYTES], + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(mu, MLDSA_CRHBYTES)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_open + * + * Description: Verify signed message. + * + * Arguments: - uint8_t *m: pointer to output message (allocated array + * with smlen bytes), can be equal to sm + * - size_t *mlen: pointer to output length of message + * - const uint8_t *sm: pointer to signed message + * - size_t smlen: length of signed message + * - const uint8_t *ctx: pointer to context tring + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(smlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(m, smlen)) + requires(memory_no_alias(mlen, sizeof(size_t))) + requires(m == sm || memory_no_alias(sm, smlen)) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + assigns(memory_slice(m, smlen)) + assigns(memory_slice(mlen, sizeof(size_t))) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_internal + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_signature_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_internal( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_internal + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *ph: pointer to pre-hashed message + * - size_t phlen: length of pre-hashed message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * - int hashalg: hash algorithm constant (one of + * MLD_PREHASH_*) + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + * Supported hash algorithm constants: + * MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384, + * MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256, + * MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384, + * MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256 + * + * Warning: This is an unstable API that may change in the future. If you need + * a stable API use mld_sign_verify_pre_hash_shake256. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_internal( + const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg, + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(ph, phlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/************************************************* + * Name: mld_sign_signature_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256. + * Computes signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + *internally. + * + * Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: + * output signature + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed and signed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t rnd[MLDSA_RNDBYTES]: + * random seed + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: + * bit-packed secret key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Other kinds of failure + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_signature_pre_hash_shake256( + uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m, + size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) || + ((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0)) +); + +/************************************************* + * Name: mld_sign_verify_pre_hash_shake256 + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256. + * Verifies signature with pre-hashed message using SHAKE256. + * This function computes the SHAKE256 hash of the message + * internally. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed and + * verified + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: + * bit-packed public key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Signature verification failed + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_verify_pre_hash_shake256( + const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); + +/* Maximum formatted domain separation message length: + * - Pure ML-DSA: 0x00 || ctxlen || ctx (max 255) + * - HashML-DSA: 0x01 || ctxlen || ctx (max 255) || oid (11) || ph (max 64) */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/************************************************* + * Name: mld_prepare_domain_separation_prefix + * + * Description: Prepares domain separation prefix for ML-DSA signing. + * For pure ML-DSA (hashalg == MLD_PREHASH_NONE): + * Format: 0x00 || ctxlen (1 byte) || ctx + * For HashML-DSA (hashalg != MLD_PREHASH_NONE): + * Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph + * + * Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]: + * output domain separation prefix buffer + * - const uint8_t *ph: pointer to pre-hashed message + * (ignored for pure ML-DSA) + * - size_t phlen: length of pre-hashed message + * (ignored for pure ML-DSA) + * - const uint8_t *ctx: pointer to context string (may be NULL) + * - size_t ctxlen: length of context string + * - int hashalg: hash algorithm constant + * (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for + * HashML-DSA) + * + * Returns the total length of the formatted prefix, or 0 on error. + * + * This function is useful for building incremental signing APIs. + * + * Specification: + * - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements + * @[FIPS204, Algorithm 4, L23] + * - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements + * ``` + * M' <- BytesToBits(IntegerToBytes(0, 1) + * || IntegerToBytes(|ctx|, 1) + * || ctx + * ``` + * which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and + * @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5]. + * + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +size_t mld_prepare_domain_separation_prefix( + uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph, + size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg) +__contract__( + requires(ctxlen <= 255) + requires(phlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen)) + requires(hashalg == MLD_PREHASH_NONE || memory_no_alias(ph, phlen)) + requires(memory_no_alias(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + assigns(memory_slice(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES)) + ensures(return_value <= MLD_DOMAIN_SEPARATION_MAX_BYTES) +); + +/************************************************* + * Name: mld_sign_pk_from_sk + * + * Description: Performs basic validity checks on secret key, and derives + * public key. + * + * Referring to the decoding of the secret key + * `sk=(rho, K, tr, s1, s2, t0)` + * (cf. [@FIPS204, Algorithm 25 skDecode]), + * the following checks are performed: + * - Check that s1 and s2 have coefficients in + * [-MLDSA_ETA, MLDSA_ETA] + * - Check that t0 and tr stored in sk match recomputed values. + * + * Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key + * - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: input secret + * key + * + * Returns: - 0: Success + * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is + * used and an allocation via MLD_CUSTOM_ALLOC returned NULL. + * - MLD_ERR_FAIL: Secret key validation failed + * + * Note: This function leaks whether the secret key is valid or invalid + * through its return value and timing. + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], + MLD_CONFIG_CONTEXT_PARAMETER_TYPE context) +__contract__( + requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) + assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES)) + ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) +); +#endif /* !MLD_SIGN_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/symmetric.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/symmetric.h new file mode 100644 index 0000000000..bb70f05552 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/symmetric.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef MLD_SYMMETRIC_H +#define MLD_SYMMETRIC_H + +#include +#include "cbmc.h" +#include "common.h" + +#include MLD_FIPS202_HEADER_FILE +#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) +#include MLD_FIPS202X4_HEADER_FILE +#endif + +#define MLD_STREAM128_BLOCKBYTES SHAKE128_RATE +#define MLD_STREAM256_BLOCKBYTES SHAKE256_RATE + +#define mld_xof256_ctx mld_shake256ctx +#define mld_xof256_init(CTX) mld_shake256_init(CTX) + +#define mld_xof256_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake256_absorb(CTX, IN, INBYTES); \ + mld_shake256_finalize(CTX); \ + } while (0) + + +#define mld_xof256_release(CTX) mld_shake256_release(CTX) +#define mld_xof256_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake256_squeeze(OUT, (OUTBLOCKS) * SHAKE256_RATE, STATE) + +#define mld_xof128_ctx mld_shake128ctx +#define mld_xof128_init(CTX) mld_shake128_init(CTX) + +#define mld_xof128_absorb_once(CTX, IN, INBYTES) \ + do \ + { \ + mld_shake128_absorb(CTX, IN, INBYTES); \ + mld_shake128_finalize(CTX); \ + } while (0) + +#define mld_xof128_release(CTX) mld_shake128_release(CTX) +#define mld_xof128_squeezeblocks(OUT, OUTBLOCKS, STATE) \ + mld_shake128_squeeze(OUT, (OUTBLOCKS) * SHAKE128_RATE, STATE) + +#define mld_xof256_x4_ctx mld_shake256x4ctx +#define mld_xof256_x4_init(CTX) mld_shake256x4_init((CTX)) +#define mld_xof256_x4_absorb(CTX, IN, INBYTES) \ + mld_shake256x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof256_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake256x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof256_x4_release(CTX) mld_shake256x4_release((CTX)) + +#define mld_xof128_x4_ctx mld_shake128x4ctx +#define mld_xof128_x4_init(CTX) mld_shake128x4_init((CTX)) +#define mld_xof128_x4_absorb(CTX, IN, INBYTES) \ + mld_shake128x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \ + (INBYTES)) +#define mld_xof128_x4_squeezeblocks(BUF, NBLOCKS, CTX) \ + mld_shake128x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \ + (NBLOCKS), (CTX)) +#define mld_xof128_x4_release(CTX) mld_shake128x4_release((CTX)) + +#endif /* !MLD_SYMMETRIC_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/sys.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/sys.h new file mode 100644 index 0000000000..1226526420 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/sys.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) The mlkem-native project authors + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_SYS_H +#define MLD_SYS_H + +#if !defined(MLD_CONFIG_NO_ASM) && (defined(__GNUC__) || defined(__clang__)) +#define MLD_HAVE_INLINE_ASM +#endif + +/* Try to find endianness, if not forced through CFLAGS already */ +#if !defined(MLD_SYS_LITTLE_ENDIAN) && !defined(MLD_SYS_BIG_ENDIAN) +#if defined(__BYTE_ORDER__) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define MLD_SYS_LITTLE_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define MLD_SYS_BIG_ENDIAN +#else +#error "__BYTE_ORDER__ defined, but don't recognize value." +#endif +#endif /* __BYTE_ORDER__ */ + +/* MSVC does not define __BYTE_ORDER__. However, MSVC only supports + * little endian x86, x86_64, and AArch64. It is, hence, safe to assume + * little endian. */ +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_IX86) || defined(_M_ARM64)) +#define MLD_SYS_LITTLE_ENDIAN +#endif + +#endif /* !MLD_SYS_LITTLE_ENDIAN && !MLD_SYS_BIG_ENDIAN */ + +/* Check if we're running on an AArch64 little endian system. _M_ARM64 is set by + * MSVC. */ +#if defined(__AARCH64EL__) || defined(_M_ARM64) +#define MLD_SYS_AARCH64 +#endif + +/* Check if we're running on an AArch64 big endian system. */ +#if defined(__AARCH64EB__) +#define MLD_SYS_AARCH64_EB +#endif + +#if defined(__x86_64__) +#define MLD_SYS_X86_64 +#if defined(__AVX2__) +#define MLD_SYS_X86_64_AVX2 +#endif +#endif /* __x86_64__ */ + +#if defined(MLD_SYS_LITTLE_ENDIAN) && defined(__powerpc64__) +#define MLD_SYS_PPC64LE +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 +#define MLD_SYS_RISCV64 +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32 +#define MLD_SYS_RISCV32 +#endif + +#if defined(_WIN64) || defined(_WIN32) +#define MLD_SYS_WINDOWS +#endif + +#if defined(__linux__) +#define MLD_SYS_LINUX +#endif + +#if defined(__APPLE__) +#define MLD_SYS_APPLE +#endif + +/* If MLD_FORCE_AARCH64 is set, assert that we're indeed on an AArch64 system. + */ +#if defined(MLD_FORCE_AARCH64) && !defined(MLD_SYS_AARCH64) +#error "MLD_FORCE_AARCH64 is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_AARCH64_EB is set, assert that we're indeed on a big endian + * AArch64 system. */ +#if defined(MLD_FORCE_AARCH64_EB) && !defined(MLD_SYS_AARCH64_EB) +#error \ + "MLD_FORCE_AARCH64_EB is set, but we don't seem to be on an AArch64 system." +#endif + +/* If MLD_FORCE_X86_64 is set, assert that we're indeed on an X86_64 system. */ +#if defined(MLD_FORCE_X86_64) && !defined(MLD_SYS_X86_64) +#error "MLD_FORCE_X86_64 is set, but we don't seem to be on an X86_64 system." +#endif + +#if defined(MLD_FORCE_PPC64LE) && !defined(MLD_SYS_PPC64LE) +#error "MLD_FORCE_PPC64LE is set, but we don't seem to be on a PPC64LE system." +#endif + +#if defined(MLD_FORCE_RISCV64) && !defined(MLD_SYS_RISCV64) +#error "MLD_FORCE_RISCV64 is set, but we don't seem to be on a RISCV64 system." +#endif + +#if defined(MLD_FORCE_RISCV32) && !defined(MLD_SYS_RISCV32) +#error "MLD_FORCE_RISCV32 is set, but we don't seem to be on a RISCV32 system." +#endif + +/* + * MLD_INLINE: Hint for inlining. + * - MSVC: __inline + * - C99+: inline + * - GCC/Clang C90: __attribute__((unused)) to silence warnings + * - Other C90: empty + */ +#if !defined(MLD_INLINE) +#if defined(_MSC_VER) +#define MLD_INLINE __inline +#elif defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +#define MLD_INLINE inline +#elif defined(__GNUC__) || defined(__clang__) +#define MLD_INLINE __attribute__((unused)) +#else +#define MLD_INLINE +#endif +#endif /* !MLD_INLINE */ + +/* + * MLD_ALWAYS_INLINE: Force inlining. + * - MSVC: __forceinline + * - GCC/Clang C99+: MLD_INLINE __attribute__((always_inline)) + * - Other: MLD_INLINE (no forced inlining) + */ +#if !defined(MLD_ALWAYS_INLINE) +#if defined(_MSC_VER) +#define MLD_ALWAYS_INLINE __forceinline +#elif (defined(__GNUC__) || defined(__clang__)) && \ + (defined(inline) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)) +#define MLD_ALWAYS_INLINE MLD_INLINE __attribute__((always_inline)) +#else +#define MLD_ALWAYS_INLINE MLD_INLINE +#endif +#endif /* !MLD_ALWAYS_INLINE */ + +#ifndef MLD_STATIC_TESTABLE +#define MLD_STATIC_TESTABLE static +#endif + +/* + * C90 does not have the restrict compiler directive yet. + * We don't use it in C90 builds. + */ +#if !defined(restrict) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define MLD_RESTRICT restrict +#else +#define MLD_RESTRICT +#endif + +#else /* !restrict */ + +#define MLD_RESTRICT restrict +#endif /* restrict */ + +#define MLD_DEFAULT_ALIGN 32 +#define MLD_ALIGN_UP(N) \ + ((((N) + (MLD_DEFAULT_ALIGN - 1)) / MLD_DEFAULT_ALIGN) * MLD_DEFAULT_ALIGN) +#if defined(__GNUC__) +#define MLD_ALIGN __attribute__((aligned(MLD_DEFAULT_ALIGN))) +#elif defined(_MSC_VER) +#define MLD_ALIGN __declspec(align(MLD_DEFAULT_ALIGN)) +#else +#define MLD_ALIGN /* No known support for alignment constraints */ +#endif + + +/* New X86_64 CPUs support Conflow-flow protection using the CET instructions. + * When enabled (through -fcf-protection=), all compilation units (including + * empty ones) need to support CET for this to work. + * For assembly, this means that source files need to signal support for + * CET by setting the appropriate note.gnu.property section. + * This can be achieved by including the header in all assembly file. + * This file also provides the _CET_ENDBR macro which needs to be placed at + * every potential target of an indirect branch. + * If CET is enabled _CET_ENDBR maps to the endbr64 instruction, otherwise + * it is empty. + * In case the compiler does not support CET (e.g., +#define MLD_CET_ENDBR _CET_ENDBR +#else +#define MLD_CET_ENDBR +#endif +#endif /* MLD_SYS_X86_64 */ + +#if defined(MLD_CONFIG_CT_TESTING_ENABLED) && !defined(__ASSEMBLER__) +#include +#define MLD_CT_TESTING_SECRET(ptr, len) \ + VALGRIND_MAKE_MEM_UNDEFINED((ptr), (len)) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) +#else /* MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__ */ +#define MLD_CT_TESTING_SECRET(ptr, len) \ + do \ + { \ + } while (0) +#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \ + do \ + { \ + } while (0) +#endif /* !(MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__) */ + +#if defined(__GNUC__) || defined(__clang__) +#define MLD_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result)) +#else +#define MLD_MUST_CHECK_RETURN_VALUE +#endif + + +#if !defined(__ASSEMBLER__) +/* System capability enumeration */ +typedef enum +{ + /* x86_64 */ + MLD_SYS_CAP_AVX2, + /* AArch64 */ + MLD_SYS_CAP_SHA3 +} mld_sys_cap; + +#if !defined(MLD_CONFIG_CUSTOM_CAPABILITY_FUNC) +#include "cbmc.h" + +static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) +__contract__( + ensures(return_value == 0 || return_value == 1) +) +{ + /* By default, we rely on compile-time feature detection/specification: + * If a feature is enabled at compile-time, we assume it is supported by + * the host that the resulting library/binary will be built on. + * If this assumption is not true, you MUST overwrite this function. + * See the documentation of MLD_CONFIG_CUSTOM_CAPABILITY_FUNC in + * mldsa_native_config.h for more information. */ + (void)cap; + return 1; +} +#endif /* !MLD_CONFIG_CUSTOM_CAPABILITY_FUNC */ +#endif /* !__ASSEMBLER__ */ + +#endif /* !MLD_SYS_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/zetas.inc b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/zetas.inc new file mode 100644 index 0000000000..dc3cf15dd3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/mldsa/src/zetas.inc @@ -0,0 +1,56 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +#include + +/* + * Table of zeta values used in the reference NTT and inverse NTT. + * See autogen for details. + */ +static const int32_t mld_zetas[MLDSA_N] = { + 0, 25847, -2608894, -518909, 237124, -777960, -876248, + 466468, 1826347, 2353451, -359251, -2091905, 3119733, -2884855, + 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488, + -1119584, 2619752, -2108549, -2118186, -3859737, -1399561, -3277672, + 1757237, -19422, 4010497, 280005, 2706023, 95776, 3077325, + 3530437, -1661693, -3592148, -2537516, 3915439, -3861115, -3043716, + 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267, + -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596, + 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, + -2797779, -3930395, -1528703, -3677745, -3041255, -1452451, 3475950, + 2176455, -1585221, -1257611, 1939314, -4083598, -1000202, -3190144, + -3157330, -3632928, 126922, 3412210, -983419, 2147896, 2715295, + -2967645, -3693493, -411027, -2477047, -671102, -1228525, -22981, + -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944, + 508951, 3097992, 44288, -1100098, 904516, 3958618, -3724342, + -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856, + 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, + 1341330, 1285669, -1584928, -812732, -1439742, -3019102, -3881060, + -3628969, 3839961, 2091667, 3407706, 2316500, 3817976, -3342478, + 2244091, -2446433, -3562462, 266997, 2434439, -1235728, 3513181, + -3520352, -3759364, -1197226, -3193378, 900702, 1859098, 909542, + 819034, 495491, -1613174, -43260, -522500, -655327, -3122442, + 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297, + 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, + 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, + 1595974, -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, + 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100, + 1312455, 3306115, -1962642, -1279661, 1917081, -2546312, -1374803, + 1500165, 777191, 2235880, 3406031, -542412, -2831860, -1671176, + -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395, + 2454455, -164721, 1957272, 3369112, 185531, -1207385, -3183426, + 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, + -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, + 472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333, + -260646, -3833893, -2939036, -2235985, -420899, -2286327, 183443, + -976891, 1612842, -3545687, -554416, 3919660, -48306, -1362209, + 3937738, 1400424, -846154, 1976782, +}; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/aarch64_be-none-linux-gnu-gcc.nix b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/aarch64_be-none-linux-gnu-gcc.nix new file mode 100644 index 0000000000..728cff226d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/aarch64_be-none-linux-gnu-gcc.nix @@ -0,0 +1,37 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +{ stdenvNoCC +, fetchurl +}: + +stdenvNoCC.mkDerivation rec { + pname = "aarch64_be-none-linux-gnu"; + version = "10.3.2021.07"; + + platform = { + x86_64-linux = "x86_64"; + }.${stdenvNoCC.hostPlatform.system} or (throw "Unsupported system: ${stdenvNoCC.hostPlatform.system}"); + + platform_suffix = { + x86_64-linux = "linux-gnu"; + }.${stdenvNoCC.hostPlatform.system} or (throw "Unsupported system: ${stdenvNoCC.hostPlatform.system}"); + + src = fetchurl { + url = "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64_be-none-linux-gnu.tar.xz"; + sha256 = { + x86_64-linux = "sha256-Y8NMrAfOrddGIOqH8nrxqmpvVcIKW8EWryGlndtramo"; + }.${stdenvNoCC.hostPlatform.system} or (throw "Unsupported system: ${stdenvNoCC.hostPlatform.system}"); + }; + + dontConfigure = true; + dontBuild = true; + dontPatchELF = true; + dontStrip = true; + + installPhase = '' + mkdir -p $out + cp -r * $out + ''; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/cbmc/cbmc-viewer.nix b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/cbmc/cbmc-viewer.nix new file mode 100644 index 0000000000..85cd0e83e1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/cbmc/cbmc-viewer.nix @@ -0,0 +1,28 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +{ python3Packages +, fetchurl +}: + +python3Packages.buildPythonApplication rec { + pname = "cbmc-viewer"; + version = "3.11"; + src = fetchurl { + url = "https://github.com/model-checking/${pname}/releases/download/viewer-${version}/cbmc_viewer-${version}-py3-none-any.whl"; + hash = "sha256-Oy51I64KMbtE8lG8xuFXdK4RvXFvWt4zYKBlcXqwILg="; + }; + format = "wheel"; + dontUseSetuptoolsCheck = true; + + propagatedBuildInputs = [ + python3Packages.voluptuous + python3Packages.setuptools + python3Packages.jinja2 + ]; + + meta = { + description = "CBMC Viewer is a tool that scans the output of CBMC"; + homepage = "https://model-checking.github.io/cbmc-viewer/"; + }; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/cbmc/default.nix b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/cbmc/default.nix new file mode 100644 index 0000000000..be333f2e13 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/cbmc/default.nix @@ -0,0 +1,47 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +{ buildEnv +, cbmc +, fetchFromGitHub +, callPackage +, bitwuzla +, ninja +, cadical +, z3 +, cudd +, replaceVars +, fetchpatch +}: + +buildEnv { + name = "pqcp-cbmc"; + paths = + builtins.attrValues { + cbmc = cbmc.overrideAttrs (old: rec { + version = "6.8.0"; + src = fetchFromGitHub { + owner = "diffblue"; + repo = "cbmc"; + hash = "sha256-PT6AYiwkplCeyMREZnGZA0BKl4ZESRC02/9ibKg7mYU="; + tag = "cbmc-6.8.0"; + }; + }); + litani = callPackage ./litani.nix { }; # 1.29.0 + cbmc-viewer = callPackage ./cbmc-viewer.nix { }; # 3.11 + z3 = z3.overrideAttrs (old: rec { + version = "4.15.3"; + src = fetchFromGitHub { + owner = "Z3Prover"; + repo = "z3"; + rev = "z3-4.15.3"; + hash = "sha256-Lw037Z0t0ySxkgMXkbjNW5CB4QQLRrrSEBsLJqiomZ4="; + }; + }); + + inherit + cadical#2.1.3 + bitwuzla# 0.8.2 + ninja; # 1.12.1 + }; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/cbmc/litani.nix b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/cbmc/litani.nix new file mode 100644 index 0000000000..ca9f9bf453 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/cbmc/litani.nix @@ -0,0 +1,38 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +{ stdenvNoCC +, fetchFromGitHub +, python3Packages +}: + +stdenvNoCC.mkDerivation { + pname = "litani"; + version = "8002c240ef4f424039ed3cc32e076c0234d01768"; + src = fetchFromGitHub { + owner = "awslabs"; + repo = "aws-build-accumulator"; + rev = "8002c240ef4f424039ed3cc32e076c0234d01768"; + sha256 = "sha256-UwF/B6lpsjpQn8SW+tCfOXTp14pNBr2sRGujJH3iPLk="; + }; + dontConfigure = true; + installPhase = '' + mkdir -p $out/bin + install -Dm755 litani $out/bin/litani + cp -r lib $out/bin + cp -r templates $out/bin + ''; + dontStrip = true; + noAuditTmpdir = true; + propagatedBuildInputs = [ + (python3Packages.python.withPackages + (pythonPackages: [ pythonPackages.jinja2 ]) + ) + ]; + + meta = { + description = "Litani metabuild system"; + homepage = "https://awslabs.github.io/aws-build-accumulator/"; + }; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/hol_light/0005-Configure-hol-sh-for-mldsa-native.patch b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/hol_light/0005-Configure-hol-sh-for-mldsa-native.patch new file mode 100644 index 0000000000..8d4883a719 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/hol_light/0005-Configure-hol-sh-for-mldsa-native.patch @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +diff --git a/hol_4.14.sh b/hol_4.14.sh +index 1311255..8b2bc36 100755 +--- a/hol_4.14.sh ++++ b/hol_4.14.sh +@@ -5,7 +5,7 @@ export HOLLIGHT_DIR=__DIR__ + + if [ "$#" -eq 1 ]; then + if [ "$1" == "-pp" ]; then +- echo "camlp5r pa_lexer.cmo pa_extend.cmo q_MLast.cmo -I "__DIR__" pa_j.cmo" ++ echo "camlp5r pa_lexer.cmo pa_extend.cmo q_MLast.cmo -I ${HOLLIGHT_DIR} pa_j.cmo" + exit 0 + elif [ "$1" == "-dir" ]; then + echo "${HOLLIGHT_DIR}" +@@ -32,4 +32,13 @@ if [ "${HOL_ML_PATH}" == "" ]; then + HOL_ML_PATH="${HOLLIGHT_DIR}/hol.ml" + fi + +-${LINE_EDITOR} ${HOLLIGHT_DIR}/ocaml-hol -init ${HOL_ML_PATH} -I ${HOLLIGHT_DIR} ++# Add site-lib directory for topfind ++SITELIB=$(dirname $(ocamlfind query findlib 2>/dev/null) 2>/dev/null) ++ ++# Set HOLLIGHT_LOAD_PATH to include S2N_BIGNUM_DIR and mldsa-native proofs ++export HOLLIGHT_LOAD_PATH="${S2N_BIGNUM_DIR}:${PROOF_DIR_X86_64}:${HOLLIGHT_LOAD_PATH}" ++ ++# Change to mldsa-native proofs directory if set, so define_from_elf can find object files ++[ -n "${PROOF_DIR_X86_64}" ] && cd "${PROOF_DIR_X86_64}" ++ ++${LINE_EDITOR} ${HOLLIGHT_DIR}/ocaml-hol -init ${HOL_ML_PATH} -I ${HOLLIGHT_DIR} ${SITELIB:+-I "$SITELIB"} +diff --git a/hol_4.sh b/hol_4.sh +index 0aaa5c7..5adaf4c 100755 +--- a/hol_4.sh ++++ b/hol_4.sh +@@ -5,7 +5,7 @@ export HOLLIGHT_DIR=__DIR__ + + if [ "$#" -eq 1 ]; then + if [ "$1" == "-pp" ]; then +- echo "camlp5r pa_lexer.cmo pa_extend.cmo q_MLast.cmo -I "__DIR__" pa_j.cmo" ++ echo "camlp5r pa_lexer.cmo pa_extend.cmo q_MLast.cmo -I "${HOLLIGHT_DIR}" pa_j.cmo" + exit 0 + elif [ "$1" == "-dir" ]; then + echo "${HOLLIGHT_DIR}" +@@ -32,4 +32,4 @@ if [ "${HOL_ML_PATH}" == "" ]; then + HOL_ML_PATH="${HOLLIGHT_DIR}/hol.ml" + fi + +-${LINE_EDITOR} ${HOLLIGHT_DIR}/ocaml-hol -I `camlp5 -where` camlp5o.cma -init ${HOL_ML_PATH} -safe-string -I ${HOLLIGHT_DIR} ++${LINE_EDITOR} ${HOLLIGHT_DIR}/ocaml-hol -I $(camlp5 -where) camlp5o.cma -init ${HOL_ML_PATH} -safe-string -I ${HOLLIGHT_DIR} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/hol_light/0006-Add-findlib-to-ocaml-hol.patch b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/hol_light/0006-Add-findlib-to-ocaml-hol.patch new file mode 100644 index 0000000000..9ad62dbb92 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/hol_light/0006-Add-findlib-to-ocaml-hol.patch @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +diff --git a/Makefile b/Makefile +index abc1234..def5678 100644 +--- a/Makefile ++++ b/Makefile +@@ -100,7 +100,7 @@ hol.sh: pa_j.cmo ${HOLSRC} bignum.cmo hol_loader.cmo update_database.ml + if [ `uname` = "Linux" ] || [ `uname` = "Darwin" ] ; then \ + if [ ${OCAML_UNARY_VERSION} = "5" ] || [ ${OCAML_VERSION} = "4.14" ] ; then \ +- ocamlfind ocamlmktop -package zarith -o ocaml-hol zarith.cma bignum.cmo hol_loader.cmo ; \ ++ ocamlfind ocamlmktop -package zarith,findlib -o ocaml-hol zarith.cma bignum.cmo hol_loader.cmo ; \ + sed "s^__DIR__^`pwd`^g; s^__USE_MODULE__^$(HOLLIGHT_USE_MODULE)^g" hol_4.14.sh > hol.sh ; \ + else \ + ocamlmktop -o ocaml-hol nums.cma bignum.cmo hol_loader.cmo ; \ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/hol_light/default.nix b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/hol_light/default.nix new file mode 100644 index 0000000000..77501626a9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/hol_light/default.nix @@ -0,0 +1,35 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +{ hol_light, fetchFromGitHub, writeText, ocamlPackages, ledit, ... }: +hol_light.overrideAttrs (old: { + setupHook = writeText "setup-hook.sh" '' + export HOLDIR="$1/lib/hol_light" + export HOLLIGHT_DIR="$1/lib/hol_light" + export PATH="$1/lib/hol_light:$PATH" + ''; + version = "unstable-2025-09-22"; + src = fetchFromGitHub { + owner = "jrh13"; + repo = "hol-light"; + rev = "bed58fa74649fa74015176f8f90e77f7af5cf8e3"; + hash = "sha256-QDubbUUChvv04239BdcKPSU+E2gdSzqAWfAETK2Xtg0="; + }; + patches = [ + ./0005-Configure-hol-sh-for-mldsa-native.patch + ./0006-Add-findlib-to-ocaml-hol.patch + ]; + propagatedBuildInputs = old.propagatedBuildInputs ++ old.nativeBuildInputs ++ [ ocamlPackages.pcre2 ledit ]; + buildPhase = '' + HOLLIGHT_USE_MODULE=1 make hol.sh + patchShebangs hol.sh + HOLLIGHT_USE_MODULE=1 make + ''; + installPhase = '' + mkdir -p "$out/lib/hol_light" + cp -a . $out/lib/hol_light + sed "s^__DIR__^$out/lib/hol_light^g; s^__USE_MODULE__^1^g" hol_4.14.sh > hol.sh + mv hol.sh $out/lib/hol_light/ + ''; +}) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/hol_light/hol-server.sh b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/hol_light/hol-server.sh new file mode 100644 index 0000000000..7d1ca52ddc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/hol_light/hol-server.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +# +# HOL Light server for programmatic communication +# Based on https://github.com/monadius/hol_server +# +# Usage: hol-server [port] + +set -e + +PORT=${1:-2012} + +# These are replaced by nix +HOL_LIGHT_DIR="@hol_light@/lib/hol_light" +HOL_SERVER_SRC="@hol_server_src@" + +# cd to x86_64 proofs directory if in mldsa-native repo +PROOF_DIR="$(git rev-parse --show-toplevel 2>/dev/null)/proofs/hol_light/x86_64" +[ -d "$PROOF_DIR" ] && cd "$PROOF_DIR" + +echo "Starting HOL Light server on port $PORT..." + +{ + # Load required libraries for server2.ml + echo '#directory "+unix";;' + echo '#directory "+threads";;' + echo '#load "unix.cma";;' + echo '#load "threads.cma";;' + + # Load the server using #use (not loads) for proper evaluation + echo "#use \"$HOL_SERVER_SRC/server2.ml\";;" + + # Start the server + echo "start ~single_connection:false $PORT;;" + + # Keep stdin open for the server to continue running + cat +} | exec "$HOL_LIGHT_DIR/hol.sh" diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/hol_light/hol_server.nix b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/hol_light/hol_server.nix new file mode 100644 index 0000000000..6568e89ed4 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/hol_light/hol_server.nix @@ -0,0 +1,27 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# HOL Light server for programmatic communication +# Based on https://github.com/monadius/hol_server +{ fetchFromGitHub, runCommand, hol_light' }: + +let + hol_server_src = fetchFromGitHub { + owner = "monadius"; + repo = "hol_server"; + rev = "vscode"; + hash = "sha256-o98ule5uuazm36+ppsvX2KCbtVbVwzHxGboUhbbrPCQ="; + }; + + hol_server_start = runCommand "hol-server" { } '' + mkdir -p $out/bin + substitute ${./hol-server.sh} $out/bin/hol-server \ + --replace-fail "@hol_light@" "${hol_light'}" \ + --replace-fail "@hol_server_src@" "${hol_server_src}" + chmod +x $out/bin/hol-server + ''; + +in +{ + inherit hol_server_src hol_server_start; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/m55-an547-arm-none-eabi/default.nix b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/m55-an547-arm-none-eabi/default.nix new file mode 100644 index 0000000000..4f92c3e093 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/m55-an547-arm-none-eabi/default.nix @@ -0,0 +1,38 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +{ stdenvNoCC +, fetchFromGitHub +, writeText +}: + +stdenvNoCC.mkDerivation { + pname = "mldsa-native-m55-an547"; + version = "main-2025-10-02"; + + + # Fetch platform files from pqmx (envs/m55-an547) + src = fetchFromGitHub { + owner = "slothy-optimizer"; + repo = "pqmx"; + rev = "4ed493d3cf2af62a08fd9fe36c3472a0dc50ad9f"; + hash = "sha256-jLIqwknjRwcoDeEAETlMhRqZQ5a3QGCDZX9DENelGeQ="; + }; + + dontBuild = true; + + installPhase = '' + mkdir -p $out/platform/m55-an547/src/platform/ + cp -r envs/m55-an547/src/platform/. $out/platform/m55-an547/src/platform/ + cp integration/*.c $out/platform/m55-an547/src/platform/ + ''; + + setupHook = writeText "setup-hook.sh" '' + export M55_AN547_PATH="$1/platform/m55-an547/src/platform/" + ''; + + meta = { + description = "Platform files for the Cortex-M55 (AN547)"; + homepage = "https://github.com/slothy-optimizer/pqmx"; + }; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/s2n_bignum/default.nix b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/s2n_bignum/default.nix new file mode 100644 index 0000000000..f088007b38 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/s2n_bignum/default.nix @@ -0,0 +1,23 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +{ stdenv, fetchFromGitHub, writeText, ... }: +stdenv.mkDerivation rec { + pname = "s2n_bignum"; + version = "2ab2252b8505e58a7c3392f8ad823782032b61e7"; + src = fetchFromGitHub { + owner = "awslabs"; + repo = "s2n-bignum"; + rev = "${version}"; + hash = "sha256-7lil3jAFo5NiyNOSBYZcRjduXkotV3x4PlxXSKt63M8="; + }; + setupHook = writeText "setup-hook.sh" '' + export S2N_BIGNUM_DIR="$1" + ''; + patches = [ ]; + dontBuild = true; + installPhase = '' + mkdir -p $out + cp -a . $out/ + ''; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/slothy/default.nix b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/slothy/default.nix new file mode 100644 index 0000000000..aae03aac45 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/slothy/default.nix @@ -0,0 +1,51 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +{ stdenvNoCC +, fetchFromGitHub +, python3 +, pkgs +, llvm +, gcc +}: + +let + pythonEnv = python3.withPackages (ps: with ps; [ + ortools + sympy + unicorn + ]); +in +stdenvNoCC.mkDerivation rec { + pname = "slothy-cli"; + version = "08ead1f2e5d07617025e00152d1a701fb1195eb9"; + src = fetchFromGitHub { + owner = "slothy-optimizer"; + repo = "slothy"; + rev = version; + sha256 = "sha256-yZ4ZW2S946VJUNNHlO4hFBNpPfIJpCjNbaWTiLmz/Js="; + }; + + nativeBuildInputs = [ pkgs.makeWrapper ]; + dontConfigure = true; + + installPhase = '' + mkdir -p $out/bin + cp slothy-cli $out/bin/ + cp -r slothy $out/bin + wrapProgram $out/bin/slothy-cli \ + --set DYLD_LIBRARY_PATH ${pythonEnv}/lib \ + --set PYTHONPATH ${pythonEnv}/bin \ + --run exec + ''; + + dontStrip = true; + noAuditTmpdir = true; + propagatedBuildInputs = [ pythonEnv llvm gcc ]; + + meta = { + description = "Slothy: assembly-level superoptimizer"; + homepage = "https://slothy-optimizer.github.io/slothy/"; + }; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/util.nix b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/util.nix new file mode 100644 index 0000000000..5a116ac38c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/util.nix @@ -0,0 +1,166 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +{ pkgs, cbmc, bitwuzla, z3 }: +rec { + glibc-join = p: p.buildPackages.symlinkJoin { + name = "glibc-join"; + paths = [ p.glibc p.glibc.static ]; + }; + + wrap-gcc = p: p.buildPackages.wrapCCWith { + cc = p.buildPackages.gcc.cc; + bintools = p.buildPackages.wrapBintoolsWith { + bintools = p.buildPackages.binutils-unwrapped; + libc = glibc-join p; + }; + }; + + native-gcc = + if pkgs.stdenv.isDarwin + then pkgs.clang + else wrap-gcc pkgs; + + # cross is for determining whether to install the cross toolchain dependencies or not + _toolchains = { cross ? true }: + let + x86_64-gcc = wrap-gcc pkgs.pkgsCross.gnu64; + aarch64-gcc = wrap-gcc pkgs.pkgsCross.aarch64-multiplatform; + riscv64-gcc = wrap-gcc pkgs.pkgsCross.riscv64; + riscv32-gcc = wrap-gcc pkgs.pkgsCross.riscv32; + ppc64le-gcc = wrap-gcc pkgs.pkgsCross.powernv; + arm-embedded-gcc = wrap-gcc pkgs.armToolchain; + aarch64_be-gcc = (pkgs.callPackage ./aarch64_be-none-linux-gnu-gcc.nix { }); + in + # NOTE: + # - native toolchain should be equipped in the shell via `mkShellWithCC` (see `mkShell`) + # - only install extra cross-compiled toolchains if not on darwin or `cross` is specifally set to true + # - providing cross compilation toolchain (x86_64/aarch64-linux) for darwin can be cumbersome + # and won't just work for now + # - equip all toolchains if cross is explicitly set to true + # - On some machines, `native-gcc` needed to be evaluated lastly (placed as the last element of the toolchain list), or else would result in environment variables (CC, AR, ...) overriding issue. + pkgs.lib.optionals cross [ pkgs.qemu x86_64-gcc aarch64-gcc riscv64-gcc riscv32-gcc ppc64le-gcc ] + ++ pkgs.lib.optionals (cross && pkgs.stdenv.isLinux && pkgs.stdenv.isx86_64) [ aarch64_be-gcc ] + ++ pkgs.lib.optionals cross [ native-gcc ] + # git is not available in the nix shell on Darwin. As a workaround we add git as a dependency here. + # Initially, we expected this to be fixed by https://github.com/NixOS/nixpkgs/pull/353893, but that does not seem to be the case. + ++ pkgs.lib.optionals (pkgs.stdenv.isDarwin) [ pkgs.git ] + ++ builtins.attrValues { + inherit (pkgs.python3Packages) sympy pyyaml; + inherit (pkgs) + gnumake + python3; + }; + + # NOTE: idiomatic nix way of properly setting the $CC in a nix shell + mkShellWithCC = cc: attrs: (pkgs.mkShellNoCC.override { stdenv = pkgs.overrideCC pkgs.stdenv cc; }) ( + attrs // { + shellHook = '' + export PATH=$PWD/scripts:$PATH + ''; + } + ); + mkShellNoCC = mkShellWithCC null; + mkShell = mkShellWithCC native-gcc; + + mkShellWithCC' = cc: + mkShellWithCC cc { + packages = [ pkgs.python3 ]; + hardeningDisable = [ "fortify" ]; + }; + mkShellWithCC_valgrind' = cc: + mkShellWithCC cc { + packages = [ pkgs.python3 ] ++ pkgs.lib.optionals (!pkgs.stdenv.isDarwin) [ valgrind_varlat ]; + hardeningDisable = [ "fortify" ]; + }; + + # some customized packages + linters = pkgs.symlinkJoin { + name = "pqcp-linters"; + paths = builtins.attrValues { + clang-tools = pkgs.clang-tools.overrideAttrs { + unwrapped = pkgs.llvmPackages.clang-unwrapped; + }; + + inherit (pkgs.llvmPackages) + bintools; + + inherit (pkgs) + nixpkgs-fmt + shfmt; + + inherit (pkgs.python3Packages) + mpmath sympy black pyparsing pyyaml rich; + }; + }; + + cbmc_pkgs = pkgs.callPackage ./cbmc { + inherit cbmc bitwuzla z3; + }; + + valgrind_varlat = pkgs.callPackage ./valgrind { }; + hol_light' = pkgs.callPackage ./hol_light { }; + hol_server = pkgs.callPackage ./hol_light/hol_server.nix { inherit hol_light'; }; + s2n_bignum = pkgs.callPackage ./s2n_bignum { }; + slothy = pkgs.callPackage ./slothy { }; + m55-an547 = pkgs.callPackage ./m55-an547-arm-none-eabi { }; + + # Helper function to build individual cross toolchains + _individual_toolchain = { name, cross_compilers }: + let + common_deps = builtins.attrValues + { + inherit (pkgs.python3Packages) sympy pyyaml; + inherit (pkgs) + gnumake + python3 + qemu; + } ++ pkgs.lib.optionals (pkgs.stdenv.isDarwin) [ pkgs.git ]; + in + pkgs.symlinkJoin { + name = "toolchain-${name}"; + paths = cross_compilers ++ common_deps ++ [ native-gcc ]; + }; + + # Individual cross toolchains + toolchain_x86_64 = _individual_toolchain { + name = "x86_64"; + cross_compilers = [ (wrap-gcc pkgs.pkgsCross.gnu64) ]; + }; + + toolchain_aarch64 = _individual_toolchain { + name = "aarch64"; + cross_compilers = [ (wrap-gcc pkgs.pkgsCross.aarch64-multiplatform) ]; + }; + + toolchain_riscv64 = _individual_toolchain { + name = "riscv64"; + cross_compilers = [ (wrap-gcc pkgs.pkgsCross.riscv64) ]; + }; + + toolchain_riscv32 = _individual_toolchain { + name = "riscv32"; + cross_compilers = [ (wrap-gcc pkgs.pkgsCross.riscv32) ]; + }; + + toolchain_ppc64le = _individual_toolchain { + name = "ppc64le"; + cross_compilers = [ (wrap-gcc pkgs.pkgsCross.powernv) ]; + }; + + toolchain_aarch64_be = _individual_toolchain { + name = "aarch64_be"; + cross_compilers = pkgs.lib.optionals (pkgs.stdenv.isLinux && pkgs.stdenv.isx86_64) [ (pkgs.callPackage ./aarch64_be-none-linux-gnu-gcc.nix { }) ]; + }; + + toolchains = pkgs.symlinkJoin { + name = "toolchains"; + paths = _toolchains { }; + }; + + toolchains_native = pkgs.symlinkJoin { + name = "toolchains-native"; + paths = _toolchains { cross = false; }; + }; +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/valgrind/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/valgrind/README.md new file mode 100644 index 0000000000..ca6a91bcab --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/valgrind/README.md @@ -0,0 +1,10 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +This patch to Valgrind allows detecting secret-dependent division +instructions by flagging variable-latency instruction depending +on uninitialized data. + +It is part of the KyberSlash paper[^KyberSlash]. + + +[^KyberSlash]: Bernstein, Bhargavan, Bhasin, Chattopadhyay, Chia, Kannwischer, Kiefer, Paiva, Ravi, Tamvada: KyberSlash: Exploiting secret-dependent division timings in Kyber implementations, [https://kyberslash.cr.yp.to/papers.html](https://kyberslash.cr.yp.to/papers.html) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/valgrind/default.nix b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/valgrind/default.nix new file mode 100644 index 0000000000..9e49a6381d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/valgrind/default.nix @@ -0,0 +1,10 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +{ valgrind, ... }: +valgrind.overrideAttrs (_: { + patches = [ + ./valgrind-varlat-patch-20240808.txt + ]; +}) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/valgrind/valgrind-varlat-patch-20240808.txt b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/valgrind/valgrind-varlat-patch-20240808.txt new file mode 100644 index 0000000000..43826afab2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/nix/valgrind/valgrind-varlat-patch-20240808.txt @@ -0,0 +1,932 @@ +# SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT +diff --git a/memcheck/mc_errors.c b/memcheck/mc_errors.c +index a708b3f85..8d163cd90 100644 +--- a/memcheck/mc_errors.c ++++ b/memcheck/mc_errors.c +@@ -94,11 +94,14 @@ struct _MC_Error { + // Use of an undefined value: + // - as a pointer in a load or store + // - as a jump target ++ // - (VARLAT mode) as an operand in a variable-latency instruction + struct { + SizeT szB; // size of value in bytes + // Origin info + UInt otag; // origin tag + ExeContext* origin_ec; // filled in later ++ // VARLAT mode ++ Bool isLatency; // if issue is variable-latency instruction + } Value; + + // Use of an undefined value in a conditional branch or move. +@@ -489,8 +492,13 @@ void MC_(pp_Error) ( const Error* err ) + MC_(any_value_errors) = True; + if (xml) { + emit( " UninitValue\n" ); +- emit( " Use of uninitialised value of size %lu\n", +- extra->Err.Value.szB ); ++ if (extra->Err.Value.isLatency) ++ emit( " Variable-latency instruction operand" ++ " of size %lu is secret/uninitialised\n", ++ extra->Err.Value.szB ); ++ else ++ emit( " Use of uninitialised value of size %lu\n", ++ extra->Err.Value.szB ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + if (extra->Err.Value.origin_ec) + mc_pp_origin( extra->Err.Value.origin_ec, +@@ -498,8 +506,13 @@ void MC_(pp_Error) ( const Error* err ) + } else { + /* Could also show extra->Err.Cond.otag if debugging origin + tracking */ +- emit( "Use of uninitialised value of size %lu\n", +- extra->Err.Value.szB ); ++ if (extra->Err.Value.isLatency) ++ emit( "Variable-latency instruction operand" ++ " of size %lu is secret/uninitialised\n", ++ extra->Err.Value.szB ); ++ else ++ emit( "Use of uninitialised value of size %lu\n", ++ extra->Err.Value.szB ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + if (extra->Err.Value.origin_ec) + mc_pp_origin( extra->Err.Value.origin_ec, +@@ -926,6 +939,20 @@ void MC_(record_value_error) ( ThreadId tid, Int szB, UInt otag ) + extra.Err.Value.szB = szB; + extra.Err.Value.otag = otag; + extra.Err.Value.origin_ec = NULL; /* Filled in later */ ++ extra.Err.Value.isLatency = False; ++ VG_(maybe_record_error)( tid, Err_Value, /*addr*/0, /*s*/NULL, &extra ); ++} ++ ++void MC_(record_varlat_value_error) ( ThreadId tid, Int szB, UInt otag ) ++{ ++ MC_Error extra; ++ tl_assert( MC_(clo_mc_level) >= 2 ); ++ if (otag > 0) ++ tl_assert( MC_(clo_mc_level) == 3 ); ++ extra.Err.Value.szB = szB; ++ extra.Err.Value.otag = otag; ++ extra.Err.Value.origin_ec = NULL; /* Filled in later */ ++ extra.Err.Value.isLatency = True; + VG_(maybe_record_error)( tid, Err_Value, /*addr*/0, /*s*/NULL, &extra ); + } + +diff --git a/memcheck/mc_include.h b/memcheck/mc_include.h +index acc595a74..2578cccb0 100644 +--- a/memcheck/mc_include.h ++++ b/memcheck/mc_include.h +@@ -525,6 +525,10 @@ void MC_(pp_LossRecord)(UInt n_this_record, UInt n_total_records, + rerun with --track-origins=yes might help. */ + extern Bool MC_(any_value_errors); + ++/* Are we running in VARLAT mode, where variable-latency operations ++ on uninitialised (or secret) values are considered as errors ? */ ++extern Bool MC_(clo_variable_latency_errors); ++ + /* Standard functions for error and suppressions as required by the + core/tool iface */ + Bool MC_(eq_Error) ( VgRes res, const Error* e1, const Error* e2 ); +@@ -552,6 +556,7 @@ void MC_(record_address_error) ( ThreadId tid, Addr a, Int szB, + Bool isWrite ); + void MC_(record_cond_error) ( ThreadId tid, UInt otag ); + void MC_(record_value_error) ( ThreadId tid, Int szB, UInt otag ); ++void MC_(record_varlat_value_error) ( ThreadId tid, Int szB, UInt otag ); + void MC_(record_jump_error) ( ThreadId tid, Addr a ); + + void MC_(record_free_error) ( ThreadId tid, Addr a ); +@@ -773,6 +778,10 @@ VG_REGPARM(1) void MC_(helperc_value_check8_fail_w_o) ( UWord ); + VG_REGPARM(1) void MC_(helperc_value_check4_fail_w_o) ( UWord ); + VG_REGPARM(1) void MC_(helperc_value_check1_fail_w_o) ( UWord ); + VG_REGPARM(1) void MC_(helperc_value_check0_fail_w_o) ( UWord ); ++VG_REGPARM(2) void MC_(helperc_value_checkN_varlat_fail_w_o) ( HWord, UWord ); ++VG_REGPARM(1) void MC_(helperc_value_check8_varlat_fail_w_o) ( UWord ); ++VG_REGPARM(1) void MC_(helperc_value_check4_varlat_fail_w_o) ( UWord ); ++VG_REGPARM(1) void MC_(helperc_value_check1_varlat_fail_w_o) ( UWord ); + + /* And call these ones instead to report an uninitialised value error + but with no origin available. */ +@@ -781,6 +790,10 @@ VG_REGPARM(0) void MC_(helperc_value_check8_fail_no_o) ( void ); + VG_REGPARM(0) void MC_(helperc_value_check4_fail_no_o) ( void ); + VG_REGPARM(0) void MC_(helperc_value_check1_fail_no_o) ( void ); + VG_REGPARM(0) void MC_(helperc_value_check0_fail_no_o) ( void ); ++VG_REGPARM(1) void MC_(helperc_value_checkN_varlat_fail_no_o) ( HWord ); ++VG_REGPARM(0) void MC_(helperc_value_check8_varlat_fail_no_o) ( void ); ++VG_REGPARM(0) void MC_(helperc_value_check4_varlat_fail_no_o) ( void ); ++VG_REGPARM(0) void MC_(helperc_value_check1_varlat_fail_no_o) ( void ); + + /* V-bits load/store helpers */ + VG_REGPARM(1) void MC_(helperc_STOREV64be) ( Addr, ULong ); +diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c +index abd5d6888..f29524d2a 100644 +--- a/memcheck/mc_main.c ++++ b/memcheck/mc_main.c +@@ -37,6 +37,7 @@ + #include "pub_tool_libcbase.h" + #include "pub_tool_libcassert.h" + #include "pub_tool_libcprint.h" ++#include "pub_tool_libcproc.h" // for VG_(getenv) + #include "pub_tool_machine.h" + #include "pub_tool_mallocfree.h" + #include "pub_tool_options.h" +@@ -5770,6 +5771,27 @@ void MC_(helperc_value_checkN_fail_w_o) ( HWord sz, UWord origin ) { + MC_(record_value_error) ( VG_(get_running_tid)(), (Int)sz, (UInt)origin ); + } + ++VG_REGPARM(1) ++void MC_(helperc_value_check1_varlat_fail_w_o) ( UWord origin ) { ++ MC_(record_varlat_value_error) ( VG_(get_running_tid)(), 1, (UInt)origin ); ++} ++ ++VG_REGPARM(1) ++void MC_(helperc_value_check4_varlat_fail_w_o) ( UWord origin ) { ++ MC_(record_varlat_value_error) ( VG_(get_running_tid)(), 4, (UInt)origin ); ++} ++ ++VG_REGPARM(1) ++void MC_(helperc_value_check8_varlat_fail_w_o) ( UWord origin ) { ++ MC_(record_varlat_value_error) ( VG_(get_running_tid)(), 8, (UInt)origin ); ++} ++ ++VG_REGPARM(2) ++void MC_(helperc_value_checkN_varlat_fail_w_o) ( HWord sz, UWord origin ) { ++ MC_(record_varlat_value_error) ( VG_(get_running_tid)(), (Int)sz, ++ (UInt)origin ); ++} ++ + /* ... and these when an origin isn't available. */ + + VG_REGPARM(0) +@@ -5797,6 +5819,27 @@ void MC_(helperc_value_checkN_fail_no_o) ( HWord sz ) { + MC_(record_value_error) ( VG_(get_running_tid)(), (Int)sz, 0/*origin*/ ); + } + ++VG_REGPARM(0) ++void MC_(helperc_value_check1_varlat_fail_no_o) ( void ) { ++ MC_(record_varlat_value_error) ( VG_(get_running_tid)(), 1, 0/*origin*/ ); ++} ++ ++VG_REGPARM(0) ++void MC_(helperc_value_check4_varlat_fail_no_o) ( void ) { ++ MC_(record_varlat_value_error) ( VG_(get_running_tid)(), 4, 0/*origin*/ ); ++} ++ ++VG_REGPARM(0) ++void MC_(helperc_value_check8_varlat_fail_no_o) ( void ) { ++ MC_(record_varlat_value_error) ( VG_(get_running_tid)(), 8, 0/*origin*/ ); ++} ++ ++VG_REGPARM(1) ++void MC_(helperc_value_checkN_varlat_fail_no_o) ( HWord sz ) { ++ MC_(record_varlat_value_error) ( VG_(get_running_tid)(), (Int)sz, ++ 0/*origin*/ ); ++} ++ + + /*------------------------------------------------------------*/ + /*--- Metadata get/set functions, for client requests. ---*/ +@@ -6064,6 +6107,7 @@ UInt MC_(clo_leak_check_heuristics) = H2S(LchStdString) + | H2S( LchMultipleInheritance); + Bool MC_(clo_xtree_leak) = False; + const HChar* MC_(clo_xtree_leak_file) = "xtleak.kcg.%p"; ++Bool MC_(clo_variable_latency_errors) = False; + Bool MC_(clo_workaround_gcc296_bugs) = False; + Int MC_(clo_malloc_fill) = -1; + Int MC_(clo_free_fill) = -1; +@@ -6135,6 +6179,8 @@ static Bool mc_process_cmd_line_options(const HChar* arg) + else if VG_USET_CLOM(cloPD, arg, "--leak-check-heuristics", + MC_(parse_leak_heuristics_tokens), + MC_(clo_leak_check_heuristics)) {} ++ else if VG_BOOL_CLOM(cloPD, arg, "--variable-latency-errors", ++ MC_(clo_variable_latency_errors)) {} + else if (VG_BOOL_CLOM(cloPD, arg, "--show-reachable", tmp_show)) { + if (tmp_show) { + MC_(clo_show_leak_kinds) = MC_(all_Reachedness)(); +@@ -6313,6 +6359,7 @@ static void mc_print_usage(void) + " --xtree-leak=no|yes output leak result in xtree format? [no]\n" + " --xtree-leak-file= xtree leak report file [xtleak.kcg.%%p]\n" + " --undef-value-errors=no|yes check for undefined value errors [yes]\n" ++" --variable-latency-errors=no|yes check for variable latency errors [no]\n" + " --track-origins=no|yes show origins of undefined values? [no]\n" + " --partial-loads-ok=no|yes too hard to explain here; see manual [yes]\n" + " --expensive-definedness-checks=no|auto|yes\n" +@@ -6340,6 +6387,15 @@ static void mc_print_debug_usage(void) + ); + } + ++// VALGRIND_BESTEFFORT_* environment variables ++// are set by programs that are hoping for the features ++// but would like to proceed in any case, ++// even with valgrind versions not having the features. ++static void mc_besteffort_init(void) ++{ ++ if (VG_(getenv)("VALGRIND_BESTEFFORT_VARIABLE_LATENCY_ERRORS") != NULL) ++ MC_(clo_variable_latency_errors) = True; ++} + + /*------------------------------------------------------------*/ + /*--- Client blocks ---*/ +@@ -8551,6 +8607,10 @@ static Bool mc_mark_unaddressable_for_watchpoint (PointKind kind, Bool insert, + + static void mc_pre_clo_init(void) + { ++ // Handle best-effort environment variables early ++ // so that they can influence handling of everything else. ++ mc_besteffort_init(); ++ + VG_(details_name) ("Memcheck"); + VG_(details_version) (NULL); + VG_(details_description) ("a memory error detector"); +diff --git a/memcheck/mc_translate.c b/memcheck/mc_translate.c +index 05e6d59af..4e3f83770 100644 +--- a/memcheck/mc_translate.c ++++ b/memcheck/mc_translate.c +@@ -1593,8 +1593,13 @@ static void setHelperAnns ( MCEnv* mce, IRDirty* di ) { + + This routine does not generate code to check the definedness of + |guard|. The caller is assumed to have taken care of that already. ++ ++ If varlatLatency is set, then this function emits complaints for ++ VARLAT mode rather than for the usual branches etc. + */ +-static void complainIfUndefined ( MCEnv* mce, IRAtom* atom, IRExpr *guard ) ++static void complainIfUndefinedOrVariableLatency ( MCEnv* mce, IRAtom* atom, ++ IRExpr *guard, ++ Bool varlatLatency ) + { + IRAtom* vatom; + IRType ty; +@@ -1664,39 +1669,69 @@ static void complainIfUndefined ( MCEnv* mce, IRAtom* atom, IRExpr *guard ) + break; + case 1: + if (origin) { +- fn = &MC_(helperc_value_check1_fail_w_o); +- nm = "MC_(helperc_value_check1_fail_w_o)"; ++ if (!varlatLatency) { ++ fn = &MC_(helperc_value_check1_fail_w_o); ++ nm = "MC_(helperc_value_check1_fail_w_o)"; ++ } else { ++ fn = &MC_(helperc_value_check1_varlat_fail_w_o); ++ nm = "MC_(helperc_value_check1_varlat_fail_w_o)"; ++ } + args = mkIRExprVec_1(origin); + nargs = 1; + } else { +- fn = &MC_(helperc_value_check1_fail_no_o); +- nm = "MC_(helperc_value_check1_fail_no_o)"; ++ if (!varlatLatency) { ++ fn = &MC_(helperc_value_check1_fail_no_o); ++ nm = "MC_(helperc_value_check1_fail_no_o)"; ++ } else { ++ fn = &MC_(helperc_value_check1_varlat_fail_no_o); ++ nm = "MC_(helperc_value_check1_varlat_fail_no_o)"; ++ } + args = mkIRExprVec_0(); + nargs = 0; + } + break; + case 4: + if (origin) { +- fn = &MC_(helperc_value_check4_fail_w_o); +- nm = "MC_(helperc_value_check4_fail_w_o)"; ++ if (!varlatLatency) { ++ fn = &MC_(helperc_value_check4_fail_w_o); ++ nm = "MC_(helperc_value_check4_fail_w_o)"; ++ } else { ++ fn = &MC_(helperc_value_check4_varlat_fail_w_o); ++ nm = "MC_(helperc_value_check4_varlat_fail_w_o)"; ++ } + args = mkIRExprVec_1(origin); + nargs = 1; + } else { +- fn = &MC_(helperc_value_check4_fail_no_o); +- nm = "MC_(helperc_value_check4_fail_no_o)"; ++ if (!varlatLatency) { ++ fn = &MC_(helperc_value_check4_fail_no_o); ++ nm = "MC_(helperc_value_check4_fail_no_o)"; ++ } else { ++ fn = &MC_(helperc_value_check4_varlat_fail_no_o); ++ nm = "MC_(helperc_value_check4_varlat_fail_no_o)"; ++ } + args = mkIRExprVec_0(); + nargs = 0; + } + break; + case 8: + if (origin) { +- fn = &MC_(helperc_value_check8_fail_w_o); +- nm = "MC_(helperc_value_check8_fail_w_o)"; ++ if (!varlatLatency) { ++ fn = &MC_(helperc_value_check8_fail_w_o); ++ nm = "MC_(helperc_value_check8_fail_w_o)"; ++ } else { ++ fn = &MC_(helperc_value_check8_varlat_fail_w_o); ++ nm = "MC_(helperc_value_check8_varlat_fail_w_o)"; ++ } + args = mkIRExprVec_1(origin); + nargs = 1; + } else { +- fn = &MC_(helperc_value_check8_fail_no_o); +- nm = "MC_(helperc_value_check8_fail_no_o)"; ++ if (!varlatLatency) { ++ fn = &MC_(helperc_value_check8_fail_no_o); ++ nm = "MC_(helperc_value_check8_fail_no_o)"; ++ } else { ++ fn = &MC_(helperc_value_check8_varlat_fail_no_o); ++ nm = "MC_(helperc_value_check8_varlat_fail_no_o)"; ++ } + args = mkIRExprVec_0(); + nargs = 0; + } +@@ -1704,13 +1739,23 @@ static void complainIfUndefined ( MCEnv* mce, IRAtom* atom, IRExpr *guard ) + case 2: + case 16: + if (origin) { +- fn = &MC_(helperc_value_checkN_fail_w_o); +- nm = "MC_(helperc_value_checkN_fail_w_o)"; ++ if (!varlatLatency) { ++ fn = &MC_(helperc_value_checkN_fail_w_o); ++ nm = "MC_(helperc_value_checkN_fail_w_o)"; ++ } else { ++ fn = &MC_(helperc_value_checkN_varlat_fail_w_o); ++ nm = "MC_(helperc_value_checkN_varlat_fail_w_o)"; ++ } + args = mkIRExprVec_2( mkIRExpr_HWord( sz ), origin); + nargs = 2; + } else { +- fn = &MC_(helperc_value_checkN_fail_no_o); +- nm = "MC_(helperc_value_checkN_fail_no_o)"; ++ if (!varlatLatency) { ++ fn = &MC_(helperc_value_checkN_fail_no_o); ++ nm = "MC_(helperc_value_checkN_fail_no_o)"; ++ } else { ++ fn = &MC_(helperc_value_checkN_varlat_fail_no_o); ++ nm = "MC_(helperc_value_checkN_varlat_fail_no_o)"; ++ } + args = mkIRExprVec_1( mkIRExpr_HWord( sz ) ); + nargs = 1; + } +@@ -1771,6 +1816,17 @@ static void complainIfUndefined ( MCEnv* mce, IRAtom* atom, IRExpr *guard ) + } + } + ++static void complainIfUndefined ( MCEnv* mce, IRAtom* atom, IRExpr *guard ) ++{ ++ complainIfUndefinedOrVariableLatency(mce, atom, guard, False); ++} ++ ++static void complainIfVariableLatency ( MCEnv* mce, IRAtom* atom ) ++{ ++ if (MC_(clo_variable_latency_errors)) ++ complainIfUndefinedOrVariableLatency(mce, atom, NULL, True); ++} ++ + + /*------------------------------------------------------------*/ + /*--- Shadowing PUTs/GETs, and indexed variants thereof ---*/ +@@ -3511,14 +3567,19 @@ IRAtom* expr2vbits_Triop ( MCEnv* mce, + case Iop_Yl2xF64: + case Iop_Yl2xp1F64: + case Iop_AtanF64: +- case Iop_PRemF64: +- case Iop_PRem1F64: + case Iop_QuantizeD64: + /* I32(rm) x F64/D64 x F64/D64 -> F64/D64 */ + return mkLazy3(mce, Ity_I64, vatom1, vatom2, vatom3); ++ case Iop_PRemF64: ++ case Iop_PRem1F64: ++ complainIfVariableLatency(mce, atom2); ++ complainIfVariableLatency(mce, atom3); ++ return mkLazy3(mce, Ity_I64, vatom1, vatom2, vatom3); + case Iop_PRemC3210F64: + case Iop_PRem1C3210F64: + /* I32(rm) x F64 x F64 -> I32 */ ++ complainIfVariableLatency(mce, atom2); ++ complainIfVariableLatency(mce, atom3); + return mkLazy3(mce, Ity_I32, vatom1, vatom2, vatom3); + case Iop_AddF32: + case Iop_SubF32: +@@ -3572,21 +3633,33 @@ IRAtom* expr2vbits_Triop ( MCEnv* mce, + case Iop_Add64Fx2: + case Iop_Sub64Fx2: + case Iop_Mul64Fx2: +- case Iop_Div64Fx2: + case Iop_Scale2_64Fx2: + return binary64Fx2_w_rm(mce, vatom1, vatom2, vatom3); + ++ case Iop_Div64Fx2: ++ complainIfVariableLatency(mce, atom2); ++ complainIfVariableLatency(mce, atom3); ++ return binary64Fx2_w_rm(mce, vatom1, vatom2, vatom3); ++ + case Iop_Add32Fx4: + case Iop_Sub32Fx4: + case Iop_Mul32Fx4: +- case Iop_Div32Fx4: + case Iop_Scale2_32Fx4: +- return binary32Fx4_w_rm(mce, vatom1, vatom2, vatom3); ++ return binary32Fx4_w_rm(mce, vatom1, vatom2, vatom3); ++ ++ case Iop_Div32Fx4: ++ complainIfVariableLatency(mce, atom2); ++ complainIfVariableLatency(mce, atom3); ++ return binary32Fx4_w_rm(mce, vatom1, vatom2, vatom3); + + case Iop_Add64Fx4: + case Iop_Sub64Fx4: + case Iop_Mul64Fx4: ++ return binary64Fx4_w_rm(mce, vatom1, vatom2, vatom3); ++ + case Iop_Div64Fx4: ++ complainIfVariableLatency(mce, atom2); ++ complainIfVariableLatency(mce, atom3); + return binary64Fx4_w_rm(mce, vatom1, vatom2, vatom3); + + /* TODO: remaining versions of 16x4 FP ops when more of the half-precision +@@ -3594,12 +3667,16 @@ IRAtom* expr2vbits_Triop ( MCEnv* mce, + */ + case Iop_Add16Fx8: + case Iop_Sub16Fx8: +- return binary16Fx8_w_rm(mce, vatom1, vatom2, vatom3); ++ return binary16Fx8_w_rm(mce, vatom1, vatom2, vatom3); + + case Iop_Add32Fx8: + case Iop_Sub32Fx8: + case Iop_Mul32Fx8: ++ return binary32Fx8_w_rm(mce, vatom1, vatom2, vatom3); ++ + case Iop_Div32Fx8: ++ complainIfVariableLatency(mce, atom2); ++ complainIfVariableLatency(mce, atom3); + return binary32Fx8_w_rm(mce, vatom1, vatom2, vatom3); + + case Iop_F32x4_2toQ16x8: +@@ -3913,11 +3990,15 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + + case Iop_I32StoF32x4: + case Iop_F32toI32Sx4: ++ return unary16Fx8_w_rm(mce, vatom1, vatom2); + case Iop_Sqrt16Fx8: ++ complainIfVariableLatency(mce, atom2); + return unary16Fx8_w_rm(mce, vatom1, vatom2); + case Iop_Sqrt32Fx4: ++ complainIfVariableLatency(mce, atom2); + return unary32Fx4_w_rm(mce, vatom1, vatom2); + case Iop_Sqrt64Fx2: ++ complainIfVariableLatency(mce, atom2); + return unary64Fx2_w_rm(mce, vatom1, vatom2); + + case Iop_ShrN8x16: +@@ -4153,6 +4234,8 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + case Iop_ModU128: + case Iop_ModS128: + /* I128 x I128 -> I128 */ ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); + return mkLazy2(mce, Ity_V128, vatom1, vatom2); + + case Iop_QNarrowBin64Sto32Sx4: +@@ -4184,7 +4267,6 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + case Iop_Mul64F0x2: + case Iop_Min64F0x2: + case Iop_Max64F0x2: +- case Iop_Div64F0x2: + case Iop_CmpLT64F0x2: + case Iop_CmpLE64F0x2: + case Iop_CmpEQ64F0x2: +@@ -4192,6 +4274,11 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + case Iop_Add64F0x2: + return binary64F0x2(mce, vatom1, vatom2); + ++ case Iop_Div64F0x2: ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); ++ return binary64F0x2(mce, vatom1, vatom2); ++ + case Iop_Min32Fx4: + case Iop_Max32Fx4: + case Iop_CmpLT32Fx4: +@@ -4220,7 +4307,6 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + case Iop_Mul32F0x4: + case Iop_Min32F0x4: + case Iop_Max32F0x4: +- case Iop_Div32F0x4: + case Iop_CmpLT32F0x4: + case Iop_CmpLE32F0x4: + case Iop_CmpEQ32F0x4: +@@ -4228,6 +4314,11 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + case Iop_Add32F0x4: + return binary32F0x4(mce, vatom1, vatom2); + ++ case Iop_Div32F0x4: ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); ++ return binary32F0x4(mce, vatom1, vatom2); ++ + case Iop_QShlNsatSU8x16: + case Iop_QShlNsatUU8x16: + case Iop_QShlNsatSS8x16: +@@ -4531,11 +4622,14 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + case Iop_CosF64: + case Iop_TanF64: + case Iop_2xm1F64: +- case Iop_SqrtF64: + case Iop_RecpExpF64: + /* I32(rm) x I64/F64 -> I64/F64 */ + return mkLazy2(mce, Ity_I64, vatom1, vatom2); + ++ case Iop_SqrtF64: ++ complainIfVariableLatency(mce, atom2); ++ return mkLazy2(mce, Ity_I64, vatom1, vatom2); ++ + case Iop_ShlD64: + case Iop_ShrD64: + case Iop_RoundD64toInt: +@@ -4589,16 +4683,21 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + + case Iop_SqrtF16: + /* I32(rm) x F16 -> F16 */ ++ complainIfVariableLatency(mce, atom2); + return mkLazy2(mce, Ity_I16, vatom1, vatom2); + + case Iop_RoundF32toInt: +- case Iop_SqrtF32: + case Iop_RecpExpF32: + /* I32(rm) x I32/F32 -> I32/F32 */ + return mkLazy2(mce, Ity_I32, vatom1, vatom2); + ++ case Iop_SqrtF32: ++ complainIfVariableLatency(mce, atom2); ++ return mkLazy2(mce, Ity_I32, vatom1, vatom2); ++ + case Iop_SqrtF128: + /* I32(rm) x F128 -> F128 */ ++ complainIfVariableLatency(mce, atom2); + return mkLazy2(mce, Ity_I128, vatom1, vatom2); + + case Iop_I32StoF32: +@@ -4687,10 +4786,14 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + + case Iop_DivModU64to32: + case Iop_DivModS64to32: ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); + return mkLazy2(mce, Ity_I64, vatom1, vatom2); + + case Iop_DivModU128to64: + case Iop_DivModS128to64: ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); + return mkLazy2(mce, Ity_I128, vatom1, vatom2); + + case Iop_8HLto16: +@@ -4702,6 +4805,8 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + + case Iop_DivModU64to64: + case Iop_DivModS64to64: { ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); + IRAtom* vTmp64 = mkLazy2(mce, Ity_I64, vatom1, vatom2); + return assignNew('V', mce, Ity_I128, + binop(Iop_64HLto128, vTmp64, vTmp64)); +@@ -4717,6 +4822,8 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + + case Iop_DivModU32to32: + case Iop_DivModS32to32: { ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); + IRAtom* vTmp32 = mkLazy2(mce, Ity_I32, vatom1, vatom2); + return assignNew('V', mce, Ity_I64, + binop(Iop_32HLto64, vTmp32, vTmp32)); +@@ -4746,18 +4853,24 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + } + + case Iop_Sad8Ux4: /* maybe we could do better? ftm, do mkLazy2. */ ++ case Iop_QAdd32S: /* could probably do better */ ++ case Iop_QSub32S: /* could probably do better */ ++ return mkLazy2(mce, Ity_I32, vatom1, vatom2); ++ + case Iop_DivS32: + case Iop_DivU32: + case Iop_DivU32E: + case Iop_DivS32E: +- case Iop_QAdd32S: /* could probably do better */ +- case Iop_QSub32S: /* could probably do better */ ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); + return mkLazy2(mce, Ity_I32, vatom1, vatom2); + + case Iop_DivS64: + case Iop_DivU64: + case Iop_DivS64E: + case Iop_DivU64E: ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); + return mkLazy2(mce, Ity_I64, vatom1, vatom2); + + case Iop_Add32: +@@ -5163,14 +5276,19 @@ IRExpr* expr2vbits_Unop ( MCEnv* mce, IROp op, IRAtom* atom ) + return unary64Fx2(mce, vatom); + + case Iop_Sqrt64F0x2: ++ complainIfVariableLatency(mce, atom); + return unary64F0x2(mce, vatom); + + case Iop_Sqrt32Fx8: ++ complainIfVariableLatency(mce, atom); ++ return unary32Fx8(mce, vatom); ++ + case Iop_RSqrtEst32Fx8: + case Iop_RecipEst32Fx8: + return unary32Fx8(mce, vatom); + + case Iop_Sqrt64Fx4: ++ complainIfVariableLatency(mce, atom); + return unary64Fx4(mce, vatom); + + case Iop_RecipEst32Fx4: +@@ -5200,6 +5318,9 @@ IRExpr* expr2vbits_Unop ( MCEnv* mce, IROp op, IRAtom* atom ) + return unary32Fx2(mce, vatom); + + case Iop_Sqrt32F0x4: ++ complainIfVariableLatency(mce, atom); ++ return unary32F0x4(mce, vatom); ++ + case Iop_RSqrtEst32F0x4: + case Iop_RecipEst32F0x4: + return unary32F0x4(mce, vatom); +@@ -8044,19 +8165,25 @@ Bool check_or_add ( Pairs* tidyingEnv, IRExpr* guard, void* entry ) + static Bool is_helperc_value_checkN_fail ( const HChar* name ) + { + /* This is expensive because it happens a lot. We are checking to +- see whether |name| is one of the following 8 strings: ++ see whether |name| is one of the following 14 strings: + + MC_(helperc_value_check8_fail_no_o) + MC_(helperc_value_check4_fail_no_o) + MC_(helperc_value_check0_fail_no_o) + MC_(helperc_value_check1_fail_no_o) + MC_(helperc_value_check8_fail_w_o) ++ MC_(helperc_value_check4_fail_w_o) + MC_(helperc_value_check0_fail_w_o) + MC_(helperc_value_check1_fail_w_o) +- MC_(helperc_value_check4_fail_w_o) ++ MC_(helperc_value_check8_varlat_fail_no_o) ++ MC_(helperc_value_check4_varlat_fail_no_o) ++ MC_(helperc_value_check1_varlat_fail_no_o) ++ MC_(helperc_value_check8_varlat_fail_w_o) ++ MC_(helperc_value_check4_varlat_fail_w_o) ++ MC_(helperc_value_check1_varlat_fail_w_o) + + To speed it up, check the common prefix just once, rather than +- all 8 times. ++ all 14 times. + */ + const HChar* prefix = "MC_(helperc_value_check"; + +@@ -8081,7 +8208,13 @@ static Bool is_helperc_value_checkN_fail ( const HChar* name ) + || 0==VG_(strcmp)(name, "8_fail_w_o)") + || 0==VG_(strcmp)(name, "4_fail_w_o)") + || 0==VG_(strcmp)(name, "0_fail_w_o)") +- || 0==VG_(strcmp)(name, "1_fail_w_o)"); ++ || 0==VG_(strcmp)(name, "1_fail_w_o)") ++ || 0==VG_(strcmp)(name, "8_varlat_fail_no_o)") ++ || 0==VG_(strcmp)(name, "4_varlat_fail_no_o)") ++ || 0==VG_(strcmp)(name, "1_varlat_fail_no_o)") ++ || 0==VG_(strcmp)(name, "8_varlat_fail_w_o)") ++ || 0==VG_(strcmp)(name, "4_varlat_fail_w_o)") ++ || 0==VG_(strcmp)(name, "1_varlat_fail_w_o)"); + } + + IRSB* MC_(final_tidy) ( IRSB* sb_in ) +@@ -8147,7 +8280,7 @@ void MC_(do_instrumentation_startup_checks)( void ) + # define CHECK(_expected, _string) \ + tl_assert((_expected) == is_helperc_value_checkN_fail(_string)) + +- /* It should identify these 8, and no others, as targets. */ ++ /* It should identify these 14, and no others, as targets. */ + CHECK(True, "MC_(helperc_value_check8_fail_no_o)"); + CHECK(True, "MC_(helperc_value_check4_fail_no_o)"); + CHECK(True, "MC_(helperc_value_check0_fail_no_o)"); +@@ -8156,6 +8289,12 @@ void MC_(do_instrumentation_startup_checks)( void ) + CHECK(True, "MC_(helperc_value_check0_fail_w_o)"); + CHECK(True, "MC_(helperc_value_check1_fail_w_o)"); + CHECK(True, "MC_(helperc_value_check4_fail_w_o)"); ++ CHECK(True, "MC_(helperc_value_check8_varlat_fail_no_o)"); ++ CHECK(True, "MC_(helperc_value_check4_varlat_fail_no_o)"); ++ CHECK(True, "MC_(helperc_value_check1_varlat_fail_no_o)"); ++ CHECK(True, "MC_(helperc_value_check8_varlat_fail_w_o)"); ++ CHECK(True, "MC_(helperc_value_check1_varlat_fail_w_o)"); ++ CHECK(True, "MC_(helperc_value_check4_varlat_fail_w_o)"); + + /* Ad-hoc selection of other strings gathered via a quick test. */ + CHECK(False, "amd64g_dirtyhelper_CPUID_avx2"); +diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am +index 19ac76730..2012be681 100644 +--- a/memcheck/tests/Makefile.am ++++ b/memcheck/tests/Makefile.am +@@ -437,6 +437,14 @@ EXTRA_DIST = \ + varinfo6.vgtest varinfo6.stdout.exp varinfo6.stderr.exp \ + varinfo6.stderr.exp-ppc64 \ + varinforestrict.vgtest varinforestrict.stderr.exp \ ++ varlat.vgtest varlat.stderr.exp \ ++ varlat-env.vgtest varlat-env.stderr.exp \ ++ varlat-no.vgtest varlat-no.stderr.exp \ ++ varlat-yes.vgtest varlat-yes.stderr.exp \ ++ varlat2.vgtest varlat2.stderr.exp \ ++ varlat2-env.vgtest varlat2-env.stderr.exp \ ++ varlat2-no.vgtest varlat2-no.stderr.exp \ ++ varlat2-yes.vgtest varlat2-yes.stderr.exp \ + vcpu_bz2.stdout.exp vcpu_bz2.stderr.exp vcpu_bz2.vgtest \ + vcpu_fbench.stdout.exp vcpu_fbench.stderr.exp vcpu_fbench.vgtest \ + vcpu_fnfns.stdout.exp vcpu_fnfns.stdout.exp-glibc28-amd64 \ +@@ -547,6 +555,7 @@ check_PROGRAMS = \ + varinfo1 varinfo2 varinfo3 varinfo4 \ + varinfo5 varinfo5so.so varinfo6 \ + varinforestrict \ ++ varlat varlat2 \ + vcpu_fbench vcpu_fnfns \ + wcs \ + xml1 \ +@@ -855,6 +864,9 @@ else + endif + varinforestrict_CFLAGS = $(AM_CFLAGS) -O0 -g @FLAG_W_NO_MAYBE_UNINITIALIZED@ + ++varlat_CFLAGS = $(AM_CFLAGS) @FLAG_W_NO_UNINITIALIZED@ ++varlat2_CFLAGS = $(AM_CFLAGS) @FLAG_W_NO_UNINITIALIZED@ ++ + # Build shared object for wrap7 + wrap7_SOURCES = wrap7.c + wrap7_DEPENDENCIES = wrap7so.so +diff --git a/memcheck/tests/varlat-env.stderr.exp b/memcheck/tests/varlat-env.stderr.exp +new file mode 100644 +index 000000000..5393cd2dc +--- /dev/null ++++ b/memcheck/tests/varlat-env.stderr.exp +@@ -0,0 +1,3 @@ ++Variable-latency instruction operand of size 4 is secret/uninitialised ++ ... ++ +diff --git a/memcheck/tests/varlat-env.vgtest b/memcheck/tests/varlat-env.vgtest +new file mode 100644 +index 000000000..945670ac3 +--- /dev/null ++++ b/memcheck/tests/varlat-env.vgtest +@@ -0,0 +1,3 @@ ++prog: varlat ++vgopts: -q ++env: VALGRIND_BESTEFFORT_VARIABLE_LATENCY_ERRORS=1 +diff --git a/memcheck/tests/varlat-no.stderr.exp b/memcheck/tests/varlat-no.stderr.exp +new file mode 100644 +index 000000000..e69de29bb +diff --git a/memcheck/tests/varlat-no.vgtest b/memcheck/tests/varlat-no.vgtest +new file mode 100644 +index 000000000..ed5fe4495 +--- /dev/null ++++ b/memcheck/tests/varlat-no.vgtest +@@ -0,0 +1,2 @@ ++prog: varlat ++vgopts: -q +diff --git a/memcheck/tests/varlat-yes.stderr.exp b/memcheck/tests/varlat-yes.stderr.exp +new file mode 100644 +index 000000000..5393cd2dc +--- /dev/null ++++ b/memcheck/tests/varlat-yes.stderr.exp +@@ -0,0 +1,3 @@ ++Variable-latency instruction operand of size 4 is secret/uninitialised ++ ... ++ +diff --git a/memcheck/tests/varlat-yes.vgtest b/memcheck/tests/varlat-yes.vgtest +new file mode 100644 +index 000000000..57a4d9d8e +--- /dev/null ++++ b/memcheck/tests/varlat-yes.vgtest +@@ -0,0 +1,2 @@ ++prog: varlat ++vgopts: -q --variable-latency-errors=yes +diff --git a/memcheck/tests/varlat.c b/memcheck/tests/varlat.c +new file mode 100644 +index 000000000..80fa2e688 +--- /dev/null ++++ b/memcheck/tests/varlat.c +@@ -0,0 +1,16 @@ ++#include ++ ++volatile int storage; ++ ++void storage_init(char c) ++{ ++ storage = 100/(1|c); ++} ++ ++int main() ++{ ++ char *x = malloc(1); ++ storage_init(x[0]); ++ free(x); ++ return 0; ++} +diff --git a/memcheck/tests/varlat.stderr.exp b/memcheck/tests/varlat.stderr.exp +new file mode 100644 +index 000000000..e69de29bb +diff --git a/memcheck/tests/varlat.vgtest b/memcheck/tests/varlat.vgtest +new file mode 100644 +index 000000000..6b55ac8f8 +--- /dev/null ++++ b/memcheck/tests/varlat.vgtest +@@ -0,0 +1,2 @@ ++prog: varlat ++vgopts: -q --variable-latency-errors=no +diff --git a/memcheck/tests/varlat2-env.stderr.exp b/memcheck/tests/varlat2-env.stderr.exp +new file mode 100644 +index 000000000..5393cd2dc +--- /dev/null ++++ b/memcheck/tests/varlat2-env.stderr.exp +@@ -0,0 +1,3 @@ ++Variable-latency instruction operand of size 4 is secret/uninitialised ++ ... ++ +diff --git a/memcheck/tests/varlat2-env.vgtest b/memcheck/tests/varlat2-env.vgtest +new file mode 100644 +index 000000000..6fa74525c +--- /dev/null ++++ b/memcheck/tests/varlat2-env.vgtest +@@ -0,0 +1,3 @@ ++prog: varlat2 ++vgopts: -q ++env: VALGRIND_BESTEFFORT_VARIABLE_LATENCY_ERRORS=1 +diff --git a/memcheck/tests/varlat2-no.stderr.exp b/memcheck/tests/varlat2-no.stderr.exp +new file mode 100644 +index 000000000..5393cd2dc +--- /dev/null ++++ b/memcheck/tests/varlat2-no.stderr.exp +@@ -0,0 +1,3 @@ ++Variable-latency instruction operand of size 4 is secret/uninitialised ++ ... ++ +diff --git a/memcheck/tests/varlat2-no.vgtest b/memcheck/tests/varlat2-no.vgtest +new file mode 100644 +index 000000000..e608f987c +--- /dev/null ++++ b/memcheck/tests/varlat2-no.vgtest +@@ -0,0 +1,2 @@ ++prog: varlat2 ++vgopts: -q +diff --git a/memcheck/tests/varlat2-yes.stderr.exp b/memcheck/tests/varlat2-yes.stderr.exp +new file mode 100644 +index 000000000..5393cd2dc +--- /dev/null ++++ b/memcheck/tests/varlat2-yes.stderr.exp +@@ -0,0 +1,3 @@ ++Variable-latency instruction operand of size 4 is secret/uninitialised ++ ... ++ +diff --git a/memcheck/tests/varlat2-yes.vgtest b/memcheck/tests/varlat2-yes.vgtest +new file mode 100644 +index 000000000..d4c908305 +--- /dev/null ++++ b/memcheck/tests/varlat2-yes.vgtest +@@ -0,0 +1,2 @@ ++prog: varlat2 ++vgopts: -q --variable-latency-errors=yes +diff --git a/memcheck/tests/varlat2.c b/memcheck/tests/varlat2.c +new file mode 100644 +index 000000000..689260a2b +--- /dev/null ++++ b/memcheck/tests/varlat2.c +@@ -0,0 +1,18 @@ ++#include ++#include "valgrind.h" ++ ++volatile int storage; ++ ++void storage_init(char c) ++{ ++ storage = 100/(1|c); ++} ++ ++int main() ++{ ++ char *x = malloc(1); ++ VALGRIND_CLO_CHANGE("--variable-latency-errors=yes"); ++ storage_init(x[0]); ++ free(x); ++ return 0; ++} +diff --git a/memcheck/tests/varlat2.stderr.exp b/memcheck/tests/varlat2.stderr.exp +new file mode 100644 +index 000000000..1e7a51a5d +--- /dev/null ++++ b/memcheck/tests/varlat2.stderr.exp +@@ -0,0 +1,4 @@ ++Variable-latency instruction operand of size 4 is secret/uninitialised ++ at 0x........: storage_init (varlat2.c:8) ++ by 0x........: main (varlat2.c:15) ++ +diff --git a/memcheck/tests/varlat2.vgtest b/memcheck/tests/varlat2.vgtest +new file mode 100644 +index 000000000..4ef2fad30 +--- /dev/null ++++ b/memcheck/tests/varlat2.vgtest +@@ -0,0 +1,2 @@ ++prog: varlat2 ++vgopts: -q --variable-latency-errors=no diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/README.md new file mode 100644 index 0000000000..7696554613 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/README.md @@ -0,0 +1,13 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Proofs for mldsa-native + +This directory contains material related to the formal verification of the source code of mldsa-native. + +## C verification: CBMC + +We use the [C Bounded Model Checker (CBMC)](https://github.com/diffblue/cbmc) to show the absence of various classes of undefined behaviour in the mldsa-native C source, including out of bounds memory accesses and integer overflows. See [proofs/cbmc](cbmc), or the [proof_guide](https://github.com/pq-code-package/mlkem-native/blob/main/proofs/cbmc/proof_guide.md). + +## Assembly verification: HOL-Light + +We use the [HOL-Light](https://github.com/jrh13/hol-light) interactive theorem prover alongside the verification infrastructure from [s2n-bignum](https://github.com/awslabs/s2n-bignum) to show the functional correctness of highly optimized assembly routines in mlkem-native at the object-code level. See [proofs/hol_light/x86_64](hol_light/x86_64). diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/.gitignore b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/.gitignore new file mode 100644 index 0000000000..c31bc17ae7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/.gitignore @@ -0,0 +1,23 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# Emitted when running CBMC proofs +**/logs +**/gotos +**/report +**/html +output + +# Emitted by CBMC Viewer +TAGS-* + +# Emitted by litani +.ninja_deps +.ninja_log +.litani_cache_dir + +# These files should be overwritten whenever prepare.py runs +cbmc-batch.yaml + +__pycache__/ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/H/H_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/H/H_harness.c new file mode 100644 index 0000000000..8cbbb48afc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/H/H_harness.c @@ -0,0 +1,22 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void mld_H(uint8_t *out, size_t outlen, const uint8_t *in1, size_t in1len, + const uint8_t *in2, size_t in2len, const uint8_t *in3, + size_t in3len); + +void harness(void) +{ + uint8_t *out; + size_t outlen; + const uint8_t *in1; + size_t in1len; + const uint8_t *in2; + size_t in2len; + const uint8_t *in3; + size_t in3len; + + mld_H(out, outlen, in1, in1len, in2, in2len, in3, in3len); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/H/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/H/Makefile new file mode 100644 index 0000000000..6684f81a72 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/H/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = H_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_h + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=mld_H +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake256_init $(MLD_NAMESPACE)shake256_absorb $(MLD_NAMESPACE)shake256_squeeze $(MLD_NAMESPACE)shake256_finalize $(MLD_NAMESPACE)shake256_release +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_h + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/Makefile.common b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/Makefile.common new file mode 100644 index 0000000000..867888cfab --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/Makefile.common @@ -0,0 +1,1188 @@ +# -*- mode: makefile -*- +# The first line sets the emacs major mode to Makefile + +# Copyright (c) The mldsa-native project authors +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 + +CBMC_STARTER_KIT_VERSION = CBMC starter kit 2.11 + +################################################################ +# The CBMC Starter Kit depends on the files Makefile.common and +# run-cbmc-proofs.py. They are installed by the setup script +# cbmc-starter-kit-setup and updated to the latest version by the +# update script cbmc-starter-kit-update. For more information about +# the starter kit and these files and these scripts, see +# https://model-checking.github.io/cbmc-starter-kit +# +# Makefile.common implements what we consider to be some best +# practices for using cbmc for software verification. +# +# Section I gives default values for a large number of Makefile +# variables that control +# * how your code is built (include paths, etc), +# * what program transformations are applied to your code (loop +# unwinding, etc), and +# * what properties cbmc checks for in your code (memory safety, etc). +# +# These variables are defined below with definitions of the form +# VARIABLE ?= DEFAULT_VALUE +# meaning VARIABLE is set to DEFAULT_VALUE if VARIABLE has not already +# been given a value. +# +# For your project, you can override these default values with +# project-specific definitions in Makefile-project-defines. +# +# For any individual proof, you can override these default values and +# project-specific values with proof-specific definitions in the +# Makefile for your proof. +# +# The definitions in the proof Makefile override definitions in the +# project Makefile-project-defines which override definitions in this +# Makefile.common. +# +# Section II uses the values defined in Section I to build your code, run +# your proof, and build a report of your results. You should not need +# to modify or override anything in Section II, but you may want to +# read it to understand how the values defined in Section I control +# things. +# +# To use Makefile.common, set variables as described above as needed, +# and then for each proof, +# +# * Create a subdirectory . +# * Write a proof harness (a function) with the name +# in a file with the name /.c +# * Write a makefile with the name /Makefile that looks +# something like +# +# HARNESS_FILE= +# HARNESS_ENTRY= +# PROOF_UID= +# +# PROJECT_SOURCES += $(SRCDIR)/libraries/api_1.c +# PROJECT_SOURCES += $(SRCDIR)/libraries/api_2.c +# +# PROOF_SOURCES += $(PROOFDIR)/harness.c +# PROOF_SOURCES += $(SRCDIR)/cbmc/proofs/stub_a.c +# PROOF_SOURCES += $(SRCDIR)/cbmc/proofs/stub_b.c +# +# UNWINDSET += foo.0:3 +# UNWINDSET += bar.1:6 +# +# REMOVE_FUNCTION_BODY += api_stub_a +# REMOVE_FUNCTION_BODY += api_stub_b +# +# DEFINES = -DDEBUG=0 +# +# include ../Makefile.common +# +# * Change directory to and run make +# +# The proof setup script cbmc-starter-kit-setup-proof from the CBMC +# Starter Kit will do most of this for, creating a directory and +# writing a basic Makefile and proof harness into it that you can edit +# as described above. +# +# Warning: If you get results that are hard to explain, consider +# running "make clean" or "make veryclean" before "make" if you get +# results that are hard to explain. Dependency handling in this +# Makefile.common may not be perfect. + +SHELL=/usr/bin/env bash + +default: report + +################################################################ +################################################################ +## Section I: This section gives common variable definitions. +## +## Override these definitions in Makefile-project-defines or +## your proof Makefile. +## +## Remember that Makefile.common and Makefile-project-defines are +## included into the proof Makefile in your proof directory, so all +## relative pathnames defined there should be relative to your proof +## directory. + +################################################################ +# Define the layout of the source tree and the proof subtree +# +# Generally speaking, +# +# SRCDIR = the root of the repository +# CBMC_ROOT = /srcdir/cbmc +# PROOF_ROOT = /srcdir/cbmc/proofs +# PROOF_SOURCE = /srcdir/cbmc/sources +# PROOF_INCLUDE = /srcdir/cbmc/include +# PROOF_STUB = /srcdir/cbmc/stubs +# PROOFDIR = the directory containing the Makefile for your proof +# +# The path /srcdir/cbmc used in the example above is determined by the +# setup script cbmc-starter-kit-setup. Projects usually create a cbmc +# directory somewhere in the source tree, and run the setup script in +# that directory. The value of CBMC_ROOT becomes the absolute path to +# that directory. +# +# The location of that cbmc directory in the source tree affects the +# definition of SRCDIR, which is defined in terms of the relative path +# from a proof directory to the repository root. The definition is +# usually determined by the setup script cbmc-starter-kit-setup and +# written to Makefile-template-defines, but you can override it for a +# project in Makefile-project-defines and for a specific proof in the +# Makefile for the proof. + +# Absolute path to the directory containing this Makefile.common +# See https://ftp.gnu.org/old-gnu/Manuals/make-3.80/html_node/make_17.html +# +# Note: We compute the absolute paths to the makefiles in MAKEFILE_LIST +# before we filter the list of makefiles for %/Makefile.common. +# Otherwise an invocation of the form "make -f Makefile.common" will set +# MAKEFILE_LIST to "Makefile.common" which will fail to match the +# pattern %/Makefile.common. +# +MAKEFILE_PATHS = $(foreach makefile,$(MAKEFILE_LIST),$(abspath $(makefile))) +PROOF_ROOT = $(dir $(filter %/Makefile.common,$(MAKEFILE_PATHS))) + +CBMC_ROOT = $(shell dirname $(PROOF_ROOT)) +PROOF_SOURCE = $(CBMC_ROOT)/sources +PROOF_INCLUDE = $(CBMC_ROOT)/include +PROOF_STUB = $(CBMC_ROOT)/stubs + +# Flag to pass to goto-cc to make all static symbols globally visible. Leave it +# unset or set it to --export-file-local-symbols to enable this behavior. Else, +# selectively enable access to such symbols via each proof's Makefile. +EXPORT_FILE_LOCAL_SYMBOLS = + +SRCDIR ?= $(abspath $(PROOF_ROOT)/../../) +LITANI ?= litani +PROJECT_NAME = "mldsa-native" + +# SRCDIR is the path to the root of the source tree +# This is a default definition that is frequently overridden in +# another Makefile, see the discussion of SRCDIR above. +SRCDIR ?= $(abspath ../..) + +# PROOFDIR is the path to the directory containing the proof harness +PROOFDIR ?= $(abspath .) + +################################################################ +# Define how to run CBMC + +# Do property checking with the external SAT solver given by +# EXTERNAL_SAT_SOLVER. Do coverage checking with the default solver, +# since coverage checking requires the use of an incremental solver. +# The EXTERNAL_SAT_SOLVER variable is typically set (if it is at all) +# as an environment variable or as a makefile variable in +# Makefile-project-defines. +# +# For a particular proof, if the default solver is faster, do property +# checking with the default solver by including this definition in the +# proof Makefile: +# USE_EXTERNAL_SAT_SOLVER = +# +ifneq ($(strip $(EXTERNAL_SAT_SOLVER)),) + USE_EXTERNAL_SAT_SOLVER ?= --external-sat-solver $(EXTERNAL_SAT_SOLVER) +endif +CHECKFLAGS += $(USE_EXTERNAL_SAT_SOLVER) + +# Job pools +# For version of Litani that are new enough (where `litani print-capabilities` +# prints "pools"), proofs for which `EXPENSIVE = true` is set can be added to a +# "job pool" that restricts how many expensive proofs are run at a time. All +# other proofs will be built in parallel as usual. +# +# In more detail: all compilation, instrumentation, and report jobs are run with +# full parallelism as usual, even for expensive proofs. The CBMC jobs for +# non-expensive proofs are also run in parallel. The only difference is that the +# CBMC safety checks and coverage checks for expensive proofs are run with a +# restricted parallelism level. At any one time, only N of these jobs are run at +# once, amongst all the proofs. +# +# To configure N, Litani needs to be initialized with a pool called "expensive". +# For example, to only run two CBMC safety/coverage jobs at a time from amongst +# all the proofs, you would initialize litani like +# litani init --pools expensive:2 +# The run-cbmc-proofs.py script takes care of this initialization through the +# --expensive-jobs-parallelism flag. +# +# To enable this feature, set +# the ENABLE_POOLS variable when running Make, like +# `make ENABLE_POOLS=true report` +# The run-cbmc-proofs.py script takes care of this through the +# --restrict-expensive-jobs flag. + +ifeq ($(strip $(ENABLE_POOLS)),) + POOL = + INIT_POOLS = +else ifeq ($(strip $(EXPENSIVE)),) + POOL = + INIT_POOLS = +else + POOL = --pool expensive + INIT_POOLS = --pools expensive:1 +endif + +# Similar to the pool feature above. If Litani is new enough, enable +# profiling CBMC's memory use. +ifeq ($(strip $(ENABLE_MEMORY_PROFILING)),) + MEMORY_PROFILING = +else + MEMORY_PROFILING = --profile-memory +endif + +# Property checking flags +# +# Each variable below controls a specific property checking flag +# within CBMC. If desired, a property flag can be disabled within +# a particular proof by nulling the corresponding variable when CBMC's default +# is not to perform such checks, or setting to --no--check when CBMC's +# default is to perform such checks. For instance, the following lines: +# +# CBMC_FLAG_POINTER_CHECK = --no-pointer-check +# CBMC_FLAG_UNSIGNED_OVERFLOW_CHECK = +# +# would disable pointer checks and unsigned overflow checks with CBMC flag +# within: +# * an entire project when added to Makefile-project-defines +# * a specific proof when added to the harness Makefile + +CBMC_FLAG_MALLOC_MAY_FAIL ?= --malloc-fail-assert +CBMC_FLAG_BOUNDS_CHECK ?= # set to --no-bounds-check to disable +CBMC_FLAG_CONVERSION_CHECK ?= --conversion-check +CBMC_FLAG_DIV_BY_ZERO_CHECK ?= # set to --no-div-by-zero-check to disable +CBMC_FLAG_FLOAT_OVERFLOW_CHECK ?= --float-overflow-check +CBMC_FLAG_NAN_CHECK ?= --nan-check +CBMC_FLAG_POINTER_CHECK ?= #set to --no-pointer-check to disable +CBMC_FLAG_POINTER_OVERFLOW_CHECK ?= --pointer-overflow-check +CBMC_FLAG_POINTER_PRIMITIVE_CHECK ?= # set to --no-pointer-primitive-check to disable +CBMC_FLAG_SIGNED_OVERFLOW_CHECK ?= # set to --no-signed-overflow-check to disable +CBMC_FLAG_UNDEFINED_SHIFT_CHECK ?= # set to --no-undefined-shift-check to disable +CBMC_FLAG_UNSIGNED_OVERFLOW_CHECK ?= --unsigned-overflow-check +CBMC_FLAG_UNWINDING_ASSERTIONS ?= # set to --no-unwinding-assertions to disable +CBMC_DEFAULT_UNWIND ?= --unwind 1 +CBMC_FLAG_FLUSH ?= --flush + +# Determine SMT back-end and prover combination chosen by the user +ifeq ($(findstring --smt2,$(CBMCFLAGS)),--smt2) # User has chosen SMT2 (which defaults to Z3) +CBMCFLAGS := $(subst --smt2,,$(CBMCFLAGS)) # Remove --smt2 from CBMCFLAGS +BACKEND_OPTION := --smt2 +PROVER_NAME=Z3 +SMT_FORMAT := --z3 +else ifeq ($(findstring --bitwuzla,$(CBMCFLAGS)),--bitwuzla) # User has chosen Bitwuzla +CBMCFLAGS := $(subst --bitwuzla,,$(CBMCFLAGS)) # Remove --bitwuzla from CBMCFLAGS +BACKEND_OPTION := --bitwuzla +PROVER_NAME=Bitwuzla +SMT_FORMAT := --bitwuzla +else ifeq ($(findstring --cvc5,$(CBMCFLAGS)),--cvc5) # User has chosen cvc5 +CBMCFLAGS := $(subst --cvc5,,$(CBMCFLAGS)) # Remove --cvc5 from CBMCFLAGS +BACKEND_OPTION := --cvc5 +PROVER_NAME=cvc5 +SMT_FORMAT := --cvc5 +endif + +# CBMC flags used for property checking and coverage checking + +CBMCFLAGS += $(CBMC_FLAG_FLUSH) + +# CBMC 6.0.0 enables all standard checks by default, which can make coverage analysis +# very slow. See https://github.com/diffblue/cbmc/issues/8389 +# For now, we disable these checks when generating coverage info. +COVERFLAGS ?= --no-standard-checks --malloc-may-fail --malloc-fail-null + +# CBMC flags used for property checking + +CHECKFLAGS += $(CBMC_FLAG_BOUNDS_CHECK) +CHECKFLAGS += $(CBMC_FLAG_CONVERSION_CHECK) +CHECKFLAGS += $(CBMC_FLAG_DIV_BY_ZERO_CHECK) +CHECKFLAGS += $(CBMC_FLAG_FLOAT_OVERFLOW_CHECK) +CHECKFLAGS += $(CBMC_FLAG_NAN_CHECK) +CHECKFLAGS += $(CBMC_FLAG_POINTER_CHECK) +CHECKFLAGS += $(CBMC_FLAG_POINTER_OVERFLOW_CHECK) +CHECKFLAGS += $(CBMC_FLAG_POINTER_PRIMITIVE_CHECK) +CHECKFLAGS += $(CBMC_FLAG_SIGNED_OVERFLOW_CHECK) +CHECKFLAGS += $(CBMC_FLAG_UNDEFINED_SHIFT_CHECK) +CHECKFLAGS += $(CBMC_FLAG_UNSIGNED_OVERFLOW_CHECK) + +# Additional CBMC flag to CBMC control verbosity. +# +# Meaningful values are +# 0 none +# 1 only errors +# 2 + warnings +# 4 + results +# 6 + status/phase information +# 8 + statistical information +# 9 + progress information +# 10 + debug info +# +# Uncomment the following line or set in Makefile-project-defines +# CBMC_VERBOSITY ?= --verbosity 4 + +# Additional CBMC flag to control how CBMC treats static variables. +# +# NONDET_STATIC is a list of flags of the form --nondet-static +# and --nondet-static-exclude VAR. The --nondet-static flag causes +# CBMC to initialize static variables with unconstrained value +# (ignoring initializers and default zero-initialization). The +# --nondet-static-exclude VAR excludes VAR for the variables +# initialized with unconstrained values. +NONDET_STATIC ?= + +# Flags to pass to goto-cc for compilation and linking +COMPILE_FLAGS ?= -Wall -Werror --native-compiler $(CC) +LINK_FLAGS ?= -Wall -Werror +EXPORT_FILE_LOCAL_SYMBOLS ?= --export-file-local-symbols + +# During instrumentation, it adds models of C library functions +ADD_LIBRARY_FLAG := --add-library + +# Preprocessor include paths -I... +INCLUDES ?= +INCLUDES += -I$(PROOFDIR) +INCLUDES += -I$(SRCDIR)/proofs/cbmc +INCLUDES += -I$(SRCDIR)/mldsa +INCLUDES += -I$(SRCDIR)/mldsa/src +INCLUDES += -I$(SRCDIR)/mldsa/src/fips202 + +# Preprocessor definitions -D... +DEFINES ?= + +# CBMC object model +# +# CBMC_OBJECT_BITS is the number of bits in a pointer CBMC uses for +# the id of the object to which a pointer is pointing. CBMC uses 8 +# bits for the object id by default. The remaining bits in the pointer +# are used for offset into the object. This limits the size of the +# objects that CBMC can model. This Makefile defines this bound on +# object size to be CBMC_MAX_OBJECT_SIZE. You are likely to get +# unexpected results if you try to malloc an object larger than this +# bound. +CBMC_OBJECT_BITS ?= 8 + +# CBMC loop unwinding (Normally set in the proof Makefile) +# +# UNWINDSET is a list of pairs of the form foo.1:4 meaning that +# CBMC should unwind loop 1 in function foo no more than 4 times. +# For historical reasons, the number 4 is one more than the number +# of times CBMC actually unwinds the loop. +UNWINDSET ?= + +# CBMC early loop unwinding (Normally set in the proof Makefile) +# +# Most users can ignore this variable. +# +# This variable exists to support the use of loop and function +# contracts, two features under development for CBMC. Checking the +# assigns clause for function contracts and loop invariants currently +# assumes loop-free bodies for loops and functions with contracts +# (possibly after replacing nested loops with their own loop +# contracts). To satisfy this requirement, it may be necessary to +# unwind some loops before the function contract and loop invariant +# transformations are applied to the goto program. This variable +# CPROVER_LIBRARY_UNWINDSET is identical to UNWINDSET, and we assume that the +# loops mentioned in CPROVER_LIBRARY_UNWINDSET and UNWINDSET are disjoint. +CPROVER_LIBRARY_UNWINDSET ?= + +# CBMC function removal (Normally set set in the proof Makefile) +# +# REMOVE_FUNCTION_BODY is a list of function names. CBMC will "undefine" +# the function, and CBMC will treat the function as having no side effects +# and returning an unconstrained value of the appropriate return type. +# The list should include the names of functions being stubbed out. +REMOVE_FUNCTION_BODY ?= + +# CBMC function pointer restriction (Normally set in the proof Makefile) +# +# RESTRICT_FUNCTION_POINTER is a list of function pointer restriction +# instructions of the form: +# +# .function_pointer_call./[,]* +# +# The function pointer call number in the specified function gets +# rewritten to a case switch over a finite list of functions. +# If some possible target functions are omitted from the list a counter +# example trace will be found by CBMC, i.e. the transformation is sound. +# If the target functions are file-local symbols, then mangled names must +# be used. +RESTRICT_FUNCTION_POINTER ?= + +# The project source files (Normally set set in the proof Makefile) +# +# PROJECT_SOURCES is the list of project source files to compile, +# including the source file defining the function under test. +PROJECT_SOURCES ?= + +# The proof source files (Normally set in the proof Makefile) +# +# PROOF_SOURCES is the list of proof source files to compile, including +# the proof harness, and including any function stubs being used. +PROOF_SOURCES ?= + +# The number of seconds that CBMC should be allowed to run for before +# being forcefully terminated. Currently, this is set to be less than +# the time limit for a CodeBuild job, which is eight hours. If a proof +# run takes longer than the time limit of the CI environment, the +# environment will halt the proof run without updating the Litani +# report, making the proof run appear to "hang". +CBMC_TIMEOUT ?= 21600 + +# CBMC string abstraction +# +# Replace all uses of char * by a struct that carries that string, +# and also the underlying allocation and the C string length. +STRING_ABSTRACTION ?= +ifdef STRING_ABSTRACTION + ifneq ($(strip $(STRING_ABSTRACTION)),) + CBMC_STRING_ABSTRACTION := --string-abstraction + endif +endif + +# Optional configuration library flags +OPT_CONFIG_LIBRARY ?= +CBMC_OPT_CONFIG_LIBRARY := $(CBMC_FLAG_MALLOC_MAY_FAIL) $(CBMC_STRING_ABSTRACTION) + +# Proof writers could add function contracts in their source code. +# These contracts are ignored by default, but may be enabled in two distinct +# contexts using the following two variables: +# 1. To check whether one or more function contracts are sound with respect to +# the function implementation, CHECK_FUNCTION_CONTRACTS should be a list of +# function names. Use CHECK_FUNCTION_CONTRACTS_REC to check contracts on +# recursive functions. +# 2. To replace calls to certain functions with their correspondent function +# contracts, USE_FUNCTION_CONTRACTS should be a list of function names. +# One must check separately whether a function contract is sound before +# replacing it in calling contexts. +CHECK_FUNCTION_CONTRACTS ?= +CBMC_CHECK_FUNCTION_CONTRACTS := $(patsubst %,--enforce-contract %, $(CHECK_FUNCTION_CONTRACTS)) + +CHECK_FUNCTION_CONTRACTS_REC ?= +CBMC_CHECK_FUNCTION_CONTRACTS_REC := $(patsubst %,--enforce-contract-rec %, $(CHECK_FUNCTION_CONTRACTS_REC)) + +USE_FUNCTION_CONTRACTS ?= +CBMC_USE_FUNCTION_CONTRACTS := $(patsubst %,--replace-call-with-contract %, $(USE_FUNCTION_CONTRACTS)) + +CODE_CONTRACTS := $(CHECK_FUNCTION_CONTRACTS)$(USE_FUNCTION_CONTRACTS)$(APPLY_LOOP_CONTRACTS) + +# Proof writers may also apply function contracts using the Dynamic Frame +# Condition Checking (DFCC) mode. For more information on DFCC, +# please see https://diffblue.github.io/cbmc/contracts-dev-spec-dfcc.html. +USE_DYNAMIC_FRAMES ?= +ifdef USE_DYNAMIC_FRAMES + ifneq ($(strip $(USE_DYNAMIC_FRAMES)),) + CBMC_USE_DYNAMIC_FRAMES := $(CBMC_OPT_CONFIG_LIBRARY) --dfcc $(HARNESS_ENTRY) $(CBMC_CHECK_FUNCTION_CONTRACTS_REC) + endif +endif + +# Similarly, proof writers could also add loop contracts in their source code +# to obtain unbounded correctness proofs. Unlike function contracts, loop +# contracts are not reusable and thus are checked and used simultaneously. +# These contracts are also ignored by default, but may be enabled by setting +# the APPLY_LOOP_CONTRACTS variable. +APPLY_LOOP_CONTRACTS ?= +ifdef APPLY_LOOP_CONTRACTS + ifneq ($(strip $(APPLY_LOOP_CONTRACTS)),) + CBMC_APPLY_LOOP_CONTRACTS := --apply-loop-contracts + endif +endif + +# The default unwind should only be used in DFCC mode without loop contracts. +# When loop contracts are applied, we only unwind specified loops. +# If any loops remain after loop contracts have been applied, CBMC might try +# to unwind the program indefinitely, because we do not pass default unwind +# (i.e., --unwind 1) to CBMC when in DFCC mode. +# We must not use a default unwind command in DFCC mode, because contract instrumentation +# introduces loops encoding write set inclusion checks that must be dynamically unwound during +# symex. +ifneq ($(strip $(USE_DYNAMIC_FRAMES)),) +ifneq ($(strip $(APPLY_LOOP_CONTRACTS)),) + UNWIND_0500_FLAGS=$(CBMC_UNWINDSET) $(CBMC_CPROVER_LIBRARY_UNWINDSET) $(CBMC_FLAG_UNWINDING_ASSERTIONS) + UNWIND_0500_DESC="$(PROOF_UID): unwinding specified subset of loops" +else + UNWIND_0500_FLAGS=$(CBMC_UNWINDSET) $(CBMC_CPROVER_LIBRARY_UNWINDSET) $(CBMC_DEFAULT_UNWIND) $(CBMC_FLAG_UNWINDING_ASSERTIONS) + UNWIND_0500_DESC="$(PROOF_UID): unwinding all loops" +endif +endif + +# Silence makefile output (eg, long litani commands) unless VERBOSE is set. +ifndef VERBOSE + MAKEFLAGS := $(MAKEFLAGS) -s +endif + +################################################################ +################################################################ +## Section II: This section defines the process of running a proof +## +## There should be no reason to edit anything below this line. + +################################################################ +# Paths + +CBMC ?= cbmc +GOTO_ANALYZER ?= goto-analyzer +GOTO_CC ?= goto-cc +GOTO_INSTRUMENT ?= goto-instrument +CRANGLER ?= crangler +VIEWER ?= cbmc-viewer +VIEWER2 ?= cbmc-viewer +CMAKE ?= cmake + +GOTODIR ?= $(PROOFDIR)/gotos +LOGDIR ?= $(PROOFDIR)/logs + +PROJECT ?= project +PROOF ?= proof + +HARNESS_GOTO ?= $(GOTODIR)/$(HARNESS_FILE) +PROJECT_GOTO ?= $(GOTODIR)/$(PROJECT) +PROOF_GOTO ?= $(GOTODIR)/$(PROOF) + +################################################################ +# Useful macros for values that are hard to reference +SPACE :=$() $() +COMMA :=, + +################################################################ +# Set C compiler defines + +CBMCFLAGS += --object-bits $(CBMC_OBJECT_BITS) + +DEFINES += -DCBMC=1 +DEFINES += -DCBMC_OBJECT_BITS=$(CBMC_OBJECT_BITS) +DEFINES += -DCBMC_MAX_OBJECT_SIZE="(SIZE_MAX>>(CBMC_OBJECT_BITS+1))" + +ifndef MLD_CONFIG_PARAMETER_SET + $(error MLD_CONFIG_PARAMETER_SET not set) +endif + +DEFINES += -DMLD_CONFIG_PARAMETER_SET=$(MLD_CONFIG_PARAMETER_SET) +# Give visibility to all static functions +DEFINES += -Dstatic= + +# CI currently assumes cbmc invocation has at most one --unwindset + +# UNWINDSET is designed for user code (i.e., proof and project code) +ifdef UNWINDSET + ifneq ($(strip $(UNWINDSET)),) + CBMC_UNWINDSET := --unwindset $(subst $(SPACE),$(COMMA),$(strip $(UNWINDSET))) + endif +endif + +# CPROVER_LIBRARY_UNWINDSET is designed for CPROVER library functions +ifdef CPROVER_LIBRARY_UNWINDSET + ifneq ($(strip $(CPROVER_LIBRARY_UNWINDSET)),) + CBMC_CPROVER_LIBRARY_UNWINDSET := --unwindset $(subst $(SPACE),$(COMMA),$(strip $(CPROVER_LIBRARY_UNWINDSET))) + endif +endif + +CBMC_REMOVE_FUNCTION_BODY := $(patsubst %,--remove-function-body %, $(REMOVE_FUNCTION_BODY)) + +ifdef RESTRICT_FUNCTION_POINTER + ifneq ($(strip $(RESTRICT_FUNCTION_POINTER)),) + CBMC_RESTRICT_FUNCTION_POINTER := $(patsubst %,--restrict-function-pointer %, $(RESTRICT_FUNCTION_POINTER)) + endif +endif + +################################################################ +# Targets for rewriting source files with crangler + +# Construct crangler configuration files +# +# REWRITTEN_SOURCES is a list of crangler output files source.i. +# This target assumes that for each source.i +# * source.i_SOURCE is the path to a source file, +# * source.i_FUNCTIONS is a list of functions (may be empty) +# * source.i_OBJECTS is a list of variables (may be empty) +# This target constructs the crangler configuration file source.i.json +# of the form +# { +# "sources": [ "/proj/code.c" ], +# "includes": [ "/proj/include" ], +# "defines": [ "VAR=1" ], +# "functions": [ {"function_name": ["remove static"]} ], +# "objects": [ {"variable_name": ["remove static"]} ], +# "output": "source.i" +# } +# to remove the static attribute from function_name and variable_name +# in the source file source.c and write the result to source.i. +# +# This target assumes that filenames include no spaces and that +# the INCLUDES and DEFINES variables include no spaces after -I +# and -D. For example, use "-DVAR=1" and not "-D VAR=1". +# +# Define *_SOURCE, *_FUNCTIONS, and *_OBJECTS in the proof Makefile. +# The string source.i is usually an absolute path $(PROOFDIR)/code.i +# to a file in the proof directory that contains the proof Makefile. +# The proof Makefile usually includes the definitions +# $(PROOFDIR)/code.i_SOURCE = /proj/code.c +# $(PROOFDIR)/code.i_FUNCTIONS = function_name +# $(PROOFDIR)/code.i_OBJECTS = variable_name +# Because these definitions refer to PROOFDIR that is defined in this +# Makefile.common, these definitions must appear after the inclusion +# of Makefile.common in the proof Makefile. +# +$(foreach rs,$(REWRITTEN_SOURCES),$(eval $(rs).json: $($(rs)_SOURCE))) +$(foreach rs,$(REWRITTEN_SOURCES),$(rs).json): + echo '{'\ + '"sources": ['\ + '"$($(@:.json=)_SOURCE)"'\ + '],'\ + '"includes": ['\ + '$(subst $(SPACE),$(COMMA),$(patsubst -I%,"%",$(strip $(INCLUDES))))' \ + '],'\ + '"defines": ['\ + '$(subst $(SPACE),$(COMMA),$(patsubst -D%,"%",$(subst ",\",$(strip $(DEFINES)))))' \ + '],'\ + '"functions": ['\ + '{'\ + '$(subst ~, ,$(subst $(SPACE),$(COMMA),$(patsubst %,"%":["remove~static"],$($(@:.json=)_FUNCTIONS))))' \ + '}'\ + '],'\ + '"objects": ['\ + '{'\ + '$(subst ~, ,$(subst $(SPACE),$(COMMA),$(patsubst %,"%":["remove~static"],$($(@:.json=)_OBJECTS))))' \ + '}'\ + '],'\ + '"output": "$(@:.json=)"'\ + '}' > $@ + +# Rewrite source files with crangler +# +$(foreach rs,$(REWRITTEN_SOURCES),$(eval $(rs): $(rs).json)) +$(REWRITTEN_SOURCES): + $(LITANI) add-job \ + --command \ + '$(CRANGLER) $@.json' \ + --inputs $($@_SOURCE) \ + --outputs $@ \ + --stdout-file $(LOGDIR)/crangler-$(subst /,_,$(subst .,_,$@))-log.txt \ + --interleave-stdout-stderr \ + --pipeline-name "$(PROOF_UID)" \ + --ci-stage build \ + --description "$(PROOF_UID): removing static" + +################################################################ +# Build targets that make the relevant .goto files + +# Compile project sources +$(PROJECT_GOTO)0100.goto: $(PROJECT_SOURCES) $(REWRITTEN_SOURCES) + $(LITANI) add-job \ + --command \ + '$(GOTO_CC) $(CBMC_VERBOSITY) $(COMPILE_FLAGS) $(EXPORT_FILE_LOCAL_SYMBOLS) $(INCLUDES) $(DEFINES) $^ -o $@' \ + --inputs $^ \ + --outputs $@ \ + --stdout-file $(LOGDIR)/project_sources-log.txt \ + --pipeline-name "$(PROOF_UID)" \ + --ci-stage build \ + --description "$(PROOF_UID): building project binary" + +# Compile proof sources +$(PROOF_GOTO)0100.goto: $(PROOF_SOURCES) + $(LITANI) add-job \ + --command \ + '$(GOTO_CC) $(CBMC_VERBOSITY) $(COMPILE_FLAGS) $(EXPORT_FILE_LOCAL_SYMBOLS) $(INCLUDES) $(DEFINES) $^ -o $@' \ + --inputs $^ \ + --outputs $@ \ + --stdout-file $(LOGDIR)/proof_sources-log.txt \ + --pipeline-name "$(PROOF_UID)" \ + --ci-stage build \ + --description "$(PROOF_UID): building proof binary" + +# Remove function bodies from project sources +$(PROJECT_GOTO)0200.goto: $(PROJECT_GOTO)0100.goto + $(LITANI) add-job \ + --command \ + '$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_REMOVE_FUNCTION_BODY) $^ $@' \ + --inputs $^ \ + --outputs $@ \ + --stdout-file $(LOGDIR)/remove_function_body-log.txt \ + --pipeline-name "$(PROOF_UID)" \ + --ci-stage build \ + --description "$(PROOF_UID): removing function bodies from project sources" + +# Link project and proof sources into the proof harness +$(HARNESS_GOTO)0100.goto: $(PROOF_GOTO)0100.goto $(PROJECT_GOTO)0200.goto + $(LITANI) add-job \ + --command '$(GOTO_CC) $(CBMC_VERBOSITY) --function $(HARNESS_ENTRY) $^ $(LINK_FLAGS) -o $@' \ + --inputs $^ \ + --outputs $@ \ + --stdout-file $(LOGDIR)/link_proof_project-log.txt \ + --pipeline-name "$(PROOF_UID)" \ + --ci-stage build \ + --description "$(PROOF_UID): linking project to proof" + +# Restrict function pointers +$(HARNESS_GOTO)0200.goto: $(HARNESS_GOTO)0100.goto + $(LITANI) add-job \ + --command \ + '$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_RESTRICT_FUNCTION_POINTER) --remove-function-pointers $^ $@' \ + --inputs $^ \ + --outputs $@ \ + --stdout-file $(LOGDIR)/restrict_function_pointer-log.txt \ + --pipeline-name "$(PROOF_UID)" \ + --ci-stage build \ + --description "$(PROOF_UID): restricting function pointers in project sources" + +# Fill static variable with unconstrained values +$(HARNESS_GOTO)0300.goto: $(HARNESS_GOTO)0200.goto +ifneq ($(strip $(CODE_CONTRACTS)),) + $(LITANI) add-job \ + --command 'cp $^ $@' \ + --inputs $^ \ + --outputs $@ \ + --stdout-file $(LOGDIR)/nondet_static-log.txt \ + --pipeline-name "$(PROOF_UID)" \ + --ci-stage build \ + --description "$(PROOF_UID): not setting static variables to nondet (will do during contract instrumentation)" +else + $(LITANI) add-job \ + --command \ + '$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(NONDET_STATIC) $^ $@' \ + --inputs $^ \ + --outputs $@ \ + --stdout-file $(LOGDIR)/nondet_static-log.txt \ + --pipeline-name "$(PROOF_UID)" \ + --ci-stage build \ + --description "$(PROOF_UID): setting static variables to nondet" +endif + +# Link CPROVER library if DFCC mode is on +$(HARNESS_GOTO)0400.goto: $(HARNESS_GOTO)0300.goto +ifneq ($(strip $(USE_DYNAMIC_FRAMES)),) + $(LITANI) add-job \ + --command \ + '$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(ADD_LIBRARY_FLAG) $(CBMC_OPT_CONFIG_LIBRARY) $^ $@' \ + --inputs $^ \ + --outputs $@ \ + --stdout-file $(LOGDIR)/linking-library-models-log.txt \ + --pipeline-name "$(PROOF_UID)" \ + --ci-stage build \ + --description "$(PROOF_UID): linking CPROVER library" +else + $(LITANI) add-job \ + --command 'cp $^ $@' \ + --inputs $^ \ + --outputs $@ \ + --stdout-file $(LOGDIR)/linking-library-models-log.txt \ + --pipeline-name "$(PROOF_UID)" \ + --ci-stage build \ + --description "$(PROOF_UID): not linking CPROVER library" +endif + +# Early unwind all loops on DFCC mode; otherwise, only unwind loops in proof and project code +$(HARNESS_GOTO)0500.goto: $(HARNESS_GOTO)0400.goto +ifneq ($(strip $(USE_DYNAMIC_FRAMES)),) + $(LITANI) add-job \ + --command \ + '$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(UNWIND_0500_FLAGS) $^ $@' \ + --inputs $^ \ + --outputs $@ \ + --stdout-file $(LOGDIR)/unwind_loops-log.txt \ + --pipeline-name "$(PROOF_UID)" \ + --ci-stage build \ + --description $(UNWIND_0500_DESC) +else ifneq ($(strip $(CODE_CONTRACTS)),) + $(LITANI) add-job \ + --command \ + '$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_UNWINDSET) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $^ $@' \ + --inputs $^ \ + --outputs $@ \ + --stdout-file $(LOGDIR)/unwind_loops-log.txt \ + --pipeline-name "$(PROOF_UID)" \ + --ci-stage build \ + --description "$(PROOF_UID): unwinding loops in proof and project code" +else + $(LITANI) add-job \ + --command 'cp $^ $@' \ + --inputs $^ \ + --outputs $@ \ + --stdout-file $(LOGDIR)/unwind_loops-log.txt \ + --pipeline-name "$(PROOF_UID)" \ + --ci-stage build \ + --description "$(PROOF_UID): not unwinding loops" +endif + +# Replace function contracts, check function contracts, instrument for loop contracts +$(HARNESS_GOTO)0600.goto: $(HARNESS_GOTO)0500.goto + $(LITANI) add-job \ + --command \ + '$(GOTO_INSTRUMENT) $(CBMC_USE_DYNAMIC_FRAMES) $(NONDET_STATIC) $(CBMC_VERBOSITY) $(CBMC_CHECK_FUNCTION_CONTRACTS) $(CBMC_USE_FUNCTION_CONTRACTS) $(CBMC_APPLY_LOOP_CONTRACTS) $^ $@' \ + --inputs $^ \ + --outputs $@ \ + --stdout-file $(LOGDIR)/check_function_contracts-log.txt \ + --pipeline-name "$(PROOF_UID)" \ + --ci-stage build \ + --description "$(PROOF_UID): checking function contracts" + +# Omit initialization of unused global variables (reduces problem size) +$(HARNESS_GOTO)0700.goto: $(HARNESS_GOTO)0600.goto + $(LITANI) add-job \ + --command \ + '$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) --slice-global-inits $^ $@' \ + --inputs $^ \ + --outputs $@ \ + --stdout-file $(LOGDIR)/slice_global_inits-log.txt \ + --pipeline-name "$(PROOF_UID)" \ + --ci-stage build \ + --description "$(PROOF_UID): slicing global initializations" + +# Omit unused functions (sharpens coverage calculations) +$(HARNESS_GOTO)0800.goto: $(HARNESS_GOTO)0700.goto + $(LITANI) add-job \ + --command \ + '$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) --drop-unused-functions $^ $@' \ + --inputs $^ \ + --outputs $@ \ + --stdout-file $(LOGDIR)/drop_unused_functions-log.txt \ + --pipeline-name "$(PROOF_UID)" \ + --ci-stage build \ + --description "$(PROOF_UID): dropping unused functions" + +# Final name for proof harness +$(HARNESS_GOTO).goto: $(HARNESS_GOTO)0800.goto + $(LITANI) add-job \ + --command 'cp $< $@' \ + --inputs $^ \ + --outputs $@ \ + --pipeline-name "$(PROOF_UID)" \ + --ci-stage build \ + --description "$(PROOF_UID): copying final goto-binary" + +################################################################ +# Targets to run the analysis commands + +ifdef CBMCFLAGS + ifeq ($(strip $(CODE_CONTRACTS)),) + CBMCFLAGS += $(CBMC_UNWINDSET) $(CBMC_CPROVER_LIBRARY_UNWINDSET) $(CBMC_DEFAULT_UNWIND) $(CBMC_OPT_CONFIG_LIBRARY) + else ifeq ($(strip $(USE_DYNAMIC_FRAMES)),) + CBMCFLAGS += $(CBMC_CPROVER_LIBRARY_UNWINDSET) $(CBMC_OPT_CONFIG_LIBRARY) + endif +endif + +$(LOGDIR)/result.xml: $(HARNESS_GOTO).goto + $(LITANI) add-job \ + $(POOL) \ + --command \ + '$(CBMC) $(CBMC_VERBOSITY) $(BACKEND_OPTION) $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --trace --xml-ui $<' \ + --inputs $^ \ + --outputs $@ \ + --ci-stage test \ + --stdout-file $@ \ + $(MEMORY_PROFILING) \ + --ignore-returns 10 \ + --timeout $(CBMC_TIMEOUT) \ + --pipeline-name "$(PROOF_UID)" \ + --tags "stats-group:safety checks" \ + --stderr-file $(LOGDIR)/result-err-log.txt \ + --description "$(PROOF_UID): checking safety properties" + +$(LOGDIR)/result.txt: $(HARNESS_GOTO).goto + $(LITANI) add-job \ + $(POOL) \ + --command \ + '$(CBMC) $(CBMC_VERBOSITY) $(BACKEND_OPTION) $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --trace $<' \ + --inputs $^ \ + --outputs $@ \ + --ci-stage test \ + --stdout-file $@ \ + $(MEMORY_PROFILING) \ + --ignore-returns 10 \ + --timeout $(CBMC_TIMEOUT) \ + --pipeline-name "$(PROOF_UID)" \ + --tags "stats-group:safety checks" \ + --stderr-file $(LOGDIR)/result-err-log.txt \ + --description "$(PROOF_UID): checking safety properties" + +# Force SMT generation to file using whatever backend (one of Z3, Bitwuzla, or cvc5) that the user specified +$(HARNESS_GOTO).smt2: $(HARNESS_GOTO).goto + $(LITANI) add-job \ + $(POOL) \ + --command \ + '$(CBMC) $(CBMC_VERBOSITY) $(BACKEND_OPTION) $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --outfile $@ $(SMT_FORMAT) $<' \ + --inputs $^ \ + --outputs $@ \ + --ci-stage test \ + --stdout-file $(LOGDIR)/smt2-log.txt \ + $(MEMORY_PROFILING) \ + --ignore-returns 10 \ + --timeout $(CBMC_TIMEOUT) \ + --pipeline-name "$(PROOF_UID)" \ + --tags "stats-group:safety checks" \ + --stderr-file $(LOGDIR)/smt2-err-log.txt \ + --description "$(PROOF_UID): checking safety properties (SMT to file only)" + +# Force SMT generation to file, but for Z3, ignoring whatever back-end the user specified +$(HARNESS_GOTO).smtz: $(HARNESS_GOTO).goto + $(LITANI) add-job \ + $(POOL) \ + --command \ + '$(CBMC) $(CBMC_VERBOSITY) --smt2 $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --outfile $@ --z3 $<' \ + --inputs $^ \ + --outputs $@ \ + --ci-stage test \ + --stdout-file $(LOGDIR)/smtz-log.txt \ + $(MEMORY_PROFILING) \ + --ignore-returns 10 \ + --timeout $(CBMC_TIMEOUT) \ + --pipeline-name "$(PROOF_UID)" \ + --tags "stats-group:safety checks" \ + --stderr-file $(LOGDIR)/smtz-err-log.txt \ + --description "$(PROOF_UID): checking safety properties (SMT for Z3 only)" + +# Force SMT generation to file, but for Bitwuzla, ignoring whatever back-end the user specified +$(HARNESS_GOTO).smtb: $(HARNESS_GOTO).goto + $(LITANI) add-job \ + $(POOL) \ + --command \ + '$(CBMC) $(CBMC_VERBOSITY) --bitwuzla $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --outfile $@ --bitwuzla $<' \ + --inputs $^ \ + --outputs $@ \ + --ci-stage test \ + --stdout-file $(LOGDIR)/smtb-log.txt \ + $(MEMORY_PROFILING) \ + --ignore-returns 10 \ + --timeout $(CBMC_TIMEOUT) \ + --pipeline-name "$(PROOF_UID)" \ + --tags "stats-group:safety checks" \ + --stderr-file $(LOGDIR)/smtb-err-log.txt \ + --description "$(PROOF_UID): checking safety properties (SMT for Bitwuzla only)" + +# Force SMT generation to file, but for cvc5, ignoring whatever back-end the user specified +$(HARNESS_GOTO).smtc: $(HARNESS_GOTO).goto + $(LITANI) add-job \ + $(POOL) \ + --command \ + '$(CBMC) $(CBMC_VERBOSITY) --cvc5 $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --outfile $@ --cvc5 $<' \ + --inputs $^ \ + --outputs $@ \ + --ci-stage test \ + --stdout-file $(LOGDIR)/smtc-log.txt \ + $(MEMORY_PROFILING) \ + --ignore-returns 10 \ + --timeout $(CBMC_TIMEOUT) \ + --pipeline-name "$(PROOF_UID)" \ + --tags "stats-group:safety checks" \ + --stderr-file $(LOGDIR)/smtc-err-log.txt \ + --description "$(PROOF_UID): checking safety properties (SMT for cvc5 only)" + +$(LOGDIR)/property.xml: $(HARNESS_GOTO).goto + $(LITANI) add-job \ + --command \ + '$(CBMC) $(CBMC_VERBOSITY) $(BACKEND_OPTION) $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --show-properties --xml-ui $<' \ + --inputs $^ \ + --outputs $@ \ + --ci-stage test \ + --stdout-file $@ \ + --ignore-returns 10 \ + --pipeline-name "$(PROOF_UID)" \ + --stderr-file $(LOGDIR)/property-err-log.txt \ + --description "$(PROOF_UID): printing safety properties" + +$(LOGDIR)/coverage.xml: $(HARNESS_GOTO).goto + $(LITANI) add-job \ + $(POOL) \ + --command \ + '$(CBMC) $(CBMC_VERBOSITY) $(BACKEND_OPTION) $(CBMCFLAGS) $(COVERFLAGS) --cover location --xml-ui $<' \ + --inputs $^ \ + --outputs $@ \ + --ci-stage test \ + --stdout-file $@ \ + $(MEMORY_PROFILING) \ + --ignore-returns 10 \ + --timeout $(CBMC_TIMEOUT) \ + --pipeline-name "$(PROOF_UID)" \ + --tags "stats-group:coverage computation" \ + --stderr-file $(LOGDIR)/coverage-err-log.txt \ + --description "$(PROOF_UID): calculating coverage" + +COVERAGE ?= $(LOGDIR)/coverage.xml +VIEWER_COVERAGE_FLAG ?= --coverage $(COVERAGE) + +$(PROOFDIR)/report: $(LOGDIR)/result.xml $(LOGDIR)/property.xml $(COVERAGE) + $(LITANI) add-job \ + --command " $(VIEWER) \ + --result $(LOGDIR)/result.xml \ + $(VIEWER_COVERAGE_FLAG) \ + --property $(LOGDIR)/property.xml \ + --srcdir $(SRCDIR) \ + --goto $(HARNESS_GOTO).goto \ + --reportdir $(PROOFDIR)/report \ + --config $(PROOFDIR)/cbmc-viewer.json" \ + --inputs $^ \ + --outputs $(PROOFDIR)/report \ + --pipeline-name "$(PROOF_UID)" \ + --stdout-file $(LOGDIR)/viewer-log.txt \ + --ci-stage report \ + --description "$(PROOF_UID): generating report" + +litani-path: + @echo $(LITANI) + +# ############################################################## +# Phony Rules +# +# These rules provide a convenient way to run a single proof up to a +# certain stage. Users can browse into a proof directory and run +# "make -Bj 3 report" to generate a report for just that proof, or +# "make goto" to build the goto binary. Under the hood, this runs litani +# for just that proof. + +_goto: $(HARNESS_GOTO).goto +goto: + @ echo Running 'litani init' + $(LITANI) init $(INIT_POOLS) --project $(PROJECT_NAME) + @ echo Running 'litani add-job' + $(MAKE) -B _goto + @ echo Running 'litani build' + $(LITANI) run-build + +_result: $(LOGDIR)/result.txt +result: + @ echo Running 'litani init' + $(LITANI) init $(INIT_POOLS) --project $(PROJECT_NAME) + @ echo Running 'litani add-job' + $(MAKE) -B _result + @ echo Running 'litani build' + $(LITANI) run-build + tail -4 $(LOGDIR)/result.txt + -grep FAILURE $(LOGDIR)/result.txt + +_smt: $(HARNESS_GOTO).smt2 +smt: + @ echo Running 'litani init' + $(LITANI) init $(INIT_POOLS) --project $(PROJECT_NAME) + @ echo Running 'litani add-job' + $(MAKE) -B _smt + @ echo Running 'litani build' + $(LITANI) run-build + @ echo Generated SMT file for prover $(PROVER_NAME) in $(HARNESS_GOTO).smt2 + +_smtz: $(HARNESS_GOTO).smtz +smtz: + @ echo Running 'litani init' + $(LITANI) init $(INIT_POOLS) --project $(PROJECT_NAME) + @ echo Running 'litani add-job' + $(MAKE) -B _smtz + @ echo Running 'litani build' + $(LITANI) run-build + @ echo Generated SMT file for Z3 in $(HARNESS_GOTO).smtz + +_smtb: $(HARNESS_GOTO).smtb +smtb: + @ echo Running 'litani init' + $(LITANI) init $(INIT_POOLS) --project $(PROJECT_NAME) + @ echo Running 'litani add-job' + $(MAKE) -B _smtb + @ echo Running 'litani build' + $(LITANI) run-build + @ echo Generated SMT file for Bitwuzla in $(HARNESS_GOTO).smtb + +_smtc: $(HARNESS_GOTO).smtc +smtc: + @ echo Running 'litani init' + $(LITANI) init $(INIT_POOLS) --project $(PROJECT_NAME) + @ echo Running 'litani add-job' + $(MAKE) -B _smtc + @ echo Running 'litani build' + $(LITANI) run-build + @ echo Generated SMT file for cvc5 in $(HARNESS_GOTO).smtc + +_smtall: $(HARNESS_GOTO).smtz $(HARNESS_GOTO).smtb $(HARNESS_GOTO).smtc +smtall: + @ echo Running 'litani init' + $(LITANI) init $(INIT_POOLS) --project $(PROJECT_NAME) + @ echo Running 'litani add-job' + $(MAKE) -B _smtall + @ echo Running 'litani build' + $(LITANI) run-build + @ echo Generated SMT files for provers Z3, Bitwuzla, and cvc5 in + @ echo $(HARNESS_GOTO).smtz + @ echo $(HARNESS_GOTO).smtb + @ echo $(HARNESS_GOTO).smtc + +_property: $(LOGDIR)/property.xml +property: + @ echo Running 'litani init' + $(LITANI) init $(INIT_POOLS) --project $(PROJECT_NAME) + @ echo Running 'litani add-job' + $(MAKE) -B _property + @ echo Running 'litani build' + $(LITANI) run-build + +_coverage: $(LOGDIR)/coverage.xml +coverage: + @ echo Running 'litani init' + $(LITANI) init $(INIT_POOLS) --project $(PROJECT_NAME) + @ echo Running 'litani add-job' + $(MAKE) -B _coverage + @ echo Running 'litani build' + $(LITANI) run-build + +_report: $(PROOFDIR)/report +report: + @ echo Running 'litani init' + $(LITANI) init $(INIT_POOLS) --project $(PROJECT_NAME) + @ echo Running 'litani add-job' + $(MAKE) -B _report + @ echo Running 'litani build' + $(LITANI) run-build + +_report_no_coverage: + $(MAKE) COVERAGE="" VIEWER_COVERAGE_FLAG="" _report +report-no-coverage: + $(MAKE) COVERAGE="" VIEWER_COVERAGE_FLAG=" " report + +################################################################ +# Targets to clean up after ourselves +clean: + -$(RM) $(DEPENDENT_GOTOS) + -$(RM) TAGS* + -$(RM) *~ \#* + -$(RM) $(REWRITTEN_SOURCES) $(foreach rs,$(REWRITTEN_SOURCES),$(rs).json) + +veryclean: clean + -$(RM) -r report + -$(RM) -r $(LOGDIR) $(GOTODIR) + +.PHONY: \ + _coverage \ + _goto \ + _property \ + _report \ + _report_no_coverage \ + clean \ + coverage \ + goto \ + litani-path \ + property \ + report \ + report-no-coverage \ + result \ + setup_dependencies \ + testdeps \ + veryclean \ + # + +################################################################ + +# Run "make echo-proof-uid" to print the proof ID of a proof. This can be +# used by scripts to ensure that every proof has an ID, that there are +# no duplicates, etc. + +.PHONY: echo-proof-uid +echo-proof-uid: + @echo $(PROOF_UID) + +.PHONY: echo-project-name +echo-project-name: + @echo $(PROJECT_NAME) + +################################################################ + +# Project-specific targets requiring values defined above +sinclude $(PROOF_ROOT)/Makefile-project-targets + +# CI-specific targets to drive cbmc in CI +sinclude $(PROOF_ROOT)/Makefile-project-testing + +################################################################ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/Makefile_params.common b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/Makefile_params.common new file mode 100644 index 0000000000..e66ffedcaf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/Makefile_params.common @@ -0,0 +1,21 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +ifndef MLD_CONFIG_PARAMETER_SET + $(warning MLD_CONFIG_PARAMETER_SET not set -- defaulting to MLD_CONFIG_PARAMETER_SET=65) +endif + +MLD_CONFIG_PARAMETER_SET ?= 65 + +ifeq ($(MLD_CONFIG_PARAMETER_SET),44) + MLD_NAMESPACE_KL=PQCP_MLDSA_NATIVE_MLDSA44_ + MLD_NAMESPACE=PQCP_MLDSA_NATIVE_MLDSA44_ +else ifeq ($(MLD_CONFIG_PARAMETER_SET),65) + MLD_NAMESPACE_KL=PQCP_MLDSA_NATIVE_MLDSA65_ + MLD_NAMESPACE=PQCP_MLDSA_NATIVE_MLDSA65_ +else ifeq ($(MLD_CONFIG_PARAMETER_SET),87) + MLD_NAMESPACE_KL=PQCP_MLDSA_NATIVE_MLDSA87_ + MLD_NAMESPACE=PQCP_MLDSA_NATIVE_MLDSA87_ +else + $(error Invalid value of MLD_CONFIG_PARAMETER_SET) +endif diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/attempt_signature_generation/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/attempt_signature_generation/Makefile new file mode 100644 index 0000000000..f7a494d1ad --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/attempt_signature_generation/Makefile @@ -0,0 +1,77 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = attempt_signature_generation_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_attempt_signature_generation + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=mld_attempt_signature_generation +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvecl_uniform_gamma1 \ + $(MLD_NAMESPACE)polyvecl_ntt \ + $(MLD_NAMESPACE)polyvec_matrix_pointwise_montgomery \ + $(MLD_NAMESPACE)polyveck_reduce \ + $(MLD_NAMESPACE)polyveck_invntt_tomont \ + $(MLD_NAMESPACE)polyveck_caddq \ + $(MLD_NAMESPACE)polyveck_decompose \ + $(MLD_NAMESPACE)polyveck_pack_w1 \ + mld_H \ + $(MLD_NAMESPACE)poly_challenge \ + $(MLD_NAMESPACE)poly_ntt \ + $(MLD_NAMESPACE)polyveck_pointwise_poly_montgomery \ + $(MLD_NAMESPACE)polyveck_sub \ + $(MLD_NAMESPACE)polyveck_reduce \ + $(MLD_NAMESPACE)polyveck_chknorm \ + $(MLD_NAMESPACE)polyveck_add \ + $(MLD_NAMESPACE)polyveck_make_hint \ + $(MLD_NAMESPACE)pack_sig_c_h \ + mld_compute_pack_z +USE_FUNCTION_CONTRACTS+=mld_zeroize + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--external-smt2-solver $(PROOF_ROOT)/lib/z3_no_bv_extract --z3 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = mld_attempt_signature_generation + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 12 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/attempt_signature_generation/attempt_signature_generation_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/attempt_signature_generation/attempt_signature_generation_harness.c new file mode 100644 index 0000000000..61650a51b3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/attempt_signature_generation/attempt_signature_generation_harness.c @@ -0,0 +1,27 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +int mld_attempt_signature_generation(uint8_t *sig, const uint8_t *mu, + const uint8_t rhoprime[MLDSA_CRHBYTES], + uint16_t nonce, mld_polymat *mat, + const mld_polyvecl *s1, + const mld_polyveck *s2, + const mld_polyveck *t0); + +void harness(void) +{ + uint8_t *sig; + uint8_t *mu; + uint8_t *rhoprime; + uint16_t nonce; + mld_polymat *mat; + mld_polyvecl *s1; + mld_polyveck *s2; + mld_polyveck *t0; + + int r; + r = mld_attempt_signature_generation(sig, mu, rhoprime, nonce, mat, s1, s2, + t0); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/caddq/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/caddq/Makefile new file mode 100644 index 0000000000..0c486c5aab --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/caddq/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = caddq_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = caddq + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_caddq +USE_FUNCTION_CONTRACTS=mld_ct_sel_int32 mld_ct_cmask_neg_i32 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = caddq + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/caddq/caddq_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/caddq/caddq_harness.c new file mode 100644 index 0000000000..84b32e9d45 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/caddq/caddq_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "reduce.h" + +void harness(void) +{ + int32_t a; + int32_t result = mld_caddq(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/check_pct/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/check_pct/Makefile new file mode 100644 index 0000000000..06d1eda47e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/check_pct/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = check_pct_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_check_pct + +DEFINES += -DMLD_CONFIG_KEYGEN_PCT +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=mld_check_pct +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)signature $(MLD_NAMESPACE)verify +USE_FUNCTION_CONTRACTS+=mld_zeroize +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_check_pct + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/sign.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/sign.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/check_pct/check_pct_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/check_pct/check_pct_harness.c new file mode 100644 index 0000000000..a5085ce73b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/check_pct/check_pct_harness.c @@ -0,0 +1,14 @@ +// Copyright (c) The mldsa-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 + +#include "sign.h" + +int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], + uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES]); + +void harness(void) +{ + uint8_t *a, *b; + mld_check_pct(a, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/compute_pack_z/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/compute_pack_z/Makefile new file mode 100644 index 0000000000..3e9166327b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/compute_pack_z/Makefile @@ -0,0 +1,64 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = compute_pack_z_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_compute_pack_z + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=mld_compute_pack_z +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_pointwise_montgomery \ + $(MLD_NAMESPACE)poly_invntt_tomont \ + $(MLD_NAMESPACE)poly_add \ + $(MLD_NAMESPACE)poly_reduce \ + $(MLD_NAMESPACE)poly_chknorm \ + $(MLD_NAMESPACE)pack_sig_z +USE_FUNCTION_CONTRACTS+=mld_zeroize + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--external-smt2-solver $(PROOF_ROOT)/lib/z3_no_bv_extract --z3 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = mld_compute_pack_z + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 12 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/compute_pack_z/compute_pack_z_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/compute_pack_z/compute_pack_z_harness.c new file mode 100644 index 0000000000..6200e76cd7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/compute_pack_z/compute_pack_z_harness.c @@ -0,0 +1,20 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +int mld_compute_pack_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *cp, + const mld_polyvecl *s1, const mld_polyvecl *y, + mld_poly *t); + +void harness(void) +{ + uint8_t *sig; + mld_poly *cp; + mld_polyvecl *s1; + mld_polyvecl *y; + mld_poly *t; + + int r; + r = mld_compute_pack_z(sig, cp, s1, y, t); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/compute_t0_t1_tr_from_sk_components/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/compute_t0_t1_tr_from_sk_components/Makefile new file mode 100644 index 0000000000..353ed28da2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/compute_t0_t1_tr_from_sk_components/Makefile @@ -0,0 +1,68 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = compute_t0_t1_tr_from_sk_components_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_compute_t0_t1_tr_from_sk_components + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=mld_compute_t0_t1_tr_from_sk_components +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake256 +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyvec_matrix_expand +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyvecl_ntt +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyvec_matrix_pointwise_montgomery +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_reduce +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_invntt_tomont +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_add +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_caddq +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_power2round +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)pack_pk +USE_FUNCTION_CONTRACTS+=mld_zeroize + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--external-smt2-solver $(PROOF_ROOT)/lib/z3_no_bv_extract --z3 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = mld_compute_t0_t1_tr_from_sk_components + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 12 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/compute_t0_t1_tr_from_sk_components/compute_t0_t1_tr_from_sk_components_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/compute_t0_t1_tr_from_sk_components/compute_t0_t1_tr_from_sk_components_harness.c new file mode 100644 index 0000000000..1fa7ed575c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/compute_t0_t1_tr_from_sk_components/compute_t0_t1_tr_from_sk_components_harness.c @@ -0,0 +1,22 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +int mld_compute_t0_t1_tr_from_sk_components( + mld_polyveck *t0, mld_polyveck *t1, uint8_t tr[MLDSA_TRBYTES], + uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], const uint8_t rho[MLDSA_SEEDBYTES], + const mld_polyvecl *s1, const mld_polyveck *s2); + +void harness(void) +{ + mld_polyveck *t0; + mld_polyveck *t1; + uint8_t *tr; + uint8_t *pk; + uint8_t *rho; + mld_polyvecl *s1; + mld_polyveck *s2; + + mld_compute_t0_t1_tr_from_sk_components(t0, t1, tr, pk, rho, s1, s2); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_abs_i32/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_abs_i32/Makefile new file mode 100644 index 0000000000..04b8485fa7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_abs_i32/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = ct_abs_i32_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_ct_abs_i32 + +DEFINES += -DMLD_CONFIG_NO_ASM_VALUE_BARRIER +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/ct.c + +CHECK_FUNCTION_CONTRACTS=mld_ct_abs_i32 +USE_FUNCTION_CONTRACTS=mld_ct_sel_int32 mld_ct_cmask_neg_i32 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_ct_abs_i32 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_abs_i32/ct_abs_i32_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_abs_i32/ct_abs_i32_harness.c new file mode 100644 index 0000000000..f2d51f5e65 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_abs_i32/ct_abs_i32_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "ct.h" + +void harness(void) +{ + int32_t a; + mld_ct_abs_i32(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_neg_i32/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_neg_i32/Makefile new file mode 100644 index 0000000000..f61f39bd8d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_neg_i32/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = ct_cmask_neg_i32_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_ct_cmask_neg_i32 + +DEFINES += -DMLD_CONFIG_NO_ASM_VALUE_BARRIER +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/ct.c + +CHECK_FUNCTION_CONTRACTS=mld_ct_cmask_neg_i32 +USE_FUNCTION_CONTRACTS=mld_value_barrier_i64 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_ct_cmask_neg_i32 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_neg_i32/ct_cmask_neg_i32_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_neg_i32/ct_cmask_neg_i32_harness.c new file mode 100644 index 0000000000..fd036503ca --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_neg_i32/ct_cmask_neg_i32_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "ct.h" + +void harness(void) +{ + int32_t a; + mld_ct_cmask_neg_i32(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_nonzero_u32/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_nonzero_u32/Makefile new file mode 100644 index 0000000000..b7e6db0b2d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_nonzero_u32/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = ct_cmask_nonzero_u32_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_ct_cmask_nonzero_u32 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c # Dummy because the Makefile wants _some_ project source + +CHECK_FUNCTION_CONTRACTS=mld_ct_cmask_nonzero_u32 +USE_FUNCTION_CONTRACTS=mld_value_barrier_i64 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_ct_cmask_nonzero_u32 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/src/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_nonzero_u32/ct_cmask_nonzero_u32_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_nonzero_u32/ct_cmask_nonzero_u32_harness.c new file mode 100644 index 0000000000..b36ba0b354 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_nonzero_u32/ct_cmask_nonzero_u32_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mlkem-native project authors +// Copyright (c) The mldsa-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 AND Apache-2.0 + +#include "ct.h" + +void harness(void) +{ + uint32_t a, b; + + b = mld_ct_cmask_nonzero_u32(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_nonzero_u8/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_nonzero_u8/Makefile new file mode 100644 index 0000000000..a0eb448848 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_nonzero_u8/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) The mldsa-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = ct_cmask_nonzero_u8_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_ct_cmask_nonzero_u8 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c # Dummy because the Makefile wants _some_ project source + +CHECK_FUNCTION_CONTRACTS=mld_ct_cmask_nonzero_u8 +USE_FUNCTION_CONTRACTS=mld_value_barrier_u32 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_ct_cmask_nonzero_u8 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/src/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_nonzero_u8/ct_cmask_nonzero_u8_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_nonzero_u8/ct_cmask_nonzero_u8_harness.c new file mode 100644 index 0000000000..a9f1699c02 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_cmask_nonzero_u8/ct_cmask_nonzero_u8_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mlkem-native project authors +// Copyright (c) The mldsa-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 AND Apache-2.0 + +#include "ct.h" + +void harness(void) +{ + uint8_t a, b; + + b = mld_ct_cmask_nonzero_u8(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_i64/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_i64/Makefile new file mode 100644 index 0000000000..41b35704f8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_i64/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = ct_get_optblocker_i64_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_ct_get_optblocker_i64 + +DEFINES += -DMLD_CONFIG_NO_ASM_VALUE_BARRIER +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/ct.c + +CHECK_FUNCTION_CONTRACTS=mld_ct_get_optblocker_i64 +USE_FUNCTION_CONTRACTS=mld_ct_get_optblocker_u64 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_ct_get_optblocker_i64 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_i64/ct_get_optblocker_i64_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_i64/ct_get_optblocker_i64_harness.c new file mode 100644 index 0000000000..2d309ef27c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_i64/ct_get_optblocker_i64_harness.c @@ -0,0 +1,6 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "ct.h" + +void harness(void) { mld_ct_get_optblocker_i64(); } diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_u32/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_u32/Makefile new file mode 100644 index 0000000000..163634af82 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_u32/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = ct_get_optblocker_u32_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_ct_get_optblocker_u32 + +DEFINES += -DMLD_CONFIG_NO_ASM_VALUE_BARRIER +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/ct.c + +CHECK_FUNCTION_CONTRACTS=mld_ct_get_optblocker_u32 +USE_FUNCTION_CONTRACTS=mld_ct_get_optblocker_u64 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_ct_get_optblocker_u32 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_u32/ct_get_optblocker_u32_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_u32/ct_get_optblocker_u32_harness.c new file mode 100644 index 0000000000..b4bb4ab5d1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_u32/ct_get_optblocker_u32_harness.c @@ -0,0 +1,6 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "ct.h" + +void harness(void) { mld_ct_get_optblocker_u32(); } diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_u8/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_u8/Makefile new file mode 100644 index 0000000000..2237b9af34 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_u8/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = ct_get_optblocker_u8_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_ct_get_optblocker_u8 + +DEFINES += -DMLD_CONFIG_NO_ASM_VALUE_BARRIER +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/ct.c + +CHECK_FUNCTION_CONTRACTS=mld_ct_get_optblocker_u8 +USE_FUNCTION_CONTRACTS=mld_ct_get_optblocker_u64 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = mld_ct_get_optblocker_u8 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/src/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_u8/ct_get_optblocker_u8_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_u8/ct_get_optblocker_u8_harness.c new file mode 100644 index 0000000000..9cd9f96bc2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_get_optblocker_u8/ct_get_optblocker_u8_harness.c @@ -0,0 +1,7 @@ +// Copyright (c) The mldsa-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 AND Apache-2.0 + +#include "ct.h" + +void harness(void) { uint8_t x = mld_ct_get_optblocker_u8(); } diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_memcmp/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_memcmp/Makefile new file mode 100644 index 0000000000..d83dd57e49 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_memcmp/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = ct_memcmp_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_ct_memcmp + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/ct.c + +CHECK_FUNCTION_CONTRACTS=mld_ct_memcmp +USE_FUNCTION_CONTRACTS=mld_value_barrier_u8 mld_ct_cmask_nonzero_u8 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_ct_memcmp + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/src/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_memcmp/ct_memcmp_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_memcmp/ct_memcmp_harness.c new file mode 100644 index 0000000000..7a496408e1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_memcmp/ct_memcmp_harness.c @@ -0,0 +1,14 @@ +// Copyright (c) The mldsa-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 AND Apache-2.0 + +#include "ct.h" + +void harness(void) +{ + uint8_t *a; + uint8_t *b; + size_t len; + int r; + r = mld_ct_memcmp(a, b, len); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_sel_int32/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_sel_int32/Makefile new file mode 100644 index 0000000000..76d76b4701 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_sel_int32/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = ct_sel_int32_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_ct_sel_int32 + +DEFINES += -DMLD_CONFIG_NO_ASM_VALUE_BARRIER +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/ct.c + +CHECK_FUNCTION_CONTRACTS=mld_ct_sel_int32 +USE_FUNCTION_CONTRACTS=mld_value_barrier_u32 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_ct_sel_int32 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_sel_int32/ct_sel_int32_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_sel_int32/ct_sel_int32_harness.c new file mode 100644 index 0000000000..e40d51c7f9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ct_sel_int32/ct_sel_int32_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "ct.h" + +void harness(void) +{ + int32_t a, b; + uint32_t cond; + mld_ct_sel_int32(a, b, cond); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/decompose/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/decompose/Makefile new file mode 100644 index 0000000000..5bbebefc22 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/decompose/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = decompose_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = decompose + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_decompose +USE_FUNCTION_CONTRACTS=mld_ct_sel_int32 mld_ct_cmask_neg_i32 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = decompose + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/decompose/decompose_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/decompose/decompose_harness.c new file mode 100644 index 0000000000..c8a7c5adb5 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/decompose/decompose_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "rounding.h" + + +void harness(void) +{ + int32_t *a0, *a1; + int32_t a; + mld_decompose(a0, a1, a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/dummy_backend.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/dummy_backend.h new file mode 100644 index 0000000000..0fff575648 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/dummy_backend.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_DUMMY_ARITH_BACKEND_H +#define MLD_DUMMY_ARITH_BACKEND_H + + +#define MLD_USE_NATIVE_NTT +#define MLD_USE_NATIVE_INTT +#define MLD_USE_NATIVE_REJ_UNIFORM +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA2 +#define MLD_USE_NATIVE_REJ_UNIFORM_ETA4 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_32 +#define MLD_USE_NATIVE_POLY_DECOMPOSE_88 +#define MLD_USE_NATIVE_POLY_CADDQ +#define MLD_USE_NATIVE_POLY_USE_HINT_32 +#define MLD_USE_NATIVE_POLY_USE_HINT_88 +#define MLD_USE_NATIVE_POLY_CHKNORM +#define MLD_USE_NATIVE_POLYZ_UNPACK_17 +#define MLD_USE_NATIVE_POLYZ_UNPACK_19 +#define MLD_USE_NATIVE_POINTWISE_MONTGOMERY +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 +#define MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 +#define MLD_USE_NATIVE_NTT_CUSTOM_ORDER + +#include "../../mldsa/src/native/api.h" + +#endif /* !MLD_DUMMY_ARITH_BACKEND_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/dummy_backend_fips202_x1.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/dummy_backend_fips202_x1.h new file mode 100644 index 0000000000..fb71bdc318 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/dummy_backend_fips202_x1.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_DUMMY_FIPS202X1_BACKEND_H +#define MLD_DUMMY_FIPS202X1_BACKEND_H + + +#define MLD_USE_FIPS202_X1_NATIVE + +#include "../../mldsa/src/fips202/native/api.h" + +#endif /* !MLD_DUMMY_FIPS202X1_BACKEND_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/dummy_backend_fips202_x4.h b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/dummy_backend_fips202_x4.h new file mode 100644 index 0000000000..d84df09c5b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/dummy_backend_fips202_x4.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_DUMMY_FIPS202X4_BACKEND_H +#define MLD_DUMMY_FIPS202X4_BACKEND_H + + +#define MLD_USE_FIPS202_X4_NATIVE + +#include "../../mldsa/src/fips202/native/api.h" + +#endif /* !MLD_DUMMY_FIPS202X4_BACKEND_H */ diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/fqmul/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/fqmul/Makefile new file mode 100644 index 0000000000..8652000fcc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/fqmul/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = fqmul_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = fqmul + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_fqmul +USE_FUNCTION_CONTRACTS=mld_montgomery_reduce +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = mld_fqmul + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/fqmul/fqmul_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/fqmul/fqmul_harness.c new file mode 100644 index 0000000000..d36072a1c8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/fqmul/fqmul_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +int32_t mld_fqmul(int32_t a, int32_t b); +void harness(void) +{ + int32_t a, b, r; + r = mld_fqmul(a, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/fqscale/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/fqscale/Makefile new file mode 100644 index 0000000000..d821b2d266 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/fqscale/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = fqscale_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = fqscale + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_fqscale +USE_FUNCTION_CONTRACTS=mld_montgomery_reduce +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = mld_fqscale + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/fqscale/fqscale_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/fqscale/fqscale_harness.c new file mode 100644 index 0000000000..647cb849b5 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/fqscale/fqscale_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +int32_t mld_fqscale(int32_t a); +void harness(void) +{ + int32_t a, r; + r = mld_fqscale(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/invntt_layer/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/invntt_layer/Makefile new file mode 100644 index 0000000000..b1503d8a51 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/invntt_layer/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = invntt_layer_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_invntt_layer + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_invntt_layer +USE_FUNCTION_CONTRACTS=mld_fqmul +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_invntt_layer + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/invntt_layer/invntt_layer_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/invntt_layer/invntt_layer_harness.c new file mode 100644 index 0000000000..4f8fb4ce94 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/invntt_layer/invntt_layer_harness.c @@ -0,0 +1,14 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include +#include "params.h" + +void mld_invntt_layer(int32_t r[MLDSA_N], unsigned layer); + +void harness(void) +{ + int32_t *r; + unsigned layer; + mld_invntt_layer(r, layer); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_absorb/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_absorb/Makefile new file mode 100644 index 0000000000..e4a228adab --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_absorb/Makefile @@ -0,0 +1,58 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = keccak_absorb_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = keccak_absorb + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +# Set specific unwinding limits for loops +# Format: function_name.loop_number:N +# Example: keccak_absorb.0:3 will unwind the first loop in keccak_absorb 3 times +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=keccak_absorb +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600_permute $(MLD_NAMESPACE)keccakf1600_xor_bytes +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = keccak_absorb + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_absorb/keccak_absorb_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_absorb/keccak_absorb_harness.c new file mode 100644 index 0000000000..6e7665469b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_absorb/keccak_absorb_harness.c @@ -0,0 +1,19 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +extern unsigned int keccak_absorb(uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r, + const uint8_t *in, size_t inlen); + +void harness(void) +{ + uint64_t *s; + unsigned int pos; + const unsigned int r; + const uint8_t *in; + size_t inlen; + + keccak_absorb(s, pos, r, in, inlen); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_absorb_once_x4/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_absorb_once_x4/Makefile new file mode 100644 index 0000000000..34be3dbc99 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_absorb_once_x4/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) The mldsa-native project authors +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = keccak_absorb_once_x4_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = keccak_absorb_once_x4 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202x4.c + +CHECK_FUNCTION_CONTRACTS=mld_keccak_absorb_once_x4 +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600x4_permute $(MLD_NAMESPACE)keccakf1600x4_xor_bytes +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = mld_keccak_absorb_once_x4 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mlkem/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mlkem/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_absorb_once_x4/keccak_absorb_once_x4_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_absorb_once_x4/keccak_absorb_once_x4_harness.c new file mode 100644 index 0000000000..b6e606de1c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_absorb_once_x4/keccak_absorb_once_x4_harness.c @@ -0,0 +1,24 @@ +// Copyright (c) The mldsa-native project authors +// Copyright (c) The mlkem-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 + +#include +#include +#include +#include + + +void mld_keccak_absorb_once_x4(uint64_t *s, uint32_t r, const uint8_t *in0, + const uint8_t *in1, const uint8_t *in2, + const uint8_t *in3, size_t inlen, uint8_t p); + +void harness(void) +{ + uint64_t *s; + uint32_t r; + const uint8_t *in0, *in1, *in2, *in3; + size_t inlen; + uint8_t p; + mld_keccak_absorb_once_x4(s, r, in0, in1, in2, in3, inlen, p); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_finalize/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_finalize/Makefile new file mode 100644 index 0000000000..b07a171b9e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_finalize/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = keccak_finalize_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = keccak_finalize + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=keccak_finalize +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600_xor_bytes +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = keccak_finalize + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_finalize/keccak_finalize_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_finalize/keccak_finalize_harness.c new file mode 100644 index 0000000000..ad33a17383 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_finalize/keccak_finalize_harness.c @@ -0,0 +1,16 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +extern void keccak_finalize(uint64_t s[MLD_KECCAK_LANES], unsigned int pos, + unsigned int r, uint8_t p); + +void harness(void) +{ + uint64_t *s; + unsigned int pos, r; + uint8_t p; + + keccak_finalize(s, pos, r, p); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_init/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_init/Makefile new file mode 100644 index 0000000000..3826414814 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_init/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = keccak_init_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = keccak_init + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=keccak_init +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = keccak_init + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_init/keccak_init_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_init/keccak_init_harness.c new file mode 100644 index 0000000000..c5a81ae5f0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_init/keccak_init_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +extern void keccak_init(uint64_t s[MLD_KECCAK_LANES]); + +void harness(void) +{ + uint64_t *s; + + keccak_init(s); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_squeeze/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_squeeze/Makefile new file mode 100644 index 0000000000..0fac3a78c3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_squeeze/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = keccak_squeeze_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = keccak_squeeze + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=keccak_squeeze +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600_permute $(MLD_NAMESPACE)keccakf1600_extract_bytes +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = keccak_squeeze + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_squeeze/keccak_squeeze_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_squeeze/keccak_squeeze_harness.c new file mode 100644 index 0000000000..1c25ae10ad --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_squeeze/keccak_squeeze_harness.c @@ -0,0 +1,18 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +static unsigned int keccak_squeeze(uint8_t *out, size_t outlen, + uint64_t s[MLD_KECCAK_LANES], + unsigned int pos, unsigned int r); + +void harness(void) +{ + uint8_t *out; + size_t outlen; + uint64_t *s; + unsigned int pos, r; + + keccak_squeeze(out, outlen, s, pos, r); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_squeezeblocks_x4/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_squeezeblocks_x4/Makefile new file mode 100644 index 0000000000..5c9432a51e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_squeezeblocks_x4/Makefile @@ -0,0 +1,67 @@ +# Copyright (c) The mldsa-native project authors +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = keccak_squeezeblocks_x4_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = keccak_squeezeblocks_x4 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202x4.c + +CHECK_FUNCTION_CONTRACTS=mld_keccak_squeezeblocks_x4 +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600x4_extract_bytes $(MLD_NAMESPACE)keccakf1600x4_permute +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +# For this proof we tell CBMC to +# - not decompose arrays into their individual cells +# - to slice constraints that are not in the cone of influence of the proof obligations +# These options simplify them modelling of arrays and produce much more compact +# SMT files, leaving all array-type reasoning to the SMT solver. +# +# For functions that use large and multi-dimensional arrays, this yields +# a substantial improvement in proof performance. +CBMCFLAGS += --no-array-field-sensitivity +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = mld_keccak_squeezeblocks_x4 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mlkem/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mlkem/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_squeezeblocks_x4/keccak_squeezeblocks_x4_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_squeezeblocks_x4/keccak_squeezeblocks_x4_harness.c new file mode 100644 index 0000000000..09af465f1b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccak_squeezeblocks_x4/keccak_squeezeblocks_x4_harness.c @@ -0,0 +1,23 @@ +// Copyright (c) The mldsa-native project authors +// Copyright (c) The mlkem-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 + +#include +#include +#include +#include + + +void mld_keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1, uint8_t *out2, + uint8_t *out3, size_t nblocks, uint64_t *s, + uint32_t r); + +void harness(void) +{ + uint8_t *out0, out1, out2, out3; + size_t nblocks; + uint64_t *s; + uint32_t r; + mld_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, s, r); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_extract_bytes/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_extract_bytes/Makefile new file mode 100644 index 0000000000..2b01976262 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_extract_bytes/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = keccakf1600_extract_bytes_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_keccakf1600_extract_bytes + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/keccakf1600.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600_extract_bytes +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_keccakf1600_extract_bytes + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_extract_bytes/keccakf1600_extract_bytes_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_extract_bytes/keccakf1600_extract_bytes_harness.c new file mode 100644 index 0000000000..9a2c745ef6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_extract_bytes/keccakf1600_extract_bytes_harness.c @@ -0,0 +1,15 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +#include + +void harness(void) +{ + uint64_t *state; + unsigned char *data; + unsigned offset; + unsigned length; + mld_keccakf1600_extract_bytes(state, data, offset, length); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_extract_bytes_BE/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_extract_bytes_BE/Makefile new file mode 100644 index 0000000000..1c160958a7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_extract_bytes_BE/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = keccakf1600_extract_bytes_be_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = keccakf1600_extract_bytes (big endian) + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/keccakf1600.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600_extract_bytes +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 --big-endian +DEFINES += -DMLD_SYS_BIG_ENDIAN=1 + +FUNCTION_NAME = mld_keccakf1600_extract_bytes + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_extract_bytes_BE/keccakf1600_extract_bytes_be_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_extract_bytes_BE/keccakf1600_extract_bytes_be_harness.c new file mode 100644 index 0000000000..9a2c745ef6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_extract_bytes_BE/keccakf1600_extract_bytes_be_harness.c @@ -0,0 +1,15 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +#include + +void harness(void) +{ + uint64_t *state; + unsigned char *data; + unsigned offset; + unsigned length; + mld_keccakf1600_extract_bytes(state, data, offset, length); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_permute/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_permute/Makefile new file mode 100644 index 0000000000..bc50dd57b9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_permute/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = keccakf1600_permute_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = keccakf1600_permute + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/keccakf1600.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600_permute +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_keccakf1600_permute + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_permute/keccakf1600_permute_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_permute/keccakf1600_permute_harness.c new file mode 100644 index 0000000000..5647efb411 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_permute/keccakf1600_permute_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include + +void harness(void) +{ + uint64_t *a; + mld_keccakf1600_permute(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_permute_native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_permute_native/Makefile new file mode 100644 index 0000000000..ce5f5a76e2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_permute_native/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = keccakf1600_permute_native_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = keccakf1600_permute_native + +DEFINES += -DMLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 -DMLD_CONFIG_FIPS202_BACKEND_FILE="\"dummy_backend_fips202_x1.h\"" +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/keccakf1600.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600_permute +USE_FUNCTION_CONTRACTS=mld_keccak_f1600_x1_native +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_keccakf1600_permute_native + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_permute_native/keccakf1600_permute_native_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_permute_native/keccakf1600_permute_native_harness.c new file mode 100644 index 0000000000..5647efb411 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_permute_native/keccakf1600_permute_native_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include + +void harness(void) +{ + uint64_t *a; + mld_keccakf1600_permute(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_xor_bytes/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_xor_bytes/Makefile new file mode 100644 index 0000000000..501d2215f3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_xor_bytes/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) The mldsa-native project authors +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = keccakf1600_xor_bytes_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = keccakf1600_xor_bytes + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/keccakf1600.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600_xor_bytes +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = mld_keccakf1600_xor_bytes + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mlkem/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mlkem/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_xor_bytes/keccakf1600_xor_bytes_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_xor_bytes/keccakf1600_xor_bytes_harness.c new file mode 100644 index 0000000000..977f571b55 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_xor_bytes/keccakf1600_xor_bytes_harness.c @@ -0,0 +1,15 @@ +// Copyright (c) The mldsa-native project authors +// Copyright (c) The mlkem-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 + +#include + +void harness(void) +{ + uint64_t *state; + const unsigned char *data; + unsigned offset; + unsigned length; + mld_keccakf1600_xor_bytes(state, data, offset, length); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_xor_bytes_BE/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_xor_bytes_BE/Makefile new file mode 100644 index 0000000000..719989c9e3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_xor_bytes_BE/Makefile @@ -0,0 +1,58 @@ +# Copyright (c) The mldsa-native project authors +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = keccakf1600_xor_bytes_be_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = keccakf1600_xor_bytes (big endian) + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/keccakf1600.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600_xor_bytes +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla --big-endian + +DEFINES += -DMLD_SYS_BIG_ENDIAN + +FUNCTION_NAME = mld_keccakf1600_xor_bytes + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mlkem/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mlkem/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_xor_bytes_BE/keccakf1600_xor_bytes_be_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_xor_bytes_BE/keccakf1600_xor_bytes_be_harness.c new file mode 100644 index 0000000000..977f571b55 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600_xor_bytes_BE/keccakf1600_xor_bytes_be_harness.c @@ -0,0 +1,15 @@ +// Copyright (c) The mldsa-native project authors +// Copyright (c) The mlkem-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 + +#include + +void harness(void) +{ + uint64_t *state; + const unsigned char *data; + unsigned offset; + unsigned length; + mld_keccakf1600_xor_bytes(state, data, offset, length); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_extract_bytes/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_extract_bytes/Makefile new file mode 100644 index 0000000000..e62f5e4f3e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_extract_bytes/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) The mldsa-native project authors +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = keccakf1600x4_extract_bytes_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = keccakf1600x4_extract_bytes + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/keccakf1600.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600x4_extract_bytes +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600_extract_bytes +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = mld_keccakf1600x4_extract_bytes + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mlkem/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mlkem/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_extract_bytes/keccakf1600x4_extract_bytes_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_extract_bytes/keccakf1600x4_extract_bytes_harness.c new file mode 100644 index 0000000000..a0791ca538 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_extract_bytes/keccakf1600x4_extract_bytes_harness.c @@ -0,0 +1,16 @@ +// Copyright (c) The mldsa-native project authors +// Copyright (c) The mlkem-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 + +#include + +void harness(void) +{ + uint64_t *state; + unsigned char *data0, *data1, *data2, *data3; + unsigned offset; + unsigned length; + mld_keccakf1600x4_extract_bytes(state, data0, data1, data2, data3, offset, + length); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_permute/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_permute/Makefile new file mode 100644 index 0000000000..4283879471 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_permute/Makefile @@ -0,0 +1,67 @@ +# Copyright (c) The mldsa-native project authors +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = keccakf1600x4_permute_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = keccakf1600x4_permute + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/keccakf1600.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600x4_permute +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600_permute +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +# For this proof we tell CBMC to +# - not decompose arrays into their individual cells +# - to slice constraints that are not in the cone of influence of the proof obligations +# These options simplify them modelling of arrays and produce much more compact +# SMT files, leaving all array-type reasoning to the SMT solver. +# +# For functions that use large and multi-dimensional arrays, this yields +# a substantial improvement in proof performance. +CBMCFLAGS += --no-array-field-sensitivity +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = mld_keccakf1600x4_permute + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mlkem/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mlkem/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_permute/keccakf1600x4_permute_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_permute/keccakf1600x4_permute_harness.c new file mode 100644 index 0000000000..ed72d896b5 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_permute/keccakf1600x4_permute_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// Copyright (c) The mlkem-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 + +#include + +void harness(void) +{ + uint64_t *s; + mld_keccakf1600x4_permute(s); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_permute_native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_permute_native/Makefile new file mode 100644 index 0000000000..a0900c1147 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_permute_native/Makefile @@ -0,0 +1,67 @@ +# Copyright (c) The mldsa-native project authors +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = keccakf1600x4_permute_native_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = keccakf1600x4_permute_native + +DEFINES += -DMLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 -DMLD_CONFIG_FIPS202_BACKEND_FILE="\"dummy_backend_fips202_x4.h\"" +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/keccakf1600.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600x4_permute +USE_FUNCTION_CONTRACTS=mld_keccak_f1600_x4_native +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +# For this proof we tell CBMC to +# - not decompose arrays into their individual cells +# - to slice constraints that are not in the cone of influence of the proof obligations +# These options simplify them modelling of arrays and produce much more compact +# SMT files, leaving all array-type reasoning to the SMT solver. +# +# For functions that use large and multi-dimensional arrays, this yields +# a substantial improvement in proof performance. +CBMCFLAGS += --no-array-field-sensitivity +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = mld_keccakf1600x4_permute_native + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mlkem/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mlkem/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_permute_native/keccakf1600x4_permute_native_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_permute_native/keccakf1600x4_permute_native_harness.c new file mode 100644 index 0000000000..ed72d896b5 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_permute_native/keccakf1600x4_permute_native_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// Copyright (c) The mlkem-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 + +#include + +void harness(void) +{ + uint64_t *s; + mld_keccakf1600x4_permute(s); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_xor_bytes/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_xor_bytes/Makefile new file mode 100644 index 0000000000..5cf96463f4 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_xor_bytes/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) The mldsa-native project authors +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = keccakf1600x4_xor_bytes_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = keccakf1600x4_xor_bytes + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/keccakf1600.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600x4_xor_bytes +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keccakf1600_xor_bytes +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = mld_keccakf1600x4_xor_bytes + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mlkem/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mlkem/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_xor_bytes/keccakf1600x4_xor_bytes_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_xor_bytes/keccakf1600x4_xor_bytes_harness.c new file mode 100644 index 0000000000..e6e88a4909 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/keccakf1600x4_xor_bytes/keccakf1600x4_xor_bytes_harness.c @@ -0,0 +1,16 @@ +// Copyright (c) The mldsa-native project authors +// Copyright (c) The mlkem-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 + +#include + +void harness(void) +{ + uint64_t *state; + const unsigned char *data0, *data1, *data2, *data3; + unsigned offset; + unsigned length; + mld_keccakf1600x4_xor_bytes(state, data0, data1, data2, data3, offset, + length); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/lib/__init__.py b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/lib/__init__.py new file mode 100644 index 0000000000..5f6b1e7764 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/lib/__init__.py @@ -0,0 +1 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/lib/print_tool_versions.py b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/lib/print_tool_versions.py new file mode 100755 index 0000000000..2fa4d0b7bc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/lib/print_tool_versions.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +# +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 + + +import logging +import pathlib +import shutil +import subprocess + + +_TOOLS = [ + "cadical", + "cbmc", + "cbmc-viewer", + "litani", +] + + +def _format_versions(table): + lines = [ + "", + '', + ] + for tool, version in table.items(): + if version: + v_str = f'
{version}
' + else: + v_str = "not found" + lines.append( + f'' + f"" + ) + lines.append("
Tool Versions
{tool}:{v_str}
") + return "\n".join(lines) + + +def _get_tool_versions(): + ret = {} + for tool in _TOOLS: + err = f"Could not determine version of {tool}: " + ret[tool] = None + if not shutil.which(tool): + logging.error("%s'%s' not found on $PATH", err, tool) + continue + cmd = [tool, "--version"] + proc = subprocess.Popen(cmd, text=True, stdout=subprocess.PIPE) + try: + out, _ = proc.communicate(timeout=10) + except subprocess.TimeoutExpired: + logging.error("%s'%s --version' timed out", err, tool) + continue + if proc.returncode: + logging.error( + "%s'%s --version' returned %s", err, tool, str(proc.returncode) + ) + continue + ret[tool] = out.strip() + return ret + + +def main(): + exe_name = pathlib.Path(__file__).name + logging.basicConfig(format=f"{exe_name}: %(message)s") + + table = _get_tool_versions() + out = _format_versions(table) + print(out) + + +if __name__ == "__main__": + main() diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/lib/summarize.py b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/lib/summarize.py new file mode 100644 index 0000000000..685cd7e764 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/lib/summarize.py @@ -0,0 +1,221 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 + +import argparse +import json +import logging +import os +import sys + + +DESCRIPTION = """Print 2 tables in GitHub-flavored Markdown that summarize +an execution of CBMC proofs.""" + + +def get_args(): + """Parse arguments for summarize script.""" + parser = argparse.ArgumentParser(description=DESCRIPTION) + for arg in [ + { + "flags": ["--run-file"], + "help": "path to the Litani run.json file", + "required": True, + }, + { + "flags": ["--output-result-json"], + "help": "path to export result JSON", + "required": False, + }, + ]: + flags = arg.pop("flags") + parser.add_argument(*flags, **arg) + return parser.parse_args() + + +def _get_max_length_per_column_list(data): + ret = [len(item) + 1 for item in data[0]] + for row in data[1:]: + for idx, item in enumerate(row): + ret[idx] = max(ret[idx], len(item) + 1) + return ret + + +def _get_table_header_separator(max_length_per_column_list): + line_sep = "" + for max_length_of_word_in_col in max_length_per_column_list: + line_sep += "|" + "-" * (max_length_of_word_in_col + 1) + line_sep += "|\n" + return line_sep + + +def _get_entries(max_length_per_column_list, row_data): + entries = [] + for row in row_data: + entry = "" + for idx, word in enumerate(row): + max_length_of_word_in_col = max_length_per_column_list[idx] + space_formatted_word = (max_length_of_word_in_col - len(word)) * " " + entry += "| " + word + space_formatted_word + entry += "|\n" + entries.append(entry) + return entries + + +def _get_rendered_table(data): + table = [] + max_length_per_column_list = _get_max_length_per_column_list(data) + entries = _get_entries(max_length_per_column_list, data) + for idx, entry in enumerate(entries): + if idx == 1: + line_sep = _get_table_header_separator(max_length_per_column_list) + table.append(line_sep) + table.append(entry) + table.append("\n") + return "".join(table) + + +def _parse_proof_pipeline(proof_pipeline): + """Parse a single proof pipeline, returning (name, status, duration, has_timeout).""" + duration = 0 + has_timeout = False + for stage in proof_pipeline["ci_stages"]: + for job in stage["jobs"]: + if job.get("timeout_reached", False): + has_timeout = True + if "duration" in job: + duration += int(job["duration"]) + + status = "Timeout" if has_timeout else proof_pipeline["status"].title() + return proof_pipeline["name"], status, duration, has_timeout + + +def _get_status_and_proof_summaries(run_dict): + """Parse a dict representing a Litani run and create lists summarizing the + proof results. + + Parameters + ---------- + run_dict + A dictionary representing a Litani run. + + + Returns + ------- + A list of 2 lists. + The first sub-list maps a status to the number of proofs with that status. + The second sub-list maps each proof to its status. + """ + count_statuses = {} + proofs = [["Proof", "Status", "Duration (in s)"]] + for proof_pipeline in run_dict["pipelines"]: + if proof_pipeline["name"] == "print_tool_versions": + continue + + name, status, duration, has_timeout = _parse_proof_pipeline(proof_pipeline) + status_pretty = status.replace("_", " ") + duration_str = "TIMEOUT" if has_timeout else str(duration) + + count_statuses[status_pretty] = count_statuses.get(status_pretty, 0) + 1 + proofs.append([name, status_pretty, duration_str]) + + statuses = [["Status", "Count"]] + for status, count in count_statuses.items(): + statuses.append([status, str(count)]) + return [statuses, proofs] + + +def export_result_json(output_path, run_file): + """Export JSON with summary, failures, and runtimes.""" + if output_path is None: + return + + with open(run_file, encoding="utf-8") as f: + run_dict = json.load(f) + + _, proof_table = _get_status_and_proof_summaries(run_dict) + # proof_table: [["Proof", "Status", "Duration (in s)"], [name, status, duration], ...] + + failures, runtimes = [], [] + for name, status, duration_str in proof_table[1:]: # skip header + is_timeout = duration_str == "TIMEOUT" + is_success = status == "Success" + + if not is_success: + failures.append({"name": name, "status": status, "duration": duration_str}) + + runtime = {"name": name, "unit": "seconds"} + if is_success: + runtime["value"] = int(duration_str) + else: + runtime["status"] = "failed" + runtimes.append(runtime) + + total = len(runtimes) + failed = sum(1 for f in failures if f["status"] != "Timeout") + timeout = sum(1 for f in failures if f["status"] == "Timeout") + + result = { + "mldsa_parameter_set": os.getenv("MLD_CONFIG_PARAMETER_SET", "unknown"), + "summary": { + "total": total, + "success": total - failed - timeout, + "failed": failed, + "timeout": timeout, + }, + "failures": failures, + "runtimes": runtimes, + } + + with open(output_path, "w", encoding="utf-8") as f: + json.dump(result, f, indent=2) + + +def print_proof_results(out_file): + """ + Print 2 strings that summarize the proof results. + When printing, each string will render as a GitHub flavored Markdown table. + """ + output = "## Summary of CBMC proof results\n\n" + with open(out_file, encoding="utf-8") as run_json: + run_dict = json.load(run_json) + status_table, proof_table = _get_status_and_proof_summaries(run_dict) + for summary in (status_table, proof_table): + output += _get_rendered_table(summary) + + print(output) + sys.stdout.flush() + + github_summary_file = os.getenv("GITHUB_STEP_SUMMARY") + if github_summary_file: + with open(github_summary_file, "a") as handle: + print(output, file=handle) + handle.flush() + else: + logging.warning("$GITHUB_STEP_SUMMARY not set, not writing summary file") + + msg = ( + "Click the 'Summary' button to view a Markdown table " + "summarizing all proof results" + ) + + # Check for timeouts by examining status table + has_timeout = any(row[0] == "Timeout" for row in status_table[1:]) + has_failure = run_dict["status"] != "success" + + if has_timeout or has_failure: + logging.error("Not all proofs passed.") + if has_timeout: + logging.error("Some proofs timed out.") + logging.error(msg) + sys.exit(1) + logging.info(msg) + + +if __name__ == "__main__": + args = get_args() + logging.basicConfig(format="%(levelname)s: %(message)s") + try: + export_result_json(args.output_result_json, args.run_file) + print_proof_results(args.run_file) + except Exception as ex: # pylint: disable=broad-except + logging.critical("Could not print results. Exception: %s", str(ex)) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/lib/z3_no_bv_extract b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/lib/z3_no_bv_extract new file mode 100755 index 0000000000..6affe9ec55 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/lib/z3_no_bv_extract @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# Disable re-writing of bit-vector expressions within quantifiers. +# Such re-writing can cause quantifier e-matching to fail in complex cases. +z3 rewriter.bv_le2extract=false "$@" diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/lib/z3_smt_only b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/lib/z3_smt_only new file mode 100755 index 0000000000..9a0fd2ecee --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/lib/z3_smt_only @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Copyright (c) The mldsa-native project authors +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# Disable initial simplify tactic and go straight to main SMT tactic +# This can prevent divergence of Z3 on different platforms +z3 tactic.default_tactic=smt "$@" diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/list_proofs.sh b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/list_proofs.sh new file mode 100755 index 0000000000..f6abd04e77 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/list_proofs.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +# +# This tiny script just lists the proof directories in proof/cbmc, +# which are those containing a *harness.c file. + +ROOT=$(git rev-parse --show-toplevel) +cd $ROOT +ls -1 proofs/cbmc/**/*harness.c | cut -d '/' -f 3 diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/make_hint/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/make_hint/Makefile new file mode 100644 index 0000000000..3b5f8ed041 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/make_hint/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = make_hint_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = make_hint + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_make_hint +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = make_hint + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/make_hint/make_hint_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/make_hint/make_hint_harness.c new file mode 100644 index 0000000000..dcbc6a62e3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/make_hint/make_hint_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "rounding.h" + +void harness(void) +{ + int32_t a, b; + unsigned int r; + r = mld_make_hint(a, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/montgomery_reduce/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/montgomery_reduce/Makefile new file mode 100644 index 0000000000..10a38d216d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/montgomery_reduce/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = montgomery_reduce_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = montgomery_reduce + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_montgomery_reduce +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = montgomery_reduce + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/montgomery_reduce/montgomery_reduce_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/montgomery_reduce/montgomery_reduce_harness.c new file mode 100644 index 0000000000..6f90bdc200 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/montgomery_reduce/montgomery_reduce_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "reduce.h" + +void harness(void) +{ + int64_t a; + int32_t r; + r = mld_montgomery_reduce(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_butterfly_block/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_butterfly_block/Makefile new file mode 100644 index 0000000000..ae4b238e98 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_butterfly_block/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = ntt_butterfly_block_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_ntt_butterfly_block + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_ntt_butterfly_block +USE_FUNCTION_CONTRACTS=mld_fqmul +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = mld_ntt_butterfly_block + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_butterfly_block/ntt_butterfly_block_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_butterfly_block/ntt_butterfly_block_harness.c new file mode 100644 index 0000000000..fb4ffa2bb1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_butterfly_block/ntt_butterfly_block_harness.c @@ -0,0 +1,16 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include +#include "params.h" + +void mld_ntt_butterfly_block(int32_t r[MLDSA_N], int32_t zeta, unsigned start, + unsigned len, unsigned bound); + +void harness(void) +{ + int32_t *r, zeta; + unsigned start, len; + unsigned bound; + mld_ntt_butterfly_block(r, zeta, start, len, bound); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_layer/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_layer/Makefile new file mode 100644 index 0000000000..e2c8a08166 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_layer/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = ntt_layer_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_ntt_layer + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_ntt_layer +USE_FUNCTION_CONTRACTS=mld_ntt_butterfly_block +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = mld_ntt_layer + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_layer/ntt_layer_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_layer/ntt_layer_harness.c new file mode 100644 index 0000000000..e07f526f0f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_layer/ntt_layer_harness.c @@ -0,0 +1,14 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include +#include "params.h" + +void mld_ntt_layer(int32_t r[MLDSA_N], unsigned layer); + +void harness(void) +{ + int32_t *r; + unsigned layer; + mld_ntt_layer(r, layer); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_native_x86_64/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_native_x86_64/Makefile new file mode 100644 index 0000000000..639efc8abf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_native_x86_64/Makefile @@ -0,0 +1,57 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = ntt_native_x86_64_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = ntt_native_x86_64 + +# We need to set MLD_CHECK_APIS as otherwise mldsa/src/native/api.h won't be +# included, which contains the CBMC specifications. +DEFINES += -DMLD_CONFIG_USE_NATIVE_BACKEND_ARITH -DMLD_CONFIG_ARITH_BACKEND_FILE="\"$(SRCDIR)/mldsa/src/native/x86_64/meta.h\"" -DMLD_CHECK_APIS +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c $(SRCDIR)/mldsa/src/native/x86_64/src/consts.c + +CHECK_FUNCTION_CONTRACTS=mld_ntt_native +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)ntt_avx2 mld_sys_check_capability +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = ntt_native_x86_64 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_native_x86_64/ntt_native_x86_64_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_native_x86_64/ntt_native_x86_64_harness.c new file mode 100644 index 0000000000..a985c3492d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/ntt_native_x86_64/ntt_native_x86_64_harness.c @@ -0,0 +1,16 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include +#include "cbmc.h" +#include "params.h" + + +int mld_ntt_native(int32_t data[MLDSA_N]); + +void harness(void) +{ + int32_t *r; + int t; + t = mld_ntt_native(r); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_pk/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_pk/Makefile new file mode 100644 index 0000000000..4907cd63f7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_pk/Makefile @@ -0,0 +1,54 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = pack_pk_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = pack_pk + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/packing.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)pack_pk +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyt1_pack +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 --no-array-field-sensitivity --slice-formula + +FUNCTION_NAME = pack_pk + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 11 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_pk/pack_pk_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_pk/pack_pk_harness.c new file mode 100644 index 0000000000..695a1884dc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_pk/pack_pk_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "packing.h" + + +void harness(void) +{ + uint8_t *a, *b; + mld_polyveck *c; + mld_pack_pk(a, b, c); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sig_c_h/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sig_c_h/Makefile new file mode 100644 index 0000000000..0c0a7e762a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sig_c_h/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = pack_sig_c_h_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = pack_sig_c_h + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/packing.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)pack_sig_c_h +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS+=--slice-formula + +FUNCTION_NAME = pack_sig_c_h + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sig_c_h/pack_sig_c_h_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sig_c_h/pack_sig_c_h_harness.c new file mode 100644 index 0000000000..fa7df3565b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sig_c_h/pack_sig_c_h_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "packing.h" + + +void harness(void) +{ + uint8_t *a, *b; + mld_polyveck *h; + unsigned int nh; + mld_pack_sig_c_h(a, b, h, nh); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sig_z/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sig_z/Makefile new file mode 100644 index 0000000000..5e28666157 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sig_z/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = pack_sig_z_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = pack_sig_z + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/packing.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)pack_sig_z +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyz_pack +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS+=--slice-formula + +FUNCTION_NAME = pack_sig_z + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sig_z/pack_sig_z_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sig_z/pack_sig_z_harness.c new file mode 100644 index 0000000000..585b5811dc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sig_z/pack_sig_z_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "packing.h" + + +void harness(void) +{ + uint8_t *a; + mld_poly *zi; + unsigned i; + mld_pack_sig_z(a, zi, i); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sk/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sk/Makefile new file mode 100644 index 0000000000..ab189f3352 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sk/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = pack_sk_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = pack_sk + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/packing.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)pack_sk +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvecl_pack_eta $(MLD_NAMESPACE)polyveck_pack_eta $(MLD_NAMESPACE)polyveck_pack_t0 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = pack_sk + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sk/pack_sk_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sk/pack_sk_harness.c new file mode 100644 index 0000000000..99558ee168 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/pack_sk/pack_sk_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "packing.h" + + +void harness(void) +{ + uint8_t *a, *b, *c, *d; + mld_polyveck *t0, *s2; + mld_polyvecl *s1; + mld_pack_sk(a, b, c, d, t0, s1, s2); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_add/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_add/Makefile new file mode 100644 index 0000000000..257ab90eac --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_add/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_add_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_add + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_add +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 --arrays-uf-always --slice-formula + +FUNCTION_NAME = poly_add + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_add/poly_add_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_add/poly_add_harness.c new file mode 100644 index 0000000000..d2be6c4ba4 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_add/poly_add_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +void harness(void) +{ + mld_poly *r, *b; + mld_poly_add(r, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq/Makefile new file mode 100644 index 0000000000..4639df9410 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE =poly_caddq_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_caddq + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_caddq +USE_FUNCTION_CONTRACTS=mld_poly_caddq_c +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_caddq + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq/poly_caddq_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq/poly_caddq_harness.c new file mode 100644 index 0000000000..93de3b5b5a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq/poly_caddq_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + + +void harness(void) +{ + mld_poly *a; + mld_poly_caddq(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq_c/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq_c/Makefile new file mode 100644 index 0000000000..04868ff84e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq_c/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE =poly_caddq_c_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_caddq_c + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_poly_caddq_c +USE_FUNCTION_CONTRACTS=mld_caddq +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_poly_caddq_c + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq_c/poly_caddq_c_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq_c/poly_caddq_c_harness.c new file mode 100644 index 0000000000..be1fa8fab9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq_c/poly_caddq_c_harness.c @@ -0,0 +1,14 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + + +// Prototype for the function under test +void mld_poly_caddq_c(mld_poly *p); + +void harness(void) +{ + mld_poly *a; + mld_poly_caddq_c(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq_native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq_native/Makefile new file mode 100644 index 0000000000..94fc09e8b1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq_native/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE =poly_caddq_native_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_caddq_native + +DEFINES += -DMLD_CONFIG_USE_NATIVE_BACKEND_ARITH -DMLD_CONFIG_ARITH_BACKEND_FILE="\"dummy_backend.h\"" +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_caddq +USE_FUNCTION_CONTRACTS=mld_poly_caddq_native mld_poly_caddq_c +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_caddq_native + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq_native/poly_caddq_native_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq_native/poly_caddq_native_harness.c new file mode 100644 index 0000000000..93de3b5b5a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_caddq_native/poly_caddq_native_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + + +void harness(void) +{ + mld_poly *a; + mld_poly_caddq(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_challenge/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_challenge/Makefile new file mode 100644 index 0000000000..6842994ba8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_challenge/Makefile @@ -0,0 +1,57 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE =poly_challenge_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_challenge + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_challenge +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake256_init $(MLD_NAMESPACE)shake256_absorb $(MLD_NAMESPACE)shake256_finalize $(MLD_NAMESPACE)shake256_squeeze $(MLD_NAMESPACE)shake256_release +USE_FUNCTION_CONTRACTS+=mld_zeroize +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = poly_challenge + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 10 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_challenge/poly_challenge_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_challenge/poly_challenge_harness.c new file mode 100644 index 0000000000..2f62241945 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_challenge/poly_challenge_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + + +void harness(void) +{ + mld_poly *c; + uint8_t *seed; + mld_poly_challenge(c, seed); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm/Makefile new file mode 100644 index 0000000000..e83362cd3b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE =poly_chknorm_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_chknorm + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_chknorm +USE_FUNCTION_CONTRACTS=mld_poly_chknorm_c +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_chknorm + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm/poly_chknorm_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm/poly_chknorm_harness.c new file mode 100644 index 0000000000..8908861542 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm/poly_chknorm_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + + +void harness(void) +{ + mld_poly *a; + uint32_t r; + int32_t B; + r = mld_poly_chknorm(a, B); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm_c/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm_c/Makefile new file mode 100644 index 0000000000..cd9ded7d81 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm_c/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE =poly_chknorm_c_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_chknorm_c + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_poly_chknorm_c +USE_FUNCTION_CONTRACTS=mld_ct_abs_i32 mld_ct_cmask_neg_i32 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_poly_chknorm_c + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm_c/poly_chknorm_c_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm_c/poly_chknorm_c_harness.c new file mode 100644 index 0000000000..65d6e48d84 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm_c/poly_chknorm_c_harness.c @@ -0,0 +1,15 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + +// Prototype for the function under test +uint32_t mld_poly_chknorm_c(mld_poly *a, int32_t B); + +void harness(void) +{ + mld_poly *a; + uint32_t r; + int32_t B; + r = mld_poly_chknorm_c(a, B); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm_native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm_native/Makefile new file mode 100644 index 0000000000..6643b2158e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm_native/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE =poly_chknorm_native_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_chknorm_native + +DEFINES += -DMLD_CONFIG_USE_NATIVE_BACKEND_ARITH -DMLD_CONFIG_ARITH_BACKEND_FILE="\"dummy_backend.h\"" +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_chknorm +USE_FUNCTION_CONTRACTS=mld_poly_chknorm_native mld_poly_chknorm_c +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_chknorm_native + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm_native/poly_chknorm_native_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm_native/poly_chknorm_native_harness.c new file mode 100644 index 0000000000..8908861542 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_chknorm_native/poly_chknorm_native_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + + +void harness(void) +{ + mld_poly *a; + uint32_t r; + int32_t B; + r = mld_poly_chknorm(a, B); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose/Makefile new file mode 100644 index 0000000000..ce20f3b4ba --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_decompose_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_decompose + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_decompose +USE_FUNCTION_CONTRACTS= mld_poly_decompose_c +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_decompose + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose/poly_decompose_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose/poly_decompose_harness.c new file mode 100644 index 0000000000..bd08c2090c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose/poly_decompose_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + + +void harness(void) +{ + mld_poly *a0, *a1; + mld_poly_decompose(a1, a0); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose_c/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose_c/Makefile new file mode 100644 index 0000000000..1c4a3c31e9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose_c/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_decompose_c_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_decompose_c + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=mld_poly_decompose_c +USE_FUNCTION_CONTRACTS=mld_decompose +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_poly_decompose_c + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose_c/poly_decompose_c_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose_c/poly_decompose_c_harness.c new file mode 100644 index 0000000000..d5f71205e2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose_c/poly_decompose_c_harness.c @@ -0,0 +1,14 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + +// Prototype for the function under test +#define mld_poly_decompose_c MLD_ADD_PARAM_SET(mld_poly_decompose_c) +void mld_poly_decompose_c(mld_poly *a1, mld_poly *a0); + +void harness(void) +{ + mld_poly *a0, *a1; + mld_poly_decompose_c(a1, a0); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose_native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose_native/Makefile new file mode 100644 index 0000000000..1f084308ed --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose_native/Makefile @@ -0,0 +1,62 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_decompose_native_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_decompose_native + +DEFINES += -DMLD_CONFIG_USE_NATIVE_BACKEND_ARITH -DMLD_CONFIG_ARITH_BACKEND_FILE="\"dummy_backend.h\"" +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_decompose +USE_FUNCTION_CONTRACTS= mld_poly_decompose_c +ifeq ($(MLD_CONFIG_PARAMETER_SET),44) + USE_FUNCTION_CONTRACTS+=mld_poly_decompose_88_native +else ifeq ($(MLD_CONFIG_PARAMETER_SET),65) + USE_FUNCTION_CONTRACTS+=mld_poly_decompose_32_native +else ifeq ($(MLD_CONFIG_PARAMETER_SET),87) + USE_FUNCTION_CONTRACTS+=mld_poly_decompose_32_native +endif +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_decompose_native + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose_native/poly_decompose_native_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose_native/poly_decompose_native_harness.c new file mode 100644 index 0000000000..bd08c2090c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_decompose_native/poly_decompose_native_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + + +void harness(void) +{ + mld_poly *a0, *a1; + mld_poly_decompose(a1, a0); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont/Makefile new file mode 100644 index 0000000000..6b1f356fc2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_invntt_tomont_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_invntt_tomont + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_invntt_tomont +USE_FUNCTION_CONTRACTS=mld_poly_invntt_tomont_c +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_invntt_tomont + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont/poly_invntt_tomont_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont/poly_invntt_tomont_harness.c new file mode 100644 index 0000000000..bf72785f40 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont/poly_invntt_tomont_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include +#include "params.h" +#include "poly.h" + +void harness(void) +{ + mld_poly *a; + mld_poly_invntt_tomont(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont_c/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont_c/Makefile new file mode 100644 index 0000000000..ac0757f1f3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont_c/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_invntt_tomont_c_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_invntt_tomont_c + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_poly_invntt_tomont_c +USE_FUNCTION_CONTRACTS=mld_invntt_layer +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_poly_invntt_tomont_c + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont_c/poly_invntt_tomont_c_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont_c/poly_invntt_tomont_c_harness.c new file mode 100644 index 0000000000..5c723c514b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont_c/poly_invntt_tomont_c_harness.c @@ -0,0 +1,16 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include +#include "params.h" +#include "poly.h" + +// Prototype for the function under test +void mld_poly_invntt_tomont_c(mld_poly *p); + + +void harness(void) +{ + mld_poly *a; + mld_poly_invntt_tomont_c(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont_native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont_native/Makefile new file mode 100644 index 0000000000..fa1a0b6238 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont_native/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_invntt_tomont_native_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_invntt_tomont_native + +DEFINES += -DMLD_CONFIG_USE_NATIVE_BACKEND_ARITH -DMLD_CONFIG_ARITH_BACKEND_FILE="\"dummy_backend.h\"" +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_invntt_tomont +USE_FUNCTION_CONTRACTS=mld_intt_native mld_poly_invntt_tomont_c +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_invntt_tomont_native + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont_native/poly_invntt_tomont_native_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont_native/poly_invntt_tomont_native_harness.c new file mode 100644 index 0000000000..27fc2b9d6f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_invntt_tomont_native/poly_invntt_tomont_native_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +void harness(void) +{ + mld_poly *a; + mld_poly_invntt_tomont(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_make_hint/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_make_hint/Makefile new file mode 100644 index 0000000000..01b1f3215c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_make_hint/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_make_hint_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_make_hint + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_make_hint +USE_FUNCTION_CONTRACTS=mld_make_hint +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_make_hint + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_make_hint/poly_make_hint_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_make_hint/poly_make_hint_harness.c new file mode 100644 index 0000000000..fc03487dc9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_make_hint/poly_make_hint_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + +void harness(void) +{ + mld_poly *a, *b, *c; + unsigned int r; + r = mld_poly_make_hint(a, b, c); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt/Makefile new file mode 100644 index 0000000000..d648576573 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_ntt_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_ntt + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_ntt +USE_FUNCTION_CONTRACTS=mld_poly_ntt_c +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_ntt + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt/poly_ntt_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt/poly_ntt_harness.c new file mode 100644 index 0000000000..a1720228fb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt/poly_ntt_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +void harness(void) +{ + mld_poly *a; + mld_poly_ntt(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt_c/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt_c/Makefile new file mode 100644 index 0000000000..6139dee9cf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt_c/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_ntt_c_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_ntt_c + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_poly_ntt_c +USE_FUNCTION_CONTRACTS=mld_ntt_layer +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_poly_ntt_c + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt_c/poly_ntt_c_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt_c/poly_ntt_c_harness.c new file mode 100644 index 0000000000..e5e1a3c233 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt_c/poly_ntt_c_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +// Prototype for the function under test +void mld_poly_ntt_c(mld_poly *p); + +void harness(void) +{ + mld_poly *a; + mld_poly_ntt_c(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt_native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt_native/Makefile new file mode 100644 index 0000000000..80d47f0499 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt_native/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_ntt_native_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_ntt_native + +DEFINES += -DMLD_CONFIG_USE_NATIVE_BACKEND_ARITH -DMLD_CONFIG_ARITH_BACKEND_FILE="\"dummy_backend.h\"" +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_ntt +USE_FUNCTION_CONTRACTS=mld_ntt_native mld_poly_ntt_c +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_ntt + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt_native/poly_ntt_native_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt_native/poly_ntt_native_harness.c new file mode 100644 index 0000000000..a1720228fb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_ntt_native/poly_ntt_native_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +void harness(void) +{ + mld_poly *a; + mld_poly_ntt(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery/Makefile new file mode 100644 index 0000000000..260e07bd4e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_pointwise_montgomery_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_pointwise_montgomery + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_pointwise_montgomery +USE_FUNCTION_CONTRACTS=mld_poly_pointwise_montgomery_c +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_pointwise_montgomery + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 10 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery/poly_pointwise_montgomery_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery/poly_pointwise_montgomery_harness.c new file mode 100644 index 0000000000..d885c2d5de --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery/poly_pointwise_montgomery_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +void harness(void) +{ + mld_poly *a, *b, *c; + mld_poly_pointwise_montgomery(c, a, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery_c/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery_c/Makefile new file mode 100644 index 0000000000..587b45915b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery_c/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_pointwise_montgomery_c_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_pointwise_montgomery_c + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_poly_pointwise_montgomery_c +USE_FUNCTION_CONTRACTS=mld_montgomery_reduce +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_poly_pointwise_montgomery_c + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 10 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery_c/poly_pointwise_montgomery_c_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery_c/poly_pointwise_montgomery_c_harness.c new file mode 100644 index 0000000000..4ff441fb6e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery_c/poly_pointwise_montgomery_c_harness.c @@ -0,0 +1,14 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +// Prototype for the function under test +void mld_poly_pointwise_montgomery_c(mld_poly *c, mld_poly *a, mld_poly *b); + + +void harness(void) +{ + mld_poly *a, *b, *c; + mld_poly_pointwise_montgomery_c(c, a, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery_native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery_native/Makefile new file mode 100644 index 0000000000..9e82db17c3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery_native/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_pointwise_montgomery_native_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_pointwise_montgomery_native + +DEFINES += -DMLD_CONFIG_USE_NATIVE_BACKEND_ARITH -DMLD_CONFIG_ARITH_BACKEND_FILE="\"dummy_backend.h\"" +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_pointwise_montgomery +USE_FUNCTION_CONTRACTS=mld_poly_pointwise_montgomery_native mld_poly_pointwise_montgomery_c +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_pointwise_montgomery_native + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 10 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery_native/poly_pointwise_montgomery_native_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery_native/poly_pointwise_montgomery_native_harness.c new file mode 100644 index 0000000000..d885c2d5de --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_pointwise_montgomery_native/poly_pointwise_montgomery_native_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +void harness(void) +{ + mld_poly *a, *b, *c; + mld_poly_pointwise_montgomery(c, a, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_power2round/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_power2round/Makefile new file mode 100644 index 0000000000..43caab126e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_power2round/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE =poly_power2round_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_power2round + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_power2round +USE_FUNCTION_CONTRACTS=mld_power2round +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_power2round + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_power2round/poly_power2round_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_power2round/poly_power2round_harness.c new file mode 100644 index 0000000000..fa1bbe0f18 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_power2round/poly_power2round_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + + +void harness(void) +{ + mld_poly *a, *a0, *a1; + mld_poly_power2round(a0, a1, a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_reduce/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_reduce/Makefile new file mode 100644 index 0000000000..cd37a40e92 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_reduce/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_reduce_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_reduce + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_reduce +USE_FUNCTION_CONTRACTS=mld_reduce32 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_reduce + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_reduce/poly_reduce_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_reduce/poly_reduce_harness.c new file mode 100644 index 0000000000..a0c0980844 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_reduce/poly_reduce_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +void harness(void) +{ + mld_poly *a; + mld_poly_reduce(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_shiftl/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_shiftl/Makefile new file mode 100644 index 0000000000..9dd4cc4bdd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_shiftl/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_shiftl_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_shiftl + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_shiftl +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_shiftl + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_shiftl/poly_shiftl_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_shiftl/poly_shiftl_harness.c new file mode 100644 index 0000000000..d6c4c6b3a4 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_shiftl/poly_shiftl_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +void harness(void) +{ + mld_poly *a; + mld_poly_shiftl(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_sub/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_sub/Makefile new file mode 100644 index 0000000000..e4ded7b2b0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_sub/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_sub_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_sub + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_sub +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_sub + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_sub/poly_sub_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_sub/poly_sub_harness.c new file mode 100644 index 0000000000..1b7a2bf3b3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_sub/poly_sub_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +void harness(void) +{ + mld_poly *r, *b; + mld_poly_sub(r, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform/Makefile new file mode 100644 index 0000000000..12fa0ac90a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform/Makefile @@ -0,0 +1,57 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_uniform_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_uniform + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c $(SRCDIR)/mldsa/src/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_uniform +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake128_init $(MLD_NAMESPACE)shake128_absorb $(MLD_NAMESPACE)shake128_finalize $(MLD_NAMESPACE)shake128_squeeze $(MLD_NAMESPACE)shake128_release mld_rej_uniform +USE_FUNCTION_CONTRACTS+=mld_zeroize +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = poly_uniform + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform/poly_uniform_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform/poly_uniform_harness.c new file mode 100644 index 0000000000..68e3ed904f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform/poly_uniform_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" +#include "poly.h" + +void harness(void) +{ + mld_poly *a; + const uint8_t *seed; + + mld_poly_uniform(a, seed); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_4x/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_4x/Makefile new file mode 100644 index 0000000000..486d2bd054 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_4x/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_uniform_4x_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_uniform_4x + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c $(SRCDIR)/mldsa/src/fips202/fips202x4.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_uniform_4x +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake128x4_absorb_once $(MLD_NAMESPACE)shake128x4_squeezeblocks mld_rej_uniform +USE_FUNCTION_CONTRACTS+=mld_zeroize +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_uniform_4x + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_4x/poly_uniform_4x_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_4x/poly_uniform_4x_harness.c new file mode 100644 index 0000000000..72bd678f01 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_4x/poly_uniform_4x_harness.c @@ -0,0 +1,15 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +void harness(void) +{ + mld_poly *r0; + mld_poly *r1; + mld_poly *r2; + mld_poly *r3; + uint8_t(*seed)[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]; + + mld_poly_uniform_4x(r0, r1, r2, r3, seed); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_eta/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_eta/Makefile new file mode 100644 index 0000000000..5b02736fdb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_eta/Makefile @@ -0,0 +1,61 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_uniform_eta_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_uniform_eta + +DEFINES += -DMLD_CONFIG_SERIAL_FIPS202_ONLY +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_uniform_eta +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake256_init +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)shake256_absorb +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)shake256_finalize +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)shake256_squeeze +USE_FUNCTION_CONTRACTS+=mld_rej_eta +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)shake256_release +USE_FUNCTION_CONTRACTS+=mld_zeroize +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_uniform_eta + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_eta/poly_uniform_eta_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_eta/poly_uniform_eta_harness.c new file mode 100644 index 0000000000..f22f228910 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_eta/poly_uniform_eta_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + +void harness(void) +{ + mld_poly *r0; + const uint8_t *seed; + uint8_t n0; + + mld_poly_uniform_eta(r0, seed, n0); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_eta_4x/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_eta_4x/Makefile new file mode 100644 index 0000000000..0c2d142030 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_eta_4x/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_uniform_eta_4x_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_uniform_eta_4x + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c $(SRCDIR)/mldsa/src/fips202/fips202x4.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_uniform_eta_4x +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake256x4_absorb_once $(MLD_NAMESPACE)shake256x4_squeezeblocks mld_rej_eta +USE_FUNCTION_CONTRACTS+=mld_zeroize +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_uniform_eta_4x + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_eta_4x/poly_uniform_eta_4x_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_eta_4x/poly_uniform_eta_4x_harness.c new file mode 100644 index 0000000000..0b847a85d2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_eta_4x/poly_uniform_eta_4x_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + +void harness(void) +{ + mld_poly *r0, *r1, *r2, *r3; + const uint8_t *seed; + uint8_t n0, n1, n2, n3; + + mld_poly_uniform_eta_4x(r0, r1, r2, r3, seed, n0, n1, n2, n3); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_gamma1/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_gamma1/Makefile new file mode 100644 index 0000000000..f515a1065b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_gamma1/Makefile @@ -0,0 +1,61 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_uniform_gamma1_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_uniform_gamma1 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c $(SRCDIR)/mldsa/src/fips202/fips202.c + +# Only relevant for ML-DSA-65 +ifeq ($(MLD_CONFIG_PARAMETER_SET),65) +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_uniform_gamma1 +else +CHECK_FUNCTION_CONTRACTS= +endif +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake256_init $(MLD_NAMESPACE)shake256_absorb $(MLD_NAMESPACE)shake256_finalize $(MLD_NAMESPACE)shake256_squeeze $(MLD_NAMESPACE)shake256_release $(MLD_NAMESPACE)polyz_unpack +USE_FUNCTION_CONTRACTS+=mld_zeroize +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_uniform_gamma1 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_gamma1/poly_uniform_gamma1_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_gamma1/poly_uniform_gamma1_harness.c new file mode 100644 index 0000000000..c7696a879e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_gamma1/poly_uniform_gamma1_harness.c @@ -0,0 +1,16 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + +void harness(void) +{ +/* mld_poly_uniform_gamma1 is only defined for ML-DSA-65 */ +#if MLD_CONFIG_PARAMETER_SET == 65 + mld_poly *a; + const uint8_t *seed; + uint16_t nonce; + + mld_poly_uniform_gamma1(a, seed, nonce); +#endif /* MLD_CONFIG_PARAMETER_SET == 65 */ +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_gamma1_4x/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_gamma1_4x/Makefile new file mode 100644 index 0000000000..bb30d16e3a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_gamma1_4x/Makefile @@ -0,0 +1,57 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_uniform_gamma1_4x_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_uniform_gamma1_4x + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c $(SRCDIR)/mldsa/src/fips202/fips202x4.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_uniform_gamma1_4x +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake256x4_absorb_once $(MLD_NAMESPACE)shake256x4_squeezeblocks $(MLD_NAMESPACE)polyz_unpack +USE_FUNCTION_CONTRACTS+=mld_zeroize +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = poly_uniform_gamma1_4x + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_gamma1_4x/poly_uniform_gamma1_4x_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_gamma1_4x/poly_uniform_gamma1_4x_harness.c new file mode 100644 index 0000000000..ed9e7070a3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_uniform_gamma1_4x/poly_uniform_gamma1_4x_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + +void harness(void) +{ + mld_poly *r0, *r1, *r2, *r3; + const uint8_t *seed; + uint16_t n0, n1, n2, n3; + + mld_poly_uniform_gamma1_4x(r0, r1, r2, r3, seed, n0, n1, n2, n3); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint/Makefile new file mode 100644 index 0000000000..d15774086f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_use_hint_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_use_hint + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_use_hint +USE_FUNCTION_CONTRACTS=mld_poly_use_hint_c +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_use_hint + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint/poly_use_hint_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint/poly_use_hint_harness.c new file mode 100644 index 0000000000..360de6d3f1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint/poly_use_hint_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + + +void harness(void) +{ + mld_poly *a, *b, *h; + mld_poly_use_hint(b, a, h); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint_c/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint_c/Makefile new file mode 100644 index 0000000000..188b8e7056 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint_c/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_use_hint_c_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_use_hint_c + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=mld_poly_use_hint_c +USE_FUNCTION_CONTRACTS=mld_use_hint +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_poly_use_hint_c + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint_c/poly_use_hint_c_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint_c/poly_use_hint_c_harness.c new file mode 100644 index 0000000000..0b17ee2be7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint_c/poly_use_hint_c_harness.c @@ -0,0 +1,15 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + +// Prototype for the function under test +#define mld_poly_use_hint_c MLD_ADD_PARAM_SET(mld_poly_use_hint_c) +void mld_poly_use_hint_c(mld_poly *b, mld_poly *a, mld_poly *h); + + +void harness(void) +{ + mld_poly *a, *b, *h; + mld_poly_use_hint_c(b, a, h); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint_native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint_native/Makefile new file mode 100644 index 0000000000..800f888cdc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint_native/Makefile @@ -0,0 +1,62 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_use_hint_native_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = poly_use_hint_native + +DEFINES += -DMLD_CONFIG_USE_NATIVE_BACKEND_ARITH -DMLD_CONFIG_ARITH_BACKEND_FILE="\"dummy_backend.h\"" +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_use_hint +USE_FUNCTION_CONTRACTS=mld_poly_use_hint_c +ifeq ($(MLD_CONFIG_PARAMETER_SET),44) + USE_FUNCTION_CONTRACTS+=mld_poly_use_hint_88_native +else ifeq ($(MLD_CONFIG_PARAMETER_SET),65) + USE_FUNCTION_CONTRACTS+=mld_poly_use_hint_32_native +else ifeq ($(MLD_CONFIG_PARAMETER_SET),87) + USE_FUNCTION_CONTRACTS+=mld_poly_use_hint_32_native +endif +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = poly_use_hint_native + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint_native/poly_use_hint_native_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint_native/poly_use_hint_native_harness.c new file mode 100644 index 0000000000..360de6d3f1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/poly_use_hint_native/poly_use_hint_native_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + + +void harness(void) +{ + mld_poly *a, *b, *h; + mld_poly_use_hint(b, a, h); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyeta_pack/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyeta_pack/Makefile new file mode 100644 index 0000000000..67fe45725b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyeta_pack/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyeta_pack_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyeta_pack + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyeta_pack +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyeta_pack + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyeta_pack/polyeta_pack_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyeta_pack/polyeta_pack_harness.c new file mode 100644 index 0000000000..d2471fc4f1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyeta_pack/polyeta_pack_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + +void harness(void) +{ + mld_poly *a; + uint8_t *b; + mld_polyeta_pack(b, a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyeta_unpack/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyeta_unpack/Makefile new file mode 100644 index 0000000000..72283783d8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyeta_unpack/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyeta_unpack_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyeta_unpack + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyeta_unpack +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyeta_unpack + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyeta_unpack/polyeta_unpack_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyeta_unpack/polyeta_unpack_harness.c new file mode 100644 index 0000000000..3b05d0acf8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyeta_unpack/polyeta_unpack_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + +void harness(void) +{ + mld_poly *a; + uint8_t *b; + mld_polyeta_unpack(a, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polymat_permute_bitrev_to_custom/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polymat_permute_bitrev_to_custom/Makefile new file mode 100644 index 0000000000..690eef038d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polymat_permute_bitrev_to_custom/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polymat_permute_bitrev_to_custom_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polymat_permute_bitrev_to_custom + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=mld_polymat_permute_bitrev_to_custom +USE_FUNCTION_CONTRACTS=mld_polyvecl_permute_bitrev_to_custom +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 --slice-formula --no-array-field-sensitivity + +FUNCTION_NAME = polymat_permute_bitrev_to_custom + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 12 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polymat_permute_bitrev_to_custom/polymat_permute_bitrev_to_custom_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polymat_permute_bitrev_to_custom/polymat_permute_bitrev_to_custom_harness.c new file mode 100644 index 0000000000..a35bc954e0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polymat_permute_bitrev_to_custom/polymat_permute_bitrev_to_custom_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void mld_polymat_permute_bitrev_to_custom(mld_polymat *mat); + +void harness(void) +{ + mld_polymat *mat; + mld_polymat_permute_bitrev_to_custom(mat); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt0_pack/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt0_pack/Makefile new file mode 100644 index 0000000000..8eeaea7d7f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt0_pack/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyt0_pack_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyt0_pack + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyt0_pack +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyt0_pack + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt0_pack/polyt0_pack_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt0_pack/polyt0_pack_harness.c new file mode 100644 index 0000000000..4601a4a7e5 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt0_pack/polyt0_pack_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +void harness(void) +{ + mld_poly *a; + uint8_t *b; + mld_polyt0_pack(b, a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt0_unpack/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt0_unpack/Makefile new file mode 100644 index 0000000000..c7811ab20c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt0_unpack/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyt0_unpack_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyt0_unpack + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyt0_unpack +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyt0_unpack + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt0_unpack/polyt0_unpack_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt0_unpack/polyt0_unpack_harness.c new file mode 100644 index 0000000000..215b5a484d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt0_unpack/polyt0_unpack_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +void harness(void) +{ + mld_poly *a; + uint8_t *b; + mld_polyt0_unpack(a, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt1_pack/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt1_pack/Makefile new file mode 100644 index 0000000000..c43d57d9c9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt1_pack/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyt1_pack_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyt1_pack + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyt1_pack +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyt1_pack + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt1_pack/polyt1_pack_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt1_pack/polyt1_pack_harness.c new file mode 100644 index 0000000000..1887b82902 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt1_pack/polyt1_pack_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +void harness(void) +{ + mld_poly *a; + uint8_t *b; + mld_polyt1_pack(b, a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt1_unpack/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt1_unpack/Makefile new file mode 100644 index 0000000000..709cd9200f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt1_unpack/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyt1_unpack_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyt1_unpack + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyt1_unpack +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyt1_unpack + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt1_unpack/polyt1_unpack_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt1_unpack/polyt1_unpack_harness.c new file mode 100644 index 0000000000..05f482fd53 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyt1_unpack/polyt1_unpack_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +void harness(void) +{ + mld_poly *a; + uint8_t *b; + mld_polyt1_unpack(a, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_expand/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_expand/Makefile new file mode 100644 index 0000000000..6bfe15c41a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_expand/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyvec_matrix_expand_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyvec_matrix_expand + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvec_matrix_expand +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_uniform_4x $(MLD_NAMESPACE)poly_uniform mld_polymat_permute_bitrev_to_custom +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--external-smt2-solver $(PROOF_ROOT)/lib/z3_no_bv_extract --z3 +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = polyvec_matrix_expand + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 11 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_expand/polyvec_matrix_expand_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_expand/polyvec_matrix_expand_harness.c new file mode 100644 index 0000000000..0365c6ac53 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_expand/polyvec_matrix_expand_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polymat *mat; + uint8_t *rho; + + mld_polyvec_matrix_expand(mat, rho); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_expand_serial/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_expand_serial/Makefile new file mode 100644 index 0000000000..d29d6c8723 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_expand_serial/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyvec_matrix_expand_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyvec_matrix_expand_serial + +DEFINES += -DMLD_CONFIG_SERIAL_FIPS202_ONLY +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvec_matrix_expand +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_uniform +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 --arrays-uf-always --slice-formula + +FUNCTION_NAME = polyvec_matrix_expand_serial + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 11 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_expand_serial/polyvec_matrix_expand_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_expand_serial/polyvec_matrix_expand_harness.c new file mode 100644 index 0000000000..0365c6ac53 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_expand_serial/polyvec_matrix_expand_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polymat *mat; + uint8_t *rho; + + mld_polyvec_matrix_expand(mat, rho); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_pointwise_montgomery/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_pointwise_montgomery/Makefile new file mode 100644 index 0000000000..cf212ee412 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_pointwise_montgomery/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyvec_matrix_pointwise_montgomery_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyvec_matrix_pointwise_montgomery + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvec_matrix_pointwise_montgomery +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvecl_pointwise_acc_montgomery +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 --arrays-uf-always --slice-formula + +FUNCTION_NAME = polyvec_matrix_pointwise_montgomery + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 10 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_pointwise_montgomery/polyvec_matrix_pointwise_montgomery_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_pointwise_montgomery/polyvec_matrix_pointwise_montgomery_harness.c new file mode 100644 index 0000000000..d967e10d88 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvec_matrix_pointwise_montgomery/polyvec_matrix_pointwise_montgomery_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *a; + mld_polymat *b; + mld_polyvecl *c; + mld_polyvec_matrix_pointwise_montgomery(a, b, c); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_add/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_add/Makefile new file mode 100644 index 0000000000..bed903f0c2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_add/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_add_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_add + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_add +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_add +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 --arrays-uf-always --slice-formula + +FUNCTION_NAME = polyveck_add + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_add/polyveck_add_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_add/polyveck_add_harness.c new file mode 100644 index 0000000000..5adb38f5b9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_add/polyveck_add_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *r, *b; + mld_polyveck_add(r, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_caddq/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_caddq/Makefile new file mode 100644 index 0000000000..42b10055ec --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_caddq/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_caddq_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_caddq + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_caddq +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_caddq +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyveck_caddq + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_caddq/polyveck_caddq_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_caddq/polyveck_caddq_harness.c new file mode 100644 index 0000000000..b8d9189ac0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_caddq/polyveck_caddq_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *a; + mld_polyveck_caddq(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_chknorm/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_chknorm/Makefile new file mode 100644 index 0000000000..daf32215bd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_chknorm/Makefile @@ -0,0 +1,57 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_chknorm_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_chknorm + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_chknorm +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_chknorm +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = polyveck_chknorm + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_chknorm/polyveck_chknorm_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_chknorm/polyveck_chknorm_harness.c new file mode 100644 index 0000000000..24934e6a1a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_chknorm/polyveck_chknorm_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + int32_t b; + mld_polyveck *v; + uint32_t r; + r = mld_polyveck_chknorm(v, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_decompose/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_decompose/Makefile new file mode 100644 index 0000000000..cf17b5c5e7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_decompose/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_decompose_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_decompose + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_decompose +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_decompose +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = polyveck_decompose + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 10 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_decompose/polyveck_decompose_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_decompose/polyveck_decompose_harness.c new file mode 100644 index 0000000000..68215df3a6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_decompose/polyveck_decompose_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *a0, *a1; + mld_polyveck_decompose(a1, a0); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_invntt_tomont/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_invntt_tomont/Makefile new file mode 100644 index 0000000000..071937d32f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_invntt_tomont/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_invntt_tomont_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_invntt_tomont + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_invntt_tomont +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_invntt_tomont +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyveck_invntt_tomont + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_invntt_tomont/polyveck_invntt_tomont_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_invntt_tomont/polyveck_invntt_tomont_harness.c new file mode 100644 index 0000000000..b159359a6a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_invntt_tomont/polyveck_invntt_tomont_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include +#include "params.h" +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *v; + mld_polyveck_invntt_tomont(v); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_make_hint/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_make_hint/Makefile new file mode 100644 index 0000000000..fc56480666 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_make_hint/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_make_hint_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_make_hint + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_make_hint +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_make_hint +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 --slice-formula + +FUNCTION_NAME = polyveck_make_hint + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_make_hint/polyveck_make_hint_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_make_hint/polyveck_make_hint_harness.c new file mode 100644 index 0000000000..c474ee0fc3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_make_hint/polyveck_make_hint_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *a, *b, *c; + unsigned int r; + r = mld_polyveck_make_hint(a, b, c); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_ntt/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_ntt/Makefile new file mode 100644 index 0000000000..0673660f75 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_ntt/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_ntt_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_ntt + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_ntt +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_ntt +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyveck_ntt + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_ntt/polyveck_ntt_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_ntt/polyveck_ntt_harness.c new file mode 100644 index 0000000000..1c6aaa8048 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_ntt/polyveck_ntt_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *a; + mld_polyveck_ntt(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_eta/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_eta/Makefile new file mode 100644 index 0000000000..447f70e8f4 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_eta/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_pack_eta_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_pack_eta + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_pack_eta +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyeta_pack +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = polyveck_pack_eta + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 10 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_eta/polyveck_pack_eta_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_eta/polyveck_pack_eta_harness.c new file mode 100644 index 0000000000..e89c514f25 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_eta/polyveck_pack_eta_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *a; + uint8_t *b; + mld_polyveck_pack_eta(b, a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_t0/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_t0/Makefile new file mode 100644 index 0000000000..174d6a3a5d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_t0/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_pack_t0_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_pack_t0 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_pack_t0 +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyt0_pack +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = polyveck_pack_t0 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_t0/polyveck_pack_t0_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_t0/polyveck_pack_t0_harness.c new file mode 100644 index 0000000000..dfa7c17f39 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_t0/polyveck_pack_t0_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *a; + uint8_t *b; + mld_polyveck_pack_t0(b, a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_w1/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_w1/Makefile new file mode 100644 index 0000000000..a7343144d8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_w1/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_pack_w1_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_pack_w1 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_pack_w1 +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyw1_pack +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = polyveck_pack_w1 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_w1/polyveck_pack_w1_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_w1/polyveck_pack_w1_harness.c new file mode 100644 index 0000000000..e2ade71a5a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pack_w1/polyveck_pack_w1_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *a; + uint8_t *b; + mld_polyveck_pack_w1(b, a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pointwise_poly_montgomery/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pointwise_poly_montgomery/Makefile new file mode 100644 index 0000000000..bf7cff4789 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pointwise_poly_montgomery/Makefile @@ -0,0 +1,54 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_pointwise_poly_montgomery_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_pointwise_poly_montgomery + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_pointwise_poly_montgomery +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_pointwise_montgomery +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 --slice-formula + +FUNCTION_NAME = polyveck_pointwise_poly_montgomery + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pointwise_poly_montgomery/polyveck_pointwise_poly_montgomery_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pointwise_poly_montgomery/polyveck_pointwise_poly_montgomery_harness.c new file mode 100644 index 0000000000..485acf8ceb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_pointwise_poly_montgomery/polyveck_pointwise_poly_montgomery_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *a, *b; + mld_poly *c; + mld_polyveck_pointwise_poly_montgomery(a, c, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_power2round/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_power2round/Makefile new file mode 100644 index 0000000000..955f487b6c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_power2round/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_power2round_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_power2round + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_power2round +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_power2round +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 --slice-formula + +FUNCTION_NAME = polyveck_power2round + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 10 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_power2round/polyveck_power2round_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_power2round/polyveck_power2round_harness.c new file mode 100644 index 0000000000..3220f440d4 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_power2round/polyveck_power2round_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *a, *b, *c; + mld_polyveck_power2round(a, b, c); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_reduce/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_reduce/Makefile new file mode 100644 index 0000000000..ed815e682d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_reduce/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_reduce_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_reduce + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_reduce +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_reduce +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyveck_reduce + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_reduce/polyveck_reduce_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_reduce/polyveck_reduce_harness.c new file mode 100644 index 0000000000..aafcf9908c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_reduce/polyveck_reduce_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *a; + mld_polyveck_reduce(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_shiftl/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_shiftl/Makefile new file mode 100644 index 0000000000..41eb8a844e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_shiftl/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_shiftl_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_shiftl + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_shiftl +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_shiftl +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyveck_shiftl + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_shiftl/polyveck_shiftl_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_shiftl/polyveck_shiftl_harness.c new file mode 100644 index 0000000000..81e33c73f2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_shiftl/polyveck_shiftl_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *a; + mld_polyveck_shiftl(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_sub/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_sub/Makefile new file mode 100644 index 0000000000..3b6c67f424 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_sub/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_sub_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_sub + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_sub +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_sub +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyveck_sub + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_sub/polyveck_sub_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_sub/polyveck_sub_harness.c new file mode 100644 index 0000000000..4dabf8fb1b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_sub/polyveck_sub_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *u, *v; + mld_polyveck_sub(u, v); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_unpack_eta/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_unpack_eta/Makefile new file mode 100644 index 0000000000..685a83faf6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_unpack_eta/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_unpack_eta_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_unpack_eta + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += $(MLD_NAMESPACE)polyveck_unpack_eta.0:8 # Largest value of MLDSA_K + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_unpack_eta +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyeta_unpack +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyveck_unpack_eta + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_unpack_eta/polyveck_unpack_eta_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_unpack_eta/polyveck_unpack_eta_harness.c new file mode 100644 index 0000000000..f3aa940130 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_unpack_eta/polyveck_unpack_eta_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *a; + uint8_t *b; + mld_polyveck_unpack_eta(a, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_unpack_t0/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_unpack_t0/Makefile new file mode 100644 index 0000000000..d55e668af2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_unpack_t0/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_unpack_t0_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_unpack_t0 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += $(MLD_NAMESPACE)polyveck_unpack_t0.0:8 # Largest value of MLDSA_K + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_unpack_t0 +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyt0_unpack +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyveck_unpack_t0 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_unpack_t0/polyveck_unpack_t0_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_unpack_t0/polyveck_unpack_t0_harness.c new file mode 100644 index 0000000000..8562c27a8d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_unpack_t0/polyveck_unpack_t0_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *a; + uint8_t *b; + mld_polyveck_unpack_t0(a, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_use_hint/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_use_hint/Makefile new file mode 100644 index 0000000000..3a32f91a63 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_use_hint/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyveck_use_hint_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyveck_use_hint + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyveck_use_hint +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_use_hint +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyveck_use_hint + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_use_hint/polyveck_use_hint_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_use_hint/polyveck_use_hint_harness.c new file mode 100644 index 0000000000..99924a89ee --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyveck_use_hint/polyveck_use_hint_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyveck *a, *b, *c; + mld_polyveck_use_hint(a, b, c); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_chknorm/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_chknorm/Makefile new file mode 100644 index 0000000000..744c3a6e75 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_chknorm/Makefile @@ -0,0 +1,57 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyvecl_chknorm_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyvecl_chknorm + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvecl_chknorm +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_chknorm +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = polyvecl_chknorm + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 12 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_chknorm/polyvecl_chknorm_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_chknorm/polyvecl_chknorm_harness.c new file mode 100644 index 0000000000..066dbf1599 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_chknorm/polyvecl_chknorm_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyvecl *v; + int32_t bound; + + mld_polyvecl_chknorm(v, bound); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_ntt/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_ntt/Makefile new file mode 100644 index 0000000000..a8ccca7b99 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_ntt/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyvecl_ntt_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyvecl_ntt + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvecl_ntt +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_ntt +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyvecl_ntt + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_ntt/polyvecl_ntt_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_ntt/polyvecl_ntt_harness.c new file mode 100644 index 0000000000..54d6a3a077 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_ntt/polyvecl_ntt_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyvecl *a; + mld_polyvecl_ntt(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pack_eta/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pack_eta/Makefile new file mode 100644 index 0000000000..767bbff66d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pack_eta/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyvecl_pack_eta_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyvecl_pack_eta + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvecl_pack_eta +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyeta_pack +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = polyvecl_pack_eta + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pack_eta/polyvecl_pack_eta_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pack_eta/polyvecl_pack_eta_harness.c new file mode 100644 index 0000000000..4c8b039d87 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pack_eta/polyvecl_pack_eta_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyvecl *a; + uint8_t *b; + mld_polyvecl_pack_eta(b, a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_permute_bitrev_to_custom/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_permute_bitrev_to_custom/Makefile new file mode 100644 index 0000000000..370d3571e3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_permute_bitrev_to_custom/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyvecl_permute_bitrev_to_custom_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyvecl_permute_bitrev_to_custom + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=mld_polyvecl_permute_bitrev_to_custom +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 --slice-formula --no-array-field-sensitivity + +FUNCTION_NAME = polyvecl_permute_bitrev_to_custom + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 12 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_permute_bitrev_to_custom/polyvecl_permute_bitrev_to_custom_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_permute_bitrev_to_custom/polyvecl_permute_bitrev_to_custom_harness.c new file mode 100644 index 0000000000..83d58ff7cb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_permute_bitrev_to_custom/polyvecl_permute_bitrev_to_custom_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void mld_polyvecl_permute_bitrev_to_custom(mld_polyvecl *v); + +void harness(void) +{ + mld_polyvecl *v; + mld_polyvecl_permute_bitrev_to_custom(v); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_permute_bitrev_to_custom_native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_permute_bitrev_to_custom_native/Makefile new file mode 100644 index 0000000000..893a26decf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_permute_bitrev_to_custom_native/Makefile @@ -0,0 +1,54 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyvecl_permute_bitrev_to_custom_native_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_polyvecl_permute_bitrev_to_custom_native + +DEFINES += -DMLD_CONFIG_USE_NATIVE_BACKEND_ARITH -DMLD_CONFIG_ARITH_BACKEND_FILE="\"dummy_backend.h\"" +INCLUDES += +UNWINDSET += + +REMOVE_FUNCTION_BODY += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=mld_polyvecl_permute_bitrev_to_custom +USE_FUNCTION_CONTRACTS= mld_poly_permute_bitrev_to_custom +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 --slice-formula --no-array-field-sensitivity + +FUNCTION_NAME = mld_polyvecl_permute_bitrev_to_custom_native + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true +CBMC_OBJECT_BITS = 10 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_permute_bitrev_to_custom_native/polyvecl_permute_bitrev_to_custom_native_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_permute_bitrev_to_custom_native/polyvecl_permute_bitrev_to_custom_native_harness.c new file mode 100644 index 0000000000..83d58ff7cb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_permute_bitrev_to_custom_native/polyvecl_permute_bitrev_to_custom_native_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void mld_polyvecl_permute_bitrev_to_custom(mld_polyvecl *v); + +void harness(void) +{ + mld_polyvecl *v; + mld_polyvecl_permute_bitrev_to_custom(v); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery/Makefile new file mode 100644 index 0000000000..c5b81567bd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery/Makefile @@ -0,0 +1,57 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyvecl_pointwise_acc_montgomery_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyvecl_pointwise_acc_montgomery + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvecl_pointwise_acc_montgomery +USE_FUNCTION_CONTRACTS= mld_polyvecl_pointwise_acc_montgomery_c +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--external-smt2-solver $(PROOF_ROOT)/lib/z3_smt_only --z3 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = polyvecl_pointwise_acc_montgomery + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 12 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery/polyvecl_pointwise_acc_montgomery_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery/polyvecl_pointwise_acc_montgomery_harness.c new file mode 100644 index 0000000000..927d5a220a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery/polyvecl_pointwise_acc_montgomery_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_poly *a; + mld_polyvecl *b, *c; + mld_polyvecl_pointwise_acc_montgomery(a, b, c); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery_c/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery_c/Makefile new file mode 100644 index 0000000000..b9daef4e8a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery_c/Makefile @@ -0,0 +1,57 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyvecl_pointwise_acc_montgomery_c_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyvecl_pointwise_acc_montgomery_c + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=mld_polyvecl_pointwise_acc_montgomery_c +USE_FUNCTION_CONTRACTS=mld_montgomery_reduce +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--external-smt2-solver $(PROOF_ROOT)/lib/z3_no_bv_extract --z3 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = mld_polyvecl_pointwise_acc_montgomery_c + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 13 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery_c/polyvecl_pointwise_acc_montgomery_c_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery_c/polyvecl_pointwise_acc_montgomery_c_harness.c new file mode 100644 index 0000000000..7ff7073aaa --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery_c/polyvecl_pointwise_acc_montgomery_c_harness.c @@ -0,0 +1,18 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + + +// Prototype for the function under test +#define mld_polyvecl_pointwise_acc_montgomery_c \ + MLD_ADD_PARAM_SET(mld_polyvecl_pointwise_acc_montgomery_c) +void mld_polyvecl_pointwise_acc_montgomery_c(mld_poly *a, mld_polyvecl *b, + mld_polyvecl *c); + +void harness(void) +{ + mld_poly *a; + mld_polyvecl *b, *c; + mld_polyvecl_pointwise_acc_montgomery_c(a, b, c); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery_native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery_native/Makefile new file mode 100644 index 0000000000..5b507f981f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery_native/Makefile @@ -0,0 +1,64 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyvecl_pointwise_acc_montgomery_native_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyvecl_pointwise_acc_montgomery_native + +DEFINES += -DMLD_CONFIG_USE_NATIVE_BACKEND_ARITH -DMLD_CONFIG_ARITH_BACKEND_FILE="\"dummy_backend.h\"" +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvecl_pointwise_acc_montgomery +USE_FUNCTION_CONTRACTS= mld_polyvecl_pointwise_acc_montgomery_c +ifeq ($(MLD_CONFIG_PARAMETER_SET),44) + USE_FUNCTION_CONTRACTS+=mld_polyvecl_pointwise_acc_montgomery_l4_native +else ifeq ($(MLD_CONFIG_PARAMETER_SET),65) + USE_FUNCTION_CONTRACTS+=mld_polyvecl_pointwise_acc_montgomery_l5_native +else ifeq ($(MLD_CONFIG_PARAMETER_SET),87) + USE_FUNCTION_CONTRACTS+=mld_polyvecl_pointwise_acc_montgomery_l7_native +endif +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--external-smt2-solver $(PROOF_ROOT)/lib/z3_smt_only --z3 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = polyvecl_pointwise_acc_montgomery_native + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 12 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery_native/polyvecl_pointwise_acc_montgomery_native_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery_native/polyvecl_pointwise_acc_montgomery_native_harness.c new file mode 100644 index 0000000000..927d5a220a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_pointwise_acc_montgomery_native/polyvecl_pointwise_acc_montgomery_native_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_poly *a; + mld_polyvecl *b, *c; + mld_polyvecl_pointwise_acc_montgomery(a, b, c); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_uniform_gamma1/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_uniform_gamma1/Makefile new file mode 100644 index 0000000000..522c73c13d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_uniform_gamma1/Makefile @@ -0,0 +1,59 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyvecl_uniform_gamma1_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyvecl_uniform_gamma1 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvecl_uniform_gamma1 +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_uniform_gamma1_4x +ifeq ($(MLD_CONFIG_PARAMETER_SET),65) +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)poly_uniform_gamma1 +endif + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyvecl_uniform_gamma1 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_uniform_gamma1/polyvecl_uniform_gamma1_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_uniform_gamma1/polyvecl_uniform_gamma1_harness.c new file mode 100644 index 0000000000..da4d75a997 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_uniform_gamma1/polyvecl_uniform_gamma1_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyvecl *v; + const uint8_t *seed; + uint16_t nonce; + + mld_polyvecl_uniform_gamma1(v, seed, nonce); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_uniform_gamma1_serial/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_uniform_gamma1_serial/Makefile new file mode 100644 index 0000000000..d63af8b409 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_uniform_gamma1_serial/Makefile @@ -0,0 +1,57 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyvecl_uniform_gamma1_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyvecl_uniform_gamma1_serial + +DEFINES += -DMLD_CONFIG_SERIAL_FIPS202_ONLY +INCLUDES += + +REMOVE_FUNCTION_BODY += + +UNWINDSET += $(MLD_NAMESPACE)polyvecl_uniform_gamma1.0:7 # Largest value of MLDSA_L + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvecl_uniform_gamma1 +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_uniform_gamma1 + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyvecl_uniform_gamma1_serial + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 10 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_uniform_gamma1_serial/polyvecl_uniform_gamma1_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_uniform_gamma1_serial/polyvecl_uniform_gamma1_harness.c new file mode 100644 index 0000000000..da4d75a997 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_uniform_gamma1_serial/polyvecl_uniform_gamma1_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyvecl *v; + const uint8_t *seed; + uint16_t nonce; + + mld_polyvecl_uniform_gamma1(v, seed, nonce); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_unpack_eta/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_unpack_eta/Makefile new file mode 100644 index 0000000000..f386648211 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_unpack_eta/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyvecl_unpack_eta_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyvecl_unpack_eta + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += $(MLD_NAMESPACE)polyvecl_unpack_eta.0:7 # Largest value of MLDSA_L + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvecl_unpack_eta +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyeta_unpack +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyvecl_unpack_eta + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_unpack_eta/polyvecl_unpack_eta_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_unpack_eta/polyvecl_unpack_eta_harness.c new file mode 100644 index 0000000000..26da6a7dca --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_unpack_eta/polyvecl_unpack_eta_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyvecl *a; + uint8_t *b; + mld_polyvecl_unpack_eta(a, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_unpack_z/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_unpack_z/Makefile new file mode 100644 index 0000000000..18534578e9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_unpack_z/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyvecl_unpack_z_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyvecl_unpack_z + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += $(MLD_NAMESPACE)polyvecl_unpack_z.0:7 # Largest value of MLDSA_L + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/polyvec.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvecl_unpack_z +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyz_unpack +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyvecl_unpack_z + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_unpack_z/polyvecl_unpack_z_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_unpack_z/polyvecl_unpack_z_harness.c new file mode 100644 index 0000000000..4eede80ac7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyvecl_unpack_z/polyvecl_unpack_z_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "polyvec.h" + +void harness(void) +{ + mld_polyvecl *a; + uint8_t *b; + mld_polyvecl_unpack_z(a, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyw1_pack/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyw1_pack/Makefile new file mode 100644 index 0000000000..2002880696 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyw1_pack/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyw1_pack_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyw1_pack + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyw1_pack +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyw1_pack + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyw1_pack/polyw1_pack_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyw1_pack/polyw1_pack_harness.c new file mode 100644 index 0000000000..93fe544f90 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyw1_pack/polyw1_pack_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + +void harness(void) +{ + mld_poly *a; + uint8_t *b; + mld_polyw1_pack(b, a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_pack/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_pack/Makefile new file mode 100644 index 0000000000..7b238828fa --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_pack/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyz_pack_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyz_pack + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyz_pack +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyz_pack + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_pack/polyz_pack_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_pack/polyz_pack_harness.c new file mode 100644 index 0000000000..463d3d3a17 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_pack/polyz_pack_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + +void harness(void) +{ + mld_poly *a; + uint8_t *b; + mld_polyz_pack(b, a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack/Makefile new file mode 100644 index 0000000000..dfe0ecff70 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyz_unpack_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyz_unpack + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyz_unpack +USE_FUNCTION_CONTRACTS=mld_polyz_unpack_c +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyz_unpack + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack/polyz_unpack_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack/polyz_unpack_harness.c new file mode 100644 index 0000000000..0dd46b69ba --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack/polyz_unpack_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + +void harness(void) +{ + mld_poly *a; + uint8_t *b; + mld_polyz_unpack(a, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack_c/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack_c/Makefile new file mode 100644 index 0000000000..0a3112c17e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack_c/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyz_unpack_c_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyz_unpack_c + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS= mld_polyz_unpack_c +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_polyz_unpack_c + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack_c/polyz_unpack_c_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack_c/polyz_unpack_c_harness.c new file mode 100644 index 0000000000..ce68d6147d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack_c/polyz_unpack_c_harness.c @@ -0,0 +1,17 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + + +// Prototype for the function under test +#define mld_polyz_unpack_c MLD_ADD_PARAM_SET(mld_polyz_unpack_c) +void mld_polyz_unpack_c(mld_poly *a, uint8_t *b); + + +void harness(void) +{ + mld_poly *a; + uint8_t *b; + mld_polyz_unpack_c(a, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack_native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack_native/Makefile new file mode 100644 index 0000000000..af621ba545 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack_native/Makefile @@ -0,0 +1,62 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = polyz_unpack_native_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = polyz_unpack_native + +DEFINES += -DMLD_CONFIG_USE_NATIVE_BACKEND_ARITH -DMLD_CONFIG_ARITH_BACKEND_FILE="\"dummy_backend.h\"" +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyz_unpack +USE_FUNCTION_CONTRACTS=mld_polyz_unpack_c +ifeq ($(MLD_CONFIG_PARAMETER_SET),44) + USE_FUNCTION_CONTRACTS+=mld_polyz_unpack_17_native +else ifeq ($(MLD_CONFIG_PARAMETER_SET),65) + USE_FUNCTION_CONTRACTS+=mld_polyz_unpack_19_native +else ifeq ($(MLD_CONFIG_PARAMETER_SET),87) + USE_FUNCTION_CONTRACTS+=mld_polyz_unpack_19_native +endif +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = polyz_unpack_native + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack_native/polyz_unpack_native_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack_native/polyz_unpack_native_harness.c new file mode 100644 index 0000000000..0dd46b69ba --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/polyz_unpack_native/polyz_unpack_native_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly_kl.h" + +void harness(void) +{ + mld_poly *a; + uint8_t *b; + mld_polyz_unpack(a, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/power2round/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/power2round/Makefile new file mode 100644 index 0000000000..a8b2bcf3f3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/power2round/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = power2round_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = power2round + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_power2round +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = power2round + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/power2round/power2round_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/power2round/power2round_harness.c new file mode 100644 index 0000000000..fd6cf44433 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/power2round/power2round_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "rounding.h" + + +void harness(void) +{ + int32_t *a0, *a1; + int32_t a; + mld_power2round(a0, a1, a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/prepare_domain_separation_prefix/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/prepare_domain_separation_prefix/Makefile new file mode 100644 index 0000000000..f8b8fb50cb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/prepare_domain_separation_prefix/Makefile @@ -0,0 +1,33 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = prepare_domain_separation_prefix_harness + +PROOF_UID = mld_prepare_domain_separation_prefix + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)prepare_domain_separation_prefix +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +FUNCTION_NAME = prepare_domain_separation_prefix + +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula + +CBMC_OBJECT_BITS = 8 + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/prepare_domain_separation_prefix/prepare_domain_separation_prefix_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/prepare_domain_separation_prefix/prepare_domain_separation_prefix_harness.c new file mode 100644 index 0000000000..e77ae4af94 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/prepare_domain_separation_prefix/prepare_domain_separation_prefix_harness.c @@ -0,0 +1,16 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void harness(void) +{ + uint8_t *prefix; + const uint8_t *ph; + size_t phlen; + const uint8_t *ctx; + size_t ctxlen; + int hashalg; + + mld_prepare_domain_separation_prefix(prefix, ph, phlen, ctx, ctxlen, hashalg); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/reduce32/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/reduce32/Makefile new file mode 100644 index 0000000000..ae879ac337 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/reduce32/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = reduce32_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = reduce32 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_reduce32 +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = reduce32 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/reduce32/reduce32_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/reduce32/reduce32_harness.c new file mode 100644 index 0000000000..d982864df7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/reduce32/reduce32_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "reduce.h" + +void harness(void) +{ + int32_t a; + int32_t result = mld_reduce32(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta/Makefile new file mode 100644 index 0000000000..350b80ca39 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = rej_eta_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = rej_eta + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=mld_rej_eta +USE_FUNCTION_CONTRACTS= mld_rej_eta_c +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = mld_rej_eta + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta/rej_eta_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta/rej_eta_harness.c new file mode 100644 index 0000000000..b540b7bf9a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta/rej_eta_harness.c @@ -0,0 +1,19 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +static unsigned int mld_rej_eta(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen); + +void harness(void) +{ + int32_t *a; + unsigned int target; + unsigned int offset; + const uint8_t *buf; + unsigned int buflen; + + mld_rej_eta(a, target, offset, buf, buflen); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta_c/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta_c/Makefile new file mode 100644 index 0000000000..ba0294c642 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta_c/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = rej_eta_c_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = rej_eta_c + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=mld_rej_eta_c +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = mld_rej_eta_c + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta_c/rej_eta_c_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta_c/rej_eta_c_harness.c new file mode 100644 index 0000000000..7355bc6c26 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta_c/rej_eta_c_harness.c @@ -0,0 +1,20 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +#define mld_rej_eta_c MLD_ADD_PARAM_SET(mld_rej_eta_c) +static unsigned int mld_rej_eta_c(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen); + +void harness(void) +{ + int32_t *a; + unsigned int target; + unsigned int offset; + const uint8_t *buf; + unsigned int buflen; + + mld_rej_eta_c(a, target, offset, buf, buflen); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta_native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta_native/Makefile new file mode 100644 index 0000000000..76fb0b117a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta_native/Makefile @@ -0,0 +1,62 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = rej_eta_native_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = rej_eta_native + +DEFINES += -DMLD_CONFIG_USE_NATIVE_BACKEND_ARITH -DMLD_CONFIG_ARITH_BACKEND_FILE="\"dummy_backend.h\"" +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly_kl.c + +CHECK_FUNCTION_CONTRACTS=mld_rej_eta +USE_FUNCTION_CONTRACTS= mld_rej_eta_c +ifeq ($(MLD_CONFIG_PARAMETER_SET),44) + USE_FUNCTION_CONTRACTS+=mld_rej_uniform_eta2_native +else ifeq ($(MLD_CONFIG_PARAMETER_SET),65) + USE_FUNCTION_CONTRACTS+=mld_rej_uniform_eta4_native +else ifeq ($(MLD_CONFIG_PARAMETER_SET),87) + USE_FUNCTION_CONTRACTS+=mld_rej_uniform_eta2_native +endif +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = mld_rej_eta_native + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta_native/rej_eta_native_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta_native/rej_eta_native_harness.c new file mode 100644 index 0000000000..b540b7bf9a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_eta_native/rej_eta_native_harness.c @@ -0,0 +1,19 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +static unsigned int mld_rej_eta(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen); + +void harness(void) +{ + int32_t *a; + unsigned int target; + unsigned int offset; + const uint8_t *buf; + unsigned int buflen; + + mld_rej_eta(a, target, offset, buf, buflen); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform/Makefile new file mode 100644 index 0000000000..12633d07de --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = rej_uniform_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = rej_uniform + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_rej_uniform +USE_FUNCTION_CONTRACTS=mld_rej_uniform_c +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_rej_uniform + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform/rej_uniform_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform/rej_uniform_harness.c new file mode 100644 index 0000000000..e4b9097483 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform/rej_uniform_harness.c @@ -0,0 +1,19 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +static unsigned int mld_rej_uniform(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen); + +void harness(void) +{ + int32_t *a; + unsigned int target; + unsigned int offset; + const uint8_t *buf; + unsigned int buflen; + + mld_rej_uniform(a, target, offset, buf, buflen); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform_c/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform_c/Makefile new file mode 100644 index 0000000000..6acca2b4d8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform_c/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = rej_uniform_c_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = rej_uniform_c + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_rej_uniform_c +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_rej_uniform_c + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform_c/rej_uniform_c_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform_c/rej_uniform_c_harness.c new file mode 100644 index 0000000000..c366b8e489 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform_c/rej_uniform_c_harness.c @@ -0,0 +1,19 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +static unsigned int mld_rej_uniform_c(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen); + +void harness(void) +{ + int32_t *a; + unsigned int target; + unsigned int offset; + const uint8_t *buf; + unsigned int buflen; + + mld_rej_uniform_c(a, target, offset, buf, buflen); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform_native/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform_native/Makefile new file mode 100644 index 0000000000..15447a074e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform_native/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = rej_uniform_native_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = rej_uniform_native + +DEFINES += -DMLD_CONFIG_USE_NATIVE_BACKEND_ARITH -DMLD_CONFIG_ARITH_BACKEND_FILE="\"dummy_backend.h\"" +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_rej_uniform +USE_FUNCTION_CONTRACTS=mld_rej_uniform_native mld_rej_uniform_c +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_rej_uniform_native_native + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform_native/rej_uniform_native_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform_native/rej_uniform_native_harness.c new file mode 100644 index 0000000000..e4b9097483 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/rej_uniform_native/rej_uniform_native_harness.c @@ -0,0 +1,19 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "poly.h" + +static unsigned int mld_rej_uniform(int32_t *a, unsigned int target, + unsigned int offset, const uint8_t *buf, + unsigned int buflen); + +void harness(void) +{ + int32_t *a; + unsigned int target; + unsigned int offset; + const uint8_t *buf; + unsigned int buflen; + + mld_rej_uniform(a, target, offset, buf, buflen); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/run-cbmc-proofs.py b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/run-cbmc-proofs.py new file mode 100755 index 0000000000..a8e08bfe08 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/run-cbmc-proofs.py @@ -0,0 +1,549 @@ +#!/usr/bin/env python3 +# +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 + +import argparse +import asyncio +import json +import logging +import math +import os +import pathlib +import re +import subprocess +import sys +import tempfile +import uuid + +from lib.summarize import print_proof_results, export_result_json + + +DESCRIPTION = "Configure and run all CBMC proofs in parallel" + +# Keep the epilog hard-wrapped at 70 characters, as it gets printed +# verbatim in the terminal. 70 characters stops here --------------> | +EPILOG = """ +This tool automates the process of running `make report` in each of +the CBMC proof directories. The tool calculates the dependency graph +of all tasks needed to build, run, and report on all the proofs, and +executes these tasks in parallel. + +The tool is roughly equivalent to doing this: + + litani init --project "my-cool-project"; + + find . -name Makefile | while read -r proof; do + pushd $(dirname ${proof}); + + # The `make _report` rule adds a single proof to litani + # without running it + make _report; + + popd; + done + + litani run-build; + +except that it is much faster and provides some convenience options. +The CBMC CI runs this script with no arguments to build and run all +proofs in parallel. The value of "my-cool-project" is taken from the +PROJECT_NAME variable in Makefile-project-defines. + +The --no-standalone argument omits the `litani init` and `litani +run-build`; use it when you want to add additional proof jobs, not +just the CBMC ones. In that case, you would run `litani init` +yourself; then run `run-cbmc-proofs --no-standalone`; add any +additional jobs that you want to execute with `litani add-job`; and +finally run `litani run-build`. + +The litani dashboard will be written under the `output` directory; the +cbmc-viewer reports remain in the `$PROOF_DIR/report` directory. The +HTML dashboard from the latest Litani run will always be symlinked to +`output/latest/html/index.html`, so you can keep that page open in +your browser and reload the page whenever you re-run this script. +""" +# 70 characters stops here ----------------------------------------> | + + +def get_project_name(): + cmd = [ + "make", + "--no-print-directory", + "-f", + "Makefile.common", + "echo-project-name", + ] + logging.debug(" ".join(cmd)) + proc = subprocess.run( + cmd, universal_newlines=True, stdout=subprocess.PIPE, check=False + ) + if proc.returncode: + logging.critical("could not run make to determine project name") + sys.exit(1) + if not proc.stdout.strip(): + logging.warning( + "project name has not been set; using generic name instead. " + "Set the PROJECT_NAME value in Makefile-project-defines to " + "remove this warning" + ) + return "" + return proc.stdout.strip() + + +def get_args(): + pars = argparse.ArgumentParser( + description=DESCRIPTION, + epilog=EPILOG, + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + for arg in [ + { + "flags": ["-j", "--parallel-jobs"], + "type": int, + "metavar": "N", + "help": "run at most N proof jobs in parallel", + }, + { + "flags": ["--fail-on-proof-failure"], + "action": "store_true", + "help": "exit with return code `10' if any proof failed" + " (default: exit 0)", + }, + { + "flags": ["--no-standalone"], + "action": "store_true", + "help": "only configure proofs: do not initialize nor run", + }, + { + "flags": ["-p", "--proofs"], + "nargs": "+", + "metavar": "DIR", + "help": "only run proof in directory DIR (can pass more than one)", + }, + { + "flags": ["--project-name"], + "metavar": "NAME", + "default": get_project_name(), + "help": "project name for report. Default: %(default)s", + }, + { + "flags": ["--marker-file"], + "metavar": "FILE", + "default": "Makefile", + "help": ( + "name of file that marks proof directories. Default: " "%(default)s" + ), + }, + { + "flags": ["--no-memory-profile"], + "action": "store_true", + "help": "disable memory profiling, even if Litani supports it", + }, + { + "flags": ["--no-expensive-limit"], + "action": "store_true", + "help": "do not limit parallelism of 'EXPENSIVE' jobs", + }, + { + "flags": ["--expensive-jobs-parallelism"], + "metavar": "N", + "default": 1, + "type": int, + "help": ( + "how many proof jobs marked 'EXPENSIVE' to run in parallel. " + "Default: %(default)s" + ), + }, + { + "flags": ["--verbose"], + "action": "store_true", + "help": "verbose output", + }, + { + "flags": ["--debug"], + "action": "store_true", + "help": "debug output", + }, + { + "flags": ["--summarize"], + "action": "store_true", + "help": "summarize proof results with two tables on stdout", + }, + { + "flags": ["--version"], + "action": "version", + "version": "CBMC starter kit 2.10", + "help": "display version and exit", + }, + { + "flags": ["--no-coverage"], + "action": "store_true", + "help": "do property checking without coverage checking", + }, + { + "flags": ["--per-proof-timeout"], + "type": int, + "metavar": "SECONDS", + "default": 1800, + "help": "timeout for each individual proof in seconds (default: 1800)", + }, + { + "flags": ["--output-result-json"], + "metavar": "FILE", + "help": "path to export result JSON", + }, + ]: + flags = arg.pop("flags") + pars.add_argument(*flags, **arg) + return pars.parse_args() + + +def set_up_logging(verbose): + if verbose: + level = logging.DEBUG + else: + level = logging.WARNING + logging.basicConfig(format="run-cbmc-proofs: %(message)s", level=level) + + +def task_pool_size(): + ret = os.cpu_count() + if ret is None or ret < 3: + return 1 + return ret - 2 + + +def print_counter(counter): + # pylint: disable=consider-using-f-string + print( + "\rConfiguring CBMC proofs: " + "{complete:{width}} / {total:{width}}".format(**counter), + end="", + file=sys.stderr, + ) + + +def get_proof_dirs(proof_root, proof_list, marker_file): + if proof_list is not None: + proofs_remaining = list(proof_list) + else: + proofs_remaining = [] + + for root, _, fyles in os.walk(proof_root): + proof_name = str(pathlib.Path(root).name) + if root != str(proof_root) and ".litani_cache_dir" in fyles: + pathlib.Path(f"{root}/.litani_cache_dir").unlink() + if proof_list and proof_name not in proof_list: + continue + if proof_list and proof_name in proofs_remaining: + proofs_remaining.remove(proof_name) + if marker_file in fyles: + yield root + + if proofs_remaining: + logging.critical( + "The following proofs were not found: %s", ", ".join(proofs_remaining) + ) + sys.exit(1) + + +def run_build(litani, jobs, fail_on_proof_failure, summarize, output_result_json=None): + cmd = [str(litani), "run-build"] + if jobs: + cmd.extend(["-j", str(jobs)]) + if fail_on_proof_failure: + cmd.append("--fail-on-pipeline-failure") + if summarize: + out_file = pathlib.Path(tempfile.gettempdir(), "run.json").resolve() + cmd.extend(["--out-file", str(out_file)]) + + logging.debug(" ".join(cmd)) + proc = subprocess.run(cmd, check=False) + + if proc.returncode and not fail_on_proof_failure: + logging.critical("Failed to run litani run-build") + sys.exit(1) + + if summarize: + export_result_json(output_result_json, out_file) + print_proof_results(out_file) + out_file.unlink() + + if proc.returncode: + logging.error("One or more proofs failed") + sys.exit(10) + + +def get_litani_path(proof_root): + cmd = [ + "make", + "--no-print-directory", + f"PROOF_ROOT={proof_root}", + "-f", + "Makefile.common", + "litani-path", + ] + logging.debug(" ".join(cmd)) + proc = subprocess.run( + cmd, universal_newlines=True, stdout=subprocess.PIPE, check=False + ) + if proc.returncode: + logging.critical("Could not determine path to litani") + sys.exit(1) + return proc.stdout.strip() + + +def get_litani_capabilities(litani_path): + cmd = [litani_path, "print-capabilities"] + proc = subprocess.run( + cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, check=False + ) + if proc.returncode: + return [] + try: + return json.loads(proc.stdout) + except RuntimeError: + logging.warning("Could not load litani capabilities: '%s'", proc.stdout) + return [] + + +def check_uid_uniqueness(proof_dir, proof_uids): + with (pathlib.Path(proof_dir) / "Makefile").open() as handle: + for line in handle: + match = re.match(r"^PROOF_UID\s*=(?P[^#]+)", line) + if not match: + continue + uid = match["uid"].strip() + if uid not in proof_uids: + proof_uids[uid] = proof_dir + return + + logging.critical( + "The Makefile in directory '%s' should have a different " + "PROOF_UID than the Makefile in directory '%s'", + proof_dir, + proof_uids[match["uid"]], + ) + sys.exit(1) + + logging.critical( + "The Makefile in directory '%s' should contain a line like", proof_dir + ) + logging.critical("PROOF_UID = ...") + logging.critical("with a unique identifier for the proof.") + sys.exit(1) + + +def should_enable_memory_profiling(litani_caps, args): + if args.no_memory_profile: + return False + return "memory_profile" in litani_caps + + +def should_enable_pools(litani_caps, args): + if args.no_expensive_limit: + return False + return "pools" in litani_caps + + +async def configure_proof_dirs( # pylint: disable=too-many-arguments + queue, + counter, + proof_uids, + enable_pools, + enable_memory_profiling, + report_target, + debug, + timeout, +): + while True: + print_counter(counter) + path = str(await queue.get()) + + check_uid_uniqueness(path, proof_uids) + + pools = ["ENABLE_POOLS=true"] if enable_pools else [] + profiling = ["ENABLE_MEMORY_PROFILING=true"] if enable_memory_profiling else [] + + # Set up environment with CBMC_TIMEOUT + env = os.environ.copy() + env["CBMC_TIMEOUT"] = str(timeout) + + # delete old reports + proc = await asyncio.create_subprocess_exec( + "make", + "veryclean", + cwd=path, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + ) + + # Allow interactive tasks to preempt proof configuration + proc = await asyncio.create_subprocess_exec( + "nice", + "-n", + "15", + "make", + *pools, + *profiling, + "-B", + report_target, + "" if debug else "--quiet", + cwd=path, + env=env, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + ) + stdout, stderr = await proc.communicate() + logging.debug("returncode: %s", str(proc.returncode)) + logging.debug("stdout:") + for line in stdout.decode().splitlines(): + logging.debug(line) + logging.debug("stderr:") + for line in stderr.decode().splitlines(): + logging.debug(line) + + counter["fail" if proc.returncode else "pass"].append(path) + counter["complete"] += 1 + + print_counter(counter) + queue.task_done() + + +def add_tool_version_job(): + cmd = [ + "litani", + "add-job", + "--command", + "./lib/print_tool_versions.py .", + "--description", + "printing out tool versions", + "--phony-outputs", + str(uuid.uuid4()), + "--pipeline-name", + "print_tool_versions", + "--ci-stage", + "report", + "--tags", + "front-page-text", + ] + proc = subprocess.run(cmd) + if proc.returncode: + logging.critical("Could not add tool version printing job") + sys.exit(1) + + +async def main(): # pylint: disable=too-many-locals + args = get_args() + set_up_logging(args.verbose) + + proof_root = pathlib.Path(os.getcwd()) + litani = get_litani_path(proof_root) + + litani_caps = get_litani_capabilities(litani) + enable_pools = should_enable_pools(litani_caps, args) + init_pools = ( + ["--pools", f"expensive:{args.expensive_jobs_parallelism}"] + if enable_pools + else [] + ) + + if not args.no_standalone: + cmd = [ + str(litani), + "init", + *init_pools, + "--project", + args.project_name, + "--no-print-out-dir", + ] + + if "output_directory_flags" in litani_caps: + out_prefix = proof_root / "output" + out_symlink = out_prefix / "latest" + out_index = out_symlink / "html" / "index.html" + cmd.extend( + [ + "--output-prefix", + str(out_prefix), + "--output-symlink", + str(out_symlink), + ] + ) + print( + "\nFor your convenience, the output of this run will be symbolically linked to ", + out_index, + "\n", + ) + + logging.debug(" ".join(cmd)) + proc = subprocess.run(cmd, check=False) + if proc.returncode: + logging.critical("Failed to run litani init") + sys.exit(1) + + proof_dirs = list(get_proof_dirs(proof_root, args.proofs, args.marker_file)) + if not proof_dirs: + logging.critical("No proof directories found") + sys.exit(1) + + proof_queue = asyncio.Queue() + for proof_dir in proof_dirs: + proof_queue.put_nowait(proof_dir) + + counter = { + "pass": [], + "fail": [], + "complete": 0, + "total": len(proof_dirs), + "width": int(math.log10(len(proof_dirs))) + 1, + } + + proof_uids = {} + tasks = [] + + enable_memory_profiling = should_enable_memory_profiling(litani_caps, args) + report_target = "_report_no_coverage" if args.no_coverage else "_report" + + for _ in range(task_pool_size()): + task = asyncio.create_task( + configure_proof_dirs( + proof_queue, + counter, + proof_uids, + enable_pools, + enable_memory_profiling, + report_target, + args.debug, + args.per_proof_timeout, + ) + ) + tasks.append(task) + + await proof_queue.join() + + add_tool_version_job() + + print_counter(counter) + print("", file=sys.stderr) + + if counter["fail"]: + logging.critical( + "Failed to configure the following proofs:\n%s", + "\n".join([str(f) for f in counter["fail"]]), + ) + sys.exit(1) + + if not args.no_standalone: + run_build( + litani, + args.parallel_jobs, + args.fail_on_proof_failure, + args.summarize, + args.output_result_json, + ) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sample_s1_s2/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sample_s1_s2/Makefile new file mode 100644 index 0000000000..c2864f18db --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sample_s1_s2/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sample_s1_s2_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_sample_s1_s2 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=mld_sample_s1_s2 +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_uniform_eta_4x +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_sample_s1_s2 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sample_s1_s2/sample_s1_s2_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sample_s1_s2/sample_s1_s2_harness.c new file mode 100644 index 0000000000..84a392a098 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sample_s1_s2/sample_s1_s2_harness.c @@ -0,0 +1,16 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +static void mld_sample_s1_s2(mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t seed[MLDSA_CRHBYTES]); + +void harness(void) +{ + mld_polyvecl *s1; + mld_polyveck *s2; + uint8_t *seed; + + mld_sample_s1_s2(s1, s2, seed); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sample_s1_s2_serial/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sample_s1_s2_serial/Makefile new file mode 100644 index 0000000000..701a6a417a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sample_s1_s2_serial/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sample_s1_s2_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_sample_s1_s2_serial + +DEFINES += -DMLD_CONFIG_SERIAL_FIPS202_ONLY +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += mld_sample_s1_s2.0:7 # Largest value of MLDSA_L +UNWINDSET += mld_sample_s1_s2.1:8 # Largest value of MLDSA_K + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=mld_sample_s1_s2 +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)poly_uniform_eta +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_sample_s1_s2_serial + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 10 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sample_s1_s2_serial/sample_s1_s2_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sample_s1_s2_serial/sample_s1_s2_harness.c new file mode 100644 index 0000000000..84a392a098 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sample_s1_s2_serial/sample_s1_s2_harness.c @@ -0,0 +1,16 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +static void mld_sample_s1_s2(mld_polyvecl *s1, mld_polyveck *s2, + const uint8_t seed[MLDSA_CRHBYTES]); + +void harness(void) +{ + mld_polyvecl *s1; + mld_polyveck *s2; + uint8_t *seed; + + mld_sample_s1_s2(s1, s2, seed); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_absorb/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_absorb/Makefile new file mode 100644 index 0000000000..93c5f83d6a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_absorb/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = shake128_absorb_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = shake128_absorb + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake128_absorb +USE_FUNCTION_CONTRACTS=keccak_absorb +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = shake128_absorb + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_absorb/shake128_absorb_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_absorb/shake128_absorb_harness.c new file mode 100644 index 0000000000..e0999f5df4 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_absorb/shake128_absorb_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +void harness(void) +{ + mld_shake128ctx *s; + const uint8_t *in; + size_t inlen; + + mld_shake128_absorb(s, in, inlen); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_finalize/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_finalize/Makefile new file mode 100644 index 0000000000..f89be63f83 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_finalize/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = shake128_finalize_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = shake128_finalize + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake128_finalize +USE_FUNCTION_CONTRACTS=keccak_finalize +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = shake128_finalize + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_finalize/shake128_finalize_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_finalize/shake128_finalize_harness.c new file mode 100644 index 0000000000..084341400a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_finalize/shake128_finalize_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +void harness(void) +{ + mld_shake256ctx *s; + + mld_shake128_finalize(s); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_init/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_init/Makefile new file mode 100644 index 0000000000..89ba432bc6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_init/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = shake128_init_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = shake128_init + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake128_init +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = shake128_init + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_init/shake128_init_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_init/shake128_init_harness.c new file mode 100644 index 0000000000..997e7c430a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_init/shake128_init_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +void harness(void) +{ + mld_shake128ctx *s; + + mld_shake128_init(s); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_release/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_release/Makefile new file mode 100644 index 0000000000..9a351e95a7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_release/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = shake128_release_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = shake128_release + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake128_release +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = shake128_release + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_release/shake128_release_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_release/shake128_release_harness.c new file mode 100644 index 0000000000..05769ab037 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_release/shake128_release_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +void harness(void) +{ + mld_shake128ctx *s; + + mld_shake128_release(s); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_squeeze/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_squeeze/Makefile new file mode 100644 index 0000000000..cde1d9d75c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_squeeze/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = shake128_squeeze_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = shake128_squeeze + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake128_squeeze +USE_FUNCTION_CONTRACTS=keccak_squeeze +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = shake128_squeeze + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_squeeze/shake128_squeeze_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_squeeze/shake128_squeeze_harness.c new file mode 100644 index 0000000000..5aaa48fd86 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128_squeeze/shake128_squeeze_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +void harness(void) +{ + uint8_t *out; + size_t outlen; + mld_shake128ctx *state; + + mld_shake128_squeeze(out, outlen, state); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128x4_absorb_once/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128x4_absorb_once/Makefile new file mode 100644 index 0000000000..507295fe7b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128x4_absorb_once/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) The mldsa-native project authors +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = shake128x4_absorb_once_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = shake128x4_absorb_once + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202x4.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake128x4_absorb_once +USE_FUNCTION_CONTRACTS=mld_keccak_absorb_once_x4 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = mld_shake128x4_absorb_once + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mlkem/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mlkem/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128x4_absorb_once/shake128x4_absorb_once_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128x4_absorb_once/shake128x4_absorb_once_harness.c new file mode 100644 index 0000000000..c9038bd364 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128x4_absorb_once/shake128x4_absorb_once_harness.c @@ -0,0 +1,17 @@ +// Copyright (c) The mldsa-native project authors +// Copyright (c) The mlkem-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 + +#include +#include +#include +#include + +void harness(void) +{ + mld_shake128x4ctx *state; + const uint8_t *in0, in1, in2, in3; + size_t inlen; + mld_shake128x4_absorb_once(state, in0, in1, in2, in3, inlen); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128x4_squeezeblocks/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128x4_squeezeblocks/Makefile new file mode 100644 index 0000000000..4156986954 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128x4_squeezeblocks/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) The mldsa-native project authors +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = shake128x4_squeezeblocks_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = shake128x4_squeezeblocks + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202x4.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake128x4_squeezeblocks +USE_FUNCTION_CONTRACTS=mld_keccak_squeezeblocks_x4 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = mld_shake128x4_squeezeblocks + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mlkem/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mlkem/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128x4_squeezeblocks/shake128x4_squeezeblocks_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128x4_squeezeblocks/shake128x4_squeezeblocks_harness.c new file mode 100644 index 0000000000..d74d6a1878 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake128x4_squeezeblocks/shake128x4_squeezeblocks_harness.c @@ -0,0 +1,18 @@ +// Copyright (c) The mldsa-native project authors +// Copyright (c) The mlkem-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 + +#include +#include +#include +#include + +void harness(void) +{ + uint8_t *output0, output1, output2, output3; + size_t nblocks; + mld_shake128x4ctx *state; + mld_shake128x4_squeezeblocks(output0, output1, output2, output3, nblocks, + state); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256/Makefile new file mode 100644 index 0000000000..462087eb8b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = shake256_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = shake256 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake256 +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake256_init $(MLD_NAMESPACE)shake256_absorb $(MLD_NAMESPACE)shake256_finalize $(MLD_NAMESPACE)shake256_squeeze $(MLD_NAMESPACE)shake256_release +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = shake256 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256/shake256_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256/shake256_harness.c new file mode 100644 index 0000000000..73364a38ea --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256/shake256_harness.c @@ -0,0 +1,14 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +void harness(void) +{ + uint8_t *out; + size_t outlen; + const uint8_t *in; + size_t inlen; + + mld_shake256(out, outlen, in, inlen); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_absorb/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_absorb/Makefile new file mode 100644 index 0000000000..5afd4ab2cf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_absorb/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = shake256_absorb_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = shake256_absorb + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake256_absorb +USE_FUNCTION_CONTRACTS=keccak_absorb +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = shake256_absorb + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_absorb/shake256_absorb_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_absorb/shake256_absorb_harness.c new file mode 100644 index 0000000000..fdeac86d9d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_absorb/shake256_absorb_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +void harness(void) +{ + mld_shake256ctx *s; + const uint8_t *in; + size_t inlen; + + mld_shake256_absorb(s, in, inlen); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_finalize/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_finalize/Makefile new file mode 100644 index 0000000000..6489e1fafc --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_finalize/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = shake256_finalize_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = shake256_finalize + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake256_finalize +USE_FUNCTION_CONTRACTS=keccak_finalize +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = shake256_finalize + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_finalize/shake256_finalize_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_finalize/shake256_finalize_harness.c new file mode 100644 index 0000000000..da0d42ef39 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_finalize/shake256_finalize_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +void harness(void) +{ + mld_shake256ctx *s; + + mld_shake256_finalize(s); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_init/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_init/Makefile new file mode 100644 index 0000000000..c0cdf0c5d3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_init/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = shake256_init_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = shake256_init + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake256_init +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = shake256_init + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_init/shake256_init_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_init/shake256_init_harness.c new file mode 100644 index 0000000000..abd18b5818 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_init/shake256_init_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +void harness(void) +{ + mld_shake256ctx *s; + + mld_shake256_init(s); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_release/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_release/Makefile new file mode 100644 index 0000000000..05b9055388 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_release/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = shake256_release_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = shake256_release + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake256_release +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = shake256_release + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_release/shake256_release_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_release/shake256_release_harness.c new file mode 100644 index 0000000000..a1342ac37c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_release/shake256_release_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +void harness(void) +{ + mld_shake256ctx *s; + + mld_shake256_release(s); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_squeeze/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_squeeze/Makefile new file mode 100644 index 0000000000..b7e83bb5e7 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_squeeze/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = shake256_squeeze_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = shake256_squeeze + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake256_squeeze +USE_FUNCTION_CONTRACTS=keccak_squeeze +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = shake256_squeeze + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_squeeze/shake256_squeeze_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_squeeze/shake256_squeeze_harness.c new file mode 100644 index 0000000000..3a52334ee4 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256_squeeze/shake256_squeeze_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +void harness(void) +{ + uint8_t *out; + size_t outlen; + mld_shake256ctx *state; + + mld_shake256_squeeze(out, outlen, state); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256x4_absorb_once/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256x4_absorb_once/Makefile new file mode 100644 index 0000000000..9cdef67f2d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256x4_absorb_once/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) The mldsa-native project authors +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = shake256x4_absorb_once_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = shake256x4_absorb_once + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202x4.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake256x4_absorb_once +USE_FUNCTION_CONTRACTS=mld_keccak_absorb_once_x4 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = mld_shake256x4_absorb_once + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mlkem/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mlkem/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256x4_absorb_once/shake256x4_absorb_once_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256x4_absorb_once/shake256x4_absorb_once_harness.c new file mode 100644 index 0000000000..948ba4b58d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256x4_absorb_once/shake256x4_absorb_once_harness.c @@ -0,0 +1,17 @@ +// Copyright (c) The mldsa-native project authors +// Copyright (c) The mlkem-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 + +#include +#include +#include +#include + +void harness(void) +{ + mld_shake256x4ctx *state; + const uint8_t *in0, in1, in2, in3; + size_t inlen; + mld_shake256x4_absorb_once(state, in0, in1, in2, in3, inlen); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256x4_squeezeblocks/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256x4_squeezeblocks/Makefile new file mode 100644 index 0000000000..8ea065ea1d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256x4_squeezeblocks/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) The mldsa-native project authors +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = shake256x4_squeezeblocks_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = shake256x4_squeezeblocks + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/fips202/fips202x4.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake256x4_squeezeblocks +USE_FUNCTION_CONTRACTS=mld_keccak_squeezeblocks_x4 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--bitwuzla + +FUNCTION_NAME = mld_shake256x4_squeezeblocks + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mlkem/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mlkem/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256x4_squeezeblocks/shake256x4_squeezeblocks_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256x4_squeezeblocks/shake256x4_squeezeblocks_harness.c new file mode 100644 index 0000000000..dfac11b13e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/shake256x4_squeezeblocks/shake256x4_squeezeblocks_harness.c @@ -0,0 +1,18 @@ +// Copyright (c) The mldsa-native project authors +// Copyright (c) The mlkem-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 + +#include +#include +#include +#include + +void harness(void) +{ + uint8_t *output0, output1, output2, output3; + size_t nblocks; + mld_shake256x4ctx *state; + mld_shake256x4_squeezeblocks(output0, output1, output2, output3, nblocks, + state); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign/Makefile new file mode 100644 index 0000000000..b0eb22a4e8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign/Makefile @@ -0,0 +1,57 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sign_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sign + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)sign +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)signature + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = sign + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign/sign_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign/sign_harness.c new file mode 100644 index 0000000000..bd6b900c90 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign/sign_harness.c @@ -0,0 +1,19 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void harness(void) +{ + uint8_t *sm; + size_t *smlen; + uint8_t *m; + size_t mlen; + uint8_t *ctx; + size_t ctxlen; + uint8_t *sk; + int r; + + r = mld_sign(sm, smlen, m, mlen, ctx, ctxlen, sk, + NULL /* context will be dropped by preprocessor */); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_keypair/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_keypair/Makefile new file mode 100644 index 0000000000..d768a478a6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_keypair/Makefile @@ -0,0 +1,59 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sign_keypair_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sign_keypair + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keypair +USE_FUNCTION_CONTRACTS=mld_randombytes +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)keypair_internal +USE_FUNCTION_CONTRACTS+=mld_zeroize + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = sign_keypair + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_keypair/sign_keypair_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_keypair/sign_keypair_harness.c new file mode 100644 index 0000000000..ecd7e8b21b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_keypair/sign_keypair_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void harness(void) +{ + uint8_t *pk, *sk; + int r; + r = mld_sign_keypair(pk, sk, + NULL /* context will be dropped by preprocessor */); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_keypair_internal/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_keypair_internal/Makefile new file mode 100644 index 0000000000..f05a245a57 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_keypair_internal/Makefile @@ -0,0 +1,65 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sign_keypair_internal_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sign_keypair_internal + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)keypair_internal +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)shake256 +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyvec_matrix_expand +USE_FUNCTION_CONTRACTS+=mld_sample_s1_s2 +USE_FUNCTION_CONTRACTS+=mld_compute_t0_t1_tr_from_sk_components +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)pack_pk +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)pack_sk +USE_FUNCTION_CONTRACTS+=mld_zeroize +USE_FUNCTION_CONTRACTS+=mld_check_pct + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--external-smt2-solver $(PROOF_ROOT)/lib/z3_no_bv_extract --z3 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = sign_keypair_internal + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 12 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_keypair_internal/sign_keypair_internal_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_keypair_internal/sign_keypair_internal_harness.c new file mode 100644 index 0000000000..1f0101bd48 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_keypair_internal/sign_keypair_internal_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void harness(void) +{ + uint8_t *a, *b, *c; + mld_sign_keypair_internal(a, b, c, + NULL /* context will be dropped by preprocessor */); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_open/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_open/Makefile new file mode 100644 index 0000000000..bdb87fd292 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_open/Makefile @@ -0,0 +1,57 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sign_open_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sign_open + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)open +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)verify + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = sign_open + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_open/sign_open_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_open/sign_open_harness.c new file mode 100644 index 0000000000..14070e12c8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_open/sign_open_harness.c @@ -0,0 +1,18 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void harness(void) +{ + uint8_t *m; + size_t *mlen; + const uint8_t *sm; + size_t smlen; + const uint8_t *ctx; + size_t ctxlen; + const uint8_t *pk; + + mld_sign_open(m, mlen, sm, smlen, ctx, ctxlen, pk, + NULL /* context will be dropped by preprocessor */); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_pk_from_sk/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_pk_from_sk/Makefile new file mode 100644 index 0000000000..39efa3bdbe --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_pk_from_sk/Makefile @@ -0,0 +1,65 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sign_pk_from_sk_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sign_pk_from_sk + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)pk_from_sk +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)unpack_sk +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)pack_pk +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyvecl_chknorm +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_chknorm +USE_FUNCTION_CONTRACTS+=mld_compute_t0_t1_tr_from_sk_components +USE_FUNCTION_CONTRACTS+=mld_value_barrier_u8 +USE_FUNCTION_CONTRACTS+=mld_ct_memcmp +USE_FUNCTION_CONTRACTS+=mld_zeroize + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--external-smt2-solver $(PROOF_ROOT)/lib/z3_no_bv_extract --z3 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = sign_pk_from_sk + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 12 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_pk_from_sk/sign_pk_from_sk_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_pk_from_sk/sign_pk_from_sk_harness.c new file mode 100644 index 0000000000..b861e45479 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_pk_from_sk/sign_pk_from_sk_harness.c @@ -0,0 +1,14 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void harness(void) +{ + uint8_t *pk; + uint8_t *sk; + + int r; + r = mld_sign_pk_from_sk(pk, sk, + NULL /* context will be dropped by preprocessor */); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature/Makefile new file mode 100644 index 0000000000..edca87cae3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature/Makefile @@ -0,0 +1,58 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sign_signature_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sign_signature + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)signature +USE_FUNCTION_CONTRACTS=mld_randombytes \ + $(MLD_NAMESPACE)signature_internal + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = sign_signature + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature/sign_signature_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature/sign_signature_harness.c new file mode 100644 index 0000000000..a7a1b0c346 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature/sign_signature_harness.c @@ -0,0 +1,19 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void harness(void) +{ + uint8_t *sig; + size_t *siglen; + uint8_t *m; + size_t mlen; + uint8_t *ctx; + size_t ctxlen; + uint8_t *sk; + int r; + + r = mld_sign_signature(sig, siglen, m, mlen, ctx, ctxlen, sk, + NULL /* context will be dropped by preprocessor */); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_extmu/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_extmu/Makefile new file mode 100644 index 0000000000..7b0a6ddaf2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_extmu/Makefile @@ -0,0 +1,58 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sign_signature_extmu_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sign_signature_extmu + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)signature_extmu +USE_FUNCTION_CONTRACTS=mld_randombytes \ + $(MLD_NAMESPACE)signature_internal + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = sign_signature_extmu + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_extmu/sign_signature_extmu_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_extmu/sign_signature_extmu_harness.c new file mode 100644 index 0000000000..a4b927cdc8 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_extmu/sign_signature_extmu_harness.c @@ -0,0 +1,16 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void harness(void) +{ + uint8_t *sig; + size_t *siglen; + uint8_t *mu; + uint8_t *sk; + int r; + + r = mld_sign_signature_extmu( + sig, siglen, mu, sk, NULL /* context will be dropped by preprocessor */); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_internal/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_internal/Makefile new file mode 100644 index 0000000000..816bb8fae0 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_internal/Makefile @@ -0,0 +1,64 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sign_signature_internal_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sign_signature_internal + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)signature_internal +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)unpack_sk \ + mld_H \ + $(MLD_NAMESPACE)polyvec_matrix_expand \ + $(MLD_NAMESPACE)polyvecl_ntt \ + $(MLD_NAMESPACE)polyveck_ntt \ + mld_attempt_signature_generation +USE_FUNCTION_CONTRACTS+=mld_zeroize + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--external-smt2-solver $(PROOF_ROOT)/lib/z3_no_bv_extract --z3 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = sign_signature_internal + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_internal/sign_signature_internal_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_internal/sign_signature_internal_harness.c new file mode 100644 index 0000000000..19b0a89210 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_internal/sign_signature_internal_harness.c @@ -0,0 +1,21 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void harness(void) +{ + uint8_t *sig; + size_t *siglen; + uint8_t *m; + size_t mlen; + uint8_t *pre; + size_t prelen; + uint8_t *rnd; + uint8_t *sk; + int externalmu; + int r; + r = mld_sign_signature_internal( + sig, siglen, m, mlen, pre, prelen, rnd, sk, externalmu, + NULL /* context will be dropped by preprocessor */); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_pre_hash_internal/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_pre_hash_internal/Makefile new file mode 100644 index 0000000000..bec285a0ad --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_pre_hash_internal/Makefile @@ -0,0 +1,58 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sign_signature_pre_hash_internal_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sign_signature_pre_hash_internal + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)signature_pre_hash_internal +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)signature_internal + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = sign_signature_pre_hash_internal + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_pre_hash_internal/sign_signature_pre_hash_internal_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_pre_hash_internal/sign_signature_pre_hash_internal_harness.c new file mode 100644 index 0000000000..51c6359875 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_pre_hash_internal/sign_signature_pre_hash_internal_harness.c @@ -0,0 +1,21 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void harness(void) +{ + uint8_t *sig; + size_t *siglen; + const uint8_t *ph; + size_t phlen; + const uint8_t *ctx; + size_t ctxlen; + const uint8_t *rnd; + const uint8_t *sk; + int hashalg; + int r; + r = mld_sign_signature_pre_hash_internal( + sig, siglen, ph, phlen, ctx, ctxlen, rnd, sk, hashalg, + NULL /* context will be dropped by preprocessor */); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_pre_hash_shake256/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_pre_hash_shake256/Makefile new file mode 100644 index 0000000000..07cc1e5184 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_pre_hash_shake256/Makefile @@ -0,0 +1,58 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sign_signature_pre_hash_shake256_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sign_signature_pre_hash_shake256 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)signature_pre_hash_shake256 +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)signature_pre_hash_internal $(MLD_NAMESPACE)shake256 + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = sign_signature_pre_hash_shake256 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_pre_hash_shake256/sign_signature_pre_hash_shake256_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_pre_hash_shake256/sign_signature_pre_hash_shake256_harness.c new file mode 100644 index 0000000000..3fa15211d1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_signature_pre_hash_shake256/sign_signature_pre_hash_shake256_harness.c @@ -0,0 +1,20 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void harness(void) +{ + uint8_t *sig; + size_t *siglen; + const uint8_t *m; + size_t mlen; + const uint8_t *ctx; + size_t ctxlen; + const uint8_t *rnd; + const uint8_t *sk; + int r; + r = mld_sign_signature_pre_hash_shake256( + sig, siglen, m, mlen, ctx, ctxlen, rnd, sk, + NULL /* context will be dropped by preprocessor */); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify/Makefile new file mode 100644 index 0000000000..6ecd2ed975 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify/Makefile @@ -0,0 +1,58 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sign_verify_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sign_verify + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)verify +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)verify_internal +USE_FUNCTION_CONTRACTS+=mld_zeroize + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = sign_verify + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify/sign_verify_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify/sign_verify_harness.c new file mode 100644 index 0000000000..223f250052 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify/sign_verify_harness.c @@ -0,0 +1,20 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void harness(void) +{ + const uint8_t *sig; + size_t siglen; + const uint8_t *m; + size_t mlen; + const uint8_t *ctx; + size_t ctxlen; + const uint8_t *pk; + + int r; + + r = mld_sign_verify(sig, siglen, m, mlen, ctx, ctxlen, pk, + NULL /* context will be dropped by preprocessor */); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_extmu/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_extmu/Makefile new file mode 100644 index 0000000000..0da0a90ddf --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_extmu/Makefile @@ -0,0 +1,57 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sign_verify_extmu_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sign_verify_extmu + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)verify_extmu +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)verify_internal + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = sign_verify_extmu + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_extmu/sign_verify_extmu_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_extmu/sign_verify_extmu_harness.c new file mode 100644 index 0000000000..1ab13723d6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_extmu/sign_verify_extmu_harness.c @@ -0,0 +1,19 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + + + +void harness(void) +{ + uint8_t *sig; + size_t siglen; + uint8_t *mu; + uint8_t *pk; + + int r; + + r = mld_sign_verify_extmu(sig, siglen, mu, pk, + NULL /* context will be dropped by preprocessor */); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_internal/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_internal/Makefile new file mode 100644 index 0000000000..8eada4d4c3 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_internal/Makefile @@ -0,0 +1,76 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sign_verify_internal_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sign_verify_internal + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)verify_internal +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)unpack_pk +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)unpack_sig +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyvecl_chknorm +USE_FUNCTION_CONTRACTS+=mld_H +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)poly_challenge +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyvec_matrix_expand +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyvecl_ntt +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyvec_matrix_pointwise_montgomery +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)poly_ntt +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_shiftl +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_ntt +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_pointwise_poly_montgomery +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_sub +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_reduce +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_invntt_tomont +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_caddq +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_use_hint +USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_pack_w1 +USE_FUNCTION_CONTRACTS+=mld_zeroize +USE_FUNCTION_CONTRACTS+=mld_ct_memcmp + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula + +FUNCTION_NAME = sign_verify_internal + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 10 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_internal/sign_verify_internal_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_internal/sign_verify_internal_harness.c new file mode 100644 index 0000000000..7ec4ac15d5 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_internal/sign_verify_internal_harness.c @@ -0,0 +1,19 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void harness(void) +{ + const uint8_t *sig; + size_t siglen; + const uint8_t *m; + size_t mlen; + const uint8_t *pre; + size_t prelen; + const uint8_t *pk; + int externalmu; + + mld_sign_verify_internal(sig, siglen, m, mlen, pre, prelen, pk, externalmu, + NULL /* context will be dropped by preprocessor */); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_pre_hash_internal/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_pre_hash_internal/Makefile new file mode 100644 index 0000000000..3a44de0fbb --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_pre_hash_internal/Makefile @@ -0,0 +1,59 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sign_verify_pre_hash_internal_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sign_verify_pre_hash_internal + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)verify_pre_hash_internal +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)verify_internal +USE_FUNCTION_CONTRACTS+=mld_zeroize + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = sign_verify_pre_hash_internal + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_pre_hash_internal/sign_verify_pre_hash_internal_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_pre_hash_internal/sign_verify_pre_hash_internal_harness.c new file mode 100644 index 0000000000..5b384d847c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_pre_hash_internal/sign_verify_pre_hash_internal_harness.c @@ -0,0 +1,20 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void harness(void) +{ + const uint8_t *sig; + size_t siglen; + const uint8_t *ph; + size_t phlen; + const uint8_t *ctx; + size_t ctxlen; + const uint8_t *pk; + int hashalg; + int r; + r = mld_sign_verify_pre_hash_internal( + sig, siglen, ph, phlen, ctx, ctxlen, pk, hashalg, + NULL /* context will be dropped by preprocessor */); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_pre_hash_shake256/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_pre_hash_shake256/Makefile new file mode 100644 index 0000000000..406e1d0007 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_pre_hash_shake256/Makefile @@ -0,0 +1,58 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sign_verify_pre_hash_shake256_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sign_verify_pre_hash_shake256 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)verify_pre_hash_shake256 +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)verify_pre_hash_internal $(MLD_NAMESPACE)shake256 + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = sign_verify_pre_hash_shake256 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_pre_hash_shake256/sign_verify_pre_hash_shake256_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_pre_hash_shake256/sign_verify_pre_hash_shake256_harness.c new file mode 100644 index 0000000000..c04d6677c1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sign_verify_pre_hash_shake256/sign_verify_pre_hash_shake256_harness.c @@ -0,0 +1,19 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void harness(void) +{ + const uint8_t *sig; + size_t siglen; + const uint8_t *m; + size_t mlen; + const uint8_t *ctx; + size_t ctxlen; + const uint8_t *pk; + int r; + r = mld_sign_verify_pre_hash_shake256( + sig, siglen, m, mlen, ctx, ctxlen, pk, + NULL /* context will be dropped by preprocessor */); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sys_check_capability/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sys_check_capability/Makefile new file mode 100644 index 0000000000..879ea99642 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sys_check_capability/Makefile @@ -0,0 +1,57 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sys_check_capability_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sys_check_capability + +# We need to set MLD_CHECK_APIS as otherwise mldsa/src/native/api.h won't be +# included, which contains the CBMC specifications. +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_sys_check_capability +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = is_native_capable + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/src/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sys_check_capability/sys_check_capability_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sys_check_capability/sys_check_capability_harness.c new file mode 100644 index 0000000000..e0a50e6f4f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/sys_check_capability/sys_check_capability_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 + +#include "sys.h" + +void harness(void) +{ + int t; + mld_sys_cap cap; + t = mld_sys_check_capability(cap); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_hints/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_hints/Makefile new file mode 100644 index 0000000000..a61c0ee75b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_hints/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = unpack_hints_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = unpack_hints + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/packing.c + +CHECK_FUNCTION_CONTRACTS=mld_unpack_hints +USE_FUNCTION_CONTRACTS= +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS+=--slice-formula + +FUNCTION_NAME = mld_unpack_hints + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_hints/unpack_hints_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_hints/unpack_hints_harness.c new file mode 100644 index 0000000000..9e10493e26 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_hints/unpack_hints_harness.c @@ -0,0 +1,15 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "packing.h" + +int mld_unpack_hints(mld_polyveck *h, + const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]); + +void harness(void) +{ + uint8_t *sig; + mld_polyveck *h; + int r; + r = mld_unpack_hints(h, sig); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_pk/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_pk/Makefile new file mode 100644 index 0000000000..8ebd77bc26 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_pk/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = unpack_pk_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = unpack_pk + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += $(MLD_NAMESPACE)unpack_pk.0:8 # Largest value of MLDSA_K + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/packing.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)unpack_pk +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyt1_unpack +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = unpack_pk + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_pk/unpack_pk_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_pk/unpack_pk_harness.c new file mode 100644 index 0000000000..49a088beae --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_pk/unpack_pk_harness.c @@ -0,0 +1,12 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "packing.h" + + +void harness(void) +{ + uint8_t *a, *b; + mld_polyveck *c; + mld_unpack_pk(a, c, b); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_sig/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_sig/Makefile new file mode 100644 index 0000000000..b8b4981dcd --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_sig/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = unpack_sig_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = unpack_sig + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/packing.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)unpack_sig +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvecl_unpack_z mld_unpack_hints +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS+=--slice-formula + +FUNCTION_NAME = unpack_sig + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_sig/unpack_sig_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_sig/unpack_sig_harness.c new file mode 100644 index 0000000000..73adbe557c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_sig/unpack_sig_harness.c @@ -0,0 +1,15 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "packing.h" + + +void harness(void) +{ + uint8_t *c; + uint8_t *sig; + mld_polyveck *h; + mld_polyvecl *z; + int r; + r = mld_unpack_sig(c, z, h, sig); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_sk/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_sk/Makefile new file mode 100644 index 0000000000..feb5b5545c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_sk/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = unpack_sk_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = unpack_sk + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/packing.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)unpack_sk +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvecl_unpack_eta $(MLD_NAMESPACE)polyveck_unpack_eta $(MLD_NAMESPACE)polyveck_unpack_t0 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = unpack_sk + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 9 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_sk/unpack_sk_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_sk/unpack_sk_harness.c new file mode 100644 index 0000000000..0f644de67e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/unpack_sk/unpack_sk_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "packing.h" + + +void harness(void) +{ + uint8_t *a, *b, *c, *d; + mld_polyveck *t0, *s2; + mld_polyvecl *s1; + mld_unpack_sk(a, b, c, t0, s1, s2, d); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/use_hint/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/use_hint/Makefile new file mode 100644 index 0000000000..5f01b0c1e9 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/use_hint/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = use_hint_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = use_hint + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/poly.c + +CHECK_FUNCTION_CONTRACTS=mld_use_hint +USE_FUNCTION_CONTRACTS=mld_decompose +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = use_hint + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/use_hint/use_hint_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/use_hint/use_hint_harness.c new file mode 100644 index 0000000000..0fe55f9297 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/use_hint/use_hint_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "rounding.h" + +void harness(void) +{ + int32_t a, r, hint; + r = mld_use_hint(a, hint); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_i64/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_i64/Makefile new file mode 100644 index 0000000000..0321332a54 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_i64/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = value_barrier_i64_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_value_barrier_i64 + +DEFINES += -DMLD_CONFIG_NO_ASM_VALUE_BARRIER +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/ct.c + +CHECK_FUNCTION_CONTRACTS=mld_value_barrier_i64 +USE_FUNCTION_CONTRACTS=mld_ct_get_optblocker_i64 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_value_barrier_i64 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_i64/value_barrier_i64_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_i64/value_barrier_i64_harness.c new file mode 100644 index 0000000000..977324b485 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_i64/value_barrier_i64_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "ct.h" + +void harness(void) +{ + int64_t a; + mld_value_barrier_i64(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_u32/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_u32/Makefile new file mode 100644 index 0000000000..eed24a9755 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_u32/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = value_barrier_u32_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_value_barrier_u32 + +DEFINES += -DMLD_CONFIG_NO_ASM_VALUE_BARRIER +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/ct.c + +CHECK_FUNCTION_CONTRACTS=mld_value_barrier_u32 +USE_FUNCTION_CONTRACTS=mld_ct_get_optblocker_u32 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_value_barrier_u32 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_u32/value_barrier_u32_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_u32/value_barrier_u32_harness.c new file mode 100644 index 0000000000..2003e5502c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_u32/value_barrier_u32_harness.c @@ -0,0 +1,10 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "ct.h" + +void harness(void) +{ + uint32_t a; + mld_value_barrier_u32(a); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_u8/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_u8/Makefile new file mode 100644 index 0000000000..5336a5b54c --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_u8/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = value_barrier_u8_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = mld_value_barrier_u8 + +DEFINES += -DMLD_CONFIG_NO_ASM_VALUE_BARRIER +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/src/ct.c + +CHECK_FUNCTION_CONTRACTS=mld_value_barrier_u8 +USE_FUNCTION_CONTRACTS=mld_ct_get_optblocker_u8 +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = mld_value_barrier_u8 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_u8/value_barrier_u8_harness.c b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_u8/value_barrier_u8_harness.c new file mode 100644 index 0000000000..bc0962bd25 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/cbmc/value_barrier_u8/value_barrier_u8_harness.c @@ -0,0 +1,11 @@ +// Copyright (c) The mldsa-native project authors +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 AND Apache-2.0 + +#include "ct.h" + +void harness(void) +{ + uint8_t x, y; + y = mld_value_barrier_u8(x); +} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/.gitignore b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/.gitignore new file mode 100644 index 0000000000..a9ad30c491 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/.gitignore @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +**/*.o +**/*.native +**/*.correct diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/README.md new file mode 100644 index 0000000000..1bf064db19 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/README.md @@ -0,0 +1,47 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# HOL Light functional correctness proofs + +This directory contains functional correctness proofs for x86_64 assembly routines +used in mldsa-native. The proofs are written in the [HOL Light](https://hol-light.github.io/) theorem +prover, utilizing the assembly verification infrastructure from [s2n-bignum](https://github.com/awslabs/s2n-bignum). + +Each function is proved in a separate `.ml` file in [x86_64/proofs/](x86_64/proofs). Each file +contains the byte code being verified, as well as the specification that is being proved. + +## Reproducing the proofs + +To reproduce the proofs, enter the nix shell via + +```bash +nix develop .#hol_light --experimental-features 'nix-command flakes' +``` + +from mldsa-native's base directory. Then + +```bash +make -C proofs/hol_light/x86_64 +``` + +will build and run the proofs. Note that this may take hours even on powerful machines. + +## Interactive proof development + +For interactive proof development, start the HOL Light server: + +```bash +hol-server [port] # default port is 2012 +``` + +Then use the [HOL Light extension for VS Code](https://marketplace.visualstudio.com/items?itemName=monadius.hol-light-simple) +to connect and send commands interactively. + +Alternatively, send commands using netcat: + +```bash +echo '1+1;;' | nc -w 5 127.0.0.1 2012 +``` + +## What is covered? + +- x86_64 forward NTT: [mldsa_ntt.S](x86_64/mldsa/mldsa_ntt.S) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/Makefile b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/Makefile new file mode 100644 index 0000000000..5b201e2f74 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/Makefile @@ -0,0 +1,124 @@ +############################################################################# +# Copyright (c) The mldsa-native project authors +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 +############################################################################# + +# +# This Makefile is derived from the Makefile x86/Makefile in s2n-bignum. +# - Remove all s2n-bignum proofs and tutorial, add mldsa-native proofs +# - Minor path modifications to support base theories from s2n-bignum +# to reside in a separate read-only directory +# + +.DEFAULT_GOAL := run_proofs + +OSTYPE_RESULT=$(shell uname -s) +ARCHTYPE_RESULT=$(shell uname -m) + +SRC ?= $(S2N_BIGNUM_DIR) +SRC_X86 ?= $(SRC)/x86 + +# If actually on an x86_64 machine, just use the assembler (as). Otherwise +# use a cross-assembling version so that the code can still be assembled +# and the proofs checked against the object files (though you won't be able +# to run code without additional emulation infrastructure). +ifeq ($(filter $(ARCHTYPE_RESULT),x86_64),) +CROSS_PREFIX=x86_64-unknown-linux-gnu- +ifeq ($(shell command -v $(ASSEMBLE) >/dev/null 2>&1 && echo yes || echo no),no) +$(error Cross-toolchain not found. Please run in the 'hol_light-cross-x86_64' nix shell via: nix develop .#hol_light-cross-x86_64) +endif +endif +ASSEMBLE=$(CROSS_PREFIX)as $(ARCHFLAGS) +OBJDUMP=$(CROSS_PREFIX)objdump -d + +# Add explicit language input parameter to cpp, otherwise the use of #n for +# numeric literals in x86 code is a problem when used inside #define macros +# since normally that means stringization. +# +# Some clang-based preprocessors seem to behave differently, and get confused +# by single-quote characters in comments, so we eliminate // comments first. + +ifeq ($(OSTYPE_RESULT),Darwin) +PREPROCESS=sed -e 's/\/\/.*//' | $(CC) -E -xassembler-with-cpp - +else +PREPROCESS=$(CC) -E -xassembler-with-cpp - +endif + +# Generally GNU-type assemblers are happy with multiple instructions on +# a line, but we split them up anyway just in case. + +SPLIT=tr ';' '\n' + +OBJ = mldsa/mldsa_ntt.o + +# Build object files from assembly sources +$(OBJ): %.o : %.S + @echo "Preparing $@ ..." + @echo "AS: `$(ASSEMBLE) --version`" + @echo "OBJDUMP: `$(OBJDUMP) --version`" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + cat $< | $(PREPROCESS) | $(SPLIT) | $(ASSEMBLE) -o $@ - + # MacOS may generate relocations in non-text sections that break + # the object file parser in HOL-Light + strip $@ + +clean:; rm -f */*.o */*/*.o */*.correct */*.native + +# Proof-related parts +# +# The proof files are all independent, though each one loads the +# same common infrastructure "base.ml". So you can potentially +# run the proofs in parallel for more speed, e.g. +# +# nohup make -j 16 proofs & +# +# If you build hol-light yourself (see https://github.com/jrh13/hol-light) +# in your home directory, and do "make" inside the subdirectory hol-light, +# then the following HOLDIR setting should be right: + +HOLDIR?=$(HOLLIGHTDIR) +HOLLIGHT:=$(HOLDIR)/hol.sh + +BASE?=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) + +PROOF_BINS = $(OBJ:.o=.native) +PROOF_LOGS = $(OBJ:.o=.correct) + +# Build precompiled binary for dumping bytecodes +proofs/dump_bytecode.native: proofs/dump_bytecode.ml $(OBJ) + ./proofs/build-proof.sh $(BASE)/$< "$(HOLLIGHT)" "$@" + +# Build precompiled native binaries of HOL Light proofs + +.SECONDEXPANSION: +%.native: proofs/$$(*F).ml %.o ; ./proofs/build-proof.sh $(BASE)/$< "$(HOLLIGHT)" "$@" + +# Run them and print the standard output+error at *.correct +%.correct: %.native + $< 2>&1 | tee $@ + @if (grep -i "error:\|exception:" "$@" >/dev/null); then \ + echo "$< had errors!"; \ + exit 1; \ + else \ + echo "$< OK"; \ + fi + +build_proofs: $(PROOF_BINS); +run_proofs: build_proofs $(PROOF_LOGS); + +proofs: run_proofs ; $(SRC)/tools/count-proofs.sh . + +dump_bytecode: proofs/dump_bytecode.native + ./$< + +.PHONY: proofs build_proofs run_proofs sematest clean dump_bytecode + +# Always run sematest regardless of dependency check +FORCE: ; +# Always use max. # of cores because in Makefile one cannot get the passed number of -j. +# A portable way of getting the number of max. cores: +# https://stackoverflow.com/a/23569003/1488216 +NUM_CORES_FOR_SEMATEST = $(shell getconf _NPROCESSORS_ONLN) +sematest: FORCE $(OBJ) $(SRC_X86)/proofs/simulator_iclasses.ml $(SRC_X86)/proofs/simulator.native + $(SRC)/tools/run-sematest.sh x86 $(NUM_CORES_FOR_SEMATEST) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/README.md b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/README.md new file mode 100644 index 0000000000..861e4a3aa6 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/README.md @@ -0,0 +1,108 @@ +[//]: # (SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0) + +# HOL Light functional correctness proofs + +This directory contains functional correctness proofs for some of the x86_64 assembly routines +used in mldsa-native. The proofs were largely developed by John Harrison and Jake Massimo, +and are written in the [HOL Light](https://hol-light.github.io/) theorem +prover, utilizing the assembly verification infrastructure from [s2n-bignum](https://github.com/awslabs/s2n-bignum). + +Each function is proved in a separate `.ml` file in [proofs/](proofs). Each file +contains the byte code being verified, as well as the specification that is being +proved. + +## Primer + +Proofs are 'post-hoc' in the sense that HOL-Light/s2n-bignum operate on the final object code. In particular, the means by which the code was generated need not be trusted. + +Specifications are essentially [Hoare triples](https://en.wikipedia.org/wiki/Hoare_logic), with the noteworthy difference that the program is implicit as the content of memory at the PC; which is asserted to +be the code under verification as part of the precondition. For example, the following is the specification of the `mldsa_ntt` function: + +```ocaml + (* For all (abbreviated by `!` in HOL): + - a: Polynomial coefficients pointer + - zetas: NTT constants pointer + - x: Original polynomial coefficients + - pc: Current value of Program Counter (PC) + - stackpointer: Stack pointer + - returnaddress: Return address on the stack *) +`!a zetas x pc stackpointer returnaddress. + (* Alignment and non-overlapping requirements *) + aligned 32 a /\ + aligned 32 zetas /\ + nonoverlapping (word pc,LENGTH mldsa_ntt_mc) (a, 1024) /\ + nonoverlapping (word pc,LENGTH mldsa_ntt_mc) (zetas, 2496) /\ + nonoverlapping (a, 1024) (zetas, 2496) /\ + nonoverlapping (stackpointer,8) (a, 1024) /\ + nonoverlapping (stackpointer,8) (zetas, 2496) + ==> ensures x86 + (* Precondition *) + (\s. (* The memory at the current PC is the byte-code of mldsa_ntt() *) + bytes_loaded s (word pc) mldsa_ntt_mc /\ + read RIP s = word pc /\ + read RSP s = stackpointer /\ + (* The return address is on the stack *) + read (memory :> bytes64 stackpointer) s = returnaddress /\ + (* Arguments are passed via C calling convention *) + C_ARGUMENTS [a; zetas] s /\ + (* NTT constants are properly loaded *) + wordlist_from_memory(zetas,624) s = MAP (iword: int -> 32 word) mldsa_complete_qdata /\ + (* Input bounds checking *) + (!i. i < 256 ==> abs(ival(x i)) <= &8380416) /\ + (* Give a name to the memory contents at the source pointer *) + !i. i < 256 + ==> read(memory :> bytes32(word_add a (word(4 * i)))) s = x i) + (* Postcondition: Eventually we reach a state where ... *) + (\s. + (* The PC is the return address *) + read RIP s = returnaddress /\ + (* Stack pointer is adjusted *) + read RSP s = word_add stackpointer (word 8) /\ + (* The integers represented by the final memory contents + * are congruent to the ML-DSA forward NTT transformation + * of the original coefficients, modulo 8380417, with proper bounds *) + !i. i < 256 + ==> let zi = read(memory :> bytes32(word_add a (word(4 * i)))) s in + (ival zi == mldsa_forward_ntt (ival o x) i) (mod &8380417) /\ + abs(ival zi) <= &42035261) + (* Footprint: The program may modify (only) the ABI permitted registers + * and flags, stack pointer, and the memory contents at the source pointer. *) + (MAYCHANGE [RSP] ,, MAYCHANGE_REGS_AND_FLAGS_PERMITTED_BY_ABI ,, + MAYCHANGE [memory :> bytes(a,1024)])` +``` + +## Platform Compatibility + +These x86_64 assembly proofs are expected to work on the following platforms: + +- **Linux x86_64**: Fully supported (native build and execution) +- **Linux AArch64**: Not currently supported. Requires x86_64 cross-compilation tools (`x86_64-linux-gnu-as` and `x86_64-linux-gnu-objdump`). +- **macOS x86_64**: Fully supported (native build and execution) +- **macOS ARM (Apple Silicon)**: Not currently supported. Differences in assembler behavior between clang-based (macOS) and gcc-based (Linux) toolchains can cause verification mismatches, particularly with regard to argument ordering optimizations for commutative instructions. + +## Reproducing the proofs + +To reproduce the proofs, enter the nix shell via + +```bash +nix develop --experimental-features 'nix-command flakes' +``` + +from mldsa-native's base directory. Then + +```bash +make -C proofs/hol_light/x86_64 +``` + +will build and run the proofs. Note that this make take hours even on powerful machines. + +For convenience, you can also use `tests hol_light` which wraps the `make` invocation above; see `tests hol_light --help`. + +## What is covered? + +Currently this includes: + +- ML-DSA Arithmetic: + * x86_64 forward NTT: [mldsa_ntt.S](mldsa/mldsa_ntt.S) + +The NTT function is optimized using AVX2 instructions and follows the s2n-bignum x86_64 assembly verification patterns. diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/list_proofs.sh b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/list_proofs.sh new file mode 100755 index 0000000000..45493f0595 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/list_proofs.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +# +# This tiny script just lists the names of source files for which +# we have a spec and proof in HOL-Light. + +ROOT=$(git rev-parse --show-toplevel) +cd $ROOT +ls -1 proofs/hol_light/x86_64/mldsa/*.S | cut -d '/' -f 5 | sed 's/\.S//' diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/build-proof.sh b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/build-proof.sh new file mode 100755 index 0000000000..3536b30cc2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/build-proof.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +# +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 +# + +# +# Compile proof script into executable binary +# + +# This file is derived from s2n-bignum's tools/build-proof.sh +# Notable changes: +# - Modify HOL-Light's inline_load.ml to allow for a 3rd include path, +# in addition to S2N_BIGNUM_DIR and HOLLIGHT_DIR +# - Removal of s2n-bignum specific code that is not relevant for +# the mldsa-native proofs. + +ROOT="$(realpath "$(dirname "$0")"/../)" + +if [ "$#" -ne 3 ]; then + echo "${ROOT}/build-proof.sh <.ml file path> " + echo "This script builds HOL Light proof using OCaml native compiler and puts the " + echo "output binary at ." + exit 1 +fi + +# Return the exit code if any statement fails +set -e + +ml_path="$1" +hol_sh_cmd=$2 +output_path=$3 +output_dir=$(dirname "$output_path") +[ -d "$output_dir" ] || mkdir -p "$output_dir" + +export HOLLIGHT_DIR="$(dirname ${hol_sh_cmd})" +if [ ! -f "${HOLLIGHT_DIR}/hol_lib.cmxa" ]; then + echo "hol_lib.cmxa does not exist in HOLLIGHT_DIR('${HOLLIGHT_DIR}')." + echo "Did you compile HOL Light with HOLLIGHT_USE_MODULE set to 1?" + exit 1 +fi + +template_ml="$(mktemp).ml" +echo "Generating a template .ml that loads the file...: ${template_ml}" + +( + echo 'let proof_start_time = Unix.time();;' + echo "loadt \"${ml_path}\";;" + echo "check_axioms ();;" + echo 'let proof_end_time = Unix.time();;' + echo 'Printf.printf "Running time: %f sec, Start unixtime: %f, End unixtime: %f\n" (proof_end_time -. proof_start_time) proof_start_time proof_end_time;;' +) >>${template_ml} + +inlined_prefix="$(mktemp)" +inlined_ml="${inlined_prefix}.ml" +inlined_cmx="${inlined_prefix}.cmx" +(cd "${S2N_BIGNUM_DIR}" && HOLLIGHT_LOAD_PATH=${ROOT} ocaml ${HOLLIGHT_DIR}/inline_load.ml "${template_ml}" "${inlined_ml}") + +# Give a large stack size. +OCAMLRUNPARAM=l=2000000000 \ + ocamlopt.byte -pp "$(${hol_sh_cmd} -pp)" -I "${HOLLIGHT_DIR}" -I +unix -c \ + hol_lib.cmxa ${inlined_ml} -o ${inlined_cmx} -w -a +ocamlfind ocamlopt -package zarith,unix -linkpkg hol_lib.cmxa \ + -I "${HOLLIGHT_DIR}" ${inlined_cmx} \ + -o "${output_path}" + +# Remove the intermediate files to save disk space +rm -f ${inlined_cmx} ${template_ml} ${inlined_ml} diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/dump_bytecode.ml b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/dump_bytecode.ml new file mode 100644 index 0000000000..c7e1b8ac3b --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/dump_bytecode.ml @@ -0,0 +1,10 @@ +(* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 + *) + +needs "x86/proofs/base.ml";; + +print_string "=== bytecode start: mldsa/mldsa_ntt.o ================\n";; +print_literal_from_elf "mldsa/mldsa_ntt.o";; +print_string "==== bytecode end =====================================\n\n";; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/mldsa_ntt.ml b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/mldsa_ntt.ml new file mode 100644 index 0000000000..5ce1fd98b2 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/mldsa_ntt.ml @@ -0,0 +1,4619 @@ +(* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 + *) + +(* ========================================================================= *) +(* ML-DSA Forward number theoretic transform. *) +(* ========================================================================= *) + +needs "x86/proofs/base.ml";; +needs "proofs/mldsa_specs.ml";; +needs "proofs/mldsa_utils.ml";; +needs "proofs/mldsa_zetas.ml";; + +(*** print_literal_from_elf "mldsa/mldsa_ntt.o";; + ***) + +let mldsa_ntt_mc = define_assert_from_elf "mldsa_ntt_mc" "mldsa/mldsa_ntt.o" +(*** BYTECODE START ***) +[ + 0xf3; 0x0f; 0x1e; 0xfa; (* ENDBR64 *) + 0xc5; 0xfd; 0x6f; 0x06; (* VMOVDQA (%_% ymm0) (Memop Word256 (%% (rsi,0))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x8e; 0x84; 0x00; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm1) (Memop Doubleword (%% (rsi,132))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x96; 0x24; 0x05; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm2) (Memop Doubleword (%% (rsi,1316))) *) + 0xc5; 0xfd; 0x6f; 0x27; (* VMOVDQA (%_% ymm4) (Memop Word256 (%% (rdi,0))) *) + 0xc5; 0xfd; 0x6f; 0xaf; 0x80; 0x00; 0x00; 0x00; + (* VMOVDQA (%_% ymm5) (Memop Word256 (%% (rdi,128))) *) + 0xc5; 0xfd; 0x6f; 0xb7; 0x00; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm6) (Memop Word256 (%% (rdi,256))) *) + 0xc5; 0xfd; 0x6f; 0xbf; 0x80; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm7) (Memop Word256 (%% (rdi,384))) *) + 0xc5; 0x7d; 0x6f; 0x87; 0x00; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm8) (Memop Word256 (%% (rdi,512))) *) + 0xc5; 0x7d; 0x6f; 0x8f; 0x80; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm9) (Memop Word256 (%% (rdi,640))) *) + 0xc5; 0x7d; 0x6f; 0x97; 0x00; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm10) (Memop Word256 (%% (rdi,768))) *) + 0xc5; 0x7d; 0x6f; 0x9f; 0x80; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm11) (Memop Word256 (%% (rdi,896))) *) + 0xc4; 0x62; 0x3d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm8) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe0; + (* VMOVSHDUP (%_% ymm12) (%_% ymm8) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x3d; 0x28; 0xc2; + (* VPMULDQ (%_% ymm8) (%_% ymm8) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc0; + (* VMOVSHDUP (%_% ymm8) (%_% ymm8) *) + 0xc4; 0x43; 0x3d; 0x02; 0xc4; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm8) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x5d; 0xfa; 0xe0; + (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm8) *) + 0xc5; 0xbd; 0xfe; 0xe4; (* VPADDD (%_% ymm4) (%_% ymm8) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xc5; + (* VPADDD (%_% ymm8) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc4; 0x62; 0x35; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm9) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe1; + (* VMOVSHDUP (%_% ymm12) (%_% ymm9) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x35; 0x28; 0xca; + (* VPMULDQ (%_% ymm9) (%_% ymm9) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc9; + (* VMOVSHDUP (%_% ymm9) (%_% ymm9) *) + 0xc4; 0x43; 0x35; 0x02; 0xcc; 0xaa; + (* VPBLENDD (%_% ymm9) (%_% ymm9) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x55; 0xfa; 0xe1; + (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm9) *) + 0xc5; 0xb5; 0xfe; 0xed; (* VPADDD (%_% ymm5) (%_% ymm9) (%_% ymm5) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xcd; + (* VPADDD (%_% ymm9) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0x62; 0x2d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm10) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe2; + (* VMOVSHDUP (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x2d; 0x28; 0xd2; + (* VPMULDQ (%_% ymm10) (%_% ymm10) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xd2; + (* VMOVSHDUP (%_% ymm10) (%_% ymm10) *) + 0xc4; 0x43; 0x2d; 0x02; 0xd4; 0xaa; + (* VPBLENDD (%_% ymm10) (%_% ymm10) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x4d; 0xfa; 0xe2; + (* VPSUBD (%_% ymm12) (%_% ymm6) (%_% ymm10) *) + 0xc5; 0xad; 0xfe; 0xf6; (* VPADDD (%_% ymm6) (%_% ymm10) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xd5; + (* VPADDD (%_% ymm10) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x4d; 0xfa; 0xf5; + (* VPSUBD (%_% ymm6) (%_% ymm6) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x45; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xff; (* VPADDD (%_% ymm7) (%_% ymm11) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x8e; 0x88; 0x00; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm1) (Memop Doubleword (%% (rsi,136))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x96; 0x28; 0x05; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm2) (Memop Doubleword (%% (rsi,1320))) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x5d; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm6) *) + 0xc5; 0xdd; 0xfe; 0xe6; (* VPADDD (%_% ymm4) (%_% ymm4) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc4; 0x62; 0x45; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm7) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe7; (* VMOVSHDUP (%_% ymm12) (%_% ymm7) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x45; 0x28; 0xfa; + (* VPMULDQ (%_% ymm7) (%_% ymm7) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xff; (* VMOVSHDUP (%_% ymm7) (%_% ymm7) *) + 0xc4; 0xc3; 0x45; 0x02; 0xfc; 0xaa; + (* VPBLENDD (%_% ymm7) (%_% ymm7) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x55; 0xfa; 0xe7; (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm7) *) + 0xc5; 0xd5; 0xfe; 0xef; (* VPADDD (%_% ymm5) (%_% ymm5) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xfd; + (* VPADDD (%_% ymm7) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x8e; 0x8c; 0x00; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm1) (Memop Doubleword (%% (rsi,140))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x96; 0x2c; 0x05; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm2) (Memop Doubleword (%% (rsi,1324))) *) + 0xc4; 0x62; 0x2d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm10) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe2; + (* VMOVSHDUP (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x2d; 0x28; 0xd2; + (* VPMULDQ (%_% ymm10) (%_% ymm10) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xd2; + (* VMOVSHDUP (%_% ymm10) (%_% ymm10) *) + 0xc4; 0x43; 0x2d; 0x02; 0xd4; 0xaa; + (* VPBLENDD (%_% ymm10) (%_% ymm10) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xe2; + (* VPSUBD (%_% ymm12) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x3d; 0xfe; 0xc2; + (* VPADDD (%_% ymm8) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xd5; + (* VPADDD (%_% ymm10) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xc5; + (* VPSUBD (%_% ymm8) (%_% ymm8) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x35; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x35; 0xfe; 0xcb; + (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc5; 0xfd; 0x7f; 0x27; (* VMOVDQA (Memop Word256 (%% (rdi,0))) (%_% ymm4) *) + 0xc5; 0xfd; 0x7f; 0xaf; 0x80; 0x00; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,128))) (%_% ymm5) *) + 0xc5; 0xfd; 0x7f; 0xb7; 0x00; 0x01; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,256))) (%_% ymm6) *) + 0xc5; 0xfd; 0x7f; 0xbf; 0x80; 0x01; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,384))) (%_% ymm7) *) + 0xc5; 0x7d; 0x7f; 0x87; 0x00; 0x02; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,512))) (%_% ymm8) *) + 0xc5; 0x7d; 0x7f; 0x8f; 0x80; 0x02; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,640))) (%_% ymm9) *) + 0xc5; 0x7d; 0x7f; 0x97; 0x00; 0x03; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,768))) (%_% ymm10) *) + 0xc5; 0x7d; 0x7f; 0x9f; 0x80; 0x03; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,896))) (%_% ymm11) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x8e; 0x84; 0x00; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm1) (Memop Doubleword (%% (rsi,132))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x96; 0x24; 0x05; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm2) (Memop Doubleword (%% (rsi,1316))) *) + 0xc5; 0xfd; 0x6f; 0x67; 0x20; + (* VMOVDQA (%_% ymm4) (Memop Word256 (%% (rdi,32))) *) + 0xc5; 0xfd; 0x6f; 0xaf; 0xa0; 0x00; 0x00; 0x00; + (* VMOVDQA (%_% ymm5) (Memop Word256 (%% (rdi,160))) *) + 0xc5; 0xfd; 0x6f; 0xb7; 0x20; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm6) (Memop Word256 (%% (rdi,288))) *) + 0xc5; 0xfd; 0x6f; 0xbf; 0xa0; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm7) (Memop Word256 (%% (rdi,416))) *) + 0xc5; 0x7d; 0x6f; 0x87; 0x20; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm8) (Memop Word256 (%% (rdi,544))) *) + 0xc5; 0x7d; 0x6f; 0x8f; 0xa0; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm9) (Memop Word256 (%% (rdi,672))) *) + 0xc5; 0x7d; 0x6f; 0x97; 0x20; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm10) (Memop Word256 (%% (rdi,800))) *) + 0xc5; 0x7d; 0x6f; 0x9f; 0xa0; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm11) (Memop Word256 (%% (rdi,928))) *) + 0xc4; 0x62; 0x3d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm8) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe0; + (* VMOVSHDUP (%_% ymm12) (%_% ymm8) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x3d; 0x28; 0xc2; + (* VPMULDQ (%_% ymm8) (%_% ymm8) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc0; + (* VMOVSHDUP (%_% ymm8) (%_% ymm8) *) + 0xc4; 0x43; 0x3d; 0x02; 0xc4; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm8) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x5d; 0xfa; 0xe0; + (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm8) *) + 0xc5; 0xbd; 0xfe; 0xe4; (* VPADDD (%_% ymm4) (%_% ymm8) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xc5; + (* VPADDD (%_% ymm8) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc4; 0x62; 0x35; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm9) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe1; + (* VMOVSHDUP (%_% ymm12) (%_% ymm9) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x35; 0x28; 0xca; + (* VPMULDQ (%_% ymm9) (%_% ymm9) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc9; + (* VMOVSHDUP (%_% ymm9) (%_% ymm9) *) + 0xc4; 0x43; 0x35; 0x02; 0xcc; 0xaa; + (* VPBLENDD (%_% ymm9) (%_% ymm9) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x55; 0xfa; 0xe1; + (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm9) *) + 0xc5; 0xb5; 0xfe; 0xed; (* VPADDD (%_% ymm5) (%_% ymm9) (%_% ymm5) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xcd; + (* VPADDD (%_% ymm9) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0x62; 0x2d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm10) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe2; + (* VMOVSHDUP (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x2d; 0x28; 0xd2; + (* VPMULDQ (%_% ymm10) (%_% ymm10) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xd2; + (* VMOVSHDUP (%_% ymm10) (%_% ymm10) *) + 0xc4; 0x43; 0x2d; 0x02; 0xd4; 0xaa; + (* VPBLENDD (%_% ymm10) (%_% ymm10) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x4d; 0xfa; 0xe2; + (* VPSUBD (%_% ymm12) (%_% ymm6) (%_% ymm10) *) + 0xc5; 0xad; 0xfe; 0xf6; (* VPADDD (%_% ymm6) (%_% ymm10) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xd5; + (* VPADDD (%_% ymm10) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x4d; 0xfa; 0xf5; + (* VPSUBD (%_% ymm6) (%_% ymm6) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x45; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xff; (* VPADDD (%_% ymm7) (%_% ymm11) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x8e; 0x88; 0x00; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm1) (Memop Doubleword (%% (rsi,136))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x96; 0x28; 0x05; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm2) (Memop Doubleword (%% (rsi,1320))) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x5d; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm6) *) + 0xc5; 0xdd; 0xfe; 0xe6; (* VPADDD (%_% ymm4) (%_% ymm4) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc4; 0x62; 0x45; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm7) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe7; (* VMOVSHDUP (%_% ymm12) (%_% ymm7) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x45; 0x28; 0xfa; + (* VPMULDQ (%_% ymm7) (%_% ymm7) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xff; (* VMOVSHDUP (%_% ymm7) (%_% ymm7) *) + 0xc4; 0xc3; 0x45; 0x02; 0xfc; 0xaa; + (* VPBLENDD (%_% ymm7) (%_% ymm7) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x55; 0xfa; 0xe7; (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm7) *) + 0xc5; 0xd5; 0xfe; 0xef; (* VPADDD (%_% ymm5) (%_% ymm5) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xfd; + (* VPADDD (%_% ymm7) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x8e; 0x8c; 0x00; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm1) (Memop Doubleword (%% (rsi,140))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x96; 0x2c; 0x05; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm2) (Memop Doubleword (%% (rsi,1324))) *) + 0xc4; 0x62; 0x2d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm10) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe2; + (* VMOVSHDUP (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x2d; 0x28; 0xd2; + (* VPMULDQ (%_% ymm10) (%_% ymm10) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xd2; + (* VMOVSHDUP (%_% ymm10) (%_% ymm10) *) + 0xc4; 0x43; 0x2d; 0x02; 0xd4; 0xaa; + (* VPBLENDD (%_% ymm10) (%_% ymm10) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xe2; + (* VPSUBD (%_% ymm12) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x3d; 0xfe; 0xc2; + (* VPADDD (%_% ymm8) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xd5; + (* VPADDD (%_% ymm10) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xc5; + (* VPSUBD (%_% ymm8) (%_% ymm8) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x35; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x35; 0xfe; 0xcb; + (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc5; 0xfd; 0x7f; 0x67; 0x20; + (* VMOVDQA (Memop Word256 (%% (rdi,32))) (%_% ymm4) *) + 0xc5; 0xfd; 0x7f; 0xaf; 0xa0; 0x00; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,160))) (%_% ymm5) *) + 0xc5; 0xfd; 0x7f; 0xb7; 0x20; 0x01; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,288))) (%_% ymm6) *) + 0xc5; 0xfd; 0x7f; 0xbf; 0xa0; 0x01; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,416))) (%_% ymm7) *) + 0xc5; 0x7d; 0x7f; 0x87; 0x20; 0x02; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,544))) (%_% ymm8) *) + 0xc5; 0x7d; 0x7f; 0x8f; 0xa0; 0x02; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,672))) (%_% ymm9) *) + 0xc5; 0x7d; 0x7f; 0x97; 0x20; 0x03; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,800))) (%_% ymm10) *) + 0xc5; 0x7d; 0x7f; 0x9f; 0xa0; 0x03; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,928))) (%_% ymm11) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x8e; 0x84; 0x00; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm1) (Memop Doubleword (%% (rsi,132))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x96; 0x24; 0x05; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm2) (Memop Doubleword (%% (rsi,1316))) *) + 0xc5; 0xfd; 0x6f; 0x67; 0x40; + (* VMOVDQA (%_% ymm4) (Memop Word256 (%% (rdi,64))) *) + 0xc5; 0xfd; 0x6f; 0xaf; 0xc0; 0x00; 0x00; 0x00; + (* VMOVDQA (%_% ymm5) (Memop Word256 (%% (rdi,192))) *) + 0xc5; 0xfd; 0x6f; 0xb7; 0x40; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm6) (Memop Word256 (%% (rdi,320))) *) + 0xc5; 0xfd; 0x6f; 0xbf; 0xc0; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm7) (Memop Word256 (%% (rdi,448))) *) + 0xc5; 0x7d; 0x6f; 0x87; 0x40; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm8) (Memop Word256 (%% (rdi,576))) *) + 0xc5; 0x7d; 0x6f; 0x8f; 0xc0; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm9) (Memop Word256 (%% (rdi,704))) *) + 0xc5; 0x7d; 0x6f; 0x97; 0x40; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm10) (Memop Word256 (%% (rdi,832))) *) + 0xc5; 0x7d; 0x6f; 0x9f; 0xc0; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm11) (Memop Word256 (%% (rdi,960))) *) + 0xc4; 0x62; 0x3d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm8) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe0; + (* VMOVSHDUP (%_% ymm12) (%_% ymm8) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x3d; 0x28; 0xc2; + (* VPMULDQ (%_% ymm8) (%_% ymm8) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc0; + (* VMOVSHDUP (%_% ymm8) (%_% ymm8) *) + 0xc4; 0x43; 0x3d; 0x02; 0xc4; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm8) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x5d; 0xfa; 0xe0; + (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm8) *) + 0xc5; 0xbd; 0xfe; 0xe4; (* VPADDD (%_% ymm4) (%_% ymm8) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xc5; + (* VPADDD (%_% ymm8) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc4; 0x62; 0x35; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm9) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe1; + (* VMOVSHDUP (%_% ymm12) (%_% ymm9) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x35; 0x28; 0xca; + (* VPMULDQ (%_% ymm9) (%_% ymm9) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc9; + (* VMOVSHDUP (%_% ymm9) (%_% ymm9) *) + 0xc4; 0x43; 0x35; 0x02; 0xcc; 0xaa; + (* VPBLENDD (%_% ymm9) (%_% ymm9) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x55; 0xfa; 0xe1; + (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm9) *) + 0xc5; 0xb5; 0xfe; 0xed; (* VPADDD (%_% ymm5) (%_% ymm9) (%_% ymm5) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xcd; + (* VPADDD (%_% ymm9) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0x62; 0x2d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm10) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe2; + (* VMOVSHDUP (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x2d; 0x28; 0xd2; + (* VPMULDQ (%_% ymm10) (%_% ymm10) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xd2; + (* VMOVSHDUP (%_% ymm10) (%_% ymm10) *) + 0xc4; 0x43; 0x2d; 0x02; 0xd4; 0xaa; + (* VPBLENDD (%_% ymm10) (%_% ymm10) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x4d; 0xfa; 0xe2; + (* VPSUBD (%_% ymm12) (%_% ymm6) (%_% ymm10) *) + 0xc5; 0xad; 0xfe; 0xf6; (* VPADDD (%_% ymm6) (%_% ymm10) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xd5; + (* VPADDD (%_% ymm10) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x4d; 0xfa; 0xf5; + (* VPSUBD (%_% ymm6) (%_% ymm6) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x45; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xff; (* VPADDD (%_% ymm7) (%_% ymm11) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x8e; 0x88; 0x00; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm1) (Memop Doubleword (%% (rsi,136))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x96; 0x28; 0x05; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm2) (Memop Doubleword (%% (rsi,1320))) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x5d; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm6) *) + 0xc5; 0xdd; 0xfe; 0xe6; (* VPADDD (%_% ymm4) (%_% ymm4) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc4; 0x62; 0x45; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm7) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe7; (* VMOVSHDUP (%_% ymm12) (%_% ymm7) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x45; 0x28; 0xfa; + (* VPMULDQ (%_% ymm7) (%_% ymm7) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xff; (* VMOVSHDUP (%_% ymm7) (%_% ymm7) *) + 0xc4; 0xc3; 0x45; 0x02; 0xfc; 0xaa; + (* VPBLENDD (%_% ymm7) (%_% ymm7) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x55; 0xfa; 0xe7; (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm7) *) + 0xc5; 0xd5; 0xfe; 0xef; (* VPADDD (%_% ymm5) (%_% ymm5) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xfd; + (* VPADDD (%_% ymm7) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x8e; 0x8c; 0x00; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm1) (Memop Doubleword (%% (rsi,140))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x96; 0x2c; 0x05; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm2) (Memop Doubleword (%% (rsi,1324))) *) + 0xc4; 0x62; 0x2d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm10) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe2; + (* VMOVSHDUP (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x2d; 0x28; 0xd2; + (* VPMULDQ (%_% ymm10) (%_% ymm10) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xd2; + (* VMOVSHDUP (%_% ymm10) (%_% ymm10) *) + 0xc4; 0x43; 0x2d; 0x02; 0xd4; 0xaa; + (* VPBLENDD (%_% ymm10) (%_% ymm10) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xe2; + (* VPSUBD (%_% ymm12) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x3d; 0xfe; 0xc2; + (* VPADDD (%_% ymm8) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xd5; + (* VPADDD (%_% ymm10) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xc5; + (* VPSUBD (%_% ymm8) (%_% ymm8) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x35; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x35; 0xfe; 0xcb; + (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc5; 0xfd; 0x7f; 0x67; 0x40; + (* VMOVDQA (Memop Word256 (%% (rdi,64))) (%_% ymm4) *) + 0xc5; 0xfd; 0x7f; 0xaf; 0xc0; 0x00; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,192))) (%_% ymm5) *) + 0xc5; 0xfd; 0x7f; 0xb7; 0x40; 0x01; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,320))) (%_% ymm6) *) + 0xc5; 0xfd; 0x7f; 0xbf; 0xc0; 0x01; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,448))) (%_% ymm7) *) + 0xc5; 0x7d; 0x7f; 0x87; 0x40; 0x02; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,576))) (%_% ymm8) *) + 0xc5; 0x7d; 0x7f; 0x8f; 0xc0; 0x02; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,704))) (%_% ymm9) *) + 0xc5; 0x7d; 0x7f; 0x97; 0x40; 0x03; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,832))) (%_% ymm10) *) + 0xc5; 0x7d; 0x7f; 0x9f; 0xc0; 0x03; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,960))) (%_% ymm11) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x8e; 0x84; 0x00; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm1) (Memop Doubleword (%% (rsi,132))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x96; 0x24; 0x05; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm2) (Memop Doubleword (%% (rsi,1316))) *) + 0xc5; 0xfd; 0x6f; 0x67; 0x60; + (* VMOVDQA (%_% ymm4) (Memop Word256 (%% (rdi,96))) *) + 0xc5; 0xfd; 0x6f; 0xaf; 0xe0; 0x00; 0x00; 0x00; + (* VMOVDQA (%_% ymm5) (Memop Word256 (%% (rdi,224))) *) + 0xc5; 0xfd; 0x6f; 0xb7; 0x60; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm6) (Memop Word256 (%% (rdi,352))) *) + 0xc5; 0xfd; 0x6f; 0xbf; 0xe0; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm7) (Memop Word256 (%% (rdi,480))) *) + 0xc5; 0x7d; 0x6f; 0x87; 0x60; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm8) (Memop Word256 (%% (rdi,608))) *) + 0xc5; 0x7d; 0x6f; 0x8f; 0xe0; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm9) (Memop Word256 (%% (rdi,736))) *) + 0xc5; 0x7d; 0x6f; 0x97; 0x60; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm10) (Memop Word256 (%% (rdi,864))) *) + 0xc5; 0x7d; 0x6f; 0x9f; 0xe0; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm11) (Memop Word256 (%% (rdi,992))) *) + 0xc4; 0x62; 0x3d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm8) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe0; + (* VMOVSHDUP (%_% ymm12) (%_% ymm8) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x3d; 0x28; 0xc2; + (* VPMULDQ (%_% ymm8) (%_% ymm8) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc0; + (* VMOVSHDUP (%_% ymm8) (%_% ymm8) *) + 0xc4; 0x43; 0x3d; 0x02; 0xc4; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm8) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x5d; 0xfa; 0xe0; + (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm8) *) + 0xc5; 0xbd; 0xfe; 0xe4; (* VPADDD (%_% ymm4) (%_% ymm8) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xc5; + (* VPADDD (%_% ymm8) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc4; 0x62; 0x35; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm9) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe1; + (* VMOVSHDUP (%_% ymm12) (%_% ymm9) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x35; 0x28; 0xca; + (* VPMULDQ (%_% ymm9) (%_% ymm9) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc9; + (* VMOVSHDUP (%_% ymm9) (%_% ymm9) *) + 0xc4; 0x43; 0x35; 0x02; 0xcc; 0xaa; + (* VPBLENDD (%_% ymm9) (%_% ymm9) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x55; 0xfa; 0xe1; + (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm9) *) + 0xc5; 0xb5; 0xfe; 0xed; (* VPADDD (%_% ymm5) (%_% ymm9) (%_% ymm5) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xcd; + (* VPADDD (%_% ymm9) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0x62; 0x2d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm10) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe2; + (* VMOVSHDUP (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x2d; 0x28; 0xd2; + (* VPMULDQ (%_% ymm10) (%_% ymm10) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xd2; + (* VMOVSHDUP (%_% ymm10) (%_% ymm10) *) + 0xc4; 0x43; 0x2d; 0x02; 0xd4; 0xaa; + (* VPBLENDD (%_% ymm10) (%_% ymm10) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x4d; 0xfa; 0xe2; + (* VPSUBD (%_% ymm12) (%_% ymm6) (%_% ymm10) *) + 0xc5; 0xad; 0xfe; 0xf6; (* VPADDD (%_% ymm6) (%_% ymm10) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xd5; + (* VPADDD (%_% ymm10) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x4d; 0xfa; 0xf5; + (* VPSUBD (%_% ymm6) (%_% ymm6) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x45; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xff; (* VPADDD (%_% ymm7) (%_% ymm11) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x8e; 0x88; 0x00; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm1) (Memop Doubleword (%% (rsi,136))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x96; 0x28; 0x05; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm2) (Memop Doubleword (%% (rsi,1320))) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x5d; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm6) *) + 0xc5; 0xdd; 0xfe; 0xe6; (* VPADDD (%_% ymm4) (%_% ymm4) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc4; 0x62; 0x45; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm7) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe7; (* VMOVSHDUP (%_% ymm12) (%_% ymm7) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x45; 0x28; 0xfa; + (* VPMULDQ (%_% ymm7) (%_% ymm7) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xff; (* VMOVSHDUP (%_% ymm7) (%_% ymm7) *) + 0xc4; 0xc3; 0x45; 0x02; 0xfc; 0xaa; + (* VPBLENDD (%_% ymm7) (%_% ymm7) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x55; 0xfa; 0xe7; (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm7) *) + 0xc5; 0xd5; 0xfe; 0xef; (* VPADDD (%_% ymm5) (%_% ymm5) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xfd; + (* VPADDD (%_% ymm7) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x8e; 0x8c; 0x00; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm1) (Memop Doubleword (%% (rsi,140))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x96; 0x2c; 0x05; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm2) (Memop Doubleword (%% (rsi,1324))) *) + 0xc4; 0x62; 0x2d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm10) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe2; + (* VMOVSHDUP (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x2d; 0x28; 0xd2; + (* VPMULDQ (%_% ymm10) (%_% ymm10) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xd2; + (* VMOVSHDUP (%_% ymm10) (%_% ymm10) *) + 0xc4; 0x43; 0x2d; 0x02; 0xd4; 0xaa; + (* VPBLENDD (%_% ymm10) (%_% ymm10) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xe2; + (* VPSUBD (%_% ymm12) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x3d; 0xfe; 0xc2; + (* VPADDD (%_% ymm8) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xd5; + (* VPADDD (%_% ymm10) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xc5; + (* VPSUBD (%_% ymm8) (%_% ymm8) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x35; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x35; 0xfe; 0xcb; + (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc5; 0xfd; 0x7f; 0x67; 0x60; + (* VMOVDQA (Memop Word256 (%% (rdi,96))) (%_% ymm4) *) + 0xc5; 0xfd; 0x7f; 0xaf; 0xe0; 0x00; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,224))) (%_% ymm5) *) + 0xc5; 0xfd; 0x7f; 0xb7; 0x60; 0x01; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,352))) (%_% ymm6) *) + 0xc5; 0xfd; 0x7f; 0xbf; 0xe0; 0x01; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,480))) (%_% ymm7) *) + 0xc5; 0x7d; 0x7f; 0x87; 0x60; 0x02; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,608))) (%_% ymm8) *) + 0xc5; 0x7d; 0x7f; 0x8f; 0xe0; 0x02; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,736))) (%_% ymm9) *) + 0xc5; 0x7d; 0x7f; 0x97; 0x60; 0x03; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,864))) (%_% ymm10) *) + 0xc5; 0x7d; 0x7f; 0x9f; 0xe0; 0x03; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,992))) (%_% ymm11) *) + 0xc5; 0xfd; 0x6f; 0x27; (* VMOVDQA (%_% ymm4) (Memop Word256 (%% (rdi,0))) *) + 0xc5; 0xfd; 0x6f; 0x6f; 0x20; + (* VMOVDQA (%_% ymm5) (Memop Word256 (%% (rdi,32))) *) + 0xc5; 0xfd; 0x6f; 0x77; 0x40; + (* VMOVDQA (%_% ymm6) (Memop Word256 (%% (rdi,64))) *) + 0xc5; 0xfd; 0x6f; 0x7f; 0x60; + (* VMOVDQA (%_% ymm7) (Memop Word256 (%% (rdi,96))) *) + 0xc5; 0x7d; 0x6f; 0x87; 0x80; 0x00; 0x00; 0x00; + (* VMOVDQA (%_% ymm8) (Memop Word256 (%% (rdi,128))) *) + 0xc5; 0x7d; 0x6f; 0x8f; 0xa0; 0x00; 0x00; 0x00; + (* VMOVDQA (%_% ymm9) (Memop Word256 (%% (rdi,160))) *) + 0xc5; 0x7d; 0x6f; 0x97; 0xc0; 0x00; 0x00; 0x00; + (* VMOVDQA (%_% ymm10) (Memop Word256 (%% (rdi,192))) *) + 0xc5; 0x7d; 0x6f; 0x9f; 0xe0; 0x00; 0x00; 0x00; + (* VMOVDQA (%_% ymm11) (Memop Word256 (%% (rdi,224))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x8e; 0x90; 0x00; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm1) (Memop Doubleword (%% (rsi,144))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x96; 0x30; 0x05; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm2) (Memop Doubleword (%% (rsi,1328))) *) + 0xc4; 0x62; 0x3d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm8) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe0; + (* VMOVSHDUP (%_% ymm12) (%_% ymm8) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x3d; 0x28; 0xc2; + (* VPMULDQ (%_% ymm8) (%_% ymm8) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc0; + (* VMOVSHDUP (%_% ymm8) (%_% ymm8) *) + 0xc4; 0x43; 0x3d; 0x02; 0xc4; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm8) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x5d; 0xfa; 0xe0; + (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm8) *) + 0xc5; 0xbd; 0xfe; 0xe4; (* VPADDD (%_% ymm4) (%_% ymm8) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xc5; + (* VPADDD (%_% ymm8) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc4; 0x62; 0x35; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm9) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe1; + (* VMOVSHDUP (%_% ymm12) (%_% ymm9) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x35; 0x28; 0xca; + (* VPMULDQ (%_% ymm9) (%_% ymm9) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc9; + (* VMOVSHDUP (%_% ymm9) (%_% ymm9) *) + 0xc4; 0x43; 0x35; 0x02; 0xcc; 0xaa; + (* VPBLENDD (%_% ymm9) (%_% ymm9) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x55; 0xfa; 0xe1; + (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm9) *) + 0xc5; 0xb5; 0xfe; 0xed; (* VPADDD (%_% ymm5) (%_% ymm9) (%_% ymm5) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xcd; + (* VPADDD (%_% ymm9) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0x62; 0x2d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm10) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe2; + (* VMOVSHDUP (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x2d; 0x28; 0xd2; + (* VPMULDQ (%_% ymm10) (%_% ymm10) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xd2; + (* VMOVSHDUP (%_% ymm10) (%_% ymm10) *) + 0xc4; 0x43; 0x2d; 0x02; 0xd4; 0xaa; + (* VPBLENDD (%_% ymm10) (%_% ymm10) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x4d; 0xfa; 0xe2; + (* VPSUBD (%_% ymm12) (%_% ymm6) (%_% ymm10) *) + 0xc5; 0xad; 0xfe; 0xf6; (* VPADDD (%_% ymm6) (%_% ymm10) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xd5; + (* VPADDD (%_% ymm10) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x4d; 0xfa; 0xf5; + (* VPSUBD (%_% ymm6) (%_% ymm6) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x45; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xff; (* VPADDD (%_% ymm7) (%_% ymm11) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc4; 0xc3; 0x5d; 0x46; 0xd8; 0x20; + (* VPERM2I128 (%_% ymm3) (%_% ymm4) (%_% ymm8) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x5d; 0x46; 0xc0; 0x31; + (* VPERM2I128 (%_% ymm8) (%_% ymm4) (%_% ymm8) (Imm8 (word 49)) *) + 0xc4; 0xc3; 0x55; 0x46; 0xe1; 0x20; + (* VPERM2I128 (%_% ymm4) (%_% ymm5) (%_% ymm9) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x55; 0x46; 0xc9; 0x31; + (* VPERM2I128 (%_% ymm9) (%_% ymm5) (%_% ymm9) (Imm8 (word 49)) *) + 0xc4; 0xc3; 0x4d; 0x46; 0xea; 0x20; + (* VPERM2I128 (%_% ymm5) (%_% ymm6) (%_% ymm10) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x4d; 0x46; 0xd2; 0x31; + (* VPERM2I128 (%_% ymm10) (%_% ymm6) (%_% ymm10) (Imm8 (word 49)) *) + 0xc4; 0xc3; 0x45; 0x46; 0xf3; 0x20; + (* VPERM2I128 (%_% ymm6) (%_% ymm7) (%_% ymm11) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x45; 0x46; 0xdb; 0x31; + (* VPERM2I128 (%_% ymm11) (%_% ymm7) (%_% ymm11) (Imm8 (word 49)) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0xa0; 0x00; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,160))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x40; 0x05; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1344))) *) + 0xc4; 0x62; 0x55; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm5) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe5; (* VMOVSHDUP (%_% ymm12) (%_% ymm5) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x55; 0x28; 0xea; + (* VPMULDQ (%_% ymm5) (%_% ymm5) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xed; (* VMOVSHDUP (%_% ymm5) (%_% ymm5) *) + 0xc4; 0xc3; 0x55; 0x02; 0xec; 0xaa; + (* VPBLENDD (%_% ymm5) (%_% ymm5) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x65; 0xfa; 0xe5; (* VPSUBD (%_% ymm12) (%_% ymm3) (%_% ymm5) *) + 0xc5; 0xe5; 0xfe; 0xdd; (* VPADDD (%_% ymm3) (%_% ymm3) (%_% ymm5) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xed; + (* VPADDD (%_% ymm5) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x65; 0xfa; 0xdd; + (* VPSUBD (%_% ymm3) (%_% ymm3) (%_% ymm13) *) + 0xc4; 0x62; 0x2d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm10) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe2; + (* VMOVSHDUP (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x2d; 0x28; 0xd2; + (* VPMULDQ (%_% ymm10) (%_% ymm10) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xd2; + (* VMOVSHDUP (%_% ymm10) (%_% ymm10) *) + 0xc4; 0x43; 0x2d; 0x02; 0xd4; 0xaa; + (* VPBLENDD (%_% ymm10) (%_% ymm10) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xe2; + (* VPSUBD (%_% ymm12) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x3d; 0xfe; 0xc2; + (* VPADDD (%_% ymm8) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xd5; + (* VPADDD (%_% ymm10) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xc5; + (* VPSUBD (%_% ymm8) (%_% ymm8) (%_% ymm13) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x5d; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm6) *) + 0xc5; 0xdd; 0xfe; 0xe6; (* VPADDD (%_% ymm4) (%_% ymm4) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x35; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x35; 0xfe; 0xcb; + (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc5; 0xe5; 0x6c; 0xfd; (* VPUNPCKLQDQ (%_% ymm7) (%_% ymm3) (%_% ymm5) *) + 0xc5; 0xe5; 0x6d; 0xed; (* VPUNPCKHQDQ (%_% ymm5) (%_% ymm3) (%_% ymm5) *) + 0xc4; 0xc1; 0x3d; 0x6c; 0xda; + (* VPUNPCKLQDQ (%_% ymm3) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x3d; 0x6d; 0xd2; + (* VPUNPCKHQDQ (%_% ymm10) (%_% ymm8) (%_% ymm10) *) + 0xc5; 0x5d; 0x6c; 0xc6; (* VPUNPCKLQDQ (%_% ymm8) (%_% ymm4) (%_% ymm6) *) + 0xc5; 0xdd; 0x6d; 0xf6; (* VPUNPCKHQDQ (%_% ymm6) (%_% ymm4) (%_% ymm6) *) + 0xc4; 0xc1; 0x35; 0x6c; 0xe3; + (* VPUNPCKLQDQ (%_% ymm4) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x35; 0x6d; 0xdb; + (* VPUNPCKHQDQ (%_% ymm11) (%_% ymm9) (%_% ymm11) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x20; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,288))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0xc0; 0x05; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1472))) *) + 0xc4; 0x62; 0x3d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm8) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe0; + (* VMOVSHDUP (%_% ymm12) (%_% ymm8) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x3d; 0x28; 0xc2; + (* VPMULDQ (%_% ymm8) (%_% ymm8) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc0; + (* VMOVSHDUP (%_% ymm8) (%_% ymm8) *) + 0xc4; 0x43; 0x3d; 0x02; 0xc4; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm8) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x45; 0xfa; 0xe0; + (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm8) *) + 0xc5; 0xbd; 0xfe; 0xff; (* VPADDD (%_% ymm7) (%_% ymm8) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xc5; + (* VPADDD (%_% ymm8) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x55; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm6) *) + 0xc5; 0xd5; 0xfe; 0xee; (* VPADDD (%_% ymm5) (%_% ymm5) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0x62; 0x5d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm4) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm12) (%_% ymm4) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x5d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm4) (%_% ymm4) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm4) (%_% ymm4) *) + 0xc4; 0xc3; 0x5d; 0x02; 0xe4; 0xaa; + (* VPBLENDD (%_% ymm4) (%_% ymm4) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x65; 0xfa; 0xe4; (* VPSUBD (%_% ymm12) (%_% ymm3) (%_% ymm4) *) + 0xc5; 0xe5; 0xfe; 0xdc; (* VPADDD (%_% ymm3) (%_% ymm3) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xe5; + (* VPADDD (%_% ymm4) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x65; 0xfa; 0xdd; + (* VPSUBD (%_% ymm3) (%_% ymm3) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x2d; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm10) (%_% ymm11) *) + 0xc4; 0x41; 0x2d; 0xfe; 0xd3; + (* VPADDD (%_% ymm10) (%_% ymm10) (%_% ymm11) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x2d; 0xfa; 0xd5; + (* VPSUBD (%_% ymm10) (%_% ymm10) (%_% ymm13) *) + 0xc4; 0x41; 0x7e; 0x12; 0xc8; + (* VMOVSLDUP (%_% ymm9) (%_% ymm8) *) + 0xc4; 0x43; 0x45; 0x02; 0xc9; 0xaa; + (* VPBLENDD (%_% ymm9) (%_% ymm7) (%_% ymm9) (Imm8 (word 170)) *) + 0xc5; 0xc5; 0x73; 0xd7; 0x20; + (* VPSRLQ (%_% ymm7) (%_% ymm7) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x45; 0x02; 0xc0; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm7) (%_% ymm8) (Imm8 (word 170)) *) + 0xc5; 0xfe; 0x12; 0xfe; (* VMOVSLDUP (%_% ymm7) (%_% ymm6) *) + 0xc4; 0xe3; 0x55; 0x02; 0xff; 0xaa; + (* VPBLENDD (%_% ymm7) (%_% ymm5) (%_% ymm7) (Imm8 (word 170)) *) + 0xc5; 0xd5; 0x73; 0xd5; 0x20; + (* VPSRLQ (%_% ymm5) (%_% ymm5) (Imm8 (word 32)) *) + 0xc4; 0xe3; 0x55; 0x02; 0xf6; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm5) (%_% ymm6) (Imm8 (word 170)) *) + 0xc5; 0xfe; 0x12; 0xec; (* VMOVSLDUP (%_% ymm5) (%_% ymm4) *) + 0xc4; 0xe3; 0x65; 0x02; 0xed; 0xaa; + (* VPBLENDD (%_% ymm5) (%_% ymm3) (%_% ymm5) (Imm8 (word 170)) *) + 0xc5; 0xe5; 0x73; 0xd3; 0x20; + (* VPSRLQ (%_% ymm3) (%_% ymm3) (Imm8 (word 32)) *) + 0xc4; 0xe3; 0x65; 0x02; 0xe4; 0xaa; + (* VPBLENDD (%_% ymm4) (%_% ymm3) (%_% ymm4) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x7e; 0x12; 0xdb; + (* VMOVSLDUP (%_% ymm3) (%_% ymm11) *) + 0xc4; 0xe3; 0x2d; 0x02; 0xdb; 0xaa; + (* VPBLENDD (%_% ymm3) (%_% ymm10) (%_% ymm3) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x2d; 0x73; 0xd2; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm10) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x2d; 0x02; 0xdb; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm10) (%_% ymm11) (Imm8 (word 170)) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0xa0; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,416))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x40; 0x06; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1600))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x55; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm5) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe5; (* VMOVSHDUP (%_% ymm12) (%_% ymm5) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x55; 0x28; 0xea; + (* VPMULDQ (%_% ymm5) (%_% ymm5) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xed; (* VMOVSHDUP (%_% ymm5) (%_% ymm5) *) + 0xc4; 0xc3; 0x55; 0x02; 0xec; 0xaa; + (* VPBLENDD (%_% ymm5) (%_% ymm5) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x35; 0xfa; 0xe5; (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm5) *) + 0xc5; 0x35; 0xfe; 0xcd; (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm5) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xed; + (* VPADDD (%_% ymm5) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc4; 0x62; 0x5d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm4) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm12) (%_% ymm4) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x5d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm4) (%_% ymm4) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm4) (%_% ymm4) *) + 0xc4; 0xc3; 0x5d; 0x02; 0xe4; 0xaa; + (* VPBLENDD (%_% ymm4) (%_% ymm4) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x3d; 0xfa; 0xe4; (* VPSUBD (%_% ymm12) (%_% ymm8) (%_% ymm4) *) + 0xc5; 0x3d; 0xfe; 0xc4; (* VPADDD (%_% ymm8) (%_% ymm8) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xe5; + (* VPADDD (%_% ymm4) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xc5; + (* VPSUBD (%_% ymm8) (%_% ymm8) (%_% ymm13) *) + 0xc4; 0x62; 0x65; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm3) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe3; (* VMOVSHDUP (%_% ymm12) (%_% ymm3) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x65; 0x28; 0xda; + (* VPMULDQ (%_% ymm3) (%_% ymm3) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xdb; (* VMOVSHDUP (%_% ymm3) (%_% ymm3) *) + 0xc4; 0xc3; 0x65; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm3) (%_% ymm3) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x45; 0xfa; 0xe3; (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm3) *) + 0xc5; 0xc5; 0xfe; 0xfb; (* VPADDD (%_% ymm7) (%_% ymm7) (%_% ymm3) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm3) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x4d; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm6) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xf6; (* VPADDD (%_% ymm6) (%_% ymm11) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x4d; 0xfa; 0xf5; + (* VPSUBD (%_% ymm6) (%_% ymm6) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x20; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,544))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0xc0; 0x06; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1728))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x45; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm7) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe7; (* VMOVSHDUP (%_% ymm12) (%_% ymm7) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x45; 0x28; 0xfa; + (* VPMULDQ (%_% ymm7) (%_% ymm7) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xff; (* VMOVSHDUP (%_% ymm7) (%_% ymm7) *) + 0xc4; 0xc3; 0x45; 0x02; 0xfc; 0xaa; + (* VPBLENDD (%_% ymm7) (%_% ymm7) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x35; 0xfa; 0xe7; (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm7) *) + 0xc5; 0x35; 0xfe; 0xcf; (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xfd; + (* VPADDD (%_% ymm7) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x3d; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm8) (%_% ymm6) *) + 0xc5; 0x3d; 0xfe; 0xc6; (* VPADDD (%_% ymm8) (%_% ymm8) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xc5; + (* VPSUBD (%_% ymm8) (%_% ymm8) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0xa0; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,672))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x40; 0x07; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1856))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x65; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm3) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe3; (* VMOVSHDUP (%_% ymm12) (%_% ymm3) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x65; 0x28; 0xda; + (* VPMULDQ (%_% ymm3) (%_% ymm3) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xdb; (* VMOVSHDUP (%_% ymm3) (%_% ymm3) *) + 0xc4; 0xc3; 0x65; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm3) (%_% ymm3) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x55; 0xfa; 0xe3; (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm3) *) + 0xc5; 0xd5; 0xfe; 0xeb; (* VPADDD (%_% ymm5) (%_% ymm5) (%_% ymm3) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm3) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x5d; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xe4; (* VPADDD (%_% ymm4) (%_% ymm11) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x20; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,800))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0xc0; 0x07; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1984))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x3d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm8) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe0; + (* VMOVSHDUP (%_% ymm12) (%_% ymm8) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x3d; 0x28; 0xc2; + (* VPMULDQ (%_% ymm8) (%_% ymm8) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc0; + (* VMOVSHDUP (%_% ymm8) (%_% ymm8) *) + 0xc4; 0x43; 0x3d; 0x02; 0xc4; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm8) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x35; 0xfa; 0xe0; + (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm8) *) + 0xc4; 0x41; 0x35; 0xfe; 0xc8; + (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm8) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xc5; + (* VPADDD (%_% ymm8) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0xa0; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,928))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x40; 0x08; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,2112))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x45; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm6) *) + 0xc5; 0xc5; 0xfe; 0xfe; (* VPADDD (%_% ymm7) (%_% ymm7) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x20; 0x04; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,1056))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0xc0; 0x08; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,2240))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x5d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm4) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm12) (%_% ymm4) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x5d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm4) (%_% ymm4) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm4) (%_% ymm4) *) + 0xc4; 0xc3; 0x5d; 0x02; 0xe4; 0xaa; + (* VPBLENDD (%_% ymm4) (%_% ymm4) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x55; 0xfa; 0xe4; (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm4) *) + 0xc5; 0xd5; 0xfe; 0xec; (* VPADDD (%_% ymm5) (%_% ymm5) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xe5; + (* VPADDD (%_% ymm4) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0xa0; 0x04; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,1184))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x40; 0x09; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,2368))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x65; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm3) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xdb; (* VPADDD (%_% ymm3) (%_% ymm11) (%_% ymm3) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x65; 0xfa; 0xdd; + (* VPSUBD (%_% ymm3) (%_% ymm3) (%_% ymm13) *) + 0xc5; 0x7d; 0x7f; 0x0f; (* VMOVDQA (Memop Word256 (%% (rdi,0))) (%_% ymm9) *) + 0xc5; 0x7d; 0x7f; 0x47; 0x20; + (* VMOVDQA (Memop Word256 (%% (rdi,32))) (%_% ymm8) *) + 0xc5; 0xfd; 0x7f; 0x7f; 0x40; + (* VMOVDQA (Memop Word256 (%% (rdi,64))) (%_% ymm7) *) + 0xc5; 0xfd; 0x7f; 0x77; 0x60; + (* VMOVDQA (Memop Word256 (%% (rdi,96))) (%_% ymm6) *) + 0xc5; 0xfd; 0x7f; 0xaf; 0x80; 0x00; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,128))) (%_% ymm5) *) + 0xc5; 0xfd; 0x7f; 0xa7; 0xa0; 0x00; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,160))) (%_% ymm4) *) + 0xc5; 0xfd; 0x7f; 0x9f; 0xc0; 0x00; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,192))) (%_% ymm3) *) + 0xc5; 0x7d; 0x7f; 0x9f; 0xe0; 0x00; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,224))) (%_% ymm11) *) + 0xc5; 0xfd; 0x6f; 0xa7; 0x00; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm4) (Memop Word256 (%% (rdi,256))) *) + 0xc5; 0xfd; 0x6f; 0xaf; 0x20; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm5) (Memop Word256 (%% (rdi,288))) *) + 0xc5; 0xfd; 0x6f; 0xb7; 0x40; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm6) (Memop Word256 (%% (rdi,320))) *) + 0xc5; 0xfd; 0x6f; 0xbf; 0x60; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm7) (Memop Word256 (%% (rdi,352))) *) + 0xc5; 0x7d; 0x6f; 0x87; 0x80; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm8) (Memop Word256 (%% (rdi,384))) *) + 0xc5; 0x7d; 0x6f; 0x8f; 0xa0; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm9) (Memop Word256 (%% (rdi,416))) *) + 0xc5; 0x7d; 0x6f; 0x97; 0xc0; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm10) (Memop Word256 (%% (rdi,448))) *) + 0xc5; 0x7d; 0x6f; 0x9f; 0xe0; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm11) (Memop Word256 (%% (rdi,480))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x8e; 0x94; 0x00; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm1) (Memop Doubleword (%% (rsi,148))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x96; 0x34; 0x05; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm2) (Memop Doubleword (%% (rsi,1332))) *) + 0xc4; 0x62; 0x3d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm8) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe0; + (* VMOVSHDUP (%_% ymm12) (%_% ymm8) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x3d; 0x28; 0xc2; + (* VPMULDQ (%_% ymm8) (%_% ymm8) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc0; + (* VMOVSHDUP (%_% ymm8) (%_% ymm8) *) + 0xc4; 0x43; 0x3d; 0x02; 0xc4; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm8) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x5d; 0xfa; 0xe0; + (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm8) *) + 0xc5; 0xbd; 0xfe; 0xe4; (* VPADDD (%_% ymm4) (%_% ymm8) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xc5; + (* VPADDD (%_% ymm8) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc4; 0x62; 0x35; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm9) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe1; + (* VMOVSHDUP (%_% ymm12) (%_% ymm9) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x35; 0x28; 0xca; + (* VPMULDQ (%_% ymm9) (%_% ymm9) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc9; + (* VMOVSHDUP (%_% ymm9) (%_% ymm9) *) + 0xc4; 0x43; 0x35; 0x02; 0xcc; 0xaa; + (* VPBLENDD (%_% ymm9) (%_% ymm9) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x55; 0xfa; 0xe1; + (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm9) *) + 0xc5; 0xb5; 0xfe; 0xed; (* VPADDD (%_% ymm5) (%_% ymm9) (%_% ymm5) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xcd; + (* VPADDD (%_% ymm9) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0x62; 0x2d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm10) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe2; + (* VMOVSHDUP (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x2d; 0x28; 0xd2; + (* VPMULDQ (%_% ymm10) (%_% ymm10) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xd2; + (* VMOVSHDUP (%_% ymm10) (%_% ymm10) *) + 0xc4; 0x43; 0x2d; 0x02; 0xd4; 0xaa; + (* VPBLENDD (%_% ymm10) (%_% ymm10) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x4d; 0xfa; 0xe2; + (* VPSUBD (%_% ymm12) (%_% ymm6) (%_% ymm10) *) + 0xc5; 0xad; 0xfe; 0xf6; (* VPADDD (%_% ymm6) (%_% ymm10) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xd5; + (* VPADDD (%_% ymm10) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x4d; 0xfa; 0xf5; + (* VPSUBD (%_% ymm6) (%_% ymm6) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x45; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xff; (* VPADDD (%_% ymm7) (%_% ymm11) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc4; 0xc3; 0x5d; 0x46; 0xd8; 0x20; + (* VPERM2I128 (%_% ymm3) (%_% ymm4) (%_% ymm8) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x5d; 0x46; 0xc0; 0x31; + (* VPERM2I128 (%_% ymm8) (%_% ymm4) (%_% ymm8) (Imm8 (word 49)) *) + 0xc4; 0xc3; 0x55; 0x46; 0xe1; 0x20; + (* VPERM2I128 (%_% ymm4) (%_% ymm5) (%_% ymm9) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x55; 0x46; 0xc9; 0x31; + (* VPERM2I128 (%_% ymm9) (%_% ymm5) (%_% ymm9) (Imm8 (word 49)) *) + 0xc4; 0xc3; 0x4d; 0x46; 0xea; 0x20; + (* VPERM2I128 (%_% ymm5) (%_% ymm6) (%_% ymm10) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x4d; 0x46; 0xd2; 0x31; + (* VPERM2I128 (%_% ymm10) (%_% ymm6) (%_% ymm10) (Imm8 (word 49)) *) + 0xc4; 0xc3; 0x45; 0x46; 0xf3; 0x20; + (* VPERM2I128 (%_% ymm6) (%_% ymm7) (%_% ymm11) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x45; 0x46; 0xdb; 0x31; + (* VPERM2I128 (%_% ymm11) (%_% ymm7) (%_% ymm11) (Imm8 (word 49)) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0xc0; 0x00; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,192))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x60; 0x05; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1376))) *) + 0xc4; 0x62; 0x55; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm5) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe5; (* VMOVSHDUP (%_% ymm12) (%_% ymm5) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x55; 0x28; 0xea; + (* VPMULDQ (%_% ymm5) (%_% ymm5) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xed; (* VMOVSHDUP (%_% ymm5) (%_% ymm5) *) + 0xc4; 0xc3; 0x55; 0x02; 0xec; 0xaa; + (* VPBLENDD (%_% ymm5) (%_% ymm5) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x65; 0xfa; 0xe5; (* VPSUBD (%_% ymm12) (%_% ymm3) (%_% ymm5) *) + 0xc5; 0xe5; 0xfe; 0xdd; (* VPADDD (%_% ymm3) (%_% ymm3) (%_% ymm5) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xed; + (* VPADDD (%_% ymm5) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x65; 0xfa; 0xdd; + (* VPSUBD (%_% ymm3) (%_% ymm3) (%_% ymm13) *) + 0xc4; 0x62; 0x2d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm10) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe2; + (* VMOVSHDUP (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x2d; 0x28; 0xd2; + (* VPMULDQ (%_% ymm10) (%_% ymm10) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xd2; + (* VMOVSHDUP (%_% ymm10) (%_% ymm10) *) + 0xc4; 0x43; 0x2d; 0x02; 0xd4; 0xaa; + (* VPBLENDD (%_% ymm10) (%_% ymm10) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xe2; + (* VPSUBD (%_% ymm12) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x3d; 0xfe; 0xc2; + (* VPADDD (%_% ymm8) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xd5; + (* VPADDD (%_% ymm10) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xc5; + (* VPSUBD (%_% ymm8) (%_% ymm8) (%_% ymm13) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x5d; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm6) *) + 0xc5; 0xdd; 0xfe; 0xe6; (* VPADDD (%_% ymm4) (%_% ymm4) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x35; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x35; 0xfe; 0xcb; + (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc5; 0xe5; 0x6c; 0xfd; (* VPUNPCKLQDQ (%_% ymm7) (%_% ymm3) (%_% ymm5) *) + 0xc5; 0xe5; 0x6d; 0xed; (* VPUNPCKHQDQ (%_% ymm5) (%_% ymm3) (%_% ymm5) *) + 0xc4; 0xc1; 0x3d; 0x6c; 0xda; + (* VPUNPCKLQDQ (%_% ymm3) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x3d; 0x6d; 0xd2; + (* VPUNPCKHQDQ (%_% ymm10) (%_% ymm8) (%_% ymm10) *) + 0xc5; 0x5d; 0x6c; 0xc6; (* VPUNPCKLQDQ (%_% ymm8) (%_% ymm4) (%_% ymm6) *) + 0xc5; 0xdd; 0x6d; 0xf6; (* VPUNPCKHQDQ (%_% ymm6) (%_% ymm4) (%_% ymm6) *) + 0xc4; 0xc1; 0x35; 0x6c; 0xe3; + (* VPUNPCKLQDQ (%_% ymm4) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x35; 0x6d; 0xdb; + (* VPUNPCKHQDQ (%_% ymm11) (%_% ymm9) (%_% ymm11) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x40; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,320))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0xe0; 0x05; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1504))) *) + 0xc4; 0x62; 0x3d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm8) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe0; + (* VMOVSHDUP (%_% ymm12) (%_% ymm8) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x3d; 0x28; 0xc2; + (* VPMULDQ (%_% ymm8) (%_% ymm8) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc0; + (* VMOVSHDUP (%_% ymm8) (%_% ymm8) *) + 0xc4; 0x43; 0x3d; 0x02; 0xc4; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm8) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x45; 0xfa; 0xe0; + (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm8) *) + 0xc5; 0xbd; 0xfe; 0xff; (* VPADDD (%_% ymm7) (%_% ymm8) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xc5; + (* VPADDD (%_% ymm8) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x55; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm6) *) + 0xc5; 0xd5; 0xfe; 0xee; (* VPADDD (%_% ymm5) (%_% ymm5) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0x62; 0x5d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm4) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm12) (%_% ymm4) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x5d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm4) (%_% ymm4) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm4) (%_% ymm4) *) + 0xc4; 0xc3; 0x5d; 0x02; 0xe4; 0xaa; + (* VPBLENDD (%_% ymm4) (%_% ymm4) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x65; 0xfa; 0xe4; (* VPSUBD (%_% ymm12) (%_% ymm3) (%_% ymm4) *) + 0xc5; 0xe5; 0xfe; 0xdc; (* VPADDD (%_% ymm3) (%_% ymm3) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xe5; + (* VPADDD (%_% ymm4) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x65; 0xfa; 0xdd; + (* VPSUBD (%_% ymm3) (%_% ymm3) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x2d; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm10) (%_% ymm11) *) + 0xc4; 0x41; 0x2d; 0xfe; 0xd3; + (* VPADDD (%_% ymm10) (%_% ymm10) (%_% ymm11) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x2d; 0xfa; 0xd5; + (* VPSUBD (%_% ymm10) (%_% ymm10) (%_% ymm13) *) + 0xc4; 0x41; 0x7e; 0x12; 0xc8; + (* VMOVSLDUP (%_% ymm9) (%_% ymm8) *) + 0xc4; 0x43; 0x45; 0x02; 0xc9; 0xaa; + (* VPBLENDD (%_% ymm9) (%_% ymm7) (%_% ymm9) (Imm8 (word 170)) *) + 0xc5; 0xc5; 0x73; 0xd7; 0x20; + (* VPSRLQ (%_% ymm7) (%_% ymm7) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x45; 0x02; 0xc0; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm7) (%_% ymm8) (Imm8 (word 170)) *) + 0xc5; 0xfe; 0x12; 0xfe; (* VMOVSLDUP (%_% ymm7) (%_% ymm6) *) + 0xc4; 0xe3; 0x55; 0x02; 0xff; 0xaa; + (* VPBLENDD (%_% ymm7) (%_% ymm5) (%_% ymm7) (Imm8 (word 170)) *) + 0xc5; 0xd5; 0x73; 0xd5; 0x20; + (* VPSRLQ (%_% ymm5) (%_% ymm5) (Imm8 (word 32)) *) + 0xc4; 0xe3; 0x55; 0x02; 0xf6; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm5) (%_% ymm6) (Imm8 (word 170)) *) + 0xc5; 0xfe; 0x12; 0xec; (* VMOVSLDUP (%_% ymm5) (%_% ymm4) *) + 0xc4; 0xe3; 0x65; 0x02; 0xed; 0xaa; + (* VPBLENDD (%_% ymm5) (%_% ymm3) (%_% ymm5) (Imm8 (word 170)) *) + 0xc5; 0xe5; 0x73; 0xd3; 0x20; + (* VPSRLQ (%_% ymm3) (%_% ymm3) (Imm8 (word 32)) *) + 0xc4; 0xe3; 0x65; 0x02; 0xe4; 0xaa; + (* VPBLENDD (%_% ymm4) (%_% ymm3) (%_% ymm4) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x7e; 0x12; 0xdb; + (* VMOVSLDUP (%_% ymm3) (%_% ymm11) *) + 0xc4; 0xe3; 0x2d; 0x02; 0xdb; 0xaa; + (* VPBLENDD (%_% ymm3) (%_% ymm10) (%_% ymm3) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x2d; 0x73; 0xd2; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm10) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x2d; 0x02; 0xdb; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm10) (%_% ymm11) (Imm8 (word 170)) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0xc0; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,448))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x60; 0x06; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1632))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x55; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm5) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe5; (* VMOVSHDUP (%_% ymm12) (%_% ymm5) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x55; 0x28; 0xea; + (* VPMULDQ (%_% ymm5) (%_% ymm5) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xed; (* VMOVSHDUP (%_% ymm5) (%_% ymm5) *) + 0xc4; 0xc3; 0x55; 0x02; 0xec; 0xaa; + (* VPBLENDD (%_% ymm5) (%_% ymm5) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x35; 0xfa; 0xe5; (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm5) *) + 0xc5; 0x35; 0xfe; 0xcd; (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm5) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xed; + (* VPADDD (%_% ymm5) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc4; 0x62; 0x5d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm4) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm12) (%_% ymm4) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x5d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm4) (%_% ymm4) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm4) (%_% ymm4) *) + 0xc4; 0xc3; 0x5d; 0x02; 0xe4; 0xaa; + (* VPBLENDD (%_% ymm4) (%_% ymm4) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x3d; 0xfa; 0xe4; (* VPSUBD (%_% ymm12) (%_% ymm8) (%_% ymm4) *) + 0xc5; 0x3d; 0xfe; 0xc4; (* VPADDD (%_% ymm8) (%_% ymm8) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xe5; + (* VPADDD (%_% ymm4) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xc5; + (* VPSUBD (%_% ymm8) (%_% ymm8) (%_% ymm13) *) + 0xc4; 0x62; 0x65; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm3) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe3; (* VMOVSHDUP (%_% ymm12) (%_% ymm3) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x65; 0x28; 0xda; + (* VPMULDQ (%_% ymm3) (%_% ymm3) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xdb; (* VMOVSHDUP (%_% ymm3) (%_% ymm3) *) + 0xc4; 0xc3; 0x65; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm3) (%_% ymm3) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x45; 0xfa; 0xe3; (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm3) *) + 0xc5; 0xc5; 0xfe; 0xfb; (* VPADDD (%_% ymm7) (%_% ymm7) (%_% ymm3) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm3) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x4d; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm6) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xf6; (* VPADDD (%_% ymm6) (%_% ymm11) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x4d; 0xfa; 0xf5; + (* VPSUBD (%_% ymm6) (%_% ymm6) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x40; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,576))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0xe0; 0x06; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1760))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x45; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm7) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe7; (* VMOVSHDUP (%_% ymm12) (%_% ymm7) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x45; 0x28; 0xfa; + (* VPMULDQ (%_% ymm7) (%_% ymm7) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xff; (* VMOVSHDUP (%_% ymm7) (%_% ymm7) *) + 0xc4; 0xc3; 0x45; 0x02; 0xfc; 0xaa; + (* VPBLENDD (%_% ymm7) (%_% ymm7) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x35; 0xfa; 0xe7; (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm7) *) + 0xc5; 0x35; 0xfe; 0xcf; (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xfd; + (* VPADDD (%_% ymm7) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x3d; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm8) (%_% ymm6) *) + 0xc5; 0x3d; 0xfe; 0xc6; (* VPADDD (%_% ymm8) (%_% ymm8) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xc5; + (* VPSUBD (%_% ymm8) (%_% ymm8) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0xc0; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,704))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x60; 0x07; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1888))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x65; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm3) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe3; (* VMOVSHDUP (%_% ymm12) (%_% ymm3) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x65; 0x28; 0xda; + (* VPMULDQ (%_% ymm3) (%_% ymm3) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xdb; (* VMOVSHDUP (%_% ymm3) (%_% ymm3) *) + 0xc4; 0xc3; 0x65; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm3) (%_% ymm3) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x55; 0xfa; 0xe3; (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm3) *) + 0xc5; 0xd5; 0xfe; 0xeb; (* VPADDD (%_% ymm5) (%_% ymm5) (%_% ymm3) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm3) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x5d; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xe4; (* VPADDD (%_% ymm4) (%_% ymm11) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x40; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,832))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0xe0; 0x07; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,2016))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x3d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm8) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe0; + (* VMOVSHDUP (%_% ymm12) (%_% ymm8) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x3d; 0x28; 0xc2; + (* VPMULDQ (%_% ymm8) (%_% ymm8) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc0; + (* VMOVSHDUP (%_% ymm8) (%_% ymm8) *) + 0xc4; 0x43; 0x3d; 0x02; 0xc4; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm8) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x35; 0xfa; 0xe0; + (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm8) *) + 0xc4; 0x41; 0x35; 0xfe; 0xc8; + (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm8) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xc5; + (* VPADDD (%_% ymm8) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0xc0; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,960))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x60; 0x08; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,2144))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x45; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm6) *) + 0xc5; 0xc5; 0xfe; 0xfe; (* VPADDD (%_% ymm7) (%_% ymm7) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x40; 0x04; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,1088))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0xe0; 0x08; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,2272))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x5d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm4) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm12) (%_% ymm4) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x5d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm4) (%_% ymm4) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm4) (%_% ymm4) *) + 0xc4; 0xc3; 0x5d; 0x02; 0xe4; 0xaa; + (* VPBLENDD (%_% ymm4) (%_% ymm4) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x55; 0xfa; 0xe4; (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm4) *) + 0xc5; 0xd5; 0xfe; 0xec; (* VPADDD (%_% ymm5) (%_% ymm5) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xe5; + (* VPADDD (%_% ymm4) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0xc0; 0x04; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,1216))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x60; 0x09; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,2400))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x65; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm3) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xdb; (* VPADDD (%_% ymm3) (%_% ymm11) (%_% ymm3) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x65; 0xfa; 0xdd; + (* VPSUBD (%_% ymm3) (%_% ymm3) (%_% ymm13) *) + 0xc5; 0x7d; 0x7f; 0x8f; 0x00; 0x01; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,256))) (%_% ymm9) *) + 0xc5; 0x7d; 0x7f; 0x87; 0x20; 0x01; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,288))) (%_% ymm8) *) + 0xc5; 0xfd; 0x7f; 0xbf; 0x40; 0x01; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,320))) (%_% ymm7) *) + 0xc5; 0xfd; 0x7f; 0xb7; 0x60; 0x01; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,352))) (%_% ymm6) *) + 0xc5; 0xfd; 0x7f; 0xaf; 0x80; 0x01; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,384))) (%_% ymm5) *) + 0xc5; 0xfd; 0x7f; 0xa7; 0xa0; 0x01; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,416))) (%_% ymm4) *) + 0xc5; 0xfd; 0x7f; 0x9f; 0xc0; 0x01; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,448))) (%_% ymm3) *) + 0xc5; 0x7d; 0x7f; 0x9f; 0xe0; 0x01; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,480))) (%_% ymm11) *) + 0xc5; 0xfd; 0x6f; 0xa7; 0x00; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm4) (Memop Word256 (%% (rdi,512))) *) + 0xc5; 0xfd; 0x6f; 0xaf; 0x20; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm5) (Memop Word256 (%% (rdi,544))) *) + 0xc5; 0xfd; 0x6f; 0xb7; 0x40; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm6) (Memop Word256 (%% (rdi,576))) *) + 0xc5; 0xfd; 0x6f; 0xbf; 0x60; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm7) (Memop Word256 (%% (rdi,608))) *) + 0xc5; 0x7d; 0x6f; 0x87; 0x80; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm8) (Memop Word256 (%% (rdi,640))) *) + 0xc5; 0x7d; 0x6f; 0x8f; 0xa0; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm9) (Memop Word256 (%% (rdi,672))) *) + 0xc5; 0x7d; 0x6f; 0x97; 0xc0; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm10) (Memop Word256 (%% (rdi,704))) *) + 0xc5; 0x7d; 0x6f; 0x9f; 0xe0; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm11) (Memop Word256 (%% (rdi,736))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x8e; 0x98; 0x00; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm1) (Memop Doubleword (%% (rsi,152))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x96; 0x38; 0x05; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm2) (Memop Doubleword (%% (rsi,1336))) *) + 0xc4; 0x62; 0x3d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm8) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe0; + (* VMOVSHDUP (%_% ymm12) (%_% ymm8) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x3d; 0x28; 0xc2; + (* VPMULDQ (%_% ymm8) (%_% ymm8) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc0; + (* VMOVSHDUP (%_% ymm8) (%_% ymm8) *) + 0xc4; 0x43; 0x3d; 0x02; 0xc4; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm8) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x5d; 0xfa; 0xe0; + (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm8) *) + 0xc5; 0xbd; 0xfe; 0xe4; (* VPADDD (%_% ymm4) (%_% ymm8) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xc5; + (* VPADDD (%_% ymm8) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc4; 0x62; 0x35; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm9) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe1; + (* VMOVSHDUP (%_% ymm12) (%_% ymm9) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x35; 0x28; 0xca; + (* VPMULDQ (%_% ymm9) (%_% ymm9) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc9; + (* VMOVSHDUP (%_% ymm9) (%_% ymm9) *) + 0xc4; 0x43; 0x35; 0x02; 0xcc; 0xaa; + (* VPBLENDD (%_% ymm9) (%_% ymm9) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x55; 0xfa; 0xe1; + (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm9) *) + 0xc5; 0xb5; 0xfe; 0xed; (* VPADDD (%_% ymm5) (%_% ymm9) (%_% ymm5) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xcd; + (* VPADDD (%_% ymm9) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0x62; 0x2d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm10) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe2; + (* VMOVSHDUP (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x2d; 0x28; 0xd2; + (* VPMULDQ (%_% ymm10) (%_% ymm10) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xd2; + (* VMOVSHDUP (%_% ymm10) (%_% ymm10) *) + 0xc4; 0x43; 0x2d; 0x02; 0xd4; 0xaa; + (* VPBLENDD (%_% ymm10) (%_% ymm10) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x4d; 0xfa; 0xe2; + (* VPSUBD (%_% ymm12) (%_% ymm6) (%_% ymm10) *) + 0xc5; 0xad; 0xfe; 0xf6; (* VPADDD (%_% ymm6) (%_% ymm10) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xd5; + (* VPADDD (%_% ymm10) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x4d; 0xfa; 0xf5; + (* VPSUBD (%_% ymm6) (%_% ymm6) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x45; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xff; (* VPADDD (%_% ymm7) (%_% ymm11) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc4; 0xc3; 0x5d; 0x46; 0xd8; 0x20; + (* VPERM2I128 (%_% ymm3) (%_% ymm4) (%_% ymm8) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x5d; 0x46; 0xc0; 0x31; + (* VPERM2I128 (%_% ymm8) (%_% ymm4) (%_% ymm8) (Imm8 (word 49)) *) + 0xc4; 0xc3; 0x55; 0x46; 0xe1; 0x20; + (* VPERM2I128 (%_% ymm4) (%_% ymm5) (%_% ymm9) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x55; 0x46; 0xc9; 0x31; + (* VPERM2I128 (%_% ymm9) (%_% ymm5) (%_% ymm9) (Imm8 (word 49)) *) + 0xc4; 0xc3; 0x4d; 0x46; 0xea; 0x20; + (* VPERM2I128 (%_% ymm5) (%_% ymm6) (%_% ymm10) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x4d; 0x46; 0xd2; 0x31; + (* VPERM2I128 (%_% ymm10) (%_% ymm6) (%_% ymm10) (Imm8 (word 49)) *) + 0xc4; 0xc3; 0x45; 0x46; 0xf3; 0x20; + (* VPERM2I128 (%_% ymm6) (%_% ymm7) (%_% ymm11) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x45; 0x46; 0xdb; 0x31; + (* VPERM2I128 (%_% ymm11) (%_% ymm7) (%_% ymm11) (Imm8 (word 49)) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0xe0; 0x00; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,224))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x80; 0x05; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1408))) *) + 0xc4; 0x62; 0x55; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm5) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe5; (* VMOVSHDUP (%_% ymm12) (%_% ymm5) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x55; 0x28; 0xea; + (* VPMULDQ (%_% ymm5) (%_% ymm5) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xed; (* VMOVSHDUP (%_% ymm5) (%_% ymm5) *) + 0xc4; 0xc3; 0x55; 0x02; 0xec; 0xaa; + (* VPBLENDD (%_% ymm5) (%_% ymm5) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x65; 0xfa; 0xe5; (* VPSUBD (%_% ymm12) (%_% ymm3) (%_% ymm5) *) + 0xc5; 0xe5; 0xfe; 0xdd; (* VPADDD (%_% ymm3) (%_% ymm3) (%_% ymm5) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xed; + (* VPADDD (%_% ymm5) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x65; 0xfa; 0xdd; + (* VPSUBD (%_% ymm3) (%_% ymm3) (%_% ymm13) *) + 0xc4; 0x62; 0x2d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm10) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe2; + (* VMOVSHDUP (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x2d; 0x28; 0xd2; + (* VPMULDQ (%_% ymm10) (%_% ymm10) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xd2; + (* VMOVSHDUP (%_% ymm10) (%_% ymm10) *) + 0xc4; 0x43; 0x2d; 0x02; 0xd4; 0xaa; + (* VPBLENDD (%_% ymm10) (%_% ymm10) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xe2; + (* VPSUBD (%_% ymm12) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x3d; 0xfe; 0xc2; + (* VPADDD (%_% ymm8) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xd5; + (* VPADDD (%_% ymm10) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xc5; + (* VPSUBD (%_% ymm8) (%_% ymm8) (%_% ymm13) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x5d; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm6) *) + 0xc5; 0xdd; 0xfe; 0xe6; (* VPADDD (%_% ymm4) (%_% ymm4) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x35; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x35; 0xfe; 0xcb; + (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc5; 0xe5; 0x6c; 0xfd; (* VPUNPCKLQDQ (%_% ymm7) (%_% ymm3) (%_% ymm5) *) + 0xc5; 0xe5; 0x6d; 0xed; (* VPUNPCKHQDQ (%_% ymm5) (%_% ymm3) (%_% ymm5) *) + 0xc4; 0xc1; 0x3d; 0x6c; 0xda; + (* VPUNPCKLQDQ (%_% ymm3) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x3d; 0x6d; 0xd2; + (* VPUNPCKHQDQ (%_% ymm10) (%_% ymm8) (%_% ymm10) *) + 0xc5; 0x5d; 0x6c; 0xc6; (* VPUNPCKLQDQ (%_% ymm8) (%_% ymm4) (%_% ymm6) *) + 0xc5; 0xdd; 0x6d; 0xf6; (* VPUNPCKHQDQ (%_% ymm6) (%_% ymm4) (%_% ymm6) *) + 0xc4; 0xc1; 0x35; 0x6c; 0xe3; + (* VPUNPCKLQDQ (%_% ymm4) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x35; 0x6d; 0xdb; + (* VPUNPCKHQDQ (%_% ymm11) (%_% ymm9) (%_% ymm11) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x60; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,352))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x00; 0x06; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1536))) *) + 0xc4; 0x62; 0x3d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm8) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe0; + (* VMOVSHDUP (%_% ymm12) (%_% ymm8) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x3d; 0x28; 0xc2; + (* VPMULDQ (%_% ymm8) (%_% ymm8) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc0; + (* VMOVSHDUP (%_% ymm8) (%_% ymm8) *) + 0xc4; 0x43; 0x3d; 0x02; 0xc4; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm8) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x45; 0xfa; 0xe0; + (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm8) *) + 0xc5; 0xbd; 0xfe; 0xff; (* VPADDD (%_% ymm7) (%_% ymm8) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xc5; + (* VPADDD (%_% ymm8) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x55; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm6) *) + 0xc5; 0xd5; 0xfe; 0xee; (* VPADDD (%_% ymm5) (%_% ymm5) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0x62; 0x5d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm4) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm12) (%_% ymm4) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x5d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm4) (%_% ymm4) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm4) (%_% ymm4) *) + 0xc4; 0xc3; 0x5d; 0x02; 0xe4; 0xaa; + (* VPBLENDD (%_% ymm4) (%_% ymm4) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x65; 0xfa; 0xe4; (* VPSUBD (%_% ymm12) (%_% ymm3) (%_% ymm4) *) + 0xc5; 0xe5; 0xfe; 0xdc; (* VPADDD (%_% ymm3) (%_% ymm3) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xe5; + (* VPADDD (%_% ymm4) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x65; 0xfa; 0xdd; + (* VPSUBD (%_% ymm3) (%_% ymm3) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x2d; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm10) (%_% ymm11) *) + 0xc4; 0x41; 0x2d; 0xfe; 0xd3; + (* VPADDD (%_% ymm10) (%_% ymm10) (%_% ymm11) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x2d; 0xfa; 0xd5; + (* VPSUBD (%_% ymm10) (%_% ymm10) (%_% ymm13) *) + 0xc4; 0x41; 0x7e; 0x12; 0xc8; + (* VMOVSLDUP (%_% ymm9) (%_% ymm8) *) + 0xc4; 0x43; 0x45; 0x02; 0xc9; 0xaa; + (* VPBLENDD (%_% ymm9) (%_% ymm7) (%_% ymm9) (Imm8 (word 170)) *) + 0xc5; 0xc5; 0x73; 0xd7; 0x20; + (* VPSRLQ (%_% ymm7) (%_% ymm7) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x45; 0x02; 0xc0; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm7) (%_% ymm8) (Imm8 (word 170)) *) + 0xc5; 0xfe; 0x12; 0xfe; (* VMOVSLDUP (%_% ymm7) (%_% ymm6) *) + 0xc4; 0xe3; 0x55; 0x02; 0xff; 0xaa; + (* VPBLENDD (%_% ymm7) (%_% ymm5) (%_% ymm7) (Imm8 (word 170)) *) + 0xc5; 0xd5; 0x73; 0xd5; 0x20; + (* VPSRLQ (%_% ymm5) (%_% ymm5) (Imm8 (word 32)) *) + 0xc4; 0xe3; 0x55; 0x02; 0xf6; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm5) (%_% ymm6) (Imm8 (word 170)) *) + 0xc5; 0xfe; 0x12; 0xec; (* VMOVSLDUP (%_% ymm5) (%_% ymm4) *) + 0xc4; 0xe3; 0x65; 0x02; 0xed; 0xaa; + (* VPBLENDD (%_% ymm5) (%_% ymm3) (%_% ymm5) (Imm8 (word 170)) *) + 0xc5; 0xe5; 0x73; 0xd3; 0x20; + (* VPSRLQ (%_% ymm3) (%_% ymm3) (Imm8 (word 32)) *) + 0xc4; 0xe3; 0x65; 0x02; 0xe4; 0xaa; + (* VPBLENDD (%_% ymm4) (%_% ymm3) (%_% ymm4) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x7e; 0x12; 0xdb; + (* VMOVSLDUP (%_% ymm3) (%_% ymm11) *) + 0xc4; 0xe3; 0x2d; 0x02; 0xdb; 0xaa; + (* VPBLENDD (%_% ymm3) (%_% ymm10) (%_% ymm3) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x2d; 0x73; 0xd2; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm10) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x2d; 0x02; 0xdb; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm10) (%_% ymm11) (Imm8 (word 170)) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0xe0; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,480))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x80; 0x06; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1664))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x55; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm5) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe5; (* VMOVSHDUP (%_% ymm12) (%_% ymm5) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x55; 0x28; 0xea; + (* VPMULDQ (%_% ymm5) (%_% ymm5) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xed; (* VMOVSHDUP (%_% ymm5) (%_% ymm5) *) + 0xc4; 0xc3; 0x55; 0x02; 0xec; 0xaa; + (* VPBLENDD (%_% ymm5) (%_% ymm5) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x35; 0xfa; 0xe5; (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm5) *) + 0xc5; 0x35; 0xfe; 0xcd; (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm5) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xed; + (* VPADDD (%_% ymm5) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc4; 0x62; 0x5d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm4) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm12) (%_% ymm4) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x5d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm4) (%_% ymm4) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm4) (%_% ymm4) *) + 0xc4; 0xc3; 0x5d; 0x02; 0xe4; 0xaa; + (* VPBLENDD (%_% ymm4) (%_% ymm4) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x3d; 0xfa; 0xe4; (* VPSUBD (%_% ymm12) (%_% ymm8) (%_% ymm4) *) + 0xc5; 0x3d; 0xfe; 0xc4; (* VPADDD (%_% ymm8) (%_% ymm8) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xe5; + (* VPADDD (%_% ymm4) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xc5; + (* VPSUBD (%_% ymm8) (%_% ymm8) (%_% ymm13) *) + 0xc4; 0x62; 0x65; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm3) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe3; (* VMOVSHDUP (%_% ymm12) (%_% ymm3) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x65; 0x28; 0xda; + (* VPMULDQ (%_% ymm3) (%_% ymm3) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xdb; (* VMOVSHDUP (%_% ymm3) (%_% ymm3) *) + 0xc4; 0xc3; 0x65; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm3) (%_% ymm3) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x45; 0xfa; 0xe3; (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm3) *) + 0xc5; 0xc5; 0xfe; 0xfb; (* VPADDD (%_% ymm7) (%_% ymm7) (%_% ymm3) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm3) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x4d; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm6) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xf6; (* VPADDD (%_% ymm6) (%_% ymm11) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x4d; 0xfa; 0xf5; + (* VPSUBD (%_% ymm6) (%_% ymm6) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x60; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,608))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x00; 0x07; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1792))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x45; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm7) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe7; (* VMOVSHDUP (%_% ymm12) (%_% ymm7) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x45; 0x28; 0xfa; + (* VPMULDQ (%_% ymm7) (%_% ymm7) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xff; (* VMOVSHDUP (%_% ymm7) (%_% ymm7) *) + 0xc4; 0xc3; 0x45; 0x02; 0xfc; 0xaa; + (* VPBLENDD (%_% ymm7) (%_% ymm7) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x35; 0xfa; 0xe7; (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm7) *) + 0xc5; 0x35; 0xfe; 0xcf; (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xfd; + (* VPADDD (%_% ymm7) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x3d; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm8) (%_% ymm6) *) + 0xc5; 0x3d; 0xfe; 0xc6; (* VPADDD (%_% ymm8) (%_% ymm8) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xc5; + (* VPSUBD (%_% ymm8) (%_% ymm8) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0xe0; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,736))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x80; 0x07; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1920))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x65; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm3) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe3; (* VMOVSHDUP (%_% ymm12) (%_% ymm3) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x65; 0x28; 0xda; + (* VPMULDQ (%_% ymm3) (%_% ymm3) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xdb; (* VMOVSHDUP (%_% ymm3) (%_% ymm3) *) + 0xc4; 0xc3; 0x65; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm3) (%_% ymm3) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x55; 0xfa; 0xe3; (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm3) *) + 0xc5; 0xd5; 0xfe; 0xeb; (* VPADDD (%_% ymm5) (%_% ymm5) (%_% ymm3) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm3) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x5d; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xe4; (* VPADDD (%_% ymm4) (%_% ymm11) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x60; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,864))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x00; 0x08; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,2048))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x3d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm8) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe0; + (* VMOVSHDUP (%_% ymm12) (%_% ymm8) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x3d; 0x28; 0xc2; + (* VPMULDQ (%_% ymm8) (%_% ymm8) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc0; + (* VMOVSHDUP (%_% ymm8) (%_% ymm8) *) + 0xc4; 0x43; 0x3d; 0x02; 0xc4; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm8) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x35; 0xfa; 0xe0; + (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm8) *) + 0xc4; 0x41; 0x35; 0xfe; 0xc8; + (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm8) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xc5; + (* VPADDD (%_% ymm8) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0xe0; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,992))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x80; 0x08; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,2176))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x45; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm6) *) + 0xc5; 0xc5; 0xfe; 0xfe; (* VPADDD (%_% ymm7) (%_% ymm7) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x60; 0x04; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,1120))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x00; 0x09; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,2304))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x5d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm4) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm12) (%_% ymm4) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x5d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm4) (%_% ymm4) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm4) (%_% ymm4) *) + 0xc4; 0xc3; 0x5d; 0x02; 0xe4; 0xaa; + (* VPBLENDD (%_% ymm4) (%_% ymm4) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x55; 0xfa; 0xe4; (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm4) *) + 0xc5; 0xd5; 0xfe; 0xec; (* VPADDD (%_% ymm5) (%_% ymm5) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xe5; + (* VPADDD (%_% ymm4) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0xe0; 0x04; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,1248))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x80; 0x09; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,2432))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x65; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm3) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xdb; (* VPADDD (%_% ymm3) (%_% ymm11) (%_% ymm3) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x65; 0xfa; 0xdd; + (* VPSUBD (%_% ymm3) (%_% ymm3) (%_% ymm13) *) + 0xc5; 0x7d; 0x7f; 0x8f; 0x00; 0x02; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,512))) (%_% ymm9) *) + 0xc5; 0x7d; 0x7f; 0x87; 0x20; 0x02; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,544))) (%_% ymm8) *) + 0xc5; 0xfd; 0x7f; 0xbf; 0x40; 0x02; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,576))) (%_% ymm7) *) + 0xc5; 0xfd; 0x7f; 0xb7; 0x60; 0x02; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,608))) (%_% ymm6) *) + 0xc5; 0xfd; 0x7f; 0xaf; 0x80; 0x02; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,640))) (%_% ymm5) *) + 0xc5; 0xfd; 0x7f; 0xa7; 0xa0; 0x02; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,672))) (%_% ymm4) *) + 0xc5; 0xfd; 0x7f; 0x9f; 0xc0; 0x02; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,704))) (%_% ymm3) *) + 0xc5; 0x7d; 0x7f; 0x9f; 0xe0; 0x02; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,736))) (%_% ymm11) *) + 0xc5; 0xfd; 0x6f; 0xa7; 0x00; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm4) (Memop Word256 (%% (rdi,768))) *) + 0xc5; 0xfd; 0x6f; 0xaf; 0x20; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm5) (Memop Word256 (%% (rdi,800))) *) + 0xc5; 0xfd; 0x6f; 0xb7; 0x40; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm6) (Memop Word256 (%% (rdi,832))) *) + 0xc5; 0xfd; 0x6f; 0xbf; 0x60; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm7) (Memop Word256 (%% (rdi,864))) *) + 0xc5; 0x7d; 0x6f; 0x87; 0x80; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm8) (Memop Word256 (%% (rdi,896))) *) + 0xc5; 0x7d; 0x6f; 0x8f; 0xa0; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm9) (Memop Word256 (%% (rdi,928))) *) + 0xc5; 0x7d; 0x6f; 0x97; 0xc0; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm10) (Memop Word256 (%% (rdi,960))) *) + 0xc5; 0x7d; 0x6f; 0x9f; 0xe0; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm11) (Memop Word256 (%% (rdi,992))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x8e; 0x9c; 0x00; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm1) (Memop Doubleword (%% (rsi,156))) *) + 0xc4; 0xe2; 0x7d; 0x58; 0x96; 0x3c; 0x05; 0x00; 0x00; + (* VPBROADCASTD (%_% ymm2) (Memop Doubleword (%% (rsi,1340))) *) + 0xc4; 0x62; 0x3d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm8) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe0; + (* VMOVSHDUP (%_% ymm12) (%_% ymm8) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x3d; 0x28; 0xc2; + (* VPMULDQ (%_% ymm8) (%_% ymm8) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc0; + (* VMOVSHDUP (%_% ymm8) (%_% ymm8) *) + 0xc4; 0x43; 0x3d; 0x02; 0xc4; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm8) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x5d; 0xfa; 0xe0; + (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm8) *) + 0xc5; 0xbd; 0xfe; 0xe4; (* VPADDD (%_% ymm4) (%_% ymm8) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xc5; + (* VPADDD (%_% ymm8) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc4; 0x62; 0x35; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm9) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe1; + (* VMOVSHDUP (%_% ymm12) (%_% ymm9) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x35; 0x28; 0xca; + (* VPMULDQ (%_% ymm9) (%_% ymm9) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc9; + (* VMOVSHDUP (%_% ymm9) (%_% ymm9) *) + 0xc4; 0x43; 0x35; 0x02; 0xcc; 0xaa; + (* VPBLENDD (%_% ymm9) (%_% ymm9) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x55; 0xfa; 0xe1; + (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm9) *) + 0xc5; 0xb5; 0xfe; 0xed; (* VPADDD (%_% ymm5) (%_% ymm9) (%_% ymm5) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xcd; + (* VPADDD (%_% ymm9) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0x62; 0x2d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm10) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe2; + (* VMOVSHDUP (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x2d; 0x28; 0xd2; + (* VPMULDQ (%_% ymm10) (%_% ymm10) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xd2; + (* VMOVSHDUP (%_% ymm10) (%_% ymm10) *) + 0xc4; 0x43; 0x2d; 0x02; 0xd4; 0xaa; + (* VPBLENDD (%_% ymm10) (%_% ymm10) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x4d; 0xfa; 0xe2; + (* VPSUBD (%_% ymm12) (%_% ymm6) (%_% ymm10) *) + 0xc5; 0xad; 0xfe; 0xf6; (* VPADDD (%_% ymm6) (%_% ymm10) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xd5; + (* VPADDD (%_% ymm10) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x4d; 0xfa; 0xf5; + (* VPSUBD (%_% ymm6) (%_% ymm6) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x45; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xff; (* VPADDD (%_% ymm7) (%_% ymm11) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc4; 0xc3; 0x5d; 0x46; 0xd8; 0x20; + (* VPERM2I128 (%_% ymm3) (%_% ymm4) (%_% ymm8) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x5d; 0x46; 0xc0; 0x31; + (* VPERM2I128 (%_% ymm8) (%_% ymm4) (%_% ymm8) (Imm8 (word 49)) *) + 0xc4; 0xc3; 0x55; 0x46; 0xe1; 0x20; + (* VPERM2I128 (%_% ymm4) (%_% ymm5) (%_% ymm9) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x55; 0x46; 0xc9; 0x31; + (* VPERM2I128 (%_% ymm9) (%_% ymm5) (%_% ymm9) (Imm8 (word 49)) *) + 0xc4; 0xc3; 0x4d; 0x46; 0xea; 0x20; + (* VPERM2I128 (%_% ymm5) (%_% ymm6) (%_% ymm10) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x4d; 0x46; 0xd2; 0x31; + (* VPERM2I128 (%_% ymm10) (%_% ymm6) (%_% ymm10) (Imm8 (word 49)) *) + 0xc4; 0xc3; 0x45; 0x46; 0xf3; 0x20; + (* VPERM2I128 (%_% ymm6) (%_% ymm7) (%_% ymm11) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x45; 0x46; 0xdb; 0x31; + (* VPERM2I128 (%_% ymm11) (%_% ymm7) (%_% ymm11) (Imm8 (word 49)) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x00; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,256))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0xa0; 0x05; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1440))) *) + 0xc4; 0x62; 0x55; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm5) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe5; (* VMOVSHDUP (%_% ymm12) (%_% ymm5) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x55; 0x28; 0xea; + (* VPMULDQ (%_% ymm5) (%_% ymm5) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xed; (* VMOVSHDUP (%_% ymm5) (%_% ymm5) *) + 0xc4; 0xc3; 0x55; 0x02; 0xec; 0xaa; + (* VPBLENDD (%_% ymm5) (%_% ymm5) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x65; 0xfa; 0xe5; (* VPSUBD (%_% ymm12) (%_% ymm3) (%_% ymm5) *) + 0xc5; 0xe5; 0xfe; 0xdd; (* VPADDD (%_% ymm3) (%_% ymm3) (%_% ymm5) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xed; + (* VPADDD (%_% ymm5) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x65; 0xfa; 0xdd; + (* VPSUBD (%_% ymm3) (%_% ymm3) (%_% ymm13) *) + 0xc4; 0x62; 0x2d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm10) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe2; + (* VMOVSHDUP (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x2d; 0x28; 0xd2; + (* VPMULDQ (%_% ymm10) (%_% ymm10) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xd2; + (* VMOVSHDUP (%_% ymm10) (%_% ymm10) *) + 0xc4; 0x43; 0x2d; 0x02; 0xd4; 0xaa; + (* VPBLENDD (%_% ymm10) (%_% ymm10) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xe2; + (* VPSUBD (%_% ymm12) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x3d; 0xfe; 0xc2; + (* VPADDD (%_% ymm8) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xd5; + (* VPADDD (%_% ymm10) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xc5; + (* VPSUBD (%_% ymm8) (%_% ymm8) (%_% ymm13) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x5d; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm6) *) + 0xc5; 0xdd; 0xfe; 0xe6; (* VPADDD (%_% ymm4) (%_% ymm4) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x35; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x35; 0xfe; 0xcb; + (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc5; 0xe5; 0x6c; 0xfd; (* VPUNPCKLQDQ (%_% ymm7) (%_% ymm3) (%_% ymm5) *) + 0xc5; 0xe5; 0x6d; 0xed; (* VPUNPCKHQDQ (%_% ymm5) (%_% ymm3) (%_% ymm5) *) + 0xc4; 0xc1; 0x3d; 0x6c; 0xda; + (* VPUNPCKLQDQ (%_% ymm3) (%_% ymm8) (%_% ymm10) *) + 0xc4; 0x41; 0x3d; 0x6d; 0xd2; + (* VPUNPCKHQDQ (%_% ymm10) (%_% ymm8) (%_% ymm10) *) + 0xc5; 0x5d; 0x6c; 0xc6; (* VPUNPCKLQDQ (%_% ymm8) (%_% ymm4) (%_% ymm6) *) + 0xc5; 0xdd; 0x6d; 0xf6; (* VPUNPCKHQDQ (%_% ymm6) (%_% ymm4) (%_% ymm6) *) + 0xc4; 0xc1; 0x35; 0x6c; 0xe3; + (* VPUNPCKLQDQ (%_% ymm4) (%_% ymm9) (%_% ymm11) *) + 0xc4; 0x41; 0x35; 0x6d; 0xdb; + (* VPUNPCKHQDQ (%_% ymm11) (%_% ymm9) (%_% ymm11) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x80; 0x01; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,384))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x20; 0x06; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1568))) *) + 0xc4; 0x62; 0x3d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm8) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe0; + (* VMOVSHDUP (%_% ymm12) (%_% ymm8) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x3d; 0x28; 0xc2; + (* VPMULDQ (%_% ymm8) (%_% ymm8) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc0; + (* VMOVSHDUP (%_% ymm8) (%_% ymm8) *) + 0xc4; 0x43; 0x3d; 0x02; 0xc4; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm8) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x45; 0xfa; 0xe0; + (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm8) *) + 0xc5; 0xbd; 0xfe; 0xff; (* VPADDD (%_% ymm7) (%_% ymm8) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xc5; + (* VPADDD (%_% ymm8) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x55; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm6) *) + 0xc5; 0xd5; 0xfe; 0xee; (* VPADDD (%_% ymm5) (%_% ymm5) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0x62; 0x5d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm4) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm12) (%_% ymm4) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0xe2; 0x5d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm4) (%_% ymm4) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm4) (%_% ymm4) *) + 0xc4; 0xc3; 0x5d; 0x02; 0xe4; 0xaa; + (* VPBLENDD (%_% ymm4) (%_% ymm4) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x65; 0xfa; 0xe4; (* VPSUBD (%_% ymm12) (%_% ymm3) (%_% ymm4) *) + 0xc5; 0xe5; 0xfe; 0xdc; (* VPADDD (%_% ymm3) (%_% ymm3) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xe5; + (* VPADDD (%_% ymm4) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x65; 0xfa; 0xdd; + (* VPSUBD (%_% ymm3) (%_% ymm3) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x62; 0x1d; 0x28; 0xf1; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm1) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x62; 0x1d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm2) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x2d; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm10) (%_% ymm11) *) + 0xc4; 0x41; 0x2d; 0xfe; 0xd3; + (* VPADDD (%_% ymm10) (%_% ymm10) (%_% ymm11) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x2d; 0xfa; 0xd5; + (* VPSUBD (%_% ymm10) (%_% ymm10) (%_% ymm13) *) + 0xc4; 0x41; 0x7e; 0x12; 0xc8; + (* VMOVSLDUP (%_% ymm9) (%_% ymm8) *) + 0xc4; 0x43; 0x45; 0x02; 0xc9; 0xaa; + (* VPBLENDD (%_% ymm9) (%_% ymm7) (%_% ymm9) (Imm8 (word 170)) *) + 0xc5; 0xc5; 0x73; 0xd7; 0x20; + (* VPSRLQ (%_% ymm7) (%_% ymm7) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x45; 0x02; 0xc0; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm7) (%_% ymm8) (Imm8 (word 170)) *) + 0xc5; 0xfe; 0x12; 0xfe; (* VMOVSLDUP (%_% ymm7) (%_% ymm6) *) + 0xc4; 0xe3; 0x55; 0x02; 0xff; 0xaa; + (* VPBLENDD (%_% ymm7) (%_% ymm5) (%_% ymm7) (Imm8 (word 170)) *) + 0xc5; 0xd5; 0x73; 0xd5; 0x20; + (* VPSRLQ (%_% ymm5) (%_% ymm5) (Imm8 (word 32)) *) + 0xc4; 0xe3; 0x55; 0x02; 0xf6; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm5) (%_% ymm6) (Imm8 (word 170)) *) + 0xc5; 0xfe; 0x12; 0xec; (* VMOVSLDUP (%_% ymm5) (%_% ymm4) *) + 0xc4; 0xe3; 0x65; 0x02; 0xed; 0xaa; + (* VPBLENDD (%_% ymm5) (%_% ymm3) (%_% ymm5) (Imm8 (word 170)) *) + 0xc5; 0xe5; 0x73; 0xd3; 0x20; + (* VPSRLQ (%_% ymm3) (%_% ymm3) (Imm8 (word 32)) *) + 0xc4; 0xe3; 0x65; 0x02; 0xe4; 0xaa; + (* VPBLENDD (%_% ymm4) (%_% ymm3) (%_% ymm4) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x7e; 0x12; 0xdb; + (* VMOVSLDUP (%_% ymm3) (%_% ymm11) *) + 0xc4; 0xe3; 0x2d; 0x02; 0xdb; 0xaa; + (* VPBLENDD (%_% ymm3) (%_% ymm10) (%_% ymm3) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x2d; 0x73; 0xd2; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm10) (Imm8 (word 32)) *) + 0xc4; 0x43; 0x2d; 0x02; 0xdb; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm10) (%_% ymm11) (Imm8 (word 170)) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x00; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,512))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0xa0; 0x06; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1696))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x55; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm5) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe5; (* VMOVSHDUP (%_% ymm12) (%_% ymm5) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x55; 0x28; 0xea; + (* VPMULDQ (%_% ymm5) (%_% ymm5) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xed; (* VMOVSHDUP (%_% ymm5) (%_% ymm5) *) + 0xc4; 0xc3; 0x55; 0x02; 0xec; 0xaa; + (* VPBLENDD (%_% ymm5) (%_% ymm5) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x35; 0xfa; 0xe5; (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm5) *) + 0xc5; 0x35; 0xfe; 0xcd; (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm5) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xed; + (* VPADDD (%_% ymm5) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc4; 0x62; 0x5d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm4) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm12) (%_% ymm4) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x5d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm4) (%_% ymm4) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm4) (%_% ymm4) *) + 0xc4; 0xc3; 0x5d; 0x02; 0xe4; 0xaa; + (* VPBLENDD (%_% ymm4) (%_% ymm4) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x3d; 0xfa; 0xe4; (* VPSUBD (%_% ymm12) (%_% ymm8) (%_% ymm4) *) + 0xc5; 0x3d; 0xfe; 0xc4; (* VPADDD (%_% ymm8) (%_% ymm8) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xe5; + (* VPADDD (%_% ymm4) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xc5; + (* VPSUBD (%_% ymm8) (%_% ymm8) (%_% ymm13) *) + 0xc4; 0x62; 0x65; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm3) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe3; (* VMOVSHDUP (%_% ymm12) (%_% ymm3) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x65; 0x28; 0xda; + (* VPMULDQ (%_% ymm3) (%_% ymm3) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xdb; (* VMOVSHDUP (%_% ymm3) (%_% ymm3) *) + 0xc4; 0xc3; 0x65; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm3) (%_% ymm3) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x45; 0xfa; 0xe3; (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm3) *) + 0xc5; 0xc5; 0xfe; 0xfb; (* VPADDD (%_% ymm7) (%_% ymm7) (%_% ymm3) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm3) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x4d; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm6) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xf6; (* VPADDD (%_% ymm6) (%_% ymm11) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x4d; 0xfa; 0xf5; + (* VPSUBD (%_% ymm6) (%_% ymm6) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x80; 0x02; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,640))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x20; 0x07; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1824))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x45; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm7) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe7; (* VMOVSHDUP (%_% ymm12) (%_% ymm7) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x45; 0x28; 0xfa; + (* VPMULDQ (%_% ymm7) (%_% ymm7) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xff; (* VMOVSHDUP (%_% ymm7) (%_% ymm7) *) + 0xc4; 0xc3; 0x45; 0x02; 0xfc; 0xaa; + (* VPBLENDD (%_% ymm7) (%_% ymm7) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x35; 0xfa; 0xe7; (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm7) *) + 0xc5; 0x35; 0xfe; 0xcf; (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm7) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xfd; + (* VPADDD (%_% ymm7) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x3d; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm8) (%_% ymm6) *) + 0xc5; 0x3d; 0xfe; 0xc6; (* VPADDD (%_% ymm8) (%_% ymm8) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x3d; 0xfa; 0xc5; + (* VPSUBD (%_% ymm8) (%_% ymm8) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x00; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,768))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0xa0; 0x07; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,1952))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x65; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm3) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe3; (* VMOVSHDUP (%_% ymm12) (%_% ymm3) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x65; 0x28; 0xda; + (* VPMULDQ (%_% ymm3) (%_% ymm3) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xdb; (* VMOVSHDUP (%_% ymm3) (%_% ymm3) *) + 0xc4; 0xc3; 0x65; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm3) (%_% ymm3) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x55; 0xfa; 0xe3; (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm3) *) + 0xc5; 0xd5; 0xfe; 0xeb; (* VPADDD (%_% ymm5) (%_% ymm5) (%_% ymm3) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm3) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x5d; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm4) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xe4; (* VPADDD (%_% ymm4) (%_% ymm11) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x5d; 0xfa; 0xe5; + (* VPSUBD (%_% ymm4) (%_% ymm4) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x80; 0x03; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,896))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x20; 0x08; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,2080))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x3d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm8) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe0; + (* VMOVSHDUP (%_% ymm12) (%_% ymm8) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x3d; 0x28; 0xc2; + (* VPMULDQ (%_% ymm8) (%_% ymm8) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xc0; + (* VMOVSHDUP (%_% ymm8) (%_% ymm8) *) + 0xc4; 0x43; 0x3d; 0x02; 0xc4; 0xaa; + (* VPBLENDD (%_% ymm8) (%_% ymm8) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x35; 0xfa; 0xe0; + (* VPSUBD (%_% ymm12) (%_% ymm9) (%_% ymm8) *) + 0xc4; 0x41; 0x35; 0xfe; 0xc8; + (* VPADDD (%_% ymm9) (%_% ymm9) (%_% ymm8) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xc5; + (* VPADDD (%_% ymm8) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0x41; 0x35; 0xfa; 0xcd; + (* VPSUBD (%_% ymm9) (%_% ymm9) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x00; 0x04; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,1024))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0xa0; 0x08; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,2208))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x4d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm6) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe6; (* VMOVSHDUP (%_% ymm12) (%_% ymm6) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x4d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm6) (%_% ymm6) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xf6; (* VMOVSHDUP (%_% ymm6) (%_% ymm6) *) + 0xc4; 0xc3; 0x4d; 0x02; 0xf4; 0xaa; + (* VPBLENDD (%_% ymm6) (%_% ymm6) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x45; 0xfa; 0xe6; (* VPSUBD (%_% ymm12) (%_% ymm7) (%_% ymm6) *) + 0xc5; 0xc5; 0xfe; 0xfe; (* VPADDD (%_% ymm7) (%_% ymm7) (%_% ymm6) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xf5; + (* VPADDD (%_% ymm6) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x45; 0xfa; 0xfd; + (* VPSUBD (%_% ymm7) (%_% ymm7) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x80; 0x04; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,1152))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0x20; 0x09; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,2336))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x5d; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm4) (%_% ymm1) *) + 0xc5; 0x7e; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm12) (%_% ymm4) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0xe2; 0x5d; 0x28; 0xe2; + (* VPMULDQ (%_% ymm4) (%_% ymm4) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc5; 0xfe; 0x16; 0xe4; (* VMOVSHDUP (%_% ymm4) (%_% ymm4) *) + 0xc4; 0xc3; 0x5d; 0x02; 0xe4; 0xaa; + (* VPBLENDD (%_% ymm4) (%_% ymm4) (%_% ymm12) (Imm8 (word 170)) *) + 0xc5; 0x55; 0xfa; 0xe4; (* VPSUBD (%_% ymm12) (%_% ymm5) (%_% ymm4) *) + 0xc5; 0xd5; 0xfe; 0xec; (* VPADDD (%_% ymm5) (%_% ymm5) (%_% ymm4) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0xc1; 0x1d; 0xfe; 0xe5; + (* VPADDD (%_% ymm4) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x55; 0xfa; 0xed; + (* VPSUBD (%_% ymm5) (%_% ymm5) (%_% ymm13) *) + 0xc5; 0xfd; 0x6f; 0x8e; 0x00; 0x05; 0x00; 0x00; + (* VMOVDQA (%_% ymm1) (Memop Word256 (%% (rsi,1280))) *) + 0xc5; 0xfd; 0x6f; 0x96; 0xa0; 0x09; 0x00; 0x00; + (* VMOVDQA (%_% ymm2) (Memop Word256 (%% (rsi,2464))) *) + 0xc5; 0xad; 0x73; 0xd1; 0x20; + (* VPSRLQ (%_% ymm10) (%_% ymm1) (Imm8 (word 32)) *) + 0xc5; 0x7e; 0x16; 0xfa; (* VMOVSHDUP (%_% ymm15) (%_% ymm2) *) + 0xc4; 0x62; 0x25; 0x28; 0xe9; + (* VPMULDQ (%_% ymm13) (%_% ymm11) (%_% ymm1) *) + 0xc4; 0x41; 0x7e; 0x16; 0xe3; + (* VMOVSHDUP (%_% ymm12) (%_% ymm11) *) + 0xc4; 0x42; 0x1d; 0x28; 0xf2; + (* VPMULDQ (%_% ymm14) (%_% ymm12) (%_% ymm10) *) + 0xc4; 0x62; 0x25; 0x28; 0xda; + (* VPMULDQ (%_% ymm11) (%_% ymm11) (%_% ymm2) *) + 0xc4; 0x42; 0x1d; 0x28; 0xe7; + (* VPMULDQ (%_% ymm12) (%_% ymm12) (%_% ymm15) *) + 0xc4; 0x62; 0x15; 0x28; 0xe8; + (* VPMULDQ (%_% ymm13) (%_% ymm13) (%_% ymm0) *) + 0xc4; 0x62; 0x0d; 0x28; 0xf0; + (* VPMULDQ (%_% ymm14) (%_% ymm14) (%_% ymm0) *) + 0xc4; 0x41; 0x7e; 0x16; 0xdb; + (* VMOVSHDUP (%_% ymm11) (%_% ymm11) *) + 0xc4; 0x43; 0x25; 0x02; 0xdc; 0xaa; + (* VPBLENDD (%_% ymm11) (%_% ymm11) (%_% ymm12) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x65; 0xfa; 0xe3; + (* VPSUBD (%_% ymm12) (%_% ymm3) (%_% ymm11) *) + 0xc5; 0xa5; 0xfe; 0xdb; (* VPADDD (%_% ymm3) (%_% ymm11) (%_% ymm3) *) + 0xc4; 0x41; 0x7e; 0x16; 0xed; + (* VMOVSHDUP (%_% ymm13) (%_% ymm13) *) + 0xc4; 0x43; 0x15; 0x02; 0xee; 0xaa; + (* VPBLENDD (%_% ymm13) (%_% ymm13) (%_% ymm14) (Imm8 (word 170)) *) + 0xc4; 0x41; 0x1d; 0xfe; 0xdd; + (* VPADDD (%_% ymm11) (%_% ymm12) (%_% ymm13) *) + 0xc4; 0xc1; 0x65; 0xfa; 0xdd; + (* VPSUBD (%_% ymm3) (%_% ymm3) (%_% ymm13) *) + 0xc5; 0x7d; 0x7f; 0x8f; 0x00; 0x03; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,768))) (%_% ymm9) *) + 0xc5; 0x7d; 0x7f; 0x87; 0x20; 0x03; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,800))) (%_% ymm8) *) + 0xc5; 0xfd; 0x7f; 0xbf; 0x40; 0x03; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,832))) (%_% ymm7) *) + 0xc5; 0xfd; 0x7f; 0xb7; 0x60; 0x03; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,864))) (%_% ymm6) *) + 0xc5; 0xfd; 0x7f; 0xaf; 0x80; 0x03; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,896))) (%_% ymm5) *) + 0xc5; 0xfd; 0x7f; 0xa7; 0xa0; 0x03; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,928))) (%_% ymm4) *) + 0xc5; 0xfd; 0x7f; 0x9f; 0xc0; 0x03; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,960))) (%_% ymm3) *) + 0xc5; 0x7d; 0x7f; 0x9f; 0xe0; 0x03; 0x00; 0x00; + (* VMOVDQA (Memop Word256 (%% (rdi,992))) (%_% ymm11) *) + 0xc3 (* RET *) +];; +(*** BYTECODE END ***) + +let mldsa_ntt_tmc = define_trimmed "mldsa_ntt_tmc" mldsa_ntt_mc;; +let MLDSA_NTT_TMC_EXEC = X86_MK_CORE_EXEC_RULE mldsa_ntt_tmc;; + +(* ------------------------------------------------------------------------- *) +(* Correctness proof. *) +(* ------------------------------------------------------------------------- *) + +(*** + *** Currently, there is a discrepency when compiling the asmb on x86 machines vs Arm + *** As such, the produced mldsa_ntt_tmc has different lengths. When on ARM 0x3049 + *** when on x86 0x3079. + ***) + +let MLDSA_NTT_CORRECT = prove + (`!a zetas (zetas_list:int32 list) x pc. + aligned 32 a /\ + aligned 32 zetas /\ + nonoverlapping (word pc,0x3049) (a, 1024) /\ + nonoverlapping (word pc,0x3049) (zetas, 2496) /\ + nonoverlapping (a, 1024) (zetas, 2496) + ==> ensures x86 + (\s. bytes_loaded s (word pc) (BUTLAST mldsa_ntt_tmc) /\ + read RIP s = word pc /\ + C_ARGUMENTS [a; zetas] s /\ + wordlist_from_memory(zetas,624) s = MAP (iword: int -> 32 word) mldsa_complete_qdata /\ + (!i. i < 256 ==> abs(ival(x i)) <= &8380416) /\ + !i. i < 256 + ==> read(memory :> bytes32(word_add a (word(4 * i)))) s = + x i) + (\s. read RIP s = word(pc + 0x3048) /\ + (!i. i < 256 + ==> let zi = + read(memory :> bytes32(word_add a (word(4 * i)))) s in + (ival zi == mldsa_forward_ntt (ival o x) i) (mod &8380417) /\ + abs(ival zi) <= &42035261)) + (MAYCHANGE_REGS_AND_FLAGS_PERMITTED_BY_ABI ,, + MAYCHANGE [ZMM0; ZMM1; ZMM4; ZMM5; ZMM6; ZMM7; ZMM8; ZMM9; ZMM10; ZMM11; ZMM12; ZMM13; ZMM14; ZMM15] ,, + MAYCHANGE [RAX] ,, MAYCHANGE SOME_FLAGS ,, + MAYCHANGE [memory :> bytes(a,1024)])`, + +(*** Setup - introduce variables and break down assumptions ***) + MAP_EVERY X_GEN_TAC + [`a:int64`; `zetas:int64`; `zetas_list:int32 list`; `x:num->int32`; `pc:num`] THEN + REWRITE_TAC[MAYCHANGE_REGS_AND_FLAGS_PERMITTED_BY_ABI; C_ARGUMENTS; + NONOVERLAPPING_CLAUSES; ALL] THEN + DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN + +(*** Pull out the bounds assumption since we don't need to expand it + *** until much later, and it keeps things a bit smaller and simpler + ***) + + GLOBALIZE_PRECONDITION_TAC THEN + +(*** But do expand all the input[i] = x i assumptions ***) + + CONV_TAC(RATOR_CONV(LAND_CONV(ONCE_DEPTH_CONV EXPAND_CASES_CONV))) THEN + CONV_TAC NUM_REDUCE_CONV THEN + REPEAT STRIP_TAC THEN + + REWRITE_TAC [SOME_FLAGS; fst MLDSA_NTT_TMC_EXEC] THEN + + GHOST_INTRO_TAC `init_ymm0:int256` `read YMM0` THEN + GHOST_INTRO_TAC `init_ymm1:int256` `read YMM1` THEN + GHOST_INTRO_TAC `init_ymm2:int256` `read YMM2` THEN + + ENSURES_INIT_TAC "s0" THEN + +(*** First restructure all the loads from the a pointer ***) + + MP_TAC(end_itlist CONJ (map (fun n -> + READ_MEMORY_MERGE_CONV 3 (subst[mk_small_numeral(32*n),`n:num`] + `read (memory :> bytes256(word_add a (word n))) s0`)) (0--31))) THEN + ASM_REWRITE_TAC[WORD_ADD_0] THEN + DISCARD_MATCHING_ASSUMPTIONS [`read (memory :> bytes32 a) s = x`] THEN + CONV_TAC(LAND_CONV WORD_REDUCE_CONV) THEN STRIP_TAC THEN + +(*** Expand the qdata table ***) + + FIRST_X_ASSUM(MP_TAC o CONV_RULE (LAND_CONV WORDLIST_FROM_MEMORY_CONV)) THEN + REWRITE_TAC[mldsa_complete_qdata; MAP; CONS_11] THEN + STRIP_TAC THEN + +(*** Restructure zeta entries, as before but with WORD_REDUCE_CONV to simplify ***) + + MP_TAC(end_itlist CONJ (map (fun n -> + READ_MEMORY_MERGE_CONV 3 (subst[mk_small_numeral(32*n),`n:num`] + `read (memory :> bytes256(word_add zetas (word n))) s0`)) (0--77))) THEN + ASM_REWRITE_TAC[WORD_ADD_0] THEN + DISCARD_MATCHING_ASSUMPTIONS [`read (memory :> bytes32 a) s = x`] THEN + CONV_TAC(LAND_CONV WORD_REDUCE_CONV) THEN STRIP_TAC THEN + +(*** We've thrown away some of the 32-bit words that are used in + *** broadcast instructions. We could have written a more refined + *** alternative to DISCARD_MATCHING_ASSUMPTIONS above. + *** But here we just recreate them: select the two memory + *** assumptions we want to break apart, then split them up. + ***) + + FIRST_ASSUM(MP_TAC o check + (can (term_match [] `read (memory :> bytes256 (word_add zetas (word 128))) s0 = xxx`) o concl)) THEN + FIRST_ASSUM(MP_TAC o check + (can (term_match [] `read (memory :> bytes256 (word_add zetas (word 1312))) s0 = xxx`) o concl)) THEN + REPLICATE_TAC 2 + (CONV_TAC(LAND_CONV(READ_MEMORY_SPLIT_CONV 3)) THEN + CONV_TAC(LAND_CONV WORD_REDUCE_CONV) THEN STRIP_TAC) THEN + +(*** Do the entire simulation (very slow!) ****) + + MAP_EVERY (fun n -> X86_STEPS_TAC MLDSA_NTT_TMC_EXEC [n] THEN + SIMD_SIMPLIFY_ABBREV_TAC[mldsa_montmul] + [WORD_ADD_MLDSA_MONTMUL; + WORD_ADD_MLDSA_MONTMUL_ALT; WORD_SUB_MLDSA_MONTMUL]) + (1--2337) THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN + +(**** Reverse the restructuring by splitting the 256-bit words up ***) + + REPEAT(FIRST_X_ASSUM(STRIP_ASSUME_TAC o + CONV_RULE(SIMD_SIMPLIFY_CONV[]) o + CONV_RULE(READ_MEMORY_SPLIT_CONV 3) o + check (can (term_match [] `read qqq s:int256 = xxx`) o concl))) THEN + +(*** Expand the cases in the conclusion (leave the let-terms for now)***) + + CONV_TAC EXPAND_CASES_CONV THEN + CONV_TAC(ONCE_DEPTH_CONV NUM_MULT_CONV) THEN + REWRITE_TAC[INT_ABS_BOUNDS; WORD_ADD_0] THEN + +(*** Rewrite with assumptions then throw them away ***) + + ASM_REWRITE_TAC[] THEN DISCARD_STATE_TAC "s2337" THEN + +(*** Remove one other non-arithmetical oddity ***) + + W(fun (asl,w) -> + let asms = + map snd (filter (is_local_definition [mldsa_montmul] o concl o snd) asl) in + MP_TAC(end_itlist CONJ (rev asms)) THEN + MAP_EVERY (fun t -> UNDISCH_THEN (concl t) (K ALL_TAC)) asms) THEN + + REWRITE_TAC[WORD_BLAST `word_subword (x:int64) (0,64) = x`] THEN + REWRITE_TAC[WORD_BLAST + `word_subword (word_ushr (word_join (h:int32) (l:int32):int64) 32) (0,32) = + h`] THEN + + STRIP_TAC THEN + +(*** Try splitting into 256 subgoals and applying CONGBOUND ***) + + CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + REWRITE_TAC[GSYM CONJ_ASSOC] THEN + + W(fun (asl,w) -> + let lfn = PROCESS_BOUND_ASSUMPTIONS + (CONJUNCTS(tryfind (CONV_RULE EXPAND_CASES_CONV o snd) asl)) + and asms = + map snd (filter (is_local_definition [mldsa_montmul] o concl o snd) asl) in + let lfn' = LOCAL_CONGBOUND_RULE lfn (rev asms) in + + REPEAT(GEN_REWRITE_TAC I + [TAUT `p /\ q /\ r /\ s <=> (p /\ q /\ r) /\ s`] THEN CONJ_TAC) THEN + W(MP_TAC o ASM_CONGBOUND_RULE lfn' o rand o lhand o rator o lhand o snd) THEN + (MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL + [REWRITE_TAC[INVERSE_MOD_CONV `inverse_mod 8380417 4294967296`] THEN + MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] INT_CONG_TRANS) THEN + CONV_TAC(ONCE_DEPTH_CONV MLDSA_FORWARD_NTT_CONV) THEN + REWRITE_TAC[GSYM INT_REM_EQ; o_THM] THEN CONV_TAC INT_REM_DOWN_CONV THEN + REWRITE_TAC[INT_REM_EQ] THEN + REWRITE_TAC[REAL_INT_CONGRUENCE; INT_OF_NUM_EQ; ARITH_EQ] THEN + REWRITE_TAC[GSYM REAL_OF_INT_CLAUSES] THEN + CONV_TAC(RAND_CONV REAL_POLY_CONV) THEN REAL_INTEGER_TAC; + MATCH_MP_TAC(INT_ARITH + `l':int <= l /\ u <= u' + ==> l <= x /\ x <= u ==> l' <= x /\ x <= u'`) THEN + CONV_TAC INT_REDUCE_CONV])));; + +(* ------------------------------------------------------------------------- *) +(* Subroutine correctness theorems. *) +(* ------------------------------------------------------------------------- *) + +(* NOTE: This must be kept in sync with the CBMC specification + * in mldsa/src/native/x86_64/src/arith_native_x86_64.h *) + +let MLDSA_NTT_NOIBT_SUBROUTINE_CORRECT = prove + (`!a zetas (zetas_list:int32 list) x pc stackpointer returnaddress. + aligned 32 a /\ + aligned 32 zetas /\ + nonoverlapping (word pc,LENGTH mldsa_ntt_tmc) (a, 1024) /\ + nonoverlapping (word pc,LENGTH mldsa_ntt_tmc) (zetas, 2496) /\ + nonoverlapping (a, 1024) (zetas, 2496) /\ + nonoverlapping (stackpointer,8) (a, 1024) /\ + nonoverlapping (stackpointer,8) (zetas, 2496) + ==> ensures x86 + (\s. bytes_loaded s (word pc) mldsa_ntt_tmc /\ + read RIP s = word pc /\ + read RSP s = stackpointer /\ + read (memory :> bytes64 stackpointer) s = returnaddress /\ + C_ARGUMENTS [a; zetas] s /\ + wordlist_from_memory(zetas,624) s = MAP (iword: int -> 32 word) mldsa_complete_qdata /\ + (!i. i < 256 ==> abs(ival(x i)) <= &8380416) /\ + !i. i < 256 + ==> read(memory :> bytes32(word_add a (word(4 * i)))) s = + x i) + (\s. read RIP s = returnaddress /\ + read RSP s = word_add stackpointer (word 8) /\ + (!i. i < 256 + ==> let zi = + read(memory :> bytes32(word_add a (word(4 * i)))) s in + (ival zi == mldsa_forward_ntt (ival o x) i) (mod &8380417) /\ + abs(ival zi) <= &42035261)) + (MAYCHANGE [RSP] ,, MAYCHANGE_REGS_AND_FLAGS_PERMITTED_BY_ABI ,, + MAYCHANGE [memory :> bytes(a,1024)])`, + let TWEAK_CONV = ONCE_DEPTH_CONV WORDLIST_FROM_MEMORY_CONV in + CONV_TAC TWEAK_CONV THEN + X86_PROMOTE_RETURN_NOSTACK_TAC mldsa_ntt_tmc (CONV_RULE TWEAK_CONV MLDSA_NTT_CORRECT));; + +let MLDSA_NTT_SUBROUTINE_CORRECT = prove + (`!a zetas (zetas_list:int32 list) x pc stackpointer returnaddress. + aligned 32 a /\ + aligned 32 zetas /\ + nonoverlapping (word pc,LENGTH mldsa_ntt_mc) (a, 1024) /\ + nonoverlapping (word pc,LENGTH mldsa_ntt_mc) (zetas, 2496) /\ + nonoverlapping (a, 1024) (zetas, 2496) /\ + nonoverlapping (stackpointer,8) (a, 1024) /\ + nonoverlapping (stackpointer,8) (zetas, 2496) + ==> ensures x86 + (\s. bytes_loaded s (word pc) mldsa_ntt_mc /\ + read RIP s = word pc /\ + read RSP s = stackpointer /\ + read (memory :> bytes64 stackpointer) s = returnaddress /\ + C_ARGUMENTS [a; zetas] s /\ + wordlist_from_memory(zetas,624) s = MAP (iword: int -> 32 word) mldsa_complete_qdata /\ + (!i. i < 256 ==> abs(ival(x i)) <= &8380416) /\ + !i. i < 256 + ==> read(memory :> bytes32(word_add a (word(4 * i)))) s = + x i) + (\s. read RIP s = returnaddress /\ + read RSP s = word_add stackpointer (word 8) /\ + (!i. i < 256 + ==> let zi = + read(memory :> bytes32(word_add a (word(4 * i)))) s in + (ival zi == mldsa_forward_ntt (ival o x) i) (mod &8380417) /\ + abs(ival zi) <= &42035261)) + (MAYCHANGE [RSP] ,, MAYCHANGE_REGS_AND_FLAGS_PERMITTED_BY_ABI ,, + MAYCHANGE [memory :> bytes(a,1024)])`, + let TWEAK_CONV = ONCE_DEPTH_CONV WORDLIST_FROM_MEMORY_CONV in + CONV_TAC TWEAK_CONV THEN + MATCH_ACCEPT_TAC(ADD_IBT_RULE + (CONV_RULE TWEAK_CONV MLDSA_NTT_NOIBT_SUBROUTINE_CORRECT)));; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/mldsa_specs.ml b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/mldsa_specs.ml new file mode 100644 index 0000000000..1b32200e53 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/mldsa_specs.ml @@ -0,0 +1,678 @@ +(* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 + *) + +(* ========================================================================= *) +(* Common specifications and tactics for ML-DSA, mainly related to the NTT. *) +(* ========================================================================= *) + +needs "Library/words.ml";; +needs "Library/isum.ml";; + +(* ------------------------------------------------------------------------- *) +(* The pure forms of forward and inverse NTT with no reordering. *) +(* ------------------------------------------------------------------------- *) + +let pure_forward_ntt_mldsa = define + `pure_forward_ntt_mldsa f k = + isum (0..127) (\j. f(2 * j + k MOD 2) * + &1753 pow ((2 * k DIV 2 + 1) * j)) + rem &8380417`;; + +(* ------------------------------------------------------------------------- *) +(* Bit-reversing order as used in the standard/default order. *) +(* ------------------------------------------------------------------------- *) + +let bitreverse8 = define + `bitreverse8(n) = val(word_reversefields 1 (word n:8 word))`;; + +(* ------------------------------------------------------------------------- *) +(* AVX2-optimized ordering for ML-DSA NTT (swaps bit fields then reverses) *) +(* ------------------------------------------------------------------------- *) + +let mldsa_avx2_ntt_order = define + `mldsa_avx2_ntt_order i = + bitreverse8(64 * (i DIV 64) + ((i MOD 64) DIV 8) + 8 * (i MOD 8))`;; + +(* ------------------------------------------------------------------------- *) +(* Conversion of each element of an array to Montgomery form with B = 2^16. *) +(* ------------------------------------------------------------------------- *) + +let tomont_8380417 = define + `tomont_8380417 (a:num->int) = \i. (&2 pow 32 * a i) rem &8380417`;; + +(* ------------------------------------------------------------------------- *) +(* The precise specs of the actual x86 code. *) +(* ------------------------------------------------------------------------- *) + +let mldsa_forward_ntt = define + `mldsa_forward_ntt f k = + isum (0..255) (\j. f j * &1753 pow ((2 * mldsa_avx2_ntt_order k + 1) * j)) + rem &8380417`;; + +(* ------------------------------------------------------------------------- *) +(* Show how these relate to the "pure" ones. *) +(* ------------------------------------------------------------------------- *) + +let MLDSA_FORWARD_NTT = prove + (`mldsa_forward_ntt f k = + isum (0..255) (\j. f j * &1753 pow ((2 * mldsa_avx2_ntt_order k + 1) * j)) rem &8380417`, + REWRITE_TAC[mldsa_forward_ntt]);; + +(* ------------------------------------------------------------------------- *) +(* Explicit computation rules to evaluate mod-8380417 powers less naively. *) +(* ------------------------------------------------------------------------- *) + +let BITREVERSE8_CLAUSES = end_itlist CONJ (map + (GEN_REWRITE_CONV I [bitreverse8] THENC DEPTH_CONV WORD_NUM_RED_CONV) + (map (curry mk_comb `bitreverse8` o mk_small_numeral) (0--255)));; + +let MLDSA_AVX2_NTT_ORDER_CLAUSES = end_itlist CONJ (map + (GEN_REWRITE_CONV I [mldsa_avx2_ntt_order] THENC DEPTH_CONV WORD_NUM_RED_CONV THENC + GEN_REWRITE_CONV I [BITREVERSE8_CLAUSES]) + (map (curry mk_comb `mldsa_avx2_ntt_order` o mk_small_numeral) (0--255)));; + +let MLDSA_FORWARD_NTT_ALT = prove + (`mldsa_forward_ntt f k = + isum (0..255) + (\j. f j * + (&1753 pow ((2 * mldsa_avx2_ntt_order k + 1) * j)) rem &8380417) + rem &8380417`, + REWRITE_TAC[mldsa_forward_ntt] THEN MATCH_MP_TAC + (REWRITE_RULE[] (ISPEC + `(\x y. x rem &8380417 = y rem &8380417)` ISUM_RELATED)) THEN + REWRITE_TAC[INT_REM_EQ; FINITE_NUMSEG; INT_CONG_ADD] THEN + X_GEN_TAC `i:num` THEN DISCH_TAC THEN + REWRITE_TAC[GSYM INT_OF_NUM_REM; GSYM INT_OF_NUM_CLAUSES; + GSYM INT_REM_EQ] THEN + CONV_TAC INT_REM_DOWN_CONV THEN + AP_THM_TAC THEN AP_TERM_TAC THEN CONV_TAC INT_ARITH);; + +let MLDSA_FORWARD_NTT_CONV = + GEN_REWRITE_CONV I [MLDSA_FORWARD_NTT_ALT] THENC + LAND_CONV EXPAND_ISUM_CONV THENC + DEPTH_CONV NUM_RED_CONV THENC + GEN_REWRITE_CONV ONCE_DEPTH_CONV [MLDSA_AVX2_NTT_ORDER_CLAUSES] THENC + DEPTH_CONV NUM_RED_CONV THENC + GEN_REWRITE_CONV DEPTH_CONV [INT_OF_NUM_POW; INT_OF_NUM_REM] THENC + ONCE_DEPTH_CONV EXP_MOD_CONV THENC INT_REDUCE_CONV;; + +(* ------------------------------------------------------------------------- *) +(* Abbreviate the Barrett reduction and multiplication and Montgomery *) +(* reduction patterns in the code. *) +(* ------------------------------------------------------------------------- *) + +let mldsa_barred = define + `(mldsa_barred:int32->int32) x = + word_sub x + (word_mul + (word_ishr (word_add x (word 4194304)) 23) + (word 8380417))`;; + +let mldsa_montred = define + `(mldsa_montred:int64->int32) x = + word_subword + (word_add + (word_mul ((word_sx:int32->int64) + (word_mul (word_subword x (0,32)) (word 4236238847))) + (word 8380417)) + x) + (32,32)`;; + +let mldsa_montmul = define + `mldsa_montmul (a:int64,b:int64) (x:int32) = + word_sub + (word_subword (word_mul (word_sx (x:int32)) a:int64) (32,32):int32) + (word_subword + (word_mul (word_sx + (word_subword (word_mul (word_sx (x:int32)) b:int64) (0,32):int32)) + (word 8380417:int64)) + (32,32))`;; + +let WORD_ADD_MLDSA_MONTMUL = prove + (`word_add y (mldsa_montmul (a,b) x) = + word_sub (word_add + (word_subword (word_mul (word_sx (x:int32)) a:int64) (32,32):int32) + y) + (word_subword + (word_mul (word_sx + (word_subword (word_mul (word_sx (x:int32)) b:int64) (0,32):int32)) + (word 8380417:int64)) + (32,32))`, + REWRITE_TAC[mldsa_montmul] THEN CONV_TAC WORD_RULE);; + +let WORD_SUB_MLDSA_MONTMUL = prove + (`word_sub y (mldsa_montmul (a,b) x) = + word_add (word_sub y + (word_subword (word_mul (word_sx (x:int32)) a:int64) (32,32):int32)) + (word_subword + (word_mul (word_sx + (word_subword (word_mul (word_sx (x:int32)) b:int64) (0,32):int32)) + (word 8380417:int64)) + (32,32))`, + REWRITE_TAC[mldsa_montmul] THEN CONV_TAC WORD_RULE);; + +let WORD_ADD_MLDSA_MONTMUL_ALT = prove + (`word_add y (mldsa_montmul (a,b) x) = + word_sub (word_add y + (word_subword (word_mul (word_sx (x:int32)) a:int64) (32,32):int32)) + (word_subword + (word_mul (word_sx + (word_subword (word_mul (word_sx (x:int32)) b:int64) (0,32):int32)) + (word 8380417:int64)) + (32,32))`, + REWRITE_TAC[mldsa_montmul] THEN CONV_TAC WORD_RULE);; + +(* ------------------------------------------------------------------------- *) +(* From |- (x == y) (mod m) /\ P to |- (x == y) (mod n) /\ P *) +(* ------------------------------------------------------------------------- *) + +let WEAKEN_INTCONG_RULE = + let prule = (MATCH_MP o prove) + (`(x:int == y) (mod m) ==> !n. m rem n = &0 ==> (x == y) (mod n)`, + REWRITE_TAC[INT_REM_EQ_0] THEN INTEGER_TAC) + and conv = GEN_REWRITE_CONV I [INT_REM_ZERO; INT_REM_REFL] ORELSEC + INT_REM_CONV + and zth = REFL `&0:int` in + let lrule n th = + let th1 = SPEC (mk_intconst n) (prule th) in + let th2 = LAND_CONV conv (lhand(concl th1)) in + MP th1 (EQ_MP (SYM th2) zth) in + fun n th -> + let th1,th2 = CONJ_PAIR th in + CONJ (lrule n th1) th2;; + +(* ------------------------------------------------------------------------- *) +(* Unify modulus and conjoin a pair of (x == y) (mod m) /\ P thoerems. *) +(* ------------------------------------------------------------------------- *) + +let UNIFY_INTCONG_RULE th1 th2 = + let p1 = dest_intconst (rand(rand(lhand(concl th1)))) + and p2 = dest_intconst (rand(rand(lhand(concl th2)))) in + let d = gcd_num p1 p2 in + CONJ (WEAKEN_INTCONG_RULE d th1) (WEAKEN_INTCONG_RULE d th2);; + +(* ------------------------------------------------------------------------- *) +(* Process list of inequality into standard congbounds for atomic terms. *) +(* ------------------------------------------------------------------------- *) + +let DIMINDEX_INT_REDUCE_CONV = + DEPTH_CONV(WORD_NUM_RED_CONV ORELSEC DIMINDEX_CONV) THENC + INT_REDUCE_CONV;; + +let PROCESS_BOUND_ASSUMPTIONS = + let cth = prove + (`(ival x <= b <=> + --(&2 pow (dimindex(:N) - 1)) <= ival x /\ ival x <= b) /\ + (b <= ival x <=> + b <= ival x /\ ival x <= &2 pow (dimindex(:N) - 1) - &1) /\ + (ival(x:N word) > b <=> + b + &1 <= ival x /\ ival x <= &2 pow (dimindex(:N) - 1) - &1) /\ + (b > ival(x:N word) <=> + --(&2 pow (dimindex(:N) - 1)) <= ival x /\ ival x <= b - &1) /\ + (ival(x:N word) >= b <=> + b <= ival x /\ ival x <= &2 pow (dimindex(:N) - 1) - &1) /\ + (b >= ival(x:N word) <=> + --(&2 pow (dimindex(:N) - 1)) <= ival x /\ ival x <= b) /\ + (ival(x:N word) < b <=> + --(&2 pow (dimindex(:N) - 1)) <= ival x /\ ival x <= b - &1) /\ + (b < ival(x:N word) <=> + b + &1 <= ival x /\ ival x <= &2 pow (dimindex(:N) - 1) - &1) /\ + (abs(ival(x:N word)) <= b <=> + --b <= ival x /\ ival x <= b) /\ + (abs(ival(x:N word)) < b <=> + &1 - b <= ival x /\ ival x <= b - &1)`, + REWRITE_TAC[IVAL_BOUND; INT_ARITH `x:int <= y - &1 <=> x < y`] THEN + INT_ARITH_TAC) + and pth = prove + (`!l u (x:N word). + l <= ival x /\ ival x <= u + ==> (ival x == ival x) (mod &0) /\ l <= ival x /\ ival x <= u`, + REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN INTEGER_TAC) in + let rule = + MATCH_MP pth o + CONV_RULE (BINOP2_CONV (LAND_CONV DIMINDEX_INT_REDUCE_CONV) + (RAND_CONV DIMINDEX_INT_REDUCE_CONV)) o + GEN_REWRITE_RULE I [cth] in + let rec process lfn ths = + match ths with + [] -> lfn + | th::oths -> + let lfn' = + try let th' = rule th in + let tm = rand(concl th') in + if is_intconst (rand(rand tm)) && is_intconst (lhand(lhand tm)) + then (rand(lhand(rand tm)) |-> th') lfn + else lfn + with Failure _ -> lfn in + process lfn' oths in + process undefined;; + +(* ------------------------------------------------------------------------- *) +(* Congruence-and-bound propagation, just recursion on the expression tree. *) +(* ------------------------------------------------------------------------- *) + +let CONGBOUND_CONST = prove + (`!(x:N word) n. + ival x = n + ==> (ival x == n) (mod &0) /\ n <= ival x /\ ival x <= n`, + REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[INT_LE_REFL] THEN INTEGER_TAC);; + +let CONGBOUND_ATOM = prove + (`!x:N word. (ival x == ival x) (mod &0) /\ + --(&2 pow (dimindex(:N) - 1)) <= ival x /\ + ival x <= &2 pow (dimindex(:N) - 1) - &1`, + GEN_TAC THEN REWRITE_TAC[INT_ARITH `x:int <= y - &1 <=> x < y`] THEN + REWRITE_TAC[IVAL_BOUND] THEN INTEGER_TAC);; + +let CONGBOUND_ATOM_GEN = prove + (`!x:N word. abs(ival x) <= n + ==> (ival x == ival x) (mod &0) /\ + --n <= ival x /\ ival x <= n`, + REWRITE_TAC[INTEGER_RULE `(x:int == x) (mod n)`] THEN INT_ARITH_TAC);; + +let CONGBOUND_IWORD = prove + (`!x. ((x == x') (mod p) /\ l <= x /\ x <= u) + ==> --(&2 pow (dimindex(:N) - 1)) <= l /\ + u <= &2 pow (dimindex(:N) - 1) - &1 + ==> (ival(iword x:N word) == x') (mod p) /\ + l <= ival(iword x:N word) /\ ival(iword x:N word) <= u`, + GEN_TAC THEN STRIP_TAC THEN STRIP_TAC THEN REWRITE_TAC[word_sx] THEN + W(MP_TAC o PART_MATCH (lhand o rand) IVAL_IWORD o + lhand o rand o rand o snd) THEN + ANTS_TAC THENL [ASM_INT_ARITH_TAC; DISCH_THEN SUBST1_TAC] THEN + ASM_REWRITE_TAC[]);; + +let CONGBOUND_WORD_SX = prove + (`!x:M word. + ((ival x == x') (mod p) /\ l <= ival x /\ ival x <= u) + ==> --(&2 pow (dimindex(:N) - 1)) <= l /\ + u <= &2 pow (dimindex(:N) - 1) - &1 + ==> (ival(word_sx x:N word) == x') (mod p) /\ + l <= ival(word_sx x:N word) /\ ival(word_sx x:N word) <= u`, + REWRITE_TAC[word_sx; CONGBOUND_IWORD]);; + +let CONGBOUND_WORD_NEG = prove + (`!x:N word. + ((ival x == x') (mod p) /\ lx <= ival x /\ ival x <= ux) + ==> --lx <= &2 pow (dimindex(:N) - 1) - &1 + ==> (ival(word_neg x) == --x') (mod p) /\ + --ux <= ival(word_neg x) /\ + ival(word_neg x) <= --lx`, + GEN_TAC THEN STRIP_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN `ival(word_neg x:N word) = --(ival x)` SUBST1_TAC THENL + [REPEAT(POP_ASSUM MP_TAC) THEN WORD_ARITH_TAC; + ASM_SIMP_TAC[INTEGER_RULE + `(x:int == x') (mod p) ==> (--x == --x') (mod p)`] THEN + ASM_ARITH_TAC]);; + +let CONGBOUND_WORD_ADD = prove + (`!x y:N word. + ((ival x == x') (mod p) /\ lx <= ival x /\ ival x <= ux) /\ + ((ival y == y') (mod p) /\ ly <= ival y /\ ival y <= uy) + ==> --(&2 pow (dimindex(:N) - 1)) <= lx + ly /\ + ux + uy <= &2 pow (dimindex(:N) - 1) - &1 + ==> (ival(word_add x y) == x' + y') (mod p) /\ + lx + ly <= ival(word_add x y) /\ + ival(word_add x y) <= ux + uy`, + REPEAT GEN_TAC THEN REWRITE_TAC[WORD_ADD_IMODULAR; imodular] THEN + STRIP_TAC THEN STRIP_TAC THEN + MATCH_MP_TAC(REWRITE_RULE[IMP_IMP] CONGBOUND_IWORD) THEN + ASM_SIMP_TAC[INT_CONG_ADD] THEN ASM_INT_ARITH_TAC);; + +let CONGBOUND_WORD_SUB = prove + (`!x y:N word. + ((ival x == x') (mod p) /\ lx <= ival x /\ ival x <= ux) /\ + ((ival y == y') (mod p) /\ ly <= ival y /\ ival y <= uy) + ==> --(&2 pow (dimindex(:N) - 1)) <= lx - uy /\ + ux - ly <= &2 pow (dimindex(:N) - 1) - &1 + ==> (ival(word_sub x y) == x' - y') (mod p) /\ + lx - uy <= ival(word_sub x y) /\ + ival(word_sub x y) <= ux - ly`, + REPEAT GEN_TAC THEN REWRITE_TAC[WORD_SUB_IMODULAR; imodular] THEN + STRIP_TAC THEN STRIP_TAC THEN + MATCH_MP_TAC(REWRITE_RULE[IMP_IMP] CONGBOUND_IWORD) THEN + ASM_SIMP_TAC[INT_CONG_SUB] THEN ASM_INT_ARITH_TAC);; + +let CONGBOUND_WORD_MUL = prove + (`!x y:N word. + ((ival x == x') (mod p) /\ lx <= ival x /\ ival x <= ux) /\ + ((ival y == y') (mod p) /\ ly <= ival y /\ ival y <= uy) + ==> --(&2 pow (dimindex(:N) - 1)) + <= min (lx * ly) (min (lx * uy) (min (ux * ly) (ux * uy))) /\ + max (lx * ly) (max (lx * uy) (max (ux * ly) (ux * uy))) + <= &2 pow (dimindex(:N) - 1) - &1 + ==> (ival(word_mul x y) == x' * y') (mod p) /\ + min (lx * ly) (min (lx * uy) (min (ux * ly) (ux * uy))) + <= ival(word_mul x y) /\ + ival(word_mul x y) + <= max (lx * ly) (max (lx * uy) (max (ux * ly) (ux * uy)))`, + let lemma = prove + (`l:int <= x /\ x <= u + ==> !a. a * l <= a * x /\ a * x <= a * u \/ + a * u <= a * x /\ a * x <= a * l`, + MESON_TAC[INT_LE_NEGTOTAL; INT_LE_LMUL; + INT_ARITH `a * x:int <= a * y <=> --a * y <= --a * x`]) in + REPEAT GEN_TAC THEN + DISCH_THEN(CONJUNCTS_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN + DISCH_THEN(ASSUME_TAC o SPEC `ival(x:N word)` o MATCH_MP lemma) THEN + DISCH_THEN(MP_TAC o MATCH_MP lemma) THEN DISCH_THEN(fun th -> + ASSUME_TAC(SPEC `ly:int` th) THEN ASSUME_TAC(SPEC `uy:int` th)) THEN + REWRITE_TAC[WORD_MUL_IMODULAR; imodular] THEN STRIP_TAC THEN + MATCH_MP_TAC(REWRITE_RULE[IMP_IMP] CONGBOUND_IWORD) THEN + ASM_SIMP_TAC[INT_CONG_MUL] THEN ASM_INT_ARITH_TAC);; + +let MONTRED_MLDSA_LEMMA = prove + (`!x. &2 pow 32 * ival(mldsa_montred x) = + ival(word_add + (word_mul (word_sx(iword(ival x * &4236238847):int32)) (word 8380417)) x)`, + GEN_TAC THEN REWRITE_TAC[mldsa_montred] THEN REWRITE_TAC[WORD_BLAST + `word_subword (x:int64) (0,32):int32 = word_sx x`] THEN + REWRITE_TAC[IWORD_INT_MUL; GSYM word_sx; GSYM WORD_IWORD] THEN + REWRITE_TAC[WORD_BLAST `(word_sx:int64->int32) x = word_zx x`] THEN + CONV_TAC INT_REDUCE_CONV THEN MATCH_MP_TAC(BITBLAST_RULE + `word_and x (word 4294967295):int64 = word 0 + ==> &4294967296 * ival(word_subword x (32,32):int32) = ival x`) THEN + REWRITE_TAC[BITBLAST_RULE + `word_and x (word 4294967295):int64 = word 0 <=> word_zx x:int32 = word 0`] THEN + W(MP_TAC o PART_MATCH (lhand o rand) WORD_ZX_ADD o lhand o snd) THEN + REWRITE_TAC[DIMINDEX_32; DIMINDEX_64; ARITH] THEN DISCH_THEN SUBST1_TAC THEN + W(MP_TAC o PART_MATCH (lhand o rand) WORD_ZX_MUL o lhand o lhand o snd) THEN + REWRITE_TAC[DIMINDEX_32; DIMINDEX_64; ARITH] THEN DISCH_THEN SUBST1_TAC THEN + REWRITE_TAC[WORD_BLAST `word_zx(word_sx (x:int32):int64) = x`] THEN + REWRITE_TAC[GSYM VAL_EQ_0; VAL_WORD_ADD; VAL_WORD_MUL; VAL_WORD] THEN + CONV_TAC MOD_DOWN_CONV THEN REWRITE_TAC[GSYM DIVIDES_MOD; DIMINDEX_32] THEN + CONV_TAC WORD_REDUCE_CONV THEN MATCH_MP_TAC(NUMBER_RULE + `(a * b + 1 == 0) (mod d) ==> d divides ((x * a) * b + x)`) THEN + REWRITE_TAC[CONG] THEN ARITH_TAC);; + +let CONGBOUND_MLDSA_MONTRED = prove + (`!a a' l u. + (ival a == a') (mod &8380417) /\ l <= ival a /\ ival a <= u + ==> --(&9205375228383854592) <= l /\ u <= &9205375228392235008 + ==> (ival(mldsa_montred a) == &(inverse_mod 8380417 4294967296) * a') + (mod &8380417) /\ + (l - &17996808470921216) div &2 pow 32 <= ival(mldsa_montred a) /\ + ival(mldsa_montred a) <= &1 + (u + &17996808462540799) div &2 pow 32`, + REPEAT GEN_TAC THEN STRIP_TAC THEN STRIP_TAC THEN + CONV_TAC NUM_REDUCE_CONV THEN CONV_TAC(ONCE_DEPTH_CONV INVERSE_MOD_CONV) THEN + MP_TAC(SPECL [`&(inverse_mod 8380417 4294967296):int`; `(&2:int) pow 32`; `&8380417:int`] (INTEGER_RULE + `!d e n:int. (e * d == &1) (mod n) + ==> !x y. ((x == d * y) (mod n) <=> (e * x == y) (mod n))`)) THEN + CONV_TAC(ONCE_DEPTH_CONV INVERSE_MOD_CONV) THEN + ANTS_TAC THENL + [REWRITE_TAC[GSYM INT_REM_EQ] THEN CONV_TAC INT_REDUCE_CONV; + DISCH_THEN(fun th -> REWRITE_TAC[th])] THEN + ONCE_REWRITE_TAC[INT_ARITH + `l:int <= x <=> &2 pow 32 * l <= &2 pow 32 * x`] THEN + REWRITE_TAC[MONTRED_MLDSA_LEMMA] THEN + REWRITE_TAC[WORD_RULE + `word_add (word_mul a b) c = iword(ival a * ival b + ival c)`] THEN + ASM_SIMP_TAC[IVAL_WORD_SX; DIMINDEX_32; DIMINDEX_64; ARITH] THEN + W(MP_TAC o PART_MATCH (lhand o rand) IVAL_IWORD o + lhand o rator o lhand o snd) THEN + REWRITE_TAC[DIMINDEX_64] THEN CONV_TAC(DEPTH_CONV WORD_NUM_RED_CONV) THEN + ANTS_TAC THENL + [SUBGOAL_THEN + `--(&9205375228383854592) <= ival(a:int64) /\ + ival(a:int64) <= &9205375228392235008` + MP_TAC THENL [ASM_INT_ARITH_TAC; ALL_TAC] THEN + POP_ASSUM_LIST(K ALL_TAC) THEN STRIP_TAC THEN + ASM BOUNDER_TAC[]; + DISCH_THEN SUBST1_TAC] THEN + ASM_REWRITE_TAC[INTEGER_RULE + `(a * p + x:int == y) (mod p) <=> (x == y) (mod p)`] THEN + CONJ_TAC THENL + [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (INT_ARITH + `l:int <= a ==> x - l <= p ==> x <= p + a`)) THEN + TRANS_TAC INT_LE_TRANS `--(&2 pow 31) * &8380417:int` THEN + CONJ_TAC THENL [ASM_INT_ARITH_TAC; BOUNDER_TAC[]]; + FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (INT_ARITH + `a:int <= u ==> x <= p - u ==> x + a <= p`)) THEN + TRANS_TAC INT_LE_TRANS `(&2 pow 31 - &1) * &8380417:int` THEN + CONJ_TAC THENL [BOUNDER_TAC[]; ASM_INT_ARITH_TAC]]);; + +let CONGBOUND_MLDSA_BARRED = prove + (`!a a' l u. + ((ival a == a') (mod &8380417) /\ l <= ival a /\ ival a <= u) + ==> u <= &0x7fbfffff + ==> (ival(mldsa_barred a) == a') (mod &8380417) /\ + --(&6283009) <= ival(mldsa_barred a) /\ + ival(mldsa_barred a) <= &6283008`, + REPEAT GEN_TAC THEN STRIP_TAC THEN STRIP_TAC THEN + MP_TAC(ISPEC `a:int32` (BITBLAST_RULE + `!a:int32. + let ML_DSA_Q = &8380417 in + let t = word_ishr (word_add a (word 4194304)) 23 in + let r = word_sub a (word_mul t (word 8380417)) in + ival(a) < &0x7fc00000 + ==> ival(a) - ML_DSA_Q * ival t = ival r /\ + --(&6283009) <= ival r /\ ival r <= &6283008`)) THEN + CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + ASM_REWRITE_TAC[GSYM mldsa_barred] THEN + ANTS_TAC THENL [ASM_INT_ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(fun th -> REWRITE_TAC[GSYM th]) THEN + ASM_REWRITE_TAC[INTEGER_RULE + `(x - p * q:int == y) (mod p) <=> (x == y) (mod p)`]);; + +let CONGBOUND_MLDSA_MONTMUL = prove + (`!x x' lx ux. + ((ival x == x') (mod &8380417) /\ lx <= ival x /\ ival x <= ux) + ==> !a b. --(&2147483648) <= ival a /\ + ival a <= &2147483647 /\ + (&8380417 * ival b) rem &4294967296 = ival a rem &4294967296 + ==> (ival(mldsa_montmul (a,b) x) == + &(inverse_mod 8380417 4294967296) * ival a * x') + (mod &8380417) /\ + (min (ival a * lx) (ival a * ux) - &17996808462540799) + div &4294967296 <= ival(mldsa_montmul (a,b) x) /\ + ival(mldsa_montmul (a,b) x) <= + (max (ival a * lx) (ival a * ux) + &17996812765888511) + div &2 pow 32`, + let lemma = prove + (`l:int <= x /\ x <= u + ==> !a. a * l <= a * x /\ a * x <= a * u \/ + a * u <= a * x /\ a * x <= a * l`, + MESON_TAC[INT_LE_NEGTOTAL; INT_LE_LMUL; + INT_ARITH `a * x:int <= a * y <=> --a * y <= --a * x`]) + and ilemma = prove + (`!x:int64. ival(word_subword x (32,32):int32) = ival x div &2 pow 32`, + REWRITE_TAC[GSYM DIMINDEX_16; GSYM IVAL_WORD_ISHR] THEN + GEN_TAC THEN REWRITE_TAC[DIMINDEX_16] THEN BITBLAST_TAC) in + let mainlemma = prove + (`!x:int64 y:int64. + (ival x == ival y) (mod (&2 pow 32)) + ==> &2 pow 32 * + ival(word_sub (word_subword x (32,32)) + (word_subword y (32,32)):int32) = + ival(word_sub x y)`, + REPEAT STRIP_TAC THEN MATCH_MP_TAC(INT_ARITH + `b rem &2 pow 32 = &0 /\ a = &2 pow 32 * b div &2 pow 32 ==> a = b`) THEN + CONJ_TAC THENL + [REWRITE_TAC[WORD_SUB_IMODULAR; imodular; INT_REM_EQ_0] THEN + SIMP_TAC[INT_DIVIDES_IVAL_IWORD; DIMINDEX_64; ARITH] THEN + POP_ASSUM MP_TAC THEN CONV_TAC INTEGER_RULE; + AP_TERM_TAC THEN REWRITE_TAC[GSYM ilemma] THEN AP_TERM_TAC] THEN + FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM INT_REM_EQ]) THEN + SIMP_TAC[INT_REM_IVAL; DIMINDEX_16; DIMINDEX_64; ARITH] THEN + BITBLAST_TAC) in + REPEAT GEN_TAC THEN DISCH_TAC THEN REPEAT GEN_TAC THEN STRIP_TAC THEN + CONV_TAC NUM_REDUCE_CONV THEN CONV_TAC(ONCE_DEPTH_CONV INVERSE_MOD_CONV) THEN + MP_TAC(SPECL [`&8265825:int`; `(&2:int) pow 32`; `&8380417:int`] (INTEGER_RULE + `!d e n:int. (e * d == &1) (mod n) + ==> !x y. ((x == d * y) (mod n) <=> (e * x == y) (mod n))`)) THEN + ANTS_TAC THENL + [REWRITE_TAC[GSYM INT_REM_EQ] THEN INT_ARITH_TAC; + DISCH_THEN(fun th -> REWRITE_TAC[th])] THEN + ONCE_REWRITE_TAC[INT_ARITH + `l:int <= x <=> &2 pow 32 * l <= &2 pow 32 * x`] THEN + REWRITE_TAC[mldsa_montmul] THEN + REWRITE_TAC[WORD_MUL_IMODULAR; imodular] THEN + SIMP_TAC[IVAL_WORD_SX; DIMINDEX_32; DIMINDEX_64; ARITH] THEN + CONV_TAC WORD_REDUCE_CONV THEN + W(MP_TAC o PART_MATCH (lhand o rand) mainlemma o + lhand o rator o lhand o snd) THEN + ANTS_TAC THENL + [SIMP_TAC[GSYM INT_REM_EQ; INT_REM_IVAL_IWORD; DIMINDEX_64; ARITH] THEN + ONCE_REWRITE_TAC[GSYM INT_MUL_REM] THEN + SIMP_TAC[GSYM VAL_IVAL_REM; GSYM DIMINDEX_32] THEN + SIMP_TAC[WORD_SUBWORD_EQUAL_WORD_ZX_POS0; DIMINDEX_32; DIMINDEX_64; + VAL_WORD_ZX_GEN; ARITH_LE; ARITH_LT] THEN + ONCE_REWRITE_TAC[ARITH_RULE `32 = MIN 64 32`] THEN + REWRITE_TAC[GSYM MOD_MOD_EXP_MIN] THEN + REWRITE_TAC[GSYM INT_OF_NUM_REM; GSYM INT_OF_NUM_CLAUSES] THEN + REWRITE_TAC[REWRITE_RULE[GSYM INT_REM_EQ; DIMINDEX_64] + (INST_TYPE [`:64`,`:N`] VAL_IWORD_CONG)] THEN + REWRITE_TAC[INT_REM_REM_POW_MIN] THEN CONV_TAC NUM_REDUCE_CONV THEN + CONV_TAC INT_REM_DOWN_CONV THEN + REWRITE_TAC[GSYM INT_MUL_ASSOC] THEN + ONCE_REWRITE_TAC[GSYM INT_MUL_REM] THEN + SIMP_TAC[GSYM VAL_IVAL_REM; GSYM DIMINDEX_32] THEN + REWRITE_TAC[DIMINDEX_32] THEN CONV_TAC INT_REM_DOWN_CONV THEN + ONCE_REWRITE_TAC[GSYM INT_MUL_REM] THEN + AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN + CONV_TAC INT_REDUCE_CONV THEN ASM_REWRITE_TAC[INT_MUL_SYM]; + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[GSYM IWORD_INT_SUB]] THEN + W(MP_TAC o PART_MATCH (lhand o rand) IVAL_IWORD o + lhand o rator o lhand o snd) THEN + ANTS_TAC THENL + [REWRITE_TAC[DIMINDEX_64; ARITH] THEN ASM BOUNDER_TAC[]; + DISCH_THEN SUBST1_TAC] THEN + ASM_SIMP_TAC[INTEGER_RULE + `(x:int == x') (mod p) ==> (x * a - q * p == a * x') (mod p)`] THEN + REWRITE_TAC[GSYM(INT_REDUCE_CONV `(&2:int) pow 32`)] THEN + MATCH_MP_TAC(INT_ARITH + `(l <= p /\ p <= u) /\ (&4294967295 - c <= q /\ q <= b) + ==> &2 pow 32 * (l - b) div &2 pow 32 <= p - q /\ + p - q <= &2 pow 32 * (u + c) div &2 pow 32`) THEN + CONJ_TAC THENL [ALL_TAC; BOUNDER_TAC[]] THEN + FIRST_X_ASSUM(MP_TAC o SPEC `ival(a:int64)` o + MATCH_MP lemma o CONJUNCT2) THEN + INT_ARITH_TAC);; + +let CONCL_BOUNDS_RULE = + CONV_RULE(BINOP2_CONV + (LAND_CONV(RAND_CONV DIMINDEX_INT_REDUCE_CONV)) + (BINOP2_CONV + (LAND_CONV DIMINDEX_INT_REDUCE_CONV) + (RAND_CONV DIMINDEX_INT_REDUCE_CONV)));; + +let SIDE_ELIM_RULE th = + MP th (EQT_ELIM(DIMINDEX_INT_REDUCE_CONV(lhand(concl th))));; + +let rec ASM_CONGBOUND_RULE lfn tm = + try apply lfn tm with Failure _ -> + match tm with + Comb(Const("word",_),n) when is_numeral n -> + let th1 = ISPEC tm CONGBOUND_CONST in + let th2 = WORD_RED_CONV(lhand(lhand(snd(strip_forall(concl th1))))) in + MATCH_MP th1 th2 + | Comb(Const("iword",_),n) when is_intconst n -> + let th0 = WORD_IWORD_CONV tm in + let th1 = ISPEC (rand(concl th0)) CONGBOUND_CONST in + let th2 = WORD_RED_CONV(lhand(lhand(snd(strip_forall(concl th1))))) in + SUBS[SYM th0] (MATCH_MP th1 th2) + | Comb(Const("mldsa_montred",_),t) -> + let th1 = WEAKEN_INTCONG_RULE (num 8380417) + (ASM_CONGBOUND_RULE lfn t) in + CONCL_BOUNDS_RULE(SIDE_ELIM_RULE(MATCH_MP CONGBOUND_MLDSA_MONTRED th1)) + | Comb(Const("mldsa_barred",_),t) -> + let th1 = WEAKEN_INTCONG_RULE (num 8380417) + (ASM_CONGBOUND_RULE lfn t) in + CONCL_BOUNDS_RULE(SIDE_ELIM_RULE(MATCH_MP CONGBOUND_MLDSA_BARRED th1)) + | Comb(Comb(Const("mldsa_montmul",_),ab),t) -> + let atm,btm = dest_pair ab and th0 = ASM_CONGBOUND_RULE lfn t in + let th0' = WEAKEN_INTCONG_RULE (num 8380417) th0 in + let th1 = SPECL [atm;btm] (MATCH_MP CONGBOUND_MLDSA_MONTMUL th0') in + CONCL_BOUNDS_RULE(SIDE_ELIM_RULE th1) + | Comb(Const("word_sx",_),t) -> + let th0 = ASM_CONGBOUND_RULE lfn t in + let tyin = type_match + (type_of(rator(rand(lhand(funpow 4 rand (snd(dest_forall + (concl CONGBOUND_WORD_SX)))))))) (type_of(rator tm)) [] in + let th1 = MATCH_MP (INST_TYPE tyin CONGBOUND_WORD_SX) th0 in + CONCL_BOUNDS_RULE(SIDE_ELIM_RULE th1) + | Comb(Const("word_neg",_),t) -> + let th0 = ASM_CONGBOUND_RULE lfn t in + let th1 = MATCH_MP CONGBOUND_WORD_NEG th0 in + CONCL_BOUNDS_RULE(SIDE_ELIM_RULE th1) + | Comb(Comb(Const("word_add",_),ltm),rtm) -> + let lth = ASM_CONGBOUND_RULE lfn ltm + and rth = ASM_CONGBOUND_RULE lfn rtm in + let th1 = MATCH_MP CONGBOUND_WORD_ADD (UNIFY_INTCONG_RULE lth rth) in + CONCL_BOUNDS_RULE(SIDE_ELIM_RULE th1) + | Comb(Comb(Const("word_sub",_),ltm),rtm) -> + let lth = ASM_CONGBOUND_RULE lfn ltm + and rth = ASM_CONGBOUND_RULE lfn rtm in + let th1 = MATCH_MP CONGBOUND_WORD_SUB (UNIFY_INTCONG_RULE lth rth) in + CONCL_BOUNDS_RULE(SIDE_ELIM_RULE th1) + | Comb(Comb(Const("word_mul",_),ltm),rtm) -> + let lth = ASM_CONGBOUND_RULE lfn ltm + and rth = ASM_CONGBOUND_RULE lfn rtm in + let th1 = MATCH_MP CONGBOUND_WORD_MUL (UNIFY_INTCONG_RULE lth rth) in + CONCL_BOUNDS_RULE(SIDE_ELIM_RULE th1) + | _ -> CONCL_BOUNDS_RULE(ISPEC tm CONGBOUND_ATOM);; + +let GEN_CONGBOUND_RULE aboths = + ASM_CONGBOUND_RULE (PROCESS_BOUND_ASSUMPTIONS aboths);; + +let CONGBOUND_RULE = GEN_CONGBOUND_RULE [];; + +let rec LOCAL_CONGBOUND_RULE lfn asms = + match asms with + [] -> lfn + | th::ths -> + let bod,var = dest_eq (concl th) in + let th1 = ASM_CONGBOUND_RULE lfn bod in + let th2 = SUBS[th] th1 in + let lfn' = (var |-> th2) lfn in + LOCAL_CONGBOUND_RULE lfn' ths;; + +(* ------------------------------------------------------------------------- *) +(* Simplify SIMD cruft and fold relevant definitions when encountered. *) +(* The ABBREV form also introduces abbreviations for relevant subterms. *) +(* ------------------------------------------------------------------------- *) + +let SIMD_SIMPLIFY_CONV unfold_defs = + TOP_DEPTH_CONV + (REWR_CONV WORD_SUBWORD_AND ORELSEC WORD_SIMPLE_SUBWORD_CONV) THENC + DEPTH_CONV WORD_NUM_RED_CONV THENC + REWRITE_CONV (map GSYM unfold_defs);; + +let SIMD_SIMPLIFY_TAC unfold_defs = + let arm_simdable = can (term_match [] `read X (s:armstate):int128 = whatever`) in + let x86_simdable = can (term_match [] `read X (s:x86state):int256 = whatever`) in + let simdable tm = arm_simdable tm || x86_simdable tm in + TRY(FIRST_X_ASSUM + (ASSUME_TAC o + CONV_RULE(RAND_CONV (SIMD_SIMPLIFY_CONV unfold_defs)) o + check (simdable o concl)));; + +let is_local_definition unfold_defs = + let pats = map (lhand o snd o strip_forall o concl) unfold_defs in + let pam t = exists (fun p -> can(term_match [] p) t) pats in + fun tm -> is_eq tm && is_var(rand tm) && pam(lhand tm);; + +let AUTO_ABBREV_TAC tm = + let gv = genvar(type_of tm) in + ABBREV_TAC(mk_eq(gv,tm));; + +let SIMD_SIMPLIFY_ABBREV_TAC = + let arm_simdable = + can (term_match [] `read X (s:armstate):int128 = whatever`) + and x86_simdable = + can (term_match [] `read X (s:x86state):int256 = whatever`) in + let simdable tm = arm_simdable tm || x86_simdable tm in + fun unfold_defs unfold_aux -> + let pats = map (lhand o snd o strip_forall o concl) unfold_defs in + let pam t = exists (fun p -> can(term_match [] p) t) pats in + let ttac th (asl,w) = + let th' = CONV_RULE(RAND_CONV + (SIMD_SIMPLIFY_CONV (unfold_defs @ unfold_aux))) th in + let asms = + map snd (filter (is_local_definition unfold_defs o concl o snd) asl) in + let th'' = GEN_REWRITE_RULE (RAND_CONV o TOP_DEPTH_CONV) asms th' in + let tms = sort free_in (find_terms pam (rand(concl th''))) in + (MP_TAC th'' THEN MAP_EVERY AUTO_ABBREV_TAC tms THEN DISCH_TAC) (asl,w) in + TRY(FIRST_X_ASSUM(ttac o check (simdable o concl)));; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/mldsa_utils.ml b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/mldsa_utils.ml new file mode 100644 index 0000000000..5600966fba --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/mldsa_utils.ml @@ -0,0 +1,92 @@ +(* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 + *) + +(* ------------------------------------------------------------------------- *) +(* Some convenient proof tools. *) +(* ------------------------------------------------------------------------- *) + +let READ_MEMORY_MERGE_CONV = + let baseconv = + GEN_REWRITE_CONV I [READ_MEMORY_BYTESIZED_SPLIT] THENC + LAND_CONV(LAND_CONV(RAND_CONV(RAND_CONV + (TRY_CONV(GEN_REWRITE_CONV I [GSYM WORD_ADD_ASSOC] THENC + RAND_CONV WORD_ADD_CONV))))) in + let rec conv n tm = + if n = 0 then REFL tm else + (baseconv THENC BINOP_CONV (conv(n - 1))) tm in + conv;; + +let READ_MEMORY_SPLIT_CONV = + let baseconv = + GEN_REWRITE_CONV I [READ_MEMORY_BYTESIZED_UNSPLIT] THENC + BINOP_CONV(LAND_CONV(LAND_CONV(RAND_CONV(RAND_CONV + (TRY_CONV(GEN_REWRITE_CONV I [GSYM WORD_ADD_ASSOC] THENC + RAND_CONV WORD_ADD_CONV)))))) in + let rec conv n tm = + if n = 0 then REFL tm else + (baseconv THENC BINOP_CONV (conv(n - 1))) tm in + conv;; + +let SIMD_SIMPLIFY_CONV unfold_defs = + TOP_DEPTH_CONV + (REWR_CONV WORD_SUBWORD_AND ORELSEC WORD_SIMPLE_SUBWORD_CONV) THENC + DEPTH_CONV WORD_NUM_RED_CONV THENC + REWRITE_CONV (map GSYM unfold_defs);; + +let SIMD_SIMPLIFY_TAC unfold_defs = + let arm_simdable = can (term_match [] `read X (s:armstate):int128 = whatever`) in + let x86_simdable = can (term_match [] `read X (s:x86state):int256 = whatever`) in + let simdable tm = arm_simdable tm || x86_simdable tm in + TRY(FIRST_X_ASSUM + (ASSUME_TAC o + CONV_RULE(RAND_CONV (SIMD_SIMPLIFY_CONV unfold_defs)) o + check (simdable o concl)));; + +let MEMORY_128_FROM_16_TAC = + let a_tm = `a:int64` and n_tm = `n:num` and i64_ty = `:int64` + and pat = `read (memory :> bytes128(word_add a (word n))) s0` in + fun v n -> + let pat' = subst[mk_var(v,i64_ty),a_tm] pat in + let f i = + let itm = mk_small_numeral(16*i) in + READ_MEMORY_MERGE_CONV 3 (subst[itm,n_tm] pat') in + MP_TAC(end_itlist CONJ (map f (0--(n-1))));; + +(* This tactic repeated calls `f n with monotonically increasing values of n + until the target PC matches one of the assumptions. + + The goal must be of the form `ensure arm ...`. Clauses constraining the PC + must be of the form `read PC some_state = some_value`. *) +let MAP_UNTIL_TARGET_PC f n = fun (asl, w) -> + let is_pc_condition = can (term_match [] `read PC some_state = some_value`) in + (* We assume that the goal has the form + `ensure arm (\s. ... /\ read PC s = some_value /\ ...)` *) + let extract_target_pc_from_goal goal = + let _, insts, _ = term_match [] `eventually arm (\s'. P) some_state` goal in + insts + |> rev_assoc `P: bool` + |> conjuncts + |> find is_pc_condition in + (* Find PC-constraining assumption from the list of all assumptions. *) + let extract_pc_assumption asl = + try Some (find (is_pc_condition o concl o snd) asl |> snd |> concl) with find -> None in + (* Check if there is an assumption constraining the PC to the target PC *) + let has_matching_pc_assumption asl target_pc = + match extract_pc_assumption asl with + | None -> false + | Some(asm) -> can (term_match [`returnaddress: 64 word`; `pc: num`] target_pc) asm in + let target_pc = extract_target_pc_from_goal w in + (* ALL_TAC if we reached the target PC, NO_TAC otherwise, so + TARGET_PC_REACHED_TAC target_pc ORELSE SOME_OTHER_TACTIC + is effectively `if !(target_pc_reached) SOME_OTHER_TACTIC` *) + let TARGET_PC_REACHED_TAC target_pc = fun (asl, w) -> + if has_matching_pc_assumption asl target_pc then + ALL_TAC (asl, w) + else + NO_TAC (asl, w) in + let rec core n (asl, w) = + (TARGET_PC_REACHED_TAC target_pc ORELSE (f n THEN core (n + 1))) (asl, w) + in + core n (asl, w);; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/mldsa_zetas.ml b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/mldsa_zetas.ml new file mode 100644 index 0000000000..921af365f1 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/proofs/hol_light/x86_64/proofs/mldsa_zetas.ml @@ -0,0 +1,96 @@ +(* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 + *) + +(* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + *) + +(* + * Table of zeta values used in the AVX2 NTTs + * See autogen for details. + *) + +let mldsa_complete_qdata = define `mldsa_complete_qdata:int list = [ + &8380417; &8380417; &8380417; &8380417; &8380417; &8380417; &8380417; &8380417; + &58728449; &58728449; &58728449; &58728449; &58728449; &58728449; &58728449; &58728449; + -- &8395782; -- &8395782; -- &8395782; -- &8395782; -- &8395782; -- &8395782; -- &8395782; -- &8395782; + &41978; &41978; &41978; &41978; &41978; &41978; &41978; &41978; + -- &151046689; &1830765815; -- &1929875198; -- &1927777021; &1640767044; &1477910808; &1612161320; &1640734244; + &308362795; &308362795; &308362795; &308362795; -- &1815525077; -- &1815525077; -- &1815525077; -- &1815525077; + -- &1374673747; -- &1374673747; -- &1374673747; -- &1374673747; -- &1091570561; -- &1091570561; -- &1091570561; -- &1091570561; + -- &1929495947; -- &1929495947; -- &1929495947; -- &1929495947; &515185417; &515185417; &515185417; &515185417; + -- &285697463; -- &285697463; -- &285697463; -- &285697463; &625853735; &625853735; &625853735; &625853735; + &1727305304; &1727305304; &2082316400; &2082316400; -- &1364982364; -- &1364982364; &858240904; &858240904; + &1806278032; &1806278032; &222489248; &222489248; -- &346752664; -- &346752664; &684667771; &684667771; + &1654287830; &1654287830; -- &878576921; -- &878576921; -- &1257667337; -- &1257667337; -- &748618600; -- &748618600; + &329347125; &329347125; &1837364258; &1837364258; -- &1443016191; -- &1443016191; -- &1170414139; -- &1170414139; + -- &1846138265; -- &1631226336; -- &1404529459; &1838055109; &1594295555; -- &1076973524; -- &1898723372; -- &594436433; + -- &202001019; -- &475984260; -- &561427818; &1797021249; -- &1061813248; &2059733581; -- &1661512036; -- &1104976547; + -- &1750224323; -- &901666090; &418987550; &1831915353; -- &1925356481; &992097815; &879957084; &2024403852; + &1484874664; -- &1636082790; -- &285388938; -- &1983539117; -- &1495136972; -- &950076368; -- &1714807468; -- &952438995; + -- &1574918427; &1350681039; -- &2143979939; &1599739335; -- &1285853323; -- &993005454; -- &1440787840; &568627424; + -- &783134478; -- &588790216; &289871779; -- &1262003603; &2135294594; -- &1018755525; -- &889861155; &1665705315; + &1321868265; &1225434135; -- &1784632064; &666258756; &675310538; -- &1555941048; -- &1999506068; -- &1499481951; + -- &695180180; -- &1375177022; &1777179795; &334803717; -- &178766299; -- &518252220; &1957047970; &1146323031; + -- &654783359; -- &1974159335; &1651689966; &140455867; -- &1039411342; &1955560694; &1529189038; -- &2131021878; + -- &247357819; &1518161567; -- &86965173; &1708872713; &1787797779; &1638590967; -- &120646188; -- &1669960606; + -- &916321552; &1155548552; &2143745726; &1210558298; -- &1261461890; -- &318346816; &628664287; -- &1729304568; + &1422575624; &1424130038; -- &1185330464; &235321234; &168022240; &1206536194; &985155484; -- &894060583; + -- &898413; -- &1363460238; -- &605900043; &2027833504; &14253662; &1014493059; &863641633; &1819892093; + &2124962073; -- &1223601433; -- &1920467227; -- &1637785316; -- &1536588520; &694382729; &235104446; -- &1045062172; + &831969619; -- &300448763; &756955444; -- &260312805; &1554794072; &1339088280; -- &2040058690; -- &853476187; + -- &2047270596; -- &1723816713; -- &1591599803; -- &440824168; &1119856484; &1544891539; &155290192; -- &973777462; + &991903578; &912367099; -- &44694137; &1176904444; -- &421552614; -- &818371958; &1747917558; -- &325927722; + &908452108; &1851023419; -- &1176751719; -- &1354528380; -- &72690498; -- &314284737; &985022747; &963438279; + -- &1078959975; &604552167; -- &1021949428; &608791570; &173440395; -- &2126092136; -- &1316619236; -- &1039370342; + &6087993; -- &110126092; &565464272; -- &1758099917; -- &1600929361; &879867909; -- &1809756372; &400711272; + &1363007700; &30313375; -- &326425360; &1683520342; -- &517299994; &2027935492; -- &1372618620; &128353682; + -- &1123881663; &137583815; -- &635454918; -- &642772911; &45766801; &671509323; -- &2070602178; &419615363; + &1216882040; -- &270590488; -- &1276805128; &371462360; -- &1357098057; -- &384158533; &827959816; -- &596344473; + &702390549; -- &279505433; -- &260424530; -- &71875110; -- &1208667171; -- &1499603926; &2036925262; -- &540420426; + &746144248; -- &1420958686; &2032221021; &1904936414; &1257750362; &1926727420; &1931587462; &1258381762; + &885133339; &1629985060; &1967222129; &6363718; -- &1287922800; &1136965286; &1779436847; &1116720494; + &1042326957; &1405999311; &713994583; &940195359; -- &1542497137; &2061661095; -- &883155599; &1726753853; + -- &1547952704; &394851342; &283780712; &776003547; &1123958025; &201262505; &1934038751; &374860238; + -- &3975713; &25847; -- &2608894; -- &518909; &237124; -- &777960; -- &876248; &466468; + &1826347; &1826347; &1826347; &1826347; &2353451; &2353451; &2353451; &2353451; + -- &359251; -- &359251; -- &359251; -- &359251; -- &2091905; -- &2091905; -- &2091905; -- &2091905; + &3119733; &3119733; &3119733; &3119733; -- &2884855; -- &2884855; -- &2884855; -- &2884855; + &3111497; &3111497; &3111497; &3111497; &2680103; &2680103; &2680103; &2680103; + &2725464; &2725464; &1024112; &1024112; -- &1079900; -- &1079900; &3585928; &3585928; + -- &549488; -- &549488; -- &1119584; -- &1119584; &2619752; &2619752; -- &2108549; -- &2108549; + -- &2118186; -- &2118186; -- &3859737; -- &3859737; -- &1399561; -- &1399561; -- &3277672; -- &3277672; + &1757237; &1757237; -- &19422; -- &19422; &4010497; &4010497; &280005; &280005; + &2706023; &95776; &3077325; &3530437; -- &1661693; -- &3592148; -- &2537516; &3915439; + -- &3861115; -- &3043716; &3574422; -- &2867647; &3539968; -- &300467; &2348700; -- &539299; + -- &1699267; -- &1643818; &3505694; -- &3821735; &3507263; -- &2140649; -- &1600420; &3699596; + &811944; &531354; &954230; &3881043; &3900724; -- &2556880; &2071892; -- &2797779; + -- &3930395; -- &3677745; -- &1452451; &2176455; -- &1257611; -- &4083598; -- &3190144; -- &3632928; + &3412210; &2147896; -- &2967645; -- &411027; -- &671102; -- &22981; -- &381987; &1852771; + -- &3343383; &508951; &44288; &904516; -- &3724342; &1653064; &2389356; &759969; + &189548; &3159746; -- &2409325; &1315589; &1285669; -- &812732; -- &3019102; -- &3628969; + -- &1528703; -- &3041255; &3475950; -- &1585221; &1939314; -- &1000202; -- &3157330; &126922; + -- &983419; &2715295; -- &3693493; -- &2477047; -- &1228525; -- &1308169; &1349076; -- &1430430; + &264944; &3097992; -- &1100098; &3958618; -- &8578; -- &3249728; -- &210977; -- &1316856; + -- &3553272; -- &1851402; -- &177440; &1341330; -- &1584928; -- &1439742; -- &3881060; &3839961; + &2091667; -- &3342478; &266997; -- &3520352; &900702; &495491; -- &655327; -- &3556995; + &342297; &3437287; &2842341; &4055324; -- &3767016; -- &2994039; -- &1333058; -- &451100; + -- &1279661; &1500165; -- &542412; -- &2584293; -- &2013608; &1957272; -- &3183426; &810149; + -- &3038916; &2213111; -- &426683; -- &1667432; -- &2939036; &183443; -- &554416; &3937738; + &3407706; &2244091; &2434439; -- &3759364; &1859098; -- &1613174; -- &3122442; -- &525098; + &286988; -- &3342277; &2691481; &1247620; &1250494; &1869119; &1237275; &1312455; + &1917081; &777191; -- &2831860; -- &3724270; &2432395; &3369112; &162844; &1652634; + &3523897; -- &975884; &1723600; -- &1104333; -- &2235985; -- &976891; &3919660; &1400424; + &2316500; -- &2446433; -- &1235728; -- &1197226; &909542; -- &43260; &2031748; -- &768622; + -- &2437823; &1735879; -- &2590150; &2486353; &2635921; &1903435; -- &3318210; &3306115; + -- &2546312; &2235880; -- &1671176; &594136; &2454455; &185531; &1616392; -- &3694233; + &3866901; &1717735; -- &1803090; -- &260646; -- &420899; &1612842; -- &48306; -- &846154; + &3817976; -- &3562462; &3513181; -- &3193378; &819034; -- &522500; &3207046; -- &3595838; + &4108315; &203044; &1265009; &1595974; -- &3548272; -- &1050970; -- &1430225; -- &1962642; + -- &1374803; &3406031; -- &1846953; -- &3776993; -- &164721; -- &1207385; &3014001; -- &1799107; + &269760; &472078; &1910376; -- &3833893; -- &2286327; -- &3545687; -- &1362209; &1976782 +]`;; diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/autogen b/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/autogen new file mode 100755 index 0000000000..cf71fa6d7d --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/autogen @@ -0,0 +1,3246 @@ +#!/usr/bin/env python3 +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +import subprocess +import tempfile +import platform +import argparse +import shutil +import pathlib +import re +import sys +import threading +import pyparsing as pp +import os +import yaml +import time + +from concurrent.futures import ThreadPoolExecutor +from functools import partial +from rich.console import Console +from rich.progress import ( + Progress, + BarColumn, + TextColumn, + TaskProgressColumn, + TimeElapsedColumn, +) + +console = Console() + +# Global progress bar - initialized in _main() +_progress = None +_main_task = None +_current_task = "" + +modulus = 8380417 +root_of_unity = 1753 +montgomery_factor = pow(2, 32, modulus) + +# Compiled regex patterns +_RE_DEFINED = re.compile(r"defined\(([^)]+)\)") +_RE_MARKDOWN_CITE = re.compile(r"\[\^(?P\w+)\]") +_RE_C_CITE = re.compile(r"@\[(?P\w+)") +_RE_BYTECODE_START = re.compile( + r"=== bytecode start: (?:aarch64|x86_64)/mldsa/([^/\s]+?)\.o" +) +_RE_FUNC_SYMBOL = re.compile(r"MLD_ASM_FN_SYMBOL\((.*)\)") +_RE_MACRO_CHECK = re.compile(r"[^_]((?:MLD_|MLDSA_)\w+)(.*)$", re.M) +_RE_MLKEM_MACRO_CHECK = re.compile(r"[^_]((?:MLK_|MLKEM_)\w+)(.*)$", re.M) +_RE_DEFINE = re.compile(r"^\s*#define\s+(\w+)") +_RE_ARGS_COMMENT = re.compile(r"(.*?)(\s*//.*)?$") +_RE_MACRO_DEF = re.compile(r"^\s*\.macro\s+(\w+)") +_RE_MACRO_DEF_ARGS = re.compile(r"^(\s*\.macro\s+\w+)(\s+.*)$") +_RE_LEADING_SPACE = re.compile(r"^(\s*)") + +# File cache: {filename: {"content": str, "original": str, "force_format": bool}} +# Caches content of files in preparation/modification to avoid repeated +# read/writes to the file system. +_file_cache = {} +_file_cache_lock = threading.Lock() + +_errors = [] +_errors_lock = threading.Lock() + +_progress_lock = threading.Lock() + + +def read_file(filename, original=False): + """Read file content, using cache if available""" + with _file_cache_lock: + if filename in _file_cache: + key = "content" if original is False else "original" + return _file_cache[filename][key] + + with open(filename, "r") as f: + content = f.read() + _file_cache[filename] = { + "content": content, + "original": content, + "force_format": False, + } + return content + + +def update_file(filename, content, force_format=False): + """Write file content to cache""" + with _file_cache_lock: + if filename not in _file_cache: + try: + with open(filename, "r") as f: + original = f.read() + _file_cache[filename] = {"original": original} + except FileNotFoundError: + _file_cache[filename] = {"original": None} + + e = _file_cache[filename] + e["content"] = content + e["force_format"] = e.get("force_format", False) or force_format + + +def finalize_format_batch(batch): + """Format a batch of files by passing to clang-format with -i flag""" + if not batch: + return + + # Create temp files for each filename in batch + temp_files = [] + try: + for filename in batch: + content = read_file(filename) + # Skip files scheduled for deletion + if content is None: + continue + with tempfile.NamedTemporaryFile(mode="w", suffix=".c", delete=False) as f: + f.write(content) + temp_files.append((f.name, filename)) + + # Call clang-format with -i to update files in-place + clang_format_file = os.path.join( + os.path.dirname(__file__), "..", ".clang-format" + ) + p = subprocess.run( + ["clang-format", "-i", f"-style=file:{clang_format_file}"] + + [t[0] for t in temp_files], + capture_output=True, + text=True, + ) + if p.returncode != 0: + print(p.stderr) + print( + f"Failed to auto-format autogenerated code (clang-format return code {p.returncode}). Are you running in a nix shell? See CONTRIBUTING.md." + ) + exit(1) + + # Read formatted files back and update cache + for temp_path, filename in temp_files: + with open(temp_path, "r") as f: + update_file(filename, f.read()) + finally: + for temp_path, _ in temp_files: + os.unlink(temp_path) + + +def finalize_file(item, dry_run): + """Write a single file or delete it if content is None""" + filename, data = item + + content_old = data["original"] + content_new = data["content"] + + if content_old == content_new: + return + + # Handle deletion (content_new is None) + if content_new is None: + if dry_run is False: + file_updated(filename, removed=True) + os.remove(filename) + else: + error(filename, None) + return + + if dry_run is False: + file_updated(filename) + with open(filename, "w") as f: + f.write(content_new) + else: + filename_new = f"{filename}.new" + with open(filename_new, "w") as f: + f.write(content_new) + error(filename, filename_new) + + +def format_files(dry_run): + """Apply formatting to files""" + to_format = [ + filename + for filename, data in _file_cache.items() + if data["force_format"] or filename.endswith((".c", ".h", ".i")) + ] + + # Group into batches of max 20 + batch_size = 20 + batches = [ + to_format[i : i + batch_size] for i in range(0, len(to_format), batch_size) + ] + + run_parallel(batches, finalize_format_batch) + + +def finalize(dry_run): + """Write dirty files to filesystem""" + run_parallel(_file_cache.items(), partial(finalize_file, dry_run=dry_run)) + + +# This file re-generated auto-generated source files in mldsa-native. +# +# It currently covers: +# - zeta values for the reference NTT and invNTT +# - lookup tables used for fast rejection sampling +# - source files for monolithic single-CU build +# - simplified assembly sources +# - header guards +# - #undef's for CU-local macros + +_step_start_time = time.time() + + +def high_level_task(msg): + """Set the current high-level task description""" + global _current_task + _current_task = msg + if _progress: + _progress.update(_main_task, description=f"[cyan]{msg}[/]") + + +def high_level_status(msg, skipped=False): + """Complete a high-level step and print status""" + global _step_start_time + elapsed = time.time() - _step_start_time + if skipped: + symbol = "[dim]–[/dim]" + else: + symbol = "[green]✓[/green]" + if _progress: + _progress.print(f"{symbol} {msg} ({elapsed:.1f}s)", highlight=False) + _progress.advance(_main_task) + else: + console.print(f"{symbol} {msg} ({elapsed:.1f}s)", highlight=False) + _step_start_time = time.time() + + +def run_parallel(files, func): + """Run func over files in parallel with progress tracking""" + if not files: + return [] + + files = list(files) + total = len(files) + state = {"completed": 0, "last_file": ""} + + def update_progress(): + if _progress and total > 0: + suffix = ( + f" {os.path.basename(state['last_file'])}" if state["last_file"] else "" + ) + _progress.update( + _main_task, + description=f"[cyan]{_current_task}[/] [dim][{state['completed']}/{total}]{suffix}[/]", + ) + + def wrapped(f): + result = func(f) + with _progress_lock: + state["completed"] += 1 + state["last_file"] = str(f[0]) if isinstance(f, tuple) else str(f) + update_progress() + return result + + with ThreadPoolExecutor() as executor: + return list(executor.map(wrapped, files)) + + +def error(filename, filename_new): + with _errors_lock: + _errors.append((filename, filename_new)) + + +def print_check_errors(): + for filename, filename_new in _errors: + console.print(f"[red]error[/] {filename}") + if filename_new is not None: + console.print( + f"Autogenerated file {filename} needs updating. Have you called scripts/autogen? Wrote new version to {filename_new}." + ) + if os.path.exists(filename): + subprocess.run(["diff", filename, filename_new]) + else: + console.print( + f"Autogenerated file {filename} needs removing. Have you called scripts/autogen?" + ) + + return len(_errors) == 0 + + +def file_updated(filename, removed=False): + if removed is False: + console.print(f"[bold]updated {filename}[/]") + else: + console.print(f"[bold]removed {filename}[/]") + + +def gen_autogen_warning(): + yield "" + yield "/*" + yield " * WARNING: This file is auto-generated from scripts/autogen" + yield " * in the mldsa-native repository." + yield " * Do not modify it directly." + yield " */" + + +def gen_header(): + yield "/*" + yield " * Copyright (c) The mldsa-native project authors" + yield " * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT" + yield " */" + yield from gen_autogen_warning() + yield "" + + +def gen_hol_light_header(): + yield "(*" + yield " * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved." + yield " * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0" + yield " *)" + yield "" + yield "(*" + yield " * WARNING: This file is auto-generated from scripts/autogen" + yield " * in the mldsa-native repository." + yield " * Do not modify it directly." + yield " *)" + yield "" + + +def gen_yaml_header(): + yield "# Copyright (c) The mldsa-native project authors" + yield "# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT" + yield "" + + +def format_content(content): + clang_format_file = os.path.join(os.path.dirname(__file__), "..", ".clang-format") + p = subprocess.run( + ["clang-format", f"-style=file:{clang_format_file}"], + capture_output=True, + input=content, + text=True, + ) + if p.returncode != 0: + print(p.stderr) + print( + f"Failed to auto-format autogenerated code (clang-format return code {p.returncode}). Are you running in a nix shell? See CONTRIBUTING.md." + ) + exit(1) + return p.stdout + + +class CondParser: + """Rudimentary parser for expressions if `#if .. #else ..` directives""" + + def __init__(self): + c_identifier = pp.common.identifier() + c_integer_suffix = pp.one_of("U L LU UL LL ULL LLU", caseless=True) + c_dec_integer = pp.Combine( + pp.Optional(pp.one_of("+ -")) + + pp.Word(pp.nums) + + pp.Optional(c_integer_suffix) + ) + c_hex_integer = pp.Combine( + pp.Literal("0x") + pp.Word(pp.hexnums) + pp.Optional(c_integer_suffix) + ) + + self.parser = pp.infix_notation( + c_identifier | c_hex_integer | c_dec_integer, + [ + (pp.one_of("!"), 1, pp.opAssoc.RIGHT), + (pp.one_of("!= == <= >= > <"), 2, pp.opAssoc.LEFT), + (pp.one_of("&&"), 2, pp.opAssoc.LEFT), + (pp.one_of("||"), 2, pp.opAssoc.LEFT), + ], + ) + + @staticmethod + def connective(res): + """Extract the top-level connective for the expression""" + if not isinstance(res, list): + return None + elif len(res) == 2: + # Unary operator (will be "!" in our case) + return res[0] + else: + # Binary operator + return res[1] + + @staticmethod + def map_top(f, res): + """Apply function to arguments of top-level connective""" + if not isinstance(res, list): + return res + else: + # We expect `f` to do nothing on strings, so it is safe + # to apply it everywhere, including the connectives. + return list(map(f, res)) + + @staticmethod + def args(res): + """Assuming the argument is a binary operation, return all arguments""" + return res[::2] + + @staticmethod + def simplify_double_negation(res): + """Cancel double negations""" + if CondParser.connective(res) == "!" and CondParser.connective(res[1]) == "!": + res = res[1][1] + res = CondParser.map_top(CondParser.simplify_double_negation, res) + return res + + @staticmethod + def simplify_not_eq(res): + """Replace !(x == y) by x != y, and !(x != y) by x == y""" + if CondParser.connective(res) == "!" and CondParser.connective(res[1]) == "==": + res = res[1] + res[1] = "!=" + if CondParser.connective(res) == "!" and CondParser.connective(res[1]) == "!=": + res = res[1] + res[1] = "==" + res = CondParser.map_top(CondParser.simplify_not_eq, res) + return res + + @staticmethod + def simplify_neq_chain(res): + """Check for &&-chains of inequalities followed by an equality + which implies the inequality. This catches patterns like + ``` + #if MLKEM_K == 2 + ... + #elif MLKEM_K == 3 + ... + #elif MLKEM_K == 4 + ... + #endif + ``` + """ + if ( + CondParser.connective(res) == "&&" + and CondParser.connective(res[-1]) == "==" + ): + lhs = res[-1][0] + rhs = res[-1][2] + args = [] + for a in CondParser.args(res[:-1]): + if CondParser.connective(a) == "!=" and a[0] == lhs: + args.append(a[2]) + else: + args = None + break + if args is None: + return res + # Check if all args are numerical and different + if rhs.isdigit() and all( + map(lambda a: a.isdigit() and int(a) != int(rhs), args) + ): + # Success -- just drop all but the final condition + return res[-1] + res = CondParser.map_top(CondParser.simplify_neq_chain, res) + return res + + @staticmethod + def print_exp(exp, inner=False): + conn = CondParser.connective(exp) + if conn is None: + return exp + elif conn == "!": + res = f"!{CondParser.print_exp(exp[1], inner=True)}" + else: + padded_conn = f" {conn} " + res = padded_conn.join( + map(lambda e: CondParser.print_exp(e, inner=True), CondParser.args(exp)) + ) + if inner is True and conn in ["&&", "||"]: + res = f"({res})" + return res + + def simplify_assoc(exp): + """Check for unnecesary bracketing and remove it""" + conn = CondParser.connective(exp) + if conn in ["&&", "||"]: + args = CondParser.args(exp) + new_args = [] + for a in args: + if CondParser.connective(a) == conn: + new_args += CondParser.args(a) + else: + new_args.append(a) + exp = [x for y in map(lambda x: [x, conn], new_args) for x in y][:-1] + exp = CondParser.map_top(CondParser.simplify_assoc, exp) + return exp + + def simplify_all(exp): + exp = CondParser.simplify_double_negation(exp) + exp = CondParser.simplify_not_eq(exp) + exp = CondParser.simplify_neq_chain(exp) + exp = CondParser.simplify_assoc(exp) + return exp + + def parse_condition(self, exp, simplify=True): + try: + exp = self.parser.parseString(exp, parseAll=True).as_list()[0] + except pp.ParseException: + print(f"WARNING: Ignoring condition '{exp}' I cannot parse") + return exp + if simplify is True: + exp = CondParser.simplify_all(exp) + return exp + + def normalize_condition(self, exp): + return CondParser.print_exp(self.parse_condition(exp)) + + +def adjust_preprocessor_comments_for_filename( + content, source_file, parser, show_status=False +): + """Automatically add comments to large `#if ... #else ... #endif` + blocks indicating the guarding conditions. + + For example, a block + + ```c + #if FOO + ... + #else + ... + #endif + ``` + + will be transformed into + + + ```c + #if FOO + ... + #else /* FOO */ + ... + #endif /* !FOO */ + ``` + + except when the distance between the preprocessor directives is + very short, and the annotations would be more harmful than useful. + + ``` + """ + + content = content.split("\n") + new_content = [] + + # Stack of `#if` statements. Every entry is a tuple + # `(conds, line_no, if_or_else, has_children)`, where + # - `conds` is the list of conditions being tested. + # In a normal `#if ... #else ...` braach, this is a singleton list + # containing the condition being tested. In a chain of + # `#if .. #elif ..` it contains all conditions encountered to this point. + # - `line_no` is the line where it started + # - `if_or_else` indicates whether we are in the `#if` + # or the `#else` branch (if present) + # - `force_print` indicates if a comment should be omitted + if_stack = [] + + def merge_escaped_lines(l, i): + while l.endswith("\\"): + l = l.removesuffix("\\").rstrip() + content[i + 1].lstrip() + i = i + 1 + return (l, i) + + def merge_commented_lines(l, i): + # Not very robust, but good enough + if not "/*" in l or "*/" in l: + return (l, i) + i += 1 + while "*/" not in content[i]: + l += content[i] + i += 1 + + l += content[i] + return (l, i) + + def should_print(cur_line_no, conds, line_no, force_print): + line_threshold = 5 + if force_print is True: + return True + + if cur_line_no - line_no >= line_threshold: + return True + return False + + def format_condition(cond): + cond = _RE_DEFINED.sub(r"\1", cond) + return parser.normalize_condition(cond) + + def format_conditions(conds, branch): + prev_conds = list(map(lambda s: f"!({s})", conds[:-1])) + final_cond = conds[-1] + if branch is False: + final_cond = f"!({final_cond})" + full_cond = "&&".join(prev_conds + [final_cond]) + return format_condition(full_cond) + + def wrap_long_directive(directive, condition, max_len=80): + """Manually wrap long preprocessor comment lines without subprocess overhead""" + single_line = directive + " " + condition + if len(single_line) <= max_len: + return single_line + + # Wrap condition across multiple lines with backslash continuation + words = condition.split() + lines = [] + current = f"{directive} " + indent = (len(directive) + 4) * " " + indent_final = (len(directive) + 2) * " " + + for word in words: + if len(current) + len(word) + 1 <= max_len: + current += word + " " + else: + lines.append(current.rstrip() + " \\") + if word == "*/": + current = indent_final + word + else: + current = indent + word + " " + + lines.append(current.rstrip()) + + return "\n".join(lines) + + def adhoc_format(directive, content): + # .c and .h files are formatted as a whole + if not source_file.endswith(".S"): + return directive + " /* " + content + " */" + # For .S files, manually wrap long lines + return wrap_long_directive(directive, "/* " + content + " */") + + i = 0 + while i < len(content): + l = content[i].strip() + # Replace #ifdef by #if defined(...) + if l.startswith("#ifdef "): + l = "#if defined(" + l.removeprefix("#ifdef").strip() + ")" + if l.startswith("#ifndef "): + l = "#if !defined(" + l.removeprefix("#ifndef").strip() + ")" + if l.startswith("#if"): + l, _ = merge_escaped_lines(l, i) + cond = l.removeprefix("#if") + if_stack.append(([cond], i, True, False)) + new_content.append(content[i]) + elif l.startswith("#elif"): + conds, _, _, force_print = if_stack.pop() + l, _ = merge_escaped_lines(l, i) + conds.append(l.removeprefix("#elif")) + if_stack.append((conds, i, True, force_print)) + new_content.append(content[i]) + elif l.startswith("#else"): + l, i = merge_escaped_lines(l, i) + _, i = merge_commented_lines(l, i) + conds, j, branch, force_print = if_stack.pop() + assert branch is True + print_else = should_print(i, cond, j, force_print) + if_stack.append((conds, i, False, print_else)) + if print_else is True: + cond = format_conditions(conds, True) + new_content.append(adhoc_format("#else", cond)) + else: + new_content.append("#else") + elif l.startswith("#endif"): + l, i = merge_escaped_lines(l, i) + _, i = merge_commented_lines(l, i) + conds, j, branch, force_print = if_stack.pop() + print_endif = should_print(i, conds, j, force_print) + if print_endif is False: + new_content.append("#endif") + else: + cond = format_conditions(conds, branch) + new_content.append(adhoc_format("#endif", cond)) + else: + # Skip over multiline comments -- we don't want to + # handle `#if ...` inside documentation as this would + # lead to nested `/* ... */`. + i_old = i + _, i = merge_commented_lines(l, i_old) + new_content += content[i_old : i + 1] + i += 1 + + return "\n".join(new_content) + + +def gen_preprocessor_comments_for(parser, source_file): + content = read_file(source_file) + new_content = adjust_preprocessor_comments_for_filename( + content, source_file, parser, show_status=True + ) + update_file(source_file, new_content) + + +def gen_preprocessor_comments(): + files = get_c_source_files() + get_asm_source_files() + get_header_files() + parser = CondParser() + run_parallel(files, partial(gen_preprocessor_comments_for, parser)) + + +def bitreverse(i, n): + r = 0 + for _ in range(n): + r = 2 * r + (i & 1) + i >>= 1 + return r + + +def signed_reduce(a): + """Return signed canonical representative of a mod b""" + c = a % modulus + if c >= modulus / 2: + c -= modulus + return c + + +def gen_c_zetas(): + """Generate source and header file for zeta values used in + the reference NTT and invNTT""" + + # The zeta values are the powers of the chosen root of unity (17), + # converted to Montgomery form. + + zeta = [0] # First entry is unused and set to 0 + for i in range(1, 256): + zeta.append(signed_reduce(pow(root_of_unity, i, modulus) * montgomery_factor)) + + # The source code stores the zeta table in bit reversed form + yield from (zeta[bitreverse(i, 8)] for i in range(256)) + + +def gen_c_zeta_file(): + def gen(): + yield from gen_header() + yield "#include " + yield "" + yield "/*" + yield " * Table of zeta values used in the reference NTT and inverse NTT." + yield " * See autogen for details." + yield " */" + yield "static const int32_t mld_zetas[MLDSA_N] = {" + yield from map(lambda t: str(t) + ",", gen_c_zetas()) + yield "};" + yield "" + + update_file("mldsa/src/zetas.inc", "\n".join(gen()), force_format=True) + + +def prepare_root_for_barrett(root): + """Takes a constant that the code needs to Barrett-multiply with, + and returns the pair of (a) its signed canonical form, (b) the + twisted constant used in the high-mul part of the Barrett multiplication.""" + + # Signed canonical reduction + root = signed_reduce(root) + + def round_to_even(t): + rt = round(t) + if rt % 2 == 0: + return rt + # Make sure to pick a rounding target + # that's <= 1 away from x in absolute value. + if rt <= t: + return rt + 1 + return rt - 1 + + root_twisted = round_to_even((root * 2**32) / modulus) // 2 + return root, root_twisted + + +def gen_aarch64_root_of_unity_for_block(layer, block, inv=False, scale=False): + # We are computing a negacyclic NTT; the twiddles needed here is + # the second half of the twiddles for a cyclic NTT of twice the size. + # For ease of calculating the roots, layers are numbers 0 through 7 + # in this function. + log = bitreverse(pow(2, layer) + block, 8) + if inv is True: + log = -log + root = pow(root_of_unity, log, modulus) + + if scale is True: + # Integrate scaling by 2**(-8) and Montgomery factor 2**32 into twiddle + root = root * pow(2, 32 - 8, modulus) + + root, root_twisted = prepare_root_for_barrett(root) + return root, root_twisted + + +def gen_aarch64_fwd_ntt_zetas_layer123456(): + # Layers 1,2,3 are merged + yield from gen_aarch64_root_of_unity_for_block(0, 0) + yield from gen_aarch64_root_of_unity_for_block(1, 0) + yield from gen_aarch64_root_of_unity_for_block(1, 1) + yield from gen_aarch64_root_of_unity_for_block(2, 0) + yield from gen_aarch64_root_of_unity_for_block(2, 1) + yield from gen_aarch64_root_of_unity_for_block(2, 2) + yield from gen_aarch64_root_of_unity_for_block(2, 3) + yield from (0, 0) # Padding + + # Layers 4,5,6 are merged + for block in range(8): # There are 8 blocks in Layer 4 + yield from gen_aarch64_root_of_unity_for_block(3, block) + yield from gen_aarch64_root_of_unity_for_block(4, 2 * block + 0) + yield from gen_aarch64_root_of_unity_for_block(4, 2 * block + 1) + yield from gen_aarch64_root_of_unity_for_block(5, 4 * block + 0) + yield from gen_aarch64_root_of_unity_for_block(5, 4 * block + 1) + yield from gen_aarch64_root_of_unity_for_block(5, 4 * block + 2) + yield from gen_aarch64_root_of_unity_for_block(5, 4 * block + 3) + yield from (0, 0) # Padding + + +def gen_aarch64_fwd_ntt_zetas_layer78(): + # Layers 4,5,6,7,8 are merged, but we emit roots for 4,5,6 + # in separate arrays than those for 7,8 + for block in range(8): + + # Ordering of blocks is adjusted to suit the transposed internal + # presentation of the data + + for i in range(2): + yield gen_aarch64_root_of_unity_for_block(6, 8 * block + 0)[i] + yield gen_aarch64_root_of_unity_for_block(6, 8 * block + 1)[i] + yield gen_aarch64_root_of_unity_for_block(6, 8 * block + 2)[i] + yield gen_aarch64_root_of_unity_for_block(6, 8 * block + 3)[i] + + for i in range(2): + yield gen_aarch64_root_of_unity_for_block(7, 16 * block + 0)[i] + yield gen_aarch64_root_of_unity_for_block(7, 16 * block + 2)[i] + yield gen_aarch64_root_of_unity_for_block(7, 16 * block + 4)[i] + yield gen_aarch64_root_of_unity_for_block(7, 16 * block + 6)[i] + + for i in range(2): + yield gen_aarch64_root_of_unity_for_block(7, 16 * block + 1)[i] + yield gen_aarch64_root_of_unity_for_block(7, 16 * block + 3)[i] + yield gen_aarch64_root_of_unity_for_block(7, 16 * block + 5)[i] + yield gen_aarch64_root_of_unity_for_block(7, 16 * block + 7)[i] + + for i in range(2): + yield gen_aarch64_root_of_unity_for_block(6, 8 * block + 0 + 4)[i] + yield gen_aarch64_root_of_unity_for_block(6, 8 * block + 1 + 4)[i] + yield gen_aarch64_root_of_unity_for_block(6, 8 * block + 2 + 4)[i] + yield gen_aarch64_root_of_unity_for_block(6, 8 * block + 3 + 4)[i] + + for i in range(2): + yield gen_aarch64_root_of_unity_for_block(7, 16 * block + 0 + 8)[i] + yield gen_aarch64_root_of_unity_for_block(7, 16 * block + 2 + 8)[i] + yield gen_aarch64_root_of_unity_for_block(7, 16 * block + 4 + 8)[i] + yield gen_aarch64_root_of_unity_for_block(7, 16 * block + 6 + 8)[i] + + for i in range(2): + yield gen_aarch64_root_of_unity_for_block(7, 16 * block + 1 + 8)[i] + yield gen_aarch64_root_of_unity_for_block(7, 16 * block + 3 + 8)[i] + yield gen_aarch64_root_of_unity_for_block(7, 16 * block + 5 + 8)[i] + yield gen_aarch64_root_of_unity_for_block(7, 16 * block + 7 + 8)[i] + + +def gen_aarch64_intt_zetas_layer78(): + for block in range(16): + for i in range(2): + yield gen_aarch64_root_of_unity_for_block(6, block * 4 + 0, inv=True)[i] + yield gen_aarch64_root_of_unity_for_block(6, block * 4 + 1, inv=True)[i] + yield gen_aarch64_root_of_unity_for_block(6, block * 4 + 2, inv=True)[i] + yield gen_aarch64_root_of_unity_for_block(6, block * 4 + 3, inv=True)[i] + + for i in range(2): + yield gen_aarch64_root_of_unity_for_block(7, block * 8 + 0, inv=True)[i] + yield gen_aarch64_root_of_unity_for_block(7, block * 8 + 2, inv=True)[i] + yield gen_aarch64_root_of_unity_for_block(7, block * 8 + 4, inv=True)[i] + yield gen_aarch64_root_of_unity_for_block(7, block * 8 + 6, inv=True)[i] + + for i in range(2): + yield gen_aarch64_root_of_unity_for_block(7, block * 8 + 1, inv=True)[i] + yield gen_aarch64_root_of_unity_for_block(7, block * 8 + 3, inv=True)[i] + yield gen_aarch64_root_of_unity_for_block(7, block * 8 + 5, inv=True)[i] + yield gen_aarch64_root_of_unity_for_block(7, block * 8 + 7, inv=True)[i] + + +def gen_aarch64_intt_zetas_layer123456(): + for i in range(16): + yield from gen_aarch64_root_of_unity_for_block(4, i, inv=True) + yield from (0, 0) # Padding + yield from gen_aarch64_root_of_unity_for_block(5, i * 2, inv=True) + yield from gen_aarch64_root_of_unity_for_block(5, i * 2 + 1, inv=True) + + # The last layer has the scaling by 1/256 integrated in the twiddle + yield from gen_aarch64_root_of_unity_for_block(0, 0, inv=True, scale=True) + + yield from gen_aarch64_root_of_unity_for_block(1, 0, inv=True) + yield from gen_aarch64_root_of_unity_for_block(1, 1, inv=True) + yield from gen_aarch64_root_of_unity_for_block(2, 0, inv=True) + yield from gen_aarch64_root_of_unity_for_block(2, 1, inv=True) + yield from gen_aarch64_root_of_unity_for_block(2, 2, inv=True) + yield from gen_aarch64_root_of_unity_for_block(2, 3, inv=True) + yield from gen_aarch64_root_of_unity_for_block(3, 0, inv=True) + yield from gen_aarch64_root_of_unity_for_block(3, 1, inv=True) + yield from gen_aarch64_root_of_unity_for_block(3, 2, inv=True) + yield from gen_aarch64_root_of_unity_for_block(3, 3, inv=True) + yield from gen_aarch64_root_of_unity_for_block(3, 4, inv=True) + yield from gen_aarch64_root_of_unity_for_block(3, 5, inv=True) + yield from gen_aarch64_root_of_unity_for_block(3, 6, inv=True) + yield from gen_aarch64_root_of_unity_for_block(3, 7, inv=True) + yield from (0, 0) # Padding + + +def print_hol_light_array(g, as_int=True, entries_per_line=8, pad=0): + + # Format of integer list entries, including `;` separator: + # - Positive numbers: &42; + # - Negative numbers: -- &42; + # If as_int is false, we omit `&` and emit constant as numerals. + def format_hol_light_int(n): + prefix = "" + if n < 0: + prefix = "-- " + n = -n + c = "&" if as_int is True else "" + return f"{prefix}{c}{n:>{pad}};" + + l = list(map(format_hol_light_int, g)) + # Remove `;` from end of last entry + l[-1] = l[-1][:-1] + + for i in range(0, len(l), entries_per_line): + yield " " + " ".join(l[i : i + entries_per_line]) + + +def gen_aarch64_zeta_file(): + def gen(): + yield from gen_header() + yield '#include "../../../common.h"' + yield "" + yield "#if defined(MLD_ARITH_BACKEND_AARCH64) && \\" + yield " !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)" + yield "" + yield "#include " + yield '#include "arith_native_aarch64.h"' + yield "" + yield "/*" + yield " * Table of zeta values used in the AArch64 forward NTT" + yield " * See autogen for details." + yield " */" + yield "MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer123456[] = {" + yield from map(lambda t: str(t) + ",", gen_aarch64_fwd_ntt_zetas_layer123456()) + yield "};" + yield "" + yield "MLD_ALIGN const int32_t mld_aarch64_ntt_zetas_layer78[] = {" + yield from map(lambda t: str(t) + ",", gen_aarch64_fwd_ntt_zetas_layer78()) + yield "};" + yield "" + yield "MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer78[] = {" + yield from map(lambda t: str(t) + ",", gen_aarch64_intt_zetas_layer78()) + yield "};" + yield "" + yield "MLD_ALIGN const int32_t mld_aarch64_intt_zetas_layer123456[] = {" + yield from map(lambda t: str(t) + ",", gen_aarch64_intt_zetas_layer123456()) + yield "};" + yield "" + yield "#else" + yield "" + yield "MLD_EMPTY_CU(aarch64_zetas)" + yield "" + yield "#endif" + yield "" + + update_file("dev/aarch64_opt/src/aarch64_zetas.c", "\n".join(gen())) + + update_file("dev/aarch64_clean/src/aarch64_zetas.c", "\n".join(gen())) + + +def gen_aarch64_rej_uniform_eta_table_rows(): + # The index into the lookup table is an 8-bit bitmap, i.e. a number 0..255. + # Conceptually, the table entry at index i is a vector of 8 16-bit values, of + # which only the first popcount(i) are set; those are the indices of the set-bits + # in i. Concretely, we store each 16-bit index as consecutive 8-bit indices. + def get_set_bits_idxs(i): + bits = list(map(int, format(i, "08b"))) + bits.reverse() + return [bit_idx for bit_idx in range(8) if bits[bit_idx] == 1] + + for i in range(256): + idxs = get_set_bits_idxs(i) + # Replace each index by two consecutive indices + idxs = [j for i in idxs for j in [2 * i, 2 * i + 1]] + # Pad by 255 (invalid index) + idxs = idxs + [255] * (16 - len(idxs)) + yield idxs + + +def gen_aarch64_rej_uniform_eta_table(): + def gen(): + yield from gen_header() + yield '#include "../../../common.h"' + yield "" + yield "#if defined(MLD_ARITH_BACKEND_AARCH64) && \\" + yield " !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)" + yield "" + yield "#include " + yield '#include "arith_native_aarch64.h"' + yield "" + yield "/*" + yield " * Lookup table used by 16-bit rejection sampling (rej_eta)." + yield " * Adapted from ML-KEM for ML-DSA eta rejection sampling." + yield " * See autogen for details." + yield " */" + yield "MLD_ALIGN const uint8_t mld_rej_uniform_eta_table[] = {" + for i, idxs in enumerate(gen_aarch64_rej_uniform_eta_table_rows()): + yield ",".join(map(str, idxs)) + f" /* {i} */," + yield "};" + yield "" + yield "#else" + yield "" + yield "MLD_EMPTY_CU(aarch64_rej_uniform_eta_table)" + yield "" + yield "#endif" + yield "" + + update_file("dev/aarch64_opt/src/rej_uniform_eta_table.c", "\n".join(gen())) + + update_file("dev/aarch64_clean/src/rej_uniform_eta_table.c", "\n".join(gen())) + + +def gen_aarch64_rej_uniform_table_rows(): + # The index into the lookup table is an 4-bit bitmap, i.e. a number 0..15. + # Conceptually, the table entry at index i is a vector of 4-bit values, of + # which only the first popcount(i) are set; those are the indices of the set-bits + # in i. Concretely, we store each 32-bit index as consecutive 8-bit indices. + def get_set_bits_idxs(i): + bits = list(map(int, format(i, "08b"))) + bits.reverse() + return [bit_idx for bit_idx in range(8) if bits[bit_idx] == 1] + + for i in range(16): + idxs = get_set_bits_idxs(i) + # Replace each index by two consecutive indices + idxs = [j for i in idxs for j in [4 * i + k for k in range(4)]] + # Pad by -1 + idxs = idxs + [255] * (16 - len(idxs)) + yield idxs + + +def gen_aarch64_rej_uniform_table(): + def gen(): + yield from gen_header() + yield '#include "../../../common.h"' + yield "" + yield "#if defined(MLD_ARITH_BACKEND_AARCH64) && \\" + yield " !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)" + yield "" + yield "#include " + yield '#include "arith_native_aarch64.h"' + yield "" + yield "/*" + yield " * Lookup table used by rejection sampling of the public matrix." + yield " * See autogen for details." + yield " */" + yield "MLD_ALIGN const uint8_t mld_rej_uniform_table[] = {" + for i, idxs in enumerate(gen_aarch64_rej_uniform_table_rows()): + yield ",".join(map(str, idxs)) + f" /* {i} */," + yield "};" + yield "" + yield "#else" + yield "" + yield "MLD_EMPTY_CU(aarch64_rej_uniform_table)" + yield "" + yield "#endif" + yield "" + + update_file("dev/aarch64_opt/src/rej_uniform_table.c", "\n".join(gen())) + + update_file("dev/aarch64_clean/src/rej_uniform_table.c", "\n".join(gen())) + + +def gen_avx2_rej_uniform_table_rows(): + # The index into the lookup table is an 8-bit bitmap, i.e. a number 0..255. + # Conceptually, the table entry at index i is a vector of 8 16-bit values, of + # which only the first popcount(i) are set; those are the indices of the set-bits + # in i. + def get_set_bits_idxs(i): + bits = list(map(int, format(i, "08b"))) + bits.reverse() + return [bit_idx for bit_idx in range(8) if bits[bit_idx] == 1] + + for i in range(256): + idxs = get_set_bits_idxs(i) + idxs = [i for i in idxs] + # Pad by 0 + idxs = idxs + [0] * (8 - len(idxs)) + yield "{" + ",".join(map(str, idxs)) + "}" + + +def gen_avx2_rej_uniform_table(): + def gen(): + yield from gen_header() + yield '#include "../../../common.h"' + yield "" + yield "#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \\" + yield " !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)" + yield "" + yield "#include " + yield '#include "arith_native_x86_64.h"' + yield "" + yield "/*" + yield " * Lookup table used by rejection sampling." + yield " * See autogen for details." + yield " */" + yield "MLD_ALIGN const uint8_t mld_rej_uniform_table[256][8] = {" + yield from map(lambda t: str(t) + ",", gen_avx2_rej_uniform_table_rows()) + yield "};" + yield "" + yield "#else" + yield "" + yield "MLD_EMPTY_CU(avx2_rej_uniform_table)" + yield "" + yield "#endif" + yield "" + + update_file("dev/x86_64/src/rej_uniform_table.c", "\n".join(gen())) + + +def signed_reduce(a): + """Return signed canonical representative of a mod b""" + c = a % modulus + if c >= modulus / 2: + c -= modulus + return c + + +def signed_reduce_u32(a): + """Return signed canonical representative of a mod b""" + c = a % 2**32 + if c >= 2**31: + c -= 2**32 + return c + + +def prepare_root_for_montmul(root, mult): + """Takes a constant that the code needs to Montgomery-multiply with, + and returns the pair of (a) the signed canonical representative of its + Montgomery form, (b) the twisted constant used in the low-mul part of + the Montgomery multiplication.""" + + # Convert to Montgomery form and pick canonical signed representative + root = signed_reduce(root * montgomery_factor) + if mult: + root = signed_reduce_u32(root * pow(modulus, -1, 2**32)) + return root + + +def gen_avx2_root_of_unity_for_block(layer, block, mult=False): + # We are computing a negacyclic NTT; the twiddles needed here is + # the second half of the twiddles for a cyclic NTT of twice the size. + log = bitreverse(pow(2, layer) + block, 8) + root = pow(root_of_unity, log, modulus) + return prepare_root_for_montmul(root, mult) + + +def gen_avx2_fwd_ntt_zetas(mult=False): + + def gen_twiddles(layer, block, repeat, mult): + root = gen_avx2_root_of_unity_for_block(layer, block, mult) + return [root] * repeat + + def gen_twiddles_many(layer, block_base, block_offsets, repeat, mult): + roots = list( + map( + lambda x: gen_twiddles(layer, block_base + x, repeat, mult), + block_offsets, + ) + ) + yield from (r for l in roots for r in l) + + # embed the scaling of 1/256 and correction of the Montgomery factor + # from the basemul into last twiddle of the inverse NTT + # - root^-128 * 2^64/256 + # In the forward NTT this twiddle is unused + f = signed_reduce(-pow(root_of_unity, -128, modulus) * 2**56) + if mult: + f = signed_reduce_u32(f * pow(modulus, -1, 2**32)) + + yield f + + # Layers 1 twiddle + # In the inverse NTT this twiddle is unused + yield from gen_twiddles_many(0, 0, range(1), 1, mult) + + # Layer 2-8 twiddles + yield from gen_twiddles_many(1, 0, range(2), 1, mult) + yield from gen_twiddles_many(2, 0, range(4), 1, mult) + yield from gen_twiddles_many(3, 0, range(8), 4, mult) + yield from gen_twiddles_many(4, 0, range(16), 2, mult) + yield from gen_twiddles_many(5, 0, range(32), 1, mult) + for i in range(32): + yield from gen_twiddles_many(6, i * 2, range(1), 1, mult) + for i in range(32): + yield from gen_twiddles_many(6, i * 2 + 1, range(1), 1, mult) + + for k in range(4): + for i in range(32): + yield from gen_twiddles_many(7, i * 4 + k, range(1), 1, mult) + + +def gen_avx2_zetas_qdata(): + def cmod(a, mod): + """Return signed canonical representative of a mod b""" + c = a % mod + if c >= mod / 2: + c -= mod + return c + + # MLD_AVX2_Q + q_dup = [modulus] * 8 + # MLD_AVX2_QINV + qinv_dup = [pow(modulus, -1, 2**32)] * 8 + # MLD_AVX2_DIV_QINV + div_qinv_dup = [cmod(pow(modulus, -1, 2**32) * pow(2, 64 - 8, modulus), 2**32)] * 8 + # MLD_AVX2_DIV + div_dup = [pow(2, 64 - 8, modulus)] * 8 + + zetas_qinv = list(gen_avx2_fwd_ntt_zetas(mult=True)) + zetas = list(gen_avx2_fwd_ntt_zetas(mult=False)) + + q_idx = 0 + qinv_idx = q_idx + len(q_dup) + div_qinv_idx = qinv_idx + len(qinv_dup) + div_idx = div_qinv_idx + len(div_qinv_dup) + zetas_qinv_idx = div_idx + len(div_dup) + zetas_idx = zetas_qinv_idx + len(zetas_qinv) + + constants = q_dup + qinv_dup + div_qinv_dup + div_dup + zetas_qinv + zetas + offsets = { + "q": q_idx, + "qinv": qinv_idx, + "div_qinv": div_qinv_idx, + "div": div_idx, + "zetas_qinv": zetas_qinv_idx, + "zetas": zetas_idx, + } + return constants, offsets + + +def gen_avx2_hol_light_zeta_file(): + def gen(): + yield from gen_hol_light_header() + yield "(*" + yield " * Table of zeta values used in the AVX2 NTTs" + yield " * See autogen for details." + yield " *)" + yield "" + yield "let mldsa_complete_qdata = define `mldsa_complete_qdata:int list = [" + constants, _ = gen_avx2_zetas_qdata() + yield from print_hol_light_array(constants) + yield "]`;;" + yield "" + + update_file("proofs/hol_light/x86_64/proofs/mldsa_zetas.ml", "\n".join(gen())) + + +def gen_avx2_zeta_file(): + constants, offsets = gen_avx2_zetas_qdata() + + def gen_c(): + yield from gen_header() + yield '#include "../../../common.h"' + yield "" + yield "#if defined(MLD_ARITH_BACKEND_X86_64_DEFAULT) && \\" + yield " !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)" + yield "" + yield '#include "consts.h"' + yield "" + yield "/*" + yield " * Table of zeta values used in the AVX2 forward and inverse NTT" + yield " * See autogen for details." + yield " */" + yield f"MLD_ALIGN const int32_t mld_qdata[{len(constants)}] = {{" + yield from map(lambda t: str(t) + ",", constants) + yield "};" + yield "" + yield "#else" + yield "" + yield "MLD_EMPTY_CU(avx2_consts)" + yield "" + yield "#endif" + yield "" + + def gen_h(): + yield from gen_header() + yield "#ifndef MLD_NATIVE_X86_64_SRC_CONSTS_H" + yield "#define MLD_NATIVE_X86_64_SRC_CONSTS_H" + yield '#include "../../../common.h"' + yield f"#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQ {offsets['q']}" + yield f"#define MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV {offsets['qinv']}" + yield f"#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV {offsets['div_qinv']}" + yield f"#define MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV {offsets['div']}" + yield f"#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV {offsets['zetas_qinv']}" + yield f"#define MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS {offsets['zetas']}" + yield "" + yield "#ifndef __ASSEMBLER__" + yield "#define mld_qdata MLD_NAMESPACE(qdata)" + yield f"extern const int32_t mld_qdata[{len(constants)}];" + yield "#endif" + yield "" + yield "#endif" + yield "" + + update_file("dev/x86_64/src/consts.c", "\n".join(gen_c())) + update_file("dev/x86_64/src/consts.h", "\n".join(gen_h())) + + +def get_c_source_files(main_only=False, core_only=False, strip_mldsa=False): + if main_only is True: + return get_files("mldsa/src/**/*.c", strip_mldsa=strip_mldsa) + elif core_only is True: + return get_files("mldsa/src/**/*.c", strip_mldsa=strip_mldsa) + get_files( + "dev/**/*.c" + ) + else: + return get_files("**/*.c", strip_mldsa=strip_mldsa) + + +def get_asm_source_files(main_only=False, core_only=False, strip_mldsa=False): + if main_only is True: + return get_files("mldsa/src/**/*.S", strip_mldsa=strip_mldsa) + elif core_only is True: + return get_files("mldsa/src/**/*.S", strip_mldsa=strip_mldsa) + get_files( + "dev/**/*.S", strip_mldsa=strip_mldsa + ) + else: + return get_files("**/*.S", strip_mldsa=strip_mldsa) + + +def get_header_files(main_only=False, core_only=False): + if main_only is True: + return get_files("mldsa/*.h") + get_files("mldsa/src/**/*.h") + elif core_only is True: + return ( + get_files("mldsa/*.h") + + get_files("mldsa/src/**/*.h") + + get_files("dev/**/*.h") + + get_files("integration/**/*.h") + ) + else: + return get_files("**/*.h") + + +def get_markdown_files(main_only=False): + return get_files("**/*.md") + + +def get_files(pattern, strip_mldsa=False): + def normalize(f): + return f.removeprefix("mldsa/") if strip_mldsa else f + + fs_files = {f for f in get_all_files() if pathlib.Path(f).is_file()} + cache_files = set(_file_cache.keys()) + + # Convert glob pattern to compiled regex + pattern = pattern.replace(".", r"\.") + pattern = pattern.replace("**/", "<<>>") + pattern = pattern.replace("*", "[^/]*") + pattern = pattern.replace("<<>>", "(?:.*/)?") + regexp = re.compile(f"^{pattern}$") + + # Remove files which are scheduled to be deleted + res = list( + map( + normalize, + filter( + lambda f: regexp.match(f) and (read_file(f) is not None), + fs_files | cache_files, + ), + ) + ) + + return res + + +def get_all_files(): + # All git-tracked files, including symlinks + r = subprocess.run(["git", "ls-files"], capture_output=True, text=True) + assert r.returncode == 0 + files = r.stdout.split("\n") + files = filter(lambda s: s != "" and pathlib.Path(s).is_symlink() is False, files) + return files + + +def get_defines_from_file(c): + for l in read_file(c).split("\n"): + m = _RE_DEFINE.match(l) + if m: + yield (c, m.group(1)) + + +def get_defines(all=False): + if all is False: + files = get_header_files(main_only=True) + else: + files = get_header_files() + get_c_source_files() + get_asm_source_files() + + for results in run_parallel(files, get_defines_from_file): + yield from results + + +def get_checked_defines(): + allow_list = [("__contract__", "cbmc.h"), ("__loop__", "cbmc.h")] + + def is_allowed(d, c): + for d0, c0 in allow_list: + if c.endswith(c0) is True and d0 == d: + return True + return False + + for c, d in get_defines(): + if d.startswith("_") and is_allowed(d, c) is False: + raise Exception( + f"{d} from {c}: starts with an underscore, which is not allowed for mldsa-native macros. " + f"If this is an mldsa-native specific macro, please pick a different name. " + f"If this is an external macro, it likely needs removing from `gen_monolithic_undef_all_core()` in `scripts/autogen` -- check this!" + ) + yield (c, d) + + +def gen_monolithic_undef_all_core(filt=None, desc=""): + + if filt is None: + filt = lambda c: True + + if desc != "": + yield "/*" + yield f" * Undefine macros from {desc}" + yield " */" + + defines = list(set(get_checked_defines())) + defines.sort() + + last_filename = None + for filename, d in defines: + if filt(filename) is False: + continue + if last_filename != filename: + yield f"/* {filename} */" + last_filename = filename + yield f"#undef {d}" + + +def native(c): + return "/native/" in c + + +def fips202(c): + return "/fips202/" in c + + +def aarch64(c): + return "/aarch64/" in c + + +def x86_64(c): + return "/x86_64/" in c + + +def riscv64(c): + return "/riscv64/" in c + + +def native_fips202(c): + return native(c) and fips202(c) + + +def native_arith(c): + return native(c) and not fips202(c) + + +def native_fips202_aarch64(c): + return native_fips202(c) and aarch64(c) + + +def native_fips202_x86_64(c): + return native_fips202(c) and x86_64(c) + + +def native_fips202_core(c): + return ( + native_fips202(c) + and not native_fips202_x86_64(c) + and not native_fips202_aarch64(c) + ) + + +def native_arith_aarch64(c): + return native_arith(c) and aarch64(c) + + +def native_arith_x86_64(c): + return native_arith(c) and x86_64(c) + + +def native_arith_riscv64(c): + return native_arith(c) and riscv64(c) + + +def native_arith_core(c): + return ( + native_arith(c) + and not native_arith_x86_64(c) + and not native_arith_aarch64(c) + and not native_arith_riscv64(c) + ) + + +# List of level-specific source files +# All other files only need including and building once +# in multi-level build. +def k_specific(c): + k_specific_sources = [ + "mldsa_native.h", + "params.h", + "common.h", + "packing.c", + "packing.h", + "poly_kl.c", + "poly_kl.h", + "polyvec.c", + "polyvec.h", + "rounding.h", + "sign.c", + "sign.h", + ] + for f in k_specific_sources: + if c.endswith(f): + return True + return False + + +def k_generic(c): + return not k_specific(c) and c != "mldsa/mldsa_native_config.h" + + +def gen_macro_undefs(extra_notes=None): + if extra_notes is None: + extra_notes = [] + + yield "/* Macro #undef's" + yield " *" + yield " * The following undefines macros from headers" + yield " * included by the source files imported above." + yield " *" + yield " * This is to allow building and linking multiple builds" + yield " * of mldsa-native for varying parameter sets through concatenation" + yield " * of this file, as if the files had been compiled separately." + yield " * If this is not relevant to you, you may remove the following." + for e in extra_notes: + yield f" * {e}" + yield " */" + yield "" + yield from gen_monolithic_undef_all_core( + filt=k_specific, desc="MLD_CONFIG_PARAMETER_SET-specific files" + ) + yield "" + yield "#if !defined(MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS)" + yield from gen_monolithic_undef_all_core( + filt=lambda c: not native(c) + and k_generic(c) + and not fips202(c) + and "cbmc.h" not in c, + desc="MLD_CONFIG_PARAMETER_SET-generic files", + ) + # Handle cbmc.h manually -- most #define's therein are only defined when CBMC is set + # and need not be #undef'ed. In fact, #undef'ing them is risky since their names may + # well already be occupied. + yield "/* mldsa/src/cbmc.h */" + yield "#undef MLD_CBMC_H" + yield "#undef __contract__" + yield "#undef __loop__" + yield "" + yield "#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER)" + yield from gen_monolithic_undef_all_core( + filt=lambda c: not native(c) and k_generic(c) and fips202(c), + desc="FIPS-202 files", + ) + yield "#endif" + yield "" + yield "#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202)" + yield from gen_monolithic_undef_all_core(filt=native_fips202_core, desc="") + yield "#if defined(MLD_SYS_AARCH64)" + yield from gen_monolithic_undef_all_core( + filt=native_fips202_aarch64, desc="native code (FIPS202, AArch64)" + ) + yield "#endif" + yield "#if defined(MLD_SYS_X86_64)" + yield from gen_monolithic_undef_all_core( + filt=native_fips202_x86_64, desc="native code (FIPS202, x86_64)" + ) + yield "#endif" + yield "#endif" + yield "#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH)" + yield from gen_monolithic_undef_all_core(filt=native_arith_core, desc="") + yield "#if defined(MLD_SYS_AARCH64)" + yield from gen_monolithic_undef_all_core( + filt=native_arith_aarch64, desc="native code (Arith, AArch64)" + ) + yield "#endif" + yield "#if defined(MLD_SYS_X86_64)" + yield from gen_monolithic_undef_all_core( + filt=native_arith_x86_64, desc="native code (Arith, X86_64)" + ) + yield "#endif" + yield "#endif" + yield "#endif" + yield "" + + +def gen_monolithic_source_file(): + + def gen(): + c_sources = get_c_source_files(main_only=True, strip_mldsa=True) + yield from gen_header() + + yield "/******************************************************************************" + yield " *" + yield " * Single compilation unit (SCU) for fixed-level build of mldsa-native" + yield " *" + yield " * This compilation unit bundles together all source files for a build" + yield " * of mldsa-native for a fixed security level (MLDSA-44/65/87)." + yield " *" + yield " * # API" + yield " *" + yield " * The API exposed by this file is described in mldsa_native.h." + yield " *" + yield " * # Multi-level build" + yield " *" + yield " * If you want an SCU build of mldsa-native with support for multiple security" + yield " * levels, you need to include this file multiple times, and set" + yield " * MLD_CONFIG_MULTILEVEL_WITH_SHARED and MLD_CONFIG_MULTILEVEL_NO_SHARED" + yield " * appropriately. This is exemplified in examples/monolithic_build_multilevel" + yield " * and examples/monolithic_build_multilevel_native." + yield " *" + yield " * # Configuration" + yield " *" + yield " * The following options from the mldsa-native configuration are relevant:" + yield " *" + yield " * - MLD_CONFIG_FIPS202_CUSTOM_HEADER" + yield " * Set this option if you use a custom FIPS202 implementation." + yield " *" + yield " * - MLD_CONFIG_USE_NATIVE_BACKEND_ARITH" + yield " * Set this option if you want to include the native arithmetic backends" + yield " * in your build." + yield " *" + yield " * - MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202" + yield " * Set this option if you want to include the native FIPS202 backends" + yield " * in your build." + yield " *" + yield " * - MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS" + yield " * Set this option if you want to keep the directives defined in" + yield " * level-independent headers. This is needed for a multi-level build." + yield " */" + yield " " + yield " /* If parts of the mldsa-native source tree are not used," + yield " * consider reducing this header via `unifdef`." + yield " *" + yield " * Example:" + yield " * ```bash" + yield " * unifdef -UMLD_CONFIG_USE_NATIVE_BACKEND_ARITH mldsa_native.c" + yield " * ```" + yield " */" + yield "" + yield '#include "src/common.h"' + yield "" + for c in filter(lambda c: not native(c) and not fips202(c), c_sources): + yield f'#include "{c}"' + yield "" + yield "#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER)" + for c in filter(lambda c: not native(c) and fips202(c), c_sources): + yield f'#include "{c}"' + yield "#endif" + yield "" + yield "#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH)" + yield "#if defined(MLD_SYS_AARCH64)" + for c in filter(native_arith_aarch64, c_sources): + yield f'#include "{c}"' + yield "#endif" + yield "#if defined(MLD_SYS_X86_64)" + for c in filter(native_arith_x86_64, c_sources): + yield f'#include "{c}"' + yield "#endif" + yield "#endif" + yield "" + yield "#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202)" + yield "#if defined(MLD_SYS_AARCH64)" + for c in filter(native_fips202_aarch64, c_sources): + yield f'#include "{c}"' + yield "#endif" + yield "#if defined(MLD_SYS_X86_64)" + for c in filter(native_fips202_x86_64, c_sources): + yield f'#include "{c}"' + yield "#endif" + yield "#endif" + yield "" + yield from gen_macro_undefs() + + update_file("mldsa/mldsa_native.c", "\n".join(gen())) + + +def gen_monolithic_asm_file(): + + def gen(): + asm_sources = get_asm_source_files(main_only=True, strip_mldsa=True) + yield from gen_header() + yield "/******************************************************************************" + yield " *" + yield " * Single assembly unit for fixed-level build of mldsa-native" + yield " *" + yield " * This assembly unit bundles together all assembly files for a build" + yield " * of mldsa-native for a fixed security level (MLDSA-44/65/87)." + yield " *" + yield " * # Multi-level build" + yield " *" + yield " * If you want an SCU build of mldsa-native with support for multiple security" + yield " * levels, you should include this file once with MLD_CONFIG_MULTILEVEL_WITH_SHARED set." + yield " *" + yield " * (You could also follow the same pattern as for mldsa_native_monobuild.c" + yield " * and include it for every level, setting MLD_CONFIG_MULTILEVEL_NO_SHARED" + yield " * for all but one. For builds with MLD_CONFIG_MULTILEVEL_NO_SHARED, this" + yield " * file will then be ignored.)" + yield " *" + yield " * # Configuration" + yield " *" + yield " * The following options from the mldsa-native configuration are relevant:" + yield " *" + yield " * - MLD_CONFIG_FIPS202_CUSTOM_HEADER" + yield " * Set this option if you use a custom FIPS202 implementation." + yield " *" + yield " * - MLD_CONFIG_USE_NATIVE_BACKEND_ARITH" + yield " * Set this option if you want to include the native arithmetic backends" + yield " * in your build." + yield " *" + yield " * - MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202" + yield " * Set this option if you want to include the native FIPS202 backends" + yield " * in your build." + yield " *" + yield " * - MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS" + yield " * Set this option if you want to keep the directives defined in" + yield " * level-independent headers. This is needed for a multi-level build." + yield " */" + yield "" + yield "/* If parts of the mldsa-native source tree are not used," + yield " * consider reducing this header via `unifdef`." + yield " *" + yield " * Example:" + yield " * ```bash" + yield " * unifdef -UMLD_CONFIG_USE_NATIVE_BACKEND_ARITH mldsa_native.S" + yield " * ```" + yield " */" + yield "" + yield '#include "src/common.h"' + yield "" + yield "#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH)" + yield "#if defined(MLD_SYS_AARCH64)" + for c in filter(native_arith_aarch64, asm_sources): + yield f'#include "{c}"' + yield "#endif" + yield "#if defined(MLD_SYS_X86_64)" + for c in filter(native_arith_x86_64, asm_sources): + yield f'#include "{c}"' + yield "#endif" + yield "#endif" + yield "" + yield "#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202)" + yield "#if defined(MLD_SYS_AARCH64)" + for c in filter(native_fips202_aarch64, asm_sources): + yield f'#include "{c}"' + yield "#endif" + yield "#if defined(MLD_SYS_X86_64)" + for c in filter(native_fips202_x86_64, asm_sources): + yield f'#include "{c}"' + yield "#endif" + yield "#endif" + yield "" + # We generate #undef's for all headers, even though most are not + # included by the assembly files. This does not harm, and avoids + # having to trace which headers are being pulled in from common.h + # included from the assembly files. + yield "" + extra = [ + "", + "NOTE: This is not needed for the assembly SCU since, at present,", + "there is no need to include it multiple times.", + "We keep it for uniformity with mldsa_native.c only.", + "", + "NOTE: To avoid having to distinguish between which headers are included", + "from the assembly files, we #undef the same set of directives", + "as in mldsa_native.c", + ] + yield from gen_macro_undefs(extra_notes=extra) + + update_file("mldsa/mldsa_native.S", "\n".join(gen()), force_format=True) + + +def get_config_options(): + content = read_file("mldsa/mldsa_native_config.h") + config_pattern = r"Name:\s*(MLD_CONFIG_\w+)" + + configs = re.findall(config_pattern, content) + + configs += [ + "MLD_FORCE_AARCH64", + "MLD_FORCE_AARCH64_EB", + "MLD_FORCE_X86_64", + "MLD_FORCE_PPC64LE", + "MLD_FORCE_RISCV64", + "MLD_FORCE_RISCV32", + "MLD_SYS_AARCH64_SLOW_BARREL_SHIFTER", + "MLDSA_DEBUG", # TODO: Rename? + "MLD_BREAK_PCT", # Use in PCT breakage test + "MLD_CHECK_APIS", + "MLD_CONFIG_API_XXX", + "MLD_ERR_XXX", + "MLD_USE_NATIVE_XXX", + "MLD_CONFIG_XXX", + "MLD_CONFIG_API_CONSTANTS_ONLY", + "MLD_PREHASH_", + ] + + return configs + + +def check_macro_typos_in_file(filename, macro_check): + """Checks for typos in MLD_XXX and MLDSA_XXX identifiers.""" + content = read_file(filename) + + # Separate check for wrongly ported MLK/MLKEM macros + for m in _RE_MLKEM_MACRO_CHECK.finditer(content): + txt = m.group(1) + rest = m.group(2) + line_no = content[: m.start()].count("\n") + 1 + if filename != "scripts/autogen": + raise Exception( + f"Likely typo {txt} in {filename}:{line_no}? wrongly ported MLK_XXX / MLKEM_XXX macros from mlkem-native." + ) + + # Check MLD/MLDSA macros + for m in _RE_MACRO_CHECK.finditer(content): + txt = m.group(1) + rest = m.group(2) + if macro_check(txt, rest, filename) is False: + line_no = content[: m.start()].count("\n") + 1 + raise Exception( + f"Likely typo {txt} in {filename}:{line_no}? Not a defined macro." + ) + + +def get_syscaps(): + return ["MLD_SYS_CAP_AVX2", "MLD_SYS_CAP_SHA3", "MLD_SYS_CAP_DUMMY"] + + +def check_macro_typos(): + files = get_all_files() + syscaps = get_syscaps() + + macros = set(map(lambda t: t[1], get_defines(all=True))) + + # Add configuration options to the list of allows macro names + macros.update(get_config_options()) + + def macro_check(m, rest, filename): + if m in macros: + return True + + # Ignore alloc macros only defined in mldsa_native.h + if m.startswith("MLD_TOTAL_ALLOC") or m.startswith("MLD_MAX_TOTAL_ALLOC"): + return True + + is_autogen = filename == "scripts/autogen" + + # Exclude system capabilities, which are enum values + if m in syscaps: + return True + + # + # Register some file-specific exceptions + # + + # 1. Makefiles use MLD_SOURCE_XXX to list source files + if is_autogen or filename.endswith("/Makefile"): + if m.startswith("MLD_SOURCE") or m.startswith("MLD_OBJ"): + return True + + # 2. libOQS specific identifier + if is_autogen or filename.startswith("integration/liboqs"): + if m.startswith("MLDSA_NATIVE_MLDSA") or m in ["MLDSA_DIR"]: + return True + + # 3. Exclude HOL-Light proof scripts + if is_autogen or filename.startswith("proofs/hol_light"): + if filename.endswith(".ml"): + return True + + # 4. Exclude regexp patterns in `autogen` + if is_autogen: + if rest.startswith("\\") or m in ["MLD_XXX", "MLD_SOURCE_XXX"]: + return True + + # 5. AWS-LC importer patch + if is_autogen or filename == "integration/awslc/awslc.patch": + return True + + if is_autogen or filename == "mldsa/src/common.h": + if m == "MLD_CONTEXT_PARAMETERS_n": + return True + + return False + + run_parallel( + list(files), partial(check_macro_typos_in_file, macro_check=macro_check) + ) + + +def check_asm_register_aliases_for_file(filename): + """Checks that `filename` has no mismatching or dangling register aliases""" + + def get_alias_def(l): + s = list(filter(lambda s: s != "", l.strip().split(" "))) + if len(s) < 3 or s[1] != ".req": + return None + return s[0] + + def get_alias_undef(l): + if l.strip().startswith(".unreq") is False: + return None + return list(filter(lambda s: s != "", l.strip().split(" ")))[1] + + content = read_file(filename) + aliases = {} + for i, l in enumerate(content.split("\n")): + alias_def = get_alias_def(l) + alias_undef = get_alias_undef(l) + if alias_def is not None: + if alias_def in aliases.keys(): + raise Exception( + f"Invalid assembly file {filename}: Duplicate .req directive for {alias_def} at line {i}" + ) + aliases[alias_def] = i + elif alias_undef is not None: + if alias_undef not in aliases.keys(): + raise Exception( + f"Invalid assembly file {filename}: .unreq without prior .req for {alias_undef} at line {i}" + ) + del aliases[alias_undef] + + if len(aliases) > 0: + fixup_suggestion = [ + "/****************** REGISTER DEALLOCATIONS *******************/" + ] + dangling = list(aliases.items()) + # Sort by line number of .req + dangling.sort(key=lambda s: s[1]) + + for a, _ in dangling: + fixup_suggestion.append(f" .unreq {a}") + fixup_suggestion.append("") + fixup_suggestion = "\n".join(fixup_suggestion) + + raise Exception( + f"Invalid assembly file {filename}: Dangling .req directives {aliases}.\n\nTry adding this?\n\n{fixup_suggestion}" + ) + + +def check_asm_register_aliases(): + run_parallel(get_asm_source_files(), check_asm_register_aliases_for_file) + + +def check_asm_loop_labels_for_file(filename): + """Checks that all labels in `filename` are prefixed according to the function defined in the file""" + + content = read_file(filename) + + # Find function symbol name + func_pattern = r"MLD_ASM_FN_SYMBOL\((.*)\)" + res = _RE_FUNC_SYMBOL.search(content) + if res is None: + raise Exception(f"Could not find function symbol in assembly file {filename}") + funcname = res.group(1) + lbl_prefix = funcname.replace("_asm", "") + "_" + lbl_pattern = r"^(\w+):" + for m in re.finditer(lbl_pattern, content, flags=re.M): + lbl = m.group(1) + if not lbl.startswith(lbl_prefix): + raise Exception( + f"Please change label {lbl} in {filename} to be prefixed by {lbl_prefix}" + ) + + +def check_asm_loop_labels(): + # Operate on assembly files in dev/ only. The ones in mlkem/ are autogenerated + # from that and don't have the original MLK_ASM_FN_SYMBOL marker anymore. + files = list(filter(lambda s: s.startswith("dev/"), get_asm_source_files())) + run_parallel(files, check_asm_loop_labels_for_file) + + +def normalize_comma_separated_args(args_str): + """Convert whitespace-separated args to comma-separated, add spaces after commas""" + # Extract and preserve comment + match = _RE_ARGS_COMMENT.match(args_str) + args_only = match.group(1).rstrip() + comment = match.group(2) or "" + + # If already has commas, just normalize spacing + if "," in args_only: + result = re.sub(r",(?! )", ", ", args_only) + else: + # Split on whitespace and join with commas + args = args_only.split() + if not args: + return args_str + result = ", ".join(args) + + return result + comment + + +def normalize_asm_macro_syntax_for_file(filename): + """Normalize macro definitions and invocations to use commas with spaces""" + + content = read_file(filename) + lines = content.split("\n") + + # First pass: collect macro names + macro_names = set() + for line in lines: + macro_match = _RE_MACRO_DEF.match(line) + if macro_match: + macro_names.add(macro_match.group(1)) + + # Second pass: normalize syntax + new_lines = [] + for line in lines: + # Normalize .macro definitions + macro_def_match = _RE_MACRO_DEF_ARGS.match(line) + if macro_def_match: + prefix = macro_def_match.group(1) + args_with_space = macro_def_match.group(2) + # Preserve leading whitespace, normalize the rest + leading_space = _RE_LEADING_SPACE.match(args_with_space).group(1) + args = args_with_space.lstrip() + normalized_args = normalize_comma_separated_args(args) + line = prefix + leading_space + normalized_args + else: + # Normalize macro invocations + for macro_name in macro_names: + # Match: whitespace + macro_name + whitespace + args + pattern = r"^(\s*" + re.escape(macro_name) + r")(\s+.*)$" + invocation_match = re.match(pattern, line) + if not invocation_match: + continue + prefix = invocation_match.group(1) + args_with_space = invocation_match.group(2) + # Preserve leading whitespace, normalize the rest + leading_space = _RE_LEADING_SPACE.match(args_with_space).group(1) + args = args_with_space.lstrip() + normalized_args = normalize_comma_separated_args(args) + line = prefix + leading_space + normalized_args + break + + new_lines.append(line) + + update_file(filename, "\n".join(new_lines)) + + +def normalize_asm_macro_syntax(): + """Normalize macro syntax in all assembly files""" + # Operate on assembly files in dev/ only. The ones in mldsa/ are autogenerated. + files = list(filter(lambda s: s.startswith("dev/"), get_asm_source_files())) + files += list(filter(lambda s: s.endswith(".inc"), get_files("dev/**/*.inc"))) + run_parallel(files, normalize_asm_macro_syntax_for_file) + + +def update_via_simpasm( + infile_full, + outdir, + outfile=None, + cflags=None, + preserve_header=True, + force_cross=False, + x86_64_syntax="att", +): + + _, infile = os.path.split(infile_full) + if outfile is None: + outfile = infile + outfile_full = os.path.join(outdir, outfile) + + if cflags is None: + cflags = "" + cflags += " -Imldsa" + + # Check if we need to use a cross-compiler + if "aarch64" in infile_full: + source_arch = "aarch64" + elif "x86_64" in infile_full: + source_arch = "x86_64" + else: + raise Exception(f"Could not detect architecture of source file {infile_full}.") + # Check native architecture + if platform.machine().lower() in ["arm64", "aarch64"]: + native_arch = "aarch64" + else: + native_arch = "x86_64" + + if native_arch != source_arch: + cross_prefix = f"{source_arch}-unknown-linux-gnu-" + cross_gcc = cross_prefix + "gcc" + # Check if cross-compiler is present + if shutil.which(cross_gcc) is None: + if force_cross is False: + return + raise Exception(f"Could not find cross toolchain {cross_prefix}") + else: + cross_prefix = None + + with tempfile.NamedTemporaryFile(suffix=".S") as tmp: + try: + # Determine architecture from filename + arch = "aarch64" if "aarch64" in infile_full else "x86_64" + + cmd = [ + "./scripts/simpasm", + "--objdump=llvm-objdump", + "--cfify", + "--arch=" + arch, + "-i", + infile_full, + "-o", + tmp.name, + ] + if cross_prefix is not None: + # Stick with llvm-objdump for disassembly + cmd += ["--cc", cross_prefix + "gcc"] + cmd += ["--nm", cross_prefix + "nm"] + if cflags is not None: + cmd += [f'--cflags="{cflags}"'] + if preserve_header is True: + cmd += ["-p"] + # Add syntax option for x86_64 + if arch == "x86_64" and x86_64_syntax != "att": + cmd += ["--syntax", x86_64_syntax] + r = subprocess.run( + cmd, + stdout=subprocess.DEVNULL, + stderr=subprocess.PIPE, + check=True, + text=True, + ) + except subprocess.CalledProcessError as e: + print(f"Command failed: {' '.join(cmd)}") + print(f"Exit code: {e.returncode}") + print(f"stderr: {e.stderr}") + raise Exception("Failed to run simpasm") from e + tmp.seek(0) + new_contents = tmp.read().decode() + + update_file(outfile_full, new_contents) + + +def gen_hol_light_asm_file(job): + infile, outfile, indir, cflags, arch = job + update_via_simpasm( + f"{indir}/{infile}", + "proofs/hol_light/" + arch + "/mldsa", + outfile=outfile, + cflags=cflags, + preserve_header=False, + ) + + +def gen_hol_light_asm(): + x86_64_flags = "-mavx2 -mbmi2 -msse4 -fcf-protection=full" + joblist_x86_64 = [ + ( + "ntt.S", + "mldsa_ntt.S", + "dev/x86_64/src", + f"-Imldsa/src/native/x86_64/src -Imldsa/src/common.h {x86_64_flags}", + "x86_64", + ), + ] + + run_parallel(joblist_x86_64, gen_hol_light_asm_file) + + +def update_via_copy(infile_full, outfile_full, transform=None): + + content = read_file(infile_full) + + if transform is not None: + content = transform(content) + + update_file(outfile_full, content) + + +def update_via_remove(filename): + update_file(filename, None) + + +def synchronize_file(f, in_dir, out_dir, delete=False, no_simplify=False, **kwargs): + + # Only synchronize sources, but not README.md, Makefile and so on + extensions = (".c", ".h", ".i", ".inc", ".S") + + if not f.endswith(extensions): + return None + + basename = os.path.basename(f) + + if delete is True: + return basename + + if no_simplify is False and f.endswith(".S"): + update_via_simpasm(f, out_dir, **kwargs) + else: + # Update via copy + _, infile = os.path.split(f) + outfile_full = os.path.join(out_dir, infile) + # The header guards will also be checked later, but if we + # don't do it here, the dry-run would fail because of a + # mismatching intermediate file + if f.endswith(".h"): + transform = lambda c: adjust_header_guard_for_filename(c, outfile_full) + else: + transform = None + update_via_copy(f, outfile_full, transform=transform) + + return basename + + +def synchronize_backend(in_dir, out_dir, delete=False, no_simplify=False, **kwargs): + copied = [] + + files = get_files(os.path.join(in_dir, "*")) + pool_results = run_parallel( + files, + partial( + synchronize_file, + in_dir=in_dir, + out_dir=out_dir, + delete=delete, + no_simplify=no_simplify, + **kwargs, + ), + ) + + copied = [r for r in pool_results if r is not None] + + if delete is False: + return + + # Check for files in the target directory that have not been copied + for f in get_files(os.path.join(out_dir, "*")): + if os.path.basename(f) in copied: + continue + # Otherwise, remove it + update_via_remove(f) + + +def synchronize_backends( + *, + force_cross=False, + clean=False, + delete=False, + no_simplify=False, + x86_64_syntax="att", +): + if clean is False: + ty = "opt" + else: + ty = "clean" + + if delete is False: + # We may switch the AArch64 arithmetic backend, so adjust the metadata file + update_via_copy( + f"dev/aarch64_{ty}/meta.h", + "mldsa/src/native/aarch64/meta.h", + transform=lambda c: adjust_header_guard_for_filename( + c, "mldsa/src/native/aarch64/meta.h" + ), + ) + + update_via_copy( + f"dev/x86_64/meta.h", + "mldsa/src/native/x86_64/meta.h", + transform=lambda c: adjust_header_guard_for_filename( + c, "mldsa/src/native/x86_64/meta.h" + ), + ) + + synchronize_backend( + f"dev/aarch64_{ty}/src", + "mldsa/src/native/aarch64/src", + delete=delete, + force_cross=force_cross, + no_simplify=no_simplify, + cflags="-Imldsa/src/native/aarch64/src", + ) + synchronize_backend( + "dev/fips202/aarch64/src", + "mldsa/src/fips202/native/aarch64/src", + delete=delete, + force_cross=force_cross, + no_simplify=no_simplify, + cflags="-Imldsa/src/fips202/native/aarch64/src -march=armv8.4-a+sha3", + ) + synchronize_backend( + "dev/fips202/aarch64", + "mldsa/src/fips202/native/aarch64", + delete=delete, + force_cross=force_cross, + no_simplify=no_simplify, + cflags="-Imldsa/src/fips202/native/aarch64 -march=armv8.4-a+sha3", + ) + synchronize_backend( + "dev/x86_64/src", + "mldsa/src/native/x86_64/src", + delete=delete, + force_cross=force_cross, + no_simplify=no_simplify, + x86_64_syntax=x86_64_syntax, + # Turn off control-flow protection (CET) explicitly. Newer versions of + # clang turn it on by default and insert endbr64 instructions at every + # global symbol. + # We insert endbr64 instruction manually via the MLD_ASM_FN_SYMBOL + # macro. + # This leads to duplicate endbr64 instructions causing a failure when + # comparing the object code before and after simplification. + cflags="-Imldsa/src/native/x86_64/src/ -mavx2 -mbmi2 -msse4 -fcf-protection=none", + ) + + +def adjust_header_guard_for_filename(content, header_file): + + content = content.split("\n") + exceptions = { + "mldsa/mldsa_native.h": "MLD_H", + "mldsa/mldsa_native_config.h": "MLD_CONFIG_H", + } + + # Use full filename as the header guard, with '/' and '.' replaced by '_' + guard_name = ( + header_file.removeprefix("mldsa/src/") + .replace("/", "_") + .replace(".", "_") + .upper() + ) + guard_name = "MLD_" + guard_name + + if header_file in exceptions.keys(): + guard_name = exceptions[header_file] + + def gen_guard(): + yield f"#ifndef {guard_name}" + yield f"#define {guard_name}" + + def gen_footer(): + yield f"#endif" + yield "" + + guard = list(gen_guard()) + footer = list(gen_footer()) + + # Skip over initial commentary + insert_at = None + for i, l in enumerate(content): + if l.strip() == "" or l.startswith(("/*", " *")): + continue + insert_at = i + break + + i = insert_at + while content[i].strip() == "": + i += 1 + # Check if header file has some guard -- if so, drop it + if content[i].strip().startswith("#if !defined") or content[i].strip().startswith( + "#ifndef" + ): + del content[i] + if content[i].strip().startswith("#define"): + del content[i] + has_guard = True + else: + has_guard = False + # Add standardized guard + content = content[:i] + guard + content[i:] + # Check if header has some footer + if ( + has_guard is True + and content[-1] == "" + and content[-2].strip().startswith("#endif") + ): + del content[-2:] + # Add standardized footer + content = content + footer + + return "\n".join(content) + + +def gen_header_guard(header_file): + content = read_file(header_file) + new_content = adjust_header_guard_for_filename(content, header_file) + update_file(header_file, new_content) + + +def gen_header_guards(): + run_parallel(get_header_files(main_only=True), gen_header_guard) + + +def gen_source_undefs(source_file): + + # Get list of #define's clauses in this source file (ignore filename) + undef_list = list(map(lambda c: c[1], get_defines_from_file(source_file))) + if not undef_list: + return + + # Get define clauses from header files, as dict + header_defs = {d: c for (c, d) in get_defines()} + + undefs = [] + ignored = [] + for d in undef_list: + if d not in header_defs.keys(): + undefs.append(f"#undef {d}") + else: + ignored.append((d, header_defs[d])) + + if len(ignored) != 0: + undefs.append( + "/* Some macros are kept because they are also defined in a header. */" + ) + for d, c in ignored: + undefs.append(f"/* Keep: {d} ({c.split('/')[-1]}) */") + + content = read_file(source_file).split("\n") + + # Find simpasm footer if present (search from end) + footer_start = None + if source_file.endswith(".S"): + footer_start_marker = "simpasm: footer-start" + for i in range(len(content) - 1, -1, -1): + if footer_start_marker in content[i]: + footer_start = i + break + + if footer_start is not None: + simpasm_footer = content[footer_start:] + content = content[:footer_start] + else: + simpasm_footer = [] + + # Strip trailing undefs and empty lines + while content and ( + content[-1].startswith("#undef") + or content[-1].startswith("/* Keep:") + or content[-1].startswith("/* Some macros") + or content[-1] == "" + ): + content.pop() + + footer = [ + "", + "/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.", + " * Don't modify by hand -- this is auto-generated by scripts/autogen. */", + ] + + # Remove existing footer if present + if len(content) >= len(footer) and content[-len(footer) :] == footer: + content = content[: -len(footer)] + + content.extend(footer) + content.extend(undefs) + content.append("") + + new_content = "\n".join(content + simpasm_footer) + update_file(source_file, new_content) + + +def gen_undefs(): + files = get_c_source_files(core_only=True) + get_asm_source_files(core_only=True) + run_parallel(files, gen_source_undefs) + + +def gen_slothy(funcs): + if not isinstance(funcs, list): + return + + targets = list(map(lambda s: s + ".S", funcs)) + + for t in targets: + + if t.startswith("keccak"): + base = "dev/fips202/aarch64/src" + else: + base = "dev/aarch64_opt/src" + + # Remove file(s) to be re-generated + if t.endswith(".S"): + subprocess.run(["rm", "-f", f"{base}/{t}"]) + + p = subprocess.run(["make", t] + ["-C", base]) + if p.returncode != 0: + print(f"Failed to run SLOTHY on {t}!") + exit(1) + + +class BibliographyEntry: + def __init__(self, raw_dict): + self._raw = raw_dict + self._usages = [] + + def register_usages(self, lst): + self._usages += lst + + @property + def usages(self): + return self._usages + + @property + def name(self): + return self._raw["name"] + + @property + def short(self): + if "short" in self._raw.keys(): + return self._raw["short"] + return self.name + + @property + def id(self): + return self._raw["id"] + + @property + def url(self): + return self._raw["url"] + + @staticmethod + def full_name(name): + if "," not in name: + return name + surname, forename = name.split(",") + return forename.strip() + " " + surname.strip() + + @property + def authors(self): + authors = self._raw["author"] + if not isinstance(authors, list): + authors = [authors] + authors = list(map(BibliographyEntry.full_name, authors)) + return authors + + @property + def authors_text(self): + authors = self._raw["author"] + if not isinstance(authors, list): + authors = [authors] + + def surname(name): + return name.split(",")[0].strip() + + if len(authors) > 1: + authors = ", ".join(map(surname, authors)) + else: + authors = BibliographyEntry.full_name(authors[0]) + return authors + + +def gen_markdown_citations_for(filename, bibliography): + + # Skip BIBLIOGRAPHY.md + if filename == "BIBLIOGRAPHY.md": + return + + content = read_file(filename) + if not _RE_MARKDOWN_CITE.search(content): + return + + content = content.split("\n") + + # Lookup all citations in style `[^ID]` + citations = {} + for i, l in enumerate(content): + for m in _RE_MARKDOWN_CITE.finditer(l): + cite_id = m.group("id") + uses = citations.get(cite_id, []) + uses.append((filename, i)) + citations[cite_id] = uses + + # Find and remove any existing citation footnotes + footnote_footer_start = "" + try: + i = content.index(footnote_footer_start) + content = content[:i] + except ValueError: + pass + + # Add footnotes for all citations found + if len(citations) > 0: + content.append(footnote_footer_start) + cite_ids = list(citations.keys()) + cite_ids.sort() + for cite_id in cite_ids: + uses = citations[cite_id] + entry = bibliography.get(cite_id, None) + if entry is None: + raise Exception( + f"Could not find bibliography entry {cite_id} referenced in {filename}. Known entries: {list(bibliography.keys())}" + ) + content.append( + f"[^{cite_id}]: {entry.authors_text}: {entry.name}, [{entry.url}]({entry.url})" + ) + + # Remember this usage of the bibliography entry + entry.register_usages(uses) + + if len(citations) > 0: + content.append("") + + update_file(filename, "\n".join(content)) + + +def gen_c_citations_for(filename, bibliography): + + content = read_file(filename) + + if not _RE_C_CITE.search(content): + return + + references_start = [ + "/* References", + " * ==========", + ] + references_end = [" */"] + + # Find and remove any existing reference section + ref_pattern = r"/\* (# )?References.*?\*/\n+" + content = re.sub(ref_pattern, "", content, flags=re.DOTALL) + + content = content.split("\n") + + # Lookup all citations in style `@[ID]` + citations = {} + for i, l in enumerate(content): + for m in _RE_C_CITE.finditer(l): + cite_id = m.group("id") + uses = citations.get(cite_id, []) + # Remember usage. +1 because line counting starts at 1 + uses.append((filename, i + 1)) + citations[cite_id] = uses + + # Add references section + references = [] + references += references_start + + cite_ids = list(citations.keys()) + cite_ids.sort() + for cite_id in cite_ids: + uses = citations[cite_id] + entry = bibliography.get(cite_id, None) + if entry is None: + raise Exception( + f"Could not find bibliography entry {cite_id} referenced in {filename}" + ) + references.append(f" *") + references.append(f" * - [{cite_id}]") + prefix = " * " + # Wrap long lines at 80 chars + for line in [entry.name, entry.authors_text, entry.url]: + if len(line) + len(prefix) <= 80: + references.append(f"{prefix}{line}") + else: + words = line.split() + current = prefix + for word in words: + if len(current) + len(word) <= 80 or current == prefix: + current += word + " " + else: + references.append(current.rstrip()) + current = prefix + word + " " + if current.rstrip() != prefix.rstrip(): + references.append(current.rstrip()) + + references += references_end + + # Fix indentation for comment lines + references = "\n".join(references) + references = references.split("\n") + references = [""] + references + + if len(cite_ids) > 0: + # Add references to file after initial header section + # Skip over copyright + insert_at = None + for i, l in enumerate(content): + if l.startswith(("/*", " *")): + continue + insert_at = i + break + content = content[:insert_at] + references + content[insert_at:] + + # Remember uses -- needs to happen after insertion of references + # since we need to adjust the line count + for cite_id in cite_ids: + uses = citations[cite_id] + entry = bibliography.get(cite_id, None) + + # Adjust line count after insertion of references + def bump_line_count(x): + return (x[0], x[1] + len(references)) + + uses = list(map(bump_line_count, uses)) + + # Remember this usage of the bibliography entry + entry.register_usages(uses) + + update_file(filename, "\n".join(content)) + + +def gen_citations_for(filename, bibliography): + if filename.endswith(".md"): + gen_markdown_citations_for(filename, bibliography) + elif filename.endswith((".c", ".h", ".S")): + gen_c_citations_for(filename, bibliography) + else: + raise Exception(f"Unexpected file extension in {filename}") + + +def gen_bib_file(bibliography): + + content = [ + "[//]: # (SPDX-License-Identifier: CC-BY-4.0)", + "[//]: # (This file is auto-generated from BIBLIOGRAPHY.yml)", + "[//]: # (Do not modify it directly)", + "", + "# Bibliography", + "", + "This file lists the citations made throughout the mldsa-native ", + "source code and documentation.", + "", + ] + + cite_ids = list(bibliography.keys()) + cite_ids.sort() + + for cite_id in cite_ids: + entry = bibliography[cite_id] + content.append(f"### `{cite_id}`") + content.append("") + content.append(f"* {entry.name}") + content.append(f"* Author(s):") + for author in entry.authors: + content.append(f" - {author}") + content.append(f"* URL: {entry.url}") + content.append(f"* Referenced from:") + # Usages are pairs of (filename, line_count) + # Ignore line_count for now, as it would require `autogen` after + # a change to source files. + files = list(set(map(lambda x: x[0], entry.usages))) + files.sort() + for filename in files: + content.append(f" - [{filename}]({filename})") + content.append("") + + update_file("BIBLIOGRAPHY.md", "\n".join(content)) + + +def get_oqs_shared_sources(backend): + """Get shared source files for OQS integration""" + mldsa_dir = "mldsa/src/" + + # add files mldsa/* + sources = [ + f"mldsa/src/{f}" + for f in os.listdir(mldsa_dir) + if os.path.isfile(f"{mldsa_dir}/{f}") + and not f.endswith(".o") + and not f == "mldsa_native.h" + ] + + if backend != "ref": + # add files mldsa/native/* (API definitions) + sources += [ + f"mldsa/src/native/{f}" + for f in os.listdir(f"{mldsa_dir}/native") + if os.path.isfile(f"{mldsa_dir}/native/{f}") + ] + # Add FIPS202 glue code + sources += [ + "integration/liboqs/fips202_glue.h", + "integration/liboqs/fips202x4_glue.h", + ] + # Add custom config + if backend == "ref": + backend = "c" + sources.append(f"integration/liboqs/config_{backend.lower()}.h") + + return sources + + +def get_oqs_native_sources(backend): + """Get native source files for OQS integration""" + return [f"mldsa/src/native/{backend}"] + + +def gen_oqs_meta_file(filename): + """Generate OQS META.yml file with updated source lists""" + + content = read_file(filename) + + # Parse YAML while preserving structure + yml_data = yaml.safe_load(content) + + for impl in yml_data["implementations"]: + name = impl["name"] + + sources = get_oqs_shared_sources(name) + + # NOTE: Sorting at the end causes the libOQS importer to fail. + # Somehow, the native directory cannot be imported too early. + sources.sort() + + if name != "ref": + sources += get_oqs_native_sources(name) + impl["sources"] = " ".join(sources) + + # Convert back to YAML string with standard copyright header + yaml_header = "\n".join(gen_yaml_header()) + + new_content = yaml.dump( + yml_data, + default_flow_style=False, + sort_keys=False, + allow_unicode=True, + encoding=None, + ) + + # Combine copyright header with new YAML content + new_content = yaml_header + new_content + + update_file(filename, new_content) + + +def gen_oqs_meta_files(): + """Generate all OQS META.yml files""" + meta_files = [ + "integration/liboqs/ML-DSA-44_META.yml", + "integration/liboqs/ML-DSA-65_META.yml", + "integration/liboqs/ML-DSA-87_META.yml", + ] + + for meta_file in meta_files: + gen_oqs_meta_file(meta_file) + + +def gen_citations(): + # Load bibliography + with open("BIBLIOGRAPHY.yml", "r") as f: + bibliography_raw = yaml.safe_load(f.read()) + + bibliography = {} + for r in bibliography_raw: + cite_id = r["id"] + bibliography[cite_id] = BibliographyEntry(r) + + files = ( + get_markdown_files() + + get_asm_source_files() + + get_c_source_files() + + get_header_files() + ) + run_parallel(files, partial(gen_citations_for, bibliography=bibliography)) + + # Check that every bibliography entry has been used as least once + for e in bibliography.values(): + if len(e.usages) == 0: + raise Exception( + f"Bibliography entry {e.id} is unused! " + "Add a citation or remove from BIBLIOGRAPHY.yml." + ) + + gen_bib_file(bibliography) + + +def extract_bytecode_from_output(output_text): + """Convert output of proofs/hol_light/x86_64/proofs/dump_bytecode.native + into a dictionary mapping function names to byte code strings.""" + bytecode_dict = {} + + lines = output_text.split("\n") + i = 0 + + while i < len(lines): + line = lines[i] + match = _RE_BYTECODE_START.search(line) + if match: + filename = match.group(1) + + # Collect bytecode until end marker + bytecode_lines = [] + i += 1 + while i < len(lines) and "==== bytecode end" not in lines[i]: + bytecode_lines.append(lines[i]) + i += 1 + + bytecode = "\n".join(bytecode_lines).strip() + bytecode_dict[filename] = bytecode + i += 1 + + return bytecode_dict + + +def update_bytecode_in_proof_script(filepath, bytecode): + content = read_file(filepath) + + # Check if markers exist + start_marker = "(*** BYTECODE START ***)" + end_marker = "(*** BYTECODE END ***)" + + if start_marker not in content or end_marker not in content: + raise Exception(f"Could not find BYTECODE START/END markers in {filepath}") + + # Replace content between markers + pattern = rf"{re.escape(start_marker)}.*?{re.escape(end_marker)}" + replacement = f"{start_marker}\n{bytecode}\n{end_marker}" + + updated_content = re.sub(pattern, replacement, content, flags=re.DOTALL) + + update_file(filepath, updated_content) + + +def update_hol_light_bytecode_for_arch(arch, force_cross=False): + source_arch = arch + if platform.machine().lower() in ["arm64", "aarch64"]: + native_arch = "aarch64" + else: + native_arch = "x86_64" + + if native_arch != source_arch: + cross_prefix = f"{source_arch}-unknown-linux-gnu-" + cross_gcc = cross_prefix + "gcc" + # Check if cross-compiler is present + if shutil.which(cross_gcc) is None: + if force_cross is False: + return + raise Exception(f"Could not find cross toolchain {cross_prefix}") + + # Run make to get bytecode output + result = subprocess.run( + ["make", "-C", "proofs/hol_light/" + arch, "dump_bytecode"], + capture_output=True, + text=True, + check=True, + ) + output_text = result.stdout + + # Extract bytecode + bytecode_dict = extract_bytecode_from_output(output_text) + + # Update each .ml file + for obj_name, bytecode in bytecode_dict.items(): + ml_file = "proofs/hol_light/" + arch + "/proofs/" + obj_name + ".ml" + update_bytecode_in_proof_script(ml_file, bytecode) + + +def update_hol_light_bytecode(force_cross=False): + """Update HOL Light proof files with bytecode from make dump_bytecode.""" + # NOTE: The following line is commented out until there are hol_light aarch64 proofs. + # update_hol_light_bytecode_for_arch("aarch64", force_cross=force_cross) + update_hol_light_bytecode_for_arch("x86_64", force_cross=force_cross) + + +def gen_test_config(config_path, config_spec, default_config_content): + """Generate a config file by modifying the default config.""" + + # Start with the default config + lines = default_config_content.split("\n") + + # Find copyright and reference header + references_start = None + references_end = None + + # NOTE: This needs further work if any custom config contains citations + # not included in the default configuration. In this case, the reference + # section needs to be updated. + + for i, line in enumerate(lines): + if "/* References" in line: + references_start = i + elif ( + references_start is not None + and references_end is None + and line.strip() == "*/" + ): + references_end = i + 1 + break + + header = lines[:references_end] + header += list(gen_autogen_warning()) + + header.append("") + header.append("/*") + header.append(f" * Test configuration: {config_spec['description']}") + header.append(" *") + header.append( + " * This configuration differs from the default mldsa/mldsa_native_config.h in the following places:" + ) + + def spec_has_value(opt_value): + if not isinstance(opt_value, dict): + return True + else: + return "value" in opt_value.keys() or "content" in opt_value.keys() + + for opt_name, opt_value in config_spec["defines"].items(): + if not spec_has_value(opt_value): + continue + header.append(f" * - {opt_name}") + header.append(" */") + header.append("") + + # Combine: new header + config body + lines = header + lines[references_end:] + + def locate_config_option(lines, opt_name): + """Locate configuration option in lines. Returns (start, end) line indices""" + i = 0 + while i < len(lines): + if re.search(rf"\* Name:\s+{re.escape(opt_name)}\b", lines[i]): + # Skip to the end of this comment block (find the closing */) + while i < len(lines) and not lines[i].strip().endswith("*/"): + i += 1 + i += 1 # Skip the closing */ + + start = i + # Find the next config option (starts with /*****) + while i < len(lines): + if lines[i].strip().startswith("/****"): + # Back up to exclude empty line before next option + while i > start and lines[i - 1].strip() == "": + i -= 1 + return (start, i) + i += 1 + # If no next option found, go to end + return (start, len(lines)) + i += 1 + raise Exception(f"Could not find config option {opt_name} in default config") + + def replace_config_option(lines, opt_name, opt_value): + """Replace config option with new value""" + block_start, block_end = locate_config_option(lines, opt_name) + + def content_from_value(value): + if value is True: + return [f"#define {opt_name}"] + elif value is False: + return [f"/* #define {opt_name} */"] + else: + return [f"#define {opt_name} {str(value)}"] + + if isinstance(opt_value, dict): + if "content" in opt_value: + content = opt_value.get("content").split("\n") + elif "value" in opt_value: + content = content_from_value(opt_value["value"]) + else: + # Use original content + content = lines[block_start:block_end] + if "comment" in opt_value: + comment = opt_value.get("comment").split("\n") + else: + comment = [] + else: + content = content_from_value(opt_value) + comment = [] + + lines[block_start:block_end] = comment + content + + # Apply modifications for each defined option + for opt_name, opt_value in config_spec["defines"].items(): + replace_config_option(lines, opt_name, opt_value) + + content = "\n".join(lines) + update_file(config_path, content) + + +def gen_test_configs(): + """Generate all test configuration files from metadata.""" + # Load metadata + metadata = yaml.safe_load(read_file("test/configs/configs.yml")) + + # Load default config + default_config = read_file("mldsa/mldsa_native_config.h") + + # Generate each test config + for config_spec in metadata["configs"]: + gen_test_config(config_spec["path"], config_spec, default_config) + + +def _main(): + slothy_choices = [ + "ntt", + "intt", + "mld_polyvecl_pointwise_acc_montgomery_l4", + "mld_polyvecl_pointwise_acc_montgomery_l5", + "mld_polyvecl_pointwise_acc_montgomery_l7", + "pointwise_montgomery", + "poly_caddq_asm", + "poly_chknorm_asm", + "poly_decompose_32_asm", + "poly_decompose_88_asm", + "poly_use_hint_32_asm", + "poly_use_hint_88_asm", + "polyz_unpack_17_asm", + "polyz_unpack_19_asm", + "rej_uniform_asm", + "rej_uniform_eta2_asm", + "rej_uniform_eta4_asm", + ] + + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter + ) + parser.add_argument("--dry-run", default=False, action="store_true") + parser.add_argument( + "--update-hol-light-bytecode", default=False, action="store_true" + ) + parser.add_argument("--slothy", nargs="*", default=None, choices=slothy_choices) + parser.add_argument("--aarch64-clean", default=False, action="store_true") + parser.add_argument("--no-simplify", default=False, action="store_true") + parser.add_argument("--force-cross", default=False, action="store_true") + parser.add_argument( + "--x86-64-syntax", + type=str, + choices=["att", "intel"], + default="att", + help="Assembly syntax for x86_64 disassembly output (att or intel)", + ) + + args = parser.parse_args() + + os.chdir(os.path.join(os.path.dirname(__file__), "..")) + + if args.slothy == []: + args.slothy = slothy_choices + + def sync_backends(): + synchronize_backends( + clean=args.aarch64_clean, + no_simplify=args.no_simplify, + force_cross=args.force_cross, + x86_64_syntax=args.x86_64_syntax, + ) + + def sync_backends_final(): + synchronize_backends( + clean=args.aarch64_clean, + delete=True, + force_cross=args.force_cross, + no_simplify=args.no_simplify, + x86_64_syntax=args.x86_64_syntax, + ) + + def gen_zeta_tables(): + gen_c_zeta_file() + gen_aarch64_zeta_file() + gen_aarch64_rej_uniform_table() + gen_aarch64_rej_uniform_eta_table() + gen_avx2_hol_light_zeta_file() + gen_avx2_zeta_file() + gen_avx2_rej_uniform_table() + + def gen_monolithic(): + gen_monolithic_source_file() + gen_monolithic_asm_file() + + hol_light_asm_supported = platform.machine().lower() in ["x86_64"] + + # Build step list: (description, function, enabled) + # If enabled is False, step is skipped + steps = [ + ("Generate citations", gen_citations), + ("Generate OQS META.yml files", gen_oqs_meta_files), + ("Normalize assembly macro syntax", normalize_asm_macro_syntax), + ( + "Generate SLOTHY optimized assembly", + lambda: gen_slothy(args.slothy), + args.slothy is not None and not args.dry_run, + ), + ("Check assembly register aliases", check_asm_register_aliases), + ("Check assembly loop labels", check_asm_loop_labels), + ("Generate zeta and lookup tables", gen_zeta_tables), + ("Generate HOL Light assembly", gen_hol_light_asm, hol_light_asm_supported), + ("Synchronize backends", sync_backends), + ("Generate header guards", gen_header_guards), + ("Complete final backend synchronization", sync_backends_final), + ( + "Update HOL Light bytecode", + partial(update_hol_light_bytecode, force_cross=args.force_cross), + args.update_hol_light_bytecode, + ), + ("Generate monolithic source files", gen_monolithic), + ("Generate undefs", gen_undefs), + ("Generate test configs", gen_test_configs), + ("Check macro typos", check_macro_typos), + ("Generate preprocessor comments", gen_preprocessor_comments), + # Formatting should be the last step + ("Format files", lambda: format_files(args.dry_run)), + ] + + global _progress, _main_task + with Progress( + BarColumn(), + TaskProgressColumn(), + TimeElapsedColumn(), + TextColumn("{task.description}"), + console=console, + ) as progress: + _progress = progress + _main_task = progress.add_task("autogen", total=len(steps) + 1) + + for step in steps: + desc, func = step[0], step[1] + enabled = step[2] if len(step) > 2 else True + high_level_task(desc) + if enabled: + func() + high_level_status(desc, skipped=not enabled) + + high_level_task("Write files") + finalize(args.dry_run) + txt = ( + "Finalize and check files are up to date" + if args.dry_run + else "Finalize and write files" + ) + high_level_status(txt) + + _progress.update(_main_task, description="[green] Done ✓[/]") + _progress = None + + return print_check_errors() + + +if __name__ == "__main__": + sys.exit(0 if _main() else 1) diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/cfify b/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/cfify new file mode 100755 index 0000000000..ef9fec2b88 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/cfify @@ -0,0 +1,279 @@ +#!/usr/bin/env python3 +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +import sys +import re +import argparse + + +def add_cfi_directives(text, arch): + lines = text.split("\n") + result = [] + i = 0 + + while i < len(lines): + line = lines[i].rstrip() + + if arch == "aarch64": + # Check for SIMD save pattern: stp d8,d9; stp d10,d11; stp d12,d13; stp d14,d15 + if i + 3 < len(lines): + pattern_text = "\n".join(lines[i : i + 4]) + simd_save_pattern = ( + r"(\s*)stp\s+d8,\s*d9,\s*\[sp(?:,\s*#([^]]+))?\]\s*\n" + r"\s*stp\s+d10,\s*d11,\s*\[sp(?:,\s*#([^]]+))?\]\s*\n" + r"\s*stp\s+d12,\s*d13,\s*\[sp(?:,\s*#([^]]+))?\]\s*\n" + r"\s*stp\s+d14,\s*d15,\s*\[sp(?:,\s*#([^]]+))?\]" + ) + match = re.match(simd_save_pattern, pattern_text, re.IGNORECASE) + if match: + indent = match.group(1) + offsets = [match.group(j + 2) or "0" for j in range(4)] + for j, reg_pair in enumerate( + [(8, 9), (10, 11), (12, 13), (14, 15)] + ): + result.append(lines[i + j].rstrip()) + try: + offset_val = int(offsets[j], 0) + result.append( + f"{indent}.cfi_rel_offset d{reg_pair[0]}, 0x{offset_val:x}" + ) + result.append( + f"{indent}.cfi_rel_offset d{reg_pair[1]}, 0x{offset_val+8:x}" + ) + except: + result.append( + f"{indent}.cfi_rel_offset d{reg_pair[0]}, {offsets[j]}" + ) + result.append( + f"{indent}.cfi_rel_offset d{reg_pair[1]}, ({offsets[j]}+8)" + ) + i += 4 + continue + + # Check for SIMD restore pattern: ldp d8,d9; ldp d10,d11; ldp d12,d13; ldp d14,d15 + if i + 3 < len(lines): + pattern_text = "\n".join(lines[i : i + 4]) + simd_restore_pattern = ( + r"(\s*)ldp\s+d8,\s*d9,\s*\[sp(?:,\s*#[^]]+)?\]\s*\n" + r"\s*ldp\s+d10,\s*d11,\s*\[sp(?:,\s*#[^]]+)?\]\s*\n" + r"\s*ldp\s+d12,\s*d13,\s*\[sp(?:,\s*#[^]]+)?\]\s*\n" + r"\s*ldp\s+d14,\s*d15,\s*\[sp(?:,\s*#[^]]+)?\]" + ) + match = re.match(simd_restore_pattern, pattern_text, re.IGNORECASE) + if match: + indent = match.group(1) + for j, reg_pair in enumerate( + [(8, 9), (10, 11), (12, 13), (14, 15)] + ): + result.append(lines[i + j].rstrip()) + result.append(f"{indent}.cfi_restore d{reg_pair[0]}") + result.append(f"{indent}.cfi_restore d{reg_pair[1]}") + i += 4 + continue + + # Check for GPR save pattern: stp x19,x20 through stp x29,x30 + if i + 5 < len(lines): + pattern_text = "\n".join(lines[i : i + 6]) + gpr_save_pattern = ( + r"(\s*)stp\s+x19,\s*x20,\s*\[sp(?:,\s*#([^]]+))?\]\s*\n" + r"\s*stp\s+x21,\s*x22,\s*\[sp(?:,\s*#([^]]+))?\]\s*\n" + r"\s*stp\s+x23,\s*x24,\s*\[sp(?:,\s*#([^]]+))?\]\s*\n" + r"\s*stp\s+x25,\s*x26,\s*\[sp(?:,\s*#([^]]+))?\]\s*\n" + r"\s*stp\s+x27,\s*x28,\s*\[sp(?:,\s*#([^]]+))?\]\s*\n" + r"\s*stp\s+x29,\s*x30,\s*\[sp(?:,\s*#([^]]+))?\]" + ) + match = re.match(gpr_save_pattern, pattern_text, re.IGNORECASE) + if match: + indent = match.group(1) + offsets = [match.group(j + 2) or "0" for j in range(6)] + for j, reg_pair in enumerate( + [(19, 20), (21, 22), (23, 24), (25, 26), (27, 28), (29, 30)] + ): + result.append(lines[i + j].rstrip()) + try: + offset_val = int(offsets[j], 0) + result.append( + f"{indent}.cfi_rel_offset x{reg_pair[0]}, 0x{offset_val:x}" + ) + result.append( + f"{indent}.cfi_rel_offset x{reg_pair[1]}, 0x{offset_val+8:x}" + ) + except: + result.append( + f"{indent}.cfi_rel_offset x{reg_pair[0]}, {offsets[j]}" + ) + result.append( + f"{indent}.cfi_rel_offset x{reg_pair[1]}, ({offsets[j]}+8)" + ) + i += 6 + continue + + # Check for GPR restore pattern: ldp x19,x20 through ldp x29,x30 + if i + 5 < len(lines): + pattern_text = "\n".join(lines[i : i + 6]) + gpr_restore_pattern = ( + r"(\s*)ldp\s+x19,\s*x20,\s*\[sp(?:,\s*#[^]]+)?\]\s*\n" + r"\s*ldp\s+x21,\s*x22,\s*\[sp(?:,\s*#[^]]+)?\]\s*\n" + r"\s*ldp\s+x23,\s*x24,\s*\[sp(?:,\s*#[^]]+)?\]\s*\n" + r"\s*ldp\s+x25,\s*x26,\s*\[sp(?:,\s*#[^]]+)?\]\s*\n" + r"\s*ldp\s+x27,\s*x28,\s*\[sp(?:,\s*#[^]]+)?\]\s*\n" + r"\s*ldp\s+x29,\s*x30,\s*\[sp(?:,\s*#[^]]+)?\]" + ) + match = re.match(gpr_restore_pattern, pattern_text, re.IGNORECASE) + if match: + indent = match.group(1) + for j, reg_pair in enumerate( + [(19, 20), (21, 22), (23, 24), (25, 26), (27, 28), (29, 30)] + ): + result.append(lines[i + j].rstrip()) + result.append(f"{indent}.cfi_restore x{reg_pair[0]}") + result.append(f"{indent}.cfi_restore x{reg_pair[1]}") + i += 6 + continue + + # Rule 7: add sp, sp, #offset -> .cfi_adjust_cfa_offset (-(offset)) + match = re.match( + r"(\s*)add\s+sp,\s*sp,\s*#(0x[0-9a-fA-F]+|\d+)", line, re.IGNORECASE + ) + if match: + indent, offset_str = match.groups() + offset = ( + int(offset_str, 16) + if offset_str.lower().startswith("0x") + else int(offset_str) + ) + result.append(line) + result.append(f"{indent}.cfi_adjust_cfa_offset -{offset:#x}") + i += 1 + continue + + # Rule 8: sub sp, sp, #offset -> .cfi_adjust_cfa_offset (offset) + match = re.match( + r"(\s*)sub\s+sp,\s*sp,\s*#(0x[0-9a-fA-F]+|\d+)", line, re.IGNORECASE + ) + if match: + indent, offset_str = match.groups() + offset = ( + int(offset_str, 16) + if offset_str.lower().startswith("0x") + else int(offset_str) + ) + result.append(line) + result.append(f"{indent}.cfi_adjust_cfa_offset {offset:#x}") + i += 1 + continue + + # Rule 2: ret -> .cfi_endproc after ret + match = re.match(r"(\s*)ret\s*$", line, re.IGNORECASE) + if match: + indent = match.group(1) + result.append(line) + result.append(f"{indent}.cfi_endproc") + i += 1 + continue + + elif arch == "x86_64": + # Check for labels and see if there's a corresponding callq + label_match = re.match(r"^([a-zA-Z_][a-zA-Z0-9_]*):$", line) + if label_match: + label = label_match.group(1) + # Check if this label is called anywhere in the text + if re.search(rf"\s*callq\s+{re.escape(label)}\b", text, re.IGNORECASE): + result.append(line) + result.append(" .cfi_startproc") + i += 1 + continue + + # x86_64: subq $OFFSET, %rsp -> .cfi_adjust_cfa_offset OFFSET (stack alloc) + match = re.match( + r"(\s*)subq\s+\$(0x[0-9a-fA-F]+|\d+),\s*%rsp", line, re.IGNORECASE + ) + if match: + indent, offset_str = match.groups() + offset = ( + int(offset_str, 16) + if offset_str.lower().startswith("0x") + else int(offset_str) + ) + result.append(line) + result.append(f"{indent}.cfi_adjust_cfa_offset {offset:#x}") + i += 1 + continue + + # x86_64: addq $OFFSET, %rsp -> .cfi_adjust_cfa_offset -OFFSET (stack free) + match = re.match( + r"(\s*)addq\s+\$(0x[0-9a-fA-F]+|\d+),\s*%rsp", line, re.IGNORECASE + ) + if match: + indent, offset_str = match.groups() + offset = ( + int(offset_str, 16) + if offset_str.lower().startswith("0x") + else int(offset_str) + ) + result.append(line) + result.append(f"{indent}.cfi_adjust_cfa_offset -{offset:#x}") + i += 1 + continue + + # x86_64: ret/retq -> .cfi_endproc after ret + match = re.match(r"(\s*)retq?\s*$", line, re.IGNORECASE) + if match: + indent = match.group(1) + result.append(line) + result.append(f"{indent}.cfi_endproc") + i += 1 + continue + + result.append(line) + i += 1 + + return "\n".join(result) + + +def main(): + + parser = argparse.ArgumentParser( + description="Add CFI directives to AArch64 assembly" + ) + parser.add_argument("-i", "--input", help="Input file (default: stdin)") + parser.add_argument("-o", "--output", help="Output file (default: stdout)") + parser.add_argument( + "--emit-cfi-proc-start", + action="store_true", + help="Emit .cfi_proc_start as first line", + ) + parser.add_argument( + "--arch", + choices=["aarch64", "x86_64"], + default="aarch64", + help="Target architecture (default: aarch64)", + ) + args = parser.parse_args() + + input_file = open(args.input, "r") if args.input else sys.stdin + output_file = open(args.output, "w") if args.output else sys.stdout + + try: + # Read all input + text = input_file.read() + + # Add initial .cfi_startproc if requested + if args.emit_cfi_proc_start: + text = " .cfi_startproc\n" + text + + # Process the text + result = add_cfi_directives(text, args.arch) + + # Write output + output_file.write(result) + finally: + if args.input: + input_file.close() + if args.output: + output_file.close() + + +if __name__ == "__main__": + main() diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/check-contracts b/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/check-contracts new file mode 100755 index 0000000000..2ad5a114ed --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/check-contracts @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# +# Looks for CBMC contracts without proof +# + +import re +import sys +import subprocess +import pathlib + +def get_c_source_files(): + return get_files("mldsa/**/*.c") + +def get_header_files(): + return get_files("mldsa/**/*.h") + +def get_files(pattern): + return list(map(str, pathlib.Path().glob(pattern))) + +def gen_proofs(): + cmd_str = ["./proofs/cbmc/list_proofs.sh"] + p = subprocess.run(cmd_str, capture_output=True, universal_newlines=False) + proofs = filter(lambda s: s.strip() != "", p.stdout.decode().split("\n")) + return proofs + +def gen_contracts(): + files = get_c_source_files() + get_header_files() + + for filename in files: + with open(filename, "r") as f: + content = f.read() + + contract_pattern = r'(\w+)\s*\([^)]*\)\s*\n?\s*__contract__' + matches = re.finditer(contract_pattern, content) + for m in matches: + line = content.count('\n', 0, m.start()) + yield (filename, line, m.group(1).removeprefix("mld_")) + +def is_exception(funcname): + # The functions passing this filter are known not to have a proof + + if funcname == 'poly_permute_bitrev_to_custom': + return True + + if funcname.endswith("_native") or funcname.endswith("_asm"): + # CBMC proofs are axiomatized against contracts of the backends + return True + + if funcname == "ct_get_optblocker_u64": + # As documented in the code, this contract is treated as an axiom + return True + + if funcname in ["memcmp", "randombytes"]: + # External functions + return True + + if funcname in ["zeroize"]: + # Implemented using inline ASM or external functions + return True + + return False + +def check_contracts(): + contracts = set(gen_contracts()) + proofs = set(gen_proofs()) + + bad = [] + + # Print contracts without proofs + for (filename, line, funcname) in contracts: + if funcname in proofs: + continue + + if is_exception(funcname): + print(f"{filename}:{line}:{funcname} has contract but no proof, " + "but is listed as exception") + continue + + print(f"{filename}:{line}:{funcname}: has contract but no proof. FAIL", + file=sys.stderr) + bad.append(funcname) + + return len(bad) == 0 + +def _main(): + if check_contracts() != True: + sys.exit(1) + +if __name__ == "__main__": + _main() diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/check-magic b/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/check-magic new file mode 100755 index 0000000000..ef7306b88e --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/check-magic @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# +# Looks for magic numbers without explanation +# + +import re +import math +import pathlib + +from sympy import simplify, sympify, Function, Rational + +def get_c_source_files(): + return get_files("mldsa/**/*.c") + +def get_header_files(): + return get_files("mldsa/**/*.h") + +def get_files(pattern): + return list(map(str, pathlib.Path().glob(pattern))) + +# Standard color definitions +GREEN="\033[32m" +RED="\033[31m" +BLUE="\033[94m" +BOLD="\033[1m" +NORMAL="\033[0m" + +CHECKED = f"{GREEN}✓{NORMAL}" +FAIL = f"{RED}✗{NORMAL}" +REMEMBERED = f"{BLUE}⊢{NORMAL}" + +def check_magic_numbers(): + mldsa_q = 8380417 + exceptions = [mldsa_q] + enable_marker = "check-magic: on" + disable_marker = "check-magic: off" + autogen_marker = "This file is auto-generated from scripts/autogen" + + files = get_c_source_files() + get_header_files() + + def is_exception(filename, l, magic): + return magic in exceptions + + def get_magic(l): + regexp = r'/\* check-magic:\s+([-]?\d{4,})\s*==\s*(.*?) \*/' + m = re.search(regexp, l) + if m is not None: + # Remove magic annotation to avoid it being treated + # as magic value itself + l = re.sub(regexp,'',l) + return l, (int(m.group(1)), m.group(2)) + return l, None + + def get_define(l): + m = re.search(r'#define\s+(\w+)', l) + if m is not None: + return m.group(1) + return None + + def evaluate_magic(m, known_magics): + def unsigned_mod(x,y): + return x % y + def signed_mod(x,y): + r = unsigned_mod(x,y) + if r >= y // 2: + r -= y + return r + def pow_mod(x,y,m): + x = int(x) + y = int(y) + m = int(m) + return signed_mod(pow(x,y,m),m) + def safe_round(x): + if x - math.floor(x) == Rational(1, 2): + raise ValueError(f"Ambiguous rounding: {x} is an odd multiple of 0.5 and it is unclear if round-up or round-down is desired") + return round(x) + def safe_floordiv(x, y): + x = int(x) + y = int(y) + if x % y != 0: + raise ValueError(f"Non-integral division: {x} // {y} has remainder {x % y}") + return x // y + locals_dict = {'signed_mod': signed_mod, + 'unsigned_mod': unsigned_mod, + 'pow': pow_mod, + 'round': safe_round, + 'intdiv': safe_floordiv } + locals_dict.update(known_magics) + return sympify(m, locals=locals_dict) + + for filename in files: + with open(filename, "r") as f: + content = f.read() + if autogen_marker in content: + continue + content = content.split("\n") + # Use negative lookbefore and lookahead to exclude numbers + # that occur as part of identifiers (e.g. layer12345 or 199901L) + pattern = r'(? 0: + print("Missing namespace literal from {}".format(namespaces)) + for symbol in non_namespaced: + print("\tsymbol: {}".format(symbol)) + assert not non_namespaced, "Literals with missing namespaces" + + +def check_folder(folder, namespace): + checked = 0 + # recursively go through folder and check all object files + for root, dirnames, filenames in os.walk(folder): + for filename in filenames: + if filename.endswith(".o"): + check_file(os.path.join(root, filename), namespace) + checked += 1 + print("Checked {} files".format(checked)) + assert checked > 0 + + +def make_mldsa_namespace(lvl): + return [f"PQCP_MLDSA_NATIVE_MLDSA{lvl}"] + + +def run(): + check_folder("test/build/mldsa44/mldsa", make_mldsa_namespace(44)) + check_folder("test/build/mldsa65/mldsa", make_mldsa_namespace(65)) + check_folder("test/build/mldsa87/mldsa", make_mldsa_namespace(87)) + + +if __name__ == "__main__": + os.chdir(os.path.join(os.path.dirname(__file__), "..")) + run() diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/copy_nix_from_upstream b/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/copy_nix_from_upstream new file mode 100755 index 0000000000..7039fa3420 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/copy_nix_from_upstream @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +ROOT="$(realpath "$(dirname "$0")"/../)" +TMP="$(mktemp -u)-mlkem-native" + +if [[ -d $TMP ]]; then + echo "$TMP already exists please remove it first" + exit 1 +fi + +git clone --depth=1 https://github.com/pq-code-package/mlkem-native.git "$TMP" + +echo "Copying nix related files from $TMP ..." +cp -R "$TMP/nix" "$ROOT" +cp -R "$TMP/.github/actions/setup-nix" "$ROOT/.github/actions/" +cp "$TMP/.github/workflows/nix.yml" "$ROOT/.github/workflows/nix.yml" +cp "$TMP/flake.lock" "$ROOT" diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/format b/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/format new file mode 100755 index 0000000000..244bfaba38 --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/format @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +set -o errexit +set -o errtrace +set -o nounset +set -o pipefail + +# consts +ROOT="$(realpath "$(dirname "$0")"/../)" + +# Standard color definitions +GREEN="\033[32m" +RED="\033[31m" +BLUE="\033[94m" +BOLD="\033[1m" +NORMAL="\033[0m" + +# utility +info() +{ + printf "%b %b\n" "${GREEN}info" "${NORMAL}${*}" +} + +error() +{ + printf "%b %b\n" "${RED}error" "${NORMAL}${*}" +} + +info "Formatting nix files" +if ! command -v nixpkgs-fmt 2>&1 >/dev/null; then + error "nixpkgs-fmt not found. Are you running in a nix shell? See CONTRIBUTING.md." + exit 1 +fi + +nixpkgs-fmt "$ROOT" + +info "Formatting shell scripts" +if ! command -v shfmt 2>&1 >/dev/null; then + error "shfmt not found. Are you running in a nix shell? See CONTRIBUTING.md." + exit 1 +fi +shfmt -s -w -l -i 2 -ci -fn $(shfmt -f $(git grep -l '' :/)) + +info "Formatting python scripts" +if ! command -v black 2>&1 >/dev/null; then + error "black not found. Are you running in a nix shell? See CONTRIBUTING.md." + exit 1 +fi +black --include "(scripts/tests|scripts/simpasm|scripts/cfify|scripts/autogen|scripts/check-namespace|\.py$)" "$ROOT" + +info "Formatting c files" +if ! command -v clang-format 2>&1 >/dev/null; then + error "clang-format not found. Are you running in a nix shell? See CONTRIBUTING.md." + exit 1 +fi + +nproc=$(getconf _NPROCESSORS_ONLN || echo 1) + +git ls-files -- ":/*.c" ":/*.h" | xargs -P $nproc -I {} sh -c ' + # Ignore symlinks + if [[ ! -L {} ]]; then + clang-format -i {} + fi' + +info "Checking for eol" +check-eol() +{ + git ls-files -- ":/" ":/!:*.png" | xargs -P $nproc -I {} sh -c ' + # Ignore symlinks + if [[ ! -L {} && $(tail -c1 "{}" | wc -l) == 0 ]]; then + echo "" >>"{}" + echo "{}" + fi' +} +check-eol diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/lint b/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/lint new file mode 100755 index 0000000000..57f8c37d5f --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/lint @@ -0,0 +1,243 @@ +#!/usr/bin/env bash +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +set -o errexit +set -o errtrace +set -o nounset +set -o pipefail + +# consts +ROOT="$(realpath "$(dirname "$0")"/../)" +GITHUB_STEP_SUMMARY=${GITHUB_STEP_SUMMARY:-/dev/stdout} + +# Check if we're in GitHub context +IN_GITHUB_CONTEXT=false +if [[ $GITHUB_STEP_SUMMARY != "/dev/stdout" ]]; then + IN_GITHUB_CONTEXT=true +fi + +# Standard color definitions +GREEN="\033[32m" +RED="\033[31m" +BLUE="\033[94m" +BOLD="\033[1m" +NORMAL="\033[0m" + +info() +{ + printf "%b %b\n" "${GREEN}✓" "${NORMAL}${*}" +} + +error() +{ + printf "%b %b\n" "${RED}✗" "${NORMAL}${*}" +} + +checkerr() +{ + local code=$? + local title="$1" + local out="$2" + local success=true + if [[ $code == 127 ]]; then + success=false + fi + + if [[ ${#out} != 0 ]]; then + if $IN_GITHUB_CONTEXT; then + echo "$out" | while read -r file line; do + echo "::error file=$file,line=${line:-1},title=Format error::$file require to be formatted" + done + fi + success=false + fi + + if $success; then + info "$title" + gh_summary_success "$title" + else + error "$title" + SUCCESS=false + gh_summary_failure "$title" + fi +} + +gh_group_start() +{ + if $IN_GITHUB_CONTEXT; then + echo "::group::$1" + fi +} + +gh_group_end() +{ + if $IN_GITHUB_CONTEXT; then + echo "::endgroup::" + fi +} + +gh_summary_success() +{ + if $IN_GITHUB_CONTEXT; then + echo ":white_check_mark: $1" >>"$GITHUB_STEP_SUMMARY" + fi +} + +gh_summary_failure() +{ + if $IN_GITHUB_CONTEXT; then + echo ":x: $1" >>"$GITHUB_STEP_SUMMARY" + fi +} + +gh_error() +{ + error "$4" + if $IN_GITHUB_CONTEXT; then + echo "::error file=$1,line=${2:-1},title=$3::$4" + fi +} + +gh_error_simple() +{ + if $IN_GITHUB_CONTEXT; then + echo "::error title=$1::$2" + fi +} + +# Formatting +SUCCESS=true + +gh_group_start "Linting nix files with nixpkgs-fmt" +checkerr "Lint nix" "$(nixpkgs-fmt --check "$ROOT")" +gh_group_end + +gh_group_start "Linting shell scripts with shfmt" +checkerr "Lint shell" "$(shfmt -s -l -i 2 -ci -fn $(shfmt -f $(git grep -l '' :/)))" +gh_group_end + +gh_group_start "Linting python scripts with black" +if ! diff=$(black --check --diff -q --include "(scripts/tests|scripts/simpasm|scripts/cfify|scripts/autogen|scripts/check-namespace|\.py$)" "$ROOT"); then + gh_error_simple "Format error" "$diff" + error "Lint python" + SUCCESS=false + gh_summary_failure "Lint python" +else + info "Lint Python" + gh_summary_success "Lint Python" +fi +gh_group_end + +gh_group_start "Linting c files with clang-format" +checkerr "Lint C" "$(clang-format $(git ls-files ":/*.c" ":/*.h") --Werror --dry-run 2>&1 | grep "error:" | cut -d ':' -f 1,2 | tr ':' ' ')" +gh_group_end + +check-eol-dry-run() +{ + for file in $(git ls-files -- ":/" ":/!:*.png"); do + # Ignore symlinks + if [[ ! -L $file && $(tail -c1 "$file" | wc -l) == 0 ]]; then + l=$(wc -l <"$file") + echo "$file $l" + fi + done +} +gh_group_start "Checking eol" +checkerr "Check eol" "$(check-eol-dry-run)" +gh_group_end + +check-spdx() +{ + local success=true + for file in $(git ls-files -- ":/" ":/!:*.json" ":/!:*.png" ":/!:*LICENSE*" ":/!:.git*" ":/!:flake.lock"); do + # Ignore symlinks + if [[ ! -L $file && $(grep "SPDX-License-Identifier:" $file | wc -l) == 0 ]]; then + gh_error "$file" "${line:-1}" "Missing license header error" "$file is missing SPDX License header" + success=false + fi + done + for file in $(git ls-files -- "*.[chsS]" "*.py" "*.mk" "*.yml" "**/Makefile*" ":/!proofs/cbmc/*.py" ":/!examples/bring_your_own_fips202/custom_fips202/tiny_sha3/*" ":/!examples/custom_backend/mldsa_native/src/fips202/native/custom/src/*"); do + # Ignore symlinks + if [[ ! -L $file && $(grep "Copyright (c) The mldsa-native project authors" $file | wc -l) == 0 ]]; then + gh_error "$file" "${line:-1}" "Missing copyright header error" "$file is missing copyright header" + success=false + fi + done + # For source files in dev/* and mldsa/*, we enforce `Apache-2.0 OR ISC OR MIT` + for file in $(git ls-files -- "*.[chsSi]" | grep "^dev/\|^mldsa/"); do + # Ignore symlinks + if [[ ! -L $file && $(grep "SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT" $file | wc -l) == 0 ]]; then + gh_error "$file" "${line:-1}" "Missing license header error" "$file is not licensed under 'Apache-2.0 OR ISC OR MIT'" + success=false + fi + done + + if $success; then + info "Check SPDX + Copyright" + gh_summary_success "Check SPDX + Copyright" + else + error "Check SPDX + Copyright" + SUCCESS=false + gh_summary_failure "Check SPDX + Copyright" + fi +} +gh_group_start "Checking SPDX + Copyright headers" +check-spdx +gh_group_end + +check-autogenerated-files() +{ + if python3 $ROOT/scripts/autogen --dry-run; then + info "Check native auto-generated files" + gh_summary_success "Check native auto-generated files" + else + error "Check native auto-generated files" + gh_summary_failure "Check native auto-generated files" + SUCCESS=false + fi +} + +gh_group_start "Check native auto-generated files" +check-autogenerated-files +gh_group_end + +check-magic() +{ + if python3 $ROOT/scripts/check-magic >/dev/null; then + info "Check magic constants" + gh_summary_success "Check magic constants" + else + error "Check magic constants" + gh_summary_failure "Check magic constants" + SUCCESS=false + fi +} + +gh_group_start "Check magic constants" +check-magic +gh_group_end + +if ! $SUCCESS; then + exit 1 +fi + +check-contracts() +{ + if python3 $ROOT/scripts/check-contracts >/dev/null; then + info "Check contracts" + gh_summary_success "Check contracts" + else + error "Check contracts" + gh_summary_failure "Check contracts" + SUCCESS=false + fi +} + +gh_group_start "Check contracts" +check-contracts +gh_group_end + +if ! $SUCCESS; then + exit 1 +fi diff --git a/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/simpasm b/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/simpasm new file mode 100755 index 0000000000..289eac4c1a --- /dev/null +++ b/tf-psa-crypto/drivers/pqcp/mldsa-native/scripts/simpasm @@ -0,0 +1,465 @@ +#!/usr/bin/env python3 +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +import subprocess +import argparse +import logging +import pathlib +import tempfile +import platform +import sys +import os +import re + + +def patchup_disasm(asm, cfify=False): + asm = asm.split("\n") + indentation = 8 + + def decode_label(asm_line): + r = re.search(r"^\s*[0-9a-fA-F]+\s*<([a-zA-Z0-9_]+)>:\s*$", asm_line) + if r is None: + return None + return r.group(1) + + def make_label(lbl): + if cfify: + return "L" + lbl + ":" + return lbl + ":" + + # Find first label + for i, l in enumerate(asm): + if decode_label(l) is not None: + break + + asm = asm[i + 1 :] + + def gen(asm): + for l in asm: + if l.strip() == "": + yield "" + continue + lbl = decode_label(l) + # Re-format labels as assembly labels + if lbl is not None: + yield make_label(lbl) + continue + # Drop comments + l = l.split(";")[0] + # Re-format references to labels + # Those are assumed to have the form `0xDEADBEEF